Skip to content

Commit

Permalink
Initial VGA console output implementation.
Browse files Browse the repository at this point in the history
- Add VgaWriter struct to handle text output to the VGA text buffer.
- Add raw_write_vga function and support functions for writing directly to the VGA text buffer.
- Add VGA_WRITER static variable to logger module for handling outputting logs to the vGA text buffer.
  • Loading branch information
barkera committed Jun 16, 2020
1 parent 2c87be3 commit 93aa009
Showing 1 changed file with 97 additions and 0 deletions.
97 changes: 97 additions & 0 deletions mythril_core/src/logger.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,68 @@ 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 scroll_vga(vga_mem: &mut [[u16; VGA_WIDTH]; VGA_HEIGHT]) {
for row in 1..VGA_HEIGHT {
for col in 0..VGA_WIDTH {
vga_mem[row - 1][col] = vga_mem[row][col];
}
}
clear_line_vga(VGA_HEIGHT - 1, vga_mem);
}

fn clear_line_vga(row: usize, vga_mem: &mut [[u16; VGA_WIDTH]; VGA_HEIGHT]) {
for col in 0..VGA_WIDTH {
(*vga_mem)[row][col] = VGA_ATTRIB | 0x20;
}
}

pub fn clear_vga(vga_mem: &mut [[u16; VGA_WIDTH]; VGA_HEIGHT]) {
for row in 0..VGA_HEIGHT {
clear_line_vga(row, vga_mem);
}
}

pub fn raw_write_vga(
s: impl AsRef<str>,
mut col: usize,
mut row: usize,
vga_mem: &mut [[u16; VGA_WIDTH]; VGA_HEIGHT],
) -> (usize, usize) {
for byte in s.as_ref().bytes() {
// move cursor on newlines (0x0A) and carriage-returns (0x0D)
if byte == 0x0A {
row += 1;
col = 0;
continue;
} else if byte == 0x0D {
col = 0;
continue;
}

if row >= VGA_HEIGHT {
scroll_vga(vga_mem);
row = VGA_HEIGHT - 1;
}

vga_mem[row][col] = VGA_ATTRIB | (byte as u16);

col += 1;

if col >= VGA_WIDTH {
row += 1;
col = 0;
}
}

(col, row)
}

pub fn write_console(s: impl AsRef<str>) {
let lock = LOG_LOCK.lock();
Expand All @@ -14,6 +76,9 @@ pub fn write_console(s: impl AsRef<str>) {

// NOTE: the caller should hold `LOG_LOCK`
pub unsafe fn raw_write_console(s: impl AsRef<str>) {
// 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();
Expand All @@ -25,6 +90,38 @@ pub unsafe fn raw_write_console(s: impl AsRef<str>) {
: "volatile");
}

pub struct VgaWriter {
cur_col: usize,
cur_row: usize,
}

impl VgaWriter {
pub const fn new() -> Self {
VgaWriter { cur_col: 0, cur_row: 0 }
}

pub fn write(&mut self, s: impl AsRef<str>) {
let mut vga_mem = unsafe { &mut *(VGA_BASE_ADDR as *mut _) };
if self.cur_col == 0 && self.cur_row == 0 {
clear_vga(&mut vga_mem);
}
let (col, row) = raw_write_vga(s, self.cur_col, self.cur_row, &mut vga_mem);
self.cur_col = col;
self.cur_row = row;
}
}

impl fmt::Write for VgaWriter {
fn write_str(&mut self, s: &str) -> fmt::Result {
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 {
Expand Down

0 comments on commit 93aa009

Please sign in to comment.