From 7a938283f7acb7fd12a621498dbdac399293823a Mon Sep 17 00:00:00 2001 From: csd4ni3l Date: Sat, 14 Mar 2026 16:40:23 +0100 Subject: [PATCH] Move to single arch, add serial console, font rendering, panic handling, move graphics to multiple files, use a global mutex framebuffer & serialconsole --- kernel/Cargo.lock | 32 ++++++++++ kernel/Cargo.toml | 4 +- kernel/src/arch/{x86_64 => }/gdt.rs | 0 kernel/src/arch/{x86_64 => }/idt.rs | 0 kernel/src/arch/{x86_64 => }/interrupts.rs | 0 kernel/src/arch/mod.rs | 5 ++ kernel/src/arch/{x86_64 => }/paging.rs | 0 kernel/src/arch/serial.rs | 42 ++++++++++++ kernel/src/arch/x86_64/serial.rs | 0 kernel/src/driver/font_render.rs | 0 kernel/src/driver/graphics/base.rs | 5 ++ kernel/src/driver/graphics/font_render.rs | 36 +++++++++++ .../src/driver/{ => graphics}/framebuffer.rs | 20 +++++- kernel/src/driver/graphics/mod.rs | 4 ++ .../{graphics.rs => graphics/primitives.rs} | 15 ++--- kernel/src/driver/mod.rs | 2 - kernel/src/main.rs | 64 ++++++++++++++++--- 17 files changed, 205 insertions(+), 24 deletions(-) rename kernel/src/arch/{x86_64 => }/gdt.rs (100%) rename kernel/src/arch/{x86_64 => }/idt.rs (100%) rename kernel/src/arch/{x86_64 => }/interrupts.rs (100%) create mode 100644 kernel/src/arch/mod.rs rename kernel/src/arch/{x86_64 => }/paging.rs (100%) create mode 100644 kernel/src/arch/serial.rs delete mode 100644 kernel/src/arch/x86_64/serial.rs delete mode 100644 kernel/src/driver/font_render.rs create mode 100644 kernel/src/driver/graphics/base.rs create mode 100644 kernel/src/driver/graphics/font_render.rs rename kernel/src/driver/{ => graphics}/framebuffer.rs (76%) create mode 100644 kernel/src/driver/graphics/mod.rs rename kernel/src/driver/{graphics.rs => graphics/primitives.rs} (92%) diff --git a/kernel/Cargo.lock b/kernel/Cargo.lock index 80cab30..7d24fdf 100644 --- a/kernel/Cargo.lock +++ b/kernel/Cargo.lock @@ -8,6 +8,12 @@ version = "2.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" +[[package]] +name = "font8x8" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "875488b8711a968268c7cf5d139578713097ca4635a76044e8fe8eedf831d07e" + [[package]] name = "limine" version = "0.5.0" @@ -21,8 +27,19 @@ dependencies = [ name = "limine-rust-template" version = "0.1.0" dependencies = [ + "font8x8", "limine", "micromath", + "spin", +] + +[[package]] +name = "lock_api" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" +dependencies = [ + "scopeguard", ] [[package]] @@ -30,3 +47,18 @@ name = "micromath" version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3c8dda44ff03a2f238717214da50f65d5a53b45cd213a7370424ffdb6fae815" + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "spin" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5fe4ccb98d9c292d56fec89a5e07da7fc4cf0dc11e156b41793132775d3e591" +dependencies = [ + "lock_api", +] diff --git a/kernel/Cargo.toml b/kernel/Cargo.toml index eb76d45..7e8660f 100644 --- a/kernel/Cargo.toml +++ b/kernel/Cargo.toml @@ -4,11 +4,13 @@ version = "0.1.0" edition = "2024" [dependencies] +font8x8 = { version="0.3.1", default-features = false } limine = "0.5" micromath = "2.1.0" +spin = "0.10.0" [profile.dev] panic = "abort" [profile.release] -panic = "abort" \ No newline at end of file +panic = "abort" diff --git a/kernel/src/arch/x86_64/gdt.rs b/kernel/src/arch/gdt.rs similarity index 100% rename from kernel/src/arch/x86_64/gdt.rs rename to kernel/src/arch/gdt.rs diff --git a/kernel/src/arch/x86_64/idt.rs b/kernel/src/arch/idt.rs similarity index 100% rename from kernel/src/arch/x86_64/idt.rs rename to kernel/src/arch/idt.rs diff --git a/kernel/src/arch/x86_64/interrupts.rs b/kernel/src/arch/interrupts.rs similarity index 100% rename from kernel/src/arch/x86_64/interrupts.rs rename to kernel/src/arch/interrupts.rs diff --git a/kernel/src/arch/mod.rs b/kernel/src/arch/mod.rs new file mode 100644 index 0000000..59a26be --- /dev/null +++ b/kernel/src/arch/mod.rs @@ -0,0 +1,5 @@ +pub mod serial; +pub mod gdt; +pub mod idt; +pub mod interrupts; +pub mod paging; \ No newline at end of file diff --git a/kernel/src/arch/x86_64/paging.rs b/kernel/src/arch/paging.rs similarity index 100% rename from kernel/src/arch/x86_64/paging.rs rename to kernel/src/arch/paging.rs diff --git a/kernel/src/arch/serial.rs b/kernel/src/arch/serial.rs new file mode 100644 index 0000000..3c01af9 --- /dev/null +++ b/kernel/src/arch/serial.rs @@ -0,0 +1,42 @@ +use crate::driver::graphics::framebuffer::{with_framebuffer, Framebuffer}; +use crate::driver::graphics::font_render::render_text; +use crate::driver::graphics::base::rgb; +use spin::Mutex; + +const DEFAULT_FONT_SIZE: usize = 3; + +pub struct SerialConsole { + start_x: usize, + current_y: usize +} + +impl SerialConsole { + pub fn new(start_x: usize, start_y: usize) -> SerialConsole { + SerialConsole { + start_x, + current_y: start_y + } + } + + pub fn render_text(&mut self, fb: &mut Framebuffer, text: &str) { + self.current_y = render_text(fb, self.start_x - ((text.len() - text.matches('\n').count()) * DEFAULT_FONT_SIZE * 4), self.current_y, text, DEFAULT_FONT_SIZE, rgb(0, 0, 0)); + self.current_y = render_text(fb, self.start_x - ((text.len() - text.matches('\n').count()) * DEFAULT_FONT_SIZE * 4), self.current_y, "\n", DEFAULT_FONT_SIZE, rgb(0, 0, 0)); // add a newline + } + + pub fn clear(&mut self, start_y: usize) { + self.current_y = start_y; + } +} + +pub static SERIAL_CONSOLE: Mutex> = Mutex::new(None); + +pub fn init_serial_console(start_x: usize, start_y: usize) { + *SERIAL_CONSOLE.lock() = Some(SerialConsole::new(start_x, start_y)); +} + +pub fn with_serial_console(f: F) { + let mut guard = SERIAL_CONSOLE.lock(); + if let Some(fb) = guard.as_mut() { + f(fb); + } +} \ No newline at end of file diff --git a/kernel/src/arch/x86_64/serial.rs b/kernel/src/arch/x86_64/serial.rs deleted file mode 100644 index e69de29..0000000 diff --git a/kernel/src/driver/font_render.rs b/kernel/src/driver/font_render.rs deleted file mode 100644 index e69de29..0000000 diff --git a/kernel/src/driver/graphics/base.rs b/kernel/src/driver/graphics/base.rs new file mode 100644 index 0000000..0133ee8 --- /dev/null +++ b/kernel/src/driver/graphics/base.rs @@ -0,0 +1,5 @@ +pub const PI: f32 = 3.1415926535897; + +pub fn rgb(r: u8, g: u8, b: u8) -> u32 { + ((r as u32) << 16) | ((g as u32) << 8) | (b as u32) +} diff --git a/kernel/src/driver/graphics/font_render.rs b/kernel/src/driver/graphics/font_render.rs new file mode 100644 index 0000000..1a1c8d0 --- /dev/null +++ b/kernel/src/driver/graphics/font_render.rs @@ -0,0 +1,36 @@ +extern crate font8x8; + +use crate::driver::graphics::framebuffer::Framebuffer; +use crate::driver::graphics::primitives::rectangle_filled; +use font8x8::legacy::BASIC_LEGACY; + +pub fn render_char(framebuffer: &mut Framebuffer, start_x: usize, start_y: usize, char: usize, font_size: usize, color: u32) { + if let Some(glyph) = BASIC_LEGACY.get(char) { + for (row, row_bits) in glyph.iter().enumerate() { + for bit in 0..8 { + if (row_bits & (1 << bit)) != 0 { + rectangle_filled(framebuffer, start_x + bit * font_size, start_y + row * font_size, font_size, font_size, color, false); + } + } + } + } +} + +pub fn render_text(framebuffer: &mut Framebuffer, start_x: usize, start_y: usize, text: &str, font_size: usize, color: u32) -> usize { + let mut x = start_x; + let mut y = start_y; + + for b in text.bytes() { + if b == b'\n' { + y += 12 * font_size; + x = start_x; + continue; + } + + render_char(framebuffer, x, y, b as usize, font_size, color); + x += 8 * font_size; + } + framebuffer.swap(); + + y +} \ No newline at end of file diff --git a/kernel/src/driver/framebuffer.rs b/kernel/src/driver/graphics/framebuffer.rs similarity index 76% rename from kernel/src/driver/framebuffer.rs rename to kernel/src/driver/graphics/framebuffer.rs index b1612e4..b50b5f0 100644 --- a/kernel/src/driver/framebuffer.rs +++ b/kernel/src/driver/graphics/framebuffer.rs @@ -1,4 +1,5 @@ use limine::framebuffer::Framebuffer as LimineFramebuffer; +use spin::Mutex; const MAX_BACKBUFFER_PIXELS: usize = 1920 * 1080; static mut BACK_BUFFER: [u32; MAX_BACKBUFFER_PIXELS] = [0; MAX_BACKBUFFER_PIXELS]; @@ -6,8 +7,8 @@ static mut BACK_BUFFER: [u32; MAX_BACKBUFFER_PIXELS] = [0; MAX_BACKBUFFER_PIXELS pub struct Framebuffer { addr: *mut u32, back_buffer: *mut u32, - width: usize, - height: usize, + pub width: usize, + pub height: usize, pitch: usize, back_buffer_len: usize, } @@ -50,4 +51,19 @@ impl Framebuffer { core::ptr::copy_nonoverlapping(self.back_buffer, self.addr, self.back_buffer_len); } } +} + +unsafe impl Send for Framebuffer {} + +pub static FRAMEBUFFER: Mutex> = Mutex::new(None); + +pub fn init_framebuffer(raw: &LimineFramebuffer) { + *FRAMEBUFFER.lock() = Some(Framebuffer::new(raw)); +} + +pub fn with_framebuffer(f: F) { + let mut guard = FRAMEBUFFER.lock(); + if let Some(fb) = guard.as_mut() { + f(fb); + } } \ No newline at end of file diff --git a/kernel/src/driver/graphics/mod.rs b/kernel/src/driver/graphics/mod.rs new file mode 100644 index 0000000..fc32755 --- /dev/null +++ b/kernel/src/driver/graphics/mod.rs @@ -0,0 +1,4 @@ +pub mod base; +pub mod framebuffer; +pub mod font_render; +pub mod primitives; \ No newline at end of file diff --git a/kernel/src/driver/graphics.rs b/kernel/src/driver/graphics/primitives.rs similarity index 92% rename from kernel/src/driver/graphics.rs rename to kernel/src/driver/graphics/primitives.rs index 3615f54..3f7270f 100644 --- a/kernel/src/driver/graphics.rs +++ b/kernel/src/driver/graphics/primitives.rs @@ -1,11 +1,6 @@ use micromath::F32Ext; -use crate::driver::framebuffer::Framebuffer; - -const PI: f32 = 3.1415926535897; - -pub fn rgb(r: u8, g: u8, b: u8) -> u32 { - ((r as u32) << 16) | ((g as u32) << 8) | (b as u32) -} +use crate::driver::graphics::framebuffer::Framebuffer; +use crate::driver::graphics::base::{rgb, PI}; pub fn line(framebuffer: &mut Framebuffer, mut x0: i64, mut y0: i64, x1: i64, y1: i64, color: u32) { let mut dx = x1 - x0; @@ -106,13 +101,15 @@ pub fn circle_filled(framebuffer: &mut Framebuffer, x0: usize, y0: usize, radius framebuffer.swap(); } -pub fn rectangle_filled(framebuffer: &mut Framebuffer, x: usize, y: usize, width: usize, height: usize, color: u32) { +pub fn rectangle_filled(framebuffer: &mut Framebuffer, x: usize, y: usize, width: usize, height: usize, color: u32, swap: bool) { for fb_x in x..x+width { for fb_y in y..y+height { framebuffer.put_pixel(fb_x, fb_y, color); } } - framebuffer.swap(); + if swap { + framebuffer.swap(); + } } pub fn rectangle_outline(framebuffer: &mut Framebuffer, x: i64, y: i64, width: i64, height: i64, color: u32) { diff --git a/kernel/src/driver/mod.rs b/kernel/src/driver/mod.rs index 745ef74..2ad5ae4 100644 --- a/kernel/src/driver/mod.rs +++ b/kernel/src/driver/mod.rs @@ -1,5 +1,3 @@ -pub mod framebuffer; pub mod graphics; -pub mod font_render; pub mod keyboard; pub mod timer; \ No newline at end of file diff --git a/kernel/src/main.rs b/kernel/src/main.rs index b6d611c..c794092 100644 --- a/kernel/src/main.rs +++ b/kernel/src/main.rs @@ -7,9 +7,14 @@ use limine::BaseRevision; use limine::request::{FramebufferRequest, RequestsEndMarker, RequestsStartMarker}; pub mod driver; +pub mod arch; -use crate::driver::graphics::{circle_filled, circle_outline, rectangle_filled, rectangle_outline, rgb, triangle_outline}; -use crate::driver::framebuffer::Framebuffer; +use spin::Mutex; +use crate::arch::serial::{SerialConsole, init_serial_console, with_serial_console}; +use crate::driver::graphics::font_render::render_text; +use crate::driver::graphics::primitives::{circle_filled, circle_outline, rectangle_filled, rectangle_outline, triangle_outline}; +use crate::driver::graphics::base::rgb; +use crate::driver::graphics::framebuffer::{Framebuffer, init_framebuffer, with_framebuffer}; /// Sets the base revision to the latest revision supported by the crate. /// See specification for further info. @@ -31,6 +36,27 @@ static _START_MARKER: RequestsStartMarker = RequestsStartMarker::new(); #[unsafe(link_section = ".requests_end_marker")] static _END_MARKER: RequestsEndMarker = RequestsEndMarker::new(); +// #[macro_export] +// macro_rules! print { +// ($($arg:tt)*) => (with_framebuffer(|mut fb|{ +// with_serial_console(|serial_console| { +// serial_console.render_text(&mut fb, format_args!($($arg)*)); +// }); +// })); +// } + +// #[macro_export] +// macro_rules! println { +// () => ($crate::print!("\n")); +// ($($arg:tt)*) => ($crate::print!("{}\n", format_args!($($arg)*))); +// } + +// #[doc(hidden)] +// pub fn _print(args: fmt::Arguments) { +// use core::fmt::Write; +// WRITER.lock().write_fmt(args).unwrap(); +// } + #[unsafe(no_mangle)] unsafe extern "C" fn kmain() -> ! { // All limine requests must also be referenced in a called function, otherwise they may be @@ -39,13 +65,18 @@ unsafe extern "C" fn kmain() -> ! { if let Some(framebuffer_response) = FRAMEBUFFER_REQUEST.get_response() { if let Some(limine_framebuffer) = framebuffer_response.framebuffers().next() { - let mut fb = Framebuffer::new(&limine_framebuffer); - rectangle_filled(&mut fb, 0, 0, limine_framebuffer.width() as usize, limine_framebuffer.height() as usize, rgb(253, 129, 0)); - rectangle_filled(&mut fb, 700, 400, 200, 200, rgb(0, 0, 0)); - rectangle_outline(&mut fb, 400, 400, 100, 100, rgb(0, 0, 0)); - circle_filled(&mut fb, 200, 200, 100.0, rgb(0, 0, 0)); - circle_outline(&mut fb, 400, 200, 100.0, rgb(0, 0, 0)); - triangle_outline(&mut fb, 100, 400, 200, 400, 150, 600, rgb(0, 0, 0)); + init_framebuffer(&limine_framebuffer); + with_framebuffer(|mut fb| { + let (width, height) = (fb.width.clone(), fb.height.clone()); + init_serial_console(width / 2, height / 3); + rectangle_filled(&mut fb, 0, 0, width, height, rgb(253, 129, 0), true); + rectangle_filled(&mut fb, 700, 400, 200, 200, rgb(0, 0, 0), true); + rectangle_outline(&mut fb, 400, 400, 100, 100, rgb(0, 0, 0)); + circle_filled(&mut fb, 200, 200, 100.0, rgb(0, 0, 0)); + circle_outline(&mut fb, 400, 200, 100.0, rgb(0, 0, 0)); + triangle_outline(&mut fb, 100, 400, 200, 400, 150, 600, rgb(0, 0, 0)); + }); + panic!("idk, test"); } } @@ -53,7 +84,20 @@ unsafe extern "C" fn kmain() -> ! { } #[panic_handler] -fn rust_panic(_info: &core::panic::PanicInfo) -> ! { +fn rust_panic(_info: &core::panic::PanicInfo) -> ! { + with_framebuffer(|mut fb|{ + let (width, height) = (fb.width.clone(), fb.height.clone()); + rectangle_filled(&mut fb, 0, 0, width, height, rgb(180, 0, 0), true); + with_serial_console(|serial_console| { + serial_console.clear(height / 3); + serial_console.render_text(&mut fb, "Kernel Panic! :C\n\n\n"); + if let Some(message) = _info.message().as_str() { + serial_console.render_text(&mut fb, "Message:"); + serial_console.render_text(&mut fb, message); + } + }); + }); + idle(); }