diff --git a/drivers/acpid/src/acpi.rs b/drivers/acpid/src/acpi.rs index 7c1eb141dc..5ab7ef155e 100644 --- a/drivers/acpid/src/acpi.rs +++ b/drivers/acpid/src/acpi.rs @@ -607,6 +607,13 @@ impl AcpiContext { /// See https://forum.osdev.org/viewtopic.php?t=16990 for practical details pub fn set_global_s_state(&self, state: u8) { if state != 5 { + // Only S5 (soft-off) is implemented. S1-S4 (suspend/hibernate) + // would require _PTS/_WAK AML method evaluation, P-state + // preservation, and a wakeup path - not yet wired up. + log::warn!( + "set_global_s_state({}) called but only S5 is implemented; ignoring", + state + ); return; } let fadt = match self.fadt() { @@ -674,9 +681,18 @@ impl AcpiContext { { log::warn!("Shutdown with ACPI outw(0x{:X}, 0x{:X})", port, val); Pio::::new(port).write(val); - } - // TODO: Handle SLP_TYPb + // Some hardware requires both PM1a and PM1b to be written for S5. + // The FADT pm1b_control_block is 0 when no second block exists; + // in that case skip the second write. + let port_b = fadt.pm1b_control_block as u16; + if port_b != 0 { + let mut val_b = 1 << 13; + val_b |= slp_typb as u16; + log::warn!("Shutdown with ACPI outw(0x{:X}, 0x{:X})", port_b, val_b); + Pio::::new(port_b).write(val_b); + } + } #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] { diff --git a/drivers/acpid/src/aml_physmem.rs b/drivers/acpid/src/aml_physmem.rs index 2bdd667ba2..1f454032ed 100644 --- a/drivers/acpid/src/aml_physmem.rs +++ b/drivers/acpid/src/aml_physmem.rs @@ -2,7 +2,7 @@ use acpi::{aml::AmlError, Handle, PciAddress, PhysicalMapping}; #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] use common::io::{Io, Pio}; use num_traits::PrimInt; -use rustc_hash::FxHashMap; +use rustc_hash::{FxHashMap, FxHashSet}; use std::fmt::LowerHex; use std::mem::size_of; use std::ptr::NonNull; @@ -141,6 +141,12 @@ impl AmlPageCache { pub struct AmlPhysMemHandler { page_cache: Arc>, pci_fd: Arc>, + mutex_state: Arc>, +} + +struct AmlMutexState { + next_id: u32, + held: FxHashSet, } /// Read from a physical address. @@ -156,6 +162,10 @@ impl AmlPhysMemHandler { Self { page_cache, pci_fd: Arc::new(pci_fd), + mutex_state: Arc::new(Mutex::new(AmlMutexState { + next_id: 1, + held: FxHashSet::default(), + })), } } @@ -415,16 +425,31 @@ impl acpi::Handler for AmlPhysMemHandler { } fn create_mutex(&self) -> Handle { - log::debug!("TODO: Handler::create_mutex"); - Handle(0) + let mut state = self.mutex_state.lock().unwrap(); + let id = state.next_id; + state.next_id += 1; + Handle(id) } fn acquire(&self, mutex: Handle, timeout: u16) -> Result<(), AmlError> { - log::debug!("TODO: Handler::acquire"); - Ok(()) + let deadline = std::time::Instant::now() + + std::time::Duration::from_millis(u64::from(timeout).saturating_mul(1000)); + loop { + { + let mut state = self.mutex_state.lock().unwrap(); + if !state.held.contains(&mutex.0) { + state.held.insert(mutex.0); + return Ok(()); + } + } + if std::time::Instant::now() >= deadline { + return Err(AmlError::MutexAcquireTimeout); + } + std::thread::sleep(std::time::Duration::from_millis(1)); + } } fn release(&self, mutex: Handle) { - log::debug!("TODO: Handler::release"); + self.mutex_state.lock().unwrap().held.remove(&mutex.0); } } diff --git a/drivers/acpid/src/dmi.rs b/drivers/acpid/src/dmi.rs index befe47aba7..89e5991bde 100644 --- a/drivers/acpid/src/dmi.rs +++ b/drivers/acpid/src/dmi.rs @@ -155,7 +155,7 @@ impl PhysmapGuard { let virt = unsafe { common::physmap(phys_start, map_size, Prot { read: true, write: false }, MemoryType::default()) - .map_err(|e| DmiError::Map(libredox::error::Error::new(e.errno)))? + .map_err(|e| DmiError::Map(syscall::error::Error::new(e.errno())))? }; Ok(Self { virt: virt as *mut u8, diff --git a/drivers/hwd/src/backend/acpi.rs b/drivers/hwd/src/backend/acpi.rs index 3970989503..ad57e93f74 100644 --- a/drivers/hwd/src/backend/acpi.rs +++ b/drivers/hwd/src/backend/acpi.rs @@ -153,10 +153,25 @@ impl Backend for AcpiBackend { // 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. +// value directly when the serializer hands us one, but only when the +// value is in the valid IRQ range (0..=255 for PIC, 0..=2047 for +// legacy-compatible IOAPIC) so we don't pollute the routing table +// with garbage values like 0xD041 misparsed from FieldUnit accessors. fn parse_lnk_irc(aml: &amlserde::AmlSerde) -> (Option, bool) { match &aml.value { - AmlSerdeValue::Integer(n) => (Some((*n & 0xFFFF) as u32), true), + AmlSerdeValue::Integer(n) => { + let irq = *n & 0xFFFF; + if irq <= 2047 { + (Some(irq as u32), true) + } else { + log::debug!( + "{}: AML integer IRQ value {} out of valid range, skipping", + aml.name, + irq + ); + (None, false) + } + } AmlSerdeValue::Buffer(bytes) => { // The AML resource-descriptor "IRQ" small resource type is // 0x21 (type 0x04, big-endian 16-bit IRQ bitmask). Two-byte @@ -166,7 +181,9 @@ fn parse_lnk_irc(aml: &amlserde::AmlSerde) -> (Option, bool) { let lo = bytes[2] as u16 | ((bytes[3] as u16) << 8); if lo != 0 { let bit = lo.trailing_zeros(); - return (Some(bit), true); + if bit <= 15 { + return (Some(bit as u32), true); + } } } (None, true)