diff --git a/docs/INTEL-IGPU-PASSTHROUGH.md b/docs/INTEL-IGPU-PASSTHROUGH.md new file mode 100644 index 00000000000..6a7ed580bdd --- /dev/null +++ b/docs/INTEL-IGPU-PASSTHROUGH.md @@ -0,0 +1,298 @@ +# Intel iGPU Passthrough in EVE OS + +This document explains how Intel integrated GPU (iGPU) passthrough works in EVE OS, +what was wrong with the original approach, how it is implemented today, what works and +what does not, and what needs to be updated when Intel releases new GPU generations. + +--- + +## Background: what the iGPU needs from firmware + +Before the OS driver (i915 on Linux, or the Intel display driver on Windows) can +initialize the Intel iGPU in a VM, two things must be set up in the guest PCI config +space by firmware — either BIOS or UEFI — during the VM boot phase. + +### OpRegion — ASLS register (PCI config offset 0xFC) + +The OpRegion is an Intel-defined in-memory structure populated by the host platform +firmware. It contains the **Video BIOS Table (VBT)** which describes the physical display +topology: which ports exist (HDMI, DisplayPort, eDP), EDID overrides, hotplug +configuration, panel sequencing, and more. + +Without it, the i915 driver has no idea which physical connectors are wired up. DP/HDMI +detection and hotplug will not work. + +QEMU copies the host's OpRegion into the VM via the fw_cfg entry `etc/igd-opregion` when +`x-igd-opregion=on` is set on the vfio-pci device. Guest firmware must: + +1. Read this fw_cfg file +2. Allocate a reserved memory region below 4 GB (ACPI NVS, 4 KB aligned) +3. Copy the content into it +4. Write the 32-bit physical address into ASLS (PCI config offset 0xFC) of the iGPU + +### Stolen memory — BDSM register (PCI config offset 0x5C or 0xC0) + +The Intel iGPU reserves a region of RAM during POST for the Graphics Translation Table +(GTT). The base address of this stolen region is held in the BDSM register. The i915 +driver reads BDSM to locate it. + +If BDSM is zero or contains the host physical address (not a valid guest address), i915 +fails to initialize the GPU. + +QEMU writes the stolen memory size to fw_cfg as `etc/igd-bdsm-size` (8-byte little-endian +integer). Guest firmware must: + +1. Read this fw_cfg file to get the size +2. Allocate a 1 MB-aligned reserved memory region below 4 GB +3. Write the physical address into BDSM + +The register width changed with Intel Gen11: + +- **Gen6–Gen10** (Sandy Bridge through Comet Lake): BDSM is a **32-bit** register at + offset **0x5C** +- **Gen11+** (Ice Lake, Tiger Lake, Alder Lake, Raptor Lake, and later): BDSM is a + **64-bit** register at offset **0xC0** + +This distinction is critical and was the main bug in the original EVE implementation. + +--- + +## Why SeaBIOS / i440fx works + +SeaBIOS is a legacy BIOS. When it encounters a PCI option ROM (the VBIOS — the 64 KB +Video BIOS built into the IGD device), it executes it in 16-bit real mode. The VBIOS: + +1. Checks the device is at guest BDF `00:02.0` (hardcoded) +2. Reads the LPC/ISA bridge at `00:1f.0` to verify device IDs match real Intel hardware +3. Reads the GMCH register at `00:00.0` to find stolen memory size +4. Allocates stolen memory, writes address to BDSM +5. Initializes the framebuffer + +For this to work in a VM under i440fx: + +- The device must be at guest BDF `00:02.0` +- A fake LPC bridge must exist at `1f.0` with host device IDs copied in via `x-igd-lpc` +- The i440fx machine type has no permanent occupant at `1f.0`, so QEMU creates a + `vfio-pci-igd-lpc-bridge` device there + +**i440fx works because slot `1f.0` is free** and can host the fake LPC bridge. + +--- + +## Why q35/UEFI fails without special handling + +UEFI/OVMF in EVE has no CSM (Compatibility Support Module). The VBIOS never executes. +Nobody sets BDSM. Nobody allocates OpRegion memory. The OS driver fails to initialize. + +The q35 machine type permanently occupies `1f.0` with the ICH9 LPC controller. QEMU +explicitly refuses to enable the legacy VBIOS path when it finds a real device there +(`hw/vfio/igd.c`: "cannot support legacy mode due to existing devices at 1f.0", also +called "Sorry Q35" in comments). `x-igd-lpc` — the QEMU option that copies LPC bridge +device IDs for the VBIOS path — does nothing useful on q35/UEFI. + +The additional problem was in QEMU's `vfio_probe_igd_bar4_quirk()`: the code that writes +`etc/igd-bdsm-size` to fw_cfg and emulates BDSM/GMCH was placed *after* the BDF and LPC +bridge checks. On q35, the "Sorry Q35" path exits early before reaching that code, so the +fw_cfg entry is never written and BDSM is never emulated. + +--- + +## The correct approach: EFI Option ROM with IgdAssignmentDxe + +### VfioIgdPkg + +Upstream OVMF maintainers declined to accept IGD-specific code (TianoCore Bug #935). +The solution is a standalone EFI Option ROM delivered as `romfile=` on the vfio-pci +device. The project that implements this is +[VfioIgdPkg](https://github.com/tomitamoeko/VfioIgdPkg). + +VfioIgdPkg builds `igd.rom`, an EFI Option ROM containing: + +- **IgdAssignmentDxe** — sets up OpRegion and BDSM; this is the required component +- **PlatformGopPolicy** — implements the protocol needed by the proprietary Intel GOP + driver for pre-OS framebuffer; only needed if a proprietary GOP ROM is also loaded + +### How it works end to end + +1. EVE builds `igd.rom` from VfioIgdPkg as part of `pkg/uefi` and ships it in the image. +2. When an Intel iGPU is configured for passthrough, EVE's KVM hypervisor adds + `romfile=` to the vfio-pci device arguments and enables + `x-igd-opregion=on`. +3. The iGPU is placed at guest BDF `00:02.0` (required by VfioIgdPkg's BDSM allocation + path). +4. OVMF's PCI bus driver discovers the EFI ROM on the device (identified by EFI ROM + header, not the legacy `0x55 0xAA` signature) and loads `IgdAssignmentDxe.efi` as a + DXE driver. +5. `IgdAssignmentDxe` runs during the DXE phase: + - Reads `etc/igd-opregion` from fw_cfg, allocates ACPI NVS memory below 4 GB, copies + the OpRegion content, and writes the guest physical address to ASLS (0xFC). + - Registers a PciIo notification callback; when the iGPU PciIo protocol appears, it + reads the GMS field from the (emulated) GMCH register, allocates 1 MB-aligned + reserved memory for stolen memory, and writes the guest physical address to BDSM + (0x5C for Gen6–Gen10, 0xC0 for Gen11+). +6. The OS driver (i915 / Intel display driver) initializes successfully. + +### Changes to QEMU's vfio-igd quirk + +The QEMU patches in `pkg/xen-tools` (patches 08–11) rework `hw/vfio/igd.c`: + +**Patch 08 — igd_gen() backport**: upstream's `igd_gen()` returns correct generation +numbers for Gen7 through Gen12 (Haswell through Raptor Lake). The old function returned +8 for all unrecognised device IDs, making generation-specific checks (BDSM register +offset, GMS encoding) ineffective on Gen9+ hardware. + +**Patch 09 — main rework of `vfio_probe_igd_bar4_quirk()`**: + +- **GMCH emulation, `etc/igd-bdsm-size` fw_cfg write, and BDSM emulation are moved + before the BDF/LPC bridge checks.** On q35 the "Sorry Q35" path exits early; without + this move, those registers are never set and `IgdAssignmentDxe` cannot do its job. +- **BDSM is emulated at the correct PCI config offset**: 0x5C (32-bit) for Gen6–Gen10, + 0xC0 (64-bit) for Gen11+. Initialized to zero so `IgdAssignmentDxe`'s idempotency + guard (skip if BDSM ≠ 0) is not falsely triggered by the host physical address. +- **GMS is preserved** in the emulated GMCH register. The guest driver reads GMS to + determine stolen memory size; zeroing it caused the Windows driver to crash (no + stolen memory available). Upstream QEMU does not zero GMS. +- **Stale GTT entries are cleared** before the BDF check. After host POST the GTT + contains entries pointing to host physical addresses, causing IOMMU faults. +- **GMS encoding for Gen9+ Atom SKUs** (codes 0xf0–0xff, 4 MB granularity) is fixed to + match the Linux kernel's `i915_gem_stolen.c`. +- The generation check is fixed to accept any recognized generation (`gen >= 0`) instead + of the old hard-coded `gen == 6 || gen == 8` which silently blocked Gen9–Gen12 devices. + +**Patch 10 — BAR0 BDSM MMIO mirror** (backported from upstream): the GPU reads BDSM +through BAR0 MMIO at offset `0x1080C0` as well as PCI config space. Without this +quirk, the MMIO read returns the host physical address while PCI config returns the +emulated guest PA. The driver sees conflicting values and crashes. This was the +critical missing piece for Tiger Lake and other Gen11+ devices. + +Based on upstream QEMU commits: +- [`11b5ce95`](https://github.com/qemu/qemu/commit/11b5ce95beecfd51d1b17858d23fe9cbb0b5783f) + "vfio/igd: add new bar0 quirk to emulate BDSM mirror" by Corvin Köhne +- [`f926baa0`](https://github.com/qemu/qemu/commit/f926baa03b7babb8291ea4c1cbeadaf224977dae) + "vfio/igd: emulate BDSM in mmio bar0 for gen 6-10 devices" by Tomita Moeko + +--- + +## What works and what does not + +| Feature | Status | Notes | +| ------- | ------ | ----- | +| i915 / Intel display driver initialization | ✓ Works | OpRegion + BDSM set correctly | +| DP / HDMI output in the guest OS | ✓ Works | VBT from OpRegion describes connectors | +| Hotplug detection (DP, HDMI) | ✓ Works | HPD interrupts forwarded via OpRegion | +| Display connector topology | ✓ Works | | +| Multiple monitors | ✓ Works | Driver-managed | +| Windows Intel display driver (no Code 43) | ✓ Works | | +| UEFI framebuffer during firmware phase | ✗ Not available | Requires proprietary Intel GOP driver | +| Pre-OS graphical output | ✗ Not available | Same reason | +| Gen12+ (Meteor Lake, Arrow Lake, Lunar Lake) OpRegion | ✓ Works | BDSM quirk not needed (LMEMBAR) | + +Pre-OS display requires `IntelGopDriver.efi`, the proprietary Intel GOP driver from the +host platform firmware. EVE's design does not depend on pre-OS display. If pre-OS display +is needed in a future use case, a proprietary GOP ROM can be placed alongside `igd.rom` +and loaded as a second option ROM on the device. + +--- + +## Supported Intel GPU generations + +VfioIgdPkg supports the following generations: + +| igd_gen() | BDSM register | Microarchitectures | PCI Device ID prefix | +| --------- | ------------- | ------------------ | -------------------- | +| 6 | 32-bit 0x5C | Sandy Bridge, Ivy Bridge | `0x01xx` | +| 7 | 32-bit 0x5C | Haswell, Valleyview/Bay Trail | `0x04xx`, `0x0axx`, `0x0cxx`, `0x0dxx`, `0x0fxx` | +| 8 | 32-bit 0x5C | Broadwell, Cherryview | `0x16xx`, `0x22xx` | +| 9 | 32-bit 0x5C | Skylake, Kaby Lake, Coffee Lake, Comet Lake, Gemini Lake, Broxton | `0x19xx`, `0x59xx`, `0x3exx`, `0x9Bxx`, `0x31xx`, `0x_a84` | +| 11 | 64-bit 0xC0 | Ice Lake, Elkhart Lake, Jasper Lake | `0x8Axx`, `0x45xx`, `0x4Exx` | +| 12 | 64-bit 0xC0 | Tiger Lake, Rocket Lake, Alder Lake, Raptor Lake | `0x9Axx`, `0x4Cxx`, `0x46xx`, `0xA7xx` | +| -1 (unknown) | No BDSM (LMEMBAR) | Meteor Lake (`0x7Dxx`), Arrow Lake, Lunar Lake (`0x64xx`), Panther Lake | not yet in `igd_gen()` | + +### Meteor Lake and later (no BDSM) + +Starting from Meteor Lake, Intel moved stolen memory access to LMEMBAR (MMIO BAR2) +and **removed the BDSM register** from PCI config space. For these devices: + +- `IgdAssignmentDxe` recognises these devices (they are in VfioIgdPkg's device table + with `GetStolenSize = NULL` and `&NullPrivate`), so it **skips stolen memory setup + entirely** and only sets up OpRegion (ASLS). It never reads `etc/igd-bdsm-size` — + VfioIgdPkg calculates stolen size from GMS internally, so a missing fw_cfg entry is + irrelevant. +- OpRegion passthrough works via `x-igd-opregion=on`, which is independent of + `igd_gen()` and the vfio-igd BAR4 quirk. EVE's `kvm.go` always enables this for + Intel iGPUs. +- The QEMU `igd_gen()` function does not yet recognise Meteor Lake+ device IDs + (returns -1), so GMCH/BDSM emulation and the BAR0 mirror are skipped. This is + correct — there is no BDSM to emulate. +- **Meteor Lake+ may already work** with no QEMU changes needed: OpRegion is handled, + stolen memory is accessed through LMEMBAR (BAR2) which VFIO passes through as a + normal BAR, and VfioIgdPkg skips BDSM setup. The only thing to verify is that the + guest driver's LMEMBAR access works correctly through VFIO BAR passthrough. + +--- + +## Updating EVE for a new Intel iGPU generation + +When Intel releases a new GPU generation, check the following in order: + +### 1. VfioIgdPkg device table + +The primary check: does the new device ID appear in VfioIgdPkg's device table? + +- Repository: +- File: `IgdAssignmentDxe/IgdPrivate.c` — look for the `IgdIds` array +- If the new Device ID is missing, open an issue or PR against VfioIgdPkg +- After a new VfioIgdPkg commit is available, update `VFIOIGD_COMMIT` in + `pkg/uefi/Dockerfile` and rebuild + +### 2. BDSM register location + +Check if the new generation uses a new BDSM register offset or width: + +- Intel publishes graphics PRM (Programmer's Reference Manual) at + +- Look for "Base Data of Stolen Memory" in the PCI config space register map +- If the offset or width changed, `IgdAssignmentDxe/IgdAssignment.c` in VfioIgdPkg needs + a new generation handler, and the QEMU patch in `pkg/xen-tools` may also need updating + +### 3. QEMU vfio-igd quirk + +Check `hw/vfio/igd.c` in the upstream QEMU repository: + +- The `igd_gen()` function maps PCI Device IDs to generations — new IDs must be added +- The `GetStolenSize()` variant for the new generation must handle any GMS encoding + changes (check Linux kernel `drivers/gpu/drm/i915/gem/i915_gem_stolen.c` for reference) +- If upstream QEMU already has support, the patch in `pkg/xen-tools` should be rebased + onto the newer xen-qemu base + +### 4. EDK2 / OVMF compatibility + +- VfioIgdPkg tracks EDK2 stable releases; check VfioIgdPkg's `VfioIgdPkg.dsc` for any + new EDK2 library dependencies +- Update `EDK_VERSION` and `EDK_COMMIT` in `pkg/uefi/Dockerfile` if needed +- Regenerate edk2 patches in `pkg/uefi/edk2-patches/edk2-stable/` against the + new EDK2 base (use `git apply --ignore-whitespace` for CRLF-tolerant patch application, + and `git format-patch` from within an actual edk2 checkout to preserve CRLF in context + lines) + +### 5. Stolen memory size encoding + +If a new generation introduces new GMS encoding codes in the GMCH register, update both: + +- VfioIgdPkg's `IgdAssignmentDxe/IgdPrivate.c` (`GetStolenSize()`) +- The QEMU patch (`pkg/xen-tools/patches-4.19.0/x86_64/09-vfio-igd-q35-uefi-bdsm-opregion.patch`) + — specifically the GMS decoding block before the fw_cfg write + +--- + +## Component map + +| Component | File | Role | +| --------- | ---- | ---- | +| UEFI Option ROM build | `pkg/uefi/Dockerfile`, `pkg/uefi/build.sh` | Builds `igd.rom` from VfioIgdPkg | +| EFI Option ROM (runtime) | `pkg/xen-tools/` ships `igd.rom` to host rootfs | Loaded by OVMF; runs `IgdAssignmentDxe` | +| KVM hypervisor integration | `pkg/pillar/hypervisor/kvm.go` | Detects iGPU, sets `romfile=`, BDF, opregion | +| QEMU igd_gen() backport | `pkg/xen-tools/.../08-vfio-igd-backport-igd-gen.patch` | Gen7–Gen12 device ID detection | +| QEMU vfio-igd rework | `pkg/xen-tools/.../09-vfio-igd-q35-uefi-bdsm-opregion.patch` | GMCH/BDSM/fw_cfg/GTT for q35/UEFI | +| QEMU BAR0 BDSM mirror | `pkg/xen-tools/.../10-vfio-igd-bar0-bdsm-mirror.patch` | Intercepts BAR0 MMIO BDSM reads | +| EDK2 base | `pkg/uefi/edk2-patches/edk2-stable*/` | EVE-specific patches on top of EDK2 | diff --git a/pkg/pillar/Dockerfile b/pkg/pillar/Dockerfile index 454f785a155..1d30f2eec24 100644 --- a/pkg/pillar/Dockerfile +++ b/pkg/pillar/Dockerfile @@ -10,7 +10,7 @@ ARG BUILD_PKGS_BASE="git gcc linux-headers libc-dev make linux-pam-dev m4 findut # we use the same image in several places ARG EVE_ALPINE_IMAGE=lfedge/eve-alpine:745ae9066273c73b0fd879c4ba4ff626a8392d04 -FROM lfedge/eve-uefi:b3ef9ca37c99439c776673aeba83c52ea8b84626 AS uefi-build +FROM lfedge/eve-uefi:417cf0c3acf434fb0f775e8a588ae7b6e3523d6d AS uefi-build FROM lfedge/eve-dom0-ztools:d19fc83dfbd01562eba914a83d571f7315429052 AS zfs RUN mkdir /out # copy zfs-related files from dom0-ztools using prepared list of files @@ -167,7 +167,6 @@ WORKDIR / RUN mkdir -p /out/usr/lib/xen/boot COPY --from=uefi-build /OVMF_VARS.fd /out/usr/lib/xen/boot/OVMF_VARS.fd - COPY --from=zfs /out /out COPY --from=fscrypt /opt/zededa/bin /out/opt/zededa/bin COPY --from=gpttools / /out diff --git a/pkg/pillar/hypervisor/kvm.go b/pkg/pillar/hypervisor/kvm.go index 92c93f7700e..181fec7df69 100644 --- a/pkg/pillar/hypervisor/kvm.go +++ b/pkg/pillar/hypervisor/kvm.go @@ -274,12 +274,21 @@ const qemuGlobalConfTemplate = `# This file is automatically generated by domain driver = "virtio-gpu-pci" {{- end }} {{- end }} +{{- if .HasIntelIGPU }} +[device "pci.2"] + driver = "pcie-root-port" + port = "12" + chassis = "2" + bus = "pcie.0" + addr = "0x1b" +{{- else }} [device "pci.2"] driver = "pcie-root-port" port = "12" chassis = "2" bus = "pcie.0" addr = "0x2" +{{- end }} [device "usb"] driver = "qemu-xhci" @@ -434,6 +443,9 @@ const qemuPCIPassthruTemplate = ` {{- if .Xopregion }} x-igd-opregion = "on" {{- end}} +{{- if .Romfile }} + romfile = "{{.Romfile}}" +{{- end}} ` const qemuSerialTemplate = ` @@ -492,12 +504,13 @@ const qemuSwtpmTemplate = ` tpmdev = "tpm0" ` -// Context for qemuGlobalConfTemplate. +// Context for qemuGlobalConfContext. type tQemuGlobalConfContext struct { Machine string VirtualizationMode string BootLoaderSettingsFile string BootOrder string // Boot order: "usb" (prioritize USB), "nousb" (deprioritize USB), or "" (default) + HasIntelIGPU bool // true when Intel iGPU is in the passthrough list; moves USB root port to slot 0x1b types.DomainConfig types.DomainStatus } @@ -513,6 +526,7 @@ type tQemuPCIPassthruContext struct { PciShortAddr string Xvga bool Xopregion bool + Romfile string // non-empty path to GOP ROM (e.g. /persist/gop/3ea0.rom); omitted if empty Bus string Addr string } @@ -1420,6 +1434,7 @@ func multifunctionDevGroup(pcis []pciDevice) multifunctionDevs { type pciAssignmentsTemplateFiller struct { multifunctionDevices multifunctionDevs file io.Writer + domainUUID string } func (f *pciAssignmentsTemplateFiller) pciEBridge(pciID int, pciWOFunction string) error { @@ -1443,17 +1458,48 @@ func (f *pciAssignmentsTemplateFiller) do(pciAssignments []pciDevice) error { Xvga: pa.isVGA(), Xopregion: false, } - if vendor, err := pa.vid(); err == nil { - // check for Intel vendor - if vendor == "0x8086" { - if pciPTContext.Xvga { - // we set opregion for Intel vga - // https://github.com/qemu/qemu/blob/stable-5.0/docs/igd-assign.txt#L91-L96 - pciPTContext.Xopregion = true + + isIntelIGPU := false + if vendor, err := pa.vid(); err == nil && vendor == "0x8086" { + if pciPTContext.Xvga { + // Enable OpRegion passthrough for Intel iGPU — writes etc/igd-opregion to fw_cfg. + // https://github.com/qemu/qemu/blob/stable-5.0/docs/igd-assign.txt#L91-L96 + pciPTContext.Xopregion = true + isIntelIGPU = true + logrus.Infof("iGPU passthrough: detected Intel GPU at host PCI %s for domain %s", + pa.ioBundle.PciLong, f.domainUUID) + if devid, err := pa.devid(); err == nil { + pciPTContext.Romfile = gopRomPath(devid) + if pciPTContext.Romfile == igdRomPath { + logrus.Infof("iGPU passthrough: no proprietary GOP ROM in %s for device %s, "+ + "using bundled VfioIgdPkg ROM (OS display works; no pre-OS UEFI framebuffer) for domain %s", + gopRomDir, devid, f.domainUUID) + } else { + logrus.Infof("iGPU passthrough: using proprietary GOP ROM %s for domain %s", + pciPTContext.Romfile, f.domainUUID) + } + } else { + logrus.Warnf("iGPU passthrough: could not read device ID for %s (domain %s): %v", + pa.ioBundle.PciLong, f.domainUUID, err) + pciPTContext.Romfile = igdRomPath } } } + if isIntelIGPU { + // Intel iGPU must appear at guest BDF 00:02.0 for VBIOS/GOP ROM initialization. + // Place directly on the root bus — no pcie-root-port wrapper. + // The USB root port was moved from 0x2 to 0x1b in qemuGlobalConfTemplate. + logrus.Infof("iGPU passthrough: placing device %s at guest BDF 00:02.0 for domain %s", + pa.ioBundle.PciLong, f.domainUUID) + pciPTContext.Bus = "pcie.0" + pciPTContext.Addr = "0x2" + if err := tQemuPCIPassthru.Execute(f.file, pciPTContext); err != nil { + return logError("can't write iGPU passthrough to config file (%v)", err) + } + continue + } + pciLongWoFunc, err := pa.pciLongWOFunction() if err != nil { logrus.Warnf("retrieving pci address without function failed: %v", err) @@ -1524,6 +1570,55 @@ func (f *virtNetworkTemplateFiller) do(virtualNetworks []virtualNetwork, return nil } +// gopRomDir is where proprietary Intel GOP Option ROMs can be placed for display output. +// ROMs are named by PCI device ID, e.g. /persist/gop/3ea0.rom for device 0x3ea0. +// The 0x-prefixed form (0x3ea0.rom) is also accepted as a fallback. +const gopRomDir = "/persist/gop" + +// igdRomPath is the bundled open-source IGD Option ROM built from VfioIgdPkg. +// It provides IgdAssignmentDxe which sets ASLS and BDSM (including Gen11+ 64-bit +// BDSM at PCI config 0xC0) without requiring a proprietary Intel GOP driver. +const igdRomPath = "/usr/lib/xen/boot/igd.rom" + +// gopRomPath returns the path to a proprietary GOP ROM for the given PCI device ID +// (as read from sysfs, e.g. "0x3ea0") if one exists in gopRomDir, otherwise returns +// igdRomPath. A proprietary ROM provides the Intel GOP driver which enables the UEFI +// framebuffer (pre-OS display: GRUB, bootloader, UEFI shell). The bundled ROM provides +// only IgdAssignmentDxe: ASLS/BDSM are set correctly so the guest OS display driver +// works, but there is no display output before the OS driver loads. +func gopRomPath(devid string) string { + name := strings.TrimPrefix(strings.ToLower(strings.TrimSpace(devid)), "0x") + for _, filename := range []string{name + ".rom", "0x" + name + ".rom"} { + path := filepath.Join(gopRomDir, filename) + if _, err := os.Stat(path); err == nil { + return path + } + } + return igdRomPath +} + +// detectIntelIGPU returns true if any adapter in the passthrough list is an Intel VGA device. +func detectIntelIGPU(adapters []types.IoAdapter, aa *types.AssignableAdapters) bool { + if aa == nil { + return false + } + for _, adapter := range adapters { + for _, ib := range aa.LookupIoBundleAny(adapter.Name) { + if ib == nil || ib.PciLong == "" || ib.UsbAddr != "" { + continue + } + dev := pciDevice{ioBundle: *ib} + if !dev.isVGA() { + continue + } + if vendor, err := dev.vid(); err == nil && vendor == "0x8086" { + return true + } + } + } + return false +} + // CreateDomConfig creates a domain config (a qemu config file, // typically named something like xen-%d.cfg) func (ctx KvmContext) CreateDomConfig(domainName string, @@ -1548,12 +1643,14 @@ func (ctx KvmContext) CreateDomConfig(domainName string, // 4. Default (BOOT_ORDER_UNSPECIFIED) - no boot order modification // By the time we get here, config.BootOrder has the final resolved value. bootOrder := bootOrderToFwCfgString(config.BootOrder) + hasIntelIGPU := detectIntelIGPU(config.IoAdapterList, aa) qemuConfContext := tQemuGlobalConfContext{ Machine: ctx.devicemodel, VirtualizationMode: virtualizationMode, BootLoaderSettingsFile: bootLoaderSettingsFile, BootOrder: bootOrder, + HasIntelIGPU: hasIntelIGPU, DomainConfig: config, DomainStatus: status, } @@ -1702,6 +1799,7 @@ func (ctx KvmContext) CreateDomConfig(domainName string, pciAssignmentsFiller := pciAssignmentsTemplateFiller{ multifunctionDevices: multifunctionDevices, file: file, + domainUUID: config.UUIDandVersion.UUID.String(), } err = pciAssignmentsFiller.do(pciAssignments) if err != nil { diff --git a/pkg/uefi/Dockerfile b/pkg/uefi/Dockerfile index d407e997d41..a1c419ca8ae 100644 --- a/pkg/uefi/Dockerfile +++ b/pkg/uefi/Dockerfile @@ -29,8 +29,8 @@ COPY rpi /rpi FROM build AS build-amd64-versions -ENV EDK_VERSION edk2-stable202408.01 -ENV EDK_COMMIT 4dfdca63a93497203f197ec98ba20e2327e4afe4 +ENV EDK_VERSION edk2-stable202508.01 +ENV EDK_COMMIT 3d244c3b364bd4e21261380662186d064659161c FROM build-${TARGETARCH}-versions AS build-edk2 @@ -45,6 +45,12 @@ RUN set -e ; [ ! -d /edk2 ] || [ ! -d /edk2-patches/${EDK_VERSION} ] || \ FROM build-edk2 AS build-amd64 +# VfioIgdPkg: open-source EFI Option ROM for Intel iGPU passthrough. +# Builds IgdAssignmentDxe which sets ASLS/BDSM registers correctly for +# Gen11+ devices (64-bit BDSM at 0xC0) — not handled by classic IgdAssignmentDxe. +ENV VFIOIGD_COMMIT 348860da70ca3a9ed6c1d95c30a97c757f54336b +ADD --keep-git-dir=true https://github.com/tomitamoeko/VfioIgdPkg.git#${VFIOIGD_COMMIT} /edk2/VfioIgdPkg + FROM build-edk2 AS build-arm64 FROM build AS build-riscv64 @@ -63,7 +69,8 @@ COPY build.sh /edk2/ RUN ./build.sh # create an out dir for all the artifacts -RUN rm -rf /out && mkdir /out && cp /edk2/OVMF*.fd /out +RUN rm -rf /out && mkdir /out && cp /edk2/OVMF*.fd /out && \ + [ -f /edk2/igd.rom ] && cp /edk2/igd.rom /out/ || true # some architecture specific cases. There probably is a cleaner dockerfile-native way to do this. RUN case $(uname -m) in \ diff --git a/pkg/uefi/build.sh b/pkg/uefi/build.sh index d7a60d05f87..1eef5085efb 100755 --- a/pkg/uefi/build.sh +++ b/pkg/uefi/build.sh @@ -2,7 +2,7 @@ TARGET=RELEASE -make -C BaseTools +make -C BaseTools -j "$(nproc)" OVMF_COMMON_FLAGS="-DNETWORK_TLS_ENABLE" OVMF_COMMON_FLAGS+=" -DSECURE_BOOT_ENABLE=TRUE" OVMF_COMMON_FLAGS+=" -DTPM2_CONFIG_ENABLE=TRUE" @@ -21,18 +21,24 @@ case $(uname -m) in cp /opensbi/build/platform/generic/firmware/fw_payload.bin OVMF_VARS.fd cp /opensbi/build/platform/generic/firmware/fw_jump.bin OVMF.fd ;; - aarch64) build -b ${TARGET} -t GCC5 -a AARCH64 -p ArmVirtPkg/ArmVirtQemu.dsc -D TPM2_ENABLE=TRUE -D TPM2_CONFIG_ENABLE=TRUE + aarch64) build -b ${TARGET} -t GCC5 -a AARCH64 -n "$(nproc)" -p ArmVirtPkg/ArmVirtQemu.dsc -D TPM2_ENABLE=TRUE -D TPM2_CONFIG_ENABLE=TRUE cp Build/ArmVirtQemu-AARCH64/${TARGET}_GCC5/FV/QEMU_EFI.fd OVMF.fd cp Build/ArmVirtQemu-AARCH64/${TARGET}_GCC5/FV/QEMU_VARS.fd OVMF_VARS.fd # now let's build PVH UEFI kernel - make -C BaseTools/Source/C - build -b ${TARGET} -t GCC5 -a AARCH64 -p ArmVirtPkg/ArmVirtXen.dsc + make -C BaseTools/Source/C -j "$(nproc)" + build -b ${TARGET} -t GCC5 -a AARCH64 -n "$(nproc)" -p ArmVirtPkg/ArmVirtXen.dsc cp Build/ArmVirtXen-AARCH64/${TARGET}_*/FV/XEN_EFI.fd OVMF_PVH.fd ;; - x86_64) build -b ${TARGET} -t GCC5 -a X64 -p OvmfPkg/OvmfPkgX64.dsc ${OVMF_COMMON_FLAGS} + x86_64) build -b ${TARGET} -t GCC5 -a X64 -n "$(nproc)" -p OvmfPkg/OvmfPkgX64.dsc ${OVMF_COMMON_FLAGS} cp Build/OvmfX64/${TARGET}_*/FV/OVMF*.fd . - build -b ${TARGET} -t GCC5 -a X64 -p OvmfPkg/OvmfXen.dsc + build -b ${TARGET} -t GCC5 -a X64 -n "$(nproc)" -p OvmfPkg/OvmfXen.dsc cp Build/OvmfXen/${TARGET}_*/FV/OVMF.fd OVMF_PVH.fd + # Build VfioIgdPkg open-source IGD Option ROM (IgdAssignmentDxe only). + # Handles Gen11+ 64-bit BDSM at PCI config 0xC0, unlike classic IgdAssignmentDxe. + build -b ${TARGET} -t GCC5 -a X64 -n "$(nproc)" -p VfioIgdPkg/VfioIgdPkg.dsc + EfiRom -f 0x8086 -i 0xffff \ + -e Build/VfioIgdPkg/${TARGET}_GCC5/X64/IgdAssignmentDxe.efi \ + -o igd.rom ;; *) echo "Unsupported architecture $(uname). Bailing." exit 1 diff --git a/pkg/uefi/edk2-patches/edk2-stable202508.01/0000-Add-Xen-spoofing-in-XenPlatformPei.patch b/pkg/uefi/edk2-patches/edk2-stable202508.01/0000-Add-Xen-spoofing-in-XenPlatformPei.patch new file mode 100644 index 00000000000..3b9abc72aa0 --- /dev/null +++ b/pkg/uefi/edk2-patches/edk2-stable202508.01/0000-Add-Xen-spoofing-in-XenPlatformPei.patch @@ -0,0 +1,27 @@ +From 91461d1da3417069df76a231138fb310c4a24549 Mon Sep 17 00:00:00 2001 +From: Shahriyar Jalayeri +Date: Mon, 14 Oct 2024 16:22:11 +0300 +Subject: [PATCH 1/4] Add Xen spoofing in XenPlatformPei + +Signed-off-by: Shahriyar Jalayeri +--- + OvmfPkg/XenPlatformPei/Xen.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/OvmfPkg/XenPlatformPei/Xen.c b/OvmfPkg/XenPlatformPei/Xen.c +index a54fd55c70..09cc3bf02d 100644 +--- a/OvmfPkg/XenPlatformPei/Xen.c ++++ b/OvmfPkg/XenPlatformPei/Xen.c +@@ -240,6 +240,9 @@ XenDetect ( + if (!AsciiStrCmp ((CHAR8 *)Signature, "XenVMMXenVMM")) { + return TRUE; + } ++ if (!AsciiStrCmp ((CHAR8 *)Signature, "ZenZenZenZen")) { ++ return TRUE; ++ } + } + + mXenLeaf = 0; +-- +2.43.0 + diff --git a/pkg/uefi/edk2-patches/edk2-stable202508.01/0001-OvmfPkg-Add-EveBootOrderLib.patch b/pkg/uefi/edk2-patches/edk2-stable202508.01/0001-OvmfPkg-Add-EveBootOrderLib.patch new file mode 100644 index 00000000000..701c93b6c46 --- /dev/null +++ b/pkg/uefi/edk2-patches/edk2-stable202508.01/0001-OvmfPkg-Add-EveBootOrderLib.patch @@ -0,0 +1,379 @@ +From 17914348290544cb3a6a447de7d8c013aa9f6feb Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Ren=C3=AA=20de=20Souza=20Pinto?= +Date: Tue, 20 May 2025 17:37:24 +0200 +Subject: [PATCH 2/4] OvmfPkg: Add EveBootOrderLib +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This commit introduces the EveBootOrderLib. This library aims to allow +EVE-OS change the boot order of Virtual Machines running OVMF. For now a +partial implementation is provided, where USB devices are prioritized in +the boot order list. + +Signed-off-by: Renê de Souza Pinto +--- + OvmfPkg/Include/Library/EveBootOrderLib.h | 46 +++++ + .../Library/EveBootOrderLib/EveBootOrderLib.c | 159 ++++++++++++++++++ + .../EveBootOrderLib/EveBootOrderLib.inf | 48 ++++++ + .../PlatformBootManagerLib/BdsPlatform.c | 1 + + .../PlatformBootManagerLib/BdsPlatform.h | 1 + + .../PlatformBootManagerLib.inf | 1 + + OvmfPkg/OvmfPkg.dec | 5 + + OvmfPkg/OvmfPkgX64.dsc | 1 + + OvmfPkg/OvmfXen.dsc | 1 + + 9 files changed, 263 insertions(+) + create mode 100644 OvmfPkg/Include/Library/EveBootOrderLib.h + create mode 100644 OvmfPkg/Library/EveBootOrderLib/EveBootOrderLib.c + create mode 100644 OvmfPkg/Library/EveBootOrderLib/EveBootOrderLib.inf + +diff --git a/OvmfPkg/Include/Library/EveBootOrderLib.h b/OvmfPkg/Include/Library/EveBootOrderLib.h +new file mode 100644 +index 0000000000..78bf4730f5 +--- /dev/null ++++ b/OvmfPkg/Include/Library/EveBootOrderLib.h +@@ -0,0 +1,46 @@ ++/** @file ++ Rewrite the BootOrder NvVar based on EVE-OS "opt/eve.bootorder" fw_cfg file -- ++ include file. ++ ++ Copyright (C) 2012-2014, Red Hat, Inc. ++ Copyright (C) 2025 Zededa, Inc. ++ ++ SPDX-License-Identifier: BSD-2-Clause-Patent ++**/ ++ ++#ifndef __EVE_BOOT_ORDER_LIB_H__ ++#define __EVE_BOOT_ORDER_LIB_H__ ++ ++#include ++#include ++ ++/** ++ ++ Attempt to retrieve the "opt/eve.bootorder" fw_cfg file from QEMU. In ++ case the file is found, set the boot order based on configuration ++ retrieved from QEMU for EVE-OS. ++ ++ ++ @retval RETURN_SUCCESS The "opt/eve.bootorder" fw_cfg file has been ++ parsed, and the referenced device-subtrees ++ have been connected. ++ ++ @retval RETURN_UNSUPPORTED QEMU's fw_cfg is not supported. ++ ++ @retval RETURN_NOT_FOUND Empty or nonexistent "opt/eve.bootorder" fw_cfg ++ file. ++ ++ @retval RETURN_INVALID_PARAMETER Parse error in the "opt/eve.bootorder" fw_cfg file. ++ ++ @retval RETURN_OUT_OF_RESOURCES Memory allocation failed. ++ ++ @return Error statuses propagated from underlying ++ functions. ++**/ ++RETURN_STATUS ++EFIAPI ++SetBootOrderFromEve ( ++ VOID ++ ); ++ ++#endif +diff --git a/OvmfPkg/Library/EveBootOrderLib/EveBootOrderLib.c b/OvmfPkg/Library/EveBootOrderLib/EveBootOrderLib.c +new file mode 100644 +index 0000000000..33b37f86a4 +--- /dev/null ++++ b/OvmfPkg/Library/EveBootOrderLib/EveBootOrderLib.c +@@ -0,0 +1,159 @@ ++/** @file ++ Rewrite the BootOrder NvVar based on EVE-OS "opt/eve.bootorder" fw_cfg file. ++ ++ Copyright (C) 2012 - 2014, Red Hat, Inc. ++ Copyright (c) 2013 - 2016, Intel Corporation. All rights reserved.
++ Copyright (C) 2025 Zededa, Inc. ++ ++ SPDX-License-Identifier: BSD-2-Clause-Patent ++**/ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/** ++ A simple array of Boot Option ID's. ++**/ ++typedef struct { ++ UINT16 *Data; ++ UINTN Allocated; ++ UINTN Produced; ++} BOOT_ORDER; ++ ++ ++/** ++ Check if a DevicePath is an USB Device ++**/ ++STATIC ++ BOOLEAN ++IsUSBDevice ( ++ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath ++ ) ++{ ++ EFI_DEVICE_PATH_PROTOCOL *Node; ++ ++ for (Node = DevicePath; !IsDevicePathEnd(Node); Node = NextDevicePathNode(Node)) { ++ if (DevicePathType(Node) == MESSAGING_DEVICE_PATH && ++ ((DevicePathSubType(Node) == MSG_USB_DP || ++ DevicePathSubType(Node) == MSG_USB_CLASS_DP))) { ++ return TRUE; ++ } ++ } ++ ++ return FALSE; ++} ++ ++/** ++ ++ Attempt to retrieve the "opt/eve.bootorder" fw_cfg file from QEMU. In ++ case the file is found, set the boot order based on configuration ++ retrieved from QEMU for EVE-OS. ++ ++ ++ @retval RETURN_SUCCESS The "opt/eve.bootorder" fw_cfg file has been ++ parsed, and the referenced device-subtrees ++ have been connected. ++ ++ @retval RETURN_UNSUPPORTED QEMU's fw_cfg is not supported. ++ ++ @retval RETURN_NOT_FOUND Empty or nonexistent "opt/eve.bootorder" fw_cfg ++ file. ++ ++ @retval RETURN_INVALID_PARAMETER Parse error in the "opt/eve.bootorder" fw_cfg file. ++ ++ @retval RETURN_OUT_OF_RESOURCES Memory allocation failed. ++ ++ @return Error statuses propagated from underlying ++ functions. ++**/ ++RETURN_STATUS ++EFIAPI ++SetBootOrderFromEve ( ++ VOID ++ ) ++{ ++ RETURN_STATUS Status; ++ BOOT_ORDER BootOrder; ++ EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions; ++ UINTN BootOptionCount; ++ UINT16 BootOptionAux; ++ UINT16 UsbPos; ++ ++ DEBUG ((DEBUG_ERROR, "%a: Force prioritize USB devices for Boot\n", __FUNCTION__)); ++ ++ // Load boot options ++ BootOptions = EfiBootManagerGetLoadOptions ( ++ &BootOptionCount, LoadOptionTypeBoot ++ ); ++ if (BootOptions == NULL) { ++ return RETURN_NOT_FOUND; ++ } ++ ++ // Create an array for boot order ++ BootOrder.Produced = BootOptionCount; ++ BootOrder.Allocated = BootOptionCount; ++ BootOrder.Data = AllocatePool ( ++ BootOrder.Allocated * sizeof (*BootOrder.Data) ++ ); ++ if (BootOrder.Data == NULL) { ++ Status = RETURN_OUT_OF_RESOURCES; ++ goto ErrorFreeBootOptions; ++ } ++ // Store the current boot sequence (indexes) ++ for (UINTN Index = 0; Index < BootOptionCount; Index++) { ++ BootOrder.Data[Index] = BootOptions[Index].OptionNumber; ++ } ++ ++ // TODO: This is a partial implementation, for now it will only ++ // prioritize USB devices in the boot list. ++ // Search for USB devices and move them to the top of the list ++ UsbPos = 0; ++ for (UINTN Index = 0; Index < BootOptionCount; Index++) { ++ if (IsUSBDevice(BootOptions[Index].FilePath)) { ++ BootOptionAux = BootOrder.Data[UsbPos]; ++ BootOrder.Data[UsbPos] = BootOrder.Data[Index]; ++ BootOrder.Data[Index] = BootOptionAux; ++ UsbPos++; ++ } ++ } ++ ++ // ++ // See Table 10 in the UEFI Spec 2.3.1 with Errata C for the required ++ // attributes. ++ // ++ Status = gRT->SetVariable ( ++ L"BootOrder", ++ &gEfiGlobalVariableGuid, ++ EFI_VARIABLE_NON_VOLATILE | ++ EFI_VARIABLE_BOOTSERVICE_ACCESS | ++ EFI_VARIABLE_RUNTIME_ACCESS, ++ BootOrder.Produced * sizeof (*BootOrder.Data), ++ BootOrder.Data ++ ); ++ if (EFI_ERROR (Status)) { ++ DEBUG ((DEBUG_ERROR, "%a: setting BootOrder: %r\n", __FUNCTION__, ++ Status)); ++ goto ErrorFreeBootOrder; ++ } ++ ++ DEBUG ((DEBUG_INFO, "%a: setting BootOrder: success\n", __FUNCTION__)); ++ ++ErrorFreeBootOrder: ++ FreePool (BootOrder.Data); ++ ++ErrorFreeBootOptions: ++ EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount); ++ ++ return Status; ++} +diff --git a/OvmfPkg/Library/EveBootOrderLib/EveBootOrderLib.inf b/OvmfPkg/Library/EveBootOrderLib/EveBootOrderLib.inf +new file mode 100644 +index 0000000000..5e11df7242 +--- /dev/null ++++ b/OvmfPkg/Library/EveBootOrderLib/EveBootOrderLib.inf +@@ -0,0 +1,48 @@ ++## @file ++# Rewrite the BootOrder NvVar based on EVE's "opt/eve.bootorder" fw_cfg file. ++# ++# Copyright (C) 2025 Zededa, Inc. ++# ++# SPDX-License-Identifier: BSD-2-Clause-Patent ++# ++## ++ ++[Defines] ++ INF_VERSION = 0x00010005 ++ BASE_NAME = EveBootOrderLib ++ FILE_GUID = 1E8AB4B5-3497-11F0-9B0F-78AF08E0E8B3 ++ MODULE_TYPE = DXE_DRIVER ++ VERSION_STRING = 1.0 ++ LIBRARY_CLASS = EveBootOrderLib|DXE_DRIVER ++ ++[Sources] ++ EveBootOrderLib.c ++ ++[Packages] ++ MdePkg/MdePkg.dec ++ MdeModulePkg/MdeModulePkg.dec ++ OvmfPkg/OvmfPkg.dec ++ ++[LibraryClasses] ++ QemuFwCfgLib ++ DebugLib ++ MemoryAllocationLib ++ UefiBootManagerLib ++ UefiBootServicesTableLib ++ UefiRuntimeServicesTableLib ++ BaseLib ++ PrintLib ++ DevicePathLib ++ BaseMemoryLib ++ OrderedCollectionLib ++ ++[Guids] ++ gEfiGlobalVariableGuid ++ gVirtioMmioTransportGuid ++ ++[Pcd] ++ gEfiMdePkgTokenSpaceGuid.PcdPlatformBootTimeOut ++ ++[Protocols] ++ gEfiDevicePathProtocolGuid ## CONSUMES ++ gEfiPciRootBridgeIoProtocolGuid ## CONSUMES +diff --git a/OvmfPkg/Library/PlatformBootManagerLib/BdsPlatform.c b/OvmfPkg/Library/PlatformBootManagerLib/BdsPlatform.c +index b696f1b338..593483f074 100644 +--- a/OvmfPkg/Library/PlatformBootManagerLib/BdsPlatform.c ++++ b/OvmfPkg/Library/PlatformBootManagerLib/BdsPlatform.c +@@ -1709,6 +1709,7 @@ PlatformBootManagerAfterConsole ( + + RemoveStaleFvFileOptions (); + SetBootOrderFromQemu (); ++ SetBootOrderFromEve (); + + PlatformBmPrintScRegisterHandler (); + } +diff --git a/OvmfPkg/Library/PlatformBootManagerLib/BdsPlatform.h b/OvmfPkg/Library/PlatformBootManagerLib/BdsPlatform.h +index e238dda9e1..ca67c31271 100644 +--- a/OvmfPkg/Library/PlatformBootManagerLib/BdsPlatform.h ++++ b/OvmfPkg/Library/PlatformBootManagerLib/BdsPlatform.h +@@ -44,6 +44,7 @@ Abstract: + #include + #include + #include ++#include + + #include + #include +diff --git a/OvmfPkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf b/OvmfPkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf +index 8257862662..9523890c49 100644 +--- a/OvmfPkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf ++++ b/OvmfPkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf +@@ -51,6 +51,7 @@ + QemuFwCfgS3Lib + QemuLoadImageLib + QemuBootOrderLib ++ EveBootOrderLib + ReportStatusCodeLib + UefiLib + PlatformBmPrintScLib +diff --git a/OvmfPkg/OvmfPkg.dec b/OvmfPkg/OvmfPkg.dec +index 0a1a09fb70..37d6a5bad1 100644 +--- a/OvmfPkg/OvmfPkg.dec ++++ b/OvmfPkg/OvmfPkg.dec +@@ -96,6 +96,11 @@ + # + QemuBootOrderLib|Include/Library/QemuBootOrderLib.h + ++ ## @libraryclass Rewrite the BootOrder NvVar based on EVE-OS ++ # "opt/eve.bootorder" fw_cfg file. ++ # ++ EveBootOrderLib|Include/Library/EveBootOrderLib.h ++ + ## @libraryclass Common code PlatformBootManager and PlatformBootManagerLight + # + PlatformBootManagerCommonLib|Include/Library/PlatformBootManagerCommonLib.h +diff --git a/OvmfPkg/OvmfPkgX64.dsc b/OvmfPkg/OvmfPkgX64.dsc +index f859db6acd..da7e10ecde 100644 +--- a/OvmfPkg/OvmfPkgX64.dsc ++++ b/OvmfPkg/OvmfPkgX64.dsc +@@ -444,6 +444,7 @@ + PlatformBootManagerLib|OvmfPkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf + PlatformBmPrintScLib|OvmfPkg/Library/PlatformBmPrintScLib/PlatformBmPrintScLib.inf + QemuBootOrderLib|OvmfPkg/Library/QemuBootOrderLib/QemuBootOrderLib.inf ++ EveBootOrderLib|OvmfPkg/Library/EveBootOrderLib/EveBootOrderLib.inf + PlatformBootManagerCommonLib|OvmfPkg/Library/PlatformBootManagerCommonLib/PlatformBootManagerCommonLib.inf + CpuExceptionHandlerLib|UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeCpuExceptionHandlerLib.inf + !if $(SMM_REQUIRE) == TRUE +diff --git a/OvmfPkg/OvmfXen.dsc b/OvmfPkg/OvmfXen.dsc +index 4e99acb800..37a359eb31 100644 +--- a/OvmfPkg/OvmfXen.dsc ++++ b/OvmfPkg/OvmfXen.dsc +@@ -334,6 +334,7 @@ + PlatformBootManagerLib|OvmfPkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf + PlatformBmPrintScLib|OvmfPkg/Library/PlatformBmPrintScLib/PlatformBmPrintScLib.inf + QemuBootOrderLib|OvmfPkg/Library/QemuBootOrderLib/QemuBootOrderLib.inf ++ EveBootOrderLib|OvmfPkg/Library/EveBootOrderLib/EveBootOrderLib.inf + PlatformBootManagerCommonLib|OvmfPkg/Library/PlatformBootManagerCommonLib/PlatformBootManagerCommonLib.inf + CpuExceptionHandlerLib|UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeCpuExceptionHandlerLib.inf + LockBoxLib|OvmfPkg/Library/LockBoxLib/LockBoxDxeLib.inf +-- +2.43.0 + diff --git a/pkg/uefi/edk2-patches/edk2-stable202508.01/0002-MdeModulePkg-Logo-Replace-Tianocore-by-EVE-OS-Logo.patch b/pkg/uefi/edk2-patches/edk2-stable202508.01/0002-MdeModulePkg-Logo-Replace-Tianocore-by-EVE-OS-Logo.patch new file mode 100644 index 00000000000..a943c8dca5a --- /dev/null +++ b/pkg/uefi/edk2-patches/edk2-stable202508.01/0002-MdeModulePkg-Logo-Replace-Tianocore-by-EVE-OS-Logo.patch @@ -0,0 +1,486 @@ +From 89b824615f6d0aae14f2f08afd41c98a7d4a8934 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Ren=C3=AA=20de=20Souza=20Pinto?= +Date: Fri, 23 May 2025 12:58:41 +0200 +Subject: [PATCH 3/4] MdeModulePkg Logo: Replace Tianocore by EVE-OS Logo +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Renê de Souza Pinto +--- + MdeModulePkg/Logo/Logo.bmp | Bin 12446 -> 921738 bytes + 1 file changed, 0 insertions(+), 0 deletions(-) + +diff --git a/MdeModulePkg/Logo/Logo.bmp b/MdeModulePkg/Logo/Logo.bmp +index 3e85229e17595ba1f9c59e13692a4f8362ebc850..d1b130eadc3091a11e44d91c4d83fe10794e6813 100644 +GIT binary patch +literal 921738 +zcmeI*31b`8^~Zf{W+d6xE;#|pQcBBK3X}qce@j>PHFTkreP7ECVF}PuXv^M)tu!+b2U!ML* +zKHFoDNA&MK`u9Gsr|18P_4LGgcC~N!^yu&Z-~OKP-_AGe&;Rd>XZWpOp7`rqzx=z& +zeWjP-fdB#sAb7VeASomLkhsV?i_#M}&`DON7ItQrp`#4N4uA525?7TPH9xwdL<=3(;0tg^5d4X6= +z5jf`QpIDE7&UwMpOZ%UGKKb;&6ZR+1NCN--ckjQJrk`GxJm=CxGMD +zqOJwsc+B_q`EKym`-S>gp*p5N^P^)0o>2vgBdx;P4f#{f3}QXOR2{9LCz!vBzw|$; +zYHOf6o{PF~999YBD>}W$b3>zr^RG&Ho*#?(zCH>uby@I0009K1L%{3t?XF(|I0$aJ +zGgTffG}_tnSaGzaD4gRNRUkXs&Of@iFD_g~;Hi4})}ejIZ@u-ynX=s`aeyKUjE>pe +z%W%6i+RFXs_1u96+NZz{79G%2b*}Pz5I|sC0-mSFuNr9nf!|Z(H>VaswN%#F6UyL>+CZdnaFO +z6l?AL`qAvASI6}c@YDxH^LO%RBR`1%0&W88a8n4@#plj@dMiyesq#Fd2~L@+wRDbn`g6@Ne`JA5D_?Hp?z*=>u5n=Uucqcy<+mV! +zz_tY}|EkBk?{A56GpD}R$QLm-R5MC>Yqhb$P(8os{&+H}IH_=H0dw1jVX{A=CYt(4 +zm8~26;)LMiwfXv(2J5roU_Hk!sz5v6XcpdG+4qAZZ6Ic{hk~C&009J?1e6@){rtFK +z#oAnLJX^7xtEd+-HdHoLV?Y7%osSCN`@XNy#ElcX!kMK`N9l`=EtFde&3d7gF!Yy4 +zu@CI|{UOm3nc}pAtQ>DN9!W;-K+g1Q0;rOMyzc}DO^h8>-jjCgc +zzXV?g0o}cf=Z5RKYp&OX-)Xpv`v)EDzq2A;YvpX{nP*gia4u3#9T%Uj$^Yb+@$lY8 +zcQ@gungdk&q=CRSP9Bu@8xzrQLK~HSJ~n{_VQkSBdwdLhHjtQHjWuB +z2C-ErpsJy{-=3AUnMm8e6JtA{BK&#;5ZLJi)OD%S5NDs~e_kf?MvT0hMJqL(tfKOg +z7yEbFCD6!vU?n%U|1=hj->V6%Txj3F_=?_iLujN +z8rUHO5ZKNFYW&VC2Fu<`Sc}Q=Vl}rnSFp1p813w5Bc)SMSDlSczojnS(=c?XT8TEv +zNd>%j`9|#dm;0il{H5ZK8CG_ZBm^@)*2 +zrb_&EyML&S+1wwE9zMD_)!(mtC=D8JOfKKv$K1vc)B~+!X>IM`x921Vhg7>;dAttM +zhiyB{ezkJT-^qM?U&ep8_gT#EM_`T!#4P2?a)bPD?;9+CCsiKH=vp0C?^gl;+5fCI +z3#u_v8`J6%icr>6)EA>|#~uJ%$!^v9+({=XU3Q0^NNQ})-z`}Bye1;0rnEytt!W$G +zuD6Qe^t9Q3lIVk=ZhYNV4OdE+U#AM*_K}I(Sn!TJx;yN&;)M}FU}^+9Iad~bdxEQO +zO>7t~Rhy+s+rr0Od1{Vlt5j*tFOMruStGI1%DKkhc3vy#JhZr1VBZ7%SKm&LRI?-1+~7!NeI++1p5@$-o+G6VmDKQv>g^XS@;c9VRtLfdtJ2>) +zB)m%RxJ$H-t#6A+#vXn=T^-YNYJ%@bHNUQ!85&Y!Fg+(u68kJ<_56G!w|+RUMV2qW +zArp^>)8%7Rwur_yKB)XP0tn1H0qa21KQVvaeD9>w;%EFSIQ>`t>A#Afey0BP=EhU+ +z)L-!H;G)ao>xMN{syVaD7Iy1@ZshO!Q!<`VL1r6|-BD+a66*XQP%G`&LTz +z;;&l1&-}aZ)CK+-XT}$tsk3E{oFv{EI!W}ous{97j?$6U8dl5&-chGEuZzH}5(tBY +z{@C=KRqt-%H>3Lx6*clR8Sn2;_kXd{M3m`QVU-5WInrdG;>Rn}haVN!FSdUD?!&Kj +zNQ5^=`j4#@Y!O`joL&DSOZl>`tF;S^=BCO#HB +z`QL2v?|h*@H+^R(-*a{k0R#}(83i;iR}*Fz{8lU1E9^#Z_S#~*%F=1%hexwFE>y3t +z)e;LLwSO&nS-WNT1>rSb9TYaq*mbZAbD?cJ&kGLzzQ6Lbbh$aN+Emh%TU)qY`o}-} +z=kIEZ4)2Udlzl<~0R#}32?7d|sa}8avq{G?o0ajfP-i>+#yh!heMhx|Ej-yg-0p*v +zZKDuu|0u^+G1xNH!&Y#2@h*IE{T59}(uV%RyOTpr?W7XS96O@3>Zm{A +z_t?wVGfbkkh}?aLr#7;ku;19zbLioT4_21y<673oE&f_bW +zt-Ij4*He4%ElS1qP8YY+yLJ&{TLch50D&1I5atf~-rnDgzqq_#l}6MU)Jn&Zn}phM +zq?KFta^f4iYs!(0-MTnvVvB}rZ(o!wH#5~{=HY+zCgN&QTU3txYs2<$pe2Z}zM;2L +zcbW^V&gW`d-37`tD_(kKU)Vg?EGO-n)4PuR*4PjM1Q0-ArU)n)b;@pDeM?-ka%!!T +zLa^fseV>){3x1o>fUj?T&kCRsAKF;E_rs(74?fkRfp%B0dN6y^DGKXOqpgbFzEY}V +zexc~S{8qnZYe$_9td_6(3M#66)ylv2UiN^4tcFY2mmmH1AR-o>)cga +zGI7u${#zeu&e6u%zR|j5>tlrxMafqF;eTYbIGrU<*+^*jEkVnZQiQcssd&P>_rc_7 +zQz23v`A9- +zfnUYNPWOFY-qujyY*L{I9y{Gj!@?r=efB*tBPQZ&L4*!w=;p&VHWxB*) +zEv?(mH(J?8p0sraEvqYxjryWn6Ez-{Wo7e)g80Kv_1BvUzFLf_P`1wAfqFZ&WGBiQjkpInmdrk|R72KmY**5SUOv{k*A+ +zci#iOWp(hntxB&hYxUo*SY0^$hhe2E%aGC|O8Zp#OPa`|@OsMW{wM3SW4XFgvMtj| +z@wZSP%dQ(KUUEg?Ydu37VxI8bP3AAOmugD? +z%--@d2q1s}0yA2m6LdPw(;pn^uUw@7r|hN(tv_1|wiC0gkaE3v&wWZOR_F~YU0BOE +ze5o$66jnVi9#6)V?QF{sTQ$q9UPvR$wQxPA(RS{|*HYj7cEajfss-!R*=v2>KmA3p +zYHeQaYgF8+`)%(jc2`#lyYbyb%`|;nFR=l-k3e`WXlDFtBR??(s|Wv@T(*%L~@4)JDnB`#(S4Tltw@D`&S8 +zS{(_#M$NshTYR0Cuf^Y1e)-$k{r0mCXB+c%>k(F~_N;T_>$C>b_?Clj=M_imgl}|Ew3Sv@>tMmpSwhYyVnDuVs979qF`xkN-J-(-dANSsS8>Q;GTPa+^v^Y;a3gCK+$*ay@Tgp +z&(yVoaG2RO;W7|v8aIoLvCIc+ia$C=>l_)lh+U9ADk0|5jOKmY*=4D9N?^lE>#InU}oZ5B_v{km?YkMql3?%Qi0 +zMLw4>qn4}nJ}Zb{e0gH1R;V@A_}%J|w7R~>@{O_5a4mn|L&>=EuxzZ=aj-S!#l359 +z>D@4DMXwAH=4QVQq4tjk>P|z009ILnCSu*-)xA~k6m_MP_8LyN=yBA +z9e*|8Yg=i^SOpu~*}>u5S?46fC6t_^OgK>LA9A3-{5|beIFPE9d7Bd##8B_Fen69g +z#|kSy&m8}AHNXS?631YtUhKWT>An7bzt*7$2gHju^*F-FxFvCw>aE;sZ};!NpWPN{ +zlsV*|>1Pr9j{pJ)AkdY7g0C$O@B4}U4@&&!-BP`&@ly+4o448~^R*g=)-ttf7?x}F +z)U*AHEn0crG4N>sH_;or?q;<;Cyu!jwn+;QKanbwERVS>l&}AACwcpK=Xe`NbG2qk +zAev7Ur7hgj%}G)H14GT+)z|d~p6E419S__1Uw>J?g8%{uATT=xEXUW1B`eR@yYjle +zp;5&YO;!zCvJ(ciEqA~w_*NQLb3+Rftr^UnaH`tAL4?HP|Akgu^7h*=c;o$yCiYI| +zHemCgQ7`(c;nazzXekM&smE%cS^`)szS}qAOI}P>S{mKXm&XcLSh7ncRpC$;bXj$@ +zTA4RL?B8<_>mRo_$y}uWJ@EV=0tg^5y9IRN56e=;4?Wm_Yh|XkvD?{loVtxH`gyH* +zTOChV+Qo+#_Z5o?HSCmn>MEtYQ +zkAGItauNf>W7#jbwtPdfML^Y}tdEBiku;UKk-hzo319nWzuno1Uw{At2p}+%1eAsA +zYgwYZALv)Vv1SaZzJ$s|gp2BS5mqeL*qmSMg8pz-DXg-n*sjRZ^}wqIqVQj9b;f#B +zhWevV^40%pNVog`XZ44-a~mp!Gk(`uH8}c#3F}r{D>~ETKlOZ~p_cEsTC!a?$<;qF +z+D?zQ=BqhB+Rl8qqIk?tbdRE5dL9TMfB*t>NFZ!=#g6`w|Ncsqt>`k~ex>WxCjJzv +zjp85ws`AUxAKIm`x7U)U^zWj-^i~^6X%5#p`pPR#;(v8Jp}T@-{?otb-gc*9w*yuP +z#3|mLc!IxbFkNZ7=0fXDDckLi`#SO0v4tKToGlSR009K1U%)bNdxAebkkqhmglyi; +zyI5<@{OEZ8qt*E%kFv(1!+TM)S(AR%cJ`0@zxex~YR+$ZB+O^t{N*O|wR+LZ>a}hb +zKCk3|e}T2cRbA6cd^zl%-dHZ@J@RCt-YP}w65njkGg{ta#pfBd@g2C>6afSfKw#zx +zC{P}Mg1>esqa|+3Hm^2%6IeaZLygjnw`;zSV>Ah8{A$K+EOy@`$*=~dvXwO7r~4u4 +zc1DwJwP=yL)1QAmJ&;oS*9u~}4hMTZ$NbFKp|BPCWJ) +z0R#}3n*w&Nw>D}lne-li!bW~Alr*CR-*9!{qN1b-M&DBaPx8Zi-uvwkAcn?Vyco_xShT-#1e03`vJY +zu_ElAZBnd_lb+2F*}{FQ^bX48r) +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 +z(?KsYvr|gllo)l;OVXIETsaj_%wIK(UNsa +z1#~;OY>fZ{Ulq_5FO~5wzb<+6-Tk-U9V}dwm|M@g61UxzxN%|c%de+uZ4IqDG?6rP +z9!~mr_1)b52WTWy`7R12)~Nd`dN=>S>#nhvUQcT-Nu@bpiwN&@9Td7_DU{o}!Aj=W +zXGNTU)bX%^ZeiJgxu42;cR$dtrt3({Dw#xn*E*oOFIuy%wD8{ko9>!p=k^z$?5lmeF?K(}Kgv;YIP|OZU2p9a|h{T7VXc3UK)4R4Dq++#^z3aYS8x61-%AG%_@LZY^ +zzp4{?iN7=AV6l@3%w~bGk)`H!szzU3b;*b-K{0 +z6==y!o`2X6{I}m%QhG@_T}rre>xp%|yV%C&YWwTn8;&b=#C}KReSf7^wB@o`WG5rw%N*#g+OQXXM^{K00IbXUjcOwYvrAUuEWQl +z9IRfSE03pa#RQj2{aAjaoOgqyjs9%K!oolpm +zi~gilajhP5r*Fbx@7NRp1Q0+VqCnU@4b)MZ-zBl+-xSEUTegET(&H1%;e#4o+ZhN>XP;R#`v@T)k>KklPBPvwB})YOyZY-Nq)(QB@AGCN8NFefolgLXWLz8*@rD)$aB7#s2i?v=-yD +zS}2;?v{^H=+dZ7lpVwIJhoAOoF+okdQU`Kaa9GaWKWq$GjNabg@?Ll?t*(i3JKMB% +zk-Cn>oz;Z(r|x7HKigj@DzaO>>hAZ6Ef7Ee0R&tH?Ajj0ci$~|;nlS2Geo$mZ`wo& +zNR{UNdMms5+4L^EY7vXLCGfg6ue5vr_alGhXX(mVsn-21!KQti<}boR8QGCq>Gr#m +zYQJtw=rfA$gPm=mE$yExu8nUf=j9M4$T?+zuN}&rb(U@nbcB9JHAvhMBKhJw%d0*Y;B4r%=0qV`-b1(Mq +zwtL_>K>xo7i~mCa0R#}3tbiiI_YU#j`XHr6Y@H%h*lS&B=I(naZ9UJH*<&M@VZZBS +zcjoIqXDMOp(q*k~U~3Gy?cwxpt|B4UA<)YI@vn(=TKxctP7wb3dz{R7Ec%Ac=QGZX +ze>Rk>{Wn~9$>kj>7i+X|$>qs#F4AOnfuBJD0R#}33IS`0h2gO$cFXO_k*2L<>lA;- +z)Z#0Cx+;ClPi-!fn$=nb*Fr}3vu`?`q1v)g^d4KBwEDd&eXKucQ2STO#$(wL)d6eg +zSAL%T*)O#AVrMFI*F(Tz*bRG#^($ijy!qZU&m~oBdeo&riUsasvz2}2jpFWmShGBQ +z0qq+d(Npo^;&&i`00I*T=#s7>Nt;&d#WfZ5gVjoH%2u?9o=ba5!LgCM=g)~u%4WSz +z@XC|=wxxtATJ?B8{YiY)VA}DnV25w6&hx)Ks%&sm*JDxy6a0`|5?=hYUj^%i)D>?_ +z6NYO~MC+C>XmQ~UjqG)c!Wt<$XjY?af*0o72q1s}0#hNNK%m5A&ku^l;BSwo%3~>& +zs|v5=(K~n*yER4VkR#$jkLLWkRbLDj!srRSXP5S=&ZOf&=MIm*+JSXL>0?h(k9=5; +z!{G>8uAJT5c#l7otTt88$^l0i)auo5=iXhBIr{%JSg)zdx+8O%tnKj5*c1T-5SSAJ +zx{QYnG4Hq&gO#6WYRzIrozLUZYda{!4A*lv-PUXEGi&8JF^28Lp5I^St=*tr)?!67 +zk7mxaqb-K}(b~Kxp6lOrH`i=%#c%x+@A0*s@~3MwUSK%UN`Z~GmFsTHIF8ivcixk- +za#(hI;CAGk4m%qofB*usU%=+&S_NS5sptCDhWa98=!c$&RuzX|Hgqvtj948>6=Muby>I{PW?G7TpVLUUeN=rZ##` +z!Ee(oN~`$9bLqZ>-T7F`u_CG4DESdT^gdpdDUW69Hfwv+O;jYSR(kP2)A^hl!Hx&9 +zi<6KaMF0T==AeL@U;_iOmtIj(3#~~P>53h0Wi_(26hbTa(rd|Ye$#E}Fl=~P+ps6L +z=U(2j<-Lt|QCYsOk;UQNO+ncG;?-^G-m$`PEql%-8hE#EUWH+;?dx{##co^FUl~>B +zgL)xc;;+)ni)+^97o4e4d-|W>g>AhATxi +zejPJ+!pOUEr!T$IAF7m;c~xo8t2U$G9z=d$Q@o+2kd>;f>}WH$^wsR1duvfbo1&#Z +zw{euV`q#Qs`N0w1yPx!1Sx&dYWfj}K{1eZnvsuSmg01c`e~ADB2+U1^aNIF$U-o?W +z(BSP4Z6SMGOQ`FG>C351zuI(R3pTQ??VbgsJ$CnAeKTXr&5z|9 +z%^6m6W1_&VRV_4mxiVhZP|03$rJ9*>bwO(sKC+fJRQp-O2shu-S8mw!F}-v+T&`Fg +zp)Fh-9nWp37S6shsi7WrR;WRdK}Hb1qtH5$d1bMC{rdlS8!#5oBgGla+S|E(_t&Zi +zIvQ?`&6us7P#o}Hem$iwXx&O#7FM&UiXRi*22Aw*u)L?rYiIxcdU~(DbdqS{Dy{h7 +zwtFsT1KT2i00Of}Ago5E_GNIu!QMx!HSDY2-Tdg-fR%ChVwiGrUxdLiT+Cg4*H8be +zcm8gHO>K2c-HF=@KmPZ==e_k_s{1B+*AZuO?{w;at?pQc>)9J_w#KhwoXh#8{%c!Y +z%1^36Jvf@Kw+3os>Cu+fj_mI4B}@RYbthF;dT_MUJojx?BL{fWWK~ +zunTI;&t>9&eY{_#CTkirRHtR6al_7pTqRDgUSBxn^l*`1El}$gO|0ZqPwWpj$1C;X +z%&PO;Z7A3ByYGIO{^nj1(_4=Iu)Yj6q5at2`}i-up?PEl&EvK~^X~4Z>>k6~&T2uo +zbM;2)&5tsN93F;tw*wmejj<&H2p}-K1UfaZjy*BHYK_9KWnR@<1EbxqVsF{D*7(hq +z8>L78uAxjd!mMzEV|S&3$^HifAFj-dj;CExvb&9j)Bp1|HGvz2yY5x3lDJFr(gxhs +zWnlL$@$-M5SW{6Vv^q4RjhO3zDjD8Jfk*23+wbX1_J##HX4gl6cY^=|2<#96TM)3v +zdw6kQ*gqLP=eahXtu*GVowY(m8-D6EM5vgn=+SA$^{4&2?@x_3G@H1yxb4*U{Z4#|3BkgH;UVWiXDg%YK-+C|~+`w}q~xwcAV$~|)mcIy0J@TNv9Eicg#nXS49AUSs|bXrv9;O +z`^A^XH&oQL>BQfz16-%bzm5F13aZ$D%biJ^bL5uuY?T<5KNL&+_}JjH^-96jBELDC +z6*YUGo&IO*B@QFqLr?T)(`vk`AKJMmp~qI!SiLq=8PlAyu&hd#iO?N(TM0`AMVp1k +zp6bu%^dYbw3jOKSKA#nzCEf%A2q4gffP$O)oxQ|&zU{yAre)@6a%ec`sQdosrm|$` +zRmZdHyMA+J;`@iiHE8M7WV36!b}!b~pLpo8ba@ukx$6G5;gfZllTK6nKkNtS;<$e8 +zM`K!dD#&Dd9(p2CYbujjV+1AZxo}| +zTYsajXQhPw;>7qT>)g6byAOOjNfTSm%)dX`pX?2iYGt}StO>2o2>wKE+$wCSW-q=>Q_O5>LYL9$ +z8TY|qhY>&k0Y?F?wWAREz=O%E=JlxM+g9(fn!sHLJGFmR-a#ot>uaeCE=$@PdNHLw +z>(A&r7&fS4r!4T-jySEsG|drnYF|!wH5zYy?)kof`Qd^{Q8{%WG|FHj4Ke@lqk=b9 +zq#I*d{qhKVtL|$}?hY5m(oI)>`Pr8rOcjtIRsr>-_AxmtyjD!NP4lw|LU)I-$vWCV>AAXFdcovNbxtn +zx7pcB!%|CAW8yBvalhxbyVD~LC1R=l>vY`3J5o#Ev@p@zr~ELNotlH6KHf3{2+Ump +zT`qh3g2x{3vlSLvs`DKEQmpu^s)_5XnFYVrv{0w(aF}wX_@Z7-|EzO^b>-}EOO?2y +z@0-i}+Tq*QR7OlyAKUrom#6mLQ*qYc(6XY&c*R{Wz9!c$wcQEF=Ky&<)YiIk&Vc|pv1O4RMNy!ncX@WG&b*jXaD%C +z%QLE^vH5ZA_G^{W3Rf=9f3mi4+{sSIosAJd0D)OApx(=HDFpA5%j4_InNHn|ZZEw0 +zd0S6MlZ7?xYs(}R9(X+IYsoxo{6_B@6@I7GL@Mn+|7!nSj=Wz#BIQQr>Ob^r6j;N+ +zj%TTgTIvqxyo=+5m9UtYimo*DMb~+En|4yOvmala%IB4cua$UU;qdvYlzRiyyDf{QTI2nr4A#sn0HNTo-UJ?q73b +zO3UCnj!tfh4zuQq_dm%Ta)b__2FG0<79-WqP$jE_=te2q1vKEEP~m$GGp`a7&_6Q|`^i^czLtu7i{oq|*Y0V};>H?yryb_ocN; +zfUdlXzfP?)W%qu2zr-8w_Rj7)lU-|DheNK?$liXBDor^CINjn{-4!)d&pIbqJF0rl +z>g5hAQaW_h*T;%WUg*;hwR89QEdAi|wh%x7fgb;m@5kT!NIlQ0101pCtMH-K*vl%# +z-^#tUVqpLMloq6a)UWBD2OC^_OMGNh;ULON@e$(M%-KY3jRamxJ +zb*sFGo>Doiq6&RzD8Y%MmETawop0qh)CzXpLq4VmATUb=>}q47L0zM%tbf(b-lPAB +zKlYErgOAP4XYaq3riQKBWcO{}&D%%q+{jqIT+iNer!Kh)yXtoiue#k|dacQ9%_f`Q +zdhj9fw>~IT#|STE>!dOTUzMxUnD`y{XDts}YIe61p~6__KG???a0diyrh3I#gF18w%G$!rgx$X32Gzw}F6N +zV=VM);-rn5op?fW%?8bUw5Fdb`OL*KeS-ra;8}% +ziN$T;H{suWSMP8`u}NzLC?dGsA#8rPF!R5bh86`@xBQ1|29EieB5&u8(rppISS(+N +z|NZgQu!@{G&P8f#(dT)Mrp~K5`pHr%qtD~R; +z{)(+**qICCc6%`E;;+K7&RAXQ)djs~uz1`likzJuPKVE^B`aHH%Rk?5i!yvA;&=JK +z$|cZ5@}efA&CO3%-O|`{)=klvci$uNT;6)1b&$d)u){H8Qv_zRKo}u{(!5~FvOd>N +zw%K@9pZsN3vs5euSbWTHsAn&}N}a~m{8e>-mlH%mKz+~09UH7%8z$n;ZRE)u4i&z5 +z^6B(0yQp8sweR1?C}Z9cNBD2Au=raU*SZXrTsN8B;AbWhSh+Uy6O9q{XcUvC;i +z+Zitq&PVhvyd*iOtXi(^4g$I?SDG3+w;3x-wf5_tD#xUr1=k!CMc>|pcmG4ZRn0|p +z*uA-Pa5Z-D*>L)V6RqiL84l4OmM5g~nN**D$DiUO;rOyOV>KO^1K}W`d(_9CP)*LT +zn5tt*xabF$EfLu90$OEn-~EC&-tKd(w#OAotFBkunyZpg)#$U&*2Q0!ZtL228~@cA +z;vezDVAZ;mRl;<*=*^vNbr+=79(4<3Q?8vpVb(!v*%2}C!2N?)-&bm)3UO!{S9e+5 +ztVS2mo$A^RnO~io5bwr$0ZxaBjS-l+0}6i|g&jNVC*z=LbjfXZ$*;i;7)V?Cw6o%EwG2ASw&cM<)QuB+QG<98(T>2^^f7aL#foT>{ +zpPC!}WrtGunHng+@cVnbcd~|VNz7TZ!)1n?7+s+4S)Y81_`l=E(wX77gZeTuKoBiQo +zw!)yzS&2T{Xd}j6%nAgZb53G?Ijg3eZjJO3BPo13D-=vEO_*yZ=GDp;0ch +z#?zxe!h#+_U%uyG%aS$<9NsAE-ZeZlU7tCVe=oD|Cl!CyrK4NQN^@YOnZ0qL)*RE_ +z4J%VbKRMZQ1_@{xyTU;1vBfE+49&hz_jJA^jby1=TGu**bzMe!bsMjaW9xo)$Rx1{ +z?)kgz9$WS@sXoqetyLUq#ts4Xtwf}3;jhPp3bvw +zmc7>dEArnzG6*dG@<3oN2>8GFd9Z4IN>gTL*=KqB-%d?6A;+@su1Npjh`1uBI-k{* +z<`RE({w3o*mtLDxs*htC%<0$I*9rdFjavwh#j*vh5!Tme +zW|YLMe$<`qEzhj|(HUNDWftC}^vQ8DJJGHn8!4Ahrlc`&|RqL{cA8kvp@jzfU3+UPr3(mbLzP{YA +z>=Zq<+|M@F8MKP=s`<0&sVR_=pW&#PM&-sdtZAi$B0sg7>gKUn{~PTY{u0|(Unm9!!R(oU$e+IBh0zPHuhSwn2+_dn@*4DTT*OF)!b&IGTfbiq25A|1{ +zTX-*D`^Z;xcht&jb)<)$=r5LZa4ZqJ^Ff-;*J0kRZ=L-ev +zoG@j#wyV9u}PW;ic@#xOybfOP+xt$B2 +z_LE_9n)1`W`n1~swMn(!Q@B@Kd>58LrKdhP;ZuFc(VuoVUZ}OQAAg=Z;bgms)k6W; +z(hzwdFuMf2p7?Js@-~!9ii71=*4DGr2W^{AH4j@_f_&q1)XG6bdFnT4tfxGd?L0fJ +z;AnrAoB54Tdn1J}|98{(yZAzz>#6&2-OQ^pUKdYYc9y-8*>z7{HEgv7my^YErei@e +zh~0j7-(WRWx5l_#c(-@~VOxeJ{LXfG@r* +z($w!R3Rix&nWl*G;M*d@6P+`YJR83_i#wl=34dGo +zDieS7{`cgcXqUq8Yc5qd1g>7*uRrxyVH%+|LBpBs)~~arr$KIf*pTfOp8qSeWeshp +z50MD$l4AeWH|!Ec{M~+0fZvP&0tg_000IagfB*srAb + +literal 12446 +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 +z^l<1Szo^yaXZ(OY0J +zz}(Cp(tL@=A(9}G3)OX#qaEZ>4@760G%~N5^>TyF?X@keFdeX# +zND}dy<3mAOF$X;PhI*MyaZjcNcbZSP?;;1R<_trG0~V+UNC~~6GaNc*Bu)W3wQ@O9 +zy0S!uaGYF3#UTi1IiibH^T*^n?!r$AU;9`CsVQjCU`Swleb9np6$&k`-r1CuYl}WD +zCx^GzrJP?9Gi0|O&Iq!6G%Xw1{l$Zgk!{Zl5Fm2iQK(QBgXzl74r0Xu?am8!cXk#5 +zprNpbG{aa(w{vp9`4Rp~7BoIA#WC-B$UtT#6=h+zd;MszS`4<1Ad8Dz!V2cQgnJ!h +z*6v>9pg~g{=nEfzU?0Rpu!nl87_+hN=SAk;8|y8ZN-tQ){fxtHA%|27Z|s*sX|?b` +za=QZ)W(>T4I6ckxK#+*csZTptP7a6rh%E$ykN-oXIVc`A$5)tqBb4^Y+`@v3Qt{QDF}sHt~)E=sT_nwoE4sz`4n=H=5S_p3331o +psZq=L&dN7)FA +Date: Tue, 23 Dec 2025 14:11:08 +0100 +Subject: [PATCH 4/4] OvmfPkg/EveBootOrderLib: Read fw_cfg before reordering + boot options + +Signed-off-by: Nikolay Martyanov +--- + .../Library/EveBootOrderLib/EveBootOrderLib.c | 219 ++++++++++++++++-- + .../EveBootOrderLib/EveBootOrderLib.inf | 1 + + 2 files changed, 197 insertions(+), 23 deletions(-) + +diff --git a/OvmfPkg/Library/EveBootOrderLib/EveBootOrderLib.c b/OvmfPkg/Library/EveBootOrderLib/EveBootOrderLib.c +index 33b37f86a4..718ea7c582 100644 +--- a/OvmfPkg/Library/EveBootOrderLib/EveBootOrderLib.c ++++ b/OvmfPkg/Library/EveBootOrderLib/EveBootOrderLib.c +@@ -19,6 +19,7 @@ + #include + #include + #include ++#include + #include + #include + +@@ -31,12 +32,26 @@ typedef struct { + UINTN Produced; + } BOOT_ORDER; + ++/** ++ The fw_cfg file name that EVE uses to signal USB boot priority. ++**/ ++#define EVE_BOOTORDER_FW_CFG_FILE "opt/eve.bootorder" ++#define EVE_BOOTORDER_USB_VALUE "usb" ++#define EVE_BOOTORDER_NOUSB_VALUE "nousb" ++ ++/** ++ Maximum reasonable size for the boot order configuration string. ++ The expected values are "usb" or "nousb" (5 bytes max), but we allow ++ some margin for future extensions while still protecting against ++ unreasonable allocations from corrupted fw_cfg data. ++**/ ++#define EVE_BOOTORDER_MAX_SIZE 64 + + /** + Check if a DevicePath is an USB Device + **/ + STATIC +- BOOLEAN ++BOOLEAN + IsUSBDevice ( + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath + ) +@@ -45,8 +60,8 @@ IsUSBDevice ( + + for (Node = DevicePath; !IsDevicePathEnd(Node); Node = NextDevicePathNode(Node)) { + if (DevicePathType(Node) == MESSAGING_DEVICE_PATH && +- ((DevicePathSubType(Node) == MSG_USB_DP || +- DevicePathSubType(Node) == MSG_USB_CLASS_DP))) { ++ ((DevicePathSubType(Node) == MSG_USB_DP) || ++ (DevicePathSubType(Node) == MSG_USB_CLASS_DP))) { + return TRUE; + } + } +@@ -55,25 +70,89 @@ IsUSBDevice ( + } + + /** ++ Read the EVE boot order configuration from fw_cfg. ++ ++ @param[out] BootOrderValue On success, contains the boot order string ++ (e.g., "usb"). Caller must free with FreePool(). ++ ++ @retval RETURN_SUCCESS The fw_cfg file was found and read. ++ @retval RETURN_UNSUPPORTED fw_cfg is not available. ++ @retval RETURN_NOT_FOUND The fw_cfg file does not exist. ++ @retval RETURN_OUT_OF_RESOURCES Memory allocation failed. ++**/ ++STATIC ++RETURN_STATUS ++ReadEveBootOrderFromFwCfg ( ++ OUT CHAR8 **BootOrderValue ++ ) ++{ ++ RETURN_STATUS Status; ++ FIRMWARE_CONFIG_ITEM FwCfgItem; ++ UINTN FwCfgSize; ++ CHAR8 *Buffer; ++ ++ Print (L"[EVE-BOOT] ReadEveBootOrderFromFwCfg: Checking fw_cfg availability\n"); ++ ++ if (!QemuFwCfgIsAvailable ()) { ++ Print (L"[EVE-BOOT] fw_cfg NOT available\n"); ++ return RETURN_UNSUPPORTED; ++ } ++ ++ Print (L"[EVE-BOOT] fw_cfg available, looking for 'opt/eve.bootorder'\n"); ++ ++ Status = QemuFwCfgFindFile (EVE_BOOTORDER_FW_CFG_FILE, &FwCfgItem, &FwCfgSize); ++ if (RETURN_ERROR (Status)) { ++ Print (L"[EVE-BOOT] fw_cfg file 'opt/eve.bootorder' NOT FOUND\n"); ++ return RETURN_NOT_FOUND; ++ } ++ ++ Print (L"[EVE-BOOT] fw_cfg file FOUND, size=%u bytes\n", FwCfgSize); + ++ if (FwCfgSize == 0) { ++ Print (L"[EVE-BOOT] fw_cfg file is EMPTY\n"); ++ return RETURN_NOT_FOUND; ++ } ++ ++ // ++ // Sanity check to protect against corrupted or malicious fw_cfg data ++ // causing excessive memory allocation. The expected values are short ++ // strings like "usb" or "nousb". ++ // ++ if (FwCfgSize > EVE_BOOTORDER_MAX_SIZE) { ++ Print (L"[EVE-BOOT] fw_cfg file size %u exceeds maximum %u\n", ++ FwCfgSize, EVE_BOOTORDER_MAX_SIZE); ++ return RETURN_INVALID_PARAMETER; ++ } ++ ++ Buffer = AllocatePool (FwCfgSize + 1); ++ if (Buffer == NULL) { ++ Print (L"[EVE-BOOT] Failed to allocate memory\n"); ++ return RETURN_OUT_OF_RESOURCES; ++ } ++ ++ QemuFwCfgSelectItem (FwCfgItem); ++ QemuFwCfgReadBytes (FwCfgSize, Buffer); ++ Buffer[FwCfgSize] = '\0'; ++ *BootOrderValue = Buffer; ++ ++ Print (L"[EVE-BOOT] Read value: '%a'\n", Buffer); ++ ++ return RETURN_SUCCESS; ++} ++ ++/** + Attempt to retrieve the "opt/eve.bootorder" fw_cfg file from QEMU. In + case the file is found, set the boot order based on configuration + retrieved from QEMU for EVE-OS. + +- + @retval RETURN_SUCCESS The "opt/eve.bootorder" fw_cfg file has been + parsed, and the referenced device-subtrees + have been connected. +- + @retval RETURN_UNSUPPORTED QEMU's fw_cfg is not supported. +- + @retval RETURN_NOT_FOUND Empty or nonexistent "opt/eve.bootorder" fw_cfg + file. +- + @retval RETURN_INVALID_PARAMETER Parse error in the "opt/eve.bootorder" fw_cfg file. +- + @retval RETURN_OUT_OF_RESOURCES Memory allocation failed. +- + @return Error statuses propagated from underlying + functions. + **/ +@@ -88,18 +167,78 @@ SetBootOrderFromEve ( + EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions; + UINTN BootOptionCount; + UINT16 BootOptionAux; +- UINT16 UsbPos; ++ UINTN UsbPos; ++ UINTN UsbCount; ++ CHAR8 *EveBootOrder; ++ ++ Print (L"[EVE-BOOT] ========================================\n"); ++ Print (L"[EVE-BOOT] SetBootOrderFromEve: CALLED\n"); ++ Print (L"[EVE-BOOT] ========================================\n"); + +- DEBUG ((DEBUG_ERROR, "%a: Force prioritize USB devices for Boot\n", __FUNCTION__)); ++ // First, log current boot options for debugging (regardless of fw_cfg) ++ BootOptions = EfiBootManagerGetLoadOptions ( ++ &BootOptionCount, LoadOptionTypeBoot ++ ); ++ if (BootOptions != NULL) { ++ Print (L"[EVE-BOOT] Current boot options (%u total):\n", BootOptionCount); ++ for (UINTN Index = 0; Index < BootOptionCount; Index++) { ++ Print (L"[EVE-BOOT] Boot%04x %s %a\n", ++ BootOptions[Index].OptionNumber, ++ BootOptions[Index].Description, ++ IsUSBDevice(BootOptions[Index].FilePath) ? "[USB]" : ""); ++ } ++ EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount); ++ BootOptions = NULL; ++ } else { ++ Print (L"[EVE-BOOT] WARNING: Could not enumerate boot options\n"); ++ } ++ ++ // Now check if EVE has configured USB boot priority via fw_cfg ++ Status = ReadEveBootOrderFromFwCfg (&EveBootOrder); ++ if (RETURN_ERROR (Status)) { ++ // No fw_cfg file found - USB boot priority is not enabled ++ Print (L"[EVE-BOOT] No config found, boot order NOT modified\n"); ++ return Status; ++ } ++ ++ // Check if the config requests USB boot priority or de-priority ++ BOOLEAN PrioritizeUsb = (AsciiStrCmp (EveBootOrder, EVE_BOOTORDER_USB_VALUE) == 0); ++ BOOLEAN DeprioritizeUsb = (AsciiStrCmp (EveBootOrder, EVE_BOOTORDER_NOUSB_VALUE) == 0); ++ ++ if (!PrioritizeUsb && !DeprioritizeUsb) { ++ Print (L"[EVE-BOOT] Unknown value '%a', boot order NOT modified\n", EveBootOrder); ++ FreePool (EveBootOrder); ++ return RETURN_SUCCESS; ++ } ++ ++ FreePool (EveBootOrder); ++ ++ if (PrioritizeUsb) { ++ Print (L"[EVE-BOOT] USB boot priority ENABLED (usb) - moving USB to FRONT\n"); ++ } else { ++ Print (L"[EVE-BOOT] USB boot disabled (nousb) - removing USB from boot order\n"); ++ } + + // Load boot options + BootOptions = EfiBootManagerGetLoadOptions ( + &BootOptionCount, LoadOptionTypeBoot + ); + if (BootOptions == NULL) { ++ Print (L"[EVE-BOOT] No boot options found!\n"); + return RETURN_NOT_FOUND; + } + ++ Print (L"[EVE-BOOT] Found %u boot options\n", BootOptionCount); ++ ++ // Log current boot order BEFORE changes ++ Print (L"[EVE-BOOT] Boot order BEFORE:\n"); ++ for (UINTN Index = 0; Index < BootOptionCount; Index++) { ++ Print (L"[EVE-BOOT] [%u] Boot%04x %s %a\n", ++ Index, BootOptions[Index].OptionNumber, ++ BootOptions[Index].Description, ++ IsUSBDevice(BootOptions[Index].FilePath) ? "[USB]" : ""); ++ } ++ + // Create an array for boot order + BootOrder.Produced = BootOptionCount; + BootOrder.Allocated = BootOptionCount; +@@ -107,31 +246,65 @@ SetBootOrderFromEve ( + BootOrder.Allocated * sizeof (*BootOrder.Data) + ); + if (BootOrder.Data == NULL) { ++ Print (L"[EVE-BOOT] Memory allocation failed!\n"); + Status = RETURN_OUT_OF_RESOURCES; + goto ErrorFreeBootOptions; + } ++ + // Store the current boot sequence (indexes) + for (UINTN Index = 0; Index < BootOptionCount; Index++) { + BootOrder.Data[Index] = BootOptions[Index].OptionNumber; + } + +- // TODO: This is a partial implementation, for now it will only +- // prioritize USB devices in the boot list. +- // Search for USB devices and move them to the top of the list +- UsbPos = 0; ++ // Count USB devices ++ UsbCount = 0; + for (UINTN Index = 0; Index < BootOptionCount; Index++) { + if (IsUSBDevice(BootOptions[Index].FilePath)) { +- BootOptionAux = BootOrder.Data[UsbPos]; +- BootOrder.Data[UsbPos] = BootOrder.Data[Index]; +- BootOrder.Data[Index] = BootOptionAux; +- UsbPos++; ++ UsbCount++; + } + } ++ Print (L"[EVE-BOOT] Found %u USB devices\n", UsbCount); ++ ++ if (PrioritizeUsb) { ++ // Move USB devices to the FRONT of the list ++ UsbPos = 0; ++ for (UINTN Index = 0; Index < BootOptionCount; Index++) { ++ if (IsUSBDevice(BootOptions[Index].FilePath)) { ++ Print (L"[EVE-BOOT] Moving Boot%04x to position %u (front)\n", ++ BootOrder.Data[Index], UsbPos); ++ BootOptionAux = BootOrder.Data[UsbPos]; ++ BootOrder.Data[UsbPos] = BootOrder.Data[Index]; ++ BootOrder.Data[Index] = BootOptionAux; ++ UsbPos++; ++ } ++ } ++ } else { ++ // Remove USB devices from boot order completely (DeprioritizeUsb / nousb) ++ UINTN NonUsbPos = 0; ++ for (UINTN Index = 0; Index < BootOptionCount; Index++) { ++ if (!IsUSBDevice(BootOptions[Index].FilePath)) { ++ BootOrder.Data[NonUsbPos] = BootOptions[Index].OptionNumber; ++ NonUsbPos++; ++ } else { ++ Print (L"[EVE-BOOT] Removing Boot%04x from boot order (USB device)\n", ++ BootOptions[Index].OptionNumber); ++ } ++ } ++ BootOrder.Produced = NonUsbPos; ++ Print (L"[EVE-BOOT] Removed %u USB devices from boot order\n", UsbCount); ++ } ++ ++ // Log new boot order AFTER changes ++ Print (L"[EVE-BOOT] Boot order AFTER (%u entries):\n", BootOrder.Produced); ++ for (UINTN Index = 0; Index < BootOrder.Produced; Index++) { ++ Print (L"[EVE-BOOT] [%u] Boot%04x\n", Index, BootOrder.Data[Index]); ++ } + + // + // See Table 10 in the UEFI Spec 2.3.1 with Errata C for the required + // attributes. + // ++ Print (L"[EVE-BOOT] Setting BootOrder variable...\n"); + Status = gRT->SetVariable ( + L"BootOrder", + &gEfiGlobalVariableGuid, +@@ -142,18 +315,18 @@ SetBootOrderFromEve ( + BootOrder.Data + ); + if (EFI_ERROR (Status)) { +- DEBUG ((DEBUG_ERROR, "%a: setting BootOrder: %r\n", __FUNCTION__, +- Status)); ++ Print (L"[EVE-BOOT] SetVariable FAILED: %r\n", Status); + goto ErrorFreeBootOrder; + } + +- DEBUG ((DEBUG_INFO, "%a: setting BootOrder: success\n", __FUNCTION__)); ++ Print (L"[EVE-BOOT] Boot order modified SUCCESSFULLY!\n"); ++ Print (L"[EVE-BOOT] ========================================\n"); + + ErrorFreeBootOrder: + FreePool (BootOrder.Data); + + ErrorFreeBootOptions: + EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount); +- + return Status; + } ++ +diff --git a/OvmfPkg/Library/EveBootOrderLib/EveBootOrderLib.inf b/OvmfPkg/Library/EveBootOrderLib/EveBootOrderLib.inf +index 5e11df7242..98a7ae715a 100644 +--- a/OvmfPkg/Library/EveBootOrderLib/EveBootOrderLib.inf ++++ b/OvmfPkg/Library/EveBootOrderLib/EveBootOrderLib.inf +@@ -35,6 +35,7 @@ + DevicePathLib + BaseMemoryLib + OrderedCollectionLib ++ UefiLib + + [Guids] + gEfiGlobalVariableGuid +-- +2.43.0 + diff --git a/pkg/xen-tools/Dockerfile b/pkg/xen-tools/Dockerfile index ba10a6d3e06..5599a866b0d 100644 --- a/pkg/xen-tools/Dockerfile +++ b/pkg/xen-tools/Dockerfile @@ -3,7 +3,7 @@ # Copyright (c) 2023-2026 Zededa, Inc. # SPDX-License-Identifier: Apache-2.0 -FROM lfedge/eve-uefi:b3ef9ca37c99439c776673aeba83c52ea8b84626 AS uefi-build +FROM lfedge/eve-uefi:417cf0c3acf434fb0f775e8a588ae7b6e3523d6d AS uefi-build FROM lfedge/eve-alpine:745ae9066273c73b0fd879c4ba4ff626a8392d04 AS runx-build ENV BUILD_PKGS="mkinitfs gcc musl-dev e2fsprogs chrony agetty" RUN eve-alpine-deploy.sh @@ -115,7 +115,8 @@ RUN if [ "$(uname -m)" = "x86_64" ]; then rm -f qemu-system-i386 && ln -s "qemu- COPY --from=uefi-build / /uefi/ RUN mkdir -p /out/usr/lib/xen/boot && cp /uefi/OVMF.fd /out/usr/lib/xen/boot/ovmf.bin && \ cp /uefi/OVMF_PVH.fd /out/usr/lib/xen/boot/ovmf-pvh.bin && \ - [ -f /uefi/OVMF_CODE.fd ] && cp /uefi/OVMF_CODE.fd /out/usr/lib/xen/boot/OVMF_CODE.fd || : + [ -f /uefi/OVMF_CODE.fd ] && cp /uefi/OVMF_CODE.fd /out/usr/lib/xen/boot/OVMF_CODE.fd || : && \ + [ -f /uefi/igd.rom ] && cp /uefi/igd.rom /out/usr/lib/xen/boot/igd.rom || : # We need to keep a slim profile, which means removing things we don't need RUN rm -rf /out/usr/lib/libxen*.a /out/usr/lib/libxl*.a /out/usr/lib/debug /out/usr/lib/python* diff --git a/pkg/xen-tools/patches-4.19.0/x86_64/08-Revert__Revert__vfio_pci-quirks_c__Disable_stolen_memory_for_igd_VFIO__.patch b/pkg/xen-tools/patches-4.19.0/x86_64/08-Revert__Revert__vfio_pci-quirks_c__Disable_stolen_memory_for_igd_VFIO__.patch deleted file mode 100644 index 26c63f729d6..00000000000 --- a/pkg/xen-tools/patches-4.19.0/x86_64/08-Revert__Revert__vfio_pci-quirks_c__Disable_stolen_memory_for_igd_VFIO__.patch +++ /dev/null @@ -1,124 +0,0 @@ -From 9eb4883e57224db64588d724d5764cdccb164c7d Mon Sep 17 00:00:00 2001 -From: Petr Fedchenkov -Date: Mon, 11 Oct 2021 17:30:15 +0300 -Subject: [PATCH] Revert "Revert "vfio/pci-quirks.c: Disable stolen memory for - igd VFIO"" and adopts it to the new qemu with moved vfio_probe_igd_bar4_quirk - into igd.c. - -This reverts commit 93587e3af3a259deac89c12863d93653d69d22b8. ---- - tools/qemu-xen/hw/vfio/igd.c | 64 ++++++++++++++++++++++++++++++--------------------- - 1 file changed, 38 insertions(+), 26 deletions(-) - -diff --git a/tools/qemu-xen/hw/vfio/igd.c b/tools/qemu-xen/hw/vfio/igd.c -index 64e332746b..573cd53803 100644 ---- a/tools/qemu-xen/hw/vfio/igd.c -+++ b/tools/qemu-xen/hw/vfio/igd.c -@@ -377,14 +377,45 @@ void vfio_probe_igd_bar4_quirk(VFIOPCIDevice *vdev, int nr) - uint16_t cmd_orig, cmd; - Error *err = NULL; - -+ /* This must be an Intel VGA device. */ -+ if (!vfio_pci_is(vdev, PCI_VENDOR_ID_INTEL, PCI_ANY_ID) || -+ !vfio_is_vga(vdev) || nr != 4 ) { -+ return; -+ } -+ - /* -- * This must be an Intel VGA device at address 00:02.0 for us to even -- * consider enabling legacy mode. The vBIOS has dependencies on the -- * PCI bus address. -+ * IGD is not a standard, they like to change their specs often. We -+ * only attempt to support back to SandBridge and we hope that newer -+ * devices maintain compatibility with generation 8. - */ -- if (!vfio_pci_is(vdev, PCI_VENDOR_ID_INTEL, PCI_ANY_ID) || -- !vfio_is_vga(vdev) || nr != 4 || -- &vdev->pdev != pci_find_device(pci_device_root_bus(&vdev->pdev), -+ gen = igd_gen(vdev); -+ if (gen != 6 && gen != 8) { -+ error_report("IGD device %s is unsupported by IGD quirks, " -+ "try SandyBridge or newer", vdev->vbasedev.name); -+ return; -+ } -+ -+ /* -+ * Regardless of running in UPT or legacy mode, the guest graphics -+ * driver may attempt to use stolen memory, however only legacy mode -+ * has BIOS support for reserving stolen memory in the guest VM. -+ * Emulate the GMCH register in all cases and zero out the stolen -+ * memory size here. Legacy mode may request allocation and re-write -+ * this below. -+ */ -+ gmch = vfio_pci_read_config(&vdev->pdev, IGD_GMCH, 4); -+ gmch &= ~((gen < 8 ? 0x1f : 0xff) << (gen < 8 ? 3 : 8)); -+ -+ /* GMCH is read-only, emulated */ -+ pci_set_long(vdev->pdev.config + IGD_GMCH, gmch); -+ pci_set_long(vdev->pdev.wmask + IGD_GMCH, 0); -+ pci_set_long(vdev->emulated_config_bits + IGD_GMCH, ~0); -+ -+ /* -+ * This must be at address 00:02.0 for us to even onsider enabling -+ * legacy mode. The vBIOS has dependencies on the PCI bus address. -+ */ -+ if (&vdev->pdev != pci_find_device(pci_device_root_bus(&vdev->pdev), - 0, PCI_DEVFN(0x2, 0))) { - return; - } -@@ -403,18 +434,6 @@ void vfio_probe_igd_bar4_quirk(VFIOPCIDevice *vdev, int nr) - return; - } - -- /* -- * IGD is not a standard, they like to change their specs often. We -- * only attempt to support back to SandBridge and we hope that newer -- * devices maintain compatibility with generation 8. -- */ -- gen = igd_gen(vdev); -- if (gen != 6 && gen != 8) { -- error_report("IGD device %s is unsupported in legacy mode, " -- "try SandyBridge or newer", vdev->vbasedev.name); -- return; -- } -- - /* - * Most of what we're doing here is to enable the ROM to run, so if - * there's no ROM, there's no point in setting up this quirk. -@@ -470,8 +489,6 @@ void vfio_probe_igd_bar4_quirk(VFIOPCIDevice *vdev, int nr) - goto out; - } - -- gmch = vfio_pci_read_config(&vdev->pdev, IGD_GMCH, 4); -- - /* - * If IGD VGA Disable is clear (expected) and VGA is not already enabled, - * try to enable it. Probably shouldn't be using legacy mode without VGA, -@@ -540,12 +557,12 @@ void vfio_probe_igd_bar4_quirk(VFIOPCIDevice *vdev, int nr) - * when IVD (IGD VGA Disable) is clear, but the claim is that it's unused, - * so let's not waste VM memory for it. - */ -- gmch &= ~((gen < 8 ? 0x1f : 0xff) << (gen < 8 ? 3 : 8)); - - if (vdev->igd_gms) { - if (vdev->igd_gms <= 0x10) { - gms_mb = vdev->igd_gms * 32; - gmch |= vdev->igd_gms << (gen < 8 ? 3 : 8); -+ pci_set_long(vdev->pdev.config + IGD_GMCH, gmch); - } else { - error_report("Unsupported IGD GMS value 0x%x", vdev->igd_gms); - vdev->igd_gms = 0; -@@ -565,11 +582,6 @@ void vfio_probe_igd_bar4_quirk(VFIOPCIDevice *vdev, int nr) - fw_cfg_add_file(fw_cfg_find(), "etc/igd-bdsm-size", - bdsm_size, sizeof(*bdsm_size)); - -- /* GMCH is read-only, emulated */ -- pci_set_long(vdev->pdev.config + IGD_GMCH, gmch); -- pci_set_long(vdev->pdev.wmask + IGD_GMCH, 0); -- pci_set_long(vdev->emulated_config_bits + IGD_GMCH, ~0); -- - /* BDSM is read-write, emulated. The BIOS needs to be able to write it */ - pci_set_long(vdev->pdev.config + IGD_BDSM, 0); - pci_set_long(vdev->pdev.wmask + IGD_BDSM, ~0); --- -2.30.2 diff --git a/pkg/xen-tools/patches-4.19.0/x86_64/08-vfio-igd-backport-igd-gen.patch b/pkg/xen-tools/patches-4.19.0/x86_64/08-vfio-igd-backport-igd-gen.patch new file mode 100644 index 00000000000..f5ae8605e21 --- /dev/null +++ b/pkg/xen-tools/patches-4.19.0/x86_64/08-vfio-igd-backport-igd-gen.patch @@ -0,0 +1,112 @@ +From e130d1db4dc882bfbdf7d57c3e80432f5b39838f Mon Sep 17 00:00:00 2001 +From: Mikhail Malyshev +Date: Tue, 31 Mar 2026 20:34:07 +0000 +Subject: [PATCH 1/2] vfio/igd: backport igd_gen() with Gen7-Gen12 device ID + detection + +Backport upstream QEMU's igd_gen() which returns correct generation +numbers for all Intel IGD device families: + + Gen 7: Haswell, Valleyview/Bay Trail + Gen 8: Broadwell, Cherryview + Gen 9: Skylake, Kaby Lake, Coffee Lake, Comet Lake, Gemini Lake, + Broxton/Apollo Lake + Gen 11: Ice Lake, Elkhart Lake, Jasper Lake + Gen 12: Tiger Lake, Rocket Lake, Alder Lake, Raptor Lake + +The old code only distinguished gen 6, gen 8, and returned 8 for all +unknown device IDs. This made generation-specific checks (e.g. for +BDSM register offset) ineffective on Gen9+ hardware. + +Also change the default return from 8 to -1 (unknown), matching +upstream. Callers that check gen < 0 will now correctly reject +unrecognised devices rather than silently treating them as gen 8. + +Signed-off-by: Mikhail Malyshev +--- + hw/vfio/igd.c | 62 ++++++++++++++++++++++++++++++--------------------- + 1 file changed, 37 insertions(+), 25 deletions(-) + +diff --git a/tools/qemu-xen/hw/vfio/igd.c b/tools/qemu-xen/hw/vfio/igd.c +index d320d032a7..c105c9993f 100644 +--- a/tools/qemu-xen/hw/vfio/igd.c ++++ b/tools/qemu-xen/hw/vfio/igd.c +@@ -59,38 +59,50 @@ + */ + static int igd_gen(VFIOPCIDevice *vdev) + { +- if ((vdev->device_id & 0xfff) == 0xa84) { +- return 8; /* Broxton */ ++ /* ++ * Device IDs for Broxton/Apollo Lake are 0x0a84, 0x1a84, 0x1a85, 0x5a84 ++ * and 0x5a85, match bit 11:1 here. ++ * Prefix 0x0a is taken by Haswell, this rule should be matched first. ++ */ ++ if ((vdev->device_id & 0xffe) == 0xa84) { ++ return 9; + } + + switch (vdev->device_id & 0xff00) { +- /* Old, untested, unavailable, unknown */ +- case 0x0000: +- case 0x2500: +- case 0x2700: +- case 0x2900: +- case 0x2a00: +- case 0x2e00: +- case 0x3500: +- case 0xa000: +- return -1; +- /* SandyBridge, IvyBridge, ValleyView, Haswell */ +- case 0x0100: +- case 0x0400: +- case 0x0a00: +- case 0x0c00: +- case 0x0d00: +- case 0x0f00: ++ case 0x0100: /* SandyBridge, IvyBridge */ + return 6; +- /* BroadWell, CherryView, SkyLake, KabyLake */ +- case 0x1600: +- case 0x1900: +- case 0x2200: +- case 0x5900: ++ case 0x0400: /* Haswell */ ++ case 0x0a00: /* Haswell */ ++ case 0x0c00: /* Haswell */ ++ case 0x0d00: /* Haswell */ ++ case 0x0f00: /* Valleyview/Bay Trail */ ++ return 7; ++ case 0x1600: /* Broadwell */ ++ case 0x2200: /* Cherryview */ + return 8; ++ case 0x1900: /* Skylake */ ++ case 0x3100: /* Gemini Lake */ ++ case 0x5900: /* Kaby Lake */ ++ case 0x3e00: /* Coffee Lake */ ++ case 0x9B00: /* Comet Lake */ ++ return 9; ++ case 0x8A00: /* Ice Lake */ ++ case 0x4500: /* Elkhart Lake */ ++ case 0x4E00: /* Jasper Lake */ ++ return 11; ++ case 0x9A00: /* Tiger Lake */ ++ case 0x4C00: /* Rocket Lake */ ++ case 0x4600: /* Alder Lake */ ++ case 0xA700: /* Raptor Lake */ ++ return 12; + } + +- return 8; /* Assume newer is compatible */ ++ /* ++ * Unfortunately, Intel changes its specification quite often. This makes ++ * it impossible to use a suitable default value for unknown devices. ++ * Return -1 for not applying any generation-specific quirks. ++ */ ++ return -1; + } + + typedef struct VFIOIGDQuirk { +-- +2.43.0 + diff --git a/pkg/xen-tools/patches-4.19.0/x86_64/09-vfio-igd-q35-uefi-bdsm-opregion.patch b/pkg/xen-tools/patches-4.19.0/x86_64/09-vfio-igd-q35-uefi-bdsm-opregion.patch new file mode 100644 index 00000000000..9219d2e59f9 --- /dev/null +++ b/pkg/xen-tools/patches-4.19.0/x86_64/09-vfio-igd-q35-uefi-bdsm-opregion.patch @@ -0,0 +1,294 @@ +From 144f3a0976837cdc93140be659c2c05b1134cd40 Mon Sep 17 00:00:00 2001 +From: Mikhail Malyshev +Date: Tue, 31 Mar 2026 20:56:59 +0000 +Subject: [PATCH] vfio/igd: q35/UEFI iGPU passthrough (GMCH/BDSM/fw_cfg/GMS + fix) + +Enable Intel iGPU passthrough on q35/UEFI machines by restructuring +vfio_probe_igd_bar4_quirk() so that GMCH emulation, BDSM emulation, +and the etc/igd-bdsm-size fw_cfg write all happen before the BDF and +LPC bridge checks. On q35 the legacy path never runs ("Sorry Q35"), +so without this change IgdAssignmentDxe never gets the fw_cfg data it +needs and BDSM retains the host physical address. + +Changes: + +- Move the Intel VGA check (vendor + class + BAR4) to the top, before + the BDF requirement. The BDF check now only gates legacy mode, not + the register emulation needed for UPT/q35. + +- Accept any recognised generation (gen >= 0) instead of the old + hard-coded gen == 6 || gen == 8, which silently blocked Gen9-Gen12 + devices. + +- Write etc/igd-bdsm-size to fw_cfg before the BDF check with correct + GMS decoding for all generations including Gen9+ Atom SKUs (codes + 0xf0-0xff use 4 MB granularity, matching i915_gem_stolen.c). + +- Emulate BDSM at the correct PCI config offset depending on + generation: 0x5C (32-bit) for Gen6-Gen10, 0xC0 (64-bit) for Gen11+. + Initialize to zero so IgdAssignmentDxe's idempotency guard + ("if BDSM != 0, skip") is not falsely triggered by the host PA. + +- Zero GMS in the emulated GMCH before the BDF check. In legacy mode + (i440fx), the igd_gms device option can restore a non-zero GMS value. + +Co-developed-by: Sergio Santos +Signed-off-by: Sergio Santos +Signed-off-by: Mikhail Malyshev +--- + hw/vfio/igd.c | 189 ++++++++++++++++++++++++++++++++++++++------------ + 1 file changed, 143 insertions(+), 46 deletions(-) + +diff --git a/tools/qemu-xen/hw/vfio/igd.c b/tools/qemu-xen/hw/vfio/igd.c +index c105c9993f..3b52c471fc 100644 +--- a/tools/qemu-xen/hw/vfio/igd.c ++++ b/tools/qemu-xen/hw/vfio/igd.c +@@ -112,7 +112,8 @@ typedef struct VFIOIGDQuirk { + } VFIOIGDQuirk; + + #define IGD_GMCH 0x50 /* Graphics Control Register */ +-#define IGD_BDSM 0x5c /* Base Data of Stolen Memory */ ++#define IGD_BDSM 0x5c /* Base Data of Stolen Memory (32-bit, Gen6-Gen10) */ ++#define IGD_BDSM_GEN11 0xc0 /* Base Data of Stolen Memory (64-bit, Gen11+) */ + + + /* +@@ -387,19 +388,144 @@ void vfio_probe_igd_bar4_quirk(VFIOPCIDevice *vdev, int nr) + VFIOIGDQuirk *igd; + PCIDevice *lpc_bridge; + int i, ret, ggms_mb, gms_mb = 0, gen; +- uint64_t *bdsm_size; + uint32_t gmch; + uint16_t cmd_orig, cmd; + Error *err = NULL; + ++ /* This must be an Intel VGA device. */ ++ if (!vfio_pci_is(vdev, PCI_VENDOR_ID_INTEL, PCI_ANY_ID) || ++ !vfio_is_vga(vdev) || nr != 4) { ++ return; ++ } ++ + /* +- * This must be an Intel VGA device at address 00:02.0 for us to even +- * consider enabling legacy mode. The vBIOS has dependencies on the +- * PCI bus address. ++ * IGD is not a standard, they like to change their specs often. We ++ * support Sandy Bridge (gen 6) through Raptor Lake (gen 12) and assume ++ * future devices maintain compatibility with the gen 8 GMCH layout. + */ +- if (!vfio_pci_is(vdev, PCI_VENDOR_ID_INTEL, PCI_ANY_ID) || +- !vfio_is_vga(vdev) || nr != 4 || +- &vdev->pdev != pci_find_device(pci_device_root_bus(&vdev->pdev), ++ gen = igd_gen(vdev); ++ if (gen < 0) { ++ error_report("IGD device %s has unknown generation, skipping IGD quirks", ++ vdev->vbasedev.name); ++ return; ++ } ++ ++ /* ++ * Regardless of running in UPT or legacy mode, the guest graphics ++ * driver may attempt to use stolen memory, however only legacy mode ++ * has BIOS support for reserving stolen memory in the guest VM. ++ * Emulate the GMCH register in all cases and zero out the stolen ++ * memory size here. Legacy mode may request allocation and re-write ++ * this below. ++ */ ++ gmch = vfio_pci_read_config(&vdev->pdev, IGD_GMCH, 4); ++ ++ /* ++ * Write the GMS-based stolen memory size to fw_cfg so that OVMF's ++ * IgdAssignmentDxe can allocate guest stolen memory and set BDSM ++ * (0x5C for Gen6-10, 0xC0 for Gen11+). We do this before the BDF ++ * and LPC bridge checks so the entry is available on q35 where the ++ * legacy-mode path never runs ("Sorry Q35"). ++ * ++ * GMS encoding (gen >= 9): codes 0x01-0xef map to N*32 MB; codes ++ * 0xf0-0xff map to (N-0xf0+1)*4 MB (4 MB granularity, Atom SKUs). ++ * For gen < 9 the field is at most 5 bits so only 0x01-0x10 are valid. ++ */ ++ { ++ uint32_t gms = (gmch >> (gen < 8 ? 3 : 8)) & (gen < 8 ? 0x1f : 0xff); ++ uint64_t bdsm_bytes; ++ if (gen < 9 || gms < 0xf0) { ++ bdsm_bytes = (uint64_t)gms * 32 * MiB; ++ } else { ++ bdsm_bytes = (uint64_t)(gms - 0xf0 + 1) * 4 * MiB; ++ } ++ error_report("IGD bdsm-size: device %04x gen=%d gmch=0x%08x " ++ "gms=%u bdsm_bytes=%" PRIu64, ++ vdev->device_id, gen, gmch, gms, bdsm_bytes); ++ if (gms) { ++ FWCfgState *fw_cfg = fw_cfg_find(); ++ if (fw_cfg) { ++ uint64_t *bdsm_size = g_malloc(sizeof(*bdsm_size)); ++ *bdsm_size = cpu_to_le64(bdsm_bytes); ++ fw_cfg_add_file(fw_cfg, "etc/igd-bdsm-size", ++ bdsm_size, sizeof(*bdsm_size)); ++ error_report("IGD bdsm-size: wrote etc/igd-bdsm-size = %" ++ PRIu64 " bytes to fw_cfg", bdsm_bytes); ++ } else { ++ error_report("IGD bdsm-size: fw_cfg not found, skipping"); ++ } ++ } else { ++ error_report("IGD bdsm-size: gms=0, no stolen memory " ++ "reported by host GMCH"); ++ } ++ } ++ ++ /* ++ * GMCH is read-only, emulated. Keep the original GMS value so the ++ * guest driver sees the correct stolen memory size. Upstream QEMU ++ * does not zero GMS unless the user explicitly sets x-igd-gms. ++ * The legacy path below may override GMS via the igd_gms option. ++ */ ++ pci_set_long(vdev->pdev.config + IGD_GMCH, gmch); ++ pci_set_long(vdev->pdev.wmask + IGD_GMCH, 0); ++ pci_set_long(vdev->emulated_config_bits + IGD_GMCH, ~0); ++ ++ /* ++ * BDSM is read-write, emulated. Initialize to 0 here (before the BDF ++ * and LPC bridge checks) so that: ++ * 1. On q35 ("Sorry Q35"), where the legacy path never runs, OVMF's ++ * IgdAssignmentDxe sees BDSM=0 and proceeds to allocate guest ++ * stolen memory, writing the guest PA back here. ++ * 2. The guest driver reads the guest PA written by OVMF, not the ++ * host PA (which would cause DMA into the wrong guest memory). ++ * 3. IgdAssignmentDxe's idempotency check ("if BDSM != 0, skip") ++ * is not falsely triggered by the host's physical address. ++ * ++ * Gen11+ (Ice Lake and later) moved BDSM to offset 0xC0 as a 64-bit ++ * register. Emulate the correct offset so IgdAssignmentDxe and the ++ * guest driver read/write the right place. ++ */ ++ if (gen >= 11) { ++ pci_set_quad(vdev->pdev.config + IGD_BDSM_GEN11, 0); ++ pci_set_quad(vdev->pdev.wmask + IGD_BDSM_GEN11, ~0ULL); ++ pci_set_quad(vdev->emulated_config_bits + IGD_BDSM_GEN11, ~0ULL); ++ } else { ++ pci_set_long(vdev->pdev.config + IGD_BDSM, 0); ++ pci_set_long(vdev->pdev.wmask + IGD_BDSM, ~0); ++ pci_set_long(vdev->emulated_config_bits + IGD_BDSM, ~0); ++ } ++ ++ /* ++ * Clear stale GTT entries left over from host POST. Without this, ++ * the GPU's display engine may DMA to host physical addresses via ++ * old GTT mappings, causing IOMMU faults. The legacy path (below) ++ * also clears the GTT, but on q35 we never reach it. ++ */ ++ { ++ uint16_t cmd_orig, cmd; ++ int j; ++ ++ if (pread(vdev->vbasedev.fd, &cmd_orig, sizeof(cmd_orig), ++ vdev->config_offset + PCI_COMMAND) == sizeof(cmd_orig)) { ++ cmd = cmd_orig | PCI_COMMAND_IO; ++ pwrite(vdev->vbasedev.fd, &cmd, sizeof(cmd), ++ vdev->config_offset + PCI_COMMAND); ++ ++ for (j = 1; j < vfio_igd_gtt_max(vdev); j += 4) { ++ vfio_region_write(&vdev->bars[4].region, 0, j, 4); ++ vfio_region_write(&vdev->bars[4].region, 4, 0, 4); ++ } ++ ++ pwrite(vdev->vbasedev.fd, &cmd_orig, sizeof(cmd_orig), ++ vdev->config_offset + PCI_COMMAND); ++ } ++ } ++ ++ /* ++ * This must be at address 00:02.0 for us to even consider enabling ++ * legacy mode. The vBIOS has dependencies on the PCI bus address. ++ */ ++ if (&vdev->pdev != pci_find_device(pci_device_root_bus(&vdev->pdev), + 0, PCI_DEVFN(0x2, 0))) { + return; + } +@@ -418,18 +544,6 @@ void vfio_probe_igd_bar4_quirk(VFIOPCIDevice *vdev, int nr) + return; + } + +- /* +- * IGD is not a standard, they like to change their specs often. We +- * only attempt to support back to SandBridge and we hope that newer +- * devices maintain compatibility with generation 8. +- */ +- gen = igd_gen(vdev); +- if (gen != 6 && gen != 8) { +- error_report("IGD device %s is unsupported in legacy mode, " +- "try SandyBridge or newer", vdev->vbasedev.name); +- return; +- } +- + /* + * Most of what we're doing here is to enable the ROM to run, so if + * there's no ROM, there's no point in setting up this quirk. +@@ -485,8 +599,6 @@ void vfio_probe_igd_bar4_quirk(VFIOPCIDevice *vdev, int nr) + return; + } + +- gmch = vfio_pci_read_config(&vdev->pdev, IGD_GMCH, 4); +- + /* + * If IGD VGA Disable is clear (expected) and VGA is not already enabled, + * try to enable it. Probably shouldn't be using legacy mode without VGA, +@@ -549,17 +661,18 @@ void vfio_probe_igd_bar4_quirk(VFIOPCIDevice *vdev, int nr) + } + + /* +- * Assume we have no GMS memory, but allow it to be overridden by device +- * option (experimental). The spec doesn't actually allow zero GMS when +- * when IVD (IGD VGA Disable) is clear, but the claim is that it's unused, +- * so let's not waste VM memory for it. ++ * In legacy mode, zero GMS to avoid wasting VM memory, then allow ++ * override via the igd_gms device option. (In UPT/q35 mode we keep ++ * the original GMS so the guest driver knows the stolen memory size.) + */ + gmch &= ~((gen < 8 ? 0x1f : 0xff) << (gen < 8 ? 3 : 8)); ++ pci_set_long(vdev->pdev.config + IGD_GMCH, gmch); + + if (vdev->igd_gms) { + if (vdev->igd_gms <= 0x10) { + gms_mb = vdev->igd_gms * 32; + gmch |= vdev->igd_gms << (gen < 8 ? 3 : 8); ++ pci_set_long(vdev->pdev.config + IGD_GMCH, gmch); + } else { + error_report("Unsupported IGD GMS value 0x%x", vdev->igd_gms); + vdev->igd_gms = 0; +@@ -567,27 +680,11 @@ void vfio_probe_igd_bar4_quirk(VFIOPCIDevice *vdev, int nr) + } + + /* +- * Request reserved memory for stolen memory via fw_cfg. VM firmware +- * must allocate a 1MB aligned reserved memory region below 4GB with +- * the requested size (in bytes) for use by the Intel PCI class VGA +- * device at VM address 00:02.0. The base address of this reserved +- * memory region must be written to the device BDSM register at PCI +- * config offset 0x5C. ++ * etc/igd-bdsm-size is written before the BDF check (above) so that it ++ * is available on q35 machines where the legacy path never runs. ++ * Do not write it again here to avoid a duplicate fw_cfg key. ++ * BDSM emulation is also set up before the BDF check. + */ +- bdsm_size = g_malloc(sizeof(*bdsm_size)); +- *bdsm_size = cpu_to_le64((ggms_mb + gms_mb) * MiB); +- fw_cfg_add_file(fw_cfg_find(), "etc/igd-bdsm-size", +- bdsm_size, sizeof(*bdsm_size)); +- +- /* GMCH is read-only, emulated */ +- pci_set_long(vdev->pdev.config + IGD_GMCH, gmch); +- pci_set_long(vdev->pdev.wmask + IGD_GMCH, 0); +- pci_set_long(vdev->emulated_config_bits + IGD_GMCH, ~0); +- +- /* BDSM is read-write, emulated. The BIOS needs to be able to write it */ +- pci_set_long(vdev->pdev.config + IGD_BDSM, 0); +- pci_set_long(vdev->pdev.wmask + IGD_BDSM, ~0); +- pci_set_long(vdev->emulated_config_bits + IGD_BDSM, ~0); + + /* + * This IOBAR gives us access to GTTADR, which allows us to write to +-- +2.43.0 + diff --git a/pkg/xen-tools/patches-4.19.0/x86_64/10-vfio-igd-bar0-bdsm-mirror.patch b/pkg/xen-tools/patches-4.19.0/x86_64/10-vfio-igd-bar0-bdsm-mirror.patch new file mode 100644 index 00000000000..df0c069cf4c --- /dev/null +++ b/pkg/xen-tools/patches-4.19.0/x86_64/10-vfio-igd-bar0-bdsm-mirror.patch @@ -0,0 +1,143 @@ +From eaeba971b492d4914535e9bde13b82bf57468a32 Mon Sep 17 00:00:00 2001 +From: Mikhail Malyshev +Date: Wed, 1 Apr 2026 01:13:31 +0000 +Subject: [PATCH] vfio/igd: add BAR0 BDSM MMIO mirror quirk for q35/UEFI + +Backport the BAR0 BDSM mirror quirk from upstream QEMU. + +The GPU reads BDSM through both PCI config space and MMIO (BAR0 + +0x1080C0). Without this quirk, the PCI config read returns the +emulated guest PA (correct) while the BAR0 MMIO read returns the host +PA from real hardware (wrong). The driver sees conflicting values and +crashes. + +Add vfio_probe_igd_bar0_quirk() which intercepts reads/writes at BAR0 +offset 0x1080C0 and redirects them to the emulated PCI config BDSM +register (0x5C for Gen6-10, 0xC0 for Gen11+). + +Signed-off-by: Mikhail Malyshev +--- + hw/vfio/igd.c | 81 ++++++++++++++++++++++++++++++++++++++++++++ + hw/vfio/pci-quirks.c | 1 + + hw/vfio/pci.h | 1 + + 3 files changed, 83 insertions(+) + +diff --git a/tools/qemu-xen/hw/vfio/igd.c b/tools/qemu-xen/hw/vfio/igd.c +index 3b52c471fc..37e985da6f 100644 +--- a/tools/qemu-xen/hw/vfio/igd.c ++++ b/tools/qemu-xen/hw/vfio/igd.c +@@ -378,6 +378,87 @@ static const MemoryRegionOps vfio_igd_index_quirk = { + .endianness = DEVICE_LITTLE_ENDIAN, + }; + ++/* ++ * IGD BAR0 BDSM mirror quirk — backported from upstream QEMU. ++ * ++ * The GPU reads BDSM through MMIO (BAR0 + 0x1080C0) as well as through ++ * PCI config space. Without this quirk the MMIO read returns the host ++ * physical address, which disagrees with the emulated PCI config value. ++ * Intercept reads/writes at this offset and redirect them to the emulated ++ * PCI config BDSM register. ++ */ ++typedef struct IGDBdsmMirrorQuirk { ++ VFIOPCIDevice *vdev; ++ uint32_t bar_offset; /* offset within BAR0 MMIO */ ++ uint32_t config_offset; /* PCI config offset (0x5C or 0xC0) */ ++ uint8_t bar; ++ MemoryRegion mem; ++} IGDBdsmMirrorQuirk; ++ ++static uint64_t igd_bdsm_mirror_read(void *opaque, hwaddr addr, unsigned size) ++{ ++ IGDBdsmMirrorQuirk *mirror = opaque; ++ VFIOPCIDevice *vdev = mirror->vdev; ++ ++ /* Read and discard from real hardware in case it has side effects */ ++ (void)vfio_region_read(&vdev->bars[mirror->bar].region, ++ addr + mirror->bar_offset, size); ++ ++ return vfio_pci_read_config(&vdev->pdev, ++ mirror->config_offset + addr, size); ++} ++ ++static void igd_bdsm_mirror_write(void *opaque, hwaddr addr, ++ uint64_t data, unsigned size) ++{ ++ IGDBdsmMirrorQuirk *mirror = opaque; ++ VFIOPCIDevice *vdev = mirror->vdev; ++ ++ vfio_pci_write_config(&vdev->pdev, ++ mirror->config_offset + addr, data, size); ++} ++ ++static const MemoryRegionOps igd_bdsm_mirror_ops = { ++ .read = igd_bdsm_mirror_read, ++ .write = igd_bdsm_mirror_write, ++ .endianness = DEVICE_LITTLE_ENDIAN, ++}; ++ ++#define IGD_BDSM_MMIO_OFFSET 0x1080C0 ++ ++void vfio_probe_igd_bar0_quirk(VFIOPCIDevice *vdev, int nr) ++{ ++ IGDBdsmMirrorQuirk *mirror; ++ VFIOQuirk *quirk; ++ int gen; ++ ++ if (!vfio_pci_is(vdev, PCI_VENDOR_ID_INTEL, PCI_ANY_ID) || ++ !vfio_is_vga(vdev) || nr != 0) { ++ return; ++ } ++ ++ gen = igd_gen(vdev); ++ if (gen < 6) { ++ return; ++ } ++ ++ quirk = vfio_quirk_alloc(1); ++ mirror = g_malloc0(sizeof(*mirror)); ++ mirror->vdev = vdev; ++ mirror->bar = nr; ++ mirror->bar_offset = IGD_BDSM_MMIO_OFFSET; ++ mirror->config_offset = (gen < 11) ? IGD_BDSM : IGD_BDSM_GEN11; ++ ++ memory_region_init_io(&quirk->mem[0], OBJECT(vdev), &igd_bdsm_mirror_ops, ++ mirror, "vfio-igd-bdsm-quirk", ++ (gen < 11) ? 4 : 8); ++ memory_region_add_subregion_overlap(vdev->bars[nr].region.mem, ++ IGD_BDSM_MMIO_OFFSET, ++ &quirk->mem[0], 1); ++ ++ QLIST_INSERT_HEAD(&vdev->bars[nr].quirks, quirk, next); ++} ++ + void vfio_probe_igd_bar4_quirk(VFIOPCIDevice *vdev, int nr) + { + g_autofree struct vfio_region_info *rom = NULL; +diff --git a/tools/qemu-xen/hw/vfio/pci-quirks.c b/tools/qemu-xen/hw/vfio/pci-quirks.c +index 39dae72497..d37f722cce 100644 +--- a/tools/qemu-xen/hw/vfio/pci-quirks.c ++++ b/tools/qemu-xen/hw/vfio/pci-quirks.c +@@ -1259,6 +1259,7 @@ void vfio_bar_quirk_setup(VFIOPCIDevice *vdev, int nr) + vfio_probe_nvidia_bar0_quirk(vdev, nr); + vfio_probe_rtl8168_bar2_quirk(vdev, nr); + #ifdef CONFIG_VFIO_IGD ++ vfio_probe_igd_bar0_quirk(vdev, nr); + vfio_probe_igd_bar4_quirk(vdev, nr); + #endif + } +diff --git a/tools/qemu-xen/hw/vfio/pci.h b/tools/qemu-xen/hw/vfio/pci.h +index bf67df2fbc..5ad090a229 100644 +--- a/tools/qemu-xen/hw/vfio/pci.h ++++ b/tools/qemu-xen/hw/vfio/pci.h +@@ -215,6 +215,7 @@ void vfio_setup_resetfn_quirk(VFIOPCIDevice *vdev); + bool vfio_add_virt_caps(VFIOPCIDevice *vdev, Error **errp); + void vfio_quirk_reset(VFIOPCIDevice *vdev); + VFIOQuirk *vfio_quirk_alloc(int nr_mem); ++void vfio_probe_igd_bar0_quirk(VFIOPCIDevice *vdev, int nr); + void vfio_probe_igd_bar4_quirk(VFIOPCIDevice *vdev, int nr); + + extern const PropertyInfo qdev_prop_nv_gpudirect_clique; +-- +2.43.0 + diff --git a/pkg/xen-tools/patches-4.19.0/x86_64/11-vfio-igd-diagnostic-logging.patch b/pkg/xen-tools/patches-4.19.0/x86_64/11-vfio-igd-diagnostic-logging.patch new file mode 100644 index 00000000000..baebaa8a8a8 --- /dev/null +++ b/pkg/xen-tools/patches-4.19.0/x86_64/11-vfio-igd-diagnostic-logging.patch @@ -0,0 +1,108 @@ +From ea8f44d5832669e05b93adff377031deedbb467a Mon Sep 17 00:00:00 2001 +From: Mikhail Malyshev +Date: Wed, 1 Apr 2026 01:41:02 +0000 +Subject: [PATCH] vfio/igd: add diagnostic logging for BDSM/GMCH/GTT/BAR0 + mirror + +Log host BDSM value vs emulated, emulated GMCH with GMS, GTT clearing +count, and BAR0 BDSM mirror reads/writes. Temporary diagnostics to +debug iGPU passthrough driver initialization failures. + +Signed-off-by: Mikhail Malyshev +--- + hw/vfio/igd.c | 41 +++++++++++++++++++++++++++++++++++------ + 1 file changed, 35 insertions(+), 6 deletions(-) + +diff --git a/tools/qemu-xen/hw/vfio/igd.c b/tools/qemu-xen/hw/vfio/igd.c +index 37e985da6f..1b38bfb227 100644 +--- a/tools/qemu-xen/hw/vfio/igd.c ++++ b/tools/qemu-xen/hw/vfio/igd.c +@@ -401,11 +401,15 @@ static uint64_t igd_bdsm_mirror_read(void *opaque, hwaddr addr, unsigned size) + VFIOPCIDevice *vdev = mirror->vdev; + + /* Read and discard from real hardware in case it has side effects */ +- (void)vfio_region_read(&vdev->bars[mirror->bar].region, +- addr + mirror->bar_offset, size); +- +- return vfio_pci_read_config(&vdev->pdev, +- mirror->config_offset + addr, size); ++ uint64_t hw_val = vfio_region_read(&vdev->bars[mirror->bar].region, ++ addr + mirror->bar_offset, size); ++ uint64_t emu_val = vfio_pci_read_config(&vdev->pdev, ++ mirror->config_offset + addr, size); ++ ++ error_report("IGD BAR0 BDSM mirror: READ config=0x%x+0x%" PRIx64 ++ " hw=0x%" PRIx64 " -> returning emulated=0x%" PRIx64, ++ mirror->config_offset, (uint64_t)addr, hw_val, emu_val); ++ return emu_val; + } + + static void igd_bdsm_mirror_write(void *opaque, hwaddr addr, +@@ -414,6 +418,9 @@ static void igd_bdsm_mirror_write(void *opaque, hwaddr addr, + IGDBdsmMirrorQuirk *mirror = opaque; + VFIOPCIDevice *vdev = mirror->vdev; + ++ error_report("IGD BAR0 BDSM mirror: WRITE config=0x%x+0x%" PRIx64 ++ " data=0x%" PRIx64, ++ mirror->config_offset, (uint64_t)addr, data); + vfio_pci_write_config(&vdev->pdev, + mirror->config_offset + addr, data, size); + } +@@ -551,6 +558,8 @@ void vfio_probe_igd_bar4_quirk(VFIOPCIDevice *vdev, int nr) + pci_set_long(vdev->pdev.wmask + IGD_GMCH, 0); + pci_set_long(vdev->emulated_config_bits + IGD_GMCH, ~0); + ++ error_report("IGD quirk: emulated GMCH=0x%08x (GMS preserved)", gmch); ++ + /* + * BDSM is read-write, emulated. Initialize to 0 here (before the BDF + * and LPC bridge checks) so that: +@@ -566,6 +575,22 @@ void vfio_probe_igd_bar4_quirk(VFIOPCIDevice *vdev, int nr) + * register. Emulate the correct offset so IgdAssignmentDxe and the + * guest driver read/write the right place. + */ ++ { ++ /* Read host BDSM for diagnostic logging */ ++ uint64_t host_bdsm = 0; ++ if (gen >= 11) { ++ pread(vdev->vbasedev.fd, &host_bdsm, 8, ++ vdev->config_offset + IGD_BDSM_GEN11); ++ } else { ++ uint32_t tmp = 0; ++ pread(vdev->vbasedev.fd, &tmp, 4, ++ vdev->config_offset + IGD_BDSM); ++ host_bdsm = tmp; ++ } ++ error_report("IGD quirk: host BDSM=0x%" PRIx64 " (offset 0x%x), " ++ "setting emulated BDSM=0 for gen %d", ++ host_bdsm, (gen >= 11) ? IGD_BDSM_GEN11 : IGD_BDSM, gen); ++ } + if (gen >= 11) { + pci_set_quad(vdev->pdev.config + IGD_BDSM_GEN11, 0); + pci_set_quad(vdev->pdev.wmask + IGD_BDSM_GEN11, ~0ULL); +@@ -588,17 +613,21 @@ void vfio_probe_igd_bar4_quirk(VFIOPCIDevice *vdev, int nr) + + if (pread(vdev->vbasedev.fd, &cmd_orig, sizeof(cmd_orig), + vdev->config_offset + PCI_COMMAND) == sizeof(cmd_orig)) { ++ int gtt_max; + cmd = cmd_orig | PCI_COMMAND_IO; + pwrite(vdev->vbasedev.fd, &cmd, sizeof(cmd), + vdev->config_offset + PCI_COMMAND); + +- for (j = 1; j < vfio_igd_gtt_max(vdev); j += 4) { ++ gtt_max = vfio_igd_gtt_max(vdev); ++ error_report("IGD quirk: clearing %d GTT entries", gtt_max / 4); ++ for (j = 1; j < gtt_max; j += 4) { + vfio_region_write(&vdev->bars[4].region, 0, j, 4); + vfio_region_write(&vdev->bars[4].region, 4, 0, 4); + } + + pwrite(vdev->vbasedev.fd, &cmd_orig, sizeof(cmd_orig), + vdev->config_offset + PCI_COMMAND); ++ error_report("IGD quirk: GTT cleared"); + } + } + +-- +2.43.0 +