Compare commits
3 Commits
1a41d087a9
...
add-serial
Author | SHA1 | Date | |
---|---|---|---|
092004bab0
|
|||
022ec27bd5
|
|||
bf3923acd0 |
2
LICENSE
2
LICENSE
@@ -1,6 +1,6 @@
|
|||||||
MIT License
|
MIT License
|
||||||
|
|
||||||
Copyright (c) 2025 noah.knegt
|
Copyright (c) 2025 Noah Knegt <personal@noahknegt.com>
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
|
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
|
||||||
associated documentation files (the "Software"), to deal in the Software without restriction, including
|
associated documentation files (the "Software"), to deal in the Software without restriction, including
|
||||||
|
8
build.rs
8
build.rs
@@ -9,15 +9,11 @@ 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)
|
bootloader::UefiBoot::new(&kernel).create_disk_image(&uefi_path).unwrap();
|
||||||
.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)
|
bootloader::BiosBoot::new(&kernel).create_disk_image(&bios_path).unwrap();
|
||||||
.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());
|
||||||
|
@@ -1,13 +0,0 @@
|
|||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,30 +0,0 @@
|
|||||||
#![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 {}
|
|
||||||
}
|
|
@@ -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::{
|
||||||
FontWeight, RasterHeight, RasterizedChar, get_raster, get_raster_width,
|
get_raster, get_raster_width, FontWeight, RasterHeight, RasterizedChar,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// 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 {other:?} not supported in logger")
|
panic!("pixel format {:?} not supported in logger", other)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let bytes_per_pixel = self.info.bytes_per_pixel;
|
let bytes_per_pixel = self.info.bytes_per_pixel;
|
@@ -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(framebuffer: &'static mut [u8], info: FrameBufferInfo) -> Self {
|
pub fn new(
|
||||||
let framebuffer = Some(Spinlock::new(framebuffer::FrameBufferWriter::new(
|
framebuffer: &'static mut [u8],
|
||||||
framebuffer,
|
info: FrameBufferInfo,
|
||||||
info,
|
) -> Self {
|
||||||
)));
|
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,8 +65,16 @@ 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(framebuffer: &'static mut [u8], info: FrameBufferInfo) {
|
pub fn init_logger(
|
||||||
let logger = LOGGER.get_or_init(move || LockedLogger::new(framebuffer, info));
|
framebuffer: &'static mut [u8],
|
||||||
|
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);
|
||||||
@@ -74,9 +82,14 @@ pub fn init_logger(framebuffer: &'static mut [u8], info: FrameBufferInfo) {
|
|||||||
#[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 { LOGGER.get().map(|l| l.force_unlock()) };
|
unsafe {
|
||||||
|
LOGGER
|
||||||
|
.get()
|
||||||
|
.map(|l| l.force_unlock())
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
@@ -1,5 +1,4 @@
|
|||||||
pub mod logger;
|
pub mod logger;
|
||||||
|
|
||||||
mod framebuffer;
|
mod framebuffer;
|
||||||
mod serial;
|
mod serial;
|
||||||
|
|
@@ -3,13 +3,35 @@
|
|||||||
|
|
||||||
use bootloader_api::{
|
use bootloader_api::{
|
||||||
config::{BootloaderConfig, Mapping},
|
config::{BootloaderConfig, Mapping},
|
||||||
entry_point,
|
entry_point, BootInfo
|
||||||
};
|
};
|
||||||
|
|
||||||
static BOOTLOADER_CONFIG: BootloaderConfig = {
|
mod logger;
|
||||||
|
|
||||||
|
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, config = &BOOTLOADER_CONFIG);
|
entry_point!(kernel_main);
|
||||||
|
|
||||||
|
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 {}
|
||||||
|
}
|
||||||
|
@@ -1,5 +1,7 @@
|
|||||||
[toolchain]
|
[toolchain]
|
||||||
channel = "nightly"
|
# The nightly version that was build on 24-07-2025 is the last known working version,
|
||||||
|
# the c-int-width definition for rust targets has changed from a string to a u16
|
||||||
|
channel = "nightly-2025-07-24"
|
||||||
targets = [
|
targets = [
|
||||||
"x86_64-unknown-none"
|
"x86_64-unknown-none"
|
||||||
]
|
]
|
||||||
|
@@ -17,6 +17,9 @@ fn main() {
|
|||||||
cmd.arg("-drive")
|
cmd.arg("-drive")
|
||||||
.arg(format!("format=raw,file={bios_path}"));
|
.arg(format!("format=raw,file={bios_path}"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cmd.arg("-serial").arg("stdio");
|
||||||
|
|
||||||
let mut child = cmd.spawn().unwrap();
|
let mut child = cmd.spawn().unwrap();
|
||||||
child.wait().unwrap();
|
child.wait().unwrap();
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user