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); }
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); }
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); }
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); }
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); }
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); }
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); }
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); }