+/*
+ * The generic mirror quirk handles devices which expose PCI config space
+ * through a region within a BAR. When enabled, reads and writes are
+ * redirected through to emulated PCI config space. XXX if PCI config space
+ * used memory regions, this could just be an alias.
+ */
+typedef struct VFIOConfigMirrorQuirk {
+ struct VFIOPCIDevice *vdev;
+ uint32_t offset;
+ uint8_t bar;
+ MemoryRegion *mem;
+} VFIOConfigMirrorQuirk;
+
+static uint64_t vfio_generic_quirk_mirror_read(void *opaque,
+ hwaddr addr, unsigned size)
+{
+ VFIOConfigMirrorQuirk *mirror = opaque;
+ VFIOPCIDevice *vdev = mirror->vdev;
+ uint64_t data;
+
+ /* Read and discard in case the hardware cares */
+ (void)vfio_region_read(&vdev->bars[mirror->bar].region,
+ addr + mirror->offset, size);
+
+ data = vfio_pci_read_config(&vdev->pdev, addr, size);
+ trace_vfio_quirk_generic_mirror_read(vdev->vbasedev.name,
+ memory_region_name(mirror->mem),
+ addr, data);
+ return data;
+}
+
+static void vfio_generic_quirk_mirror_write(void *opaque, hwaddr addr,
+ uint64_t data, unsigned size)
+{
+ VFIOConfigMirrorQuirk *mirror = opaque;
+ VFIOPCIDevice *vdev = mirror->vdev;
+
+ vfio_pci_write_config(&vdev->pdev, addr, data, size);
+ trace_vfio_quirk_generic_mirror_write(vdev->vbasedev.name,
+ memory_region_name(mirror->mem),
+ addr, data);
+}
+
+static const MemoryRegionOps vfio_generic_mirror_quirk = {
+ .read = vfio_generic_quirk_mirror_read,
+ .write = vfio_generic_quirk_mirror_write,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+};
+