From b0e760659c4c951381e8916dc64dca8a53af584f Mon Sep 17 00:00:00 2001 From: Red Bear OS Date: Thu, 23 Jul 2026 20:13:17 +0900 Subject: [PATCH] pcid: no panic on PCI 3.0 fallback config access; warning sweep - fallback.rs: config reads at offset >= 256 (PCIe extended space) now return the PCI-standard 0xFFFFFFFF 'absent' value and writes are dropped, instead of panicking the PCI daemon. This is the exact behavior of real hardware and Linux's CF8 path on MCFG-less machines, and it lets MSI-X feature discovery degrade to INTx cleanly. Found by the first driver-manager QEMU gate (i440fx): pcid panicked at fallback.rs:65 and the boot hung. - driver_handler.rs: drop vestigial func param from read_full_device_id. - driver_interface/mod.rs: use Option::insert's return value directly (must_use) instead of discarding and re-reading as_ref. --- drivers/pcid/src/cfg_access/fallback.rs | 16 ++++++++++++---- drivers/pcid/src/driver_handler.rs | 4 ++-- drivers/pcid/src/driver_interface/mod.rs | 4 ++-- 3 files changed, 16 insertions(+), 8 deletions(-) diff --git a/drivers/pcid/src/cfg_access/fallback.rs b/drivers/pcid/src/cfg_access/fallback.rs index fac0514ae5..e583ba75e5 100644 --- a/drivers/pcid/src/cfg_access/fallback.rs +++ b/drivers/pcid/src/cfg_access/fallback.rs @@ -61,8 +61,13 @@ impl ConfigRegionAccess for Pci { Self::set_iopl(); - let offset = - u8::try_from(offset).expect("offset too large for PCI 3.0 configuration space"); + // PCI 3.0 I/O-port config space is 256 bytes. Reads beyond it + // (PCIe extended space) must return the PCI-standard "absent" + // value, exactly like real hardware and Linux's CF8 path — + // panicking here kills the PCI daemon on MCFG-less machines. + let Ok(offset) = u8::try_from(offset) else { + return u32::MAX; + }; let address = Self::address(address, offset); Pio::::new(0xCF8).write(address); @@ -74,8 +79,11 @@ impl ConfigRegionAccess for Pci { Self::set_iopl(); - let offset = - u8::try_from(offset).expect("offset too large for PCI 3.0 configuration space"); + // Writes into PCIe extended space are dropped: the region does + // not exist in PCI 3.0 I/O-port mode. + let Ok(offset) = u8::try_from(offset) else { + return; + }; let address = Self::address(address, offset); Pio::::new(0xCF8).write(address); diff --git a/drivers/pcid/src/driver_handler.rs b/drivers/pcid/src/driver_handler.rs index 96188dbc55..478ff6d922 100644 --- a/drivers/pcid/src/driver_handler.rs +++ b/drivers/pcid/src/driver_handler.rs @@ -8,7 +8,7 @@ use pcid_interface::FullDeviceId; /// Read the full PCI device ID (vendor, device, class, etc.) from /// the kernel's PCIe config space. Mirrors the data Linux's /// xhci-pci.c uses to look up per-vendor quirks. -fn read_full_device_id(pcie: &Pcie, func: &PciFunction, addr: pci_types::PciAddress) -> Option { +fn read_full_device_id(pcie: &Pcie, addr: pci_types::PciAddress) -> Option { // PCI config space offsets: // 0x00..0x01: vendor_id // 0x02..0x03: device_id @@ -55,7 +55,7 @@ impl<'a> DriverHandler<'a> { // (offsets 0x00, 0x02, 0x08) and class/subclass/interface // (offset 0x08 upper bytes). This is what Linux's // xhci-pci.c uses to look up quirks. - let device_id = read_full_device_id(pcie, &func, func.addr); + let device_id = read_full_device_id(pcie, func.addr); DriverHandler { func, device_id, diff --git a/drivers/pcid/src/driver_interface/mod.rs b/drivers/pcid/src/driver_interface/mod.rs index 5cf16e34a2..9aba6f8520 100644 --- a/drivers/pcid/src/driver_interface/mod.rs +++ b/drivers/pcid/src/driver_interface/mod.rs @@ -562,10 +562,10 @@ impl PciFunctionHandle { let ptr = NonNull::new(ptr.cast::()) .ok_or_else(|| "physmap returned null".to_string())?; - mapped_bar.insert(MappedBar { + return Ok(mapped_bar.insert(MappedBar { ptr, bar_size, - }); + })); } Ok(mapped_bar.as_ref().expect("BAR was just mapped")) }