The Eight Days Before Hello
The second article in a series on building a real-time audio operating system with an AI under my review.
At 13:22 on 11 August 2026, tan_k was twenty-seven lines of assembly.
global_asm!(
".section .text.boot",
".global _start",
"_start:",
" mrs x0, mpidr_el1",
" and x0, x0, #0xff",
" cbz x0, 2f",
"1: wfe",
" b 1b",
"2: adrp x0, __stack_top",
" add x0, x0, :lo12:__stack_top",
" mov sp, x0",
" mrs x0, cpacr_el1",
" mov x1, #0x300000",
" orr x0, x0, x1",
" msr cpacr_el1, x0",
" isb",
" adrp x0, __bss_start",
" add x0, x0, :lo12:__bss_start",
" adrp x1, __bss_end",
" add x1, x1, :lo12:__bss_end",
"3: cmp x0, x1",
" b.hs 4f",
" str xzr, [x0], #8",
" b 3b",
"4: bl kernel_main",
"5: wfe",
" b 5b",
);That is the whole boot of the first commit, 24ba709, exactly as written. Ten files, 236 lines, a kernel that, under QEMU, could say one thing. Eight days later it said hello from bare metal on a real Raspberry Pi 4, which is where the first article began. This one is about what happened in between: not features, but a ladder of failures, each rung built so that the one below could not fail in silence.
Twenty-seven lines, five jobs
QEMU loads the kernel and jumps to _start with nothing set up. Five things have to happen before a single line of Rust is valid. Park every core except the first. Point the stack at the linker’s __stack_top. Unlock floating point and SIMD. Zero .bss. Branch to Rust.
The third is the one that surprises. CPACR_EL1 resets to trapping all floating-point and SIMD access at EL1, and core::fmt uses SIMD registers to move bulk data, so without the unlock the first println! faults before printing anything. The commit message records why it is not optional.
Output goes to the PL011 UART that QEMU’s virt machine maps at 0x09000000. Implementing core::fmt::Write for it is enough to get println! with full Rust formatting. Exit is semihosting: a kernel has no operating system to call exit() on, so the emulator is the only thing that can end the run.
One detail points forward. kernel_main is declared by absence: _start ends with bl kernel_main, and whichever binary is linked supplies it. That symbol is the seam the test harness would use.
Sixteen doors
Two minutes later, dcca3ad closed the next gap. Before it, a fault jumped to VBAR_EL1, which was still zero, so the CPU landed in unmapped memory and spun. The commit calls that failure a silent hang with no output at all, the worst kind, because it tells you nothing about what went wrong or where.
The fix is a table. VBAR_EL1 points at sixteen entries, 128 bytes apart, the whole table aligned to 2048 bytes: four kinds of exception from four sources. The commit is blunt that the spacing and the alignment are architectural requirements, not choices. Each entry does one thing.
".align 7",
"mov x0, #0",
"b exception_trampoline",
".align 7",
"mov x0, #1",
"b exception_trampoline",Fourteen more follow, the same two lines with a different number. All sixteen land in one trampoline.
"exception_trampoline:",
" mrs x4, cpacr_el1",
" mov x5, #0x300000",
" orr x4, x4, x5",
" msr cpacr_el1, x4",
" isb",
" mrs x1, esr_el1",
" mrs x2, elr_el1",
" mrs x3, far_el1",
" b handle_exception",The trampoline unlocks SIMD again before anything else. The code that reports a fault formats text, and formatting uses SIMD, so reporting a trapped floating-point access would otherwise trap inside the reporter, in the one place that exists to prevent hangs. Then it reads the syndrome, the return address and the faulting address, and calls into Rust to decode and print them.
The first test of it was a fault on purpose. tests/exception.rs executes brk #0 and passes only if the handler catches a breakpoint fault.
A name, twelve minutes in
Twelve minutes after the first commit the project changed its name: eca7136 renamed tattva to tan_k. I love Sanskrit, and the name comes from it: tan is a verbal root, and the k stands for kernel. tānaOS is a product of Tattva, my first project, which slept and now wakes.
A green suite that printed nothing
Nine hours after the first commit, 027d2c8 found a problem in the instrument itself. A kernel whose serial port is broken still exits with code 0 through the emulator’s semihosting call. Stubbing out Uart::write_byte, or swapping -nographic for -serial null, produced a clean exit and no output at all. Nobody reads the empty log of a passing job.
Get Octavio Rojas’s stories in your inbox
Join Medium for free to get updates from this writer.
The fix is small. The kernel now prints [exit N] before it halts, and the runner requires that marker and cross-checks it against the process exit code. A run that says nothing is a failed run. Each new failure path was proven to fire: a bad timeout returns 2, a missing marker returns 3 even when QEMU exits 0, a disagreement between the two codes returns 4, a hang returns 124.
A test that passed for the wrong crash
On 12 August, a review found something worse in the fault test itself. expect() compared only the exception class, and the exception test binary contained three brk instructions: the intentional brk #0 and two brk #0x1 that LLVM emits to lower unreachable and abort paths. Class 0x3c matched all three.
So if a real bug drove execution into one of LLVM’s traps, which is exactly the signal that you reached unreachable code, any test armed with that class would print ok and exit success. The commit’s phrase for it is a real undefined-behaviour trap laundered into a green test. The armed fingerprint now carries the class and the low sixteen bits of the syndrome, which for a breakpoint is the brk comment. Arming for brk #0 and firing brk #1 used to print caught expected and exit 0. Now it prints an unhandled-exception report and exits 1.
Order is a fact
On 14 August, b26254d moved one line. .bss was sixteen bytes and held nothing but the exception handler’s own state, so arming VBAR_EL1 before zeroing it opened a window in which a fault would be dispatched to a handler whose state was whatever the RAM contained.
A probe made it measurable: poison .bss, then execute brk #0 immediately after the VBAR write.
- Vector table first, zero second: no output at all, killed by the watchdog, exit code 124.
- Zero first, vector table second: a full decoded fault report, exit code 1.
Same poison, same fault, same instruction address. The only variable was where one line sat. The reorder costs nothing.
An auditor that had not written it
Later that day, df192d9 landed the findings of an independent audit. An agent with no conversation context audited the same boot block, confirmed five of six recorded findings, beat every one by measuring instead of reasoning, corrected one proposed fix, and produced eight more.
Two of them show the kind of thing it found. The first instruction of _start destroyed the device tree pointer that the ARM64 boot protocol passes in x0. And the core mask 0xff kept only the lowest affinity field, so on a machine with clusters of sixteen cores, CPU 16 would pass the park check and run the primary boot path on core 0’s stack. The audit even corrected the fix: the general Linux mask 0xff00ffffff cannot be encoded as an AArch64 logical immediate and would not have assembled.
An agent that did not write the code, asked to attack it, is the practice this series keeps coming back to.
Two doors, and only one ever opened
That night, a6dedab taught _start to detect EL2 and drop to EL1, because the Pi enters at EL2. Its message ends with an honest line: nothing there had run on a board. Then, on 17 August, four commits in just over two hours each closed a gap of the same shape, a path that only silicon would take.
e316faa: a diagnostic that cannot fail the same way. The usual instrument,println!, may be the thing the firmware broke. So the first report is written in assembly, reads the machine before the kernel changes anything, and uses no stack, no Rust and no SIMD. Each line is one tag byte and sixteen hex digits. Those are the lines at the top of the console in the first article.2e7954d: both entry levels. The runner passed-machine virt, which gives QEMU no EL2, so entry was always at EL1 and the whole EL2 drop was skipped. Tracing the instructions confirmed that block was never translated. Every green run in the history had exercised one of the two entry paths, and the Pi boots at the other. The runner now boots both.01f4ecd: a build that had not compiled. The Pi’s UART address,0xfe201000, cannot be encoded as a singleMOVimmediate, so the hardware build had been broken since an earlier commit. It stayed invisible because the check ran behind&& echowith the errors discarded, and a missing success line was read as success. The address is now built from two 16-bit halves.031ef46: registers nobody set. The drop leftCPTR_EL2as the firmware had it, and its reset value is architecturally unknown. If the bit that traps floating point is set, the firstprintln!of an integer stops the output: the release image contains 59 FP and SIMD instructions, including insidecore::fmt. The traps-off value is0x33ff, not zero, because some bits are reserved as ones.
Then the board
On 19 August, between 05:28 and 08:55, twelve commits chased one symptom, a console nobody could read. Two of them were reverts. The first article told how that morning ended, with a wire. What matters here is what the ladder had already built by then: a kernel that reported its state before touching it, decoded its own faults, and could tell silence from success. The day was lost to a jumper on the wrong pin, not to a kernel that could not speak.
A kernel is built failure by failure. Each rung exists because the one below it could fail in silence.
What this article did to itself
We took every date, hash and figure from git log and the commit messages, and quoted the first commits themselves rather than today’s source, which has grown past them: the vector table that was sixteen uniform entries on the first day now fills more than a hundred lines. The first outline said the opening was twenty-nine lines. Counting the block gave twenty-seven.
Next
Two days after the console, on 21 August, the board answered a question about memory with a number the emulator had never printed. That is the next article.









