diff --git a/drivers/hwd/src/backend/acpi.rs b/drivers/hwd/src/backend/acpi.rs index 3da41d6382..e87aa61f60 100644 --- a/drivers/hwd/src/backend/acpi.rs +++ b/drivers/hwd/src/backend/acpi.rs @@ -87,7 +87,6 @@ impl Backend for AcpiBackend { "PNP0A03" | "PNP0A08" => "PCI bus", "PNP0A05" => "Generic ACPI bus", "PNP0A06" => "Generic ACPI Extended-IO bus (EIO bus)", - "PNP0B00" => "AT real-time clock", "PNP0C01" => "System board", "PNP0C02" => "Reserved resources", "PNP0C04" => "Math coprocessor", @@ -106,6 +105,66 @@ impl Backend for AcpiBackend { } } } + // PCI interrupt link objects: LNK A, B, C, D and the system-level _PIC. + // Linux's acpi_irq.c walks these during boot to resolve PIRQ routing; + // we surface them as info-level logs so the same diagnostic is + // available without full _PRT evaluation. Format mirrors the + // Linux dmesg: "\_SB_.LNKC: Enabled at IRQ 10". + if let Ok(link_entries) = fs::read_dir("/scheme/acpi/symbols") { + for link_entry in link_entries.flatten() { + let Some(name) = link_entry.file_name().to_str().map(|s| s.to_owned()) else { + continue; + }; + if !name.contains(".LNK") { + continue; + } + let Ok(link_fd) = symbols_fd.openat(&name, libredox::flag::O_RDONLY, 0) else { + continue; + }; + let Ok(stat) = link_fd.stat() else { continue }; + let mut buf = vec![0u8; stat.st_size as usize]; + let Ok(n) = link_fd.read(&mut buf) else { continue }; + buf.truncate(n); + let Ok(s) = std::str::from_utf8(&buf) else { continue }; + let Ok(parsed) = ron::from_str::(s) else { continue }; + let (irq, enabled) = match parsed.value { + AmlSerdeValue::OpRegion { .. } | AmlSerdeValue::Field { .. } + | AmlSerdeValue::Buffer { .. } | AmlSerdeValue::Package { .. } => continue, + _ => parse_lnk_irc(&parsed), + }; + let state = if enabled { "Enabled" } else { "Disabled" }; + let irq_s = irq + .map(|i| i.to_string()) + .unwrap_or_else(|| "?".to_owned()); + log::info!("{}: {} at IRQ {}", parsed.name, state, irq_s); + } + } Ok(()) } } + +// Parse a LNK object's serialized AML value into (IRQ, enabled). +// The LNK object's value here is the result of evaluating its _CRS, +// which on QEMU/PIIX4 returns a serialized resource descriptor that +// resolves to the current IRQ assignment. We accept the integer IRQ +// value directly when the serializer hands us one. +fn parse_lnk_irc(aml: &amlserde::AmlSerde) -> (Option, bool) { + match &aml.value { + AmlSerdeValue::Integer(n) => (Some((*n & 0xFFFF) as u32), true), + AmlSerdeValue::Buffer(bytes) => { + // The AML resource-descriptor "IRQ" small resource type is + // 0x21 (type 0x04, big-endian 16-bit IRQ bitmask). Two-byte + // header + variable-length bitmask; we extract a single IRQ + // bit when possible. + if bytes.len() >= 4 && bytes[0] == 0x21 { + let lo = bytes[2] as u16 | ((bytes[3] as u16) << 8); + if lo != 0 { + let bit = lo.trailing_zeros(); + return (Some(bit), true); + } + } + (None, true) + } + _ => (None, false), + } +}