ia64/xen-unstable

view tools/libxc/xc_linux_build.c @ 10659:2aa910eb3713

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