zodiac 0.3.0

Rust OS framework that offers safe interfaces for kernel development
Documentation
use core::{
    sync::atomic::{AtomicBool, AtomicU32, Ordering},
    time::Duration,
};

use x2apic::lapic::TimerMode;

use crate::hal::{kernel::LAPIC, timer::hpet::HPET};

const TIMER_FREQUENCY_HZ: u32 = 200;
const TIMER_CALIBRATION_ITERATION: u32 = 50;

static LAPIC_TIMER_INIT: AtomicBool = AtomicBool::new(false);
static LAPIC_TIMER_INITIAL: AtomicU32 = AtomicU32::new(0);

pub fn init() {
    unsafe {
        calibrate_timer();
        LAPIC.lock().enable_timer();
    }
    LAPIC_TIMER_INIT.store(true, Ordering::SeqCst);
}

pub fn ap_init() {
    while !LAPIC_TIMER_INIT.load(Ordering::SeqCst) {
        core::hint::spin_loop();
    }
    let timer_initial = LAPIC_TIMER_INITIAL.load(Ordering::Relaxed);
    unsafe {
        LAPIC.lock().set_timer_mode(TimerMode::Periodic);
        LAPIC.lock().set_timer_initial(timer_initial);
        LAPIC.lock().enable_timer();
    }
}

unsafe fn calibrate_timer() {
    let mut lapic = LAPIC.lock();
    let mut lapic_total_ticks = 0;

    for _ in 0..TIMER_CALIBRATION_ITERATION {
        let last_time = HPET.elapsed();
        unsafe {
            lapic.set_timer_initial(u32::MAX);
        }
        while HPET.elapsed() - last_time < Duration::from_millis(1) {}
        lapic_total_ticks += u32::MAX - unsafe { lapic.timer_current() };
    }

    let average_ticks_per_ms = lapic_total_ticks / TIMER_CALIBRATION_ITERATION;
    let calibrated_timer_initial = average_ticks_per_ms * 1000 / TIMER_FREQUENCY_HZ;
    log::debug!("Calibrated timer initial: {calibrated_timer_initial}");

    unsafe {
        lapic.set_timer_mode(TimerMode::Periodic);
        lapic.set_timer_initial(calibrated_timer_initial);
    }

    LAPIC_TIMER_INITIAL.store(calibrated_timer_initial, Ordering::Relaxed);
}