int xc_dom_alloc_segment(struct xc_dom_image *dom, struct xc_dom_seg *seg, char *name, xen_vaddr_t start, xen_vaddr_t size) { unsigned int page_size = XC_DOM_PAGE_SIZE(dom); xen_pfn_t pages; void *ptr; if ( start && xc_dom_alloc_pad(dom, start) ) return -1; pages = (size + page_size - 1) / page_size; start = dom->virt_alloc_end; seg->pfn = dom->pfn_alloc_end; seg->pages = pages; if ( xc_dom_chk_alloc_pages(dom, name, pages) ) return -1; /* map and clear pages */ ptr = xc_dom_seg_to_ptr(dom, seg); if ( ptr == NULL ) return -1; memset(ptr, 0, pages * page_size); seg->vstart = start; seg->vend = dom->virt_alloc_end; DOMPRINTF("%-20s: %-12s : 0x%" PRIx64 " -> 0x%" PRIx64 " (pfn 0x%" PRIpfn " + 0x%" PRIpfn " pages)", __FUNCTION__, name, seg->vstart, seg->vend, seg->pfn, pages); return 0; }
int xc_dom_alloc_segment(struct xc_dom_image *dom, struct xc_dom_seg *seg, char *name, xen_vaddr_t start, xen_vaddr_t size) { unsigned int page_size = XC_DOM_PAGE_SIZE(dom); xen_pfn_t pages = (size + page_size - 1) / page_size; xen_pfn_t pfn; void *ptr; if ( start == 0 ) start = dom->virt_alloc_end; if ( start & (page_size - 1) ) { xc_dom_panic(dom->xch, XC_INTERNAL_ERROR, "%s: segment start isn't page aligned (0x%" PRIx64 ")", __FUNCTION__, start); return -1; } if ( start < dom->virt_alloc_end ) { xc_dom_panic(dom->xch, XC_INTERNAL_ERROR, "%s: segment start too low (0x%" PRIx64 " < 0x%" PRIx64 ")", __FUNCTION__, start, dom->virt_alloc_end); return -1; } seg->vstart = start; pfn = (seg->vstart - dom->parms.virt_base) / page_size; seg->pfn = pfn + dom->rambase_pfn; if ( pages > dom->total_pages || /* multiple test avoids overflow probs */ pfn > dom->total_pages || pages > dom->total_pages - pfn) { xc_dom_panic(dom->xch, XC_OUT_OF_MEMORY, "%s: segment %s too large (0x%"PRIpfn" > " "0x%"PRIpfn" - 0x%"PRIpfn" pages)", __FUNCTION__, name, pages, dom->total_pages, pfn); return -1; } seg->vend = start + pages * page_size; dom->virt_alloc_end = seg->vend; if (dom->allocate) dom->allocate(dom, dom->virt_alloc_end); DOMPRINTF("%-20s: %-12s : 0x%" PRIx64 " -> 0x%" PRIx64 " (pfn 0x%" PRIpfn " + 0x%" PRIpfn " pages)", __FUNCTION__, name, seg->vstart, seg->vend, seg->pfn, pages); /* map and clear pages */ ptr = xc_dom_seg_to_ptr(dom, seg); if ( ptr == NULL ) return -1; memset(ptr, 0, pages * page_size); return 0; }
static int xc_dom_load_elf_kernel(struct xc_dom_image *dom) { struct elf_binary *elf = dom->private_loader; elf->dest = xc_dom_seg_to_ptr(dom, &dom->kernel_seg); elf_load_binary(elf); if ( dom->parms.bsd_symtab ) xc_dom_load_elf_symtab(dom, elf, 1); return 0; }
static int alloc_magic_pages(struct xc_dom_image *dom) { struct ft_cxt devtree; void *guest_devtree; unsigned long shadow_mb; int rma_pages; int rc; /* Allocate special pages from the end of the RMA. */ rma_pages = 1 << (dom->realmodearea_log - PAGE_SHIFT); dom->shared_info_pfn = --rma_pages; dom->console_pfn = --rma_pages; dom->xenstore_pfn = --rma_pages; /* Gather shadow allocation info for the device tree. */ rc = xc_shadow_control(dom->guest_xc, dom->guest_domid, XEN_DOMCTL_SHADOW_OP_GET_ALLOCATION, NULL, 0, &shadow_mb, 0, NULL); if (rc < 0 || shadow_mb == 0) { xc_dom_printf("Couldn't get shadow allocation size or it was 0.\n"); return rc; } /* Build device tree. */ rc = make_devtree(&devtree, dom, shadow_mb); if (rc < 0) { xc_dom_printf("Failed to create flattened device tree.\n"); return rc; } /* Find a spot for it. */ rc = xc_dom_alloc_segment(dom, &dom->devicetree_seg, "devtree", 0, devtree.bph->totalsize); if (rc) goto out; /* Copy the device tree into place. */ guest_devtree = xc_dom_seg_to_ptr(dom, &dom->devicetree_seg); if (!guest_devtree) { xc_dom_printf("Couldn't map guest memory for device tree.\n"); rc = -1; goto out; } memcpy(guest_devtree, devtree.bph, devtree.bph->totalsize); out: free_devtree(&devtree); return rc; }
int xc_dom_alloc_segment(struct xc_dom_image *dom, struct xc_dom_seg *seg, char *name, xen_vaddr_t start, xen_vaddr_t size) { unsigned int page_size = XC_DOM_PAGE_SIZE(dom); xen_pfn_t pages = (size + page_size - 1) / page_size; void *ptr; if ( start == 0 ) start = dom->virt_alloc_end; if ( start & (page_size - 1) ) { xc_dom_panic(XC_INTERNAL_ERROR, "%s: segment start isn't page aligned (0x%" PRIx64 ")\n", __FUNCTION__, start); return -1; } if ( start < dom->virt_alloc_end ) { xc_dom_panic(XC_INTERNAL_ERROR, "%s: segment start too low (0x%" PRIx64 " < 0x%" PRIx64 ")\n", __FUNCTION__, start, dom->virt_alloc_end); return -1; } seg->vstart = start; seg->vend = start + pages * page_size; seg->pfn = (seg->vstart - dom->parms.virt_base) / page_size; dom->virt_alloc_end = seg->vend; if (dom->allocate) dom->allocate(dom, dom->virt_alloc_end); xc_dom_printf("%-20s: %-12s : 0x%" PRIx64 " -> 0x%" PRIx64 " (pfn 0x%" PRIpfn " + 0x%" PRIpfn " pages)\n", __FUNCTION__, name, seg->vstart, seg->vend, seg->pfn, pages); /* map and clear pages */ ptr = xc_dom_seg_to_ptr(dom, seg); if ( ptr == NULL ) return -1; memset(ptr, 0, pages * page_size); return 0; }
static int xc_dom_load_zimage_kernel(struct xc_dom_image *dom) { void *dst; DOMPRINTF_CALLED(dom->xch); dst = xc_dom_seg_to_ptr(dom, &dom->kernel_seg); if ( dst == NULL ) { DOMPRINTF("%s: xc_dom_seg_to_ptr(dom, &dom->kernel_seg) => NULL", __func__); return -1; } DOMPRINTF("%s: kernel sed %#"PRIx64"-%#"PRIx64, __func__, dom->kernel_seg.vstart, dom->kernel_seg.vend); DOMPRINTF("%s: copy %zd bytes from blob %p to dst %p", __func__, dom->kernel_size, dom->kernel_blob, dst); memcpy(dst, dom->kernel_blob, dom->kernel_size); return 0; }
int xc_dom_build_image(struct xc_dom_image *dom) { unsigned int page_size; xc_dom_printf("%s: called\n", __FUNCTION__); /* check for arch hooks */ if ( dom->arch_hooks == NULL ) { xc_dom_panic(XC_INTERNAL_ERROR, "%s: arch hooks not set\n", __FUNCTION__); goto err; } page_size = XC_DOM_PAGE_SIZE(dom); /* load kernel */ if ( xc_dom_alloc_segment(dom, &dom->kernel_seg, "kernel", dom->kernel_seg.vstart, dom->kernel_seg.vend - dom->kernel_seg.vstart) != 0 ) goto err; if ( dom->kernel_loader->loader(dom) != 0 ) goto err; /* load ramdisk */ if ( dom->ramdisk_blob ) { size_t unziplen, ramdisklen; void *ramdiskmap; unziplen = xc_dom_check_gzip(dom->ramdisk_blob, dom->ramdisk_size); ramdisklen = unziplen ? unziplen : dom->ramdisk_size; if ( xc_dom_alloc_segment(dom, &dom->ramdisk_seg, "ramdisk", 0, ramdisklen) != 0 ) goto err; ramdiskmap = xc_dom_seg_to_ptr(dom, &dom->ramdisk_seg); if ( unziplen ) { if ( xc_dom_do_gunzip(dom->ramdisk_blob, dom->ramdisk_size, ramdiskmap, ramdisklen) == -1 ) goto err; } else memcpy(ramdiskmap, dom->ramdisk_blob, dom->ramdisk_size); } /* allocate other pages */ if ( dom->arch_hooks->alloc_magic_pages(dom) != 0 ) goto err; if ( dom->arch_hooks->count_pgtables ) { dom->arch_hooks->count_pgtables(dom); if ( (dom->pgtables > 0) && (xc_dom_alloc_segment(dom, &dom->pgtables_seg, "page tables", 0, dom->pgtables * page_size) != 0) ) goto err; } if ( dom->alloc_bootstack ) dom->bootstack_pfn = xc_dom_alloc_page(dom, "boot stack"); xc_dom_printf("%-20s: virt_alloc_end : 0x%" PRIx64 "\n", __FUNCTION__, dom->virt_alloc_end); xc_dom_printf("%-20s: virt_pgtab_end : 0x%" PRIx64 "\n", __FUNCTION__, dom->virt_pgtab_end); return 0; err: return -1; }
void kexec(void *kernel, long kernel_size, void *module, long module_size, char *cmdline, unsigned long flags) { struct xc_dom_image *dom; int rc; domid_t domid = DOMID_SELF; xen_pfn_t pfn; xc_interface *xc_handle; unsigned long i; void *seg; xen_pfn_t boot_page_mfn = virt_to_mfn(&_boot_page); char features[] = ""; struct mmu_update *m2p_updates; unsigned long nr_m2p_updates; DEBUG("booting with cmdline %s\n", cmdline); xc_handle = xc_interface_open(0,0,0); dom = xc_dom_allocate(xc_handle, cmdline, features); dom->allocate = kexec_allocate; /* We are using guest owned memory, therefore no limits. */ xc_dom_kernel_max_size(dom, 0); xc_dom_ramdisk_max_size(dom, 0); dom->kernel_blob = kernel; dom->kernel_size = kernel_size; dom->ramdisk_blob = module; dom->ramdisk_size = module_size; dom->flags = flags; dom->console_evtchn = start_info.console.domU.evtchn; dom->xenstore_evtchn = start_info.store_evtchn; tpm_hash2pcr(dom, cmdline); if ( (rc = xc_dom_boot_xen_init(dom, xc_handle, domid)) != 0 ) { grub_printf("xc_dom_boot_xen_init returned %d\n", rc); errnum = ERR_BOOT_FAILURE; goto out; } if ( (rc = xc_dom_parse_image(dom)) != 0 ) { grub_printf("xc_dom_parse_image returned %d\n", rc); errnum = ERR_BOOT_FAILURE; goto out; } #ifdef __i386__ if (strcmp(dom->guest_type, "xen-3.0-x86_32p")) { grub_printf("can only boot x86 32 PAE kernels, not %s\n", dom->guest_type); errnum = ERR_EXEC_FORMAT; goto out; } #endif #ifdef __x86_64__ if (strcmp(dom->guest_type, "xen-3.0-x86_64")) { grub_printf("can only boot x86 64 kernels, not %s\n", dom->guest_type); errnum = ERR_EXEC_FORMAT; goto out; } #endif /* equivalent of xc_dom_mem_init */ dom->arch_hooks = xc_dom_find_arch_hooks(xc_handle, dom->guest_type); dom->total_pages = start_info.nr_pages; /* equivalent of arch_setup_meminit */ /* setup initial p2m */ dom->p2m_host = malloc(sizeof(*dom->p2m_host) * dom->total_pages); /* Start with our current P2M */ for (i = 0; i < dom->total_pages; i++) dom->p2m_host[i] = pfn_to_mfn(i); if ( (rc = xc_dom_build_image(dom)) != 0 ) { grub_printf("xc_dom_build_image returned %d\n", rc); errnum = ERR_BOOT_FAILURE; goto out; } /* copy hypercall page */ /* TODO: domctl instead, but requires privileges */ if (dom->parms.virt_hypercall != -1) { pfn = PHYS_PFN(dom->parms.virt_hypercall - dom->parms.virt_base); memcpy((void *) pages[pfn], hypercall_page, PAGE_SIZE); } /* Equivalent of xc_dom_boot_image */ dom->shared_info_mfn = PHYS_PFN(start_info.shared_info); if (!xc_dom_compat_check(dom)) { grub_printf("xc_dom_compat_check failed\n"); errnum = ERR_EXEC_FORMAT; goto out; } /* Move current console, xenstore and boot MFNs to the allocated place */ do_exchange(dom, dom->console_pfn, start_info.console.domU.mfn); do_exchange(dom, dom->xenstore_pfn, start_info.store_mfn); DEBUG("virt base at %llx\n", dom->parms.virt_base); DEBUG("bootstack_pfn %lx\n", dom->bootstack_pfn); _boot_target = dom->parms.virt_base + PFN_PHYS(dom->bootstack_pfn); DEBUG("_boot_target %lx\n", _boot_target); do_exchange(dom, PHYS_PFN(_boot_target - dom->parms.virt_base), virt_to_mfn(&_boot_page)); /* Make sure the bootstrap page table does not RW-map any of our current * page table frames */ kexec_allocate(dom, dom->virt_pgtab_end); if ( (rc = xc_dom_update_guest_p2m(dom))) { grub_printf("xc_dom_update_guest_p2m returned %d\n", rc); errnum = ERR_BOOT_FAILURE; goto out; } if ( dom->arch_hooks->setup_pgtables ) if ( (rc = dom->arch_hooks->setup_pgtables(dom))) { grub_printf("setup_pgtables returned %d\n", rc); errnum = ERR_BOOT_FAILURE; goto out; } /* start info page */ #undef start_info if ( dom->arch_hooks->start_info ) dom->arch_hooks->start_info(dom); #define start_info (start_info_union.start_info) xc_dom_log_memory_footprint(dom); /* Unmap libxc's projection of the boot page table */ seg = xc_dom_seg_to_ptr(dom, &dom->pgtables_seg); munmap(seg, dom->pgtables_seg.vend - dom->pgtables_seg.vstart); /* Unmap day0 pages to avoid having a r/w mapping of the future page table */ for (pfn = 0; pfn < allocated; pfn++) munmap((void*) pages[pfn], PAGE_SIZE); /* Pin the boot page table base */ if ( (rc = pin_table(dom->xch, #ifdef __i386__ MMUEXT_PIN_L3_TABLE, #endif #ifdef __x86_64__ MMUEXT_PIN_L4_TABLE, #endif xc_dom_p2m_host(dom, dom->pgtables_seg.pfn), dom->guest_domid)) != 0 ) { grub_printf("pin_table(%lx) returned %d\n", xc_dom_p2m_host(dom, dom->pgtables_seg.pfn), rc); errnum = ERR_BOOT_FAILURE; goto out_remap; } /* We populate the Mini-OS page table here so that boot.S can just call * update_va_mapping to project itself there. */ need_pgt(_boot_target); DEBUG("day0 pages %lx\n", allocated); DEBUG("boot target page %lx\n", _boot_target); DEBUG("boot page %p\n", &_boot_page); DEBUG("boot page mfn %lx\n", boot_page_mfn); _boot_page_entry = PFN_PHYS(boot_page_mfn) | L1_PROT; DEBUG("boot page entry %llx\n", _boot_page_entry); _boot_oldpdmfn = virt_to_mfn(start_info.pt_base); DEBUG("boot old pd mfn %lx\n", _boot_oldpdmfn); DEBUG("boot pd virt %lx\n", dom->pgtables_seg.vstart); _boot_pdmfn = dom->p2m_host[PHYS_PFN(dom->pgtables_seg.vstart - dom->parms.virt_base)]; DEBUG("boot pd mfn %lx\n", _boot_pdmfn); _boot_stack = _boot_target + PAGE_SIZE; DEBUG("boot stack %lx\n", _boot_stack); _boot_start_info = dom->parms.virt_base + PFN_PHYS(dom->start_info_pfn); DEBUG("boot start info %lx\n", _boot_start_info); _boot_start = dom->parms.virt_entry; DEBUG("boot start %lx\n", _boot_start); /* Keep only useful entries */ for (nr_m2p_updates = pfn = 0; pfn < start_info.nr_pages; pfn++) if (dom->p2m_host[pfn] != pfn_to_mfn(pfn)) nr_m2p_updates++; m2p_updates = malloc(sizeof(*m2p_updates) * nr_m2p_updates); for (i = pfn = 0; pfn < start_info.nr_pages; pfn++) if (dom->p2m_host[pfn] != pfn_to_mfn(pfn)) { m2p_updates[i].ptr = PFN_PHYS(dom->p2m_host[pfn]) | MMU_MACHPHYS_UPDATE; m2p_updates[i].val = pfn; i++; } for (i = 0; i < blk_nb; i++) shutdown_blkfront(blk_dev[i]); if (net_dev) shutdown_netfront(net_dev); if (kbd_dev) shutdown_kbdfront(kbd_dev); stop_kernel(); /* Update M2P */ if ((rc = HYPERVISOR_mmu_update(m2p_updates, nr_m2p_updates, NULL, DOMID_SELF)) < 0) { xprintk("Could not update M2P\n"); ASSERT(0); } xprintk("go!\n"); /* Jump to trampoline boot page */ _boot(); ASSERT(0); out_remap: for (pfn = 0; pfn < allocated; pfn++) do_map_frames(pages[pfn], &pages_mfns[pfn], 1, 0, 0, DOMID_SELF, 0, L1_PROT); out: xc_dom_release(dom); for (pfn = 0; pfn < allocated; pfn++) free_page((void*)pages[pfn]); free(pages); free(pages_mfns); pages = NULL; pages_mfns = NULL; allocated = 0; xc_interface_close(xc_handle ); }