Rust for Kernels · lab 01 of 7

01

Make the compiler prove it

[ preview ] The lesson is free to read — building it needs a free account.

You'll learn: the one idea the rest of Rust hangs off — that every value has exactly one owner, and the compiler tracks it. This is also the reason Rust can write a kernel at all.

Why a kernel writer cares

C manages memory with discipline and convention: you free what you allocate, and a comment tells you who owns the pointer. Java, Go and Python manage it with a garbage collector — a runtime that pauses your program to find unreachable objects.

A kernel can use neither. There is no runtime to pause, and no allocator at all until you write one. Meanwhile the consequences of getting it wrong are not an exception and a stack trace; they're a triple fault and a silent reboot.

Rust's answer is to move the bookkeeping to compile time. Every value has one owner. When the owner goes out of scope, the value is dropped. No GC, no runtime, and — this is the part that matters for us — no cost at runtime. The checks happen while compiling; the machine code is what C would have emitted.

Moves

Assigning a value transfers ownership:

let a = String::from("kernel");
let b = a;          // ownership MOVES to b
// println!("{a}"); // compile error: a is no longer valid

C would have copied the pointer and left you two owners, either of which might free it. Rust makes the second use a compile error instead.

Types that are cheap and safe to duplicate opt out of this by being Copy — integers, bool, char, raw pointers, and small structs that derive it. Copy types are duplicated instead of moved, which is why let x = 5; let y = x; leaves both usable. You will see #[derive(Clone, Copy)] on nearly every small struct in kernel code, for exactly this reason.

Borrows

Passing ownership every time would be miserable, so you can lend a value out:

fn total(regions: &[Region]) -> u64 { /* reads, doesn't own */ }

The rule the compiler enforces is one line long, and it is the whole borrow checker:

Either any number of shared references (&T), or exactly one mutable reference (&mut T) — never both at once.

That single rule eliminates data races and use-after-free by construction. It is also why kernel code reaches for addr_of_mut! on a static mut rather than &mut GLOBAL: taking a reference is how you accidentally end up with two live &mut to the same object, and the compiler can't save you from something it can't see.

Lifetimes, briefly

A reference must not outlive what it points to, and the compiler proves it. Usually it infers this silently. The one annotation you'll meet early is 'static — "lives for the whole program":

pub fn init(map: &'static [MemRegion]);

That signature is a claim about the machine: the memory map was written by the bootloader into memory the kernel never reclaims, so a reference to it is valid forever. 'static is how you say that to the compiler.

You can write real kernel code knowing only this much about lifetimes. The elaborate lifetime puzzles Rust is famous for come from generic library design, which is not what we're doing.

Option and Result

Rust has no null. A value that might be absent is an Option<T>Some(x) or None — and one that might fail is a Result<T, E>. Both force you to handle the missing case to get at the value:

match alloc_frame() {
    Some(frame) => /* use it */,
    None => /* out of memory — decide what that means */,
}

For now, just be able to read them. They appear the moment an allocator can run out of memory, which is exactly where the OS course introduces them.

The shape of what's ahead: ownership is the concept you'll use constantly and think about rarely. What kernel work leans on hardest is the next three stages — how a struct is laid out in memory, what unsafe buys you, and how to build without the standard library. Rust's famous learning curve is mostly generics and lifetimes in library code; a kernel touches remarkably little of it.

That's the lesson — free to read. Create a free account to build it: the brief, the grading table and the hint ladder are on the Lab tab.

Create a free account →

Free to start · no credit card · Rust for Beginners is free

The brief, the grading table and the hint ladder live here.

Signing in will not open this lab — it needs a plan. Rust for Beginners is free, every lab of it, to a free account.

See plans and what’s free →Sign in

Chat with Guru about the check that is failing you — the written hint ladder on the Lab tab is free and unlimited either way.

Signing in will not open this lab — it needs a plan. Rust for Beginners is free, every lab of it, to a free account.

See plans and what’s free →Sign in

Your submitted diff lands here with comments on the exact lines.

Signing in will not open this lab — it needs a plan. Rust for Beginners is free, every lab of it, to a free account.

See plans and what’s free →Sign in