From 4977f17e7914a736815001f542ca6e31af127c21 Mon Sep 17 00:00:00 2001 From: ParrotXray Date: Fri, 10 Oct 2025 21:30:02 +0800 Subject: [PATCH] feat: Can start normally --- builder/Cargo.toml | 15 ++ builder/build.rs | 34 +++ builder/src/main.rs | 4 + kernel/.cargo/config.toml | 7 + kernel/Cargo.toml | 15 ++ kernel/src/hal/cpu.rs | 279 +++++++++++++++++++++++++ kernel/src/hal/io.rs | 83 ++++++++ kernel/src/hal/mod.rs | 22 ++ kernel/src/kernel/asm/mod.rs | 1 + kernel/src/kernel/asm/x86/gdt.rs | 64 ++++++ kernel/src/kernel/asm/x86/idt.rs | 0 kernel/src/kernel/asm/x86/interrupt.S | 0 kernel/src/kernel/asm/x86/interrupt.rs | 0 kernel/src/kernel/asm/x86/mod.rs | 4 + kernel/src/kernel/asm/x86/segment.rs | 0 kernel/src/kernel/mod.rs | 5 + kernel/src/kernel/tty/font.rs | 133 ++++++++++++ kernel/src/kernel/tty/mod.rs | 4 + kernel/src/kernel/tty/tty.rs | 186 +++++++++++++++++ kernel/src/libs/libc/mod.rs | 1 + kernel/src/libs/libc/print.rs | 33 +++ kernel/src/libs/mod.rs | 1 + kernel/src/main.rs | 55 +++++ old/GRUB_TEMPLATE | 6 + old/config-grub.sh | 5 + old/linker.ld | 23 ++ old/makefile | 98 +++++++++ 27 files changed, 1078 insertions(+) create mode 100644 builder/Cargo.toml create mode 100644 builder/build.rs create mode 100644 builder/src/main.rs create mode 100644 kernel/.cargo/config.toml create mode 100644 kernel/Cargo.toml create mode 100644 kernel/src/hal/cpu.rs create mode 100644 kernel/src/hal/io.rs create mode 100644 kernel/src/hal/mod.rs create mode 100644 kernel/src/kernel/asm/mod.rs create mode 100644 kernel/src/kernel/asm/x86/gdt.rs create mode 100644 kernel/src/kernel/asm/x86/idt.rs create mode 100644 kernel/src/kernel/asm/x86/interrupt.S create mode 100644 kernel/src/kernel/asm/x86/interrupt.rs create mode 100644 kernel/src/kernel/asm/x86/mod.rs create mode 100644 kernel/src/kernel/asm/x86/segment.rs create mode 100644 kernel/src/kernel/mod.rs create mode 100644 kernel/src/kernel/tty/font.rs create mode 100644 kernel/src/kernel/tty/mod.rs create mode 100644 kernel/src/kernel/tty/tty.rs create mode 100644 kernel/src/libs/libc/mod.rs create mode 100644 kernel/src/libs/libc/print.rs create mode 100644 kernel/src/libs/mod.rs create mode 100644 kernel/src/main.rs create mode 100644 old/GRUB_TEMPLATE create mode 100644 old/config-grub.sh create mode 100644 old/linker.ld create mode 100644 old/makefile diff --git a/builder/Cargo.toml b/builder/Cargo.toml new file mode 100644 index 0000000..72f6390 --- /dev/null +++ b/builder/Cargo.toml @@ -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" \ No newline at end of file diff --git a/builder/build.rs b/builder/build.rs new file mode 100644 index 0000000..980fe1b --- /dev/null +++ b/builder/build.rs @@ -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()); +} \ No newline at end of file diff --git a/builder/src/main.rs b/builder/src/main.rs new file mode 100644 index 0000000..dc35fc2 --- /dev/null +++ b/builder/src/main.rs @@ -0,0 +1,4 @@ +fn main() { + println!("Build completed successfully!"); + println!("Disk images created in target directory"); +} \ No newline at end of file diff --git a/kernel/.cargo/config.toml b/kernel/.cargo/config.toml new file mode 100644 index 0000000..b4b89df --- /dev/null +++ b/kernel/.cargo/config.toml @@ -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"] \ No newline at end of file diff --git a/kernel/Cargo.toml b/kernel/Cargo.toml new file mode 100644 index 0000000..288789d --- /dev/null +++ b/kernel/Cargo.toml @@ -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" \ No newline at end of file diff --git a/kernel/src/hal/cpu.rs b/kernel/src/hal/cpu.rs new file mode 100644 index 0000000..f8ab091 --- /dev/null +++ b/kernel/src/hal/cpu.rs @@ -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: 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() +} \ No newline at end of file diff --git a/kernel/src/hal/io.rs b/kernel/src/hal/io.rs new file mode 100644 index 0000000..549045a --- /dev/null +++ b/kernel/src/hal/io.rs @@ -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() + } +} \ No newline at end of file diff --git a/kernel/src/hal/mod.rs b/kernel/src/hal/mod.rs new file mode 100644 index 0000000..77bd768 --- /dev/null +++ b/kernel/src/hal/mod.rs @@ -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; \ No newline at end of file diff --git a/kernel/src/kernel/asm/mod.rs b/kernel/src/kernel/asm/mod.rs new file mode 100644 index 0000000..a977cad --- /dev/null +++ b/kernel/src/kernel/asm/mod.rs @@ -0,0 +1 @@ +pub mod x86; \ No newline at end of file diff --git a/kernel/src/kernel/asm/x86/gdt.rs b/kernel/src/kernel/asm/x86/gdt.rs new file mode 100644 index 0000000..d912570 --- /dev/null +++ b/kernel/src/kernel/asm/x86/gdt.rs @@ -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); + } +} \ No newline at end of file diff --git a/kernel/src/kernel/asm/x86/idt.rs b/kernel/src/kernel/asm/x86/idt.rs new file mode 100644 index 0000000..e69de29 diff --git a/kernel/src/kernel/asm/x86/interrupt.S b/kernel/src/kernel/asm/x86/interrupt.S new file mode 100644 index 0000000..e69de29 diff --git a/kernel/src/kernel/asm/x86/interrupt.rs b/kernel/src/kernel/asm/x86/interrupt.rs new file mode 100644 index 0000000..e69de29 diff --git a/kernel/src/kernel/asm/x86/mod.rs b/kernel/src/kernel/asm/x86/mod.rs new file mode 100644 index 0000000..d9b8889 --- /dev/null +++ b/kernel/src/kernel/asm/x86/mod.rs @@ -0,0 +1,4 @@ +pub mod gdt; +// pub mod idt; +// pub mod interrupt; +// pub mod segment; \ No newline at end of file diff --git a/kernel/src/kernel/asm/x86/segment.rs b/kernel/src/kernel/asm/x86/segment.rs new file mode 100644 index 0000000..e69de29 diff --git a/kernel/src/kernel/mod.rs b/kernel/src/kernel/mod.rs new file mode 100644 index 0000000..61cec37 --- /dev/null +++ b/kernel/src/kernel/mod.rs @@ -0,0 +1,5 @@ +pub mod tty; +pub mod asm; + +// 重新導出由 boot.S 調用的入口點 +// pub use kernel::{_kernel_init, _kernel_main}; \ No newline at end of file diff --git a/kernel/src/kernel/tty/font.rs b/kernel/src/kernel/tty/font.rs new file mode 100644 index 0000000..2407799 --- /dev/null +++ b/kernel/src/kernel/tty/font.rs @@ -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 +]; diff --git a/kernel/src/kernel/tty/mod.rs b/kernel/src/kernel/tty/mod.rs new file mode 100644 index 0000000..c803794 --- /dev/null +++ b/kernel/src/kernel/tty/mod.rs @@ -0,0 +1,4 @@ +// src/kernel/tty/mod.rs + +pub mod tty; +pub mod font; \ No newline at end of file diff --git a/kernel/src/kernel/tty/tty.rs b/kernel/src/kernel/tty/tty.rs new file mode 100644 index 0000000..026e0e2 --- /dev/null +++ b/kernel/src/kernel/tty/tty.rs @@ -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, + 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) { + 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) +} \ No newline at end of file diff --git a/kernel/src/libs/libc/mod.rs b/kernel/src/libs/libc/mod.rs new file mode 100644 index 0000000..f6380ae --- /dev/null +++ b/kernel/src/libs/libc/mod.rs @@ -0,0 +1 @@ +pub mod print; diff --git a/kernel/src/libs/libc/print.rs b/kernel/src/libs/libc/print.rs new file mode 100644 index 0000000..9795ebc --- /dev/null +++ b/kernel/src/libs/libc/print.rs @@ -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)*))) + }; +} \ No newline at end of file diff --git a/kernel/src/libs/mod.rs b/kernel/src/libs/mod.rs new file mode 100644 index 0000000..5cc3af0 --- /dev/null +++ b/kernel/src/libs/mod.rs @@ -0,0 +1 @@ +pub mod libc; \ No newline at end of file diff --git a/kernel/src/main.rs b/kernel/src/main.rs new file mode 100644 index 0000000..d98b866 --- /dev/null +++ b/kernel/src/main.rs @@ -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(); + } +} \ No newline at end of file diff --git a/old/GRUB_TEMPLATE b/old/GRUB_TEMPLATE new file mode 100644 index 0000000..80668e5 --- /dev/null +++ b/old/GRUB_TEMPLATE @@ -0,0 +1,6 @@ +default=0 +timeout=3 + +menuentry "$_OS_NAME" { + multiboot /boot/$_OS_NAME.bin +} \ No newline at end of file diff --git a/old/config-grub.sh b/old/config-grub.sh new file mode 100644 index 0000000..ff4d4b6 --- /dev/null +++ b/old/config-grub.sh @@ -0,0 +1,5 @@ +#!/usr/bin/bash + +export _OS_NAME=$1 + +cat GRUB_TEMPLATE | envsubst > "$2" \ No newline at end of file diff --git a/old/linker.ld b/old/linker.ld new file mode 100644 index 0000000..113345f --- /dev/null +++ b/old/linker.ld @@ -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) + } +} \ No newline at end of file diff --git a/old/makefile b/old/makefile new file mode 100644 index 0000000..e96a054 --- /dev/null +++ b/old/makefile @@ -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" \ No newline at end of file