feat: Implement shutdown and restart

This commit is contained in:
ParrotXray 2025-10-17 21:19:58 +08:00
parent 775626379e
commit d11c7842d4
14 changed files with 1125 additions and 245 deletions

View File

@ -23,7 +23,8 @@
// BUG
// - 在測試RTC中斷時 rtc::get_time() 處卡住
// - ACPI 關機 mem 映射問題
// - 關機重啟回收記憶體
// ==================== 高半核地址空間佈局 ====================
//

View File

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

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

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

View File

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

View File

@ -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<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;
}
};
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::<u8>();
// 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<u64> {
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");
}

View File

@ -4,4 +4,5 @@ pub mod acpi;
pub mod rtc;
pub mod lapic;
pub mod ioapic;
pub mod timer;
pub mod timer;
pub mod power;

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

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

View File

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

View File

@ -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<u64>, physical_memory_offset: u64) -> Option<acp
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");
@ -284,9 +280,7 @@ pub fn _kernel_init(boot_info: &'static mut BootInfo) -> ! {
_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();

View File

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

View File

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

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

View File

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

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