feat: ACPI implementation completed
This commit is contained in:
parent
1c92cacbc3
commit
429e396474
59
Cargo.lock
generated
59
Cargo.lock
generated
@ -2,6 +2,20 @@
|
||||
# It is not intended for manual editing.
|
||||
version = 4
|
||||
|
||||
[[package]]
|
||||
name = "acpi"
|
||||
version = "6.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4c85d96f36022f650ee6f184f1353d077124754cecf6a3e91085a708495c6f5a"
|
||||
dependencies = [
|
||||
"bit_field",
|
||||
"bitflags 2.9.4",
|
||||
"byteorder",
|
||||
"log",
|
||||
"pci_types",
|
||||
"spinning_top 0.3.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.100"
|
||||
@ -123,8 +137,10 @@ dependencies = [
|
||||
name = "cure-kernel"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"acpi",
|
||||
"bootloader_api",
|
||||
"lazy_static",
|
||||
"linked_list_allocator",
|
||||
"raw-cpuid",
|
||||
"spin 0.10.0",
|
||||
"x86_64",
|
||||
@ -218,6 +234,15 @@ version = "0.2.177"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976"
|
||||
|
||||
[[package]]
|
||||
name = "linked_list_allocator"
|
||||
version = "0.10.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9afa463f5405ee81cdb9cc2baf37e08ec7e4c8209442b5d72c04cfb2cd6e6286"
|
||||
dependencies = [
|
||||
"spinning_top 0.2.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "linux-raw-sys"
|
||||
version = "0.11.0"
|
||||
@ -270,6 +295,16 @@ version = "1.21.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
|
||||
|
||||
[[package]]
|
||||
name = "pci_types"
|
||||
version = "0.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c4325c6aa3cca3373503b1527e75756f9fbfe5fd76be4b4c8a143ee47430b8e0"
|
||||
dependencies = [
|
||||
"bit_field",
|
||||
"bitflags 2.9.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.101"
|
||||
@ -302,11 +337,11 @@ checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09"
|
||||
|
||||
[[package]]
|
||||
name = "raw-cpuid"
|
||||
version = "10.7.0"
|
||||
version = "11.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6c297679cb867470fa8c9f67dbba74a78d78e3e98d7cf2b08d6d71540f797332"
|
||||
checksum = "498cd0dc59d73224351ee52a95fee0f1a617a2eae0e7d9d720cc622c73a54186"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
"bitflags 2.9.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -407,6 +442,24 @@ dependencies = [
|
||||
"lock_api",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "spinning_top"
|
||||
version = "0.2.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5b9eb1a2f4c41445a3a0ff9abc5221c5fcd28e1f13cd7c0397706f9ac938ddb0"
|
||||
dependencies = [
|
||||
"lock_api",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "spinning_top"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d96d2d1d716fb500937168cc09353ffdc7a012be8475ac7308e1bdf0e3923300"
|
||||
dependencies = [
|
||||
"lock_api",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.106"
|
||||
|
||||
22
TODO.txt
Normal file
22
TODO.txt
Normal file
@ -0,0 +1,22 @@
|
||||
// 1. 中斷處理
|
||||
// - IDT (中斷描述符表) - OK
|
||||
// - 中斷處理函數 - OK
|
||||
// - ACPI 初始化 - OK
|
||||
// - PIC/APIC 初始化
|
||||
|
||||
// - 滾動
|
||||
|
||||
// 2. 內存管理
|
||||
// - 物理內存分配器
|
||||
// - 虛擬內存分配器
|
||||
// - 堆分配器
|
||||
|
||||
// 3. 頁表管理
|
||||
// - 修改頁表
|
||||
// - 映射新的內存區域
|
||||
// - 取消映射
|
||||
|
||||
// 4. 進程管理
|
||||
// - 任務切換
|
||||
// - 調度器
|
||||
// - 用戶態/內核態切換
|
||||
@ -8,8 +8,10 @@ bootloader_api = "0.11.12"
|
||||
lazy_static = { version = "1.5.0", features = ["spin_no_std"] }
|
||||
x86_64 = { version = "0.15.2", features = ["instructions"] }
|
||||
spin = "0.10.0"
|
||||
raw-cpuid = "10.7.0"
|
||||
raw-cpuid = "11.6.0"
|
||||
acpi = "6.0.1"
|
||||
linked_list_allocator = "0.10.5"
|
||||
|
||||
[package.metadata.bootloader]
|
||||
map-physical-memory = true
|
||||
physical-memory-offset = "0xFFFF800000000000"
|
||||
#[package.metadata.bootloader]
|
||||
#map-physical-memory = true
|
||||
#physical-memory-offset = "0xFFFF800000000000"
|
||||
@ -48,8 +48,6 @@ pub struct SgReg {
|
||||
pub cs: Reg16,
|
||||
}
|
||||
|
||||
// ============ 控制寄存器 ============
|
||||
|
||||
/// 讀取 CR0 暫存器
|
||||
#[allow(dead_code)]
|
||||
#[inline]
|
||||
@ -181,8 +179,6 @@ pub fn cpu_get_brand(brand_out: &mut [u8]) -> &str {
|
||||
}
|
||||
}
|
||||
|
||||
// ============ CPU 指令 ============
|
||||
|
||||
/// 讀取 CPU 時間戳計數器 (TSC)
|
||||
///
|
||||
/// # 返回
|
||||
|
||||
79
kernel/src/k_init.rs
Normal file
79
kernel/src/k_init.rs
Normal file
@ -0,0 +1,79 @@
|
||||
use bootloader_api::BootInfo;
|
||||
use x86_64::structures::paging::OffsetPageTable;
|
||||
use x86_64::VirtAddr;
|
||||
use crate::kernel::asm::x86::{gdt, idt, acpi};
|
||||
use crate::kernel::mm::{heap, frame_allocator};
|
||||
use crate::kernel::tty::tty;
|
||||
use crate::kprintln;
|
||||
use crate::k_main;
|
||||
use crate::hal::cpu;
|
||||
|
||||
pub fn kernel_init(boot_info: &'static mut BootInfo) -> ! {
|
||||
if let Some(framebuffer) = boot_info.framebuffer.as_mut() {
|
||||
tty::init(framebuffer);
|
||||
tty::clear(0x000000);
|
||||
|
||||
kprintln!("CureOS Booting...");
|
||||
kprintln!("Framebuffer initialized");
|
||||
|
||||
kprintln!();
|
||||
kprintln!("Initializing GDT...");
|
||||
gdt::init();
|
||||
kprintln!("GDT initialized");
|
||||
gdt::print_info();
|
||||
|
||||
kprintln!();
|
||||
kprintln!("Initializing IDT...");
|
||||
idt::init();
|
||||
kprintln!("IDT initialized");
|
||||
idt::print_info();
|
||||
|
||||
kprintln!();
|
||||
tty::clear(0x000000);
|
||||
let physical_memory_offset = if let Some(offset) = boot_info.physical_memory_offset.into_option() {
|
||||
kprintln!("Physical Memory Offset: {:#x}", offset);
|
||||
offset
|
||||
} else {
|
||||
panic!("Physical memory offset not provided by bootloader");
|
||||
};
|
||||
|
||||
let phys_mem_offset = VirtAddr::new(physical_memory_offset);
|
||||
let mut mapper = unsafe {
|
||||
OffsetPageTable::new(heap::get_level_4_table(phys_mem_offset), phys_mem_offset)
|
||||
};
|
||||
|
||||
let mut frame_allocator = unsafe {
|
||||
frame_allocator::BootInfoFrameAllocator::init(&boot_info.memory_regions)
|
||||
};
|
||||
|
||||
kprintln!("Initializing heap allocator...");
|
||||
heap::init_heap(&mut mapper, &mut frame_allocator)
|
||||
.expect("heap initialization failed");
|
||||
|
||||
kprintln!("Heap allocator initialized");
|
||||
kprintln!("Heap Start: {:#x}", heap::HEAP_START);
|
||||
kprintln!("Heap Size: {} KiB", heap::HEAP_SIZE / 1024);
|
||||
|
||||
kprintln!();
|
||||
if let Some(rsdp) = boot_info.rsdp_addr.into_option() {
|
||||
kprintln!("RSDP Address: {:#x}", rsdp);
|
||||
kprintln!("Initializing ACPI...");
|
||||
|
||||
if let Some(acpi_info) = acpi::init(*&rsdp, physical_memory_offset) {
|
||||
acpi::print_info(&acpi_info);
|
||||
} else {
|
||||
kprintln!("Warning: ACPI initialization failed");
|
||||
}
|
||||
} else {
|
||||
kprintln!("Warning: RSDP not provided");
|
||||
}
|
||||
|
||||
|
||||
k_main::kernel_main();
|
||||
|
||||
} else {
|
||||
loop {
|
||||
cpu::cpu_halt();
|
||||
}
|
||||
}
|
||||
}
|
||||
27
kernel/src/k_main.rs
Normal file
27
kernel/src/k_main.rs
Normal file
@ -0,0 +1,27 @@
|
||||
use crate::hal::cpu;
|
||||
use crate::kprintln;
|
||||
|
||||
pub fn kernel_main() -> ! {
|
||||
kprintln!("Welcome to CureOS!");
|
||||
|
||||
let mut brand_buf = [0u8; 64];
|
||||
let mut model_buf = [0u8; 16];
|
||||
kprintln!("CPU: {} ({})",
|
||||
cpu::cpu_get_brand(&mut brand_buf),
|
||||
cpu::cpu_get_model(&mut model_buf)
|
||||
);
|
||||
|
||||
kprintln!();
|
||||
kprintln!("Control Registers:");
|
||||
kprintln!(" CR0: 0x{:016x}", cpu::cpu_r_cr0().bits());
|
||||
kprintln!(" CR2: 0x{:016x}", cpu::cpu_r_cr2());
|
||||
kprintln!(" CR3: 0x{:016x}", cpu::cpu_r_cr3());
|
||||
kprintln!(" CR4: 0x{:016x}", cpu::cpu_r_cr4().bits());
|
||||
|
||||
kprintln!();
|
||||
kprintln!("Kernel initialized successfully!");
|
||||
|
||||
loop {
|
||||
cpu::cpu_halt();
|
||||
}
|
||||
}
|
||||
318
kernel/src/kernel/asm/x86/acpi.rs
Normal file
318
kernel/src/kernel/asm/x86/acpi.rs
Normal file
@ -0,0 +1,318 @@
|
||||
use acpi::{aml, AcpiTables, Handle, Handler, PciAddress, PhysicalMapping};
|
||||
use acpi::platform::{AcpiPlatform, interrupt::InterruptModel, PciConfigRegions};
|
||||
use acpi::sdt::hpet::HpetInfo;
|
||||
use acpi::rsdp::Rsdp;
|
||||
use core::ptr::NonNull;
|
||||
use core::mem;
|
||||
use crate::kprintln;
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct CureAcpiHandler {
|
||||
physical_memory_offset: u64,
|
||||
}
|
||||
|
||||
impl CureAcpiHandler {
|
||||
pub const fn new(physical_memory_offset: u64) -> Self {
|
||||
Self {
|
||||
physical_memory_offset,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Handler for CureAcpiHandler {
|
||||
unsafe fn map_physical_region<T>(
|
||||
&self,
|
||||
physical_address: usize,
|
||||
size: usize,
|
||||
) -> PhysicalMapping<Self, T> {
|
||||
// Bootloader 已經映射了所有物理記憶體
|
||||
let virtual_address = physical_address as u64 + self.physical_memory_offset;
|
||||
let virtual_start = NonNull::new((virtual_address) as *mut T).unwrap();
|
||||
|
||||
PhysicalMapping {
|
||||
physical_start: physical_address,
|
||||
virtual_start,
|
||||
region_length: size,
|
||||
mapped_length: size,
|
||||
handler: *self,
|
||||
}
|
||||
}
|
||||
|
||||
fn unmap_physical_region<T>(region: &PhysicalMapping<Self, T>) {
|
||||
//
|
||||
}
|
||||
|
||||
fn read_u8(&self, address: usize) -> u8 {
|
||||
unsafe {
|
||||
let ptr = self.map_physical_region::<u8>(address, 1);
|
||||
core::ptr::read_volatile(ptr.virtual_start.as_ptr())
|
||||
}
|
||||
}
|
||||
|
||||
fn read_u16(&self, address: usize) -> u16 {
|
||||
unsafe {
|
||||
let ptr = self.map_physical_region::<u16>(address, 2);
|
||||
core::ptr::read_volatile(ptr.virtual_start.as_ptr())
|
||||
}
|
||||
}
|
||||
|
||||
fn read_u32(&self, address: usize) -> u32 {
|
||||
unsafe {
|
||||
let ptr = self.map_physical_region::<u32>(address, 4);
|
||||
core::ptr::read_volatile(ptr.virtual_start.as_ptr())
|
||||
}
|
||||
}
|
||||
|
||||
fn read_u64(&self, address: usize) -> u64 {
|
||||
unsafe {
|
||||
let ptr = self.map_physical_region::<u64>(address, 8);
|
||||
core::ptr::read_volatile(ptr.virtual_start.as_ptr())
|
||||
}
|
||||
}
|
||||
|
||||
fn write_u8(&self, address: usize, value: u8) {
|
||||
unsafe {
|
||||
let ptr = self.map_physical_region::<u8>(address, 1);
|
||||
core::ptr::write_volatile(ptr.virtual_start.as_ptr(), value);
|
||||
}
|
||||
}
|
||||
|
||||
fn write_u16(&self, address: usize, value: u16) {
|
||||
unsafe {
|
||||
let ptr = self.map_physical_region::<u16>(address, 2);
|
||||
core::ptr::write_volatile(ptr.virtual_start.as_ptr(), value);
|
||||
}
|
||||
}
|
||||
|
||||
fn write_u32(&self, address: usize, value: u32) {
|
||||
unsafe {
|
||||
let ptr = self.map_physical_region::<u32>(address, 4);
|
||||
core::ptr::write_volatile(ptr.virtual_start.as_ptr(), value);
|
||||
}
|
||||
}
|
||||
|
||||
fn write_u64(&self, address: usize, value: u64) {
|
||||
unsafe {
|
||||
let ptr = self.map_physical_region::<u64>(address, 8);
|
||||
core::ptr::write_volatile(ptr.virtual_start.as_ptr(), value);
|
||||
}
|
||||
}
|
||||
|
||||
fn read_io_u8(&self, port: u16) -> u8 {
|
||||
unsafe { crate::hal::io::io_port_rb(port) }
|
||||
}
|
||||
|
||||
fn read_io_u16(&self, port: u16) -> u16 {
|
||||
unsafe { crate::hal::io::io_port_rw(port) }
|
||||
}
|
||||
|
||||
fn read_io_u32(&self, port: u16) -> u32 {
|
||||
unsafe { crate::hal::io::io_port_rl(port) }
|
||||
}
|
||||
|
||||
fn write_io_u8(&self, port: u16, value: u8) {
|
||||
unsafe { crate::hal::io::io_port_wb(port, value) };
|
||||
}
|
||||
|
||||
fn write_io_u16(&self, port: u16, value: u16) {
|
||||
unsafe { crate::hal::io::io_port_ww(port, value) };
|
||||
}
|
||||
|
||||
fn write_io_u32(&self, port: u16, value: u32) {
|
||||
unsafe { crate::hal::io::io_port_wl(port, value) };
|
||||
}
|
||||
|
||||
fn read_pci_u8(&self, address: PciAddress, offset: u16) -> u8 {
|
||||
// TODO: 實作 PCI 配置空間讀取
|
||||
0xFF
|
||||
}
|
||||
|
||||
fn read_pci_u16(&self, address: PciAddress, offset: u16) -> u16 {
|
||||
// TODO: 實作 PCI 配置空間讀取
|
||||
0xFFFF
|
||||
}
|
||||
|
||||
fn read_pci_u32(&self, address: PciAddress, offset: u16) -> u32 {
|
||||
// TODO: 實作 PCI 配置空間讀取
|
||||
0xFFFFFFFF
|
||||
}
|
||||
|
||||
fn write_pci_u8(&self, address: PciAddress, offset: u16, value: u8) {
|
||||
// TODO: 實作 PCI 配置空間寫入
|
||||
}
|
||||
|
||||
fn write_pci_u16(&self, address: PciAddress, offset: u16, value: u16) {
|
||||
// TODO: 實作 PCI 配置空間寫入
|
||||
}
|
||||
|
||||
fn write_pci_u32(&self, address: PciAddress, offset: u16, value: u32) {
|
||||
// TODO: 實作 PCI 配置空間寫入
|
||||
}
|
||||
|
||||
fn nanos_since_boot(&self) -> u64 {
|
||||
// TODO: 實作高精度計時器 (需要 HPET 或 TSC)
|
||||
// 目前返回 0
|
||||
0
|
||||
}
|
||||
|
||||
fn stall(&self, _microseconds: u64) {
|
||||
// TODO: 實作微秒級延遲
|
||||
// 簡單的忙等待實作
|
||||
for _ in 0..(_microseconds * 1000) {
|
||||
crate::hal::cpu::cpu_pause();
|
||||
}
|
||||
}
|
||||
|
||||
fn sleep(&self, _milliseconds: u64) {
|
||||
// TODO: 實作毫秒級睡眠
|
||||
// 簡單的忙等待實作
|
||||
self.stall(_milliseconds * 1000);
|
||||
}
|
||||
|
||||
fn create_mutex(&self) -> acpi::Handle {
|
||||
// TODO: 實作 Mutex
|
||||
// 目前返回一個假的 handle
|
||||
acpi::Handle(0)
|
||||
}
|
||||
|
||||
fn acquire(&self, mutex: Handle, timeout: u16) -> Result<(), aml::AmlError> {
|
||||
// TODO: 實作 Mutex 獲取
|
||||
// 暫時直接返回成功
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn release(&self, _handle: acpi::Handle) {
|
||||
// TODO: 實作 Mutex 釋放
|
||||
}
|
||||
}
|
||||
|
||||
pub struct AcpiInfo {
|
||||
pub revision: u8,
|
||||
pub boot_processor: Option<u32>,
|
||||
pub cpu_count: usize,
|
||||
pub has_apic: bool,
|
||||
pub has_hpet: bool,
|
||||
}
|
||||
|
||||
pub fn init(rsdp_addr: u64, physical_memory_offset: u64) -> Option<AcpiInfo> {
|
||||
|
||||
let handler = CureAcpiHandler::new(physical_memory_offset);
|
||||
|
||||
let rsdp_mapping = unsafe {
|
||||
handler.map_physical_region::<Rsdp>(rsdp_addr as usize, mem::size_of::<Rsdp>())
|
||||
};
|
||||
let revision = rsdp_mapping.revision();
|
||||
kprintln!(" ACPI Revision: {}", revision);
|
||||
|
||||
let tables = unsafe {
|
||||
match AcpiTables::from_rsdp(handler, rsdp_addr as usize) {
|
||||
Ok(tables) => tables,
|
||||
Err(e) => {
|
||||
kprintln!(" Failed to parse ACPI tables: {:?}", e);
|
||||
return None;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let platform = match AcpiPlatform::new(tables, handler) {
|
||||
Ok(platform) => platform,
|
||||
Err(e) => {
|
||||
kprintln!(" Failed to create ACPI platform: {:?}", e);
|
||||
return None;
|
||||
}
|
||||
};
|
||||
|
||||
kprintln!(" Platform Info:");
|
||||
kprintln!(" 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;
|
||||
|
||||
kprintln!(" Boot Processor UID: {:?}", boot_proc);
|
||||
kprintln!(" Total CPU Count: {}", cpu_cnt);
|
||||
|
||||
(boot_proc, cpu_cnt)
|
||||
} else {
|
||||
kprintln!(" No processor info found");
|
||||
(None, 0)
|
||||
};
|
||||
|
||||
// 檢查中斷模型
|
||||
let has_apic = match &platform.interrupt_model {
|
||||
InterruptModel::Apic(apic) => {
|
||||
kprintln!(" Interrupt Model: APIC");
|
||||
kprintln!(" Local APIC Address: {:#x}", apic.local_apic_address);
|
||||
kprintln!(" IO APICs: {} controller(s)", apic.io_apics.len());
|
||||
|
||||
for (i, io_apic) in apic.io_apics.iter().enumerate() {
|
||||
kprintln!(" IO APIC {}: ID={}, Address={:#x}, GSI Base={}",
|
||||
i, io_apic.id, io_apic.address, io_apic.global_system_interrupt_base);
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
InterruptModel::Unknown => {
|
||||
kprintln!(" Interrupt Model: Unknown (not APIC)");
|
||||
false
|
||||
}
|
||||
_ => {
|
||||
kprintln!(" Interrupt Model: Other");
|
||||
false
|
||||
}
|
||||
};
|
||||
|
||||
// 檢查 HPET (High Precision Event Timer)
|
||||
let has_hpet = match HpetInfo::new(&platform.tables) {
|
||||
Ok(hpet) => {
|
||||
kprintln!(" HPET (High Precision Event Timer):");
|
||||
kprintln!(" Base Address: {:#x}", hpet.base_address);
|
||||
kprintln!(" Hardware Rev: {}", hpet.hardware_rev);
|
||||
kprintln!(" Comparator Count: {}", hpet.num_comparators);
|
||||
kprintln!(" Counter Size: {} bit", if hpet.main_counter_is_64bits { 64 } else { 32 });
|
||||
kprintln!(" Legacy IRQ Capable: {}", hpet.legacy_irq_capable);
|
||||
kprintln!(" PCI Vendor ID: {:#x}", hpet.pci_vendor_id);
|
||||
true
|
||||
}
|
||||
Err(_) => {
|
||||
kprintln!(" HPET: Not available");
|
||||
false
|
||||
}
|
||||
};
|
||||
|
||||
if let Ok(mcfg) = PciConfigRegions::new(&platform.tables) {
|
||||
kprintln!(" PCI Express Configuration:");
|
||||
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;
|
||||
|
||||
kprintln!(" Entry {}: Segment Group {}", i, segment_group);
|
||||
kprintln!(" Base Address: {:#x}", base_addr);
|
||||
kprintln!(" Bus Range: {}-{}", bus_start, bus_end);
|
||||
}
|
||||
}
|
||||
|
||||
kprintln!(" ACPI initialized successfully!");
|
||||
|
||||
Some(AcpiInfo {
|
||||
revision,
|
||||
boot_processor,
|
||||
cpu_count,
|
||||
has_apic,
|
||||
has_hpet,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn print_info(info: &AcpiInfo) {
|
||||
kprintln!();
|
||||
kprintln!("ACPI Summary:");
|
||||
kprintln!(" Revision: ACPI {}.0", info.revision);
|
||||
kprintln!(" CPUs: {} processor(s)", info.cpu_count);
|
||||
if let Some(boot_proc) = info.boot_processor {
|
||||
kprintln!(" Boot Processor: UID {}", boot_proc);
|
||||
}
|
||||
kprintln!(" APIC: {}", if info.has_apic { "Available " } else { "Not available" });
|
||||
kprintln!(" HPET: {}", if info.has_hpet { "Available " } else { "Not available" });
|
||||
}
|
||||
@ -1,4 +1,5 @@
|
||||
pub mod gdt;
|
||||
pub mod idt;
|
||||
pub mod interrupt;
|
||||
pub(crate) mod acpi;
|
||||
// pub mod segment;
|
||||
49
kernel/src/kernel/mm/frame_allocator.rs
Normal file
49
kernel/src/kernel/mm/frame_allocator.rs
Normal file
@ -0,0 +1,49 @@
|
||||
|
||||
// kernel/src/mm/frame_allocator.rs
|
||||
use bootloader_api::info::{MemoryRegion, MemoryRegionKind, MemoryRegions};
|
||||
use x86_64::{
|
||||
structures::paging::{FrameAllocator, PhysFrame, Size4KiB},
|
||||
PhysAddr,
|
||||
};
|
||||
|
||||
pub struct BootInfoFrameAllocator {
|
||||
memory_regions: &'static MemoryRegions,
|
||||
next: usize,
|
||||
}
|
||||
|
||||
impl BootInfoFrameAllocator {
|
||||
/// Create a FrameAllocator from the memory map provided by the bootloader.
|
||||
///
|
||||
/// # Safety
|
||||
/// The caller must ensure that the memory map passed in is valid.
|
||||
/// In particular, all frames marked `USABLE` must actually be unused.
|
||||
pub unsafe fn init(memory_regions: &'static MemoryRegions) -> Self {
|
||||
BootInfoFrameAllocator {
|
||||
memory_regions,
|
||||
next: 0,
|
||||
}
|
||||
}
|
||||
|
||||
fn usable_frames(&self) -> impl Iterator<Item = PhysFrame> {
|
||||
// Get the available memory area
|
||||
let regions = self.memory_regions.iter();
|
||||
let usable_regions = regions.filter(|r| r.kind == MemoryRegionKind::Usable);
|
||||
|
||||
// Map each region to its address range
|
||||
let addr_ranges = usable_regions.map(|r| r.start..r.end);
|
||||
|
||||
// Convert to an iterator of the frame start address
|
||||
let frame_addresses = addr_ranges.flat_map(|r| r.step_by(4096));
|
||||
|
||||
// Create `PhysFrame` type from the starting address
|
||||
frame_addresses.map(|addr| PhysFrame::containing_address(PhysAddr::new(addr)))
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl FrameAllocator<Size4KiB> for BootInfoFrameAllocator {
|
||||
fn allocate_frame(&mut self) -> Option<PhysFrame> {
|
||||
let frame = self.usable_frames().nth(self.next);
|
||||
self.next += 1;
|
||||
frame
|
||||
}
|
||||
}
|
||||
68
kernel/src/kernel/mm/heap.rs
Normal file
68
kernel/src/kernel/mm/heap.rs
Normal file
@ -0,0 +1,68 @@
|
||||
// kernel/src/mm/heap.rs
|
||||
use linked_list_allocator::LockedHeap;
|
||||
use x86_64::{
|
||||
structures::paging::{
|
||||
mapper::MapToError, FrameAllocator, Mapper, Page, PageTableFlags, Size4KiB,
|
||||
},
|
||||
VirtAddr,
|
||||
};
|
||||
use x86_64::structures::paging::PageTable;
|
||||
use crate::hal::cpu;
|
||||
|
||||
#[global_allocator]
|
||||
static ALLOCATOR: LockedHeap = LockedHeap::empty();
|
||||
|
||||
/// 堆的起始虛擬位址
|
||||
pub const HEAP_START: usize = 0x_4444_4444_0000;
|
||||
/// 堆的大小(100 KiB)
|
||||
pub const HEAP_SIZE: usize = 100 * 1024;
|
||||
|
||||
/// Initialize the heap
|
||||
///
|
||||
/// This function will:
|
||||
/// 1. Allocate physical frames for the heap
|
||||
/// 2. Map these frames in the page table
|
||||
/// 3. Initialize the heap allocator
|
||||
pub fn init_heap(
|
||||
mapper: &mut impl Mapper<Size4KiB>,
|
||||
frame_allocator: &mut impl FrameAllocator<Size4KiB>,
|
||||
) -> Result<(), MapToError<Size4KiB>> {
|
||||
// Calculate the page range required for the heap
|
||||
let page_range = {
|
||||
let heap_start = VirtAddr::new(HEAP_START as u64);
|
||||
let heap_end = heap_start + HEAP_SIZE as u64 - 1u64;
|
||||
let heap_start_page = Page::containing_address(heap_start);
|
||||
let heap_end_page = Page::containing_address(heap_end);
|
||||
Page::range_inclusive(heap_start_page, heap_end_page)
|
||||
};
|
||||
|
||||
// Allocate a physical frame for each page and map it
|
||||
for page in page_range {
|
||||
// Allocate a physical frame
|
||||
let frame = frame_allocator
|
||||
.allocate_frame()
|
||||
.ok_or(MapToError::FrameAllocationFailed)?;
|
||||
|
||||
// Set page flags: exists + writable
|
||||
let flags = PageTableFlags::PRESENT | PageTableFlags::WRITABLE;
|
||||
|
||||
// Map page to frame
|
||||
unsafe {
|
||||
mapper.map_to(page, frame, flags, frame_allocator)?.flush();
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize the heap allocator
|
||||
unsafe {
|
||||
ALLOCATOR.lock().init(HEAP_START as *mut u8, HEAP_SIZE);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub unsafe fn get_level_4_table(physical_memory_offset: VirtAddr) -> &'static mut PageTable {
|
||||
let virt = physical_memory_offset + cpu::cpu_r_cr3();
|
||||
let page_table_ptr: *mut PageTable = virt.as_mut_ptr();
|
||||
|
||||
&mut *page_table_ptr
|
||||
}
|
||||
2
kernel/src/kernel/mm/mod.rs
Normal file
2
kernel/src/kernel/mm/mod.rs
Normal file
@ -0,0 +1,2 @@
|
||||
pub mod frame_allocator;
|
||||
pub mod heap;
|
||||
@ -1,5 +1,5 @@
|
||||
pub mod tty;
|
||||
pub mod asm;
|
||||
|
||||
pub(crate) mod mm;
|
||||
// 重新導出由 boot.S 調用的入口點
|
||||
// pub use kernel::{_kernel_init, _kernel_main};
|
||||
@ -36,8 +36,6 @@ pub fn init(framebuffer: &'static mut FrameBuffer) {
|
||||
state.cursor_x = 0;
|
||||
state.cursor_y = 0;
|
||||
}
|
||||
|
||||
clear(0x000000);
|
||||
}
|
||||
|
||||
pub fn clear(color: u32) {
|
||||
|
||||
@ -2,71 +2,36 @@
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
#![feature(abi_x86_interrupt)]
|
||||
#![feature(alloc_error_handler)]
|
||||
extern crate alloc;
|
||||
use alloc::vec::Vec;
|
||||
|
||||
use core::panic::PanicInfo;
|
||||
use bootloader_api::{entry_point, BootInfo};
|
||||
use core::alloc::Layout;
|
||||
use bootloader_api::{config, entry_point, BootInfo, BootloaderConfig};
|
||||
use x86_64::structures::paging::OffsetPageTable;
|
||||
use x86_64::{
|
||||
structures::paging::PageTable,
|
||||
VirtAddr,
|
||||
};
|
||||
|
||||
mod kernel;
|
||||
mod hal;
|
||||
mod libs;
|
||||
mod logger;
|
||||
mod k_init;
|
||||
mod k_main;
|
||||
|
||||
use kernel::tty::tty;
|
||||
use kernel::asm::x86::{gdt, idt};
|
||||
use hal::cpu;
|
||||
const CONFIG: BootloaderConfig = {
|
||||
let mut config = BootloaderConfig::new_default();
|
||||
config.mappings.physical_memory = Some(config::Mapping::Dynamic);
|
||||
config
|
||||
};
|
||||
|
||||
entry_point!(k_init::kernel_init, config = &CONFIG);
|
||||
|
||||
|
||||
entry_point!(kernel_main);
|
||||
|
||||
fn kernel_main(boot_info: &'static mut BootInfo) -> ! {
|
||||
if let Some(framebuffer) = boot_info.framebuffer.as_mut() {
|
||||
tty::init(framebuffer);
|
||||
tty::clear(0x000000);
|
||||
|
||||
kprintln!("CureOS Booting...");
|
||||
kprintln!("Framebuffer initialized");
|
||||
|
||||
kprintln!("Initializing GDT...");
|
||||
gdt::init();
|
||||
kprintln!("GDT initialized");
|
||||
gdt::print_info();
|
||||
kprintln!();
|
||||
|
||||
kprintln!("Initializing IDT...");
|
||||
idt::init();
|
||||
kprintln!("IDT initialized");
|
||||
idt::print_info();
|
||||
kprintln!();
|
||||
|
||||
kprintln!("Welcome to CureOS!");
|
||||
|
||||
let mut brand_buf = [0u8; 64];
|
||||
let mut model_buf = [0u8; 16];
|
||||
kprintln!("CPU: {} ({})",
|
||||
cpu::cpu_get_brand(&mut brand_buf),
|
||||
cpu::cpu_get_model(&mut model_buf)
|
||||
);
|
||||
|
||||
kprintln!();
|
||||
kprintln!("Control Registers:");
|
||||
kprintln!(" CR0: 0x{:016x}", hal::cpu::cpu_r_cr0().bits());
|
||||
kprintln!(" CR2: 0x{:016x}", hal::cpu::cpu_r_cr2());
|
||||
kprintln!(" CR3: 0x{:016x}", hal::cpu::cpu_r_cr3());
|
||||
kprintln!(" CR4: 0x{:016x}", hal::cpu::cpu_r_cr4().bits());
|
||||
|
||||
kprintln!();
|
||||
kprintln!("Kernel initialized successfully!");
|
||||
|
||||
} else {
|
||||
loop {
|
||||
hal::cpu::cpu_halt();
|
||||
}
|
||||
}
|
||||
|
||||
loop {
|
||||
hal::cpu::cpu_halt();
|
||||
}
|
||||
}
|
||||
#[cfg(not(test))]
|
||||
#[panic_handler]
|
||||
fn panic(info: &PanicInfo) -> ! {
|
||||
@ -78,6 +43,12 @@ fn panic(info: &PanicInfo) -> ! {
|
||||
kprintln!("{}", info);
|
||||
|
||||
loop {
|
||||
hal::cpu::cpu_halt();
|
||||
cpu::cpu_halt();
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(test))]
|
||||
#[alloc_error_handler]
|
||||
fn alloc_error_handler(layout: Layout) -> ! {
|
||||
panic!("Allocation error: {:?}", layout)
|
||||
}
|
||||
36
makefile
36
makefile
@ -3,19 +3,16 @@ include config/make-os
|
||||
include config/make-cc
|
||||
include config/make-debug-tool
|
||||
|
||||
# Rust 構建配置
|
||||
BUILD_MODE := release
|
||||
CARGO_FLAGS := --release
|
||||
ifeq ($(BUILD_MODE),debug)
|
||||
CARGO_FLAGS :=
|
||||
endif
|
||||
|
||||
# 目標和輸出
|
||||
RUST_TARGET := x86_64-unknown-none
|
||||
BUILDER_PKG := cure-builder
|
||||
DISK_IMAGE := cure-os.img
|
||||
|
||||
# 顏色輸出
|
||||
COLOR_RESET := \033[0m
|
||||
COLOR_GREEN := \033[32m
|
||||
COLOR_YELLOW := \033[33m
|
||||
@ -24,7 +21,6 @@ COLOR_RED := \033[31m
|
||||
|
||||
.PHONY: all rust-build run clean debug-bochs debug-qemu help all-debug
|
||||
|
||||
# 創建目錄(先清理)
|
||||
$(BUILD_DIR):
|
||||
@rm -rf $(BUILD_DIR)
|
||||
@mkdir -p $(BUILD_DIR)
|
||||
@ -32,21 +28,17 @@ $(BUILD_DIR):
|
||||
$(BIN_DIR):
|
||||
@mkdir -p $(BIN_DIR)
|
||||
|
||||
# 默認目標
|
||||
all: clean-build rust-build copy-artifacts
|
||||
|
||||
# 清理 build 目錄
|
||||
clean-build:
|
||||
@echo "$(COLOR_YELLOW)Cleaning build directory...$(COLOR_RESET)"
|
||||
@rm -rf $(BUILD_DIR)
|
||||
|
||||
# 構建內核
|
||||
rust-build:
|
||||
@echo "$(COLOR_BLUE)Building CureOS...$(COLOR_RESET)"
|
||||
@cargo build -p $(BUILDER_PKG) $(CARGO_FLAGS)
|
||||
@echo "$(COLOR_GREEN)✓ Build complete$(COLOR_RESET)"
|
||||
@echo "$(COLOR_GREEN)Build complete$(COLOR_RESET)"
|
||||
|
||||
# 複製構建產物到 build/ 目錄
|
||||
copy-artifacts: $(BUILD_DIR) $(BIN_DIR)
|
||||
@echo "$(COLOR_BLUE)Copying build artifacts...$(COLOR_RESET)"
|
||||
@BIOS_IMG=$$(find target -name "cure-bios.img" -type f | head -1); \
|
||||
@ -65,46 +57,40 @@ copy-artifacts: $(BUILD_DIR) $(BIN_DIR)
|
||||
cp "$$KERNEL_BIN" $(BIN_DIR)/$(OS_BIN); \
|
||||
fi
|
||||
|
||||
@echo "$(COLOR_GREEN)✓ Artifacts copied$(COLOR_RESET)"
|
||||
@echo "$(COLOR_GREEN)Artifacts copied$(COLOR_RESET)"
|
||||
|
||||
# Debug 構建(包含 dump)
|
||||
all-debug: BUILD_MODE := debug
|
||||
all-debug: CARGO_FLAGS :=
|
||||
all-debug: clean-build rust-build copy-artifacts dump
|
||||
all-debug: clean-build rust-build copy-artifacts
|
||||
|
||||
# 生成反彙編 dump
|
||||
dump:
|
||||
@echo "$(COLOR_BLUE)Generating disassembly dump...$(COLOR_RESET)"
|
||||
@if [ -f "$(BIN_DIR)/$(OS_BIN)" ]; then \
|
||||
echo "$(COLOR_YELLOW)Dumping to $(BUILD_DIR)/dump.txt$(COLOR_RESET)"; \
|
||||
objdump -D $(BIN_DIR)/$(OS_BIN) > $(BUILD_DIR)/dump.txt; \
|
||||
echo "$(COLOR_GREEN)✓ Dump complete$(COLOR_RESET)"; \
|
||||
echo "$(COLOR_GREEN)Dump complete$(COLOR_RESET)"; \
|
||||
else \
|
||||
echo "$(COLOR_RED)Error: Kernel binary not found$(COLOR_RESET)"; \
|
||||
exit 1; \
|
||||
fi
|
||||
|
||||
# 完全清理
|
||||
clean:
|
||||
@echo "$(COLOR_YELLOW)Cleaning all build artifacts...$(COLOR_RESET)"
|
||||
@cargo clean
|
||||
@rm -rf $(BUILD_DIR)
|
||||
@rm -f $(DISK_IMAGE) bochs.log serial.log serial-debug.log bochs-debug.log
|
||||
@echo "$(COLOR_GREEN)✓ Clean complete$(COLOR_RESET)"
|
||||
@echo "$(COLOR_GREEN)Clean complete$(COLOR_RESET)"
|
||||
|
||||
# 使用 QEMU 運行
|
||||
run: all
|
||||
@echo "$(COLOR_BLUE)Running with QEMU...$(COLOR_RESET)"
|
||||
@qemu-system-x86_64 -drive format=raw,file=$(BUILD_DIR)/cure-bios.img \
|
||||
-m 128M \
|
||||
-serial stdio
|
||||
|
||||
# 使用 Bochs 運行
|
||||
run-bochs: all
|
||||
@echo "$(COLOR_BLUE)Running with Bochs...$(COLOR_RESET)"
|
||||
@bochs -q -f bochs.cfg
|
||||
|
||||
# QEMU 調試模式
|
||||
debug-qemu: all-debug
|
||||
@echo "$(COLOR_BLUE)Starting QEMU in debug mode...$(COLOR_RESET)"
|
||||
@qemu-system-x86_64 -drive format=raw,file=$(BUILD_DIR)/cure-bios.img \
|
||||
@ -120,13 +106,11 @@ debug-qemu: all-debug
|
||||
@echo " (gdb) continue"
|
||||
@echo ""
|
||||
|
||||
# Bochs 調試模式
|
||||
debug-bochs: all-debug
|
||||
@echo "$(COLOR_BLUE)Running Bochs in debug mode...$(COLOR_RESET)"
|
||||
@echo "$(COLOR_YELLOW)Dump file available at: $(BUILD_DIR)/dump.txt$(COLOR_RESET)"
|
||||
@bochs -q -f bochs.cfg
|
||||
|
||||
# 顯示構建產物位置
|
||||
show-artifacts:
|
||||
@echo "$(COLOR_BLUE)Build artifacts:$(COLOR_RESET)"
|
||||
@echo " Build directory: $(BUILD_DIR)/"
|
||||
@ -146,26 +130,22 @@ show-artifacts:
|
||||
echo "$(COLOR_YELLOW) (directory doesn't exist)$(COLOR_RESET)"; \
|
||||
fi
|
||||
|
||||
# 檢查構建
|
||||
check:
|
||||
@echo "$(COLOR_BLUE)Checking code...$(COLOR_RESET)"
|
||||
@cargo check -p cure-kernel
|
||||
@cargo check -p $(BUILDER_PKG)
|
||||
@echo "$(COLOR_GREEN)✓ Check complete$(COLOR_RESET)"
|
||||
@echo "$(COLOR_GREEN)Check complete$(COLOR_RESET)"
|
||||
|
||||
# 格式化代碼
|
||||
fmt:
|
||||
@echo "$(COLOR_BLUE)Formatting code...$(COLOR_RESET)"
|
||||
@cargo fmt
|
||||
@echo "$(COLOR_GREEN)✓ Format complete$(COLOR_RESET)"
|
||||
@echo "$(COLOR_GREEN)Format complete$(COLOR_RESET)"
|
||||
|
||||
# Clippy 檢查
|
||||
clippy:
|
||||
@echo "$(COLOR_BLUE)Running clippy...$(COLOR_RESET)"
|
||||
@cargo clippy
|
||||
@echo "$(COLOR_GREEN)✓ Clippy complete$(COLOR_RESET)"
|
||||
@echo "$(COLOR_GREEN)Clippy complete$(COLOR_RESET)"
|
||||
|
||||
# 幫助信息
|
||||
help:
|
||||
@echo "$(COLOR_BLUE)CureOS Makefile Commands:$(COLOR_RESET)"
|
||||
@echo ""
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user