diff --git a/hypervisor/dm/vpci/pci_pt.c b/hypervisor/dm/vpci/pci_pt.c index cb212fd8a..6b2c3c048 100644 --- a/hypervisor/dm/vpci/pci_pt.c +++ b/hypervisor/dm/vpci/pci_pt.c @@ -261,3 +261,74 @@ int32_t vdev_pt_cfgwrite(struct pci_vdev *vdev, uint32_t offset, return ret; } + +/** + * For bar emulation, currently only MMIO is supported and bar size cannot be greater than 4GB + * @pre bar != NULL + */ +static inline bool is_bar_supported(const struct pci_bar *bar) +{ + return (is_mmio_bar(bar) && is_valid_bar_size(bar)); +} + +/** + * PCI base address register (bar) virtualization: + * + * Virtualize the PCI bars (up to 6 bars at byte offset 0x10~0x24 for type 0 PCI device, + * 2 bars at byte offset 0x10-0x14 for type 1 PCI device) of the PCI configuration space + * header. + * + * pbar: bar for the physical PCI device (pci_pdev), the value of pbar (hpa) is assigned + * by platform firmware during boot. It is assumed a valid hpa is always assigned to a + * mmio pbar, hypervisor shall not change the value of a pbar. + * + * vbar: for each pci_pdev, it has a virtual PCI device (pci_vdev) counterpart. pci_vdev + * virtualizes all the bars (called vbars). a vbar can be initialized by hypervisor by + * assigning a gpa to it; if vbar has a value of 0 (unassigned), guest may assign + * and program a gpa to it. The guest only sees the vbars, it will not see and can + * never change the pbars. + * + * Hypervisor traps guest changes to the mmio vbar (gpa) to establish ept mapping + * between vbar(gpa) and pbar(hpa). pbar should always align on 4K boundary. + * + * @pre vdev != NULL + * @pre vdev->vpci != NULL + * @pre vdev->vpci->vm != NULL + * @pre vdev->pdev != NULL + */ +void init_vdev_pt(struct pci_vdev *vdev) +{ + uint32_t idx; + struct pci_bar *pbar, *vbar; + uint16_t pci_command; + + if (is_prelaunched_vm(vdev->vpci->vm)) { + for (idx = 0U; idx < (uint32_t)PCI_BAR_COUNT; idx++) { + pbar = &vdev->pdev->bar[idx]; + vbar = &vdev->bar[idx]; + + if (is_bar_supported(pbar)) { + /** + * If vbar->base is 0 (unassigned), Linux kernel will reprogram the vbar on + * its bar size boundary, so in order to ensure the vbar allocated by guest + * is 4k aligned, set its size to be 4K aligned. + */ + vbar->size = round_page_up(pbar->size); + + /** + * Only 32-bit bar is supported for now so both PCIBAR_MEM32 and PCIBAR_MEM64 + * are reported to guest as PCIBAR_MEM32 + */ + vbar->type = PCIBAR_MEM32; + } else { + vbar->size = 0UL; + vbar->type = PCIBAR_NONE; + } + } + + pci_command = (uint16_t)pci_pdev_read_cfg(vdev->pdev->bdf, PCIR_COMMAND, 2U); + /* Disable INTX */ + pci_command |= 0x400U; + pci_pdev_write_cfg(vdev->pdev->bdf, PCIR_COMMAND, 2U, pci_command); + } +} diff --git a/hypervisor/dm/vpci/vpci.c b/hypervisor/dm/vpci/vpci.c index 13b53fe48..8df4f17a2 100644 --- a/hypervisor/dm/vpci/vpci.c +++ b/hypervisor/dm/vpci/vpci.c @@ -268,31 +268,6 @@ static inline bool is_hostbridge(const struct pci_vdev *vdev) return (vdev->vbdf.value == 0U); } -/** - * @pre bar != NULL - */ -static inline bool is_valid_bar_type(const struct pci_bar *bar) -{ - return (bar->type == PCIBAR_MEM32) || (bar->type == PCIBAR_MEM64); -} - -/** - * @pre bar != NULL - */ -static inline bool is_valid_bar_size(const struct pci_bar *bar) -{ - return (bar->size > 0UL) && (bar->size <= 0xffffffffU); -} - -/** - * Only MMIO is supported and bar size cannot be greater than 4GB - * @pre bar != NULL - */ -static inline bool is_valid_bar(const struct pci_bar *bar) -{ - return (is_valid_bar_type(bar) && is_valid_bar_size(bar)); -} - /** * @pre vdev != NULL * @pre vdev->vpci != NULL @@ -341,35 +316,12 @@ static void remove_vdev_pt_iommu_domain(const struct pci_vdev *vdev) static void partition_mode_pdev_init(struct pci_vdev *vdev, union pci_bdf pbdf) { struct pci_pdev *pdev; - uint32_t idx; - struct pci_bar *pbar, *vbar; - uint16_t pci_command; pdev = find_pci_pdev(pbdf); ASSERT(pdev != NULL, "pdev is NULL"); vdev->pdev = pdev; - /* Sanity checking for vbar */ - for (idx = 0U; idx < (uint32_t)PCI_BAR_COUNT; idx++) { - pbar = &vdev->pdev->bar[idx]; - vbar = &vdev->bar[idx]; - - if (is_valid_bar(pbar)) { - vbar->size = (pbar->size < 0x1000U) ? 0x1000U : pbar->size; - vbar->type = PCIBAR_MEM32; - } else { - /* Mark this vbar as invalid */ - vbar->size = 0UL; - vbar->type = PCIBAR_NONE; - } - } - - pci_command = (uint16_t)pci_pdev_read_cfg(vdev->pdev->bdf, PCIR_COMMAND, 2U); - /* Disable INTX */ - pci_command |= 0x400U; - pci_pdev_write_cfg(vdev->pdev->bdf, PCIR_COMMAND, 2U, pci_command); - assign_vdev_pt_iommu_domain(vdev); } @@ -402,6 +354,8 @@ int32_t partition_mode_vpci_init(struct acrn_vm *vm) } else { partition_mode_pdev_init(vdev, ptdev_config->pbdf); + init_vdev_pt(vdev); + vmsi_init(vdev); vmsix_init(vdev); @@ -560,7 +514,6 @@ static void init_vdev_for_pdev(struct pci_pdev *pdev, const void *vm) } } - /** * @pre vm != NULL * @pre is_sos_vm(vm) == true diff --git a/hypervisor/dm/vpci/vpci_priv.h b/hypervisor/dm/vpci/vpci_priv.h index 281954898..5638202c9 100644 --- a/hypervisor/dm/vpci/vpci_priv.h +++ b/hypervisor/dm/vpci/vpci_priv.h @@ -80,6 +80,7 @@ int32_t vhostbridge_cfgread(const struct pci_vdev *vdev, uint32_t offset, uint32 int32_t vhostbridge_cfgwrite(struct pci_vdev *vdev, uint32_t offset, uint32_t bytes, uint32_t val); void vhostbridge_deinit(__unused const struct pci_vdev *vdev); +void init_vdev_pt(struct pci_vdev *vdev); int32_t vdev_pt_cfgread(const struct pci_vdev *vdev, uint32_t offset, uint32_t bytes, uint32_t *val); int32_t vdev_pt_cfgwrite(struct pci_vdev *vdev, uint32_t offset, uint32_t bytes, uint32_t val); diff --git a/hypervisor/include/hw/pci.h b/hypervisor/include/hw/pci.h index 8495e8506..4468293ea 100644 --- a/hypervisor/include/hw/pci.h +++ b/hypervisor/include/hw/pci.h @@ -220,14 +220,31 @@ static inline uint8_t pci_devfn(uint16_t bdf) return (uint8_t)(bdf & 0xFFU); } -/* - * @pre a != NULL && b != NULL +/** + * @pre a != NULL + * @pre b != NULL */ static inline bool bdf_is_equal(const union pci_bdf *a, const union pci_bdf *b) { return (a->value == b->value); } +/** + * @pre bar != NULL + */ +static inline bool is_mmio_bar(const struct pci_bar *bar) +{ + return (bar->type == PCIBAR_MEM32) || (bar->type == PCIBAR_MEM64); +} + +/** + * @pre bar != NULL + */ +static inline bool is_valid_bar_size(const struct pci_bar *bar) +{ + return (bar->size > 0UL) && (bar->size <= 0xffffffffU); +} + uint32_t pci_pdev_read_cfg(union pci_bdf bdf, uint32_t offset, uint32_t bytes); void pci_pdev_write_cfg(union pci_bdf bdf, uint32_t offset, uint32_t bytes, uint32_t val); void enable_disable_pci_intx(union pci_bdf bdf, bool enable);