Re: [PATCH v3 2/3] vfio: selftests: Add vfio_pci_find_mem_bar() helper

From: Alex Williamson

Date: Tue Nov 03 2026 - 14:04:47 EST


On Mon, 2 Nov 2026 23:04:44 +0000
Mina Almasry <almasrymina@xxxxxxxxxx> wrote:

> 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=<size> and
> membar-backed=on.

Should we test for this?

We could toggle memory decode around writing a short, unique pattern
with read-back verification. This might be unnecessary for a physical
device, but per the definition of this function it should also be
harmless. For the pci-testdev, which is our only match in this
proposal, it validates the BAR is backed by real memory and not handled
as an unimplemented memory range.

For the use case in patch 3/ it doesn't matter, but for future use
cases I'd rather see that we generate a skip or failure based on the
test here rather than debug failures in the test case consumers.
Thanks,

Alex

> Suggested-by: David Matlack <dmatlack@xxxxxxxxxx>
> Cc: David Matlack <dmatlack@xxxxxxxxxx>
> Cc: Matt Evans <matt@xxxxxxxxxx>
> Signed-off-by: Mina Almasry <almasrymina@xxxxxxxxxx>
> ---
> .../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 <linux/log2.h>
> #include <linux/mman.h>
> #include <linux/overflow.h>
> +#include <linux/pci_ids.h>
> #include <linux/sizes.h>
> #include <linux/types.h>
> #include <linux/vfio.h>
> @@ -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=<size>,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)
> {