Skip to content

firmware flash: check the partition layout from the image itself, and say what differs - #35

Merged
bdbarnett merged 1 commit into
mainfrom
ptable-rom-check
Sep 22, 2026
Merged

bdbarnett merged 1 commit into
mainfrom
ptable-rom-check

Conversation

@bdbarnett

Copy link
Copy Markdown
Collaborator

Closes #32.

The hole was wider than reported

The issue says the layout check is skipped when flashing through the ROM
download port. It is also skipped on a perfectly healthy REPL port, for a
commoner reason: the expected table was only ever read from
<artifact dir>/partition_table/partition-table.bin, and that directory does
not exist beside a saved .bin. So every --artifact flash skipped the
check.
Measured against the real code before any change:

artifact: cmods/micropython/ports/esp32/firmware-s3-bounce.bin
  sibling partition-table.bin exists? False
  _esp32_layout_changed -> None    (None == check skipped)

artifact: .../build-ESP32_GENERIC_S3-SPIRAM_OCT/firmware.bin
  sibling partition-table.bin exists? True
  _esp32_layout_changed -> False   (check ran, layout matched)

That is the flash people reach for when something has already gone wrong.

What changed

Take the expected table from the image. A whole-flash image written at 0x0
carries its table at 0x8000 (magic AA 50), so the check works from the .bin
alone. The build directory's copy is still preferred when present.

Read the device's table in ROM download mode too. esptool was only asked
with --before default-reset, which is right for a board at a REPL and wrong
for one already in download mode, where toggling DTR/RTS can knock it back out.
It now tries no-reset as well.

Say what differs. Both tables are decoded and compared partition by
partition. "enable Erase if the board misbehaves" was the wrong advice for the
failure this exists to prevent — the T-Embed's files were intact 64 KB further
on and an erase would have destroyed them.

New mpftp firmware ptable <image> — prints an image's table, and diffs it
against --compare <other image> or --device <COM>.

Proof on hardware

A Waveshare ESP32-S3-Touch-LCD-4.3, and a copy of its own firmware with the
vfs entry moved to 0x390000 — the T-Embed's exact fault.

ptable --compare finds it without touching a board:

differences: ['vfs: offset 0x390000 on the device, 0x3a0000 in the image']

Refused on the REPL port (COM49) — the case that used to skip:

[mpftp] partition layout on the device differs from this firmware: vfs: offset 0x3a0000 on the device, 0x390000 in the image
"ok": false

Refused again through the ROM download port, which is what the issue asked
for. machine.bootloader() took COM73 (303A:4003) to COM13 (303A:1001),
and the flash there was refused with the same sentence.

And the control, because a checker that refuses everything proves nothing — the
unmodified image flashed through both ports in the same session:

[mpftp] partition layout matches (compared against firmware-s3-bounce.bin @ 0x8000)
Wrote 3469248 bytes (2121514 compressed) at 0x00000000 in 25.1 seconds
Hash of data verified.
"ok": true

The board came back out of ROM mode on its own (COM73 back at 303A:4003, REPL
alive, /lib intact) — no button, no replug.

Tests

13 new tests in cli/tests/test_partition_table.py, each planting the fault it
is meant to catch, plus an identical-tables control so the differ cannot pass
by always complaining. Full suite: 329 tests, OK.

Image under test: firmware-s3-bounce.bin, sha256
14e683fff2b2c50b37a4e425c55c3023dc56c9f24d920618238679e903f472cb.

… and say what differs

The layout check took the table it expects from the build directory's
partition_table/partition-table.bin, so it silently skipped itself whenever
that directory was not there -- which is every flash of a saved .bin with
--artifact, not just the ROM-download-port case the issue reported. That is
also the flash people reach for when something has already gone wrong.

A whole-flash image carries its own table at 0x8000, so take it from there when
the build directory is gone. Reading the device's table needed one more thing:
esptool was only ever asked with --before default-reset, which is right for a
board sitting at a REPL and wrong for one already in ROM download mode, where
toggling DTR/RTS can knock it back out. Try no-reset as well.

When the tables differ, decode both and name the partition, the field and the
two values instead of saying only that they differ. "Enable Erase if the board
misbehaves" was the wrong advice for the failure this exists to prevent: the
T-Embed's files were intact 64 KB further on, and an erase would have destroyed
them. Say what moved, and why flashing anyway leaves a filesystem where the new
table does not expect it -- the board then sits in inisetup.fs_corrupted()
before USB starts, with no panic and nothing on the bus.

Add mpftp firmware ptable <image>, which prints an image's table and diffs it
against another image or against an attached board. That is the command that
would have found the T-Embed's fault in seconds.

Proven on a Waveshare ESP32-S3-Touch-LCD-4.3, with a copy of its own firmware
whose vfs entry was moved to 0x390000. Refused on the REPL port and again
through the ROM download port after machine.bootloader() (COM73 at 303A:4003
re-enumerated as COM13 at 303A:1001), both times reporting "vfs: offset
0x3a0000 on the device, 0x390000 in the image". The unmodified image flashed
through both ports in the same session, reporting "partition layout matches",
so the check is not simply refusing everything.
@bdbarnett
bdbarnett merged commit 008156b into main Sep 22, 2026
3 checks passed
@bdbarnett
bdbarnett deleted the ptable-rom-check branch September 22, 2026 02:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

firmware flash skips its partition-layout check when flashing through the ROM download port — exactly when it is needed

1 participant