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] vfio/igd: q35 iGPU passthrough support (GMCH/BDSM/bdsm-size)
75
8- This reverts commit 93587e3af3a259deac89c12863d93653d69d22b8.
96---
10- tools/qemu-xen/ hw/vfio/igd.c | 64 ++++++++++++++++++++++++++++++----- ----------------
11- 1 file changed, 38 insertions(+), 26 deletions(-)
7+ hw/vfio/igd.c | 133 ++++++++++++++++++++++++++++++++++ ----------------
8+ 1 file changed, 91 insertions(+), 42 deletions(-)
129
1310diff --git a/tools/qemu-xen/hw/vfio/igd.c b/tools/qemu-xen/hw/vfio/igd.c
14- index 64e332746b..573cd53803 100644
11+ index d320d032a7..cb37f8ce08 100644
1512--- a/tools/qemu-xen/hw/vfio/igd.c
1613+++ b/tools/qemu-xen/hw/vfio/igd.c
17- @@ -377,14 +377,45 @@ void vfio_probe_igd_bar4_quirk(VFIOPCIDevice *vdev, int nr)
14+ @@ -375,19 +375,98 @@ void vfio_probe_igd_bar4_quirk(VFIOPCIDevice *vdev, int nr)
15+ VFIOIGDQuirk *igd;
16+ PCIDevice *lpc_bridge;
17+ int i, ret, ggms_mb, gms_mb = 0, gen;
18+ - uint64_t *bdsm_size;
19+ uint32_t gmch;
1820 uint16_t cmd_orig, cmd;
1921 Error *err = NULL;
20-
22+
2123+ /* This must be an Intel VGA device. */
2224+ if (!vfio_pci_is(vdev, PCI_VENDOR_ID_INTEL, PCI_ANY_ID) ||
2325+ !vfio_is_vga(vdev) || nr != 4 ) {
@@ -29,16 +31,16 @@ index 64e332746b..573cd53803 100644
2931- * consider enabling legacy mode. The vBIOS has dependencies on the
3032- * PCI bus address.
3133+ * 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 .
34+ + * support Sandy Bridge (gen 6) through Raptor Lake (gen 12) and assume
35+ + * future devices maintain compatibility with the gen 8 GMCH layout .
3436 */
3537- if (!vfio_pci_is(vdev, PCI_VENDOR_ID_INTEL, PCI_ANY_ID) ||
3638- !vfio_is_vga(vdev) || nr != 4 ||
3739- &vdev->pdev != pci_find_device(pci_device_root_bus(&vdev->pdev),
3840+ 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);
41+ + if (gen < 0 ) {
42+ + error_report("IGD device %s has unknown generation, skipping IGD quirks",
43+ + vdev->vbasedev.name);
4244+ return;
4345+ }
4446+
@@ -51,6 +53,40 @@ index 64e332746b..573cd53803 100644
5153+ * this below.
5254+ */
5355+ gmch = vfio_pci_read_config(&vdev->pdev, IGD_GMCH, 4);
56+ +
57+ + /*
58+ + * Write the GMS-based stolen memory size to fw_cfg so that OVMF's
59+ + * IgdAssignmentDxe can allocate guest stolen memory and set BDSM
60+ + * (PCI config 0x5C). We do this before the BDF and LPC bridge checks
61+ + * so the entry is available on q35 where the legacy-mode path never
62+ + * runs ("Sorry Q35").
63+ + *
64+ + * GMS codes 1-16 map to 32-512 MB (code * 32 MB).
65+ + */
66+ + {
67+ + uint32_t gms = (gmch >> (gen < 8 ? 3 : 8)) & (gen < 8 ? 0x1f : 0xff);
68+ + uint64_t bdsm_bytes = (uint64_t)gms * 32 * MiB;
69+ + error_report("IGD bdsm-size: device %04x gen=%d gmch=0x%08x "
70+ + "gms=%u bdsm_bytes=%" PRIu64,
71+ + vdev->device_id, gen, gmch, gms, bdsm_bytes);
72+ + if (gms) {
73+ + FWCfgState *fw_cfg = fw_cfg_find();
74+ + if (fw_cfg) {
75+ + uint64_t *bdsm_size = g_malloc(sizeof(*bdsm_size));
76+ + *bdsm_size = cpu_to_le64(bdsm_bytes);
77+ + fw_cfg_add_file(fw_cfg, "etc/igd-bdsm-size",
78+ + bdsm_size, sizeof(*bdsm_size));
79+ + error_report("IGD bdsm-size: wrote etc/igd-bdsm-size = %"
80+ + PRIu64 " bytes to fw_cfg", bdsm_bytes);
81+ + } else {
82+ + error_report("IGD bdsm-size: fw_cfg not found, skipping");
83+ + }
84+ + } else {
85+ + error_report("IGD bdsm-size: gms=0, no stolen memory "
86+ + "reported by host GMCH");
87+ + }
88+ + }
89+ +
5490+ gmch &= ~((gen < 8 ? 0x1f : 0xff) << (gen < 8 ? 3 : 8));
5591+
5692+ /* GMCH is read-only, emulated */
@@ -59,17 +95,32 @@ index 64e332746b..573cd53803 100644
5995+ pci_set_long(vdev->emulated_config_bits + IGD_GMCH, ~0);
6096+
6197+ /*
98+ + * BDSM is read-write, emulated. Initialize to 0 here (before the BDF
99+ + * and LPC bridge checks) so that:
100+ + * 1. On q35 ("Sorry Q35"), where the legacy path never runs, OVMF's
101+ + * IgdAssignmentDxe sees BDSM=0 and proceeds to allocate guest
102+ + * stolen memory, writing the guest PA back here.
103+ + * 2. The guest driver reads the guest PA written by OVMF, not the
104+ + * host PA (which would cause DMA into the wrong guest memory).
105+ + * 3. IgdAssignmentDxe's idempotency check ("if BDSM != 0, skip")
106+ + * is not falsely triggered by the host's physical address.
107+ + */
108+ + pci_set_long(vdev->pdev.config + IGD_BDSM, 0);
109+ + pci_set_long(vdev->pdev.wmask + IGD_BDSM, ~0);
110+ + pci_set_long(vdev->emulated_config_bits + IGD_BDSM, ~0);
111+ +
112+ + /*
62113+ * This must be at address 00:02.0 for us to even onsider enabling
63114+ * legacy mode. The vBIOS has dependencies on the PCI bus address.
64115+ */
65116+ if (&vdev->pdev != pci_find_device(pci_device_root_bus(&vdev->pdev),
66117 0, PCI_DEVFN(0x2, 0))) {
67118 return;
68119 }
69- @@ -403 ,18 +434 ,6 @@ void vfio_probe_igd_bar4_quirk(VFIOPCIDevice *vdev, int nr)
120+ @@ -406 ,18 +485 ,6 @@ void vfio_probe_igd_bar4_quirk(VFIOPCIDevice *vdev, int nr)
70121 return;
71122 }
72-
123+
73124- /*
74125- * IGD is not a standard, they like to change their specs often. We
75126- * only attempt to support back to SandBridge and we hope that newer
@@ -85,21 +136,21 @@ index 64e332746b..573cd53803 100644
85136 /*
86137 * Most of what we're doing here is to enable the ROM to run, so if
87138 * 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 ;
139+ @@ -473 ,8 +540 ,6 @@ void vfio_probe_igd_bar4_quirk(VFIOPCIDevice *vdev, int nr)
140+ return ;
90141 }
91-
142+
92143- gmch = vfio_pci_read_config(&vdev->pdev, IGD_GMCH, 4);
93144-
94145 /*
95146 * If IGD VGA Disable is clear (expected) and VGA is not already enabled,
96147 * 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)
148+ @@ -542 ,12 +607 ,12 @@ void vfio_probe_igd_bar4_quirk(VFIOPCIDevice *vdev, int nr)
98149 * when IVD (IGD VGA Disable) is clear, but the claim is that it's unused,
99150 * so let's not waste VM memory for it.
100151 */
101152- gmch &= ~((gen < 8 ? 0x1f : 0xff) << (gen < 8 ? 3 : 8));
102-
153+
103154 if (vdev->igd_gms) {
104155 if (vdev->igd_gms <= 0x10) {
105156 gms_mb = vdev->igd_gms * 32;
@@ -108,17 +159,38 @@ index 64e332746b..573cd53803 100644
108159 } else {
109160 error_report("Unsupported IGD GMS value 0x%x", vdev->igd_gms);
110161 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-
162+ @@ -555,27 +620,11 @@ void vfio_probe_igd_bar4_quirk(VFIOPCIDevice *vdev, int nr)
163+ }
164+
165+ /*
166+ - * Request reserved memory for stolen memory via fw_cfg. VM firmware
167+ - * must allocate a 1MB aligned reserved memory region below 4GB with
168+ - * the requested size (in bytes) for use by the Intel PCI class VGA
169+ - * device at VM address 00:02.0. The base address of this reserved
170+ - * memory region must be written to the device BDSM register at PCI
171+ - * config offset 0x5C.
172+ + * etc/igd-bdsm-size is written before the BDF check (above) so that it
173+ + * is available on q35 machines where the legacy path never runs.
174+ + * Do not write it again here to avoid a duplicate fw_cfg key.
175+ + * BDSM emulation is also set up before the BDF check.
176+ */
177+ - bdsm_size = g_malloc(sizeof(*bdsm_size));
178+ - *bdsm_size = cpu_to_le64((ggms_mb + gms_mb) * MiB);
179+ - fw_cfg_add_file(fw_cfg_find(), "etc/igd-bdsm-size",
180+ - bdsm_size, sizeof(*bdsm_size));
181+ -
115182- /* GMCH is read-only, emulated */
116183- pci_set_long(vdev->pdev.config + IGD_GMCH, gmch);
117184- pci_set_long(vdev->pdev.wmask + IGD_GMCH, 0);
118185- pci_set_long(vdev->emulated_config_bits + IGD_GMCH, ~0);
119186-
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
187+ - /* BDSM is read-write, emulated. The BIOS needs to be able to write it */
188+ - pci_set_long(vdev->pdev.config + IGD_BDSM, 0);
189+ - pci_set_long(vdev->pdev.wmask + IGD_BDSM, ~0);
190+ - pci_set_long(vdev->emulated_config_bits + IGD_BDSM, ~0);
191+
192+ /*
193+ * This IOBAR gives us access to GTTADR, which allows us to write to
194+ - -
195+ 2.43.0
196+
0 commit comments