good_os_framework/drivers/
hpet.rs1use core::sync::atomic::{AtomicBool, Ordering};
2use core::{cell::UnsafeCell, ptr};
3use x86_64::PhysAddr;
4
5use crate::arch::acpi::ACPI;
6use crate::memory::convert_physical_to_virtual;
7
8pub static HPET: Hpet = Hpet::uninit();
9pub static HPET_INIT: AtomicBool = AtomicBool::new(false);
10
11pub fn init() {
12 let acpi = ACPI.try_get().unwrap();
13 let physical_address = PhysAddr::new(acpi.hpet_info.base_address as u64);
14 let virtual_address = convert_physical_to_virtual(physical_address);
15
16 HPET.init(virtual_address.as_u64());
17 HPET.enable_counter();
18
19 log::debug!("HPET clock speed: {} femto seconds", HPET.clock_speed());
20 log::debug!("HPET timers: {} available", HPET.timers_count());
21
22 HPET_INIT.store(true, Ordering::SeqCst);
23}
24
25pub struct Hpet {
26 base_addr: UnsafeCell<u64>,
27}
28
29impl Hpet {
30 #[inline]
31 pub const fn uninit() -> Self {
32 Hpet {
33 base_addr: UnsafeCell::new(0),
34 }
35 }
36
37 pub fn init(&self, base_addr: u64) {
38 unsafe {
39 self.base_addr.get().write(base_addr);
40 }
41 }
42
43 pub fn clock_speed(&self) -> u32 {
45 unsafe {
46 let base_addr = *self.base_addr.get();
47 let value = ptr::read_volatile(base_addr as *const u64);
48 (value >> 32) as u32
49 }
50 }
51
52 pub fn timers_count(&self) -> u32 {
54 unsafe {
55 let base_addr = *self.base_addr.get();
56 let value = ptr::read_volatile(base_addr as *const u64);
57 (((value >> 8) & 0b11111) + 1) as u32
58 }
59 }
60
61 pub fn enable_counter(&self) {
63 unsafe {
64 let configuration_addr = *self.base_addr.get() + 0x10;
65 let old = ptr::read_volatile(configuration_addr as *const u64);
66 ptr::write_volatile(configuration_addr as *mut u64, old | 1);
67 }
68 }
69
70 pub fn get_counter(&self) -> u64 {
72 unsafe {
73 let counter_l_addr = *self.base_addr.get() + 0xf0;
74 let counter_h_addr = *self.base_addr.get() + 0xf4;
75 loop {
76 let high1 = ptr::read_volatile(counter_h_addr as *const u32);
77 let low = ptr::read_volatile(counter_l_addr as *const u32);
78 let high2 = ptr::read_volatile(counter_h_addr as *const u32);
79 if high1 == high2 {
80 return (high1 as u64) << 32 | low as u64;
81 }
82 }
83 }
84 }
85
86 #[inline]
88 pub fn get_time_elapsed(&self) -> u64 {
89 self.get_counter() * (self.clock_speed() as u64 / 1_000_000)
90 }
91}
92
93unsafe impl Sync for Hpet {}