direct-io.hg

view tools/libxc/xc_linux_build.c @ 10297:8c64169a05d3

[TOOLS] Fix domain builder to carefully check that mapped memory area
does not overflow and wrap to zero.
Signed-off-by: Keir Fraser <keir@xensource.com>
author kaf24@firebug.cl.cam.ac.uk
date Thu Jun 08 09:52:04 2006 +0100 (2006-06-08)
parents f8af7041bf5b
children 1a52829fd60e b16063ae0703
line source
1 /******************************************************************************
2 * xc_linux_build.c
3 */
5 #include "xg_private.h"
6 #include "xc_private.h"
7 #include <xenctrl.h>
9 #include "xc_elf.h"
10 #include "xc_aout9.h"
11 #include <stdlib.h>
12 #include <unistd.h>
13 #include <inttypes.h>
14 #include <zlib.h>
16 #if defined(__i386__)
17 #define L1_PROT (_PAGE_PRESENT|_PAGE_RW|_PAGE_ACCESSED)
18 #define L2_PROT (_PAGE_PRESENT|_PAGE_RW|_PAGE_ACCESSED|_PAGE_DIRTY|_PAGE_USER)
19 #define L3_PROT (_PAGE_PRESENT)
20 #endif
22 #if defined(__x86_64__)
23 #define L1_PROT (_PAGE_PRESENT|_PAGE_RW|_PAGE_ACCESSED|_PAGE_USER)
24 #define L2_PROT (_PAGE_PRESENT|_PAGE_RW|_PAGE_ACCESSED|_PAGE_DIRTY|_PAGE_USER)
25 #define L3_PROT (_PAGE_PRESENT|_PAGE_RW|_PAGE_ACCESSED|_PAGE_DIRTY|_PAGE_USER)
26 #define L4_PROT (_PAGE_PRESENT|_PAGE_RW|_PAGE_ACCESSED|_PAGE_DIRTY|_PAGE_USER)
27 #endif
29 #ifdef __ia64__
30 #define get_tot_pages xc_get_max_pages
31 #else
32 #define get_tot_pages xc_get_tot_pages
33 #endif
35 #define round_pgup(_p) (((_p)+(PAGE_SIZE-1))&PAGE_MASK)
36 #define round_pgdown(_p) ((_p)&PAGE_MASK)
38 #ifdef __ia64__
39 #define probe_aout9(image,image_size,load_funcs) 1
40 #endif
42 struct initrd_info {
43 enum { INITRD_none, INITRD_file, INITRD_mem } type;
44 unsigned long len;
45 union {
46 gzFile file_handle;
47 char *mem_addr;
48 } u;
49 };
51 static const char *feature_names[XENFEAT_NR_SUBMAPS*32] = {
52 [XENFEAT_writable_page_tables] = "writable_page_tables",
53 [XENFEAT_writable_descriptor_tables] = "writable_descriptor_tables",
54 [XENFEAT_auto_translated_physmap] = "auto_translated_physmap",
55 [XENFEAT_supervisor_mode_kernel] = "supervisor_mode_kernel",
56 [XENFEAT_pae_pgdir_above_4gb] = "pae_pgdir_above_4gb"
57 };
59 static inline void set_feature_bit (int nr, uint32_t *addr)
60 {
61 addr[nr>>5] |= (1<<(nr&31));
62 }
64 static inline int test_feature_bit(int nr, uint32_t *addr)
65 {
66 return !!(addr[nr>>5] & (1<<(nr&31)));
67 }
69 static int parse_features(
70 const char *feats,
71 uint32_t supported[XENFEAT_NR_SUBMAPS],
72 uint32_t required[XENFEAT_NR_SUBMAPS])
73 {
74 const char *end, *p;
75 int i, req;
77 if ( (end = strchr(feats, ',')) == NULL )
78 end = feats + strlen(feats);
80 while ( feats < end )
81 {
82 p = strchr(feats, '|');
83 if ( (p == NULL) || (p > end) )
84 p = end;
86 req = (*feats == '!');
87 if ( req )
88 feats++;
90 for ( i = 0; i < XENFEAT_NR_SUBMAPS*32; i++ )
91 {
92 if ( feature_names[i] == NULL )
93 continue;
95 if ( strncmp(feature_names[i], feats, p-feats) == 0 )
96 {
97 set_feature_bit(i, supported);
98 if ( required && req )
99 set_feature_bit(i, required);
100 break;
101 }
102 }
104 if ( i == XENFEAT_NR_SUBMAPS*32 )
105 {
106 ERROR("Unknown feature \"%.*s\".", (int)(p-feats), feats);
107 if ( req )
108 {
109 ERROR("Kernel requires an unknown hypervisor feature.");
110 return -EINVAL;
111 }
112 }
114 feats = p;
115 if ( *feats == '|' )
116 feats++;
117 }
119 return -EINVAL;
120 }
122 static int probeimageformat(const char *image,
123 unsigned long image_size,
124 struct load_funcs *load_funcs)
125 {
126 if ( probe_elf(image, image_size, load_funcs) &&
127 probe_bin(image, image_size, load_funcs) &&
128 probe_aout9(image, image_size, load_funcs) )
129 {
130 ERROR( "Unrecognized image format" );
131 return -EINVAL;
132 }
134 return 0;
135 }
137 int load_initrd(int xc_handle, domid_t dom,
138 struct initrd_info *initrd,
139 unsigned long physbase,
140 xen_pfn_t *phys_to_mach)
141 {
142 char page[PAGE_SIZE];
143 unsigned long pfn_start, pfn, nr_pages;
145 if ( initrd->type == INITRD_none )
146 return 0;
148 pfn_start = physbase >> PAGE_SHIFT;
149 nr_pages = (initrd->len + PAGE_SIZE - 1) >> PAGE_SHIFT;
151 for ( pfn = pfn_start; pfn < (pfn_start + nr_pages); pfn++ )
152 {
153 if ( initrd->type == INITRD_mem )
154 {
155 xc_copy_to_domain_page(
156 xc_handle, dom, phys_to_mach[pfn],
157 &initrd->u.mem_addr[(pfn - pfn_start) << PAGE_SHIFT]);
158 }
159 else
160 {
161 if ( gzread(initrd->u.file_handle, page, PAGE_SIZE) == -1 )
162 {
163 PERROR("Error reading initrd image, could not");
164 return -EINVAL;
165 }
166 xc_copy_to_domain_page(xc_handle, dom, phys_to_mach[pfn], page);
167 }
168 }
170 return 0;
171 }
173 #define alloc_pt(ltab, vltab, pltab) \
174 do { \
175 pltab = ppt_alloc++; \
176 ltab = (uint64_t)page_array[pltab] << PAGE_SHIFT; \
177 pltab <<= PAGE_SHIFT; \
178 if ( vltab != NULL ) \
179 munmap(vltab, PAGE_SIZE); \
180 if ( (vltab = xc_map_foreign_range(xc_handle, dom, PAGE_SIZE, \
181 PROT_READ|PROT_WRITE, \
182 ltab >> PAGE_SHIFT)) == NULL ) \
183 goto error_out; \
184 memset(vltab, 0x0, PAGE_SIZE); \
185 } while ( 0 )
187 #if defined(__i386__)
189 static int setup_pg_tables(int xc_handle, uint32_t dom,
190 vcpu_guest_context_t *ctxt,
191 unsigned long dsi_v_start,
192 unsigned long v_end,
193 xen_pfn_t *page_array,
194 unsigned long vpt_start,
195 unsigned long vpt_end,
196 unsigned shadow_mode_enabled)
197 {
198 l1_pgentry_t *vl1tab=NULL, *vl1e=NULL;
199 l2_pgentry_t *vl2tab=NULL, *vl2e=NULL;
200 unsigned long l1tab = 0, pl1tab;
201 unsigned long l2tab = 0, pl2tab;
202 unsigned long ppt_alloc;
203 unsigned long count;
205 ppt_alloc = (vpt_start - dsi_v_start) >> PAGE_SHIFT;
206 alloc_pt(l2tab, vl2tab, pl2tab);
207 vl2e = &vl2tab[l2_table_offset(dsi_v_start)];
208 if (shadow_mode_enabled)
209 ctxt->ctrlreg[3] = xen_pfn_to_cr3(pl2tab >> PAGE_SHIFT);
210 else
211 ctxt->ctrlreg[3] = xen_pfn_to_cr3(l2tab >> PAGE_SHIFT);
213 for ( count = 0; count < ((v_end - dsi_v_start) >> PAGE_SHIFT); count++ )
214 {
215 if ( ((unsigned long)vl1e & (PAGE_SIZE-1)) == 0 )
216 {
217 alloc_pt(l1tab, vl1tab, pl1tab);
218 vl1e = &vl1tab[l1_table_offset(dsi_v_start + (count<<PAGE_SHIFT))];
219 if (shadow_mode_enabled)
220 *vl2e = pl1tab | L2_PROT;
221 else
222 *vl2e = l1tab | L2_PROT;
223 vl2e++;
224 }
226 if ( shadow_mode_enabled )
227 {
228 *vl1e = (count << PAGE_SHIFT) | L1_PROT;
229 }
230 else
231 {
232 *vl1e = (page_array[count] << PAGE_SHIFT) | L1_PROT;
233 if ( (count >= ((vpt_start-dsi_v_start)>>PAGE_SHIFT)) &&
234 (count < ((vpt_end -dsi_v_start)>>PAGE_SHIFT)) )
235 *vl1e &= ~_PAGE_RW;
236 }
237 vl1e++;
238 }
239 munmap(vl1tab, PAGE_SIZE);
240 munmap(vl2tab, PAGE_SIZE);
241 return 0;
243 error_out:
244 if (vl1tab)
245 munmap(vl1tab, PAGE_SIZE);
246 if (vl2tab)
247 munmap(vl2tab, PAGE_SIZE);
248 return -1;
249 }
251 static int setup_pg_tables_pae(int xc_handle, uint32_t dom,
252 vcpu_guest_context_t *ctxt,
253 unsigned long dsi_v_start,
254 unsigned long v_end,
255 xen_pfn_t *page_array,
256 unsigned long vpt_start,
257 unsigned long vpt_end,
258 unsigned shadow_mode_enabled,
259 unsigned pae_mode)
260 {
261 l1_pgentry_64_t *vl1tab = NULL, *vl1e = NULL;
262 l2_pgentry_64_t *vl2tab = NULL, *vl2e = NULL;
263 l3_pgentry_64_t *vl3tab = NULL, *vl3e = NULL;
264 uint64_t l1tab, l2tab, l3tab, pl1tab, pl2tab, pl3tab;
265 unsigned long ppt_alloc, count, nmfn;
267 /* First allocate page for page dir. */
268 ppt_alloc = (vpt_start - dsi_v_start) >> PAGE_SHIFT;
270 if ( pae_mode == PAEKERN_extended_cr3 )
271 {
272 ctxt->vm_assist |= (1UL << VMASST_TYPE_pae_extended_cr3);
273 }
274 else if ( page_array[ppt_alloc] > 0xfffff )
275 {
276 nmfn = xc_make_page_below_4G(xc_handle, dom, page_array[ppt_alloc]);
277 if ( nmfn == 0 )
278 {
279 DPRINTF("Couldn't get a page below 4GB :-(\n");
280 goto error_out;
281 }
282 page_array[ppt_alloc] = nmfn;
283 }
285 alloc_pt(l3tab, vl3tab, pl3tab);
286 vl3e = &vl3tab[l3_table_offset_pae(dsi_v_start)];
287 if (shadow_mode_enabled)
288 ctxt->ctrlreg[3] = xen_pfn_to_cr3(pl3tab >> PAGE_SHIFT);
289 else
290 ctxt->ctrlreg[3] = xen_pfn_to_cr3(l3tab >> PAGE_SHIFT);
292 for ( count = 0; count < ((v_end - dsi_v_start) >> PAGE_SHIFT); count++)
293 {
294 if ( !((unsigned long)vl1e & (PAGE_SIZE-1)) )
295 {
296 if ( !((unsigned long)vl2e & (PAGE_SIZE-1)) )
297 {
298 alloc_pt(l2tab, vl2tab, pl2tab);
299 vl2e = &vl2tab[l2_table_offset_pae(
300 dsi_v_start + (count << PAGE_SHIFT))];
301 if (shadow_mode_enabled)
302 *vl3e = pl2tab | L3_PROT;
303 else
304 *vl3e++ = l2tab | L3_PROT;
305 }
307 alloc_pt(l1tab, vl1tab, pl1tab);
308 vl1e = &vl1tab[l1_table_offset_pae(
309 dsi_v_start + (count << PAGE_SHIFT))];
310 if (shadow_mode_enabled)
311 *vl2e = pl1tab | L2_PROT;
312 else
313 *vl2e++ = l1tab | L2_PROT;
314 }
316 if ( shadow_mode_enabled )
317 {
318 *vl1e = (count << PAGE_SHIFT) | L1_PROT;
319 }
320 else
321 {
322 *vl1e = ((uint64_t)page_array[count] << PAGE_SHIFT) | L1_PROT;
323 if ( (count >= ((vpt_start-dsi_v_start)>>PAGE_SHIFT)) &&
324 (count < ((vpt_end -dsi_v_start)>>PAGE_SHIFT)) )
325 *vl1e &= ~_PAGE_RW;
326 }
327 vl1e++;
328 }
330 /* Xen requires a mid-level pgdir mapping 0xC0000000 region. */
331 if ( (vl3tab[3] & _PAGE_PRESENT) == 0 )
332 {
333 alloc_pt(l2tab, vl2tab, pl2tab);
334 vl3tab[3] = l2tab | L3_PROT;
335 }
337 munmap(vl1tab, PAGE_SIZE);
338 munmap(vl2tab, PAGE_SIZE);
339 munmap(vl3tab, PAGE_SIZE);
340 return 0;
342 error_out:
343 if (vl1tab)
344 munmap(vl1tab, PAGE_SIZE);
345 if (vl2tab)
346 munmap(vl2tab, PAGE_SIZE);
347 if (vl3tab)
348 munmap(vl3tab, PAGE_SIZE);
349 return -1;
350 }
352 #endif
354 #if defined(__x86_64__)
356 static int setup_pg_tables_64(int xc_handle, uint32_t dom,
357 vcpu_guest_context_t *ctxt,
358 unsigned long dsi_v_start,
359 unsigned long v_end,
360 xen_pfn_t *page_array,
361 unsigned long vpt_start,
362 unsigned long vpt_end,
363 int shadow_mode_enabled)
364 {
365 l1_pgentry_t *vl1tab=NULL, *vl1e=NULL;
366 l2_pgentry_t *vl2tab=NULL, *vl2e=NULL;
367 l3_pgentry_t *vl3tab=NULL, *vl3e=NULL;
368 l4_pgentry_t *vl4tab=NULL, *vl4e=NULL;
369 unsigned long l2tab = 0, pl2tab;
370 unsigned long l1tab = 0, pl1tab;
371 unsigned long l3tab = 0, pl3tab;
372 unsigned long l4tab = 0, pl4tab;
373 unsigned long ppt_alloc;
374 unsigned long count;
376 /* First allocate page for page dir. */
377 ppt_alloc = (vpt_start - dsi_v_start) >> PAGE_SHIFT;
378 alloc_pt(l4tab, vl4tab, pl4tab);
379 vl4e = &vl4tab[l4_table_offset(dsi_v_start)];
380 if (shadow_mode_enabled)
381 ctxt->ctrlreg[3] = xen_pfn_to_cr3(pl4tab >> PAGE_SHIFT);
382 else
383 ctxt->ctrlreg[3] = xen_pfn_to_cr3(l4tab >> PAGE_SHIFT);
385 for ( count = 0; count < ((v_end-dsi_v_start)>>PAGE_SHIFT); count++)
386 {
387 if ( !((unsigned long)vl1e & (PAGE_SIZE-1)) )
388 {
389 alloc_pt(l1tab, vl1tab, pl1tab);
391 if ( !((unsigned long)vl2e & (PAGE_SIZE-1)) )
392 {
393 alloc_pt(l2tab, vl2tab, pl2tab);
394 if ( !((unsigned long)vl3e & (PAGE_SIZE-1)) )
395 {
396 alloc_pt(l3tab, vl3tab, pl3tab);
397 vl3e = &vl3tab[l3_table_offset(dsi_v_start + (count<<PAGE_SHIFT))];
398 if (shadow_mode_enabled)
399 *vl4e = pl3tab | L4_PROT;
400 else
401 *vl4e = l3tab | L4_PROT;
402 vl4e++;
403 }
404 vl2e = &vl2tab[l2_table_offset(dsi_v_start + (count<<PAGE_SHIFT))];
405 if (shadow_mode_enabled)
406 *vl3e = pl2tab | L3_PROT;
407 else
408 *vl3e = l2tab | L3_PROT;
409 vl3e++;
410 }
411 vl1e = &vl1tab[l1_table_offset(dsi_v_start + (count<<PAGE_SHIFT))];
412 if (shadow_mode_enabled)
413 *vl2e = pl1tab | L2_PROT;
414 else
415 *vl2e = l1tab | L2_PROT;
416 vl2e++;
417 }
419 if ( shadow_mode_enabled )
420 {
421 *vl1e = (count << PAGE_SHIFT) | L1_PROT;
422 }
423 else
424 {
425 *vl1e = (page_array[count] << PAGE_SHIFT) | L1_PROT;
426 if ( (count >= ((vpt_start-dsi_v_start)>>PAGE_SHIFT)) &&
427 (count < ((vpt_end -dsi_v_start)>>PAGE_SHIFT)) )
428 {
429 *vl1e &= ~_PAGE_RW;
430 }
431 }
432 vl1e++;
433 }
435 munmap(vl1tab, PAGE_SIZE);
436 munmap(vl2tab, PAGE_SIZE);
437 munmap(vl3tab, PAGE_SIZE);
438 munmap(vl4tab, PAGE_SIZE);
439 return 0;
441 error_out:
442 if (vl1tab)
443 munmap(vl1tab, PAGE_SIZE);
444 if (vl2tab)
445 munmap(vl2tab, PAGE_SIZE);
446 if (vl3tab)
447 munmap(vl3tab, PAGE_SIZE);
448 if (vl4tab)
449 munmap(vl4tab, PAGE_SIZE);
450 return -1;
451 }
452 #endif
454 #ifdef __ia64__
455 extern unsigned long xc_ia64_fpsr_default(void);
457 static int setup_guest(int xc_handle,
458 uint32_t dom,
459 const char *image, unsigned long image_size,
460 struct initrd_info *initrd,
461 unsigned long nr_pages,
462 unsigned long *pvsi, unsigned long *pvke,
463 unsigned long *pvss, vcpu_guest_context_t *ctxt,
464 const char *cmdline,
465 unsigned long shared_info_frame,
466 unsigned long flags,
467 unsigned int store_evtchn, unsigned long *store_mfn,
468 unsigned int console_evtchn, unsigned long *console_mfn,
469 uint32_t required_features[XENFEAT_NR_SUBMAPS])
470 {
471 xen_pfn_t *page_array = NULL;
472 struct load_funcs load_funcs;
473 struct domain_setup_info dsi;
474 unsigned long vinitrd_start;
475 unsigned long vinitrd_end;
476 unsigned long v_end;
477 unsigned long start_page, pgnr;
478 start_info_t *start_info;
479 int rc;
481 rc = probeimageformat(image, image_size, &load_funcs);
482 if ( rc != 0 )
483 goto error_out;
485 memset(&dsi, 0, sizeof(struct domain_setup_info));
487 rc = (load_funcs.parseimage)(image, image_size, &dsi);
488 if ( rc != 0 )
489 goto error_out;
491 dsi.v_start = round_pgdown(dsi.v_start);
492 vinitrd_start = round_pgup(dsi.v_end);
493 vinitrd_end = vinitrd_start + initrd->len;
494 v_end = round_pgup(vinitrd_end);
496 start_page = dsi.v_start >> PAGE_SHIFT;
497 pgnr = (v_end - dsi.v_start) >> PAGE_SHIFT;
498 if ( (page_array = malloc(pgnr * sizeof(xen_pfn_t))) == NULL )
499 {
500 PERROR("Could not allocate memory");
501 goto error_out;
502 }
504 if ( xc_ia64_get_pfn_list(xc_handle, dom, page_array,
505 start_page, pgnr) != pgnr )
506 {
507 PERROR("Could not get the page frame list");
508 goto error_out;
509 }
511 #define _p(a) ((void *) (a))
513 IPRINTF("VIRTUAL MEMORY ARRANGEMENT:\n"
514 " Loaded kernel: %p->%p\n"
515 " Init. ramdisk: %p->%p\n"
516 " TOTAL: %p->%p\n",
517 _p(dsi.v_kernstart), _p(dsi.v_kernend),
518 _p(vinitrd_start), _p(vinitrd_end),
519 _p(dsi.v_start), _p(v_end));
520 IPRINTF(" ENTRY ADDRESS: %p\n", _p(dsi.v_kernentry));
522 (load_funcs.loadimage)(image, image_size, xc_handle, dom, page_array,
523 &dsi);
525 if ( load_initrd(xc_handle, dom, initrd,
526 vinitrd_start - dsi.v_start, page_array) )
527 goto error_out;
529 *pvke = dsi.v_kernentry;
531 /* Now need to retrieve machine pfn for system pages:
532 * start_info/store/console
533 */
534 pgnr = 3;
535 if ( xc_ia64_get_pfn_list(xc_handle, dom, page_array,
536 nr_pages - 3, pgnr) != pgnr )
537 {
538 PERROR("Could not get page frame for xenstore");
539 goto error_out;
540 }
542 *store_mfn = page_array[1];
543 *console_mfn = page_array[2];
544 IPRINTF("start_info: 0x%lx at 0x%lx, "
545 "store_mfn: 0x%lx at 0x%lx, "
546 "console_mfn: 0x%lx at 0x%lx\n",
547 page_array[0], nr_pages,
548 *store_mfn, nr_pages - 2,
549 *console_mfn, nr_pages - 1);
551 start_info = xc_map_foreign_range(
552 xc_handle, dom, PAGE_SIZE, PROT_READ|PROT_WRITE, page_array[0]);
553 memset(start_info, 0, sizeof(*start_info));
554 rc = xc_version(xc_handle, XENVER_version, NULL);
555 sprintf(start_info->magic, "xen-%i.%i-ia64", rc >> 16, rc & (0xFFFF));
556 start_info->flags = flags;
557 start_info->store_mfn = nr_pages - 2;
558 start_info->store_evtchn = store_evtchn;
559 start_info->console_mfn = nr_pages - 1;
560 start_info->console_evtchn = console_evtchn;
561 start_info->nr_pages = nr_pages; // FIXME?: nr_pages - 2 ????
562 if ( initrd->len != 0 )
563 {
564 ctxt->initrd.start = vinitrd_start;
565 ctxt->initrd.size = initrd->len;
566 }
567 else
568 {
569 ctxt->initrd.start = 0;
570 ctxt->initrd.size = 0;
571 }
572 if ( cmdline != NULL )
573 {
574 strncpy((char *)ctxt->cmdline, cmdline, IA64_COMMAND_LINE_SIZE);
575 ctxt->cmdline[IA64_COMMAND_LINE_SIZE-1] = '\0';
576 }
577 munmap(start_info, PAGE_SIZE);
579 free(page_array);
580 return 0;
582 error_out:
583 free(page_array);
584 return -1;
585 }
586 #else /* x86 */
588 /* Check if the platform supports the guest kernel format */
589 static int compat_check(int xc_handle, struct domain_setup_info *dsi)
590 {
591 xen_capabilities_info_t xen_caps = "";
593 if (xc_version(xc_handle, XENVER_capabilities, &xen_caps) != 0) {
594 ERROR("Cannot determine host capabilities.");
595 return 0;
596 }
598 if (strstr(xen_caps, "xen-3.0-x86_32p")) {
599 if (dsi->pae_kernel == PAEKERN_no) {
600 ERROR("Non PAE-kernel on PAE host.");
601 return 0;
602 }
603 } else if (dsi->pae_kernel != PAEKERN_no) {
604 ERROR("PAE-kernel on non-PAE host.");
605 return 0;
606 }
608 return 1;
609 }
611 static inline int increment_ulong(unsigned long *pval, unsigned long inc)
612 {
613 if ( inc >= -*pval )
614 {
615 ERROR("Value wrapped to zero: image too large?");
616 return 0;
617 }
618 *pval += inc;
619 return 1;
620 }
622 static int setup_guest(int xc_handle,
623 uint32_t dom,
624 const char *image, unsigned long image_size,
625 struct initrd_info *initrd,
626 unsigned long nr_pages,
627 unsigned long *pvsi, unsigned long *pvke,
628 unsigned long *pvss, vcpu_guest_context_t *ctxt,
629 const char *cmdline,
630 unsigned long shared_info_frame,
631 unsigned long flags,
632 unsigned int store_evtchn, unsigned long *store_mfn,
633 unsigned int console_evtchn, unsigned long *console_mfn,
634 uint32_t required_features[XENFEAT_NR_SUBMAPS])
635 {
636 xen_pfn_t *page_array = NULL;
637 unsigned long count, i, hypercall_pfn;
638 start_info_t *start_info;
639 shared_info_t *shared_info;
640 xc_mmu_t *mmu = NULL;
641 char *p;
642 DECLARE_DOM0_OP;
643 int rc;
645 unsigned long nr_pt_pages;
646 unsigned long physmap_pfn;
647 xen_pfn_t *physmap, *physmap_e;
649 struct load_funcs load_funcs;
650 struct domain_setup_info dsi;
651 unsigned long vinitrd_start;
652 unsigned long vphysmap_start;
653 unsigned long vstartinfo_start;
654 unsigned long vstoreinfo_start;
655 unsigned long vconsole_start;
656 unsigned long vsharedinfo_start = 0; /* XXX gcc */
657 unsigned long vstack_start;
658 unsigned long vstack_end;
659 unsigned long vpt_start;
660 unsigned long vpt_end;
661 unsigned long v_end;
662 unsigned long guest_store_mfn, guest_console_mfn, guest_shared_info_mfn;
663 unsigned long shadow_mode_enabled;
664 uint32_t supported_features[XENFEAT_NR_SUBMAPS] = { 0, };
666 rc = probeimageformat(image, image_size, &load_funcs);
667 if ( rc != 0 )
668 goto error_out;
670 memset(&dsi, 0, sizeof(struct domain_setup_info));
672 rc = (load_funcs.parseimage)(image, image_size, &dsi);
673 if ( rc != 0 )
674 goto error_out;
676 if ( (dsi.v_start & (PAGE_SIZE-1)) != 0 )
677 {
678 PERROR("Guest OS must load to a page boundary.");
679 goto error_out;
680 }
682 if (!compat_check(xc_handle, &dsi))
683 goto error_out;
685 /* Parse and validate kernel features. */
686 p = strstr(dsi.xen_guest_string, "FEATURES=");
687 if ( p != NULL )
688 {
689 if ( !parse_features(p + strlen("FEATURES="),
690 supported_features,
691 required_features) )
692 {
693 ERROR("Failed to parse guest kernel features.");
694 goto error_out;
695 }
697 IPRINTF("Supported features = { %08x }.\n", supported_features[0]);
698 IPRINTF("Required features = { %08x }.\n", required_features[0]);
699 }
701 for ( i = 0; i < XENFEAT_NR_SUBMAPS; i++ )
702 {
703 if ( (supported_features[i] & required_features[i]) !=
704 required_features[i] )
705 {
706 ERROR("Guest kernel does not support a required feature.");
707 goto error_out;
708 }
709 }
711 shadow_mode_enabled = test_feature_bit(XENFEAT_auto_translated_physmap,
712 required_features);
714 /*
715 * Why do we need this? The number of page-table frames depends on the
716 * size of the bootstrap address space. But the size of the address space
717 * depends on the number of page-table frames (since each one is mapped
718 * read-only). We have a pair of simultaneous equations in two unknowns,
719 * which we solve by exhaustive search.
720 */
721 v_end = round_pgup(dsi.v_end);
722 if ( v_end == 0 )
723 {
724 ERROR("End of mapped kernel image too close to end of memory");
725 goto error_out;
726 }
727 vinitrd_start = v_end;
728 if ( !increment_ulong(&v_end, round_pgup(initrd->len)) )
729 goto error_out;
730 vphysmap_start = v_end;
731 if ( !increment_ulong(&v_end, round_pgup(nr_pages * sizeof(long))) )
732 goto error_out;
733 vstartinfo_start = v_end;
734 if ( !increment_ulong(&v_end, PAGE_SIZE) )
735 goto error_out;
736 vstoreinfo_start = v_end;
737 if ( !increment_ulong(&v_end, PAGE_SIZE) )
738 goto error_out;
739 vconsole_start = v_end;
740 if ( !increment_ulong(&v_end, PAGE_SIZE) )
741 goto error_out;
742 if ( shadow_mode_enabled ) {
743 vsharedinfo_start = v_end;
744 if ( !increment_ulong(&v_end, PAGE_SIZE) )
745 goto error_out;
746 }
747 vpt_start = v_end;
749 for ( nr_pt_pages = 2; ; nr_pt_pages++ )
750 {
751 /* vpt_end = vpt_staret + (nr_pt_pages * PAGE_SIZE); */
752 vpt_end = vpt_start;
753 if ( !increment_ulong(&vpt_end, nr_pt_pages * PAGE_SIZE) )
754 goto error_out;
756 vstack_start = vpt_end;
757 /* vstack_end = vstack_start + PAGE_SIZE; */
758 vstack_end = vstack_start;
759 if ( !increment_ulong(&vstack_end, PAGE_SIZE) )
760 goto error_out;
762 /* v_end = (vstack_end + (1UL<<22)-1) & ~((1UL<<22)-1); */
763 v_end = vstack_end;
764 if ( !increment_ulong(&v_end, (1UL<<22)-1) )
765 goto error_out;
766 v_end &= ~((1UL<<22)-1);
768 if ( (v_end - vstack_end) < (512UL << 10) )
769 {
770 /* Add extra 4MB to get >= 512kB padding. */
771 if ( !increment_ulong(&v_end, 1UL << 22) )
772 goto error_out;
773 }
775 #define NR(_l,_h,_s) \
776 (((((_h) + ((1UL<<(_s))-1)) & ~((1UL<<(_s))-1)) - \
777 ((_l) & ~((1UL<<(_s))-1))) >> (_s))
778 #if defined(__i386__)
779 if ( dsi.pae_kernel != PAEKERN_no )
780 {
781 if ( (1 + /* # L3 */
782 NR(dsi.v_start, v_end, L3_PAGETABLE_SHIFT_PAE) + /* # L2 */
783 NR(dsi.v_start, v_end, L2_PAGETABLE_SHIFT_PAE) + /* # L1 */
784 /* Include a fourth mid-level page directory for Xen. */
785 (v_end <= (3 << L3_PAGETABLE_SHIFT_PAE)))
786 <= nr_pt_pages )
787 break;
788 }
789 else
790 {
791 if ( (1 + /* # L2 */
792 NR(dsi.v_start, v_end, L2_PAGETABLE_SHIFT)) /* # L1 */
793 <= nr_pt_pages )
794 break;
795 }
796 #elif defined(__x86_64__)
797 if ( (1 + /* # L4 */
798 NR(dsi.v_start, v_end, L4_PAGETABLE_SHIFT) + /* # L3 */
799 NR(dsi.v_start, v_end, L3_PAGETABLE_SHIFT) + /* # L2 */
800 NR(dsi.v_start, v_end, L2_PAGETABLE_SHIFT)) /* # L1 */
801 <= nr_pt_pages )
802 break;
803 #endif
804 }
806 #define _p(a) ((void *) (a))
808 IPRINTF("VIRTUAL MEMORY ARRANGEMENT:\n");
809 IPRINTF(" Loaded kernel: %p->%p\n", _p(dsi.v_kernstart),
810 _p(dsi.v_kernend));
811 if ( initrd->len )
812 IPRINTF(" Initial ramdisk: %p->%p\n", _p(vinitrd_start),
813 _p(vinitrd_start + initrd->len));
814 IPRINTF(" Phys-Mach map: %p\n", _p(vphysmap_start));
815 IPRINTF(" Start info: %p\n", _p(vstartinfo_start));
816 IPRINTF(" Store page: %p\n", _p(vstoreinfo_start));
817 IPRINTF(" Console page: %p\n", _p(vconsole_start));
818 if ( shadow_mode_enabled )
819 IPRINTF(" Shared Info page: %p\n", _p(vsharedinfo_start));
820 IPRINTF(" Page tables: %p\n", _p(vpt_start));
821 IPRINTF(" Boot stack: %p\n", _p(vstack_start));
822 IPRINTF(" TOTAL: %p->%p\n", _p(dsi.v_start), _p(v_end));
823 IPRINTF(" ENTRY ADDRESS: %p\n", _p(dsi.v_kernentry));
825 if ( ((v_end - dsi.v_start)>>PAGE_SHIFT) > nr_pages )
826 {
827 PERROR("Initial guest OS requires too much space\n"
828 "(%luMB is greater than %luMB limit)\n",
829 (v_end-dsi.v_start)>>20, nr_pages>>(20-PAGE_SHIFT));
830 goto error_out;
831 }
833 if ( (page_array = malloc(nr_pages * sizeof(unsigned long))) == NULL )
834 {
835 PERROR("Could not allocate memory");
836 goto error_out;
837 }
839 if ( xc_get_pfn_list(xc_handle, dom, page_array, nr_pages) != nr_pages )
840 {
841 PERROR("Could not get the page frame list");
842 goto error_out;
843 }
845 rc = (load_funcs.loadimage)(image, image_size,
846 xc_handle, dom, page_array,
847 &dsi);
848 if ( rc != 0 )
849 goto error_out;
851 if ( load_initrd(xc_handle, dom, initrd,
852 vinitrd_start - dsi.v_start, page_array) )
853 goto error_out;
855 /* setup page tables */
856 #if defined(__i386__)
857 if (dsi.pae_kernel != PAEKERN_no)
858 rc = setup_pg_tables_pae(xc_handle, dom, ctxt,
859 dsi.v_start, v_end,
860 page_array, vpt_start, vpt_end,
861 shadow_mode_enabled, dsi.pae_kernel);
862 else
863 rc = setup_pg_tables(xc_handle, dom, ctxt,
864 dsi.v_start, v_end,
865 page_array, vpt_start, vpt_end,
866 shadow_mode_enabled);
867 #endif
868 #if defined(__x86_64__)
869 rc = setup_pg_tables_64(xc_handle, dom, ctxt,
870 dsi.v_start, v_end,
871 page_array, vpt_start, vpt_end,
872 shadow_mode_enabled);
873 #endif
874 if (0 != rc)
875 goto error_out;
877 #if defined(__i386__)
878 /*
879 * Pin down l2tab addr as page dir page - causes hypervisor to provide
880 * correct protection for the page
881 */
882 if ( !shadow_mode_enabled )
883 {
884 if ( dsi.pae_kernel != PAEKERN_no )
885 {
886 if ( pin_table(xc_handle, MMUEXT_PIN_L3_TABLE,
887 xen_cr3_to_pfn(ctxt->ctrlreg[3]), dom) )
888 goto error_out;
889 }
890 else
891 {
892 if ( pin_table(xc_handle, MMUEXT_PIN_L2_TABLE,
893 xen_cr3_to_pfn(ctxt->ctrlreg[3]), dom) )
894 goto error_out;
895 }
896 }
897 #endif
899 #if defined(__x86_64__)
900 /*
901 * Pin down l4tab addr as page dir page - causes hypervisor to provide
902 * correct protection for the page
903 */
904 if ( pin_table(xc_handle, MMUEXT_PIN_L4_TABLE,
905 xen_cr3_to_pfn(ctxt->ctrlreg[3]), dom) )
906 goto error_out;
907 #endif
909 if ( (mmu = xc_init_mmu_updates(xc_handle, dom)) == NULL )
910 goto error_out;
912 /* Write the phys->machine and machine->phys table entries. */
913 physmap_pfn = (vphysmap_start - dsi.v_start) >> PAGE_SHIFT;
914 physmap = physmap_e = xc_map_foreign_range(
915 xc_handle, dom, PAGE_SIZE, PROT_READ|PROT_WRITE,
916 page_array[physmap_pfn++]);
918 for ( count = 0; count < nr_pages; count++ )
919 {
920 if ( xc_add_mmu_update(
921 xc_handle, mmu,
922 ((uint64_t)page_array[count] << PAGE_SHIFT) | MMU_MACHPHYS_UPDATE,
923 count) )
924 {
925 DPRINTF("m2p update failure p=%lx m=%"PRIx64"\n",
926 count, (uint64_t)page_array[count]);
927 munmap(physmap, PAGE_SIZE);
928 goto error_out;
929 }
930 *physmap_e++ = page_array[count];
931 if ( ((unsigned long)physmap_e & (PAGE_SIZE-1)) == 0 )
932 {
933 munmap(physmap, PAGE_SIZE);
934 physmap = physmap_e = xc_map_foreign_range(
935 xc_handle, dom, PAGE_SIZE, PROT_READ|PROT_WRITE,
936 page_array[physmap_pfn++]);
937 }
938 }
939 munmap(physmap, PAGE_SIZE);
941 /* Send the page update requests down to the hypervisor. */
942 if ( xc_finish_mmu_updates(xc_handle, mmu) )
943 goto error_out;
945 if ( shadow_mode_enabled )
946 {
947 struct xen_add_to_physmap xatp;
949 /* Enable shadow translate mode */
950 if ( xc_shadow_control(xc_handle, dom,
951 DOM0_SHADOW_CONTROL_OP_ENABLE_TRANSLATE,
952 NULL, 0, NULL) < 0 )
953 {
954 PERROR("Could not enable translation mode");
955 goto error_out;
956 }
958 guest_shared_info_mfn = (vsharedinfo_start-dsi.v_start) >> PAGE_SHIFT;
960 /* Map shared info frame into guest physmap. */
961 xatp.domid = dom;
962 xatp.space = XENMAPSPACE_shared_info;
963 xatp.idx = 0;
964 xatp.gpfn = guest_shared_info_mfn;
965 rc = xc_memory_op(xc_handle, XENMEM_add_to_physmap, &xatp);
966 if ( rc != 0 )
967 {
968 PERROR("Cannot map shared info pfn");
969 goto error_out;
970 }
972 /* Map grant table frames into guest physmap. */
973 for ( i = 0; ; i++ )
974 {
975 xatp.domid = dom;
976 xatp.space = XENMAPSPACE_grant_table;
977 xatp.idx = i;
978 xatp.gpfn = nr_pages + i;
979 rc = xc_memory_op(xc_handle, XENMEM_add_to_physmap, &xatp);
980 if ( rc != 0 )
981 {
982 if ( errno == EINVAL )
983 break; /* done all grant tables */
984 PERROR("Cannot map grant table pfn");
985 goto error_out;
986 }
987 }
988 }
989 else
990 {
991 guest_shared_info_mfn = shared_info_frame;
992 }
994 *store_mfn = page_array[(vstoreinfo_start-dsi.v_start) >> PAGE_SHIFT];
995 *console_mfn = page_array[(vconsole_start-dsi.v_start) >> PAGE_SHIFT];
996 if ( xc_clear_domain_page(xc_handle, dom, *store_mfn) ||
997 xc_clear_domain_page(xc_handle, dom, *console_mfn) )
998 goto error_out;
999 if ( shadow_mode_enabled )
1001 guest_store_mfn = (vstoreinfo_start-dsi.v_start) >> PAGE_SHIFT;
1002 guest_console_mfn = (vconsole_start-dsi.v_start) >> PAGE_SHIFT;
1004 else
1006 guest_store_mfn = *store_mfn;
1007 guest_console_mfn = *console_mfn;
1010 start_info = xc_map_foreign_range(
1011 xc_handle, dom, PAGE_SIZE, PROT_READ|PROT_WRITE,
1012 page_array[(vstartinfo_start-dsi.v_start)>>PAGE_SHIFT]);
1013 /*shared_info, start_info */
1014 memset(start_info, 0, sizeof(*start_info));
1015 rc = xc_version(xc_handle, XENVER_version, NULL);
1016 sprintf(start_info->magic, "xen-%i.%i-x86_%d%s",
1017 rc >> 16, rc & (0xFFFF), (unsigned int)sizeof(long)*8,
1018 (dsi.pae_kernel != PAEKERN_no) ? "p" : "");
1019 start_info->nr_pages = nr_pages;
1020 start_info->shared_info = guest_shared_info_mfn << PAGE_SHIFT;
1021 start_info->flags = flags;
1022 start_info->pt_base = vpt_start;
1023 start_info->nr_pt_frames = nr_pt_pages;
1024 start_info->mfn_list = vphysmap_start;
1025 start_info->store_mfn = guest_store_mfn;
1026 start_info->store_evtchn = store_evtchn;
1027 start_info->console_mfn = guest_console_mfn;
1028 start_info->console_evtchn = console_evtchn;
1029 if ( initrd->len != 0 )
1031 start_info->mod_start = vinitrd_start;
1032 start_info->mod_len = initrd->len;
1034 if ( cmdline != NULL )
1036 strncpy((char *)start_info->cmd_line, cmdline, MAX_GUEST_CMDLINE);
1037 start_info->cmd_line[MAX_GUEST_CMDLINE-1] = '\0';
1039 munmap(start_info, PAGE_SIZE);
1041 /* shared_info page starts its life empty. */
1042 shared_info = xc_map_foreign_range(
1043 xc_handle, dom, PAGE_SIZE, PROT_READ|PROT_WRITE, shared_info_frame);
1044 memset(shared_info, 0, sizeof(shared_info_t));
1045 /* Mask all upcalls... */
1046 for ( i = 0; i < MAX_VIRT_CPUS; i++ )
1047 shared_info->vcpu_info[i].evtchn_upcall_mask = 1;
1049 munmap(shared_info, PAGE_SIZE);
1051 /* Send the page update requests down to the hypervisor. */
1052 if ( xc_finish_mmu_updates(xc_handle, mmu) )
1053 goto error_out;
1055 p = strstr(dsi.xen_guest_string, "HYPERCALL_PAGE=");
1056 if ( p != NULL )
1058 p += strlen("HYPERCALL_PAGE=");
1059 hypercall_pfn = strtoul(p, NULL, 16);
1060 if ( hypercall_pfn >= nr_pages )
1061 goto error_out;
1062 op.u.hypercall_init.domain = (domid_t)dom;
1063 op.u.hypercall_init.mfn = page_array[hypercall_pfn];
1064 op.cmd = DOM0_HYPERCALL_INIT;
1065 if ( xc_dom0_op(xc_handle, &op) )
1066 goto error_out;
1069 free(mmu);
1070 free(page_array);
1072 *pvsi = vstartinfo_start;
1073 *pvss = vstack_start;
1074 *pvke = dsi.v_kernentry;
1076 return 0;
1078 error_out:
1079 free(mmu);
1080 free(page_array);
1081 return -1;
1083 #endif
1085 static int xc_linux_build_internal(int xc_handle,
1086 uint32_t domid,
1087 char *image,
1088 unsigned long image_size,
1089 struct initrd_info *initrd,
1090 const char *cmdline,
1091 const char *features,
1092 unsigned long flags,
1093 unsigned int store_evtchn,
1094 unsigned long *store_mfn,
1095 unsigned int console_evtchn,
1096 unsigned long *console_mfn)
1098 dom0_op_t launch_op;
1099 DECLARE_DOM0_OP;
1100 int rc, i;
1101 vcpu_guest_context_t st_ctxt, *ctxt = &st_ctxt;
1102 unsigned long nr_pages;
1103 unsigned long vstartinfo_start, vkern_entry, vstack_start;
1104 uint32_t features_bitmap[XENFEAT_NR_SUBMAPS] = { 0, };
1106 if ( features != NULL )
1108 if ( !parse_features(features, features_bitmap, NULL) )
1110 PERROR("Failed to parse configured features\n");
1111 goto error_out;
1115 if ( (nr_pages = get_tot_pages(xc_handle, domid)) < 0 )
1117 PERROR("Could not find total pages for domain");
1118 goto error_out;
1121 #ifdef VALGRIND
1122 memset(&st_ctxt, 0, sizeof(st_ctxt));
1123 #endif
1125 if ( mlock(&st_ctxt, sizeof(st_ctxt) ) )
1127 PERROR("%s: ctxt mlock failed", __func__);
1128 return 1;
1131 op.cmd = DOM0_GETDOMAININFO;
1132 op.u.getdomaininfo.domain = (domid_t)domid;
1133 if ( (xc_dom0_op(xc_handle, &op) < 0) ||
1134 ((uint16_t)op.u.getdomaininfo.domain != domid) )
1136 PERROR("Could not get info on domain");
1137 goto error_out;
1140 memset(ctxt, 0, sizeof(*ctxt));
1142 if ( setup_guest(xc_handle, domid, image, image_size,
1143 initrd,
1144 nr_pages,
1145 &vstartinfo_start, &vkern_entry,
1146 &vstack_start, ctxt, cmdline,
1147 op.u.getdomaininfo.shared_info_frame,
1148 flags, store_evtchn, store_mfn,
1149 console_evtchn, console_mfn,
1150 features_bitmap) < 0 )
1152 ERROR("Error constructing guest OS");
1153 goto error_out;
1156 #ifdef __ia64__
1157 /* based on new_thread in xen/arch/ia64/domain.c */
1158 ctxt->flags = 0;
1159 ctxt->shared.flags = flags;
1160 ctxt->shared.start_info_pfn = nr_pages - 3; /* metaphysical */
1161 ctxt->regs.cr_ipsr = 0; /* all necessary bits filled by hypervisor */
1162 ctxt->regs.cr_iip = vkern_entry;
1163 ctxt->regs.cr_ifs = 1UL << 63;
1164 ctxt->regs.ar_fpsr = xc_ia64_fpsr_default();
1165 /* currently done by hypervisor, should move here */
1166 /* ctxt->regs.r28 = dom_fw_setup(); */
1167 ctxt->privregs = 0;
1168 ctxt->sys_pgnr = 3;
1169 i = 0; /* silence unused variable warning */
1170 #else /* x86 */
1171 /*
1172 * Initial register values:
1173 * DS,ES,FS,GS = FLAT_KERNEL_DS
1174 * CS:EIP = FLAT_KERNEL_CS:start_pc
1175 * SS:ESP = FLAT_KERNEL_DS:start_stack
1176 * ESI = start_info
1177 * [EAX,EBX,ECX,EDX,EDI,EBP are zero]
1178 * EFLAGS = IF | 2 (bit 1 is reserved and should always be 1)
1179 */
1180 ctxt->user_regs.ds = FLAT_KERNEL_DS;
1181 ctxt->user_regs.es = FLAT_KERNEL_DS;
1182 ctxt->user_regs.fs = FLAT_KERNEL_DS;
1183 ctxt->user_regs.gs = FLAT_KERNEL_DS;
1184 ctxt->user_regs.ss = FLAT_KERNEL_SS;
1185 ctxt->user_regs.cs = FLAT_KERNEL_CS;
1186 ctxt->user_regs.eip = vkern_entry;
1187 ctxt->user_regs.esp = vstack_start + PAGE_SIZE;
1188 ctxt->user_regs.esi = vstartinfo_start;
1189 ctxt->user_regs.eflags = 1 << 9; /* Interrupt Enable */
1191 ctxt->flags = VGCF_IN_KERNEL;
1193 /* FPU is set up to default initial state. */
1194 memset(&ctxt->fpu_ctxt, 0, sizeof(ctxt->fpu_ctxt));
1196 /* Virtual IDT is empty at start-of-day. */
1197 for ( i = 0; i < 256; i++ )
1199 ctxt->trap_ctxt[i].vector = i;
1200 ctxt->trap_ctxt[i].cs = FLAT_KERNEL_CS;
1203 /* No LDT. */
1204 ctxt->ldt_ents = 0;
1206 /* Use the default Xen-provided GDT. */
1207 ctxt->gdt_ents = 0;
1209 /* Ring 1 stack is the initial stack. */
1210 ctxt->kernel_ss = FLAT_KERNEL_SS;
1211 ctxt->kernel_sp = vstack_start + PAGE_SIZE;
1213 /* No debugging. */
1214 memset(ctxt->debugreg, 0, sizeof(ctxt->debugreg));
1216 /* No callback handlers. */
1217 #if defined(__i386__)
1218 ctxt->event_callback_cs = FLAT_KERNEL_CS;
1219 ctxt->event_callback_eip = 0;
1220 ctxt->failsafe_callback_cs = FLAT_KERNEL_CS;
1221 ctxt->failsafe_callback_eip = 0;
1222 #elif defined(__x86_64__)
1223 ctxt->event_callback_eip = 0;
1224 ctxt->failsafe_callback_eip = 0;
1225 ctxt->syscall_callback_eip = 0;
1226 #endif
1227 #endif /* x86 */
1229 memset( &launch_op, 0, sizeof(launch_op) );
1231 launch_op.u.setvcpucontext.domain = (domid_t)domid;
1232 launch_op.u.setvcpucontext.vcpu = 0;
1233 set_xen_guest_handle(launch_op.u.setvcpucontext.ctxt, ctxt);
1235 launch_op.cmd = DOM0_SETVCPUCONTEXT;
1236 rc = xc_dom0_op(xc_handle, &launch_op);
1238 return rc;
1240 error_out:
1241 return -1;
1244 int xc_linux_build_mem(int xc_handle,
1245 uint32_t domid,
1246 const char *image_buffer,
1247 unsigned long image_size,
1248 const char *initrd,
1249 unsigned long initrd_len,
1250 const char *cmdline,
1251 const char *features,
1252 unsigned long flags,
1253 unsigned int store_evtchn,
1254 unsigned long *store_mfn,
1255 unsigned int console_evtchn,
1256 unsigned long *console_mfn)
1258 int sts;
1259 char *img_buf;
1260 unsigned long img_len;
1261 struct initrd_info initrd_info = { .type = INITRD_none };
1263 /* A kernel buffer is required */
1264 if ( (image_buffer == NULL) || (image_size == 0) )
1266 ERROR("kernel image buffer not present");
1267 return -1;
1270 /* If it's gzipped, inflate it; otherwise, use as is */
1271 /* xc_inflate_buffer may return the same buffer pointer if */
1272 /* the buffer is already inflated */
1273 img_buf = xc_inflate_buffer(image_buffer, image_size, &img_len);
1274 if ( img_buf == NULL )
1276 ERROR("unable to inflate kernel image buffer");
1277 return -1;
1280 /* RAM disks are optional; if we get one, inflate it */
1281 if ( initrd != NULL )
1283 initrd_info.type = INITRD_mem;
1284 initrd_info.u.mem_addr = xc_inflate_buffer(
1285 initrd, initrd_len, &initrd_info.len);
1286 if ( initrd_info.u.mem_addr == NULL )
1288 ERROR("unable to inflate ram disk buffer");
1289 sts = -1;
1290 goto out;
1294 sts = xc_linux_build_internal(xc_handle, domid, img_buf, img_len,
1295 &initrd_info, cmdline, features, flags,
1296 store_evtchn, store_mfn,
1297 console_evtchn, console_mfn);
1299 out:
1300 /* The inflation routines may pass back the same buffer so be */
1301 /* sure that we have a buffer and that it's not the one passed in. */
1302 /* Don't unnecessarily annoy/surprise/confound the caller */
1303 if ( (img_buf != NULL) && (img_buf != image_buffer) )
1304 free(img_buf);
1305 if ( (initrd_info.u.mem_addr != NULL) &&
1306 (initrd_info.u.mem_addr != initrd) )
1307 free(initrd_info.u.mem_addr);
1309 return sts;
1312 int xc_linux_build(int xc_handle,
1313 uint32_t domid,
1314 const char *image_name,
1315 const char *initrd_name,
1316 const char *cmdline,
1317 const char *features,
1318 unsigned long flags,
1319 unsigned int store_evtchn,
1320 unsigned long *store_mfn,
1321 unsigned int console_evtchn,
1322 unsigned long *console_mfn)
1324 char *image = NULL;
1325 unsigned long image_size;
1326 struct initrd_info initrd_info = { .type = INITRD_none };
1327 int fd = -1, sts = -1;
1329 if ( (image_name == NULL) ||
1330 ((image = xc_read_image(image_name, &image_size)) == NULL ))
1331 return -1;
1333 if ( (initrd_name != NULL) && (strlen(initrd_name) != 0) )
1335 initrd_info.type = INITRD_file;
1337 if ( (fd = open(initrd_name, O_RDONLY)) < 0 )
1339 PERROR("Could not open the initial ramdisk image");
1340 goto error_out;
1343 initrd_info.len = xc_get_filesz(fd);
1344 if ( (initrd_info.u.file_handle = gzdopen(fd, "rb")) == NULL )
1346 PERROR("Could not allocate decompression state for initrd");
1347 goto error_out;
1351 sts = xc_linux_build_internal(xc_handle, domid, image, image_size,
1352 &initrd_info, cmdline, features, flags,
1353 store_evtchn, store_mfn,
1354 console_evtchn, console_mfn);
1356 error_out:
1357 free(image);
1358 if ( fd >= 0 )
1359 close(fd);
1360 if ( initrd_info.u.file_handle )
1361 gzclose(initrd_info.u.file_handle);
1363 return sts;
1366 /*
1367 * Local variables:
1368 * mode: C
1369 * c-set-style: "BSD"
1370 * c-basic-offset: 4
1371 * tab-width: 4
1372 * indent-tabs-mode: nil
1373 * End:
1374 */