Browse Source

Extract info about the HPET

Isaac Woods 6 years ago
parent
commit
de3e02e037
3 changed files with 56 additions and 9 deletions
  1. 48 4
      acpi/src/hpet.rs
  2. 4 1
      acpi/src/lib.rs
  3. 4 4
      acpi/src/sdt.rs

+ 48 - 4
acpi/src/hpet.rs

@@ -1,9 +1,31 @@
-use crate::{sdt::SdtHeader, AcpiError, GenericAddress, PhysicalMapping};
+use crate::{sdt::SdtHeader, Acpi, AcpiError, GenericAddress, PhysicalMapping};
+use bit_field::BitField;
+
+#[derive(Debug)]
+pub enum PageProtection {
+    None,
+    /// Access to the adjacent 3KB to the base address will not generate a fault.
+    Protected_4K,
+    /// Access to the adjacent 64KB to the base address will not generate a fault.
+    Protected_64K,
+    Other,
+}
+
+/// Information about the High Precision Event Timer
+#[derive(Debug)]
+pub struct HpetInfo {
+    event_timer_block_id: u32,
+    base_address: usize,
+    hpet_number: u8,
+    /// The minimum number of clock ticks that can be set without losing interrupts (for timers in
+    /// Periodic Mode)
+    clock_tick_unit: u16,
+    page_protection: PageProtection,
+}
 
 #[repr(C, packed)]
-pub struct Hpet {
+pub(crate) struct HpetTable {
     header: SdtHeader,
-
     event_timer_block_id: u32,
     base_address: GenericAddress,
     hpet_number: u8,
@@ -11,8 +33,30 @@ pub struct Hpet {
     page_protection_oem: u8,
 }
 
-pub fn parse_hpet(mapping: &PhysicalMapping<Hpet>) -> Result<(), AcpiError> {
+pub(crate) fn parse_hpet(
+    acpi: &mut Acpi,
+    mapping: &PhysicalMapping<HpetTable>,
+) -> Result<(), AcpiError> {
     (*mapping).header.validate(b"HPET")?;
+    let hpet = &*mapping;
+
+    // Make sure the HPET's in system memory
+    assert_eq!(hpet.base_address.address_space, 0);
+
+    info!("HPET address: {:#?}", hpet.base_address);
+    acpi.hpet = Some(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_oem.get_bits(0..5) {
+            0 => PageProtection::None,
+            1 => PageProtection::Protected_4K,
+            2 => PageProtection::Protected_64K,
+            3..=15 => PageProtection::Other,
+            _ => unreachable!(),
+        },
+    });
 
     Ok(())
 }

+ 4 - 1
acpi/src/lib.rs

@@ -50,7 +50,7 @@ pub use crate::{
     rsdp_search::search_for_rsdp_bios,
 };
 
-use crate::{interrupt::InterruptModel, rsdp::Rsdp, sdt::SdtHeader};
+use crate::{hpet::HpetInfo, interrupt::InterruptModel, rsdp::Rsdp, sdt::SdtHeader};
 use alloc::vec::Vec;
 use core::mem;
 
@@ -70,6 +70,7 @@ pub enum AcpiError {
     InvalidMadt(MadtError),
 }
 
+#[derive(Clone, Copy, Debug)]
 #[repr(C, packed)]
 pub(crate) struct GenericAddress {
     address_space: u8,
@@ -128,6 +129,7 @@ pub struct Acpi {
     /// hardware. For simplicity and because hardware practically will only support one model, we
     /// just error in cases that the tables detail more than one.
     interrupt_model: Option<InterruptModel>,
+    hpet: Option<HpetInfo>,
 
     /// The physical address of the DSDT, if we manage to find it.
     dsdt_address: Option<usize>,
@@ -215,6 +217,7 @@ where
         boot_processor: None,
         application_processors: Vec::new(),
         interrupt_model: None,
+        hpet: None,
         dsdt_address: None,
         ssdt_addresses: Vec::with_capacity(0),
     };

+ 4 - 4
acpi/src/sdt.rs

@@ -1,4 +1,4 @@
-use crate::{fadt::Fadt, hpet::Hpet, madt::Madt, Acpi, AcpiError, AcpiHandler};
+use crate::{fadt::Fadt, hpet::HpetTable, madt::Madt, Acpi, AcpiError, AcpiHandler};
 use core::{mem, str};
 
 /// All SDTs share the same header, and are `length` bytes long. The signature tells us which SDT
@@ -156,9 +156,9 @@ where
         }
 
         "HPET" => {
-            let hpet_mapping =
-                handler.map_physical_region::<Hpet>(physical_address, mem::size_of::<Hpet>());
-            crate::hpet::parse_hpet(&hpet_mapping)?;
+            let hpet_mapping = handler
+                .map_physical_region::<HpetTable>(physical_address, mem::size_of::<HpetTable>());
+            crate::hpet::parse_hpet(acpi, &hpet_mapping)?;
             handler.unmap_physical_region(hpet_mapping);
         }