# Return-to-root roadmap — landing the reshaped kernel as THE kernel **Status:** LIVING migration state (reconciled 2026-08-19). Return-to-root has **landed**: the reshaped core is the repository root, and the pre-reshape tree is archived read-only under `_legacy/`. This document tracks *what has re-attached* and *what has not yet been ported forward* — it is the companion to `docs/requirements.md` (the north star) and the two accepted decisions `docs/decisions/0001` / `0002`. ## 1. Why this document The reshape was built in isolation in `sketches/kernel-reshape/` deliberately — a clean rebuild of the kernel core (`arch` / `boards` / `kernel` / `make` / `profiles` / `examples`) whose thesis is discharged: portable across two switch models (deferred-PendSV + trap-frame), privilege-parametric (M/S mode), SMP on two arches, and freedom-from-interference proven on **three** mechanisms (ARM MPU, RISC-V PMP, RISC-V Sv32 paging). That sketch has now **become the root**. The migration is not more kernel design — it is a *re-attachment* effort: the reshaped core is promoted to `/kernel` + `/arch`, and the reuse layers (HAL, devices, drivers, tools, tests) are being reconnected on top, forward- ported against the reshaped API rather than moved as-is. This is integration work, and the real finish line. The reuse layers listed below carry **file/LOC counts from the `_legacy/` tree** — they measure the size of the port-forward job, not what is at root today (most of these are **not yet at root**; see §5): | `_legacy` layer | Files / LOC | Nature | Verdict | At root? | |---|---|---|---|---| | `hal/` | 40 / 2701 | MCAL + HAL (Option-C resolver, instance model) | **Reuse** (composability I1) | **Partial** — a slim `hal/` (9 files: board/console/dio/mcu/port/uart) landed; crypto/wdg/error/compiler headers not ported | | `tools/` | 13 / 9174 | `tkgen` pinmux, composability matrix, loaders | **Reuse** — kernel-agnostic | **No** — root `tools/` has only `SEGGER/` + `bin2uf2.py` | | `tests/` | 19 / 1670 | host unit tests | **Reuse + extend** | **No** — no `tests/` dir at root | | `devices/` | 12 / 1122 | PN532, sensors, device drivers | **Reuse** — sit on HAL | **No** — no `devices/` dir at root | | `drivers/` | 6 / 391 | board-agnostic `tk_button`/`tk_led`/`gpiote` | **Reuse** — one kernel touchpoint | **No** — no `drivers/` dir at root (ISR→wake shown via `examples/button_irq`) | | `system/` | 5 / 370 | trust-chain / heartbeat / secure-boot glue | **Reuse** | **Partial** — only `system/tk_sysview.c` landed | | `boards/` | 203 / 13613 | every board port | **Selective** | **Partial** — 4 reshaped boards landed | | `kernel/` | 18 / 4349 | the pre-reshape kernel | **Superseded** by the reshaped core | **Superseded** — reshaped `kernel/` is at root | | `arch/` | 19 / 4298 | pre-reshape arch ports | **Superseded** where a reshaped port exists | **Superseded** — reshaped `arch/` is at root | ## 2. The load-bearing risk: API drift The reuse layers were written against the **pre-reshape** kernel API. The reshaped kernel deliberately has a different, tighter surface (the `[rt]`/`[setup]` boundary settled in ADR 0002) and is missing some features the pre-reshape kernel exposed. Every reuse layer crosses one of these seams: - **Sync/thread API shape** — drivers/devices that block, wake from ISR, or use sems/mutexes call kernel runtime APIs. Names/semantics mostly align (both `tk_`-prefixed, pthread-shaped), but each call site must be **audited, not assumed**. - **Features present in `_legacy/` but NOT yet in the reshaped core** — must be ported *forward* before the layers that need them can re-attach. Landing state as of this reconciliation: - `tk_introspect.{c,h}` — remote-monitor / RO introspection region — **NOT ported** (a lighter `tk_kernel_thread_snapshot` + `struct tk_thread_info` exist under `TK_CONFIG_ENABLE_INTROSPECT`, but not the seqlock region). - `tk_trace.h` + `tk_trace_ring.c` + `tk_sysview.h` + `system/tk_sysview.c` — flight-recorder + SEGGER SystemView — **✅ ported** (R2 half done). - `tk_time.c` — the reshape folds the kernel-owned tick inline; root has only `kernel/tk_time.h` (no `.c`). Parity **confirmed** (inlined), not a gap. - `tk_stack.c` — root has `kernel/tk_stack.h` as a **placeholder no-op** (`tk_stack_prepare`/ `tk_stack_check` are stubs; fill + canary + high-water "land here when enabled"). The L1 software-canary *implementation* + the `tk_thread_stack_peak/free` + overflow-hook API are **not yet re-hosted** — reconcile against the arch canary. - **HAL↔kernel independence must stay intact** — composability invariants I1/I2/I3 (HAL never depends on kernel). The enforcing tool `_legacy/tools/composability_matrix.sh` is **not yet at root**; re-porting it (R4) is what restores the CI gate — until then the invariant is honored by convention, not enforced automatically. ## 3. Phased sequence & status Each phase is independently landable and leaves the tree building + tests green. - **R0 — Freeze & diff.** ✅ **Done** (implicit in the promotion). The reshaped core was snapshotted and promoted; the pre-reshape tree is frozen under `_legacy/`. - **R1 — Promote the core.** ✅ **Done.** Reshaped `kernel/` + `arch/` + `make/` are the root build. Host, nRF52 (`arm_v7m`), and RV32-QEMU (`risc_v`) build; the reshaped examples build from their root home. The make system wires `arm_v6m/arm_v7m/arm_v8m/pthread/risc_v` and boards `host/nrf52832_pca10040/qemu_riscv32_virt(+_sbi)/rp2040_pico(+_flash)/mps2_an505`. - **R2 — Port forward the missing kernel features.** 🟡 **Half done.** Trace / trace-ring / SystemView are **landed** (`kernel/tk_trace.h`, `kernel/tk_trace_ring.c`, `kernel/tk_sysview.h`, `system/tk_sysview.c`; demos `examples/{trace,sysview}`). **Not done:** `tk_introspect` + `examples/monitor`; the L1-canary implementation behind `tk_stack.h`. `tk_time.c` reconciled (inlined). - **R3 — Re-attach HAL + devices + drivers.** 🔴 **Not started.** A slim `hal/` is present, but `devices/` and `drivers/` do **not exist** at root. Re-point them at the reshaped runtime API, fix the drift (expected: a handful of renames + the ISR→wake path), then re-assert the composability matrix gate. - **R4 — Retarget tests + tools.** 🔴 **Not started.** `tests/` does **not exist** at root; `tools/` has only `SEGGER/` + `bin2uf2.py` — `tkgen` (pinmux) and `composability_matrix.sh` are **not** ported. Repoint host unit tests + tkgen/matrix at the promoted core. - **R5 — Board sweep.** 🟡 **Partial.** Four reshaped boards landed (`host`, `nrf52832_pca10040`, `qemu_riscv32_virt`, `rp2040_pico`). Reshaped ports drop in directly; HAL-only boards (MSP430, FR2433, STM32H723) re-attach via R3's HAL. RA4M1, TC275, STM32, ESP32, AVR boards are **not yet** at root. Retire the (already archived) pre-reshape `kernel/`+`arch/` once every live board is on the new core. Do this board-by-board, not big-bang. **Boundary — what is explicitly NOT in this plan** (so scope stays honest): new arch ports. The remaining reshape arches are mostly *confirmatory* and should be done **lazily, pulled by a board an integration target actually needs**, reusing the HW-verified `_legacy/` code rather than re-proving the pattern: - RISC-V S-standalone / SMP+U-mode — confirmatory (S-mode, U-mode, SMP each already proven; both the M-mode and S-mode/SBI QEMU targets are already at root). - **C2000 / TriCore / MSP430 full reshaped ports** — AXIS + CSA + small-RAM already validated. *Ahead of the plan:* `arch/c2000/` and `arch/tricore/` **already landed** as arch directories (C2000 core compiles under cl2000; TriCore has switch + SMP + lazy-CSA) — but neither is make-wired and neither has an in-root board yet. Finish them at R5 when their board is next. - **Cortex-M33 / ARMv8-M + TrustZone** — the one genuinely-NEW capability (secure/non-secure *world* isolation). `arch/arm_v8m` + the `mps2-an505` QEMU target are **already at root** (QEMU-proven); the TrustZone *world* dimension and HW bring-up (FRDM-MCXN947) remain the deliberate slot. ## 4. Rough total & the honest caveat Order-of-magnitude: **R0–R2 are largely behind us; R3–R4 ≈ 1 focused week; R5 is open-ended** (203 `_legacy` board files, done incrementally and only for boards that stay alive). The dominant cost is not writing code — it is the drift audit and keeping the composability gate green so the HAL/kernel independence the reshape earned is not lost on the way back in. The highest-value next slice that still delivers a coherent result is **R2 (finish introspect) → R3 on one reference board** (nRF52), proving the reshaped core hosts the full reuse stack on real silicon. ## 5. Not yet ported to root (the standing carry-forward list) The concrete backlog, reconciled against the root tree on 2026-08-19. Each item is *absent at root and present (proven) in `_legacy/`* unless noted. **Kernel features / observability** - **`tk_introspect.{c,h}` + `examples/monitor`** — the seqlock-guarded RO `ps`/`top` region and its unprivileged reader. (The `TK_CONFIG_ENABLE_INTROSPECT` knob and `tk_kernel_thread_snapshot` exist; the region + monitor do not.) → R2. - **L1 software-canary implementation** — `kernel/tk_stack.h` is a no-op placeholder; the fill / canary / high-water scan and `tk_thread_stack_peak/free` + overflow-hook API are not re-hosted. Note the placeholder's stale comment says "default `ENABLE_STACK_CHECK=0`" while `tk_config.h` defaults it to **1** — reconcile when the canary lands. → R2. - **Error / DET subsystem** — `kernel/tk_det.h` is a no-op stub (`TK_DET(...) → ((void)0)`); the `tk_error.*` counters/hooks/28-module-ID machinery is `_legacy/hal/` only. → R3/R4. - **`tk_time_us()` carries only millisecond resolution** — it ships as a flat `tk_kernel_now_ms() * 1000` rather than reading a sub-tick source, so even the host's nanosecond `CLOCK_MONOTONIC` is truncated to ms before it. A real per-board sub-tick surface is a later add. → R2. **Tooling (`tools/`)** - **`tkgen` pinmux registry** (`_legacy/tools/tkgen/pingen.py`) — YAML pin registry → validated const C tables. → R4. - **`composability_matrix.sh`** — the HAL-never-depends-on-kernel CI gate. **Not at root.** See the review carry-forward below. → R4. **Reuse layers (whole directories absent at root)** - **`tests/`** — 19 host unit test files; retarget at the promoted core. → R4. - **`devices/`** — PN532 + sensors (sit on HAL, not kernel). → R3. - **`drivers/`** — `tk_button` / `tk_led` / `gpiote` (one kernel touchpoint: ISR→wake). → R3. **Unported subsystems (safety/security — staged in `docs/safety-and-security.md`)** - **Crypto + verified boot** — SHA-256 / HMAC / AES-CBC / P-256 ECDSA, `tk_vboot` trust chain + signer pipeline. No crypto/vboot headers at root. - **Watchdog** — `tk_wdg` (mode-based HW watchdog). No `hal/tk_wdg.h` at root. - **Cross-core heartbeat** — `system/tk_heartbeat` + `TK_CONFIG_ENABLE_HEARTBEAT`. Not at root. - **Reset-reason / brownout** — `tk_mcu_reset_reason` / BOD warning backends. Not at root. - **Persistence** — the `.noinit`-survives-reset story: the *demo* `examples/noinit` **is** at root (with its own linker script), but any broader persistence subsystem is not tracked here. **API-boundary annotations & type hygiene** - **`[rt]` / `[setup]` header annotations** — ADR 0002 §4 fixes the runtime-vs-setup API split; the annotations ARE present in `kernel/tk_kernel.h` (**done**). ⚠ Open: `[rt]`-tagged `tk_kernel_self`/`tk_kernel_name` read privileged data → a fault under `TK_CONFIG_UNPRIV_THREADS` (see `docs/reviews/amp-smp-review-0001.md` L2). - **Residual `uint8_t` leak** — `kernel/tk_kernel.h`'s public `struct tk_thread_info` still declares `uint8_t base_priority` / `uint8_t state` — the kind-1-as-`uint8_t` anti-pattern ADR 0001 (Addendum 2) forbids. Fix to `unsigned char` when the introspection surface is next touched. **Isolation — implemented in `arch/`+`kernel/` but not wired at root** - **No root board provides the MPU zone symbols.** The `arm_v7m` (and `arm_v8m`/`risc_v`) isolation path references board-supplied linker symbols — `tk_mpu_flash_base/_size`, `tk_mpu_ram_base/_size`, plus the `.privileged_bss` / `.thread_stacks` zones — and **no root board defines them** (verified: `arch/arm_v7m/kernel_arch.c:295` externs them; nothing in `boards/` supplies them). So a build with `TK_CONFIG_ENABLE_MPU_ISOLATION` or `TK_CONFIG_UNPRIV_THREADS=1` **will not link on any root board today** — the machinery is present, the board wiring is not. Wire nRF52 first (its `arm_v7m` MPU path is the most complete). → R3/R5. - **`arch_stack_isolatable()` has no caller.** The fail-closed guard — reject/DET an unprivileged thread whose stack can't be MPU-isolated — is implemented on every `ARCH_HAS_MPU` arch (`arm_v7m`/`arm_v8m`/`risc_v`) but `kernel/tk_kernel.c` never calls it (verified). Add the check where unprivileged threads are admitted; until then the guard the isolation design assumes is absent. → R2/R3. **Review carry-forwards (re-verify; do not reopen the design)** - **SEC-4 — hard-coded MPU sub-region mask.** A prior review flagged a hard-coded sub-region disable mask in the MPU region programming. Re-verify it against the reshaped `arch/arm_v7m` / `arch/arm_v8m` MPU code; confirm it is still correct (or parameterized) — this is a re-verification, not a reopened design question. - **HAL-only CI build.** The follow-up to prove HAL builds standalone (no kernel) was expected to be satisfied by `composability_matrix.sh`. **Correction:** that tool is **not yet at root** (see Tooling above), so the automated gate is **not currently satisfied here** — the *design* is settled (the `_legacy` matrix), the *re-port* is the open action (R4). Confirm the invariant still holds; do not reopen the design.