Skip to content

Commit 3a472bd

Browse files
rucoderclaude
andcommitted
pkg/pillar: ship igd.rom and use it for Intel iGPU passthrough
Add Intel iGPU passthrough support to the KVM hypervisor: - Copy igd.rom from eve-uefi to /usr/lib/xen/boot/igd.rom so the bundled VfioIgdPkg Option ROM is always available at a fixed path - Always load igd.rom as the Option ROM for Intel iGPU passthrough; if a proprietary GOP ROM exists in /persist/gop/ for the device, prefer it (adds IntelGopDriver: UEFI framebuffer + pre-OS display), otherwise fall back to the bundled igd.rom (IgdAssignmentDxe only: OS display driver works correctly, no pre-OS UEFI framebuffer) - Place iGPU at guest BDF 00:02.0 on pcie.0 with x-igd-opregion=on - Move USB root port from addr=0x2 to addr=0x1b to free slot 2 Signed-off-by: Mikhail Malyshev <mike.malyshev@gmail.com> Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 1628d23 commit 3a472bd

File tree

3 files changed

+111
-37
lines changed

3 files changed

+111
-37
lines changed

pkg/pillar/hypervisor/kvm.go

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1472,7 +1472,7 @@ func (f *pciAssignmentsTemplateFiller) do(pciAssignments []pciDevice) error {
14721472
pciPTContext.Romfile = gopRomPath(devid)
14731473
if pciPTContext.Romfile == igdRomPath {
14741474
logrus.Infof("iGPU passthrough: no proprietary GOP ROM in %s for device %s, "+
1475-
"using bundled VfioIgdPkg ROM (no display output) for domain %s",
1475+
"using bundled VfioIgdPkg ROM (OS display works; no pre-OS UEFI framebuffer) for domain %s",
14761476
gopRomDir, devid, f.domainUUID)
14771477
} else {
14781478
logrus.Infof("iGPU passthrough: using proprietary GOP ROM %s for domain %s",
@@ -1582,8 +1582,10 @@ const igdRomPath = "/usr/lib/xen/boot/igd.rom"
15821582

15831583
// gopRomPath returns the path to a proprietary GOP ROM for the given PCI device ID
15841584
// (as read from sysfs, e.g. "0x3ea0") if one exists in gopRomDir, otherwise returns
1585-
// igdRomPath. A proprietary ROM enables physical display output; the bundled ROM
1586-
// enables passthrough without display but with correct ASLS/BDSM for all generations.
1585+
// igdRomPath. A proprietary ROM provides the Intel GOP driver which enables the UEFI
1586+
// framebuffer (pre-OS display: GRUB, bootloader, UEFI shell). The bundled ROM provides
1587+
// only IgdAssignmentDxe: ASLS/BDSM are set correctly so the guest OS display driver
1588+
// works, but there is no display output before the OS driver loads.
15871589
func gopRomPath(devid string) string {
15881590
name := strings.TrimPrefix(strings.ToLower(strings.TrimSpace(devid)), "0x")
15891591
for _, filename := range []string{name + ".rom", "0x" + name + ".rom"} {

pkg/xen-tools/Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
# Copyright (c) 2023-2026 Zededa, Inc.
44
# SPDX-License-Identifier: Apache-2.0
55

6-
FROM lfedge/eve-uefi:b3ef9ca37c99439c776673aeba83c52ea8b84626 AS uefi-build
6+
FROM lfedge/eve-uefi:f34ddf148f2ad94c1a9c669efcd28ceaf3cac685 AS uefi-build
77
FROM lfedge/eve-alpine:745ae9066273c73b0fd879c4ba4ff626a8392d04 AS runx-build
88
ENV BUILD_PKGS="mkinitfs gcc musl-dev e2fsprogs chrony agetty"
99
RUN eve-alpine-deploy.sh
Lines changed: 105 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,25 @@
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

1310
diff --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

Comments
 (0)