Phase 3 of the device sim, all verified on QEMU 10.0.11: - qemu/rs485-bridge/: std-only crate bridging a QEMU serial chardev (unix socket) to warden_sim::ModbusSlave — gap-based RTU framing (CRC failures degrade to real-slave silence), line-protocol control socket for register seeding and fault injection (drop/exception/clear), bounds-checked so a scenario typo answers err instead of panicking the bus. 7 unit tests, bench in the sim_bench pattern. Verified end-to-end: guest master frame on /dev/ttyS4 (pci-serial) answered from the sim slave, CRC-correct. - virt machine gains highmem=off: the 32-bit non-LPAE kernel cannot reach virt's default 40-bit PCIe ECAM (pci-host-generic EOVERFLOW); with it the full PCI set probes (16550A ttyS0, i6300esb). - Watchdog scenario verified: guest arms /dev/watchdog, no petting, i6300esb resets the VM ~30s later (first environment where this arm is testable). - qemu/tests/portal-scenario.sh: the real static-musl warden-flared inside the VM against flare-edge's mock portal on the host — authenticated check-in, firmware desired-state pull, and download of a real signed tier-1 .wfw offer, asserted from the portal log. Found and filed flare-edge#106 (fatal SIGBUS in the HPMCU boot-loaded probe on non-RV1106 memory maps); runs against a flared built from the qemu-vm-support fix branch. - stage-2 init: WARDEN_FLARE_INSECURE=1 + WARDEN_HPMCU=0 (documented VM deviations), firmware-version stamp, newline-terminated state seeds. - CI: rs485-bridge joins the test loop and bench job; new qemu-tools job (shellcheck + initramfs + disk image on hosted runners); kernel-build gains a fail-closed qemu boot-smoke step. All qemu scripts shellcheck-clean. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018HUayid7W5w7jBdb9Rrj1K
qemu/ — the WardenOS device simulator
A QEMU virtual machine that boots the real forward-ported kernel (build/ +
patches/) and real userspace, so the device — init, daemons, networking,
OTA, watchdog — can be tested off-hardware. The third simulator in the stack,
deliberately not named "sim":
lvglsim(flare-edge) — SDL desktop build of the UI. Rendering only.sim/(this repo) — register-level Rust models of RV1106 blocks behind driver seams.qemu/(this) — the whole machine above the kernel entry point.
The boundary (read this before trusting a green run)
There is no RV1106 machine model in QEMU and everything below the kernel is
closed rkbin blobs plus mask ROM, so the VM enters at -kernel zImage on
-M virt (generic ARMv7 machine, virtio peripherals). That means:
- Not emulated, not tested here: BootROM, idblock/DDR-init, SPL, U-Boot, the real BCB-driven A/B slot selection, bootcount auto-revert. The untested A/B rollback chain stays untested by this tool.
- Substituted, not modeled: display (virtio-gpu, not VOP), input
(virtio-tablet, not GT911), network (virtio-net, not GMAC), storage
(virtio-blk, not eMMC). NPU/RGA/HPMCU behavior stays
sim/territory. - "Boots under emulation" is not "works on silicon". On-device claims still need on-device evidence; the VM narrows which claims need a panel.
Quick start
# 1. build the QEMU kernel variant (canonical RV1106 build + virt fragment)
WORK=$HOME/kbuild-out CROSS_COMPILE=arm-linux-gnueabihf- \
WARDEN_KCONFIG_FRAGMENT=qemu/configs/virt.fragment bash build/build-kernel.sh
# 2. build the initramfs (sha256-pinned static busybox + qemu/rootfs/)
bash qemu/mkinitramfs.sh
# 3. smoke it
bash qemu/tests/boot-smoke.sh $HOME/kbuild-out/linux-6.18.46/arch/arm/boot/zImage
Host requirements: qemu-system-arm (Debian 13 ships QEMU 10), curl, cpio,
gcc-arm-linux-gnueabihf for the kernel build.
Status: bringup — boot smoke only. Disk/network harness, RS485 bridge to
sim/, portal scenarios, and display/touch land in later phases (see
docs/decisions/0006-qemu-device-sim.md once written).