From: Mina Almasry Add vfio_pci_find_mem_bar() to libvfio to locate a BAR (or range within a BAR) of at least min_size bytes that behaves like ordinary memory and can be safely read and written without device-specific side effects. Detection is backed by a table of known devices, starting with QEMU's pci-testdev (1b36:0005) BAR 2 when configured with membar= and membar-backed=on. Suggested-by: David Matlack Cc: David Matlack Cc: Matt Evans Signed-off-by: Mina Almasry Reviewed-by: David Matlack Signed-off-by: David Matlack --- .../lib/include/libvfio/vfio_pci_device.h | 10 +++ .../selftests/vfio/lib/vfio_pci_device.c | 67 +++++++++++++++++++ 2 files changed, 77 insertions(+) diff --git a/tools/testing/selftests/vfio/lib/include/libvfio/vfio_pci_device.h b/tools/testing/selftests/vfio/lib/include/libvfio/vfio_pci_device.h index 007adc322c1e..19d458adba1a 100644 --- a/tools/testing/selftests/vfio/lib/include/libvfio/vfio_pci_device.h +++ b/tools/testing/selftests/vfio/lib/include/libvfio/vfio_pci_device.h @@ -15,6 +15,13 @@ struct vfio_pci_bar { void *vaddr; }; +struct vfio_pci_mem_bar { + struct vfio_pci_bar *bar; + void *vaddr; + u64 offset; + u64 size; +}; + struct vfio_pci_device { const char *bdf; int fd; @@ -162,6 +169,9 @@ static inline bool vfio_pci_device_match(struct vfio_pci_device *device, (device_id == vfio_pci_config_readw(device, PCI_DEVICE_ID)); } +bool vfio_pci_find_mem_bar(struct vfio_pci_device *device, u64 min_size, + struct vfio_pci_mem_bar *mem_bar); + const char *vfio_pci_get_cdev_path(const char *bdf); void vfio_pci_group_setup(struct vfio_pci_device *device, const char *bdf); diff --git a/tools/testing/selftests/vfio/lib/vfio_pci_device.c b/tools/testing/selftests/vfio/lib/vfio_pci_device.c index 4063a0e2b3df..d5308fe61490 100644 --- a/tools/testing/selftests/vfio/lib/vfio_pci_device.c +++ b/tools/testing/selftests/vfio/lib/vfio_pci_device.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -245,6 +246,72 @@ static void vfio_pci_bar_unmap_all(struct vfio_pci_device *device) } } +#define PCI_DEVICE_ID_REDHAT_TEST 0x0005 + +struct vfio_pci_mem_bar_desc { + u16 vendor_id; + u16 device_id; + u8 bar_index; + u64 offset; + u64 size; +}; + +static const struct vfio_pci_mem_bar_desc mem_bar_descs[] = { + /* QEMU pci-testdev with membar=,membar-backed=on */ + { + .vendor_id = PCI_VENDOR_ID_REDHAT, + .device_id = PCI_DEVICE_ID_REDHAT_TEST, + .bar_index = 2, + }, +}; + +bool vfio_pci_find_mem_bar(struct vfio_pci_device *device, u64 min_size, + struct vfio_pci_mem_bar *mem_bar) +{ + const u32 rw_mmap_flags = VFIO_REGION_INFO_FLAG_MMAP | + VFIO_REGION_INFO_FLAG_READ | + VFIO_REGION_INFO_FLAG_WRITE; + size_t i; + + 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; + u64 size; + + if (!vfio_pci_device_match(device, desc->vendor_id, + desc->device_id)) + continue; + + VFIO_ASSERT_LT(desc->bar_index, PCI_STD_NUM_BARS); + bar = &device->bars[desc->bar_index]; + + if ((bar->info.flags & rw_mmap_flags) != rw_mmap_flags) + continue; + + VFIO_ASSERT_NOT_NULL(bar->vaddr); + + if (bar->info.size <= desc->offset) + continue; + + size = bar->info.size - desc->offset; + if (desc->size) + size = min(size, desc->size); + + if (size < min_size) + continue; + + *mem_bar = (struct vfio_pci_mem_bar){ + .bar = bar, + .vaddr = bar->vaddr + desc->offset, + .offset = desc->offset, + .size = size, + }; + return true; + } + + return false; +} + void vfio_pci_config_access(struct vfio_pci_device *device, bool write, size_t config, size_t size, void *data) { -- 2.56.0.567.gdb80ae8cd5-goog