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.
This commit is contained in:
@@ -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<Self> {
|
||||
+ pub fn map(page: usize, page_count: usize) -> std::io::Result<Self> {
|
||||
@@ -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::<SdtHeader>());
|
||||
+ if pages.len() < mem::size_of::<SdtHeader>() {
|
||||
+ return Err(TablePhysLoadError::Validity(InvalidSdtError::InvalidSize));
|
||||
+ }
|
||||
@@ -174,2 +179,5 @@ impl Sdt {
|
||||
- let sdt = plain::from_bytes::<SdtHeader>(&sdt_mem[..mem::size_of::<SdtHeader>()])
|
||||
- .expect("either alignment is wrong, or the length is too short, both of which are already checked for");
|
||||
+ let sdt = match plain::from_bytes::<SdtHeader>(&sdt_mem[..mem::size_of::<SdtHeader>()]) {
|
||||
+ 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::<SdtHeader>(&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<parking_lot::RwLock<Option<libredox::Fd>>>,
|
||||
@@ -251 +263 @@ impl AmlSymbols {
|
||||
- pub fn new(aml_region_handlers: Vec<(RegionSpace, Box<dyn RegionHandler>)>) -> Self {
|
||||
+ pub fn new(aml_region_handlers: Vec<(RegionSpace, Box<dyn RegionHandler>)>, pci_fd: Arc<parking_lot::RwLock<Option<libredox::Fd>>>) -> Self {
|
||||
@@ -256,0 +269 @@ impl AmlSymbols {
|
||||
+ pci_fd,
|
||||
@@ -260 +273 @@ impl AmlSymbols {
|
||||
- pub fn init(&mut self, pci_fd: Option<&libredox::Fd>) -> Result<(), Box<dyn Error>> {
|
||||
+ pub fn init(&mut self) -> Result<(), Box<dyn Error>> {
|
||||
@@ -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<AmlError> 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<Option<S5State>>,
|
||||
+
|
||||
+ pub pci_fd: Arc<parking_lot::RwLock<Option<libredox::Fd>>>,
|
||||
+
|
||||
@@ -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<Vec<String>, 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<S5State, ShutdownError> {
|
||||
+ 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::<u8>::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::<u8>::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::<u16>::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::<u16>::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::<u8>::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::<u16>::new(port).write(val);
|
||||
+ { Pio::<u16>::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::<FadtStruct>(&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<Fd>,
|
||||
@@ -30,0 +31 @@ pub struct AcpiScheme<'acpi, 'sock> {
|
||||
+ dmi_text: Option<String>,
|
||||
@@ -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<DmiStrings>) -> 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);
|
||||
|
||||
Reference in New Issue
Block a user