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(tables: &AcpiTables) -> Result where H: AcpiHandler, { let hpet = tables.find_table::()?; // 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 } }