acpi/sdt/
hpet.rs

1use crate::{
2    AcpiError,
3    AcpiTable,
4    AcpiTables,
5    Handler,
6    address::RawGenericAddress,
7    sdt::{SdtHeader, Signature},
8};
9use bit_field::BitField;
10use log::warn;
11
12#[derive(Debug)]
13pub enum PageProtection {
14    None,
15    /// Access to the rest of the 4KiB, relative to the base address, will not generate a fault.
16    Protected4K,
17    /// Access to the rest of the 64KiB, relative to the base address, will not generate a fault.
18    Protected64K,
19    Other,
20}
21
22/// Information about the High Precision Event Timer (HPET)
23#[derive(Debug)]
24pub struct HpetInfo {
25    pub hardware_rev: u8,
26    pub num_comparators: u8,
27    pub main_counter_is_64bits: bool,
28    pub legacy_irq_capable: bool,
29    pub pci_vendor_id: u16,
30    pub base_address: usize,
31    pub hpet_number: u8,
32    /// The minimum number of clock ticks that can be set without losing interrupts (for timers in Periodic Mode)
33    pub clock_tick_unit: u16,
34    pub page_protection: PageProtection,
35}
36
37impl HpetInfo {
38    pub fn new<H>(tables: &AcpiTables<H>) -> Result<HpetInfo, AcpiError>
39    where
40        H: Handler,
41    {
42        let Some(hpet) = tables.find_table::<HpetTable>() else { Err(AcpiError::TableNotFound(Signature::HPET))? };
43
44        if hpet.base_address.address_space != 0 {
45            warn!("HPET reported as not in system memory; tables invalid?");
46        }
47
48        let event_timer_block_id = hpet.event_timer_block_id;
49        Ok(HpetInfo {
50            hardware_rev: event_timer_block_id.get_bits(0..8) as u8,
51            num_comparators: event_timer_block_id.get_bits(8..13) as u8,
52            main_counter_is_64bits: event_timer_block_id.get_bit(13),
53            legacy_irq_capable: event_timer_block_id.get_bit(15),
54            pci_vendor_id: event_timer_block_id.get_bits(16..32) as u16,
55            base_address: hpet.base_address.address as usize,
56            hpet_number: hpet.hpet_number,
57            clock_tick_unit: hpet.clock_tick_unit,
58            page_protection: match hpet.page_protection_and_oem.get_bits(0..4) {
59                0 => PageProtection::None,
60                1 => PageProtection::Protected4K,
61                2 => PageProtection::Protected64K,
62                3..=15 => PageProtection::Other,
63                _ => unreachable!(),
64            },
65        })
66    }
67}
68
69#[repr(C, packed)]
70#[derive(Debug, Clone, Copy)]
71pub struct HpetTable {
72    pub header: SdtHeader,
73    pub event_timer_block_id: u32,
74    pub base_address: RawGenericAddress,
75    pub hpet_number: u8,
76    pub clock_tick_unit: u16,
77    /// Bits `0..4` specify the page protection guarantee. Bits `4..8` are reserved for OEM attributes.
78    pub page_protection_and_oem: u8,
79}
80
81unsafe impl AcpiTable for HpetTable {
82    const SIGNATURE: Signature = Signature::HPET;
83
84    fn header(&self) -> &SdtHeader {
85        &self.header
86    }
87}