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 6f0b037
Showing 1 changed file with 102 additions and 0 deletions.
102 changes: 102 additions & 0 deletions mythril_core/src/logger.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<str>,
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<str>) {
let lock = LOG_LOCK.lock();
Expand All @@ -14,6 +82,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 +96,37 @@ pub unsafe fn raw_write_console(s: impl AsRef<str>) {
: "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<str>) {
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 {
Expand Down

0 comments on commit 6f0b037

Please sign in to comment.