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