Write and read back test patterns before returning a BAR from vfio_pci_find_mem_bar(), restoring the original contents and PCI_COMMAND_MEMORY state afterward. QEMU's pci-testdev exposes a readable, writable, mmap-capable BAR2 whenever membar= is passed, even if membar-backed=on was omitted and accesses are dropped as unimplemented MMIO. Probing the BAR upfront lets callers skip cleanly instead of failing later DMA or fault checks. Suggested-by: Alex Williamson Signed-off-by: David Matlack --- .../selftests/vfio/lib/vfio_pci_device.c | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/tools/testing/selftests/vfio/lib/vfio_pci_device.c b/tools/testing/selftests/vfio/lib/vfio_pci_device.c index d5308fe61490..9840463594ab 100644 --- a/tools/testing/selftests/vfio/lib/vfio_pci_device.c +++ b/tools/testing/selftests/vfio/lib/vfio_pci_device.c @@ -13,6 +13,7 @@ #include #include +#include #include #include #include @@ -265,6 +266,33 @@ static const struct vfio_pci_mem_bar_desc mem_bar_descs[] = { }, }; +static bool vfio_pci_mem_bar_verify(struct vfio_pci_device *device, void *vaddr) +{ + const u64 pattern = 0x55aa55aa55aa55aaULL; + u16 orig_cmd; + u64 orig; + bool ok; + + orig_cmd = vfio_pci_config_readw(device, PCI_COMMAND); + if (!(orig_cmd & PCI_COMMAND_MEMORY)) + vfio_pci_config_writew(device, PCI_COMMAND, + orig_cmd | PCI_COMMAND_MEMORY); + + orig = readq(vaddr); + writeq(pattern, vaddr); + ok = (readq(vaddr) == pattern); + if (ok) { + writeq(~pattern, vaddr); + ok = (readq(vaddr) == ~pattern); + } + writeq(orig, vaddr); + + if (!(orig_cmd & PCI_COMMAND_MEMORY)) + vfio_pci_config_writew(device, PCI_COMMAND, orig_cmd); + + return ok; +} + bool vfio_pci_find_mem_bar(struct vfio_pci_device *device, u64 min_size, struct vfio_pci_mem_bar *mem_bar) { @@ -273,6 +301,8 @@ bool vfio_pci_find_mem_bar(struct vfio_pci_device *device, u64 min_size, VFIO_REGION_INFO_FLAG_WRITE; size_t i; + min_size = max_t(u64, min_size, sizeof(u64)); + for (i = 0; i < ARRAY_SIZE(mem_bar_descs); i++) { const struct vfio_pci_mem_bar_desc *desc = &mem_bar_descs[i]; struct vfio_pci_bar *bar; @@ -300,6 +330,9 @@ bool vfio_pci_find_mem_bar(struct vfio_pci_device *device, u64 min_size, if (size < min_size) continue; + if (!vfio_pci_mem_bar_verify(device, bar->vaddr + desc->offset)) + continue; + *mem_bar = (struct vfio_pci_mem_bar){ .bar = bar, .vaddr = bar->vaddr + desc->offset, -- 2.56.0.567.gdb80ae8cd5-goog