Repository navigation
Protocol 0x05: partial or unaligned writes silently erase the rest of the touched page and report success #68
Description
Summary
On protocol 0x05 (flash 5V page-write) the firmware writes only the bytes it was given and then
commits the page. The device erases the whole physical page and programs only the loaded bytes, so
every byte of that page which was not part of the write is erased to 0xFF — in both
directions, before the start address as well as after the end. The write then reports
successful.
There is no read-modify-write anywhere on this path, and no warning.
This affects all 27 protocol-0x05 parts, including the validated ones (w29c020, w29c040,
sst39sf020, AE29F2008). It is independent of #67, which is about the page size being
wrong on 9 of them; this one bites even when the page size is right.
Bench evidence
Rig: W29C020 on a Leonardo, Rev 2.0-class shield, firmware 3.0.0b22, host 3.0.0b38.
Real page size 128 bytes — a part where the firmware's page size is correct.
Baseline — 256 bytes written as four distinct 64-byte quarters, read back clean:
bytes 0x000-0x03f 0x11 bytes 0x080-0x0bf 0x33
bytes 0x040-0x07f 0x22 bytes 0x0c0-0x0ff 0x44
Trailing loss — write w29c020 probe.bin -a 0x0 with a 64-byte file (first half of page 0):
bytes 0x000-0x03f 0x55 <- written
bytes 0x040-0x07f 0xff <- ERASED (was 0x22), not part of the write
bytes 0x080-0x0bf 0x33 <- intact, next physical page
bytes 0x0c0-0x0ff 0x44 <- intact
Leading loss — then write w29c020 probe2.bin -a 0x40 with a 64-byte file (second half of the
same page):
bytes 0x000-0x03f 0xff <- ERASED (was 0x55), BEFORE the write's start address
bytes 0x040-0x07f 0x66 <- written
Both writes printed Write to W29C020 successful. Damage is confined to the physical page
containing the written range, which also confirms the 128-byte page.
Impact
Any of these silently corrupts up to page_size - 1 neighbouring bytes:
firestarter write <chip> patch.bin -a <offset>with a file shorter than a page, or an offset
that is not page-aligned — the normal way to patch part of a ROM image.- Any write whose total length is not a whole multiple of the page size: the final partial page
loses its tail.
The dev test harness does not catch it because it writes a full-device, page-aligned region
for flash parts, so it never issues a partial page load. That is why #52, #48, #25 and #61 all
passed.
Suggested remedies
In rough order of preference:
- Read-modify-write on partial pages. Before committing a page that is only partly covered by
the payload, read the existing page content, merge the payload over it, and write the whole
page. This is what the device's page semantics require and it makes offset writes safe. - Refuse and explain. If read-modify-write is not wanted in firmware, have the host detect a
write whose start or end is not page-aligned on protocol0x05and refuse it with a message
naming the bytes at risk, behind an explicit override flag. - At minimum, stop reporting
successfulfor a write that has demonstrably erased data
outside the requested range.
Option 1 needs a real page size to be correct, which is #67.
Related
#62 ("Unable to erase AE29F2008") is the same family of behaviour seen from the other side:
FLAG_CAN_ERASE is deliberately cleared for protocol 0x05 because the page write auto-erases
per page, so erase correctly answers Not supported. That auto-erase is exactly the mechanism
documented here.
Activity
henols commentedon Sep 16, 2026
Scope correction on the four parts named above, measured against the shipped chip database
(
firestarter_app/firestarter/data/chip_database.json):SST39SF020is recorded asalgorithm: 6(PROTO_FLASH_NOR_UNLOCK), not protocol0x05.It is a sector-erase NOR part handled by a different firmware file (
flash_nor_unlock.cpp) andnever traverses
flash_5v_page.cpp, the file this defect lives in. It is therefore outside thisdefect's blast radius entirely -- the measurement is the part's own row in the shipped database:
SST SST39SF020,SST39SF020A alg=6 page_size=None raw=0 size=262144, againstW29C020/W29C040/AE29F2008, allalg=5.AE29F2008andW29C020are the same silicon under two names -- theirdatabase rows are identical on every field, including the chip id (
0xDA45).This is a scope correction on which parts this defect can reach, not a statement that it has been
fixed or released. Nothing here has shipped; the work referenced is on a milestone branch.
henols commentedon Sep 18, 2026
Fixed by refusing the write, not by adding a read-modify-write. A protocol
0x05write whose start address or payload length is not a whole multiple of the chip's page size is now rejected before any page cycle runs, with a message naming the page size, the start address and the length. Both sides check: the host refuses before it opens the port, and the firmware refuses again on the write command. Whole-page writes are unchanged, so patching part of a page now means supplying the whole page.The fix is carried by firmware
3.0.0b33and host3.0.0b48:Verified on a W29C020 on a Leonardo and by the firmware and host test suites. No other protocol
0x05part has been re-checked on hardware.