20260612 rust: upskilling toward kernel rust
The Rust milestone
Of everything on my list, Rust is the one I am being most deliberate about, because it is the only genuinely new thing here. I know Go well. The plan is a post-assessment track, a marathon not a sprint, paced at about 30 to 60 minutes a day. The week numbers below are a rhythm, not a deadline. The only rule that actually matters for retention is that short regular sessions beat rare long ones.
What carries over from Go
Coming from Go this is not learning to program again. It is learning one new idea plus a set of nicer but familiar tools. The map:
| Concept | Go | Rust |
|---|---|---|
| Memory | garbage collector | ownership and the borrow checker, no GC |
| Null | nil | no null, Option<T> |
| Errors | error plus multiple return | Result<T, E> and the ? operator |
| Interfaces | interface (implicit) | trait (explicit impl) |
| Cleanup | defer | RAII, the Drop trait runs automatically |
| Collections | slice, map, append | Vec<T>, HashMap<K,V>, .push() |
| Mutability | mutable by default | immutable by default, opt in with mut |
| Build | go.mod, go build | Cargo.toml, cargo build |
Go's if err != nil is the same instinct as Rust's Result. Rust
just makes the compiler enforce that you handle it.
The one genuinely hard thing
Go's garbage collector hid memory management completely. Rust makes it explicit and checks it at compile time. That is the borrow checker, and it is the whole learning curve. Three rules in plain terms:
- Ownership. Every value has exactly one owner. When the owner goes out of scope the value is dropped automatically. No GC, no manual free.
- Move. Assigning or passing a non-
Copyvalue moves ownership. The old name can no longer use it. - Borrow. Instead of moving you can lend a reference:
&T(shared, read-only, many at once) or&mut T(exclusive, one at a time). The compiler enforces many readers or one writer, never both. That is what kills data races and use-after-free.
Lifetimes are just the compiler's bookkeeping for how long a borrow is valid. The plan is honest that you fight the borrow checker for a week or two and that this is normal. It is the model being installed, not a sign you do not get it.
The four phases
- Fundamentals. The Rust Book chapters 1 to 10 (do not skim ch.4 ownership
or ch.10 generics and traits), Rustlings up through error handling, and one small program
from scratch: read a file, count word frequency, print the top ten. That one touches
String,Vec,HashMap,Option,Resultand iteration all at once. - Idiomatic. The Book 11 to 20, the rest of Rustlings, drilling
matchand iterator chains (map,filter,collect,fold), and understanding when each ofBox,Rc,RefCellis needed. That last one is the GC-shaped hole: Rust makes you pick the strategy yourself. - Systems. The bridge to the kernel.
unsafeand raw pointers, FFI withextern "C"and#[repr(C)], andno_std: Rust without the standard library, which is the environment the kernel runs in. You losestdand keepcore. The Rustonomicon covers the unsafe and FFI parts. - Kernel Rust. Read
Documentation/rust/, build a kernel withCONFIG_RUST=yon x86_64 first then cross-compile for s390x, build and load a module fromsamples/rust/, and study thekernelcrate: a thin auditedunsafecore with a safe Rust surface on top.bindgenauto-generates the Rust bindings from the C headers.
Keep a scratch crate for trying one idea at a time, and let the compiler teach you. Its error messages are unusually good if you actually read them instead of skipping past:
rustup default stable # toolchain; add nightly later for kernel work
cargo new scratch # somewhere to try one idea at a time
Where this ties back to IBM Z
The reason Rust sits inside the s390 thread and not off on its own: IBM engineer Jan Polensky posted the first patches to bring in-kernel Rust to s390. That would make s390 the sixth architecture with Rust support, after x86_64, ARM, ARM64, LoongArch and RISC-V. Since the 2025 Maintainer Summit made kernel Rust permanent, per-architecture enablement is real engineering work now, not a science project.
What the s390 patches have to deal with is a neat tour of why this arch is awkward:
- Architecture wiring. Add s390 to the Rust-capable arch list and set the
rustc target
s390x-unknown-linux-gnu. - Assembly stubs.
WARN/BUGreporting and the static-branch patching machinery use arch-specific assembly trampolines that had to be exposed to Rust. - Bindgen adjustments. s390 hardware structs (CCW, the SIE block, ORB) use
__packedand__alignedtogether, which creates layout conflicts that bindgen cannot reconcile. The patches work around it for those types.
And the real blocker on full upstreaming: s390 needs nightly rustc today
because of -Zpacked-stack, an unstable flag for the s390 calling convention.
On s390 the ABI reserves a 160-byte register save area at the bottom of the frame, and
callees save into the caller's area rather than their own. The standard Rust and LLVM stack
layout does not produce that, and -Zpacked-stack is not stabilised yet. Until
it is, s390 Rust kernel support is nightly-only.
Milestones I am holding myself to
- M1: the borrow checker stops surprising me.
- M2: I write idiomatic Rust, not transliterated Go.
- M3: I can explain
unsafe, FFI andno_std. - M4: I built and loaded a Rust kernel module.
- M5: I can discuss the s390 Rust patch series accurately.
Reading: The Rust Book, Rustlings, Rust for Linux, and the rustc s390x platform support page.
Next week, away from the mainframe entirely and over to the other prospect: the Rockchip RK3576 and the Flipper One.
← arm64 guests on a mainframe all posts next: picking an rk3576 board →