diff --git a/makefile b/makefile index e3b74c2..2b0b441 100644 --- a/makefile +++ b/makefile @@ -22,24 +22,20 @@ $(ISO_DIR): @mkdir -p $(ISO_BOOT_DIR) @mkdir -p $(ISO_GRUB_DIR) -# 編譯 Rust 代碼 rust-kernel: @echo "Building Rust kernel..." @cargo build $(CARGO_FLAGS) -# 編譯組合語言文件(如果還需要) $(OBJECT_DIR)/%.S.o: %.S @mkdir -p $(@D) @echo "Compiling: $< -> $@" @$(CC) $(INCLUDES) -c $< -o $@ -# 編譯需要的 C 文件(如果還有) $(OBJECT_DIR)/%.c.o: %.c @mkdir -p $(@D) @echo "Compiling: $< -> $@" @$(CC) $(INCLUDES) -c $< -o $@ $(CFLAGS) -# 連結 $(BIN_DIR)/$(OS_BIN): $(OBJECT_DIR) $(BIN_DIR) rust-kernel $(SRC) @echo "Linking..." @cp target/$(RUST_TARGET)/$(BUILD_MODE)/libcure.a $(OBJECT_DIR)/ diff --git a/src/arch/x86/boot.S b/src/arch/x86/boot.S index e8b50fb..f7203fc 100644 --- a/src/arch/x86/boot.S +++ b/src/arch/x86/boot.S @@ -18,6 +18,8 @@ .section .text .global start_ start_: + cli + movl $stack_top, %esp /* TODO: kernel init @@ -27,10 +29,31 @@ */ call _kernel_init + /* install gdt */ + subl $0x6, %esp + movl $_GDT, 2(%esp) + movw _GDT_LIMIT, %ax + movw %ax, (%esp) + lgdt (%esp) + addl $0x6, %esp + + /* processing register (CS, ES, SS, DS, FS, GS) */ + movw $0x10, %cx /* 0x10 in binary representation is 0001 0000. If you right-shift this number by 3 bits, you will get 0000 0010, so the index is 2. */ + movw %cx, %es + movw %cx, %ds + movw %cx, %fs + movw %cx, %gs + movw %cx, %ss + + /* Change CS:IP */ + pushw $0x08 /* 0x08 in binary representation is 0000 1000. If you right-shift this number by 3 bits, you will get 0000 0001, so the index is 1. */ + pushl $_after_gdt + retf + + _after_gdt: pushl %ebx call _kernel_main - - cli + j_: hlt jmp j_ \ No newline at end of file diff --git a/src/hal/cpu.rs b/src/hal/cpu.rs index 95b0914..1aa15fb 100644 --- a/src/hal/cpu.rs +++ b/src/hal/cpu.rs @@ -36,7 +36,7 @@ pub struct SgReg { pub fn cpu_r_cr0() -> Reg32 { let val: Reg32; unsafe { - asm!("mov %cr0, {}", out(reg) val); + asm!("mov %cr0, {0}", out(reg) val); } val } @@ -46,7 +46,7 @@ pub fn cpu_r_cr0() -> Reg32 { pub fn cpu_r_cr2() -> Reg32 { let val: Reg32; unsafe { - asm!("mov %cr2, {}", out(reg) val); + asm!("mov %cr2, {0}", out(reg) val); } val } @@ -56,7 +56,7 @@ pub fn cpu_r_cr2() -> Reg32 { pub fn cpu_r_cr3() -> Reg32 { let val: Reg32; unsafe { - asm!("mov %cr3, {}", out(reg) val); + asm!("mov %cr3, {0}", out(reg) val); } val } @@ -65,7 +65,7 @@ pub fn cpu_r_cr3() -> Reg32 { #[inline] pub fn cpu_w_cr0(val: Reg32) { unsafe { - asm!("mov {}, %cr0", in(reg) val); + asm!("mov {0}, %cr0", in(reg) val); } } @@ -73,7 +73,7 @@ pub fn cpu_w_cr0(val: Reg32) { #[inline] pub fn cpu_w_cr2(val: Reg32) { unsafe { - asm!("mov {}, %cr2", in(reg) val); + asm!("mov {0}, %cr2", in(reg) val); } } @@ -81,7 +81,7 @@ pub fn cpu_w_cr2(val: Reg32) { #[inline] pub fn cpu_w_cr3(val: Reg32) { unsafe { - asm!("mov {}, %cr3", in(reg) val); + asm!("mov {0}, %cr3", in(reg) val); } } @@ -112,12 +112,15 @@ pub fn cpu_get_model(model_out: &mut [u8]) { out[1] = edx; out[2] = ecx; + let _max_function_id: u32 = eax; + // 確保以 null 結尾 if model_out.len() > 12 { model_out[12] = 0; } } +#[allow(dead_code)] const BRAND_LEAF: u32 = 0x80000000; /// 檢查是否支持品牌字串 @@ -136,7 +139,8 @@ pub fn cpu_brand_string_supported() -> bool { ); } - eax >= 0x80000004 + // eax >= 0x80000004 + eax >= BRAND_LEAF + 4 } /// 獲取 CPU 品牌字串 diff --git a/src/hal/mod.rs b/src/hal/mod.rs index 3085b50..8607e9a 100644 --- a/src/hal/mod.rs +++ b/src/hal/mod.rs @@ -1,2 +1,23 @@ pub mod io; pub mod cpu; + +pub use io::io_port_wb; +pub use io::io_port_wl; +pub use io::io_port_rb; +pub use io::io_port_rl; + +pub use cpu::cpu_r_cr0; +pub use cpu::cpu_r_cr2; +pub use cpu::cpu_r_cr3; +pub use cpu::cpu_w_cr0; +pub use cpu::cpu_w_cr2; +pub use cpu::cpu_w_cr3; +pub use cpu::cpu_get_model; +pub use cpu::cpu_brand_string_supported; +pub use cpu::cpu_get_brand; +pub use cpu::cpu_rdtsc; +pub use cpu::cpu_pause; +pub use cpu::cpu_halt; +pub use cpu::cpu_idle; +pub use cpu::cpu_enable_interrupts; +pub use cpu::cpu_disable_interrupts; \ No newline at end of file diff --git a/src/kernel/asm/mod.rs b/src/kernel/asm/mod.rs new file mode 100644 index 0000000..a977cad --- /dev/null +++ b/src/kernel/asm/mod.rs @@ -0,0 +1 @@ +pub mod x86; \ No newline at end of file diff --git a/src/kernel/asm/x86/gdt.rs b/src/kernel/asm/x86/gdt.rs new file mode 100644 index 0000000..dd7d045 --- /dev/null +++ b/src/kernel/asm/x86/gdt.rs @@ -0,0 +1,115 @@ +// src/kernel/asm/x86/gdt.rs + +use core::mem; + +#[allow(dead_code)] +pub const fn sd_type(x: u64) -> u64 { x << 8 } +#[allow(dead_code)] +pub const fn sd_code_data(x: u64) -> u64 { x << 12 } +#[allow(dead_code)] +pub const fn sd_dpl(x: u64) -> u64 { x << 13 } +#[allow(dead_code)] +pub const fn sd_present(x: u64) -> u64 { x << 15 } +#[allow(dead_code)] +pub const fn sd_avl(x: u64) -> u64 { x << 20 } +#[allow(dead_code)] +pub const fn sd_64bits(x: u64) -> u64 { x << 21 } +#[allow(dead_code)] +pub const fn sd_32bits(x: u64) -> u64 { x << 22 } +#[allow(dead_code)] +pub const fn sd_4k_gran(x: u64) -> u64 { x << 23 } + +#[allow(dead_code)] +pub const fn seg_lim_l(x: u64) -> u64 { x & 0x0ffff } +#[allow(dead_code)] +pub const fn seg_lim_h(x: u64) -> u64 { x & 0xf0000 } +#[allow(dead_code)] +pub const fn seg_base_l(x: u64) -> u64 { (x & 0x0000ffff) << 16 } +#[allow(dead_code)] +pub const fn seg_base_m(x: u64) -> u64 { (x & 0x00ff0000) >> 16 } +#[allow(dead_code)] +pub const fn seg_base_h(x: u64) -> u64 { x & 0xff000000 } + +#[allow(dead_code)] +pub const SEG_DATA_RD: u64 = 0x00; // Read-Only +#[allow(dead_code)] +pub const SEG_DATA_RDA: u64 = 0x01; // Read-Only, accessed +#[allow(dead_code)] +pub const SEG_DATA_RDWR: u64 = 0x02; // Read/Write +#[allow(dead_code)] +pub const SEG_DATA_RDWRA: u64 = 0x03; // Read/Write, accessed +#[allow(dead_code)] +pub const SEG_DATA_RDEXPD: u64 = 0x04; // Read-Only, expand-down +#[allow(dead_code)] +pub const SEG_DATA_RDEXPDA: u64 = 0x05; // Read-Only, expand-down, accessed +#[allow(dead_code)] +pub const SEG_DATA_RDWREXPD: u64 = 0x06; // Read/Write, expand-down +#[allow(dead_code)] +pub const SEG_DATA_RDWREXPDA: u64 = 0x07; // Read/Write, expand-down, accessed +#[allow(dead_code)] +pub const SEG_CODE_EX: u64 = 0x08; // Execute-Only +#[allow(dead_code)] +pub const SEG_CODE_EXA: u64 = 0x09; // Execute-Only, accessed +#[allow(dead_code)] +pub const SEG_CODE_EXRD: u64 = 0x0A; // Execute/Read +#[allow(dead_code)] +pub const SEG_CODE_EXRDA: u64 = 0x0B; // Execute/Read, accessed +#[allow(dead_code)] +pub const SEG_CODE_EXC: u64 = 0x0C; // Execute-Only, conforming +#[allow(dead_code)] +pub const SEG_CODE_EXCA: u64 = 0x0D; // Execute-Only, conforming, accessed +#[allow(dead_code)] +pub const SEG_CODE_EXRDC: u64 = 0x0E; // Execute/Read, conforming +#[allow(dead_code)] +pub const SEG_CODE_EXRDCA: u64 = 0x0F; // Execute/Read, conforming, accessed + +#[allow(dead_code)] +pub const SEG_R0_CODE: u64 = + sd_type(SEG_CODE_EXRD) | sd_code_data(1) | sd_dpl(0) | + sd_present(1) | sd_avl(0) | sd_64bits(0) | sd_32bits(1) | + sd_4k_gran(1); + +#[allow(dead_code)] +pub const SEG_R0_DATA: u64 = + sd_type(SEG_DATA_RDWR) | sd_code_data(1) | sd_dpl(0) | + sd_present(1) | sd_avl(0) | sd_64bits(0) | sd_32bits(1) | + sd_4k_gran(1); + +#[allow(dead_code)] +pub const SEG_R3_CODE: u64 = + sd_type(SEG_CODE_EXRD) | sd_code_data(1) | sd_dpl(3) | + sd_present(1) | sd_avl(0) | sd_64bits(0) | sd_32bits(1) | + sd_4k_gran(1); + +#[allow(dead_code)] +pub const SEG_R3_DATA: u64 = + sd_type(SEG_DATA_RDWR) | sd_code_data(1) | sd_dpl(3) | + sd_present(1) | sd_avl(0) | sd_64bits(0) | sd_32bits(1) | + sd_4k_gran(1); + +pub const GDT_ENTRY: usize = 5; + +#[no_mangle] +pub static mut _GDT: [u64; GDT_ENTRY] = [0; GDT_ENTRY]; + +#[no_mangle] +pub static mut _GDT_LIMIT: u16 = (mem::size_of::<[u64; GDT_ENTRY]>() - 1) as u16; + +#[no_mangle] +pub fn _set_gdt_entry(index: usize, base: u64, limit: u64, flags: u64) { + unsafe { + _GDT[index] = seg_base_h(base) | flags | seg_lim_h(limit) | seg_base_h(base); + _GDT[index] <<= 32; + _GDT[index] |= seg_base_l(base) | seg_lim_l(limit); + } + +} + +#[no_mangle] +pub fn _init_gdt() { + _set_gdt_entry(0, 0, 0, 0); + _set_gdt_entry(1, 0, 0xfffff, SEG_R0_CODE); + _set_gdt_entry(2, 0, 0xfffff, SEG_R0_DATA); + _set_gdt_entry(3, 0, 0xfffff, SEG_R3_CODE); + _set_gdt_entry(4, 0, 0xfffff, SEG_R3_DATA); +} \ No newline at end of file diff --git a/src/kernel/asm/x86/idt.rs b/src/kernel/asm/x86/idt.rs new file mode 100644 index 0000000..e69de29 diff --git a/src/kernel/asm/x86/mod.rs b/src/kernel/asm/x86/mod.rs new file mode 100644 index 0000000..6aed368 --- /dev/null +++ b/src/kernel/asm/x86/mod.rs @@ -0,0 +1,2 @@ +pub mod gdt; +pub mod idt; \ No newline at end of file diff --git a/src/kernel/kernel.rs b/src/kernel/kernel.rs index 9befe22..ddd84fe 100644 --- a/src/kernel/kernel.rs +++ b/src/kernel/kernel.rs @@ -3,6 +3,7 @@ use core::arch::asm; use crate::kernel::tty::tty; use crate::hal::cpu; use crate::{print, println}; +use crate::kernel::asm::x86::gdt; // boot.S 調用的入口點 #[no_mangle] @@ -12,6 +13,8 @@ pub extern "C" fn _kernel_init() { // TODO: 啟用分頁 tty::tty_init(tty::VGA_BUFFER_PADDR); tty::tty_set_theme(tty::VGA_COLOR_WHITE, tty::VGA_COLOR_BLACK); + + gdt::_init_gdt(); } #[no_mangle] @@ -38,8 +41,15 @@ pub extern "C" fn _kernel_main() { println!("10: {}, 16: {:x}", value, value); unsafe { - loop { - cpu::cpu_idle(); + let limit = gdt::_GDT_LIMIT; + println!("GDT Limit: {:#x}", limit); + for i in 0..gdt::GDT_ENTRY { + println!("GDT[{}] = {:#018x}", i, gdt::_GDT[i]); } } + + + loop { + cpu::cpu_idle(); + } } \ No newline at end of file diff --git a/src/kernel/mod.rs b/src/kernel/mod.rs index 8264245..53c0c05 100644 --- a/src/kernel/mod.rs +++ b/src/kernel/mod.rs @@ -1,5 +1,6 @@ pub mod kernel; pub mod tty; +pub mod asm; // 重新導出由 boot.S 調用的入口點 // pub use kernel::{_kernel_init, _kernel_main}; \ No newline at end of file diff --git a/src/kernel/tty/mod.rs b/src/kernel/tty/mod.rs index 67b2091..393aac4 100644 --- a/src/kernel/tty/mod.rs +++ b/src/kernel/tty/mod.rs @@ -2,7 +2,6 @@ pub mod tty; -// 重新導出 TTY 公共函數 pub use tty::tty_init; pub use tty::tty_set_buffer; pub use tty::tty_set_theme; diff --git a/src/kernel/tty/tty.rs b/src/kernel/tty/tty.rs index 7e95c9b..3404634 100644 --- a/src/kernel/tty/tty.rs +++ b/src/kernel/tty/tty.rs @@ -1,6 +1,7 @@ // src/kernel/tty/tty.rs use crate::hal::io::{io_port_wb}; +use core::ptr::NonNull; /// VGA 屬性類型 (16位) pub type VgaAttribute = u16; @@ -31,7 +32,7 @@ const VGA_DATA_PORT: u16 = 0x03D5; // 全局 TTY 狀態 pub struct TTYState { - vga_buffer: *mut VgaAttribute, + vga_buffer: Option>, theme_color: VgaAttribute, x: usize, y: usize, @@ -40,7 +41,7 @@ pub struct TTYState { impl TTYState { const fn new() -> Self { Self { - vga_buffer: VGA_BUFFER_PADDR as *mut VgaAttribute, + vga_buffer: None, theme_color: (VGA_COLOR_BLACK as VgaAttribute) << 8, x: 0, y: 0, @@ -50,6 +51,7 @@ impl TTYState { static mut TTY_STATE: TTYState = TTYState::new(); +#[no_mangle] fn update_cursor() { unsafe { let pos = TTY_STATE.y * TTY_WIDTH + TTY_STATE.x; @@ -63,21 +65,24 @@ fn update_cursor() { /// 初始化 TTY // vga_buf: *mut u8 +#[no_mangle] pub fn tty_init(vga_buf: usize) { unsafe { - TTY_STATE.vga_buffer = vga_buf as *mut VgaAttribute; + TTY_STATE.vga_buffer = NonNull::new(vga_buf as *mut VgaAttribute); tty_clear(); } } /// 設置 VGA 緩衝區 +#[no_mangle] pub fn tty_set_buffer(vga_buf: usize) { unsafe { - TTY_STATE.vga_buffer = vga_buf as *mut VgaAttribute; + TTY_STATE.vga_buffer = NonNull::new(vga_buf as *mut VgaAttribute); } } /// 設置主題顏色(前景色和背景色) +#[no_mangle] pub fn tty_set_theme(fg: u8, bg: u8) { unsafe { TTY_STATE.theme_color = ((bg << 4 | fg) as VgaAttribute) << 8; @@ -92,37 +97,40 @@ pub fn tty_set_theme(fg: u8, bg: u8) { /// - '\t' 擴展為 4 個空格 /// - '\n' 換行並將游標移至行首 /// - '\r' 將游標移至行首 +#[no_mangle] pub fn tty_put_char(chr: char) { unsafe { - match chr { - '\t' => { - TTY_STATE.x += 4; + if let Some(vga_ptr) = TTY_STATE.vga_buffer { + match chr { + '\t' => { + TTY_STATE.x += 4; + } + '\n' => { + TTY_STATE.y += 1; + TTY_STATE.x = 0; + } + '\r' => { + TTY_STATE.x = 0; + } + _ => { + let offset = TTY_STATE.x + TTY_STATE.y * TTY_WIDTH; + // VGA 文本模式僅支持 8 位字符 + *vga_ptr.as_ptr().add(offset) = TTY_STATE.theme_color | (chr as u8) as VgaAttribute; + TTY_STATE.x += 1; + } } - '\n' => { + + if TTY_STATE.x >= TTY_WIDTH { + TTY_STATE.x = 0; TTY_STATE.y += 1; - TTY_STATE.x = 0; } - '\r' => { - TTY_STATE.x = 0; + + if TTY_STATE.y >= TTY_HEIGHT { + tty_scroll_up(); } - _ => { - let offset = TTY_STATE.x + TTY_STATE.y * TTY_WIDTH; - // VGA 文本模式僅支持 8 位字符 - *TTY_STATE.vga_buffer.add(offset) = TTY_STATE.theme_color | (chr as u8) as VgaAttribute; - TTY_STATE.x += 1; - } - } - if TTY_STATE.x >= TTY_WIDTH { - TTY_STATE.x = 0; - TTY_STATE.y += 1; + update_cursor(); } - - if TTY_STATE.y >= TTY_HEIGHT { - tty_scroll_up(); - } - - update_cursor(); } } @@ -131,6 +139,7 @@ pub fn tty_put_char(chr: char) { /// # 注意 /// - 字符串中的多字節 Unicode 字符會被截斷為低 8 位 /// - 支持 Rust 字符串切片 (&str) +#[no_mangle] pub fn tty_put_str(s: &str) { for chr in s.chars() { tty_put_char(chr); @@ -138,48 +147,64 @@ pub fn tty_put_str(s: &str) { } /// 向上滾動一行 +#[no_mangle] pub fn tty_scroll_up() { unsafe { - let last_line = TTY_WIDTH * (TTY_HEIGHT - 1); - - // 將所有行向上移動一行 - core::ptr::copy( - TTY_STATE.vga_buffer.add(TTY_WIDTH), - TTY_STATE.vga_buffer, - last_line - ); - - // 清空最後一行 - for i in 0..TTY_WIDTH { - *TTY_STATE.vga_buffer.add(i + last_line) = TTY_STATE.theme_color; + if let Some(vga_ptr) = TTY_STATE.vga_buffer { + let last_line = TTY_WIDTH * (TTY_HEIGHT - 1); + let buffer_ptr = vga_ptr.as_ptr(); + + // 將所有行向上移動一行 + core::ptr::copy( + buffer_ptr.add(TTY_WIDTH), + buffer_ptr, + last_line + ); + + // 清空最後一行 + for i in 0..TTY_WIDTH { + *buffer_ptr.add(i + last_line) = TTY_STATE.theme_color; + } + + TTY_STATE.y = if TTY_STATE.y == 0 { 0 } else { TTY_HEIGHT - 1 }; } - - TTY_STATE.y = if TTY_STATE.y == 0 { 0 } else { TTY_HEIGHT - 1 }; } } /// 清空屏幕 +#[no_mangle] pub fn tty_clear() { unsafe { - for i in 0..(TTY_WIDTH * TTY_HEIGHT) { - *TTY_STATE.vga_buffer.add(i) = TTY_STATE.theme_color; + if let Some(vga_ptr) = TTY_STATE.vga_buffer { + let buffer_ptr = vga_ptr.as_ptr(); + + for i in 0..(TTY_WIDTH * TTY_HEIGHT) { + *buffer_ptr.add(i) = TTY_STATE.theme_color; + } + + TTY_STATE.x = 0; + TTY_STATE.y = 0; + update_cursor(); } - TTY_STATE.x = 0; - TTY_STATE.y = 0; - update_cursor(); } } /// 清空指定行 +#[no_mangle] pub fn tty_clear_line(y: usize) { unsafe { - for i in 0..TTY_WIDTH { - *TTY_STATE.vga_buffer.add(i + y * TTY_WIDTH) = TTY_STATE.theme_color; + if let Some(vga_ptr) = TTY_STATE.vga_buffer { + let buffer_ptr = vga_ptr.as_ptr(); + + for i in 0..TTY_WIDTH { + *buffer_ptr.add(i + y * TTY_WIDTH) = TTY_STATE.theme_color; + } } } } /// 設置游標位置 +#[no_mangle] pub fn tty_set_cpos(x: usize, y: usize) { unsafe { TTY_STATE.x = x % TTY_WIDTH; @@ -189,6 +214,7 @@ pub fn tty_set_cpos(x: usize, y: usize) { } /// 獲取游標位置 +#[no_mangle] pub fn tty_get_cpos() -> (usize, usize) { unsafe { (TTY_STATE.x, TTY_STATE.y) @@ -196,6 +222,7 @@ pub fn tty_get_cpos() -> (usize, usize) { } /// 獲取當前主題顏色 +#[no_mangle] pub fn tty_get_theme() -> VgaAttribute { unsafe { TTY_STATE.theme_color