mod apic;
mod hpet;
mod jiffies;
pub(crate) mod pit;
use alloc::{boxed::Box, vec::Vec};
use core::{cell::RefCell, sync::atomic::Ordering};
pub use jiffies::Jiffies;
use spin::Once;
use trapframe::TrapFrame;
use self::apic::APIC_TIMER_CALLBACK;
use crate::{arch::x86::kernel, cpu_local, trap::IrqLine, CpuLocal};
pub const TIMER_FREQ: u64 = 1000;
static TIMER_IRQ: Once<IrqLine> = Once::new();
pub(super) fn init() {
const PIT_MODE_TIMER_IRQ_NUM: u8 = 32;
let mut timer_irq = if kernel::apic::APIC_INSTANCE.is_completed() {
apic::init()
} else {
pit::init(pit::OperatingMode::SquareWaveGenerator);
IrqLine::alloc_specific(PIT_MODE_TIMER_IRQ_NUM).unwrap()
};
timer_irq.on_active(timer_callback);
TIMER_IRQ.call_once(|| timer_irq);
}
cpu_local! {
static INTERRUPT_CALLBACKS: RefCell<Vec<Box<dyn Fn() + Sync + Send>>> = RefCell::new(Vec::new());
}
pub fn register_callback<F>(func: F)
where
F: Fn() + Sync + Send + 'static,
{
CpuLocal::borrow_with(&INTERRUPT_CALLBACKS, |callbacks| {
callbacks.borrow_mut().push(Box::new(func));
});
}
fn timer_callback(_: &TrapFrame) {
jiffies::ELAPSED.fetch_add(1, Ordering::SeqCst);
CpuLocal::borrow_with(&INTERRUPT_CALLBACKS, |callbacks| {
for callback in callbacks.borrow().iter() {
(callback)();
}
});
if APIC_TIMER_CALLBACK.is_completed() {
APIC_TIMER_CALLBACK.get().unwrap().call(());
}
}