1- From 9eb4883e57224db64588d724d5764cdccb164c7d Mon Sep 17 00:00:00 2001
2- From: Petr Fedchenkov <giggsoff@gmail.com>
3- Date: Mon, 11 Oct 2021 17:30:15 +0300
4- Subject: [PATCH] Revert "Revert "vfio/pci-quirks.c: Disable stolen memory for
5- igd VFIO"" and adopts it to the new qemu with moved vfio_probe_igd_bar4_quirk
6- into igd.c.
1+ From 22e1ac33571bbb70740bb181e4729018b6402442 Mon Sep 17 00:00:00 2001
2+ From: Mikhail Malyshev <mike.malyshev@gmail.com>
3+ Date: Fri, 27 Mar 2026 23:26:25 +0000
4+ Subject: [PATCH 1/2] vfio/igd: q35 iGPU passthrough support
5+ (GMCH/BDSM/bdsm-size)
76
8- This reverts commit 93587e3af3a259deac89c12863d93653d69d22b8.
97---
10- tools/qemu-xen/ hw/vfio/igd.c | 64 ++++++++++++++++++++++++++++++----- ----------------
11- 1 file changed, 38 insertions(+), 26 deletions(-)
8+ hw/vfio/igd.c | 133 ++++++++++++++++++++++++++++++++++ ----------------
9+ 1 file changed, 91 insertions(+), 42 deletions(-)
1210
1311diff --git a/tools/qemu-xen/hw/vfio/igd.c b/tools/qemu-xen/hw/vfio/igd.c
14- index 64e332746b..573cd53803 100644
12+ index d320d032a7..cb37f8ce08 100644
1513--- a/tools/qemu-xen/hw/vfio/igd.c
1614+++ b/tools/qemu-xen/hw/vfio/igd.c
17- @@ -377,14 +377,45 @@ void vfio_probe_igd_bar4_quirk(VFIOPCIDevice *vdev, int nr)
15+ @@ -375,19 +375,98 @@ void vfio_probe_igd_bar4_quirk(VFIOPCIDevice *vdev, int nr)
16+ VFIOIGDQuirk *igd;
17+ PCIDevice *lpc_bridge;
18+ int i, ret, ggms_mb, gms_mb = 0, gen;
19+ - uint64_t *bdsm_size;
20+ uint32_t gmch;
1821 uint16_t cmd_orig, cmd;
1922 Error *err = NULL;
20-
23+
2124+ /* This must be an Intel VGA device. */
2225+ if (!vfio_pci_is(vdev, PCI_VENDOR_ID_INTEL, PCI_ANY_ID) ||
2326+ !vfio_is_vga(vdev) || nr != 4 ) {
@@ -29,16 +32,16 @@ index 64e332746b..573cd53803 100644
2932- * consider enabling legacy mode. The vBIOS has dependencies on the
3033- * PCI bus address.
3134+ * IGD is not a standard, they like to change their specs often. We
32- + * only attempt to support back to SandBridge and we hope that newer
33- + * devices maintain compatibility with generation 8 .
35+ + * support Sandy Bridge (gen 6) through Raptor Lake (gen 12) and assume
36+ + * future devices maintain compatibility with the gen 8 GMCH layout .
3437 */
3538- if (!vfio_pci_is(vdev, PCI_VENDOR_ID_INTEL, PCI_ANY_ID) ||
3639- !vfio_is_vga(vdev) || nr != 4 ||
3740- &vdev->pdev != pci_find_device(pci_device_root_bus(&vdev->pdev),
3841+ gen = igd_gen(vdev);
39- + if (gen != 6 && gen != 8 ) {
40- + error_report("IGD device %s is unsupported by IGD quirks, "
41- + "try SandyBridge or newer", vdev->vbasedev.name);
42+ + if (gen < 0 ) {
43+ + error_report("IGD device %s has unknown generation, skipping IGD quirks",
44+ + vdev->vbasedev.name);
4245+ return;
4346+ }
4447+
@@ -51,6 +54,40 @@ index 64e332746b..573cd53803 100644
5154+ * this below.
5255+ */
5356+ gmch = vfio_pci_read_config(&vdev->pdev, IGD_GMCH, 4);
57+ +
58+ + /*
59+ + * Write the GMS-based stolen memory size to fw_cfg so that OVMF's
60+ + * IgdAssignmentDxe can allocate guest stolen memory and set BDSM
61+ + * (PCI config 0x5C). We do this before the BDF and LPC bridge checks
62+ + * so the entry is available on q35 where the legacy-mode path never
63+ + * runs ("Sorry Q35").
64+ + *
65+ + * GMS codes 1-16 map to 32-512 MB (code * 32 MB).
66+ + */
67+ + {
68+ + uint32_t gms = (gmch >> (gen < 8 ? 3 : 8)) & (gen < 8 ? 0x1f : 0xff);
69+ + uint64_t bdsm_bytes = (uint64_t)gms * 32 * MiB;
70+ + error_report("IGD bdsm-size: device %04x gen=%d gmch=0x%08x "
71+ + "gms=%u bdsm_bytes=%" PRIu64,
72+ + vdev->device_id, gen, gmch, gms, bdsm_bytes);
73+ + if (gms) {
74+ + FWCfgState *fw_cfg = fw_cfg_find();
75+ + if (fw_cfg) {
76+ + uint64_t *bdsm_size = g_malloc(sizeof(*bdsm_size));
77+ + *bdsm_size = cpu_to_le64(bdsm_bytes);
78+ + fw_cfg_add_file(fw_cfg, "etc/igd-bdsm-size",
79+ + bdsm_size, sizeof(*bdsm_size));
80+ + error_report("IGD bdsm-size: wrote etc/igd-bdsm-size = %"
81+ + PRIu64 " bytes to fw_cfg", bdsm_bytes);
82+ + } else {
83+ + error_report("IGD bdsm-size: fw_cfg not found, skipping");
84+ + }
85+ + } else {
86+ + error_report("IGD bdsm-size: gms=0, no stolen memory "
87+ + "reported by host GMCH");
88+ + }
89+ + }
90+ +
5491+ gmch &= ~((gen < 8 ? 0x1f : 0xff) << (gen < 8 ? 3 : 8));
5592+
5693+ /* GMCH is read-only, emulated */
@@ -59,17 +96,32 @@ index 64e332746b..573cd53803 100644
5996+ pci_set_long(vdev->emulated_config_bits + IGD_GMCH, ~0);
6097+
6198+ /*
99+ + * BDSM is read-write, emulated. Initialize to 0 here (before the BDF
100+ + * and LPC bridge checks) so that:
101+ + * 1. On q35 ("Sorry Q35"), where the legacy path never runs, OVMF's
102+ + * IgdAssignmentDxe sees BDSM=0 and proceeds to allocate guest
103+ + * stolen memory, writing the guest PA back here.
104+ + * 2. The guest driver reads the guest PA written by OVMF, not the
105+ + * host PA (which would cause DMA into the wrong guest memory).
106+ + * 3. IgdAssignmentDxe's idempotency check ("if BDSM != 0, skip")
107+ + * is not falsely triggered by the host's physical address.
108+ + */
109+ + pci_set_long(vdev->pdev.config + IGD_BDSM, 0);
110+ + pci_set_long(vdev->pdev.wmask + IGD_BDSM, ~0);
111+ + pci_set_long(vdev->emulated_config_bits + IGD_BDSM, ~0);
112+ +
113+ + /*
62114+ * This must be at address 00:02.0 for us to even onsider enabling
63115+ * legacy mode. The vBIOS has dependencies on the PCI bus address.
64116+ */
65117+ if (&vdev->pdev != pci_find_device(pci_device_root_bus(&vdev->pdev),
66118 0, PCI_DEVFN(0x2, 0))) {
67119 return;
68120 }
69- @@ -403 ,18 +434 ,6 @@ void vfio_probe_igd_bar4_quirk(VFIOPCIDevice *vdev, int nr)
121+ @@ -406 ,18 +485 ,6 @@ void vfio_probe_igd_bar4_quirk(VFIOPCIDevice *vdev, int nr)
70122 return;
71123 }
72-
124+
73125- /*
74126- * IGD is not a standard, they like to change their specs often. We
75127- * only attempt to support back to SandBridge and we hope that newer
@@ -85,21 +137,21 @@ index 64e332746b..573cd53803 100644
85137 /*
86138 * Most of what we're doing here is to enable the ROM to run, so if
87139 * there's no ROM, there's no point in setting up this quirk.
88- @@ -470 ,8 +489 ,6 @@ void vfio_probe_igd_bar4_quirk(VFIOPCIDevice *vdev, int nr)
89- goto out ;
140+ @@ -473 ,8 +540 ,6 @@ void vfio_probe_igd_bar4_quirk(VFIOPCIDevice *vdev, int nr)
141+ return ;
90142 }
91-
143+
92144- gmch = vfio_pci_read_config(&vdev->pdev, IGD_GMCH, 4);
93145-
94146 /*
95147 * If IGD VGA Disable is clear (expected) and VGA is not already enabled,
96148 * try to enable it. Probably shouldn't be using legacy mode without VGA,
97- @@ -540 ,12 +557 ,12 @@ void vfio_probe_igd_bar4_quirk(VFIOPCIDevice *vdev, int nr)
149+ @@ -542 ,12 +607 ,12 @@ void vfio_probe_igd_bar4_quirk(VFIOPCIDevice *vdev, int nr)
98150 * when IVD (IGD VGA Disable) is clear, but the claim is that it's unused,
99151 * so let's not waste VM memory for it.
100152 */
101153- gmch &= ~((gen < 8 ? 0x1f : 0xff) << (gen < 8 ? 3 : 8));
102-
154+
103155 if (vdev->igd_gms) {
104156 if (vdev->igd_gms <= 0x10) {
105157 gms_mb = vdev->igd_gms * 32;
@@ -108,17 +160,77 @@ index 64e332746b..573cd53803 100644
108160 } else {
109161 error_report("Unsupported IGD GMS value 0x%x", vdev->igd_gms);
110162 vdev->igd_gms = 0;
111- @@ -565,11 +582,6 @@ void vfio_probe_igd_bar4_quirk(VFIOPCIDevice *vdev, int nr)
112- fw_cfg_add_file(fw_cfg_find(), "etc/igd-bdsm-size",
113- bdsm_size, sizeof(*bdsm_size));
114-
163+ @@ -555,27 +620,11 @@ void vfio_probe_igd_bar4_quirk(VFIOPCIDevice *vdev, int nr)
164+ }
165+
166+ /*
167+ - * Request reserved memory for stolen memory via fw_cfg. VM firmware
168+ - * must allocate a 1MB aligned reserved memory region below 4GB with
169+ - * the requested size (in bytes) for use by the Intel PCI class VGA
170+ - * device at VM address 00:02.0. The base address of this reserved
171+ - * memory region must be written to the device BDSM register at PCI
172+ - * config offset 0x5C.
173+ + * etc/igd-bdsm-size is written before the BDF check (above) so that it
174+ + * is available on q35 machines where the legacy path never runs.
175+ + * Do not write it again here to avoid a duplicate fw_cfg key.
176+ + * BDSM emulation is also set up before the BDF check.
177+ */
178+ - bdsm_size = g_malloc(sizeof(*bdsm_size));
179+ - *bdsm_size = cpu_to_le64((ggms_mb + gms_mb) * MiB);
180+ - fw_cfg_add_file(fw_cfg_find(), "etc/igd-bdsm-size",
181+ - bdsm_size, sizeof(*bdsm_size));
182+ -
115183- /* GMCH is read-only, emulated */
116184- pci_set_long(vdev->pdev.config + IGD_GMCH, gmch);
117185- pci_set_long(vdev->pdev.wmask + IGD_GMCH, 0);
118186- pci_set_long(vdev->emulated_config_bits + IGD_GMCH, ~0);
119187-
120- /* BDSM is read-write, emulated. The BIOS needs to be able to write it */
121- pci_set_long(vdev->pdev.config + IGD_BDSM, 0);
122- pci_set_long(vdev->pdev.wmask + IGD_BDSM, ~0);
123- - -
124- 2.30.2
188+ - /* BDSM is read-write, emulated. The BIOS needs to be able to write it */
189+ - pci_set_long(vdev->pdev.config + IGD_BDSM, 0);
190+ - pci_set_long(vdev->pdev.wmask + IGD_BDSM, ~0);
191+ - pci_set_long(vdev->emulated_config_bits + IGD_BDSM, ~0);
192+
193+ /*
194+ * This IOBAR gives us access to GTTADR, which allows us to write to
195+ - -
196+ 2.43.0
197+
198+
199+ From 77fe327406163bd4acfb1fccb1fc37d17b458ef3 Mon Sep 17 00:00:00 2001
200+ From: Mikhail Malyshev <mike.malyshev@gmail.com>
201+ Date: Sat, 28 Mar 2026 00:25:44 +0000
202+ Subject: [PATCH 2/2] vfio/igd: fix GMS stolen memory size for gen9+ 0xf0-0xff
203+ codes
204+
205+ ---
206+ hw/vfio/igd.c | 11 +++++++++--
207+ 1 file changed, 9 insertions(+), 2 deletions(-)
208+
209+ diff --git a/tools/qemu-xen/hw/vfio/igd.c b/tools/qemu-xen/hw/vfio/igd.c
210+ index cb37f8ce08..921cddfa16 100644
211+ --- a/tools/qemu-xen/hw/vfio/igd.c
212+ +++ b/tools/qemu-xen/hw/vfio/igd.c
213+ @@ -414,11 +414,18 @@ void vfio_probe_igd_bar4_quirk(VFIOPCIDevice *vdev, int nr)
214+ * so the entry is available on q35 where the legacy-mode path never
215+ * runs ("Sorry Q35").
216+ *
217+ - * GMS codes 1-16 map to 32-512 MB (code * 32 MB).
218+ + * GMS encoding (gen >= 9): codes 0x01-0xef map to N*32 MB; codes
219+ + * 0xf0-0xff map to (N-0xf0+1)*4 MB (4 MB granularity, Atom SKUs).
220+ + * For gen < 9 the field is at most 5 bits so only 0x01-0x10 are valid.
221+ */
222+ {
223+ uint32_t gms = (gmch >> (gen < 8 ? 3 : 8)) & (gen < 8 ? 0x1f : 0xff);
224+ - uint64_t bdsm_bytes = (uint64_t)gms * 32 * MiB;
225+ + uint64_t bdsm_bytes;
226+ + if (gen < 9 || gms < 0xf0) {
227+ + bdsm_bytes = (uint64_t)gms * 32 * MiB;
228+ + } else {
229+ + bdsm_bytes = (uint64_t)(gms - 0xf0 + 1) * 4 * MiB;
230+ + }
231+ error_report("IGD bdsm-size: device %04x gen=%d gmch=0x%08x "
232+ "gms=%u bdsm_bytes=%" PRIu64,
233+ vdev->device_id, gen, gmch, gms, bdsm_bytes);
234+ - -
235+ 2.43.0
236+
0 commit comments