From 52832335f5a9a02747eaf69a09d8f67e3e0e7047 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juanjo=20Asensio=20Garc=C3=ADa?= Date: Sat, 14 Jan 2023 22:34:42 +0100 Subject: [PATCH 1/9] Add support for a configuration file --- Cargo.lock | 102 ++++++++++++++++++++++++++++++++++--- api/build.rs | 5 -- api/src/config.rs | 107 +-------------------------------------- bios/common/src/lib.rs | 1 + bios/stage-2/src/main.rs | 12 +++++ bios/stage-4/src/main.rs | 22 ++++---- common/Cargo.toml | 2 + common/src/lib.rs | 9 +++- common/src/logger.rs | 4 +- src/bios/mod.rs | 11 ++++ src/lib.rs | 1 + src/uefi/mod.rs | 11 ++++ uefi/src/main.rs | 20 ++++++-- 13 files changed, 172 insertions(+), 135 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6fbaa43d..adfc9f59 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -79,6 +79,15 @@ version = "4.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a40729d2133846d9ed0ea60a8b9541bccddab49cd30f0715a1da672fe9a2524" +[[package]] +name = "atomic-polyfill" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3ff7eb3f316534d83a8a2c3d1674ace8a5a71198eba31e2e2b597833f699b28" +dependencies = [ + "critical-section", +] + [[package]] name = "atomic-waker" version = "1.0.0" @@ -208,6 +217,8 @@ dependencies = [ "rand", "rand_hc", "raw-cpuid", + "serde", + "serde-json-core", "spinning_top", "uart_16550", "usize_conversions", @@ -312,6 +323,12 @@ dependencies = [ "build_const", ] +[[package]] +name = "critical-section" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6548a0ad5d2549e111e1f6a11a6c2e2d00ce6a3dafe22948d67c2b443f775e52" + [[package]] name = "crossbeam-utils" version = "0.8.14" @@ -492,6 +509,28 @@ dependencies = [ "uuid", ] +[[package]] +name = "hash32" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0c35f58762feb77d74ebe43bdbc3210f09be9fe6742234d573bacc26ed92b67" +dependencies = [ + "byteorder", +] + +[[package]] +name = "heapless" +version = "0.7.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db04bc24a18b9ea980628ecf00e6c0264f3c1426dac36c00cb49b6fbad8b0743" +dependencies = [ + "atomic-polyfill", + "hash32", + "rustc_version", + "spin", + "stable_deref_trait", +] + [[package]] name = "instant" version = "0.1.12" @@ -657,9 +696,9 @@ checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872" [[package]] name = "proc-macro2" -version = "1.0.39" +version = "1.0.49" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c54b25569025b7fc9651de43004ae593a75ad88543b17178aa5e1b9c4f15f56f" +checksum = "57a8eca9f9c4ffde41714334dee777596264c7825420f521abc92b5b5deb63a5" dependencies = [ "unicode-ident", ] @@ -754,23 +793,44 @@ dependencies = [ "log", ] +[[package]] +name = "rustc_version" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +dependencies = [ + "semver", +] + [[package]] name = "rustversion" version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f2cc38e8fa666e2de3c4aba7edeb5ffc5246c1c2ed0e3d17e560aeeba736b23f" +[[package]] +name = "ryu" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b4b9743ed687d4b4bcedf9ff5eaa7398495ae14e61cba0a295704edbc7decde" + [[package]] name = "scopeguard" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" +[[package]] +name = "semver" +version = "1.0.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58bc9567378fc7690d6b2addae4e60ac2eeea07becb2c64b9f218b53865cba2a" + [[package]] name = "serde" -version = "1.0.136" +version = "1.0.152" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce31e24b01e1e524df96f1c2fdd054405f8d7376249a5110886fb4b658484789" +checksum = "bb7d1f0d3021d347a83e556fc4683dea2ea09d87bccdf88ff5c12545d89d5efb" dependencies = [ "serde_derive", ] @@ -784,11 +844,22 @@ dependencies = [ "serde", ] +[[package]] +name = "serde-json-core" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58ec3c8fe427f45ee3aaa0ebb9f0d9ab8ae9ad05d12047fe7249ae5ea9374ff0" +dependencies = [ + "heapless", + "ryu", + "serde", +] + [[package]] name = "serde_derive" -version = "1.0.136" +version = "1.0.152" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08597e7152fcd306f41838ed3e37be9eaeed2b61c42e2117266a554fab4662f9" +checksum = "af487d118eecd09402d70a5d72551860e788df87b464af30e5ea6a38c75c541e" dependencies = [ "proc-macro2", "quote", @@ -833,6 +904,15 @@ dependencies = [ "winapi", ] +[[package]] +name = "spin" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f6002a767bff9e83f8eeecf883ecb8011875a21ae8da43bffb817a57e78cc09" +dependencies = [ + "lock_api", +] + [[package]] name = "spinning_top" version = "0.2.4" @@ -842,6 +922,12 @@ dependencies = [ "lock_api", ] +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + [[package]] name = "strip-ansi-escapes" version = "0.1.1" @@ -853,9 +939,9 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.95" +version = "1.0.107" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbaf6116ab8924f39d52792136fb74fd60a80194cf1b1c6ffa6453eef1c3f942" +checksum = "1f4064b5b16e03ae50984a5a8ed5d4f8803e6bc1fd170a3cda91a1be4b18e3f5" dependencies = [ "proc-macro2", "quote", diff --git a/api/build.rs b/api/build.rs index 99235653..e7e06a99 100644 --- a/api/build.rs +++ b/api/build.rs @@ -21,11 +21,6 @@ fn main() { (79, 9), (88, 9), (97, 9), - (106, 9), - (115, 9), - (124, 1), - (125, 1), - (126, 1), ]; let mut code = String::new(); diff --git a/api/src/config.rs b/api/src/config.rs index 7b91a4bd..32d2f67c 100644 --- a/api/src/config.rs +++ b/api/src/config.rs @@ -23,24 +23,6 @@ pub struct BootloaderConfig { /// the stack size that the bootloader should allocate and map. The stack is created /// with a guard page, so a stack overflow will lead to a page fault. pub kernel_stack_size: u64, - - /// 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, - - /// Whether the bootloader should print log messages to the framebuffer when booting. - /// - /// Enabled by default. - pub frame_buffer_logger_status: LoggerStatus, - - /// Whether the bootloader should print log messages to the serial port when booting. - /// - /// Enabled by default. - pub serial_logger_status: LoggerStatus, } impl BootloaderConfig { @@ -49,7 +31,7 @@ impl BootloaderConfig { 0x3D, ]; #[doc(hidden)] - pub const SERIALIZED_LEN: usize = 127; + pub const SERIALIZED_LEN: usize = 106; /// Creates a new default configuration with the following values: /// @@ -61,10 +43,6 @@ impl BootloaderConfig { kernel_stack_size: 80 * 1024, version: ApiVersion::new_default(), mappings: Mappings::new_default(), - frame_buffer: FrameBuffer::new_default(), - log_level: LevelFilter::Trace, - frame_buffer_logger_status: LoggerStatus::Enable, - serial_logger_status: LoggerStatus::Enable, } } @@ -77,10 +55,6 @@ impl BootloaderConfig { version, mappings, kernel_stack_size, - frame_buffer, - log_level, - frame_buffer_logger_status, - serial_logger_status, } = self; let ApiVersion { version_major, @@ -99,10 +73,6 @@ impl BootloaderConfig { dynamic_range_end, ramdisk_memory, } = mappings; - let FrameBuffer { - minimum_framebuffer_height, - minimum_framebuffer_width, - } = frame_buffer; let version = { let one = concat_2_2(version_major.to_le_bytes(), version_minor.to_le_bytes()); @@ -146,33 +116,7 @@ impl BootloaderConfig { }, ); - let buf = concat_97_9(buf, ramdisk_memory.serialize()); - - let buf = concat_106_9( - buf, - match minimum_framebuffer_height { - Option::None => [0; 9], - Option::Some(addr) => concat_1_8([1], addr.to_le_bytes()), - }, - ); - - let buf = concat_115_9( - buf, - match minimum_framebuffer_width { - Option::None => [0; 9], - Option::Some(addr) => concat_1_8([1], addr.to_le_bytes()), - }, - ); - - let log_level = concat_124_1(buf, (*log_level as u8).to_le_bytes()); - - let frame_buffer_logger_status = - concat_125_1(log_level, (*frame_buffer_logger_status as u8).to_le_bytes()); - - concat_126_1( - frame_buffer_logger_status, - (*serial_logger_status as u8).to_le_bytes(), - ) + concat_97_9(buf, ramdisk_memory.serialize()) } /// Tries to deserialize a config byte array that was created using [`Self::serialize`]. @@ -266,49 +210,6 @@ impl BootloaderConfig { (mappings, s) }; - let (frame_buffer, s) = { - let (&min_framebuffer_height_some, s) = split_array_ref(s); - let (&min_framebuffer_height, s) = split_array_ref(s); - let (&min_framebuffer_width_some, s) = split_array_ref(s); - let (&min_framebuffer_width, s) = split_array_ref(s); - - let frame_buffer = FrameBuffer { - minimum_framebuffer_height: match min_framebuffer_height_some { - [0] if min_framebuffer_height == [0; 8] => Option::None, - [1] => Option::Some(u64::from_le_bytes(min_framebuffer_height)), - _ => return Err("minimum_framebuffer_height invalid"), - }, - minimum_framebuffer_width: match min_framebuffer_width_some { - [0] if min_framebuffer_width == [0; 8] => Option::None, - [1] => Option::Some(u64::from_le_bytes(min_framebuffer_width)), - _ => return Err("minimum_framebuffer_width invalid"), - }, - }; - (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"), - }; - - let (&frame_buffer_logger_status, s) = split_array_ref(s); - let frame_buffer_logger_status = - LoggerStatus::from_u8(u8::from_le_bytes(frame_buffer_logger_status)); - let frame_buffer_logger_status = match frame_buffer_logger_status { - Option::Some(status) => status, - Option::None => return Err("frame_buffer_logger_status invalid"), - }; - - let (&serial_logger_status, s) = split_array_ref(s); - let serial_logger_status = LoggerStatus::from_u8(u8::from_le_bytes(serial_logger_status)); - let serial_logger_status = match serial_logger_status { - Option::Some(status) => status, - Option::None => return Err("serial_logger_status invalid"), - }; - if !s.is_empty() { return Err("unexpected rest"); } @@ -317,10 +218,6 @@ impl BootloaderConfig { version, kernel_stack_size: u64::from_le_bytes(kernel_stack_size), mappings, - frame_buffer, - log_level, - frame_buffer_logger_status, - serial_logger_status, }) } diff --git a/bios/common/src/lib.rs b/bios/common/src/lib.rs index 59a7737d..6d34e559 100644 --- a/bios/common/src/lib.rs +++ b/bios/common/src/lib.rs @@ -8,6 +8,7 @@ pub struct BiosInfo { pub stage_4: Region, pub kernel: Region, pub ramdisk: Region, + pub config_file: Region, pub framebuffer: BiosFramebufferInfo, pub memory_map_addr: u32, pub memory_map_len: u16, diff --git a/bios/stage-2/src/main.rs b/bios/stage-2/src/main.rs index d8335e14..e8a8ec14 100644 --- a/bios/stage-2/src/main.rs +++ b/bios/stage-2/src/main.rs @@ -112,6 +112,14 @@ fn start(disk_number: u16, partition_table_start: *const u8) -> ! { } else { writeln!(screen::Writer, "Loaded ramdisk at {ramdisk_start:#p}").unwrap(); } + let config_file_start = ramdisk_start.wrapping_add(ramdisk_len.try_into().unwrap()); + let config_file_len = load_file( + "config.json", + config_file_start, + &mut fs, + &mut disk, + disk_buffer, + ); let memory_map = unsafe { memory_map::query_memory_map() }.unwrap(); writeln!(screen::Writer, "{memory_map:x?}").unwrap(); @@ -147,6 +155,10 @@ fn start(disk_number: u16, partition_table_start: *const u8) -> ! { start: ramdisk_start as u64, len: ramdisk_len, }, + config_file: Region { + start: config_file_start as u64, + len: config_file_len, + }, memory_map_addr: memory_map.as_mut_ptr() as u32, memory_map_len: memory_map.len().try_into().unwrap(), framebuffer: BiosFramebufferInfo { diff --git a/bios/stage-4/src/main.rs b/bios/stage-4/src/main.rs index d9e10843..0ddd816b 100644 --- a/bios/stage-4/src/main.rs +++ b/bios/stage-4/src/main.rs @@ -2,15 +2,13 @@ #![no_main] use crate::memory_descriptor::MemoryRegion; -use bootloader_api::{ - config::{LevelFilter, LoggerStatus}, - info::{FrameBufferInfo, PixelFormat}, -}; +use bootloader_api::info::{FrameBufferInfo, PixelFormat}; use bootloader_x86_64_bios_common::{BiosFramebufferInfo, BiosInfo, E820MemoryRegion}; use bootloader_x86_64_common::RawFrameBufferInfo; use bootloader_x86_64_common::{ - legacy_memory_region::LegacyFrameAllocator, load_and_switch_to_kernel, Kernel, PageTables, - SystemInfo, + config::{BootloaderConfigFile, LevelFilter, LoggerStatus}, + legacy_memory_region::LegacyFrameAllocator, + load_and_switch_to_kernel, Kernel, PageTables, SystemInfo, }; use core::{cmp, slice}; use usize_conversions::usize_from; @@ -113,11 +111,17 @@ pub extern "C" fn _start(info: &mut BiosInfo) -> ! { }; let kernel = Kernel::parse(kernel_slice); + let mut config_file_slice = { + let mut ptr = info.config_file.start as *mut u8; + unsafe { slice::from_raw_parts_mut(ptr, usize_from(info.config_file.len)) } + }; + let config_file = BootloaderConfigFile::deserialize(Some(&mut config_file_slice)); + let framebuffer_info = init_logger( info.framebuffer, - kernel.config.log_level, - kernel.config.frame_buffer_logger_status, - kernel.config.serial_logger_status, + config_file.log_level, + config_file.frame_buffer_logger_status, + config_file.serial_logger_status, ); log::info!("4th Stage"); diff --git a/common/Cargo.toml b/common/Cargo.toml index c830200a..0ab7731f 100644 --- a/common/Cargo.toml +++ b/common/Cargo.toml @@ -20,6 +20,8 @@ raw-cpuid = "10.2.0" rand = { version = "0.8.4", default-features = false } rand_hc = "0.3.1" uart_16550 = "0.2.18" +serde-json-core = "0.5.0" +serde = { version = "1.0.152", default-features = false, features = ["derive"] } [dependencies.noto-sans-mono-bitmap] version = "0.2.0" diff --git a/common/src/lib.rs b/common/src/lib.rs index ad92556f..9e595844 100644 --- a/common/src/lib.rs +++ b/common/src/lib.rs @@ -2,9 +2,12 @@ #![feature(step_trait)] #![deny(unsafe_op_in_unsafe_fn)] -use crate::legacy_memory_region::{LegacyFrameAllocator, LegacyMemoryRegion}; +use crate::{ + config::{LevelFilter, LoggerStatus}, + legacy_memory_region::{LegacyFrameAllocator, LegacyMemoryRegion}, +}; use bootloader_api::{ - config::{LevelFilter, LoggerStatus, Mapping}, + config::Mapping, info::{FrameBuffer, FrameBufferInfo, MemoryRegion, TlsTemplate}, BootInfo, BootloaderConfig, }; @@ -20,6 +23,8 @@ use x86_64::{ }; use xmas_elf::ElfFile; +/// Provides a type with the runtime configurations that are saved in a JSON file. +pub mod config; /// Provides a function to gather entropy and build a RNG. mod entropy; /// Provides a type that logs output as text to pixel-based framebuffers. diff --git a/common/src/logger.rs b/common/src/logger.rs index 741c64c5..d3c27975 100644 --- a/common/src/logger.rs +++ b/common/src/logger.rs @@ -1,5 +1,5 @@ -use crate::{framebuffer::FrameBufferWriter, serial::SerialPort}; -use bootloader_api::{config::LoggerStatus, info::FrameBufferInfo}; +use crate::{config::LoggerStatus, framebuffer::FrameBufferWriter, serial::SerialPort}; +use bootloader_api::info::FrameBufferInfo; use conquer_once::spin::OnceCell; use core::fmt::Write; use spinning_top::Spinlock; diff --git a/src/bios/mod.rs b/src/bios/mod.rs index 78ebe957..6275affc 100644 --- a/src/bios/mod.rs +++ b/src/bios/mod.rs @@ -15,6 +15,7 @@ const BIOS_STAGE_4: &str = "boot-stage-4"; pub struct BiosBoot { kernel: PathBuf, ramdisk: Option, + config_file: Option, } impl BiosBoot { @@ -23,6 +24,7 @@ impl BiosBoot { Self { kernel: kernel_path.to_owned(), ramdisk: None, + config_file: None, } } @@ -32,6 +34,12 @@ impl BiosBoot { self } + /// Add a JSON configuration file to the disk image + pub fn set_config_file(&mut self, config_file_path: &Path) -> &mut Self { + self.config_file = Some(config_file_path.to_owned()); + self + } + /// Create a bootable BIOS disk image at the given path. pub fn create_disk_image(&self, out_path: &Path) -> anyhow::Result<()> { let bootsector_path = Path::new(env!("BIOS_BOOT_SECTOR_PATH")); @@ -68,6 +76,9 @@ impl BiosBoot { if let Some(ramdisk_path) = &self.ramdisk { files.insert(crate::RAMDISK_FILE_NAME, ramdisk_path); } + if let Some(config_file_path) = &self.config_file { + files.insert(crate::CONFIG_FILE_NAME, config_file_path); + } let out_file = NamedTempFile::new().context("failed to create temp file")?; fat::create_fat_filesystem(files, out_file.path()) diff --git a/src/lib.rs b/src/lib.rs index 4f540c04..de51b8e5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -18,3 +18,4 @@ pub use uefi::UefiBoot; const KERNEL_FILE_NAME: &str = "kernel-x86_64"; const RAMDISK_FILE_NAME: &str = "ramdisk"; +const CONFIG_FILE_NAME: &str = "config.json"; diff --git a/src/uefi/mod.rs b/src/uefi/mod.rs index e2d273dd..bb96d500 100644 --- a/src/uefi/mod.rs +++ b/src/uefi/mod.rs @@ -13,6 +13,7 @@ mod pxe; pub struct UefiBoot { kernel: PathBuf, ramdisk: Option, + config_file: Option, } impl UefiBoot { @@ -21,6 +22,7 @@ impl UefiBoot { Self { kernel: kernel_path.to_owned(), ramdisk: None, + config_file: None, } } @@ -30,6 +32,12 @@ impl UefiBoot { self } + /// Add a JSON configuration file to the disk image + pub fn set_config_file(&mut self, config_file_path: &Path) -> &mut Self { + self.config_file = Some(config_file_path.to_owned()); + self + } + /// Create a bootable UEFI disk image at the given path. pub fn create_disk_image(&self, out_path: &Path) -> anyhow::Result<()> { let fat_partition = self @@ -75,6 +83,9 @@ impl UefiBoot { if let Some(ramdisk_path) = &self.ramdisk { files.insert(crate::RAMDISK_FILE_NAME, ramdisk_path); } + if let Some(config_file_path) = &self.config_file { + files.insert(crate::CONFIG_FILE_NAME, config_file_path); + } let out_file = NamedTempFile::new().context("failed to create temp file")?; fat::create_fat_filesystem(files, out_file.path()) diff --git a/uefi/src/main.rs b/uefi/src/main.rs index e6da4b50..12e5e160 100644 --- a/uefi/src/main.rs +++ b/uefi/src/main.rs @@ -4,9 +4,10 @@ #![deny(unsafe_op_in_unsafe_fn)] use crate::memory_descriptor::UefiMemoryDescriptor; -use bootloader_api::{info::FrameBufferInfo, BootloaderConfig}; +use bootloader_api::info::FrameBufferInfo; use bootloader_x86_64_common::{ - legacy_memory_region::LegacyFrameAllocator, Kernel, RawFrameBufferInfo, SystemInfo, + config::BootloaderConfigFile, legacy_memory_region::LegacyFrameAllocator, Kernel, + RawFrameBufferInfo, SystemInfo, }; use core::{ cell::UnsafeCell, @@ -96,6 +97,9 @@ fn main_inner(image: Handle, mut st: SystemTable) -> Status { writeln!(st.stdout(), "Trying to load ramdisk via {:?}", boot_mode).unwrap(); // Ramdisk must load from same source, or not at all. let ramdisk = load_ramdisk(image, &mut st, boot_mode); + // Dirty code! + let config_file = load_config_file(image, &mut st, boot_mode); + let config = BootloaderConfigFile::deserialize(config_file); writeln!( st.stdout(), @@ -107,7 +111,7 @@ fn main_inner(image: Handle, mut st: SystemTable) -> Status { ) .unwrap(); - let framebuffer = init_logger(image, &st, kernel.config); + let framebuffer = init_logger(image, &st, config); unsafe { *SYSTEM_TABLE.get() = None; } @@ -194,6 +198,14 @@ fn load_ramdisk( load_file_from_boot_method(image, st, "ramdisk\0", boot_mode) } +fn load_config_file( + image: Handle, + st: &mut SystemTable, + boot_mode: BootMode, +) -> Option<&'static mut [u8]> { + load_file_from_boot_method(image, st, "config.json\0", boot_mode) +} + fn load_kernel( image: Handle, st: &mut SystemTable, @@ -446,7 +458,7 @@ fn create_page_tables( fn init_logger( image_handle: Handle, st: &SystemTable, - config: BootloaderConfig, + config: BootloaderConfigFile, ) -> Option { let gop_handle = st .boot_services() From 3ab261bd79eb9c3f4243c688957e73fa42b00501 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juanjo=20Asensio=20Garc=C3=ADa?= Date: Sat, 14 Jan 2023 23:01:05 +0100 Subject: [PATCH 2/9] Fix an error --- common/src/config.rs | 119 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 119 insertions(+) create mode 100644 common/src/config.rs diff --git a/common/src/config.rs b/common/src/config.rs new file mode 100644 index 00000000..3ebf13c3 --- /dev/null +++ b/common/src/config.rs @@ -0,0 +1,119 @@ +use serde::Deserialize; + +#[derive(Deserialize)] +pub struct BootloaderConfigFile { + /// Configuration for the frame buffer that can be used by the kernel to display pixels + /// on the screen. + #[serde(default)] + 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'. + #[serde(default)] + pub log_level: LevelFilter, + + /// Whether the bootloader should print log messages to the framebuffer when booting. + /// + /// Enabled by default. + #[serde(default)] + pub frame_buffer_logger_status: LoggerStatus, + + /// Whether the bootloader should print log messages to the serial port when booting. + /// + /// Enabled by default. + #[serde(default)] + pub serial_logger_status: LoggerStatus, +} + +impl Default for BootloaderConfigFile { + fn default() -> Self { + Self { + frame_buffer: Default::default(), + log_level: Default::default(), + frame_buffer_logger_status: Default::default(), + serial_logger_status: Default::default(), + } + } +} + +impl BootloaderConfigFile { + pub fn deserialize<'a>(serialized: Option<&'a mut [u8]>) -> Self { + match serialized { + Some(json) => return serde_json_core::from_slice(&json).unwrap().0, + None => return Default::default(), + } + } +} + +/// Configuration for the frame buffer used for graphical output. +#[derive(Deserialize, Debug, Default, PartialEq, Eq, Clone, Copy)] +#[non_exhaustive] +pub struct FrameBuffer { + /// Instructs the bootloader to set up a framebuffer format that has at least the given height. + /// + /// If this is not possible, the bootloader will fall back to a smaller format. + pub minimum_framebuffer_height: Option, + /// Instructs the bootloader to set up a framebuffer format that has at least the given width. + /// + /// If this is not possible, the bootloader will fall back to a smaller format. + pub minimum_framebuffer_width: Option, +} + +impl FrameBuffer { + #[cfg(test)] + fn random() -> FrameBuffer { + Self { + minimum_framebuffer_height: if rand::random() { + Option::Some(rand::random()) + } else { + Option::None + }, + minimum_framebuffer_width: if rand::random() { + Option::Some(rand::random()) + } else { + Option::None + }, + } + } +} + +/// 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 +#[derive(Deserialize, 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 Default for LevelFilter { + fn default() -> Self { + Self::Trace + } +} + +/// An enum for enabling or disabling the different methods for logging. +#[derive(Deserialize, Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub enum LoggerStatus { + /// This method of logging is disabled + Disable, + /// This method of logging is enabled + Enable, +} + +impl Default for LoggerStatus { + fn default() -> Self { + Self::Enable + } +} From 93516045f56d603d8e0c766fe58f8a2aafbf76df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juanjo=20Asensio=20Garc=C3=ADa?= Date: Sun, 15 Jan 2023 00:29:14 +0100 Subject: [PATCH 3/9] Fix api test --- api/src/config.rs | 102 -------------------------------------- api/src/lib.rs | 2 +- bios/stage-4/src/main.rs | 2 +- common/src/load_kernel.rs | 1 - 4 files changed, 2 insertions(+), 105 deletions(-) diff --git a/api/src/config.rs b/api/src/config.rs index 32d2f67c..12a3d494 100644 --- a/api/src/config.rs +++ b/api/src/config.rs @@ -37,7 +37,6 @@ impl BootloaderConfig { /// /// - `kernel_stack_size`: 80kiB /// - `mappings`: See [`Mappings::new_default()`] - /// - `frame_buffer`: See [`FrameBuffer::new_default()`] pub const fn new_default() -> Self { Self { kernel_stack_size: 80 * 1024, @@ -227,10 +226,6 @@ impl BootloaderConfig { version: ApiVersion::random(), mappings: Mappings::random(), kernel_stack_size: rand::random(), - frame_buffer: FrameBuffer::random(), - log_level: LevelFilter::Trace, - frame_buffer_logger_status: LoggerStatus::Enable, - serial_logger_status: LoggerStatus::Enable, } } } @@ -398,46 +393,6 @@ impl Mappings { } } -/// Configuration for the frame buffer used for graphical output. -#[derive(Debug, Default, PartialEq, Eq, Clone, Copy)] -#[non_exhaustive] -pub struct FrameBuffer { - /// Instructs the bootloader to set up a framebuffer format that has at least the given height. - /// - /// If this is not possible, the bootloader will fall back to a smaller format. - pub minimum_framebuffer_height: Option, - /// Instructs the bootloader to set up a framebuffer format that has at least the given width. - /// - /// If this is not possible, the bootloader will fall back to a smaller format. - pub minimum_framebuffer_width: Option, -} - -impl FrameBuffer { - /// Creates a default configuration without any requirements. - pub const fn new_default() -> Self { - Self { - minimum_framebuffer_height: Option::None, - minimum_framebuffer_width: Option::None, - } - } - - #[cfg(test)] - fn random() -> FrameBuffer { - Self { - minimum_framebuffer_height: if rand::random() { - Option::Some(rand::random()) - } else { - Option::None - }, - minimum_framebuffer_width: if rand::random() { - Option::Some(rand::random()) - } else { - Option::None - }, - } - } -} - /// Specifies how the bootloader should map a memory region into the virtual address space. #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] pub enum Mapping { @@ -499,63 +454,6 @@ 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, - } - } -} - -/// An enum for enabling or disabling the different methods for logging. -#[repr(u8)] -#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub enum LoggerStatus { - /// This method of logging is disabled - Disable, - /// This method of logging is enabled - Enable, -} - -impl LoggerStatus { - /// Converts an u8 into a Option - pub fn from_u8(value: u8) -> Option { - match value { - 0 => Some(Self::Disable), - 1 => Some(Self::Enable), - _ => 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/api/src/lib.rs b/api/src/lib.rs index 2f6d5f36..4ada525f 100644 --- a/api/src/lib.rs +++ b/api/src/lib.rs @@ -73,7 +73,7 @@ mod version_info { /// /// pub static BOOTLOADER_CONFIG: BootloaderConfig = { /// let mut config = BootloaderConfig::new_default(); -/// config.frame_buffer.minimum_framebuffer_height = Some(720); +/// config.kernel_stack_size = 90 * 1024; /// config /// }; /// diff --git a/bios/stage-4/src/main.rs b/bios/stage-4/src/main.rs index 0ddd816b..169ed901 100644 --- a/bios/stage-4/src/main.rs +++ b/bios/stage-4/src/main.rs @@ -112,7 +112,7 @@ pub extern "C" fn _start(info: &mut BiosInfo) -> ! { let kernel = Kernel::parse(kernel_slice); let mut config_file_slice = { - let mut ptr = info.config_file.start as *mut u8; + let ptr = info.config_file.start as *mut u8; unsafe { slice::from_raw_parts_mut(ptr, usize_from(info.config_file.len)) } }; let config_file = BootloaderConfigFile::deserialize(Some(&mut config_file_slice)); diff --git a/common/src/load_kernel.rs b/common/src/load_kernel.rs index 685bad0f..26798207 100644 --- a/common/src/load_kernel.rs +++ b/common/src/load_kernel.rs @@ -1,7 +1,6 @@ use crate::{level_4_entries::UsedLevel4Entries, PAGE_SIZE}; use bootloader_api::info::TlsTemplate; use core::{cmp, iter::Step, mem::size_of, ops::Add}; -use log::debug; use x86_64::{ align_up, From a7a1958c9f6fc9d568c780958abf765537409332 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juanjo=20Asensio=20Garc=C3=ADa?= Date: Sun, 15 Jan 2023 13:24:45 +0100 Subject: [PATCH 4/9] Make it fault tolerant --- bios/stage-2/src/main.rs | 7 +++++-- bios/stage-4/src/main.rs | 28 +++++++++++++++++++++------- common/src/config.rs | 12 +++++++++--- uefi/src/main.rs | 15 +++++++++++++-- 4 files changed, 48 insertions(+), 14 deletions(-) diff --git a/bios/stage-2/src/main.rs b/bios/stage-2/src/main.rs index e8a8ec14..cf70ca47 100644 --- a/bios/stage-2/src/main.rs +++ b/bios/stage-2/src/main.rs @@ -113,13 +113,16 @@ fn start(disk_number: u16, partition_table_start: *const u8) -> ! { writeln!(screen::Writer, "Loaded ramdisk at {ramdisk_start:#p}").unwrap(); } let config_file_start = ramdisk_start.wrapping_add(ramdisk_len.try_into().unwrap()); - let config_file_len = load_file( + let config_file_len = match try_load_file( "config.json", config_file_start, &mut fs, &mut disk, disk_buffer, - ); + ) { + Some(s) => s, + None => 0u64, + }; let memory_map = unsafe { memory_map::query_memory_map() }.unwrap(); writeln!(screen::Writer, "{memory_map:x?}").unwrap(); diff --git a/bios/stage-4/src/main.rs b/bios/stage-4/src/main.rs index 169ed901..37c5813f 100644 --- a/bios/stage-4/src/main.rs +++ b/bios/stage-4/src/main.rs @@ -111,17 +111,31 @@ pub extern "C" fn _start(info: &mut BiosInfo) -> ! { }; let kernel = Kernel::parse(kernel_slice); - let mut config_file_slice = { - let ptr = info.config_file.start as *mut u8; - unsafe { slice::from_raw_parts_mut(ptr, usize_from(info.config_file.len)) } + let mut config_file_slice: Option<&'static mut [u8]> = None; + if info.config_file.len != 0 { + config_file_slice = { + let ptr = info.config_file.start as *mut u8; + unsafe { + Some(slice::from_raw_parts_mut( + ptr, + usize_from(info.config_file.len), + )) + } + }; + } + let config = match BootloaderConfigFile::deserialize(config_file_slice) { + Ok(data) => data, + Err((data, err)) => { + log::warn!("Failed to deserialize the config file {:?}", err); + data + } }; - let config_file = BootloaderConfigFile::deserialize(Some(&mut config_file_slice)); let framebuffer_info = init_logger( info.framebuffer, - config_file.log_level, - config_file.frame_buffer_logger_status, - config_file.serial_logger_status, + config.log_level, + config.frame_buffer_logger_status, + config.serial_logger_status, ); log::info!("4th Stage"); diff --git a/common/src/config.rs b/common/src/config.rs index 3ebf13c3..34edfe83 100644 --- a/common/src/config.rs +++ b/common/src/config.rs @@ -1,4 +1,5 @@ use serde::Deserialize; +use serde_json_core::de; #[derive(Deserialize)] pub struct BootloaderConfigFile { @@ -37,10 +38,15 @@ impl Default for BootloaderConfigFile { } impl BootloaderConfigFile { - pub fn deserialize<'a>(serialized: Option<&'a mut [u8]>) -> Self { + pub fn deserialize<'a>(serialized: Option<&'a mut [u8]>) -> Result { match serialized { - Some(json) => return serde_json_core::from_slice(&json).unwrap().0, - None => return Default::default(), + Some(json) => { + match serde_json_core::from_slice::(&json) { + Ok((data, _)) => return Ok(data), + Err(err) => return Err((Default::default(), err)), + }; + } + None => return Ok(Default::default()), } } } diff --git a/uefi/src/main.rs b/uefi/src/main.rs index 12e5e160..ab054d82 100644 --- a/uefi/src/main.rs +++ b/uefi/src/main.rs @@ -97,9 +97,20 @@ fn main_inner(image: Handle, mut st: SystemTable) -> Status { writeln!(st.stdout(), "Trying to load ramdisk via {:?}", boot_mode).unwrap(); // Ramdisk must load from same source, or not at all. let ramdisk = load_ramdisk(image, &mut st, boot_mode); - // Dirty code! + let config_file = load_config_file(image, &mut st, boot_mode); - let config = BootloaderConfigFile::deserialize(config_file); + let config = match BootloaderConfigFile::deserialize(config_file) { + Ok(data) => data, + Err((data, err)) => { + writeln!( + st.stdout(), + "Failed to deserialize the config file {:?}", + err + ) + .unwrap(); + data + } + }; writeln!( st.stdout(), From bc7ccf87ac53f87a42d9d5319e2f163b52e5ea36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juanjo=20Asensio=20Garc=C3=ADa?= Date: Sun, 15 Jan 2023 16:34:03 +0100 Subject: [PATCH 5/9] Add a test --- Cargo.lock | 10 +++++++ Cargo.toml | 1 + tests/config_file.rs | 21 ++++++++++++++ tests/config_files/broken_config.json | 3 ++ tests/config_files/full_config.json | 6 ++++ tests/default_settings.rs | 24 ++++++++++------ tests/higher_half.rs | 28 +++++++++++++------ tests/lto.rs | 2 +- tests/map_phys_mem.rs | 16 +++++++---- tests/pie.rs | 24 +++++++++++++--- tests/ramdisk.rs | 8 ++++-- tests/runner/src/lib.rs | 16 +++++++---- tests/test_kernels/config_file/Cargo.toml | 13 +++++++++ .../config_file/src/bin/basic_boot.rs | 21 ++++++++++++++ .../src/bin/basic_boot_broken_config_file.rs | 21 ++++++++++++++ tests/test_kernels/config_file/src/lib.rs | 27 ++++++++++++++++++ 16 files changed, 205 insertions(+), 36 deletions(-) create mode 100644 tests/config_file.rs create mode 100644 tests/config_files/broken_config.json create mode 100644 tests/config_files/full_config.json create mode 100644 tests/test_kernels/config_file/Cargo.toml create mode 100644 tests/test_kernels/config_file/src/bin/basic_boot.rs create mode 100644 tests/test_kernels/config_file/src/bin/basic_boot_broken_config_file.rs create mode 100644 tests/test_kernels/config_file/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index adfc9f59..4226e164 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -161,6 +161,7 @@ dependencies = [ "llvm-tools", "mbrman", "tempfile", + "test_kernel_config_file", "test_kernel_default_settings", "test_kernel_higher_half", "test_kernel_map_phys_mem", @@ -968,6 +969,15 @@ dependencies = [ "winapi", ] +[[package]] +name = "test_kernel_config_file" +version = "0.1.0" +dependencies = [ + "bootloader_api", + "uart_16550", + "x86_64", +] + [[package]] name = "test_kernel_default_settings" version = "0.1.0" diff --git a/Cargo.toml b/Cargo.toml index d2c0122c..e00d3752 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -57,6 +57,7 @@ test_kernel_higher_half = { path = "tests/test_kernels/higher_half", artifact = test_kernel_map_phys_mem = { path = "tests/test_kernels/map_phys_mem", artifact = "bin", target = "x86_64-unknown-none" } test_kernel_pie = { path = "tests/test_kernels/pie", artifact = "bin", target = "x86_64-unknown-none" } test_kernel_ramdisk = { path = "tests/test_kernels/ramdisk", artifact = "bin", target = "x86_64-unknown-none" } +test_kernel_config_file = { path = "tests/test_kernels/config_file", artifact = "bin", target = "x86_64-unknown-none" } [profile.dev] panic = "abort" diff --git a/tests/config_file.rs b/tests/config_file.rs new file mode 100644 index 00000000..99933531 --- /dev/null +++ b/tests/config_file.rs @@ -0,0 +1,21 @@ +use std::path::Path; + +use bootloader_test_runner::run_test_kernel; + +#[test] +fn basic_boot() { + run_test_kernel( + env!("CARGO_BIN_FILE_TEST_KERNEL_CONFIG_FILE_basic_boot"), + None, + Some(Path::new("tests/config_files/full_config.json")), + ); +} + +#[test] +fn basic_boot_broken_config_file() { + run_test_kernel( + env!("CARGO_BIN_FILE_TEST_KERNEL_CONFIG_FILE_basic_boot_broken_config_file"), + None, + Some(Path::new("tests/config_files/broken_config.json")), + ); +} diff --git a/tests/config_files/broken_config.json b/tests/config_files/broken_config.json new file mode 100644 index 00000000..77128d36 --- /dev/null +++ b/tests/config_files/broken_config.json @@ -0,0 +1,3 @@ +{ + Lorem ipsum dolor sit amet consectetue +} diff --git a/tests/config_files/full_config.json b/tests/config_files/full_config.json new file mode 100644 index 00000000..b721967e --- /dev/null +++ b/tests/config_files/full_config.json @@ -0,0 +1,6 @@ +{ + "frame_buffer": { "minimun_framebuffer_height": null, "minimun_framebuffer_width": null }, + "log_level": "Trace", + "frame_buffer_logger_status": "Enable", + "serial_logger_status": "Enable" +} diff --git a/tests/default_settings.rs b/tests/default_settings.rs index d610508c..0069af03 100644 --- a/tests/default_settings.rs +++ b/tests/default_settings.rs @@ -2,21 +2,27 @@ use bootloader_test_runner::run_test_kernel; #[test] fn basic_boot() { - run_test_kernel(env!( - "CARGO_BIN_FILE_TEST_KERNEL_DEFAULT_SETTINGS_basic_boot" - )); + run_test_kernel( + env!("CARGO_BIN_FILE_TEST_KERNEL_DEFAULT_SETTINGS_basic_boot"), + None, + None, + ); } #[test] fn should_panic() { - run_test_kernel(env!( - "CARGO_BIN_FILE_TEST_KERNEL_DEFAULT_SETTINGS_should_panic" - )); + run_test_kernel( + env!("CARGO_BIN_FILE_TEST_KERNEL_DEFAULT_SETTINGS_should_panic"), + None, + None, + ); } #[test] fn check_boot_info() { - run_test_kernel(env!( - "CARGO_BIN_FILE_TEST_KERNEL_DEFAULT_SETTINGS_check_boot_info" - )); + run_test_kernel( + env!("CARGO_BIN_FILE_TEST_KERNEL_DEFAULT_SETTINGS_check_boot_info"), + None, + None, + ); } diff --git a/tests/higher_half.rs b/tests/higher_half.rs index c2b9ac91..2b754e0a 100644 --- a/tests/higher_half.rs +++ b/tests/higher_half.rs @@ -2,24 +2,36 @@ use bootloader_test_runner::run_test_kernel; #[test] fn basic_boot() { - run_test_kernel(env!("CARGO_BIN_FILE_TEST_KERNEL_HIGHER_HALF_basic_boot")); + run_test_kernel( + env!("CARGO_BIN_FILE_TEST_KERNEL_HIGHER_HALF_basic_boot"), + None, + None, + ); } #[test] fn should_panic() { - run_test_kernel(env!("CARGO_BIN_FILE_TEST_KERNEL_HIGHER_HALF_should_panic")); + run_test_kernel( + env!("CARGO_BIN_FILE_TEST_KERNEL_HIGHER_HALF_should_panic"), + None, + None, + ); } #[test] fn check_boot_info() { - run_test_kernel(env!( - "CARGO_BIN_FILE_TEST_KERNEL_HIGHER_HALF_check_boot_info" - )); + run_test_kernel( + env!("CARGO_BIN_FILE_TEST_KERNEL_HIGHER_HALF_check_boot_info"), + None, + None, + ); } #[test] fn verify_higher_half() { - run_test_kernel(env!( - "CARGO_BIN_FILE_TEST_KERNEL_HIGHER_HALF_verify_higher_half" - )); + run_test_kernel( + env!("CARGO_BIN_FILE_TEST_KERNEL_HIGHER_HALF_verify_higher_half"), + None, + None, + ); } diff --git a/tests/lto.rs b/tests/lto.rs index 00cfe60f..e31b3060 100644 --- a/tests/lto.rs +++ b/tests/lto.rs @@ -21,5 +21,5 @@ fn basic_boot() { .join("basic_boot"); assert!(kernel_path.exists()); - run_test_kernel(kernel_path.as_path().to_str().unwrap()); + run_test_kernel(kernel_path.as_path().to_str().unwrap(), None, None); } diff --git a/tests/map_phys_mem.rs b/tests/map_phys_mem.rs index b19ba987..a322ac92 100644 --- a/tests/map_phys_mem.rs +++ b/tests/map_phys_mem.rs @@ -2,14 +2,18 @@ use bootloader_test_runner::run_test_kernel; #[test] fn check_boot_info() { - run_test_kernel(env!( - "CARGO_BIN_FILE_TEST_KERNEL_MAP_PHYS_MEM_check_boot_info" - )); + run_test_kernel( + env!("CARGO_BIN_FILE_TEST_KERNEL_MAP_PHYS_MEM_check_boot_info"), + None, + None, + ); } #[test] fn access_phys_mem() { - run_test_kernel(env!( - "CARGO_BIN_FILE_TEST_KERNEL_MAP_PHYS_MEM_access_phys_mem" - )); + run_test_kernel( + env!("CARGO_BIN_FILE_TEST_KERNEL_MAP_PHYS_MEM_access_phys_mem"), + None, + None, + ); } diff --git a/tests/pie.rs b/tests/pie.rs index c2d30d80..bdafaf4d 100644 --- a/tests/pie.rs +++ b/tests/pie.rs @@ -2,20 +2,36 @@ use bootloader_test_runner::run_test_kernel; #[test] fn basic_boot() { - run_test_kernel(env!("CARGO_BIN_FILE_TEST_KERNEL_PIE_basic_boot")); + run_test_kernel( + env!("CARGO_BIN_FILE_TEST_KERNEL_PIE_basic_boot"), + None, + None, + ); } #[test] fn should_panic() { - run_test_kernel(env!("CARGO_BIN_FILE_TEST_KERNEL_PIE_should_panic")); + run_test_kernel( + env!("CARGO_BIN_FILE_TEST_KERNEL_PIE_should_panic"), + None, + None, + ); } #[test] fn check_boot_info() { - run_test_kernel(env!("CARGO_BIN_FILE_TEST_KERNEL_PIE_check_boot_info")); + run_test_kernel( + env!("CARGO_BIN_FILE_TEST_KERNEL_PIE_check_boot_info"), + None, + None, + ); } #[test] fn global_variable() { - run_test_kernel(env!("CARGO_BIN_FILE_TEST_KERNEL_PIE_global_variable")); + run_test_kernel( + env!("CARGO_BIN_FILE_TEST_KERNEL_PIE_global_variable"), + None, + None, + ); } diff --git a/tests/ramdisk.rs b/tests/ramdisk.rs index bdd7f9db..881ce98c 100644 --- a/tests/ramdisk.rs +++ b/tests/ramdisk.rs @@ -1,20 +1,22 @@ use std::path::Path; -use bootloader_test_runner::run_test_kernel_with_ramdisk; +use bootloader_test_runner::run_test_kernel; static RAMDISK_PATH: &str = "tests/ramdisk.txt"; #[test] fn basic_boot() { - run_test_kernel_with_ramdisk( + run_test_kernel( env!("CARGO_BIN_FILE_TEST_KERNEL_RAMDISK_basic_boot"), Some(Path::new(RAMDISK_PATH)), + None, ); } #[test] fn check_ramdisk() { - run_test_kernel_with_ramdisk( + run_test_kernel( env!("CARGO_BIN_FILE_TEST_KERNEL_RAMDISK_ramdisk"), Some(Path::new(RAMDISK_PATH)), + None, ); } diff --git a/tests/runner/src/lib.rs b/tests/runner/src/lib.rs index f9491493..b3ec8dd5 100644 --- a/tests/runner/src/lib.rs +++ b/tests/runner/src/lib.rs @@ -10,11 +10,11 @@ const QEMU_ARGS: &[&str] = &[ "--no-reboot", ]; -pub fn run_test_kernel(kernel_binary_path: &str) { - run_test_kernel_with_ramdisk(kernel_binary_path, None) -} - -pub fn run_test_kernel_with_ramdisk(kernel_binary_path: &str, ramdisk_path: Option<&Path>) { +pub fn run_test_kernel( + kernel_binary_path: &str, + ramdisk_path: Option<&Path>, + config_file_path: Option<&Path>, +) { let kernel_path = Path::new(kernel_binary_path); #[cfg(feature = "uefi")] @@ -26,6 +26,9 @@ pub fn run_test_kernel_with_ramdisk(kernel_binary_path: &str, ramdisk_path: Opti if let Some(rdp) = ramdisk_path { uefi_builder.set_ramdisk(rdp); } + if let Some(cfp) = config_file_path { + uefi_builder.set_ramdisk(cfp); + } uefi_builder.create_disk_image(&gpt_path).unwrap(); // create a TFTP folder with the kernel executable and UEFI bootloader for @@ -46,6 +49,9 @@ pub fn run_test_kernel_with_ramdisk(kernel_binary_path: &str, ramdisk_path: Opti if let Some(rdp) = ramdisk_path { bios_builder.set_ramdisk(rdp); } + if let Some(cfp) = config_file_path { + bios_builder.set_ramdisk(cfp); + } bios_builder.create_disk_image(&mbr_path).unwrap(); run_test_kernel_on_bios(&mbr_path); diff --git a/tests/test_kernels/config_file/Cargo.toml b/tests/test_kernels/config_file/Cargo.toml new file mode 100644 index 00000000..990b9508 --- /dev/null +++ b/tests/test_kernels/config_file/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "test_kernel_config_file" +version = "0.1.0" +authors = ["Philipp Oppermann "] +edition = "2021" + +[dependencies] +bootloader_api = { path = "../../../api" } +x86_64 = { version = "0.14.7", default-features = false, features = [ + "instructions", + "inline_asm", +] } +uart_16550 = "0.2.10" diff --git a/tests/test_kernels/config_file/src/bin/basic_boot.rs b/tests/test_kernels/config_file/src/bin/basic_boot.rs new file mode 100644 index 00000000..d6401dc7 --- /dev/null +++ b/tests/test_kernels/config_file/src/bin/basic_boot.rs @@ -0,0 +1,21 @@ +#![no_std] // don't link the Rust standard library +#![no_main] // disable all Rust-level entry points + +use bootloader_api::{entry_point, BootInfo}; +use core::fmt::Write; +use test_kernel_config_file::{exit_qemu, serial, QemuExitCode}; + +entry_point!(kernel_main); + +fn kernel_main(boot_info: &'static mut BootInfo) -> ! { + writeln!(serial(), "Entered kernel with boot info: {:?}", boot_info).unwrap(); + exit_qemu(QemuExitCode::Success); +} + +/// This function is called on panic. +#[panic_handler] +#[cfg(not(test))] +fn panic(info: &core::panic::PanicInfo) -> ! { + let _ = writeln!(serial(), "PANIC: {}", info); + exit_qemu(QemuExitCode::Failed); +} diff --git a/tests/test_kernels/config_file/src/bin/basic_boot_broken_config_file.rs b/tests/test_kernels/config_file/src/bin/basic_boot_broken_config_file.rs new file mode 100644 index 00000000..d6401dc7 --- /dev/null +++ b/tests/test_kernels/config_file/src/bin/basic_boot_broken_config_file.rs @@ -0,0 +1,21 @@ +#![no_std] // don't link the Rust standard library +#![no_main] // disable all Rust-level entry points + +use bootloader_api::{entry_point, BootInfo}; +use core::fmt::Write; +use test_kernel_config_file::{exit_qemu, serial, QemuExitCode}; + +entry_point!(kernel_main); + +fn kernel_main(boot_info: &'static mut BootInfo) -> ! { + writeln!(serial(), "Entered kernel with boot info: {:?}", boot_info).unwrap(); + exit_qemu(QemuExitCode::Success); +} + +/// This function is called on panic. +#[panic_handler] +#[cfg(not(test))] +fn panic(info: &core::panic::PanicInfo) -> ! { + let _ = writeln!(serial(), "PANIC: {}", info); + exit_qemu(QemuExitCode::Failed); +} diff --git a/tests/test_kernels/config_file/src/lib.rs b/tests/test_kernels/config_file/src/lib.rs new file mode 100644 index 00000000..4e46fdb6 --- /dev/null +++ b/tests/test_kernels/config_file/src/lib.rs @@ -0,0 +1,27 @@ +#![no_std] + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[repr(u32)] +pub enum QemuExitCode { + Success = 0x10, + Failed = 0x11, +} + +pub fn exit_qemu(exit_code: QemuExitCode) -> ! { + use x86_64::instructions::{nop, port::Port}; + + unsafe { + let mut port = Port::new(0xf4); + port.write(exit_code as u32); + } + + loop { + nop(); + } +} + +pub fn serial() -> uart_16550::SerialPort { + let mut port = unsafe { uart_16550::SerialPort::new(0x3F8) }; + port.init(); + port +} From a164de5be262e25250217763e90ad473d911fb65 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juanjo=20Asensio=20Garc=C3=ADa?= Date: Sat, 21 Jan 2023 17:39:04 +0100 Subject: [PATCH 6/9] Apply suggestions --- Cargo.lock | 21 ++++++ Cargo.toml | 2 + api/build.rs | 2 + api/src/config.rs | 99 ++++++++++++++++++++++++++- bios/stage-4/Cargo.toml | 1 + bios/stage-4/src/main.rs | 35 +++++++--- common/Cargo.toml | 2 +- common/src/config.rs | 72 ++++--------------- common/src/lib.rs | 6 +- common/src/logger.rs | 14 ++-- src/bios/mbr.rs | 2 +- src/bios/mod.rs | 21 ++++-- src/lib.rs | 4 +- src/uefi/mod.rs | 21 ++++-- tests/config_file.rs | 21 ++++-- tests/config_files/broken_config.json | 3 - tests/config_files/full_config.json | 6 -- tests/default_settings.rs | 24 +++---- tests/higher_half.rs | 28 +++----- tests/lto.rs | 2 +- tests/map_phys_mem.rs | 16 ++--- tests/pie.rs | 24 ++----- tests/ramdisk.rs | 8 +-- tests/runner/src/lib.rs | 22 ++++-- uefi/Cargo.toml | 1 + uefi/src/main.rs | 95 +++++++++++++------------ 26 files changed, 323 insertions(+), 229 deletions(-) delete mode 100644 tests/config_files/broken_config.json delete mode 100644 tests/config_files/full_config.json diff --git a/Cargo.lock b/Cargo.lock index 4226e164..8c7f2e17 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -153,6 +153,7 @@ version = "0.11.0" dependencies = [ "anyhow", "async-process", + "bootloader-x86_64-common", "bootloader_test_runner", "fatfs", "futures", @@ -160,6 +161,7 @@ dependencies = [ "gpt", "llvm-tools", "mbrman", + "serde_json", "tempfile", "test_kernel_config_file", "test_kernel_default_settings", @@ -203,6 +205,7 @@ dependencies = [ "bootloader_api", "log", "rsdp", + "serde-json-core", "usize_conversions", "x86_64", ] @@ -234,6 +237,7 @@ dependencies = [ "bootloader-x86_64-common", "bootloader_api", "log", + "serde-json-core", "uefi", "x86_64", ] @@ -541,6 +545,12 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "itoa" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fad582f4b9e86b6caa621cabeb0963332d92eea04729ab12892c2533951e6440" + [[package]] name = "libc" version = "0.2.139" @@ -867,6 +877,17 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.91" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877c235533714907a8c2464236f5c4b2a17262ef1bd71f38f35ea592c8da6883" +dependencies = [ + "itoa", + "ryu", + "serde", +] + [[package]] name = "signal-hook" version = "0.3.14" diff --git a/Cargo.toml b/Cargo.toml index e00d3752..84352f02 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -49,6 +49,8 @@ fatfs = "0.3.4" tempfile = "3.3.0" mbrman = { version = "0.5.1", optional = true } gpt = { version = "3.0.0", optional = true } +bootloader-x86_64-common = { version = "0.11.0", path = "common" } +serde_json = "1.0.91" [dev-dependencies] bootloader_test_runner = { path = "tests/runner" } diff --git a/api/build.rs b/api/build.rs index e7e06a99..3621eeef 100644 --- a/api/build.rs +++ b/api/build.rs @@ -21,6 +21,8 @@ fn main() { (79, 9), (88, 9), (97, 9), + (106, 9), + (115, 9), ]; let mut code = String::new(); diff --git a/api/src/config.rs b/api/src/config.rs index 12a3d494..d4d953c1 100644 --- a/api/src/config.rs +++ b/api/src/config.rs @@ -1,3 +1,5 @@ +#![allow(deprecated)] + use crate::{concat::*, version_info}; /// Allows configuring the bootloader behavior. @@ -23,6 +25,14 @@ pub struct BootloaderConfig { /// the stack size that the bootloader should allocate and map. The stack is created /// with a guard page, so a stack overflow will lead to a page fault. pub kernel_stack_size: u64, + + /// Configuration for the frame buffer that can be used by the kernel to display pixels + /// on the screen. + #[deprecated( + since = "0.11.1", + note = "This field is being obsolete because now it's at the JSON configuration file" + )] + pub frame_buffer: FrameBuffer, } impl BootloaderConfig { @@ -31,7 +41,7 @@ impl BootloaderConfig { 0x3D, ]; #[doc(hidden)] - pub const SERIALIZED_LEN: usize = 106; + pub const SERIALIZED_LEN: usize = 124; /// Creates a new default configuration with the following values: /// @@ -42,6 +52,7 @@ impl BootloaderConfig { kernel_stack_size: 80 * 1024, version: ApiVersion::new_default(), mappings: Mappings::new_default(), + frame_buffer: FrameBuffer::new_default(), } } @@ -54,6 +65,7 @@ impl BootloaderConfig { version, mappings, kernel_stack_size, + frame_buffer, } = self; let ApiVersion { version_major, @@ -72,6 +84,10 @@ impl BootloaderConfig { dynamic_range_end, ramdisk_memory, } = mappings; + let FrameBuffer { + minimum_framebuffer_height, + minimum_framebuffer_width, + } = frame_buffer; let version = { let one = concat_2_2(version_major.to_le_bytes(), version_minor.to_le_bytes()); @@ -115,7 +131,23 @@ impl BootloaderConfig { }, ); - concat_97_9(buf, ramdisk_memory.serialize()) + let buf = concat_97_9(buf, ramdisk_memory.serialize()); + + let buf = concat_106_9( + buf, + match minimum_framebuffer_height { + Option::None => [0; 9], + Option::Some(addr) => concat_1_8([1], addr.to_le_bytes()), + }, + ); + + concat_115_9( + buf, + match minimum_framebuffer_width { + Option::None => [0; 9], + Option::Some(addr) => concat_1_8([1], addr.to_le_bytes()), + }, + ) } /// Tries to deserialize a config byte array that was created using [`Self::serialize`]. @@ -209,6 +241,27 @@ impl BootloaderConfig { (mappings, s) }; + let (frame_buffer, s) = { + let (&min_framebuffer_height_some, s) = split_array_ref(s); + let (&min_framebuffer_height, s) = split_array_ref(s); + let (&min_framebuffer_width_some, s) = split_array_ref(s); + let (&min_framebuffer_width, s) = split_array_ref(s); + + let frame_buffer = FrameBuffer { + minimum_framebuffer_height: match min_framebuffer_height_some { + [0] if min_framebuffer_height == [0; 8] => Option::None, + [1] => Option::Some(u64::from_le_bytes(min_framebuffer_height)), + _ => return Err("minimum_framebuffer_height invalid"), + }, + minimum_framebuffer_width: match min_framebuffer_width_some { + [0] if min_framebuffer_width == [0; 8] => Option::None, + [1] => Option::Some(u64::from_le_bytes(min_framebuffer_width)), + _ => return Err("minimum_framebuffer_width invalid"), + }, + }; + (frame_buffer, s) + }; + if !s.is_empty() { return Err("unexpected rest"); } @@ -217,6 +270,7 @@ impl BootloaderConfig { version, kernel_stack_size: u64::from_le_bytes(kernel_stack_size), mappings, + frame_buffer, }) } @@ -226,6 +280,7 @@ impl BootloaderConfig { version: ApiVersion::random(), mappings: Mappings::random(), kernel_stack_size: rand::random(), + frame_buffer: FrameBuffer::random(), } } } @@ -454,6 +509,46 @@ impl Default for Mapping { } } +/// Configuration for the frame buffer used for graphical output. +#[derive(Debug, Default, PartialEq, Eq, Clone, Copy)] +#[non_exhaustive] +pub struct FrameBuffer { + /// Instructs the bootloader to set up a framebuffer format that has at least the given height. + /// + /// If this is not possible, the bootloader will fall back to a smaller format. + pub minimum_framebuffer_height: Option, + /// Instructs the bootloader to set up a framebuffer format that has at least the given width. + /// + /// If this is not possible, the bootloader will fall back to a smaller format. + pub minimum_framebuffer_width: Option, +} + +impl FrameBuffer { + /// Creates a default configuration without any requirements. + pub const fn new_default() -> Self { + Self { + minimum_framebuffer_height: Option::None, + minimum_framebuffer_width: Option::None, + } + } + + #[cfg(test)] + fn random() -> FrameBuffer { + Self { + minimum_framebuffer_height: if rand::random() { + Option::Some(rand::random()) + } else { + Option::None + }, + minimum_framebuffer_width: if rand::random() { + Option::Some(rand::random()) + } else { + Option::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/Cargo.toml b/bios/stage-4/Cargo.toml index c02209fb..fee9f5ac 100644 --- a/bios/stage-4/Cargo.toml +++ b/bios/stage-4/Cargo.toml @@ -16,6 +16,7 @@ log = "0.4.14" x86_64 = "0.14.8" rsdp = "2.0.0" usize_conversions = "0.2.0" +serde-json-core = "0.5.0" # This currently causes a cargo warning, but it is required for publishing to crates.io. # See https://github.com/rust-lang/cargo/issues/8264 for details. diff --git a/bios/stage-4/src/main.rs b/bios/stage-4/src/main.rs index 37c5813f..8063ccb0 100644 --- a/bios/stage-4/src/main.rs +++ b/bios/stage-4/src/main.rs @@ -1,12 +1,13 @@ #![no_std] #![no_main] +#![allow(deprecated)] use crate::memory_descriptor::MemoryRegion; use bootloader_api::info::{FrameBufferInfo, PixelFormat}; use bootloader_x86_64_bios_common::{BiosFramebufferInfo, BiosInfo, E820MemoryRegion}; use bootloader_x86_64_common::RawFrameBufferInfo; use bootloader_x86_64_common::{ - config::{BootloaderConfigFile, LevelFilter, LoggerStatus}, + config::{BootConfig, LevelFilter}, legacy_memory_region::LegacyFrameAllocator, load_and_switch_to_kernel, Kernel, PageTables, SystemInfo, }; @@ -111,7 +112,7 @@ pub extern "C" fn _start(info: &mut BiosInfo) -> ! { }; let kernel = Kernel::parse(kernel_slice); - let mut config_file_slice: Option<&'static mut [u8]> = None; + let mut config_file_slice: Option<&[u8]> = None; if info.config_file.len != 0 { config_file_slice = { let ptr = info.config_file.start as *mut u8; @@ -123,14 +124,26 @@ pub extern "C" fn _start(info: &mut BiosInfo) -> ! { } }; } - let config = match BootloaderConfigFile::deserialize(config_file_slice) { - Ok(data) => data, - Err((data, err)) => { - log::warn!("Failed to deserialize the config file {:?}", err); - data + let mut error_loading_config: Option = None; + let mut config: BootConfig = match config_file_slice + .map(serde_json_core::from_slice) + .transpose() + { + Ok(data) => data.unwrap_or_default().0, + Err(err) => { + error_loading_config = Some(err); + Default::default() } }; + if config.frame_buffer.minimum_framebuffer_height.is_none() { + config.frame_buffer.minimum_framebuffer_height = + kernel.config.frame_buffer.minimum_framebuffer_height; + } + if config.frame_buffer.minimum_framebuffer_width.is_none() { + config.frame_buffer.minimum_framebuffer_width = + kernel.config.frame_buffer.minimum_framebuffer_width; + } let framebuffer_info = init_logger( info.framebuffer, config.log_level, @@ -138,6 +151,10 @@ pub extern "C" fn _start(info: &mut BiosInfo) -> ! { config.serial_logger_status, ); + if let Some(err) = error_loading_config { + log::warn!("Failed to deserialize the config file {:?}", err); + } + log::info!("4th Stage"); log::info!("{info:x?}"); log::info!("BIOS boot"); @@ -161,8 +178,8 @@ pub extern "C" fn _start(info: &mut BiosInfo) -> ! { fn init_logger( info: BiosFramebufferInfo, log_level: LevelFilter, - frame_buffer_logger_status: LoggerStatus, - serial_logger_status: LoggerStatus, + frame_buffer_logger_status: bool, + serial_logger_status: bool, ) -> FrameBufferInfo { let framebuffer_info = FrameBufferInfo { byte_len: info.region.len.try_into().unwrap(), diff --git a/common/Cargo.toml b/common/Cargo.toml index 0ab7731f..cd41e720 100644 --- a/common/Cargo.toml +++ b/common/Cargo.toml @@ -11,7 +11,6 @@ repository.workspace = true [dependencies] bootloader_api = { workspace = true } conquer-once = { version = "0.3.2", default-features = false } -log = "0.4.14" spinning_top = "0.2.4" usize_conversions = "0.2.0" x86_64 = { version = "0.14.8" } @@ -22,6 +21,7 @@ rand_hc = "0.3.1" uart_16550 = "0.2.18" serde-json-core = "0.5.0" serde = { version = "1.0.152", default-features = false, features = ["derive"] } +log = "0.4.17" [dependencies.noto-sans-mono-bitmap] version = "0.2.0" diff --git a/common/src/config.rs b/common/src/config.rs index 34edfe83..985beca7 100644 --- a/common/src/config.rs +++ b/common/src/config.rs @@ -1,8 +1,7 @@ -use serde::Deserialize; -use serde_json_core::de; +use serde::{Deserialize, Serialize}; -#[derive(Deserialize)] -pub struct BootloaderConfigFile { +#[derive(Serialize, Deserialize)] +pub struct BootConfig { /// Configuration for the frame buffer that can be used by the kernel to display pixels /// on the screen. #[serde(default)] @@ -16,43 +15,29 @@ pub struct BootloaderConfigFile { /// Whether the bootloader should print log messages to the framebuffer when booting. /// /// Enabled by default. - #[serde(default)] - pub frame_buffer_logger_status: LoggerStatus, + #[serde(default = "default_logger_status")] + pub frame_buffer_logger_status: bool, /// Whether the bootloader should print log messages to the serial port when booting. /// /// Enabled by default. - #[serde(default)] - pub serial_logger_status: LoggerStatus, + #[serde(default = "default_logger_status")] + pub serial_logger_status: bool, } -impl Default for BootloaderConfigFile { +impl Default for BootConfig { fn default() -> Self { Self { frame_buffer: Default::default(), log_level: Default::default(), - frame_buffer_logger_status: Default::default(), - serial_logger_status: Default::default(), - } - } -} - -impl BootloaderConfigFile { - pub fn deserialize<'a>(serialized: Option<&'a mut [u8]>) -> Result { - match serialized { - Some(json) => { - match serde_json_core::from_slice::(&json) { - Ok((data, _)) => return Ok(data), - Err(err) => return Err((Default::default(), err)), - }; - } - None => return Ok(Default::default()), + frame_buffer_logger_status: true, + serial_logger_status: true, } } } /// Configuration for the frame buffer used for graphical output. -#[derive(Deserialize, Debug, Default, PartialEq, Eq, Clone, Copy)] +#[derive(Serialize, Deserialize, Debug, Default, PartialEq, Eq, Clone, Copy)] #[non_exhaustive] pub struct FrameBuffer { /// Instructs the bootloader to set up a framebuffer format that has at least the given height. @@ -65,29 +50,11 @@ pub struct FrameBuffer { pub minimum_framebuffer_width: Option, } -impl FrameBuffer { - #[cfg(test)] - fn random() -> FrameBuffer { - Self { - minimum_framebuffer_height: if rand::random() { - Option::Some(rand::random()) - } else { - Option::None - }, - minimum_framebuffer_width: if rand::random() { - Option::Some(rand::random()) - } else { - Option::None - }, - } - } -} - /// 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 -#[derive(Deserialize, Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[derive(Serialize, Deserialize, Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub enum LevelFilter { /// A level lower than all log levels. Off, @@ -109,17 +76,6 @@ impl Default for LevelFilter { } } -/// An enum for enabling or disabling the different methods for logging. -#[derive(Deserialize, Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub enum LoggerStatus { - /// This method of logging is disabled - Disable, - /// This method of logging is enabled - Enable, -} - -impl Default for LoggerStatus { - fn default() -> Self { - Self::Enable - } +fn default_logger_status() -> bool { + true } diff --git a/common/src/lib.rs b/common/src/lib.rs index 9e595844..9f0def71 100644 --- a/common/src/lib.rs +++ b/common/src/lib.rs @@ -3,7 +3,7 @@ #![deny(unsafe_op_in_unsafe_fn)] use crate::{ - config::{LevelFilter, LoggerStatus}, + config::LevelFilter, legacy_memory_region::{LegacyFrameAllocator, LegacyMemoryRegion}, }; use bootloader_api::{ @@ -48,8 +48,8 @@ pub fn init_logger( framebuffer: &'static mut [u8], info: FrameBufferInfo, log_level: LevelFilter, - frame_buffer_logger_status: LoggerStatus, - serial_logger_status: LoggerStatus, + frame_buffer_logger_status: bool, + serial_logger_status: bool, ) { let logger = logger::LOGGER.get_or_init(move || { logger::LockedLogger::new( diff --git a/common/src/logger.rs b/common/src/logger.rs index d3c27975..582e65e2 100644 --- a/common/src/logger.rs +++ b/common/src/logger.rs @@ -1,4 +1,4 @@ -use crate::{config::LoggerStatus, framebuffer::FrameBufferWriter, serial::SerialPort}; +use crate::{framebuffer::FrameBufferWriter, serial::SerialPort}; use bootloader_api::info::FrameBufferInfo; use conquer_once::spin::OnceCell; use core::fmt::Write; @@ -18,17 +18,17 @@ impl LockedLogger { pub fn new( framebuffer: &'static mut [u8], info: FrameBufferInfo, - frame_buffer_logger_status: LoggerStatus, - serial_logger_status: LoggerStatus, + frame_buffer_logger_status: bool, + serial_logger_status: bool, ) -> Self { let framebuffer = match frame_buffer_logger_status { - LoggerStatus::Enable => Some(Spinlock::new(FrameBufferWriter::new(framebuffer, info))), - LoggerStatus::Disable => None, + true => Some(Spinlock::new(FrameBufferWriter::new(framebuffer, info))), + false => None, }; let serial = match serial_logger_status { - LoggerStatus::Enable => Some(Spinlock::new(SerialPort::new())), - LoggerStatus::Disable => None, + true => Some(Spinlock::new(SerialPort::new())), + false => None, }; LockedLogger { diff --git a/src/bios/mbr.rs b/src/bios/mbr.rs index 821bb7eb..fb421f32 100644 --- a/src/bios/mbr.rs +++ b/src/bios/mbr.rs @@ -84,7 +84,7 @@ pub fn create_mbr_disk( assert_eq!( disk.stream_position() .context("failed to get disk image seek position")?, - (second_stage_start_sector * SECTOR_SIZE).into() + >::into(second_stage_start_sector * SECTOR_SIZE) ); io::copy(&mut second_stage, &mut disk) .context("failed to copy second stage binary to MBR disk image")?; diff --git a/src/bios/mod.rs b/src/bios/mod.rs index 6275affc..4abcf151 100644 --- a/src/bios/mod.rs +++ b/src/bios/mod.rs @@ -1,5 +1,7 @@ use crate::fat; use anyhow::Context; +use bootloader_x86_64_common::config::BootConfig; +use std::io::Write; use std::{ collections::BTreeMap, path::{Path, PathBuf}, @@ -15,7 +17,7 @@ const BIOS_STAGE_4: &str = "boot-stage-4"; pub struct BiosBoot { kernel: PathBuf, ramdisk: Option, - config_file: Option, + config: Option, } impl BiosBoot { @@ -24,7 +26,7 @@ impl BiosBoot { Self { kernel: kernel_path.to_owned(), ramdisk: None, - config_file: None, + config: None, } } @@ -35,8 +37,8 @@ impl BiosBoot { } /// Add a JSON configuration file to the disk image - pub fn set_config_file(&mut self, config_file_path: &Path) -> &mut Self { - self.config_file = Some(config_file_path.to_owned()); + pub fn set_config_file(&mut self, config: &BootConfig) -> &mut Self { + self.config = Some(serde_json::to_string(&config).expect("failed to serialize BootConfig")); self } @@ -76,8 +78,15 @@ impl BiosBoot { if let Some(ramdisk_path) = &self.ramdisk { files.insert(crate::RAMDISK_FILE_NAME, ramdisk_path); } - if let Some(config_file_path) = &self.config_file { - files.insert(crate::CONFIG_FILE_NAME, config_file_path); + + let mut config_file: NamedTempFile; + + if let Some(config_ser) = &self.config { + config_file = NamedTempFile::new() + .context("failed to create temp file") + .unwrap(); + writeln!(config_file, "{config_ser}")?; + files.insert(crate::CONFIG_FILE_NAME, config_file.path()); } let out_file = NamedTempFile::new().context("failed to create temp file")?; diff --git a/src/lib.rs b/src/lib.rs index de51b8e5..155cdf4c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -16,6 +16,8 @@ pub use bios::BiosBoot; #[cfg(feature = "uefi")] pub use uefi::UefiBoot; +pub use bootloader_x86_64_common::config::BootConfig; + const KERNEL_FILE_NAME: &str = "kernel-x86_64"; const RAMDISK_FILE_NAME: &str = "ramdisk"; -const CONFIG_FILE_NAME: &str = "config.json"; +const CONFIG_FILE_NAME: &str = "boot.json"; diff --git a/src/uefi/mod.rs b/src/uefi/mod.rs index bb96d500..10c4cd4d 100644 --- a/src/uefi/mod.rs +++ b/src/uefi/mod.rs @@ -1,5 +1,7 @@ use crate::fat; use anyhow::Context; +use bootloader_x86_64_common::config::BootConfig; +use std::io::Write; use std::{ collections::BTreeMap, path::{Path, PathBuf}, @@ -13,7 +15,7 @@ mod pxe; pub struct UefiBoot { kernel: PathBuf, ramdisk: Option, - config_file: Option, + config: Option, } impl UefiBoot { @@ -22,7 +24,7 @@ impl UefiBoot { Self { kernel: kernel_path.to_owned(), ramdisk: None, - config_file: None, + config: None, } } @@ -33,8 +35,8 @@ impl UefiBoot { } /// Add a JSON configuration file to the disk image - pub fn set_config_file(&mut self, config_file_path: &Path) -> &mut Self { - self.config_file = Some(config_file_path.to_owned()); + pub fn set_config_file(&mut self, config: &BootConfig) -> &mut Self { + self.config = Some(serde_json::to_string(&config).expect("failed to serialize BootConfig")); self } @@ -83,8 +85,15 @@ impl UefiBoot { if let Some(ramdisk_path) = &self.ramdisk { files.insert(crate::RAMDISK_FILE_NAME, ramdisk_path); } - if let Some(config_file_path) = &self.config_file { - files.insert(crate::CONFIG_FILE_NAME, config_file_path); + + let mut config_file: NamedTempFile; + + if let Some(config_ser) = &self.config { + config_file = NamedTempFile::new() + .context("failed to create temp file") + .unwrap(); + writeln!(config_file, "{config_ser}")?; + files.insert(crate::CONFIG_FILE_NAME, config_file.path()); } let out_file = NamedTempFile::new().context("failed to create temp file")?; diff --git a/tests/config_file.rs b/tests/config_file.rs index 99933531..a4104f92 100644 --- a/tests/config_file.rs +++ b/tests/config_file.rs @@ -1,21 +1,28 @@ -use std::path::Path; +use bootloader_test_runner::run_test_kernel_internal; -use bootloader_test_runner::run_test_kernel; +use bootloader::BootConfig; #[test] fn basic_boot() { - run_test_kernel( + let config: BootConfig = Default::default(); + run_test_kernel_internal( env!("CARGO_BIN_FILE_TEST_KERNEL_CONFIG_FILE_basic_boot"), None, - Some(Path::new("tests/config_files/full_config.json")), + Some(&config), ); } #[test] -fn basic_boot_broken_config_file() { - run_test_kernel( +fn custom_options_boot() { + let config = BootConfig { + frame_buffer: Default::default(), + log_level: Default::default(), + frame_buffer_logger_status: false, + serial_logger_status: true, + }; + run_test_kernel_internal( env!("CARGO_BIN_FILE_TEST_KERNEL_CONFIG_FILE_basic_boot_broken_config_file"), None, - Some(Path::new("tests/config_files/broken_config.json")), + Some(&config), ); } diff --git a/tests/config_files/broken_config.json b/tests/config_files/broken_config.json deleted file mode 100644 index 77128d36..00000000 --- a/tests/config_files/broken_config.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - Lorem ipsum dolor sit amet consectetue -} diff --git a/tests/config_files/full_config.json b/tests/config_files/full_config.json deleted file mode 100644 index b721967e..00000000 --- a/tests/config_files/full_config.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "frame_buffer": { "minimun_framebuffer_height": null, "minimun_framebuffer_width": null }, - "log_level": "Trace", - "frame_buffer_logger_status": "Enable", - "serial_logger_status": "Enable" -} diff --git a/tests/default_settings.rs b/tests/default_settings.rs index 0069af03..d610508c 100644 --- a/tests/default_settings.rs +++ b/tests/default_settings.rs @@ -2,27 +2,21 @@ use bootloader_test_runner::run_test_kernel; #[test] fn basic_boot() { - run_test_kernel( - env!("CARGO_BIN_FILE_TEST_KERNEL_DEFAULT_SETTINGS_basic_boot"), - None, - None, - ); + run_test_kernel(env!( + "CARGO_BIN_FILE_TEST_KERNEL_DEFAULT_SETTINGS_basic_boot" + )); } #[test] fn should_panic() { - run_test_kernel( - env!("CARGO_BIN_FILE_TEST_KERNEL_DEFAULT_SETTINGS_should_panic"), - None, - None, - ); + run_test_kernel(env!( + "CARGO_BIN_FILE_TEST_KERNEL_DEFAULT_SETTINGS_should_panic" + )); } #[test] fn check_boot_info() { - run_test_kernel( - env!("CARGO_BIN_FILE_TEST_KERNEL_DEFAULT_SETTINGS_check_boot_info"), - None, - None, - ); + run_test_kernel(env!( + "CARGO_BIN_FILE_TEST_KERNEL_DEFAULT_SETTINGS_check_boot_info" + )); } diff --git a/tests/higher_half.rs b/tests/higher_half.rs index 2b754e0a..c2b9ac91 100644 --- a/tests/higher_half.rs +++ b/tests/higher_half.rs @@ -2,36 +2,24 @@ use bootloader_test_runner::run_test_kernel; #[test] fn basic_boot() { - run_test_kernel( - env!("CARGO_BIN_FILE_TEST_KERNEL_HIGHER_HALF_basic_boot"), - None, - None, - ); + run_test_kernel(env!("CARGO_BIN_FILE_TEST_KERNEL_HIGHER_HALF_basic_boot")); } #[test] fn should_panic() { - run_test_kernel( - env!("CARGO_BIN_FILE_TEST_KERNEL_HIGHER_HALF_should_panic"), - None, - None, - ); + run_test_kernel(env!("CARGO_BIN_FILE_TEST_KERNEL_HIGHER_HALF_should_panic")); } #[test] fn check_boot_info() { - run_test_kernel( - env!("CARGO_BIN_FILE_TEST_KERNEL_HIGHER_HALF_check_boot_info"), - None, - None, - ); + run_test_kernel(env!( + "CARGO_BIN_FILE_TEST_KERNEL_HIGHER_HALF_check_boot_info" + )); } #[test] fn verify_higher_half() { - run_test_kernel( - env!("CARGO_BIN_FILE_TEST_KERNEL_HIGHER_HALF_verify_higher_half"), - None, - None, - ); + run_test_kernel(env!( + "CARGO_BIN_FILE_TEST_KERNEL_HIGHER_HALF_verify_higher_half" + )); } diff --git a/tests/lto.rs b/tests/lto.rs index e31b3060..00cfe60f 100644 --- a/tests/lto.rs +++ b/tests/lto.rs @@ -21,5 +21,5 @@ fn basic_boot() { .join("basic_boot"); assert!(kernel_path.exists()); - run_test_kernel(kernel_path.as_path().to_str().unwrap(), None, None); + run_test_kernel(kernel_path.as_path().to_str().unwrap()); } diff --git a/tests/map_phys_mem.rs b/tests/map_phys_mem.rs index a322ac92..b19ba987 100644 --- a/tests/map_phys_mem.rs +++ b/tests/map_phys_mem.rs @@ -2,18 +2,14 @@ use bootloader_test_runner::run_test_kernel; #[test] fn check_boot_info() { - run_test_kernel( - env!("CARGO_BIN_FILE_TEST_KERNEL_MAP_PHYS_MEM_check_boot_info"), - None, - None, - ); + run_test_kernel(env!( + "CARGO_BIN_FILE_TEST_KERNEL_MAP_PHYS_MEM_check_boot_info" + )); } #[test] fn access_phys_mem() { - run_test_kernel( - env!("CARGO_BIN_FILE_TEST_KERNEL_MAP_PHYS_MEM_access_phys_mem"), - None, - None, - ); + run_test_kernel(env!( + "CARGO_BIN_FILE_TEST_KERNEL_MAP_PHYS_MEM_access_phys_mem" + )); } diff --git a/tests/pie.rs b/tests/pie.rs index bdafaf4d..c2d30d80 100644 --- a/tests/pie.rs +++ b/tests/pie.rs @@ -2,36 +2,20 @@ use bootloader_test_runner::run_test_kernel; #[test] fn basic_boot() { - run_test_kernel( - env!("CARGO_BIN_FILE_TEST_KERNEL_PIE_basic_boot"), - None, - None, - ); + run_test_kernel(env!("CARGO_BIN_FILE_TEST_KERNEL_PIE_basic_boot")); } #[test] fn should_panic() { - run_test_kernel( - env!("CARGO_BIN_FILE_TEST_KERNEL_PIE_should_panic"), - None, - None, - ); + run_test_kernel(env!("CARGO_BIN_FILE_TEST_KERNEL_PIE_should_panic")); } #[test] fn check_boot_info() { - run_test_kernel( - env!("CARGO_BIN_FILE_TEST_KERNEL_PIE_check_boot_info"), - None, - None, - ); + run_test_kernel(env!("CARGO_BIN_FILE_TEST_KERNEL_PIE_check_boot_info")); } #[test] fn global_variable() { - run_test_kernel( - env!("CARGO_BIN_FILE_TEST_KERNEL_PIE_global_variable"), - None, - None, - ); + run_test_kernel(env!("CARGO_BIN_FILE_TEST_KERNEL_PIE_global_variable")); } diff --git a/tests/ramdisk.rs b/tests/ramdisk.rs index 881ce98c..bdd7f9db 100644 --- a/tests/ramdisk.rs +++ b/tests/ramdisk.rs @@ -1,22 +1,20 @@ use std::path::Path; -use bootloader_test_runner::run_test_kernel; +use bootloader_test_runner::run_test_kernel_with_ramdisk; static RAMDISK_PATH: &str = "tests/ramdisk.txt"; #[test] fn basic_boot() { - run_test_kernel( + run_test_kernel_with_ramdisk( env!("CARGO_BIN_FILE_TEST_KERNEL_RAMDISK_basic_boot"), Some(Path::new(RAMDISK_PATH)), - None, ); } #[test] fn check_ramdisk() { - run_test_kernel( + run_test_kernel_with_ramdisk( env!("CARGO_BIN_FILE_TEST_KERNEL_RAMDISK_ramdisk"), Some(Path::new(RAMDISK_PATH)), - None, ); } diff --git a/tests/runner/src/lib.rs b/tests/runner/src/lib.rs index b3ec8dd5..9c156fd8 100644 --- a/tests/runner/src/lib.rs +++ b/tests/runner/src/lib.rs @@ -1,3 +1,4 @@ +use bootloader::BootConfig; use std::{io::Write, path::Path, process::Command}; const QEMU_ARGS: &[&str] = &[ @@ -10,10 +11,23 @@ const QEMU_ARGS: &[&str] = &[ "--no-reboot", ]; -pub fn run_test_kernel( +pub fn run_test_kernel(kernel_binary_path: &str) { + run_test_kernel_internal(kernel_binary_path, None, None) +} +pub fn run_test_kernel_with_ramdisk(kernel_binary_path: &str, ramdisk_path: Option<&Path>) { + run_test_kernel_internal(kernel_binary_path, ramdisk_path, None) +} +pub fn run_test_kernel_with_config_file( + kernel_binary_path: &str, + config_file: Option<&BootConfig>, +) { + run_test_kernel_internal(kernel_binary_path, None, config_file) +} + +pub fn run_test_kernel_internal( kernel_binary_path: &str, ramdisk_path: Option<&Path>, - config_file_path: Option<&Path>, + config_file_path: Option<&BootConfig>, ) { let kernel_path = Path::new(kernel_binary_path); @@ -27,7 +41,7 @@ pub fn run_test_kernel( uefi_builder.set_ramdisk(rdp); } if let Some(cfp) = config_file_path { - uefi_builder.set_ramdisk(cfp); + uefi_builder.set_config_file(cfp); } uefi_builder.create_disk_image(&gpt_path).unwrap(); @@ -50,7 +64,7 @@ pub fn run_test_kernel( bios_builder.set_ramdisk(rdp); } if let Some(cfp) = config_file_path { - bios_builder.set_ramdisk(cfp); + bios_builder.set_config_file(cfp); } bios_builder.create_disk_image(&mbr_path).unwrap(); diff --git a/uefi/Cargo.toml b/uefi/Cargo.toml index a637db6e..0cba7533 100644 --- a/uefi/Cargo.toml +++ b/uefi/Cargo.toml @@ -14,3 +14,4 @@ bootloader-x86_64-common = { workspace = true } log = "0.4.14" uefi = "0.18.0" x86_64 = "0.14.8" +serde-json-core = "0.5.0" diff --git a/uefi/src/main.rs b/uefi/src/main.rs index ab054d82..a90ef8bc 100644 --- a/uefi/src/main.rs +++ b/uefi/src/main.rs @@ -2,16 +2,16 @@ #![no_main] #![feature(abi_efiapi)] #![deny(unsafe_op_in_unsafe_fn)] +#![allow(deprecated)] use crate::memory_descriptor::UefiMemoryDescriptor; use bootloader_api::info::FrameBufferInfo; use bootloader_x86_64_common::{ - config::BootloaderConfigFile, legacy_memory_region::LegacyFrameAllocator, Kernel, - RawFrameBufferInfo, SystemInfo, + config::BootConfig, legacy_memory_region::LegacyFrameAllocator, Kernel, RawFrameBufferInfo, + SystemInfo, }; use core::{ cell::UnsafeCell, - fmt::Write, ops::{Deref, DerefMut}, ptr, slice, }; @@ -73,64 +73,69 @@ fn main_inner(image: Handle, mut st: SystemTable) -> Status { unsafe { *SYSTEM_TABLE.get() = Some(st.unsafe_clone()); } - st.stdout().clear().unwrap(); - writeln!( - st.stdout(), - "UEFI bootloader started; trying to load kernel" - ) - .unwrap(); let mut boot_mode = BootMode::Disk; + let config_file = load_config_file(image, &mut st, boot_mode); + let config_file: Option<&[u8]> = match config_file { + Some(config) => Some(config), + None => None, + }; + + let mut error_loading_config: Option = None; + let mut config: BootConfig = match config_file.map(serde_json_core::from_slice).transpose() { + Ok(data) => data.unwrap_or_default().0, + Err(err) => { + error_loading_config = Some(err); + Default::default() + } + }; + let mut kernel = load_kernel(image, &mut st, boot_mode); if kernel.is_none() { - writeln!( - st.stdout(), - "Failed to load kernel via {:?}, trying TFTP", - boot_mode - ) - .unwrap(); // Try TFTP boot boot_mode = BootMode::Tftp; kernel = load_kernel(image, &mut st, boot_mode); } let kernel = kernel.expect("Failed to load kernel"); - writeln!(st.stdout(), "Trying to load ramdisk via {:?}", boot_mode).unwrap(); - // Ramdisk must load from same source, or not at all. - let ramdisk = load_ramdisk(image, &mut st, boot_mode); - - let config_file = load_config_file(image, &mut st, boot_mode); - let config = match BootloaderConfigFile::deserialize(config_file) { - Ok(data) => data, - Err((data, err)) => { - writeln!( - st.stdout(), - "Failed to deserialize the config file {:?}", - err - ) - .unwrap(); - data - } - }; - - writeln!( - st.stdout(), - "{}", - match ramdisk { - Some(_) => "Loaded ramdisk", - None => "Ramdisk not found.", - } - ) - .unwrap(); + if config.frame_buffer.minimum_framebuffer_height.is_none() { + config.frame_buffer.minimum_framebuffer_height = + kernel.config.frame_buffer.minimum_framebuffer_height; + } + if config.frame_buffer.minimum_framebuffer_width.is_none() { + config.frame_buffer.minimum_framebuffer_width = + kernel.config.frame_buffer.minimum_framebuffer_width; + } let framebuffer = init_logger(image, &st, config); + unsafe { *SYSTEM_TABLE.get() = None; } + log::info!("UEFI bootloader started"); - log::info!("Reading kernel and configuration from disk was successful"); + if let Some(framebuffer) = framebuffer { log::info!("Using framebuffer at {:#x}", framebuffer.addr); } + + if let Some(err) = error_loading_config { + log::warn!("Failed to deserialize the config file {:?}", err); + } else { + log::info!("Reading configuration from disk was successful"); + } + + log::info!("Trying to load ramdisk via {:?}", boot_mode); + // Ramdisk must load from same source, or not at all. + let ramdisk = load_ramdisk(image, &mut st, boot_mode); + + log::info!( + "{}", + match ramdisk { + Some(_) => "Loaded ramdisk", + None => "Ramdisk not found.", + } + ); + let mmap_storage = { let mut memory_map_size = st.boot_services().memory_map_size(); loop { @@ -469,7 +474,7 @@ fn create_page_tables( fn init_logger( image_handle: Handle, st: &SystemTable, - config: BootloaderConfigFile, + config: BootConfig, ) -> Option { let gop_handle = st .boot_services() @@ -554,8 +559,10 @@ fn init_logger( #[panic_handler] fn panic(info: &core::panic::PanicInfo) -> ! { use core::arch::asm; + use core::fmt::Write; if let Some(st) = unsafe { &mut *SYSTEM_TABLE.get() } { + let _ = st.stdout().clear(); let _ = writeln!(st.stdout(), "{}", info); } From bb461c3c12871d5f85104b426d0a67dfb4fae58b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juanjo=20Asensio=20Garc=C3=ADa?= Date: Thu, 26 Jan 2023 16:52:49 +0100 Subject: [PATCH 7/9] Apply suggestions (Second Part) --- Cargo.lock | 14 ++++++++++--- Cargo.toml | 4 +++- api/src/config.rs | 2 +- bios/stage-4/Cargo.toml | 1 + bios/stage-4/src/main.rs | 13 ++++++------ common/Cargo.toml | 3 +-- common/config/Cargo.toml | 10 ++++++++++ common/{src/config.rs => config/src/lib.rs} | 19 +++++------------- common/src/lib.rs | 8 ++------ src/bios/mbr.rs | 2 +- src/bios/mod.rs | 8 ++++---- src/lib.rs | 2 +- src/uefi/mod.rs | 8 ++++---- tests/config_file.rs | 4 ++-- tests/runner/src/lib.rs | 4 ++-- uefi/Cargo.toml | 1 + uefi/src/main.rs | 22 ++++++++++----------- 17 files changed, 67 insertions(+), 58 deletions(-) create mode 100644 common/config/Cargo.toml rename common/{src/config.rs => config/src/lib.rs} (85%) diff --git a/Cargo.lock b/Cargo.lock index 8c7f2e17..c38513c8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -153,7 +153,7 @@ version = "0.11.0" dependencies = [ "anyhow", "async-process", - "bootloader-x86_64-common", + "bootloader-boot-config", "bootloader_test_runner", "fatfs", "futures", @@ -171,6 +171,13 @@ dependencies = [ "test_kernel_ramdisk", ] +[[package]] +name = "bootloader-boot-config" +version = "0.11.0" +dependencies = [ + "serde", +] + [[package]] name = "bootloader-x86_64-bios-boot-sector" version = "0.11.0" @@ -200,6 +207,7 @@ dependencies = [ name = "bootloader-x86_64-bios-stage-4" version = "0.11.0" dependencies = [ + "bootloader-boot-config", "bootloader-x86_64-bios-common", "bootloader-x86_64-common", "bootloader_api", @@ -214,6 +222,7 @@ dependencies = [ name = "bootloader-x86_64-common" version = "0.11.0" dependencies = [ + "bootloader-boot-config", "bootloader_api", "conquer-once", "log", @@ -221,8 +230,6 @@ dependencies = [ "rand", "rand_hc", "raw-cpuid", - "serde", - "serde-json-core", "spinning_top", "uart_16550", "usize_conversions", @@ -234,6 +241,7 @@ dependencies = [ name = "bootloader-x86_64-uefi" version = "0.11.0" dependencies = [ + "bootloader-boot-config", "bootloader-x86_64-common", "bootloader_api", "log", diff --git a/Cargo.toml b/Cargo.toml index 84352f02..80abc3a8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,6 +13,7 @@ edition = "2021" members = [ "api", "common", + "common/config", "uefi", "bios/boot_sector", "bios/stage-*", @@ -36,6 +37,7 @@ repository = "https://github.com/rust-osdev/bootloader" [workspace.dependencies] bootloader_api = { version = "0.11.0", path = "api" } bootloader-x86_64-common = { version = "0.11.0", path = "common" } +bootloader-boot-config = { version = "0.11.0", path = "common/config" } bootloader-x86_64-bios-common = { version = "0.11.0", path = "bios/common" } [features] @@ -49,7 +51,7 @@ fatfs = "0.3.4" tempfile = "3.3.0" mbrman = { version = "0.5.1", optional = true } gpt = { version = "3.0.0", optional = true } -bootloader-x86_64-common = { version = "0.11.0", path = "common" } +bootloader-boot-config = { version = "0.11.0", path = "common/config" } serde_json = "1.0.91" [dev-dependencies] diff --git a/api/src/config.rs b/api/src/config.rs index d4d953c1..a8c2b5ca 100644 --- a/api/src/config.rs +++ b/api/src/config.rs @@ -30,7 +30,7 @@ pub struct BootloaderConfig { /// on the screen. #[deprecated( since = "0.11.1", - note = "This field is being obsolete because now it's at the JSON configuration file" + note = "The frame buffer is now configured through the `BootConfig` struct when creating the bootable disk image" )] pub frame_buffer: FrameBuffer, } diff --git a/bios/stage-4/Cargo.toml b/bios/stage-4/Cargo.toml index fee9f5ac..769ca657 100644 --- a/bios/stage-4/Cargo.toml +++ b/bios/stage-4/Cargo.toml @@ -12,6 +12,7 @@ description = "Fourth BIOS stage of the `bootloader` crate" bootloader_api = { workspace = true } bootloader-x86_64-common = { workspace = true } bootloader-x86_64-bios-common = { workspace = true } +bootloader-boot-config = { workspace = true } log = "0.4.14" x86_64 = "0.14.8" rsdp = "2.0.0" diff --git a/bios/stage-4/src/main.rs b/bios/stage-4/src/main.rs index 8063ccb0..f51f2252 100644 --- a/bios/stage-4/src/main.rs +++ b/bios/stage-4/src/main.rs @@ -1,15 +1,14 @@ #![no_std] #![no_main] -#![allow(deprecated)] use crate::memory_descriptor::MemoryRegion; use bootloader_api::info::{FrameBufferInfo, PixelFormat}; +use bootloader_boot_config::{BootConfig, LevelFilter}; use bootloader_x86_64_bios_common::{BiosFramebufferInfo, BiosInfo, E820MemoryRegion}; use bootloader_x86_64_common::RawFrameBufferInfo; use bootloader_x86_64_common::{ - config::{BootConfig, LevelFilter}, - legacy_memory_region::LegacyFrameAllocator, - load_and_switch_to_kernel, Kernel, PageTables, SystemInfo, + legacy_memory_region::LegacyFrameAllocator, load_and_switch_to_kernel, Kernel, PageTables, + SystemInfo, }; use core::{cmp, slice}; use usize_conversions::usize_from; @@ -136,10 +135,12 @@ pub extern "C" fn _start(info: &mut BiosInfo) -> ! { } }; + #[allow(deprecated)] if config.frame_buffer.minimum_framebuffer_height.is_none() { config.frame_buffer.minimum_framebuffer_height = kernel.config.frame_buffer.minimum_framebuffer_height; } + #[allow(deprecated)] if config.frame_buffer.minimum_framebuffer_width.is_none() { config.frame_buffer.minimum_framebuffer_width = kernel.config.frame_buffer.minimum_framebuffer_width; @@ -147,8 +148,8 @@ pub extern "C" fn _start(info: &mut BiosInfo) -> ! { let framebuffer_info = init_logger( info.framebuffer, config.log_level, - config.frame_buffer_logger_status, - config.serial_logger_status, + config.frame_buffer_logging, + config.serial_logging, ); if let Some(err) = error_loading_config { diff --git a/common/Cargo.toml b/common/Cargo.toml index cd41e720..afc8ed7d 100644 --- a/common/Cargo.toml +++ b/common/Cargo.toml @@ -10,6 +10,7 @@ repository.workspace = true [dependencies] bootloader_api = { workspace = true } +bootloader-boot-config = { workspace = true } conquer-once = { version = "0.3.2", default-features = false } spinning_top = "0.2.4" usize_conversions = "0.2.0" @@ -19,8 +20,6 @@ raw-cpuid = "10.2.0" rand = { version = "0.8.4", default-features = false } rand_hc = "0.3.1" uart_16550 = "0.2.18" -serde-json-core = "0.5.0" -serde = { version = "1.0.152", default-features = false, features = ["derive"] } log = "0.4.17" [dependencies.noto-sans-mono-bitmap] diff --git a/common/config/Cargo.toml b/common/config/Cargo.toml new file mode 100644 index 00000000..560c6284 --- /dev/null +++ b/common/config/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "bootloader-boot-config" +version.workspace = true +edition = "2021" +description = "The runtime configurations that are saved in a JSON file for the bootloader crate" +license.workspace = true +repository.workspace = true + +[dependencies] +serde = { version = "1.0.152", default-features = false, features = ["derive"] } diff --git a/common/src/config.rs b/common/config/src/lib.rs similarity index 85% rename from common/src/config.rs rename to common/config/src/lib.rs index 985beca7..f9031fd7 100644 --- a/common/src/config.rs +++ b/common/config/src/lib.rs @@ -1,6 +1,8 @@ +#![no_std] + use serde::{Deserialize, Serialize}; -#[derive(Serialize, Deserialize)] +#[derive(Serialize, Deserialize, Default)] pub struct BootConfig { /// Configuration for the frame buffer that can be used by the kernel to display pixels /// on the screen. @@ -16,24 +18,13 @@ pub struct BootConfig { /// /// Enabled by default. #[serde(default = "default_logger_status")] - pub frame_buffer_logger_status: bool, + pub frame_buffer_logging: bool, /// Whether the bootloader should print log messages to the serial port when booting. /// /// Enabled by default. #[serde(default = "default_logger_status")] - pub serial_logger_status: bool, -} - -impl Default for BootConfig { - fn default() -> Self { - Self { - frame_buffer: Default::default(), - log_level: Default::default(), - frame_buffer_logger_status: true, - serial_logger_status: true, - } - } + pub serial_logging: bool, } /// Configuration for the frame buffer used for graphical output. diff --git a/common/src/lib.rs b/common/src/lib.rs index 9f0def71..97778db1 100644 --- a/common/src/lib.rs +++ b/common/src/lib.rs @@ -2,15 +2,13 @@ #![feature(step_trait)] #![deny(unsafe_op_in_unsafe_fn)] -use crate::{ - config::LevelFilter, - legacy_memory_region::{LegacyFrameAllocator, LegacyMemoryRegion}, -}; +use crate::legacy_memory_region::{LegacyFrameAllocator, LegacyMemoryRegion}; use bootloader_api::{ config::Mapping, info::{FrameBuffer, FrameBufferInfo, MemoryRegion, TlsTemplate}, BootInfo, BootloaderConfig, }; +use bootloader_boot_config::LevelFilter; use core::{alloc::Layout, arch::asm, mem::MaybeUninit, slice}; use level_4_entries::UsedLevel4Entries; use usize_conversions::FromUsize; @@ -23,8 +21,6 @@ use x86_64::{ }; use xmas_elf::ElfFile; -/// Provides a type with the runtime configurations that are saved in a JSON file. -pub mod config; /// Provides a function to gather entropy and build a RNG. mod entropy; /// Provides a type that logs output as text to pixel-based framebuffers. diff --git a/src/bios/mbr.rs b/src/bios/mbr.rs index fb421f32..6c7a9f0d 100644 --- a/src/bios/mbr.rs +++ b/src/bios/mbr.rs @@ -84,7 +84,7 @@ pub fn create_mbr_disk( assert_eq!( disk.stream_position() .context("failed to get disk image seek position")?, - >::into(second_stage_start_sector * SECTOR_SIZE) + u64::from(second_stage_start_sector * SECTOR_SIZE) ); io::copy(&mut second_stage, &mut disk) .context("failed to copy second stage binary to MBR disk image")?; diff --git a/src/bios/mod.rs b/src/bios/mod.rs index 4abcf151..ec0db402 100644 --- a/src/bios/mod.rs +++ b/src/bios/mod.rs @@ -1,6 +1,6 @@ use crate::fat; use anyhow::Context; -use bootloader_x86_64_common::config::BootConfig; +use bootloader_boot_config::BootConfig; use std::io::Write; use std::{ collections::BTreeMap, @@ -30,14 +30,14 @@ impl BiosBoot { } } - /// Add a ramdisk file to the image + /// Add a ramdisk file to the image. pub fn set_ramdisk(&mut self, ramdisk_path: &Path) -> &mut Self { self.ramdisk = Some(ramdisk_path.to_owned()); self } - /// Add a JSON configuration file to the disk image - pub fn set_config_file(&mut self, config: &BootConfig) -> &mut Self { + /// Configures the runtime behavior of the bootloader. + pub fn set_boot_config(&mut self, config: &BootConfig) -> &mut Self { self.config = Some(serde_json::to_string(&config).expect("failed to serialize BootConfig")); self } diff --git a/src/lib.rs b/src/lib.rs index 155cdf4c..ff1894de 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -16,7 +16,7 @@ pub use bios::BiosBoot; #[cfg(feature = "uefi")] pub use uefi::UefiBoot; -pub use bootloader_x86_64_common::config::BootConfig; +pub use bootloader_boot_config::BootConfig; const KERNEL_FILE_NAME: &str = "kernel-x86_64"; const RAMDISK_FILE_NAME: &str = "ramdisk"; diff --git a/src/uefi/mod.rs b/src/uefi/mod.rs index 10c4cd4d..69024718 100644 --- a/src/uefi/mod.rs +++ b/src/uefi/mod.rs @@ -1,6 +1,6 @@ use crate::fat; use anyhow::Context; -use bootloader_x86_64_common::config::BootConfig; +use bootloader_boot_config::BootConfig; use std::io::Write; use std::{ collections::BTreeMap, @@ -28,14 +28,14 @@ impl UefiBoot { } } - /// Add a ramdisk file to the disk image + /// Add a ramdisk file to the disk image. pub fn set_ramdisk(&mut self, ramdisk_path: &Path) -> &mut Self { self.ramdisk = Some(ramdisk_path.to_owned()); self } - /// Add a JSON configuration file to the disk image - pub fn set_config_file(&mut self, config: &BootConfig) -> &mut Self { + /// Configures the runtime behavior of the bootloader. + pub fn set_boot_config(&mut self, config: &BootConfig) -> &mut Self { self.config = Some(serde_json::to_string(&config).expect("failed to serialize BootConfig")); self } diff --git a/tests/config_file.rs b/tests/config_file.rs index a4104f92..af5c0f31 100644 --- a/tests/config_file.rs +++ b/tests/config_file.rs @@ -17,8 +17,8 @@ fn custom_options_boot() { let config = BootConfig { frame_buffer: Default::default(), log_level: Default::default(), - frame_buffer_logger_status: false, - serial_logger_status: true, + frame_buffer_logging: false, + serial_logging: true, }; run_test_kernel_internal( env!("CARGO_BIN_FILE_TEST_KERNEL_CONFIG_FILE_basic_boot_broken_config_file"), diff --git a/tests/runner/src/lib.rs b/tests/runner/src/lib.rs index 9c156fd8..f0b5b16d 100644 --- a/tests/runner/src/lib.rs +++ b/tests/runner/src/lib.rs @@ -41,7 +41,7 @@ pub fn run_test_kernel_internal( uefi_builder.set_ramdisk(rdp); } if let Some(cfp) = config_file_path { - uefi_builder.set_config_file(cfp); + uefi_builder.set_boot_config(cfp); } uefi_builder.create_disk_image(&gpt_path).unwrap(); @@ -64,7 +64,7 @@ pub fn run_test_kernel_internal( bios_builder.set_ramdisk(rdp); } if let Some(cfp) = config_file_path { - bios_builder.set_config_file(cfp); + bios_builder.set_boot_config(cfp); } bios_builder.create_disk_image(&mbr_path).unwrap(); diff --git a/uefi/Cargo.toml b/uefi/Cargo.toml index 0cba7533..b9f5ec29 100644 --- a/uefi/Cargo.toml +++ b/uefi/Cargo.toml @@ -11,6 +11,7 @@ repository.workspace = true [dependencies] bootloader_api = { workspace = true } bootloader-x86_64-common = { workspace = true } +bootloader-boot-config = { workspace = true } log = "0.4.14" uefi = "0.18.0" x86_64 = "0.14.8" diff --git a/uefi/src/main.rs b/uefi/src/main.rs index a90ef8bc..1b809d62 100644 --- a/uefi/src/main.rs +++ b/uefi/src/main.rs @@ -2,13 +2,12 @@ #![no_main] #![feature(abi_efiapi)] #![deny(unsafe_op_in_unsafe_fn)] -#![allow(deprecated)] use crate::memory_descriptor::UefiMemoryDescriptor; use bootloader_api::info::FrameBufferInfo; +use bootloader_boot_config::BootConfig; use bootloader_x86_64_common::{ - config::BootConfig, legacy_memory_region::LegacyFrameAllocator, Kernel, RawFrameBufferInfo, - SystemInfo, + legacy_memory_region::LegacyFrameAllocator, Kernel, RawFrameBufferInfo, SystemInfo, }; use core::{ cell::UnsafeCell, @@ -76,13 +75,12 @@ fn main_inner(image: Handle, mut st: SystemTable) -> Status { let mut boot_mode = BootMode::Disk; let config_file = load_config_file(image, &mut st, boot_mode); - let config_file: Option<&[u8]> = match config_file { - Some(config) => Some(config), - None => None, - }; - let mut error_loading_config: Option = None; - let mut config: BootConfig = match config_file.map(serde_json_core::from_slice).transpose() { + let mut config: BootConfig = match config_file + .as_deref() + .map(serde_json_core::from_slice) + .transpose() + { Ok(data) => data.unwrap_or_default().0, Err(err) => { error_loading_config = Some(err); @@ -98,10 +96,12 @@ fn main_inner(image: Handle, mut st: SystemTable) -> Status { } let kernel = kernel.expect("Failed to load kernel"); + #[allow(deprecated)] if config.frame_buffer.minimum_framebuffer_height.is_none() { config.frame_buffer.minimum_framebuffer_height = kernel.config.frame_buffer.minimum_framebuffer_height; } + #[allow(deprecated)] if config.frame_buffer.minimum_framebuffer_width.is_none() { config.frame_buffer.minimum_framebuffer_width = kernel.config.frame_buffer.minimum_framebuffer_width; @@ -545,8 +545,8 @@ fn init_logger( slice, info, config.log_level, - config.frame_buffer_logger_status, - config.serial_logger_status, + config.frame_buffer_logging, + config.serial_logging, ); Some(RawFrameBufferInfo { From a6ee0f4f7b1e5406700321922ee212630a1ac163 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juanjo=20Asensio=20Garc=C3=ADa?= Date: Thu, 26 Jan 2023 17:14:50 +0100 Subject: [PATCH 8/9] Fix an import --- tests/runner/src/lib.rs | 2 +- uefi/src/main.rs | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/runner/src/lib.rs b/tests/runner/src/lib.rs index 120ec2d4..eb11384b 100644 --- a/tests/runner/src/lib.rs +++ b/tests/runner/src/lib.rs @@ -1,5 +1,5 @@ use bootloader::BootConfig; -use std::{io::Write, path::Path, process::Command}; +use std::{io::Read, path::Path, process::Command}; const QEMU_ARGS: &[&str] = &[ "-device", diff --git a/uefi/src/main.rs b/uefi/src/main.rs index 1b809d62..47653ca1 100644 --- a/uefi/src/main.rs +++ b/uefi/src/main.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(abi_efiapi)] #![deny(unsafe_op_in_unsafe_fn)] use crate::memory_descriptor::UefiMemoryDescriptor; From 32277c4e16cc31dbd60482fd536ee42a47b0ea49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juanjo=20Asensio=20Garc=C3=ADa?= Date: Fri, 27 Jan 2023 14:49:18 +0100 Subject: [PATCH 9/9] Improve Default trait use in bootloader boot config --- common/config/src/lib.rs | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/common/config/src/lib.rs b/common/config/src/lib.rs index f9031fd7..6599c09e 100644 --- a/common/config/src/lib.rs +++ b/common/config/src/lib.rs @@ -2,31 +2,39 @@ use serde::{Deserialize, Serialize}; -#[derive(Serialize, Deserialize, Default)] +#[derive(Serialize, Deserialize)] +#[serde(default)] pub struct BootConfig { /// Configuration for the frame buffer that can be used by the kernel to display pixels /// on the screen. - #[serde(default)] 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'. - #[serde(default)] pub log_level: LevelFilter, /// Whether the bootloader should print log messages to the framebuffer when booting. /// /// Enabled by default. - #[serde(default = "default_logger_status")] pub frame_buffer_logging: bool, /// Whether the bootloader should print log messages to the serial port when booting. /// /// Enabled by default. - #[serde(default = "default_logger_status")] pub serial_logging: bool, } +impl Default for BootConfig { + fn default() -> Self { + Self { + frame_buffer: Default::default(), + log_level: Default::default(), + frame_buffer_logging: true, + serial_logging: true, + } + } +} + /// Configuration for the frame buffer used for graphical output. #[derive(Serialize, Deserialize, Debug, Default, PartialEq, Eq, Clone, Copy)] #[non_exhaustive] @@ -66,7 +74,3 @@ impl Default for LevelFilter { Self::Trace } } - -fn default_logger_status() -> bool { - true -}