diff --git a/hypervisor/arch/x86/cpu.c b/hypervisor/arch/x86/cpu.c index 0397e04b8..621b9a7f0 100644 --- a/hypervisor/arch/x86/cpu.c +++ b/hypervisor/arch/x86/cpu.c @@ -237,6 +237,7 @@ void init_pcpu_post(uint16_t pcpu_id) panic("failed to initialize iommu!"); } + hv_access_memory_region_update(get_mmcfg_base(), PCI_MMCONFIG_SIZE); init_pci_pdev_list(); /* init_iommu must come before this */ ptdev_init(); diff --git a/hypervisor/arch/x86/guest/vm.c b/hypervisor/arch/x86/guest/vm.c index 19d2eac48..ff2bb2a3a 100644 --- a/hypervisor/arch/x86/guest/vm.c +++ b/hypervisor/arch/x86/guest/vm.c @@ -431,6 +431,9 @@ static void prepare_sos_vm_memmap(struct acrn_vm *vm) * code be page-aligned. */ ept_del_mr(vm, pml4_page, get_ap_trampoline_buf(), CONFIG_LOW_RAM_SIZE); + + /* unmap PCIe MMCONFIG region since it's owned by hypervisor */ + ept_del_mr(vm, (uint64_t *)vm->arch_vm.nworld_eptp, get_mmcfg_base(), PCI_MMCONFIG_SIZE); } /* Add EPT mapping of EPC reource for the VM */ diff --git a/hypervisor/dm/vpci/vpci.c b/hypervisor/dm/vpci/vpci.c index badb5951c..fffcdecbe 100644 --- a/hypervisor/dm/vpci/vpci.c +++ b/hypervisor/dm/vpci/vpci.c @@ -29,6 +29,7 @@ #include #include +#include #include #include #include "vpci_priv.h" @@ -172,6 +173,48 @@ static bool pci_cfgdata_io_write(struct acrn_vcpu *vcpu, uint16_t addr, size_t b return true; } +/** + * @pre io_req != NULL && private_data != NULL + */ +static int32_t vpci_handle_mmconfig_access(struct io_request *io_req, void *private_data) +{ + struct mmio_request *mmio = &io_req->reqs.mmio; + struct acrn_vpci *vpci = (struct acrn_vpci *)private_data; + uint64_t pci_mmcofg_base = vpci->pci_mmcfg_base; + uint64_t address = mmio->address; + uint32_t reg_num = (uint32_t)(address & 0xfffUL); + union pci_bdf bdf; + + /** + * Enhanced Configuration Address Mapping + * A[(20+n-1):20] Bus Number 1 ≤ n ≤ 8 + * A[19:15] Device Number + * A[14:12] Function Number + * A[11:8] Extended Register Number + * A[7:2] Register Number + * A[1:0] Along with size of the access, used to generate Byte Enables + */ + bdf.value = (uint16_t)((address - pci_mmcofg_base) >> 12U); + + if (mmio->direction == REQUEST_READ) { + if (!is_plat_hidden_pdev(bdf)) { + read_cfg(vpci, bdf, reg_num, (uint32_t)mmio->size, (uint32_t *)&mmio->value); + } else { + /* expose and pass through platform hidden devices to SOS */ + mmio->value = (uint64_t)pci_pdev_read_cfg(bdf, reg_num, (uint32_t)mmio->size); + } + } else { + if (!is_plat_hidden_pdev(bdf)) { + write_cfg(vpci, bdf, reg_num, (uint32_t)mmio->size, (uint32_t)mmio->value); + } else { + /* expose and pass through platform hidden devices to SOS */ + pci_pdev_write_cfg(bdf, reg_num, (uint32_t)mmio->size, (uint32_t)mmio->value); + } + } + + return 0; +} + /** * @pre vm != NULL * @pre vm->vm_id < CONFIG_MAX_VM_NUM @@ -189,6 +232,7 @@ void vpci_init(struct acrn_vm *vm) }; struct acrn_vm_config *vm_config; + uint64_t pci_mmcfg_base; vm->vpci.vm = vm; vm->iommu = create_iommu_domain(vm->vm_id, hva2hpa(vm->arch_vm.nworld_eptp), 48U); @@ -197,8 +241,13 @@ void vpci_init(struct acrn_vm *vm) vm_config = get_vm_config(vm->vm_id); switch (vm_config->load_order) { - case PRE_LAUNCHED_VM: case SOS_VM: + pci_mmcfg_base = get_mmcfg_base(); + vm->vpci.pci_mmcfg_base = pci_mmcfg_base; + register_mmio_emulation_handler(vm, vpci_handle_mmconfig_access, + pci_mmcfg_base, pci_mmcfg_base + PCI_MMCONFIG_SIZE, &vm->vpci); + /* falls through */ + case PRE_LAUNCHED_VM: /* * SOS: intercept port CF8 only. * UOS or pre-launched VM: register handler for CF8 only and I/O requests to CF9/CFA/CFB are @@ -404,6 +453,9 @@ static void write_cfg(struct acrn_vpci *vpci, union pci_bdf bdf, vdev = find_vdev(vpci, bdf); if (vdev != NULL) { vdev->vdev_ops->write_vdev_cfg(vdev, offset, bytes, val); + } else { + pr_acrnlog("%s %x:%x.%x not found! off: 0x%x, val: 0x%x\n", __func__, + bdf.bits.b, bdf.bits.d, bdf.bits.f, offset, val); } spinlock_release(&vpci->lock); } diff --git a/hypervisor/hw/pci.c b/hypervisor/hw/pci.c index c3020a274..3238814ae 100644 --- a/hypervisor/hw/pci.c +++ b/hypervisor/hw/pci.c @@ -78,7 +78,6 @@ static uint32_t pci_mmcfg_read_cfg(union pci_bdf bdf, uint32_t offset, uint32_t uint32_t val; spinlock_obtain(&pci_device_lock); - stac(); switch (bytes) { case 1U: val = (uint32_t)mmio_read8(hva); @@ -90,7 +89,6 @@ static uint32_t pci_mmcfg_read_cfg(union pci_bdf bdf, uint32_t offset, uint32_t val = mmio_read32(hva); break; } - clac(); spinlock_release(&pci_device_lock); return val; @@ -105,7 +103,6 @@ static void pci_mmcfg_write_cfg(union pci_bdf bdf, uint32_t offset, uint32_t byt void *hva = hpa2hva(addr); spinlock_obtain(&pci_device_lock); - stac(); switch (bytes) { case 1U: mmio_write8((uint8_t)val, hva); @@ -117,7 +114,6 @@ static void pci_mmcfg_write_cfg(union pci_bdf bdf, uint32_t offset, uint32_t byt mmio_write32(val, hva); break; } - clac(); spinlock_release(&pci_device_lock); } @@ -225,6 +221,22 @@ void enable_disable_pci_intx(union pci_bdf bdf, bool enable) } } +bool is_plat_hidden_pdev(union pci_bdf bdf) +{ + static uint32_t hidden_pdevs_num = MAX_HIDDEN_PDEVS_NUM; + uint32_t hidden_idx; + bool hidden = false; + + for (hidden_idx = 0U; hidden_idx < hidden_pdevs_num; hidden_idx++) { + if (bdf_is_equal(plat_hidden_pdevs[hidden_idx], bdf)) { + hidden = true; + break; + } + } + + return hidden; +} + static bool is_hv_owned_pdev(union pci_bdf pbdf) { bool hidden = false; diff --git a/hypervisor/include/dm/vpci.h b/hypervisor/include/dm/vpci.h index c86877a84..02f4f351b 100644 --- a/hypervisor/include/dm/vpci.h +++ b/hypervisor/include/dm/vpci.h @@ -70,9 +70,9 @@ struct pci_msix { }; union pci_cfgdata { - uint8_t data_8[PCI_REGMAX + 1U]; - uint16_t data_16[(PCI_REGMAX + 1U) >> 1U]; - uint32_t data_32[(PCI_REGMAX + 1U) >> 2U]; + uint8_t data_8[PCIE_CONFIG_SPACE_SIZE]; + uint16_t data_16[PCIE_CONFIG_SPACE_SIZE >> 1U]; + uint32_t data_32[PCIE_CONFIG_SPACE_SIZE >> 2U]; }; struct pci_vdev; @@ -123,6 +123,7 @@ struct acrn_vpci { spinlock_t lock; struct acrn_vm *vm; union pci_cfg_addr_reg addr; + uint64_t pci_mmcfg_base; uint32_t pci_vdev_cnt; struct pci_vdev pci_vdevs[CONFIG_MAX_PCI_DEV_NUM]; }; diff --git a/hypervisor/include/hw/pci.h b/hypervisor/include/hw/pci.h index d8fee0aed..3230fbfe2 100644 --- a/hypervisor/include/hw/pci.h +++ b/hypervisor/include/hw/pci.h @@ -48,9 +48,12 @@ #define PCI_SLOTMAX 0x1FU #define PCI_FUNCMAX 0x7U #define PCI_BAR_COUNT 0x6U -#define PCI_REGMAX 0xFFU #define PCI_REGMASK 0xFCU +#define PCI_CONFIG_SPACE_SIZE 0x100U +#define PCIE_CONFIG_SPACE_SIZE 0x1000U +#define PCI_MMCONFIG_SIZE 0x10000000U + /* I/O ports */ #define PCI_CONFIG_ADDR 0xCF8U #define PCI_CONFIG_DATA 0xCFCU @@ -323,6 +326,7 @@ static inline bool is_pci_cfg_bridge(uint8_t header_type) return ((header_type & PCIM_HDRTYPE) == PCIM_HDRTYPE_BRIDGE); } +bool is_plat_hidden_pdev(union pci_bdf bdf); bool pdev_need_bar_restore(const struct pci_pdev *pdev); void pdev_restore_bar(const struct pci_pdev *pdev); void pci_switch_to_mmio_cfg_ops(void);