diff --git a/api/build.rs b/api/build.rs index a5e4b72d..bacb5bf9 100644 --- a/api/build.rs +++ b/api/build.rs @@ -22,6 +22,7 @@ fn main() { (88, 9), (97, 9), (106, 9), + (115, 1), ]; let mut code = String::new(); diff --git a/api/src/config.rs b/api/src/config.rs index 3eb4fb87..a7660746 100644 --- a/api/src/config.rs +++ b/api/src/config.rs @@ -27,6 +27,10 @@ pub struct BootloaderConfig { /// Configuration for the frame buffer that can be used by the kernel to display pixels /// on the screen. pub frame_buffer: FrameBuffer, + + /// Configuration for changing the level of the filter of the messages that are shown in the + /// screen when booting. The default is 'Trace'. + pub log_level: LevelFilter, } impl BootloaderConfig { @@ -35,7 +39,7 @@ impl BootloaderConfig { 0x3D, ]; #[doc(hidden)] - pub const SERIALIZED_LEN: usize = 115; + pub const SERIALIZED_LEN: usize = 116; /// Creates a new default configuration with the following values: /// @@ -48,6 +52,7 @@ impl BootloaderConfig { version: ApiVersion::new_default(), mappings: Mappings::new_default(), frame_buffer: FrameBuffer::new_default(), + log_level: LevelFilter::Trace, } } @@ -61,6 +66,7 @@ impl BootloaderConfig { mappings, kernel_stack_size, frame_buffer, + log_level, } = self; let ApiVersion { version_major, @@ -133,13 +139,15 @@ impl BootloaderConfig { }, ); - concat_106_9( + let buf = concat_106_9( buf, match minimum_framebuffer_width { Option::None => [0; 9], Option::Some(addr) => concat_1_8([1], addr.to_le_bytes()), }, - ) + ); + + concat_115_1(buf, (*log_level as u8).to_le_bytes()) } /// Tries to deserialize a config byte array that was created using [`Self::serialize`]. @@ -252,6 +260,13 @@ impl BootloaderConfig { (frame_buffer, s) }; + let (&log_level, s) = split_array_ref(s); + let log_level = LevelFilter::from_u8(u8::from_le_bytes(log_level)); + let log_level = match log_level { + Option::Some(level) => level, + Option::None => return Err("log_level invalid"), + }; + if !s.is_empty() { return Err("unexpected rest"); } @@ -261,6 +276,7 @@ impl BootloaderConfig { kernel_stack_size: u64::from_le_bytes(kernel_stack_size), mappings, frame_buffer, + log_level, }) } @@ -271,6 +287,7 @@ impl BootloaderConfig { mappings: Mappings::random(), kernel_stack_size: rand::random(), frame_buffer: FrameBuffer::random(), + log_level: LevelFilter::Trace, } } } @@ -534,6 +551,42 @@ impl Default for Mapping { } } +/// An enum representing the available verbosity level filters of the logger. +/// +/// Based on +/// https://github.com/rust-lang/log/blob/dc32ab999f52805d5ce579b526bd9d9684c38d1a/src/lib.rs#L552-565 +#[repr(u8)] +#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub enum LevelFilter { + /// A level lower than all log levels. + Off, + /// Corresponds to the `Error` log level. + Error, + /// Corresponds to the `Warn` log level. + Warn, + /// Corresponds to the `Info` log level. + Info, + /// Corresponds to the `Debug` log level. + Debug, + /// Corresponds to the `Trace` log level. + Trace, +} + +impl LevelFilter { + /// Converts a u8 into a Option + pub fn from_u8(value: u8) -> Option { + match value { + 0 => Some(Self::Off), + 1 => Some(Self::Error), + 2 => Some(Self::Warn), + 3 => Some(Self::Info), + 4 => Some(Self::Debug), + 5 => Some(Self::Trace), + _ => None, + } + } +} + /// Taken from https://github.com/rust-lang/rust/blob/e100ec5bc7cd768ec17d75448b29c9ab4a39272b/library/core/src/slice/mod.rs#L1673-L1677 /// /// TODO replace with `split_array` feature in stdlib as soon as it's stabilized, diff --git a/bios/stage-4/src/main.rs b/bios/stage-4/src/main.rs index bd44b396..d6a50b9c 100644 --- a/bios/stage-4/src/main.rs +++ b/bios/stage-4/src/main.rs @@ -2,7 +2,10 @@ #![no_main] use crate::memory_descriptor::MemoryRegion; -use bootloader_api::info::{FrameBufferInfo, PixelFormat}; +use bootloader_api::{ + config::LevelFilter, + info::{FrameBufferInfo, PixelFormat}, +}; use bootloader_x86_64_bios_common::{BiosFramebufferInfo, BiosInfo, E820MemoryRegion}; use bootloader_x86_64_common::RawFrameBufferInfo; use bootloader_x86_64_common::{ @@ -24,10 +27,6 @@ mod memory_descriptor; #[no_mangle] #[link_section = ".start"] pub extern "C" fn _start(info: &mut BiosInfo) -> ! { - let framebuffer_info = init_logger(info.framebuffer); - log::info!("4th Stage"); - log::info!("{info:x?}"); - let memory_map: &mut [E820MemoryRegion] = unsafe { core::slice::from_raw_parts_mut( info.memory_map_addr as *mut _, @@ -102,8 +101,6 @@ pub extern "C" fn _start(info: &mut BiosInfo) -> ! { // it's mapped using `invlpg`, for efficiency. x86_64::instructions::tlb::flush_all(); - log::info!("BIOS boot"); - let page_tables = create_page_tables(&mut frame_allocator); let kernel_slice = { @@ -112,6 +109,12 @@ pub extern "C" fn _start(info: &mut BiosInfo) -> ! { }; let kernel = Kernel::parse(kernel_slice); + let framebuffer_info = init_logger(info.framebuffer, kernel.config.log_level); + + log::info!("4th Stage"); + log::info!("{info:x?}"); + log::info!("BIOS boot"); + let system_info = SystemInfo { framebuffer: Some(RawFrameBufferInfo { addr: PhysAddr::new(info.framebuffer.region.start), @@ -123,7 +126,7 @@ pub extern "C" fn _start(info: &mut BiosInfo) -> ! { load_and_switch_to_kernel(kernel, frame_allocator, page_tables, system_info); } -fn init_logger(info: BiosFramebufferInfo) -> FrameBufferInfo { +fn init_logger(info: BiosFramebufferInfo, log_level: LevelFilter) -> FrameBufferInfo { let framebuffer_info = FrameBufferInfo { byte_len: info.region.len.try_into().unwrap(), width: info.width.into(), @@ -152,7 +155,7 @@ fn init_logger(info: BiosFramebufferInfo) -> FrameBufferInfo { ) }; - bootloader_x86_64_common::init_logger(framebuffer, framebuffer_info); + bootloader_x86_64_common::init_logger(framebuffer, framebuffer_info, log_level); framebuffer_info } diff --git a/common/src/lib.rs b/common/src/lib.rs index 4a204972..fc1c7d59 100644 --- a/common/src/lib.rs +++ b/common/src/lib.rs @@ -4,7 +4,7 @@ use crate::legacy_memory_region::{LegacyFrameAllocator, LegacyMemoryRegion}; use bootloader_api::{ - config::Mapping, + config::{LevelFilter, Mapping}, info::{FrameBuffer, FrameBufferInfo, MemoryRegion, TlsTemplate}, BootInfo, BootloaderConfig, }; @@ -35,13 +35,24 @@ pub mod logger; const PAGE_SIZE: u64 = 4096; /// Initialize a text-based logger using the given pixel-based framebuffer as output. -pub fn init_logger(framebuffer: &'static mut [u8], info: FrameBufferInfo) { +pub fn init_logger(framebuffer: &'static mut [u8], info: FrameBufferInfo, log_level: LevelFilter) { let logger = logger::LOGGER.get_or_init(move || logger::LockedLogger::new(framebuffer, info)); log::set_logger(logger).expect("logger already set"); - log::set_max_level(log::LevelFilter::Trace); + log::set_max_level(convert_level(log_level)); log::info!("Framebuffer info: {:?}", info); } +fn convert_level(level: LevelFilter) -> log::LevelFilter { + match level { + LevelFilter::Off => log::LevelFilter::Off, + LevelFilter::Error => log::LevelFilter::Error, + LevelFilter::Warn => log::LevelFilter::Warn, + LevelFilter::Info => log::LevelFilter::Info, + LevelFilter::Debug => log::LevelFilter::Debug, + LevelFilter::Trace => log::LevelFilter::Trace, + } +} + /// Required system information that should be queried from the BIOS or UEFI firmware. #[derive(Debug, Copy, Clone)] pub struct SystemInfo { diff --git a/uefi/src/main.rs b/uefi/src/main.rs index e94bc00c..d96d60c1 100644 --- a/uefi/src/main.rs +++ b/uefi/src/main.rs @@ -420,7 +420,7 @@ fn init_logger(st: &SystemTable, config: BootloaderConfig) -> Option