Files
bfe-core1106-sdk/README.md
T
BFE EngineeringandClaude Fable 5 2756de0b46 review: iteration-1 fixes across CI, bridge, VM harness, and docs
CI/pipeline:
- KERNEL_TARBALL passed as a YAML env literal '~' was never tilde-expanded
  and would have failed every hosted kernel-build dispatch; the path is now
  exported from the shell. Verified reproducible before the fix.
- Every job gets timeout-minutes; boot smoke uses timeout -k so a wedged
  qemu is SIGKILLed instead of holding the job.
- Tarball fetch + fail-closed sha256 verification deduplicated into
  build/fetch-kernel-tarball.sh (with curl retries), used by build-kernel.sh
  and both CI jobs. busybox fetch gains retries too.
- ccache layer for kernel-build (cache keyed on defconfig+patches) recovers
  the incremental-compile speed the ephemeral-runner move cost.
- build-kernel.sh now asserts every fragment option survived olddefconfig —
  merge_config -m pastes text and Kconfig silently drops unmet symbols.

rs485-bridge:
- pending-buffer cap (2x max RTU ADU) instead of unbounded growth;
  explicit accept-loop error handling with backoff instead of .flatten();
  per-arm inline bounds instead of the string-keyed lookup whose default
  would have mis-bounded a future get-input; control-socket cleanup errors
  surfaced; flag-shaped values rejected in arg parsing; doc example uses a
  private mktemp dir. Test timing margins widened for contended runners
  (gap 25->120ms, 60x margin on the split-frame test).

VM harness:
- stage-1/stage-2 boot scripts share one validated slot parser and one
  by-name populator (qemu/rootfs/etc/warden-lib.sh) — the duplicated
  parser had already diverged on validation; userdata/oem mount failures
  now fail fast with a greppable sentinel; udhcpc fallback keys off the
  interface actually having an address; switch_root applet guarded.
- boot-smoke delegates the qemu invocation to run.sh (machine shape lives
  in ONE place); run.sh port 0 disables a hostfwd.
- mkimage: unknown partition names fail at build time; DISK_END is a max,
  not last-entry; --state keys validated as filenames.
- portal-scenario: mock readiness is asserted (no silent fall-through),
  hostfwd port collisions retried, mount-failure sentinel fails fast.
- ui-shot: fixed sleeps replaced with bounded screendump polling; the
  repaint assertion is real and documented as such. qmp.py loses its
  module-global and gains argv validation.

Docs/scrub: bench-host paths and the site AP name removed from six more
port docs and two evidence tables; path-bearing build artifacts (.elf,
.map) untracked (the 154-byte firmware .bin is path-free and stays);
ADR-0003 marked visibility-superseded by ADR-0007; stale section
cross-reference fixed; flare-edge noted as private for outside readers;
stale root-level review report removed per the new workspace rule.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018HUayid7W5w7jBdb9Rrj1K
2026-08-30 08:19:17 -06:00

138 lines
7.6 KiB
Markdown

# warden-sdk
[![ci](https://github.com/bfe-noah/warden-sdk/actions/workflows/ci.yml/badge.svg)](https://github.com/bfe-noah/warden-sdk/actions/workflows/ci.yml)
![Lines of code](.github/badges/loc.svg)
![Tests](.github/badges/tests.svg)
![Coverage](.github/badges/coverage.svg)
The build, driver, and simulation SDK for WardenOS (the Luckfox Pico 86-Panel /
RV1106 HMI). A from-scratch replacement for the twice-ported vendor stack
(Rockchip SDK → Luckfox SDK → our patched fork), built to the same standard as
the rest of the firmware: tested, benchmarked, reproducible, and honest about
what runs on real silicon versus what we simulate.
> Status: **bringup.** The hardware **simulator** and its tests, the RV1106 kernel
> forward-port as a reviewable `patches/` series, the hermetic kernel build, two
> Tier-1 drivers at 100% MC/DC, and the **QEMU device sim** (`qemu/`, ADR-0006:
> boots the real kernel + real userspace on `-M virt` — check-in/OTA against the
> mock portal, watchdog, RS485-to-sim bridge, 720x720 display + touch, all
> emulation-verified) are in. What remains before this is on the production build
> path: having flare-edge consume warden-sdk as a dependency (maintainer-gated).
> Until then, flare-edge still builds firmware from the vendored SDK +
> `sdk-patches/`.
## Why a new SDK
The vendored SDK is a ~2 GB opaque fork of a fork. Our real changes to it lived,
until recently, as uncommitted edits in one working copy (`flare-edge/sdk-patches/`
is the tracked form). It bakes absolute paths, needs `python` (not python3),
silently drops Kconfig options, and — the failure that motivated this repo — gives
us **no way to test hardware-dependent code off the device.** Every driver change
had to be validated by flashing a panel. That is slow, and it is dangerous: it is
how a boot-loaded-watchdog change bricked a bench unit (the load address collided
with unreserved kernel RAM — a mistake a target-config check or a memory-map model
would have caught before any flash).
The SDK's job is to make the firmware **buildable, testable, and hardenable
without a panel in the loop**, and to move us onto a modern, maintained kernel.
## Goals (from future-features)
1. **Modern kernel.** A self-built **Linux 6.18.46**, forward-ported directly from
the vendor 5.10.160 tree (no plan44/OpenWrt code) on our current Buildroot LTS
(2025.02.x). This is **done and hardware-verified on `warden-c8a3`**: essentially
every RV1106 block the 86-Panel uses boots and works — clk, pinctrl, eMMC, GMAC,
TRNG, OTP, SARADC/TSADC, RTC, USB host, PWM/backlight, **VOP display**, **GT911
touch**, **AIC8800 wifi**, **RGA**, **I2S audio**, **HPMCU mailbox**, the **open
NPU driver**, and **PVTM**. Mainline was not viable (no DT/clk/display/RGA/NPU/
flash-boot upstream for RV1106); the direct 5.10→6.18 forward-port reuses the
already-in-mainline rv1126 register data where it matches and carries our deltas
as a reviewable patch series (`patches/`).
2. **Ported, hardened drivers → 100% MC/DC on the code we own.** "100% MC/DC on
100% of drivers" is infeasible as literally stated: ~97% of driver LOC is
vendor blobs (the AIC8800 wifi driver alone is 88.5K lines). So the target is
**tiered**: real MC/DC on *our* hardware code (modbus master, relays, RGA
wrapper, HPMCU supervisor, devmem/reset ladder); fault-injection + branch
hardening for the vendor blobs behind a stable seam.
3. **A proper simulator.** Simulate the hardware the vendor SDK cannot: **RGA**
(2D blitter), the **RISC-V HPMCU** coprocessor, and the **NPU** — plus the
register/SRAM (`/dev/mem`) and sysfs surfaces the drivers touch — so driver and
supervisor logic runs and is tested on the host, in CI, with no panel.
4. **Its own repo, held to firmware standards.** Tests, benchmarks, reproducible
builds, CI. This repo.
## Architecture — one seam, two backends
The organizing idea is a thin **Hardware Abstraction Seam** per hardware block.
Firmware code talks to the seam (a trait in Rust, a function table in C); the seam
has two backends:
```
firmware / driver logic
Hardware Abstraction Seam (devmem, hpmcu, rga, npu, modbus, gpio)
┌────┴────┐
real backend sim backend
(/dev/mem, ioctl, (software model,
/proc, serial) host-testable)
```
- **On-device**, the seam binds the real backend (mmap `/dev/mem`, `librga`
ioctls, the serial port, `/proc/rknpu`).
- **On the host**, it binds the **sim backend** — a faithful software model of the
block. The HPMCU sim, for example, runs the SCR1 watchdog firmware's exact state
machine (boot-grace, heartbeat-timeout, fire) against an in-memory mailbox, so
the flared supervisor's arm/beat protocol is exercised end-to-end in a unit test.
The seam is the same object the driver-hardening effort measures MC/DC against,
and the same object the simulator implements — so the two goals reinforce rather
than duplicate each other.
## Layout
```
sim/ the hardware simulator (Rust): membus/devmem, HPMCU, CRU, Modbus, RGA, NPU.
qemu/ the device simulator (ADR-0006): QEMU -M virt boots the real kernel and
real userspace; A/B disk layout, RS485 bridge into sim/, scenario tests.
drivers/ our own hardened drivers + their seams (relays, freshness; more migrate in).
patches/ the RV1106 kernel forward-port delta onto pristine linux-6.18.46 (subsystem-split).
kernel/ forward-port docs + provenance (rv1106-enablement/, PROVENANCE.md).
build/ the hermetic kernel build (fetch pristine → apply patches → zImage + dtb).
docs/ architecture + ADRs (decisions/) + ci-cd + generated workflow flowcharts.
tools/ dev tooling. config-lint: static target-config gates (MCU-load-vs-reserved-memory,
the 0x40000 brick class); flowgen: the workflow-flowchart generator.
.github/ CI (workflows/ci.yml): patches-apply, host tests, coverage, MC/DC, benchmarks, badges.
```
## Principles
Evaluated against the stack philosophy — **openness, hardness, modernness**:
- **Open** over closed where we can: `rkdeveloptool` over the closed `upgrade_tool`;
source-buildable `librga` over blobs where a source path exists; the simulator is
fully open and ours.
- **Hard**: every seam has a fault-injection path (a wedged SDIO link, a stalled
MCU, an RGA timeout) so recovery code is tested against failure, not just success.
On-device claims still need on-device evidence; the sim narrows *which* claims
need a panel, it does not replace that rule.
- **Modern**: newest kernel we can actually run; current Buildroot LTS; Rust for new
host-testable code; reproducible builds.
## Relationship to flare-edge
flare-edge (WardenOS: the LVGL UI + the `flared` daemon) is the product; warden-sdk
is what builds and tests it. flare-edge is BlueFlare's private companion repo —
not publicly available — so flare-edge issue references and checkout paths in
this repo's docs are context, not reachable links. During bootstrap, flare-edge consumes warden-sdk piece
by piece: first the simulator (as a dev/test dependency), later the image build.
No flare-edge code moves here — only the SDK/build/sim/driver-seam layer.
## License
**GPL-2.0-only**, repo-wide (see `LICENSE`; a per-file SPDX identifier governs
where one is present, e.g. a few GPL-2.0-or-later kernel files). The kernel
material in `patches/` and `kernel/rv1106-enablement/` is derivative of the
Linux kernel and of GPL-2.0 vendor code either way — per-driver origin and
license are tracked in `kernel/rv1106-enablement/PROVENANCE.md`. Contributions
are accepted under the same license (inbound = outbound).