feat: Support basic tty output

This commit is contained in:
ParrotXray 2025-05-05 20:06:18 +08:00
parent 3177749dbe
commit 591372c741
5 changed files with 252 additions and 15 deletions

View File

@ -13,16 +13,17 @@ use core::arch::asm;
/// * `port` - 端口號
/// * `value` - 要寫入的值
#[inline]
pub fn io_port_wb(port: u8, value: u8) {
pub fn io_port_wb(port: u16, value: u8) {
unsafe {
asm!(
"movb {0}, %al",
"movw {1:x}, %dx",
"outb %al, %dx",
in(reg_byte) value,
in(reg) port as u16,
in(reg) port,
out("al") _,
out("dx") _
out("dx") _,
options(att_syntax)
);
}
}
@ -33,16 +34,17 @@ pub fn io_port_wb(port: u8, value: u8) {
/// * `port` - 端口號
/// * `value` - 要寫入的值
#[inline]
pub fn io_port_wl(port: u8, value: u32) {
pub fn io_port_wl(port: u16, value: u32) {
unsafe {
asm!(
"movl {0}, %eax",
"movw {1:x}, %dx",
"outl %eax, %dx",
in(reg) value,
in(reg) port as u16,
in(reg) port,
out("eax") _,
out("dx") _
out("dx") _,
options(att_syntax)
);
}
}
@ -54,7 +56,7 @@ pub fn io_port_wl(port: u8, value: u32) {
/// # 返回
/// 讀取到的值
#[inline]
pub fn io_port_rb(port: u8) -> u8 {
pub fn io_port_rb(port: u16) -> u8 {
let value: u8;
unsafe {
asm!(
@ -62,9 +64,10 @@ pub fn io_port_rb(port: u8) -> u8 {
"inb %dx, %al",
"movb %al, {0}",
out(reg_byte) value,
in(reg) port as u16,
in(reg) port,
out("al") _,
out("dx") _
out("dx") _,
options(att_syntax)
);
}
value
@ -77,7 +80,7 @@ pub fn io_port_rb(port: u8) -> u8 {
/// # 返回
/// 讀取到的值
#[inline]
pub fn io_port_rl(port: u8) -> u32 {
pub fn io_port_rl(port: u16) -> u32 {
let value: u32;
unsafe {
asm!(
@ -85,9 +88,10 @@ pub fn io_port_rl(port: u8) -> u32 {
"inl %dx, %eax",
"movl %eax, {0}",
out(reg) value,
in(reg) port as u16,
in(reg) port,
out("eax") _,
out("dx") _
out("dx") _,
options(att_syntax)
);
}
value

View File

@ -1,5 +1,6 @@
// src/kernel/kernel.rs
use core::arch::asm;
use crate::kernel::tty::tty;
// boot.S 調用的入口點
#[no_mangle]
@ -7,11 +8,24 @@ pub extern "C" fn _kernel_init() {
// TODO: 加載 GDT
// TODO: 加載 IDT
// TODO: 啟用分頁
tty::tty_init(tty::VGA_BUFFER_PADDR);
tty::tty_set_theme(tty::VGA_COLOR_WHITE, tty::VGA_COLOR_BLACK);
}
#[no_mangle]
pub extern "C" fn _kernel_main(_multiboot_info: u32) {
pub extern "C" fn _kernel_post_init() {
}
#[no_mangle]
pub extern "C" fn _kernel_main() {
tty::tty_put_str("Loading....!\n");
// tty::tty_clear();
tty::tty_put_str("Welcome to Cure OS!\n");
unsafe {
loop {
asm!("hlt");

View File

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

View File

@ -1 +1,16 @@
pub mod tty;
// src/kernel/tty/mod.rs
pub mod tty;
// 重新導出 TTY 公共函數
pub use tty::tty_init;
pub use tty::tty_set_buffer;
pub use tty::tty_set_theme;
pub use tty::tty_put_char;
pub use tty::tty_put_str;
pub use tty::tty_scroll_up;
pub use tty::tty_clear;
pub use tty::tty_clear_line;
pub use tty::tty_set_cpos;
pub use tty::tty_get_cpos;
pub use tty::tty_get_theme;

View File

@ -0,0 +1,203 @@
// src/kernel/tty/tty.rs
use crate::hal::io::{io_port_wb};
/// VGA 屬性類型 (16位)
pub type VgaAttribute = u16;
// VGA 顏色常量
pub const VGA_COLOR_BLACK: u8 = 0;
pub const VGA_COLOR_BLUE: u8 = 1;
pub const VGA_COLOR_GREEN: u8 = 2;
pub const VGA_COLOR_CYAN: u8 = 3;
pub const VGA_COLOR_RED: u8 = 4;
pub const VGA_COLOR_MAGENTA: u8 = 5;
pub const VGA_COLOR_BROWN: u8 = 6;
pub const VGA_COLOR_LIGHT_GREY: u8 = 7;
pub const VGA_COLOR_DARK_GREY: u8 = 8;
pub const VGA_COLOR_LIGHT_BLUE: u8 = 9;
pub const VGA_COLOR_LIGHT_GREEN: u8 = 10;
pub const VGA_COLOR_LIGHT_CYAN: u8 = 11;
pub const VGA_COLOR_LIGHT_RED: u8 = 12;
pub const VGA_COLOR_LIGHT_MAGENTA: u8 = 13;
pub const VGA_COLOR_LIGHT_BROWN: u8 = 14;
pub const VGA_COLOR_WHITE: u8 = 15;
pub const VGA_BUFFER_PADDR: usize = 0xB8000;
const TTY_WIDTH: usize = 80;
const TTY_HEIGHT: usize = 25;
const VGA_CTRL_PORT: u16 = 0x03D4;
const VGA_DATA_PORT: u16 = 0x03D5;
// 全局 TTY 狀態
pub struct TTYState {
vga_buffer: *mut VgaAttribute,
theme_color: VgaAttribute,
x: usize,
y: usize,
}
impl TTYState {
const fn new() -> Self {
Self {
vga_buffer: VGA_BUFFER_PADDR as *mut VgaAttribute,
theme_color: (VGA_COLOR_BLACK as VgaAttribute) << 8,
x: 0,
y: 0,
}
}
}
static mut TTY_STATE: TTYState = TTYState::new();
fn update_cursor() {
unsafe {
let pos = TTY_STATE.y * TTY_WIDTH + TTY_STATE.x;
io_port_wb(VGA_CTRL_PORT, 0x0F);
io_port_wb(VGA_DATA_PORT, (pos & 0xFF) as u8);
io_port_wb(VGA_CTRL_PORT, 0x0E);
io_port_wb(VGA_DATA_PORT, ((pos >> 8) & 0xFF) as u8);
}
}
/// 初始化 TTY
// vga_buf: *mut u8
pub fn tty_init(vga_buf: usize) {
unsafe {
TTY_STATE.vga_buffer = vga_buf as *mut VgaAttribute;
tty_clear();
}
}
/// 設置 VGA 緩衝區
pub fn tty_set_buffer(vga_buf: usize) {
unsafe {
TTY_STATE.vga_buffer = vga_buf as *mut VgaAttribute;
}
}
/// 設置主題顏色(前景色和背景色)
pub fn tty_set_theme(fg: u8, bg: u8) {
unsafe {
TTY_STATE.theme_color = ((bg << 4 | fg) as VgaAttribute) << 8;
}
}
/// 向 TTY 輸出單個字符
///
/// # 注意
/// - 僅支援 ASCII 範圍 (0-255) 的字符
/// - 多字節 Unicode 字符會被截斷為低 8 位
/// - '\t' 擴展為 4 個空格
/// - '\n' 換行並將游標移至行首
/// - '\r' 將游標移至行首
pub fn tty_put_char(chr: char) {
unsafe {
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 位字符
*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;
}
if TTY_STATE.y >= TTY_HEIGHT {
tty_scroll_up();
}
update_cursor();
}
}
/// 向 TTY 輸出字符串
///
/// # 注意
/// - 字符串中的多字節 Unicode 字符會被截斷為低 8 位
/// - 支持 Rust 字符串切片 (&str)
pub fn tty_put_str(s: &str) {
for chr in s.chars() {
tty_put_char(chr);
}
}
/// 向上滾動一行
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;
}
TTY_STATE.y = if TTY_STATE.y == 0 { 0 } else { TTY_HEIGHT - 1 };
}
}
/// 清空屏幕
pub fn tty_clear() {
unsafe {
for i in 0..(TTY_WIDTH * TTY_HEIGHT) {
*TTY_STATE.vga_buffer.add(i) = TTY_STATE.theme_color;
}
TTY_STATE.x = 0;
TTY_STATE.y = 0;
update_cursor();
}
}
/// 清空指定行
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;
}
}
}
/// 設置游標位置
pub fn tty_set_cpos(x: usize, y: usize) {
unsafe {
TTY_STATE.x = x % TTY_WIDTH;
TTY_STATE.y = y % TTY_HEIGHT;
update_cursor();
}
}
/// 獲取游標位置
pub fn tty_get_cpos() -> (usize, usize) {
unsafe {
(TTY_STATE.x, TTY_STATE.y)
}
}
/// 獲取當前主題顏色
pub fn tty_get_theme() -> VgaAttribute {
unsafe {
TTY_STATE.theme_color
}
}