feat: ACPI reboot implementation
This commit is contained in:
parent
687c59f467
commit
8bae31852d
3
TODO.txt
3
TODO.txt
@ -22,8 +22,7 @@
|
|||||||
// - 用戶態/內核態切換
|
// - 用戶態/內核態切換
|
||||||
|
|
||||||
|
|
||||||
// BUG
|
// 5. 回收
|
||||||
// - ACPI 關機 mem 映射問題
|
|
||||||
// - 關機重啟回收記憶體
|
// - 關機重啟回收記憶體
|
||||||
|
|
||||||
// ==================== 高半核地址空間佈局 ====================
|
// ==================== 高半核地址空間佈局 ====================
|
||||||
|
|||||||
@ -3,9 +3,10 @@ use x86_64::instructions::port::Port;
|
|||||||
use x86_64::structures::idt::{InterruptStackFrame, PageFaultErrorCode};
|
use x86_64::structures::idt::{InterruptStackFrame, PageFaultErrorCode};
|
||||||
use x86_64::VirtAddr;
|
use x86_64::VirtAddr;
|
||||||
use crate::{drivers, kprintln};
|
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 super::gdt;
|
||||||
use crate::hal::{timer, cpu, lapic, rtc};
|
use crate::hal::{cpu, rtc, timer};
|
||||||
|
use crate::hal::apic::lapic;
|
||||||
use crate::mm::paging;
|
use crate::mm::paging;
|
||||||
|
|
||||||
/// Divide Error (#DE)
|
/// Divide Error (#DE)
|
||||||
|
|||||||
@ -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 super::{AcpiInfo, CureAcpiHandler};
|
||||||
use crate::hal::{cpu, io};
|
use crate::hal::{cpu, io};
|
||||||
use crate::kprintln;
|
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");
|
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!");
|
log_info!("ACPI initialized successfully!");
|
||||||
|
|
||||||
Some(AcpiInfo {
|
Some(AcpiInfo {
|
||||||
|
|||||||
@ -29,6 +29,16 @@ pub struct AcpiPowerInfo {
|
|||||||
pub slp_en: u16,
|
pub slp_en: u16,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// ACPI 重置寄存器信息
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub struct ResetRegister {
|
||||||
|
pub address_space: u8, // 0=SystemMemory, 1=SystemIO, 2=PciConfig
|
||||||
|
pub address: u64,
|
||||||
|
pub value: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
static mut ACPI_RESET_REG: Option<ResetRegister> = None;
|
||||||
|
|
||||||
static mut ACPI_POWER_INFO: Option<AcpiPowerInfo> = None;
|
static mut ACPI_POWER_INFO: Option<AcpiPowerInfo> = None;
|
||||||
|
|
||||||
impl CureAcpiHandler {
|
impl CureAcpiHandler {
|
||||||
|
|||||||
@ -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::hal::{cpu, io};
|
||||||
use crate::kprintln;
|
use crate::kprintln;
|
||||||
use crate::mm::vma;
|
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
|
// Map the DSDT header first to get the length
|
||||||
let dsdt_header_mapping = unsafe {
|
let dsdt_header_mapping = unsafe {
|
||||||
handler.map_physical_region::<SdtHeader>(
|
handler.map_physical_region::<SdtHeader>(dsdt_phys_addr as usize, size_of::<SdtHeader>())
|
||||||
dsdt_phys_addr as usize,
|
|
||||||
size_of::<SdtHeader>(),
|
|
||||||
)
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if dsdt_header_mapping.signature != Signature::DSDT {
|
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_ptr = dsdt_mapping.virtual_start.as_ptr();
|
||||||
let dsdt_data = core::slice::from_raw_parts(dsdt_ptr, dsdt_length);
|
let dsdt_data = core::slice::from_raw_parts(dsdt_ptr, dsdt_length);
|
||||||
|
|
||||||
// 在 DSDT 中搜索 "_S5_"
|
// Search DSDT for "_S5_"
|
||||||
let s5_name = b"_S5_";
|
let s5_name = b"_S5_";
|
||||||
|
|
||||||
for i in 0..(dsdt_data.len() - 4) {
|
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_"
|
let mut offset = i + 4; // Skip "_S5_"
|
||||||
|
|
||||||
// Skip any intermediate bytes and go straight to PackageOp
|
// 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() {
|
while offset < search_limit && offset < dsdt_data.len() {
|
||||||
if dsdt_data[offset] == 0x12 {
|
if dsdt_data[offset] == 0x12 {
|
||||||
log_debug!("Found PackageOp at offset {:#x}", offset);
|
log_debug!("Found PackageOp at offset {:#x}", offset);
|
||||||
@ -248,15 +245,16 @@ fn get_pkg_length_size(data: &[u8]) -> usize {
|
|||||||
1 + byte_count
|
1 + byte_count
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 解析 AML 整數
|
/// Parse AML integer
|
||||||
fn parse_aml_integer(data: &[u8]) -> Option<u64> {
|
fn parse_aml_integer(data: &[u8]) -> Option<u64> {
|
||||||
if data.is_empty() {
|
if data.is_empty() {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
match data[0] {
|
match data[0] {
|
||||||
0x00 => Some(0), // ZeroOp
|
0x00 => Some(0), // ZeroOp
|
||||||
0x01 => Some(1), // OneOp
|
0x01 => Some(1), // OneOp
|
||||||
|
0xFF => Some(0xFFFFFFFF), // OnesOp
|
||||||
0x0A => {
|
0x0A => {
|
||||||
// BytePrefix
|
// BytePrefix
|
||||||
if data.len() < 2 {
|
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],
|
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] {
|
match data[0] {
|
||||||
0x00 | 0x01 => 1,
|
0x00 | 0x01 | 0xFF => 1, // Zero, One, Ones
|
||||||
0x0A => 2,
|
0x0A => 2, // Byte
|
||||||
0x0B => 3,
|
0x0B => 3, // Word
|
||||||
0x0C => 5,
|
0x0C => 5, // DWord
|
||||||
0x0E => 9,
|
0x0E => 9, // QWord
|
||||||
_ => 1,
|
_ => 1,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Perform ACPI shutdown
|
/// Perform ACPI shutdown
|
||||||
pub fn acpi_shutdown() -> ! {
|
pub fn acpi_shutdown() -> bool {
|
||||||
log_info!("Attempting ACPI shutdown...");
|
log_info!("Attempting ACPI shutdown...");
|
||||||
|
|
||||||
let power_info = unsafe {
|
let power_info = unsafe {
|
||||||
@ -316,7 +317,7 @@ pub fn acpi_shutdown() -> ! {
|
|||||||
Some(info) => info,
|
Some(info) => info,
|
||||||
None => {
|
None => {
|
||||||
log_error!("ACPI power info not initialized!");
|
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);
|
io::io_port_ww(power_info.pm1b_control_block as u16, slp_cmd_b);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 等待關機
|
cpu::cpu_pause(10000);
|
||||||
for _ in 0..1000000 {
|
|
||||||
cpu::cpu_pause(100);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
log_error!("ACPI shutdown failed!");
|
log_error!("ACPI shutdown failed!");
|
||||||
fallback_shutdown()
|
false
|
||||||
}
|
|
||||||
|
|
||||||
/// 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
|
/// Store ACPI shutdown information
|
||||||
@ -387,3 +359,181 @@ pub fn store_power_info(info: AcpiPowerInfo) {
|
|||||||
}
|
}
|
||||||
log_info!("ACPI power info stored successfully");
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -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 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)
|
/// Initialize a single IO APIC (using mapped virtual addresses)
|
||||||
///
|
///
|
||||||
@ -305,4 +207,4 @@ pub fn print_info() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1,68 +1,11 @@
|
|||||||
// kernel/src/hal/lapic.rs
|
// kernel/src/hal/lapic.rs
|
||||||
|
|
||||||
use x86_64::VirtAddr;
|
use super::{flags, ApicInfo, ApicRegister, APIC_INFO, LOCAL_APIC_BASE};
|
||||||
use crate::{log_trace, log_debug, log_info, log_warn, log_error};
|
|
||||||
use crate::hal::io;
|
use crate::hal::io;
|
||||||
use crate::mm::vma;
|
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
|
/// Read APIC registers
|
||||||
///
|
///
|
||||||
/// # Safety
|
/// # 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) {
|
pub unsafe fn init_local_apic_with_vaddr(base_vaddr: VirtAddr) {
|
||||||
log_debug!("Initializing Local APIC at {:#x}", base_vaddr.as_u64());
|
log_debug!("Initializing Local APIC at {:#x}", base_vaddr.as_u64());
|
||||||
|
|
||||||
// 儲存基地址
|
// Storage base address
|
||||||
LOCAL_APIC_BASE = Some(base_vaddr);
|
LOCAL_APIC_BASE = Some(base_vaddr);
|
||||||
|
|
||||||
// 讀取 APIC 信息
|
// Read APIC information
|
||||||
let id_reg = read_apic_reg(ApicRegister::Id).unwrap();
|
let id_reg = read_apic_reg(ApicRegister::Id).unwrap();
|
||||||
let version_reg = read_apic_reg(ApicRegister::Version).unwrap();
|
let version_reg = read_apic_reg(ApicRegister::Version).unwrap();
|
||||||
|
|
||||||
@ -181,9 +124,7 @@ pub fn send_eoi() {
|
|||||||
/// Get the Local APIC ID
|
/// Get the Local APIC ID
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn get_apic_id() -> Option<u32> {
|
pub fn get_apic_id() -> Option<u32> {
|
||||||
unsafe {
|
unsafe { Some(APIC_INFO.id) }
|
||||||
Some(APIC_INFO.id)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the Local APIC base virtual address
|
/// 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
|
/// Must be called before using the APIC to avoid conflicts
|
||||||
pub fn disable_legacy_pic() {
|
pub fn disable_legacy_pic() {
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
// Master PIC
|
// Master PIC
|
||||||
io::io_port_wb(0x20, 0x11); // ICW1: initialization
|
io::io_port_wb(0x20, 0x11); // ICW1: initialization
|
||||||
@ -253,4 +193,4 @@ pub fn print_info() {
|
|||||||
log_warn!("Local APIC not initialized");
|
log_warn!("Local APIC not initialized");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
163
kernel/src/hal/apic/mod.rs
Normal file
163
kernel/src/hal/apic/mod.rs
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -2,7 +2,6 @@ pub mod io;
|
|||||||
pub mod cpu;
|
pub mod cpu;
|
||||||
pub mod acpi;
|
pub mod acpi;
|
||||||
pub mod rtc;
|
pub mod rtc;
|
||||||
pub mod lapic;
|
|
||||||
pub mod ioapic;
|
|
||||||
pub mod timer;
|
pub mod timer;
|
||||||
pub mod power;
|
pub mod power;
|
||||||
|
pub mod apic;
|
||||||
@ -71,18 +71,18 @@ fn try_shutdown(method: ShutdownMethod) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ShutdownMethod::QemuExit => {
|
ShutdownMethod::QemuExit => {
|
||||||
// QEMU isa-debug-exit 設備
|
// QEMU isa-debug-exit device
|
||||||
io::io_port_ww(0x604, 0x2000);
|
io::io_port_ww(0x604, 0x2000);
|
||||||
io::io_port_rl(0x501);
|
io::io_port_rl(0x501);
|
||||||
}
|
}
|
||||||
|
|
||||||
ShutdownMethod::BochsExit => {
|
ShutdownMethod::BochsExit => {
|
||||||
// Bochs 專用關機端口
|
// Bochs dedicated shutdown port
|
||||||
io::io_port_ww(0xB004, 0x2000);
|
io::io_port_ww(0xB004, 0x2000);
|
||||||
}
|
}
|
||||||
|
|
||||||
ShutdownMethod::VirtualBox => {
|
ShutdownMethod::VirtualBox => {
|
||||||
// VirtualBox 關機端口
|
// VirtualBox shutdown port
|
||||||
io::io_port_ww(0x4004, 0x3400);
|
io::io_port_ww(0x4004, 0x3400);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -100,7 +100,7 @@ fn try_shutdown(method: ShutdownMethod) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 重啟系統
|
/// Restart the system
|
||||||
pub fn reboot() -> ! {
|
pub fn reboot() -> ! {
|
||||||
log_info!("Rebooting system...");
|
log_info!("Rebooting system...");
|
||||||
|
|
||||||
@ -119,10 +119,10 @@ pub fn reboot() -> ! {
|
|||||||
];
|
];
|
||||||
|
|
||||||
for method in methods.iter() {
|
for method in methods.iter() {
|
||||||
log_debug!("Trying shutdown method: {:?}", method);
|
log_debug!("Trying reboot method: {:?}", method);
|
||||||
try_reboot(*method);
|
try_reboot(*method);
|
||||||
|
|
||||||
log_warn!("{:?} shutdown failed", method);
|
log_warn!("{:?} reboot failed", method);
|
||||||
cpu::cpu_pause(1000);
|
cpu::cpu_pause(1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -137,42 +137,30 @@ pub fn reboot() -> ! {
|
|||||||
fn try_reboot(method: RebootMethod) {
|
fn try_reboot(method: RebootMethod) {
|
||||||
match method {
|
match method {
|
||||||
RebootMethod::BootACPI => {
|
RebootMethod::BootACPI => {
|
||||||
acpi_reboot()
|
acpi::power::acpi_reset_reg_reboot();
|
||||||
}
|
}
|
||||||
|
|
||||||
RebootMethod::BootKBD => {
|
RebootMethod::BootKBD => {
|
||||||
keyboard_controller_reboot()
|
keyboard_controller_reboot();
|
||||||
}
|
}
|
||||||
|
|
||||||
RebootMethod::BootCF9 => {
|
RebootMethod::BootCF9 => {
|
||||||
pci_reboot()
|
pci_reboot();
|
||||||
}
|
}
|
||||||
RebootMethod::BootEFI => {
|
RebootMethod::BootEFI => {
|
||||||
efi_reboot()
|
efi_reboot();
|
||||||
}
|
}
|
||||||
|
|
||||||
RebootMethod::Boot92h => {
|
RebootMethod::Boot92h => {
|
||||||
cpu_reset()
|
cpu_reset();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cpu::cpu_pause(10000);
|
cpu::cpu_pause(10000);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn acpi_reboot() {
|
fn keyboard_controller_reboot() -> bool {
|
||||||
log_debug!("Trying ACPI reboot...");
|
log_debug!("keyboard controller 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 {
|
unsafe {
|
||||||
for _ in 0..1000 {
|
for _ in 0..1000 {
|
||||||
@ -186,10 +174,12 @@ fn keyboard_controller_reboot() {
|
|||||||
|
|
||||||
cpu::cpu_pause(100000);
|
cpu::cpu_pause(100000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pci_reboot() {
|
fn pci_reboot() -> bool {
|
||||||
log_debug!("Trying PCI reboot...");
|
log_debug!("PCI reboot...");
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
let mut val = io::io_port_rb(0xCF9) & !0x06;
|
let mut val = io::io_port_rb(0xCF9) & !0x06;
|
||||||
@ -199,24 +189,29 @@ fn pci_reboot() {
|
|||||||
|
|
||||||
cpu::cpu_pause(100000);
|
cpu::cpu_pause(100000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fn efi_reboot() {
|
fn efi_reboot() -> bool {
|
||||||
log_debug!("Trying EFI runtime services reboot...");
|
log_debug!("Trying EFI runtime services reboot...");
|
||||||
|
|
||||||
// TODO: 實現 EFI ResetSystem 調用
|
// TODO: 實現 EFI ResetSystem 調用
|
||||||
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cpu_reset() {
|
fn cpu_reset() -> bool {
|
||||||
log_debug!("Trying CPU reset via port 92h...");
|
log_debug!("CPU reset via port 92h...");
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
let mut val = io::io_port_rb(0x92);
|
let mut val = io::io_port_rb(0x92);
|
||||||
val &= !0x01; // 清除快速 A20 位
|
val &= !0x01; // Clear Fast A20 Bit
|
||||||
val |= 0x01; // 設置重置位
|
val |= 0x01; // Set the reset bit
|
||||||
io::io_port_wb(0x92, val);
|
io::io_port_wb(0x92, val);
|
||||||
|
|
||||||
cpu::cpu_pause(100000);
|
cpu::cpu_pause(100000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
false
|
||||||
}
|
}
|
||||||
@ -1,8 +1,9 @@
|
|||||||
// kernel/src/hal/timer
|
// kernel/src/hal/timer
|
||||||
|
|
||||||
use crate::hal::{lapic, rtc, cpu, ioapic};
|
use crate::hal::{cpu, rtc};
|
||||||
use core::sync::atomic::{AtomicU64, AtomicBool, Ordering};
|
use core::sync::atomic::{AtomicBool, AtomicU64, Ordering};
|
||||||
use crate::{log_info, log_debug, log_warn, log_error};
|
use crate::{log_debug, log_error, log_info, log_warn};
|
||||||
|
use crate::hal::apic::{ioapic, lapic};
|
||||||
|
|
||||||
const APIC_CALIBRATION_CONST: u32 = 0x100000;
|
const APIC_CALIBRATION_CONST: u32 = 0x100000;
|
||||||
const RTC_BASE_FREQUENCY: u32 = 1024;
|
const RTC_BASE_FREQUENCY: u32 = 1024;
|
||||||
|
|||||||
@ -3,7 +3,7 @@ use bootloader_api::BootInfo;
|
|||||||
use bootloader_api::info::MemoryRegionKind;
|
use bootloader_api::info::MemoryRegionKind;
|
||||||
use x86_64::structures::paging::OffsetPageTable;
|
use x86_64::structures::paging::OffsetPageTable;
|
||||||
use x86_64::{PhysAddr, VirtAddr};
|
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::arch::amd64::{gdt, idt};
|
||||||
use crate::tty::tty;
|
use crate::tty::tty;
|
||||||
use crate::kprintln;
|
use crate::kprintln;
|
||||||
@ -12,7 +12,8 @@ use crate::klibc::logger::{init, LogLevel, LoggerConfig};
|
|||||||
use crate::klibc::malloc;
|
use crate::klibc::malloc;
|
||||||
use crate::{log_debug, log_error, log_info, log_trace, log_warn};
|
use crate::{log_debug, log_error, log_info, log_trace, log_warn};
|
||||||
use crate::drivers::keyboard;
|
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;
|
use crate::hal::cpu::cpu_enable_interrupts;
|
||||||
|
|
||||||
fn _logger_init() {
|
fn _logger_init() {
|
||||||
@ -294,5 +295,5 @@ pub fn _kernel_init(boot_info: &'static mut BootInfo) -> ! {
|
|||||||
pub fn kernel_emergency_cleanup() {
|
pub fn kernel_emergency_cleanup() {
|
||||||
log_error!("Emergency cleanup triggered");
|
log_error!("Emergency cleanup triggered");
|
||||||
// 在 panic 前調用,做最後的清理工作
|
// 在 panic 前調用,做最後的清理工作
|
||||||
// 比如刷新緩衝區、保存日誌等
|
// 刷新緩衝區、保存日誌等
|
||||||
}
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user