Skip to content

Commit 6f0b037

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 6f0b037

File tree

1 file changed

+102
-0
lines changed

1 file changed

+102
-0
lines changed

mythril_core/src/logger.rs

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,74 @@ 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 get_vga_ptr() -> *mut [u16; VGA_WIDTH * VGA_HEIGHT] {
16+
VGA_BASE_ADDR as _
17+
}
18+
19+
unsafe fn scroll_vga() {
20+
let vga_mem = get_vga_ptr();
21+
for y in 1..VGA_HEIGHT {
22+
for x in 0..VGA_WIDTH {
23+
(*vga_mem)[(y - 1) * VGA_WIDTH + x] = (*vga_mem)[y * VGA_WIDTH + x];
24+
}
25+
}
26+
clear_line_vga(VGA_HEIGHT - 1);
27+
}
28+
29+
unsafe fn clear_line_vga(y: usize) {
30+
let vga_mem = get_vga_ptr();
31+
for x in 0..VGA_WIDTH {
32+
(*vga_mem)[y * VGA_WIDTH + x] = VGA_ATTRIB | 0x20;
33+
}
34+
}
35+
36+
pub unsafe fn clear_vga() {
37+
for y in 0..VGA_HEIGHT {
38+
clear_line_vga(y);
39+
}
40+
}
41+
42+
pub unsafe fn raw_write_vga(
43+
s: impl AsRef<str>,
44+
mut x: usize,
45+
mut y: usize,
46+
) -> (usize, usize) {
47+
let vga_mem = get_vga_ptr();
48+
for byte in s.as_ref().bytes() {
49+
// move cursor on newlines (0x0A) and carriage-returns (0x0D)
50+
if byte == 0x0A {
51+
y += 1;
52+
x = 0;
53+
continue;
54+
} else if byte == 0x0D {
55+
x = 0;
56+
continue;
57+
}
58+
59+
if y >= VGA_HEIGHT {
60+
scroll_vga();
61+
y = VGA_HEIGHT - 1;
62+
}
63+
64+
(*vga_mem)[y * VGA_WIDTH + x] = VGA_ATTRIB | (byte as u16);
65+
66+
x += 1;
67+
68+
if x >= VGA_WIDTH {
69+
y += 1;
70+
x = 0;
71+
}
72+
}
73+
74+
(x, y)
75+
}
876

977
pub fn write_console(s: impl AsRef<str>) {
1078
let lock = LOG_LOCK.lock();
@@ -14,6 +82,9 @@ pub fn write_console(s: impl AsRef<str>) {
1482

1583
// NOTE: the caller should hold `LOG_LOCK`
1684
pub unsafe fn raw_write_console(s: impl AsRef<str>) {
85+
// mirror console output to VGA
86+
VGA_WRITER.write(s.as_ref());
87+
1788
//FIXME: what about addresses above 4GB?
1889
let len = s.as_ref().len();
1990
let ptr = s.as_ref().as_ptr();
@@ -25,6 +96,37 @@ pub unsafe fn raw_write_console(s: impl AsRef<str>) {
2596
: "volatile");
2697
}
2798

99+
pub struct VgaWriter {
100+
cur_x: usize,
101+
cur_y: usize,
102+
}
103+
104+
impl VgaWriter {
105+
pub const fn new() -> Self {
106+
VgaWriter { cur_x: 0, cur_y: 0 }
107+
}
108+
109+
pub unsafe fn write(&mut self, s: impl AsRef<str>) {
110+
if self.cur_x == 0 && self.cur_y == 0 {
111+
clear_vga();
112+
}
113+
let (x, y) = raw_write_vga(s, self.cur_x, self.cur_y);
114+
self.cur_x = x;
115+
self.cur_y = y;
116+
}
117+
}
118+
119+
impl fmt::Write for VgaWriter {
120+
fn write_str(&mut self, s: &str) -> fmt::Result {
121+
unsafe { self.write(s) };
122+
Ok(())
123+
}
124+
125+
fn write_fmt(&mut self, args: fmt::Arguments) -> Result<(), fmt::Error> {
126+
fmt::write(self, args)
127+
}
128+
}
129+
28130
pub struct DirectLogger;
29131
impl DirectLogger {
30132
pub const fn new() -> Self {

0 commit comments

Comments
 (0)