debuggers.hg

view tools/internal/xi_build.c @ 633:884c96cebace

bitkeeper revision 1.329.1.4 (3f0d4373d9SiOpCi9y2d8jsIGk2rgw)

More silly little cleanups.
author sos22@labyrinth.cl.cam.ac.uk
date Thu Jul 10 10:44:03 2003 +0000 (2003-07-10)
parents e421961ce0bc
children 681598b3259f
line source
1 /*
2 * XenoDomainBuilder, copyright (c) Boris Dragovic, bd240@cl.cam.ac.uk
3 * This code is released under terms and conditions of GNU GPL :).
4 * Usage: <executable> <mem_kb> <os image> <num_vifs>
5 */
7 #include <unistd.h>
8 #include <stdio.h>
9 #include <errno.h>
10 #include <fcntl.h>
11 #include <sys/stat.h>
12 #include <sys/ioctl.h>
13 #include <string.h>
14 #include <stdlib.h>
16 #include "asm-xeno/dom0.h"
17 #include "hypervisor-ifs/hypervisor-if.h"
18 #include "dom0_ops.h"
19 #include "dom0_defs.h"
20 #include "mem_defs.h"
22 #define PERR_STRING "Xeno Domain Builder"
24 #define GUEST_SIG "XenoGues"
25 #define SIG_LEN 8
27 /* Watch for precedence when using thses ones... */
28 #define PROC_XENO_DOM0_CMD "/proc/" PROC_XENO_ROOT "/" PROC_CMD
29 #define PROC_XENO_DOMAINS "/proc" PROC_XENO_ROOT "/" PROC_DOMAINS
31 /*
32 * NB. No ring-3 access in initial guestOS pagetables. Note that we allow
33 * ring-3 privileges in the page directories, so that the guestOS may later
34 * decide to share a 4MB region with applications.
35 */
36 #define L1_PROT (_PAGE_PRESENT|_PAGE_RW|_PAGE_ACCESSED)
37 #define L2_PROT (_PAGE_PRESENT|_PAGE_RW|_PAGE_ACCESSED|_PAGE_DIRTY|_PAGE_USER)
39 /* standardized error reporting function */
40 static void dberr(char *msg)
41 {
42 printf("%s: %s\n", PERR_STRING, msg);
43 }
45 /* status reporting function */
46 static void dbstatus(char * msg)
47 {
48 printf("Domain Builder: %s\n", msg);
49 }
52 /* clean up domain's memory allocations */
53 static void dom_mem_cleanup(dom_mem_t * dom_mem)
54 {
55 int fd;
56 struct dom0_unmapdommem_args argbuf;
58 fd = open("/proc/xeno/dom0_cmd", O_WRONLY);
59 if(fd < 0){
60 perror("openning /proc/xeno/dom0_cmd");
61 return;
62 }
64 argbuf.vaddr = dom_mem->vaddr;
65 argbuf.start_pfn = dom_mem->start_pfn;
66 argbuf.tot_pages = dom_mem->tot_pages;
68 if (ioctl(fd, IOCTL_DOM0_UNMAPDOMMEM, &argbuf) < 0) {
69 dbstatus("Error unmapping domain's memory.\n");
70 }
72 close(fd);
73 }
75 static int map_dom_mem(unsigned long pfn, int pages, int dom,
76 dom_mem_t * dom_mem)
77 {
78 struct dom0_mapdommem_args argbuf;
79 int fd;
81 argbuf.domain = dom;
82 argbuf.start_pfn = pfn;
83 argbuf.tot_pages = pages;
85 fd = open("/proc/xeno/dom0_cmd", O_RDWR);
86 if (fd < 0) {
87 perror("openning /proc/xeno/dom0_cmd");
88 return -1;
89 }
91 dom_mem->domain = dom;
92 dom_mem->start_pfn = pfn;
93 dom_mem->tot_pages = pages;
94 dom_mem->vaddr = ioctl(fd, IOCTL_DOM0_MAPDOMMEM, &argbuf);
96 if (dom_mem->vaddr == -1) {
97 perror("mapping domain memory");
98 close(fd);
99 return -1;
100 }
101 close(fd);
103 return 0;
104 }
106 /* read the kernel header, extracting the image size and load address. */
107 static int read_kernel_header(int fd, long dom_size,
108 unsigned long * load_addr, size_t * ksize)
109 {
110 char signature[8];
111 char status[MAX_PATH];
112 struct stat stat;
114 if(fstat(fd, &stat) < 0){
115 perror(PERR_STRING);
116 return -1;
117 }
119 if(stat.st_size > (dom_size << 10)){
120 sprintf(status, "Kernel image size %ld larger than requested "
121 "domain size %ld\n Terminated.\n", stat.st_size, dom_size);
122 dberr(status);
123 return -1;
124 }
126 read(fd, signature, SIG_LEN);
127 if(strncmp(signature, GUEST_SIG, SIG_LEN)){
128 dberr("Kernel image does not contain required signature. "
129 "Terminating.\n");
130 return -1;
131 }
133 read(fd, load_addr, sizeof(unsigned long));
135 *ksize = stat.st_size - SIG_LEN - sizeof(unsigned long);
137 return 0;
138 }
140 /* this is the main guestos setup function,
141 * returnes domain descriptor structure to be used when launching
142 * the domain by hypervisor to do some last minute initialization.
143 * page table initialization is done by making a list of page table
144 * requests that are handeled by the hypervisor in the ordinary
145 * manner. this way, many potentially messy things are avoided...
146 */
147 #define PAGE_TO_VADDR(_pfn) ((void *)(dom_mem->vaddr + ((_pfn) * PAGE_SIZE)))
148 static dom_meminfo_t *setup_guestos(int dom, int kernel_fd, int initrd_fd,
149 unsigned long virt_load_addr, size_t ksize, dom_mem_t *dom_mem)
150 {
151 dom_meminfo_t *meminfo = NULL;
152 unsigned long *page_array = NULL;
153 page_update_request_t *pgt_updates = NULL;
154 int alloc_index, num_pt_pages;
155 unsigned long l2tab;
156 unsigned long l1tab = 0;
157 unsigned long num_pgt_updates = 0;
158 unsigned long count, pt_start;
159 struct dom0_dopgupdates_args pgupdate_req;
160 int cmd_fd;
161 int result;
163 meminfo = (dom_meminfo_t *)malloc(sizeof(dom_meminfo_t));
164 page_array = malloc(dom_mem->tot_pages * 4);
165 if (!meminfo || !page_array) {
166 dberr ("Could not allocate memory");
167 goto error_out;
168 }
169 pgt_updates = (page_update_request_t *)dom_mem->vaddr;
170 alloc_index = dom_mem->tot_pages - 1;
172 memset(meminfo, 0, sizeof(*meminfo));
174 memcpy(page_array, (void *)dom_mem->vaddr, dom_mem->tot_pages * 4);
176 /* Count bottom-level PTs, rounding up. Include one PTE for shared info. */
177 num_pt_pages =
178 (l1_table_offset(virt_load_addr) + dom_mem->tot_pages + 1024) / 1024;
180 /* We must also count the page directory. */
181 num_pt_pages++;
183 /* Index of first PT page. */
184 pt_start = dom_mem->tot_pages - num_pt_pages;
186 /* first allocate page for page dir. allocation goes backwards from the
187 * end of the allocated physical address space.
188 */
189 l2tab = *(page_array + alloc_index) << PAGE_SHIFT;
190 memset(PAGE_TO_VADDR(alloc_index), 0, PAGE_SIZE);
191 alloc_index--;
192 meminfo->l2_pgt_addr = l2tab;
193 meminfo->virt_shinfo_addr = virt_load_addr + nr_2_page(dom_mem->tot_pages);
195 /* pin down l2tab addr as page dir page - causes hypervisor to provide
196 * correct protection for the page
197 */
198 pgt_updates->ptr = l2tab | PGREQ_EXTENDED_COMMAND;
199 pgt_updates->val = PGEXT_PIN_L2_TABLE;
200 pgt_updates++;
201 num_pgt_updates++;
203 /*
204 * Initialise the page tables. The final iteration is for the shared_info
205 * PTE -- we break out before filling in the entry, as that is done by
206 * Xen during final setup.
207 */
208 l2tab += l2_table_offset(virt_load_addr) * sizeof(l2_pgentry_t);
209 for ( count = 0; count < (dom_mem->tot_pages + 1); count++ )
210 {
211 if ( !((unsigned long)l1tab & (PAGE_SIZE-1)) )
212 {
213 l1tab = *(page_array + alloc_index) << PAGE_SHIFT;
214 memset(PAGE_TO_VADDR(alloc_index), 0, PAGE_SIZE);
215 alloc_index--;
217 l1tab += l1_table_offset(virt_load_addr + nr_2_page(count))
218 * sizeof(l1_pgentry_t);
220 /* make apropriate entry in the page directory */
221 pgt_updates->ptr = l2tab;
222 pgt_updates->val = l1tab | L2_PROT;
223 pgt_updates++;
224 num_pgt_updates++;
225 l2tab += sizeof(l2_pgentry_t);
226 }
228 /* The last PTE we consider is filled in later by Xen. */
229 if ( count == dom_mem->tot_pages ) break;
231 if ( count < pt_start )
232 {
233 pgt_updates->ptr = l1tab;
234 pgt_updates->val = (*(page_array + count) << PAGE_SHIFT) | L1_PROT;
235 pgt_updates++;
236 num_pgt_updates++;
237 l1tab += sizeof(l1_pgentry_t);
238 }
239 else
240 {
241 pgt_updates->ptr = l1tab;
242 pgt_updates->val =
243 ((*(page_array + count) << PAGE_SHIFT) | L1_PROT) & ~_PAGE_RW;
244 pgt_updates++;
245 num_pgt_updates++;
246 l1tab += sizeof(l1_pgentry_t);
247 }
249 pgt_updates->ptr =
250 (*(page_array + count) << PAGE_SHIFT) | PGREQ_MPT_UPDATE;
251 pgt_updates->val = count;
252 pgt_updates++;
253 num_pgt_updates++;
254 }
256 meminfo->virt_startinfo_addr = virt_load_addr + nr_2_page(alloc_index - 1);
257 meminfo->domain = dom;
259 free(page_array);
261 /*
262 * Send the page update requests down to the hypervisor.
263 * NB. We must do this before loading the guest OS image!
264 */
265 if ( (cmd_fd = open(PROC_XENO_DOM0_CMD, O_WRONLY)) < 0 )
266 {
267 dberr ("Could not open " PROC_XENO_DOM0_CMD);
268 goto error_out;
269 }
271 pgupdate_req.pgt_update_arr = (unsigned long)dom_mem->vaddr;
272 pgupdate_req.num_pgt_updates = num_pgt_updates;
273 result = ioctl(cmd_fd, IOCTL_DOM0_DOPGUPDATES, &pgupdate_req);
274 close(cmd_fd);
275 if (result < 0) {
276 dberr ("Could not build domain page tables.");
277 goto error_out;
278 }
280 /* Load the guest OS image. */
281 if( read(kernel_fd, (char *)dom_mem->vaddr, ksize) != ksize )
282 {
283 dberr("Error reading kernel image, could not"
284 " read the whole image.");
285 goto error_out;
286 }
288 if( initrd_fd >= 0)
289 {
290 struct stat stat;
291 unsigned long isize;
293 if(fstat(initrd_fd, &stat) < 0){
294 perror(PERR_STRING);
295 goto error_out;
296 }
297 isize = stat.st_size;
299 if( read(initrd_fd, ((char *)dom_mem->vaddr)+ksize, isize) != isize )
300 {
301 dberr("Error reading initrd image, could not"
302 " read the whole image. Terminating.");
303 goto error_out;
304 }
306 meminfo->virt_mod_addr = virt_load_addr + ksize;
307 meminfo->virt_mod_len = isize;
309 }
312 return meminfo;
314 error_out:
315 if (meminfo)
316 free(meminfo);
317 if (page_array)
318 free(page_array);
320 return NULL;
321 }
323 static int launch_domain(dom_meminfo_t * meminfo)
324 {
325 dom0_op_t dop;
326 int cmd_fd;
328 cmd_fd = open(PROC_XENO_DOM0_CMD, O_WRONLY);
329 if(cmd_fd < 0){
330 perror(PERR_STRING);
331 return -1;
332 }
334 dop.cmd = DOM0_BUILDDOMAIN;
335 memcpy(&dop.u.meminfo, meminfo, sizeof(dom_meminfo_t));
336 write(cmd_fd, &dop, sizeof(dom0_op_t));
337 close(cmd_fd);
339 return 0;
340 }
342 static int get_domain_info (int domain_id,
343 int *pg_head,
344 int *tot_pages)
345 {
346 FILE *f;
347 char domains_line[256];
348 int read_id;
350 f = fopen (PROC_XENO_DOMAINS, "r");
351 if (f == NULL) return -1;
353 read_id = -1;
354 while (fgets (domains_line, 256, f) != 0)
355 {
356 int trans;
357 read_id = -1;
358 trans = sscanf (domains_line, "%d %*d %*d %*d %*d %*d %x %d %*s", &read_id
359 , pg_head, tot_pages);
360 if (trans != 3) {
361 dberr ("format of " PROC_XENO_DOMAINS " changed -- wrong kernel version?");
362 read_id = -1;
363 break;
364 }
366 if (read_id == domain_id) {
367 break;
368 }
369 }
371 fclose (f);
373 if (read_id == -1) {
374 errno = ESRCH;
375 }
377 return 0;
378 }
381 int main(int argc, char **argv)
382 {
384 dom_mem_t dom_os_image;
385 dom_meminfo_t * meminfo;
386 size_t ksize;
387 unsigned long load_addr;
388 int kernel_fd, initrd_fd = -1;
389 int count;
390 int cmd_len;
391 int args_start = 4;
392 char initrd_name[1024];
393 int domain_id;
394 int pg_head;
395 int tot_pages;
396 int rc;
398 /**** this argument parsing code is really _gross_. rewrite me! ****/
400 if(argc < 4) {
401 dberr("Usage: dom_builder <domain_id> <image> <num_vifs> "
402 "[<initrd=initrd_name>] <boot_params>\n");
403 return -1;
404 }
406 /* Look up information about the domain */
407 domain_id = atol(argv[1]);
408 if ( get_domain_info (domain_id, &pg_head, &tot_pages) != 0 )
409 {
410 perror ("Could not find domain information");
411 return -1;
412 }
414 kernel_fd = open(argv[2], O_RDONLY);
415 if (kernel_fd < 0) {
416 perror ("Could not open kernel image");
417 return -1;
418 }
420 rc = read_kernel_header(kernel_fd,
421 tot_pages << (PAGE_SHIFT - 10),
422 &load_addr, &ksize);
423 if ( rc < 0 )
424 return -1;
427 /* map domain's memory */
428 if ( map_dom_mem(pg_head, tot_pages,
429 domain_id, &dom_os_image) )
430 return -1;
432 if( (argc > args_start) &&
433 (strncmp("initrd=", argv[args_start], 7) == 0) )
434 {
435 strncpy( initrd_name, argv[args_start]+7, sizeof(initrd_name) );
436 initrd_name[sizeof(initrd_name)-1] = 0;
437 printf("initrd present, name = %s\n", initrd_name );
438 args_start++;
440 initrd_fd = open(initrd_name, O_RDONLY);
441 if(initrd_fd < 0){
442 perror(PERR_STRING);
443 return -1;
444 }
445 }
447 /* the following code does the actual domain building */
448 meminfo = setup_guestos(domain_id, kernel_fd, initrd_fd, load_addr,
449 ksize, &dom_os_image);
450 if (!meminfo)
451 return -1;
453 if (initrd_fd >= 0)
454 close(initrd_fd);
455 close(kernel_fd);
457 /* and unmap the new domain's memory image since we no longer need it */
458 dom_mem_cleanup(&dom_os_image);
460 meminfo->virt_load_addr = load_addr;
461 meminfo->num_vifs = atoi(argv[3]);
462 meminfo->cmd_line[0] = '\0';
463 cmd_len = 0;
464 for(count = args_start; count < argc; count++){
465 if(cmd_len + strlen(argv[count]) > MAX_CMD_LEN - 1){
466 dberr("Size of image boot params too big!\n");
467 break;
468 }
469 strcat(meminfo->cmd_line, argv[count]);
470 strcat(meminfo->cmd_line, " ");
471 cmd_len += strlen(argv[count] + 1);
472 }
474 /* and launch the domain */
475 rc = launch_domain(meminfo);
477 return 0;
478 }