hv: vPCI: fix large bar base update

The current code would write 'BAR address & size_maks' into PCIe virtual
BAR before updating the virtual BAR's base address when guest writing a
PCIe device's BAR. If the size of a PCIe device's BAR is larger than 4G,
the low 32 bits size_mask for this 64 bits BAR is zero. When ACRN updating
the virtual BAR's base address, the low 32 bits sizing information would
be lost.

This patch saves whether a BAR writing is sizing or not before updating the
virtual BAR's base address.

Tracked-On: #8267
Signed-off-by: Fei Li <fei1.li@intel.com>
This commit is contained in:
Fei Li 2022-09-07 11:24:04 +08:00 committed by acrnsi-robot
parent 5a452e5e32
commit ab4e19d0be
2 changed files with 5 additions and 3 deletions

View File

@ -111,13 +111,13 @@ static void pci_vdev_update_vbar_base(struct pci_vdev *vdev, uint32_t idx)
vbar = &vdev->vbars[idx]; vbar = &vdev->vbars[idx];
offset = pci_bar_offset(idx); offset = pci_bar_offset(idx);
lo = pci_vdev_read_vcfg(vdev, offset, 4U); lo = pci_vdev_read_vcfg(vdev, offset, 4U);
if ((!is_pci_reserved_bar(vbar)) && (lo != (vbar->mask | vbar->bar_type.bits))) { if ((!is_pci_reserved_bar(vbar)) && !vbar->sizing) {
base = lo & vbar->mask; base = lo & vbar->mask;
if (is_pci_mem64lo_bar(vbar)) { if (is_pci_mem64lo_bar(vbar)) {
vbar = &vdev->vbars[idx + 1U]; vbar = &vdev->vbars[idx + 1U];
if (!vbar->sizing) {
hi = pci_vdev_read_vcfg(vdev, (offset + 4U), 4U); hi = pci_vdev_read_vcfg(vdev, (offset + 4U), 4U);
if (hi != vbar->mask) {
base |= ((uint64_t)hi << 32U); base |= ((uint64_t)hi << 32U);
} else { } else {
base = 0UL; base = 0UL;
@ -199,6 +199,7 @@ void pci_vdev_write_vbar(struct pci_vdev *vdev, uint32_t idx, uint32_t val)
uint32_t update_idx = idx; uint32_t update_idx = idx;
vbar = &vdev->vbars[idx]; vbar = &vdev->vbars[idx];
vbar->sizing = (val == ~0U);
bar = val & vbar->mask; bar = val & vbar->mask;
if (vbar->is_mem64hi) { if (vbar->is_mem64hi) {
update_idx -= 1U; update_idx -= 1U;

View File

@ -38,6 +38,7 @@
struct pci_vbar { struct pci_vbar {
bool is_mem64hi; /* this is to indicate the high part of 64 bits MMIO bar */ bool is_mem64hi; /* this is to indicate the high part of 64 bits MMIO bar */
bool sizing; /* this is to indicate the guest is sizing this BAR */
uint64_t size; /* BAR size */ uint64_t size; /* BAR size */
uint64_t base_gpa; /* BAR guest physical address */ uint64_t base_gpa; /* BAR guest physical address */
uint64_t base_hpa; /* BAR host physical address */ uint64_t base_hpa; /* BAR host physical address */