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 Protected4K,
17 Protected64K,
19 Other,
20}
21
22#[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 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 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}