Skip to content

Commit 93aa009

Browse files
committed
Initial VGA console output implementation.
- 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.
1 parent 2c87be3 commit 93aa009

File tree

1 file changed

+97
-0
lines changed

1 file changed

+97
-0
lines changed

mythril_core/src/logger.rs

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,68 @@ use core::fmt::Write;
55
use spin::Mutex;
66

77
static LOG_LOCK: Mutex<()> = Mutex::new(());
8+
static mut VGA_WRITER: VgaWriter = VgaWriter::new();
9+
10+
const VGA_BASE_ADDR: usize = 0xB8000;
11+
const VGA_WIDTH: usize = 80;
12+
const VGA_HEIGHT: usize = 25;
13+
const VGA_ATTRIB: u16 = 0x0F00; // black background, white text
14+
15+
fn scroll_vga(vga_mem: &mut [[u16; VGA_WIDTH]; VGA_HEIGHT]) {
16+
for row in 1..VGA_HEIGHT {
17+
for col in 0..VGA_WIDTH {
18+
vga_mem[row - 1][col] = vga_mem[row][col];
19+
}
20+
}
21+
clear_line_vga(VGA_HEIGHT - 1, vga_mem);
22+
}
23+
24+
fn clear_line_vga(row: usize, vga_mem: &mut [[u16; VGA_WIDTH]; VGA_HEIGHT]) {
25+
for col in 0..VGA_WIDTH {
26+
(*vga_mem)[row][col] = VGA_ATTRIB | 0x20;
27+
}
28+
}
29+
30+
pub fn clear_vga(vga_mem: &mut [[u16; VGA_WIDTH]; VGA_HEIGHT]) {
31+
for row in 0..VGA_HEIGHT {
32+
clear_line_vga(row, vga_mem);
33+
}
34+
}
35+
36+
pub fn raw_write_vga(
37+
s: impl AsRef<str>,
38+
mut col: usize,
39+
mut row: usize,
40+
vga_mem: &mut [[u16; VGA_WIDTH]; VGA_HEIGHT],
41+
) -> (usize, usize) {
42+
for byte in s.as_ref().bytes() {
43+
// move cursor on newlines (0x0A) and carriage-returns (0x0D)
44+
if byte == 0x0A {
45+
row += 1;
46+
col = 0;
47+
continue;
48+
} else if byte == 0x0D {
49+
col = 0;
50+
continue;
51+
}
52+
53+
if row >= VGA_HEIGHT {
54+
scroll_vga(vga_mem);
55+
row = VGA_HEIGHT - 1;
56+
}
57+
58+
vga_mem[row][col] = VGA_ATTRIB | (byte as u16);
59+
60+
col += 1;
61+
62+
if col >= VGA_WIDTH {
63+
row += 1;
64+
col = 0;
65+
}
66+
}
67+
68+
(col, row)
69+
}
870

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

1577
// NOTE: the caller should hold `LOG_LOCK`
1678
pub unsafe fn raw_write_console(s: impl AsRef<str>) {
79+
// mirror console output to VGA
80+
VGA_WRITER.write(s.as_ref());
81+
1782
//FIXME: what about addresses above 4GB?
1883
let len = s.as_ref().len();
1984
let ptr = s.as_ref().as_ptr();
@@ -25,6 +90,38 @@ pub unsafe fn raw_write_console(s: impl AsRef<str>) {
2590
: "volatile");
2691
}
2792

93+
pub struct VgaWriter {
94+
cur_col: usize,
95+
cur_row: usize,
96+
}
97+
98+
impl VgaWriter {
99+
pub const fn new() -> Self {
100+
VgaWriter { cur_col: 0, cur_row: 0 }
101+
}
102+
103+
pub fn write(&mut self, s: impl AsRef<str>) {
104+
let mut vga_mem = unsafe { &mut *(VGA_BASE_ADDR as *mut _) };
105+
if self.cur_col == 0 && self.cur_row == 0 {
106+
clear_vga(&mut vga_mem);
107+
}
108+
let (col, row) = raw_write_vga(s, self.cur_col, self.cur_row, &mut vga_mem);
109+
self.cur_col = col;
110+
self.cur_row = row;
111+
}
112+
}
113+
114+
impl fmt::Write for VgaWriter {
115+
fn write_str(&mut self, s: &str) -> fmt::Result {
116+
self.write(s);
117+
Ok(())
118+
}
119+
120+
fn write_fmt(&mut self, args: fmt::Arguments) -> Result<(), fmt::Error> {
121+
fmt::write(self, args)
122+
}
123+
}
124+
28125
pub struct DirectLogger;
29126
impl DirectLogger {
30127
pub const fn new() -> Self {

0 commit comments

Comments
 (0)