feat: RTC interrupt passed

This commit is contained in:
ParrotXray 2025-10-17 10:38:24 +08:00
parent 74de8650fe
commit 53475435d9
3 changed files with 114 additions and 95 deletions

View File

@ -3,7 +3,7 @@ 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};
use crate::hal::{cpu, lapic, rtc};
use crate::mm::paging;
/// Divide Error (#DE)
@ -261,15 +261,13 @@ pub extern "x86-interrupt" fn keyboard_interrupt_handler(stack_frame: InterruptS
pub extern "x86-interrupt" fn default_irq_handler(stack_frame: InterruptStackFrame) {
lapic::send_eoi();
log_trace!("Unhandled IRQ: {:#?}", stack_frame);
log_trace!("Unhandled IRQ");
}
// kernel/src/arch/amd64/isr.rs
/// RTC 中斷處理 (IRQ 8, Vector 40)
pub extern "x86-interrupt" fn rtc_interrupt_handler(_stack_frame: InterruptStackFrame) {
// 必須讀取 Register C 來清除 RTC 中斷標誌
crate::hal::rtc::handle_interrupt();
rtc::handle_interrupt();
// 發送 EOI
crate::hal::lapic::send_eoi();
lapic::send_eoi();
}

View File

@ -1,5 +1,6 @@
// kernel/src/hal/rtc.rs
use crate::hal::io::{io_port_rb, io_port_wb};
use core::sync::atomic::{AtomicU64, Ordering};
use spin::Mutex;
use crate::log_info;
@ -96,14 +97,14 @@ impl Rtc {
}
}
/// Read CMOS registers (with NMI disabled)
unsafe fn read_register(reg: u8) -> u8 {
/// Read CMOS registers (with NMI disabled) - 公開的靜態方法
pub unsafe fn read_register(reg: u8) -> u8 {
io_port_wb(RTC_INDEX_PORT, reg | WITH_NMI_DISABLED);
io_port_rb(RTC_TARGET_PORT)
}
/// Write to CMOS register (with NMI disabled)
unsafe fn write_register(reg: u8, value: u8) {
/// Write to CMOS register (with NMI disabled) - 公開的靜態方法
pub unsafe fn write_register(reg: u8, value: u8) {
io_port_wb(RTC_INDEX_PORT, reg | WITH_NMI_DISABLED);
io_port_wb(RTC_TARGET_PORT, value);
}
@ -113,11 +114,23 @@ impl Rtc {
(Self::read_register(RTC_REG_A) & RTC_UPDATE_IN_PROGRESS) != 0
}
/// Wait for RTC update to complete
unsafe fn wait_for_update() {
while Self::is_updating() {
/// Wait for RTC update to complete (with timeout)
unsafe fn wait_for_update() -> bool {
const MAX_ATTEMPTS: u32 = 100000;
let mut attempts = 0;
while Self::is_updating() && attempts < MAX_ATTEMPTS {
core::hint::spin_loop();
attempts += 1;
}
if attempts >= MAX_ATTEMPTS {
crate::log_warn!("RTC wait_for_update timeout");
Self::read_register(RTC_REG_C); // Force clear
return false;
}
true
}
/// Convert BCD to binary
@ -125,12 +138,6 @@ impl Rtc {
(bcd & 0x0F) + ((bcd >> 4) * 10)
}
/// Convert binary to BCD
#[allow(dead_code)]
fn binary_to_bcd(bin: u8) -> u8 {
((bin / 10) << 4) | (bin % 10)
}
pub fn init(&mut self) {
unsafe {
let status_b = Self::read_register(RTC_REG_B | WITH_NMI_DISABLED);
@ -141,17 +148,16 @@ impl Rtc {
reg_a = (reg_a & 0xF0) | RTC_DIVIDER_33KHZ | RTC_FREQUENCY_1024HZ;
Self::write_register(RTC_REG_A | WITH_NMI_DISABLED, reg_a);
// ⭐ CRITICAL: Read Register C to clear any pending interrupts!
Self::read_register(RTC_REG_C);
self.disable_timer();
Self::read_register(RTC_REG_C);
}
}
/// Read raw RTC time data
unsafe fn read_raw(&self) -> (u8, u8, u8, u8, u8, u8, u8) {
Self::wait_for_update();
/// Read raw data directly (without waiting for update)
unsafe fn read_raw_no_wait(&self) -> (u8, u8, u8, u8, u8, u8, u8) {
let second = Self::read_register(RTC_REG_SEC);
let minute = Self::read_register(RTC_REG_MIN);
let hour = Self::read_register(RTC_REG_HRS);
@ -163,6 +169,12 @@ impl Rtc {
(second, minute, hour, day, month, year, weekday)
}
/// Wait for update and then read (for initialization)
unsafe fn read_raw(&self) -> (u8, u8, u8, u8, u8, u8, u8) {
Self::wait_for_update();
self.read_raw_no_wait()
}
/// Convert the value based on encoding mode
fn convert_value(&self, value: u8) -> u8 {
if self.binary_mode {
@ -172,11 +184,11 @@ impl Rtc {
}
}
/// Read the RTC time
/// Read the RTC time (safe version - no wait during interrupts)
pub fn read_time(&self) -> DateTime {
unsafe {
let (mut second, mut minute, mut hour, mut day, mut month, mut year, weekday) =
self.read_raw();
self.read_raw_no_wait();
// Convert from BCD to binary when needed
second = self.convert_value(second);
@ -207,17 +219,20 @@ impl Rtc {
}
}
/// Read multiple times and ensure consistency
/// Read time with retry (for initialization)
pub fn read_time_stable(&self) -> DateTime {
loop {
let time1 = self.read_time();
let time2 = self.read_time();
unsafe {
loop {
Self::wait_for_update();
let time1 = self.read_time();
let time2 = self.read_time();
if time1.second == time2.second
&& time1.minute == time2.minute
&& time1.hour == time2.hour
{
return time1;
if time1.second == time2.second
&& time1.minute == time2.minute
&& time1.hour == time2.hour
{
return time1;
}
}
}
}
@ -225,10 +240,23 @@ impl Rtc {
/// Enable RTC timer interrupt (1024Hz)
pub fn enable_timer(&self) {
unsafe {
// 步驟 1: 先確保關閉
self.disable_timer();
Self::read_register(RTC_REG_C);
// 步驟 2: 設置頻率
let mut reg_a = Self::read_register(RTC_REG_A | WITH_NMI_DISABLED);
reg_a = (reg_a & 0xF0) | RTC_DIVIDER_33KHZ | RTC_FREQUENCY_1024HZ;
Self::write_register(RTC_REG_A | WITH_NMI_DISABLED, reg_a);
// 步驟 3: 啟用週期性中斷
let mut reg_b = Self::read_register(RTC_REG_B | WITH_NMI_DISABLED);
reg_b |= RTC_TIMER_ON;
Self::write_register(RTC_REG_B | WITH_NMI_DISABLED, reg_b);
// 步驟 4: 清除中斷標誌
Self::read_register(RTC_REG_C);
log_info!("RTC timer enabled at {}Hz", RTC_TIMER_BASE_FREQUENCY);
}
}
@ -240,32 +268,54 @@ impl Rtc {
reg_b &= !RTC_TIMER_ON;
Self::write_register(RTC_REG_B | WITH_NMI_DISABLED, reg_b);
log_info!("RTC timer disabled");
Self::read_register(RTC_REG_C);
}
}
/// Read and clear RTC interrupt status (must be called in the interrupt handler)
pub fn read_interrupt_status(&self) -> u8 {
unsafe { Self::read_register(RTC_REG_C) }
}
}
static RTC: Mutex<Option<Rtc>> = Mutex::new(None);
static RTC_DEVICE: Mutex<Option<Rtc>> = Mutex::new(None);
static RTC_TIME_CACHE: Mutex<Option<DateTime>> = Mutex::new(None);
static RTC_TICK_COUNT: AtomicU64 = AtomicU64::new(0);
/// Initialize RTC
pub fn init() {
let mut rtc = Rtc::new();
rtc.init();
*RTC.lock() = Some(rtc);
let initial_time = rtc.read_time_stable();
*RTC_DEVICE.lock() = Some(rtc);
*RTC_TIME_CACHE.lock() = Some(initial_time);
log_info!("RTC initialized");
}
/// Get cached time (safe, no deadlock)
pub fn get_time() -> Option<DateTime> {
let rtc = RTC.lock();
let rtc = rtc.as_ref()?;
Some(rtc.read_time_stable())
RTC_TIME_CACHE.lock().clone()
}
/// Update time cache (call periodically in main loop, NOT in interrupt)
pub fn update_time_cache() {
if let Some(rtc) = RTC_DEVICE.lock().as_ref() {
let time = rtc.read_time();
*RTC_TIME_CACHE.lock() = Some(time);
}
}
/// Force read time from RTC (slow, use sparingly)
pub fn force_read_time() -> Option<DateTime> {
let rtc = RTC_DEVICE.lock();
let rtc = rtc.as_ref()?;
let time = rtc.read_time();
// Update cache
*RTC_TIME_CACHE.lock() = Some(time);
Some(time)
}
/// Print current time info
pub fn print_info() {
if let Some(time) = get_time() {
log_info!(
@ -285,64 +335,33 @@ pub fn print_info() {
/// Enable RTC timer
pub fn enable_timer() {
if let Some(rtc) = RTC.lock().as_ref() {
if let Some(rtc) = RTC_DEVICE.lock().as_ref() {
rtc.enable_timer();
}
}
/// Disable the RTC timer
pub fn disable_timer() {
if let Some(rtc) = RTC.lock().as_ref() {
if let Some(rtc) = RTC_DEVICE.lock().as_ref() {
rtc.disable_timer();
}
}
/// Handle RTC interrupt (needs to be called in IRQ 8 handler)
pub fn handle_interrupt() {
if let Some(rtc) = RTC.lock().as_ref() {
// CRITICAL: Must read Register C to clear the interrupt flag
// Otherwise the RTC will not send the next interrupt!
let status = rtc.read_interrupt_status();
// bit 6 = periodic interrupt
if (status & 0x40) != 0 {
on_periodic_interrupt();
}
// bit 5 = alarm interrupt
if (status & 0x20) != 0 {
on_alarm_interrupt();
}
}
}
/// RTC periodic interrupt callback (can be overwritten by other modules)
#[allow(dead_code)]
fn on_periodic_interrupt() {
// Handle timer events here
// e.g., update system time, schedule tasks, etc.
// For testing: increment counter
unsafe {
RTC_TICK_COUNT += 1;
}
}
/// RTC alarm interrupt callback
#[allow(dead_code)]
fn on_alarm_interrupt() {
// Handle alarm events here
}
// Test counter
static mut RTC_TICK_COUNT: u64 = 0;
/// Get RTC tick count (for testing)
/// Get RTC tick count (lock-free, safe in interrupts)
pub fn get_tick_count() -> u64 {
unsafe { RTC_TICK_COUNT }
RTC_TICK_COUNT.load(Ordering::Relaxed)
}
/// Reset tick count (for testing)
pub fn reset_tick_count() {
unsafe { RTC_TICK_COUNT = 0; }
RTC_TICK_COUNT.store(0, Ordering::Relaxed);
}
/// Handle RTC interrupt (called in IRQ 8 handler)
pub fn handle_interrupt() {
unsafe {
Rtc::read_register(RTC_REG_C);
}
RTC_TICK_COUNT.fetch_add(1, Ordering::Relaxed);
}

View File

@ -131,17 +131,19 @@ fn test_rtc_interrupt() {
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;
kprintln!(" [{}s] Total ticks: {}, Delta: {}, Rate: {} Hz",
log_info!(" [{}s] Total ticks: {}, Delta: {}, ticks: {}",
seconds, current_count, delta, delta);
// Also show current time
// if let Some(time) = rtc::get_time() {
// kprintln!(" Time: {}", time.format());
// }
if let Some(time) = rtc::get_time() {
log_info!(" Time: {}", time.format());
}
}
log_info!("RTC test complete!");