Based on experiments and reverse engineering about the mysterious IO BAR4, it appears that the current quirk implementation is incorrect. As discussed in a previous mail thread [1], current implementation believes VBIOS is writing HPA of Data Stolen Memory (DSM) in GTT entries, so it intercepts and writes (addr - Host BDSM + Guest BDSM) instead, probably believes the addresses are hardcoded in VBIOS.
With disassembling a VBIOS of Intel Sandy/Ivy Bridge and Haswell [2] (thankfully there is only a few 32-bit out instructions), VBIOS read BDSM from pci config space, which is programmed by SeaBIOS [3] in guest. That is to say, VBIOS actually writes GPA when programming GTT initial entries, the current quirk is incorrect. The change was tested on a Kaby Lake HD620 (Gen 9) by comparing GTT entries read from MMIO BAR0 and IO BAR4. This patchset also creates a new function vfio_config_quirk_setup() for the config space quirk previously in vfio_probe_igd_bar4_quirk(). The OpRegion quirk in vfio_realize() is also merged into the config qurk. Finally all the igd-related codes are moved to igd.c. [1] https://lore.kernel.org/qemu-devel/b373a030-5ccf-418c-9213-865ddc674...@gmail.com/ [2] https://winraid.level1techs.com/t/offer-intel-sandy-ivy-bridge-and-haswell-vbios-modules/30272 [3] https://gitlab.com/qemu-project/seabios/-/blob/1.12-stable/src/fw/pciinit.c#L319-332 Related VBIOS disassembly: # read BDSM 6498: 66 53 push %ebx 649a: 66 2e 83 3e 94 64 00 cmpl $0x0,%cs:0x6494 # BDSM already read? 64a1: 74 07 je 0x64aa 64a3: 66 2e a1 94 64 mov %cs:0x6494,%eax 64a8: eb 0f jmp 0x64b9 64aa: b8 5e 10 mov $0x105e,%ax # 5e == 5c + 2, that's why shl 16 later? # ((2 << 11) + 0x5e) 64ad: e8 55 05 call 0x6a05 # read config space via port cf8/cfc 64b0: 66 c1 e0 10 shl $0x10,%eax # eax << 16 64b4: 66 2e a3 94 64 mov %eax,%cs:0x6494 # save BDSM 64b9: 66 5b pop %ebx 64bb: c3 ret # program single GTT entry, esi: addr, eax: data 6d16: 66 50 push %eax 6d18: 52 push %dx 6d19: 2e 8b 16 4a e4 mov %cs:-0x1bb6,%dx # saved MMIO_Index port 6d1e: 66 96 xchg %eax,%esi 6d20: 66 ef out %eax,(%dx) # write MMIO_Index 6d22: 2e 8b 16 4c e4 mov %cs:-0x1bb4,%dx # saved MMIO_Data port 6d27: 66 96 xchg %eax,%esi 6d29: 66 83 c8 01 or $0x1,%eax # set valid bit 6d2d: 66 ef out %eax,(%dx) # write MMIO_Data 6d2f: 5a pop %dx 6d30: 66 58 pop %eax 6d32: c3 ret # program GTT entries, esi: entry addr, eax: page addr e929: 51 push %cx e92a: e8 6b 7b call 0x6498 # read BDSM e92d: 25 00 e0 and $0xe000,%ax e930: 66 83 c8 01 or $0x1,%eax # valid bit e934: 66 be 01 00 00 00 mov $0x1,%esi # gtt access bit in addr e93a: e8 d9 83 call 0x6d16 # single entry routine e93d: 66 83 c6 04 add $0x4,%esi # next entry e941: 66 05 00 10 00 00 add $0x1000,%eax # next page e947: e2 f1 loop 0xe93a e949: 59 pop %cx e94a: c3 ret Observed layout of the undocumented MMIO_Index register: 31 2 1 0 +-------------------------------------------------------------------+ | Offset | Rsvd | Sel | +-------------------------------------------------------------------+ - Offset: Byte offset in specified region, 4-byte aligned. - Sel: Region selector 0: MMIO register region (first half of MMIO BAR0) 1: GTT region (second half of MMIO BAR0). Pre Gen11 only. Changelog: v2: * Move the OpRegion quirk from vfio_realize() to vfio_probe_igd_config_ quirk(), as proposed in v1, making it reasonable to return bool. Link: https://lore.kernel.org/qemu-devel/20250122171731.40444-1-tomitamo...@gmail.com/ Tomita Moeko (5): vfio/igd: remove GTT write quirk in IO BAR 4 vfio/pci: add placeholder for device-specific config space quirks vfio/igd: refactor vfio_probe_igd_bar4_quirk() into pci config quirk vfio/igd: do not include GTT stolen size in etc/igd-bdsm-size vfio/igd: handle x-igd-opregion in vfio_probe_igd_config_quirk() hw/vfio/igd.c | 381 ++++++++++++++----------------------------- hw/vfio/pci-quirks.c | 51 +----- hw/vfio/pci.c | 29 +--- hw/vfio/pci.h | 7 +- 4 files changed, 136 insertions(+), 332 deletions(-) -- 2.45.2