fix(read_flash): add flash size arg to enable reading past 2MB without stub

This commit is contained in:
Peter Dragun
2024-01-10 16:59:43 +01:00
committed by Radim Karniš
parent 8ce5ed3c2b
commit f1eb65f885
4 changed files with 88 additions and 42 deletions

View File

@@ -113,6 +113,11 @@ It is also possible to autodetect flash size by using ``ALL`` as size. The above
esptool.py -p PORT -b 460800 read_flash 0 ALL flash_contents.bin esptool.py -p PORT -b 460800 read_flash 0 ALL flash_contents.bin
.. note::
When using the ``read_flash`` command in combination with the ``--no-stub`` argument, it may be necessary to also set the ``--flash_size`` argument to ensure proper reading of the flash contents by the ROM.
.. note:: .. note::
If ``write_flash`` updated the boot image's :ref:`flash mode and flash size <flash-modes>` during flashing then these bytes may be different when read back. If ``write_flash`` updated the boot image's :ref:`flash mode and flash size <flash-modes>` during flashing then these bytes may be different when read back.

View File

@@ -217,7 +217,12 @@ def main(argv=None, esp=None):
default="0xFFFFFFFF", default="0xFFFFFFFF",
) )
def add_spi_flash_subparsers(parent, allow_keep, auto_detect): def add_spi_flash_subparsers(
parent: argparse.ArgumentParser,
allow_keep: bool,
auto_detect: bool,
size_only: bool = False,
):
"""Add common parser arguments for SPI flash properties""" """Add common parser arguments for SPI flash properties"""
extra_keep_args = ["keep"] if allow_keep else [] extra_keep_args = ["keep"] if allow_keep else []
@@ -234,33 +239,35 @@ def main(argv=None, esp=None):
extra_fs_message = "" extra_fs_message = ""
flash_sizes = [] flash_sizes = []
parent.add_argument( if not size_only:
"--flash_freq", parent.add_argument(
"-ff", "--flash_freq",
help="SPI Flash frequency", "-ff",
choices=extra_keep_args help="SPI Flash frequency",
+ [ choices=extra_keep_args
"80m", + [
"60m", "80m",
"48m", "60m",
"40m", "48m",
"30m", "40m",
"26m", "30m",
"24m", "26m",
"20m", "24m",
"16m", "20m",
"15m", "16m",
"12m", "15m",
], "12m",
default=os.environ.get("ESPTOOL_FF", "keep" if allow_keep else None), ],
) default=os.environ.get("ESPTOOL_FF", "keep" if allow_keep else None),
parent.add_argument( )
"--flash_mode", parent.add_argument(
"-fm", "--flash_mode",
help="SPI Flash mode", "-fm",
choices=extra_keep_args + ["qio", "qout", "dio", "dout"], help="SPI Flash mode",
default=os.environ.get("ESPTOOL_FM", "keep" if allow_keep else "qio"), choices=extra_keep_args + ["qio", "qout", "dio", "dout"],
) default=os.environ.get("ESPTOOL_FM", "keep" if allow_keep else "qio"),
)
parent.add_argument( parent.add_argument(
"--flash_size", "--flash_size",
"-fs", "-fs",
@@ -540,7 +547,9 @@ def main(argv=None, esp=None):
parser_read_flash = subparsers.add_parser( parser_read_flash = subparsers.add_parser(
"read_flash", help="Read SPI flash content" "read_flash", help="Read SPI flash content"
) )
add_spi_connection_arg(parser_read_flash) add_spi_flash_subparsers(
parser_read_flash, allow_keep=True, auto_detect=True, size_only=True
)
parser_read_flash.add_argument("address", help="Start address", type=arg_auto_int) parser_read_flash.add_argument("address", help="Start address", type=arg_auto_int)
parser_read_flash.add_argument( parser_read_flash.add_argument(
"size", "size",

View File

@@ -329,11 +329,17 @@ class ESP32ROM(ESPLoader):
data = b"" data = b""
while len(data) < length: while len(data) < length:
block_len = min(BLOCK_LEN, length - len(data)) block_len = min(BLOCK_LEN, length - len(data))
r = self.check_command( try:
"read flash block", r = self.check_command(
self.ESP_READ_FLASH_SLOW, "read flash block",
struct.pack("<II", offset + len(data), block_len), self.ESP_READ_FLASH_SLOW,
) struct.pack("<II", offset + len(data), block_len),
)
except FatalError:
print(
"Hint: Consider specifying flash size using '--flash_size' argument"
)
raise
if len(r) < block_len: if len(r) < block_len:
raise FatalError( raise FatalError(
"Expected %d byte block, got %d bytes. Serial errors?" "Expected %d byte block, got %d bytes. Serial errors?"

View File

@@ -251,6 +251,12 @@ class EsptoolTestCase:
dump_file.close() dump_file.close()
os.unlink(dump_file.name) os.unlink(dump_file.name)
def diff(self, readback, compare_to):
for rb_b, ct_b, offs in zip(readback, compare_to, range(len(readback))):
assert (
rb_b == ct_b
), f"First difference at offset {offs:#x} Expected {ct_b} got {rb_b}"
def verify_readback( def verify_readback(
self, offset, length, compare_to, is_bootloader=False, spi_connection=None self, offset, length, compare_to, is_bootloader=False, spi_connection=None
): ):
@@ -268,10 +274,7 @@ class EsptoolTestCase:
assert ct[0] == rb[0], "First bytes should be identical" assert ct[0] == rb[0], "First bytes should be identical"
rb = rb[8:] rb = rb[8:]
ct = ct[8:] ct = ct[8:]
for rb_b, ct_b, offs in zip(rb, ct, range(len(rb))): self.diff(rb, ct)
assert (
rb_b == ct_b
), f"First difference at offset {offs:#x} Expected {ct_b} got {rb_b}"
@pytest.mark.skipif(arg_chip != "esp32", reason="ESP32 only") @pytest.mark.skipif(arg_chip != "esp32", reason="ESP32 only")
@@ -735,6 +738,32 @@ class TestFlashSizes(EsptoolTestCase):
# header should be the same as in the .bin file # header should be the same as in the .bin file
self.verify_readback(offset, image_len, image) self.verify_readback(offset, image_len, image)
@pytest.mark.skipif(
arg_chip == "esp8266", reason="ESP8266 does not support read_flash_slow"
)
def test_read_nostub_high_offset(self):
offset = 0x300000
length = 1024
self.run_esptool(f"write_flash -fs detect {offset} images/one_kb.bin")
dump_file = tempfile.NamedTemporaryFile(delete=False)
# readback with no-stub and flash-size set
try:
self.run_esptool(
f"--no-stub read_flash -fs detect {offset} 1024 {dump_file.name}"
)
with open(dump_file.name, "rb") as f:
rb = f.read()
assert length == len(
rb
), f"read_flash length {length} offset {offset:#x} yielded {len(rb)} bytes!"
finally:
dump_file.close()
os.unlink(dump_file.name)
# compare files
with open("images/one_kb.bin", "rb") as f:
ct = f.read()
self.diff(rb, ct)
class TestFlashDetection(EsptoolTestCase): class TestFlashDetection(EsptoolTestCase):
@pytest.mark.quick_test @pytest.mark.quick_test
@@ -1337,10 +1366,7 @@ class TestMakeImage(EsptoolTestCase):
f"WARNING: Expected length {len(ct)} doesn't match comparison {len(rb)}" f"WARNING: Expected length {len(ct)} doesn't match comparison {len(rb)}"
) )
print(f"Readback {len(rb)} bytes") print(f"Readback {len(rb)} bytes")
for rb_b, ct_b, offs in zip(rb, ct, range(len(rb))): self.diff(rb, ct)
assert (
rb_b == ct_b
), f"First difference at offset {offs:#x} Expected {ct_b} got {rb_b}"
def test_make_image(self): def test_make_image(self):
output = self.run_esptool( output = self.run_esptool(