[PATCH v5 0/3] vfio/igd: Fix garbled screen on IGD passthrough with legacy VBIOS

Tomita Moeko posted 3 patches 2 weeks, 5 days ago
Patches applied successfully (tree, apply log)
git fetch https://github.com/patchew-project/qemu tags/patchew/20260707083550.25765-1-tomitamoeko@gmail.com
Maintainers: "Michael S. Tsirkin" <mst@redhat.com>, Alex Williamson <alex@shazbot.org>, "Cédric Le Goater" <clg@redhat.com>, Tomita Moeko <tomitamoeko@gmail.com>
hw/pci/pci.c                |   4 ++
hw/vfio/igd-stubs.c         |   5 ++
hw/vfio/igd.c               | 129 ++++++++++++++++++++++++++++++++++++
hw/vfio/pci-quirks.c        |   5 ++
hw/vfio/pci.c               |   2 +
hw/vfio/pci.h               |   3 +
hw/vfio/trace-events        |   1 +
include/hw/pci/pci_device.h |   1 +
8 files changed, 150 insertions(+)
[PATCH v5 0/3] vfio/igd: Fix garbled screen on IGD passthrough with legacy VBIOS
Posted by Tomita Moeko 2 weeks, 5 days ago
This series fixes the regression that on IGD passthrough with legacy
BIOS boot and VBIOS, the screen is garbled during BIOS POST and GRUB
(which uses standard VGA output routines), starting from QEMU 10.0.
Though the kernel i915 driver still works, it reports an error about
the initial GTT programmed by VBIOS is using invalid address.

i915 0000:00:02.0: [drm] *ERROR* Initial plane programming using invalid range, dma_addr=0x00000000db200000 ((null) [0x00000000baf00000-0x00000000beefffff])

With the help of AI disassembling the VBIOS image dumped from host, it
is found that the VBIOS itself implements a routine like:

    uint32_t get_BDSM() {
        static uint32_t saved = 0;
        if (saved != 0) {
            return saved;
        }
        return read_pci_config(BDSM_REG);
    }

And the saved value is not cleared after initialization. Given that IGD
devices don't have a real ROM BAR, the VBIOS image read by default from
host is actually the VBIOS shadow RAM region, containing host-side
modifications like the saved BDSM value above during POST. When the
image is executed in guest, it still uses the saved host BDSM (HPA)
instead of the value programmed by SeaBIOS in config space (GPA). This
address mismatch leads to the garbled screen and i915 error.

The previous solution, c4c45e943e51 ("vfio/pci: Intel graphics legacy
mode assignment"), adjusts GTT entry addresses to (addr - host BDSM +
guest BDSM) to workaround that. But it is removed in 5aed8b0f0be2
("vfio/igd: Remove GTT write quirk in IO BAR 4") due to inconsistent
values in MMIO BAR0 and IO BAR4. Considering it's unsafe to expose HPA
to guest, a ROM quirk clearing the saved value in VBIOS image is
introduced to fix the issue.

During debugging, it is also found that IGD VBIOS ROM doesn't always
match the actual IGD device ID, due to the fact that IGD of the same
CPU family has multiple device IDs but shares the same ROM image.
However, SeaBIOS checks the device ID strictly and refuses to run if
IDs does not match. Currently only the default path, reading ROM from
kernel patches the device ID, but the romfile path doesn't. So the ROM
ID patching logic is also refactored in this patch series to also handle
the romfile path.

These changes are tested on Haswell platform with legacy BIOS boot, by
K S Maan. Thanks to K S Maan for continuous help on locating and testing
the issue!

Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3093
Reported-by: K S Maan <kirandeepmaan45@gmail.com>

Changelog:
v5:
* Keep the current ID and checksum patching logic in vfio_pci_load_rom()
  since it is not IGD-specific, as pointed out by Alex. The IGD-specific
  quirk is now invoked after the generic patching. The ID and checksum
  patching is duplicated in vfio_igd_legacy_rom_quirk() to handle the
  romfile path, since the generic patching is not invoked on romfile.
* Picked up the Michael's Acked-by on patch 1.
* Reduced from 4 to 3 patches.
Link: https://lore.kernel.org/all/20260701182035.96010-1-tomitamoeko@gmail.com/t

v4:
* Reworked per review feedback to keep IGD-specific workarounds out of
  the generic PCI code. Instead of recalculating the checksum in
  hw/pci/pci.c, a single generic romfile_fixup hook is added for device-
  specific ROM patching. Now both kernel ROM BAR and romfile paths share
  the same quirk, so the saved BDSM in user-provided romfile will also
  get cleared.
* Reduced from 7 to 4 patches.
Link: https://lore.kernel.org/all/20260617100646.28326-1-tomitamoeko@gmail.com/t

v3:
* Refactor ROM checksum calculation and patching logic as Alex's comment
* Fix boundary checks as comments in v2.
Link: https://lore.kernel.org/all/20260608134559.23971-1-tomitamoeko@gmail.com/t

v2:
* New patch 2/7 to fix regression with EFI option ROMs
* Refine logic in ROM ID and checksum patching
* Reorder patch 4 and 5 for cleaner bisection
* Address comments from v1
Link: https://lore.kernel.org/all/20260603173355.36121-1-tomitamoeko@gmail.com/t

Tomita Moeko (3):
  hw/pci: Introduce romfile_fixup hook in PCIDevice
  vfio/igd: Patch device ID for romfile-provided VBIOS
  vfio/igd: Clear saved BDSM in legacy VBIOS ROM at load time

 hw/pci/pci.c                |   4 ++
 hw/vfio/igd-stubs.c         |   5 ++
 hw/vfio/igd.c               | 129 ++++++++++++++++++++++++++++++++++++
 hw/vfio/pci-quirks.c        |   5 ++
 hw/vfio/pci.c               |   2 +
 hw/vfio/pci.h               |   3 +
 hw/vfio/trace-events        |   1 +
 include/hw/pci/pci_device.h |   1 +
 8 files changed, 150 insertions(+)

-- 
2.53.0
Re: [PATCH v5 0/3] vfio/igd: Fix garbled screen on IGD passthrough with legacy VBIOS
Posted by Alex Williamson 2 weeks, 4 days ago
On Tue,  7 Jul 2026 16:35:47 +0800
Tomita Moeko <tomitamoeko@gmail.com> wrote:

> This series fixes the regression that on IGD passthrough with legacy
> BIOS boot and VBIOS, the screen is garbled during BIOS POST and GRUB
> (which uses standard VGA output routines), starting from QEMU 10.0.
> Though the kernel i915 driver still works, it reports an error about
> the initial GTT programmed by VBIOS is using invalid address.
> 
> i915 0000:00:02.0: [drm] *ERROR* Initial plane programming using invalid range, dma_addr=0x00000000db200000 ((null) [0x00000000baf00000-0x00000000beefffff])
> 
> With the help of AI disassembling the VBIOS image dumped from host, it
> is found that the VBIOS itself implements a routine like:
> 
>     uint32_t get_BDSM() {
>         static uint32_t saved = 0;
>         if (saved != 0) {
>             return saved;
>         }
>         return read_pci_config(BDSM_REG);
>     }
> 
> And the saved value is not cleared after initialization. Given that IGD
> devices don't have a real ROM BAR, the VBIOS image read by default from
> host is actually the VBIOS shadow RAM region, containing host-side
> modifications like the saved BDSM value above during POST. When the
> image is executed in guest, it still uses the saved host BDSM (HPA)
> instead of the value programmed by SeaBIOS in config space (GPA). This
> address mismatch leads to the garbled screen and i915 error.
> 
> The previous solution, c4c45e943e51 ("vfio/pci: Intel graphics legacy
> mode assignment"), adjusts GTT entry addresses to (addr - host BDSM +
> guest BDSM) to workaround that. But it is removed in 5aed8b0f0be2
> ("vfio/igd: Remove GTT write quirk in IO BAR 4") due to inconsistent
> values in MMIO BAR0 and IO BAR4. Considering it's unsafe to expose HPA
> to guest, a ROM quirk clearing the saved value in VBIOS image is
> introduced to fix the issue.

How is it unsafe to expose an HPA?  The initial values in the PCI BARs
expose their HPAs, it's not unsafe.  The issue here is that the host
value is latched into the BIOS, which breaks the virtualization since
we're not mapping the GTT at the same address in the VM.
 
> During debugging, it is also found that IGD VBIOS ROM doesn't always
> match the actual IGD device ID, due to the fact that IGD of the same
> CPU family has multiple device IDs but shares the same ROM image.
> However, SeaBIOS checks the device ID strictly and refuses to run if
> IDs does not match. Currently only the default path, reading ROM from
> kernel patches the device ID, but the romfile path doesn't. So the ROM
> ID patching logic is also refactored in this patch series to also handle
> the romfile path.

This is a separate feature from the regression fix.  Up until now we've
only modified the ROM as provided through the vfio interface as the
user is out of the loop.  Once the user is in the loop and providing
the ROM via a file, we've always assumed it's the user's responsibility
to fixup the ROM and QEMU should pass it through unmodified.  I have a
tool[1] in my github that has served this purpose, allowing a device ID
to be written into the ROM image and the checksum recalculated.  We've
always required a ROM provided as a romfile to be pre-modified to match
the device ID.  Even the existing fixup in the PCI code is only for
default ROMs, not the PCIDevice.romfile image.

As I understand this series, we're using the rationale that removing
the GTT hack introduced a regression in QEMU and the fix we've
discovered for that regression requires clearing a field in the ROM
image, therefore we want to do that regardless of whether the ROM image
is provided through vfio or by the user... and while we're already
mangling the user provided image, we might as well fixup the device ID.

Also, as I'm reading the gitlab issue resolved by patch 3, it's
reported against the ROM read through vfio path, not the romfile path.
So for the issue presented, this could be a single patch that adds an
igd callout/stub to vfio_pci_load_rom() to zero the BDSM field, and
we'd require the romfile path to provide a pristine ROM image, with
matching device ID (already a requirement) and now the BDSM workaround.

Given that QEMU 11.1 is already in soft-freeze, that sounds more like
the self-contained, no additional feature fix that we need.
Effectively patch 3 with the BDSM zeroing directly wired through
vfio_pci_load_rom() and a Fixes: tag referencing the 10.0 commit
removing the previous GTT hack.  Thanks,

Alex

[1]https://github.com/awilliam/rom-parser
Re: [PATCH v5 0/3] vfio/igd: Fix garbled screen on IGD passthrough with legacy VBIOS
Posted by K S Maan 2 weeks, 4 days ago
Tested-by: K S Maan <kirandeepmaan45@gmail.com>

On 7/7/26 2:05 PM, Tomita Moeko wrote:
> This series fixes the regression that on IGD passthrough with legacy
> BIOS boot and VBIOS, the screen is garbled during BIOS POST and GRUB
> (which uses standard VGA output routines), starting from QEMU 10.0.
> Though the kernel i915 driver still works, it reports an error about
> the initial GTT programmed by VBIOS is using invalid address.
>
> i915 0000:00:02.0: [drm] *ERROR* Initial plane programming using invalid range, dma_addr=0x00000000db200000 ((null) [0x00000000baf00000-0x00000000beefffff])
>
> With the help of AI disassembling the VBIOS image dumped from host, it
> is found that the VBIOS itself implements a routine like:
>
>      uint32_t get_BDSM() {
>          static uint32_t saved = 0;
>          if (saved != 0) {
>              return saved;
>          }
>          return read_pci_config(BDSM_REG);
>      }
>
> And the saved value is not cleared after initialization. Given that IGD
> devices don't have a real ROM BAR, the VBIOS image read by default from
> host is actually the VBIOS shadow RAM region, containing host-side
> modifications like the saved BDSM value above during POST. When the
> image is executed in guest, it still uses the saved host BDSM (HPA)
> instead of the value programmed by SeaBIOS in config space (GPA). This
> address mismatch leads to the garbled screen and i915 error.
>
> The previous solution, c4c45e943e51 ("vfio/pci: Intel graphics legacy
> mode assignment"), adjusts GTT entry addresses to (addr - host BDSM +
> guest BDSM) to workaround that. But it is removed in 5aed8b0f0be2
> ("vfio/igd: Remove GTT write quirk in IO BAR 4") due to inconsistent
> values in MMIO BAR0 and IO BAR4. Considering it's unsafe to expose HPA
> to guest, a ROM quirk clearing the saved value in VBIOS image is
> introduced to fix the issue.
>
> During debugging, it is also found that IGD VBIOS ROM doesn't always
> match the actual IGD device ID, due to the fact that IGD of the same
> CPU family has multiple device IDs but shares the same ROM image.
> However, SeaBIOS checks the device ID strictly and refuses to run if
> IDs does not match. Currently only the default path, reading ROM from
> kernel patches the device ID, but the romfile path doesn't. So the ROM
> ID patching logic is also refactored in this patch series to also handle
> the romfile path.
>
> These changes are tested on Haswell platform with legacy BIOS boot, by
> K S Maan. Thanks to K S Maan for continuous help on locating and testing
> the issue!
>
> Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3093
> Reported-by: K S Maan <kirandeepmaan45@gmail.com>
>
> Changelog:
> v5:
> * Keep the current ID and checksum patching logic in vfio_pci_load_rom()
>    since it is not IGD-specific, as pointed out by Alex. The IGD-specific
>    quirk is now invoked after the generic patching. The ID and checksum
>    patching is duplicated in vfio_igd_legacy_rom_quirk() to handle the
>    romfile path, since the generic patching is not invoked on romfile.
> * Picked up the Michael's Acked-by on patch 1.
> * Reduced from 4 to 3 patches.
> Link: https://lore.kernel.org/all/20260701182035.96010-1-tomitamoeko@gmail.com/t
>
> v4:
> * Reworked per review feedback to keep IGD-specific workarounds out of
>    the generic PCI code. Instead of recalculating the checksum in
>    hw/pci/pci.c, a single generic romfile_fixup hook is added for device-
>    specific ROM patching. Now both kernel ROM BAR and romfile paths share
>    the same quirk, so the saved BDSM in user-provided romfile will also
>    get cleared.
> * Reduced from 7 to 4 patches.
> Link: https://lore.kernel.org/all/20260617100646.28326-1-tomitamoeko@gmail.com/t
>
> v3:
> * Refactor ROM checksum calculation and patching logic as Alex's comment
> * Fix boundary checks as comments in v2.
> Link: https://lore.kernel.org/all/20260608134559.23971-1-tomitamoeko@gmail.com/t
>
> v2:
> * New patch 2/7 to fix regression with EFI option ROMs
> * Refine logic in ROM ID and checksum patching
> * Reorder patch 4 and 5 for cleaner bisection
> * Address comments from v1
> Link: https://lore.kernel.org/all/20260603173355.36121-1-tomitamoeko@gmail.com/t
>
> Tomita Moeko (3):
>    hw/pci: Introduce romfile_fixup hook in PCIDevice
>    vfio/igd: Patch device ID for romfile-provided VBIOS
>    vfio/igd: Clear saved BDSM in legacy VBIOS ROM at load time
>
>   hw/pci/pci.c                |   4 ++
>   hw/vfio/igd-stubs.c         |   5 ++
>   hw/vfio/igd.c               | 129 ++++++++++++++++++++++++++++++++++++
>   hw/vfio/pci-quirks.c        |   5 ++
>   hw/vfio/pci.c               |   2 +
>   hw/vfio/pci.h               |   3 +
>   hw/vfio/trace-events        |   1 +
>   include/hw/pci/pci_device.h |   1 +
>   8 files changed, 150 insertions(+)
>