qemu: display + touch scenario, ADR-0006, docs
Phase 4+5 of the device sim: - Display + touch verified end-to-end: virtio-gpu at 720x720 (fbdev emulation) renders the real WardenOS dashboard from the static LVGL fbdev+evdev UI build (flare-edge qemu-vm-support tools/build-ui-vm.sh); QMP input-send-event taps the Metrics tab and qemu/tests/ui-shot.sh asserts the repaint from screendumps. Two load-bearing QEMU flags found and documented: -global virtio-mmio.force-legacy=false (gpu/input are VERSION_1-only) and the 200ms press hold (an instantaneous press+release lands inside one LVGL indev poll and never clicks). - qemu/tests/qmp.py: minimal QMP client (screendump, tap, quit). - stage-2 init starts warden-ui when present and fb0 exists. - docs/decisions/0006-qemu-device-sim.md: virt-not-custom-board, the enters-at-kernel boundary, fragment policy, naming, consequences. - docs/architecture.md: new section 7 (device emulation), order-of-work item 7; modbus cross-reference to the bridge. - qemu/README.md: emulated-vs-not table, scenarios, gotchas, host/runner requirements. docs/ci-cd.md: runner needs one-time qemu-system-arm install (fail-closed smoke until then, [maintainer]-gated). Repo README updated. Final sweep on this commit: shellcheck clean, bridge 7/7 tests, boot smoke PASS, portal scenario PASS (check-in + fw pull + signed .wfw download), ui-shot PASS (touch navigates to Metrics) — all under the final flags. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018HUayid7W5w7jBdb9Rrj1K
This commit is contained in:
co-authored by
Claude Fable 5
parent
c7e06514ad
commit
13b7d063a2
+31
-2
@@ -71,7 +71,9 @@ supervisor logic runs in CI with no panel.
|
||||
(CRC16 byte-identical to the master, FC 0x01–0x06/0x0F/0x10/0x11, exception replies,
|
||||
and fault injection — silent-drop and forced-NAK) so `warden-modbus`'s master can be
|
||||
hardened to MC/DC against realistic device behaviour with no serial hardware. MEI
|
||||
(0x2B/0x0E) identification is the documented follow-up.
|
||||
(0x2B/0x0E) identification is the documented follow-up. The same slave also serves
|
||||
as the QEMU device sim's field bus: `qemu/rs485-bridge/` feeds it from a serial
|
||||
chardev so the guest's real master polls it over what it believes is /dev/ttyS4 (§7).
|
||||
- **`npu` — NPU load model.** Done. `NpuSim` models `/proc/rknpu/load` (the exact
|
||||
"NPU load: N%" text the sysmon reads) behind the path seam, so the load-readout UI
|
||||
is host-testable. NPU *compute* is explicitly out of scope — no inference runs here.
|
||||
@@ -152,7 +154,31 @@ kernel move as one matched boot+oem image, never a partial reflash.
|
||||
series honest against pristine 6.18.46; provenance is in `patches/README.md` and
|
||||
`kernel/rv1106-enablement/`.
|
||||
|
||||
## 7. Order of work
|
||||
## 7. Device emulation (`qemu/`) — see ADR-0006
|
||||
|
||||
The third simulator, deliberately not named "sim": a QEMU VM (`-M virt,highmem=off`,
|
||||
one Cortex-A7, 256M — the RV1106G3's shape) that boots the real forward-ported
|
||||
kernel and real userspace, entering at `-kernel zImage` because everything below
|
||||
(BootROM, idblock/DDR-init, U-Boot, the BCB A/B machinery) is closed blobs plus
|
||||
mask ROM. The canonical RV1106 zImage boots virt unmodified; an additive kconfig
|
||||
fragment (`qemu/configs/virt.fragment` via `WARDEN_KCONFIG_FRAGMENT`) adds the
|
||||
scenario devices (PCI serial for RS485, i6300esb watchdog, WireGuard,
|
||||
virtio-gpu/input for the 720x720 UI). The virtio disk carries the device's exact
|
||||
12-partition `blkdevparts=` A/B layout and the `/dev/block/by-name/` contract.
|
||||
|
||||
Where the seams meet: the guest runs the *real* binaries (static musl flared,
|
||||
the LVGL fbdev UI); the RS485 bridge (`qemu/rs485-bridge/`) connects a QEMU
|
||||
serial chardev to `sim/`'s `ModbusSlave`, so the register-level models serve as
|
||||
the VM's field bus — behavior lives in one place, `sim/`, and the VM consumes
|
||||
it. Scenario tests: `qemu/tests/boot-smoke.sh` (CI, in kernel-build),
|
||||
`portal-scenario.sh` (check-in + OTA offer download against flare-edge's mock
|
||||
portal), `ui-shot.sh` (QMP screendump + touch injection). Division of labour
|
||||
with the other sims: NPU/RGA/HPMCU *behavior* stays `sim/`; UI *rendering
|
||||
development* stays `lvglsim`; the VM is where processes, the kernel, and the
|
||||
network meet. §5 still applies — no behavioural sim, this one included, catches
|
||||
memory-map faults; and "boots under emulation" is never on-silicon evidence.
|
||||
|
||||
## 8. Order of work
|
||||
|
||||
1. **Simulator core** — `membus`, `hpmcu`, the `cru` reset ladder, `modbus`, plus the
|
||||
`rga`/`npu` models. **Done.**
|
||||
@@ -163,3 +189,6 @@ series honest against pristine 6.18.46; provenance is in `patches/README.md` and
|
||||
4. **Config-lint CI gates** (§5) — the brick-class of bug. **Done.**
|
||||
5. **Hermetic kernel build** (`build/build-kernel.sh` + the `patches-apply` gate). **Done.**
|
||||
6. **Kernel 5.10→6.18.46 forward-port** (§6, ADR-0001). **Done** (hardware-verified).
|
||||
7. **QEMU device sim** (§7, ADR-0006) — boot smoke, A/B disk harness, RS485 bridge,
|
||||
portal/watchdog/clock scenarios, display+touch. **Done** (emulation-verified;
|
||||
booting the real flare-edge rootfs+oem image pair is a documented later milestone).
|
||||
|
||||
@@ -45,6 +45,14 @@ A **third** repo-scoped runner instance on `bfe-mpc-0640` (alongside `flare` and
|
||||
|
||||
Host build deps: `dtc bc flex bison libssl-dev` — already present on 0640.
|
||||
|
||||
5. **`qemu-system-arm`** (for the boot-smoke step inside `kernel-build`, added
|
||||
with the `qemu/` device sim — ADR-0006): one-time
|
||||
`sudo apt-get install qemu-system-arm cpio` on 0640. The step is
|
||||
**fail-closed** — a missing qemu binary fails the job with a message
|
||||
pointing here; it never silently skips. NOT YET PROVISIONED (2026-08-29):
|
||||
the first dispatched `kernel-build` after this lands will fail its smoke
|
||||
step until the install is done ([maintainer]-gated sudo on 0640).
|
||||
|
||||
## Badges
|
||||
|
||||
Static shields SVGs are committed by the `badges` job (private repo can't use
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
# ADR 0006 — QEMU device sim: generic `-M virt`, entered at the kernel
|
||||
|
||||
**Status:** Accepted (2026-08-29).
|
||||
|
||||
## Context
|
||||
The two existing simulators cannot test the *device*: `lvglsim` (flare-edge)
|
||||
is an SDL rendering harness, and `sim/` models registers behind driver seams.
|
||||
Init ordering, the daemons as real processes, networking/enrollment against
|
||||
FLARE, OTA, and the watchdog were testable only on a bench panel — flare-edge's
|
||||
fault suite marks five scenarios "HIL, human prompts", its Playwright e2e needs
|
||||
a live panel on the LAN, and its OTA desk test stops at "reached APPLYING".
|
||||
|
||||
Two ways to emulate the panel were considered:
|
||||
|
||||
1. **A custom RV1106 QEMU board model.** Nothing exists upstream or in the
|
||||
community, so this means writing VOP/CRU/GRF/eMMC/HPMCU device models from
|
||||
scratch and maintaining them against QEMU — months of work that duplicates
|
||||
what `sim/` already models in Rust. It still could not run the boot chain:
|
||||
BootROM is mask ROM and the DDR-init/idblock stages are closed rkbin blobs.
|
||||
2. **The generic `-M virt` machine, entering at `-kernel zImage`.** The
|
||||
forward-ported 6.18.46 config is multi_v7-derived and already carries
|
||||
`ARCH_VIRT` plus the full virtio set — the canonical RV1106 zImage boots
|
||||
virt **unmodified** (verified 2026-08-29). Peripherals become virtio
|
||||
substitutes; SoC-block behavior stays in `sim/`, bridged in (the RS485
|
||||
chardev bridge) rather than re-modeled.
|
||||
|
||||
## Decision
|
||||
Option 2. `qemu/` holds the harness: `qemu-system-arm -M virt,highmem=off
|
||||
-cpu cortex-a7 -smp 1 -m 256M` (the RV1106G3's shape), one canonical kernel
|
||||
image plus an optional additive config fragment (`qemu/configs/virt.fragment`
|
||||
via the `WARDEN_KCONFIG_FRAGMENT` hook — PCI/pci-serial/i6300esb/WireGuard/
|
||||
virtio-gpu/virtio-input; the RV1106 build is byte-identical with the variable
|
||||
unset). The VM carries the device's real 12-partition `blkdevparts=` A/B
|
||||
layout on a virtio disk and populates the `/dev/block/by-name/` contract.
|
||||
The name is `qemu/`, not any variant of "sim" — the wikis already warn that
|
||||
"sim" is two different things.
|
||||
|
||||
Notable mechanics: `highmem=off` because the non-LPAE 32-bit kernel cannot
|
||||
reach virt's default 40-bit PCIe ECAM; `-global virtio-mmio.force-legacy=false`
|
||||
because virtio-gpu/input are VERSION_1-only devices.
|
||||
|
||||
## Consequences
|
||||
- Everything below the kernel is **out of scope**: BootROM, idblock, U-Boot,
|
||||
the real BCB-driven A/B selection and bootcount auto-revert. The initramfs
|
||||
`warden.slot=` switch emulates U-Boot's *choice*, not the mechanism. The
|
||||
untested A/B rollback chain stays bench territory.
|
||||
- Display, input, network, and storage are **substitutes** (virtio), not
|
||||
models. "Boots/works under emulation" is never evidence of "works on
|
||||
silicon"; the VM narrows which claims need a panel.
|
||||
- The VM is the first environment that runs production userspace binaries on
|
||||
a non-RV1106 physical memory map, which makes it a canary for baked-in
|
||||
hardware assumptions (it immediately found flare-edge #106, a fatal SIGBUS
|
||||
in flared's HPMCU probe, and #107, a Y2038 time_t truncation in the UI).
|
||||
- The guest deliberately deviates from production in documented ways
|
||||
(`WARDEN_FLARE_INSECURE=1` for the desk mock portal, `WARDEN_HPMCU=0`);
|
||||
qemu/README.md carries the emulated-vs-not table.
|
||||
- The kernel-build CI job gains a fail-closed qemu boot smoke; hosted runners
|
||||
build (but cannot boot) the initramfs and disk image.
|
||||
Reference in New Issue
Block a user