8 Commits

Author SHA1 Message Date
1a41d087a9 Strucutring unit-tests
Signed-off-by: Noah Knegt <git@noahknegt.com>
2025-07-22 22:19:20 +02:00
bd035f1c9a Rename test to tests indicating that it will contain more than one test
Signed-off-by: Noah Knegt <git@noahknegt.com>
2025-07-22 20:30:20 +02:00
548acbbb5e Apply bootloader config correctly
Signed-off-by: Noah Knegt <git@noahknegt.com>
2025-07-22 20:27:01 +02:00
4605190a4e Rename logger to logging and fix formatting
Signed-off-by: Noah Knegt <git@noahknegt.com>
2025-07-22 20:21:51 +02:00
cd817d2013 Add dummy functoin that does a simple addition to verify that unit tests are working
Signed-off-by: Noah Knegt <git@noahknegt.com>
2025-07-22 20:12:45 +02:00
a91d52890a Move the qemu helper to the integration tests
Signed-off-by: Noah Knegt <git@noahknegt.com>
2025-07-22 20:12:13 +02:00
34283780c0 Create Qemu helpers
Signed-off-by: Noah Knegt <git@noahknegt.com>
2025-07-22 20:03:01 +02:00
f1e6ef14b2 Split into main and kernel lib
Signed-off-by: Noah Knegt <git@noahknegt.com>
2025-07-22 20:02:47 +02:00
9 changed files with 71 additions and 56 deletions

View File

@@ -9,11 +9,15 @@ fn main() {
// create an UEFI disk image (optional) // create an UEFI disk image (optional)
let uefi_path = out_dir.join("uefi.img"); let uefi_path = out_dir.join("uefi.img");
bootloader::UefiBoot::new(&kernel).create_disk_image(&uefi_path).unwrap(); bootloader::UefiBoot::new(&kernel)
.create_disk_image(&uefi_path)
.unwrap();
// create a BIOS disk image // create a BIOS disk image
let bios_path = out_dir.join("bios.img"); let bios_path = out_dir.join("bios.img");
bootloader::BiosBoot::new(&kernel).create_disk_image(&bios_path).unwrap(); bootloader::BiosBoot::new(&kernel)
.create_disk_image(&bios_path)
.unwrap();
// pass the disk image paths as env variables to the `main.rs` // pass the disk image paths as env variables to the `main.rs`
println!("cargo:rustc-env=UEFI_PATH={}", uefi_path.display()); println!("cargo:rustc-env=UEFI_PATH={}", uefi_path.display());

13
kernel/src/adder.rs Normal file
View File

@@ -0,0 +1,13 @@
pub fn add(a: i32, b: i32) -> i32 {
a + b
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn add_test() {
assert_eq!(add(1, 2), 3);
}
}

30
kernel/src/lib.rs Normal file
View File

@@ -0,0 +1,30 @@
#![cfg_attr(not(test), no_std)]
use bootloader_api::BootInfo;
mod logging;
mod adder;
pub fn main(boot_info: &'static mut BootInfo) -> ! {
let info = boot_info.framebuffer.as_ref().unwrap().info();
let buffer = boot_info.framebuffer.as_mut().unwrap().buffer_mut();
logging::init_logger(buffer, info);
log::info!("Hello World from KERNEL");
log::debug!("ADDING 1 & 6, result == {}", adder::add(1, 6));
// Endless loop as the kernel must stay running
#[allow(clippy::empty_loop)]
loop {}
}
#[cfg(not(test))]
#[panic_handler]
fn panic(info: &core::panic::PanicInfo) -> ! {
logging::force_unlock();
log::error!("{info}");
#[allow(clippy::empty_loop)]
loop {}
}

View File

@@ -2,7 +2,7 @@ use bootloader_api::info::{FrameBufferInfo, PixelFormat};
use core::{fmt, ptr}; use core::{fmt, ptr};
use font_constants::BACKUP_CHAR; use font_constants::BACKUP_CHAR;
use noto_sans_mono_bitmap::{ use noto_sans_mono_bitmap::{
get_raster, get_raster_width, FontWeight, RasterHeight, RasterizedChar, FontWeight, RasterHeight, RasterizedChar, get_raster, get_raster_width,
}; };
/// Additional vertical space between lines /// Additional vertical space between lines
@@ -130,7 +130,7 @@ impl FrameBufferWriter {
// set a supported (but invalid) pixel format before panicking to avoid a double // set a supported (but invalid) pixel format before panicking to avoid a double
// panic; it might not be readable though // panic; it might not be readable though
self.info.pixel_format = PixelFormat::Rgb; self.info.pixel_format = PixelFormat::Rgb;
panic!("pixel format {:?} not supported in logger", other) panic!("pixel format {other:?} not supported in logger")
} }
}; };
let bytes_per_pixel = self.info.bytes_per_pixel; let bytes_per_pixel = self.info.bytes_per_pixel;

View File

@@ -11,21 +11,21 @@ static LOGGER: OnceCell<LockedLogger> = OnceCell::uninit();
/// A logger instance protected by a spinlock. /// A logger instance protected by a spinlock.
struct LockedLogger { struct LockedLogger {
framebuffer: Option<Spinlock<framebuffer::FrameBufferWriter>>, framebuffer: Option<Spinlock<framebuffer::FrameBufferWriter>>,
serial: Option<Spinlock<serial::SerialPort>> serial: Option<Spinlock<serial::SerialPort>>,
} }
impl LockedLogger { impl LockedLogger {
/// Create a new instance that logs to the given framebuffer. /// Create a new instance that logs to the given framebuffer.
pub fn new( pub fn new(framebuffer: &'static mut [u8], info: FrameBufferInfo) -> Self {
framebuffer: &'static mut [u8], let framebuffer = Some(Spinlock::new(framebuffer::FrameBufferWriter::new(
info: FrameBufferInfo, framebuffer,
) -> Self { info,
let framebuffer = Some(Spinlock::new(framebuffer::FrameBufferWriter::new(framebuffer, info))); )));
let serial = Some(Spinlock::new(unsafe { serial::SerialPort::init() })); let serial = Some(Spinlock::new(unsafe { serial::SerialPort::init() }));
LockedLogger { LockedLogger {
framebuffer, framebuffer,
serial serial,
} }
} }
@@ -65,16 +65,8 @@ impl log::Log for LockedLogger {
} }
/// Initialize a text-based logger using the given pixel-based framebuffer as output. /// Initialize a text-based logger using the given pixel-based framebuffer as output.
pub fn init_logger( pub fn init_logger(framebuffer: &'static mut [u8], info: FrameBufferInfo) {
framebuffer: &'static mut [u8], let logger = LOGGER.get_or_init(move || LockedLogger::new(framebuffer, info));
info: FrameBufferInfo,
) {
let logger = LOGGER.get_or_init(move || {
LockedLogger::new(
framebuffer,
info,
)
});
log::set_logger(logger).expect("logger already set"); log::set_logger(logger).expect("logger already set");
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
log::set_max_level(log::LevelFilter::Debug); log::set_max_level(log::LevelFilter::Debug);
@@ -82,14 +74,9 @@ pub fn init_logger(
#[cfg(not(debug_assertions))] #[cfg(not(debug_assertions))]
log::set_max_level(log::LevelFilter::Info); log::set_max_level(log::LevelFilter::Info);
log::debug!("Framebuffer info: {:?}", info); log::debug!("Framebuffer info: {info:?}");
} }
pub fn force_unlock() { pub fn force_unlock() {
unsafe { unsafe { LOGGER.get().map(|l| l.force_unlock()) };
LOGGER
.get()
.map(|l| l.force_unlock())
};
} }

View File

@@ -1,4 +1,5 @@
pub mod logger; pub mod logger;
mod framebuffer; mod framebuffer;
mod serial; mod serial;

View File

@@ -3,35 +3,13 @@
use bootloader_api::{ use bootloader_api::{
config::{BootloaderConfig, Mapping}, config::{BootloaderConfig, Mapping},
entry_point, BootInfo entry_point,
}; };
mod logger; static BOOTLOADER_CONFIG: BootloaderConfig = {
pub static BOOTLOADER_CONFIG: BootloaderConfig = {
let mut config = BootloaderConfig::new_default(); let mut config = BootloaderConfig::new_default();
config.mappings.physical_memory = Some(Mapping::Dynamic); config.mappings.physical_memory = Some(Mapping::Dynamic);
config config
}; };
entry_point!(kernel_main); entry_point!(kernel::main, config = &BOOTLOADER_CONFIG);
fn kernel_main(boot_info: &'static mut BootInfo) -> ! {
let info = boot_info.framebuffer.as_ref().unwrap().info();
let buffer = boot_info.framebuffer.as_mut().unwrap().buffer_mut();
logger::init_logger(buffer, info);
log::info!("Hello World from KERNEL");
// Endless loop as the kernel must stay running
loop {}
}
#[panic_handler]
#[cfg(not(test))]
fn panic(info: &core::panic::PanicInfo) -> ! {
logger::force_unlock();
log::error!("{}", info);
loop {}
}

View File

@@ -11,9 +11,11 @@ fn main() {
let mut cmd = std::process::Command::new("qemu-system-x86_64"); let mut cmd = std::process::Command::new("qemu-system-x86_64");
if uefi { if uefi {
cmd.arg("-bios").arg(ovmf_prebuilt::ovmf_pure_efi()); cmd.arg("-bios").arg(ovmf_prebuilt::ovmf_pure_efi());
cmd.arg("-drive").arg(format!("format=raw,file={uefi_path}")); cmd.arg("-drive")
.arg(format!("format=raw,file={uefi_path}"));
} else { } else {
cmd.arg("-drive").arg(format!("format=raw,file={bios_path}")); cmd.arg("-drive")
.arg(format!("format=raw,file={bios_path}"));
} }
let mut child = cmd.spawn().unwrap(); let mut child = cmd.spawn().unwrap();
child.wait().unwrap(); child.wait().unwrap();