diff --git a/hypervisor/arch/x86/guest/vm.c b/hypervisor/arch/x86/guest/vm.c index 5ad320e2b..1b2b3c25e 100644 --- a/hypervisor/arch/x86/guest/vm.c +++ b/hypervisor/arch/x86/guest/vm.c @@ -599,34 +599,37 @@ int32_t create_vm(uint16_t vm_id, uint64_t pcpu_bitmap, struct acrn_vm_config *v passthrough_smbios(vm, get_acrn_boot_info()); #endif - init_vpci(vm); - enable_iommu(); - - /* Create virtual uart;*/ - init_legacy_vuarts(vm, vm_config->vuart); - - register_reset_port_handler(vm); - - /* vpic wire_mode default is INTR */ - vm->wire_mode = VPIC_WIRE_INTR; - - /* Init full emulated vIOAPIC instance: - * Present a virtual IOAPIC to guest, as a placeholder interrupt controller, - * even if the guest uses PT LAPIC. This is to satisfy the guest OSes, - * in some cases, though the functionality of vIOAPIC doesn't work. - */ - vioapic_init(vm); - - /* Populate return VM handle */ - *rtn_vm = vm; - vm->sw.io_shared_page = NULL; - if ((vm_config->load_order == POST_LAUNCHED_VM) && ((vm_config->guest_flags & GUEST_FLAG_IO_COMPLETION_POLLING) != 0U)) { - /* enable IO completion polling mode per its guest flags in vm_config. */ - vm->sw.is_polling_ioreq = true; - } - status = set_vcpuid_entries(vm); + status = init_vpci(vm); if (status == 0) { - vm->state = VM_CREATED; + enable_iommu(); + + /* Create virtual uart;*/ + init_legacy_vuarts(vm, vm_config->vuart); + + register_reset_port_handler(vm); + + /* vpic wire_mode default is INTR */ + vm->wire_mode = VPIC_WIRE_INTR; + + /* Init full emulated vIOAPIC instance: + * Present a virtual IOAPIC to guest, as a placeholder interrupt controller, + * even if the guest uses PT LAPIC. This is to satisfy the guest OSes, + * in some cases, though the functionality of vIOAPIC doesn't work. + */ + vioapic_init(vm); + + /* Populate return VM handle */ + *rtn_vm = vm; + vm->sw.io_shared_page = NULL; + if ((vm_config->load_order == POST_LAUNCHED_VM) + && ((vm_config->guest_flags & GUEST_FLAG_IO_COMPLETION_POLLING) != 0U)) { + /* enable IO completion polling mode per its guest flags in vm_config. */ + vm->sw.is_polling_ioreq = true; + } + status = set_vcpuid_entries(vm); + if (status == 0) { + vm->state = VM_CREATED; + } } } diff --git a/hypervisor/dm/vpci/vdev.c b/hypervisor/dm/vpci/vdev.c index 5b90bf200..031070ef5 100644 --- a/hypervisor/dm/vpci/vdev.c +++ b/hypervisor/dm/vpci/vdev.c @@ -149,6 +149,27 @@ static void pci_vdev_update_vbar_base(struct pci_vdev *vdev, uint32_t idx) vdev->vbars[idx].base_gpa = base; } +int32_t check_pt_dev_pio_bars(struct pci_vdev *vdev) +{ + int32_t ret = 0; + uint32_t idx; + + if (vdev->pdev != NULL) { + for (idx = 0U; idx < vdev->nr_bars; idx++) { + if ((is_pci_io_bar(&vdev->vbars[idx])) && (vdev->vbars[idx].base_gpa != vdev->vbars[idx].base_hpa)) { + ret = -EIO; + pr_err("%s, PCI:%02x:%02x.%x PIO BAR%d isn't identical mapping, " + "host start addr is 0x%lx, while guest start addr is 0x%lx", + __func__, vdev->bdf.bits.b, vdev->bdf.bits.d, vdev->bdf.bits.f, idx, + vdev->vbars[idx].base_hpa, vdev->vbars[idx].base_gpa); + break; + } + } + } + + return ret; +} + void pci_vdev_write_vbar(struct pci_vdev *vdev, uint32_t idx, uint32_t val) { struct pci_vbar *vbar; diff --git a/hypervisor/dm/vpci/vpci.c b/hypervisor/dm/vpci/vpci.c index c1f813895..92dc8f8b0 100644 --- a/hypervisor/dm/vpci/vpci.c +++ b/hypervisor/dm/vpci/vpci.c @@ -41,7 +41,7 @@ #include -static void vpci_init_vdevs(struct acrn_vm *vm); +static int32_t vpci_init_vdevs(struct acrn_vm *vm); static int32_t vpci_read_cfg(struct acrn_vpci *vpci, union pci_bdf bdf, uint32_t offset, uint32_t bytes, uint32_t *val); static int32_t vpci_write_cfg(struct acrn_vpci *vpci, union pci_bdf bdf, uint32_t offset, uint32_t bytes, uint32_t val); static struct pci_vdev *find_available_vdev(struct acrn_vpci *vpci, union pci_bdf bdf); @@ -205,7 +205,7 @@ static int32_t vpci_mmio_cfg_access(struct io_request *io_req, void *private_dat * @pre vm != NULL * @pre vm->vm_id < CONFIG_MAX_VM_NUM */ -void init_vpci(struct acrn_vm *vm) +int32_t init_vpci(struct acrn_vm *vm) { struct vm_io_range pci_cfgaddr_range = { .base = PCI_CONFIG_ADDR, @@ -219,6 +219,7 @@ void init_vpci(struct acrn_vm *vm) struct acrn_vm_config *vm_config; struct pci_mmcfg_region *pci_mmcfg; + int32_t ret = 0; vm->iommu = create_iommu_domain(vm->vm_id, hva2hpa(vm->arch_vm.nworld_eptp), 48U); @@ -242,20 +243,24 @@ void init_vpci(struct acrn_vm *vm) } /* Build up vdev list for vm */ - vpci_init_vdevs(vm); + ret = vpci_init_vdevs(vm); - register_mmio_emulation_handler(vm, vpci_mmio_cfg_access, vm->vpci.pci_mmcfg.address, - vm->vpci.pci_mmcfg.address + get_pci_mmcfg_size(&vm->vpci.pci_mmcfg), &vm->vpci, false); + if (ret == 0) { + register_mmio_emulation_handler(vm, vpci_mmio_cfg_access, vm->vpci.pci_mmcfg.address, + vm->vpci.pci_mmcfg.address + get_pci_mmcfg_size(&vm->vpci.pci_mmcfg), &vm->vpci, false); - /* Intercept and handle I/O ports CF8h */ - register_pio_emulation_handler(vm, PCI_CFGADDR_PIO_IDX, &pci_cfgaddr_range, - vpci_pio_cfgaddr_read, vpci_pio_cfgaddr_write); + /* Intercept and handle I/O ports CF8h */ + register_pio_emulation_handler(vm, PCI_CFGADDR_PIO_IDX, &pci_cfgaddr_range, + vpci_pio_cfgaddr_read, vpci_pio_cfgaddr_write); - /* Intercept and handle I/O ports CFCh -- CFFh */ - register_pio_emulation_handler(vm, PCI_CFGDATA_PIO_IDX, &pci_cfgdata_range, - vpci_pio_cfgdata_read, vpci_pio_cfgdata_write); + /* Intercept and handle I/O ports CFCh -- CFFh */ + register_pio_emulation_handler(vm, PCI_CFGDATA_PIO_IDX, &pci_cfgdata_range, + vpci_pio_cfgdata_read, vpci_pio_cfgdata_write); - spinlock_init(&vm->vpci.lock); + spinlock_init(&vm->vpci.lock); + } + + return ret; } /** @@ -666,18 +671,25 @@ struct pci_vdev *vpci_init_vdev(struct acrn_vpci *vpci, struct acrn_vm_pci_dev_c /** * @pre vm != NULL */ -static void vpci_init_vdevs(struct acrn_vm *vm) +static int32_t vpci_init_vdevs(struct acrn_vm *vm) { uint32_t idx; struct acrn_vpci *vpci = &(vm->vpci); const struct acrn_vm_config *vm_config = get_vm_config(vpci2vm(vpci)->vm_id); + int32_t ret = 0; for (idx = 0U; idx < vm_config->pci_dev_num; idx++) { /* the vdev whose vBDF is unassigned will be created by hypercall */ if ((!is_postlaunched_vm(vm)) || (vm_config->pci_devs[idx].vbdf.value != UNASSIGNED_VBDF)) { (void)vpci_init_vdev(vpci, &vm_config->pci_devs[idx], NULL); + ret = check_pt_dev_pio_bars(&vpci->pci_vdevs[idx]); + if (ret != 0) { + break; + } } } + + return ret; } /** @@ -733,14 +745,21 @@ int32_t vpci_assign_pcidev(struct acrn_vm *tgt_vm, struct acrn_pcidev *pcidev) pci_vdev_write_vbar(vdev, idx, pcidev->bar[idx]); } - vdev->flags |= pcidev->type; - vdev->bdf.value = pcidev->virt_bdf; - /*We should re-add the vdev to hashlist since its vbdf has changed */ - hlist_del(&vdev->link); - hlist_add_head(&vdev->link, &vpci->vdevs_hlist_heads[hash64(vdev->bdf.value, VDEV_LIST_HASHBITS)]); - vdev->parent_user = vdev_in_sos; + ret = check_pt_dev_pio_bars(vdev); + + if (ret == 0) { + vdev->flags |= pcidev->type; + vdev->bdf.value = pcidev->virt_bdf; + /*We should re-add the vdev to hashlist since its vbdf has changed */ + hlist_del(&vdev->link); + hlist_add_head(&vdev->link, &vpci->vdevs_hlist_heads[hash64(vdev->bdf.value, VDEV_LIST_HASHBITS)]); + vdev->parent_user = vdev_in_sos; + vdev_in_sos->user = vdev; + } else { + vdev->vdev_ops->deinit_vdev(vdev); + vdev_in_sos->vdev_ops->init_vdev(vdev_in_sos); + } spinlock_release(&tgt_vm->vpci.lock); - vdev_in_sos->user = vdev; } else { pr_fatal("%s, can't find PCI device %x:%x.%x for vm[%d] %x:%x.%x\n", __func__, pcidev->phys_bdf >> 8U, (pcidev->phys_bdf >> 3U) & 0x1fU, pcidev->phys_bdf & 0x7U, diff --git a/hypervisor/dm/vpci/vpci_priv.h b/hypervisor/dm/vpci/vpci_priv.h index f4c426e03..766de009e 100644 --- a/hypervisor/dm/vpci/vpci_priv.h +++ b/hypervisor/dm/vpci/vpci_priv.h @@ -178,6 +178,8 @@ void pci_vdev_write_vbar(struct pci_vdev *vdev, uint32_t idx, uint32_t val); void vdev_pt_hide_sriov_cap(struct pci_vdev *vdev); +int32_t check_pt_dev_pio_bars(struct pci_vdev *vdev); + typedef void (*map_pcibar)(struct pci_vdev *vdev, uint32_t bar_idx); typedef void (*unmap_pcibar)(struct pci_vdev *vdev, uint32_t bar_idx); void vpci_update_one_vbar(struct pci_vdev *vdev, uint32_t bar_idx, uint32_t val, map_pcibar map_cb, unmap_pcibar unmap_cb); diff --git a/hypervisor/include/dm/vpci.h b/hypervisor/include/dm/vpci.h index fd91459de..4797c4025 100644 --- a/hypervisor/include/dm/vpci.h +++ b/hypervisor/include/dm/vpci.h @@ -184,7 +184,7 @@ struct acrn_vm; extern const struct pci_vdev_ops vhostbridge_ops; extern const struct pci_vdev_ops vpci_bridge_ops; -void init_vpci(struct acrn_vm *vm); +int32_t init_vpci(struct acrn_vm *vm); void deinit_vpci(struct acrn_vm *vm); struct pci_vdev *pci_find_vdev(struct acrn_vpci *vpci, union pci_bdf vbdf); struct acrn_pcidev;