From bcf97c9e2433fb50fa9c0704fc973adc64251f6c Mon Sep 17 00:00:00 2001 From: ParrotXray Date: Mon, 13 Oct 2025 20:47:42 +0800 Subject: [PATCH 01/13] feat: Prepare for PIC/APIC initialization --- kernel/src/kernel/k_init.rs | 65 ------------------------------------- kernel/src/kernel/k_main.rs | 9 +++-- kernel/src/mm/vma.rs | 15 ++++----- kernel/src/mm/vmm.rs | 8 ++--- 4 files changed, 16 insertions(+), 81 deletions(-) diff --git a/kernel/src/kernel/k_init.rs b/kernel/src/kernel/k_init.rs index 27c956a..7060295 100644 --- a/kernel/src/kernel/k_init.rs +++ b/kernel/src/kernel/k_init.rs @@ -187,8 +187,6 @@ pub fn _kernel_init(boot_info: &'static mut BootInfo) -> ! { _post_init(); - _test_memory_management(&mut mapper, &mut frame_allocator); - kprintln!(); kprintln!("========================================"); kprintln!(" Kernel Initialization Complete! "); @@ -207,67 +205,4 @@ pub fn kernel_emergency_cleanup() { log_error!("Emergency cleanup triggered"); // 在 panic 前調用,做最後的清理工作 // 比如刷新緩衝區、保存日誌等 -} - -fn _test_memory_management( - mapper: &mut OffsetPageTable, - frame_allocator: &mut frame::BootInfoFrameAllocator -) { - kprintln!(); - log_info!("Testing Memory Management System..."); - - // Physical memory allocation - log_debug!("Test 1: Physical frame allocation"); - if let Some(frame) = pmm::allocate_frame() { - log_debug!(" Allocated frame at: {:#x}", frame.start_address().as_u64()); - pmm::deallocate_frame(frame); - log_debug!(" Deallocated frame"); - } - - // Virtual memory allocation - log_debug!("Test 2: Virtual memory allocation (kmalloc)"); - if let Some(vaddr) = malloc::kmalloc(8192, mapper, frame_allocator) { - log_debug!(" Allocated 8KB at: {:#x}", vaddr.as_u64()); - - // Test Write - unsafe { - let ptr = vaddr.as_mut_ptr::(); - *ptr = 0xDEADBEEF; - log_debug!(" Written test value: {:#x}", *ptr); - } - - malloc::kfree(vaddr, 8192, mapper, frame_allocator); - log_debug!(" Freed memory"); - } - - // Page table mapping - log_debug!("Test 3: Page table mapping"); - let test_vaddr = VirtAddr::new(0x5000_0000_0000); - let test_page = Page::containing_address(test_vaddr); - - if let Some(test_frame) = pmm::allocate_frame() { - if paging::PageTableManager::map_page( - test_page, - test_frame, - paging::kernel_data(), - mapper, - frame_allocator - ).is_ok() { - log_debug!(" Mapped page {:#x} to frame {:#x}", - test_vaddr.as_u64(), test_frame.start_address().as_u64()); - - // Testing Address Translation - if let Some(phys) = paging::PageTableManager::translate_addr(test_vaddr, mapper) { - log_debug!(" Translation check: {:#x} -> {:#x}", test_vaddr.as_u64(), phys.as_u64()); - } - - // Unmap - if paging::PageTableManager::unmap_page(test_page, mapper).is_ok() { - log_debug!(" Unmapped page"); - } - } - pmm::deallocate_frame(test_frame); - } - - log_info!("Memory tests completed!"); } \ No newline at end of file diff --git a/kernel/src/kernel/k_main.rs b/kernel/src/kernel/k_main.rs index 5ed7beb..b0f7927 100644 --- a/kernel/src/kernel/k_main.rs +++ b/kernel/src/kernel/k_main.rs @@ -17,14 +17,17 @@ pub fn _kernel_main() -> ! { ); kprintln!(); + + vma::print_info(); + vmm::get_vmm_stats().print(); + kprintln!(); + log_debug!("CR0: 0x{:016x}", cpu::cpu_r_cr0()); log_debug!("CR2: 0x{:016x}", cpu::cpu_r_cr2()); log_debug!("CR3: 0x{:016x}", cpu::cpu_r_cr3()); log_debug!("CR4: 0x{:016x}", cpu::cpu_r_cr4()); - vma::print_info(); - let vmm_stats = vmm::get_vmm_stats(); - vmm_stats.print(); + // kprintln!(); // kprintln!("=== Logger Level Demonstration ==="); diff --git a/kernel/src/mm/vma.rs b/kernel/src/mm/vma.rs index 052b34a..30d1b84 100644 --- a/kernel/src/mm/vma.rs +++ b/kernel/src/mm/vma.rs @@ -141,32 +141,31 @@ pub fn get_region_name(addr: VirtAddr) -> &'static str { /// Print hhk address space layout pub fn print_info() { - log_info!("Higher Half Kernel Memory Layout:"); - log_info!(" User Space: {:#018x} - {:#018x}", + log_info!("User Space: {:#018x} - {:#018x}", 0x0u64, 0x0000_7FFF_FFFF_FFFFu64 ); - log_info!(" Physical Map: {:#018x} - {:#018x}", + log_info!("Physical Map: {:#018x} - {:#018x}", PHYS_MEM_OFFSET, HIGHER_HALF_BASE - 1 ); - log_info!(" Kernel Base: {:#018x}", HIGHER_HALF_BASE); - log_info!(" Heap: {:#018x} - {:#018x} ({} KiB)", + log_info!("Kernel Base: {:#018x}", HIGHER_HALF_BASE); + log_info!("Heap: {:#018x} - {:#018x} ({} KiB)", HEAP_START.as_u64(), HEAP_START.as_u64() + HEAP_SIZE as u64, HEAP_SIZE / 1024 ); - log_info!(" Dynamic: {:#018x} - {:#018x} ({} MiB)", + log_info!("Dynamic: {:#018x} - {:#018x} ({} MiB)", KERNEL_DYNAMIC_START.as_u64(), KERNEL_DYNAMIC_END.as_u64(), KERNEL_DYNAMIC_SIZE / (1024 * 1024) ); - log_info!(" Kernel Stack: {:#018x} - {:#018x} ({} MiB)", + log_info!("Kernel Stack: {:#018x} - {:#018x} ({} MiB)", KERNEL_STACK_START.as_u64(), KERNEL_STACK_END.as_u64(), KERNEL_STACK_SIZE / (1024 * 1024) ); - log_info!(" Device Mapping: {:#018x} - {:#018x} ({} MiB)", + log_info!("Device Mapping: {:#018x} - {:#018x} ({} MiB)", DEVICE_MAPPING_START.as_u64(), DEVICE_MAPPING_END.as_u64(), DEVICE_MAPPING_SIZE / (1024 * 1024) diff --git a/kernel/src/mm/vmm.rs b/kernel/src/mm/vmm.rs index 08e2c45..a989990 100644 --- a/kernel/src/mm/vmm.rs +++ b/kernel/src/mm/vmm.rs @@ -21,7 +21,6 @@ struct MemoryBlock { page_count: usize, } - #[derive(Debug, Clone, Copy)] pub struct VmmStats { pub next_vaddr: VirtAddr, @@ -35,18 +34,17 @@ pub struct VmmStats { impl VmmStats { pub fn print(&self) { - log_info!("Virtual Memory Statistics:"); - log_info!(" Allocated: {} pages ({} KiB) in {} blocks", + log_info!("Allocated: {} pages ({} KiB) in {} blocks", self.allocated_pages, self.allocated_pages * 4, self.allocated_blocks_count ); - log_info!(" Free: {} pages ({} KiB) in {} blocks", + log_info!("Free: {} pages ({} KiB) in {} blocks", self.free_pages, self.free_pages * 4, self.free_blocks_count ); - log_info!(" New Usage: {} pages ({} KiB)", + log_info!("New Usage: {} pages ({} KiB)", self.used_from_new, self.used_from_new * 4 ); From b277334069be4ccd95d75065a608c45de3f6b2a9 Mon Sep 17 00:00:00 2001 From: ParrotXray Date: Mon, 13 Oct 2025 22:00:13 +0800 Subject: [PATCH 02/13] feat: RTC initialized --- kernel/src/hal/apic.rs | 0 kernel/src/hal/ioapic.rs | 0 kernel/src/hal/mod.rs | 4 +- kernel/src/hal/rtc.rs | 333 ++++++++++++++++++++++++++++++++++++ kernel/src/kernel/k_init.rs | 4 +- kernel/src/kernel/k_main.rs | 9 +- 6 files changed, 346 insertions(+), 4 deletions(-) create mode 100644 kernel/src/hal/apic.rs create mode 100644 kernel/src/hal/ioapic.rs diff --git a/kernel/src/hal/apic.rs b/kernel/src/hal/apic.rs new file mode 100644 index 0000000..e69de29 diff --git a/kernel/src/hal/ioapic.rs b/kernel/src/hal/ioapic.rs new file mode 100644 index 0000000..e69de29 diff --git a/kernel/src/hal/mod.rs b/kernel/src/hal/mod.rs index c380425..c619489 100644 --- a/kernel/src/hal/mod.rs +++ b/kernel/src/hal/mod.rs @@ -1,4 +1,6 @@ pub mod io; pub mod cpu; pub mod acpi; -mod rtc; \ No newline at end of file +pub mod rtc; +pub mod apic; +mod ioapic; \ No newline at end of file diff --git a/kernel/src/hal/rtc.rs b/kernel/src/hal/rtc.rs index e69de29..f51ef2f 100644 --- a/kernel/src/hal/rtc.rs +++ b/kernel/src/hal/rtc.rs @@ -0,0 +1,333 @@ +// kernel/src/hal/rtc.rs +use crate::hal::io::{io_port_rb, io_port_wb}; +use spin::Mutex; +use crate::log_info; + +const RTC_INDEX_PORT: u16 = 0x70; +const RTC_TARGET_PORT: u16 = 0x71; +const WITH_NMI_DISABLED: u8 = 0x80; + +const RTC_REG_SEC: u8 = 0x00; +const RTC_REG_MIN: u8 = 0x02; +const RTC_REG_HRS: u8 = 0x04; +const RTC_REG_WDY: u8 = 0x06; // Weekday +const RTC_REG_DAY: u8 = 0x07; +const RTC_REG_MTH: u8 = 0x08; +const RTC_REG_YRS: u8 = 0x09; + +const RTC_REG_A: u8 = 0x0A; +const RTC_REG_B: u8 = 0x0B; +const RTC_REG_C: u8 = 0x0C; +const RTC_REG_D: u8 = 0x0D; + +const RTC_UPDATE_IN_PROGRESS: u8 = 0x80; // Status Register A bit 7 +const RTC_BIN_ENCODED_BIT: u8 = 0x04; // Status Register B bit 2 +const RTC_24HRS_ENCODED_BIT: u8 = 0x02; // Status Register B bit 1 + +const RTC_TIMER_ON: u8 = 0x40; // Enable periodic interrupt (bit 6) +const RTC_FREQUENCY_1024HZ: u8 = 0b110; // Rate selector for 1024Hz +const RTC_DIVIDER_33KHZ: u8 = 0b010 << 4; // 32.768kHz crystal divider +const RTC_TIMER_BASE_FREQUENCY: u32 = 1024; + +const RTC_CURRENT_CENTURY: u16 = 2000; + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct DateTime { + pub year: u16, + pub month: u8, + pub day: u8, + pub weekday: u8, + pub hour: u8, + pub minute: u8, + pub second: u8, +} + +impl DateTime { + pub fn format(&self) -> alloc::string::String { + alloc::format!( + "{:04}-{:02}-{:02} {:02}:{:02}:{:02}", + self.year, self.month, self.day, + self.hour, self.minute, self.second + ) + } + + pub fn weekday_name(&self) -> &'static str { + match self.weekday { + 1 => "Sunday", + 2 => "Monday", + 3 => "Tuesday", + 4 => "Wednesday", + 5 => "Thursday", + 6 => "Friday", + 7 => "Saturday", + _ => "Unknown", + } + } + + pub fn month_name(&self) -> &'static str { + match self.month { + 1 => "January", + 2 => "February", + 3 => "March", + 4 => "April", + 5 => "May", + 6 => "June", + 7 => "July", + 8 => "August", + 9 => "September", + 10 => "October", + 11 => "November", + 12 => "December", + _ => "Unknown", + } + } +} + +pub struct Rtc { + binary_mode: bool, + hour_24_mode: bool, +} + +impl Rtc { + pub fn new() -> Self { + Self { + binary_mode: false, + hour_24_mode: false, + } + } + + /// Read CMOS registers (with NMI disabled) + 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) { + io_port_wb(RTC_INDEX_PORT, reg | WITH_NMI_DISABLED); + io_port_wb(RTC_TARGET_PORT, value); + } + + /// Check if RTC is updating + unsafe fn is_updating() -> bool { + (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() { + core::hint::spin_loop(); + } + } + + /// 將 BCD 轉換為二進制 + fn bcd_to_binary(bcd: u8) -> u8 { + (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 { + // Read status register B + let status_b = Self::read_register(RTC_REG_B); + + self.binary_mode = (status_b & RTC_BIN_ENCODED_BIT) != 0; + self.hour_24_mode = (status_b & RTC_24HRS_ENCODED_BIT) != 0; + + crate::log_debug!( + "RTC Mode: {} encoding, {} hour format", + if self.binary_mode { "Binary" } else { "BCD" }, + if self.hour_24_mode { "24" } else { "12" } + ); + } + } + + /// Read raw RTC time data + unsafe fn read_raw(&self) -> (u8, u8, u8, u8, u8, u8, u8) { + Self::wait_for_update(); + + let second = Self::read_register(RTC_REG_SEC); + let minute = Self::read_register(RTC_REG_MIN); + let hour = Self::read_register(RTC_REG_HRS); + let day = Self::read_register(RTC_REG_DAY); + let month = Self::read_register(RTC_REG_MTH); + let year = Self::read_register(RTC_REG_YRS); + let weekday = Self::read_register(RTC_REG_WDY); + + (second, minute, hour, day, month, year, weekday) + } + + /// Convert the value + fn convert_value(&self, value: u8) -> u8 { + if self.binary_mode { + value + } else { + Self::bcd_to_binary(value) + } + } + + /// Read the RTC time + pub fn read_time(&self) -> DateTime { + unsafe { + let (mut second, mut minute, mut hour, mut day, mut month, mut year, weekday) = + self.read_raw(); + + second = self.convert_value(second); + minute = self.convert_value(minute); + day = self.convert_value(day); + month = self.convert_value(month); + year = self.convert_value(year); + + let pm_bit = hour & 0x80; + hour = self.convert_value(hour & 0x7F); + + if !self.hour_24_mode && pm_bit != 0 { + hour = (hour + 12) % 24; + } + + let full_year = RTC_CURRENT_CENTURY + year as u16; + + DateTime { + year: full_year, + month, + day, + weekday, + hour, + minute, + second, + } + } + } + + /// Read multiple times and ensure consistency + pub fn read_time_stable(&self) -> DateTime { + loop { + 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; + } + } + } + + /// Enable RTC timer interrupt (1024Hz) + pub fn enable_timer(&self) { + unsafe { + // Disable NMI and set frequency + let mut reg_a = Self::read_register(RTC_REG_A); + reg_a = (reg_a & 0xF0) | RTC_DIVIDER_33KHZ | RTC_FREQUENCY_1024HZ; + Self::write_register(RTC_REG_A, reg_a); + + // Enable periodic interrupts + let mut reg_b = Self::read_register(RTC_REG_B); + reg_b |= RTC_TIMER_ON; + Self::write_register(RTC_REG_B, reg_b); + + log_info!("RTC timer enabled at {}Hz", RTC_TIMER_BASE_FREQUENCY); + } + } + + /// Disable RTC timer interrupt + pub fn disable_timer(&self) { + unsafe { + let mut reg_b = Self::read_register(RTC_REG_B); + reg_b &= !RTC_TIMER_ON; + Self::write_register(RTC_REG_B, reg_b); + + log_info!("RTC timer disabled"); + } + } + + /// 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> = Mutex::new(None); + +pub fn init() { + let mut rtc = Rtc::new(); + rtc.init(); + *RTC.lock() = Some(rtc); + + log_info!("RTC initialized"); +} + +pub fn get_time() -> Option { + let rtc = RTC.lock(); + let rtc = rtc.as_ref()?; + Some(rtc.read_time_stable()) +} + +pub fn print_info() { + if let Some(time) = get_time() { + log_info!( + "{}, {} {}, {} - {:02}:{:02}:{:02}", + time.weekday_name(), + time.month_name(), + time.day, + time.year, + time.hour, + time.minute, + time.second + ); + } else { + crate::log_warn!("RTC not initialized"); + } +} + +/// Enable RTC timer +pub fn enable_timer() { + if let Some(rtc) = RTC.lock().as_ref() { + rtc.enable_timer(); + } +} + +/// Disable the RTC timer +pub fn disable_timer() { + if let Some(rtc) = RTC.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() { + // 在這裡處理定時器事件 + // 例如: 更新系統時間、調度任務等 +} + +/// RTC alarm interrupt callback +#[allow(dead_code)] +fn on_alarm_interrupt() { + // 在這裡處理鬧鐘事件 +} diff --git a/kernel/src/kernel/k_init.rs b/kernel/src/kernel/k_init.rs index 7060295..c65f3aa 100644 --- a/kernel/src/kernel/k_init.rs +++ b/kernel/src/kernel/k_init.rs @@ -11,7 +11,7 @@ use crate::kernel::k_main; 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::hal::acpi; +use crate::hal::{acpi, rtc}; fn _logger_init() { init( @@ -158,6 +158,8 @@ fn _post_init() { kprintln!(); log_info!("Post Initialization"); // TODO: 釋放 bootloader 佔用的內存 + + rtc::init(); log_debug!("Cleanup completed"); } diff --git a/kernel/src/kernel/k_main.rs b/kernel/src/kernel/k_main.rs index b0f7927..781f09d 100644 --- a/kernel/src/kernel/k_main.rs +++ b/kernel/src/kernel/k_main.rs @@ -1,5 +1,5 @@ -// kernel/src/k_main.rs (Updated with Logger Demo) -use crate::hal::cpu; +// kernel/src/k_main.rs +use crate::hal::{cpu, rtc}; use crate::kprintln; use crate::{log_trace, log_debug, log_info, log_warn, log_error, log_fatal}; use crate::mm::{vma, vmm}; @@ -20,6 +20,11 @@ pub fn _kernel_main() -> ! { vma::print_info(); vmm::get_vmm_stats().print(); + + kprintln!(); + + rtc::print_info(); + kprintln!(); log_debug!("CR0: 0x{:016x}", cpu::cpu_r_cr0()); From 5313892f809e046e581c50ed880e30c18c30a898 Mon Sep 17 00:00:00 2001 From: ParrotXray Date: Tue, 14 Oct 2025 11:04:17 +0800 Subject: [PATCH 03/13] feat: Initialize Local APIC and IO APIC --- kernel/src/arch/amd64/idt.rs | 3 + kernel/src/arch/amd64/isr.rs | 20 ++- kernel/src/drivers/keyboard.rs | 184 ++++++++++++++++++++ kernel/src/drivers/mod.rs | 1 + kernel/src/hal/acpi.rs | 37 ++-- kernel/src/hal/apic.rs | 0 kernel/src/hal/ioapic.rs | 306 +++++++++++++++++++++++++++++++++ kernel/src/hal/lapic.rs | 190 ++++++++++++++++++++ kernel/src/hal/mod.rs | 4 +- kernel/src/kernel/k_init.rs | 88 ++++++++-- kernel/src/kernel/k_main.rs | 63 ++++--- kernel/src/klibc/print.rs | 2 +- kernel/src/main.rs | 1 + 13 files changed, 843 insertions(+), 56 deletions(-) create mode 100644 kernel/src/drivers/keyboard.rs create mode 100644 kernel/src/drivers/mod.rs delete mode 100644 kernel/src/hal/apic.rs create mode 100644 kernel/src/hal/lapic.rs diff --git a/kernel/src/arch/amd64/idt.rs b/kernel/src/arch/amd64/idt.rs index 0fe1376..502c6bf 100644 --- a/kernel/src/arch/amd64/idt.rs +++ b/kernel/src/arch/amd64/idt.rs @@ -35,6 +35,9 @@ lazy_static! { idt.simd_floating_point.set_handler_fn(simd_floating_point_handler); idt.virtualization.set_handler_fn(virtualization_handler); + // IRQ 32 start + idt[33].set_handler_fn(keyboard_interrupt_handler); // IRQ 1 Keyboard + idt }; } diff --git a/kernel/src/arch/amd64/isr.rs b/kernel/src/arch/amd64/isr.rs index aa78f70..c3d2737 100644 --- a/kernel/src/arch/amd64/isr.rs +++ b/kernel/src/arch/amd64/isr.rs @@ -3,7 +3,7 @@ use x86_64::structures::idt::{InterruptStackFrame, PageFaultErrorCode}; use x86_64::VirtAddr; use crate::kprintln; use crate::{log_trace, log_debug, log_info, log_warn, log_error, log_fatal}; -use crate::hal::cpu; +use crate::hal::{cpu, lapic}; use crate::mm::paging; /// Divide Error (#DE) @@ -224,4 +224,20 @@ pub extern "x86-interrupt" fn virtualization_handler(stack_frame: InterruptStack } } -// TODO Timer interrupt, Keyboard interrupt \ No newline at end of file +// 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); + let scancode: u8 = port.read(); + + // 传递给键盘驱动处理 + crate::drivers::keyboard::handle_scancode(scancode); + } + + // 发送 EOI + lapic::send_eoi(); +} \ No newline at end of file diff --git a/kernel/src/drivers/keyboard.rs b/kernel/src/drivers/keyboard.rs new file mode 100644 index 0000000..eb87880 --- /dev/null +++ b/kernel/src/drivers/keyboard.rs @@ -0,0 +1,184 @@ +// kernel/src/drivers/keyboard.rs +use spin::Mutex; +use crate::{kprintln, log_debug, log_info}; + +/// Keyboard scancode to ASCII mapping table (US keyboard layout) +static SCANCODE_TO_ASCII: [u8; 128] = [ + 0, 27, b'1', b'2', b'3', b'4', b'5', b'6', // 0x00-0x07 + b'7', b'8', b'9', b'0', b'-', b'=', 8, b'\t', // 0x08-0x0F (8=Backspace) + b'q', b'w', b'e', b'r', b't', b'y', b'u', b'i', // 0x10-0x17 + b'o', b'p', b'[', b']', b'\n', 0, b'a', b's', // 0x18-0x1F (Ctrl) + b'd', b'f', b'g', b'h', b'j', b'k', b'l', b';', // 0x20-0x27 + b'\'',b'`', 0, b'\\',b'z', b'x', b'c', b'v', // 0x28-0x2F (LShift) + b'b', b'n', b'm', b',', b'.', b'/', 0, b'*', // 0x30-0x37 (RShift) + 0, b' ', 0, 0, 0, 0, 0, 0, // 0x38-0x3F (Alt, CapsLock, F1-F5) + 0, 0, 0, 0, 0, 0, 0, 0, // 0x40-0x47 (F6-F10, NumLock, ScrollLock) + 0, 0, 0, 0, 0, 0, 0, 0, // 0x48-0x4F (Home, Up, PgUp, -, Left, ...) + 0, 0, 0, 0, 0, 0, 0, 0, // 0x50-0x57 + 0, 0, 0, 0, 0, 0, 0, 0, // 0x58-0x5F + 0, 0, 0, 0, 0, 0, 0, 0, // 0x60-0x67 + 0, 0, 0, 0, 0, 0, 0, 0, // 0x68-0x6F + 0, 0, 0, 0, 0, 0, 0, 0, // 0x70-0x77 + 0, 0, 0, 0, 0, 0, 0, 0, // 0x78-0x7F +]; + +/// Character mapping when Shift key is pressed +static SCANCODE_TO_ASCII_SHIFT: [u8; 128] = [ + 0, 27, b'!', b'@', b'#', b'$', b'%', b'^', // 0x00-0x07 + b'&', b'*', b'(', b')', b'_', b'+', 8, b'\t', // 0x08-0x0F + b'Q', b'W', b'E', b'R', b'T', b'Y', b'U', b'I', // 0x10-0x17 + b'O', b'P', b'{', b'}', b'\n', 0, b'A', b'S', // 0x18-0x1F + b'D', b'F', b'G', b'H', b'J', b'K', b'L', b':', // 0x20-0x27 + b'"', b'~', 0, b'|', b'Z', b'X', b'C', b'V', // 0x28-0x2F + b'B', b'N', b'M', b'<', b'>', b'?', 0, b'*', // 0x30-0x37 + 0, b' ', 0, 0, 0, 0, 0, 0, // 0x38-0x3F + 0, 0, 0, 0, 0, 0, 0, 0, // 0x40-0x47 + 0, 0, 0, 0, 0, 0, 0, 0, // 0x48-0x4F + 0, 0, 0, 0, 0, 0, 0, 0, // 0x50-0x57 + 0, 0, 0, 0, 0, 0, 0, 0, // 0x58-0x5F + 0, 0, 0, 0, 0, 0, 0, 0, // 0x60-0x67 + 0, 0, 0, 0, 0, 0, 0, 0, // 0x68-0x6F + 0, 0, 0, 0, 0, 0, 0, 0, // 0x70-0x77 + 0, 0, 0, 0, 0, 0, 0, 0, // 0x78-0x7F +]; + +/// Numpad scancode mapping +static NUMPAD_SCANCODE_TO_ASCII: [u8; 128] = { + let mut map = [0u8; 128]; + map[0x47] = b'7'; + map[0x48] = b'8'; + map[0x49] = b'9'; + map[0x4B] = b'4'; + map[0x4C] = b'5'; + map[0x4D] = b'6'; + map[0x4F] = b'1'; + map[0x50] = b'2'; + map[0x51] = b'3'; + map[0x52] = b'0'; + map[0x53] = b'.'; + map[0x4A] = b'-'; + map[0x4E] = b'+'; + map[0x37] = b'*'; + map[0x35] = b'/'; + map +}; + +/// Keyboard state +struct KeyboardState { + shift_pressed: bool, + ctrl_pressed: bool, + alt_pressed: bool, + caps_lock: bool, + num_lock: bool, +} + +impl KeyboardState { + const fn new() -> Self { + Self { + shift_pressed: false, + ctrl_pressed: false, + alt_pressed: false, + caps_lock: false, + num_lock: true, // Usually enabled by default + } + } +} + +static KEYBOARD_STATE: Mutex = Mutex::new(KeyboardState::new()); + +/// Handle keyboard scancode +pub fn handle_scancode(raw: u8) { + let mut state = KEYBOARD_STATE.lock(); + + let key_released = (raw & 0x80) != 0; + let scancode = raw & 0x7F; + + // Handle modifier keys + match scancode { + 0x2A | 0x36 => { state.shift_pressed = !key_released; return; } // Shift + 0x1D => { state.ctrl_pressed = !key_released; return; } // Ctrl + 0x38 => { state.alt_pressed = !key_released; return; } // Alt + 0x3A => { if !key_released { state.caps_lock = !state.caps_lock; } return; } // Caps Lock + 0x45 => { if !key_released { state.num_lock = !state.num_lock; } return; } // Num Lock + _ => {} + } + + if key_released { return; } + + // When NumLock is off: Numpad outputs arrow or control keys + if !state.num_lock { + match scancode { + 0x47 => { kprintln!("[Home]"); return; } + 0x48 => { kprintln!("[Up]"); return; } + 0x49 => { kprintln!("[PgUp]"); return; } + 0x4B => { kprintln!("[Left]"); return; } + 0x4C => { kprintln!("[Center]"); return; } + 0x4D => { kprintln!("[Right]"); return; } + 0x4F => { kprintln!("[End]"); return; } + 0x50 => { kprintln!("[Down]"); return; } + 0x51 => { kprintln!("[PgDn]"); return; } + 0x52 => { kprintln!("[Insert]"); return; } + 0x53 => { kprintln!("[Delete]"); return; } + _ => {} + } + } + + // Handle numpad output based on NumLock state + let ascii = if state.num_lock && NUMPAD_SCANCODE_TO_ASCII[scancode as usize] != 0 { + NUMPAD_SCANCODE_TO_ASCII[scancode as usize] + } else if state.shift_pressed { + SCANCODE_TO_ASCII_SHIFT[scancode as usize] + } else { + SCANCODE_TO_ASCII[scancode as usize] + }; + + if ascii == 0 { + return; // Unmapped key + } + + // Handle Caps Lock (affects letters only) + let ascii = if state.caps_lock && ascii.is_ascii_alphabetic() { + if state.shift_pressed { + ascii.to_ascii_lowercase() + } else { + ascii.to_ascii_uppercase() + } + } else { + ascii + }; + + // Handle Ctrl combinations + if state.ctrl_pressed { + match ascii { + b'c' | b'C' => { kprintln!("^C"); return; } + b'd' | b'D' => { kprintln!("^D"); return; } + b'l' | b'L' => { + crate::tty::tty::clear(0x000000); + return; + } + _ => {} + } + } + + // Output character + print_char(ascii); +} + +/// Print a character to the screen +fn print_char(c: u8) { + use crate::kprint; + + if c == b'\n' { + kprintln!(); + } else if c == 8 { + // TODO: Implement backspace functionality + kprint!("\x08"); + } else if c.is_ascii_graphic() || c == b' ' { + kprint!("{}", c as char); + } +} + +/// Initialize keyboard driver +pub fn init() { + log_info!("Keyboard driver initialized"); +} diff --git a/kernel/src/drivers/mod.rs b/kernel/src/drivers/mod.rs new file mode 100644 index 0000000..d731c41 --- /dev/null +++ b/kernel/src/drivers/mod.rs @@ -0,0 +1 @@ +pub mod keyboard; \ No newline at end of file diff --git a/kernel/src/hal/acpi.rs b/kernel/src/hal/acpi.rs index b79c458..01680eb 100644 --- a/kernel/src/hal/acpi.rs +++ b/kernel/src/hal/acpi.rs @@ -12,6 +12,16 @@ pub struct CureAcpiHandler { physical_memory_offset: u64, } +pub struct AcpiInfo { + pub revision: u8, + pub boot_processor: Option, + pub cpu_count: usize, + pub has_apic: bool, + pub has_hpet: bool, + pub local_apic_address: Option, + pub io_apics: alloc::vec::Vec<(u64, u8, u32)>, // (address, id, gsi_base) +} + impl CureAcpiHandler { pub const fn new(physical_memory_offset: u64) -> Self { Self { @@ -187,14 +197,6 @@ impl Handler for CureAcpiHandler { } } -pub struct AcpiInfo { - pub revision: u8, - pub boot_processor: Option, - pub cpu_count: usize, - pub has_apic: bool, - pub has_hpet: bool, -} - pub fn init(rsdp_addr: u64, physical_memory_offset: u64) -> Option { let handler = CureAcpiHandler::new(physical_memory_offset); @@ -214,7 +216,6 @@ pub fn init(rsdp_addr: u64, physical_memory_offset: u64) -> Option { } } }; - // kprintln!(" ACPI Revision: {}", tables.rsdp_revision); let platform = match AcpiPlatform::new(tables, handler) { Ok(platform) => platform, @@ -240,25 +241,33 @@ pub fn init(rsdp_addr: u64, physical_memory_offset: u64) -> Option { }; // 檢查中斷模型 - let has_apic = match &platform.interrupt_model { + let (has_apic, local_apic_addr, io_apics_info) = match &platform.interrupt_model { InterruptModel::Apic(apic) => { log_info!("Local APIC Address: {:#x}", apic.local_apic_address); log_info!("IO APICs: {} controller(s)", apic.io_apics.len()); + let mut io_apics = alloc::vec::Vec::new(); + for (i, io_apic) in apic.io_apics.iter().enumerate() { log_info!("IO APIC {}: ID={}, Address={:#x}, GSI Base={}", i, io_apic.id, io_apic.address, io_apic.global_system_interrupt_base); + + io_apics.push(( + io_apic.address as u64, + io_apic.id, + io_apic.global_system_interrupt_base, + )); } - true + (true, Some(apic.local_apic_address as u64), io_apics) } InterruptModel::Unknown => { log_warn!("Interrupt Model: Unknown (not APIC)"); - false + (false, None, alloc::vec::Vec::new()) } _ => { log_warn!("Interrupt Model: Other"); - false + (false, None, alloc::vec::Vec::new()) } }; @@ -299,6 +308,8 @@ pub fn init(rsdp_addr: u64, physical_memory_offset: u64) -> Option { cpu_count, has_apic, has_hpet, + local_apic_address: local_apic_addr, + io_apics: io_apics_info, }) } diff --git a/kernel/src/hal/apic.rs b/kernel/src/hal/apic.rs deleted file mode 100644 index e69de29..0000000 diff --git a/kernel/src/hal/ioapic.rs b/kernel/src/hal/ioapic.rs index e69de29..e679bab 100644 --- a/kernel/src/hal/ioapic.rs +++ b/kernel/src/hal/ioapic.rs @@ -0,0 +1,306 @@ +// kernel/src/hal/ioapic.rs +use x86_64::{PhysAddr, VirtAddr}; +use spin::Mutex; +use alloc::vec::Vec; +use crate::{log_trace, log_debug, log_info, log_warn, log_error}; +use crate::mm::vma; + +/// IO APIC register selector +const IOREGSEL: u32 = 0x00; +const IOWIN: u32 = 0x10; + +/// IO APIC register index +#[allow(dead_code)] +mod reg { + pub const ID: u8 = 0x00; + pub const VER: u8 = 0x01; + pub const ARB: u8 = 0x02; + pub const REDTBL_BASE: u8 = 0x10; +} + +/// Redirection Entry flag +#[allow(dead_code)] +mod redir_flags { + pub const MASKED: u64 = 1 << 16; + pub const TRIGGER_LEVEL: u64 = 1 << 15; + pub const TRIGGER_EDGE: u64 = 0; + pub const POLARITY_LOW: u64 = 1 << 13; + pub const POLARITY_HIGH: u64 = 0; + pub const DEST_LOGICAL: u64 = 1 << 11; + pub const DEST_PHYSICAL: u64 = 0; + pub const DELIVERY_FIXED: u64 = 0 << 8; + pub const DELIVERY_LOWEST: u64 = 1 << 8; +} + +pub struct IoApic { + base_vaddr: VirtAddr, + id: u8, + gsi_base: u32, + max_redirection_entries: u8, +} + +static IO_APICS: Mutex> = Mutex::new(Vec::new()); + +impl IoApic { + /// Create IO APIC from physical address + pub unsafe fn new(base_paddr: PhysAddr, id: u8, gsi_base: u32) -> Self { + let base_vaddr = vma::phys_to_virt(base_paddr.as_u64()); + + log_debug!("IO APIC {} physical base: {:#x}", id, base_paddr.as_u64()); + log_debug!("IO APIC {} virtual base: {:#x}", id, base_vaddr.as_u64()); + log_debug!("IO APIC {} GSI base: {}", id, gsi_base); + + let mut ioapic = Self { + base_vaddr, + id, + gsi_base, + max_redirection_entries: 0, + }; + + // Read version information to get the maximum number of redirect entries + let version = ioapic.read(reg::VER); + ioapic.max_redirection_entries = ((version >> 16) & 0xFF) as u8 + 1; + + ioapic + } + + /// Read IO APIC registers + unsafe fn read(&mut self, reg: u8) -> u32 { + let regsel_addr = self.base_vaddr.as_u64() + IOREGSEL as u64; + let win_addr = self.base_vaddr.as_u64() + IOWIN as u64; + + core::ptr::write_volatile(regsel_addr as *mut u32, reg as u32); + core::ptr::read_volatile(win_addr as *const u32) + } + + /// Writing to IO APIC registers + unsafe fn write(&mut self, reg: u8, value: u32) { + let regsel_addr = self.base_vaddr.as_u64() + IOREGSEL as u64; + let win_addr = self.base_vaddr.as_u64() + IOWIN as u64; + + core::ptr::write_volatile(regsel_addr as *mut u32, reg as u32); + core::ptr::write_volatile(win_addr as *mut u32, value); + } + + /// Read redirection table entries + unsafe fn read_redirection_entry(&mut self, irq: u8) -> u64 { + if irq >= self.max_redirection_entries { + log_warn!("IRQ {} out of range for IO APIC {}", irq, self.id); + return 0; + } + + let low_reg = reg::REDTBL_BASE + (irq * 2); + let high_reg = low_reg + 1; + + let low = self.read(low_reg) as u64; + let high = self.read(high_reg) as u64; + + (high << 32) | low + } + + /// Write redirection table entry + unsafe fn write_redirection_entry(&mut self, irq: u8, entry: u64) { + if irq >= self.max_redirection_entries { + log_warn!("IRQ {} out of range for IO APIC {}", irq, self.id); + return; + } + + let low_reg = reg::REDTBL_BASE + (irq * 2); + let high_reg = low_reg + 1; + + let low = entry as u32; + let high = (entry >> 32) as u32; + + self.write(high_reg, high); + self.write(low_reg, low); + } + + /// Initialize the IO APIC + pub unsafe fn init(&mut self) { + // Mask all interrupts + for irq in 0..self.max_redirection_entries { + let entry = redir_flags::MASKED; + self.write_redirection_entry(irq, entry); + } + + log_info!("IO APIC {} initialized, {} entries", self.id, self.max_redirection_entries); + } + + /// Configure IRQ redirection + /// + /// # Parameters + /// - `irq`: IRQ number (0-23) + /// - `vector`: Interrupt vector number (32-255) + /// - `dest_apic_id`: Destination Local APIC ID + /// - `level_triggered`: true = level triggered, false = edge triggered + /// - `active_low`: true = active low, false = active high + pub unsafe fn set_irq_redirect( + &mut self, + irq: u8, + vector: u8, + dest_apic_id: u8, + level_triggered: bool, + active_low: bool, + ) { + let mut entry: u64 = 0; + + // Set target APIC ID (bits 56-63) + entry |= (dest_apic_id as u64) << 56; + + // Set the trigger mode + if level_triggered { + entry |= redir_flags::TRIGGER_LEVEL; + } + + // Setting Polarity + if active_low { + entry |= redir_flags::POLARITY_LOW; + } + + // Set the delivery mode to Fixed + entry |= redir_flags::DELIVERY_FIXED; + + // Set the target mode to Physical + entry |= redir_flags::DEST_PHYSICAL; + + // Set vector number + entry |= vector as u64; + + // Write redirection table (unmask) + self.write_redirection_entry(irq, entry); + + log_info!( + "IO APIC {} IRQ {} -> Vector {} (APIC {}, {}, {})", + self.id, + irq, + vector, + dest_apic_id, + if level_triggered { "level" } else { "edge" }, + if active_low { "low" } else { "high" } + ); + } + + /// masked IRQ + pub unsafe fn mask_irq(&mut self, irq: u8) { + let mut entry = self.read_redirection_entry(irq); + entry |= redir_flags::MASKED; + self.write_redirection_entry(irq, entry); + + log_debug!("IO APIC {} IRQ {} masked", self.id, irq); + } + + /// unmasked IRQ + pub unsafe fn unmask_irq(&mut self, irq: u8) { + let mut entry = self.read_redirection_entry(irq); + entry &= !redir_flags::MASKED; + self.write_redirection_entry(irq, entry); + + log_debug!("IO APIC {} IRQ {} unmasked", self.id, irq); + } + + /// Print IO APIC information + pub unsafe fn print_info(&mut self) { + let id = self.read(reg::ID) >> 24; + let version = self.read(reg::VER); + let apic_ver = version & 0xFF; + + log_info!("IO APIC {} ID: {}", self.id, id); + log_info!("IO APIC {} Version: {:#x}", self.id, apic_ver); + log_info!("IO APIC {} Max Redirection Entries: {}", self.id, self.max_redirection_entries); + log_info!("IO APIC {} GSI Base: {}", self.id, self.gsi_base); + } +} + +/// Initialize a single IO APIC (using mapped virtual address) +pub unsafe fn init_single_ioapic(base_vaddr: VirtAddr, id: u8, gsi_base: u32) { + let mut ioapic = IoApic { + base_vaddr, + id, + gsi_base, + max_redirection_entries: 0, + }; + + // Read version information to get the maximum number of redirect entries + let version = ioapic.read(reg::VER); + ioapic.max_redirection_entries = ((version >> 16) & 0xFF) as u8 + 1; + + ioapic.init(); + ioapic.print_info(); + + IO_APICS.lock().push(ioapic); +} + +/// Initialize all IO APICs (from physical address, need to be mapped first) +pub unsafe fn init_io_apics(io_apics: &[(PhysAddr, u8, u32)]) { + let mut apics = IO_APICS.lock(); + + for (paddr, id, gsi_base) in io_apics { + let mut ioapic = IoApic::new(*paddr, *id, *gsi_base); + ioapic.init(); + ioapic.print_info(); + apics.push(ioapic); + } + + log_info!("All IO APICs initialized"); +} + +/// Configuring IRQ Redirection +pub fn set_irq_redirect( + irq: u8, + vector: u8, + dest_apic_id: u8, + level_triggered: bool, + active_low: bool, +) { + unsafe { + let mut apics = IO_APICS.lock(); + + // Find the IO APIC responsible for this IRQ + for ioapic in apics.iter_mut() { + let gsi_start = ioapic.gsi_base as u8; + let gsi_end = gsi_start + ioapic.max_redirection_entries; + + if irq >= gsi_start && irq < gsi_end { + let local_irq = irq - gsi_start; + ioapic.set_irq_redirect(local_irq, vector, dest_apic_id, level_triggered, active_low); + return; + } + } + + log_warn!("No IO APIC found for IRQ {}", irq); + } +} + +/// Block IRQ +pub fn mask_irq(irq: u8) { + unsafe { + let mut apics = IO_APICS.lock(); + for ioapic in apics.iter_mut() { + let gsi_start = ioapic.gsi_base as u8; + let gsi_end = gsi_start + ioapic.max_redirection_entries; + + if irq >= gsi_start && irq < gsi_end { + let local_irq = irq - gsi_start; + ioapic.mask_irq(local_irq); + return; + } + } + } +} + +/// Unmask IRQ +pub fn unmask_irq(irq: u8) { + unsafe { + let mut apics = IO_APICS.lock(); + for ioapic in apics.iter_mut() { + let gsi_start = ioapic.gsi_base as u8; + let gsi_end = gsi_start + ioapic.max_redirection_entries; + + if irq >= gsi_start && irq < gsi_end { + let local_irq = irq - gsi_start; + ioapic.unmask_irq(local_irq); + return; + } + } + } +} \ No newline at end of file diff --git a/kernel/src/hal/lapic.rs b/kernel/src/hal/lapic.rs new file mode 100644 index 0000000..f82199f --- /dev/null +++ b/kernel/src/hal/lapic.rs @@ -0,0 +1,190 @@ +// kernel/src/hal/lapic.rs +use x86_64::{PhysAddr, VirtAddr}; +use spin::Mutex; +use crate::{log_trace, log_debug, log_info, log_warn, log_error}; +use crate::mm::vma; + +/// Local APIC register offset +#[repr(u32)] +#[derive(Debug, Clone, Copy)] +#[allow(dead_code)] +enum ApicRegister { + Id = 0x20, + Version = 0x30, + TaskPriority = 0x80, + ProcessorPriority = 0xA0, + Eoi = 0xB0, + LogicalDestination = 0xD0, + DestinationFormat = 0xE0, + SpuriousInterruptVector = 0xF0, + ErrorStatus = 0x280, + LvtTimer = 0x320, + LvtThermalSensor = 0x330, + LvtPerformanceCounter = 0x340, + LvtLint0 = 0x350, + LvtLint1 = 0x360, + LvtError = 0x370, + TimerInitialCount = 0x380, + TimerCurrentCount = 0x390, + TimerDivideConfig = 0x3E0, +} + +/// APIC configuration flags +#[allow(dead_code)] +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 struct LocalApic { + base_vaddr: VirtAddr, +} + +static LOCAL_APIC: Mutex> = Mutex::new(None); + +impl LocalApic { + /// Create Local APIC from physical address + pub unsafe fn new(base_paddr: PhysAddr) -> Self { + let base_vaddr = vma::phys_to_virt(base_paddr.as_u64()); + + log_debug!("Local APIC physical base: {:#x}", base_paddr.as_u64()); + log_debug!("Local APIC virtual base: {:#x}", base_vaddr.as_u64()); + + Self { base_vaddr } + } + + /// Read APIC registers + 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) { + let addr = self.base_vaddr.as_u64() + reg as u64; + core::ptr::write_volatile(addr as *mut u32, value); + } + + /// 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 + self.write(ApicRegister::SpuriousInterruptVector, spurious); + + // Set task priority to 0 (accept all interrupts) + self.write(ApicRegister::TaskPriority, 0); + + // Configure LVT entries - mask all local interrupts by default + self.write(ApicRegister::LvtTimer, flags::LVT_MASKED); + self.write(ApicRegister::LvtLint0, flags::LVT_MASKED); + self.write(ApicRegister::LvtLint1, flags::LVT_MASKED); + self.write(ApicRegister::LvtError, flags::LVT_MASKED); + self.write(ApicRegister::LvtPerformanceCounter, flags::LVT_MASKED); + self.write(ApicRegister::LvtThermalSensor, flags::LVT_MASKED); + + log_info!("Local APIC initialized"); + } + + /// Obtaining the APIC ID + pub unsafe fn id(&self) -> u32 { + self.read(ApicRegister::Id) >> 24 + } + + /// Get the APIC version + pub unsafe fn version(&self) -> u32 { + self.read(ApicRegister::Version) + } + + /// Send EOI (End of Interrupt) + pub unsafe fn send_eoi(&mut self) { + self.write(ApicRegister::Eoi, 0); + } + + /// Configuring Timers + pub unsafe fn setup_timer(&mut self, vector: u8, divide_config: u32, initial_count: u32) { + // Setting the crossover + self.write(ApicRegister::TimerDivideConfig, divide_config); + + // Setting the LVT Timer (periodic mode) + let lvt = flags::LVT_TIMER_PERIODIC | (vector as u32); + self.write(ApicRegister::LvtTimer, lvt); + + // Set the initial count + self.write(ApicRegister::TimerInitialCount, initial_count); + + log_info!("Local APIC timer configured: vector={}, count={}", vector, initial_count); + } + + pub unsafe fn print_info(&self) { + let id = self.id(); + let version = self.version(); + let max_lvt = (version >> 16) & 0xFF; + let apic_version = version & 0xFF; + + log_info!("Local APIC ID: {}", id); + log_info!("Local APIC Version: {:#x}", apic_version); + log_info!("Max LVT Entry: {}", max_lvt); + } +} + +/// Initialize Local APIC (using mapped virtual address) +pub unsafe fn init_local_apic_with_vaddr(base_vaddr: VirtAddr) { + let mut apic = LocalApic { base_vaddr }; + apic.init(); + apic.print_info(); + + *LOCAL_APIC.lock() = Some(apic); +} + +/// Initialize Local APIC (from physical address, needs to be mapped first) +pub unsafe fn init_local_apic(base_paddr: PhysAddr) { + let base_vaddr = vma::phys_to_virt(base_paddr.as_u64()); + init_local_apic_with_vaddr(base_vaddr); +} + +/// Send EOI +pub fn send_eoi() { + unsafe { + if let Some(apic) = LOCAL_APIC.lock().as_mut() { + apic.send_eoi(); + } + } +} + +/// Get the Local APIC ID +pub fn get_apic_id() -> Option { + unsafe { + LOCAL_APIC.lock().as_ref().map(|apic| apic.id()) + } +} + +/// Disable legacy 8259 PIC +/// This function should be called before using the APIC to avoid conflicts. +pub fn disable_legacy_pic() { + use crate::hal::io::io_port_wb; + + unsafe { + // Remap PIC to unused interrupt vector + // Master PIC + io_port_wb(0x20, 0x11); // ICW1: initialization + io_port_wb(0x21, 0x20); // ICW2: Interrupt vector offset (32-39) + io_port_wb(0x21, 0x04); // ICW3: Tell the Master PIC Slave to be on IRQ2 + io_port_wb(0x21, 0x01); // ICW4: 8086 mode + + // Slave PIC + io_port_wb(0xA0, 0x11); // ICW1: initialization + io_port_wb(0xA1, 0x28); // ICW2: Interrupt vector offset (40-47) + io_port_wb(0xA1, 0x02); // ICW3: Tell the Slave PIC to connect to Master IRQ2 + io_port_wb(0xA1, 0x01); // ICW4: 8086 mode + + // Block all IRQs (disable PIC) + io_port_wb(0x21, 0xFF); + io_port_wb(0xA1, 0xFF); + } + + log_info!("Legacy 8259 PIC disabled"); +} \ No newline at end of file diff --git a/kernel/src/hal/mod.rs b/kernel/src/hal/mod.rs index c619489..e82908d 100644 --- a/kernel/src/hal/mod.rs +++ b/kernel/src/hal/mod.rs @@ -2,5 +2,5 @@ pub mod io; pub mod cpu; pub mod acpi; pub mod rtc; -pub mod apic; -mod ioapic; \ No newline at end of file +pub mod lapic; +pub mod ioapic; \ No newline at end of file diff --git a/kernel/src/kernel/k_init.rs b/kernel/src/kernel/k_init.rs index c65f3aa..0138dca 100644 --- a/kernel/src/kernel/k_init.rs +++ b/kernel/src/kernel/k_init.rs @@ -1,7 +1,7 @@ -// kernel/src/k_init.rs (Updated with Logger) +// kernel/src/kernel/k_init.rs use bootloader_api::BootInfo; use bootloader_api::info::MemoryRegionKind; -use x86_64::structures::paging::{OffsetPageTable, Page }; +use x86_64::structures::paging::OffsetPageTable; use x86_64::{PhysAddr, VirtAddr}; use crate::mm::{allocator::{heap, frame, pmm}, vmm, paging, vma}; use crate::arch::amd64::{gdt, idt}; @@ -11,7 +11,8 @@ use crate::kernel::k_main; 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::hal::{acpi, rtc}; +use crate::drivers::keyboard; +use crate::hal::{acpi, lapic, rtc}; fn _logger_init() { init( @@ -132,13 +133,11 @@ fn _boot_report(memory_regions: &bootloader_api::info::MemoryRegions, physical_m log_info!("Heap Start: {:#x}", vma::HEAP_START); log_info!("Heap Size: {} KiB", vma::HEAP_SIZE / 1024); - if let Some(stats) = pmm::get_memory_stats() { - log_info!("Total Memory: {} MiB", stats.total_memory / (1024 * 1024)); - log_info!("Free Memory: {} MiB", stats.free_memory / (1024 * 1024)); - } + vma::print_info(); + vmm::get_vmm_stats().print(); } -fn _acpi_init(rsdp_addr: Option, physical_memory_offset: u64) { +fn _acpi_init(rsdp_addr: Option, physical_memory_offset: u64) -> Option { kprintln!(); if let Some(rsdp) = rsdp_addr { @@ -146,20 +145,82 @@ fn _acpi_init(rsdp_addr: Option, physical_memory_offset: u64) { if let Some(acpi_info) = acpi::init(rsdp, physical_memory_offset) { acpi::print_info(&acpi_info); + return Some(acpi_info); } else { log_warn!("ACPI initialization failed"); } } else { log_warn!("RSDP not provided by bootloader"); } + + None } -fn _post_init() { +fn _post_init( + acpi_info: Option<&acpi::AcpiInfo>, + mapper: &mut OffsetPageTable, + frame_allocator: &mut frame::BootInfoFrameAllocator, +) { kprintln!(); log_info!("Post Initialization"); - // TODO: 釋放 bootloader 佔用的內存 + + // 初始化 APIC/IOAPIC (如果有的話) + if let Some(info) = acpi_info { + if info.has_apic { + lapic::disable_legacy_pic(); + + unsafe { + if let Some(local_apic_addr) = info.local_apic_address { + log_info!("Initializing Local APIC..."); + log_debug!("Mapping Local APIC physical address: {:#x}", local_apic_addr); + + if let Some(vaddr) = vmm::map_device_memory( + PhysAddr::new(local_apic_addr), + 4096, + mapper, + frame_allocator, + ) { + log_debug!("Local APIC mapped to virtual address: {:#x}", vaddr.as_u64()); + + lapic::init_local_apic_with_vaddr(vaddr); + + if let Some(apic_id) = lapic::get_apic_id() { + log_info!("Current Local APIC ID: {}", apic_id); + } + } else { + log_error!("Failed to map Local APIC memory"); + } + } + + if !info.io_apics.is_empty() { + log_info!("Initializing IO APICs..."); + + for (paddr, id, gsi_base) in &info.io_apics { + log_debug!("Mapping IO APIC {} at physical address: {:#x}", id, paddr); + + if let Some(vaddr) = vmm::map_device_memory( + PhysAddr::new(*paddr), + 4096, + mapper, + frame_allocator, + ) { + log_debug!("IO APIC {} mapped to virtual address: {:#x}", id, vaddr.as_u64()); + crate::hal::ioapic::init_single_ioapic(vaddr, *id, *gsi_base); + } else { + log_error!("Failed to map IO APIC {} memory", id); + } + } + + log_info!("All IO APICs initialized"); + } + } + } else { + log_warn!("APIC not available, using legacy PIC (not implemented yet)"); + } + } rtc::init(); + keyboard::init(); log_debug!("Cleanup completed"); } @@ -182,13 +243,12 @@ pub fn _kernel_init(boot_info: &'static mut BootInfo) -> ! { &boot_info.memory_regions, physical_memory_offset ); + let acpi_info = _acpi_init(rsdp_addr, physical_memory_offset); + + _post_init(acpi_info.as_ref(), &mut mapper, &mut frame_allocator); _boot_report(&boot_info.memory_regions, physical_memory_offset); - _acpi_init(rsdp_addr, physical_memory_offset); - - _post_init(); - kprintln!(); kprintln!("========================================"); kprintln!(" Kernel Initialization Complete! "); diff --git a/kernel/src/kernel/k_main.rs b/kernel/src/kernel/k_main.rs index 781f09d..327f161 100644 --- a/kernel/src/kernel/k_main.rs +++ b/kernel/src/kernel/k_main.rs @@ -1,8 +1,9 @@ -// kernel/src/k_main.rs +// kernel/src/kernel/k_main.rs use crate::hal::{cpu, rtc}; use crate::kprintln; use crate::{log_trace, log_debug, log_info, log_warn, log_error, log_fatal}; use crate::mm::{vma, vmm}; +use crate::mm::allocator::pmm; pub fn _kernel_main() -> ! { kprintln!(); @@ -18,8 +19,10 @@ pub fn _kernel_main() -> ! { kprintln!(); - vma::print_info(); - vmm::get_vmm_stats().print(); + if let Some(stats) = pmm::get_memory_stats() { + log_info!("Total Memory: {} MiB", stats.total_memory / (1024 * 1024)); + log_info!("Free Memory: {} MiB", stats.free_memory / (1024 * 1024)); + } kprintln!(); @@ -32,33 +35,45 @@ pub fn _kernel_main() -> ! { log_debug!("CR3: 0x{:016x}", cpu::cpu_r_cr3()); log_debug!("CR4: 0x{:016x}", cpu::cpu_r_cr4()); + 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); - // kprintln!(); - // kprintln!("=== Logger Level Demonstration ==="); - // kprintln!(); - // - // log_trace!("TRACE: This is a trace message (lowest priority)"); - // log_debug!("DEBUG: Detailed debugging information"); - // log_info!("INFO: General information about system operation"); - // log_warn!("WARN: Warning message - something might be wrong"); - // log_error!("ERROR: Error occurred but system can continue"); - // log_fatal!("FATAL: Critical error (highest priority)"); - // - // kprintln!(); - // - // log_info!("Starting system services..."); - // log_debug!("Loading drivers..."); - // log_trace!(" Scanning PCI bus"); - // log_trace!("Initializing USB controller"); - // log_debug!("Drivers loaded successfully"); - // - // log_info!("System is ready!"); + 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"); + + // Enable CPU interrupts + cpu::cpu_enable_interrupts(); + + log_info!("CPU interrupts enabled"); + + kprintln!(); + log_info!("Interrupt system ready!"); + + } else { + log_error!("APIC not available, cannot enable keyboard"); + } kprintln!(); - log_warn!("Entering idle loop"); + log_info!("System initialization complete!"); + log_warn!("Entering idle loop..."); + kprintln!(); loop { + // Until the next interrupt occurs cpu::cpu_halt(); } } \ No newline at end of file diff --git a/kernel/src/klibc/print.rs b/kernel/src/klibc/print.rs index 496841c..b5c5bb0 100644 --- a/kernel/src/klibc/print.rs +++ b/kernel/src/klibc/print.rs @@ -18,7 +18,7 @@ pub fn _print(args: fmt::Arguments) { } #[macro_export] -macro_rules! print { +macro_rules! kprint { ($($arg:tt)*) => ($crate::klibc::print::_print(format_args!($($arg)*))); } diff --git a/kernel/src/main.rs b/kernel/src/main.rs index 96c6792..ac2a535 100644 --- a/kernel/src/main.rs +++ b/kernel/src/main.rs @@ -21,6 +21,7 @@ pub mod arch; pub mod mm; pub mod tty; pub mod kernel; +pub mod drivers; use hal::cpu; const CONFIG: BootloaderConfig = { From 0d494a1e8d01869c81247abbc74a00b140c4f3cf Mon Sep 17 00:00:00 2001 From: ParrotXray Date: Tue, 14 Oct 2025 16:11:13 +0800 Subject: [PATCH 04/13] feat: Actual machine test triggers #NP --- kernel/src/arch/amd64/idt.rs | 4 ++-- kernel/src/kernel/k_main.rs | 3 +-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/kernel/src/arch/amd64/idt.rs b/kernel/src/arch/amd64/idt.rs index 502c6bf..05318b3 100644 --- a/kernel/src/arch/amd64/idt.rs +++ b/kernel/src/arch/amd64/idt.rs @@ -47,6 +47,6 @@ pub fn init() { } pub fn print_info() { - log_info!(" IDT loaded and active"); - log_info!(" Exception handlers registered"); + log_info!("IDT loaded and active"); + log_info!("Exception handlers registered"); } \ No newline at end of file diff --git a/kernel/src/kernel/k_main.rs b/kernel/src/kernel/k_main.rs index 327f161..2d9f7a0 100644 --- a/kernel/src/kernel/k_main.rs +++ b/kernel/src/kernel/k_main.rs @@ -55,7 +55,7 @@ pub fn _kernel_main() -> ! { crate::hal::ioapic::unmask_irq(1); log_info!("Keyboard interrupt unmasked"); - // Enable CPU interrupts + cpu::cpu_enable_interrupts(); log_info!("CPU interrupts enabled"); @@ -73,7 +73,6 @@ pub fn _kernel_main() -> ! { kprintln!(); loop { - // Until the next interrupt occurs cpu::cpu_halt(); } } \ No newline at end of file From fa311cfab4bde14be6cfb81ac4acdeb7f678fb8c Mon Sep 17 00:00:00 2001 From: ParrotXray Date: Thu, 16 Oct 2025 14:54:31 +0800 Subject: [PATCH 05/13] fix: Fix real machine anomalies and improve keyboard driver --- kernel/src/arch/amd64/gdt.rs | 61 ++++++------ kernel/src/arch/amd64/idt.rs | 11 ++- kernel/src/arch/amd64/isr.rs | 34 +++++-- kernel/src/drivers/keyboard.rs | 163 ++++++++++++++++++++------------- 4 files changed, 168 insertions(+), 101 deletions(-) diff --git a/kernel/src/arch/amd64/gdt.rs b/kernel/src/arch/amd64/gdt.rs index 393a1b4..1a7466f 100644 --- a/kernel/src/arch/amd64/gdt.rs +++ b/kernel/src/arch/amd64/gdt.rs @@ -14,25 +14,25 @@ lazy_static! { static ref TSS: TaskStateSegment = { let mut tss = TaskStateSegment::new(); - unsafe { tss.interrupt_stack_table[DOUBLE_FAULT_IST_INDEX as usize] = { - const STACK_SIZE: usize = 4096 * 5; // 20KB - static mut STACK: [u8; STACK_SIZE] = [0; STACK_SIZE]; + // Double Fault Stack + unsafe { + tss.interrupt_stack_table[DOUBLE_FAULT_IST_INDEX as usize] = { + const STACK_SIZE: usize = 4096 * 5; + static mut STACK: [u8; STACK_SIZE] = [0; STACK_SIZE]; + let stack_start = VirtAddr::new(&raw const STACK as u64); + stack_start + STACK_SIZE as u64 + }; + } - let stack_start = VirtAddr::new(&raw const STACK as *const _ as u64); - let stack_end = stack_start + STACK_SIZE as u64; - - stack_end - }; } - - unsafe { tss.privilege_stack_table[0] = { - const STACK_SIZE: usize = 4096 * 5; // 20KB - static mut STACK: [u8; STACK_SIZE] = [0; STACK_SIZE]; - - let stack_start = VirtAddr::new(&raw const STACK as *const _ as u64); - let stack_end = stack_start + STACK_SIZE as u64; - - stack_end - }; } + // Privilege Stack + unsafe { + tss.privilege_stack_table[0] = { + const STACK_SIZE: usize = 4096 * 5; + static mut STACK: [u8; STACK_SIZE] = [0; STACK_SIZE]; + let stack_start = VirtAddr::new(&raw const STACK as u64); + stack_start + STACK_SIZE as u64 + }; + } tss }; @@ -42,21 +42,21 @@ lazy_static! { static ref GDT: (GlobalDescriptorTable, Selectors) = { let mut gdt = GlobalDescriptorTable::new(); - // 0x00: Null + // 0x00: Null Descriptor (必須) - // 0x08 ring 0 + // 0x08: Kernel Code (ring 0, executable) let kernel_code_selector = gdt.append(Descriptor::kernel_code_segment()); - // 0x10 ring 0 + // 0x10: Kernel Data (ring 0, writable) let kernel_data_selector = gdt.append(Descriptor::kernel_data_segment()); - // 0x18 ring 3 - let user_code_selector = gdt.append(Descriptor::user_code_segment()); - - // 0x20 ring 3 + // 0x18: User Data (ring 3, writable) - 注意順序 let user_data_selector = gdt.append(Descriptor::user_data_segment()); - // 0x28 Task seg + // 0x20: User Code (ring 3, executable) + let user_code_selector = gdt.append(Descriptor::user_code_segment()); + + // 0x28: TSS (佔用 2 個條目) let tss_selector = gdt.append(Descriptor::tss_segment(&TSS)); ( @@ -101,11 +101,10 @@ pub fn kernel_data_selector() -> SegmentSelector { GDT.1.kernel_data_selector } -// 初始化 GDT +// initialization GDT pub fn init() { + GDT.0.load(); - let gdt_addr = &GDT.0 as *const _ as u64; - log_debug!("GDT address: {:#018x}", gdt_addr); unsafe { CS::set_reg(GDT.1.kernel_code_selector); @@ -114,9 +113,11 @@ pub fn init() { ES::set_reg(GDT.1.kernel_data_selector); SS::set_reg(GDT.1.kernel_data_selector); - // 加載 TSS load_tss(GDT.1.tss_selector); } + + log_debug!("GDT loaded at {:#018x}", &GDT.0 as *const _ as u64); + log_debug!("TSS loaded, selector: {:#x}", GDT.1.tss_selector.0); } pub fn print_info() { diff --git a/kernel/src/arch/amd64/idt.rs b/kernel/src/arch/amd64/idt.rs index 05318b3..d167d49 100644 --- a/kernel/src/arch/amd64/idt.rs +++ b/kernel/src/arch/amd64/idt.rs @@ -35,9 +35,18 @@ lazy_static! { idt.simd_floating_point.set_handler_fn(simd_floating_point_handler); idt.virtualization.set_handler_fn(virtualization_handler); - // IRQ 32 start + + // 硬件中斷 (32-255) + // IRQ 0 (32) + idt[32].set_handler_fn(default_irq_handler); + + // IRQ 1 (33) - Keyboard idt[33].set_handler_fn(keyboard_interrupt_handler); // IRQ 1 Keyboard + // IRQ 2-15 (34-47) - default + for i in 34..=47 { + idt[i].set_handler_fn(default_irq_handler); + } idt }; } diff --git a/kernel/src/arch/amd64/isr.rs b/kernel/src/arch/amd64/isr.rs index c3d2737..1b5f40f 100644 --- a/kernel/src/arch/amd64/isr.rs +++ b/kernel/src/arch/amd64/isr.rs @@ -1,7 +1,7 @@ // kernel/src/kernel/asm/amd64/isr use x86_64::structures::idt::{InterruptStackFrame, PageFaultErrorCode}; use x86_64::VirtAddr; -use crate::kprintln; +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::mm::paging; @@ -20,7 +20,11 @@ pub extern "x86-interrupt" fn divide_error_handler(stack_frame: InterruptStackFr pub extern "x86-interrupt" fn debug_handler(stack_frame: InterruptStackFrame) { kprintln!(); log_debug!("EXCEPTION: DEBUG (#DB)"); - log_debug!("{:#?}", stack_frame); + log_debug!("instruction pointer: {:#x}", stack_frame.instruction_pointer.as_u64()); + log_debug!("code segment: index: {:#?}, rpl: {:#?}", stack_frame.code_segment.index(), stack_frame.code_segment.rpl()); + log_debug!("cpu flags: {:#x}", stack_frame.cpu_flags.bits()); + log_debug!("stack pointer: {:#x}", stack_frame.stack_pointer.as_u64()); + log_debug!("stack segment: index: {:#?}, rpl: {:#?}", stack_frame.stack_segment.index(), stack_frame.stack_segment.rpl()); } /// Non-Maskable Interrupt (NMI) @@ -111,7 +115,23 @@ pub extern "x86-interrupt" fn segment_not_present_handler( kprintln!(); log_fatal!("EXCEPTION: SEGMENT NOT PRESENT (#NP)"); log_fatal!("Error Code: {:#x}", error_code); + log_fatal!("instruction pointer: {:#x}", stack_frame.instruction_pointer.as_u64()); + log_fatal!("code segment: index: {:#?}, rpl: {:#?}", stack_frame.code_segment.index(), stack_frame.code_segment.rpl()); + log_fatal!("cpu flags: {:#x}", stack_frame.cpu_flags.bits()); + log_fatal!("stack pointer: {:#x}", stack_frame.stack_pointer.as_u64()); + log_fatal!("stack segment: index: {:#?}, rpl: {:#?}", stack_frame.stack_segment.index(), stack_frame.stack_segment.rpl()); + + let is_external = (error_code & 0x01) != 0; + let table = if (error_code & 0x02) != 0 { "IDT" } else { "GDT" }; + let index = (error_code >> 3) & 0x1FFF; + + log_fatal!("Segment: {} index {:#x} (external: {})", table, index, is_external); log_fatal!("{:#?}", stack_frame); + + log_fatal!("Current segments:"); + log_fatal!(" CS: {:#x}", crate::arch::amd64::gdt::kernel_code_selector().0); + log_fatal!(" SS: {:#x}", crate::arch::amd64::gdt::kernel_data_selector().0); + loop { cpu::cpu_halt(); } @@ -230,14 +250,16 @@ pub extern "x86-interrupt" fn keyboard_interrupt_handler(stack_frame: InterruptS use x86_64::instructions::port::Port; unsafe { - // 读取键盘扫描码 let mut port = Port::new(0x60); let scancode: u8 = port.read(); - // 传递给键盘驱动处理 - crate::drivers::keyboard::handle_scancode(scancode); + drivers::keyboard::handle_scancode(scancode); } - // 发送 EOI lapic::send_eoi(); +} + +pub extern "x86-interrupt" fn default_irq_handler(stack_frame: InterruptStackFrame) { + lapic::send_eoi(); + log_trace!("Unhandled IRQ: {:#?}", stack_frame); } \ No newline at end of file diff --git a/kernel/src/drivers/keyboard.rs b/kernel/src/drivers/keyboard.rs index eb87880..80791fd 100644 --- a/kernel/src/drivers/keyboard.rs +++ b/kernel/src/drivers/keyboard.rs @@ -9,17 +9,17 @@ static SCANCODE_TO_ASCII: [u8; 128] = [ b'q', b'w', b'e', b'r', b't', b'y', b'u', b'i', // 0x10-0x17 b'o', b'p', b'[', b']', b'\n', 0, b'a', b's', // 0x18-0x1F (Ctrl) b'd', b'f', b'g', b'h', b'j', b'k', b'l', b';', // 0x20-0x27 - b'\'',b'`', 0, b'\\',b'z', b'x', b'c', b'v', // 0x28-0x2F (LShift) - b'b', b'n', b'm', b',', b'.', b'/', 0, b'*', // 0x30-0x37 (RShift) - 0, b' ', 0, 0, 0, 0, 0, 0, // 0x38-0x3F (Alt, CapsLock, F1-F5) - 0, 0, 0, 0, 0, 0, 0, 0, // 0x40-0x47 (F6-F10, NumLock, ScrollLock) - 0, 0, 0, 0, 0, 0, 0, 0, // 0x48-0x4F (Home, Up, PgUp, -, Left, ...) - 0, 0, 0, 0, 0, 0, 0, 0, // 0x50-0x57 - 0, 0, 0, 0, 0, 0, 0, 0, // 0x58-0x5F - 0, 0, 0, 0, 0, 0, 0, 0, // 0x60-0x67 - 0, 0, 0, 0, 0, 0, 0, 0, // 0x68-0x6F - 0, 0, 0, 0, 0, 0, 0, 0, // 0x70-0x77 - 0, 0, 0, 0, 0, 0, 0, 0, // 0x78-0x7F + b'\'',b'`', 0, b'\\',b'z', b'x', b'c', b'v', // 0x28-0x2F (LShift) + b'b', b'n', b'm', b',', b'.', b'/', 0, b'*', // 0x30-0x37 (RShift, Numpad *) + 0, b' ', 0, 0, 0, 0, 0, 0, // 0x38-0x3F + 0, 0, 0, 0, 0, 0, 0, b'7', // 0x40-0x47 (Numpad 7) + b'8', b'9', b'-', b'4', b'5', b'6', b'+', b'1', // 0x48-0x4F (Numpad) + b'2', b'3', b'0', b'.', 0, 0, 0, 0, // 0x50-0x57 (Numpad) + 0, 0, 0, 0, 0, 0, 0, 0, // 0x58-0x5F + 0, 0, 0, 0, 0, 0, 0, 0, // 0x60-0x67 + 0, 0, 0, 0, 0, 0, 0, 0, // 0x68-0x6F + 0, 0, 0, 0, 0, 0, 0, 0, // 0x70-0x77 + 0, 0, 0, 0, 0, 0, 0, 0, // 0x78-0x7F ]; /// Character mapping when Shift key is pressed @@ -31,38 +31,17 @@ static SCANCODE_TO_ASCII_SHIFT: [u8; 128] = [ b'D', b'F', b'G', b'H', b'J', b'K', b'L', b':', // 0x20-0x27 b'"', b'~', 0, b'|', b'Z', b'X', b'C', b'V', // 0x28-0x2F b'B', b'N', b'M', b'<', b'>', b'?', 0, b'*', // 0x30-0x37 - 0, b' ', 0, 0, 0, 0, 0, 0, // 0x38-0x3F - 0, 0, 0, 0, 0, 0, 0, 0, // 0x40-0x47 - 0, 0, 0, 0, 0, 0, 0, 0, // 0x48-0x4F - 0, 0, 0, 0, 0, 0, 0, 0, // 0x50-0x57 - 0, 0, 0, 0, 0, 0, 0, 0, // 0x58-0x5F - 0, 0, 0, 0, 0, 0, 0, 0, // 0x60-0x67 - 0, 0, 0, 0, 0, 0, 0, 0, // 0x68-0x6F - 0, 0, 0, 0, 0, 0, 0, 0, // 0x70-0x77 - 0, 0, 0, 0, 0, 0, 0, 0, // 0x78-0x7F + 0, b' ', 0, 0, 0, 0, 0, 0, // 0x38-0x3F + 0, 0, 0, 0, 0, 0, 0, b'7', // 0x40-0x47 + b'8', b'9', b'-', b'4', b'5', b'6', b'+', b'1', // 0x48-0x4F + b'2', b'3', b'0', b'.', 0, 0, 0, 0, // 0x50-0x57 + 0, 0, 0, 0, 0, 0, 0, 0, // 0x58-0x5F + 0, 0, 0, 0, 0, 0, 0, 0, // 0x60-0x67 + 0, 0, 0, 0, 0, 0, 0, 0, // 0x68-0x6F + 0, 0, 0, 0, 0, 0, 0, 0, // 0x70-0x77 + 0, 0, 0, 0, 0, 0, 0, 0, // 0x78-0x7F ]; -/// Numpad scancode mapping -static NUMPAD_SCANCODE_TO_ASCII: [u8; 128] = { - let mut map = [0u8; 128]; - map[0x47] = b'7'; - map[0x48] = b'8'; - map[0x49] = b'9'; - map[0x4B] = b'4'; - map[0x4C] = b'5'; - map[0x4D] = b'6'; - map[0x4F] = b'1'; - map[0x50] = b'2'; - map[0x51] = b'3'; - map[0x52] = b'0'; - map[0x53] = b'.'; - map[0x4A] = b'-'; - map[0x4E] = b'+'; - map[0x37] = b'*'; - map[0x35] = b'/'; - map -}; - /// Keyboard state struct KeyboardState { shift_pressed: bool, @@ -70,6 +49,7 @@ struct KeyboardState { alt_pressed: bool, caps_lock: bool, num_lock: bool, + e0_prefix: bool, } impl KeyboardState { @@ -79,7 +59,8 @@ impl KeyboardState { ctrl_pressed: false, alt_pressed: false, caps_lock: false, - num_lock: true, // Usually enabled by default + num_lock: true, + e0_prefix: false, } } } @@ -90,22 +71,86 @@ static KEYBOARD_STATE: Mutex = Mutex::new(KeyboardState::new()); pub fn handle_scancode(raw: u8) { let mut state = KEYBOARD_STATE.lock(); + if raw == 0xE0 { + state.e0_prefix = true; + return; + } + let key_released = (raw & 0x80) != 0; let scancode = raw & 0x7F; + let is_extended = state.e0_prefix; + state.e0_prefix = false; - // Handle modifier keys + // Process the extended key + if is_extended { + if key_released { + return; + } + + match scancode { + 0x1C => print_char(b'\n'), // Numpad Enter + 0x35 => print_char(b'/'), // Numpad / + 0x47 => kprintln!("[Home]"), + 0x48 => kprintln!("[Up]"), + 0x49 => kprintln!("[PgUp]"), + 0x4B => kprintln!("[Left]"), + 0x4D => kprintln!("[Right]"), + 0x4F => kprintln!("[End]"), + 0x50 => kprintln!("[Down]"), + 0x51 => kprintln!("[PgDn]"), + 0x52 => kprintln!("[Insert]"), + 0x53 => kprintln!("[Delete]"), + + // 0x19 => { kprintln!("[Next Track]");} + // 0x10 => { kprintln!("[Prev Track]");} + // 0x24 => { kprintln!("[Stop]");} + // 0x22 => { kprintln!("[Play/Pause]");} + // 0x20 => { kprintln!("[Mute]");} + // 0x30 => { kprintln!("[Volume Up]");} + // 0x2E => { kprintln!("[Volume Down]");} + _ => {} + } + return; + } + + // Modifier keys match scancode { - 0x2A | 0x36 => { state.shift_pressed = !key_released; return; } // Shift - 0x1D => { state.ctrl_pressed = !key_released; return; } // Ctrl - 0x38 => { state.alt_pressed = !key_released; return; } // Alt - 0x3A => { if !key_released { state.caps_lock = !state.caps_lock; } return; } // Caps Lock - 0x45 => { if !key_released { state.num_lock = !state.num_lock; } return; } // Num Lock + 0x2A | 0x36 => { state.shift_pressed = !key_released; return; } + 0x1D => { state.ctrl_pressed = !key_released; return; } + 0x38 => { state.alt_pressed = !key_released; return; } + 0x3A => { if !key_released { state.caps_lock = !state.caps_lock; } return; } + 0x45 => { if !key_released { state.num_lock = !state.num_lock; } return; } _ => {} } - if key_released { return; } + if key_released { + return; + } - // When NumLock is off: Numpad outputs arrow or control keys + // F1-F12 + match scancode { + 0x3B => { kprintln!("[F1]"); return; } + 0x3C => { kprintln!("[F2]"); return; } + 0x3D => { kprintln!("[F3]"); return; } + 0x3E => { kprintln!("[F4]"); return; } + 0x3F => { kprintln!("[F5]"); return; } + 0x40 => { kprintln!("[F6]"); return; } + 0x41 => { kprintln!("[F7]"); return; } + 0x42 => { kprintln!("[F8]"); return; } + 0x43 => { kprintln!("[F9]"); return; } + 0x44 => { kprintln!("[F10]"); return; } + 0x57 => { kprintln!("[F11]"); return; } + 0x58 => { kprintln!("[F12]"); return; } + _ => {} + } + + // Esc 鍵 + if scancode == 0x01 { + kprintln!("[Esc]"); + return; + } + + // Arrow keys when NumLock is OFF (0x47-0x53) if !state.num_lock { match scancode { 0x47 => { kprintln!("[Home]"); return; } @@ -123,20 +168,16 @@ pub fn handle_scancode(raw: u8) { } } - // Handle numpad output based on NumLock state - let ascii = if state.num_lock && NUMPAD_SCANCODE_TO_ASCII[scancode as usize] != 0 { - NUMPAD_SCANCODE_TO_ASCII[scancode as usize] - } else if state.shift_pressed { + let ascii = if state.shift_pressed { SCANCODE_TO_ASCII_SHIFT[scancode as usize] } else { SCANCODE_TO_ASCII[scancode as usize] }; if ascii == 0 { - return; // Unmapped key + return; } - // Handle Caps Lock (affects letters only) let ascii = if state.caps_lock && ascii.is_ascii_alphabetic() { if state.shift_pressed { ascii.to_ascii_lowercase() @@ -147,20 +188,15 @@ pub fn handle_scancode(raw: u8) { ascii }; - // Handle Ctrl combinations if state.ctrl_pressed { match ascii { b'c' | b'C' => { kprintln!("^C"); return; } b'd' | b'D' => { kprintln!("^D"); return; } - b'l' | b'L' => { - crate::tty::tty::clear(0x000000); - return; - } + b'l' | b'L' => { crate::tty::tty::clear(0x000000); return; } _ => {} } } - // Output character print_char(ascii); } @@ -171,7 +207,6 @@ fn print_char(c: u8) { if c == b'\n' { kprintln!(); } else if c == 8 { - // TODO: Implement backspace functionality kprint!("\x08"); } else if c.is_ascii_graphic() || c == b' ' { kprint!("{}", c as char); @@ -181,4 +216,4 @@ fn print_char(c: u8) { /// Initialize keyboard driver pub fn init() { log_info!("Keyboard driver initialized"); -} +} \ No newline at end of file From 74de8650fe3824406330ede434654be561fe8676 Mon Sep 17 00:00:00 2001 From: ParrotXray Date: Thu, 16 Oct 2025 20:34:20 +0800 Subject: [PATCH 06/13] feat: Test RTC interrupt --- TODO.txt | 3 ++ kernel/src/arch/amd64/idt.rs | 7 +++- kernel/src/arch/amd64/isr.rs | 10 +++++ kernel/src/hal/rtc.rs | 61 +++++++++++++++++++------------ kernel/src/kernel/k_main.rs | 71 ++++++++++++++++++++++++++++++++++++ 5 files changed, 127 insertions(+), 25 deletions(-) diff --git a/TODO.txt b/TODO.txt index 881c53b..fb545b5 100644 --- a/TODO.txt +++ b/TODO.txt @@ -22,6 +22,9 @@ // - 用戶態/內核態切換 +// BUG +// - 在測試RTC中斷時 rtc::get_time() 處卡住 + // ==================== 高半核地址空間佈局 ==================== // // 0x0000_0000_0000 ┌─────────────────────┐ diff --git a/kernel/src/arch/amd64/idt.rs b/kernel/src/arch/amd64/idt.rs index d167d49..736a710 100644 --- a/kernel/src/arch/amd64/idt.rs +++ b/kernel/src/arch/amd64/idt.rs @@ -43,9 +43,12 @@ lazy_static! { // IRQ 1 (33) - Keyboard idt[33].set_handler_fn(keyboard_interrupt_handler); // IRQ 1 Keyboard - // IRQ 2-15 (34-47) - default + idt[40].set_handler_fn(rtc_interrupt_handler); // IRQ 8 + for i in 34..=47 { - idt[i].set_handler_fn(default_irq_handler); + if i != 40 { // 跳過 RTC + idt[i].set_handler_fn(default_irq_handler); + } } idt }; diff --git a/kernel/src/arch/amd64/isr.rs b/kernel/src/arch/amd64/isr.rs index 1b5f40f..675f5ba 100644 --- a/kernel/src/arch/amd64/isr.rs +++ b/kernel/src/arch/amd64/isr.rs @@ -262,4 +262,14 @@ 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); +} + +// 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(); + // 發送 EOI + crate::hal::lapic::send_eoi(); } \ No newline at end of file diff --git a/kernel/src/hal/rtc.rs b/kernel/src/hal/rtc.rs index f51ef2f..9b6aada 100644 --- a/kernel/src/hal/rtc.rs +++ b/kernel/src/hal/rtc.rs @@ -120,7 +120,7 @@ impl Rtc { } } - /// 將 BCD 轉換為二進制 + /// Convert BCD to binary fn bcd_to_binary(bcd: u8) -> u8 { (bcd & 0x0F) + ((bcd >> 4) * 10) } @@ -133,17 +133,18 @@ impl Rtc { pub fn init(&mut self) { unsafe { - // Read status register B - let status_b = Self::read_register(RTC_REG_B); - + let status_b = Self::read_register(RTC_REG_B | WITH_NMI_DISABLED); self.binary_mode = (status_b & RTC_BIN_ENCODED_BIT) != 0; self.hour_24_mode = (status_b & RTC_24HRS_ENCODED_BIT) != 0; - crate::log_debug!( - "RTC Mode: {} encoding, {} hour format", - if self.binary_mode { "Binary" } else { "BCD" }, - if self.hour_24_mode { "24" } else { "12" } - ); + 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); + + // ⭐ CRITICAL: Read Register C to clear any pending interrupts! + Self::read_register(RTC_REG_C); + + self.disable_timer(); } } @@ -162,7 +163,7 @@ impl Rtc { (second, minute, hour, day, month, year, weekday) } - /// Convert the value + /// Convert the value based on encoding mode fn convert_value(&self, value: u8) -> u8 { if self.binary_mode { value @@ -177,12 +178,14 @@ impl Rtc { let (mut second, mut minute, mut hour, mut day, mut month, mut year, weekday) = self.read_raw(); + // Convert from BCD to binary when needed second = self.convert_value(second); minute = self.convert_value(minute); day = self.convert_value(day); month = self.convert_value(month); year = self.convert_value(year); + // Handle 12-hour format let pm_bit = hour & 0x80; hour = self.convert_value(hour & 0x7F); @@ -222,15 +225,9 @@ impl Rtc { /// Enable RTC timer interrupt (1024Hz) pub fn enable_timer(&self) { unsafe { - // Disable NMI and set frequency - let mut reg_a = Self::read_register(RTC_REG_A); - reg_a = (reg_a & 0xF0) | RTC_DIVIDER_33KHZ | RTC_FREQUENCY_1024HZ; - Self::write_register(RTC_REG_A, reg_a); - - // Enable periodic interrupts - let mut reg_b = Self::read_register(RTC_REG_B); + let mut reg_b = Self::read_register(RTC_REG_B | WITH_NMI_DISABLED); reg_b |= RTC_TIMER_ON; - Self::write_register(RTC_REG_B, reg_b); + Self::write_register(RTC_REG_B | WITH_NMI_DISABLED, reg_b); log_info!("RTC timer enabled at {}Hz", RTC_TIMER_BASE_FREQUENCY); } @@ -239,9 +236,9 @@ impl Rtc { /// Disable RTC timer interrupt pub fn disable_timer(&self) { unsafe { - let mut reg_b = Self::read_register(RTC_REG_B); + let mut reg_b = Self::read_register(RTC_REG_B | WITH_NMI_DISABLED); reg_b &= !RTC_TIMER_ON; - Self::write_register(RTC_REG_B, reg_b); + Self::write_register(RTC_REG_B | WITH_NMI_DISABLED, reg_b); log_info!("RTC timer disabled"); } @@ -322,12 +319,30 @@ pub fn handle_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) +pub fn get_tick_count() -> u64 { + unsafe { RTC_TICK_COUNT } +} + +/// Reset tick count (for testing) +pub fn reset_tick_count() { + unsafe { RTC_TICK_COUNT = 0; } +} \ No newline at end of file diff --git a/kernel/src/kernel/k_main.rs b/kernel/src/kernel/k_main.rs index 2d9f7a0..301e845 100644 --- a/kernel/src/kernel/k_main.rs +++ b/kernel/src/kernel/k_main.rs @@ -54,12 +54,29 @@ pub fn _kernel_main() -> ! { // 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!"); @@ -75,4 +92,58 @@ pub fn _kernel_main() -> ! { loop { cpu::cpu_halt(); } +} + +fn test_rtc_interrupt() { + log_info!("=== RTC Interrupt Test ==="); + + + // Wait and check tick count + log_info!("Waiting for RTC interrupts..."); + + let start_count = rtc::get_tick_count(); + + // Busy wait for ~1 second (approximately) + for _ in 0..1000000 { + cpu::cpu_pause(); + } + + let end_count = rtc::get_tick_count(); + let ticks = end_count - start_count; + + 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"); + } + + // 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(); + } + + 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", + seconds, current_count, delta, delta); + // Also show current time + // if let Some(time) = rtc::get_time() { + // kprintln!(" Time: {}", time.format()); + // } + } + + log_info!("RTC test complete!"); + kprintln!(); } \ No newline at end of file From 53475435d9fda080dcc7860ec41e4626ca82f935 Mon Sep 17 00:00:00 2001 From: ParrotXray Date: Fri, 17 Oct 2025 10:38:24 +0800 Subject: [PATCH 07/13] feat: RTC interrupt passed --- kernel/src/arch/amd64/isr.rs | 10 +- kernel/src/hal/rtc.rs | 189 +++++++++++++++++++---------------- kernel/src/kernel/k_main.rs | 10 +- 3 files changed, 114 insertions(+), 95 deletions(-) diff --git a/kernel/src/arch/amd64/isr.rs b/kernel/src/arch/amd64/isr.rs index 675f5ba..a4fb842 100644 --- a/kernel/src/arch/amd64/isr.rs +++ b/kernel/src/arch/amd64/isr.rs @@ -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(); } \ No newline at end of file diff --git a/kernel/src/hal/rtc.rs b/kernel/src/hal/rtc.rs index 9b6aada..e02a4de 100644 --- a/kernel/src/hal/rtc.rs +++ b/kernel/src/hal/rtc.rs @@ -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> = Mutex::new(None); +static RTC_DEVICE: Mutex> = Mutex::new(None); +static RTC_TIME_CACHE: Mutex> = 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 { - 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 { + 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); } \ No newline at end of file diff --git a/kernel/src/kernel/k_main.rs b/kernel/src/kernel/k_main.rs index 301e845..1486343 100644 --- a/kernel/src/kernel/k_main.rs +++ b/kernel/src/kernel/k_main.rs @@ -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!"); From bb9a89d0b9b7dd5c4ad8670237d4cffe5c2680fc Mon Sep 17 00:00:00 2001 From: ParrotXray Date: Fri, 17 Oct 2025 11:50:09 +0800 Subject: [PATCH 08/13] feat: Initialize APIC Timer --- kernel/src/arch/amd64/idt.rs | 6 +- kernel/src/arch/amd64/isr.rs | 31 ++++- kernel/src/hal/apic_timer.rs | 240 +++++++++++++++++++++++++++++++++++ kernel/src/hal/lapic.rs | 70 +++++++++- kernel/src/hal/mod.rs | 3 +- kernel/src/kernel/k_init.rs | 36 +++++- kernel/src/kernel/k_main.rs | 110 +++------------- 7 files changed, 382 insertions(+), 114 deletions(-) create mode 100644 kernel/src/hal/apic_timer.rs 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 +} From 775626379ec6d752d14b493a11cb4c78038dccc3 Mon Sep 17 00:00:00 2001 From: ParrotXray Date: Fri, 17 Oct 2025 18:20:41 +0800 Subject: [PATCH 09/13] add: Added a new shell and removed a bunch of locks --- kernel/src/arch/amd64/isr.rs | 12 +- kernel/src/drivers/keyboard.rs | 14 +- kernel/src/hal/acpi.rs | 22 +- kernel/src/hal/apic_timer.rs | 240 ------------------- kernel/src/hal/cpu.rs | 28 ++- kernel/src/hal/ioapic.rs | 352 ++++++++++++++-------------- kernel/src/hal/lapic.rs | 320 ++++++++++++------------- kernel/src/hal/mod.rs | 2 +- kernel/src/hal/rtc.rs | 414 ++++++++++++++------------------- kernel/src/hal/timer.rs | 344 +++++++++++++++++++++++++++ kernel/src/kernel/k_init.rs | 10 +- kernel/src/kernel/k_main.rs | 61 +++-- kernel/src/main.rs | 1 + kernel/src/shell/commands.rs | 138 +++++++++++ kernel/src/shell/mod.rs | 59 +++++ 15 files changed, 1132 insertions(+), 885 deletions(-) delete mode 100644 kernel/src/hal/apic_timer.rs create mode 100644 kernel/src/hal/timer.rs create mode 100644 kernel/src/shell/commands.rs create mode 100644 kernel/src/shell/mod.rs diff --git a/kernel/src/arch/amd64/isr.rs b/kernel/src/arch/amd64/isr.rs index f7166a2..f88c027 100644 --- a/kernel/src/arch/amd64/isr.rs +++ b/kernel/src/arch/amd64/isr.rs @@ -4,7 +4,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::{apic_timer, cpu, lapic, rtc}; +use crate::hal::{timer, cpu, lapic, rtc}; use crate::mm::paging; /// Divide Error (#DE) @@ -268,10 +268,10 @@ pub extern "x86-interrupt" fn default_irq_handler(stack_frame: InterruptStackFra 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(); + if timer::is_calibrating() { + timer::apic_calibration_handler(); } else { - apic_timer::timer_tick_handler(); + timer::timer_tick_handler(); } lapic::send_eoi(); @@ -281,8 +281,8 @@ pub extern "x86-interrupt" fn rtc_interrupt_handler(_stack_frame: InterruptStack rtc::handle_interrupt(); // log_info!("Processing of APIC Timer Calibration Phase"); - if apic_timer::is_calibrating() { - apic_timer::rtc_calibration_handler(); + if timer::is_calibrating() { + timer::rtc_calibration_handler(); } lapic::send_eoi(); diff --git a/kernel/src/drivers/keyboard.rs b/kernel/src/drivers/keyboard.rs index 80791fd..4e5e546 100644 --- a/kernel/src/drivers/keyboard.rs +++ b/kernel/src/drivers/keyboard.rs @@ -1,6 +1,6 @@ // kernel/src/drivers/keyboard.rs use spin::Mutex; -use crate::{kprintln, log_debug, log_info}; +use crate::{kprintln, log_debug, log_info, shell, tty}; /// Keyboard scancode to ASCII mapping table (US keyboard layout) static SCANCODE_TO_ASCII: [u8; 128] = [ @@ -192,7 +192,7 @@ pub fn handle_scancode(raw: u8) { match ascii { b'c' | b'C' => { kprintln!("^C"); return; } b'd' | b'D' => { kprintln!("^D"); return; } - b'l' | b'L' => { crate::tty::tty::clear(0x000000); return; } + b'l' | b'L' => { tty::tty::clear(0x000000); return; } _ => {} } } @@ -202,14 +202,12 @@ pub fn handle_scancode(raw: u8) { /// Print a character to the screen fn print_char(c: u8) { - use crate::kprint; - if c == b'\n' { - kprintln!(); - } else if c == 8 { - kprint!("\x08"); + shell::process_keyboard_char('\n'); + } else if c == 8 { // Backspace + shell::process_keyboard_char('\x08'); } else if c.is_ascii_graphic() || c == b' ' { - kprint!("{}", c as char); + shell::process_keyboard_char(c as char); } } diff --git a/kernel/src/hal/acpi.rs b/kernel/src/hal/acpi.rs index 01680eb..815cfcb 100644 --- a/kernel/src/hal/acpi.rs +++ b/kernel/src/hal/acpi.rs @@ -6,6 +6,7 @@ use core::ptr::NonNull; use core::mem; use crate::kprintln; use crate::{log_trace, log_debug, log_info, log_warn, log_error, log_fatal}; +use crate::hal::{cpu, io}; #[derive(Clone, Copy)] pub struct CureAcpiHandler { @@ -36,7 +37,7 @@ impl Handler for CureAcpiHandler { physical_address: usize, size: usize, ) -> PhysicalMapping { - // Bootloader 已經映射了所有物理記憶體 + // Bootloader has mapped all physical memory let virtual_address = physical_address as u64 + self.physical_memory_offset; let virtual_start = NonNull::new((virtual_address) as *mut T).unwrap(); @@ -110,27 +111,27 @@ impl Handler for CureAcpiHandler { } fn read_io_u8(&self, port: u16) -> u8 { - unsafe { crate::hal::io::io_port_rb(port) } + unsafe { io::io_port_rb(port) } } fn read_io_u16(&self, port: u16) -> u16 { - unsafe { crate::hal::io::io_port_rw(port) } + unsafe { io::io_port_rw(port) } } fn read_io_u32(&self, port: u16) -> u32 { - unsafe { crate::hal::io::io_port_rl(port) } + unsafe { io::io_port_rl(port) } } fn write_io_u8(&self, port: u16, value: u8) { - unsafe { crate::hal::io::io_port_wb(port, value) }; + unsafe { io::io_port_wb(port, value) }; } fn write_io_u16(&self, port: u16, value: u16) { - unsafe { crate::hal::io::io_port_ww(port, value) }; + unsafe { io::io_port_ww(port, value) }; } fn write_io_u32(&self, port: u16, value: u32) { - unsafe { crate::hal::io::io_port_wl(port, value) }; + unsafe { io::io_port_wl(port, value) }; } fn read_pci_u8(&self, address: PciAddress, offset: u16) -> u8 { @@ -169,9 +170,8 @@ impl Handler for CureAcpiHandler { fn stall(&self, _microseconds: u64) { // TODO: 實作微秒級延遲 // 簡單的忙等待實作 - for _ in 0..(_microseconds * 1000) { - crate::hal::cpu::cpu_pause(); - } + cpu::cpu_pause(_microseconds * 1000); + } fn sleep(&self, _milliseconds: u64) { @@ -240,7 +240,7 @@ pub fn init(rsdp_addr: u64, physical_memory_offset: u64) -> Option { (None, 0) }; - // 檢查中斷模型 + // Check interrupt mode let (has_apic, local_apic_addr, io_apics_info) = match &platform.interrupt_model { InterruptModel::Apic(apic) => { log_info!("Local APIC Address: {:#x}", apic.local_apic_address); diff --git a/kernel/src/hal/apic_timer.rs b/kernel/src/hal/apic_timer.rs deleted file mode 100644 index eb2639c..0000000 --- a/kernel/src/hal/apic_timer.rs +++ /dev/null @@ -1,240 +0,0 @@ -// 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/cpu.rs b/kernel/src/hal/cpu.rs index 9218ddb..e804551 100644 --- a/kernel/src/hal/cpu.rs +++ b/kernel/src/hal/cpu.rs @@ -3,8 +3,7 @@ use x86_64::registers::control::{Cr0, Cr0Flags, Cr2, Cr3, Cr4, Cr4Flags}; use x86_64::instructions::{interrupts, hlt}; use core::arch::asm; use raw_cpuid::CpuId; -use x86_64::{PhysAddr, structures::paging::PhysFrame}; -use x86_64::VirtAddr; +use x86_64::{PhysAddr, structures::paging::PhysFrame, registers}; /// 64-bit register type #[allow(dead_code)] @@ -197,15 +196,15 @@ pub fn cpu_get_brand(brand_out: &mut [u8]) -> &str { /// The timestamp count value #[allow(dead_code)] #[inline] -pub fn cpu_rdtsc() -> u64 { +pub fn cpu_rdtscp() -> u64 { unsafe { let low: u32; let high: u32; asm!( - "rdtsc", + "rdtscp", out("eax") low, out("edx") high, - options(nomem, nostack, preserves_flags) + options(nomem, nostack, preserves_flags, att_syntax) ); ((high as u64) << 32) | (low as u64) } @@ -214,8 +213,19 @@ pub fn cpu_rdtsc() -> u64 { /// Execute CPU pause instruction (reduce power consumption) #[allow(dead_code)] #[inline] -pub fn cpu_pause() { - core::hint::spin_loop(); +pub fn cpu_pause(ms: u64) { + if ms == 0 { + core::hint::spin_loop(); + return; + } + + let start = cpu_rdtscp(); + let target = start + ms * 1000; + + while cpu_rdtscp() < target { + core::hint::spin_loop(); + } + } /// Stop CPU execution until the next interrupt occurs @@ -276,12 +286,12 @@ where #[allow(dead_code)] #[inline] pub fn cpu_breakpoint() { - x86_64::instructions::interrupts::int3(); + interrupts::int3(); } /// Read the RFLAGS register #[allow(dead_code)] #[inline] pub fn cpu_read_flags() -> u64 { - x86_64::registers::rflags::read().bits() + registers::rflags::read().bits() } \ No newline at end of file diff --git a/kernel/src/hal/ioapic.rs b/kernel/src/hal/ioapic.rs index e679bab..8c50d8a 100644 --- a/kernel/src/hal/ioapic.rs +++ b/kernel/src/hal/ioapic.rs @@ -1,9 +1,7 @@ -// kernel/src/hal/ioapic.rs -use x86_64::{PhysAddr, VirtAddr}; -use spin::Mutex; -use alloc::vec::Vec; +// kernel/src/hal/ioapic.rs - 無鎖設計 + +use x86_64::VirtAddr; use crate::{log_trace, log_debug, log_info, log_warn, log_error}; -use crate::mm::vma; /// IO APIC register selector const IOREGSEL: u32 = 0x00; @@ -32,40 +30,25 @@ mod redir_flags { pub const DELIVERY_LOWEST: u64 = 1 << 8; } -pub struct IoApic { +// Supports up to 8 IO APICs +const MAX_IOAPICS: usize = 8; + +//IO APIC information array (read-only after initialization) +static mut IO_APICS: [Option; MAX_IOAPICS] = [None; MAX_IOAPICS]; +static mut IO_APIC_COUNT: usize = 0; + +#[derive(Debug, Clone, Copy)] +struct IoApicInfo { base_vaddr: VirtAddr, id: u8, gsi_base: u32, max_redirection_entries: u8, } -static IO_APICS: Mutex> = Mutex::new(Vec::new()); - -impl IoApic { - /// Create IO APIC from physical address - pub unsafe fn new(base_paddr: PhysAddr, id: u8, gsi_base: u32) -> Self { - let base_vaddr = vma::phys_to_virt(base_paddr.as_u64()); - - log_debug!("IO APIC {} physical base: {:#x}", id, base_paddr.as_u64()); - log_debug!("IO APIC {} virtual base: {:#x}", id, base_vaddr.as_u64()); - log_debug!("IO APIC {} GSI base: {}", id, gsi_base); - - let mut ioapic = Self { - base_vaddr, - id, - gsi_base, - max_redirection_entries: 0, - }; - - // Read version information to get the maximum number of redirect entries - let version = ioapic.read(reg::VER); - ioapic.max_redirection_entries = ((version >> 16) & 0xFF) as u8 + 1; - - ioapic - } - - /// Read IO APIC registers - unsafe fn read(&mut self, reg: u8) -> u32 { +impl IoApicInfo { + /// Read IO APIC register + #[inline] + unsafe fn read(&self, reg: u8) -> u32 { let regsel_addr = self.base_vaddr.as_u64() + IOREGSEL as u64; let win_addr = self.base_vaddr.as_u64() + IOWIN as u64; @@ -73,8 +56,9 @@ impl IoApic { core::ptr::read_volatile(win_addr as *const u32) } - /// Writing to IO APIC registers - unsafe fn write(&mut self, reg: u8, value: u32) { + /// Write to IO APIC register + #[inline] + unsafe fn write(&self, reg: u8, value: u32) { let regsel_addr = self.base_vaddr.as_u64() + IOREGSEL as u64; let win_addr = self.base_vaddr.as_u64() + IOWIN as u64; @@ -82,8 +66,9 @@ impl IoApic { core::ptr::write_volatile(win_addr as *mut u32, value); } - /// Read redirection table entries - unsafe fn read_redirection_entry(&mut self, irq: u8) -> u64 { + /// Read the redirection table entry + #[inline] + unsafe fn read_redirection_entry(&self, irq: u8) -> u64 { if irq >= self.max_redirection_entries { log_warn!("IRQ {} out of range for IO APIC {}", irq, self.id); return 0; @@ -99,7 +84,8 @@ impl IoApic { } /// Write redirection table entry - unsafe fn write_redirection_entry(&mut self, irq: u8, entry: u64) { + #[inline] + unsafe fn write_redirection_entry(&self, irq: u8, entry: u64) { if irq >= self.max_redirection_entries { log_warn!("IRQ {} out of range for IO APIC {}", irq, self.id); return; @@ -114,137 +100,76 @@ impl IoApic { self.write(high_reg, high); self.write(low_reg, low); } - - /// Initialize the IO APIC - pub unsafe fn init(&mut self) { - // Mask all interrupts - for irq in 0..self.max_redirection_entries { - let entry = redir_flags::MASKED; - self.write_redirection_entry(irq, entry); - } - - log_info!("IO APIC {} initialized, {} entries", self.id, self.max_redirection_entries); - } - - /// Configure IRQ redirection - /// - /// # Parameters - /// - `irq`: IRQ number (0-23) - /// - `vector`: Interrupt vector number (32-255) - /// - `dest_apic_id`: Destination Local APIC ID - /// - `level_triggered`: true = level triggered, false = edge triggered - /// - `active_low`: true = active low, false = active high - pub unsafe fn set_irq_redirect( - &mut self, - irq: u8, - vector: u8, - dest_apic_id: u8, - level_triggered: bool, - active_low: bool, - ) { - let mut entry: u64 = 0; - - // Set target APIC ID (bits 56-63) - entry |= (dest_apic_id as u64) << 56; - - // Set the trigger mode - if level_triggered { - entry |= redir_flags::TRIGGER_LEVEL; - } - - // Setting Polarity - if active_low { - entry |= redir_flags::POLARITY_LOW; - } - - // Set the delivery mode to Fixed - entry |= redir_flags::DELIVERY_FIXED; - - // Set the target mode to Physical - entry |= redir_flags::DEST_PHYSICAL; - - // Set vector number - entry |= vector as u64; - - // Write redirection table (unmask) - self.write_redirection_entry(irq, entry); - - log_info!( - "IO APIC {} IRQ {} -> Vector {} (APIC {}, {}, {})", - self.id, - irq, - vector, - dest_apic_id, - if level_triggered { "level" } else { "edge" }, - if active_low { "low" } else { "high" } - ); - } - - /// masked IRQ - pub unsafe fn mask_irq(&mut self, irq: u8) { - let mut entry = self.read_redirection_entry(irq); - entry |= redir_flags::MASKED; - self.write_redirection_entry(irq, entry); - - log_debug!("IO APIC {} IRQ {} masked", self.id, irq); - } - - /// unmasked IRQ - pub unsafe fn unmask_irq(&mut self, irq: u8) { - let mut entry = self.read_redirection_entry(irq); - entry &= !redir_flags::MASKED; - self.write_redirection_entry(irq, entry); - - log_debug!("IO APIC {} IRQ {} unmasked", self.id, irq); - } - - /// Print IO APIC information - pub unsafe fn print_info(&mut self) { - let id = self.read(reg::ID) >> 24; - let version = self.read(reg::VER); - let apic_ver = version & 0xFF; - - log_info!("IO APIC {} ID: {}", self.id, id); - log_info!("IO APIC {} Version: {:#x}", self.id, apic_ver); - log_info!("IO APIC {} Max Redirection Entries: {}", self.id, self.max_redirection_entries); - log_info!("IO APIC {} GSI Base: {}", self.id, self.gsi_base); - } } -/// Initialize a single IO APIC (using mapped virtual address) +/// Initialize a single IO APIC (using mapped virtual addresses) +/// +/// # Safety +/// Must be called after mapping the IO APIC memory. pub unsafe fn init_single_ioapic(base_vaddr: VirtAddr, id: u8, gsi_base: u32) { - let mut ioapic = IoApic { + if IO_APIC_COUNT >= MAX_IOAPICS { + log_error!("Too many IO APICs! Maximum {} supported", MAX_IOAPICS); + return; + } + + log_debug!("Initializing IO APIC {} at {:#x}", id, base_vaddr.as_u64()); + + // Create a temporary structure to read the version information + let temp_info = IoApicInfo { base_vaddr, id, gsi_base, max_redirection_entries: 0, }; - // Read version information to get the maximum number of redirect entries - let version = ioapic.read(reg::VER); - ioapic.max_redirection_entries = ((version >> 16) & 0xFF) as u8 + 1; + // Read version information to get the maximum number of entries + let version = temp_info.read(reg::VER); + let max_entries = ((version >> 16) & 0xFF) as u8 + 1; - ioapic.init(); - ioapic.print_info(); + // 創建完整的信息結構 + let info = IoApicInfo { + base_vaddr, + id, + gsi_base, + max_redirection_entries: max_entries, + }; - IO_APICS.lock().push(ioapic); + // Mask all interrupts + for irq in 0..max_entries { + info.write_redirection_entry(irq, redir_flags::MASKED); + } + + // Store to global array + IO_APICS[IO_APIC_COUNT] = Some(info); + IO_APIC_COUNT += 1; + + log_info!("IO APIC {} initialized, {} entries", id, max_entries); + print_single_ioapic_info(&info); } -/// Initialize all IO APICs (from physical address, need to be mapped first) -pub unsafe fn init_io_apics(io_apics: &[(PhysAddr, u8, u32)]) { - let mut apics = IO_APICS.lock(); +/// Initialize all IO APICs (from physical addresses) +/// +/// # Safety +/// The physical addresses must be correctly mapped. +pub unsafe fn init_io_apics(io_apics: &[(x86_64::PhysAddr, u8, u32)]) { + log_info!("Initializing {} IO APIC(s)...", io_apics.len()); for (paddr, id, gsi_base) in io_apics { - let mut ioapic = IoApic::new(*paddr, *id, *gsi_base); - ioapic.init(); - ioapic.print_info(); - apics.push(ioapic); + let vaddr = crate::mm::vma::phys_to_virt(paddr.as_u64()); + init_single_ioapic(vaddr, *id, *gsi_base); } log_info!("All IO APICs initialized"); } -/// Configuring IRQ Redirection +/// Configure IRQ redirection +/// +/// # Parameters +/// - `irq`: IRQ number (0-23) +/// - `vector`: Interrupt vector number (32-255) +/// - `dest_apic_id`: Destination Local APIC ID +/// - `level_triggered`: true = level triggered, false = edge triggered +/// - `active_low`: true = active low, false = active high pub fn set_irq_redirect( irq: u8, vector: u8, @@ -253,17 +178,55 @@ pub fn set_irq_redirect( active_low: bool, ) { unsafe { - let mut apics = IO_APICS.lock(); - // Find the IO APIC responsible for this IRQ - for ioapic in apics.iter_mut() { - let gsi_start = ioapic.gsi_base as u8; - let gsi_end = gsi_start + ioapic.max_redirection_entries; + for i in 0..IO_APIC_COUNT { + if let Some(ioapic) = &IO_APICS[i] { + let gsi_start = ioapic.gsi_base as u8; + let gsi_end = gsi_start + ioapic.max_redirection_entries; - if irq >= gsi_start && irq < gsi_end { - let local_irq = irq - gsi_start; - ioapic.set_irq_redirect(local_irq, vector, dest_apic_id, level_triggered, active_low); - return; + if irq >= gsi_start && irq < gsi_end { + let local_irq = irq - gsi_start; + + // Build redirection entry + let mut entry: u64 = 0; + + // Set target APIC ID (bits 56-63) + entry |= (dest_apic_id as u64) << 56; + + // Set the trigger mode + if level_triggered { + entry |= redir_flags::TRIGGER_LEVEL; + } + + // Set polarity + if active_low { + entry |= redir_flags::POLARITY_LOW; + } + + // Set the transfer mode to Fixed + entry |= redir_flags::DELIVERY_FIXED; + + // Set the target mode to Physical + entry |= redir_flags::DEST_PHYSICAL; + + // Set the vector number + entry |= vector as u64; + + // Write to the redirection table (unmask) + ioapic.write_redirection_entry(local_irq, entry); + + log_info!( + "IO APIC {} IRQ {} -> Vector {} (APIC {}, {}, {})", + ioapic.id, + irq, + vector, + dest_apic_id, + if level_triggered { "level" } else { "edge" }, + if active_low { "low" } else { "high" } + ); + + return; + } } } @@ -271,18 +234,23 @@ pub fn set_irq_redirect( } } -/// Block IRQ +/// Mask IRQ pub fn mask_irq(irq: u8) { unsafe { - let mut apics = IO_APICS.lock(); - for ioapic in apics.iter_mut() { - let gsi_start = ioapic.gsi_base as u8; - let gsi_end = gsi_start + ioapic.max_redirection_entries; + for i in 0..IO_APIC_COUNT { + if let Some(ioapic) = &IO_APICS[i] { + let gsi_start = ioapic.gsi_base as u8; + let gsi_end = gsi_start + ioapic.max_redirection_entries; - if irq >= gsi_start && irq < gsi_end { - let local_irq = irq - gsi_start; - ioapic.mask_irq(local_irq); - return; + if irq >= gsi_start && irq < gsi_end { + let local_irq = irq - gsi_start; + let mut entry = ioapic.read_redirection_entry(local_irq); + entry |= redir_flags::MASKED; + ioapic.write_redirection_entry(local_irq, entry); + + log_debug!("IO APIC {} IRQ {} masked", ioapic.id, irq); + return; + } } } } @@ -291,15 +259,49 @@ pub fn mask_irq(irq: u8) { /// Unmask IRQ pub fn unmask_irq(irq: u8) { unsafe { - let mut apics = IO_APICS.lock(); - for ioapic in apics.iter_mut() { - let gsi_start = ioapic.gsi_base as u8; - let gsi_end = gsi_start + ioapic.max_redirection_entries; + for i in 0..IO_APIC_COUNT { + if let Some(ioapic) = &IO_APICS[i] { + let gsi_start = ioapic.gsi_base as u8; + let gsi_end = gsi_start + ioapic.max_redirection_entries; - if irq >= gsi_start && irq < gsi_end { - let local_irq = irq - gsi_start; - ioapic.unmask_irq(local_irq); - return; + if irq >= gsi_start && irq < gsi_end { + let local_irq = irq - gsi_start; + let mut entry = ioapic.read_redirection_entry(local_irq); + entry &= !redir_flags::MASKED; + ioapic.write_redirection_entry(local_irq, entry); + + log_debug!("IO APIC {} IRQ {} unmasked", ioapic.id, irq); + return; + } + } + } + } +} + +/// Print single IO APIC information +fn print_single_ioapic_info(info: &IoApicInfo) { + unsafe { + let id = info.read(reg::ID) >> 24; + let version = info.read(reg::VER); + let apic_ver = version & 0xFF; + + log_info!("ID: {}", id); + log_info!("Version: {:#x}", apic_ver); + log_info!("Max Entries: {}", info.max_redirection_entries); + log_info!("GSI Base: {}", info.gsi_base); + } +} + +/// Print all IO APIC information +pub fn print_info() { + unsafe { + log_info!("=== IO APIC Information ==="); + log_info!("Total IO APICs: {}", IO_APIC_COUNT); + + for i in 0..IO_APIC_COUNT { + if let Some(info) = &IO_APICS[i] { + log_info!("IO APIC {}:", i); + print_single_ioapic_info(info); } } } diff --git a/kernel/src/hal/lapic.rs b/kernel/src/hal/lapic.rs index 4f4b360..024e3df 100644 --- a/kernel/src/hal/lapic.rs +++ b/kernel/src/hal/lapic.rs @@ -1,8 +1,8 @@ -// kernel/src/hal/lapic.rs - 添加公開 API +// kernel/src/hal/lapic.rs -use x86_64::{PhysAddr, VirtAddr}; -use spin::Mutex; +use x86_64::VirtAddr; use crate::{log_trace, log_debug, log_info, log_warn, log_error}; +use crate::hal::io; use crate::mm::vma; /// Local APIC register offset @@ -42,207 +42,215 @@ pub mod flags { pub const LVT_TIMER_ONESHOT: u32 = 0 << 17; } -pub struct LocalApic { - base_vaddr: VirtAddr, +// Local APIC base address (read-only after initialization) +static mut LOCAL_APIC_BASE: Option = None; + +// APIC information (read-only after initialization) +static mut APIC_INFO: ApicInfo = ApicInfo::new(); + +struct ApicInfo { + id: u32, + version: u32, + max_lvt: u32, } -static LOCAL_APIC: Mutex> = Mutex::new(None); - -impl LocalApic { - /// Create Local APIC from physical address - pub unsafe fn new(base_paddr: PhysAddr) -> Self { - let base_vaddr = vma::phys_to_virt(base_paddr.as_u64()); - - log_debug!("Local APIC physical base: {:#x}", base_paddr.as_u64()); - log_debug!("Local APIC virtual base: {:#x}", base_vaddr.as_u64()); - - Self { base_vaddr } +impl ApicInfo { + const fn new() -> Self { + Self { + id: 0, + version: 0, + max_lvt: 0, + } } - - /// Read APIC registers - pub unsafe fn read(&self, reg: ApicRegister) -> u32 { - let addr = self.base_vaddr.as_u64() + reg as u64; +} +/// Read APIC registers +/// +/// # Safety +/// The caller must ensure the APIC is initialized. +#[inline] +pub unsafe fn read_apic_reg(reg: ApicRegister) -> Option { + LOCAL_APIC_BASE.map(|base| { + let addr = base.as_u64() + reg as u64; core::ptr::read_volatile(addr as *const u32) - } + }) +} - /// Write to APIC register - pub unsafe fn write(&mut self, reg: ApicRegister, value: u32) { - let addr = self.base_vaddr.as_u64() + reg as u64; +/// Write to APIC registers +/// +/// # Safety +/// The caller must ensure the APIC is initialized. +#[inline] +pub unsafe fn write_apic_reg(reg: ApicRegister, value: u32) -> bool { + if let Some(base) = LOCAL_APIC_BASE { + let addr = base.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; - self.write(ApicRegister::SpuriousInterruptVector, spurious); - - // Set task priority to 0 (accept all interrupts) - self.write(ApicRegister::TaskPriority, 0); - - // Configure LVT entries - mask all local interrupts by default - self.write(ApicRegister::LvtTimer, flags::LVT_MASKED); - self.write(ApicRegister::LvtLint0, flags::LVT_MASKED); - self.write(ApicRegister::LvtLint1, flags::LVT_MASKED); - self.write(ApicRegister::LvtError, flags::LVT_MASKED); - self.write(ApicRegister::LvtPerformanceCounter, flags::LVT_MASKED); - self.write(ApicRegister::LvtThermalSensor, flags::LVT_MASKED); - - log_info!("Local APIC initialized"); - } - - /// Obtaining the APIC ID - pub unsafe fn id(&self) -> u32 { - self.read(ApicRegister::Id) >> 24 - } - - /// Get the APIC version - pub unsafe fn version(&self) -> u32 { - self.read(ApicRegister::Version) - } - - /// Send EOI (End of Interrupt) - pub unsafe fn send_eoi(&mut self) { - self.write(ApicRegister::Eoi, 0); - } - - /// Configuring Timers - pub unsafe fn setup_timer(&mut self, vector: u8, divide_config: u32, initial_count: u32) { - // Setting the crossover - self.write(ApicRegister::TimerDivideConfig, divide_config); - - // Setting the LVT Timer (periodic mode) - let lvt = flags::LVT_TIMER_PERIODIC | (vector as u32); - self.write(ApicRegister::LvtTimer, lvt); - - // Set the initial count - self.write(ApicRegister::TimerInitialCount, initial_count); - - log_info!("Local APIC timer configured: vector={}, count={}", vector, initial_count); - } - - pub unsafe fn print_info(&self) { - let id = self.id(); - let version = self.version(); - let max_lvt = (version >> 16) & 0xFF; - let apic_version = version & 0xFF; - - log_info!("Local APIC ID: {}", id); - log_info!("Local APIC Version: {:#x}", apic_version); - log_info!("Max LVT Entry: {}", max_lvt); + true + } else { + false } } -/// Initialize Local APIC (using mapped virtual address) -pub unsafe fn init_local_apic_with_vaddr(base_vaddr: VirtAddr) { - let mut apic = LocalApic { base_vaddr }; - apic.init(); - apic.print_info(); +/// Directly read the APIC register using an offset (for apic_timer) +/// +/// # Safety +/// The caller must ensure the APIC is initialized and the offset is valid. +#[inline] +pub unsafe fn read_apic_reg_raw(offset: u32) -> Option { + LOCAL_APIC_BASE.map(|base| { + let addr = base.as_u64() + offset as u64; + core::ptr::read_volatile(addr as *const u32) + }) +} - *LOCAL_APIC.lock() = Some(apic); +/// Directly read the APIC register using an offset (for apic_timer) +/// +/// # Safety +/// The caller must ensure the APIC is initialized and the offset is valid. +#[inline] +pub unsafe fn write_apic_reg_raw(offset: u32, value: u32) -> bool { + if let Some(base) = LOCAL_APIC_BASE { + let addr = base.as_u64() + offset as u64; + core::ptr::write_volatile(addr as *mut u32, value); + true + } else { + false + } +} + +/// Initialize the Local APIC (using mapped virtual addresses) +/// +/// # Safety +/// Must be called after paging is initialized and APIC memory is mapped. +pub unsafe fn init_local_apic_with_vaddr(base_vaddr: VirtAddr) { + log_debug!("Initializing Local APIC at {:#x}", base_vaddr.as_u64()); + + // 儲存基地址 + LOCAL_APIC_BASE = Some(base_vaddr); + + // 讀取 APIC 信息 + let id_reg = read_apic_reg(ApicRegister::Id).unwrap(); + let version_reg = read_apic_reg(ApicRegister::Version).unwrap(); + + APIC_INFO = ApicInfo { + id: id_reg >> 24, + version: version_reg & 0xFF, + max_lvt: (version_reg >> 16) & 0xFF, + }; + + // Enable APIC (via Spurious Interrupt Vector Register) + let spurious = flags::APIC_SW_ENABLE | 0xFF; + write_apic_reg(ApicRegister::SpuriousInterruptVector, spurious); + + // Set task priority to 0 (accept all interrupts) + write_apic_reg(ApicRegister::TaskPriority, 0); + + // Configure LVT entries - default to full mask + write_apic_reg(ApicRegister::LvtTimer, flags::LVT_MASKED); + write_apic_reg(ApicRegister::LvtLint0, flags::LVT_MASKED); + write_apic_reg(ApicRegister::LvtLint1, flags::LVT_MASKED); + write_apic_reg(ApicRegister::LvtError, flags::LVT_MASKED); + write_apic_reg(ApicRegister::LvtPerformanceCounter, flags::LVT_MASKED); + write_apic_reg(ApicRegister::LvtThermalSensor, flags::LVT_MASKED); + + log_info!("Local APIC initialized"); + print_info(); } /// Initialize Local APIC (from physical address, needs to be mapped first) -pub unsafe fn init_local_apic(base_paddr: PhysAddr) { +/// +/// # Safety +/// The physical address must be a valid APIC base address. +pub unsafe fn init_local_apic(base_paddr: x86_64::PhysAddr) { let base_vaddr = vma::phys_to_virt(base_paddr.as_u64()); init_local_apic_with_vaddr(base_vaddr); } -/// Send EOI +/// Send EOI (End of Interrupt) +/// +/// This is the most frequently called function and must be extremely fast. +#[inline] pub fn send_eoi() { unsafe { - if let Some(apic) = LOCAL_APIC.lock().as_mut() { - apic.send_eoi(); + if let Some(base) = LOCAL_APIC_BASE { + let addr = base.as_u64() + ApicRegister::Eoi as u64; + core::ptr::write_volatile(addr as *mut u32, 0); } } } /// Get the Local APIC ID +#[inline] pub fn get_apic_id() -> Option { unsafe { - LOCAL_APIC.lock().as_ref().map(|apic| apic.id()) + Some(APIC_INFO.id) } } /// Get the Local APIC base virtual address +#[inline] pub fn get_base_vaddr() -> Option { - LOCAL_APIC.lock().as_ref().map(|apic| apic.base_vaddr()) + unsafe { LOCAL_APIC_BASE } } -/// 公開的 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 +/// Get APIC version +#[inline] +pub fn get_version() -> Option { + unsafe { + if LOCAL_APIC_BASE.is_some() { + Some(APIC_INFO.version) + } else { + None + } } } -/// 直接通過偏移量讀取 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 +/// Get the maximum number of LVT entries +#[inline] +pub fn get_max_lvt() -> Option { + unsafe { + if LOCAL_APIC_BASE.is_some() { + Some(APIC_INFO.max_lvt) + } else { + None + } } } /// Disable legacy 8259 PIC -/// This function should be called before using the APIC to avoid conflicts. +/// +/// Must be called before using the APIC to avoid conflicts pub fn disable_legacy_pic() { - use crate::hal::io::io_port_wb; unsafe { - // Remap PIC to unused interrupt vector // Master PIC - io_port_wb(0x20, 0x11); // ICW1: initialization - io_port_wb(0x21, 0x20); // ICW2: Interrupt vector offset (32-39) - io_port_wb(0x21, 0x04); // ICW3: Tell the Master PIC Slave to be on IRQ2 - io_port_wb(0x21, 0x01); // ICW4: 8086 mode + io::io_port_wb(0x20, 0x11); // ICW1: initialization + io::io_port_wb(0x21, 0x20); // ICW2: Interrupt vector offset (32-39) + io::io_port_wb(0x21, 0x04); // ICW3: Tell the Master PIC Slave to be on IRQ2 + io::io_port_wb(0x21, 0x01); // ICW4: 8086 mode // Slave PIC - io_port_wb(0xA0, 0x11); // ICW1: initialization - io_port_wb(0xA1, 0x28); // ICW2: Interrupt vector offset (40-47) - io_port_wb(0xA1, 0x02); // ICW3: Tell the Slave PIC to connect to Master IRQ2 - io_port_wb(0xA1, 0x01); // ICW4: 8086 mode + io::io_port_wb(0xA0, 0x11); // ICW1: initialization + io::io_port_wb(0xA1, 0x28); // ICW2: Interrupt vector offset (40-47) + io::io_port_wb(0xA1, 0x02); // ICW3: Tell the Slave PIC to connect to Master IRQ2 + io::io_port_wb(0xA1, 0x01); // ICW4: 8086 mode - // Block all IRQs (disable PIC) - io_port_wb(0x21, 0xFF); - io_port_wb(0xA1, 0xFF); + // Mask all IRQs (disable PIC) + io::io_port_wb(0x21, 0xFF); + io::io_port_wb(0xA1, 0xFF); } log_info!("Legacy 8259 PIC disabled"); +} + +/// Print APIC information +pub fn print_info() { + unsafe { + if LOCAL_APIC_BASE.is_some() { + log_info!("Local APIC ID: {}", APIC_INFO.id); + log_info!("Local APIC Version: {:#x}", APIC_INFO.version); + log_info!("Max LVT Entry: {}", APIC_INFO.max_lvt); + } else { + log_warn!("Local APIC not initialized"); + } + } } \ No newline at end of file diff --git a/kernel/src/hal/mod.rs b/kernel/src/hal/mod.rs index 7ece7c9..0ed70e9 100644 --- a/kernel/src/hal/mod.rs +++ b/kernel/src/hal/mod.rs @@ -4,4 +4,4 @@ pub mod acpi; pub mod rtc; pub mod lapic; pub mod ioapic; -pub mod apic_timer; \ No newline at end of file +pub mod timer; \ No newline at end of file diff --git a/kernel/src/hal/rtc.rs b/kernel/src/hal/rtc.rs index e02a4de..a33aa75 100644 --- a/kernel/src/hal/rtc.rs +++ b/kernel/src/hal/rtc.rs @@ -1,7 +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; const RTC_INDEX_PORT: u16 = 0x70; @@ -11,7 +10,7 @@ const WITH_NMI_DISABLED: u8 = 0x80; const RTC_REG_SEC: u8 = 0x00; const RTC_REG_MIN: u8 = 0x02; const RTC_REG_HRS: u8 = 0x04; -const RTC_REG_WDY: u8 = 0x06; // Weekday +const RTC_REG_WDY: u8 = 0x06; const RTC_REG_DAY: u8 = 0x07; const RTC_REG_MTH: u8 = 0x08; const RTC_REG_YRS: u8 = 0x09; @@ -19,16 +18,14 @@ const RTC_REG_YRS: u8 = 0x09; const RTC_REG_A: u8 = 0x0A; const RTC_REG_B: u8 = 0x0B; const RTC_REG_C: u8 = 0x0C; -const RTC_REG_D: u8 = 0x0D; -const RTC_UPDATE_IN_PROGRESS: u8 = 0x80; // Status Register A bit 7 -const RTC_BIN_ENCODED_BIT: u8 = 0x04; // Status Register B bit 2 -const RTC_24HRS_ENCODED_BIT: u8 = 0x02; // Status Register B bit 1 +const RTC_UPDATE_IN_PROGRESS: u8 = 0x80; +const RTC_BIN_ENCODED_BIT: u8 = 0x04; +const RTC_24HRS_ENCODED_BIT: u8 = 0x02; -const RTC_TIMER_ON: u8 = 0x40; // Enable periodic interrupt (bit 6) -const RTC_FREQUENCY_1024HZ: u8 = 0b110; // Rate selector for 1024Hz -const RTC_DIVIDER_33KHZ: u8 = 0b010 << 4; // 32.768kHz crystal divider -const RTC_TIMER_BASE_FREQUENCY: u32 = 1024; +const RTC_TIMER_ON: u8 = 0x40; +const RTC_FREQUENCY_1024HZ: u8 = 0b110; +const RTC_DIVIDER_33KHZ: u8 = 0b010 << 4; const RTC_CURRENT_CENTURY: u16 = 2000; @@ -84,284 +81,219 @@ impl DateTime { } } -pub struct Rtc { +// RTC Configuration +static mut RTC_CONFIG: RtcConfig = RtcConfig::new(); + +// Tick Counter +static RTC_TICK_COUNT: AtomicU64 = AtomicU64::new(0); + +struct RtcConfig { binary_mode: bool, hour_24_mode: bool, } -impl Rtc { - pub fn new() -> Self { +impl RtcConfig { + const fn new() -> Self { Self { binary_mode: false, hour_24_mode: false, } } +} - /// 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) - } +/// Read CMOS register +#[inline] +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) - 公開的靜態方法 - 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); - } +/// Write to CMOS register +#[inline] +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); +} - /// Check if RTC is updating - unsafe fn is_updating() -> bool { - (Self::read_register(RTC_REG_A) & RTC_UPDATE_IN_PROGRESS) != 0 - } +/// Check if RTC is updating +#[inline] +unsafe fn is_updating() -> bool { + (read_register(RTC_REG_A) & RTC_UPDATE_IN_PROGRESS) != 0 +} - /// 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 - fn bcd_to_binary(bcd: u8) -> u8 { - (bcd & 0x0F) + ((bcd >> 4) * 10) - } - - pub fn init(&mut self) { - unsafe { - let status_b = Self::read_register(RTC_REG_B | WITH_NMI_DISABLED); - self.binary_mode = (status_b & RTC_BIN_ENCODED_BIT) != 0; - self.hour_24_mode = (status_b & RTC_24HRS_ENCODED_BIT) != 0; - - 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); - - Self::read_register(RTC_REG_C); - - self.disable_timer(); - - Self::read_register(RTC_REG_C); - } - } - - /// 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); - let day = Self::read_register(RTC_REG_DAY); - let month = Self::read_register(RTC_REG_MTH); - let year = Self::read_register(RTC_REG_YRS); - let weekday = Self::read_register(RTC_REG_WDY); - - (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 { - value - } else { - Self::bcd_to_binary(value) - } - } - - /// 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_no_wait(); - - // Convert from BCD to binary when needed - second = self.convert_value(second); - minute = self.convert_value(minute); - day = self.convert_value(day); - month = self.convert_value(month); - year = self.convert_value(year); - - // Handle 12-hour format - let pm_bit = hour & 0x80; - hour = self.convert_value(hour & 0x7F); - - if !self.hour_24_mode && pm_bit != 0 { - hour = (hour + 12) % 24; - } - - let full_year = RTC_CURRENT_CENTURY + year as u16; - - DateTime { - year: full_year, - month, - day, - weekday, - hour, - minute, - second, - } - } - } - - /// Read time with retry (for initialization) - pub fn read_time_stable(&self) -> DateTime { - 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; - } - } - } - } - - /// 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); - } - } - - /// Disable RTC timer interrupt - pub fn disable_timer(&self) { - unsafe { - 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); - - Self::read_register(RTC_REG_C); - } +/// Wait for RTC update to complete +unsafe fn wait_for_update() { + while is_updating() { + core::hint::spin_loop(); } } -static RTC_DEVICE: Mutex> = Mutex::new(None); +/// Convert BCD to binary +#[inline] +fn bcd_to_binary(bcd: u8) -> u8 { + (bcd & 0x0F) + ((bcd >> 4) * 10) +} -static RTC_TIME_CACHE: Mutex> = Mutex::new(None); - -static RTC_TICK_COUNT: AtomicU64 = AtomicU64::new(0); - -/// Initialize RTC pub fn init() { - let mut rtc = Rtc::new(); - rtc.init(); + unsafe { + // Read configuration + let status_b = read_register(RTC_REG_B); + RTC_CONFIG.binary_mode = (status_b & RTC_BIN_ENCODED_BIT) != 0; + RTC_CONFIG.hour_24_mode = (status_b & RTC_24HRS_ENCODED_BIT) != 0; - let initial_time = rtc.read_time_stable(); + // Configuring frequencies and dividers + let mut reg_a = read_register(RTC_REG_A); + reg_a = (reg_a & 0xF0) | RTC_DIVIDER_33KHZ | RTC_FREQUENCY_1024HZ; + write_register(RTC_REG_A, reg_a); - *RTC_DEVICE.lock() = Some(rtc); - *RTC_TIME_CACHE.lock() = Some(initial_time); + // 清除中斷 + read_register(RTC_REG_C); - log_info!("RTC initialized"); + // 確保 timer 關閉 + disable_timer(); + + // 再次清除 + read_register(RTC_REG_C); + } + + log_info!("RTC initialized (lock-free design)"); } -/// Get cached time (safe, no deadlock) -pub fn get_time() -> Option { - RTC_TIME_CACHE.lock().clone() -} +pub fn get_time() -> DateTime { + unsafe { + loop { + // Wait for RTC to be ready + wait_for_update(); -/// 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); + // Read twice quickly + let time1 = read_time_raw(); + let time2 = read_time_raw(); + + // If the two reads are consistent, return the result + if time1 == time2 { + return time1; + } + + // Retry if inconsistent (maybe just rollover in seconds) + } } } -/// Force read time from RTC (slow, use sparingly) -pub fn force_read_time() -> Option { - 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) -} +/// Directly read the RTC register +unsafe fn read_time_raw() -> DateTime { + let config = &RTC_CONFIG; -/// Print current time info -pub fn print_info() { - if let Some(time) = get_time() { - log_info!( - "{}, {} {}, {} - {:02}:{:02}:{:02}", - time.weekday_name(), - time.month_name(), - time.day, - time.year, - time.hour, - time.minute, - time.second - ); + let mut second = read_register(RTC_REG_SEC); + let mut minute = read_register(RTC_REG_MIN); + let mut hour = read_register(RTC_REG_HRS); + let mut day = read_register(RTC_REG_DAY); + let mut month = read_register(RTC_REG_MTH); + let mut year = read_register(RTC_REG_YRS); + let weekday = read_register(RTC_REG_WDY); + + if !config.binary_mode { + second = bcd_to_binary(second); + minute = bcd_to_binary(minute); + day = bcd_to_binary(day); + month = bcd_to_binary(month); + year = bcd_to_binary(year); + } + + let pm_bit = hour & 0x80; + hour = if config.binary_mode { + hour & 0x7F } else { - crate::log_warn!("RTC not initialized"); + bcd_to_binary(hour & 0x7F) + }; + + if !config.hour_24_mode && pm_bit != 0 { + hour = (hour + 12) % 24; + } + + DateTime { + year: RTC_CURRENT_CENTURY + year as u16, + month, + day, + weekday, + hour, + minute, + second, } } -/// Enable RTC timer +/// Enable RTC periodic interrupt (1024Hz) pub fn enable_timer() { - if let Some(rtc) = RTC_DEVICE.lock().as_ref() { - rtc.enable_timer(); + unsafe { + // Close first + disable_timer(); + read_register(RTC_REG_C); + + // Setting the frequency + let mut reg_a = read_register(RTC_REG_A); + reg_a = (reg_a & 0xF0) | RTC_DIVIDER_33KHZ | RTC_FREQUENCY_1024HZ; + write_register(RTC_REG_A, reg_a); + + // Enable periodic interrupts + let mut reg_b = read_register(RTC_REG_B); + reg_b |= RTC_TIMER_ON; + write_register(RTC_REG_B, reg_b); + + // Clear interrupt flag + read_register(RTC_REG_C); } + + log_info!("RTC timer enabled at 1024Hz"); } -/// Disable the RTC timer +/// Disable RTC periodic interrupt pub fn disable_timer() { - if let Some(rtc) = RTC_DEVICE.lock().as_ref() { - rtc.disable_timer(); + unsafe { + let mut reg_b = read_register(RTC_REG_B); + reg_b &= !RTC_TIMER_ON; + write_register(RTC_REG_B, reg_b); + + read_register(RTC_REG_C); } } -/// Get RTC tick count (lock-free, safe in interrupts) +/// RTC interrupt handler +/// +/// This is the only function called in interrupt context. +/// Clears the interrupt flag +/// Increments the tick counter +#[inline] +pub fn handle_interrupt() { + unsafe { + read_register(RTC_REG_C); + } + + RTC_TICK_COUNT.fetch_add(1, Ordering::Relaxed); +} + +/// Get RTC tick count (lock-free) +#[inline] pub fn get_tick_count() -> u64 { RTC_TICK_COUNT.load(Ordering::Relaxed) } -/// Reset tick count (for testing) +/// Reset tick count +#[inline] pub fn reset_tick_count() { 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); - } +/// Print current time information +pub fn print_info() { + let time = get_time(); - RTC_TICK_COUNT.fetch_add(1, Ordering::Relaxed); + log_info!( + "{}, {} {}, {} - {:02}:{:02}:{:02}", + time.weekday_name(), + time.month_name(), + time.day, + time.year, + time.hour, + time.minute, + time.second + ); } \ No newline at end of file diff --git a/kernel/src/hal/timer.rs b/kernel/src/hal/timer.rs new file mode 100644 index 0000000..35866b6 --- /dev/null +++ b/kernel/src/hal/timer.rs @@ -0,0 +1,344 @@ +// kernel/src/hal/timer + +use crate::hal::{lapic, rtc, cpu, ioapic}; +use core::sync::atomic::{AtomicU64, AtomicBool, Ordering}; +use crate::{log_info, log_debug, log_warn, log_error}; + +const APIC_CALIBRATION_CONST: u32 = 0x100000; +const RTC_BASE_FREQUENCY: u32 = 1024; + +// APIC Timer register offset +const APIC_LVT_TIMER: u32 = 0x320; +const APIC_TIMER_ICR: u32 = 0x380; +const APIC_TIMER_DCR: u32 = 0x3E0; + +/// APIC Timer divider +#[repr(u32)] +#[allow(dead_code)] +pub enum ApicTimerDivider { + Div1 = 0b1011, + Div2 = 0b0000, + Div4 = 0b0001, + Div8 = 0b0010, + Div16 = 0b0011, + Div32 = 0b1000, + Div64 = 0b1001, + Div128 = 0b1010, +} + +// Timer configuration +static mut TIMER_CONFIG: TimerConfig = TimerConfig::new(); + +// Calibration status +static mut CALIBRATION: CalibrationState = CalibrationState::new(); + +// Runtime counter +static TICK_COUNTER: AtomicU64 = AtomicU64::new(0); + +// Calibration flag +static IS_CALIBRATING: AtomicBool = AtomicBool::new(false); + +static TIMEOUT: AtomicU64 = AtomicU64::new(0); + +struct TimerConfig { + base_frequency: u32, + running_frequency: u32, + tick_interval: u32, + initialized: bool, +} + +impl TimerConfig { + const fn new() -> Self { + Self { + base_frequency: 0, + running_frequency: 0, + tick_interval: 0, + initialized: false, + } + } +} + +struct CalibrationState { + rtc_ticks: u64, + done: bool, + frequency: u64, +} + +impl CalibrationState { + const fn new() -> Self { + Self { + rtc_ticks: 0, + done: false, + frequency: 0, + } + } + + fn reset(&mut self) { + self.rtc_ticks = 0; + self.done = false; + self.frequency = 0; + } +} + +/// Check if calibration is in progress (lock-free) +#[inline] +pub fn is_calibrating() -> bool { + IS_CALIBRATING.load(Ordering::Relaxed) +} + +/// Initialize and calibrate the APIC Timer +/// +/// # Parameters +/// - `target_frequency`: Target frequency (Hz), recommended range: 100-1000 +/// - `apic_id`: APIC ID of the current CPU +/// +/// # Returns +/// Whether initialization was successful +pub fn init(target_frequency: u32, apic_id: u8) -> bool { + if lapic::get_base_vaddr().is_none() { + log_error!("LAPIC not initialized!"); + return false; + } + + unsafe { + CALIBRATION.reset(); + } + + IS_CALIBRATING.store(true, Ordering::SeqCst); + + cpu::cpu_disable_interrupts(); + + log_debug!("Setting up APIC Timer for calibration..."); + + unsafe { + // Configure LVT Timer: one-shot mode, vector 32, masked + lapic::write_apic_reg_raw(APIC_LVT_TIMER, 32 | (1 << 16)); + + // Set the divider to 64 + lapic::write_apic_reg_raw(APIC_TIMER_DCR, ApicTimerDivider::Div64 as u32); + } + + log_debug!("Configuring interrupts..."); + + // Configure RTC interrupt (IRQ 8 -> Vector 40) + ioapic::set_irq_redirect(8, 40, apic_id, false, false); + ioapic::unmask_irq(8); + + log_info!("Starting calibration..."); + + rtc::reset_tick_count(); + rtc::enable_timer(); + + cpu::cpu_pause(1000); + + unsafe { + // Unmask APIC Timer + lapic::write_apic_reg_raw(APIC_LVT_TIMER, 32); + + // Write the initial count value and start counting down + lapic::write_apic_reg_raw(APIC_TIMER_ICR, APIC_CALIBRATION_CONST); + } + + log_debug!("Waiting for calibration..."); + + cpu::cpu_enable_interrupts(); + + let mut timeout = 100_000_000; + while !unsafe { CALIBRATION.done } && timeout > 0 { + cpu::cpu_pause(0); + timeout -= 1; + } + + cpu::cpu_disable_interrupts(); + + if timeout == 0 { + log_error!("Calibration timeout!"); + IS_CALIBRATING.store(false, Ordering::SeqCst); + return false; + } + + let base_frequency = unsafe { CALIBRATION.frequency as u32 }; + let rtc_ticks = unsafe { CALIBRATION.rtc_ticks }; + + 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); + + // Calculating the tick interval + let tick_interval = base_frequency / target_frequency; + + log_info!("Configuring periodic timer..."); + log_info!("Target: {} Hz", target_frequency); + log_info!("Interval: {}", tick_interval); + + unsafe { + TIMER_CONFIG = TimerConfig { + base_frequency, + running_frequency: target_frequency, + tick_interval, + initialized: true, + }; + } + + unsafe { + // Configure for periodic mode: periodic bit | vector 32 + lapic::write_apic_reg_raw(APIC_LVT_TIMER, (1 << 17) | 32); + + // Set the count value + lapic::write_apic_reg_raw(APIC_TIMER_ICR, tick_interval); + } + + // Mark calibration completed + IS_CALIBRATING.store(false, Ordering::SeqCst); + + // Ensure all writes are complete + core::sync::atomic::fence(Ordering::SeqCst); + + log_info!("APIC Timer ready at {} Hz", target_frequency); + log_info!("APIC Timer started successfully!"); + + cpu::cpu_enable_interrupts(); + + true +} + +/// RTC interrupt handling (calibration phase) +/// +/// Only called during calibration, only counts +#[inline] +pub fn rtc_calibration_handler() { + unsafe { + CALIBRATION.rtc_ticks += 1; + } +} + +/// APIC Timer Interrupt Handling (Calibration Phase) +/// +/// Calculate frequency and mark completion +pub fn apic_calibration_handler() { + let rtc_ticks = unsafe { CALIBRATION.rtc_ticks }; + + if rtc_ticks == 0 { + log_warn!("APIC Timer fired but RTC = 0!"); + unsafe { + CALIBRATION.done = true; + } + 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); + + unsafe { + CALIBRATION.frequency = base_frequency; + CALIBRATION.done = true; + } + + // 停止 RTC + rtc::disable_timer(); +} + +/// APIC Timer Periodic Tick Processing (Run Phase) +/// +/// Counts only, does nothing else +#[inline] +pub fn timer_tick_handler() { + TICK_COUNTER.fetch_add(1, Ordering::Relaxed); +} + +/// Get timer information +pub fn get_info() -> Option<(u32, u32, u64)> { + unsafe { + if TIMER_CONFIG.initialized { + Some(( + TIMER_CONFIG.base_frequency, + TIMER_CONFIG.running_frequency, + TICK_COUNTER.load(Ordering::Relaxed) + )) + } else { + None + } + } +} + +/// Get the total number of ticks (lock-free) +#[inline] +pub fn get_tick_count() -> u64 { + TICK_COUNTER.load(Ordering::Relaxed) +} + +/// Reset the tick counter +#[inline] +pub fn reset_tick_count() { + TICK_COUNTER.store(0, Ordering::Relaxed); +} + +/// Get the basic frequency +#[inline] +pub fn get_base_frequency() -> Option { + unsafe { + if TIMER_CONFIG.initialized { + Some(TIMER_CONFIG.base_frequency) + } else { + None + } + } +} + +/// Get the running frequency +#[inline] +pub fn get_running_frequency() -> Option { + unsafe { + if TIMER_CONFIG.initialized { + Some(TIMER_CONFIG.running_frequency) + } else { + None + } + } +} + +/// Wait for the specified number of milliseconds (busy wait) +pub fn busy_wait_ms(ms: u64) { + if let Some(freq) = get_running_frequency() { + let ticks_to_wait = (ms * freq as u64) / 1000; + let start = get_tick_count(); + + while get_tick_count() - start < ticks_to_wait { + cpu::cpu_pause(0); + } + } +} + +/// Wait for the specified number of microseconds (busy wait) +pub fn busy_wait_us(us: u64) { + if let Some(freq) = get_running_frequency() { + let ticks_to_wait = (us * freq as u64) / 1_000_000; + let start = get_tick_count(); + + while get_tick_count() - start < ticks_to_wait { + cpu::cpu_pause(0); + } + } +} + +/// Print timer information +pub fn print_info() { + if let Some((base_freq, running_freq, ticks)) = get_info() { + log_info!("Base Frequency: {} Hz", base_freq); + log_info!("Running Frequency: {} Hz", running_freq); + log_info!("Total Ticks: {}", ticks); + log_info!("Bus Speed: ~{} MHz", base_freq * 64 / 1_000_000); + } else { + log_warn!("APIC Timer not initialized"); + } +} \ No newline at end of file diff --git a/kernel/src/kernel/k_init.rs b/kernel/src/kernel/k_init.rs index 59b058d..076eec2 100644 --- a/kernel/src/kernel/k_init.rs +++ b/kernel/src/kernel/k_init.rs @@ -12,7 +12,7 @@ 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, apic_timer, cpu, ioapic, lapic, rtc}; +use crate::hal::{acpi, timer, cpu, ioapic, lapic, rtc}; use crate::hal::cpu::cpu_enable_interrupts; fn _logger_init() { @@ -206,7 +206,7 @@ fn _post_init( frame_allocator, ) { log_debug!("IO APIC {} mapped to virtual address: {:#x}", id, vaddr.as_u64()); - crate::hal::ioapic::init_single_ioapic(vaddr, *id, *gsi_base); + ioapic::init_single_ioapic(vaddr, *id, *gsi_base); } else { log_error!("Failed to map IO APIC {} memory", id); } @@ -227,11 +227,11 @@ fn _post_init( log_info!("Setting up APIC Timer..."); log_info!("Current CPU APIC ID: {}", apic_id); - if apic_timer::init(100, apic_id as u8) { + if timer::init(100, apic_id as u8) { log_info!("APIC Timer initialized successfully!"); // 顯示信息 - if let Some((base, running, ticks)) = apic_timer::get_info() { + if let Some((base, running, ticks)) = timer::get_info() { log_info!("Base freq: {} Hz", base); log_info!("Running at: {} Hz", running); log_info!("Current ticks: {}", ticks); @@ -239,7 +239,7 @@ fn _post_init( } else { log_error!("Failed to initialize APIC Timer!"); } - + ioapic::set_irq_redirect( 1, // IRQ number (keyboard) 33, // Interrupt vector number diff --git a/kernel/src/kernel/k_main.rs b/kernel/src/kernel/k_main.rs index 1391db9..c9f3f1e 100644 --- a/kernel/src/kernel/k_main.rs +++ b/kernel/src/kernel/k_main.rs @@ -1,6 +1,6 @@ // kernel/src/kernel/k_main.rs -use crate::hal::{apic_timer, cpu, rtc}; -use crate::kprintln; +use crate::hal::{timer, cpu, rtc}; +use crate::{kprint, kprintln, shell}; use crate::{log_trace, log_debug, log_info, log_warn, log_error, log_fatal}; use crate::mm::{vma, vmm}; use crate::mm::allocator::pmm; @@ -10,38 +10,36 @@ pub fn _kernel_main() -> ! { kprintln!("=== Welcome to CureOS! ==="); kprintln!(); - let mut brand_buf = [0u8; 64]; - let mut model_buf = [0u8; 16]; - log_info!("CPU: {} ({})", - cpu::cpu_get_brand(&mut brand_buf), - cpu::cpu_get_model(&mut model_buf) - ); - - kprintln!(); + let mut brand = [0u8; 64]; + let cpu_brand = cpu::cpu_get_brand(&mut brand); + kprintln!("CPU: {}", cpu_brand); if let Some(stats) = pmm::get_memory_stats() { - log_info!("Total Memory: {} MiB", stats.total_memory / (1024 * 1024)); - log_info!("Free Memory: {} MiB", stats.free_memory / (1024 * 1024)); + kprintln!("Memory: {} MiB / {} MiB free", + stats.free_memory / (1024 * 1024), + stats.total_memory / (1024 * 1024)); + kprintln!(" {}% used", + (stats.used_memory * 100) / stats.total_memory); } + if let Some((base_freq, running_freq, ticks)) = timer::get_info() { + kprintln!("Timer: {} Hz (base: {} Hz)", running_freq, base_freq); + kprintln!("Ticks: {}", ticks); + } + + if let time = rtc::get_time() { + kprintln!("Date/Time: {}", time.format()); + } + + log_info!("{}", cpu::cpu_rdtscp()) ; kprintln!(); - rtc::print_info(); - - kprintln!(); - - log_debug!("CR0: 0x{:016x}", cpu::cpu_r_cr0()); - log_debug!("CR2: 0x{:016x}", cpu::cpu_r_cr2()); - log_debug!("CR3: 0x{:016x}", cpu::cpu_r_cr3()); - log_debug!("CR4: 0x{:016x}", cpu::cpu_r_cr4()); - - kprintln!(); - - test_apic_timer(); - log_info!("System initialization complete!"); - log_warn!("Entering idle loop..."); kprintln!(); + kprintln!("Type 'help' for available commands"); + kprintln!(); + + shell::init(); loop { cpu::cpu_halt(); @@ -52,19 +50,16 @@ pub fn test_apic_timer() { log_info!("=== APIC Timer Test ==="); - let start_ticks = apic_timer::get_tick_count(); + let start_ticks = timer::get_tick_count(); - // 等待約 1 秒 - for _ in 0..1_000_000 { - cpu::cpu_pause(); - } + cpu::cpu_pause(1000); - let end_ticks = apic_timer::get_tick_count(); + let end_ticks = timer::get_tick_count(); let elapsed = end_ticks - start_ticks; log_info!("Elapsed ticks: {}", elapsed); - if let Some((_, freq, _)) = apic_timer::get_info() { + if let Some((_, freq, _)) = timer::get_info() { log_info!("Expected ~{} ticks/sec", freq); log_info!("Actual rate: {} Hz", elapsed); } diff --git a/kernel/src/main.rs b/kernel/src/main.rs index ac2a535..5f04f61 100644 --- a/kernel/src/main.rs +++ b/kernel/src/main.rs @@ -22,6 +22,7 @@ pub mod mm; pub mod tty; pub mod kernel; pub mod drivers; +pub mod shell; use hal::cpu; const CONFIG: BootloaderConfig = { diff --git a/kernel/src/shell/commands.rs b/kernel/src/shell/commands.rs new file mode 100644 index 0000000..168a47a --- /dev/null +++ b/kernel/src/shell/commands.rs @@ -0,0 +1,138 @@ +// kernel/src/shell/commands.rs +use crate::{kprintln, tty, hal::{rtc, timer, cpu}, mm::allocator::pmm, log_info}; +use crate::hal::io::io_port_wb; + +/// help 命令 +pub fn cmd_help() { + kprintln!(" help - Show this help message"); + kprintln!(" clear - Clear the screen"); + kprintln!(" time - Display current date and time"); + kprintln!(" uptime - Show system uptime"); + kprintln!(" sysinfo - Display system information"); + kprintln!(" reboot - Reboot the system"); + kprintln!(); +} + + +pub fn cmd_clear() { + tty::tty::clear(0x000000); +} + +pub fn cmd_time() { + if let time = rtc::get_time() { + kprintln!("Current time: {}", time.format()); + kprintln!("{}, {} {}, {}", + time.weekday_name(), + time.month_name(), + time.day, + time.year + ); + } else { + kprintln!("Error: Unable to read RTC"); + } +} + +pub fn cmd_uptime() { + let ticks = timer::get_tick_count(); + let total_seconds = ticks / 100; + let hours = total_seconds / 3600; + let minutes = (total_seconds % 3600) / 60; + let seconds = total_seconds % 60; + + kprintln!("System uptime: {}h {}m {}s ({} ticks)", + hours, minutes, seconds, ticks); +} + +pub fn cmd_echo(text: &str) { + if text.is_empty() { + kprintln!(); + } else { + kprintln!("{}", text); + } +} + +pub fn cmd_sysinfo() { + kprintln!(); + kprintln!("=== System Information ==="); + kprintln!(); + + let mut brand = [0u8; 64]; + let cpu_brand = cpu::cpu_get_brand(&mut brand); + kprintln!("CPU: {}", cpu_brand); + + // 記憶體信息 + if let Some(stats) = pmm::get_memory_stats() { + kprintln!("Memory: {} MiB / {} MiB free", + stats.free_memory / (1024 * 1024), + stats.total_memory / (1024 * 1024)); + kprintln!(" {}% used", + (stats.used_memory * 100) / stats.total_memory); + } + + if let Some((base_freq, running_freq, ticks)) = timer::get_info() { + kprintln!("Timer: {} Hz (base: {} Hz)", running_freq, base_freq); + kprintln!("Ticks: {}", ticks); + } + + if let time = rtc::get_time() { + kprintln!("Date/Time: {}", time.format()); + } + + kprintln!(); +} + +pub fn cmd_reboot() { + kprintln!("Rebooting system..."); + + cpu::cpu_pause(1000); + tty::tty::clear(0x000000); + + log_info!("Disabling CPU interrupts"); + cpu::cpu_disable_interrupts(); + + log_info!("Disabling RTC Timer"); + rtc::disable_timer(); + + unsafe { + io_port_wb(0x64, 0xFE); + + log_info!("Complete"); + + loop { + cpu::cpu_halt(); + } + } +} + +pub fn cmd_halt() { + kprintln!("System Statistics:"); + + let ticks = timer::get_tick_count(); + let total_seconds = ticks / 100; + let hours = total_seconds / 3600; + let minutes = (total_seconds % 3600) / 60; + let seconds = total_seconds % 60; + kprintln!(" Uptime: {}h {}m {}s", hours, minutes, seconds); + + if let Some(stats) = pmm::get_memory_stats() { + kprintln!(" Memory Used: {} MiB / {} MiB", + stats.used_memory / (1024 * 1024), + stats.total_memory / (1024 * 1024)); + } + + if let time = rtc::get_time() { + kprintln!(" Shutdown at: {}", time.format()); + } + + kprintln!(); + kprintln!("System halted. Safe to power off."); + kprintln!(); + + cpu::cpu_disable_interrupts(); + + rtc::disable_timer(); + + loop { + cpu::cpu_halt(); + } +} diff --git a/kernel/src/shell/mod.rs b/kernel/src/shell/mod.rs new file mode 100644 index 0000000..37116b7 --- /dev/null +++ b/kernel/src/shell/mod.rs @@ -0,0 +1,59 @@ +// kernel/src/shell/mod.rs +use alloc::string::String; +use spin::Mutex; +use crate::{kprint, kprintln, tty, hal::{rtc, timer}}; + +pub mod commands; + +static COMMAND_BUFFER: Mutex = Mutex::new(String::new()); + +pub fn init() { + show_prompt(); +} + +pub fn show_prompt() { + kprint!("cure > "); +} + +pub fn process_keyboard_char(c: char) { + let mut buffer = COMMAND_BUFFER.lock(); + + if c == '\n' { + let cmd = buffer.clone(); + buffer.clear(); + + kprintln!(); + execute_command(&cmd); + show_prompt(); + } else if c == '\x08' { + if !buffer.is_empty() { + buffer.pop(); + kprint!("\x08 \x08"); + } + } else if c.is_ascii_graphic() || c == ' ' { + buffer.push(c); + kprint!("{}", c); + } +} + +fn execute_command(cmd: &str) { + let cmd = cmd.trim(); + + if cmd.is_empty() { + return; + } + + match cmd { + "help" => commands::cmd_help(), + "clear" => commands::cmd_clear(), + "time" => commands::cmd_time(), + "uptime" => commands::cmd_uptime(), + "sysinfo" => commands::cmd_sysinfo(), + "reboot" => commands::cmd_reboot(), + "halt" | "shutdown" | "poweroff" => commands::cmd_halt(), + _ => { + kprintln!("Unknown command: '{}'", cmd); + kprintln!("Type 'help' for available commands"); + } + } +} \ No newline at end of file From d11c7842d44e0373b7f81cf7620f1947f3568141 Mon Sep 17 00:00:00 2001 From: ParrotXray Date: Fri, 17 Oct 2025 21:19:58 +0800 Subject: [PATCH 10/13] feat: Implement shutdown and restart --- TODO.txt | 3 +- kernel/src/arch/amd64/isr.rs | 125 +++++++-- kernel/src/hal/acpi/init.rs | 148 +++++++++++ kernel/src/hal/{acpi.rs => acpi/mod.rs} | 154 ++--------- kernel/src/hal/acpi/power.rs | 336 ++++++++++++++++++++++++ kernel/src/hal/mod.rs | 3 +- kernel/src/hal/power.rs | 222 ++++++++++++++++ kernel/src/hal/timer.rs | 11 +- kernel/src/kernel/k_init.rs | 14 +- kernel/src/kernel/k_main.rs | 6 +- kernel/src/shell/commands.rs | 162 ++++++++---- kernel/src/shell/math.rs | 138 ++++++++++ kernel/src/shell/mod.rs | 23 +- kernel/src/tty/tty.rs | 25 ++ 14 files changed, 1125 insertions(+), 245 deletions(-) create mode 100644 kernel/src/hal/acpi/init.rs rename kernel/src/hal/{acpi.rs => acpi/mod.rs} (52%) create mode 100644 kernel/src/hal/acpi/power.rs create mode 100644 kernel/src/hal/power.rs create mode 100644 kernel/src/shell/math.rs diff --git a/TODO.txt b/TODO.txt index fb545b5..75d4b79 100644 --- a/TODO.txt +++ b/TODO.txt @@ -23,7 +23,8 @@ // BUG -// - 在測試RTC中斷時 rtc::get_time() 處卡住 +// - ACPI 關機 mem 映射問題 +// - 關機重啟回收記憶體 // ==================== 高半核地址空間佈局 ==================== // diff --git a/kernel/src/arch/amd64/isr.rs b/kernel/src/arch/amd64/isr.rs index f88c027..aac96fb 100644 --- a/kernel/src/arch/amd64/isr.rs +++ b/kernel/src/arch/amd64/isr.rs @@ -4,6 +4,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 super::gdt; use crate::hal::{timer, cpu, lapic, rtc}; use crate::mm::paging; @@ -32,21 +33,34 @@ pub extern "x86-interrupt" fn debug_handler(stack_frame: InterruptStackFrame) { pub extern "x86-interrupt" fn nmi_handler(stack_frame: InterruptStackFrame) { kprintln!(); log_fatal!("EXCEPTION: NON-MASKABLE INTERRUPT (NMI)"); - log_fatal!("{:#?}", stack_frame); + log_fatal!("instruction pointer: {:#x}", stack_frame.instruction_pointer.as_u64()); + log_fatal!("code segment: index: {:#?}, rpl: {:#?}", stack_frame.code_segment.index(), stack_frame.code_segment.rpl()); + log_fatal!("cpu flags: {:#x}", stack_frame.cpu_flags.bits()); + log_fatal!("stack pointer: {:#x}", stack_frame.stack_pointer.as_u64()); + log_fatal!("stack segment: index: {:#?}, rpl: {:#?}", stack_frame.stack_segment.index(), stack_frame.stack_segment.rpl()); } /// Breakpoint (#BP) pub extern "x86-interrupt" fn breakpoint_handler(stack_frame: InterruptStackFrame) { kprintln!(); log_debug!("EXCEPTION: BREAKPOINT (#BP)"); - log_debug!("{:#?}", stack_frame); + log_debug!("instruction pointer: {:#x}", stack_frame.instruction_pointer.as_u64()); + log_debug!("code segment: index: {:#?}, rpl: {:#?}", stack_frame.code_segment.index(), stack_frame.code_segment.rpl()); + log_debug!("cpu flags: {:#x}", stack_frame.cpu_flags.bits()); + log_debug!("stack pointer: {:#x}", stack_frame.stack_pointer.as_u64()); + log_debug!("stack segment: index: {:#?}, rpl: {:#?}", stack_frame.stack_segment.index(), stack_frame.stack_segment.rpl()); } /// Overflow (#OF) pub extern "x86-interrupt" fn overflow_handler(stack_frame: InterruptStackFrame) { kprintln!(); log_error!("EXCEPTION: OVERFLOW (#OF)"); - log_error!("{:#?}", stack_frame); + log_error!("instruction pointer: {:#x}", stack_frame.instruction_pointer.as_u64()); + log_error!("code segment: index: {:#?}, rpl: {:#?}", stack_frame.code_segment.index(), stack_frame.code_segment.rpl()); + log_error!("cpu flags: {:#x}", stack_frame.cpu_flags.bits()); + log_error!("stack pointer: {:#x}", stack_frame.stack_pointer.as_u64()); + log_error!("stack segment: index: {:#?}, rpl: {:#?}", stack_frame.stack_segment.index(), stack_frame.stack_segment.rpl()); + loop { cpu::cpu_halt(); } @@ -56,7 +70,12 @@ pub extern "x86-interrupt" fn overflow_handler(stack_frame: InterruptStackFrame) pub extern "x86-interrupt" fn bound_range_handler(stack_frame: InterruptStackFrame) { kprintln!(); log_error!("EXCEPTION: BOUND RANGE EXCEEDED (#BR)"); - log_error!("{:#?}", stack_frame); + log_error!("instruction pointer: {:#x}", stack_frame.instruction_pointer.as_u64()); + log_error!("code segment: index: {:#?}, rpl: {:#?}", stack_frame.code_segment.index(), stack_frame.code_segment.rpl()); + log_error!("cpu flags: {:#x}", stack_frame.cpu_flags.bits()); + log_error!("stack pointer: {:#x}", stack_frame.stack_pointer.as_u64()); + log_error!("stack segment: index: {:#?}, rpl: {:#?}", stack_frame.stack_segment.index(), stack_frame.stack_segment.rpl()); + loop { cpu::cpu_halt(); } @@ -66,7 +85,12 @@ pub extern "x86-interrupt" fn bound_range_handler(stack_frame: InterruptStackFra pub extern "x86-interrupt" fn invalid_opcode_handler(stack_frame: InterruptStackFrame) { kprintln!(); log_error!("EXCEPTION: INVALID OPCODE (#UD)"); - log_error!("{:#?}", stack_frame); + log_error!("instruction pointer: {:#x}", stack_frame.instruction_pointer.as_u64()); + log_error!("code segment: index: {:#?}, rpl: {:#?}", stack_frame.code_segment.index(), stack_frame.code_segment.rpl()); + log_error!("cpu flags: {:#x}", stack_frame.cpu_flags.bits()); + log_error!("stack pointer: {:#x}", stack_frame.stack_pointer.as_u64()); + log_error!("stack segment: index: {:#?}, rpl: {:#?}", stack_frame.stack_segment.index(), stack_frame.stack_segment.rpl()); + loop { cpu::cpu_halt(); } @@ -76,7 +100,12 @@ pub extern "x86-interrupt" fn invalid_opcode_handler(stack_frame: InterruptStack pub extern "x86-interrupt" fn device_not_available_handler(stack_frame: InterruptStackFrame) { kprintln!(); log_error!("EXCEPTION: DEVICE NOT AVAILABLE (#NM)"); - log_error!("{:#?}", stack_frame); + log_error!("instruction pointer: {:#x}", stack_frame.instruction_pointer.as_u64()); + log_error!("code segment: index: {:#?}, rpl: {:#?}", stack_frame.code_segment.index(), stack_frame.code_segment.rpl()); + log_error!("cpu flags: {:#x}", stack_frame.cpu_flags.bits()); + log_error!("stack pointer: {:#x}", stack_frame.stack_pointer.as_u64()); + log_error!("stack segment: index: {:#?}, rpl: {:#?}", stack_frame.stack_segment.index(), stack_frame.stack_segment.rpl()); + loop { cpu::cpu_halt(); } @@ -90,7 +119,13 @@ pub extern "x86-interrupt" fn double_fault_handler( kprintln!(); log_fatal!("EXCEPTION: DOUBLE FAULT (#DF)"); log_fatal!("Error Code: {:#x}", error_code); - log_fatal!("{:#?}", stack_frame); + + log_fatal!("instruction pointer: {:#x}", stack_frame.instruction_pointer.as_u64()); + log_fatal!("code segment: index: {:#?}, rpl: {:#?}", stack_frame.code_segment.index(), stack_frame.code_segment.rpl()); + log_fatal!("cpu flags: {:#x}", stack_frame.cpu_flags.bits()); + log_fatal!("stack pointer: {:#x}", stack_frame.stack_pointer.as_u64()); + log_fatal!("stack segment: index: {:#?}, rpl: {:#?}", stack_frame.stack_segment.index(), stack_frame.stack_segment.rpl()); + panic!("DOUBLE FAULT - System cannot continue"); } @@ -102,7 +137,13 @@ pub extern "x86-interrupt" fn invalid_tss_handler( kprintln!(); log_fatal!("EXCEPTION: INVALID TSS (#TS)"); log_fatal!("Error Code: {:#x}", error_code); - log_fatal!("{:#?}", stack_frame); + + log_fatal!("instruction pointer: {:#x}", stack_frame.instruction_pointer.as_u64()); + log_fatal!("code segment: index: {:#?}, rpl: {:#?}", stack_frame.code_segment.index(), stack_frame.code_segment.rpl()); + log_fatal!("cpu flags: {:#x}", stack_frame.cpu_flags.bits()); + log_fatal!("stack pointer: {:#x}", stack_frame.stack_pointer.as_u64()); + log_fatal!("stack segment: index: {:#?}, rpl: {:#?}", stack_frame.stack_segment.index(), stack_frame.stack_segment.rpl()); + loop { cpu::cpu_halt(); } @@ -127,11 +168,9 @@ pub extern "x86-interrupt" fn segment_not_present_handler( let index = (error_code >> 3) & 0x1FFF; log_fatal!("Segment: {} index {:#x} (external: {})", table, index, is_external); - log_fatal!("{:#?}", stack_frame); - log_fatal!("Current segments:"); - log_fatal!(" CS: {:#x}", crate::arch::amd64::gdt::kernel_code_selector().0); - log_fatal!(" SS: {:#x}", crate::arch::amd64::gdt::kernel_data_selector().0); + log_fatal!("CS: {:#x}", gdt::kernel_code_selector().0); + log_fatal!("SS: {:#x}", gdt::kernel_data_selector().0); loop { cpu::cpu_halt(); @@ -146,7 +185,12 @@ pub extern "x86-interrupt" fn stack_segment_fault_handler( kprintln!(); log_fatal!("EXCEPTION: STACK SEGMENT FAULT (#SS)"); log_fatal!("Error Code: {:#x}", error_code); - log_fatal!("{:#?}", stack_frame); + log_fatal!("instruction pointer: {:#x}", stack_frame.instruction_pointer.as_u64()); + log_fatal!("code segment: index: {:#?}, rpl: {:#?}", stack_frame.code_segment.index(), stack_frame.code_segment.rpl()); + log_fatal!("cpu flags: {:#x}", stack_frame.cpu_flags.bits()); + log_fatal!("stack pointer: {:#x}", stack_frame.stack_pointer.as_u64()); + log_fatal!("stack segment: index: {:#?}, rpl: {:#?}", stack_frame.stack_segment.index(), stack_frame.stack_segment.rpl()); + loop { cpu::cpu_halt(); } @@ -160,7 +204,12 @@ pub extern "x86-interrupt" fn general_protection_fault_handler( kprintln!(); log_fatal!("EXCEPTION: GENERAL PROTECTION FAULT (#GP)"); log_fatal!("Error Code: {:#x}", error_code); - log_fatal!("{:#?}", stack_frame); + log_fatal!("instruction pointer: {:#x}", stack_frame.instruction_pointer.as_u64()); + log_fatal!("code segment: index: {:#?}, rpl: {:#?}", stack_frame.code_segment.index(), stack_frame.code_segment.rpl()); + log_fatal!("cpu flags: {:#x}", stack_frame.cpu_flags.bits()); + log_fatal!("stack pointer: {:#x}", stack_frame.stack_pointer.as_u64()); + log_fatal!("stack segment: index: {:#?}, rpl: {:#?}", stack_frame.stack_segment.index(), stack_frame.stack_segment.rpl()); + loop { cpu::cpu_halt(); } @@ -181,7 +230,12 @@ pub extern "x86-interrupt" fn page_fault_handler( log_fatal!("User: {}", error_code.contains(PageFaultErrorCode::USER_MODE)); log_fatal!("Reserved Write: {}", error_code.contains(PageFaultErrorCode::MALFORMED_TABLE)); log_fatal!("Instruction Fetch: {}", error_code.contains(PageFaultErrorCode::INSTRUCTION_FETCH)); - log_fatal!("{:#?}", stack_frame); + + log_fatal!("instruction pointer: {:#x}", stack_frame.instruction_pointer.as_u64()); + log_fatal!("code segment: index: {:#?}, rpl: {:#?}", stack_frame.code_segment.index(), stack_frame.code_segment.rpl()); + log_fatal!("cpu flags: {:#x}", stack_frame.cpu_flags.bits()); + log_fatal!("stack pointer: {:#x}", stack_frame.stack_pointer.as_u64()); + log_fatal!("stack segment: index: {:#?}, rpl: {:#?}", stack_frame.stack_segment.index(), stack_frame.stack_segment.rpl()); paging::handle_page_fault( VirtAddr::new(cpu::cpu_r_cr2()), @@ -197,7 +251,12 @@ pub extern "x86-interrupt" fn page_fault_handler( pub extern "x86-interrupt" fn x87_floating_point_handler(stack_frame: InterruptStackFrame) { kprintln!(); log_error!("EXCEPTION: x87 FLOATING POINT (#MF)"); - log_error!("{:#?}", stack_frame); + log_error!("instruction pointer: {:#x}", stack_frame.instruction_pointer.as_u64()); + log_error!("code segment: index: {:#?}, rpl: {:#?}", stack_frame.code_segment.index(), stack_frame.code_segment.rpl()); + log_error!("cpu flags: {:#x}", stack_frame.cpu_flags.bits()); + log_error!("stack pointer: {:#x}", stack_frame.stack_pointer.as_u64()); + log_error!("stack segment: index: {:#?}, rpl: {:#?}", stack_frame.stack_segment.index(), stack_frame.stack_segment.rpl()); + loop { cpu::cpu_halt(); } @@ -211,7 +270,12 @@ pub extern "x86-interrupt" fn alignment_check_handler( kprintln!(); log_error!("EXCEPTION: ALIGNMENT CHECK (#AC)"); log_error!("Error Code: {:#x}", error_code); - log_error!("{:#?}", stack_frame); + log_error!("instruction pointer: {:#x}", stack_frame.instruction_pointer.as_u64()); + log_error!("code segment: index: {:#?}, rpl: {:#?}", stack_frame.code_segment.index(), stack_frame.code_segment.rpl()); + log_error!("cpu flags: {:#x}", stack_frame.cpu_flags.bits()); + log_error!("stack pointer: {:#x}", stack_frame.stack_pointer.as_u64()); + log_error!("stack segment: index: {:#?}, rpl: {:#?}", stack_frame.stack_segment.index(), stack_frame.stack_segment.rpl()); + loop { cpu::cpu_halt(); } @@ -221,15 +285,25 @@ pub extern "x86-interrupt" fn alignment_check_handler( pub extern "x86-interrupt" fn machine_check_handler(stack_frame: InterruptStackFrame) -> ! { kprintln!(); log_error!("EXCEPTION: MACHINE CHECK (#MC)"); - log_error!("{:#?}", stack_frame); + log_error!("instruction pointer: {:#x}", stack_frame.instruction_pointer.as_u64()); + log_error!("code segment: index: {:#?}, rpl: {:#?}", stack_frame.code_segment.index(), stack_frame.code_segment.rpl()); + log_error!("cpu flags: {:#x}", stack_frame.cpu_flags.bits()); + log_error!("stack pointer: {:#x}", stack_frame.stack_pointer.as_u64()); + log_error!("stack segment: index: {:#?}, rpl: {:#?}", stack_frame.stack_segment.index(), stack_frame.stack_segment.rpl()); + panic!("MACHINE CHECK - System cannot continue"); } /// SIMD Floating-Point Exception (#XM/#XF) pub extern "x86-interrupt" fn simd_floating_point_handler(stack_frame: InterruptStackFrame) { kprintln!(); - kprintln!("EXCEPTION: SIMD FLOATING POINT (#XM/#XF)"); - kprintln!("{:#?}", stack_frame); + log_error!("EXCEPTION: SIMD FLOATING POINT (#XM/#XF)"); + log_error!("instruction pointer: {:#x}", stack_frame.instruction_pointer.as_u64()); + log_error!("code segment: index: {:#?}, rpl: {:#?}", stack_frame.code_segment.index(), stack_frame.code_segment.rpl()); + log_error!("cpu flags: {:#x}", stack_frame.cpu_flags.bits()); + log_error!("stack pointer: {:#x}", stack_frame.stack_pointer.as_u64()); + log_error!("stack segment: index: {:#?}, rpl: {:#?}", stack_frame.stack_segment.index(), stack_frame.stack_segment.rpl()); + loop { cpu::cpu_halt(); } @@ -239,7 +313,12 @@ pub extern "x86-interrupt" fn simd_floating_point_handler(stack_frame: Interrupt pub extern "x86-interrupt" fn virtualization_handler(stack_frame: InterruptStackFrame) { kprintln!(); log_warn!("EXCEPTION: VIRTUALIZATION (#VE)"); - log_warn!("{:#?}", stack_frame); + log_warn!("instruction pointer: {:#x}", stack_frame.instruction_pointer.as_u64()); + log_warn!("code segment: index: {:#?}, rpl: {:#?}", stack_frame.code_segment.index(), stack_frame.code_segment.rpl()); + log_warn!("cpu flags: {:#x}", stack_frame.cpu_flags.bits()); + log_warn!("stack pointer: {:#x}", stack_frame.stack_pointer.as_u64()); + log_warn!("stack segment: index: {:#?}, rpl: {:#?}", stack_frame.stack_segment.index(), stack_frame.stack_segment.rpl()); + loop { cpu::cpu_halt(); } @@ -247,7 +326,7 @@ 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) { +pub extern "x86-interrupt" fn keyboard_interrupt_handler(_stack_frame: InterruptStackFrame) { unsafe { let mut port = Port::new(0x60); @@ -259,7 +338,7 @@ pub extern "x86-interrupt" fn keyboard_interrupt_handler(stack_frame: InterruptS lapic::send_eoi(); } -pub extern "x86-interrupt" fn default_irq_handler(stack_frame: InterruptStackFrame) { +pub extern "x86-interrupt" fn default_irq_handler(_stack_frame: InterruptStackFrame) { lapic::send_eoi(); log_trace!("Unhandled IRQ"); } diff --git a/kernel/src/hal/acpi/init.rs b/kernel/src/hal/acpi/init.rs new file mode 100644 index 0000000..c9f9445 --- /dev/null +++ b/kernel/src/hal/acpi/init.rs @@ -0,0 +1,148 @@ +use acpi::{aml, sdt, AcpiTables, Handle, Handler, PciAddress, PhysicalMapping}; +use acpi::platform::{AcpiPlatform, interrupt::InterruptModel, PciConfigRegions}; +use acpi::sdt::hpet::HpetInfo; +use acpi::rsdp::Rsdp; +use core::ptr::NonNull; +use core::mem; +use crate::kprintln; +use crate::{log_trace, log_debug, log_info, log_warn, log_error, log_fatal}; +use crate::hal::{cpu, io}; +use super::*; + + +pub fn init(rsdp_addr: u64, physical_memory_offset: u64) -> Option { + + let handler = CureAcpiHandler::new(physical_memory_offset); + + let rsdp_mapping = unsafe { + handler.map_physical_region::(rsdp_addr as usize, mem::size_of::()) + }; + let revision = rsdp_mapping.revision(); + log_info!("ACPI Revision: {}", revision); + + let tables = unsafe { + match AcpiTables::from_rsdp(handler, rsdp_addr as usize) { + Ok(tables) => tables, + Err(e) => { + log_error!("Failed to parse ACPI tables: {:?}", e); + return None; + } + } + }; + + let platform = match AcpiPlatform::new(tables, handler) { + Ok(platform) => platform, + Err(e) => { + log_error!("Failed to create ACPI platform: {:?}", e); + return None; + } + }; + + log_info!("Power Profile: {:?}", platform.power_profile); + + let (boot_processor, cpu_count) = if let Some(proc_info) = &platform.processor_info { + let boot_proc = Some(proc_info.boot_processor.processor_uid); + let cpu_cnt = proc_info.application_processors.len() + 1; + + log_info!("Boot Processor UID: {:?}", boot_proc); + log_info!("Total CPU Count: {}", cpu_cnt); + + (boot_proc, cpu_cnt) + } else { + log_warn!("No processor info found"); + (None, 0) + }; + + // Check interrupt mode + let (has_apic, local_apic_addr, io_apics_info) = match &platform.interrupt_model { + InterruptModel::Apic(apic) => { + log_info!("Local APIC Address: {:#x}", apic.local_apic_address); + log_info!("IO APICs: {} controller(s)", apic.io_apics.len()); + + let mut io_apics = alloc::vec::Vec::new(); + + for (i, io_apic) in apic.io_apics.iter().enumerate() { + log_info!("IO APIC {}: ID={}, Address={:#x}, GSI Base={}", + i, io_apic.id, io_apic.address, io_apic.global_system_interrupt_base); + + io_apics.push(( + io_apic.address as u64, + io_apic.id, + io_apic.global_system_interrupt_base, + )); + } + + (true, Some(apic.local_apic_address as u64), io_apics) + } + InterruptModel::Unknown => { + log_warn!("Interrupt Model: Unknown (not APIC)"); + (false, None, alloc::vec::Vec::new()) + } + _ => { + log_warn!("Interrupt Model: Other"); + (false, None, alloc::vec::Vec::new()) + } + }; + + let has_hpet = match HpetInfo::new(&platform.tables) { + Ok(hpet) => { + log_info!("Base Address: {:#x}", hpet.base_address); + log_info!("Hardware Rev: {}", hpet.hardware_rev); + log_info!("Comparator Count: {}", hpet.num_comparators); + log_info!("Counter Size: {} bit", if hpet.main_counter_is_64bits { 64 } else { 32 }); + log_info!("Legacy IRQ Capable: {}", hpet.legacy_irq_capable); + log_info!("PCI Vendor ID: {:#x}", hpet.pci_vendor_id); + true + } + Err(_) => { + log_warn!("HPET: Not available"); + false + } + }; + + if let Ok(mcfg) = PciConfigRegions::new(&platform.tables) { + for (i, entry) in mcfg.regions.iter().enumerate() { + let segment_group = entry.pci_segment_group; + let base_addr = entry.base_address; + let bus_start = entry.bus_number_start; + let bus_end = entry.bus_number_end; + + log_info!("Entry {}: Segment Group {}", i, segment_group); + log_info!("Base Address: {:#x}", base_addr); + log_info!("Bus Range: {}-{}", bus_start, bus_end); + } + } + + kprintln!(); + log_info!("Extracting ACPI power management info..."); + // if let Some(power_info) = extract_power_info(&platform.tables) { + // store_power_info(power_info); + // } else { + // log_warn!("Could not extract ACPI power info, shutdown may not work"); + // } + + + log_info!("ACPI initialized successfully!"); + + Some(AcpiInfo { + revision, + boot_processor, + cpu_count, + has_apic, + has_hpet, + local_apic_address: local_apic_addr, + io_apics: io_apics_info, + }) +} + +pub fn print_info(info: &AcpiInfo) { + kprintln!(); + log_info!("Revision: ACPI {}.0", info.revision); + log_info!("CPUs: {} processor(s)", info.cpu_count); + if let Some(boot_proc) = info.boot_processor { + log_info!("Boot Processor: UID {}", boot_proc); + } + log_info!("APIC: {}", if info.has_apic { "Available " } else { "Not available" }); + log_info!("HPET: {}", if info.has_hpet { "Available " } else { "Not available" }); +} + diff --git a/kernel/src/hal/acpi.rs b/kernel/src/hal/acpi/mod.rs similarity index 52% rename from kernel/src/hal/acpi.rs rename to kernel/src/hal/acpi/mod.rs index 815cfcb..fd97adf 100644 --- a/kernel/src/hal/acpi.rs +++ b/kernel/src/hal/acpi/mod.rs @@ -1,13 +1,15 @@ -use acpi::{aml, AcpiTables, Handle, Handler, PciAddress, PhysicalMapping}; -use acpi::platform::{AcpiPlatform, interrupt::InterruptModel, PciConfigRegions}; +pub mod power; +pub mod init; + +use acpi::{aml, sdt, AcpiTables, Handle, Handler, PciAddress, PhysicalMapping}; use acpi::sdt::hpet::HpetInfo; -use acpi::rsdp::Rsdp; use core::ptr::NonNull; use core::mem; use crate::kprintln; use crate::{log_trace, log_debug, log_info, log_warn, log_error, log_fatal}; use crate::hal::{cpu, io}; + #[derive(Clone, Copy)] pub struct CureAcpiHandler { physical_memory_offset: u64, @@ -23,6 +25,17 @@ pub struct AcpiInfo { pub io_apics: alloc::vec::Vec<(u64, u8, u32)>, // (address, id, gsi_base) } +/// ACPI 關機所需的信息 +pub struct AcpiPowerInfo { + pub pm1a_control_block: u32, + pub pm1b_control_block: u32, + pub slp_typa: u16, + pub slp_typb: u16, + pub slp_en: u16, +} + +static mut ACPI_POWER_INFO: Option = None; + impl CureAcpiHandler { pub const fn new(physical_memory_offset: u64) -> Self { Self { @@ -170,7 +183,7 @@ impl Handler for CureAcpiHandler { fn stall(&self, _microseconds: u64) { // TODO: 實作微秒級延遲 // 簡單的忙等待實作 - cpu::cpu_pause(_microseconds * 1000); + cpu::cpu_pause(_microseconds * 1000); } @@ -180,10 +193,10 @@ impl Handler for CureAcpiHandler { self.stall(_milliseconds * 1000); } - fn create_mutex(&self) -> acpi::Handle { + fn create_mutex(&self) -> Handle { // TODO: 實作 Mutex // 目前返回一個假的 handle - acpi::Handle(0) + Handle(0) } fn acquire(&self, mutex: Handle, timeout: u16) -> Result<(), aml::AmlError> { @@ -192,134 +205,7 @@ impl Handler for CureAcpiHandler { Ok(()) } - fn release(&self, _handle: acpi::Handle) { + fn release(&self, _handle: Handle) { // TODO: 實作 Mutex 釋放 } -} - -pub fn init(rsdp_addr: u64, physical_memory_offset: u64) -> Option { - - let handler = CureAcpiHandler::new(physical_memory_offset); - - let rsdp_mapping = unsafe { - handler.map_physical_region::(rsdp_addr as usize, mem::size_of::()) - }; - let revision = rsdp_mapping.revision(); - log_info!("ACPI Revision: {}", revision); - - let tables = unsafe { - match AcpiTables::from_rsdp(handler, rsdp_addr as usize) { - Ok(tables) => tables, - Err(e) => { - log_error!("Failed to parse ACPI tables: {:?}", e); - return None; - } - } - }; - - let platform = match AcpiPlatform::new(tables, handler) { - Ok(platform) => platform, - Err(e) => { - log_error!("Failed to create ACPI platform: {:?}", e); - return None; - } - }; - - log_info!("Power Profile: {:?}", platform.power_profile); - - let (boot_processor, cpu_count) = if let Some(proc_info) = &platform.processor_info { - let boot_proc = Some(proc_info.boot_processor.processor_uid); - let cpu_cnt = proc_info.application_processors.len() + 1; - - log_info!("Boot Processor UID: {:?}", boot_proc); - log_info!("Total CPU Count: {}", cpu_cnt); - - (boot_proc, cpu_cnt) - } else { - log_warn!("No processor info found"); - (None, 0) - }; - - // Check interrupt mode - let (has_apic, local_apic_addr, io_apics_info) = match &platform.interrupt_model { - InterruptModel::Apic(apic) => { - log_info!("Local APIC Address: {:#x}", apic.local_apic_address); - log_info!("IO APICs: {} controller(s)", apic.io_apics.len()); - - let mut io_apics = alloc::vec::Vec::new(); - - for (i, io_apic) in apic.io_apics.iter().enumerate() { - log_info!("IO APIC {}: ID={}, Address={:#x}, GSI Base={}", - i, io_apic.id, io_apic.address, io_apic.global_system_interrupt_base); - - io_apics.push(( - io_apic.address as u64, - io_apic.id, - io_apic.global_system_interrupt_base, - )); - } - - (true, Some(apic.local_apic_address as u64), io_apics) - } - InterruptModel::Unknown => { - log_warn!("Interrupt Model: Unknown (not APIC)"); - (false, None, alloc::vec::Vec::new()) - } - _ => { - log_warn!("Interrupt Model: Other"); - (false, None, alloc::vec::Vec::new()) - } - }; - - let has_hpet = match HpetInfo::new(&platform.tables) { - Ok(hpet) => { - log_info!("Base Address: {:#x}", hpet.base_address); - log_info!("Hardware Rev: {}", hpet.hardware_rev); - log_info!("Comparator Count: {}", hpet.num_comparators); - log_info!("Counter Size: {} bit", if hpet.main_counter_is_64bits { 64 } else { 32 }); - log_info!("Legacy IRQ Capable: {}", hpet.legacy_irq_capable); - log_info!("PCI Vendor ID: {:#x}", hpet.pci_vendor_id); - true - } - Err(_) => { - log_warn!("HPET: Not available"); - false - } - }; - - if let Ok(mcfg) = PciConfigRegions::new(&platform.tables) { - for (i, entry) in mcfg.regions.iter().enumerate() { - let segment_group = entry.pci_segment_group; - let base_addr = entry.base_address; - let bus_start = entry.bus_number_start; - let bus_end = entry.bus_number_end; - - log_info!("Entry {}: Segment Group {}", i, segment_group); - log_info!("Base Address: {:#x}", base_addr); - log_info!("Bus Range: {}-{}", bus_start, bus_end); - } - } - - log_info!("ACPI initialized successfully!"); - - Some(AcpiInfo { - revision, - boot_processor, - cpu_count, - has_apic, - has_hpet, - local_apic_address: local_apic_addr, - io_apics: io_apics_info, - }) -} - -pub fn print_info(info: &AcpiInfo) { - kprintln!(); - log_info!("Revision: ACPI {}.0", info.revision); - log_info!("CPUs: {} processor(s)", info.cpu_count); - if let Some(boot_proc) = info.boot_processor { - log_info!("Boot Processor: UID {}", boot_proc); - } - log_info!("APIC: {}", if info.has_apic { "Available " } else { "Not available" }); - log_info!("HPET: {}", if info.has_hpet { "Available " } else { "Not available" }); } \ No newline at end of file diff --git a/kernel/src/hal/acpi/power.rs b/kernel/src/hal/acpi/power.rs new file mode 100644 index 0000000..2f3199a --- /dev/null +++ b/kernel/src/hal/acpi/power.rs @@ -0,0 +1,336 @@ +use acpi::{aml, sdt, AcpiTables, Handle, Handler, PciAddress, PhysicalMapping}; +use acpi::platform::{AcpiPlatform, interrupt::InterruptModel, PciConfigRegions}; +use core::mem; +use crate::kprintln; +use crate::{log_trace, log_debug, log_info, log_warn, log_error, log_fatal}; +use crate::hal::{cpu, io}; +use crate::mm::vma; +use super::*; + + +/// Extract shutdown information from ACPI table +pub fn extract_power_info(tables: &AcpiTables) -> Option { + log_info!("Extracting ACPI power management info..."); + + let fadt = match tables.find_table::() { + Some(fadt) => fadt, + None => { + log_error!("Failed to find FADT"); + return None; + } + }; + + log_debug!("FADT found"); + + // Get the control block address and DSDT address from FADT + unsafe { + // Get the raw pointer of FADT to read the fields manually + let fadt_ptr = (&*fadt as *const sdt::fadt::Fadt) as *const u8; + + // FADT structure offset + let pm1a_control_block = core::ptr::read_unaligned(fadt_ptr.add(64) as *const u32); + let pm1b_control_block = core::ptr::read_unaligned(fadt_ptr.add(68) as *const u32); + + // Read DSDT address + let fadt_revision = core::ptr::read_unaligned(fadt_ptr.add(8) as *const u8); + let dsdt_address = if fadt_revision >= 2 { + let x_dsdt = core::ptr::read_unaligned(fadt_ptr.add(140) as *const u64); + if x_dsdt != 0 { + x_dsdt + } else { + core::ptr::read_unaligned(fadt_ptr.add(40) as *const u32) as u64 + } + } else { + core::ptr::read_unaligned(fadt_ptr.add(40) as *const u32) as u64 + }; + + log_info!("PM1a Control Block: {:#x}", pm1a_control_block); + if pm1b_control_block != 0 { + log_info!("PM1b Control Block: {:#x}", pm1b_control_block); + } + log_debug!("DSDT address: {:#x}", dsdt_address); + + // Parse the _S5 object + let (slp_typa, slp_typb) = match parse_s5_object(dsdt_address) { + Some(values) => values, + None => { + log_warn!("Could not parse _S5 object, using default values"); + (5, 5) + } + }; + + log_info!("SLP_TYPa: {:#x}", slp_typa); + log_info!("SLP_TYPb: {:#x}", slp_typb); + + Some(AcpiPowerInfo { + pm1a_control_block, + pm1b_control_block, + slp_typa, + slp_typb, + slp_en: 1 << 13, + }) + } +} + +/// Parse the _S5 object in the DSDT +/// +/// AML bytecode format for the _S5 object: +/// ``` +/// Name(_S5, Package() { +/// SLP_TYPa, // Type A for entering the S5 state +/// SLP_TYPb, // Type B for entering the S5 state +/// ... +/// }) +/// ``` +fn parse_s5_object(dsdt_phys_addr: u64) -> Option<(u16, u16)> { + let dsdt_virt_addr = vma::phys_to_virt(dsdt_phys_addr); + + unsafe { + let dsdt_ptr = dsdt_virt_addr.as_ptr::(); + + // DSDT header + let signature = core::slice::from_raw_parts(dsdt_ptr, 4); + if signature != b"DSDT" { + log_error!("Invalid DSDT signature"); + return None; + } + + // Get DSDT length + let length = core::ptr::read_unaligned(dsdt_ptr.add(4) as *const u32); + log_debug!("DSDT length: {} bytes", length); + + // Search for the "_S5_" string in DSDT + let dsdt_data = core::slice::from_raw_parts(dsdt_ptr, length as usize); + + // Byte representation of "_S5_" in AML + let s5_name = b"_S5_"; + + for i in 0..(dsdt_data.len() - 4) { + if &dsdt_data[i..i+4] == s5_name { + log_debug!("Found _S5 at offset {:#x}", i); + + // Parse the _S5 package + // Typical AML bytecode: + // Name(_S5, Package() {...}) + // Or: 08 5F 53 35 5F 12 [pkg_length] [num_elements] ... + + let mut offset = i + 4; + + // Skip possible NameOp (0x08) + if offset < dsdt_data.len() && dsdt_data[offset] == 0x08 { + offset += 1; + } + + // Find PackageOp (0x12) + while offset < dsdt_data.len() && dsdt_data[offset] != 0x12 { + offset += 1; + if offset - i > 16 { + break; + } + } + + if offset >= dsdt_data.len() { + log_warn!("PackageOp not found after _S5"); + continue; + } + + offset += 1; // 跳過 PackageOp + + // Parse PkgLength + let pkg_length = parse_pkg_length(&dsdt_data[offset..]); + offset += get_pkg_length_size(&dsdt_data[offset..]); + + // NumElements + let num_elements = dsdt_data[offset]; + offset += 1; + + log_debug!("Package length: {}, elements: {}", pkg_length, num_elements); + + if num_elements < 2 { + log_warn!("_S5 package has less than 2 elements"); + continue; + } + + // Extract SLP_TYPa + let slp_typa = parse_aml_integer(&dsdt_data[offset..]).unwrap_or(0); + offset += get_aml_integer_size(&dsdt_data[offset..]); + + // Extract SLP_TYPb + let slp_typb = parse_aml_integer(&dsdt_data[offset..]).unwrap_or(0); + + log_info!("Parsed _S5: SLP_TYPa={:#x}, SLP_TYPb={:#x}", slp_typa, slp_typb); + + return Some((slp_typa as u16, slp_typb as u16)); + } + } + + log_error!("_S5 object not found in DSDT"); + None + } +} + +/// Parse AML packet length +fn parse_pkg_length(data: &[u8]) -> usize { + if data.is_empty() { + return 0; + } + + let lead_byte = data[0]; + let byte_count = (lead_byte >> 6) as usize; + + match byte_count { + 0 => (lead_byte & 0x3F) as usize, + 1 => { + if data.len() < 2 { return 0; } + ((lead_byte & 0x0F) as usize) | ((data[1] as usize) << 4) + } + 2 => { + if data.len() < 3 { return 0; } + ((lead_byte & 0x0F) as usize) + | ((data[1] as usize) << 4) + | ((data[2] as usize) << 12) + } + 3 => { + if data.len() < 4 { return 0; } + ((lead_byte & 0x0F) as usize) + | ((data[1] as usize) << 4) + | ((data[2] as usize) << 12) + | ((data[3] as usize) << 20) + } + _ => 0, + } +} + +/// Get the number of bytes encoded by the packet length +fn get_pkg_length_size(data: &[u8]) -> usize { + if data.is_empty() { + return 0; + } + + let lead_byte = data[0]; + let byte_count = (lead_byte >> 6) as usize; + 1 + byte_count +} + +/// 解析 AML 整數 +fn parse_aml_integer(data: &[u8]) -> Option { + if data.is_empty() { + return None; + } + + match data[0] { + 0x00 => Some(0), // ZeroOp + 0x01 => Some(1), // OneOp + 0x0A => { // BytePrefix + if data.len() < 2 { return None; } + Some(data[1] as u64) + } + 0x0B => { // WordPrefix + if data.len() < 3 { return None; } + Some(u16::from_le_bytes([data[1], data[2]]) as u64) + } + 0x0C => { // DWordPrefix + if data.len() < 5 { return None; } + Some(u32::from_le_bytes([data[1], data[2], data[3], data[4]]) as u64) + } + 0x0E => { // QWordPrefix + if data.len() < 9 { return None; } + Some(u64::from_le_bytes([ + data[1], data[2], data[3], data[4], + data[5], data[6], data[7], data[8], + ])) + } + _ => None, + } +} + +/// Get the byte size of the AML integer +fn get_aml_integer_size(data: &[u8]) -> usize { + if data.is_empty() { + return 0; + } + + match data[0] { + 0x00 | 0x01 => 1, + 0x0A => 2, + 0x0B => 3, + 0x0C => 5, + 0x0E => 9, + _ => 1, + } +} + +/// Perform ACPI shutdown +pub fn acpi_shutdown() -> ! { + log_info!("Attempting ACPI shutdown..."); + + let power_info = unsafe { + match &ACPI_POWER_INFO { + Some(info) => info, + None => { + log_error!("ACPI power info not initialized!"); + return fallback_shutdown(); + } + } + }; + + unsafe { + let slp_cmd_a = (power_info.slp_typa << 10) | power_info.slp_en; + + log_info!("Writing {:#x} to PM1a_CNT ({:#x})", + slp_cmd_a, power_info.pm1a_control_block); + + // Write to PM1a control register + io::io_port_ww(power_info.pm1a_control_block as u16, slp_cmd_a); + + // If PM1b exists, also write + if power_info.pm1b_control_block != 0 { + let slp_cmd_b = (power_info.slp_typb << 10) | power_info.slp_en; + log_info!("Writing {:#x} to PM1b_CNT ({:#x})", + slp_cmd_b, power_info.pm1b_control_block); + io::io_port_ww(power_info.pm1b_control_block as u16, slp_cmd_b); + } + + // 等待關機 + for _ in 0..1000000 { + cpu::cpu_pause(100); + } + } + + log_error!("ACPI shutdown failed!"); + fallback_shutdown() +} + +/// Backup shutdown method +fn fallback_shutdown() -> ! { + log_warn!("Using fallback shutdown methods..."); + + unsafe { + // QEMU + io::io_port_ww(0x604, 0x2000); + cpu::cpu_pause(10000); + + // Bochs + for &c in b"Shutdown" { + io::io_port_wb(0x8900, c); + } + cpu::cpu_pause(10000); + + // VirtualBox + io::io_port_ww(0x4004, 0x3400); + } + + log_error!("All shutdown methods failed!"); + + loop { + cpu::cpu_halt(); + } +} + +/// Store ACPI shutdown information +pub fn store_power_info(info: AcpiPowerInfo) { + unsafe { + ACPI_POWER_INFO = Some(info); + } + log_info!("ACPI power info stored successfully"); +} \ No newline at end of file diff --git a/kernel/src/hal/mod.rs b/kernel/src/hal/mod.rs index 0ed70e9..bd4b081 100644 --- a/kernel/src/hal/mod.rs +++ b/kernel/src/hal/mod.rs @@ -4,4 +4,5 @@ pub mod acpi; pub mod rtc; pub mod lapic; pub mod ioapic; -pub mod timer; \ No newline at end of file +pub mod timer; +pub mod power; \ No newline at end of file diff --git a/kernel/src/hal/power.rs b/kernel/src/hal/power.rs new file mode 100644 index 0000000..eac9eae --- /dev/null +++ b/kernel/src/hal/power.rs @@ -0,0 +1,222 @@ +// kernel/src/hal/power.rs + +use crate::hal::{io, cpu, rtc}; +use crate::{log_info, log_debug, log_warn, log_error}; +use super::acpi; + +#[derive(Debug, Clone, Copy)] +pub enum PowerState { + S0, // Working + S1, // Sleep + S3, // Suspend to RAM + S4, // Suspend to Disk + S5, // Soft Off +} + +#[derive(Debug, Clone, Copy, PartialEq)] +pub enum ShutdownMethod { + Acpi, + QemuExit, + BochsExit, + VirtualBox, + Apm, +} +#[derive(Debug, Clone, Copy, PartialEq)] +pub enum RebootMethod { + BootACPI, + BootEFI, + BootKBD, + BootCF9, + Boot92h, +} + +pub fn shutdown() -> ! { + log_info!("Initiating system shutdown..."); + + log_info!("Disabling CPU interrupts"); + cpu::cpu_disable_interrupts(); + + log_info!("Shutting down the RTC Timer"); + rtc::disable_timer(); + + let methods = [ + ShutdownMethod::Acpi, + ShutdownMethod::QemuExit, + ShutdownMethod::BochsExit, + ShutdownMethod::VirtualBox, + ShutdownMethod::Apm, + ]; + + for method in methods.iter() { + log_debug!("Trying shutdown method: {:?}", method); + try_shutdown(*method); + + log_warn!("{:?} shutdown failed", method); + cpu::cpu_pause(1000); + } + + log_error!("All shutdown methods failed!"); + log_error!("System halted. Please power off manually."); + + loop { + cpu::cpu_halt(); + } +} + +fn try_shutdown(method: ShutdownMethod) { + unsafe { + match method { + ShutdownMethod::Acpi => { + acpi::power::acpi_shutdown(); + } + + ShutdownMethod::QemuExit => { + // QEMU isa-debug-exit 設備 + io::io_port_ww(0x604, 0x2000); + io::io_port_rl(0x501); + } + + ShutdownMethod::BochsExit => { + // Bochs 專用關機端口 + io::io_port_ww(0xB004, 0x2000); + } + + ShutdownMethod::VirtualBox => { + // VirtualBox 關機端口 + io::io_port_ww(0x4004, 0x3400); + } + + ShutdownMethod::Apm => { + // APM (Advanced Power Management) BIOS + // APM version 1.0 + io::io_port_wb(0x8900, 0x53); + io::io_port_wb(0x8900, 0x00); + io::io_port_wb(0x8900, 0x01); + io::io_port_wb(0x8900, 0x53); + } + } + + cpu::cpu_pause(10000); + } +} + +/// 重啟系統 +pub fn reboot() -> ! { + log_info!("Rebooting system..."); + + log_info!("Disabling CPU interrupts"); + cpu::cpu_disable_interrupts(); + + log_info!("Shutting down the RTC Timer"); + rtc::disable_timer(); + + let methods = [ + RebootMethod::BootACPI, + RebootMethod::BootEFI, + RebootMethod::BootKBD, + RebootMethod::BootCF9, + RebootMethod::Boot92h, + ]; + + for method in methods.iter() { + log_debug!("Trying shutdown method: {:?}", method); + try_reboot(*method); + + log_warn!("{:?} shutdown failed", method); + cpu::cpu_pause(1000); + } + + log_error!("All reboot methods failed!"); + log_error!("System halted. Please power off manually."); + + loop { + cpu::cpu_halt(); + } +} + +fn try_reboot(method: RebootMethod) { + match method { + RebootMethod::BootACPI => { + acpi_reboot() + } + + RebootMethod::BootKBD => { + keyboard_controller_reboot() + } + + RebootMethod::BootCF9 => { + pci_reboot() + } + RebootMethod::BootEFI => { + efi_reboot() + } + + RebootMethod::Boot92h => { + cpu_reset() + } + } + + cpu::cpu_pause(10000); +} + +fn acpi_reboot() { + log_debug!("Trying ACPI reboot..."); + + unsafe { + // ACPI FADT 的 RESET_REG + // 需要從 ACPI 表中讀取實際地址 + // 這裡使用常見的地址作為示例 + io::io_port_wb(0xCF9, 0x06); + cpu::cpu_pause(10000); + } +} + +fn keyboard_controller_reboot() { + log_debug!("Trying keyboard controller reboot..."); + + unsafe { + for _ in 0..1000 { + if (io::io_port_rb(0x64) & 0x02) == 0 { + break; + } + cpu::cpu_pause(10); + } + + io::io_port_wb(0x64, 0xFE); + + cpu::cpu_pause(100000); + } +} + +fn pci_reboot() { + log_debug!("Trying PCI reboot..."); + + unsafe { + let mut val = io::io_port_rb(0xCF9) & !0x06; + io::io_port_wb(0xCF9, val | 0x02); + cpu::cpu_pause(1000); + io::io_port_wb(0xCF9, val | 0x06); + + cpu::cpu_pause(100000); + } +} + + +fn efi_reboot() { + log_debug!("Trying EFI runtime services reboot..."); + + // TODO: 實現 EFI ResetSystem 調用 +} + +fn cpu_reset() { + log_debug!("Trying CPU reset via port 92h..."); + + unsafe { + let mut val = io::io_port_rb(0x92); + val &= !0x01; // 清除快速 A20 位 + val |= 0x01; // 設置重置位 + io::io_port_wb(0x92, val); + + cpu::cpu_pause(100000); + } +} \ No newline at end of file diff --git a/kernel/src/hal/timer.rs b/kernel/src/hal/timer.rs index 35866b6..cf7b9ba 100644 --- a/kernel/src/hal/timer.rs +++ b/kernel/src/hal/timer.rs @@ -38,7 +38,7 @@ static TICK_COUNTER: AtomicU64 = AtomicU64::new(0); // Calibration flag static IS_CALIBRATING: AtomicBool = AtomicBool::new(false); -static TIMEOUT: AtomicU64 = AtomicU64::new(0); +static TIMEOUT: AtomicU64 = AtomicU64::new(100_000_000); struct TimerConfig { base_frequency: u32, @@ -143,15 +143,14 @@ pub fn init(target_frequency: u32, apic_id: u8) -> bool { cpu::cpu_enable_interrupts(); - let mut timeout = 100_000_000; - while !unsafe { CALIBRATION.done } && timeout > 0 { + let mut remaining = TIMEOUT.load(Ordering::Relaxed); + while !unsafe { CALIBRATION.done } && remaining > 0 { cpu::cpu_pause(0); - timeout -= 1; + remaining -= 1; } - cpu::cpu_disable_interrupts(); - if timeout == 0 { + if remaining == 0 { log_error!("Calibration timeout!"); IS_CALIBRATING.store(false, Ordering::SeqCst); return false; diff --git a/kernel/src/kernel/k_init.rs b/kernel/src/kernel/k_init.rs index 076eec2..da5e29c 100644 --- a/kernel/src/kernel/k_init.rs +++ b/kernel/src/kernel/k_init.rs @@ -94,14 +94,10 @@ fn _memory_init( fn _display_init(framebuffer: &'static mut bootloader_api::info::FrameBuffer) { tty::init(framebuffer); tty::clear(0x000000); - - kprintln!("========================================"); - kprintln!(" CureOS Kernel v0.1.0" ); - kprintln!("========================================"); - kprintln!(); } fn _boot_report(memory_regions: &bootloader_api::info::MemoryRegions, physical_memory_offset: u64) { + kprintln!(); log_info!("GDT initialized"); gdt::print_info(); @@ -144,8 +140,8 @@ fn _acpi_init(rsdp_addr: Option, physical_memory_offset: u64) -> Option ! { _boot_report(&boot_info.memory_regions, physical_memory_offset); kprintln!(); - kprintln!("========================================"); - kprintln!(" Kernel Initialization Complete! "); - kprintln!("========================================"); + log_info!("System initialization complete!"); kprintln!(); k_main::_kernel_main(); diff --git a/kernel/src/kernel/k_main.rs b/kernel/src/kernel/k_main.rs index c9f3f1e..419f0e8 100644 --- a/kernel/src/kernel/k_main.rs +++ b/kernel/src/kernel/k_main.rs @@ -30,11 +30,7 @@ pub fn _kernel_main() -> ! { if let time = rtc::get_time() { kprintln!("Date/Time: {}", time.format()); } - - log_info!("{}", cpu::cpu_rdtscp()) ; - kprintln!(); - - log_info!("System initialization complete!"); + kprintln!(); kprintln!("Type 'help' for available commands"); kprintln!(); diff --git a/kernel/src/shell/commands.rs b/kernel/src/shell/commands.rs index 168a47a..e7274f1 100644 --- a/kernel/src/shell/commands.rs +++ b/kernel/src/shell/commands.rs @@ -1,15 +1,17 @@ // kernel/src/shell/commands.rs -use crate::{kprintln, tty, hal::{rtc, timer, cpu}, mm::allocator::pmm, log_info}; +use crate::{kprintln, tty, hal::{rtc, timer, cpu}, log_info}; use crate::hal::io::io_port_wb; - +use crate::hal::power; +use crate::mm::{vma, vmm, allocator::pmm}; /// help 命令 pub fn cmd_help() { - kprintln!(" help - Show this help message"); - kprintln!(" clear - Clear the screen"); - kprintln!(" time - Display current date and time"); - kprintln!(" uptime - Show system uptime"); - kprintln!(" sysinfo - Display system information"); - kprintln!(" reboot - Reboot the system"); + kprintln!(" help - Show this help message"); + kprintln!(" clear | clr - Clear the screen"); + kprintln!(" time - Display current date and time"); + kprintln!(" uptime - Show system uptime"); + kprintln!(" sysinfo | sys - Display system information"); + kprintln!(" meminfo | mem - Display memory information"); + kprintln!(" reboot - Reboot the system"); kprintln!(); } @@ -51,6 +53,93 @@ pub fn cmd_echo(text: &str) { } } +pub fn cmd_meminfo() { + kprintln!(); + kprintln!("=== Memory Layout ==="); + kprintln!(); + + // 高半核地址空間布局 + kprintln!("Virtual Memory Layout:"); + kprintln!(" User Space: {:#018x} - {:#018x}", + 0x0u64, + 0x0000_7FFF_FFFF_FFFFu64 + ); + kprintln!(" (Non-canonical): {:#018x} - {:#018x}", + 0x0000_8000_0000_0000u64, + 0xFFFF_7FFF_FFFF_FFFFu64 + ); + kprintln!(" Physical Map: {:#018x} - {:#018x}", + vma::PHYS_MEM_OFFSET, + vma::HIGHER_HALF_BASE - 1 + ); + kprintln!(" Kernel Base: {:#018x}", vma::HIGHER_HALF_BASE); + kprintln!(" Kernel Heap: {:#018x} - {:#018x} ({} KiB)", + vma::HEAP_START.as_u64(), + vma::HEAP_START.as_u64() + vma::HEAP_SIZE as u64, + vma::HEAP_SIZE / 1024 + ); + kprintln!(" Kernel Dynamic: {:#018x} - {:#018x} ({} MiB)", + vma::KERNEL_DYNAMIC_START.as_u64(), + vma::KERNEL_DYNAMIC_END.as_u64(), + vma::KERNEL_DYNAMIC_SIZE / (1024 * 1024) + ); + kprintln!(" Kernel Stack: {:#018x} - {:#018x} ({} MiB)", + vma::KERNEL_STACK_START.as_u64(), + vma::KERNEL_STACK_END.as_u64(), + vma::KERNEL_STACK_SIZE / (1024 * 1024) + ); + kprintln!(" Device Mapping: {:#018x} - {:#018x} ({} MiB)", + vma::DEVICE_MAPPING_START.as_u64(), + vma::DEVICE_MAPPING_END.as_u64(), + vma::DEVICE_MAPPING_SIZE / (1024 * 1024) + ); + + kprintln!(); + kprintln!("Physical Memory (PMM):"); + + if let Some(stats) = pmm::get_memory_stats() { + kprintln!(" Total: {} MiB ({} frames)", + stats.total_memory / (1024 * 1024), + stats.total_frames + ); + kprintln!(" Used: {} MiB ({} frames)", + stats.used_memory / (1024 * 1024), + stats.allocated_frames + ); + kprintln!(" Free: {} MiB ({} frames)", + stats.free_memory / (1024 * 1024), + stats.free_frames + ); + kprintln!(" Usage: {}%", + (stats.used_memory * 100) / stats.total_memory + ); + } else { + kprintln!(" (PMM not initialized)"); + } + + kprintln!(); + kprintln!("Virtual Memory Manager (VMM):"); + + let vmm_stats = vmm::get_vmm_stats(); + kprintln!(" Next Address: {:#018x}", vmm_stats.next_vaddr.as_u64()); + kprintln!(" Allocated: {} pages ({} KiB) in {} blocks", + vmm_stats.allocated_pages, + vmm_stats.allocated_pages * 4, + vmm_stats.allocated_blocks_count + ); + kprintln!(" Free: {} pages ({} KiB) in {} blocks", + vmm_stats.free_pages, + vmm_stats.free_pages * 4, + vmm_stats.free_blocks_count + ); + kprintln!(" New Usage: {} pages ({} KiB)", + vmm_stats.used_from_new, + vmm_stats.used_from_new * 4 + ); + + kprintln!(); +} + pub fn cmd_sysinfo() { kprintln!(); kprintln!("=== System Information ==="); @@ -81,58 +170,17 @@ pub fn cmd_sysinfo() { kprintln!(); } +pub fn cmd_shutdown() { + kprintln!("Shutdown system..."); + cpu::cpu_pause(1000); + tty::tty::clear(0x000000); + power::shutdown(); +} + pub fn cmd_reboot() { kprintln!("Rebooting system..."); - cpu::cpu_pause(1000); tty::tty::clear(0x000000); - log_info!("Disabling CPU interrupts"); - cpu::cpu_disable_interrupts(); - - log_info!("Disabling RTC Timer"); - rtc::disable_timer(); - - unsafe { - io_port_wb(0x64, 0xFE); - - log_info!("Complete"); - - loop { - cpu::cpu_halt(); - } - } -} - -pub fn cmd_halt() { - kprintln!("System Statistics:"); - - let ticks = timer::get_tick_count(); - let total_seconds = ticks / 100; - let hours = total_seconds / 3600; - let minutes = (total_seconds % 3600) / 60; - let seconds = total_seconds % 60; - kprintln!(" Uptime: {}h {}m {}s", hours, minutes, seconds); - - if let Some(stats) = pmm::get_memory_stats() { - kprintln!(" Memory Used: {} MiB / {} MiB", - stats.used_memory / (1024 * 1024), - stats.total_memory / (1024 * 1024)); - } - - if let time = rtc::get_time() { - kprintln!(" Shutdown at: {}", time.format()); - } - - kprintln!(); - kprintln!("System halted. Safe to power off."); - kprintln!(); - - cpu::cpu_disable_interrupts(); - - rtc::disable_timer(); - - loop { - cpu::cpu_halt(); - } + power::reboot(); } diff --git a/kernel/src/shell/math.rs b/kernel/src/shell/math.rs new file mode 100644 index 0000000..8544055 --- /dev/null +++ b/kernel/src/shell/math.rs @@ -0,0 +1,138 @@ +use alloc::string::String; +use alloc::vec::Vec; +use crate::kprint; + +#[derive(Debug)] +pub enum CalcError { + UnexpectedChar(char), + UnexpectedEnd, + DivisionByZero, + InvalidNumber, +} + +pub fn eval_expression(expr: &str) -> Result { + let mut parser = Parser::new(expr); + let result = parser.parse_expr()?; + parser.skip_whitespace(); + if parser.pos < parser.chars.len() { + Err(CalcError::UnexpectedChar(parser.chars[parser.pos])) + } else { + Ok(result) + } +} + +struct Parser<'a> { + chars: Vec, + pos: usize, + _expr: &'a str, +} + +impl<'a> Parser<'a> { + fn new(expr: &'a str) -> Self { + Self { + chars: expr.chars().collect(), + pos: 0, + _expr: expr, + } + } + + fn peek(&self) -> Option { + self.chars.get(self.pos).cloned() + } + + fn next(&mut self) -> Option { + let c = self.chars.get(self.pos).cloned(); + if c.is_some() { + self.pos += 1; + } + c + } + + fn skip_whitespace(&mut self) { + while let Some(c) = self.peek() { + if c.is_whitespace() { + self.pos += 1; + } else { + break; + } + } + } + fn parse_number(&mut self) -> Result { + self.skip_whitespace(); + let start = self.pos; + while let Some(c) = self.peek() { + if c.is_ascii_digit() || c == '.' { + self.pos += 1; + } else { + break; + } + } + if start == self.pos { + return Err(CalcError::InvalidNumber); + } + let s: String = self.chars[start..self.pos].iter().collect(); + s.parse::().map_err(|_| CalcError::InvalidNumber) + } + + fn parse_factor(&mut self) -> Result { + self.skip_whitespace(); + match self.peek() { + Some('(') => { + self.next(); + let val = self.parse_expr()?; + self.skip_whitespace(); + if self.next() != Some(')') { + return Err(CalcError::UnexpectedEnd); + } + Ok(val) + } + Some('-') => { + self.next(); + Ok(-self.parse_factor()?) + } + _ => self.parse_number(), + } + } + + fn parse_term(&mut self) -> Result { + let mut val = self.parse_factor()?; + loop { + self.skip_whitespace(); + match self.peek() { + Some('*') => { + self.next(); + val *= self.parse_factor()?; + } + Some('/') => { + self.next(); + let rhs = self.parse_factor()?; + if rhs == 0.0 { + return Err(CalcError::DivisionByZero); + } + val /= rhs; + } + _ => break, + } + } + Ok(val) + } + + fn parse_expr(&mut self) -> Result { + let mut val = self.parse_term()?; + loop { + self.skip_whitespace(); + match self.peek() { + Some('+') => { + self.next(); + val += self.parse_term()?; + } + Some('-') => { + self.next(); + val -= self.parse_term()?; + } + _ => break, + } + } + Ok(val) + } +} diff --git a/kernel/src/shell/mod.rs b/kernel/src/shell/mod.rs index 37116b7..5902855 100644 --- a/kernel/src/shell/mod.rs +++ b/kernel/src/shell/mod.rs @@ -4,6 +4,7 @@ use spin::Mutex; use crate::{kprint, kprintln, tty, hal::{rtc, timer}}; pub mod commands; +pub mod math; static COMMAND_BUFFER: Mutex = Mutex::new(String::new()); @@ -12,7 +13,7 @@ pub fn init() { } pub fn show_prompt() { - kprint!("cure > "); + tty::tty::write_str("cure > ", 0x00FF00); } pub fn process_keyboard_char(c: char) { @@ -37,23 +38,29 @@ pub fn process_keyboard_char(c: char) { } fn execute_command(cmd: &str) { - let cmd = cmd.trim(); + let mut cmd = cmd.trim(); if cmd.is_empty() { return; } - + match cmd { "help" => commands::cmd_help(), - "clear" => commands::cmd_clear(), + "clear" | "clr" => commands::cmd_clear(), "time" => commands::cmd_time(), "uptime" => commands::cmd_uptime(), - "sysinfo" => commands::cmd_sysinfo(), + "sysinfo" | "sys" => commands::cmd_sysinfo(), + "meminfo" | "mem" => commands::cmd_meminfo(), "reboot" => commands::cmd_reboot(), - "halt" | "shutdown" | "poweroff" => commands::cmd_halt(), + "halt" | "shutdown" | "poweroff" => commands::cmd_shutdown(), _ => { - kprintln!("Unknown command: '{}'", cmd); - kprintln!("Type 'help' for available commands"); + match math::eval_expression(cmd) { + Ok(result) => kprintln!("{}", result), + Err(_) => { + kprintln!("Unknown command: '{}'", cmd); + kprintln!("Type 'help' for available commands"); + } + } } } } \ No newline at end of file diff --git a/kernel/src/tty/tty.rs b/kernel/src/tty/tty.rs index 62ff4e5..dc06676 100644 --- a/kernel/src/tty/tty.rs +++ b/kernel/src/tty/tty.rs @@ -128,6 +128,28 @@ impl TTYState { return; } + if c == '\x08' { + if self.cursor_x >= CHAR_WIDTH { + self.cursor_x -= CHAR_WIDTH; + + for y in 0..CHAR_HEIGHT { + for x in 0..CHAR_WIDTH { + self.draw_pixel(self.cursor_x + x, self.cursor_y + y, 0x000000); + } + } + } else if self.cursor_y >= CHAR_HEIGHT { + self.cursor_y -= CHAR_HEIGHT; + self.cursor_x = (self.info.width / CHAR_WIDTH - 1) * CHAR_WIDTH; + + for y in 0..CHAR_HEIGHT { + for x in 0..CHAR_WIDTH { + self.draw_pixel(self.cursor_x + x, self.cursor_y + y, 0x000000); + } + } + } + return; + } + if c == '\n' { self.cursor_x = 0; self.cursor_y += CHAR_HEIGHT; @@ -160,6 +182,9 @@ impl TTYState { for x in 0..8 { if (row >> (7 - x)) & 1 == 1 { self.draw_pixel(cursor_x + x, cursor_y + y, color); + } else { + // 同時清除背景 + self.draw_pixel(cursor_x + x, cursor_y + y, 0x000000); } } } From 687c59f467b3b1d97e25240de837b56ecf3a279f Mon Sep 17 00:00:00 2001 From: ParrotXray Date: Sat, 18 Oct 2025 12:59:07 +0800 Subject: [PATCH 11/13] fix: Fix ACPI shutdown --- kernel/src/hal/acpi/init.rs | 71 +++++++----- kernel/src/hal/acpi/mod.rs | 16 +-- kernel/src/hal/acpi/power.rs | 207 ++++++++++++++++++++++------------- 3 files changed, 179 insertions(+), 115 deletions(-) diff --git a/kernel/src/hal/acpi/init.rs b/kernel/src/hal/acpi/init.rs index c9f9445..12728db 100644 --- a/kernel/src/hal/acpi/init.rs +++ b/kernel/src/hal/acpi/init.rs @@ -1,22 +1,19 @@ -use acpi::{aml, sdt, AcpiTables, Handle, Handler, PciAddress, PhysicalMapping}; -use acpi::platform::{AcpiPlatform, interrupt::InterruptModel, PciConfigRegions}; -use acpi::sdt::hpet::HpetInfo; -use acpi::rsdp::Rsdp; -use core::ptr::NonNull; -use core::mem; -use crate::kprintln; -use crate::{log_trace, log_debug, log_info, log_warn, log_error, log_fatal}; +use super::power::{extract_power_info, store_power_info}; +use super::{AcpiInfo, CureAcpiHandler}; use crate::hal::{cpu, io}; -use super::*; - +use crate::kprintln; +use crate::{log_debug, log_error, log_fatal, log_info, log_trace, log_warn}; +use acpi::platform::{interrupt::InterruptModel, AcpiPlatform, PciConfigRegions}; +use acpi::rsdp::Rsdp; +use acpi::sdt::hpet::HpetInfo; +use acpi::{aml, sdt, AcpiTables, Handle, Handler, PciAddress, PhysicalMapping}; +use core::{mem, ptr::NonNull}; pub fn init(rsdp_addr: u64, physical_memory_offset: u64) -> Option { - let handler = CureAcpiHandler::new(physical_memory_offset); - let rsdp_mapping = unsafe { - handler.map_physical_region::(rsdp_addr as usize, mem::size_of::()) - }; + let rsdp_mapping = + unsafe { handler.map_physical_region::(rsdp_addr as usize, size_of::()) }; let revision = rsdp_mapping.revision(); log_info!("ACPI Revision: {}", revision); @@ -62,8 +59,13 @@ pub fn init(rsdp_addr: u64, physical_memory_offset: u64) -> Option { let mut io_apics = alloc::vec::Vec::new(); for (i, io_apic) in apic.io_apics.iter().enumerate() { - log_info!("IO APIC {}: ID={}, Address={:#x}, GSI Base={}", - i, io_apic.id, io_apic.address, io_apic.global_system_interrupt_base); + log_info!( + "IO APIC {}: ID={}, Address={:#x}, GSI Base={}", + i, + io_apic.id, + io_apic.address, + io_apic.global_system_interrupt_base + ); io_apics.push(( io_apic.address as u64, @@ -89,7 +91,10 @@ pub fn init(rsdp_addr: u64, physical_memory_offset: u64) -> Option { log_info!("Base Address: {:#x}", hpet.base_address); log_info!("Hardware Rev: {}", hpet.hardware_rev); log_info!("Comparator Count: {}", hpet.num_comparators); - log_info!("Counter Size: {} bit", if hpet.main_counter_is_64bits { 64 } else { 32 }); + log_info!( + "Counter Size: {} bit", + if hpet.main_counter_is_64bits { 64 } else { 32 } + ); log_info!("Legacy IRQ Capable: {}", hpet.legacy_irq_capable); log_info!("PCI Vendor ID: {:#x}", hpet.pci_vendor_id); true @@ -114,13 +119,12 @@ pub fn init(rsdp_addr: u64, physical_memory_offset: u64) -> Option { } kprintln!(); - log_info!("Extracting ACPI power management info..."); - // if let Some(power_info) = extract_power_info(&platform.tables) { - // store_power_info(power_info); - // } else { - // log_warn!("Could not extract ACPI power info, shutdown may not work"); - // } - + log_info!("Extracting power management information..."); + if let Some(power_info) = extract_power_info(&platform.tables, &handler) { + store_power_info(power_info); + } else { + log_warn!("Could not extract ACPI power info"); + } log_info!("ACPI initialized successfully!"); @@ -142,7 +146,20 @@ pub fn print_info(info: &AcpiInfo) { if let Some(boot_proc) = info.boot_processor { log_info!("Boot Processor: UID {}", boot_proc); } - log_info!("APIC: {}", if info.has_apic { "Available " } else { "Not available" }); - log_info!("HPET: {}", if info.has_hpet { "Available " } else { "Not available" }); + log_info!( + "APIC: {}", + if info.has_apic { + "Available " + } else { + "Not available" + } + ); + log_info!( + "HPET: {}", + if info.has_hpet { + "Available " + } else { + "Not available" + } + ); } - diff --git a/kernel/src/hal/acpi/mod.rs b/kernel/src/hal/acpi/mod.rs index fd97adf..27d5d82 100644 --- a/kernel/src/hal/acpi/mod.rs +++ b/kernel/src/hal/acpi/mod.rs @@ -1,14 +1,9 @@ -pub mod power; pub mod init; +pub mod power; -use acpi::{aml, sdt, AcpiTables, Handle, Handler, PciAddress, PhysicalMapping}; -use acpi::sdt::hpet::HpetInfo; -use core::ptr::NonNull; -use core::mem; -use crate::kprintln; -use crate::{log_trace, log_debug, log_info, log_warn, log_error, log_fatal}; use crate::hal::{cpu, io}; - +use acpi::{aml, Handle, Handler, PciAddress, PhysicalMapping}; +use core::ptr::NonNull; #[derive(Clone, Copy)] pub struct CureAcpiHandler { @@ -25,7 +20,7 @@ pub struct AcpiInfo { pub io_apics: alloc::vec::Vec<(u64, u8, u32)>, // (address, id, gsi_base) } -/// ACPI 關機所需的信息 +/// Information required for ACPI shutdown pub struct AcpiPowerInfo { pub pm1a_control_block: u32, pub pm1b_control_block: u32, @@ -184,7 +179,6 @@ impl Handler for CureAcpiHandler { // TODO: 實作微秒級延遲 // 簡單的忙等待實作 cpu::cpu_pause(_microseconds * 1000); - } fn sleep(&self, _milliseconds: u64) { @@ -208,4 +202,4 @@ impl Handler for CureAcpiHandler { fn release(&self, _handle: Handle) { // TODO: 實作 Mutex 釋放 } -} \ No newline at end of file +} diff --git a/kernel/src/hal/acpi/power.rs b/kernel/src/hal/acpi/power.rs index 2f3199a..0a496b3 100644 --- a/kernel/src/hal/acpi/power.rs +++ b/kernel/src/hal/acpi/power.rs @@ -1,15 +1,18 @@ -use acpi::{aml, sdt, AcpiTables, Handle, Handler, PciAddress, PhysicalMapping}; -use acpi::platform::{AcpiPlatform, interrupt::InterruptModel, PciConfigRegions}; -use core::mem; -use crate::kprintln; -use crate::{log_trace, log_debug, log_info, log_warn, log_error, log_fatal}; +use super::{AcpiPowerInfo, CureAcpiHandler, ACPI_POWER_INFO}; use crate::hal::{cpu, io}; +use crate::kprintln; use crate::mm::vma; -use super::*; - +use crate::{log_debug, log_error, log_fatal, log_info, log_trace, log_warn}; +use acpi::platform::{interrupt::InterruptModel, AcpiPlatform, PciConfigRegions}; +use acpi::sdt::{SdtHeader, Signature}; +use acpi::{aml, sdt, AcpiTables, Handle, Handler, PciAddress, PhysicalMapping}; +use core::mem; /// Extract shutdown information from ACPI table -pub fn extract_power_info(tables: &AcpiTables) -> Option { +pub fn extract_power_info( + tables: &AcpiTables, + handler: &CureAcpiHandler, +) -> Option { log_info!("Extracting ACPI power management info..."); let fadt = match tables.find_table::() { @@ -20,18 +23,12 @@ pub fn extract_power_info(tables: &AcpiTables) -> Option= 2 { let x_dsdt = core::ptr::read_unaligned(fadt_ptr.add(140) as *const u64); @@ -50,8 +47,7 @@ pub fn extract_power_info(tables: &AcpiTables) -> Option values, None => { log_warn!("Could not parse _S5 object, using default values"); @@ -82,88 +78,124 @@ pub fn extract_power_info(tables: &AcpiTables) -> Option Option<(u16, u16)> { - let dsdt_virt_addr = vma::phys_to_virt(dsdt_phys_addr); +fn parse_s5_object(dsdt_phys_addr: u64, handler: &CureAcpiHandler) -> Option<(u16, u16)> { + log_debug!("Parsing DSDT at physical address {:#x}", dsdt_phys_addr); + + // Map the DSDT header first to get the length + let dsdt_header_mapping = unsafe { + handler.map_physical_region::( + dsdt_phys_addr as usize, + size_of::(), + ) + }; + + if dsdt_header_mapping.signature != Signature::DSDT { + log_error!("Invalid DSDT signature"); + return None; + } + + let dsdt_length = dsdt_header_mapping.length as usize; + log_debug!("DSDT length: {} bytes", dsdt_length); + + // Release the header mapping + drop(dsdt_header_mapping); + + // 映射完整的 DSDT + let dsdt_mapping = + unsafe { handler.map_physical_region::(dsdt_phys_addr as usize, dsdt_length) }; unsafe { - let dsdt_ptr = dsdt_virt_addr.as_ptr::(); + let dsdt_ptr = dsdt_mapping.virtual_start.as_ptr(); + let dsdt_data = core::slice::from_raw_parts(dsdt_ptr, dsdt_length); - // DSDT header - let signature = core::slice::from_raw_parts(dsdt_ptr, 4); - if signature != b"DSDT" { - log_error!("Invalid DSDT signature"); - return None; - } - - // Get DSDT length - let length = core::ptr::read_unaligned(dsdt_ptr.add(4) as *const u32); - log_debug!("DSDT length: {} bytes", length); - - // Search for the "_S5_" string in DSDT - let dsdt_data = core::slice::from_raw_parts(dsdt_ptr, length as usize); - - // Byte representation of "_S5_" in AML + // 在 DSDT 中搜索 "_S5_" let s5_name = b"_S5_"; for i in 0..(dsdt_data.len() - 4) { - if &dsdt_data[i..i+4] == s5_name { + if &dsdt_data[i..i + 4] == s5_name { log_debug!("Found _S5 at offset {:#x}", i); - // Parse the _S5 package - // Typical AML bytecode: - // Name(_S5, Package() {...}) - // Or: 08 5F 53 35 5F 12 [pkg_length] [num_elements] ... + let debug_range = i..core::cmp::min(i + 32, dsdt_data.len()); + log_debug!("_S5 region bytes: {:02x?}", &dsdt_data[debug_range]); - let mut offset = i + 4; + let mut offset = i + 4; // Skip "_S5_" - // Skip possible NameOp (0x08) - if offset < dsdt_data.len() && dsdt_data[offset] == 0x08 { - offset += 1; - } - - // Find PackageOp (0x12) - while offset < dsdt_data.len() && dsdt_data[offset] != 0x12 { - offset += 1; - if offset - i > 16 { + // Skip any intermediate bytes and go straight to PackageOp + let search_limit = offset + 8; + while offset < search_limit && offset < dsdt_data.len() { + if dsdt_data[offset] == 0x12 { + log_debug!("Found PackageOp at offset {:#x}", offset); break; } + offset += 1; } - if offset >= dsdt_data.len() { + if offset >= dsdt_data.len() || dsdt_data[offset] != 0x12 { log_warn!("PackageOp not found after _S5"); continue; } - offset += 1; // 跳過 PackageOp + offset += 1; // Skip PackageOp (0x12) + + log_debug!("Found _S5 at offset {:#x}", i); + log_debug!("Found _S5 at offset {:#x}", i); // Parse PkgLength let pkg_length = parse_pkg_length(&dsdt_data[offset..]); - offset += get_pkg_length_size(&dsdt_data[offset..]); + let pkg_length_size = get_pkg_length_size(&dsdt_data[offset..]); + log_debug!("PkgLength: {}, size: {}", pkg_length, pkg_length_size); + offset += pkg_length_size; // NumElements + if offset >= dsdt_data.len() { + log_warn!("Unexpected end of data"); + continue; + } let num_elements = dsdt_data[offset]; offset += 1; - log_debug!("Package length: {}, elements: {}", pkg_length, num_elements); + log_debug!("Package elements: {}", num_elements); if num_elements < 2 { log_warn!("_S5 package has less than 2 elements"); continue; } + log_debug!( + "Current offset: {:#x}, next bytes: {:02x?}", + offset, + &dsdt_data[offset..core::cmp::min(offset + 8, dsdt_data.len())] + ); + // Extract SLP_TYPa + log_debug!( + "Reading SLP_TYPa at offset {:#x}, byte: {:#x}", + offset, + dsdt_data[offset] + ); let slp_typa = parse_aml_integer(&dsdt_data[offset..]).unwrap_or(0); - offset += get_aml_integer_size(&dsdt_data[offset..]); + log_debug!("SLP_TYPa parsed: {:#x}", slp_typa); + let typa_size = get_aml_integer_size(&dsdt_data[offset..]); + offset += typa_size; // Extract SLP_TYPb + log_debug!( + "Reading SLP_TYPb at offset {:#x}, byte: {:#x}", + offset, + dsdt_data[offset] + ); let slp_typb = parse_aml_integer(&dsdt_data[offset..]).unwrap_or(0); + log_debug!("SLP_TYPb parsed: {:#x}", slp_typb); - log_info!("Parsed _S5: SLP_TYPa={:#x}, SLP_TYPb={:#x}", slp_typa, slp_typb); + log_info!( + "Parsed _S5: SLP_TYPa={:#x}, SLP_TYPb={:#x}", + slp_typa, + slp_typb + ); return Some((slp_typa as u16, slp_typb as u16)); } } - log_error!("_S5 object not found in DSDT"); None } @@ -181,17 +213,21 @@ fn parse_pkg_length(data: &[u8]) -> usize { match byte_count { 0 => (lead_byte & 0x3F) as usize, 1 => { - if data.len() < 2 { return 0; } + if data.len() < 2 { + return 0; + } ((lead_byte & 0x0F) as usize) | ((data[1] as usize) << 4) } 2 => { - if data.len() < 3 { return 0; } - ((lead_byte & 0x0F) as usize) - | ((data[1] as usize) << 4) - | ((data[2] as usize) << 12) + if data.len() < 3 { + return 0; + } + ((lead_byte & 0x0F) as usize) | ((data[1] as usize) << 4) | ((data[2] as usize) << 12) } 3 => { - if data.len() < 4 { return 0; } + if data.len() < 4 { + return 0; + } ((lead_byte & 0x0F) as usize) | ((data[1] as usize) << 4) | ((data[2] as usize) << 12) @@ -221,23 +257,34 @@ fn parse_aml_integer(data: &[u8]) -> Option { match data[0] { 0x00 => Some(0), // ZeroOp 0x01 => Some(1), // OneOp - 0x0A => { // BytePrefix - if data.len() < 2 { return None; } + 0x0A => { + // BytePrefix + if data.len() < 2 { + return None; + } Some(data[1] as u64) } - 0x0B => { // WordPrefix - if data.len() < 3 { return None; } + 0x0B => { + // WordPrefix + if data.len() < 3 { + return None; + } Some(u16::from_le_bytes([data[1], data[2]]) as u64) } - 0x0C => { // DWordPrefix - if data.len() < 5 { return None; } + 0x0C => { + // DWordPrefix + if data.len() < 5 { + return None; + } Some(u32::from_le_bytes([data[1], data[2], data[3], data[4]]) as u64) } - 0x0E => { // QWordPrefix - if data.len() < 9 { return None; } + 0x0E => { + // QWordPrefix + if data.len() < 9 { + return None; + } Some(u64::from_le_bytes([ - data[1], data[2], data[3], data[4], - data[5], data[6], data[7], data[8], + data[1], data[2], data[3], data[4], data[5], data[6], data[7], data[8], ])) } _ => None, @@ -277,8 +324,11 @@ pub fn acpi_shutdown() -> ! { unsafe { let slp_cmd_a = (power_info.slp_typa << 10) | power_info.slp_en; - log_info!("Writing {:#x} to PM1a_CNT ({:#x})", - slp_cmd_a, power_info.pm1a_control_block); + log_info!( + "Writing {:#x} to PM1a_CNT ({:#x})", + slp_cmd_a, + power_info.pm1a_control_block + ); // Write to PM1a control register io::io_port_ww(power_info.pm1a_control_block as u16, slp_cmd_a); @@ -286,8 +336,11 @@ pub fn acpi_shutdown() -> ! { // If PM1b exists, also write if power_info.pm1b_control_block != 0 { let slp_cmd_b = (power_info.slp_typb << 10) | power_info.slp_en; - log_info!("Writing {:#x} to PM1b_CNT ({:#x})", - slp_cmd_b, power_info.pm1b_control_block); + log_info!( + "Writing {:#x} to PM1b_CNT ({:#x})", + slp_cmd_b, + power_info.pm1b_control_block + ); io::io_port_ww(power_info.pm1b_control_block as u16, slp_cmd_b); } @@ -333,4 +386,4 @@ pub fn store_power_info(info: AcpiPowerInfo) { ACPI_POWER_INFO = Some(info); } log_info!("ACPI power info stored successfully"); -} \ No newline at end of file +} From 8bae31852d7b4006c0b6a7d1076cb66aafd4f3b1 Mon Sep 17 00:00:00 2001 From: ParrotXray Date: Sat, 18 Oct 2025 16:04:48 +0800 Subject: [PATCH 12/13] feat: ACPI reboot implementation --- TODO.txt | 3 +- kernel/src/arch/amd64/isr.rs | 5 +- kernel/src/hal/acpi/init.rs | 10 +- kernel/src/hal/acpi/mod.rs | 10 ++ kernel/src/hal/acpi/power.rs | 248 ++++++++++++++++++++++------ kernel/src/hal/{ => apic}/ioapic.rs | 106 +----------- kernel/src/hal/{ => apic}/lapic.rs | 74 +-------- kernel/src/hal/apic/mod.rs | 163 ++++++++++++++++++ kernel/src/hal/mod.rs | 5 +- kernel/src/hal/power.rs | 59 +++---- kernel/src/hal/timer.rs | 7 +- kernel/src/kernel/k_init.rs | 7 +- 12 files changed, 433 insertions(+), 264 deletions(-) rename kernel/src/hal/{ => apic}/ioapic.rs (68%) rename kernel/src/hal/{ => apic}/lapic.rs (78%) create mode 100644 kernel/src/hal/apic/mod.rs diff --git a/TODO.txt b/TODO.txt index 75d4b79..c9bbc43 100644 --- a/TODO.txt +++ b/TODO.txt @@ -22,8 +22,7 @@ // - 用戶態/內核態切換 -// BUG -// - ACPI 關機 mem 映射問題 +// 5. 回收 // - 關機重啟回收記憶體 // ==================== 高半核地址空間佈局 ==================== diff --git a/kernel/src/arch/amd64/isr.rs b/kernel/src/arch/amd64/isr.rs index aac96fb..7288ef6 100644 --- a/kernel/src/arch/amd64/isr.rs +++ b/kernel/src/arch/amd64/isr.rs @@ -3,9 +3,10 @@ use x86_64::instructions::port::Port; 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::{log_debug, log_error, log_fatal, log_info, log_trace, log_warn}; use super::gdt; -use crate::hal::{timer, cpu, lapic, rtc}; +use crate::hal::{cpu, rtc, timer}; +use crate::hal::apic::lapic; use crate::mm::paging; /// Divide Error (#DE) diff --git a/kernel/src/hal/acpi/init.rs b/kernel/src/hal/acpi/init.rs index 12728db..21cfb21 100644 --- a/kernel/src/hal/acpi/init.rs +++ b/kernel/src/hal/acpi/init.rs @@ -1,4 +1,4 @@ -use super::power::{extract_power_info, store_power_info}; +use super::power::{extract_power_info, extract_reset_reg, store_power_info, store_reset_reg}; use super::{AcpiInfo, CureAcpiHandler}; use crate::hal::{cpu, io}; use crate::kprintln; @@ -126,6 +126,14 @@ pub fn init(rsdp_addr: u64, physical_memory_offset: u64) -> Option { log_warn!("Could not extract ACPI power info"); } + kprintln!(); + log_info!("Extracting reset register information..."); + if let Some(reset_reg) = extract_reset_reg(&platform.tables) { + store_reset_reg(reset_reg); + } else { + log_warn!("Could not extract ACPI reset register"); + } + log_info!("ACPI initialized successfully!"); Some(AcpiInfo { diff --git a/kernel/src/hal/acpi/mod.rs b/kernel/src/hal/acpi/mod.rs index 27d5d82..53c478e 100644 --- a/kernel/src/hal/acpi/mod.rs +++ b/kernel/src/hal/acpi/mod.rs @@ -29,6 +29,16 @@ pub struct AcpiPowerInfo { pub slp_en: u16, } +/// ACPI 重置寄存器信息 +#[derive(Debug, Clone, Copy)] +pub struct ResetRegister { + pub address_space: u8, // 0=SystemMemory, 1=SystemIO, 2=PciConfig + pub address: u64, + pub value: u8, +} + +static mut ACPI_RESET_REG: Option = None; + static mut ACPI_POWER_INFO: Option = None; impl CureAcpiHandler { diff --git a/kernel/src/hal/acpi/power.rs b/kernel/src/hal/acpi/power.rs index 0a496b3..fc05423 100644 --- a/kernel/src/hal/acpi/power.rs +++ b/kernel/src/hal/acpi/power.rs @@ -1,4 +1,4 @@ -use super::{AcpiPowerInfo, CureAcpiHandler, ACPI_POWER_INFO}; +use super::{AcpiPowerInfo, CureAcpiHandler, ResetRegister, ACPI_POWER_INFO, ACPI_RESET_REG}; use crate::hal::{cpu, io}; use crate::kprintln; use crate::mm::vma; @@ -83,10 +83,7 @@ fn parse_s5_object(dsdt_phys_addr: u64, handler: &CureAcpiHandler) -> Option<(u1 // Map the DSDT header first to get the length let dsdt_header_mapping = unsafe { - handler.map_physical_region::( - dsdt_phys_addr as usize, - size_of::(), - ) + handler.map_physical_region::(dsdt_phys_addr as usize, size_of::()) }; if dsdt_header_mapping.signature != Signature::DSDT { @@ -108,7 +105,7 @@ fn parse_s5_object(dsdt_phys_addr: u64, handler: &CureAcpiHandler) -> Option<(u1 let dsdt_ptr = dsdt_mapping.virtual_start.as_ptr(); let dsdt_data = core::slice::from_raw_parts(dsdt_ptr, dsdt_length); - // 在 DSDT 中搜索 "_S5_" + // Search DSDT for "_S5_" let s5_name = b"_S5_"; for i in 0..(dsdt_data.len() - 4) { @@ -121,7 +118,7 @@ fn parse_s5_object(dsdt_phys_addr: u64, handler: &CureAcpiHandler) -> Option<(u1 let mut offset = i + 4; // Skip "_S5_" // Skip any intermediate bytes and go straight to PackageOp - let search_limit = offset + 8; + let search_limit = offset + 16; while offset < search_limit && offset < dsdt_data.len() { if dsdt_data[offset] == 0x12 { log_debug!("Found PackageOp at offset {:#x}", offset); @@ -248,15 +245,16 @@ fn get_pkg_length_size(data: &[u8]) -> usize { 1 + byte_count } -/// 解析 AML 整數 +/// Parse AML integer fn parse_aml_integer(data: &[u8]) -> Option { if data.is_empty() { return None; } match data[0] { - 0x00 => Some(0), // ZeroOp - 0x01 => Some(1), // OneOp + 0x00 => Some(0), // ZeroOp + 0x01 => Some(1), // OneOp + 0xFF => Some(0xFFFFFFFF), // OnesOp 0x0A => { // BytePrefix if data.len() < 2 { @@ -287,7 +285,10 @@ fn parse_aml_integer(data: &[u8]) -> Option { data[1], data[2], data[3], data[4], data[5], data[6], data[7], data[8], ])) } - _ => None, + _ => { + log_warn!("Unknown AML integer prefix: {:#02x}", data[0]); + None + } } } @@ -298,17 +299,17 @@ fn get_aml_integer_size(data: &[u8]) -> usize { } match data[0] { - 0x00 | 0x01 => 1, - 0x0A => 2, - 0x0B => 3, - 0x0C => 5, - 0x0E => 9, + 0x00 | 0x01 | 0xFF => 1, // Zero, One, Ones + 0x0A => 2, // Byte + 0x0B => 3, // Word + 0x0C => 5, // DWord + 0x0E => 9, // QWord _ => 1, } } /// Perform ACPI shutdown -pub fn acpi_shutdown() -> ! { +pub fn acpi_shutdown() -> bool { log_info!("Attempting ACPI shutdown..."); let power_info = unsafe { @@ -316,7 +317,7 @@ pub fn acpi_shutdown() -> ! { Some(info) => info, None => { log_error!("ACPI power info not initialized!"); - return fallback_shutdown(); + return false; } } }; @@ -344,40 +345,11 @@ pub fn acpi_shutdown() -> ! { io::io_port_ww(power_info.pm1b_control_block as u16, slp_cmd_b); } - // 等待關機 - for _ in 0..1000000 { - cpu::cpu_pause(100); - } + cpu::cpu_pause(10000); } log_error!("ACPI shutdown failed!"); - fallback_shutdown() -} - -/// Backup shutdown method -fn fallback_shutdown() -> ! { - log_warn!("Using fallback shutdown methods..."); - - unsafe { - // QEMU - io::io_port_ww(0x604, 0x2000); - cpu::cpu_pause(10000); - - // Bochs - for &c in b"Shutdown" { - io::io_port_wb(0x8900, c); - } - cpu::cpu_pause(10000); - - // VirtualBox - io::io_port_ww(0x4004, 0x3400); - } - - log_error!("All shutdown methods failed!"); - - loop { - cpu::cpu_halt(); - } + false } /// Store ACPI shutdown information @@ -387,3 +359,181 @@ pub fn store_power_info(info: AcpiPowerInfo) { } log_info!("ACPI power info stored successfully"); } + +/// Extract reset register information from FADT +pub fn extract_reset_reg(tables: &AcpiTables) -> Option { + log_info!("Extracting ACPI reset register info..."); + + let fadt = match tables.find_table::() { + Some(fadt) => fadt, + None => { + log_error!("Failed to find FADT"); + return None; + } + }; + + unsafe { + let fadt_ptr = (&*fadt as *const sdt::fadt::Fadt) as *const u8; + + let fadt_revision = core::ptr::read_unaligned(fadt_ptr.add(8) as *const u8); + + if fadt_revision < 2 { + log_warn!("FADT revision {} does not support RESET_REG", fadt_revision); + return None; + } + + // 讀取 Flags (offset 112 in FADT) + let flags = core::ptr::read_unaligned(fadt_ptr.add(112) as *const u32); + let reset_reg_supported = (flags & (1 << 10)) != 0; + + if !reset_reg_supported { + log_warn!("RESET_REG not supported (FADT flags bit 10 not set)"); + return None; + } + + // RESET_REG is at offset 116 in the FADT + // Generic Address Structure format: + // +0: Address Space ID (1 byte) + // +1: Register Bit Width (1 byte) + // +2: Register Bit Offset (1 byte) + // +3: Access Size (1 byte) + // +4: Address (8 bytes) + + let reset_reg_offset = 116; + + let address_space = core::ptr::read_unaligned(fadt_ptr.add(reset_reg_offset) as *const u8); + let bit_width = core::ptr::read_unaligned(fadt_ptr.add(reset_reg_offset + 1) as *const u8); + let bit_offset = core::ptr::read_unaligned(fadt_ptr.add(reset_reg_offset + 2) as *const u8); + let address = core::ptr::read_unaligned(fadt_ptr.add(reset_reg_offset + 4) as *const u64); + + // RESET_VALUE is after RESET_REG (offset 128) + let reset_value = core::ptr::read_unaligned(fadt_ptr.add(128) as *const u8); + + if bit_width != 8 || bit_offset != 0 { + log_warn!( + "Invalid RESET_REG configuration: width={}, offset={}", + bit_width, + bit_offset + ); + return None; + } + + if address_space > 2 { + log_warn!("Invalid address space ID: {}", address_space); + return None; + } + + log_info!("RESET_REG found:"); + log_info!( + " Address Space: {} ({})", + address_space, + match address_space { + 0 => "System Memory", + 1 => "System I/O", + 2 => "PCI Config", + _ => "Unknown", + } + ); + log_info!("Address: {:#x}", address); + log_info!("Reset Value: {:#x}", reset_value); + + Some(ResetRegister { + address_space, + address, + value: reset_value, + }) + } +} + +pub fn store_reset_reg(reset_reg: ResetRegister) { + unsafe { + ACPI_RESET_REG = Some(reset_reg); + } + log_info!("ACPI reset register info stored"); +} + +/// Restart using ACPI RESET_REG +pub fn acpi_reset_reg_reboot() -> bool { + unsafe { + let reset_reg = match &ACPI_RESET_REG { + Some(reg) => reg, + None => { + log_debug!("ACPI RESET_REG not available"); + return false; + } + }; + + log_info!("Using ACPI RESET_REG for reboot"); + log_info!( + " Space: {}, Address: {:#x}, Value: {:#x}", + reset_reg.address_space, + reset_reg.address, + reset_reg.value + ); + + match reset_reg.address_space { + // System I/O + 1 => { + log_debug!( + "Writing {:#x} to I/O port {:#x}", + reset_reg.value, + reset_reg.address + ); + io::io_port_wb(reset_reg.address as u16, reset_reg.value); + true + } + + // System Memory + 0 => { + log_debug!( + "Writing {:#x} to memory address {:#x}", + reset_reg.value, + reset_reg.address + ); + + let virt_addr = vma::phys_to_virt(reset_reg.address); + let ptr = virt_addr.as_mut_ptr::(); + core::ptr::write_volatile(ptr, reset_reg.value); + true + } + + // PCI Config Space + 2 => { + log_debug!( + "Writing {:#x} to PCI config space {:#x}", + reset_reg.value, + reset_reg.address + ); + + // PCI address encoding (ACPI format): + // Bits 63-32: Reserved + // Bits 31-16: Bus Number + // Bits 15-11: Device Number + // Bits 10-8: Function Number + // Bits 7-0: Register Offset + + let bus = ((reset_reg.address >> 16) & 0xFFFF) as u8; + let device = ((reset_reg.address >> 11) & 0x1F) as u8; + let function = ((reset_reg.address >> 8) & 0x7) as u8; + let offset = (reset_reg.address & 0xFF) as u8; + + log_debug!( + "PCI Bus={}, Dev={}, Func={}, Offset={:#x}", + bus, + device, + function, + offset + ); + + // TODO: 調用你的 PCI 配置空間寫入函數 + // pci_config_write_byte(bus, device, function, offset, reset_reg.value); + false + } + + _ => { + log_error!("Unknown address space: {}", reset_reg.address_space); + false + } + } + } +} diff --git a/kernel/src/hal/ioapic.rs b/kernel/src/hal/apic/ioapic.rs similarity index 68% rename from kernel/src/hal/ioapic.rs rename to kernel/src/hal/apic/ioapic.rs index 8c50d8a..b0713a4 100644 --- a/kernel/src/hal/ioapic.rs +++ b/kernel/src/hal/apic/ioapic.rs @@ -1,106 +1,8 @@ -// kernel/src/hal/ioapic.rs - 無鎖設計 +// kernel/src/hal/ioapic.rs +use super::{redir_flags, reg, IoApicInfo, IO_APICS, IO_APIC_COUNT, MAX_IOAPICS}; +use crate::{log_debug, log_error, log_info, log_trace, log_warn}; use x86_64::VirtAddr; -use crate::{log_trace, log_debug, log_info, log_warn, log_error}; - -/// IO APIC register selector -const IOREGSEL: u32 = 0x00; -const IOWIN: u32 = 0x10; - -/// IO APIC register index -#[allow(dead_code)] -mod reg { - pub const ID: u8 = 0x00; - pub const VER: u8 = 0x01; - pub const ARB: u8 = 0x02; - pub const REDTBL_BASE: u8 = 0x10; -} - -/// Redirection Entry flag -#[allow(dead_code)] -mod redir_flags { - pub const MASKED: u64 = 1 << 16; - pub const TRIGGER_LEVEL: u64 = 1 << 15; - pub const TRIGGER_EDGE: u64 = 0; - pub const POLARITY_LOW: u64 = 1 << 13; - pub const POLARITY_HIGH: u64 = 0; - pub const DEST_LOGICAL: u64 = 1 << 11; - pub const DEST_PHYSICAL: u64 = 0; - pub const DELIVERY_FIXED: u64 = 0 << 8; - pub const DELIVERY_LOWEST: u64 = 1 << 8; -} - -// Supports up to 8 IO APICs -const MAX_IOAPICS: usize = 8; - -//IO APIC information array (read-only after initialization) -static mut IO_APICS: [Option; MAX_IOAPICS] = [None; MAX_IOAPICS]; -static mut IO_APIC_COUNT: usize = 0; - -#[derive(Debug, Clone, Copy)] -struct IoApicInfo { - base_vaddr: VirtAddr, - id: u8, - gsi_base: u32, - max_redirection_entries: u8, -} - -impl IoApicInfo { - /// Read IO APIC register - #[inline] - unsafe fn read(&self, reg: u8) -> u32 { - let regsel_addr = self.base_vaddr.as_u64() + IOREGSEL as u64; - let win_addr = self.base_vaddr.as_u64() + IOWIN as u64; - - core::ptr::write_volatile(regsel_addr as *mut u32, reg as u32); - core::ptr::read_volatile(win_addr as *const u32) - } - - /// Write to IO APIC register - #[inline] - unsafe fn write(&self, reg: u8, value: u32) { - let regsel_addr = self.base_vaddr.as_u64() + IOREGSEL as u64; - let win_addr = self.base_vaddr.as_u64() + IOWIN as u64; - - core::ptr::write_volatile(regsel_addr as *mut u32, reg as u32); - core::ptr::write_volatile(win_addr as *mut u32, value); - } - - /// Read the redirection table entry - #[inline] - unsafe fn read_redirection_entry(&self, irq: u8) -> u64 { - if irq >= self.max_redirection_entries { - log_warn!("IRQ {} out of range for IO APIC {}", irq, self.id); - return 0; - } - - let low_reg = reg::REDTBL_BASE + (irq * 2); - let high_reg = low_reg + 1; - - let low = self.read(low_reg) as u64; - let high = self.read(high_reg) as u64; - - (high << 32) | low - } - - /// Write redirection table entry - #[inline] - unsafe fn write_redirection_entry(&self, irq: u8, entry: u64) { - if irq >= self.max_redirection_entries { - log_warn!("IRQ {} out of range for IO APIC {}", irq, self.id); - return; - } - - let low_reg = reg::REDTBL_BASE + (irq * 2); - let high_reg = low_reg + 1; - - let low = entry as u32; - let high = (entry >> 32) as u32; - - self.write(high_reg, high); - self.write(low_reg, low); - } -} /// Initialize a single IO APIC (using mapped virtual addresses) /// @@ -305,4 +207,4 @@ pub fn print_info() { } } } -} \ No newline at end of file +} diff --git a/kernel/src/hal/lapic.rs b/kernel/src/hal/apic/lapic.rs similarity index 78% rename from kernel/src/hal/lapic.rs rename to kernel/src/hal/apic/lapic.rs index 024e3df..9f2af76 100644 --- a/kernel/src/hal/lapic.rs +++ b/kernel/src/hal/apic/lapic.rs @@ -1,68 +1,11 @@ // kernel/src/hal/lapic.rs -use x86_64::VirtAddr; -use crate::{log_trace, log_debug, log_info, log_warn, log_error}; +use super::{flags, ApicInfo, ApicRegister, APIC_INFO, LOCAL_APIC_BASE}; use crate::hal::io; use crate::mm::vma; +use crate::{log_debug, log_error, log_info, log_trace, log_warn}; +use x86_64::VirtAddr; -/// Local APIC register offset -#[repr(u32)] -#[derive(Debug, Clone, Copy)] -#[allow(dead_code)] -pub enum ApicRegister { - Id = 0x20, - Version = 0x30, - TaskPriority = 0x80, - ProcessorPriority = 0xA0, - Eoi = 0xB0, - LogicalDestination = 0xD0, - DestinationFormat = 0xE0, - SpuriousInterruptVector = 0xF0, - ErrorStatus = 0x280, - LvtTimer = 0x320, - LvtThermalSensor = 0x330, - LvtPerformanceCounter = 0x340, - LvtLint0 = 0x350, - LvtLint1 = 0x360, - LvtError = 0x370, - TimerInitialCount = 0x380, - TimerCurrentCount = 0x390, - TimerDivideConfig = 0x3E0, -} - -/// APIC configuration flags -#[allow(dead_code)] -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; -} - -// Local APIC base address (read-only after initialization) -static mut LOCAL_APIC_BASE: Option = None; - -// APIC information (read-only after initialization) -static mut APIC_INFO: ApicInfo = ApicInfo::new(); - -struct ApicInfo { - id: u32, - version: u32, - max_lvt: u32, -} - -impl ApicInfo { - const fn new() -> Self { - Self { - id: 0, - version: 0, - max_lvt: 0, - } - } -} /// Read APIC registers /// /// # Safety @@ -124,10 +67,10 @@ pub unsafe fn write_apic_reg_raw(offset: u32, value: u32) -> bool { pub unsafe fn init_local_apic_with_vaddr(base_vaddr: VirtAddr) { log_debug!("Initializing Local APIC at {:#x}", base_vaddr.as_u64()); - // 儲存基地址 + // Storage base address LOCAL_APIC_BASE = Some(base_vaddr); - // 讀取 APIC 信息 + // Read APIC information let id_reg = read_apic_reg(ApicRegister::Id).unwrap(); let version_reg = read_apic_reg(ApicRegister::Version).unwrap(); @@ -181,9 +124,7 @@ pub fn send_eoi() { /// Get the Local APIC ID #[inline] pub fn get_apic_id() -> Option { - unsafe { - Some(APIC_INFO.id) - } + unsafe { Some(APIC_INFO.id) } } /// Get the Local APIC base virtual address @@ -220,7 +161,6 @@ pub fn get_max_lvt() -> Option { /// /// Must be called before using the APIC to avoid conflicts pub fn disable_legacy_pic() { - unsafe { // Master PIC io::io_port_wb(0x20, 0x11); // ICW1: initialization @@ -253,4 +193,4 @@ pub fn print_info() { log_warn!("Local APIC not initialized"); } } -} \ No newline at end of file +} diff --git a/kernel/src/hal/apic/mod.rs b/kernel/src/hal/apic/mod.rs new file mode 100644 index 0000000..b66cab7 --- /dev/null +++ b/kernel/src/hal/apic/mod.rs @@ -0,0 +1,163 @@ +use x86_64::VirtAddr; +use crate::log_warn; + +pub mod ioapic; +pub mod lapic; + +/// IO APIC register selector +const IOREGSEL: u32 = 0x00; +const IOWIN: u32 = 0x10; + +/// IO APIC register index +#[allow(dead_code)] +mod reg { + pub const ID: u8 = 0x00; + pub const VER: u8 = 0x01; + pub const ARB: u8 = 0x02; + pub const REDTBL_BASE: u8 = 0x10; +} + +/// Redirection Entry flag +#[allow(dead_code)] +mod redir_flags { + pub const MASKED: u64 = 1 << 16; + pub const TRIGGER_LEVEL: u64 = 1 << 15; + pub const TRIGGER_EDGE: u64 = 0; + pub const POLARITY_LOW: u64 = 1 << 13; + pub const POLARITY_HIGH: u64 = 0; + pub const DEST_LOGICAL: u64 = 1 << 11; + pub const DEST_PHYSICAL: u64 = 0; + pub const DELIVERY_FIXED: u64 = 0 << 8; + pub const DELIVERY_LOWEST: u64 = 1 << 8; +} + +// Supports up to 8 IO APICs +const MAX_IOAPICS: usize = 8; + +//IO APIC information array (read-only after initialization) +static mut IO_APICS: [Option; MAX_IOAPICS] = [None; MAX_IOAPICS]; +static mut IO_APIC_COUNT: usize = 0; + +#[derive(Debug, Clone, Copy)] +struct IoApicInfo { + base_vaddr: VirtAddr, + id: u8, + gsi_base: u32, + max_redirection_entries: u8, +} + +/// Local APIC register offset +#[repr(u32)] +#[derive(Debug, Clone, Copy)] +#[allow(dead_code)] +pub enum ApicRegister { + Id = 0x20, + Version = 0x30, + TaskPriority = 0x80, + ProcessorPriority = 0xA0, + Eoi = 0xB0, + LogicalDestination = 0xD0, + DestinationFormat = 0xE0, + SpuriousInterruptVector = 0xF0, + ErrorStatus = 0x280, + LvtTimer = 0x320, + LvtThermalSensor = 0x330, + LvtPerformanceCounter = 0x340, + LvtLint0 = 0x350, + LvtLint1 = 0x360, + LvtError = 0x370, + TimerInitialCount = 0x380, + TimerCurrentCount = 0x390, + TimerDivideConfig = 0x3E0, +} + +/// APIC configuration flags +#[allow(dead_code)] +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; +} + +// Local APIC base address (read-only after initialization) +static mut LOCAL_APIC_BASE: Option = None; + +// APIC information (read-only after initialization) +static mut APIC_INFO: ApicInfo = ApicInfo::new(); + +struct ApicInfo { + id: u32, + version: u32, + max_lvt: u32, +} + +impl ApicInfo { + const fn new() -> Self { + Self { + id: 0, + version: 0, + max_lvt: 0, + } + } +} + +impl IoApicInfo { + /// Read IO APIC register + #[inline] + unsafe fn read(&self, reg: u8) -> u32 { + let regsel_addr = self.base_vaddr.as_u64() + IOREGSEL as u64; + let win_addr = self.base_vaddr.as_u64() + IOWIN as u64; + + core::ptr::write_volatile(regsel_addr as *mut u32, reg as u32); + core::ptr::read_volatile(win_addr as *const u32) + } + + /// Write to IO APIC register + #[inline] + unsafe fn write(&self, reg: u8, value: u32) { + let regsel_addr = self.base_vaddr.as_u64() + IOREGSEL as u64; + let win_addr = self.base_vaddr.as_u64() + IOWIN as u64; + + core::ptr::write_volatile(regsel_addr as *mut u32, reg as u32); + core::ptr::write_volatile(win_addr as *mut u32, value); + } + + /// Read the redirection table entry + #[inline] + unsafe fn read_redirection_entry(&self, irq: u8) -> u64 { + if irq >= self.max_redirection_entries { + log_warn!("IRQ {} out of range for IO APIC {}", irq, self.id); + return 0; + } + + let low_reg = reg::REDTBL_BASE + (irq * 2); + let high_reg = low_reg + 1; + + let low = self.read(low_reg) as u64; + let high = self.read(high_reg) as u64; + + (high << 32) | low + } + + /// Write redirection table entry + #[inline] + unsafe fn write_redirection_entry(&self, irq: u8, entry: u64) { + if irq >= self.max_redirection_entries { + log_warn!("IRQ {} out of range for IO APIC {}", irq, self.id); + return; + } + + let low_reg = reg::REDTBL_BASE + (irq * 2); + let high_reg = low_reg + 1; + + let low = entry as u32; + let high = (entry >> 32) as u32; + + self.write(high_reg, high); + self.write(low_reg, low); + } +} \ No newline at end of file diff --git a/kernel/src/hal/mod.rs b/kernel/src/hal/mod.rs index bd4b081..9cdf55e 100644 --- a/kernel/src/hal/mod.rs +++ b/kernel/src/hal/mod.rs @@ -2,7 +2,6 @@ pub mod io; pub mod cpu; pub mod acpi; pub mod rtc; -pub mod lapic; -pub mod ioapic; pub mod timer; -pub mod power; \ No newline at end of file +pub mod power; +pub mod apic; \ No newline at end of file diff --git a/kernel/src/hal/power.rs b/kernel/src/hal/power.rs index eac9eae..72c98db 100644 --- a/kernel/src/hal/power.rs +++ b/kernel/src/hal/power.rs @@ -71,18 +71,18 @@ fn try_shutdown(method: ShutdownMethod) { } ShutdownMethod::QemuExit => { - // QEMU isa-debug-exit 設備 + // QEMU isa-debug-exit device io::io_port_ww(0x604, 0x2000); io::io_port_rl(0x501); } ShutdownMethod::BochsExit => { - // Bochs 專用關機端口 + // Bochs dedicated shutdown port io::io_port_ww(0xB004, 0x2000); } ShutdownMethod::VirtualBox => { - // VirtualBox 關機端口 + // VirtualBox shutdown port io::io_port_ww(0x4004, 0x3400); } @@ -100,7 +100,7 @@ fn try_shutdown(method: ShutdownMethod) { } } -/// 重啟系統 +/// Restart the system pub fn reboot() -> ! { log_info!("Rebooting system..."); @@ -119,10 +119,10 @@ pub fn reboot() -> ! { ]; for method in methods.iter() { - log_debug!("Trying shutdown method: {:?}", method); + log_debug!("Trying reboot method: {:?}", method); try_reboot(*method); - log_warn!("{:?} shutdown failed", method); + log_warn!("{:?} reboot failed", method); cpu::cpu_pause(1000); } @@ -137,42 +137,30 @@ pub fn reboot() -> ! { fn try_reboot(method: RebootMethod) { match method { RebootMethod::BootACPI => { - acpi_reboot() + acpi::power::acpi_reset_reg_reboot(); } RebootMethod::BootKBD => { - keyboard_controller_reboot() + keyboard_controller_reboot(); } RebootMethod::BootCF9 => { - pci_reboot() + pci_reboot(); } RebootMethod::BootEFI => { - efi_reboot() + efi_reboot(); } RebootMethod::Boot92h => { - cpu_reset() + cpu_reset(); } } cpu::cpu_pause(10000); } -fn acpi_reboot() { - log_debug!("Trying ACPI reboot..."); - - unsafe { - // ACPI FADT 的 RESET_REG - // 需要從 ACPI 表中讀取實際地址 - // 這裡使用常見的地址作為示例 - io::io_port_wb(0xCF9, 0x06); - cpu::cpu_pause(10000); - } -} - -fn keyboard_controller_reboot() { - log_debug!("Trying keyboard controller reboot..."); +fn keyboard_controller_reboot() -> bool { + log_debug!("keyboard controller reboot..."); unsafe { for _ in 0..1000 { @@ -186,10 +174,12 @@ fn keyboard_controller_reboot() { cpu::cpu_pause(100000); } + + false } -fn pci_reboot() { - log_debug!("Trying PCI reboot..."); +fn pci_reboot() -> bool { + log_debug!("PCI reboot..."); unsafe { let mut val = io::io_port_rb(0xCF9) & !0x06; @@ -199,24 +189,29 @@ fn pci_reboot() { cpu::cpu_pause(100000); } + + false } -fn efi_reboot() { +fn efi_reboot() -> bool { log_debug!("Trying EFI runtime services reboot..."); // TODO: 實現 EFI ResetSystem 調用 + false } -fn cpu_reset() { - log_debug!("Trying CPU reset via port 92h..."); +fn cpu_reset() -> bool { + log_debug!("CPU reset via port 92h..."); unsafe { let mut val = io::io_port_rb(0x92); - val &= !0x01; // 清除快速 A20 位 - val |= 0x01; // 設置重置位 + val &= !0x01; // Clear Fast A20 Bit + val |= 0x01; // Set the reset bit io::io_port_wb(0x92, val); cpu::cpu_pause(100000); } + + false } \ No newline at end of file diff --git a/kernel/src/hal/timer.rs b/kernel/src/hal/timer.rs index cf7b9ba..dc85d6d 100644 --- a/kernel/src/hal/timer.rs +++ b/kernel/src/hal/timer.rs @@ -1,8 +1,9 @@ // kernel/src/hal/timer -use crate::hal::{lapic, rtc, cpu, ioapic}; -use core::sync::atomic::{AtomicU64, AtomicBool, Ordering}; -use crate::{log_info, log_debug, log_warn, log_error}; +use crate::hal::{cpu, rtc}; +use core::sync::atomic::{AtomicBool, AtomicU64, Ordering}; +use crate::{log_debug, log_error, log_info, log_warn}; +use crate::hal::apic::{ioapic, lapic}; const APIC_CALIBRATION_CONST: u32 = 0x100000; const RTC_BASE_FREQUENCY: u32 = 1024; diff --git a/kernel/src/kernel/k_init.rs b/kernel/src/kernel/k_init.rs index da5e29c..12987c8 100644 --- a/kernel/src/kernel/k_init.rs +++ b/kernel/src/kernel/k_init.rs @@ -3,7 +3,7 @@ use bootloader_api::BootInfo; use bootloader_api::info::MemoryRegionKind; use x86_64::structures::paging::OffsetPageTable; use x86_64::{PhysAddr, VirtAddr}; -use crate::mm::{allocator::{heap, frame, pmm}, vmm, paging, vma}; +use crate::mm::{allocator::{frame, heap, pmm}, paging, vma, vmm}; use crate::arch::amd64::{gdt, idt}; use crate::tty::tty; use crate::kprintln; @@ -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, timer, cpu, ioapic, lapic, rtc}; +use crate::hal::{acpi, cpu, rtc, timer}; +use crate::hal::apic::{ioapic, lapic}; use crate::hal::cpu::cpu_enable_interrupts; fn _logger_init() { @@ -294,5 +295,5 @@ pub fn _kernel_init(boot_info: &'static mut BootInfo) -> ! { pub fn kernel_emergency_cleanup() { log_error!("Emergency cleanup triggered"); // 在 panic 前調用,做最後的清理工作 - // 比如刷新緩衝區、保存日誌等 + // 刷新緩衝區、保存日誌等 } \ No newline at end of file From c9de6360c726f57c77f8466a2ccc85b9aa08c2e3 Mon Sep 17 00:00:00 2001 From: ParrotXray Date: Sat, 18 Oct 2025 17:49:37 +0800 Subject: [PATCH 13/13] update: Edit TODO.txt --- TODO.txt | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/TODO.txt b/TODO.txt index c9bbc43..1759875 100644 --- a/TODO.txt +++ b/TODO.txt @@ -2,9 +2,7 @@ // - IDT (中斷描述符表) - OK // - 中斷處理函數 - OK // - ACPI 初始化 - OK -// - PIC/APIC 初始化 - -// - 滾動 - OK +// - PIC/APIC 初始化 - OK // 2. 內存管理 // - 物理內存分配器 - OK