# ESP flash images REA reads a dump of an ESP32-family SPI flash, such as the output of `esptool read-flash 0 ALL dump.bin` or `esptool merge-bin`, through `inspect_artifact` and `extract_artifact`. The reader is static: no device, esptool or ESP-IDF is needed, and no code is run. The container format is `esp-flash-image`. Entries are the bootloader region, the partition table sector and one file per partition. The bootloader and each app partition are also decoded as [ESP images](esp-image.md), so their headers, segments, integrity and descriptors appear in the root `format_metadata`. Layout facts are cited to ESP-IDF v6.1 (`esp_flash_partitions.h`, `flash_partitions.c`, `gen_esp32part.py`, `bootloader_common_loader.c`, `bootloader_utility.c` and each chip's `esp_rom_caps.h`). ## Recognition A file is a flash image when REA finds a partition table in the entry structure ESP-IDF's bootloader verifies (`esp_partition_table_verify`): 32-byte `0x50AA` entries, at most one `0xEBEB` MD5 entry over the entries before it, and a terminating entry within `0xC00` bytes. ESP-IDF accepts a table with no partition entries, but REA requires one, so that neither erased flash nor a lone MD5 entry is read as a table. A table whose MD5 does not match, or that has a second MD5 entry, is still read, with `md5.status` `invalid` and a limitation, because the bootloader would refuse it. The table is located in this order: 1. at the caller's `partition_table_offset`, when given; no scan follows; 2. at the default `0x8000`; 3. by scanning every `0x1000`-aligned flash sector for a table whose MD5 verifies. This location is derived, and the inventory says so. A table never lies inside the located bootloader image, so the default offset and the scan are tried only after the image's last segment. Without a caller selection, the scan runs only when an ESP image sits at a ROM bootloader offset, and a single app or bootloader image ends at its last segment, so neither ordinary files nor single images are scanned. A C3 or S3 dump begins with its bootloader, so flash layouts are detected before a file is read as one ESP image. Unless the caller names the table with `partition_table_offset`, REA refuses two kinds of dump before looking for a table: - an image of a known chip at another chip's ROM offset, such as an ESP32 bootloader at the start of a dump read from `0x1000`. The dump's origin is not the flash address REA assumed, given or default, and a table found there would place every partition at the wrong file offset; pass the `flash_offset` where the dump starts. When a partition table sits where the image's own ROM offset puts `0x8000`, after the image's segments, the refusal names that offset. Without a selected format such a dump opens as its bootloader image, whose [ESP image](esp-image.md) facts say how to reopen it. - an ESP8266 image at a ROM offset. ESP8266 dumps can hold the same table format, and they keep the [ESP image](esp-image.md) reader's ESP8266 refusal. When no table is found the layout is not recognized. This is an unknown outcome, not a malformed file: flash encryption, which encrypts the bootloader and the table, is one cause. When a table is found without a located bootloader and `flash_offset` is omitted, a limitation says that each partition's file offset assumes the dump starts at flash `0x0`. ## Caller inputs | Input | Meaning | | ------------------------- | ----------------------------------------------------------------------------- | | `format: esp-flash-image` | Read the file as a flash dump; with no table found, refuse it | | `flash_offset` | Flash address (`0x…`) of the dump's first byte; default 0 | | `partition_table_offset` | Flash address (`0x…`, a multiple of `0x1000`) of the table; disables the scan | MCP takes these on `open_binary`; the CLI takes `--target-format esp-flash-image`, `--flash-offset` and `--partition-table-offset` on `inspect-artifact` and `extract-artifact`. The offsets require the format, and the format takes no `architecture` or `entry_point`. The inputs are part of the target's identity, so reopening the same bytes with other inputs reads them again instead of reusing the earlier reading. The `open_binary` summary reports them as `flash_offset` and `partition_table_offset`, null when omitted. ## Layout facts The root `format_metadata` (`esp-flash-image`) records: - `flash_offset`: its `value` and whether the `caller` gave it or it is the `default`; - `chip`: from the bootloader's `chip_id`, or null without a located bootloader; - `bootloader`: the region from the chip's ROM bootloader offset to the table, with its ESP image facts; - `partition_table`: its flash address, the `method` that found it (`default`, `caller` or `scan`), the partition count and the MD5 `status` (`valid`, `invalid` or `absent`) with the stored and computed digests; - `apps`: ESP image facts for each app partition the dump holds; app partitions declared over the same bytes share one decode; - `otadata`: the otadata partition's records, or null without one; - `boot_selection`: the app the bootloader would select, for every table; - `partitions_outside_dump`: declared partitions that begin before the dump's first byte, which have no entry; - `undescribed`: ranges outside every region, each from a byte that is not erased flash to the end of its gap. The ROM loads the bootloader from `ESP_ROM_BOOTLOADER_OFFSET_FLASH`: `0x1000` for ESP32 and ESP32-S2; `0x0` for ESP32-S3, C2, C3, C6, C61, H2 and H21; and `0x2000` for ESP32-C5, H4, P4 and S31. A bootloader is located only where its own `chip_id` says the ROM loads it. ### Partitions Each partition entry is `partitions/