Files
fds-os/docs/init.md
T
2026-09-21 22:29:23 +08:00

9.4 KiB

M2: native s6 init and the ARM development VM

Documentation index · Rootfs build · Services

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 and the rootfs prerequisites. 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:

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 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:

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:

make vm

The same guest checks run, then the VM opens a temporary root shell on its serial console. Try:

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:

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, Cartridges and Desktop. 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 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 for its eventual hardware validation.

Upstream references: s6-linux-init, init generation, s6-rc initialization, and ext4 creation.