diff --git a/hypervisor/dm/vpci/pci_pt.c b/hypervisor/dm/vpci/pci_pt.c index f7f3b1269..c61bf5860 100644 --- a/hypervisor/dm/vpci/pci_pt.c +++ b/hypervisor/dm/vpci/pci_pt.c @@ -434,69 +434,72 @@ void vdev_pt_write_cfg(struct pci_vdev *vdev, uint32_t offset, uint32_t bytes, u */ void init_vdev_pt(struct pci_vdev *vdev) { + enum pci_bar_type type; uint32_t idx; - struct pci_bar *pbar, *vbar; + struct pci_bar *vbar; uint16_t pci_command; - uint64_t vbar_base; + uint32_t size32, offset, lo, hi = 0U; + union pci_bdf pbdf; + uint64_t mask; vdev->nr_bars = vdev->pdev->nr_bars; - - ASSERT(vdev->nr_bars > 0U, "vdev->nr_bars should be greater than 0!"); + pbdf.value = vdev->pdev->bdf.value; for (idx = 0U; idx < vdev->nr_bars; idx++) { - pbar = &vdev->pdev->bar[idx]; vbar = &vdev->bar[idx]; + offset = pci_bar_offset(idx); + lo = pci_pdev_read_cfg(pbdf, offset, 4U); - vbar->size = 0UL; - vbar->reg.value = pbar->reg.value; - vbar->is_64bit_high = pbar->is_64bit_high; - vbar->base_hpa = pbar->base_hpa; + type = pci_get_bar_type(lo); + if (type == PCIBAR_NONE) { + continue; + } + mask = (type == PCIBAR_IO_SPACE) ? PCI_BASE_ADDRESS_IO_MASK : PCI_BASE_ADDRESS_MEM_MASK; + vbar->base_hpa = (uint64_t)lo & mask; - if (pbar->is_64bit_high) { - ASSERT(idx > 0U, "idx for upper 32-bit of the 64-bit bar should be greater than 0!"); + if (type == PCIBAR_MEM64) { + hi = pci_pdev_read_cfg(pbdf, offset + 4U, 4U); + vbar->base_hpa |= ((uint64_t)hi << 32U); + } - if (is_sos_vm(vdev->vpci->vm)) { - /* For SOS: vbar base (GPA) = pbar base (HPA) */ - vbar_base = vdev->bar[idx - 1U].base_hpa; - } else if (idx > 0U) { - /* For pre-launched VMs: vbar base is predefined in vm_config */ - vbar_base = vdev->pci_dev_config->vbar_base[idx - 1U]; - } else { - vbar_base = 0UL; + if (vbar->base_hpa != 0UL) { + pci_pdev_write_cfg(pbdf, offset, 4U, ~0U); + size32 = pci_pdev_read_cfg(pbdf, offset, 4U); + pci_pdev_write_cfg(pbdf, offset, 4U, lo); + + vbar->size = (uint64_t)size32 & mask; + vbar->reg.value = lo; + + if (is_prelaunched_vm(vdev->vpci->vm)) { + lo = (uint32_t)vdev->pci_dev_config->vbar_base[idx]; } - /* Write the upper 32-bit of a 64-bit bar */ - vdev_pt_write_vbar(vdev, pci_bar_offset(idx), (uint32_t)(vbar_base >> 32U)); - } else { - enum pci_bar_type type = pci_get_bar_type(pbar->reg.value); - switch (type) { - case PCIBAR_MEM32: - case PCIBAR_MEM64: - /** - * If vbar->base is 0 (unassigned), Linux kernel will reprogram the vbar on - * its bar size boundary, so in order to ensure the MMIO vbar allocated by guest - * is 4k aligned, set its size to be 4K aligned. - */ - vbar->size = round_page_up(pbar->size); + if (type == PCIBAR_MEM64) { + idx++; + offset = pci_bar_offset(idx); + pci_pdev_write_cfg(pbdf, offset, 4U, ~0U); + size32 = pci_pdev_read_cfg(pbdf, offset, 4U); + pci_pdev_write_cfg(pbdf, offset, 4U, hi); - if (is_sos_vm(vdev->vpci->vm)) { - /* For SOS: vbar base (GPA) = pbar base (HPA) */ - vbar_base = vbar->base_hpa; - } else { - /* For pre-launched VMs: vbar base is predefined in vm_config */ - vbar_base = vdev->pci_dev_config->vbar_base[idx]; + vbar->size |= ((uint64_t)size32 << 32U); + vbar->size = vbar->size & ~(vbar->size - 1UL); + vbar->size = round_page_up(vbar->size); + + vbar = &vdev->bar[idx]; + vbar->is_64bit_high = true; + vbar->reg.value = hi; + + if (is_prelaunched_vm(vdev->vpci->vm)) { + hi = (uint32_t)(vdev->pci_dev_config->vbar_base[idx - 1U] >> 32U); } - vdev_pt_write_vbar(vdev, pci_bar_offset(idx), (uint32_t)vbar_base); - break; - - case PCIBAR_IO_SPACE: - vbar->size = pbar->size; - vdev_pt_write_vbar(vdev, pci_bar_offset(idx), (uint32_t)vbar->base_hpa); - break; - - default: - /* Nothing to do in this case */ - break; + vdev_pt_write_vbar(vdev, pci_bar_offset(idx - 1U), lo); + vdev_pt_write_vbar(vdev, pci_bar_offset(idx), hi); + } else { + vbar->size = vbar->size & ~(vbar->size - 1UL); + if (type == PCIBAR_MEM32) { + vbar->size = round_page_up(vbar->size); + } + vdev_pt_write_vbar(vdev, pci_bar_offset(idx), lo); } } } diff --git a/hypervisor/hw/pci.c b/hypervisor/hw/pci.c index ebc248a5b..444ca6795 100644 --- a/hypervisor/hw/pci.c +++ b/hypervisor/hw/pci.c @@ -213,106 +213,6 @@ static uint32_t pci_pdev_get_nr_bars(uint8_t hdr_type) return nr_bars; } -/* Get the base address of the raw bar value (val) */ -static inline uint32_t pci_pdev_get_bar_base(uint32_t bar_val) -{ - uint32_t base; - union pci_bar_reg reg; - - /* set raw bar value */ - reg.value = bar_val; - - /* Extract base address portion from the raw bar value */ - if (reg.bits.io.is_io != 0U) { - /* IO bar, BITS 31-2 = base address, 4-byte aligned */ - base = (uint32_t)(reg.bits.io.base); - base <<= 2U; - } else { - /* MMIO bar, BITS 31-4 = base address, 16-byte aligned */ - base = (uint32_t)(reg.bits.mem.base); - base <<= 4U; - } - - return base; -} - -/* - * @pre bar != NULL - */ -static uint32_t pci_pdev_read_bar(union pci_bdf bdf, uint32_t idx, struct pci_bar *bar) -{ - uint64_t base, size; - enum pci_bar_type type; - uint32_t bar_lo, bar_hi, size_lo; - - bar->reg.value = pci_pdev_read_cfg(bdf, pci_bar_offset(idx), 4U); - - base = 0UL; - size = 0UL; - type = pci_get_bar_type(bar->reg.value); - bar_hi = 0U; - - if (type != PCIBAR_NONE) { - bar_lo = pci_pdev_read_cfg(bdf, pci_bar_offset(idx), 4U); - - base = (uint64_t)pci_pdev_get_bar_base(bar_lo); - - if (type == PCIBAR_MEM64) { - bar_hi = pci_pdev_read_cfg(bdf, pci_bar_offset(idx + 1U), 4U); - base |= ((uint64_t)bar_hi << 32U); - } - - if (base != 0UL) { - /* Sizing the BAR */ - if ((type == PCIBAR_MEM64) && (idx < (PCI_BAR_COUNT - 1U))) { - pci_pdev_write_cfg(bdf, pci_bar_offset(idx + 1U), 4U, ~0U); - size = (uint64_t)pci_pdev_read_cfg(bdf, pci_bar_offset(idx + 1U), 4U); - size <<= 32U; - } - - pci_pdev_write_cfg(bdf, pci_bar_offset(idx), 4U, ~0U); - size_lo = pci_pdev_read_cfg(bdf, pci_bar_offset(idx), 4U); - size |= (uint64_t)pci_pdev_get_bar_base(size_lo); - - if (size != 0UL) { - size = size & ~(size - 1U); - } - - /* Restore the BAR */ - pci_pdev_write_cfg(bdf, pci_bar_offset(idx), 4U, bar_lo); - - if (type == PCIBAR_MEM64) { - pci_pdev_write_cfg(bdf, pci_bar_offset(idx + 1U), 4U, bar_hi); - } - } - } - - bar->size = size; - bar->base_hpa = base; - - return (type == PCIBAR_MEM64)?2U:1U; -} - -/* - * @pre nr_bars <= PCI_BAR_COUNT - */ -static void pci_pdev_read_bars(union pci_bdf bdf, uint32_t nr_bars, struct pci_bar *bar) -{ - uint32_t idx = 0U; - uint32_t bar_step; - - while (idx < nr_bars) { - bar_step = pci_pdev_read_bar(bdf, idx, &bar[idx]); - if ((bar_step == 2U) && ((idx + 1U) < nr_bars)) { - /* Upper 32-bit of a 64-bit bar: */ - bar[idx + 1U].is_64bit_high = true; - bar[idx + 1U].reg.value = pci_pdev_read_cfg(bdf, pci_bar_offset(idx + 1U), 4U); - } - - idx += bar_step; - } -} - /* * @pre ((hdr_type & PCIM_HDRTYPE) == PCIM_HDRTYPE_NORMAL) || ((hdr_type & PCIM_HDRTYPE) == PCIM_HDRTYPE_BRIDGE) || ((hdr_type & PCIM_HDRTYPE) == PCIM_HDRTYPE_CARDBUS) */ @@ -411,8 +311,6 @@ static void fill_pdev(uint16_t pbdf, struct pci_pdev *pdev) pdev->nr_bars = pci_pdev_get_nr_bars(hdr_type); - pci_pdev_read_bars(pdev->bdf, pdev->nr_bars, &pdev->bar[0]); - if ((pci_pdev_read_cfg(pdev->bdf, PCIR_STATUS, 2U) & PCIM_STATUS_CAPPRESENT) != 0U) { pci_read_cap(pdev, hdr_type); } diff --git a/hypervisor/include/hw/pci.h b/hypervisor/include/hw/pci.h index db9d7e9d7..aafa78ca6 100644 --- a/hypervisor/include/hw/pci.h +++ b/hypervisor/include/hw/pci.h @@ -85,6 +85,8 @@ #define PCIM_BAR_MEM_BASE 0xFFFFFFF0U #define PCIR_CAP_PTR 0x34U #define PCIR_CAP_PTR_CARDBUS 0x14U +#define PCI_BASE_ADDRESS_MEM_MASK (~0x0fUL) +#define PCI_BASE_ADDRESS_IO_MASK (~0x03UL) /* config registers for header type 1 (PCI-to-PCI bridge) devices */ #define PCIR_PRIBUS_1 0x18U @@ -209,7 +211,6 @@ struct pci_msix_cap { struct pci_pdev { /* The bar info of the physical PCI device. */ uint32_t nr_bars; /* 6 for normal device, 2 for bridge, 1 for cardbus */ - struct pci_bar bar[PCI_BAR_COUNT]; /* The bus/device/function triple of the physical PCI device. */ union pci_bdf bdf;