1use alloc::{boxed::Box, format, string::String, vec, vec::Vec};
8
9use spin::Mutex;
10
11use crate::{
12 error::KernelError,
13 services::driver_framework::{DeviceClass, DeviceInfo, Driver},
14 sync::once_lock::OnceLock,
15};
16
17#[repr(u8)]
19pub enum ConsoleColor {
20 Black = 0,
21 Blue = 1,
22 Green = 2,
23 Cyan = 3,
24 Red = 4,
25 Magenta = 5,
26 Brown = 6,
27 LightGray = 7,
28 DarkGray = 8,
29 LightBlue = 9,
30 LightGreen = 10,
31 LightCyan = 11,
32 LightRed = 12,
33 Pink = 13,
34 Yellow = 14,
35 White = 15,
36}
37
38#[derive(Debug, Clone, Copy)]
40#[repr(C)]
41pub struct ConsoleChar {
42 pub ascii: u8,
43 pub color: u8,
44}
45
46impl ConsoleChar {
47 pub fn new(ascii: u8, foreground: ConsoleColor, background: ConsoleColor) -> Self {
48 Self {
49 ascii,
50 color: ((background as u8) << 4) | (foreground as u8),
51 }
52 }
53}
54
55pub trait ConsoleDevice: Send + Sync {
57 fn name(&self) -> &str;
59
60 fn dimensions(&self) -> (usize, usize); fn clear(&mut self) -> Result<(), KernelError>;
65
66 fn write_char(&mut self, x: usize, y: usize, ch: ConsoleChar) -> Result<(), KernelError>;
68
69 fn write_string(&mut self, x: usize, y: usize, s: &str, color: u8) -> Result<(), KernelError>;
71
72 fn scroll_up(&mut self) -> Result<(), KernelError>;
74
75 fn set_cursor(&mut self, x: usize, y: usize) -> Result<(), KernelError>;
77
78 fn get_cursor(&self) -> (usize, usize);
80
81 fn set_cursor_visible(&mut self, visible: bool) -> Result<(), KernelError>;
83}
84
85pub struct VgaConsole {
87 buffer: *mut ConsoleChar,
88 width: usize,
89 height: usize,
90 cursor_x: usize,
91 cursor_y: usize,
92 cursor_visible: bool,
93 #[allow(dead_code)] default_color: u8,
95}
96
97unsafe impl Send for VgaConsole {}
100
101unsafe impl Sync for VgaConsole {}
104
105impl Default for VgaConsole {
106 fn default() -> Self {
107 Self::new()
108 }
109}
110
111impl VgaConsole {
112 pub fn new() -> Self {
114 Self {
115 buffer: 0xB8000 as *mut ConsoleChar,
116 width: 80,
117 height: 25,
118 cursor_x: 0,
119 cursor_y: 0,
120 cursor_visible: true,
121 default_color: ((ConsoleColor::Black as u8) << 4) | (ConsoleColor::LightGray as u8),
122 }
123 }
124
125 fn buffer_index(&self, x: usize, y: usize) -> usize {
127 y * self.width + x
128 }
129
130 fn update_cursor(&self) {
132 let pos = self.cursor_y * self.width + self.cursor_x;
133
134 unsafe {
138 crate::arch::outb(0x3D4, 0x0F);
140 crate::arch::outb(0x3D5, (pos & 0xFF) as u8);
141
142 crate::arch::outb(0x3D4, 0x0E);
144 crate::arch::outb(0x3D5, ((pos >> 8) & 0xFF) as u8);
145 }
146 }
147}
148
149impl ConsoleDevice for VgaConsole {
150 fn name(&self) -> &str {
151 "vga"
152 }
153
154 fn dimensions(&self) -> (usize, usize) {
155 (self.width, self.height)
156 }
157
158 fn clear(&mut self) -> Result<(), KernelError> {
159 let blank = ConsoleChar::new(b' ', ConsoleColor::LightGray, ConsoleColor::Black);
160
161 unsafe {
165 for i in 0..(self.width * self.height) {
166 *self.buffer.add(i) = blank;
167 }
168 }
169
170 self.cursor_x = 0;
171 self.cursor_y = 0;
172 self.update_cursor();
173
174 Ok(())
175 }
176
177 fn write_char(&mut self, x: usize, y: usize, ch: ConsoleChar) -> Result<(), KernelError> {
178 if x >= self.width || y >= self.height {
179 return Err(KernelError::InvalidArgument {
180 name: "position",
181 value: "out of bounds",
182 });
183 }
184
185 let index = self.buffer_index(x, y);
186 unsafe {
189 *self.buffer.add(index) = ch;
190 }
191
192 Ok(())
193 }
194
195 fn write_string(&mut self, x: usize, y: usize, s: &str, color: u8) -> Result<(), KernelError> {
196 let mut pos_x = x;
197 let pos_y = y;
198
199 if pos_y >= self.height {
200 return Err(KernelError::InvalidArgument {
201 name: "y_position",
202 value: "out of bounds",
203 });
204 }
205
206 for byte in s.bytes() {
207 if pos_x >= self.width {
208 break; }
210
211 let ch = ConsoleChar { ascii: byte, color };
212 self.write_char(pos_x, pos_y, ch)?;
213 pos_x += 1;
214 }
215
216 Ok(())
217 }
218
219 fn scroll_up(&mut self) -> Result<(), KernelError> {
220 unsafe {
225 for y in 1..self.height {
227 for x in 0..self.width {
228 let src_index = self.buffer_index(x, y);
229 let dst_index = self.buffer_index(x, y - 1);
230 *self.buffer.add(dst_index) = *self.buffer.add(src_index);
231 }
232 }
233
234 let blank = ConsoleChar::new(b' ', ConsoleColor::LightGray, ConsoleColor::Black);
236 for x in 0..self.width {
237 let index = self.buffer_index(x, self.height - 1);
238 *self.buffer.add(index) = blank;
239 }
240 }
241
242 Ok(())
243 }
244
245 fn set_cursor(&mut self, x: usize, y: usize) -> Result<(), KernelError> {
246 if x >= self.width || y >= self.height {
247 return Err(KernelError::InvalidArgument {
248 name: "cursor_position",
249 value: "out of bounds",
250 });
251 }
252
253 self.cursor_x = x;
254 self.cursor_y = y;
255 self.update_cursor();
256
257 Ok(())
258 }
259
260 fn get_cursor(&self) -> (usize, usize) {
261 (self.cursor_x, self.cursor_y)
262 }
263
264 fn set_cursor_visible(&mut self, visible: bool) -> Result<(), KernelError> {
265 self.cursor_visible = visible;
266
267 unsafe {
270 crate::arch::outb(0x3D4, 0x0A);
272 if visible {
273 crate::arch::outb(0x3D5, 0x0E); } else {
275 crate::arch::outb(0x3D5, 0x20); }
277 }
278
279 Ok(())
280 }
281}
282
283pub struct SerialConsole {
285 port: u16,
286 name: String,
287 cursor_x: usize,
288 cursor_y: usize,
289 width: usize,
290 height: usize,
291}
292
293impl SerialConsole {
294 pub fn new(port: u16) -> Self {
296 let mut console = Self {
297 port,
298 name: format!(
299 "serial{}",
300 match port {
301 0x3F8 => 0, 0x2F8 => 1, 0x3E8 => 2, 0x2E8 => 3, _ => 9,
306 }
307 ),
308 cursor_x: 0,
309 cursor_y: 0,
310 width: 80,
311 height: 25,
312 };
313
314 console.init();
315 console
316 }
317
318 fn init(&mut self) {
320 unsafe {
325 crate::arch::outb(self.port + 1, 0x00);
327
328 crate::arch::outb(self.port + 3, 0x80);
330
331 crate::arch::outb(self.port, 0x03);
333 crate::arch::outb(self.port + 1, 0x00);
334
335 crate::arch::outb(self.port + 3, 0x03);
337
338 crate::arch::outb(self.port + 2, 0xC7);
340
341 crate::arch::outb(self.port + 4, 0x0B);
343 }
344 }
345
346 fn write_byte(&self, byte: u8) {
348 unsafe {
352 while (crate::arch::inb(self.port + 5) & 0x20) == 0 {
354 core::hint::spin_loop();
355 }
356
357 crate::arch::outb(self.port, byte);
358 }
359 }
360
361 #[allow(dead_code)] fn read_byte(&self) -> Option<u8> {
364 unsafe {
367 if (crate::arch::inb(self.port + 5) & 0x01) != 0 {
368 Some(crate::arch::inb(self.port))
369 } else {
370 None
371 }
372 }
373 }
374
375 fn write_str(&self, s: &str) {
377 for byte in s.bytes() {
378 if byte == b'\n' {
379 self.write_byte(b'\r'); }
381 self.write_byte(byte);
382 }
383 }
384}
385
386impl ConsoleDevice for SerialConsole {
387 fn name(&self) -> &str {
388 &self.name
389 }
390
391 fn dimensions(&self) -> (usize, usize) {
392 (self.width, self.height)
393 }
394
395 fn clear(&mut self) -> Result<(), KernelError> {
396 self.write_str("\x1b[2J\x1b[H");
398 self.cursor_x = 0;
399 self.cursor_y = 0;
400 Ok(())
401 }
402
403 fn write_char(&mut self, x: usize, y: usize, ch: ConsoleChar) -> Result<(), KernelError> {
404 self.write_str(&alloc::format!(
406 "\x1b[{};{}H{}",
407 y + 1,
408 x + 1,
409 ch.ascii as char
410 ));
411 Ok(())
412 }
413
414 fn write_string(&mut self, x: usize, y: usize, s: &str, _color: u8) -> Result<(), KernelError> {
415 self.write_str(&alloc::format!("\x1b[{};{}H{}", y + 1, x + 1, s));
417 Ok(())
418 }
419
420 fn scroll_up(&mut self) -> Result<(), KernelError> {
421 self.write_str("\x1b[S");
423 Ok(())
424 }
425
426 fn set_cursor(&mut self, x: usize, y: usize) -> Result<(), KernelError> {
427 if x >= self.width || y >= self.height {
428 return Err(KernelError::InvalidArgument {
429 name: "cursor_position",
430 value: "out of bounds",
431 });
432 }
433
434 self.cursor_x = x;
435 self.cursor_y = y;
436
437 self.write_str(&alloc::format!("\x1b[{};{}H", y + 1, x + 1));
439 Ok(())
440 }
441
442 fn get_cursor(&self) -> (usize, usize) {
443 (self.cursor_x, self.cursor_y)
444 }
445
446 fn set_cursor_visible(&mut self, visible: bool) -> Result<(), KernelError> {
447 if visible {
448 self.write_str("\x1b[?25h"); } else {
450 self.write_str("\x1b[?25l"); }
452 Ok(())
453 }
454}
455
456pub struct ConsoleDriver {
458 devices: Vec<Box<dyn ConsoleDevice>>,
459 active_device: usize,
460 name: String,
461}
462
463impl Default for ConsoleDriver {
464 fn default() -> Self {
465 Self::new()
466 }
467}
468
469impl ConsoleDriver {
470 pub fn new() -> Self {
472 Self {
473 devices: Vec::new(),
474 active_device: 0,
475 name: String::from("console"),
476 }
477 }
478
479 pub fn add_device(&mut self, device: Box<dyn ConsoleDevice>) {
481 crate::println!("[CONSOLE] Added console device: {}", device.name());
482 self.devices.push(device);
483 }
484
485 pub fn set_active_device(&mut self, index: usize) -> Result<(), KernelError> {
487 if index >= self.devices.len() {
488 return Err(KernelError::InvalidArgument {
489 name: "device_index",
490 value: "out of range",
491 });
492 }
493
494 self.active_device = index;
495 crate::println!(
496 "[CONSOLE] Switched to console device: {}",
497 self.devices[index].name()
498 );
499 Ok(())
500 }
501
502 pub fn get_active_device(&mut self) -> Option<&mut dyn ConsoleDevice> {
504 match self.devices.get_mut(self.active_device) {
505 Some(device) => Some(device.as_mut()),
506 None => None,
507 }
508 }
509
510 pub fn write_to_all(&mut self, s: &str) {
512 for device in &mut self.devices {
513 let (x, y) = device.get_cursor();
514 device.write_string(x, y, s, 0x07).ok(); }
516 }
517}
518
519impl Driver for ConsoleDriver {
520 fn name(&self) -> &str {
521 &self.name
522 }
523
524 fn supported_classes(&self) -> Vec<DeviceClass> {
525 vec![DeviceClass::Display, DeviceClass::Serial]
526 }
527
528 fn supports_device(&self, device: &DeviceInfo) -> bool {
529 matches!(device.class, DeviceClass::Display | DeviceClass::Serial)
530 }
531
532 fn probe(&mut self, _device: &DeviceInfo) -> Result<(), KernelError> {
533 crate::println!("[CONSOLE] Probing device: {}", _device.name);
534 Ok(())
535 }
536
537 fn attach(&mut self, device: &DeviceInfo) -> Result<(), KernelError> {
538 crate::println!("[CONSOLE] Attaching to device: {}", device.name);
539
540 match device.class {
541 DeviceClass::Display => {
542 let vga_console = VgaConsole::new();
544 self.add_device(Box::new(vga_console));
545 }
546 DeviceClass::Serial => {
547 let serial_console = SerialConsole::new(0x3F8);
549 self.add_device(Box::new(serial_console));
550 }
551 _ => {
552 return Err(KernelError::OperationNotSupported {
553 operation: "attach unsupported device class",
554 })
555 }
556 }
557
558 Ok(())
559 }
560
561 fn detach(&mut self, _device: &DeviceInfo) -> Result<(), KernelError> {
562 crate::println!("[CONSOLE] Detaching from device: {}", _device.name);
563
564 let device_name = match _device.class {
566 DeviceClass::Display => "vga",
567 DeviceClass::Serial => "serial0",
568 _ => "",
569 };
570
571 if let Some(pos) = self.devices.iter().position(|d| d.name() == device_name) {
572 self.devices.remove(pos);
573 if self.active_device >= self.devices.len() && !self.devices.is_empty() {
575 self.active_device = self.devices.len() - 1;
576 }
577 crate::println!("[CONSOLE] Removed console device: {}", device_name);
578 Ok(())
579 } else {
580 Err(KernelError::NotFound {
581 resource: "console_device",
582 id: 0,
583 })
584 }
585 }
586
587 fn suspend(&mut self) -> Result<(), KernelError> {
588 crate::println!("[CONSOLE] Suspending console driver");
589 Ok(())
590 }
591
592 fn resume(&mut self) -> Result<(), KernelError> {
593 crate::println!("[CONSOLE] Resuming console driver");
594 Ok(())
595 }
596
597 fn handle_interrupt(&mut self, _irq: u8) -> Result<(), KernelError> {
598 crate::println!("[CONSOLE] Handling interrupt {} for console", _irq);
599 Ok(())
600 }
601
602 fn read(&mut self, _offset: u64, _buffer: &mut [u8]) -> Result<usize, KernelError> {
603 let mut bytes_read = 0usize;
608
609 for slot in _buffer.iter_mut() {
610 match crate::drivers::keyboard::read_key() {
611 Some(byte) => {
612 *slot = byte;
613 bytes_read += 1;
614 }
615 None => break,
616 }
617 }
618
619 Ok(bytes_read)
620 }
621
622 fn write(&mut self, _offset: u64, data: &[u8]) -> Result<usize, KernelError> {
623 if let Ok(s) = core::str::from_utf8(data) {
624 self.write_to_all(s);
625 Ok(data.len())
626 } else {
627 Err(KernelError::InvalidArgument {
628 name: "data",
629 value: "invalid UTF-8",
630 })
631 }
632 }
633
634 fn ioctl(&mut self, cmd: u32, arg: u64) -> Result<u64, KernelError> {
635 match cmd {
636 0x2000 => {
637 Ok(self.active_device as u64)
639 }
640 0x2001 => {
641 self.set_active_device(arg as usize)?;
643 Ok(0)
644 }
645 0x2002 => {
646 Ok(self.devices.len() as u64)
648 }
649 0x2003 => {
650 if let Some(device) = self.get_active_device() {
652 device.clear()?;
653 }
654 Ok(0)
655 }
656 _ => Err(KernelError::InvalidArgument {
657 name: "ioctl_cmd",
658 value: "unknown",
659 }),
660 }
661 }
662}
663
664static CONSOLE_DRIVER: OnceLock<Mutex<ConsoleDriver>> = OnceLock::new();
666
667pub fn init() {
669 let mut console_driver = ConsoleDriver::new();
670
671 let vga_console = VgaConsole::new();
673 console_driver.add_device(Box::new(vga_console));
674
675 let serial_console = SerialConsole::new(0x3F8);
677 console_driver.add_device(Box::new(serial_console));
678
679 if let Some(device) = console_driver.get_active_device() {
681 device.clear().ok();
682 device.set_cursor_visible(true).ok();
683 }
684
685 let _ = CONSOLE_DRIVER.set(Mutex::new(console_driver));
686
687 let driver_framework = crate::services::driver_framework::get_driver_framework();
689 let console_instance = ConsoleDriver::new();
690
691 if let Err(_e) = driver_framework.register_driver(Box::new(console_instance)) {
692 crate::println!("[CONSOLE] Failed to register console driver: {}", _e);
693 } else {
694 crate::println!("[CONSOLE] Console subsystem initialized");
695 }
696}
697
698pub fn get_console_driver() -> &'static Mutex<ConsoleDriver> {
700 CONSOLE_DRIVER
701 .get()
702 .expect("Console driver not initialized")
703}