evidence · 11.6 KiB

mainline-serial-only-boot-boundary-2026-10-03.md

Committed at docs/research/mainline-serial-only-boot-boundary-2026-10-03.md. This is what grounds the requirements that cite it.

Open raw source

Serial-only observer: boot/output discrimination

Evidence class: exact installed source/config audit and coordinator-reported physical milestones. No implementation, build, board access or raw UART read was performed. Cause attribution and the next comparison are UNVERIFIED. Task 5b.5 remains open.

Worktree /home/jadams/tmp/k230-mainline-serial-only-boundary, branch audit/mainline-serial-only-boundary, base 33242719c08d38cf0758e8181088fd57c5dfcd6e; this note is the sole owned path. The coordinator owns hardware/builds. Cached start/handoff status scans run at idle priority with output outside the repository; slow scans do not hold this source deliverable.

Observation and source order

The coordinator reports that the reviewed serial-only controller passed its 32 host tests and full immutable preparation. Bundle 16cpjjiifxgwyb6bndhi39vfmlvcdw6h, system k1zjqdn4ks7b5dd7b3py6cavhf85g6j6 and kernel 9vdk79pa4pm38mlmbflkqh4i4sc9kha0 were unchanged from the dual-console READY trial. Only the reviewed volatile console=tty0 removal was applied. Serial console enabled; no systemd banner, observer frame, primary prompt, host input or restart followed. The bounded return wait ended with controller exit 2. The coordinator committed the serial-only failure packet as bb76750c; its private raw-log SHA256 is 3446fdaaa2e524d05026409d66a6744c60878b66bd86c51a2fbe11e3f4492d24 (47,035 bytes). The earlier dual-console packet has raw-log SHA256 7fefbf17759b9ea8accd808a3e6cb9fcdf92ad811cb730eba62118450ddd8427 (53,905 bytes). Operator reset recovery was pending at this audit checkpoint. This is a coordinator-reported failure, not a new observation by this auditor.

Safe final milestones were DRM registration at 2.548986, Goodix input registration at 2.810421, unused-clock cleanup at 2.811995, unused-power-domain cleanup at 2.812201, ALSA list at 2.812254 and no soundcards at 2.812261. There was no visible init-memory freeing or Run /init. Both private captures contained fbcon:/fb0 adoption strings and neither contained the stage-1 fbdev-skip message. Those strings narrow the earlier conditional fbcon limit; they do not prove an active tty0 write or a blocked framebuffer callback.

Exact source/config paths and pins are in the READY/write-boundary audit. All line references here were checked against that installed l0j3rf11… source and 7vxby0h… config, matching the same 9vdk79… kernel.

drivers/clk/clk.c:1588–1627 prints the cleanup marker before runtime-PM acquisition, prepare-lock acquisition and clock traversal. It is an entry marker. The later PM/ALSA late-initcall milestones show progression beyond that clock initcall; they do not identify one clock as responsible for a later stall. sound/last.c:10–29 prints the final observed ALSA lines and returns 0, as a late_initcall_sync. Do not equate its last printed line with a stuck ALSA callback or assume no later initcall ran.

The UART0 functional gate is critical (drivers/clk/clk-k230.c:903–914); the APB gate is also critical, as established in the UART audit. Earlier no-bypass five-clock minimal/blkid trials reached a shell, accepted UART commands and returned automatically. A universal static UART clock/IRQ/wiring failure does not fit that evidence. Those trials used a different userspace/init path; they do not establish liveness of this observer run.

After initcalls, init/main.c:1675–1705 performs wait_for_initramfs(), console_on_rootfs(), init accessibility handling and integrity_load_keys(). Returning to kernel_init() is followed by async_synchronize_full(), init memory cleanup, read-only mapping work and init execution (init/main.c:1554–1595). The initramfs wait joins a dedicated async cookie domain (init/initramfs.c:770–798). This is a concrete set of unseen boundaries, not proof that any particular wait blocked. The same archive already reached READY in the earlier trial, so generic archive absence/corruption is not established by this failure.

Existing-image early console comparison

There is a source-supported way to alter printk delivery without changing the Image. A retained CON_BOOT console makes have_boot_console stay true; keep_bootcon prevents normal deregistration (kernel/printk/printk.c:3868–3878, 4212–4225). The kernel then does not start nbcon printer threads (printk.c:3827–3837), and normal flush policy uses the legacy path instead of nbcon offload/atomic selection (kernel/printk/internal.h:194–215). In the current path, UART work can be offloaded through irq_work to pr/ttyS0 (kernel/printk/nbcon.c:1311–1342, 1375–1398). Thus retaining a polling boot console is a concrete output-policy comparison, not a clock or RX fix.

Two explicit forms need separate qualification:

Do not substitute bare earlycon: this config enables ACPI_SPCR_TABLE, so the bare-parameter branch selects the ACPI SPCR path rather than the DT stdout path (drivers/tty/serial/earlycon.c:223–242). Do not add a baud to the explicit UART form: absent a qualified rate, its generic default clock could reprogram a wrong divisor. The early console is intentionally an additional kernel TX path; it is outside the observer helper’s getter-only contract.

keep_bootcon has a real tradeoff: the kernel explicitly notes that boot and regular console hardware registers cannot be synchronized (printk.c:3827–3832). It changes output scheduling and timing, may duplicate/interleave output, and retains a polling path that can itself block. It does not guarantee automatic recovery. Before any trial, require operator reset and the full protected normal postflight, unchanged selected artifacts, and a separately reviewed controller allowlist for precisely one explicit earlycon form plus keep_bootcon on the serial-only argument set. Preserve all identity/control guards and printed exact arguments; never enable a permanent clock bypass or saveenv.

If this comparison reveals later kernel/init progress, it establishes dependence on this output/boot-console policy, with the timing perturbation qualified. It cannot identify a broken irq_work, UART interrupt, clock or renderer. Exact observer CRC/sequence parsing must not silently accept duplicated/interleaved records. Retained SBI and regular ttyS0 can print the same record twice on the shared UART. The existing strict parser may therefore reject this run even when output progresses. Preserve the current strict parser: retain a recovered failed/unknown diagnostic classification while recording raw fresh progress and separately qualifying any protected automatic return. Send zero receipts when duplicate readiness fails. Do not claim RX success. If actual duplicated output later makes collapse necessary, it requires a separately reviewed explicit mode, bounded maximum-two/source semantics and meaningful tests; no such acceptance change is proposed or implemented here. Raw wire provenance stays intact. Existing unknown-state behavior remains decisive. No receipt until the fresh READY/before/prompt gates; unknown output stops input and still requires the passive deadline/operator recovery. This plan is not a command to run now.

If existing boot arguments are insufficient

A finite optional diagnostic kernel patch can bracket the unseen boundaries: basic-setup exit; initramfs wait enter/exit; root-console open enter/exit; init-accessibility/namespace boundary; integrity-key work enter/exit; global async wait enter/exit; init-memory cleanup enter/exit; and init-exec entry. Use fixed public step names and no cmdline, pointer, label or address dump. Every marker can briefly call nbcon_cpu_emergency_enter(), pr_info() and nbcon_cpu_emergency_exit() to attempt direct UART atomic flushing (kernel/printk/nbcon.c:1709–1758, kernel/printk/internal.h:216–227). Use this as an alternative on the serial-only/no-boot-console baseline, rather than stacking it with keep_bootcon, which changes the emergency flush policy too. Never hold emergency state/preemption disabled across the bracketed blocking work. This separates selected task progress from normal nbcon-thread delivery more directly than another quiet retry, but still cannot guarantee output from a halted kernel or an unavailable UART. Ordinary log severity alone does not select nbcon emergency priority.

The marker helper and opt-in flag must survive free_initmem(); do not place them in __init/__initdata if used afterward. Disabled mode must be a no-op. A separate reviewed opt-in kernel/bundle and explicit host identity acceptance are required: current observer Image/base-kernel equality guards must not be bypassed. Host source/API/object proof and a root-owned full matching build precede any physical gate. No such patch/build was made here.

Unfiltered initcall_debug adds broad output without bracketing the waits after initcalls. Filtered bootconfig tracing is unavailable on this exact image because CONFIG_BOOT_CONFIG is unset, despite ftrace/tracepoints being enabled. The supported initramfs_async=0 knob changes where extraction is joined (init/initramfs.c:603–608, 789–798), but does not by itself distinguish lost printk delivery from an actual init wait; it is weaker than boundary evidence.

Validation: exact installed source/config reads and nl -ba citation checks; git diff --check/commit whitespace check. No claim of a kernel root cause, automatic observer recovery, usable root, panel frame or glass touch follows.