//! Simple VGA console for AIOS v2 //! No external crates, pure Rust implementation use core::fmt::{self, Write}; const VGA_BUFFER: *mut u16 = 0xb8000 as *mut u16; const VGA_WIDTH: usize = 80; const VGA_HEIGHT: usize = 25; static mut CONSOLE: Console = Console { col: 0, row: 0, color: 0x0f, // White on black }; struct Console { col: usize, row: usize, color: u8, } impl Console { fn clear(&mut self) { for i in 0..(VGA_WIDTH * VGA_HEIGHT) { unsafe { VGA_BUFFER.add(i).write_volatile(0x0f00); // Clear with white on black } } self.col = 0; self.row = 0; } fn write_byte(&mut self, byte: u8) { match byte { b'\n' => { self.col = 0; self.row += 1; if self.row >= VGA_HEIGHT { self.scroll_up(); } } byte => { if self.col >= VGA_WIDTH { self.col = 0; self.row += 1; if self.row >= VGA_HEIGHT { self.scroll_up(); } } let pos = self.row * VGA_WIDTH + self.col; let entry = (self.color as u16) << 8 | byte as u16; unsafe { VGA_BUFFER.add(pos).write_volatile(entry); } self.col += 1; } } } fn scroll_up(&mut self) { // Move all lines up by one for row in 1..VGA_HEIGHT { for col in 0..VGA_WIDTH { let pos = row * VGA_WIDTH + col; let prev_pos = (row - 1) * VGA_WIDTH + col; unsafe { let entry = VGA_BUFFER.add(pos).read_volatile(); VGA_BUFFER.add(prev_pos).write_volatile(entry); } } } // Clear last line for col in 0..VGA_WIDTH { let pos = (VGA_HEIGHT - 1) * VGA_WIDTH + col; unsafe { VGA_BUFFER.add(pos).write_volatile(0x0f00); } } self.row = VGA_HEIGHT - 1; } } impl Write for Console { fn write_str(&mut self, s: &str) -> fmt::Result { for byte in s.bytes() { self.write_byte(byte); } Ok(()) } } pub fn init() { unsafe { CONSOLE.clear(); } } pub fn print(s: &str) { unsafe { CONSOLE.write_str(s).unwrap(); } } #[macro_export] macro_rules! kprint { ($($arg:tt)*) => { $crate::console::_print(format_args!($($arg)*)) }; } #[macro_export] macro_rules! kprintln { () => ($crate::console::print("\n")); ($($arg:tt)*) => ({ $crate::console::_print(format_args!($($arg)*)); $crate::console::print("\n"); }) } #[doc(hidden)] pub fn _print(args: fmt::Arguments) { unsafe { CONSOLE.write_fmt(args).unwrap(); } }