@@ -5,6 +5,68 @@ use core::fmt::Write;
5
5
use spin:: Mutex ;
6
6
7
7
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
+ }
8
70
9
71
pub fn write_console ( s : impl AsRef < str > ) {
10
72
let lock = LOG_LOCK . lock ( ) ;
@@ -14,6 +76,9 @@ pub fn write_console(s: impl AsRef<str>) {
14
76
15
77
// NOTE: the caller should hold `LOG_LOCK`
16
78
pub unsafe fn raw_write_console ( s : impl AsRef < str > ) {
79
+ // mirror console output to VGA
80
+ VGA_WRITER . write ( s. as_ref ( ) ) ;
81
+
17
82
//FIXME: what about addresses above 4GB?
18
83
let len = s. as_ref ( ) . len ( ) ;
19
84
let ptr = s. as_ref ( ) . as_ptr ( ) ;
@@ -25,6 +90,42 @@ pub unsafe fn raw_write_console(s: impl AsRef<str>) {
25
90
: "volatile" ) ;
26
91
}
27
92
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
+
28
129
pub struct DirectLogger ;
29
130
impl DirectLogger {
30
131
pub const fn new ( ) -> Self {
0 commit comments