[PATCH v4 6/6] xen/igd: use custom option ROM if provided

Chuck Zmudzinski <[email protected]> Fri, 31 Jul 2026 20:17:30 -0400
Newsgroups gmane.comp.emulators.xen.devel,gmane.comp.emulators.qemu,gmane.comp.emulators.qemu.stable
Message-ID <[email protected]>
Since in some cases the option ROM is not readable from sysfs
on the host, provide the option to use a custom option ROM file
instead that, for example, could be extracted from BIOS or UEFI
firmware and modified as needed for use with a particular Intel
IGD device.

The file must be named "igd.rom" and be located in a directory
configured at build time as a Qemu firmware directory and its
size should be a power of two, and it must be compatible with
the particular Intel IGD device being passed through.

If provided, the "igd.rom" file will be used as the option ROM
instead of the option ROM file epxosed in the host sysfs.

If no "igd.rom" file is provided, this patch has no effect.

Signed-off-by: Chuck Zmudzinski <[email protected]>
---
Changes in v4:
  - v4 is the first version of the series that has this patch

Sorry for the length of these notes but there are many things
to say about this patch that are not obvious to persons without
some experience of actually trying to use the option ROM of an
Intel IGD when it is passed through to a Xen HVM guest.

This patch is primarily for providing a way to add Intel IGD
support for the OvmfXen platform to get graphics output during
early boot from modern Intel IGD devices that are only compatible
with UEFI for graphics output during early boot.

Note this patch is not necessary for successful operation of the
Intel IGD in the guest once the guest OS drivers have loaded. It
is only needed as part of the patchset necessary to provide
graphics output from the Intel IGD in the guest during early
boot when using newer devices that are only compatible with UEFI
for graphics output during early boot. Most older devices that are
compatible with legacy VGA BIOS will work with Seabios without
this patch, but they will need Patch 3 of this patchset to work
with Seabios.

Some notes on adding Intel IGD support for the OvmfXen platform:

It is necessary to provide an EFI graphics output protocol (GOP)
driver to the guest to get output from the Intel IGD before the
guest OS loads the graphics drivers when the guest uses UEFI.
This GOP driver is essentially the replacement of the VBIOS
driver that applied to older devices that use legacy bios, as
described here:

https://www.intel.com/content/www/us/en/support/articles/000005749/graphics.html

Unfortunately, with modern Intel IGD devices, the EFI GOP driver
is not provided to the guest in the usual way of providing firmware
for a PCI device in the option ROM of the real PCI device. So I
included this patch in this patchset to provide a way to expose
the EFI GOP driver to the guest. I was able to extract the
GOP driver for my device using the UEFI bios update file from
the motherboard manufacturer and the UEFITool available here:

https://github.com/longsoft/uefitool

That EFI driver can be wrapped into an option ROM using the
EfiRom bin wrapper that is part of the edk2 project:

https://github.com/tianocore/edk2/blob/master/BaseTools/BinWrappers/PosixLike/EfiRom

I tried setting the 'romfile' member of the PCIDevice struct that
is used by KVM/VFIO Qemu devices and emulated Qemu PCI devices, but
that did not work with Xen PCI passthrough devices. Neither Seabios
nor the OvmfXen platform could detect the option ROM in the guest
with that method of exposing an option ROM to the guest. So I
implemented this approach of substituting the 'rom' file exposed by
sysfs with an administrator-provided file instead of using 'romfile'.

In the commit message I mentioned the size of the rom file "should"
be a power of two. I mentioned this because the code in pci.c that
handles the 'romfile' setting for PCI devices enforces this
requirement strictly on the romfile that Qemu emulated or VFIO
devices use. However, I do not know for sure whether or not the rom 
file is strictly required to have a size of a power of two, so that
is why I say it should be a power of two. In my testing, I zero pad
the "igd.rom" file so it has a size of a power of two. I will accept
the suggestions of experts on this question about the appropriate size
of the option ROM file (I am not such an expert!).

As mentioned in the message accompanying Patch 4 of this patchset,
the official edk2 project does not provide support for the Intel
IGD, but some OVMF patches for Intel IGD support are available
online for KVM/VFIO guests, such as at the links below (they apply
to the OvmfPkgX64 platform):

https://github.com/cmd2001/build-edk2-gvtd
https://eci.intel.com/docs/3.3/components/kvm-hypervisor.html#build-ovmf-fd-for-kvm
https://github.com/LongQT-sea/intel-igpu-passthru

With such patches it is reported that the passed through Intel
IGD device lights up the display during early boot from OVMF
and the guest bootloader in KVM/VFIO guests provided that the
administrator provides the correct ROM file via the 'romfile'
setting for the passed thorugh Intel iGD device and applies
appropriate patches to the OvmfPkgX64 platform.

It should also be possible to add Intel IGD support for the OvmfXen
platform also but I have not seen any such patches online for OvmfXen
and if anyone knows of such patches online I would be interested to
be informed about them. I am also working on my own patches to
add Intel IGD support to the OvmfXen platform, in private for now.
If anyone is interested, I can make the work I have done so far
toward this goal avalable online.

 hw/xen/xen_pt_load_rom.c | 47 +++++++++++++++++++++++++++-------------
 1 file changed, 32 insertions(+), 15 deletions(-)

diff --git a/hw/xen/xen_pt_load_rom.c b/hw/xen/xen_pt_load_rom.c
index eaf0ae1..6c2aa8f 100644
--- a/hw/xen/xen_pt_load_rom.c
+++ b/hw/xen/xen_pt_load_rom.c
@@ -2,6 +2,7 @@
  * This is splited from hw/i386/kvm/pci-assign.c
  */
 #include "qemu/osdep.h"
+#include "qemu/datadir.h"
 #include "qapi/error.h"
 #include "qemu/error-report.h"
 #include "hw/pci/pci.h"
@@ -13,9 +14,9 @@
  * need to be modified.
  *
  * For such cases, use this function to get a pointer to the option ROM
- * from sysfs. Caller has the responsibility to edit the option ROM as
- * needed, call pci_register_bar to register the modified option ROM,
- * and set has_rom to true for the PCI device.
+ * from a user provided romfile or sysfs. Caller has the responsibility
+ * to edit the option ROM as needed, call pci_register_bar to register
+ * the modified option ROM, and set has_rom to true for the PCI device.
  *
  * This function must be called before xen_pt_register_regions is called
  * because if xen_pt_register_regions is called first, it will register
@@ -32,17 +33,27 @@ void *pci_assign_dev_load_option_rom(PCIDevice *dev,
     struct stat st;
     void *ptr = NULL;
     Object *owner = OBJECT(dev);
+    g_autofree const char *fname = g_strdup("igd.rom");
+    g_autofree const char *path = qemu_find_file(QEMU_FILE_TYPE_BIOS, fname);
+    bool sysfs = false;
 
     /* If loading ROM from file, pci handles it */
     if (dev->romfile || !dev->rom_bar) {
         return NULL;
     }
 
-    snprintf(rom_file, sizeof(rom_file),
-             "/sys/bus/pci/devices/%04x:%02x:%02x.%01x/rom",
-             domain, bus, slot, function);
+    if (path) {
+        snprintf(rom_file, sizeof(rom_file), "%s", path);
+        XEN_PT_LOG(dev, "Using Intel IGD romfile %s "
+                   "(administratior provided)\n", path);
+    } else {
+        snprintf(rom_file, sizeof(rom_file),
+                 "/sys/bus/pci/devices/%04x:%02x:%02x.%01x/rom",
+                 domain, bus, slot, function);
+        sysfs = true;
+        XEN_PT_LOG(dev, "Using Intel IGD romfile from host sysfs\n");
+    }
 
-    /* Write "1" to the ROM file to enable it */
     fp = fopen(rom_file, "r+");
     if (fp == NULL) {
         if (errno != ENOENT) {
@@ -55,10 +66,14 @@ void *pci_assign_dev_load_option_rom(PCIDevice *dev,
         goto close_rom;
     }
 
-    val = 1;
-    if (fwrite(&val, 1, 1, fp) != 1) {
-        goto close_rom;
+    /* Write "1" to the ROM file to enable it if using ROM from sysfs */
+    if (sysfs) {
+       val = 1;
+       if (fwrite(&val, 1, 1, fp) != 1) {
+           goto close_rom;
+       }
     }
+
     fseek(fp, 0, SEEK_SET);
 
     if (dev->romsize != UINT_MAX) {
@@ -83,11 +98,13 @@ void *pci_assign_dev_load_option_rom(PCIDevice *dev,
 
     *size = st.st_size;
 close_rom:
-    /* Write "0" to disable ROM */
-    fseek(fp, 0, SEEK_SET);
-    val = 0;
-    if (!fwrite(&val, 1, 1, fp)) {
-        XEN_PT_WARN(dev, "%s\n", "Failed to disable pci-sysfs rom file");
+    /* Write "0" to disable ROM if using ROM from sysfs */
+    if (sysfs) {
+        fseek(fp, 0, SEEK_SET);
+        val = 0;
+        if (!fwrite(&val, 1, 1, fp)) {
+            XEN_PT_WARN(dev, "%s\n", "Failed to disable pci-sysfs rom file");
+        }
     }
     fclose(fp);
 
-- 
2.52.0