Esempio n. 1
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;
    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;
}
Esempio n. 2
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;
}
Esempio n. 5
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;
    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;
}
Esempio n. 6
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;
}
Esempio n. 7
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;
}
Esempio n. 8
0
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 );
}