//! Kernel I/O helpers and logging frontend. //! //! Provides a lightweight logger implementation routing to UART and helper //! macros for printing from kernel code. use crate::print; use crate::tty::{TTY_INITIALIZED, TTY0}; use alloc::format; use io::Write; use log::{Level, Metadata, Record}; use log::{LevelFilter, SetLoggerError}; use crate::uart::write_uart; /// Print a string to the kernel console (via UART). /// /// Accepts any type that implements `AsRef` to avoid unnecessary /// allocations at call sites. pub(crate) fn print>(content: T) { if TTY_INITIALIZED.load(core::sync::atomic::Ordering::Relaxed) { unsafe { TTY0.new_node().write(content.as_ref().as_bytes()).unwrap() }; } else { write_uart(&content); } } /// Logger implementation that routes kernel log records to the UART-based console. pub struct Logger; impl log::Log for Logger { fn enabled(&self, metadata: &Metadata) -> bool { metadata.level() <= Level::Info } fn log(&self, record: &Record) { if self.enabled(record.metadata()) { let to_print = if let Some((file, line)) = record.file().zip(record.line()) { format!( "[{}] at {}:{} - {}\n", record.level(), file, line, record.args() ) } else { format!("[{}] - {}\n", record.level(), record.args()) }; print!("{to_print}"); } } fn flush(&self) {} } pub static LOGGER: Logger = Logger; /// Initialize the kernel logger and set the default level. /// /// Returns an error if a global logger has already been set. pub fn init_log() -> Result<(), SetLoggerError> { log::set_logger(&LOGGER).map(|()| log::set_max_level(LevelFilter::Info)) } #[macro_export] macro_rules! print { ($($args:expr),*) => { $crate::io::print(alloc::format!($($args),*)) }; } #[macro_export] macro_rules! println { () => { $crate::print!("\n") }; ($($args:expr),*) => {{ $crate::print!("{}\n", alloc::format!($($args),*)); }}; }