ia64/xen-unstable

view tools/libxc/xc_dom_boot.c @ 13831:82171212156b

New domain builder arch_setup hook clean up.
arch_setup_early -> arch_setup_meminit
arch_setup_middle -> arch_setup_bootearly
arch_setup_late -> arch_setup_bootlate

Signed-off-by: Isaku Yamahata <yamahata@valinux.co.jp>
author kfraser@localhost.localdomain
date Fri Feb 02 15:50:27 2007 +0000 (2007-02-02)
parents f91dd7642a42
children c051ed67258a
line source
1 /*
2 * Xen domain builder -- xen booter.
3 *
4 * This is the code which actually boots a fresh
5 * prepared domain image as xen guest domain.
6 *
7 * ==> this is the only domain bilder code piece
8 * where xen hypercalls are allowed <==
9 *
10 * This code is licenced under the GPL.
11 * written 2006 by Gerd Hoffmann <kraxel@suse.de>.
12 *
13 */
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <string.h>
17 #include <inttypes.h>
18 #include <zlib.h>
20 #include "xg_private.h"
21 #include "xc_dom.h"
22 #include <xen/hvm/params.h>
24 /* ------------------------------------------------------------------------ */
26 static int setup_hypercall_page(struct xc_dom_image *dom)
27 {
28 DECLARE_DOMCTL;
29 xen_pfn_t pfn;
30 int rc;
32 if (-1 == dom->parms.virt_hypercall)
33 return 0;
34 pfn = (dom->parms.virt_hypercall - dom->parms.virt_base)
35 >> XC_DOM_PAGE_SHIFT(dom);
37 xc_dom_printf("%s: vaddr=0x%" PRIx64 " pfn=0x%" PRIpfn "\n", __FUNCTION__,
38 dom->parms.virt_hypercall, pfn);
39 domctl.cmd = XEN_DOMCTL_hypercall_init;
40 domctl.domain = dom->guest_domid;
41 domctl.u.hypercall_init.gmfn = xc_dom_p2m_guest(dom, pfn);
42 rc = do_domctl(dom->guest_xc, &domctl);
43 if (0 != rc)
44 xc_dom_panic(XC_INTERNAL_ERROR, "%s: HYPERCALL_INIT failed (rc=%d)\n",
45 __FUNCTION__, rc);
46 return rc;
47 }
49 static int launch_vm(int xc, domid_t domid, void *ctxt)
50 {
51 DECLARE_DOMCTL;
52 int rc;
54 xc_dom_printf("%s: called, ctxt=%p\n", __FUNCTION__, ctxt);
55 memset(&domctl, 0, sizeof(domctl));
56 domctl.cmd = XEN_DOMCTL_setvcpucontext;
57 domctl.domain = domid;
58 domctl.u.vcpucontext.vcpu = 0;
59 set_xen_guest_handle(domctl.u.vcpucontext.ctxt, ctxt);
60 rc = do_domctl(xc, &domctl);
61 if (0 != rc)
62 xc_dom_panic(XC_INTERNAL_ERROR,
63 "%s: SETVCPUCONTEXT failed (rc=%d)\n", __FUNCTION__, rc);
64 return rc;
65 }
67 static int clear_page(struct xc_dom_image *dom, xen_pfn_t pfn)
68 {
69 xen_pfn_t dst;
70 int rc;
72 if (0 == pfn)
73 return 0;
75 dst = xc_dom_p2m_host(dom, pfn);
76 xc_dom_printf("%s: pfn 0x%" PRIpfn ", mfn 0x%" PRIpfn "\n",
77 __FUNCTION__, pfn, dst);
78 rc = xc_clear_domain_page(dom->guest_xc, dom->guest_domid, dst);
79 if (0 != rc)
80 xc_dom_panic(XC_INTERNAL_ERROR,
81 "%s: xc_clear_domain_page failed (pfn 0x%" PRIpfn
82 ", rc=%d)\n", __FUNCTION__, pfn, rc);
83 return rc;
84 }
86 /* ------------------------------------------------------------------------ */
87 /* arch stuff: x86 bits */
89 #if defined(__i386__) || defined(__x86_64__)
92 static int x86_compat(int xc, domid_t domid, char *guest_type)
93 {
94 static const struct {
95 char *guest;
96 uint32_t size;
97 } types[] = {
98 { "xen-3.0-x86_32p", 32 },
99 { "xen-3.0-x86_64", 64 },
100 };
101 DECLARE_DOMCTL;
102 int i,rc;
104 memset(&domctl, 0, sizeof(domctl));
105 domctl.domain = domid;
106 domctl.cmd = XEN_DOMCTL_set_address_size;
107 for (i = 0; i < sizeof(types)/sizeof(types[0]); i++)
108 if (0 == strcmp(types[i].guest, guest_type))
109 domctl.u.address_size.size = types[i].size;
110 if (0 == domctl.u.address_size.size)
111 /* nothing to do */
112 return 0;
114 xc_dom_printf("%s: guest %s, address size %" PRId32 "\n", __FUNCTION__,
115 guest_type, domctl.u.address_size.size);
116 rc = do_domctl(xc, &domctl);
117 if (0 != rc)
118 xc_dom_printf("%s: warning: failed (rc=%d)\n",
119 __FUNCTION__, rc);
120 return rc;
121 }
124 static int x86_shadow(int xc, domid_t domid)
125 {
126 int rc, mode;
128 xc_dom_printf("%s: called\n", __FUNCTION__);
130 mode = XEN_DOMCTL_SHADOW_ENABLE_REFCOUNT |
131 XEN_DOMCTL_SHADOW_ENABLE_TRANSLATE;
133 rc = xc_shadow_control(xc, domid,
134 XEN_DOMCTL_SHADOW_OP_ENABLE,
135 NULL, 0, NULL, mode, NULL);
136 if (0 != rc)
137 {
138 xc_dom_panic(XC_INTERNAL_ERROR,
139 "%s: SHADOW_OP_ENABLE (mode=0x%x) failed (rc=%d)\n",
140 __FUNCTION__, mode, rc);
141 return rc;
142 }
143 xc_dom_printf("%s: shadow enabled (mode=0x%x)\n", __FUNCTION__, mode);
144 return rc;
145 }
147 static int arch_setup_meminit(struct xc_dom_image *dom)
148 {
149 int rc = 0;
151 x86_compat(dom->guest_xc, dom->guest_domid, dom->guest_type);
152 if (xc_dom_feature_translated(dom))
153 {
154 dom->shadow_enabled = 1;
155 rc = x86_shadow(dom->guest_xc, dom->guest_domid);
156 }
157 return rc;
158 }
160 static int arch_setup_bootearly(struct xc_dom_image *dom)
161 {
162 xc_dom_printf("%s: doing nothing\n", __FUNCTION__);
163 return 0;
164 }
166 static int arch_setup_bootlate(struct xc_dom_image *dom)
167 {
168 static const struct {
169 char *guest;
170 unsigned long pgd_type;
171 } types[] = {
172 { "xen-3.0-x86_32", MMUEXT_PIN_L2_TABLE},
173 { "xen-3.0-x86_32p", MMUEXT_PIN_L3_TABLE},
174 { "xen-3.0-x86_64", MMUEXT_PIN_L4_TABLE},
175 };
176 unsigned long pgd_type = 0;
177 shared_info_t *shared_info;
178 xen_pfn_t shinfo;
179 int i, rc;
181 for (i = 0; i < sizeof(types) / sizeof(types[0]); i++)
182 if (0 == strcmp(types[i].guest, dom->guest_type))
183 pgd_type = types[i].pgd_type;
185 if (!xc_dom_feature_translated(dom))
186 {
187 /* paravirtualized guest */
188 xc_dom_unmap_one(dom, dom->pgtables_seg.pfn);
189 rc = pin_table(dom->guest_xc, pgd_type,
190 xc_dom_p2m_host(dom, dom->pgtables_seg.pfn),
191 dom->guest_domid);
192 if (0 != rc)
193 {
194 xc_dom_panic(XC_INTERNAL_ERROR,
195 "%s: pin_table failed (pfn 0x%" PRIpfn ", rc=%d)\n",
196 __FUNCTION__, dom->pgtables_seg.pfn, rc);
197 return rc;
198 }
199 shinfo = dom->shared_info_mfn;
200 }
201 else
202 {
203 /* paravirtualized guest with auto-translation */
204 struct xen_add_to_physmap xatp;
205 int i;
207 /* Map shared info frame into guest physmap. */
208 xatp.domid = dom->guest_domid;
209 xatp.space = XENMAPSPACE_shared_info;
210 xatp.idx = 0;
211 xatp.gpfn = dom->shared_info_pfn;
212 rc = xc_memory_op(dom->guest_xc, XENMEM_add_to_physmap, &xatp);
213 if (rc != 0)
214 {
215 xc_dom_panic(XC_INTERNAL_ERROR, "%s: mapping shared_info failed "
216 "(pfn=0x%" PRIpfn ", rc=%d)\n",
217 __FUNCTION__, xatp.gpfn, rc);
218 return rc;
219 }
221 /* Map grant table frames into guest physmap. */
222 for (i = 0;; i++)
223 {
224 xatp.domid = dom->guest_domid;
225 xatp.space = XENMAPSPACE_grant_table;
226 xatp.idx = i;
227 xatp.gpfn = dom->total_pages + i;
228 rc = xc_memory_op(dom->guest_xc, XENMEM_add_to_physmap, &xatp);
229 if (rc != 0)
230 {
231 if (i > 0 && errno == EINVAL)
232 {
233 xc_dom_printf("%s: %d grant tables mapped\n", __FUNCTION__,
234 i);
235 break;
236 }
237 xc_dom_panic(XC_INTERNAL_ERROR,
238 "%s: mapping grant tables failed " "(pfn=0x%"
239 PRIpfn ", rc=%d)\n", __FUNCTION__, xatp.gpfn, rc);
240 return rc;
241 }
242 }
243 shinfo = dom->shared_info_pfn;
244 }
246 /* setup shared_info page */
247 xc_dom_printf("%s: shared_info: pfn 0x%" PRIpfn ", mfn 0x%" PRIpfn "\n",
248 __FUNCTION__, dom->shared_info_pfn, dom->shared_info_mfn);
249 shared_info = xc_map_foreign_range(dom->guest_xc, dom->guest_domid,
250 PAGE_SIZE_X86,
251 PROT_READ | PROT_WRITE,
252 shinfo);
253 if (NULL == shared_info)
254 return -1;
255 dom->arch_hooks->shared_info(dom, shared_info);
256 munmap(shared_info, PAGE_SIZE_X86);
258 return 0;
259 }
261 /* ------------------------------------------------------------------------ */
262 /* arch stuff: ia64 */
264 #elif defined(__ia64__)
266 static int arch_setup_meminit(struct xc_dom_image *dom)
267 {
268 xc_dom_printf("%s: doing nothing\n", __FUNCTION__);
269 return 0;
270 }
272 static int arch_setup_bootearly(struct xc_dom_image *dom)
273 {
274 DECLARE_DOMCTL;
275 int rc;
277 xc_dom_printf("%s: setup firmware\n", __FUNCTION__);
279 memset(&domctl, 0, sizeof(domctl));
280 domctl.cmd = XEN_DOMCTL_arch_setup;
281 domctl.domain = dom->guest_domid;
282 domctl.u.arch_setup.flags = 0;
284 domctl.u.arch_setup.bp = (dom->start_info_pfn << PAGE_SHIFT)
285 + sizeof(start_info_t);
286 /* 3 = start info page, xenstore page and console page */
287 domctl.u.arch_setup.maxmem = (dom->total_pages - 3) << PAGE_SHIFT;
288 rc = do_domctl(dom->guest_xc, &domctl);
289 return rc;
290 }
292 static int arch_setup_bootlate(struct xc_dom_image *dom)
293 {
294 unsigned int page_size = XC_DOM_PAGE_SIZE(dom);
295 shared_info_t *shared_info;
297 /* setup shared_info page */
298 xc_dom_printf("%s: shared_info: mfn 0x%" PRIpfn "\n",
299 __FUNCTION__, dom->shared_info_mfn);
300 shared_info = xc_map_foreign_range(dom->guest_xc, dom->guest_domid,
301 page_size,
302 PROT_READ | PROT_WRITE,
303 dom->shared_info_mfn);
304 if (NULL == shared_info)
305 return -1;
306 dom->arch_hooks->shared_info(dom, shared_info);
307 munmap(shared_info, page_size);
308 return 0;
309 }
311 /* ------------------------------------------------------------------------ */
312 /* arch stuff: powerpc */
314 #elif defined(__powerpc64__)
316 static int arch_setup_meminit(struct xc_dom_image *dom)
317 {
318 xc_dom_printf("%s: doing nothing\n", __FUNCTION__);
319 return 0;
320 }
322 static int arch_setup_bootearly(struct xc_dom_image *dom)
323 {
324 xc_dom_printf("%s: doing nothing\n", __FUNCTION__);
325 return 0;
326 }
328 static int arch_setup_bootlate(struct xc_dom_image *dom)
329 {
330 start_info_t *si =
331 xc_dom_pfn_to_ptr(dom, dom->start_info_pfn, 1);
333 xc_dom_printf("%s: TODO: setup devtree\n", __FUNCTION__);
335 #if 0
336 load_devtree(dom->guest_xc,
337 dom->guest_domid,
338 dom->p2m_host,
339 devtree, // FIXME
340 devtree_addr, // FIXME
341 dom->ramdisk_seg.vstart,
342 dom->ramdisk_seg.vend - dom->ramdisk_seg.vstart,
343 si,
344 dom->start_info_pfn << PAGE_SHIFT);
345 #endif
346 return rc;
347 }
349 /* ------------------------------------------------------------------------ */
350 /* arch stuff: other */
352 #else
354 static int arch_setup_meminit(struct xc_dom_image *dom)
355 {
356 xc_dom_printf("%s: doing nothing\n", __FUNCTION__);
357 return 0;
358 }
360 static int arch_setup_bootearly(struct xc_dom_image *dom)
361 {
362 xc_dom_printf("%s: doing nothing\n", __FUNCTION__);
363 return 0;
364 }
366 static int arch_setup_bootlate(struct xc_dom_image *dom)
367 {
368 xc_dom_printf("%s: doing nothing\n", __FUNCTION__);
369 return 0;
370 }
372 #endif /* arch stuff */
374 /* ------------------------------------------------------------------------ */
376 int xc_dom_compat_check(struct xc_dom_image *dom)
377 {
378 xen_capabilities_info_t xen_caps;
379 char *item, *ptr;
380 int match, found = 0;
382 strcpy(xen_caps, dom->xen_caps);
383 for (item = strtok_r(xen_caps, " ", &ptr);
384 NULL != item; item = strtok_r(NULL, " ", &ptr))
385 {
386 match = (0 == strcmp(dom->guest_type, item));
387 xc_dom_printf("%s: supported guest type: %s%s\n", __FUNCTION__,
388 item, match ? " <= matches" : "");
389 if (match)
390 found++;
391 }
392 if (!found)
393 xc_dom_panic(XC_INVALID_KERNEL,
394 "%s: guest type %s not supported by xen kernel, sorry\n",
395 __FUNCTION__, dom->guest_type);
397 return found;
398 }
400 int xc_dom_boot_xen_init(struct xc_dom_image *dom, int xc, domid_t domid)
401 {
402 dom->guest_xc = xc;
403 dom->guest_domid = domid;
405 dom->xen_version = xc_version(dom->guest_xc, XENVER_version, NULL);
406 if (xc_version(xc, XENVER_capabilities, &dom->xen_caps) < 0) {
407 xc_dom_panic(XC_INTERNAL_ERROR, "can't get xen capabilities");
408 return -1;
409 }
410 xc_dom_printf("%s: ver %d.%d, caps %s\n", __FUNCTION__,
411 dom->xen_version >> 16, dom->xen_version & 0xff,
412 dom->xen_caps);
413 return 0;
414 }
416 int xc_dom_boot_mem_init(struct xc_dom_image *dom)
417 {
418 long rc;
420 xc_dom_printf("%s: called\n", __FUNCTION__);
422 if (0 != (rc = arch_setup_meminit(dom)))
423 return rc;
425 /* allocate guest memory */
426 rc = xc_domain_memory_populate_physmap(dom->guest_xc, dom->guest_domid,
427 dom->total_pages, 0, 0,
428 dom->p2m_host);
429 if (0 != rc)
430 {
431 xc_dom_panic(XC_OUT_OF_MEMORY,
432 "%s: can't allocate low memory for domain\n",
433 __FUNCTION__);
434 return rc;
435 }
437 return 0;
438 }
440 void *xc_dom_boot_domU_map(struct xc_dom_image *dom, xen_pfn_t pfn,
441 xen_pfn_t count)
442 {
443 int page_shift = XC_DOM_PAGE_SHIFT(dom);
444 privcmd_mmap_entry_t *entries;
445 void *ptr;
446 int i, rc;
448 entries = xc_dom_malloc(dom, count * sizeof(privcmd_mmap_entry_t));
449 if (NULL == entries)
450 {
451 xc_dom_panic(XC_INTERNAL_ERROR,
452 "%s: failed to mmap domU pages 0x%" PRIpfn "+0x%" PRIpfn
453 " [malloc]\n", __FUNCTION__, pfn, count);
454 return NULL;
455 }
457 ptr = mmap(NULL, count << page_shift, PROT_READ | PROT_WRITE,
458 MAP_SHARED, dom->guest_xc, 0);
459 if (MAP_FAILED == ptr)
460 {
461 xc_dom_panic(XC_INTERNAL_ERROR,
462 "%s: failed to mmap domU pages 0x%" PRIpfn "+0x%" PRIpfn
463 " [mmap]\n", __FUNCTION__, pfn, count);
464 return NULL;
465 }
467 for (i = 0; i < count; i++)
468 {
469 entries[i].va = (uintptr_t) ptr + (i << page_shift);
470 entries[i].mfn = xc_dom_p2m_host(dom, pfn + i);
471 entries[i].npages = 1;
472 }
474 rc = xc_map_foreign_ranges(dom->guest_xc, dom->guest_domid, entries, count);
475 if (rc < 0)
476 {
477 xc_dom_panic(XC_INTERNAL_ERROR,
478 "%s: failed to mmap domU pages 0x%" PRIpfn "+0x%" PRIpfn
479 " [xenctl, rc=%d]\n", __FUNCTION__, pfn, count, rc);
480 return NULL;
481 }
482 return ptr;
483 }
485 int xc_dom_boot_image(struct xc_dom_image *dom)
486 {
487 DECLARE_DOMCTL;
488 void *ctxt;
489 int rc;
491 xc_dom_printf("%s: called\n", __FUNCTION__);
493 /* misc ia64 stuff*/
494 if (0 != (rc = arch_setup_bootearly(dom)))
495 return rc;
497 /* collect some info */
498 domctl.cmd = XEN_DOMCTL_getdomaininfo;
499 domctl.domain = dom->guest_domid;
500 rc = do_domctl(dom->guest_xc, &domctl);
501 if (0 != rc)
502 {
503 xc_dom_panic(XC_INTERNAL_ERROR,
504 "%s: getdomaininfo failed (rc=%d)\n", __FUNCTION__, rc);
505 return rc;
506 }
507 if (domctl.domain != dom->guest_domid)
508 {
509 xc_dom_panic(XC_INTERNAL_ERROR,
510 "%s: Huh? domid mismatch (%d != %d)\n", __FUNCTION__,
511 domctl.domain, dom->guest_domid);
512 return -1;
513 }
514 dom->shared_info_mfn = domctl.u.getdomaininfo.shared_info_frame;
516 /* sanity checks */
517 if (!xc_dom_compat_check(dom))
518 return -1;
520 /* initial mm setup */
521 if (0 != (rc = xc_dom_update_guest_p2m(dom)))
522 return rc;
523 if (dom->arch_hooks->setup_pgtables)
524 if (0 != (rc = dom->arch_hooks->setup_pgtables(dom)))
525 return rc;
527 if (0 != (rc = clear_page(dom, dom->console_pfn)))
528 return rc;
529 if (0 != (rc = clear_page(dom, dom->xenstore_pfn)))
530 return rc;
532 /* start info page */
533 if (dom->arch_hooks->start_info)
534 dom->arch_hooks->start_info(dom);
536 /* hypercall page */
537 if (0 != (rc = setup_hypercall_page(dom)))
538 return rc;
539 xc_dom_log_memory_footprint(dom);
541 /* misc x86 stuff */
542 if (0 != (rc = arch_setup_bootlate(dom)))
543 return rc;
545 /* let the vm run */
546 ctxt = xc_dom_malloc(dom, PAGE_SIZE * 2 /* FIXME */ );
547 memset(ctxt, 0, PAGE_SIZE * 2);
548 if (0 != (rc = dom->arch_hooks->vcpu(dom, ctxt)))
549 return rc;
550 xc_dom_unmap_all(dom);
551 rc = launch_vm(dom->guest_xc, dom->guest_domid, ctxt);
553 return rc;
554 }