diff options
Diffstat (limited to 'crates')
-rw-r--r-- | crates/kernel/src/lib.rs | 5 | ||||
-rw-r--r-- | crates/kernel/src/logger.rs | 71 |
2 files changed, 73 insertions, 3 deletions
diff --git a/crates/kernel/src/lib.rs b/crates/kernel/src/lib.rs index eff6d36..8e418e7 100644 --- a/crates/kernel/src/lib.rs +++ b/crates/kernel/src/lib.rs @@ -11,6 +11,7 @@ use vernos_utils::dbg; mod panic; pub mod arch; +pub mod logger; /// The entrypoint to the kernel. This should be executed by hart0 alone. It performs some early /// boot tasks, then wakes up any other harts. @@ -25,9 +26,7 @@ pub mod arch; #[no_mangle] pub unsafe extern "C" fn hart0_boot(device_tree: *const u8) -> ! { // Set up the logger. - // - // TODO: This should really be named something better than console. - // console::init(); + logger::init(); // Parse the DeviceTree. let flattened_device_tree = diff --git a/crates/kernel/src/logger.rs b/crates/kernel/src/logger.rs new file mode 100644 index 0000000..696c9a6 --- /dev/null +++ b/crates/kernel/src/logger.rs @@ -0,0 +1,71 @@ +//! The logger used to store logs from the kernel. This accepts logs from the `log` crate, and +//! delivers them to console devices. + +use core::fmt::{self, Write}; + +/// Initializes the logger. This should be called exactly once, early in boot. +pub fn init() { + log::set_logger(&Logger).expect("failed to set logger"); + log::set_max_level(log::LevelFilter::Trace); + log::warn!("Using a bad unportable logger that only works on qemu-virt"); +} + +struct BadRiscvWrite; + +impl Write for BadRiscvWrite { + fn write_str(&mut self, s: &str) -> fmt::Result { + let ptr = 0x10000000 as *mut u8; + for b in s.bytes() { + unsafe { ptr.write_volatile(b) }; + } + Ok(()) + } +} + +pub struct Logger; + +impl log::Log for Logger { + fn enabled(&self, _metadata: &log::Metadata) -> bool { + true + } + + fn log(&self, record: &log::Record) { + if !self.enabled(record.metadata()) { + return; + } + + let body = |line| { + let level = match record.level() { + log::Level::Error => "\x1b[1;31mERR\x1b[0m", + log::Level::Warn => "\x1b[1;33mWRN\x1b[0m", + log::Level::Info => "\x1b[1;36mINF\x1b[0m", + log::Level::Debug => "\x1b[1;35mDBG\x1b[0m", + log::Level::Trace => "TRC", + }; + let file = record.file().unwrap_or("???"); + let args = record.args(); + + let result = if args.as_str() == Some("") { + // A silly convenience, but don't write the extra space if we're + // not going to write anything anyways. + writeln!(BadRiscvWrite, "[{level}][{file}:{line}]") + } else { + writeln!(BadRiscvWrite, "[{level}][{file}:{line}] {args}") + }; + + // UNWRAP: Since the fmt::Write impl for ConsoleInner has a + // contract promising that it won't ever return an error, this + // should be unreachable. + result.unwrap(); + }; + + // Some contortions to avoid running afoul of the lifetime requirements + // of format_args... + match record.line() { + Some(line) => body(format_args!("{line}")), + None => body(format_args!("???")), + } + } + + fn flush(&self) {} +} |