diff --git a/hypervisor/dm/vpci/ivshmem.c b/hypervisor/dm/vpci/ivshmem.c index a3f999eed..304908a58 100644 --- a/hypervisor/dm/vpci/ivshmem.c +++ b/hypervisor/dm/vpci/ivshmem.c @@ -295,8 +295,11 @@ static void init_ivshmem_bar(struct pci_vdev *vdev, uint32_t bar_idx) struct acrn_vm_pci_dev_config *dev_config = vdev->pci_dev_config; addr = dev_config->vbar_base[bar_idx]; - mask = (is_pci_io_bar((uint32_t)addr)) ? PCI_BASE_ADDRESS_IO_MASK : PCI_BASE_ADDRESS_MEM_MASK; vbar = &vdev->vbars[bar_idx]; + vbar->bar_type.bits = addr; + mask = is_pci_io_bar(vbar) ? PCI_BASE_ADDRESS_IO_MASK : PCI_BASE_ADDRESS_MEM_MASK; + vbar->bar_type.bits &= (~mask); + if (bar_idx == IVSHMEM_SHM_BAR) { struct ivshmem_shm_region *region = find_shm_region(dev_config->shm_region_name); if (region != NULL) { @@ -314,9 +317,8 @@ static void init_ivshmem_bar(struct pci_vdev *vdev, uint32_t bar_idx) if (size != 0UL) { vbar->size = size; vbar->mask = (uint32_t) (~(size - 1UL)); - vbar->bar_type.bits = (uint32_t) (addr & (~mask)); - pci_vdev_write_vbar(vdev, bar_idx, (uint32_t) addr); - if (is_pci_mem64_bar((uint32_t)addr)) { + pci_vdev_write_vbar(vdev, bar_idx, (uint32_t)addr); + if (is_pci_mem64lo_bar(vbar)) { vbar = &vdev->vbars[bar_idx + 1U]; vbar->is_mem64hi = true; vbar->mask = (uint32_t) ((~(size - 1UL)) >> 32U); diff --git a/hypervisor/dm/vpci/pci_pt.c b/hypervisor/dm/vpci/pci_pt.c index b113bbdf1..18a36578b 100644 --- a/hypervisor/dm/vpci/pci_pt.c +++ b/hypervisor/dm/vpci/pci_pt.c @@ -292,11 +292,9 @@ void vdev_pt_write_vbar(struct pci_vdev *vdev, uint32_t idx, uint32_t val) { struct pci_vbar *vbar = &vdev->vbars[idx]; - if (is_pci_io_bar(vbar->bar_type.bits)) { + if (is_pci_io_bar(vbar)) { vpci_update_one_vbar(vdev, idx, val, vdev_pt_allow_io_vbar, vdev_pt_deny_io_vbar); - } - - if (is_pci_mem32_bar(vbar->bar_type.bits) || is_pci_mem64_bar(vbar->bar_type.bits) || vbar->is_mem64hi) { + } else if (is_pci_mem_bar(vbar)) { vpci_update_one_vbar(vdev, idx, val, vdev_pt_map_mem_vbar, vdev_pt_unmap_mem_vbar); } } @@ -360,14 +358,15 @@ static void init_bars(struct pci_vdev *vdev, bool is_sriov_bar) offset = pci_bar_offset(idx); } lo = pci_pdev_read_cfg(pbdf, offset, 4U); + vbar->bar_type.bits = lo; - if (!(is_pci_io_bar(lo) || is_pci_mem32_bar(lo) || is_pci_mem64_bar(lo))) { + if (is_pci_reserved_bar(vbar)) { continue; } - mask = (is_pci_io_bar(lo)) ? PCI_BASE_ADDRESS_IO_MASK : PCI_BASE_ADDRESS_MEM_MASK; + mask = (is_pci_io_bar(vbar)) ? PCI_BASE_ADDRESS_IO_MASK : PCI_BASE_ADDRESS_MEM_MASK; vbar->base_hpa = (uint64_t)lo & mask; - if (is_pci_mem64_bar(lo)) { + if (is_pci_mem64lo_bar(vbar)) { hi = pci_pdev_read_cfg(pbdf, offset + 4U, 4U); vbar->base_hpa |= ((uint64_t)hi << 32U); } @@ -378,14 +377,14 @@ static void init_bars(struct pci_vdev *vdev, bool is_sriov_bar) pci_pdev_write_cfg(pbdf, offset, 4U, lo); vbar->mask = size32 & mask; - vbar->bar_type.bits = lo & (~mask); + vbar->bar_type.bits &= (~mask); vbar->size = (uint64_t)size32 & mask; if (is_prelaunched_vm(vpci2vm(vdev->vpci))) { lo = (uint32_t)vdev->pci_dev_config->vbar_base[idx]; } - if (is_pci_mem64_bar(lo)) { + if (is_pci_mem64lo_bar(vbar)) { idx++; if (is_sriov_bar) { offset = sriov_bar_offset(vdev, idx); @@ -419,7 +418,7 @@ static void init_bars(struct pci_vdev *vdev, bool is_sriov_bar) } } else { vbar->size = vbar->size & ~(vbar->size - 1UL); - if (is_pci_mem32_bar(lo)) { + if (is_pci_mem32_bar(vbar)) { vbar->size = round_page_up(vbar->size); } diff --git a/hypervisor/dm/vpci/vdev.c b/hypervisor/dm/vpci/vdev.c index c7ac38828..99927e381 100644 --- a/hypervisor/dm/vpci/vdev.c +++ b/hypervisor/dm/vpci/vdev.c @@ -115,10 +115,10 @@ static void pci_vdev_update_vbar_base(struct pci_vdev *vdev, uint32_t idx) vbar = &vdev->vbars[idx]; offset = pci_bar_offset(idx); lo = pci_vdev_read_vcfg(vdev, offset, 4U); - if (((is_pci_io_bar(vbar->bar_type.bits) || is_pci_mem32_bar(vbar->bar_type.bits) || is_pci_mem64_bar(vbar->bar_type.bits) || vbar->is_mem64hi)) && (lo != ~0U)) { + if ((!is_pci_reserved_bar(vbar)) && (lo != ~0U)) { base = lo & vbar->mask; - if (is_pci_mem64_bar(vbar->bar_type.bits)) { + if (is_pci_mem64lo_bar(vbar)) { vbar = &vdev->vbars[idx + 1U]; hi = pci_vdev_read_vcfg(vdev, (offset + 4U), 4U); if (hi != ~0U) { @@ -128,12 +128,14 @@ static void pci_vdev_update_vbar_base(struct pci_vdev *vdev, uint32_t idx) base = 0UL; } } - if (is_pci_io_bar(vbar->bar_type.bits)) { - base &= 0xffffUL; - } + } else if (is_pci_io_bar(vbar)) { + /* Because guest driver may write to upper 16-bits of PIO BAR and expect that should have no effect, + * SO PIO BAR base may bigger than 0xffff after calculation, should mask the upper 16-bits. + */ + base &= 0xffffUL; } - if ((base != 0UL) && !ept_is_mr_valid(vpci2vm(vdev->vpci), base, vdev->vbars[idx].size)) { + if (is_pci_mem_bar(vbar) && (base != 0UL) && !ept_is_mr_valid(vpci2vm(vdev->vpci), base, vdev->vbars[idx].size)) { pr_warn("%s, %x:%x.%x set invalid bar[%d] base: 0x%lx, size: 0x%lx\n", __func__, vdev->bdf.bits.b, vdev->bdf.bits.d, vdev->bdf.bits.f, idx, base, vdev->vbars[idx].size); base = 0UL; /* 0UL means invalid GPA, so that EPT won't map */ @@ -150,13 +152,17 @@ void pci_vdev_write_vbar(struct pci_vdev *vdev, uint32_t idx, uint32_t val) vbar = &vdev->vbars[idx]; bar = val & vbar->mask; - bar |= vbar->bar_type.bits; + if (vbar->is_mem64hi) { + update_idx -= 1U; + } else { + if (is_pci_io_bar(vbar)) { + bar |= (vbar->bar_type.bits & (~PCI_BASE_ADDRESS_IO_MASK)); + } else { + bar |= (vbar->bar_type.bits & (~PCI_BASE_ADDRESS_MEM_MASK)); + } + } offset = pci_bar_offset(idx); pci_vdev_write_vcfg(vdev, offset, 4U, bar); - if (vbar->is_mem64hi) { - update_idx -= 1U; - } - pci_vdev_update_vbar_base(vdev, update_idx); } diff --git a/hypervisor/dm/vpci/vmsix_on_msi.c b/hypervisor/dm/vpci/vmsix_on_msi.c index 09fbe8217..fcd50e348 100644 --- a/hypervisor/dm/vpci/vmsix_on_msi.c +++ b/hypervisor/dm/vpci/vmsix_on_msi.c @@ -83,7 +83,7 @@ void init_vmsix_on_msi(struct pci_vdev *vdev) if (vdev->vbars[i].base_hpa == 0UL){ break; } - if (is_pci_mem64_bar(vdev->vbars[i].bar_type.bits)) { + if (is_pci_mem64lo_bar(&vdev->vbars[i])) { i++; } } diff --git a/hypervisor/include/dm/vpci.h b/hypervisor/include/dm/vpci.h index 541d11afe..813881a2d 100644 --- a/hypervisor/include/dm/vpci.h +++ b/hypervisor/include/dm/vpci.h @@ -38,11 +38,11 @@ #define VDEV_LIST_HASHSIZE (1U << VDEV_LIST_HASHBITS) struct pci_vbar { - bool is_mem64hi;; + bool is_mem64hi; /* this is to indicate the high part of 64 bits MMIO bar */ uint64_t size; /* BAR size */ uint64_t base_gpa; /* BAR guest physical address */ uint64_t base_hpa; /* BAR host physical address */ - union pci_bar_type bar_type; + union pci_bar_type bar_type; /* the low 2(PIO)/4(MMIO) bits of BAR */ uint32_t mask; /* BAR size mask */ }; @@ -184,4 +184,30 @@ int32_t vpci_assign_pcidev(struct acrn_vm *tgt_vm, struct acrn_assign_pcidev *pc int32_t vpci_deassign_pcidev(struct acrn_vm *tgt_vm, struct acrn_assign_pcidev *pcidev); struct pci_vdev *vpci_init_vdev(struct acrn_vpci *vpci, struct acrn_vm_pci_dev_config *dev_config, struct pci_vdev *parent_pf_vdev); +static inline bool is_pci_io_bar(struct pci_vbar *vbar) +{ + return ((vbar->bar_type.io_space.indicator == 1U) && (!vbar->is_mem64hi)); +} + +static inline bool is_pci_mem_bar(struct pci_vbar *vbar) +{ + return ((vbar->is_mem64hi) || ((vbar->bar_type.mem_space.indicator == 0U))); +} + +/* Reserved PCI BAR type: 1.Memory bar with reserved memory type; 2.IO bar reserved bit is set */ +static inline bool is_pci_reserved_bar(struct pci_vbar *vbar) +{ + return (((vbar->bar_type.mem_space.indicator == 0U) && ((vbar->bar_type.mem_space.mem_type & 0x1U) == 0x1U) && (!vbar->is_mem64hi)) || + ((vbar->bar_type.io_space.indicator == 1U) && (vbar->bar_type.io_space.reserved == 1U))); +} + +static inline bool is_pci_mem32_bar(struct pci_vbar *vbar) +{ + return ((vbar->bar_type.mem_space.indicator == 0U) && (vbar->bar_type.mem_space.mem_type == 0U) && (!vbar->is_mem64hi)); +} + +static inline bool is_pci_mem64lo_bar(struct pci_vbar *vbar) +{ + return ((vbar->bar_type.mem_space.indicator == 0U) && (vbar->bar_type.mem_space.mem_type == 2U) && (!vbar->is_mem64hi)); +} #endif /* VPCI_H_ */ diff --git a/hypervisor/include/hw/pci.h b/hypervisor/include/hw/pci.h index 4ec7242fc..fc3c8f4a5 100644 --- a/hypervisor/include/hw/pci.h +++ b/hypervisor/include/hw/pci.h @@ -203,16 +203,22 @@ union pci_bdf { } fields; }; +/* + * The next data structure is to reflect the format of PCI BAR base on the PCI sepc. + */ + union pci_bar_type { uint32_t bits; struct { - uint8_t indicator :1; /* BITs[0], mapped to I/O space if read as 1 */ - uint8_t reserved :1; /* BITs[1], reserved */ + uint32_t indicator :1; /* BITs[0], mapped to I/O space if read as 1 */ + uint32_t reserved :1; /* BITs[1], reserved and must be "0" per spec. */ + uint32_t reserved2 : 30; } io_space; struct { - uint8_t indicator :1; /* BITs[0], mapped to memory space if read as 0 */ - uint8_t mem_type :2; /* BITs[1:2], 32-bit address if read as 00b, 64-bit address as 01b */ - uint8_t prefetchable :1; /* BITs[3], set to 1b if the data is prefetchable and set to 0b otherwise */ + uint32_t indicator :1; /* BITs[0], mapped to memory space if read as 0 */ + uint32_t mem_type :2; /* BITs[1:2], 32-bit address if read as 00b, 64-bit address as 01b */ + uint32_t prefetchable :1; /* BITs[3], set to 1b if the data is prefetchable and set to 0b otherwise */ + uint32_t reserved2 : 28; } mem_space; }; @@ -309,34 +315,6 @@ static inline bool is_bar_offset(uint32_t nr_bars, uint32_t offset) return ret; } -static inline bool is_pci_io_bar(uint32_t val) -{ - union pci_bar_type bar_type = {.bits = val}; - - return (bar_type.io_space.indicator == 1U); -} - -static inline bool is_pci_mem_bar(uint32_t val) -{ - union pci_bar_type bar_type = {.bits = val}; - - return ((bar_type.mem_space.indicator == 0U)); -} - -static inline bool is_pci_mem32_bar(uint32_t val) -{ - union pci_bar_type bar_type = {.bits = val}; - - return (is_pci_mem_bar(val) && (bar_type.mem_space.mem_type == 0U)); -} - -static inline bool is_pci_mem64_bar(uint32_t val) -{ - union pci_bar_type bar_type = {.bits = val}; - - return (is_pci_mem_bar(val) && (bar_type.mem_space.mem_type == 2U)); -} - static inline bool bdf_is_equal(union pci_bdf a, union pci_bdf b) { return (a.value == b.value);