feat: Initialize APIC Timer
This commit is contained in:
parent
53475435d9
commit
bb9a89d0b9
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -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();
|
||||
}
|
||||
|
||||
|
||||
240
kernel/src/hal/apic_timer.rs
Normal file
240
kernel/src/hal/apic_timer.rs
Normal 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);
|
||||
}
|
||||
@ -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() {
|
||||
|
||||
@ -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;
|
||||
@ -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");
|
||||
}
|
||||
|
||||
|
||||
@ -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!();
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user