Something went wrong. Try again.
A custom OS written in Zig
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212use either::Either;use embedded_graphics::{Drawable, draw_target::DrawTarget, geometry::{Dimensions, Point, Size}, mono_font::{MonoTextStyleBuilder, iso_8859_14::FONT_10X20}, pixelcolor::{Rgb888, RgbColor}, primitives::{Primitive, PrimitiveStyleBuilder, Rectangle}, text::{Baseline, Text}};use limine::request::FramebufferResponse;use log::{Level, LevelFilter, Log};use uart_16550::{Config, Uart16550Tty, backend::{MmioBackend, PioBackend}};use unicode_segmentation::UnicodeSegmentation;use core::fmt::{Display, Write};use crate::{cpu_local_data::{cpus_count, try_get_local}, frame_buffer_embedded_graphics::FrameBufferEmbeddedGraphics, write_with_cr::WriterWithCr};use owo_colors::OwoColorize;
struct Inner { serial: Option<Either<Uart16550Tty<PioBackend>, Uart16550Tty<MmioBackend>>>, display: Option<DisplayData>}
impl Inner { fn write_with_color(&mut self, color: Color, string: impl Display) { // Write to serial { let string: &dyn Display = match color { Color::Default => &string, Color::BrightRed => &string.bright_red(), Color::BrightYellow => &string.bright_yellow(), Color::BrightBlue => &string.bright_blue(), Color::BrightCyan => &string.bright_cyan(), Color::BrightMagenta => &string.bright_magenta(), Color::Grey => &string.dimmed(), };
if let Some(serial) = &mut self.serial { let mut writer = WriterWithCr::new(serial); write!(writer, "{string}").unwrap(); } }
// Write to screen if let Some(display_data) = &mut self.display { struct Writer<'a> { display: &'a mut FrameBufferEmbeddedGraphics<'static>, position: &'a mut Point, text_color: <FrameBufferEmbeddedGraphics<'a> as DrawTarget>::Color }
impl Write for Writer<'_> { fn write_str(&mut self, s: &str) -> core::fmt::Result { let font = FONT_10X20; let background_color = Rgb888::BLACK; for c in s.graphemes(true) { let height_not_seen = self.position.y + font.character_size.height as i32 - self.display.bounding_box().size.height as i32;
if height_not_seen > 0 { self.display.shift_up(height_not_seen as usize); self.position.y -= height_not_seen; }
match c { "\r" => { // We do not handle special cursor movements }, "\n" | "\r\n" => { // Fill the remaining space with background color Rectangle::new( *self.position, Size::new( self.display.bounding_box().size.width - self.position.x as u32, font.character_size.height ) ) .into_styled( PrimitiveStyleBuilder::new() .fill_color(background_color) .build() ) .draw(self.display) .map_err(|_| core::fmt::Error)?; self.position.y += font.character_size.height as i32; self.position.x = 0; }, c => { let style = MonoTextStyleBuilder::new() .font(&font) .text_color(self.text_color) .background_color(background_color) .build();
*self.position = Text::with_baseline(c, *self.position, style, Baseline::Top) .draw(self.display) .map_err(|_| core::fmt::Error)?; if self.position.x as u32 + font.character_size.width > self.display.bounding_box().size.width { self.position.y += font.character_size.height as i32; self.position.x = 0; } } } }
Ok(()) } }
let mut writer = Writer { display: &mut display_data.display, position: &mut display_data.position, text_color: match color { Color::Default => Rgb888::WHITE, // Mimick the ANSI escape colors Color::BrightRed => Rgb888::new(255, 85, 85), Color::BrightYellow => Rgb888::new(255, 255, 85), Color::BrightBlue => Rgb888::new(85, 85, 255), Color::BrightCyan => Rgb888::new(85, 255, 255), Color::BrightMagenta => Rgb888::new(255, 85, 255), Color::Grey => Rgb888::new(128, 128, 128), } };
write!(writer, "{string}").unwrap(); } }}
/// Represents a color in a terminal or screen. The default color may depend on/// if the theme is light or dark.enum Color { Default, BrightRed, BrightYellow, BrightBlue, BrightCyan, BrightMagenta, Grey}
struct KernelLogger { inner: spin::Mutex<Inner>}
impl Log for KernelLogger { fn enabled(&self, _metadata: &log::Metadata) -> bool { todo!() } fn log(&self, record: &log::Record) { let mut inner = self.inner.lock();
let cpu_id = try_get_local().map_or(0, |data| data.kernel_assigned_id); let width = match cpus_count() { 1 => 1, n => (n - 1).ilog(16) as usize + 1 }; inner.write_with_color(Color::Grey, format_args!("[{cpu_id:0width$X}] ")); let level = record.level();
inner.write_with_color( match level { Level::Error => Color::BrightRed, Level::Warn => Color::BrightYellow, Level::Info => Color::BrightBlue, Level::Debug => Color::BrightCyan, Level::Trace => Color::BrightMagenta }, format_args!("{level:5} ") );
inner.write_with_color(Color::Default, record.args()); inner.write_with_color(Color::Default, "\n"); } fn flush(&self) { todo!() }}
struct DisplayData { display: FrameBufferEmbeddedGraphics<'static>, position: Point}
static LOGGER: KernelLogger = KernelLogger { inner: spin::Mutex::new(Inner { serial: None, display: None })};
pub fn init(frame_buffer: &'static FramebufferResponse) -> Result<(), log::SetLoggerError> { let mut inner = LOGGER.inner.try_lock().unwrap(); inner.serial = Some(Either::Left(unsafe { Uart16550Tty::new_port(0x3f8, Config::default()) }.expect("should initialize device"))); inner.display = frame_buffer .framebuffers() .iter() .next() .map(|frame_buffer| DisplayData { display: { let addr = frame_buffer.address().addr().try_into().unwrap(); let info = (*frame_buffer).into(); unsafe { FrameBufferEmbeddedGraphics::new(addr, info) } }, position: Point::zero() }); log::set_max_level(LevelFilter::max()); log::set_logger(&LOGGER)}
pub fn replace_serial_port(serial_port: Uart16550Tty<MmioBackend>) { LOGGER.inner.lock().serial = Some(Either::Right(serial_port));}