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}