feat: ACPI reboot implementation

This commit is contained in:
ParrotXray 2025-10-18 16:04:48 +08:00
parent 687c59f467
commit 8bae31852d
12 changed files with 433 additions and 264 deletions

View File

@ -22,8 +22,7 @@
// - 用戶態/內核態切換
// BUG
// - ACPI 關機 mem 映射問題
// 5. 回收
// - 關機重啟回收記憶體
// ==================== 高半核地址空間佈局 ====================

View File

@ -3,9 +3,10 @@ use x86_64::instructions::port::Port;
use x86_64::structures::idt::{InterruptStackFrame, PageFaultErrorCode};
use x86_64::VirtAddr;
use crate::{drivers, kprintln};
use crate::{log_trace, log_debug, log_info, log_warn, log_error, log_fatal};
use crate::{log_debug, log_error, log_fatal, log_info, log_trace, log_warn};
use super::gdt;
use crate::hal::{timer, cpu, lapic, rtc};
use crate::hal::{cpu, rtc, timer};
use crate::hal::apic::lapic;
use crate::mm::paging;
/// Divide Error (#DE)

View File

@ -1,4 +1,4 @@
use super::power::{extract_power_info, store_power_info};
use super::power::{extract_power_info, extract_reset_reg, store_power_info, store_reset_reg};
use super::{AcpiInfo, CureAcpiHandler};
use crate::hal::{cpu, io};
use crate::kprintln;
@ -126,6 +126,14 @@ pub fn init(rsdp_addr: u64, physical_memory_offset: u64) -> Option<AcpiInfo> {
log_warn!("Could not extract ACPI power info");
}
kprintln!();
log_info!("Extracting reset register information...");
if let Some(reset_reg) = extract_reset_reg(&platform.tables) {
store_reset_reg(reset_reg);
} else {
log_warn!("Could not extract ACPI reset register");
}
log_info!("ACPI initialized successfully!");
Some(AcpiInfo {

View File

@ -29,6 +29,16 @@ pub struct AcpiPowerInfo {
pub slp_en: u16,
}
/// ACPI 重置寄存器信息
#[derive(Debug, Clone, Copy)]
pub struct ResetRegister {
pub address_space: u8, // 0=SystemMemory, 1=SystemIO, 2=PciConfig
pub address: u64,
pub value: u8,
}
static mut ACPI_RESET_REG: Option<ResetRegister> = None;
static mut ACPI_POWER_INFO: Option<AcpiPowerInfo> = None;
impl CureAcpiHandler {

View File

@ -1,4 +1,4 @@
use super::{AcpiPowerInfo, CureAcpiHandler, ACPI_POWER_INFO};
use super::{AcpiPowerInfo, CureAcpiHandler, ResetRegister, ACPI_POWER_INFO, ACPI_RESET_REG};
use crate::hal::{cpu, io};
use crate::kprintln;
use crate::mm::vma;
@ -83,10 +83,7 @@ fn parse_s5_object(dsdt_phys_addr: u64, handler: &CureAcpiHandler) -> Option<(u1
// Map the DSDT header first to get the length
let dsdt_header_mapping = unsafe {
handler.map_physical_region::<SdtHeader>(
dsdt_phys_addr as usize,
size_of::<SdtHeader>(),
)
handler.map_physical_region::<SdtHeader>(dsdt_phys_addr as usize, size_of::<SdtHeader>())
};
if dsdt_header_mapping.signature != Signature::DSDT {
@ -108,7 +105,7 @@ fn parse_s5_object(dsdt_phys_addr: u64, handler: &CureAcpiHandler) -> Option<(u1
let dsdt_ptr = dsdt_mapping.virtual_start.as_ptr();
let dsdt_data = core::slice::from_raw_parts(dsdt_ptr, dsdt_length);
// 在 DSDT 中搜索 "_S5_"
// Search DSDT for "_S5_"
let s5_name = b"_S5_";
for i in 0..(dsdt_data.len() - 4) {
@ -121,7 +118,7 @@ fn parse_s5_object(dsdt_phys_addr: u64, handler: &CureAcpiHandler) -> Option<(u1
let mut offset = i + 4; // Skip "_S5_"
// Skip any intermediate bytes and go straight to PackageOp
let search_limit = offset + 8;
let search_limit = offset + 16;
while offset < search_limit && offset < dsdt_data.len() {
if dsdt_data[offset] == 0x12 {
log_debug!("Found PackageOp at offset {:#x}", offset);
@ -248,15 +245,16 @@ fn get_pkg_length_size(data: &[u8]) -> usize {
1 + byte_count
}
/// 解析 AML 整數
/// Parse AML integer
fn parse_aml_integer(data: &[u8]) -> Option<u64> {
if data.is_empty() {
return None;
}
match data[0] {
0x00 => Some(0), // ZeroOp
0x01 => Some(1), // OneOp
0x00 => Some(0), // ZeroOp
0x01 => Some(1), // OneOp
0xFF => Some(0xFFFFFFFF), // OnesOp
0x0A => {
// BytePrefix
if data.len() < 2 {
@ -287,7 +285,10 @@ fn parse_aml_integer(data: &[u8]) -> Option<u64> {
data[1], data[2], data[3], data[4], data[5], data[6], data[7], data[8],
]))
}
_ => None,
_ => {
log_warn!("Unknown AML integer prefix: {:#02x}", data[0]);
None
}
}
}
@ -298,17 +299,17 @@ fn get_aml_integer_size(data: &[u8]) -> usize {
}
match data[0] {
0x00 | 0x01 => 1,
0x0A => 2,
0x0B => 3,
0x0C => 5,
0x0E => 9,
0x00 | 0x01 | 0xFF => 1, // Zero, One, Ones
0x0A => 2, // Byte
0x0B => 3, // Word
0x0C => 5, // DWord
0x0E => 9, // QWord
_ => 1,
}
}
/// Perform ACPI shutdown
pub fn acpi_shutdown() -> ! {
pub fn acpi_shutdown() -> bool {
log_info!("Attempting ACPI shutdown...");
let power_info = unsafe {
@ -316,7 +317,7 @@ pub fn acpi_shutdown() -> ! {
Some(info) => info,
None => {
log_error!("ACPI power info not initialized!");
return fallback_shutdown();
return false;
}
}
};
@ -344,40 +345,11 @@ pub fn acpi_shutdown() -> ! {
io::io_port_ww(power_info.pm1b_control_block as u16, slp_cmd_b);
}
// 等待關機
for _ in 0..1000000 {
cpu::cpu_pause(100);
}
cpu::cpu_pause(10000);
}
log_error!("ACPI shutdown failed!");
fallback_shutdown()
}
/// Backup shutdown method
fn fallback_shutdown() -> ! {
log_warn!("Using fallback shutdown methods...");
unsafe {
// QEMU
io::io_port_ww(0x604, 0x2000);
cpu::cpu_pause(10000);
// Bochs
for &c in b"Shutdown" {
io::io_port_wb(0x8900, c);
}
cpu::cpu_pause(10000);
// VirtualBox
io::io_port_ww(0x4004, 0x3400);
}
log_error!("All shutdown methods failed!");
loop {
cpu::cpu_halt();
}
false
}
/// Store ACPI shutdown information
@ -387,3 +359,181 @@ pub fn store_power_info(info: AcpiPowerInfo) {
}
log_info!("ACPI power info stored successfully");
}
/// Extract reset register information from FADT
pub fn extract_reset_reg(tables: &AcpiTables<CureAcpiHandler>) -> Option<ResetRegister> {
log_info!("Extracting ACPI reset register info...");
let fadt = match tables.find_table::<sdt::fadt::Fadt>() {
Some(fadt) => fadt,
None => {
log_error!("Failed to find FADT");
return None;
}
};
unsafe {
let fadt_ptr = (&*fadt as *const sdt::fadt::Fadt) as *const u8;
let fadt_revision = core::ptr::read_unaligned(fadt_ptr.add(8) as *const u8);
if fadt_revision < 2 {
log_warn!("FADT revision {} does not support RESET_REG", fadt_revision);
return None;
}
// 讀取 Flags (offset 112 in FADT)
let flags = core::ptr::read_unaligned(fadt_ptr.add(112) as *const u32);
let reset_reg_supported = (flags & (1 << 10)) != 0;
if !reset_reg_supported {
log_warn!("RESET_REG not supported (FADT flags bit 10 not set)");
return None;
}
// RESET_REG is at offset 116 in the FADT
// Generic Address Structure format:
// +0: Address Space ID (1 byte)
// +1: Register Bit Width (1 byte)
// +2: Register Bit Offset (1 byte)
// +3: Access Size (1 byte)
// +4: Address (8 bytes)
let reset_reg_offset = 116;
let address_space = core::ptr::read_unaligned(fadt_ptr.add(reset_reg_offset) as *const u8);
let bit_width = core::ptr::read_unaligned(fadt_ptr.add(reset_reg_offset + 1) as *const u8);
let bit_offset = core::ptr::read_unaligned(fadt_ptr.add(reset_reg_offset + 2) as *const u8);
let address = core::ptr::read_unaligned(fadt_ptr.add(reset_reg_offset + 4) as *const u64);
// RESET_VALUE is after RESET_REG (offset 128)
let reset_value = core::ptr::read_unaligned(fadt_ptr.add(128) as *const u8);
if bit_width != 8 || bit_offset != 0 {
log_warn!(
"Invalid RESET_REG configuration: width={}, offset={}",
bit_width,
bit_offset
);
return None;
}
if address_space > 2 {
log_warn!("Invalid address space ID: {}", address_space);
return None;
}
log_info!("RESET_REG found:");
log_info!(
" Address Space: {} ({})",
address_space,
match address_space {
0 => "System Memory",
1 => "System I/O",
2 => "PCI Config",
_ => "Unknown",
}
);
log_info!("Address: {:#x}", address);
log_info!("Reset Value: {:#x}", reset_value);
Some(ResetRegister {
address_space,
address,
value: reset_value,
})
}
}
pub fn store_reset_reg(reset_reg: ResetRegister) {
unsafe {
ACPI_RESET_REG = Some(reset_reg);
}
log_info!("ACPI reset register info stored");
}
/// Restart using ACPI RESET_REG
pub fn acpi_reset_reg_reboot() -> bool {
unsafe {
let reset_reg = match &ACPI_RESET_REG {
Some(reg) => reg,
None => {
log_debug!("ACPI RESET_REG not available");
return false;
}
};
log_info!("Using ACPI RESET_REG for reboot");
log_info!(
" Space: {}, Address: {:#x}, Value: {:#x}",
reset_reg.address_space,
reset_reg.address,
reset_reg.value
);
match reset_reg.address_space {
// System I/O
1 => {
log_debug!(
"Writing {:#x} to I/O port {:#x}",
reset_reg.value,
reset_reg.address
);
io::io_port_wb(reset_reg.address as u16, reset_reg.value);
true
}
// System Memory
0 => {
log_debug!(
"Writing {:#x} to memory address {:#x}",
reset_reg.value,
reset_reg.address
);
let virt_addr = vma::phys_to_virt(reset_reg.address);
let ptr = virt_addr.as_mut_ptr::<u8>();
core::ptr::write_volatile(ptr, reset_reg.value);
true
}
// PCI Config Space
2 => {
log_debug!(
"Writing {:#x} to PCI config space {:#x}",
reset_reg.value,
reset_reg.address
);
// PCI address encoding (ACPI format):
// Bits 63-32: Reserved
// Bits 31-16: Bus Number
// Bits 15-11: Device Number
// Bits 10-8: Function Number
// Bits 7-0: Register Offset
let bus = ((reset_reg.address >> 16) & 0xFFFF) as u8;
let device = ((reset_reg.address >> 11) & 0x1F) as u8;
let function = ((reset_reg.address >> 8) & 0x7) as u8;
let offset = (reset_reg.address & 0xFF) as u8;
log_debug!(
"PCI Bus={}, Dev={}, Func={}, Offset={:#x}",
bus,
device,
function,
offset
);
// TODO: 調用你的 PCI 配置空間寫入函數
// pci_config_write_byte(bus, device, function, offset, reset_reg.value);
false
}
_ => {
log_error!("Unknown address space: {}", reset_reg.address_space);
false
}
}
}
}

View File

@ -1,106 +1,8 @@
// kernel/src/hal/ioapic.rs - 無鎖設計
// kernel/src/hal/ioapic.rs
use super::{redir_flags, reg, IoApicInfo, IO_APICS, IO_APIC_COUNT, MAX_IOAPICS};
use crate::{log_debug, log_error, log_info, log_trace, log_warn};
use x86_64::VirtAddr;
use crate::{log_trace, log_debug, log_info, log_warn, log_error};
/// IO APIC register selector
const IOREGSEL: u32 = 0x00;
const IOWIN: u32 = 0x10;
/// IO APIC register index
#[allow(dead_code)]
mod reg {
pub const ID: u8 = 0x00;
pub const VER: u8 = 0x01;
pub const ARB: u8 = 0x02;
pub const REDTBL_BASE: u8 = 0x10;
}
/// Redirection Entry flag
#[allow(dead_code)]
mod redir_flags {
pub const MASKED: u64 = 1 << 16;
pub const TRIGGER_LEVEL: u64 = 1 << 15;
pub const TRIGGER_EDGE: u64 = 0;
pub const POLARITY_LOW: u64 = 1 << 13;
pub const POLARITY_HIGH: u64 = 0;
pub const DEST_LOGICAL: u64 = 1 << 11;
pub const DEST_PHYSICAL: u64 = 0;
pub const DELIVERY_FIXED: u64 = 0 << 8;
pub const DELIVERY_LOWEST: u64 = 1 << 8;
}
// Supports up to 8 IO APICs
const MAX_IOAPICS: usize = 8;
//IO APIC information array (read-only after initialization)
static mut IO_APICS: [Option<IoApicInfo>; MAX_IOAPICS] = [None; MAX_IOAPICS];
static mut IO_APIC_COUNT: usize = 0;
#[derive(Debug, Clone, Copy)]
struct IoApicInfo {
base_vaddr: VirtAddr,
id: u8,
gsi_base: u32,
max_redirection_entries: u8,
}
impl IoApicInfo {
/// Read IO APIC register
#[inline]
unsafe fn read(&self, reg: u8) -> u32 {
let regsel_addr = self.base_vaddr.as_u64() + IOREGSEL as u64;
let win_addr = self.base_vaddr.as_u64() + IOWIN as u64;
core::ptr::write_volatile(regsel_addr as *mut u32, reg as u32);
core::ptr::read_volatile(win_addr as *const u32)
}
/// Write to IO APIC register
#[inline]
unsafe fn write(&self, reg: u8, value: u32) {
let regsel_addr = self.base_vaddr.as_u64() + IOREGSEL as u64;
let win_addr = self.base_vaddr.as_u64() + IOWIN as u64;
core::ptr::write_volatile(regsel_addr as *mut u32, reg as u32);
core::ptr::write_volatile(win_addr as *mut u32, value);
}
/// Read the redirection table entry
#[inline]
unsafe fn read_redirection_entry(&self, irq: u8) -> u64 {
if irq >= self.max_redirection_entries {
log_warn!("IRQ {} out of range for IO APIC {}", irq, self.id);
return 0;
}
let low_reg = reg::REDTBL_BASE + (irq * 2);
let high_reg = low_reg + 1;
let low = self.read(low_reg) as u64;
let high = self.read(high_reg) as u64;
(high << 32) | low
}
/// Write redirection table entry
#[inline]
unsafe fn write_redirection_entry(&self, irq: u8, entry: u64) {
if irq >= self.max_redirection_entries {
log_warn!("IRQ {} out of range for IO APIC {}", irq, self.id);
return;
}
let low_reg = reg::REDTBL_BASE + (irq * 2);
let high_reg = low_reg + 1;
let low = entry as u32;
let high = (entry >> 32) as u32;
self.write(high_reg, high);
self.write(low_reg, low);
}
}
/// Initialize a single IO APIC (using mapped virtual addresses)
///
@ -305,4 +207,4 @@ pub fn print_info() {
}
}
}
}
}

View File

@ -1,68 +1,11 @@
// kernel/src/hal/lapic.rs
use x86_64::VirtAddr;
use crate::{log_trace, log_debug, log_info, log_warn, log_error};
use super::{flags, ApicInfo, ApicRegister, APIC_INFO, LOCAL_APIC_BASE};
use crate::hal::io;
use crate::mm::vma;
use crate::{log_debug, log_error, log_info, log_trace, log_warn};
use x86_64::VirtAddr;
/// Local APIC register offset
#[repr(u32)]
#[derive(Debug, Clone, Copy)]
#[allow(dead_code)]
pub enum ApicRegister {
Id = 0x20,
Version = 0x30,
TaskPriority = 0x80,
ProcessorPriority = 0xA0,
Eoi = 0xB0,
LogicalDestination = 0xD0,
DestinationFormat = 0xE0,
SpuriousInterruptVector = 0xF0,
ErrorStatus = 0x280,
LvtTimer = 0x320,
LvtThermalSensor = 0x330,
LvtPerformanceCounter = 0x340,
LvtLint0 = 0x350,
LvtLint1 = 0x360,
LvtError = 0x370,
TimerInitialCount = 0x380,
TimerCurrentCount = 0x390,
TimerDivideConfig = 0x3E0,
}
/// APIC configuration flags
#[allow(dead_code)]
pub mod flags {
pub const APIC_ENABLE: u32 = 0x100;
pub const APIC_SW_ENABLE: u32 = 0x100;
pub const APIC_SPURIOUS_ALL: u32 = 0xFF;
pub const LVT_MASKED: u32 = 1 << 16;
pub const LVT_TIMER_PERIODIC: u32 = 1 << 17;
pub const LVT_TIMER_ONESHOT: u32 = 0 << 17;
}
// Local APIC base address (read-only after initialization)
static mut LOCAL_APIC_BASE: Option<VirtAddr> = None;
// APIC information (read-only after initialization)
static mut APIC_INFO: ApicInfo = ApicInfo::new();
struct ApicInfo {
id: u32,
version: u32,
max_lvt: u32,
}
impl ApicInfo {
const fn new() -> Self {
Self {
id: 0,
version: 0,
max_lvt: 0,
}
}
}
/// Read APIC registers
///
/// # Safety
@ -124,10 +67,10 @@ pub unsafe fn write_apic_reg_raw(offset: u32, value: u32) -> bool {
pub unsafe fn init_local_apic_with_vaddr(base_vaddr: VirtAddr) {
log_debug!("Initializing Local APIC at {:#x}", base_vaddr.as_u64());
// 儲存基地址
// Storage base address
LOCAL_APIC_BASE = Some(base_vaddr);
// 讀取 APIC 信息
// Read APIC information
let id_reg = read_apic_reg(ApicRegister::Id).unwrap();
let version_reg = read_apic_reg(ApicRegister::Version).unwrap();
@ -181,9 +124,7 @@ pub fn send_eoi() {
/// Get the Local APIC ID
#[inline]
pub fn get_apic_id() -> Option<u32> {
unsafe {
Some(APIC_INFO.id)
}
unsafe { Some(APIC_INFO.id) }
}
/// Get the Local APIC base virtual address
@ -220,7 +161,6 @@ pub fn get_max_lvt() -> Option<u32> {
///
/// Must be called before using the APIC to avoid conflicts
pub fn disable_legacy_pic() {
unsafe {
// Master PIC
io::io_port_wb(0x20, 0x11); // ICW1: initialization
@ -253,4 +193,4 @@ pub fn print_info() {
log_warn!("Local APIC not initialized");
}
}
}
}

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

@ -0,0 +1,163 @@
use x86_64::VirtAddr;
use crate::log_warn;
pub mod ioapic;
pub mod lapic;
/// IO APIC register selector
const IOREGSEL: u32 = 0x00;
const IOWIN: u32 = 0x10;
/// IO APIC register index
#[allow(dead_code)]
mod reg {
pub const ID: u8 = 0x00;
pub const VER: u8 = 0x01;
pub const ARB: u8 = 0x02;
pub const REDTBL_BASE: u8 = 0x10;
}
/// Redirection Entry flag
#[allow(dead_code)]
mod redir_flags {
pub const MASKED: u64 = 1 << 16;
pub const TRIGGER_LEVEL: u64 = 1 << 15;
pub const TRIGGER_EDGE: u64 = 0;
pub const POLARITY_LOW: u64 = 1 << 13;
pub const POLARITY_HIGH: u64 = 0;
pub const DEST_LOGICAL: u64 = 1 << 11;
pub const DEST_PHYSICAL: u64 = 0;
pub const DELIVERY_FIXED: u64 = 0 << 8;
pub const DELIVERY_LOWEST: u64 = 1 << 8;
}
// Supports up to 8 IO APICs
const MAX_IOAPICS: usize = 8;
//IO APIC information array (read-only after initialization)
static mut IO_APICS: [Option<IoApicInfo>; MAX_IOAPICS] = [None; MAX_IOAPICS];
static mut IO_APIC_COUNT: usize = 0;
#[derive(Debug, Clone, Copy)]
struct IoApicInfo {
base_vaddr: VirtAddr,
id: u8,
gsi_base: u32,
max_redirection_entries: u8,
}
/// Local APIC register offset
#[repr(u32)]
#[derive(Debug, Clone, Copy)]
#[allow(dead_code)]
pub enum ApicRegister {
Id = 0x20,
Version = 0x30,
TaskPriority = 0x80,
ProcessorPriority = 0xA0,
Eoi = 0xB0,
LogicalDestination = 0xD0,
DestinationFormat = 0xE0,
SpuriousInterruptVector = 0xF0,
ErrorStatus = 0x280,
LvtTimer = 0x320,
LvtThermalSensor = 0x330,
LvtPerformanceCounter = 0x340,
LvtLint0 = 0x350,
LvtLint1 = 0x360,
LvtError = 0x370,
TimerInitialCount = 0x380,
TimerCurrentCount = 0x390,
TimerDivideConfig = 0x3E0,
}
/// APIC configuration flags
#[allow(dead_code)]
pub mod flags {
pub const APIC_ENABLE: u32 = 0x100;
pub const APIC_SW_ENABLE: u32 = 0x100;
pub const APIC_SPURIOUS_ALL: u32 = 0xFF;
pub const LVT_MASKED: u32 = 1 << 16;
pub const LVT_TIMER_PERIODIC: u32 = 1 << 17;
pub const LVT_TIMER_ONESHOT: u32 = 0 << 17;
}
// Local APIC base address (read-only after initialization)
static mut LOCAL_APIC_BASE: Option<VirtAddr> = None;
// APIC information (read-only after initialization)
static mut APIC_INFO: ApicInfo = ApicInfo::new();
struct ApicInfo {
id: u32,
version: u32,
max_lvt: u32,
}
impl ApicInfo {
const fn new() -> Self {
Self {
id: 0,
version: 0,
max_lvt: 0,
}
}
}
impl IoApicInfo {
/// Read IO APIC register
#[inline]
unsafe fn read(&self, reg: u8) -> u32 {
let regsel_addr = self.base_vaddr.as_u64() + IOREGSEL as u64;
let win_addr = self.base_vaddr.as_u64() + IOWIN as u64;
core::ptr::write_volatile(regsel_addr as *mut u32, reg as u32);
core::ptr::read_volatile(win_addr as *const u32)
}
/// Write to IO APIC register
#[inline]
unsafe fn write(&self, reg: u8, value: u32) {
let regsel_addr = self.base_vaddr.as_u64() + IOREGSEL as u64;
let win_addr = self.base_vaddr.as_u64() + IOWIN as u64;
core::ptr::write_volatile(regsel_addr as *mut u32, reg as u32);
core::ptr::write_volatile(win_addr as *mut u32, value);
}
/// Read the redirection table entry
#[inline]
unsafe fn read_redirection_entry(&self, irq: u8) -> u64 {
if irq >= self.max_redirection_entries {
log_warn!("IRQ {} out of range for IO APIC {}", irq, self.id);
return 0;
}
let low_reg = reg::REDTBL_BASE + (irq * 2);
let high_reg = low_reg + 1;
let low = self.read(low_reg) as u64;
let high = self.read(high_reg) as u64;
(high << 32) | low
}
/// Write redirection table entry
#[inline]
unsafe fn write_redirection_entry(&self, irq: u8, entry: u64) {
if irq >= self.max_redirection_entries {
log_warn!("IRQ {} out of range for IO APIC {}", irq, self.id);
return;
}
let low_reg = reg::REDTBL_BASE + (irq * 2);
let high_reg = low_reg + 1;
let low = entry as u32;
let high = (entry >> 32) as u32;
self.write(high_reg, high);
self.write(low_reg, low);
}
}

View File

@ -2,7 +2,6 @@ pub mod io;
pub mod cpu;
pub mod acpi;
pub mod rtc;
pub mod lapic;
pub mod ioapic;
pub mod timer;
pub mod power;
pub mod power;
pub mod apic;

View File

@ -71,18 +71,18 @@ fn try_shutdown(method: ShutdownMethod) {
}
ShutdownMethod::QemuExit => {
// QEMU isa-debug-exit 設備
// QEMU isa-debug-exit device
io::io_port_ww(0x604, 0x2000);
io::io_port_rl(0x501);
}
ShutdownMethod::BochsExit => {
// Bochs 專用關機端口
// Bochs dedicated shutdown port
io::io_port_ww(0xB004, 0x2000);
}
ShutdownMethod::VirtualBox => {
// VirtualBox 關機端口
// VirtualBox shutdown port
io::io_port_ww(0x4004, 0x3400);
}
@ -100,7 +100,7 @@ fn try_shutdown(method: ShutdownMethod) {
}
}
/// 重啟系統
/// Restart the system
pub fn reboot() -> ! {
log_info!("Rebooting system...");
@ -119,10 +119,10 @@ pub fn reboot() -> ! {
];
for method in methods.iter() {
log_debug!("Trying shutdown method: {:?}", method);
log_debug!("Trying reboot method: {:?}", method);
try_reboot(*method);
log_warn!("{:?} shutdown failed", method);
log_warn!("{:?} reboot failed", method);
cpu::cpu_pause(1000);
}
@ -137,42 +137,30 @@ pub fn reboot() -> ! {
fn try_reboot(method: RebootMethod) {
match method {
RebootMethod::BootACPI => {
acpi_reboot()
acpi::power::acpi_reset_reg_reboot();
}
RebootMethod::BootKBD => {
keyboard_controller_reboot()
keyboard_controller_reboot();
}
RebootMethod::BootCF9 => {
pci_reboot()
pci_reboot();
}
RebootMethod::BootEFI => {
efi_reboot()
efi_reboot();
}
RebootMethod::Boot92h => {
cpu_reset()
cpu_reset();
}
}
cpu::cpu_pause(10000);
}
fn acpi_reboot() {
log_debug!("Trying ACPI reboot...");
unsafe {
// ACPI FADT 的 RESET_REG
// 需要從 ACPI 表中讀取實際地址
// 這裡使用常見的地址作為示例
io::io_port_wb(0xCF9, 0x06);
cpu::cpu_pause(10000);
}
}
fn keyboard_controller_reboot() {
log_debug!("Trying keyboard controller reboot...");
fn keyboard_controller_reboot() -> bool {
log_debug!("keyboard controller reboot...");
unsafe {
for _ in 0..1000 {
@ -186,10 +174,12 @@ fn keyboard_controller_reboot() {
cpu::cpu_pause(100000);
}
false
}
fn pci_reboot() {
log_debug!("Trying PCI reboot...");
fn pci_reboot() -> bool {
log_debug!("PCI reboot...");
unsafe {
let mut val = io::io_port_rb(0xCF9) & !0x06;
@ -199,24 +189,29 @@ fn pci_reboot() {
cpu::cpu_pause(100000);
}
false
}
fn efi_reboot() {
fn efi_reboot() -> bool {
log_debug!("Trying EFI runtime services reboot...");
// TODO: 實現 EFI ResetSystem 調用
false
}
fn cpu_reset() {
log_debug!("Trying CPU reset via port 92h...");
fn cpu_reset() -> bool {
log_debug!("CPU reset via port 92h...");
unsafe {
let mut val = io::io_port_rb(0x92);
val &= !0x01; // 清除快速 A20 位
val |= 0x01; // 設置重置位
val &= !0x01; // Clear Fast A20 Bit
val |= 0x01; // Set the reset bit
io::io_port_wb(0x92, val);
cpu::cpu_pause(100000);
}
false
}

View File

@ -1,8 +1,9 @@
// kernel/src/hal/timer
use crate::hal::{lapic, rtc, cpu, ioapic};
use core::sync::atomic::{AtomicU64, AtomicBool, Ordering};
use crate::{log_info, log_debug, log_warn, log_error};
use crate::hal::{cpu, rtc};
use core::sync::atomic::{AtomicBool, AtomicU64, Ordering};
use crate::{log_debug, log_error, log_info, log_warn};
use crate::hal::apic::{ioapic, lapic};
const APIC_CALIBRATION_CONST: u32 = 0x100000;
const RTC_BASE_FREQUENCY: u32 = 1024;

View File

@ -3,7 +3,7 @@ use bootloader_api::BootInfo;
use bootloader_api::info::MemoryRegionKind;
use x86_64::structures::paging::OffsetPageTable;
use x86_64::{PhysAddr, VirtAddr};
use crate::mm::{allocator::{heap, frame, pmm}, vmm, paging, vma};
use crate::mm::{allocator::{frame, heap, pmm}, paging, vma, vmm};
use crate::arch::amd64::{gdt, idt};
use crate::tty::tty;
use crate::kprintln;
@ -12,7 +12,8 @@ use crate::klibc::logger::{init, LogLevel, LoggerConfig};
use crate::klibc::malloc;
use crate::{log_debug, log_error, log_info, log_trace, log_warn};
use crate::drivers::keyboard;
use crate::hal::{acpi, timer, cpu, ioapic, lapic, rtc};
use crate::hal::{acpi, cpu, rtc, timer};
use crate::hal::apic::{ioapic, lapic};
use crate::hal::cpu::cpu_enable_interrupts;
fn _logger_init() {
@ -294,5 +295,5 @@ pub fn _kernel_init(boot_info: &'static mut BootInfo) -> ! {
pub fn kernel_emergency_cleanup() {
log_error!("Emergency cleanup triggered");
// 在 panic 前調用,做最後的清理工作
// 比如刷新緩衝區、保存日誌等
// 刷新緩衝區、保存日誌等
}