1# SPDX-FileCopyrightText: 2014-2022 Fredrik Ahlberg, Angus Gratton,
2# Espressif Systems (Shanghai) CO LTD, other contributors as noted.
3#
4# SPDX-License-Identifier: GPL-2.0-or-later
5
6import hashlib
7import io
8import os
9import struct
10import sys
11import time
12import zlib
13
14from .bin_image import ELFFile, ImageSegment, LoadFirmwareImage
15from .bin_image import (
16    ESP8266ROMFirmwareImage,
17    ESP8266V2FirmwareImage,
18    ESP8266V3FirmwareImage,
19)
20from .loader import (
21    DEFAULT_CONNECT_ATTEMPTS,
22    DEFAULT_TIMEOUT,
23    ERASE_WRITE_TIMEOUT_PER_MB,
24    ESPLoader,
25    timeout_per_mb,
26)
27from .targets import CHIP_DEFS, CHIP_LIST, ROM_LIST
28from .util import (
29    FatalError,
30    NotImplementedInROMError,
31    NotSupportedError,
32    UnsupportedCommandError,
33)
34from .util import (
35    div_roundup,
36    flash_size_bytes,
37    hexify,
38    pad_to,
39    print_overwrite,
40)
41
42DETECTED_FLASH_SIZES = {
43    0x12: "256KB",
44    0x13: "512KB",
45    0x14: "1MB",
46    0x15: "2MB",
47    0x16: "4MB",
48    0x17: "8MB",
49    0x18: "16MB",
50    0x19: "32MB",
51    0x1A: "64MB",
52    0x1B: "128MB",
53    0x1C: "256MB",
54    0x20: "64MB",
55    0x21: "128MB",
56    0x22: "256MB",
57    0x32: "256KB",
58    0x33: "512KB",
59    0x34: "1MB",
60    0x35: "2MB",
61    0x36: "4MB",
62    0x37: "8MB",
63    0x38: "16MB",
64    0x39: "32MB",
65    0x3A: "64MB",
66}
67
68FLASH_MODES = {"qio": 0, "qout": 1, "dio": 2, "dout": 3}
69
70
71def detect_chip(
72    port=ESPLoader.DEFAULT_PORT,
73    baud=ESPLoader.ESP_ROM_BAUD,
74    connect_mode="default_reset",
75    trace_enabled=False,
76    connect_attempts=DEFAULT_CONNECT_ATTEMPTS,
77):
78    """Use serial access to detect the chip type.
79
80    First, get_security_info command is sent to detect the ID of the chip
81    (supported only by ESP32-C3 and later, works even in the Secure Download Mode).
82    If this fails, we reconnect and fall-back to reading the magic number.
83    It's mapped at a specific ROM address and has a different value on each chip model.
84    This way we use one memory read and compare it to the magic number for each chip.
85
86    This routine automatically performs ESPLoader.connect() (passing
87    connect_mode parameter) as part of querying the chip.
88    """
89    inst = None
90    detect_port = ESPLoader(port, baud, trace_enabled=trace_enabled)
91    if detect_port.serial_port.startswith("rfc2217:"):
92        detect_port.USES_RFC2217 = True
93    detect_port.connect(connect_mode, connect_attempts, detecting=True)
94    try:
95        print("Detecting chip type...", end="")
96        chip_id = detect_port.get_chip_id()
97        for cls in [
98            n for n in ROM_LIST if n.CHIP_NAME not in ("ESP8266", "ESP32", "ESP32S2")
99        ]:
100            # cmd not supported on ESP8266 and ESP32 + ESP32-S2 doesn't return chip_id
101            if chip_id == cls.IMAGE_CHIP_ID:
102                inst = cls(detect_port._port, baud, trace_enabled=trace_enabled)
103                try:
104                    inst.read_reg(
105                        ESPLoader.CHIP_DETECT_MAGIC_REG_ADDR
106                    )  # Dummy read to check Secure Download mode
107                except UnsupportedCommandError:
108                    inst.secure_download_mode = True
109                inst._post_connect()
110    except (UnsupportedCommandError, struct.error, FatalError) as e:
111        # UnsupportedCommmanddError: ESP8266/ESP32 ROM
112        # struct.error: ESP32-S2
113        # FatalError: ESP8266/ESP32 STUB
114        print(" Unsupported detection protocol, switching and trying again...")
115        try:
116            # ESP32/ESP8266 are reset after an unsupported command, need to reconnect
117            # (not needed on ESP32-S2)
118            if not isinstance(e, struct.error):
119                detect_port.connect(
120                    connect_mode, connect_attempts, detecting=True, warnings=False
121                )
122            print("Detecting chip type...", end="")
123            sys.stdout.flush()
124            chip_magic_value = detect_port.read_reg(
125                ESPLoader.CHIP_DETECT_MAGIC_REG_ADDR
126            )
127
128            for cls in ROM_LIST:
129                if chip_magic_value in cls.CHIP_DETECT_MAGIC_VALUE:
130                    inst = cls(detect_port._port, baud, trace_enabled=trace_enabled)
131                    inst._post_connect()
132                    inst.check_chip_id()
133        except UnsupportedCommandError:
134            raise FatalError(
135                "Unsupported Command Error received. "
136                "Probably this means Secure Download Mode is enabled, "
137                "autodetection will not work. Need to manually specify the chip."
138            )
139    finally:
140        if inst is not None:
141            print(" %s" % inst.CHIP_NAME, end="")
142            if detect_port.sync_stub_detected:
143                inst = inst.STUB_CLASS(inst)
144                inst.sync_stub_detected = True
145            print("")  # end line
146            return inst
147    raise FatalError(
148        "Unexpected CHIP magic value 0x%08x. Failed to autodetect chip type."
149        % (chip_magic_value)
150    )
151
152
153# "Operation" commands, executable at command line. One function each
154#
155# Each function takes either two args (<ESPLoader instance>, <args>) or a single <args>
156# argument.
157
158
159def load_ram(esp, args):
160    image = LoadFirmwareImage(esp.CHIP_NAME, args.filename)
161
162    print("RAM boot...")
163    for seg in image.segments:
164        size = len(seg.data)
165        print("Downloading %d bytes at %08x..." % (size, seg.addr), end=" ")
166        sys.stdout.flush()
167        esp.mem_begin(
168            size, div_roundup(size, esp.ESP_RAM_BLOCK), esp.ESP_RAM_BLOCK, seg.addr
169        )
170
171        seq = 0
172        while len(seg.data) > 0:
173            esp.mem_block(seg.data[0 : esp.ESP_RAM_BLOCK], seq)
174            seg.data = seg.data[esp.ESP_RAM_BLOCK :]
175            seq += 1
176        print("done!")
177
178    print("All segments done, executing at %08x" % image.entrypoint)
179    esp.mem_finish(image.entrypoint)
180
181
182def read_mem(esp, args):
183    print("0x%08x = 0x%08x" % (args.address, esp.read_reg(args.address)))
184
185
186def write_mem(esp, args):
187    esp.write_reg(args.address, args.value, args.mask, 0)
188    print("Wrote %08x, mask %08x to %08x" % (args.value, args.mask, args.address))
189
190
191def dump_mem(esp, args):
192    with open(args.filename, "wb") as f:
193        for i in range(args.size // 4):
194            d = esp.read_reg(args.address + (i * 4))
195            f.write(struct.pack(b"<I", d))
196            if f.tell() % 1024 == 0:
197                print_overwrite(
198                    "%d bytes read... (%d %%)" % (f.tell(), f.tell() * 100 // args.size)
199                )
200            sys.stdout.flush()
201        print_overwrite("Read %d bytes" % f.tell(), last_line=True)
202    print("Done!")
203
204
205def detect_flash_size(esp, args):
206    if args.flash_size == "detect":
207        if esp.secure_download_mode:
208            raise FatalError(
209                "Detecting flash size is not supported in secure download mode. "
210                "Need to manually specify flash size."
211            )
212        flash_id = esp.flash_id()
213        size_id = flash_id >> 16
214        args.flash_size = DETECTED_FLASH_SIZES.get(size_id)
215        if args.flash_size is None:
216            print(
217                "Warning: Could not auto-detect Flash size (FlashID=0x%x, SizeID=0x%x),"
218                " defaulting to 4MB" % (flash_id, size_id)
219            )
220            args.flash_size = "4MB"
221        else:
222            print("Auto-detected Flash size:", args.flash_size)
223
224
225def _update_image_flash_params(esp, address, args, image):
226    """
227    Modify the flash mode & size bytes if this looks like an executable bootloader image
228    """
229    if len(image) < 8:
230        return image  # not long enough to be a bootloader image
231
232    # unpack the (potential) image header
233    magic, _, flash_mode, flash_size_freq = struct.unpack("BBBB", image[:4])
234    if address != esp.BOOTLOADER_FLASH_OFFSET:
235        return image  # not flashing bootloader offset, so don't modify this
236
237    if (args.flash_mode, args.flash_freq, args.flash_size) == ("keep",) * 3:
238        return image  # all settings are 'keep', not modifying anything
239
240    # easy check if this is an image: does it start with a magic byte?
241    if magic != esp.ESP_IMAGE_MAGIC:
242        print(
243            "Warning: Image file at 0x%x doesn't look like an image file, "
244            "so not changing any flash settings." % address
245        )
246        return image
247
248    # make sure this really is an image, and not just data that
249    # starts with esp.ESP_IMAGE_MAGIC (mostly a problem for encrypted
250    # images that happen to start with a magic byte
251    try:
252        test_image = esp.BOOTLOADER_IMAGE(io.BytesIO(image))
253        test_image.verify()
254    except Exception:
255        print(
256            "Warning: Image file at 0x%x is not a valid %s image, "
257            "so not changing any flash settings." % (address, esp.CHIP_NAME)
258        )
259        return image
260
261    # After the 8-byte header comes the extended header for chips others than ESP8266.
262    # The 15th byte of the extended header indicates if the image is protected by
263    # a SHA256 checksum. In that case we should not modify the header because
264    # the checksum check would fail.
265    sha_implies_keep = args.chip != "esp8266" and image[8 + 15] == 1
266
267    def print_keep_warning(arg_to_keep, arg_used):
268        print(
269            "Warning: Image file at {addr} is protected with a hash checksum, "
270            "so not changing the flash {arg} setting. "
271            "Use the --flash_{arg}=keep option instead of --flash_{arg}={arg_orig} "
272            "in order to remove this warning, or use the --dont-append-digest option "
273            "for the elf2image command in order to generate an image file "
274            "without a hash checksum".format(
275                addr=hex(address), arg=arg_to_keep, arg_orig=arg_used
276            )
277        )
278
279    if args.flash_mode != "keep":
280        new_flash_mode = FLASH_MODES[args.flash_mode]
281        if flash_mode != new_flash_mode and sha_implies_keep:
282            print_keep_warning("mode", args.flash_mode)
283        else:
284            flash_mode = new_flash_mode
285
286    flash_freq = flash_size_freq & 0x0F
287    if args.flash_freq != "keep":
288        new_flash_freq = esp.parse_flash_freq_arg(args.flash_freq)
289        if flash_freq != new_flash_freq and sha_implies_keep:
290            print_keep_warning("frequency", args.flash_freq)
291        else:
292            flash_freq = new_flash_freq
293
294    flash_size = flash_size_freq & 0xF0
295    if args.flash_size != "keep":
296        new_flash_size = esp.parse_flash_size_arg(args.flash_size)
297        if flash_size != new_flash_size and sha_implies_keep:
298            print_keep_warning("size", args.flash_size)
299        else:
300            flash_size = new_flash_size
301
302    flash_params = struct.pack(b"BB", flash_mode, flash_size + flash_freq)
303    if flash_params != image[2:4]:
304        print("Flash params set to 0x%04x" % struct.unpack(">H", flash_params))
305        image = image[0:2] + flash_params + image[4:]
306    return image
307
308
309def write_flash(esp, args):
310    # set args.compress based on default behaviour:
311    # -> if either --compress or --no-compress is set, honour that
312    # -> otherwise, set --compress unless --no-stub is set
313    if args.compress is None and not args.no_compress:
314        args.compress = not args.no_stub
315
316    if not args.force and esp.CHIP_NAME != "ESP8266" and not esp.secure_download_mode:
317        # Check if secure boot is active
318        if esp.get_secure_boot_enabled():
319            for address, _ in args.addr_filename:
320                if address < 0x8000:
321                    raise FatalError(
322                        "Secure Boot detected, writing to flash regions < 0x8000 "
323                        "is disabled to protect the bootloader. "
324                        "Use --force to override, "
325                        "please use with caution, otherwise it may brick your device!"
326                    )
327        # Check if chip_id and min_rev in image are valid for the target in use
328        for _, argfile in args.addr_filename:
329            try:
330                image = LoadFirmwareImage(esp.CHIP_NAME, argfile)
331            except (FatalError, struct.error, RuntimeError):
332                continue
333            finally:
334                argfile.seek(0)  # LoadFirmwareImage changes the file handle position
335            if image.chip_id != esp.IMAGE_CHIP_ID:
336                raise FatalError(
337                    f"{argfile.name} is not an {esp.CHIP_NAME} image. "
338                    "Use --force to flash anyway."
339                )
340
341            # this logic below decides which min_rev to use, min_rev or min/max_rev_full
342            if image.max_rev_full == 0:  # image does not have max/min_rev_full fields
343                use_rev_full_fields = False
344            elif image.max_rev_full == 65535:  # image has default value of max_rev_full
345                use_rev_full_fields = True
346                if (
347                    image.min_rev_full == 0 and image.min_rev != 0
348                ):  # min_rev_full is not set, min_rev is used
349                    use_rev_full_fields = False
350            else:  # max_rev_full set to a version
351                use_rev_full_fields = True
352
353            if use_rev_full_fields:
354                rev = esp.get_chip_revision()
355                if rev < image.min_rev_full or rev > image.max_rev_full:
356                    error_str = f"{argfile.name} requires chip revision in range "
357                    error_str += (
358                        f"[v{image.min_rev_full // 100}.{image.min_rev_full % 100} - "
359                    )
360                    if image.max_rev_full == 65535:
361                        error_str += "max rev not set] "
362                    else:
363                        error_str += (
364                            f"v{image.max_rev_full // 100}.{image.max_rev_full % 100}] "
365                        )
366                    error_str += f"(this chip is revision v{rev // 100}.{rev % 100})"
367                    raise FatalError(f"{error_str}. Use --force to flash anyway.")
368            else:
369                # In IDF, image.min_rev is set based on Kconfig option.
370                # For C3 chip, image.min_rev is the Minor revision
371                # while for the rest chips it is the Major revision.
372                if esp.CHIP_NAME == "ESP32-C3":
373                    rev = esp.get_minor_chip_version()
374                else:
375                    rev = esp.get_major_chip_version()
376                if rev < image.min_rev:
377                    raise FatalError(
378                        f"{argfile.name} requires chip revision "
379                        f"{image.min_rev} or higher (this chip is revision {rev}). "
380                        "Use --force to flash anyway."
381                    )
382
383    # In case we have encrypted files to write,
384    # we first do few sanity checks before actual flash
385    if args.encrypt or args.encrypt_files is not None:
386        do_write = True
387
388        if not esp.secure_download_mode:
389            if esp.get_encrypted_download_disabled():
390                raise FatalError(
391                    "This chip has encrypt functionality "
392                    "in UART download mode disabled. "
393                    "This is the Flash Encryption configuration for Production mode "
394                    "instead of Development mode."
395                )
396
397            crypt_cfg_efuse = esp.get_flash_crypt_config()
398
399            if crypt_cfg_efuse is not None and crypt_cfg_efuse != 0xF:
400                print("Unexpected FLASH_CRYPT_CONFIG value: 0x%x" % (crypt_cfg_efuse))
401                do_write = False
402
403            enc_key_valid = esp.is_flash_encryption_key_valid()
404
405            if not enc_key_valid:
406                print("Flash encryption key is not programmed")
407                do_write = False
408
409        # Determine which files list contain the ones to encrypt
410        files_to_encrypt = args.addr_filename if args.encrypt else args.encrypt_files
411
412        for address, argfile in files_to_encrypt:
413            if address % esp.FLASH_ENCRYPTED_WRITE_ALIGN:
414                print(
415                    "File %s address 0x%x is not %d byte aligned, can't flash encrypted"
416                    % (argfile.name, address, esp.FLASH_ENCRYPTED_WRITE_ALIGN)
417                )
418                do_write = False
419
420        if not do_write and not args.ignore_flash_encryption_efuse_setting:
421            raise FatalError(
422                "Can't perform encrypted flash write, "
423                "consult Flash Encryption documentation for more information"
424            )
425    else:
426        if not args.force and esp.CHIP_NAME != "ESP8266":
427            # ESP32 does not support `get_security_info()` and `secure_download_mode`
428            if (
429                esp.CHIP_NAME != "ESP32"
430                and esp.secure_download_mode
431                and bin(esp.get_security_info()["flash_crypt_cnt"]).count("1") & 1 != 0
432            ):
433                raise FatalError(
434                    "WARNING: Detected flash encryption and "
435                    "secure download mode enabled.\n"
436                    "Flashing plaintext binary may brick your device! "
437                    "Use --force to override the warning."
438                )
439
440            if (
441                not esp.secure_download_mode
442                and esp.get_encrypted_download_disabled()
443                and esp.get_flash_encryption_enabled()
444            ):
445                raise FatalError(
446                    "WARNING: Detected flash encryption enabled and "
447                    "download manual encrypt disabled.\n"
448                    "Flashing plaintext binary may brick your device! "
449                    "Use --force to override the warning."
450                )
451
452    # verify file sizes fit in flash
453    if args.flash_size != "keep":  # TODO: check this even with 'keep'
454        flash_end = flash_size_bytes(args.flash_size)
455        for address, argfile in args.addr_filename:
456            argfile.seek(0, os.SEEK_END)
457            if address + argfile.tell() > flash_end:
458                raise FatalError(
459                    "File %s (length %d) at offset %d "
460                    "will not fit in %d bytes of flash. "
461                    "Use --flash_size argument, or change flashing address."
462                    % (argfile.name, argfile.tell(), address, flash_end)
463                )
464            argfile.seek(0)
465
466    if args.erase_all:
467        erase_flash(esp, args)
468    else:
469        for address, argfile in args.addr_filename:
470            argfile.seek(0, os.SEEK_END)
471            write_end = address + argfile.tell()
472            argfile.seek(0)
473            bytes_over = address % esp.FLASH_SECTOR_SIZE
474            if bytes_over != 0:
475                print(
476                    "WARNING: Flash address {:#010x} is not aligned "
477                    "to a {:#x} byte flash sector. "
478                    "{:#x} bytes before this address will be erased.".format(
479                        address, esp.FLASH_SECTOR_SIZE, bytes_over
480                    )
481                )
482            # Print the address range of to-be-erased flash memory region
483            print(
484                "Flash will be erased from {:#010x} to {:#010x}...".format(
485                    address - bytes_over,
486                    div_roundup(write_end, esp.FLASH_SECTOR_SIZE)
487                    * esp.FLASH_SECTOR_SIZE
488                    - 1,
489                )
490            )
491
492    """ Create a list describing all the files we have to flash.
493    Each entry holds an "encrypt" flag marking whether the file needs encryption or not.
494    This list needs to be sorted.
495
496    First, append to each entry of our addr_filename list the flag args.encrypt
497    E.g., if addr_filename is [(0x1000, "partition.bin"), (0x8000, "bootloader")],
498    all_files will be [
499        (0x1000, "partition.bin", args.encrypt),
500        (0x8000, "bootloader", args.encrypt)
501        ],
502    where, of course, args.encrypt is either True or False
503    """
504    all_files = [
505        (offs, filename, args.encrypt) for (offs, filename) in args.addr_filename
506    ]
507
508    """
509    Now do the same with encrypt_files list, if defined.
510    In this case, the flag is True
511    """
512    if args.encrypt_files is not None:
513        encrypted_files_flag = [
514            (offs, filename, True) for (offs, filename) in args.encrypt_files
515        ]
516
517        # Concatenate both lists and sort them.
518        # As both list are already sorted, we could simply do a merge instead,
519        # but for the sake of simplicity and because the lists are very small,
520        # let's use sorted.
521        all_files = sorted(all_files + encrypted_files_flag, key=lambda x: x[0])
522
523    for address, argfile, encrypted in all_files:
524        compress = args.compress
525
526        # Check whether we can compress the current file before flashing
527        if compress and encrypted:
528            print("\nWARNING: - compress and encrypt options are mutually exclusive ")
529            print("Will flash %s uncompressed" % argfile.name)
530            compress = False
531
532        if args.no_stub:
533            print("Erasing flash...")
534        image = pad_to(
535            argfile.read(), esp.FLASH_ENCRYPTED_WRITE_ALIGN if encrypted else 4
536        )
537        if len(image) == 0:
538            print("WARNING: File %s is empty" % argfile.name)
539            continue
540        image = _update_image_flash_params(esp, address, args, image)
541        calcmd5 = hashlib.md5(image).hexdigest()
542        uncsize = len(image)
543        if compress:
544            uncimage = image
545            image = zlib.compress(uncimage, 9)
546            # Decompress the compressed binary a block at a time,
547            # to dynamically calculate the timeout based on the real write size
548            decompress = zlib.decompressobj()
549            blocks = esp.flash_defl_begin(uncsize, len(image), address)
550        else:
551            blocks = esp.flash_begin(uncsize, address, begin_rom_encrypted=encrypted)
552        argfile.seek(0)  # in case we need it again
553        seq = 0
554        bytes_sent = 0  # bytes sent on wire
555        bytes_written = 0  # bytes written to flash
556        t = time.time()
557
558        timeout = DEFAULT_TIMEOUT
559
560        while len(image) > 0:
561            print_overwrite(
562                "Writing at 0x%08x... (%d %%)"
563                % (address + bytes_written, 100 * (seq + 1) // blocks)
564            )
565            sys.stdout.flush()
566            block = image[0 : esp.FLASH_WRITE_SIZE]
567            if compress:
568                # feeding each compressed block into the decompressor lets us
569                # see block-by-block how much will be written
570                block_uncompressed = len(decompress.decompress(block))
571                bytes_written += block_uncompressed
572                block_timeout = max(
573                    DEFAULT_TIMEOUT,
574                    timeout_per_mb(ERASE_WRITE_TIMEOUT_PER_MB, block_uncompressed),
575                )
576                if not esp.IS_STUB:
577                    timeout = (
578                        block_timeout  # ROM code writes block to flash before ACKing
579                    )
580                esp.flash_defl_block(block, seq, timeout=timeout)
581                if esp.IS_STUB:
582                    # Stub ACKs when block is received,
583                    # then writes to flash while receiving the block after it
584                    timeout = block_timeout
585            else:
586                # Pad the last block
587                block = block + b"\xff" * (esp.FLASH_WRITE_SIZE - len(block))
588                if encrypted:
589                    esp.flash_encrypt_block(block, seq)
590                else:
591                    esp.flash_block(block, seq)
592                bytes_written += len(block)
593            bytes_sent += len(block)
594            image = image[esp.FLASH_WRITE_SIZE :]
595            seq += 1
596
597        if esp.IS_STUB:
598            # Stub only writes each block to flash after 'ack'ing the receive,
599            # so do a final dummy operation which will not be 'ack'ed
600            # until the last block has actually been written out to flash
601            esp.read_reg(ESPLoader.CHIP_DETECT_MAGIC_REG_ADDR, timeout=timeout)
602
603        t = time.time() - t
604        speed_msg = ""
605        if compress:
606            if t > 0.0:
607                speed_msg = " (effective %.1f kbit/s)" % (uncsize / t * 8 / 1000)
608            print_overwrite(
609                "Wrote %d bytes (%d compressed) at 0x%08x in %.1f seconds%s..."
610                % (uncsize, bytes_sent, address, t, speed_msg),
611                last_line=True,
612            )
613        else:
614            if t > 0.0:
615                speed_msg = " (%.1f kbit/s)" % (bytes_written / t * 8 / 1000)
616            print_overwrite(
617                "Wrote %d bytes at 0x%08x in %.1f seconds%s..."
618                % (bytes_written, address, t, speed_msg),
619                last_line=True,
620            )
621
622        if not encrypted and not esp.secure_download_mode:
623            try:
624                res = esp.flash_md5sum(address, uncsize)
625                if res != calcmd5:
626                    print("File  md5: %s" % calcmd5)
627                    print("Flash md5: %s" % res)
628                    print(
629                        "MD5 of 0xFF is %s"
630                        % (hashlib.md5(b"\xFF" * uncsize).hexdigest())
631                    )
632                    raise FatalError("MD5 of file does not match data in flash!")
633                else:
634                    print("Hash of data verified.")
635            except NotImplementedInROMError:
636                pass
637
638    print("\nLeaving...")
639
640    if esp.IS_STUB:
641        # skip sending flash_finish to ROM loader here,
642        # as it causes the loader to exit and run user code
643        esp.flash_begin(0, 0)
644
645        # Get the "encrypted" flag for the last file flashed
646        # Note: all_files list contains triplets like:
647        # (address: Integer, filename: String, encrypted: Boolean)
648        last_file_encrypted = all_files[-1][2]
649
650        # Check whether the last file flashed was compressed or not
651        if args.compress and not last_file_encrypted:
652            esp.flash_defl_finish(False)
653        else:
654            esp.flash_finish(False)
655
656    if args.verify:
657        print("Verifying just-written flash...")
658        print(
659            "(This option is deprecated, "
660            "flash contents are now always read back after flashing.)"
661        )
662        # If some encrypted files have been flashed,
663        # print a warning saying that we won't check them
664        if args.encrypt or args.encrypt_files is not None:
665            print("WARNING: - cannot verify encrypted files, they will be ignored")
666        # Call verify_flash function only if there is at least
667        # one non-encrypted file flashed
668        if not args.encrypt:
669            verify_flash(esp, args)
670
671
672def image_info(args):
673    def v2():
674        def get_key_from_value(dict, val):
675            """Get key from value in dictionary"""
676            for key, value in dict.items():
677                if value == val:
678                    return key
679            return None
680
681        print()
682        title = "{} image header".format(args.chip.upper())
683        print(title)
684        print("=" * len(title))
685        print("Image version: {}".format(image.version))
686        print(
687            "Entry point: {:#8x}".format(image.entrypoint)
688            if image.entrypoint != 0
689            else "Entry point not set"
690        )
691
692        print("Segments: {}".format(len(image.segments)))
693
694        # Flash size
695        flash_s_bits = image.flash_size_freq & 0xF0  # high four bits
696        flash_s = get_key_from_value(image.ROM_LOADER.FLASH_SIZES, flash_s_bits)
697        print(
698            "Flash size: {}".format(flash_s)
699            if flash_s is not None
700            else "WARNING: Invalid flash size ({:#02x})".format(flash_s_bits)
701        )
702
703        # Flash frequency
704        flash_fr_bits = image.flash_size_freq & 0x0F  # low four bits
705        flash_fr = get_key_from_value(image.ROM_LOADER.FLASH_FREQUENCY, flash_fr_bits)
706        print(
707            "Flash freq: {}".format(flash_fr)
708            if flash_fr is not None
709            else "WARNING: Invalid flash frequency ({:#02x})".format(flash_fr_bits)
710        )
711
712        # Flash mode
713        flash_mode = get_key_from_value(FLASH_MODES, image.flash_mode)
714        print(
715            "Flash mode: {}".format(flash_mode.upper())
716            if flash_mode is not None
717            else "WARNING: Invalid flash mode ({})".format(image.flash_mode)
718        )
719
720        # Extended header (ESP32 and later only)
721        if args.chip != "esp8266":
722            print()
723            title = "{} extended image header".format(args.chip.upper())
724            print(title)
725            print("=" * len(title))
726            print("WP pin: {:#02x}".format(image.wp_pin))
727            print(
728                "Flash pins drive settings: "
729                "clk_drv: {:#02x}, q_drv: {:#02x}, d_drv: {:#02x}, "
730                "cs0_drv: {:#02x}, hd_drv: {:#02x}, wp_drv: {:#02x}".format(
731                    image.clk_drv,
732                    image.q_drv,
733                    image.d_drv,
734                    image.cs_drv,
735                    image.hd_drv,
736                    image.wp_drv,
737                )
738            )
739            print("Chip ID: {}".format(image.chip_id))
740            print(
741                "Minimal chip revision: "
742                f"v{image.min_rev_full // 100}.{image.min_rev_full % 100}, "
743                f"(legacy min_rev = {image.min_rev})"
744            )
745            print(
746                "Maximal chip revision: "
747                f"v{image.max_rev_full // 100}.{image.max_rev_full % 100}"
748            )
749        print()
750
751        # Segments overview
752        title = "Segments information"
753        print(title)
754        print("=" * len(title))
755        headers_str = "{:>7}  {:>7}  {:>10}  {:>10}  {:10}"
756        print(
757            headers_str.format(
758                "Segment", "Length", "Load addr", "File offs", "Memory types"
759            )
760        )
761        print(
762            "{}  {}  {}  {}  {}".format("-" * 7, "-" * 7, "-" * 10, "-" * 10, "-" * 12)
763        )
764        format_str = "{:7}  {:#07x}  {:#010x}  {:#010x}  {}"
765        app_desc = None
766        for idx, seg in enumerate(image.segments, start=1):
767            segs = seg.get_memory_type(image)
768            seg_name = ", ".join(segs)
769            if "DROM" in segs:  # The DROM segment starts with the esp_app_desc_t struct
770                app_desc = seg.data[:256]
771            print(
772                format_str.format(idx, len(seg.data), seg.addr, seg.file_offs, seg_name)
773            )
774        print()
775
776        # Footer
777        title = f"{args.chip.upper()} image footer"
778        print(title)
779        print("=" * len(title))
780        calc_checksum = image.calculate_checksum()
781        print(
782            "Checksum: {:#02x} ({})".format(
783                image.checksum,
784                "valid"
785                if image.checksum == calc_checksum
786                else "invalid - calculated {:02x}".format(calc_checksum),
787            )
788        )
789        try:
790            digest_msg = "Not appended"
791            if image.append_digest:
792                is_valid = image.stored_digest == image.calc_digest
793                digest_msg = "{} ({})".format(
794                    hexify(image.calc_digest, uppercase=False),
795                    "valid" if is_valid else "invalid",
796                )
797                print("Validation hash: {}".format(digest_msg))
798        except AttributeError:
799            pass  # ESP8266 image has no append_digest field
800
801        if app_desc:
802            APP_DESC_STRUCT_FMT = "<II" + "8s" + "32s32s16s16s32s32s" + "80s"
803            (
804                magic_word,
805                secure_version,
806                reserv1,
807                version,
808                project_name,
809                time,
810                date,
811                idf_ver,
812                app_elf_sha256,
813                reserv2,
814            ) = struct.unpack(APP_DESC_STRUCT_FMT, app_desc)
815
816            if magic_word == 0xABCD5432:
817                print()
818                title = "Application information"
819                print(title)
820                print("=" * len(title))
821                print(f'Project name: {project_name.decode("utf-8")}')
822                print(f'App version: {version.decode("utf-8")}')
823                print(f'Compile time: {date.decode("utf-8")} {time.decode("utf-8")}')
824                print(f"ELF file SHA256: {hexify(app_elf_sha256, uppercase=False)}")
825                print(f'ESP-IDF: {idf_ver.decode("utf-8")}')
826                print(f"Secure version: {secure_version}")
827
828    with open(args.filename, "rb") as f:
829        # magic number
830        try:
831            common_header = f.read(8)
832            magic = common_header[0]
833        except IndexError:
834            raise FatalError("File is empty")
835        if magic not in [
836            ESPLoader.ESP_IMAGE_MAGIC,
837            ESP8266V2FirmwareImage.IMAGE_V2_MAGIC,
838        ]:
839            raise FatalError(
840                "This is not a valid image "
841                "(invalid magic number: {:#x})".format(magic)
842            )
843
844        if args.chip == "auto":
845            try:
846                extended_header = f.read(16)
847                # reserved fields, should all be zero
848                if int.from_bytes(extended_header[7:-1], "little") != 0:
849                    raise FatalError("Reserved fields not all zero")
850
851                # append_digest, either 0 or 1
852                if extended_header[-1] not in [0, 1]:
853                    raise FatalError("Append digest field not 0 or 1")
854
855                chip_id = int.from_bytes(extended_header[4:5], "little")
856                for rom in [n for n in ROM_LIST if n.CHIP_NAME != "ESP8266"]:
857                    if chip_id == rom.IMAGE_CHIP_ID:
858                        args.chip = rom.CHIP_NAME
859                        break
860                else:
861                    raise FatalError(f"Unknown image chip ID ({chip_id})")
862            except FatalError:
863                args.chip = "esp8266"
864
865            print(f"Detected image type: {args.chip.upper()}")
866
867    image = LoadFirmwareImage(args.chip, args.filename)
868
869    if args.version == "2":
870        v2()
871        return
872
873    print("Image version: {}".format(image.version))
874    print(
875        "Entry point: {:8x}".format(image.entrypoint)
876        if image.entrypoint != 0
877        else "Entry point not set"
878    )
879    print("{} segments".format(len(image.segments)))
880    print()
881    idx = 0
882    for seg in image.segments:
883        idx += 1
884        segs = seg.get_memory_type(image)
885        seg_name = ",".join(segs)
886        print("Segment {}: {} [{}]".format(idx, seg, seg_name))
887    calc_checksum = image.calculate_checksum()
888    print(
889        "Checksum: {:02x} ({})".format(
890            image.checksum,
891            "valid"
892            if image.checksum == calc_checksum
893            else "invalid - calculated {:02x}".format(calc_checksum),
894        )
895    )
896    try:
897        digest_msg = "Not appended"
898        if image.append_digest:
899            is_valid = image.stored_digest == image.calc_digest
900            digest_msg = "{} ({})".format(
901                hexify(image.calc_digest, uppercase=False),
902                "valid" if is_valid else "invalid",
903            )
904            print("Validation Hash: {}".format(digest_msg))
905    except AttributeError:
906        pass  # ESP8266 image has no append_digest field
907
908
909def make_image(args):
910    print("Creating {} image...".format(args.chip))
911    image = ESP8266ROMFirmwareImage()
912    if len(args.segfile) == 0:
913        raise FatalError("No segments specified")
914    if len(args.segfile) != len(args.segaddr):
915        raise FatalError(
916            "Number of specified files does not match number of specified addresses"
917        )
918    for seg, addr in zip(args.segfile, args.segaddr):
919        with open(seg, "rb") as f:
920            data = f.read()
921            image.segments.append(ImageSegment(addr, data))
922    image.entrypoint = args.entrypoint
923    image.save(args.output)
924    print("Successfully created {} image.".format(args.chip))
925
926
927def elf2image(args):
928    e = ELFFile(args.input)
929    if args.chip == "auto":  # Default to ESP8266 for backwards compatibility
930        args.chip = "esp8266"
931
932    print("Creating {} image...".format(args.chip))
933
934    if args.chip != "esp8266":
935        image = CHIP_DEFS[args.chip].BOOTLOADER_IMAGE()
936        if args.chip == "esp32" and args.secure_pad:
937            image.secure_pad = "1"
938        if args.secure_pad_v2:
939            image.secure_pad = "2"
940        image.min_rev = args.min_rev
941        image.min_rev_full = args.min_rev_full
942        image.max_rev_full = args.max_rev_full
943        image.append_digest = args.append_digest
944    elif args.version == "1":  # ESP8266
945        image = ESP8266ROMFirmwareImage()
946    elif args.version == "2":
947        image = ESP8266V2FirmwareImage()
948    else:
949        image = ESP8266V3FirmwareImage()
950    image.entrypoint = e.entrypoint
951    image.flash_mode = FLASH_MODES[args.flash_mode]
952
953    if args.flash_mmu_page_size:
954        image.set_mmu_page_size(flash_size_bytes(args.flash_mmu_page_size))
955
956    # ELFSection is a subclass of ImageSegment, so can use interchangeably
957    image.segments = e.segments if args.use_segments else e.sections
958    if args.pad_to_size:
959        image.pad_to_size = flash_size_bytes(args.pad_to_size)
960    image.flash_size_freq = image.ROM_LOADER.parse_flash_size_arg(args.flash_size)
961    image.flash_size_freq += image.ROM_LOADER.parse_flash_freq_arg(args.flash_freq)
962
963    if args.elf_sha256_offset:
964        image.elf_sha256 = e.sha256()
965        image.elf_sha256_offset = args.elf_sha256_offset
966
967    before = len(image.segments)
968    image.merge_adjacent_segments()
969    if len(image.segments) != before:
970        delta = before - len(image.segments)
971        print("Merged %d ELF section%s" % (delta, "s" if delta > 1 else ""))
972
973    image.verify()
974
975    if args.output is None:
976        args.output = image.default_output_name(args.input)
977    image.save(args.output)
978
979    print("Successfully created {} image.".format(args.chip))
980
981
982def read_mac(esp, args):
983    mac = esp.read_mac()
984
985    def print_mac(label, mac):
986        print("%s: %s" % (label, ":".join(map(lambda x: "%02x" % x, mac))))
987
988    print_mac("MAC", mac)
989
990
991def chip_id(esp, args):
992    try:
993        chipid = esp.chip_id()
994        print("Chip ID: 0x%08x" % chipid)
995    except NotSupportedError:
996        print("Warning: %s has no Chip ID. Reading MAC instead." % esp.CHIP_NAME)
997        read_mac(esp, args)
998
999
1000def erase_flash(esp, args):
1001    if not args.force and esp.CHIP_NAME != "ESP8266" and not esp.secure_download_mode:
1002        if esp.get_flash_encryption_enabled() or esp.get_secure_boot_enabled():
1003            raise FatalError(
1004                "Active security features detected, "
1005                "erasing flash is disabled as a safety measure. "
1006                "Use --force to override, "
1007                "please use with caution, otherwise it may brick your device!"
1008            )
1009    print("Erasing flash (this may take a while)...")
1010    t = time.time()
1011    esp.erase_flash()
1012    print("Chip erase completed successfully in %.1fs" % (time.time() - t))
1013
1014
1015def erase_region(esp, args):
1016    if not args.force and esp.CHIP_NAME != "ESP8266" and not esp.secure_download_mode:
1017        if esp.get_flash_encryption_enabled() or esp.get_secure_boot_enabled():
1018            raise FatalError(
1019                "Active security features detected, "
1020                "erasing flash is disabled as a safety measure. "
1021                "Use --force to override, "
1022                "please use with caution, otherwise it may brick your device!"
1023            )
1024    print("Erasing region (may be slow depending on size)...")
1025    t = time.time()
1026    esp.erase_region(args.address, args.size)
1027    print("Erase completed successfully in %.1f seconds." % (time.time() - t))
1028
1029
1030def run(esp, args):
1031    esp.run()
1032
1033
1034def flash_id(esp, args):
1035    flash_id = esp.flash_id()
1036    print("Manufacturer: %02x" % (flash_id & 0xFF))
1037    flid_lowbyte = (flash_id >> 16) & 0xFF
1038    print("Device: %02x%02x" % ((flash_id >> 8) & 0xFF, flid_lowbyte))
1039    print(
1040        "Detected flash size: %s" % (DETECTED_FLASH_SIZES.get(flid_lowbyte, "Unknown"))
1041    )
1042    flash_type = esp.flash_type()
1043    flash_type_dict = {0: "quad (4 data lines)", 1: "octal (8 data lines)"}
1044    flash_type_str = flash_type_dict.get(flash_type)
1045    if flash_type_str:
1046        print(f"Flash type set in eFuse: {flash_type_str}")
1047
1048
1049def read_flash(esp, args):
1050    if args.no_progress:
1051        flash_progress = None
1052    else:
1053
1054        def flash_progress(progress, length):
1055            msg = "%d (%d %%)" % (progress, progress * 100.0 / length)
1056            padding = "\b" * len(msg)
1057            if progress == length:
1058                padding = "\n"
1059            sys.stdout.write(msg + padding)
1060            sys.stdout.flush()
1061
1062    t = time.time()
1063    data = esp.read_flash(args.address, args.size, flash_progress)
1064    t = time.time() - t
1065    speed_msg = " ({:.1f} kbit/s)".format(len(data) / t * 8 / 1000) if t > 0.0 else ""
1066    print_overwrite(
1067        "Read {:d} bytes at {:#010x} in {:.1f} seconds{}...".format(
1068            len(data), args.address, t, speed_msg
1069        ),
1070        last_line=True,
1071    )
1072    with open(args.filename, "wb") as f:
1073        f.write(data)
1074
1075
1076def verify_flash(esp, args):
1077    differences = False
1078
1079    for address, argfile in args.addr_filename:
1080        image = pad_to(argfile.read(), 4)
1081        argfile.seek(0)  # rewind in case we need it again
1082
1083        image = _update_image_flash_params(esp, address, args, image)
1084
1085        image_size = len(image)
1086        print(
1087            "Verifying 0x%x (%d) bytes @ 0x%08x in flash against %s..."
1088            % (image_size, image_size, address, argfile.name)
1089        )
1090        # Try digest first, only read if there are differences.
1091        digest = esp.flash_md5sum(address, image_size)
1092        expected_digest = hashlib.md5(image).hexdigest()
1093        if digest == expected_digest:
1094            print("-- verify OK (digest matched)")
1095            continue
1096        else:
1097            differences = True
1098            if getattr(args, "diff", "no") != "yes":
1099                print("-- verify FAILED (digest mismatch)")
1100                continue
1101
1102        flash = esp.read_flash(address, image_size)
1103        assert flash != image
1104        diff = [i for i in range(image_size) if flash[i] != image[i]]
1105        print(
1106            "-- verify FAILED: %d differences, first @ 0x%08x"
1107            % (len(diff), address + diff[0])
1108        )
1109        for d in diff:
1110            flash_byte = flash[d]
1111            image_byte = image[d]
1112            print("   %08x %02x %02x" % (address + d, flash_byte, image_byte))
1113    if differences:
1114        raise FatalError("Verify failed.")
1115
1116
1117def read_flash_status(esp, args):
1118    print("Status value: 0x%04x" % esp.read_status(args.bytes))
1119
1120
1121def write_flash_status(esp, args):
1122    fmt = "0x%%0%dx" % (args.bytes * 2)
1123    args.value = args.value & ((1 << (args.bytes * 8)) - 1)
1124    print(("Initial flash status: " + fmt) % esp.read_status(args.bytes))
1125    print(("Setting flash status: " + fmt) % args.value)
1126    esp.write_status(args.value, args.bytes, args.non_volatile)
1127    print(("After flash status:   " + fmt) % esp.read_status(args.bytes))
1128
1129
1130def get_security_info(esp, args):
1131    si = esp.get_security_info()
1132    # TODO: better display
1133    print("Flags: {:#010x} ({})".format(si["flags"], bin(si["flags"])))
1134    print("Flash_Crypt_Cnt: {:#x}".format(si["flash_crypt_cnt"]))
1135    print("Key_Purposes: {}".format(si["key_purposes"]))
1136    if si["chip_id"] is not None and si["api_version"] is not None:
1137        print("Chip_ID: {}".format(si["chip_id"]))
1138        print("Api_Version: {}".format(si["api_version"]))
1139
1140
1141def merge_bin(args):
1142    try:
1143        chip_class = CHIP_DEFS[args.chip]
1144    except KeyError:
1145        msg = (
1146            "Please specify the chip argument"
1147            if args.chip == "auto"
1148            else "Invalid chip choice: '{}'".format(args.chip)
1149        )
1150        msg = msg + " (choose from {})".format(", ".join(CHIP_LIST))
1151        raise FatalError(msg)
1152
1153    # sort the files by offset.
1154    # The AddrFilenamePairAction has already checked for overlap
1155    input_files = sorted(args.addr_filename, key=lambda x: x[0])
1156    if not input_files:
1157        raise FatalError("No input files specified")
1158    first_addr = input_files[0][0]
1159    if first_addr < args.target_offset:
1160        raise FatalError(
1161            "Output file target offset is 0x%x. Input file offset 0x%x is before this."
1162            % (args.target_offset, first_addr)
1163        )
1164
1165    if args.format != "raw":
1166        raise FatalError(
1167            "This version of esptool only supports the 'raw' output format"
1168        )
1169
1170    with open(args.output, "wb") as of:
1171
1172        def pad_to(flash_offs):
1173            # account for output file offset if there is any
1174            of.write(b"\xFF" * (flash_offs - args.target_offset - of.tell()))
1175
1176        for addr, argfile in input_files:
1177            pad_to(addr)
1178            image = argfile.read()
1179            image = _update_image_flash_params(chip_class, addr, args, image)
1180            of.write(image)
1181        if args.fill_flash_size:
1182            pad_to(flash_size_bytes(args.fill_flash_size))
1183        print(
1184            "Wrote 0x%x bytes to file %s, ready to flash to offset 0x%x"
1185            % (of.tell(), args.output, args.target_offset)
1186        )
1187
1188
1189def version(args):
1190    from . import __version__
1191
1192    print(__version__)
1193