diff --git a/kernel/src/arch/amd64/idt.rs b/kernel/src/arch/amd64/idt.rs index 736a710..85f0d86 100644 --- a/kernel/src/arch/amd64/idt.rs +++ b/kernel/src/arch/amd64/idt.rs @@ -35,10 +35,8 @@ lazy_static! { idt.simd_floating_point.set_handler_fn(simd_floating_point_handler); idt.virtualization.set_handler_fn(virtualization_handler); - - // 硬件中斷 (32-255) // IRQ 0 (32) - idt[32].set_handler_fn(default_irq_handler); + idt[32].set_handler_fn(apic_timer_handler); // IRQ 1 (33) - Keyboard idt[33].set_handler_fn(keyboard_interrupt_handler); // IRQ 1 Keyboard @@ -46,7 +44,7 @@ lazy_static! { idt[40].set_handler_fn(rtc_interrupt_handler); // IRQ 8 for i in 34..=47 { - if i != 40 { // 跳過 RTC + if i != 40 && i != 32 { idt[i].set_handler_fn(default_irq_handler); } } diff --git a/kernel/src/arch/amd64/isr.rs b/kernel/src/arch/amd64/isr.rs index a4fb842..f7166a2 100644 --- a/kernel/src/arch/amd64/isr.rs +++ b/kernel/src/arch/amd64/isr.rs @@ -1,9 +1,10 @@ +use x86_64::instructions::port::Port; // kernel/src/kernel/asm/amd64/isr use x86_64::structures::idt::{InterruptStackFrame, PageFaultErrorCode}; use x86_64::VirtAddr; use crate::{drivers, kprintln}; use crate::{log_trace, log_debug, log_info, log_warn, log_error, log_fatal}; -use crate::hal::{cpu, lapic, rtc}; +use crate::hal::{apic_timer, cpu, lapic, rtc}; use crate::mm::paging; /// Divide Error (#DE) @@ -247,7 +248,6 @@ pub extern "x86-interrupt" fn virtualization_handler(stack_frame: InterruptStack // TODO Timer interrupt, Keyboard interrupt pub extern "x86-interrupt" fn keyboard_interrupt_handler(stack_frame: InterruptStackFrame) { - use x86_64::instructions::port::Port; unsafe { let mut port = Port::new(0x60); @@ -265,9 +265,26 @@ pub extern "x86-interrupt" fn default_irq_handler(stack_frame: InterruptStackFra } -pub extern "x86-interrupt" fn rtc_interrupt_handler(_stack_frame: InterruptStackFrame) { - // 必須讀取 Register C 來清除 RTC 中斷標誌 - rtc::handle_interrupt(); - // 發送 EOI +pub extern "x86-interrupt" fn apic_timer_handler(_stack_frame: InterruptStackFrame) { + + // log_info!("Processing of APIC Timer Calibration Phase"); + if apic_timer::is_calibrating() { + apic_timer::apic_calibration_handler(); + } else { + apic_timer::timer_tick_handler(); + } + lapic::send_eoi(); -} \ No newline at end of file +} + +pub extern "x86-interrupt" fn rtc_interrupt_handler(_stack_frame: InterruptStackFrame) { + rtc::handle_interrupt(); + + // log_info!("Processing of APIC Timer Calibration Phase"); + if apic_timer::is_calibrating() { + apic_timer::rtc_calibration_handler(); + } + + lapic::send_eoi(); +} + diff --git a/kernel/src/hal/apic_timer.rs b/kernel/src/hal/apic_timer.rs new file mode 100644 index 0000000..eb2639c --- /dev/null +++ b/kernel/src/hal/apic_timer.rs @@ -0,0 +1,240 @@ +// kernel/src/hal/apic_timer.rs - 使用 lapic 公開 API 的簡化版 + +use crate::hal::{lapic, rtc, cpu, ioapic}; +use core::sync::atomic::{AtomicU64, AtomicBool, Ordering}; +use spin::Mutex; +use crate::{log_info, log_debug, log_warn, log_error}; + +const APIC_CALIBRATION_CONST: u32 = 0x100000; +const RTC_BASE_FREQUENCY: u32 = 1024; + +// APIC Timer 寄存器偏移 +const APIC_LVT_TIMER: u32 = 0x320; +const APIC_TIMER_ICR: u32 = 0x380; +const APIC_TIMER_DCR: u32 = 0x3E0; + +/// APIC Timer 分頻器 +#[repr(u32)] +pub enum ApicTimerDivider { + Div64 = 0b1001, +} + +/// APIC Timer 上下文 +pub struct ApicTimer { + base_frequency: u32, + running_frequency: u32, + tick_interval: u32, +} + +// 全局狀態 +static APIC_TIMER: Mutex> = Mutex::new(None); +static RTC_COUNTER: AtomicU64 = AtomicU64::new(0); +static CALIBRATION_DONE: AtomicBool = AtomicBool::new(false); +static CALIBRATED_FREQUENCY: AtomicU64 = AtomicU64::new(0); +static IS_CALIBRATING: AtomicBool = AtomicBool::new(false); +static TICK_COUNTER: AtomicU64 = AtomicU64::new(0); + +impl ApicTimer { + fn new(base_frequency: u32, target_frequency: u32) -> Self { + let tick_interval = base_frequency / target_frequency; + + Self { + base_frequency, + running_frequency: target_frequency, + tick_interval, + } + } +} + +/// 檢查是否正在校準 +#[inline] +pub fn is_calibrating() -> bool { + IS_CALIBRATING.load(Ordering::Relaxed) +} + +/// 初始化並校準 APIC Timer +/// +/// # Parameters +/// - `target_frequency`: 目標頻率 (Hz),建議 100-1000 +/// - `apic_id`: 當前 CPU 的 APIC ID +/// +/// # Returns +/// 是否成功初始化 +pub fn init(target_frequency: u32, apic_id: u8) -> bool { + log_info!("=== APIC Timer Initialization ==="); + + // 檢查 LAPIC 是否已初始化 + if lapic::get_base_vaddr().is_none() { + log_error!("LAPIC not initialized!"); + return false; + } + + // 重置校準狀態 + IS_CALIBRATING.store(true, Ordering::SeqCst); + RTC_COUNTER.store(0, Ordering::SeqCst); + CALIBRATION_DONE.store(false, Ordering::SeqCst); + CALIBRATED_FREQUENCY.store(0, Ordering::SeqCst); + + // 禁用中斷 + cpu::cpu_disable_interrupts(); + + log_debug!("Setting up APIC Timer for calibration..."); + + unsafe { + // 配置 LVT Timer: one-shot 模式, vector 32, masked + lapic::write_apic_reg_raw(APIC_LVT_TIMER, 32 | (1 << 16)); + + // 設置分頻器為 64 + lapic::write_apic_reg_raw(APIC_TIMER_DCR, ApicTimerDivider::Div64 as u32); + } + + log_debug!("Configuring interrupts..."); + + // 配置 RTC 中斷(IRQ 8 -> Vector 40) + ioapic::set_irq_redirect( + 8, // IRQ 8 (RTC) + 40, // Vector 40 + apic_id, + false, // Edge triggered + false // Active high + ); + ioapic::unmask_irq(8); + + log_info!("Starting calibration..."); + + // 啟動 RTC + rtc::reset_tick_count(); + rtc::enable_timer(); + + // 延遲確保 RTC 啟動 + for _ in 0..1000 { + cpu::cpu_pause(); + } + + unsafe { + // Unmask APIC Timer + lapic::write_apic_reg_raw(APIC_LVT_TIMER, 32); + + // 寫入初始計數值,開始倒數 + lapic::write_apic_reg_raw(APIC_TIMER_ICR, APIC_CALIBRATION_CONST); + } + + log_debug!("Waiting for calibration..."); + + // 啟用中斷 + cpu::cpu_enable_interrupts(); + + // 等待校準完成(最多 3 秒) + let mut timeout = 3_000_000; + while !CALIBRATION_DONE.load(Ordering::SeqCst) && timeout > 0 { + cpu::cpu_pause(); + timeout -= 1; + } + + cpu::cpu_disable_interrupts(); + + // 檢查超時 + if timeout == 0 { + log_error!("Calibration timeout!"); + IS_CALIBRATING.store(false, Ordering::SeqCst); + return false; + } + + let base_frequency = CALIBRATED_FREQUENCY.load(Ordering::SeqCst) as u32; + let rtc_ticks = RTC_COUNTER.load(Ordering::SeqCst); + + if base_frequency == 0 { + log_error!("Calibration failed (freq = 0)!"); + IS_CALIBRATING.store(false, Ordering::SeqCst); + return false; + } + + log_info!("Calibration complete!"); + log_info!(" RTC ticks: {}", rtc_ticks); + log_info!(" Base frequency: {} Hz", base_frequency); + log_info!(" Bus speed: ~{} MHz", base_frequency * 64 / 1_000_000); + + // 創建 timer + let timer = ApicTimer::new(base_frequency, target_frequency); + + log_info!("Configuring periodic timer..."); + log_info!(" Target: {} Hz", target_frequency); + log_info!(" Interval: {}", timer.tick_interval); + + unsafe { + // 配置為週期模式: periodic bit | vector 32 + lapic::write_apic_reg_raw(APIC_LVT_TIMER, (1 << 17) | 32); + + // 設置計數值 + lapic::write_apic_reg_raw(APIC_TIMER_ICR, timer.tick_interval); + } + + // 先設置為非校準模式,再存儲 timer + IS_CALIBRATING.store(false, Ordering::SeqCst); + + // 確保所有寫入完成 + core::sync::atomic::fence(Ordering::SeqCst); + + *APIC_TIMER.lock() = Some(timer); + + log_info!("APIC Timer ready at {} Hz", target_frequency); + + log_info!("APIC Timer started successfully!"); + + true +} + +/// RTC 中斷處理(校準階段) +#[inline] +pub fn rtc_calibration_handler() { + RTC_COUNTER.fetch_add(1, Ordering::Relaxed); +} + +/// APIC Timer 中斷處理(校準階段) +pub fn apic_calibration_handler() { + let rtc_ticks = RTC_COUNTER.load(Ordering::Relaxed); + + if rtc_ticks == 0 { + log_warn!("APIC Timer fired but RTC = 0!"); + CALIBRATION_DONE.store(true, Ordering::SeqCst); + return; + } + + // 計算頻率: base_freq = (CONST / ticks) * RTC_FREQ + let base_frequency = ((APIC_CALIBRATION_CONST as u64) * (RTC_BASE_FREQUENCY as u64)) + / rtc_ticks; + + log_debug!("Calibration: {} ticks -> {} Hz", rtc_ticks, base_frequency); + + CALIBRATED_FREQUENCY.store(base_frequency, Ordering::SeqCst); + CALIBRATION_DONE.store(true, Ordering::SeqCst); + + // 停止 RTC + rtc::disable_timer(); +} + +/// APIC Timer 週期 tick 處理 +pub fn timer_tick_handler() { + let ticks = TICK_COUNTER.fetch_add(1, Ordering::Relaxed); +} + +/// 獲取 timer 信息 +pub fn get_info() -> Option<(u32, u32, u64)> { + APIC_TIMER.lock().as_ref().map(|t| { + ( + t.base_frequency, + t.running_frequency, + TICK_COUNTER.load(Ordering::Relaxed) + ) + }) +} + +/// 獲取總 tick 數 +pub fn get_tick_count() -> u64 { + TICK_COUNTER.load(Ordering::Relaxed) +} + +/// 重置 tick 計數器 +pub fn reset_tick_count() { + TICK_COUNTER.store(0, Ordering::SeqCst); +} \ No newline at end of file diff --git a/kernel/src/hal/lapic.rs b/kernel/src/hal/lapic.rs index f82199f..4f4b360 100644 --- a/kernel/src/hal/lapic.rs +++ b/kernel/src/hal/lapic.rs @@ -1,4 +1,5 @@ -// kernel/src/hal/lapic.rs +// kernel/src/hal/lapic.rs - 添加公開 API + use x86_64::{PhysAddr, VirtAddr}; use spin::Mutex; use crate::{log_trace, log_debug, log_info, log_warn, log_error}; @@ -8,7 +9,7 @@ use crate::mm::vma; #[repr(u32)] #[derive(Debug, Clone, Copy)] #[allow(dead_code)] -enum ApicRegister { +pub enum ApicRegister { Id = 0x20, Version = 0x30, TaskPriority = 0x80, @@ -31,13 +32,14 @@ enum ApicRegister { /// APIC configuration flags #[allow(dead_code)] -mod flags { +pub mod flags { pub const APIC_ENABLE: u32 = 0x100; pub const APIC_SW_ENABLE: u32 = 0x100; pub const APIC_SPURIOUS_ALL: u32 = 0xFF; pub const LVT_MASKED: u32 = 1 << 16; pub const LVT_TIMER_PERIODIC: u32 = 1 << 17; + pub const LVT_TIMER_ONESHOT: u32 = 0 << 17; } pub struct LocalApic { @@ -58,21 +60,26 @@ impl LocalApic { } /// Read APIC registers - unsafe fn read(&self, reg: ApicRegister) -> u32 { + pub unsafe fn read(&self, reg: ApicRegister) -> u32 { let addr = self.base_vaddr.as_u64() + reg as u64; core::ptr::read_volatile(addr as *const u32) } /// Write to APIC register - unsafe fn write(&mut self, reg: ApicRegister, value: u32) { + pub unsafe fn write(&mut self, reg: ApicRegister, value: u32) { let addr = self.base_vaddr.as_u64() + reg as u64; core::ptr::write_volatile(addr as *mut u32, value); } + /// Get base virtual address + pub fn base_vaddr(&self) -> VirtAddr { + self.base_vaddr + } + /// Initialize Local APIC pub unsafe fn init(&mut self) { // Enable APIC (via Spurious Interrupt Vector Register) - let spurious = flags::APIC_SW_ENABLE | 0xFF; // IRQ 0xFF 作为 spurious vector + let spurious = flags::APIC_SW_ENABLE | 0xFF; self.write(ApicRegister::SpuriousInterruptVector, spurious); // Set task priority to 0 (accept all interrupts) @@ -162,6 +169,57 @@ pub fn get_apic_id() -> Option { } } +/// Get the Local APIC base virtual address +pub fn get_base_vaddr() -> Option { + LOCAL_APIC.lock().as_ref().map(|apic| apic.base_vaddr()) +} + +/// 公開的 APIC 寄存器讀取 API +/// +/// # Safety +/// 調用者必須確保 APIC 已正確初始化 +pub unsafe fn read_apic_reg(reg: ApicRegister) -> Option { + LOCAL_APIC.lock().as_ref().map(|apic| apic.read(reg)) +} + +/// 公開的 APIC 寄存器寫入 API +/// +/// # Safety +/// 調用者必須確保 APIC 已正確初始化 +pub unsafe fn write_apic_reg(reg: ApicRegister, value: u32) -> bool { + if let Some(apic) = LOCAL_APIC.lock().as_mut() { + apic.write(reg, value); + true + } else { + false + } +} + +/// 直接通過偏移量讀取 APIC 寄存器(用於 apic_timer) +/// +/// # Safety +/// 調用者必須確保 APIC 已正確初始化且偏移量有效 +pub unsafe fn read_apic_reg_raw(offset: u32) -> Option { + LOCAL_APIC.lock().as_ref().map(|apic| { + let addr = apic.base_vaddr.as_u64() + offset as u64; + core::ptr::read_volatile(addr as *const u32) + }) +} + +/// 直接通過偏移量寫入 APIC 寄存器(用於 apic_timer) +/// +/// # Safety +/// 調用者必須確保 APIC 已正確初始化且偏移量有效 +pub unsafe fn write_apic_reg_raw(offset: u32, value: u32) -> bool { + if let Some(apic) = LOCAL_APIC.lock().as_ref() { + let addr = apic.base_vaddr.as_u64() + offset as u64; + core::ptr::write_volatile(addr as *mut u32, value); + true + } else { + false + } +} + /// Disable legacy 8259 PIC /// This function should be called before using the APIC to avoid conflicts. pub fn disable_legacy_pic() { diff --git a/kernel/src/hal/mod.rs b/kernel/src/hal/mod.rs index e82908d..7ece7c9 100644 --- a/kernel/src/hal/mod.rs +++ b/kernel/src/hal/mod.rs @@ -3,4 +3,5 @@ pub mod cpu; pub mod acpi; pub mod rtc; pub mod lapic; -pub mod ioapic; \ No newline at end of file +pub mod ioapic; +pub mod apic_timer; \ No newline at end of file diff --git a/kernel/src/kernel/k_init.rs b/kernel/src/kernel/k_init.rs index 0138dca..59b058d 100644 --- a/kernel/src/kernel/k_init.rs +++ b/kernel/src/kernel/k_init.rs @@ -12,7 +12,8 @@ use crate::klibc::logger::{init, LogLevel, LoggerConfig}; use crate::klibc::malloc; use crate::{log_debug, log_error, log_info, log_trace, log_warn}; use crate::drivers::keyboard; -use crate::hal::{acpi, lapic, rtc}; +use crate::hal::{acpi, apic_timer, cpu, ioapic, lapic, rtc}; +use crate::hal::cpu::cpu_enable_interrupts; fn _logger_init() { init( @@ -221,6 +222,39 @@ fn _post_init( rtc::init(); keyboard::init(); + + if let Some(apic_id) = lapic::get_apic_id() { + log_info!("Setting up APIC Timer..."); + log_info!("Current CPU APIC ID: {}", apic_id); + + if apic_timer::init(100, apic_id as u8) { + log_info!("APIC Timer initialized successfully!"); + + // 顯示信息 + if let Some((base, running, ticks)) = apic_timer::get_info() { + log_info!("Base freq: {} Hz", base); + log_info!("Running at: {} Hz", running); + log_info!("Current ticks: {}", ticks); + } + } else { + log_error!("Failed to initialize APIC Timer!"); + } + + ioapic::set_irq_redirect( + 1, // IRQ number (keyboard) + 33, // Interrupt vector number + apic_id as u8, // APIC ID of target CPU + false, // Edge triggered (false = edge, true = level) + false // Active high (false = high, true = low) + ); + + log_info!("Configuring hardware interrupts..."); + cpu_enable_interrupts(); + + } else { + log_error!("APIC not available, cannot enable keyboard"); + } + log_debug!("Cleanup completed"); } diff --git a/kernel/src/kernel/k_main.rs b/kernel/src/kernel/k_main.rs index 1486343..1391db9 100644 --- a/kernel/src/kernel/k_main.rs +++ b/kernel/src/kernel/k_main.rs @@ -1,5 +1,5 @@ // kernel/src/kernel/k_main.rs -use crate::hal::{cpu, rtc}; +use crate::hal::{apic_timer, cpu, rtc}; use crate::kprintln; use crate::{log_trace, log_debug, log_info, log_warn, log_error, log_fatal}; use crate::mm::{vma, vmm}; @@ -37,54 +37,8 @@ pub fn _kernel_main() -> ! { kprintln!(); - if let Some(apic_id) = crate::hal::lapic::get_apic_id() { - log_info!("Configuring hardware interrupts..."); - log_info!("Current CPU APIC ID: {}", apic_id); + test_apic_timer(); - - log_info!("Setting up keyboard interrupt (IRQ 1 -> Vector 33)"); - crate::hal::ioapic::set_irq_redirect( - 1, // IRQ number (keyboard) - 33, // Interrupt vector number - apic_id as u8, // APIC ID of target CPU - false, // Edge triggered (false = edge, true = level) - false // Active high (false = high, true = low) - ); - - // Unmask IRQ 1 (enable keyboard interrupt) - crate::hal::ioapic::unmask_irq(1); - log_info!("Keyboard interrupt unmasked"); - log_info!("Setting up RTC interrupt (IRQ 8 -> Vector 40)"); - crate::hal::ioapic::set_irq_redirect( - 8, // RTC is IRQ 8 - 40, // Vector 40 - apic_id as u8, - false, // Edge triggered - false // Active high - ); - - crate::hal::ioapic::unmask_irq(8); - log_info!("RTC interrupt unmasked"); - - log_info!("Enabling RTC timer interrupt (1024Hz)..."); - // Reset counter - rtc::reset_tick_count(); - rtc::enable_timer(); - - cpu::cpu_enable_interrupts(); - - log_info!("CPU interrupts enabled"); - - test_rtc_interrupt(); - - kprintln!(); - log_info!("Interrupt system ready!"); - - } else { - log_error!("APIC not available, cannot enable keyboard"); - } - - kprintln!(); log_info!("System initialization complete!"); log_warn!("Entering idle loop..."); kprintln!(); @@ -94,58 +48,24 @@ pub fn _kernel_main() -> ! { } } -fn test_rtc_interrupt() { - log_info!("=== RTC Interrupt Test ==="); +pub fn test_apic_timer() { + log_info!("=== APIC Timer Test ==="); - // Wait and check tick count - log_info!("Waiting for RTC interrupts..."); + let start_ticks = apic_timer::get_tick_count(); - let start_count = rtc::get_tick_count(); - - // Busy wait for ~1 second (approximately) - for _ in 0..1000000 { + // 等待約 1 秒 + for _ in 0..1_000_000 { cpu::cpu_pause(); } - let end_count = rtc::get_tick_count(); - let ticks = end_count - start_count; + let end_ticks = apic_timer::get_tick_count(); + let elapsed = end_ticks - start_ticks; - if ticks > 0 { - log_info!("RTC interrupt working! Received {} ticks", ticks); - log_info!("Expected: ~1024 ticks/second"); - log_info!("Actual rate: {} Hz", ticks); - } else { - log_error!("RTC interrupt NOT working! No ticks received"); + log_info!("Elapsed ticks: {}", elapsed); + + if let Some((_, freq, _)) = apic_timer::get_info() { + log_info!("Expected ~{} ticks/sec", freq); + log_info!("Actual rate: {} Hz", elapsed); } - - // Live counter display - log_info!("Live tick counter (press any key to continue):"); - - let mut last_count = rtc::get_tick_count(); - let mut seconds = 0; - - for _ in 0..5 { // Display for 5 seconds - // Wait approximately 1 second - for _ in 0..1000000 { - cpu::cpu_pause(); - } - - rtc::update_time_cache(); - - let current_count = rtc::get_tick_count(); - let delta = current_count - last_count; - last_count = current_count; - seconds += 1; - - log_info!(" [{}s] Total ticks: {}, Delta: {}, ticks: {}", - seconds, current_count, delta, delta); - // Also show current time - if let Some(time) = rtc::get_time() { - log_info!(" Time: {}", time.format()); - } - } - - log_info!("RTC test complete!"); - kprintln!(); -} \ No newline at end of file +}