···3434 panic!("DrawTarget implemented for RGB888, but bpp doesn't match RGB888");
3535 }
3636 }
3737+3838+ /// Moves everythying on the screen up, leaving the bottom the same as it was before
3939+ pub fn shift_up(&mut self, amount: usize) {
4040+ self.buffer.copy_within(amount * self.pixel_pitch.., 0);
4141+ }
3742}
38433944impl Dimensions for FrameBufferEmbeddedGraphics<'_> {
+200
kernel/src/logger.rs
···11+use log::{Level, LevelFilter, Log};
22+use uart_16550::SerialPort;
33+use core::fmt::{Display, Write};
44+use unicode_segmentation::UnicodeSegmentation;
55+use crate::frame_buffer_embedded_graphics::FrameBufferEmbeddedGraphics;
66+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}};
77+use limine::response::FramebufferResponse;
88+99+struct KernelLogger {
1010+ inner: spin::Mutex<Inner>
1111+}
1212+1313+impl Log for KernelLogger {
1414+ fn enabled(&self, _metadata: &log::Metadata) -> bool {
1515+ true
1616+ }
1717+1818+ fn log(&self, record: &log::Record) {
1919+ let mut inner = self.inner.try_lock().unwrap();
2020+ let level = record.level();
2121+2222+ inner.write_with_color(
2323+ match level {
2424+ Level::Error => Color::BrightRed,
2525+ Level::Warn => Color::BrightYellow,
2626+ Level::Info => Color::BrightBlue,
2727+ Level::Debug => Color::BrightCyan,
2828+ Level::Trace => Color::BrightMagenta
2929+ },
3030+ format_args!("{level:5} "),
3131+ );
3232+3333+ inner.write_with_color(Color::Default, record.args());
3434+ inner.write_with_color(Color::Default, "\n");
3535+ }
3636+3737+ fn flush(&self) {
3838+ todo!()
3939+ }
4040+}
4141+4242+struct Inner {
4343+ serial_port: SerialPort,
4444+ display: Option<DisplayData>
4545+}
4646+4747+/// Represents a color in a terminal or screen. The default color may depend on if the theme is light or dark.
4848+enum Color {
4949+ Default,
5050+ BrightRed,
5151+ BrightYellow,
5252+ BrightBlue,
5353+ BrightCyan,
5454+ BrightMagenta
5555+}
5656+5757+impl Inner {
5858+ fn write_with_color(&mut self, color: Color, string: impl Display) {
5959+ // Write to screen
6060+ if let Some(display_data) = &mut self.display {
6161+ let mut writer = Writer {
6262+ display: &mut display_data.display,
6363+ position: &mut display_data.position,
6464+ text_color: match color {
6565+ Color::Default => Rgb888::WHITE,
6666+ // Mimick the ANSI escape colors
6767+ Color::BrightRed => Rgb888::new(255, 8, 85),
6868+ Color::BrightYellow => Rgb888::new(255, 255, 85),
6969+ Color::BrightBlue => Rgb888::new(85, 85, 255),
7070+ Color::BrightCyan => Rgb888::new(85, 255, 255),
7171+ Color::BrightMagenta => Rgb888::new(255, 85, 255)
7272+ }
7373+ };
7474+7575+ write!(writer, "{}", string).unwrap();
7676+ }
7777+ }
7878+}
7979+8080+/// A writer that writes to a writer, replacing `\n` with `\r\n`
8181+pub struct WriterWithCr<T> {
8282+ writer: T
8383+}
8484+8585+impl<T> WriterWithCr<T> {
8686+ pub const fn new(writer: T) -> Self {
8787+ Self { writer }
8888+ }
8989+}
9090+9191+impl<T: Write> Write for WriterWithCr<T> {
9292+ fn write_str(&mut self, s: &str) -> core::fmt::Result {
9393+ for c in s.graphemes(true) {
9494+ match c {
9595+ "\n" => self.writer.write_str("\r\n")?,
9696+ s => self.writer.write_str(s)?,
9797+ }
9898+ }
9999+100100+ Ok(())
101101+ }
102102+}
103103+104104+struct DisplayData {
105105+ display: FrameBufferEmbeddedGraphics<'static>,
106106+ position: Point
107107+}
108108+109109+struct Writer<'a> {
110110+ display: &'a mut FrameBufferEmbeddedGraphics<'static>,
111111+ position: &'a mut Point,
112112+ text_color: <FrameBufferEmbeddedGraphics<'a> as DrawTarget>::Color
113113+}
114114+115115+impl Write for Writer<'_> {
116116+ fn write_str(&mut self, s: &str) -> core::fmt::Result {
117117+ let font = FONT_10X20;
118118+ let background_color = Rgb888::BLACK;
119119+120120+ for c in s.graphemes(true) {
121121+ let height_not_seen = self.position.y + font.character_size.height as i32 - self.display.bounding_box().size.height as i32;
122122+123123+ if height_not_seen > 0 {
124124+ self.display.shift_up(height_not_seen as usize);
125125+ self.position.y -= height_not_seen;
126126+ }
127127+128128+ match c {
129129+ "\r" => {
130130+ // We do not handle special cursor movements
131131+ },
132132+ "\n" | "\r\n" => {
133133+ // Fill the remaining space with background color
134134+ Rectangle::new(
135135+ *self.position,
136136+ Size::new(
137137+ self.display.bounding_box().size.width - self.position.x as u32,
138138+ font.character_size.height,
139139+ ),
140140+ )
141141+ .into_styled(
142142+ PrimitiveStyleBuilder::new()
143143+ .fill_color(background_color)
144144+ .build(),
145145+ )
146146+ .draw(self.display)
147147+ .map_err(|_| core::fmt::Error)?;
148148+149149+ self.position.y += font.character_size.height as i32;
150150+ self.position.x = 0;
151151+ },
152152+ c => {
153153+ let style = MonoTextStyleBuilder::new()
154154+ .font(&font)
155155+ .text_color(self.text_color)
156156+ .background_color(background_color)
157157+ .build();
158158+159159+ *self.position = Text::with_baseline(c, *self.position, style, Baseline::Top)
160160+ .draw(self.display)
161161+ .map_err(|_| core::fmt::Error)?;
162162+163163+ if self.position.x as u32 + font.character_size.width > self.display.bounding_box().size.width {
164164+ self.position.y += font.character_size.height as i32;
165165+ self.position.x = 0;
166166+ }
167167+ }
168168+ }
169169+ }
170170+171171+ Ok(())
172172+ }
173173+}
174174+175175+static LOGGER: KernelLogger = KernelLogger {
176176+ inner: spin::Mutex::new(Inner {
177177+ serial_port: unsafe { SerialPort::new(0x3F8) },
178178+ display: None
179179+ })
180180+};
181181+182182+pub fn init(frame_buffer: &'static FramebufferResponse) -> Result<(), log::SetLoggerError> {
183183+ let mut inner = LOGGER.inner.try_lock().unwrap();
184184+ inner.serial_port.init();
185185+186186+ inner.display = frame_buffer
187187+ .framebuffers()
188188+ .next()
189189+ .map(|frame_buffer| DisplayData {
190190+ display: {
191191+ let addr = frame_buffer.addr().addr().try_into().unwrap();
192192+ let info = (&frame_buffer).into();
193193+ unsafe { FrameBufferEmbeddedGraphics::new(addr, info) }
194194+ },
195195+ position: Point::zero()
196196+ });
197197+198198+ log::set_max_level(LevelFilter::max());
199199+ log::set_logger(&LOGGER)
200200+}