]> git.lizzy.rs Git - loadnothing.git/blob - stage2/src/vga.rs
fa4a49996aa47ce4bd05cf7f5267c89e0cc84bad
[loadnothing.git] / stage2 / src / vga.rs
1 use core::ops::{AddAssign, Deref, DerefMut, Shl, Sub};
2
3 use lazy_static::lazy_static;
4 use spin::Mutex;
5 use volatile::Volatile;
6
7 #[allow(dead_code)]
8 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
9 #[repr(u8)]
10 pub enum Color {
11     Black = 0,
12     Blue = 1,
13     Green = 2,
14     Cyan = 3,
15     Red = 4,
16     Magenta = 5,
17     Brown = 6,
18     LightGray = 7,
19     DarkGray = 8,
20     LightBlue = 9,
21     LightGreen = 10,
22     LightCyan = 11,
23     LightRed = 12,
24     Pink = 13,
25     Yellow = 14,
26     White = 15,
27 }
28
29 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
30 #[repr(transparent)]
31 pub struct ColorCode(u8);
32
33 impl ColorCode {
34     pub fn new(foreground: Color, background: Color) -> ColorCode {
35         ColorCode((background as u8).shl(4) | (foreground as u8))
36     }
37 }
38
39 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
40 #[repr(C)]
41 struct ScreenChar {
42     ascii_character: u8,
43     color_code: ColorCode,
44 }
45
46 impl Deref for ScreenChar {
47     type Target = ScreenChar;
48
49     fn deref(&self) -> &Self::Target {
50         self
51     }
52 }
53
54 impl DerefMut for ScreenChar {
55     fn deref_mut(&mut self) -> &mut Self::Target {
56         self
57     }
58 }
59
60 const BUFFER_WIDTH: usize = 80;
61 const BUFFER_HEIGHT: usize = 25;
62
63 #[repr(transparent)]
64 struct Buffer {
65     chars: [[Volatile<ScreenChar>; BUFFER_WIDTH]; BUFFER_HEIGHT],
66 }
67
68 pub struct Writer {
69     row_position: usize,
70     column_position: usize,
71     color_code: ColorCode,
72     buffer: &'static mut Buffer,
73 }
74
75 impl Writer {
76     #[inline(always)]
77     pub fn write_byte(&mut self, byte: u8) {
78         match byte {
79             b'\n' => self.new_line(),
80             byte => {
81                 if self.column_position >= BUFFER_WIDTH {
82                     self.new_line();
83                 }
84
85                 let row = self.row_position;
86                 let col = self.column_position;
87
88                 let color_code = self.color_code;
89                 self.buffer.chars[row][col].write(ScreenChar {
90                     ascii_character: byte,
91                     color_code,
92                 });
93
94                 self.column_position.add_assign(1);
95             }
96         }
97     }
98
99     #[inline(always)]
100     pub fn write_string(&mut self, s: &str) {
101         for byte in s.bytes() {
102             match byte {
103                 // Printable ASCII character or \n
104                 0x20..=0x7e | b'\n' => self.write_byte(byte),
105                 // Not printable, write error char instead
106                 _ => self.write_byte(0xfe),
107             }
108         }
109     }
110
111     #[inline(always)]
112     fn new_line(&mut self) {
113         if self.row_position >= BUFFER_HEIGHT {
114             for row in 1..BUFFER_HEIGHT {
115                 for col in 0..BUFFER_WIDTH {
116                     let character = self.buffer.chars[row][col].read();
117                     self.buffer.chars[row.sub(1)][col].write(character);
118                 }
119             }
120
121             self.clear_row(BUFFER_HEIGHT.sub(1));
122         }
123
124         self.row_position.add_assign(1);
125         self.column_position = 0;
126     }
127
128     fn clear_row(&mut self, row: usize) {
129         let blank = ScreenChar {
130             ascii_character: b' ',
131             color_code: self.color_code,
132         };
133
134         for col in 0..BUFFER_WIDTH {
135             self.buffer.chars[row][col].write(blank);
136         }
137     }
138 }
139
140 lazy_static! {
141     pub static ref WRITER: Mutex<Writer> = Mutex::new(Writer {
142         row_position: 1,
143         column_position: 0,
144         color_code: ColorCode::new(Color::LightGray, Color::Black),
145         buffer: unsafe { &mut *(0xb8000 as *mut Buffer) },
146     });
147 }