ia64/xen-unstable

view tools/libxc/xc_linux_build.c @ 12794:9787cb7262e8

[IA64] changed foreign domain page mapping semantic.

x86 foreign HVM domain page mapping semantic was changed to use gmfn
instead mfn. It applies to domains with auto_translated_mode enabled,
and all ia64 domains enable auto_translated_mode. This patch changes
ia64 foreign domain page mapping to use gmfn and fixes ia64 domU buidler.
However this patch breaks domain save/restore/dump-core.
They should also be fixed-up

Signed-off-by: Isaku Yamahata <yamahata@valinux.co.jp>
author awilliam@xenbuild.aw
date Tue Dec 05 10:59:32 2006 -0700 (2006-12-05)
parents 27c2e9aa83e9
children 970ff2ba748f
line source
1 /******************************************************************************
2 * xc_linux_build.c
3 */
5 #include <stddef.h>
6 #include "xg_private.h"
7 #include "xc_private.h"
8 #include <xenctrl.h>
10 #include "xc_elf.h"
11 #include <stdlib.h>
12 #include <unistd.h>
13 #include <inttypes.h>
14 #include <zlib.h>
16 /* Handy for printing out '0' prepended values at native pointer size */
17 #define _p(a) ((void *) ((ulong)a))
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 #if defined(__i386__)
22 #define L3_PROT (_PAGE_PRESENT)
23 #elif defined(__x86_64__)
24 #define L3_PROT (_PAGE_PRESENT|_PAGE_RW|_PAGE_ACCESSED|_PAGE_DIRTY|_PAGE_USER)
25 #define L4_PROT (_PAGE_PRESENT|_PAGE_RW|_PAGE_ACCESSED|_PAGE_DIRTY|_PAGE_USER)
26 #endif
28 #define round_pgup(_p) (((_p)+(PAGE_SIZE-1))&PAGE_MASK)
29 #define round_pgdown(_p) ((_p)&PAGE_MASK)
31 struct initrd_info {
32 enum { INITRD_none, INITRD_file, INITRD_mem } type;
33 /*
34 * .len must be filled in by the user for type==INITRD_mem. It is
35 * filled in by load_initrd() for INITRD_file and unused for
36 * INITRD_none.
37 */
38 unsigned long len;
39 union {
40 gzFile file_handle;
41 char *mem_addr;
42 } u;
43 };
45 static const char *feature_names[XENFEAT_NR_SUBMAPS*32] = {
46 [XENFEAT_writable_page_tables] = "writable_page_tables",
47 [XENFEAT_writable_descriptor_tables] = "writable_descriptor_tables",
48 [XENFEAT_auto_translated_physmap] = "auto_translated_physmap",
49 [XENFEAT_supervisor_mode_kernel] = "supervisor_mode_kernel",
50 [XENFEAT_pae_pgdir_above_4gb] = "pae_pgdir_above_4gb"
51 };
53 static inline void set_feature_bit (int nr, uint32_t *addr)
54 {
55 addr[nr>>5] |= (1<<(nr&31));
56 }
58 static inline int test_feature_bit(int nr, uint32_t *addr)
59 {
60 return !!(addr[nr>>5] & (1<<(nr&31)));
61 }
63 static int parse_features(
64 const char *feats,
65 uint32_t supported[XENFEAT_NR_SUBMAPS],
66 uint32_t required[XENFEAT_NR_SUBMAPS])
67 {
68 const char *end, *p;
69 int i, req;
71 if ( (end = strchr(feats, ',')) == NULL )
72 end = feats + strlen(feats);
74 while ( feats < end )
75 {
76 p = strchr(feats, '|');
77 if ( (p == NULL) || (p > end) )
78 p = end;
80 req = (*feats == '!');
81 if ( req )
82 feats++;
84 for ( i = 0; i < XENFEAT_NR_SUBMAPS*32; i++ )
85 {
86 if ( feature_names[i] == NULL )
87 continue;
89 if ( strncmp(feature_names[i], feats, p-feats) == 0 )
90 {
91 set_feature_bit(i, supported);
92 if ( required && req )
93 set_feature_bit(i, required);
94 break;
95 }
96 }
98 if ( i == XENFEAT_NR_SUBMAPS*32 )
99 {
100 ERROR("Unknown feature \"%.*s\".", (int)(p-feats), feats);
101 if ( req )
102 {
103 ERROR("Kernel requires an unknown hypervisor feature.");
104 return -EINVAL;
105 }
106 }
108 feats = p;
109 if ( *feats == '|' )
110 feats++;
111 }
113 return -EINVAL;
114 }
116 static int probeimageformat(const char *image,
117 unsigned long image_size,
118 struct load_funcs *load_funcs)
119 {
120 if ( probe_elf(image, image_size, load_funcs) &&
121 probe_bin(image, image_size, load_funcs) )
122 {
123 ERROR( "Unrecognized image format" );
124 return -EINVAL;
125 }
127 return 0;
128 }
130 static int load_initrd(int xc_handle, domid_t dom,
131 struct initrd_info *initrd,
132 unsigned long physbase,
133 xen_pfn_t *phys_to_mach)
134 {
135 char page[PAGE_SIZE];
136 unsigned long pfn_start, pfn;
138 if ( initrd->type == INITRD_none )
139 return 0;
141 pfn_start = physbase >> PAGE_SHIFT;
143 if ( initrd->type == INITRD_mem )
144 {
145 unsigned long nr_pages = (initrd->len + PAGE_SIZE - 1) >> PAGE_SHIFT;
147 for ( pfn = pfn_start; pfn < (pfn_start + nr_pages); pfn++ )
148 {
149 xc_copy_to_domain_page(
150 xc_handle, dom, phys_to_mach[pfn],
151 &initrd->u.mem_addr[(pfn - pfn_start) << PAGE_SHIFT]);
152 }
153 }
154 else
155 {
156 int readlen;
158 pfn = pfn_start;
159 initrd->len = 0;
161 /* gzread returns 0 on EOF */
162 while ( (readlen = gzread(initrd->u.file_handle, page, PAGE_SIZE)) )
163 {
164 if ( readlen < 0 )
165 {
166 PERROR("Error reading initrd image, could not");
167 return -EINVAL;
168 }
170 initrd->len += readlen;
171 xc_copy_to_domain_page(xc_handle, dom, phys_to_mach[pfn++], page);
172 }
173 }
175 return 0;
176 }
178 #define alloc_pt(ltab, vltab, pltab) \
179 do { \
180 pltab = ppt_alloc++; \
181 ltab = (uint64_t)page_array[pltab] << PAGE_SHIFT; \
182 pltab <<= PAGE_SHIFT; \
183 if ( vltab != NULL ) \
184 munmap(vltab, PAGE_SIZE); \
185 if ( (vltab = xc_map_foreign_range(xc_handle, dom, PAGE_SIZE, \
186 PROT_READ|PROT_WRITE, \
187 ltab >> PAGE_SHIFT)) == NULL ) \
188 goto error_out; \
189 memset(vltab, 0x0, PAGE_SIZE); \
190 } while ( 0 )
192 #if defined(__i386__)
194 static int setup_pg_tables(int xc_handle, uint32_t dom,
195 vcpu_guest_context_t *ctxt,
196 unsigned long dsi_v_start,
197 unsigned long v_end,
198 xen_pfn_t *page_array,
199 unsigned long vpt_start,
200 unsigned long vpt_end,
201 unsigned shadow_mode_enabled)
202 {
203 l1_pgentry_t *vl1tab=NULL, *vl1e=NULL;
204 l2_pgentry_t *vl2tab=NULL, *vl2e=NULL;
205 unsigned long l1tab = 0, pl1tab;
206 unsigned long l2tab = 0, pl2tab;
207 unsigned long ppt_alloc;
208 unsigned long count;
210 ppt_alloc = (vpt_start - dsi_v_start) >> PAGE_SHIFT;
211 alloc_pt(l2tab, vl2tab, pl2tab);
212 vl2e = &vl2tab[l2_table_offset(dsi_v_start)];
213 if (shadow_mode_enabled)
214 ctxt->ctrlreg[3] = xen_pfn_to_cr3(pl2tab >> PAGE_SHIFT);
215 else
216 ctxt->ctrlreg[3] = xen_pfn_to_cr3(l2tab >> PAGE_SHIFT);
218 for ( count = 0; count < ((v_end - dsi_v_start) >> PAGE_SHIFT); count++ )
219 {
220 if ( ((unsigned long)vl1e & (PAGE_SIZE-1)) == 0 )
221 {
222 alloc_pt(l1tab, vl1tab, pl1tab);
223 vl1e = &vl1tab[l1_table_offset(dsi_v_start + (count<<PAGE_SHIFT))];
224 if (shadow_mode_enabled)
225 *vl2e = pl1tab | L2_PROT;
226 else
227 *vl2e = l1tab | L2_PROT;
228 vl2e++;
229 }
231 if ( shadow_mode_enabled )
232 {
233 *vl1e = (count << PAGE_SHIFT) | L1_PROT;
234 }
235 else
236 {
237 *vl1e = (page_array[count] << PAGE_SHIFT) | L1_PROT;
238 if ( (count >= ((vpt_start-dsi_v_start)>>PAGE_SHIFT)) &&
239 (count < ((vpt_end -dsi_v_start)>>PAGE_SHIFT)) )
240 *vl1e &= ~_PAGE_RW;
241 }
242 vl1e++;
243 }
244 munmap(vl1tab, PAGE_SIZE);
245 munmap(vl2tab, PAGE_SIZE);
246 return 0;
248 error_out:
249 if (vl1tab)
250 munmap(vl1tab, PAGE_SIZE);
251 if (vl2tab)
252 munmap(vl2tab, PAGE_SIZE);
253 return -1;
254 }
256 static int setup_pg_tables_pae(int xc_handle, uint32_t dom,
257 vcpu_guest_context_t *ctxt,
258 unsigned long dsi_v_start,
259 unsigned long v_end,
260 xen_pfn_t *page_array,
261 unsigned long vpt_start,
262 unsigned long vpt_end,
263 unsigned shadow_mode_enabled,
264 unsigned pae_mode)
265 {
266 l1_pgentry_64_t *vl1tab = NULL, *vl1e = NULL;
267 l2_pgentry_64_t *vl2tab = NULL, *vl2e = NULL;
268 l3_pgentry_64_t *vl3tab = NULL, *vl3e = NULL;
269 uint64_t l1tab, l2tab, l3tab, pl1tab, pl2tab, pl3tab;
270 unsigned long ppt_alloc, count, nmfn;
272 /* First allocate page for page dir. */
273 ppt_alloc = (vpt_start - dsi_v_start) >> PAGE_SHIFT;
275 if ( pae_mode == PAEKERN_extended_cr3 )
276 {
277 ctxt->vm_assist |= (1UL << VMASST_TYPE_pae_extended_cr3);
278 }
279 else if ( page_array[ppt_alloc] > 0xfffff )
280 {
281 nmfn = xc_make_page_below_4G(xc_handle, dom, page_array[ppt_alloc]);
282 if ( nmfn == 0 )
283 {
284 DPRINTF("Couldn't get a page below 4GB :-(\n");
285 goto error_out;
286 }
287 page_array[ppt_alloc] = nmfn;
288 }
290 alloc_pt(l3tab, vl3tab, pl3tab);
291 vl3e = &vl3tab[l3_table_offset_pae(dsi_v_start)];
292 if (shadow_mode_enabled)
293 ctxt->ctrlreg[3] = xen_pfn_to_cr3(pl3tab >> PAGE_SHIFT);
294 else
295 ctxt->ctrlreg[3] = xen_pfn_to_cr3(l3tab >> PAGE_SHIFT);
297 for ( count = 0; count < ((v_end - dsi_v_start) >> PAGE_SHIFT); count++)
298 {
299 if ( !((unsigned long)vl1e & (PAGE_SIZE-1)) )
300 {
301 if ( !((unsigned long)vl2e & (PAGE_SIZE-1)) )
302 {
303 alloc_pt(l2tab, vl2tab, pl2tab);
304 vl2e = &vl2tab[l2_table_offset_pae(
305 dsi_v_start + (count << PAGE_SHIFT))];
306 if (shadow_mode_enabled)
307 *vl3e = pl2tab | L3_PROT;
308 else
309 *vl3e++ = l2tab | L3_PROT;
310 }
312 alloc_pt(l1tab, vl1tab, pl1tab);
313 vl1e = &vl1tab[l1_table_offset_pae(
314 dsi_v_start + (count << PAGE_SHIFT))];
315 if (shadow_mode_enabled)
316 *vl2e = pl1tab | L2_PROT;
317 else
318 *vl2e++ = l1tab | L2_PROT;
319 }
321 if ( shadow_mode_enabled )
322 {
323 *vl1e = (count << PAGE_SHIFT) | L1_PROT;
324 }
325 else
326 {
327 *vl1e = ((uint64_t)page_array[count] << PAGE_SHIFT) | L1_PROT;
328 if ( (count >= ((vpt_start-dsi_v_start)>>PAGE_SHIFT)) &&
329 (count < ((vpt_end -dsi_v_start)>>PAGE_SHIFT)) )
330 *vl1e &= ~_PAGE_RW;
331 }
332 vl1e++;
333 }
335 /* Xen requires a mid-level pgdir mapping 0xC0000000 region. */
336 if ( (vl3tab[3] & _PAGE_PRESENT) == 0 )
337 {
338 alloc_pt(l2tab, vl2tab, pl2tab);
339 vl3tab[3] = l2tab | L3_PROT;
340 }
342 munmap(vl1tab, PAGE_SIZE);
343 munmap(vl2tab, PAGE_SIZE);
344 munmap(vl3tab, PAGE_SIZE);
345 return 0;
347 error_out:
348 if (vl1tab)
349 munmap(vl1tab, PAGE_SIZE);
350 if (vl2tab)
351 munmap(vl2tab, PAGE_SIZE);
352 if (vl3tab)
353 munmap(vl3tab, PAGE_SIZE);
354 return -1;
355 }
357 #endif
359 #if defined(__x86_64__)
361 static int setup_pg_tables_64(int xc_handle, uint32_t dom,
362 vcpu_guest_context_t *ctxt,
363 unsigned long dsi_v_start,
364 unsigned long v_end,
365 xen_pfn_t *page_array,
366 unsigned long vpt_start,
367 unsigned long vpt_end,
368 int shadow_mode_enabled)
369 {
370 l1_pgentry_t *vl1tab=NULL, *vl1e=NULL;
371 l2_pgentry_t *vl2tab=NULL, *vl2e=NULL;
372 l3_pgentry_t *vl3tab=NULL, *vl3e=NULL;
373 l4_pgentry_t *vl4tab=NULL, *vl4e=NULL;
374 unsigned long l2tab = 0, pl2tab;
375 unsigned long l1tab = 0, pl1tab;
376 unsigned long l3tab = 0, pl3tab;
377 unsigned long l4tab = 0, pl4tab;
378 unsigned long ppt_alloc;
379 unsigned long count;
381 /* First allocate page for page dir. */
382 ppt_alloc = (vpt_start - dsi_v_start) >> PAGE_SHIFT;
383 alloc_pt(l4tab, vl4tab, pl4tab);
384 vl4e = &vl4tab[l4_table_offset(dsi_v_start)];
385 if (shadow_mode_enabled)
386 ctxt->ctrlreg[3] = xen_pfn_to_cr3(pl4tab >> PAGE_SHIFT);
387 else
388 ctxt->ctrlreg[3] = xen_pfn_to_cr3(l4tab >> PAGE_SHIFT);
390 for ( count = 0; count < ((v_end-dsi_v_start)>>PAGE_SHIFT); count++)
391 {
392 if ( !((unsigned long)vl1e & (PAGE_SIZE-1)) )
393 {
394 alloc_pt(l1tab, vl1tab, pl1tab);
396 if ( !((unsigned long)vl2e & (PAGE_SIZE-1)) )
397 {
398 alloc_pt(l2tab, vl2tab, pl2tab);
399 if ( !((unsigned long)vl3e & (PAGE_SIZE-1)) )
400 {
401 alloc_pt(l3tab, vl3tab, pl3tab);
402 vl3e = &vl3tab[l3_table_offset(dsi_v_start + (count<<PAGE_SHIFT))];
403 if (shadow_mode_enabled)
404 *vl4e = pl3tab | L4_PROT;
405 else
406 *vl4e = l3tab | L4_PROT;
407 vl4e++;
408 }
409 vl2e = &vl2tab[l2_table_offset(dsi_v_start + (count<<PAGE_SHIFT))];
410 if (shadow_mode_enabled)
411 *vl3e = pl2tab | L3_PROT;
412 else
413 *vl3e = l2tab | L3_PROT;
414 vl3e++;
415 }
416 vl1e = &vl1tab[l1_table_offset(dsi_v_start + (count<<PAGE_SHIFT))];
417 if (shadow_mode_enabled)
418 *vl2e = pl1tab | L2_PROT;
419 else
420 *vl2e = l1tab | L2_PROT;
421 vl2e++;
422 }
424 if ( shadow_mode_enabled )
425 {
426 *vl1e = (count << PAGE_SHIFT) | L1_PROT;
427 }
428 else
429 {
430 *vl1e = (page_array[count] << PAGE_SHIFT) | L1_PROT;
431 if ( (count >= ((vpt_start-dsi_v_start)>>PAGE_SHIFT)) &&
432 (count < ((vpt_end -dsi_v_start)>>PAGE_SHIFT)) )
433 {
434 *vl1e &= ~_PAGE_RW;
435 }
436 }
437 vl1e++;
438 }
440 munmap(vl1tab, PAGE_SIZE);
441 munmap(vl2tab, PAGE_SIZE);
442 munmap(vl3tab, PAGE_SIZE);
443 munmap(vl4tab, PAGE_SIZE);
444 return 0;
446 error_out:
447 if (vl1tab)
448 munmap(vl1tab, PAGE_SIZE);
449 if (vl2tab)
450 munmap(vl2tab, PAGE_SIZE);
451 if (vl3tab)
452 munmap(vl3tab, PAGE_SIZE);
453 if (vl4tab)
454 munmap(vl4tab, PAGE_SIZE);
455 return -1;
456 }
457 #endif
459 #ifdef __ia64__
460 static int setup_guest(int xc_handle,
461 uint32_t dom,
462 const char *image, unsigned long image_size,
463 struct initrd_info *initrd,
464 unsigned long nr_pages,
465 unsigned long *pvsi, unsigned long *pvke,
466 unsigned long *pvss, vcpu_guest_context_t *ctxt,
467 const char *cmdline,
468 unsigned long shared_info_frame,
469 unsigned long flags,
470 unsigned int store_evtchn, unsigned long *store_mfn,
471 unsigned int console_evtchn, unsigned long *console_mfn,
472 uint32_t required_features[XENFEAT_NR_SUBMAPS])
473 {
474 xen_pfn_t *page_array = NULL;
475 struct load_funcs load_funcs;
476 struct domain_setup_info dsi;
477 unsigned long vinitrd_start;
478 unsigned long vinitrd_end;
479 unsigned long v_end;
480 unsigned long start_page, pgnr;
481 start_info_t *start_info;
482 unsigned long start_info_mpa;
483 struct xen_ia64_boot_param *bp;
484 #if 0 // see comment below
485 shared_info_t *shared_info;
486 #endif
487 int i;
488 DECLARE_DOMCTL;
489 int rc;
491 rc = probeimageformat(image, image_size, &load_funcs);
492 if ( rc != 0 )
493 goto error_out;
495 memset(&dsi, 0, sizeof(struct domain_setup_info));
497 rc = (load_funcs.parseimage)(image, image_size, &dsi);
498 if ( rc != 0 )
499 goto error_out;
501 if ( (page_array = malloc(nr_pages * sizeof(xen_pfn_t))) == NULL )
502 {
503 PERROR("Could not allocate memory");
504 goto error_out;
505 }
506 for ( i = 0; i < nr_pages; i++ )
507 page_array[i] = i;
508 if ( xc_domain_memory_populate_physmap(xc_handle, dom, nr_pages,
509 0, 0, page_array) )
510 {
511 PERROR("Could not allocate memory for PV guest.\n");
512 goto error_out;
513 }
515 dsi.v_start = round_pgdown(dsi.v_start);
516 vinitrd_start = round_pgup(dsi.v_end);
517 start_info_mpa = (nr_pages - 3) << PAGE_SHIFT;
518 *pvke = dsi.v_kernentry;
520 /* Build firmware. */
521 memset(&domctl.u.arch_setup, 0, sizeof(domctl.u.arch_setup));
522 domctl.u.arch_setup.flags = 0;
523 domctl.u.arch_setup.bp = start_info_mpa + sizeof (start_info_t);
524 domctl.u.arch_setup.maxmem = (nr_pages - 3) << PAGE_SHIFT;
525 domctl.cmd = XEN_DOMCTL_arch_setup;
526 domctl.domain = (domid_t)dom;
527 if ( xc_domctl(xc_handle, &domctl) )
528 goto error_out;
530 start_page = dsi.v_start >> PAGE_SHIFT;
531 /* in order to get initrd->len, we need to load initrd image at first */
532 if ( load_initrd(xc_handle, dom, initrd,
533 vinitrd_start - dsi.v_start, page_array + start_page) )
534 goto error_out;
536 vinitrd_end = vinitrd_start + initrd->len;
537 v_end = round_pgup(vinitrd_end);
538 pgnr = (v_end - dsi.v_start) >> PAGE_SHIFT;
539 if ( pgnr > nr_pages )
540 {
541 PERROR("too small memory is specified. "
542 "At least %ld kb is necessary.\n",
543 pgnr << (PAGE_SHIFT - 10));
544 }
546 IPRINTF("VIRTUAL MEMORY ARRANGEMENT:\n"
547 " Loaded kernel: %p->%p\n"
548 " Init. ramdisk: %p->%p\n"
549 " TOTAL: %p->%p\n",
550 _p(dsi.v_kernstart), _p(dsi.v_kernend),
551 _p(vinitrd_start), _p(vinitrd_end),
552 _p(dsi.v_start), _p(v_end));
553 IPRINTF(" ENTRY ADDRESS: %p\n", _p(dsi.v_kernentry));
555 (load_funcs.loadimage)(image, image_size, xc_handle, dom,
556 page_array + start_page, &dsi);
558 *store_mfn = page_array[nr_pages - 2]; //XXX
559 *console_mfn = page_array[nr_pages - 1]; //XXX
560 IPRINTF("start_info: 0x%lx at 0x%lx, "
561 "store_mfn: 0x%lx at 0x%lx, "
562 "console_mfn: 0x%lx at 0x%lx\n",
563 page_array[nr_pages - 3], nr_pages - 3,
564 *store_mfn, nr_pages - 2,
565 *console_mfn, nr_pages - 1);
567 start_info = xc_map_foreign_range(
568 xc_handle, dom, PAGE_SIZE, PROT_READ|PROT_WRITE,
569 page_array[nr_pages - 3]);
570 if ( start_info == NULL )
571 goto error_out;
573 memset(start_info, 0, sizeof(*start_info));
574 rc = xc_version(xc_handle, XENVER_version, NULL);
575 sprintf(start_info->magic, "xen-%i.%i-ia64", rc >> 16, rc & (0xFFFF));
576 start_info->flags = flags;
577 start_info->store_mfn = nr_pages - 2;
578 start_info->store_evtchn = store_evtchn;
579 start_info->console.domU.mfn = nr_pages - 1;
580 start_info->console.domU.evtchn = console_evtchn;
581 start_info->nr_pages = nr_pages; // FIXME?: nr_pages - 2 ????
583 bp = (struct xen_ia64_boot_param *)(start_info + 1);
584 bp->command_line = start_info_mpa + offsetof(start_info_t, cmd_line);
585 if ( cmdline != NULL )
586 {
587 strncpy((char *)start_info->cmd_line, cmdline, MAX_GUEST_CMDLINE);
588 start_info->cmd_line[MAX_GUEST_CMDLINE - 1] = 0;
589 }
590 if ( initrd->len != 0 )
591 {
592 bp->initrd_start = vinitrd_start;
593 bp->initrd_size = initrd->len;
594 }
595 ctxt->user_regs.r28 = start_info_mpa + sizeof (start_info_t);
596 munmap(start_info, PAGE_SIZE);
598 #if 0
599 /*
600 * XXX FIXME:
601 * The follwoing initialization is done by XEN_DOMCTL_arch_setup as
602 * work around.
603 * Should XENMEM_add_to_physmap with XENMAPSPACE_shared_info be used?
604 */
606 /* shared_info page starts its life empty. */
607 shared_info = xc_map_foreign_range(
608 xc_handle, dom, PAGE_SIZE, PROT_READ|PROT_WRITE, shared_info_frame);
609 printf("shared_info = %p, err=%s frame=%lx\n",
610 shared_info, strerror (errno), shared_info_frame);
611 //memset(shared_info, 0, PAGE_SIZE);
612 /* Mask all upcalls... */
613 for ( i = 0; i < MAX_VIRT_CPUS; i++ )
614 shared_info->vcpu_info[i].evtchn_upcall_mask = 1;
615 shared_info->arch.start_info_pfn = nr_pages - 3;
617 munmap(shared_info, PAGE_SIZE);
618 #endif
619 free(page_array);
620 return 0;
622 error_out:
623 free(page_array);
624 return -1;
625 }
626 #else /* x86 */
628 /* Check if the platform supports the guest kernel format */
629 static int compat_check(int xc_handle, struct domain_setup_info *dsi)
630 {
631 xen_capabilities_info_t xen_caps = "";
633 if (xc_version(xc_handle, XENVER_capabilities, &xen_caps) != 0) {
634 ERROR("Cannot determine host capabilities.");
635 return 0;
636 }
638 if (strstr(xen_caps, "xen-3.0-x86_32p")) {
639 if (dsi->pae_kernel == PAEKERN_no) {
640 ERROR("Non PAE-kernel on PAE host.");
641 return 0;
642 }
643 } else if (dsi->pae_kernel != PAEKERN_no) {
644 ERROR("PAE-kernel on non-PAE host.");
645 return 0;
646 }
648 return 1;
649 }
651 static inline int increment_ulong(unsigned long *pval, unsigned long inc)
652 {
653 if ( inc >= -*pval )
654 {
655 ERROR("Value wrapped to zero: image too large?");
656 return 0;
657 }
658 *pval += inc;
659 return 1;
660 }
662 static int setup_guest(int xc_handle,
663 uint32_t dom,
664 const char *image, unsigned long image_size,
665 struct initrd_info *initrd,
666 unsigned long nr_pages,
667 unsigned long *pvsi, unsigned long *pvke,
668 unsigned long *pvss, vcpu_guest_context_t *ctxt,
669 const char *cmdline,
670 unsigned long shared_info_frame,
671 unsigned long flags,
672 unsigned int store_evtchn, unsigned long *store_mfn,
673 unsigned int console_evtchn, unsigned long *console_mfn,
674 uint32_t required_features[XENFEAT_NR_SUBMAPS])
675 {
676 xen_pfn_t *page_array = NULL;
677 unsigned long count, i;
678 unsigned long long hypercall_page;
679 int hypercall_page_defined;
680 start_info_t *start_info;
681 shared_info_t *shared_info;
682 const char *p;
683 DECLARE_DOMCTL;
684 int rc;
686 unsigned long nr_pt_pages;
687 unsigned long physmap_pfn;
688 xen_pfn_t *physmap, *physmap_e;
690 struct load_funcs load_funcs;
691 struct domain_setup_info dsi;
692 unsigned long vinitrd_start;
693 unsigned long vphysmap_start;
694 unsigned long vstartinfo_start;
695 unsigned long vstoreinfo_start;
696 unsigned long vconsole_start;
697 unsigned long vsharedinfo_start = 0; /* XXX gcc */
698 unsigned long vstack_start;
699 unsigned long vstack_end;
700 unsigned long vpt_start;
701 unsigned long vpt_end;
702 unsigned long v_end;
703 unsigned long guest_store_mfn, guest_console_mfn, guest_shared_info_mfn;
704 unsigned long shadow_mode_enabled;
705 uint32_t supported_features[XENFEAT_NR_SUBMAPS] = { 0, };
707 rc = probeimageformat(image, image_size, &load_funcs);
708 if ( rc != 0 )
709 goto error_out;
711 memset(&dsi, 0, sizeof(struct domain_setup_info));
713 rc = (load_funcs.parseimage)(image, image_size, &dsi);
714 if ( rc != 0 )
715 goto error_out;
717 if ( (dsi.v_start & (PAGE_SIZE-1)) != 0 )
718 {
719 PERROR("Guest OS must load to a page boundary.");
720 goto error_out;
721 }
723 if ( !compat_check(xc_handle, &dsi) )
724 goto error_out;
726 /* Parse and validate kernel features. */
727 if ( (p = xen_elfnote_string(&dsi, XEN_ELFNOTE_FEATURES)) != NULL )
728 {
729 if ( !parse_features(p, supported_features, required_features) )
730 {
731 ERROR("Failed to parse guest kernel features.");
732 goto error_out;
733 }
735 IPRINTF("Supported features = { %08x }.\n", supported_features[0]);
736 IPRINTF("Required features = { %08x }.\n", required_features[0]);
737 }
739 for ( i = 0; i < XENFEAT_NR_SUBMAPS; i++ )
740 {
741 if ( (supported_features[i] & required_features[i]) !=
742 required_features[i] )
743 {
744 ERROR("Guest kernel does not support a required feature.");
745 goto error_out;
746 }
747 }
749 shadow_mode_enabled = test_feature_bit(XENFEAT_auto_translated_physmap,
750 required_features);
752 if ( (page_array = malloc(nr_pages * sizeof(unsigned long))) == NULL )
753 {
754 PERROR("Could not allocate memory");
755 goto error_out;
756 }
758 for ( i = 0; i < nr_pages; i++ )
759 page_array[i] = i;
761 if ( xc_domain_memory_populate_physmap(xc_handle, dom, nr_pages,
762 0, 0, page_array) )
763 {
764 PERROR("Could not allocate memory for PV guest.\n");
765 goto error_out;
766 }
768 rc = (load_funcs.loadimage)(image, image_size,
769 xc_handle, dom, page_array,
770 &dsi);
771 if ( rc != 0 )
772 goto error_out;
774 /*
775 * Why do we need this? The number of page-table frames depends on the
776 * size of the bootstrap address space. But the size of the address space
777 * depends on the number of page-table frames (since each one is mapped
778 * read-only). We have a pair of simultaneous equations in two unknowns,
779 * which we solve by exhaustive search.
780 */
781 v_end = round_pgup(dsi.v_end);
782 if ( v_end == 0 )
783 {
784 ERROR("End of mapped kernel image too close to end of memory");
785 goto error_out;
786 }
788 vinitrd_start = v_end;
789 if ( load_initrd(xc_handle, dom, initrd,
790 vinitrd_start - dsi.v_start, page_array) )
791 goto error_out;
792 if ( !increment_ulong(&v_end, round_pgup(initrd->len)) )
793 goto error_out;
795 vphysmap_start = v_end;
796 if ( !increment_ulong(&v_end, round_pgup(nr_pages * sizeof(long))) )
797 goto error_out;
798 vstartinfo_start = v_end;
799 if ( !increment_ulong(&v_end, PAGE_SIZE) )
800 goto error_out;
801 vstoreinfo_start = v_end;
802 if ( !increment_ulong(&v_end, PAGE_SIZE) )
803 goto error_out;
804 vconsole_start = v_end;
805 if ( !increment_ulong(&v_end, PAGE_SIZE) )
806 goto error_out;
807 if ( shadow_mode_enabled ) {
808 vsharedinfo_start = v_end;
809 if ( !increment_ulong(&v_end, PAGE_SIZE) )
810 goto error_out;
811 }
812 vpt_start = v_end;
814 for ( nr_pt_pages = 2; ; nr_pt_pages++ )
815 {
816 /* vpt_end = vpt_staret + (nr_pt_pages * PAGE_SIZE); */
817 vpt_end = vpt_start;
818 if ( !increment_ulong(&vpt_end, nr_pt_pages * PAGE_SIZE) )
819 goto error_out;
821 vstack_start = vpt_end;
822 /* vstack_end = vstack_start + PAGE_SIZE; */
823 vstack_end = vstack_start;
824 if ( !increment_ulong(&vstack_end, PAGE_SIZE) )
825 goto error_out;
827 /* v_end = (vstack_end + (1UL<<22)-1) & ~((1UL<<22)-1); */
828 v_end = vstack_end;
829 if ( !increment_ulong(&v_end, (1UL<<22)-1) )
830 goto error_out;
831 v_end &= ~((1UL<<22)-1);
833 if ( (v_end - vstack_end) < (512UL << 10) )
834 {
835 /* Add extra 4MB to get >= 512kB padding. */
836 if ( !increment_ulong(&v_end, 1UL << 22) )
837 goto error_out;
838 }
840 #define NR(_l,_h,_s) \
841 (((((unsigned long)(_h) + ((1UL<<(_s))-1)) & ~((1UL<<(_s))-1)) - \
842 ((unsigned long)(_l) & ~((1UL<<(_s))-1))) >> (_s))
843 #if defined(__i386__)
844 if ( dsi.pae_kernel != PAEKERN_no )
845 {
846 if ( (1 + /* # L3 */
847 NR(dsi.v_start, v_end, L3_PAGETABLE_SHIFT_PAE) + /* # L2 */
848 NR(dsi.v_start, v_end, L2_PAGETABLE_SHIFT_PAE) + /* # L1 */
849 /* Include a fourth mid-level page directory for Xen. */
850 (v_end <= (3 << L3_PAGETABLE_SHIFT_PAE)))
851 <= nr_pt_pages )
852 break;
853 }
854 else
855 {
856 if ( (1 + /* # L2 */
857 NR(dsi.v_start, v_end, L2_PAGETABLE_SHIFT)) /* # L1 */
858 <= nr_pt_pages )
859 break;
860 }
861 #elif defined(__x86_64__)
862 if ( (1 + /* # L4 */
863 NR(dsi.v_start, v_end, L4_PAGETABLE_SHIFT) + /* # L3 */
864 NR(dsi.v_start, v_end, L3_PAGETABLE_SHIFT) + /* # L2 */
865 NR(dsi.v_start, v_end, L2_PAGETABLE_SHIFT)) /* # L1 */
866 <= nr_pt_pages )
867 break;
868 #endif
869 }
871 IPRINTF("VIRTUAL MEMORY ARRANGEMENT:\n");
872 IPRINTF(" Loaded kernel: %p->%p\n", _p(dsi.v_kernstart),
873 _p(dsi.v_kernend));
874 if ( initrd->len )
875 IPRINTF(" Initial ramdisk: %p->%p\n", _p(vinitrd_start),
876 _p(vinitrd_start + initrd->len));
877 IPRINTF(" Phys-Mach map: %p\n", _p(vphysmap_start));
878 IPRINTF(" Start info: %p\n", _p(vstartinfo_start));
879 IPRINTF(" Store page: %p\n", _p(vstoreinfo_start));
880 IPRINTF(" Console page: %p\n", _p(vconsole_start));
881 if ( shadow_mode_enabled )
882 IPRINTF(" Shared Info page: %p\n", _p(vsharedinfo_start));
883 IPRINTF(" Page tables: %p\n", _p(vpt_start));
884 IPRINTF(" Boot stack: %p\n", _p(vstack_start));
885 IPRINTF(" TOTAL: %p->%p\n", _p(dsi.v_start), _p(v_end));
886 IPRINTF(" ENTRY ADDRESS: %p\n", _p(dsi.v_kernentry));
888 if ( ((v_end - dsi.v_start)>>PAGE_SHIFT) > nr_pages )
889 {
890 PERROR("Initial guest OS requires too much space\n"
891 "(%pMB is greater than %luMB limit)\n",
892 _p((v_end-dsi.v_start)>>20), nr_pages>>(20-PAGE_SHIFT));
893 goto error_out;
894 }
896 #if defined(__i386__)
897 if ( dsi.pae_kernel != PAEKERN_no )
898 rc = setup_pg_tables_pae(xc_handle, dom, ctxt,
899 dsi.v_start, v_end,
900 page_array, vpt_start, vpt_end,
901 shadow_mode_enabled, dsi.pae_kernel);
902 else
903 rc = setup_pg_tables(xc_handle, dom, ctxt,
904 dsi.v_start, v_end,
905 page_array, vpt_start, vpt_end,
906 shadow_mode_enabled);
907 #endif
908 #if defined(__x86_64__)
909 rc = setup_pg_tables_64(xc_handle, dom, ctxt,
910 dsi.v_start, v_end,
911 page_array, vpt_start, vpt_end,
912 shadow_mode_enabled);
913 #endif
914 if ( rc != 0 )
915 goto error_out;
917 /*
918 * Pin down l2tab addr as page dir page - causes hypervisor to provide
919 * correct protection for the page
920 */
921 if ( !shadow_mode_enabled )
922 {
923 #if defined(__i386__)
924 if ( dsi.pae_kernel != PAEKERN_no )
925 {
926 if ( pin_table(xc_handle, MMUEXT_PIN_L3_TABLE,
927 xen_cr3_to_pfn(ctxt->ctrlreg[3]), dom) )
928 goto error_out;
929 }
930 else
931 {
932 if ( pin_table(xc_handle, MMUEXT_PIN_L2_TABLE,
933 xen_cr3_to_pfn(ctxt->ctrlreg[3]), dom) )
934 goto error_out;
935 }
936 #elif defined(__x86_64__)
937 /*
938 * Pin down l4tab addr as page dir page - causes hypervisor to provide
939 * correct protection for the page
940 */
941 if ( pin_table(xc_handle, MMUEXT_PIN_L4_TABLE,
942 xen_cr3_to_pfn(ctxt->ctrlreg[3]), dom) )
943 goto error_out;
944 #endif
945 }
947 /* Write the phys->machine table entries (machine->phys already done). */
948 physmap_pfn = (vphysmap_start - dsi.v_start) >> PAGE_SHIFT;
949 physmap = physmap_e = xc_map_foreign_range(
950 xc_handle, dom, PAGE_SIZE, PROT_READ|PROT_WRITE,
951 page_array[physmap_pfn++]);
952 for ( count = 0; count < nr_pages; count++ )
953 {
954 *physmap_e++ = page_array[count];
955 if ( ((unsigned long)physmap_e & (PAGE_SIZE-1)) == 0 )
956 {
957 munmap(physmap, PAGE_SIZE);
958 physmap = physmap_e = xc_map_foreign_range(
959 xc_handle, dom, PAGE_SIZE, PROT_READ|PROT_WRITE,
960 page_array[physmap_pfn++]);
961 }
962 }
963 munmap(physmap, PAGE_SIZE);
965 if ( shadow_mode_enabled )
966 {
967 struct xen_add_to_physmap xatp;
969 /* Enable shadow translate mode */
970 if ( xc_shadow_control(xc_handle, dom,
971 XEN_DOMCTL_SHADOW_OP_ENABLE_TRANSLATE,
972 NULL, 0, NULL, 0, NULL) < 0 )
973 {
974 PERROR("Could not enable translation mode");
975 goto error_out;
976 }
978 guest_shared_info_mfn = (vsharedinfo_start-dsi.v_start) >> PAGE_SHIFT;
980 /* Map shared info frame into guest physmap. */
981 xatp.domid = dom;
982 xatp.space = XENMAPSPACE_shared_info;
983 xatp.idx = 0;
984 xatp.gpfn = guest_shared_info_mfn;
985 rc = xc_memory_op(xc_handle, XENMEM_add_to_physmap, &xatp);
986 if ( rc != 0 )
987 {
988 PERROR("Cannot map shared info pfn");
989 goto error_out;
990 }
992 /* Map grant table frames into guest physmap. */
993 for ( i = 0; ; i++ )
994 {
995 xatp.domid = dom;
996 xatp.space = XENMAPSPACE_grant_table;
997 xatp.idx = i;
998 xatp.gpfn = nr_pages + i;
999 rc = xc_memory_op(xc_handle, XENMEM_add_to_physmap, &xatp);
1000 if ( rc != 0 )
1002 if ( errno == EINVAL )
1003 break; /* done all grant tables */
1004 PERROR("Cannot map grant table pfn");
1005 goto error_out;
1009 else
1011 guest_shared_info_mfn = shared_info_frame;
1014 *store_mfn = page_array[(vstoreinfo_start-dsi.v_start) >> PAGE_SHIFT];
1015 *console_mfn = page_array[(vconsole_start-dsi.v_start) >> PAGE_SHIFT];
1016 if ( xc_clear_domain_page(xc_handle, dom, *store_mfn) ||
1017 xc_clear_domain_page(xc_handle, dom, *console_mfn) )
1018 goto error_out;
1019 if ( shadow_mode_enabled )
1021 guest_store_mfn = (vstoreinfo_start-dsi.v_start) >> PAGE_SHIFT;
1022 guest_console_mfn = (vconsole_start-dsi.v_start) >> PAGE_SHIFT;
1024 else
1026 guest_store_mfn = *store_mfn;
1027 guest_console_mfn = *console_mfn;
1030 start_info = xc_map_foreign_range(
1031 xc_handle, dom, PAGE_SIZE, PROT_READ|PROT_WRITE,
1032 page_array[(vstartinfo_start-dsi.v_start)>>PAGE_SHIFT]);
1033 /*shared_info, start_info */
1034 memset(start_info, 0, sizeof(*start_info));
1035 rc = xc_version(xc_handle, XENVER_version, NULL);
1036 sprintf(start_info->magic, "xen-%i.%i-x86_%d%s",
1037 rc >> 16, rc & (0xFFFF), (unsigned int)sizeof(long)*8,
1038 (dsi.pae_kernel != PAEKERN_no) ? "p" : "");
1039 start_info->nr_pages = nr_pages;
1040 start_info->shared_info = guest_shared_info_mfn << PAGE_SHIFT;
1041 start_info->flags = flags;
1042 start_info->pt_base = vpt_start;
1043 start_info->nr_pt_frames = nr_pt_pages;
1044 start_info->mfn_list = vphysmap_start;
1045 start_info->store_mfn = guest_store_mfn;
1046 start_info->store_evtchn = store_evtchn;
1047 start_info->console.domU.mfn = guest_console_mfn;
1048 start_info->console.domU.evtchn = console_evtchn;
1049 if ( initrd->len != 0 )
1051 start_info->mod_start = vinitrd_start;
1052 start_info->mod_len = initrd->len;
1054 if ( cmdline != NULL )
1056 strncpy((char *)start_info->cmd_line, cmdline, MAX_GUEST_CMDLINE);
1057 start_info->cmd_line[MAX_GUEST_CMDLINE-1] = '\0';
1059 munmap(start_info, PAGE_SIZE);
1061 /* shared_info page starts its life empty. */
1062 shared_info = xc_map_foreign_range(
1063 xc_handle, dom, PAGE_SIZE, PROT_READ|PROT_WRITE, shared_info_frame);
1064 memset(shared_info, 0, PAGE_SIZE);
1065 /* Mask all upcalls... */
1066 for ( i = 0; i < MAX_VIRT_CPUS; i++ )
1067 shared_info->vcpu_info[i].evtchn_upcall_mask = 1;
1069 munmap(shared_info, PAGE_SIZE);
1071 hypercall_page = xen_elfnote_numeric(&dsi, XEN_ELFNOTE_HYPERCALL_PAGE,
1072 &hypercall_page_defined);
1073 if ( hypercall_page_defined )
1075 unsigned long long pfn = (hypercall_page - dsi.v_start) >> PAGE_SHIFT;
1076 if ( pfn >= nr_pages )
1077 goto error_out;
1078 domctl.domain = (domid_t)dom;
1079 domctl.u.hypercall_init.gmfn = shadow_mode_enabled ?
1080 pfn : page_array[pfn];
1081 domctl.cmd = XEN_DOMCTL_hypercall_init;
1082 if ( xc_domctl(xc_handle, &domctl) )
1083 goto error_out;
1086 free(page_array);
1088 *pvsi = vstartinfo_start;
1089 *pvss = vstack_start;
1090 *pvke = dsi.v_kernentry;
1092 return 0;
1094 error_out:
1095 free(page_array);
1096 return -1;
1098 #endif
1100 static int xc_linux_build_internal(int xc_handle,
1101 uint32_t domid,
1102 unsigned int mem_mb,
1103 char *image,
1104 unsigned long image_size,
1105 struct initrd_info *initrd,
1106 const char *cmdline,
1107 const char *features,
1108 unsigned long flags,
1109 unsigned int store_evtchn,
1110 unsigned long *store_mfn,
1111 unsigned int console_evtchn,
1112 unsigned long *console_mfn)
1114 struct xen_domctl launch_domctl;
1115 DECLARE_DOMCTL;
1116 int rc;
1117 struct vcpu_guest_context st_ctxt, *ctxt = &st_ctxt;
1118 unsigned long vstartinfo_start, vkern_entry, vstack_start;
1119 uint32_t features_bitmap[XENFEAT_NR_SUBMAPS] = { 0, };
1121 if ( features != NULL )
1123 if ( !parse_features(features, features_bitmap, NULL) )
1125 PERROR("Failed to parse configured features\n");
1126 goto error_out;
1130 memset(ctxt, 0, sizeof(*ctxt));
1132 if ( lock_pages(ctxt, sizeof(*ctxt) ) )
1134 PERROR("%s: ctxt lock failed", __func__);
1135 return 1;
1138 domctl.cmd = XEN_DOMCTL_getdomaininfo;
1139 domctl.domain = (domid_t)domid;
1140 if ( (xc_domctl(xc_handle, &domctl) < 0) ||
1141 ((uint16_t)domctl.domain != domid) )
1143 PERROR("Could not get info on domain");
1144 goto error_out;
1147 if ( setup_guest(xc_handle, domid, image, image_size,
1148 initrd,
1149 mem_mb << (20 - PAGE_SHIFT),
1150 &vstartinfo_start, &vkern_entry,
1151 &vstack_start, ctxt, cmdline,
1152 domctl.u.getdomaininfo.shared_info_frame,
1153 flags, store_evtchn, store_mfn,
1154 console_evtchn, console_mfn,
1155 features_bitmap) < 0 )
1157 ERROR("Error constructing guest OS");
1158 goto error_out;
1161 #ifdef __ia64__
1162 /* based on new_thread in xen/arch/ia64/domain.c */
1163 ctxt->user_regs.cr_iip = vkern_entry;
1164 ctxt->user_regs.cr_ifs = 1UL << 63;
1165 ctxt->user_regs.ar_fpsr = xc_ia64_fpsr_default();
1166 #else /* x86 */
1167 /*
1168 * Initial register values:
1169 * DS,ES,FS,GS = FLAT_KERNEL_DS
1170 * CS:EIP = FLAT_KERNEL_CS:start_pc
1171 * SS:ESP = FLAT_KERNEL_DS:start_stack
1172 * ESI = start_info
1173 * [EAX,EBX,ECX,EDX,EDI,EBP are zero]
1174 * EFLAGS = IF | 2 (bit 1 is reserved and should always be 1)
1175 */
1176 ctxt->user_regs.ds = FLAT_KERNEL_DS;
1177 ctxt->user_regs.es = FLAT_KERNEL_DS;
1178 ctxt->user_regs.fs = FLAT_KERNEL_DS;
1179 ctxt->user_regs.gs = FLAT_KERNEL_DS;
1180 ctxt->user_regs.ss = FLAT_KERNEL_SS;
1181 ctxt->user_regs.cs = FLAT_KERNEL_CS;
1182 ctxt->user_regs.eip = vkern_entry;
1183 ctxt->user_regs.esp = vstack_start + PAGE_SIZE;
1184 ctxt->user_regs.esi = vstartinfo_start;
1185 ctxt->user_regs.eflags = 1 << 9; /* Interrupt Enable */
1187 ctxt->flags = VGCF_IN_KERNEL;
1189 ctxt->kernel_ss = ctxt->user_regs.ss;
1190 ctxt->kernel_sp = ctxt->user_regs.esp;
1191 #endif /* x86 */
1193 memset(&launch_domctl, 0, sizeof(launch_domctl));
1195 launch_domctl.domain = (domid_t)domid;
1196 launch_domctl.u.vcpucontext.vcpu = 0;
1197 set_xen_guest_handle(launch_domctl.u.vcpucontext.ctxt, ctxt);
1199 launch_domctl.cmd = XEN_DOMCTL_setvcpucontext;
1200 rc = xc_domctl(xc_handle, &launch_domctl);
1202 return rc;
1204 error_out:
1205 return -1;
1208 int xc_linux_build_mem(int xc_handle,
1209 uint32_t domid,
1210 unsigned int mem_mb,
1211 const char *image_buffer,
1212 unsigned long image_size,
1213 const char *initrd,
1214 unsigned long initrd_len,
1215 const char *cmdline,
1216 const char *features,
1217 unsigned long flags,
1218 unsigned int store_evtchn,
1219 unsigned long *store_mfn,
1220 unsigned int console_evtchn,
1221 unsigned long *console_mfn)
1223 int sts;
1224 char *img_buf;
1225 unsigned long img_len;
1226 struct initrd_info initrd_info = { .type = INITRD_none };
1228 /* A kernel buffer is required */
1229 if ( (image_buffer == NULL) || (image_size == 0) )
1231 ERROR("kernel image buffer not present");
1232 return -1;
1235 /* If it's gzipped, inflate it; otherwise, use as is */
1236 /* xc_inflate_buffer may return the same buffer pointer if */
1237 /* the buffer is already inflated */
1238 img_buf = xc_inflate_buffer(image_buffer, image_size, &img_len);
1239 if ( img_buf == NULL )
1241 ERROR("unable to inflate kernel image buffer");
1242 return -1;
1245 /* RAM disks are optional; if we get one, inflate it */
1246 if ( initrd != NULL )
1248 initrd_info.type = INITRD_mem;
1249 initrd_info.u.mem_addr = xc_inflate_buffer(
1250 initrd, initrd_len, &initrd_info.len);
1251 if ( initrd_info.u.mem_addr == NULL )
1253 ERROR("unable to inflate ram disk buffer");
1254 sts = -1;
1255 goto out;
1259 sts = xc_linux_build_internal(xc_handle, domid, mem_mb, img_buf, img_len,
1260 &initrd_info, cmdline, features, flags,
1261 store_evtchn, store_mfn,
1262 console_evtchn, console_mfn);
1264 out:
1265 /* The inflation routines may pass back the same buffer so be */
1266 /* sure that we have a buffer and that it's not the one passed in. */
1267 /* Don't unnecessarily annoy/surprise/confound the caller */
1268 if ( (img_buf != NULL) && (img_buf != image_buffer) )
1269 free(img_buf);
1270 if ( (initrd_info.u.mem_addr != NULL) &&
1271 (initrd_info.u.mem_addr != initrd) )
1272 free(initrd_info.u.mem_addr);
1274 return sts;
1277 int xc_linux_build(int xc_handle,
1278 uint32_t domid,
1279 unsigned int mem_mb,
1280 const char *image_name,
1281 const char *initrd_name,
1282 const char *cmdline,
1283 const char *features,
1284 unsigned long flags,
1285 unsigned int store_evtchn,
1286 unsigned long *store_mfn,
1287 unsigned int console_evtchn,
1288 unsigned long *console_mfn)
1290 char *image = NULL;
1291 unsigned long image_size;
1292 struct initrd_info initrd_info = { .type = INITRD_none };
1293 int fd = -1, sts = -1;
1295 if ( (image_name == NULL) ||
1296 ((image = xc_read_image(image_name, &image_size)) == NULL ))
1297 return -1;
1299 if ( (initrd_name != NULL) && (strlen(initrd_name) != 0) )
1301 initrd_info.type = INITRD_file;
1303 if ( (fd = open(initrd_name, O_RDONLY)) < 0 )
1305 PERROR("Could not open the initial ramdisk image");
1306 goto error_out;
1309 if ( (initrd_info.u.file_handle = gzdopen(fd, "rb")) == NULL )
1311 PERROR("Could not allocate decompression state for initrd");
1312 goto error_out;
1316 sts = xc_linux_build_internal(xc_handle, domid, mem_mb, image, image_size,
1317 &initrd_info, cmdline, features, flags,
1318 store_evtchn, store_mfn,
1319 console_evtchn, console_mfn);
1321 error_out:
1322 free(image);
1323 if ( initrd_info.type == INITRD_file && initrd_info.u.file_handle )
1324 gzclose(initrd_info.u.file_handle);
1325 else if ( fd >= 0 )
1326 close(fd);
1328 return sts;
1331 /*
1332 * Local variables:
1333 * mode: C
1334 * c-set-style: "BSD"
1335 * c-basic-offset: 4
1336 * tab-width: 4
1337 * indent-tabs-mode: nil
1338 * End:
1339 */