1 use crate::{ 2 address::RawGenericAddress, 3 sdt::{SdtHeader, Signature}, 4 AcpiError, 5 AcpiHandler, 6 AcpiTable, 7 AcpiTables, 8 }; 9 use bit_field::BitField; 10 11 #[derive(Debug)] 12 pub enum PageProtection { 13 None, 14 /// Access to the rest of the 4KiB, relative to the base address, will not generate a fault. 15 Protected4K, 16 /// Access to the rest of the 64KiB, relative to the base address, will not generate a fault. 17 Protected64K, 18 Other, 19 } 20 21 /// Information about the High Precision Event Timer (HPET) 22 #[derive(Debug)] 23 pub struct HpetInfo { 24 // TODO(3.0.0): unpack these fields directly, and get rid of methods 25 pub event_timer_block_id: u32, 26 pub base_address: usize, 27 pub hpet_number: u8, 28 /// The minimum number of clock ticks that can be set without losing interrupts (for timers in Periodic Mode) 29 pub clock_tick_unit: u16, 30 pub page_protection: PageProtection, 31 } 32 33 impl HpetInfo { new<H>(tables: &AcpiTables<H>) -> Result<HpetInfo, AcpiError> where H: AcpiHandler,34 pub fn new<H>(tables: &AcpiTables<H>) -> Result<HpetInfo, AcpiError> 35 where 36 H: AcpiHandler, 37 { 38 let hpet = tables.find_table::<HpetTable>()?; 39 40 // Make sure the HPET is in system memory 41 assert_eq!(hpet.base_address.address_space, 0); 42 43 Ok(HpetInfo { 44 event_timer_block_id: hpet.event_timer_block_id, 45 base_address: hpet.base_address.address as usize, 46 hpet_number: hpet.hpet_number, 47 clock_tick_unit: hpet.clock_tick_unit, 48 page_protection: match hpet.page_protection_and_oem.get_bits(0..4) { 49 0 => PageProtection::None, 50 1 => PageProtection::Protected4K, 51 2 => PageProtection::Protected64K, 52 3..=15 => PageProtection::Other, 53 _ => unreachable!(), 54 }, 55 }) 56 } 57 hardware_rev(&self) -> u858 pub fn hardware_rev(&self) -> u8 { 59 self.event_timer_block_id.get_bits(0..8) as u8 60 } 61 num_comparators(&self) -> u862 pub fn num_comparators(&self) -> u8 { 63 self.event_timer_block_id.get_bits(8..13) as u8 + 1 64 } 65 main_counter_is_64bits(&self) -> bool66 pub fn main_counter_is_64bits(&self) -> bool { 67 self.event_timer_block_id.get_bit(13) 68 } 69 legacy_irq_capable(&self) -> bool70 pub fn legacy_irq_capable(&self) -> bool { 71 self.event_timer_block_id.get_bit(15) 72 } 73 pci_vendor_id(&self) -> u1674 pub fn pci_vendor_id(&self) -> u16 { 75 self.event_timer_block_id.get_bits(16..32) as u16 76 } 77 } 78 79 #[repr(C, packed)] 80 #[derive(Debug, Clone, Copy)] 81 pub struct HpetTable { 82 /// The contents of the HPET's 'General Capabilities and ID register' 83 header: SdtHeader, 84 event_timer_block_id: u32, 85 base_address: RawGenericAddress, 86 hpet_number: u8, 87 clock_tick_unit: u16, 88 /// Bits `0..4` specify the page protection guarantee. Bits `4..8` are reserved for OEM attributes. 89 page_protection_and_oem: u8, 90 } 91 92 /// ### Safety: Implementation properly represents a valid HPET table. 93 unsafe impl AcpiTable for HpetTable { 94 const SIGNATURE: Signature = Signature::HPET; 95 header(&self) -> &SdtHeader96 fn header(&self) -> &SdtHeader { 97 &self.header 98 } 99 } 100