hw/vfio/igd.c | 49 ++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 46 insertions(+), 3 deletions(-)
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 <tomitamoeko@gmail.com>
Reviewed-by: Tomita Moeko <tomitamoeko@gmail.com>
Reviewed-by: Bosheng Xue <bosheng.xue@intel.com>
Reviewed-by: Junjie Cao <junjie.cao@intel.com>
Reviewed-by: Cédric Le Goater <clg@redhat.com>
Signed-off-by: Yuan Wang <yuan1.wang@intel.com>
---
Changes:
v5:
- Rebased on top of Cédric's vfio-next branch to resolve conflicts
with Mike's commit.
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 5e6160763c..4c7d654592 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,8 +454,30 @@ 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,
+};
/*
* IGD BAR0 DBUF_CTL sanitize quirk.
@@ -547,7 +571,7 @@ static const MemoryRegionOps igd_dbuf_ctl_ops = {
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;
@@ -562,6 +586,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
On 9/23/26 07:25, Yuan Wang wrote:
> 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 <tomitamoeko@gmail.com>
> Reviewed-by: Tomita Moeko <tomitamoeko@gmail.com>
> Reviewed-by: Bosheng Xue <bosheng.xue@intel.com>
> Reviewed-by: Junjie Cao <junjie.cao@intel.com>
> Reviewed-by: Cédric Le Goater <clg@redhat.com>
> Signed-off-by: Yuan Wang <yuan1.wang@intel.com>
> ---
> Changes:
> v5:
> - Rebased on top of Cédric's vfio-next branch to resolve conflicts
> with Mike's commit.
Thanks for doing so.
Applied to
https://github.com/legoater/qemu vfio-next
C.
© 2016 - 2026 Red Hat, Inc.