use crate::{
AcpiError,
AcpiTable,
AcpiTables,
Handler,
address::RawGenericAddress,
sdt::{SdtHeader, Signature},
};
use bit_field::BitField;
use log::warn;
#[derive(Debug)]
pub enum PageProtection {
None,
Protected4K,
Protected64K,
Other,
}
#[derive(Debug)]
pub struct HpetInfo {
pub hardware_rev: u8,
pub num_comparators: u8,
pub main_counter_is_64bits: bool,
pub legacy_irq_capable: bool,
pub pci_vendor_id: u16,
pub base_address: usize,
pub hpet_number: u8,
pub clock_tick_unit: u16,
pub page_protection: PageProtection,
}
impl HpetInfo {
pub fn new<H>(tables: &AcpiTables<H>) -> Result<HpetInfo, AcpiError>
where
H: Handler,
{
let Some(hpet) = tables.find_table::<HpetTable>() else { Err(AcpiError::TableNotFound(Signature::HPET))? };
if hpet.base_address.address_space != 0 {
warn!("HPET reported as not in system memory; tables invalid?");
}
let event_timer_block_id = hpet.event_timer_block_id;
Ok(HpetInfo {
hardware_rev: event_timer_block_id.get_bits(0..8) as u8,
num_comparators: event_timer_block_id.get_bits(8..13) as u8,
main_counter_is_64bits: event_timer_block_id.get_bit(13),
legacy_irq_capable: event_timer_block_id.get_bit(15),
pci_vendor_id: event_timer_block_id.get_bits(16..32) as u16,
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!(),
},
})
}
}
#[repr(C, packed)]
#[derive(Debug, Clone, Copy)]
pub struct HpetTable {
pub header: SdtHeader,
pub event_timer_block_id: u32,
pub base_address: RawGenericAddress,
pub hpet_number: u8,
pub clock_tick_unit: u16,
pub page_protection_and_oem: u8,
}
unsafe impl AcpiTable for HpetTable {
const SIGNATURE: Signature = Signature::HPET;
fn header(&self) -> &SdtHeader {
&self.header
}
}