From 8fa77f31a462b78921dfb46d22291b8fd7e519d0 Mon Sep 17 00:00:00 2001 From: Tom Dohrmann Date: Thu, 5 Mar 2026 08:36:17 +0100 Subject: [PATCH 1/2] don't use BPB_TotSec16 to determine FAT type MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Description for BPB_TotSec16: > This field is the old 16-bit total count of sectors on the volume. > This count includes the count of all sectors in all four regions of > the volume. This field can be 0; if it is 0, then BPB_TotSec32 must > be non-zero. For FAT32 volumes, this field must be 0. For FAT12 and > FAT16 volumes, this field contains the sector count, and BPB_TotSec32 > is 0 if the total sector count “fits” (is less than 0x10000). Source: https://download.microsoft.com/download/1/6/1/161ba512-40e2-4cc9-843a-923143f3456c/fatgen103.doc TL;DR: BPB_TotSec16 can be zero even for FAT12/FAT16 volumes if the sector count exceeds 0x10000. Instead, let's use BPB_FATSz16. Unlike BPB_TotSec16, BPB_FATSz16 must be non-zero for FAT12/FAT16 volumes because BPB_FATSz32 only exists in the FAT32 BPB. According to the document mentioned above, BPB_FATSz16 must be zero for FAT32 volumes. --- bios/stage-2/src/fat.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/bios/stage-2/src/fat.rs b/bios/stage-2/src/fat.rs index 9ce41d6f..0f24e0b4 100644 --- a/bios/stage-2/src/fat.rs +++ b/bios/stage-2/src/fat.rs @@ -48,16 +48,14 @@ impl Bpb { let root_cluster; let fat_size_32; - if (total_sectors_16 == 0) && (total_sectors_32 != 0) { + if fat_size_16 == 0 { // FAT32 fat_size_32 = u32::from_le_bytes(raw[36..40].try_into().unwrap()); root_cluster = u32::from_le_bytes(raw[44..48].try_into().unwrap()); - } else if (total_sectors_16 != 0) && (total_sectors_32 == 0) { + } else { // FAT12 or FAT16 fat_size_32 = 0; root_cluster = 0; - } else { - panic!("ExactlyOneTotalSectorsFieldMustBeZero"); } Self { From afdebf5fca74bc17dddadec1393fa09c9eef1eb2 Mon Sep 17 00:00:00 2001 From: Tom Dohrmann Date: Thu, 5 Mar 2026 08:47:03 +0100 Subject: [PATCH 2/2] add test with large RAM disk --- tests/ramdisk.rs | 14 +++++++++++ .../ramdisk/src/bin/large_ramdisk.rs | 24 +++++++++++++++++++ 2 files changed, 38 insertions(+) create mode 100644 tests/test_kernels/ramdisk/src/bin/large_ramdisk.rs diff --git a/tests/ramdisk.rs b/tests/ramdisk.rs index 08c86f9b..668a10c3 100644 --- a/tests/ramdisk.rs +++ b/tests/ramdisk.rs @@ -1,6 +1,8 @@ use std::path::Path; use bootloader_test_runner::run_test_kernel_with_ramdisk; +use tempfile::NamedTempFile; + static RAMDISK_PATH: &str = "tests/ramdisk.txt"; #[test] @@ -26,3 +28,15 @@ fn memory_map() { Some(Path::new(RAMDISK_PATH)), ); } + +#[test] +fn large_ramdisk() { + // Create a large file to act as the RAM disk. + let ramdisk = NamedTempFile::new().unwrap(); + ramdisk.as_file().set_len(1024 * 1024 * 16).unwrap(); + + run_test_kernel_with_ramdisk( + env!("CARGO_BIN_FILE_TEST_KERNEL_RAMDISK_large_ramdisk"), + Some(ramdisk.as_ref()), + ); +} diff --git a/tests/test_kernels/ramdisk/src/bin/large_ramdisk.rs b/tests/test_kernels/ramdisk/src/bin/large_ramdisk.rs new file mode 100644 index 00000000..2962e147 --- /dev/null +++ b/tests/test_kernels/ramdisk/src/bin/large_ramdisk.rs @@ -0,0 +1,24 @@ +#![no_std] // don't link the Rust standard library +#![no_main] // disable all Rust-level entry points + +use bootloader_api::{BootInfo, entry_point}; +use core::fmt::Write; +use test_kernel_ramdisk::{QemuExitCode, exit_qemu, serial}; + +entry_point!(kernel_main); + +fn kernel_main(boot_info: &'static mut BootInfo) -> ! { + writeln!(serial(), "Boot info: {boot_info:?}").unwrap(); + assert!(boot_info.ramdisk_addr.into_option().is_some()); + writeln!(serial(), "RAM disk size: {}", boot_info.ramdisk_len).unwrap(); + + exit_qemu(QemuExitCode::Success); +} + +/// This function is called on panic. +#[cfg(not(test))] +#[panic_handler] +fn panic(info: &core::panic::PanicInfo) -> ! { + let _ = writeln!(test_kernel_ramdisk::serial(), "PANIC: {info}"); + exit_qemu(QemuExitCode::Failed); +}