188 lines
9.4 KiB
Markdown
188 lines
9.4 KiB
Markdown
# M2: native s6 init and the ARM development VM
|
|
|
|
[Documentation index](README.md) · [Rootfs build](rootfs.md) · [Services](services.md)
|
|
|
|
M2 adds the system's real init path. The kernel enters the generated execline
|
|
launcher at `/sbin/init`; that immediately executes `s6-linux-init`, which prepares
|
|
`/run` and replaces itself with `s6-svscan`. The supervisor remains
|
|
PID 1. Bash is used for some stage-2 configuration tasks, as an ordinary child
|
|
process. No shell loop, systemd, runit, or BusyBox owns PID 1.
|
|
|
|
You can boot and inspect this system on the x86_64 workstation using a complete
|
|
ARM QEMU machine. This is a generic development VM, not a Raspberry Pi image.
|
|
It does not test Pi firmware, a cartridge boot path, or the physical monitor.
|
|
|
|
## Build and verify
|
|
|
|
First complete the [build-host setup](getting-started.md) and the
|
|
[rootfs prerequisites](rootfs.md#1-prepare-the-workstation). M2 additionally uses
|
|
the Arch `e2fsprogs` and `libarchive` packages to create an ext4 VM disk directly
|
|
from the tar, without mounting it or requiring root:
|
|
|
|
```sh
|
|
sudo pacman -S --needed e2fsprogs libarchive
|
|
make rootfs PROFILE=cli
|
|
make rootfs-test
|
|
make init-test
|
|
```
|
|
|
|
`make init-test` installs `qemu-system-aarch64` inside the project-local Void build
|
|
container when missing. Void packages its emulator with display, audio, and other
|
|
libraries, even though this test uses only a serial console. Those dependencies
|
|
stay in the build container; they do not become target packages or host services.
|
|
|
|
The test also downloads a signed generic ARM kernel, pinned by version and SHA-256
|
|
in `config/vm-test.conf`. Its AHCI, ext4, serial console and PCI drivers are built
|
|
in and devtmpfs is automounted by the kernel, so no test initramfs or replacement stage 0 is needed. The kernel package is
|
|
approximately 161 MB; only its boot files are extracted. Its module collection is
|
|
not installed into FDS. The separate [M4 boot test](boot.md) uses the actual
|
|
FDS Pi kernel and its initramfs-to-EROFS handoff.
|
|
|
|
The VM uses software CPU emulation, 1 GiB of RAM, two virtual CPUs, no network,
|
|
and no host USB, display, filesystem sharing, or block-device passthrough.
|
|
Its root filesystem is mounted read-only. QEMU discards any block changes in a
|
|
temporary disk overlay, preserving the generated test disk.
|
|
|
|
Successful output includes:
|
|
|
|
```text
|
|
FDS_M2_PID1: /usr/bin/s6-svscan
|
|
FDS_M2_FILESYSTEM: read-only root, writable tmpfs, root ownership and capabilities
|
|
FDS_M2_BOOT: getty, eudev and Dasung supervised without a monitor
|
|
FDS_M2_SERVICE: s6-rc start, echo, supervised restart, stop and start passed
|
|
FDS_M2_PASS
|
|
PASS: M2 ARM boot, native s6 PID 1, service control, and orderly power-off
|
|
```
|
|
|
|
The test must finish within 180 seconds. This is a failure deadline, not a boot
|
|
performance target. A panic, failed assertion, missing marker, timeout, or missing
|
|
power-off message makes the command fail. Retained logs explain the result.
|
|
|
|
## Open a real booted ARM shell
|
|
|
|
After `make init-test` succeeds:
|
|
|
|
```sh
|
|
make vm
|
|
```
|
|
|
|
The same guest checks run, then the VM opens a temporary root shell on its serial
|
|
console. Try:
|
|
|
|
```sh
|
|
readlink /proc/1/exe
|
|
findmnt /
|
|
findmnt /run
|
|
s6-rc -l /run/s6-rc -a list
|
|
s6-svstat /run/service/dasungd
|
|
dasungd status
|
|
```
|
|
|
|
The rootfs's ordinary getty still requires authentication and root remains locked.
|
|
The VM hook stops getty before opening its shell so they do not compete for the
|
|
serial console; `s6-svstat` therefore reports getty down during that shell session.
|
|
The password-free shell exists only in the disposable VM test overlay, when
|
|
`make vm` explicitly requests it. The checker and shell hook do not ship in the
|
|
normal rootfs archive. Type `exit` to request orderly VM power-off. Ctrl+C stops
|
|
the emulator immediately if the guest is stuck; it does not shut down your host.
|
|
|
|
The shell's `/run`, `/tmp`, `/var/tmp`, and `/var/log` writes disappear at power-off.
|
|
Changes to `/etc` or `/usr` fail because SYSTEM is read-only. Rebuild the rootfs
|
|
and rerun `make init-test` after changing packages or init configuration; `make vm`
|
|
otherwise boots the previous successful test disk.
|
|
|
|
## Control the test service
|
|
|
|
The `test-echo` service is an actual Unix-socket echo server, supervised by s6.
|
|
It is included in the service database but excluded from the normal boot bundle.
|
|
In the VM shell:
|
|
|
|
```sh
|
|
s6-rc -l /run/s6-rc -u change test-echo
|
|
s6-svstat -o up,ready,pid /run/service/test-echo
|
|
printf 'hello from ARM\n' | s6-ipcclient /run/fds-test/echo.sock s6-ioconnect -t 3000
|
|
s6-svc -wR -T 5000 -r /run/service/test-echo
|
|
s6-rc -l /run/s6-rc -d change test-echo
|
|
```
|
|
|
|
Its socket is root-only, under `/run/fds-test` with mode 0700. The server sends an
|
|
actual readiness notification when it is listening. The automated test checks
|
|
the reply, confirms the PID changes on restart, stops the service, and starts it
|
|
again. No arbitrary boot delay substitutes for readiness.
|
|
|
|
## What starts at boot
|
|
|
|
| Component | Role and dependencies |
|
|
| --- | --- |
|
|
| Native stage 1 | Consume the kernel-provided `/dev`, mount `/run`; start s6 supervision and the catch-all logger |
|
|
| `runtime-fs` | Mount proc, sysfs, devpts and volatile temporary/log filesystems |
|
|
| `hostname` | Apply the image's `/etc/hostname` |
|
|
| `console` | Create volatile login accounting files after runtime mounts |
|
|
| `getty` | Offer a login on `/dev/console`, after console and hostname setup |
|
|
| `eudevd` | Process device events; readiness requires a successful control request |
|
|
| `udev-trigger` | Request initial subsystem and device events after eudev readiness |
|
|
| `dasungd-runtime`, `dasungd-log`, `dasungd` | Prepare private state/log paths and supervise the base monitor controller |
|
|
|
|
Console startup does not depend on eudev enumeration, a monitor connection, the
|
|
network, or a cartridge scan. No global `udevadm settle` is used. The eudev package
|
|
has no native s6 notification, so `s6-notifyoncheck` performs a bounded check of
|
|
its control channel. It signals readiness only after a successful response.
|
|
|
|
Cartridge discovery, the FDS CLI, desktop activation and on-demand Ethernet were
|
|
added after the original M2 milestone. The current image includes their real
|
|
implementations; see [Services](services.md), [Cartridges](cartridges.md) and
|
|
[Desktop](desktop.md). This page focuses on the native init mechanism and its
|
|
generic test fixture. SSH remains outside the default boot bundle.
|
|
|
|
## Files and build-time work
|
|
|
|
| Location | Meaning |
|
|
| --- | --- |
|
|
| `packages/fds-init/` | Init skeleton, runtime mount/accounting helpers, and package template |
|
|
| `s6/source/` | Complete current service graph, split between init, Dasung and cartridge/desktop packages |
|
|
| `/etc/s6-linux-init/current/` | Generated native init environment and stage scripts in the image |
|
|
| `/etc/s6-rc/compiled/` | Compiled service database, produced during image construction |
|
|
| `/run/service/`, `/run/s6-rc/` | Writable supervision and live service state |
|
|
| `/run/uncaught-logs/` | Catch-all service log, also copied to the console |
|
|
| `/run/log/dasungd/` | Rotating monitor-controller log |
|
|
| `out/m2-vm-latest/serial.log` | Last successful full ARM boot test |
|
|
| `out/m2-vm-latest/rootfs.ext4` | Disposable test disk; not a Pi or SYSTEM cartridge image |
|
|
|
|
`s6-linux-init-maker` and `s6-rc-compile` run during the rootfs build under ARM
|
|
emulation. Boot only reads their output. The VM test preserves that exact compiled
|
|
database. Its only init hook runs the original stage-2 script to completion, then
|
|
runs the checker as a child process. Normal `out/rootfs-aarch64.tar` contains
|
|
neither the checker nor the development-shell hook.
|
|
|
|
The s6-generated template contains FIFOs. Archive validation permits them only
|
|
inside its `run-image` directory; those templates are copied into writable `/run`
|
|
at boot. Before entering `/sbin/init`, the kernel or later stage 0 must provide
|
|
a mounted devtmpfs at `/dev`. Stage 1 deliberately does not mount it twice.
|
|
Services never place their live FIFOs or status files on read-only SYSTEM.
|
|
|
|
M10 adds cartridge-aware preparation before s6-rc stops the remaining services.
|
|
Its native shutdown hook stays alive if DATA cannot be verified and unmounted.
|
|
`s6-linux-init-shutdownd` still performs final process cleanup and the kernel
|
|
power action. See [Shutdown and reboot](power.md) for usage, blocked-request
|
|
recovery, and the current M10 acceptance status.
|
|
|
|
## Troubleshooting
|
|
|
|
- **`make vm` asks you to run `make init-test`:** no successful VM disk has been
|
|
published yet. Build the rootfs, then run the test.
|
|
- **Kernel pin/hash failure:** do not substitute an unverified kernel. The exact
|
|
configured package must remain available or be deliberately updated and retested.
|
|
- **Disk creation reports missing tar support:** use an `e2fsprogs` build with
|
|
libarchive support and install `libarchive`. No loop mount or sudo fallback is used.
|
|
- **No guest success marker:** read `out/logs/init-checks.log` and the printed
|
|
`out/m2-vm.*` directory's `serial.log`. Failed test workspaces are retained.
|
|
- **Root login is denied on the ordinary getty:** this is expected with the locked
|
|
base accounts. Use the explicit development VM shell, not a default password.
|
|
- **Dasung says disconnected:** the VM intentionally has no physical monitor.
|
|
Use [Dasung integration](dasung.md) for its eventual hardware validation.
|
|
|
|
Upstream references: [s6-linux-init](https://skarnet.org/software/s6-linux-init/overview.html),
|
|
[init generation](https://skarnet.org/software/s6-linux-init/s6-linux-init-maker.html),
|
|
[s6-rc initialization](https://skarnet.org/software/s6-rc/s6-rc-init.html), and
|
|
[ext4 creation](https://man7.org/linux/man-pages/man8/mke2fs.8.html).
|