diff --git a/TODO.txt b/TODO.txt index fb545b5..75d4b79 100644 --- a/TODO.txt +++ b/TODO.txt @@ -23,7 +23,8 @@ // BUG -// - 在測試RTC中斷時 rtc::get_time() 處卡住 +// - ACPI 關機 mem 映射問題 +// - 關機重啟回收記憶體 // ==================== 高半核地址空間佈局 ==================== // diff --git a/kernel/src/arch/amd64/isr.rs b/kernel/src/arch/amd64/isr.rs index f88c027..aac96fb 100644 --- a/kernel/src/arch/amd64/isr.rs +++ b/kernel/src/arch/amd64/isr.rs @@ -4,6 +4,7 @@ use x86_64::structures::idt::{InterruptStackFrame, PageFaultErrorCode}; use x86_64::VirtAddr; use crate::{drivers, kprintln}; use crate::{log_trace, log_debug, log_info, log_warn, log_error, log_fatal}; +use super::gdt; use crate::hal::{timer, cpu, lapic, rtc}; use crate::mm::paging; @@ -32,21 +33,34 @@ pub extern "x86-interrupt" fn debug_handler(stack_frame: InterruptStackFrame) { pub extern "x86-interrupt" fn nmi_handler(stack_frame: InterruptStackFrame) { kprintln!(); log_fatal!("EXCEPTION: NON-MASKABLE INTERRUPT (NMI)"); - log_fatal!("{:#?}", stack_frame); + log_fatal!("instruction pointer: {:#x}", stack_frame.instruction_pointer.as_u64()); + log_fatal!("code segment: index: {:#?}, rpl: {:#?}", stack_frame.code_segment.index(), stack_frame.code_segment.rpl()); + log_fatal!("cpu flags: {:#x}", stack_frame.cpu_flags.bits()); + log_fatal!("stack pointer: {:#x}", stack_frame.stack_pointer.as_u64()); + log_fatal!("stack segment: index: {:#?}, rpl: {:#?}", stack_frame.stack_segment.index(), stack_frame.stack_segment.rpl()); } /// Breakpoint (#BP) pub extern "x86-interrupt" fn breakpoint_handler(stack_frame: InterruptStackFrame) { kprintln!(); log_debug!("EXCEPTION: BREAKPOINT (#BP)"); - log_debug!("{:#?}", stack_frame); + log_debug!("instruction pointer: {:#x}", stack_frame.instruction_pointer.as_u64()); + log_debug!("code segment: index: {:#?}, rpl: {:#?}", stack_frame.code_segment.index(), stack_frame.code_segment.rpl()); + log_debug!("cpu flags: {:#x}", stack_frame.cpu_flags.bits()); + log_debug!("stack pointer: {:#x}", stack_frame.stack_pointer.as_u64()); + log_debug!("stack segment: index: {:#?}, rpl: {:#?}", stack_frame.stack_segment.index(), stack_frame.stack_segment.rpl()); } /// Overflow (#OF) pub extern "x86-interrupt" fn overflow_handler(stack_frame: InterruptStackFrame) { kprintln!(); log_error!("EXCEPTION: OVERFLOW (#OF)"); - log_error!("{:#?}", stack_frame); + log_error!("instruction pointer: {:#x}", stack_frame.instruction_pointer.as_u64()); + log_error!("code segment: index: {:#?}, rpl: {:#?}", stack_frame.code_segment.index(), stack_frame.code_segment.rpl()); + log_error!("cpu flags: {:#x}", stack_frame.cpu_flags.bits()); + log_error!("stack pointer: {:#x}", stack_frame.stack_pointer.as_u64()); + log_error!("stack segment: index: {:#?}, rpl: {:#?}", stack_frame.stack_segment.index(), stack_frame.stack_segment.rpl()); + loop { cpu::cpu_halt(); } @@ -56,7 +70,12 @@ pub extern "x86-interrupt" fn overflow_handler(stack_frame: InterruptStackFrame) pub extern "x86-interrupt" fn bound_range_handler(stack_frame: InterruptStackFrame) { kprintln!(); log_error!("EXCEPTION: BOUND RANGE EXCEEDED (#BR)"); - log_error!("{:#?}", stack_frame); + log_error!("instruction pointer: {:#x}", stack_frame.instruction_pointer.as_u64()); + log_error!("code segment: index: {:#?}, rpl: {:#?}", stack_frame.code_segment.index(), stack_frame.code_segment.rpl()); + log_error!("cpu flags: {:#x}", stack_frame.cpu_flags.bits()); + log_error!("stack pointer: {:#x}", stack_frame.stack_pointer.as_u64()); + log_error!("stack segment: index: {:#?}, rpl: {:#?}", stack_frame.stack_segment.index(), stack_frame.stack_segment.rpl()); + loop { cpu::cpu_halt(); } @@ -66,7 +85,12 @@ pub extern "x86-interrupt" fn bound_range_handler(stack_frame: InterruptStackFra pub extern "x86-interrupt" fn invalid_opcode_handler(stack_frame: InterruptStackFrame) { kprintln!(); log_error!("EXCEPTION: INVALID OPCODE (#UD)"); - log_error!("{:#?}", stack_frame); + log_error!("instruction pointer: {:#x}", stack_frame.instruction_pointer.as_u64()); + log_error!("code segment: index: {:#?}, rpl: {:#?}", stack_frame.code_segment.index(), stack_frame.code_segment.rpl()); + log_error!("cpu flags: {:#x}", stack_frame.cpu_flags.bits()); + log_error!("stack pointer: {:#x}", stack_frame.stack_pointer.as_u64()); + log_error!("stack segment: index: {:#?}, rpl: {:#?}", stack_frame.stack_segment.index(), stack_frame.stack_segment.rpl()); + loop { cpu::cpu_halt(); } @@ -76,7 +100,12 @@ pub extern "x86-interrupt" fn invalid_opcode_handler(stack_frame: InterruptStack pub extern "x86-interrupt" fn device_not_available_handler(stack_frame: InterruptStackFrame) { kprintln!(); log_error!("EXCEPTION: DEVICE NOT AVAILABLE (#NM)"); - log_error!("{:#?}", stack_frame); + log_error!("instruction pointer: {:#x}", stack_frame.instruction_pointer.as_u64()); + log_error!("code segment: index: {:#?}, rpl: {:#?}", stack_frame.code_segment.index(), stack_frame.code_segment.rpl()); + log_error!("cpu flags: {:#x}", stack_frame.cpu_flags.bits()); + log_error!("stack pointer: {:#x}", stack_frame.stack_pointer.as_u64()); + log_error!("stack segment: index: {:#?}, rpl: {:#?}", stack_frame.stack_segment.index(), stack_frame.stack_segment.rpl()); + loop { cpu::cpu_halt(); } @@ -90,7 +119,13 @@ pub extern "x86-interrupt" fn double_fault_handler( kprintln!(); log_fatal!("EXCEPTION: DOUBLE FAULT (#DF)"); log_fatal!("Error Code: {:#x}", error_code); - log_fatal!("{:#?}", stack_frame); + + log_fatal!("instruction pointer: {:#x}", stack_frame.instruction_pointer.as_u64()); + log_fatal!("code segment: index: {:#?}, rpl: {:#?}", stack_frame.code_segment.index(), stack_frame.code_segment.rpl()); + log_fatal!("cpu flags: {:#x}", stack_frame.cpu_flags.bits()); + log_fatal!("stack pointer: {:#x}", stack_frame.stack_pointer.as_u64()); + log_fatal!("stack segment: index: {:#?}, rpl: {:#?}", stack_frame.stack_segment.index(), stack_frame.stack_segment.rpl()); + panic!("DOUBLE FAULT - System cannot continue"); } @@ -102,7 +137,13 @@ pub extern "x86-interrupt" fn invalid_tss_handler( kprintln!(); log_fatal!("EXCEPTION: INVALID TSS (#TS)"); log_fatal!("Error Code: {:#x}", error_code); - log_fatal!("{:#?}", stack_frame); + + log_fatal!("instruction pointer: {:#x}", stack_frame.instruction_pointer.as_u64()); + log_fatal!("code segment: index: {:#?}, rpl: {:#?}", stack_frame.code_segment.index(), stack_frame.code_segment.rpl()); + log_fatal!("cpu flags: {:#x}", stack_frame.cpu_flags.bits()); + log_fatal!("stack pointer: {:#x}", stack_frame.stack_pointer.as_u64()); + log_fatal!("stack segment: index: {:#?}, rpl: {:#?}", stack_frame.stack_segment.index(), stack_frame.stack_segment.rpl()); + loop { cpu::cpu_halt(); } @@ -127,11 +168,9 @@ pub extern "x86-interrupt" fn segment_not_present_handler( let index = (error_code >> 3) & 0x1FFF; log_fatal!("Segment: {} index {:#x} (external: {})", table, index, is_external); - log_fatal!("{:#?}", stack_frame); - log_fatal!("Current segments:"); - log_fatal!(" CS: {:#x}", crate::arch::amd64::gdt::kernel_code_selector().0); - log_fatal!(" SS: {:#x}", crate::arch::amd64::gdt::kernel_data_selector().0); + log_fatal!("CS: {:#x}", gdt::kernel_code_selector().0); + log_fatal!("SS: {:#x}", gdt::kernel_data_selector().0); loop { cpu::cpu_halt(); @@ -146,7 +185,12 @@ pub extern "x86-interrupt" fn stack_segment_fault_handler( kprintln!(); log_fatal!("EXCEPTION: STACK SEGMENT FAULT (#SS)"); log_fatal!("Error Code: {:#x}", error_code); - log_fatal!("{:#?}", stack_frame); + log_fatal!("instruction pointer: {:#x}", stack_frame.instruction_pointer.as_u64()); + log_fatal!("code segment: index: {:#?}, rpl: {:#?}", stack_frame.code_segment.index(), stack_frame.code_segment.rpl()); + log_fatal!("cpu flags: {:#x}", stack_frame.cpu_flags.bits()); + log_fatal!("stack pointer: {:#x}", stack_frame.stack_pointer.as_u64()); + log_fatal!("stack segment: index: {:#?}, rpl: {:#?}", stack_frame.stack_segment.index(), stack_frame.stack_segment.rpl()); + loop { cpu::cpu_halt(); } @@ -160,7 +204,12 @@ pub extern "x86-interrupt" fn general_protection_fault_handler( kprintln!(); log_fatal!("EXCEPTION: GENERAL PROTECTION FAULT (#GP)"); log_fatal!("Error Code: {:#x}", error_code); - log_fatal!("{:#?}", stack_frame); + log_fatal!("instruction pointer: {:#x}", stack_frame.instruction_pointer.as_u64()); + log_fatal!("code segment: index: {:#?}, rpl: {:#?}", stack_frame.code_segment.index(), stack_frame.code_segment.rpl()); + log_fatal!("cpu flags: {:#x}", stack_frame.cpu_flags.bits()); + log_fatal!("stack pointer: {:#x}", stack_frame.stack_pointer.as_u64()); + log_fatal!("stack segment: index: {:#?}, rpl: {:#?}", stack_frame.stack_segment.index(), stack_frame.stack_segment.rpl()); + loop { cpu::cpu_halt(); } @@ -181,7 +230,12 @@ pub extern "x86-interrupt" fn page_fault_handler( log_fatal!("User: {}", error_code.contains(PageFaultErrorCode::USER_MODE)); log_fatal!("Reserved Write: {}", error_code.contains(PageFaultErrorCode::MALFORMED_TABLE)); log_fatal!("Instruction Fetch: {}", error_code.contains(PageFaultErrorCode::INSTRUCTION_FETCH)); - log_fatal!("{:#?}", stack_frame); + + log_fatal!("instruction pointer: {:#x}", stack_frame.instruction_pointer.as_u64()); + log_fatal!("code segment: index: {:#?}, rpl: {:#?}", stack_frame.code_segment.index(), stack_frame.code_segment.rpl()); + log_fatal!("cpu flags: {:#x}", stack_frame.cpu_flags.bits()); + log_fatal!("stack pointer: {:#x}", stack_frame.stack_pointer.as_u64()); + log_fatal!("stack segment: index: {:#?}, rpl: {:#?}", stack_frame.stack_segment.index(), stack_frame.stack_segment.rpl()); paging::handle_page_fault( VirtAddr::new(cpu::cpu_r_cr2()), @@ -197,7 +251,12 @@ pub extern "x86-interrupt" fn page_fault_handler( pub extern "x86-interrupt" fn x87_floating_point_handler(stack_frame: InterruptStackFrame) { kprintln!(); log_error!("EXCEPTION: x87 FLOATING POINT (#MF)"); - log_error!("{:#?}", stack_frame); + log_error!("instruction pointer: {:#x}", stack_frame.instruction_pointer.as_u64()); + log_error!("code segment: index: {:#?}, rpl: {:#?}", stack_frame.code_segment.index(), stack_frame.code_segment.rpl()); + log_error!("cpu flags: {:#x}", stack_frame.cpu_flags.bits()); + log_error!("stack pointer: {:#x}", stack_frame.stack_pointer.as_u64()); + log_error!("stack segment: index: {:#?}, rpl: {:#?}", stack_frame.stack_segment.index(), stack_frame.stack_segment.rpl()); + loop { cpu::cpu_halt(); } @@ -211,7 +270,12 @@ pub extern "x86-interrupt" fn alignment_check_handler( kprintln!(); log_error!("EXCEPTION: ALIGNMENT CHECK (#AC)"); log_error!("Error Code: {:#x}", error_code); - log_error!("{:#?}", stack_frame); + log_error!("instruction pointer: {:#x}", stack_frame.instruction_pointer.as_u64()); + log_error!("code segment: index: {:#?}, rpl: {:#?}", stack_frame.code_segment.index(), stack_frame.code_segment.rpl()); + log_error!("cpu flags: {:#x}", stack_frame.cpu_flags.bits()); + log_error!("stack pointer: {:#x}", stack_frame.stack_pointer.as_u64()); + log_error!("stack segment: index: {:#?}, rpl: {:#?}", stack_frame.stack_segment.index(), stack_frame.stack_segment.rpl()); + loop { cpu::cpu_halt(); } @@ -221,15 +285,25 @@ pub extern "x86-interrupt" fn alignment_check_handler( pub extern "x86-interrupt" fn machine_check_handler(stack_frame: InterruptStackFrame) -> ! { kprintln!(); log_error!("EXCEPTION: MACHINE CHECK (#MC)"); - log_error!("{:#?}", stack_frame); + log_error!("instruction pointer: {:#x}", stack_frame.instruction_pointer.as_u64()); + log_error!("code segment: index: {:#?}, rpl: {:#?}", stack_frame.code_segment.index(), stack_frame.code_segment.rpl()); + log_error!("cpu flags: {:#x}", stack_frame.cpu_flags.bits()); + log_error!("stack pointer: {:#x}", stack_frame.stack_pointer.as_u64()); + log_error!("stack segment: index: {:#?}, rpl: {:#?}", stack_frame.stack_segment.index(), stack_frame.stack_segment.rpl()); + panic!("MACHINE CHECK - System cannot continue"); } /// SIMD Floating-Point Exception (#XM/#XF) pub extern "x86-interrupt" fn simd_floating_point_handler(stack_frame: InterruptStackFrame) { kprintln!(); - kprintln!("EXCEPTION: SIMD FLOATING POINT (#XM/#XF)"); - kprintln!("{:#?}", stack_frame); + log_error!("EXCEPTION: SIMD FLOATING POINT (#XM/#XF)"); + log_error!("instruction pointer: {:#x}", stack_frame.instruction_pointer.as_u64()); + log_error!("code segment: index: {:#?}, rpl: {:#?}", stack_frame.code_segment.index(), stack_frame.code_segment.rpl()); + log_error!("cpu flags: {:#x}", stack_frame.cpu_flags.bits()); + log_error!("stack pointer: {:#x}", stack_frame.stack_pointer.as_u64()); + log_error!("stack segment: index: {:#?}, rpl: {:#?}", stack_frame.stack_segment.index(), stack_frame.stack_segment.rpl()); + loop { cpu::cpu_halt(); } @@ -239,7 +313,12 @@ pub extern "x86-interrupt" fn simd_floating_point_handler(stack_frame: Interrupt pub extern "x86-interrupt" fn virtualization_handler(stack_frame: InterruptStackFrame) { kprintln!(); log_warn!("EXCEPTION: VIRTUALIZATION (#VE)"); - log_warn!("{:#?}", stack_frame); + log_warn!("instruction pointer: {:#x}", stack_frame.instruction_pointer.as_u64()); + log_warn!("code segment: index: {:#?}, rpl: {:#?}", stack_frame.code_segment.index(), stack_frame.code_segment.rpl()); + log_warn!("cpu flags: {:#x}", stack_frame.cpu_flags.bits()); + log_warn!("stack pointer: {:#x}", stack_frame.stack_pointer.as_u64()); + log_warn!("stack segment: index: {:#?}, rpl: {:#?}", stack_frame.stack_segment.index(), stack_frame.stack_segment.rpl()); + loop { cpu::cpu_halt(); } @@ -247,7 +326,7 @@ pub extern "x86-interrupt" fn virtualization_handler(stack_frame: InterruptStack // TODO Timer interrupt, Keyboard interrupt -pub extern "x86-interrupt" fn keyboard_interrupt_handler(stack_frame: InterruptStackFrame) { +pub extern "x86-interrupt" fn keyboard_interrupt_handler(_stack_frame: InterruptStackFrame) { unsafe { let mut port = Port::new(0x60); @@ -259,7 +338,7 @@ pub extern "x86-interrupt" fn keyboard_interrupt_handler(stack_frame: InterruptS lapic::send_eoi(); } -pub extern "x86-interrupt" fn default_irq_handler(stack_frame: InterruptStackFrame) { +pub extern "x86-interrupt" fn default_irq_handler(_stack_frame: InterruptStackFrame) { lapic::send_eoi(); log_trace!("Unhandled IRQ"); } diff --git a/kernel/src/hal/acpi/init.rs b/kernel/src/hal/acpi/init.rs new file mode 100644 index 0000000..c9f9445 --- /dev/null +++ b/kernel/src/hal/acpi/init.rs @@ -0,0 +1,148 @@ +use acpi::{aml, sdt, AcpiTables, Handle, Handler, PciAddress, PhysicalMapping}; +use acpi::platform::{AcpiPlatform, interrupt::InterruptModel, PciConfigRegions}; +use acpi::sdt::hpet::HpetInfo; +use acpi::rsdp::Rsdp; +use core::ptr::NonNull; +use core::mem; +use crate::kprintln; +use crate::{log_trace, log_debug, log_info, log_warn, log_error, log_fatal}; +use crate::hal::{cpu, io}; +use super::*; + + +pub fn init(rsdp_addr: u64, physical_memory_offset: u64) -> Option { + + let handler = CureAcpiHandler::new(physical_memory_offset); + + let rsdp_mapping = unsafe { + handler.map_physical_region::(rsdp_addr as usize, mem::size_of::()) + }; + let revision = rsdp_mapping.revision(); + log_info!("ACPI Revision: {}", revision); + + let tables = unsafe { + match AcpiTables::from_rsdp(handler, rsdp_addr as usize) { + Ok(tables) => tables, + Err(e) => { + log_error!("Failed to parse ACPI tables: {:?}", e); + return None; + } + } + }; + + let platform = match AcpiPlatform::new(tables, handler) { + Ok(platform) => platform, + Err(e) => { + log_error!("Failed to create ACPI platform: {:?}", e); + return None; + } + }; + + log_info!("Power Profile: {:?}", platform.power_profile); + + let (boot_processor, cpu_count) = if let Some(proc_info) = &platform.processor_info { + let boot_proc = Some(proc_info.boot_processor.processor_uid); + let cpu_cnt = proc_info.application_processors.len() + 1; + + log_info!("Boot Processor UID: {:?}", boot_proc); + log_info!("Total CPU Count: {}", cpu_cnt); + + (boot_proc, cpu_cnt) + } else { + log_warn!("No processor info found"); + (None, 0) + }; + + // Check interrupt mode + let (has_apic, local_apic_addr, io_apics_info) = match &platform.interrupt_model { + InterruptModel::Apic(apic) => { + log_info!("Local APIC Address: {:#x}", apic.local_apic_address); + log_info!("IO APICs: {} controller(s)", apic.io_apics.len()); + + let mut io_apics = alloc::vec::Vec::new(); + + for (i, io_apic) in apic.io_apics.iter().enumerate() { + log_info!("IO APIC {}: ID={}, Address={:#x}, GSI Base={}", + i, io_apic.id, io_apic.address, io_apic.global_system_interrupt_base); + + io_apics.push(( + io_apic.address as u64, + io_apic.id, + io_apic.global_system_interrupt_base, + )); + } + + (true, Some(apic.local_apic_address as u64), io_apics) + } + InterruptModel::Unknown => { + log_warn!("Interrupt Model: Unknown (not APIC)"); + (false, None, alloc::vec::Vec::new()) + } + _ => { + log_warn!("Interrupt Model: Other"); + (false, None, alloc::vec::Vec::new()) + } + }; + + let has_hpet = match HpetInfo::new(&platform.tables) { + Ok(hpet) => { + log_info!("Base Address: {:#x}", hpet.base_address); + log_info!("Hardware Rev: {}", hpet.hardware_rev); + log_info!("Comparator Count: {}", hpet.num_comparators); + log_info!("Counter Size: {} bit", if hpet.main_counter_is_64bits { 64 } else { 32 }); + log_info!("Legacy IRQ Capable: {}", hpet.legacy_irq_capable); + log_info!("PCI Vendor ID: {:#x}", hpet.pci_vendor_id); + true + } + Err(_) => { + log_warn!("HPET: Not available"); + false + } + }; + + if let Ok(mcfg) = PciConfigRegions::new(&platform.tables) { + for (i, entry) in mcfg.regions.iter().enumerate() { + let segment_group = entry.pci_segment_group; + let base_addr = entry.base_address; + let bus_start = entry.bus_number_start; + let bus_end = entry.bus_number_end; + + log_info!("Entry {}: Segment Group {}", i, segment_group); + log_info!("Base Address: {:#x}", base_addr); + log_info!("Bus Range: {}-{}", bus_start, bus_end); + } + } + + kprintln!(); + log_info!("Extracting ACPI power management info..."); + // if let Some(power_info) = extract_power_info(&platform.tables) { + // store_power_info(power_info); + // } else { + // log_warn!("Could not extract ACPI power info, shutdown may not work"); + // } + + + log_info!("ACPI initialized successfully!"); + + Some(AcpiInfo { + revision, + boot_processor, + cpu_count, + has_apic, + has_hpet, + local_apic_address: local_apic_addr, + io_apics: io_apics_info, + }) +} + +pub fn print_info(info: &AcpiInfo) { + kprintln!(); + log_info!("Revision: ACPI {}.0", info.revision); + log_info!("CPUs: {} processor(s)", info.cpu_count); + if let Some(boot_proc) = info.boot_processor { + log_info!("Boot Processor: UID {}", boot_proc); + } + log_info!("APIC: {}", if info.has_apic { "Available " } else { "Not available" }); + log_info!("HPET: {}", if info.has_hpet { "Available " } else { "Not available" }); +} + diff --git a/kernel/src/hal/acpi.rs b/kernel/src/hal/acpi/mod.rs similarity index 52% rename from kernel/src/hal/acpi.rs rename to kernel/src/hal/acpi/mod.rs index 815cfcb..fd97adf 100644 --- a/kernel/src/hal/acpi.rs +++ b/kernel/src/hal/acpi/mod.rs @@ -1,13 +1,15 @@ -use acpi::{aml, AcpiTables, Handle, Handler, PciAddress, PhysicalMapping}; -use acpi::platform::{AcpiPlatform, interrupt::InterruptModel, PciConfigRegions}; +pub mod power; +pub mod init; + +use acpi::{aml, sdt, AcpiTables, Handle, Handler, PciAddress, PhysicalMapping}; use acpi::sdt::hpet::HpetInfo; -use acpi::rsdp::Rsdp; use core::ptr::NonNull; use core::mem; use crate::kprintln; use crate::{log_trace, log_debug, log_info, log_warn, log_error, log_fatal}; use crate::hal::{cpu, io}; + #[derive(Clone, Copy)] pub struct CureAcpiHandler { physical_memory_offset: u64, @@ -23,6 +25,17 @@ pub struct AcpiInfo { pub io_apics: alloc::vec::Vec<(u64, u8, u32)>, // (address, id, gsi_base) } +/// ACPI 關機所需的信息 +pub struct AcpiPowerInfo { + pub pm1a_control_block: u32, + pub pm1b_control_block: u32, + pub slp_typa: u16, + pub slp_typb: u16, + pub slp_en: u16, +} + +static mut ACPI_POWER_INFO: Option = None; + impl CureAcpiHandler { pub const fn new(physical_memory_offset: u64) -> Self { Self { @@ -170,7 +183,7 @@ impl Handler for CureAcpiHandler { fn stall(&self, _microseconds: u64) { // TODO: 實作微秒級延遲 // 簡單的忙等待實作 - cpu::cpu_pause(_microseconds * 1000); + cpu::cpu_pause(_microseconds * 1000); } @@ -180,10 +193,10 @@ impl Handler for CureAcpiHandler { self.stall(_milliseconds * 1000); } - fn create_mutex(&self) -> acpi::Handle { + fn create_mutex(&self) -> Handle { // TODO: 實作 Mutex // 目前返回一個假的 handle - acpi::Handle(0) + Handle(0) } fn acquire(&self, mutex: Handle, timeout: u16) -> Result<(), aml::AmlError> { @@ -192,134 +205,7 @@ impl Handler for CureAcpiHandler { Ok(()) } - fn release(&self, _handle: acpi::Handle) { + fn release(&self, _handle: Handle) { // TODO: 實作 Mutex 釋放 } -} - -pub fn init(rsdp_addr: u64, physical_memory_offset: u64) -> Option { - - let handler = CureAcpiHandler::new(physical_memory_offset); - - let rsdp_mapping = unsafe { - handler.map_physical_region::(rsdp_addr as usize, mem::size_of::()) - }; - let revision = rsdp_mapping.revision(); - log_info!("ACPI Revision: {}", revision); - - let tables = unsafe { - match AcpiTables::from_rsdp(handler, rsdp_addr as usize) { - Ok(tables) => tables, - Err(e) => { - log_error!("Failed to parse ACPI tables: {:?}", e); - return None; - } - } - }; - - let platform = match AcpiPlatform::new(tables, handler) { - Ok(platform) => platform, - Err(e) => { - log_error!("Failed to create ACPI platform: {:?}", e); - return None; - } - }; - - log_info!("Power Profile: {:?}", platform.power_profile); - - let (boot_processor, cpu_count) = if let Some(proc_info) = &platform.processor_info { - let boot_proc = Some(proc_info.boot_processor.processor_uid); - let cpu_cnt = proc_info.application_processors.len() + 1; - - log_info!("Boot Processor UID: {:?}", boot_proc); - log_info!("Total CPU Count: {}", cpu_cnt); - - (boot_proc, cpu_cnt) - } else { - log_warn!("No processor info found"); - (None, 0) - }; - - // Check interrupt mode - let (has_apic, local_apic_addr, io_apics_info) = match &platform.interrupt_model { - InterruptModel::Apic(apic) => { - log_info!("Local APIC Address: {:#x}", apic.local_apic_address); - log_info!("IO APICs: {} controller(s)", apic.io_apics.len()); - - let mut io_apics = alloc::vec::Vec::new(); - - for (i, io_apic) in apic.io_apics.iter().enumerate() { - log_info!("IO APIC {}: ID={}, Address={:#x}, GSI Base={}", - i, io_apic.id, io_apic.address, io_apic.global_system_interrupt_base); - - io_apics.push(( - io_apic.address as u64, - io_apic.id, - io_apic.global_system_interrupt_base, - )); - } - - (true, Some(apic.local_apic_address as u64), io_apics) - } - InterruptModel::Unknown => { - log_warn!("Interrupt Model: Unknown (not APIC)"); - (false, None, alloc::vec::Vec::new()) - } - _ => { - log_warn!("Interrupt Model: Other"); - (false, None, alloc::vec::Vec::new()) - } - }; - - let has_hpet = match HpetInfo::new(&platform.tables) { - Ok(hpet) => { - log_info!("Base Address: {:#x}", hpet.base_address); - log_info!("Hardware Rev: {}", hpet.hardware_rev); - log_info!("Comparator Count: {}", hpet.num_comparators); - log_info!("Counter Size: {} bit", if hpet.main_counter_is_64bits { 64 } else { 32 }); - log_info!("Legacy IRQ Capable: {}", hpet.legacy_irq_capable); - log_info!("PCI Vendor ID: {:#x}", hpet.pci_vendor_id); - true - } - Err(_) => { - log_warn!("HPET: Not available"); - false - } - }; - - if let Ok(mcfg) = PciConfigRegions::new(&platform.tables) { - for (i, entry) in mcfg.regions.iter().enumerate() { - let segment_group = entry.pci_segment_group; - let base_addr = entry.base_address; - let bus_start = entry.bus_number_start; - let bus_end = entry.bus_number_end; - - log_info!("Entry {}: Segment Group {}", i, segment_group); - log_info!("Base Address: {:#x}", base_addr); - log_info!("Bus Range: {}-{}", bus_start, bus_end); - } - } - - log_info!("ACPI initialized successfully!"); - - Some(AcpiInfo { - revision, - boot_processor, - cpu_count, - has_apic, - has_hpet, - local_apic_address: local_apic_addr, - io_apics: io_apics_info, - }) -} - -pub fn print_info(info: &AcpiInfo) { - kprintln!(); - log_info!("Revision: ACPI {}.0", info.revision); - log_info!("CPUs: {} processor(s)", info.cpu_count); - if let Some(boot_proc) = info.boot_processor { - log_info!("Boot Processor: UID {}", boot_proc); - } - log_info!("APIC: {}", if info.has_apic { "Available " } else { "Not available" }); - log_info!("HPET: {}", if info.has_hpet { "Available " } else { "Not available" }); } \ No newline at end of file diff --git a/kernel/src/hal/acpi/power.rs b/kernel/src/hal/acpi/power.rs new file mode 100644 index 0000000..2f3199a --- /dev/null +++ b/kernel/src/hal/acpi/power.rs @@ -0,0 +1,336 @@ +use acpi::{aml, sdt, AcpiTables, Handle, Handler, PciAddress, PhysicalMapping}; +use acpi::platform::{AcpiPlatform, interrupt::InterruptModel, PciConfigRegions}; +use core::mem; +use crate::kprintln; +use crate::{log_trace, log_debug, log_info, log_warn, log_error, log_fatal}; +use crate::hal::{cpu, io}; +use crate::mm::vma; +use super::*; + + +/// Extract shutdown information from ACPI table +pub fn extract_power_info(tables: &AcpiTables) -> Option { + log_info!("Extracting ACPI power management info..."); + + let fadt = match tables.find_table::() { + Some(fadt) => fadt, + None => { + log_error!("Failed to find FADT"); + return None; + } + }; + + log_debug!("FADT found"); + + // Get the control block address and DSDT address from FADT + unsafe { + // Get the raw pointer of FADT to read the fields manually + let fadt_ptr = (&*fadt as *const sdt::fadt::Fadt) as *const u8; + + // FADT structure offset + let pm1a_control_block = core::ptr::read_unaligned(fadt_ptr.add(64) as *const u32); + let pm1b_control_block = core::ptr::read_unaligned(fadt_ptr.add(68) as *const u32); + + // Read DSDT address + let fadt_revision = core::ptr::read_unaligned(fadt_ptr.add(8) as *const u8); + let dsdt_address = if fadt_revision >= 2 { + let x_dsdt = core::ptr::read_unaligned(fadt_ptr.add(140) as *const u64); + if x_dsdt != 0 { + x_dsdt + } else { + core::ptr::read_unaligned(fadt_ptr.add(40) as *const u32) as u64 + } + } else { + core::ptr::read_unaligned(fadt_ptr.add(40) as *const u32) as u64 + }; + + log_info!("PM1a Control Block: {:#x}", pm1a_control_block); + if pm1b_control_block != 0 { + log_info!("PM1b Control Block: {:#x}", pm1b_control_block); + } + log_debug!("DSDT address: {:#x}", dsdt_address); + + // Parse the _S5 object + let (slp_typa, slp_typb) = match parse_s5_object(dsdt_address) { + Some(values) => values, + None => { + log_warn!("Could not parse _S5 object, using default values"); + (5, 5) + } + }; + + log_info!("SLP_TYPa: {:#x}", slp_typa); + log_info!("SLP_TYPb: {:#x}", slp_typb); + + Some(AcpiPowerInfo { + pm1a_control_block, + pm1b_control_block, + slp_typa, + slp_typb, + slp_en: 1 << 13, + }) + } +} + +/// Parse the _S5 object in the DSDT +/// +/// AML bytecode format for the _S5 object: +/// ``` +/// Name(_S5, Package() { +/// SLP_TYPa, // Type A for entering the S5 state +/// SLP_TYPb, // Type B for entering the S5 state +/// ... +/// }) +/// ``` +fn parse_s5_object(dsdt_phys_addr: u64) -> Option<(u16, u16)> { + let dsdt_virt_addr = vma::phys_to_virt(dsdt_phys_addr); + + unsafe { + let dsdt_ptr = dsdt_virt_addr.as_ptr::(); + + // DSDT header + let signature = core::slice::from_raw_parts(dsdt_ptr, 4); + if signature != b"DSDT" { + log_error!("Invalid DSDT signature"); + return None; + } + + // Get DSDT length + let length = core::ptr::read_unaligned(dsdt_ptr.add(4) as *const u32); + log_debug!("DSDT length: {} bytes", length); + + // Search for the "_S5_" string in DSDT + let dsdt_data = core::slice::from_raw_parts(dsdt_ptr, length as usize); + + // Byte representation of "_S5_" in AML + let s5_name = b"_S5_"; + + for i in 0..(dsdt_data.len() - 4) { + if &dsdt_data[i..i+4] == s5_name { + log_debug!("Found _S5 at offset {:#x}", i); + + // Parse the _S5 package + // Typical AML bytecode: + // Name(_S5, Package() {...}) + // Or: 08 5F 53 35 5F 12 [pkg_length] [num_elements] ... + + let mut offset = i + 4; + + // Skip possible NameOp (0x08) + if offset < dsdt_data.len() && dsdt_data[offset] == 0x08 { + offset += 1; + } + + // Find PackageOp (0x12) + while offset < dsdt_data.len() && dsdt_data[offset] != 0x12 { + offset += 1; + if offset - i > 16 { + break; + } + } + + if offset >= dsdt_data.len() { + log_warn!("PackageOp not found after _S5"); + continue; + } + + offset += 1; // 跳過 PackageOp + + // Parse PkgLength + let pkg_length = parse_pkg_length(&dsdt_data[offset..]); + offset += get_pkg_length_size(&dsdt_data[offset..]); + + // NumElements + let num_elements = dsdt_data[offset]; + offset += 1; + + log_debug!("Package length: {}, elements: {}", pkg_length, num_elements); + + if num_elements < 2 { + log_warn!("_S5 package has less than 2 elements"); + continue; + } + + // Extract SLP_TYPa + let slp_typa = parse_aml_integer(&dsdt_data[offset..]).unwrap_or(0); + offset += get_aml_integer_size(&dsdt_data[offset..]); + + // Extract SLP_TYPb + let slp_typb = parse_aml_integer(&dsdt_data[offset..]).unwrap_or(0); + + log_info!("Parsed _S5: SLP_TYPa={:#x}, SLP_TYPb={:#x}", slp_typa, slp_typb); + + return Some((slp_typa as u16, slp_typb as u16)); + } + } + + log_error!("_S5 object not found in DSDT"); + None + } +} + +/// Parse AML packet length +fn parse_pkg_length(data: &[u8]) -> usize { + if data.is_empty() { + return 0; + } + + let lead_byte = data[0]; + let byte_count = (lead_byte >> 6) as usize; + + match byte_count { + 0 => (lead_byte & 0x3F) as usize, + 1 => { + if data.len() < 2 { return 0; } + ((lead_byte & 0x0F) as usize) | ((data[1] as usize) << 4) + } + 2 => { + if data.len() < 3 { return 0; } + ((lead_byte & 0x0F) as usize) + | ((data[1] as usize) << 4) + | ((data[2] as usize) << 12) + } + 3 => { + if data.len() < 4 { return 0; } + ((lead_byte & 0x0F) as usize) + | ((data[1] as usize) << 4) + | ((data[2] as usize) << 12) + | ((data[3] as usize) << 20) + } + _ => 0, + } +} + +/// Get the number of bytes encoded by the packet length +fn get_pkg_length_size(data: &[u8]) -> usize { + if data.is_empty() { + return 0; + } + + let lead_byte = data[0]; + let byte_count = (lead_byte >> 6) as usize; + 1 + byte_count +} + +/// 解析 AML 整數 +fn parse_aml_integer(data: &[u8]) -> Option { + if data.is_empty() { + return None; + } + + match data[0] { + 0x00 => Some(0), // ZeroOp + 0x01 => Some(1), // OneOp + 0x0A => { // BytePrefix + if data.len() < 2 { return None; } + Some(data[1] as u64) + } + 0x0B => { // WordPrefix + if data.len() < 3 { return None; } + Some(u16::from_le_bytes([data[1], data[2]]) as u64) + } + 0x0C => { // DWordPrefix + if data.len() < 5 { return None; } + Some(u32::from_le_bytes([data[1], data[2], data[3], data[4]]) as u64) + } + 0x0E => { // QWordPrefix + if data.len() < 9 { return None; } + Some(u64::from_le_bytes([ + data[1], data[2], data[3], data[4], + data[5], data[6], data[7], data[8], + ])) + } + _ => None, + } +} + +/// Get the byte size of the AML integer +fn get_aml_integer_size(data: &[u8]) -> usize { + if data.is_empty() { + return 0; + } + + match data[0] { + 0x00 | 0x01 => 1, + 0x0A => 2, + 0x0B => 3, + 0x0C => 5, + 0x0E => 9, + _ => 1, + } +} + +/// Perform ACPI shutdown +pub fn acpi_shutdown() -> ! { + log_info!("Attempting ACPI shutdown..."); + + let power_info = unsafe { + match &ACPI_POWER_INFO { + Some(info) => info, + None => { + log_error!("ACPI power info not initialized!"); + return fallback_shutdown(); + } + } + }; + + unsafe { + let slp_cmd_a = (power_info.slp_typa << 10) | power_info.slp_en; + + log_info!("Writing {:#x} to PM1a_CNT ({:#x})", + slp_cmd_a, power_info.pm1a_control_block); + + // Write to PM1a control register + io::io_port_ww(power_info.pm1a_control_block as u16, slp_cmd_a); + + // If PM1b exists, also write + if power_info.pm1b_control_block != 0 { + let slp_cmd_b = (power_info.slp_typb << 10) | power_info.slp_en; + log_info!("Writing {:#x} to PM1b_CNT ({:#x})", + slp_cmd_b, power_info.pm1b_control_block); + io::io_port_ww(power_info.pm1b_control_block as u16, slp_cmd_b); + } + + // 等待關機 + for _ in 0..1000000 { + cpu::cpu_pause(100); + } + } + + log_error!("ACPI shutdown failed!"); + fallback_shutdown() +} + +/// Backup shutdown method +fn fallback_shutdown() -> ! { + log_warn!("Using fallback shutdown methods..."); + + unsafe { + // QEMU + io::io_port_ww(0x604, 0x2000); + cpu::cpu_pause(10000); + + // Bochs + for &c in b"Shutdown" { + io::io_port_wb(0x8900, c); + } + cpu::cpu_pause(10000); + + // VirtualBox + io::io_port_ww(0x4004, 0x3400); + } + + log_error!("All shutdown methods failed!"); + + loop { + cpu::cpu_halt(); + } +} + +/// Store ACPI shutdown information +pub fn store_power_info(info: AcpiPowerInfo) { + unsafe { + ACPI_POWER_INFO = Some(info); + } + log_info!("ACPI power info stored successfully"); +} \ No newline at end of file diff --git a/kernel/src/hal/mod.rs b/kernel/src/hal/mod.rs index 0ed70e9..bd4b081 100644 --- a/kernel/src/hal/mod.rs +++ b/kernel/src/hal/mod.rs @@ -4,4 +4,5 @@ pub mod acpi; pub mod rtc; pub mod lapic; pub mod ioapic; -pub mod timer; \ No newline at end of file +pub mod timer; +pub mod power; \ No newline at end of file diff --git a/kernel/src/hal/power.rs b/kernel/src/hal/power.rs new file mode 100644 index 0000000..eac9eae --- /dev/null +++ b/kernel/src/hal/power.rs @@ -0,0 +1,222 @@ +// kernel/src/hal/power.rs + +use crate::hal::{io, cpu, rtc}; +use crate::{log_info, log_debug, log_warn, log_error}; +use super::acpi; + +#[derive(Debug, Clone, Copy)] +pub enum PowerState { + S0, // Working + S1, // Sleep + S3, // Suspend to RAM + S4, // Suspend to Disk + S5, // Soft Off +} + +#[derive(Debug, Clone, Copy, PartialEq)] +pub enum ShutdownMethod { + Acpi, + QemuExit, + BochsExit, + VirtualBox, + Apm, +} +#[derive(Debug, Clone, Copy, PartialEq)] +pub enum RebootMethod { + BootACPI, + BootEFI, + BootKBD, + BootCF9, + Boot92h, +} + +pub fn shutdown() -> ! { + log_info!("Initiating system shutdown..."); + + log_info!("Disabling CPU interrupts"); + cpu::cpu_disable_interrupts(); + + log_info!("Shutting down the RTC Timer"); + rtc::disable_timer(); + + let methods = [ + ShutdownMethod::Acpi, + ShutdownMethod::QemuExit, + ShutdownMethod::BochsExit, + ShutdownMethod::VirtualBox, + ShutdownMethod::Apm, + ]; + + for method in methods.iter() { + log_debug!("Trying shutdown method: {:?}", method); + try_shutdown(*method); + + log_warn!("{:?} shutdown failed", method); + cpu::cpu_pause(1000); + } + + log_error!("All shutdown methods failed!"); + log_error!("System halted. Please power off manually."); + + loop { + cpu::cpu_halt(); + } +} + +fn try_shutdown(method: ShutdownMethod) { + unsafe { + match method { + ShutdownMethod::Acpi => { + acpi::power::acpi_shutdown(); + } + + ShutdownMethod::QemuExit => { + // QEMU isa-debug-exit 設備 + io::io_port_ww(0x604, 0x2000); + io::io_port_rl(0x501); + } + + ShutdownMethod::BochsExit => { + // Bochs 專用關機端口 + io::io_port_ww(0xB004, 0x2000); + } + + ShutdownMethod::VirtualBox => { + // VirtualBox 關機端口 + io::io_port_ww(0x4004, 0x3400); + } + + ShutdownMethod::Apm => { + // APM (Advanced Power Management) BIOS + // APM version 1.0 + io::io_port_wb(0x8900, 0x53); + io::io_port_wb(0x8900, 0x00); + io::io_port_wb(0x8900, 0x01); + io::io_port_wb(0x8900, 0x53); + } + } + + cpu::cpu_pause(10000); + } +} + +/// 重啟系統 +pub fn reboot() -> ! { + log_info!("Rebooting system..."); + + log_info!("Disabling CPU interrupts"); + cpu::cpu_disable_interrupts(); + + log_info!("Shutting down the RTC Timer"); + rtc::disable_timer(); + + let methods = [ + RebootMethod::BootACPI, + RebootMethod::BootEFI, + RebootMethod::BootKBD, + RebootMethod::BootCF9, + RebootMethod::Boot92h, + ]; + + for method in methods.iter() { + log_debug!("Trying shutdown method: {:?}", method); + try_reboot(*method); + + log_warn!("{:?} shutdown failed", method); + cpu::cpu_pause(1000); + } + + log_error!("All reboot methods failed!"); + log_error!("System halted. Please power off manually."); + + loop { + cpu::cpu_halt(); + } +} + +fn try_reboot(method: RebootMethod) { + match method { + RebootMethod::BootACPI => { + acpi_reboot() + } + + RebootMethod::BootKBD => { + keyboard_controller_reboot() + } + + RebootMethod::BootCF9 => { + pci_reboot() + } + RebootMethod::BootEFI => { + efi_reboot() + } + + RebootMethod::Boot92h => { + cpu_reset() + } + } + + cpu::cpu_pause(10000); +} + +fn acpi_reboot() { + log_debug!("Trying ACPI reboot..."); + + unsafe { + // ACPI FADT 的 RESET_REG + // 需要從 ACPI 表中讀取實際地址 + // 這裡使用常見的地址作為示例 + io::io_port_wb(0xCF9, 0x06); + cpu::cpu_pause(10000); + } +} + +fn keyboard_controller_reboot() { + log_debug!("Trying keyboard controller reboot..."); + + unsafe { + for _ in 0..1000 { + if (io::io_port_rb(0x64) & 0x02) == 0 { + break; + } + cpu::cpu_pause(10); + } + + io::io_port_wb(0x64, 0xFE); + + cpu::cpu_pause(100000); + } +} + +fn pci_reboot() { + log_debug!("Trying PCI reboot..."); + + unsafe { + let mut val = io::io_port_rb(0xCF9) & !0x06; + io::io_port_wb(0xCF9, val | 0x02); + cpu::cpu_pause(1000); + io::io_port_wb(0xCF9, val | 0x06); + + cpu::cpu_pause(100000); + } +} + + +fn efi_reboot() { + log_debug!("Trying EFI runtime services reboot..."); + + // TODO: 實現 EFI ResetSystem 調用 +} + +fn cpu_reset() { + log_debug!("Trying CPU reset via port 92h..."); + + unsafe { + let mut val = io::io_port_rb(0x92); + val &= !0x01; // 清除快速 A20 位 + val |= 0x01; // 設置重置位 + io::io_port_wb(0x92, val); + + cpu::cpu_pause(100000); + } +} \ No newline at end of file diff --git a/kernel/src/hal/timer.rs b/kernel/src/hal/timer.rs index 35866b6..cf7b9ba 100644 --- a/kernel/src/hal/timer.rs +++ b/kernel/src/hal/timer.rs @@ -38,7 +38,7 @@ static TICK_COUNTER: AtomicU64 = AtomicU64::new(0); // Calibration flag static IS_CALIBRATING: AtomicBool = AtomicBool::new(false); -static TIMEOUT: AtomicU64 = AtomicU64::new(0); +static TIMEOUT: AtomicU64 = AtomicU64::new(100_000_000); struct TimerConfig { base_frequency: u32, @@ -143,15 +143,14 @@ pub fn init(target_frequency: u32, apic_id: u8) -> bool { cpu::cpu_enable_interrupts(); - let mut timeout = 100_000_000; - while !unsafe { CALIBRATION.done } && timeout > 0 { + let mut remaining = TIMEOUT.load(Ordering::Relaxed); + while !unsafe { CALIBRATION.done } && remaining > 0 { cpu::cpu_pause(0); - timeout -= 1; + remaining -= 1; } - cpu::cpu_disable_interrupts(); - if timeout == 0 { + if remaining == 0 { log_error!("Calibration timeout!"); IS_CALIBRATING.store(false, Ordering::SeqCst); return false; diff --git a/kernel/src/kernel/k_init.rs b/kernel/src/kernel/k_init.rs index 076eec2..da5e29c 100644 --- a/kernel/src/kernel/k_init.rs +++ b/kernel/src/kernel/k_init.rs @@ -94,14 +94,10 @@ fn _memory_init( fn _display_init(framebuffer: &'static mut bootloader_api::info::FrameBuffer) { tty::init(framebuffer); tty::clear(0x000000); - - kprintln!("========================================"); - kprintln!(" CureOS Kernel v0.1.0" ); - kprintln!("========================================"); - kprintln!(); } fn _boot_report(memory_regions: &bootloader_api::info::MemoryRegions, physical_memory_offset: u64) { + kprintln!(); log_info!("GDT initialized"); gdt::print_info(); @@ -144,8 +140,8 @@ fn _acpi_init(rsdp_addr: Option, physical_memory_offset: u64) -> Option ! { _boot_report(&boot_info.memory_regions, physical_memory_offset); kprintln!(); - kprintln!("========================================"); - kprintln!(" Kernel Initialization Complete! "); - kprintln!("========================================"); + log_info!("System initialization complete!"); kprintln!(); k_main::_kernel_main(); diff --git a/kernel/src/kernel/k_main.rs b/kernel/src/kernel/k_main.rs index c9f3f1e..419f0e8 100644 --- a/kernel/src/kernel/k_main.rs +++ b/kernel/src/kernel/k_main.rs @@ -30,11 +30,7 @@ pub fn _kernel_main() -> ! { if let time = rtc::get_time() { kprintln!("Date/Time: {}", time.format()); } - - log_info!("{}", cpu::cpu_rdtscp()) ; - kprintln!(); - - log_info!("System initialization complete!"); + kprintln!(); kprintln!("Type 'help' for available commands"); kprintln!(); diff --git a/kernel/src/shell/commands.rs b/kernel/src/shell/commands.rs index 168a47a..e7274f1 100644 --- a/kernel/src/shell/commands.rs +++ b/kernel/src/shell/commands.rs @@ -1,15 +1,17 @@ // kernel/src/shell/commands.rs -use crate::{kprintln, tty, hal::{rtc, timer, cpu}, mm::allocator::pmm, log_info}; +use crate::{kprintln, tty, hal::{rtc, timer, cpu}, log_info}; use crate::hal::io::io_port_wb; - +use crate::hal::power; +use crate::mm::{vma, vmm, allocator::pmm}; /// help 命令 pub fn cmd_help() { - kprintln!(" help - Show this help message"); - kprintln!(" clear - Clear the screen"); - kprintln!(" time - Display current date and time"); - kprintln!(" uptime - Show system uptime"); - kprintln!(" sysinfo - Display system information"); - kprintln!(" reboot - Reboot the system"); + kprintln!(" help - Show this help message"); + kprintln!(" clear | clr - Clear the screen"); + kprintln!(" time - Display current date and time"); + kprintln!(" uptime - Show system uptime"); + kprintln!(" sysinfo | sys - Display system information"); + kprintln!(" meminfo | mem - Display memory information"); + kprintln!(" reboot - Reboot the system"); kprintln!(); } @@ -51,6 +53,93 @@ pub fn cmd_echo(text: &str) { } } +pub fn cmd_meminfo() { + kprintln!(); + kprintln!("=== Memory Layout ==="); + kprintln!(); + + // 高半核地址空間布局 + kprintln!("Virtual Memory Layout:"); + kprintln!(" User Space: {:#018x} - {:#018x}", + 0x0u64, + 0x0000_7FFF_FFFF_FFFFu64 + ); + kprintln!(" (Non-canonical): {:#018x} - {:#018x}", + 0x0000_8000_0000_0000u64, + 0xFFFF_7FFF_FFFF_FFFFu64 + ); + kprintln!(" Physical Map: {:#018x} - {:#018x}", + vma::PHYS_MEM_OFFSET, + vma::HIGHER_HALF_BASE - 1 + ); + kprintln!(" Kernel Base: {:#018x}", vma::HIGHER_HALF_BASE); + kprintln!(" Kernel Heap: {:#018x} - {:#018x} ({} KiB)", + vma::HEAP_START.as_u64(), + vma::HEAP_START.as_u64() + vma::HEAP_SIZE as u64, + vma::HEAP_SIZE / 1024 + ); + kprintln!(" Kernel Dynamic: {:#018x} - {:#018x} ({} MiB)", + vma::KERNEL_DYNAMIC_START.as_u64(), + vma::KERNEL_DYNAMIC_END.as_u64(), + vma::KERNEL_DYNAMIC_SIZE / (1024 * 1024) + ); + kprintln!(" Kernel Stack: {:#018x} - {:#018x} ({} MiB)", + vma::KERNEL_STACK_START.as_u64(), + vma::KERNEL_STACK_END.as_u64(), + vma::KERNEL_STACK_SIZE / (1024 * 1024) + ); + kprintln!(" Device Mapping: {:#018x} - {:#018x} ({} MiB)", + vma::DEVICE_MAPPING_START.as_u64(), + vma::DEVICE_MAPPING_END.as_u64(), + vma::DEVICE_MAPPING_SIZE / (1024 * 1024) + ); + + kprintln!(); + kprintln!("Physical Memory (PMM):"); + + if let Some(stats) = pmm::get_memory_stats() { + kprintln!(" Total: {} MiB ({} frames)", + stats.total_memory / (1024 * 1024), + stats.total_frames + ); + kprintln!(" Used: {} MiB ({} frames)", + stats.used_memory / (1024 * 1024), + stats.allocated_frames + ); + kprintln!(" Free: {} MiB ({} frames)", + stats.free_memory / (1024 * 1024), + stats.free_frames + ); + kprintln!(" Usage: {}%", + (stats.used_memory * 100) / stats.total_memory + ); + } else { + kprintln!(" (PMM not initialized)"); + } + + kprintln!(); + kprintln!("Virtual Memory Manager (VMM):"); + + let vmm_stats = vmm::get_vmm_stats(); + kprintln!(" Next Address: {:#018x}", vmm_stats.next_vaddr.as_u64()); + kprintln!(" Allocated: {} pages ({} KiB) in {} blocks", + vmm_stats.allocated_pages, + vmm_stats.allocated_pages * 4, + vmm_stats.allocated_blocks_count + ); + kprintln!(" Free: {} pages ({} KiB) in {} blocks", + vmm_stats.free_pages, + vmm_stats.free_pages * 4, + vmm_stats.free_blocks_count + ); + kprintln!(" New Usage: {} pages ({} KiB)", + vmm_stats.used_from_new, + vmm_stats.used_from_new * 4 + ); + + kprintln!(); +} + pub fn cmd_sysinfo() { kprintln!(); kprintln!("=== System Information ==="); @@ -81,58 +170,17 @@ pub fn cmd_sysinfo() { kprintln!(); } +pub fn cmd_shutdown() { + kprintln!("Shutdown system..."); + cpu::cpu_pause(1000); + tty::tty::clear(0x000000); + power::shutdown(); +} + pub fn cmd_reboot() { kprintln!("Rebooting system..."); - cpu::cpu_pause(1000); tty::tty::clear(0x000000); - log_info!("Disabling CPU interrupts"); - cpu::cpu_disable_interrupts(); - - log_info!("Disabling RTC Timer"); - rtc::disable_timer(); - - unsafe { - io_port_wb(0x64, 0xFE); - - log_info!("Complete"); - - loop { - cpu::cpu_halt(); - } - } -} - -pub fn cmd_halt() { - kprintln!("System Statistics:"); - - let ticks = timer::get_tick_count(); - let total_seconds = ticks / 100; - let hours = total_seconds / 3600; - let minutes = (total_seconds % 3600) / 60; - let seconds = total_seconds % 60; - kprintln!(" Uptime: {}h {}m {}s", hours, minutes, seconds); - - if let Some(stats) = pmm::get_memory_stats() { - kprintln!(" Memory Used: {} MiB / {} MiB", - stats.used_memory / (1024 * 1024), - stats.total_memory / (1024 * 1024)); - } - - if let time = rtc::get_time() { - kprintln!(" Shutdown at: {}", time.format()); - } - - kprintln!(); - kprintln!("System halted. Safe to power off."); - kprintln!(); - - cpu::cpu_disable_interrupts(); - - rtc::disable_timer(); - - loop { - cpu::cpu_halt(); - } + power::reboot(); } diff --git a/kernel/src/shell/math.rs b/kernel/src/shell/math.rs new file mode 100644 index 0000000..8544055 --- /dev/null +++ b/kernel/src/shell/math.rs @@ -0,0 +1,138 @@ +use alloc::string::String; +use alloc::vec::Vec; +use crate::kprint; + +#[derive(Debug)] +pub enum CalcError { + UnexpectedChar(char), + UnexpectedEnd, + DivisionByZero, + InvalidNumber, +} + +pub fn eval_expression(expr: &str) -> Result { + let mut parser = Parser::new(expr); + let result = parser.parse_expr()?; + parser.skip_whitespace(); + if parser.pos < parser.chars.len() { + Err(CalcError::UnexpectedChar(parser.chars[parser.pos])) + } else { + Ok(result) + } +} + +struct Parser<'a> { + chars: Vec, + pos: usize, + _expr: &'a str, +} + +impl<'a> Parser<'a> { + fn new(expr: &'a str) -> Self { + Self { + chars: expr.chars().collect(), + pos: 0, + _expr: expr, + } + } + + fn peek(&self) -> Option { + self.chars.get(self.pos).cloned() + } + + fn next(&mut self) -> Option { + let c = self.chars.get(self.pos).cloned(); + if c.is_some() { + self.pos += 1; + } + c + } + + fn skip_whitespace(&mut self) { + while let Some(c) = self.peek() { + if c.is_whitespace() { + self.pos += 1; + } else { + break; + } + } + } + fn parse_number(&mut self) -> Result { + self.skip_whitespace(); + let start = self.pos; + while let Some(c) = self.peek() { + if c.is_ascii_digit() || c == '.' { + self.pos += 1; + } else { + break; + } + } + if start == self.pos { + return Err(CalcError::InvalidNumber); + } + let s: String = self.chars[start..self.pos].iter().collect(); + s.parse::().map_err(|_| CalcError::InvalidNumber) + } + + fn parse_factor(&mut self) -> Result { + self.skip_whitespace(); + match self.peek() { + Some('(') => { + self.next(); + let val = self.parse_expr()?; + self.skip_whitespace(); + if self.next() != Some(')') { + return Err(CalcError::UnexpectedEnd); + } + Ok(val) + } + Some('-') => { + self.next(); + Ok(-self.parse_factor()?) + } + _ => self.parse_number(), + } + } + + fn parse_term(&mut self) -> Result { + let mut val = self.parse_factor()?; + loop { + self.skip_whitespace(); + match self.peek() { + Some('*') => { + self.next(); + val *= self.parse_factor()?; + } + Some('/') => { + self.next(); + let rhs = self.parse_factor()?; + if rhs == 0.0 { + return Err(CalcError::DivisionByZero); + } + val /= rhs; + } + _ => break, + } + } + Ok(val) + } + + fn parse_expr(&mut self) -> Result { + let mut val = self.parse_term()?; + loop { + self.skip_whitespace(); + match self.peek() { + Some('+') => { + self.next(); + val += self.parse_term()?; + } + Some('-') => { + self.next(); + val -= self.parse_term()?; + } + _ => break, + } + } + Ok(val) + } +} diff --git a/kernel/src/shell/mod.rs b/kernel/src/shell/mod.rs index 37116b7..5902855 100644 --- a/kernel/src/shell/mod.rs +++ b/kernel/src/shell/mod.rs @@ -4,6 +4,7 @@ use spin::Mutex; use crate::{kprint, kprintln, tty, hal::{rtc, timer}}; pub mod commands; +pub mod math; static COMMAND_BUFFER: Mutex = Mutex::new(String::new()); @@ -12,7 +13,7 @@ pub fn init() { } pub fn show_prompt() { - kprint!("cure > "); + tty::tty::write_str("cure > ", 0x00FF00); } pub fn process_keyboard_char(c: char) { @@ -37,23 +38,29 @@ pub fn process_keyboard_char(c: char) { } fn execute_command(cmd: &str) { - let cmd = cmd.trim(); + let mut cmd = cmd.trim(); if cmd.is_empty() { return; } - + match cmd { "help" => commands::cmd_help(), - "clear" => commands::cmd_clear(), + "clear" | "clr" => commands::cmd_clear(), "time" => commands::cmd_time(), "uptime" => commands::cmd_uptime(), - "sysinfo" => commands::cmd_sysinfo(), + "sysinfo" | "sys" => commands::cmd_sysinfo(), + "meminfo" | "mem" => commands::cmd_meminfo(), "reboot" => commands::cmd_reboot(), - "halt" | "shutdown" | "poweroff" => commands::cmd_halt(), + "halt" | "shutdown" | "poweroff" => commands::cmd_shutdown(), _ => { - kprintln!("Unknown command: '{}'", cmd); - kprintln!("Type 'help' for available commands"); + match math::eval_expression(cmd) { + Ok(result) => kprintln!("{}", result), + Err(_) => { + kprintln!("Unknown command: '{}'", cmd); + kprintln!("Type 'help' for available commands"); + } + } } } } \ No newline at end of file diff --git a/kernel/src/tty/tty.rs b/kernel/src/tty/tty.rs index 62ff4e5..dc06676 100644 --- a/kernel/src/tty/tty.rs +++ b/kernel/src/tty/tty.rs @@ -128,6 +128,28 @@ impl TTYState { return; } + if c == '\x08' { + if self.cursor_x >= CHAR_WIDTH { + self.cursor_x -= CHAR_WIDTH; + + for y in 0..CHAR_HEIGHT { + for x in 0..CHAR_WIDTH { + self.draw_pixel(self.cursor_x + x, self.cursor_y + y, 0x000000); + } + } + } else if self.cursor_y >= CHAR_HEIGHT { + self.cursor_y -= CHAR_HEIGHT; + self.cursor_x = (self.info.width / CHAR_WIDTH - 1) * CHAR_WIDTH; + + for y in 0..CHAR_HEIGHT { + for x in 0..CHAR_WIDTH { + self.draw_pixel(self.cursor_x + x, self.cursor_y + y, 0x000000); + } + } + } + return; + } + if c == '\n' { self.cursor_x = 0; self.cursor_y += CHAR_HEIGHT; @@ -160,6 +182,9 @@ impl TTYState { for x in 0..8 { if (row >> (7 - x)) & 1 == 1 { self.draw_pixel(cursor_x + x, cursor_y + y, color); + } else { + // 同時清除背景 + self.draw_pixel(cursor_x + x, cursor_y + y, 0x000000); } } }