Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

acpi: Expose extra register information in FADT #198

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
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
81 changes: 81 additions & 0 deletions acpi/src/fadt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,20 @@ pub enum PowerProfile {
Reserved(u8),
}

/// PM1x status and enable registers. These registers are part of PM1x event blocks and provide
/// access to fixed hardware status/enable features like power button, power management timer etc.
#[derive(Debug, Clone)]
pub struct Pm1Registers {
/// PM1a fixed hardware status register
pub x_pm1a_status: GenericAddress,
/// PM1a fixed hardware enable register
pub x_pm1a_enable: GenericAddress,
/// PM1b fixed hardware status register
pub x_pm1b_status: Option<GenericAddress>,
/// PM1b fixed hardware enable register
pub x_pm1b_enable: Option<GenericAddress>,
}

/// Represents the Fixed ACPI Description Table (FADT). This table contains various fixed hardware
/// details, such as the addresses of the hardware register blocks. It also contains a pointer to
/// the Differentiated Definition Block (DSDT).
Expand Down Expand Up @@ -346,6 +360,73 @@ impl Fadt {
Ok(None)
}
}

/// Returns the PM1x fixed hardware feature registers
pub fn pm1_registers(&self) -> Result<Pm1Registers, AcpiError> {
let pm1a_event_block = self.pm1a_event_block()?;
let pm1b_event_block = self.pm1b_event_block()?;
let pm1_byte_width = pm1a_event_block.bit_width / 16;

let x_pm1a_status = GenericAddress {
address_space: pm1a_event_block.address_space,
address: pm1a_event_block.address,
bit_width: pm1_byte_width * 8,
bit_offset: 0,
access_size: AccessSize::Undefined,
};
let x_pm1a_enable = GenericAddress {
address_space: pm1a_event_block.address_space,
address: pm1a_event_block.address + pm1_byte_width as u64,
bit_width: pm1_byte_width * 8,
bit_offset: 0,
access_size: AccessSize::Undefined,
};

let (x_pm1b_status, x_pm1b_enable) = if let Some(pm1b) = pm1b_event_block {
(
Some(GenericAddress {
address_space: pm1b.address_space,
address: pm1b.address,
bit_width: pm1_byte_width * 8,
bit_offset: 0,
access_size: AccessSize::Undefined,
}),
Some({
GenericAddress {
address_space: pm1b.address_space,
address: pm1b.address + pm1_byte_width as u64,
bit_width: pm1_byte_width * 8,
bit_offset: 0,
access_size: AccessSize::Undefined,
}
}),
)
} else {
(None, None)
};

Ok(Pm1Registers { x_pm1a_status, x_pm1a_enable, x_pm1b_status, x_pm1b_enable })
}

/// Returns the length of General-Purpose Event register block 0 in bytes.
///
/// # Note
///
/// The GPE blocks are optional, their presence first needs to be checked through gpe0_block().
#[inline]
pub const fn gpe0_block_length(&self) -> u8 {
self.gpe0_block_length
}

/// Returns the length of General-Purpose Event register block 1 in bytes.
///
/// # Note
///
/// The GPE blocks are optional, their presence first needs to be checked through gpe0_block().
#[inline]
pub const fn gpe1_block_length(&self) -> u8 {
self.gpe1_block_length
}
}

#[derive(Clone, Copy, Debug)]
Expand Down