Skip to content

Commit 24ea503

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 24ea503

File tree

1 file changed

+101
-0
lines changed

1 file changed

+101
-0
lines changed

mythril_core/src/logger.rs

+101
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,42 @@ 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 {
101+
cur_col: 0,
102+
cur_row: 0,
103+
}
104+
}
105+
106+
pub fn write(&mut self, s: impl AsRef<str>) {
107+
let mut vga_mem = unsafe { &mut *(VGA_BASE_ADDR as *mut _) };
108+
if self.cur_col == 0 && self.cur_row == 0 {
109+
clear_vga(&mut vga_mem);
110+
}
111+
let (col, row) =
112+
raw_write_vga(s, self.cur_col, self.cur_row, &mut vga_mem);
113+
self.cur_col = col;
114+
self.cur_row = row;
115+
}
116+
}
117+
118+
impl fmt::Write for VgaWriter {
119+
fn write_str(&mut self, s: &str) -> fmt::Result {
120+
self.write(s);
121+
Ok(())
122+
}
123+
124+
fn write_fmt(&mut self, args: fmt::Arguments) -> Result<(), fmt::Error> {
125+
fmt::write(self, args)
126+
}
127+
}
128+
28129
pub struct DirectLogger;
29130
impl DirectLogger {
30131
pub const fn new() -> Self {

0 commit comments

Comments
 (0)