← black metal kernel — series index
// black metal kernel — episode 08 of 08
closing transmission:
what rust proves and what remains yours
// kernel programming in rust — zero-cost abstractions — no gc — no mercy
ownership
unsafe
Send/Sync
initialization
// 08 — closing transmission
memory safety without a garbage collector is not magic — it is the acknowledgment that ownership is a real property of running systems and that expressing it explicitly in the type system costs nothing at runtime because the runtime never sees it. the borrow checker is not a limitation it is a proof engine that runs at compile time and emits machine code that is as tight as anything you would write in C. it guarantees that two cores cannot corrupt each other's allocations, that a freed pointer cannot be dereferenced, and that an interrupt handler cannot silently alias your kernel's critical data structures. rust in the kernel is not a comfort — it is accountability at machine speed.
this philosophy manifests most purely during system initialization. before you can use the luxurious traits and threading models of safe rust, you must manually align the chaotic assembly state into rigid structure. all systems initialization relies heavily on explicit `unsafe` blocks setting memory invariants and binding raw addresses.
pub unsafe fn black_kernel_init() -> ! {
crate::black_allocator::black_heap_init();
let mut black_pml4 = crate::black_paging::BlackPageTable::black_zeroed();
black_pml4.black_map_huge(0, 0, crate::black_paging::BLACK_PAGE_WRITABLE);
black_pml4.black_load();
crate::black_interrupts::black_idt_init();
core::arch::asm!("sti", options(nomem, nostack));
loop {
core::arch::asm!("hlt", options(nomem, nostack));
}
}
// expanded — what rust proves, what unsafe admits, and what remains your problem
the borrow checker enforces one invariant: at any point in time, a piece of memory is accessible through either one exclusive mutable reference or any number of shared immutable references — never both. this single rule, enforced entirely at compile time with zero runtime representation, eliminates use-after-free (the owner dropped the value; no reference can outlive the owner), iterator invalidation (you cannot hold a reference into a collection while mutating it), and data races (two threads cannot simultaneously hold mutable access to the same value — the Send and Sync marker traits encode thread-safety at the type level and are checked at compile time).
unsafe is Rust's explicit escape hatch. every unsafe block in this series is a signed contract between the developer and the compiler: "I am asserting that the invariants you cannot verify are upheld by this code." UnsafeCell in the mutex, raw pointer arithmetic in the bump allocator, inline assembly writing to hardware registers, the naked interrupt entry point — all of these require unsafe. the power of Rust's model is that unsafe is contained, explicit, and auditable. a security review can enumerate every unsafe block in the kernel and focus attention there. in C, every pointer dereference, every struct cast, every arithmetic operation is potentially unsafe and there is no structural way to find the dangerous ones.
what Rust does not prove: it cannot verify that your interrupt handler completes before the hardware timeout. it cannot verify that your page table does not accidentally mark kernel memory as user-accessible. it cannot verify that your spinlock is not held across an interrupt that tries to acquire the same lock — a deadlock. it cannot verify that your memory ordering choices correctly synchronize with the DMA controller. these are semantic correctness properties — relationships between your code and the hardware specification — that exist outside any type system. they require hardware documentation, architectural knowledge, and adversarial thinking.
Rust pushes the safety boundary as far forward as any systems language has ever pushed it. the category of bugs that caused the majority of critical kernel vulnerabilities over the past thirty years — memory corruption, use-after-free, data races — become structurally impossible to express in safe Rust and explicitly acknowledged in unsafe Rust. the rest is engineering. the kernel written in this style is harder to write than C. it is also the only kind of kernel that cannot corrupt itself silently. that difference is the entire argument.
// EOF — no comments — no apologies — no garbage collection — black_ptr owns its truth — BLACK0X80