1+ use core:: fmt;
2+ use core:: fmt:: Write ;
3+ use core:: ptr:: write_volatile;
4+
5+ #[ cfg( feature = "global-console" ) ]
6+ use spin:: { Mutex , MutexGuard } ;
7+
8+ //Simple 8x16 font bitmap for ASCII 32..127
9+ //Each character: 16 bytes, each byte: 8 pixels
10+ const FONT_8X16 : & [ u8 ] = include_bytes ! ( "font8x16.bin" ) ;
11+
12+ #[ cfg( feature = "global-console" ) ]
13+ static GLOBAL_CONSOLE : Mutex < Option < FramebufferConsole > > = Mutex :: new ( None ) ;
14+
15+ pub struct FramebufferConsole {
16+ framebuffer : * mut u8 ,
17+ width : usize ,
18+ height : usize ,
19+ pitch : usize ,
20+ cursor_x : usize ,
21+ cursor_y : usize ,
22+ }
23+
24+ unsafe impl Sync for FramebufferConsole { }
25+ unsafe impl Send for FramebufferConsole { }
26+
27+
28+ impl FramebufferConsole {
29+ pub unsafe fn new ( framebuffer : * mut u8 , width : usize , height : usize , pitch : usize ) -> Self {
30+ Self {
31+ framebuffer,
32+ width,
33+ height,
34+ pitch,
35+ cursor_x : 0 ,
36+ cursor_y : 0 ,
37+ }
38+ }
39+
40+ fn put_char ( & mut self , c : char ) {
41+ if c == '\n' {
42+ self . cursor_x = 0 ;
43+ self . cursor_y += 1 ;
44+ self . scroll_if_needed ( ) ;
45+ return ;
46+ }
47+ if c == '\r' {
48+ self . cursor_x = 0 ;
49+ return ;
50+ }
51+ self . draw_char ( c, self . cursor_x , self . cursor_y ) ;
52+
53+ self . cursor_x += 1 ;
54+ if self . cursor_x * 8 >= self . width {
55+ self . cursor_x = 0 ;
56+ self . cursor_y += 1 ;
57+ self . scroll_if_needed ( ) ;
58+ }
59+ }
60+
61+ fn scroll_if_needed ( & mut self ) {
62+ let max_lines = self . height / 16 ;
63+ if self . cursor_y >= max_lines {
64+ self . scroll_up ( ) ;
65+ self . cursor_y = max_lines - 1 ;
66+ }
67+ }
68+
69+ fn scroll_up ( & mut self ) {
70+ unsafe {
71+ let fb = self . framebuffer ;
72+ let pitch = self . pitch ;
73+ let height_bytes = self . height * pitch;
74+
75+ //Move framebuffer lines up by one character height (16 pixels)
76+ let src = fb. add ( 16 * pitch) ;
77+ core:: ptr:: copy ( src, fb, height_bytes - 16 * pitch) ;
78+
79+ //Clear the last character line by writing zero
80+ let clear_start = fb. add ( height_bytes - 16 * pitch) ;
81+ for i in 0 ..( 16 * pitch) {
82+ write_volatile ( clear_start. add ( i) , 0 ) ;
83+ }
84+ }
85+ }
86+
87+ fn draw_char ( & mut self , c : char , x_char : usize , y_char : usize ) {
88+ let c = c as u8 ;
89+ let glyph = if c < 32 || c > 127 {
90+ & FONT_8X16 [ ( b'?' - 32 ) as usize * 16 ..] [ ..16 ]
91+ } else {
92+ & FONT_8X16 [ ( c - 32 ) as usize * 16 ..] [ ..16 ]
93+ } ;
94+
95+ let fb = self . framebuffer ;
96+ let pitch = self . pitch ;
97+ let x_pixel = x_char * 8 ;
98+ let y_pixel = y_char * 16 ;
99+
100+ unsafe {
101+ for ( row, & bits) in glyph. iter ( ) . enumerate ( ) {
102+ for bit in 0 ..8 {
103+ let pixel_on = ( bits & ( 1 << ( 7 - bit) ) ) != 0 ;
104+ let pixel = if pixel_on { [ 0xFF , 0xFF , 0xFF , 0x00 ] } else { [ 0x00 , 0x00 , 0x00 , 0x00 ] } ;
105+ let offset = ( y_pixel + row) * pitch + ( x_pixel + bit) * 4 ;
106+ for p in 0 ..4 {
107+ write_volatile ( fb. add ( offset + p) , pixel[ p] ) ;
108+ }
109+ }
110+ }
111+ }
112+ }
113+
114+ fn write_string ( & mut self , s : & str ) {
115+ for c in s. chars ( ) {
116+ self . put_char ( c) ;
117+ }
118+ }
119+ }
120+
121+ impl Write for FramebufferConsole {
122+ fn write_str ( & mut self , s : & str ) -> fmt:: Result {
123+ self . write_string ( s) ;
124+ Ok ( ( ) )
125+ }
126+ }
127+
128+ #[ cfg( feature = "global-console" ) ]
129+ pub fn init_console ( framebuffer : * mut u8 , width : usize , height : usize , pitch : usize ) {
130+ let mut con = GLOBAL_CONSOLE . lock ( ) ;
131+ * con = Some ( unsafe { FramebufferConsole :: new ( framebuffer, width, height, pitch) } ) ;
132+ }
133+
134+ #[ cfg( feature = "global-console" ) ]
135+ pub fn console ( ) -> impl Write + ' static {
136+ struct ConsoleGuard < ' a > {
137+ guard : MutexGuard < ' a , Option < FramebufferConsole > > ,
138+ }
139+
140+ impl < ' a > Write for ConsoleGuard < ' a > {
141+ fn write_str ( & mut self , s : & str ) -> fmt:: Result {
142+ if let Some ( console) = & mut * self . guard {
143+ console. write_string ( s) ;
144+ Ok ( ( ) )
145+ } else {
146+ Err ( fmt:: Error )
147+ }
148+ }
149+ }
150+ ConsoleGuard {
151+ guard : GLOBAL_CONSOLE . lock ( ) ,
152+ }
153+ }
154+
155+ #[ macro_export]
156+ macro_rules! fb_print {
157+ ( $( $arg: tt) * ) => { {
158+ use core:: fmt:: Write as _;
159+ let _ = $crate:: console:: console( ) . write_fmt( format_args!( $( $arg) * ) ) ;
160+ } } ;
161+ }
162+
163+ #[ macro_export]
164+ macro_rules! fb_println {
165+ ( ) => {
166+ $crate:: fb_print!( "\n " )
167+ } ;
168+ ( $fmt: expr) => {
169+ $crate:: fb_print!( concat!( $fmt, "\n " ) )
170+ } ;
171+ ( $fmt: expr, $( $arg: tt) * ) => {
172+ $crate:: fb_print!( concat!( $fmt, "\n " ) , $( $arg) * )
173+ } ;
174+ }
0 commit comments