A repository for a long-term OS project titled DasOS (named after the Greek for "forest")

Added logging

+217 -15
+5 -1
kernel/Cargo.toml
··· 9 9 x86_64 = "0.15.2" 10 10 uart_16550 = "0.3.2" 11 11 embedded-graphics = "0.8.1" 12 + log = "0.4.27" 13 + spin = "0.10.0" 14 + owo-colors = "4.2.1" 15 + unicode-segmentation = "1.12.0" 12 16 13 17 [[bin]] 14 18 name = "kernel" 15 19 test = false 16 - bench = false 20 + bench = false
+5
kernel/src/frame_buffer_embedded_graphics.rs
··· 34 34 panic!("DrawTarget implemented for RGB888, but bpp doesn't match RGB888"); 35 35 } 36 36 } 37 + 38 + /// Moves everythying on the screen up, leaving the bottom the same as it was before 39 + pub fn shift_up(&mut self, amount: usize) { 40 + self.buffer.copy_within(amount * self.pixel_pitch.., 0); 41 + } 37 42 } 38 43 39 44 impl Dimensions for FrameBufferEmbeddedGraphics<'_> {
+200
kernel/src/logger.rs
··· 1 + use log::{Level, LevelFilter, Log}; 2 + use uart_16550::SerialPort; 3 + use core::fmt::{Display, Write}; 4 + use unicode_segmentation::UnicodeSegmentation; 5 + use crate::frame_buffer_embedded_graphics::FrameBufferEmbeddedGraphics; 6 + use embedded_graphics::{Drawable, geometry::Dimensions, mono_font::{MonoTextStyleBuilder, iso_8859_16::FONT_10X20}, pixelcolor::Rgb888, prelude::{DrawTarget, Point, Primitive, RgbColor, Size}, primitives::{PrimitiveStyleBuilder, Rectangle}, text::{Baseline, Text}}; 7 + use limine::response::FramebufferResponse; 8 + 9 + struct KernelLogger { 10 + inner: spin::Mutex<Inner> 11 + } 12 + 13 + impl Log for KernelLogger { 14 + fn enabled(&self, _metadata: &log::Metadata) -> bool { 15 + true 16 + } 17 + 18 + fn log(&self, record: &log::Record) { 19 + let mut inner = self.inner.try_lock().unwrap(); 20 + let level = record.level(); 21 + 22 + inner.write_with_color( 23 + match level { 24 + Level::Error => Color::BrightRed, 25 + Level::Warn => Color::BrightYellow, 26 + Level::Info => Color::BrightBlue, 27 + Level::Debug => Color::BrightCyan, 28 + Level::Trace => Color::BrightMagenta 29 + }, 30 + format_args!("{level:5} "), 31 + ); 32 + 33 + inner.write_with_color(Color::Default, record.args()); 34 + inner.write_with_color(Color::Default, "\n"); 35 + } 36 + 37 + fn flush(&self) { 38 + todo!() 39 + } 40 + } 41 + 42 + struct Inner { 43 + serial_port: SerialPort, 44 + display: Option<DisplayData> 45 + } 46 + 47 + /// Represents a color in a terminal or screen. The default color may depend on if the theme is light or dark. 48 + enum Color { 49 + Default, 50 + BrightRed, 51 + BrightYellow, 52 + BrightBlue, 53 + BrightCyan, 54 + BrightMagenta 55 + } 56 + 57 + impl Inner { 58 + fn write_with_color(&mut self, color: Color, string: impl Display) { 59 + // Write to screen 60 + if let Some(display_data) = &mut self.display { 61 + let mut writer = Writer { 62 + display: &mut display_data.display, 63 + position: &mut display_data.position, 64 + text_color: match color { 65 + Color::Default => Rgb888::WHITE, 66 + // Mimick the ANSI escape colors 67 + Color::BrightRed => Rgb888::new(255, 8, 85), 68 + Color::BrightYellow => Rgb888::new(255, 255, 85), 69 + Color::BrightBlue => Rgb888::new(85, 85, 255), 70 + Color::BrightCyan => Rgb888::new(85, 255, 255), 71 + Color::BrightMagenta => Rgb888::new(255, 85, 255) 72 + } 73 + }; 74 + 75 + write!(writer, "{}", string).unwrap(); 76 + } 77 + } 78 + } 79 + 80 + /// A writer that writes to a writer, replacing `\n` with `\r\n` 81 + pub struct WriterWithCr<T> { 82 + writer: T 83 + } 84 + 85 + impl<T> WriterWithCr<T> { 86 + pub const fn new(writer: T) -> Self { 87 + Self { writer } 88 + } 89 + } 90 + 91 + impl<T: Write> Write for WriterWithCr<T> { 92 + fn write_str(&mut self, s: &str) -> core::fmt::Result { 93 + for c in s.graphemes(true) { 94 + match c { 95 + "\n" => self.writer.write_str("\r\n")?, 96 + s => self.writer.write_str(s)?, 97 + } 98 + } 99 + 100 + Ok(()) 101 + } 102 + } 103 + 104 + struct DisplayData { 105 + display: FrameBufferEmbeddedGraphics<'static>, 106 + position: Point 107 + } 108 + 109 + struct Writer<'a> { 110 + display: &'a mut FrameBufferEmbeddedGraphics<'static>, 111 + position: &'a mut Point, 112 + text_color: <FrameBufferEmbeddedGraphics<'a> as DrawTarget>::Color 113 + } 114 + 115 + impl Write for Writer<'_> { 116 + fn write_str(&mut self, s: &str) -> core::fmt::Result { 117 + let font = FONT_10X20; 118 + let background_color = Rgb888::BLACK; 119 + 120 + for c in s.graphemes(true) { 121 + let height_not_seen = self.position.y + font.character_size.height as i32 - self.display.bounding_box().size.height as i32; 122 + 123 + if height_not_seen > 0 { 124 + self.display.shift_up(height_not_seen as usize); 125 + self.position.y -= height_not_seen; 126 + } 127 + 128 + match c { 129 + "\r" => { 130 + // We do not handle special cursor movements 131 + }, 132 + "\n" | "\r\n" => { 133 + // Fill the remaining space with background color 134 + Rectangle::new( 135 + *self.position, 136 + Size::new( 137 + self.display.bounding_box().size.width - self.position.x as u32, 138 + font.character_size.height, 139 + ), 140 + ) 141 + .into_styled( 142 + PrimitiveStyleBuilder::new() 143 + .fill_color(background_color) 144 + .build(), 145 + ) 146 + .draw(self.display) 147 + .map_err(|_| core::fmt::Error)?; 148 + 149 + self.position.y += font.character_size.height as i32; 150 + self.position.x = 0; 151 + }, 152 + c => { 153 + let style = MonoTextStyleBuilder::new() 154 + .font(&font) 155 + .text_color(self.text_color) 156 + .background_color(background_color) 157 + .build(); 158 + 159 + *self.position = Text::with_baseline(c, *self.position, style, Baseline::Top) 160 + .draw(self.display) 161 + .map_err(|_| core::fmt::Error)?; 162 + 163 + if self.position.x as u32 + font.character_size.width > self.display.bounding_box().size.width { 164 + self.position.y += font.character_size.height as i32; 165 + self.position.x = 0; 166 + } 167 + } 168 + } 169 + } 170 + 171 + Ok(()) 172 + } 173 + } 174 + 175 + static LOGGER: KernelLogger = KernelLogger { 176 + inner: spin::Mutex::new(Inner { 177 + serial_port: unsafe { SerialPort::new(0x3F8) }, 178 + display: None 179 + }) 180 + }; 181 + 182 + pub fn init(frame_buffer: &'static FramebufferResponse) -> Result<(), log::SetLoggerError> { 183 + let mut inner = LOGGER.inner.try_lock().unwrap(); 184 + inner.serial_port.init(); 185 + 186 + inner.display = frame_buffer 187 + .framebuffers() 188 + .next() 189 + .map(|frame_buffer| DisplayData { 190 + display: { 191 + let addr = frame_buffer.addr().addr().try_into().unwrap(); 192 + let info = (&frame_buffer).into(); 193 + unsafe { FrameBufferEmbeddedGraphics::new(addr, info) } 194 + }, 195 + position: Point::zero() 196 + }); 197 + 198 + log::set_max_level(LevelFilter::max()); 199 + log::set_logger(&LOGGER) 200 + }
+7 -14
kernel/src/main.rs
··· 5 5 mod rgb_pixel_info; 6 6 mod frame_buffer_info; 7 7 mod frame_buffer_embedded_graphics; 8 + mod logger; 8 9 9 10 use uart_16550::SerialPort; 10 11 use core::fmt::Write; 11 - use crate::{limine_requests::{BASE_REVISION, FRAME_BUFFER_REQUEST}, frame_buffer_embedded_graphics::FrameBufferEmbeddedGraphics}; 12 - use embedded_graphics::{draw_target::DrawTarget, geometry::Dimensions, prelude::RgbColor}; 12 + use crate::limine_requests::{BASE_REVISION, FRAME_BUFFER_REQUEST}; 13 13 14 14 #[unsafe(no_mangle)] 15 15 unsafe extern "C" fn entry_point_from_limine() -> ! { ··· 22 22 writeln!(serial_port, "Hello World!\r").unwrap(); 23 23 24 24 let frame_buffer = FRAME_BUFFER_REQUEST.get_response().unwrap(); 25 - 26 - if let Some(frame_buffer) = frame_buffer.framebuffers().next() { 27 - let mut frame_buffer = { 28 - let addr = frame_buffer.addr().addr().try_into().unwrap(); 29 - let info = (&frame_buffer).into(); 30 - unsafe { FrameBufferEmbeddedGraphics::new(addr, info) } 31 - }; 32 - 33 - frame_buffer.fill_solid(&frame_buffer.bounding_box(), RgbColor::MAGENTA); 34 - } 35 - 25 + logger::init(frame_buffer).unwrap(); 26 + log::info!("Hello World!"); 27 + 36 28 hlt_loop(); 37 29 } 38 30 ··· 43 35 } 44 36 45 37 #[panic_handler] 46 - fn rust_panic(_info: &core::panic::PanicInfo) -> ! { 38 + fn rust_panic(info: &core::panic::PanicInfo) -> ! { 39 + log::error!("{info}"); 47 40 hlt_loop(); 48 41 }