From be38acd3d17d5a47f8ff1124efa1edc0844ec843 Mon Sep 17 00:00:00 2001 From: Rajas Paranjpe <52586855+ChocolateLoverRaj@users.noreply.github.com> Date: Wed, 26 Aug 2026 23:27:57 -0700 Subject: [PATCH 1/2] Add methods to get and clear Pm1 events --- src/address.rs | 26 ++++++++++++++++++++++++++ src/registers.rs | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+) diff --git a/src/address.rs b/src/address.rs index 0bb3eeb3..701d18ad 100644 --- a/src/address.rs +++ b/src/address.rs @@ -216,6 +216,32 @@ where } } } + + /// Ignores the GAS access size and does a 16-bit read. + pub fn read_u16(&self, byte_offset: u64) -> u16 { + match self.gas.address_space { + AddressSpace::SystemMemory => { + let addr = self.mapping.as_ref().unwrap().virtual_start.cast::(); + unsafe { addr.byte_offset(byte_offset as isize).read_unaligned() } + } + AddressSpace::SystemIo => self.handler.read_io_u16(self.gas.address as u16 + byte_offset as u16), + address_space => todo!("{address_space:?}"), + } + } + + /// Ignores the GAS access size and does a 16-bit write. + pub fn write_u16(&self, byte_offset: u64, value: u16) { + match self.gas.address_space { + AddressSpace::SystemMemory => { + let addr = self.mapping.as_ref().unwrap().virtual_start.cast::(); + unsafe { addr.byte_offset(byte_offset as isize).write_unaligned(value) } + } + AddressSpace::SystemIo => { + self.handler.write_io_u16(self.gas.address as u16 + byte_offset as u16, value) + } + address_space => todo!("{address_space:?}"), + } + } } /// Returns the access size that should be made for a given `GenericAddress`, in bits. diff --git a/src/registers.rs b/src/registers.rs index 58701805..ecf2f597 100644 --- a/src/registers.rs +++ b/src/registers.rs @@ -1,5 +1,6 @@ use crate::{AcpiError, Handler, address::MappedGas, sdt::fadt::Fadt}; use bit_field::BitField; +use bitflags::{Flags, bitflags}; pub struct FixedRegisters { pub pm1_event_registers: Pm1EventRegisterBlock, @@ -58,6 +59,19 @@ pub enum Pm1Event { Wake = 15, } +bitflags! { + #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] + pub struct Pm1EventFlags: u16 { + const TIMER = 1 << 0; + const GLOBAL_LOCK = 1 << 5; + const POWER_BUTTON = 1 << 8; + const SLEEP_BUTTON = 1 << 9; + const RTC = 1 << 10; + const PCIE_WAKE = 1 << 14; + const WAKE = 1 << 15; + } +} + impl Pm1EventRegisterBlock where H: Handler, @@ -95,6 +109,25 @@ where Ok(pm1a | pm1b) } + + pub fn pending_events(&self) -> Pm1EventFlags { + let bits = { + let mut bits = self.pm1a.read_u16(0); + if let Some(pm1b) = &self.pm1b { + bits |= pm1b.read_u16(0); + } + bits + }; + Pm1EventFlags::from_bits_retain(bits) + } + + pub fn clear_events(&self, events: Pm1EventFlags) { + let bits = events.known_bits(); + self.pm1a.write_u16(0, bits); + if let Some(pm1b) = &self.pm1b { + pm1b.write_u16(0, bits); + } + } } pub struct Pm1ControlRegisterBlock { From a54e8f68a6f5d19055253d2e0db85ecbbd71ad86 Mon Sep 17 00:00:00 2001 From: Rajas Paranjpe <52586855+ChocolateLoverRaj@users.noreply.github.com> Date: Wed, 26 Aug 2026 23:33:16 -0700 Subject: [PATCH 2/2] Improve pm1 enable registers control Now set/clear all event flags in one write. This means no read is necessary and also eliminates that cause of race conditions. --- src/platform/mod.rs | 12 +++------- src/registers.rs | 55 ++++++++++----------------------------------- 2 files changed, 15 insertions(+), 52 deletions(-) diff --git a/src/platform/mod.rs b/src/platform/mod.rs index d0b42a24..470bae0e 100644 --- a/src/platform/mod.rs +++ b/src/platform/mod.rs @@ -11,7 +11,7 @@ use crate::{ Handler, PowerProfile, address::GenericAddress, - registers::{FixedRegisters, Pm1ControlBit, Pm1Event}, + registers::{FixedRegisters, Pm1ControlBit, Pm1EventFlags}, sdt::{ Signature, fadt::Fadt, @@ -82,15 +82,9 @@ impl AcpiPlatform { /// Initializes the event registers, masking all events to start. pub fn initialize_events(&self) -> Result<(), AcpiError> { /* - * Disable all fixed events to start. + * Disable all fixed event interrupts to start, including the global flag. */ - self.registers.pm1_event_registers.set_event_enabled(Pm1Event::Timer, false)?; - self.registers.pm1_event_registers.set_event_enabled(Pm1Event::GlobalLock, false)?; - self.registers.pm1_event_registers.set_event_enabled(Pm1Event::PowerButton, false)?; - self.registers.pm1_event_registers.set_event_enabled(Pm1Event::SleepButton, false)?; - self.registers.pm1_event_registers.set_event_enabled(Pm1Event::Rtc, false)?; - self.registers.pm1_event_registers.set_event_enabled(Pm1Event::PciEWake, false)?; - self.registers.pm1_event_registers.set_event_enabled(Pm1Event::Wake, false)?; + self.registers.pm1_event_registers.set_enable_flags(Pm1EventFlags::empty()); // TODO: deal with GPEs diff --git a/src/registers.rs b/src/registers.rs index ecf2f597..d80ef50f 100644 --- a/src/registers.rs +++ b/src/registers.rs @@ -47,23 +47,11 @@ pub struct Pm1EventRegisterBlock { pub pm1b: Option>, } -#[derive(Clone, Copy, PartialEq, Eq, Debug)] -#[repr(u8)] -pub enum Pm1Event { - Timer = 0, - GlobalLock = 5, - PowerButton = 8, - SleepButton = 9, - Rtc = 10, - PciEWake = 14, - Wake = 15, -} - bitflags! { #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct Pm1EventFlags: u16 { const TIMER = 1 << 0; - const GLOBAL_LOCK = 1 << 5; + const GLOBAL_ENABLE = 1 << 5; const POWER_BUTTON = 1 << 8; const SLEEP_BUTTON = 1 << 9; const RTC = 1 << 10; @@ -76,38 +64,19 @@ impl Pm1EventRegisterBlock where H: Handler, { - pub fn set_event_enabled(&self, event: Pm1Event, enabled: bool) -> Result<(), AcpiError> { - let enable_offset = self.pm1_event_length * 8 / 2; - let event_bit = match event { - Pm1Event::Timer => 0, - Pm1Event::GlobalLock => 5, - Pm1Event::PowerButton => 8, - Pm1Event::SleepButton => 9, - Pm1Event::Rtc => 10, - Pm1Event::PciEWake => 14, - Pm1Event::Wake => 15, - }; - - let mut pm1a = self.pm1a.read()?; - pm1a.set_bit(enable_offset + event_bit, enabled); - self.pm1a.write(pm1a)?; - + /// Sets the specified flags and unsets the other flags. + /// When an event happens, the corresponding status bit is always set. + /// These flags control whether an *interrupt* is triggered as a result of that status bit being set. + /// Note that global enable (GBL_EN) must be set for any SCI interrupts to be fired. + /// For most flags you set to enable and clear to disable. + /// But for PCIe wake the flag is set to disable and clear to enable. + pub fn set_enable_flags(&self, events: Pm1EventFlags) { + let enable_offset = self.pm1_event_length as u64 / 2; + let bits = events.known_bits(); + self.pm1a.write_u16(enable_offset, bits); if let Some(pm1b) = &self.pm1b { - let mut value = pm1b.read()?; - value.set_bit(enable_offset + event_bit, enabled); - pm1b.write(value)?; + pm1b.write_u16(enable_offset, bits); } - - Ok(()) - } - - pub fn read(&self) -> Result { - let pm1_len = self.pm1_event_length * 8; - - let pm1a = self.pm1a.read()?.get_bits(0..pm1_len); - let pm1b = if let Some(pm1b) = &self.pm1b { pm1b.read()?.get_bits(0..pm1_len) } else { 0 }; - - Ok(pm1a | pm1b) } pub fn pending_events(&self) -> Pm1EventFlags {