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
tools/test-small-core-coprocessor-echo.sh(on this branch, rebased onto5c3c5492) builtecho.bin: 224 bytes, SHA-2562ec68316e7d66a9380701c2011cd02c663ef945826afb30736c44b42017e46cc, CRC327492e46f, identical to the runbook.- Copied over SSH to the normal card’s
/boot/small-core-echo.bin; the board’ssha256summatched. - Board: installed system
kc3iyr4c…(the mainline splash default).
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.
| Transcript | Mode | Result |
|---|---|---|
dry-run-uboot.txt | no release | pre-release checks PASS (filesize=e0, CRC32 7492e46f); Linux back |
release-1-missed-uboot.txt | --release | U-Boot prompt not caught; nothing released; Linux back |
release-2-no-evict-uboot.txt | --release | CPU0 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 --evict | 4/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 --evict | ECHO 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):
| t | request | response line | read |
|---|---|---|---|
| 26.28 s | seq 1, 0x11111111 | 0x07002140 | 00000001 11111112 eeeeeeee 00000001 |
| 31.34 s | seq 2, 0xdeadbeef | 0x07002180 | 00000002 deadbef0 21524110 00000002 |
| 36.41 s | seq 3, 0xffffffff | 0x070021c0 | 00000003 00000000 00000000 00000003 |
| 41.48 s | seq 4, 0x12345678 | 0x07002200 | 00000004 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).