⚠️ VeridianOS Kernel Documentation - This is low-level kernel code. All functions are unsafe unless explicitly marked otherwise. no_std

veridian_kernel/arch/x86_64/
timer.rs

1//! x86_64 timer implementation
2
3use core::sync::atomic::{AtomicU64, Ordering};
4
5static TICKS: AtomicU64 = AtomicU64::new(0);
6
7/// Get current timer ticks
8pub fn get_ticks() -> u64 {
9    TICKS.load(Ordering::Relaxed)
10}
11
12/// Increment timer ticks (called from APIC timer interrupt handler at vector
13/// 48).
14///
15/// Increments the global tick counter and triggers a scheduler tick for
16/// preemptive scheduling. Uses `try_lock()` on the scheduler to avoid
17/// deadlock if the scheduler lock is already held (e.g., we interrupted
18/// mid-schedule).
19pub fn tick() {
20    TICKS.fetch_add(1, Ordering::Relaxed);
21
22    // Trigger scheduler tick. Use try_lock to avoid deadlock: if the
23    // scheduler lock is already held (e.g., we interrupted mid-schedule),
24    // skip the tick -- the holder will complete its scheduling decision.
25    if let Some(mut sched) = crate::sched::scheduler::current_scheduler().try_lock() {
26        sched.tick();
27    }
28}
29
30/// Setup timer for periodic interrupts
31pub fn setup_timer(interval_ms: u32) {
32    // For now, we'll use the PIT (Programmable Interval Timer)
33    // In a real implementation, we'd use the APIC timer
34
35    const PIT_FREQUENCY: u32 = 1193182; // Hz
36    let divisor = PIT_FREQUENCY / (1000 / interval_ms);
37
38    // SAFETY: I/O port writes to the 8254 PIT (Programmable Interval Timer).
39    // Port 0x43 is the command register, port 0x40 is channel 0 data. The
40    // command 0x36 configures channel 0 for rate generator mode with
41    // lobyte/hibyte access. The divisor is split into low and high bytes.
42    unsafe {
43        use x86_64::instructions::port::Port;
44
45        // Command port
46        let mut cmd_port: Port<u8> = Port::new(0x43);
47        // Channel 0 data port
48        let mut data_port: Port<u8> = Port::new(0x40);
49
50        // Configure PIT channel 0 for periodic interrupts
51        cmd_port.write(0x36); // Channel 0, lobyte/hibyte, rate generator
52
53        // Set frequency divisor
54        data_port.write((divisor & 0xFF) as u8);
55        data_port.write((divisor >> 8) as u8);
56    }
57
58    // Enable timer interrupt (IRQ0 = interrupt 32)
59    // This would be done in the IDT setup
60    println!("[TIMER] Configured PIT for {}ms intervals", interval_ms);
61}