Repository navigation
fix: reads resume after a dropout, and verify contact after every chunk - #15
Merged
Merged
Conversation
Two problems, found by trying to take a real backup off a real chip.
1. A read that lost contact threw away everything it had correctly read. On the
bench the probe held for ~20s and the read needed ~4 minutes, so the attempt
died at 7% and 2.4MB of good data went in the bin. Those two numbers do not have
to meet. Each attempt now keeps its completed 64KB chunks in the output file and
records them in a sidecar, so re-running reads only what is missing and short
attempts add up to a whole dump. Without this a marginal probe yields no backup
at all - and no backup is what makes a reflash lose the board's MAC permanently,
since the MAC lives in flash and is not in the vendor image.
The sidecar is paranoid about staleness: chip id, total size and chunk stride
must all match or it is ignored and the read starts fresh. A resume that spliced
two different chips' bytes into one file would produce a corrupt backup that
looks perfect, which is the exact failure this subsystem exists to prevent. A
sidecar claiming progress with no partial file behind it is likewise rejected.
2. read_chunk_checked only re-checked the chip id when a chunk was ENTIRELY
0x00, which misses two real dropouts:
- a probe that drops MID-chunk leaves real data followed by dropout bytes. The
chunk is not uniform, so the all-zero test passes it and a corrupt chunk gets
marked done. The new resume test caught exactly this: contact dropped at
150000, inside chunk 2, and the resumed read skipped the corrupt chunk
forever.
- a probe whose MISO floats high leaves 0xFF, byte-for-byte identical to
erased flash. A lifted probe on this part reads ffffff. This was never
checked at all.
The chunk's bytes are not the evidence; the chip is. The id is now re-read after
EVERY chunk. Cost is one RDID per 64KB: ~350us per chunk, ~0.2s over a 32MB
dump, and it deletes a whole class of silently-corrupt dumps.
Test fake gained losing_contact_at(offset), which models the real signature:
reads past the offset return 0x00 AND the chip stops answering RDID.
Two existing tests updated, both still asserting their original property:
read_range_streams_single_opcode now expects the deliberate liveness RDID frame
(READ is still issued exactly once per range, never re-addressed per KiB), and
verify_chip_exits_4byte_mode_after_completion needed filler that decodes as its
own chip id rather than a5a5a5.
528 tests pass; clippy -D warnings and fmt clean.
Goal: 020-soic-debug-identify-fix-ship
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Both problems found by trying to take a real backup off real silicon.
1. A read that lost contact threw away everything it had read
On the bench the probe held ~20s; the read needed ~4 minutes. The attempt died at 7% and 2.4MB of correctly-read data went in the bin.
Those two numbers do not have to meet. Each attempt now keeps its completed 64KB chunks in the output file and records them in a sidecar, so re-running reads only what is missing and short attempts add up to a whole dump.
This matters more than it looks: without it, a marginal probe yields no backup at all - and no backup is what makes a reflash lose the board's MAC permanently, since the MAC lives in flash and is not in the vendor image.
The sidecar is deliberately paranoid about staleness. Chip id, total size and chunk stride must all match or it is ignored and the read starts fresh. A resume that spliced two different chips' bytes into one file would produce a corrupt backup that looks perfect - the exact failure this subsystem exists to prevent. A sidecar claiming progress with no partial file behind it is rejected too.
2. The contact check missed two real dropouts
read_chunk_checkedonly re-read the chip id when a chunk was entirely0x00. That misses:0xFF, byte-for-byte identical to erased flash. A lifted probe on this part readsffffff. This was never checked at all.The chunk's bytes are not the evidence; the chip is. The id is now re-read after every chunk.
Cost: one RDID per 64KB - ~350us per chunk, ~0.2s over a 32MB dump. It deletes a whole class of silently-corrupt dumps for a fifth of a second.
Test fake
LoopbackFlash::losing_contact_at(offset)models the real signature: reads past the offset return0x00and the chip stops answering RDID.Tests
528 pass, 0 fail. Clippy
-D warningsand fmt clean.Two existing tests updated, both still asserting their original property:
read_range_streams_single_opcode- expects the deliberate liveness RDID frame; READ is still issued exactly once per range, never re-addressed per KiBverify_chip_exits_4byte_mode_after_completion- needed filler that decodes as its own chip id rather thana5a5a5