Part 1 - Humble Beginnings

To write an operating system kernel in Rust, we need to run Rust code without any OS or standard library. This means no threads, files, or memory allocation just pure code and zero abstractions running on bare metal.

Rust’s #![no_std] attribute excludes the standard library, but removes familiar tools like println!. We also need a custom panic handler using #[panic_handler](since ours is gone now), and must disable stack unwinding in Cargo.toml:

[profile.dev]
panic = "abort"

[profile.release]
panic = "abort"
Stack Unwinding in Rust

Stack unwinding is the process of reversing function calls on the call stack when a program encounters a panic (in Rust) or an exception (in C++).
During unwinding, each stack frame is popped, and destructors are run to clean up resources like memory or file handles.
This ensures proper cleanup and avoids leaks.
In Rust, unwinding enables error recovery, but can be disabled (panic = "abort" in Cargo.toml) to reduce binary size and improve performance when recovery isn’t needed.

Since standard Rust programs use a runtime with an entry point via the C library, we disable this using #![no_main], and define our own _start function:

#![no_std]
#![no_main]

use core::panic::PanicInfo;

#[no_mangle]
pub extern "C" fn _start() -> ! {
    loop {}
}

#[panic_handler]
fn panic(_info: &PanicInfo) -> ! {
    loop {}
}

This minimal setup compiles into a bare-metal binary. To avoid linker errors, compile for a bare-metal target like thumbv7em-none-eabihf with:

rustup target add thumbv7em-none-eabihf
cargo build --target thumbv7em-none-eabihf

This is the foundation of a Rust OS kernel: no OS, no runtime dependencies, just pure control.