From 4fe734d1c262b79d9754b43bf0a0553e48854f9c Mon Sep 17 00:00:00 2001 From: Admin Pupkin Date: Wed, 20 May 2026 14:11:00 +0300 Subject: [PATCH] fix: Regenerate P44 patch with clean upstream baseline Previous P44 was generated against an already-patched tree causing validation failures. Regenerated using git diff -U0 -w against P0-P43 baseline. --- .../base/P44-acpid-thermal-zones.patch | 723 +----------------- 1 file changed, 15 insertions(+), 708 deletions(-) diff --git a/local/patches/base/P44-acpid-thermal-zones.patch b/local/patches/base/P44-acpid-thermal-zones.patch index 1e555daccf..db95d87935 100644 --- a/local/patches/base/P44-acpid-thermal-zones.patch +++ b/local/patches/base/P44-acpid-thermal-zones.patch @@ -1,205 +1,18 @@ diff --git a/drivers/acpid/src/acpi.rs b/drivers/acpid/src/acpi.rs -index 94a1eb17..5c881334 100644 +index 74997be0..5c881334 100644 --- a/drivers/acpid/src/acpi.rs +++ b/drivers/acpid/src/acpi.rs -@@ -55,3 +55,2 @@ impl SdtHeader { -- self.length -- .try_into() -- .expect("expected usize to be at least 32 bits") -+ // usize is at least 32 bits on all supported architectures. -+ self.length as usize -@@ -95,0 +95,3 @@ pub enum InvalidSdtError { -+ -+ #[error("bad alignment")] -+ BadAlignment, -@@ -98 +100 @@ pub enum InvalidSdtError { --struct PhysmapGuard { -+pub struct PhysmapGuard { -@@ -103 +105 @@ impl PhysmapGuard { -- fn map(page: usize, page_count: usize) -> std::io::Result { -+ pub fn map(page: usize, page_count: usize) -> std::io::Result { -@@ -139,3 +141,4 @@ impl Sdt { -- Err(plain::Error::BadAlignment) => panic!( -- "plain::from_bytes failed due to alignment, but SdtHeader is #[repr(packed)]!" -- ), -+ Err(plain::Error::BadAlignment) => { -+ log::error!("plain::from_bytes failed due to alignment, but SdtHeader is #[repr(packed)]"); -+ return Err(InvalidSdtError::BadAlignment); -+ } -@@ -171 +174,3 @@ impl Sdt { -- assert!(pages.len() >= mem::size_of::()); -+ if pages.len() < mem::size_of::() { -+ return Err(TablePhysLoadError::Validity(InvalidSdtError::InvalidSize)); -+ } -@@ -174,2 +179,5 @@ impl Sdt { -- let sdt = plain::from_bytes::(&sdt_mem[..mem::size_of::()]) -- .expect("either alignment is wrong, or the length is too short, both of which are already checked for"); -+ let sdt = match plain::from_bytes::(&sdt_mem[..mem::size_of::()]) { -+ Ok(header) => header, -+ Err(plain::Error::TooShort) => return Err(TablePhysLoadError::Validity(InvalidSdtError::InvalidSize)), -+ Err(plain::Error::BadAlignment) => return Err(TablePhysLoadError::Validity(InvalidSdtError::BadAlignment)), -+ }; -@@ -200 +208,4 @@ impl Sdt { -- assert_eq!(left, 0); -+ if left != 0 { -+ log::error!("SDT physical load left {} bytes remaining after loop", left); -+ return Err(TablePhysLoadError::Validity(InvalidSdtError::InvalidSize)); -+ } -@@ -213,2 +224,2 @@ impl Deref for Sdt { -- plain::from_bytes::(&self.0) -- .expect("expected already validated Sdt to be able to get its header") -+ // SAFETY: Sdt::new validated the slice length and SdtHeader is #[repr(packed)]. -+ unsafe { &*(self.0.as_ptr() as *const SdtHeader) } -@@ -247,0 +259 @@ pub struct AmlSymbols { -+ pci_fd: Arc>>, -@@ -251 +263 @@ impl AmlSymbols { -- pub fn new(aml_region_handlers: Vec<(RegionSpace, Box)>) -> Self { -+ pub fn new(aml_region_handlers: Vec<(RegionSpace, Box)>, pci_fd: Arc>>) -> Self { -@@ -256,0 +269 @@ impl AmlSymbols { -+ pci_fd, -@@ -260 +273 @@ impl AmlSymbols { -- pub fn init(&mut self, pci_fd: Option<&libredox::Fd>) -> Result<(), Box> { -+ pub fn init(&mut self) -> Result<(), Box> { -@@ -265 +278 @@ impl AmlSymbols { -- let handler = AmlPhysMemHandler::new(pci_fd, Arc::clone(&self.page_cache)); -+ let handler = AmlPhysMemHandler::new(Arc::clone(&self.pci_fd), Arc::clone(&self.page_cache)); -@@ -281 +293,0 @@ impl AmlSymbols { -- pci_fd: Option<&libredox::Fd>, -@@ -284 +296 @@ impl AmlSymbols { -- match self.init(pci_fd) { -+ match self.init() { -@@ -308,2 +320,2 @@ impl AmlSymbols { -- pub fn build_cache(&mut self, pci_fd: Option<&libredox::Fd>) { -- let Ok(aml_context) = self.aml_context_mut(pci_fd) else { -+ pub fn build_cache(&mut self) { -+ let Ok(aml_context) = self.aml_context_mut() else { -@@ -377,0 +390,44 @@ impl From for AmlEvalError { -+/// Cached S5 (soft-off) state derived from FADT and AML \_S5 package. -+/// -+/// Derived once at startup (or on first shutdown if AML was not ready at init) -+/// and reused for all subsequent shutdown attempts, eliminating redundant AML -+/// namespace lookups on the critical shutdown path. -+#[derive(Clone, Debug)] -+pub struct S5State { -+ pub slp_typa: u16, -+ pub slp_typb: u16, -+ pub pm1a_port: u16, -+ pub pm1b_port: u16, -+ pub derived_at: &'static str, -+} -+ -+/// Errors that can occur when deriving or executing the S5 shutdown sequence. -+#[derive(Debug, Error)] -+pub enum ShutdownError { -+ #[error("FADT not available — cannot determine shutdown parameters")] -+ MissingFadt, -+ #[error("PM1a control block address is zero — ACPI shutdown unavailable")] -+ Pm1aZero, -+ #[error("AML interpreter not initialized — cannot look up \\_S5")] -+ AmlNotReady, -+ #[error("\\_S5 not found in AML namespace")] -+ S5NotFound, -+ #[error("\\_S5 is not a Package object")] -+ S5NotPackage, -+ #[error("SLP_TYP value in \\_S5 is not an Integer")] -+ SlpTypNotInteger, -+ #[error("PM1a control write failed")] -+ S5WriteFailed, -+} -+ -+/// Result of a shutdown attempt. -+#[derive(Debug)] -+pub enum ShutdownResult { -+ /// Shutdown sequence completed (machine should power off). -+ Ok, -+ /// ACPI shutdown failed; fell back to keyboard controller reset. -+ FallbackReset, -+ /// Shutdown could not proceed due to a deterministic error. -+ Err(ShutdownError), -+} -+ -@@ -384,0 +441,4 @@ pub struct AcpiContext { -+ s5_state: RwLock>, -+ -+ pub pci_fd: Arc>>, -+ -@@ -390,0 +451,2 @@ pub struct AcpiContext { +@@ -450,0 +451,2 @@ pub struct AcpiContext { + + pub thermal_state: crate::thermal::ThermalState, -@@ -400 +462 @@ impl AcpiContext { -- let interpreter = symbols.aml_context_mut(None)?; -+ let interpreter = symbols.aml_context_mut()?; -@@ -414,3 +476,3 @@ impl AcpiContext { -- interpreter -- .release_global_lock() -- .expect("Failed to release GIL!"); //TODO: check if this should panic -+ if let Err(e) = interpreter.release_global_lock() { -+ log::error!("Failed to release AML global lock: {:?}", e); -+ } -@@ -432,4 +494,8 @@ impl AcpiContext { -- .map(|physaddr| { -- let physaddr: usize = physaddr -- .try_into() -- .expect("expected ACPI addresses to be compatible with the current word size"); -+ .filter_map(|physaddr| { -+ let physaddr: usize = match physaddr.try_into() { -+ Ok(addr) => addr, -+ Err(e) => { -+ log::error!("expected ACPI addresses to be compatible with the current word size: {}", e); -+ return None; -+ } -+ }; -@@ -439 +505,7 @@ impl AcpiContext { -- Sdt::load_from_physical(physaddr).expect("failed to load physical SDT") -+ match Sdt::load_from_physical(physaddr) { -+ Ok(sdt) => Some(sdt), -+ Err(error) => { -+ log::error!("failed to load physical SDT at {:#x}: {}", physaddr, error); -+ None -+ } -+ } -@@ -442,0 +515,2 @@ impl AcpiContext { -+ let pci_fd = Arc::new(parking_lot::RwLock::new(None)); -+ -@@ -449 +523,5 @@ impl AcpiContext { -- aml_symbols: RwLock::new(AmlSymbols::new(ec)), -+ aml_symbols: RwLock::new(AmlSymbols::new(ec, Arc::clone(&pci_fd))), -+ -+ s5_state: RwLock::new(None), -+ -+ pci_fd, -@@ -453,0 +532,2 @@ impl AcpiContext { +@@ -529,0 +532,2 @@ impl AcpiContext { + + thermal_state: crate::thermal::ThermalState::new(), -@@ -462,0 +543,24 @@ impl AcpiContext { -+ // Trigger AML interpreter initialization so we can derive S5 state early. -+ // If AML init fails, S5 derivation will fall back to "shutdown_fallback" at -+ // shutdown time. -+ { -+ let mut symbols = this.aml_symbols.write(); -+ if symbols.aml_context.is_none() { -+ if let Err(e) = symbols.init() { -+ log::warn!("ACPI S5: AML init at startup failed: {} — will derive at shutdown", e); -+ } -+ } -+ } -+ match this.derive_s5_state("register_pci") { -+ Ok(_) => {} -+ Err(ShutdownError::AmlNotReady) => { -+ log::info!("ACPI S5: AML not ready at init — will derive at shutdown"); -+ } -+ Err(e) => { -+ log::warn!("ACPI S5: early derivation failed: {} — will derive at shutdown", e); -+ } -+ } -+ +@@ -559,0 +564,3 @@ impl AcpiContext { + // Discover thermal zones if AML is ready. + this.thermal_state.refresh(&this); + -@@ -529 +633 @@ impl AcpiContext { -- if let Ok(aml_symbols) = self.aml_symbols(None) { -+ if let Ok(aml_symbols) = self.aml_symbols() { -@@ -535,0 +640,24 @@ impl AcpiContext { +@@ -632,0 +640,24 @@ impl AcpiContext { + /// Discover thermal zone names by scanning the AML namespace under `\_TZ`. + pub fn thermal_zone_names(&self) -> Result, AmlEvalError> { + let mut symbols = self.aml_symbols.write(); @@ -224,508 +37,26 @@ index 94a1eb17..5c881334 100644 + Ok(names) + } + -@@ -538 +665,0 @@ impl AcpiContext { -- pci_fd: Option<&libredox::Fd>, -@@ -553 +680 @@ impl AcpiContext { -- aml_symbols.build_cache(pci_fd); -+ aml_symbols.build_cache(); -@@ -564,0 +692,69 @@ impl AcpiContext { -+ /// Derive the S5 (soft-off) state from FADT and AML \_S5 package. -+/// -+/// Reads PM1a/PM1b control block addresses from the FADT and the SLP_TYP -+/// values from the AML `\_S5` package, then caches the result. Subsequent -+/// calls return the cached value without re-parsing AML. -+/// -+/// `derived_at` is a log marker indicating when this derivation occurred -+/// (e.g. "register_pci", "shutdown_fallback"). -+ pub fn derive_s5_state(&self, derived_at: &'static str) -> Result { -+ let fadt = self.fadt().ok_or(ShutdownError::MissingFadt)?; -+ let pm1a_port = fadt.pm1a_control_block as u16; -+ let pm1b_port = fadt.pm1b_control_block as u16; -+ -+ if pm1a_port == 0 { -+ return Err(ShutdownError::Pm1aZero); -+ } -+ -+ let aml_symbols = self.aml_symbols.read(); -+ let aml_context = aml_symbols -+ .aml_context -+ .as_ref() -+ .ok_or(ShutdownError::AmlNotReady)?; -+ -+ let s5_name = acpi::aml::namespace::AmlName::from_str("\\_S5") -+ .map_err(|_| ShutdownError::S5NotFound)?; -+ -+ let s5 = aml_context -+ .namespace -+ .lock() -+ .get(s5_name) -+ .map_err(|_| ShutdownError::S5NotFound)?; -+ -+ let package = match s5.deref() { -+ acpi::aml::object::Object::Package(p) => p, -+ _ => return Err(ShutdownError::S5NotPackage), -+ }; -+ -+ let slp_typa = match package[0].deref() { -+ acpi::aml::object::Object::Integer(i) => *i as u16, -+ _ => return Err(ShutdownError::SlpTypNotInteger), -+ }; -+ let slp_typb = if package.len() > 1 { -+ match package[1].deref() { -+ acpi::aml::object::Object::Integer(i) => *i as u16, -+ _ => 0u16, -+ } -+ } else { -+ 0u16 -+ }; -+ -+ let state = S5State { -+ slp_typa, -+ slp_typb, -+ pm1a_port, -+ pm1b_port, -+ derived_at, -+ }; -+ -+ log::info!( -+ "ACPI S5: derived at={}, SLP_TYPa=0x{:X}, SLP_TYPb=0x{:X}, PM1a=0x{:04X}, PM1b=0x{:04X}", -+ derived_at, slp_typa, slp_typb, pm1a_port, pm1b_port -+ ); -+ -+ drop(aml_symbols); -+ *self.s5_state.write() = Some(state.clone()); -+ -+ Ok(state) -+ } -+ -@@ -569 +765 @@ impl AcpiContext { -- pub fn set_global_s_state(&self, state: u8) { -+ pub fn set_global_s_state(&self, state: u8) -> ShutdownResult { -@@ -571 +767 @@ impl AcpiContext { -- return; -+ return ShutdownResult::Ok; -@@ -573,5 +769,12 @@ impl AcpiContext { -- let fadt = match self.fadt() { -- Some(fadt) => fadt, -- None => { -- log::error!("Cannot set global S-state due to missing FADT."); -- return; -+ -+ let s5 = match self.s5_state.read().as_ref() { -+ Some(cached) => cached.clone(), -+ None => match self.derive_s5_state("shutdown_fallback") { -+ Ok(s5) => s5, -+ Err(e) => { -+ log::error!("ACPI S5 derivation failed: {}", e); -+ if matches!(e, ShutdownError::Pm1aZero | ShutdownError::MissingFadt) { -+ log::warn!("Falling back to keyboard controller reset"); -+ #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] -+ Pio::::new(0x64u16).write(0xFEu8); -+ return ShutdownResult::FallbackReset; -@@ -578,0 +782,3 @@ impl AcpiContext { -+ return ShutdownResult::Err(e); -+ } -+ }, -@@ -581,2 +787,7 @@ impl AcpiContext { -- let port = fadt.pm1a_control_block as u16; -- let mut val = 1 << 13; -+ if s5.pm1a_port == 0 { -+ log::error!("ACPI S5: cached PM1a port is zero — shutdown unavailable"); -+ log::warn!("Falling back to keyboard controller reset"); -+ #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] -+ Pio::::new(0x64u16).write(0xFEu8); -+ return ShutdownResult::FallbackReset; -+ } -@@ -584 +795 @@ impl AcpiContext { -- let aml_symbols = self.aml_symbols.read(); -+ let mut val = (1u16 << 13) | (s5.slp_typa & 0x1FFF); -@@ -586,7 +797,6 @@ impl AcpiContext { -- let s5_aml_name = match acpi::aml::namespace::AmlName::from_str("\\_S5") { -- Ok(aml_name) => aml_name, -- Err(error) => { -- log::error!("Could not build AmlName for \\_S5, {:?}", error); -- return; -- } -- }; -+ #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] -+ { -+ log::info!( -+ "ACPI shutdown: writing PM1a=0x{:04X} val=0x{:04X} (SLP_TYPa=0x{:X}, SLP_TYPb=0x{:X})", -+ s5.pm1a_port, val, s5.slp_typa, s5.slp_typb -+ ); -@@ -594,11 +804,13 @@ impl AcpiContext { -- let s5 = match &aml_symbols.aml_context { -- Some(aml_context) => match aml_context.namespace.lock().get(s5_aml_name) { -- Ok(s5) => s5, -- Err(error) => { -- log::error!("Cannot set S-state, missing \\_S5, {:?}", error); -- return; -- } -- }, -- None => { -- log::error!("Cannot set S-state, AML context not initialized"); -- return; -+ let mut pio = Pio::::new(s5.pm1a_port); -+ pio.write(val); -+ -+ std::thread::sleep(std::time::Duration::from_secs(3)); -+ -+ log::warn!("ACPI PM1a shutdown did not power off — retrying with PM1b"); -+ val = (1u16 << 13) | (s5.slp_typb & 0x1FFF); -+ pio.write(val); -+ -+ if s5.pm1b_port != 0 { -+ let mut pio_b = Pio::::new(s5.pm1b_port); -+ pio_b.write(val); -+ log::info!("ACPI shutdown: also wrote PM1b=0x{:04X}", s5.pm1b_port); -@@ -606 +817,0 @@ impl AcpiContext { -- }; -@@ -608,5 +819,4 @@ impl AcpiContext { -- let package = match s5.deref() { -- acpi::aml::object::Object::Package(package) => package, -- _ => { -- log::error!("Cannot set S-state, \\_S5 is not a package"); -- return; -+ std::thread::sleep(std::time::Duration::from_secs(2)); -+ log::error!("ACPI shutdown failed — falling back to keyboard controller reset"); -+ Pio::::new(0x64u16).write(0xFEu8); -+ return ShutdownResult::FallbackReset; -@@ -614 +823,0 @@ impl AcpiContext { -- }; -@@ -616,5 +825,5 @@ impl AcpiContext { -- let slp_typa = match package[0].deref() { -- acpi::aml::object::Object::Integer(i) => i.to_owned(), -- _ => { -- log::error!("typa is not an Integer"); -- return; -+ #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] -+ { -+ log::error!("ACPI shutdown not supported on this architecture"); -+ ShutdownResult::Err(ShutdownError::S5WriteFailed) -+ } -@@ -621,0 +831,8 @@ impl AcpiContext { -+ -+ /// Suspend-to-RAM (S3 sleep state) -+ /// See ACPI 6.1 spec for SLP_TYPa/SLP_TYPb encoding -+ pub fn suspend_to_ram(&self) { -+ log::info!("ACPI: attempting suspend-to-RAM (S3)"); -+ let fadt = match self.fadt() { -+ Some(f) => f, -+ None => { log::error!("ACPI S3: missing FADT"); return; } -@@ -623,4 +840,3 @@ impl AcpiContext { -- let slp_typb = match package[1].deref() { -- acpi::aml::object::Object::Integer(i) => i.to_owned(), -- _ => { -- log::error!("typb is not an Integer"); -+ let pm1a = fadt.pm1a_control_block as u16; -+ if pm1a == 0 { -+ log::error!("ACPI S3: PM1a port is zero"); -@@ -628,0 +845,4 @@ impl AcpiContext { -+ let aml_symbols = self.aml_symbols.read(); -+ let s3_name = match acpi::aml::namespace::AmlName::from_str("\\_S3") { -+ Ok(n) => n, -+ Err(e) => { log::error!("ACPI S3: \\_S3 name error: {:?}", e); return; } -@@ -630,4 +850,17 @@ impl AcpiContext { -- -- log::trace!("Shutdown SLP_TYPa {:X}, SLP_TYPb {:X}", slp_typa, slp_typb); -- val |= slp_typa as u16; -- -+ let s3 = match &aml_symbols.aml_context { -+ Some(ctx) => match ctx.namespace.lock().get(s3_name) { -+ Ok(s) => s, -+ Err(e) => { log::error!("ACPI S3: \\_S3 not found: {:?}", e); return; } -+ }, -+ None => { log::error!("ACPI S3: AML context missing"); return; } -+ }; -+ let pkg = match s3.deref() { -+ acpi::aml::object::Object::Package(p) => p, -+ _ => { log::error!("ACPI S3: \\_S3 not a package"); return; } -+ }; -+ let slp_typa = match pkg[0].deref() { -+ acpi::aml::object::Object::Integer(i) => *i as u16, -+ _ => { log::error!("ACPI S3: SLP_TYPa not integer"); return; } -+ }; -+ let mut val = (1u16 << 13) | (slp_typa & 0x1FFF); -+ log::info!("ACPI S3: writing PM1a=0x{:04X} val=0x{:04X}", pm1a, val); -@@ -635,3 +868 @@ impl AcpiContext { -- { -- log::warn!("Shutdown with ACPI outw(0x{:X}, 0x{:X})", port, val); -- Pio::::new(port).write(val); -+ { Pio::::new(pm1a).write(val); } -@@ -640 +870,0 @@ impl AcpiContext { -- // TODO: Handle SLP_TYPb -@@ -642,7 +872,16 @@ impl AcpiContext { -- #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] -- { -- log::error!( -- "Cannot shutdown with ACPI outw(0x{:X}, 0x{:X}) on this architecture", -- port, -- val -- ); -+ /// Query ACPI battery via \\_SB_.BAT0._BST -+ /// Returns (remaining_capacity_mAh, present_voltage_mV) if available -+ pub fn read_battery_status(&self) -> Option<(u32, u32)> { -+ let aml_symbols = self.aml_symbols.read(); -+ let ctx = aml_symbols.aml_context.as_ref()?; -+ let mut ns = ctx.namespace.lock(); -+ let bst_name = acpi::aml::namespace::AmlName::from_str("\\_SB_.BAT0._BST").ok()?; -+ let bst = ns.get(bst_name).ok()?; -+ match bst.deref() { -+ acpi::aml::object::Object::Package(p) if p.len() >= 4 => { -+ let cap = match p[1].deref() { acpi::aml::object::Object::Integer(i) => *i as u32, _ => return None }; -+ let volt = match p[2].deref() { acpi::aml::object::Object::Integer(i) => *i as u32, _ => return None }; -+ Some((cap, volt)) -+ } -+ _ => { log::warn!("ACPI: _BST not a valid battery package"); None } -+ } -@@ -651,2 +890,14 @@ impl AcpiContext { -- loop { -- core::hint::spin_loop(); -+ /// Query ACPI battery info via \\_SB_.BAT0._BIF -+ /// Returns (design_capacity_mAh, last_full_capacity_mAh, design_voltage_mV) if available -+ pub fn read_battery_info(&self) -> Option<(u32, u32, u32)> { -+ let aml_symbols = self.aml_symbols.read(); -+ let ctx = aml_symbols.aml_context.as_ref()?; -+ let mut ns = ctx.namespace.lock(); -+ let bif_name = acpi::aml::namespace::AmlName::from_str("\\_SB_.BAT0._BIF").ok()?; -+ let bif = ns.get(bif_name).ok()?; -+ match bif.deref() { -+ acpi::aml::object::Object::Package(p) if p.len() >= 13 => { -+ let design = match p[1].deref() { acpi::aml::object::Object::Integer(i) => *i as u32, _ => return None }; -+ let last = match p[2].deref() { acpi::aml::object::Object::Integer(i) => *i as u32, _ => return None }; -+ let volt = match p[4].deref() { acpi::aml::object::Object::Integer(i) => *i as u32, _ => return None }; -+ Some((design, last, volt)) -@@ -653,0 +905 @@ impl AcpiContext { -+ _ => { log::warn!("ACPI: _BIF not a valid battery package"); None } -@@ -656,0 +909,2 @@ impl AcpiContext { -+} -+ -@@ -752,3 +1006,4 @@ impl Fadt { -- Err(plain::Error::BadAlignment) => unreachable!( -- "plain::from_bytes reported bad alignment, but FadtAcpi2Struct is #[repr(packed)]" -- ), -+ Err(plain::Error::BadAlignment) => { -+ log::error!("plain::from_bytes reported bad alignment for FadtAcpi2Struct, but it is #[repr(packed)]"); -+ None -+ } -@@ -763,2 +1018,2 @@ impl Deref for Fadt { -- plain::from_bytes::(&self.0 .0) -- .expect("expected FADT struct to already be validated in Deref impl") -+ // SAFETY: Fadt::new validated the slice length and FadtStruct is #[repr(packed)]. -+ unsafe { &*(self.0 .0.as_ptr() as *const FadtStruct) } -@@ -777,3 +1032,7 @@ impl Fadt { -- let fadt_sdt = context -- .take_single_sdt(*b"FACP") -- .expect("expected ACPI to always have a FADT"); -+ let fadt_sdt = match context.take_single_sdt(*b"FACP") { -+ Some(sdt) => sdt, -+ None => { -+ log::error!("expected ACPI to always have a FADT"); -+ return; -+ } -+ }; -@@ -790,4 +1049,2 @@ impl Fadt { -- Some(fadt2) => usize::try_from(fadt2.x_dsdt).unwrap_or_else(|_| { -- usize::try_from(fadt.dsdt).expect("expected any given u32 to fit within usize") -- }), -- None => usize::try_from(fadt.dsdt).expect("expected any given u32 to fit within usize"), -+ Some(fadt2) => fadt2.x_dsdt as usize, -+ None => fadt.dsdt as usize, diff --git a/drivers/acpid/src/main.rs b/drivers/acpid/src/main.rs -index 059254b3..91336ba7 100644 +index a9d47e09..91336ba7 100644 --- a/drivers/acpid/src/main.rs +++ b/drivers/acpid/src/main.rs -@@ -16,0 +17,2 @@ mod ec; -+mod dmi; +@@ -17,0 +18 @@ mod dmi; +mod thermal; -@@ -31,3 +33,8 @@ fn daemon(daemon: daemon::Daemon) -> ! { -- let rxsdt_raw_data: Arc<[u8]> = std::fs::read("/scheme/kernel.acpi/rxsdt") -- .expect("acpid: failed to read `/scheme/kernel.acpi/rxsdt`") -- .into(); -+ let rxsdt_raw_data: Arc<[u8]> = match std::fs::read("/scheme/kernel.acpi/rxsdt") { -+ Ok(data) => data.into(), -+ Err(e) => { -+ log::warn!("acpid: failed to read `/scheme/kernel.acpi/rxsdt`: {} — no ACPI", e); -+ daemon.ready(); -+ std::process::exit(0); -+ } -+ }; -@@ -41 +48,8 @@ fn daemon(daemon: daemon::Daemon) -> ! { -- let sdt = self::acpi::Sdt::new(rxsdt_raw_data).expect("acpid: failed to parse [RX]SDT"); -+ let sdt = match self::acpi::Sdt::new(rxsdt_raw_data) { -+ Ok(sdt) => sdt, -+ Err(e) => { -+ log::warn!("acpid: failed to parse [RX]SDT: {} — booting without ACPI", e); -+ daemon.ready(); -+ std::process::exit(0); -+ } -+ }; -@@ -67 +81,5 @@ fn daemon(daemon: daemon::Daemon) -> ! { -- _ => panic!("acpid: expected [RX]SDT from kernel to be either of those"), -+ _ => { -+ log::warn!("acpid: expected [RX]SDT from kernel to be RSDT or XSDT, got {:?} — booting without ACPI", String::from_utf8_lossy(&sdt.signature)); -+ daemon.ready(); -+ std::process::exit(0); -+ } -@@ -75,0 +94,8 @@ fn daemon(daemon: daemon::Daemon) -> ! { -+ let dmi_strings = match self::dmi::read_smbios_dmi() { -+ Ok(strings) => Some(strings), -+ Err(e) => { -+ log::warn!("Failed to read SMBIOS DMI: {}", e); -+ None -+ } -+ }; -+ -@@ -78 +104,3 @@ fn daemon(daemon: daemon::Daemon) -> ! { -- common::acquire_port_io_rights().expect("acpid: failed to set I/O privilege level to Ring 3"); -+ if let Err(e) = common::acquire_port_io_rights() { -+ log::warn!("acpid: failed to set I/O privilege level to Ring 3: {} — continuing without port I/O", e); -+ } -@@ -80,2 +108,8 @@ fn daemon(daemon: daemon::Daemon) -> ! { -- let shutdown_pipe = File::open("/scheme/kernel.acpi/kstop") -- .expect("acpid: failed to open `/scheme/kernel.acpi/kstop`"); -+ let shutdown_pipe = match File::open("/scheme/kernel.acpi/kstop") { -+ Ok(f) => f, -+ Err(e) => { -+ log::warn!("acpid: failed to open `/scheme/kernel.acpi/kstop`: {} — booting without ACPI shutdown", e); -+ daemon.ready(); -+ std::process::exit(0); -+ } -+ }; -@@ -83,2 +117,17 @@ fn daemon(daemon: daemon::Daemon) -> ! { -- let mut event_queue = RawEventQueue::new().expect("acpid: failed to create event queue"); -- let socket = Socket::nonblock().expect("acpid: failed to create disk scheme"); -+ let mut event_queue = match RawEventQueue::new() { -+ Ok(q) => q, -+ Err(e) => { -+ log::warn!("acpid: failed to create event queue: {} — booting without ACPI", e); -+ daemon.ready(); -+ std::process::exit(0); -+ } -+ }; -+ -+ let socket = match Socket::nonblock() { -+ Ok(s) => s, -+ Err(e) => { -+ log::warn!("acpid: failed to create scheme socket: {} — booting without ACPI", e); -+ daemon.ready(); -+ std::process::exit(0); -+ } -+ }; -@@ -86 +135 @@ fn daemon(daemon: daemon::Daemon) -> ! { -- let mut scheme = self::scheme::AcpiScheme::new(&acpi_context, &socket); -+ let mut scheme = self::scheme::AcpiScheme::new(&acpi_context, &socket, dmi_strings); -@@ -89,6 +138,12 @@ fn daemon(daemon: daemon::Daemon) -> ! { -- event_queue -- .subscribe(shutdown_pipe.as_raw_fd() as usize, 0, EventFlags::READ) -- .expect("acpid: failed to register shutdown pipe for event queue"); -- event_queue -- .subscribe(socket.inner().raw(), 1, EventFlags::READ) -- .expect("acpid: failed to register scheme socket for event queue"); -+ if let Err(e) = event_queue -+ .subscribe(shutdown_pipe.as_raw_fd() as usize, 0, EventFlags::READ) { -+ log::warn!("acpid: failed to register shutdown pipe for event queue: {} — booting without ACPI", e); -+ daemon.ready(); -+ std::process::exit(0); -+ } -+ if let Err(e) = event_queue -+ .subscribe(socket.inner().raw(), 1, EventFlags::READ) { -+ log::warn!("acpid: failed to register scheme socket for event queue: {} — booting without ACPI", e); -+ daemon.ready(); -+ std::process::exit(0); -+ } -@@ -96,2 +151,8 @@ fn daemon(daemon: daemon::Daemon) -> ! { -- register_sync_scheme(&socket, "acpi", &mut scheme) -- .expect("acpid: failed to register acpi scheme to namespace"); -+ if let Err(err) = register_sync_scheme(&socket, "acpi", &mut scheme) { -+ log::warn!( -+ "acpid: failed to register acpi scheme (error: {}). Another acpid instance may already own it.", -+ err -+ ); -+ daemon.ready(); -+ std::process::exit(0); -+ } -@@ -101 +162,3 @@ fn daemon(daemon: daemon::Daemon) -> ! { -- libredox::call::setrens(0, 0).expect("acpid: failed to enter null namespace"); -+ if let Err(e) = libredox::call::setrens(0, 0) { -+ log::warn!("acpid: failed to enter null namespace: {} — continuing", e); -+ } -@@ -105,6 +168,7 @@ fn daemon(daemon: daemon::Daemon) -> ! { -- let Some(event) = event_queue -- .next() -- .transpose() -- .expect("acpid: failed to read event file") -- else { -- break; -+ let event = match event_queue.next().transpose() { -+ Ok(Some(e)) => e, -+ Ok(None) => break, -+ Err(e) => { -+ log::error!("acpid: failed to read event file: {} — continuing", e); -+ continue; -+ } -@@ -115,6 +179,7 @@ fn daemon(daemon: daemon::Daemon) -> ! { -- match handler -- .process_requests_nonblocking(&mut scheme) -- .expect("acpid: failed to process requests") -- { -- ControlFlow::Continue(()) => {} -- ControlFlow::Break(()) => break, -+ match handler.process_requests_nonblocking(&mut scheme) { -+ Ok(ControlFlow::Continue(())) => {} -+ Ok(ControlFlow::Break(())) => break, -+ Err(e) => { -+ log::error!("acpid: failed to process requests: {} — continuing", e); -+ continue; -+ } -@@ -135 +200,2 @@ fn daemon(daemon: daemon::Daemon) -> ! { -- acpi_context.set_global_s_state(5); -+ let result = acpi_context.set_global_s_state(5); -+ log::info!("ACPI shutdown result: {:?}", result); -@@ -137 +203,2 @@ fn daemon(daemon: daemon::Daemon) -> ! { -- unreachable!("System should have shut down before this is entered"); -+ log::error!("System should have shut down before this was reached"); -+ std::process::exit(1); -@@ -141 +208 @@ fn main() { -- common::init(); -+ if let Err(err) = common::init() { eprintln!("acpid: failed to initialize common: {err}"); std::process::exit(1); } diff --git a/drivers/acpid/src/scheme.rs b/drivers/acpid/src/scheme.rs -index 5a5040c3..b92327be 100644 +index 85c425c1..b92327be 100644 --- a/drivers/acpid/src/scheme.rs +++ b/drivers/acpid/src/scheme.rs -@@ -24,0 +25 @@ use crate::acpi::{AcpiContext, AmlSymbols, SdtSignature}; -+use crate::dmi::DmiStrings; -@@ -29 +29,0 @@ pub struct AcpiScheme<'acpi, 'sock> { -- pci_fd: Option, -@@ -30,0 +31 @@ pub struct AcpiScheme<'acpi, 'sock> { -+ dmi_text: Option, -@@ -45,0 +47,3 @@ enum HandleKind<'a> { -+ Dmi(String), +@@ -47,0 +48,2 @@ enum HandleKind<'a> { + Thermal, + ThermalZone(String), -@@ -57,0 +62,3 @@ impl HandleKind<'_> { -+ Self::Dmi(_) => false, +@@ -60,0 +63,2 @@ impl HandleKind<'_> { + Self::Thermal => true, + Self::ThermalZone(_) => false, -@@ -67,0 +75 @@ impl HandleKind<'_> { -+ Self::Dmi(text) => text.len(), -@@ -70,0 +79,2 @@ impl HandleKind<'_> { +@@ -74,0 +79,2 @@ impl HandleKind<'_> { + Self::Thermal => 0, + Self::ThermalZone(ref text) => text.len(), -@@ -76 +86 @@ impl<'acpi, 'sock> AcpiScheme<'acpi, 'sock> { -- pub fn new(ctx: &'acpi AcpiContext, socket: &'sock Socket) -> Self { -+ pub fn new(ctx: &'acpi AcpiContext, socket: &'sock Socket, dmi: Option) -> Self { -@@ -80 +89,0 @@ impl<'acpi, 'sock> AcpiScheme<'acpi, 'sock> { -- pci_fd: None, -@@ -81,0 +91 @@ impl<'acpi, 'sock> AcpiScheme<'acpi, 'sock> { -+ dmi_text: dmi.map(|d| d.to_text()), -@@ -198,0 +209 @@ impl SchemeSync for AcpiScheme<'_, '_> { -+ ["dmi"] => HandleKind::Dmi(self.dmi_text.clone().unwrap_or_default()), -@@ -207 +218 @@ impl SchemeSync for AcpiScheme<'_, '_> { -- if let Ok(aml_symbols) = self.ctx.aml_symbols(self.pci_fd.as_ref()) { -+ if let Ok(aml_symbols) = self.ctx.aml_symbols() { -@@ -224,0 +236,9 @@ impl SchemeSync for AcpiScheme<'_, '_> { +@@ -229,0 +236,9 @@ impl SchemeSync for AcpiScheme<'_, '_> { + ["thermal"] => HandleKind::Thermal, + ["thermal", zone] => { + if let Some(tz) = self.ctx.thermal_state.zone_by_name(zone) { @@ -735,25 +66,11 @@ index 5a5040c3..b92327be 100644 + } + } + -@@ -311,0 +332,2 @@ impl SchemeSync for AcpiScheme<'_, '_> { -+ HandleKind::Dmi(ref text) => text.as_bytes(), +@@ -317,0 +333 @@ impl SchemeSync for AcpiScheme<'_, '_> { + HandleKind::ThermalZone(ref text) => text.as_bytes(), -@@ -335,3 +357,8 @@ impl SchemeSync for AcpiScheme<'_, '_> { -- const TOPLEVEL_ENTRIES: &[&str] = &["tables", "symbols"]; -- -- for (idx, name) in TOPLEVEL_ENTRIES -+ const TOPLEVEL_ENTRIES: &[(DirentKind, &str)] = &[ -+ (DirentKind::Regular, "dmi"), -+ (DirentKind::Directory, "tables"), -+ (DirentKind::Directory, "symbols"), +@@ -344,0 +361 @@ impl SchemeSync for AcpiScheme<'_, '_> { + (DirentKind::Directory, "thermal"), -+ ]; -+ -+ for (idx, (kind, name)) in TOPLEVEL_ENTRIES -@@ -346 +373 @@ impl SchemeSync for AcpiScheme<'_, '_> { -- kind: DirentKind::Directory, -+ kind: *kind, -@@ -393,0 +421,17 @@ impl SchemeSync for AcpiScheme<'_, '_> { +@@ -403,0 +421,17 @@ impl SchemeSync for AcpiScheme<'_, '_> { + HandleKind::Thermal => { + for (idx, zone) in self + .ctx @@ -771,13 +88,3 @@ index 5a5040c3..b92327be 100644 + })?; + } + } -@@ -473 +517,3 @@ impl SchemeSync for AcpiScheme<'_, '_> { -- if self.pci_fd.is_some() { -+ { -+ let mut pci_fd = self.ctx.pci_fd.write(); -+ if pci_fd.is_some() { -@@ -475,2 +521,2 @@ impl SchemeSync for AcpiScheme<'_, '_> { -- } else { -- self.pci_fd = Some(new_fd); -+ } -+ *pci_fd = Some(new_fd);