direct-io.hg

view tools/libxc/xc_linux_build.c @ 12765:2dd4569e0640

[LIBXC] Add an error reporting API to the libxc library.

- An 'xc_error' struct is used to pass around error
details. Currently contains two members 'code' an enumeration of
error types, and 'message' a free text description of the specific
problem.

- The xc_get_last_error() method returns a const pointer to the
internal instance of this struct manged by libxc. By returning a
const pointer we can add extra members to the end of the struct at
any time without worrying about ABI of callers. This will let us
provide more fine-grained info if needed in the future.

- The xc_error instance is statically defined inside libxc and marked
__thread. This ensures that errors are recorded per-thread, and
that when dealing with errors we never need to call malloc - all
storage needed is statically allocated.

- The xc_clear_last_error() method resets any currently recorded
error details

- The xc_error_code_to_desc() method converts the integer error code
into a generic user facing messsage. eg "Invalid kernel". Together
with the 'message' field from xc_error, this provides the user
visible feedback. eg "Invalid kernel: Non PAE-kernel on PAE host."

- A callback can be registered with xc_set_error_handler to receive
notification whenever an error is recorded, rather than querying
for error details after the fact with xc_get_last_error

- If built with -DDEBUG set, a default error handler will be
registered which calls fprintf(stderr), thus maintaining current
behaviour of logging errors to stderr during developer builds.

- The python binding for libxc is updated to use xc_get_last_error
to pull out error details whenever appropriate, instead of
returning info based on 'errno'

- The xc_set_error method is private to libxc internals, and is used
for setting error details

- The ERROR and PERROR macros have been updated to call xc_set_error
automatically specifying XC_INTERNAL_ERROR as the error code. This
gives a generic error report for all current failure points

- Some uses of the ERROR macro have been replaced with explicit
calls to xc_set_error to enable finer grained error reporting. In
particular the code dealing with invalid kernel types uses this
to report about PAE/architecture/wordsize mismatches

The patch has been tested by calling xm create against a varietry of
config files defining invalid kernels of various kinds. It has also
been tested with libvirt talking to xend. In both cases the error
messages were propagated all the way back up the stack.

There is only one place where I need to do further work. The suspend
& restore APIs in Xend invoke external helper programs rather than
calling libxc directly. This means that error details are essentially
lost. Since there is already code in XenD which scans STDERR from
these programs I will investigate adapting this to extract actual
error messages from these helpers.

Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
author kfraser@localhost.localdomain
date Thu Dec 07 11:36:26 2006 +0000 (2006-12-07)
parents 2ae4e4e89d6d
children da87dc126b33
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 xc_set_error(XC_INVALID_KERNEL, "Not a valid ELF or raw kernel image");
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 shared_info_t *shared_info;
485 int i;
486 DECLARE_DOMCTL;
487 int rc;
489 rc = probeimageformat(image, image_size, &load_funcs);
490 if ( rc != 0 )
491 goto error_out;
493 memset(&dsi, 0, sizeof(struct domain_setup_info));
495 rc = (load_funcs.parseimage)(image, image_size, &dsi);
496 if ( rc != 0 )
497 goto error_out;
499 if ( (page_array = malloc(nr_pages * sizeof(xen_pfn_t))) == NULL )
500 {
501 PERROR("Could not allocate memory");
502 goto error_out;
503 }
504 for ( i = 0; i < nr_pages; i++ )
505 page_array[i] = i;
506 if ( xc_domain_memory_populate_physmap(xc_handle, dom, nr_pages,
507 0, 0, page_array) )
508 {
509 PERROR("Could not allocate memory for PV guest.\n");
510 goto error_out;
511 }
513 dsi.v_start = round_pgdown(dsi.v_start);
514 vinitrd_start = round_pgup(dsi.v_end);
515 start_info_mpa = (nr_pages - 3) << PAGE_SHIFT;
516 *pvke = dsi.v_kernentry;
518 /* Build firmware. */
519 memset(&domctl.u.arch_setup, 0, sizeof(domctl.u.arch_setup));
520 domctl.u.arch_setup.flags = 0;
521 domctl.u.arch_setup.bp = start_info_mpa + sizeof (start_info_t);
522 domctl.u.arch_setup.maxmem = (nr_pages - 3) << PAGE_SHIFT;
523 domctl.cmd = XEN_DOMCTL_arch_setup;
524 domctl.domain = (domid_t)dom;
525 if ( xc_domctl(xc_handle, &domctl) )
526 goto error_out;
528 start_page = dsi.v_start >> PAGE_SHIFT;
529 /* in order to get initrd->len, we need to load initrd image at first */
530 if ( load_initrd(xc_handle, dom, initrd,
531 vinitrd_start - dsi.v_start, page_array + start_page) )
532 goto error_out;
534 vinitrd_end = vinitrd_start + initrd->len;
535 v_end = round_pgup(vinitrd_end);
536 pgnr = (v_end - dsi.v_start) >> PAGE_SHIFT;
537 if ( pgnr > nr_pages )
538 {
539 PERROR("too small memory is specified. "
540 "At least %ld kb is necessary.\n",
541 pgnr << (PAGE_SHIFT - 10));
542 }
544 IPRINTF("VIRTUAL MEMORY ARRANGEMENT:\n"
545 " Loaded kernel: %p->%p\n"
546 " Init. ramdisk: %p->%p\n"
547 " TOTAL: %p->%p\n",
548 _p(dsi.v_kernstart), _p(dsi.v_kernend),
549 _p(vinitrd_start), _p(vinitrd_end),
550 _p(dsi.v_start), _p(v_end));
551 IPRINTF(" ENTRY ADDRESS: %p\n", _p(dsi.v_kernentry));
553 (load_funcs.loadimage)(image, image_size, xc_handle, dom,
554 page_array + start_page, &dsi);
556 *store_mfn = page_array[nr_pages - 2];
557 *console_mfn = page_array[nr_pages - 1];
558 IPRINTF("start_info: 0x%lx at 0x%lx, "
559 "store_mfn: 0x%lx at 0x%lx, "
560 "console_mfn: 0x%lx at 0x%lx\n",
561 page_array[nr_pages - 3], nr_pages - 3,
562 *store_mfn, nr_pages - 2,
563 *console_mfn, nr_pages - 1);
565 start_info = xc_map_foreign_range(
566 xc_handle, dom, PAGE_SIZE, PROT_READ|PROT_WRITE,
567 page_array[nr_pages - 3]);
568 memset(start_info, 0, sizeof(*start_info));
569 rc = xc_version(xc_handle, XENVER_version, NULL);
570 sprintf(start_info->magic, "xen-%i.%i-ia64", rc >> 16, rc & (0xFFFF));
571 start_info->flags = flags;
572 start_info->store_mfn = nr_pages - 2;
573 start_info->store_evtchn = store_evtchn;
574 start_info->console.domU.mfn = nr_pages - 1;
575 start_info->console.domU.evtchn = console_evtchn;
576 start_info->nr_pages = nr_pages; // FIXME?: nr_pages - 2 ????
578 bp = (struct xen_ia64_boot_param *)(start_info + 1);
579 bp->command_line = start_info_mpa + offsetof(start_info_t, cmd_line);
580 if ( cmdline != NULL )
581 {
582 strncpy((char *)start_info->cmd_line, cmdline, MAX_GUEST_CMDLINE);
583 start_info->cmd_line[MAX_GUEST_CMDLINE - 1] = 0;
584 }
585 if ( initrd->len != 0 )
586 {
587 bp->initrd_start = vinitrd_start;
588 bp->initrd_size = initrd->len;
589 }
590 ctxt->user_regs.r28 = start_info_mpa + sizeof (start_info_t);
591 munmap(start_info, PAGE_SIZE);
593 /* shared_info page starts its life empty. */
594 shared_info = xc_map_foreign_range(
595 xc_handle, dom, PAGE_SIZE, PROT_READ|PROT_WRITE, shared_info_frame);
596 printf("shared_info = %p, err=%s frame=%lx\n",
597 shared_info, strerror (errno), shared_info_frame);
598 //memset(shared_info, 0, PAGE_SIZE);
599 /* Mask all upcalls... */
600 for ( i = 0; i < MAX_VIRT_CPUS; i++ )
601 shared_info->vcpu_info[i].evtchn_upcall_mask = 1;
602 shared_info->arch.start_info_pfn = nr_pages - 3;
604 munmap(shared_info, PAGE_SIZE);
606 free(page_array);
607 return 0;
609 error_out:
610 free(page_array);
611 return -1;
612 }
613 #else /* x86 */
615 /* Check if the platform supports the guest kernel format */
616 static int compat_check(int xc_handle, struct domain_setup_info *dsi)
617 {
618 xen_capabilities_info_t xen_caps = "";
620 if (xc_version(xc_handle, XENVER_capabilities, &xen_caps) != 0) {
621 xc_set_error(XC_INVALID_KERNEL,
622 "Cannot determine host capabilities.");
623 return 0;
624 }
626 if (strstr(xen_caps, "xen-3.0-x86_32p")) {
627 if (dsi->pae_kernel == PAEKERN_no) {
628 xc_set_error(XC_INVALID_KERNEL,
629 "Non PAE-kernel on PAE host.");
630 return 0;
631 }
632 } else if (dsi->pae_kernel != PAEKERN_no) {
633 xc_set_error(XC_INVALID_KERNEL,
634 "PAE-kernel on non-PAE host.");
635 return 0;
636 }
638 return 1;
639 }
641 static inline int increment_ulong(unsigned long *pval, unsigned long inc)
642 {
643 if ( inc >= -*pval )
644 {
645 ERROR("Value wrapped to zero: image too large?");
646 return 0;
647 }
648 *pval += inc;
649 return 1;
650 }
652 static int setup_guest(int xc_handle,
653 uint32_t dom,
654 const char *image, unsigned long image_size,
655 struct initrd_info *initrd,
656 unsigned long nr_pages,
657 unsigned long *pvsi, unsigned long *pvke,
658 unsigned long *pvss, vcpu_guest_context_t *ctxt,
659 const char *cmdline,
660 unsigned long shared_info_frame,
661 unsigned long flags,
662 unsigned int store_evtchn, unsigned long *store_mfn,
663 unsigned int console_evtchn, unsigned long *console_mfn,
664 uint32_t required_features[XENFEAT_NR_SUBMAPS])
665 {
666 xen_pfn_t *page_array = NULL;
667 unsigned long count, i;
668 unsigned long long hypercall_page;
669 int hypercall_page_defined;
670 start_info_t *start_info;
671 shared_info_t *shared_info;
672 const char *p;
673 DECLARE_DOMCTL;
674 int rc;
676 unsigned long nr_pt_pages;
677 unsigned long physmap_pfn;
678 xen_pfn_t *physmap, *physmap_e;
680 struct load_funcs load_funcs;
681 struct domain_setup_info dsi;
682 unsigned long vinitrd_start;
683 unsigned long vphysmap_start;
684 unsigned long vstartinfo_start;
685 unsigned long vstoreinfo_start;
686 unsigned long vconsole_start;
687 unsigned long vsharedinfo_start = 0; /* XXX gcc */
688 unsigned long vstack_start;
689 unsigned long vstack_end;
690 unsigned long vpt_start;
691 unsigned long vpt_end;
692 unsigned long v_end;
693 unsigned long guest_store_mfn, guest_console_mfn, guest_shared_info_mfn;
694 unsigned long shadow_mode_enabled;
695 uint32_t supported_features[XENFEAT_NR_SUBMAPS] = { 0, };
697 rc = probeimageformat(image, image_size, &load_funcs);
698 if ( rc != 0 )
699 goto error_out;
701 memset(&dsi, 0, sizeof(struct domain_setup_info));
703 rc = (load_funcs.parseimage)(image, image_size, &dsi);
704 if ( rc != 0 )
705 goto error_out;
707 if ( (dsi.v_start & (PAGE_SIZE-1)) != 0 )
708 {
709 PERROR("Guest OS must load to a page boundary.");
710 goto error_out;
711 }
713 if ( !compat_check(xc_handle, &dsi) )
714 goto error_out;
716 /* Parse and validate kernel features. */
717 if ( (p = xen_elfnote_string(&dsi, XEN_ELFNOTE_FEATURES)) != NULL )
718 {
719 if ( !parse_features(p, supported_features, required_features) )
720 {
721 ERROR("Failed to parse guest kernel features.");
722 goto error_out;
723 }
725 IPRINTF("Supported features = { %08x }.\n", supported_features[0]);
726 IPRINTF("Required features = { %08x }.\n", required_features[0]);
727 }
729 for ( i = 0; i < XENFEAT_NR_SUBMAPS; i++ )
730 {
731 if ( (supported_features[i] & required_features[i]) !=
732 required_features[i] )
733 {
734 ERROR("Guest kernel does not support a required feature.");
735 goto error_out;
736 }
737 }
739 shadow_mode_enabled = test_feature_bit(XENFEAT_auto_translated_physmap,
740 required_features);
742 if ( (page_array = malloc(nr_pages * sizeof(unsigned long))) == NULL )
743 {
744 PERROR("Could not allocate memory");
745 goto error_out;
746 }
748 for ( i = 0; i < nr_pages; i++ )
749 page_array[i] = i;
751 if ( xc_domain_memory_populate_physmap(xc_handle, dom, nr_pages,
752 0, 0, page_array) )
753 {
754 PERROR("Could not allocate memory for PV guest.\n");
755 goto error_out;
756 }
758 rc = (load_funcs.loadimage)(image, image_size,
759 xc_handle, dom, page_array,
760 &dsi);
761 if ( rc != 0 )
762 goto error_out;
764 /*
765 * Why do we need this? The number of page-table frames depends on the
766 * size of the bootstrap address space. But the size of the address space
767 * depends on the number of page-table frames (since each one is mapped
768 * read-only). We have a pair of simultaneous equations in two unknowns,
769 * which we solve by exhaustive search.
770 */
771 v_end = round_pgup(dsi.v_end);
772 if ( v_end == 0 )
773 {
774 ERROR("End of mapped kernel image too close to end of memory");
775 goto error_out;
776 }
778 vinitrd_start = v_end;
779 if ( load_initrd(xc_handle, dom, initrd,
780 vinitrd_start - dsi.v_start, page_array) )
781 goto error_out;
782 if ( !increment_ulong(&v_end, round_pgup(initrd->len)) )
783 goto error_out;
785 vphysmap_start = v_end;
786 if ( !increment_ulong(&v_end, round_pgup(nr_pages * sizeof(long))) )
787 goto error_out;
788 vstartinfo_start = v_end;
789 if ( !increment_ulong(&v_end, PAGE_SIZE) )
790 goto error_out;
791 vstoreinfo_start = v_end;
792 if ( !increment_ulong(&v_end, PAGE_SIZE) )
793 goto error_out;
794 vconsole_start = v_end;
795 if ( !increment_ulong(&v_end, PAGE_SIZE) )
796 goto error_out;
797 if ( shadow_mode_enabled ) {
798 vsharedinfo_start = v_end;
799 if ( !increment_ulong(&v_end, PAGE_SIZE) )
800 goto error_out;
801 }
802 vpt_start = v_end;
804 for ( nr_pt_pages = 2; ; nr_pt_pages++ )
805 {
806 /* vpt_end = vpt_staret + (nr_pt_pages * PAGE_SIZE); */
807 vpt_end = vpt_start;
808 if ( !increment_ulong(&vpt_end, nr_pt_pages * PAGE_SIZE) )
809 goto error_out;
811 vstack_start = vpt_end;
812 /* vstack_end = vstack_start + PAGE_SIZE; */
813 vstack_end = vstack_start;
814 if ( !increment_ulong(&vstack_end, PAGE_SIZE) )
815 goto error_out;
817 /* v_end = (vstack_end + (1UL<<22)-1) & ~((1UL<<22)-1); */
818 v_end = vstack_end;
819 if ( !increment_ulong(&v_end, (1UL<<22)-1) )
820 goto error_out;
821 v_end &= ~((1UL<<22)-1);
823 if ( (v_end - vstack_end) < (512UL << 10) )
824 {
825 /* Add extra 4MB to get >= 512kB padding. */
826 if ( !increment_ulong(&v_end, 1UL << 22) )
827 goto error_out;
828 }
830 #define NR(_l,_h,_s) \
831 (((((unsigned long)(_h) + ((1UL<<(_s))-1)) & ~((1UL<<(_s))-1)) - \
832 ((unsigned long)(_l) & ~((1UL<<(_s))-1))) >> (_s))
833 #if defined(__i386__)
834 if ( dsi.pae_kernel != PAEKERN_no )
835 {
836 if ( (1 + /* # L3 */
837 NR(dsi.v_start, v_end, L3_PAGETABLE_SHIFT_PAE) + /* # L2 */
838 NR(dsi.v_start, v_end, L2_PAGETABLE_SHIFT_PAE) + /* # L1 */
839 /* Include a fourth mid-level page directory for Xen. */
840 (v_end <= (3 << L3_PAGETABLE_SHIFT_PAE)))
841 <= nr_pt_pages )
842 break;
843 }
844 else
845 {
846 if ( (1 + /* # L2 */
847 NR(dsi.v_start, v_end, L2_PAGETABLE_SHIFT)) /* # L1 */
848 <= nr_pt_pages )
849 break;
850 }
851 #elif defined(__x86_64__)
852 if ( (1 + /* # L4 */
853 NR(dsi.v_start, v_end, L4_PAGETABLE_SHIFT) + /* # L3 */
854 NR(dsi.v_start, v_end, L3_PAGETABLE_SHIFT) + /* # L2 */
855 NR(dsi.v_start, v_end, L2_PAGETABLE_SHIFT)) /* # L1 */
856 <= nr_pt_pages )
857 break;
858 #endif
859 }
861 IPRINTF("VIRTUAL MEMORY ARRANGEMENT:\n");
862 IPRINTF(" Loaded kernel: %p->%p\n", _p(dsi.v_kernstart),
863 _p(dsi.v_kernend));
864 if ( initrd->len )
865 IPRINTF(" Initial ramdisk: %p->%p\n", _p(vinitrd_start),
866 _p(vinitrd_start + initrd->len));
867 IPRINTF(" Phys-Mach map: %p\n", _p(vphysmap_start));
868 IPRINTF(" Start info: %p\n", _p(vstartinfo_start));
869 IPRINTF(" Store page: %p\n", _p(vstoreinfo_start));
870 IPRINTF(" Console page: %p\n", _p(vconsole_start));
871 if ( shadow_mode_enabled )
872 IPRINTF(" Shared Info page: %p\n", _p(vsharedinfo_start));
873 IPRINTF(" Page tables: %p\n", _p(vpt_start));
874 IPRINTF(" Boot stack: %p\n", _p(vstack_start));
875 IPRINTF(" TOTAL: %p->%p\n", _p(dsi.v_start), _p(v_end));
876 IPRINTF(" ENTRY ADDRESS: %p\n", _p(dsi.v_kernentry));
878 if ( ((v_end - dsi.v_start)>>PAGE_SHIFT) > nr_pages )
879 {
880 PERROR("Initial guest OS requires too much space\n"
881 "(%pMB is greater than %luMB limit)\n",
882 _p((v_end-dsi.v_start)>>20), nr_pages>>(20-PAGE_SHIFT));
883 goto error_out;
884 }
886 #if defined(__i386__)
887 if ( dsi.pae_kernel != PAEKERN_no )
888 rc = setup_pg_tables_pae(xc_handle, dom, ctxt,
889 dsi.v_start, v_end,
890 page_array, vpt_start, vpt_end,
891 shadow_mode_enabled, dsi.pae_kernel);
892 else
893 rc = setup_pg_tables(xc_handle, dom, ctxt,
894 dsi.v_start, v_end,
895 page_array, vpt_start, vpt_end,
896 shadow_mode_enabled);
897 #endif
898 #if defined(__x86_64__)
899 rc = setup_pg_tables_64(xc_handle, dom, ctxt,
900 dsi.v_start, v_end,
901 page_array, vpt_start, vpt_end,
902 shadow_mode_enabled);
903 #endif
904 if ( rc != 0 )
905 goto error_out;
907 /*
908 * Pin down l2tab addr as page dir page - causes hypervisor to provide
909 * correct protection for the page
910 */
911 if ( !shadow_mode_enabled )
912 {
913 #if defined(__i386__)
914 if ( dsi.pae_kernel != PAEKERN_no )
915 {
916 if ( pin_table(xc_handle, MMUEXT_PIN_L3_TABLE,
917 xen_cr3_to_pfn(ctxt->ctrlreg[3]), dom) )
918 goto error_out;
919 }
920 else
921 {
922 if ( pin_table(xc_handle, MMUEXT_PIN_L2_TABLE,
923 xen_cr3_to_pfn(ctxt->ctrlreg[3]), dom) )
924 goto error_out;
925 }
926 #elif defined(__x86_64__)
927 /*
928 * Pin down l4tab addr as page dir page - causes hypervisor to provide
929 * correct protection for the page
930 */
931 if ( pin_table(xc_handle, MMUEXT_PIN_L4_TABLE,
932 xen_cr3_to_pfn(ctxt->ctrlreg[3]), dom) )
933 goto error_out;
934 #endif
935 }
937 /* Write the phys->machine table entries (machine->phys already done). */
938 physmap_pfn = (vphysmap_start - dsi.v_start) >> PAGE_SHIFT;
939 physmap = physmap_e = xc_map_foreign_range(
940 xc_handle, dom, PAGE_SIZE, PROT_READ|PROT_WRITE,
941 page_array[physmap_pfn++]);
942 for ( count = 0; count < nr_pages; count++ )
943 {
944 *physmap_e++ = page_array[count];
945 if ( ((unsigned long)physmap_e & (PAGE_SIZE-1)) == 0 )
946 {
947 munmap(physmap, PAGE_SIZE);
948 physmap = physmap_e = xc_map_foreign_range(
949 xc_handle, dom, PAGE_SIZE, PROT_READ|PROT_WRITE,
950 page_array[physmap_pfn++]);
951 }
952 }
953 munmap(physmap, PAGE_SIZE);
955 if ( shadow_mode_enabled )
956 {
957 struct xen_add_to_physmap xatp;
959 /* Enable shadow translate mode */
960 if ( xc_shadow_control(xc_handle, dom,
961 XEN_DOMCTL_SHADOW_OP_ENABLE_TRANSLATE,
962 NULL, 0, NULL, 0, NULL) < 0 )
963 {
964 PERROR("Could not enable translation mode");
965 goto error_out;
966 }
968 guest_shared_info_mfn = (vsharedinfo_start-dsi.v_start) >> PAGE_SHIFT;
970 /* Map shared info frame into guest physmap. */
971 xatp.domid = dom;
972 xatp.space = XENMAPSPACE_shared_info;
973 xatp.idx = 0;
974 xatp.gpfn = guest_shared_info_mfn;
975 rc = xc_memory_op(xc_handle, XENMEM_add_to_physmap, &xatp);
976 if ( rc != 0 )
977 {
978 PERROR("Cannot map shared info pfn");
979 goto error_out;
980 }
982 /* Map grant table frames into guest physmap. */
983 for ( i = 0; ; i++ )
984 {
985 xatp.domid = dom;
986 xatp.space = XENMAPSPACE_grant_table;
987 xatp.idx = i;
988 xatp.gpfn = nr_pages + i;
989 rc = xc_memory_op(xc_handle, XENMEM_add_to_physmap, &xatp);
990 if ( rc != 0 )
991 {
992 if ( errno == EINVAL )
993 break; /* done all grant tables */
994 PERROR("Cannot map grant table pfn");
995 goto error_out;
996 }
997 }
998 }
999 else
1001 guest_shared_info_mfn = shared_info_frame;
1004 *store_mfn = page_array[(vstoreinfo_start-dsi.v_start) >> PAGE_SHIFT];
1005 *console_mfn = page_array[(vconsole_start-dsi.v_start) >> PAGE_SHIFT];
1006 if ( xc_clear_domain_page(xc_handle, dom, *store_mfn) ||
1007 xc_clear_domain_page(xc_handle, dom, *console_mfn) )
1008 goto error_out;
1009 if ( shadow_mode_enabled )
1011 guest_store_mfn = (vstoreinfo_start-dsi.v_start) >> PAGE_SHIFT;
1012 guest_console_mfn = (vconsole_start-dsi.v_start) >> PAGE_SHIFT;
1014 else
1016 guest_store_mfn = *store_mfn;
1017 guest_console_mfn = *console_mfn;
1020 start_info = xc_map_foreign_range(
1021 xc_handle, dom, PAGE_SIZE, PROT_READ|PROT_WRITE,
1022 page_array[(vstartinfo_start-dsi.v_start)>>PAGE_SHIFT]);
1023 /*shared_info, start_info */
1024 memset(start_info, 0, sizeof(*start_info));
1025 rc = xc_version(xc_handle, XENVER_version, NULL);
1026 sprintf(start_info->magic, "xen-%i.%i-x86_%d%s",
1027 rc >> 16, rc & (0xFFFF), (unsigned int)sizeof(long)*8,
1028 (dsi.pae_kernel != PAEKERN_no) ? "p" : "");
1029 start_info->nr_pages = nr_pages;
1030 start_info->shared_info = guest_shared_info_mfn << PAGE_SHIFT;
1031 start_info->flags = flags;
1032 start_info->pt_base = vpt_start;
1033 start_info->nr_pt_frames = nr_pt_pages;
1034 start_info->mfn_list = vphysmap_start;
1035 start_info->store_mfn = guest_store_mfn;
1036 start_info->store_evtchn = store_evtchn;
1037 start_info->console.domU.mfn = guest_console_mfn;
1038 start_info->console.domU.evtchn = console_evtchn;
1039 if ( initrd->len != 0 )
1041 start_info->mod_start = vinitrd_start;
1042 start_info->mod_len = initrd->len;
1044 if ( cmdline != NULL )
1046 strncpy((char *)start_info->cmd_line, cmdline, MAX_GUEST_CMDLINE);
1047 start_info->cmd_line[MAX_GUEST_CMDLINE-1] = '\0';
1049 munmap(start_info, PAGE_SIZE);
1051 /* shared_info page starts its life empty. */
1052 shared_info = xc_map_foreign_range(
1053 xc_handle, dom, PAGE_SIZE, PROT_READ|PROT_WRITE, shared_info_frame);
1054 memset(shared_info, 0, PAGE_SIZE);
1055 /* Mask all upcalls... */
1056 for ( i = 0; i < MAX_VIRT_CPUS; i++ )
1057 shared_info->vcpu_info[i].evtchn_upcall_mask = 1;
1059 munmap(shared_info, PAGE_SIZE);
1061 hypercall_page = xen_elfnote_numeric(&dsi, XEN_ELFNOTE_HYPERCALL_PAGE,
1062 &hypercall_page_defined);
1063 if ( hypercall_page_defined )
1065 unsigned long long pfn = (hypercall_page - dsi.v_start) >> PAGE_SHIFT;
1066 if ( pfn >= nr_pages )
1067 goto error_out;
1068 domctl.domain = (domid_t)dom;
1069 domctl.u.hypercall_init.gmfn = shadow_mode_enabled ?
1070 pfn : page_array[pfn];
1071 domctl.cmd = XEN_DOMCTL_hypercall_init;
1072 if ( xc_domctl(xc_handle, &domctl) )
1073 goto error_out;
1076 free(page_array);
1078 *pvsi = vstartinfo_start;
1079 *pvss = vstack_start;
1080 *pvke = dsi.v_kernentry;
1082 return 0;
1084 error_out:
1085 free(page_array);
1086 return -1;
1088 #endif
1090 static int xc_linux_build_internal(int xc_handle,
1091 uint32_t domid,
1092 unsigned int mem_mb,
1093 char *image,
1094 unsigned long image_size,
1095 struct initrd_info *initrd,
1096 const char *cmdline,
1097 const char *features,
1098 unsigned long flags,
1099 unsigned int store_evtchn,
1100 unsigned long *store_mfn,
1101 unsigned int console_evtchn,
1102 unsigned long *console_mfn)
1104 struct xen_domctl launch_domctl;
1105 DECLARE_DOMCTL;
1106 int rc;
1107 struct vcpu_guest_context st_ctxt, *ctxt = &st_ctxt;
1108 unsigned long vstartinfo_start, vkern_entry, vstack_start;
1109 uint32_t features_bitmap[XENFEAT_NR_SUBMAPS] = { 0, };
1111 if ( features != NULL )
1113 if ( !parse_features(features, features_bitmap, NULL) )
1115 PERROR("Failed to parse configured features\n");
1116 goto error_out;
1120 memset(ctxt, 0, sizeof(*ctxt));
1122 if ( lock_pages(ctxt, sizeof(*ctxt) ) )
1124 PERROR("%s: ctxt lock failed", __func__);
1125 return 1;
1128 domctl.cmd = XEN_DOMCTL_getdomaininfo;
1129 domctl.domain = (domid_t)domid;
1130 if ( (xc_domctl(xc_handle, &domctl) < 0) ||
1131 ((uint16_t)domctl.domain != domid) )
1133 PERROR("Could not get info on domain");
1134 goto error_out;
1137 if ( setup_guest(xc_handle, domid, image, image_size,
1138 initrd,
1139 mem_mb << (20 - PAGE_SHIFT),
1140 &vstartinfo_start, &vkern_entry,
1141 &vstack_start, ctxt, cmdline,
1142 domctl.u.getdomaininfo.shared_info_frame,
1143 flags, store_evtchn, store_mfn,
1144 console_evtchn, console_mfn,
1145 features_bitmap) < 0 )
1147 goto error_out;
1150 #ifdef __ia64__
1151 /* based on new_thread in xen/arch/ia64/domain.c */
1152 ctxt->user_regs.cr_iip = vkern_entry;
1153 ctxt->user_regs.cr_ifs = 1UL << 63;
1154 ctxt->user_regs.ar_fpsr = xc_ia64_fpsr_default();
1155 #else /* x86 */
1156 /*
1157 * Initial register values:
1158 * DS,ES,FS,GS = FLAT_KERNEL_DS
1159 * CS:EIP = FLAT_KERNEL_CS:start_pc
1160 * SS:ESP = FLAT_KERNEL_DS:start_stack
1161 * ESI = start_info
1162 * [EAX,EBX,ECX,EDX,EDI,EBP are zero]
1163 * EFLAGS = IF | 2 (bit 1 is reserved and should always be 1)
1164 */
1165 ctxt->user_regs.ds = FLAT_KERNEL_DS;
1166 ctxt->user_regs.es = FLAT_KERNEL_DS;
1167 ctxt->user_regs.fs = FLAT_KERNEL_DS;
1168 ctxt->user_regs.gs = FLAT_KERNEL_DS;
1169 ctxt->user_regs.ss = FLAT_KERNEL_SS;
1170 ctxt->user_regs.cs = FLAT_KERNEL_CS;
1171 ctxt->user_regs.eip = vkern_entry;
1172 ctxt->user_regs.esp = vstack_start + PAGE_SIZE;
1173 ctxt->user_regs.esi = vstartinfo_start;
1174 ctxt->user_regs.eflags = 1 << 9; /* Interrupt Enable */
1176 ctxt->flags = VGCF_IN_KERNEL;
1178 ctxt->kernel_ss = ctxt->user_regs.ss;
1179 ctxt->kernel_sp = ctxt->user_regs.esp;
1180 #endif /* x86 */
1182 memset(&launch_domctl, 0, sizeof(launch_domctl));
1184 launch_domctl.domain = (domid_t)domid;
1185 launch_domctl.u.vcpucontext.vcpu = 0;
1186 set_xen_guest_handle(launch_domctl.u.vcpucontext.ctxt, ctxt);
1188 launch_domctl.cmd = XEN_DOMCTL_setvcpucontext;
1189 rc = xc_domctl(xc_handle, &launch_domctl);
1191 return rc;
1193 error_out:
1194 return -1;
1197 int xc_linux_build_mem(int xc_handle,
1198 uint32_t domid,
1199 unsigned int mem_mb,
1200 const char *image_buffer,
1201 unsigned long image_size,
1202 const char *initrd,
1203 unsigned long initrd_len,
1204 const char *cmdline,
1205 const char *features,
1206 unsigned long flags,
1207 unsigned int store_evtchn,
1208 unsigned long *store_mfn,
1209 unsigned int console_evtchn,
1210 unsigned long *console_mfn)
1212 int sts;
1213 char *img_buf;
1214 unsigned long img_len;
1215 struct initrd_info initrd_info = { .type = INITRD_none };
1217 /* A kernel buffer is required */
1218 if ( (image_buffer == NULL) || (image_size == 0) )
1220 ERROR("kernel image buffer not present");
1221 return -1;
1224 /* If it's gzipped, inflate it; otherwise, use as is */
1225 /* xc_inflate_buffer may return the same buffer pointer if */
1226 /* the buffer is already inflated */
1227 img_buf = xc_inflate_buffer(image_buffer, image_size, &img_len);
1228 if ( img_buf == NULL )
1230 ERROR("unable to inflate kernel image buffer");
1231 return -1;
1234 /* RAM disks are optional; if we get one, inflate it */
1235 if ( initrd != NULL )
1237 initrd_info.type = INITRD_mem;
1238 initrd_info.u.mem_addr = xc_inflate_buffer(
1239 initrd, initrd_len, &initrd_info.len);
1240 if ( initrd_info.u.mem_addr == NULL )
1242 ERROR("unable to inflate ram disk buffer");
1243 sts = -1;
1244 goto out;
1248 sts = xc_linux_build_internal(xc_handle, domid, mem_mb, img_buf, img_len,
1249 &initrd_info, cmdline, features, flags,
1250 store_evtchn, store_mfn,
1251 console_evtchn, console_mfn);
1253 out:
1254 /* The inflation routines may pass back the same buffer so be */
1255 /* sure that we have a buffer and that it's not the one passed in. */
1256 /* Don't unnecessarily annoy/surprise/confound the caller */
1257 if ( (img_buf != NULL) && (img_buf != image_buffer) )
1258 free(img_buf);
1259 if ( (initrd_info.u.mem_addr != NULL) &&
1260 (initrd_info.u.mem_addr != initrd) )
1261 free(initrd_info.u.mem_addr);
1263 return sts;
1266 int xc_linux_build(int xc_handle,
1267 uint32_t domid,
1268 unsigned int mem_mb,
1269 const char *image_name,
1270 const char *initrd_name,
1271 const char *cmdline,
1272 const char *features,
1273 unsigned long flags,
1274 unsigned int store_evtchn,
1275 unsigned long *store_mfn,
1276 unsigned int console_evtchn,
1277 unsigned long *console_mfn)
1279 char *image = NULL;
1280 unsigned long image_size;
1281 struct initrd_info initrd_info = { .type = INITRD_none };
1282 int fd = -1, sts = -1;
1284 if ( (image_name == NULL) ||
1285 ((image = xc_read_image(image_name, &image_size)) == NULL ))
1286 return -1;
1288 if ( (initrd_name != NULL) && (strlen(initrd_name) != 0) )
1290 initrd_info.type = INITRD_file;
1292 if ( (fd = open(initrd_name, O_RDONLY)) < 0 )
1294 PERROR("Could not open the initial ramdisk image");
1295 goto error_out;
1298 if ( (initrd_info.u.file_handle = gzdopen(fd, "rb")) == NULL )
1300 PERROR("Could not allocate decompression state for initrd");
1301 goto error_out;
1305 sts = xc_linux_build_internal(xc_handle, domid, mem_mb, image, image_size,
1306 &initrd_info, cmdline, features, flags,
1307 store_evtchn, store_mfn,
1308 console_evtchn, console_mfn);
1310 error_out:
1311 free(image);
1312 if ( initrd_info.type == INITRD_file && initrd_info.u.file_handle )
1313 gzclose(initrd_info.u.file_handle);
1314 else if ( fd >= 0 )
1315 close(fd);
1317 return sts;
1320 /*
1321 * Local variables:
1322 * mode: C
1323 * c-set-style: "BSD"
1324 * c-basic-offset: 4
1325 * tab-width: 4
1326 * indent-tabs-mode: nil
1327 * End:
1328 */