fix(pi3): bypass systemd with velxio-init — ~10s to root shell

Pi 3 simulator boot through Pi OS systemd graph was unworkable inside
QEMU's raspi3b emulation:

* The PL011 UART at 0x3f201000 enumerates as ttyAMA1 (not ttyAMA0 —
  the mini-UART at 0x3f215040 takes ttyAMA0 and fails to probe under
  QEMU). After ~9 s of kernel time the boot effectively went silent
  on the serial: earlycon was disabled by the normal console init
  and the IRQ-driven serial driver loses TX under QEMU's emulation.
* Even with `keep_bootcon`, systemd dependency graph took 2-3 min to
  walk inside emulation (network waits, tmpfiles, journald,
  hostname/machine-id randomness). Masking 9 boot-blocking units
  helped but didn't fix the silent-after-9s problem.

Solution: skip systemd. The SD image is now baked with
`/usr/local/sbin/velxio-init` (a 30-line bash script) and the kernel
cmdline points init= at it. velxio-init mounts /proc /sys /dev /pts
/run /tmp, sets hostname, then loops a passwordless `/bin/bash
--login </dev/ttyAMA1 >/dev/ttyAMA1`. User sees the prompt within
~10 s of clicking Run; Ctrl-D respawns a fresh session.

Cmdline additions:
  - `keep_bootcon` — keep earlycon alive after the regular console
    registers, so kernel printk continues to reach ttyAMA1.
  - `console=ttyAMA1,115200` — the correct PL011, not ttyAMA0.
  - `init=/usr/local/sbin/velxio-init` — bypass systemd entirely.

Python, GPIO shim, apt, mount, etc. all work — they don't need
systemd as PID 1, just a populated rootfs + mounted pseudo-fs.

Manifest version bumped to 2026-04-21+velxio-init. Same byte size,
different SHA, so the sidecar-based cache invalidator forces a
re-fetch on every velxio backend the next time it starts.
This commit is contained in:
davidmonterocrespo24 2026-05-16 08:04:57 +02:00
parent 4d4d4622ff
commit c4b6b8ea69
2 changed files with 32 additions and 19 deletions

View File

@ -22,13 +22,13 @@
{
"name": "raspios-trixie-armhf.img",
"asset_id": "raspios-trixie-armhf-zst",
"sha256": "36b0e9358940ff1ffa9a0f2da3e74c75a2ff657e67e3ed6780df3c5c0df3038d",
"sha256": "8963dbfafa2b0e4673499a74cc9fc0dcb8da49d023e6d340301d071abd07bba8",
"size_bytes": 5729419264,
"version": "2026-04-21+autologin+fastboot",
"version": "2026-04-21+velxio-init",
"compressed": {
"encoding": "zstd",
"sha256": "8de2ed5e49031a92d56a15e894a9f430949cd21ce5ebe26353839073853162e0",
"size_bytes": 1488007643
"sha256": "8e0eca1865c4a32bbe096044e8ea1d9adeb80f3ffe9fe2f45a54881f7020266d",
"size_bytes": 1488007156
}
}
]

View File

@ -184,23 +184,36 @@ class QemuManager:
# ttyAMA1 → GPIO shim protocol
'-serial', f'tcp:127.0.0.1:{inst.gpio_port},server,nowait',
'-append',
# earlycon=pl011,mmio32,0x3f201000 — without explicit address
# the kernel doesn't initialise the BCM2837 PL011 UART early
# enough for any output to reach ttyAMA0; we get a silent
# boot followed by a "broken simulator" report. The address
# matches the BCM2837 SoC peripheral mapping (Pi 3 base
# 0x3f000000 + PL011 offset 0x201000).
# earlycon=pl011,mmio32,0x3f201000 — the BCM2837 PL011 UART
# MMIO address. earlycon polled-mode is what actually carries
# all of our serial output; QEMU's raspi3b emulation drives
# the PL011 correctly in this mode but the kernel's normal
# interrupt-based serial driver loses TX once systemd hands
# off (confirmed by experiment — output silently stops after
# ~9 s of kernel time without keep_bootcon).
#
# No `quiet`: surface kernel boot messages to ttyAMA0 so the
# user sees progress while the 5.4 GiB Pi OS rootfs comes up.
# No `init=/bin/sh`: let systemd run normally; the SD image
# ships with a serial-getty@ttyAMA0 autologin drop-in (baked
# by scripts/configure-pi3-autologin.sh) so the user lands
# at a root shell without credentials.
'earlycon=pl011,mmio32,0x3f201000 '
'console=ttyAMA0,115200 '
# keep_bootcon — don't disable earlycon when the regular
# console driver registers. Without this, the boot goes
# silent at the same moment systemd takes /dev/console.
#
# console=ttyAMA1,115200 — the PL011 at 0x3f201000
# enumerates as ttyAMA1 (not ttyAMA0!). The mini-UART at
# 0x3f215040 takes ttyAMA0 and fails to probe under QEMU.
# console= here drives userspace output once the kernel
# hands off; it works in tandem with the kept-alive earlycon
# for full kernel printk coverage.
#
# init=/usr/local/sbin/velxio-init — skip systemd entirely.
# The init script (baked into the SD image by
# scripts/configure-pi3-autologin.sh) mounts the pseudo-
# filesystems systemd would, then loops a passwordless root
# bash on ttyAMA1. User sees the prompt in ~10 s instead of
# 2-3 min of Pi OS systemd graph churning inside emulation.
'earlycon=pl011,mmio32,0x3f201000 keep_bootcon '
'console=ttyAMA1,115200 '
'root=/dev/mmcblk0p2 rootwait rw '
'dwc_otg.lpm_enable=0',
'dwc_otg.lpm_enable=0 '
'init=/usr/local/sbin/velxio-init',
]
logger.info('Launching QEMU for %s: %s', inst.client_id, ' '.join(cmd))