@@ -5,6 +5,68 @@ use core::fmt::Write;
55use spin:: Mutex ;
66
77static 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
971pub 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`
1678pub 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+
28129pub struct DirectLogger ;
29130impl DirectLogger {
30131 pub const fn new ( ) -> Self {
0 commit comments