strat9_kernel/arch/x86_64/
timer.rs1use core::sync::atomic::{AtomicBool, AtomicU32, Ordering};
8use x86_64::instructions::port::Port;
9
10pub const TIMER_HZ: u64 = 100;
15
16pub const NS_PER_TICK: u64 = 1_000_000_000 / TIMER_HZ;
18
19const PIT_CHANNEL0_PORT: u16 = 0x40;
21const PIT_COMMAND_PORT: u16 = 0x43;
22const PIT_FREQUENCY: u32 = 1_193_182; static APIC_TIMER_ACTIVE: AtomicBool = AtomicBool::new(false);
26static APIC_TICKS_PER_10MS: AtomicU32 = AtomicU32::new(0);
28
29pub fn init_pit(frequency_hz: u32) {
34 log::info!("========================================");
35 log::info!("PIT INITIALIZATION (fallback mode)");
36 log::info!("========================================");
37 log::info!("Target frequency: {} Hz", frequency_hz);
38 log::info!("PIT base frequency: {} Hz", PIT_FREQUENCY);
39
40 let divisor = PIT_FREQUENCY / frequency_hz;
41 log::info!("Calculated divisor: {} (0x{:04X})", divisor, divisor);
42
43 let actual_freq = PIT_FREQUENCY / divisor;
45 log::info!(
46 "Expected actual frequency: {} Hz (error: {} Hz)",
47 actual_freq,
48 if actual_freq > frequency_hz {
49 actual_freq - frequency_hz
50 } else {
51 frequency_hz - actual_freq
52 }
53 );
54
55 let mut cmd_port = Port::new(PIT_COMMAND_PORT);
67 unsafe {
68 cmd_port.write(0x34u8); }
70 log::info!(
71 "PIT command port (0x{:X}) wrote: 0x{:02X}",
72 PIT_COMMAND_PORT,
73 0x34u8
74 );
75 log::info!(" Channel: 0");
76 log::info!(" Access: low byte then high byte");
77 log::info!(" Mode: 2 (Rate Generator)");
78
79 let mut ch0_port = Port::new(PIT_CHANNEL0_PORT);
81 let low_byte = (divisor & 0xFF) as u8;
82 let high_byte = ((divisor >> 8) & 0xFF) as u8;
83
84 unsafe {
85 ch0_port.write(low_byte); ch0_port.write(high_byte); }
88
89 log::info!("PIT channel 0 port (0x{:X}) wrote:", PIT_CHANNEL0_PORT);
90 log::info!(" Low byte: 0x{:02X} ({})", low_byte, low_byte);
91 log::info!(" High byte: 0x{:02X} ({})", high_byte, high_byte);
92
93 log::info!("========================================");
94 log::info!("PIT INITIALIZED SUCCESSFULLY");
95 log::info!(" Frequency: {} Hz", frequency_hz);
96 log::info!(" Interval: {} ms", 1_000 / frequency_hz);
97 log::info!("========================================");
98}
99
100pub fn is_apic_timer_active() -> bool {
102 APIC_TIMER_ACTIVE.load(Ordering::Relaxed)
103}
104
105pub fn stop_pit() {
111 let mut cmd_port = Port::new(PIT_COMMAND_PORT);
112 let mut ch0_port = Port::new(PIT_CHANNEL0_PORT);
113 unsafe {
114 cmd_port.write(0x30u8);
116 ch0_port.write(0u8);
118 ch0_port.write(0u8);
119 }
120 log::debug!("PIT channel 0 stopped (one-shot mode, count=0)");
121}
122
123pub fn calibrate_apic_timer() -> u32 {
130 use super::{
131 apic,
132 io::{inb, outb},
133 };
134 let saved_flags = super::save_flags_and_cli();
135
136 log::info!("========================================");
140 log::info!("APIC TIMER CALIBRATION (verbose debug)");
141 log::info!("========================================");
142
143 const PIT_10MS_COUNT: u16 = 11932;
145 const PIT_WINDOW_NS: u64 = (PIT_10MS_COUNT as u64) * 1_000_000_000 / (PIT_FREQUENCY as u64);
146 const MAX_POLL_ITERATIONS: u32 = 10_000_000;
148
149 log::info!("PIT frequency: {} Hz", PIT_FREQUENCY);
150 log::info!("PIT 10ms count: {}", PIT_10MS_COUNT);
151 log::info!("Target wait time: ~10ms");
152
153 unsafe {
158 apic::write_reg(apic::REG_LVT_TIMER, apic::LVT_TIMER_MASKED);
159 apic::write_reg(apic::REG_TIMER_DIVIDE, 0x03);
160 apic::write_reg(apic::REG_TIMER_INIT, 0);
161 }
162 log::info!("APIC timer divide set to 16 (0x03)");
163
164 unsafe {
184 let val = inb(0x61);
185 log::info!("Port 0x61 initial value: 0x{:02X}", val);
186 outb(0x61, val & 0xFC); }
188 log::info!("PIT channel 2 gate DISABLED for setup");
189
190 unsafe {
195 outb(0x43, 0xB0);
196 outb(0x42, (PIT_10MS_COUNT & 0xFF) as u8); outb(0x42, ((PIT_10MS_COUNT >> 8) & 0xFF) as u8); }
199 log::info!(
200 "PIT channel 2 programmed: mode 0 (one-shot), count={}",
201 PIT_10MS_COUNT
202 );
203 log::info!(" Low byte: 0x{:02X}", (PIT_10MS_COUNT & 0xFF) as u8);
204 log::info!(
205 " High byte: 0x{:02X}",
206 ((PIT_10MS_COUNT >> 8) & 0xFF) as u8
207 );
208
209 unsafe {
215 apic::write_reg(apic::REG_TIMER_INIT, 0xFFFF_FFFF);
216 }
217
218 let tsc_start = super::rdtsc();
222 unsafe {
223 let val = inb(0x61);
224 outb(0x61, (val | 0x01) & 0xFD); }
226
227 let mut iterations: u32 = 0;
230 loop {
231 let status = unsafe { inb(0x61) };
233 if status & 0x20 != 0 {
234 break; }
236 iterations += 1;
237 if iterations >= MAX_POLL_ITERATIONS {
238 log::warn!(
239 "APIC timer calibration: PIT poll timeout after {} iterations",
240 iterations
241 );
242 log::warn!(" This may indicate a hardware issue or incorrect PIT configuration");
243 unsafe {
245 apic::write_reg(apic::REG_TIMER_INIT, 0);
246 }
247 super::restore_flags(saved_flags);
248 return 0;
249 }
250 }
251 let tsc_delta = super::rdtsc().wrapping_sub(tsc_start);
252
253 let current = unsafe { apic::read_reg(apic::REG_TIMER_CURRENT) };
256 let elapsed = 0xFFFF_FFFFu32.wrapping_sub(current);
257
258 unsafe {
261 apic::write_reg(apic::REG_LVT_TIMER, apic::LVT_TIMER_MASKED);
262 apic::write_reg(apic::REG_TIMER_INIT, 0);
263 }
264
265 log::info!("PIT poll completed after {} iterations", iterations);
269 log::info!("APIC timer current count: 0x{:08X}", current);
270 log::info!("APIC timer elapsed ticks: {} (0x{:08X})", elapsed, elapsed);
271
272 if elapsed == 0 {
274 log::error!("APIC timer calibration: ZERO ticks measured!");
275 log::error!(" This indicates a serious problem with the APIC timer");
276 super::restore_flags(saved_flags);
277 return 0;
278 }
279
280 const MIN_EXPECTED_TICKS: u32 = 1_000; const MAX_EXPECTED_TICKS: u32 = 5_000_000; if elapsed < MIN_EXPECTED_TICKS {
289 log::warn!(
290 "APIC calibration SUSPICIOUS: {} ticks/10ms is TOO LOW",
291 elapsed
292 );
293 log::warn!(
294 " Expected range: {} - {} ticks/10ms",
295 MIN_EXPECTED_TICKS,
296 MAX_EXPECTED_TICKS
297 );
298 log::warn!(" Possible causes:");
299 log::warn!(" - APIC divide configured incorrectly");
300 log::warn!(" - PIT frequency mismatch");
301 log::warn!(" - hardware issue");
302 log::warn!(" Forcing fallback to PIT timer");
303 super::restore_flags(saved_flags);
304 return 0;
305 }
306
307 if elapsed > MAX_EXPECTED_TICKS {
308 log::warn!(
309 "APIC calibration SUSPICIOUS: {} ticks/10ms is TOO HIGH",
310 elapsed
311 );
312 log::warn!(
313 " Expected range: {} - {} ticks/10ms",
314 MIN_EXPECTED_TICKS,
315 MAX_EXPECTED_TICKS
316 );
317 log::warn!(" Possible causes:");
318 log::warn!(" - PIT poll completed too early");
319 log::warn!(" - APIC timer running at wrong frequency");
320 log::warn!(" - hardware issue");
321 log::warn!(" Forcing fallback to PIT timer");
322 super::restore_flags(saved_flags);
323 return 0;
324 }
325
326 let estimated_cpu_freq_mhz = (elapsed as u64) * 16 * 100 / 1_000_000;
329 log::info!(
330 "Estimated CPU frequency: {} MHz (based on APIC ticks)",
331 estimated_cpu_freq_mhz
332 );
333 super::boot_timestamp::calibrate(PIT_WINDOW_NS, tsc_delta);
334 log::info!(
335 "Measured TSC frequency: {} KHz (window={} ns, delta={})",
336 super::boot_timestamp::tsc_khz(),
337 PIT_WINDOW_NS,
338 tsc_delta
339 );
340
341 APIC_TICKS_PER_10MS.store(elapsed, Ordering::Release);
343
344 log::info!("========================================");
345 log::info!("APIC TIMER CALIBRATION COMPLETE");
346 log::info!(" Ticks per 10ms: {}", elapsed);
347 log::info!(" Expected frequency: ~100Hz");
348 log::info!(" Estimated CPU: {} MHz", estimated_cpu_freq_mhz);
349 log::info!("========================================");
350
351 super::restore_flags(saved_flags);
352 elapsed
353}
354
355pub fn start_apic_timer(ticks_per_10ms: u32) {
360 use super::apic;
361
362 log::info!("========================================");
363 log::info!("APIC TIMER START");
364 log::info!("========================================");
365
366 if ticks_per_10ms == 0 {
367 log::warn!("APIC timer: cannot start with 0 ticks");
368 return;
369 }
370
371 log::info!("Ticks per 10ms: {}", ticks_per_10ms);
372 log::info!("Target frequency: 100Hz (10ms interval)");
373
374 super::idt::register_lapic_timer_vector(apic::LVT_TIMER_VECTOR);
376
377 unsafe {
379 let divide_val = apic::read_reg(apic::REG_TIMER_DIVIDE);
381 log::info!("APIC timer divide register before: 0x{:08X}", divide_val);
382 apic::write_reg(apic::REG_TIMER_DIVIDE, 0x03);
383 let divide_val_after = apic::read_reg(apic::REG_TIMER_DIVIDE);
384 log::info!(
385 "APIC timer divide register after: 0x{:08X}",
386 divide_val_after
387 );
388
389 let lvt_before = apic::read_reg(apic::REG_LVT_TIMER);
391 log::info!("LVT Timer register before: 0x{:08X}", lvt_before);
392
393 let lvt_config = apic::LVT_TIMER_PERIODIC | (apic::LVT_TIMER_VECTOR as u32);
394 log::info!(
395 "LVT Timer config: 0x{:08X} (periodic + vector {:#x})",
396 lvt_config,
397 apic::LVT_TIMER_VECTOR
398 );
399 apic::write_reg(apic::REG_LVT_TIMER, lvt_config);
400
401 let lvt_after = apic::read_reg(apic::REG_LVT_TIMER);
402 log::info!("LVT Timer register after: 0x{:08X}", lvt_after);
403
404 stop_pit();
405
406 log::info!(
408 "Setting timer initial count to: {} (0x{:08X})",
409 ticks_per_10ms,
410 ticks_per_10ms
411 );
412 apic::write_reg(apic::REG_TIMER_INIT, ticks_per_10ms);
413
414 let init_verify = apic::read_reg(apic::REG_TIMER_INIT);
415 log::info!(
416 "Timer initial count verified: {} (0x{:08X})",
417 init_verify,
418 init_verify
419 );
420 }
421
422 APIC_TIMER_ACTIVE.store(true, Ordering::Relaxed);
423
424 log::info!(
425 "APIC timer: started periodic mode, vector={:#x}, count={} ({}Hz)",
426 apic::LVT_TIMER_VECTOR,
427 ticks_per_10ms,
428 TIMER_HZ,
429 );
430 log::info!("========================================");
431}
432
433pub fn apic_ticks_per_10ms() -> u32 {
435 APIC_TICKS_PER_10MS.load(Ordering::Acquire)
436}
437
438pub fn start_apic_timer_cached() {
443 let ticks = apic_ticks_per_10ms();
444 if ticks == 0 {
445 log::warn!("APIC timer: cached ticks=0, falling back to PIT");
446 init_pit(TIMER_HZ as u32);
447 return;
448 }
449 start_apic_timer(ticks);
450}