Skip to content

No hardware rig verifies the PRG image after loading it — propose a post-load verify (blast-radius assessment of harness#231) #199

Description

@JC-000

Where this comes from

While building tests/rig_ip65_rrnet_hw.py (the first ip65 hardware rig) I measured a sporadic single-byte corruption in the harness's bulk machine:writemem POST path — filed as c64-test-harness#231. That prompted the obvious question: has any hardware result this project has produced been running silently corrupted code?

I checked, and I want the answer written down, including the part that says "no".

What I found

The measured defect does not touch any existing rig. Two separate reasons:

  1. Every UCI rig loads its PRG with client.run_prg(prg)POST /v1/runners:run_prg, a different endpoint from machine:writemem. My measurement says nothing about that path, in either direction.
  2. Every transport.write_memory() call in tools/uci/ is small: 64-byte trampoline slices (rig_https_bad_finished.py, rig_https_local.py), 32-byte host strings, 48-byte scalars and 1-4 byte sentinels (bench_ecdsa_u64e.py). All far under the 2,048 bytes the harness docstring says the POST form was verified at, and far under the ~2.7-3.2 kB offsets where I saw corruption.

But nothing verifies. No rig in tools/uci/ or tests/ reads the loaded image back and compares it to the file. So the class of fault is undetectable by our tooling, whatever transfer path it might arrive on. If a run_prg upload ever dropped or flipped a byte, the failure mode is:

a one-byte change inside 6502 code surfaces minutes or tens of minutes later as a crash, a hang, or a failed handshake — and gets attributed to the code under test.

That is this project's single most-recorded misdiagnosis shape (the …KEYS ENC1 RX screen with two unrelated causes, the "U64E firmware wedged" conclusions that were nothing of the kind, the NO_SOCKET ladder). It costs one read to exclude.

Proposal

Add a post-load verify to the rigs that load a PRG, along the lines of what tests/rig_ip65_rrnet_hw.py::load_prg_verified already does:

  • read the loaded span back and compare to the file, before the program is started or exercised;
  • report the first differing offset, not just "mismatch";
  • for images that reach $A000, verify only up to $9FFF and say so — the tail is BSS zero fill and a host read of it returns the BASIC ROM until the program banks it out (check_shadow_ram_readable in tools/ip65_hw_checks.py is the discriminator);
  • allow one retry, then fail rather than start a run on an image known to be wrong.

run_prg complicates this slightly: it loads and starts, so a verify would race the running program's own writes. Verifying the code/rodata span immediately after, or moving to a write-then-SYS load, are both options; that design choice is the substance of this issue.

Confidence

Honest limits: n=2 on one device (U64E, fw v3.15-78-g71480a9d) for the corruption itself, and zero observations of a corrupted run_prg load. I am not claiming any past result is wrong. I am claiming we could not tell, and that the check is cheap.

One result that is explicitly not affected, so nobody re-opens it: the issue #181 hardware validation never loaded a PRG at all — bench_ecdsa_u64e.py exited 4 at the REU preflight, before run_prg, and the master-vs-branch comparison was pure Python against live firmware responses. That result stands.

Out of scope for the RR-Net PR; filed separately on purpose.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions