From 04d953fba010149b7f5a6368baef25ec86453695 Mon Sep 17 00:00:00 2001 From: shibedrill Date: Sun, 18 May 2025 21:17:26 -0400 Subject: [PATCH] Logging macros --- README.md | 4 +- src/kernel/constants.rs | 28 ++++ src/kernel/log.rs | 86 +++++++++- src/kernel/main.rs | 303 ++++++++++++++++------------------- src/kernel/panic.rs | 18 ++- src/kernel/syscall_runner.rs | 23 --- 6 files changed, 263 insertions(+), 199 deletions(-) create mode 100644 src/kernel/constants.rs diff --git a/README.md b/README.md index 04b811b..f5ba969 100644 --- a/README.md +++ b/README.md @@ -104,9 +104,9 @@ List of current extant kernel parameters: - `-logdev`: A sequence of one or more values representing devices to log to. Current options are `display` and `serial`. - `-initramfs`: A valid path to a module to serve as the initramfs (containing the init binary). Only one value supported. -The default `cmdline` is: +The default behavior for each parameter, when not supplied, is: -`-loglevel=INFO -logdev=display,serial -initramfs=/boot/initramfs.tar.lzma` +`-loglevel=Trace -initramfs=/boot/initramfs.tar.lzma` ## Credits diff --git a/src/kernel/constants.rs b/src/kernel/constants.rs new file mode 100644 index 0000000..83e7b77 --- /dev/null +++ b/src/kernel/constants.rs @@ -0,0 +1,28 @@ +use crate::log::LogLevel; + +pub static INITRAMFS_DEFAULT_PATH: &str = "/boot/initramfs.tar.lzma"; + +pub static LOG_DEFAULT_LEVEL: LogLevel = LogLevel::Info; + +// FUCKING ADD CONST UNWRAP!!! +pub static KERNEL_VERSION_MAJOR: u8 = match u8::from_str_radix(env!("CARGO_PKG_VERSION_MAJOR"), 10) +{ + Ok(ver) => ver, + Err(_) => { + panic!("Invalid major version number ") + } +}; +pub static KERNEL_VERSION_MINOR: u8 = match u8::from_str_radix(env!("CARGO_PKG_VERSION_MINOR"), 10) +{ + Ok(ver) => ver, + Err(_) => { + panic!("Invalid minor version number ") + } +}; +pub static KERNEL_VERSION_PATCH: u8 = match u8::from_str_radix(env!("CARGO_PKG_VERSION_PATCH"), 10) +{ + Ok(ver) => ver, + Err(_) => { + panic!("Invalid patch version number ") + } +}; diff --git a/src/kernel/log.rs b/src/kernel/log.rs index d5a0aba..afe2c48 100644 --- a/src/kernel/log.rs +++ b/src/kernel/log.rs @@ -3,18 +3,73 @@ use core::fmt::Write; +use crate::constants::LOG_DEFAULT_LEVEL; use crate::memory::alloc; use alloc::boxed::*; use alloc::string::*; use alloc::vec::*; use spin::Mutex; +macro_rules! log_info { + ($($arg:tt)*) => { + LOGGER.log(LogLevel::Info, &format!($($arg)*)) + }; +} + +macro_rules! log_trace { + ($($arg:tt)*) => { + LOGGER.log(LogLevel::Trace, &format!($($arg)*)) + }; +} + +#[allow(unused_macros)] +macro_rules! log_warning { + ($($arg:tt)*) => { + LOGGER.log(LogLevel::Warning, &format!($($arg)*)) + }; +} + +#[allow(unused_macros)] +macro_rules! log_error { + ($($arg:tt)*) => { + LOGGER.log(LogLevel::Error, &format!($($arg)*)) + }; +} + +#[allow(unused_macros)] +macro_rules! log_critical { + ($($arg:tt)*) => { + LOGGER.log(LogLevel::Critical, &format!($($arg)*)) + }; +} + +pub struct Logger { + pub inner: Mutex, +} + +impl Logger { + pub fn log(&self, level: LogLevel, msg: &str) { + self.inner.lock().log(level, msg); + } + pub fn add_subscriber(&self, sub: T) { + self.inner + .lock() + .subscriber + .push(Mutex::new(alloc::boxed::Box::new(sub))); + } + pub fn set_level(&self, level: LogLevel) { + self.inner.lock().level = level; + } +} + /// The logger exists for the entire lifetime of the kernel. -pub static LOGGER: Mutex = Mutex::new(Logger::new()); +pub static LOGGER: Logger = Logger { + inner: Mutex::new(LoggerInner::new()), +}; pub struct EnumParseError {} -pub struct Logger { +pub struct LoggerInner { pub level: LogLevel, pub subscriber: Vec>>, } @@ -23,16 +78,16 @@ pub trait LogSubscriber { fn write(&self, msg: &str); } -impl Default for Logger { +impl Default for LoggerInner { fn default() -> Self { Self::new() } } -impl Logger { +impl LoggerInner { pub const fn new() -> Self { - Logger { - level: LogLevel::Warning, + LoggerInner { + level: LOG_DEFAULT_LEVEL, subscriber: Vec::new(), } } @@ -44,16 +99,17 @@ impl Logger { if level == LogLevel::Disabled { // Nothing } else if level <= self.level { + let level_string = String::from(level); for sub in &self.subscriber { let mut message = String::new(); - writeln!(&mut message, "{level:?}:\t{msg}").unwrap(); + writeln!(&mut message, "{level_string}: \t{msg}").unwrap(); sub.lock().write(&message); } } } } -#[derive(PartialEq, Eq, PartialOrd, Ord, Debug)] +#[derive(PartialEq, Eq, PartialOrd, Ord, Debug, Clone, Copy)] pub enum LogLevel { Disabled = 0, Critical = 1, @@ -92,3 +148,17 @@ impl TryFrom<&str> for LogLevel { } } } + +impl From for String { + fn from(from: LogLevel) -> String { + match from { + LogLevel::Disabled => "Disabled", + LogLevel::Critical => "CRIT", + LogLevel::Error => "ERROR", + LogLevel::Warning => "WARN", + LogLevel::Info => "INFO", + LogLevel::Trace => "TRACE", + } + .into() + } +} diff --git a/src/kernel/main.rs b/src/kernel/main.rs index 9bc0c4e..9372e84 100644 --- a/src/kernel/main.rs +++ b/src/kernel/main.rs @@ -7,6 +7,8 @@ mod arch; mod boot; +mod constants; +#[macro_use] mod log; mod memory; mod panic; @@ -17,19 +19,16 @@ mod syscall_runner; use arch::current::*; use arch::x86_64::serial::Serialport; +use boot::*; +use constants::*; +use log::*; +use memory::alloc::{format, string::*, vec}; +use params::*; + use limine::file::File; use limine::memory_map::EntryType; #[allow(unused_imports)] use lzma_rs::lzma_decompress; -use spin::mutex::Mutex; -use syscall_runner::KERNEL_VERSION_MAJOR; -use syscall_runner::KERNEL_VERSION_MINOR; -use syscall_runner::KERNEL_VERSION_PATCH; - -use crate::boot::*; -use crate::log::*; -use crate::memory::alloc::{boxed, collections::BTreeMap, format, string::*, vec}; -use crate::params::*; #[unsafe(no_mangle)] unsafe extern "C" fn main() -> ! { @@ -39,197 +38,173 @@ unsafe extern "C" fn main() -> ! { // TODO: This is hacky and will not work on any other machine. let qemu_serial = Serialport::new(0x3f8); - // Local logger fn - fn log(level: LogLevel, msg: &str) { - LOGGER.lock().log(level, msg); + let executable_file_response = FILE_REQUEST + .get_response() + .expect("Bootloader did not return executable data"); + let params = + get_kernel_params(limine::file::File::string(executable_file_response.file()).to_bytes()); + + // Set up logging level from params + // Nothing we can do here if this fails since no log subscribers are initialized yet + if let Some(level) = params.get("-loglevel") + && let Ok(parsed_level) = LogLevel::try_from(level.as_str()) + { + LOGGER.set_level(parsed_level); } - - let mut params: BTreeMap = BTreeMap::new(); - - // Set up some stuff based on kernel params if we get any - if let Some(executable_file_response) = FILE_REQUEST.get_response() { - params = get_kernel_params( - limine::file::File::string(executable_file_response.file()).to_bytes(), - ); - - // Set up logging level from params - // Nothing we can do here if this fails since no log subscribers are initialized yet - if let Some(level) = params.get("-loglevel") - && let Ok(parsed_level) = LogLevel::try_from(level.as_str()) - { - LOGGER.lock().level = parsed_level; + // Add subscribers to logger + if let Some(device) = params.get("-logdev") { + let log_device_list: vec::Vec<&str> = device.split(',').collect(); + if log_device_list.contains(&"display") { + // Append display console to log subs } - // Add subscribers to logger - if let Some(device) = params.get("-logdev") { - let log_device_list: vec::Vec<&str> = device.split(',').collect(); - if log_device_list.contains(&"display") { - // Append display console to log subs - } - if log_device_list.contains(&"serial") { - LOGGER - .lock() - .subscriber - .push(Mutex::new(boxed::Box::new(qemu_serial))); - } - log(LogLevel::Info, "Boot: Configured kernel logging devices.") + if log_device_list.contains(&"serial") { + LOGGER.add_subscriber(qemu_serial); } - log( - LogLevel::Info, - &format!( - "Boot: Kernel cmdline: {}", - String::from_utf8_lossy( - limine::file::File::string(executable_file_response.file()).to_bytes() - ) - ), - ); - log( - LogLevel::Info, - &format!( - "Boot: Kernel file path: {}", - String::from_utf8_lossy(executable_file_response.file().path().to_bytes()) - ), - ); + log_trace!("Boot: Configured kernel logging devices"); } - - log( - LogLevel::Info, - &format!( - "Boot: Booting gila version {KERNEL_VERSION_MAJOR}.{KERNEL_VERSION_MINOR}.{KERNEL_VERSION_PATCH}" - ), + log_info!( + "Boot: Kernel cmdline: {}", + String::from_utf8_lossy( + limine::file::File::string(executable_file_response.file()).to_bytes() + ) + ); + log_info!( + "Boot: Kernel file path: {}", + String::from_utf8_lossy(executable_file_response.file().path().to_bytes()) + ); + log_info!( + "Boot: Booting gila version {KERNEL_VERSION_MAJOR}.{KERNEL_VERSION_MINOR}.{KERNEL_VERSION_PATCH}" ); - log(LogLevel::Info, "Boot: Trans Rights!"); - - if let Some(address_response) = ADDRESS_REQUEST.get_response() { - log( - LogLevel::Trace, - &format!( - "Boot: Kernel address: 0x{:0x}", - address_response.physical_base() - ), - ) - } + log_info!("Boot: Trans rights!"); if let Some(framebuffer_response) = FRAMEBUFFER_REQUEST.get_response() { let fb = framebuffer_response.framebuffers().next().unwrap(); - log(LogLevel::Info, "Boot: Framebuffer response received"); - log( - LogLevel::Trace, - &format!( - "Boot: Framebuffer dimensions: {}x{}, {}", - fb.width(), - fb.height(), - fb.bpp() - ), + log_info!("Boot: Framebuffer response received"); + log_trace!( + "Boot: Framebuffer dimensions: {}x{}, {} bits per pixel", + fb.width(), + fb.height(), + fb.bpp() ); + } else { + log_info!("Boot: Framebuffer response absent, graphics disabled",); } - let _smp_response = MP_REQUEST.get_response(); - match _smp_response { - None => log(LogLevel::Error, "MP: Multiprocessing response not received"), + let smp_response = MP_REQUEST.get_response(); + match smp_response { + None => log_info!("MP: Multiprocessing response not received"), Some(resp) => { - log(LogLevel::Info, "MP: Multiprocessing response received"); - log( - LogLevel::Info, - &format!("MP: {} CPUs found", resp.cpus().len()), - ); + log_info!("MP: Multiprocessing response received"); + log_trace!("MP: {} CPUs found", resp.cpus().len()); } } let _rsdp_response = RSDP_REQUEST.get_response(); - // TODO: Get the initramfs - if let Some(module_response) = MODULE_REQUEST.get_response() { - log( - LogLevel::Info, - &format!( - "Boot: {} kernel modules found", - module_response.modules().len() - ), - ); - if !module_response.modules().is_empty() { - log(LogLevel::Info, "Boot: Kernel modules list:"); - for module in module_response.modules() { - log( - LogLevel::Info, - &format!("\t{}", String::from_utf8_lossy(module.path().to_bytes())), - ) - } - } - if let Some(irfs_path) = params.get("-initramfs") { - log( - LogLevel::Info, - &format!("Boot: initramfs path requested: {irfs_path}"), - ); - let initramfs_option: Option<&File> = { - let mut result: Option<&File> = None; - for file in module_response.modules() { - if &file.path().to_string_lossy().to_string() == irfs_path { - result = Some(file); - } - } - result - }; - if let Some(_initramfs_file) = initramfs_option { - log(LogLevel::Info, "Boot: Found initramfs at supplied path") - } + let module_response = MODULE_REQUEST + .get_response() + .expect("Bootloader did not return kernel modules"); + log_info!( + "Boot: {} kernel modules found", + module_response.modules().len() + ); + if !module_response.modules().is_empty() { + log_trace!("Boot: Kernel modules list:"); + for module in module_response.modules() { + log_trace!("\t{}", String::from_utf8_lossy(module.path().to_bytes())); } } + let irfs_path = { + if let Some(key) = params.get("-initramfs") { + key + } else { + INITRAMFS_DEFAULT_PATH + } + }; + + log_trace!("Boot: initramfs path requested: {irfs_path}"); + let _initramfs = { + let mut result: Option<&File> = None; + for file in module_response.modules() { + if file.path().to_string_lossy() == irfs_path { + result = Some(file); + log_info!("Boot: initramfs found"); + } + } + result + } + .expect("initramfs not found in modules list"); + if let Some(mmap_response) = MEMMAP_REQUEST.get_response() { - log(LogLevel::Info, "Boot: Memory map received"); + log_info!("Boot: Memory map received"); if !mmap_response.entries().is_empty() { - log(LogLevel::Info, "Boot: Memory map entries list:"); + log_trace!("Boot: Memory map entries list:"); let mut usable: u64 = 0; let mut reclaimable: u64 = 0; + let mut hardware: u64 = 0; + let mut unusable: u64 = 0; for entry in mmap_response.entries() { - log( - LogLevel::Info, - &format!( - "\t0x{:x} @ 0x{:x}: {}", - entry.length, - entry.base, - match entry.entry_type { - EntryType::ACPI_NVS => "ACPI (reserved)", - EntryType::ACPI_RECLAIMABLE => { - reclaimable += entry.length; - "ACPI (reclaimable)" - } - EntryType::BAD_MEMORY => "damaged/unusable", - EntryType::BOOTLOADER_RECLAIMABLE => { - reclaimable += entry.length; - "bootloader (reclaimable)" - } - #[allow(unreachable_patterns, deprecated)] - EntryType::EXECUTABLE_AND_MODULES | EntryType::KERNEL_AND_MODULES => - "executable & modules", - EntryType::FRAMEBUFFER => "framebuffer", - EntryType::RESERVED => "reserved", - EntryType::USABLE => { - usable += entry.length; - "usable" - } - _ => "unidentified", + log_trace!( + "\t{} bytes @ 0x{:x}: {}", + entry.length, + entry.base, + match entry.entry_type { + EntryType::ACPI_NVS => { + hardware += entry.length; + "ACPI (reserved)" } - ), + EntryType::ACPI_RECLAIMABLE => { + reclaimable += entry.length; + "ACPI (reclaimable)" + } + EntryType::BAD_MEMORY => { + unusable += entry.length; + "damaged/unusable" + } + EntryType::BOOTLOADER_RECLAIMABLE => { + reclaimable += entry.length; + "bootloader (reclaimable)" + } + #[allow(unreachable_patterns, deprecated)] + EntryType::EXECUTABLE_AND_MODULES | EntryType::KERNEL_AND_MODULES => { + unusable += entry.length; + "executable & modules" + } + EntryType::FRAMEBUFFER => { + hardware += entry.length; + "framebuffer" + } + EntryType::RESERVED => { + unusable += entry.length; + "reserved" + } + EntryType::USABLE => { + usable += entry.length; + "usable" + } + _ => "unidentified", + } ) } - log( - LogLevel::Info, - &format!( - "Boot: Memory report: {usable} bytes usable, {reclaimable} bytes reclaimable, {} bytes ultimately available", - usable + reclaimable - ), - ) + log_info!( + "Boot: Memory report:\n\tFree: {usable}\n\tAvailable: {reclaimable}\n\tUsable: {}\n\tHardware: {hardware}\n\tUnusable: {unusable}\n\tTotal: {}", + usable + reclaimable, + usable + reclaimable + hardware + unusable + ); } } + panic!("Test panic"); + + #[allow(unreachable_code)] loop { - for _i in 0..100000000 { + for _i in 0..50000000 { unsafe { core::arch::asm!("nop"); } } - log(LogLevel::Trace, "Heartbeat") + log_trace!("Heartbeat"); } } diff --git a/src/kernel/panic.rs b/src/kernel/panic.rs index 3869a71..cd5d80a 100644 --- a/src/kernel/panic.rs +++ b/src/kernel/panic.rs @@ -1,9 +1,23 @@ // Copyright (c) 2025 shibedrill // SPDX-License-Identifier: GPL-3.0-or-later +use core::arch::asm; use core::panic::*; +use crate::format; + +use crate::{LOGGER, LogLevel}; + #[panic_handler] -pub fn panic(_info: &PanicInfo) -> ! { - loop {} +pub fn panic(info: &PanicInfo) -> ! { + log_critical!( + "Panic in {}: {}", + info.location().unwrap(), + info.message().as_str().unwrap_or("missing panic message"), + ); + loop { + unsafe { + asm!("nop"); + } + } } diff --git a/src/kernel/syscall_runner.rs b/src/kernel/syscall_runner.rs index be6d0a7..6bb8838 100644 --- a/src/kernel/syscall_runner.rs +++ b/src/kernel/syscall_runner.rs @@ -5,29 +5,6 @@ use crate::process::Process; -// FUCKING ADD CONST UNWRAP!!! -pub static KERNEL_VERSION_MAJOR: u8 = match u8::from_str_radix(env!("CARGO_PKG_VERSION_MAJOR"), 10) -{ - Ok(ver) => ver, - Err(_) => { - panic!("Invalid major version number ") - } -}; -pub static KERNEL_VERSION_MINOR: u8 = match u8::from_str_radix(env!("CARGO_PKG_VERSION_MINOR"), 10) -{ - Ok(ver) => ver, - Err(_) => { - panic!("Invalid minor version number ") - } -}; -pub static KERNEL_VERSION_PATCH: u8 = match u8::from_str_radix(env!("CARGO_PKG_VERSION_PATCH"), 10) -{ - Ok(ver) => ver, - Err(_) => { - panic!("Invalid patch version number ") - } -}; - #[allow(unused_variables)] pub fn run_syscall(process: &mut Process) { // Get the syscall ID from the process's CPU registers.