Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions src/address.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::<u16>();
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::<u16>();
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.
Expand Down
12 changes: 3 additions & 9 deletions src/platform/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use crate::{
Handler,
PowerProfile,
address::GenericAddress,
registers::{FixedRegisters, Pm1ControlBit, Pm1Event},
registers::{FixedRegisters, Pm1ControlBit, Pm1EventFlags},
sdt::{
Signature,
fadt::Fadt,
Expand Down Expand Up @@ -82,15 +82,9 @@ impl<H: Handler, A: Allocator + Clone> AcpiPlatform<H, A> {
/// 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

Expand Down
76 changes: 39 additions & 37 deletions src/registers.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use crate::{AcpiError, Handler, address::MappedGas, sdt::fadt::Fadt};
use bit_field::BitField;
use bitflags::{Flags, bitflags};

pub struct FixedRegisters<H: Handler> {
pub pm1_event_registers: Pm1EventRegisterBlock<H>,
Expand Down Expand Up @@ -46,54 +47,55 @@ pub struct Pm1EventRegisterBlock<H: Handler> {
pub pm1b: Option<MappedGas<H>>,
}

#[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_ENABLE = 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<H> Pm1EventRegisterBlock<H>
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<u64, AcpiError> {
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 };
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)
}

Ok(pm1a | pm1b)
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);
}
}
}

Expand Down