Hi, as these patches fixes legacy mode grabled grub screen they add regression to UEFI guest where monitor won't woke up until grub timeout.
CMD used : -device vfio-pci,host=00:02.0,id=igpu,addr=2.0,x-igd-legacy-mode=off,x-igd-lpc=on,romfile=/home/maan/QemuVMs/MyGopRomfiles/InteligdGopHD4600.rom romfile is patched with intelgopdriver.efi from VfioIgdPkg repo. Here is what i915 logs say in guest with patched qemu : [ 10.823656] i915 0000:00:02.0: [drm] Found haswell (device ID 0412) integrated display version 7.00 stepping N/A [ 10.824300] i915 0000:00:02.0: [drm] VT-d active for gfx access [ 10.824763] i915 0000:00:02.0: vgaarb: deactivate vga console [ 10.824867] i915 0000:00:02.0: [drm] Using Transparent Hugepages [ 10.824871] i915 0000:00:02.0: [drm] DMAR active, disabling use of stolen memory [ 10.832111] i915 0000:00:02.0: Invalid PCI ROM header signature: expecting 0xaa55, got 0x0000 [ 10.832118] i915 0000:00:02.0: [drm] Failed to find VBIOS tables (VBT) [ 10.832154] i915 0000:00:02.0: vgaarb: VGA decodes changed: olddecodes=io+mem,decodes=io+mem:owns=io+mem [ 10.842837] i915 0000:00:02.0: [drm] Registered 3 planes with drm panic [ 10.850377] [drm] Initialized i915 1.6.0 for 0000:00:02.0 on minor 0 [ 11.678013] fbcon: i915drmfb (fb0) is primary device [ 11.748610] i915 0000:00:02.0: [drm] fb0: i915drmfb frame buffer device So look like VBT table is not expose to guest. These are the logs of stock qemu with working grub and all : [ 28.945622] i915 0000:00:02.0: [drm] Found haswell (device ID 0412) integrated display version 7.00 stepping N/A [ 28.946393] i915 0000:00:02.0: [drm] VT-d active for gfx access [ 28.961770] i915 0000:00:02.0: vgaarb: deactivate vga console [ 28.961830] i915 0000:00:02.0: [drm] Using Transparent Hugepages [ 28.961833] i915 0000:00:02.0: [drm] DMAR active, disabling use of stolen memory [ 29.016673] i915 0000:00:02.0: vgaarb: VGA decodes changed: olddecodes=io+mem,decodes=io+mem:owns=io+mem [ 29.051910] i915 0000:00:02.0: [drm] Registered 3 planes with drm panic [ 29.055360] [drm] Initialized i915 1.6.0 for 0000:00:02.0 on minor 1 [ 29.903202] fbcon: i915drmfb (fb0) is primary device [ 29.990056] i915 0000:00:02.0: [drm] fb0: i915drmfb frame buffer device Regards, K S Maan On Sat, 6 Jun 2026 at 03:32, Alex Williamson <[email protected]> wrote: > On Thu, 4 Jun 2026 01:33:54 +0800 > Tomita Moeko <[email protected]> wrote: > > diff --git a/hw/vfio/igd.c b/hw/vfio/igd.c > > index 17437ae18d..e00f6f8315 100644 > > --- a/hw/vfio/igd.c > > +++ b/hw/vfio/igd.c > > @@ -739,3 +739,109 @@ bool vfio_probe_igd_config_quirk(VFIOPCIDevice > *vdev, Error **errp) > > > > return vfio_pci_igd_config_quirk(vdev, errp); > > } > > + > > +/* > > + * IGD ROM BAR read from kernel is actually the host VBIOS shadow RAM > region, > > + * which contains host modifications. In Gen 6-9 VBIOS, the routine > below is > > + * used to get BDSM value when programming the initial GTT. > > + * xx xx xx xx v: .long ? # saved value > > + * 66 53 push %ebx > > + * 66 2e 83 3e xx xx 00 cmpl $0x0,%cs:v # is saved value > empty? > > + * 74 07 je 1f # if zero, go > compute > > + * 66 2e a1 xx xx mov %cs:v,%eax # else return > saved value > > + * eb 0f jmp 2f > > + * b8 5e 10 1: mov $0x105e,%ax # dev 00:02.0, > offset 5E > > + * e8 xx xx call pci_read_cfg_word > > + * 66 c1 e0 10 shl $0x10,%eax # left shift 16 > bits > > + * 66 2e a3 xx xx mov %eax,%cs:v # save the result > > + * 66 5b 2:pop %ebx > > + * c3 ret > > + * When running the VBIOS in guest, saved value still reflects the host > stolen > > + * memory base address, which is not correct in guest. So we need to > patch the > > + * VBIOS to clear the saved value. > > + * > > + * The unique 19-byte starts at `cmpl $0,%cs:v` and ends at `mov > $0x105e,%ax` > > + * anchors the match to the routine. Both `cs:` displacements must > reference > > + * the same offset. > > + */ > > Neat, cool quirk. > > > +static int igd_vbios_find_saved_bdsm(const uint8_t *rom, size_t > rom_size, > > + uint16_t *bdsm_offset) > > +{ > > + static const uint8_t start[] = { 0x66, 0x2e, 0x83, 0x3e }; > > + static const uint8_t middle[] = { 0x00, 0x74, 0x07, 0x66, 0x2e, > 0xa1 }; > > + static const uint8_t end[] = { 0xeb, 0x0f, 0xb8, 0x5e, 0x10 }; > > + size_t i; > > + bool found = false; > > + > > + if (rom_size < 19) { > > + return -ENOENT; > > + } > > + > > + for (i = 0; i + 19 <= rom_size; i++) { > > + if (memcmp(rom + i, start, sizeof(start)) != 0 || > > + memcmp(rom + i + 6, middle, sizeof(middle)) != 0 || > > + memcmp(rom + i + 14, end, sizeof(end)) != 0) { > > + continue; > > + } > > + > > + /* same saved value address? */ > > + if (rom[i + 4] != rom[i + 12] || rom[i + 5] != rom[i + 13]) { > > + continue; > > + } > > + > > + if (found) { > > + return -EEXIST; > > + } > > + > > + *bdsm_offset = rom[i + 4] | ((uint16_t)rom[i + 5] << 8); > > This needs a bounds check to make sure it's still within the ROM, > either here or before the memset(). > > > + found = true; > > + } > > + > > + if (!found) { > > + return -ENOENT; > > + } > > + > > + return 0; > > +} > > + > > +void vfio_probe_igd_legacy_rom_quirk(VFIOPCIDevice *vdev) > > +{ > > + int ret, gen; > > + uint16_t pcir_offset, bdsm_offset = 0; > > + uint8_t checksum; > > + > > + if (!vfio_pci_is(vdev, PCI_VENDOR_ID_INTEL, PCI_ANY_ID) || > > + !vfio_is_vga(vdev) || !vdev->vga) { > > + return; > > + } > > + > > + /* Only Gen 6~9 devices have legacy VBIOS as Option ROM */ > > + gen = igd_gen(vdev); > > + if (gen < 6 || gen > 9) { > > + return; > > + } > > + > > + if (pci_get_word(vdev->rom) != 0xaa55) { > > + return; > > + } > > + > > + /* Must be a legacy ROM */ > > + pcir_offset = pci_get_word(vdev->rom + 0x18); > > + if (pcir_offset >= vdev->rom_size || > > This gates the below test to pcir_offset + 0x14, so should be: > > if (pcir_offset + 0x14 >= vdev->rom_size || > > > + memcmp(vdev->rom + pcir_offset, "PCIR", 4) || > > + pci_get_byte(vdev->rom + pcir_offset + 0x14) != 0x00) { > > + return; > > + } > > + > > + ret = igd_vbios_find_saved_bdsm(vdev->rom, vdev->rom_size, > &bdsm_offset); > > + if (ret < 0) { > > + return; > > + } > > + > > + memset(vdev->rom + bdsm_offset, 0, sizeof(uint32_t)); > > + > > + checksum = pci_rom_calculate_checksum(vdev->rom, vdev->rom_size); > > + ((uint8_t *)vdev->rom)[6] = checksum; > > If updated per previous recommendation, this becomes: > > ((uint8_t *)vdev->rom)[6] -= checksum; > > Thanks, > Alex >
