Move to single arch, add serial console, font rendering, panic handling, move graphics to multiple files, use a global mutex framebuffer & serialconsole

This commit is contained in:
csd4ni3l
2026-03-14 16:40:23 +01:00
parent 8308a7ae32
commit 7a938283f7
17 changed files with 205 additions and 24 deletions

32
kernel/Cargo.lock generated
View File

@@ -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",
]

View File

@@ -4,8 +4,10 @@ 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"

5
kernel/src/arch/mod.rs Normal file
View File

@@ -0,0 +1,5 @@
pub mod serial;
pub mod gdt;
pub mod idt;
pub mod interrupts;
pub mod paging;

42
kernel/src/arch/serial.rs Normal file
View File

@@ -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<Option<SerialConsole>> = 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: FnOnce(&mut SerialConsole)>(f: F) {
let mut guard = SERIAL_CONSOLE.lock();
if let Some(fb) = guard.as_mut() {
f(fb);
}
}

View File

@@ -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)
}

View File

@@ -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
}

View File

@@ -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,
}
@@ -51,3 +52,18 @@ impl Framebuffer {
}
}
}
unsafe impl Send for Framebuffer {}
pub static FRAMEBUFFER: Mutex<Option<Framebuffer>> = Mutex::new(None);
pub fn init_framebuffer(raw: &LimineFramebuffer) {
*FRAMEBUFFER.lock() = Some(Framebuffer::new(raw));
}
pub fn with_framebuffer<F: FnOnce(&mut Framebuffer)>(f: F) {
let mut guard = FRAMEBUFFER.lock();
if let Some(fb) = guard.as_mut() {
f(fb);
}
}

View File

@@ -0,0 +1,4 @@
pub mod base;
pub mod framebuffer;
pub mod font_render;
pub mod primitives;

View File

@@ -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,14 +101,16 @@ 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);
}
}
if swap {
framebuffer.swap();
}
}
pub fn rectangle_outline(framebuffer: &mut Framebuffer, x: i64, y: i64, width: i64, height: i64, color: u32) {
line(framebuffer, x, y, x + width, y, color); // bottomleft -> bottomright

View File

@@ -1,5 +1,3 @@
pub mod framebuffer;
pub mod graphics;
pub mod font_render;
pub mod keyboard;
pub mod timer;

View File

@@ -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));
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");
}
}
@@ -54,6 +85,19 @@ unsafe extern "C" fn kmain() -> ! {
#[panic_handler]
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();
}