Posts

Showing posts from June, 2026

QSOE/L: the same userspace, on seL4

The three QSOE/N posts ended with a promise — the other half of the umbrella, QSOE/L, the same userspace running on seL4. This is that post. It is also, in a sense, the first post, because QSOE/L is where the whole thing began. Tomorrow is one month to the day since I started the real QSOE, and the first thing that booted was an seL4 image. QSOE/N, the from-scratch-kernel variant I wrote about first, is the younger sibling. I led with it because the milestone there was loud: a microkernel I wrote myself taking its first breath on real silicon. QSOE/L's story is quieter and, for the shared userspace, more foundational. Everything that runs on Skimmer today was made to run on seL4 first. No kernel to write On seL4 there is no kernel to write, and that is the entire point. seL4 is a verified, capability-based microkernel; the job was never to build a kernel but to build a QNX-Neutrino-shape operating system on top of one. seL4 has opinions, and the strongest of them is about IPC. It...

QSOE/N, part 3: first boot on the HiFive Unmatched

Part 2 left QSOE/N as a working operating system that had only ever run in QEMU. This post is the jump to real silicon — a SiFive HiFive Unmatched (FU740) on my desk — and the five obstacles between "boots fine in the emulator" and an interactive shell on real hardware. The recurring theme is that QEMU is generous in ways the FU740 is not. Every fix below is a thing the emulator either did for me silently or didn't model at all. Two of them I had already paid for once, on the same board, during the QRV port; the commits cite the QRV fixes by hash. That's the value of having ported QNX to RISC-V first: the bring-up obstacles on this board are not a surprise, they're a checklist. 1. The image won't load: boot-image header U-Boot's booti refused the flat binary outright — Bad Linux RISCV Image magic! . The same first obstacle QRV hit on the same board. RISC-V's Image protocol wants a specific header at the front of the kernel: a code0 that jumps over...

QSOE/N, part 2: from a kernel to an operating system

Part 1 ended with Skimmer at v0.5 — a sound microkernel with QNX-shape synchronous IPC, and nothing running on top of it. This post is the rest: how Skimmer became QSOE/N, an actual operating system with processes, a C library, drivers, and a conformance suite that passes a full lap. All of it still in QEMU; real hardware is part 3. The umbrella QSOE — "Quick and Secure Operating Environment" — is a QNX-Neutrino-style operating environment for 64-bit RISC-V, built entirely under Apache-2.0. It comes in two variants that share almost everything: QSOE/N (project NQ), the native-kernel variant, running on Skimmer. QSOE/L (project LQ), running the same userspace on the seL4 microkernel. The split is deliberately thin. The kernel differs, the system process (taskman) differs, and a small OS-dependent slice of libc differs. Everything else — the C library body, the drivers, the utilities — is shared between the two systems. That constraint shaped a lot of the decisions below,...

QSOE/N, part 1: proving the core (Skimmer v0.1–v0.5)

This is the first of three posts tracing QSOE/N from its first commit to its first boot on real hardware. This one is about the kernel alone — Skimmer — before there was any userspace to speak of. The whole point of v0.1 through v0.5 was to answer one question: is the core sound? Everything after it assumes the answer is yes. I built all of it alongside Claude Code (Opus 4.7 for this stretch, 4.8 later). The commits carry the co-author line; I'm not going to repeat it every paragraph, but the race hunts below were genuinely a two-party effort. Where the design comes from Skimmer is a from-scratch microkernel for 64-bit RISC-V, Apache-2.0, written to a QNX shape. The concurrency model is not QNX's, though — it's DragonFly BSD's. The two ideas I took are Light Weight Kernel Threads (LWKT) and message ports: per-CPU run queues with no cross-CPU locks on the hot path, and cross-CPU work expressed as messages routed through per-CPU rings rather than as foreign writes into...