kernel/io/console/
vga_text.rs1use crate::{memory_management::virtual_space::VirtualSpace, multiboot2};
5
6use super::{VideoConsole, VideoConsoleAttribute};
7
8const DEFAULT_ATTRIB: u8 = 0x0f;
10
11pub(super) struct VgaText {
12 pos: (usize, usize),
13 attrib: u8,
14 pitch: usize,
15 height: usize,
16 width: usize,
17 memory: VirtualSpace<[u8]>,
18}
19
20impl VgaText {
21 pub fn new(framebuffer: multiboot2::Framebuffer) -> Self {
22 assert!(matches!(
23 framebuffer.color_info,
24 multiboot2::FramebufferColorInfo::EgaText
25 ));
26 let physical_addr = framebuffer.addr;
27 let memory_size = framebuffer.pitch * framebuffer.height;
28 let memory =
29 unsafe { VirtualSpace::new_slice(physical_addr, memory_size as usize).unwrap() };
30
31 Self {
32 pos: (0, 0),
33 attrib: DEFAULT_ATTRIB,
34 pitch: framebuffer.pitch as usize,
35 height: framebuffer.height as usize,
36 width: framebuffer.width as usize,
37 memory,
38 }
39 }
40
41 fn get_arr_pos(&self, pos: (usize, usize)) -> usize {
42 pos.0 * 2 + pos.1 * self.pitch
43 }
44
45 fn fix_after_advance(&mut self) {
46 if self.pos.0 >= self.width {
47 self.pos.0 = 0;
48 self.pos.1 += 1;
49 }
50 if self.pos.1 >= self.height {
51 for i in 0..self.height - 1 {
53 let copy_to = self.get_arr_pos((0, i));
54 let copy_from = self.get_arr_pos((0, i + 1));
55 let size = self.pitch;
56 let (before, after) = self.memory.split_at_mut(copy_from);
57
58 before[copy_to..copy_to + size].copy_from_slice(&after[..size]);
59 }
60
61 self.pos.1 -= 1;
62 self.clear_line(self.pos.1);
63 self.fix_after_advance();
65 }
66 }
67
68 #[allow(dead_code)]
69 fn clear(&mut self) {
70 for i in 0..self.height {
71 self.clear_line(i);
72 }
73 self.pos = (0, 0);
74 }
75
76 fn clear_line(&mut self, line: usize) {
77 for i in 0..self.width {
78 let pos = self.get_arr_pos((i, line));
79
80 self.memory[pos] = b' ';
81 self.memory[pos + 1] = 0x0;
82 }
83 }
84}
85
86impl VideoConsole for VgaText {
87 fn init(&mut self) {
88 self.clear();
89 }
90
91 fn set_attrib(&mut self, attrib: VideoConsoleAttribute) {
92 let to_vga_color = |color: u8| {
93 let mappings = &[
94 0, 4, 2, 6, 1, 5, 3, 7, 8, 12, 10, 14, 9, 13, 11, 15, ];
111 mappings[color as usize]
112 };
113
114 let mut fg_index = attrib.foreground as u8;
115 if attrib.faint && fg_index >= 8 {
116 fg_index -= 8;
117 }
118 if attrib.bold && fg_index < 8 {
119 fg_index += 8;
120 }
121
122 let fg = to_vga_color(fg_index);
123 let bg = to_vga_color(attrib.background as u8);
124 self.attrib = (bg << 4) | fg;
125 }
126
127 fn write_byte(&mut self, c: u8) {
128 if c == b'\n' {
129 self.pos.0 = 0;
130 self.pos.1 += 1;
131 self.fix_after_advance();
132 return;
133 }
134 let i = self.get_arr_pos(self.pos);
135 self.memory[i] = c;
136 self.memory[i + 1] = self.attrib;
137 self.pos.0 += 1;
138 self.fix_after_advance();
139 }
140
141 fn backspace(&mut self) {
142 if self.pos.0 == 0 {
143 if self.pos.1 == 0 {
144 return;
145 }
146 self.pos.0 = self.width - 1;
147 self.pos.1 -= 1;
148 } else {
149 self.pos.0 -= 1;
150 }
151 let i = self.get_arr_pos(self.pos);
152 self.memory[i] = b' ';
153 self.memory[i + 1] = self.attrib;
154 }
155}