evidence · 6.1 KiB

cpu0-identity-physical-trial.md

Committed at docs/evidence/second-core/cpu0-identity-physical-trial.md. This is what grounds the requirements that cite it.

Open raw source

Physical CPU0 identity diagnostic and restoration

On 2026-09-27 UTC, the board operator used the exclusive /dev/ttyACM0 console to run the default-off SPL diagnostic described in cpu0-identity-trial.md. This was a physical M-mode identity measurement for the Linux SMP investigation, not a second Linux CPU or an AMP feature. The full serial captures are retained as protected host files at /tmp/k230-second-core-trial-boot.private and /tmp/k230-second-core-restored-boot.private; only selected, non-secret lines are reproduced here. The host capture file modification times after the respective boots were 2026-09-27T04:39:17Z and 2026-09-27T04:42:10Z. They are host file times, not board RTC readings.

Card and recovery bytes

Before writing, Linux identified /boot as /dev/mmcblk1p1 on whole card /dev/mmcblk1, model SD128, with 249872384 sectors of 512 bytes. The SPL slots were the 512 KiB regions at offsets 1 MiB and 1.5 MiB (sectors 2048 and 3072); partition 1 begins at sector 8192. The operator read each slot with dd if=/dev/mmcblk1 bs=524288 skip=2 (then skip=3), count=1, and verified each backup by a fresh byte comparison and a direct I/O SHA-256 readback. Both original slots were 524288 bytes and had SHA-256 25521b917baf3c62d03cb84fe283e47042ca88bde614695c13d4c860fed36241.

Independent copies were kept on board under /var/lib/k230/second-core-identity-20260927/slot-{a,b}.bin and off board under /tmp/k230-second-core-backup.private/slot-{a,b}.bin. Both host copies were verified as 524288 bytes with the same SHA-256; their exact bytes were not committed. The off-board transfer used gzip and base64 over the serial console, then verified the decoded bytes. The user confirmed an external microSD reader was available as a fallback, but no reader-based restoration was performed or claimed.

The diagnostic package was /nix/store/6y6v6vyg37r04jjj5057j8yfisxayf69-k230-stage1-packaging/fn_u-boot-spl.bin: 223412 bytes, SHA-256 a4c1ae6a038bb3e7326b375f15431c498db5c185dd192cdb4391bd3b265d1cc9. The operator transferred it to the board and verified that hash there. Padding it to one 524288-byte slot produced SHA-256 e1126e1e3f2da6fdcce4c8307668bda2832a812effdb9811476165366635b0e1. Only the two raw SPL slots were written, using dd bs=524288 seek=2/3 count=1 oflag=direct conv=notrunc,fsync; each direct readback matched that padded trial hash. U-Boot proper, environment, OpenSBI, DT, kernel, rootfs, and partition files were not written by this diagnostic.

Trial boot and normal restoration

The trial was rebooted and captured with:

python3 tools/capture-boot.py --dev /dev/ttyACM0 --out /tmp/k230-second-core-trial-boot.private --seconds 180 --kick --expect 'root@nixos' --send reboot --settle 0.30

Selected first-hand serial lines:

CPU0_SPL_IDENTITY mhartid=0x0 misa=0x800000000094112f
Platform HART Count       : 1
Boot HART ID              : 0
[    0.015717] smp: Brought up 1 node, 1 CPU
<<< Welcome to NixOS 26.11.20260919.20b1ddd (riscv64) - ttyS0 >>>

Linux then reached its root prompt. The normal installed system remained /nix/store/7hhr1fp722cq147svn5ni67ar1i66mys-nixos-system-nixos-26.11.20260919.20b1ddd; /sys/devices/system/cpu/online was 0, the four shell, shell-ui, shell-session-bus, and shell-notifications services were active, and systemctl --failed --no-legend --plain returned no units.

The operator then restored both original slots from the on-board backups with dd bs=524288 seek=2/3 count=1 oflag=direct conv=notrunc,fsync. Direct I/O readback of each slot again gave SHA-256 25521b917baf3c62d03cb84fe283e47042ca88bde614695c13d4c860fed36241. The restored reboot used the same capture command with output /tmp/k230-second-core-restored-boot.private and produced:

U-Boot SPL 2022.10 (Oct 03 2022 - 19:25:32 +0000)
Platform HART Count       : 1
Boot HART ID              : 0
[    0.015726] smp: Brought up 1 node, 1 CPU
<<< Welcome to NixOS 26.11.20260919.20b1ddd (riscv64) - ttyS0 >>>

The restored boot reached its root prompt with no CPU0_SPL_IDENTITY line. Afterward the same installed system path, CPU online mask 0, four active shell services, zero failed units, and both original slot SHA-256 values were checked again through the live console. The protected verification output is /tmp/k230-second-core-restored-verification.private.

The physical CPU0 SPL sampled CSR.MHARTID=0 and CSR.MISA=0x800000000094112f. The CPU1-side OpenSBI banner also derives its Boot HART ID : 0 directly from CSR.MHARTID: in the pinned OpenSBI 1.4 source, include/sbi/riscv_asm.h:166 defines current_hartid() as csr_read(CSR_MHARTID); lib/sbi/sbi_init.c:534 reads that value, :394 passes it to sbi_boot_print_hart(), and :169 prints the observed banner field. These line numbers use Canaan’s pinned opensbi-1.4-overlay for sbi_init.c; its overlay changes only an unrelated PMP banner line in this area. The physical CPU1 attribution follows the pinned stage-1 k230_img.c:276-285 release of CPU1 and park of CPU0, corroborated by the live 256 KiB L2/RVV CPU profile. Thus both executing physical cores report mhartid=0 on this board through separate first-hand boot outputs and the pinned source chain. CPU1 was not instrumented with a separate new marker, so its physical attribution is source-backed rather than a second independent physical-core label in the banner.

Duplicate CSR IDs rule out a DT-only second cpu@1 node with generic OpenSBI’s current hart-index/scratch/HSM handling. A safe virtual-ID scheme or other supported mapping, physical CPU0 interrupts/timers, shared cached-memory/atomic coherence, and Linux SMP operation remain unproved.

As a separate read-only observation on the restored image, perf was absent from PATH and /run/current-system/sw/bin/perf, while /proc/config.gz reported CONFIG_PERF_EVENTS=y, CONFIG_FRAME_POINTER=y, CONFIG_RISCV_PMU=y, and CONFIG_FTRACE=y. /sys/bus/event_source/devices listed cpu, kprobe, software, tracepoint, and uprobe. The protected raw output is /tmp/k230-second-core-perf-readonly.private; no sampling was run.