From 52832335f5a9a02747eaf69a09d8f67e3e0e7047 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Juanjo=20Asensio=20Garc=C3=ADa?= <asengar2009@gmail.com>
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<PathBuf>,
+    config_file: Option<PathBuf>,
 }
 
 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<PathBuf>,
+    config_file: Option<PathBuf>,
 }
 
 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<Boot>) -> 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<Boot>) -> 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>,
+    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<Boot>,
@@ -446,7 +458,7 @@ fn create_page_tables(
 fn init_logger(
     image_handle: Handle,
     st: &SystemTable<Boot>,
-    config: BootloaderConfig,
+    config: BootloaderConfigFile,
 ) -> Option<RawFrameBufferInfo> {
     let gop_handle = st
         .boot_services()

From 3ab261bd79eb9c3f4243c688957e73fa42b00501 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Juanjo=20Asensio=20Garc=C3=ADa?= <asengar2009@gmail.com>
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<u64>,
+    /// 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<u64>,
+}
+
+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?= <asengar2009@gmail.com>
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<u64>,
-    /// 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<u64>,
-}
-
-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<LevelFilter>
-    pub fn from_u8(value: u8) -> Option<LevelFilter> {
-        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<LoggerStatus>
-    pub fn from_u8(value: u8) -> Option<LoggerStatus> {
-        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?= <asengar2009@gmail.com>
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<Self, (Self, de::Error)> {
         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::<Self>(&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<Boot>) -> 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?= <asengar2009@gmail.com>
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 <dev@phil-opp.com>"]
+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?= <asengar2009@gmail.com>
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<u64>,
+    /// 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<u64>,
+}
+
+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<serde_json_core::de::Error> = 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<Self, (Self, de::Error)> {
-        match serialized {
-            Some(json) => {
-                match serde_json_core::from_slice::<Self>(&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<u64>,
 }
 
-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()
+        <u32 as Into<u64>>::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<PathBuf>,
-    config_file: Option<PathBuf>,
+    config: Option<String>,
 }
 
 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<PathBuf>,
-    config_file: Option<PathBuf>,
+    config: Option<String>,
 }
 
 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<Boot>) -> 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<serde_json_core::de::Error> = 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<Boot>,
-    config: BootloaderConfigFile,
+    config: BootConfig,
 ) -> Option<RawFrameBufferInfo> {
     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?= <asengar2009@gmail.com>
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")?,
-        <u32 as Into<u64>>::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<Boot>) -> 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<serde_json_core::de::Error> = 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<Boot>) -> 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?= <asengar2009@gmail.com>
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?= <asengar2009@gmail.com>
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
-}