feat: Can start normally

This commit is contained in:
ParrotXray 2025-10-10 21:30:02 +08:00
parent 920f7f5fc8
commit 4977f17e79
27 changed files with 1078 additions and 0 deletions

15
builder/Cargo.toml Normal file
View File

@ -0,0 +1,15 @@
[package]
name = "cure-builder"
version = "0.1.0"
edition = "2021"
[dependencies]
[build-dependencies]
bootloader = "0.11.12"
# artifact dependency - 指定 kernel 的 target
[build-dependencies.cure-kernel]
path = "../kernel"
artifact = "bin"
target = "x86_64-unknown-none"

34
builder/build.rs Normal file
View File

@ -0,0 +1,34 @@
use std::path::PathBuf;
fn main() {
// 從環境變數獲取內核路徑(運行時)
let kernel_path = PathBuf::from(
std::env::var("CARGO_BIN_FILE_CURE_KERNEL_cure-kernel")
.expect("CARGO_BIN_FILE_CURE_KERNEL_cure-kernel not set")
);
println!("cargo:warning=Kernel path: {:?}", kernel_path);
// 創建輸出目錄
let out_dir = PathBuf::from(std::env::var("OUT_DIR").unwrap());
// 創建 BIOS 磁盤映像
let bios_path = out_dir.join("cure-bios.img");
bootloader::BiosBoot::new(&kernel_path)
.create_disk_image(&bios_path)
.expect("Failed to create BIOS disk image");
// 創建 UEFI 磁盤映像
let uefi_path = out_dir.join("cure-uefi.img");
bootloader::UefiBoot::new(&kernel_path)
.create_disk_image(&uefi_path)
.expect("Failed to create UEFI disk image");
// 輸出路徑信息
println!("cargo:warning=✓ BIOS image: {:?}", bios_path);
println!("cargo:warning=✓ UEFI image: {:?}", uefi_path);
// 讓 cargo 知道磁盤映像的位置
println!("cargo:rustc-env=BIOS_IMAGE={}", bios_path.display());
println!("cargo:rustc-env=UEFI_IMAGE={}", uefi_path.display());
}

4
builder/src/main.rs Normal file
View File

@ -0,0 +1,4 @@
fn main() {
println!("Build completed successfully!");
println!("Disk images created in target directory");
}

View File

@ -0,0 +1,7 @@
[unstable]
bindeps = true
# 只對 kernel 套用 no_std target
[target.x86_64-unknown-none]
build-std = ["core", "compiler_builtins"]
build-std-features = ["compiler-builtins-mem"]

15
kernel/Cargo.toml Normal file
View File

@ -0,0 +1,15 @@
[package]
name = "cure-kernel"
version = "0.1.0"
edition = "2021"
[dependencies]
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"
[package.metadata.bootloader]
map-physical-memory = true
physical-memory-offset = "0xFFFF800000000000"

279
kernel/src/hal/cpu.rs Normal file
View File

@ -0,0 +1,279 @@
// kernel/src/hal/cpu.rs
use x86_64::registers::control::{Cr0, Cr0Flags, Cr2, Cr3, Cr4, Cr4Flags};
use x86_64::instructions::{interrupts, hlt};
use core::arch::asm;
use x86_64::VirtAddr;
/// 64 位元暫存器類型
#[allow(dead_code)]
pub type Reg64 = u64;
/// 32 位元暫存器類型
#[allow(dead_code)]
pub type Reg32 = u32;
/// 16 位元暫存器類型
#[allow(dead_code)]
pub type Reg16 = u16;
/// 通用目的暫存器結構 (64-bit)
#[allow(dead_code)]
#[repr(C, packed)]
pub struct GpRegs {
pub rax: Reg64,
pub rbx: Reg64,
pub rcx: Reg64,
pub rdx: Reg64,
pub rdi: Reg64,
pub rbp: Reg64,
pub rsi: Reg64,
pub rsp: Reg64,
pub r8: Reg64,
pub r9: Reg64,
pub r10: Reg64,
pub r11: Reg64,
pub r12: Reg64,
pub r13: Reg64,
pub r14: Reg64,
pub r15: Reg64,
}
/// 段暫存器結構
#[allow(dead_code)]
#[repr(C, packed)]
pub struct SgReg {
pub ss: Reg16,
pub es: Reg16,
pub ds: Reg16,
pub fs: Reg16,
pub gs: Reg16,
pub cs: Reg16,
}
// ============ 控制寄存器 ============
/// 讀取 CR0 暫存器
#[allow(dead_code)]
#[inline]
pub fn cpu_r_cr0() -> Cr0Flags {
Cr0::read()
}
/// 讀取 CR2 暫存器
#[allow(dead_code)]
#[inline]
pub fn cpu_r_cr2() -> u64 {
Cr2::read_raw()
}
/// 讀取 CR3 暫存器
#[allow(dead_code)]
#[inline]
pub fn cpu_r_cr3() -> u64 {
Cr3::read().0.start_address().as_u64()
}
/// 讀取 CR4 暫存器
#[allow(dead_code)]
#[inline]
pub fn cpu_r_cr4() -> Cr4Flags {
Cr4::read()
}
/// 寫入 CR0 暫存器
#[allow(dead_code)]
#[inline]
pub fn cpu_w_cr0(val: Cr0Flags) {
unsafe { Cr0::write(val); }
}
/// 寫入 CR3 暫存器
#[allow(dead_code)]
#[inline]
pub fn cpu_w_cr3(val: u64) {
use x86_64::{PhysAddr, structures::paging::PhysFrame};
let frame = PhysFrame::containing_address(PhysAddr::new(val));
unsafe {
Cr3::write(frame, Cr3::read().1);
}
}
/// 寫入 CR4 暫存器
#[allow(dead_code)]
#[inline]
pub fn cpu_w_cr4(val: Cr4Flags) {
unsafe { Cr4::write(val); }
}
// ============ CPU 資訊 ============
/// 獲取 CPU 供應商 ID
///
/// # 參數
/// * `model_out` - 輸出緩衝區,至少需要 13 bytes
/// # 返回
/// 字符串切片,表示 CPU 供應商資訊
#[allow(dead_code)]
pub fn cpu_get_model(model_out: &mut [u8]) -> &str {
if model_out.len() < 13 {
return "Buffer too small";
}
// 使用 raw_cpuid crate
use raw_cpuid::CpuId;
let cpuid = CpuId::new();
if let Some(vendor) = cpuid.get_vendor_info() {
let vendor_string = vendor.as_str();
let bytes = vendor_string.as_bytes();
let copy_len = core::cmp::min(bytes.len(), model_out.len() - 1);
model_out[..copy_len].copy_from_slice(&bytes[..copy_len]);
model_out[copy_len] = 0; // null terminator
match core::str::from_utf8(&model_out[..copy_len]) {
Ok(s) => s,
Err(_) => "Invalid UTF-8"
}
} else {
model_out[0] = b'?';
model_out[1] = 0;
"Unknown Vendor"
}
}
/// 檢查是否支持品牌字串
#[allow(dead_code)]
pub fn cpu_brand_string_supported() -> bool {
use raw_cpuid::CpuId;
let cpuid = CpuId::new();
cpuid.get_processor_brand_string().is_some()
}
/// 獲取 CPU 品牌字串
///
/// # 參數
/// * `brand_out` - 輸出緩衝區,至少需要 49 bytes
///
/// # 返回
/// 字符串切片,表示 CPU 品牌
#[allow(dead_code)]
pub fn cpu_get_brand(brand_out: &mut [u8]) -> &str {
if brand_out.len() < 49 {
return "Buffer too small";
}
use raw_cpuid::CpuId;
let cpuid = CpuId::new();
if let Some(brand) = cpuid.get_processor_brand_string() {
let brand_string = brand.as_str();
let bytes = brand_string.as_bytes();
let copy_len = core::cmp::min(bytes.len(), brand_out.len() - 1);
brand_out[..copy_len].copy_from_slice(&bytes[..copy_len]);
brand_out[copy_len] = 0; // null terminator
core::str::from_utf8(&brand_out[..copy_len]).unwrap_or_else(|_| "Invalid UTF-8")
} else {
brand_out[0] = b'?';
brand_out[1] = 0;
"Unknown CPU"
}
}
// ============ CPU 指令 ============
/// 讀取 CPU 時間戳計數器 (TSC)
///
/// # 返回
/// 時間戳計數值
#[allow(dead_code)]
#[inline]
pub fn cpu_rdtsc() -> u64 {
unsafe {
let low: u32;
let high: u32;
asm!(
"rdtsc",
out("eax") low,
out("edx") high,
options(nomem, nostack, preserves_flags)
);
((high as u64) << 32) | (low as u64)
}
}
/// 執行 CPU 暫停指令 (減少功耗)
#[allow(dead_code)]
#[inline]
pub fn cpu_pause() {
core::hint::spin_loop();
}
/// 停止 CPU 執行,直到下一個中斷發生
#[allow(dead_code)]
#[inline]
pub fn cpu_halt() {
hlt();
}
/// 停止 CPU 並進入低功耗模式 (等同於 cpu_halt)
#[allow(dead_code)]
#[inline]
pub fn cpu_idle() {
hlt();
}
/// 啟用中斷
#[allow(dead_code)]
#[inline]
pub fn cpu_enable_interrupts() {
interrupts::enable();
}
/// 禁用中斷
#[allow(dead_code)]
#[inline]
pub fn cpu_disable_interrupts() {
interrupts::disable();
}
/// 檢查中斷是否啟用
#[allow(dead_code)]
#[inline]
pub fn cpu_interrupts_enabled() -> bool {
interrupts::are_enabled()
}
/// 在禁用中斷的情況下執行閉包
///
/// # 範例
/// ```
/// cpu_without_interrupts(|| {
/// // 臨界區代碼
/// // 中斷被禁用
/// });
/// // 中斷恢復到之前的狀態
/// ```
#[allow(dead_code)]
#[inline]
pub fn cpu_without_interrupts<F, R>(f: F) -> R
where
F: FnOnce() -> R,
{
interrupts::without_interrupts(f)
}
/// 無條件觸發斷點異常 (用於調試)
#[allow(dead_code)]
#[inline]
pub fn cpu_breakpoint() {
x86_64::instructions::interrupts::int3();
}
/// 讀取 RFLAGS 寄存器
#[allow(dead_code)]
#[inline]
pub fn cpu_read_flags() -> u64 {
x86_64::registers::rflags::read().bits()
}

83
kernel/src/hal/io.rs Normal file
View File

@ -0,0 +1,83 @@
// kernel/src/hal/io.rs
use x86_64::instructions::port::{Port, PortReadOnly, PortWriteOnly};
/// 向 I/O 端口寫入一個字節
///
/// # 參數
/// * `port` - 端口號
/// * `value` - 要寫入的值
#[allow(dead_code)]
#[inline]
pub fn io_port_wb(port: u16, value: u8) {
unsafe {
Port::new(port).write(value);
}
}
/// 從 I/O 端口讀取一個字節
///
/// # 參數
/// * `port` - 端口號
/// # 返回
/// 讀取到的值
#[allow(dead_code)]
#[inline]
pub fn io_port_rb(port: u16) -> u8 {
unsafe {
Port::new(port).read()
}
}
/// 向 I/O 端口寫入一個字 (16-bit)
///
/// # 參數
/// * `port` - 端口號
/// * `value` - 要寫入的值
#[allow(dead_code)]
#[inline]
pub fn io_port_ww(port: u16, value: u16) {
unsafe {
Port::new(port).write(value);
}
}
/// 從 I/O 端口讀取一個字 (16-bit)
///
/// # 參數
/// * `port` - 端口號
/// # 返回
/// 讀取到的值
#[allow(dead_code)]
#[inline]
pub fn io_port_rw(port: u16) -> u16 {
unsafe {
Port::new(port).read()
}
}
/// 向 I/O 端口寫入一個雙字 (32-bit)
///
/// # 參數
/// * `port` - 端口號
/// * `value` - 要寫入的值
#[allow(dead_code)]
#[inline]
pub fn io_port_wl(port: u16, value: u32) {
unsafe {
Port::new(port).write(value);
}
}
/// 從 I/O 端口讀取一個雙字 (32-bit)
///
/// # 參數
/// * `port` - 端口號
/// # 返回
/// 讀取到的值
#[allow(dead_code)]
#[inline]
pub fn io_port_rl(port: u16) -> u32 {
unsafe {
Port::new(port).read()
}
}

22
kernel/src/hal/mod.rs Normal file
View File

@ -0,0 +1,22 @@
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_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;

View File

@ -0,0 +1 @@
pub mod x86;

View File

@ -0,0 +1,64 @@
// kernel/src/gdt.rs
use x86_64::structures::gdt::{GlobalDescriptorTable, Descriptor, SegmentSelector};
use x86_64::structures::tss::TaskStateSegment;
use x86_64::VirtAddr;
use lazy_static::lazy_static;
pub const DOUBLE_FAULT_IST_INDEX: u16 = 0;
// === 步驟 1: 創建 TSS ===
lazy_static! {
static ref TSS: TaskStateSegment = {
let mut tss = TaskStateSegment::new();
tss.interrupt_stack_table[DOUBLE_FAULT_IST_INDEX as usize] = {
const STACK_SIZE: usize = 4096 * 5; // 20KB
static mut STACK: [u8; STACK_SIZE] = [0; STACK_SIZE];
let stack_start = VirtAddr::new(unsafe { &raw const STACK as *const _ as u64 });
let stack_end = stack_start + STACK_SIZE as u64;
stack_end
};
tss
};
}
// === 步驟 2: 創建 GDT ===
lazy_static! {
static ref GDT: (GlobalDescriptorTable, Selectors) = {
let mut gdt = GlobalDescriptorTable::new();
let code_selector = gdt.append(Descriptor::kernel_code_segment());
let data_selector = gdt.append(Descriptor::kernel_data_segment());
let tss_selector = gdt.append(Descriptor::tss_segment(&TSS));
(
gdt,
Selectors {
code_selector,
data_selector,
tss_selector,
},
)
};
}
struct Selectors {
code_selector: SegmentSelector,
data_selector: SegmentSelector,
tss_selector: SegmentSelector,
}
pub fn init() {
use x86_64::instructions::segmentation::{Segment, CS};
use x86_64::instructions::tables::load_tss;
GDT.0.load();
unsafe {
CS::set_reg(GDT.1.code_selector);
load_tss(GDT.1.tss_selector);
}
}

View File

View File

View File

View File

@ -0,0 +1,4 @@
pub mod gdt;
// pub mod idt;
// pub mod interrupt;
// pub mod segment;

View File

5
kernel/src/kernel/mod.rs Normal file
View File

@ -0,0 +1,5 @@
pub mod tty;
pub mod asm;
// 重新導出由 boot.S 調用的入口點
// pub use kernel::{_kernel_init, _kernel_main};

View File

@ -0,0 +1,133 @@
#[allow(dead_code)]
pub static FONT_BASIC: [[u8; 16]; 128] = [
[ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ], //0x00,
[ 0x00, 0x00, 0x7E, 0x81, 0xA5, 0x81, 0x81, 0xBD, 0x99, 0x81, 0x81, 0x7E, 0x00, 0x00, 0x00, 0x00, ], //0x01,
[ 0x00, 0x00, 0x7E, 0xFF, 0xDB, 0xFF, 0xFF, 0xC3, 0xE7, 0xFF, 0xFF, 0x7E, 0x00, 0x00, 0x00, 0x00, ], //0x02,
[ 0x00, 0x00, 0x00, 0x00, 0x6C, 0xFE, 0xFE, 0xFE, 0xFE, 0x7C, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, ], //0x03,
[ 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x7C, 0xFE, 0x7C, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, ], //0x04,
[ 0x00, 0x00, 0x00, 0x18, 0x3C, 0x3C, 0xE7, 0xE7, 0xE7, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00, ], //0x05,
[ 0x00, 0x00, 0x00, 0x18, 0x3C, 0x7E, 0xFF, 0xFF, 0x7E, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00, ], //0x06,
[ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3C, 0x3C, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ], //0x07,
[ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE7, 0xC3, 0xC3, 0xE7, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, ], //0x08,
[ 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x66, 0x42, 0x42, 0x66, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, ], //0x09,
[ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC3, 0x99, 0xBD, 0xBD, 0x99, 0xC3, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, ], //0x0A,
[ 0x00, 0x00, 0x1E, 0x0E, 0x1A, 0x32, 0x78, 0xCC, 0xCC, 0xCC, 0xCC, 0x78, 0x00, 0x00, 0x00, 0x00, ], //0x0B,
[ 0x00, 0x00, 0x3C, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x7E, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, ], //0x0C,
[ 0x00, 0x00, 0x3F, 0x33, 0x3F, 0x30, 0x30, 0x30, 0x30, 0x70, 0xF0, 0xE0, 0x00, 0x00, 0x00, 0x00, ], //0x0D,
[ 0x00, 0x00, 0x7F, 0x63, 0x7F, 0x63, 0x63, 0x63, 0x63, 0x67, 0xE7, 0xE6, 0xC0, 0x00, 0x00, 0x00, ], //0x0E,
[ 0x00, 0x00, 0x00, 0x18, 0x18, 0xDB, 0x3C, 0xE7, 0x3C, 0xDB, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, ], //0x0F,
[ 0x00, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFE, 0xF8, 0xF0, 0xE0, 0xC0, 0x80, 0x00, 0x00, 0x00, 0x00, ], //0x10,
[ 0x00, 0x02, 0x06, 0x0E, 0x1E, 0x3E, 0xFE, 0x3E, 0x1E, 0x0E, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00, ], //0x11,
[ 0x00, 0x00, 0x18, 0x3C, 0x7E, 0x18, 0x18, 0x18, 0x7E, 0x3C, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, ], //0x12,
[ 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, ], //0x13,
[ 0x00, 0x00, 0x7F, 0xDB, 0xDB, 0xDB, 0x7B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x00, 0x00, 0x00, 0x00, ], //0x14,
[ 0x00, 0x7C, 0xC6, 0x60, 0x38, 0x6C, 0xC6, 0xC6, 0x6C, 0x38, 0x0C, 0xC6, 0x7C, 0x00, 0x00, 0x00, ], //0x15,
[ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFE, 0xFE, 0xFE, 0x00, 0x00, 0x00, 0x00, ], //0x16,
[ 0x00, 0x00, 0x18, 0x3C, 0x7E, 0x18, 0x18, 0x18, 0x7E, 0x3C, 0x18, 0x7E, 0x00, 0x00, 0x00, 0x00, ], //0x17,
[ 0x00, 0x00, 0x18, 0x3C, 0x7E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, ], //0x18,
[ 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7E, 0x3C, 0x18, 0x00, 0x00, 0x00, 0x00, ], //0x19,
[ 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x0C, 0xFE, 0x0C, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ], //0x1A,
[ 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x60, 0xFE, 0x60, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ], //0x1B, esc
[ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xC0, 0xC0, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ], //0x1C,
[ 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x6C, 0xFE, 0x6C, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ], //0x1D,
[ 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x38, 0x7C, 0x7C, 0xFE, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, ], //0x1E,
[ 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFE, 0x7C, 0x7C, 0x38, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, ], //0x1F,
[ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ], //0x20, ' '
[ 0x00, 0x00, 0x18, 0x3C, 0x3C, 0x3C, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, ], //0x21, '!'
[ 0x00, 0x66, 0x66, 0x66, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ], //0x22, '"'
[ 0x00, 0x00, 0x00, 0x6C, 0x6C, 0xFE, 0x6C, 0x6C, 0x6C, 0xFE, 0x6C, 0x6C, 0x00, 0x00, 0x00, 0x00, ], //0x23, '#'
[ 0x18, 0x18, 0x7C, 0xC6, 0xC2, 0xC0, 0x7C, 0x06, 0x06, 0x86, 0xC6, 0x7C, 0x18, 0x18, 0x00, 0x00, ], //0x24, '$'
[ 0x00, 0x00, 0x00, 0x00, 0xC2, 0xC6, 0x0C, 0x18, 0x30, 0x60, 0xC6, 0x86, 0x00, 0x00, 0x00, 0x00, ], //0x25, '%'
[ 0x00, 0x00, 0x38, 0x6C, 0x6C, 0x38, 0x76, 0xDC, 0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00, ], //0x26, '&'
[ 0x00, 0x30, 0x30, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ], //0x27, '''
[ 0x00, 0x00, 0x0C, 0x18, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x18, 0x0C, 0x00, 0x00, 0x00, 0x00, ], //0x28, '('
[ 0x00, 0x00, 0x30, 0x18, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, ], //0x29, ')'
[ 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x3C, 0xFF, 0x3C, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ], //0x2A, '*'
[ 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7E, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ], //0x2B, '+'
[ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, ], //0x2C, '
[ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ], //0x2D, '-'
[ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, ], //0x2E, '.'
[ 0x00, 0x00, 0x00, 0x00, 0x02, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC0, 0x80, 0x00, 0x00, 0x00, 0x00, ], //0x2F, '/'
[ 0x00, 0x00, 0x38, 0x6C, 0xC6, 0xC6, 0xD6, 0xD6, 0xC6, 0xC6, 0x6C, 0x38, 0x00, 0x00, 0x00, 0x00, ], //0x30, '0'
[ 0x00, 0x00, 0x18, 0x38, 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7E, 0x00, 0x00, 0x00, 0x00, ], //0x31, '1'
[ 0x00, 0x00, 0x7C, 0xC6, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC0, 0xC6, 0xFE, 0x00, 0x00, 0x00, 0x00, ], //0x32, '2'
[ 0x00, 0x00, 0x7C, 0xC6, 0x06, 0x06, 0x3C, 0x06, 0x06, 0x06, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00, ], //0x33, '3'
[ 0x00, 0x00, 0x0C, 0x1C, 0x3C, 0x6C, 0xCC, 0xFE, 0x0C, 0x0C, 0x0C, 0x1E, 0x00, 0x00, 0x00, 0x00, ], //0x34, '4'
[ 0x00, 0x00, 0xFE, 0xC0, 0xC0, 0xC0, 0xFC, 0x06, 0x06, 0x06, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00, ], //0x35, '5'
[ 0x00, 0x00, 0x38, 0x60, 0xC0, 0xC0, 0xFC, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00, ], //0x36, '6'
[ 0x00, 0x00, 0xFE, 0xC6, 0x06, 0x06, 0x0C, 0x18, 0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, ], //0x37, '7'
[ 0x00, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00, ], //0x38, '8'
[ 0x00, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0x7E, 0x06, 0x06, 0x06, 0x0C, 0x78, 0x00, 0x00, 0x00, 0x00, ], //0x39, '9'
[ 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, ], //0x3A, ':'
[ 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, ], //0x3B, ';'
[ 0x00, 0x00, 0x00, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0C, 0x06, 0x00, 0x00, 0x00, 0x00, ], //0x3C, '<'
[ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ], //0x3D, '='
[ 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x0C, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, ], //0x3E, '>'
[ 0x00, 0x00, 0x7C, 0xC6, 0xC6, 0x0C, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, ], //0x3F, '?'
[ 0x00, 0x00, 0x00, 0x7C, 0xC6, 0xC6, 0xDE, 0xDE, 0xDE, 0xDC, 0xC0, 0x7C, 0x00, 0x00, 0x00, 0x00, ], //0x40, '@'
[ 0x00, 0x00, 0x10, 0x38, 0x6C, 0xC6, 0xC6, 0xFE, 0xC6, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00, ], //0x41, 'A'
[ 0x00, 0x00, 0xFC, 0x66, 0x66, 0x66, 0x7C, 0x66, 0x66, 0x66, 0x66, 0xFC, 0x00, 0x00, 0x00, 0x00, ], //0x42, 'B'
[ 0x00, 0x00, 0x3C, 0x66, 0xC2, 0xC0, 0xC0, 0xC0, 0xC0, 0xC2, 0x66, 0x3C, 0x00, 0x00, 0x00, 0x00, ], //0x43, 'C'
[ 0x00, 0x00, 0xF8, 0x6C, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x6C, 0xF8, 0x00, 0x00, 0x00, 0x00, ], //0x44, 'D'
[ 0x00, 0x00, 0xFE, 0x66, 0x62, 0x68, 0x78, 0x68, 0x60, 0x62, 0x66, 0xFE, 0x00, 0x00, 0x00, 0x00, ], //0x45, 'E'
[ 0x00, 0x00, 0xFE, 0x66, 0x62, 0x68, 0x78, 0x68, 0x60, 0x60, 0x60, 0xF0, 0x00, 0x00, 0x00, 0x00, ], //0x46, 'F'
[ 0x00, 0x00, 0x3C, 0x66, 0xC2, 0xC0, 0xC0, 0xDE, 0xC6, 0xC6, 0x66, 0x3A, 0x00, 0x00, 0x00, 0x00, ], //0x47, 'G'
[ 0x00, 0x00, 0xC6, 0xC6, 0xC6, 0xC6, 0xFE, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00, ], //0x48, 'H'
[ 0x00, 0x00, 0x3C, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00, ], //0x49, 'I'
[ 0x00, 0x00, 0x1E, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0xCC, 0xCC, 0xCC, 0x78, 0x00, 0x00, 0x00, 0x00, ], //0x4A, 'J'
[ 0x00, 0x00, 0xE6, 0x66, 0x66, 0x6C, 0x78, 0x78, 0x6C, 0x66, 0x66, 0xE6, 0x00, 0x00, 0x00, 0x00, ], //0x4B, 'K'
[ 0x00, 0x00, 0xF0, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x62, 0x66, 0xFE, 0x00, 0x00, 0x00, 0x00, ], //0x4C, 'L'
[ 0x00, 0x00, 0xC6, 0xEE, 0xFE, 0xFE, 0xD6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00, ], //0x4D, 'M'
[ 0x00, 0x00, 0xC6, 0xE6, 0xF6, 0xFE, 0xDE, 0xCE, 0xC6, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00, ], //0x4E, 'N'
[ 0x00, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00, ], //0x4F, 'O'
[ 0x00, 0x00, 0xFC, 0x66, 0x66, 0x66, 0x7C, 0x60, 0x60, 0x60, 0x60, 0xF0, 0x00, 0x00, 0x00, 0x00, ], //0x50, 'P'
[ 0x00, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xD6, 0xDE, 0x7C, 0x0C, 0x0E, 0x00, 0x00, ], //0x51, 'Q'
[ 0x00, 0x00, 0xFC, 0x66, 0x66, 0x66, 0x7C, 0x6C, 0x66, 0x66, 0x66, 0xE6, 0x00, 0x00, 0x00, 0x00, ], //0x52, 'R'
[ 0x00, 0x00, 0x7C, 0xC6, 0xC6, 0x60, 0x38, 0x0C, 0x06, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00, ], //0x53, 'S'
[ 0x00, 0x00, 0x7E, 0x7E, 0x5A, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00, ], //0x54, 'T'
[ 0x00, 0x00, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00, ], //0x55, 'U'
[ 0x00, 0x00, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x6C, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, ], //0x56, 'V'
[ 0x00, 0x00, 0xC6, 0xC6, 0xC6, 0xC6, 0xD6, 0xD6, 0xD6, 0xFE, 0xEE, 0x6C, 0x00, 0x00, 0x00, 0x00, ], //0x57, 'W'
[ 0x00, 0x00, 0xC6, 0xC6, 0x6C, 0x7C, 0x38, 0x38, 0x7C, 0x6C, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00, ], //0x58, 'X'
[ 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00, ], //0x59, 'Y'
[ 0x00, 0x00, 0xFE, 0xC6, 0x86, 0x0C, 0x18, 0x30, 0x60, 0xC2, 0xC6, 0xFE, 0x00, 0x00, 0x00, 0x00, ], //0x5A, 'Z'
[ 0x00, 0x00, 0x3C, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x3C, 0x00, 0x00, 0x00, 0x00, ], //0x5B, '['
[ 0x00, 0x00, 0x00, 0x80, 0xC0, 0xE0, 0x70, 0x38, 0x1C, 0x0E, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00, ], //0x5C, '\'
[ 0x00, 0x00, 0x3C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x3C, 0x00, 0x00, 0x00, 0x00, ], //0x5D, ']'
[ 0x10, 0x38, 0x6C, 0xC6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ], //0x5E, '^'
[ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, ], //0x5F, '_'
[ 0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ], //0x60, '`'
[ 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00, ], //0x61, 'a'
[ 0x00, 0x00, 0xE0, 0x60, 0x60, 0x78, 0x6C, 0x66, 0x66, 0x66, 0x66, 0x7C, 0x00, 0x00, 0x00, 0x00, ], //0x62, 'b'
[ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xC6, 0xC0, 0xC0, 0xC0, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00, ], //0x63, 'c'
[ 0x00, 0x00, 0x1C, 0x0C, 0x0C, 0x3C, 0x6C, 0xCC, 0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00, ], //0x64, 'd'
[ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xC6, 0xFE, 0xC0, 0xC0, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00, ], //0x65, 'e'
[ 0x00, 0x00, 0x38, 0x6C, 0x64, 0x60, 0xF0, 0x60, 0x60, 0x60, 0x60, 0xF0, 0x00, 0x00, 0x00, 0x00, ], //0x66, 'f'
[ 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x7C, 0x0C, 0xCC, 0x78, 0x00, ], //0x67, 'g'
[ 0x00, 0x00, 0xE0, 0x60, 0x60, 0x6C, 0x76, 0x66, 0x66, 0x66, 0x66, 0xE6, 0x00, 0x00, 0x00, 0x00, ], //0x68, 'h'
[ 0x00, 0x00, 0x18, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00, ], //0x69, 'i'
[ 0x00, 0x00, 0x06, 0x06, 0x00, 0x0E, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x66, 0x66, 0x3C, 0x00, ], //0x6A, 'j'
[ 0x00, 0x00, 0xE0, 0x60, 0x60, 0x66, 0x6C, 0x78, 0x78, 0x6C, 0x66, 0xE6, 0x00, 0x00, 0x00, 0x00, ], //0x6B, 'k'
[ 0x00, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00, ], //0x6C, 'l'
[ 0x00, 0x00, 0x00, 0x00, 0x00, 0xEC, 0xFE, 0xD6, 0xD6, 0xD6, 0xD6, 0xC6, 0x00, 0x00, 0x00, 0x00, ], //0x6D, 'm'
[ 0x00, 0x00, 0x00, 0x00, 0x00, 0xDC, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, ], //0x6E, 'n'
[ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00, ], //0x6F, 'o'
[ 0x00, 0x00, 0x00, 0x00, 0x00, 0xDC, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7C, 0x60, 0x60, 0xF0, 0x00, ], //0x70, 'p'
[ 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x7C, 0x0C, 0x0C, 0x1E, 0x00, ], //0x71, 'q'
[ 0x00, 0x00, 0x00, 0x00, 0x00, 0xDC, 0x76, 0x66, 0x60, 0x60, 0x60, 0xF0, 0x00, 0x00, 0x00, 0x00, ], //0x72, 'r'
[ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xC6, 0x60, 0x38, 0x0C, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00, ], //0x73, 's'
[ 0x00, 0x00, 0x10, 0x30, 0x30, 0xFC, 0x30, 0x30, 0x30, 0x30, 0x36, 0x1C, 0x00, 0x00, 0x00, 0x00, ], //0x74, 't'
[ 0x00, 0x00, 0x00, 0x00, 0x00, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00, ], //0x75, 'u'
[ 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x00, 0x00, 0x00, 0x00, ], //0x76, 'v'
[ 0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0xC6, 0xD6, 0xD6, 0xD6, 0xFE, 0x6C, 0x00, 0x00, 0x00, 0x00, ], //0x77, 'w'
[ 0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0x6C, 0x38, 0x38, 0x38, 0x6C, 0xC6, 0x00, 0x00, 0x00, 0x00, ], //0x78, 'x'
[ 0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7E, 0x06, 0x0C, 0xF8, 0x00, ], //0x79, 'y'
[ 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xCC, 0x18, 0x30, 0x60, 0xC6, 0xFE, 0x00, 0x00, 0x00, 0x00, ], //0x7A, 'z'
[ 0x00, 0x00, 0x0E, 0x18, 0x18, 0x18, 0x70, 0x18, 0x18, 0x18, 0x18, 0x0E, 0x00, 0x00, 0x00, 0x00, ], //0x7B, '['
[ 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, ], //0x7C, '|'
[ 0x00, 0x00, 0x70, 0x18, 0x18, 0x18, 0x0E, 0x18, 0x18, 0x18, 0x18, 0x70, 0x00, 0x00, 0x00, 0x00, ], //0x7D, ']'
[ 0x00, 0x00, 0x76, 0xDC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ], //0x7E, '~'
[ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ], //0x7F, delete
];

View File

@ -0,0 +1,4 @@
// src/kernel/tty/mod.rs
pub mod tty;
pub mod font;

View File

@ -0,0 +1,186 @@
use bootloader_api::info::{FrameBuffer, FrameBufferInfo, PixelFormat};
use crate::kernel::tty::font::FONT_BASIC;
use core::ptr::{addr_of, addr_of_mut};
pub struct TTYState {
framebuffer: *mut u8,
fb_len: usize,
info: Option<FrameBufferInfo>,
cursor_x: usize,
cursor_y: usize,
}
impl TTYState {
const fn new() -> Self {
Self {
framebuffer: core::ptr::null_mut(),
fb_len: 0,
info: None,
cursor_x: 0,
cursor_y: 0,
}
}
}
static mut TTY_STATE: TTYState = TTYState::new();
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;
}
clear(0x000000);
}
pub fn clear(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,
};
let (r, g, b) = u32_to_rgb(color);
let buffer = core::slice::from_raw_parts_mut(state.framebuffer, state.fb_len);
for pixel in buffer.chunks_exact_mut(info.bytes_per_pixel) {
write_pixel(info, pixel, r, g, b);
}
let state_mut = &mut *addr_of_mut!(TTY_STATE);
state_mut.cursor_x = 0;
state_mut.cursor_y = 0;
}
}
fn write_pixel(info: &FrameBufferInfo, pixel: &mut [u8], r: u8, g: u8, b: u8) {
match info.pixel_format {
PixelFormat::Rgb => {
pixel[0] = r;
pixel[1] = g;
pixel[2] = b;
}
PixelFormat::Bgr => {
pixel[0] = b;
pixel[1] = g;
pixel[2] = r;
}
_ => {}
}
}
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;
let b = (color & 0xFF) as u8;
(r, g, b)
}

View File

@ -0,0 +1 @@
pub mod print;

View File

@ -0,0 +1,33 @@
// src/libs/libc/print.rs
use core::fmt;
use crate::kernel::tty::tty;
pub struct Writer;
impl fmt::Write for Writer {
fn write_str(&mut self, s: &str) -> fmt::Result {
tty::tty_put_str(s, None);
Ok(())
}
}
pub fn _print(args: fmt::Arguments) {
use core::fmt::Write;
Writer.write_fmt(args).unwrap();
}
#[macro_export]
macro_rules! print {
($($arg:tt)*) => ($crate::libs::libc::print::_print(format_args!($($arg)*)));
}
#[macro_export]
macro_rules! kprintln {
() => {
$crate::libs::libc::print::_print(format_args!("\n"))
};
($($arg:tt)*) => {
$crate::libs::libc::print::_print(format_args!("{}\n", format_args!($($arg)*)))
};
}

1
kernel/src/libs/mod.rs Normal file
View File

@ -0,0 +1 @@
pub mod libc;

55
kernel/src/main.rs Normal file
View File

@ -0,0 +1,55 @@
// kernel/src/main.rs
#![no_std]
#![no_main]
#![feature(abi_x86_interrupt)]
use core::panic::PanicInfo;
use bootloader_api::{entry_point, BootInfo};
mod kernel;
mod hal;
mod libs;
use kernel::tty::tty;
use kernel::asm::x86::gdt;
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!("Welcome to CureOS!");
kprintln!("initialize GDT");
gdt::init();
kprintln!("GDT initialized");
} else {
loop {
hal::cpu::cpu_halt();
}
}
loop {
hal::cpu::cpu_halt();
}
}
#[cfg(not(test))]
#[panic_handler]
fn panic(info: &PanicInfo) -> ! {
kprintln!();
kprintln!("================================");
kprintln!(" KERNEL PANIC!" );
kprintln!("================================");
kprintln!();
kprintln!("{}", info);
loop {
hal::cpu::cpu_halt();
}
}

6
old/GRUB_TEMPLATE Normal file
View File

@ -0,0 +1,6 @@
default=0
timeout=3
menuentry "$_OS_NAME" {
multiboot /boot/$_OS_NAME.bin
}

5
old/config-grub.sh Normal file
View File

@ -0,0 +1,5 @@
#!/usr/bin/bash
export _OS_NAME=$1
cat GRUB_TEMPLATE | envsubst > "$2"

23
old/linker.ld Normal file
View File

@ -0,0 +1,23 @@
ENTRY(start_)
SECTIONS {
. = 0x100000;
.text BLOCK(4K): {
* (.multiboot) /* boot.o (.multiboot) */
* (.text)
}
.bss BLOCK(4K): {
* (COMMON)
* (.bss)
}
.data BLOCK(4K): {
* (.data)
}
.rodata BLOCK(4k): {
* (.rodata)
}
}

98
old/makefile Normal file
View File

@ -0,0 +1,98 @@
include config/make-locations
include config/make-os
include config/make-debug-tool
BUILD_MODE := release
CARGO_FLAGS := --release
# Rust target for bootloader
RUST_TARGET := x86_64-unknown-none
.PHONY: all all-debug clean run debug-qemu debug-bochs rust-kernel
$(BUILD_DIR):
@mkdir -p $(BUILD_DIR)
$(BIN_DIR):
@mkdir -p $(BIN_DIR)
$(ISO_DIR):
@mkdir -p $(ISO_DIR)
@mkdir -p $(ISO_BOOT_DIR)
@mkdir -p $(ISO_GRUB_DIR)
# 構建 Rust kernel + bootloader提取 bin 文件
rust-kernel: $(BUILD_DIR) $(BIN_DIR)
@echo "Building Rust kernel with bootloader..."
@cargo build -p cure-builder $(CARGO_FLAGS)
@echo "Finding kernel binary..."
@KERNEL_BIN=$$(find target/$(RUST_TARGET)/$(BUILD_MODE) -name "cure-kernel" -type f | head -1); \
if [ -z "$$KERNEL_BIN" ]; then \
echo "Error: Kernel binary not found!"; \
exit 1; \
fi; \
echo "Copying kernel binary to $(BIN_DIR)/$(OS_BIN)"; \
cp "$$KERNEL_BIN" $(BIN_DIR)/$(OS_BIN)
# 創建 ISO使用 GRUB Multiboot2
$(BUILD_DIR)/$(OS_ISO): $(ISO_DIR) rust-kernel
@echo "Creating ISO image..."
@./config-grub.sh $(OS_NAME) $(ISO_GRUB_DIR)/grub.cfg
@cp $(BIN_DIR)/$(OS_BIN) $(ISO_BOOT_DIR)/$(OS_BIN)
@echo "Running grub-mkrescue..."
@grub-mkrescue -o $(BUILD_DIR)/$(OS_ISO) $(ISO_DIR) 2>&1 || \
(echo "Error: grub-mkrescue failed. Installing grub-pc-bin..."; \
sudo apt install -y grub-pc-bin xorriso mtools && \
grub-mkrescue -o $(BUILD_DIR)/$(OS_ISO) $(ISO_DIR))
@echo "ISO created at $(BUILD_DIR)/$(OS_ISO)"
all: $(BUILD_DIR)/$(OS_ISO)
all-debug: BUILD_MODE := debug
all-debug: CARGO_FLAGS :=
all-debug: $(BUILD_DIR)/$(OS_ISO)
@echo "Debug build completed"
clean:
@rm -rf $(BUILD_DIR)
@cargo clean
@echo "Cleaned build artifacts"
# 使用 QEMU 運行 ISO
run: $(BUILD_DIR)/$(OS_ISO)
@echo "Running $(OS_ISO) with QEMU..."
@qemu-system-x86_64 -cdrom $(BUILD_DIR)/$(OS_ISO) -m 512M -serial stdio
# 使用 Bochs 運行 ISO
run-bochs: $(BUILD_DIR)/$(OS_ISO)
@echo "Running ISO with Bochs..."
@bochs -q -f bochs.cfg
# QEMU 調試模式
debug-qemu: all-debug
@echo "Starting QEMU in debug mode..."
@qemu-system-x86_64 -cdrom $(BUILD_DIR)/$(OS_ISO) -m 512M \
-serial stdio -s -S &
@sleep 1
@echo "QEMU waiting for GDB connection on localhost:1234"
@echo "Run: gdb target/$(RUST_TARGET)/debug/cure-kernel"
@echo "Then: (gdb) target remote localhost:1234"
# Bochs 調試模式
debug-bochs: all-debug
@echo "Running Bochs in debug mode..."
@bochs -q -f bochs.cfg
# 幫助信息
help:
@echo "CureOS Build System"
@echo ""
@echo "Targets:"
@echo " all - Build ISO image (release mode)"
@echo " all-debug - Build ISO image (debug mode)"
@echo " clean - Clean all build artifacts"
@echo " run - Build and run ISO with QEMU"
@echo " run-bochs - Build and run ISO with Bochs"
@echo " debug-qemu - Run QEMU in debug mode"
@echo " debug-bochs - Run Bochs in debug mode"
@echo " help - Show this help message"