Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

VGA console output implementation. #65

Merged
merged 1 commit into from
Jun 21, 2020
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
101 changes: 101 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,42 @@ 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