Meteor Lake and Arrow Lake GOP can read BAR0 MMIO offset 0x138914 to detect whether direct framebuffer access via DSM is available.
In a VFIO passthrough VM, the guest cannot access the host DSM memory region via such a pointer. If the guest GOP enables that path, it may hand off a DSM-based framebuffer address that the guest cannot actually use. Intercept reads from the detection register and return 0 so the guest does not enable the DSM-based path and instead keeps using the standard BAR-based framebuffer address. Suggested-by: Tomita Moeko <[email protected]> Reviewed-by: Tomita Moeko <[email protected]> Reviewed-by: Bosheng Xue <[email protected]> Reviewed-by: Junjie Cao <[email protected]> Reviewed-by: Cédric Le Goater <[email protected]> Signed-off-by: Yuan Wang <[email protected]> --- Changes: v4: - Address review comments from Tomita Moeko (update macro/variable names and comments). - Pick up Reviewed-by tags from Tomita Moeko and Cédric Le Goater. v3: - Emulated register 0x138914 to return 0x0, which signals the guest GOP driver to fall back to BAR-based mapping since DSM is unavailable in the VM. v2: - Resending because the v1 patch was sent with an incorrect future system timestamp due to an unsynchronized local clock. No code changes. Notes: MTL/ARL device IDs remain in igd_gen(). This is required because vfio_probe_igd_bar0_quirk() checks the generation before installing BAR0 quirks, and the 0x138914 quirk is added afterward. Meanwhile, we also plan to remove the bdsm-size check in the OVMF offline patches. --- hw/vfio/igd.c | 49 ++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 46 insertions(+), 3 deletions(-) diff --git a/hw/vfio/igd.c b/hw/vfio/igd.c index 413a49aae9..fe9ffc93c8 100644 --- a/hw/vfio/igd.c +++ b/hw/vfio/igd.c @@ -96,6 +96,8 @@ static int igd_gen(VFIOPCIDevice *vdev) case 0x4C00: /* Rocket Lake */ case 0x4600: /* Alder Lake */ case 0xA700: /* Raptor Lake */ + case 0x7D00: /* Meteor Lake / Arrow Lake */ + case 0xB600: /* Arrow Lake */ return 12; } @@ -452,12 +454,34 @@ static bool vfio_pci_igd_override_gms(int gen, uint32_t gms, uint32_t *gmch) return ret; } -#define IGD_GGC_MMIO_OFFSET 0x108040 -#define IGD_BDSM_MMIO_OFFSET 0x1080C0 +#define IGD_GGC_MMIO_OFFSET 0x108040 +#define IGD_BDSM_MMIO_OFFSET 0x1080C0 +#define IGD_MTL_PCODE_STOLEN_ACCESS 0x138914 + +#define IGD_IS_MTL_OR_ARL(vdev) \ + ((((vdev)->device_id & 0xff00) == 0x7d00) || \ + (((vdev)->device_id & 0xff00) == 0xb600)) + +static uint64_t vfio_igd_pcode_stolen_access_read(void *opaque, hwaddr addr, + unsigned size) +{ + return 0; +} + +static void vfio_igd_pcode_stolen_access_write(void *opaque, hwaddr addr, + uint64_t data, unsigned size) +{ +} + +static const MemoryRegionOps vfio_igd_pcode_stolen_access_quirk = { + .read = vfio_igd_pcode_stolen_access_read, + .write = vfio_igd_pcode_stolen_access_write, + .endianness = DEVICE_LITTLE_ENDIAN, +}; void vfio_probe_igd_bar0_quirk(VFIOPCIDevice *vdev, int nr) { - VFIOQuirk *ggc_quirk, *bdsm_quirk; + VFIOQuirk *ggc_quirk, *bdsm_quirk, *pcode_stolen_access_quirk; VFIOConfigMirrorQuirk *ggc_mirror, *bdsm_mirror; int gen; @@ -472,6 +496,25 @@ void vfio_probe_igd_bar0_quirk(VFIOPCIDevice *vdev, int nr) return; } + /* + * MTL/ARL guests must keep using the BAR-based framebuffer address. + * Return 0 for PCODE stolen memory access detection (0x138914) so GOP + * stays on the standard access path in the VM. + */ + if (IGD_IS_MTL_OR_ARL(vdev)) { + pcode_stolen_access_quirk = vfio_quirk_alloc(1); + memory_region_init_io(pcode_stolen_access_quirk->mem, OBJECT(vdev), + &vfio_igd_pcode_stolen_access_quirk, vdev, + "vfio-igd-pcode-stolen-access-quirk", 4); + memory_region_add_subregion_overlap(vdev->bars[nr].region.mem, + IGD_MTL_PCODE_STOLEN_ACCESS, + pcode_stolen_access_quirk->mem, + 1); + + QLIST_INSERT_HEAD(&vdev->bars[nr].quirks, + pcode_stolen_access_quirk, next); + } + if (vdev->igd_gms) { ggc_quirk = vfio_quirk_alloc(1); ggc_mirror = ggc_quirk->data = g_malloc0(sizeof(*ggc_mirror)); -- 2.34.1
