diff --git a/Makefile b/Makefile index 13b013f47..56a334c03 100644 --- a/Makefile +++ b/Makefile @@ -11,6 +11,7 @@ GDB_TCP_PORT ?= 1234 INTEL_TDX ?= 0 RELEASE ?= 0 RELEASE_LTO ?= 0 +LOG_LEVEL ?= error SCHEME ?= "" # End of global options. @@ -24,7 +25,7 @@ SYSCALL_TEST_DIR ?= /tmp CARGO_OSDK := ~/.cargo/bin/cargo-osdk -CARGO_OSDK_ARGS := --target-arch=$(ARCH) +CARGO_OSDK_ARGS := --target-arch=$(ARCH) --kcmd-args="ostd.log_level=$(LOG_LEVEL)" ifeq ($(AUTO_TEST), syscall) BUILD_SYSCALL_TEST := 1 diff --git a/ostd/src/boot/kcmdline.rs b/ostd/src/boot/kcmdline.rs index 97d650dd6..517610b87 100644 --- a/ostd/src/boot/kcmdline.rs +++ b/ostd/src/boot/kcmdline.rs @@ -18,7 +18,7 @@ use alloc::{ vec::Vec, }; -use log::warn; +use crate::early_println; #[derive(PartialEq, Debug)] struct InitprocArgs { @@ -116,7 +116,10 @@ impl From<&str> for KCmdlineArg { 1 => (arg_pattern[0], None), 2 => (arg_pattern[0], Some(arg_pattern[1])), _ => { - warn!("Unable to parse kernel argument {}, skip for now", arg); + early_println!( + "[KCmdline] Unable to parse kernel argument {}, skip for now", + arg + ); continue; } }; @@ -126,9 +129,10 @@ impl From<&str> for KCmdlineArg { 1 => (None, entry_pattern[0]), 2 => (Some(entry_pattern[0]), entry_pattern[1]), _ => { - warn!( - "Unable to parse entry {} in argument {}, skip for now", - entry, arg + early_println!( + "[KCmdline] Unable to parse entry {} in argument {}, skip for now", + entry, + arg ); continue; } diff --git a/ostd/src/lib.rs b/ostd/src/lib.rs index 4e7ab6e51..d1b0645a2 100644 --- a/ostd/src/lib.rs +++ b/ostd/src/lib.rs @@ -59,7 +59,6 @@ pub use self::{cpu::cpu_local::CpuLocal, error::Error, prelude::Result}; /// boot stage only global variables. pub fn init() { arch::before_all_init(); - logger::init(); #[cfg(feature = "intel_tdx")] let td_info = init_tdx().unwrap(); @@ -73,6 +72,7 @@ pub fn init() { mm::heap_allocator::init(); boot::init(); + logger::init(); mm::page::allocator::init(); mm::kspace::init_boot_page_table(); diff --git a/ostd/src/logger.rs b/ostd/src/logger.rs index 5cf313008..b37a1ae7c 100644 --- a/ostd/src/logger.rs +++ b/ostd/src/logger.rs @@ -2,23 +2,20 @@ //! Logging support. -use log::{Level, Metadata, Record}; +use log::{LevelFilter, Metadata, Record}; -use crate::early_println; +use crate::{ + boot::{kcmdline::ModuleArg, kernel_cmdline}, + early_println, +}; const LOGGER: Logger = Logger {}; -/// The log level. -/// -/// FIXME: The logs should be able to be read from files in the userspace, -/// and the log level should be configurable. -pub const INIT_LOG_LEVEL: Level = Level::Error; - struct Logger {} impl log::Log for Logger { fn enabled(&self, metadata: &Metadata) -> bool { - metadata.level() <= INIT_LOG_LEVEL + metadata.level() <= log::max_level() } fn log(&self, record: &Record) { @@ -30,8 +27,33 @@ impl log::Log for Logger { fn flush(&self) {} } +/// Initialize the logger. Users should avoid using the log macros before this function is called. pub(crate) fn init() { - log::set_logger(&LOGGER) - .map(|()| log::set_max_level(INIT_LOG_LEVEL.to_level_filter())) - .unwrap(); + let level = get_log_level().unwrap_or(LevelFilter::Off); + + log::set_max_level(level); + log::set_logger(&LOGGER).unwrap(); +} + +fn get_log_level() -> Option { + let module_args = kernel_cmdline().get_module_args("ostd")?; + + let arg = module_args.iter().find(|arg| match arg { + ModuleArg::Arg(_) => false, + ModuleArg::KeyVal(name, _) => name.as_bytes() == "log_level".as_bytes(), + })?; + + let ModuleArg::KeyVal(_, value) = arg else { + unreachable!() + }; + let value = value.as_c_str().to_str().unwrap_or("off"); + Some(match value { + "error" => LevelFilter::Error, + "warn" => LevelFilter::Warn, + "info" => LevelFilter::Info, + "debug" => LevelFilter::Debug, + "trace" => LevelFilter::Trace, + // Otherwise, OFF + _ => LevelFilter::Off, + }) }