debuggers.hg

view tools/internal/xi_build.c @ 654:18c36f61f4cd

bitkeeper revision 1.345 (3f12be5aIxtVNJz4gdn0zwGqyPofFQ)

Merge labyrinth.cl.cam.ac.uk:/auto/groups/xeno/BK/xeno.bk
into labyrinth.cl.cam.ac.uk:/auto/anfs/scratch/labyrinth/iap10/xeno-clone/xeno.bk
author iap10@labyrinth.cl.cam.ac.uk
date Mon Jul 14 14:29:46 2003 +0000 (2003-07-14)
parents cda951fc1bef 75185d4cce5b
children b344838eb409 e09b8abaa2e3
line source
2 #include "hypervisor-ifs/dom0_ops.h"
3 #include "dom0_defs.h"
4 #include "mem_defs.h"
6 #define GUEST_SIG "XenoGues"
7 #define SIG_LEN 8
9 #define L1_PROT (_PAGE_PRESENT|_PAGE_RW|_PAGE_ACCESSED)
10 #define L2_PROT (_PAGE_PRESENT|_PAGE_RW|_PAGE_ACCESSED|_PAGE_DIRTY|_PAGE_USER)
12 static long get_tot_pages(int domain_id)
13 {
14 dom0_op_t op;
15 op.cmd = DOM0_GETDOMAININFO;
16 op.u.getdominfo.domain = domain_id;
17 return (do_dom0_op(&op) < 0) ? -1 : op.u.getdominfo.tot_pages;
18 }
20 static int get_pfn_list(
21 int domain_id, unsigned long *pfn_buf, unsigned long max_pfns)
22 {
23 dom0_op_t op;
24 int ret;
25 op.cmd = DOM0_GETMEMLIST;
26 op.u.getmemlist.domain = domain_id;
27 op.u.getmemlist.max_pfns = max_pfns;
28 op.u.getmemlist.buffer = pfn_buf;
30 if ( mlock(pfn_buf, max_pfns * sizeof(unsigned long)) != 0 )
31 {
32 PERROR("Could not lock pfn list buffer");
33 return -1;
34 }
36 ret = do_dom0_op(&op);
38 (void)munlock(pfn_buf, max_pfns * sizeof(unsigned long));
40 return (ret < 0) ? -1 : op.u.getmemlist.num_pfns;
41 }
43 static int send_pgupdates(page_update_request_t *updates, int nr_updates)
44 {
45 int ret = -1;
46 privcmd_hypercall_t hypercall;
48 hypercall.op = __HYPERVISOR_pt_update;
49 hypercall.arg[0] = (unsigned long)updates;
50 hypercall.arg[1] = (unsigned long)nr_updates;
52 if ( mlock(updates, nr_updates * sizeof(*updates)) != 0 )
53 {
54 PERROR("Could not lock pagetable update array");
55 goto out1;
56 }
58 if ( do_xen_hypercall(&hypercall) < 0 )
59 goto out2;
61 ret = 0;
63 out2: (void)munlock(updates, nr_updates * sizeof(*updates));
64 out1: return ret;
65 }
67 /* Read the kernel header, extracting the image size and load address. */
68 static int read_kernel_header(int fd, long dom_size,
69 unsigned long * load_addr, size_t * ksize)
70 {
71 char signature[8];
72 char status[1024];
73 struct stat stat;
75 if ( fstat(fd, &stat) < 0 )
76 {
77 PERROR("Cannot stat the kernel image");
78 return -1;
79 }
81 if ( (stat.st_size * 2) > (dom_size << 10) )
82 {
83 sprintf(status, "Kernel image size %ld larger than requested "
84 "domain size %ld\n Terminated.\n", stat.st_size, dom_size);
85 ERROR(status);
86 return -1;
87 }
89 read(fd, signature, SIG_LEN);
90 if ( strncmp(signature, GUEST_SIG, SIG_LEN) )
91 {
92 ERROR("Kernel image does not contain required signature. "
93 "Terminating.\n");
94 return -1;
95 }
97 read(fd, load_addr, sizeof(unsigned long));
99 *ksize = stat.st_size - SIG_LEN - sizeof(unsigned long);
101 return 0;
102 }
104 static int devmem_fd;
106 static int init_pfn_mapper(void)
107 {
108 if ( (devmem_fd = open("/dev/mem", O_RDWR)) < 0 )
109 {
110 PERROR("Could not open /dev/mem");
111 return -1;
112 }
113 return 0;
114 }
116 static void *map_pfn(unsigned long pfn)
117 {
118 void *vaddr = mmap(NULL, PAGE_SIZE, PROT_READ|PROT_WRITE,
119 MAP_SHARED, devmem_fd, pfn << PAGE_SHIFT);
120 if ( vaddr == MAP_FAILED )
121 {
122 PERROR("Could not mmap a domain pfn using /dev/mem");
123 return NULL;
124 }
125 return vaddr;
126 }
128 static void unmap_pfn(void *vaddr)
129 {
130 (void)munmap(vaddr, PAGE_SIZE);
131 }
133 static int clear_domain_page(unsigned long pfn)
134 {
135 void *vaddr = map_pfn(pfn);
136 if ( vaddr == NULL )
137 return -1;
138 memset(vaddr, 0, PAGE_SIZE);
139 unmap_pfn(vaddr);
140 return 0;
141 }
143 static int copy_to_domain_page(unsigned long dst_pfn, void *src_page)
144 {
145 void *vaddr = map_pfn(dst_pfn);
146 if ( vaddr == NULL )
147 return -1;
148 memcpy(vaddr, src_page, PAGE_SIZE);
149 unmap_pfn(vaddr);
150 return 0;
151 }
153 static int setup_guestos(
154 int dom, int kernel_fd, int initrd_fd, unsigned long tot_pages,
155 unsigned long virt_load_addr, size_t ksize, dom_meminfo_t *meminfo)
156 {
157 unsigned long *page_array = NULL;
158 page_update_request_t *pgt_update_arr = NULL, *pgt_updates = NULL;
159 int alloc_index, num_pt_pages;
160 unsigned long l2tab;
161 unsigned long l1tab = 0;
162 unsigned long num_pgt_updates = 0;
163 unsigned long count, pt_start, i, j;
165 memset(meminfo, 0, sizeof(*meminfo));
167 if ( init_pfn_mapper() < 0 )
168 goto error_out;
170 pgt_updates = malloc((tot_pages + 1024) * 3
171 * sizeof(page_update_request_t));
172 page_array = malloc(tot_pages * sizeof(unsigned long));
173 pgt_update_arr = pgt_updates;
174 if ( (pgt_update_arr == NULL) || (page_array == NULL) )
175 {
176 PERROR("Could not allocate memory");
177 goto error_out;
178 }
180 if ( get_pfn_list(dom, page_array, tot_pages) != tot_pages )
181 {
182 PERROR("Could not get the page frame list");
183 goto error_out;
184 }
186 /* Load the guest OS image. */
187 for ( i = 0; i < ksize; i += PAGE_SIZE )
188 {
189 char page[PAGE_SIZE];
190 int size = ((ksize-i) < PAGE_SIZE) ? (ksize-i) : PAGE_SIZE;
191 if ( read(kernel_fd, page, size) != size )
192 {
193 PERROR("Error reading kernel image, could not"
194 " read the whole image.");
195 goto error_out;
196 }
197 copy_to_domain_page(page_array[i>>PAGE_SHIFT], page);
198 }
200 /* Load the initial ramdisk image. */
201 if ( initrd_fd >= 0 )
202 {
203 struct stat stat;
204 unsigned long isize;
206 if ( fstat(initrd_fd, &stat) < 0 )
207 {
208 PERROR("Could not stat the initrd image");
209 goto error_out;
210 }
211 isize = stat.st_size;
212 if ( ((isize + ksize) * 2) > (tot_pages << PAGE_SHIFT) )
213 {
214 ERROR("Kernel + initrd too big to safely fit in domain memory");
215 goto error_out;
216 }
218 meminfo->virt_mod_addr = virt_load_addr + i;
219 meminfo->virt_mod_len = isize;
221 for ( j = 0; j < isize; j += PAGE_SIZE, i += PAGE_SIZE )
222 {
223 char page[PAGE_SIZE];
224 int size = ((isize-j) < PAGE_SIZE) ? (isize-j) : PAGE_SIZE;
225 if ( read(initrd_fd, page, size) != size )
226 {
227 PERROR("Error reading initrd image, could not"
228 " read the whole image.");
229 goto error_out;
230 }
231 copy_to_domain_page(page_array[i>>PAGE_SHIFT], page);
232 }
233 }
235 alloc_index = tot_pages - 1;
237 /*
238 * Count bottom-level PTs, rounding up. Include one PTE for shared info. We
239 * therefore add 1024 because 1 is for shared_info, 1023 is to round up.
240 */
241 num_pt_pages =
242 (l1_table_offset(virt_load_addr) + tot_pages + 1024) / 1024;
244 /* We must also count the page directory. */
245 num_pt_pages++;
247 /* Index of first PT page. */
248 pt_start = tot_pages - num_pt_pages;
250 /*
251 * First allocate page for page dir. Allocation goes backwards from the end
252 * of the allocated physical address space.
253 */
254 l2tab = page_array[alloc_index] << PAGE_SHIFT;
255 if ( clear_domain_page(page_array[alloc_index]) < 0 )
256 goto error_out;
257 alloc_index--;
258 meminfo->l2_pgt_addr = l2tab;
259 meminfo->virt_shinfo_addr = virt_load_addr + (tot_pages << PAGE_SHIFT);
261 /*
262 * Pin down l2tab addr as page dir page - causes hypervisor to provide
263 * correct protection for the page
264 */
265 pgt_updates->ptr = l2tab | PGREQ_EXTENDED_COMMAND;
266 pgt_updates->val = PGEXT_PIN_L2_TABLE;
267 pgt_updates++;
268 num_pgt_updates++;
270 /*
271 * Initialise the page tables. The final iteration is for the shared_info
272 * PTE -- we break out before filling in the entry, as that is done by
273 * Xen during final setup.
274 */
275 l2tab += l2_table_offset(virt_load_addr) * sizeof(l2_pgentry_t);
276 for ( count = 0; count < (tot_pages + 1); count++ )
277 {
278 if ( !((unsigned long)l1tab & (PAGE_SIZE-1)) )
279 {
280 l1tab = page_array[alloc_index] << PAGE_SHIFT;
281 if ( clear_domain_page(page_array[alloc_index]) < 0 )
282 goto error_out;
283 alloc_index--;
285 l1tab += l1_table_offset(virt_load_addr + (count << PAGE_SHIFT))
286 * sizeof(l1_pgentry_t);
288 /* make apropriate entry in the page directory */
289 pgt_updates->ptr = l2tab;
290 pgt_updates->val = l1tab | L2_PROT;
291 pgt_updates++;
292 num_pgt_updates++;
293 l2tab += sizeof(l2_pgentry_t);
294 }
296 /* The last PTE we consider is filled in later by Xen. */
297 if ( count == tot_pages ) break;
299 if ( count < pt_start )
300 {
301 pgt_updates->ptr = l1tab;
302 pgt_updates->val = (page_array[count] << PAGE_SHIFT) | L1_PROT;
303 pgt_updates++;
304 num_pgt_updates++;
305 l1tab += sizeof(l1_pgentry_t);
306 }
307 else
308 {
309 pgt_updates->ptr = l1tab;
310 pgt_updates->val =
311 ((page_array[count] << PAGE_SHIFT) | L1_PROT) & ~_PAGE_RW;
312 pgt_updates++;
313 num_pgt_updates++;
314 l1tab += sizeof(l1_pgentry_t);
315 }
317 pgt_updates->ptr =
318 (page_array[count] << PAGE_SHIFT) | PGREQ_MPT_UPDATE;
319 pgt_updates->val = count;
320 pgt_updates++;
321 num_pgt_updates++;
322 }
324 meminfo->virt_startinfo_addr =
325 virt_load_addr + ((alloc_index-1)<<PAGE_SHIFT);
327 /* Send the page update requests down to the hypervisor. */
328 if ( send_pgupdates(pgt_update_arr, num_pgt_updates) < 0 )
329 goto error_out;
331 free(page_array);
332 free(pgt_update_arr);
333 return 0;
335 error_out:
336 if ( page_array == NULL )
337 free(page_array);
338 if ( pgt_update_arr == NULL )
339 free(pgt_update_arr);
340 return -1;
341 }
343 int main(int argc, char **argv)
344 {
345 dom0_op_t launch_op;
346 size_t ksize;
347 unsigned long load_addr;
348 long tot_pages;
349 int kernel_fd, initrd_fd = -1;
350 int count;
351 int cmd_len;
352 int args_start = 4;
353 char initrd_name[1024];
354 int domain_id;
355 int rc;
357 if ( argc < 4 )
358 {
359 fprintf(stderr, "Usage: dom_builder <domain_id> <image> <num_vifs> "
360 "[<initrd=initrd_name>] <boot_params>\n");
361 return 1;
362 }
364 domain_id = atol(argv[1]);
365 if ( (tot_pages = get_tot_pages(domain_id)) < 0 )
366 {
367 PERROR("Could not find total pages for domain");
368 return 1;
369 }
371 kernel_fd = open(argv[2], O_RDONLY);
372 if ( kernel_fd < 0 )
373 {
374 PERROR("Could not open kernel image");
375 return 1;
376 }
378 rc = read_kernel_header(kernel_fd,
379 tot_pages << (PAGE_SHIFT - 10),
380 &load_addr, &ksize);
381 if ( rc < 0 )
382 return 1;
384 if( (argc > args_start) &&
385 (strncmp("initrd=", argv[args_start], 7) == 0) )
386 {
387 strncpy( initrd_name, argv[args_start]+7, sizeof(initrd_name) );
388 initrd_name[sizeof(initrd_name)-1] = 0;
389 printf("initrd present, name = %s\n", initrd_name );
390 args_start++;
392 initrd_fd = open(initrd_name, O_RDONLY);
393 if ( initrd_fd < 0 )
394 {
395 PERROR("Could not open the initial ramdisk image");
396 return 1;
397 }
398 }
400 if ( setup_guestos(domain_id, kernel_fd, initrd_fd, tot_pages,
401 load_addr, ksize, &launch_op.u.meminfo) < 0 )
402 return 1;
404 if ( initrd_fd >= 0 )
405 close(initrd_fd);
406 close(kernel_fd);
408 launch_op.u.meminfo.domain = domain_id;
409 launch_op.u.meminfo.virt_load_addr = load_addr;
410 launch_op.u.meminfo.num_vifs = atoi(argv[3]);
411 launch_op.u.meminfo.cmd_line[0] = '\0';
412 cmd_len = 0;
413 for ( count = args_start; count < argc; count++ )
414 {
415 if ( cmd_len + strlen(argv[count]) > MAX_CMD_LEN - 1 )
416 {
417 ERROR("Size of image boot params too big!\n");
418 break;
419 }
420 strcat(launch_op.u.meminfo.cmd_line, argv[count]);
421 strcat(launch_op.u.meminfo.cmd_line, " ");
422 cmd_len += strlen(argv[count] + 1);
423 }
425 launch_op.cmd = DOM0_BUILDDOMAIN;
426 rc = do_dom0_op(&launch_op);
428 return (rc != 0) ? 1 : 0;
429 }