feat: Initialize APIC Timer

This commit is contained in:
ParrotXray 2025-10-17 11:50:09 +08:00
parent 53475435d9
commit bb9a89d0b9
7 changed files with 382 additions and 114 deletions

View File

@ -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);
}
}

View File

@ -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();
}
}
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();
}

View File

@ -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<Option<ApicTimer>> = 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);
}

View File

@ -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<u32> {
}
}
/// Get the Local APIC base virtual address
pub fn get_base_vaddr() -> Option<VirtAddr> {
LOCAL_APIC.lock().as_ref().map(|apic| apic.base_vaddr())
}
/// 公開的 APIC 寄存器讀取 API
///
/// # Safety
/// 調用者必須確保 APIC 已正確初始化
pub unsafe fn read_apic_reg(reg: ApicRegister) -> Option<u32> {
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<u32> {
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() {

View File

@ -3,4 +3,5 @@ pub mod cpu;
pub mod acpi;
pub mod rtc;
pub mod lapic;
pub mod ioapic;
pub mod ioapic;
pub mod apic_timer;

View File

@ -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");
}

View File

@ -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!();
}
}