In this lesson, you will learn how to bridge the gap between the CPU's power-on reset state and the first line of your Rust code.
When you power on a system, the CPU is in a primitive state, executing code from a fixed hardware address (the reset vector). To run Rust code, you must manually transform this raw environment into a space where Rust’s safety assumptions can exist.
The Entry Point
Since your Rust code runs before a standard library or even a C runtime exists, you must define your entry point using the #[no_mangle] and #[naked] attributes. We use #[naked] to prevent the compiler from adding a function prologue/epilogue, which would corrupt the stack pointer before we've even set one up.
#[no_mangle]
#[naked]
pub unsafe extern "C" fn _start() -> ! {
// 1. Set the stack pointer
core::arch::asm!(
"ldr sp, =_stack_top",
"bl rust_main",
options(noreturn)
);
}
The Transition
Writing boot code is fundamentally about "setting the stage." You cannot rely on Rust's Vec, String, or even stack-based local variables until you have performed three critical, low-level manual tasks:
- Initialize the Stack Pointer: The hardware reset vector doesn't know where memory is allocated for the stack. You must point
spto a reserved area in your memory map. - Clear the BSS Section: Rust expects global variables to be initialized to zero. Your linker script defines a range for
.bss(uninitialized memory), and you must usecore::ptr::write_volatilein a loop to zero it out. - Handle Relocation: If you are building a position-independent executable, you may need to apply offsets to global pointers before the runtime environment is valid.
Once the stack is ready and memory is zeroed, you transition into a "normal" #[no_std] Rust environment by calling a rust_main function. From that point forward, you can start using your custom panic handler and hardware abstraction layers to interact with the system. Because you are at the very bottom of the chain, every byte you write here is unchecked and relies entirely on your knowledge of the memory map.
Key Takeaway: Boot code is the manual setup of the CPU’s execution environment, primarily focused on initializing the stack pointer and zeroing memory before Rust’s safety features can be safely invoked.