good-os-framework 0.5.3

A simple operating system framework for framekernel written in Rust
Documentation
use core::sync::atomic::{AtomicBool, Ordering};
use core::{cell::UnsafeCell, ptr};
use x86_64::PhysAddr;

use crate::arch::acpi::ACPI;
use crate::memory::convert_physical_to_virtual;

pub static HPET: Hpet = Hpet::uninit();
pub static HPET_INIT: AtomicBool = AtomicBool::new(false);

pub fn init() {
    let acpi = ACPI.try_get().unwrap();
    let physical_address = PhysAddr::new(acpi.hpet_info.base_address as u64);
    let virtual_address = convert_physical_to_virtual(physical_address);

    HPET.init(virtual_address.as_u64());
    HPET.enable_counter();

    log::debug!("HPET clock speed: {} femto seconds", HPET.clock_speed());
    log::debug!("HPET timers: {} available", HPET.timers_count());

    HPET_INIT.store(true, Ordering::SeqCst);
}

pub struct Hpet {
    base_addr: UnsafeCell<u64>,
}

impl Hpet {
    #[inline]
    pub const fn uninit() -> Self {
        Hpet {
            base_addr: UnsafeCell::new(0),
        }
    }

    pub fn init(&self, base_addr: u64) {
        unsafe {
            self.base_addr.get().write(base_addr);
        }
    }

    /// Gets the clock speed of the HPET.
    pub fn clock_speed(&self) -> u32 {
        unsafe {
            let base_addr = *self.base_addr.get();
            let value = ptr::read_volatile(base_addr as *const u64);
            (value >> 32) as u32
        }
    }

    /// Gets the timers count of the HPET.
    pub fn timers_count(&self) -> u32 {
        unsafe {
            let base_addr = *self.base_addr.get();
            let value = ptr::read_volatile(base_addr as *const u64);
            (((value >> 8) & 0b11111) + 1) as u32
        }
    }

    /// Enable the HPET counter.
    pub fn enable_counter(&self) {
        unsafe {
            let configuration_addr = *self.base_addr.get() + 0x10;
            let old = ptr::read_volatile(configuration_addr as *const u64);
            ptr::write_volatile(configuration_addr as *mut u64, old | 1);
        }
    }

    /// Read the current value of the HPET counter.
    pub fn get_counter(&self) -> u64 {
        unsafe {
            let counter_l_addr = *self.base_addr.get() + 0xf0;
            let counter_h_addr = *self.base_addr.get() + 0xf4;
            loop {
                let high1 = ptr::read_volatile(counter_h_addr as *const u32);
                let low = ptr::read_volatile(counter_l_addr as *const u32);
                let high2 = ptr::read_volatile(counter_h_addr as *const u32);
                if high1 == high2 {
                    return (high1 as u64) << 32 | low as u64;
                }
            }
        }
    }

    /// Get the time
    #[inline]
    pub fn get_time_elapsed(&self) -> u64 {
        self.get_counter() * (self.clock_speed() as u64 / 1_000_000)
    }
}

unsafe impl Sync for Hpet {}