fix: boot failure on VirtualBox legacy-BIOS VMs (AC'97 probed as HDA)

VirtualBox default VMs expose an AC'97 audio controller (8086:2415,
class 04/subclass 01) whose BAR0 is an I/O-space BAR. The IntelHDA
driver matched any Intel multimedia subclass, and ReadBar0 masked the
I/O BAR's port number into a bogus 'physical address' that MapMMIO
panicked on (non-page-aligned), halting boot.

Two fixes:
- IntelHDA now matches only subclass 0x03 (HD Audio); AC'97 (0x01) is
  a different programming model and is not claimed.
- ReadBar0 returns 0 (no usable MMIO BAR) for I/O-space BARs instead
  of handing a port number to MapMMIO.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-08 16:33:54 +02:00
parent 24e5973c4b
commit ce5f407513
2 changed files with 13 additions and 3 deletions
+5 -3
View File
@@ -149,13 +149,15 @@ namespace Drivers {
ProbeNvme,
},
// Order 7: Intel HDA — Normal phase, match vendor=0x8086 + class=0x04 (Multimedia)
// SubClass 0x01 = "Multimedia audio controller" (most Intel HDA)
// SubClass 0x03 = "Audio device" (HDA-compatible)
// SubClass 0x03 = "Audio device" = HD Audio controller.
// SubClass 0x01 = "Multimedia audio controller" = legacy AC'97
// (e.g. VirtualBox 8086:2415), which is NOT HDA and has an I/O
// BAR, not an MMIO BAR — do NOT match it here.
{
"IntelHDA",
0x8086, // VendorId (Intel)
0x04, // ClassCode (Multimedia)
0xFF, // SubClass (any — covers both 0x01 and 0x03)
0x03, // SubClass (0x03 = HD Audio; excludes AC'97 0x01)
0xFF, // ProgIf (any)
nullptr,
0,
+8
View File
@@ -404,6 +404,14 @@ namespace Pci {
uint64_t ReadBar0(uint8_t bus, uint8_t device, uint8_t function) {
uint32_t bar0Low = LegacyRead32(bus, device, function, (uint8_t)PCI_REG_BAR0);
// Bit 0 == 1 means this is an I/O-space BAR, not memory. The low bits of
// an I/O BAR are a port number, not a physical address, and must never be
// fed to MapMMIO (it would panic on the non-page-aligned value). Callers
// treat 0 as "no usable MMIO BAR". (e.g. VirtualBox AC'97 8086:2415.)
if (bar0Low & 0x1)
return 0;
uint64_t addr = bar0Low & 0xFFFFFFF0u;
// Check for 64-bit BAR (type field bits 2:1 == 0b10)