evidence · 4.0 KiB

README.md

Committed at docs/evidence/second-core/echo-physical-2026-10-12/README.md. This is what grounds the requirements that cite it.

Open raw source

Physical CPU0 echo/ping, 2026-10-12

Coprocessor task 3.3: requests written from the CPU1 U-Boot prompt into the slot page, answered by our payload on physical CPU0 (the small C908 core). Runbook: ../echo-runbook.md. Driver: tools/small-core-echo-session.py.

Evidence class: physical board, serial console transcripts (host clock). No camera, no Linux coexistence.

Authorization. The operator chose “Yes, go” on 2026-10-12 for releasing CPU0 on the normal card, and asked for “the second core bring up”. Spare-card and recovery rehearsal were waived on 2026-09-28 (quoted in the runbook).

Payload and card

Sessions

All ran under flock /tmp/k230-board.lock; each warm-rebooted Linux and stopped autoboot. U-Boot has no dcache command (help dcache and dcache both print Unknown command), so CPU1’s data cache could not be turned off.

TranscriptModeResult
dry-run-uboot.txtno releasepre-release checks PASS (filesize=e0, CRC32 7492e46f); Linux back
release-1-missed-uboot.txt--releaseU-Boot prompt not caught; nothing released; Linux back
release-2-no-evict-uboot.txt--releaseCPU0 ran: status line mhartid=0x0, misa=0x800000000094112f, magic 4f484345. 0/4 responses, served=0. Inconclusive per the runbook (no cache control): CPU1’s mw.l stores can stay in CPU1’s cache
release-3-evict-uboot.txt--release --evict4/4 responses correct, counters 4f484345 00000004 00000004; the tool reported FAIL only on the control line (see below)
release-4-evict-pass-uboot.txt--release --evictECHO VERDICT: PASS: 4/4, control rsp_seq 0, counters 4/4, prompt alive; Linux back

--evict runs crc32 0x10000000 0x2000000 (a read of 32 MiB of unrelated DRAM) after each request’s two mw.l and before every md.l, so CPU1’s caches write the request back and drop any stale copy of the slot page. That one change took the result from 0/4 to 4/4, which is the evidence that CPU1’s cache, not CPU0, held the requests in release 2.

Release 4, responses read once each after sleep 1 (host stamps):

trequestresponse lineread
26.28 sseq 1, 0x111111110x0700214000000001 11111112 eeeeeeee 00000001
31.34 sseq 2, 0xdeadbeef0x0700218000000002 deadbef0 21524110 00000002
36.41 sseq 3, 0xffffffff0x070021c000000003 00000000 00000000 00000003
41.48 sseq 4, 0x123456780x0700220000000004 12345679 edcba987 00000004

Each value is a function of a request written moments before and differs from every other line, so no stale or static content can match.

Negative control, corrected. The runbook said the never-requested line 5 (0x07002240) must read all zeros. The payload (small-core-echo.S) zeroes only each response line’s rsp_seq word at start, so the other three words are whatever DRAM held: releases 3 and 4 read 00000000 ffffffff 03bca868 ffffffff, release 2 00000000 00000002 00000000 00000000. “Not answered” is rsp_seq == 0, which holds in every run. The driver’s check was changed to that after release 3 and release 4 was run with it; the runbook is corrected to match.

Limits

CPU0 talks to CPU1’s U-Boot through DRAM with explicit cache maintenance on both sides, Linux not running. Not shown: a Linux-side mapping, reserved memory, interrupts or the TRM mailbox, CPU0 stop/restart, or latency (the heartbeat field stayed 0 within these ~25 s, consistent with the expensive per-poll l2cache.ciall; not measured).