summaryrefslogtreecommitdiff
path: root/src/hpet.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/hpet.rs')
-rw-r--r--src/hpet.rs99
1 files changed, 99 insertions, 0 deletions
diff --git a/src/hpet.rs b/src/hpet.rs
new file mode 100644
index 0000000..6360486
--- /dev/null
+++ b/src/hpet.rs
@@ -0,0 +1,99 @@
+use crate::{
+ address::RawGenericAddress,
+ sdt::{SdtHeader, Signature},
+ AcpiError,
+ AcpiHandler,
+ AcpiTable,
+ AcpiTables,
+};
+use bit_field::BitField;
+
+#[derive(Debug)]
+pub enum PageProtection {
+ None,
+ /// Access to the rest of the 4KiB, relative to the base address, will not generate a fault.
+ Protected4K,
+ /// Access to the rest of the 64KiB, relative to the base address, will not generate a fault.
+ Protected64K,
+ Other,
+}
+
+/// Information about the High Precision Event Timer (HPET)
+#[derive(Debug)]
+pub struct HpetInfo {
+ // TODO(3.0.0): unpack these fields directly, and get rid of methods
+ pub event_timer_block_id: u32,
+ pub base_address: usize,
+ pub hpet_number: u8,
+ /// The minimum number of clock ticks that can be set without losing interrupts (for timers in Periodic Mode)
+ pub clock_tick_unit: u16,
+ pub page_protection: PageProtection,
+}
+
+impl HpetInfo {
+ pub fn new<H>(tables: &AcpiTables<H>) -> Result<HpetInfo, AcpiError>
+ where
+ H: AcpiHandler,
+ {
+ let hpet = tables.find_table::<HpetTable>()?;
+
+ // Make sure the HPET is in system memory
+ assert_eq!(hpet.base_address.address_space, 0);
+
+ Ok(HpetInfo {
+ event_timer_block_id: hpet.event_timer_block_id,
+ base_address: hpet.base_address.address as usize,
+ hpet_number: hpet.hpet_number,
+ clock_tick_unit: hpet.clock_tick_unit,
+ page_protection: match hpet.page_protection_and_oem.get_bits(0..4) {
+ 0 => PageProtection::None,
+ 1 => PageProtection::Protected4K,
+ 2 => PageProtection::Protected64K,
+ 3..=15 => PageProtection::Other,
+ _ => unreachable!(),
+ },
+ })
+ }
+
+ pub fn hardware_rev(&self) -> u8 {
+ self.event_timer_block_id.get_bits(0..8) as u8
+ }
+
+ pub fn num_comparators(&self) -> u8 {
+ self.event_timer_block_id.get_bits(8..13) as u8 + 1
+ }
+
+ pub fn main_counter_is_64bits(&self) -> bool {
+ self.event_timer_block_id.get_bit(13)
+ }
+
+ pub fn legacy_irq_capable(&self) -> bool {
+ self.event_timer_block_id.get_bit(15)
+ }
+
+ pub fn pci_vendor_id(&self) -> u16 {
+ self.event_timer_block_id.get_bits(16..32) as u16
+ }
+}
+
+#[repr(C, packed)]
+#[derive(Debug, Clone, Copy)]
+pub struct HpetTable {
+ /// The contents of the HPET's 'General Capabilities and ID register'
+ header: SdtHeader,
+ event_timer_block_id: u32,
+ base_address: RawGenericAddress,
+ hpet_number: u8,
+ clock_tick_unit: u16,
+ /// Bits `0..4` specify the page protection guarantee. Bits `4..8` are reserved for OEM attributes.
+ page_protection_and_oem: u8,
+}
+
+/// ### Safety: Implementation properly represents a valid HPET table.
+unsafe impl AcpiTable for HpetTable {
+ const SIGNATURE: Signature = Signature::HPET;
+
+ fn header(&self) -> &SdtHeader {
+ &self.header
+ }
+}