add: Added GDT table support
This commit is contained in:
parent
00d2cf4344
commit
95d86cf7c9
4
makefile
4
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)/
|
||||
|
||||
@ -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_
|
||||
@ -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 品牌字串
|
||||
|
||||
@ -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;
|
||||
1
src/kernel/asm/mod.rs
Normal file
1
src/kernel/asm/mod.rs
Normal file
@ -0,0 +1 @@
|
||||
pub mod x86;
|
||||
115
src/kernel/asm/x86/gdt.rs
Normal file
115
src/kernel/asm/x86/gdt.rs
Normal file
@ -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);
|
||||
}
|
||||
0
src/kernel/asm/x86/idt.rs
Normal file
0
src/kernel/asm/x86/idt.rs
Normal file
2
src/kernel/asm/x86/mod.rs
Normal file
2
src/kernel/asm/x86/mod.rs
Normal file
@ -0,0 +1,2 @@
|
||||
pub mod gdt;
|
||||
pub mod idt;
|
||||
@ -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();
|
||||
}
|
||||
}
|
||||
@ -1,5 +1,6 @@
|
||||
pub mod kernel;
|
||||
pub mod tty;
|
||||
pub mod asm;
|
||||
|
||||
// 重新導出由 boot.S 調用的入口點
|
||||
// pub use kernel::{_kernel_init, _kernel_main};
|
||||
@ -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;
|
||||
|
||||
@ -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<NonNull<VgaAttribute>>,
|
||||
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
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user