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
135 log::info!("========================================");
139 log::info!("APIC TIMER CALIBRATION (verbose debug)");
140 log::info!("========================================");
141
142 const PIT_10MS_COUNT: u16 = 11932;
144 const MAX_POLL_ITERATIONS: u32 = 10_000_000;
146
147 log::info!("PIT frequency: {} Hz", PIT_FREQUENCY);
148 log::info!("PIT 10ms count: {}", PIT_10MS_COUNT);
149 log::info!("Target wait time: ~10ms");
150
151 unsafe {
156 apic::write_reg(apic::REG_LVT_TIMER, apic::LVT_TIMER_MASKED);
157 apic::write_reg(apic::REG_TIMER_DIVIDE, 0x03);
158 apic::write_reg(apic::REG_TIMER_INIT, 0);
159 }
160 log::info!("APIC timer divide set to 16 (0x03)");
161
162 unsafe {
182 let val = inb(0x61);
183 log::info!("Port 0x61 initial value: 0x{:02X}", val);
184 outb(0x61, val & 0xFC); }
186 log::info!("PIT channel 2 gate DISABLED for setup");
187
188 unsafe {
193 outb(0x43, 0xB0);
194 outb(0x42, (PIT_10MS_COUNT & 0xFF) as u8); outb(0x42, ((PIT_10MS_COUNT >> 8) & 0xFF) as u8); }
197 log::info!(
198 "PIT channel 2 programmed: mode 0 (one-shot), count={}",
199 PIT_10MS_COUNT
200 );
201 log::info!(" Low byte: 0x{:02X}", (PIT_10MS_COUNT & 0xFF) as u8);
202 log::info!(
203 " High byte: 0x{:02X}",
204 ((PIT_10MS_COUNT >> 8) & 0xFF) as u8
205 );
206
207 unsafe {
213 apic::write_reg(apic::REG_TIMER_INIT, 0xFFFF_FFFF);
214 }
215
216 unsafe {
220 let val = inb(0x61);
221 outb(0x61, (val | 0x01) & 0xFD); }
223
224 let mut iterations: u32 = 0;
227 loop {
228 let status = unsafe { inb(0x61) };
230 if status & 0x20 != 0 {
231 break; }
233 iterations += 1;
234 if iterations >= MAX_POLL_ITERATIONS {
235 log::warn!(
236 "APIC timer calibration: PIT poll timeout after {} iterations",
237 iterations
238 );
239 log::warn!(" This may indicate a hardware issue or incorrect PIT configuration");
240 unsafe {
242 apic::write_reg(apic::REG_TIMER_INIT, 0);
243 }
244 return 0;
245 }
246 }
247
248 let current = unsafe { apic::read_reg(apic::REG_TIMER_CURRENT) };
251 let elapsed = 0xFFFF_FFFFu32.wrapping_sub(current);
252
253 unsafe {
256 apic::write_reg(apic::REG_LVT_TIMER, apic::LVT_TIMER_MASKED);
257 apic::write_reg(apic::REG_TIMER_INIT, 0);
258 }
259
260 log::info!("PIT poll completed after {} iterations", iterations);
264 log::info!("APIC timer current count: 0x{:08X}", current);
265 log::info!("APIC timer elapsed ticks: {} (0x{:08X})", elapsed, elapsed);
266
267 if elapsed == 0 {
269 log::error!("APIC timer calibration: ZERO ticks measured!");
270 log::error!(" This indicates a serious problem with the APIC timer");
271 return 0;
272 }
273
274 const MIN_EXPECTED_TICKS: u32 = 1_000; const MAX_EXPECTED_TICKS: u32 = 5_000_000; if elapsed < MIN_EXPECTED_TICKS {
283 log::warn!(
284 "APIC calibration SUSPICIOUS: {} ticks/10ms is TOO LOW",
285 elapsed
286 );
287 log::warn!(
288 " Expected range: {} - {} ticks/10ms",
289 MIN_EXPECTED_TICKS,
290 MAX_EXPECTED_TICKS
291 );
292 log::warn!(" Possible causes:");
293 log::warn!(" - APIC divide configured incorrectly");
294 log::warn!(" - PIT frequency mismatch");
295 log::warn!(" - hardware issue");
296 log::warn!(" Forcing fallback to PIT timer");
297 return 0;
298 }
299
300 if elapsed > MAX_EXPECTED_TICKS {
301 log::warn!(
302 "APIC calibration SUSPICIOUS: {} ticks/10ms is TOO HIGH",
303 elapsed
304 );
305 log::warn!(
306 " Expected range: {} - {} ticks/10ms",
307 MIN_EXPECTED_TICKS,
308 MAX_EXPECTED_TICKS
309 );
310 log::warn!(" Possible causes:");
311 log::warn!(" - PIT poll completed too early");
312 log::warn!(" - APIC timer running at wrong frequency");
313 log::warn!(" - hardware issue");
314 log::warn!(" Forcing fallback to PIT timer");
315 return 0;
316 }
317
318 let estimated_cpu_freq_mhz = (elapsed as u64) * 16 * 100 / 1_000_000;
321 log::info!(
322 "Estimated CPU frequency: {} MHz (based on APIC ticks)",
323 estimated_cpu_freq_mhz
324 );
325
326 APIC_TICKS_PER_10MS.store(elapsed, Ordering::Release);
328
329 log::info!("========================================");
330 log::info!("APIC TIMER CALIBRATION COMPLETE");
331 log::info!(" Ticks per 10ms: {}", elapsed);
332 log::info!(" Expected frequency: ~100Hz");
333 log::info!(" Estimated CPU: {} MHz", estimated_cpu_freq_mhz);
334 log::info!("========================================");
335
336 elapsed
337}
338
339pub fn start_apic_timer(ticks_per_10ms: u32) {
344 use super::apic;
345
346 log::info!("========================================");
347 log::info!("APIC TIMER START");
348 log::info!("========================================");
349
350 if ticks_per_10ms == 0 {
351 log::warn!("APIC timer: cannot start with 0 ticks");
352 return;
353 }
354
355 log::info!("Ticks per 10ms: {}", ticks_per_10ms);
356 log::info!("Target frequency: 100Hz (10ms interval)");
357
358 super::idt::register_lapic_timer_vector(apic::LVT_TIMER_VECTOR);
360
361 unsafe {
363 let divide_val = apic::read_reg(apic::REG_TIMER_DIVIDE);
365 log::info!("APIC timer divide register before: 0x{:08X}", divide_val);
366 apic::write_reg(apic::REG_TIMER_DIVIDE, 0x03);
367 let divide_val_after = apic::read_reg(apic::REG_TIMER_DIVIDE);
368 log::info!(
369 "APIC timer divide register after: 0x{:08X}",
370 divide_val_after
371 );
372
373 let lvt_before = apic::read_reg(apic::REG_LVT_TIMER);
375 log::info!("LVT Timer register before: 0x{:08X}", lvt_before);
376
377 let lvt_config = apic::LVT_TIMER_PERIODIC | (apic::LVT_TIMER_VECTOR as u32);
378 log::info!(
379 "LVT Timer config: 0x{:08X} (periodic + vector {:#x})",
380 lvt_config,
381 apic::LVT_TIMER_VECTOR
382 );
383 apic::write_reg(apic::REG_LVT_TIMER, lvt_config);
384
385 let lvt_after = apic::read_reg(apic::REG_LVT_TIMER);
386 log::info!("LVT Timer register after: 0x{:08X}", lvt_after);
387
388 stop_pit();
389
390 log::info!(
392 "Setting timer initial count to: {} (0x{:08X})",
393 ticks_per_10ms,
394 ticks_per_10ms
395 );
396 apic::write_reg(apic::REG_TIMER_INIT, ticks_per_10ms);
397
398 let init_verify = apic::read_reg(apic::REG_TIMER_INIT);
399 log::info!(
400 "Timer initial count verified: {} (0x{:08X})",
401 init_verify,
402 init_verify
403 );
404 }
405
406 APIC_TIMER_ACTIVE.store(true, Ordering::Relaxed);
407
408 log::info!(
409 "APIC timer: started periodic mode, vector={:#x}, count={} ({}Hz)",
410 apic::LVT_TIMER_VECTOR,
411 ticks_per_10ms,
412 TIMER_HZ,
413 );
414 log::info!("========================================");
415}
416
417pub fn apic_ticks_per_10ms() -> u32 {
419 APIC_TICKS_PER_10MS.load(Ordering::Acquire)
420}
421
422pub fn start_apic_timer_cached() {
424 let ticks = apic_ticks_per_10ms();
425 start_apic_timer(ticks);
426}