acpi/
hpet.rs

1use crate::{
2    address::RawGenericAddress,
3    sdt::{SdtHeader, Signature},
4    AcpiError,
5    AcpiHandler,
6    AcpiTable,
7    AcpiTables,
8};
9use bit_field::BitField;
10
11#[derive(Debug)]
12pub 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)]
23pub 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
33impl HpetInfo {
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
58    pub fn hardware_rev(&self) -> u8 {
59        self.event_timer_block_id.get_bits(0..8) as u8
60    }
61
62    pub fn num_comparators(&self) -> u8 {
63        self.event_timer_block_id.get_bits(8..13) as u8 + 1
64    }
65
66    pub fn main_counter_is_64bits(&self) -> bool {
67        self.event_timer_block_id.get_bit(13)
68    }
69
70    pub fn legacy_irq_capable(&self) -> bool {
71        self.event_timer_block_id.get_bit(15)
72    }
73
74    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)]
81pub 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.
93unsafe impl AcpiTable for HpetTable {
94    const SIGNATURE: Signature = Signature::HPET;
95
96    fn header(&self) -> &SdtHeader {
97        &self.header
98    }
99}