From ede9a47f9c2504edf9ab0e9e6ef8e70ebf358877 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 14 Sep 2025 16:39:33 +0200 Subject: [PATCH] Move .bss and .data tests to inline asm If .bss is not properly cleared or .data is incorrectly cleared, there is no way to tell what will happen if we try to run Rust code. --- src/arch/aarch64/start.rs | 33 ++++++++++++++++------ src/arch/riscv64/start.rs | 39 +++++++++++++++++--------- src/arch/x86_shared/start.rs | 54 +++++++++++++++++++++++++++++------- 3 files changed, 95 insertions(+), 31 deletions(-) diff --git a/src/arch/aarch64/start.rs b/src/arch/aarch64/start.rs index eec13f801a..cd0b6828b6 100644 --- a/src/arch/aarch64/start.rs +++ b/src/arch/aarch64/start.rs @@ -3,6 +3,7 @@ //! It must create the IDT with the correct entries, those entries are //! defined in other files inside of the `arch` module use core::{ + arch::global_asm, slice, sync::atomic::{AtomicBool, Ordering}, }; @@ -21,19 +22,35 @@ static mut DATA_TEST_NONZERO: usize = 0xFFFF_FFFF_FFFF_FFFF; pub static AP_READY: AtomicBool = AtomicBool::new(false); static BSP_READY: AtomicBool = AtomicBool::new(false); +global_asm!(" + .globl kstart + kstart: + // BSS should already be zero + adrp x9, {bss_test_zero} + ldr x9, [x9, :lo12:{bss_test_zero}] + cbnz x9, .Lkstart_crash + adrp x9, {data_test_nonzero} + ldr x9, [x9, :lo12:{data_test_nonzero}] + cbz x9, .Lkstart_crash + + mov lr, 0 + b {start} + + .Lkstart_crash: + mov x9, 0 + br x9 + ", + bss_test_zero = sym BSS_TEST_ZERO, + data_test_nonzero = sym DATA_TEST_NONZERO, + start = sym start, +); + /// The entry to Rust, all things must be initialized -#[unsafe(no_mangle)] -pub unsafe extern "C" fn kstart(args_ptr: *const KernelArgs) -> ! { +unsafe extern "C" fn start(args_ptr: *const KernelArgs) -> ! { unsafe { let bootstrap = { let args = args_ptr.read(); - // BSS should already be zero - { - assert_eq!(BSS_TEST_ZERO, 0); - assert_eq!(DATA_TEST_NONZERO, 0xFFFF_FFFF_FFFF_FFFF); - } - // Set up graphical debug graphical_debug::init(args.env()); diff --git a/src/arch/riscv64/start.rs b/src/arch/riscv64/start.rs index 2ef6e2b035..3af8e917cc 100644 --- a/src/arch/riscv64/start.rs +++ b/src/arch/riscv64/start.rs @@ -1,9 +1,7 @@ use core::{ - arch::asm, - slice, + arch::{asm, global_asm}, sync::atomic::{AtomicUsize, Ordering}, }; -use fdt::Fdt; use crate::{ allocator, @@ -38,13 +36,34 @@ fn get_boot_hart_id(env: &[u8]) -> Option { None } +global_asm!(" + .globl kstart + kstart: + mv gp, x0 // ensure gp relative accesses crash + mv tp, x0 // reset percpu until it is initialized + csrw sscratch, tp + + // BSS should already be zero + ld t0, {bss_test_zero} + bnez t0, .Lkstart_crash + ld t0, {data_test_nonzero} + beqz t0, .Lkstart_crash + + li ra, 0 + j {start} + + .Lkstart_crash: + jr x0 + ", + bss_test_zero = sym BSS_TEST_ZERO, + data_test_nonzero = sym DATA_TEST_NONZERO, + start = sym start, +); + /// The entry to Rust, all things must be initialized -#[unsafe(no_mangle)] -pub unsafe extern "C" fn kstart(args_ptr: *const KernelArgs) -> ! { +unsafe extern "C" fn start(args_ptr: *const KernelArgs) -> ! { unsafe { asm!( - "mv tp, x0", // reset percpu until it is initialized - "csrw sscratch, tp", "sd x0, -16(fp)", // and stop frame walker here "sd x0, -8(fp)", ); @@ -52,12 +71,6 @@ pub unsafe extern "C" fn kstart(args_ptr: *const KernelArgs) -> ! { let bootstrap = { let args = args_ptr.read(); - // BSS should already be zero - { - assert_eq!(BSS_TEST_ZERO, 0); - assert_eq!(DATA_TEST_NONZERO, 0xFFFF_FFFF_FFFF_FFFF); - } - let dtb_data = if args.hwdesc_base != 0 { Some(( crate::PHYS_OFFSET + args.hwdesc_base as usize, diff --git a/src/arch/x86_shared/start.rs b/src/arch/x86_shared/start.rs index 8317c7361b..3c858b043e 100644 --- a/src/arch/x86_shared/start.rs +++ b/src/arch/x86_shared/start.rs @@ -3,6 +3,7 @@ //! It must create the IDT with the correct entries, those entries are //! defined in other files inside of the `arch` module use core::{ + arch::global_asm, cell::SyncUnsafeCell, hint, sync::atomic::{AtomicBool, Ordering}, @@ -29,19 +30,54 @@ static DATA_TEST_NONZERO: SyncUnsafeCell = SyncUnsafeCell::new(usize::max pub static AP_READY: AtomicBool = AtomicBool::new(false); static BSP_READY: AtomicBool = AtomicBool::new(false); +#[cfg(target_arch = "x86")] +global_asm!(" + .globl kstart + kstart: + // BSS should already be zero + cmp dword ptr [{bss_test_zero}], 0 + jne .Lkstart_crash + cmp dword ptr [{data_test_nonzero}], 0 + je .Lkstart_crash + + jmp {start} + + .Lkstart_crash: + mov eax, 0 + jmp eax + ", + bss_test_zero = sym BSS_TEST_ZERO, + data_test_nonzero = sym DATA_TEST_NONZERO, + start = sym start, +); + +#[cfg(target_arch = "x86_64")] +global_asm!(" + .globl kstart + kstart: + // BSS should already be zero + cmp qword ptr [rip + {bss_test_zero}], 0 + jne .Lkstart_crash + cmp qword ptr [rip + {data_test_nonzero}], 0 + je .Lkstart_crash + + jmp {start} + + .Lkstart_crash: + mov rax, 0 + jmp rax + ", + bss_test_zero = sym BSS_TEST_ZERO, + data_test_nonzero = sym DATA_TEST_NONZERO, + start = sym start, +); + /// The entry to Rust, all things must be initialized -#[unsafe(no_mangle)] -pub unsafe extern "C" fn kstart(args_ptr: *const KernelArgs) -> ! { +unsafe extern "C" fn start(args_ptr: *const KernelArgs) -> ! { unsafe { let bootstrap = { let args = args_ptr.read(); - // BSS should already be zero - { - assert_eq!(BSS_TEST_ZERO.get().read(), 0); - assert_eq!(DATA_TEST_NONZERO.get().read(), usize::max_value()); - } - // Set up serial debug device::serial::init(); @@ -123,8 +159,6 @@ pub unsafe extern "C" fn kstart_ap(args_ptr: *const KernelArgsAp) -> ! { unsafe { let cpu_id = { let args = &*args_ptr; - assert_eq!(BSS_TEST_ZERO.get().read(), 0); - assert_eq!(DATA_TEST_NONZERO.get().read(), usize::max_value()); // Set up GDT gdt::install_pcr(args.pcr_ptr);