diff --git a/qemu/README.md b/qemu/README.md index e4c3551..a6f38e8 100644 --- a/qemu/README.md +++ b/qemu/README.md @@ -63,9 +63,15 @@ bash qemu/run.sh --kernel $HOME/kbuild-out/linux-6.18.46/arch/arm/boot/zImage -- ``` Payload: drop static musl armv7 binaries into `qemu/payload/` (see its -README); `warden-flared`, `warden-modbus`, and `warden-ui` (the LVGL -fbdev+evdev build from flare-edge `tools/build-ui-vm.sh`) are started by -stage-2 init when present. +README). Stage-2 init starts every panel daemon it finds, in the panel's own +S-number order (`warden-ai`, `warden-automation`, `warden-modbus`, +`warden-mikrotik`, `warden-asic`, `warden-starlink`, `warden-stratum`, +`warden-flared`), then `warden-ui` (the LVGL fbdev+evdev build from +flare-edge `tools/build-ui-vm.sh`). The quickest faithful payload is the +daemons a bench panel already runs: flare-edge `tools/rig-pull-daemons.sh +--host ` copies them in. The RS485 UART is always present (a null +chardev without `--rs485`), so `warden-modbus` polls a port with nothing on +it, as on a panel with an empty header, and never the control channel. The VT cursor is kept off (`vt.global_cursor_default=0`): fbcon shares the virtio-gpu framebuffer with warden-ui and its blinking cursor would otherwise diff --git a/qemu/payload/README.md b/qemu/payload/README.md index ba2fae4..1ef464c 100644 --- a/qemu/payload/README.md +++ b/qemu/payload/README.md @@ -20,7 +20,16 @@ Then: cp /target/armv7-unknown-linux-musleabihf/release/warden-flared qemu/payload/ ``` -Stage-2 init starts `warden-flared`, `warden-modbus`, and `warden-ui` (the -UI also needs `--display on|headless` + the virt.fragment kernel for -/dev/fb0) automatically when present (logs land in `/tmp/.log` inside -the guest). An empty payload is valid: the image boots busybox-only. +Or take them from a panel that already runs them: every daemon is a static +musl binary, so flare-edge `tools/rig-pull-daemons.sh --host ` copies +`/usr/bin/warden-*` straight into this directory (recording the panel's +release and each md5 in `PULLED.txt`), minus `warden-ui`, which the rig +needs as the fbdev+evdev build. + +Stage-2 init starts every `warden-*` daemon it finds here, in the panel's +own S-number order (ai, automation, modbus, mikrotik, asic, starlink, +stratum, flared), then `warden-ui` (the UI also needs `--display +on|headless` + the virt.fragment kernel for /dev/fb0). Logs land in +`/tmp/.log` inside the guest, readable over the control bridge with +`ctl @cat /tmp/.log`. An empty payload is valid: the image boots +busybox-only. diff --git a/qemu/rootfs/sbin/init b/qemu/rootfs/sbin/init index 52f3420..2a52105 100755 --- a/qemu/rootfs/sbin/init +++ b/qemu/rootfs/sbin/init @@ -47,8 +47,12 @@ mount_fatal "oem${slot}" /oem mkdir -p /userdata/warden # RS485: warden-modbus hardcodes /dev/ttyS4 at compile time; alias it to the -# VM's pci-serial UART when one is present (needs the virt.fragment kernel). -[ -c /dev/ttyS0 ] && ln -sf /dev/ttyS0 /dev/ttyS4 +# VM's RS485 pci-serial UART (needs the virt.fragment kernel). run.sh lists +# the control channel's port first when there is one (warden.ctl on the +# cmdline), so the RS485 UART is ttyS1 then and ttyS0 otherwise. Aliasing +# ttyS0 blindly put Modbus polls on the control channel. +if grep -qw warden.ctl /proc/cmdline; then rs485="/dev/ttyS1"; else rs485="/dev/ttyS0"; fi +[ -c "$rs485" ] && ln -sf "$rs485" /dev/ttyS4 # Network: slirp user-mode net on eth0 (DHCP, fallback to QEMU's static map). # The fallback keys off the interface actually having an address: udhcpc @@ -86,7 +90,17 @@ if grep -qw warden.fwapply /proc/cmdline; then export WARDEN_FW_ALLOW_APPLY=1 echo "init: OTA APPLY ENABLED (warden.fwapply)" fi -for d in /usr/bin/warden-flared /usr/bin/warden-modbus; do +# The same daemons the panel's SysV scripts start, in their S-number order +# (S92 ai, S93 automation, S94 modbus, S95 mikrotik, S96 asic/starlink/ +# stratum, S97 flared), each with no arguments and no environment, exactly +# as start-stop-daemon runs them there. A daemon that cannot live on -M virt +# (warden-ai wants the NPU) exits into its log and the UI shows the same +# "not running" it would show on a panel whose daemon died; that is the +# panel's behaviour, not a rig substitute for it. warden-watchdog stays out: +# it and a payload flared do not mix (README). +for d in /usr/bin/warden-ai /usr/bin/warden-automation /usr/bin/warden-modbus \ + /usr/bin/warden-mikrotik /usr/bin/warden-asic /usr/bin/warden-starlink \ + /usr/bin/warden-stratum /usr/bin/warden-flared; do if [ -x "$d" ]; then name="$(basename "$d")" echo "init: starting $name" diff --git a/qemu/run.sh b/qemu/run.sh index 7587b96..934b6e5 100755 --- a/qemu/run.sh +++ b/qemu/run.sh @@ -126,8 +126,17 @@ fi # Modbus wire. [ -n "$CTL" ] && ARGS+=( -chardev "socket,id=ctl,path=$CTL,server=on,wait=off" -device "pci-serial,chardev=ctl" ) -[ -n "$RS485" ] && ARGS+=( -chardev "socket,id=rs485,path=$RS485,server=on,wait=off" - -device "pci-serial,chardev=rs485" ) +# Without --rs485 the UART is still there, wired to nothing: warden-modbus +# then polls a port that never answers, which is what a panel with an empty +# RS485 header looks like, rather than failing to open a port that does not +# exist (a different UI state) or, worse, being aliased onto the control +# channel by init (which happened: Modbus frames in the wake reply). +if [ -n "$RS485" ]; then + ARGS+=( -chardev "socket,id=rs485,path=$RS485,server=on,wait=off" + -device "pci-serial,chardev=rs485" ) +else + ARGS+=( -chardev "null,id=rs485" -device "pci-serial,chardev=rs485" ) +fi [ -n "$QMP" ] && ARGS+=( -qmp "unix:$QMP,server=on,wait=off" ) case "$DISPLAY_MODE" in