diff --git a/mythril_core/src/logger.rs b/mythril_core/src/logger.rs index 3330d72..25ca171 100644 --- a/mythril_core/src/logger.rs +++ b/mythril_core/src/logger.rs @@ -5,6 +5,74 @@ use core::fmt::Write; use spin::Mutex; static LOG_LOCK: Mutex<()> = Mutex::new(()); +static mut VGA_WRITER: VgaWriter = VgaWriter::new(); + +const VGA_BASE_ADDR: usize = 0xB8000; +const VGA_WIDTH: usize = 80; +const VGA_HEIGHT: usize = 25; +const VGA_ATTRIB: u16 = 0x0F00; // black background, white text + +fn get_vga_ptr() -> *mut [u16; VGA_WIDTH * VGA_HEIGHT] { + VGA_BASE_ADDR as _ +} + +unsafe fn scroll_vga() { + let vga_mem = get_vga_ptr(); + for y in 1..VGA_HEIGHT { + for x in 0..VGA_WIDTH { + (*vga_mem)[(y - 1) * VGA_WIDTH + x] = (*vga_mem)[y * VGA_WIDTH + x]; + } + } + clear_line_vga(VGA_HEIGHT - 1); +} + +unsafe fn clear_line_vga(y: usize) { + let vga_mem = get_vga_ptr(); + for x in 0..VGA_WIDTH { + (*vga_mem)[y * VGA_WIDTH + x] = VGA_ATTRIB | 0x20; + } +} + +pub unsafe fn clear_vga() { + for y in 0..VGA_HEIGHT { + clear_line_vga(y); + } +} + +pub unsafe fn raw_write_vga( + s: impl AsRef, + mut x: usize, + mut y: usize, +) -> (usize, usize) { + let vga_mem = get_vga_ptr(); + for byte in s.as_ref().bytes() { + // move cursor on newlines (0x0A) and carriage-returns (0x0D) + if byte == 0x0A { + y += 1; + x = 0; + continue; + } else if byte == 0x0D { + x = 0; + continue; + } + + if y >= VGA_HEIGHT { + scroll_vga(); + y = VGA_HEIGHT - 1; + } + + (*vga_mem)[y * VGA_WIDTH + x] = VGA_ATTRIB | (byte as u16); + + x += 1; + + if x >= VGA_WIDTH { + y += 1; + x = 0; + } + } + + (x, y) +} pub fn write_console(s: impl AsRef) { let lock = LOG_LOCK.lock(); @@ -14,6 +82,9 @@ pub fn write_console(s: impl AsRef) { // NOTE: the caller should hold `LOG_LOCK` pub unsafe fn raw_write_console(s: impl AsRef) { + // mirror console output to VGA + VGA_WRITER.write(s.as_ref()); + //FIXME: what about addresses above 4GB? let len = s.as_ref().len(); let ptr = s.as_ref().as_ptr(); @@ -25,6 +96,37 @@ pub unsafe fn raw_write_console(s: impl AsRef) { : "volatile"); } +pub struct VgaWriter { + cur_x: usize, + cur_y: usize, +} + +impl VgaWriter { + pub const fn new() -> Self { + VgaWriter { cur_x: 0, cur_y: 0 } + } + + pub unsafe fn write(&mut self, s: impl AsRef) { + if self.cur_x == 0 && self.cur_y == 0 { + clear_vga(); + } + let (x, y) = raw_write_vga(s, self.cur_x, self.cur_y); + self.cur_x = x; + self.cur_y = y; + } +} + +impl fmt::Write for VgaWriter { + fn write_str(&mut self, s: &str) -> fmt::Result { + unsafe { self.write(s) }; + Ok(()) + } + + fn write_fmt(&mut self, args: fmt::Arguments) -> Result<(), fmt::Error> { + fmt::write(self, args) + } +} + pub struct DirectLogger; impl DirectLogger { pub const fn new() -> Self {