Beispiel #1
0
static void domcreate_attach_vtpms(libxl__egc *egc,
                                   libxl__multidev *multidev,
                                   int ret)
{
   libxl__domain_create_state *dcs = CONTAINER_OF(multidev, *dcs, multidev);
   STATE_AO_GC(dcs->ao);
   int domid = dcs->guest_domid;

   libxl_domain_config* const d_config = dcs->guest_config;

   if(ret) {
       LOG(ERROR, "unable to add nic devices");
       goto error_out;
   }

    /* Plug vtpm devices */
   if (d_config->num_vtpms > 0) {
       /* Attach vtpms */
       libxl__multidev_begin(ao, &dcs->multidev);
       dcs->multidev.callback = domcreate_attach_pci;
       libxl__add_vtpms(egc, ao, domid, d_config, &dcs->multidev);
       libxl__multidev_prepared(egc, &dcs->multidev, 0);
       return;
   }

   domcreate_attach_pci(egc, multidev, 0);
   return;

error_out:
   assert(ret);
   domcreate_complete(egc, dcs, ret);
}
Beispiel #2
0
static void domcreate_rebuild_done(libxl__egc *egc,
                                   libxl__domain_create_state *dcs,
                                   int ret)
{
    STATE_AO_GC(dcs->ao);

    /* convenience aliases */
    const uint32_t domid = dcs->guest_domid;
    libxl_domain_config *const d_config = dcs->guest_config;
    libxl_ctx *const ctx = CTX;

    if (ret) {
        LIBXL__LOG(ctx, LIBXL__LOG_ERROR, "cannot (re-)build domain: %d", ret);
        ret = ERROR_FAIL;
        goto error_out;
    }

    store_libxl_entry(gc, domid, &d_config->b_info);

    libxl__multidev_begin(ao, &dcs->multidev);
    dcs->multidev.callback = domcreate_launch_dm;
    libxl__add_disks(egc, ao, domid, d_config, &dcs->multidev);
    libxl__multidev_prepared(egc, &dcs->multidev, 0);

    return;

 error_out:
    assert(ret);
    domcreate_complete(egc, dcs, ret);
}
Beispiel #3
0
static void domcreate_attach_pci(libxl__egc *egc, libxl__multidev *multidev,
                                 int ret)
{
    libxl__domain_create_state *dcs = CONTAINER_OF(multidev, *dcs, multidev);
    STATE_AO_GC(dcs->ao);
    int i;
    libxl_ctx *ctx = CTX;
    int domid = dcs->guest_domid;

    /* convenience aliases */
    libxl_domain_config *const d_config = dcs->guest_config;

    if (ret) {
        LOG(ERROR, "unable to add vtpm devices");
        goto error_out;
    }

    for (i = 0; i < d_config->num_pcidevs; i++) {
        ret = libxl__device_pci_add(gc, domid, &d_config->pcidevs[i], 1);
        if (ret < 0) {
            LIBXL__LOG(ctx, LIBXL__LOG_ERROR,
                       "libxl_device_pci_add failed: %d", ret);
            goto error_out;
        }
    }

    if (d_config->num_pcidevs > 0) {
        ret = libxl__create_pci_backend(gc, domid, d_config->pcidevs,
            d_config->num_pcidevs);
        if (ret < 0) {
            LIBXL__LOG(ctx, LIBXL__LOG_ERROR,
                "libxl_create_pci_backend failed: %d", ret);
            goto error_out;
        }
    }

    domcreate_console_available(egc, dcs);

    domcreate_complete(egc, dcs, 0);
    return;

error_out:
    assert(ret);
    domcreate_complete(egc, dcs, ret);
}
Beispiel #4
0
static void domcreate_attach_pci(libxl__egc *egc, libxl__multidev *multidev,
                                 int ret)
{
    libxl__domain_create_state *dcs = CONTAINER_OF(multidev, *dcs, multidev);
    STATE_AO_GC(dcs->ao);
    int i;
    libxl_ctx *ctx = CTX;
    int domid = dcs->guest_domid;

    /* convenience aliases */
    libxl_domain_config *const d_config = dcs->guest_config;

    if (ret) {
        LOG(ERROR, "unable to add nic devices");
        goto error_out;
    }

    for (i = 0; i < d_config->num_pcidevs; i++) {
	// TODO(Yusuke Suzuki): we should check target device is nvc0
        libxl__device_pci_add_with_nvc0(gc, domid, &d_config->pcidevs[i], 1, d_config->b_info.u.hvm.nvc0 >= 0);
    }

    if (d_config->num_pcidevs > 0) {
        ret = libxl__create_pci_backend(gc, domid, d_config->pcidevs,
            d_config->num_pcidevs);
        if (ret < 0) {
            LIBXL__LOG(ctx, LIBXL__LOG_ERROR,
                "libxl_create_pci_backend failed: %d", ret);
            goto error_out;
        }
    }

    libxl__arch_domain_create(gc, d_config, domid);
    domcreate_console_available(egc, dcs);

    domcreate_complete(egc, dcs, 0);
    return;

error_out:
    assert(ret);
    domcreate_complete(egc, dcs, ret);
}
Beispiel #5
0
static void domcreate_devmodel_started(libxl__egc *egc,
                                       libxl__dm_spawn_state *dmss,
                                       int ret)
{
    libxl__domain_create_state *dcs = CONTAINER_OF(dmss, *dcs, dmss.dm);
    STATE_AO_GC(dmss->spawn.ao);
    libxl_ctx *ctx = CTX;
    int domid = dcs->guest_domid;

    /* convenience aliases */
    libxl_domain_config *const d_config = dcs->guest_config;

    if (ret) {
        LIBXL__LOG(ctx, LIBXL__LOG_ERROR,
                   "device model did not start: %d", ret);
        goto error_out;
    }

    if (dcs->dmss.dm.guest_domid) {
        if (d_config->b_info.device_model_version
            == LIBXL_DEVICE_MODEL_VERSION_QEMU_XEN) {
            libxl__qmp_initializations(gc, domid, d_config);
        }
    }

    /* Plug nic interfaces */
    if (d_config->num_nics > 0) {
        /* Attach nics */
        libxl__multidev_begin(ao, &dcs->multidev);
        dcs->multidev.callback = domcreate_attach_pci;
        libxl__add_nics(egc, ao, domid, d_config, &dcs->multidev);
        libxl__multidev_prepared(egc, &dcs->multidev, 0);
        return;
    }

    domcreate_attach_pci(egc, &dcs->multidev, 0);
    return;

error_out:
    assert(ret);
    domcreate_complete(egc, dcs, ret);
}
Beispiel #6
0
static void domcreate_launch_dm(libxl__egc *egc, libxl__multidev *multidev,
                                int ret)
{
    libxl__domain_create_state *dcs = CONTAINER_OF(multidev, *dcs, multidev);
    STATE_AO_GC(dcs->ao);
    int i;

    /* convenience aliases */
    const uint32_t domid = dcs->guest_domid;
    libxl_domain_config *const d_config = dcs->guest_config;
    libxl__domain_build_state *const state = &dcs->build_state;

    if (ret) {
        LOG(ERROR, "unable to add disk devices");
        goto error_out;
    }

    for (i = 0; i < d_config->b_info.num_ioports; i++) {
        libxl_ioport_range *io = &d_config->b_info.ioports[i];

        LOG(DEBUG, "dom%d ioports %"PRIx32"-%"PRIx32,
            domid, io->first, io->first + io->number - 1);

        ret = xc_domain_ioport_permission(CTX->xch, domid,
                                          io->first, io->number, 1);
        if ( ret<0 ){
            LOGE(ERROR,
                 "failed give dom%d access to ioports %"PRIx32"-%"PRIx32,
                 domid, io->first, io->first + io->number - 1);
            ret = ERROR_FAIL;
        }
    }

    for (i = 0; i < d_config->b_info.num_irqs; i++) {
        uint32_t irq = d_config->b_info.irqs[i];

        LOG(DEBUG, "dom%d irq %"PRIx32, domid, irq);

        ret = xc_domain_irq_permission(CTX->xch, domid, irq, 1);
        if ( ret<0 ){
            LOGE(ERROR,
                 "failed give dom%d access to irq %"PRId32, domid, irq);
            ret = ERROR_FAIL;
        }
    }

    for (i = 0; i < d_config->num_nics; i++) {
        /* We have to init the nic here, because we still haven't
         * called libxl_device_nic_add at this point, but qemu needs
         * the nic information to be complete.
         */
        ret = libxl__device_nic_setdefault(gc, &d_config->nics[i], domid);
        if (ret)
            goto error_out;
    }
    switch (d_config->c_info.type) {
    case LIBXL_DOMAIN_TYPE_HVM:
    {
        libxl__device_console console;
        libxl_device_vkb vkb;

        ret = init_console_info(&console, 0);
        if ( ret )
            goto error_out;
        libxl__device_console_add(gc, domid, &console, state);
        libxl__device_console_dispose(&console);

        libxl_device_vkb_init(&vkb);
        libxl__device_vkb_add(gc, domid, &vkb);
        libxl_device_vkb_dispose(&vkb);

        dcs->dmss.dm.guest_domid = domid;
        if (libxl_defbool_val(d_config->b_info.device_model_stubdomain))
            libxl__spawn_stub_dm(egc, &dcs->dmss);
        else
            libxl__spawn_local_dm(egc, &dcs->dmss.dm);
        return;
    }
    case LIBXL_DOMAIN_TYPE_PV:
    {
        int need_qemu = 0;
        libxl__device_console console;

        for (i = 0; i < d_config->num_vfbs; i++) {
            libxl__device_vfb_add(gc, domid, &d_config->vfbs[i]);
            libxl__device_vkb_add(gc, domid, &d_config->vkbs[i]);
        }

        ret = init_console_info(&console, 0);
        if ( ret )
            goto error_out;

        need_qemu = libxl__need_xenpv_qemu(gc, 1, &console,
                d_config->num_vfbs, d_config->vfbs,
                d_config->num_disks, &d_config->disks[0]);

        libxl__device_console_add(gc, domid, &console, state);
        libxl__device_console_dispose(&console);

        if (need_qemu) {
            dcs->dmss.dm.guest_domid = domid;
            libxl__spawn_local_dm(egc, &dcs->dmss.dm);
            return;
        } else {
            assert(!dcs->dmss.dm.guest_domid);
            domcreate_devmodel_started(egc, &dcs->dmss.dm, 0);
            return;
        }
    }
    default:
        ret = ERROR_INVAL;
        goto error_out;
    }
    abort(); /* not reached */

 error_out:
    assert(ret);
    domcreate_complete(egc, dcs, ret);
}
Beispiel #7
0
static void initiate_domain_create(libxl__egc *egc,
                                   libxl__domain_create_state *dcs)
{
    STATE_AO_GC(dcs->ao);
    libxl_ctx *ctx = libxl__gc_owner(gc);
    uint32_t domid;
    int i, ret;

    /* convenience aliases */
    libxl_domain_config *const d_config = dcs->guest_config;
    const int restore_fd = dcs->restore_fd;
    memset(&dcs->build_state, 0, sizeof(dcs->build_state));

    domid = 0;

    ret = libxl__domain_create_info_setdefault(gc, &d_config->c_info);
    if (ret) goto error_out;

    ret = libxl__domain_make(gc, &d_config->c_info, &domid);
    if (ret) {
        LIBXL__LOG(ctx, LIBXL__LOG_ERROR, "cannot make domain: %d", ret);
        dcs->guest_domid = domid;
        ret = ERROR_FAIL;
        goto error_out;
    }

    dcs->guest_domid = domid;
    dcs->dmss.dm.guest_domid = 0; /* means we haven't spawned */

    ret = libxl__domain_build_info_setdefault(gc, &d_config->b_info);
    if (ret) goto error_out;

    if (!sched_params_valid(gc, domid, &d_config->b_info.sched_params)) {
        LOG(ERROR, "Invalid scheduling parameters\n");
        ret = ERROR_INVAL;
        goto error_out;
    }

    for (i = 0; i < d_config->num_disks; i++) {
        ret = libxl__device_disk_setdefault(gc, &d_config->disks[i]);
        if (ret) goto error_out;
    }

    dcs->bl.ao = ao;
    libxl_device_disk *bootdisk =
        d_config->num_disks > 0 ? &d_config->disks[0] : NULL;

    if (restore_fd >= 0) {
        LOG(DEBUG, "restoring, not running bootloader\n");
        domcreate_bootloader_done(egc, &dcs->bl, 0);
    } else  {
        LOG(DEBUG, "running bootloader");
        dcs->bl.callback = domcreate_bootloader_done;
        dcs->bl.console_available = domcreate_bootloader_console_available;
        dcs->bl.info = &d_config->b_info;
        dcs->bl.disk = bootdisk;
        dcs->bl.domid = dcs->guest_domid;

        dcs->bl.kernel = &dcs->build_state.pv_kernel;
        dcs->bl.ramdisk = &dcs->build_state.pv_ramdisk;

        libxl__bootloader_run(egc, &dcs->bl);
    }
    return;

error_out:
    assert(ret);
    domcreate_complete(egc, dcs, ret);
}
Beispiel #8
0
static void initiate_domain_create(libxl__egc *egc,
                                   libxl__domain_create_state *dcs)
{
    STATE_AO_GC(dcs->ao);
    libxl_ctx *ctx = libxl__gc_owner(gc);
    uint32_t domid;
    int i, ret;
    size_t last_devid = -1;
    bool pod_enabled = false;

    /* convenience aliases */
    libxl_domain_config *const d_config = dcs->guest_config;
    const int restore_fd = dcs->restore_fd;
    memset(&dcs->build_state, 0, sizeof(dcs->build_state));

    domid = 0;

    /* If target_memkb is smaller than max_memkb, the subsequent call
     * to libxc when building HVM domain will enable PoD mode.
     */
    pod_enabled = (d_config->c_info.type == LIBXL_DOMAIN_TYPE_HVM) &&
        (d_config->b_info.target_memkb < d_config->b_info.max_memkb);

    /* We cannot have PoD and PCI device assignment at the same time
     * for HVM guest. It was reported that IOMMU cannot work with PoD
     * enabled because it needs to populated entire page table for
     * guest. To stay on the safe side, we disable PCI device
     * assignment when PoD is enabled.
     */
    if (d_config->c_info.type == LIBXL_DOMAIN_TYPE_HVM &&
        d_config->num_pcidevs && pod_enabled) {
        ret = ERROR_INVAL;
        LOG(ERROR, "PCI device assignment for HVM guest failed due to PoD enabled");
        goto error_out;
    }

    ret = libxl__domain_create_info_setdefault(gc, &d_config->c_info);
    if (ret) goto error_out;

    ret = libxl__domain_make(gc, &d_config->c_info, &domid);
    if (ret) {
        LIBXL__LOG(ctx, LIBXL__LOG_ERROR, "cannot make domain: %d", ret);
        dcs->guest_domid = domid;
        ret = ERROR_FAIL;
        goto error_out;
    }

    dcs->guest_domid = domid;
    dcs->dmss.dm.guest_domid = 0; /* means we haven't spawned */

    ret = libxl__domain_build_info_setdefault(gc, &d_config->b_info);
    if (ret) goto error_out;

    if (!sched_params_valid(gc, domid, &d_config->b_info.sched_params)) {
        LOG(ERROR, "Invalid scheduling parameters\n");
        ret = ERROR_INVAL;
        goto error_out;
    }

    for (i = 0; i < d_config->num_disks; i++) {
        ret = libxl__device_disk_setdefault(gc, &d_config->disks[i]);
        if (ret) goto error_out;
    }

    dcs->bl.ao = ao;
    libxl_device_disk *bootdisk =
        d_config->num_disks > 0 ? &d_config->disks[0] : NULL;

    /*
     * The devid has to be set before launching the device model. For the
     * hotplug case this is done in libxl_device_nic_add but on domain
     * creation this is called too late.
     * Make two runs over configured NICs in order to avoid duplicate IDs
     * in case the caller partially assigned IDs.
     */
    for (i = 0; i < d_config->num_nics; i++) {
        /* We have to init the nic here, because we still haven't
         * called libxl_device_nic_add when domcreate_launch_dm gets called,
         * but qemu needs the nic information to be complete.
         */
        ret = libxl__device_nic_setdefault(gc, &d_config->nics[i], domid);
        if (ret) goto error_out;

        if (d_config->nics[i].devid > last_devid)
            last_devid = d_config->nics[i].devid;
    }
    for (i = 0; i < d_config->num_nics; i++) {
        if (d_config->nics[i].devid < 0)
            d_config->nics[i].devid = ++last_devid;
    }

    if (restore_fd >= 0) {
        LOG(DEBUG, "restoring, not running bootloader\n");
        domcreate_bootloader_done(egc, &dcs->bl, 0);
    } else  {
        LOG(DEBUG, "running bootloader");
        dcs->bl.callback = domcreate_bootloader_done;
        dcs->bl.console_available = domcreate_bootloader_console_available;
        dcs->bl.info = &d_config->b_info;
        dcs->bl.disk = bootdisk;
        dcs->bl.domid = dcs->guest_domid;

        dcs->bl.kernel = &dcs->build_state.pv_kernel;
        dcs->bl.ramdisk = &dcs->build_state.pv_ramdisk;

        libxl__bootloader_run(egc, &dcs->bl);
    }
    return;

error_out:
    assert(ret);
    domcreate_complete(egc, dcs, ret);
}