From 461c7fbce07487c651e682479f4221828e727487 Mon Sep 17 00:00:00 2001 From: Eemeli <eemeli.o.lehtonen@utu.fi> Date: Sun, 15 Jan 2023 21:42:06 +0200 Subject: [PATCH] kernel commandline --- Cargo.lock | 3 +- Cargo.toml | 8 +- cfg/limine.cfg | 2 +- src/arch/x86_64/gdt.rs | 5 +- src/arch/x86_64/idt.rs | 6 +- src/arch/x86_64/limine/cmdline.rs | 18 ++++ src/arch/x86_64/limine/framebuffer.rs | 4 +- src/arch/x86_64/limine/mod.rs | 12 +-- src/env.rs | 80 +++++++++++++++ src/log.rs | 135 ++++++++++++++++++++++++-- src/main.rs | 26 ++++- src/splash | 8 ++ src/term/escape/encode.rs | 30 ++++-- src/video/logger.rs | 5 +- 14 files changed, 303 insertions(+), 39 deletions(-) create mode 100644 src/arch/x86_64/limine/cmdline.rs create mode 100644 src/env.rs create mode 100644 src/splash diff --git a/Cargo.lock b/Cargo.lock index e26fdd6..1dec863 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -275,8 +275,7 @@ checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79" [[package]] name = "limine" version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c847ac148a0c53ba3755dfa9830722b1043179584009869e6afc2b413e13f105" +source = "git+https://github.com/limine-bootloader/limine-rs?rev=c2fbc349419d4330b80e053019ad2fe504a61764#c2fbc349419d4330b80e053019ad2fe504a61764" [[package]] name = "lock_api" diff --git a/Cargo.toml b/Cargo.toml index 49de3ad..96e7ffd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,8 +21,14 @@ spin = "0.9.4" volatile = "0.4.5" x86_64 = "0.14.10" uart_16550 = "0.2.18" -limine = { version = "0.1.9", optional = true } #tracing = { version = "0.1.37", default-features = false } +[dependencies.limine] +git = "https://github.com/limine-bootloader/limine-rs" +rev = "c2fbc349419d4330b80e053019ad2fe504a61764" +# version = "0.1.9" # 0.1.9 LimineFile struct has a bug +optional = true + + [build-dependencies] image = "0.24.5" diff --git a/cfg/limine.cfg b/cfg/limine.cfg index fd84e95..0201da3 100644 --- a/cfg/limine.cfg +++ b/cfg/limine.cfg @@ -4,4 +4,4 @@ TIMEOUT=0 :Hyperion PROTOCOL=limine KERNEL_PATH=boot:///hyperion - # KERNEL_CMDLINE= + KERNEL_CMDLINE=log=trace diff --git a/src/arch/x86_64/gdt.rs b/src/arch/x86_64/gdt.rs index c7a4b29..9589fbd 100644 --- a/src/arch/x86_64/gdt.rs +++ b/src/arch/x86_64/gdt.rs @@ -1,6 +1,5 @@ -use crate::println; - use super::idt::DOUBLE_FAULT_IST; +use crate::debug; use spin::Lazy; use x86_64::{ instructions::tables::load_tss, @@ -15,7 +14,7 @@ use x86_64::{ // pub fn init() { - println!("Initializing GDT"); + debug!("Initializing GDT"); GDT.0.load(); unsafe { diff --git a/src/arch/x86_64/idt.rs b/src/arch/x86_64/idt.rs index 4a09b04..41943cd 100644 --- a/src/arch/x86_64/idt.rs +++ b/src/arch/x86_64/idt.rs @@ -1,4 +1,4 @@ -use crate::println; +use crate::{debug, info}; use spin::Lazy; use x86_64::structures::idt::{InterruptDescriptorTable, InterruptStackFrame}; @@ -9,14 +9,14 @@ pub static DOUBLE_FAULT_IST: u16 = 1; // pub fn init() { - println!("Initializing IDT"); + debug!("Initializing IDT"); IDT.load(); } // extern "x86-interrupt" fn breakpoint(stack: InterruptStackFrame) { - println!("INT: Breakpoint\n{stack:#?}") + info!("INT: Breakpoint\n{stack:#?}") } extern "x86-interrupt" fn double_fault(stack: InterruptStackFrame, ec: u64) -> ! { diff --git a/src/arch/x86_64/limine/cmdline.rs b/src/arch/x86_64/limine/cmdline.rs new file mode 100644 index 0000000..26c4b5b --- /dev/null +++ b/src/arch/x86_64/limine/cmdline.rs @@ -0,0 +1,18 @@ +use crate::env::Arguments; +use limine::LimineKernelFileRequest; + +// + +pub fn init() { + static REQ: LimineKernelFileRequest = LimineKernelFileRequest::new(0); + + if let Some(cmdline) = REQ + .get_response() + .get() + .and_then(|resp| resp.kernel_file.get()) + .and_then(|file| file.cmdline.to_str()) + .and_then(|cmdline| cmdline.to_str().ok()) + { + Arguments::parse(cmdline); + } +} diff --git a/src/arch/x86_64/limine/framebuffer.rs b/src/arch/x86_64/limine/framebuffer.rs index d7e874e..1238512 100644 --- a/src/arch/x86_64/limine/framebuffer.rs +++ b/src/arch/x86_64/limine/framebuffer.rs @@ -1,5 +1,5 @@ use crate::{ - println, + debug, video::framebuffer::{get_fbo, Framebuffer, FramebufferInfo, FBO}, }; use core::slice; @@ -36,5 +36,5 @@ pub fn init() { fbo.clear(); FBO.call_once(|| Mutex::new(fbo)); } - println!("Global framebuffer: {:#?}", get_fbo().map(|f| f.info)) + debug!("Global framebuffer: {:#?}", get_fbo().map(|f| f.info)) } diff --git a/src/arch/x86_64/limine/mod.rs b/src/arch/x86_64/limine/mod.rs index 9c90210..f188493 100644 --- a/src/arch/x86_64/limine/mod.rs +++ b/src/arch/x86_64/limine/mod.rs @@ -1,6 +1,5 @@ -use crate::println; - use super::{gdt, idt}; +use crate::debug; // @@ -8,6 +7,7 @@ pub use term::_print; // +mod cmdline; mod framebuffer; mod term; @@ -15,18 +15,18 @@ mod term; #[no_mangle] pub extern "C" fn _start() -> ! { - x86_64::instructions::interrupts::disable(); - *crate::BOOTLOADER.lock() = "Limine"; + crate::BOOTLOADER.call_once(|| "Limine"); + cmdline::init(); framebuffer::init(); gdt::init(); idt::init(); - println!("Re-enabling x86_64 interrupts"); + debug!("Re-enabling x86_64 interrupts"); x86_64::instructions::interrupts::enable(); - println!("Calling general kernel_main"); + debug!("Calling general kernel_main"); crate::kernel_main() } diff --git a/src/env.rs b/src/env.rs new file mode 100644 index 0000000..899980f --- /dev/null +++ b/src/env.rs @@ -0,0 +1,80 @@ +use crate::log::{self, LogLevel}; +use spin::Once; + +// + +// + +pub fn args() -> Arguments { + Arguments::get() +} + +// + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct Arguments { + pub log_level: LogLevel, + // log_color: bool, + pub had_unrecognized: bool, + + pub cmdline: &'static str, +} + +// + +impl Arguments { + pub fn parse(s: &'static str) { + ARGUMENTS.call_once(|| { + let mut iter = s.split_whitespace(); + let mut result = Arguments::default(); + result.cmdline = s; + + while let Some(item) = iter.next() { + match item { + "log" => { + if let Some(level) = iter.next() { + if let Some(l) = LogLevel::parse(level) { + result.log_level = l + } else { + result.had_unrecognized = true + } + } + } + _ if item.starts_with("log=") => { + if let Some(l) = LogLevel::parse(&item[4..]) { + result.log_level = l + } else { + result.had_unrecognized = true + } + } + _ => result.had_unrecognized = true, + } + } + + result.assign(); + + result + }); + } + + pub fn get() -> Self { + ARGUMENTS.get().copied().unwrap_or(Self::default()) + } + + pub fn assign(&self) { + log::set_log_level(self.log_level); + // log::set_log_color(self.log_color); + } +} + +impl Default for Arguments { + fn default() -> Self { + Self { + log_level: LogLevel::default(), + had_unrecognized: false, + cmdline: "", + } + } +} + +static ARGUMENTS: Once<Arguments> = Once::new(); diff --git a/src/log.rs b/src/log.rs index 0cb6a59..f23f82e 100644 --- a/src/log.rs +++ b/src/log.rs @@ -1,8 +1,8 @@ +use crate::term::escape::encode::EscapeEncoder; use core::{ fmt::Arguments, - sync::atomic::{AtomicBool, Ordering}, + sync::atomic::{AtomicBool, AtomicU8, Ordering}, }; -use spin::Lazy; // @@ -17,6 +17,41 @@ macro_rules! println { ($($t:tt)*) => { $crate::log::_print(format_args_nl!($($t)*)) }; } +#[macro_export] +macro_rules! log { + ($level:expr, $($t:tt)*) => { + if $crate::log::test_log_level($level) { + $crate::log::_print_log_stamp($level, module_path!()); + $crate::println!($($t)*); + } + }; +} + +#[macro_export] +macro_rules! error { + ($($t:tt)*) => { $crate::log!($crate::log::LogLevel::Error, $($t)*) }; +} + +#[macro_export] +macro_rules! warn { + ($($t:tt)*) => { $crate::log!($crate::log::LogLevel::Warn, $($t)*) }; +} + +#[macro_export] +macro_rules! info { + ($($t:tt)*) => { $crate::log!($crate::log::LogLevel::Info, $($t)*) }; +} + +#[macro_export] +macro_rules! debug { + ($($t:tt)*) => { $crate::log!($crate::log::LogLevel::Debug, $($t)*) }; +} + +#[macro_export] +macro_rules! trace { + ($($t:tt)*) => { $crate::log!($crate::log::LogLevel::Trace, $($t)*) }; +} + // // pub fn enable_term() { @@ -43,9 +78,89 @@ pub fn disable_qemu() { LOGGER.qemu.store(false, Ordering::SeqCst); } +pub fn set_log_level(level: LogLevel) { + LOGGER.level.store(level as u8, Ordering::SeqCst); +} + +// pub fn set_log_color(color: bool) { +// LOGGER.color.store(color, Ordering::SeqCst); +// } + +pub fn test_log_level(level: LogLevel) -> bool { + LOGGER.level.load(Ordering::SeqCst) >= level as u8 +} + +#[doc(hidden)] +pub fn _print_log_stamp(level: LogLevel, module: &str) { + // if !LOGGER.color.load(Ordering::SeqCst) { + // print!("[{level:?}]: ") + // } else { + let level = match level { + LogLevel::None => " NONE ", + LogLevel::Error => "\x1b[38;2;255;85;85m ERROR ", + LogLevel::Warn => "\x1b[38;2;255;255;85m WARN ", + LogLevel::Info => "\x1b[38;2;85;255;85m INFO ", + LogLevel::Debug => "\x1b[38;2;85;255;255m DEBUG ", + LogLevel::Trace => "\x1b[38;2;255;85;255m TRACE ", + }; + + print!( + "{}{level} {} {}: ", + '['.true_grey(), + module.true_grey(), + ']'.true_grey(), + ) + // } +} + // -static LOGGER: Lazy<Logger> = Lazy::new(Logger::init); +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] +#[repr(u8)] +pub enum LogLevel { + None, + Error, + Warn, + Info, + Debug, + Trace, +} + +// + +impl LogLevel { + pub const DEFAULT: Self = Self::Info; + pub const ALL: [LogLevel; 5] = [ + Self::Error, + Self::Warn, + Self::Info, + Self::Debug, + Self::Trace, + ]; + + pub fn parse(s: &str) -> Option<Self> { + // TODO: match any case + Some(match s { + "none" => Self::None, + "error" => Self::Error, + "warn" => Self::Warn, + "info" => Self::Info, + "debug" => Self::Debug, + "trace" => Self::Trace, + _ => return None, + }) + } +} + +impl Default for LogLevel { + fn default() -> Self { + Self::DEFAULT + } +} + +// + +static LOGGER: Logger = Logger::init(); struct Logger { // Log to a bootloader given terminal @@ -56,14 +171,22 @@ struct Logger { // Log to a QEMU serial qemu: AtomicBool, + + // [`LogLevel`] in u8 form + level: AtomicU8, + // print logs with colors + // color: AtomicBool, } impl Logger { - fn init() -> Self { + const fn init() -> Self { Logger { // term: false.into(), - fbo: true.into(), - qemu: true.into(), + fbo: AtomicBool::new(true), + qemu: AtomicBool::new(true), + + level: AtomicU8::new(LogLevel::DEFAULT as u8), + // color: AtomicBool::new(true), } } diff --git a/src/main.rs b/src/main.rs index b75b122..660ee75 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,22 +4,23 @@ #![feature(abi_x86_interrupt)] #![feature(custom_test_frameworks)] #![feature(type_alias_impl_trait)] +#![feature(result_option_inspect)] #![test_runner(crate::testfw::test_runner)] #![reexport_test_harness_main = "test_main"] // -use spin::Mutex; - use crate::{ term::escape::encode::EscapeEncoder, video::framebuffer::{get_fbo, Color}, }; +use spin::Once; // #[path = "arch/x86_64/mod.rs"] pub mod arch; +pub mod env; pub mod log; pub mod panic; pub mod qemu; @@ -38,13 +39,20 @@ pub static KERNEL: &str = if cfg!(test) { }; /// Name of the detected bootloader -pub static BOOTLOADER: Mutex<&'static str> = Mutex::new(KERNEL); +pub static BOOTLOADER: Once<&'static str> = Once::new(); // fn kernel_main() -> ! { - println!("\n\nHello from {}", KERNEL.cyan()); - println!(" - {} was booted with {}", KERNEL.cyan(), BOOTLOADER.lock()); + debug!("Cmdline: {:?}", env::Arguments::get()); + + // ofc. every kernel has to have this cringy ascii name splash + info!("\n{}\n", include_str!("./splash")); + + if let Some(bl) = BOOTLOADER.get() { + let kernel = KERNEL.true_cyan(); + debug!("{kernel} was booted with {bl}"); + } // error handling test // stack_overflow(79999999); @@ -52,6 +60,14 @@ fn kernel_main() -> ! { // *(0xFFFFFFFFDEADC0DE as *mut u8) = 42; // } + // for level in log::LogLevel::ALL { + // log!(level, "LOG TEST") + // } + + // for c in 0..=255u8 { + // print!("{}", c as char); + // } + if let Some(mut fbo) = get_fbo() { fbo.fill(240, 340, 40, 40, Color::RED); fbo.fill(250, 350, 60, 40, Color::GREEN); diff --git a/src/splash b/src/splash new file mode 100644 index 0000000..3aebd48 --- /dev/null +++ b/src/splash @@ -0,0 +1,8 @@ + _ _ _ + | | | | (_) + | |__| |_ _ _ __ ___ _ __ _ ___ _ __ + | __ | | | | '_ \ / _ \ '__| |/ _ \| '_ \ + | | | | |_| | |_) | __/ | | | (_) | | | | + |_| |_|\__, | __/ \___|_| |_|\___/|_| |_| + __/ | | + |___/|_| diff --git a/src/term/escape/encode.rs b/src/term/escape/encode.rs index 23af242..6eec9ea 100644 --- a/src/term/escape/encode.rs +++ b/src/term/escape/encode.rs @@ -7,29 +7,41 @@ pub trait EscapeEncoder { EncodedPart { code, data: self } } - fn red(&self) -> EncodedPart<Self> { + fn true_red(&self) -> EncodedPart<Self> { self.with_escape_code("\x1B[38;2;255;0;0m") } - fn green(&self) -> EncodedPart<Self> { + fn true_green(&self) -> EncodedPart<Self> { self.with_escape_code("\x1B[38;2;0;255;0m") } - fn blue(&self) -> EncodedPart<Self> { + fn true_blue(&self) -> EncodedPart<Self> { self.with_escape_code("\x1B[38;2;0;0;255m") } - fn cyan(&self) -> EncodedPart<Self> { + fn true_cyan(&self) -> EncodedPart<Self> { self.with_escape_code("\x1B[38;2;0;255;255m") } - fn magenta(&self) -> EncodedPart<Self> { + fn true_magenta(&self) -> EncodedPart<Self> { self.with_escape_code("\x1B[38;2;255;0;255m") } - fn yellow(&self) -> EncodedPart<Self> { + fn true_yellow(&self) -> EncodedPart<Self> { self.with_escape_code("\x1B[38;2;255;255;0m") } + + fn true_black(&self) -> EncodedPart<Self> { + self.with_escape_code("\x1B[38;2;0;0;0m") + } + + fn true_white(&self) -> EncodedPart<Self> { + self.with_escape_code("\x1B[38;2;255;255;255m") + } + + fn true_grey(&self) -> EncodedPart<Self> { + self.with_escape_code("\x1B[38;2;128;128;128m") + } } pub struct EncodedPart<'a, T: ?Sized> { @@ -39,7 +51,11 @@ pub struct EncodedPart<'a, T: ?Sized> { // -impl EscapeEncoder for &str {} +// impl EscapeEncoder for &str {} +// +// impl EscapeEncoder for char {} + +impl<T> EscapeEncoder for T {} impl<'a, T> fmt::Display for EncodedPart<'a, T> where diff --git a/src/video/logger.rs b/src/video/logger.rs index 2812854..18f2ad4 100644 --- a/src/video/logger.rs +++ b/src/video/logger.rs @@ -1,9 +1,8 @@ -use crate::term::escape::decode::{DecodedPart, EscapeDecoder}; - use super::{ font::FONT, framebuffer::{get_fbo, Color, Framebuffer}, }; +use crate::term::escape::decode::{DecodedPart, EscapeDecoder}; use core::fmt::{self, Arguments, Write}; use spin::{Mutex, MutexGuard}; @@ -125,7 +124,7 @@ impl Writer { } fn size(fbo: &mut MutexGuard<Framebuffer>) -> [u16; 2] { - [(fbo.width / 16) as _, (fbo.height / 16) as _] + [(fbo.width / 8) as _, (fbo.height / 16) as _] } } -- GitLab