Merge pull request #6 from ParrotXray/feat/timer

Feat/timer
This commit is contained in:
ParrotXray 2025-10-18 18:07:22 +08:00 committed by GitHub
commit 2197f20134
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
28 changed files with 3405 additions and 528 deletions

View File

@ -2,9 +2,7 @@
// - IDT (中斷描述符表) - OK
// - 中斷處理函數 - OK
// - ACPI 初始化 - OK
// - PIC/APIC 初始化
// - 滾動 - OK
// - PIC/APIC 初始化 - OK
// 2. 內存管理
// - 物理內存分配器 - OK
@ -22,6 +20,9 @@
// - 用戶態/內核態切換
// 5. 回收
// - 關機重啟回收記憶體
// ==================== 高半核地址空間佈局 ====================
//
// 0x0000_0000_0000 ┌─────────────────────┐

View File

@ -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() {

View File

@ -35,6 +35,19 @@ lazy_static! {
idt.simd_floating_point.set_handler_fn(simd_floating_point_handler);
idt.virtualization.set_handler_fn(virtualization_handler);
// IRQ 0 (32)
idt[32].set_handler_fn(apic_timer_handler);
// IRQ 1 (33) - Keyboard
idt[33].set_handler_fn(keyboard_interrupt_handler); // IRQ 1 Keyboard
idt[40].set_handler_fn(rtc_interrupt_handler); // IRQ 8
for i in 34..=47 {
if i != 40 && i != 32 {
idt[i].set_handler_fn(default_irq_handler);
}
}
idt
};
}
@ -44,6 +57,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");
}

View File

@ -1,9 +1,12 @@
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::kprintln;
use crate::{log_trace, log_debug, log_info, log_warn, log_error, log_fatal};
use crate::hal::cpu;
use crate::{drivers, kprintln};
use crate::{log_debug, log_error, log_fatal, log_info, log_trace, log_warn};
use super::gdt;
use crate::hal::{cpu, rtc, timer};
use crate::hal::apic::lapic;
use crate::mm::paging;
/// Divide Error (#DE)
@ -20,28 +23,45 @@ 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)
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();
}
@ -51,7 +71,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();
}
@ -61,7 +86,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();
}
@ -71,7 +101,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();
}
@ -85,7 +120,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");
}
@ -97,7 +138,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();
}
@ -111,7 +158,21 @@ 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!("{:#?}", 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());
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!("CS: {:#x}", gdt::kernel_code_selector().0);
log_fatal!("SS: {:#x}", gdt::kernel_data_selector().0);
loop {
cpu::cpu_halt();
}
@ -125,7 +186,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();
}
@ -139,7 +205,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();
}
@ -160,7 +231,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()),
@ -176,7 +252,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();
}
@ -190,7 +271,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();
}
@ -200,15 +286,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();
}
@ -218,10 +314,57 @@ 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();
}
}
// TODO Timer interrupt, Keyboard interrupt
// TODO Timer interrupt, Keyboard interrupt
pub extern "x86-interrupt" fn keyboard_interrupt_handler(_stack_frame: InterruptStackFrame) {
unsafe {
let mut port = Port::new(0x60);
let scancode: u8 = port.read();
drivers::keyboard::handle_scancode(scancode);
}
lapic::send_eoi();
}
pub extern "x86-interrupt" fn default_irq_handler(_stack_frame: InterruptStackFrame) {
lapic::send_eoi();
log_trace!("Unhandled IRQ");
}
pub extern "x86-interrupt" fn apic_timer_handler(_stack_frame: InterruptStackFrame) {
// log_info!("Processing of APIC Timer Calibration Phase");
if timer::is_calibrating() {
timer::apic_calibration_handler();
} else {
timer::timer_tick_handler();
}
lapic::send_eoi();
}
pub extern "x86-interrupt" fn rtc_interrupt_handler(_stack_frame: InterruptStackFrame) {
rtc::handle_interrupt();
// log_info!("Processing of APIC Timer Calibration Phase");
if timer::is_calibrating() {
timer::rtc_calibration_handler();
}
lapic::send_eoi();
}

View File

@ -0,0 +1,217 @@
// kernel/src/drivers/keyboard.rs
use spin::Mutex;
use crate::{kprintln, log_debug, log_info, shell, tty};
/// 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, 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
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, 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
];
/// Keyboard state
struct KeyboardState {
shift_pressed: bool,
ctrl_pressed: bool,
alt_pressed: bool,
caps_lock: bool,
num_lock: bool,
e0_prefix: bool,
}
impl KeyboardState {
const fn new() -> Self {
Self {
shift_pressed: false,
ctrl_pressed: false,
alt_pressed: false,
caps_lock: false,
num_lock: true,
e0_prefix: false,
}
}
}
static KEYBOARD_STATE: Mutex<KeyboardState> = Mutex::new(KeyboardState::new());
/// Handle keyboard scancode
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;
// 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; }
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;
}
// 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; }
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; }
_ => {}
}
}
let ascii = if state.shift_pressed {
SCANCODE_TO_ASCII_SHIFT[scancode as usize]
} else {
SCANCODE_TO_ASCII[scancode as usize]
};
if ascii == 0 {
return;
}
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
};
if state.ctrl_pressed {
match ascii {
b'c' | b'C' => { kprintln!("^C"); return; }
b'd' | b'D' => { kprintln!("^D"); return; }
b'l' | b'L' => { tty::tty::clear(0x000000); return; }
_ => {}
}
}
print_char(ascii);
}
/// Print a character to the screen
fn print_char(c: u8) {
if c == b'\n' {
shell::process_keyboard_char('\n');
} else if c == 8 { // Backspace
shell::process_keyboard_char('\x08');
} else if c.is_ascii_graphic() || c == b' ' {
shell::process_keyboard_char(c as char);
}
}
/// Initialize keyboard driver
pub fn init() {
log_info!("Keyboard driver initialized");
}

View File

@ -0,0 +1 @@
pub mod keyboard;

View File

@ -1,314 +0,0 @@
use acpi::{aml, 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};
#[derive(Clone, Copy)]
pub struct CureAcpiHandler {
physical_memory_offset: u64,
}
impl CureAcpiHandler {
pub const fn new(physical_memory_offset: u64) -> Self {
Self {
physical_memory_offset,
}
}
}
impl Handler for CureAcpiHandler {
unsafe fn map_physical_region<T>(
&self,
physical_address: usize,
size: usize,
) -> PhysicalMapping<Self, T> {
// Bootloader 已經映射了所有物理記憶體
let virtual_address = physical_address as u64 + self.physical_memory_offset;
let virtual_start = NonNull::new((virtual_address) as *mut T).unwrap();
PhysicalMapping {
physical_start: physical_address,
virtual_start,
region_length: size,
mapped_length: size,
handler: *self,
}
}
fn unmap_physical_region<T>(region: &PhysicalMapping<Self, T>) {
//
}
fn read_u8(&self, address: usize) -> u8 {
unsafe {
let ptr = self.map_physical_region::<u8>(address, 1);
core::ptr::read_volatile(ptr.virtual_start.as_ptr())
}
}
fn read_u16(&self, address: usize) -> u16 {
unsafe {
let ptr = self.map_physical_region::<u16>(address, 2);
core::ptr::read_volatile(ptr.virtual_start.as_ptr())
}
}
fn read_u32(&self, address: usize) -> u32 {
unsafe {
let ptr = self.map_physical_region::<u32>(address, 4);
core::ptr::read_volatile(ptr.virtual_start.as_ptr())
}
}
fn read_u64(&self, address: usize) -> u64 {
unsafe {
let ptr = self.map_physical_region::<u64>(address, 8);
core::ptr::read_volatile(ptr.virtual_start.as_ptr())
}
}
fn write_u8(&self, address: usize, value: u8) {
unsafe {
let ptr = self.map_physical_region::<u8>(address, 1);
core::ptr::write_volatile(ptr.virtual_start.as_ptr(), value);
}
}
fn write_u16(&self, address: usize, value: u16) {
unsafe {
let ptr = self.map_physical_region::<u16>(address, 2);
core::ptr::write_volatile(ptr.virtual_start.as_ptr(), value);
}
}
fn write_u32(&self, address: usize, value: u32) {
unsafe {
let ptr = self.map_physical_region::<u32>(address, 4);
core::ptr::write_volatile(ptr.virtual_start.as_ptr(), value);
}
}
fn write_u64(&self, address: usize, value: u64) {
unsafe {
let ptr = self.map_physical_region::<u64>(address, 8);
core::ptr::write_volatile(ptr.virtual_start.as_ptr(), value);
}
}
fn read_io_u8(&self, port: u16) -> u8 {
unsafe { crate::hal::io::io_port_rb(port) }
}
fn read_io_u16(&self, port: u16) -> u16 {
unsafe { crate::hal::io::io_port_rw(port) }
}
fn read_io_u32(&self, port: u16) -> u32 {
unsafe { crate::hal::io::io_port_rl(port) }
}
fn write_io_u8(&self, port: u16, value: u8) {
unsafe { crate::hal::io::io_port_wb(port, value) };
}
fn write_io_u16(&self, port: u16, value: u16) {
unsafe { crate::hal::io::io_port_ww(port, value) };
}
fn write_io_u32(&self, port: u16, value: u32) {
unsafe { crate::hal::io::io_port_wl(port, value) };
}
fn read_pci_u8(&self, address: PciAddress, offset: u16) -> u8 {
// TODO: 實作 PCI 配置空間讀取
0xFF
}
fn read_pci_u16(&self, address: PciAddress, offset: u16) -> u16 {
// TODO: 實作 PCI 配置空間讀取
0xFFFF
}
fn read_pci_u32(&self, address: PciAddress, offset: u16) -> u32 {
// TODO: 實作 PCI 配置空間讀取
0xFFFFFFFF
}
fn write_pci_u8(&self, address: PciAddress, offset: u16, value: u8) {
// TODO: 實作 PCI 配置空間寫入
}
fn write_pci_u16(&self, address: PciAddress, offset: u16, value: u16) {
// TODO: 實作 PCI 配置空間寫入
}
fn write_pci_u32(&self, address: PciAddress, offset: u16, value: u32) {
// TODO: 實作 PCI 配置空間寫入
}
fn nanos_since_boot(&self) -> u64 {
// TODO: 實作高精度計時器 (需要 HPET 或 TSC)
// 目前返回 0
0
}
fn stall(&self, _microseconds: u64) {
// TODO: 實作微秒級延遲
// 簡單的忙等待實作
for _ in 0..(_microseconds * 1000) {
crate::hal::cpu::cpu_pause();
}
}
fn sleep(&self, _milliseconds: u64) {
// TODO: 實作毫秒級睡眠
// 簡單的忙等待實作
self.stall(_milliseconds * 1000);
}
fn create_mutex(&self) -> acpi::Handle {
// TODO: 實作 Mutex
// 目前返回一個假的 handle
acpi::Handle(0)
}
fn acquire(&self, mutex: Handle, timeout: u16) -> Result<(), aml::AmlError> {
// TODO: 實作 Mutex 獲取
// 暫時直接返回成功
Ok(())
}
fn release(&self, _handle: acpi::Handle) {
// TODO: 實作 Mutex 釋放
}
}
pub struct AcpiInfo {
pub revision: u8,
pub boot_processor: Option<u32>,
pub cpu_count: usize,
pub has_apic: bool,
pub has_hpet: bool,
}
pub fn init(rsdp_addr: u64, physical_memory_offset: u64) -> Option<AcpiInfo> {
let handler = CureAcpiHandler::new(physical_memory_offset);
let rsdp_mapping = unsafe {
handler.map_physical_region::<Rsdp>(rsdp_addr as usize, mem::size_of::<Rsdp>())
};
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;
}
}
};
// kprintln!(" ACPI Revision: {}", tables.rsdp_revision);
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)
};
// 檢查中斷模型
let has_apic = 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());
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);
}
true
}
InterruptModel::Unknown => {
log_warn!("Interrupt Model: Unknown (not APIC)");
false
}
_ => {
log_warn!("Interrupt Model: Other");
false
}
};
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,
})
}
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" });
}

173
kernel/src/hal/acpi/init.rs Normal file
View File

@ -0,0 +1,173 @@
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;
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<AcpiInfo> {
let handler = CureAcpiHandler::new(physical_memory_offset);
let rsdp_mapping =
unsafe { handler.map_physical_region::<Rsdp>(rsdp_addr as usize, size_of::<Rsdp>()) };
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 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");
}
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 {
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"
}
);
}

215
kernel/src/hal/acpi/mod.rs Normal file
View File

@ -0,0 +1,215 @@
pub mod init;
pub mod power;
use crate::hal::{cpu, io};
use acpi::{aml, Handle, Handler, PciAddress, PhysicalMapping};
use core::ptr::NonNull;
#[derive(Clone, Copy)]
pub struct CureAcpiHandler {
physical_memory_offset: u64,
}
pub struct AcpiInfo {
pub revision: u8,
pub boot_processor: Option<u32>,
pub cpu_count: usize,
pub has_apic: bool,
pub has_hpet: bool,
pub local_apic_address: Option<u64>,
pub io_apics: alloc::vec::Vec<(u64, u8, u32)>, // (address, id, gsi_base)
}
/// Information required for ACPI shutdown
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,
}
/// 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<ResetRegister> = None;
static mut ACPI_POWER_INFO: Option<AcpiPowerInfo> = None;
impl CureAcpiHandler {
pub const fn new(physical_memory_offset: u64) -> Self {
Self {
physical_memory_offset,
}
}
}
impl Handler for CureAcpiHandler {
unsafe fn map_physical_region<T>(
&self,
physical_address: usize,
size: usize,
) -> PhysicalMapping<Self, T> {
// 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();
PhysicalMapping {
physical_start: physical_address,
virtual_start,
region_length: size,
mapped_length: size,
handler: *self,
}
}
fn unmap_physical_region<T>(region: &PhysicalMapping<Self, T>) {
//
}
fn read_u8(&self, address: usize) -> u8 {
unsafe {
let ptr = self.map_physical_region::<u8>(address, 1);
core::ptr::read_volatile(ptr.virtual_start.as_ptr())
}
}
fn read_u16(&self, address: usize) -> u16 {
unsafe {
let ptr = self.map_physical_region::<u16>(address, 2);
core::ptr::read_volatile(ptr.virtual_start.as_ptr())
}
}
fn read_u32(&self, address: usize) -> u32 {
unsafe {
let ptr = self.map_physical_region::<u32>(address, 4);
core::ptr::read_volatile(ptr.virtual_start.as_ptr())
}
}
fn read_u64(&self, address: usize) -> u64 {
unsafe {
let ptr = self.map_physical_region::<u64>(address, 8);
core::ptr::read_volatile(ptr.virtual_start.as_ptr())
}
}
fn write_u8(&self, address: usize, value: u8) {
unsafe {
let ptr = self.map_physical_region::<u8>(address, 1);
core::ptr::write_volatile(ptr.virtual_start.as_ptr(), value);
}
}
fn write_u16(&self, address: usize, value: u16) {
unsafe {
let ptr = self.map_physical_region::<u16>(address, 2);
core::ptr::write_volatile(ptr.virtual_start.as_ptr(), value);
}
}
fn write_u32(&self, address: usize, value: u32) {
unsafe {
let ptr = self.map_physical_region::<u32>(address, 4);
core::ptr::write_volatile(ptr.virtual_start.as_ptr(), value);
}
}
fn write_u64(&self, address: usize, value: u64) {
unsafe {
let ptr = self.map_physical_region::<u64>(address, 8);
core::ptr::write_volatile(ptr.virtual_start.as_ptr(), value);
}
}
fn read_io_u8(&self, port: u16) -> u8 {
unsafe { io::io_port_rb(port) }
}
fn read_io_u16(&self, port: u16) -> u16 {
unsafe { io::io_port_rw(port) }
}
fn read_io_u32(&self, port: u16) -> u32 {
unsafe { io::io_port_rl(port) }
}
fn write_io_u8(&self, port: u16, value: u8) {
unsafe { io::io_port_wb(port, value) };
}
fn write_io_u16(&self, port: u16, value: u16) {
unsafe { io::io_port_ww(port, value) };
}
fn write_io_u32(&self, port: u16, value: u32) {
unsafe { io::io_port_wl(port, value) };
}
fn read_pci_u8(&self, address: PciAddress, offset: u16) -> u8 {
// TODO: 實作 PCI 配置空間讀取
0xFF
}
fn read_pci_u16(&self, address: PciAddress, offset: u16) -> u16 {
// TODO: 實作 PCI 配置空間讀取
0xFFFF
}
fn read_pci_u32(&self, address: PciAddress, offset: u16) -> u32 {
// TODO: 實作 PCI 配置空間讀取
0xFFFFFFFF
}
fn write_pci_u8(&self, address: PciAddress, offset: u16, value: u8) {
// TODO: 實作 PCI 配置空間寫入
}
fn write_pci_u16(&self, address: PciAddress, offset: u16, value: u16) {
// TODO: 實作 PCI 配置空間寫入
}
fn write_pci_u32(&self, address: PciAddress, offset: u16, value: u32) {
// TODO: 實作 PCI 配置空間寫入
}
fn nanos_since_boot(&self) -> u64 {
// TODO: 實作高精度計時器 (需要 HPET 或 TSC)
// 目前返回 0
0
}
fn stall(&self, _microseconds: u64) {
// TODO: 實作微秒級延遲
// 簡單的忙等待實作
cpu::cpu_pause(_microseconds * 1000);
}
fn sleep(&self, _milliseconds: u64) {
// TODO: 實作毫秒級睡眠
// 簡單的忙等待實作
self.stall(_milliseconds * 1000);
}
fn create_mutex(&self) -> Handle {
// TODO: 實作 Mutex
// 目前返回一個假的 handle
Handle(0)
}
fn acquire(&self, mutex: Handle, timeout: u16) -> Result<(), aml::AmlError> {
// TODO: 實作 Mutex 獲取
// 暫時直接返回成功
Ok(())
}
fn release(&self, _handle: Handle) {
// TODO: 實作 Mutex 釋放
}
}

View File

@ -0,0 +1,539 @@
use super::{AcpiPowerInfo, CureAcpiHandler, ResetRegister, ACPI_POWER_INFO, ACPI_RESET_REG};
use crate::hal::{cpu, io};
use crate::kprintln;
use crate::mm::vma;
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<CureAcpiHandler>,
handler: &CureAcpiHandler,
) -> Option<AcpiPowerInfo> {
log_info!("Extracting ACPI power management info...");
let fadt = match tables.find_table::<sdt::fadt::Fadt>() {
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 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);
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);
let (slp_typa, slp_typb) = match parse_s5_object(dsdt_address, handler) {
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, 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::<SdtHeader>(dsdt_phys_addr as usize, size_of::<SdtHeader>())
};
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::<u8>(dsdt_phys_addr as usize, dsdt_length) };
unsafe {
let dsdt_ptr = dsdt_mapping.virtual_start.as_ptr();
let dsdt_data = core::slice::from_raw_parts(dsdt_ptr, dsdt_length);
// Search DSDT for "_S5_"
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);
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; // Skip "_S5_"
// Skip any intermediate bytes and go straight to PackageOp
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);
break;
}
offset += 1;
}
if offset >= dsdt_data.len() || dsdt_data[offset] != 0x12 {
log_warn!("PackageOp not found after _S5");
continue;
}
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..]);
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 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);
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
);
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
}
/// Parse AML integer
fn parse_aml_integer(data: &[u8]) -> Option<u64> {
if data.is_empty() {
return None;
}
match data[0] {
0x00 => Some(0), // ZeroOp
0x01 => Some(1), // OneOp
0xFF => Some(0xFFFFFFFF), // OnesOp
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],
]))
}
_ => {
log_warn!("Unknown AML integer prefix: {:#02x}", data[0]);
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 | 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() -> bool {
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 false;
}
}
};
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);
}
cpu::cpu_pause(10000);
}
log_error!("ACPI shutdown failed!");
false
}
/// Store ACPI shutdown information
pub fn store_power_info(info: AcpiPowerInfo) {
unsafe {
ACPI_POWER_INFO = Some(info);
}
log_info!("ACPI power info stored successfully");
}
/// Extract reset register information from FADT
pub fn extract_reset_reg(tables: &AcpiTables<CureAcpiHandler>) -> Option<ResetRegister> {
log_info!("Extracting ACPI reset register info...");
let fadt = match tables.find_table::<sdt::fadt::Fadt>() {
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::<u8>();
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
}
}
}
}

View File

@ -0,0 +1,210 @@
// 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;
/// 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) {
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 entries
let version = temp_info.read(reg::VER);
let max_entries = ((version >> 16) & 0xFF) as u8 + 1;
// 創建完整的信息結構
let info = IoApicInfo {
base_vaddr,
id,
gsi_base,
max_redirection_entries: max_entries,
};
// 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 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 vaddr = crate::mm::vma::phys_to_virt(paddr.as_u64());
init_single_ioapic(vaddr, *id, *gsi_base);
}
log_info!("All IO APICs initialized");
}
/// 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,
dest_apic_id: u8,
level_triggered: bool,
active_low: bool,
) {
unsafe {
// Find the IO APIC responsible for this IRQ
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;
// 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;
}
}
}
log_warn!("No IO APIC found for IRQ {}", irq);
}
}
/// Mask IRQ
pub fn mask_irq(irq: u8) {
unsafe {
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;
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;
}
}
}
}
}
/// Unmask IRQ
pub fn unmask_irq(irq: u8) {
unsafe {
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;
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);
}
}
}
}

View File

@ -0,0 +1,196 @@
// kernel/src/hal/lapic.rs
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;
/// Read APIC registers
///
/// # Safety
/// The caller must ensure the APIC is initialized.
#[inline]
pub unsafe fn read_apic_reg(reg: ApicRegister) -> Option<u32> {
LOCAL_APIC_BASE.map(|base| {
let addr = base.as_u64() + reg as u64;
core::ptr::read_volatile(addr as *const u32)
})
}
/// 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);
true
} else {
false
}
}
/// 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<u32> {
LOCAL_APIC_BASE.map(|base| {
let addr = base.as_u64() + offset as u64;
core::ptr::read_volatile(addr as *const u32)
})
}
/// 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());
// Storage base address
LOCAL_APIC_BASE = Some(base_vaddr);
// Read APIC information
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)
///
/// # 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 (End of Interrupt)
///
/// This is the most frequently called function and must be extremely fast.
#[inline]
pub fn send_eoi() {
unsafe {
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<u32> {
unsafe { Some(APIC_INFO.id) }
}
/// Get the Local APIC base virtual address
#[inline]
pub fn get_base_vaddr() -> Option<VirtAddr> {
unsafe { LOCAL_APIC_BASE }
}
/// Get APIC version
#[inline]
pub fn get_version() -> Option<u32> {
unsafe {
if LOCAL_APIC_BASE.is_some() {
Some(APIC_INFO.version)
} else {
None
}
}
}
/// Get the maximum number of LVT entries
#[inline]
pub fn get_max_lvt() -> Option<u32> {
unsafe {
if LOCAL_APIC_BASE.is_some() {
Some(APIC_INFO.max_lvt)
} else {
None
}
}
}
/// Disable legacy 8259 PIC
///
/// 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
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::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
// 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");
}
}
}

163
kernel/src/hal/apic/mod.rs Normal file
View File

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

View File

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

View File

@ -1,4 +1,7 @@
pub mod io;
pub mod cpu;
pub mod acpi;
mod rtc;
pub mod rtc;
pub mod timer;
pub mod power;
pub mod apic;

217
kernel/src/hal/power.rs Normal file
View File

@ -0,0 +1,217 @@
// 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 device
io::io_port_ww(0x604, 0x2000);
io::io_port_rl(0x501);
}
ShutdownMethod::BochsExit => {
// Bochs dedicated shutdown port
io::io_port_ww(0xB004, 0x2000);
}
ShutdownMethod::VirtualBox => {
// VirtualBox shutdown port
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);
}
}
/// Restart the system
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 reboot method: {:?}", method);
try_reboot(*method);
log_warn!("{:?} reboot 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::power::acpi_reset_reg_reboot();
}
RebootMethod::BootKBD => {
keyboard_controller_reboot();
}
RebootMethod::BootCF9 => {
pci_reboot();
}
RebootMethod::BootEFI => {
efi_reboot();
}
RebootMethod::Boot92h => {
cpu_reset();
}
}
cpu::cpu_pause(10000);
}
fn keyboard_controller_reboot() -> bool {
log_debug!("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);
}
false
}
fn pci_reboot() -> bool {
log_debug!("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);
}
false
}
fn efi_reboot() -> bool {
log_debug!("Trying EFI runtime services reboot...");
// TODO: 實現 EFI ResetSystem 調用
false
}
fn cpu_reset() -> bool {
log_debug!("CPU reset via port 92h...");
unsafe {
let mut val = io::io_port_rb(0x92);
val &= !0x01; // Clear Fast A20 Bit
val |= 0x01; // Set the reset bit
io::io_port_wb(0x92, val);
cpu::cpu_pause(100000);
}
false
}

View File

@ -0,0 +1,299 @@
// kernel/src/hal/rtc.rs
use crate::hal::io::{io_port_rb, io_port_wb};
use core::sync::atomic::{AtomicU64, Ordering};
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;
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_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;
const RTC_FREQUENCY_1024HZ: u8 = 0b110;
const RTC_DIVIDER_33KHZ: u8 = 0b010 << 4;
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",
}
}
}
// 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 RtcConfig {
const fn new() -> Self {
Self {
binary_mode: false,
hour_24_mode: false,
}
}
}
/// 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
#[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
#[inline]
unsafe fn is_updating() -> bool {
(read_register(RTC_REG_A) & RTC_UPDATE_IN_PROGRESS) != 0
}
/// Wait for RTC update to complete
unsafe fn wait_for_update() {
while is_updating() {
core::hint::spin_loop();
}
}
/// Convert BCD to binary
#[inline]
fn bcd_to_binary(bcd: u8) -> u8 {
(bcd & 0x0F) + ((bcd >> 4) * 10)
}
pub fn 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;
// 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);
// 清除中斷
read_register(RTC_REG_C);
// 確保 timer 關閉
disable_timer();
// 再次清除
read_register(RTC_REG_C);
}
log_info!("RTC initialized (lock-free design)");
}
pub fn get_time() -> DateTime {
unsafe {
loop {
// Wait for RTC to be ready
wait_for_update();
// 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)
}
}
}
/// Directly read the RTC register
unsafe fn read_time_raw() -> DateTime {
let config = &RTC_CONFIG;
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 {
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 periodic interrupt (1024Hz)
pub fn 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 RTC periodic interrupt
pub fn 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);
}
}
/// 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
#[inline]
pub fn reset_tick_count() {
RTC_TICK_COUNT.store(0, Ordering::Relaxed);
}
/// Print current time information
pub fn print_info() {
let time = get_time();
log_info!(
"{}, {} {}, {} - {:02}:{:02}:{:02}",
time.weekday_name(),
time.month_name(),
time.day,
time.year,
time.hour,
time.minute,
time.second
);
}

344
kernel/src/hal/timer.rs Normal file
View File

@ -0,0 +1,344 @@
// kernel/src/hal/timer
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;
// 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(100_000_000);
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 remaining = TIMEOUT.load(Ordering::Relaxed);
while !unsafe { CALIBRATION.done } && remaining > 0 {
cpu::cpu_pause(0);
remaining -= 1;
}
cpu::cpu_disable_interrupts();
if remaining == 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<u32> {
unsafe {
if TIMER_CONFIG.initialized {
Some(TIMER_CONFIG.base_frequency)
} else {
None
}
}
}
/// Get the running frequency
#[inline]
pub fn get_running_frequency() -> Option<u32> {
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");
}
}

View File

@ -1,9 +1,9 @@
// 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::mm::{allocator::{frame, heap, pmm}, paging, vma, vmm};
use crate::arch::amd64::{gdt, idt};
use crate::tty::tty;
use crate::kprintln;
@ -11,7 +11,10 @@ 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::drivers::keyboard;
use crate::hal::{acpi, cpu, rtc, timer};
use crate::hal::apic::{ioapic, lapic};
use crate::hal::cpu::cpu_enable_interrupts;
fn _logger_init() {
init(
@ -92,14 +95,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();
@ -132,32 +131,127 @@ 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<u64>, physical_memory_offset: u64) {
fn _acpi_init(rsdp_addr: Option<u64>, physical_memory_offset: u64) -> Option<acpi::AcpiInfo> {
kprintln!();
if let Some(rsdp) = rsdp_addr {
log_debug!("RSDP Address: {:#x}", rsdp);
if let Some(acpi_info) = acpi::init(rsdp, physical_memory_offset) {
acpi::print_info(&acpi_info);
if let Some(acpi_info) = acpi::init::init(rsdp, physical_memory_offset) {
acpi::init::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());
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();
if let Some(apic_id) = lapic::get_apic_id() {
log_info!("Setting up APIC Timer...");
log_info!("Current CPU APIC ID: {}", apic_id);
if timer::init(100, apic_id as u8) {
log_info!("APIC Timer initialized successfully!");
// 顯示信息
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);
}
} 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");
}
@ -180,19 +274,14 @@ 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();
_test_memory_management(&mut mapper, &mut frame_allocator);
kprintln!();
kprintln!("========================================");
kprintln!(" Kernel Initialization Complete! ");
kprintln!("========================================");
log_info!("System initialization complete!");
kprintln!();
k_main::_kernel_main();
@ -206,68 +295,5 @@ pub fn _kernel_init(boot_info: &'static mut BootInfo) -> ! {
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::<u64>();
*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!");
// 刷新緩衝區、保存日誌等
}

View File

@ -1,56 +1,62 @@
// kernel/src/k_main.rs (Updated with Logger Demo)
use crate::hal::cpu;
use crate::kprintln;
// kernel/src/kernel/k_main.rs
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;
pub fn _kernel_main() -> ! {
kprintln!();
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)
);
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!();
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 ===");
// 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!");
kprintln!("Type 'help' for available commands");
kprintln!();
log_warn!("Entering idle loop");
shell::init();
loop {
cpu::cpu_halt();
}
}
}
pub fn test_apic_timer() {
log_info!("=== APIC Timer Test ===");
let start_ticks = timer::get_tick_count();
cpu::cpu_pause(1000);
let end_ticks = timer::get_tick_count();
let elapsed = end_ticks - start_ticks;
log_info!("Elapsed ticks: {}", elapsed);
if let Some((_, freq, _)) = timer::get_info() {
log_info!("Expected ~{} ticks/sec", freq);
log_info!("Actual rate: {} Hz", elapsed);
}
}

View File

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

View File

@ -21,6 +21,8 @@ pub mod arch;
pub mod mm;
pub mod tty;
pub mod kernel;
pub mod drivers;
pub mod shell;
use hal::cpu;
const CONFIG: BootloaderConfig = {

View File

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

View File

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

View File

@ -0,0 +1,186 @@
// kernel/src/shell/commands.rs
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 | 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!();
}
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_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 ===");
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_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);
power::reboot();
}

138
kernel/src/shell/math.rs Normal file
View File

@ -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<f64, CalcError> {
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<char>,
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<char> {
self.chars.get(self.pos).cloned()
}
fn next(&mut self) -> Option<char> {
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<f64, CalcError> {
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::<f64>().map_err(|_| CalcError::InvalidNumber)
}
fn parse_factor(&mut self) -> Result<f64, CalcError> {
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<f64, CalcError> {
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<f64, CalcError> {
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)
}
}

66
kernel/src/shell/mod.rs Normal file
View File

@ -0,0 +1,66 @@
// kernel/src/shell/mod.rs
use alloc::string::String;
use spin::Mutex;
use crate::{kprint, kprintln, tty, hal::{rtc, timer}};
pub mod commands;
pub mod math;
static COMMAND_BUFFER: Mutex<String> = Mutex::new(String::new());
pub fn init() {
show_prompt();
}
pub fn show_prompt() {
tty::tty::write_str("cure > ", 0x00FF00);
}
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 mut cmd = cmd.trim();
if cmd.is_empty() {
return;
}
match cmd {
"help" => commands::cmd_help(),
"clear" | "clr" => commands::cmd_clear(),
"time" => commands::cmd_time(),
"uptime" => commands::cmd_uptime(),
"sysinfo" | "sys" => commands::cmd_sysinfo(),
"meminfo" | "mem" => commands::cmd_meminfo(),
"reboot" => commands::cmd_reboot(),
"halt" | "shutdown" | "poweroff" => commands::cmd_shutdown(),
_ => {
match math::eval_expression(cmd) {
Ok(result) => kprintln!("{}", result),
Err(_) => {
kprintln!("Unknown command: '{}'", cmd);
kprintln!("Type 'help' for available commands");
}
}
}
}
}

View File

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