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 if let Some(tsc_khz) = super::cpuid::tsc_frequency_khz() {
140 log::info!("TSC frequency from CPUID 0x15: {} KHz", tsc_khz);
141 super::boot_timestamp::calibrate_khz(tsc_khz);
142 }
143
144 log::info!("========================================");
148 log::info!("APIC TIMER CALIBRATION (verbose debug)");
149 log::info!("========================================");
150
151 const PIT_10MS_COUNT: u16 = 11932;
153 const PIT_WINDOW_NS: u64 = (PIT_10MS_COUNT as u64) * 1_000_000_000 / (PIT_FREQUENCY as u64);
154 const MAX_POLL_ITERATIONS: u32 = 10_000_000;
156
157 log::info!("PIT frequency: {} Hz", PIT_FREQUENCY);
158 log::info!("PIT 10ms count: {}", PIT_10MS_COUNT);
159 log::info!("Target wait time: ~10ms");
160
161 unsafe {
166 apic::write_reg(apic::REG_LVT_TIMER, apic::LVT_TIMER_MASKED);
167 apic::write_reg(apic::REG_TIMER_DIVIDE, 0x03);
168 apic::write_reg(apic::REG_TIMER_INIT, 0);
169 }
170 log::info!("APIC timer divide set to 16 (0x03)");
171
172 unsafe {
192 let val = inb(0x61);
193 log::info!("Port 0x61 initial value: 0x{:02X}", val);
194 outb(0x61, val & 0xFC); }
196 log::info!("PIT channel 2 gate DISABLED for setup");
197
198 unsafe {
203 outb(0x43, 0xB0);
204 outb(0x42, (PIT_10MS_COUNT & 0xFF) as u8); outb(0x42, ((PIT_10MS_COUNT >> 8) & 0xFF) as u8); }
207 log::info!(
208 "PIT channel 2 programmed: mode 0 (one-shot), count={}",
209 PIT_10MS_COUNT
210 );
211 log::info!(" Low byte: 0x{:02X}", (PIT_10MS_COUNT & 0xFF) as u8);
212 log::info!(
213 " High byte: 0x{:02X}",
214 ((PIT_10MS_COUNT >> 8) & 0xFF) as u8
215 );
216
217 unsafe {
223 apic::write_reg(apic::REG_TIMER_INIT, 0xFFFF_FFFF);
224 }
225
226 let tsc_start = super::rdtsc();
230 unsafe {
231 let val = inb(0x61);
232 outb(0x61, (val | 0x01) & 0xFD); }
234
235 let mut iterations: u32 = 0;
238 loop {
239 let status = unsafe { inb(0x61) };
241 if status & 0x20 != 0 {
242 break; }
244 iterations += 1;
245 if iterations >= MAX_POLL_ITERATIONS {
246 log::warn!(
247 "APIC timer calibration: PIT poll timeout after {} iterations",
248 iterations
249 );
250 log::warn!(" This may indicate a hardware issue or incorrect PIT configuration");
251 unsafe {
253 apic::write_reg(apic::REG_TIMER_INIT, 0);
254 }
255 super::restore_flags(saved_flags);
256 return 0;
257 }
258 }
259 let tsc_delta = super::rdtsc().wrapping_sub(tsc_start);
260
261 let current = unsafe { apic::read_reg(apic::REG_TIMER_CURRENT) };
264 let elapsed = 0xFFFF_FFFFu32.wrapping_sub(current);
265
266 unsafe {
269 apic::write_reg(apic::REG_LVT_TIMER, apic::LVT_TIMER_MASKED);
270 apic::write_reg(apic::REG_TIMER_INIT, 0);
271 }
272
273 log::info!("PIT poll completed after {} iterations", iterations);
277 log::info!("APIC timer current count: 0x{:08X}", current);
278 log::info!("APIC timer elapsed ticks: {} (0x{:08X})", elapsed, elapsed);
279
280 if elapsed == 0 {
282 log::error!("APIC timer calibration: ZERO ticks measured!");
283 log::error!(" This indicates a serious problem with the APIC timer");
284 super::restore_flags(saved_flags);
285 return 0;
286 }
287
288 const MIN_EXPECTED_TICKS: u32 = 1_000; const MAX_EXPECTED_TICKS: u32 = 5_000_000; if elapsed < MIN_EXPECTED_TICKS {
297 log::warn!(
298 "APIC calibration SUSPICIOUS: {} ticks/10ms is TOO LOW",
299 elapsed
300 );
301 log::warn!(
302 " Expected range: {} - {} ticks/10ms",
303 MIN_EXPECTED_TICKS,
304 MAX_EXPECTED_TICKS
305 );
306 log::warn!(" Possible causes:");
307 log::warn!(" - APIC divide configured incorrectly");
308 log::warn!(" - PIT frequency mismatch");
309 log::warn!(" - hardware issue");
310 log::warn!(" Forcing fallback to PIT timer");
311 super::restore_flags(saved_flags);
312 return 0;
313 }
314
315 if elapsed > MAX_EXPECTED_TICKS {
316 log::warn!(
317 "APIC calibration SUSPICIOUS: {} ticks/10ms is TOO HIGH",
318 elapsed
319 );
320 log::warn!(
321 " Expected range: {} - {} ticks/10ms",
322 MIN_EXPECTED_TICKS,
323 MAX_EXPECTED_TICKS
324 );
325 log::warn!(" Possible causes:");
326 log::warn!(" - PIT poll completed too early");
327 log::warn!(" - APIC timer running at wrong frequency");
328 log::warn!(" - hardware issue");
329 log::warn!(" Forcing fallback to PIT timer");
330 super::restore_flags(saved_flags);
331 return 0;
332 }
333
334 let estimated_cpu_freq_mhz = (elapsed as u64) * 16 * 100 / 1_000_000;
337 log::info!(
338 "Estimated CPU frequency: {} MHz (based on APIC ticks)",
339 estimated_cpu_freq_mhz
340 );
341 super::boot_timestamp::calibrate(PIT_WINDOW_NS, tsc_delta);
342 log::info!(
343 "Measured TSC frequency: {} KHz (window={} ns, delta={})",
344 super::boot_timestamp::tsc_khz(),
345 PIT_WINDOW_NS,
346 tsc_delta
347 );
348
349 APIC_TICKS_PER_10MS.store(elapsed, Ordering::Release);
351
352 log::info!("========================================");
353 log::info!("APIC TIMER CALIBRATION COMPLETE");
354 log::info!(" Ticks per 10ms: {}", elapsed);
355 log::info!(" Expected frequency: ~100Hz");
356 log::info!(" Estimated CPU: {} MHz", estimated_cpu_freq_mhz);
357 log::info!("========================================");
358
359 super::restore_flags(saved_flags);
360 elapsed
361}
362
363pub fn start_apic_timer(ticks_per_10ms: u32) {
368 use super::apic;
369
370 log::info!("========================================");
371 log::info!("APIC TIMER START");
372 log::info!("========================================");
373
374 if ticks_per_10ms == 0 {
375 log::warn!("APIC timer: cannot start with 0 ticks");
376 return;
377 }
378
379 log::info!("Ticks per 10ms: {}", ticks_per_10ms);
380 log::info!("Target frequency: 100Hz (10ms interval)");
381
382 super::idt::register_lapic_timer_vector(apic::LVT_TIMER_VECTOR);
384
385 unsafe {
387 let divide_val = apic::read_reg(apic::REG_TIMER_DIVIDE);
389 log::info!("APIC timer divide register before: 0x{:08X}", divide_val);
390 apic::write_reg(apic::REG_TIMER_DIVIDE, 0x03);
391 let divide_val_after = apic::read_reg(apic::REG_TIMER_DIVIDE);
392 log::info!(
393 "APIC timer divide register after: 0x{:08X}",
394 divide_val_after
395 );
396
397 let lvt_before = apic::read_reg(apic::REG_LVT_TIMER);
399 log::info!("LVT Timer register before: 0x{:08X}", lvt_before);
400
401 let lvt_config = apic::LVT_TIMER_PERIODIC | (apic::LVT_TIMER_VECTOR as u32);
402 log::info!(
403 "LVT Timer config: 0x{:08X} (periodic + vector {:#x})",
404 lvt_config,
405 apic::LVT_TIMER_VECTOR
406 );
407 apic::write_reg(apic::REG_LVT_TIMER, lvt_config);
408
409 let lvt_after = apic::read_reg(apic::REG_LVT_TIMER);
410 log::info!("LVT Timer register after: 0x{:08X}", lvt_after);
411
412 stop_pit();
413
414 log::info!(
416 "Setting timer initial count to: {} (0x{:08X})",
417 ticks_per_10ms,
418 ticks_per_10ms
419 );
420 apic::write_reg(apic::REG_TIMER_INIT, ticks_per_10ms);
421
422 let init_verify = apic::read_reg(apic::REG_TIMER_INIT);
423 log::info!(
424 "Timer initial count verified: {} (0x{:08X})",
425 init_verify,
426 init_verify
427 );
428 }
429
430 APIC_TIMER_ACTIVE.store(true, Ordering::Relaxed);
431
432 log::info!(
433 "APIC timer: started periodic mode, vector={:#x}, count={} ({}Hz)",
434 apic::LVT_TIMER_VECTOR,
435 ticks_per_10ms,
436 TIMER_HZ,
437 );
438 log::info!("========================================");
439}
440
441pub fn apic_ticks_per_10ms() -> u32 {
443 APIC_TICKS_PER_10MS.load(Ordering::Acquire)
444}
445
446pub fn start_apic_timer_cached() {
451 let ticks = apic_ticks_per_10ms();
452 if ticks == 0 {
453 log::warn!("APIC timer: cached ticks=0, falling back to PIT");
454 init_pit(TIMER_HZ as u32);
455 return;
456 }
457 start_apic_timer(ticks);
458}