diff options
Diffstat (limited to 'src/hpet.rs')
-rw-r--r-- | src/hpet.rs | 99 |
1 files changed, 99 insertions, 0 deletions
diff --git a/src/hpet.rs b/src/hpet.rs new file mode 100644 index 0000000..6360486 --- /dev/null +++ b/src/hpet.rs @@ -0,0 +1,99 @@ +use crate::{ + address::RawGenericAddress, + sdt::{SdtHeader, Signature}, + AcpiError, + AcpiHandler, + AcpiTable, + AcpiTables, +}; +use bit_field::BitField; + +#[derive(Debug)] +pub enum PageProtection { + None, + /// Access to the rest of the 4KiB, relative to the base address, will not generate a fault. + Protected4K, + /// Access to the rest of the 64KiB, relative to the base address, will not generate a fault. + Protected64K, + Other, +} + +/// Information about the High Precision Event Timer (HPET) +#[derive(Debug)] +pub struct HpetInfo { + // TODO(3.0.0): unpack these fields directly, and get rid of methods + pub event_timer_block_id: u32, + pub base_address: usize, + pub hpet_number: u8, + /// The minimum number of clock ticks that can be set without losing interrupts (for timers in Periodic Mode) + pub clock_tick_unit: u16, + pub page_protection: PageProtection, +} + +impl HpetInfo { + pub fn new<H>(tables: &AcpiTables<H>) -> Result<HpetInfo, AcpiError> + where + H: AcpiHandler, + { + let hpet = tables.find_table::<HpetTable>()?; + + // Make sure the HPET is in system memory + assert_eq!(hpet.base_address.address_space, 0); + + Ok(HpetInfo { + event_timer_block_id: hpet.event_timer_block_id, + base_address: hpet.base_address.address as usize, + hpet_number: hpet.hpet_number, + clock_tick_unit: hpet.clock_tick_unit, + page_protection: match hpet.page_protection_and_oem.get_bits(0..4) { + 0 => PageProtection::None, + 1 => PageProtection::Protected4K, + 2 => PageProtection::Protected64K, + 3..=15 => PageProtection::Other, + _ => unreachable!(), + }, + }) + } + + pub fn hardware_rev(&self) -> u8 { + self.event_timer_block_id.get_bits(0..8) as u8 + } + + pub fn num_comparators(&self) -> u8 { + self.event_timer_block_id.get_bits(8..13) as u8 + 1 + } + + pub fn main_counter_is_64bits(&self) -> bool { + self.event_timer_block_id.get_bit(13) + } + + pub fn legacy_irq_capable(&self) -> bool { + self.event_timer_block_id.get_bit(15) + } + + pub fn pci_vendor_id(&self) -> u16 { + self.event_timer_block_id.get_bits(16..32) as u16 + } +} + +#[repr(C, packed)] +#[derive(Debug, Clone, Copy)] +pub struct HpetTable { + /// The contents of the HPET's 'General Capabilities and ID register' + header: SdtHeader, + event_timer_block_id: u32, + base_address: RawGenericAddress, + hpet_number: u8, + clock_tick_unit: u16, + /// Bits `0..4` specify the page protection guarantee. Bits `4..8` are reserved for OEM attributes. + page_protection_and_oem: u8, +} + +/// ### Safety: Implementation properly represents a valid HPET table. +unsafe impl AcpiTable for HpetTable { + const SIGNATURE: Signature = Signature::HPET; + + fn header(&self) -> &SdtHeader { + &self.header + } +} |