ISA Extensions and Custom Instructions for Embedded IoT Edge Devices: How Linux Discovers and Context-Switches Hardware It Wasn’t Born With
1. Introduction
Every general-purpose kernel is designed around an assumption: the instruction set is a fixed, known quantity. x86-64 has AVX. ARM64 has NEON. The kernel knows what registers exist, how big they are, and how to save them across a context switch, because the vendor manual said so years before the kernel shipped.
Embedded IoT edge silicon breaks that assumption on purpose. A RISC-V SoC vendor building a sensor-fusion chip, a crypto accelerator, or an always-on DSP core will frequently bolt a custom instruction extension onto the base ISA — new opcodes, new architectural registers, sometimes an entirely new register file — because the base ISA doesn’t have a MAC unit that fits a keyword-spotting model in 200 microwatts. RISC-V was designed for exactly this: the base ISA is small, ratified, and stable, and everything else is additive, encoded in reserved opcode space, and optional per-implementation.
This creates a real kernel engineering problem with two distinct halves. First, software has to find out at runtime whether a given extension is present at all — a problem the RISC-V ecosystem solved formally only in 2023, three decades into Linux’s life, with a dedicated syscall. Second, if that extension adds architectural state — new registers that live in silicon, not memory — the kernel has to know about that state well enough to save and restore it correctly every time it switches which task is running, or one task’s secrets leak into the next task’s register file.
This article works through both halves using real kernel mechanisms — riscv_hwprobe(2) for discovery, and the RISC-V vector extension’s context-switch machinery as the reference design for extended-state save/restore — and builds a validated userspace simulation of both, including two real bugs caught while writing the demo: a data race in a naive discovery cache, and a genuine cross-task register-state leak from a naive lazy-restore policy. That second bug, it turns out, is not hypothetical — it mirrors a class of bug the actual RISC-V vector subsystem has had to explicitly guard against in-tree.


