feat: implement staged kernel initialization with memory management and TTY scrolling
This commit is contained in:
parent
429e396474
commit
ac199eabe2
@ -6,74 +6,146 @@ use crate::kernel::mm::{heap, frame_allocator};
|
||||
use crate::kernel::tty::tty;
|
||||
use crate::kprintln;
|
||||
use crate::k_main;
|
||||
use crate::hal::cpu;
|
||||
|
||||
fn _critical_init() {
|
||||
gdt::init();
|
||||
idt::init();
|
||||
}
|
||||
|
||||
fn _memory_init(
|
||||
memory_regions: &'static bootloader_api::info::MemoryRegions,
|
||||
physical_memory_offset: u64
|
||||
) -> (OffsetPageTable<'static>, frame_allocator::BootInfoFrameAllocator) {
|
||||
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(memory_regions)
|
||||
};
|
||||
|
||||
heap::init_heap(&mut mapper, &mut frame_allocator)
|
||||
.expect("Heap initialization failed");
|
||||
|
||||
(mapper, frame_allocator)
|
||||
}
|
||||
|
||||
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!("[INIT] Stage 1: Critical Hardware");
|
||||
kprintln!(" [OK] GDT initialized");
|
||||
gdt::print_info();
|
||||
|
||||
kprintln!();
|
||||
kprintln!(" [OK] IDT initialized");
|
||||
idt::print_info();
|
||||
|
||||
kprintln!();
|
||||
kprintln!("[INIT] Stage 2: Memory Management");
|
||||
kprintln!(" [OK] Physical Memory Offset: {:#x}", physical_memory_offset);
|
||||
|
||||
kprintln!(" [OK] Memory Regions:");
|
||||
let mut total_usable = 0u64;
|
||||
for region in memory_regions.iter() {
|
||||
use bootloader_api::info::MemoryRegionKind;
|
||||
let kind_str = match region.kind {
|
||||
MemoryRegionKind::Usable => {
|
||||
total_usable += region.end - region.start;
|
||||
"Usable"
|
||||
},
|
||||
MemoryRegionKind::Bootloader => "Bootloader",
|
||||
MemoryRegionKind::UnknownBios(_) => "Unknown",
|
||||
MemoryRegionKind::UnknownUefi(_) => "UEFI Reserved",
|
||||
_ => "Reserved",
|
||||
};
|
||||
kprintln!(" {:#016x} - {:#016x} ({})",
|
||||
region.start, region.end, kind_str);
|
||||
}
|
||||
kprintln!(" [INFO] Total Usable Memory: {} MiB", total_usable / (1024 * 1024));
|
||||
|
||||
kprintln!();
|
||||
kprintln!("[INIT] Stage 3: Heap Allocator");
|
||||
kprintln!(" [OK] Heap Start: {:#x}", heap::HEAP_START);
|
||||
kprintln!(" [OK] Heap Size: {} KiB", heap::HEAP_SIZE / 1024);
|
||||
}
|
||||
|
||||
fn _acpi_init(rsdp_addr: Option<u64>, physical_memory_offset: u64) {
|
||||
kprintln!();
|
||||
kprintln!("[INIT] Stage 4: ACPI");
|
||||
|
||||
if let Some(rsdp) = rsdp_addr {
|
||||
kprintln!(" [INFO] RSDP Address: {:#x}", rsdp);
|
||||
|
||||
if let Some(acpi_info) = acpi::init(rsdp, physical_memory_offset) {
|
||||
acpi::print_info(&acpi_info);
|
||||
} else {
|
||||
kprintln!(" [WARN] ACPI initialization failed");
|
||||
}
|
||||
} else {
|
||||
kprintln!(" [WARN] RSDP not provided by bootloader");
|
||||
}
|
||||
}
|
||||
|
||||
fn _post_init() {
|
||||
kprintln!();
|
||||
kprintln!("[INIT] Stage 5: Post Initialization");
|
||||
// TODO: 釋放 bootloader 佔用的內存
|
||||
// TODO: 釋放初始化代碼段(.init 段)
|
||||
kprintln!(" [INFO] Cleanup completed");
|
||||
}
|
||||
|
||||
/// 主初始化入口
|
||||
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");
|
||||
_critical_init();
|
||||
|
||||
let physical_memory_offset = boot_info
|
||||
.physical_memory_offset
|
||||
.into_option()
|
||||
.expect("Physical memory offset not provided");
|
||||
|
||||
let rsdp_addr = boot_info.rsdp_addr.into_option();
|
||||
|
||||
let (_mapper, _frame_allocator) = _memory_init(
|
||||
&boot_info.memory_regions,
|
||||
physical_memory_offset
|
||||
);
|
||||
|
||||
_display_init(framebuffer);
|
||||
|
||||
_boot_report(&boot_info.memory_regions, physical_memory_offset);
|
||||
|
||||
_acpi_init(rsdp_addr, physical_memory_offset);
|
||||
|
||||
_post_init();
|
||||
|
||||
kprintln!();
|
||||
kprintln!("Initializing GDT...");
|
||||
gdt::init();
|
||||
kprintln!("GDT initialized");
|
||||
gdt::print_info();
|
||||
|
||||
kprintln!("========================================");
|
||||
kprintln!(" Kernel Initialization Complete!");
|
||||
kprintln!("========================================");
|
||||
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();
|
||||
}
|
||||
panic!("No framebuffer provided by bootloader");
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn kernel_emergency_cleanup() {
|
||||
// 在 panic 前調用,做最後的清理工作
|
||||
// 比如刷新緩衝區、保存日誌等
|
||||
}
|
||||
@ -213,7 +213,8 @@ pub fn init(rsdp_addr: u64, physical_memory_offset: u64) -> Option<AcpiInfo> {
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// kprintln!(" ACPI Revision: {}", tables.rsdp_revision);
|
||||
|
||||
let platform = match AcpiPlatform::new(tables, handler) {
|
||||
Ok(platform) => platform,
|
||||
Err(e) => {
|
||||
|
||||
@ -1,67 +1,224 @@
|
||||
use bootloader_api::info::{FrameBuffer, FrameBufferInfo, PixelFormat};
|
||||
use crate::kernel::tty::font::FONT_BASIC;
|
||||
use core::ptr::{addr_of, addr_of_mut};
|
||||
use spin::Mutex;
|
||||
|
||||
pub struct TTYState {
|
||||
framebuffer: *mut u8,
|
||||
fb_len: usize,
|
||||
info: Option<FrameBufferInfo>,
|
||||
info: FrameBufferInfo,
|
||||
cursor_x: usize,
|
||||
cursor_y: usize,
|
||||
}
|
||||
|
||||
unsafe impl Send for TTYState {}
|
||||
|
||||
impl TTYState {
|
||||
const fn new() -> Self {
|
||||
const fn new_empty() -> Self {
|
||||
Self {
|
||||
framebuffer: core::ptr::null_mut(),
|
||||
fb_len: 0,
|
||||
info: None,
|
||||
info: FrameBufferInfo {
|
||||
byte_len: 0,
|
||||
width: 0,
|
||||
height: 0,
|
||||
pixel_format: PixelFormat::Rgb,
|
||||
bytes_per_pixel: 0,
|
||||
stride: 0,
|
||||
},
|
||||
cursor_x: 0,
|
||||
cursor_y: 0,
|
||||
}
|
||||
}
|
||||
|
||||
fn init(&mut self, framebuffer: *mut u8, fb_len: usize, info: FrameBufferInfo) {
|
||||
self.framebuffer = framebuffer;
|
||||
self.fb_len = fb_len;
|
||||
self.info = info;
|
||||
self.cursor_x = 0;
|
||||
self.cursor_y = 0;
|
||||
}
|
||||
|
||||
fn is_initialized(&self) -> bool {
|
||||
!self.framebuffer.is_null()
|
||||
}
|
||||
|
||||
fn clear(&mut self, color: u32) {
|
||||
if !self.is_initialized() {
|
||||
return;
|
||||
}
|
||||
|
||||
let (r, g, b) = u32_to_rgb(color);
|
||||
let buffer = unsafe {
|
||||
core::slice::from_raw_parts_mut(self.framebuffer, self.fb_len)
|
||||
};
|
||||
|
||||
for pixel in buffer.chunks_exact_mut(self.info.bytes_per_pixel) {
|
||||
write_pixel(&self.info, pixel, r, g, b);
|
||||
}
|
||||
|
||||
self.cursor_x = 0;
|
||||
self.cursor_y = 0;
|
||||
}
|
||||
|
||||
fn draw_pixel(&mut self, x: usize, y: usize, color: u32) {
|
||||
if !self.is_initialized() {
|
||||
return;
|
||||
}
|
||||
|
||||
if x >= self.info.width || y >= self.info.height {
|
||||
return;
|
||||
}
|
||||
|
||||
let pixel_offset = (y * self.info.stride + x) * self.info.bytes_per_pixel;
|
||||
let (r, g, b) = u32_to_rgb(color);
|
||||
|
||||
let buffer = unsafe {
|
||||
core::slice::from_raw_parts_mut(self.framebuffer, self.fb_len)
|
||||
};
|
||||
|
||||
if let Some(pixel) = buffer.get_mut(pixel_offset..pixel_offset + self.info.bytes_per_pixel) {
|
||||
write_pixel(&self.info, pixel, r, g, b);
|
||||
}
|
||||
}
|
||||
|
||||
fn scroll_up(&mut self) {
|
||||
const CHAR_HEIGHT: usize = 16;
|
||||
|
||||
if !self.is_initialized() {
|
||||
return;
|
||||
}
|
||||
|
||||
let buffer = unsafe {
|
||||
core::slice::from_raw_parts_mut(self.framebuffer, self.fb_len)
|
||||
};
|
||||
|
||||
let bytes_per_pixel = self.info.bytes_per_pixel;
|
||||
let stride = self.info.stride;
|
||||
let width = self.info.width;
|
||||
let height = self.info.height;
|
||||
|
||||
for y in CHAR_HEIGHT..height {
|
||||
let src_offset = y * stride * bytes_per_pixel;
|
||||
let dst_offset = (y - CHAR_HEIGHT) * stride * bytes_per_pixel;
|
||||
let row_size = width * bytes_per_pixel;
|
||||
|
||||
if src_offset + row_size <= buffer.len() && dst_offset + row_size <= buffer.len() {
|
||||
buffer.copy_within(src_offset..src_offset + row_size, dst_offset);
|
||||
}
|
||||
}
|
||||
|
||||
for y in (height.saturating_sub(CHAR_HEIGHT))..height {
|
||||
for x in 0..width {
|
||||
let pixel_offset = (y * stride + x) * bytes_per_pixel;
|
||||
if let Some(pixel) = buffer.get_mut(pixel_offset..pixel_offset + bytes_per_pixel) {
|
||||
write_pixel(&self.info, pixel, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.cursor_x = 0;
|
||||
self.cursor_y = height.saturating_sub(CHAR_HEIGHT);
|
||||
}
|
||||
|
||||
fn draw_char(&mut self, c: char, color: u32) {
|
||||
const CHAR_WIDTH: usize = 8;
|
||||
const CHAR_HEIGHT: usize = 16;
|
||||
|
||||
if !self.is_initialized() {
|
||||
return;
|
||||
}
|
||||
|
||||
if c == '\n' {
|
||||
self.cursor_x = 0;
|
||||
self.cursor_y += CHAR_HEIGHT;
|
||||
|
||||
if self.cursor_y + CHAR_HEIGHT > self.info.height {
|
||||
self.scroll_up();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if self.cursor_x + CHAR_WIDTH > self.info.width {
|
||||
self.cursor_x = 0;
|
||||
self.cursor_y += CHAR_HEIGHT;
|
||||
}
|
||||
|
||||
if self.cursor_y + CHAR_HEIGHT > self.info.height {
|
||||
self.scroll_up();
|
||||
}
|
||||
|
||||
let idx = c as usize;
|
||||
if idx >= FONT_BASIC.len() {
|
||||
return;
|
||||
}
|
||||
let glyph = &FONT_BASIC[idx];
|
||||
|
||||
let cursor_x = self.cursor_x;
|
||||
let cursor_y = self.cursor_y;
|
||||
|
||||
for (y, row) in glyph.iter().enumerate() {
|
||||
for x in 0..8 {
|
||||
if (row >> (7 - x)) & 1 == 1 {
|
||||
self.draw_pixel(cursor_x + x, cursor_y + y, color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.cursor_x += CHAR_WIDTH;
|
||||
}
|
||||
|
||||
fn write_str(&mut self, s: &str, color: u32) {
|
||||
for c in s.chars() {
|
||||
self.draw_char(c, color);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_cursor_pos(&self) -> (usize, usize) {
|
||||
(self.cursor_x, self.cursor_y)
|
||||
}
|
||||
|
||||
pub fn set_cursor_pos(&mut self, x: usize, y: usize) {
|
||||
self.cursor_x = x;
|
||||
self.cursor_y = y;
|
||||
}
|
||||
}
|
||||
|
||||
static mut TTY_STATE: TTYState = TTYState::new();
|
||||
static TTY: Mutex<TTYState> = Mutex::new(TTYState::new_empty());
|
||||
|
||||
pub fn init(framebuffer: &'static mut FrameBuffer) {
|
||||
let info = framebuffer.info();
|
||||
let buffer = framebuffer.buffer_mut();
|
||||
|
||||
unsafe {
|
||||
let state = &mut *addr_of_mut!(TTY_STATE);
|
||||
state.framebuffer = buffer.as_mut_ptr();
|
||||
state.fb_len = buffer.len();
|
||||
state.info = Some(info);
|
||||
state.cursor_x = 0;
|
||||
state.cursor_y = 0;
|
||||
}
|
||||
TTY.lock().init(buffer.as_mut_ptr(), buffer.len(), info);
|
||||
}
|
||||
|
||||
pub fn clear(color: u32) {
|
||||
unsafe {
|
||||
let state = &*addr_of!(TTY_STATE);
|
||||
TTY.lock().clear(color);
|
||||
}
|
||||
|
||||
if state.framebuffer.is_null() {
|
||||
return;
|
||||
}
|
||||
pub fn draw_pixel(x: usize, y: usize, color: u32) {
|
||||
TTY.lock().draw_pixel(x, y, color);
|
||||
}
|
||||
|
||||
let info = match state.info.as_ref() {
|
||||
Some(i) => i,
|
||||
None => return,
|
||||
};
|
||||
pub fn draw_char(c: char, color: u32) {
|
||||
TTY.lock().draw_char(c, color);
|
||||
}
|
||||
|
||||
let (r, g, b) = u32_to_rgb(color);
|
||||
let buffer = core::slice::from_raw_parts_mut(state.framebuffer, state.fb_len);
|
||||
pub fn write_str(s: &str, color: u32) {
|
||||
TTY.lock().write_str(s, color);
|
||||
}
|
||||
|
||||
for pixel in buffer.chunks_exact_mut(info.bytes_per_pixel) {
|
||||
write_pixel(info, pixel, r, g, b);
|
||||
}
|
||||
pub fn tty_put_str(s: &str, color: Option<u32>) {
|
||||
let c = color.unwrap_or(0xFFFFFF);
|
||||
write_str(s, c);
|
||||
}
|
||||
|
||||
let state_mut = &mut *addr_of_mut!(TTY_STATE);
|
||||
state_mut.cursor_x = 0;
|
||||
state_mut.cursor_y = 0;
|
||||
}
|
||||
pub fn get_cursor_pos() -> (usize, usize) {
|
||||
TTY.lock().get_cursor_pos()
|
||||
}
|
||||
|
||||
pub fn set_cursor_pos(x: usize, y: usize) {
|
||||
TTY.lock().set_cursor_pos(x, y);
|
||||
}
|
||||
|
||||
fn write_pixel(info: &FrameBufferInfo, pixel: &mut [u8], r: u8, g: u8, b: u8) {
|
||||
@ -80,102 +237,6 @@ fn write_pixel(info: &FrameBufferInfo, pixel: &mut [u8], r: u8, g: u8, b: u8) {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn draw_pixel(x: usize, y: usize, color: u32) {
|
||||
unsafe {
|
||||
let state = &*addr_of!(TTY_STATE);
|
||||
|
||||
if state.framebuffer.is_null() {
|
||||
return;
|
||||
}
|
||||
|
||||
let info = match state.info.as_ref() {
|
||||
Some(i) => i,
|
||||
None => return,
|
||||
};
|
||||
|
||||
if x >= info.width || y >= info.height {
|
||||
return;
|
||||
}
|
||||
|
||||
let pixel_offset = (y * info.stride + x) * info.bytes_per_pixel;
|
||||
let (r, g, b) = u32_to_rgb(color);
|
||||
|
||||
let buffer = core::slice::from_raw_parts_mut(state.framebuffer, state.fb_len);
|
||||
|
||||
if let Some(pixel) = buffer.get_mut(pixel_offset..pixel_offset + info.bytes_per_pixel) {
|
||||
write_pixel(info, pixel, r, g, b);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn draw_char(c: char, color: u32) {
|
||||
const CHAR_WIDTH: usize = 8;
|
||||
const CHAR_HEIGHT: usize = 16;
|
||||
|
||||
unsafe {
|
||||
let state = &*addr_of!(TTY_STATE);
|
||||
|
||||
if state.framebuffer.is_null() {
|
||||
return;
|
||||
}
|
||||
|
||||
let info = match state.info.as_ref() {
|
||||
Some(i) => i,
|
||||
None => return,
|
||||
};
|
||||
|
||||
let state_mut = &mut *addr_of_mut!(TTY_STATE);
|
||||
|
||||
if c == '\n' {
|
||||
state_mut.cursor_x = 0;
|
||||
state_mut.cursor_y += CHAR_HEIGHT;
|
||||
return;
|
||||
}
|
||||
|
||||
if state_mut.cursor_x + CHAR_WIDTH > info.width {
|
||||
state_mut.cursor_x = 0;
|
||||
state_mut.cursor_y += CHAR_HEIGHT;
|
||||
}
|
||||
|
||||
if state_mut.cursor_y + CHAR_HEIGHT > info.height {
|
||||
state_mut.cursor_y = 0;
|
||||
}
|
||||
|
||||
let idx = c as usize;
|
||||
if idx >= FONT_BASIC.len() {
|
||||
return;
|
||||
}
|
||||
let glyph = &FONT_BASIC[idx];
|
||||
|
||||
let cursor_x = state_mut.cursor_x;
|
||||
let cursor_y = state_mut.cursor_y;
|
||||
|
||||
for (y, row) in glyph.iter().enumerate() {
|
||||
for x in 0..8 {
|
||||
if (row >> (7 - x)) & 1 == 1 {
|
||||
draw_pixel(cursor_x + x, cursor_y + y, color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
state_mut.cursor_x += CHAR_WIDTH;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn write_str(s: &str, color: u32) {
|
||||
for c in s.chars() {
|
||||
draw_char(c, color);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn tty_put_str(s: &str, color: Option<u32>) {
|
||||
if let Some(c) = color {
|
||||
write_str(s, c);
|
||||
} else {
|
||||
write_str(s, 0xFFFFFF);
|
||||
}
|
||||
}
|
||||
|
||||
fn u32_to_rgb(color: u32) -> (u8, u8, u8) {
|
||||
let r = ((color >> 16) & 0xFF) as u8;
|
||||
let g = ((color >> 8) & 0xFF) as u8;
|
||||
|
||||
@ -41,7 +41,13 @@ fn panic(info: &PanicInfo) -> ! {
|
||||
kprintln!("================================");
|
||||
kprintln!();
|
||||
kprintln!("{}", info);
|
||||
|
||||
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());
|
||||
|
||||
loop {
|
||||
cpu::cpu_halt();
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user