evidence · 11.3 KiB

boot-boundary-sbi-only-host-2026-10-03.md

Committed at docs/evidence/mainline-system-trial/boot-boundary-sbi-only-host-2026-10-03.md. This is what grounds the requirements that cite it.

Open raw source

Optional SBI-only diagnostic marker mode — host proof

2026-10-03 UTC. Branch mainline-boot-boundary-sbi-only, base 0d23bb890f891b69fb32d121bc3c4be08ad1d91c, worktree /home/jadams/tmp/k230-mainline-boot-boundary-sbi-only. This is source/native/API/object/evaluation proof only. Complete matching kernel/bundle build, actual SBI-only output, ordinary init/root/login, automatic return and deliberate glass touch remain UNVERIFIED. Normal recovery must be verified before any new physical trial. Task 5b.5 stays open. No board/UART/camera/full kernel build/staging was performed; protected normal boot files/profile were not changed.

Scope and observable limits

The previous four-record trial in docs/evidence/mainline-system-trial/boot-boundary-sbi-physical-2026-10-03/README.md reached all four direct points and original printk seq1–4, but no next marker or login. Both suspect original marker calls were passed; the last direct basic-after ECALL return remained unknown. The KUnit call is a no-op when disabled (include/kunit/test.h:402–408), and the actual initramfs wait is after the missing next marker. This does not establish a console deadlock, an initramfs-wait stall or a kernel/driver cause.

The separate kernelMainlineBootTraceSbiOnly directly layers one patch on /nix/store/5k23sa4pbcs651vssp6ybifnr5qc1g9g-linux-mainline-k230-boot-trace-src, the ORIGINAL boot-trace source, not the four outer-record layer. Exact env.src inspection verifies this order. Original init/main.c SHA-256: ce95e6b40b1cbdebff28f4f3434afb87a51e207cf4e7928588b820904e16520d. No twenty call sites, kernel operations or branches move. No original optional output or normal driver/kernel logging is changed.

Only exact runtime k230.boot_trace_sbi_only=1 selects the new helper path. An absent/invalid/bare/empty new flag retains the original diagnostic helper, including its printk/emergency path and 32-record cap. The original runtime k230.boot_trace=1 is still required. In selected direct mode there is no pr_info, nbcon emergency operation, formatting, polling, retry or fallback. Missing CONFIG_RISCV_SBI, unavailable runtime DBCN, null/unknown step, or invalid record length emits no diagnostic fallback.

The constant table contains exactly enter/exit records for basic setup, initcalls, initramfs wait, root console, init access, namespace, integrity keys, async wait, initmem/readonly and init exec. Example:

K230_BOOT_SBI_ONLY_V1 step=initramfs-wait-enter

Every public fixed record has leading/trailing CRLF in a 64-byte NUL-padded array with 64-byte alignment. The bounded lookup scans at most twenty known step names; strnlen bounds the record to its fixed field. Matched valid attempts increment the existing sequence counter before exactly one sbi_debug_console_write() call, with at most 32 attempts across all sites including exec fallbacks. Zero/partial/error returns still consume that attempt and never retry. Return count/error is deliberately discarded; there is no transmitted full-return or output-success claim.

The table, helper, enable state and counter have regular lifetimes; only option setup is __init. No VMAP_STACK formatting buffer or private text is used. On 4KiB pages every aligned <64-byte field is page-contained, even though the complete table spans pages. arch/riscv/kernel/sbi.c:591–617 uses vmalloc page conversion or kernel __pa, clamps page crossings, and makes one ECALL. asm/page.h:133–150 supplies kernel mapping conversion; sbi.c:691–694 establishes runtime DBCN availability. The one-call mode uses the API directly, not the zero-progress retry loop in earlycon-riscv-sbi.c:30–37.

A visible record proves an output point was reached, not that its ECALL returned. A later distinct record proves progress past earlier calls, not their return byte counts. sbi_ecall.c:27–46 includes trace hooks and an ECALL with no wall-clock deadline. Firmware or the shared physical UART can still block, drop or interleave output; missing/partial records remain unknown. Removing this diagnostic helper’s printk/emergency work changes flushing/preemption timing and is a discriminator, not a production fix. Ordinary driver and kernel logging remains active and can independently block. No reboot/hang-recovery guarantee is provided.

Narrow checks

The original installed dev headers/build config were copied privately from /nix/store/k9clwc0icv3xr6caplk2sp2s866875fj-linux-riscv64-unknown-linux-gnu-7.3.0-rc5-dev/lib/modules/7.3.0-rc5/build. The immutable original was not changed. Config SHA-256: c5c128ed8b9701f78a0b8bd4f18dacd0d2407ae90eda79a35bba2d9f5ffbeae7. It enables 64BIT/RISCV_SBI/VMAP_STACK/PREEMPTION/4KiB pages; KUNIT is disabled. A private external Kbuild directory contains the actual patched main.c and obj-y += main.o.

make -C /nix/store/5k23sa4pbcs651vssp6ybifnr5qc1g9g-linux-mainline-k230-boot-trace-src \
  O=/home/jadams/tmp/k230-boot-trace-sbi-only-object/build \
  M=/home/jadams/tmp/k230-boot-trace-sbi-only-object/module ARCH=riscv \
  CROSS_COMPILE=/nix/store/4j2mwxqjvnyr6da0925sp0bm4jaj5r5i-riscv64-unknown-linux-gnu-gcc-wrapper-15.3.0/bin/riscv64-unknown-linux-gnu- \
  W=1 main.o

Passed, actual ELF64 little-endian RISC-V relocatable object, no MODULE define or full kernel link/run. readelf -sW/-SW places the helper in .text.unlikely, state in .sbss, only setup in .init.text, and the 2560-byte table at .rodata offset 0x740 with section alignment 64. An actual ELF-byte inspection verifies all twenty record fields at 0x740 + 64 + 128*i, exactly matching public messages followed by NUL padding, aligned and <64 bytes/page-contained. Thus the real RISC-V ABI member offset/stride agrees with native layout, not merely an inferred struct layout. sbi_debug_console_write remains a final-link reference. Patched C SHA-256: b776bb9707168ed2a26e393bcdd45808e132e661f1083662640268d856f028b9. Object SHA-256: daea3dc299e9beb50f24cc758fcbfda4e3e1a5dc8f6588cdab46649b4e63042b.

Optional identities and evaluation

The new system inherits ORIGINAL serial-only ordinary trace parameters, replaces only the selected kernel/list, and adds exactly the new opt-in. There is no four-record flag, earlycon/keep_bootcon, clock bypass, observer unit or console registration. Uname remains 7.3.0-rc5. Evaluated params:

consoleblank=0 console=ttyS0,115200n8 root=fstab loglevel=4
lsm=landlock,yama,bpf loglevel=7 k230.boot_trace=1 k230.boot_trace_sbi_only=1

Evaluated derivations, not built outputs:

nix eval --offline --no-write-lock-file --json --impure --expr '
  let f = builtins.getFlake (toString /home/jadams/tmp/k230-mainline-boot-boundary-sbi-only);
      p = f.packages.x86_64-linux;
      c = f.nixosConfigurations.k230-mainline-boot-trace-sbi-only.config;
  in assert p.kernelMainlineBootTraceSbiOnly.drvPath == c.boot.kernelPackages.kernel.drvPath; {
    kernel = p.kernelMainlineBootTraceSbiOnly.drvPath;
    source = p.kernelMainlineBootTraceSbiOnly.src.drvPath;
    system = c.system.build.toplevel.drvPath;
    bundle = p.kernelMainlineBootTraceSbiOnlyTrialBootFiles.drvPath;
    params = c.boot.kernelParams;
    uname = c.boot.kernelPackages.kernel.version;
  }'
nix derivation show /nix/store/dy5gqz0nqydnay9w9wj6xhhp6hhywv3h-linux-mainline-k230-boot-trace-sbi-only-src.drv
nix eval --offline --no-write-lock-file --json --impure --expr '
  let old = builtins.getFlake "git+file:///home/jadams/tmp/k230-mainline-boot-boundary-sbi-only?rev=0d23bb890f891b69fb32d121bc3c4be08ad1d91c";
      new = builtins.getFlake (toString /home/jadams/tmp/k230-mainline-boot-boundary-sbi-only);
      names = [ "kernel" "kernelMainline" "kernelMainlineDrm"
        "kernelMainlineDrmTrialBootFiles" "kernelMainlineUartObserverBootFiles"
        "kernelMainlineBootTrace" "kernelMainlineBootTraceTrialBootFiles"
        "kernelMainlineBootTraceSbi" "kernelMainlineBootTraceSbiTrialBootFiles"
        "toplevel" "toplevel-mainline-console" "toplevel-mainline-drm-trial"
        "toplevel-mainline-uart-observer" "toplevel-mainline-boot-trace"
        "toplevel-mainline-boot-trace-sbi" ];
      paths = f: builtins.listToAttrs (map (name: {
        inherit name; value = f.packages.x86_64-linux.${name}.drvPath;
      }) names);
  in assert paths old == paths new; { before = paths old; after = paths new; }'

All evaluations/source-order checks passed. All fifteen existing identities are equal to base, including both original optional trace variants. Evaluation performed no realization/full kernel build. Strict OpenSpec/all 56 and whitespace checks passed. Cached work-status ran at start/handoff; any slow pending handoff result is reported separately without holding the ready source commit.

Remaining operator gates

After review, the build owner runs nix build .#kernelMainlineBootTraceSbiOnlyTrialBootFiles --no-link --print-out-paths, inspects the exact bundle with tools/mainline-drm-trial-inspect.py, verifies matching source/Image/initrd/DT/config/sole init, and prepares a fresh exact manifest/normal report for the existing controller. No controller changes or artifact-identity guard bypasses are included.

Only after verified protected normal recovery and board/UART reservation: python3 tools/mainline-drm-system-trial.py begin --bundle <exact-built-bundle> --manifest <private-exact-manifest> --normal-report <private-normal-report> --state <private-state> --log <private-uart-log> --result <private-result>. The original three qualified ordinary-init controls and 180-second readiness bound stay in force. Preserve raw private evidence; unknown readiness sends no command or guessed reboot. Firmware call-return remains ambiguous at the last visible direct record; operator reset/power recovery may be necessary. No ordinary root, glass touch, unmasked production or automatic recovery claim follows from this host increment.