Observe ordinary initrd coldplug without stage2 login
Evidence class: read-only host inspection of the exact archived initrd and official systemd v261.2 source. No implementation, build, board or UART action. This is a proposed bounded diagnostic within mainline task 5b.5; its readiness, coldplug observations and recovery remain UNVERIFIED on the board.
Worktree /home/jadams/tmp/k230-mainline-initrd-debug-console, branch
audit/mainline-initrd-debug-console, base
01dcca4601428b0872a11b3a54417bd70a9f0f35. Own only this note; no board/build
reservation. Cached python3 tools/work-status.py start/handoff commands run
at idle priority.
Exact artifacts and recommended comparison
Use the same bundle
/nix/store/5yqilsfyj35jzrcqjjqilkr6sd47qlms-k230-mainline-drm-trial-boot-files,
system 9gdmsrh2igqla1qz0ll97czfw2x42icw-nixos-system-nixos-26.11.20260919.20b1ddd,
kernel 9vdk79pa4pm38mlmbflkqh4i4sc9kha0-linux-riscv64-unknown-linux-gnu-7.3.0-rc5.
The exact compressed initrd remains SHA-256
046c5b012a2b993caa1082926e9928c14bccc0fff456f20f8716c91d13f51842.
Require the separately reviewed single-partition blkid trial’s returned success
and protected normal return before this next comparison. The previous ordinary
failure and verified operator recovery are in the physical packet.
Retain the complete bundle arguments, sole selected init=, both consoles and
the three qualified controls from the ordinary-init plan.
Append exactly:
rd.systemd.unit=basic.target rd.systemd.debug_shell=ttyS0
Use only the existing volatile U-Boot argument path with exact printed-argument
comparison. No rdinit, clock-ignore, persistent environment/profile change or
new kernel/initrd build is required by the inspected artifacts. This keeps
ordinary systemd as PID1, runs its early coldplug transaction, and selects a
target before the root activation chain. It is a qualified initrd diagnostic,
not ordinary-root acceptance or a fix for the prior timeout.
Why these controls are supported
A read-only zstd -dc/newc walk confirmed the debug generator, debug-shell unit,
/bin/sh, systemctl, journalctl, timeout, readlink and udevadm are
archived. Units resolve to systemd
srwrq12f962d5prr382vvsq76nfvmm84-systemd-riscv64-unknown-linux-gnu-261.2’s
example/systemd/system directory. Its recorded source store path is absent
locally; implementation semantics below use official v261.2 tagged source,
while actual compiled unit substitutions were checked in the archive.
- PID1 selection, core/main.c:299–307
accepts
rd.systemd.unitin the initrd. The debug generator:170–191,230–278,372–394 parses initrd-prefixed options, adds the shell to the selected target’s Wants, and generates itsTTYPath=/dev/ttyS0override, clearing the default tty9 existence condition.rd.systemd.default_debug_tty=ttyS0alone does not enable the shell; the recommended single shell option supplies both choices. - Archived
debug-shell.serviceuses/bin/sh,DefaultDependencies=no,StandardInput=tty,TTYReset=yes,TTYVHangup=yesandRestart=always. It does not wait for sysinit/coldplug completion. Inheritable tty input preserves stdout inheritance in service.c:1033–1055, so this unit is an interactive terminal shell, not merely journal output. - Archived
basic.targetrequires sysinit. Its sysinit Wants containsystemd-udev-trigger.serviceandsystemd-udevd.service. Archivedinitrd.targetseparately wants the root/device/filesystem targets and requires closure lookup; switch-root requires NixOS activation. These root requirements are not attached to basic.target in this archive. The fstab generator:994–1025 connects/sysroottoinitrd-root-fs.target, rather thanlocal-fs.target. This static graph supports the proposed boundary; still require a live check that/sysrootis unmounted before accepting any diagnostic state.
Archived debug-shell unit SHA-256:
edc8fe166b94d3c9e76879662780679b6092944f88e9966a27a41f0aa2767a81;
basic target 7d97dda25769ba30dff93d7aa2818151d968c843281767b720b3eabf09563f0b;
sysinit target 4d7fdd6b1a2f15647d69d886519c7809ed3adc493e8bd5bb3f88d360dda965eb.
Console conflicts and readiness gates
The bundle includes console=ttyS0,115200n8. Debug-shell deliberately owns that
same reserved UART; ordinary kernel/status output can still interleave. Its
terminal reset restores software termios flags and flushes pending input;
terminal-util.c:906–975
does not change the baud selection. This is source behavior, not a physical
serial-readiness proof. Send no input during boot/terminal reset. Require a fresh
candidate boot banner, expected early-shell startup and a completed primary
shell prompt; reject continuation prompts, stale echoes and truncated frames.
Do not combine this with rd.systemd.break=pre-udev, pre-mount or
pre-switch-root: the archived breakpoint shells use StandardInput=tty-force
on the default console and can compete for the same UART. Pre-mount also waits
after basic, so it may never arrive if coldplug is the stopping point.
Debug-shell alone, without the basic target selection, could continue through
root activation/switch-root. Do not enable a second getty, exit the shell
(Restart=always), start/isolate initrd.target, or run prepare-root manually.
Emergency/password-console units are further possible contenders; their
activation is a failed comparison, not permission to answer a guessed prompt.
Before observations, a new controller must obtain a fresh nonce receipt and
independently verify: UID0; fresh private boot ID; expected kernel release;
/proc/1/exe resolves to the archived systemd binary; /etc/initrd-release
exists; the interactive shell PID equals debug-shell’s live ExecMainPID and
has PPID1; debug-shell is running with TTYPath=/dev/ttyS0; exact sole selected
init= and exactly the two diagnostic tokens with no rdinit/clock-ignore;
proc/sysfs/cgroup mounts are present; no /sysroot mount; root activation and
switch-root units are inactive and have no pending jobs. Recheck boot identity
and this boundary before recovery. Stage2 /run/booted-system and selected
root-profile checks cannot replace these guards because root is not activated.
One bounded snapshot sequence
The following are exact helper paths/arguments, to be individually fresh-framed
by a reviewed controller. Redirect detailed output into a proven unique private
volatile initramfs directory; print only fixed RC/guard/state summaries. Retain
raw logs privately. The initrd bin environment supplies the absolute paths;
candidate Python and ps are not required.
/bin/timeout --signal=TERM --kill-after=2s 5s /bin/systemctl --no-pager --plain --no-legend list-jobs
/bin/timeout --signal=TERM --kill-after=2s 5s /bin/systemctl --no-pager show systemd-udev-trigger.service systemd-udevd.service basic.target sysinit.target --property=Id,ActiveState,SubState,Result,ExecMainPID,ControlPID,ExecMainStatus,ControlGroup
/bin/timeout --signal=TERM --kill-after=2s 5s /bin/udevadm control --ping --timeout=3
/bin/timeout --signal=TERM --kill-after=2s 5s /bin/journalctl --no-pager --boot --lines=80 --output=short-monotonic --unit=systemd-udev-trigger.service --unit=systemd-udevd.service
For at most 16 PIDs obtained from the two verified udev units’ cgroups, read only
those cgroups’ cgroup.procs and those PIDs’ /proc/<pid>/comm, status and
wchan, validating numeric IDs and membership immediately. Keep only name,
state and wait-symbol fields; account for process disappearance. This can
identify a live trigger/worker and a sleeping or uninterruptible wait without
dumping command lines, addresses, environments or every process. A zero/unavailable
wchan is inconclusive. Do not read arbitrary registers or /proc/interrupts.
The tagged manager creates workers named (udev-worker) at
udev-manager.c:523.
The control parser:135–154
supports ping/timeout. Ping proves daemon responsiveness only; it is not settle
and does not prove that queued device processing completed.
Choose one overall observation deadline, e.g. 90 seconds from shell readiness, and a ten-second host marker deadline for each five-second child. Missing final markers, broken identity or terminal ownership, duplicate/truncated receipts or a blocked child mean unknown: no retries, Ctrl-C, follow-up snapshots or reboot input. TERM/KILL cannot guarantee return from a kernel D-state wait. Preserve evidence and require the proven operator-reset/protected-normal procedure. Known complete nonzero commands are diagnostic failures, not proof of a driver cause; end the sequence and recover only through a separately acknowledged healthy protocol.
With every guard still proven and /sysroot unmounted, one fresh acknowledged
/bin/reboot -ff uses the existing direct kernel-reboot path rather than starting
a potentially blocked unit-stop transaction. This systemd-PID1 diagnostic’s
automatic return is still unproved: require kernel restart, SPL, new protected
normal boot ID, exact profile/kernel/services and all eight hashes. Never claim
the host deadline itself guarantees recovery.
Supported logging alternative, separate comparison
Prefer quiet boot plus the bounded journal snapshot above. If shell readiness
fails, these supported initrd-only logging tokens are a separately qualified
passive alternative: rd.udev.log_level=debug,
rd.systemd.log_level=debug rd.systemd.log_target=console, and
rd.systemd.journald.forward_to_console=1 rd.systemd.journald.max_level_console=debug.
The udev parser:62–80,
common log parser:1288–1303
and journal parser:206–231
support those choices. Journal forwarding defaults to /dev/console; it can
perturb timing and flood/interleave UART output. It is not the first quiet-shell
proposal. rd.udev.log_target=console remains unsupported. Worker-count and
event-timeout controls would change execution behavior and are not part of this
first state observation.
Host validation: openspec validate the-board-runs-a-mainline-kernel --strict
and staged git diff --check. Implementation needs meaningful host tests for
exact argument selection, initrd versus stage2/PID1-shell guards, terminal/PID
ownership, snapshot bounds/private output, stale/interleaved/truncated receipts
and zero further input after unknown. Physical proof and 5b.5 remain open.