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 | |
} | |
} |