From 6232b2a50ad4f67344776e2987280fa53a5ee306 Mon Sep 17 00:00:00 2001 From: Marek Matej Date: Tue, 1 Jul 2025 13:37:42 +0200 Subject: [PATCH 1/3] tools: esptool_py: Update to latest version Bring the latest feature and fixes from the upstream. Signed-off-by: Marek Matej --- tools/esptool_py/CHANGELOG.md | 703 +- tools/esptool_py/CONTRIBUTING.rst | 60 +- tools/esptool_py/MANIFEST.in | 2 +- tools/esptool_py/README.md | 10 +- tools/esptool_py/ci/download_flasher_stubs.py | 34 +- .../docs/_static/esptool_versions.js | 9 +- tools/esptool_py/docs/conf_common.py | 17 +- .../advanced-topics/boot-mode-selection.rst | 52 +- .../firmware_image_ext_header_format.diag | 15 + .../diag/firmware_image_format.diag | 12 + .../diag/firmware_image_format_esp8266.diag | 11 + .../diag/firmware_image_header_format.diag | 12 + .../advanced-topics/firmware-image-format.rst | 49 +- .../en/advanced-topics/serial-protocol.rst | 60 +- .../en/advanced-topics/spi-flash-modes.rst | 22 +- tools/esptool_py/docs/en/conf.py | 3 +- .../docs/en/espefuse/adc-info-cmd.rst | 14 +- .../docs/en/espefuse/burn-bit-cmd.rst | 20 +- .../docs/en/espefuse/burn-block-data-cmd.rst | 16 +- .../docs/en/espefuse/burn-custom-mac-cmd.rst | 20 +- .../docs/en/espefuse/burn-efuse-cmd.rst | 16 +- .../docs/en/espefuse/burn-key-cmd.rst | 40 +- .../docs/en/espefuse/burn-key-digest-cmd.rst | 22 +- .../docs/en/espefuse/check-error-cmd.rst | 12 +- .../esptool_py/docs/en/espefuse/dump-cmd.rst | 29 +- .../docs/en/espefuse/get-custom-mac-cmd.rst | 10 +- .../docs/en/espefuse/inc/summary_ESP32-C2.rst | 2 +- .../docs/en/espefuse/inc/summary_ESP32-C3.rst | 2 +- .../docs/en/espefuse/inc/summary_ESP32-C5.rst | 198 + .../docs/en/espefuse/inc/summary_ESP32-C6.rst | 2 +- .../en/espefuse/inc/summary_ESP32-C61.rst | 161 + .../docs/en/espefuse/inc/summary_ESP32-H2.rst | 2 +- .../docs/en/espefuse/inc/summary_ESP32-P4.rst | 4 +- .../docs/en/espefuse/inc/summary_ESP32-S2.rst | 2 +- .../docs/en/espefuse/inc/summary_ESP32-S3.rst | 4 +- .../docs/en/espefuse/inc/summary_ESP32.rst | 2 +- tools/esptool_py/docs/en/espefuse/index.rst | 72 +- .../espefuse/read-write-protections-cmd.rst | 12 +- .../esptool_py/docs/en/espefuse/scripting.rst | 231 + .../en/espefuse/set-flash-voltage-cmd.rst | 36 +- .../docs/en/espefuse/summary-cmd.rst | 16 +- tools/esptool_py/docs/en/espsecure/index.rst | 20 +- .../docs/en/esptool/advanced-commands.rst | 107 +- .../docs/en/esptool/advanced-options.rst | 97 +- .../docs/en/esptool/basic-commands.rst | 131 +- .../docs/en/esptool/basic-options.rst | 25 +- .../docs/en/esptool/configuration-file.rst | 72 +- .../docs/en/esptool/diag/reset_sequence.svg | 1380 +++ .../docs/en/esptool/entering-bootloader.rst | 2 +- .../docs/en/esptool/flash-modes.rst | 40 +- .../docs/en/esptool/flasher-stub.rst | 10 +- .../docs/en/esptool/flashing-firmware.rst | 53 +- tools/esptool_py/docs/en/esptool/index.rst | 14 +- .../esptool_py/docs/en/esptool/scripting.rst | 351 +- tools/esptool_py/docs/en/index.rst | 48 +- tools/esptool_py/docs/en/installation.rst | 97 +- tools/esptool_py/docs/en/migration-guide.rst | 416 + .../docs/en/remote-serial-ports.rst | 66 + tools/esptool_py/docs/en/resources.rst | 8 +- tools/esptool_py/docs/en/troubleshooting.rst | 22 +- tools/esptool_py/docs/en/versions.rst | 24 +- tools/esptool_py/docs/requirements.txt | 1 - tools/esptool_py/esp_rfc2217_server.py | 2 +- .../esptool_py/esp_rfc2217_server/__init__.py | 38 +- .../esp_rfc2217_server/esp_port_manager.py | 8 +- tools/esptool_py/espefuse/__init__.py | 512 +- tools/esptool_py/espefuse/cli_util.py | 246 + .../esptool_py/espefuse/efuse/base_fields.py | 396 +- .../espefuse/efuse/base_operations.py | 1847 ++-- .../espefuse/efuse/csv_table_parser.py | 11 +- .../efuse/emulate_efuse_controller_base.py | 3 +- .../espefuse/efuse/esp32/__init__.py | 2 + .../efuse/esp32/emulate_efuse_controller.py | 11 +- .../esptool_py/espefuse/efuse/esp32/fields.py | 37 +- .../espefuse/efuse/esp32/operations.py | 620 +- .../espefuse/efuse/esp32c2/__init__.py | 2 + .../espefuse/efuse/esp32c2/fields.py | 56 +- .../espefuse/efuse/esp32c2/mem_definition.py | 3 - .../espefuse/efuse/esp32c2/operations.py | 575 +- .../espefuse/efuse/esp32c3/__init__.py | 2 + .../espefuse/efuse/esp32c3/fields.py | 64 +- .../espefuse/efuse/esp32c3/mem_definition.py | 4 - .../espefuse/efuse/esp32c3/operations.py | 640 +- .../espefuse/efuse/esp32c5/__init__.py | 2 + .../espefuse/efuse/esp32c5/fields.py | 127 +- .../espefuse/efuse/esp32c5/mem_definition.py | 42 +- .../espefuse/efuse/esp32c5/operations.py | 636 +- .../espefuse/efuse/esp32c5beta3/operations.py | 395 - .../espefuse/efuse/esp32c6/__init__.py | 2 + .../espefuse/efuse/esp32c6/fields.py | 59 +- .../espefuse/efuse/esp32c6/mem_definition.py | 4 - .../espefuse/efuse/esp32c6/operations.py | 654 +- .../espefuse/efuse/esp32c61/__init__.py | 2 + .../espefuse/efuse/esp32c61/fields.py | 68 +- .../espefuse/efuse/esp32c61/mem_definition.py | 7 +- .../espefuse/efuse/esp32c61/operations.py | 700 +- .../espefuse/efuse/esp32h2/__init__.py | 2 + .../espefuse/efuse/esp32h2/fields.py | 69 +- .../espefuse/efuse/esp32h2/mem_definition.py | 8 +- .../espefuse/efuse/esp32h2/operations.py | 684 +- .../{esp32c5beta3 => esp32h21}/__init__.py | 2 + .../emulate_efuse_controller.py | 8 +- .../{esp32h2beta1 => esp32h21}/fields.py | 90 +- .../mem_definition.py | 10 +- .../espefuse/efuse/esp32h21/operations.py | 313 + .../efuse/esp32h2beta1/mem_definition.py | 156 - .../espefuse/efuse/esp32h2beta1/operations.py | 407 - .../{esp32h2beta1 => esp32h4}/__init__.py | 2 + .../emulate_efuse_controller.py | 8 +- .../efuse/{esp32c5beta3 => esp32h4}/fields.py | 104 +- .../mem_definition.py | 40 +- .../espefuse/efuse/esp32h4/operations.py | 305 + .../espefuse/efuse/esp32p4/__init__.py | 2 + .../espefuse/efuse/esp32p4/fields.py | 82 +- .../espefuse/efuse/esp32p4/mem_definition.py | 18 +- .../espefuse/efuse/esp32p4/operations.py | 698 +- .../espefuse/efuse/esp32s2/__init__.py | 2 + .../espefuse/efuse/esp32s2/fields.py | 54 +- .../espefuse/efuse/esp32s2/mem_definition.py | 4 - .../espefuse/efuse/esp32s2/operations.py | 823 +- .../espefuse/efuse/esp32s3/__init__.py | 2 + .../espefuse/efuse/esp32s3/fields.py | 76 +- .../espefuse/efuse/esp32s3/mem_definition.py | 14 +- .../espefuse/efuse/esp32s3/operations.py | 827 +- .../espefuse/efuse/esp32s3beta2/__init__.py | 3 - .../esp32s3beta2/emulate_efuse_controller.py | 92 - .../espefuse/efuse/esp32s3beta2/fields.py | 489 -- .../espefuse/efuse/esp32s3beta2/operations.py | 521 -- .../espefuse/efuse/mem_definition_base.py | 27 +- tools/esptool_py/espefuse/efuse/util.py | 4 +- .../espefuse/efuse_defs/esp32c5.yaml | 225 +- .../espefuse/efuse_defs/esp32c61.yaml | 187 +- .../espefuse/efuse_defs/esp32h2.yaml | 13 +- .../{esp32c5beta3.yaml => esp32h21.yaml} | 150 +- .../efuse_defs/esp32h2_v0.0_v1.1.yaml | 3 + .../espefuse/efuse_defs/esp32h4.yaml | 92 + .../espefuse/efuse_defs/esp32p4.yaml | 72 +- .../espefuse/efuse_defs/esp32s3.yaml | 10 +- tools/esptool_py/espefuse/efuse_interface.py | 197 + tools/esptool_py/espsecure/__init__.py | 1604 ++-- .../espsecure/esp_hsm_sign/__init__.py | 85 +- .../espsecure/esp_hsm_sign/exceptions.py | 34 +- tools/esptool_py/esptool/__init__.py | 1992 ++--- tools/esptool_py/esptool/bin_image.py | 523 +- tools/esptool_py/esptool/cli_util.py | 428 + tools/esptool_py/esptool/cmds.py | 2541 ++++-- tools/esptool_py/esptool/config.py | 11 +- tools/esptool_py/esptool/loader.py | 820 +- tools/esptool_py/esptool/logger.py | 273 + tools/esptool_py/esptool/reset.py | 15 +- tools/esptool_py/esptool/targets/__init__.py | 14 +- tools/esptool_py/esptool/targets/esp32.py | 82 +- tools/esptool_py/esptool/targets/esp32c2.py | 48 +- tools/esptool_py/esptool/targets/esp32c3.py | 61 +- tools/esptool_py/esptool/targets/esp32c5.py | 113 +- .../esptool/targets/esp32c5beta3.py | 129 - tools/esptool_py/esptool/targets/esp32c6.py | 60 +- tools/esptool_py/esptool/targets/esp32c61.py | 41 +- .../esptool_py/esptool/targets/esp32c6beta.py | 27 - tools/esptool_py/esptool/targets/esp32h2.py | 47 +- tools/esptool_py/esptool/targets/esp32h21.py | 96 + .../esptool/targets/esp32h2beta1.py | 186 - .../esptool/targets/esp32h2beta2.py | 43 - tools/esptool_py/esptool/targets/esp32h4.py | 201 + tools/esptool_py/esptool/targets/esp32p4.py | 130 +- tools/esptool_py/esptool/targets/esp32s2.py | 109 +- tools/esptool_py/esptool/targets/esp32s3.py | 119 +- .../esptool/targets/esp32s3beta2.py | 37 - tools/esptool_py/esptool/targets/esp8266.py | 37 +- .../esptool/targets/stub_flasher/1/README.md | 2 +- .../esptool/targets/stub_flasher/1/esp32.json | 6 +- .../targets/stub_flasher/1/esp32c2.json | 6 +- .../targets/stub_flasher/1/esp32c3.json | 6 +- .../targets/stub_flasher/1/esp32c5.json | 6 +- .../targets/stub_flasher/1/esp32c5beta3.json | 8 - .../targets/stub_flasher/1/esp32c6.json | 6 +- .../targets/stub_flasher/1/esp32c61.json | 6 +- .../targets/stub_flasher/1/esp32c6beta.json | 8 - .../targets/stub_flasher/1/esp32h2.json | 6 +- .../targets/stub_flasher/1/esp32h2beta1.json | 8 - .../targets/stub_flasher/1/esp32h2beta2.json | 8 - .../targets/stub_flasher/1/esp32p4.json | 8 +- .../targets/stub_flasher/1/esp32s2.json | 6 +- .../targets/stub_flasher/1/esp32s3.json | 6 +- .../targets/stub_flasher/1/esp32s3beta2.json | 8 - .../targets/stub_flasher/2/LICENSE-APACHE | 402 +- .../targets/stub_flasher/2/LICENSE-MIT | 40 +- .../esptool/targets/stub_flasher/2/README.md | 2 +- .../esptool/targets/stub_flasher/2/esp32.json | 6 +- .../targets/stub_flasher/2/esp32c2.json | 6 +- .../targets/stub_flasher/2/esp32c3.json | 6 +- .../targets/stub_flasher/2/esp32c5.json | 5 + .../targets/stub_flasher/2/esp32c6.json | 6 +- .../targets/stub_flasher/2/esp32c61.json | 5 + .../targets/stub_flasher/2/esp32h2.json | 6 +- .../targets/stub_flasher/2/esp32p4.json | 5 + .../targets/stub_flasher/2/esp32s2.json | 6 +- .../targets/stub_flasher/2/esp32s3.json | 6 +- .../targets/stub_flasher/2/esp8266.json | 5 + .../targets/stub_flasher/stub_flasher_32.json | 8 - .../stub_flasher/stub_flasher_32c2.json | 8 - .../stub_flasher/stub_flasher_32c3.json | 8 - .../stub_flasher/stub_flasher_32c5beta3.json | 8 - .../stub_flasher/stub_flasher_32c6.json | 8 - .../stub_flasher/stub_flasher_32c6beta.json | 8 - .../stub_flasher/stub_flasher_32h2.json | 8 - .../stub_flasher/stub_flasher_32h2beta1.json | 8 - .../stub_flasher/stub_flasher_32h2beta2.json | 8 - .../stub_flasher/stub_flasher_32p4.json | 8 - .../stub_flasher/stub_flasher_32s2.json | 8 - .../stub_flasher/stub_flasher_32s3.json | 8 - .../stub_flasher/stub_flasher_32s3beta2.json | 8 - .../stub_flasher/stub_flasher_8266.json | 8 - tools/esptool_py/esptool/uf2_writer.py | 10 +- tools/esptool_py/esptool/util.py | 93 +- tools/esptool_py/flasher_stub/Makefile | 187 - tools/esptool_py/flasher_stub/README.md | 41 - .../esptool_py/flasher_stub/compare_stubs.py | 97 - .../flasher_stub/esptool_test_stub.py | 36 - tools/esptool_py/flasher_stub/include/miniz.h | 1342 --- .../flasher_stub/include/rom_functions.h | 356 - tools/esptool_py/flasher_stub/include/slip.h | 40 - .../flasher_stub/include/soc_support.h | 592 -- .../flasher_stub/include/stub_commands.h | 46 - .../flasher_stub/include/stub_flasher.h | 110 - .../esptool_py/flasher_stub/include/stub_io.h | 62 - .../flasher_stub/include/stub_write_flash.h | 30 - tools/esptool_py/flasher_stub/ld/rom_32.ld | 1782 ---- tools/esptool_py/flasher_stub/ld/rom_32c2.ld | 2960 ------- tools/esptool_py/flasher_stub/ld/rom_32c3.ld | 2200 ----- .../flasher_stub/ld/rom_32c5_beta_3.ld | 429 - tools/esptool_py/flasher_stub/ld/rom_32c6.ld | 487 -- .../flasher_stub/ld/rom_32c6_beta.ld | 1951 ----- tools/esptool_py/flasher_stub/ld/rom_32h2.ld | 428 - .../flasher_stub/ld/rom_32h2_beta_1.ld | 731 -- .../flasher_stub/ld/rom_32h2_beta_2.ld | 1714 ---- tools/esptool_py/flasher_stub/ld/rom_32p4.ld | 619 -- tools/esptool_py/flasher_stub/ld/rom_32s2.ld | 1064 --- tools/esptool_py/flasher_stub/ld/rom_32s3.ld | 2285 ----- .../flasher_stub/ld/rom_32s3_beta_2.ld | 2397 ------ tools/esptool_py/flasher_stub/ld/rom_8266.ld | 351 - tools/esptool_py/flasher_stub/ld/stub_32.ld | 29 - tools/esptool_py/flasher_stub/ld/stub_32c2.ld | 26 - tools/esptool_py/flasher_stub/ld/stub_32c3.ld | 26 - .../flasher_stub/ld/stub_32c5_beta_3.ld | 26 - tools/esptool_py/flasher_stub/ld/stub_32c6.ld | 26 - .../flasher_stub/ld/stub_32c6_beta.ld | 26 - tools/esptool_py/flasher_stub/ld/stub_32h2.ld | 26 - .../flasher_stub/ld/stub_32h2_beta_1.ld | 26 - .../flasher_stub/ld/stub_32h2_beta_2.ld | 26 - tools/esptool_py/flasher_stub/ld/stub_32p4.ld | 26 - tools/esptool_py/flasher_stub/ld/stub_32s2.ld | 26 - tools/esptool_py/flasher_stub/ld/stub_32s3.ld | 26 - .../flasher_stub/ld/stub_32s3_beta_2.ld | 26 - tools/esptool_py/flasher_stub/ld/stub_8266.ld | 32 - tools/esptool_py/flasher_stub/miniz.c | 7657 ----------------- .../flasher_stub/run_tests_with_stub.sh | 10 - tools/esptool_py/flasher_stub/slip.c | 94 - tools/esptool_py/flasher_stub/stub_commands.c | 279 - tools/esptool_py/flasher_stub/stub_flasher.c | 540 -- tools/esptool_py/flasher_stub/stub_io.c | 313 - .../flasher_stub/stub_write_flash.c | 480 -- tools/esptool_py/flasher_stub/wrap_stub.py | 90 - tools/esptool_py/pyproject.toml | 47 +- tools/esptool_py/setup.py | 15 +- tools/esptool_py/test/README.md | 4 +- tools/esptool_py/test/conftest.py | 9 + .../test/efuse_scripts/efuse_burn1.py | 18 - .../test/efuse_scripts/efuse_burn2.py | 18 - .../test/efuse_scripts/esp32/config1.json | 6 - .../test/efuse_scripts/esp32/config2.json | 8 - .../esp32/execute_efuse_script.py | 50 - .../esp32/execute_efuse_script2.py | 23 - .../test/efuse_scripts/esp32xx/config1.json | 6 - .../test/efuse_scripts/esp32xx/config2.json | 8 - .../esp32xx/execute_efuse_script.py | 64 - .../esp32xx/execute_efuse_script2.py | 30 - .../elf2image/esp32-app-cust-ver-info.elf | Bin 2911132 -> 0 bytes .../test/elf2image/esp32c6-appdesc.elf | Bin 0 -> 4984 bytes .../test/elf2image/esp32c6-appdesc/Makefile | 18 + .../esp32c6-appdesc/esp32c6-appdesc.ld | 16 + .../test/elf2image/esp32c6-appdesc/main.c | 45 + .../esp8266-nonossdkv20-at-v2.elf-0x00000.bin | Bin 0 -> 42096 bytes .../esp8266-nonossdkv20-at-v2.elf-0x01010.bin | Bin 0 -> 376732 bytes tools/esptool_py/test/images/efuse/256bit_3 | 1 + .../images/ram_helloworld/source/Makefile | 5 - ...ed_v2.bin => bootloader_signed_v2_rsa.bin} | Bin ...m => ecdsa256_secure_boot_signing_key.pem} | 0 ... => ecdsa256_secure_boot_signing_key2.pem} | 0 ...cdsa256_secure_boot_signing_key_pkcs8.pem} | 0 ...> ecdsa256_secure_boot_signing_pubkey.pem} | 0 ... ecdsa256_secure_boot_signing_pubkey2.pem} | 0 ...cdsa256_secure_boot_signing_pubkey_raw.bin | 1 + tools/esptool_py/test/test_espefuse.py | 963 ++- tools/esptool_py/test/test_espsecure.py | 675 +- tools/esptool_py/test/test_espsecure_hsm.py | 113 +- tools/esptool_py/test/test_esptool.py | 827 +- tools/esptool_py/test/test_esptool_sdm.py | 45 +- tools/esptool_py/test/test_image_info.py | 118 +- tools/esptool_py/test/test_imagegen.py | 251 +- tools/esptool_py/test/test_logger.py | 154 + tools/esptool_py/test/test_merge_bin.py | 36 +- tools/esptool_py/test/test_modules.py | 2 +- 303 files changed, 18841 insertions(+), 47311 deletions(-) create mode 100644 tools/esptool_py/docs/en/advanced-topics/diag/firmware_image_ext_header_format.diag create mode 100644 tools/esptool_py/docs/en/advanced-topics/diag/firmware_image_format.diag create mode 100644 tools/esptool_py/docs/en/advanced-topics/diag/firmware_image_format_esp8266.diag create mode 100644 tools/esptool_py/docs/en/advanced-topics/diag/firmware_image_header_format.diag create mode 100644 tools/esptool_py/docs/en/espefuse/inc/summary_ESP32-C5.rst create mode 100644 tools/esptool_py/docs/en/espefuse/inc/summary_ESP32-C61.rst create mode 100644 tools/esptool_py/docs/en/espefuse/scripting.rst create mode 100644 tools/esptool_py/docs/en/esptool/diag/reset_sequence.svg create mode 100644 tools/esptool_py/docs/en/migration-guide.rst create mode 100644 tools/esptool_py/docs/en/remote-serial-ports.rst delete mode 100644 tools/esptool_py/docs/requirements.txt mode change 100755 => 100644 tools/esptool_py/esp_rfc2217_server.py create mode 100644 tools/esptool_py/espefuse/cli_util.py delete mode 100644 tools/esptool_py/espefuse/efuse/esp32c5beta3/operations.py rename tools/esptool_py/espefuse/efuse/{esp32c5beta3 => esp32h21}/__init__.py (74%) rename tools/esptool_py/espefuse/efuse/{esp32c5beta3 => esp32h21}/emulate_efuse_controller.py (93%) rename tools/esptool_py/espefuse/efuse/{esp32h2beta1 => esp32h21}/fields.py (85%) rename tools/esptool_py/espefuse/efuse/{esp32c5beta3 => esp32h21}/mem_definition.py (96%) create mode 100644 tools/esptool_py/espefuse/efuse/esp32h21/operations.py delete mode 100644 tools/esptool_py/espefuse/efuse/esp32h2beta1/mem_definition.py delete mode 100644 tools/esptool_py/espefuse/efuse/esp32h2beta1/operations.py rename tools/esptool_py/espefuse/efuse/{esp32h2beta1 => esp32h4}/__init__.py (74%) rename tools/esptool_py/espefuse/efuse/{esp32h2beta1 => esp32h4}/emulate_efuse_controller.py (93%) rename tools/esptool_py/espefuse/efuse/{esp32c5beta3 => esp32h4}/fields.py (84%) rename tools/esptool_py/espefuse/efuse/{esp32s3beta2 => esp32h4}/mem_definition.py (83%) create mode 100644 tools/esptool_py/espefuse/efuse/esp32h4/operations.py delete mode 100644 tools/esptool_py/espefuse/efuse/esp32s3beta2/__init__.py delete mode 100644 tools/esptool_py/espefuse/efuse/esp32s3beta2/emulate_efuse_controller.py delete mode 100644 tools/esptool_py/espefuse/efuse/esp32s3beta2/fields.py delete mode 100644 tools/esptool_py/espefuse/efuse/esp32s3beta2/operations.py rename tools/esptool_py/espefuse/efuse_defs/{esp32c5beta3.yaml => esp32h21.yaml} (55%) create mode 100644 tools/esptool_py/espefuse/efuse_defs/esp32h2_v0.0_v1.1.yaml create mode 100644 tools/esptool_py/espefuse/efuse_defs/esp32h4.yaml create mode 100644 tools/esptool_py/espefuse/efuse_interface.py create mode 100644 tools/esptool_py/esptool/cli_util.py create mode 100644 tools/esptool_py/esptool/logger.py delete mode 100644 tools/esptool_py/esptool/targets/esp32c5beta3.py delete mode 100644 tools/esptool_py/esptool/targets/esp32c6beta.py create mode 100644 tools/esptool_py/esptool/targets/esp32h21.py delete mode 100644 tools/esptool_py/esptool/targets/esp32h2beta1.py delete mode 100644 tools/esptool_py/esptool/targets/esp32h2beta2.py create mode 100644 tools/esptool_py/esptool/targets/esp32h4.py delete mode 100644 tools/esptool_py/esptool/targets/esp32s3beta2.py delete mode 100644 tools/esptool_py/esptool/targets/stub_flasher/1/esp32c5beta3.json delete mode 100644 tools/esptool_py/esptool/targets/stub_flasher/1/esp32c6beta.json delete mode 100644 tools/esptool_py/esptool/targets/stub_flasher/1/esp32h2beta1.json delete mode 100644 tools/esptool_py/esptool/targets/stub_flasher/1/esp32h2beta2.json delete mode 100644 tools/esptool_py/esptool/targets/stub_flasher/1/esp32s3beta2.json create mode 100644 tools/esptool_py/esptool/targets/stub_flasher/2/esp32c5.json create mode 100644 tools/esptool_py/esptool/targets/stub_flasher/2/esp32c61.json create mode 100644 tools/esptool_py/esptool/targets/stub_flasher/2/esp32p4.json create mode 100644 tools/esptool_py/esptool/targets/stub_flasher/2/esp8266.json delete mode 100644 tools/esptool_py/esptool/targets/stub_flasher/stub_flasher_32.json delete mode 100644 tools/esptool_py/esptool/targets/stub_flasher/stub_flasher_32c2.json delete mode 100644 tools/esptool_py/esptool/targets/stub_flasher/stub_flasher_32c3.json delete mode 100644 tools/esptool_py/esptool/targets/stub_flasher/stub_flasher_32c5beta3.json delete mode 100644 tools/esptool_py/esptool/targets/stub_flasher/stub_flasher_32c6.json delete mode 100644 tools/esptool_py/esptool/targets/stub_flasher/stub_flasher_32c6beta.json delete mode 100644 tools/esptool_py/esptool/targets/stub_flasher/stub_flasher_32h2.json delete mode 100644 tools/esptool_py/esptool/targets/stub_flasher/stub_flasher_32h2beta1.json delete mode 100644 tools/esptool_py/esptool/targets/stub_flasher/stub_flasher_32h2beta2.json delete mode 100644 tools/esptool_py/esptool/targets/stub_flasher/stub_flasher_32p4.json delete mode 100644 tools/esptool_py/esptool/targets/stub_flasher/stub_flasher_32s2.json delete mode 100644 tools/esptool_py/esptool/targets/stub_flasher/stub_flasher_32s3.json delete mode 100644 tools/esptool_py/esptool/targets/stub_flasher/stub_flasher_32s3beta2.json delete mode 100644 tools/esptool_py/esptool/targets/stub_flasher/stub_flasher_8266.json delete mode 100644 tools/esptool_py/flasher_stub/Makefile delete mode 100644 tools/esptool_py/flasher_stub/README.md delete mode 100755 tools/esptool_py/flasher_stub/compare_stubs.py delete mode 100755 tools/esptool_py/flasher_stub/esptool_test_stub.py delete mode 100644 tools/esptool_py/flasher_stub/include/miniz.h delete mode 100644 tools/esptool_py/flasher_stub/include/rom_functions.h delete mode 100644 tools/esptool_py/flasher_stub/include/slip.h delete mode 100644 tools/esptool_py/flasher_stub/include/soc_support.h delete mode 100644 tools/esptool_py/flasher_stub/include/stub_commands.h delete mode 100644 tools/esptool_py/flasher_stub/include/stub_flasher.h delete mode 100644 tools/esptool_py/flasher_stub/include/stub_io.h delete mode 100644 tools/esptool_py/flasher_stub/include/stub_write_flash.h delete mode 100644 tools/esptool_py/flasher_stub/ld/rom_32.ld delete mode 100755 tools/esptool_py/flasher_stub/ld/rom_32c2.ld delete mode 100755 tools/esptool_py/flasher_stub/ld/rom_32c3.ld delete mode 100755 tools/esptool_py/flasher_stub/ld/rom_32c5_beta_3.ld delete mode 100755 tools/esptool_py/flasher_stub/ld/rom_32c6.ld delete mode 100755 tools/esptool_py/flasher_stub/ld/rom_32c6_beta.ld delete mode 100755 tools/esptool_py/flasher_stub/ld/rom_32h2.ld delete mode 100644 tools/esptool_py/flasher_stub/ld/rom_32h2_beta_1.ld delete mode 100644 tools/esptool_py/flasher_stub/ld/rom_32h2_beta_2.ld delete mode 100644 tools/esptool_py/flasher_stub/ld/rom_32p4.ld delete mode 100755 tools/esptool_py/flasher_stub/ld/rom_32s2.ld delete mode 100644 tools/esptool_py/flasher_stub/ld/rom_32s3.ld delete mode 100644 tools/esptool_py/flasher_stub/ld/rom_32s3_beta_2.ld delete mode 100644 tools/esptool_py/flasher_stub/ld/rom_8266.ld delete mode 100644 tools/esptool_py/flasher_stub/ld/stub_32.ld delete mode 100644 tools/esptool_py/flasher_stub/ld/stub_32c2.ld delete mode 100644 tools/esptool_py/flasher_stub/ld/stub_32c3.ld delete mode 100644 tools/esptool_py/flasher_stub/ld/stub_32c5_beta_3.ld delete mode 100644 tools/esptool_py/flasher_stub/ld/stub_32c6.ld delete mode 100644 tools/esptool_py/flasher_stub/ld/stub_32c6_beta.ld delete mode 100644 tools/esptool_py/flasher_stub/ld/stub_32h2.ld delete mode 100644 tools/esptool_py/flasher_stub/ld/stub_32h2_beta_1.ld delete mode 100644 tools/esptool_py/flasher_stub/ld/stub_32h2_beta_2.ld delete mode 100644 tools/esptool_py/flasher_stub/ld/stub_32p4.ld delete mode 100644 tools/esptool_py/flasher_stub/ld/stub_32s2.ld delete mode 100644 tools/esptool_py/flasher_stub/ld/stub_32s3.ld delete mode 100644 tools/esptool_py/flasher_stub/ld/stub_32s3_beta_2.ld delete mode 100644 tools/esptool_py/flasher_stub/ld/stub_8266.ld delete mode 100644 tools/esptool_py/flasher_stub/miniz.c delete mode 100755 tools/esptool_py/flasher_stub/run_tests_with_stub.sh delete mode 100644 tools/esptool_py/flasher_stub/slip.c delete mode 100644 tools/esptool_py/flasher_stub/stub_commands.c delete mode 100644 tools/esptool_py/flasher_stub/stub_flasher.c delete mode 100644 tools/esptool_py/flasher_stub/stub_io.c delete mode 100644 tools/esptool_py/flasher_stub/stub_write_flash.c delete mode 100755 tools/esptool_py/flasher_stub/wrap_stub.py delete mode 100644 tools/esptool_py/test/efuse_scripts/efuse_burn1.py delete mode 100644 tools/esptool_py/test/efuse_scripts/efuse_burn2.py delete mode 100644 tools/esptool_py/test/efuse_scripts/esp32/config1.json delete mode 100644 tools/esptool_py/test/efuse_scripts/esp32/config2.json delete mode 100644 tools/esptool_py/test/efuse_scripts/esp32/execute_efuse_script.py delete mode 100644 tools/esptool_py/test/efuse_scripts/esp32/execute_efuse_script2.py delete mode 100644 tools/esptool_py/test/efuse_scripts/esp32xx/config1.json delete mode 100644 tools/esptool_py/test/efuse_scripts/esp32xx/config2.json delete mode 100644 tools/esptool_py/test/efuse_scripts/esp32xx/execute_efuse_script.py delete mode 100644 tools/esptool_py/test/efuse_scripts/esp32xx/execute_efuse_script2.py delete mode 100755 tools/esptool_py/test/elf2image/esp32-app-cust-ver-info.elf create mode 100755 tools/esptool_py/test/elf2image/esp32c6-appdesc.elf create mode 100644 tools/esptool_py/test/elf2image/esp32c6-appdesc/Makefile create mode 100644 tools/esptool_py/test/elf2image/esp32c6-appdesc/esp32c6-appdesc.ld create mode 100644 tools/esptool_py/test/elf2image/esp32c6-appdesc/main.c create mode 100644 tools/esptool_py/test/elf2image/esp8266-nonossdkv20-at-v2.elf-0x00000.bin create mode 100644 tools/esptool_py/test/elf2image/esp8266-nonossdkv20-at-v2.elf-0x01010.bin create mode 100644 tools/esptool_py/test/images/efuse/256bit_3 rename tools/esptool_py/test/secure_images/{bootloader_signed_v2.bin => bootloader_signed_v2_rsa.bin} (100%) rename tools/esptool_py/test/secure_images/{ecdsa_secure_boot_signing_key.pem => ecdsa256_secure_boot_signing_key.pem} (100%) rename tools/esptool_py/test/secure_images/{ecdsa_secure_boot_signing_key2.pem => ecdsa256_secure_boot_signing_key2.pem} (100%) rename tools/esptool_py/test/secure_images/{ecdsa_secure_boot_signing_key_pkcs8.pem => ecdsa256_secure_boot_signing_key_pkcs8.pem} (100%) rename tools/esptool_py/test/secure_images/{ecdsa_secure_boot_signing_pubkey.pem => ecdsa256_secure_boot_signing_pubkey.pem} (100%) rename tools/esptool_py/test/secure_images/{ecdsa_secure_boot_signing_pubkey2.pem => ecdsa256_secure_boot_signing_pubkey2.pem} (100%) create mode 100644 tools/esptool_py/test/secure_images/ecdsa256_secure_boot_signing_pubkey_raw.bin create mode 100644 tools/esptool_py/test/test_logger.py diff --git a/tools/esptool_py/CHANGELOG.md b/tools/esptool_py/CHANGELOG.md index f3d16e0b4c..e422e66508 100644 --- a/tools/esptool_py/CHANGELOG.md +++ b/tools/esptool_py/CHANGELOG.md @@ -1,255 +1,492 @@ + + + + +# CHANGELOG + +> All notable changes to this project are documented in this file. +> This list is not exhaustive - only important changes, fixes, and new features in the code are reflected here. + +
+ + Static Badge + + + Static Badge + + + Static Badge + +
+
+ +## v5.0.0 (2025-07-02) + +### 🚨 Breaking changes + +- - The .py suffix is deprecated for the following scripts: + - esptool + - espefuse + - espsecure + - esp_rfc2217_server *(Peter Dragun - 635cde1)* +- - execute-scripts command is removed *(Peter Dragun - ff72b26)* + +### ✨ New Features + +- **espefuse**: Use the esptool logger, more concise messages *(Radim Karniš - 983338f)* +- **espefuse**: Replace execute-scripts with public API *(Peter Dragun - ff72b26)* +- **espefuse**: Add public API for espefuse *(Peter Dragun - d7da0f8)* +- **espefuse**: Rename all commands to use dashes and add tests for deprecated commands *(Peter Dragun - ade3088)* +- **espefuse**: Add support for chaining commands with click parser *(Peter Dragun - 0a2ea69)* +- **espefuse**: Refactor CLI and use click for parsing arguments *(Peter Dragun - aa80001)* +- **espefuse**: Adds efuse calculation fields for ESP32-C5 *(Konstantin Kondrashov - 9104038)* +- **espefuse**: Adds 3-bit field for wafer major version in ESP32-P4 *(Konstantin Kondrashov - c102510)* +- **verbosity**: Allow setting silent or verbose output levels *(Radim Karniš - 90e3770)* +- **efuse**: Adds efuses for ESP32-C61 ECO3 *(Konstantin Kondrashov - 6146410)* +- **espefuse**: Support efuse for ESP32-C5 ECO2 (v1.0) *(Konstantin Kondrashov - 3726726)* +- **espsecure**: Use esptool logger, unify output format of messages *(Radim Karniš - 905249c)* +- **stub_flasher**: Support for >16MB flash on P4 and >16MB encrypted writes on S3 *(Radim Karniš - 4e6803e)* +- **espsecure**: Drop ecdsa module, use cryptography instead *(Radim Karniš - e132f6f)* +- **espsecure**: Unify all commands and options to use dash instead of underscore *(Peter Dragun - 36325fd)* +- **espsecure**: Use rich click for CLI parsing *(Peter Dragun - 9c7ddc1)* +- **targets**: Update chip features lists with more info *(Radim Karniš - 3c776aa)* +- **logging**: Add collapsible output stages and ASCII progress bars *(Radim Karniš - f3cf107)* +- **trace**: Update --trace with more info and more readable formatting *(Radim Karniš - 0beee77)* +- **cli**: Commands and options use dashes instead of underscores for uniformity *(Peter Dragun - 3cecd6d)* +- **cmds**: Expand input of all functions to file paths, bytes, or file-like objects *(Radim Karniš - 46a9e31)* +- **cmds**: Allow all functions to both return bytes and write to files *(Radim Karniš - 03b84a1)* +- **cmds**: Polish the public API, unify arg names, pack some args *(Radim Karniš - 37a13a9)* +- **cmds**: Encapsulate logic for running the stub flasher in run_stub *(Radim Karniš - 063d9d5)* +- **cli**: Add click-based CLI interface *(Peter Dragun - d40fefa)* +- **cmds**: Allow commands to output bytes, as well as write to a file *(Radim Karniš - 0153b79)* +- **cmds**: Rework the public API to work as a Python module *(Radim Karniš - ba36933)* +- **flash_attach**: Encapsulate logic for flash attaching and configuration *(Radim Karniš - 6e959ef)* +- **esp32h4**: update the ESP32H4StubLoader *(Chen Jichang - f7c78f8)* +- **espefuse**: Updates esp32h4 efuse table and fixes tests *(Konstantin Kondrashov - 3da8c57)* +- **esp32h4**: add ESP32H4 esptool support *(Chen Jichang - bcf5c6e)* +- **esp32h21**: Add Microsoft UF2 family ID *(Radim Karniš - cb0d334)* +- **errors**: Print errors to STDERR, catch KeyboardInterrupt *(Radim Karniš - 0864e17)* +- **write_flash**: Remove the superfluous --verify option *(Radim Karniš - dbf3d1c)* +- **logger**: Add a custom logger, allow output redirection *(Radim Karniš - 1ce02db)* +- **image_info**: Deprecate the --version 1 output format *(Radim Karniš - 3f625c3)* +- Remove .py suffix from scripts *(Peter Dragun - 635cde1)* +- detect flash size of Adesto flash chips *(Jaroslav Burian - 0b56f85)* +- Add support for k, M suffix for flash size *(Peter Dragun - 6f0d779)* +- Rename reset modes to use dash instead of underscore *(Peter Dragun - 851919f)* + +### 🐛 Bug Fixes + +- **logger**: Turn on smart features in more cases *(Jason2866 - 5d5eafb)* +- **elf2image**: Multiple fixes from 3rd party frameworks *(Sylvio Alves - cbd4e9b)* +- **stub_flasher**: Fix USB-Serial/JTAG mode on C5 ECO2 and C61 ECO3 *(Radim Karniš - 1decf86)* +- **write_flash**: Detect more cases of unresponsive flash, fix failing flash_size check *(Radim Karniš - e6bfc3b)* +- **stub_flasher**: Fix ESP32-C5 ECO2 flashing *(Radim Karniš - 3a4c15c)* +- **espefuse**: Fix output messages for set_flash_voltage *(Peter Dragun - daaedf8)* +- **espefuse**: JTAG_SEL_ENABLE has GPIO34 strapping pin for ESP32P4 *(Jan Beran - 78535e4)* +- **esp32c5**: fix bootloader address *(Jaroslav Burian - ec12073)* +- **autodetection**: Remove the Unsupported detection protocol stage *(Radim Karniš - 05553a4)* +- **logging**: Unify output messages, notes, and warning formatting *(Radim Karniš - 07879eb)* +- **elf2image**: fix elf2image for ram app when sha256 offset not specified *(Jaroslav Burian - 6f8ff39)* +- **esp32h4**: fix h4 chip feature *(Chen Jichang - 955943a)* +- **image_info**: Sanitize app and bootloader info of null bytes *(Radim Karniš - 8016455)* +- **lint**: Correct type annotations issues reported by mypy *(Radim Karniš - 0bca550)* +- **esptool**: Fix efuse base address for esp32h21 *(Konstantin Kondrashov - c3d28ee)* +- **elf2image**: support --flash-mmu-page-config for all chips *(Jaroslav Burian - 8be617c)* +- **elf2image**: Try to correct MMU page size if not specified *(Jaroslav Burian - f4fabc5)* +- **elf2image**: Print correct MMU page size in error message *(Jaroslav Burian - 9da4948)* +- **logging**: Avoid crashes when flushing if sys.stdout is not available *(Radim Karniš - 5176b67)* +- enable auto-detection of ESP32-S2 in secure download mode *(Jaroslav Burian - c2f5d21)* +- enable ESP32-P4 ECO5 chip detection *(Jaroslav Burian - 0b3460f)* +- Do not use padding for merged IntelHex files *(Peter Dragun - 08c170b)* +- lock upper version of click to <8.2.0 *(Peter Dragun - 5241cba)* +- Add timeout to read_flash to avoid infinite loops *(Peter Dragun - f26a7bb)* +- Close the data file after reading the data *(Stevan Stevic - 807d02b)* + +### 📖 Documentation + +- **elf2image**: Link an article with Simple Boot explanation *(Radim Karniš - 202dfad)* +- **logger**: Fix custom logger example code *(Radim Karniš - 26e86e9)* +- **logger**: Fix custom logger example code *(Radim Karniš - eaaa6b3)* +- Clarify versions in documentation *(Peter Dragun - 4586e4b)* +- Remove .py suffix from tool names *(Peter Dragun - e9f03ae)* +- Remove espefuse and espsecure migration guide for esp8266 *(Peter Dragun - b6e08a3)* +- Update migration guide for espefuse with click parser *(Peter Dragun - faf3e22)* +- Add missing esp32-p4 target to supported targets *(Peter Dragun - 8b5a5d9)* +- fix targets dropdown in production *(Peter Dragun - 2643101)* +- Update autocomplete docs for click-based CLI *(Peter Dragun - 89cfa52)* +- fix minor issues and improve vague statements *(Peter Dragun - 6d04155)* + +### 🔧 Code Refactoring + +- **cli_mode**: Improve CLI mode workflow code *(Radim Karniš - 0671d35)* +- **stub_class**: Make into a mixin to avoid code repetition *(Radim Karniš - 83613c8)* + +### 🗑️ Removals + +- **make_image**: Remove the make_image command in favor of other workflows *(Radim Karniš - 955a7c8)* +- **beta_targets**: Removed support for beta chip targets *(Radim Karniš - 8f1c206)* +- Deprecate Python versions 3.7, 3.8 and 3.9 *(Peter Dragun - 19f1bee)* + + +## v4.9.0 (2025-06-19) + +### ✨ New Features + +- **espefuse**: Add eFuses for ESP32-C61 ECO3 *(Radim Karniš - 98688ab)* +- **espefuse**: Support efuse for ESP32-C5 ECO2 (v1.0) *(Konstantin Kondrashov - ce16054)* +- **stub_flasher**: Support for >16MB flash on P4 and >16MB encrypted writes on S3 *(Radim Karniš - 0110514)* +- **espefuse**: Updates esp32h4 efuse table and fixes tests *(Konstantin Kondrashov - 777c505)* +- **esp32h4**: add ESP32H4 esptool support *(Chen Jichang - edb99bd)* +- **esp32h21**: Add Microsoft UF2 family ID *(Radim Karniš - 74d27ae)* +- **watchdog_reset**: Add a new watchdog_reset option working even in USB modes *(Radim Karniš - d37c38a)* +- **espsecure**: Improves an error message for encrypt_flash_data and decrypt_flash_data *(Konstantin Kondrashov - ef407ed)* +- **espefuse**: Clean up efuse code for ESP32H2 *(Konstantin Kondrashov - 4e922fe)* +- **espefuse**: Support different efuse table versions for ESP32H2 *(Konstantin Kondrashov - d51ecbe)* +- **espefuse**: Adds efuses for esp32h2 eco5 *(Konstantin Kondrashov - 9b74df6)* +- **esp32h21**: add ESP32H21 esptool support *(gaoxu - 92ceff2)* +- **esp32-p4**: add support for flasher stub in USB OTG mode *(Peter Dragun - 804f2db)* +- **esp32-c5**: Add ECO1 magic number *(Radim Karniš - 6cc002c)* +- **esp_rfc2217**: Improved the logger message format *(Jakub Kocka - 39a12a4)* +- **espefuse**: Adds 3 bit for PSRAM_CAP efuse field *(Konstantin Kondrashov - ab2e0bf)* +- **espefuse**: Adds API for getting block and wafer versions *(Konstantin Kondrashov - 111c6c0)* +- **espefuse**: Adds ADC calibration data for ESP32-C61 *(Konstantin Kondrashov - 36d9735)* +- **espefuse**: Adds ADC calibration data for ESP32-C5 *(Konstantin Kondrashov - a903812)* +- **espefuse**: Adds ADC calibration data for ESP32-P4 *(Konstantin Kondrashov - 215e4b8)* +- **erase_region**: Enable erasing in ROM bootloader and SDM *(Radim Karniš - e0deeac)* +- **hard_reset**: Support custom hard reset sequence configuration *(Radim Karniš - 1b15738)* +- print usb mode when output chip info *(Jan Beran - 749d1ad)* +- Add new app description segments *(Jaroslav Burian - b23e60f)* +- add filtering based on serial number *(Jaroslav Burian - 88319db)* +- Add support for Python 3.13 *(Radim Karniš - 6abd05d)* + +### 🐛 Bug Fixes + +- **stub_flasher**: Fix USB-Serial/JTAG mode on C5 ECO2 and C61 ECO3 *(Radim Karniš - 4382f14)* +- **write_flash**: Detect more cases of unresponsive flash, fix failing flash_size check *(Radim Karniš - f83d598)* +- **stub_flasher**: Fix ESP32-C5 ECO2 flashing *(Radim Karniš - bb237bc)* +- **espefuse**: Fix output messages for set_flash_voltage *(Peter Dragun - 759bcc6)* +- **espefuse**: JTAG_SEL_ENABLE has GPIO34 strapping pin for ESP32P4 *(Jan Beran - f6d1833)* +- **esp32c5**: fix bootloader address *(Jaroslav Burian - 83e0973)* +- **elf2image**: fix elf2image for ram app when sha256 offset not specified *(Radim Karniš - 9fd7b7a)* +- **esp32h4**: Correct ESP32-H4 chip features *(Radim Karniš - 5520963)* +- **esp32h21**: Fix eFuse base address *(Radim Karniš - dc05792)* +- **elf2image**: support --flash-mmu-page-config for all chips *(Jaroslav Burian - 54fdc75)* +- **elf2image**: Try to correct MMU page size if not specified *(Jaroslav Burian - d9afa9c)* +- **elf2image**: Print correct MMU page size in error message *(Jaroslav Burian - 447de60)* +- **test**: Expect the correct module name for Python's 3.14 argparse *(Karolina Surma - 98001b7)* +- **write_flash**: Skip flash_size checks if we can't read flash size *(Radim Karniš - 12095b2)* +- **save_segment**: Adds segment len check the same as bootloader does *(Konstantin Kondrashov - a6bceb7)* +- **chip_type_verification**: Enable in SDM, do not rely on magic numbers *(Radim Karniš - 598e07b)* +- **esp32-c6**: Disable RTC WDT reset to prevent port disappearing *(Radim Karniš - d47004e)* +- **esp_rfc2217**: Fixed keyboard interrupt on Windows and added info for command *(Jakub Kocka - 5569aa5)* +- **detect_chip**: Select correct loader before further operations to avoid silent failures *(Jan Beran - 8897ff8)* +- **usb_resets**: Fix resetting in USB-OTG and USB-Serial/JTAG modes *(Radim Karniš - 8298cdc)* +- Do not use padding for merged IntelHex files *(Peter Dragun - 739669f)* +- close port when connect fails *(Jaroslav Burian - d99c972)* +- Hide missing app info based on IDF version *(Jaroslav Burian - d2bca1e)* +- add delay after WDT reset for better stability *(Peter Dragun - 188c162)* +- Not reading app description for some SoCs *(Jaroslav Burian - 3555fe1)* +- Fix missing newline in output *(Jan Beran - 26b676b)* + +### 📖 Documentation + +- **esptool**: Fix reset sequences in documentation *(Jan Beran - 92160eb)* +- **flash_modes**: Correct QIO GPIO pins for all chips *(Radim Karniš - 23f11f0)* +- **espefuse**: Fixed JTAG strapping pin for ESP32-S3 in the help and documentation *(Roland Dobai - de1d1ce)* +- **scripting**: Add example of usage as a Python module *(Radim Karniš - d54e59f)* +- **esp8266**: change boot select pin to IO0 *(ChromaLock - c06ce1e)* +- **read_flash_sfdp**: Fix command formatting *(Radim Karniš - ec309bb)* +- **spi_connection**: Explain which flash chips are supported *(Radim Karniš - 6d37e30)* +- fix targets dropdown in production *(Peter Dragun - 9201ccd)* +- Point directly to the datasheet for given target *(Jan Beran - a32988e)* +- Add ESP32-C5 and ESP32-C61 docs *(Radim Karniš - f52c723)* + +--- + ## v4.8.1 (2024-09-25) -### Bug Fixes - -- **esp32c2**: Add esp32c2 eco4 rom magic value -- **packaging**: Correctly exclude the unwanted sub/modules - -## v4.8.0 (2024-09-18) - -### New Features - -- **espefuse**: Supports wafer efuse versions for esp32c61 -- **esptool**: add new command SFDP read -- **esptool**: Add option to retry connection in a loop -- **efuse**: Updates efuse table for esp32c5 -- **efuse**: Updates efuse table for esp32p4 -- **esp32c61**: Added stub flasher support -- **cli**: add autocompletions -- **esptool**: allow picking UART by VID/PID/Name -- **esp32c5**: Add USB-serial/JTAG stub support -- **esp32c5**: Add UART stub support -- **esptool**: Print key_purpose name for get_security_info cmd -- **espefuse**: Adds support extend efuse table by user CSV file -- **espefuse**: Adds efuse dump formats: separated(default) and united(new) -- **espefuse**: Adds incompatible eFuse settings check for S3 -- **reset**: Apply reconnections to the whole reset sequence, not line transitions -- **reset**: Automatically reconnect if port disconnects during reset -- **esp32-p4**: Add ECO1 magic number -- **espsecure**: Add support for secure boot v2 using ECDSA-P384 signatures -- **write_flash**: retry flashing if chip disconnects -- **espefuse**: Allow filtering efuses based on command line arguments -- **esploader**: Enable context manager for esp instances -- **espefuse**: Added check for correctness of written data -- **espefuse**: Improves help for burn_efuse cmd -- **esp32s3**: clear boot control register on hard reset -- **esp32-p4**: add spi-connection restriction to ROM class -- add UF2 IDs for ESP32-C5 and ESP32-C61 -- **espefuse**: Updates efuses for C5 and C61 -- **esp32c61**: add c61 basic flash support (no_stub) -- **esp32c5**: skipped the stub check for esp32c5 mp -- **esp32c5**: base support of esp32c5 mp (no stub) -- Added warning when secure boot enabled -- **cmds/write_flash**: Recalculated SHA digest for image binary -- print flash voltage in flash_id command -- **esptool**: Adds wafer and pkg versions -- **espefuse**: Update adc_info commands for all chips -- **espefuse**: Adds new efuses for esp32p4 -- **espefuse**: Allow the espefuse.py to work when coding scheme == 3 -- **err_defs**: Add ROM bootloader flash error definitions -- Use ruff instead of flake8 and black both in pre-commit and CI -- **esp32p4**: Enable USB-serial/JTAG in flasher stub -- **espefuse**: Postpone some efuses to burn them at the very end -- add advisory port locking -- **espefuse**: check_error --recover chip even if there are num_errors -- **espefuse**: Adds new efuses for esp32c6 and esp32h2 -- **esp32c5**: add target esp32c5 beta3 - -### Bug Fixes - -- **esptool**: Fix esp32c61 flash frequency config -- **esptool**: Fix incorrect chip version for esp32c5 -- **write_flash**: Verify if files will fit against the real flash size when possible -- **remote_ports**: Disable reset sequence when a socket is used -- **bitstring**: Restricted bitstring dependency to fix 32-bit compatibility -- **esp32_d0wdr2_v3**: Print correct chip name -- pass error message to exception in OTG mode -- **bin_image**: add check for ELF file segment when saving RAM segments -- **docs**: Add a note about entering manual bootloader mode -- **esp32c5**: Fix MAC reading for esptool -- Erase non-aligned bytes with --no-stub -- **esp32-c5**: Use a longer reset delay with usb-serial/jtag to stabilize boot-up -- **espefuse**: Use stub class if stub flasher is running -- Do not append SHA256 when `--ram-only-header` -- **elf2image**: add ELF flags to merge condition -- ram_only_header: pad flash segment to next boundary -- sort segments if ram_only_header is used -- **espefuse**: Fix efuse base addr for esp32c5 MP -- fix type annotation to comply with mypy -- **espefuse**: Fix burn_key for ECDSA_KEY, it can read pem file -- **secure_download_mode**: Disable secure boot detection and print more info -- **esptool**: clear boot control register on ESP32-S3 -- **intelhex**: catch unicode decode errors when converting hex to binary -- ROM doesn't attach in-package flash chips -- close file gracefully in espsecure -- Fixed glitches on RTS line when no_reset option on Windows -- **merge_bin**: treat files starting with colon as raw files -- Index image segments from 0 instead of 1 -- **read_flash**: add flash size arg to enable reading past 2MB without stub -- **read_flash**: flush transmit buffer less often to inrease throughput -- **esptool**: Proper alignment for SoCs with offset load -- ignore resetting on unsupported ports -- **esptool**: Remove the shebang from uf2_writer.py - -### Code Refactoring - -- Migrated esp_rfc2217_server into standalone subpackage -- **test/esptool**: Updated tests according to SHA recomputation for binary -- **style**: Comply with black>=24.0.0 +### ✨ New Features + +- **espefuse**: Supports wafer efuse versions for esp32c61 *(Konstantin Kondrashov - 0472846)* +- **esptool**: add new command SFDP read *(Xiao Xufeng - 92143ed)* +- **esptool**: Add option to retry connection in a loop *(Alfonso Acosta - 04045d6)* +- **efuse**: Updates efuse table for esp32c5 *(Konstantin Kondrashov - b3022fa)* +- **efuse**: Updates efuse table for esp32p4 *(Konstantin Kondrashov - 669a69f)* +- **esp32c61**: Added stub flasher support *(Jakub Kocka - e8b3911)* +- **cli**: add autocompletions *(Dmitriy Astapov - 7cc35e4)* +- **esptool**: allow picking UART by VID/PID/Name *(Richard Allen - 5dd3dcc)* +- **esp32c5**: Add USB-serial/JTAG stub support *(Jaroslav Burian - e170bcc)* +- **esp32c5**: Add UART stub support *(Konstantin Kondrashov - b199534)* +- **esptool**: Print key_purpose name for get_security_info cmd *(Konstantin Kondrashov - ccd8c72)* +- **espefuse**: Adds support extend efuse table by user CSV file *(Konstantin Kondrashov - 6bb2b92)* +- **espefuse**: Adds efuse dump formats: separated(default) and united(new) *(Konstantin Kondrashov - fc2856a)* +- **espefuse**: Adds incompatible eFuse settings check for S3 *(Konstantin Kondrashov - c244843)* +- **reset**: Apply reconnections to the whole reset sequence, not line transitions *(Radim Karniš - d49837e)* +- **reset**: Automatically reconnect if port disconnects during reset *(Andrew Leech - 9dc5dfb)* +- **esp32-p4**: Add ECO1 magic number *(Radim Karniš - d4d2153)* +- **espsecure**: Add support for secure boot v2 using ECDSA-P384 signatures *(harshal.patil - f014cad)* +- **write_flash**: retry flashing if chip disconnects *(Peter Dragun - a15089a)* +- **espefuse**: Allow filtering efuses based on command line arguments *(Jan Beran - bb52d36)* +- **esploader**: Enable context manager for esp instances *(Radim Karniš - d4c8cb3)* +- **espefuse**: Added check for correctness of written data *(Konstantin Kondrashov - d2bfaad)* +- **espefuse**: Improves help for burn_efuse cmd *(Konstantin Kondrashov - ef8ee8a)* +- **esp32s3**: clear boot control register on hard reset *(Peter Dragun - 1c355f9)* +- **esp32-p4**: add spi-connection restriction to ROM class *(Peter Dragun - dad0edc)* +- **espefuse**: Updates efuses for C5 and C61 *(Konstantin Kondrashov - e34df69)* +- **esp32c61**: add c61 basic flash support (no_stub) *(wanlei - ef4d8a7)* +- **esp32c5**: skipped the stub check for esp32c5 mp *(laokaiyao - a773e6b)* +- **esp32c5**: base support of esp32c5 mp (no stub) *(laokaiyao - e414cef)* +- **cmds/write_flash**: Recalculated SHA digest for image binary *(Jakub Kocka - 3b0939c)* +- **esptool**: Adds wafer and pkg versions *(Konstantin Kondrashov - 6c5cfd6)* +- **espefuse**: Update adc_info commands for all chips *(Konstantin Kondrashov - 31eb15b)* +- **espefuse**: Adds new efuses for esp32p4 *(Konstantin Kondrashov - 31477fb)* +- **espefuse**: Allow the espefuse.py to work when coding scheme == 3 *(Francisco Blas (klondike) Izquierdo Riera - 1e79f25)* +- **err_defs**: Add ROM bootloader flash error definitions *(radim.karnis - 2d8a3ad)* +- **esp32p4**: Enable USB-serial/JTAG in flasher stub *(Peter Dragun - 96a5c21)* +- **espefuse**: Postpone some efuses to burn them at the very end *(KonstantinKondrashov - bdeec68)* +- **espefuse**: check_error --recover chip even if there are num_errors *(KonstantinKondrashov - f72b5ad)* +- **espefuse**: Adds new efuses for esp32c6 and esp32h2 *(KonstantinKondrashov - 16e4fae)* +- **esp32c5**: add target esp32c5 beta3 *(laokaiyao - d9a6660)* +- add UF2 IDs for ESP32-C5 and ESP32-C61 *(Peter Dragun - cf6d94e)* +- Added warning when secure boot enabled *(Jakub Kocka - 8d26375)* +- print flash voltage in flash_id command *(Peter Dragun - 6393d6b)* +- Use ruff instead of flake8 and black both in pre-commit and CI *(Jan Beran - 1d5fcb3)* +- add advisory port locking *(Peter Dragun - 8ad6d57)* + +### 🐛 Bug Fixes + +- **esp32c2**: Add esp32c2 eco4 rom magic value *(Jiang Guang Ming - 3434433)* +- **packaging**: Correctly exclude the unwanted sub/modules *(Karolina Surma - 908d0b5)* +- **esptool**: Fix esp32c61 flash frequency config *(C.S.M - 6edafea)* +- **esptool**: Fix incorrect chip version for esp32c5 *(Konstantin Kondrashov - 138660b)* +- **write_flash**: Verify if files will fit against the real flash size when possible *(Radim Karniš - 1693449)* +- **remote_ports**: Disable reset sequence when a socket is used *(Radim Karniš - 28556fb)* +- **bitstring**: Restricted bitstring dependency to fix 32-bit compatibility *(Jakub Kocka - 4f7e223)* +- **esp32_d0wdr2_v3**: Print correct chip name *(Radim Karniš - dfd61e2)* +- **bin_image**: add check for ELF file segment when saving RAM segments *(Peter Dragun - 6e8632d)* +- **docs**: Add a note about entering manual bootloader mode *(Roland Dobai - 4d0c7d9)* +- **esp32c5**: Fix MAC reading for esptool *(Konstantin Kondrashov - 2b0ec7a)* +- **esp32-c5**: Use a longer reset delay with usb-serial/jtag to stabilize boot-up *(C.S.M - 1059ec7)* +- **espefuse**: Use stub class if stub flasher is running *(Radim Karniš - 67d66a0)* +- **elf2image**: add ELF flags to merge condition *(Marek Matej - e87cc3e)* +- **espefuse**: Fix efuse base addr for esp32c5 MP *(Konstantin Kondrashov - 248dc9a)* +- **espefuse**: Fix burn_key for ECDSA_KEY, it can read pem file *(Konstantin Kondrashov - 450db24)* +- **secure_download_mode**: Disable secure boot detection and print more info *(Radim Karniš - 1dc3c8b)* +- **esptool**: clear boot control register on ESP32-S3 *(Peter Dragun - 0215786)* +- **intelhex**: catch unicode decode errors when converting hex to binary *(Peter Dragun - a2bdaa2)* +- **merge_bin**: treat files starting with colon as raw files *(Peter Dragun - 2c0a5da)* +- **read_flash**: add flash size arg to enable reading past 2MB without stub *(Peter Dragun - f1eb65f)* +- **read_flash**: flush transmit buffer less often to inrease throughput *(Peter Dragun - 8ce5ed3)* +- **esptool**: Proper alignment for SoCs with offset load *(Marek Matej - 17866a5)* +- **esptool**: Remove the shebang from uf2_writer.py *(Karolina Surma - 45fbcdd)* +- pass error message to exception in OTG mode *(Peter Dragun - c266fdd)* +- Erase non-aligned bytes with --no-stub *(Jaroslav Burian - c984aa9)* +- Do not append SHA256 when `--ram-only-header` *(Tiago Medicci Serrano - 5d9d5be)* +- ram_only_header: pad flash segment to next boundary *(Sylvio Alves - 4394a65)* +- sort segments if ram_only_header is used *(Sylvio Alves - 4c5874a)* +- fix type annotation to comply with mypy *(Peter Dragun - 55b338a)* +- ROM doesn't attach in-package flash chips *(Jakub Kocka - bc9f2a6)* +- close file gracefully in espsecure *(gnought - 2381711)* +- Fixed glitches on RTS line when no_reset option on Windows *(Jakub Kocka - 956557b)* +- Index image segments from 0 instead of 1 *(Jan Beran - b5939da)* +- ignore resetting on unsupported ports *(Peter Dragun - e948993)* + +### 📖 Documentation + +- **troubleshooting**: Add info about debugging in USB-Serial/JTAG and USB-OTG modes *(Radim Karniš - 3a74f62)* +- **troubleshooting**: Mention needed permissions to the serial port on Linux *(Radim Karniš - 8e39ef6)* +- **troubleshooting**: Mention the ESP Hardware Design Guidelines docs *(Radim Karniš - 74ce286)* +- **flashing**: Fixed a typo in /docs/en/esptool/flashing-firmware.rst *(Green - 9f46568)* +- **sphinx-lint**: Add previous commit to .git-blame-ignore-revs *(Jan Beran - c750549)* +- **sphinx-lint**: Fix issues reported by sphinx-lint before adding it to pre-commit *(Jan Beran - 6282f98)* +- **sphinx-lint**: Add sphinx-lint to pre-commit, GH and GL pipelines *(Jan Beran - 1de1a26)* +- **esptool**: Reflect change from flake8 and black to ruff *(Jan Beran - 9f1bde4)* +- add note about Intel Hex merging limitations *(Peter Dragun - d83dd3b)* +- Updated documentation to reflect changes of SHA256 digest recomputation *(Jakub Kocka - 6c28df3)* +- add esp32p4 target to docs *(Peter Dragun - 4a6ad55)* +- Correct bootloader offsets *(radim.karnis - 79978c0)* +- Add instructions on how to update *(radim.karnis - d448851)* + +### 🔧 Code Refactoring + +- **test/esptool**: Updated tests according to SHA recomputation for binary *(Jakub Kocka - 598b703)* +- **style**: Comply with black>=24.0.0 *(radim.karnis - 5ad3c48)* +- Migrated esp_rfc2217_server into standalone subpackage *(Jakub Kocka - 9b24215)* + +--- ## v4.7.0 (2023-12-13) -### New Features - -- **test_esptool**: Added test for embedded and detected flash size match -- **spi_connection**: Support --spi-connection on all chips -- **espefuse**: Support XTS_AES_256_KEY key_purpose for ESP32P4 -- **xip_psram**: support xip psram feature on esp32p4 -- add support for intel hex format -- **esp32p4**: Stub flasher support -- **elf2image**: add ram-only-header argument -- **rfc2217_server**: Add hard reset sequence -- **espefuse**: Adds efuse ADC calibration data for ESP32H2 -- **espefuse**: Update the way to complete the operation -- add support for get_security_info on esp32c3 ECO7 -- **loader**: Added hints for some serial port issues when rising port error -- Add support for Python 3.12 -- **esp32c3**: Support ECO6 and ECO7 magic numbers -- **merge_bin**: add support for uf2 format -- **esp32-s3**: Support >16MB quad flash chips -- **efuse**: Update key purpose table and tests -- **efuse**: ESP32P4 adds ecdsa_key support -- **espefuse**: Add support for esp32p4 chip -- **esptool**: added target to esp32p4 -- **espsecure**: Allow prompting for HSM PIN in read_hsm_config -- **esptool**: Add new packages for ESP32C3 and flash efuses -- **esptool**: Add tests for get_chip_features -- **esptool**: Add PICO package for ESP32S3 and flash/psram efuses -- **get_security_info**: Improved the output format and added more details - -### Bug Fixes - -- **esp32c2**: Added get_flash_cap and get_flash_vendor -- **testloadram**: Windows assertion error -- fixed exit() to be used from right module -- **esp32c2**: Recommend using higher baud rate if connection fails -- **test_esptool**: Fixed connection issue on Windows -- **esptool**: Rephrase the --ram-only-header command message -- **load_ram**: check for overlaps in bss section -- **tests/intelhex**: make sure file is closed on Windows -- **spi_connection**: Unattach previously attached SPI flash -- **espefuse**: Fix ECDSA_FORCE_USE_HARDWARE_K for ECDSA key (esp32h2) -- **loader**: Could not open serial port message adjusted -- **flasher_stub**: fix usb-serial-jtag enabled non-related intr source -- **bin_image**: Check only ELF sections when searching for .flash.appdesc -- **danger-github**: Fir Danger GitHub token permission -- Fix redirection of STDOUT -- **autodetection**: Remove the ESP32-S2 ROM class from get_security_info autodetection -- assert in esp32 exclusive workaround -- **elf2image**: fix text/rodata mapping overlap issue on uni-idrom bus chips -- **dangerGH**: Update token permissions - allow Danger to add comments to PR -- **expand file args**: Correctly print the expanded command -- **esp32-c2**: Enable flashing in secure download mode - -### Code Refactoring - -- **stub_flasher**: Cleanup, make adding new targets easier +### ✨ New Features + +- **test_esptool**: Added test for embedded and detected flash size match *(Jakub Kocka - c0ea74a)* +- **spi_connection**: Support --spi-connection on all chips *(radim.karnis - 1a38293)* +- **espefuse**: Support XTS_AES_256_KEY key_purpose for ESP32P4 *(KonstantinKondrashov - a91eee1)* +- **xip_psram**: support xip psram feature on esp32p4 *(Armando - 1b350ce)* +- **esp32p4**: Stub flasher support *(radim.karnis - d266645)* +- **elf2image**: add ram-only-header argument *(Almir Okato - da28460)* +- **rfc2217_server**: Add hard reset sequence *(20162026 - d66de5c)* +- **espefuse**: Adds efuse ADC calibration data for ESP32H2 *(KonstantinKondrashov - 2a57d6c)* +- **espefuse**: Update the way to complete the operation *(KonstantinKondrashov - c8d688d)* +- **loader**: Added hints for some serial port issues when rising port error *(Jakub Kocka - d61da77)* +- **esp32c3**: Support ECO6 and ECO7 magic numbers *(radim.karnis - 6943c5d)* +- **merge_bin**: add support for uf2 format *(Peter Dragun - 3d899b2)* +- **esp32-s3**: Support >16MB quad flash chips *(radim.karnis - 67a91cb)* +- **efuse**: Update key purpose table and tests *(KonstantinKondrashov - cb5e850)* +- **efuse**: ESP32P4 adds ecdsa_key support *(KonstantinKondrashov - 3654267)* +- **espefuse**: Add support for esp32p4 chip *(KonstantinKondrashov - 8273916)* +- **esptool**: added target to esp32p4 *(Armando - 654e626)* +- **espsecure**: Allow prompting for HSM PIN in read_hsm_config *(Richard Retanubun - ab25fc1)* +- **esptool**: Add new packages for ESP32C3 and flash efuses *(KonstantinKondrashov - 8f37762)* +- **esptool**: Add tests for get_chip_features *(KonstantinKondrashov - d5bb1ee)* +- **esptool**: Add PICO package for ESP32S3 and flash/psram efuses *(KonstantinKondrashov - b70ead2)* +- **get_security_info**: Improved the output format and added more details *(Aditya Patwardhan - 9b95de8)* +- add support for intel hex format *(Peter Dragun - 7074bed)* +- add support for get_security_info on esp32c3 ECO7 *(Peter Dragun - 20565a0)* +- Add support for Python 3.12 *(radim.karnis - ef02d52)* + +### 🐛 Bug Fixes + +- **esp32c2**: Added get_flash_cap and get_flash_vendor *(Jakub Kocka - b8dd74d)* +- **testloadram**: Windows assertion error *(Jakub Kocka - cd51bbc)* +- **esp32c2**: Recommend using higher baud rate if connection fails *(Jakub Kocka - ef0c91f)* +- **test_esptool**: Fixed connection issue on Windows *(Jakub Kocka - 4622bb2)* +- **esptool**: Rephrase the --ram-only-header command message *(Marek Matej - da4a486)* +- **load_ram**: check for overlaps in bss section *(Peter Dragun - 3a82d7a)* +- **tests/intelhex**: make sure file is closed on Windows *(Peter Dragun - 900d385)* +- **spi_connection**: Unattach previously attached SPI flash *(radim.karnis - afaa7d2)* +- **espefuse**: Fix ECDSA_FORCE_USE_HARDWARE_K for ECDSA key (esp32h2) *(KonstantinKondrashov - f607f19)* +- **loader**: Could not open serial port message adjusted *(Jakub Kocka - 0d3a077)* +- **flasher_stub**: fix usb-serial-jtag enabled non-related intr source *(wuzhenghui - 3f2dc6f)* +- **bin_image**: Check only ELF sections when searching for .flash.appdesc *(radim.karnis - ffaf6db)* +- **danger-github**: Fir Danger GitHub token permission *(Tomas Sebestik - c0df9b7)* +- **autodetection**: Remove the ESP32-S2 ROM class from get_security_info autodetection *(radim.karnis - 3d8c304)* +- **elf2image**: fix text/rodata mapping overlap issue on uni-idrom bus chips *(wuzhenghui - c48523e)* +- **dangerGH**: Update token permissions - allow Danger to add comments to PR *(Tomas Sebestik - 6b4786a)* +- **expand file args**: Correctly print the expanded command *(radim.karnis - 2bea6f4)* +- **esp32-c2**: Enable flashing in secure download mode *(radim.karnis - e862e10)* +- fixed exit() to be used from right module *(Jakub Kocka - d1610a9)* +- Fix redirection of STDOUT *(radim.karnis - 9585c0e)* +- assert in esp32 exclusive workaround *(wuzhenghui - 5b69e07)* + +### 📖 Documentation + +- **advanced-topics**: Fixed strapping pin for Automatic Bootloader section *(Jakub Kocka - 590c2c6)* +- **serial-protocol**: add images and flowchart *(Peter Dragun - e99c114)* +- **boot_mode_selection**: Correct secondary strapping pin boot mode levels *(radim.karnis - 3b38e79)* +- **troubleshooting**: Explain issues when flashing with USB-Serial/JTAG or USB-OTG *(radim.karnis - 2a399a0)* +- **basic-commands**: added note for PowerShell users for merge_bin command *(Jakub Kocka - dc8a337)* +- Add other resources page *(radim.karnis - cc6c4ce)* + +### 🔧 Code Refactoring + +- **stub_flasher**: Cleanup, make adding new targets easier *(radim.karnis - fb7f4db)* + +--- ## v4.6.2 (2023-06-12) -### Bug Fixes - -- **CH9102F**: Suggest to install new serial drivers if writing to RAM fails -- **compressed upload**: Accept short data blocks with only Adler-32 bytes - -## v4.6.1 (2023-06-01) - -### Bug Fixes - -- **ESP32-S3**: Correct RTC WDT registers to fix resets during flashing - -## v4.6 (2023-05-29) - -### New Features - -- **esptool**: add option to dump whole flash based on detected size - -### Bug Fixes +### 🐛 Bug Fixes -- inconsistent usage of dirs separator -- USB-JTAG-Serial PID detection error -- Set flash parameters even with --flash_size keep -- **ESP32-C6**: Fix get_pkg_version and get_{major,minor}_chip_version +- **CH9102F**: Suggest to install new serial drivers if writing to RAM fails *(radim.karnis - f4b5914)* +- **compressed upload**: Accept short data blocks with only Adler-32 bytes *(radim.karnis - d984647)* -## v4.5.1 (2023-02-28) - -### Bug Fixes - -- **ESP32-S3**: Temporarily disable increasing CPU freq -- Unknown chip (ID or magic number) error -- **ESP32-S3**: Lower CPU freq to improve flasher stub stability -- **rfc2217_server**: Use new reset sequences - -## v4.5 (2023-02-10) - -### New Features +### 📖 Documentation -- **stub**: Add ESP32-S3 octal flash support -- **esp32h2**: Enable USB-JTAG/Serial mode in the stub flasher -- **bootloader reset**: Allow custom reset strategy setting with a config file -- Allow configuration with a config file -- **bootloader reset**: Tighter transitions on Unix systems -- **ci**: Publish development releases with custom pipeline -- **esp32c6 stub**: Increase CPU frequency and write/read speeds over USB-JTAG/Serial -- **esp32c6 stub**: Enable USB-JTAG/Serial -- **flash_id**: Print the flash type if available for the chip +- **boot-log**: fix list formatting *(Peter Dragun - b137d3d)* +- add c2, c6 and h2 as build targets *(Peter Dragun - 590fb55)* +- add explanation for flash_id example to avoid confusion *(Peter Dragun - fbe8066)* -### Bug Fixes +--- -- **cmds**: Make clear that flash type is from eFuse and not detection -- **load config file**: Sort unknown config options -- **esp32c6**: Workaround for bad MSPI frequency in HS mode -- **flasher_stub**: Correct boundaries for SPIWrite4B and SPIRead4B -- **secure download mode**: Reconnect if ROM refuses to respond -- **secure download mode**: Fix SDM detection on S2/S3 -- **ci**: Merge two "ci" directories and build_tools into one -- **ci**: The development release job should not run by default -- **setup**: Use latest reedsolo package which can be installed with Python3.10 and Cython -- **write_flash**: Fix `--erase-all` option -- **espefuse**: Close serial port even when espefuse fails -- **espefuse**: Fix compatibility with Bitstring>=4 - -### Code Refactoring - -- Comply with black 23.1 style -- Optimize unnecessary chip interrogations -- **connection attempt**: Decouple reset sequence settings - -## v4.4 (2022-11-21) +## v4.6.1 (2023-06-01) -### New Features +### ✨ New Features -- **flasher_stub**: Increase CPU frequency and write/read speeds over native USB (USB-OTG) -- **flasher_stub**: Increase CPU frequency and write/read speeds over USB-JTAG/Serial -- Readable error message for serial-related issues -- Detect Guru Meditation errors +- **esptool**: add option to dump whole flash based on detected size *(Peter Dragun - 049baaa)* -### Bug Fixes +### 🐛 Bug Fixes -- Add workaround for breaking changes of bitstring==4 -- close unused ports while get_default_connected_device +- **ESP32-S3**: Correct RTC WDT registers to fix resets during flashing *(radim.karnis - 6fd91af)* +- **ESP32-C6**: Fix get_pkg_version and get\_{major,minor}\_chip_version *(XiNGRZ - 555458c)* +- inconsistent usage of dirs separator *(Massimiliano Montagni - f558f22)* +- USB-JTAG-Serial PID detection error *(Dean Gardiner - 9a719f4)* +- Set flash parameters even with --flash_size keep *(radim.karnis - 0e9c85e)* -## v4.3 (2022-09-14) +### 📖 Documentation -### New Features +- **Boot log**: Add all esp targets to cover boot troubleshooting *(Peter Dragun - 5892496)* -- **image_info**: Print application information if possible -- Add Macronix flash memory density definitions -- **write_flash**: Prevent flashing incompatible images -- Recover from serial errors when flashing -- Add stub flasher error messages definitions -- **image_info**: Image type autodetection +--- -### Code Refactoring +## v4.5.1 (2023-02-28) -- **elf2image**: Simplify bootloader image selection +### ✨ New Features + +- **stub**: Add ESP32-S3 octal flash support *(Roland Dobai - b746aa7)* +- **esp32h2**: Enable USB-JTAG/Serial mode in the stub flasher *(radim.karnis - cc06208)* +- **bootloader reset**: Allow custom reset strategy setting with a config file *(radim.karnis - a8586d0)* +- **bootloader reset**: Tighter transitions on Unix systems *(radim.karnis - 353cefc)* +- **ci**: Publish development releases with custom pipeline *(Roland Dobai - 3a77f1f)* +- **esp32c6 stub**: Increase CPU frequency and write/read speeds over USB-JTAG/Serial *(radim.karnis - 180695e)* +- **esp32c6 stub**: Enable USB-JTAG/Serial *(radim.karnis - b04cc52)* +- **flash_id**: Print the flash type if available for the chip *(Roland Dobai - b25606b)* +- **flasher_stub**: Increase CPU frequency and write/read speeds over native USB (USB-OTG) *(radim.karnis - 52278a9)* +- **flasher_stub**: Increase CPU frequency and write/read speeds over USB-JTAG/Serial *(radim.karnis - dccf4df)* +- **image_info**: Print application information if possible *(radim.karnis - 82bfe98)* +- **write_flash**: Prevent flashing incompatible images *(radim.karnis - 395fcb0)* +- **image_info**: Image type autodetection *(radim.karnis - 791a20b)* +- Allow configuration with a config file *(radim.karnis - 3ad680a)* +- Readable error message for serial-related issues *(radim.karnis - 1082852)* +- Detect Guru Meditation errors *(radim.karnis - 6fac261)* +- Add Macronix flash memory density definitions *(radim.karnis - 3190894)* +- Recover from serial errors when flashing *(radim.karnis - 2fb8d45)* +- Add stub flasher error messages definitions *(radim.karnis - 66502d5)* + +### 🐛 Bug Fixes + +- **ESP32-S3**: Temporarily disable increasing CPU freq *(radim.karnis - 23a5095)* +- **ESP32-S3**: Lower CPU freq to improve flasher stub stability *(radim.karnis - 7b28699)* +- **rfc2217_server**: Use new reset sequences *(radim.karnis - 4f13cf6)* +- **cmds**: Make clear that flash type is from eFuse and not detection *(Roland Dobai - caeab98)* +- **load config file**: Sort unknown config options *(radim.karnis - cc80ecd)* +- **esp32c6**: Workaround for bad MSPI frequency in HS mode *(wuzhenghui - 4738ef7)* +- **flasher_stub**: Correct boundaries for SPIWrite4B and SPIRead4B *(Roland Dobai - 21e5914)* +- **secure download mode**: Reconnect if ROM refuses to respond *(radim.karnis - 869740a)* +- **secure download mode**: Fix SDM detection on S2/S3 *(radim.karnis - b67e557)* +- **ci**: Merge two "ci" directories and build_tools into one *(Roland Dobai - 2ed1fc1)* +- **ci**: The development release job should not run by default *(Roland Dobai - 3f3a2d3)* +- **setup**: Use latest reedsolo package which can be installed with Python3.10 and Cython *(Roland Dobai - 5490b0b)* +- **write_flash**: Fix `--erase-all` option *(radim.karnis - d0af65f)* +- **espefuse**: Close serial port even when espefuse fails *(radim.karnis - 26df171)* +- **espefuse**: Fix compatibility with Bitstring>=4 *(Roland Dobai - ee27a64)* +- Unknown chip (ID or magic number) error *(radim.karnis - 11e6425)* +- Add workaround for breaking changes of bitstring==4 *(Roland Dobai - 09e41df)* +- close unused ports while get_default_connected_device *(Fu Hanxi - 76f491e)* + +### 📖 Documentation + +- **tests**: Add test suite description and instructions *(radim.karnis - 943b997)* +- **serial port**: Update basic-options with more linux instructions *(Robin Gower - b37496f)* +- espsecure remote signing using a HSM broken link fix *(harshal.patil - 0095a26)* +- Update serial protocol description *(radim.karnis - f4ed949)* +- Describe --chip option, fix small typos *(radim.karnis - 2eff1be)* + +### 🔧 Code Refactoring + +- **connection attempt**: Decouple reset sequence settings *(radim.karnis - cee66a2)* +- **elf2image**: Simplify bootloader image selection *(radim.karnis - 2e95f66)* +- Comply with black 23.1 style *(radim.karnis - ea61f8f)* +- Optimize unnecessary chip interrogations *(radim.karnis - f3437a3)* + +--- + +
+ + + Commitizen Espressif plugin + +
+ Espressif Systems CO LTD. (2025) +
+
diff --git a/tools/esptool_py/CONTRIBUTING.rst b/tools/esptool_py/CONTRIBUTING.rst index de0ca91ed8..c946dc3f4e 100644 --- a/tools/esptool_py/CONTRIBUTING.rst +++ b/tools/esptool_py/CONTRIBUTING.rst @@ -1,19 +1,19 @@ Contributions Guide =================== -We welcome contributions to the ``esptool.py`` project! +We welcome contributions to the ``esptool`` project! How to Contribute ----------------- -Contributions to ``esptool.py`` - fixing bugs, adding features, adding documentation - are welcome. We accept contributions via `Github Pull Requests `_. +Contributions to ``esptool`` - fixing bugs, adding features, adding documentation - are welcome. We accept contributions via `Github Pull Requests `_. .. _development-setup: Development Setup ----------------- -Development mode allows you to run the latest development version from the `esptool.py repository on GitHub `_. +Development mode allows you to run the latest development version from the `esptool repository on GitHub `_. .. code-block:: sh @@ -21,11 +21,11 @@ Development mode allows you to run the latest development version from the `espt $ cd esptool $ pip install --user -e . -This will install ``esptool.py``’s dependencies and create some executable script wrappers in the user’s ``bin`` directory. The wrappers will run the scripts found in the git working directory directly, so any time the working directory contents change it will pick up the new versions. +This will install ``esptool``'s dependencies and create some executable script wrappers in the user's ``bin`` directory. The wrappers will run the scripts found in the git working directory directly, so any time the working directory contents change it will pick up the new versions. -It’s also possible to run the scripts directly from the working directory with this Development Mode installation. +It's also possible to run the scripts directly from the working directory with this Development Mode installation. -To also install additional tools needed for actually developing and testing ``esptool.py``, run this command to install a development copy of ``esptool.py`` *plus* packages useful for development: +To also install additional tools needed for actually developing and testing ``esptool``, run this command to install a development copy of ``esptool`` *plus* packages useful for development: :: @@ -36,7 +36,7 @@ To also install additional tools needed for actually developing and testing ``es Reporting Issues ---------------- -Please report bugs in ``esptool.py`` if you find them. However, before reporting a bug please check through the following: +Please report bugs in ``esptool`` if you find them. However, before reporting a bug please check through the following: * `Troubleshooting Guide `_ - common problems and known issues. @@ -44,6 +44,8 @@ Please report bugs in ``esptool.py`` if you find them. However, before reporting If you don’t find anything, please `open a new issue `_. +.. _feature-requests: + Sending Feature Requests ------------------------ @@ -56,7 +58,7 @@ Before Contributing Before sending us a Pull Request, please consider this list of points: -* Have you tried running ``esptool.py`` test suite locally? +* Have you tried running ``esptool`` test suite locally? * Is the code adequately commented for people to understand how it is structured? @@ -71,9 +73,9 @@ Before sending us a Pull Request, please consider this list of points: Code Style & Static Analysis ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Please follow these coding standards when writing code for ``esptool.py``: +Please follow these coding standards when writing code for ``esptool``: -Pre-commit checks +Pre-Commit Checks """"""""""""""""" `pre-commit `_ is a framework for managing pre-commit hooks. These hooks help to identify simple issues before committing code for review. @@ -90,13 +92,13 @@ On the first commit ``pre-commit`` will install the hooks, subsequent checks wil Conventional Commits """""""""""""""""""" -``esptool.py`` complies with the `Conventional Commits standard `_. Every commit message is checked with `Conventional Precommit Linter `_, ensuring it adheres to the standard. +``esptool`` complies with the `Conventional Commits standard `_. Every commit message is checked with `Conventional Precommit Linter `_, ensuring it adheres to the standard. Ruff """" -``esptool.py`` is `PEP8 `_ compliant and enforces this style guide. For compliance checking, we use `ruff `_. +``esptool`` is `PEP8 `_ compliant and enforces this style guide. For compliance checking, we use `ruff `_. ``Ruff`` also auto-format files in the same style as previously used ``black``. @@ -104,13 +106,13 @@ Ruff When you submit a Pull Request, the GitHub Actions automated build system will run automated checks using these tools. -Shinx-lint -"""""""""" +Sphinx-Lint +""""""""""" The documentation is checked for stylistic and formal issues by ``sphinx-lint``. -Codespell check +Codespell Check """"""""""""""" This repository utilizes an automatic `spell checker `_ integrated into the pre-commit process. If any spelling issues are detected, the recommended corrections will be applied automatically to the file, ready for commit. @@ -120,22 +122,22 @@ In the event of false positives, you can adjust the configuration in the `.codes Automated Integration Tests ^^^^^^^^^^^^^^^^^^^^^^^^^^^ -The test directory contains a `pytest `_ integration suite with some integration tests for ``esptool.py``, ``espefuse.py``, and ``espsecure.py``. +The test directory contains a `pytest `_ integration suite with some integration tests for ``esptool``, ``espefuse``, and ``espsecure``. -It is necessary to have ``esptool.py`` installed (see `Development Setup`_) in your environment in order to run these tests. +It is necessary to have ``esptool`` installed (see `Development Setup`_) in your environment in order to run these tests. The following tests run automatically by GitHub Actions for each Pull Request. You can run them locally to check for regressions in the respective functionality: * ``test_imagegen.py`` tests the ``elf2image`` command -* ``test_image_info.py`` tests the ``image_info`` command -* ``test_mergebin.py`` tests the ``merge_bin`` command -* ``test_modules.py`` tests the modules used by ``esptool.py`` for regressions -* ``test_espsecure.py`` tests ``espsecure.py`` functionality -* ``test_espsecure_hsm.py`` tests support of external HSM signing in ``espsecure.py``. These tests require additional prerequisites, see ``SoftHSM2 setup`` in the `tests workflow definition `_ for more information. +* ``test_image_info.py`` tests the ``image-info`` command +* ``test_mergebin.py`` tests the ``merge-bin`` command +* ``test_modules.py`` tests the modules used by ``esptool`` for regressions +* ``test_espsecure.py`` tests ``espsecure`` functionality +* ``test_espsecure_hsm.py`` tests support of external HSM signing in ``espsecure``. These tests require additional prerequisites, see ``SoftHSM2 setup`` in the `tests workflow definition `_ for more information. The following tests are not run automatically by GitHub Actions, because they need real connected hardware. Therefore, they need to be run locally in a command line: -* ``test_esptool.py`` contains integration tests for ``esptool.py`` and needs to be run against real Espressif hardware with the following format: +* ``test_esptool.py`` contains integration tests for ``esptool`` and needs to be run against real Espressif hardware with the following format: ``pytest test_esptool.py --port --chip --baud `` @@ -143,7 +145,7 @@ The following tests are not run automatically by GitHub Actions, because they ne ``pytest test_esptool.py --port /dev/ttyUSB0 --chip esp32 --baud 230400`` - Or to run the TestFlashing suite only (using the pytest ``-k`` option to select tests based on their name) on an ESP8266 board connected to /dev/ttyUSB2, at 460800bps: + Or to run the ``TestFlashing`` suite only (using the pytest ``-k`` option to select tests based on their name) on an ESP8266 board connected to /dev/ttyUSB2, at 460800bps: ``pytest test_esptool.py --port /dev/ttyUSB2 --chip esp8266 --baud 460800 -k TestFlashing`` @@ -151,15 +153,15 @@ The following tests are not run automatically by GitHub Actions, because they ne Some tests might fail at higher baud rates on some hardware. -* ``test_esptool_sdm.py`` contains integration tests for ``esptool.py`` with chips in secure download mode. It needs to be run against real Espressif hardware (with active SDM). The command line format is the same as for ``test_esptool.py``. +* ``test_esptool_sdm.py`` contains integration tests for ``esptool`` with chips in secure download mode. It needs to be run against real Espressif hardware (with active SDM). The command line format is the same as for ``test_esptool.py``. The following tests are not run automatically by GitHub Actions, but can be run locally in a command line: -* ``test_espefuse.py`` tests ``espefuse.py`` functionality. To run it: +* ``test_espefuse.py`` tests ``espefuse`` functionality. To run it: ``pytest test_espefuse.py --chip `` - These test use the ``--virt`` virtual mode of ``espefuse.py`` to safely test the functionality without a connection to a chip and without the possibility of affecting the actual eFuses in a real hardware. + These test use the ``--virt`` virtual mode of ``espefuse`` to safely test the functionality without a connection to a chip and without the possibility of affecting the actual eFuses in a real hardware. .. warning:: @@ -171,9 +173,7 @@ The whole test suite (without the tests needing an actual hardware or installati Pull Request Process -------------------- -.. note:: - - If you are developing the stub flasher and plan to send a pull request, please use the latest toolchains available. +If you would like to contribute to the flasher stub, please see the `Flasher stub repository `_. After you open the Pull Request, there will probably be some discussion in the comments field of the request itself. diff --git a/tools/esptool_py/MANIFEST.in b/tools/esptool_py/MANIFEST.in index f135efaa6f..38de7b16ca 100644 --- a/tools/esptool_py/MANIFEST.in +++ b/tools/esptool_py/MANIFEST.in @@ -3,7 +3,7 @@ include LICENSE include esptool/targets/stub_flasher/1/* include esptool/targets/stub_flasher/2/* include espefuse/efuse_defs/*.yaml -# sdist includes test/test*.py by default, but esptool.py tests +# sdist includes test/test*.py by default, but esptool tests # are so far only intended to run from the git repo itself prune test prune .github diff --git a/tools/esptool_py/README.md b/tools/esptool_py/README.md index afb83bc198..40815f468e 100644 --- a/tools/esptool_py/README.md +++ b/tools/esptool_py/README.md @@ -1,20 +1,20 @@ -# esptool.py +# esptool -A Python-based, open-source, platform-independent utility to communicate with the ROM bootloader in Espressif chips. +A Python-based, open-source, platform-independent serial utility for flashing, provisioning, and interacting with Espressif SoCs. [![Test esptool](https://github.com/espressif/esptool/actions/workflows/test_esptool.yml/badge.svg?branch=master)](https://github.com/espressif/esptool/actions/workflows/test_esptool.yml) [![Build esptool](https://github.com/espressif/esptool/actions/workflows/build_esptool.yml/badge.svg?branch=master)](https://github.com/espressif/esptool/actions/workflows/build_esptool.yml) ## Documentation -Visit the [documentation](https://docs.espressif.com/projects/esptool/) or run `esptool.py -h`. +Visit the [documentation](https://docs.espressif.com/projects/esptool/) or run `esptool -h`. ## Contribute -If you're interested in contributing to esptool.py, please check the [contributions guide](https://docs.espressif.com/projects/esptool/en/latest/contributing.html). +If you're interested in contributing to esptool, please check the [contributions guide](https://docs.espressif.com/projects/esptool/en/latest/contributing.html). ## About -esptool.py was initially created by Fredrik Ahlberg (@[themadinventor](https://github.com/themadinventor/)), and later maintained by Angus Gratton (@[projectgus](https://github.com/projectgus/)). It is now supported by Espressif Systems. It has also received improvements from many members of the community. +esptool was initially created by Fredrik Ahlberg (@[themadinventor](https://github.com/themadinventor/)), and later maintained by Angus Gratton (@[projectgus](https://github.com/projectgus/)). It is now supported by Espressif Systems. It has also received improvements from many members of the community. ## License diff --git a/tools/esptool_py/ci/download_flasher_stubs.py b/tools/esptool_py/ci/download_flasher_stubs.py index 8f34c41296..935e8f2a12 100755 --- a/tools/esptool_py/ci/download_flasher_stubs.py +++ b/tools/esptool_py/ci/download_flasher_stubs.py @@ -1,6 +1,6 @@ #!/usr/bin/env python # -# SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD +# SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD # SPDX-License-Identifier: GPL-2.0-or-later import glob @@ -12,42 +12,43 @@ "STUB_SET_VERSION": "1", "DOWNLOAD_URL": "https://github.com/espressif/esptool-legacy-flasher-stub/releases/download", "TAG_URL": "https://github.com/espressif/esptool-legacy-flasher-stub/releases/tag", - "VERSION": "v1.3.0", + "VERSION": "v1.6.0", "FILE_LIST": ( "esp32", "esp32c2", "esp32c3", "esp32c5", - "esp32c5beta3", "esp32c6", "esp32c61", - "esp32c6beta", "esp32h2", - "esp32h2beta1", - "esp32h2beta2", "esp32p4", "esp32s2", "esp32s3", - "esp32s3beta2", "esp8266", ), - "LICENSE": "released as Free Software under GNU General Public License Version 2 or later", + "LICENSE": "released as Free Software under GNU General Public License " + "Version 2 or later", }, { "STUB_SET_VERSION": "2", - "DOWNLOAD_URL": "https://github.com/esp-rs/esp-flasher-stub/releases/download", - "TAG_URL": "https://github.com/esp-rs/esp-flasher-stub/releases/tag", - "VERSION": "v0.3.0", + "DOWNLOAD_URL": "https://github.com/espressif/esp-flasher-stub/releases/download", + "TAG_URL": "https://github.com/espressif/esp-flasher-stub/releases/tag", + "VERSION": "v0.1.0", "FILE_LIST": ( "esp32", "esp32c2", "esp32c3", + "esp32c5", "esp32c6", + "esp32c61", "esp32h2", + "esp32p4", "esp32s2", "esp32s3", + "esp8266", ), - "LICENSE": "dual licensed under the Apache License Version 2.0 or the MIT license", + "LICENSE": "dual licensed under the Apache License Version 2.0 or the MIT " + "license", }, ) @@ -56,16 +57,17 @@ README_TEMPLATE = """# Licensing The binaries in JSON format distributed in this directory are {LICENSE}. They were released at {URL} from where the sources can be obtained. -""" +""" # noqa: E501 def main(): for stub_set in STUBS: dest_sub_dir = os.path.join(DESTINATION_DIR, stub_set["STUB_SET_VERSION"]) - """ The directory is cleaned up so we would detect if a stub was just committed into the repository but the - name was not added into the FILE_LIST of STUBS. This would be an unwanted state because the checker would not - detect any changes in that stub.""" + """ The directory is cleaned up so we would detect if a stub was just committed + into the repository but the name was not added into the FILE_LIST of STUBS. + This would be an unwanted state because the checker would not detect any + changes in that stub.""" for old_file in glob.glob(os.path.join(dest_sub_dir, "*.json")): print(f"Removing old file {old_file}") os.remove(old_file) diff --git a/tools/esptool_py/docs/_static/esptool_versions.js b/tools/esptool_py/docs/_static/esptool_versions.js index 409ecf2e9b..0cc53dd148 100644 --- a/tools/esptool_py/docs/_static/esptool_versions.js +++ b/tools/esptool_py/docs/_static/esptool_versions.js @@ -1,8 +1,11 @@ var DOCUMENTATION_VERSIONS = { - DEFAULTS: { has_targets: false, + DEFAULTS: { has_targets: true, supported_targets: [ "esp32" ] }, - VERSIONS: [ ], + VERSIONS: [ + { name: "latest", old: false, pre_release: false, supported_targets: [ "esp8266", "esp32", "esp32s2", "esp32s3", "esp32c3", "esp32c2", "esp32c6", "esp32p4", "esp32h2", "esp32c5", "esp32c61" ] }, + { name: "release-v4", old: false, pre_release: false, supported_targets: [ "esp8266", "esp32", "esp32s2", "esp32s3", "esp32c3", "esp32c2", "esp32c6", "esp32p4", "esp32h2", "esp32c5", "esp32c61" ] }, + ], IDF_TARGETS: [ { text: "ESP8266", value: "esp8266" }, { text: "ESP32", value: "esp32" }, @@ -13,5 +16,7 @@ var DOCUMENTATION_VERSIONS = { { text: "ESP32-C6", value: "esp32c6" }, { text: "ESP32-H2", value: "esp32h2" }, { text: "ESP32-P4", value: "esp32p4" }, + { text: "ESP32-C5", value: "esp32c5" }, + { text: "ESP32-C61", value: "esp32c61" }, ] }; diff --git a/tools/esptool_py/docs/conf_common.py b/tools/esptool_py/docs/conf_common.py index 03e69fc861..4edae78bc4 100644 --- a/tools/esptool_py/docs/conf_common.py +++ b/tools/esptool_py/docs/conf_common.py @@ -11,6 +11,8 @@ "esp32c6", "esp32h2", "esp32p4", + "esp32c5", + "esp32c61", ] # link roles config @@ -23,7 +25,14 @@ html_static_path = ["../_static"] # Conditional content -extensions += ["esp_docs.esp_extensions.dummy_build_system"] +extensions += [ + "esp_docs.esp_extensions.dummy_build_system", + "sphinx.ext.autodoc", + "sphinx.ext.napoleon", + "sphinx_tabs.tabs", +] + +sphinx_tabs_disable_tab_closing = True ESP8266_DOCS = [] @@ -42,9 +51,15 @@ "esp32c6": ESP32_DOCS, "esp32h2": ESP32_DOCS, "esp32p4": ESP32_DOCS, + "esp32c5": ESP32_DOCS, + "esp32c61": ESP32_DOCS, } # Extra options required by sphinx_idf_theme project_slug = "esptool" versions_url = "./_static/esptool_versions.js" + + +def conf_setup(app, config): + config.html_baseurl = f"https://docs.espressif.com/projects/esptool/{config.language}/stable/{config.idf_target}/" diff --git a/tools/esptool_py/docs/en/advanced-topics/boot-mode-selection.rst b/tools/esptool_py/docs/en/advanced-topics/boot-mode-selection.rst index dfa4a04e37..ee1eb54326 100644 --- a/tools/esptool_py/docs/en/advanced-topics/boot-mode-selection.rst +++ b/tools/esptool_py/docs/en/advanced-topics/boot-mode-selection.rst @@ -1,8 +1,8 @@ -{IDF_TARGET_STRAP_BOOT_GPIO:default="GPIO9", esp32="GPIO0", esp32s2="GPIO0", esp32s3="GPIO0", esp32p4="GPIO35"} +{IDF_TARGET_STRAP_BOOT_GPIO:default="GPIO9", esp8266="GPIO0", esp32="GPIO0", esp32s2="GPIO0", esp32s3="GPIO0", esp32p4="GPIO35", esp32c5="GPIO28"} -{IDF_TARGET_STRAP_BOOT_2_GPIO:default="GPIO8", esp32="GPIO2", esp32s2="GPIO46", esp32s3="GPIO46", esp32p4="GPIO36"} +{IDF_TARGET_STRAP_BOOT_2_GPIO:default="GPIO8", esp32="GPIO2", esp32s2="GPIO46", esp32s3="GPIO46", esp32p4="GPIO36", esp32c5="GPIO27"} -{IDF_TARGET_BOOTLOADER_OFFSET:default="0", esp32="1000", esp32s2="1000", esp32p4="2000"} +{IDF_TARGET_BOOTLOADER_OFFSET:default="0x0", esp32="0x1000", esp32s2="0x1000", esp32p4="0x2000", esp32c5="0x2000"} .. _boot-mode: @@ -53,9 +53,9 @@ This guide explains how to select the boot mode correctly and describes the boot The {IDF_TARGET_NAME} has a 45k ohm internal pull-up/pull-down resistor at {IDF_TARGET_STRAP_BOOT_GPIO} (and other pins). If you want to connect a switch button to enter the boot mode, this has to be a strong pull-down. For example a 10k resistor to GND. - Information about {IDF_TARGET_NAME} strapping pins can also be found in the `{IDF_TARGET_NAME} Datasheet `__, section "Strapping Pins". + Information about {IDF_TARGET_NAME} strapping pins can also be found in the `{IDF_TARGET_NAME} Datasheet <{IDF_TARGET_DATASHEET_EN_URL}>`__, section "Strapping Pins". - On many development boards with built-in USB/Serial, ``esptool.py`` can automatically reset the board into bootloader mode. For other configurations or custom hardware, you will need to check the orientation of some "strapping pins" to get the correct boot mode: + On many development boards with built-in USB/Serial, ``esptool`` can automatically reset the board into bootloader mode. For other configurations or custom hardware, you will need to check the orientation of some "strapping pins" to get the correct boot mode: Select Bootloader Mode ---------------------- @@ -87,7 +87,7 @@ This guide explains how to select the boot mode correctly and describes the boot {IDF_TARGET_STRAP_BOOT_2_GPIO} must also be either left unconnected/floating, or driven Low, in order to enter the serial bootloader. - .. only:: esp32c3 or esp32c2 or esp32h2 or esp32c6 or esp32p4 + .. only:: esp32c3 or esp32c2 or esp32h2 or esp32c6 or esp32p4 or esp32c5 or esp32c61 {IDF_TARGET_STRAP_BOOT_2_GPIO} must also be driven High, in order to enter the serial bootloader reliably. The strapping combination of {IDF_TARGET_STRAP_BOOT_2_GPIO} = 0 and {IDF_TARGET_STRAP_BOOT_GPIO} = 0 is invalid and will trigger unexpected behavior. @@ -99,7 +99,7 @@ This guide explains how to select the boot mode correctly and describes the boot .. only:: not esp32 - As well as the above mentioned pins, other ones influence the serial bootloader, please consult the `{IDF_TARGET_NAME} Datasheet `__, section "Strapping Pins". + As well as the above mentioned pins, other ones influence the serial bootloader, please consult the `{IDF_TARGET_NAME} Datasheet <{IDF_TARGET_DATASHEET_EN_URL}>`__, section "Strapping Pins". .. only:: esp32 @@ -113,23 +113,23 @@ This guide explains how to select the boot mode correctly and describes the boot | 15 (MTDO) | If driven Low, silences boot messages printed by the ROM bootloader. Has an internal pull-up, so unconnected = High = normal output. | +-------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - For more information, consult the `{IDF_TARGET_NAME} Datasheet `__, section "Strapping Pins". + For more information, consult the `{IDF_TARGET_NAME} Datasheet <{IDF_TARGET_DATASHEET_EN_URL}>`__, section "Strapping Pins". .. _automatic-bootloader: Automatic Bootloader -------------------- -``esptool.py`` resets {IDF_TARGET_NAME} automatically by asserting ``DTR`` and ``RTS`` control lines of the USB to serial converter chip, i.e., FTDI, CP210x, or CH340x. The ``DTR`` and ``RTS`` control lines are in turn connected to ``{IDF_TARGET_STRAP_BOOT_GPIO}`` and ``EN`` (``CHIP_PU``) pins of {IDF_TARGET_NAME}, thus changes in the voltage levels of ``DTR`` and ``RTS`` will boot the {IDF_TARGET_NAME} into Firmware Download mode. +``esptool`` resets {IDF_TARGET_NAME} automatically by asserting ``DTR`` and ``RTS`` control lines of the USB to serial converter chip, i.e., FTDI, CP210x, or CH340x. The ``DTR`` and ``RTS`` control lines are in turn connected to ``{IDF_TARGET_STRAP_BOOT_GPIO}`` and ``EN`` (``CHIP_PU``) pins of {IDF_TARGET_NAME}, thus changes in the voltage levels of ``DTR`` and ``RTS`` will boot the {IDF_TARGET_NAME} into Firmware Download mode. .. note:: - When developing ``esptool.py``, keep in mind ``DTR`` and ``RTS`` are active low signals, i.e., ``True`` = pin @ 0V, ``False`` = pin @ VCC. + When developing ``esptool``, keep in mind ``DTR`` and ``RTS`` are active low signals, i.e., ``True`` = pin @ 0V, ``False`` = pin @ VCC. As an example of auto-reset curcuitry implementation, check the `schematic `_ of the ESP32 DevKitC development board: - The **Micro USB 5V & USB-UART** section shows the ``DTR`` and ``RTS`` control lines of the USB to serial converter chip connected to ``{IDF_TARGET_STRAP_BOOT_GPIO}`` and ``EN`` pins of the ESP module. -- Some OS and/or drivers may activate ``RTS`` and or ``DTR`` automatically when opening the serial port (true only for some serial terminal programs, not ``esptool.py``), pulling them low together and holding the ESP in reset. If ``RTS`` is wired directly to ``EN`` then RTS/CTS "hardware flow control" needs to be disabled in the serial program to avoid this. +- Some OS and/or drivers may activate ``RTS`` and or ``DTR`` automatically when opening the serial port (true only for some serial terminal programs, not ``esptool``), pulling them low together and holding the ESP in reset. If ``RTS`` is wired directly to ``EN`` then RTS/CTS "hardware flow control" needs to be disabled in the serial program to avoid this. An additional circuitry is implemented in order to avoid this problem - if both ``RTS`` and ``DTR`` are asserted together, this doesn't reset the chip. The schematic shows this specific circuit with two transistors and its truth table. - If this circuitry is implemented (all Espressif boards have it), adding a capacitor between the ``EN`` pin and ``GND`` (in the 1uF-10uF range) is necessary for the reset circuitry to work reliably. This is shown in the **ESP32 Module** section of the schematic. - The **Switch Button** section shows buttons needed for :ref:`manually switching to bootloader `. @@ -150,7 +150,7 @@ In Linux serial ports by default will assert RTS when nothing is attached to the (Some third party {IDF_TARGET_NAME} development boards use an automatic reset circuit for ``EN`` & ``{IDF_TARGET_STRAP_BOOT_GPIO}`` pins, but don't add a capacitor on the ``EN`` pin. This results in unreliable automatic reset, especially on Windows. Adding a 1uF (or higher) value capacitor between ``EN`` pin and ``GND`` may make automatic reset more reliable.) -In general, you should have no problems with the official Espressif development boards. However, ``esptool.py`` is not able to reset your hardware automatically in the following cases: +In general, you should have no problems with the official Espressif development boards. However, ``esptool`` is not able to reset your hardware automatically in the following cases: - Your hardware does not have the ``DTR`` and ``RTS`` lines connected to ``{IDF_TARGET_STRAP_BOOT_GPIO}`` and ``EN`` (``CHIP_PU``) - The ``DTR`` and ``RTS`` lines are configured differently @@ -224,7 +224,7 @@ Depending on the kind of hardware you have, it may also be possible to manually **chksum:** - If value of “chksum” == value of “csum”, it means flash has been read correctly during booting. + If value of "chksum" == value of "csum", it means flash has been read correctly during booting. The rest of boot messages are used internally by Espressif. @@ -290,15 +290,23 @@ Depending on the kind of hardware you have, it may also be possible to manually Early Flash Read Error """""""""""""""""""""" - :: + .. only:: esp8266 + + :: + + flash read err, 0 + + .. only:: not esp8266 + + :: - flash read err, {IDF_TARGET_BOOTLOADER_OFFSET} + Invalid header - This fatal error indicates that the bootloader tried to read the software bootloader header at address 0x{IDF_TARGET_BOOTLOADER_OFFSET} but failed to read valid data. Possible reasons for this include: + This fatal error indicates that the bootloader tried to read the software bootloader header at address {IDF_TARGET_BOOTLOADER_OFFSET} but failed to read valid data. Possible reasons for this include: .. list:: - - There isn't actually a bootloader at offset 0x{IDF_TARGET_BOOTLOADER_OFFSET} (maybe the bootloader was flashed to the wrong offset by mistake, or the flash has been erased and no bootloader has been flashed yet.) + - There isn't actually a bootloader at offset {IDF_TARGET_BOOTLOADER_OFFSET} (maybe the bootloader was flashed to the wrong offset by mistake, or the flash has been erased and no bootloader has been flashed yet.) - Physical problem with the connection to the flash chip, or flash chip power. - Flash encryption is enabled but the bootloader is plaintext. Alternatively, flash encryption is disabled but the bootloader is encrypted ciphertext. @@ -326,7 +334,7 @@ Depending on the kind of hardware you have, it may also be possible to manually mode:DIO, clock div:1 - This is normal boot output based on a combination of eFuse values and information read from the bootloader header at flash offset 0x{IDF_TARGET_BOOTLOADER_OFFSET}: + This is normal boot output based on a combination of eFuse values and information read from the bootloader header at flash offset {IDF_TARGET_BOOTLOADER_OFFSET}: .. list:: @@ -339,10 +347,10 @@ Depending on the kind of hardware you have, it may also be possible to manually - ``SPIWP:0xNN`` indicates a custom ``WP`` pin value, which is stored in the bootloader header. This pin value is only used if SPI flash pins have been remapped via eFuse (as shown in the ``configsip`` value). All custom pin values but WP are encoded in the configsip byte loaded from eFuse, and WP is supplied in the bootloader header. :esp32: - ``clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00`` Custom GPIO drive strength values for SPI flash pins. These are read from the bootloader header in flash. Not currently supported. - - ``mode: AAA, clock div: N``. SPI flash access mode. Read from the bootloader header, correspond to the ``--flash_mode`` and ``--flash_freq`` arguments supplied to ``esptool.py write_flash`` or ``esptool.py elf2image``. + - ``mode: AAA, clock div: N``. SPI flash access mode. Read from the bootloader header, correspond to the ``--flash-mode`` and ``--flash-freq`` arguments supplied to ``esptool write-flash`` or ``esptool elf2image``. - ``mode`` can be DIO, DOUT, QIO, or QOUT. *QIO and QOUT are not supported here*, to boot in a Quad I/O mode the ROM bootloader should load the software bootloader in a Dual I/O mode and then the ESP-IDF software bootloader enables Quad I/O based on the detected flash chip mode. - - ``clock div: N`` is the SPI flash clock frequency divider. This is an integer clock divider value from an 80MHz APB clock, based on the supplied ``--flash_freq`` argument (ie 80MHz=1, 40MHz=2, etc). - The ROM bootloader actually loads the software bootloader at a lower frequency than the flash_freq value. The initial APB clock frequency is equal to the crystal frequency, so with a 40MHz crystal the SPI clock used to load the software bootloader will be half the configured value (40MHz/2=20MHz). + - ``clock div: N`` is the SPI flash clock frequency divider. This is an integer clock divider value from an 80MHz APB clock, based on the supplied ``--flash-freq`` argument (ie 80MHz=1, 40MHz=2, etc). + The ROM bootloader actually loads the software bootloader at a lower frequency than the ``--flash-freq`` value. The initial APB clock frequency is equal to the crystal frequency, so with a 40MHz crystal the SPI clock used to load the software bootloader will be half the configured value (40MHz/2=20MHz). When the software bootloader starts it sets the APB clock to 80MHz causing the SPI clock frequency to match the value set when flashing. Software Bootloader Load Segments @@ -358,7 +366,7 @@ Depending on the kind of hardware you have, it may also be possible to manually These entries are printed as the ROM bootloader loads each segment in the software bootloader image. The load address and length of each segment is printed. - You can compare these values to the software bootloader image by running ``esptool.py --chip {IDF_TARGET_PATH_NAME} image_info /path/to/bootloader.bin`` to dump image info including a summary of each segment. Corresponding details will also be found in the bootloader ELF file headers. + You can compare these values to the software bootloader image by running ``esptool --chip {IDF_TARGET_PATH_NAME} image-info /path/to/bootloader.bin`` to dump image info including a summary of each segment. Corresponding details will also be found in the bootloader ELF file headers. If there is a problem with the SPI flash chip addressing mode, the values printed by the bootloader here may be corrupted. diff --git a/tools/esptool_py/docs/en/advanced-topics/diag/firmware_image_ext_header_format.diag b/tools/esptool_py/docs/en/advanced-topics/diag/firmware_image_ext_header_format.diag new file mode 100644 index 0000000000..1c3d8c95b4 --- /dev/null +++ b/tools/esptool_py/docs/en/advanced-topics/diag/firmware_image_ext_header_format.diag @@ -0,0 +1,15 @@ +packetdiag command_packet_format{ + colwidth = 16 + node_width = 50 + node_height = 50 + default_fontsize = 16 + + 0: "WP"; + 1-3: "Drive settings"; + 4-5: "Chip ID"; + 6: "Rev." [color = grey]; + 7-8: "Min rev."; + 9-10: "Max rev."; + 11-14: "Reserved" [color = grey]; + 15: "Hash"; +} diff --git a/tools/esptool_py/docs/en/advanced-topics/diag/firmware_image_format.diag b/tools/esptool_py/docs/en/advanced-topics/diag/firmware_image_format.diag new file mode 100644 index 0000000000..7566c37e5f --- /dev/null +++ b/tools/esptool_py/docs/en/advanced-topics/diag/firmware_image_format.diag @@ -0,0 +1,12 @@ +packetdiag command_packet_format{ + colwidth = 16 + node_width = 50 + node_height = 50 + default_fontsize = 16 + + 0-7: "Image header"; + 8-23: "Image extended header"; + 24-31: "Segmets" [color = lightgrey]; + 32-47: "..." [color = lightgrey]; + 48-63: "Footer"; +} diff --git a/tools/esptool_py/docs/en/advanced-topics/diag/firmware_image_format_esp8266.diag b/tools/esptool_py/docs/en/advanced-topics/diag/firmware_image_format_esp8266.diag new file mode 100644 index 0000000000..8b94afbd0c --- /dev/null +++ b/tools/esptool_py/docs/en/advanced-topics/diag/firmware_image_format_esp8266.diag @@ -0,0 +1,11 @@ +packetdiag command_packet_format{ + colwidth = 16 + node_width = 50 + node_height = 50 + default_fontsize = 16 + + 0-7: "Image header"; + 8-23: "Segmets" [color = lightgrey]; + 24-31: "..." [color = lightgrey]; + 32-47: "Footer"; +} diff --git a/tools/esptool_py/docs/en/advanced-topics/diag/firmware_image_header_format.diag b/tools/esptool_py/docs/en/advanced-topics/diag/firmware_image_header_format.diag new file mode 100644 index 0000000000..bc230811f5 --- /dev/null +++ b/tools/esptool_py/docs/en/advanced-topics/diag/firmware_image_header_format.diag @@ -0,0 +1,12 @@ +packetdiag command_packet_format{ + colwidth = 8 + node_width = 100 + node_height = 50 + default_fontsize = 16 + + 0: "0xE9"; + 1: "Number of\nsegments"; + 2: "Flash Mode"; + 3: "Flash\nsize/freq"; + 4-7: "Entry point"; +} diff --git a/tools/esptool_py/docs/en/advanced-topics/firmware-image-format.rst b/tools/esptool_py/docs/en/advanced-topics/firmware-image-format.rst index 10d81bb576..66f6fe1d58 100644 --- a/tools/esptool_py/docs/en/advanced-topics/firmware-image-format.rst +++ b/tools/esptool_py/docs/en/advanced-topics/firmware-image-format.rst @@ -6,7 +6,7 @@ {IDF_TARGET_FLASH_FREQ_2:default="20", esp32c2="15", esp32h2="12"} -{IDF_TARGET_BOOTLOADER_OFFSET:default="0x0", esp32="0x1000", esp32s2="0x1000", esp32p4="0x2000"} +{IDF_TARGET_BOOTLOADER_OFFSET:default="0x0", esp32="0x1000", esp32s2="0x1000", esp32p4="0x2000", esp32c5="0x2000"} .. _image-format: @@ -14,19 +14,31 @@ Firmware Image Format ===================== -This is technical documentation for the firmware image format used by the ROM bootloader. These are the images created by ``esptool.py elf2image``. +This is technical documentation for the firmware image format used by the ROM bootloader. These are the images created by ``esptool elf2image``. .. only:: esp8266 + .. packetdiag:: diag/firmware_image_format_esp8266.diag + :caption: Firmware image format + :align: center + The firmware file consists of a header, a variable number of data segments and a footer. Multi-byte fields are little-endian. .. only:: not esp8266 + .. packetdiag:: diag/firmware_image_format.diag + :caption: Firmware image format + :align: center + The firmware file consists of a header, an extended header, a variable number of data segments and a footer. Multi-byte fields are little-endian. File Header ----------- +.. packetdiag:: diag/firmware_image_header_format.diag + :caption: Firmware image header + :align: center + The image header is 8 bytes long: .. only:: esp8266 @@ -91,7 +103,25 @@ The image header is 8 bytes long: Flash frequency with value ``0`` can mean either 80MHz or 40MHz based on MSPI clock source mode. -.. only:: not (esp8266 or esp32c6 or esp32s3 or esp32s2 or esp32p4) +.. only:: esp32c5 or esp32c61 + + +--------+------------------------------------------------------------------------------------------------+ + | Byte | Description | + +========+================================================================================================+ + | 0 | Magic number (always ``0xE9``) | + +--------+------------------------------------------------------------------------------------------------+ + | 1 | Number of segments | + +--------+------------------------------------------------------------------------------------------------+ + | 2 | SPI Flash Mode (``0`` = QIO, ``1`` = QOUT, ``2`` = DIO, ``3`` = DOUT) | + +--------+------------------------------------------------------------------------------------------------+ + | 3 | High four bits - Flash size (``0`` = 1MB, ``1`` = 2MB, ``2`` = 4MB, ``3`` = 8MB, ``4`` = 16MB) | + | | | + | | Low four bits - Flash frequency (``0xf`` = {IDF_TARGET_FLASH_FREQ_F}MHz, ``0`` = {IDF_TARGET_FLASH_FREQ_0}MHz, ``2`` = {IDF_TARGET_FLASH_FREQ_2}MHz) | + +--------+------------------------------------------------------------------------------------------------+ + | 4-7 | Entry point address | + +--------+------------------------------------------------------------------------------------------------+ + +.. only:: not (esp8266 or esp32c6 or esp32s3 or esp32s2 or esp32p4 or esp32c5 or esp32c61) +--------+------------------------------------------------------------------------------------------------+ | Byte | Description | @@ -110,7 +140,10 @@ The image header is 8 bytes long: +--------+------------------------------------------------------------------------------------------------+ -``esptool.py`` overrides the 2nd and 3rd (counted from 0) bytes according to the SPI flash info provided through the command line option. These bytes are only overridden if this is a bootloader image (an image written to a correct bootloader offset of {IDF_TARGET_BOOTLOADER_OFFSET}), in this case, the appended SHA256 digest is also updated to reflect the header changes. Generating images without SHA256 digest can be achieved by running ``esptool.py elf2image`` with the ``--dont-append-digest`` argument. +``esptool`` overrides the 2nd and 3rd (counted from 0) bytes according to the SPI flash info provided through the command line options (see :ref:`flash-modes`). +These bytes are only overridden if this is a bootloader image (an image written to a correct bootloader offset of {IDF_TARGET_BOOTLOADER_OFFSET}). +In this case, the appended SHA256 digest, which is a cryptographic hash used to verify the integrity of the image, is also updated to reflect the header changes. +Generating images without SHA256 digest can be achieved by running ``esptool elf2image`` with the ``--dont-append-digest`` argument. .. only:: esp8266 @@ -121,12 +154,14 @@ The image header is 8 bytes long: Extended File Header -------------------- - The 16-byte long extended header comes right after the image header, individual segments come right after it: + .. packetdiag:: diag/firmware_image_ext_header_format.diag + :caption: Extended File Header + :align: center +--------+---------------------------------------------------------------------------------------------------------+ | Byte | Description | +========+=========================================================================================================+ - | 0 | WP pin when SPI pins set via efuse (read by ROM bootloader) | + | 0 | WP pin when SPI pins set via eFuse (read by ROM bootloader) | +--------+---------------------------------------------------------------------------------------------------------+ | 1-3 | Drive settings for the SPI flash pins (read by ROM bootloader) | +--------+---------------------------------------------------------------------------------------------------------+ @@ -171,4 +206,4 @@ The file is padded with zeros until its size is one byte less than a multiple of Analyzing a Binary Image ------------------------ -To analyze a binary image and get a complete summary of its headers and segments, use the :ref:`image_info ` command with the ``--version 2`` option. +To analyze a binary image and get a complete summary of its headers and segments, use the :ref:`image-info ` command. diff --git a/tools/esptool_py/docs/en/advanced-topics/serial-protocol.rst b/tools/esptool_py/docs/en/advanced-topics/serial-protocol.rst index 48c85eec93..17b0152278 100644 --- a/tools/esptool_py/docs/en/advanced-topics/serial-protocol.rst +++ b/tools/esptool_py/docs/en/advanced-topics/serial-protocol.rst @@ -1,5 +1,7 @@ {IDF_TARGET_SECURITY_INFO:default="32 bits ``flags``, 1 byte ``flash_crypt_cnt``, 7x1 byte ``key_purposes``, 32-bit word ``chip_id``, 32-bit word ``eco_version``", esp32s2="32 bits ``flags``, 1 byte ``flash_crypt_cnt``, 7x1 byte ``key_purposes`` "} +.. _serial-protocol: + Serial Protocol =============== @@ -7,11 +9,7 @@ This is technical documentation for the serial protocol used by the UART bootloa The UART bootloader runs on chip reset if certain strapping pins are set. See :ref:`entering-the-bootloader` for details of this process. -.. only:: not esp8266 - - The {IDF_TARGET_NAME} ROM loader serial protocol is similar to ESP8266, although {IDF_TARGET_NAME} adds some additional commands and some slightly different behaviour. - -By default, esptool uploads a stub "software loader" to the IRAM of the chip. The stub loader then replaces the ROM loader for all future interactions. This standardizes much of the behaviour. Pass ``--no-stub`` to esptool in order to disable the stub loader. See :ref:`stub` for more information. +By default, esptool uploads a stub "software loader" to the IRAM of the chip. The stub loader then replaces the ROM loader for all future interactions. This standardizes much of the behavior. Pass ``--no-stub`` to esptool in order to disable the stub loader. See :ref:`stub` for more information. .. note:: @@ -78,7 +76,7 @@ Each received command will result in a response SLIP packet sent from the ESP ch | 8..n | Data | Variable length data payload. Length indicated by "Size" field. | +--------+-------------+--------------------------------------------------------------------------------------------------------------+ -Status bytes +Status Bytes """""""""""" The final bytes of the Data payload indicate command status: @@ -153,7 +151,7 @@ After sending a command, the host should continue to read response packets until Commands ^^^^^^^^ -Supported by stub loader and ROM loader +Supported by Stub Loader and ROM Loader """"""""""""""""""""""""""""""""""""""" .. only:: esp8266 @@ -259,10 +257,10 @@ Supported by stub loader and ROM loader | ``0x14`` | GET_SECURITY_INFO | Read chip security info | | {IDF_TARGET_SECURITY_INFO} | +------------+----------------------+----------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------+ -Supported by stub loader only +Supported by Stub Loader Only """"""""""""""""""""""""""""" -ROM loaders will not recognise these commands. +ROM loaders will not recognize these commands. +------------+-------------------+-----------------------------------+-------------------------------------------------------------------------------------------------------------------------+----------+ | Byte | Name | Description | Input | Output | @@ -349,7 +347,7 @@ All three of these sequences follow a similar pattern: * An _END command (FLASH_END, etc) is sent to exit the bootloader and optionally reset the chip (or jump to an address in RAM, in the case of MEM_END). Not necessary to send after flashing if you wish to continue sending other or different commands. It's not necessary to send flash erase commands before sending commands to write to flash, etc. The ROM loaders erase the to-be-written region in response to the FLASH_BEGIN command. -The stub loader does just-in-time erasing as it writes data, to maximise overall flashing performance (each block of data is read into RAM via serial while the previous block is simultaneously being written to flash, and 4KB and 64KB erases are done as needed before writing to flash). +The stub loader does just-in-time erasing as it writes data, to maximize overall flashing performance (each block of data is read into RAM via serial while the previous block is simultaneously being written to flash, and 4KB and 64KB erases are done as needed before writing to flash). The block size chosen should be small enough to fit into RAM of the device. Esptool uses 16KB which gives good performance when used with the stub loader. @@ -382,7 +380,7 @@ The SPI_FLASH_MD5 command passes the start address in flash and the size of data SPI Configuration Commands ^^^^^^^^^^^^^^^^^^^^^^^^^^ -SPI Attach command +SPI Attach Command """""""""""""""""" The SPI _ATTACH command enables the SPI flash interface. It takes a 32-bit data payload which is used to determine which SPI peripheral and pins should be used to connect to SPI flash. @@ -413,7 +411,7 @@ The SPI _ATTACH command enables the SPI flash interface. It takes a 32-bit data | (other values) | Pin numbers as 6-bit values, packed into a 30-bit value. Order (from MSB): HD pin, Q pin, D pin, CS pin, CLK pin. | +------------------+----------------------------------------------------------------------------------------------------------------------------------+ - The "Default SPI flash interface" uses pins configured via the ``SPI_PAD_CONFIG_xxx`` efuses (if unset, these efuses are all zero and the default SPI flash pins given in the datasheet are used.) + The "Default SPI flash interface" uses pins configured via the ``SPI_PAD_CONFIG_xxx`` eFuses (if unset, these eFuses are all zero and the default SPI flash pins given in the datasheet are used.) When writing the values of each pin as 6-bit numbers packed into the data word, each 6-bit value uses the following representation: @@ -421,7 +419,7 @@ The SPI _ATTACH command enables the SPI flash interface. It takes a 32-bit data * Pin numbers 0 through 30 are represented as themselves. * Pin numbers 32 & 33 are represented as values 30 & 31. - * It is not possible to represent pins 30 & 31 or pins higher than 33. This is the same 6-bit representation used by the ``SPI_PAD_CONFIG_xxx`` efuses. + * It is not possible to represent pins 30 & 31 or pins higher than 33. This is the same 6-bit representation used by the ``SPI_PAD_CONFIG_xxx`` eFuses. On {IDF_TARGET_NAME} ROM loader only, there is an additional 4 bytes in the data payload of this command. These bytes should all be set to zero. @@ -436,7 +434,7 @@ The SPI_SET_PARAMS command sets some parameters of the attached SPI flash chip ( All the values which are passed except total size are hardcoded, and most are not used when writing to flash. See `flash_set_parameters function `__ in esptool for the values which it sends. -32-bit Read/Write +32-Bit Read/Write ^^^^^^^^^^^^^^^^^ The 32-bit read/write commands (READ_REG, WRITE_REG) allow word-oriented reading and writing of memory and register data. @@ -470,11 +468,11 @@ Here is a sample extract, showing a READ_REG command and response: :: - TRACE +0.000 command op=0x0a data len=4 wait_response=1 timeout=3.000 data=1400f43f - TRACE +0.000 Write 14 bytes: c0000a0400000000001400f43fc0 - TRACE +0.005 Read 1 bytes: c0 - TRACE +0.000 Read 11 bytes: 010a0200620100000000c0 - TRACE +0.000 Received full packet: 010a0200620100000000 + TRACE +0.000 --- Cmd READ_REG (0x0a) | data_len 4 | wait_response 1 | timeout 3.000 | data 00100040 --- + TRACE +0.000 Write 14 bytes: c0000a04000000000000100040c0 + TRACE +0.046 Read 1 bytes: c0 + TRACE +0.000 Read 11 bytes: 010a0200090000000000c0 + TRACE +0.000 Received full packet: 010a0200090000000000 The +X.XXX value is the time delta (in seconds) since the last trace line. @@ -487,18 +485,18 @@ Here is a second example showing part of the initial synchronization sequence (l :: - TRACE +0.000 Write 46 bytes: - c000082400000000 0007071220555555 | ...$........ UUU - 5555555555555555 5555555555555555 | UUUUUUUUUUUUUUUU - 5555555555555555 5555555555c0 | UUUUUUUUUUUUU. - TRACE +0.011 Read 1 bytes: c0 - TRACE +0.000 Read 63 bytes: - 0108040007122055 00000000c0c00108 | ...... U........ - 0400071220550000 0000c0c001080400 | .... U.......... - 0712205500000000 c0c0010804000712 | .. U............ - 205500000000c0c0 01080400071220 | U............ - TRACE +0.000 Received full packet: 010804000712205500000000 - TRACE +0.000 Received full packet: 010804000712205500000000 + TRACE +0.000 Write 46 bytes: + c000082400000000 0007071220555555 | ...$........ UUU + 5555555555555555 5555555555555555 | UUUUUUUUUUUUUUUU + 5555555555555555 5555555555c0 | UUUUUUUUUUUUU. + TRACE +0.012 Read 1 bytes: c0 + TRACE +0.000 Read 63 bytes: + 0108040007071220 00000000c0c00108 | ....... ........ + 0400070712200000 0000c0c001080400 | ..... .......... + 0707122000000000 c0c0010804000707 | ... ............ + 122000000000c0c0 01080400070712 | . ............. + TRACE +0.000 Received full packet: 010804000707122000000000 + TRACE +0.000 Received full packet: 010804000707122000000000 .. important:: diff --git a/tools/esptool_py/docs/en/advanced-topics/spi-flash-modes.rst b/tools/esptool_py/docs/en/advanced-topics/spi-flash-modes.rst index 22b54766de..e796b0fa3d 100644 --- a/tools/esptool_py/docs/en/advanced-topics/spi-flash-modes.rst +++ b/tools/esptool_py/docs/en/advanced-topics/spi-flash-modes.rst @@ -3,7 +3,7 @@ SPI Flash Modes =============== -The ESP chips support four different SPI flash access modes: DIO, DOUT, QIO & QOUT. These can be set via the ``--flash_mode`` option of ``esptool.py write_flash``. +The ESP chips support four different SPI flash access modes: DIO, DOUT, QIO & QOUT. These can be set via the ``--flash-mode`` option of ``esptool write-flash``. These options control how many I/O pins are used for communication with the attached SPI flash chip, and which SPI commands are used. @@ -26,7 +26,7 @@ In order of performance: | ``dout`` | Dual Output | 2 pins used for data. | Approx 50% slower than ``qio``. | +------------+---------------+----------------------------------+-----------------------------------+ -In general, choose the fastest option for flash_mode that works with your device. Not all devices support all modes. See FAQ below for details. +In general, choose the fastest option for ``--flash-mode`` that works with your device. Not all devices support all modes. See FAQ below for details. Mode Descriptions ----------------- @@ -74,6 +74,20 @@ In ``qout`` mode, the host uses the "Quad Output Fast Read" (6BH) command to rea In ``qio`` mode, the host uses the "Quad I/O Fast Read" (EBH) command to read data. This command is the same as "Dual I/O Fast Read", only both address & data are transferred on 4 pins instead of 2 with 4 bits per clock cycle. This makes both the address & data transfer exactly twice as fast as "Dual I/O Fast Read". +.. only:: esp32s3 + + Octal SPI + ^^^^^^^^^ + + Some ESP chips additionally support Octal SPI mode. This mode uses 8 pins for communication with the SPI flash chip, and allows for even faster data transfers than Quad SPI. This mode added four additional pins (SPIIO4~7) compared to Quad SPI for data transfers. + + The 1st and 2nd bootloaders don't support ``opi`` mode. Because of that esptool doesn't use ``opi`` and ``dout`` is used instead. The bootloader retrieves the information from eFuse and effectively replaces the mode. + + .. note:: + + Use the ``esptool flash-id`` command to check if your ESP is using Quad or Octal SPI mode. It prints information based on the eFuse settings. + + Frequently Asked Questions -------------------------- @@ -83,7 +97,7 @@ Why don't qio & qout modes work with my Espressif chip/module? It is usually one of the following reasons: * The WP and HOLD pins of the SPI flash chip are not wired to the correct GPIOs of the Espressif chip. These pins must be connected correctly for quad modes to work, and not all boards/modules connect them at all. -* The SPI flash chip does not support quad modes. Look up the flash chip datasheet to see which modes it supports. You can identify the flash chip visually, or by using the :ref:`esptool.py flash_id ` command. +* The SPI flash chip does not support quad modes. Look up the flash chip datasheet to see which modes it supports. You can identify the flash chip visually, or by using the :ref:`esptool flash-id ` command. * Quad mode is not enabled correctly for this chip model. SPI flash is not a standard, so every manufacturer implements their chip differently. Most flash chips require certain commands to be sent in order to enable Quad SPI modes, and these commands vary. For Espressif chips, this often means that the chip first boots in a Dual SPI mode and then software detects the chip type and tries to enable Quad SPI mode. If the particular chip model is not supported by the software then it won't be able to enter quad mode. @@ -105,7 +119,7 @@ How is flash mode communicated to the Espressif chip? ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ The bootloader .bin file, flashed to the SPI flash, contains a header which has flash speed, flash mode, and some other metadata. The initial host mode is determined by ROM code when it reads this header after reset. -Passing the ``--flash_mode`` argument to esptool will update this header when the file is being written to flash. +Passing the ``--flash-mode`` argument to esptool will update this header when the file is being written to flash. This only determines the mode which is used for the initial boot from reset. Software may then configure the flash mode differently as part of the boot process. diff --git a/tools/esptool_py/docs/en/conf.py b/tools/esptool_py/docs/en/conf.py index 0362dfc3e0..39d4385a67 100644 --- a/tools/esptool_py/docs/en/conf.py +++ b/tools/esptool_py/docs/en/conf.py @@ -19,10 +19,11 @@ from conf_common import * # noqa: F403,F401 # General information about the project. -project = "esptool.py" +project = "esptool" copyright = "2016 - {}, Espressif Systems (Shanghai) Co., Ltd".format( datetime.datetime.now().year ) +autodoc_typehints_format = "short" # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/tools/esptool_py/docs/en/espefuse/adc-info-cmd.rst b/tools/esptool_py/docs/en/espefuse/adc-info-cmd.rst index e7c11f22ce..a87461f34a 100644 --- a/tools/esptool_py/docs/en/espefuse/adc-info-cmd.rst +++ b/tools/esptool_py/docs/en/espefuse/adc-info-cmd.rst @@ -3,24 +3,24 @@ Adc Info ======== -The ``espefuse.py adc_info`` command displays information about ADC calibration data stored in eFuse. +The ``espefuse adc-info`` command displays information about ADC calibration data stored in eFuse. .. only:: esp32 .. code-block:: none - > espefuse.py adc_info + > espefuse adc-info - === Run "adc_info" command === + === Run "adc-info" command === ADC VRef calibration: 1121mV .. only:: esp32c3 or esp32s2 or esp32s3 .. code-block:: none - > espefuse.py adc_info + > espefuse adc-info - === Run "adc_info" command === + === Run "adc-info" command === Temperature Sensor Calibration = -2.1C ADC1 readings stored in efuse BLOCK2: @@ -47,9 +47,9 @@ The ``espefuse.py adc_info`` command displays information about ADC calibration .. code-block:: none - > espefuse.py adc_info + > espefuse adc-info - === Run "adc_info" command === + === Run "adc-info" command === RF_REF_I_BIAS_CONFIG: 0 LDO_VOL_BIAS_CONFIG_LOW: 0 LDO_VOL_BIAS_CONFIG_HIGH: 0 diff --git a/tools/esptool_py/docs/en/espefuse/burn-bit-cmd.rst b/tools/esptool_py/docs/en/espefuse/burn-bit-cmd.rst index 11b180bf41..5b2d5716ca 100644 --- a/tools/esptool_py/docs/en/espefuse/burn-bit-cmd.rst +++ b/tools/esptool_py/docs/en/espefuse/burn-bit-cmd.rst @@ -3,12 +3,12 @@ Burn Bit ======== -The ``espefuse.py burn_bit`` command burns bits in efuse blocks by bit number. This is useful when the fields are not represented in the eFuse table. +The ``espefuse burn-bit`` command burns bits in eFuse blocks by bit number. This is useful when the fields are not represented in the eFuse table. Positional arguments: -- ``block`` - Efuse block. -- ``bit number`` - Bit number in the efuse block [0..BLK_LEN-1] (list of numbers, like 10 15 18 17 5 etc.). +- ``block`` - eFuse block. +- ``bit number`` - Bit number in the eFuse block [0..BLK_LEN-1] (list of numbers, like 10 15 18 17 5 etc.). Optional arguments: @@ -21,9 +21,9 @@ Burning bits to BLOCK2: .. code-block:: none - > espefuse.py burn_bit BLOCK2 15 16 17 18 19 20 + > espefuse burn-bit BLOCK2 15 16 17 18 19 20 - === Run "burn_bit" command === + === Run "burn-bit" command === bit_number: [255]........................................................[0] BLOCK2 : 0x00000000000000000000000000000000000000000000000000000000001f8000 BLOCK2 (secure_boot_v1 s) [2 ] regs_to_write: 001f8000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 @@ -39,22 +39,22 @@ Burning bits to BLOCK2: Reading updated efuses... Successful -Burning In Multiple Blocks +Burning in Multiple Blocks ^^^^^^^^^^^^^^^^^^^^^^^^^^ .. code-block:: none - > espefuse.py --virt burn_bit BLOCK2 15 16 17 18 19 20 \ - burn_bit BLOCK3 15 16 17 18 19 20 + > espefuse --virt burn-bit BLOCK2 15 16 17 18 19 20 \ + burn-bit BLOCK3 15 16 17 18 19 20 - === Run "burn_bit" command === + === Run "burn-bit" command === bit_number: [255]........................................................[0] BLOCK2 : 0x00000000000000000000000000000000000000000000000000000000001f8000 BLOCK2 (secure_boot_v1 s) [2 ] regs_to_write: 001f8000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 Batch mode is enabled, the burn will be done at the end of the command. - === Run "burn_bit" command === + === Run "burn-bit" command === bit_number: [255]........................................................[0] BLOCK3 : 0x00000000000000000000000000000000000000000000000000000000001f8000 BLOCK3 ( ) [3 ] regs_to_write: 001f8000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 diff --git a/tools/esptool_py/docs/en/espefuse/burn-block-data-cmd.rst b/tools/esptool_py/docs/en/espefuse/burn-block-data-cmd.rst index 0b09519600..2c24bbf668 100644 --- a/tools/esptool_py/docs/en/espefuse/burn-block-data-cmd.rst +++ b/tools/esptool_py/docs/en/espefuse/burn-block-data-cmd.rst @@ -3,14 +3,14 @@ Burn Block Data =============== -The ``espefuse.py burn_block_data`` command allows writing arbitrary data (non-key data) from a file into an eFuse block, for software use. +The ``espefuse burn-block-data`` command allows writing arbitrary data (non-key data) from a file into an eFuse block, for software use. -This command is available in ``espefuse.py`` v2.6 and newer. +This command is available in ``espefuse`` v2.6 and newer. Positional arguments: * ``Name of key block`` -* ``Datafile``. File containing data to burn into the efuse block. The file size can be smaller than the eFuse block size. +* ``Datafile``. File containing data to burn into the eFuse block. The file size can be smaller than the eFuse block size. It can be list of blocks and datafiles (like BLOCK1 datafile1.bin BLOCK2 datafile2.bin etc.). @@ -23,9 +23,9 @@ Optional arguments: .. code-block:: none - > espefuse.py -p PORT burn_block_data --offset 6 BLOCK3 device_id.bin + > espefuse -p PORT burn-block-data --offset 6 BLOCK3 device_id.bin - === Run "burn_block_data" command === + === Run "burn-block-data" command === [03] BLOCK3 size=32 bytes, offset=06 - > [00 00 00 00 00 00 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 00 00 00 00 00 00 00 00 00 00]. Check all blocks for burn... @@ -46,14 +46,14 @@ Peculiarities .. code-block:: none - > espefuse.py dump + > espefuse dump ... BLOCK3 ( ) [3 ] read_regs: 00000000 01000000 05040302 09080706 0d0c0b0a 00000f0e 00000000 00000000 - > espefuse.py summary + > espefuse summary .... BLOCK3 (BLOCK3): Variable Block 3 = 00 00 00 00 00 00 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 00 00 00 00 00 00 00 00 00 00 R/W 2. Part of the eFuse block can be written at a time. The ``--offset`` argument allows writing to a byte offset inside the eFuse block itself. -3. This command is not suitable for writing key data which will be used by flash encryption or secure boot hardware, use ``burn_key`` for this. +3. This command is not suitable for writing key data which will be used by flash encryption or secure boot hardware, use ``burn-key`` for this. diff --git a/tools/esptool_py/docs/en/espefuse/burn-custom-mac-cmd.rst b/tools/esptool_py/docs/en/espefuse/burn-custom-mac-cmd.rst index fe1ea178a0..f6e262226f 100644 --- a/tools/esptool_py/docs/en/espefuse/burn-custom-mac-cmd.rst +++ b/tools/esptool_py/docs/en/espefuse/burn-custom-mac-cmd.rst @@ -3,7 +3,7 @@ Burn Custom Mac =============== -The ``espefuse.py burn_custom_mac`` command burns a 48-bit Custom MAC Address. +The ``espefuse burn-custom-mac`` command burns a 48-bit Custom MAC Address. Positional arguments: @@ -25,9 +25,9 @@ If ``CUSTOM_MAC`` is placed in an eFuse block with a coding scheme and already h .. code-block:: none - > espefuse.py burn_custom_mac 48:63:92:15:72:16 + > espefuse burn-custom-mac 48:63:92:15:72:16 - === Run "burn_custom_mac" command === + === Run "burn-custom-mac" command === - 'MAC_VERSION' (Version of the MAC field) 0x00 -> 0x1 - 'CUSTOM_MAC' (Custom MAC) 0x000000000000 -> 0x167215926348 - 'CUSTOM_MAC_CRC' (CRC of custom MAC) 0x00 -> 0x75 @@ -44,7 +44,7 @@ If ``CUSTOM_MAC`` is placed in an eFuse block with a coding scheme and already h Custom MAC Address version 1: 48:63:92:15:72:16 (CRC 0x75 OK) Successful - > espefuse.py summary + > espefuse summary ... MAC_VERSION (BLOCK3): Version of the MAC field = Custom MAC in BLOCK3 R/W (0x01) CUSTOM_MAC (BLOCK3): Custom MAC @@ -63,9 +63,9 @@ If ``CUSTOM_MAC`` is placed in an eFuse block with a coding scheme and already h .. code-block:: none - > espefuse.py burn_custom_mac 48:63:92:15:72:16 + > espefuse burn-custom-mac 48:63:92:15:72:16 - === Run "burn_custom_mac" command === + === Run "burn-custom-mac" command === - 'CUSTOM_MAC' (Custom MAC addr) 0x000000000000 -> 0x167215926348 Check all blocks for burn... @@ -85,7 +85,7 @@ If ``CUSTOM_MAC`` is placed in an eFuse block with a coding scheme and already h Custom MAC Address: 48:63:92:15:72:16 (OK) Successful - > espefuse.py summary + > espefuse summary ... CUSTOM_MAC_USED (BLOCK0) Enable CUSTOM_MAC programming = True R/W (0b1) CUSTOM_MAC (BLOCK1) Custom MAC addr @@ -97,9 +97,9 @@ If ``CUSTOM_MAC`` is placed in an eFuse block with a coding scheme and already h .. code-block:: none - > espefuse.py burn_custom_mac 48:63:92:15:72:16 + > espefuse burn-custom-mac 48:63:92:15:72:16 - === Run "burn_custom_mac" command === + === Run "burn-custom-mac" command === - 'CUSTOM_MAC' (Custom MAC Address) 0x000000000000 -> 0x167215926348 Check all blocks for burn... @@ -114,7 +114,7 @@ If ``CUSTOM_MAC`` is placed in an eFuse block with a coding scheme and already h Custom MAC Address: 48:63:92:15:72:16 (OK) Successful - > espefuse.py summary + > espefuse summary ... CUSTOM_MAC (BLOCK3) Custom MAC Address = 48:63:92:15:72:16 (OK) R/W diff --git a/tools/esptool_py/docs/en/espefuse/burn-efuse-cmd.rst b/tools/esptool_py/docs/en/espefuse/burn-efuse-cmd.rst index 4d6446d9c7..bdf59f9cc7 100644 --- a/tools/esptool_py/docs/en/espefuse/burn-efuse-cmd.rst +++ b/tools/esptool_py/docs/en/espefuse/burn-efuse-cmd.rst @@ -1,9 +1,9 @@ .. _burn-efuse-cmd: -Burn Efuse +Burn eFuse ========== -The ``espefuse.py burn_efuse`` command burns eFuses. The arguments to ``burn_efuse`` are eFuse names (as shown in summary output) and new values. +The ``espefuse burn-efuse`` command burns eFuses. The arguments to ``burn-efuse`` are eFuse names (as shown in summary output) and new values. Positional arguments: @@ -16,15 +16,15 @@ Optional arguments: It can be list of eFuse names and values (like EFUSE_NAME1 1 EFUSE_NAME2 7 EFUSE_NAME3 10 etc.). -New values can be a numeric value in decimal or hex (with "0x" prefix). eFuse bits can only be burned from 0 to 1, attempting to set any back to 0 will have no effect. Most eFuses have a limited bit width (many are only 1-bit flags). Longer eFuses (MAC addresses, keys) can be set with this command, but it's better to use a specific command (``burn_custom_mac``, ``burn_key``) for a specific field. +New values can be a numeric value in decimal or hex (with "0x" prefix). eFuse bits can only be burned from 0 to 1, attempting to set any back to 0 will have no effect. Most eFuses have a limited bit width (many are only 1-bit flags). Longer eFuses (MAC addresses, keys) can be set with this command, but it's better to use a specific command (``burn-custom-mac``, ``burn-key``) for a specific field. This command supports simultaneous burning of multiple eFuses, it doesn't matter if they are from different eFuse blocks or not. The format is the same as for burning just one eFuse, just list the eFuse name and value pairs, see the example below. .. code-block:: none - > espefuse.py --port /dev/ttyUSB0 burn_efuse DIS_USB_JTAG 1 VDD_SPI_AS_GPIO 1 + > espefuse --port /dev/ttyUSB0 burn-efuse DIS_USB_JTAG 1 VDD_SPI_AS_GPIO 1 - === Run "burn_efuse" command === + === Run "burn-efuse" command === The efuses to burn: from BLOCK0 - DIS_USB_JTAG @@ -42,7 +42,7 @@ This command supports simultaneous burning of multiple eFuses, it doesn't matter This is an irreversible operation! Type 'BURN' (all capitals) to continue. -By default, ``espefuse.py`` will ask you to type ``BURN`` before it permanently sets eFuses. The ``--do-not-confirm`` option allows you to bypass this. +By default, ``espefuse`` will ask you to type ``BURN`` before it permanently sets eFuses. The ``--do-not-confirm`` option allows you to bypass this. .. code-block:: none @@ -90,7 +90,7 @@ On {IDF_TARGET_NAME} chips without integrated SPI flash, these eFuses are left z On {IDF_TARGET_NAME} chips with integrated internal SPI flash, these eFuses are burned in the factory to the GPIO numbers where the flash is connected. These values override the defaults on boot. -In order to change the SPI flash pin configuration, these eFuses can be burned to the GPIO numbers where the flash is connected. If at least one of these eFuses is burned, all of of them must be set to the correct values. +In order to change the SPI flash pin configuration, these eFuses can be burned to the GPIO numbers where the flash is connected. If at least one of these eFuses is burned, all of them must be set to the correct values. If these eFuses are burned, GPIO1 (U0TXD pin) is no longer consulted to set the boot mode from SPI to HSPI flash on reset. @@ -102,4 +102,4 @@ For example: SPI_PAD_CONFIG_CS0 Override SD_CMD pad (GPIO11/SPICS0) = 32 R/W (0x1e) -If using the ``burn_efuse`` command to configure these pins, always specify the actual GPIO number you wish to set. +If using the ``burn-efuse`` command to configure these pins, always specify the actual GPIO number you wish to set. diff --git a/tools/esptool_py/docs/en/espefuse/burn-key-cmd.rst b/tools/esptool_py/docs/en/espefuse/burn-key-cmd.rst index c6a7714c26..722831808b 100644 --- a/tools/esptool_py/docs/en/espefuse/burn-key-cmd.rst +++ b/tools/esptool_py/docs/en/espefuse/burn-key-cmd.rst @@ -3,7 +3,7 @@ Burn Key ======== -The ``espefuse.py burn_key`` command burns keys to eFuse blocks: +The ``espefuse burn-key`` command burns keys to eFuse blocks: .. list:: @@ -78,18 +78,18 @@ Optional arguments: .. only:: esp32h2 - {IDF_TARGET_NAME} has the ECDSA accelerator for signature purposes and supports private keys based on the NIST192p or NIST256p curve. These two commands below can be used to generate such keys (``PEM`` file). The ``burn_key`` command with the ``ECDSA_KEY`` purpose takes the ``PEM`` file and writes the private key into a eFuse block. The key is written to the block in reverse byte order. + {IDF_TARGET_NAME} has the ECDSA accelerator for signature purposes and supports private keys based on the NIST192p or NIST256p curve. These two commands below can be used to generate such keys (``PEM`` file). The ``burn-key`` command with the ``ECDSA_KEY`` purpose takes the ``PEM`` file and writes the private key into a eFuse block. The key is written to the block in reverse byte order. For NIST192p, the private key is 192 bits long, so 8 padding bytes ("0x00") are added. .. code-block:: none - > espsecure.py generate_signing_key -v 2 -s ecdsa192 ecdsa192.pem + > espsecure generate_signing_key -v 2 -s ecdsa192 ecdsa192.pem ECDSA NIST192p private key in PEM format written to ecdsa192.pem .. code-block:: none - > espsecure.py generate_signing_key -v 2 -s ecdsa256 ecdsa256.pem + > espsecure generate_signing_key -v 2 -s ecdsa256 ecdsa256.pem ECDSA NIST256p private key in PEM format written to ecdsa256.pem .. only:: esp32c2 @@ -146,7 +146,7 @@ By default, when an encryption key block is burned it is also read and write pro .. code-block:: none - espefuse.py burn_key secure_boot_v1 secure_boot_key_v1.bin + espefuse burn-key secure_boot_v1 secure_boot_key_v1.bin .. only:: esp32 @@ -155,7 +155,7 @@ By default, when an encryption key block is burned it is also read and write pro Force Writing a Key ^^^^^^^^^^^^^^^^^^^ -Normally, a key will only be burned if the efuse block has not been previously written to. The ``--force-write-always`` option can be used to ignore this and try to burn the key anyhow. +Normally, a key will only be burned if the eFuse block has not been previously written to. The ``--force-write-always`` option can be used to ignore this and try to burn the key anyhow. Note that this option is still limited by the eFuse hardware - hardware does not allow any eFuse bits to be cleared 1->0, and can not write anything to write protected eFuse blocks. @@ -166,9 +166,9 @@ Usage .. code-block:: none - > espefuse.py burn_key flash_encryption 256bit_fe_key.bin + > espefuse burn-key flash_encryption 256bit_fe_key.bin - === Run "burn_key" command === + === Run "burn-key" command === Sensitive data will be hidden (see --show-sensitive-info) Burn keys to blocks: - BLOCK1 -> [?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ??] @@ -194,7 +194,7 @@ Usage .. code-block:: none - > espefuse.py summary + > espefuse summary ... BLOCK1 (BLOCK1): Flash encryption key = ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? -/- @@ -209,9 +209,9 @@ Usage .. code-block:: none - > espefuse.py burn_key flash_encryption 256bit_fe_key.bin --no-protect-key + > espefuse burn-key flash_encryption 256bit_fe_key.bin --no-protect-key - === Run "burn_key" command === + === Run "burn-key" command === Sensitive data will be hidden (see --show-sensitive-info) Burn keys to blocks: - BLOCK1 -> [?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ??] @@ -234,7 +234,7 @@ Usage .. code-block:: none - > espefuse.py summary + > espefuse summary ... BLOCK1 (BLOCK1): Flash encryption key = 1f 1e 1d 1c 1b 1a 19 18 17 16 15 14 13 12 11 10 0f 0e 0d 0c 0b 0a 09 08 07 06 05 04 03 02 01 00 R/W @@ -256,9 +256,9 @@ Usage .. code-block:: none - > espefuse.py burn_key BLOCK_KEY0 ~/esp/tests/efuse/512bits_0.bin XTS_AES_256_KEY --no-read-protect + > espefuse burn-key BLOCK_KEY0 ~/esp/tests/efuse/512bits_0.bin XTS_AES_256_KEY --no-read-protect - === Run "burn_key" command === + === Run "burn-key" command === Sensitive data will be hidden (see --show-sensitive-info) Burn keys to blocks: - BLOCK_KEY0 -> [?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ??] @@ -290,7 +290,7 @@ Usage Reading updated efuses... Successful - > espefuse.py summary + > espefuse summary ... KEY_PURPOSE_0 (BLOCK0) KEY0 purpose = XTS_AES_256_KEY_1 R/- (0x2) KEY_PURPOSE_1 (BLOCK0) KEY1 purpose = XTS_AES_256_KEY_2 R/- (0x3) @@ -308,11 +308,11 @@ Usage .. code-block:: none - > espefuse.py -c esp32c2 \ - burn_key_digest secure_images/ecdsa256_secure_boot_signing_key_v2.pem \ - burn_key BLOCK_KEY0 images/efuse/128bit_key.bin XTS_AES_128_KEY_DERIVED_FROM_128_EFUSE_BITS + > espefuse -c esp32c2 \ + burn-key-digest secure_images/ecdsa256_secure_boot_signing_key_v2.pem \ + burn-key BLOCK_KEY0 images/efuse/128bit_key.bin XTS_AES_128_KEY_DERIVED_FROM_128_EFUSE_BITS - === Run "burn_key_digest" command === + === Run "burn-key-digest" command === Sensitive data will be hidden (see --show-sensitive-info) Burn keys to blocks: - BLOCK_KEY0_HI_128 -> [?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ??] @@ -321,7 +321,7 @@ Usage Batch mode is enabled, the burn will be done at the end of the command. - === Run "burn_key" command === + === Run "burn-key" command === Sensitive data will be hidden (see --show-sensitive-info) Burn keys to blocks: - BLOCK_KEY0_LOW_128 -> [?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ??] diff --git a/tools/esptool_py/docs/en/espefuse/burn-key-digest-cmd.rst b/tools/esptool_py/docs/en/espefuse/burn-key-digest-cmd.rst index 4402a8c92c..51d88c57bc 100644 --- a/tools/esptool_py/docs/en/espefuse/burn-key-digest-cmd.rst +++ b/tools/esptool_py/docs/en/espefuse/burn-key-digest-cmd.rst @@ -1,9 +1,9 @@ .. _burn-key-digest-cmd: -Burn key Digest +Burn Key Digest =============== -The ``espefuse.py burn_key_digest`` command parses a RSA public key and burns the digest to eFuse block for use with `Secure Boot V2 `_. +The ``espefuse burn-key-digest`` command parses a RSA public key and burns the digest to eFuse block for use with `Secure Boot V2 `_. Positional arguments: @@ -44,9 +44,9 @@ Usage .. code-block:: none - > espefuse.py burn_key_digest secure_boot_key_v2_0.pem + > espefuse burn-key-digest secure_boot_key_v2_0.pem - === Run "burn_key_digest" command === + === Run "burn-key-digest" command === Sensitive data will be hidden (see --show-sensitive-info) - BLOCK2 -> [?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ??] Disabling write to efuse BLOCK2... @@ -64,7 +64,7 @@ Usage Reading updated efuses... Successful - > espefuse.py summary + > espefuse summary ... BLOCK2 (BLOCK2): Secure boot key = a2 cd 39 85 df 00 d7 95 07 0f f6 7c 8b ab e1 7d 39 11 95 c4 5b 37 6e 7b f0 ec 04 5e 36 30 02 5d R/- @@ -75,9 +75,9 @@ Usage .. code-block:: none - > espefuse.py burn_key_digest secure_boot_v2_ecdsa192.pem + > espefuse burn-key-digest secure_boot_v2_ecdsa192.pem - === Run "burn_key_digest" command === + === Run "burn-key-digest" command === Sensitive data will be hidden (see --show-sensitive-info) Burn keys to blocks: - BLOCK_KEY0_HI_128 -> [?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ??] @@ -96,7 +96,7 @@ Usage Reading updated efuses... Successful - > espefuse.py summary + > espefuse summary ... XTS_KEY_LENGTH_256 (BLOCK0) Flash encryption key length = 128 bits key R/W (0b0) ... @@ -114,12 +114,12 @@ Usage .. code-block:: none - > espefuse.py burn_key_digest \ + > espefuse burn-key-digest \ BLOCK_KEY0 ~/esp/tests/efuse/secure_boot_key_v2_0.pem SECURE_BOOT_DIGEST0 \ BLOCK_KEY1 ~/esp/tests/efuse/secure_boot_key_v2_1.pem SECURE_BOOT_DIGEST1 \ BLOCK_KEY2 ~/esp/tests/efuse/secure_boot_key_v2_2.pem SECURE_BOOT_DIGEST2 - === Run "burn_key_digest" command === + === Run "burn-key-digest" command === Sensitive data will be hidden (see --show-sensitive-info) Burn keys to blocks: - BLOCK_KEY0 -> [?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ??] @@ -154,7 +154,7 @@ Usage Reading updated efuses... Successful - > espefuse.py summary + > espefuse summary KEY_PURPOSE_0 (BLOCK0) KEY0 purpose = SECURE_BOOT_DIGEST0 R/- (0x9) KEY_PURPOSE_1 (BLOCK0) KEY1 purpose = SECURE_BOOT_DIGEST1 R/- (0xa) diff --git a/tools/esptool_py/docs/en/espefuse/check-error-cmd.rst b/tools/esptool_py/docs/en/espefuse/check-error-cmd.rst index 0723adf2c2..e80dff1dd3 100644 --- a/tools/esptool_py/docs/en/espefuse/check-error-cmd.rst +++ b/tools/esptool_py/docs/en/espefuse/check-error-cmd.rst @@ -3,7 +3,7 @@ Check Error =========== -The ``espefuse.py check_error`` command checks eFuse errors. It triggers several reads to force the eFuse controller to reload eFuses and update status registers. This command can be run after burn operations to make sure that there is not errors. +The ``espefuse check-error`` command checks eFuse errors. It triggers several reads to force the eFuse controller to reload eFuses and update status registers. This command can be run after burn operations to make sure that there is not errors. Optional argument: @@ -13,7 +13,7 @@ The summary log below shows an error in BLOCK0. .. code-block:: none - > espefuse.py summary + > espefuse summary ... WDT_DELAY_SEL (BLOCK0)[FAIL:1] Selects RTC WDT timeout threshold at startup = False R/W (0b0) ... @@ -31,7 +31,7 @@ Checks the status registers of eFuse blocks and throws an error if there is an e .. code-block:: none - > espefuse.py check_error + > espefuse check-error Error(s) in BLOCK1 [ERRORS:0 FAIL:1] Error(s) in BLOCK2 [ERRORS:1 FAIL:1] @@ -41,7 +41,7 @@ Checks the status registers of eFuse blocks and throws an error if there is an e EFUSE_RD_RS_ERR0_REG 0x00008990 EFUSE_RD_RS_ERR1_REG 0x00000000 - === Run "check_error" command === + === Run "check-error" command === Error(s) in BLOCK1 [ERRORS:0 FAIL:1] Error(s) in BLOCK2 [ERRORS:1 FAIL:1] Error(s) in BLOCK3 [ERRORS:1 FAIL:1] @@ -56,7 +56,7 @@ Repairs encoding errors in eFuse blocks, if possible. .. code-block:: none - > espefuse.py check_error --recovery + > espefuse check-error --recovery Error(s) in BLOCK1 [ERRORS:0 FAIL:1] Error(s) in BLOCK2 [ERRORS:1 FAIL:1] @@ -66,7 +66,7 @@ Repairs encoding errors in eFuse blocks, if possible. EFUSE_RD_RS_ERR0_REG 0x00008990 EFUSE_RD_RS_ERR1_REG 0x00000000 - === Run "check_error" command === + === Run "check-error" command === Error(s) in BLOCK1 [ERRORS:0 FAIL:1] Error(s) in BLOCK2 [ERRORS:1 FAIL:1] Error(s) in BLOCK3 [ERRORS:1 FAIL:1] diff --git a/tools/esptool_py/docs/en/espefuse/dump-cmd.rst b/tools/esptool_py/docs/en/espefuse/dump-cmd.rst index 8f841ccb8e..919a2ababc 100644 --- a/tools/esptool_py/docs/en/espefuse/dump-cmd.rst +++ b/tools/esptool_py/docs/en/espefuse/dump-cmd.rst @@ -3,7 +3,7 @@ Dump ==== -The ``espefuse.py dump`` command allows: +The ``espefuse dump`` command allows: - display raw values of eFuse registers, grouped by block. Output corresponds directly to eFuse register values in the `register space `__. - save dump into files. @@ -13,13 +13,13 @@ Optional arguments: - ``--format`` - Selects the dump format: - ``default`` - Usual console eFuse dump; - ``joint`` - All eFuse blocks are stored in one file; - - ``split`` - Each eFuse block is placed in its own file. The tool will create multiple files based on the given the ``--file_name`` argument. Example: "--file_name /path/blk.bin", blk0.bin, blk1.bin ... blkN.bin. Use the ``burn_block_data`` cmd to write it back to another chip. -- ``--file_name`` - The path to the file in which to save the dump, if not specified, output to the console. + - ``split`` - Each eFuse block is placed in its own file. The tool will create multiple files based on the given the ``--file-name`` argument. Example: "--file-name /path/blk.bin", blk0.bin, blk1.bin ... blkN.bin. Use the ``burn-block-data`` cmd to write it back to another chip. +- ``--file-name`` - The path to the file in which to save the dump, if not specified, output to the console. -Raw Values Of Efuse Registers +Raw Values of eFuse Registers ----------------------------- -The number of blocks depends on the chips and can vary from 4 to 11. A block can have different names, which can be used with ``burn_key`` or ``burn_block_data``. +The number of blocks depends on the chips and can vary from 4 to 11. A block can have different names, which can be used with ``burn-key`` or ``burn-block-data``. The order of registers in the dump: @@ -32,10 +32,9 @@ The order of registers in the dump: .. code-block:: none - > espefuse.py dump + > espefuse dump - Detecting chip type... Unsupported detection protocol, switching and trying again... - Connecting.... + Connecting......... Detecting chip type... ESP32 BLOCK0 ( ) [0 ] read_regs: 00000000 7e5a6e58 00e294b9 0000a200 00000333 00100000 00000004 BLOCK1 (flash_encryption) [1 ] read_regs: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 @@ -48,7 +47,7 @@ The order of registers in the dump: .. code-block:: none - > espefuse.py dump + > espefuse dump Connecting......... Detecting chip type... ESP32-C2 @@ -64,7 +63,7 @@ The order of registers in the dump: .. code-block:: none - > espefuse.py dump + > espefuse dump Connecting.... Detecting chip type... ESP32-C3 @@ -86,14 +85,14 @@ The order of registers in the dump: In the last lines, which are separated from the main dump, you can see the encoding scheme status for each block. If there are all zeros, then there are no coding scheme errors. -Save Dump To Files +Save Dump to Files ------------------ -This command saves dump for each block into a separate file. You need to provide the common path name ``/chip1/blk.bin``, it will create files in the given directory (the directory must exist): /chip1/blk0.bin, /chip1/blk1.bin - /chip1/blkN.bin. Use ``burn_block_data`` command to write them back to another chip. Note that some blocks may be read-protected, in which case the data in the block will be zero. +This command saves dump for each block into a separate file. You need to provide the common path name ``/chip1/blk.bin``, it will create files in the given directory (the directory must exist): /chip1/blk0.bin, /chip1/blk1.bin - /chip1/blkN.bin. Use ``burn-block-data`` command to write them back to another chip. Note that some blocks may be read-protected, in which case the data in the block will be zero. .. code-block:: none - > espefuse.py dump --format split --file_name backup/chip1/blk.bin + > espefuse dump --format split --file-name backup/chip1/blk.bin === Run "dump" command === backup/chip1/blk0.bin @@ -112,7 +111,7 @@ These dump files can be written to another chip: .. code-block:: none - > espefuse.py burn_block_data BLOCK0 backup/chip1/blk0.bin \ + > espefuse burn-block-data BLOCK0 backup/chip1/blk0.bin \ BLOCK1 backup/chip1/blk1.bin \ BLOCK2 backup/chip1/blk2.bin @@ -120,7 +119,7 @@ To save all eFuse blocks in one file, use the following command: .. code-block:: none - > espefuse.py dump --format joint --file_name backup/chip1/efuses.bin + > espefuse dump --format joint --file-name backup/chip1/efuses.bin === Run "dump" command === backup/chip1/efuses.bin diff --git a/tools/esptool_py/docs/en/espefuse/get-custom-mac-cmd.rst b/tools/esptool_py/docs/en/espefuse/get-custom-mac-cmd.rst index 3077e991e7..ece81b594a 100644 --- a/tools/esptool_py/docs/en/espefuse/get-custom-mac-cmd.rst +++ b/tools/esptool_py/docs/en/espefuse/get-custom-mac-cmd.rst @@ -3,7 +3,7 @@ Get Custom Mac ============== -The ``espefuse.py burn_custom_mac`` command prints the Custom MAC Address (``CUSTOM_MAC``). +The ``espefuse get-custom-mac`` command prints the Custom MAC Address (``CUSTOM_MAC``). The chips also have a factory MAC address (eFuse name ``MAC``), which is written at the factory. It can not be changed with this tool. @@ -11,9 +11,9 @@ The chips also have a factory MAC address (eFuse name ``MAC``), which is written .. code-block:: none - > espefuse.py get_custom_mac + > espefuse get-custom-mac - === Run "get_custom_mac" command === + === Run "get-custom-mac" command === Custom MAC Address version 1: 48:63:92:15:72:16 (CRC 0x75 OK) If the custom MAC address is not burned, then you will see the message "Custom MAC Address is not set in the device". And in the summary, those eFuses associated with custom MAC addresses will not show up. @@ -22,9 +22,9 @@ The chips also have a factory MAC address (eFuse name ``MAC``), which is written .. code-block:: none - > espefuse.py get_custom_mac + > espefuse get-custom-mac - === Run "get_custom_mac" command === + === Run "get-custom-mac" command === Custom MAC Address: 48:63:92:15:72:16 (OK) If the custom MAC address is not burned, then you will see the message "Custom MAC Address: 00:00:00:00:00:00 (OK)". diff --git a/tools/esptool_py/docs/en/espefuse/inc/summary_ESP32-C2.rst b/tools/esptool_py/docs/en/espefuse/inc/summary_ESP32-C2.rst index f42d80d43a..efdca4e909 100644 --- a/tools/esptool_py/docs/en/espefuse/inc/summary_ESP32-C2.rst +++ b/tools/esptool_py/docs/en/espefuse/inc/summary_ESP32-C2.rst @@ -1,6 +1,6 @@ .. code-block:: none - > espefuse.py -p PORT summary + > espefuse -p PORT summary Connecting................... Detecting chip type... ESP32-C2 diff --git a/tools/esptool_py/docs/en/espefuse/inc/summary_ESP32-C3.rst b/tools/esptool_py/docs/en/espefuse/inc/summary_ESP32-C3.rst index c20b5c58df..ba3cc874c1 100644 --- a/tools/esptool_py/docs/en/espefuse/inc/summary_ESP32-C3.rst +++ b/tools/esptool_py/docs/en/espefuse/inc/summary_ESP32-C3.rst @@ -1,6 +1,6 @@ .. code-block:: none - > espefuse.py -p PORT summary + > espefuse -p PORT summary Connecting.... Detecting chip type... ESP32-C3 diff --git a/tools/esptool_py/docs/en/espefuse/inc/summary_ESP32-C5.rst b/tools/esptool_py/docs/en/espefuse/inc/summary_ESP32-C5.rst new file mode 100644 index 0000000000..314a061e8d --- /dev/null +++ b/tools/esptool_py/docs/en/espefuse/inc/summary_ESP32-C5.rst @@ -0,0 +1,198 @@ +.. code-block:: none + + > espefuse -p PORT summary + + Connecting.... + Detecting chip type... ESP32-C5 + + === Run "summary" command === + EFUSE_NAME (Block) Description = [Meaningful Value] [Readable/Writeable] (Hex Value) + ---------------------------------------------------------------------------------------- + Config fuses: + WR_DIS (BLOCK0) Disable programming of individual eFuses = 4608 R/W (0x00001200) + RD_DIS (BLOCK0) Disable reading from BlOCK4-10 = 0 R/W (0b0000000) + DIS_ICACHE (BLOCK0) Represents whether icache is disabled or enabled.\ = False R/W (0b0) + \ 1: disabled\\ 0: enabled\\ + DIS_TWAI (BLOCK0) Represents whether TWAI function is disabled or en = False R/W (0b0) + abled.\\ 1: disabled\\ 0: enabled\\ + KM_DISABLE_DEPLOY_MODE (BLOCK0) Represents whether the deploy mode of key manager = 0 R/W (0x0) + is disable or not. \\ 1: disabled \\ 0: enabled.\\ + KM_RND_SWITCH_CYCLE (BLOCK0) Set the bits to control key manager random number = 0 R/W (0b00) + switch cycle. 0: control by register. 1: 8 km clk + cycles. 2: 16 km cycles. 3: 32 km cycles + KM_DEPLOY_ONLY_ONCE (BLOCK0) Set each bit to control whether corresponding key = 0 R/W (0x0) + can only be deployed once. 1 is true; 0 is false. + bit 0: ecsda; bit 1: xts; bit2: hmac; bit3: ds + DIS_DIRECT_BOOT (BLOCK0) Represents whether direct boot mode is disabled or = False R/W (0b0) + enabled.\\ 1: disabled\\ 0: enabled\\ + UART_PRINT_CONTROL (BLOCK0) Set the default UARTboot message output mode = Enable R/W (0b00) + HYS_EN_PAD (BLOCK0) Represents whether the hysteresis function of corr = False R/W (0b0) + esponding PAD is enabled.\\ 1: enabled\\ 0:disable + d\\ + HUK_GEN_STATE (BLOCK0) Set the bits to control validation of HUK generate = 0 R/W (0b000000000) + mode.\\ Odd of 1 is invalid.\\ Even of 1 is valid + .\\ + XTAL_48M_SEL (BLOCK0) Represents whether XTAL frequency is 48MHz or not. = 1 R/W (0b001) + If not; 40MHz XTAL will be used. If this field co + ntains Odd number bit 1: Enable 48MHz XTAL\ Even n + umber bit 1: Enable 40MHz XTAL + XTAL_48M_SEL_MODE (BLOCK0) Specify the XTAL frequency selection is decided by = True R/W (0b1) + eFuse or strapping-PAD-state. 1: eFuse\\ 0: strap + ping-PAD-state + ECC_FORCE_CONST_TIME (BLOCK0) Represents whether to force ecc to use const-time = False R/W (0b0) + calculation mode. \\ 1: Enable. \\ 0: Disable + PSRAM_CAP (BLOCK1) Psram capacity = 0 R/W (0b000) + PSRAM_VENDOR (BLOCK1) Psram vendor = 0 R/W (0b00) + TEMP (BLOCK1) Temp (die embedded inside) = 0 R/W (0b00) + TRIM_N_BIAS (BLOCK1) PADC CAL N bias = 0 R/W (0b00000) + TRIM_P_BIAS (BLOCK1) PADC CAL P bias = 0 R/W (0b00000) + BLOCK_USR_DATA (BLOCK3) User data + = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 R/W + BLOCK_SYS_DATA2 (BLOCK10) System data part 2 (reserved) + = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 R/W + + Flash fuses: + FLASH_TPUW (BLOCK0) Represents the flash waiting time after power-up; = 0 R/W (0x0) + in unit of ms. When the value less than 15; the wa + iting time is the programmed value. Otherwise; the + waiting time is 2 times the programmed value + FORCE_SEND_RESUME (BLOCK0) Represents whether ROM code is forced to send a re = False R/W (0b0) + sume command during SPI boot.\\ 1: forced\\ 0:not + forced\\ + FLASH_CAP (BLOCK1) Flash capacity = 0 R/W (0b000) + FLASH_VENDOR (BLOCK1) Flash vendor = 0 R/W (0b000) + + Identity fuses: + WAFER_VERSION_MINOR (BLOCK1) Minor chip version = 0 R/W (0x0) + WAFER_VERSION_MAJOR (BLOCK1) Minor chip version = 0 R/W (0b00) + DISABLE_WAFER_VERSION_MAJOR (BLOCK1) Disables check of wafer version major = False R/W (0b0) + DISABLE_BLK_VERSION_MAJOR (BLOCK1) Disables check of blk version major = False R/W (0b0) + BLK_VERSION_MINOR (BLOCK1) BLK_VERSION_MINOR of BLOCK2 = 0 R/W (0b000) + BLK_VERSION_MAJOR (BLOCK1) BLK_VERSION_MAJOR of BLOCK2 = 0 R/W (0b00) + PKG_VERSION (BLOCK1) Package version = 0 R/W (0b000) + PA_TRIM_VERSION (BLOCK1) PADC CAL PA trim version = 0 R/W (0b000) + OPTIONAL_UNIQUE_ID (BLOCK2) Optional unique 128-bit ID + = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 R/W + + Jtag fuses: + JTAG_SEL_ENABLE (BLOCK0) Represents whether the selection between usb_to_jt = False R/W (0b0) + ag and pad_to_jtag through strapping gpio15 when b + oth EFUSE_DIS_PAD_JTAG and EFUSE_DIS_USB_JTAG are + equal to 0 is enabled or disabled.\\ 1: enabled\\ + 0: disabled\\ + SOFT_DIS_JTAG (BLOCK0) Represents whether JTAG is disabled in soft way.\\ = 0 R/W (0b000) + Odd number: disabled\\ Even number: enabled\\ + DIS_PAD_JTAG (BLOCK0) Represents whether JTAG is disabled in the hard wa = False R/W (0b0) + y(permanently).\\ 1: disabled\\ 0: enabled\\ + + Mac fuses: + MAC (BLOCK1) MAC address + = 60:55:f9:f9:54:1c (OK) R/W + MAC_EXT (BLOCK1) Represents the extended bits of MAC address = ff:fe (OK) R/W + CUSTOM_MAC (BLOCK3) Custom MAC + = 00:00:00:00:00:00 (OK) R/W + MAC_EUI64 (BLOCK1) calc MAC_EUI64 = MAC[0]:MAC[1]:MAC[2]:MAC_EXT[0]:M + = 60:55:f9:ff:fe:f9:54:1c (OK) R/W + AC_EXT[1]:MAC[3]:MAC[4]:MAC[5] + + Security fuses: + DIS_FORCE_DOWNLOAD (BLOCK0) Represents whether the function that forces chip i = False R/W (0b0) + nto download mode is disabled or enabled.\\ 1: dis + abled\\ 0: enabled\\ + SPI_DOWNLOAD_MSPI_DIS (BLOCK0) Represents whether SPI0 controller during boot_mod = False R/W (0b0) + e_download is disabled or enabled.\\ 1: disabled\\ + 0: enabled\\ + DIS_DOWNLOAD_MANUAL_ENCRYPT (BLOCK0) Represents whether flash encrypt function is disab = False R/W (0b0) + led or enabled(except in SPI boot mode).\\ 1: disa + bled\\ 0: enabled\\ + FORCE_USE_KEY_MANAGER_KEY (BLOCK0) Set each bit to control whether corresponding key = 0 R/W (0x0) + must come from key manager. 1 is true; 0 is false. + bit 0: ecsda; bit 1: xts; bit2: hmac; bit3: ds + FORCE_DISABLE_SW_INIT_KEY (BLOCK0) Set this bit to disable software written init key; = False R/W (0b0) + and force use efuse_init_key + SPI_BOOT_CRYPT_CNT (BLOCK0) Enables flash encryption when 1 or 3 bits are set = Disable R/W (0b000) + and disables otherwise + SECURE_BOOT_KEY_REVOKE0 (BLOCK0) Revoke 1st secure boot key = False R/W (0b0) + SECURE_BOOT_KEY_REVOKE1 (BLOCK0) Revoke 2nd secure boot key = False R/W (0b0) + SECURE_BOOT_KEY_REVOKE2 (BLOCK0) Revoke 3rd secure boot key = False R/W (0b0) + KEY_PURPOSE_0 (BLOCK0) Represents the purpose of Key0 = USER R/W (0x0) + KEY_PURPOSE_1 (BLOCK0) Represents the purpose of Key1 = USER R/- (0x0) + KEY_PURPOSE_2 (BLOCK0) Represents the purpose of Key2 = USER R/W (0x0) + KEY_PURPOSE_3 (BLOCK0) Represents the purpose of Key3 = USER R/W (0x0) + KEY_PURPOSE_4 (BLOCK0) Represents the purpose of Key4 = USER R/- (0x0) + KEY_PURPOSE_5 (BLOCK0) Represents the purpose of Key5 = USER R/W (0x0) + SEC_DPA_LEVEL (BLOCK0) Represents the spa secure level by configuring the = 0 R/W (0b00) + clock random divide mode + SECURE_BOOT_EN (BLOCK0) Represents whether secure boot is enabled or disab = False R/W (0b0) + led.\\ 1: enabled\\ 0: disabled\\ + SECURE_BOOT_AGGRESSIVE_REVOKE (BLOCK0) Represents whether revoking aggressive secure boot = False R/W (0b0) + is enabled or disabled.\\ 1: enabled.\\ 0: disabl + ed\\ + KM_XTS_KEY_LENGTH_256 (BLOCK0) Set this bitto configure flash encryption use xts- = False R/W (0b0) + 128 key. else use xts-256 key + DIS_DOWNLOAD_MODE (BLOCK0) Represents whether Download mode is disabled or en = False R/W (0b0) + abled.\\ 1: disabled\\ 0: enabled\\ + LOCK_KM_KEY (BLOCK0) Represetns whether to lock the efuse xts key.\\ 1. = False R/W (0b0) + Lock\\ 0: Unlock\\ + ENABLE_SECURITY_DOWNLOAD (BLOCK0) Represents whether security download is enabled or = False R/W (0b0) + disabled.\\ 1: enabled\\ 0: disabled\\ + SECURE_VERSION (BLOCK0) Represents the version used by ESP-IDF anti-rollba = 0 R/W (0x0000) + ck feature + SECURE_BOOT_DISABLE_FAST_WAKE (BLOCK0) Represents whether FAST VERIFY ON WAKE is disabled = False R/W (0b0) + or enabled when Secure Boot is enabled.\\ 1: disa + bled\\ 0: enabled\\ + XTS_DPA_PSEUDO_LEVEL (BLOCK0) Represents the pseudo round level of xts-aes anti- = 0 R/W (0b00) + dpa attack.\\ 3: High.\\ 2: Moderate 1. Low\\ 0: D + isabled\\ + XTS_DPA_CLK_ENABLE (BLOCK0) Represents whether xts-aes anti-dpa attack clock i = False R/W (0b0) + s enabled.\\ 1. Enable.\\ 0: Disable.\\ + ECDSA_DISABLE_P192 (BLOCK0) Represents whether to disable P192 curve in ECDSA. = False R/W (0b0) + \\ 1: Disabled.\\ 0: Not disable + BLOCK_KEY0 (BLOCK4) + Purpose: USER + Key0 or user data + = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 R/W + BLOCK_KEY1 (BLOCK5) + Purpose: USER + Key1 or user data + = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 R/W + BLOCK_KEY2 (BLOCK6) + Purpose: USER + Key2 or user data + = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 R/W + BLOCK_KEY3 (BLOCK7) + Purpose: USER + Key3 or user data + = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 R/W + BLOCK_KEY4 (BLOCK8) + Purpose: USER + Key4 or user data + = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 R/W + BLOCK_KEY5 (BLOCK9) + Purpose: USER + Key5 or user data + = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 R/W + + Usb fuses: + DIS_USB_JTAG (BLOCK0) Represents whether the function of usb switch to j = False R/W (0b0) + tag is disabled or enabled.\\ 1: disabled\\ 0: ena + bled\\ + USB_EXCHG_PINS (BLOCK0) Represents whether the D+ and D- pins is exchanged = False R/W (0b0) + .\\ 1: exchanged\\ 0: not exchanged\\ + DIS_USB_SERIAL_JTAG_ROM_PRINT (BLOCK0) Represents whether print from USB-Serial-JTAG is d = False R/W (0b0) + isabled or enabled.\\ 1: disabled\\ 0: enabled\\ + DIS_USB_SERIAL_JTAG_DOWNLOAD_MODE (BLOCK0) Represents whether the USB-Serial-JTAG download fu = False R/W (0b0) + nction is disabled or enabled.\\ 1: Disable\\ 0: E + nable\\ + + Vdd fuses: + VDD_SPI_AS_GPIO (BLOCK0) Represents whether vdd spi pin is functioned as gp = False R/W (0b0) + io.\\ 1: functioned\\ 0: not functioned\\ + + Wdt fuses: + WDT_DELAY_SEL (BLOCK0) Represents the threshold level of the RTC watchdog = 0 R/W (0b00) + STG0 timeout.\\ 0: Original threshold configurati + on value of STG0 *2 \\1: Original threshold config + uration value of STG0 *4 \\2: Original threshold c + onfiguration value of STG0 *8 \\3: Original thresh + old configuration value of STG0 *16 \\ diff --git a/tools/esptool_py/docs/en/espefuse/inc/summary_ESP32-C6.rst b/tools/esptool_py/docs/en/espefuse/inc/summary_ESP32-C6.rst index fdfc78bcec..134f2d41a7 100644 --- a/tools/esptool_py/docs/en/espefuse/inc/summary_ESP32-C6.rst +++ b/tools/esptool_py/docs/en/espefuse/inc/summary_ESP32-C6.rst @@ -1,6 +1,6 @@ .. code-block:: none - > espefuse.py -p PORT summary + > espefuse -p PORT summary Connecting.... Detecting chip type... ESP32-C6 diff --git a/tools/esptool_py/docs/en/espefuse/inc/summary_ESP32-C61.rst b/tools/esptool_py/docs/en/espefuse/inc/summary_ESP32-C61.rst new file mode 100644 index 0000000000..faa6e06de7 --- /dev/null +++ b/tools/esptool_py/docs/en/espefuse/inc/summary_ESP32-C61.rst @@ -0,0 +1,161 @@ +.. code-block:: none + + > espefuse -p PORT summary + + Connecting.... + Detecting chip type... ESP32-C61 + + === Run "summary" command === + EFUSE_NAME (Block) Description = [Meaningful Value] [Readable/Writeable] (Hex Value) + ---------------------------------------------------------------------------------------- + Config fuses: + WR_DIS (BLOCK0) Disable programming of individual eFuses = 0 R/W (0x00000000) + RD_DIS (BLOCK0) Disable reading from BlOCK4-10 = 0 R/W (0b0000000) + DIS_ICACHE (BLOCK0) Represents whether icache is disabled or enabled.\ = False R/W (0b0) + \ 1: disabled\\ 0: enabled\\ + DIS_DIRECT_BOOT (BLOCK0) Represents whether direct boot mode is disabled or = False R/W (0b0) + enabled.\\ 1. Disable\\ 0: Enable\\ + UART_PRINT_CONTROL (BLOCK0) Represents the types of UART printing = 0 R/W (0b00) + HYS_EN_PAD (BLOCK0) Represents whether the hysteresis function of corr = False R/W (0b0) + esponding PAD is enabled.\\ 1: enabled\\ 0:disable + d\\ + DIS_WIFI6 (BLOCK0) Represents whether the WiFi 6 feature is enable or = False R/W (0b0) + disable.\\ 1: WiFi 6 is disable\\ 0: WiFi 6 is en + abled.\\ + ECC_FORCE_CONST_TIME (BLOCK0) Represents whether to force ecc to use const-time = False R/W (0b0) + calculation mode. \\ 1: Enable. \\ 0: Disable + PSRAM_CAP (BLOCK1) PSRAM capacity = 1 R/W (0b001) + PSRAM_VENDOR (BLOCK1) PSRAM vendor = 1 R/W (0b01) + TEMP (BLOCK1) Temperature = 1 R/W (0b01) + BLOCK_USR_DATA (BLOCK3) User data + = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 R/W + BLOCK_SYS_DATA2 (BLOCK10) System data part 2 (reserved) + = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 R/W + + Flash fuses: + FLASH_TPUW (BLOCK0) Represents the flash waiting time after power-up; = 0 R/W (0x0) + in unit of ms. When the value less than 15; the wa + iting time is programmed value. Otherwise; the wai + ting time is 2 times the programmed value + FORCE_SEND_RESUME (BLOCK0) Represents whether ROM code is forced to send a re = False R/W (0b0) + sume command during SPI boot + FLASH_CAP (BLOCK1) Flash capacity = 0 R/W (0b000) + FLASH_VENDOR (BLOCK1) Flash vendor = 0 R/W (0b000) + + Identity fuses: + WAFER_VERSION_MINOR (BLOCK1) Minor chip version = 1 R/W (0x1) + WAFER_VERSION_MAJOR (BLOCK1) Major chip version = 0 R/W (0b00) + DISABLE_WAFER_VERSION_MAJOR (BLOCK1) Disables check of wafer version major = False R/W (0b0) + DISABLE_BLK_VERSION_MAJOR (BLOCK1) Disables check of blk version major = False R/W (0b0) + BLK_VERSION_MINOR (BLOCK1) BLK_VERSION_MINOR of BLOCK2 = 0 R/W (0b000) + BLK_VERSION_MAJOR (BLOCK1) BLK_VERSION_MAJOR of BLOCK2 = 0 R/W (0b00) + PKG_VERSION (BLOCK1) Package version = 0 R/W (0b000) + OPTIONAL_UNIQUE_ID (BLOCK2) Optional unique 128-bit ID + = 75 7f 2d 6e 1c 1c 60 c6 6a 63 e6 d0 d8 8a 5b 14 R/W + + Jtag fuses: + JTAG_SEL_ENABLE (BLOCK0) Represents whether the selection between usb_to_jt = False R/W (0b0) + ag and pad_to_jtag through strapping gpio15 when b + oth EFUSE_DIS_PAD_JTAG and EFUSE_DIS_USB_JTAG are + equal to 0 is enabled or disabled.\\ 1: enabled\\ + 0: disabled\\ + DIS_PAD_JTAG (BLOCK0) Represents whether JTAG is disabled in the hard wa = False R/W (0b0) + y(permanently).\\ 1: disabled\\ 0: enabled\\ + + Mac fuses: + MAC (BLOCK1) MAC address + = 60:55:f9:fb:17:58 (OK) R/W + CUSTOM_MAC (BLOCK3) Custom MAC + = 00:00:00:00:00:00 (OK) R/W + + Security fuses: + DIS_FORCE_DOWNLOAD (BLOCK0) Represents whether the function that forces chip i = False R/W (0b0) + nto download mode is disabled or enabled.\\ 1: dis + abled\\ 0: enabled\\ + SPI_DOWNLOAD_MSPI_DIS (BLOCK0) Represents whether SPI0 controller during boot_mod = False R/W (0b0) + e_download is disabled or enabled.\\ 1: disabled\\ + 0: enabled\\ + DIS_DOWNLOAD_MANUAL_ENCRYPT (BLOCK0) Represents whether flash encrypt function is disab = False R/W (0b0) + led or enabled(except in SPI boot mode).\\ 1: disa + bled\\ 0: enabled\\ + SPI_BOOT_CRYPT_CNT (BLOCK0) Enables flash encryption when 1 or 3 bits are set = Disable R/W (0b000) + and disables otherwise + SECURE_BOOT_KEY_REVOKE0 (BLOCK0) Revoke 1st secure boot key = False R/W (0b0) + SECURE_BOOT_KEY_REVOKE1 (BLOCK0) Revoke 2nd secure boot key = False R/W (0b0) + SECURE_BOOT_KEY_REVOKE2 (BLOCK0) Revoke 3rd secure boot key = False R/W (0b0) + KEY_PURPOSE_0 (BLOCK0) Represents the purpose of Key0 = USER R/W (0x0) + KEY_PURPOSE_1 (BLOCK0) Represents the purpose of Key1 = USER R/W (0x0) + KEY_PURPOSE_2 (BLOCK0) Represents the purpose of Key2 = USER R/W (0x0) + KEY_PURPOSE_3 (BLOCK0) Represents the purpose of Key3 = USER R/W (0x0) + KEY_PURPOSE_4 (BLOCK0) Represents the purpose of Key4 = USER R/W (0x0) + KEY_PURPOSE_5 (BLOCK0) Represents the purpose of Key5 = USER R/W (0x0) + SEC_DPA_LEVEL (BLOCK0) Represents the spa secure level by configuring the = 0 R/W (0b00) + clock random divide mode + SECURE_BOOT_EN (BLOCK0) Represents whether secure boot is enabled or disab = False R/W (0b0) + led.\\ 1: enabled\\ 0: disabled\\ + SECURE_BOOT_AGGRESSIVE_REVOKE (BLOCK0) Represents whether revoking aggressive secure boot = False R/W (0b0) + is enabled or disabled.\\ 1: enabled.\\ 0: disabl + ed\\ + DIS_DOWNLOAD_MODE (BLOCK0) Represents whether Download mode is disable or ena = False R/W (0b0) + ble.\\ 1. Disable\\ 0: Enable\\ + ENABLE_SECURITY_DOWNLOAD (BLOCK0) Represents whether security download is enabled or = False R/W (0b0) + disabled.\\ 1: Enable\\ 0: Disable\\ + SECURE_VERSION (BLOCK0) Represents the version used by ESP-IDF anti-rollba = 0 R/W (0x0000) + ck feature + SECURE_BOOT_DISABLE_FAST_WAKE (BLOCK0) Represents whether FAST_VERIFY_ON_WAKE is disable = False R/W (0b0) + or enable when Secure Boot is enable + XTS_DPA_CLK_ENABLE (BLOCK0) Represents whether anti-dpa attack clock function = False R/W (0b0) + is enabled.\\ 1. Enable\\ 0: Disable\\ + XTS_DPA_PSEUDO_LEVEL (BLOCK0) Represents the anti-dpa attack pseudo function lev = 0 R/W (0b00) + el.\\ 3:High\\ 2: Moderate\\ 1: Low\\ 0: Decided b + y register configuration\\ + ECDSA_DISABLE_P192 (BLOCK0) Represents whether to disable P192 curve in ECDSA. = False R/W (0b0) + \\ 1: Disabled.\\ 0: Not disable + BLOCK_KEY0 (BLOCK4) + Purpose: USER + Key0 or user data + = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 R/W + BLOCK_KEY1 (BLOCK5) + Purpose: USER + Key1 or user data + = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 R/W + BLOCK_KEY2 (BLOCK6) + Purpose: USER + Key2 or user data + = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 R/W + BLOCK_KEY3 (BLOCK7) + Purpose: USER + Key3 or user data + = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 R/W + BLOCK_KEY4 (BLOCK8) + Purpose: USER + Key4 or user data + = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 R/W + BLOCK_KEY5 (BLOCK9) + Purpose: USER + Key5 or user data + = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 R/W + + Usb fuses: + DIS_USB_JTAG (BLOCK0) Represents whether the function of usb switch to j = False R/W (0b0) + tag is disabled or enabled.\\ 1: disabled\\ 0: ena + bled\\ + USB_EXCHG_PINS (BLOCK0) Represents whether the D+ and D- pins is exchanged = False R/W (0b0) + .\\ 1: exchanged\\ 0: not exchanged\\ + DIS_USB_SERIAL_JTAG_ROM_PRINT (BLOCK0) Represents whether print from USB-Serial-JTAG is d = False R/W (0b0) + isabled or enabled.\\ 1. Disable\\ 0: Enable\\ + DIS_USB_SERIAL_JTAG_DOWNLOAD_MODE (BLOCK0) Represents whether the USB-Serial-JTAG download fu = False R/W (0b0) + nction is disabled or enabled.\\ 1: Disable\\ 0: E + nable\\ + + Vdd fuses: + VDD_SPI_AS_GPIO (BLOCK0) Represents whether vdd spi pin is functioned as gp = False R/W (0b0) + io.\\ 1: functioned\\ 0: not functioned\\ + + Wdt fuses: + WDT_DELAY_SEL (BLOCK0) Represents the threshold level of the RTC watchdog = 0 R/W (0b00) + STG0 timeout.\\ 0: Original threshold configurati + on value of STG0 *2 \\1: Original threshold config + uration value of STG0 *4 \\2: Original threshold c + onfiguration value of STG0 *8 \\3: Original thresh + old configuration value of STG0 *16 \\ diff --git a/tools/esptool_py/docs/en/espefuse/inc/summary_ESP32-H2.rst b/tools/esptool_py/docs/en/espefuse/inc/summary_ESP32-H2.rst index 53c48e830e..74a033bd35 100644 --- a/tools/esptool_py/docs/en/espefuse/inc/summary_ESP32-H2.rst +++ b/tools/esptool_py/docs/en/espefuse/inc/summary_ESP32-H2.rst @@ -1,6 +1,6 @@ .. code-block:: none - > espefuse.py -p PORT summary + > espefuse -p PORT summary Connecting.... Detecting chip type... ESP32-H2 diff --git a/tools/esptool_py/docs/en/espefuse/inc/summary_ESP32-P4.rst b/tools/esptool_py/docs/en/espefuse/inc/summary_ESP32-P4.rst index e03d5f06ac..aef4bdebad 100644 --- a/tools/esptool_py/docs/en/espefuse/inc/summary_ESP32-P4.rst +++ b/tools/esptool_py/docs/en/espefuse/inc/summary_ESP32-P4.rst @@ -1,6 +1,6 @@ .. code-block:: none - > espefuse.py -p PORT summary + > espefuse -p PORT summary Connecting.... Detecting chip type... ESP32-P4 @@ -64,7 +64,7 @@ Jtag fuses: JTAG_SEL_ENABLE (BLOCK0) Represents whether the selection between usb_to_jt = False R/W (0b0) - ag and pad_to_jtag through strapping gpio15 when b + ag and pad_to_jtag through strapping gpio34 when b oth EFUSE_DIS_PAD_JTAG and EFUSE_DIS_USB_JTAG are equal to 0 is enabled or disabled. 1: enabled. 0: disabled diff --git a/tools/esptool_py/docs/en/espefuse/inc/summary_ESP32-S2.rst b/tools/esptool_py/docs/en/espefuse/inc/summary_ESP32-S2.rst index 8589c36207..c1d918f392 100644 --- a/tools/esptool_py/docs/en/espefuse/inc/summary_ESP32-S2.rst +++ b/tools/esptool_py/docs/en/espefuse/inc/summary_ESP32-S2.rst @@ -1,6 +1,6 @@ .. code-block:: none - > espefuse.py -p PORT summary + > espefuse -p PORT summary Connecting.... Detecting chip type... ESP32-S2 diff --git a/tools/esptool_py/docs/en/espefuse/inc/summary_ESP32-S3.rst b/tools/esptool_py/docs/en/espefuse/inc/summary_ESP32-S3.rst index dbd4b05859..9b32662a4b 100644 --- a/tools/esptool_py/docs/en/espefuse/inc/summary_ESP32-S3.rst +++ b/tools/esptool_py/docs/en/espefuse/inc/summary_ESP32-S3.rst @@ -1,6 +1,6 @@ .. code-block:: none - > espefuse.py -p PORT summary + > espefuse -p PORT summary Connecting.... Detecting chip type... ESP32-S3 @@ -57,7 +57,7 @@ DIS_PAD_JTAG (BLOCK0) Set this bit to disable JTAG in the hard way. JTAG = False R/W (0b0) is disabled permanently STRAP_JTAG_SEL (BLOCK0) Set this bit to enable selection between usb_to_jt = False R/W (0b0) - ag and pad_to_jtag through strapping gpio10 when b + ag and pad_to_jtag through strapping gpio3 when b oth reg_dis_usb_jtag and reg_dis_pad_jtag are equa l to 0 diff --git a/tools/esptool_py/docs/en/espefuse/inc/summary_ESP32.rst b/tools/esptool_py/docs/en/espefuse/inc/summary_ESP32.rst index ff4d018f07..bc323998e4 100644 --- a/tools/esptool_py/docs/en/espefuse/inc/summary_ESP32.rst +++ b/tools/esptool_py/docs/en/espefuse/inc/summary_ESP32.rst @@ -1,6 +1,6 @@ .. code-block:: none - > espefuse.py -p PORT summary + > espefuse -p PORT summary Connecting........__ Detecting chip type... ESP32 diff --git a/tools/esptool_py/docs/en/espefuse/index.rst b/tools/esptool_py/docs/en/espefuse/index.rst index 26e19cb496..3fefe9a15b 100644 --- a/tools/esptool_py/docs/en/espefuse/index.rst +++ b/tools/esptool_py/docs/en/espefuse/index.rst @@ -1,19 +1,19 @@ .. _espefuse: -espefuse.py -=========== +espefuse +======== -``espefuse.py`` is a tool for communicating with Espressif chips for the purpose of reading/writing ("burning") the one-time-programmable eFuses. Burning occurs only in one direction from 0 to 1 (never cleared 1->0). +``espefuse`` is a tool for communicating with Espressif chips for the purpose of reading/writing ("burning") the one-time-programmable eFuses. Burning occurs only in one direction from 0 to 1 (never cleared 1->0). .. warning:: Because eFuse is one-time-programmable, it is possible to permanently damage or "brick" your {IDF_TARGET_NAME} using this tool. Use it with great care. -For more details about Espressif chips eFuse features, see the `Technical Reference Manual `__. +For more details about Espressif chips eFuse features, see the `{IDF_TARGET_NAME} Technical Reference Manual <{IDF_TARGET_TRM_EN_URL}>`__. -``espefuse.py`` is installed alongside ``esptool.py``, so if ``esptool.py`` (v2.0 or newer) is available on the PATH then ``espefuse.py`` should be as well. +``espefuse`` is installed alongside ``esptool``, so if ``esptool`` (v2.0 or newer) is available on the PATH then ``espefuse`` should be as well. -Initial State of Efuses +Initial State of eFuses ----------------------- On relatively new chip, most eFuses are unburned (value 0). Some eFuses are already burned at the factory stage: @@ -31,34 +31,33 @@ Supported Commands dump summary - burn_efuse - burn_block_data - burn_bit - read_protect_efuse and write_protect_efuse - burn_key - burn_key_digest - burn_custom_mac - get_custom_mac - adc_info - set_flash_voltage - execute_scripts - check_error + burn-efuse + burn-block-data + burn-bit + read-protect-efuse and write-protect-efuse + burn-key + burn-key-digest + burn-custom-mac + get-custom-mac + adc-info + set-flash-voltage + check-error Optional General Arguments Of Commands -------------------------------------- -- ``-h``, ``--help`` - Show help message and exit. Use ``-h`` to see a summary of all available commands and command line options. To see all options for a particular chip and command, add ``-c {IDF_TARGET_NAME}`` and ``-h`` to the command name, i.e. ``espefuse.py -c {IDF_TARGET_NAME} burn_key -h``. +- ``-h``, ``--help`` - Show help message and exit. Use ``-h`` to see a summary of all available commands and command line options. To see all options for a particular chip and command, add ``-c {IDF_TARGET_NAME}`` and ``-h`` to the command name, i.e. ``espefuse -c {IDF_TARGET_NAME} burn-key -h``. - ``--chip``, ``-c`` - Target chip type. If this argument is omitted, the tool automatically detects the chip type when connected. But if the command has a help option, the chip is not connected, and the default chip is ``esp32``, please specify the specific type of chip to get the correct help. Example of usage: ``-c esp32``, ``-c esp32c3``, ``-c esp32s2`` and others. - ``--baud``, ``-b`` - Serial port baud rate, the same as for esptool. -- ``--port``, ``-p`` - Serial port device, ``-p /dev/ttyUSB0`` (Linux and macOS) or ``-p COM1`` (Windows). -- ``--before`` - What to do before connecting to the chip: ``default_reset``, ``no_reset``, ``esp32r1``, ``no_reset_no_sync``. +- ``--port``, ``-p`` - Serial port device, for example: ``-p /dev/ttyUSB0`` (Linux and macOS) or ``-p COM1`` (Windows). +- ``--before`` - What to do before connecting to the chip: ``default-reset``, ``no-reset``, ``esp32r1``, ``no-reset-no-sync``. - ``--debug``, ``-d`` - Show debugging information. - ``--virt`` - For host tests. The tool will work in the virtual mode (without connecting to a chip). - ``--path-efuse-file`` - For host tests. Use it together with ``--virt`` option. The tool will work in the virtual mode (without connecting to a chip) and save eFuse memory to a given file. If the file does not exists the tool creates it. To reset written eFuses just delete the file. Usage: ``--path-efuse-file efuse_memory.bin``. - ``--do-not-confirm`` - Do not pause for confirmation before permanently writing eFuses. Use with caution. If this option is not used, a manual confirmation step is required, you need to enter the word ``BURN`` to continue burning. - ``--extend-efuse-table`` - CSV file from `ESP-IDF `_ (esp_efuse_custom_table.csv). -Virtual mode +Virtual Mode ^^^^^^^^^^^^ This mode is enabled with the ``--virt`` flag (need to specify chip with ``--chip``). This helps to test commands without physical access to the chip. Burned data is not saved between commands. Using ``--path-efuse-file``, you can save the written data to a file. Delete the file to clear eFuses. @@ -94,7 +93,7 @@ This tool automatically adds encoding data to the burning data if it requires. E All coding schemes (except ``None``) require additional encoding data to be provided at write time. Due to the encoding data, such blocks cannot be overwritten again without breaking the block's coding scheme. Use the :ref:`perform-multiple-operations` feature or list multiple eFuses/keys. -Burning Efuse +Burning eFuse ------------- Burning occurs in order from BLOCK(max) to BLOCK0. This prevents read/write protection from being set before the data is set. After burning, the tool reads the written data back and compares the original data, and additionally checks the status of the coding scheme, if there are any errors, it re-burns the data again to correct it. @@ -106,22 +105,22 @@ Perform Multiple Operations In A Single Espefuse Run Some eFuse blocks have an encoding scheme (Reed-Solomon or 3/4) that requires encoded data, making these blocks only writable once. If you need to write multiple keys/eFuses to one block using different commands, you can use this feature - multiple commands. This feature burns given data once at the end of all commands. All commands supported by version v3.2 or later are supported to be chained together. -The example below shows how to use the two commands ``burn_key_digest`` and ``burn_key`` to write the Secure Boot key and Flash Encryption key into one BLOCK3 for the ``ESP32-C2`` chip. Using these commands individually will result in only one key being written correctly. +The example below shows how to use the two commands ``burn-key-digest`` and ``burn-key`` to write the Secure Boot key and Flash Encryption key into one BLOCK3 for the ``ESP32-C2`` chip. Using these commands individually will result in only one key being written correctly. .. code-block:: none - > espefuse.py -c esp32c2 \ - burn_key_digest secure_images/ecdsa256_secure_boot_signing_key_v2.pem \ - burn_key BLOCK_KEY0 images/efuse/128bit_key.bin XTS_AES_128_KEY_DERIVED_FROM_128_EFUSE_BITS + > espefuse -c esp32c2 \ + burn-key-digest secure_images/ecdsa256_secure_boot_signing_key_v2.pem \ + burn-key BLOCK_KEY0 images/efuse/128bit_key.bin XTS_AES_128_KEY_DERIVED_FROM_128_EFUSE_BITS -Extend Efuse Table +Extend eFuse Table ------------------ This tool supports the use of `CSV files `_ from the `ESP-IDF `_ (e.g., ``esp_efuse_custom_table.csv``) to add custom eFuse fields. You can use this argument with any supported commands to access these custom eFuses. .. code-block:: none - > espefuse.py -c esp32 --extend-efuse-table path/esp_efuse_custom_table.csv summary + > espefuse -c esp32 --extend-efuse-table path/esp_efuse_custom_table.csv summary Below is an example of an ``esp_efuse_custom_table.csv`` file. This example demonstrates how to define single eFuse fields, ``structured eFuse fields`` and ``non-sequential bit fields``: @@ -160,16 +159,27 @@ When you include this CSV file, the tool will generate a new section in the summ You can reference these fields using the names and aliases provided in the CSV file. For non-sequential bits, the names are modified slightly with the addition of _0 and _1 postfixes for every sub-field, to ensure safer handling. -For the current example, you can reference the custom fields with the following names: MODULE_VERSION, DEVICE_ROLE, SETTING_1, SETTING_2, ID_NUM_0, ID_NUM_1, ID_NUM_2, CUSTOM_SECURE_VERSION, ID_NUMK_0, ID_NUMK_1, MY_DATA, MY_DATA_FIELD1; and alises: SETTING_1_ALT_NAME, MY_ID_NUM_0, MY_ID_NUM_1, MY_ID_NUM_2, MY_ID_NUMK_0, MY_ID_NUMK_1. +For the current example, you can reference the custom fields with the following names: MODULE_VERSION, DEVICE_ROLE, SETTING_1, SETTING_2, ID_NUM_0, ID_NUM_1, ID_NUM_2, CUSTOM_SECURE_VERSION, ID_NUMK_0, ID_NUMK_1, MY_DATA, MY_DATA_FIELD1; and aliases: SETTING_1_ALT_NAME, MY_ID_NUM_0, MY_ID_NUM_1, MY_ID_NUM_2, MY_ID_NUMK_0, MY_ID_NUMK_1. For convenience, the espefuse summary command includes the used bit range of the field in a comment, such as ``(150-157)`` len = 8 bits. For more details on the structure and usage of the CSV file, refer to the `eFuse Manager `_ chapter in the ESP-IDF documentation. +Scripting +--------- + +Espefuse can be used as a Python library. See :ref:`espefuse Scripting ` for more details. + +.. toctree:: + :maxdepth: 1 + :hidden: + + scripting + Recommendations --------------- -1. The `Technical Reference Manual `__ has a recommendation for reducing the number of burn operations as much as possible. The tool supports several ways to do this: +1. The `{IDF_TARGET_NAME} Technical Reference Manual <{IDF_TARGET_TRM_EN_URL}>`__ has a recommendation for reducing the number of burn operations as much as possible. The tool supports several ways to do this: - Combine multiple commands into one with this :ref:`perform-multiple-operations` feature. - Most commands support getting a list of arguments (eFuse names, keys). diff --git a/tools/esptool_py/docs/en/espefuse/read-write-protections-cmd.rst b/tools/esptool_py/docs/en/espefuse/read-write-protections-cmd.rst index e1611e538b..fbfbf6b640 100644 --- a/tools/esptool_py/docs/en/espefuse/read-write-protections-cmd.rst +++ b/tools/esptool_py/docs/en/espefuse/read-write-protections-cmd.rst @@ -5,8 +5,8 @@ Read Write Protection There are two commands (to get the correct list of eFuse fields that can be protected, specify the chip with ``--chip``): -- ``espefuse.py read_protect_efuse``. It sets read protection for given eFuse names. -- ``espefuse.py write_protect_efuse``. It sets write protection for given eFuse names. +- ``espefuse read-protect-efuse``. It sets read protection for given eFuse names. +- ``espefuse write-protect-efuse``. It sets write protection for given eFuse names. Positional arguments: @@ -40,9 +40,9 @@ Usage .. code-block:: none - > espefuse.py read_protect_efuse BLOCK2 BLOCK3 MAC_VERSION + > espefuse read-protect-efuse BLOCK2 BLOCK3 MAC_VERSION - === Run "read_protect_efuse" command === + === Run "read-protect-efuse" command === If Secure Boot V2 is used, BLOCK2 must be readable, please stop this operation! Permanently read-disabling efuse BLOCK2 Permanently read-disabling efuses MAC_VERSION, BLOCK3 @@ -62,9 +62,9 @@ Usage .. code-block:: none - > espefuse.py write_protect_efuse WR_DIS FLASH_CRYPT_CNT + > espefuse write-protect-efuse WR_DIS FLASH_CRYPT_CNT - === Run "write_protect_efuse" command === + === Run "write-protect-efuse" command === Permanently write-disabling efuse WR_DIS Permanently write-disabling efuses FLASH_CRYPT_CNT, UART_DOWNLOAD_DIS diff --git a/tools/esptool_py/docs/en/espefuse/scripting.rst b/tools/esptool_py/docs/en/espefuse/scripting.rst new file mode 100644 index 0000000000..261ebf8061 --- /dev/null +++ b/tools/esptool_py/docs/en/espefuse/scripting.rst @@ -0,0 +1,231 @@ +.. _espefuse-scripting: + +Embedding into Custom Scripts +============================= + +Similar to :ref:`esptool `, ``espefuse`` can be easily integrated into Python applications or called from other Python scripts. + +For details on redirecting the output, see :ref:`esptool logging section `. + +Using Espefuse as a Python Module +--------------------------------- + +The espefuse module provides a comprehensive Python API for interacting with ESP32 chips programmatically. By leveraging the API, developers can automate tasks such as reading and writing eFuse values, managing secure boot, and more. + +The API also provides the benefit of being able to chain commands with ``esptool`` commands and create a custom script. With this approach, you can e.g. flash firmware and set eFuse values in one go. + +Using the Command-Line Interface +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The most straightforward and basic integration option is to pass arguments to ``espefuse.main()``. This workaround allows you to pass exactly the same arguments as you would on the CLI: + +.. code-block:: python + + import espefuse + + command = ["--port", "/dev/ttyACM0", "summary"] + print("Using command ", " ".join(command)) + espefuse.main(command) + + +Public API Reference +^^^^^^^^^^^^^^^^^^^^ + +Basic Workflow: + +1. **Detect and Connect**: Connect to the chip and load the available eFuse commands for the given chip. +2. **Execute Commands**: Execute the commands you need, e.g. read the current eFuse values. +3. **Reset and Cleanup**: Reset the chip if needed. Context manager will take care of closing the port. + +This example demonstrates a basic workflow using the espefuse API to read the current eFuse values: + +.. code-block:: python + + from espefuse import init_commands + + PORT = "/dev/ttyACM0" + + # Autodetect and connect to the chip and load the eFuse commands for the given chip + with init_commands(port=PORT) as espefuse: + espefuse.summary() # Print the current eFuse values + + # Get the value of single eFuse + custom_mac = espefuse.efuses["CUSTOM_MAC"].get() + print(f"CUSTOM_MAC: {custom_mac}") + +.. note:: + + It is also possible to operate in virtual mode, which allows to read and write eFuse values without connecting to the chip for testing purposes. + For more information, refer to :func:`init_commands ` docstring or take a look at tests in :file:`test/test_espefuse.py`. + +------------ + +This API can be also used to chain commands with esptool commands. + +.. code-block:: python + + from espefuse import init_commands + from esptool import attach_flash, flash_id, reset_chip + + PORT = "/dev/ttyACM0" + + with init_commands(port=PORT) as espefuse: + espefuse.summary() # Get the current eFuse values + # Esptool commands + attach_flash(espefuse.esp) # Attach the flash memory chip, required for flash operations + flash_id(espefuse.esp) # Get the flash information + reset_chip(espefuse.esp, "hard-reset") # Reset the chip + +------------ + +If you would like to have a better control over the ESP object from esptool, you can first get the ESP object from esptool as described in :ref:`esptool ` and then pass it to the espefuse API. + +.. code-block:: python + + from espefuse import init_commands + from esptool import detect_chip, run_stub, attach_flash, flash_id, reset_chip + + PORT = "/dev/ttyACM0" + + # Get the ESP object from esptool + with detect_chip(PORT) as esp: + # Prepare the ESP object; run stub and attach flash + esp = run_stub(esp) + attach_flash(esp) + + # Pass the ESP object to the espefuse API + with init_commands(esp=esp) as espefuse: + espefuse.summary() # Get the current eFuse values + # External ESP object was passed, so port won't be closed here + + # Here you can continue with esptool commands if needed + flash_id(esp) # Get the flash information + + reset_chip(esp, "hard-reset") # Reset the chip + +------------ + +Batch Mode +^^^^^^^^^^ + +For burning eFuses, it is possible to use batch mode. This allows to queue multiple eFuse operations and execute them all at once. +Please note that nesting batch mode is also supported. + +Batch mode is enabled by passing the ``batch_mode=True`` argument to the function :func:`init_commands `. +Or can be enabled later by calling the :func:`use_batch_mode ` method. + +The :func:`burn_all ` method will execute all queued eFuse operations and decrement the batch mode counter. + +Here is an example of how to use a batch mode on ESP32: + +.. code-block:: python + + from espefuse import init_commands + + PORT = "/dev/ttyACM0" + + # Connect to chip and enable batch mode + with init_commands(port=PORT, batch_mode=True) as espefuse: + # Queue multiple eFuse operations + with open("flash_encryption_key.bin", "rb") as f: + espefuse.burn_key(["flash_encryption"], [f], no_protect_key=True) + espefuse.burn_efuse({"FLASH_CRYPT_CNT": 0x7}) + espefuse.burn_efuse({"DISABLE_DL_ENCRYPT": 1}) + espefuse.burn_efuse({"JTAG_DISABLE": 1}) + + # Execute all queued eFuse operations + espefuse.burn_all() + + # Check that all eFuses are set properly + espefuse.summary() + + # Checks written eFuses + if espefuse.efuses["FLASH_CRYPT_CNT"].get() != 0x7: + raise esptool.FatalError("FLASH_CRYPT_CNT was not set") + if espefuse.efuses["DISABLE_DL_ENCRYPT"].get() != 1: + raise esptool.FatalError("DISABLE_DL_ENCRYPT was not set") + if espefuse.efuses["JTAG_DISABLE"].is_readable() or espefuse.efuses["JTAG_DISABLE"].is_writeable(): + raise esptool.FatalError("JTAG_DISABLE should be read and write protected") + +.. note:: + + Please note that provided example is written for ESP32. For other chips, the names of eFuses might be different and signature of the :func:`burn_key ` function might also be different. + +After ``espefuse.burn_all()``, all needed eFuses will be burnt to chip in order ``BLK_MAX`` to ``BLK_0``. This order prevents cases when protection is set before the value goes to a block. Please note this while developing your scripts. +Upon completion, the new eFuses will be read back, and checks will be performed on the written eFuses by ``espefuse``. In production, you might need to check that all written eFuses are set properly. +In the example above, we check that ``FLASH_CRYPT_CNT`` and ``DISABLE_DL_ENCRYPT`` are set properly. Also, we check that ``JTAG_DISABLE`` is read and write protected. + +------------ + +**The following section provides a detailed reference for the public API functions.** + +Init Commands +^^^^^^^^^^^^^ + +.. autofunction:: espefuse.init_commands + +.. autofunction:: espefuse.get_esp + +------------ + +Batch Mode Helpers +^^^^^^^^^^^^^^^^^^ + +.. autofunction:: espefuse.BaseCommands.use_batch_mode + +.. autofunction:: espefuse.BaseCommands.burn_all + +------------ + +Common Read Commands +^^^^^^^^^^^^^^^^^^^^ + +.. autofunction:: espefuse.BaseCommands.summary + +.. autofunction:: espefuse.BaseCommands.dump + +.. autofunction:: espefuse.BaseCommands.get_custom_mac + +.. autofunction:: espefuse.BaseCommands.adc_info + +.. autofunction:: espefuse.BaseCommands.check_error + +------------ + +Common Write Commands +^^^^^^^^^^^^^^^^^^^^^ + +.. autofunction:: espefuse.BaseCommands.burn_efuse + +.. autofunction:: espefuse.BaseCommands.read_protect_efuse + +.. autofunction:: espefuse.BaseCommands.write_protect_efuse + +.. autofunction:: espefuse.BaseCommands.burn_block_data + +.. autofunction:: espefuse.BaseCommands.burn_bit + +.. autofunction:: espefuse.BaseCommands.burn_custom_mac + +.. autofunction:: espefuse.BaseCommands.set_flash_voltage + +------------ + +Chip-Specific Commands +^^^^^^^^^^^^^^^^^^^^^^ + +.. autofunction:: espefuse.efuse.{IDF_TARGET_PATH_NAME}.commands.burn_key + +.. autofunction:: espefuse.efuse.{IDF_TARGET_PATH_NAME}.commands.burn_key_digest + + +eFuse Operations +^^^^^^^^^^^^^^^^ + +.. autofunction:: espefuse.efuse.base_fields.EfuseFieldBase.get + +.. autofunction:: espefuse.efuse.base_fields.EfuseFieldBase.is_readable + +.. autofunction:: espefuse.efuse.base_fields.EfuseFieldBase.is_writeable + +.. autofunction:: espefuse.efuse.base_fields.EfuseFieldBase.get_meaning diff --git a/tools/esptool_py/docs/en/espefuse/set-flash-voltage-cmd.rst b/tools/esptool_py/docs/en/espefuse/set-flash-voltage-cmd.rst index 6340858cae..f3202da4f2 100644 --- a/tools/esptool_py/docs/en/espefuse/set-flash-voltage-cmd.rst +++ b/tools/esptool_py/docs/en/espefuse/set-flash-voltage-cmd.rst @@ -9,7 +9,7 @@ Set Flash Voltage {IDF_TARGET_VDD_REG:default="VDD_SPI_XPD",esp32="XPD_SDIO_REG"} {IDF_TARGET_VDD_GPIO:default="GPIO45",esp32="GPIO12"} -The ``espefuse.py set_flash_voltage`` command permanently sets the internal flash voltage regulator to either 1.8V, 3.3V or OFF. This means a GPIO can be high or low at reset without changing the flash voltage. +The ``espefuse set-flash-voltage`` command permanently sets the internal flash voltage regulator to either 1.8V, 3.3V or OFF. This means a GPIO can be high or low at reset without changing the flash voltage. Positional arguments: @@ -19,14 +19,14 @@ Positional arguments: .. note:: - This command is not supported. The tool prints the error ``set_flash_voltage not supported!``. + This command is not supported. The tool prints the error ``set-flash-voltage not supported!``. Setting Flash Voltage ({IDF_TARGET_VDD_SPI}) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -After reset, the default {IDF_TARGET_NAME} behaviour is to enable and configure the flash voltage regulator ({IDF_TARGET_VDD_SPI}) based on the level of the MTDI pin ({IDF_TARGET_VDD_GPIO}). +After reset, the default {IDF_TARGET_NAME} behavior is to enable and configure the flash voltage regulator ({IDF_TARGET_VDD_SPI}) based on the level of the MTDI pin ({IDF_TARGET_VDD_GPIO}). -The default behaviour on reset is: +The default behavior on reset is: +--------------------+--------------------+ | MTDI | Internal Regulator | @@ -44,28 +44,28 @@ The default behaviour on reset is: Consult {IDF_TARGET_NAME} Technical Reference Manual for details. -A combination of 3 efuses (``{IDF_TARGET_VDD_FORCE}``, ``{IDF_TARGET_VDD_REG}``, ``{IDF_TARGET_VDD_TIEH}``) can be burned in order to override this behaviour and disable {IDF_TARGET_VDD_SPI} regulator, or set it to a fixed voltage. These efuses can be burned with individual ``burn_efuse`` commands, but the ``set_flash_voltage`` command makes it easier: +A combination of 3 eFuses (``{IDF_TARGET_VDD_FORCE}``, ``{IDF_TARGET_VDD_REG}``, ``{IDF_TARGET_VDD_TIEH}``) can be burned in order to override this behavior and disable {IDF_TARGET_VDD_SPI} regulator, or set it to a fixed voltage. These eFuses can be burned with individual ``burn-efuse`` commands, but the ``set-flash-voltage`` command makes it easier: Disable {IDF_TARGET_VDD_SPI} Regulator ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. code-block:: none - espefuse.py set_flash_voltage OFF + espefuse set-flash-voltage OFF Once set: * {IDF_TARGET_VDD_SPI} regulator always disabled. * MTDI pin ({IDF_TARGET_VDD_GPIO}) is ignored. * Flash must be powered externally and voltage supplied to {IDF_TARGET_VDD_SPI} pin of {IDF_TARGET_NAME}. -* Efuse ``{IDF_TARGET_VDD_FORCE}`` is burned. +* eFuse ``{IDF_TARGET_VDD_FORCE}`` is burned. Fixed 1.8V {IDF_TARGET_VDD_SPI} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. code-block:: none - espefuse.py set_flash_voltage 1.8V + espefuse set-flash-voltage 1.8V Once set: @@ -79,7 +79,7 @@ Fixed 3.3V {IDF_TARGET_VDD_SPI} .. code-block:: none - espefuse.py set_flash_voltage 3.3V + espefuse set-flash-voltage 3.3V Once set: @@ -91,19 +91,19 @@ Once set: Subsequent Changes ^^^^^^^^^^^^^^^^^^ -Once an efuse is burned it cannot be un-burned. However, changes can be made by burning additional efuses: +Once an eFuse is burned it cannot be un-burned. However, changes can be made by burning additional eFuses: -* ``set_flash_voltage OFF`` can be changed to ``1.8V`` or ``3.3V`` -* ``set_flash_voltage 1.8V`` can be changed to ``3.3V`` +* ``set-flash-voltage OFF`` can be changed to ``1.8V`` or ``3.3V`` +* ``set-flash-voltage 1.8V`` can be changed to ``3.3V`` .. only:: esp32s2 or esp32s3 .. code-block:: none - > espefuse.py set_flash_voltage 1.8V + > espefuse set-flash-voltage 1.8V - === Run "set_flash_voltage" command === + === Run "set-flash-voltage" command === Set internal flash voltage regulator (VDD_SPI) to 1.8V. VDD_SPI setting complete. @@ -122,9 +122,9 @@ Once an efuse is burned it cannot be un-burned. However, changes can be made by .. code-block:: none - > espefuse.py set_flash_voltage 3.3V + > espefuse set-flash-voltage 3.3V - === Run "set_flash_voltage" command === + === Run "set-flash-voltage" command === Enable internal flash voltage regulator (VDD_SPI) to 3.3V. VDD_SPI setting complete. @@ -143,9 +143,9 @@ Once an efuse is burned it cannot be un-burned. However, changes can be made by .. code-block:: none - > espefuse.py set_flash_voltage OFF + > espefuse set-flash-voltage OFF - === Run "set_flash_voltage" command === + === Run "set-flash-voltage" command === Disable internal flash voltage regulator (VDD_SPI). SPI flash will VDD_SPI setting complete. diff --git a/tools/esptool_py/docs/en/espefuse/summary-cmd.rst b/tools/esptool_py/docs/en/espefuse/summary-cmd.rst index 195083ebdd..f92c00e93d 100644 --- a/tools/esptool_py/docs/en/espefuse/summary-cmd.rst +++ b/tools/esptool_py/docs/en/espefuse/summary-cmd.rst @@ -3,7 +3,7 @@ Summary ======= -The ``espefuse.py summary`` command reads the eFuses from the chip and outputs them in text or json format. It is also possible to save it to a file. The command also supports eFuse filtering by name. +The ``espefuse summary`` command reads the eFuses from the chip and outputs them in text or json format. It is also possible to save it to a file. The command also supports eFuse filtering by name. Optional arguments: @@ -11,7 +11,7 @@ Optional arguments: - ``summary`` - text format (default option). - ``json`` - json format. Usage ``--format json``. - ``value_only`` - only the value of the eFuse specified as an argument will be displayed. For more information, refer to the :ref:`Filtering eFuses ` section. -- ``--file`` - File to save the efuse summary. Usage ``--file efuses.json``. +- ``--file`` - File to save the eFuse summary. Usage ``--file efuses.json``. - List of eFuses to filter. For more information, refer to the :ref:`Filtering eFuses ` section. Text Format Summary @@ -56,7 +56,7 @@ The json representation of eFuses for the ESP32 chip is shown below. .. code-block:: none - > espefuse.py summary --format json + > espefuse summary --format json { "ABS_DONE_0": { @@ -107,10 +107,8 @@ Save Json Format Summary To File .. code-block:: none - > espefuse.py summary --format json --file efuses.json + > espefuse summary --format json --file efuses.json - Connecting.......... - Detecting chip type... Unsupported detection protocol, switching and trying again... Connecting.... Detecting chip type... ESP32 @@ -122,11 +120,11 @@ Save Json Format Summary To File Filtering Efuses and Displaying Only the Value ---------------------------------------------- -The ``espefuse.py summary`` command supports filtering eFuses by name. The eFuses to filter needs to be specified as positional arguments. If no eFuses are specified, complete summary will be displayed. Example: +The ``espefuse summary`` command supports filtering eFuses by name. The eFuses to filter needs to be specified as positional arguments. If no eFuses are specified, complete summary will be displayed. Example: .. code-block:: none - > espefuse.py summary ABS_DONE_0 BLOCK1 + > espefuse summary ABS_DONE_0 BLOCK1 === Run "summary" command === EFUSE_NAME (Block) Description = [Meaningful Value] [Readable/Writeable] (Hex Value) @@ -140,7 +138,7 @@ If ``--format value_only`` is specified, only the value of the eFuse specified a .. code-block:: none - > espefuse.py summary --format value_only MAC + > espefuse summary --format value_only MAC === Run "summary" command === 00:00:00:00:00:00 (CRC 0x00 OK) diff --git a/tools/esptool_py/docs/en/espsecure/index.rst b/tools/esptool_py/docs/en/espsecure/index.rst index c03b3478e1..6bd2a1604b 100644 --- a/tools/esptool_py/docs/en/espsecure/index.rst +++ b/tools/esptool_py/docs/en/espsecure/index.rst @@ -1,9 +1,9 @@ .. _espsecure: -espsecure.py -============ +espsecure +========= -``espsecure.py`` is a tool for manipulating data that relates to the secure boot and flash encryption features of ESP32 and later Espressif chips. +``espsecure`` is a tool for manipulating data that relates to the secure boot and flash encryption features of ESP32 and later Espressif chips. For more details, see the ESP-IDF documentation which explains this tool and how to use it to enable the relevant features: @@ -12,22 +12,22 @@ For more details, see the ESP-IDF documentation which explains this tool and how .. _hsm_signing: -Remote Signing using an external HSM +Remote Signing Using an External HSM ------------------------------------ An external Hardware Security Module (HSM) can be used for remote signing of images in secure boot v2 scheme. -You must install ``esptool.py`` package with the ``hsm`` extra using the command ``pip install 'esptool[hsm]'`` to use this feature. ``esp_hsm_sign`` provides a PKCS #11 interface to communicate with the external HSM and is integrated in ``espsecure.py``. +You must install ``esptool`` package with the ``hsm`` extra using the command ``pip install 'esptool[hsm]'`` to use this feature. ``esp_hsm_sign`` provides a PKCS #11 interface to communicate with the external HSM and is integrated in ``espsecure``. The following command should be used to get an image signed using an external HSM. :: - python espsecure.py sign_data --version 2 --hsm --hsm-config --output + espsecure sign-data --version 2 --hsm --hsm-config --output The above command first extracts the public key from the HSM, generates a signature for an image using the HSM, and then creates a signature block and appends it to the image to generate a signed image. If the public key is not stored in the external HSM, you can specify the ``--pub-key`` argument to supply the public key. :: - python espsecure.py sign_data --version 2 --hsm --hsm-config --pub-key --output + espsecure sign-data --version 2 --hsm --hsm-config --pub-key --output .. note:: In case you are using ESP-IDF, then an unsigned application can be generated by disabling ``CONFIG_SECURE_BOOT_BUILD_SIGNED_BINARIES`` configuration option in the project settings. @@ -37,14 +37,14 @@ Verifying the Signed Image Once the signed image is generated, we can verify it using the following command: :: - python espsecure.py verify_signature --version 2 --hsm --hsm-config + espsecure verify-signature --version 2 --hsm --hsm-config If the public key is not stored in the external HSM, you can specify the ``--keyfile`` argument to supply the public key. :: - python espsecure.py verify_signature --version 2 --keyfile + espsecure verify-signature --version 2 --keyfile -HSM config file +HSM Config File ~~~~~~~~~~~~~~~ An HSM config file is required with the fields (``pkcs11_lib``, ``credentials``, ``slot``, ``label``, ``label_pubkey``) diff --git a/tools/esptool_py/docs/en/esptool/advanced-commands.rst b/tools/esptool_py/docs/en/esptool/advanced-commands.rst index 905739ba27..5a035a4091 100644 --- a/tools/esptool_py/docs/en/esptool/advanced-commands.rst +++ b/tools/esptool_py/docs/en/esptool/advanced-commands.rst @@ -1,90 +1,91 @@ -{IDF_TARGET_BOOTLOADER_OFFSET:default="0x0", esp32="0x1000", esp32s2="0x1000", esp32p4="0x2000"} +{IDF_TARGET_BOOTLOADER_OFFSET:default="0x0", esp32="0x1000", esp32s2="0x1000", esp32p4="0x2000", esp32c5="0x2000"} .. _advanced-commands: Advanced Commands ================= -The ``write_flash``, ``read_flash``, ``erase_flash``, ``erase_region``, ``read_mac``, ``flash_id``, ``elf2image``, ``image_info`` and ``merge_bin`` commands are all documented in the :ref:`commands` section. +The ``write-flash``, ``read-flash``, ``erase-flash``, ``erase-region``, ``read-mac``, ``flash-id``, ``elf2image``, ``image-info`` and ``merge-bin`` commands are all documented in the :ref:`commands` section. The following less common commands are for more advanced users. .. _verify-flash: -Verify Flash Data: verify_flash -------------------------------- +Verify Flash Data: ``verify-flash`` +----------------------------------- -The ``verify_flash`` command allows you to verify that data in flash matches a local file. +The ``verify-flash`` command allows you to verify that data in flash matches a local file. -The ``write_flash`` command always verifies the MD5 hash of data which is written to flash, so additional verification is not usually needed. However, if you wish to perform a byte-by-byte verification of the flash contents (and optionally print the differences to the console) then you can do so with this command: +The ``write-flash`` command always verifies the MD5 hash of data which is written to flash, so additional verification is not usually needed. However, if you wish to perform a byte-by-byte verification of the flash contents (and optionally print the differences to the console) then you can do so with this command: :: - esptool.py verify_flash --diff yes 0x40000 my_app.elf-0x40000.bin + esptool verify-flash --diff 0x40000 my_app.elf-0x40000.bin -The ``--diff yes`` option specifies that if the files are different, the details should be printed to the console. +The ``--diff`` option specifies that if the files are different, the details should be printed to the console. .. note:: .. list:: - * If verifying a default boot image (offset {IDF_TARGET_BOOTLOADER_OFFSET} for {IDF_TARGET_NAME}) then any ``--flash_mode``, ``--flash_size`` and ``--flash_freq`` arguments which were passed to `write_flash` must also be passed to ``verify_flash``. Otherwise, ``verify_flash`` will detect mismatches in the header of the image file. - * Another way to compare flash contents is to use the ``read_flash`` command, and then use binary diffing tools on the host. + * If verifying a default boot image (offset {IDF_TARGET_BOOTLOADER_OFFSET} for {IDF_TARGET_NAME}) then any ``--flash-mode``, ``--flash-size`` and ``--flash-freq`` arguments which were passed to `write-flash` must also be passed to ``verify-flash``. Otherwise, ``verify-flash`` will detect mismatches in the header of the image file. + * Another way to compare flash contents is to use the ``read-flash`` command, and then use binary diffing tools on the host. .. _dump-mem: -Dump a Memory Region to File: dump_mem --------------------------------------- +Dump a Memory Region to File: ``dump-mem`` +------------------------------------------ -The ``dump_mem`` command will dump a region from the chip's memory space to a file. For example, to dump the ROM (64 kB) from an ESP8266: +The ``dump-mem`` command will dump a region from the chip's memory space to a file. For example, to dump the ROM (64 kB) from an ESP8266: :: - esptool.py dump_mem 0x40000000 65536 iram0.bin + esptool dump-mem 0x40000000 64k iram0.bin + .. _load-ram: -Load a Binary to RAM: load_ram ------------------------------- +Load a Binary to RAM: ``load-ram`` +---------------------------------- -The ``load_ram`` command allows the loading of an executable binary image (created with the ``elf2image`` or ``make_image`` commands) directly into RAM, and then immediately executes the program contained within it. Command also supports ``.hex`` file created by ``merge_bin`` command from supported ``.bin`` files. +The ``load-ram`` command allows the loading of an executable binary image (created with the ``elf2image`` or ``make-image`` commands) directly into RAM, and then immediately executes the program contained within it. Command also supports ``.hex`` file created by ``merge-bin`` command from supported ``.bin`` files. :: - esptool.py --no-stub load_ram ./test/images/helloworld-esp8266.bin + esptool --no-stub load-ram ./test/images/helloworld-esp8266.bin .. note:: - * The binary image must only contain IRAM- and DRAM-resident segments. Any SPI flash mapped segments will not load correctly and the image will probably crash. The ``image_info`` command can be used to check the binary image contents. - * Because the software loader is resident in IRAM and DRAM, this limits the region where a new program may be loaded. An error will be printed if the new program overlaps with the software loader in RAM. Older esptool versions may hang. Pass ``esptool.py --no-stub`` to avoid this problem. + * The binary image must only contain IRAM- and DRAM-resident segments. Any SPI flash mapped segments will not load correctly and the image will probably crash. The ``image-info`` command can be used to check the binary image contents. + * Because the software loader is resident in IRAM and DRAM, this limits the region where a new program may be loaded. An error will be printed if the new program overlaps with the software loader in RAM. Older esptool versions may hang. Pass ``esptool --no-stub`` to avoid this problem. * Due to a limitation in the ROM loader, when using ``--no-stub`` any very early serial output from a program may be lost if the program resets or reconfigures the UART. To avoid this problem, a program can be compiled with ``ets_delay_us(1)`` as the very first statement after the entry point. .. _read-mem-write-mem: -Read or Write RAM: read_mem / write_mem ---------------------------------------- +Read or Write RAM: ``read-mem`` & ``write-mem`` +----------------------------------------------- -The ``read_mem`` & ``write_mem`` commands allow reading and writing single words (4 bytes) of RAM. This can be used to "peek" and "poke" at registers. +The ``read-mem`` & ``write-mem`` commands allow reading and writing single words (4 bytes) of RAM. This can be used to "peek" and "poke" at registers. :: - esptool.py write_mem 0x400C0000 0xabad1dea + esptool write-mem 0x400C0000 0xabad1dea :: - esptool.py read_mem 0x400C0000 + esptool read-mem 0x400C0000 .. _read-flash-status: -Read Flash Chip Registers: read_flash_status --------------------------------------------- +Read Flash Chip Registers: ``read-flash-status`` +------------------------------------------------ This command is intended for use when debugging hardware flash chip-related problems. It allows sending a ``RDSR``, ``RDSR2`` and/or ``RDSR3`` commands to the flash chip to read the status register contents. This can be used to check write protection status, for example: :: - esptool.py read_flash_status --bytes 2 + esptool read-flash-status --bytes 2 The ``--bytes`` argument determines how many status register bytes are read. @@ -98,16 +99,16 @@ The ``--bytes`` argument determines how many status register bytes are read. .. _write-flash-status: -Write Flash Chip Registers: write_flash_status ------------------------------------------------ +Write Flash Chip Registers: ``write-flash-status`` +-------------------------------------------------- This command is intended for use when debugging hardware flash chip-related problems. It allows sending ``WRSR``, ``WRSR2`` and/or ``WRSR3`` commands to the flash chip to write the status register contents. This can be used to clear write protection bits, for example: :: - esptool.py write_flash_status --bytes 2 --non-volatile 0 + esptool write-flash-status --bytes 2 --non-volatile 0 -The ``--bytes`` option is similar to the corresponding option for ``read_flash_status`` and causes a mix of ``WRSR`` (01h), ``WRSR2`` (31h), and ``WRSR3`` (11h) commands to be sent to the chip. If ``--bytes 2`` is used then ``WRSR`` is sent first with a 16-bit argument and then with an 8-bit argument, as different flash chips use this command differently. +The ``--bytes`` option is similar to the corresponding option for ``read-flash-status`` and causes a mix of ``WRSR`` (01h), ``WRSR2`` (31h), and ``WRSR3`` (11h) commands to be sent to the chip. If ``--bytes 2`` is used then ``WRSR`` is sent first with a 16-bit argument and then with an 8-bit argument, as different flash chips use this command differently. Otherwise, each command is accompanied by 8-bits of the new status register value. A second option ``--non-volatile`` can be used in order to send a ``WREN`` (06h) command before writing the status. This may allow non-volatile status register bits to be set or cleared. If the ``--non-volatile`` option is not supplied, a ``WEVSR`` (50h) command is sent instead of ``WREN``. @@ -122,51 +123,47 @@ A second option ``--non-volatile`` can be used in order to send a ``WREN`` (06h) .. _read-flash-sfdp: -Read Serial Flash Discoverable Parameters (SFDP) ------------------------------------------------- +Read Serial Flash Discoverable Parameters (SFDP): ``read-flash-sfdp`` +--------------------------------------------------------------------- The Serial Flash Discoverable Parameters (SFDP) store essential vendor-specific configuration data of the flash memory chip. These parameters help identify and interact with different flash devices. Usage: :: - esptool.py read_flash_sfdp 16 4 - -This will read 4 bytes from SFDP address 16. -.. only:: esp8266 + esptool read-flash-sfdp 16 4 - .. _chip-id: +This will read 4 bytes from SFDP address 16. - Read the Chip ID: chip_id - ------------------------- +.. only:: not esp8266 and not esp32 - The ``chip_id`` command allows you to read a 4 byte ID which forms part of the MAC address. It is usually better to use ``read_mac`` to identify a chip. + Read Security Info: ``get_security_info`` + ------------------------------------------ - On {IDF_TARGET_NAME}, output is the same as the ``system_get_chip_id()`` SDK function. The chip ID is four bytes long, the lower three bytes are the final bytes of the MAC address. The upper byte is zero. + The ``get_security_info`` command allows you to read security-related information (secure boot, secure download, etc.) about the Espressif devices. :: - esptool.py chip_id + esptool get_security_info - .. _make-image: - Assemble a Firmware Image: make_image - ------------------------------------- +.. only:: esp8266 - ``make_image`` allows you to manually assemble a firmware image from binary segments (such as those extracted from objcopy). For example: + .. _chip-id: - :: + Read the Chip ID: ``chip-id`` + ----------------------------- - esptool.py --chip esp8266 make_image -f app.text.bin -a 0x40100000 -f app.data.bin -a 0x3ffe8000 -f app.rodata.bin -a 0x3ffe8c00 app.flash.bin + The ``chip-id`` command allows you to read a 4 byte ID which forms part of the MAC address. It is usually better to use ``read-mac`` to identify a chip. - This command does not require a serial connection. + On {IDF_TARGET_NAME}, output is the same as the ``system_get_chip_id()`` SDK function. The chip ID is four bytes long, the lower three bytes are the final bytes of the MAC address. The upper byte is zero. - .. note:: + :: - In general, it is better to create an ELF image (including any binary data as part of the ELF, by using objcopy or other tools) and then use ``elf2image`` to generate the ``.bin`` file. + esptool chip-id .. _run: - Boot Application Code: run - -------------------------- + Boot Application Code: ``run`` + ------------------------------ The ``run`` command immediately exits the bootloader and attempts to boot the normal application code. diff --git a/tools/esptool_py/docs/en/esptool/advanced-options.rst b/tools/esptool_py/docs/en/esptool/advanced-options.rst index db47b8aa04..c0d1a81fc0 100644 --- a/tools/esptool_py/docs/en/esptool/advanced-options.rst +++ b/tools/esptool_py/docs/en/esptool/advanced-options.rst @@ -3,38 +3,39 @@ Advanced Options ================ -The following advanced configuration options can be used for all esptool commands (they are placed before the command name on the command line). +The following advanced global configuration options can be used for all esptool commands. They are placed before the command name on the command line. For example, the option ``--before no-reset`` has to be placed before ``flash-id``. The command should look like this: ``esptool --before no-reset flash-id``. -For basic/fundamental configuration options, see the :ref:`options` page. +For basic/fundamental global configuration options, see the :ref:`options` page. Reset Modes ----------- By default, esptool tries to hard reset the chip into bootloader mode before it starts and hard resets the chip to run the normal program once it is complete. The ``--before`` and ``--after`` options allow this behavior to be changed: -Reset Before Operation -^^^^^^^^^^^^^^^^^^^^^^ +Reset Before Operation: ``--before`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ The ``--before`` argument allows you to specify whether the chip needs resetting into bootloader mode before esptool talks to it. .. list:: - * ``--before default_reset`` is the default, which uses DTR & RTS serial control lines (see :ref:`entering-the-bootloader`) to try to reset the chip into bootloader mode. - * ``--before no_reset`` will skip DTR/RTS control signal assignments and just start sending a serial synchronisation command to the chip. This is useful if your chip doesn't have DTR/RTS, or for some serial interfaces (like Arduino board onboard serial) which behave differently when DTR/RTS are toggled. - * ``--before no_reset_no_sync`` will skip DTR/RTS control signal assignments and skip also the serial synchronization command. This is useful if your chip is already running the :ref:`stub bootloader ` and you want to avoid resetting the chip and uploading the stub again. - :esp32c3 or esp32s3 or esp32c6 or esp32h2 or esp32p4: * ``--before usb_reset`` will use custom reset sequence for USB-JTAG-Serial (used for example for ESP chips connected through the USB-JTAG-Serial peripheral). Usually, this option doesn't have to be used directly. Esptool should be able to detect connection through USB-JTAG-Serial. + * ``--before default-reset`` is the default, which uses DTR & RTS serial control lines (see :ref:`entering-the-bootloader`) to try to reset the chip into bootloader mode. + * ``--before no-reset`` will skip DTR/RTS control signal assignments and just start sending a serial synchronisation command to the chip. This is useful if your chip doesn't have DTR/RTS, or for some serial interfaces (like Arduino board onboard serial) which behave differently when DTR/RTS are toggled. + * ``--before no-reset-no-sync`` will skip DTR/RTS control signal assignments and skip also the serial synchronization command. This is useful if your chip is already running the :ref:`stub bootloader ` and you want to avoid resetting the chip and uploading the stub again. + :esp32c3 or esp32s3 or esp32c6 or esp32h2 or esp32p4 or esp32c5 or esp32c61: * ``--before usb-reset`` will use custom reset sequence for USB-JTAG-Serial (used for example for ESP chips connected through the USB-JTAG-Serial peripheral). Usually, this option doesn't have to be used directly. Esptool should be able to detect connection through USB-JTAG-Serial. -Reset After Operation -^^^^^^^^^^^^^^^^^^^^^ +Reset After Operation: ``--after`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ The ``--after`` argument allows you to specify whether the chip should be reset after the esptool operation completes: .. list:: - * ``--after hard_reset`` is the default. The DTR serial control line is used to reset the chip into a normal boot sequence. - :esp8266:* ``--after soft_reset`` This runs the user firmware, but any subsequent reset will return to the serial bootloader. This was the reset behaviour in esptool v1.x. - * ``--after no_reset`` leaves the chip in the serial bootloader, no reset is performed. - * ``--after no_reset_stub`` leaves the chip in the stub bootloader, no reset is performed. + * ``--after hard-reset`` is the default. The RTS serial control line is used to reset the chip into a normal boot sequence. + :esp8266: * ``--after soft-reset`` runs the user firmware, but any subsequent reset will return to the serial bootloader. This was the reset behaviour in esptool v1.x. + * ``--after no-reset`` leaves the chip in the serial bootloader, no reset is performed. + * ``--after no-reset-stub`` leaves the chip in the stub bootloader, no reset is performed. + :not esp8266 and not esp32 and not esp32h2 and not esp32c6: * ``--after watchdog-reset`` hard-resets the chip by triggering an internal watchdog reset. This is useful when the RTS control line is not available, especially in the USB-OTG and USB-Serial/JTAG modes. Use this if a chip is getting stuck in download mode when using the default reset method in USB-Serial/JTAG mode. Using this may cause the port to re-enumerate on Linux (e.g. ``/dev/ttyACM0`` -> ``/dev/ttyACM1``). Connect Loop @@ -59,8 +60,8 @@ There are 3 possible values for this option: .. _disable_stub: -Disabling the Stub Loader -------------------------- +Disabling the Stub Loader: ``--no-stub`` +---------------------------------------- The ``--no-stub`` option disables uploading of a software "stub loader" that manages flash operations, and only talks directly to the loader in ROM. @@ -68,19 +69,23 @@ Passing ``--no-stub`` will disable certain options, as not all options are imple .. only:: not esp8266 - Overriding SPI Flash Connections - -------------------------------- + Overriding SPI Flash Connections: ``--spi-connection`` + ------------------------------------------------------ - The optional ``--spi-connection`` argument overrides the SPI flash connection configuration on ESP32. This means that the SPI flash can be connected to other pins, or esptool can be used to communicate with a different SPI flash chip to the default. + The optional ``--spi-connection`` argument overrides the SPI flash connection configuration on {IDF_TARGET_NAME}. This means that the SPI flash can be connected to other pins, or esptool can be used to communicate with a different SPI flash chip to the default. - Supply the ``--spi-connection`` argument after the ``esptool.py`` command, ie ``esptool.py flash_id --spi-connection HSPI``. + Supply the ``--spi-connection`` argument after the ``esptool`` command, ie ``esptool flash-id --spi-connection HSPI``. + + .. note:: + + Only NOR flash chips that are capable of at least Dual I/O (DIO) mode for SPI communication are supported. SPI NAND flash chips, as well as other types of memory devices that do not meet this requirement, are not supported. Default Behavior ^^^^^^^^^^^^^^^^ - If the ``--spi-connection`` argument is not provided, the SPI flash is configured to use :ref:`pin numbers set in efuse `. These are the same SPI flash pins that are used during a normal boot. + If the ``--spi-connection`` argument is not provided, the SPI flash is configured to use :ref:`pin numbers set in eFuse `. These are the same SPI flash pins that are used during a normal boot. - The only exception to this is if the ``--no-stub`` option is also provided. In this case, efuse values are ignored and ``--spi-connection`` will default to ``--spi-connection SPI`` unless set to a different value. + The only exception to this is if the ``--no-stub`` option is also provided. In this case, eFuse values are ignored and ``--spi-connection`` will default to ``--spi-connection SPI`` unless set to a different value. .. only:: esp32 @@ -95,7 +100,7 @@ Passing ``--no-stub`` will disable certain options, as not all options are imple * HD = GPIO 9 * CS = GPIO 11 - During normal booting, this configuration is selected if all SPI pin efuses are unset and GPIO1 (U0TXD) is not pulled low (default). + During normal booting, this configuration is selected if all SPI pin eFuses are unset and GPIO1 (U0TXD) is not pulled low (default). This is the normal pin configuration for ESP32 chips that do not contain embedded flash. @@ -110,16 +115,16 @@ Passing ``--no-stub`` will disable certain options, as not all options are imple * HD = GPIO 4 * CS = GPIO 15 - During normal booting, this configuration is selected if all SPI pin efuses are unset and GPIO1 (U0TXD) is pulled low on reset. + During normal booting, this configuration is selected if all SPI pin eFuses are unset and GPIO1 (U0TXD) is pulled low on reset. Custom SPI Pin Configuration ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - ``--spi-connection ,,,,`` allows a custom list of pins to be configured for the SPI flash connection. This can be used to emulate the flash configuration equivalent to a particular set of SPI pin efuses being burned. The values supplied are GPIO numbers. + ``--spi-connection ,,,,`` allows a custom list of pins to be configured for the SPI flash connection. This can be used to emulate the flash configuration equivalent to a particular set of SPI pin eFuses being burned. The values supplied are GPIO numbers. .. only:: esp32 - For example, ``--spi-connection 6,17,8,11,16`` sets an identical configuration to the factory efuse configuration for ESP32s with embedded flash. + For example, ``--spi-connection 6,17,8,11,16`` sets an identical configuration to the factory eFuse configuration for ESP32s with embedded flash. When setting a custom pin configuration, the SPI peripheral (not HSPI) will be used unless the ``CLK`` pin value is set to 14 (HSPI CLK), in which case the HSPI peripheral will be used. @@ -133,17 +138,17 @@ Specifying Arguments via File Anywhere on the esptool command line, you can specify a file name as ``@filename.txt`` to read one or more arguments from text file ``filename.txt``. Arguments can be separated by newlines or spaces, quotes can be used to enclose arguments that span multiple words. Arguments read from the text file are expanded exactly as if they had appeared in that order on the esptool command line. -An example of this is available in the :ref:`merge_bin ` command description. +An example of this is available in the :ref:`merge-bin ` command description. -.. note:: PowerShell users +.. note:: - Because of `splatting `__ in PowerShell (method of passing a collection of parameter values to a command as a unit) there is a need to add quotes around @filename.txt ("@filename.txt") to be correctly resolved. + PowerShell users need to add quotes around @filename.txt ("@filename.txt") for it to be correctly resolved. This is because of `splatting `__, a method of passing a collection of parameter values to a command as a unit. -Filtering serial ports ----------------------- +Filtering Serial Ports: ``--port-filter`` +----------------------------------------- .. _filtering_serial_ports: -``--port-filter =`` allows limiting ports that will be tried. This can be useful when esptool is run on a system +``--port-filter =`` allows limiting ports that will be considered during chip autodetection. This can be useful when esptool is run on a system with many serial ports. There are a few different types that can be combined. A port must match all specified FilterTypes, and must match at least one FilterValue for each specified FilterType to be considered. Example filter configurations: @@ -154,5 +159,33 @@ at least one FilterValue for each specified FilterType to be considered. Example * ``--port-filter vid=0x303A --port-filter pid=0x0002`` matches Espressif ESP32-S2 in USB-OTG mode by VID and PID. * ``--port-filter vid=0x303A --port-filter pid=0x1001`` matches Espressif USB-Serial/JTAG unit used by multiple chips by VID and PID. * ``--port-filter name=ttyUSB`` matches ports where the port name contains the specified text. + * ``--port-filter serial=7c98d1065267ee11bcc4c8ab93cd958c`` matches ports where the serial number contains the specified text. See also the `Espressif USB customer-allocated PID repository `_ + +Output Verbosity +---------------- + +Output verbosity can be controlled using the ``--verbose`` and ``--silent`` flags. + +Verbose output: ``--verbose``, ``-v`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +.. _verbose: + +The ``--verbose``, ``-v`` flag can be used to show all output without any overwriting or collapsing stages into a single line: + +.. code-block:: bash + + esptool --verbose flash-id + +See :ref:`the trace option ` if you want to dump all serial interactions to the standard output for debugging purposes. + +Silent output: ``--silent``, ``-s`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +.. _silent: + +The ``--silent``, ``-s`` flag can be used to limit the output to errors only: + +.. code-block:: bash + + esptool -s write-flash 0x0 image.bin diff --git a/tools/esptool_py/docs/en/esptool/basic-commands.rst b/tools/esptool_py/docs/en/esptool/basic-commands.rst index 8e16df7b42..b13c718249 100644 --- a/tools/esptool_py/docs/en/esptool/basic-commands.rst +++ b/tools/esptool_py/docs/en/esptool/basic-commands.rst @@ -3,20 +3,22 @@ Basic Commands ============== -Write Binary Data to Flash: write_flash ----------------------------------------- +.. _write-flash: -Binary data can be written to the ESP's flash chip via the serial ``write_flash`` command: +Write Binary Data to Flash: ``write-flash`` +------------------------------------------- + +Binary data can be written to the ESP's flash chip via the serial ``write-flash`` command: :: - esptool.py --port COM4 write_flash 0x1000 my_app-0x01000.bin + esptool --port COM4 write-flash 0x1000 my_app-0x01000.bin Multiple flash addresses and file names can be given on the same command line: :: - esptool.py --port COM4 write_flash 0x00000 my_app.elf-0x00000.bin 0x40000 my_app.elf-0x40000.bin + esptool --port COM4 write-flash 0x00000 my_app.elf-0x00000.bin 0x40000 my_app.elf-0x40000.bin The ``--chip`` argument is optional when writing to flash, esptool will detect the type of chip when it connects to the serial port. @@ -24,16 +26,16 @@ The ``--port`` argument is documented under :ref:`serial-port`. .. only:: esp8266 - The next arguments to ``write_flash`` are one or more pairs of offset (address) and file name. When generating ESP8266 "version 1" images, the file names created by ``elf2image`` include the flash offsets as part of the file name. + The next arguments to ``write-flash`` are one or more pairs of offset (address) and file name. When generating ESP8266 "version 1" images, the file names created by ``elf2image`` include the flash offsets as part of the file name. For other types of images, consult your SDK documentation to determine the files to flash at which offsets. .. only:: not esp8266 - The next arguments to ``write_flash`` are one or more pairs of offset (address) and file name. Consult your SDK documentation to determine the files to flash at which offsets. + The next arguments to ``write-flash`` are one or more pairs of offset (address) and file name. Consult your SDK documentation to determine the files to flash at which offsets. -Numeric values passed to write_flash (and other commands) can be specified either in hex (ie 0x1000), or in decimal (ie 4096). +Numeric values passed to write-flash (and other commands) can be specified either in hex (ie 0x1000), or in decimal (ie 4096). -See the :ref:`troubleshooting` section if the ``write_flash`` command is failing, or the flashed module fails to boot. +See the :ref:`troubleshooting` section if the ``write-flash`` command is failing, or the flashed module fails to boot. Setting Flash Mode and Size ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -42,7 +44,7 @@ You may also need to specify arguments for :ref:`flash mode and flash size `_ is enabled and Encrypted Download being disabled (efuse bit ``EFUSE_DISABLE_DL_ENCRYPT`` is set). + Overwriting the encrypted firmware (bootloader, application, etc.) without the ``--encrypt`` option is disabled, if `Flash Encryption `_ is enabled and Encrypted Download being disabled (eFuse bit ``EFUSE_DISABLE_DL_ENCRYPT`` is set). .. only:: not esp32 Overwriting the encrypted firmware (bootloader, application, etc.) without the ``--encrypt`` option is disabled, if: * `Flash Encryption `_ and Secure Download Mode are enabled or - * `Flash Encryption `_ is enabled but Encrypted Download is disabled (efuse bit ``EFUSE_DIS_DOWNLOAD_MANUAL_ENCRYPT`` is set). + * `Flash Encryption `_ is enabled but Encrypted Download is disabled (eFuse bit ``EFUSE_DIS_DOWNLOAD_MANUAL_ENCRYPT`` is set). This is a safety measure to prevent accidentally overwriting the encrypted firmware with a plaintext binary, which **can ultimately lead to bricking the device**. @@ -91,53 +93,55 @@ Use the ``-e/--erase-all`` option to erase all flash sectors (not just the write Flashing an Incompatible Image ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - ``esptool.py`` checks every binary before flashing. If a valid firmware image is detected, the ``Chip ID`` and ``Minimum chip revision`` fields in its :ref:`header ` are compared against the actually connected chip. + ``esptool`` checks every binary before flashing. If a valid firmware image is detected, the ``Chip ID`` and ``Minimum chip revision`` fields in its :ref:`header ` are compared against the actually connected chip. If the image turns out to be incompatible with the chip in use or requires a newer chip revision, flashing is stopped. This behavior can be overridden with the ``--force`` option. -Read Flash Contents: read_flash --------------------------------- +Read Flash Contents: ``read-flash`` +----------------------------------- -The read_flash command allows reading back the contents of flash. The arguments to the command are an address, a size, and a filename to dump the output to. For example, to read a full 2MB of attached flash: +The read-flash command allows reading back the contents of flash. The arguments to the command are an address, a size, and a file path to output to. For example, to read a full 2MB of attached flash: :: - esptool.py -p PORT -b 460800 read_flash 0 0x200000 flash_contents.bin + esptool -p PORT -b 460800 read-flash 0 0x200000 flash_contents.bin + +Size can be specified in bytes, or with suffixes like ``k`` and ``M``. So ``0x200000`` in example can be replaced with ``2M``. It is also possible to autodetect flash size by using ``ALL`` as size. The above example with autodetection would look like this: :: - esptool.py -p PORT -b 460800 read_flash 0 ALL flash_contents.bin + esptool -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. + 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:: - If ``write_flash`` updated the boot image's :ref:`flash mode and flash size ` 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 ` during flashing then these bytes may be different when read back. -.. _erase_flash: +.. _erase-flash: -Erase Flash: erase_flash & erase_region ---------------------------------------- +Erase Flash: ``erase-flash`` & ``erase-region`` +----------------------------------------------- To erase the entire flash chip (all data replaced with 0xFF bytes): :: - esptool.py erase_flash + esptool erase-flash -To erase a region of the flash, starting at address 0x20000 with length 0x4000 bytes (16KB): +To erase a region of the flash, starting at address 0x20000 with length 16 kB (0x4000 bytes): :: - esptool.py erase_region 0x20000 0x4000 + esptool erase-region 0x20000 16k The address and length must both be multiples of the SPI flash erase sector size. This is 0x1000 (4096) bytes for supported flash chips. @@ -152,21 +156,21 @@ The address and length must both be multiples of the SPI flash erase sector size This behavior can be overridden with the ``--force`` option. **Use this only at your own risk and only if you know what you are doing!** -Read Built-in MAC Address: read_mac ------------------------------------- +Read Built-in MAC Address: ``read-mac`` +--------------------------------------- :: - esptool.py read_mac + esptool read-mac .. _read-spi-flash-id: -Read SPI Flash ID: flash_id ---------------------------- +Read SPI Flash ID: ``flash-id`` +------------------------------- :: - esptool.py flash_id + esptool flash-id Example output: @@ -180,21 +184,21 @@ Refer to `flashrom source code `__ arguments ``--flash_freq`` and ``--flash_mode``, which can be used to set the default values in the image header. This is important when generating any image which will be booted directly by the chip. -These values can also be overwritten via the ``write_flash`` command, see the `write_flash command <#write-binary-data-to-flash-write-flash>`__ for details. Overwriting these values via the ``write_flash`` command will produce an image with a recalculated SHA256 digest, otherwise, the image SHA256 digest would be invalidated by rewriting the image header. There is an option to skip appending a SHA256 digest after the image with ``--dont-append-digest`` argument of the ``elf2image`` command. +``elf2image`` also accepts the `Flash Modes <#flash-modes>`__ arguments ``--flash-freq`` and ``--flash-mode``, which can be used to set the default values in the image header. This is important when generating any image which will be booted directly by the chip. +These values can also be overwritten via the ``write-flash`` command, see the `write-flash command <#write-binary-data-to-flash-write-flash>`__ for details. Overwriting these values via the ``write-flash`` command will produce an image with a recalculated SHA256 digest, otherwise, the image SHA256 digest would be invalidated by rewriting the image header. There is an option to skip appending a SHA256 digest after the image with ``--dont-append-digest`` argument of the ``elf2image`` command. -By default, ``elf2image`` uses the sections in the ELF file to generate each segment in the binary executable. To use segments (PHDRs) instead, pass the ``--use_segments`` option. +By default, ``elf2image`` uses the sections in the ELF file to generate each segment in the binary executable. To use segments (PHDRs) instead, pass the ``--use-segments`` option. .. only:: esp8266 @@ -204,61 +208,60 @@ By default, ``elf2image`` uses the sections in the ELF file to generate each seg :: - esptool.py --chip {IDF_TARGET_NAME} elf2image --version=2 -o my_app-ota.bin my_app.elf + esptool --chip {IDF_TARGET_NAME} elf2image --version=2 -o my_app-ota.bin my_app.elf .. only:: not esp8266 - For {IDF_TARGET_NAME}, elf2image produces a single output binary "image file". By default this has the same name as the .elf file, with a .bin extension. For example: + For {IDF_TARGET_NAME}, elf2image produces a single output binary "image file". By default, this has the same name as the .elf file, with a .bin extension. For example: :: - esptool.py --chip {IDF_TARGET_NAME} elf2image my_esp_app.elf + esptool --chip {IDF_TARGET_NAME} elf2image my_esp_app.elf In the above example, the output image file would be called ``my_esp_app.bin``. The ``--ram-only-header`` configuration is mainly applicable for use within the Espressif's SIMPLE_BOOT option from 3rd party OSes such as ZephyrOS and NuttX OS. + For a detailed explanation of Simple Boot and how it works, see `Simple Boot explained `_. This option makes only the RAM segments visible to the ROM bootloader placing them at the beginning of the file and altering the segment count from the image header with the quantity of these segments, and also writing only their checksum. This segment placement may result in a more fragmented binary because of flash alignment constraints. It is strongly recommended to use this configuration with care, because the image built must then handle the basic hardware initialization and the flash mapping for code execution after ROM bootloader boot it. .. _image-info: -Output .bin Image Details: image_info -------------------------------------- +Output .bin Image Details: ``image-info`` +----------------------------------------- -The ``image_info`` command outputs some information (load addresses, sizes, etc) about a ``.bin`` file created by ``elf2image``. Command also supports ``.hex`` file created by ``merge_bin`` command from supported ``.bin`` files. - -To view more information about the image, such as set flash size, frequency and mode, or extended header information, use the ``--version 2`` option. This extended output will become the default in a future major release. +The ``image-info`` command outputs some information (load addresses, segment sizes, set flash size, frequency, and mode, extended header information, etc) about a ``.bin`` file created by ``elf2image``. Command also supports ``.hex`` file created by ``merge-bin`` command from supported ``.bin`` files. This information corresponds to the headers described in :ref:`image-format`. :: - esptool.py image_info --version 2 my_esp_app.bin + esptool image-info my_esp_app.bin .. only:: not esp8266 - If the given binary file is an application and a valid `ESP-IDF application header `__ is detected in the image, specific fields describing the application are also displayed. - - If the given binary file is a bootloader and a valid `ESP-IDF bootloader header `__ is detected in the image, specific fields describing the bootloader are also displayed. + If the given binary file is an application with a valid `ESP-IDF application header `__ + or a bootloader with a valid `ESP-IDF bootloader header `__ + detected in the image, specific fields describing the application or bootloader are also displayed. .. _merge-bin: -Merge Binaries for Flashing: merge_bin --------------------------------------- -The ``merge_bin`` command will merge multiple binary files (of any kind) into a single file that can be flashed to a device later. Any gaps between the input files are padded based on the selected output format. +Merge Binaries for Flashing: ``merge-bin`` +------------------------------------------ +The ``merge-bin`` command will merge multiple binary files (of any kind) into a single file that can be flashed to a device later. Any gaps between the input files are padded based on the selected output format. For example: :: - esptool.py --chip {IDF_TARGET_NAME} merge_bin -o merged-flash.bin --flash_mode dio --flash_size 4MB 0x1000 bootloader.bin 0x8000 partition-table.bin 0x10000 app.bin + esptool --chip {IDF_TARGET_NAME} merge-bin -o merged-flash.bin --flash-mode dio --flash-size 4MB 0x1000 bootloader.bin 0x8000 partition-table.bin 0x10000 app.bin -Will create a file ``merged-flash.bin`` with the contents of the other 3 files. This file can be later written to flash with ``esptool.py write_flash 0x0 merged-flash.bin``. +Will create a file ``merged-flash.bin`` with the contents of the other 3 files. This file can be later written to flash with ``esptool write-flash 0x0 merged-flash.bin``. **Common options:** -* The ``merge_bin`` command supports the same ``--flash_mode``, ``--flash_size`` and ``--flash_freq`` options as the ``write_flash`` command to override the bootloader flash header (see above for details). +* The ``merge-bin`` command supports the same ``--flash-mode``, ``--flash-size`` and ``--flash-freq`` options as the ``write-flash`` command to override the bootloader flash header (see above for details). These options are applied to the output file contents in the same way as when writing to flash. Make sure to pass the ``--chip`` parameter if using these options, as the supported values and the bootloader offset both depend on the chip. * The ``--format`` option will change the format of the output file. For more information about formats see formats description below. * The input files can be in either ``bin`` or ``hex`` format and they will be automatically converted to type selected by ``--format`` argument. @@ -267,7 +270,7 @@ Will create a file ``merged-flash.bin`` with the contents of the other 3 files. .. code:: sh cd build # The build directory of an ESP-IDF project - esptool.py --chip {IDF_TARGET_NAME} merge_bin -o merged-flash.bin @flash_args + esptool --chip {IDF_TARGET_NAME} merge-bin -o merged-flash.bin @flash_args HEX Output Format @@ -281,9 +284,16 @@ Intel Hex format offers distinct advantages when compared to the binary format, * **Size**: Data is carefully allocated to specific memory addresses eliminating the need for unnecessary padding. Binary images often lack detailed addressing information, leading to the inclusion of data for all memory locations from the file's initial address to its end. * **Validity Checks**: Each line in an Intel Hex file has a checksum to help find errors and make sure data stays unchanged. +When using a merged Intel Hex file with the ``write-flash`` or ``image-info`` commands, the file is automatically split into temporary raw binary files at the gaps between input files. +This splitting process allows each section to be analyzed independently, producing output similar to running ``image-info`` on the original files before merging (with the only difference being the splitting based on gaps). + +In contrast, analyzing a merged raw binary file only processes the header of the first file, providing less detailed information. + +The splitting behavior of Intel Hex files offers an additional advantage during flashing: since no padding is used between sections, flash sectors between input files remain unerased. This can significantly improve flashing speed compared to using a merged raw binary file. + .. code:: sh - esptool.py --chip {IDF_TARGET_NAME} merge_bin --format hex -o merged-flash.hex --flash_mode dio --flash_size 4MB 0x1000 bootloader.bin 0x8000 partition-table.bin 0x10000 app.bin + esptool --chip {IDF_TARGET_NAME} merge-bin --format hex -o merged-flash.hex --flash-mode dio --flash-size 4MB 0x1000 bootloader.bin 0x8000 partition-table.bin 0x10000 app.bin .. note:: @@ -303,7 +313,7 @@ The output of the command will be in ``raw`` format and gaps between individual **RAW options:** -* The ``--fill-flash-size SIZE`` option will pad the merged binary with `0xFF` bytes to the full flash specified size, for example ``--fill-flash-size 4MB`` will create a 4MB binary file. +* The ``--pad-to-size SIZE`` option will pad the merged binary with `0xFF` bytes to the full flash specified size, for example ``--pad-to-size 4MB`` will create a 4MB binary file. * The ``--target-offset 0xNNN`` option will create a merged binary that should be flashed at the specified offset, instead of at offset 0x0. @@ -322,7 +332,7 @@ Gaps between the files will be filled with `0x00` bytes. .. code:: sh - esptool.py --chip {IDF_TARGET_NAME} merge_bin --format uf2 -o merged-flash.uf2 --flash_mode dio --flash_size 4MB 0x1000 bootloader.bin 0x8000 partition-table.bin 0x10000 app.bin + esptool --chip {IDF_TARGET_NAME} merge-bin --format uf2 -o merged-flash.uf2 --flash-mode dio --flash-size 4MB 0x1000 bootloader.bin 0x8000 partition-table.bin 0x10000 app.bin Advanced Commands @@ -340,5 +350,4 @@ The following commands are less commonly used, or only of interest to advanced u * :ref:`write-flash-status` * :ref:`read-flash-sfdp` :esp8266: * :ref:`chip-id` - :esp8266: * :ref:`make-image` :esp8266: * :ref:`run` diff --git a/tools/esptool_py/docs/en/esptool/basic-options.rst b/tools/esptool_py/docs/en/esptool/basic-options.rst index 5d9bb4c468..d954e3c00b 100644 --- a/tools/esptool_py/docs/en/esptool/basic-options.rst +++ b/tools/esptool_py/docs/en/esptool/basic-options.rst @@ -5,24 +5,27 @@ Basic Options These are the basic/fundamental esptool options needed to define the communication with an ESP target. For advanced configuration options, see the :ref:`advanced-options` page. +Esptool has global and command-specific options. Global options have to be specified after ``esptool``. They are used to configure the serial port, baud rate, and chip type. +Command-specific options are specified after the command and are used to configure the command itself. For more information about commands and their options, see :ref:`commands` or see help in the command line. + .. _chip-type: -Chip Type ---------- +Chip Type: ``--chip``, ``-c`` +----------------------------- -* The target chip type can be selected using the ``--chip``/ ``-c`` option, e.g. ``esptool.py --chip {IDF_TARGET_PATH_NAME} ``. +* The target chip type can be selected using the ``--chip``/ ``-c`` option, e.g. ``esptool --chip {IDF_TARGET_PATH_NAME} ``. * A default chip type can be specified by setting the ``ESPTOOL_CHIP`` environment variable. -* If no ``-c`` option or ``ESPTOOL_CHIP`` value is specified, ``esptool.py`` automatically detects the chip type when connecting. -* Binary image generation commands, such as :ref:`elf2image ` or :ref:`merge_bin `, require the chip type to be specified. +* If no ``-c`` option or ``ESPTOOL_CHIP`` value is specified, ``esptool`` automatically detects the chip type when connecting. +* Binary image generation commands, such as :ref:`elf2image ` or :ref:`merge-bin `, require the chip type to be specified. .. _serial-port: -Serial Port ------------ +Serial Port: ``--port``, ``-p`` +------------------------------- * The serial port is selected using the ``-p`` option, like ``-p /dev/ttyUSB0`` (Linux and macOS) or ``-p COM1`` (Windows). * A default serial port can be specified by setting the ``ESPTOOL_PORT`` environment variable. -* If no ``-p`` option or ``ESPTOOL_PORT`` value is specified, ``esptool.py`` will enumerate all connected serial ports and try each one until it finds an Espressif device connected. +* If no ``-p`` option or ``ESPTOOL_PORT`` value is specified, ``esptool`` will enumerate all connected serial ports and try each one until it finds an Espressif device connected. .. note:: @@ -38,10 +41,10 @@ On most Linux distributions, the solution is to add the user to the ``dialout`` You can call ``su - $USER`` to enable read and write permissions for the serial port without having to log out and back in again. Check your Linux distribution's documentation for more information. -Baud Rate ---------- +Baud Rate: ``--baud``, ``-b`` +----------------------------- -The default esptool baud rate is 115200bps. Different rates may be set using ``-b 921600`` (or another baud rate of your choice). A default baud rate can also be specified using the ``ESPTOOL_BAUD`` environment variable. This can speed up ``write_flash`` and ``read_flash`` operations. +The default esptool baud rate is 115200bps. Different rates may be set using ``-b 921600`` (or another baud rate of your choice). A default baud rate can also be specified using the ``ESPTOOL_BAUD`` environment variable. This can speed up ``write-flash`` and ``read-flash`` operations. The baud rate is limited to 115200 when esptool establishes the initial connection, higher speeds are only used for data transfers. diff --git a/tools/esptool_py/docs/en/esptool/configuration-file.rst b/tools/esptool_py/docs/en/esptool/configuration-file.rst index 1583f86d17..8d8ccb2c9f 100644 --- a/tools/esptool_py/docs/en/esptool/configuration-file.rst +++ b/tools/esptool_py/docs/en/esptool/configuration-file.rst @@ -3,33 +3,33 @@ Configuration File ================== -``esptool.py`` relies on serial communication when connecting to, reading from, or writing to an ESP chip. -To ensure this two-way serial connection works properly, ``esptool.py`` is tuned with several pre-defined +``esptool`` relies on serial communication when connecting to, reading from, or writing to an ESP chip. +To ensure this two-way serial connection works properly, ``esptool`` is tuned with several pre-defined variables describing the timings and other nuances when sending or receiving data. These variables have been finely tuned to work in absolute majority of environments. However, it is impossible to cover all of the existing combinations of hardware, OS, and drivers. Sometimes little tweaking is necessary to cover even the most extreme edge cases. These options can be specified in a configuration file. This makes it easy to run -``esptool.py`` with custom settings, and also allows for specification of options +``esptool`` with custom settings, and also allows for specification of options that are otherwise not available to a user without having to tamper with the source code. File Location ------------- The default name for a configuration file is ``esptool.cfg``. First, the same -directory ``esptool.py`` is being run in is inspected. +directory ``esptool`` is being run in is inspected. If a configuration file is not found here, the current user's OS configuration directory is inspected next: - Linux: ``/home//.config/esptool/`` - - MacOS ``/Users//.config/esptool/`` + - macOS ``/Users//.config/esptool/`` - Windows: ``c:\Users\\AppData\Local\esptool\`` If a configuration file is still not found, the last inspected location is the home directory: - Linux: ``/home//`` - - MacOS ``/Users//`` + - macOS ``/Users//`` - Windows: ``c:\Users\\`` On Windows, the home directory can be set with the ``HOME`` or ``USERPROFILE`` environment variables. @@ -39,8 +39,8 @@ A different location for the configuration file can be specified with the ``ESPT environment variable, e.g. ``ESPTOOL_CFGFILE = ~/custom_config.cfg``. This overrides the search priorities described above. -``esptool.py`` will read settings from other usual configuration files if no other -configuration file is used. It will automatically read from ``setup.cfg`` or +``esptool`` will read settings from other usual configuration files if no other +configuration file is used. It will automatically read from ``setup.cfg`` or ``tox.ini`` if they exist. As a result, the order of priority of inspected configuration files is: @@ -53,7 +53,7 @@ As a result, the order of priority of inspected configuration files is: Syntax ------ -An ``esptool.py`` configuration file is in .ini file format: it must be +An ``esptool`` configuration file is in .ini file format: it must be introduced by an ``[esptool]`` header to be recognized as valid. This section then contains ``name = value`` entries. Lines beginning with ``#`` or ``;`` are ignored as comments. @@ -72,8 +72,8 @@ Sample configuration file: connect_attempts = 7 write_block_attempts = 2 reset_delay = 0.75 - # Overriding the default reset sequence to work in an abnormal environment - custom_reset_sequence = D0|R1|W0.1|D1|R0|W0.5|D0 + # Overriding the default reset sequence to work in an abnormal environment (prolonged delay): + custom_reset_sequence = D0|R1|W1.3|D1|R0|W0.5|D0 Options ------- @@ -87,7 +87,7 @@ Complete list of configurable options: +------------------------------+-----------------------------------------------------------+----------+ | chip_erase_timeout | Timeout for a full chip erase | 120 s | +------------------------------+-----------------------------------------------------------+----------+ -| max_timeout | The longest any command can run | 240 s | +| max_timeout | The longest any operation can run (e.g. writing a block) | 240 s | +------------------------------+-----------------------------------------------------------+----------+ | sync_timeout | Timeout for syncing with the bootloader | 0.1 s | +------------------------------+-----------------------------------------------------------+----------+ @@ -97,7 +97,7 @@ Complete list of configurable options: +------------------------------+-----------------------------------------------------------+----------+ | erase_write_timeout_per_mb | Timeout (per megabyte) for erasing and writing data | 40 s | +------------------------------+-----------------------------------------------------------+----------+ -| mem_end_rom_timeout | Short timeout for ESP_MEM_END | 0.2 s | +| mem_end_rom_timeout | Short timeout for MEM_END | 0.2 s | +------------------------------+-----------------------------------------------------------+----------+ | serial_write_timeout | Timeout for serial port write | 10 s | +------------------------------+-----------------------------------------------------------+----------+ @@ -111,14 +111,26 @@ Complete list of configurable options: +------------------------------+-----------------------------------------------------------+----------+ | custom_reset_sequence | Custom reset sequence for resetting into the bootloader | | +------------------------------+-----------------------------------------------------------+----------+ +| custom_hard_reset_sequence | Custom reset sequence for hard resetting the chip | | ++------------------------------+-----------------------------------------------------------+----------+ + + +.. note:: + + ``connect_attempts`` is the number of attempts to connect to the chip after the port is detected. This is useful when the chip does not enter bootloader mode immediately. For example, when :ref:`automatic bootloader mode ` does not work and :ref:`manual bootloader mode ` has to be used. + + On the other hand, ``open_port_attempts`` is the number of attempts to look for a port to open. When starting the command, the port does not have to be available. This can be useful when the chip is in deep sleep and is connected using USB-Serial/JTAG. In such cases, the port can disappear. -Custom Reset Sequence ---------------------- +Custom Reset Sequences +---------------------- The ``custom_reset_sequence`` configuration option allows you to define a reset sequence which will get used when an :ref:`automatic reset into the serial bootloader ` is performed. -The sequence is defined with a string in the following format: +The ``custom_hard_reset_sequence`` option allows you to define a reset sequence which will get +used when a hard reset (a reset out of the bootloader) is performed. + +A sequence is defined with a string in the following format: - Consists of individual commands divided by ``|`` (e.g. ``R0|D1|W0.5``). - Commands (e.g. ``R0``) are defined by a code (``R``) and an argument (``0``). @@ -137,14 +149,34 @@ The sequence is defined with a string in the following format: +------+-----------------------------------------------------------+-----------------+ -For example: ``D0|R1|W0.1|D1|R0|W0.5|D0`` represents the following classic reset sequence: +For example: ``D0|R1|W0.1|D1|R0|W0.05|D0`` represents the following classic reset sequence: .. code-block:: python - _setDTR(False) # IO0=HIGH + _setDTR(False) # BOOT=HIGH _setRTS(True) # EN=LOW, chip in reset time.sleep(0.1) - _setDTR(True) # IO0=LOW + _setDTR(True) # BOOT=LOW _setRTS(False) # EN=HIGH, chip out of reset time.sleep(0.05) - _setDTR(False) # IO0=HIGH, done + _setDTR(False) # BOOT=HIGH, done + +The sequence can be visualized as follows: + +.. figure:: diag/reset_sequence.svg + :align: center + :alt: Signal representation of sequence + + Signal representation of the reset sequence + +.. note:: + + Please note that this sequence is representation of signals on Espressif devkit and may differ on other boards. + +Similarly, ``R1|W0.1|R0`` represents the classic hard reset sequence: + +.. code-block:: python + + _setRTS(True) # EN=LOW, chip in reset + time.sleep(0.1) + _setRTS(False) # EN=HIGH, chip out of reset diff --git a/tools/esptool_py/docs/en/esptool/diag/reset_sequence.svg b/tools/esptool_py/docs/en/esptool/diag/reset_sequence.svg new file mode 100644 index 0000000000..32eca6bc3d --- /dev/null +++ b/tools/esptool_py/docs/en/esptool/diag/reset_sequence.svg @@ -0,0 +1,1380 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + DTR + + + + + + + + + + + + + + + + + + + + + RTS + + + + + + + + + + + + + + + + + + + + + EN + + + + + + + + + + + + + + + + + + + + + BOOT + + + + + + + + + + + + + + + + + + + + + + + + 0.1s + + + + + 0.05s + + + + + + + + + + + + + + + diff --git a/tools/esptool_py/docs/en/esptool/entering-bootloader.rst b/tools/esptool_py/docs/en/esptool/entering-bootloader.rst index 4e5a95837a..204e07ffa3 100644 --- a/tools/esptool_py/docs/en/esptool/entering-bootloader.rst +++ b/tools/esptool_py/docs/en/esptool/entering-bootloader.rst @@ -3,7 +3,7 @@ Entering the Bootloader ======================= -Espressif chips have to be reset in a certain way in order to launch the serial bootloader, only then can ``esptool.py`` communicate with the ESP chip. +Espressif chips have to be reset in a certain way in order to launch the serial bootloader, only then can ``esptool`` communicate with the ESP chip. On some development boards (including NodeMCU, WeMOS, HUZZAH Feather, Core Board, ESP32-WROVER-KIT), esptool can :ref:`automatically trigger a reset into the serial bootloader ` - in which case you don't need to read this section. diff --git a/tools/esptool_py/docs/en/esptool/flash-modes.rst b/tools/esptool_py/docs/en/esptool/flash-modes.rst index b9d18686d0..211349bb4f 100644 --- a/tools/esptool_py/docs/en/esptool/flash-modes.rst +++ b/tools/esptool_py/docs/en/esptool/flash-modes.rst @@ -1,10 +1,10 @@ -{IDF_TARGET_BOOTLOADER_OFFSET:default="0x0", esp32="0x1000", esp32s2="0x1000", esp32p4="0x2000"} +{IDF_TARGET_BOOTLOADER_OFFSET:default="0x0", esp32="0x1000", esp32s2="0x1000", esp32p4="0x2000", esp32c5="0x2000"} {IDF_TARGET_FLASH_FREQ_F:default="80", esp32c2="60", esp32h2="48"} {IDF_TARGET_FLASH_FREQ_0:default="40", esp32c2="30", esp32h2="24"} -{IDF_TARGET_FLASH_FREQ:default="``40m``, ``26m``, ``20m``, ``80m``", esp32c2="``30m``, ``20m``, ``15m``, ``60m``", esp32h2="``24m``, ``16m``, ``12m``, ``48m``", esp32c6="``40m``, ``20m``, ``80m``"} +{IDF_TARGET_FLASH_FREQ:default="``40m``, ``26m``, ``20m``, ``80m``", esp32c2="``30m``, ``20m``, ``15m``, ``60m``", esp32h2="``24m``, ``16m``, ``12m``, ``48m``", esp32c6="``40m``, ``20m``, ``80m``, esp32c5="``40m``, ``20m``, ``80m``, esp32c61="``40m``, ``20m``, ``80m``"} .. _flash-modes: @@ -12,43 +12,43 @@ Flash Modes =========== -``write_flash`` and some other commands accept command line arguments to set bootloader flash mode, flash size and flash clock frequency. The chip needs correct mode, frequency and size settings in order to run correctly - although there is some flexibility. +``write-flash`` and some other commands accept command line arguments to set bootloader flash mode, flash size and flash clock frequency. The chip needs correct mode, frequency and size settings in order to run correctly - although there is some flexibility. A header at the beginning of a bootable image contains these values. -To override these values, the options ``--flash_mode``, ``--flash_size`` and/or ``--flash_freq`` must appear after ``write_flash`` on the command line, for example: +To override these values, the options ``--flash-mode``, ``--flash-size`` and/or ``--flash-freq`` must appear after ``write-flash`` on the command line, for example: :: - esptool.py --port /dev/ttyUSB1 write_flash --flash_mode dio --flash_size 4MB 0x0 bootloader.bin + esptool --port /dev/ttyUSB1 write-flash --flash-mode dio --flash-size 4MB 0x0 bootloader.bin These options are only consulted when flashing a bootable image to an {IDF_TARGET_NAME} at offset {IDF_TARGET_BOOTLOADER_OFFSET}. These are addresses used by the ROM bootloader to load from flash. When flashing at all other offsets, these arguments are not used. -Flash Mode (--flash_mode, -fm) -------------------------------- +Flash Mode: ``--flash-mode``, ``-fm`` +------------------------------------- These set Quad Flash I/O or Dual Flash I/O modes. Valid values are ``keep``, ``qio``, ``qout``, ``dio``, ``dout``. The default is ``keep``, which keeps whatever value is already in the image file. This parameter can also be specified using the environment variable ``ESPTOOL_FM``. .. only:: esp8266 - Most boards use ``qio`` mode. Some ESP8266 modules, including the ESP-12E modules on some (not all) NodeMCU boards, are dual I/O and the firmware will only boot when flashed with ``--flash_mode dio``. + Most boards use ``qio`` mode. Some ESP8266 modules, including the ESP-12E modules on some (not all) NodeMCU boards, are dual I/O and the firmware will only boot when flashed with ``--flash-mode dio``. .. only:: not esp8266 Most {IDF_TARGET_NAME} modules use ``qio``, but are also dual I/O. -In ``qio`` mode, two additional GPIOs (9 and 10) are used for SPI flash communications. If flash mode is set to ``dio`` then these pins are available for other purposes. +In ``qio`` mode, two additional GPIOs are used for SPI flash communications. If flash mode is set to ``dio`` then these pins are available for other purposes. Search for ``SPIWP`` and ``SPIHD`` pins in the `{IDF_TARGET_NAME} Technical Reference Manual <{IDF_TARGET_TRM_EN_URL}>`__ to learn more. For a full explanation of these modes, see the :ref:`SPI Flash Modes page `. -Flash Frequency (--flash_freq, -ff) ------------------------------------- +Flash Frequency: ``--flash-freq``, ``-ff`` +------------------------------------------ Clock frequency for SPI flash interactions. Valid values are ``keep``, {IDF_TARGET_FLASH_FREQ} (MHz). The default is ``keep``, which keeps whatever value is already in the image file. This parameter can also be specified using the environment variable ``ESPTOOL_FF``. The flash chip connected to most chips works with {IDF_TARGET_FLASH_FREQ_0}MHz clock speeds, but you can try lower values if the device won't boot. The highest {IDF_TARGET_FLASH_FREQ_F}MHz flash clock speed will give the best performance, but may cause crashing if the flash or board design is not capable of this speed. -Flash Size (--flash_size, -fs) -------------------------------- +Flash Size: ``--flash-size``, ``-fs`` +------------------------------------- Size of the SPI flash, given in megabytes. @@ -56,7 +56,7 @@ Size of the SPI flash, given in megabytes. Valid values are: ``keep``, ``detect``, ``256KB``, ``512KB``, ``1MB``, ``2MB``, ``4MB``, ``2MB-c1``, ``4MB-c1``, ``8MB``, ``16MB`` -.. only:: esp32 or esp32c3 or esp32c6 or esp32c2 or esp32h2 +.. only:: esp32 or esp32c3 or esp32c6 or esp32c2 or esp32h2 or esp32c5 or esp32c61 Valid values are: ``keep``, ``detect``, ``1MB``, ``2MB``, ``4MB``, ``8MB``, ``16MB`` @@ -72,14 +72,14 @@ Size of the SPI flash, given in megabytes. For ESP8266, some :ref:`additional sizes & layouts for OTA "firmware slots" are available `. -The default ``--flash_size`` parameter is ``keep``. This means that if no ``--flash_size`` argument is passed when flashing a bootloader, the value in the bootloader .bin file header is kept instead of detecting the actual flash size and updating the header. +The default ``--flash-size`` parameter is ``keep``. This means that if no ``--flash-size`` argument is passed when flashing a bootloader, the value in the bootloader .bin file header is kept instead of detecting the actual flash size and updating the header. -To enable automatic flash size detection based on SPI flash ID, add the argument ``esptool.py [...] write_flash [...] -fs detect``. If detection fails, a warning is printed and a default value of of ``4MB`` (4 megabytes) is used. +To enable automatic flash size detection based on SPI flash ID, add the argument ``esptool [...] write-flash [...] -fs detect``. If detection fails, a warning is printed and a default value of of ``4MB`` (4 megabytes) is used. -If flash size is not successfully detected, you can find the flash size by using the ``flash_id`` command and then looking up the ID from the output (see :ref:`Read SPI flash id `). +If flash size is not successfully detected, you can find the flash size by using the ``flash-id`` command and then looking up the ID from the output (see :ref:`Read SPI flash id `). Alternatively, read off the silkscreen labelling of the flash chip and search for its datasheet. -The default ``flash_size`` parameter can also be overridden using the environment variable ``ESPTOOL_FS``. +The default ``--flash-size`` parameter can also be overridden using the environment variable ``ESPTOOL_FS``. .. only:: esp8266 @@ -92,7 +92,7 @@ The default ``flash_size`` parameter can also be overridden using the environmen If using OTA, some additional sizes & layouts for OTA "firmware slots" are available. If not using OTA updates then you can ignore these extra sizes: +-------------------+-----------------------+-----------------+-----------------+ - | flash_size arg | Number of OTA slots | OTA Slot Size | Non-OTA Space | + | flash size arg | Number of OTA slots | OTA Slot Size | Non-OTA Space | +===================+=======================+=================+=================+ | 256KB | 1 (no OTA) | 256KB | N/A | +-------------------+-----------------------+-----------------+-----------------+ @@ -113,7 +113,7 @@ The default ``flash_size`` parameter can also be overridden using the environmen | 16MB [^] | 2 | 1024KB | 14336KB | +-------------------+-----------------------+-----------------+-----------------+ - - [^] Support for 8MB & 16MB flash size is not present in all ESP8266 SDKs. If your SDK doesn't support these flash sizes, use ``--flash_size 4MB``. + - [^] Support for 8MB & 16MB flash size is not present in all ESP8266 SDKs. If your SDK doesn't support these flash sizes, use ``--flash-size 4MB``. .. only:: not esp8266 diff --git a/tools/esptool_py/docs/en/esptool/flasher-stub.rst b/tools/esptool_py/docs/en/esptool/flasher-stub.rst index c2f179be7c..ec27959d01 100644 --- a/tools/esptool_py/docs/en/esptool/flasher-stub.rst +++ b/tools/esptool_py/docs/en/esptool/flasher-stub.rst @@ -3,22 +3,22 @@ Flasher Stub ============ -``esptool.py`` is a serial flasher utility. It communicates with the ROM bootloader in `Espressif SoCs `_ in order to load user applications or read chip data via serial port. +``esptool`` is a serial flasher utility. It communicates with the ROM bootloader in `Espressif SoCs `_ in order to load user applications or read chip data via serial port. The ROM bootloader is burned into the ESP chip during manufacturing and cannot be updated. A new version is issued only when a new chip revision is released. -``esptool.py`` works around the limitations imposed by a fixed ROM bootloader by implementing a flasher stub (also known as "stub loader" or just "stub"). It is a small application used as a temporary substitute or extension for the ROM. +``esptool`` works around the limitations imposed by a fixed ROM bootloader by implementing a flasher stub (also known as "stub loader" or just "stub"). It is a small application used as a temporary substitute or extension for the ROM. -When ``esptool.py`` connects to a chip, it first uploads the flasher stub, which basically replaces the original bootloader. All following operations are then handled by the stub. +When ``esptool`` connects to a chip, it first uploads the flasher stub, which basically replaces the original bootloader. All following operations are then handled by the stub. Benefits -------- The flasher stub behaves the same as the original bootloader, but uses more heavily optimized UART routines. -The main benefit is improved performance of flashing and some other operations (like reading flash). Additionally, there are a few commands which are only available when using the stub loader (such as :ref:`erase_flash and erase_region `). It also allows to work around any bugs in ROM bootloaders. +The main benefit is improved performance of flashing and some other operations (like reading flash). Additionally, it also allows to work around any bugs in ROM bootloaders. Disabling the Stub Loader ------------------------- -There might be cases where it is necessary to disable the stub loader (e.g. debugging). To do that, run ``esptool.py`` with the ``--no-stub`` argument. All operations will then be handled by the original ROM bootloader. See the related :ref:`advanced options page `. +There might be cases where it is necessary to disable the stub loader (e.g. debugging). To do that, run ``esptool`` with the ``--no-stub`` argument. All operations will then be handled by the original ROM bootloader. See the related :ref:`advanced options page `. diff --git a/tools/esptool_py/docs/en/esptool/flashing-firmware.rst b/tools/esptool_py/docs/en/esptool/flashing-firmware.rst index 78a6c575d0..c6917b0da3 100644 --- a/tools/esptool_py/docs/en/esptool/flashing-firmware.rst +++ b/tools/esptool_py/docs/en/esptool/flashing-firmware.rst @@ -1,4 +1,4 @@ -{IDF_TARGET_BOOTLOADER_OFFSET:default="0x0", esp32="0x1000", esp32s2="0x1000", esp32p4="0x2000"} +{IDF_TARGET_BOOTLOADER_OFFSET:default="0x0", esp32="0x1000", esp32s2="0x1000", esp32p4="0x2000", esp32c5="0x2000"} .. _flashing: @@ -46,9 +46,14 @@ ESP-IDF ESP-IDF outputs the full esptool command used for flashing after the build is finished, for example:: - Project build complete. To flash, run this command: - python esptool.py -p (PORT) -b 460800 --before default_reset --after hard_reset --chip {IDF_TARGET_PATH_NAME} write_flash --flash_mode dio --flash_size detect --flash_freq 40m {IDF_TARGET_BOOTLOADER_OFFSET} build/bootloader/bootloader.bin 0x8000 build/partition_table/partition-table.bin 0x10000 build/hello_world.bin - or run 'idf.py -p (PORT) flash' + Project build complete. To flash, run: + idf.py flash + or + idf.py -p PORT flash + or + python -m esptool --chip {IDF_TARGET_PATH_NAME} -b 460800 --before default-reset --after hard-reset write-flash --flash-mode dio --flash-size 2MB --flash-freq 40m {IDF_TARGET_BOOTLOADER_OFFSET} build/bootloader/bootloader.bin 0x8000 build/partition_table/partition-table.bin 0x10000 build/hello_world.bin + or from the "esp-idf/examples/get-started/hello_world/build" directory + python -m esptool --chip {IDF_TARGET_PATH_NAME} -b 460800 --before default-reset --after hard-reset write-flash "@flash_args" Arduino ^^^^^^^ @@ -62,46 +67,48 @@ To do a verbose upload and see the exact esptool invocation, run ``pio run -v -t :: - “.../.platformio/penv/bin/python2.7” “.../.platformio/packages/tool-esptoolpy/esptool.py” --chip {IDF_TARGET_PATH_NAME} --port “/dev/cu.usbserial001” --baud 921600 --before default_reset --after hard_reset write_flash -z --flash_mode dio --flash_freq 40m --flash_size detect {IDF_TARGET_BOOTLOADER_OFFSET} .../.platformio/packages/framework-arduinoespressif32/tools/sdk/bin/bootloader_dio_40m.bin 0x8000 .../project_folder/.pio/build/esp32doit-devkit-v1/partitions.bin 0xe000 .../.platformio/packages/framework-arduinoespressif32/tools/partitions/boot_app0.bin 0x10000 .pio/build/esp32doit-devkit-v1/firmware.bin + ".../.platformio/penv/bin/python" ".../.platformio/packages/tool-esptoolpy/esptool.py" --chip {IDF_TARGET_PATH_NAME} --port "/dev/cu.usbserial001" --baud 921600 --before default-reset --after hard-reset write-flash -z --flash-mode dio --flash-freq 40m --flash-size detect {IDF_TARGET_BOOTLOADER_OFFSET} .../.platformio/packages/framework-arduinoespressif32/tools/sdk/bin/bootloader_dio_40m.bin 0x8000 .../project_folder/.pio/build/esp32doit-devkit-v1/partitions.bin 0xe000 .../.platformio/packages/framework-arduinoespressif32/tools/partitions/boot_app0.bin 0x10000 .pio/build/esp32doit-devkit-v1/firmware.bin Flashing -------- -If you split the output, you’ll find the ``write_flash`` command with a list of paths to binary files and their respective flashing offsets. If necessary, change the paths to the actual file locations. +If you split the output, you'll find the ``write-flash`` command with a list of paths to binary files and their respective flashing offsets. If necessary, change the paths to the actual file locations. Change ``PORT`` to the name of :ref:`actually used serial port ` and run the command. A successful flash looks like this:: - $ python esptool.py -p /dev/tty.usbserial-0001 -b 460800 --before default_reset --after hard_reset --chip {IDF_TARGET_PATH_NAME} write_flash --flash_mode dio --flash_size detect --flash_freq 40m {IDF_TARGET_BOOTLOADER_OFFSET} build/bootloader/bootloader.bin 0x8000 build/partition_table/partition-table.bin 0x10000 build/hello_world.bin - esptool.py v3.2-dev - Serial port /dev/tty.usbserial-0001 + $ python -m esptool -p /dev/tty.usbserial-0001 -b 460800 --before default-reset --after hard-reset --chip {IDF_TARGET_PATH_NAME} write-flash --flash-mode dio --flash-size detect --flash-freq 40m {IDF_TARGET_BOOTLOADER_OFFSET} build/bootloader/bootloader.bin 0x8000 build/partition_table/partition-table.bin 0x10000 build/hello_world.bin + esptool v5.0 + Serial port /dev/tty.usbserial-0001: Connecting......... - Chip is ESP32-D0WD (revision 1) - Features: WiFi, BT, Dual Core, 240MHz, VRef calibration in efuse, Coding Scheme None - Crystal is 40MHz - MAC: de:ad:be:ef:1d:ea - Uploading stub... - Running stub... - Stub running... - Changing baud rate to 460800 + Connected to ESP32 on /dev/tty.usbserial-0001: + Chip type: ESP32-D0WD (revision 1) + Features: WiFi, BT, Dual Core, 240MHz, Vref calibration in eFuse, Coding Scheme None + Crystal frequency: 40MHz + MAC: de:ad:be:ef:1d:ea + + Uploading stub flasher... + Running stub flasher... + Stub flasher running. + Changing baud rate to 460800... Changed. Configuring flash size... - Auto-detected Flash size: 16MB + Auto-detected flash size: 4MB Flash will be erased from 0x00001000 to 0x00007fff... Flash will be erased from 0x00008000 to 0x00008fff... Flash will be erased from 0x00010000 to 0x00039fff... - Flash params set to 0x0240 + Flash parameters set to 0x0240. + SHA digest in image updated. Compressed 25536 bytes to 15935... - Wrote 25536 bytes (15935 compressed) at 0x00001000 in 0.7 seconds (effective 275.5 kbit/s)... + Wrote 25536 bytes (15935 compressed) at 0x00001000 in 0.7 seconds (effective 275.5 kbit/s). Hash of data verified. Compressed 3072 bytes to 103... - Wrote 3072 bytes (103 compressed) at 0x00008000 in 0.1 seconds (effective 334.1 kbit/s)... + Wrote 3072 bytes (103 compressed) at 0x00008000 in 0.1 seconds (effective 334.1 kbit/s). Hash of data verified. Compressed 169232 bytes to 89490... - Wrote 169232 bytes (89490 compressed) at 0x00010000 in 2.6 seconds (effective 513.0 kbit/s)... + Wrote 169232 bytes (89490 compressed) at 0x00010000 in 2.6 seconds (effective 513.0 kbit/s). Hash of data verified. - Leaving... Hard resetting via RTS pin... It is now possible to unplug the flashed device and repeat the process by connecting another one and running the command again. diff --git a/tools/esptool_py/docs/en/esptool/index.rst b/tools/esptool_py/docs/en/esptool/index.rst index 495896fb99..b5beb29e2e 100644 --- a/tools/esptool_py/docs/en/esptool/index.rst +++ b/tools/esptool_py/docs/en/esptool/index.rst @@ -1,11 +1,11 @@ .. _esptool: -esptool.py +esptool ========== -Use ``esptool.py -h`` to see a summary of all available commands and command line options. +Use ``esptool -h`` to see a summary of all available commands and command line options. -To see all options for a particular command, append ``-h`` to the command name. ie ``esptool.py write_flash -h``. +To see all options for a particular command, append ``-h`` to the command name. ie ``esptool write-flash -h``. .. toctree:: :maxdepth: 1 @@ -14,13 +14,12 @@ To see all options for a particular command, append ``-h`` to the command name. Basic Commands Advanced Options Advanced Commands - Flasher Stub - Flash Modes Entering the Bootloader Serial Connection - Configuration File - Remote Serial Ports Flashing Firmware + Flasher Stub + Flash Modes + Configuration File Scripting .. only:: not esp8266 @@ -29,3 +28,4 @@ To see all options for a particular command, append ``-h`` to the command name. * :ref:`espefuse` * :ref:`espsecure` + * :ref:`esp_rfc2217_server ` diff --git a/tools/esptool_py/docs/en/esptool/scripting.rst b/tools/esptool_py/docs/en/esptool/scripting.rst index e4e96608d2..c2a0ee05d4 100644 --- a/tools/esptool_py/docs/en/esptool/scripting.rst +++ b/tools/esptool_py/docs/en/esptool/scripting.rst @@ -3,12 +3,355 @@ Embedding into Custom Scripts ============================= -``esptool.py``, ``espefuse.py``, and ``espsecure.py`` can easily be integrated into Python applications or called from other Python scripts. +``esptool`` can be easily integrated into Python applications or called from other Python scripts. -While it currently does have a poor Python API, something which `#208 `_ will address, it allows for passing CLI arguments to ``esptool.main()``. This workaround makes integration very straightforward as you can pass exactly the same arguments as you would on the CLI: +Using Esptool as a Python Module +-------------------------------- + +The esptool module provides a comprehensive Python API for interacting with ESP chips programmatically. By leveraging the API, developers can automate tasks such as flashing firmware, reading device information, managing flash memory, or preparing and analyzing binary images. The API supports both high-level abstractions and low-level control. + +Using the Command-Line Interface +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The most straightforward and basic integration option is to pass arguments to ``esptool.main()``. This workaround allows you to pass exactly the same arguments as you would on the CLI: .. code-block:: python - command = ['--baud', '460800', 'read_flash', '0', '0x200000', 'flash_contents.bin'] - print('Using command %s' % ' '.join(command)) + import esptool + + command = ['--baud', '460800', 'read-flash', '0', '0x200000', 'flash_contents.bin'] + print("Using command ", " ".join(command)) esptool.main(command) + +Public API Reference +^^^^^^^^^^^^^^^^^^^^ + +For more control and custom integration, esptool exposes a public API - a set of high-level functions that encapsulate common operations and simplify the interaction with the ESP chip. These functions are designed to be user-friendly and provide an intuitive way to work with the chip. The public API is the recommended way to interact with the chip programmatically. + +Basic Workflow: + +1. **Detect and Connect**: Use ``detect_chip()`` to automatically identify the connected ESP chip and establish a connection, or manually create and instantiate a specific ``ESPLoader`` object (e.g. ``ESP32ROM``) and establish a connection in two steps. +2. **Run Stub Flasher (Optional)**: Upload and execute the :ref:`stub flasher ` which provides enhanced functionality and speed. +3. **Perform Operations**: Utilize the chip object's methods or public API command functions to interact with the device. +4. **Reset and Cleanup**: Ensure proper reset and resource cleanup using context managers. + +------------ + +This example demonstrates writing two binary files using high-level commands: + +.. code-block:: python + + from esptool.cmds import detect_chip, attach_flash, reset_chip, run_stub, write_flash + + PORT = "/dev/ttyACM0" + BOOTLOADER = "bootloader.bin" + FIRMWARE = "firmware.bin" + + with detect_chip(PORT) as esp: + esp = run_stub(esp) # Skip this line to avoid running the stub flasher + attach_flash(esp) # Attach the flash memory chip, required for flash operations + with open(BOOTLOADER, "rb") as bl_file, open(FIRMWARE, "rb") as fw_file: + write_flash(esp, [(0, bl_file), (0x1000, fw_file)]) # Write the binary files + reset_chip(esp, "hard-reset") # Reset the chip + +- The ``esp`` object has to be replaced with the stub flasher object returned by ``run_stub(esp)`` when the stub flasher is activated. This step can be skipped if the stub flasher is not needed. +- Running ``attach_flash(esp)`` is required for any flash-memory-related operations to work. +- Using the ``esp`` object in a context manager ensures the port gets closed properly after the block is executed. + +------------ + +The following example demonstrates running a series of flash memory operations in one go: + +.. code-block:: python + + from esptool.cmds import ( + erase_flash, + attach_flash, + flash_id, + read_flash, + reset_chip, + run_stub, + verify_flash, + write_flash, + ) + from esptool.targets import ESP32ROM # Import the target class, e.g. ESP8266ROM, ESP32S3ROM, etc. + + PORT = "/dev/ttyACM0" + BOOTLOADER = "bootloader.bin" + FIRMWARE = "firmware.bin" + + with ESP32ROM(PORT) as esp: + esp.connect() # Connect to the ESP chip, needed when ESP32ROM is instantiated directly + esp = run_stub(esp) # Run the stub loader (optional) + attach_flash(esp) # Attach the flash memory chip, required for flash operations + flash_id(esp) # Print information about the flash chip + erase_flash(esp) # Erase the flash memory first + with open(BOOTLOADER, "rb") as bl_file, open(FIRMWARE, "rb") as fw_file: + write_flash(esp, [(0, bl_file), (0x1000, fw_file)]) # Write the binary files + verify_flash(esp, [(0, bl_file), (0x1000, fw_file)]) # Verify the written data + read_flash(esp, 0x0, 0x2400, "output.bin") # Read the flash memory into a file + reset_chip(esp, "hard-reset") # Reset the chip + +- This example doesn't use ``detect_chip()``, but instantiates a ``ESP32ROM`` class directly. This is useful when you know the target chip in advance. In this scenario ``esp.connect()`` is required to establish a connection with the device. +- Multiple operations can be chained together in a single context manager block. + +------------ + +The Public API implements a custom ``ImageSource`` input type, which expands to ``str | bytes | IO[bytes]`` - a path to the firmware image file, an opened file-like object, or the image data as bytes. + +As output, the API returns a ``bytes`` object representing the binary image or writes the image to a file if the ``output`` parameter is provided. + +The following example converts an ELF file to a flashable binary, prints the image information, and flashes the image. The example demonstrates three different ways to achieve the same result, showcasing the flexibility of the API: + +.. code-block:: python + + ELF = "firmware.elf" + + # var 1 - Loading ELF from a file, not writing binary to a file + bin_file = elf2image(ELF, "esp32c3") + image_info(bin_file) + with detect_chip(PORT) as esp: + attach_flash(esp) + write_flash(esp, [(0, bin_file)]) + + # var 2 - Loading ELF from an opened file object, not writing binary to a file + with open(ELF, "rb") as elf_file, detect_chip(PORT) as esp: + bin_file = elf2image(elf_file, "esp32c3") + image_info(bin_file) + attach_flash(esp) + write_flash(esp, [(0, bin_file)]) + + # var 3 - Loading ELF from a file, writing binary to a file + elf2image(ELF, "esp32c3", "image.bin") + image_info("image.bin") + with detect_chip(PORT) as esp: + attach_flash(esp) + write_flash(esp, [(0, "image.bin")]) + + +------------ + +**The following section provides a detailed reference for the public API functions.** + +Chip Control Operations +""""""""""""""""""""""" + +.. autofunction:: esptool.cmds.detect_chip + +.. autofunction:: esptool.cmds.run_stub + +.. autofunction:: esptool.cmds.load_ram + +.. autofunction:: esptool.cmds.run + +.. autofunction:: esptool.cmds.reset_chip + +------------ + +Chip Information Operations +""""""""""""""""""""""""""" + +.. autofunction:: esptool.cmds.chip_id + +.. autofunction:: esptool.cmds.get_security_info + +.. autofunction:: esptool.cmds.read_mac + +------------ + +Flash Memory Manipulation Operations +"""""""""""""""""""""""""""""""""""" + +.. autofunction:: esptool.cmds.attach_flash + +.. autofunction:: esptool.cmds.flash_id + +.. autofunction:: esptool.cmds.read_flash + +.. autofunction:: esptool.cmds.write_flash + +.. autofunction:: esptool.cmds.erase_flash + +.. autofunction:: esptool.cmds.erase_region + +.. autofunction:: esptool.cmds.verify_flash + +.. autofunction:: esptool.cmds.read_flash_status + +.. autofunction:: esptool.cmds.write_flash_status + +.. autofunction:: esptool.cmds.read_flash_sfdp + +------------ + +Memory Operations +""""""""""""""""" + +.. autofunction:: esptool.cmds.read_mem + +.. autofunction:: esptool.cmds.write_mem + +.. autofunction:: esptool.cmds.dump_mem + +------------ + +Binary Image Manipulation Operations +"""""""""""""""""""""""""""""""""""" + +The following commands can run without the need for a connected chip: + +.. autofunction:: esptool.cmds.elf2image + +.. autofunction:: esptool.cmds.merge_bin + +.. autofunction:: esptool.cmds.image_info + +------------ + +Utility Functions +""""""""""""""""" + +.. autofunction:: esptool.cmds.version + +------------ + +For more information, refer to the command implementations in `esptool/cmds.py `_. + + +Low-Level API Reference +^^^^^^^^^^^^^^^^^^^^^^^ + +.. warning:: + + The low-level API provides more control but requires a deeper understanding of the ESP chip, the esptool internals, and the :ref:`serial protocol `. It is recommended to use the public API functions for most use cases. + + Also, the low-level internals are not a part of the public API, so they may change in between releases. + + Please submit a :ref:`feature request ` if you are missing something from the officially supported API. + +For granular control and more configuration freedom, you can directly access the low-level methods and attributes of the ``ESPLoader`` object and create your own routines. The following is an example of a custom routine to flash the {IDF_TARGET_NAME}: + +.. note:: + + This example code is a very basic implementation of ``esptool -p /dev/ttyACM0 write-flash 0x10000 firmware.bin`` + +.. code-block:: python + + from esptool.cmds import detect_chip + + # The port of the connected ESP + PORT = "/dev/ttyACM0" + # The binary file + BIN_FILE = "./firmware.bin" + # Flash offset to flash the binary to + FLASH_ADDRESS = 0x10000 + + def progress_callback(percent): + print(f"Wrote: {int(percent)}%") + + with detect_chip(PORT) as esp: + description = esp.get_chip_description() + features = esp.get_chip_features() + print(f"Detected ESP on port {PORT}: {description}") + print("Features:", ", ".join(features)) + + esp = esp.run_stub() + with open(BIN_FILE, 'rb') as binary: + # Load the binary + binary_data = binary.read() + total_size = len(binary_data) + print(f"Binary size: {total_size} bytes") + + # Write binary blocks + esp.flash_begin(total_size, FLASH_ADDRESS) + for i in range(0, total_size, esp.FLASH_WRITE_SIZE): + block = binary_data[i:i + esp.FLASH_WRITE_SIZE] + # Pad the last block + block = block + bytes([0xFF]) * (esp.FLASH_WRITE_SIZE - len(block)) + esp.flash_block(block, i + FLASH_ADDRESS) + progress_callback(i / total_size * 100) + esp.flash_finish() + + # Reset the chip out of bootloader mode + esp.hard_reset() + +------------ + +For more information, refer to the methods of the ``ESPLoader`` class in `esptool/loader.py `_. + +.. _logging: + +Redirecting Output with a Custom Logger +--------------------------------------- + +Esptool allows redirecting output by implementing a custom logger class. This can be useful when integrating esptool with graphical user interfaces or other systems where the default console output is not appropriate. Below is an example demonstrating how to create and use a custom logger: + +.. code-block:: python + + from esptool.logger import log, TemplateLogger + import sys + + class CustomLogger(TemplateLogger): + log_to_file = True + log_file = "esptool.log" + + def print(self, message="", *args, **kwargs): + # Print to console + print(f"[CustomLogger]: {message}", *args, **kwargs) + # Optionally log to a file + if self.log_to_file: + with open(self.log_file, "a") as log: + log.write(f"{message}\n") + + def note(self, message): + self.print(f"NOTE: {message}") + + def warning(self, message): + self.print(f"WARNING: {message}") + + def error(self, message): + self.print(message, file=sys.stderr) + + def stage(self, finish=False): + # Collapsible stages not needed in this example + pass + + def progress_bar( + self, + cur_iter, + total_iters, + prefix = "", + suffix = "", + bar_length: int = 30, + ): + # Progress bars replaced with simple percentage output in this example + percent = f"{100 * (cur_iter / float(total_iters)):.1f}" + self.print(f"Finished: {percent}%") + + def set_verbosity(self, verbosity): + # Set verbosity level not needed in this example + pass + + # Replace the default logger with the custom logger + log.set_logger(CustomLogger()) + + # From now on, all esptool output will be redirected through the custom logger + # Your code here ... + +In this example, the ``CustomLogger`` class provides additional functionality such as logging messages to a file, which the original ``EsptoolLogger`` (imported from ``esptool.logger`` as an initiated object ``log``) doesn't. The ``EsptoolLogger.set_logger()`` method is used to replace the default logger with the custom logger. + +To ensure compatibility with esptool, the custom logger should re-implement (or inherit) the following methods from the original ``EsptoolLogger`` class (see the reference implementation `here `__), this is enforced by the ``TemplateLogger`` abstract class: + +- ``print``: Handles plain message logging. +- ``note``: Logs informational messages. +- ``warning``: Logs warning messages. +- ``error``: Logs error messages. +- ``stage``: Starts or ends a collapsible output stage. +- ``progress_bar``: Displays a progress bar. +- ``set_verbosity``: Sets the verbosity level for logging. + +.. autoclass:: esptool.logger.EsptoolLogger + :members: print, note, warning, error, stage, progress_bar, set_verbosity + :member-order: bysource + +These methods are essential for maintaining proper integration and behavior with esptool. Additionally, all output printing should be made using ``log.print()`` (or the respective method, such as ``log.note()`` or ``log.warning()``) instead of the standard ``print()`` function to ensure the output is routed through the custom logger. This ensures consistency and allows the custom logger to handle all output appropriately. You can further customize this logger to fit your application's needs, such as integrating with GUI components or advanced logging frameworks. diff --git a/tools/esptool_py/docs/en/index.rst b/tools/esptool_py/docs/en/index.rst index 201b71bf14..1a74e68b17 100644 --- a/tools/esptool_py/docs/en/index.rst +++ b/tools/esptool_py/docs/en/index.rst @@ -1,24 +1,34 @@ -Esptool.py Documentation -======================== +Esptool Documentation +===================== -This is the documentation for ``esptool.py`` - a Python-based, open source, platform independent utility to communicate with the ROM bootloader in `Espressif SoCs `_. +.. important:: -``esptool.py``, ``espefuse.py`` and ``espsecure.py`` are a complete toolset for working with Espressif chips. They can do a number of things, for example: + This document describes how to use ``esptool`` with the {IDF_TARGET_NAME} SoC. To switch to a different SoC target, choose target from the dropdown in the upper left corner. + + Please note that this documentation is for the version of ``esptool`` v5. You can find your version in the command output or by running ``esptool version``. + For the version of ``esptool`` v4 please refer to the `v4 documentation `_ or pick from the dropdown in the upper left corner. + +This is the documentation for ``esptool`` - a Python-based, open-source, platform-independent utility for flashing, provisioning, and interacting with Espressif SoCs. Esptool communicates with the ROM bootloader (or the flasher stub) in `Espressif SoCs `_. + +The flasher stub is a small program included with esptool that replaces the original ROM bootloader in the chip to fix some of its limitations and bugs. See :ref:`stub` for more details. + +``esptool``, ``espefuse`` and ``espsecure`` are a complete toolset for working with Espressif chips. They can do a number of things, for example: * Read, write, erase, and verify binary data stored in flash. * Read chip features and other related data such as MAC address or flash chip ID. -* Read and write the one-time-programmable efuses. +* Read and write the one-time-programmable eFuses. * Prepare binary executable images ready for flashing. * Analyze, assemble, and merge binary images. -This document describes using ``esptool.py`` with the {IDF_TARGET_NAME} SoC. To switch to a different SoC target, choose target from the dropdown in the upper left. +``esptool`` can be used both as a command-line tool and as a Python library. The command-line is the most common way to use the tool, and is the primary focus of this documentation. To use it as a library, see the :ref:`scripting ` section. + Quick Start ----------- Getting started is easy: -1) Install ``esptool.py``: +1) Install ``esptool``: :: @@ -29,14 +39,32 @@ Getting started is easy: 2) Connect an Espressif chip to your computer. -3) Run ``esptool.py`` commands. For example, to read information about your chip's SPI flash, run: +.. note:: + + Please note that serial communication has to work and chip has to be in the :ref:`download mode `. + This is usually done :ref:`automatically ` or can be done :ref:`manually `. Esptool cannot function until this is resolved. For more information, see :ref:`troubleshooting`. + +3) Run ``esptool`` commands. For example, to read information about your chip's SPI flash, run: :: - $ esptool.py -p PORT flash_id + $ esptool -p PORT flash-id Replace ``PORT`` with the name of used serial port. If connection fails, see :ref:`troubleshooting`. +After successfully executing the command, esptool will hard reset the chip, causing it to run the user code. This behavior can be adjusted, see :ref:`advanced-options`. + +Alternatives +------------ + +``esptool`` is not the only tool for working with Espressif chips. Some notable options include: + +- `esptool.js `__ is a JavaScript port of esptool that can be used in a web browser or in a Node.js environment. +- `espflash `__ is a Rust port of esptool. It relies on the support in `esp-hal `__, which may delay support for new chips. +- `OpenOCD `__ is a general-purpose tool for debugging and flashing chips. + +Among these, esptool is the most feature-rich, and support for the newest chips and features usually appears here first. + More Information ---------------- @@ -47,9 +75,11 @@ More Information Esptool :not esp8266:Espefuse :not esp8266:Espsecure + Remote Serial Ports Advanced Topics Troubleshooting Contribute Versions + Migration Guide Resources About diff --git a/tools/esptool_py/docs/en/installation.rst b/tools/esptool_py/docs/en/installation.rst index 9e201d9d37..40a1b1bb26 100644 --- a/tools/esptool_py/docs/en/installation.rst +++ b/tools/esptool_py/docs/en/installation.rst @@ -9,8 +9,8 @@ How to Install Global Installation ^^^^^^^^^^^^^^^^^^^ -You will need `Python 3.7 or newer `_ installed on your system to use the latest version of ``esptool.py``. -If your use case requires Python 2.7, 3.4, 3.5, or 3.6, please use ``esptool.py`` v3.3.* instead. +You will need `Python 3.10 or newer `_ installed on your system to use the latest version of ``esptool``. +If your use case requires Python 3.7, 3.8, or 3.9, please use ``esptool`` v4.x. For Python 2.7, 3.4, 3.5, or 3.6, please use ``esptool`` v3.3.* instead. The latest stable esptool release can be installed from `PyPI `_ via pip: @@ -18,11 +18,11 @@ The latest stable esptool release can be installed from `PyPI `_ for information about how to access pip. +With some Python installations this may not work and you'll receive an error, try ``python -m pip install esptool`` or ``pip3 install esptool``, or consult your `Python installation manual `_ for information about how to access pip. `Setuptools `_ is also a requirement which is not available on all systems by default. You can install it by a package manager of your operating system, or by ``pip install setuptools``. -After installing, you will have ``esptool.py`` installed into the default Python executables directory and you should be able to run it with the command ``esptool.py`` or ``python -m esptool``. Please note that probably only ``python -m esptool`` will work for Pythons installed from Windows Store. +After installing, you will have ``esptool`` installed into the default Python executables directory and you should be able to run it with the command ``esptool`` or ``python -m esptool``. Please note that probably only ``python -m esptool`` will work for Pythons installed from Windows Store. .. note:: @@ -31,7 +31,7 @@ After installing, you will have ``esptool.py`` installed into the default Python Virtual Environment Installation ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -To ensure that ``esptool.py`` is used in isolation, and any changes made during its usage won't affect other Python environments or SDK installations, it is advised to install it in a virtual environment and use it directly if possible (more information in the :ref:`flashing` article). +To ensure that ``esptool`` is used in isolation, and any changes made during its usage won't affect other Python environments or SDK installations, it is advised to install it in a virtual environment and use it directly if possible (more information in the :ref:`flashing` article). Creating a virtual environment (venv) is a good practice. This is particularly helpful for users who may be concerned about interfering with existing installations (e.g. in an environment of a development-setup framework). Here's a quick guide: @@ -39,70 +39,103 @@ Creating a virtual environment (venv) is a good practice. This is particularly h - Activate the virtual environment: - On Windows: ``esptoolenv\Scripts\activate`` - - On Linux or MacOS: ``source esptoolenv/bin/activate`` + - On Linux or macOS: ``source esptoolenv/bin/activate`` -- Install the latest ``esptool.py`` version within the active virtual environment: ``pip install esptool`` -- You can now use it within this virtual environment without affecting your system-wide installations: ``esptool.py `` -- When you're done using ``esptool.py``, deactivate the virtual environment: ``deactivate``. The environment can be reused by activating it again. +- Install the latest ``esptool`` version within the active virtual environment: ``pip install esptool`` +- You can now use it within this virtual environment without affecting your system-wide installations: ``esptool `` +- When you're done using ``esptool``, deactivate the virtual environment: ``deactivate``. The environment can be reused by activating it again. - If you no longer need the virtual environment, you can remove it by deleting the ``esptoolenv`` directory. +Binary Releases +^^^^^^^^^^^^^^^^ + +If you do not want to install Python and all the dependencies, you can use the pre-built binaries from the `GitHub Releases `_. + +Please note that the binaries might have some limitations: + +- The binaries might rely on some system libraries that are not available on all systems. +- The binaries are available only for selected operating systems - currently macOS (x86_64, arm64), Linux (x86_64, armv7,aarch64) and Windows (x86_64). +- The binaries might get reported as malware by your antivirus software. +- The application is larger in size compared to the Python package installation, as it includes all dependencies. +- The application has slower startup time compared to running the Python script directly. +- The application cannot be imported as a Python module in other Python applications. + +.. note:: + + For Linux, the binaries are built using Ubuntu 22.04 as the base image. That means any version older than Ubuntu 22.04 (or any other distribution that uses ``glibc<2.35``) might not work. + For using on Ubuntu 20.04, please use the Python package installation or ``v4.*`` release. + How to Update ------------- Standalone ^^^^^^^^^^ -If you are using ``esptool.py`` as a standalone tool (as a global installation or in a virtual environment), updating to the latest version released on the `PyPI `_ index is simple: +If you are using ``esptool`` as a standalone tool (as a global installation or in a virtual environment), updating to the latest version released on the `PyPI `_ index is simple: :: $ pip install --upgrade esptool -As a Component -^^^^^^^^^^^^^^ +As a Part of SDK/Framework +^^^^^^^^^^^^^^^^^^^^^^^^^^ -If ``esptool.py`` is installed as a component of a development framework (e.g. `ESP-IDF `_, `Arduino `_, or `PlatformIO `_), it is advised to follow the update guide of used framework for instructions and not to update the tool directly. +If ``esptool`` is installed as a part of a development SDK/framework (e.g. `ESP-IDF `_, `Arduino `_, or `PlatformIO `_), it is advised to follow the update guide of used framework for instructions and not to update the tool directly. -If updating directly is unavoidable, make sure you update to a compatible version by staying on the same MAJOR version number (explained in the :ref:`versions` article). For instance, if your currently installed ``esptool.py`` is ``v3.3.1``, only update to ``v3.*.*``. You risk introducing incompatible changes by updating to ``v4.*.*`` or higher. +If updating directly is unavoidable, make sure you update to a compatible version by staying on the same MAJOR version number (explained in the :ref:`versions` article). For instance, if your currently installed ``esptool`` is ``v3.3.1``, only update to ``v3.*.*``. You risk introducing incompatible changes by updating to ``v4.*.*`` or higher. :: - $ pip install esptool==3.3.2 + $ pip install "esptool<4" -Shell completions +.. _shell-completion: + +Shell Completions ----------------- To activate autocompletion, you can manually add commands provided below to your shell's config file or run them in your current terminal session for one-time activation. You will likely have to restart or re-login for the autocompletion to start working. -bash: -:: +.. tabs:: - eval "$(register-python-argcomplete esptool.py espsecure.py espefuse.py)" + .. group-tab:: Bash -zsh: + .. code-block:: bash -To activate completions in zsh, first make sure `compinit` is marked for -autoload and run autoload: + eval "$(_ESPTOOL_PY_COMPLETE=bash_source esptool)" + eval "$(_ESPSECURE_PY_COMPLETE=bash_source espsecure)" + eval "$(_ESPEFUSE_PY_COMPLETE=bash_source espefuse)" -.. code-block:: bash - autoload -U compinit - compinit + .. group-tab:: Zsh -Afterwards you can enable completions for esptool.py, espsecure.py and espefuse.py: + To activate completions in zsh, first make sure `compinit` is marked for + autoload and run autoload: -:: + .. code-block:: bash - eval "$(register-python-argcomplete esptool.py espsecure.py espefuse.py)" + autoload -U compinit + compinit -fish: + Afterwards you can enable completions for esptool, espsecure and espefuse: -Not required to be in the config file, only run once -:: + .. code-block:: bash + + eval "$(_ESPTOOL_PY_COMPLETE=zsh_source esptool)" + eval "$(_ESPSECURE_PY_COMPLETE=zsh_source espsecure)" + eval "$(_ESPEFUSE_PY_COMPLETE=zsh_source espefuse)" + + + .. group-tab:: Fish + + .. code-block:: bash + + _ESPTOOL_PY_COMPLETE=fish_source esptool | source + _ESPSECURE_PY_COMPLETE=fish_source espsecure | source + _ESPEFUSE_PY_COMPLETE=fish_source espefuse | source + - register-python-argcomplete --shell fish esptool.py espsecure.py espefuse.py >~/.config/fish/completions/esptool.py.fish Other shells nor OS Windows are not supported. diff --git a/tools/esptool_py/docs/en/migration-guide.rst b/tools/esptool_py/docs/en/migration-guide.rst new file mode 100644 index 0000000000..bbf4ec82dd --- /dev/null +++ b/tools/esptool_py/docs/en/migration-guide.rst @@ -0,0 +1,416 @@ +.. _migration: + +``v5`` Migration Guide +====================== + +This document describes the breaking changes made to esptool.py, espsecure.py and espefuse.py in the major release ``v5``. It provides guidance on adapting existing workflows and scripts to ensure compatibility when updating from ``v4.*``. + + +Command-Line Tool Invocation Changes +************************************ + +The preferred way to invoke esptool command-line tools has changed. Instead of running the scripts with `.py` suffix, you should now use the console scripts without the `.py` suffix. + +**Affected Tools:** + +- ``esptool.py`` → ``esptool`` +- ``espefuse.py`` → ``espefuse`` +- ``espsecure.py`` → ``espsecure`` +- ``esp_rfc2217_server.py`` → ``esp_rfc2217_server`` + +**Migration Steps:** + +1. Update your command-line invocations to use the new names without `.py`: + + **Before:** + + .. code-block:: bash + + esptool.py chip_id + espefuse.py summary + espsecure.py sign_data --keyfile key.pem data.bin + + **After:** + + .. code-block:: bash + + esptool chip_id + espefuse summary + espsecure sign-data --keyfile key.pem data.bin + +2. Update scripts to use the new command names. + +.. note:: + + Scripts with ``.py`` suffix are still available for backward compatibility, but they will produce deprecation warning and will be removed in the next major release. + + +esptool ``v5`` Migration Guide +****************************** + +``image-info`` Output Format Change +################################### + +The output format of the :ref:`image-info ` command has been **updated in v5**. The original format (``--version 1``) is **deprecated** and replaced by the updated format (``--version 2``). The ``--version`` argument has been **removed entirely**, and the new format is now the default and only option. + +**Changes in the New Format:** + +- Improved readability and structure. +- Additional metadata fields for better debugging and analysis. +- Consistent formatting for all ESP chip variants. + +**Migration Steps:** + +1. Update any scripts or tools that parse the ``image-info`` output to use the new format. +2. Remove any ``--version`` arguments from ``image-info`` commands. + +Output Logging +############## + +The esptool ``v5`` release introduces a centralized logging mechanism to improve output management and allow redirection. + +**Key Changes:** + +- All esptool output is now routed through an ``EsptoolLogger`` class. +- The output can include ANSI color codes for better readability. +- Custom loggers can be implemented to redirect output to files or other destinations. + +**Migration Steps:** + +1. If your scripts rely on direct ``print()`` statements, update them to use the centralized logger for consistent output. Calls to the logger should be made using ``log.print()`` (or the respective method, such as ``log.note()``, ``log.warning()``, or ``log.error()``). +2. Refer to the provided documentation to implement custom loggers as needed. +3. Update GUIs or tools to leverage the progress tracking API for better user feedback during lengthy operations. + +See the :ref:`logging ` section for more details on available logger methods and custom logger implementation. + +``write-flash`` ``--verify`` Argument +##################################### + +The ``--verify`` option for the :ref:`write-flash ` command has been **deprecated in v5**. Flash verification is performed automatically after every successful write operation when technically feasible. + +**Behavior:** + +- Verification occurs by default after flashing completes. +- No action is needed to enable verification - it is mandatory when possible. +- Verification is **skipped** if Secure Download Mode (SDM) is active or during encrypted writes (using ``--encrypt``). + +**Migration Steps:** + +1. Remove all ``--verify`` arguments from existing ``write-flash`` commands. +2. Update scripts/CI pipelines to remove ``--verify`` flags. + +Error Output Handling +##################### + +In ``v5``, error handling and output behavior have been improved to provide better user experience and script compatibility. + +**Key Changes:** + +- All error messages, including fatal errors, are now printed to **STDERR** instead of STDOUT. +- User keyboard interrupts (e.g., Ctrl+C) are caught and raise an exit code of 2 to indicate an operation interruption. +- Error messages are displayed in **red text** for better visibility. +- This change ensures that errors are not lost when STDOUT is filtered or redirected. + +**Migration Steps:** + +1. Update scripts that rely on parsing STDOUT for error messages to check STDERR instead. +2. Ensure scripts handle non-zero exit codes correctly in the case of operations interrupted by the user. + +Beta Target Support Removal +########################### + +Support for the following beta targets has been **removed in v5**: + +- ``ESP32-C5(beta3)`` +- ``ESP32-C6(beta)`` +- ``ESP32-H2(beta1)`` +- ``ESP32-H2(beta2)`` +- ``ESP32-S3(beta2)`` + +**Migration Steps:** + +1. Update any scripts or workflows not to target these beta chips. +2. Remove any references to these beta targets from CI/CD pipelines or build scripts. + +Use esptool ``v4`` for legacy workflows targeting these beta chips. + +``verify-flash`` ``--diff`` Argument +#################################### + +The format of the ``--diff`` option of the :ref:`verify-flash ` command has **changed in v5**. Previously, ``--diff=yes/no`` had to be specified to enable or disable the diff output. In the new version, the ``--diff`` option is a simple boolean switch without the need of a ``yes`` or ``no`` value. + +**Migration Steps:** + +1. Rewrite the ``--diff=yes`` argument to a simple ``--diff`` in any existing ``verify-flash`` commands in scripts/CI pipelines. Delete ``--diff=no`` completely if detailed diff output is not required. + +Using esptool as a Python Module +################################ + +All command functions (e.g., ``verify-flash``, ``write-flash``) have been refactored to remove their dependency on the ``args`` object from the argparse module. Instead, all arguments are now passed explicitly as individual parameters. This change, combined with enhancements to the public API, provides a cleaner, more modular interface for programmatic use of esptool in custom scripts and applications (see :ref:`scripting `). + +**Key Changes:** + +- Refactored Function Signatures: Previously, command functions relied on an ``args`` object (e.g., ``args.addr_filename``, ``args.diff``). Now, they take individual parameters with explicit types and default values, improving clarity and enabling a robust API. +- Public API Expansion: The public API (exposed via ``esptool.cmds``) has been formalized with high-level functions like ``detect_chip()``, ``attach_flash()``, ``write-flash()``, and ``reset_chip()``, designed for ease of use in Python scripts. + +**Migration Steps:** + +1. Update Function Calls: If you are calling esptool functions programmatically, replace ``args`` object usage with individual parameter passing. Refer to the function signatures in ``esptool.cmds`` for the new parameter names, types, and defaults. +2. Leverage the Public API: Use the new high-level functions in ``esptool.cmds`` for common operations like chip detection, flash attachment, flashing, resetting, or image generation. +3. Test your updated scripts to ensure compatibility with the new API. + +For detailed examples and API reference, see the :ref:`scripting ` section. + + +Flash Operations from Non-flash Related Commands +################################################ + +When esptool is used as a CLI tool, the following commands no longer automatically attach the flash by default, since flash access is not required for their core functionality: + +- ``load-ram`` +- ``read-mem`` +- ``write-mem`` +- ``dump-mem`` +- ``chip-id`` +- ``read-mac`` + +The ``--spi-connection`` CLI argument has been **removed** from non-flash related commands in v5. This argument had no effect on the command execution. Affected commands: + +- ``elf2image`` +- ``merge-bin`` + +**Migration Steps:** + +1. Update any scripts that attempt to attach flash from non-flash related commands. +2. If you need to attach flash for above mentioned commands, use the ``attach_flash`` function from the public API instead. For more details see :ref:`scripting `. +3. Remove the ``--spi-connection`` argument from ``elf2image`` and ``merge-bin`` commands. + + +Shell Completion +################ + +The esptool ``v5`` has switched to using `Click `_ for command line argument parsing, which changes how shell completion works. + +**Migration Steps:** + +1. Remove the old shell completion code from your scripts and shell configuration files like ``.bashrc``, ``.zshrc``, ``.config/fish/config.fish``, etc. +2. Follow the new shell completion setup instructions in the :ref:`shell-completion` section of the :ref:`installation ` guide. + +``merge-bin`` ``--fill-flash-size`` Argument +############################################ + +The ``--fill-flash-size`` option of the :ref:`merge-bin ` command has been renamed to ``--pad-to-size``. This change provides a more intuitive and descriptive name for the argument and is consistent with the naming scheme in other esptool image manipulation commands. + +**Migration Steps:** + +1. Rename the ``--fill-flash-size`` to ``--pad-to-size`` in any existing ``merge-bin`` commands in scripts/CI pipelines. + +``write-flash`` ``--ignore-flash-encryption-efuse-setting`` Argument +#################################################################### + +The ``--ignore-flash-encryption-efuse-setting`` option of the :ref:`write-flash ` command has been renamed to ``--ignore-flash-enc-efuse``. This change shortens the argument name to improve readability and consistency with other esptool options. + +**Migration Steps:** + +1. Rename the ``--ignore-flash-encryption-efuse-setting`` to ``--ignore-flash-enc-efuse`` in any existing ``write-flash`` commands in scripts/CI pipelines. + +``make_image`` Command Removal +############################## + +The ``make_image`` command for the ESP8266 has been **removed in v5**. This command has been deprecated in favor of using **objcopy** (or other tools) to generate ELF images and then using ``elf2image`` to create the final ``.bin`` file. + +**Migration Steps:** + +1. Replace any ``make_image`` workflows with the recommended way of assembling firmware images using **objcopy** and ``elf2image``. + +Using Binary from GitHub Releases on Linux +########################################## + +The ``esptool`` binary from GitHub Releases on Linux is now using Ubuntu 22.04 as the base image. That means the image is using ``glibc`` 2.35, which is not fully compatible with the ``glibc`` 2.28 from Ubuntu 20.04 (the base image for ``v4.*``). + +**Migration Steps:** + +1. Update your operating system to a newer version which bundles ``glibc`` 2.35 or later + +Command and Option Renaming +########################### + +All the commands and options have been renamed to use ``-`` instead of ``_`` as a separator (e.g., ``write_flash`` -> ``write-flash``). + +Old command and option names are **deprecated**, meaning they will work for now with a warning, but will be removed in the next major release. + +This change affects most of the commands and the following options: ``--flash_size``, ``--flash_mode``, ``--flash_freq``, ``--use_segments``. + +**Migration Steps:** + +1. Replace all underscores in command and option names with ``-`` in your scripts and CI pipelines. + +Log Format Changes +################## + +A significant amount of changes have been made to the log styling and formatting in ``v5``. Some of the messages, warnings, and errors are now formatted differently or reworded to provide more context and improve readability. Exhaustive list of changed messages won't be provided. + +**Migration Steps:** + +1. Make sure to adjust any of your scripts, asserts, CI workflows, or others to accommodate the new/changed format of messages. If you are parsing the log output (not recommended), consider importing esptool as a module and using the public API (see :ref:`here `) to get the information you need. + + +Reset Mode Renaming +################### + +Choices for the ``--before`` and ``--after`` options have been renamed to use ``-`` instead of ``_`` as a separator (e.g., ``default_reset`` -> ``default-reset``). + + +**Migration Steps:** + +1. Replace all underscores in the ``--before`` and ``--after`` options with ``-`` in your scripts. + +.. only:: not esp8266 + + espsecure ``v5`` Migration Guide + ******************************** + + Command and Option Renaming + ########################### + + All the commands and options have been renamed to use ``-`` instead of ``_`` as a separator (e.g., ``sign_data`` -> ``sign-data``). + + Old command and option names are **deprecated**, meaning they will work for now with a warning, but will be removed in the next major release. + + This change affects most of the commands and the following options: ``--aes_xts``, ``--flash_crypt_conf``, ``--append_signatures``. + + **Migration Steps:** + + 1. Replace all underscores in command and option names with ``-`` in your scripts and CI pipelines. + + Public API Changes + ################## + + The public API of ``espsecure`` has been updated to provide a more consistent and user-friendly interface for programmatic use in custom scripts and applications. + + **Key Changes:** + + - All functions now accept individual parameters instead of relying on the ``args`` object from the argparse module. Affected functions are: + - ``digest_secure_bootloader`` + - ``generate_signing_key`` + - ``digest_secure_bootloader`` + - ``generate_signing_key`` + - ``sign_data`` including ``sign_secure_boot_v1`` and ``sign_secure_boot_v2`` + - ``verify_signature`` including ``verify_signature_v1`` and ``verify_signature_v2`` + - ``extract_public_key`` + - ``signature_info_v2`` + - ``digest_sbv2_public_key`` and ``digest_rsa_public_key`` + - ``digest_private_key`` + - ``generate_flash_encryption_key`` + - ``decrypt_flash_data`` + - ``encrypt_flash_data`` + - The ``main`` function parameter ``custom_commandline`` has been renamed to ``argv`` to unify the naming convention with esptool. + + **Migration Steps:** + + 1. Update function calls to pass individual parameters instead of the ``args`` object. For example: + ``sign_data(args)`` -> ``sign_data(data=args.data, key=args.key, ...)`` + or if you were mocking the args object, now you don't have to do that and you can pass parameters directly to the function like: + ``sign_data(data=data, key=key, ...)``. + 2. Replace the ``custom_commandline`` parameter with ``argv`` in the ``main`` function call. + + espefuse ``v5`` Migration Guide + ******************************* + + Reset Mode Renaming + ################### + + Choices for the ``--before`` option have been renamed to use ``-`` instead of ``_`` as a separator (e.g., ``default_reset`` -> ``default-reset``). + + **Migration Steps:** + + 1. Replace all underscores in the ``--before`` option with ``-`` in your scripts. + + Command and Option Renaming + ########################### + + All the commands and options have been renamed to use ``-`` instead of ``_`` as a separator (e.g., ``burn_custom_mac`` -> ``burn-custom-mac``). + + From options only ``--file_name`` has been renamed to ``--file-name``. + + Old command and option names are **deprecated**, meaning they will work for now with a warning, but will be removed in the next major release. + + **Migration Steps:** + + 1. Replace all underscores in the command names with ``-`` in your scripts. + + + ``--port`` Option is Required + ############################# + + The ``--port`` option is now required for all commands (except when using ``--virt``). Previously it was optional and defaulted to ``/dev/ttyUSB0``. + + **Migration Steps:** + + 1. Add the ``--port`` option to all your espefuse commands. + + + ``execute-scripts`` Command Removal + ################################### + + The ``execute-scripts`` command has been **removed in v5**. This command was used to execute custom eFuses scripts. It was deprecated in favor of using ``espefuse`` as a Python module (see :ref:`here `). + + **Migration Steps:** + + 1. Refactor any workflows using the deprecated ``execute-scripts`` to use the public API. + 2. Make sure to use the ``batch_mode`` argument for ``init_commands`` to avoid burning eFuses one by one. + 3. Variables ``idx`` and ``configfiles`` are no longer supported. These can be replaced with simple for loops in Python. + + For example, the following commands and script (using ESP32): + + .. code-block:: bash + + > espefuse --port /dev/ttyUSB0 execute_scripts efuse_script.py --do-not-confirm + + .. code-block:: python + + espefuse(esp, efuses, args, "burn_efuse JTAG_DISABLE 1 DISABLE_SDIO_HOST 1 CONSOLE_DEBUG_DISABLE 1") + espefuse(esp, efuses, args, "burn_key flash_encryption ../../images/efuse/256bit --no-protect-key") + espefuse(esp, efuses, args, "burn_key_digest ../../secure_images/rsa_secure_boot_signing_key.pem") + espefuse(esp, efuses, args, "burn_bit BLOCK3 64 66 69 72 78 82 83 90") + espefuse(esp, efuses, args, "burn_custom_mac AA:BB:CC:DD:EE:88") + + efuses.burn_all() + + espefuse(esp, efuses, args, "summary") + espefuse(esp, efuses, args, "adc_info") + espefuse(esp, efuses, args, "get_custom_mac") + + if not efuses["BLOCK1"].is_readable() or not efuses["BLOCK1"].is_writeable(): + raise Exception("BLOCK1 should be readable and writeable") + + Can be replaced with public API: + + .. code-block:: python + + from espefuse import init_commands + + with init_commands(port="/dev/ttyUSB0", batch_mode=True, do_not_confirm=True) as espefuse: + espefuse.burn_efuse({"JTAG_DISABLE": "1", "DISABLE_SDIO_HOST": "1", "CONSOLE_DEBUG_DISABLE": "1"}) + with open("../../images/efuse/256bit", "rb") as f: + espefuse.burn_key(["flash_encryption"], [f], no_protect_key=True) + with open("../../secure_images/rsa_secure_boot_signing_key.pem", "rb") as f: + espefuse.burn_key_digest([f]) + espefuse.burn_bit("BLOCK3", [64, 66, 69, 72, 78, 82, 83, 90]) + espefuse.burn_custom_mac(b"\xaa\xbb\xcc\xdd\xee\x88") + + espefuse.burn_all() + + espefuse.summary() + espefuse.adc_info() + espefuse.get_custom_mac() + + if not espefuse.efuses["BLOCK1"].is_readable() or not espefuse.efuses["BLOCK1"].is_writeable(): + raise Exception("BLOCK1 should be readable and writeable") + + .. note:: + + Please note that the ``batch_mode`` argument for ``init_commands`` is required to avoid burning eFuses one by one. This was previously + the default behavior for ``execute-scripts`` command. + + For more details on the public API, see :ref:`espefuse-scripting`. diff --git a/tools/esptool_py/docs/en/remote-serial-ports.rst b/tools/esptool_py/docs/en/remote-serial-ports.rst new file mode 100644 index 0000000000..d450f2481e --- /dev/null +++ b/tools/esptool_py/docs/en/remote-serial-ports.rst @@ -0,0 +1,66 @@ +Remote Serial Ports +=================== + +If you would like to connect to an Espressif SoC that is not directly connected to your system, you can use a remote serial port. This is useful when the chip is on a different machine, or for example when using WSL on Windows. + +It is possible to connect to any networked remote serial port that supports `RFC2217 `__ (Telnet) protocol. To do this, specify the serial port to esptool as ``rfc2217://:``. For example, to read information about your chip's SPI flash, run: + +:: + + esptool --port rfc2217://192.168.1.77:4000 flash-id + +Custom baud rates and DTR/RTS automatic resetting are supported over the RFC2217 protocol, the same as for a local serial port. + +.. _rfc2217_server: + +Pyserial Example Servers +------------------------ + +PySerial (which is a dependency of esptool) includes two RFC2217 example programs - `a single-port example `__ and a `multi-port example `__. +These example servers can run on any OS that supports pyserial, and are the simplest way to connect to an Espressif SoC over the network. + +There is an issue with `automatic resetting due to network latency `__. In order to work around this issue, a modified version of the single-port server example called ``esp_rfc2217_server`` is provided with esptool. + +On server: + +:: + + esp_rfc2217_server -p 4000 /dev/ttyUSB1 + +On client: + +:: + + esptool --port rfc2217://ADDRESS_OF_SERVER:4000?ign_set_control flash-id + + +Raw Sockets +----------- + +For servers or hardware network/serial adapters which don't support the full RFC2217, it is also possible to specify ``--port socket://:`` syntax for a simple "raw TCP socket" protocol. + +These raw sockets don't support setting the baud rate or automatic resetting into the bootloader. If using this mode, don't pass the ``--baud`` option to esptool. You need to set the baud rate manually on the server, and manually reset the chip into the bootloader mode (or use some other signalling/control method to tell the server to do so). + +Here's a very basic example using the common Linux/macOS command line "netcat" and "stty" commands: + +On server: + +:: + + stty -F /dev/ttyUSB1 230400 # set baud rate + nc -p 4000 -lk < /dev/ttyUSB1 > /dev/ttyUSB1 + +On client: + +:: + + esptool -p socket://localhost:4000 flash-id + +.. note:: + + Using RFC2217 is strongly recommended where possible. + +More Details +------------ + +All of the remote serial port support comes via pyserial. Read more `here `__. (Please keep in mind that the link points to documentation for the most recent pyserial version. You may have an older version.) diff --git a/tools/esptool_py/docs/en/resources.rst b/tools/esptool_py/docs/en/resources.rst index 13add7041e..ac6f325cbf 100644 --- a/tools/esptool_py/docs/en/resources.rst +++ b/tools/esptool_py/docs/en/resources.rst @@ -13,7 +13,7 @@ Useful Links * Several `books `_ have been written about the ESP8266 or ESP32 series of SoCs and they are listed on `Espressif `__ web site. -* If you're interested in contributing to esptool.py, please check the :ref:`contribute` page. +* If you're interested in contributing to esptool, please check the :ref:`contribute` page. * For additional {IDF_TARGET_NAME} product related information, please refer to the `documentation `_ section of `Espressif `__ web site. @@ -23,9 +23,9 @@ Webinars and Trainings Mastering the Basics of Espressif Chips: An In-Depth Look at Chip Flashing ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -The content of this webinar is designed for developers, engineers and hobbyists interested in getting a better understanding of how to use esptool.py or other tools for the development with the ESP8266 or ESP32 series of SoCs. +The content of this webinar is designed for developers, engineers and hobbyists interested in getting a better understanding of how to use esptool or other tools for the development with the ESP8266 or ESP32 series of SoCs. -It offers an in-depth look at the inner mechanisms of esptool.py, including the :ref:`boot-mode` process. +It offers an in-depth look at the inner mechanisms of esptool, including the :ref:`boot-mode` process. .. image:: https://img.youtube.com/vi/zh-Y_s4X6zs/maxresdefault.jpg :alt: Mastering the Basics of Espressif Chips: An In-Depth Look at Chip Flashing @@ -33,7 +33,7 @@ It offers an in-depth look at the inner mechanisms of esptool.py, including the DevCon22: esptool.py: Espressif's Swiss Army Knife ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -This talk aims to show how simple, yet powerful, esptool.py is, and how to use it to tame your ESP. +This talk aims to show how simple, yet powerful, esptool is, and how to use it to tame your ESP. .. image:: https://img.youtube.com/vi/GjWGKzu3XTk/maxresdefault.jpg :alt: DevCon22: esptool.py: Espressif's Swiss Army Knife diff --git a/tools/esptool_py/docs/en/troubleshooting.rst b/tools/esptool_py/docs/en/troubleshooting.rst index 5f6fbead0f..19276d9d2d 100644 --- a/tools/esptool_py/docs/en/troubleshooting.rst +++ b/tools/esptool_py/docs/en/troubleshooting.rst @@ -1,4 +1,4 @@ -{IDF_TARGET_BOOTLOADER_OFFSET:default="0x0", esp32="0x1000", esp32s2="0x1000", esp32p4="0x2000"} +{IDF_TARGET_BOOTLOADER_OFFSET:default="0x0", esp32="0x1000", esp32s2="0x1000", esp32p4="0x2000", esp32c5="0x2000"} .. _troubleshooting: @@ -31,12 +31,12 @@ Power stability problems may also cause this (see `Insufficient Power`_.) Writing to Flash Succeeds but Program Doesn't Run ------------------------------------------------- -If esptool can flash your module with ``write_flash`` but your program doesn't run, check the following: +If esptool can flash your module with ``write-flash`` but your program doesn't run, check the following: Wrong Flash Mode ^^^^^^^^^^^^^^^^ -Some devices only support the ``dio`` flash mode. Writing to flash with ``qio`` mode will succeed but the chip can't read the flash back to run - so nothing happens on boot. Try passing the ``-fm dio`` option to ``write_flash``. +Some devices only support the ``dio`` flash mode. Writing to flash with ``qio`` mode will succeed but the chip can't read the flash back to run - so nothing happens on boot. Try passing the ``-fm dio`` option to ``write-flash``. See the :ref:`spi-flash-modes` page for a full description of the flash modes and how to determine which ones are supported on your device. @@ -113,7 +113,7 @@ Early Stage Crash If the application accidentally reconfigures the USB peripheral pins or disables the USB peripheral, the device disappears from the system. You can also encounter unstable flashing or errors like ``OSError: [Errno 71] Protocol error``. - If that happens, try to :ref:`manually enter the download mode ` and then use the :ref:`erase_flash ` command to wipe the flash memory. Then, make sure to fix the issue in the application before flashing again. + If that happens, try to :ref:`manually enter the download mode ` and then use the :ref:`erase-flash ` command to wipe the flash memory. Then, make sure to fix the issue in the application before flashing again. On boards with two USB ports (usually marked as USB and UART), you can use the USB port for flashing while listening on the UART port for debugging purposes. This setup is useful for retrieving core dumps or the reset reason in the event of a crash. To implement this, connect the UART port to another instance of any of the `serial terminal programs`_, while repeating the failing action over the USB port. You'll be able to monitor the crash log without interference from the USB port used for communication or it disappearing due to a firmware crash. If your devkit doesn't have a dedicated USB port connected to an on-board USB-to-UART bridge, you can use a separate adapter to connect to the UART pins on the board. @@ -131,14 +131,14 @@ For exact serial port configuration values, see :ref:`serial-port-settings`. Tracing Esptool Interactions ---------------------------- -Running ``esptool.py --trace`` will dump all serial interactions to the standard output (this is *a lot* of output). This can be helpful when debugging issues with the serial connection, or when providing information for bug reports. +Running ``esptool --trace`` will dump all serial interactions to the standard output (this is *a lot* of output). This can be helpful when debugging issues with the serial connection, or when providing information for bug reports. See :ref:`the related Advanced Topics page ` for more information. Configuration File ------------------ -Although ``esptool.py`` has been tuned to work in the widest possible range of environments, an incompatible combination of hardware, OS, and drivers might cause it to fail. If you suspect this is the case, a custom configuration of internal variables might be necessary. +Although ``esptool`` has been tuned to work in the widest possible range of environments, an incompatible combination of hardware, OS, and drivers might cause it to fail. If you suspect this is the case, a custom configuration of internal variables might be necessary. These variables and options can be specified in a configuration file. See :ref:`the related Configuration File page ` for more information. @@ -190,16 +190,16 @@ Other things to try: .. list:: - * Try to sync and communicate at a much lower baud rate, e.g. ``esptool.py --baud 9600 ...``. - * Try `tracing the interactions `_ running ``esptool.py --trace ...`` and see if anything is received back at all. - * Try skipping chip autodetection by specifying the chip type, run ``esptool.py --chip {IDF_TARGET_NAME} ...``. + * Try to sync and communicate at a much lower baud rate, e.g. ``esptool --baud 9600 ...``. + * Try `tracing the interactions `_ running ``esptool --trace ...`` and see if anything is received back at all. + * Try skipping chip autodetection by specifying the chip type, run ``esptool --chip {IDF_TARGET_NAME} ...``. If none of the above mentioned fixes help and your problem persists, please `open a new issue `_. A serial exception error occurred ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -``esptool.py`` uses the `pySerial `_ Python module for accessing the serial port. +``esptool`` uses the `pySerial `_ Python module for accessing the serial port. If pySerial cannot operate normally, it raises an error and terminates. An example of a pySerial error: @@ -208,7 +208,7 @@ An example of a pySerial error: A serial exception error occurred: read failed: [Errno 6] Device not configured -Errors originating from pySerial are, therefore, not a problem with ``esptool.py``, but are usually caused by a problem with hardware or drivers. +Errors originating from pySerial are, therefore, not a problem with ``esptool``, but are usually caused by a problem with hardware or drivers. Some of the most common pySerial error causes are: diff --git a/tools/esptool_py/docs/en/versions.rst b/tools/esptool_py/docs/en/versions.rst index 648701e066..a0c385fde8 100644 --- a/tools/esptool_py/docs/en/versions.rst +++ b/tools/esptool_py/docs/en/versions.rst @@ -3,7 +3,7 @@ Versions ======== -Starting from ``v4.0.0``, ``esptool.py`` adopts the `semantic versioning specification `_, following the ``MAJOR.MINOR.PATCH`` version number. +Starting from ``v4.0.0``, ``esptool`` adopts the `semantic versioning specification `_, following the ``MAJOR.MINOR.PATCH`` version number. Major release ``v4`` is under active development, receiving new features and bugfixes, while ``v3`` only keeps receiving important bugfixes. @@ -11,38 +11,38 @@ There are no support periods defined and bugfixes are not planned, therefore it .. note:: - The following information is directed mainly towards package maintainers. Regular users should always use the most recent version of ``esptool.py`` to benefit from the latest features and bugfixes. + The following information is directed mainly towards package maintainers. Regular users should always use the most recent version of ``esptool`` to benefit from the latest features and bugfixes. -Use the latest esptool (recommended) +Use the Latest Esptool (Recommended) ------------------------------------ -If your use case doesn't impose any constraints on ``esptool.py``, the latest release should be always used. +If your use case doesn't impose any constraints on ``esptool``, the latest release should be always used. To see the latest available version and its release notes, visit the `release page on GitHub `_. To get the latest possible version, simply define your dependency as ``esptool`` (without any release operator and a version identifier). -Use the latest bugfix release of a minor esptool release +Use the Latest Bugfix Release of a Minor Esptool Release -------------------------------------------------------- -Some use cases might require a specific ``esptool.py`` version without getting new features, but with automatic bugfixes. +Some use cases might require a specific ``esptool`` version without getting new features, but with automatic bugfixes. This can be achieved by defining your dependency as ``esptool~=4.0.1`` (explicitly stating the ``MAJOR``, ``MINOR``, and ``PATCH`` numbers). -This notation selects the latest version of ``esptool.py``, greater than or equal to ``v4.0.1``, but still in the ``v4.0.*`` version (this compatible release clause is approximately equivalent to the pair of comparison clauses ``>= 4.0.1``, ``== 4.0.*``). +This notation selects the latest version of ``esptool``, greater than or equal to ``v4.0.1``, but still in the ``v4.0.*`` version (this compatible release clause is approximately equivalent to the pair of comparison clauses ``>= 4.0.1``, ``== 4.0.*``). So, for example, ``v4.1.0`` won't be downloaded. More information about compatible release clauses `can be found here `_. -Use the latest esptool without any future breaking change +Use the Latest Esptool Without Any Future Breaking Change --------------------------------------------------------- If you also want to get new features (instead of just bugfixes), define your version requirement as ``esptool~=4.0`` (explicitly stating only the ``MAJOR`` and ``MINOR`` numbers). This way the latest minor versions (``>= 4.0``, ``== 4.*``) are automatically installed. -Backward-compatibility is still ensured, because ``esptool.py`` respects the semantic versioning specification (which states that breaking changes should occur only in ``MAJOR`` versions). +Backward-compatibility is still ensured, because ``esptool`` respects the semantic versioning specification (which states that breaking changes should occur only in ``MAJOR`` versions). -Use the previous major esptool release (only if you cannot upgrade) +Use the Previous Major Esptool Release (Only if You Cannot Upgrade) ------------------------------------------------------------------- -If your use case is not compatible with the latest ``MAJOR`` release of ``esptool.py``, a previous compatible version has to be specified. +If your use case is not compatible with the latest ``MAJOR`` release of ``esptool``, a previous compatible version has to be specified. This can be achieved by defining your dependency as ``esptool~=3.0`` (explicitly stating your desired ``MAJOR`` number and at least also the ``MINOR`` number, ``PATCH`` can also be specified). -Use a specific esptool release +Use a Specific Esptool Release ------------------------------ If a very specific release is required, define your dependency as ``esptool==4.1.2``. This specific version will be used and no new features or bugfixes will be automatically installed. diff --git a/tools/esptool_py/docs/requirements.txt b/tools/esptool_py/docs/requirements.txt deleted file mode 100644 index 948dda348e..0000000000 --- a/tools/esptool_py/docs/requirements.txt +++ /dev/null @@ -1 +0,0 @@ -esp-docs~=1.5 diff --git a/tools/esptool_py/esp_rfc2217_server.py b/tools/esptool_py/esp_rfc2217_server.py old mode 100755 new mode 100644 index 4d97247592..b03a684951 --- a/tools/esptool_py/esp_rfc2217_server.py +++ b/tools/esptool_py/esp_rfc2217_server.py @@ -26,7 +26,7 @@ # Esptool can connect to the ESP device through that server as it is # demonstrated in the following example: # -# esptool.py --port rfc2217://localhost:4000?ign_set_control flash_id +# esptool --port rfc2217://localhost:4000?ign_set_control flash-id # import contextlib diff --git a/tools/esptool_py/esp_rfc2217_server/__init__.py b/tools/esptool_py/esp_rfc2217_server/__init__.py index 4c489ec284..c5bc3a697f 100644 --- a/tools/esptool_py/esp_rfc2217_server/__init__.py +++ b/tools/esptool_py/esp_rfc2217_server/__init__.py @@ -18,9 +18,11 @@ import serial from esp_rfc2217_server.redirector import Redirector +from esptool.util import check_deprecated_py_suffix def main(): + check_deprecated_py_suffix("esp_rfc2217_server") import argparse parser = argparse.ArgumentParser( @@ -64,8 +66,7 @@ def main(): level = (logging.WARNING, logging.INFO, logging.DEBUG, logging.NOTSET)[ args.verbosity ] - logging.basicConfig(level=logging.INFO) - # logging.getLogger('root').setLevel(logging.INFO) + logging.basicConfig(format="%(levelname)s: %(message)s", level=logging.INFO) logging.getLogger("rfc2217").setLevel(level) # connect to serial port @@ -75,26 +76,45 @@ def main(): ser.dtr = False ser.rts = False - logging.info(" RFC 2217 TCP/IP to Serial redirector - type Ctrl-C / BREAK to quit") + logging.info("RFC 2217 TCP/IP to Serial redirector - type Ctrl-C / BREAK to quit") try: ser.open() except serial.SerialException as e: - logging.error(" Could not open serial port {}: {}".format(ser.name, e)) + logging.error(f"Could not open serial port {ser.name}: {e}") sys.exit(1) - logging.info(" Serving serial port: {}".format(ser.name)) + logging.info(f"Serving serial port: {ser.name}") settings = ser.get_settings() srv = socket.socket(socket.AF_INET, socket.SOCK_STREAM) srv.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) srv.bind(("", args.localport)) srv.listen(1) - logging.info(" TCP/IP port: {}".format(args.localport)) + logging.info(f"TCP/IP port: {args.localport}") + + host_ip = socket.gethostbyname(socket.gethostname()) + wait_msg = ( + "Waiting for connection ... use the 'rfc2217://" + f"{host_ip}:{args.localport}?ign_set_control' as a PORT" + ) + logging.info(wait_msg) + while True: + srv.settimeout(5) + client_socket = None + try: + while client_socket is None: + try: + client_socket, addr = srv.accept() + except TimeoutError: + print(".", end="", flush=True) + except KeyboardInterrupt: + print("") # resetting inline print + logging.info("Exited with keyboard interrupt") + break try: - client_socket, addr = srv.accept() - logging.info("Connected by {}:{}".format(addr[0], addr[1])) + logging.info(f"Connected by {addr[0]}:{addr[1]}") client_socket.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) ser.rts = True ser.dtr = True @@ -112,7 +132,7 @@ def main(): # capable client) ser.apply_settings(settings) except KeyboardInterrupt: - sys.stdout.write("\n") + print(flush=True) break except socket.error as msg: logging.error(str(msg)) diff --git a/tools/esptool_py/esp_rfc2217_server/esp_port_manager.py b/tools/esptool_py/esp_rfc2217_server/esp_port_manager.py index 29f1046384..b5614af6f4 100644 --- a/tools/esptool_py/esp_rfc2217_server/esp_port_manager.py +++ b/tools/esptool_py/esp_rfc2217_server/esp_port_manager.py @@ -74,11 +74,15 @@ def _hard_reset_thread(self): """ if self.logger: self.logger.info("Activating hard reset in thread") - HardReset(self.serial)() + cfg_custom_hard_reset_sequence = cfg.get("custom_hard_reset_sequence") + if cfg_custom_hard_reset_sequence is not None: + CustomReset(self.serial, cfg_custom_hard_reset_sequence)() + else: + HardReset(self.serial)() def _reset_thread(self): """ - The reset logic is used from esptool.py because the RTS and DTR signals + The reset logic is used from esptool because the RTS and DTR signals cannot be retransmitted through RFC 2217 with proper timing. """ if self.logger: diff --git a/tools/esptool_py/espefuse/__init__.py b/tools/esptool_py/espefuse/__init__.py index 518e96566e..31e8998a2f 100755 --- a/tools/esptool_py/espefuse/__init__.py +++ b/tools/esptool_py/espefuse/__init__.py @@ -1,365 +1,231 @@ -# SPDX-FileCopyrightText: 2016-2022 Espressif Systems (Shanghai) CO LTD +# SPDX-FileCopyrightText: 2016-2025 Espressif Systems (Shanghai) CO LTD # # SPDX-License-Identifier: GPL-2.0-or-later -# PYTHON_ARGCOMPLETE_OK -import argparse -import os import sys -from collections import namedtuple -from io import StringIO -import espefuse.efuse.esp32 as esp32_efuse -import espefuse.efuse.esp32c2 as esp32c2_efuse -import espefuse.efuse.esp32c3 as esp32c3_efuse -import espefuse.efuse.esp32c5 as esp32c5_efuse -import espefuse.efuse.esp32c5beta3 as esp32c5beta3_efuse -import espefuse.efuse.esp32c6 as esp32c6_efuse -import espefuse.efuse.esp32c61 as esp32c61_efuse -import espefuse.efuse.esp32h2 as esp32h2_efuse -import espefuse.efuse.esp32h2beta1 as esp32h2beta1_efuse -import espefuse.efuse.esp32p4 as esp32p4_efuse -import espefuse.efuse.esp32s2 as esp32s2_efuse -import espefuse.efuse.esp32s3 as esp32s3_efuse -import espefuse.efuse.esp32s3beta2 as esp32s3beta2_efuse +import rich_click as click import esptool - -DefChip = namedtuple("DefChip", ["chip_name", "efuse_lib", "chip_class"]) - -SUPPORTED_BURN_COMMANDS = [ - "read_protect_efuse", - "write_protect_efuse", - "burn_efuse", - "burn_block_data", - "burn_bit", - "burn_key", - "burn_key_digest", - "burn_custom_mac", - "set_flash_voltage", - "execute_scripts", +from esptool.cli_util import ChipType, ResetModeType +from esptool.logger import log + +from espefuse.cli_util import Group +from espefuse.efuse.base_operations import BaseCommands +from espefuse.efuse_interface import ( + DEPRECATED_COMMANDS, + get_esp, + init_commands, + SUPPORTED_COMMANDS, + SUPPORTED_BURN_COMMANDS, + SUPPORTED_READ_COMMANDS, + SUPPORTED_CHIPS, +) +from esptool.util import check_deprecated_py_suffix + +__all__ = [ + "get_esp", + "init_commands", + "BaseCommands", + "SUPPORTED_COMMANDS", + "SUPPORTED_CHIPS", + "SUPPORTED_BURN_COMMANDS", + "SUPPORTED_READ_COMMANDS", ] -SUPPORTED_READ_COMMANDS = [ - "summary", - "dump", - "get_custom_mac", - "adc_info", - "check_error", -] -SUPPORTED_COMMANDS = SUPPORTED_READ_COMMANDS + SUPPORTED_BURN_COMMANDS - -SUPPORTED_CHIPS = { - "esp32": DefChip("ESP32", esp32_efuse, esptool.targets.ESP32ROM), - "esp32c2": DefChip("ESP32-C2", esp32c2_efuse, esptool.targets.ESP32C2ROM), - "esp32c3": DefChip("ESP32-C3", esp32c3_efuse, esptool.targets.ESP32C3ROM), - "esp32c6": DefChip("ESP32-C6", esp32c6_efuse, esptool.targets.ESP32C6ROM), - "esp32c61": DefChip("ESP32-C61", esp32c61_efuse, esptool.targets.ESP32C61ROM), - "esp32c5": DefChip("ESP32-C5", esp32c5_efuse, esptool.targets.ESP32C5ROM), - "esp32c5beta3": DefChip( - "ESP32-C5(beta3)", esp32c5beta3_efuse, esptool.targets.ESP32C5BETA3ROM - ), - "esp32h2": DefChip("ESP32-H2", esp32h2_efuse, esptool.targets.ESP32H2ROM), - "esp32p4": DefChip("ESP32-P4", esp32p4_efuse, esptool.targets.ESP32P4ROM), - "esp32h2beta1": DefChip( - "ESP32-H2(beta1)", esp32h2beta1_efuse, esptool.targets.ESP32H2BETA1ROM +@click.group( + cls=Group, + chain=True, # allow using multiple commands in a single run + no_args_is_help=True, + context_settings=dict(help_option_names=["-h", "--help"], max_content_width=120), + help=f"espefuse v{esptool.__version__} - " + "Utility for eFuse configuration in Espressif SoCs.", +) +@click.option( + "--chip", + "-c", + type=ChipType(choices=["auto"] + list(SUPPORTED_CHIPS.keys())), + default="auto", + envvar="ESPTOOL_CHIP", + help="Target chip type.", +) +@click.option( + "--baud", + "-b", + type=int, + default=esptool.ESPLoader.ESP_ROM_BAUD, + envvar="ESPTOOL_BAUD", + help="Serial port baud rate used when flashing/reading.", +) +@click.option( + "--port", + "-p", + envvar="ESPTOOL_PORT", + type=click.Path(), + help="Serial port device.", +) +@click.option( + "--before", + type=ResetModeType( + choices=["default-reset", "usb-reset", "no-reset", "no-reset-no-sync"] ), - "esp32s2": DefChip("ESP32-S2", esp32s2_efuse, esptool.targets.ESP32S2ROM), - "esp32s3": DefChip("ESP32-S3", esp32s3_efuse, esptool.targets.ESP32S3ROM), - "esp32s3beta2": DefChip( - "ESP32-S3(beta2)", esp32s3beta2_efuse, esptool.targets.ESP32S3BETA2ROM - ), -} - - -def get_esp( - port, + default="default-reset", + help="Which reset to perform before connecting to the chip.", +) +@click.option( + "--debug", "-d", is_flag=True, help="Show debugging information (loglevel=DEBUG)." +) +@click.option( + "--virt", + is_flag=True, + help="For host tests, work in virtual mode (no chip connection).", +) +@click.option( + "--path-efuse-file", + type=click.Path(), + help="For host tests, save eFuse memory to file.", +) +@click.option( + "--do-not-confirm", + is_flag=True, + help="Do not pause for confirmation before permanently writing eFuses. " + "Use with caution!", +) +@click.option( + "--postpone", + is_flag=True, + help="Postpone burning some eFuses from BLOCK0 at the end.", +) +@click.option( + "--extend-efuse-table", + type=click.File("r"), + help="CSV file from ESP-IDF (esp_efuse_custom_table.csv).", +) +@click.pass_context +def cli( + ctx, + chip, baud, - connect_mode, - chip="auto", - skip_connect=False, - virt=False, - debug=False, - virt_efuse_file=None, -): - if chip not in ["auto"] + list(SUPPORTED_CHIPS.keys()): - raise esptool.FatalError("get_esp: Unsupported chip (%s)" % chip) - if virt: - efuse = SUPPORTED_CHIPS.get(chip, SUPPORTED_CHIPS["esp32"]).efuse_lib - esp = efuse.EmulateEfuseController(virt_efuse_file, debug) - else: - if chip == "auto" and not skip_connect: - esp = esptool.cmds.detect_chip(port, baud, connect_mode) - else: - esp = SUPPORTED_CHIPS.get(chip, SUPPORTED_CHIPS["esp32"]).chip_class( - port if not skip_connect else StringIO(), baud - ) - if not skip_connect: - esp.connect(connect_mode) - if esp.sync_stub_detected: - esp = esp.STUB_CLASS(esp) - return esp - - -def get_efuses( - esp, - skip_connect=False, - debug_mode=False, - do_not_confirm=False, - extend_efuse_table=None, + port, + before, + debug, + virt, + path_efuse_file, + do_not_confirm, + postpone, + extend_efuse_table, ): - for name in SUPPORTED_CHIPS: - if SUPPORTED_CHIPS[name].chip_name == esp.CHIP_NAME: - efuse = SUPPORTED_CHIPS[name].efuse_lib - return ( - efuse.EspEfuses( - esp, skip_connect, debug_mode, do_not_confirm, extend_efuse_table - ), - efuse.operations, - ) - else: - raise esptool.FatalError("get_efuses: Unsupported chip (%s)" % esp.CHIP_NAME) - - -def split_on_groups(all_args): - """ - This function splits the all_args list into groups, - where each item is a cmd with all its args. - - Example: - all_args: - ['burn_key_digest', 'secure_images/ecdsa256_secure_boot_signing_key_v2.pem', - 'burn_key', 'BLOCK_KEY0', 'images/efuse/128bit_key', - 'XTS_AES_128_KEY_DERIVED_FROM_128_EFUSE_BITS'] - - used_cmds: ['burn_key_digest', 'burn_key'] - groups: - [['burn_key_digest', 'secure_images/ecdsa256_secure_boot_signing_key_v2.pem'], - ['burn_key', 'BLOCK_KEY0', 'images/efuse/128bit_key', - 'XTS_AES_128_KEY_DERIVED_FROM_128_EFUSE_BITS']] - """ - - groups = [] - cmd = [] - used_cmds = [] - for item in all_args: - if item in SUPPORTED_COMMANDS: - used_cmds.append(item) - if cmd != []: - groups.append(cmd) - cmd = [] - cmd.append(item) - if cmd: - groups.append(cmd) - return groups, used_cmds - - -def main(custom_commandline=None, esp=None): - """ - Main function for espefuse - - custom_commandline - Optional override for default arguments parsing - (that uses sys.argv), can be a list of custom arguments as strings. - Arguments and their values need to be added as individual items to the list - e.g. "--port /dev/ttyUSB1" thus becomes ['--port', '/dev/ttyUSB1']. - - esp - Optional override of the connected device previously - returned by esptool.get_default_connected_device() - """ + log.print(f"espefuse v{esptool.__version__}") + ctx.ensure_object(dict) + esp = ctx.obj.get("esp", None) external_esp = esp is not None + is_help = ctx.obj.get("is_help", False) + used_cmds = ctx.obj.get("used_cmds", []) - init_parser = argparse.ArgumentParser( - description="espefuse.py v%s - [ESP32xx] efuse get/set tool" - % esptool.__version__, - prog="espefuse", - add_help=False, - ) - - init_parser.add_argument( - "--chip", - "-c", - help="Target chip type", - choices=["auto"] + list(SUPPORTED_CHIPS.keys()), - default=os.environ.get("ESPTOOL_CHIP", "auto"), - ) - - init_parser.add_argument( - "--baud", - "-b", - help="Serial port baud rate used when flashing/reading", - type=esptool.arg_auto_int, - default=os.environ.get("ESPTOOL_BAUD", esptool.loader.ESPLoader.ESP_ROM_BAUD), - ) + if any(cmd.replace("_", "-") in DEPRECATED_COMMANDS for cmd in used_cmds): + return # do not connect to ESP if any command is deprecated - init_parser.add_argument( - "--port", - "-p", - help="Serial port device", - default=os.environ.get("ESPTOOL_PORT", esptool.loader.ESPLoader.DEFAULT_PORT), - ) - - init_parser.add_argument( - "--before", - help="What to do before connecting to the chip", - choices=["default_reset", "usb_reset", "no_reset", "no_reset_no_sync"], - default="default_reset", - ) + if not port and not external_esp and not is_help and not virt: + raise click.BadOptionUsage( + "--port", "Missing required argument. Please specify the --port option." + ) - init_parser.add_argument( - "--debug", - "-d", - help="Show debugging information (loglevel=DEBUG)", - action="store_true", - ) - init_parser.add_argument( - "--virt", - help="For host tests, the tool will work in the virtual mode " - "(without connecting to a chip).", - action="store_true", - ) - init_parser.add_argument( - "--path-efuse-file", - help="For host tests, saves efuse memory to file.", - type=str, - default=None, - ) - init_parser.add_argument( - "--do-not-confirm", - help="Do not pause for confirmation before permanently writing efuses. " - "Use with caution.", - action="store_true", - ) - init_parser.add_argument( - "--postpone", - help="Postpone burning some efuses from BLOCK0 at the end, " - "(efuses which disable access to blocks or chip).", - action="store_true", - ) - init_parser.add_argument( - "--extend-efuse-table", - help="CSV file from ESP-IDF (esp_efuse_custom_table.csv)", - type=argparse.FileType("r"), - default=None, - ) - - common_args, remaining_args = init_parser.parse_known_args(custom_commandline) - debug_mode = common_args.debug - just_print_help = [ - True for arg in remaining_args if arg in ["--help", "-h"] - ] or remaining_args == [] - - print("espefuse.py v{}".format(esptool.__version__)) - - if not external_esp: + if not esp: try: esp = get_esp( - common_args.port, - common_args.baud, - common_args.before, - common_args.chip, - just_print_help, - common_args.virt, - common_args.debug, - common_args.path_efuse_file, + port, baud, before, chip, is_help, virt, debug, path_efuse_file ) except esptool.FatalError as e: raise esptool.FatalError( - f"{e}\nPlease make sure that you have specified " - "the right port with the --port argument" + f"{e}\nPlease make sure you specified the right port with --port." ) - # TODO: Require the --port argument in the next major release, ESPTOOL-490 - - efuses, efuse_operations = get_efuses( - esp, - just_print_help, - debug_mode, - common_args.do_not_confirm, - common_args.extend_efuse_table, - ) - - parser = argparse.ArgumentParser(parents=[init_parser]) - subparsers = parser.add_subparsers( - dest="operation", help="Run espefuse.py {command} -h for additional help" - ) - - efuse_operations.add_commands(subparsers, efuses) - # Enable argcomplete only on Unix-like systems - if sys.platform != "win32": - try: - import argcomplete + def close_port(): + if not external_esp and not virt and esp._port: + esp._port.close() - argcomplete.autocomplete(parser) - except ImportError: - pass + ctx.call_on_close(close_port) - grouped_remaining_args, used_cmds = split_on_groups(remaining_args) - if len(grouped_remaining_args) == 0: - parser.print_help() - parser.exit(1) - there_are_multiple_burn_commands_in_args = ( - sum(cmd in SUPPORTED_BURN_COMMANDS for cmd in used_cmds) > 1 + # handle chip auto + if chip == "auto": + if ctx.obj.get("is_help", False): + log.note( + "Chip not specified, showing commands for ESP32 by default. " + "Specify the --chip option to get chip-specific help." + ) + chip = esp.CHIP_NAME.lower() + + commands = init_commands( + esp=esp, + skip_connect=is_help, + debug=debug, + do_not_confirm=do_not_confirm, + extend_efuse_table=extend_efuse_table, ) - if there_are_multiple_burn_commands_in_args: - efuses.batch_mode_cnt += 1 + commands.efuses.postpone = postpone + commands.add_cli_commands(cli) - efuses.postpone = common_args.postpone - - try: - for rem_args in grouped_remaining_args: - args, unused_args = parser.parse_known_args(rem_args, namespace=common_args) - if args.operation is None: - parser.print_help() - parser.exit(1) - assert ( - len(unused_args) == 0 - ), 'Not all commands were recognized "{}"'.format(unused_args) - - operation_func = vars(efuse_operations)[args.operation] - # each 'operation' is a module-level function of the same name - print('\n=== Run "{}" command ==='.format(args.operation)) + multiple_burn_commands = ( + sum(cmd.replace("_", "-") in SUPPORTED_BURN_COMMANDS for cmd in used_cmds) > 1 + ) + if multiple_burn_commands: + commands.use_batch_mode() + + # Add the objects to the context + ctx.obj["debug"] = debug + ctx.obj["commands"] = commands + ctx.obj["efuses"] = commands.efuses + ctx.obj["do_not_confirm"] = do_not_confirm + + @cli.result_callback() + def process_result(result, *args, **kwargs): + if multiple_burn_commands: + if not commands.burn_all(check_batch_mode=True): + raise esptool.FatalError("BURN was not done.") + log.print("Successful.") + + +@cli.command("execute-scripts", hidden=True) +@click.argument("scripts", nargs=-1, type=click.UNPROCESSED) +@click.option("--index", type=click.UNPROCESSED) +@click.option("--configfiles", type=click.UNPROCESSED) +def execute_scripts_cli(scripts, index, configfiles): + """REMOVED: See Migration guide in documentation for details.""" + log.error( + "REMOVED: `execute_scripts` was replaced with the public API in v5. " + "Please see Migration Guide in documentation for details: " + "https://docs.espressif.com/projects/esptool/en/latest/migration-guide.html#espefuse-py-v5-migration-guide" + ) + sys.exit(2) - if hasattr(args, "show_sensitive_info"): - if args.show_sensitive_info or args.debug: - args.show_sensitive_info = True - else: - print("Sensitive data will be hidden (see --show-sensitive-info)") - operation_func(esp, efuses, args) +def main(argv: list[str] | None = None, esp: esptool.ESPLoader | None = None): + """ + Main function for espefuse - if there_are_multiple_burn_commands_in_args: - efuses.batch_mode_cnt -= 1 - if not efuses.burn_all(check_batch_mode=True): - raise esptool.FatalError("BURN was not done") - print("Successful") + argv - Optional override for default arguments parsing + (that uses sys.argv), can be a list of custom arguments as strings. + Arguments and their values need to be added as individual items to the list + e.g. "--port /dev/ttyUSB1" thus becomes ['--port', '/dev/ttyUSB1']. - if ( - sum(cmd in SUPPORTED_BURN_COMMANDS for cmd in used_cmds) > 0 - and sum(cmd in SUPPORTED_READ_COMMANDS for cmd in used_cmds) > 0 - ): - # [burn_cmd1] [burn_cmd2] [read_cmd1] [burn_cmd3] [read_cmd2] - print("\n=== Run read commands after burn commands ===") - for rem_args in grouped_remaining_args: - args, unused_args = parser.parse_known_args( - rem_args, namespace=common_args - ) - current_cmd = args.operation - if current_cmd in SUPPORTED_READ_COMMANDS: - print(f"\n=== Run {args.operation} command ===") - operation_func = vars(efuse_operations)[current_cmd] - operation_func(esp, efuses, args) - finally: - if not external_esp and not common_args.virt and esp._port: - esp._port.close() + esp - Optional override of the connected device previously + returned by esptool.get_default_connected_device() + """ + args = esptool.expand_file_arguments(argv or sys.argv[1:]) + cli(args=args, esp=esp) def _main(): + check_deprecated_py_suffix(__name__) try: main() except esptool.FatalError as e: - print("\nA fatal error occurred: %s" % e) + log.error(f"\nA fatal error occurred: {e}") + sys.exit(2) + except KeyboardInterrupt: + log.error("KeyboardInterrupt: Run cancelled by user.") sys.exit(2) diff --git a/tools/esptool_py/espefuse/cli_util.py b/tools/esptool_py/espefuse/cli_util.py new file mode 100644 index 0000000000..e2ee6d97f0 --- /dev/null +++ b/tools/esptool_py/espefuse/cli_util.py @@ -0,0 +1,246 @@ +# SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD +# +# SPDX-License-Identifier: GPL-2.0-or-later + +from typing import Any + +import rich_click as click +from click.parser import OptionParser, ParsingState, _unpack_args +from esptool.cli_util import Group as EsptoolGroup +from esptool.logger import log + +from espefuse.efuse_interface import ( + DEPRECATED_COMMANDS, + init_commands, + SUPPORTED_BURN_COMMANDS, + SUPPORTED_READ_COMMANDS, + SUPPORTED_COMMANDS, +) + + +click.rich_click.USE_CLICK_SHORT_HELP = True +click.rich_click.COMMAND_GROUPS = { + "*": [ + { + "name": "Burn commands", + "commands": SUPPORTED_BURN_COMMANDS, + }, + { + "name": "Read commands", + "commands": SUPPORTED_READ_COMMANDS, + }, + ] +} + + +class ChainParser(OptionParser): + """ + This is a modified version of the OptionParser class from click.parser. + It allows for the processing of arguments and options in interspersed order + together with chaining commands. + """ + + def _process_args_for_options(self, state: ParsingState) -> None: + while state.rargs: + arg = state.rargs.pop(0) + arglen = len(arg) + # Double dashes always handled explicitly regardless of what + # prefixes are valid. + if arg == "--": + return + # if the argument is a command, stop parsing options + elif arg.replace("_", "-") in SUPPORTED_COMMANDS: + state.largs.append(arg) + return + elif arg[:1] in self._opt_prefixes and arglen > 1: + self._process_opts(arg, state) + elif self.allow_interspersed_args: + state.largs.append(arg) + else: + state.rargs.insert(0, arg) + return + + def _process_args_for_args(self, state: ParsingState) -> None: + pargs, args = _unpack_args( + state.largs + state.rargs, [x.nargs for x in self._args] + ) + + # This check is required because of the way we modify nargs in ChainingCommand + if len(pargs) > 0: + for idx, arg in enumerate(self._args): + arg.process(pargs[idx], state) + + state.largs = args + state.rargs = [] + + +class EfuseContext(click.RichContext): + @property + def show_sensitive_info(self) -> bool: + self.ensure_object(dict) + value: bool = self.obj.get("show_sensitive_info", False) + if not value: + log.print("Sensitive data will be hidden (see --show-sensitive-info)") + return value + + +class ChainingCommand(click.RichCommand, click.Command): + context_class = EfuseContext + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + def _is_option(self, arg: str) -> bool: + return arg.startswith("--") or arg.startswith("-") + + def invoke(self, ctx: click.Context) -> Any: + log.print(f'\n=== Run "{self.name}" command ===') + return super().invoke(ctx) + + def parse_args(self, ctx: click.Context, args: list[str]): + # This is a hack to set nargs of the last argument to the number of arguments + # that will be processed separately + param_changed = None + for idx, arg in enumerate(args): + # command found in args or option found after argument + if arg.replace("_", "-") in SUPPORTED_COMMANDS or ( + self._is_option(arg) and idx > 0 + ): + arguments_count = sum( + isinstance(param, click.Argument) for param in self.params + ) + for param in self.params: + if param.nargs != -1: + continue + # set nargs of parameter to actual count of arguments and deduct + # arguments_count as each argument will be processed separately, + # we only care about the last one with nargs=-1 + # at the end we add 1 to account for the processedargument itself + # e.g. if we have burn-bit BLOCK2 1 2 3, we want to set nargs to 3, + # so we need to account for BLOCK2 being processed separately + param.nargs = args.index(arg) - arguments_count + 1 + param_changed = param + if ( + param.nargs == 0 + and param.required + and not ctx.resilient_parsing + ): + raise click.UsageError( + f"Command `{self.name}` requires the `{param.name}` " + "argument." + ) + break + break + ret = super().parse_args(ctx, args) + # restore nargs of the last argument to -1, in case it is going to be used again + if param_changed is not None: + param.nargs = -1 + return ret + + def make_parser(self, ctx: click.Context) -> OptionParser: + """Creates the underlying option parser for this command.""" + parser = ChainParser(ctx) + parser.allow_interspersed_args = True + for param in self.get_params(ctx): + param.add_to_parser(parser, ctx) + return parser + + +class Group(EsptoolGroup): + DEPRECATED_OPTIONS = { + "--file_name": "--file-name", + } + + command_class = ChainingCommand + context_class = EfuseContext + + @staticmethod + def _split_to_groups(args: list[str]) -> tuple[list[list[str]], list[str]]: + """ + This function splits the args list into groups, + where each item is a cmd with all its args. + + Example: + all_args: + ['burn-key-digest', 'secure_images/ecdsa256_secure_boot_signing_key_v2.pem', + 'burn-key', 'BLOCK_KEY0', 'images/efuse/128bit_key', + 'XTS_AES_128_KEY_DERIVED_FROM_128_EFUSE_BITS'] + + used_cmds: ['burn-key-digest', 'burn-key'] + groups: + [['burn-key-digest', 'secure_images/ecdsa256_secure_boot_signing_key_v2.pem'], + ['burn-key', 'BLOCK_KEY0', 'images/efuse/128bit_key', + 'XTS_AES_128_KEY_DERIVED_FROM_128_EFUSE_BITS']] + """ + groups: list[list[str]] = [] + args_group: list[str] = [] + used_cmds: list[str] = [] + for arg in args: + if arg.replace("_", "-") in SUPPORTED_COMMANDS: + groups.append(args_group) + used_cmds.append(arg) + args_group = [arg] + else: + args_group.append(arg) + groups.append(args_group) + return groups, used_cmds + + @staticmethod + def repeat_read_commands( + used_cmds: list[str], groups: list[list[str]] + ) -> list[list[str]]: + if ( + sum(cmd in SUPPORTED_BURN_COMMANDS for cmd in used_cmds) > 0 + and sum(cmd in SUPPORTED_READ_COMMANDS for cmd in used_cmds) > 0 + ): + # append all read commands at the end of group + read_commands = [] + for group in groups: + if group[0] in SUPPORTED_READ_COMMANDS: + read_commands.append(group) + groups.extend(read_commands) + return groups + + def parse_args(self, ctx: click.Context, args: list[str]): + ctx.ensure_object(dict) + ctx.obj["is_help"] = any(help_arg in args for help_arg in ctx.help_option_names) + idx = ( + args.index("--chip") + if "--chip" in args + else (args.index("-c") if "-c" in args else -1) + ) + ctx.obj["chip"] = args[idx + 1] if idx != -1 and idx + 1 < len(args) else "auto" + # override the default behavior of EsptoolGroup, because we don't need + # support for parameters with nargs=-1 + args = self._replace_deprecated_args(args) + cmd_groups, used_cmds = self._split_to_groups(args) + + # Add commands for shell completion + if ctx.resilient_parsing: + commands = init_commands(port=None, chip=ctx.obj["chip"], skip_connect=True) + commands.add_cli_commands(self) + elif len(used_cmds) == 0: + self.get_help(ctx) + ctx.exit() + + cmd_groups = self.repeat_read_commands(used_cmds, cmd_groups) + args = [arg for group in cmd_groups for arg in group] + + ctx.obj["used_cmds"] = used_cmds + ctx.obj["args"] = args + return super(click.RichGroup, self).parse_args(ctx, args) + + def get_help(self, ctx: click.Context) -> str: + # help was called without any commands, so we need to add the commands for the + # default chip + if not (set(self.list_commands(ctx)) - set(DEPRECATED_COMMANDS)): + chip = ctx.obj["chip"] + if chip == "auto": + log.note( + "Chip not specified, showing commands for ESP32 by default. " + "Specify the --chip option to get chip-specific help." + ) + chip = "esp32" + commands = init_commands(port=None, chip=chip, skip_connect=True) + commands.add_cli_commands(self) + return super().get_help(ctx) # type: ignore diff --git a/tools/esptool_py/espefuse/efuse/base_fields.py b/tools/esptool_py/espefuse/efuse/base_fields.py index 654d0fd668..ab39b0a757 100644 --- a/tools/esptool_py/espefuse/efuse/base_fields.py +++ b/tools/esptool_py/espefuse/efuse/base_fields.py @@ -4,15 +4,17 @@ # # SPDX-License-Identifier: GPL-2.0-or-later +from abc import abstractmethod import binascii import sys -from bitstring import BitArray, BitStream, CreationError +from bitstring import BitArray, BitStream, Bits, CreationError +from espefuse.efuse.mem_definition_base import EfuseBlocksBase, EfuseRegistersBase import esptool +from esptool.logger import log from . import util -from typing import List class CheckArgValue(object): @@ -26,7 +28,7 @@ def check_arg_value(efuse, new_value): new_value = 1 if new_value is None else int(new_value, 0) if new_value != 1: raise esptool.FatalError( - "New value is not accepted for efuse '{}' " + "New value is not accepted for eFuse '{}' " "(will always burn 0->1), given value={}".format( efuse.name, new_value ) @@ -46,7 +48,7 @@ def check_arg_value(efuse, new_value): else: if new_value is None: raise esptool.FatalError( - "New value required for efuse '{}' (given None)".format( + "New value required for eFuse '{}' (given None)".format( efuse.name ) ) @@ -59,20 +61,20 @@ def check_arg_value(efuse, new_value): elif efuse.efuse_type.startswith("bytes"): if new_value is None: raise esptool.FatalError( - "New value required for efuse '{}' (given None)".format( + "New value required for eFuse '{}' (given None)".format( efuse.name ) ) if len(new_value) * 8 != efuse.bitarray.len: raise esptool.FatalError( - "The length of efuse '{}' ({} bits) " + "The length of eFuse '{}' ({} bits) " "(given len of the new value= {} bits)".format( efuse.name, efuse.bitarray.len, len(new_value) * 8 ) ) else: raise esptool.FatalError( - "The '{}' type for the '{}' efuse is not supported yet.".format( + "The '{}' type for the '{}' eFuse is not supported yet.".format( efuse.efuse_type, efuse.name ) ) @@ -85,6 +87,10 @@ def check_arg_value(efuse, new_value): class EfuseProtectBase(object): # This class is used by EfuseBlockBase and EfuseFieldBase + read_disable_bit: int | list[int] | None + write_disable_bit: int | list[int] | None + parent: "EspEfusesBase" + name: str def get_read_disable_mask(self, blk_part=None): """Returns mask of read protection bits @@ -108,35 +114,48 @@ def get_count_read_disable_bits(self): # On the C2 chip, BLOCK_KEY0 has two read protection bits [0, 1]. return bin(self.get_read_disable_mask()).count("1") - def is_readable(self, blk_part=None): - """Return true if the efuse is readable by software""" + def is_readable(self, blk_part: int | None = None) -> bool: + """Check if the eFuse is readable by software + + Args: + blk_part: The part of the block to check. + If None, check all parts. + + Returns: + bool: True if the eFuse is readable by software + """ num_bit = self.read_disable_bit if num_bit is None: return True # read cannot be disabled - return (self.parent["RD_DIS"].get() & self.get_read_disable_mask(blk_part)) == 0 + return (self.parent["RD_DIS"].get() & self.get_read_disable_mask(blk_part)) == 0 # type: ignore def disable_read(self): num_bit = self.read_disable_bit if num_bit is None: - raise esptool.FatalError("This efuse cannot be read-disabled") + raise esptool.FatalError("This eFuse cannot be read-disabled") if not self.parent["RD_DIS"].is_writeable(): raise esptool.FatalError( - "This efuse cannot be read-disabled due the to RD_DIS field is " + "This eFuse cannot be read-disabled due to the RD_DIS field being " "already write-disabled" ) self.parent["RD_DIS"].save(self.get_read_disable_mask()) - def is_writeable(self): + def is_writeable(self) -> bool: + """Check if the eFuse is writeable by software + + Returns: + bool: True if the eFuse is writeable by software + """ num_bit = self.write_disable_bit if num_bit is None: return True # write cannot be disabled - return (self.parent["WR_DIS"].get() & (1 << num_bit)) == 0 + return (self.parent["WR_DIS"].get() & (1 << num_bit)) == 0 # type: ignore def disable_write(self): num_bit = self.write_disable_bit if not self.parent["WR_DIS"].is_writeable(): raise esptool.FatalError( - "This efuse cannot be write-disabled due to the WR_DIS field is " + "This eFuse cannot be write-disabled due to the WR_DIS field being " "already write-disabled" ) self.parent["WR_DIS"].save(1 << num_bit) @@ -144,7 +163,7 @@ def disable_write(self): def check_wr_rd_protect(self): if not self.is_readable(): error_msg = "\t{} is read-protected.".format(self.name) - "The written value can not be read, the efuse/block looks as all 0.\n" + "The written value can not be read, the eFuse/block looks as all 0.\n" error_msg += "\tBurn in this case may damage an already written value." self.parent.print_error_msg(error_msg) if not self.is_writeable(): @@ -155,26 +174,26 @@ def check_wr_rd_protect(self): class EfuseBlockBase(EfuseProtectBase): - def __init__(self, parent, param, skip_read=False): - self.parent = parent - self.name = param.name - self.alias = param.alias - self.id = param.id - self.rd_addr = param.rd_addr - self.wr_addr = param.wr_addr - self.write_disable_bit = param.write_disable_bit - self.read_disable_bit = param.read_disable_bit - self.len = param.len - self.key_purpose_name = param.key_purpose - bit_block_len = self.get_block_len() * 8 - self.bitarray = BitStream(bit_block_len) + def __init__(self, parent: "EspEfusesBase", param, skip_read: bool = False) -> None: + self.parent: EspEfusesBase = parent + self.name: str = param.name + self.alias: list[str] = param.alias + self.id: int = param.id + self.rd_addr: int = param.rd_addr + self.wr_addr: int = param.wr_addr + self.write_disable_bit: int | None = param.write_disable_bit + self.read_disable_bit: int | None = param.read_disable_bit + self.len: int = param.len + self.key_purpose_name: str | None = param.key_purpose + bit_block_len: int = self.get_block_len() * 8 + self.bitarray: BitStream = BitStream(bit_block_len) self.bitarray.set(0) - self.wr_bitarray = BitStream(bit_block_len) + self.wr_bitarray: BitStream = BitStream(bit_block_len) self.wr_bitarray.set(0) - self.fail = False - self.num_errors = 0 + self.fail: bool = False + self.num_errors: int = 0 if self.id == 0: - self.err_bitarray = BitStream(bit_block_len) + self.err_bitarray: BitStream | None = BitStream(bit_block_len) self.err_bitarray.set(0) else: self.err_bitarray = None @@ -182,6 +201,10 @@ def __init__(self, parent, param, skip_read=False): if not skip_read: self.read() + @abstractmethod + def apply_coding_scheme(self): + pass + def get_block_len(self): coding_scheme = self.get_coding_scheme() if coding_scheme == self.parent.REGS.CODING_SCHEME_NONE: @@ -207,10 +230,10 @@ def get_raw(self, from_read=True): else: return self.wr_bitarray.bytes - def get(self, from_read=True): - self.get_bitstring(from_read=from_read) + def get(self, from_read: bool = True) -> BitStream: + return self.get_bitstring(from_read=from_read) - def get_bitstring(self, from_read=True): + def get_bitstring(self, from_read: bool = True) -> BitStream: if from_read: return self.bitarray else: @@ -240,7 +263,7 @@ def read(self, print_info=True): def print_block(self, bit_string, comment, debug=False): if self.parent.debug or debug: bit_string.pos = 0 - print( + log.print( "%-15s (%-16s) [%-2d] %s:" % (self.name, " ".join(self.alias)[:16], self.id, comment), " ".join( @@ -258,7 +281,7 @@ def check_wr_data(self): if wr_data.all(False): # nothing to burn if self.parent.debug: - print("[{:02}] {:20} nothing to burn".format(self.id, self.name)) + log.print("[{:02}] {:20} nothing to burn".format(self.id, self.name)) return False if len(wr_data.bytes) != len(self.bitarray.bytes): raise esptool.FatalError( @@ -268,7 +291,7 @@ def check_wr_data(self): self.check_wr_rd_protect() if self.get_bitstring().all(False): - print( + log.print( "[{:02}] {:20} is empty, will burn the new value".format( self.id, self.name ) @@ -276,18 +299,18 @@ def check_wr_data(self): else: # the written block in chip is not empty if self.get_bitstring() == wr_data: - print( + log.print( "[{:02}] {:20} is already written the same value, " "continue with EMPTY_BLOCK".format(self.id, self.name) ) wr_data.set(0) else: - print("[{:02}] {:20} is not empty".format(self.id, self.name)) - print("\t(written ):", self.get_bitstring()) - print("\t(to write):", wr_data) + log.print("[{:02}] {:20} is not empty".format(self.id, self.name)) + log.print("\t(written ):", self.get_bitstring()) + log.print("\t(to write):", wr_data) mask = self.get_bitstring() & wr_data if mask == wr_data: - print( + log.print( "\tAll wr_data bits are set in the written block, " "continue with EMPTY_BLOCK." ) @@ -295,49 +318,47 @@ def check_wr_data(self): else: coding_scheme = self.get_coding_scheme() if coding_scheme == self.parent.REGS.CODING_SCHEME_NONE: - print("\t(coding scheme = NONE)") + log.print("\t(coding scheme = NONE)") elif coding_scheme == self.parent.REGS.CODING_SCHEME_RS: - print("\t(coding scheme = RS)") + log.print("\t(coding scheme = RS)") error_msg = ( - "\tBurn into %s is forbidden " - "(RS coding scheme does not allow this)." % (self.name) + f"\tBurn into {self.name} is forbidden " + "(RS coding scheme does not allow this)." ) self.parent.print_error_msg(error_msg) elif coding_scheme == self.parent.REGS.CODING_SCHEME_34: - print("\t(coding scheme = 3/4)") + log.print("\t(coding scheme = 3/4)") data_can_not_be_burn = False for i in range(0, self.get_bitstring().len, 6 * 8): rd_chunk = self.get_bitstring()[i : i + 6 * 8 :] wr_chunk = wr_data[i : i + 6 * 8 :] if rd_chunk.any(True): if wr_chunk.any(True): - print( - "\twritten chunk [%d] and wr_chunk " - "are not empty. " % (i // (6 * 8)), + log.print( + f"\twritten chunk [{i // (6 * 8)}] and wr_chunk" + " are not empty. ", end="", ) if rd_chunk == wr_chunk: - print( + log.print( "wr_chunk == rd_chunk. " "Continue with empty chunk." ) wr_data[i : i + 6 * 8 :].set(0) else: - print("wr_chunk != rd_chunk. Can not burn.") - print("\twritten ", rd_chunk) - print("\tto write", wr_chunk) + log.print("wr_chunk != rd_chunk. Can not burn.") + log.print("\twritten ", rd_chunk) + log.print("\tto write", wr_chunk) data_can_not_be_burn = True if data_can_not_be_burn: error_msg = ( - "\tBurn into %s is forbidden " - "(3/4 coding scheme does not allow this)." % (self.name) + f"\tBurn into {self.name} is forbidden " + "(3/4 coding scheme does not allow this)." ) self.parent.print_error_msg(error_msg) else: raise esptool.FatalError( - "The coding scheme ({}) is not supported".format( - coding_scheme - ) + f"The coding scheme ({coding_scheme}) is not supported." ) def save(self, new_data): @@ -351,16 +372,14 @@ def save(self, new_data): # *[x] - means a byte. data = BitStream(bytes=new_data[::-1], length=len(new_data) * 8) if self.parent.debug: - print( - "\twritten : {} ->\n\tto write: {}".format(self.get_bitstring(), data) - ) + log.print(f"\twritten : {self.get_bitstring()} ->\n\tto write: {data}") self.wr_bitarray.overwrite(self.wr_bitarray | data, pos=0) def burn_words(self, words): for burns in range(3): self.parent.efuse_controller_setup() if self.parent.debug: - print("Write data to BLOCK%d" % (self.id)) + log.print(f"Write data to BLOCK{self.id}") write_reg_addr = self.wr_addr for word in words: # for ep32s2: using EFUSE_PGM_DATA[0..7]_REG for writing data @@ -371,7 +390,7 @@ def burn_words(self, words): # each block has the special regs EFUSE_BLK[0..3]_WDATA[0..7]_REG # for writing data if self.parent.debug: - print("Addr 0x%08x, data=0x%08x" % (write_reg_addr, word)) + log.print(f"Addr {write_reg_addr:10x}, data={word:10x}") self.parent.write_reg(write_reg_addr, word) write_reg_addr += 4 @@ -380,10 +399,9 @@ def burn_words(self, words): self.parent.efuse_read() self.parent.get_coding_scheme_warnings(silent=True) if self.fail or self.num_errors: - print( - "Error in BLOCK%d, re-burn it again (#%d), to fix it. " - "fail_bit=%d, num_errors=%d" - % (self.id, burns, self.fail, self.num_errors) + log.print( + f"Error in BLOCK{self.id}, re-burn it again (#{burns}) to fix." + f" fail_bit={self.fail}, num_errors={self.num_errors}" ) break if not self.fail and self.num_errors == 0: @@ -391,13 +409,15 @@ def burn_words(self, words): if self.wr_bitarray & self.bitarray != self.wr_bitarray: # if the required bits are not set then we need to re-burn it again. if burns < 2: - print( - f"\nRepeat burning BLOCK{self.id} (#{burns + 2}) because not all bits were set" + log.print( + f"\nRepeat burning BLOCK{self.id} (#{burns + 2}) " + "because not all bits were set" ) continue else: - print( - f"\nAfter {burns + 1} attempts, the required data was not set to BLOCK{self.id}" + log.print( + f"\nAfter {burns + 1} attempts, the required data was not " + f"set to BLOCK{self.id}" ) break @@ -412,29 +432,28 @@ def burn(self): self.burn_words(words) self.read() if not self.is_readable(): - print( - "{} ({}) is read-protected. " - "Read back the burn value is not possible.".format( - self.name, self.alias - ) + log.print( + f"{self.name} ({self.alias}) is read-protected. " + "Read back the burn value is not possible." ) if self.bitarray.all(False): - print("Read all '0'") + log.print("Read all '0'") else: # Should never happen raise esptool.FatalError( - "The {} is read-protected but not all '0' ({})".format( - self.name, self.bitarray.hex - ) + f"The {self.name} is read-protected but not all '0' " + f"({self.bitarray.hex})" ) else: if self.wr_bitarray == self.bitarray: - print("BURN BLOCK%-2d - OK (write block == read block)" % self.id) + log.print(f"BURN BLOCK{self.id:<2d} - OK (write block == read block)") elif ( self.wr_bitarray & self.bitarray == self.wr_bitarray and self.bitarray & before_burn_bitarray == before_burn_bitarray ): - print("BURN BLOCK%-2d - OK (all write block bits are set)" % self.id) + log.print( + f"BURN BLOCK{self.id:<2d} - OK (all write block bits are set)" + ) else: # Happens only when an efuse is written and read-protected # in one command @@ -444,7 +463,7 @@ def burn(self): # raise error only for other blocks if self.id != 0: raise esptool.FatalError( - "Burn {} ({}) was not successful".format(self.name, self.alias) + f"Burn {self.name} ({self.alias}) was not successful." ) self.wr_bitarray.set(0) @@ -454,17 +473,36 @@ class EspEfusesBase(object): Wrapper object to manage the efuse fields in a connected ESP bootloader """ - _esp = None - blocks: List[EfuseBlockBase] = [] - efuses: List = [] + _esp: esptool.ESPLoader + blocks: list[EfuseBlockBase] = [] + efuses: list = [] coding_scheme = None force_write_always = None - batch_mode_cnt = 0 - postpone = False + batch_mode_cnt: int = 0 + postpone: bool = False + BURN_BLOCK_DATA_NAMES: list[str] = [] + REGS: type[EfuseRegistersBase] + Blocks: EfuseBlocksBase + + def __init__( + self, + esp: esptool.ESPLoader, + skip_connect: bool = False, + debug: bool = False, + do_not_confirm: bool = False, + extend_efuse_table: None = None, + ) -> None: + self._esp = esp + self.debug = debug + self.do_not_confirm = do_not_confirm def __iter__(self): return self.efuses.__iter__() + @abstractmethod + def __getitem__(self, efuse_name): + pass + def get_crystal_freq(self): return self._esp.get_crystal_freq() @@ -484,12 +522,24 @@ def update_reg(self, addr, mask, new_val): def efuse_controller_setup(self): pass + @abstractmethod + def write_efuses(self, block): + pass + + @abstractmethod + def efuse_read(self): + pass + + @abstractmethod + def read_coding_scheme(self): + pass + def reconnect_chip(self, esp): - print("Re-connecting...") + log.print("Re-connecting...") baudrate = esp._port.baudrate port = esp._port.port esp._port.close() - return esptool.cmds.detect_chip(port, baudrate) + return esptool.detect_chip(port, baudrate) def get_index_block_by_name(self, name): for block in self.blocks: @@ -545,8 +595,8 @@ def get_raw_value_from_write(self, efuse_name): if any(value != 0 for value in postpone_efuses.values()): if self.debug: - print("These BLOCK0 efuses will be burned later at the very end:") - print(postpone_efuses) + log.print("These BLOCK0 eFuses will be burned later at the very end:") + log.print(postpone_efuses) # exclude these efuses from the first burn (postpone them till the end). for key_name in postpone_efuses.keys(): self[key_name].reset() @@ -554,20 +604,20 @@ def get_raw_value_from_write(self, efuse_name): def recover_postponed_efuses_from_block0_to_burn(self, postpone_efuses): if any(value != 0 for value in postpone_efuses.values()): - print("Burn postponed efuses from BLOCK0.") + log.print("Burn postponed eFuses from BLOCK0.") for key_name in postpone_efuses.keys(): self[key_name].save(postpone_efuses[key_name]) - def burn_all(self, check_batch_mode=False): + def burn_all(self, check_batch_mode: bool = False) -> bool: if check_batch_mode: if self.batch_mode_cnt != 0: - print( + log.print( "\nBatch mode is enabled, " "the burn will be done at the end of the command." ) return False - print("\nCheck all blocks for burn...") - print("idx, BLOCK_NAME, Conclusion") + log.print("\nCheck all blocks for burn...") + log.print("idx, BLOCK_NAME, Conclusion") have_wr_data_for_burn = False for block in self.blocks: block.check_wr_data() @@ -576,7 +626,7 @@ def burn_all(self, check_batch_mode=False): ): have_wr_data_for_burn = True if not have_wr_data_for_burn: - print("Nothing to burn, see messages above.") + log.print("Nothing to burn, see messages above.") return True EspEfusesBase.confirm("", self.do_not_confirm) @@ -588,16 +638,16 @@ def burn_block(block, postponed_efuses): block.num_errors and block.num_errors > old_num_errors ): if postponed_efuses: - print("The postponed efuses were not burned due to an error.") - print("\t1. Try to fix a coding error by this cmd:") - print("\t 'espefuse.py check_error --recovery'") + log.print("The postponed eFuses were not burned due to an error.") + log.print("\t1. Try to fix a coding error by this cmd:") + log.print("\t 'espefuse check-error --recovery'") command_string = " ".join( f"{key} {value}" for key, value in postponed_efuses.items() if value.any(True) ) - print("\t2. Then run the cmd to burn all postponed efuses:") - print(f"\t 'espefuse.py burn_efuse {command_string}'") + log.print("\t2. Then run the cmd to burn all postponed eFuses:") + log.print(f"\t 'espefuse burn-efuse {command_string}'") raise esptool.FatalError("Error(s) were detected in eFuses") @@ -615,7 +665,7 @@ def burn_block(block, postponed_efuses): self.recover_postponed_efuses_from_block0_to_burn(postponed_efuses) burn_block(block, postponed_efuses) - print("Reading updated efuses...") + log.print("Reading updated eFuses...") self.read_coding_scheme() self.read_blocks() self.update_efuses() @@ -623,17 +673,17 @@ def burn_block(block, postponed_efuses): @staticmethod def confirm(action, do_not_confirm): - print( + log.print( "%s%s\nThis is an irreversible operation!" % (action, "" if action.endswith("\n") else ". ") ) if not do_not_confirm: - print("Type 'BURN' (all capitals) to continue.") - # required for Pythons which disable line buffering, ie mingw in mintty - sys.stdout.flush() + log.print("Type 'BURN' (all capitals) to continue.", flush=True) + # Flush required for Pythons which disable line buffering, + # ie mingw in mintty yes = input() if yes != "BURN": - print("Aborting.") + log.print("Aborting.") sys.exit(0) def print_error_msg(self, error_msg): @@ -641,7 +691,7 @@ def print_error_msg(self, error_msg): if not self.force_write_always: error_msg += "(use '--force-write-always' option to ignore it)" if self.force_write_always: - print(error_msg, "Skipped because '--force-write-always' option.") + log.print(error_msg, "Skipped because '--force-write-always' option.") else: raise esptool.FatalError(error_msg) @@ -650,9 +700,54 @@ def get_block_errors(self, block_num): return self.blocks[block_num].num_errors, self.blocks[block_num].fail def is_efuses_incompatible_for_burn(self): - # Overwrite this function for a specific target if you want to check if a certain eFuse(s) can be burned. + # Overwrite this function for a specific target if you want to check if a + # certain eFuse(s) can be burned. return False + def get_major_chip_version(self): + try: + return self["WAFER_VERSION_MAJOR"].get() + except KeyError: + return 0 + + def get_minor_chip_version(self): + try: + return self["WAFER_VERSION_MINOR"].get() + except KeyError: + return 0 + + def get_chip_version(self): + return self.get_major_chip_version() * 100 + self.get_minor_chip_version() + + def get_major_block_version(self): + try: + return self["BLK_VERSION_MAJOR"].get() + except KeyError: + return 0 + + def get_minor_block_version(self): + try: + return self["BLK_VERSION_MINOR"].get() + except KeyError: + return 0 + + def get_block_version(self): + return self.get_major_block_version() * 100 + self.get_minor_block_version() + + def get_pkg_version(self): + try: + return self["PKG_VERSION"].get() + except KeyError: + return 0 + + @abstractmethod + def summary(self): + pass + + @abstractmethod + def get_coding_scheme_warnings(self, silent: bool = False): + pass + class EfuseFieldBase(EfuseProtectBase): def __init__(self, parent, param): @@ -665,7 +760,7 @@ def __init__(self, parent, param): self.read_disable_bit = param.read_disable_bit self.name = param.name self.efuse_class = param.class_type - self.efuse_type = param.type + self.efuse_type: str = param.type self.description = param.description self.dict_value = param.dictionary self.bit_len = param.bit_len @@ -718,10 +813,9 @@ def convert_to_bitstring(self, new_value): try: return BitArray(self.efuse_type + "={}".format(new_value)) except CreationError as err: - print( - "New value '{}' is not suitable for {} ({})".format( - new_value, self.name, self.efuse_type - ) + log.print( + f"New value '{new_value}' is not suitable for " + f"{self.name} ({self.efuse_type})" ) raise esptool.FatalError(err) @@ -733,23 +827,22 @@ def check_new_value(self, bitarray_new_value): if bitarray_new_value.len != bitarray_old_value.len: raise esptool.FatalError( - "For {} efuse, the length of the new value is wrong, " - "expected {} bits, was {} bits.".format( - self.name, bitarray_old_value.len, bitarray_new_value.len - ) + f"For {self.name} eFuse, the length of the new value is wrong, " + f"expected {bitarray_old_value.len} bits, " + f"was {bitarray_new_value.len} bits." ) if ( bitarray_new_value == bitarray_old_value or bitarray_new_value & self.get_bitstring() == bitarray_new_value ): - error_msg = "\tThe same value for {} ".format(self.name) - error_msg += "is already burned. Do not change the efuse." - print(error_msg) + error_msg = f"\tThe same value for {self.name} " + error_msg += "is already burned. Do not change the eFuse." + log.print(error_msg) bitarray_new_value.set(0) elif bitarray_new_value == self.get_bitstring(from_read=False): error_msg = "\tThe same value for {} ".format(self.name) error_msg += "is already prepared for the burn operation." - print(error_msg) + log.print(error_msg) bitarray_new_value.set(0) else: if self.name not in ["WR_DIS", "RD_DIS"]: @@ -798,49 +891,72 @@ def update(self, bit_array_block): self.fail = self.parent.blocks[self.block].fail self.num_errors = self.parent.blocks[self.block].num_errors - def get_raw(self, from_read=True): - """Return the raw (unformatted) numeric value of the efuse bits + def get_raw(self, from_read: bool = True) -> int | bytearray: + """Return the raw (unformatted) numeric value of the eFuse bits Returns a simple integer or (for some subclasses) a bitstring. type: int or bool -> int type: bytes -> bytearray + + Args: + from_read: If True, read the eFuse value from the device. + If False, use the cached value. + + Returns: + int | bytearray: The raw value of the eFuse """ - return self.get_bitstring(from_read).read(self.efuse_type) + return self.get_bitstring(from_read).read(self.efuse_type) # type: ignore + + def get(self, from_read: bool = True) -> str | int | bytearray: + """Get a formatted version of the eFuse value, suitable for display - def get(self, from_read=True): - """Get a formatted version of the efuse value, suitable for display type: int or bool -> int type: bytes -> string "01 02 03 04 05 06 07 08 ... ". Byte order [0] ... [N]. dump regs: 0x04030201 0x08070605 ... + + Args: + from_read: If True, read the eFuse value from the device. + If False, use the cached value. + + Returns: + str | int | bytearray: The formatted version of the eFuse value """ if self.efuse_type.startswith("bytes"): - return util.hexify(self.get_bitstring(from_read).bytes[::-1], " ") + return util.hexify(self.get_bitstring(from_read).bytes[::-1], " ") # type: ignore else: return self.get_raw(from_read) - def get_meaning(self, from_read=True): - """Get the meaning of efuse from dict if possible, suitable for display""" + def get_meaning(self, from_read: bool = True) -> str | int | bytearray: + """Get the meaning of eFuse from dict if possible, suitable for display + + Args: + from_read: If True, read the eFuse value from the device. + If False, use the cached value. + + Returns: + str | int | bytearray: The meaning of the eFuse + """ if self.dict_value: try: - return self.dict_value[self.get_raw(from_read)] + return self.dict_value[self.get_raw(from_read)] # type: ignore except KeyError: pass return self.get(from_read) - def get_bitstring(self, from_read=True): + def get_bitstring(self, from_read: bool = True) -> BitStream | Bits: if from_read: self.bitarray.pos = 0 return self.bitarray else: field_len = self.bitarray.len - block = self.parent.blocks[self.block] + block: EfuseBlockBase = self.parent.blocks[self.block] block.wr_bitarray.pos = block.wr_bitarray.length - ( self.word * 32 + self.pos + field_len ) return block.wr_bitarray.read(self.bitarray.len) def burn(self, new_value): - # Burn a efuse. Added for compatibility reason. + """Burn a eFuse. Added for compatibility reason.""" self.save(new_value) self.parent.burn_all() @@ -860,7 +976,7 @@ def get_info(self): return output def reset(self): - # resets a efuse that is prepared for burning + """Resets a eFuse that is prepared for burning""" bitarray_field = self.convert_to_bitstring(0) block = self.parent.blocks[self.block] wr_bitarray_temp = block.wr_bitarray.copy() diff --git a/tools/esptool_py/espefuse/efuse/base_operations.py b/tools/esptool_py/espefuse/efuse/base_operations.py index 60f18dc5e5..c732756ba9 100644 --- a/tools/esptool_py/espefuse/efuse/base_operations.py +++ b/tools/esptool_py/espefuse/efuse/base_operations.py @@ -1,804 +1,1181 @@ # This file includes the common operations with eFuses for chips # -# SPDX-FileCopyrightText: 2020-2022 Espressif Systems (Shanghai) CO LTD +# SPDX-FileCopyrightText: 2020-2025 Espressif Systems (Shanghai) CO LTD # # SPDX-License-Identifier: GPL-2.0-or-later -import argparse +from abc import abstractmethod +import io import os import json import sys +from typing import Any, BinaryIO, Callable, TextIO + +import rich_click as click from bitstring import BitStream import esptool +from esptool.logger import log from . import base_fields from . import util +from .emulate_efuse_controller_base import EmulateEfuseControllerBase -def add_common_commands(subparsers, efuses): - class ActionEfuseValuePair(argparse.Action): - def __init__(self, option_strings, dest, nargs=None, **kwargs): - self._nargs = nargs - self._choices = kwargs.get("efuse_choices") - self.efuses = kwargs.get("efuses") - del kwargs["efuse_choices"] - del kwargs["efuses"] - super(ActionEfuseValuePair, self).__init__( - option_strings, dest, nargs=nargs, **kwargs - ) +class EfuseValuePairArg(click.Argument): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) - def __call__(self, parser, namespace, values, option_string=None): - def check_efuse_name(efuse_name, efuse_list): - if efuse_name not in self._choices: - raise esptool.FatalError( - "Invalid the efuse name '{}'. " - "Available the efuse names: {}".format( - efuse_name, self._choices - ) - ) + def make_metavar(self) -> str: + return f"[{super().make_metavar()}] ..." - efuse_value_pairs = {} - if len(values) > 1: - if len(values) % 2: - raise esptool.FatalError( - "The list does not have a valid pair (name value) {}".format( - values - ) - ) - for i in range(0, len(values), 2): - efuse_name, new_value = values[i : i + 2 :] - check_efuse_name(efuse_name, self._choices) - check_arg = base_fields.CheckArgValue(self.efuses, efuse_name) - efuse_value_pairs[efuse_name] = check_arg(new_value) - else: - # For the case of compatibility, when only the efuse_name is given - # Fields with 'bitcount' and 'bool' types can be without new_value arg - efuse_name = values[0] - check_efuse_name(efuse_name, self._choices) + def type_cast_value(self, ctx: click.Context, value: list[str]): + return self.type.convert(value, None, ctx) + + +class EfuseValuePairType(click.ParamType): + name = "efuse-value-pair" + + def __init__(self, efuse_choices, efuses): + self.efuse_choices = efuse_choices + self.efuses = efuses + + def convert(self, value: str, param: click.Parameter | None, ctx: click.Context): + def check_efuse_name(efuse_name: str): + if efuse_name not in self.efuse_choices: + raise click.BadParameter( + f"Invalid eFuse name '{efuse_name}'. " + f"Available eFuse names: {self.efuse_choices}" + ) + return efuse_name + + # Handle single value case (eFuse name only) + efuse_value_pairs = {} + if len(value) > 1: + if len(value) % 2: + raise click.BadParameter( + f"The list does not have a valid pair (name value) {value}" + ) + for i in range(0, len(value), 2): + efuse_name: str = value[i] + new_value: str = value[i + 1] + efuse_name = check_efuse_name(efuse_name) check_arg = base_fields.CheckArgValue(self.efuses, efuse_name) - efuse_value_pairs[efuse_name] = check_arg(None) - setattr(namespace, self.dest, efuse_value_pairs) - - burn = subparsers.add_parser( - "burn_efuse", help="Burn the efuse with the specified name" - ) - burn.add_argument( - "name_value_pairs", - help="Name of efuse field and new value pairs to burn. EFUSE_NAME: " - "[{}].".format(", ".join([e.name for e in efuses.efuses])), - action=ActionEfuseValuePair, - nargs="+", - metavar="[EFUSE_NAME VALUE]", - efuse_choices=[e.name for e in efuses.efuses] - + [name for e in efuses.efuses for name in e.alt_names if name != ""], - efuses=efuses, - ) - burn.add_argument( - "--force", - help="Suppress an error to burn eFuses", - action="store_true", - ) - - read_protect_efuse = subparsers.add_parser( - "read_protect_efuse", - help="Disable readback for the efuse with the specified name", - ) - read_protect_efuse.add_argument( - "efuse_name", - help="Name of efuse register to burn", - nargs="+", - choices=[e.name for e in efuses.efuses if e.read_disable_bit is not None] - + [ - name - for e in efuses.efuses - if e.read_disable_bit is not None - for name in e.alt_names - if name != "" - ], - ) - - write_protect_efuse = subparsers.add_parser( - "write_protect_efuse", - help="Disable writing to the efuse with the specified name", - ) - write_protect_efuse.add_argument( - "efuse_name", - help="Name of efuse register to burn", - nargs="+", - choices=[e.name for e in efuses.efuses if e.write_disable_bit is not None] - + [ - name - for e in efuses.efuses - if e.write_disable_bit is not None - for name in e.alt_names - if name != "" - ], - ) - - burn_block_data = subparsers.add_parser( - "burn_block_data", - help="Burn non-key data to EFUSE blocks. " - "(Don't use this command to burn key data for Flash Encryption or " - "ESP32 Secure Boot V1, as the byte order of keys is swapped (use burn_key)).", - ) - add_force_write_always(burn_block_data) - burn_block_data.add_argument( - "--offset", "-o", help="Byte offset in the efuse block", type=int, default=0 - ) - burn_block_data.add_argument( - "block", - help="Efuse block to burn.", - action="append", - choices=efuses.BURN_BLOCK_DATA_NAMES, - ) - burn_block_data.add_argument( - "datafile", - help="File containing data to burn into the efuse block", - action="append", - type=argparse.FileType("rb"), - ) - for _ in range(0, len(efuses.BURN_BLOCK_DATA_NAMES)): - burn_block_data.add_argument( - "block", - help="Efuse block to burn.", - metavar="BLOCK", - nargs="?", - action="append", - choices=efuses.BURN_BLOCK_DATA_NAMES, - ) - burn_block_data.add_argument( - "datafile", - nargs="?", - help="File containing data to burn into the efuse block", - metavar="DATAFILE", - action="append", - type=argparse.FileType("rb"), - ) + efuse_value_pairs[efuse_name] = check_arg(new_value) + + else: + # For the case of compatibility, when only the efuse_name is given + # Fields with 'bitcount' and 'bool' types can be without new_value arg + efuse_name = value[0] + check_efuse_name(efuse_name) + check_arg = base_fields.CheckArgValue(self.efuses, efuse_name) + efuse_value_pairs[efuse_name] = check_arg(None) + + return efuse_value_pairs + + +class CustomMACType(click.ParamType): + name = "custom_mac" + + def convert(self, value: str, param: click.Parameter | None, ctx: click.Context): + return base_fields.CheckArgValue(ctx.obj["efuses"], "CUSTOM_MAC")(value) + + +class TupleParameter(click.Argument): + def __init__(self, *args, **kwargs): + self.max_arity = kwargs.pop("max_arity", None) + super().__init__(*args, **kwargs) + + def make_metavar(self) -> str: + if self.nargs == 1: + return super().make_metavar() # type: ignore + if self.max_arity is None: + return f"[{super().make_metavar()}] ..." + return f"[{super().make_metavar()}] ... (max {self.max_arity} groups)" + + def type_cast_value(self, ctx: click.Context, value: list[str]) -> tuple[Any, ...]: + # This is by default eating all options, so we need to check for help option + if any(v in ctx.help_option_names for v in value): + # show help + click.echo(ctx.get_help()) + ctx.exit() + + # Check if we have more values than allowed by max_arity + if self.max_arity is not None and len(value) > self.max_arity * self.type.arity: + raise click.BadParameter( + f"Expected at most {self.max_arity} groups ({self.type.arity} values " + f"each), got {len(value)} (values: {value})" + ) + + # check that the number of values is a multiple of self.type.arity + if len(value) % self.type.arity != 0: + raise click.BadParameter( + f"Expected multiple of {self.type.arity} values, got {len(value)} " + f"(values: {value})" + ) - set_bit_cmd = subparsers.add_parser("burn_bit", help="Burn bit in the efuse block.") - add_force_write_always(set_bit_cmd) - set_bit_cmd.add_argument( - "block", help="Efuse block to burn.", choices=efuses.BURN_BLOCK_DATA_NAMES - ) - set_bit_cmd.add_argument( - "bit_number", - help="Bit number in the efuse block [0..BLK_LEN-1]", - nargs="+", - type=int, - ) - - subparsers.add_parser( - "adc_info", - help="Display information about ADC calibration data stored in efuse.", - ) - - dump_cmd = subparsers.add_parser("dump", help="Dump raw hex values of all eFuses") - dump_cmd.add_argument( - "--format", - help="Select the dump format: " - "default - usual console eFuse dump; " - "joint - all eFuse blocks are stored in one file; " - "split - each eFuse block is placed into its own file. The tool will create multiple files based on " - "the given --file_name (/path/blk.bin): blk0.bin, blk1.bin ... blkN.bin. Use the burn_block_data cmd " - "to write it back to another chip.", - choices=["default", "split", "joint"], - default="default", - ) - dump_cmd.add_argument( - "--file_name", - help="The path to the file in which to save the dump, if not specified, output to the console.", - default=sys.stdout, - ) - - summary_cmd = subparsers.add_parser( - "summary", help="Print human-readable summary of efuse values" - ) - summary_cmd.add_argument( - "--format", - help="Select the summary format", - choices=["summary", "json", "value_only"], - default="summary", - ) - summary_cmd.add_argument( - "--file", - help="File to save the efuse summary", - type=argparse.FileType("w"), - default=sys.stdout, - ) - summary_cmd.add_argument( - "efuses_to_show", - help="The efuses to show. If not provided, all efuses will be shown.", - nargs="*", - ) - - execute_scripts = subparsers.add_parser( - "execute_scripts", help="Executes scripts to burn at one time." - ) - execute_scripts.add_argument( - "scripts", - help="The special format of python scripts.", - nargs="+", - type=argparse.FileType("r"), - ) - execute_scripts.add_argument( - "--index", - help="integer index. " - "It allows to retrieve unique data per chip from configfiles " - "and then burn them (ex. CUSTOM_MAC, UNIQUE_ID).", - type=int, - ) - execute_scripts.add_argument( - "--configfiles", - help="List of configfiles with data", - nargs="?", - action="append", - type=argparse.FileType("r"), - ) - - check_error_cmd = subparsers.add_parser("check_error", help="Checks eFuse errors") - check_error_cmd.add_argument( - "--recovery", - help="Recovery of BLOCKs after encoding errors", - action="store_true", - ) - - -def add_force_write_always(p): - p.add_argument( + # split value into groups of self.type.arity and call convert() for each group + groups = [ + value[i : i + self.type.arity] + for i in range(0, len(value), self.type.arity) + ] + return tuple(self.type.convert(group, None, ctx) for group in groups) + + +class NonCompositeTuple(click.Tuple): + is_composite = False # Hack to work around click's default nargs=1 + + def __init__(self, types): + super().__init__(types) + + +def add_force_write_always(function: Callable): + def callback(ctx: click.Context, param: click.Parameter, value: str): + ctx.ensure_object(dict) + if ctx.obj.get("commands", None) is not None: + ctx.obj["commands"].efuses.force_write_always = value + + return click.option( "--force-write-always", - help="Write the efuse even if it looks like it's already been written, " + help="Write the eFuse even if it looks like it's already been written, " "or is write protected. Note that this option can't disable write protection, " "or clear any bit which has already been set.", - action="store_true", - ) + is_flag=True, + callback=callback, + )(function) -def add_show_sensitive_info_option(p): - p.add_argument( +def add_show_sensitive_info_option(function: Callable): + def callback(ctx: click.Context, param: click.Parameter, value: bool): + if value or ctx.obj.get("debug") or ctx.obj.get("show_sensitive_info", False): + value = True + ctx.obj["show_sensitive_info"] = value + return value + + return click.option( "--show-sensitive-info", help="Show data to be burned (may expose sensitive data). " "Enabled if --debug is used.", - action="store_true", - default=False, - ) - - -def summary(esp, efuses, args): - """Print a human-readable or json summary of efuse contents""" - ROW_FORMAT = "%-50s %-50s%s = %s %s %s" - human_output = args.format in ["summary", "value_only"] - value_only = args.format == "value_only" - if value_only and len(args.efuses_to_show) != 1: - raise esptool.FatalError( - "The 'value_only' format can be used exactly for one efuse." - ) - do_filtering = bool(args.efuses_to_show) - json_efuse = {} - summary_efuse = [] - if args.file != sys.stdout: - print("Saving efuse values to " + args.file.name) - if human_output and not value_only: - summary_efuse.append( - ROW_FORMAT.replace("-50", "-12") - % ( - "EFUSE_NAME (Block)", - "Description", - "", - "[Meaningful Value]", - "[Readable/Writeable]", - "(Hex Value)", - ) - ) - summary_efuse.append("-" * 88) - for category in sorted(set(e.category for e in efuses), key=lambda c: c.title()): - if human_output and not value_only: - summary_efuse.append(f"{category.title()} fuses:") - for e in (e for e in efuses if e.category == category): - if e.efuse_type.startswith("bytes"): - raw = "" - else: - raw = "({})".format(e.get_bitstring()) - (readable, writeable) = (e.is_readable(), e.is_writeable()) - if readable and writeable: - perms = "R/W" - elif readable: - perms = "R/-" - elif writeable: - perms = "-/W" - else: - perms = "-/-" - base_value = e.get_meaning() - value = str(base_value) - if not readable: - count_read_disable_bits = e.get_count_read_disable_bits() - if count_read_disable_bits == 2: - # On the C2 chip, BLOCK_KEY0 has two read protection bits [0, 1] - # related to the lower and higher part of the block. - v = [value[: (len(value) // 2)], value[(len(value) // 2) :]] - for i in range(count_read_disable_bits): - if not e.is_readable(blk_part=i): - v[i] = v[i].replace("0", "?") - value = "".join(v) - else: - value = value.replace("0", "?") - if ( - human_output - and (not do_filtering or e.name in args.efuses_to_show) - and not value_only - ): - summary_efuse.append( - ROW_FORMAT - % ( - e.get_info(), - e.description[:50], - "\n " if len(value) > 20 else "", - value, - perms, - raw, - ) - ) - desc_len = len(e.description[50:]) - if desc_len: - desc_len += 50 - for i in range(50, desc_len, 50): - summary_efuse.append( - f"{'':<50} {e.description[i : (50 + i)]:<50}" - ) - elif human_output and value_only and e.name in args.efuses_to_show: - summary_efuse.append(f"{value}") - elif args.format == "json" and ( - not do_filtering or e.name in args.efuses_to_show - ): - json_efuse[e.name] = { - "name": e.name, - "value": base_value if readable else value, - "readable": readable, - "writeable": writeable, - "description": e.description, - "category": e.category, - "block": e.block, - "word": e.word, - "pos": e.pos, - "efuse_type": e.efuse_type, - "bit_len": e.bit_len, - } - if human_output and not value_only: - # Remove empty category if efuses are filtered and there are none to show - if do_filtering and summary_efuse[-1] == f"{category.title()} fuses:": - summary_efuse.pop() - else: - summary_efuse.append("") - if human_output and not value_only: - summary_efuse.append(efuses.summary()) - warnings = efuses.get_coding_scheme_warnings() - if warnings: - summary_efuse.append( - "WARNING: Coding scheme has encoding bit error warnings" + is_flag=True, + callback=callback, + expose_value=True, # ensure that callback is called even if option is not used + )(function) + + +def protect_options(function: Callable): + function = click.option( + "--no-write-protect", + help="Disable write-protecting of the key. The key remains writable. " + "(The keys use the RS coding scheme that does not support " + "post-write data changes. Forced write can damage RS encoding bits.) " + "The write-protecting of keypurposes does not depend on the option, " + "it will be set anyway.", + is_flag=True, + )(function) + function = click.option( + "--no-read-protect", + help="Disable read-protecting of the key. The key remains readable software.", + is_flag=True, + )(function) + return function + + +class BaseCommands: + CHIP_NAME = "auto" + efuse_lib: type[base_fields.EspEfusesBase] | None = None + efuses: base_fields.EspEfusesBase + esp: esptool.ESPLoader | EmulateEfuseControllerBase + external_esp: bool = False + + def get_efuses( + self, + skip_connect=False, + debug_mode=False, + do_not_confirm=False, + extend_efuse_table=None, + ): + if self.esp is None: + raise esptool.FatalError("get_efuses: esp is not set") + if self.CHIP_NAME == self.esp.CHIP_NAME: + if self.efuse_lib is None: + raise esptool.FatalError("get_efuses: efuse_lib is not set") + self.efuses = self.efuse_lib( + self.esp, skip_connect, debug_mode, do_not_confirm, extend_efuse_table ) - if human_output: - for line in summary_efuse: - print(line, file=args.file) - if args.file != sys.stdout: - args.file.close() - print("Done") - elif args.format == "json": - json.dump(json_efuse, args.file, sort_keys=True, indent=4) - print("") - - -def dump(esp, efuses, args): - """Dump raw efuse data registers""" - dump_file = args.file_name - to_console = args.file_name == sys.stdout - - def output_block_to_file(block, f, to_console): - block_dump = BitStream(block.get_bitstring()) - block_dump.byteswap() - if to_console: - f.write(block_dump.hex + "\n") else: - block_dump.tofile(f) + raise esptool.FatalError( + "get_efuses: Mismatch chip name " + f"({self.CHIP_NAME} != {self.esp.CHIP_NAME})" + ) - if args.format == "default": - if to_console: - # for "espefuse.py dump" cmd - for block in efuses.blocks: - block.print_block(block.get_bitstring(), "dump", debug=True) - return - else: - # for back compatibility to support "espefuse.py dump --file_name dump.bin" - args.format = "split" + def __enter__(self): + return self - if args.format == "split": - # each efuse block is placed into its own file - for block in efuses.blocks: - if not to_console: - file_dump_name = args.file_name - fname, fextension = os.path.splitext(file_dump_name) - file_dump_name = f"{fname}{block.id}{fextension}" - print(f"Dump efuse block{block.id} -> {file_dump_name}") - dump_file = open(file_dump_name, "wb") - output_block_to_file(block, dump_file, to_console) - if not to_console: - dump_file.close() - elif args.format == "joint": - # all efuse blocks are stored in one file - if not to_console: - print(f"Dump efuse blocks -> {args.file_name}") - dump_file = open(args.file_name, "wb") - for block in efuses.blocks: - output_block_to_file(block, dump_file, to_console) - if not to_console: - dump_file.close() - - -def burn_efuse(esp, efuses, args): - def print_attention(blocked_efuses_after_burn): - if len(blocked_efuses_after_burn): - print( - " ATTENTION! This BLOCK uses NOT the NONE coding scheme " - "and after 'BURN', these efuses can not be burned in the feature:" - ) - for i in range(0, len(blocked_efuses_after_burn), 5): - print( - " ", - "".join("{}".format(blocked_efuses_after_burn[i : i + 5 :])), - ) + def __exit__(self, exc_type, exc_value, traceback): + if ( + self.esp is not None + and not self.external_esp + and isinstance(self.esp, esptool.ESPLoader) + ): + self.esp._port.close() - efuse_name_list = [name for name in args.name_value_pairs.keys()] - burn_efuses_list = [efuses[name] for name in efuse_name_list] - old_value_list = [efuses[name].get_raw() for name in efuse_name_list] - new_value_list = [value for value in args.name_value_pairs.values()] - util.check_duplicate_name_in_list(efuse_name_list) - - attention = "" - print("The efuses to burn:") - for block in efuses.blocks: - burn_list_a_block = [e for e in burn_efuses_list if e.block == block.id] - if len(burn_list_a_block): - print(" from BLOCK%d" % (block.id)) - for field in burn_list_a_block: - print(" - %s" % (field.name)) - if ( - efuses.blocks[field.block].get_coding_scheme() - != efuses.REGS.CODING_SCHEME_NONE - ): - using_the_same_block_names = [ - e.name for e in efuses if e.block == field.block - ] - wr_names = [e.name for e in burn_list_a_block] - blocked_efuses_after_burn = [ - name - for name in using_the_same_block_names - if name not in wr_names - ] - attention = " (see 'ATTENTION!' above)" - if attention: - print_attention(blocked_efuses_after_burn) - - print("\nBurning efuses{}:".format(attention)) - for efuse, new_value in zip(burn_efuses_list, new_value_list): - print( - "\n - '{}' ({}) {} -> {}".format( - efuse.name, - efuse.description, - efuse.get_bitstring(), - efuse.convert_to_bitstring(new_value), + ################################# CLI definitions ################################# + + def add_cli_commands(self, cli: click.Group): + """Add the CLI commands to the given click group""" + + if self.efuses is None: + # This should never happen, but just in case someone calls it from API + raise esptool.FatalError( + "To initialize the CLI commands, you need to call get_efuses() first." ) + + efuses: list[base_fields.EfuseFieldBase] = getattr(self.efuses, "efuses", []) + + @cli.command( + "burn-efuse", + help="Burn the eFuse with the specified name.\n\n" + f"Allowed options for EFUSE_NAME: [{', '.join([e.name for e in efuses])}].", + ) + @click.argument( + "name_value_pairs", + cls=EfuseValuePairArg, + metavar=" ", + required=True, + nargs=-1, + type=EfuseValuePairType( + [e.name for e in efuses] + + [name for e in efuses for name in e.alt_names if name != ""], + self.efuses, + ), ) - efuse.save(new_value) - - print() - if "ENABLE_SECURITY_DOWNLOAD" in efuse_name_list: - print( - "ENABLE_SECURITY_DOWNLOAD -> 1: eFuses will not be read back " - "for confirmation because this mode disables " - "any SRAM and register operations." + @click.option( + "--force", is_flag=True, help="Suppress errors when burning eFuses." ) - print(" espefuse will not work.") - print(" esptool can read/write only flash.") + @click.pass_context + def burn_efuse_cli(ctx, name_value_pairs, force): + self.burn_efuse(name_value_pairs, force) - if "DIS_DOWNLOAD_MODE" in efuse_name_list: - print( - "DIS_DOWNLOAD_MODE -> 1: eFuses will not be read back for " - "confirmation because this mode disables any communication with the chip." + @cli.command( + "read-protect-efuse", + help="Disable readback for the selected eFuse with the specified name.", + short_help="Disable readback for the eFuse.", ) - print( - " espefuse/esptool will not work because " - "they will not be able to connect to the chip." + @click.argument("efuse_name", nargs=-1, required=True) + @click.pass_context + def read_protect_efuse_cli(ctx, efuse_name): + self.read_protect_efuse(efuse_name) + + @cli.command( + "write-protect-efuse", + help="Disable writing to the eFuse with the specified name.", + short_help="Disable writing to the eFuse.", ) + @click.argument("efuse_name", nargs=-1, required=True) + def write_protect_efuse_cli(efuse_name): + """Disable writing to the eFuse with the specified name.""" + self.write_protect_efuse(efuse_name) - if ( - esp.CHIP_NAME == "ESP32" - and esp.get_chip_revision() >= 300 - and "UART_DOWNLOAD_DIS" in efuse_name_list - ): - print( - "UART_DOWNLOAD_DIS -> 1: eFuses will be read for confirmation, " - "but after that connection to the chip will become impossible." + @cli.command( + "burn-block-data", + help="Burn non-key data to EFUSE blocks. " + "(Don't use this command to burn key data for Flash Encryption or ESP32 " + "Secure Boot V1, as the byte order of keys is swapped (use burn-key)).\n\n" + "Allowed options for BLOCK: " + f"[{', '.join(self.efuses.BURN_BLOCK_DATA_NAMES)}].", ) - print(" espefuse/esptool will not work.") + @click.argument( + "block_datafile", + cls=TupleParameter, + metavar=" ", + required=True, + nargs=-1, + max_arity=len(self.efuses.BURN_BLOCK_DATA_NAMES), + type=NonCompositeTuple( + [ + click.Choice(self.efuses.BURN_BLOCK_DATA_NAMES), + click.File("rb"), + ] + ), + ) + @click.option( + "--offset", + "-o", + type=int, + default=0, + help="Byte offset in the eFuse block.", + ) + @add_force_write_always + def burn_block_data_cli(block_datafile, offset, **kwargs): + block, datafile = zip(*block_datafile) + self.burn_block_data(block, datafile, offset) - if efuses.is_efuses_incompatible_for_burn(): - if args.force: - print("Ignore incompatible eFuse settings.") - else: + @cli.command("burn-bit") + @click.argument("block", required=True) + @click.argument( + "bit_number", + nargs=-1, + type=int, + required=True, + ) + @add_force_write_always + def burn_bit_cli(block, bit_number, **kwargs): + """Burn bit in the eFuse block.""" + self.burn_bit(block, bit_number) + + @cli.command("dump") + @click.option( + "--format", + type=click.Choice(["default", "split", "joint"]), + default="default", + help="Select the dump format: default - usual console eFuse dump; " + "joint - all eFuse blocks are stored in one file; " + "split - each eFuse block is placed into its own file.", + ) + @click.option( + "--file-name", + type=click.Path(dir_okay=False, writable=True), + default=None, + help="The path to the file in which to save the dump, if not specified, " + "output to the console.", + ) + def dump_cli(format, file_name): + """Dump raw hex values of all eFuses.""" + self.dump(format, file_name) + + @cli.command("summary") + @click.argument("efuses_to_show", nargs=-1, required=False) + @click.option( + "--format", + type=click.Choice(["summary", "json", "value_only"]), + default="summary", + help="Select the summary format.", + ) + @click.option( + "--file", + type=click.File("w"), + default=sys.stdout, + help="File to save the eFuse summary to.", + ) + def summary_cli(format, file, efuses_to_show=[]): + """Print human-readable summary of eFuse values.""" + self.summary(efuses_to_show, format, file) + + @cli.command("check-error") + @click.option( + "--recovery", is_flag=True, help="Recovery of BLOCKs after encoding errors." + ) + @click.pass_context + def check_error_cli(ctx, recovery): + """Checks eFuse errors.""" + self.check_error(recovery, ctx.obj["do_not_confirm"]) + + @cli.command( + "adc-info", + short_help="Display information about ADC calibration data " + "stored in eFuse.", + help="Display information about ADC calibration data stored in eFuse.", + ) + def adc_info_cli(): + self.adc_info() + + @cli.command( + "burn-custom-mac", + short_help="Burn a 48-bit Custom MAC address.", + help="Burn a 48-bit Custom MAC address to EFUSE," + f"BLOCK{self.efuses['CUSTOM_MAC'].block}. " + "Mac address should be given in hexadecimal format with bytes separated " + "by colons (e.g. AA:CD:EF:01:02:03).", + ) + @click.argument( + "mac", + type=CustomMACType(), + ) + @add_force_write_always + def burn_custom_mac_cli(mac, **kwargs): + self.burn_custom_mac(mac) + + @cli.command("get-custom-mac") + def get_custom_mac_cli(): + """Get the 48-bit Custom MAC Address.""" + self.get_custom_mac() + + ################################## Helper methods ################################## + + def use_batch_mode(self): + """Enable batch mode for eFuse operations. + + This method increments the batch mode counter, allowing multiple eFuse + operations to be queued before burning. All queued operations will be + executed together when :func:`burn_all` is called. + + This method can be called multiple times to nest batch operations. + Each call should be paired with a corresponding call to :func:`burn_all`. + """ + self.efuses.batch_mode_cnt += 1 + + def burn_all(self, check_batch_mode=False): + """Execute all queued eFuse operations and decrement batch mode counter. + + This method decrements the batch mode counter, then burns all eFuses + that have been queued during batch mode. When the counter reaches zero, + batch mode is fully exited. + + This method should be called after :func:`use_batch_mode` to execute + the queued operations. + + Args: + check_batch_mode: If True, only execute the burn operation if this is the + final burn_all call (i.e., when batch_mode_cnt reaches zero in nested + operations). + + Returns: + bool: True if the burn operation was successful. + """ + self.efuses.batch_mode_cnt -= 1 + return self.efuses.burn_all(check_batch_mode) + + def _key_block_is_unused( + self, + block: base_fields.EfuseBlockBase, + key_purpose_block: base_fields.EfuseBlockBase, + ) -> bool: + """Helper method to check if a key block is available for use""" + if not block.is_readable() or not block.is_writeable(): + return False + + if key_purpose_block.get() != "USER" or not key_purpose_block.is_writeable(): + return False + + if not block.get_bitstring().all(False): + return False + + return True + + def _get_next_key_block( + self, current_key_block: base_fields.EfuseBlockBase, block_name_list: list[str] + ) -> base_fields.EfuseBlockBase | None: + """Helper method to get the next available key block""" + key_blocks = [b for b in self.efuses.blocks if b.key_purpose_name] + start = key_blocks.index(current_key_block) + + # Sort key blocks so that we pick the next free block + # (and loop around if necessary) + key_blocks = key_blocks[start:] + key_blocks[0:start] + + # Exclude any other blocks that will be be burned + key_blocks = [b for b in key_blocks if b.name not in block_name_list] + + for block in key_blocks: + key_purpose_block = self.efuses[block.key_purpose_name] + if self._key_block_is_unused(block, key_purpose_block): + return block + + return None + + def _split_512_bit_key( + self, + block_names: list[str], + datafiles: list[BinaryIO], + keypurposes: list[str], + ) -> tuple[list[str], list[BinaryIO], list[str]]: + """Helper method to split 512-bit key into two 256-bit keys""" + keypurpose_list = list(keypurposes) + datafile_list = list(datafiles) + block_name_list = list(block_names) + + i = keypurpose_list.index("XTS_AES_256_KEY") + block_name = block_name_list[i] + + block_num = self.efuses.get_index_block_by_name(block_name) + block = self.efuses.blocks[block_num] + + data = datafile_list[i].read() + if len(data) != 64: raise esptool.FatalError( - "Incompatible eFuse settings detected, abort. (use --force flag to skip it)." + "Incorrect key file size %d, XTS_AES_256_KEY should be 64 bytes" + % len(data) ) - if not efuses.burn_all(check_batch_mode=True): - return + key_block_2 = self._get_next_key_block(block, block_name_list) + if not key_block_2: + raise esptool.FatalError("XTS_AES_256_KEY requires two free keyblocks") - print("Checking efuses...") - raise_error = False - for efuse, old_value, new_value in zip( - burn_efuses_list, old_value_list, new_value_list - ): - if not efuse.is_readable(): - print( - "Efuse %s is read-protected. Read back the burn value is not possible." - % efuse.name - ) - else: - new_value = efuse.convert_to_bitstring(new_value) - burned_value = efuse.get_bitstring() - if burned_value != new_value: - print( - burned_value, - "->", - new_value, - "Efuse %s failed to burn. Protected?" % efuse.name, - ) - raise_error = True - if raise_error: - raise esptool.FatalError("The burn was not successful.") - else: - print("Successful") + keypurpose_list.append("XTS_AES_256_KEY_1") + datafile_list.append(io.BytesIO(data[:32])) + block_name_list.append(block_name) + keypurpose_list.append("XTS_AES_256_KEY_2") + datafile_list.append(io.BytesIO(data[32:])) + block_name_list.append(key_block_2.name) -def read_protect_efuse(esp, efuses, args): - util.check_duplicate_name_in_list(args.efuse_name) + keypurpose_list.pop(i) + datafile_list.pop(i) + block_name_list.pop(i) - for efuse_name in args.efuse_name: - efuse = efuses[efuse_name] - if not efuse.is_readable(): - print("Efuse %s is already read protected" % efuse.name) - else: - if esp.CHIP_NAME == "ESP32": + return block_name_list, datafile_list, keypurpose_list + + def _convert_mac_to_bytes(self, mac: str | bytes) -> bytes: + if isinstance(mac, str): + return base_fields.CheckArgValue(self.efuses, "CUSTOM_MAC")(mac) # type: ignore + return mac + + ##################################### Commands #################################### + + def summary( + self, + efuses_to_show: list[str] = [], + format: str = "summary", + file: TextIO = sys.stdout, + ): + """ + Print a human-readable or json summary of eFuse contents. + + Args: + efuses_to_show: List of eFuse names to show. + format: Format to use for the summary. + file: File to write the summary to. + """ + ROW_FORMAT = "%-50s %-50s%s = %s %s %s" + human_output = format in ["summary", "value_only"] + value_only = format == "value_only" + if value_only and len(efuses_to_show) != 1: + raise esptool.FatalError( + "The 'value_only' format can be used exactly for one eFuse." + ) + do_filtering = bool(efuses_to_show) + json_efuse = {} + summary_efuse = [] + if file != sys.stdout: + log.print("Saving eFuse values to " + file.name) + if human_output and not value_only: + summary_efuse.append( + ROW_FORMAT.replace("-50", "-12") + % ( + "EFUSE_NAME (Block)", + "Description", + "", + "[Meaningful Value]", + "[Readable/Writeable]", + "(Hex Value)", + ) + ) + summary_efuse.append("-" * 88) + for category in sorted( + set(e.category for e in self.efuses), key=lambda c: c.title() + ): + if human_output and not value_only: + summary_efuse.append(f"{category.title()} fuses:") + for e in (e for e in self.efuses if e.category == category): + if e.efuse_type.startswith("bytes"): + raw = "" + else: + raw = "({})".format(e.get_bitstring()) + (readable, writeable) = (e.is_readable(), e.is_writeable()) + if readable and writeable: + perms = "R/W" + elif readable: + perms = "R/-" + elif writeable: + perms = "-/W" + else: + perms = "-/-" + base_value = e.get_meaning() + value = str(base_value) + if not readable: + count_read_disable_bits = e.get_count_read_disable_bits() + if count_read_disable_bits == 2: + # On the C2 chip, BLOCK_KEY0 has two read protection bits [0, 1] + # related to the lower and higher part of the block. + v = [value[: (len(value) // 2)], value[(len(value) // 2) :]] + for i in range(count_read_disable_bits): + if not e.is_readable(blk_part=i): + v[i] = v[i].replace("0", "?") + value = "".join(v) + else: + value = value.replace("0", "?") if ( - efuse_name == "BLOCK2" - and not efuses["ABS_DONE_0"].get() - and esp.get_chip_revision() >= 300 + human_output + and (not do_filtering or e.name in efuses_to_show) + and not value_only ): - if efuses["ABS_DONE_1"].get(): - raise esptool.FatalError( - "Secure Boot V2 is on (ABS_DONE_1 = True), " - "BLOCK2 must be readable, stop this operation!" - ) - else: - print( - "If Secure Boot V2 is used, BLOCK2 must be readable, " - "please stop this operation!" + summary_efuse.append( + ROW_FORMAT + % ( + e.get_info(), + e.description[:50], + "\n " if len(value) > 20 else "", + value, + perms, + raw, ) - elif esp.CHIP_NAME == "ESP32-C2": - error = ( - not efuses["XTS_KEY_LENGTH_256"].get() - and efuse_name == "BLOCK_KEY0" + ) + desc_len = len(e.description[50:]) + if desc_len: + desc_len += 50 + for i in range(50, desc_len, 50): + summary_efuse.append( + f"{'':<50} {e.description[i : (50 + i)]:<50}" + ) + elif human_output and value_only and e.name in efuses_to_show: + summary_efuse.append(f"{value}") + elif format == "json" and ( + not do_filtering or e.name in efuses_to_show + ): + json_efuse[e.name] = { + "name": e.name, + "value": base_value if readable else value, + "readable": readable, + "writeable": writeable, + "description": e.description, + "category": e.category, + "block": e.block, + "word": e.word, + "pos": e.pos, + "efuse_type": e.efuse_type, + "bit_len": e.bit_len, + } + if human_output and not value_only: + # Remove empty category when filtered efuses have none to show + if do_filtering and summary_efuse[-1] == f"{category.title()} fuses:": + summary_efuse.pop() + else: + summary_efuse.append("") + if human_output and not value_only: + summary_efuse.append(self.efuses.summary()) + warnings = self.efuses.get_coding_scheme_warnings() + if warnings: + summary_efuse.append( + "WARNING: Coding scheme has encoding bit error warnings" ) - error |= efuses["SECURE_BOOT_EN"].get() and efuse_name in [ - "BLOCK_KEY0", - "BLOCK_KEY0_HI_128", - ] - if error: - raise esptool.FatalError( - "%s must be readable, stop this operation!" % efuse_name + if human_output: + for line in summary_efuse: + log.print(line, file=file) + if file != sys.stdout: + file.close() + log.print("Done") + elif format == "json": + json.dump(json_efuse, file, sort_keys=True, indent=4) + log.print("") + + def dump(self, format: str = "default", file_name: str | None = None): + """ + Dump raw eFuse data registers. + + Args: + format: Format to use for the dump. Available options are: + - "default": Print the dump to the console. + - "split": Dump each eFuse block to a separate file. + - "joint": Dump all eFuse blocks to a single file. + file_name: File to write the dump to. If not provided, the dump will + be printed to the console. + """ + to_console = file_name is None + dump_file: BinaryIO | TextIO = sys.stdout + + def output_block_to_file( + block: base_fields.EfuseBlockBase, f: BinaryIO | TextIO, to_console: bool + ): + block_dump = BitStream(block.get_bitstring()) + block_dump.byteswap() + if to_console: + f.write(block_dump.hex + "\n") + else: + block_dump.tofile(f) # type: ignore + + if format == "default": + if to_console: + # for "espefuse dump" cmd + for block in self.efuses.blocks: + block.print_block(block.get_bitstring(), "dump", debug=True) + return + else: + # for back compatibility to support + # "espefuse dump --file_name dump.bin" + format = "split" + + if format == "split": + # each eFuse block is placed into its own file + for block in self.efuses.blocks: + if not to_console: + fname, fextension = os.path.splitext(file_name) # type: ignore + file_dump_name = f"{fname}{block.id}{fextension}" + log.print(f"Dump eFuse block{block.id} -> {file_dump_name}") + dump_file = open(file_dump_name, "wb") + output_block_to_file(block, dump_file, to_console) + if not to_console: + dump_file.close() + elif format == "joint": + # all eFuse blocks are stored in one file + if not to_console: + log.print(f"Dump eFuse blocks -> {file_name}") + dump_file = open(file_name, "wb") # type: ignore + for block in self.efuses.blocks: + output_block_to_file(block, dump_file, to_console) + if not to_console: + dump_file.close() + + def burn_efuse(self, name_value_pairs: dict[str, str], force: bool = False): + """ + Burn eFuses. + + Args: + name_value_pairs: Dictionary of eFuse names and values to burn. + force: If True, the burn will be performed even if the eFuse settings + are incompatible. + """ + + def print_attention(blocked_efuses_after_burn: list[str]): + if len(blocked_efuses_after_burn): + log.print( + " ATTENTION! This BLOCK uses NOT the NONE coding scheme " + "and after 'BURN', these efuses can not be burned in the feature:" + ) + for i in range(0, len(blocked_efuses_after_burn), 5): + log.print( + " ", + "".join("{}".format(blocked_efuses_after_burn[i : i + 5 :])), ) + + efuse_name_list = [name for name in name_value_pairs.keys()] + burn_efuses_list = [self.efuses[name] for name in efuse_name_list] + old_value_list = [self.efuses[name].get_raw() for name in efuse_name_list] + new_value_list = [value for value in name_value_pairs.values()] + util.check_duplicate_name_in_list(efuse_name_list) + + attention = "" + log.print("The eFuses to burn:") + for block in self.efuses.blocks: + burn_list_a_block = [e for e in burn_efuses_list if e.block == block.id] + if len(burn_list_a_block): + log.print(" from BLOCK%d" % (block.id)) + for field in burn_list_a_block: + log.print(" - %s" % (field.name)) + if ( + self.efuses.blocks[field.block].get_coding_scheme() + != self.efuses.REGS.CODING_SCHEME_NONE + ): + using_the_same_block_names = [ + e.name for e in self.efuses if e.block == field.block + ] + wr_names = [e.name for e in burn_list_a_block] + blocked_efuses_after_burn = [ + name + for name in using_the_same_block_names + if name not in wr_names + ] + attention = " (see 'ATTENTION!' above)" + if attention: + print_attention(blocked_efuses_after_burn) + + log.print(f"\nBurning eFuses{attention}:") + for efuse, new_value in zip(burn_efuses_list, new_value_list): + log.print( + f" - '{efuse.name}' ({efuse.description}) " + f"{efuse.get_bitstring()} -> {efuse.convert_to_bitstring(new_value)}" + ) + efuse.save(new_value) + + log.print() + if "ENABLE_SECURITY_DOWNLOAD" in efuse_name_list: + log.print( + "ENABLE_SECURITY_DOWNLOAD -> 1: eFuses will not be read back " + "for confirmation because this mode disables " + "any SRAM and register operations." + ) + log.print(" espefuse will not work.") + log.print( + " esptool can read/write only flash." + ) + + if "DIS_DOWNLOAD_MODE" in efuse_name_list: + log.print( + "DIS_DOWNLOAD_MODE -> 1: eFuses will not be read back for confirmation " + "because this mode disables any communication with the chip." + ) + log.print( + " espefuse/esptool will not work because " + "they will not be able to connect to the chip." + ) + + if ( + self.esp.CHIP_NAME == "ESP32" + and self.esp.get_chip_revision() >= 300 + and "UART_DOWNLOAD_DIS" in efuse_name_list + ): + log.print( + "UART_DOWNLOAD_DIS -> 1: eFuses will be read for confirmation, " + "but after that connection to the chip will become impossible." + ) + log.print(" espefuse/esptool will not work.") + + if self.efuses.is_efuses_incompatible_for_burn(): + if force: + log.print("Ignore incompatible eFuse settings.") + else: + raise esptool.FatalError( + "Incompatible eFuse settings detected, abort. " + "(use --force flag to skip it)." + ) + + if not self.efuses.burn_all(check_batch_mode=True): + return + + log.print("Checking eFuses...") + raise_error = False + for efuse, old_value, new_value in zip( + burn_efuses_list, old_value_list, new_value_list + ): + if not efuse.is_readable(): + log.print( + f"Efuse {efuse.name} is read-protected. " + "Read back the burn value is not possible." + ) + else: + new_value = efuse.convert_to_bitstring(new_value) + burned_value = efuse.get_bitstring() + if burned_value != new_value: + log.print( + burned_value, + "->", + new_value, + f"Efuse {efuse.name} failed to burn. Protected?", + ) + raise_error = True + if raise_error: + raise esptool.FatalError("The burn was not successful.") + else: + log.print("Successful.") + + def read_protect_efuse(self, efuse_names: list[str]): + """ + Disable readback for the eFuse with the specified name. + + Args: + efuse_names: List of eFuse names to read-protect. + """ + util.check_duplicate_name_in_list(efuse_names) + + for efuse_name in efuse_names: + efuse = self.efuses[efuse_name] + if not efuse.is_readable(): + log.print(f"Efuse {efuse.name} is already read protected") else: - for block in efuses.Blocks.BLOCKS: - block = efuses.Blocks.get(block) - if block.name == efuse_name and block.key_purpose is not None: - if not efuses[block.key_purpose].need_rd_protect( - efuses[block.key_purpose].get() - ): + if self.esp.CHIP_NAME == "ESP32": + if ( + efuse_name == "BLOCK2" + and not self.efuses["ABS_DONE_0"].get() + and self.esp.get_chip_revision() >= 300 + ): + if self.efuses["ABS_DONE_1"].get(): raise esptool.FatalError( - "%s must be readable, stop this operation!" % efuse_name + "Secure Boot V2 is on (ABS_DONE_1 = True), " + "BLOCK2 must be readable, stop this operation!" ) - break - # make full list of which efuses will be disabled - # (ie share a read disable bit) - all_disabling = [ - e for e in efuses if e.read_disable_bit == efuse.read_disable_bit - ] - names = ", ".join(e.name for e in all_disabling) - print( - "Permanently read-disabling efuse%s %s" - % ("s" if len(all_disabling) > 1 else "", names) + else: + log.print( + "If Secure Boot V2 is used, BLOCK2 must be readable, " + "please stop this operation!" + ) + elif self.esp.CHIP_NAME == "ESP32-C2": + error = ( + not self.efuses["XTS_KEY_LENGTH_256"].get() + and efuse_name == "BLOCK_KEY0" + ) + error |= self.efuses["SECURE_BOOT_EN"].get() and efuse_name in [ + "BLOCK_KEY0", + "BLOCK_KEY0_HI_128", + ] + if error: + raise esptool.FatalError( + "%s must be readable, stop this operation!" % efuse_name + ) + else: + for block in self.efuses.Blocks.BLOCKS: + block = self.efuses.Blocks.get(block) + if block.name == efuse_name and block.key_purpose is not None: + if not self.efuses[block.key_purpose].need_rd_protect( + self.efuses[block.key_purpose].get() + ): + raise esptool.FatalError( + "%s must be readable, stop this operation!" + % efuse_name + ) + break + # make full list of which efuses will be disabled + # (ie share a read disable bit) + all_disabling = [ + e + for e in self.efuses + if e.read_disable_bit == efuse.read_disable_bit + ] + names = ", ".join(e.name for e in all_disabling) + log.print( + "Permanently read-disabling eFuse%s %s" + % ("s" if len(all_disabling) > 1 else "", names) + ) + efuse.disable_read() + + if not self.efuses.burn_all(check_batch_mode=True): + return + + log.print("Checking eFuses...") + raise_error = False + for efuse_name in efuse_names: + efuse = self.efuses[efuse_name] + if efuse.is_readable(): + log.print(f"Efuse {efuse.name} is not read-protected.") + raise_error = True + if raise_error: + raise esptool.FatalError("The burn was not successful.") + else: + log.print("Successful.") + + def write_protect_efuse(self, efuse_names: list[str]): + """ + Disable writing to the eFuse with the specified name. + + Args: + efuse_names: List of eFuse names to write-protect. + """ + util.check_duplicate_name_in_list(efuse_names) + for efuse_name in efuse_names: + efuse = self.efuses[efuse_name] + if not efuse.is_writeable(): + log.print(f"Efuse {efuse.name} is already write protected.") + else: + # make full list of which efuses will be disabled + # (ie share a write disable bit) + all_disabling = [ + e + for e in self.efuses + if e.write_disable_bit == efuse.write_disable_bit + ] + names = ", ".join(e.name for e in all_disabling) + log.print( + "Permanently write-disabling eFuse%s %s" + % ("s" if len(all_disabling) > 1 else "", names) + ) + efuse.disable_write() + + if not self.efuses.burn_all(check_batch_mode=True): + return + + log.print("Checking eFuses...") + raise_error = False + for efuse_name in efuse_names: + efuse = self.efuses[efuse_name] + if efuse.is_writeable(): + log.print(f"Efuse {efuse.name} is not write-protected.") + raise_error = True + if raise_error: + raise esptool.FatalError("The burn was not successful.") + else: + log.print("Successful.") + + def burn_block_data( + self, + block_names: list[str], + datafiles: list[BinaryIO], + offset: int = 0, + ) -> None: + """ + Burn non-key data to EFUSE blocks. + + Don't use this command to burn key data for Flash Encryption or ESP32 + Secure Boot V1, as the byte order of keys is swapped (use burn-key). + + Args: + block_names: List of eFuse block names to burn data to. + datafiles: List of files to read data from. + offset: Byte offset in the eFuse block to start writing data at. + """ + block_name_list = block_names[ + 0 : len([name for name in block_names if name is not None]) : + ] + datafile_list = datafiles[ + 0 : len([name for name in datafiles if name is not None]) : + ] + + util.check_duplicate_name_in_list(block_name_list) + if offset and len(block_name_list) > 1: + raise esptool.FatalError( + "The 'offset' option is not applicable when a few blocks are passed. " + "With 'offset', should only one block be used." ) - efuse.disable_read() - - if not efuses.burn_all(check_batch_mode=True): - return - - print("Checking efuses...") - raise_error = False - for efuse_name in args.efuse_name: - efuse = efuses[efuse_name] - if efuse.is_readable(): - print("Efuse %s is not read-protected." % efuse.name) - raise_error = True - if raise_error: - raise esptool.FatalError("The burn was not successful.") - else: - print("Successful") - - -def write_protect_efuse(esp, efuses, args): - util.check_duplicate_name_in_list(args.efuse_name) - for efuse_name in args.efuse_name: - efuse = efuses[efuse_name] - if not efuse.is_writeable(): - print("Efuse %s is already write protected" % efuse.name) else: - # make full list of which efuses will be disabled - # (ie share a write disable bit) - all_disabling = [ - e for e in efuses if e.write_disable_bit == efuse.write_disable_bit - ] - names = ", ".join(e.name for e in all_disabling) - print( - "Permanently write-disabling efuse%s %s" - % ("s" if len(all_disabling) > 1 else "", names) + if offset: + num_block = self.efuses.get_index_block_by_name(block_name_list[0]) + block: base_fields.EfuseBlockBase = self.efuses.blocks[num_block] + num_bytes = block.get_block_len() + if offset >= num_bytes: + raise esptool.FatalError( + f"Invalid offset: the block{block.id} only holds " + f"{num_bytes} bytes." + ) + if len(block_name_list) != len(datafile_list): + raise esptool.FatalError( + f"The number of block_name ({len(block_name_list)}) and " + f"datafile ({len(datafile_list)}) should be the same." ) - efuse.disable_write() - - if not efuses.burn_all(check_batch_mode=True): - return - - print("Checking efuses...") - raise_error = False - for efuse_name in args.efuse_name: - efuse = efuses[efuse_name] - if efuse.is_writeable(): - print("Efuse %s is not write-protected." % efuse.name) - raise_error = True - if raise_error: - raise esptool.FatalError("The burn was not successful.") - else: - print("Successful") - - -def burn_block_data(esp, efuses, args): - block_name_list = args.block[ - 0 : len([name for name in args.block if name is not None]) : - ] - datafile_list = args.datafile[ - 0 : len([name for name in args.datafile if name is not None]) : - ] - efuses.force_write_always = args.force_write_always - - util.check_duplicate_name_in_list(block_name_list) - if args.offset and len(block_name_list) > 1: - raise esptool.FatalError( - "The 'offset' option is not applicable when a few blocks are passed. " - "With 'offset', should only one block be used." - ) - else: - offset = args.offset - if offset: - num_block = efuses.get_index_block_by_name(block_name_list[0]) - block = efuses.blocks[num_block] + + for block_name, datafile in zip(block_name_list, datafile_list): + num_block = self.efuses.get_index_block_by_name(block_name) + block = self.efuses.blocks[num_block] + data = datafile.read() num_bytes = block.get_block_len() - if offset >= num_bytes: + if offset != 0: + data = (b"\x00" * offset) + data + data = data + (b"\x00" * (num_bytes - len(data))) + if len(data) != num_bytes: raise esptool.FatalError( - "Invalid offset: the block%d only holds %d bytes." - % (block.id, num_bytes) + f"Data does not fit: the block{block.id} size is " + f"{num_bytes} bytes, data file is {len(data)} bytes, " + f"offset {offset}." ) - if len(block_name_list) != len(datafile_list): - raise esptool.FatalError( - "The number of block_name (%d) and datafile (%d) should be the same." - % (len(block_name_list), len(datafile_list)) - ) + log.print( + "[{:02}] {:20} size={:02} bytes, offset={:02} - > [{}].".format( + block.id, block.name, len(data), offset, util.hexify(data, " ") + ) + ) + block.save(data) + + if not self.efuses.burn_all(check_batch_mode=True): + return + log.print("Successful.") - for block_name, datafile in zip(block_name_list, datafile_list): - num_block = efuses.get_index_block_by_name(block_name) - block = efuses.blocks[num_block] - data = datafile.read() - num_bytes = block.get_block_len() - if offset != 0: - data = (b"\x00" * offset) + data - data = data + (b"\x00" * (num_bytes - len(data))) - if len(data) != num_bytes: + def burn_bit(self, block: str, bit_number: list[int]): + """ + Burn a single bit to the eFuse with the specified name. + + Args: + block: Name of the eFuse block to burn the bit to. + bit_number: List of bit numbers to burn. + """ + num_block = self.efuses.get_index_block_by_name(block) + block_obj: base_fields.EfuseBlockBase = self.efuses.blocks[num_block] + data_block = BitStream(block_obj.get_block_len() * 8) + data_block.set(0) + try: + data_block.set(True, bit_number) + except IndexError: raise esptool.FatalError( - "Data does not fit: the block%d size is %d bytes, " - "data file is %d bytes, offset %d" - % (block.id, num_bytes, len(data), offset) - ) - print( - "[{:02}] {:20} size={:02} bytes, offset={:02} - > [{}].".format( - block.id, block.name, len(data), offset, util.hexify(data, " ") + f"{block} has bit_number in [0..{data_block.len - 1}]" ) + data_block.reverse() + log.print( + "bit_number: " + "[%-03d]........................................................[0]" + % (data_block.len - 1) ) - block.save(data) - - if not efuses.burn_all(check_batch_mode=True): - return - print("Successful") - - -def burn_bit(esp, efuses, args): - efuses.force_write_always = args.force_write_always - num_block = efuses.get_index_block_by_name(args.block) - block = efuses.blocks[num_block] - data_block = BitStream(block.get_block_len() * 8) - data_block.set(0) - try: - data_block.set(True, args.bit_number) - except IndexError: - raise esptool.FatalError( - "%s has bit_number in [0..%d]" % (args.block, data_block.len - 1) + log.print("BLOCK%-2d :" % block_obj.id, data_block) + block_obj.print_block(data_block, "regs_to_write", debug=True) + block_obj.save(data_block.bytes[::-1]) + + if not self.efuses.burn_all(check_batch_mode=True): + return + log.print("Successful.") + + def get_error_summary(self): + self.efuses.get_coding_scheme_warnings() + error_in_blocks = any( + blk.fail or blk.num_errors != 0 for blk in self.efuses.blocks ) - data_block.reverse() - print( - "bit_number: " - "[%-03d]........................................................[0]" - % (data_block.len - 1) - ) - print("BLOCK%-2d :" % block.id, data_block) - block.print_block(data_block, "regs_to_write", debug=True) - block.save(data_block.bytes[::-1]) - - if not efuses.burn_all(check_batch_mode=True): - return - print("Successful") - - -def get_error_summary(efuses): - efuses.get_coding_scheme_warnings() - error_in_blocks = any(blk.fail or blk.num_errors != 0 for blk in efuses.blocks) - if not error_in_blocks: - return False - writable = True - for blk in efuses.blocks: - if blk.fail or blk.num_errors: - if blk.id == 0: - for field in efuses: - if field.block == blk.id and (field.fail or field.num_errors): - wr = "writable" if field.is_writeable() else "not writable" - writable &= wr == "writable" - name = field.name - val = field.get() - print(f"BLOCK{field.block:<2}: {name:<40} = {val:<8} ({wr})") - else: - wr = "writable" if blk.is_writeable() else "not writable" - writable &= wr == "writable" - name = f"{blk.name} [ERRORS:{blk.num_errors} FAIL:{int(blk.fail)}]" - val = str(blk.get_bitstring()) - print(f"BLOCK{blk.id:<2}: {name:<40} = {val:<8} ({wr})") - if not writable and error_in_blocks: - print("Not all errors can be fixed because some fields are write-protected!") - return True - - -def check_error(esp, efuses, args): - error_in_blocks = get_error_summary(efuses) - if args.recovery and error_in_blocks: - confirmed = False - for block in reversed(efuses.blocks): - if block.fail or block.num_errors > 0: - if not block.get_bitstring().all(False): - block.save(block.get_bitstring().bytes[::-1]) - if not confirmed: - confirmed = True - efuses.confirm( - "Recovery of block coding errors", args.do_not_confirm - ) - block.burn() - if confirmed: - efuses.update_efuses() - error_in_blocks = get_error_summary(efuses) - if error_in_blocks: - raise esptool.FatalError("Error(s) were detected in eFuses") - print("No errors detected") + if not error_in_blocks: + return False + writable = True + for blk in self.efuses.blocks: + if blk.fail or blk.num_errors: + if blk.id == 0: + for field in self.efuses: + if field.block == blk.id and (field.fail or field.num_errors): + wr = "writable" if field.is_writeable() else "not writable" + writable &= wr == "writable" + name = field.name + val = field.get() + log.print( + f"BLOCK{field.block:<2}: {name:<40} = {val:<8} ({wr})" + ) + else: + wr = "writable" if blk.is_writeable() else "not writable" + writable &= wr == "writable" + name = f"{blk.name} [ERRORS:{blk.num_errors} FAIL:{int(blk.fail)}]" + val = str(blk.get_bitstring()) + log.print(f"BLOCK{blk.id:<2}: {name:<40} = {val:<8} ({wr})") + if not writable and error_in_blocks: + log.print( + "Not all errors can be fixed because some fields are write-protected!" + ) + return True + + def check_error(self, recovery: bool = False, do_not_confirm: bool = False): + """ + Check for errors in the eFuse blocks. + + Args: + recovery: Recovery of BLOCKs after encoding errors. + do_not_confirm: If True, the confirmation will be skipped. + """ + error_in_blocks = self.get_error_summary() + if recovery and error_in_blocks: + confirmed = False + for block in reversed(self.efuses.blocks): + if block.fail or block.num_errors > 0: + if not block.get_bitstring().all(False): + block.save(block.get_bitstring().bytes[::-1]) + if not confirmed: + confirmed = True + self.efuses.confirm( + "Recovery of block coding errors", do_not_confirm + ) + block.burn() + if confirmed: + self.efuses.update_efuses() + error_in_blocks = self.get_error_summary() + if error_in_blocks: + raise esptool.FatalError("Error(s) were detected in eFuses.") + log.print("No errors detected.") + + def burn_custom_mac(self, mac: str | bytes): + """ + Burn a 48-bit Custom MAC Address. + + Args: + mac (str | bytes): Custom MAC Address to burn. e.g. "aa:cd:ef:11:22:33" or + b'\xaa\xcd\xef\x11\x22\x33' + """ + mac = self._convert_mac_to_bytes(mac) + + self.efuses["CUSTOM_MAC"].save(mac) + if not self.efuses.burn_all(check_batch_mode=True): + return + self.get_custom_mac() + log.print("Successful.") + + def get_custom_mac(self): + """Get the Custom MAC Address.""" + log.print(f"Custom MAC Address: {self.efuses['CUSTOM_MAC'].get()}") + + def set_flash_voltage(self, voltage: str): + """ + Set the Flash Voltage. Available only for selected chips. + + Args: + voltage: Voltage to set. Available options are: "1.8V", "3.3V", "OFF" + """ + raise esptool.FatalError("set_flash_voltage is not supported for this chip") + + def adc_info(self): + """Display information about ADC calibration data stored in eFuse.""" + raise NotImplementedError("adc-info is not implemented for this chip") + + @abstractmethod + def burn_key(self, *args, **kwargs): + """Burn a key to the eFuse. Exact implementation is chip-specific.""" + pass + + @abstractmethod + def burn_key_digest(self, *args, **kwargs): + """Burn a key digest to the eFuse. Exact implementation is chip-specific.""" + pass diff --git a/tools/esptool_py/espefuse/efuse/csv_table_parser.py b/tools/esptool_py/espefuse/efuse/csv_table_parser.py index 4bebbb02ab..4fd4cba090 100644 --- a/tools/esptool_py/espefuse/efuse/csv_table_parser.py +++ b/tools/esptool_py/espefuse/efuse/csv_table_parser.py @@ -8,6 +8,8 @@ import re import sys +from esptool.logger import log + class CSVFuseTable(list): @classmethod @@ -94,7 +96,7 @@ def verify_duplicate_name(self): field_name = p.field_name + p.group if field_name != "" and len(duplicates.intersection([field_name])) != 0: fl_error = True - print( + log.print( f"Field at {p.field_name}, {p.efuse_block}, " f"{p.bit_start}, {p.bit_count} have duplicate field_name" ) @@ -137,7 +139,9 @@ def check(p, n): def print_error(p, n, state): raise InputError( - f"Field at {p.field_name}, {p.efuse_block}, {p.bit_start}, {p.bit_count} {state} {n.field_name}, {n.efuse_block}, {n.bit_start}, {n.bit_count}" + f"Field at {p.field_name}, {p.efuse_block}, {p.bit_start}, " + f"{p.bit_count} {state} {n.field_name}, {n.efuse_block}, " + f"{n.bit_start}, {n.bit_count}" ) for p in self: @@ -238,7 +242,8 @@ def verify(self, type_table): if self.bit_start + self.bit_count > max_bits: raise ValidationError( self, - f"The field is outside the boundaries(max_bits = {max_bits}) of the {self.efuse_block} block", + f"The field is outside the boundaries (max_bits = {max_bits}) " + f"of the {self.efuse_block} block", ) def get_bit_count(self, check_define=True): diff --git a/tools/esptool_py/espefuse/efuse/emulate_efuse_controller_base.py b/tools/esptool_py/espefuse/efuse/emulate_efuse_controller_base.py index 232bfaad83..4fd6fee633 100644 --- a/tools/esptool_py/espefuse/efuse/emulate_efuse_controller_base.py +++ b/tools/esptool_py/espefuse/efuse/emulate_efuse_controller_base.py @@ -7,6 +7,7 @@ import re from bitstring import BitStream +from esptool.logger import log class EmulateEfuseControllerBase(object): @@ -96,7 +97,7 @@ def copy_blocks_wr_regs_to_rd_regs(self, updated_block=None): continue data = self.read_block(blk.id, wr_regs=True) if self.debug: - print(blk.name, data.hex) + log.print(blk.name, data.hex) plain_data = self.handle_coding_scheme(blk, data) plain_data = self.check_wr_protection_area(blk.id, plain_data) self.update_block(blk, plain_data) diff --git a/tools/esptool_py/espefuse/efuse/esp32/__init__.py b/tools/esptool_py/espefuse/efuse/esp32/__init__.py index a3b55a8023..641fadaea5 100644 --- a/tools/esptool_py/espefuse/efuse/esp32/__init__.py +++ b/tools/esptool_py/espefuse/efuse/esp32/__init__.py @@ -1,3 +1,5 @@ from . import operations from .emulate_efuse_controller import EmulateEfuseController from .fields import EspEfuses + +commands = operations.ESP32Commands diff --git a/tools/esptool_py/espefuse/efuse/esp32/emulate_efuse_controller.py b/tools/esptool_py/espefuse/efuse/esp32/emulate_efuse_controller.py index 03011fa59f..4f53f10c1f 100644 --- a/tools/esptool_py/espefuse/efuse/esp32/emulate_efuse_controller.py +++ b/tools/esptool_py/espefuse/efuse/esp32/emulate_efuse_controller.py @@ -8,6 +8,7 @@ from .mem_definition import EfuseDefineBlocks, EfuseDefineFields, EfuseDefineRegisters from ..emulate_efuse_controller_base import EmulateEfuseControllerBase, FatalError +from esptool.logger import log class EmulateEfuseController(EmulateEfuseControllerBase): @@ -49,7 +50,7 @@ def wait_idle(): if self.read_reg(self.REGS.EFUSE_REG_CMD) == 0: return raise FatalError( - "Timed out waiting for Efuse controller command to complete" + "Timed out waiting for eFuse controller command to complete" ) self.write_reg(self.REGS.EFUSE_REG_CMD, self.REGS.EFUSE_CMD_WRITE) @@ -89,7 +90,7 @@ def write_raw_coding_scheme(self, value): raise FatalError( "Error during a burning process to set the new coding scheme" ) - print("Set coding scheme = %d" % self.read_raw_coding_scheme()) + log.print(f"Set coding scheme = {self.read_raw_coding_scheme()}") def get_bitlen_of_block(self, blk, wr=False): if blk.id == 0: @@ -104,9 +105,7 @@ def get_bitlen_of_block(self, blk, wr=False): else: return 32 * blk.len * 3 // 4 else: - raise FatalError( - "The {} coding scheme is not supported".format(coding_scheme) - ) + raise FatalError(f"The {coding_scheme} coding scheme is not supported") def handle_coding_scheme(self, blk, data): # it verifies the coding scheme part of data and returns just data @@ -125,7 +124,7 @@ def handle_coding_scheme(self, blk, data): xor_res ^= byte_data mul_res += (i + 1) * bin(byte_data).count("1") if xor_res != chunk_data[6] or mul_res != chunk_data[7]: - print( + log.print( "xor_res ", xor_res, chunk_data[6], diff --git a/tools/esptool_py/espefuse/efuse/esp32/fields.py b/tools/esptool_py/espefuse/efuse/esp32/fields.py index c1a625bcb2..666076b495 100644 --- a/tools/esptool_py/espefuse/efuse/esp32/fields.py +++ b/tools/esptool_py/espefuse/efuse/esp32/fields.py @@ -9,6 +9,7 @@ import time import esptool +from esptool import log from .mem_definition import EfuseDefineBlocks, EfuseDefineFields, EfuseDefineRegisters from .. import base_fields @@ -65,9 +66,6 @@ class EspEfuses(base_fields.EspEfusesBase): Wrapper object to manage the efuse fields in a connected ESP bootloader """ - debug = False - do_not_confirm = False - def __init__( self, esp, @@ -76,14 +74,12 @@ def __init__( do_not_confirm=False, extend_efuse_table=None, ): + super().__init__(esp, skip_connect, debug, do_not_confirm, extend_efuse_table) self.Blocks = EfuseDefineBlocks() self.Fields = EfuseDefineFields(extend_efuse_table) self.REGS = EfuseDefineRegisters self.BURN_BLOCK_DATA_NAMES = self.Blocks.get_burn_block_data_names() self.BLOCKS_FOR_KEYS = self.Blocks.get_blocks_for_keys() - self._esp = esp - self.debug = debug - self.do_not_confirm = do_not_confirm if esp.CHIP_NAME != "ESP32": raise esptool.FatalError( "Expected the 'esp' param for ESP32 chip but got for '%s'." @@ -174,8 +170,8 @@ def read_coding_scheme(self): self.coding_scheme = coding_scheme def print_status_regs(self): - print("") - print( + log.print("") + log.print( "{:27} 0x{:08x}".format( "EFUSE_REG_DEC_STATUS", self.read_reg(self.REGS.EFUSE_REG_DEC_STATUS) ) @@ -212,7 +208,7 @@ def wait_efuse_idle(self): if self.read_reg(self.REGS.EFUSE_REG_CMD) == 0: return raise esptool.FatalError( - "Timed out waiting for Efuse controller command to complete" + "Timed out waiting for eFuse controller command to complete" ) def efuse_read(self): @@ -234,9 +230,9 @@ def get_coding_scheme_warnings(self, silent=False): block.num_errors = 0 block.fail = err != 0 if not silent and block.fail: - print( - "Error(s) in BLOCK%d [ERRORS:%d FAIL:%d]" - % (block.id, block.num_errors, block.fail) + log.print( + f"Error(s) in BLOCK{block.id} " + f"[ERRORS:{block.num_errors} FAIL:{block.fail}]" ) if (self.debug or err) and not silent: self.print_status_regs() @@ -273,7 +269,7 @@ class EfuseMacField(EfuseField): (if MAC_VERSION == 1 then the CUSTOM_MAC is used) """ - def check_format(self, new_value_str): + def check_format(self, new_value_str: str | None): if new_value_str is None: raise esptool.FatalError( "Required MAC Address in AA:CD:EF:01:02:03 format!" @@ -337,10 +333,8 @@ def get(self, from_read=True): def save(self, new_value): def print_field(e, new_value): - print( - " - '{}' ({}) {} -> {}".format( - e.name, e.description, e.get_bitstring(), new_value - ) + log.print( + f" - '{e.name}' ({e.description}) {e.get_bitstring()} -> {new_value}" ) if self.name == "CUSTOM_MAC": @@ -357,9 +351,7 @@ def print_field(e, new_value): if mac_version.get() != 1: if not self.parent.force_write_always: raise esptool.FatalError( - "MAC_VERSION = {}, should be 0 or 1.".format( - mac_version.get() - ) + f"MAC_VERSION = {mac_version.get()}, should be 0 or 1." ) bitarray_mac = self.convert_to_bitstring(new_value) @@ -407,7 +399,7 @@ def get(self, from_read=True): return (hi_bits << 3) + lo_bits def save(self, new_value): - raise esptool.FatalError("Burning %s is not supported" % self.name) + raise esptool.FatalError(f"Burning {self.name} is not supported.") class EfuseSpiPinField(EfuseField): @@ -429,8 +421,7 @@ def check_format(self, new_value_str): ) elif new_value_int > 33: raise esptool.FatalError( - "IO pin %d cannot be set for SPI flash. 0-29, 32 & 33 only." - % new_value_int + f"IO pin {new_value_int} cannot be set for SPI flash. 0-29, 32 & 33 only." ) elif new_value_int in [32, 33]: return str(new_value_int - 2) diff --git a/tools/esptool_py/espefuse/efuse/esp32/operations.py b/tools/esptool_py/espefuse/efuse/esp32/operations.py index e0f419a1c1..8138377cd0 100644 --- a/tools/esptool_py/espefuse/efuse/esp32/operations.py +++ b/tools/esptool_py/espefuse/efuse/esp32/operations.py @@ -1,365 +1,327 @@ # This file includes the operations with eFuses for ESP32 chip # -# SPDX-FileCopyrightText: 2020-2022 Espressif Systems (Shanghai) CO LTD +# SPDX-FileCopyrightText: 2020-2025 Espressif Systems (Shanghai) CO LTD # # SPDX-License-Identifier: GPL-2.0-or-later -import argparse -import os # noqa: F401. It is used in IDF scripts -import traceback +from typing import BinaryIO +import rich_click as click import espsecure import esptool +from esptool.logger import log -from . import fields +from .mem_definition import EfuseDefineBlocks from .. import util +from .fields import EspEfuses from ..base_operations import ( - add_common_commands, + BaseCommands, + NonCompositeTuple, + TupleParameter, add_force_write_always, add_show_sensitive_info_option, - burn_bit, - burn_block_data, - burn_efuse, - check_error, - dump, - read_protect_efuse, - summary, - write_protect_efuse, ) -def add_commands(subparsers, efuses): - add_common_commands(subparsers, efuses) - p = subparsers.add_parser( - "burn_key", - help="Burn a 256-bit key to EFUSE: %s" % ", ".join(efuses.BLOCKS_FOR_KEYS), - ) - p.add_argument( - "--no-protect-key", - help="Disable default read- and write-protecting of the key. " - "If this option is not set, once the key is flashed " - "it cannot be read back or changed.", - action="store_true", - ) - add_force_write_always(p) - add_show_sensitive_info_option(p) - p.add_argument( - "block", - help='Key block to burn. "flash_encryption" (block1), ' - '"secure_boot_v1" (block2), "secure_boot_v2" (block2)', - action="append", - choices=efuses.BLOCKS_FOR_KEYS, - ) - p.add_argument( - "keyfile", - help="File containing 256 bits of binary key data", - action="append", - type=argparse.FileType("rb"), - ) - for _ in efuses.BLOCKS_FOR_KEYS: - p.add_argument( - "block", - help='Key block to burn. "flash_encryption" (block1), ' - '"secure_boot_v1" (block2), "secure_boot_v2" (block2)', - metavar="BLOCK", - nargs="?", - action="append", - choices=efuses.BLOCKS_FOR_KEYS, +class ESP32Commands(BaseCommands): + CHIP_NAME = "ESP32" + efuse_lib = EspEfuses + + ################################### CLI definitions ################################### + + def add_cli_commands(self, cli: click.Group): + super().add_cli_commands(cli) + blocks_for_keys = EfuseDefineBlocks().get_blocks_for_keys() + + @cli.command( + "burn-key", + help="Burn a 256-bit key to EFUSE. Arguments are pairs of block name and " + "key file, containing 256 bits of binary key data.\n\n" + f"Block is one of: [{', '.join(blocks_for_keys)}]", + ) + @click.argument( + "block_keyfile", + metavar=" ", + cls=TupleParameter, + required=True, + nargs=-1, + max_arity=len(blocks_for_keys), + type=NonCompositeTuple([click.Choice(blocks_for_keys), click.File("rb")]), + ) + @click.option( + "--no-protect-key", + is_flag=True, + help="Disable the default read- and write-protection of the key. " + "If this option is not set, once the key is flashed " + "it cannot be read back or changed.", + ) + @add_force_write_always + @add_show_sensitive_info_option + @click.pass_context + def burn_key_cli( + ctx, block_keyfile, no_protect_key, show_sensitive_info, **kwargs + ): + block, keyfile = zip(*block_keyfile) + show_sensitive_info = ctx.show_sensitive_info + self.burn_key(block, keyfile, no_protect_key, show_sensitive_info) + + @cli.command( + "burn-key-digest", + short_help="Parse a RSA public key and burn the digest.", + help="Parse a RSA public key and burn the digest to eFuse for use with Secure Boot V2.", + ) + @click.argument("keyfile", type=click.File("rb")) + @click.option( + "--no-protect-key", + is_flag=True, + help="Disable the default write-protection of the key digest. " + "If this option is not set, once the key is flashed it cannot be changed.", ) - p.add_argument( - "keyfile", - help="File containing 256 bits of binary key data", - metavar="KEYFILE", - nargs="?", - action="append", - type=argparse.FileType("rb"), + @add_force_write_always + @add_show_sensitive_info_option + @click.pass_context + def burn_key_digest_cli( + ctx, keyfile, no_protect_key, show_sensitive_info, **kwargs + ): + kwargs["show_sensitive_info"] = ctx.show_sensitive_info + self.burn_key_digest(keyfile, no_protect_key, show_sensitive_info) + + @cli.command( + "set-flash-voltage", + short_help="Permanently set the internal flash voltage regulator.", ) + @click.argument("voltage", type=click.Choice(["1.8V", "3.3V", "OFF"])) + def set_flash_voltage_cli(voltage): + """Permanently set the internal flash voltage regulator to either 1.8V, 3.3V or OFF. + This means GPIO12 can be high or low at reset without changing the flash voltage.""" + self.set_flash_voltage(voltage) + + ###################################### Commands ###################################### + + def get_custom_mac(self): + version = self.efuses["MAC_VERSION"].get() + if version > 0: + log.print( + f"Custom MAC Address version {version}: {self.efuses['CUSTOM_MAC'].get()}" + ) + else: + log.print("Custom MAC Address is not set in the device.") + + def set_flash_voltage(self, voltage: str): + sdio_force = self.efuses["XPD_SDIO_FORCE"] + sdio_tieh = self.efuses["XPD_SDIO_TIEH"] + sdio_reg = self.efuses["XPD_SDIO_REG"] - burn_key_digest = subparsers.add_parser( - "burn_key_digest", - help="Parse a RSA public key and burn the digest " - "to eFuse for use with Secure Boot V2", - ) - burn_key_digest.add_argument( - "keyfile", help="Key file to digest (PEM format)", type=argparse.FileType("rb") - ) - burn_key_digest.add_argument( - "--no-protect-key", - help="Disable default write-protecting of the key digest. " - "If this option is not set, once the key is flashed it cannot be changed.", - action="store_true", - ) - add_force_write_always(burn_key_digest) - add_show_sensitive_info_option(burn_key_digest) - - p = subparsers.add_parser( - "set_flash_voltage", - help="Permanently set the internal flash voltage regulator " - "to either 1.8V, 3.3V or OFF. This means GPIO12 can be high or low at reset " - "without changing the flash voltage.", - ) - p.add_argument("voltage", help="Voltage selection", choices=["1.8V", "3.3V", "OFF"]) - - p = subparsers.add_parser( - "burn_custom_mac", help="Burn a 48-bit Custom MAC Address to EFUSE BLOCK3." - ) - p.add_argument( - "mac", - help="Custom MAC Address to burn given in hexadecimal format " - "with bytes separated by colons " - "(e.g. AA:CD:EF:01:02:03).", - type=fields.base_fields.CheckArgValue(efuses, "CUSTOM_MAC"), - ) - add_force_write_always(p) - - p = subparsers.add_parser("get_custom_mac", help="Prints the Custom MAC Address.") - - -def burn_custom_mac(esp, efuses, args): - # Writing to BLK3: - # - MAC_VERSION = 1 - # - CUSTOM_MAC = AA:CD:EF:01:02:03 - # - CUSTOM_MAC_CRC = crc8(CUSTOM_MAC) - efuses["CUSTOM_MAC"].save(args.mac) - if not efuses.burn_all(check_batch_mode=True): - return - get_custom_mac(esp, efuses, args) - print("Successful") - - -def get_custom_mac(esp, efuses, args): - version = efuses["MAC_VERSION"].get() - if version > 0: - print( - "Custom MAC Address version {}: {}".format( - version, efuses["CUSTOM_MAC"].get() + # check efuses aren't burned in a way which makes this impossible + if voltage == "OFF" and sdio_reg.get() != 0: + raise esptool.FatalError( + "Can't set flash regulator to OFF as XPD_SDIO_REG eFuse is already burned." ) - ) - else: - print("Custom MAC Address is not set in the device.") + if voltage == "1.8V" and sdio_tieh.get() != 0: + raise esptool.FatalError( + "Can't set regulator to 1.8V is XPD_SDIO_TIEH eFuse is already burned." + ) -def set_flash_voltage(esp, efuses, args): - sdio_force = efuses["XPD_SDIO_FORCE"] - sdio_tieh = efuses["XPD_SDIO_TIEH"] - sdio_reg = efuses["XPD_SDIO_REG"] + if voltage == "OFF": + log.print( + "Disable internal flash voltage regulator (VDD_SDIO). " + "SPI flash will need to be powered from an external source.\n" + "The following eFuse is burned: XPD_SDIO_FORCE.\n" + "It is possible to later re-enable the internal regulator" + f"{'to 3.3V' if sdio_tieh.get() != 0 else 'to 1.8V or 3.3V'}" + "by burning an additional eFuse." + ) + elif voltage == "1.8V": + log.print( + "Set internal flash voltage regulator (VDD_SDIO) to 1.8V.\n" + "The following eFuses are burned: XPD_SDIO_FORCE, XPD_SDIO_REG.\n" + "It is possible to later increase the voltage to 3.3V (permanently) " + "by burning additional eFuse XPD_SDIO_TIEH." + ) + elif voltage == "3.3V": + log.print( + "Enable internal flash voltage regulator (VDD_SDIO) to 3.3V.\n" + "The following eFuses are burned: XPD_SDIO_FORCE, XPD_SDIO_REG, XPD_SDIO_TIEH." + ) - # check efuses aren't burned in a way which makes this impossible - if args.voltage == "OFF" and sdio_reg.get() != 0: - raise esptool.FatalError( - "Can't set flash regulator to OFF as XPD_SDIO_REG efuse is already burned" - ) + sdio_force.save(1) # Disable GPIO12 + if voltage != "OFF": + sdio_reg.save(1) # Enable internal regulator + if voltage == "3.3V": + sdio_tieh.save(1) + log.print("VDD_SDIO setting complete.") + if not self.efuses.burn_all(check_batch_mode=True): + return + log.print("Successful.") + + def adc_info(self): + adc_vref = self.efuses["ADC_VREF"] + blk3_reserve = self.efuses["BLK3_PART_RESERVE"] + + vref_raw = adc_vref.get_raw() + if vref_raw == 0: + log.print("ADC VRef calibration: None (1100mV nominal)") + else: + log.print(f"ADC VRef calibration: {adc_vref.get()}mV") + + if blk3_reserve.get(): + log.print("ADC readings stored in eFuse BLOCK3:") + log.print( + f" ADC1 Low reading (150mV): {self.efuses['ADC1_TP_LOW'].get()}" + ) + log.print( + f" ADC1 High reading (850mV): {self.efuses['ADC1_TP_HIGH'].get()}" + ) + log.print( + f" ADC2 Low reading (150mV): {self.efuses['ADC2_TP_LOW'].get()}" + ) + log.print( + f" ADC2 High reading (850mV): {self.efuses['ADC2_TP_HIGH'].get()}" + ) - if args.voltage == "1.8V" and sdio_tieh.get() != 0: - raise esptool.FatalError( - "Can't set regulator to 1.8V is XPD_SDIO_TIEH efuse is already burned" - ) + def burn_key( + self, + block: list[str], + keyfile: list[BinaryIO], + no_protect_key: bool = False, + show_sensitive_info: bool = False, + ): + """Burn a 256-bit key to EFUSE. Arguments are pairs of block name and + key file, containing 256 bits of binary key data. + + Args: + block: List of eFuse block names to burn keys to. + keyfile: List of open files to read key data from. + no_protect_key: If True, the write protection will NOT be enabled. + show_sensitive_info: If True, the sensitive information will be shown. + """ + datafile_list = keyfile[ + 0 : len([keyfile for keyfile in keyfile if keyfile is not None]) : + ] + block_name_list = block[ + 0 : len([block for block in block if block is not None]) : + ] + + util.check_duplicate_name_in_list(block_name_list) + if len(block_name_list) != len(datafile_list): + raise esptool.FatalError( + f"The number of blocks ({len(block_name_list)}) " + f"and datafile ({len(datafile_list)}) should be the same." + ) - if args.voltage == "OFF": - msg = "Disable internal flash voltage regulator (VDD_SDIO). " - "SPI flash will need to be powered from an external source.\n" - "The following efuse is burned: XPD_SDIO_FORCE.\n" - "It is possible to later re-enable the internal regulator (%s) " % ( - "to 3.3V" if sdio_tieh.get() != 0 else "to 1.8V or 3.3V" - ) - "by burning an additional efuse" - elif args.voltage == "1.8V": - msg = "Set internal flash voltage regulator (VDD_SDIO) to 1.8V.\n" - "The following efuses are burned: XPD_SDIO_FORCE, XPD_SDIO_REG.\n" - "It is possible to later increase the voltage to 3.3V (permanently) " - "by burning additional efuse XPD_SDIO_TIEH" - elif args.voltage == "3.3V": - msg = "Enable internal flash voltage regulator (VDD_SDIO) to 3.3V.\n" - "The following efuses are burned: XPD_SDIO_FORCE, XPD_SDIO_REG, XPD_SDIO_TIEH." - print(msg) - sdio_force.save(1) # Disable GPIO12 - if args.voltage != "OFF": - sdio_reg.save(1) # Enable internal regulator - if args.voltage == "3.3V": - sdio_tieh.save(1) - print("VDD_SDIO setting complete.") - if not efuses.burn_all(check_batch_mode=True): - return - print("Successful") - - -def adc_info(esp, efuses, args): - adc_vref = efuses["ADC_VREF"] - blk3_reserve = efuses["BLK3_PART_RESERVE"] - - vref_raw = adc_vref.get_raw() - if vref_raw == 0: - print("ADC VRef calibration: None (1100mV nominal)") - else: - print("ADC VRef calibration: %dmV" % adc_vref.get()) - - if blk3_reserve.get(): - print("ADC readings stored in efuse BLOCK3:") - print(" ADC1 Low reading (150mV): %d" % efuses["ADC1_TP_LOW"].get()) - print(" ADC1 High reading (850mV): %d" % efuses["ADC1_TP_HIGH"].get()) - print(" ADC2 Low reading (150mV): %d" % efuses["ADC2_TP_LOW"].get()) - print(" ADC2 High reading (850mV): %d" % efuses["ADC2_TP_HIGH"].get()) - - -def burn_key(esp, efuses, args): - datafile_list = args.keyfile[ - 0 : len([keyfile for keyfile in args.keyfile if keyfile is not None]) : - ] - block_name_list = args.block[ - 0 : len([block for block in args.block if block is not None]) : - ] - efuses.force_write_always = args.force_write_always - no_protect_key = args.no_protect_key - - util.check_duplicate_name_in_list(block_name_list) - if len(block_name_list) != len(datafile_list): - raise esptool.FatalError( - "The number of blocks (%d) and datafile (%d) should be the same." - % (len(block_name_list), len(datafile_list)) - ) + log.print("Burn keys to blocks:") + for block_name, datafile in zip(block_name_list, datafile_list): + efuse = None + for blk in self.efuses.blocks: + if block_name == blk.name or block_name in blk.alias: + efuse = self.efuses[blk.name] + if efuse is None: + raise esptool.FatalError(f"Unknown block name - {block_name}.") + num_bytes = efuse.bit_len // 8 + data = datafile.read() + datafile.close() + revers_msg = None + if block_name in ("flash_encryption", "secure_boot_v1"): + revers_msg = "\tReversing the byte order..." + data = data[::-1] + log.print(f" - {efuse.name}", end=" ") + log.print( + "-> [{}]".format( + util.hexify(data, " ") + if show_sensitive_info + else " ".join(["??"] * len(data)) + ) + ) + if revers_msg: + log.print(revers_msg) + if len(data) != num_bytes: + raise esptool.FatalError( + f"Incorrect key file size {len(data)}. Key file must be {num_bytes}" + f" bytes ({num_bytes * 8} bits) of raw binary key data." + ) - print("Burn keys to blocks:") - for block_name, datafile in zip(block_name_list, datafile_list): - efuse = None - for block in efuses.blocks: - if block_name == block.name or block_name in block.alias: - efuse = efuses[block.name] - if efuse is None: - raise esptool.FatalError("Unknown block name - %s" % (block_name)) - num_bytes = efuse.bit_len // 8 - data = datafile.read() - revers_msg = None - if block_name in ("flash_encryption", "secure_boot_v1"): - revers_msg = "\tReversing the byte order" - data = data[::-1] - print(" - %s" % (efuse.name), end=" ") - print( - "-> [{}]".format( - util.hexify(data, " ") - if args.show_sensitive_info - else " ".join(["??"] * len(data)) + efuse.save(data) + + if block_name in ("flash_encryption", "secure_boot_v1"): + if not no_protect_key: + log.print("\tDisabling read to key block...") + efuse.disable_read() + + if not no_protect_key: + log.print("\tDisabling write to key block...") + efuse.disable_write() + log.print("") + + if no_protect_key: + log.print("Key is left unprotected as per --no-protect-key argument.") + + msg = "Burn keys in eFuse blocks.\n" + if no_protect_key: + msg += ( + "The key block will be left readable and writeable " + "(due to --no-protect-key)." ) - ) - if revers_msg: - print(revers_msg) - if len(data) != num_bytes: + else: + msg += ( + "The key block will be read and write protected " + "(no further changes or readback)." + ) + log.print(msg, "\n") + if not self.efuses.burn_all(check_batch_mode=True): + return + log.print("Successful.") + + def burn_key_digest( + self, + keyfile: BinaryIO, + no_protect_key: bool = False, + show_sensitive_info: bool = False, + ): + """Parse a RSA public key and burn the digest to eFuse for use with Secure Boot V2. + + Args: + keyfile: Open file to read key data from. + no_protect_key: If True, the write protection will NOT be enabled. + show_sensitive_info: If True, the sensitive information will be shown. + """ + if self.efuses.coding_scheme == self.efuses.REGS.CODING_SCHEME_34: raise esptool.FatalError( - "Incorrect key file size %d. " - "Key file must be %d bytes (%d bits) of raw binary key data." - % (len(data), num_bytes, num_bytes * 8) + "burn-key-digest only works with 'None' coding scheme" ) - efuse.save(data) + chip_revision = self.esp.get_chip_revision() + if chip_revision < 300: + raise esptool.FatalError( + "Incorrect chip revision for Secure boot v2. " + "Detected: v%d.%d. Expected: >= v3.0" + % (chip_revision / 100, chip_revision % 100) + ) - if block_name in ("flash_encryption", "secure_boot_v1"): - if not no_protect_key: - print("\tDisabling read to key block") - efuse.disable_read() + digest = espsecure._digest_sbv2_public_key(keyfile) + efuse = self.efuses["BLOCK2"] + num_bytes = efuse.bit_len // 8 + if len(digest) != num_bytes: + raise esptool.FatalError( + f"Incorrect digest size {len(digest)}. " + f"Digest must be {num_bytes} bytes " + f"({num_bytes * 8} bits) of raw binary key data." + ) + log.print(f" - {efuse.name}", end=" ") + log.print( + "-> [{}]".format( + util.hexify(digest, " ") + if show_sensitive_info + else " ".join(["??"] * len(digest)) + ) + ) + efuse.save(digest) if not no_protect_key: - print("\tDisabling write to key block") + log.print(f"Disabling write to eFuse {efuse.name}...") efuse.disable_write() - print("") - if args.no_protect_key: - print("Key is left unprotected as per --no-protect-key argument.") - - msg = "Burn keys in efuse blocks.\n" - if no_protect_key: - msg += ( - "The key block will left readable and writeable (due to --no-protect-key)" - ) - else: - msg += "The key block will be read and write protected " - "(no further changes or readback)" - print(msg, "\n") - if not efuses.burn_all(check_batch_mode=True): - return - print("Successful") - - -def burn_key_digest(esp, efuses, args): - if efuses.coding_scheme == efuses.REGS.CODING_SCHEME_34: - raise esptool.FatalError("burn_key_digest only works with 'None' coding scheme") - - chip_revision = esp.get_chip_revision() - if chip_revision < 300: - raise esptool.FatalError( - "Incorrect chip revision for Secure boot v2. " - "Detected: v%d.%d. Expected: >= v3.0" - % (chip_revision / 100, chip_revision % 100) - ) - - digest = espsecure._digest_sbv2_public_key(args.keyfile) - efuse = efuses["BLOCK2"] - num_bytes = efuse.bit_len // 8 - if len(digest) != num_bytes: - raise esptool.FatalError( - "Incorrect digest size %d. " - "Digest must be %d bytes (%d bits) of raw binary key data." - % (len(digest), num_bytes, num_bytes * 8) - ) - print(" - %s" % (efuse.name), end=" ") - print( - "-> [{}]".format( - util.hexify(digest, " ") - if args.show_sensitive_info - else " ".join(["??"] * len(digest)) - ) - ) - - efuse.save(digest) - if not args.no_protect_key: - print("Disabling write to efuse %s..." % (efuse.name)) - efuse.disable_write() - - if not efuses.burn_all(check_batch_mode=True): - return - print("Successful") - - -def espefuse(esp, efuses, args, command): - parser = argparse.ArgumentParser() - subparsers = parser.add_subparsers(dest="operation") - add_commands(subparsers, efuses) - try: - cmd_line_args = parser.parse_args(command.split()) - except SystemExit: - traceback.print_stack() - raise esptool.FatalError('"{}" - incorrect command'.format(command)) - if cmd_line_args.operation == "execute_scripts": - configfiles = cmd_line_args.configfiles - index = cmd_line_args.index - # copy arguments from args to cmd_line_args - vars(cmd_line_args).update(vars(args)) - if cmd_line_args.operation == "execute_scripts": - cmd_line_args.configfiles = configfiles - cmd_line_args.index = index - if cmd_line_args.operation is None: - parser.print_help() - parser.exit(1) - operation_func = globals()[cmd_line_args.operation] - # each 'operation' is a module-level function of the same name - operation_func(esp, efuses, cmd_line_args) - - -def execute_scripts(esp, efuses, args): - efuses.batch_mode_cnt += 1 - del args.operation - scripts = args.scripts - del args.scripts - - for file in scripts: - with open(file.name, "r") as file: - exec(compile(file.read(), file.name, "exec")) - - if args.debug: - for block in efuses.blocks: - data = block.get_bitstring(from_read=False) - block.print_block(data, "regs_for_burn", args.debug) - - efuses.batch_mode_cnt -= 1 - if not efuses.burn_all(check_batch_mode=True): - return - print("Successful") + if not self.efuses.burn_all(check_batch_mode=True): + return + log.print("Successful.") diff --git a/tools/esptool_py/espefuse/efuse/esp32c2/__init__.py b/tools/esptool_py/espefuse/efuse/esp32c2/__init__.py index a3b55a8023..167574c94b 100644 --- a/tools/esptool_py/espefuse/efuse/esp32c2/__init__.py +++ b/tools/esptool_py/espefuse/efuse/esp32c2/__init__.py @@ -1,3 +1,5 @@ from . import operations from .emulate_efuse_controller import EmulateEfuseController from .fields import EspEfuses + +commands = operations.ESP32C2Commands diff --git a/tools/esptool_py/espefuse/efuse/esp32c2/fields.py b/tools/esptool_py/espefuse/efuse/esp32c2/fields.py index a9fe33cce4..a2923b7db5 100644 --- a/tools/esptool_py/espefuse/efuse/esp32c2/fields.py +++ b/tools/esptool_py/espefuse/efuse/esp32c2/fields.py @@ -12,6 +12,7 @@ from bitstring import BitArray import esptool +from esptool.logger import log import reedsolo @@ -55,9 +56,6 @@ class EspEfuses(base_fields.EspEfusesBase): Wrapper object to manage the efuse fields in a connected ESP bootloader """ - debug = False - do_not_confirm = False - def __init__( self, esp, @@ -66,14 +64,12 @@ def __init__( do_not_confirm=False, extend_efuse_table=None, ): + super().__init__(esp, skip_connect, debug, do_not_confirm, extend_efuse_table) self.Blocks = EfuseDefineBlocks() self.Fields = EfuseDefineFields(extend_efuse_table) self.REGS = EfuseDefineRegisters self.BURN_BLOCK_DATA_NAMES = self.Blocks.get_burn_block_data_names() self.BLOCKS_FOR_KEYS = self.Blocks.get_blocks_for_keys() - self._esp = esp - self.debug = debug - self.do_not_confirm = do_not_confirm if esp.CHIP_NAME != "ESP32-C2": raise esptool.FatalError( "Expected the 'esp' param for ESP32-C2 chip but got for '%s'." @@ -102,7 +98,7 @@ def __init__( for efuse in self.Fields.BLOCK2_CALIBRATION_EFUSES ] else: - if self["BLK_VERSION_MINOR"].get() == 1: + if self.get_block_version() >= 1: self.efuses += [ EfuseField.convert(self, efuse) for efuse in self.Fields.BLOCK2_CALIBRATION_EFUSES @@ -133,9 +129,9 @@ def read_coding_scheme(self): self.coding_scheme = self.REGS.CODING_SCHEME_RS def print_status_regs(self): - print("") + log.print("") self.blocks[0].print_block(self.blocks[0].err_bitarray, "err__regs", debug=True) - print( + log.print( "{:27} 0x{:08x}".format( "EFUSE_RD_RS_ERR_REG", self.read_reg(self.REGS.EFUSE_RD_RS_ERR_REG) ) @@ -168,7 +164,7 @@ def wait_efuse_idle(self): # For PGM_CMD it is not necessary. return raise esptool.FatalError( - "Timed out waiting for Efuse controller command to complete" + "Timed out waiting for eFuse controller command to complete" ) def efuse_program(self, block): @@ -196,30 +192,30 @@ def efuse_read(self): try: self._esp = self.reconnect_chip(self._esp) except esptool.FatalError: - print("Can not re-connect to the chip") + log.print("Can not re-connect to the chip.") if not self["DIS_DOWNLOAD_MODE"].get() and self[ "DIS_DOWNLOAD_MODE" ].get(from_read=False): - print( + log.print( "This is the correct behavior as we are actually burning " - "DIS_DOWNLOAD_MODE which disables the connection to the chip" + "DIS_DOWNLOAD_MODE which disables the connection to the chip." ) - print("DIS_DOWNLOAD_MODE is enabled") - print("Successful") + log.print("DIS_DOWNLOAD_MODE is enabled.") + log.print("Successful.") sys.exit(0) # finish without errors raise - print("Established a connection with the chip") + log.print("Established a connection with the chip.") if self._esp.secure_download_mode and not secure_download_mode_before: - print("Secure download mode is enabled") + log.print("Secure download mode is enabled.") if not self["ENABLE_SECURITY_DOWNLOAD"].get() and self[ "ENABLE_SECURITY_DOWNLOAD" ].get(from_read=False): - print( - "espefuse tool can not continue to work in Secure download mode" + log.print( + "espefuse can not continue to work in Secure download mode." ) - print("ENABLE_SECURITY_DOWNLOAD is enabled") - print("Successful") + log.print("ENABLE_SECURITY_DOWNLOAD is enabled.") + log.print("Successful.") sys.exit(0) # finish without errors raise @@ -279,9 +275,9 @@ def get_coding_scheme_warnings(self, silent=False): block.num_errors = (reg_value >> err_num_offs) & err_num_mask ret_fail |= block.fail if not silent and (block.fail or block.num_errors): - print( - "Error(s) in BLOCK%d [ERRORS:%d FAIL:%d]" - % (block.id, block.num_errors, block.fail) + log.print( + f"Error(s) in BLOCK{block.id} " + f"[ERRORS:{block.num_errors} FAIL:{block.fail}]" ) if (self.debug or ret_fail) and not silent: self.print_status_regs() @@ -346,7 +342,7 @@ def check_format(self, new_value_str): def check(self): errs, fail = self.parent.get_block_errors(self.block) if errs != 0 or fail: - output = "Block%d has ERRORS:%d FAIL:%d" % (self.block, errs, fail) + output = f"Block{self.block} has ERRORS:{errs} FAIL:{fail}" else: output = "OK" return "(" + output + ")" @@ -356,14 +352,12 @@ def get(self, from_read=True): mac = self.get_raw(from_read)[::-1] else: mac = self.get_raw(from_read) - return "%s %s" % (util.hexify(mac, ":"), self.check()) + return f"{util.hexify(mac, ':')} {self.check()}" def save(self, new_value): def print_field(e, new_value): - print( - " - '{}' ({}) {} -> {}".format( - e.name, e.description, e.get_bitstring(), new_value - ) + log.print( + f" - '{e.name}' ({e.description}) {e.get_bitstring()} -> {new_value}" ) if self.name == "CUSTOM_MAC": @@ -371,7 +365,7 @@ def print_field(e, new_value): print_field(self, bitarray_mac) super(EfuseMacField, self).save(new_value) else: - raise esptool.FatalError("Writing Factory MAC address is not supported") + raise esptool.FatalError("Writing Factory MAC address is not supported.") class EfuseKeyPurposeField(EfuseField): diff --git a/tools/esptool_py/espefuse/efuse/esp32c2/mem_definition.py b/tools/esptool_py/espefuse/efuse/esp32c2/mem_definition.py index 47cd18c047..05b3135cda 100644 --- a/tools/esptool_py/espefuse/efuse/esp32c2/mem_definition.py +++ b/tools/esptool_py/espefuse/efuse/esp32c2/mem_definition.py @@ -97,10 +97,7 @@ class EfuseDefineFields(EfuseFieldsBase): def __init__(self, extend_efuse_table) -> None: # List of efuse fields from TRM the chapter eFuse Controller. self.EFUSES = [] - self.KEYBLOCKS = [] - - # if BLK_VERSION_MINOR is 1, these efuse fields are in BLOCK2 self.BLOCK2_CALIBRATION_EFUSES = [] dir_name = os.path.dirname(os.path.abspath(__file__)) diff --git a/tools/esptool_py/espefuse/efuse/esp32c2/operations.py b/tools/esptool_py/espefuse/efuse/esp32c2/operations.py index d23f6a721b..4e51f84b8d 100644 --- a/tools/esptool_py/espefuse/efuse/esp32c2/operations.py +++ b/tools/esptool_py/espefuse/efuse/esp32c2/operations.py @@ -1,351 +1,292 @@ # This file includes the operations with eFuses for ESP32-C2 chip # -# SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD +# SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD # # SPDX-License-Identifier: GPL-2.0-or-later -import argparse -import os # noqa: F401. It is used in IDF scripts -import traceback +from io import IOBase +from typing import BinaryIO +import rich_click as click import espsecure - import esptool +from esptool.logger import log from . import fields +from .mem_definition import EfuseDefineBlocks from .. import util from ..base_operations import ( - add_common_commands, + BaseCommands, + NonCompositeTuple, + TupleParameter, add_force_write_always, add_show_sensitive_info_option, - burn_bit, - burn_block_data, - burn_efuse, - check_error, - dump, - read_protect_efuse, - summary, - write_protect_efuse, + protect_options, ) -def protect_options(p): - p.add_argument( - "--no-write-protect", - help="Disable write-protecting of the key. The key remains writable. " - "(The keys use the RS coding scheme that does not support " - "post-write data changes. Forced write can damage RS encoding bits.) " - "The write-protecting of keypurposes does not depend on the option, " - "it will be set anyway.", - action="store_true", - ) - p.add_argument( - "--no-read-protect", - help="Disable read-protecting of the key. The key remains readable software.", - action="store_true", - ) +class ESP32C2Commands(BaseCommands): + CHIP_NAME = "ESP32-C2" + efuse_lib = fields.EspEfuses + + ################################### CLI definitions ################################### + def add_cli_commands(self, cli: click.Group): + super().add_cli_commands(cli) + blocks_for_keys = EfuseDefineBlocks().get_blocks_for_keys() -def add_commands(subparsers, efuses): - add_common_commands(subparsers, efuses) - burn_key = subparsers.add_parser( - "burn_key", help="Burn the key block with the specified name" - ) - protect_options(burn_key) - add_force_write_always(burn_key) - add_show_sensitive_info_option(burn_key) - burn_key.add_argument( - "block", - help="Key block to burn", - action="append", - choices=efuses.BLOCKS_FOR_KEYS, - ) - burn_key.add_argument( - "keyfile", - help="File containing 128/256 bits of binary key data", - action="append", - type=argparse.FileType("rb"), - ) - burn_key.add_argument( - "keypurpose", - help="Purpose to set.", - action="append", - choices=fields.EfuseKeyPurposeField.KEY_PURPOSES_NAME, - ) - for _ in range(1): - burn_key.add_argument( - "block", - help="Key block to burn", - nargs="?", - action="append", - metavar="BLOCK", - choices=efuses.BLOCKS_FOR_KEYS, + @cli.command( + "burn-key", + help="Burn the key block with the specified name. Arguments are groups of block name, " + "key file (containing 128/256 bits of binary key data) and key purpose.\n\n" + f"Block is one of: [{', '.join(blocks_for_keys)}]\n\n" + f"Key purpose is one of: [{', '.join(fields.EfuseKeyPurposeField.KEY_PURPOSES_NAME)}]", ) - burn_key.add_argument( - "keyfile", - help="File containing 128/256 bits of binary key data", - nargs="?", - action="append", - metavar="KEYFILE", - type=argparse.FileType("rb"), + @click.argument( + "block_keyfile_keypurpose", + metavar=" ", + cls=TupleParameter, + nargs=-1, + # we need to add +1 here as this chip has only one key block. SB and FE + # keys will share this key block if both of them have to be written. + max_arity=len(blocks_for_keys) + 1, + type=NonCompositeTuple( + [ + click.Choice(blocks_for_keys), + click.File("rb"), + click.Choice(fields.EfuseKeyPurposeField.KEY_PURPOSES_NAME), + ] + ), ) - burn_key.add_argument( - "keypurpose", - help="Purpose to set.", - nargs="?", - action="append", - metavar="KEYPURPOSE", - choices=fields.EfuseKeyPurposeField.KEY_PURPOSES_NAME, + @protect_options + @add_force_write_always + @add_show_sensitive_info_option + @click.pass_context + def burn_key_cli(ctx, **kwargs): + """Burn the key block with the specified name""" + block, keyfile, keypurpose = zip(*kwargs.pop("block_keyfile_keypurpose")) + kwargs.pop("force_write_always") + kwargs["show_sensitive_info"] = ctx.show_sensitive_info + self.burn_key(block, keyfile, keypurpose, **kwargs) + + @cli.command( + "burn-key-digest", + short_help="Parse an ECDSA public key and burn the digest.", + help="Parse an ECDSA public key and burn the digest to higher 128-bits of BLOCK_KEY0. " + "KEYFILE is in PEM format.", ) - - burn_key_digest = subparsers.add_parser( - "burn_key_digest", - help="Parse an ECDSA public key and burn the digest " - "to higher 128-bits of BLOCK_KEY0", - ) - protect_options(burn_key_digest) - add_force_write_always(burn_key_digest) - add_show_sensitive_info_option(burn_key_digest) - burn_key_digest.add_argument( - "keyfile", help="Key file to digest (PEM format)", type=argparse.FileType("rb") - ) - - p = subparsers.add_parser( - "set_flash_voltage", - help="Permanently set the internal flash voltage regulator " - "to either 1.8V, 3.3V or OFF. This means GPIO45 can be high or low " - "at reset without changing the flash voltage.", - ) - p.add_argument("voltage", help="Voltage selection", choices=["1.8V", "3.3V", "OFF"]) - - p = subparsers.add_parser( - "burn_custom_mac", help="Burn a 48-bit Custom MAC Address to EFUSE BLOCK1." - ) - p.add_argument( - "mac", - help="Custom MAC Address to burn given in hexadecimal format " - "with bytes separated by colons (e.g. AA:CD:EF:01:02:03).", - type=fields.base_fields.CheckArgValue(efuses, "CUSTOM_MAC"), - ) - add_force_write_always(p) - - p = subparsers.add_parser("get_custom_mac", help="Prints the Custom MAC Address.") - - -def burn_custom_mac(esp, efuses, args): - efuses["CUSTOM_MAC"].save(args.mac) - efuses["CUSTOM_MAC_USED"].save(1) - if not efuses.burn_all(check_batch_mode=True): - return - get_custom_mac(esp, efuses, args) - print("Successful") - - -def get_custom_mac(esp, efuses, args): - print("Custom MAC Address: {}".format(efuses["CUSTOM_MAC"].get())) - - -def set_flash_voltage(esp, efuses, args): - raise esptool.FatalError("set_flash_voltage is not supported!") - - -def adc_info(esp, efuses, args): - print("") - # fmt: off - if efuses["BLK_VERSION_MINOR"].get() == 1: - print("Temperature Sensor Calibration = {}C".format(efuses["TEMP_CALIB"].get())) - print("ADC OCode = ", efuses["OCODE"].get()) - print("ADC1:") - print("INIT_CODE_ATTEN0 = ", efuses["ADC1_INIT_CODE_ATTEN0"].get()) - print("INIT_CODE_ATTEN3 = ", efuses["ADC1_INIT_CODE_ATTEN3"].get()) - print("CAL_VOL_ATTEN0 = ", efuses["ADC1_CAL_VOL_ATTEN0"].get()) - print("CAL_VOL_ATTEN3 = ", efuses["ADC1_CAL_VOL_ATTEN3"].get()) - else: - print("BLK_VERSION_MINOR = {}".format(efuses["BLK_VERSION_MINOR"].get_meaning())) - # fmt: on - - -def burn_key(esp, efuses, args, digest=None): - if digest is None: - datafile_list = args.keyfile[ - 0 : len([name for name in args.keyfile if name is not None]) : - ] - else: - datafile_list = digest[0 : len([name for name in digest if name is not None]) :] - efuses.force_write_always = args.force_write_always - block_name_list = args.block[ - 0 : len([name for name in args.block if name is not None]) : - ] - keypurpose_list = args.keypurpose[ - 0 : len([name for name in args.keypurpose if name is not None]) : - ] - - util.check_duplicate_name_in_list(keypurpose_list) - if len(block_name_list) != len(datafile_list) or len(block_name_list) != len( - keypurpose_list + @click.argument("keyfile", type=click.File("rb")) + @protect_options + @add_force_write_always + @add_show_sensitive_info_option + @click.pass_context + def burn_key_digest_cli(ctx, **kwargs): + kwargs.pop("force_write_always") + kwargs["show_sensitive_info"] = ctx.show_sensitive_info + self.burn_key_digest(**kwargs) + + ###################################### Commands ###################################### + + def burn_custom_mac(self, mac: str | bytes): + mac = self._convert_mac_to_bytes(mac) + self.efuses["CUSTOM_MAC"].save(mac) + self.efuses["CUSTOM_MAC_USED"].save(1) + if not self.efuses.burn_all(check_batch_mode=True): + return + self.get_custom_mac() + log.print("Successful.") + + def adc_info(self): + log.print("Block version:", self.efuses.get_block_version()) + if self.efuses.get_block_version() >= 1: + # fmt: off + log.print(f"Temperature Sensor Calibration = {self.efuses['TEMP_CALIB'].get()}C") + log.print("ADC OCode = ", self.efuses["OCODE"].get()) + log.print("ADC1:") + log.print("INIT_CODE_ATTEN0 = ", self.efuses["ADC1_INIT_CODE_ATTEN0"].get()) + log.print("INIT_CODE_ATTEN3 = ", self.efuses["ADC1_INIT_CODE_ATTEN3"].get()) + log.print("CAL_VOL_ATTEN0 = ", self.efuses["ADC1_CAL_VOL_ATTEN0"].get()) + log.print("CAL_VOL_ATTEN3 = ", self.efuses["ADC1_CAL_VOL_ATTEN3"].get()) + # fmt: on + + def burn_key( + self, + blocks: list[str], + keyfiles: list[BinaryIO], + keypurposes: list[str], + no_write_protect: bool = False, + no_read_protect: bool = False, + show_sensitive_info: bool = False, + digest: list[bytes] | None = None, ): - raise esptool.FatalError( - "The number of blocks (%d), datafile (%d) and " - "keypurpose (%d) should be the same." - % (len(block_name_list), len(datafile_list), len(keypurpose_list)) - ) - - assert 1 <= len(block_name_list) <= 2, "Unexpected case" - - if len(block_name_list) == 2: - incompatible = True if "XTS_AES_128_KEY" in keypurpose_list else False - permitted_purposes = [ - "XTS_AES_128_KEY_DERIVED_FROM_128_EFUSE_BITS", - "SECURE_BOOT_DIGEST", + """Burn the key block with the specified name. Arguments are groups of block name, + key file (containing 128/256 bits of binary key data) and key purpose. + + Args: + blocks: List of eFuse block names to burn keys to. + keyfiles: List of open files to read key data from. + keypurposes: List of key purposes to burn. + no_write_protect: If True, the write protection will NOT be enabled. + no_read_protect: If True, the read protection will NOT be enabled. + show_sensitive_info: If True, the sensitive information will be shown. + digest: List of digests to burn. + """ + datafile_list: list[BinaryIO] | list[bytes] + if digest is None: + datafile_list = keyfiles[ + 0 : len([keyfile for keyfile in keyfiles if keyfile is not None]) : + ] + else: + datafile_list = digest[ + 0 : len([name for name in digest if name is not None]) : + ] + block_name_list = blocks[ + 0 : len([name for name in blocks if name is not None]) : ] - incompatible |= ( - keypurpose_list[0] in permitted_purposes - and keypurpose_list[1] not in permitted_purposes - ) - if incompatible: + keypurpose_list = keypurposes[ + 0 : len([name for name in keypurposes if name is not None]) : + ] + + util.check_duplicate_name_in_list(keypurpose_list) + if len(block_name_list) != len(datafile_list) or len(block_name_list) != len( + keypurpose_list + ): raise esptool.FatalError( - "These keypurposes are incompatible %s" % (keypurpose_list) + "The number of blocks (%d), datafile (%d) and " + "keypurpose (%d) should be the same." + % (len(block_name_list), len(datafile_list), len(keypurpose_list)) ) - print("Burn keys to blocks:") - for datafile, keypurpose in zip(datafile_list, keypurpose_list): - data = datafile if isinstance(datafile, bytes) else datafile.read() - - if keypurpose == "XTS_AES_128_KEY_DERIVED_FROM_128_EFUSE_BITS": - efuse = efuses["BLOCK_KEY0_LOW_128"] - elif keypurpose == "SECURE_BOOT_DIGEST": - efuse = efuses["BLOCK_KEY0_HI_128"] - if len(data) == 32: - print( - "\tProgramming only left-most 128-bits from SHA256 hash of " - "public key to highest 128-bits of BLOCK KEY0" - ) - data = data[:16] - elif len(data) != efuse.bit_len // 8: + assert 1 <= len(block_name_list) <= 2, "Unexpected case" + + if len(block_name_list) == 2: + incompatible = True if "XTS_AES_128_KEY" in keypurpose_list else False + permitted_purposes = [ + "XTS_AES_128_KEY_DERIVED_FROM_128_EFUSE_BITS", + "SECURE_BOOT_DIGEST", + ] + incompatible |= ( + keypurpose_list[0] in permitted_purposes + and keypurpose_list[1] not in permitted_purposes + ) + if incompatible: raise esptool.FatalError( - "Wrong length of this file for SECURE_BOOT_DIGEST. " - "Got %d (expected %d or %d)" % (len(data), 32, efuse.bit_len // 8) + f"These keypurposes are incompatible {list(keypurpose_list)}" ) - assert len(data) == 16, "Only 16 bytes expected" - else: - efuse = efuses["BLOCK_KEY0"] - - num_bytes = efuse.bit_len // 8 - print(" - %s" % (efuse.name), end=" ") - revers_msg = None - if keypurpose.startswith("XTS_AES_"): - revers_msg = "\tReversing byte order for AES-XTS hardware peripheral" - data = data[::-1] - print( - "-> [{}]".format( - util.hexify(data, " ") - if args.show_sensitive_info - else " ".join(["??"] * len(data)) + log.print("Burn keys to blocks:") + for datafile, keypurpose in zip(datafile_list, keypurpose_list): + if isinstance(datafile, IOBase): + data = datafile.read() + datafile.close() + else: + data = datafile # type: ignore # this is safe but mypy still complains + + if keypurpose == "XTS_AES_128_KEY_DERIVED_FROM_128_EFUSE_BITS": + efuse = self.efuses["BLOCK_KEY0_LOW_128"] + elif keypurpose == "SECURE_BOOT_DIGEST": + efuse = self.efuses["BLOCK_KEY0_HI_128"] + if len(data) == 32: + log.print( + "\tProgramming only left-most 128-bits from SHA256 hash of " + "public key to highest 128-bits of BLOCK KEY0" + ) + data = data[:16] + elif len(data) != efuse.bit_len // 8: + raise esptool.FatalError( + "Wrong length of this file for SECURE_BOOT_DIGEST. " + f"Got {len(data)} (expected 32 or {efuse.bit_len // 8})" + ) + assert len(data) == 16, "Only 16 bytes expected" + else: + efuse = self.efuses["BLOCK_KEY0"] + + num_bytes = efuse.bit_len // 8 + + log.print(f" - {efuse.name}", end=" ") + revers_msg = None + if keypurpose.startswith("XTS_AES_"): + revers_msg = "\tReversing byte order for AES-XTS hardware peripheral..." + data = data[::-1] + log.print( + "-> [{}]".format( + util.hexify(data, " ") + if show_sensitive_info + else " ".join(["??"] * len(data)) + ) ) - ) - if revers_msg: - print(revers_msg) - if len(data) != num_bytes: + if revers_msg: + log.print(revers_msg) + if len(data) != num_bytes: + raise esptool.FatalError( + f"Incorrect key file size {len(data)}. Key file must be {num_bytes}" + f" bytes ({num_bytes * 8} bits) of raw binary key data." + ) + if keypurpose.startswith("XTS_AES_"): + read_protect = not no_read_protect + else: + read_protect = False + write_protect = not no_write_protect + + # using eFuse instead of a block gives the advantage + # of checking it as the whole field. + efuse.save(data) + + if keypurpose == "XTS_AES_128_KEY": + if self.efuses["XTS_KEY_LENGTH_256"].get(): + log.print("\t'XTS_KEY_LENGTH_256' is already '1'") + else: + log.print("\tXTS_KEY_LENGTH_256 -> 1") + self.efuses["XTS_KEY_LENGTH_256"].save(1) + + if read_protect: + log.print("\tDisabling read to key block...") + efuse.disable_read() + + if write_protect: + log.print("\tDisabling write to key block...") + efuse.disable_write() + log.print("") + + if not write_protect: + log.print("Keys will remain writeable (due to --no-write-protect).") + if no_read_protect: + log.print("Keys will remain readable (due to --no-read-protect).") + + if not self.efuses.burn_all(check_batch_mode=True): + return + log.print("Successful.") + + def burn_key_digest( + self, + keyfile: BinaryIO, + no_write_protect: bool = False, + no_read_protect: bool = False, + show_sensitive_info: bool = False, + ): + """Parse a RSA public key and burn the digest to key eFuse block. + + Args: + keyfile: Open file to read key data from. + no_write_protect: If True, the write protection will NOT be enabled. + no_read_protect: If True, the read protection will NOT be enabled. + show_sensitive_info: If True, the sensitive information will be shown. + """ + digest = espsecure._digest_sbv2_public_key(keyfile) + digest = digest[:16] + num_bytes = self.efuses["BLOCK_KEY0_HI_128"].bit_len // 8 + if len(digest) != num_bytes: raise esptool.FatalError( - "Incorrect key file size %d. " - "Key file must be %d bytes (%d bits) of raw binary key data." - % (len(data), num_bytes, num_bytes * 8) + "Incorrect digest size %d. " + "Digest must be %d bytes (%d bits) of raw binary key data." + % (len(digest), num_bytes, num_bytes * 8) ) - - if keypurpose.startswith("XTS_AES_"): - read_protect = False if args.no_read_protect else True - else: - read_protect = False - write_protect = not args.no_write_protect - - # using efuse instead of a block gives the advantage - # of checking it as the whole field. - efuse.save(data) - - if keypurpose == "XTS_AES_128_KEY": - if efuses["XTS_KEY_LENGTH_256"].get(): - print("\t'XTS_KEY_LENGTH_256' is already '1'") - else: - print("\tXTS_KEY_LENGTH_256 -> 1") - efuses["XTS_KEY_LENGTH_256"].save(1) - - if read_protect: - print("\tDisabling read to key block") - efuse.disable_read() - - if write_protect: - print("\tDisabling write to key block") - efuse.disable_write() - print("") - - if not write_protect: - print("Keys will remain writeable (due to --no-write-protect)") - if args.no_read_protect: - print("Keys will remain readable (due to --no-read-protect)") - - if not efuses.burn_all(check_batch_mode=True): - return - print("Successful") - - -def burn_key_digest(esp, efuses, args): - datafile = args.keyfile - args.keypurpose = ["SECURE_BOOT_DIGEST"] - args.block = ["BLOCK_KEY0"] - digest = espsecure._digest_sbv2_public_key(datafile) - digest = digest[:16] - num_bytes = efuses["BLOCK_KEY0_HI_128"].bit_len // 8 - if len(digest) != num_bytes: - raise esptool.FatalError( - "Incorrect digest size %d. " - "Digest must be %d bytes (%d bits) of raw binary key data." - % (len(digest), num_bytes, num_bytes * 8) + self.burn_key( + ["BLOCK_KEY0"], + [keyfile], + ["SECURE_BOOT_DIGEST"], + no_write_protect, + no_read_protect, + show_sensitive_info, + digest=[digest], ) - burn_key(esp, efuses, args, digest=[digest]) - - -def espefuse(esp, efuses, args, command): - parser = argparse.ArgumentParser() - subparsers = parser.add_subparsers(dest="operation") - add_commands(subparsers, efuses) - try: - cmd_line_args = parser.parse_args(command.split()) - except SystemExit: - traceback.print_stack() - raise esptool.FatalError('"{}" - incorrect command'.format(command)) - if cmd_line_args.operation == "execute_scripts": - configfiles = cmd_line_args.configfiles - index = cmd_line_args.index - # copy arguments from args to cmd_line_args - vars(cmd_line_args).update(vars(args)) - if cmd_line_args.operation == "execute_scripts": - cmd_line_args.configfiles = configfiles - cmd_line_args.index = index - if cmd_line_args.operation is None: - parser.print_help() - parser.exit(1) - operation_func = globals()[cmd_line_args.operation] - # each 'operation' is a module-level function of the same name - operation_func(esp, efuses, cmd_line_args) - - -def execute_scripts(esp, efuses, args): - efuses.batch_mode_cnt += 1 - del args.operation - scripts = args.scripts - del args.scripts - - for file in scripts: - with open(file.name, "r") as file: - exec(compile(file.read(), file.name, "exec")) - - if args.debug: - for block in efuses.blocks: - data = block.get_bitstring(from_read=False) - block.print_block(data, "regs_for_burn", args.debug) - - efuses.batch_mode_cnt -= 1 - if not efuses.burn_all(check_batch_mode=True): - return - print("Successful") diff --git a/tools/esptool_py/espefuse/efuse/esp32c3/__init__.py b/tools/esptool_py/espefuse/efuse/esp32c3/__init__.py index a3b55a8023..6c708d0c92 100644 --- a/tools/esptool_py/espefuse/efuse/esp32c3/__init__.py +++ b/tools/esptool_py/espefuse/efuse/esp32c3/__init__.py @@ -1,3 +1,5 @@ from . import operations from .emulate_efuse_controller import EmulateEfuseController from .fields import EspEfuses + +commands = operations.ESP32C3Commands diff --git a/tools/esptool_py/espefuse/efuse/esp32c3/fields.py b/tools/esptool_py/espefuse/efuse/esp32c3/fields.py index f367540a80..36a4a8df7e 100644 --- a/tools/esptool_py/espefuse/efuse/esp32c3/fields.py +++ b/tools/esptool_py/espefuse/efuse/esp32c3/fields.py @@ -12,6 +12,7 @@ from bitstring import BitArray import esptool +from esptool.logger import log import reedsolo @@ -55,9 +56,6 @@ class EspEfuses(base_fields.EspEfusesBase): Wrapper object to manage the efuse fields in a connected ESP bootloader """ - debug = False - do_not_confirm = False - def __init__( self, esp, @@ -66,14 +64,12 @@ def __init__( do_not_confirm=False, extend_efuse_table=None, ): + super().__init__(esp, skip_connect, debug, do_not_confirm, extend_efuse_table) self.Blocks = EfuseDefineBlocks() self.Fields = EfuseDefineFields(extend_efuse_table) self.REGS = EfuseDefineRegisters self.BURN_BLOCK_DATA_NAMES = self.Blocks.get_burn_block_data_names() self.BLOCKS_FOR_KEYS = self.Blocks.get_blocks_for_keys() - self._esp = esp - self.debug = debug - self.do_not_confirm = do_not_confirm if esp.CHIP_NAME != "ESP32-C3": raise esptool.FatalError( "Expected the 'esp' param for ESP32-C3 chip but got for '%s'." @@ -102,7 +98,7 @@ def __init__( for efuse in self.Fields.BLOCK2_CALIBRATION_EFUSES ] else: - if self["BLK_VERSION_MAJOR"].get() == 1: + if self.get_block_version() >= 100: self.efuses += [ EfuseField.convert(self, efuse) for efuse in self.Fields.BLOCK2_CALIBRATION_EFUSES @@ -136,14 +132,14 @@ def read_coding_scheme(self): self.coding_scheme = self.REGS.CODING_SCHEME_RS def print_status_regs(self): - print("") + log.print("") self.blocks[0].print_block(self.blocks[0].err_bitarray, "err__regs", debug=True) - print( + log.print( "{:27} 0x{:08x}".format( "EFUSE_RD_RS_ERR0_REG", self.read_reg(self.REGS.EFUSE_RD_RS_ERR0_REG) ) ) - print( + log.print( "{:27} 0x{:08x}".format( "EFUSE_RD_RS_ERR1_REG", self.read_reg(self.REGS.EFUSE_RD_RS_ERR1_REG) ) @@ -176,7 +172,7 @@ def wait_efuse_idle(self): # For PGM_CMD it is not necessary. return raise esptool.FatalError( - "Timed out waiting for Efuse controller command to complete" + "Timed out waiting for eFuse controller command to complete." ) def efuse_program(self, block): @@ -204,30 +200,30 @@ def efuse_read(self): try: self._esp = self.reconnect_chip(self._esp) except esptool.FatalError: - print("Can not re-connect to the chip") + log.print("Can not re-connect to the chip.") if not self["DIS_DOWNLOAD_MODE"].get() and self[ "DIS_DOWNLOAD_MODE" ].get(from_read=False): - print( + log.print( "This is the correct behavior as we are actually burning " - "DIS_DOWNLOAD_MODE which disables the connection to the chip" + "DIS_DOWNLOAD_MODE which disables the connection to the chip." ) - print("DIS_DOWNLOAD_MODE is enabled") - print("Successful") + log.print("DIS_DOWNLOAD_MODE is enabled.") + log.print("Successful.") sys.exit(0) # finish without errors raise - print("Established a connection with the chip") + log.print("Established a connection with the chip.") if self._esp.secure_download_mode and not secure_download_mode_before: - print("Secure download mode is enabled") + log.print("Secure download mode is enabled.") if not self["ENABLE_SECURITY_DOWNLOAD"].get() and self[ "ENABLE_SECURITY_DOWNLOAD" ].get(from_read=False): - print( - "espefuse tool can not continue to work in Secure download mode" + log.print( + "espefuse can not continue to work in Secure download mode." ) - print("ENABLE_SECURITY_DOWNLOAD is enabled") - print("Successful") + log.print("ENABLE_SECURITY_DOWNLOAD is enabled.") + log.print("Successful.") sys.exit(0) # finish without errors raise @@ -237,7 +233,7 @@ def set_efuse_timing(self): apb_freq = self.get_crystal_freq() if apb_freq != 40: raise esptool.FatalError( - "The eFuse supports only xtal=40M (xtal was %d)" % apb_freq + f"The eFuse supports only xtal=40M (xtal was {apb_freq})." ) self.update_reg(self.REGS.EFUSE_DAC_CONF_REG, self.REGS.EFUSE_DAC_NUM_M, 0xFF) @@ -262,7 +258,7 @@ def get_coding_scheme_warnings(self, silent=False): ] block.err_bitarray.pos = 0 for word in reversed(words): - block.err_bitarray.overwrite(BitArray("uint:32=%d" % word)) + block.err_bitarray.overwrite(BitArray(f"uint:32={word}")) block.num_errors = block.err_bitarray.count(True) block.fail = block.num_errors != 0 else: @@ -282,9 +278,9 @@ def get_coding_scheme_warnings(self, silent=False): ret_fail |= block.fail if not silent and (block.fail or block.num_errors): - print( - "Error(s) in BLOCK%d [ERRORS:%d FAIL:%d]" - % (block.id, block.num_errors, block.fail) + log.print( + f"Error(s) in BLOCK{block.id} " + f"[ERRORS:{block.num_errors} FAIL:{block.fail}]." ) if (self.debug or ret_fail) and not silent: self.print_status_regs() @@ -316,7 +312,7 @@ def get(self, from_read=True): return (hi_bits << 3) + lo_bits def save(self, new_value): - raise esptool.FatalError("Burning %s is not supported" % self.name) + raise esptool.FatalError(f"Burning {self.name} is not supported.") class EfuseTempSensor(EfuseField): @@ -362,7 +358,7 @@ def check_format(self, new_value_str): def check(self): errs, fail = self.parent.get_block_errors(self.block) if errs != 0 or fail: - output = "Block%d has ERRORS:%d FAIL:%d" % (self.block, errs, fail) + output = f"Block{self.block} has ERRORS:{errs} FAIL:{fail}." else: output = "OK" return "(" + output + ")" @@ -376,10 +372,8 @@ def get(self, from_read=True): def save(self, new_value): def print_field(e, new_value): - print( - " - '{}' ({}) {} -> {}".format( - e.name, e.description, e.get_bitstring(), new_value - ) + log.print( + f" - '{e.name}' ({e.description}) {e.get_bitstring()} -> {new_value}" ) if self.name == "CUSTOM_MAC": @@ -420,9 +414,9 @@ def check_format(self, new_value_str): break if raw_val.isdigit(): if int(raw_val) not in [p[1] for p in self.KEY_PURPOSES if p[1] > 0]: - raise esptool.FatalError("'%s' can not be set (value out of range)" % raw_val) + raise esptool.FatalError(f"'{raw_val}' can not be set (value out of range)") else: - raise esptool.FatalError("'%s' unknown name" % raw_val) + raise esptool.FatalError(f"'{raw_val}' unknown name") return raw_val def need_reverse(self, new_key_purpose): diff --git a/tools/esptool_py/espefuse/efuse/esp32c3/mem_definition.py b/tools/esptool_py/espefuse/efuse/esp32c3/mem_definition.py index bd13bd7738..105f1ed906 100644 --- a/tools/esptool_py/espefuse/efuse/esp32c3/mem_definition.py +++ b/tools/esptool_py/espefuse/efuse/esp32c3/mem_definition.py @@ -130,12 +130,8 @@ class EfuseDefineFields(EfuseFieldsBase): def __init__(self, extend_efuse_table) -> None: # List of efuse fields from TRM the chapter eFuse Controller. self.EFUSES = [] - self.KEYBLOCKS = [] - - # if BLK_VERSION_MAJOR is 1, these efuse fields are in BLOCK2 self.BLOCK2_CALIBRATION_EFUSES = [] - self.CALC = [] dir_name = os.path.dirname(os.path.abspath(__file__)) diff --git a/tools/esptool_py/espefuse/efuse/esp32c3/operations.py b/tools/esptool_py/espefuse/efuse/esp32c3/operations.py index ff63109570..57baae243d 100644 --- a/tools/esptool_py/espefuse/efuse/esp32c3/operations.py +++ b/tools/esptool_py/espefuse/efuse/esp32c3/operations.py @@ -1,404 +1,310 @@ # This file includes the operations with eFuses for ESP32-C3 chip # -# SPDX-FileCopyrightText: 2020-2022 Espressif Systems (Shanghai) CO LTD +# SPDX-FileCopyrightText: 2020-2025 Espressif Systems (Shanghai) CO LTD # # SPDX-License-Identifier: GPL-2.0-or-later -import argparse -import os # noqa: F401. It is used in IDF scripts -import traceback +from io import IOBase +from typing import BinaryIO +import click import espsecure import esptool +from esptool.logger import log from . import fields from .. import util +from .mem_definition import EfuseDefineBlocks from ..base_operations import ( - add_common_commands, + BaseCommands, + NonCompositeTuple, + TupleParameter, add_force_write_always, add_show_sensitive_info_option, - burn_bit, - burn_block_data, - burn_efuse, - check_error, - dump, - read_protect_efuse, - summary, - write_protect_efuse, + protect_options, ) -def protect_options(p): - p.add_argument( - "--no-write-protect", - help="Disable write-protecting of the key. The key remains writable. " - "(The keys use the RS coding scheme that does not support " - "post-write data changes. Forced write can damage RS encoding bits.) " - "The write-protecting of keypurposes does not depend on the option, " - "it will be set anyway.", - action="store_true", - ) - p.add_argument( - "--no-read-protect", - help="Disable read-protecting of the key. The key remains readable software." - "The key with keypurpose[USER, RESERVED and *_DIGEST] " - "will remain readable anyway. For the rest keypurposes the read-protection " - "will be defined the option (Read-protect by default).", - action="store_true", - ) +class ESP32C3Commands(BaseCommands): + CHIP_NAME = "ESP32-C3" + efuse_lib = fields.EspEfuses + ################################### CLI definitions ################################### -def add_commands(subparsers, efuses): - add_common_commands(subparsers, efuses) - burn_key = subparsers.add_parser( - "burn_key", help="Burn the key block with the specified name" - ) - protect_options(burn_key) - add_force_write_always(burn_key) - add_show_sensitive_info_option(burn_key) - burn_key.add_argument( - "block", - help="Key block to burn", - action="append", - choices=efuses.BLOCKS_FOR_KEYS, - ) - burn_key.add_argument( - "keyfile", - help="File containing 256 bits of binary key data", - action="append", - type=argparse.FileType("rb"), - ) - burn_key.add_argument( - "keypurpose", - help="Purpose to set.", - action="append", - choices=fields.EfuseKeyPurposeField.KEY_PURPOSES_NAME, - ) - for _ in efuses.BLOCKS_FOR_KEYS: - burn_key.add_argument( - "block", - help="Key block to burn", - nargs="?", - action="append", - metavar="BLOCK", - choices=efuses.BLOCKS_FOR_KEYS, - ) - burn_key.add_argument( - "keyfile", - help="File containing 256 bits of binary key data", - nargs="?", - action="append", - metavar="KEYFILE", - type=argparse.FileType("rb"), - ) - burn_key.add_argument( - "keypurpose", - help="Purpose to set.", - nargs="?", - action="append", - metavar="KEYPURPOSE", - choices=fields.EfuseKeyPurposeField.KEY_PURPOSES_NAME, - ) + def add_cli_commands(self, cli: click.Group): + super().add_cli_commands(cli) + blocks_for_keys = EfuseDefineBlocks().get_blocks_for_keys() - burn_key_digest = subparsers.add_parser( - "burn_key_digest", - help="Parse a RSA public key and burn the digest to key efuse block", - ) - protect_options(burn_key_digest) - add_force_write_always(burn_key_digest) - add_show_sensitive_info_option(burn_key_digest) - burn_key_digest.add_argument( - "block", - help="Key block to burn", - action="append", - choices=efuses.BLOCKS_FOR_KEYS, - ) - burn_key_digest.add_argument( - "keyfile", - help="Key file to digest (PEM format)", - action="append", - type=argparse.FileType("rb"), - ) - burn_key_digest.add_argument( - "keypurpose", - help="Purpose to set.", - action="append", - choices=fields.EfuseKeyPurposeField.DIGEST_KEY_PURPOSES, - ) - for _ in efuses.BLOCKS_FOR_KEYS: - burn_key_digest.add_argument( - "block", - help="Key block to burn", - nargs="?", - action="append", - metavar="BLOCK", - choices=efuses.BLOCKS_FOR_KEYS, + @cli.command( + "burn-key", + short_help="Burn the key block with the specified name.", + help="Burn the key block with the specified name. Arguments are groups of block name, " + "key file (containing 128/256 bits of binary key data) and key purpose.\n\n" + f"Block is one of: [{', '.join(blocks_for_keys)}]\n\n" + f"Key purpose is one of: [{', '.join(fields.EfuseKeyPurposeField.KEY_PURPOSES_NAME)}]", ) - burn_key_digest.add_argument( - "keyfile", - help="Key file to digest (PEM format)", - nargs="?", - action="append", - metavar="KEYFILE", - type=argparse.FileType("rb"), + @click.argument( + "block_keyfile_keypurpose", + metavar=" ", + cls=TupleParameter, + required=True, + nargs=-1, + max_arity=len(blocks_for_keys), + type=NonCompositeTuple( + [ + click.Choice(blocks_for_keys), + click.File("rb"), + click.Choice(fields.EfuseKeyPurposeField.KEY_PURPOSES_NAME), + ] + ), ) - burn_key_digest.add_argument( - "keypurpose", - help="Purpose to set.", - nargs="?", - action="append", - metavar="KEYPURPOSE", - choices=fields.EfuseKeyPurposeField.DIGEST_KEY_PURPOSES, + @protect_options + @add_force_write_always + @add_show_sensitive_info_option + @click.pass_context + def burn_key_cli(ctx, **kwargs): + block, keyfile, keypurpose = zip(*kwargs.pop("block_keyfile_keypurpose")) + kwargs.pop("force_write_always") + kwargs["show_sensitive_info"] = ctx.show_sensitive_info + self.burn_key(block, keyfile, keypurpose, **kwargs) + + @cli.command( + "burn-key-digest", + short_help="Parse a RSA public key and burn the digest.", + help="Parse a RSA public key and burn the digest to key eFuse block.\n\n" + f"Block is one of: [{', '.join(blocks_for_keys)}]\n\n" + f"Key purpose is one of: [{', '.join(fields.EfuseKeyPurposeField.DIGEST_KEY_PURPOSES)}]", ) - - p = subparsers.add_parser( - "set_flash_voltage", - help="Permanently set the internal flash voltage regulator " - "to either 1.8V, 3.3V or OFF. " - "This means GPIO45 can be high or low at reset without " - "changing the flash voltage.", - ) - p.add_argument("voltage", help="Voltage selection", choices=["1.8V", "3.3V", "OFF"]) - - p = subparsers.add_parser( - "burn_custom_mac", help="Burn a 48-bit Custom MAC Address to EFUSE BLOCK3." - ) - p.add_argument( - "mac", - help="Custom MAC Address to burn given in hexadecimal format with bytes " - "separated by colons (e.g. AA:CD:EF:01:02:03).", - type=fields.base_fields.CheckArgValue(efuses, "CUSTOM_MAC"), - ) - add_force_write_always(p) - - p = subparsers.add_parser("get_custom_mac", help="Prints the Custom MAC Address.") - - -def burn_custom_mac(esp, efuses, args): - efuses["CUSTOM_MAC"].save(args.mac) - if not efuses.burn_all(check_batch_mode=True): - return - get_custom_mac(esp, efuses, args) - print("Successful") - - -def get_custom_mac(esp, efuses, args): - print("Custom MAC Address: {}".format(efuses["CUSTOM_MAC"].get())) - - -def set_flash_voltage(esp, efuses, args): - raise esptool.FatalError("set_flash_voltage is not supported!") - - -def adc_info(esp, efuses, args): - print("") - # fmt: off - if efuses["BLK_VERSION_MAJOR"].get() == 1: - print("Temperature Sensor Calibration = {}C".format(efuses["TEMP_CALIB"].get())) - print("ADC OCode = ", efuses["OCODE"].get()) - print("ADC1:") - print("INIT_CODE_ATTEN0 = ", efuses["ADC1_INIT_CODE_ATTEN0"].get()) - print("INIT_CODE_ATTEN1 = ", efuses["ADC1_INIT_CODE_ATTEN1"].get()) - print("INIT_CODE_ATTEN2 = ", efuses["ADC1_INIT_CODE_ATTEN2"].get()) - print("INIT_CODE_ATTEN3 = ", efuses["ADC1_INIT_CODE_ATTEN3"].get()) - print("CAL_VOL_ATTEN0 = ", efuses["ADC1_CAL_VOL_ATTEN0"].get()) - print("CAL_VOL_ATTEN1 = ", efuses["ADC1_CAL_VOL_ATTEN1"].get()) - print("CAL_VOL_ATTEN2 = ", efuses["ADC1_CAL_VOL_ATTEN2"].get()) - print("CAL_VOL_ATTEN3 = ", efuses["ADC1_CAL_VOL_ATTEN3"].get()) - else: - print("BLK_VERSION_MAJOR = {}".format(efuses["BLK_VERSION_MAJOR"].get_meaning())) - # fmt: on - - -def burn_key(esp, efuses, args, digest=None): - if digest is None: - datafile_list = args.keyfile[ - 0 : len([name for name in args.keyfile if name is not None]) : - ] - else: - datafile_list = digest[0 : len([name for name in digest if name is not None]) :] - efuses.force_write_always = args.force_write_always - block_name_list = args.block[ - 0 : len([name for name in args.block if name is not None]) : - ] - keypurpose_list = args.keypurpose[ - 0 : len([name for name in args.keypurpose if name is not None]) : - ] - - util.check_duplicate_name_in_list(block_name_list) - if len(block_name_list) != len(datafile_list) or len(block_name_list) != len( - keypurpose_list - ): - raise esptool.FatalError( - "The number of blocks (%d), datafile (%d) and keypurpose (%d) " - "should be the same." - % (len(block_name_list), len(datafile_list), len(keypurpose_list)) + @click.argument( + "block_keyfile_keypurpose", + metavar=" ", + cls=TupleParameter, + required=True, + nargs=-1, + max_arity=len(blocks_for_keys), + type=NonCompositeTuple( + [ + click.Choice(blocks_for_keys), + click.File("rb"), + click.Choice(fields.EfuseKeyPurposeField.DIGEST_KEY_PURPOSES), + ] + ), ) - - print("Burn keys to blocks:") - for block_name, datafile, keypurpose in zip( - block_name_list, datafile_list, keypurpose_list + @protect_options + @add_force_write_always + @add_show_sensitive_info_option + @click.pass_context + def burn_key_digest_cli(ctx, **kwargs): + block, keyfile, keypurpose = zip(*kwargs.pop("block_keyfile_keypurpose")) + kwargs.pop("force_write_always") + kwargs["show_sensitive_info"] = ctx.show_sensitive_info + self.burn_key_digest(block, keyfile, keypurpose, **kwargs) + + ###################################### Commands ###################################### + + def adc_info(self): + log.print("Block version:", self.efuses.get_block_version()) + if self.efuses.get_block_version() >= 100: + # fmt: off + log.print(f"Temperature Sensor Calibration = {self.efuses['TEMP_CALIB'].get()}C") + log.print("ADC OCode = ", self.efuses["OCODE"].get()) + log.print("ADC1:") + log.print("INIT_CODE_ATTEN0 = ", self.efuses["ADC1_INIT_CODE_ATTEN0"].get()) + log.print("INIT_CODE_ATTEN1 = ", self.efuses["ADC1_INIT_CODE_ATTEN1"].get()) + log.print("INIT_CODE_ATTEN2 = ", self.efuses["ADC1_INIT_CODE_ATTEN2"].get()) + log.print("INIT_CODE_ATTEN3 = ", self.efuses["ADC1_INIT_CODE_ATTEN3"].get()) + log.print("CAL_VOL_ATTEN0 = ", self.efuses["ADC1_CAL_VOL_ATTEN0"].get()) + log.print("CAL_VOL_ATTEN1 = ", self.efuses["ADC1_CAL_VOL_ATTEN1"].get()) + log.print("CAL_VOL_ATTEN2 = ", self.efuses["ADC1_CAL_VOL_ATTEN2"].get()) + log.print("CAL_VOL_ATTEN3 = ", self.efuses["ADC1_CAL_VOL_ATTEN3"].get()) + # fmt: on + + def burn_key( + self, + blocks: list[str], + keyfiles: list[BinaryIO], + keypurposes: list[str], + no_write_protect: bool = False, + no_read_protect: bool = False, + show_sensitive_info: bool = False, + digest: list[bytes] | None = None, ): - efuse = None - for block in efuses.blocks: - if block_name == block.name or block_name in block.alias: - efuse = efuses[block.name] - if efuse is None: - raise esptool.FatalError("Unknown block name - %s" % (block_name)) - num_bytes = efuse.bit_len // 8 - - block_num = efuses.get_index_block_by_name(block_name) - block = efuses.blocks[block_num] - + """Burn the key block with the specified name. Arguments are groups of block name, + key file (containing 128/256 bits of binary key data) and key purpose. + + Args: + blocks: List of eFuse block names to burn keys to. + keyfiles: List of open files to read key data from. + keypurposes: List of key purposes to burn. + no_write_protect: If True, the write protection will NOT be enabled. + no_read_protect: If True, the read protection will NOT be enabled. + show_sensitive_info: If True, the sensitive information will be shown. + digest: List of digests to burn. + """ + datafile_list: list[BinaryIO] | list[bytes] if digest is None: - data = datafile.read() + datafile_list = keyfiles[ + 0 : len([name for name in keyfiles if name is not None]) : + ] else: - data = datafile + datafile_list = digest[ + 0 : len([name for name in digest if name is not None]) : + ] + block_name_list = blocks[ + 0 : len([name for name in blocks if name is not None]) : + ] + keypurpose_list = keypurposes[ + 0 : len([name for name in keypurposes if name is not None]) : + ] - print(" - %s" % (efuse.name), end=" ") - revers_msg = None - if efuses[block.key_purpose_name].need_reverse(keypurpose): - revers_msg = "\tReversing byte order for AES-XTS hardware peripheral" - data = data[::-1] - print( - "-> [{}]".format( - util.hexify(data, " ") - if args.show_sensitive_info - else " ".join(["??"] * len(data)) - ) - ) - if revers_msg: - print(revers_msg) - if len(data) != num_bytes: + util.check_duplicate_name_in_list(block_name_list) + if len(block_name_list) != len(datafile_list) or len(block_name_list) != len( + keypurpose_list + ): raise esptool.FatalError( - "Incorrect key file size %d. Key file must be %d bytes (%d bits) " - "of raw binary key data." % (len(data), num_bytes, num_bytes * 8) + f"The number of blocks ({len(block_name_list)}), datafile ({len(datafile_list)}) " + f"and keypurpose ({len(keypurpose_list)}) should be the same." ) - if efuses[block.key_purpose_name].need_rd_protect(keypurpose): - read_protect = False if args.no_read_protect else True - else: - read_protect = False - write_protect = not args.no_write_protect - - # using efuse instead of a block gives the advantage of checking it as the whole field. - efuse.save(data) + log.print("Burn keys to blocks:") + for block_name, datafile, keypurpose in zip( + block_name_list, datafile_list, keypurpose_list + ): + efuse = None + for blk in self.efuses.blocks: + if block_name == blk.name or block_name in blk.alias: + efuse = self.efuses[blk.name] + if efuse is None: + raise esptool.FatalError(f"Unknown block name - {block_name}.") + num_bytes = efuse.bit_len // 8 + + block_num = self.efuses.get_index_block_by_name(block_name) + block = self.efuses.blocks[block_num] + + if isinstance(datafile, IOBase): + data = datafile.read() + datafile.close() + else: + data = datafile # type: ignore # this is safe but mypy still complains + + log.print(f" - {efuse.name}", end=" ") + revers_msg = None + if self.efuses[block.key_purpose_name].need_reverse(keypurpose): + revers_msg = "\tReversing byte order for AES-XTS hardware peripheral..." + data = data[::-1] + log.print( + "-> [{}]".format( + util.hexify(data, " ") + if show_sensitive_info + else " ".join(["??"] * len(data)) + ) + ) + if revers_msg: + log.print(revers_msg) + if len(data) != num_bytes: + raise esptool.FatalError( + f"Incorrect key file size {len(data)}. Key file must be {num_bytes} " + f"bytes ({num_bytes * 8} bits) of raw binary key data." + ) - disable_wr_protect_key_purpose = False - if efuses[block.key_purpose_name].get() != keypurpose: - if efuses[block.key_purpose_name].is_writeable(): - print( - "\t'%s': '%s' -> '%s'." - % ( - block.key_purpose_name, - efuses[block.key_purpose_name].get(), - keypurpose, + if self.efuses[block.key_purpose_name].need_rd_protect(keypurpose): + read_protect = False if no_read_protect else True + else: + read_protect = False + write_protect = not no_write_protect + + # using eFuse instead of a block gives the advantage of checking it as the whole field. + efuse.save(data) + + disable_wr_protect_key_purpose = False + if self.efuses[block.key_purpose_name].get() != keypurpose: + if self.efuses[block.key_purpose_name].is_writeable(): + log.print( + f"\t'{block.key_purpose_name}': " + f"'{self.efuses[block.key_purpose_name].get()}' -> '{keypurpose}'." + ) + self.efuses[block.key_purpose_name].save(keypurpose) + disable_wr_protect_key_purpose = True + else: + raise esptool.FatalError( + f"It is not possible to change '{block.key_purpose_name}' " + f"to '{keypurpose}' because write protection bit is set." ) - ) - efuses[block.key_purpose_name].save(keypurpose) - disable_wr_protect_key_purpose = True else: + log.print(f"\t'{block.key_purpose_name}' is already '{keypurpose}'.") + if self.efuses[block.key_purpose_name].is_writeable(): + disable_wr_protect_key_purpose = True + + if disable_wr_protect_key_purpose: + log.print(f"\tDisabling write to '{block.key_purpose_name}'...") + self.efuses[block.key_purpose_name].disable_write() + + if read_protect: + log.print("\tDisabling read to key block...") + efuse.disable_read() + + if write_protect: + log.print("\tDisabling write to key block...") + efuse.disable_write() + log.print("") + + if not write_protect: + log.print("Keys will remain writeable (due to --no-write-protect).") + if no_read_protect: + log.print("Keys will remain readable (due to --no-read-protect).") + + if not self.efuses.burn_all(check_batch_mode=True): + return + log.print("Successful.") + + def burn_key_digest( + self, + blocks: list[str], + keyfiles: list[BinaryIO], + keypurposes: list[str], + no_write_protect: bool = False, + no_read_protect: bool = False, + show_sensitive_info: bool = False, + ): + """Parse a RSA public key and burn the digest to key eFuse block. + + Args: + blocks: List of eFuse block names to burn keys to. + keyfiles: List of open files to read key data from. + keypurposes: List of key purposes to burn. + no_write_protect: If True, the write protection will NOT be enabled. + no_read_protect: If True, the read protection will NOT be enabled. + show_sensitive_info: If True, the sensitive information will be shown. + """ + digest_list = [] + datafile_list = keyfiles[ + 0 : len([name for name in keyfiles if name is not None]) : + ] + block_list = blocks[0 : len([block for block in blocks if block is not None]) :] + + for block_name, datafile in zip(block_list, datafile_list): + efuse = None + for block in self.efuses.blocks: + if block_name == block.name or block_name in block.alias: + efuse = self.efuses[block.name] + if efuse is None: + raise esptool.FatalError(f"Unknown block name - {block_name}.") + num_bytes = efuse.bit_len // 8 + digest = espsecure._digest_sbv2_public_key(datafile) + if len(digest) != num_bytes: raise esptool.FatalError( - "It is not possible to change '%s' to '%s' " - "because write protection bit is set." - % (block.key_purpose_name, keypurpose) + "Incorrect digest size %d. Digest must be %d bytes (%d bits) " + "of raw binary key data." % (len(digest), num_bytes, num_bytes * 8) ) - else: - print("\t'%s' is already '%s'." % (block.key_purpose_name, keypurpose)) - if efuses[block.key_purpose_name].is_writeable(): - disable_wr_protect_key_purpose = True - - if disable_wr_protect_key_purpose: - print("\tDisabling write to '%s'." % block.key_purpose_name) - efuses[block.key_purpose_name].disable_write() - - if read_protect: - print("\tDisabling read to key block") - efuse.disable_read() - - if write_protect: - print("\tDisabling write to key block") - efuse.disable_write() - print("") - - if not write_protect: - print("Keys will remain writeable (due to --no-write-protect)") - if args.no_read_protect: - print("Keys will remain readable (due to --no-read-protect)") - - if not efuses.burn_all(check_batch_mode=True): - return - print("Successful") - - -def burn_key_digest(esp, efuses, args): - digest_list = [] - datafile_list = args.keyfile[ - 0 : len([name for name in args.keyfile if name is not None]) : - ] - block_list = args.block[ - 0 : len([block for block in args.block if block is not None]) : - ] - for block_name, datafile in zip(block_list, datafile_list): - efuse = None - for block in efuses.blocks: - if block_name == block.name or block_name in block.alias: - efuse = efuses[block.name] - if efuse is None: - raise esptool.FatalError("Unknown block name - %s" % (block_name)) - num_bytes = efuse.bit_len // 8 - digest = espsecure._digest_sbv2_public_key(datafile) - if len(digest) != num_bytes: - raise esptool.FatalError( - "Incorrect digest size %d. Digest must be %d bytes (%d bits) " - "of raw binary key data." % (len(digest), num_bytes, num_bytes * 8) - ) - digest_list.append(digest) - burn_key(esp, efuses, args, digest=digest_list) - - -def espefuse(esp, efuses, args, command): - parser = argparse.ArgumentParser() - subparsers = parser.add_subparsers(dest="operation") - add_commands(subparsers, efuses) - try: - cmd_line_args = parser.parse_args(command.split()) - except SystemExit: - traceback.print_stack() - raise esptool.FatalError('"{}" - incorrect command'.format(command)) - if cmd_line_args.operation == "execute_scripts": - configfiles = cmd_line_args.configfiles - index = cmd_line_args.index - # copy arguments from args to cmd_line_args - vars(cmd_line_args).update(vars(args)) - if cmd_line_args.operation == "execute_scripts": - cmd_line_args.configfiles = configfiles - cmd_line_args.index = index - if cmd_line_args.operation is None: - parser.print_help() - parser.exit(1) - operation_func = globals()[cmd_line_args.operation] - # each 'operation' is a module-level function of the same name - operation_func(esp, efuses, cmd_line_args) - - -def execute_scripts(esp, efuses, args): - efuses.batch_mode_cnt += 1 - del args.operation - scripts = args.scripts - del args.scripts - - for file in scripts: - with open(file.name, "r") as file: - exec(compile(file.read(), file.name, "exec")) - - if args.debug: - for block in efuses.blocks: - data = block.get_bitstring(from_read=False) - block.print_block(data, "regs_for_burn", args.debug) - - efuses.batch_mode_cnt -= 1 - if not efuses.burn_all(check_batch_mode=True): - return - print("Successful") + digest_list.append(digest) + + self.burn_key( + block_list, + datafile_list, + keypurposes, + no_write_protect, + no_read_protect, + show_sensitive_info, + digest=digest_list, + ) diff --git a/tools/esptool_py/espefuse/efuse/esp32c5/__init__.py b/tools/esptool_py/espefuse/efuse/esp32c5/__init__.py index a3b55a8023..94da102b64 100644 --- a/tools/esptool_py/espefuse/efuse/esp32c5/__init__.py +++ b/tools/esptool_py/espefuse/efuse/esp32c5/__init__.py @@ -1,3 +1,5 @@ from . import operations from .emulate_efuse_controller import EmulateEfuseController from .fields import EspEfuses + +commands = operations.ESP32C5Commands diff --git a/tools/esptool_py/espefuse/efuse/esp32c5/fields.py b/tools/esptool_py/espefuse/efuse/esp32c5/fields.py index b61ba6077b..63992c56c3 100644 --- a/tools/esptool_py/espefuse/efuse/esp32c5/fields.py +++ b/tools/esptool_py/espefuse/efuse/esp32c5/fields.py @@ -12,6 +12,7 @@ from bitstring import BitArray import esptool +from esptool.logger import log import reedsolo @@ -55,9 +56,6 @@ class EspEfuses(base_fields.EspEfusesBase): Wrapper object to manage the efuse fields in a connected ESP bootloader """ - debug = False - do_not_confirm = False - def __init__( self, esp, @@ -66,14 +64,12 @@ def __init__( do_not_confirm=False, extend_efuse_table=None, ): + super().__init__(esp, skip_connect, debug, do_not_confirm, extend_efuse_table) self.Blocks = EfuseDefineBlocks() self.Fields = EfuseDefineFields(extend_efuse_table) self.REGS = EfuseDefineRegisters self.BURN_BLOCK_DATA_NAMES = self.Blocks.get_burn_block_data_names() self.BLOCKS_FOR_KEYS = self.Blocks.get_blocks_for_keys() - self._esp = esp - self.debug = debug - self.do_not_confirm = do_not_confirm if esp.CHIP_NAME != "ESP32-C5": raise esptool.FatalError( "Expected the 'esp' param for ESP32-C5 chip but got for '%s'." @@ -102,11 +98,11 @@ def __init__( for efuse in self.Fields.BLOCK2_CALIBRATION_EFUSES ] else: - # if self["BLK_VERSION_MINOR"].get() == 1: - # self.efuses += [ - # EfuseField.convert(self, efuse) - # for efuse in self.Fields.BLOCK2_CALIBRATION_EFUSES - # ] + if self.get_block_version() >= 1: + self.efuses += [ + EfuseField.convert(self, efuse) + for efuse in self.Fields.BLOCK2_CALIBRATION_EFUSES + ] self.efuses += [ EfuseField.convert(self, efuse) for efuse in self.Fields.CALC ] @@ -136,14 +132,14 @@ def read_coding_scheme(self): self.coding_scheme = self.REGS.CODING_SCHEME_RS def print_status_regs(self): - print("") + log.print("") self.blocks[0].print_block(self.blocks[0].err_bitarray, "err__regs", debug=True) - print( + log.print( "{:27} 0x{:08x}".format( "EFUSE_RD_RS_ERR0_REG", self.read_reg(self.REGS.EFUSE_RD_RS_ERR0_REG) ) ) - print( + log.print( "{:27} 0x{:08x}".format( "EFUSE_RD_RS_ERR1_REG", self.read_reg(self.REGS.EFUSE_RD_RS_ERR1_REG) ) @@ -176,7 +172,7 @@ def wait_efuse_idle(self): # For PGM_CMD it is not necessary. return raise esptool.FatalError( - "Timed out waiting for Efuse controller command to complete" + "Timed out waiting for eFuse controller command to complete" ) def efuse_program(self, block): @@ -204,30 +200,30 @@ def efuse_read(self): try: self._esp = self.reconnect_chip(self._esp) except esptool.FatalError: - print("Can not re-connect to the chip") + log.print("Can not re-connect to the chip.") if not self["DIS_DOWNLOAD_MODE"].get() and self[ "DIS_DOWNLOAD_MODE" ].get(from_read=False): - print( + log.print( "This is the correct behavior as we are actually burning " - "DIS_DOWNLOAD_MODE which disables the connection to the chip" + "DIS_DOWNLOAD_MODE which disables the connection to the chip." ) - print("DIS_DOWNLOAD_MODE is enabled") - print("Successful") + log.print("DIS_DOWNLOAD_MODE is enabled.") + log.print("Successful.") sys.exit(0) # finish without errors raise - print("Established a connection with the chip") + log.print("Established a connection with the chip.") if self._esp.secure_download_mode and not secure_download_mode_before: - print("Secure download mode is enabled") + log.print("Secure download mode is enabled.") if not self["ENABLE_SECURITY_DOWNLOAD"].get() and self[ "ENABLE_SECURITY_DOWNLOAD" ].get(from_read=False): - print( - "espefuse tool can not continue to work in Secure download mode" + log.print( + "espefuse can not continue to work in Secure download mode." ) - print("ENABLE_SECURITY_DOWNLOAD is enabled") - print("Successful") + log.print("ENABLE_SECURITY_DOWNLOAD is enabled.") + log.print("Successful.") sys.exit(0) # finish without errors raise @@ -280,7 +276,7 @@ def get_coding_scheme_warnings(self, silent=False): block.num_errors = (reg_value >> err_num_offs) & err_num_mask ret_fail |= block.fail if not silent and (block.fail or block.num_errors): - print( + log.print( "Error(s) in BLOCK%d [ERRORS:%d FAIL:%d]" % (block.id, block.num_errors, block.fail) ) @@ -301,20 +297,55 @@ def convert(parent, efuse): "keypurpose": EfuseKeyPurposeField, "t_sensor": EfuseTempSensor, "adc_tp": EfuseAdcPointCalibration, - "wafer": EfuseWafer, + "recovery_bootloader": EfuseBtldrRecoveryField, + "bootloader_anti_rollback": EfuseBtldrAntiRollbackField, }.get(efuse.class_type, EfuseField)(parent, efuse) -class EfuseWafer(EfuseField): +class EfuseBtldrRecoveryField(EfuseField): def get(self, from_read=True): - hi_bits = self.parent["WAFER_VERSION_MINOR_HI"].get(from_read) - assert self.parent["WAFER_VERSION_MINOR_HI"].bit_len == 1 - lo_bits = self.parent["WAFER_VERSION_MINOR_LO"].get(from_read) - assert self.parent["WAFER_VERSION_MINOR_LO"].bit_len == 3 + hi_bits = self.parent["RECOVERY_BOOTLOADER_FLASH_SECTOR_HI"].get(from_read) + assert self.parent["RECOVERY_BOOTLOADER_FLASH_SECTOR_HI"].bit_len == 3 + lo_bits = self.parent["RECOVERY_BOOTLOADER_FLASH_SECTOR_LO"].get(from_read) + assert self.parent["RECOVERY_BOOTLOADER_FLASH_SECTOR_LO"].bit_len == 9 + return (hi_bits << 9) + lo_bits + + def save(self, new_value): + efuse = self.parent["RECOVERY_BOOTLOADER_FLASH_SECTOR_HI"] + efuse.save((new_value >> 9) & 3) + log.print( + f"\t - '{efuse.name}' {efuse.get_bitstring()} -> {efuse.get_bitstring(from_read=False)}" + ) + efuse = self.parent["RECOVERY_BOOTLOADER_FLASH_SECTOR_LO"] + efuse.save(new_value & 0x1FF) + log.print( + f"\t - '{efuse.name}' {efuse.get_bitstring()} -> {efuse.get_bitstring(from_read=False)}" + ) + + +class EfuseBtldrAntiRollbackField(EfuseField): + def get(self, from_read=True): + hi_bits = self.parent["BOOTLOADER_ANTI_ROLLBACK_SECURE_VERSION_HI"].get( + from_read + ) + assert self.parent["BOOTLOADER_ANTI_ROLLBACK_SECURE_VERSION_HI"].bit_len == 1 + lo_bits = self.parent["BOOTLOADER_ANTI_ROLLBACK_SECURE_VERSION_LO"].get( + from_read + ) + assert self.parent["BOOTLOADER_ANTI_ROLLBACK_SECURE_VERSION_LO"].bit_len == 3 return (hi_bits << 3) + lo_bits def save(self, new_value): - raise esptool.FatalError("Burning %s is not supported" % self.name) + efuse = self.parent["BOOTLOADER_ANTI_ROLLBACK_SECURE_VERSION_HI"] + efuse.save((new_value >> 3) & 1) + log.print( + f"\t - '{efuse.name}' {efuse.get_bitstring()} -> {efuse.get_bitstring(from_read=False)}" + ) + efuse = self.parent["BOOTLOADER_ANTI_ROLLBACK_SECURE_VERSION_LO"] + efuse.save(new_value & 0x7) + log.print( + f"\t - '{efuse.name}' {efuse.get_bitstring()} -> {efuse.get_bitstring(from_read=False)}" + ) class EfuseTempSensor(EfuseField): @@ -364,7 +395,7 @@ def check_format(self, new_value_str): def check(self): errs, fail = self.parent.get_block_errors(self.block) if errs != 0 or fail: - output = "Block%d has ERRORS:%d FAIL:%d" % (self.block, errs, fail) + output = f"Block{self.block} has ERRORS:{errs} FAIL:{fail}." else: output = "OK" return "(" + output + ")" @@ -385,10 +416,8 @@ def get(self, from_read=True): def save(self, new_value): def print_field(e, new_value): - print( - " - '{}' ({}) {} -> {}".format( - e.name, e.description, e.get_bitstring(), new_value - ) + log.print( + f" - '{e.name}' ({e.description}) {e.get_bitstring()} -> {new_value}" ) if self.name == "CUSTOM_MAC": @@ -398,15 +427,19 @@ def print_field(e, new_value): else: # Writing the BLOCK1 (MAC_SPI_8M_0) default MAC is not possible, # as it's written in the factory. - raise esptool.FatalError(f"Burning {self.name} is not supported") + raise esptool.FatalError(f"Burning {self.name} is not supported.") # fmt: off class EfuseKeyPurposeField(EfuseField): KEY_PURPOSES = [ ("USER", 0, None, None, "no_need_rd_protect"), # User purposes (software-only use) - ("ECDSA_KEY", 1, None, "Reverse", "need_rd_protect"), # ECDSA key + ("ECDSA_KEY", 1, None, "Reverse", "need_rd_protect"), # ECDSA key P256 + ("ECDSA_KEY_P256", 1, None, "Reverse", "need_rd_protect"), # ECDSA key P256 ("RESERVED", 1, None, None, "no_need_rd_protect"), # Reserved + ("XTS_AES_256_KEY_1", 2, None, "Reverse", "need_rd_protect"), # XTS_AES_256_KEY_1 (flash/PSRAM encryption) + ("XTS_AES_256_KEY_2", 3, None, "Reverse", "need_rd_protect"), # XTS_AES_256_KEY_2 (flash/PSRAM encryption) + ("XTS_AES_256_KEY", -1, "VIRTUAL", None, "no_need_rd_protect"), # Virtual purpose splits to XTS_AES_256_KEY_1 and XTS_AES_256_KEY_2 ("XTS_AES_128_KEY", 4, None, "Reverse", "need_rd_protect"), # XTS_AES_128_KEY (flash/PSRAM encryption) ("HMAC_DOWN_ALL", 5, None, None, "need_rd_protect"), # HMAC Downstream mode ("HMAC_DOWN_JTAG", 6, None, None, "need_rd_protect"), # JTAG soft enable key (uses HMAC Downstream mode) @@ -415,6 +448,14 @@ class EfuseKeyPurposeField(EfuseField): ("SECURE_BOOT_DIGEST0", 9, "DIGEST", None, "no_need_rd_protect"), # SECURE_BOOT_DIGEST0 (Secure Boot key digest) ("SECURE_BOOT_DIGEST1", 10, "DIGEST", None, "no_need_rd_protect"), # SECURE_BOOT_DIGEST1 (Secure Boot key digest) ("SECURE_BOOT_DIGEST2", 11, "DIGEST", None, "no_need_rd_protect"), # SECURE_BOOT_DIGEST2 (Secure Boot key digest) + ("KM_INIT_KEY", 12, None, None, "need_rd_protect"), # init key that is used for the generation of AES/ECDSA key + ("XTS_AES_256_PSRAM_KEY_1", 13, None, "Reverse", "need_rd_protect"), # XTS_AES_256_PSRAM_KEY_1 (PSRAM encryption) + ("XTS_AES_256_PSRAM_KEY_2", 14, None, "Reverse", "need_rd_protect"), # XTS_AES_256_PSRAM_KEY_1 (PSRAM encryption) + # ("XTS_AES_256_PSRAM_KEY", -2, "VIRTUAL", None, "no_need_rd_protect"), # Virtual purpose splits to XTS_AES_256_PSRAM_KEY_1 and XTS_AES_256_PSRAM_KEY_1 + ("XTS_AES_128_PSRAM_KEY", 15, None, "Reverse", "need_rd_protect"), # XTS_AES_128_PSRAM_KEY (PSRAM encryption) + ("ECDSA_KEY_P192", 16, None, "Reverse", "need_rd_protect"), # ECDSA key P192 + ("ECDSA_KEY_P384_L", 17, None, "Reverse", "need_rd_protect"), # ECDSA key P384 low + ("ECDSA_KEY_P384_H", 18, None, "Reverse", "need_rd_protect"), # ECDSA key P384 high ] # fmt: on KEY_PURPOSES_NAME = [name[0] for name in KEY_PURPOSES] @@ -430,9 +471,9 @@ def check_format(self, new_value_str): break if raw_val.isdigit(): if int(raw_val) not in [p[1] for p in self.KEY_PURPOSES if p[1] > 0]: - raise esptool.FatalError("'%s' can not be set (value out of range)" % raw_val) + raise esptool.FatalError(f"'{raw_val}' can not be set (value out of range).") else: - raise esptool.FatalError("'%s' unknown name" % raw_val) + raise esptool.FatalError(f"'{raw_val}' unknown name.") return raw_val def need_reverse(self, new_key_purpose): diff --git a/tools/esptool_py/espefuse/efuse/esp32c5/mem_definition.py b/tools/esptool_py/espefuse/efuse/esp32c5/mem_definition.py index 0520328baf..74643c2535 100644 --- a/tools/esptool_py/espefuse/efuse/esp32c5/mem_definition.py +++ b/tools/esptool_py/espefuse/efuse/esp32c5/mem_definition.py @@ -25,20 +25,20 @@ class EfuseDefineRegisters(EfuseRegistersBase): EFUSE_CHECK_VALUE0_REG = DR_REG_EFUSE_BASE + 0x020 EFUSE_CLK_REG = DR_REG_EFUSE_BASE + 0x1C8 EFUSE_CONF_REG = DR_REG_EFUSE_BASE + 0x1CC - EFUSE_STATUS_REG = DR_REG_EFUSE_BASE + 0x1D0 - EFUSE_CMD_REG = DR_REG_EFUSE_BASE + 0x1D4 - EFUSE_RD_RS_ERR0_REG = DR_REG_EFUSE_BASE + 0x1C0 - EFUSE_RD_RS_ERR1_REG = DR_REG_EFUSE_BASE + 0x1C4 + EFUSE_STATUS_REG = DR_REG_EFUSE_BASE + 0x1D4 + EFUSE_CMD_REG = DR_REG_EFUSE_BASE + 0x1D8 + EFUSE_RD_RS_ERR0_REG = DR_REG_EFUSE_BASE + 0x190 + EFUSE_RD_RS_ERR1_REG = DR_REG_EFUSE_BASE + 0x194 EFUSE_RD_REPEAT_ERR0_REG = DR_REG_EFUSE_BASE + 0x17C EFUSE_RD_REPEAT_ERR1_REG = DR_REG_EFUSE_BASE + 0x180 EFUSE_RD_REPEAT_ERR2_REG = DR_REG_EFUSE_BASE + 0x184 EFUSE_RD_REPEAT_ERR3_REG = DR_REG_EFUSE_BASE + 0x188 EFUSE_RD_REPEAT_ERR4_REG = DR_REG_EFUSE_BASE + 0x18C - EFUSE_DAC_CONF_REG = DR_REG_EFUSE_BASE + 0x1E8 - EFUSE_RD_TIM_CONF_REG = DR_REG_EFUSE_BASE + 0x1EC - EFUSE_WR_TIM_CONF1_REG = DR_REG_EFUSE_BASE + 0x1F0 - EFUSE_WR_TIM_CONF2_REG = DR_REG_EFUSE_BASE + 0x1F4 - EFUSE_DATE_REG = DR_REG_EFUSE_BASE + 0x1FC + EFUSE_DAC_CONF_REG = DR_REG_EFUSE_BASE + 0x1EC + EFUSE_RD_TIM_CONF_REG = DR_REG_EFUSE_BASE + 0x1F0 + EFUSE_WR_TIM_CONF1_REG = DR_REG_EFUSE_BASE + 0x1F4 + EFUSE_WR_TIM_CONF2_REG = DR_REG_EFUSE_BASE + 0x1F8 + EFUSE_DATE_REG = DR_REG_EFUSE_BASE + 0x198 EFUSE_WRITE_OP_CODE = 0x5A5A EFUSE_READ_OP_CODE = 0x5AA5 EFUSE_PGM_CMD_MASK = 0x3 @@ -114,12 +114,8 @@ class EfuseDefineFields(EfuseFieldsBase): def __init__(self, extend_efuse_table) -> None: # List of efuse fields from TRM the chapter eFuse Controller. self.EFUSES = [] - self.KEYBLOCKS = [] - - # if BLK_VERSION_MINOR is 1, these efuse fields are in BLOCK2 self.BLOCK2_CALIBRATION_EFUSES = [] - self.CALC = [] dir_name = os.path.dirname(os.path.abspath(__file__)) @@ -162,6 +158,26 @@ def __init__(self, extend_efuse_table) -> None: f.description = "calc MAC_EUI64 = MAC[0]:MAC[1]:MAC[2]:MAC_EXT[0]:MAC_EXT[1]:MAC[3]:MAC[4]:MAC[5]" self.CALC.append(f) + f = Field() + f.name = "RECOVERY_BOOTLOADER_FLASH_SECTOR" + f.block = 0 + f.bit_len = 12 + f.type = f"uint:{f.bit_len}" + f.category = "config" + f.class_type = "recovery_bootloader" + f.description = "calc recovery_bootloader = recovery_bootloader_hi << 9 + recovery_bootloader_lo" + self.CALC.append(f) + + f = Field() + f.name = "BOOTLOADER_ANTI_ROLLBACK_SECURE_VERSION" + f.block = 0 + f.bit_len = 4 + f.type = f"uint:{f.bit_len}" + f.category = "config" + f.class_type = "bootloader_anti_rollback" + f.description = "calc ANTI_ROLLBACK_SECURE_VERSION = ANTI_ROLLBACK_SECURE_VERSION_HI << 3 + ANTI_ROLLBACK_SECURE_VERSION_LO" + self.CALC.append(f) + for efuse in self.ALL_EFUSES: if efuse is not None: self.EFUSES.append(efuse) diff --git a/tools/esptool_py/espefuse/efuse/esp32c5/operations.py b/tools/esptool_py/espefuse/efuse/esp32c5/operations.py index 1fca6bcb69..83c571d121 100644 --- a/tools/esptool_py/espefuse/efuse/esp32c5/operations.py +++ b/tools/esptool_py/espefuse/efuse/esp32c5/operations.py @@ -1,395 +1,317 @@ # This file includes the operations with eFuses for ESP32-C5 chip # -# SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD +# SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD # # SPDX-License-Identifier: GPL-2.0-or-later -import argparse -import os # noqa: F401. It is used in IDF scripts -import traceback +from io import IOBase +from typing import BinaryIO +import rich_click as click import espsecure - import esptool +from esptool.logger import log from . import fields +from .mem_definition import EfuseDefineBlocks from .. import util from ..base_operations import ( - add_common_commands, + BaseCommands, + NonCompositeTuple, + TupleParameter, add_force_write_always, add_show_sensitive_info_option, - burn_bit, - burn_block_data, - burn_efuse, - check_error, - dump, - read_protect_efuse, - summary, - write_protect_efuse, + protect_options, ) -def protect_options(p): - p.add_argument( - "--no-write-protect", - help="Disable write-protecting of the key. The key remains writable. " - "(The keys use the RS coding scheme that does not support " - "post-write data changes. Forced write can damage RS encoding bits.) " - "The write-protecting of keypurposes does not depend on the option, " - "it will be set anyway.", - action="store_true", - ) - p.add_argument( - "--no-read-protect", - help="Disable read-protecting of the key. The key remains readable software." - "The key with keypurpose[USER, RESERVED and *_DIGEST] " - "will remain readable anyway. For the rest keypurposes the read-protection " - "will be defined the option (Read-protect by default).", - action="store_true", - ) +class ESP32C5Commands(BaseCommands): + CHIP_NAME = "ESP32-C5" + efuse_lib = fields.EspEfuses + ################################### CLI definitions ################################### -def add_commands(subparsers, efuses): - add_common_commands(subparsers, efuses) - burn_key = subparsers.add_parser( - "burn_key", help="Burn the key block with the specified name" - ) - protect_options(burn_key) - add_force_write_always(burn_key) - add_show_sensitive_info_option(burn_key) - burn_key.add_argument( - "block", - help="Key block to burn", - action="append", - choices=efuses.BLOCKS_FOR_KEYS, - ) - burn_key.add_argument( - "keyfile", - help="File containing 256 bits of binary key data. For the ECDSA_KEY purpose use PEM file.", - action="append", - type=argparse.FileType("rb"), - ) - burn_key.add_argument( - "keypurpose", - help="Purpose to set.", - action="append", - choices=fields.EfuseKeyPurposeField.KEY_PURPOSES_NAME, - ) - for _ in efuses.BLOCKS_FOR_KEYS: - burn_key.add_argument( - "block", - help="Key block to burn", - nargs="?", - action="append", - metavar="BLOCK", - choices=efuses.BLOCKS_FOR_KEYS, - ) - burn_key.add_argument( - "keyfile", - help="File containing 256 bits of binary key data. For the ECDSA_KEY purpose use PEM file.", - nargs="?", - action="append", - metavar="KEYFILE", - type=argparse.FileType("rb"), - ) - burn_key.add_argument( - "keypurpose", - help="Purpose to set.", - nargs="?", - action="append", - metavar="KEYPURPOSE", - choices=fields.EfuseKeyPurposeField.KEY_PURPOSES_NAME, - ) + def add_cli_commands(self, cli: click.Group): + super().add_cli_commands(cli) + blocks_for_keys = EfuseDefineBlocks().get_blocks_for_keys() - burn_key_digest = subparsers.add_parser( - "burn_key_digest", - help="Parse a RSA public key and burn the digest to key efuse block", - ) - protect_options(burn_key_digest) - add_force_write_always(burn_key_digest) - add_show_sensitive_info_option(burn_key_digest) - burn_key_digest.add_argument( - "block", - help="Key block to burn", - action="append", - choices=efuses.BLOCKS_FOR_KEYS, - ) - burn_key_digest.add_argument( - "keyfile", - help="Key file to digest (PEM format)", - action="append", - type=argparse.FileType("rb"), - ) - burn_key_digest.add_argument( - "keypurpose", - help="Purpose to set.", - action="append", - choices=fields.EfuseKeyPurposeField.DIGEST_KEY_PURPOSES, - ) - for _ in efuses.BLOCKS_FOR_KEYS: - burn_key_digest.add_argument( - "block", - help="Key block to burn", - nargs="?", - action="append", - metavar="BLOCK", - choices=efuses.BLOCKS_FOR_KEYS, + @cli.command( + "burn-key", + help="Burn the key block with the specified name. Arguments are groups of block name, " + "key file (containing 256 bits of binary key data) and key purpose.\n\n" + f"Block is one of: [{', '.join(blocks_for_keys)}]\n\n" + f"Key purpose is one of: [{', '.join(fields.EfuseKeyPurposeField.KEY_PURPOSES_NAME)}]", ) - burn_key_digest.add_argument( - "keyfile", - help="Key file to digest (PEM format)", - nargs="?", - action="append", - metavar="KEYFILE", - type=argparse.FileType("rb"), + @click.argument( + "block_keyfile_keypurpose", + metavar=" ", + cls=TupleParameter, + required=True, + nargs=-1, + max_arity=len(blocks_for_keys), + type=NonCompositeTuple( + [ + click.Choice(blocks_for_keys), + click.File("rb"), + click.Choice(fields.EfuseKeyPurposeField.KEY_PURPOSES_NAME), + ] + ), ) - burn_key_digest.add_argument( - "keypurpose", - help="Purpose to set.", - nargs="?", - action="append", - metavar="KEYPURPOSE", - choices=fields.EfuseKeyPurposeField.DIGEST_KEY_PURPOSES, + @protect_options + @add_force_write_always + @add_show_sensitive_info_option + @click.pass_context + def burn_key_cli(ctx, **kwargs): + kwargs.pop("force_write_always") + block, keyfile, keypurpose = zip(*kwargs.pop("block_keyfile_keypurpose")) + kwargs["show_sensitive_info"] = ctx.show_sensitive_info + self.burn_key(block, keyfile, keypurpose, **kwargs) + + @cli.command( + "burn-key-digest", + short_help="Parse a RSA public key and burn the digest.", + help="Parse a RSA public key and burn the digest to key eFuse block.\n\n" + f"Block is one of: [{', '.join(blocks_for_keys)}]\n\n" + f"Key purpose is one of: [{', '.join(fields.EfuseKeyPurposeField.DIGEST_KEY_PURPOSES)}]", ) - - p = subparsers.add_parser( - "set_flash_voltage", - help="Permanently set the internal flash voltage regulator " - "to either 1.8V, 3.3V or OFF. " - "This means GPIO45 can be high or low at reset without " - "changing the flash voltage.", - ) - p.add_argument("voltage", help="Voltage selection", choices=["1.8V", "3.3V", "OFF"]) - - p = subparsers.add_parser( - "burn_custom_mac", help="Burn a 48-bit Custom MAC Address to EFUSE BLOCK3." - ) - p.add_argument( - "mac", - help="Custom MAC Address to burn given in hexadecimal format with bytes " - "separated by colons (e.g. AA:CD:EF:01:02:03).", - type=fields.base_fields.CheckArgValue(efuses, "CUSTOM_MAC"), - ) - add_force_write_always(p) - - p = subparsers.add_parser("get_custom_mac", help="Prints the Custom MAC Address.") - - -def burn_custom_mac(esp, efuses, args): - efuses["CUSTOM_MAC"].save(args.mac) - if not efuses.burn_all(check_batch_mode=True): - return - get_custom_mac(esp, efuses, args) - print("Successful") - - -def get_custom_mac(esp, efuses, args): - print("Custom MAC Address: {}".format(efuses["CUSTOM_MAC"].get())) - - -def set_flash_voltage(esp, efuses, args): - raise esptool.FatalError("set_flash_voltage is not supported!") - - -def adc_info(esp, efuses, args): - print("not supported yet") - - -def burn_key(esp, efuses, args, digest=None): - if digest is None: - datafile_list = args.keyfile[ - 0 : len([name for name in args.keyfile if name is not None]) : - ] - else: - datafile_list = digest[0 : len([name for name in digest if name is not None]) :] - efuses.force_write_always = args.force_write_always - block_name_list = args.block[ - 0 : len([name for name in args.block if name is not None]) : - ] - keypurpose_list = args.keypurpose[ - 0 : len([name for name in args.keypurpose if name is not None]) : - ] - - util.check_duplicate_name_in_list(block_name_list) - if len(block_name_list) != len(datafile_list) or len(block_name_list) != len( - keypurpose_list - ): - raise esptool.FatalError( - "The number of blocks (%d), datafile (%d) and keypurpose (%d) " - "should be the same." - % (len(block_name_list), len(datafile_list), len(keypurpose_list)) + @click.argument( + "block_keyfile_keypurpose", + metavar=" ", + cls=TupleParameter, + required=True, + nargs=-1, + max_arity=len(blocks_for_keys), + type=NonCompositeTuple( + [ + click.Choice(blocks_for_keys), + click.File("rb"), + click.Choice(fields.EfuseKeyPurposeField.DIGEST_KEY_PURPOSES), + ] + ), ) - - print("Burn keys to blocks:") - for block_name, datafile, keypurpose in zip( - block_name_list, datafile_list, keypurpose_list + @protect_options + @add_force_write_always + @add_show_sensitive_info_option + @click.pass_context + def burn_key_digest_cli(ctx, **kwargs): + kwargs.pop("force_write_always") + block, keyfile, keypurpose = zip(*kwargs.pop("block_keyfile_keypurpose")) + kwargs["show_sensitive_info"] = ctx.show_sensitive_info + self.burn_key_digest(block, keyfile, keypurpose, **kwargs) + + ###################################### Commands ###################################### + + def adc_info(self): + log.print("Block version:", self.efuses.get_block_version()) + if self.efuses.get_block_version() >= 1: + for efuse in self.efuses: + if efuse.category == "calibration": + log.print(f"{efuse.name:<30} = ", self.efuses[efuse.name].get()) + + def burn_key( + self, + blocks: list[str], + keyfiles: list[BinaryIO], + keypurposes: list[str], + no_write_protect: bool = False, + no_read_protect: bool = False, + show_sensitive_info: bool = False, + digest: list[bytes] | None = None, ): - efuse = None - for block in efuses.blocks: - if block_name == block.name or block_name in block.alias: - efuse = efuses[block.name] - if efuse is None: - raise esptool.FatalError("Unknown block name - %s" % (block_name)) - num_bytes = efuse.bit_len // 8 - - block_num = efuses.get_index_block_by_name(block_name) - block = efuses.blocks[block_num] - + """Burn the key block with the specified name. Arguments are groups of block name, + key file (containing 256 bits of binary key data) and key purpose. + + Args: + blocks: List of eFuse block names to burn keys to. + keyfiles: List of open files to read key data from. + keypurposes: List of key purposes to burn. + no_write_protect: If True, the write protection will NOT be enabled. + no_read_protect: If True, the read protection will NOT be enabled. + show_sensitive_info: If True, the sensitive information will be shown. + digest: List of digests to burn. + """ + datafile_list: list[BinaryIO] | list[bytes] if digest is None: - if keypurpose == "ECDSA_KEY": - sk = espsecure.load_ecdsa_signing_key(datafile) - data = sk.to_string() - if len(data) == 24: - # the private key is 24 bytes long for NIST192p, and 8 bytes of padding - data = b"\x00" * 8 + data - else: - data = datafile.read() + datafile_list = keyfiles[ + 0 : len([name for name in keyfiles if name is not None]) : + ] else: - data = datafile + datafile_list = digest[ + 0 : len([name for name in digest if name is not None]) : + ] + block_name_list = blocks[ + 0 : len([name for name in blocks if name is not None]) : + ] + keypurpose_list = keypurposes[ + 0 : len([name for name in keypurposes if name is not None]) : + ] - print(" - %s" % (efuse.name), end=" ") - revers_msg = None - if efuses[block.key_purpose_name].need_reverse(keypurpose): - revers_msg = f"\tReversing byte order for {keypurpose} hardware peripheral" - data = data[::-1] - print( - "-> [{}]".format( - util.hexify(data, " ") - if args.show_sensitive_info - else " ".join(["??"] * len(data)) + if "XTS_AES_256_KEY" in keypurpose_list: + # XTS_AES_256_KEY is not an actual HW key purpose, needs to be split into + # XTS_AES_256_KEY_1 and XTS_AES_256_KEY_2 + block_name_list, datafile_list, keypurpose_list = self._split_512_bit_key( + block_name_list, + datafile_list, # type: ignore + keypurpose_list, ) - ) - if revers_msg: - print(revers_msg) - if len(data) != num_bytes: + + util.check_duplicate_name_in_list(block_name_list) + if len(block_name_list) != len(datafile_list) or len(block_name_list) != len( + keypurpose_list + ): raise esptool.FatalError( - "Incorrect key file size %d. Key file must be %d bytes (%d bits) " - "of raw binary key data." % (len(data), num_bytes, num_bytes * 8) + "The number of blocks (%d), datafile (%d) and keypurpose (%d) " + "should be the same." + % (len(block_name_list), len(datafile_list), len(keypurpose_list)) ) - if efuses[block.key_purpose_name].need_rd_protect(keypurpose): - read_protect = False if args.no_read_protect else True - else: - read_protect = False - write_protect = not args.no_write_protect + log.print("Burn keys to blocks:") + for block_name, datafile, keypurpose in zip( + block_name_list, datafile_list, keypurpose_list + ): + efuse = None + for block in self.efuses.blocks: + if block_name == block.name or block_name in block.alias: + efuse = self.efuses[block.name] + if efuse is None: + raise esptool.FatalError(f"Unknown block name - {block_name}.") + num_bytes = efuse.bit_len // 8 + + block_num = self.efuses.get_index_block_by_name(block_name) + block = self.efuses.blocks[block_num] + + if isinstance(datafile, IOBase): + if keypurpose.startswith("ECDSA_KEY"): + sk = espsecure.load_ecdsa_signing_key(datafile) # type: ignore + data = espsecure.get_ecdsa_signing_key_raw_bytes(sk) + if len(data) == 24: + # the private key is 24 bytes long for NIST192p, and 8 bytes of padding + data = b"\x00" * 8 + data + else: + data = datafile.read() + datafile.close() + else: + data = datafile - # using efuse instead of a block gives the advantage of checking it as the whole field. - efuse.save(data) + log.print(f" - {efuse.name}", end=" ") + revers_msg = None + if self.efuses[block.key_purpose_name].need_reverse(keypurpose): + revers_msg = ( + f"\tReversing byte order for {keypurpose} hardware peripheral..." + ) + data = data[::-1] + log.print( + "-> [{}]".format( + util.hexify(data, " ") + if show_sensitive_info + else " ".join(["??"] * len(data)) + ) + ) + if revers_msg: + log.print(revers_msg) + if len(data) != num_bytes: + raise esptool.FatalError( + f"Incorrect key file size {len(data)}. Key file must be {num_bytes} " + f"bytes ({num_bytes * 8} bits) of raw binary key data." + ) - disable_wr_protect_key_purpose = False - if efuses[block.key_purpose_name].get() != keypurpose: - if efuses[block.key_purpose_name].is_writeable(): - print( - "\t'%s': '%s' -> '%s'." - % ( - block.key_purpose_name, - efuses[block.key_purpose_name].get(), - keypurpose, + if self.efuses[block.key_purpose_name].need_rd_protect(keypurpose): + read_protect = False if no_read_protect else True + else: + read_protect = False + write_protect = not no_write_protect + + # using eFuse instead of a block gives the advantage of checking it as the whole field. + efuse.save(data) + + disable_wr_protect_key_purpose = False + if self.efuses[block.key_purpose_name].get() != keypurpose: + if self.efuses[block.key_purpose_name].is_writeable(): + log.print( + f"\t'{block.key_purpose_name}': " + f"'{self.efuses[block.key_purpose_name].get()}' -> '{keypurpose}'." + ) + self.efuses[block.key_purpose_name].save(keypurpose) + disable_wr_protect_key_purpose = True + else: + raise esptool.FatalError( + f"It is not possible to change '{block.key_purpose_name}' " + f"to '{keypurpose}' because write protection bit is set." ) - ) - efuses[block.key_purpose_name].save(keypurpose) - disable_wr_protect_key_purpose = True else: + log.print(f"\t'{block.key_purpose_name}' is already '{keypurpose}'.") + if self.efuses[block.key_purpose_name].is_writeable(): + disable_wr_protect_key_purpose = True + + if disable_wr_protect_key_purpose: + log.print(f"\tDisabling write to '{block.key_purpose_name}'...") + self.efuses[block.key_purpose_name].disable_write() + + if read_protect: + log.print("\tDisabling read to key block...") + efuse.disable_read() + + if write_protect: + log.print("\tDisabling write to key block...") + efuse.disable_write() + log.print("") + + if not write_protect: + log.print("Keys will remain writeable (due to --no-write-protect).") + if no_read_protect: + log.print("Keys will remain readable (due to --no-read-protect).") + + if not self.efuses.burn_all(check_batch_mode=True): + return + log.print("Successful.") + + def burn_key_digest( + self, + blocks: list[str], + keyfiles: list[BinaryIO], + keypurposes: list[str], + no_write_protect: bool = False, + no_read_protect: bool = False, + show_sensitive_info: bool = False, + ): + """Parse a RSA public key and burn the digest to key eFuse block. + + Args: + blocks: List of eFuse block names to burn keys to. + keyfiles: List of open files to read key data from. + keypurposes: List of key purposes to burn. + no_write_protect: If True, the write protection will NOT be enabled. + no_read_protect: If True, the read protection will NOT be enabled. + show_sensitive_info: If True, the sensitive information will be shown. + """ + digest_list = [] + datafile_list = keyfiles[ + 0 : len([name for name in keyfiles if name is not None]) : + ] + block_list = blocks[0 : len([block for block in blocks if block is not None]) :] + + for block_name, datafile in zip(block_list, datafile_list): + efuse = None + for blk in self.efuses.blocks: + if block_name == blk.name or block_name in blk.alias: + efuse = self.efuses[blk.name] + if efuse is None: + raise esptool.FatalError(f"Unknown block name - {block_name}.") + num_bytes = efuse.bit_len // 8 + digest = espsecure._digest_sbv2_public_key(datafile) + if len(digest) != num_bytes: raise esptool.FatalError( - "It is not possible to change '%s' to '%s' " - "because write protection bit is set." - % (block.key_purpose_name, keypurpose) + f"Incorrect digest size {len(digest)}. Digest must be {num_bytes} " + f"bytes ({num_bytes * 8} bits) of raw binary key data." ) - else: - print("\t'%s' is already '%s'." % (block.key_purpose_name, keypurpose)) - if efuses[block.key_purpose_name].is_writeable(): - disable_wr_protect_key_purpose = True - - if disable_wr_protect_key_purpose: - print("\tDisabling write to '%s'." % block.key_purpose_name) - efuses[block.key_purpose_name].disable_write() - - if read_protect: - print("\tDisabling read to key block") - efuse.disable_read() - - if write_protect: - print("\tDisabling write to key block") - efuse.disable_write() - print("") - - if not write_protect: - print("Keys will remain writeable (due to --no-write-protect)") - if args.no_read_protect: - print("Keys will remain readable (due to --no-read-protect)") - - if not efuses.burn_all(check_batch_mode=True): - return - print("Successful") - - -def burn_key_digest(esp, efuses, args): - digest_list = [] - datafile_list = args.keyfile[ - 0 : len([name for name in args.keyfile if name is not None]) : - ] - block_list = args.block[ - 0 : len([block for block in args.block if block is not None]) : - ] - for block_name, datafile in zip(block_list, datafile_list): - efuse = None - for block in efuses.blocks: - if block_name == block.name or block_name in block.alias: - efuse = efuses[block.name] - if efuse is None: - raise esptool.FatalError("Unknown block name - %s" % (block_name)) - num_bytes = efuse.bit_len // 8 - digest = espsecure._digest_sbv2_public_key(datafile) - if len(digest) != num_bytes: - raise esptool.FatalError( - "Incorrect digest size %d. Digest must be %d bytes (%d bits) " - "of raw binary key data." % (len(digest), num_bytes, num_bytes * 8) - ) - digest_list.append(digest) - burn_key(esp, efuses, args, digest=digest_list) - - -def espefuse(esp, efuses, args, command): - parser = argparse.ArgumentParser() - subparsers = parser.add_subparsers(dest="operation") - add_commands(subparsers, efuses) - try: - cmd_line_args = parser.parse_args(command.split()) - except SystemExit: - traceback.print_stack() - raise esptool.FatalError('"{}" - incorrect command'.format(command)) - if cmd_line_args.operation == "execute_scripts": - configfiles = cmd_line_args.configfiles - index = cmd_line_args.index - # copy arguments from args to cmd_line_args - vars(cmd_line_args).update(vars(args)) - if cmd_line_args.operation == "execute_scripts": - cmd_line_args.configfiles = configfiles - cmd_line_args.index = index - if cmd_line_args.operation is None: - parser.print_help() - parser.exit(1) - operation_func = globals()[cmd_line_args.operation] - # each 'operation' is a module-level function of the same name - operation_func(esp, efuses, cmd_line_args) - - -def execute_scripts(esp, efuses, args): - efuses.batch_mode_cnt += 1 - del args.operation - scripts = args.scripts - del args.scripts - - for file in scripts: - with open(file.name, "r") as file: - exec(compile(file.read(), file.name, "exec")) - - if args.debug: - for block in efuses.blocks: - data = block.get_bitstring(from_read=False) - block.print_block(data, "regs_for_burn", args.debug) - - efuses.batch_mode_cnt -= 1 - if not efuses.burn_all(check_batch_mode=True): - return - print("Successful") + digest_list.append(digest) + + self.burn_key( + block_list, + datafile_list, + keypurposes, + no_write_protect, + no_read_protect, + show_sensitive_info, + digest=digest_list, + ) diff --git a/tools/esptool_py/espefuse/efuse/esp32c5beta3/operations.py b/tools/esptool_py/espefuse/efuse/esp32c5beta3/operations.py deleted file mode 100644 index fbd721bd63..0000000000 --- a/tools/esptool_py/espefuse/efuse/esp32c5beta3/operations.py +++ /dev/null @@ -1,395 +0,0 @@ -# This file includes the operations with eFuses for ESP32-C5 beta3 chip -# -# SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD -# -# SPDX-License-Identifier: GPL-2.0-or-later - -import argparse -import os # noqa: F401. It is used in IDF scripts -import traceback - -import espsecure - -import esptool - -from . import fields -from .. import util -from ..base_operations import ( - add_common_commands, - add_force_write_always, - add_show_sensitive_info_option, - burn_bit, - burn_block_data, - burn_efuse, - check_error, - dump, - read_protect_efuse, - summary, - write_protect_efuse, -) - - -def protect_options(p): - p.add_argument( - "--no-write-protect", - help="Disable write-protecting of the key. The key remains writable. " - "(The keys use the RS coding scheme that does not support " - "post-write data changes. Forced write can damage RS encoding bits.) " - "The write-protecting of keypurposes does not depend on the option, " - "it will be set anyway.", - action="store_true", - ) - p.add_argument( - "--no-read-protect", - help="Disable read-protecting of the key. The key remains readable software." - "The key with keypurpose[USER, RESERVED and *_DIGEST] " - "will remain readable anyway. For the rest keypurposes the read-protection " - "will be defined the option (Read-protect by default).", - action="store_true", - ) - - -def add_commands(subparsers, efuses): - add_common_commands(subparsers, efuses) - burn_key = subparsers.add_parser( - "burn_key", help="Burn the key block with the specified name" - ) - protect_options(burn_key) - add_force_write_always(burn_key) - add_show_sensitive_info_option(burn_key) - burn_key.add_argument( - "block", - help="Key block to burn", - action="append", - choices=efuses.BLOCKS_FOR_KEYS, - ) - burn_key.add_argument( - "keyfile", - help="File containing 256 bits of binary key data. For the ECDSA_KEY purpose use PEM file.", - action="append", - type=argparse.FileType("rb"), - ) - burn_key.add_argument( - "keypurpose", - help="Purpose to set.", - action="append", - choices=fields.EfuseKeyPurposeField.KEY_PURPOSES_NAME, - ) - for _ in efuses.BLOCKS_FOR_KEYS: - burn_key.add_argument( - "block", - help="Key block to burn", - nargs="?", - action="append", - metavar="BLOCK", - choices=efuses.BLOCKS_FOR_KEYS, - ) - burn_key.add_argument( - "keyfile", - help="File containing 256 bits of binary key data. For the ECDSA_KEY purpose use PEM file.", - nargs="?", - action="append", - metavar="KEYFILE", - type=argparse.FileType("rb"), - ) - burn_key.add_argument( - "keypurpose", - help="Purpose to set.", - nargs="?", - action="append", - metavar="KEYPURPOSE", - choices=fields.EfuseKeyPurposeField.KEY_PURPOSES_NAME, - ) - - burn_key_digest = subparsers.add_parser( - "burn_key_digest", - help="Parse a RSA public key and burn the digest to key efuse block", - ) - protect_options(burn_key_digest) - add_force_write_always(burn_key_digest) - add_show_sensitive_info_option(burn_key_digest) - burn_key_digest.add_argument( - "block", - help="Key block to burn", - action="append", - choices=efuses.BLOCKS_FOR_KEYS, - ) - burn_key_digest.add_argument( - "keyfile", - help="Key file to digest (PEM format)", - action="append", - type=argparse.FileType("rb"), - ) - burn_key_digest.add_argument( - "keypurpose", - help="Purpose to set.", - action="append", - choices=fields.EfuseKeyPurposeField.DIGEST_KEY_PURPOSES, - ) - for _ in efuses.BLOCKS_FOR_KEYS: - burn_key_digest.add_argument( - "block", - help="Key block to burn", - nargs="?", - action="append", - metavar="BLOCK", - choices=efuses.BLOCKS_FOR_KEYS, - ) - burn_key_digest.add_argument( - "keyfile", - help="Key file to digest (PEM format)", - nargs="?", - action="append", - metavar="KEYFILE", - type=argparse.FileType("rb"), - ) - burn_key_digest.add_argument( - "keypurpose", - help="Purpose to set.", - nargs="?", - action="append", - metavar="KEYPURPOSE", - choices=fields.EfuseKeyPurposeField.DIGEST_KEY_PURPOSES, - ) - - p = subparsers.add_parser( - "set_flash_voltage", - help="Permanently set the internal flash voltage regulator " - "to either 1.8V, 3.3V or OFF. " - "This means GPIO45 can be high or low at reset without " - "changing the flash voltage.", - ) - p.add_argument("voltage", help="Voltage selection", choices=["1.8V", "3.3V", "OFF"]) - - p = subparsers.add_parser( - "burn_custom_mac", help="Burn a 48-bit Custom MAC Address to EFUSE BLOCK3." - ) - p.add_argument( - "mac", - help="Custom MAC Address to burn given in hexadecimal format with bytes " - "separated by colons (e.g. AA:CD:EF:01:02:03).", - type=fields.base_fields.CheckArgValue(efuses, "CUSTOM_MAC"), - ) - add_force_write_always(p) - - p = subparsers.add_parser("get_custom_mac", help="Prints the Custom MAC Address.") - - -def burn_custom_mac(esp, efuses, args): - efuses["CUSTOM_MAC"].save(args.mac) - if not efuses.burn_all(check_batch_mode=True): - return - get_custom_mac(esp, efuses, args) - print("Successful") - - -def get_custom_mac(esp, efuses, args): - print("Custom MAC Address: {}".format(efuses["CUSTOM_MAC"].get())) - - -def set_flash_voltage(esp, efuses, args): - raise esptool.FatalError("set_flash_voltage is not supported!") - - -def adc_info(esp, efuses, args): - print("not supported yet") - - -def burn_key(esp, efuses, args, digest=None): - if digest is None: - datafile_list = args.keyfile[ - 0 : len([name for name in args.keyfile if name is not None]) : - ] - else: - datafile_list = digest[0 : len([name for name in digest if name is not None]) :] - efuses.force_write_always = args.force_write_always - block_name_list = args.block[ - 0 : len([name for name in args.block if name is not None]) : - ] - keypurpose_list = args.keypurpose[ - 0 : len([name for name in args.keypurpose if name is not None]) : - ] - - util.check_duplicate_name_in_list(block_name_list) - if len(block_name_list) != len(datafile_list) or len(block_name_list) != len( - keypurpose_list - ): - raise esptool.FatalError( - "The number of blocks (%d), datafile (%d) and keypurpose (%d) " - "should be the same." - % (len(block_name_list), len(datafile_list), len(keypurpose_list)) - ) - - print("Burn keys to blocks:") - for block_name, datafile, keypurpose in zip( - block_name_list, datafile_list, keypurpose_list - ): - efuse = None - for block in efuses.blocks: - if block_name == block.name or block_name in block.alias: - efuse = efuses[block.name] - if efuse is None: - raise esptool.FatalError("Unknown block name - %s" % (block_name)) - num_bytes = efuse.bit_len // 8 - - block_num = efuses.get_index_block_by_name(block_name) - block = efuses.blocks[block_num] - - if digest is None: - if keypurpose == "ECDSA_KEY": - sk = espsecure.load_ecdsa_signing_key(datafile) - data = sk.to_string() - if len(data) == 24: - # the private key is 24 bytes long for NIST192p, and 8 bytes of padding - data = b"\x00" * 8 + data - else: - data = datafile.read() - else: - data = datafile - - print(" - %s" % (efuse.name), end=" ") - revers_msg = None - if efuses[block.key_purpose_name].need_reverse(keypurpose): - revers_msg = f"\tReversing byte order for {keypurpose} hardware peripheral" - data = data[::-1] - print( - "-> [{}]".format( - util.hexify(data, " ") - if args.show_sensitive_info - else " ".join(["??"] * len(data)) - ) - ) - if revers_msg: - print(revers_msg) - if len(data) != num_bytes: - raise esptool.FatalError( - "Incorrect key file size %d. Key file must be %d bytes (%d bits) " - "of raw binary key data." % (len(data), num_bytes, num_bytes * 8) - ) - - if efuses[block.key_purpose_name].need_rd_protect(keypurpose): - read_protect = False if args.no_read_protect else True - else: - read_protect = False - write_protect = not args.no_write_protect - - # using efuse instead of a block gives the advantage of checking it as the whole field. - efuse.save(data) - - disable_wr_protect_key_purpose = False - if efuses[block.key_purpose_name].get() != keypurpose: - if efuses[block.key_purpose_name].is_writeable(): - print( - "\t'%s': '%s' -> '%s'." - % ( - block.key_purpose_name, - efuses[block.key_purpose_name].get(), - keypurpose, - ) - ) - efuses[block.key_purpose_name].save(keypurpose) - disable_wr_protect_key_purpose = True - else: - raise esptool.FatalError( - "It is not possible to change '%s' to '%s' " - "because write protection bit is set." - % (block.key_purpose_name, keypurpose) - ) - else: - print("\t'%s' is already '%s'." % (block.key_purpose_name, keypurpose)) - if efuses[block.key_purpose_name].is_writeable(): - disable_wr_protect_key_purpose = True - - if disable_wr_protect_key_purpose: - print("\tDisabling write to '%s'." % block.key_purpose_name) - efuses[block.key_purpose_name].disable_write() - - if read_protect: - print("\tDisabling read to key block") - efuse.disable_read() - - if write_protect: - print("\tDisabling write to key block") - efuse.disable_write() - print("") - - if not write_protect: - print("Keys will remain writeable (due to --no-write-protect)") - if args.no_read_protect: - print("Keys will remain readable (due to --no-read-protect)") - - if not efuses.burn_all(check_batch_mode=True): - return - print("Successful") - - -def burn_key_digest(esp, efuses, args): - digest_list = [] - datafile_list = args.keyfile[ - 0 : len([name for name in args.keyfile if name is not None]) : - ] - block_list = args.block[ - 0 : len([block for block in args.block if block is not None]) : - ] - for block_name, datafile in zip(block_list, datafile_list): - efuse = None - for block in efuses.blocks: - if block_name == block.name or block_name in block.alias: - efuse = efuses[block.name] - if efuse is None: - raise esptool.FatalError("Unknown block name - %s" % (block_name)) - num_bytes = efuse.bit_len // 8 - digest = espsecure._digest_sbv2_public_key(datafile) - if len(digest) != num_bytes: - raise esptool.FatalError( - "Incorrect digest size %d. Digest must be %d bytes (%d bits) " - "of raw binary key data." % (len(digest), num_bytes, num_bytes * 8) - ) - digest_list.append(digest) - burn_key(esp, efuses, args, digest=digest_list) - - -def espefuse(esp, efuses, args, command): - parser = argparse.ArgumentParser() - subparsers = parser.add_subparsers(dest="operation") - add_commands(subparsers, efuses) - try: - cmd_line_args = parser.parse_args(command.split()) - except SystemExit: - traceback.print_stack() - raise esptool.FatalError('"{}" - incorrect command'.format(command)) - if cmd_line_args.operation == "execute_scripts": - configfiles = cmd_line_args.configfiles - index = cmd_line_args.index - # copy arguments from args to cmd_line_args - vars(cmd_line_args).update(vars(args)) - if cmd_line_args.operation == "execute_scripts": - cmd_line_args.configfiles = configfiles - cmd_line_args.index = index - if cmd_line_args.operation is None: - parser.print_help() - parser.exit(1) - operation_func = globals()[cmd_line_args.operation] - # each 'operation' is a module-level function of the same name - operation_func(esp, efuses, cmd_line_args) - - -def execute_scripts(esp, efuses, args): - efuses.batch_mode_cnt += 1 - del args.operation - scripts = args.scripts - del args.scripts - - for file in scripts: - with open(file.name, "r") as file: - exec(compile(file.read(), file.name, "exec")) - - if args.debug: - for block in efuses.blocks: - data = block.get_bitstring(from_read=False) - block.print_block(data, "regs_for_burn", args.debug) - - efuses.batch_mode_cnt -= 1 - if not efuses.burn_all(check_batch_mode=True): - return - print("Successful") diff --git a/tools/esptool_py/espefuse/efuse/esp32c6/__init__.py b/tools/esptool_py/espefuse/efuse/esp32c6/__init__.py index a3b55a8023..89782d5efc 100644 --- a/tools/esptool_py/espefuse/efuse/esp32c6/__init__.py +++ b/tools/esptool_py/espefuse/efuse/esp32c6/__init__.py @@ -1,3 +1,5 @@ from . import operations from .emulate_efuse_controller import EmulateEfuseController from .fields import EspEfuses + +commands = operations.ESP32C6Commands diff --git a/tools/esptool_py/espefuse/efuse/esp32c6/fields.py b/tools/esptool_py/espefuse/efuse/esp32c6/fields.py index 70df55cecd..47662c6fc9 100644 --- a/tools/esptool_py/espefuse/efuse/esp32c6/fields.py +++ b/tools/esptool_py/espefuse/efuse/esp32c6/fields.py @@ -8,7 +8,7 @@ import struct import sys import time - +from esptool.logger import log from bitstring import BitArray import esptool @@ -55,9 +55,6 @@ class EspEfuses(base_fields.EspEfusesBase): Wrapper object to manage the efuse fields in a connected ESP bootloader """ - debug = False - do_not_confirm = False - def __init__( self, esp, @@ -66,14 +63,12 @@ def __init__( do_not_confirm=False, extend_efuse_table=None, ): + super().__init__(esp, skip_connect, debug, do_not_confirm, extend_efuse_table) self.Blocks = EfuseDefineBlocks() self.Fields = EfuseDefineFields(extend_efuse_table) self.REGS = EfuseDefineRegisters self.BURN_BLOCK_DATA_NAMES = self.Blocks.get_burn_block_data_names() self.BLOCKS_FOR_KEYS = self.Blocks.get_blocks_for_keys() - self._esp = esp - self.debug = debug - self.do_not_confirm = do_not_confirm if esp.CHIP_NAME != "ESP32-C6": raise esptool.FatalError( "Expected the 'esp' param for ESP32-C6 chip but got for '%s'." @@ -102,7 +97,7 @@ def __init__( for efuse in self.Fields.BLOCK2_CALIBRATION_EFUSES ] else: - if self["BLK_VERSION_MINOR"].get() == 1: + if self.get_block_version() >= 1: self.efuses += [ EfuseField.convert(self, efuse) for efuse in self.Fields.BLOCK2_CALIBRATION_EFUSES @@ -136,14 +131,14 @@ def read_coding_scheme(self): self.coding_scheme = self.REGS.CODING_SCHEME_RS def print_status_regs(self): - print("") + log.print("") self.blocks[0].print_block(self.blocks[0].err_bitarray, "err__regs", debug=True) - print( + log.print( "{:27} 0x{:08x}".format( "EFUSE_RD_RS_ERR0_REG", self.read_reg(self.REGS.EFUSE_RD_RS_ERR0_REG) ) ) - print( + log.print( "{:27} 0x{:08x}".format( "EFUSE_RD_RS_ERR1_REG", self.read_reg(self.REGS.EFUSE_RD_RS_ERR1_REG) ) @@ -176,7 +171,7 @@ def wait_efuse_idle(self): # For PGM_CMD it is not necessary. return raise esptool.FatalError( - "Timed out waiting for Efuse controller command to complete" + "Timed out waiting for eFuse controller command to complete" ) def efuse_program(self, block): @@ -204,30 +199,30 @@ def efuse_read(self): try: self._esp = self.reconnect_chip(self._esp) except esptool.FatalError: - print("Can not re-connect to the chip") + log.print("Can not re-connect to the chip.") if not self["DIS_DOWNLOAD_MODE"].get() and self[ "DIS_DOWNLOAD_MODE" ].get(from_read=False): - print( + log.print( "This is the correct behavior as we are actually burning " - "DIS_DOWNLOAD_MODE which disables the connection to the chip" + "DIS_DOWNLOAD_MODE which disables the connection to the chip." ) - print("DIS_DOWNLOAD_MODE is enabled") - print("Successful") + log.print("DIS_DOWNLOAD_MODE is enabled.") + log.print("Successful.") sys.exit(0) # finish without errors raise - print("Established a connection with the chip") + log.print("Established a connection with the chip.") if self._esp.secure_download_mode and not secure_download_mode_before: - print("Secure download mode is enabled") + log.print("Secure download mode is enabled.") if not self["ENABLE_SECURITY_DOWNLOAD"].get() and self[ "ENABLE_SECURITY_DOWNLOAD" ].get(from_read=False): - print( - "espefuse tool can not continue to work in Secure download mode" + log.print( + "espefuse can not continue to work in Secure download mode." ) - print("ENABLE_SECURITY_DOWNLOAD is enabled") - print("Successful") + log.print("ENABLE_SECURITY_DOWNLOAD is enabled.") + log.print("Successful.") sys.exit(0) # finish without errors raise @@ -280,9 +275,9 @@ def get_coding_scheme_warnings(self, silent=False): block.num_errors = (reg_value >> err_num_offs) & err_num_mask ret_fail |= block.fail if not silent and (block.fail or block.num_errors): - print( - "Error(s) in BLOCK%d [ERRORS:%d FAIL:%d]" - % (block.id, block.num_errors, block.fail) + log.print( + f"Error(s) in BLOCK{block.id} " + f"[ERRORS:{block.num_errors} FAIL:{block.fail}]." ) if (self.debug or ret_fail) and not silent: self.print_status_regs() @@ -364,7 +359,7 @@ def check_format(self, new_value_str): def check(self): errs, fail = self.parent.get_block_errors(self.block) if errs != 0 or fail: - output = "Block%d has ERRORS:%d FAIL:%d" % (self.block, errs, fail) + output = f"Block{self.block} has ERRORS:{errs} FAIL:{fail}" else: output = "OK" return "(" + output + ")" @@ -385,10 +380,8 @@ def get(self, from_read=True): def save(self, new_value): def print_field(e, new_value): - print( - " - '{}' ({}) {} -> {}".format( - e.name, e.description, e.get_bitstring(), new_value - ) + log.print( + f" - '{e.name}' ({e.description}) {e.get_bitstring()} -> {new_value}" ) if self.name == "CUSTOM_MAC": @@ -429,9 +422,9 @@ def check_format(self, new_value_str): break if raw_val.isdigit(): if int(raw_val) not in [p[1] for p in self.KEY_PURPOSES if p[1] > 0]: - raise esptool.FatalError("'%s' can not be set (value out of range)" % raw_val) + raise esptool.FatalError(f"'{raw_val}' can not be set (value out of range).") else: - raise esptool.FatalError("'%s' unknown name" % raw_val) + raise esptool.FatalError(f"'{raw_val}' unknown name.") return raw_val def need_reverse(self, new_key_purpose): diff --git a/tools/esptool_py/espefuse/efuse/esp32c6/mem_definition.py b/tools/esptool_py/espefuse/efuse/esp32c6/mem_definition.py index 4574fdf63e..788828a366 100644 --- a/tools/esptool_py/espefuse/efuse/esp32c6/mem_definition.py +++ b/tools/esptool_py/espefuse/efuse/esp32c6/mem_definition.py @@ -114,12 +114,8 @@ class EfuseDefineFields(EfuseFieldsBase): def __init__(self, extend_efuse_table) -> None: # List of efuse fields from TRM the chapter eFuse Controller. self.EFUSES = [] - self.KEYBLOCKS = [] - - # if BLK_VERSION_MINOR is 1, these efuse fields are in BLOCK2 self.BLOCK2_CALIBRATION_EFUSES = [] - self.CALC = [] dir_name = os.path.dirname(os.path.abspath(__file__)) diff --git a/tools/esptool_py/espefuse/efuse/esp32c6/operations.py b/tools/esptool_py/espefuse/efuse/esp32c6/operations.py index 9307ecac3b..cf04aef71f 100644 --- a/tools/esptool_py/espefuse/efuse/esp32c6/operations.py +++ b/tools/esptool_py/espefuse/efuse/esp32c6/operations.py @@ -1,411 +1,315 @@ # This file includes the operations with eFuses for ESP32-C6 chip # -# SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD +# SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD # # SPDX-License-Identifier: GPL-2.0-or-later -import argparse -import os # noqa: F401. It is used in IDF scripts -import traceback +from io import IOBase +from typing import BinaryIO +from esptool.logger import log +import rich_click as click import espsecure - import esptool from . import fields +from .mem_definition import EfuseDefineBlocks from .. import util from ..base_operations import ( - add_common_commands, + BaseCommands, + NonCompositeTuple, + TupleParameter, add_force_write_always, add_show_sensitive_info_option, - burn_bit, - burn_block_data, - burn_efuse, - check_error, - dump, - read_protect_efuse, - summary, - write_protect_efuse, + protect_options, ) -def protect_options(p): - p.add_argument( - "--no-write-protect", - help="Disable write-protecting of the key. The key remains writable. " - "(The keys use the RS coding scheme that does not support " - "post-write data changes. Forced write can damage RS encoding bits.) " - "The write-protecting of keypurposes does not depend on the option, " - "it will be set anyway.", - action="store_true", - ) - p.add_argument( - "--no-read-protect", - help="Disable read-protecting of the key. The key remains readable software." - "The key with keypurpose[USER, RESERVED and *_DIGEST] " - "will remain readable anyway. For the rest keypurposes the read-protection " - "will be defined the option (Read-protect by default).", - action="store_true", - ) +class ESP32C6Commands(BaseCommands): + CHIP_NAME = "ESP32-C6" + efuse_lib = fields.EspEfuses + ################################### CLI definitions ################################### -def add_commands(subparsers, efuses): - add_common_commands(subparsers, efuses) - burn_key = subparsers.add_parser( - "burn_key", help="Burn the key block with the specified name" - ) - protect_options(burn_key) - add_force_write_always(burn_key) - add_show_sensitive_info_option(burn_key) - burn_key.add_argument( - "block", - help="Key block to burn", - action="append", - choices=efuses.BLOCKS_FOR_KEYS, - ) - burn_key.add_argument( - "keyfile", - help="File containing 256 bits of binary key data", - action="append", - type=argparse.FileType("rb"), - ) - burn_key.add_argument( - "keypurpose", - help="Purpose to set.", - action="append", - choices=fields.EfuseKeyPurposeField.KEY_PURPOSES_NAME, - ) - for _ in efuses.BLOCKS_FOR_KEYS: - burn_key.add_argument( - "block", - help="Key block to burn", - nargs="?", - action="append", - metavar="BLOCK", - choices=efuses.BLOCKS_FOR_KEYS, - ) - burn_key.add_argument( - "keyfile", - help="File containing 256 bits of binary key data", - nargs="?", - action="append", - metavar="KEYFILE", - type=argparse.FileType("rb"), - ) - burn_key.add_argument( - "keypurpose", - help="Purpose to set.", - nargs="?", - action="append", - metavar="KEYPURPOSE", - choices=fields.EfuseKeyPurposeField.KEY_PURPOSES_NAME, - ) + def add_cli_commands(self, cli: click.Group): + super().add_cli_commands(cli) + blocks_for_keys = EfuseDefineBlocks().get_blocks_for_keys() - burn_key_digest = subparsers.add_parser( - "burn_key_digest", - help="Parse a RSA public key and burn the digest to key efuse block", - ) - protect_options(burn_key_digest) - add_force_write_always(burn_key_digest) - add_show_sensitive_info_option(burn_key_digest) - burn_key_digest.add_argument( - "block", - help="Key block to burn", - action="append", - choices=efuses.BLOCKS_FOR_KEYS, - ) - burn_key_digest.add_argument( - "keyfile", - help="Key file to digest (PEM format)", - action="append", - type=argparse.FileType("rb"), - ) - burn_key_digest.add_argument( - "keypurpose", - help="Purpose to set.", - action="append", - choices=fields.EfuseKeyPurposeField.DIGEST_KEY_PURPOSES, - ) - for _ in efuses.BLOCKS_FOR_KEYS: - burn_key_digest.add_argument( - "block", - help="Key block to burn", - nargs="?", - action="append", - metavar="BLOCK", - choices=efuses.BLOCKS_FOR_KEYS, + @cli.command( + "burn-key", + help="Burn the key block with the specified name. Arguments are groups of block name, " + "key file (containing 256 bits of binary key data) and key purpose.\n\n" + f"Block is one of: [{', '.join(blocks_for_keys)}]\n\n" + f"Key purpose is one of: [{', '.join(fields.EfuseKeyPurposeField.KEY_PURPOSES_NAME)}]", ) - burn_key_digest.add_argument( - "keyfile", - help="Key file to digest (PEM format)", - nargs="?", - action="append", - metavar="KEYFILE", - type=argparse.FileType("rb"), + @click.argument( + "block_keyfile_keypurpose", + metavar=" ", + cls=TupleParameter, + required=True, + nargs=-1, + max_arity=len(blocks_for_keys), + type=NonCompositeTuple( + [ + click.Choice(blocks_for_keys), + click.File("rb"), + click.Choice(fields.EfuseKeyPurposeField.KEY_PURPOSES_NAME), + ] + ), ) - burn_key_digest.add_argument( - "keypurpose", - help="Purpose to set.", - nargs="?", - action="append", - metavar="KEYPURPOSE", - choices=fields.EfuseKeyPurposeField.DIGEST_KEY_PURPOSES, + @protect_options + @add_force_write_always + @add_show_sensitive_info_option + @click.pass_context + def burn_key_cli(ctx, **kwargs): + kwargs.pop("force_write_always") + block, keyfile, keypurpose = zip(*kwargs.pop("block_keyfile_keypurpose")) + kwargs["show_sensitive_info"] = ctx.show_sensitive_info + self.burn_key(block, keyfile, keypurpose, **kwargs) + + @cli.command( + "burn-key-digest", + short_help="Parse a RSA public key and burn the digest.", + help="Parse a RSA public key and burn the digest to key eFuse block.\n\n" + f"Block is one of: [{', '.join(blocks_for_keys)}]\n\n" + f"Key purpose is one of: [{', '.join(fields.EfuseKeyPurposeField.DIGEST_KEY_PURPOSES)}]", ) - - p = subparsers.add_parser( - "set_flash_voltage", - help="Permanently set the internal flash voltage regulator " - "to either 1.8V, 3.3V or OFF. " - "This means GPIO45 can be high or low at reset without " - "changing the flash voltage.", - ) - p.add_argument("voltage", help="Voltage selection", choices=["1.8V", "3.3V", "OFF"]) - - p = subparsers.add_parser( - "burn_custom_mac", help="Burn a 48-bit Custom MAC Address to EFUSE BLOCK3." - ) - p.add_argument( - "mac", - help="Custom MAC Address to burn given in hexadecimal format with bytes " - "separated by colons (e.g. AA:CD:EF:01:02:03).", - type=fields.base_fields.CheckArgValue(efuses, "CUSTOM_MAC"), - ) - add_force_write_always(p) - - p = subparsers.add_parser("get_custom_mac", help="Prints the Custom MAC Address.") - - -def burn_custom_mac(esp, efuses, args): - efuses["CUSTOM_MAC"].save(args.mac) - if not efuses.burn_all(check_batch_mode=True): - return - get_custom_mac(esp, efuses, args) - print("Successful") - - -def get_custom_mac(esp, efuses, args): - print("Custom MAC Address: {}".format(efuses["CUSTOM_MAC"].get())) - - -def set_flash_voltage(esp, efuses, args): - raise esptool.FatalError("set_flash_voltage is not supported!") - - -def adc_info(esp, efuses, args): - print("") - # fmt: off - if efuses["BLK_VERSION_MINOR"].get() == 1: - print("Temperature Sensor Calibration = {}C".format(efuses["TEMP_CALIB"].get())) - print("ADC OCode = ", efuses["OCODE"].get()) - print("ADC1:") - print("INIT_CODE_ATTEN0 = ", efuses['ADC1_INIT_CODE_ATTEN0'].get()) - print("INIT_CODE_ATTEN1 = ", efuses['ADC1_INIT_CODE_ATTEN1'].get()) - print("INIT_CODE_ATTEN2 = ", efuses['ADC1_INIT_CODE_ATTEN2'].get()) - print("INIT_CODE_ATTEN3 = ", efuses['ADC1_INIT_CODE_ATTEN3'].get()) - print("CAL_VOL_ATTEN0 = ", efuses['ADC1_CAL_VOL_ATTEN0'].get()) - print("CAL_VOL_ATTEN1 = ", efuses['ADC1_CAL_VOL_ATTEN1'].get()) - print("CAL_VOL_ATTEN2 = ", efuses['ADC1_CAL_VOL_ATTEN2'].get()) - print("CAL_VOL_ATTEN3 = ", efuses['ADC1_CAL_VOL_ATTEN3'].get()) - print("INIT_CODE_ATTEN0_CH0 = ", efuses['ADC1_INIT_CODE_ATTEN0_CH0'].get()) - print("INIT_CODE_ATTEN0_CH1 = ", efuses['ADC1_INIT_CODE_ATTEN0_CH1'].get()) - print("INIT_CODE_ATTEN0_CH2 = ", efuses['ADC1_INIT_CODE_ATTEN0_CH2'].get()) - print("INIT_CODE_ATTEN0_CH3 = ", efuses['ADC1_INIT_CODE_ATTEN0_CH3'].get()) - print("INIT_CODE_ATTEN0_CH4 = ", efuses['ADC1_INIT_CODE_ATTEN0_CH4'].get()) - print("INIT_CODE_ATTEN0_CH5 = ", efuses['ADC1_INIT_CODE_ATTEN0_CH5'].get()) - print("INIT_CODE_ATTEN0_CH6 = ", efuses['ADC1_INIT_CODE_ATTEN0_CH6'].get()) - else: - print("BLK_VERSION_MINOR = {}".format(efuses["BLK_VERSION_MINOR"].get_meaning())) - # fmt: on - - -def burn_key(esp, efuses, args, digest=None): - if digest is None: - datafile_list = args.keyfile[ - 0 : len([name for name in args.keyfile if name is not None]) : - ] - else: - datafile_list = digest[0 : len([name for name in digest if name is not None]) :] - efuses.force_write_always = args.force_write_always - block_name_list = args.block[ - 0 : len([name for name in args.block if name is not None]) : - ] - keypurpose_list = args.keypurpose[ - 0 : len([name for name in args.keypurpose if name is not None]) : - ] - - util.check_duplicate_name_in_list(block_name_list) - if len(block_name_list) != len(datafile_list) or len(block_name_list) != len( - keypurpose_list - ): - raise esptool.FatalError( - "The number of blocks (%d), datafile (%d) and keypurpose (%d) " - "should be the same." - % (len(block_name_list), len(datafile_list), len(keypurpose_list)) + @click.argument( + "block_keyfile_keypurpose", + metavar=" ", + cls=TupleParameter, + required=True, + nargs=-1, + max_arity=len(blocks_for_keys), + type=NonCompositeTuple( + [ + click.Choice(blocks_for_keys), + click.File("rb"), + click.Choice(fields.EfuseKeyPurposeField.DIGEST_KEY_PURPOSES), + ] + ), ) - - print("Burn keys to blocks:") - for block_name, datafile, keypurpose in zip( - block_name_list, datafile_list, keypurpose_list + @protect_options + @add_force_write_always + @add_show_sensitive_info_option + @click.pass_context + def burn_key_digest_cli(ctx, **kwargs): + kwargs.pop("force_write_always") + block, keyfile, keypurpose = zip(*kwargs.pop("block_keyfile_keypurpose")) + kwargs["show_sensitive_info"] = ctx.show_sensitive_info + self.burn_key_digest(block, keyfile, keypurpose, **kwargs) + + ###################################### Commands ###################################### + + def adc_info(self): + log.print("Block version:", self.efuses.get_block_version()) + if self.efuses.get_block_version() >= 1: + # fmt: off + log.print(f"Temperature Sensor Calibration = {self.efuses['TEMP_CALIB'].get()}C") + log.print("ADC OCode = ", self.efuses["OCODE"].get()) + log.print("ADC1:") + log.print("INIT_CODE_ATTEN0 = ", self.efuses['ADC1_INIT_CODE_ATTEN0'].get()) + log.print("INIT_CODE_ATTEN1 = ", self.efuses['ADC1_INIT_CODE_ATTEN1'].get()) + log.print("INIT_CODE_ATTEN2 = ", self.efuses['ADC1_INIT_CODE_ATTEN2'].get()) + log.print("INIT_CODE_ATTEN3 = ", self.efuses['ADC1_INIT_CODE_ATTEN3'].get()) + log.print("CAL_VOL_ATTEN0 = ", self.efuses['ADC1_CAL_VOL_ATTEN0'].get()) + log.print("CAL_VOL_ATTEN1 = ", self.efuses['ADC1_CAL_VOL_ATTEN1'].get()) + log.print("CAL_VOL_ATTEN2 = ", self.efuses['ADC1_CAL_VOL_ATTEN2'].get()) + log.print("CAL_VOL_ATTEN3 = ", self.efuses['ADC1_CAL_VOL_ATTEN3'].get()) + log.print("INIT_CODE_ATTEN0_CH0 = ", self.efuses['ADC1_INIT_CODE_ATTEN0_CH0'].get()) + log.print("INIT_CODE_ATTEN0_CH1 = ", self.efuses['ADC1_INIT_CODE_ATTEN0_CH1'].get()) + log.print("INIT_CODE_ATTEN0_CH2 = ", self.efuses['ADC1_INIT_CODE_ATTEN0_CH2'].get()) + log.print("INIT_CODE_ATTEN0_CH3 = ", self.efuses['ADC1_INIT_CODE_ATTEN0_CH3'].get()) + log.print("INIT_CODE_ATTEN0_CH4 = ", self.efuses['ADC1_INIT_CODE_ATTEN0_CH4'].get()) + log.print("INIT_CODE_ATTEN0_CH5 = ", self.efuses['ADC1_INIT_CODE_ATTEN0_CH5'].get()) + log.print("INIT_CODE_ATTEN0_CH6 = ", self.efuses['ADC1_INIT_CODE_ATTEN0_CH6'].get()) + # fmt: on + + def burn_key( + self, + blocks: list[str], + keyfiles: list[BinaryIO], + keypurposes: list[str], + no_write_protect: bool = False, + no_read_protect: bool = False, + show_sensitive_info: bool = False, + digest: list[bytes] | None = None, ): - efuse = None - for block in efuses.blocks: - if block_name == block.name or block_name in block.alias: - efuse = efuses[block.name] - if efuse is None: - raise esptool.FatalError("Unknown block name - %s" % (block_name)) - num_bytes = efuse.bit_len // 8 - - block_num = efuses.get_index_block_by_name(block_name) - block = efuses.blocks[block_num] - + """Burn the key block with the specified name. Arguments are groups of block name, + key file (containing 256 bits of binary key data) and key purpose. + + Args: + blocks: List of eFuse block names to burn keys to. + keyfiles: List of open files to read key data from. + keypurposes: List of key purposes to burn. + no_write_protect: If True, the write protection will NOT be enabled. + no_read_protect: If True, the read protection will NOT be enabled. + show_sensitive_info: If True, the sensitive information will be shown. + digest: List of digests to burn. + """ + datafile_list: list[BinaryIO] | list[bytes] if digest is None: - data = datafile.read() + datafile_list = keyfiles[ + 0 : len([name for name in keyfiles if name is not None]) : + ] else: - data = datafile + datafile_list = digest[ + 0 : len([name for name in digest if name is not None]) : + ] + block_name_list = blocks[ + 0 : len([name for name in blocks if name is not None]) : + ] + keypurpose_list = keypurposes[ + 0 : len([name for name in keypurposes if name is not None]) : + ] - print(" - %s" % (efuse.name), end=" ") - revers_msg = None - if efuses[block.key_purpose_name].need_reverse(keypurpose): - revers_msg = "\tReversing byte order for AES-XTS hardware peripheral" - data = data[::-1] - print( - "-> [{}]".format( - util.hexify(data, " ") - if args.show_sensitive_info - else " ".join(["??"] * len(data)) - ) - ) - if revers_msg: - print(revers_msg) - if len(data) != num_bytes: + util.check_duplicate_name_in_list(block_name_list) + if len(block_name_list) != len(datafile_list) or len(block_name_list) != len( + keypurpose_list + ): raise esptool.FatalError( - "Incorrect key file size %d. Key file must be %d bytes (%d bits) " - "of raw binary key data." % (len(data), num_bytes, num_bytes * 8) + "The number of blocks (%d), datafile (%d) and keypurpose (%d) should be the same." + % (len(block_name_list), len(datafile_list), len(keypurpose_list)) ) - if efuses[block.key_purpose_name].need_rd_protect(keypurpose): - read_protect = False if args.no_read_protect else True - else: - read_protect = False - write_protect = not args.no_write_protect - - # using efuse instead of a block gives the advantage of checking it as the whole field. - efuse.save(data) + log.print("Burn keys to blocks:") + for block_name, datafile, keypurpose in zip( + block_name_list, datafile_list, keypurpose_list + ): + efuse = None + for block in self.efuses.blocks: + if block_name == block.name or block_name in block.alias: + efuse = self.efuses[block.name] + if efuse is None: + raise esptool.FatalError(f"Unknown block name - {block_name}.") + num_bytes = efuse.bit_len // 8 + + block_num = self.efuses.get_index_block_by_name(block_name) + block = self.efuses.blocks[block_num] + + if isinstance(datafile, IOBase): + data = datafile.read() + datafile.close() + else: + data = datafile # type: ignore # this is safe but mypy still complains + + log.print(f" - {efuse.name}", end=" ") + revers_msg = None + if self.efuses[block.key_purpose_name].need_reverse(keypurpose): + revers_msg = "\tReversing byte order for AES-XTS hardware peripheral..." + data = data[::-1] + log.print( + "-> [{}]".format( + util.hexify(data, " ") + if show_sensitive_info + else " ".join(["??"] * len(data)) + ) + ) + if revers_msg: + log.print(revers_msg) + if len(data) != num_bytes: + raise esptool.FatalError( + f"Incorrect key file size {len(data)}. Key file must be {num_bytes} " + f"bytes ({num_bytes * 8} bits) of raw binary key data." + ) - disable_wr_protect_key_purpose = False - if efuses[block.key_purpose_name].get() != keypurpose: - if efuses[block.key_purpose_name].is_writeable(): - print( - "\t'%s': '%s' -> '%s'." - % ( - block.key_purpose_name, - efuses[block.key_purpose_name].get(), - keypurpose, + if self.efuses[block.key_purpose_name].need_rd_protect(keypurpose): + read_protect = False if no_read_protect else True + else: + read_protect = False + write_protect = not no_write_protect + + # using eFuse instead of a block gives the advantage of checking it as the whole field. + efuse.save(data) + + disable_wr_protect_key_purpose = False + if self.efuses[block.key_purpose_name].get() != keypurpose: + if self.efuses[block.key_purpose_name].is_writeable(): + log.print( + f"\t'{block.key_purpose_name}': " + f"'{self.efuses[block.key_purpose_name].get()}' -> '{keypurpose}'." + ) + self.efuses[block.key_purpose_name].save(keypurpose) + disable_wr_protect_key_purpose = True + else: + raise esptool.FatalError( + f"It is not possible to change '{block.key_purpose_name}' " + f"to '{keypurpose}' because write protection bit is set." ) - ) - efuses[block.key_purpose_name].save(keypurpose) - disable_wr_protect_key_purpose = True else: + log.print(f"\t'{block.key_purpose_name}' is already '{keypurpose}'.") + if self.efuses[block.key_purpose_name].is_writeable(): + disable_wr_protect_key_purpose = True + + if disable_wr_protect_key_purpose: + log.print(f"\tDisabling write to '{block.key_purpose_name}'...") + self.efuses[block.key_purpose_name].disable_write() + + if read_protect: + log.print("\tDisabling read to key block...") + efuse.disable_read() + + if write_protect: + log.print("\tDisabling write to key block...") + efuse.disable_write() + log.print("") + + if not write_protect: + log.print("Keys will remain writeable (due to --no-write-protect).") + if no_read_protect: + log.print("Keys will remain readable (due to --no-read-protect).") + + if not self.efuses.burn_all(check_batch_mode=True): + return + log.print("Successful.") + + def burn_key_digest( + self, + blocks: list[str], + keyfiles: list[BinaryIO], + keypurposes: list[str], + no_write_protect: bool = False, + no_read_protect: bool = False, + show_sensitive_info: bool = False, + ): + """Parse a RSA public key and burn the digest to key eFuse block. + + Args: + blocks: List of eFuse block names to burn keys to. + keyfiles: List of open files to read key data from. + keypurposes: List of key purposes to burn. + no_write_protect: If True, the write protection will NOT be enabled. + no_read_protect: If True, the read protection will NOT be enabled. + show_sensitive_info: If True, the sensitive information will be shown. + """ + digest_list = [] + datafile_list = keyfiles[ + 0 : len([name for name in keyfiles if name is not None]) : + ] + block_list = blocks[0 : len([block for block in blocks if block is not None]) :] + + for block_name, datafile in zip(block_list, datafile_list): + efuse = None + for block in self.efuses.blocks: + if block_name == block.name or block_name in block.alias: + efuse = self.efuses[block.name] + if efuse is None: + raise esptool.FatalError(f"Unknown block name - {block_name}") + num_bytes = efuse.bit_len // 8 + digest = espsecure._digest_sbv2_public_key(datafile) + if len(digest) != num_bytes: raise esptool.FatalError( - "It is not possible to change '%s' to '%s' " - "because write protection bit is set." - % (block.key_purpose_name, keypurpose) + f"Incorrect digest size {len(digest)}. Digest must be {num_bytes} " + f"bytes ({num_bytes * 8} bits) of raw binary key data." ) - else: - print("\t'%s' is already '%s'." % (block.key_purpose_name, keypurpose)) - if efuses[block.key_purpose_name].is_writeable(): - disable_wr_protect_key_purpose = True - - if disable_wr_protect_key_purpose: - print("\tDisabling write to '%s'." % block.key_purpose_name) - efuses[block.key_purpose_name].disable_write() - - if read_protect: - print("\tDisabling read to key block") - efuse.disable_read() - - if write_protect: - print("\tDisabling write to key block") - efuse.disable_write() - print("") - - if not write_protect: - print("Keys will remain writeable (due to --no-write-protect)") - if args.no_read_protect: - print("Keys will remain readable (due to --no-read-protect)") - - if not efuses.burn_all(check_batch_mode=True): - return - print("Successful") - - -def burn_key_digest(esp, efuses, args): - digest_list = [] - datafile_list = args.keyfile[ - 0 : len([name for name in args.keyfile if name is not None]) : - ] - block_list = args.block[ - 0 : len([block for block in args.block if block is not None]) : - ] - for block_name, datafile in zip(block_list, datafile_list): - efuse = None - for block in efuses.blocks: - if block_name == block.name or block_name in block.alias: - efuse = efuses[block.name] - if efuse is None: - raise esptool.FatalError("Unknown block name - %s" % (block_name)) - num_bytes = efuse.bit_len // 8 - digest = espsecure._digest_sbv2_public_key(datafile) - if len(digest) != num_bytes: - raise esptool.FatalError( - "Incorrect digest size %d. Digest must be %d bytes (%d bits) " - "of raw binary key data." % (len(digest), num_bytes, num_bytes * 8) - ) - digest_list.append(digest) - burn_key(esp, efuses, args, digest=digest_list) - - -def espefuse(esp, efuses, args, command): - parser = argparse.ArgumentParser() - subparsers = parser.add_subparsers(dest="operation") - add_commands(subparsers, efuses) - try: - cmd_line_args = parser.parse_args(command.split()) - except SystemExit: - traceback.print_stack() - raise esptool.FatalError('"{}" - incorrect command'.format(command)) - if cmd_line_args.operation == "execute_scripts": - configfiles = cmd_line_args.configfiles - index = cmd_line_args.index - # copy arguments from args to cmd_line_args - vars(cmd_line_args).update(vars(args)) - if cmd_line_args.operation == "execute_scripts": - cmd_line_args.configfiles = configfiles - cmd_line_args.index = index - if cmd_line_args.operation is None: - parser.print_help() - parser.exit(1) - operation_func = globals()[cmd_line_args.operation] - # each 'operation' is a module-level function of the same name - operation_func(esp, efuses, cmd_line_args) - - -def execute_scripts(esp, efuses, args): - efuses.batch_mode_cnt += 1 - del args.operation - scripts = args.scripts - del args.scripts - - for file in scripts: - with open(file.name, "r") as file: - exec(compile(file.read(), file.name, "exec")) - - if args.debug: - for block in efuses.blocks: - data = block.get_bitstring(from_read=False) - block.print_block(data, "regs_for_burn", args.debug) - - efuses.batch_mode_cnt -= 1 - if not efuses.burn_all(check_batch_mode=True): - return - print("Successful") + digest_list.append(digest) + + self.burn_key( + block_list, + datafile_list, + keypurposes, + no_write_protect, + no_read_protect, + show_sensitive_info, + digest=digest_list, + ) diff --git a/tools/esptool_py/espefuse/efuse/esp32c61/__init__.py b/tools/esptool_py/espefuse/efuse/esp32c61/__init__.py index a3b55a8023..568e228569 100644 --- a/tools/esptool_py/espefuse/efuse/esp32c61/__init__.py +++ b/tools/esptool_py/espefuse/efuse/esp32c61/__init__.py @@ -1,3 +1,5 @@ from . import operations from .emulate_efuse_controller import EmulateEfuseController from .fields import EspEfuses + +commands = operations.ESP32C61Commands diff --git a/tools/esptool_py/espefuse/efuse/esp32c61/fields.py b/tools/esptool_py/espefuse/efuse/esp32c61/fields.py index 5f6fe7b8cb..4c129b92b0 100644 --- a/tools/esptool_py/espefuse/efuse/esp32c61/fields.py +++ b/tools/esptool_py/espefuse/efuse/esp32c61/fields.py @@ -10,6 +10,7 @@ import time from bitstring import BitArray +from esptool.logger import log import esptool @@ -55,9 +56,6 @@ class EspEfuses(base_fields.EspEfusesBase): Wrapper object to manage the efuse fields in a connected ESP bootloader """ - debug = False - do_not_confirm = False - def __init__( self, esp, @@ -66,14 +64,12 @@ def __init__( do_not_confirm=False, extend_efuse_table=None, ): + super().__init__(esp, skip_connect, debug, do_not_confirm, extend_efuse_table) self.Blocks = EfuseDefineBlocks() self.Fields = EfuseDefineFields(extend_efuse_table) self.REGS = EfuseDefineRegisters self.BURN_BLOCK_DATA_NAMES = self.Blocks.get_burn_block_data_names() self.BLOCKS_FOR_KEYS = self.Blocks.get_blocks_for_keys() - self._esp = esp - self.debug = debug - self.do_not_confirm = do_not_confirm if esp.CHIP_NAME != "ESP32-C61": raise esptool.FatalError( "Expected the 'esp' param for ESP32-C61 chip but got for '%s'." @@ -102,11 +98,11 @@ def __init__( for efuse in self.Fields.BLOCK2_CALIBRATION_EFUSES ] else: - # if self["BLK_VERSION_MINOR"].get() == 1: - # self.efuses += [ - # EfuseField.convert(self, efuse) - # for efuse in self.Fields.BLOCK2_CALIBRATION_EFUSES - # ] + if self.get_block_version() >= 1: + self.efuses += [ + EfuseField.convert(self, efuse) + for efuse in self.Fields.BLOCK2_CALIBRATION_EFUSES + ] self.efuses += [ EfuseField.convert(self, efuse) for efuse in self.Fields.CALC ] @@ -136,14 +132,14 @@ def read_coding_scheme(self): self.coding_scheme = self.REGS.CODING_SCHEME_RS def print_status_regs(self): - print("") + log.print("") self.blocks[0].print_block(self.blocks[0].err_bitarray, "err__regs", debug=True) - print( + log.print( "{:27} 0x{:08x}".format( "EFUSE_RD_RS_ERR0_REG", self.read_reg(self.REGS.EFUSE_RD_RS_ERR0_REG) ) ) - print( + log.print( "{:27} 0x{:08x}".format( "EFUSE_RD_RS_ERR1_REG", self.read_reg(self.REGS.EFUSE_RD_RS_ERR1_REG) ) @@ -176,7 +172,7 @@ def wait_efuse_idle(self): # For PGM_CMD it is not necessary. return raise esptool.FatalError( - "Timed out waiting for Efuse controller command to complete" + "Timed out waiting for eFuse controller command to complete" ) def efuse_program(self, block): @@ -204,30 +200,30 @@ def efuse_read(self): try: self._esp = self.reconnect_chip(self._esp) except esptool.FatalError: - print("Can not re-connect to the chip") + log.print("Can not re-connect to the chip.") if not self["DIS_DOWNLOAD_MODE"].get() and self[ "DIS_DOWNLOAD_MODE" ].get(from_read=False): - print( + log.print( "This is the correct behavior as we are actually burning " - "DIS_DOWNLOAD_MODE which disables the connection to the chip" + "DIS_DOWNLOAD_MODE which disables the connection to the chip." ) - print("DIS_DOWNLOAD_MODE is enabled") - print("Successful") + log.print("DIS_DOWNLOAD_MODE is enabled.") + log.print("Successful.") sys.exit(0) # finish without errors raise - print("Established a connection with the chip") + log.print("Established a connection with the chip.") if self._esp.secure_download_mode and not secure_download_mode_before: - print("Secure download mode is enabled") + log.print("Secure download mode is enabled.") if not self["ENABLE_SECURITY_DOWNLOAD"].get() and self[ "ENABLE_SECURITY_DOWNLOAD" ].get(from_read=False): - print( - "espefuse tool can not continue to work in Secure download mode" + log.print( + "espefuse can not continue to work in Secure download mode." ) - print("ENABLE_SECURITY_DOWNLOAD is enabled") - print("Successful") + log.print("ENABLE_SECURITY_DOWNLOAD is enabled.") + log.print("Successful.") sys.exit(0) # finish without errors raise @@ -237,7 +233,7 @@ def set_efuse_timing(self): apb_freq = self.get_crystal_freq() if apb_freq != 40: raise esptool.FatalError( - "The eFuse supports only xtal=40M (xtal was %d)" % apb_freq + f"The eFuse supports only xtal=40M (xtal was {apb_freq})." ) self.update_reg(self.REGS.EFUSE_DAC_CONF_REG, self.REGS.EFUSE_DAC_NUM_M, 0xFF) @@ -264,7 +260,7 @@ def get_coding_scheme_warnings(self, silent=False): ] block.err_bitarray.pos = 0 for word in reversed(words): - block.err_bitarray.overwrite(BitArray("uint:32=%d" % word)) + block.err_bitarray.overwrite(BitArray(f"uint:32={word}")) block.num_errors = block.err_bitarray.count(True) block.fail = block.num_errors != 0 else: @@ -280,9 +276,9 @@ def get_coding_scheme_warnings(self, silent=False): block.num_errors = (reg_value >> err_num_offs) & err_num_mask ret_fail |= block.fail if not silent and (block.fail or block.num_errors): - print( - "Error(s) in BLOCK%d [ERRORS:%d FAIL:%d]" - % (block.id, block.num_errors, block.fail) + log.print( + f"Error(s) in BLOCK{block.id} " + f"[ERRORS:{block.num_errors} FAIL:{block.fail}]." ) if (self.debug or ret_fail) and not silent: self.print_status_regs() @@ -385,10 +381,8 @@ def get(self, from_read=True): def save(self, new_value): def print_field(e, new_value): - print( - " - '{}' ({}) {} -> {}".format( - e.name, e.description, e.get_bitstring(), new_value - ) + log.print( + f" - '{e.name}' ({e.description}) {e.get_bitstring()} -> {new_value}" ) if self.name == "CUSTOM_MAC": @@ -432,9 +426,9 @@ def check_format(self, new_value_str): break if raw_val.isdigit(): if int(raw_val) not in [p[1] for p in self.KEY_PURPOSES if p[1] > 0]: - raise esptool.FatalError("'%s' can not be set (value out of range)" % raw_val) + raise esptool.FatalError(f"'{raw_val}' can not be set (value out of range)") else: - raise esptool.FatalError("'%s' unknown name" % raw_val) + raise esptool.FatalError(f"'{raw_val}' unknown name") return raw_val def need_reverse(self, new_key_purpose): diff --git a/tools/esptool_py/espefuse/efuse/esp32c61/mem_definition.py b/tools/esptool_py/espefuse/efuse/esp32c61/mem_definition.py index 2f8f818a53..39050f66d7 100644 --- a/tools/esptool_py/espefuse/efuse/esp32c61/mem_definition.py +++ b/tools/esptool_py/espefuse/efuse/esp32c61/mem_definition.py @@ -5,7 +5,6 @@ # SPDX-License-Identifier: GPL-2.0-or-later import os -from typing import List import yaml @@ -114,13 +113,9 @@ class EfuseDefineFields(EfuseFieldsBase): def __init__(self, extend_efuse_table) -> None: # List of efuse fields from TRM the chapter eFuse Controller. self.EFUSES = [] - self.KEYBLOCKS = [] - - # if BLK_VERSION_MINOR is 1, these efuse fields are in BLOCK2 self.BLOCK2_CALIBRATION_EFUSES = [] - - self.CALC: List = [] + self.CALC: list = [] dir_name = os.path.dirname(os.path.abspath(__file__)) dir_name, file_name = os.path.split(dir_name) diff --git a/tools/esptool_py/espefuse/efuse/esp32c61/operations.py b/tools/esptool_py/espefuse/efuse/esp32c61/operations.py index 2306565554..066b9626ab 100644 --- a/tools/esptool_py/espefuse/efuse/esp32c61/operations.py +++ b/tools/esptool_py/espefuse/efuse/esp32c61/operations.py @@ -1,462 +1,316 @@ # This file includes the operations with eFuses for ESP32-C61 chip # -# SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD +# SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD # # SPDX-License-Identifier: GPL-2.0-or-later -import argparse import io -import os # noqa: F401. It is used in IDF scripts -import traceback +from typing import BinaryIO +from esptool.logger import log +import rich_click as click import espsecure - import esptool from . import fields +from .mem_definition import EfuseDefineBlocks from .. import util from ..base_operations import ( - add_common_commands, + BaseCommands, + NonCompositeTuple, + TupleParameter, add_force_write_always, add_show_sensitive_info_option, - burn_bit, - burn_block_data, - burn_efuse, - check_error, - dump, - read_protect_efuse, - summary, - write_protect_efuse, + protect_options, ) -def protect_options(p): - p.add_argument( - "--no-write-protect", - help="Disable write-protecting of the key. The key remains writable. " - "(The keys use the RS coding scheme that does not support " - "post-write data changes. Forced write can damage RS encoding bits.) " - "The write-protecting of keypurposes does not depend on the option, " - "it will be set anyway.", - action="store_true", - ) - p.add_argument( - "--no-read-protect", - help="Disable read-protecting of the key. The key remains readable software." - "The key with keypurpose[USER, RESERVED and *_DIGEST] " - "will remain readable anyway. For the rest keypurposes the read-protection " - "will be defined the option (Read-protect by default).", - action="store_true", - ) +class ESP32C61Commands(BaseCommands): + CHIP_NAME = "ESP32-C61" + efuse_lib = fields.EspEfuses + ################################### CLI definitions ################################### -def add_commands(subparsers, efuses): - add_common_commands(subparsers, efuses) - burn_key = subparsers.add_parser( - "burn_key", help="Burn the key block with the specified name" - ) - protect_options(burn_key) - add_force_write_always(burn_key) - add_show_sensitive_info_option(burn_key) - burn_key.add_argument( - "block", - help="Key block to burn", - action="append", - choices=efuses.BLOCKS_FOR_KEYS, - ) - burn_key.add_argument( - "keyfile", - help="File containing 256 bits of binary key data. For the ECDSA_KEY purpose use PEM file.", - action="append", - type=argparse.FileType("rb"), - ) - burn_key.add_argument( - "keypurpose", - help="Purpose to set.", - action="append", - choices=fields.EfuseKeyPurposeField.KEY_PURPOSES_NAME, - ) - for _ in efuses.BLOCKS_FOR_KEYS: - burn_key.add_argument( - "block", - help="Key block to burn", - nargs="?", - action="append", - metavar="BLOCK", - choices=efuses.BLOCKS_FOR_KEYS, - ) - burn_key.add_argument( - "keyfile", - help="File containing 256 bits of binary key data. For the ECDSA_KEY purpose use PEM file.", - nargs="?", - action="append", - metavar="KEYFILE", - type=argparse.FileType("rb"), - ) - burn_key.add_argument( - "keypurpose", - help="Purpose to set.", - nargs="?", - action="append", - metavar="KEYPURPOSE", - choices=fields.EfuseKeyPurposeField.KEY_PURPOSES_NAME, - ) + def add_cli_commands(self, cli: click.Group): + super().add_cli_commands(cli) + blocks_for_keys = EfuseDefineBlocks().get_blocks_for_keys() - burn_key_digest = subparsers.add_parser( - "burn_key_digest", - help="Parse a RSA public key and burn the digest to key efuse block", - ) - protect_options(burn_key_digest) - add_force_write_always(burn_key_digest) - add_show_sensitive_info_option(burn_key_digest) - burn_key_digest.add_argument( - "block", - help="Key block to burn", - action="append", - choices=efuses.BLOCKS_FOR_KEYS, - ) - burn_key_digest.add_argument( - "keyfile", - help="Key file to digest (PEM format)", - action="append", - type=argparse.FileType("rb"), - ) - burn_key_digest.add_argument( - "keypurpose", - help="Purpose to set.", - action="append", - choices=fields.EfuseKeyPurposeField.DIGEST_KEY_PURPOSES, - ) - for _ in efuses.BLOCKS_FOR_KEYS: - burn_key_digest.add_argument( - "block", - help="Key block to burn", - nargs="?", - action="append", - metavar="BLOCK", - choices=efuses.BLOCKS_FOR_KEYS, + @cli.command( + "burn-key", + help="Burn the key block with the specified name. Arguments are groups of block name, " + "key file (containing 256 bits of binary key data) and key purpose.\n\n" + f"Block is one of: [{', '.join(blocks_for_keys)}]\n\n" + f"Key purpose is one of: [{', '.join(fields.EfuseKeyPurposeField.KEY_PURPOSES_NAME)}]", ) - burn_key_digest.add_argument( - "keyfile", - help="Key file to digest (PEM format)", - nargs="?", - action="append", - metavar="KEYFILE", - type=argparse.FileType("rb"), + @click.argument( + "block_keyfile_keypurpose", + metavar=" ", + cls=TupleParameter, + required=True, + nargs=-1, + max_arity=len(blocks_for_keys), + type=NonCompositeTuple( + [ + click.Choice(blocks_for_keys), + click.File("rb"), + click.Choice(fields.EfuseKeyPurposeField.KEY_PURPOSES_NAME), + ] + ), ) - burn_key_digest.add_argument( - "keypurpose", - help="Purpose to set.", - nargs="?", - action="append", - metavar="KEYPURPOSE", - choices=fields.EfuseKeyPurposeField.DIGEST_KEY_PURPOSES, + @protect_options + @add_force_write_always + @add_show_sensitive_info_option + @click.pass_context + def burn_key_cli(ctx, **kwargs): + kwargs.pop("force_write_always") + block, keyfile, keypurpose = zip(*kwargs.pop("block_keyfile_keypurpose")) + kwargs["show_sensitive_info"] = ctx.show_sensitive_info + self.burn_key(block, keyfile, keypurpose, **kwargs) + + @cli.command( + "burn-key-digest", + short_help="Parse a RSA public key and burn the digest.", + help="Parse a RSA public key and burn the digest to key eFuse block.\n\n" + f"Block is one of: [{', '.join(blocks_for_keys)}]\n\n" + f"Key purpose is one of: [{', '.join(fields.EfuseKeyPurposeField.DIGEST_KEY_PURPOSES)}]", ) - - p = subparsers.add_parser( - "set_flash_voltage", - help="Permanently set the internal flash voltage regulator " - "to either 1.8V, 3.3V or OFF. " - "This means GPIO45 can be high or low at reset without " - "changing the flash voltage.", - ) - p.add_argument("voltage", help="Voltage selection", choices=["1.8V", "3.3V", "OFF"]) - - p = subparsers.add_parser( - "burn_custom_mac", help="Burn a 48-bit Custom MAC Address to EFUSE BLOCK3." - ) - p.add_argument( - "mac", - help="Custom MAC Address to burn given in hexadecimal format with bytes " - "separated by colons (e.g. AA:CD:EF:01:02:03).", - type=fields.base_fields.CheckArgValue(efuses, "CUSTOM_MAC"), - ) - add_force_write_always(p) - - p = subparsers.add_parser("get_custom_mac", help="Prints the Custom MAC Address.") - - -def burn_custom_mac(esp, efuses, args): - efuses["CUSTOM_MAC"].save(args.mac) - if not efuses.burn_all(check_batch_mode=True): - return - get_custom_mac(esp, efuses, args) - print("Successful") - - -def get_custom_mac(esp, efuses, args): - print("Custom MAC Address: {}".format(efuses["CUSTOM_MAC"].get())) - - -def set_flash_voltage(esp, efuses, args): - raise esptool.FatalError("set_flash_voltage is not supported!") - - -def adc_info(esp, efuses, args): - print("not supported yet") - - -def key_block_is_unused(block, key_purpose_block): - if not block.is_readable() or not block.is_writeable(): - return False - - if key_purpose_block.get() != "USER" or not key_purpose_block.is_writeable(): - return False - - if not block.get_bitstring().all(False): - return False - - return True - - -def get_next_key_block(efuses, current_key_block, block_name_list): - key_blocks = [b for b in efuses.blocks if b.key_purpose_name] - start = key_blocks.index(current_key_block) - - # Sort key blocks so that we pick the next free block (and loop around if necessary) - key_blocks = key_blocks[start:] + key_blocks[0:start] - - # Exclude any other blocks that will be be burned - key_blocks = [b for b in key_blocks if b.name not in block_name_list] - - for block in key_blocks: - key_purpose_block = efuses[block.key_purpose_name] - if key_block_is_unused(block, key_purpose_block): - return block - - return None - - -def split_512_bit_key(efuses, block_name_list, datafile_list, keypurpose_list): - i = keypurpose_list.index("XTS_AES_256_KEY") - block_name = block_name_list[i] - - block_num = efuses.get_index_block_by_name(block_name) - block = efuses.blocks[block_num] - - data = datafile_list[i].read() - if len(data) != 64: - raise esptool.FatalError( - "Incorrect key file size %d, XTS_AES_256_KEY should be 64 bytes" % len(data) + @click.argument( + "block_keyfile_keypurpose", + metavar=" ", + cls=TupleParameter, + required=True, + nargs=-1, + max_arity=len(blocks_for_keys), + type=NonCompositeTuple( + [ + click.Choice(blocks_for_keys), + click.File("rb"), + click.Choice(fields.EfuseKeyPurposeField.DIGEST_KEY_PURPOSES), + ] + ), ) - - key_block_2 = get_next_key_block(efuses, block, block_name_list) - if not key_block_2: - raise esptool.FatalError("XTS_AES_256_KEY requires two free keyblocks") - - keypurpose_list.append("XTS_AES_256_KEY_1") - datafile_list.append(io.BytesIO(data[:32])) - block_name_list.append(block_name) - - keypurpose_list.append("XTS_AES_256_KEY_2") - datafile_list.append(io.BytesIO(data[32:])) - block_name_list.append(key_block_2.name) - - keypurpose_list.pop(i) - datafile_list.pop(i) - block_name_list.pop(i) - - -def burn_key(esp, efuses, args, digest=None): - if digest is None: - datafile_list = args.keyfile[ - 0 : len([name for name in args.keyfile if name is not None]) : - ] - else: - datafile_list = digest[0 : len([name for name in digest if name is not None]) :] - efuses.force_write_always = args.force_write_always - block_name_list = args.block[ - 0 : len([name for name in args.block if name is not None]) : - ] - keypurpose_list = args.keypurpose[ - 0 : len([name for name in args.keypurpose if name is not None]) : - ] - - if "XTS_AES_256_KEY" in keypurpose_list: - # XTS_AES_256_KEY is not an actual HW key purpose, needs to be split into - # XTS_AES_256_KEY_1 and XTS_AES_256_KEY_2 - split_512_bit_key(efuses, block_name_list, datafile_list, keypurpose_list) - - util.check_duplicate_name_in_list(block_name_list) - if len(block_name_list) != len(datafile_list) or len(block_name_list) != len( - keypurpose_list + @protect_options + @add_force_write_always + @add_show_sensitive_info_option + @click.pass_context + def burn_key_digest_cli(ctx, **kwargs): + kwargs.pop("force_write_always") + block, keyfile, keypurpose = zip(*kwargs.pop("block_keyfile_keypurpose")) + kwargs["show_sensitive_info"] = ctx.show_sensitive_info + self.burn_key_digest(block, keyfile, keypurpose, **kwargs) + + ###################################### Commands ###################################### + + def adc_info(self): + log.print("Block version:", self.efuses.get_block_version()) + if self.efuses.get_block_version() >= 1: + for efuse in self.efuses: + if efuse.category == "calibration": + log.print(f"{efuse.name:<30} = ", self.efuses[efuse.name].get()) + + def burn_key( + self, + blocks: list[str], + keyfiles: list[BinaryIO], + keypurposes: list[str], + no_write_protect: bool = False, + no_read_protect: bool = False, + show_sensitive_info: bool = False, + digest: list[bytes] | None = None, ): - raise esptool.FatalError( - "The number of blocks (%d), datafile (%d) and keypurpose (%d) " - "should be the same." - % (len(block_name_list), len(datafile_list), len(keypurpose_list)) - ) - - print("Burn keys to blocks:") - for block_name, datafile, keypurpose in zip( - block_name_list, datafile_list, keypurpose_list - ): - efuse = None - for block in efuses.blocks: - if block_name == block.name or block_name in block.alias: - efuse = efuses[block.name] - if efuse is None: - raise esptool.FatalError("Unknown block name - %s" % (block_name)) - num_bytes = efuse.bit_len // 8 - - block_num = efuses.get_index_block_by_name(block_name) - block = efuses.blocks[block_num] - + """Burn the key block with the specified name. Arguments are groups of block name, + key file (containing 256 bits of binary key data) and key purpose. + + Args: + blocks: List of eFuse block names to burn keys to. + keyfiles: List of open files to read key data from. + keypurposes: List of key purposes to burn. + no_write_protect: If True, the write protection will NOT be enabled. + no_read_protect: If True, the read protection will NOT be enabled. + show_sensitive_info: If True, the sensitive information will be shown. + digest: List of digests to burn. + """ + datafile_list: list[BinaryIO] | list[bytes] if digest is None: - if keypurpose == "ECDSA_KEY": - sk = espsecure.load_ecdsa_signing_key(datafile) - data = sk.to_string() - if len(data) == 24: - # the private key is 24 bytes long for NIST192p, and 8 bytes of padding - data = b"\x00" * 8 + data - else: - data = datafile.read() + datafile_list = keyfiles[ + 0 : len([name for name in keyfiles if name is not None]) : + ] else: - data = datafile + datafile_list = digest[ + 0 : len([name for name in digest if name is not None]) : + ] + block_name_list = blocks[ + 0 : len([name for name in blocks if name is not None]) : + ] + keypurpose_list = keypurposes[ + 0 : len([name for name in keypurposes if name is not None]) : + ] - print(" - %s" % (efuse.name), end=" ") - revers_msg = None - if efuses[block.key_purpose_name].need_reverse(keypurpose): - revers_msg = f"\tReversing byte order for {keypurpose} hardware peripheral" - data = data[::-1] - print( - "-> [{}]".format( - util.hexify(data, " ") - if args.show_sensitive_info - else " ".join(["??"] * len(data)) + if "XTS_AES_256_KEY" in keypurpose_list: + # XTS_AES_256_KEY is not an actual HW key purpose, needs to be split into + # XTS_AES_256_KEY_1 and XTS_AES_256_KEY_2 + block_name_list, datafile_list, keypurpose_list = self._split_512_bit_key( + block_name_list, + datafile_list, # type: ignore + keypurpose_list, ) - ) - if revers_msg: - print(revers_msg) - if len(data) != num_bytes: + + util.check_duplicate_name_in_list(block_name_list) + if len(block_name_list) != len(datafile_list) or len(block_name_list) != len( + keypurpose_list + ): raise esptool.FatalError( - "Incorrect key file size %d. Key file must be %d bytes (%d bits) " - "of raw binary key data." % (len(data), num_bytes, num_bytes * 8) + "The number of blocks (%d), datafile (%d) and keypurpose (%d) should be the same." + % (len(block_name_list), len(datafile_list), len(keypurpose_list)) ) - if efuses[block.key_purpose_name].need_rd_protect(keypurpose): - read_protect = False if args.no_read_protect else True - else: - read_protect = False - write_protect = not args.no_write_protect + log.print("Burn keys to blocks:") + for block_name, datafile, keypurpose in zip( + block_name_list, datafile_list, keypurpose_list + ): + efuse = None + for block in self.efuses.blocks: + if block_name == block.name or block_name in block.alias: + efuse = self.efuses[block.name] + if efuse is None: + raise esptool.FatalError(f"Unknown block name - {block_name}.") + num_bytes = efuse.bit_len // 8 + + block_num = self.efuses.get_index_block_by_name(block_name) + block = self.efuses.blocks[block_num] + + if isinstance(datafile, io.IOBase): + if keypurpose == "ECDSA_KEY": + sk = espsecure.load_ecdsa_signing_key(datafile) # type: ignore + data = espsecure.get_ecdsa_signing_key_raw_bytes(sk) + if len(data) == 24: + # the private key is 24 bytes long for NIST192p, and 8 bytes of padding + data = b"\x00" * 8 + data + else: + data = datafile.read() + datafile.close() + else: + data = datafile - # using efuse instead of a block gives the advantage of checking it as the whole field. - efuse.save(data) + log.print(f" - {efuse.name}", end=" ") + revers_msg = None + if self.efuses[block.key_purpose_name].need_reverse(keypurpose): + revers_msg = ( + f"\tReversing byte order for {keypurpose} hardware peripheral..." + ) + data = data[::-1] + log.print( + "-> [{}]".format( + util.hexify(data, " ") + if show_sensitive_info + else " ".join(["??"] * len(data)) + ) + ) + if revers_msg: + log.print(revers_msg) + if len(data) != num_bytes: + raise esptool.FatalError( + f"Incorrect key file size {len(data)}. Key file must be {num_bytes} " + f"bytes ({num_bytes * 8} bits) of raw binary key data." + ) - disable_wr_protect_key_purpose = False - if efuses[block.key_purpose_name].get() != keypurpose: - if efuses[block.key_purpose_name].is_writeable(): - print( - "\t'%s': '%s' -> '%s'." - % ( - block.key_purpose_name, - efuses[block.key_purpose_name].get(), - keypurpose, + if self.efuses[block.key_purpose_name].need_rd_protect(keypurpose): + read_protect = False if no_read_protect else True + else: + read_protect = False + write_protect = not no_write_protect + + # using eFuse instead of a block gives the advantage of checking it as the whole field. + efuse.save(data) + + disable_wr_protect_key_purpose = False + if self.efuses[block.key_purpose_name].get() != keypurpose: + if self.efuses[block.key_purpose_name].is_writeable(): + log.print( + f"\t'{block.key_purpose_name}': " + f"'{self.efuses[block.key_purpose_name].get()}' -> '{keypurpose}'." + ) + self.efuses[block.key_purpose_name].save(keypurpose) + disable_wr_protect_key_purpose = True + else: + raise esptool.FatalError( + f"It is not possible to change '{block.key_purpose_name}' " + f"to '{keypurpose}' because write protection bit is set." ) - ) - efuses[block.key_purpose_name].save(keypurpose) - disable_wr_protect_key_purpose = True else: + log.print(f"\t'{block.key_purpose_name}' is already '{keypurpose}'.") + if self.efuses[block.key_purpose_name].is_writeable(): + disable_wr_protect_key_purpose = True + + if disable_wr_protect_key_purpose: + log.print(f"\tDisabling write to '{block.key_purpose_name}'...") + self.efuses[block.key_purpose_name].disable_write() + + if read_protect: + log.print("\tDisabling read to key block...") + efuse.disable_read() + + if write_protect: + log.print("\tDisabling write to key block...") + efuse.disable_write() + log.print("") + + if not write_protect: + log.print("Keys will remain writeable (due to --no-write-protect).") + if no_read_protect: + log.print("Keys will remain readable (due to --no-read-protect).") + + if not self.efuses.burn_all(check_batch_mode=True): + return + log.print("Successful.") + + def burn_key_digest( + self, + blocks: list[str], + keyfiles: list[BinaryIO], + keypurposes: list[str], + no_write_protect: bool = False, + no_read_protect: bool = False, + show_sensitive_info: bool = False, + ): + """Parse a RSA public key and burn the digest to key eFuse block. + + Args: + blocks: List of eFuse block names to burn keys to. + keyfiles: List of open files to read key data from. + keypurposes: List of key purposes to burn. + no_write_protect: If True, the write protection will NOT be enabled. + no_read_protect: If True, the read protection will NOT be enabled. + show_sensitive_info: If True, the sensitive information will be shown. + """ + digest_list = [] + datafile_list = keyfiles[ + 0 : len([name for name in keyfiles if name is not None]) : + ] + block_list = blocks[0 : len([block for block in blocks if block is not None]) :] + + for block_name, datafile in zip(block_list, datafile_list): + efuse = None + for block in self.efuses.blocks: + if block_name == block.name or block_name in block.alias: + efuse = self.efuses[block.name] + if efuse is None: + raise esptool.FatalError(f"Unknown block name - {block_name}.") + num_bytes = efuse.bit_len // 8 + digest = espsecure._digest_sbv2_public_key(datafile) + if len(digest) != num_bytes: raise esptool.FatalError( - "It is not possible to change '%s' to '%s' " - "because write protection bit is set." - % (block.key_purpose_name, keypurpose) + "Incorrect digest size %d. Digest must be %d bytes (%d bits) " + "of raw binary key data." % (len(digest), num_bytes, num_bytes * 8) ) - else: - print("\t'%s' is already '%s'." % (block.key_purpose_name, keypurpose)) - if efuses[block.key_purpose_name].is_writeable(): - disable_wr_protect_key_purpose = True - - if disable_wr_protect_key_purpose: - print("\tDisabling write to '%s'." % block.key_purpose_name) - efuses[block.key_purpose_name].disable_write() - - if read_protect: - print("\tDisabling read to key block") - efuse.disable_read() - - if write_protect: - print("\tDisabling write to key block") - efuse.disable_write() - print("") - - if not write_protect: - print("Keys will remain writeable (due to --no-write-protect)") - if args.no_read_protect: - print("Keys will remain readable (due to --no-read-protect)") - - if not efuses.burn_all(check_batch_mode=True): - return - print("Successful") - - -def burn_key_digest(esp, efuses, args): - digest_list = [] - datafile_list = args.keyfile[ - 0 : len([name for name in args.keyfile if name is not None]) : - ] - block_list = args.block[ - 0 : len([block for block in args.block if block is not None]) : - ] - for block_name, datafile in zip(block_list, datafile_list): - efuse = None - for block in efuses.blocks: - if block_name == block.name or block_name in block.alias: - efuse = efuses[block.name] - if efuse is None: - raise esptool.FatalError("Unknown block name - %s" % (block_name)) - num_bytes = efuse.bit_len // 8 - digest = espsecure._digest_sbv2_public_key(datafile) - if len(digest) != num_bytes: - raise esptool.FatalError( - "Incorrect digest size %d. Digest must be %d bytes (%d bits) " - "of raw binary key data." % (len(digest), num_bytes, num_bytes * 8) - ) - digest_list.append(digest) - burn_key(esp, efuses, args, digest=digest_list) - - -def espefuse(esp, efuses, args, command): - parser = argparse.ArgumentParser() - subparsers = parser.add_subparsers(dest="operation") - add_commands(subparsers, efuses) - try: - cmd_line_args = parser.parse_args(command.split()) - except SystemExit: - traceback.print_stack() - raise esptool.FatalError('"{}" - incorrect command'.format(command)) - if cmd_line_args.operation == "execute_scripts": - configfiles = cmd_line_args.configfiles - index = cmd_line_args.index - # copy arguments from args to cmd_line_args - vars(cmd_line_args).update(vars(args)) - if cmd_line_args.operation == "execute_scripts": - cmd_line_args.configfiles = configfiles - cmd_line_args.index = index - if cmd_line_args.operation is None: - parser.print_help() - parser.exit(1) - operation_func = globals()[cmd_line_args.operation] - # each 'operation' is a module-level function of the same name - operation_func(esp, efuses, cmd_line_args) - - -def execute_scripts(esp, efuses, args): - efuses.batch_mode_cnt += 1 - del args.operation - scripts = args.scripts - del args.scripts - - for file in scripts: - with open(file.name, "r") as file: - exec(compile(file.read(), file.name, "exec")) - - if args.debug: - for block in efuses.blocks: - data = block.get_bitstring(from_read=False) - block.print_block(data, "regs_for_burn", args.debug) - - efuses.batch_mode_cnt -= 1 - if not efuses.burn_all(check_batch_mode=True): - return - print("Successful") + digest_list.append(digest) + + self.burn_key( + block_list, + datafile_list, + keypurposes, + no_write_protect, + no_read_protect, + show_sensitive_info, + digest=digest_list, + ) diff --git a/tools/esptool_py/espefuse/efuse/esp32h2/__init__.py b/tools/esptool_py/espefuse/efuse/esp32h2/__init__.py index a3b55a8023..635662d9e3 100644 --- a/tools/esptool_py/espefuse/efuse/esp32h2/__init__.py +++ b/tools/esptool_py/espefuse/efuse/esp32h2/__init__.py @@ -1,3 +1,5 @@ from . import operations from .emulate_efuse_controller import EmulateEfuseController from .fields import EspEfuses + +commands = operations.ESP32H2Commands diff --git a/tools/esptool_py/espefuse/efuse/esp32h2/fields.py b/tools/esptool_py/espefuse/efuse/esp32h2/fields.py index 91ef6c15ca..f06f41f3cc 100644 --- a/tools/esptool_py/espefuse/efuse/esp32h2/fields.py +++ b/tools/esptool_py/espefuse/efuse/esp32h2/fields.py @@ -10,6 +10,7 @@ import time from bitstring import BitArray +from esptool.logger import log import esptool @@ -55,9 +56,6 @@ class EspEfuses(base_fields.EspEfusesBase): Wrapper object to manage the efuse fields in a connected ESP bootloader """ - debug = False - do_not_confirm = False - def __init__( self, esp, @@ -66,14 +64,12 @@ def __init__( do_not_confirm=False, extend_efuse_table=None, ): + super().__init__(esp, skip_connect, debug, do_not_confirm, extend_efuse_table) self.Blocks = EfuseDefineBlocks() self.Fields = EfuseDefineFields(extend_efuse_table) self.REGS = EfuseDefineRegisters self.BURN_BLOCK_DATA_NAMES = self.Blocks.get_burn_block_data_names() self.BLOCKS_FOR_KEYS = self.Blocks.get_blocks_for_keys() - self._esp = esp - self.debug = debug - self.do_not_confirm = do_not_confirm if esp.CHIP_NAME != "ESP32-H2": raise esptool.FatalError( "Expected the 'esp' param for ESP32-H2 chip but got for '%s'." @@ -102,7 +98,7 @@ def __init__( for efuse in self.Fields.BLOCK2_CALIBRATION_EFUSES ] else: - if self["BLK_VERSION_MINOR"].get() == 2: + if self.get_block_version() >= 2: self.efuses += [ EfuseField.convert(self, efuse) for efuse in self.Fields.BLOCK2_CALIBRATION_EFUSES @@ -111,6 +107,10 @@ def __init__( EfuseField.convert(self, efuse) for efuse in self.Fields.CALC ] + if self.get_chip_version() <= 101: + rev = EfuseDefineFields(None, revision="esp32h2_v0.0_v1.1") + self.efuses += [EfuseField.convert(self, efuse) for efuse in rev.EFUSES] + def __getitem__(self, efuse_name): """Return the efuse field with the given name""" for e in self.efuses: @@ -136,14 +136,14 @@ def read_coding_scheme(self): self.coding_scheme = self.REGS.CODING_SCHEME_RS def print_status_regs(self): - print("") + log.print("") self.blocks[0].print_block(self.blocks[0].err_bitarray, "err__regs", debug=True) - print( + log.print( "{:27} 0x{:08x}".format( "EFUSE_RD_RS_ERR0_REG", self.read_reg(self.REGS.EFUSE_RD_RS_ERR0_REG) ) ) - print( + log.print( "{:27} 0x{:08x}".format( "EFUSE_RD_RS_ERR1_REG", self.read_reg(self.REGS.EFUSE_RD_RS_ERR1_REG) ) @@ -176,7 +176,7 @@ def wait_efuse_idle(self): # For PGM_CMD it is not necessary. return raise esptool.FatalError( - "Timed out waiting for Efuse controller command to complete" + "Timed out waiting for eFuse controller command to complete" ) def efuse_program(self, block): @@ -204,30 +204,30 @@ def efuse_read(self): try: self._esp = self.reconnect_chip(self._esp) except esptool.FatalError: - print("Can not re-connect to the chip") + log.print("Can not re-connect to the chip.") if not self["DIS_DOWNLOAD_MODE"].get() and self[ "DIS_DOWNLOAD_MODE" ].get(from_read=False): - print( + log.print( "This is the correct behavior as we are actually burning " - "DIS_DOWNLOAD_MODE which disables the connection to the chip" + "DIS_DOWNLOAD_MODE which disables the connection to the chip." ) - print("DIS_DOWNLOAD_MODE is enabled") - print("Successful") + log.print("DIS_DOWNLOAD_MODE is enabled.") + log.print("Successful.") sys.exit(0) # finish without errors raise - print("Established a connection with the chip") + log.print("Established a connection with the chip.") if self._esp.secure_download_mode and not secure_download_mode_before: - print("Secure download mode is enabled") + log.print("Secure download mode is enabled.") if not self["ENABLE_SECURITY_DOWNLOAD"].get() and self[ "ENABLE_SECURITY_DOWNLOAD" ].get(from_read=False): - print( - "espefuse tool can not continue to work in Secure download mode" + log.print( + "espefuse can not continue to work in Secure download mode." ) - print("ENABLE_SECURITY_DOWNLOAD is enabled") - print("Successful") + log.print("ENABLE_SECURITY_DOWNLOAD is enabled.") + log.print("Successful.") sys.exit(0) # finish without errors raise @@ -281,9 +281,9 @@ def get_coding_scheme_warnings(self, silent=False): block.num_errors = (reg_value >> err_num_offs) & err_num_mask ret_fail |= block.fail if not silent and (block.fail or block.num_errors): - print( - "Error(s) in BLOCK%d [ERRORS:%d FAIL:%d]" - % (block.id, block.num_errors, block.fail) + log.print( + f"Error(s) in BLOCK{block.id} " + f"[ERRORS:{block.num_errors} FAIL:{block.fail}]." ) if (self.debug or ret_fail) and not silent: self.print_status_regs() @@ -302,22 +302,9 @@ def convert(parent, efuse): "keypurpose": EfuseKeyPurposeField, "t_sensor": EfuseTempSensor, "adc_tp": EfuseAdcPointCalibration, - "wafer": EfuseWafer, }.get(efuse.class_type, EfuseField)(parent, efuse) -class EfuseWafer(EfuseField): - def get(self, from_read=True): - hi_bits = self.parent["WAFER_VERSION_MINOR_HI"].get(from_read) - assert self.parent["WAFER_VERSION_MINOR_HI"].bit_len == 1 - lo_bits = self.parent["WAFER_VERSION_MINOR_LO"].get(from_read) - assert self.parent["WAFER_VERSION_MINOR_LO"].bit_len == 3 - return (hi_bits << 3) + lo_bits - - def save(self, new_value): - raise esptool.FatalError("Burning %s is not supported" % self.name) - - class EfuseTempSensor(EfuseField): def get(self, from_read=True): value = self.get_bitstring(from_read) @@ -386,10 +373,8 @@ def get(self, from_read=True): def save(self, new_value): def print_field(e, new_value): - print( - " - '{}' ({}) {} -> {}".format( - e.name, e.description, e.get_bitstring(), new_value - ) + log.print( + f" - '{e.name}' ({e.description}) {e.get_bitstring()} -> {new_value}" ) if self.name == "CUSTOM_MAC": diff --git a/tools/esptool_py/espefuse/efuse/esp32h2/mem_definition.py b/tools/esptool_py/espefuse/efuse/esp32h2/mem_definition.py index 87663e95f7..4de0e1aeb6 100644 --- a/tools/esptool_py/espefuse/efuse/esp32h2/mem_definition.py +++ b/tools/esptool_py/espefuse/efuse/esp32h2/mem_definition.py @@ -111,19 +111,17 @@ def get_burn_block_data_names(self): class EfuseDefineFields(EfuseFieldsBase): - def __init__(self, extend_efuse_table) -> None: + def __init__(self, extend_efuse_table, revision=None) -> None: # List of efuse fields from TRM the chapter eFuse Controller. self.EFUSES = [] - self.KEYBLOCKS = [] - - # if BLK_VERSION_MINOR is 2, these efuse fields are in BLOCK2 self.BLOCK2_CALIBRATION_EFUSES = [] - self.CALC = [] dir_name = os.path.dirname(os.path.abspath(__file__)) dir_name, file_name = os.path.split(dir_name) + if revision is not None: + file_name = revision file_name = file_name + ".yaml" dir_name, _ = os.path.split(dir_name) efuse_file = os.path.join(dir_name, "efuse_defs", file_name) diff --git a/tools/esptool_py/espefuse/efuse/esp32h2/operations.py b/tools/esptool_py/espefuse/efuse/esp32h2/operations.py index 2aac7448b7..719e6559f7 100644 --- a/tools/esptool_py/espefuse/efuse/esp32h2/operations.py +++ b/tools/esptool_py/espefuse/efuse/esp32h2/operations.py @@ -1,424 +1,334 @@ # This file includes the operations with eFuses for ESP32-H2 chip # -# SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD +# SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD # # SPDX-License-Identifier: GPL-2.0-or-later -import argparse -import os # noqa: F401. It is used in IDF scripts -import traceback +from io import IOBase +from typing import BinaryIO +from esptool.logger import log +import rich_click as click import espsecure - import esptool from . import fields +from .mem_definition import EfuseDefineBlocks from .. import util from ..base_operations import ( - add_common_commands, + BaseCommands, + NonCompositeTuple, + TupleParameter, add_force_write_always, add_show_sensitive_info_option, - burn_bit, - burn_block_data, - burn_efuse, - check_error, - dump, - read_protect_efuse, - summary, - write_protect_efuse, + protect_options, ) -def protect_options(p): - p.add_argument( - "--no-write-protect", - help="Disable write-protecting of the key. The key remains writable. " - "(The keys use the RS coding scheme that does not support " - "post-write data changes. Forced write can damage RS encoding bits.) " - "The write-protecting of keypurposes does not depend on the option, " - "it will be set anyway.", - action="store_true", - ) - p.add_argument( - "--no-read-protect", - help="Disable read-protecting of the key. The key remains readable software." - "The key with keypurpose[USER, RESERVED and *_DIGEST] " - "will remain readable anyway. For the rest keypurposes the read-protection " - "will be defined the option (Read-protect by default).", - action="store_true", - ) +class ESP32H2Commands(BaseCommands): + CHIP_NAME = "ESP32-H2" + efuse_lib = fields.EspEfuses + ################################### CLI definitions ################################### -def add_commands(subparsers, efuses): - add_common_commands(subparsers, efuses) - burn_key = subparsers.add_parser( - "burn_key", help="Burn the key block with the specified name" - ) - protect_options(burn_key) - add_force_write_always(burn_key) - add_show_sensitive_info_option(burn_key) - burn_key.add_argument( - "block", - help="Key block to burn", - action="append", - choices=efuses.BLOCKS_FOR_KEYS, - ) - burn_key.add_argument( - "keyfile", - help="File containing 256 bits of binary key data. For the ECDSA_KEY purpose use PEM file.", - action="append", - type=argparse.FileType("rb"), - ) - burn_key.add_argument( - "keypurpose", - help="Purpose to set.", - action="append", - choices=fields.EfuseKeyPurposeField.KEY_PURPOSES_NAME, - ) - for _ in efuses.BLOCKS_FOR_KEYS: - burn_key.add_argument( - "block", - help="Key block to burn", - nargs="?", - action="append", - metavar="BLOCK", - choices=efuses.BLOCKS_FOR_KEYS, - ) - burn_key.add_argument( - "keyfile", - help="File containing 256 bits of binary key data. For the ECDSA_KEY purpose use PEM file.", - nargs="?", - action="append", - metavar="KEYFILE", - type=argparse.FileType("rb"), - ) - burn_key.add_argument( - "keypurpose", - help="Purpose to set.", - nargs="?", - action="append", - metavar="KEYPURPOSE", - choices=fields.EfuseKeyPurposeField.KEY_PURPOSES_NAME, - ) + def add_cli_commands(self, cli: click.Group): + super().add_cli_commands(cli) + blocks_for_keys = EfuseDefineBlocks().get_blocks_for_keys() - burn_key_digest = subparsers.add_parser( - "burn_key_digest", - help="Parse a RSA public key and burn the digest to key efuse block", - ) - protect_options(burn_key_digest) - add_force_write_always(burn_key_digest) - add_show_sensitive_info_option(burn_key_digest) - burn_key_digest.add_argument( - "block", - help="Key block to burn", - action="append", - choices=efuses.BLOCKS_FOR_KEYS, - ) - burn_key_digest.add_argument( - "keyfile", - help="Key file to digest (PEM format)", - action="append", - type=argparse.FileType("rb"), - ) - burn_key_digest.add_argument( - "keypurpose", - help="Purpose to set.", - action="append", - choices=fields.EfuseKeyPurposeField.DIGEST_KEY_PURPOSES, - ) - for _ in efuses.BLOCKS_FOR_KEYS: - burn_key_digest.add_argument( - "block", - help="Key block to burn", - nargs="?", - action="append", - metavar="BLOCK", - choices=efuses.BLOCKS_FOR_KEYS, + @cli.command( + "burn-key", + help="Burn the key block with the specified name. Arguments are groups of block name, " + "key file (containing 256 bits of binary key data) and key purpose.\n\n" + f"Block is one of: [{', '.join(blocks_for_keys)}]\n\n" + f"Key purpose is one of: [{', '.join(fields.EfuseKeyPurposeField.KEY_PURPOSES_NAME)}]", ) - burn_key_digest.add_argument( - "keyfile", - help="Key file to digest (PEM format)", - nargs="?", - action="append", - metavar="KEYFILE", - type=argparse.FileType("rb"), + @click.argument( + "block_keyfile_keypurpose", + metavar=" ", + cls=TupleParameter, + required=True, + nargs=-1, + max_arity=len(blocks_for_keys), + type=NonCompositeTuple( + [ + click.Choice(blocks_for_keys), + click.File("rb"), + click.Choice(fields.EfuseKeyPurposeField.KEY_PURPOSES_NAME), + ] + ), ) - burn_key_digest.add_argument( - "keypurpose", - help="Purpose to set.", - nargs="?", - action="append", - metavar="KEYPURPOSE", - choices=fields.EfuseKeyPurposeField.DIGEST_KEY_PURPOSES, + @protect_options + @add_force_write_always + @add_show_sensitive_info_option + @click.pass_context + def burn_key_cli(ctx, **kwargs): + kwargs.pop("force_write_always") + block, keyfile, keypurpose = zip(*kwargs.pop("block_keyfile_keypurpose")) + kwargs["show_sensitive_info"] = ctx.show_sensitive_info + self.burn_key(block, keyfile, keypurpose, **kwargs) + + @cli.command( + "burn-key-digest", + short_help="Parse a RSA public key and burn the digest.", + help="Parse a RSA public key and burn the digest to key eFuse block.\n\n" + f"Block is one of: [{', '.join(blocks_for_keys)}]\n\n" + f"Key purpose is one of: [{', '.join(fields.EfuseKeyPurposeField.DIGEST_KEY_PURPOSES)}]", ) - - p = subparsers.add_parser( - "set_flash_voltage", - help="Permanently set the internal flash voltage regulator " - "to either 1.8V, 3.3V or OFF. This means GPIO45 can be high or low " - "at reset without changing the flash voltage.", - ) - p.add_argument("voltage", help="Voltage selection", choices=["1.8V", "3.3V", "OFF"]) - - p = subparsers.add_parser( - "burn_custom_mac", help="Burn a 48-bit Custom MAC Address to EFUSE BLOCK3." - ) - p.add_argument( - "mac", - help="Custom MAC Address to burn given in hexadecimal format with bytes " - "separated by colons (e.g. AA:CD:EF:01:02:03).", - type=fields.base_fields.CheckArgValue(efuses, "CUSTOM_MAC"), - ) - add_force_write_always(p) - - p = subparsers.add_parser("get_custom_mac", help="Prints the Custom MAC Address.") - - -def burn_custom_mac(esp, efuses, args): - efuses["CUSTOM_MAC"].save(args.mac) - if not efuses.burn_all(check_batch_mode=True): - return - get_custom_mac(esp, efuses, args) - print("Successful") - - -def get_custom_mac(esp, efuses, args): - print("Custom MAC Address: {}".format(efuses["CUSTOM_MAC"].get())) - - -def set_flash_voltage(esp, efuses, args): - raise esptool.FatalError("set_flash_voltage is not supported!") - - -def adc_info(esp, efuses, args): - print("") - # fmt: off - if efuses["BLK_VERSION_MINOR"].get() == 2: - print("Temperature Sensor Calibration = {}C".format(efuses["TEMP_CALIB"].get())) - print("") - print("ADC1:") - print("AVE_INITCODE_ATTEN0 = ", efuses["ADC1_AVE_INITCODE_ATTEN0"].get()) - print("AVE_INITCODE_ATTEN1 = ", efuses["ADC1_AVE_INITCODE_ATTEN1"].get()) - print("AVE_INITCODE_ATTEN2 = ", efuses["ADC1_AVE_INITCODE_ATTEN2"].get()) - print("AVE_INITCODE_ATTEN3 = ", efuses["ADC1_AVE_INITCODE_ATTEN3"].get()) - print("HI_DOUT_ATTEN0 = ", efuses["ADC1_HI_DOUT_ATTEN0"].get()) - print("HI_DOUT_ATTEN1 = ", efuses["ADC1_HI_DOUT_ATTEN1"].get()) - print("HI_DOUT_ATTEN2 = ", efuses["ADC1_HI_DOUT_ATTEN2"].get()) - print("HI_DOUT_ATTEN3 = ", efuses["ADC1_HI_DOUT_ATTEN3"].get()) - print("CH0_ATTEN0_INITCODE_DIFF = ", efuses["ADC1_CH0_ATTEN0_INITCODE_DIFF"].get()) - print("CH1_ATTEN0_INITCODE_DIFF = ", efuses["ADC1_CH1_ATTEN0_INITCODE_DIFF"].get()) - print("CH2_ATTEN0_INITCODE_DIFF = ", efuses["ADC1_CH2_ATTEN0_INITCODE_DIFF"].get()) - print("CH3_ATTEN0_INITCODE_DIFF = ", efuses["ADC1_CH3_ATTEN0_INITCODE_DIFF"].get()) - print("CH4_ATTEN0_INITCODE_DIFF = ", efuses["ADC1_CH4_ATTEN0_INITCODE_DIFF"].get()) - else: - print("BLK_VERSION_MINOR = {}".format(efuses["BLK_VERSION_MINOR"].get())) - # fmt: on - - -def burn_key(esp, efuses, args, digest=None): - if digest is None: - datafile_list = args.keyfile[ - 0 : len([name for name in args.keyfile if name is not None]) : - ] - else: - datafile_list = digest[0 : len([name for name in digest if name is not None]) :] - efuses.force_write_always = args.force_write_always - block_name_list = args.block[ - 0 : len([name for name in args.block if name is not None]) : - ] - keypurpose_list = args.keypurpose[ - 0 : len([name for name in args.keypurpose if name is not None]) : - ] - - util.check_duplicate_name_in_list(block_name_list) - if len(block_name_list) != len(datafile_list) or len(block_name_list) != len( - keypurpose_list - ): - raise esptool.FatalError( - "The number of blocks (%d), datafile (%d) and keypurpose (%d) " - "should be the same." - % (len(block_name_list), len(datafile_list), len(keypurpose_list)) + @click.argument( + "block_keyfile_keypurpose", + metavar=" ", + cls=TupleParameter, + required=True, + nargs=-1, + max_arity=len(blocks_for_keys), + type=NonCompositeTuple( + [ + click.Choice(blocks_for_keys), + click.File("rb"), + click.Choice(fields.EfuseKeyPurposeField.DIGEST_KEY_PURPOSES), + ] + ), ) - - print("Burn keys to blocks:") - for block_name, datafile, keypurpose in zip( - block_name_list, datafile_list, keypurpose_list + @protect_options + @add_force_write_always + @add_show_sensitive_info_option + @click.pass_context + def burn_key_digest_cli(ctx, **kwargs): + kwargs.pop("force_write_always") + block, keyfile, keypurpose = zip(*kwargs.pop("block_keyfile_keypurpose")) + kwargs["show_sensitive_info"] = ctx.show_sensitive_info + self.burn_key_digest(block, keyfile, keypurpose, **kwargs) + + ###################################### Commands ###################################### + + def adc_info(self): + log.print("Block version:", self.efuses.get_block_version()) + if self.efuses.get_block_version() >= 2: + # fmt: off + log.print(f"Temperature Sensor Calibration = {self.efuses['TEMP_CALIB'].get()}C") + log.print("") + log.print("ADC1:") + log.print("AVE_INITCODE_ATTEN0 = ", self.efuses["ADC1_AVE_INITCODE_ATTEN0"].get()) + log.print("AVE_INITCODE_ATTEN1 = ", self.efuses["ADC1_AVE_INITCODE_ATTEN1"].get()) + log.print("AVE_INITCODE_ATTEN2 = ", self.efuses["ADC1_AVE_INITCODE_ATTEN2"].get()) + log.print("AVE_INITCODE_ATTEN3 = ", self.efuses["ADC1_AVE_INITCODE_ATTEN3"].get()) + log.print("HI_DOUT_ATTEN0 = ", self.efuses["ADC1_HI_DOUT_ATTEN0"].get()) + log.print("HI_DOUT_ATTEN1 = ", self.efuses["ADC1_HI_DOUT_ATTEN1"].get()) + log.print("HI_DOUT_ATTEN2 = ", self.efuses["ADC1_HI_DOUT_ATTEN2"].get()) + log.print("HI_DOUT_ATTEN3 = ", self.efuses["ADC1_HI_DOUT_ATTEN3"].get()) + log.print("CH0_ATTEN0_INITCODE_DIFF = ", self.efuses["ADC1_CH0_ATTEN0_INITCODE_DIFF"].get()) + log.print("CH1_ATTEN0_INITCODE_DIFF = ", self.efuses["ADC1_CH1_ATTEN0_INITCODE_DIFF"].get()) + log.print("CH2_ATTEN0_INITCODE_DIFF = ", self.efuses["ADC1_CH2_ATTEN0_INITCODE_DIFF"].get()) + log.print("CH3_ATTEN0_INITCODE_DIFF = ", self.efuses["ADC1_CH3_ATTEN0_INITCODE_DIFF"].get()) + log.print("CH4_ATTEN0_INITCODE_DIFF = ", self.efuses["ADC1_CH4_ATTEN0_INITCODE_DIFF"].get()) + # fmt: on + + def burn_key( + self, + blocks: list[str], + keyfiles: list[BinaryIO], + keypurposes: list[str], + no_write_protect: bool = False, + no_read_protect: bool = False, + show_sensitive_info: bool = False, + digest: list[bytes] | None = None, ): - efuse = None - for block in efuses.blocks: - if block_name == block.name or block_name in block.alias: - efuse = efuses[block.name] - if efuse is None: - raise esptool.FatalError("Unknown block name - %s" % (block_name)) - num_bytes = efuse.bit_len // 8 - - block_num = efuses.get_index_block_by_name(block_name) - block = efuses.blocks[block_num] - + """Burn the key block with the specified name. Arguments are groups of block name, + key file (containing 256 bits of binary key data) and key purpose. + + Args: + blocks: List of eFuse block names to burn keys to. + keyfiles: List of open files to read key data from. + keypurposes: List of key purposes to burn. + no_write_protect: If True, the write protection will NOT be enabled. + no_read_protect: If True, the read protection will NOT be enabled. + show_sensitive_info: If True, the sensitive information will be shown. + digest: List of digests to burn. + """ + datafile_list: list[BinaryIO] | list[bytes] if digest is None: - if keypurpose == "ECDSA_KEY": - sk = espsecure.load_ecdsa_signing_key(datafile) - data = sk.to_string() - if len(data) == 24: - # the private key is 24 bytes long for NIST192p, add 8 bytes of padding - data = b"\x00" * 8 + data - else: - data = datafile.read() + datafile_list = keyfiles[ + 0 : len([name for name in keyfiles if name is not None]) : + ] else: - data = datafile + datafile_list = digest[ + 0 : len([name for name in digest if name is not None]) : + ] + block_name_list = blocks[ + 0 : len([name for name in blocks if name is not None]) : + ] + keypurpose_list = keypurposes[ + 0 : len([name for name in keypurposes if name is not None]) : + ] - print(" - %s" % (efuse.name), end=" ") - revers_msg = None - if efuses[block.key_purpose_name].need_reverse(keypurpose): - revers_msg = f"\tReversing byte order for {keypurpose} hardware peripheral" - data = data[::-1] - print( - "-> [{}]".format( - util.hexify(data, " ") - if args.show_sensitive_info - else " ".join(["??"] * len(data)) - ) - ) - if revers_msg: - print(revers_msg) - if len(data) != num_bytes: + util.check_duplicate_name_in_list(block_name_list) + if len(block_name_list) != len(datafile_list) or len(block_name_list) != len( + keypurpose_list + ): raise esptool.FatalError( - "Incorrect key file size %d. Key file must be %d bytes (%d bits) " - "of raw binary key data." % (len(data), num_bytes, num_bytes * 8) + f"The number of blocks ({len(block_name_list)}), " + f"datafile ({len(datafile_list)}) and keypurpose ({len(keypurpose_list)}) " + "should be the same." ) - if efuses[block.key_purpose_name].need_rd_protect(keypurpose): - read_protect = False if args.no_read_protect else True - else: - read_protect = False - write_protect = not args.no_write_protect - - # using efuse instead of a block gives the advantage of checking it as the whole field. - efuse.save(data) + log.print("Burn keys to blocks:") + for block_name, datafile, keypurpose in zip( + block_name_list, datafile_list, keypurpose_list + ): + efuse = None + for block in self.efuses.blocks: + if block_name == block.name or block_name in block.alias: + efuse = self.efuses[block.name] + if efuse is None: + raise esptool.FatalError(f"Unknown block name - {block_name}.") + num_bytes = efuse.bit_len // 8 + + block_num = self.efuses.get_index_block_by_name(block_name) + block = self.efuses.blocks[block_num] + + if isinstance(datafile, IOBase): + if keypurpose == "ECDSA_KEY": + sk = espsecure.load_ecdsa_signing_key(datafile) # type: ignore + data = espsecure.get_ecdsa_signing_key_raw_bytes(sk) + if len(data) == 24: + # the private key is 24 bytes long for NIST192p, add 8 bytes of padding + data = b"\x00" * 8 + data + else: + data = datafile.read() + datafile.close() + else: + data = datafile - disable_wr_protect_key_purpose = False - if efuses[block.key_purpose_name].get() != keypurpose: - if efuses[block.key_purpose_name].is_writeable(): - print( - "\t'%s': '%s' -> '%s'." - % ( - block.key_purpose_name, - efuses[block.key_purpose_name].get(), - keypurpose, - ) + log.print(f" - {efuse.name}", end=" ") + revers_msg = None + if self.efuses[block.key_purpose_name].need_reverse(keypurpose): + revers_msg = ( + f"\tReversing byte order for {keypurpose} hardware peripheral..." ) - efuses[block.key_purpose_name].save(keypurpose) - disable_wr_protect_key_purpose = True - else: + data = data[::-1] + log.print( + "-> [{}]".format( + util.hexify(data, " ") + if show_sensitive_info + else " ".join(["??"] * len(data)) + ) + ) + if revers_msg: + log.print(revers_msg) + if len(data) != num_bytes: raise esptool.FatalError( - "It is not possible to change '%s' to '%s' " - "because write protection bit is set." - % (block.key_purpose_name, keypurpose) + "Incorrect key file size %d. Key file must be %d bytes (%d bits) " + "of raw binary key data." % (len(data), num_bytes, num_bytes * 8) ) - else: - print("\t'%s' is already '%s'." % (block.key_purpose_name, keypurpose)) - if efuses[block.key_purpose_name].is_writeable(): - disable_wr_protect_key_purpose = True - if keypurpose == "ECDSA_KEY": - if efuses["ECDSA_FORCE_USE_HARDWARE_K"].get() == 0: - # For ECDSA key purpose block permanently enable - # the hardware TRNG supplied k mode (most secure mode) - print("\tECDSA_FORCE_USE_HARDWARE_K: 0 -> 1") - efuses["ECDSA_FORCE_USE_HARDWARE_K"].save(1) + if self.efuses[block.key_purpose_name].need_rd_protect(keypurpose): + read_protect = False if no_read_protect else True else: - print("\tECDSA_FORCE_USE_HARDWARE_K is already '1'") - - if disable_wr_protect_key_purpose: - print("\tDisabling write to '%s'." % block.key_purpose_name) - efuses[block.key_purpose_name].disable_write() - - if read_protect: - print("\tDisabling read to key block") - efuse.disable_read() - - if write_protect: - print("\tDisabling write to key block") - efuse.disable_write() - print("") - - if not write_protect: - print("Keys will remain writeable (due to --no-write-protect)") - if args.no_read_protect: - print("Keys will remain readable (due to --no-read-protect)") - - if not efuses.burn_all(check_batch_mode=True): - return - print("Successful") - - -def burn_key_digest(esp, efuses, args): - digest_list = [] - datafile_list = args.keyfile[ - 0 : len([name for name in args.keyfile if name is not None]) : - ] - block_list = args.block[ - 0 : len([block for block in args.block if block is not None]) : - ] - for block_name, datafile in zip(block_list, datafile_list): - efuse = None - for block in efuses.blocks: - if block_name == block.name or block_name in block.alias: - efuse = efuses[block.name] - if efuse is None: - raise esptool.FatalError("Unknown block name - %s" % (block_name)) - num_bytes = efuse.bit_len // 8 - digest = espsecure._digest_sbv2_public_key(datafile) - if len(digest) != num_bytes: - raise esptool.FatalError( - "Incorrect digest size %d. Digest must be %d bytes (%d bits) " - "of raw binary key data." % (len(digest), num_bytes, num_bytes * 8) - ) - digest_list.append(digest) - burn_key(esp, efuses, args, digest=digest_list) - - -def espefuse(esp, efuses, args, command): - parser = argparse.ArgumentParser() - subparsers = parser.add_subparsers(dest="operation") - add_commands(subparsers, efuses) - try: - cmd_line_args = parser.parse_args(command.split()) - except SystemExit: - traceback.print_stack() - raise esptool.FatalError('"{}" - incorrect command'.format(command)) - if cmd_line_args.operation == "execute_scripts": - configfiles = cmd_line_args.configfiles - index = cmd_line_args.index - # copy arguments from args to cmd_line_args - vars(cmd_line_args).update(vars(args)) - if cmd_line_args.operation == "execute_scripts": - cmd_line_args.configfiles = configfiles - cmd_line_args.index = index - if cmd_line_args.operation is None: - parser.print_help() - parser.exit(1) - operation_func = globals()[cmd_line_args.operation] - # each 'operation' is a module-level function of the same name - operation_func(esp, efuses, cmd_line_args) - - -def execute_scripts(esp, efuses, args): - efuses.batch_mode_cnt += 1 - del args.operation - scripts = args.scripts - del args.scripts - - for file in scripts: - with open(file.name, "r") as file: - exec(compile(file.read(), file.name, "exec")) - - if args.debug: - for block in efuses.blocks: - data = block.get_bitstring(from_read=False) - block.print_block(data, "regs_for_burn", args.debug) - - efuses.batch_mode_cnt -= 1 - if not efuses.burn_all(check_batch_mode=True): - return - print("Successful") + read_protect = False + write_protect = not no_write_protect + + # using eFuse instead of a block gives the advantage of checking it as the whole field. + efuse.save(data) + + disable_wr_protect_key_purpose = False + if self.efuses[block.key_purpose_name].get() != keypurpose: + if self.efuses[block.key_purpose_name].is_writeable(): + log.print( + f"\t'{block.key_purpose_name}': " + f"'{self.efuses[block.key_purpose_name].get()}' -> '{keypurpose}'." + ) + self.efuses[block.key_purpose_name].save(keypurpose) + disable_wr_protect_key_purpose = True + else: + raise esptool.FatalError( + f"It is not possible to change '{block.key_purpose_name}' " + f"to '{keypurpose}' because write protection bit is set." + ) + else: + log.print(f"\t'{block.key_purpose_name}' is already '{keypurpose}'.") + if self.efuses[block.key_purpose_name].is_writeable(): + disable_wr_protect_key_purpose = True + + # >= ESP32-H2 ECO5 revision (v1.2) does not have ECDSA_FORCE_USE_HARDWARE_K + if self.efuses.get_chip_version() <= 101: + if keypurpose == "ECDSA_KEY": + if self.efuses["ECDSA_FORCE_USE_HARDWARE_K"].get() == 0: + # For ECDSA key purpose block permanently enable + # the hardware TRNG supplied k mode (most secure mode) + log.print("\tECDSA_FORCE_USE_HARDWARE_K: 0 -> 1") + self.efuses["ECDSA_FORCE_USE_HARDWARE_K"].save(1) + else: + log.print("\tECDSA_FORCE_USE_HARDWARE_K is already '1'") + + if disable_wr_protect_key_purpose: + log.print(f"\tDisabling write to '{block.key_purpose_name}'...") + self.efuses[block.key_purpose_name].disable_write() + + if read_protect: + log.print("\tDisabling read to key block...") + efuse.disable_read() + + if write_protect: + log.print("\tDisabling write to key block...") + efuse.disable_write() + log.print("") + + if not write_protect: + log.print("Keys will remain writeable (due to --no-write-protect).") + if no_read_protect: + log.print("Keys will remain readable (due to --no-read-protect).") + + if not self.efuses.burn_all(check_batch_mode=True): + return + log.print("Successful.") + + def burn_key_digest( + self, + blocks: list[str], + keyfiles: list[BinaryIO], + keypurposes: list[str], + no_write_protect: bool = False, + no_read_protect: bool = False, + show_sensitive_info: bool = False, + ): + """Parse a RSA public key and burn the digest to key eFuse block. + + Args: + blocks: List of eFuse block names to burn keys to. + keyfiles: List of open files to read key data from. + keypurposes: List of key purposes to burn. + no_write_protect: If True, the write protection will NOT be enabled. + no_read_protect: If True, the read protection will NOT be enabled. + show_sensitive_info: If True, the sensitive information will be shown. + """ + digest_list = [] + datafile_list = keyfiles[ + 0 : len([name for name in keyfiles if name is not None]) : + ] + block_list = blocks[0 : len([block for block in blocks if block is not None]) :] + + for block_name, datafile in zip(block_list, datafile_list): + efuse = None + for block in self.efuses.blocks: + if block_name == block.name or block_name in block.alias: + efuse = self.efuses[block.name] + if efuse is None: + raise esptool.FatalError(f"Unknown block name - {block_name}.") + num_bytes = efuse.bit_len // 8 + digest = espsecure._digest_sbv2_public_key(datafile) + if len(digest) != num_bytes: + raise esptool.FatalError( + f"Incorrect digest size {len(digest)}. Digest must be {num_bytes} " + f"bytes ({num_bytes * 8} bits) of raw binary key data." + ) + digest_list.append(digest) + + self.burn_key( + block_list, + datafile_list, + keypurposes, + no_write_protect, + no_read_protect, + show_sensitive_info, + digest=digest_list, + ) diff --git a/tools/esptool_py/espefuse/efuse/esp32c5beta3/__init__.py b/tools/esptool_py/espefuse/efuse/esp32h21/__init__.py similarity index 74% rename from tools/esptool_py/espefuse/efuse/esp32c5beta3/__init__.py rename to tools/esptool_py/espefuse/efuse/esp32h21/__init__.py index a3b55a8023..240b05442d 100644 --- a/tools/esptool_py/espefuse/efuse/esp32c5beta3/__init__.py +++ b/tools/esptool_py/espefuse/efuse/esp32h21/__init__.py @@ -1,3 +1,5 @@ from . import operations from .emulate_efuse_controller import EmulateEfuseController from .fields import EspEfuses + +commands = operations.ESP32H21Commands diff --git a/tools/esptool_py/espefuse/efuse/esp32c5beta3/emulate_efuse_controller.py b/tools/esptool_py/espefuse/efuse/esp32h21/emulate_efuse_controller.py similarity index 93% rename from tools/esptool_py/espefuse/efuse/esp32c5beta3/emulate_efuse_controller.py rename to tools/esptool_py/espefuse/efuse/esp32h21/emulate_efuse_controller.py index 3fdab6f816..6dff54ca43 100644 --- a/tools/esptool_py/espefuse/efuse/esp32c5beta3/emulate_efuse_controller.py +++ b/tools/esptool_py/espefuse/efuse/esp32h21/emulate_efuse_controller.py @@ -1,6 +1,6 @@ -# This file describes eFuses controller for ESP32-C5 beta3 chip +# This file describes eFuses controller for ESP32-H21 chip # -# SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD +# SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD # # SPDX-License-Identifier: GPL-2.0-or-later @@ -13,7 +13,7 @@ class EmulateEfuseController(EmulateEfuseControllerBase): """The class for virtual efuse operation. Using for HOST_TEST.""" - CHIP_NAME = "ESP32-C5(beta3)" + CHIP_NAME = "ESP32-H21" mem = None debug = False @@ -33,7 +33,7 @@ def get_minor_chip_version(self): return 0 def get_crystal_freq(self): - return 40 # MHz (common for all chips) + return 32 # MHz def get_security_info(self): return { diff --git a/tools/esptool_py/espefuse/efuse/esp32h2beta1/fields.py b/tools/esptool_py/espefuse/efuse/esp32h21/fields.py similarity index 85% rename from tools/esptool_py/espefuse/efuse/esp32h2beta1/fields.py rename to tools/esptool_py/espefuse/efuse/esp32h21/fields.py index 90fb72bb58..bfb1e1e7ad 100644 --- a/tools/esptool_py/espefuse/efuse/esp32h2beta1/fields.py +++ b/tools/esptool_py/espefuse/efuse/esp32h21/fields.py @@ -1,6 +1,6 @@ -# This file describes eFuses for ESP32-H2 chip +# This file describes eFuses for ESP32-H21 chip # -# SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD +# SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD # # SPDX-License-Identifier: GPL-2.0-or-later @@ -10,6 +10,7 @@ import time from bitstring import BitArray +from esptool.logger import log import esptool @@ -55,9 +56,6 @@ class EspEfuses(base_fields.EspEfusesBase): Wrapper object to manage the efuse fields in a connected ESP bootloader """ - debug = False - do_not_confirm = False - def __init__( self, esp, @@ -66,17 +64,15 @@ def __init__( do_not_confirm=False, extend_efuse_table=None, ): + super().__init__(esp, skip_connect, debug, do_not_confirm, extend_efuse_table) self.Blocks = EfuseDefineBlocks() self.Fields = EfuseDefineFields(extend_efuse_table) self.REGS = EfuseDefineRegisters self.BURN_BLOCK_DATA_NAMES = self.Blocks.get_burn_block_data_names() self.BLOCKS_FOR_KEYS = self.Blocks.get_blocks_for_keys() - self._esp = esp - self.debug = debug - self.do_not_confirm = do_not_confirm - if esp.CHIP_NAME != "ESP32-H2(beta1)": + if esp.CHIP_NAME != "ESP32-H21": raise esptool.FatalError( - "Expected the 'esp' param for ESP32-H2(beta1) chip but got for '%s'." + "Expected the 'esp' param for ESP32-H21 chip but got for '%s'." % (esp.CHIP_NAME) ) if not skip_connect: @@ -102,7 +98,7 @@ def __init__( for efuse in self.Fields.BLOCK2_CALIBRATION_EFUSES ] else: - if self["BLK_VERSION_MINOR"].get() == 2: + if self.get_block_version() >= 2: self.efuses += [ EfuseField.convert(self, efuse) for efuse in self.Fields.BLOCK2_CALIBRATION_EFUSES @@ -136,14 +132,14 @@ def read_coding_scheme(self): self.coding_scheme = self.REGS.CODING_SCHEME_RS def print_status_regs(self): - print("") + log.print("") self.blocks[0].print_block(self.blocks[0].err_bitarray, "err__regs", debug=True) - print( + log.print( "{:27} 0x{:08x}".format( "EFUSE_RD_RS_ERR0_REG", self.read_reg(self.REGS.EFUSE_RD_RS_ERR0_REG) ) ) - print( + log.print( "{:27} 0x{:08x}".format( "EFUSE_RD_RS_ERR1_REG", self.read_reg(self.REGS.EFUSE_RD_RS_ERR1_REG) ) @@ -176,7 +172,7 @@ def wait_efuse_idle(self): # For PGM_CMD it is not necessary. return raise esptool.FatalError( - "Timed out waiting for Efuse controller command to complete" + "Timed out waiting for eFuse controller command to complete" ) def efuse_program(self, block): @@ -204,30 +200,30 @@ def efuse_read(self): try: self._esp = self.reconnect_chip(self._esp) except esptool.FatalError: - print("Can not re-connect to the chip") + log.print("Can not re-connect to the chip.") if not self["DIS_DOWNLOAD_MODE"].get() and self[ "DIS_DOWNLOAD_MODE" ].get(from_read=False): - print( + log.print( "This is the correct behavior as we are actually burning " - "DIS_DOWNLOAD_MODE which disables the connection to the chip" + "DIS_DOWNLOAD_MODE which disables the connection to the chip." ) - print("DIS_DOWNLOAD_MODE is enabled") - print("Successful") + log.print("DIS_DOWNLOAD_MODE is enabled.") + log.print("Successful.") sys.exit(0) # finish without errors raise - print("Established a connection with the chip") + log.print("Established a connection with the chip.") if self._esp.secure_download_mode and not secure_download_mode_before: - print("Secure download mode is enabled") + log.print("Secure download mode is enabled.") if not self["ENABLE_SECURITY_DOWNLOAD"].get() and self[ "ENABLE_SECURITY_DOWNLOAD" ].get(from_read=False): - print( - "espefuse tool can not continue to work in Secure download mode" + log.print( + "espefuse can not continue to work in Secure download mode." ) - print("ENABLE_SECURITY_DOWNLOAD is enabled") - print("Successful") + log.print("ENABLE_SECURITY_DOWNLOAD is enabled.") + log.print("Successful.") sys.exit(0) # finish without errors raise @@ -235,21 +231,12 @@ def set_efuse_timing(self): """Set timing registers for burning efuses""" # Configure clock apb_freq = self.get_crystal_freq() + # Based on `CONFIG_SOC_XTAL_SUPPORT_32M=y` for this target from ESP-IDF configuration if apb_freq != 32: raise esptool.FatalError( "The eFuse supports only xtal=32M (xtal was %d)" % apb_freq ) - - self.update_reg(self.REGS.EFUSE_DAC_CONF_REG, self.REGS.EFUSE_DAC_NUM_M, 0xFF) - self.update_reg( - self.REGS.EFUSE_DAC_CONF_REG, self.REGS.EFUSE_DAC_CLK_DIV_M, 0x28 - ) - self.update_reg( - self.REGS.EFUSE_WR_TIM_CONF1_REG, self.REGS.EFUSE_PWR_ON_NUM_M, 0x3000 - ) - self.update_reg( - self.REGS.EFUSE_WR_TIM_CONF2_REG, self.REGS.EFUSE_PWR_OFF_NUM_M, 0x190 - ) + # TODO: [ESP32H21] IDF-11506 def get_coding_scheme_warnings(self, silent=False): """Check if the coding scheme has detected any errors.""" @@ -280,9 +267,9 @@ def get_coding_scheme_warnings(self, silent=False): block.num_errors = (reg_value >> err_num_offs) & err_num_mask ret_fail |= block.fail if not silent and (block.fail or block.num_errors): - print( - "Error(s) in BLOCK%d [ERRORS:%d FAIL:%d]" - % (block.id, block.num_errors, block.fail) + log.print( + f"Error(s) in BLOCK{block.id} " + f"[ERRORS:{block.num_errors} FAIL:{block.fail}]." ) if (self.debug or ret_fail) and not silent: self.print_status_regs() @@ -307,11 +294,8 @@ def convert(parent, efuse): class EfuseWafer(EfuseField): def get(self, from_read=True): - hi_bits = self.parent["WAFER_VERSION_MINOR_HI"].get(from_read) - assert self.parent["WAFER_VERSION_MINOR_HI"].bit_len == 1 - lo_bits = self.parent["WAFER_VERSION_MINOR_LO"].get(from_read) - assert self.parent["WAFER_VERSION_MINOR_LO"].bit_len == 3 - return (hi_bits << 3) + lo_bits + # TODO: [ESP32H21] IDF-11506 + return 0 def save(self, new_value): raise esptool.FatalError("Burning %s is not supported" % self.name) @@ -344,7 +328,7 @@ def check_format(self, new_value_str): f"MAC Address needs to be a {num_bytes}-byte hexadecimal format " "separated by colons (:)!" ) - hexad = new_value_str.replace(":", "").split(" ", 1)[0] + hexad = new_value_str.replace(":", "") hexad = hexad.split(" ", 1)[0] if self.is_field_calculated() else hexad if len(hexad) != num_bytes * 2: raise esptool.FatalError( @@ -385,10 +369,8 @@ def get(self, from_read=True): def save(self, new_value): def print_field(e, new_value): - print( - " - '{}' ({}) {} -> {}".format( - e.name, e.description, e.get_bitstring(), new_value - ) + log.print( + f" - '{e.name}' ({e.description}) {e.get_bitstring()} -> {new_value}" ) if self.name == "CUSTOM_MAC": @@ -399,14 +381,14 @@ def print_field(e, new_value): # Writing the BLOCK1 (MAC_SPI_8M_0) default MAC is not possible, # as it's written in the factory. raise esptool.FatalError(f"Burning {self.name} is not supported") - raise esptool.FatalError("Writing Factory MAC address is not supported") # fmt: off class EfuseKeyPurposeField(EfuseField): KEY_PURPOSES = [ ("USER", 0, None, None, "no_need_rd_protect"), # User purposes (software-only use) - ("RESERVED", 1, None, None, "no_need_rd_protect"), # Reserved + ("ECDSA_KEY", 1, None, "Reverse", "need_rd_protect"), # ECDSA key + ("RESERVED", 2, None, None, "no_need_rd_protect"), # Reserved ("XTS_AES_128_KEY", 4, None, "Reverse", "need_rd_protect"), # XTS_AES_128_KEY (flash/PSRAM encryption) ("HMAC_DOWN_ALL", 5, None, None, "need_rd_protect"), # HMAC Downstream mode ("HMAC_DOWN_JTAG", 6, None, None, "need_rd_protect"), # JTAG soft enable key (uses HMAC Downstream mode) @@ -417,7 +399,6 @@ class EfuseKeyPurposeField(EfuseField): ("SECURE_BOOT_DIGEST2", 11, "DIGEST", None, "no_need_rd_protect"), # SECURE_BOOT_DIGEST2 (Secure Boot key digest) ] # fmt: on - KEY_PURPOSES_NAME = [name[0] for name in KEY_PURPOSES] DIGEST_KEY_PURPOSES = [name[0] for name in KEY_PURPOSES if name[2] == "DIGEST"] @@ -459,7 +440,4 @@ def get_name(self, raw_val): def save(self, new_value): raw_val = int(self.check_format(str(new_value))) - str_new_value = self.get_name(raw_val) - if self.name == "KEY_PURPOSE_5" and str_new_value.startswith("XTS_AES"): - raise esptool.FatalError(f"{self.name} can not have {str_new_value} key due to a hardware bug (please see TRM for more details)") return super(EfuseKeyPurposeField, self).save(raw_val) diff --git a/tools/esptool_py/espefuse/efuse/esp32c5beta3/mem_definition.py b/tools/esptool_py/espefuse/efuse/esp32h21/mem_definition.py similarity index 96% rename from tools/esptool_py/espefuse/efuse/esp32c5beta3/mem_definition.py rename to tools/esptool_py/espefuse/efuse/esp32h21/mem_definition.py index 67ffff60ed..92865e0489 100644 --- a/tools/esptool_py/espefuse/efuse/esp32c5beta3/mem_definition.py +++ b/tools/esptool_py/espefuse/efuse/esp32h21/mem_definition.py @@ -1,6 +1,6 @@ -# This file describes eFuses fields and registers for ESP32-C5 beta3 chip +# This file describes eFuses fields and registers for ESP32-H21 chip # -# SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD +# SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD # # SPDX-License-Identifier: GPL-2.0-or-later @@ -20,7 +20,7 @@ class EfuseDefineRegisters(EfuseRegistersBase): EFUSE_MEM_SIZE = 0x01FC + 4 # EFUSE registers & command/conf values - DR_REG_EFUSE_BASE = 0x600B0800 + DR_REG_EFUSE_BASE = 0x600B4000 EFUSE_PGM_DATA0_REG = DR_REG_EFUSE_BASE EFUSE_CHECK_VALUE0_REG = DR_REG_EFUSE_BASE + 0x020 EFUSE_CLK_REG = DR_REG_EFUSE_BASE + 0x1C8 @@ -114,12 +114,8 @@ class EfuseDefineFields(EfuseFieldsBase): def __init__(self, extend_efuse_table) -> None: # List of efuse fields from TRM the chapter eFuse Controller. self.EFUSES = [] - self.KEYBLOCKS = [] - - # if BLK_VERSION_MINOR is 1, these efuse fields are in BLOCK2 self.BLOCK2_CALIBRATION_EFUSES = [] - self.CALC = [] dir_name = os.path.dirname(os.path.abspath(__file__)) diff --git a/tools/esptool_py/espefuse/efuse/esp32h21/operations.py b/tools/esptool_py/espefuse/efuse/esp32h21/operations.py new file mode 100644 index 0000000000..89de347953 --- /dev/null +++ b/tools/esptool_py/espefuse/efuse/esp32h21/operations.py @@ -0,0 +1,313 @@ +# This file includes the operations with eFuses for ESP32-H21 chip +# +# SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD +# +# SPDX-License-Identifier: GPL-2.0-or-later + +from io import IOBase +from typing import BinaryIO +from esptool.logger import log +import rich_click as click + +import espsecure +import esptool + +from . import fields +from .mem_definition import EfuseDefineBlocks +from .. import util +from ..base_operations import ( + BaseCommands, + NonCompositeTuple, + TupleParameter, + add_force_write_always, + add_show_sensitive_info_option, + protect_options, +) + + +class ESP32H21Commands(BaseCommands): + CHIP_NAME = "ESP32-H21" + efuse_lib = fields.EspEfuses + + ################################### CLI definitions ################################### + + def add_cli_commands(self, cli: click.Group): + super().add_cli_commands(cli) + blocks_for_keys = EfuseDefineBlocks().get_blocks_for_keys() + + @cli.command( + "burn-key", + help="Burn the key block with the specified name. Arguments are groups of block name, " + "key file (containing 256 bits of binary key data) and key purpose.\n\n" + f"Block is one of: [{', '.join(blocks_for_keys)}]\n\n" + f"Key purpose is one of: [{', '.join(fields.EfuseKeyPurposeField.KEY_PURPOSES_NAME)}]", + ) + @click.argument( + "block_keyfile_keypurpose", + metavar=" ", + cls=TupleParameter, + required=True, + nargs=-1, + max_arity=len(blocks_for_keys), + type=NonCompositeTuple( + [ + click.Choice(blocks_for_keys), + click.File("rb"), + click.Choice(fields.EfuseKeyPurposeField.KEY_PURPOSES_NAME), + ] + ), + ) + @protect_options + @add_force_write_always + @add_show_sensitive_info_option + @click.pass_context + def burn_key_cli(ctx, **kwargs): + kwargs.pop("force_write_always") + block, keyfile, keypurpose = zip(*kwargs.pop("block_keyfile_keypurpose")) + kwargs["show_sensitive_info"] = ctx.show_sensitive_info + self.burn_key(block, keyfile, keypurpose, **kwargs) + + @cli.command( + "burn-key-digest", + short_help="Parse a RSA public key and burn the digest.", + help="Parse a RSA public key and burn the digest to key eFuse block.\n\n" + f"Block is one of: [{', '.join(blocks_for_keys)}]\n\n" + f"Key purpose is one of: [{', '.join(fields.EfuseKeyPurposeField.DIGEST_KEY_PURPOSES)}]", + ) + @click.argument( + "block_keyfile_keypurpose", + metavar=" ", + cls=TupleParameter, + required=True, + nargs=-1, + max_arity=len(blocks_for_keys), + type=NonCompositeTuple( + [ + click.Choice(blocks_for_keys), + click.File("rb"), + click.Choice(fields.EfuseKeyPurposeField.DIGEST_KEY_PURPOSES), + ] + ), + ) + @protect_options + @add_force_write_always + @add_show_sensitive_info_option + @click.pass_context + def burn_key_digest_cli(ctx, **kwargs): + kwargs.pop("force_write_always") + block, keyfile, keypurpose = zip(*kwargs.pop("block_keyfile_keypurpose")) + kwargs["show_sensitive_info"] = ctx.show_sensitive_info + self.burn_key_digest(block, keyfile, keypurpose, **kwargs) + + ###################################### Commands ###################################### + + def adc_info(self): + # TODO: [ESP32H21] IDF-11506 + log.print("Not supported yet.") + + def burn_key( + self, + blocks: list[str], + keyfiles: list[BinaryIO], + keypurposes: list[str], + no_write_protect: bool = False, + no_read_protect: bool = False, + show_sensitive_info: bool = False, + digest: list[bytes] | None = None, + ): + """Burn the key block with the specified name. Arguments are groups of block name, + key file (containing 256 bits of binary key data) and key purpose. + + Args: + blocks: List of eFuse block names to burn keys to. + keyfiles: List of open files to read key data from. + keypurposes: List of key purposes to burn. + no_write_protect: If True, the write protection will NOT be enabled. + no_read_protect: If True, the read protection will NOT be enabled. + show_sensitive_info: If True, the sensitive information will be shown. + digest: List of digests to burn. + """ + datafile_list: list[BinaryIO] | list[bytes] + if digest is None: + datafile_list = keyfiles[ + 0 : len([name for name in keyfiles if name is not None]) : + ] + else: + datafile_list = digest[ + 0 : len([name for name in digest if name is not None]) : + ] + block_name_list = blocks[ + 0 : len([name for name in blocks if name is not None]) : + ] + keypurpose_list = keypurposes[ + 0 : len([name for name in keypurposes if name is not None]) : + ] + + util.check_duplicate_name_in_list(block_name_list) + if len(block_name_list) != len(datafile_list) or len(block_name_list) != len( + keypurpose_list + ): + raise esptool.FatalError( + f"The number of blocks ({len(block_name_list)}), datafile ({len(datafile_list)}) " + f"and keypurpose ({len(keypurpose_list)}) should be the same." + ) + + log.print("Burn keys to blocks:") + for block_name, datafile, keypurpose in zip( + block_name_list, datafile_list, keypurpose_list + ): + efuse = None + for block in self.efuses.blocks: + if block_name == block.name or block_name in block.alias: + efuse = self.efuses[block.name] + if efuse is None: + raise esptool.FatalError(f"Unknown block name - {block_name}.") + num_bytes = efuse.bit_len // 8 + + block_num = self.efuses.get_index_block_by_name(block_name) + block = self.efuses.blocks[block_num] + + if isinstance(datafile, IOBase): + if keypurpose == "ECDSA_KEY": + sk = espsecure.load_ecdsa_signing_key(datafile) # type: ignore + data = espsecure.get_ecdsa_signing_key_raw_bytes(sk) + if len(data) == 24: + # the private key is 24 bytes long for NIST192p, add 8 bytes of padding + data = b"\x00" * 8 + data + else: + data = datafile.read() + datafile.close() + else: + data = datafile + + log.print(f" - {efuse.name}", end=" ") + revers_msg = None + if self.efuses[block.key_purpose_name].need_reverse(keypurpose): + revers_msg = ( + f"\tReversing byte order for {keypurpose} hardware peripheral..." + ) + data = data[::-1] + log.print( + "-> [{}]".format( + util.hexify(data, " ") + if show_sensitive_info + else " ".join(["??"] * len(data)) + ) + ) + if revers_msg: + log.print(revers_msg) + if len(data) != num_bytes: + raise esptool.FatalError( + f"Incorrect key file size {len(data)}. Key file must be {num_bytes}" + f" bytes ({num_bytes * 8} bits) of raw binary key data." + ) + + if self.efuses[block.key_purpose_name].need_rd_protect(keypurpose): + read_protect = False if no_read_protect else True + else: + read_protect = False + write_protect = not no_write_protect + + # using eFuse instead of a block gives the advantage of checking it as the whole field. + efuse.save(data) + + disable_wr_protect_key_purpose = False + if self.efuses[block.key_purpose_name].get() != keypurpose: + if self.efuses[block.key_purpose_name].is_writeable(): + log.print( + f"\t'{block.key_purpose_name}': " + f"'{self.efuses[block.key_purpose_name].get()}' -> '{keypurpose}'." + ) + self.efuses[block.key_purpose_name].save(keypurpose) + disable_wr_protect_key_purpose = True + else: + raise esptool.FatalError( + f"It is not possible to change '{block.key_purpose_name}' " + f"to '{keypurpose}' because write protection bit is set." + ) + else: + log.print(f"\t'{block.key_purpose_name}' is already '{keypurpose}'.") + if self.efuses[block.key_purpose_name].is_writeable(): + disable_wr_protect_key_purpose = True + + if keypurpose == "ECDSA_KEY": + if self.efuses["ECDSA_FORCE_USE_HARDWARE_K"].get() == 0: + # For ECDSA key purpose block permanently enable + # the hardware TRNG supplied k mode (most secure mode) + log.print("\tECDSA_FORCE_USE_HARDWARE_K: 0 -> 1") + self.efuses["ECDSA_FORCE_USE_HARDWARE_K"].save(1) + else: + log.print("\tECDSA_FORCE_USE_HARDWARE_K is already '1'") + + if disable_wr_protect_key_purpose: + log.print(f"\tDisabling write to '{block.key_purpose_name}'...") + self.efuses[block.key_purpose_name].disable_write() + + if read_protect: + log.print("\tDisabling read to key block...") + efuse.disable_read() + + if write_protect: + log.print("\tDisabling write to key block...") + efuse.disable_write() + log.print("") + + if not write_protect: + log.print("Keys will remain writeable (due to --no-write-protect).") + if no_read_protect: + log.print("Keys will remain readable (due to --no-read-protect).") + + if not self.efuses.burn_all(check_batch_mode=True): + return + log.print("Successful.") + + def burn_key_digest( + self, + blocks: list[str], + keyfiles: list[BinaryIO], + keypurposes: list[str], + no_write_protect: bool = False, + no_read_protect: bool = False, + show_sensitive_info: bool = False, + ): + """Parse a RSA public key and burn the digest to key eFuse block. + + Args: + blocks: List of eFuse block names to burn keys to. + keyfiles: List of open files to read key data from. + keypurposes: List of key purposes to burn. + no_write_protect: If True, the write protection will NOT be enabled. + no_read_protect: If True, the read protection will NOT be enabled. + show_sensitive_info: If True, the sensitive information will be shown. + """ + digest_list = [] + datafile_list = keyfiles[ + 0 : len([name for name in keyfiles if name is not None]) : + ] + block_list = blocks[0 : len([block for block in blocks if block is not None]) :] + + for block_name, datafile in zip(block_list, datafile_list): + efuse = None + for block in self.efuses.blocks: + if block_name == block.name or block_name in block.alias: + efuse = self.efuses[block.name] + if efuse is None: + raise esptool.FatalError(f"Unknown block name - {block_name}.") + num_bytes = efuse.bit_len // 8 + digest = espsecure._digest_sbv2_public_key(datafile) + if len(digest) != num_bytes: + raise esptool.FatalError( + f"Incorrect digest size {len(digest)}. Digest must be {num_bytes} " + f"bytes ({num_bytes * 8} bits) of raw binary key data." + ) + digest_list.append(digest) + + self.burn_key( + block_list, + datafile_list, + keypurposes, + no_write_protect, + no_read_protect, + show_sensitive_info, + digest=digest_list, + ) diff --git a/tools/esptool_py/espefuse/efuse/esp32h2beta1/mem_definition.py b/tools/esptool_py/espefuse/efuse/esp32h2beta1/mem_definition.py deleted file mode 100644 index 73bfb370ed..0000000000 --- a/tools/esptool_py/espefuse/efuse/esp32h2beta1/mem_definition.py +++ /dev/null @@ -1,156 +0,0 @@ -# This file describes eFuses fields and registers for ESP32-H2 chip -# -# SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD -# -# SPDX-License-Identifier: GPL-2.0-or-later - -import os - -import yaml - -from ..mem_definition_base import EfuseBlocksBase, EfuseFieldsBase, EfuseRegistersBase -from typing import List - - -class EfuseDefineRegisters(EfuseRegistersBase): - EFUSE_MEM_SIZE = 0x01FC + 4 - - # EFUSE registers & command/conf values - DR_REG_EFUSE_BASE = 0x6001A000 - EFUSE_PGM_DATA0_REG = DR_REG_EFUSE_BASE - EFUSE_CHECK_VALUE0_REG = DR_REG_EFUSE_BASE + 0x020 - EFUSE_CLK_REG = DR_REG_EFUSE_BASE + 0x1C8 - EFUSE_CONF_REG = DR_REG_EFUSE_BASE + 0x1CC - EFUSE_STATUS_REG = DR_REG_EFUSE_BASE + 0x1D0 - EFUSE_CMD_REG = DR_REG_EFUSE_BASE + 0x1D4 - EFUSE_RD_RS_ERR0_REG = DR_REG_EFUSE_BASE + 0x1C0 - EFUSE_RD_RS_ERR1_REG = DR_REG_EFUSE_BASE + 0x1C4 - EFUSE_RD_REPEAT_ERR0_REG = DR_REG_EFUSE_BASE + 0x17C - EFUSE_RD_REPEAT_ERR1_REG = DR_REG_EFUSE_BASE + 0x180 - EFUSE_RD_REPEAT_ERR2_REG = DR_REG_EFUSE_BASE + 0x184 - EFUSE_RD_REPEAT_ERR3_REG = DR_REG_EFUSE_BASE + 0x188 - EFUSE_RD_REPEAT_ERR4_REG = DR_REG_EFUSE_BASE + 0x18C - EFUSE_DAC_CONF_REG = DR_REG_EFUSE_BASE + 0x1E8 - EFUSE_RD_TIM_CONF_REG = DR_REG_EFUSE_BASE + 0x1EC - EFUSE_WR_TIM_CONF1_REG = DR_REG_EFUSE_BASE + 0x1F0 - EFUSE_WR_TIM_CONF2_REG = DR_REG_EFUSE_BASE + 0x1F4 - EFUSE_DATE_REG = DR_REG_EFUSE_BASE + 0x1FC - EFUSE_WRITE_OP_CODE = 0x5A5A - EFUSE_READ_OP_CODE = 0x5AA5 - EFUSE_PGM_CMD_MASK = 0x3 - EFUSE_PGM_CMD = 0x2 - EFUSE_READ_CMD = 0x1 - - BLOCK_ERRORS = [ - # error_reg, err_num_mask, err_num_offs, fail_bit - (EFUSE_RD_REPEAT_ERR0_REG, None, None, None), # BLOCK0 - (EFUSE_RD_RS_ERR0_REG, 0x7, 0, 3), # MAC_SPI_8M_0 - (EFUSE_RD_RS_ERR0_REG, 0x7, 4, 7), # BLOCK_SYS_DATA - (EFUSE_RD_RS_ERR0_REG, 0x7, 8, 11), # BLOCK_USR_DATA - (EFUSE_RD_RS_ERR0_REG, 0x7, 12, 15), # BLOCK_KEY0 - (EFUSE_RD_RS_ERR0_REG, 0x7, 16, 19), # BLOCK_KEY1 - (EFUSE_RD_RS_ERR0_REG, 0x7, 20, 23), # BLOCK_KEY2 - (EFUSE_RD_RS_ERR0_REG, 0x7, 24, 27), # BLOCK_KEY3 - (EFUSE_RD_RS_ERR0_REG, 0x7, 28, 31), # BLOCK_KEY4 - (EFUSE_RD_RS_ERR1_REG, 0x7, 0, 3), # BLOCK_KEY5 - (EFUSE_RD_RS_ERR1_REG, 0x7, 4, 7), # BLOCK_SYS_DATA2 - ] - - # EFUSE_WR_TIM_CONF2_REG - EFUSE_PWR_OFF_NUM_S = 0 - EFUSE_PWR_OFF_NUM_M = 0xFFFF << EFUSE_PWR_OFF_NUM_S - - # EFUSE_WR_TIM_CONF1_REG - EFUSE_PWR_ON_NUM_S = 8 - EFUSE_PWR_ON_NUM_M = 0x0000FFFF << EFUSE_PWR_ON_NUM_S - - # EFUSE_DAC_CONF_REG - EFUSE_DAC_CLK_DIV_S = 0 - EFUSE_DAC_CLK_DIV_M = 0xFF << EFUSE_DAC_CLK_DIV_S - - # EFUSE_DAC_CONF_REG - EFUSE_DAC_NUM_S = 9 - EFUSE_DAC_NUM_M = 0xFF << EFUSE_DAC_NUM_S - - -class EfuseDefineBlocks(EfuseBlocksBase): - __base_rd_regs = EfuseDefineRegisters.DR_REG_EFUSE_BASE - __base_wr_regs = EfuseDefineRegisters.EFUSE_PGM_DATA0_REG - # List of efuse blocks - # fmt: off - BLOCKS = [ - # Name, Alias, Index, Read address, Write address, Write protect bit, Read protect bit, Len, key_purpose - ("BLOCK0", [], 0, __base_rd_regs + 0x02C, __base_wr_regs, None, None, 6, None), - ("MAC_SPI_8M_0", ["BLOCK1"], 1, __base_rd_regs + 0x044, __base_wr_regs, 20, None, 6, None), - ("BLOCK_SYS_DATA", ["BLOCK2"], 2, __base_rd_regs + 0x05C, __base_wr_regs, 21, None, 8, None), - ("BLOCK_USR_DATA", ["BLOCK3"], 3, __base_rd_regs + 0x07C, __base_wr_regs, 22, None, 8, None), - ("BLOCK_KEY0", ["BLOCK4"], 4, __base_rd_regs + 0x09C, __base_wr_regs, 23, 0, 8, "KEY_PURPOSE_0"), - ("BLOCK_KEY1", ["BLOCK5"], 5, __base_rd_regs + 0x0BC, __base_wr_regs, 24, 1, 8, "KEY_PURPOSE_1"), - ("BLOCK_KEY2", ["BLOCK6"], 6, __base_rd_regs + 0x0DC, __base_wr_regs, 25, 2, 8, "KEY_PURPOSE_2"), - ("BLOCK_KEY3", ["BLOCK7"], 7, __base_rd_regs + 0x0FC, __base_wr_regs, 26, 3, 8, "KEY_PURPOSE_3"), - ("BLOCK_KEY4", ["BLOCK8"], 8, __base_rd_regs + 0x11C, __base_wr_regs, 27, 4, 8, "KEY_PURPOSE_4"), - ("BLOCK_KEY5", ["BLOCK9"], 9, __base_rd_regs + 0x13C, __base_wr_regs, 28, 5, 8, "KEY_PURPOSE_5"), - ("BLOCK_SYS_DATA2", ["BLOCK10"], 10, __base_rd_regs + 0x15C, __base_wr_regs, 29, 6, 8, None), - ] - # fmt: on - - def get_burn_block_data_names(self): - list_of_names = [] - for block in self.BLOCKS: - blk = self.get(block) - if blk.name: - list_of_names.append(blk.name) - if blk.alias: - for alias in blk.alias: - list_of_names.append(alias) - return list_of_names - - -class EfuseDefineFields(EfuseFieldsBase): - def __init__(self, extend_efuse_table) -> None: - # List of efuse fields from TRM the chapter eFuse Controller. - self.EFUSES = [] - - self.KEYBLOCKS = [] - - # if BLK_VERSION_MAJOR is 1, these efuse fields are in BLOCK2 - self.BLOCK2_CALIBRATION_EFUSES = [] - - self.CALC: List = [] - - dir_name = os.path.dirname(os.path.abspath(__file__)) - dir_name, file_name = os.path.split(dir_name) - file_name = file_name + ".yaml" - dir_name, _ = os.path.split(dir_name) - efuse_file = os.path.join(dir_name, "efuse_defs", file_name) - efuse_file = efuse_file.replace("esp32h2beta1", "esp32h2") - with open(f"{efuse_file}", "r") as r_file: - e_desc = yaml.safe_load(r_file) - super().__init__(e_desc, extend_efuse_table) - - for i, efuse in enumerate(self.ALL_EFUSES): - if efuse.name in [ - "BLOCK_USR_DATA", - "BLOCK_KEY0", - "BLOCK_KEY1", - "BLOCK_KEY2", - "BLOCK_KEY3", - "BLOCK_KEY4", - "BLOCK_KEY5", - "BLOCK_SYS_DATA2", - ]: - if efuse.name == "BLOCK_USR_DATA": - efuse.bit_len = 256 - efuse.type = "bytes:32" - self.KEYBLOCKS.append(efuse) - self.ALL_EFUSES[i] = None - - elif efuse.category == "calibration": - self.BLOCK2_CALIBRATION_EFUSES.append(efuse) - self.ALL_EFUSES[i] = None - - for efuse in self.ALL_EFUSES: - if efuse is not None: - self.EFUSES.append(efuse) - - self.ALL_EFUSES = [] diff --git a/tools/esptool_py/espefuse/efuse/esp32h2beta1/operations.py b/tools/esptool_py/espefuse/efuse/esp32h2beta1/operations.py deleted file mode 100644 index f884b8aa55..0000000000 --- a/tools/esptool_py/espefuse/efuse/esp32h2beta1/operations.py +++ /dev/null @@ -1,407 +0,0 @@ -# This file includes the operations with eFuses for ESP32-H2 chip -# -# SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD -# -# SPDX-License-Identifier: GPL-2.0-or-later - -import argparse -import os # noqa: F401. It is used in IDF scripts -import traceback - -import espsecure - -import esptool - -from . import fields -from .. import util -from ..base_operations import ( - add_common_commands, - add_force_write_always, - add_show_sensitive_info_option, - burn_bit, - burn_block_data, - burn_efuse, - check_error, - dump, - read_protect_efuse, - summary, - write_protect_efuse, -) - - -def protect_options(p): - p.add_argument( - "--no-write-protect", - help="Disable write-protecting of the key. The key remains writable. " - "(The keys use the RS coding scheme that does not support post-write " - "data changes. Forced write can damage RS encoding bits.) " - "The write-protecting of keypurposes does not depend on the option, " - "it will be set anyway.", - action="store_true", - ) - p.add_argument( - "--no-read-protect", - help="Disable read-protecting of the key. The key remains readable software." - "The key with keypurpose[USER, RESERVED and *_DIGEST] will remain " - "readable anyway. For the rest keypurposes the read-protection will be " - "defined the option (Read-protect by default).", - action="store_true", - ) - - -def add_commands(subparsers, efuses): - add_common_commands(subparsers, efuses) - burn_key = subparsers.add_parser( - "burn_key", help="Burn the key block with the specified name" - ) - protect_options(burn_key) - add_force_write_always(burn_key) - add_show_sensitive_info_option(burn_key) - burn_key.add_argument( - "block", - help="Key block to burn", - action="append", - choices=efuses.BLOCKS_FOR_KEYS, - ) - burn_key.add_argument( - "keyfile", - help="File containing 256 bits of binary key data", - action="append", - type=argparse.FileType("rb"), - ) - burn_key.add_argument( - "keypurpose", - help="Purpose to set.", - action="append", - choices=fields.EfuseKeyPurposeField.KEY_PURPOSES_NAME, - ) - for _ in efuses.BLOCKS_FOR_KEYS: - burn_key.add_argument( - "block", - help="Key block to burn", - nargs="?", - action="append", - metavar="BLOCK", - choices=efuses.BLOCKS_FOR_KEYS, - ) - burn_key.add_argument( - "keyfile", - help="File containing 256 bits of binary key data", - nargs="?", - action="append", - metavar="KEYFILE", - type=argparse.FileType("rb"), - ) - burn_key.add_argument( - "keypurpose", - help="Purpose to set.", - nargs="?", - action="append", - metavar="KEYPURPOSE", - choices=fields.EfuseKeyPurposeField.KEY_PURPOSES_NAME, - ) - - burn_key_digest = subparsers.add_parser( - "burn_key_digest", - help="Parse a RSA public key and burn the digest to key efuse block", - ) - protect_options(burn_key_digest) - add_force_write_always(burn_key_digest) - add_show_sensitive_info_option(burn_key_digest) - burn_key_digest.add_argument( - "block", - help="Key block to burn", - action="append", - choices=efuses.BLOCKS_FOR_KEYS, - ) - burn_key_digest.add_argument( - "keyfile", - help="Key file to digest (PEM format)", - action="append", - type=argparse.FileType("rb"), - ) - burn_key_digest.add_argument( - "keypurpose", - help="Purpose to set.", - action="append", - choices=fields.EfuseKeyPurposeField.DIGEST_KEY_PURPOSES, - ) - for _ in efuses.BLOCKS_FOR_KEYS: - burn_key_digest.add_argument( - "block", - help="Key block to burn", - nargs="?", - action="append", - metavar="BLOCK", - choices=efuses.BLOCKS_FOR_KEYS, - ) - burn_key_digest.add_argument( - "keyfile", - help="Key file to digest (PEM format)", - nargs="?", - action="append", - metavar="KEYFILE", - type=argparse.FileType("rb"), - ) - burn_key_digest.add_argument( - "keypurpose", - help="Purpose to set.", - nargs="?", - action="append", - metavar="KEYPURPOSE", - choices=fields.EfuseKeyPurposeField.DIGEST_KEY_PURPOSES, - ) - - p = subparsers.add_parser( - "set_flash_voltage", - help="Permanently set the internal flash voltage regulator " - "to either 1.8V, 3.3V or OFF. This means GPIO45 can be high or low " - "at reset without changing the flash voltage.", - ) - p.add_argument("voltage", help="Voltage selection", choices=["1.8V", "3.3V", "OFF"]) - - p = subparsers.add_parser( - "burn_custom_mac", help="Burn a 48-bit Custom MAC Address to EFUSE BLOCK3." - ) - p.add_argument( - "mac", - help="Custom MAC Address to burn given in hexadecimal format with bytes " - "separated by colons (e.g. AA:CD:EF:01:02:03).", - type=fields.base_fields.CheckArgValue(efuses, "CUSTOM_MAC"), - ) - add_force_write_always(p) - - p = subparsers.add_parser("get_custom_mac", help="Prints the Custom MAC Address.") - - -def burn_custom_mac(esp, efuses, args): - efuses["CUSTOM_MAC"].save(args.mac) - if not efuses.burn_all(check_batch_mode=True): - return - get_custom_mac(esp, efuses, args) - print("Successful") - - -def get_custom_mac(esp, efuses, args): - print("Custom MAC Address: {}".format(efuses["CUSTOM_MAC"].get())) - - -def set_flash_voltage(esp, efuses, args): - raise esptool.FatalError("set_flash_voltage is not supported!") - - -def adc_info(esp, efuses, args): - print("") - # fmt: off - if efuses["BLK_VERSION_MINOR"].get() == 2: - print("Temperature Sensor Calibration = {}C".format(efuses["TEMP_CALIB"].get())) - print("") - print("ADC1:") - print("AVE_INITCODE_ATTEN0 = ", efuses["ADC1_AVE_INITCODE_ATTEN0"].get()) - print("AVE_INITCODE_ATTEN1 = ", efuses["ADC1_AVE_INITCODE_ATTEN1"].get()) - print("AVE_INITCODE_ATTEN2 = ", efuses["ADC1_AVE_INITCODE_ATTEN2"].get()) - print("AVE_INITCODE_ATTEN3 = ", efuses["ADC1_AVE_INITCODE_ATTEN3"].get()) - print("HI_DOUT_ATTEN0 = ", efuses["ADC1_HI_DOUT_ATTEN0"].get()) - print("HI_DOUT_ATTEN1 = ", efuses["ADC1_HI_DOUT_ATTEN1"].get()) - print("HI_DOUT_ATTEN2 = ", efuses["ADC1_HI_DOUT_ATTEN2"].get()) - print("HI_DOUT_ATTEN3 = ", efuses["ADC1_HI_DOUT_ATTEN3"].get()) - print("CH0_ATTEN0_INITCODE_DIFF = ", efuses["ADC1_CH0_ATTEN0_INITCODE_DIFF"].get()) - print("CH1_ATTEN0_INITCODE_DIFF = ", efuses["ADC1_CH1_ATTEN0_INITCODE_DIFF"].get()) - print("CH2_ATTEN0_INITCODE_DIFF = ", efuses["ADC1_CH2_ATTEN0_INITCODE_DIFF"].get()) - print("CH3_ATTEN0_INITCODE_DIFF = ", efuses["ADC1_CH3_ATTEN0_INITCODE_DIFF"].get()) - print("CH4_ATTEN0_INITCODE_DIFF = ", efuses["ADC1_CH4_ATTEN0_INITCODE_DIFF"].get()) - else: - print("BLK_VERSION_MINOR = {}".format(efuses["BLK_VERSION_MINOR"].get())) - # fmt: on - - -def burn_key(esp, efuses, args, digest=None): - if digest is None: - datafile_list = args.keyfile[ - 0 : len([name for name in args.keyfile if name is not None]) : - ] - else: - datafile_list = digest[0 : len([name for name in digest if name is not None]) :] - efuses.force_write_always = args.force_write_always - block_name_list = args.block[ - 0 : len([name for name in args.block if name is not None]) : - ] - keypurpose_list = args.keypurpose[ - 0 : len([name for name in args.keypurpose if name is not None]) : - ] - - util.check_duplicate_name_in_list(block_name_list) - if len(block_name_list) != len(datafile_list) or len(block_name_list) != len( - keypurpose_list - ): - raise esptool.FatalError( - "The number of blocks (%d), datafile (%d) and keypurpose (%d) " - "should be the same." - % (len(block_name_list), len(datafile_list), len(keypurpose_list)) - ) - - print("Burn keys to blocks:") - for block_name, datafile, keypurpose in zip( - block_name_list, datafile_list, keypurpose_list - ): - efuse = None - for block in efuses.blocks: - if block_name == block.name or block_name in block.alias: - efuse = efuses[block.name] - if efuse is None: - raise esptool.FatalError("Unknown block name - %s" % (block_name)) - num_bytes = efuse.bit_len // 8 - - block_num = efuses.get_index_block_by_name(block_name) - block = efuses.blocks[block_num] - - if digest is None: - data = datafile.read() - else: - data = datafile - - print(" - %s" % (efuse.name), end=" ") - revers_msg = None - if efuses[block.key_purpose_name].need_reverse(keypurpose): - revers_msg = "\tReversing byte order for AES-XTS hardware peripheral" - data = data[::-1] - print( - "-> [{}]".format( - util.hexify(data, " ") - if args.show_sensitive_info - else " ".join(["??"] * len(data)) - ) - ) - if revers_msg: - print(revers_msg) - if len(data) != num_bytes: - raise esptool.FatalError( - "Incorrect key file size %d. Key file must be %d bytes (%d bits) " - "of raw binary key data." % (len(data), num_bytes, num_bytes * 8) - ) - - if efuses[block.key_purpose_name].need_rd_protect(keypurpose): - read_protect = False if args.no_read_protect else True - else: - read_protect = False - write_protect = not args.no_write_protect - - # using efuse instead of a block gives the advantage of checking it as the whole field. - efuse.save(data) - - disable_wr_protect_key_purpose = False - if efuses[block.key_purpose_name].get() != keypurpose: - if efuses[block.key_purpose_name].is_writeable(): - print( - "\t'%s': '%s' -> '%s'." - % ( - block.key_purpose_name, - efuses[block.key_purpose_name].get(), - keypurpose, - ) - ) - efuses[block.key_purpose_name].save(keypurpose) - disable_wr_protect_key_purpose = True - else: - raise esptool.FatalError( - "It is not possible to change '%s' to '%s' because write " - "protection bit is set." % (block.key_purpose_name, keypurpose) - ) - else: - print("\t'%s' is already '%s'." % (block.key_purpose_name, keypurpose)) - if efuses[block.key_purpose_name].is_writeable(): - disable_wr_protect_key_purpose = True - - if disable_wr_protect_key_purpose: - print("\tDisabling write to '%s'." % block.key_purpose_name) - efuses[block.key_purpose_name].disable_write() - - if read_protect: - print("\tDisabling read to key block") - efuse.disable_read() - - if write_protect: - print("\tDisabling write to key block") - efuse.disable_write() - print("") - - if not write_protect: - print("Keys will remain writeable (due to --no-write-protect)") - if args.no_read_protect: - print("Keys will remain readable (due to --no-read-protect)") - - if not efuses.burn_all(check_batch_mode=True): - return - print("Successful") - - -def burn_key_digest(esp, efuses, args): - digest_list = [] - datafile_list = args.keyfile[ - 0 : len([name for name in args.keyfile if name is not None]) : - ] - block_list = args.block[ - 0 : len([block for block in args.block if block is not None]) : - ] - for block_name, datafile in zip(block_list, datafile_list): - efuse = None - for block in efuses.blocks: - if block_name == block.name or block_name in block.alias: - efuse = efuses[block.name] - if efuse is None: - raise esptool.FatalError("Unknown block name - %s" % (block_name)) - num_bytes = efuse.bit_len // 8 - digest = espsecure._digest_sbv2_public_key(datafile) - if len(digest) != num_bytes: - raise esptool.FatalError( - "Incorrect digest size %d. Digest must be %d bytes (%d bits) of raw " - "binary key data." % (len(digest), num_bytes, num_bytes * 8) - ) - digest_list.append(digest) - burn_key(esp, efuses, args, digest=digest_list) - - -def espefuse(esp, efuses, args, command): - parser = argparse.ArgumentParser() - subparsers = parser.add_subparsers(dest="operation") - add_commands(subparsers, efuses) - try: - cmd_line_args = parser.parse_args(command.split()) - except SystemExit: - traceback.print_stack() - raise esptool.FatalError('"{}" - incorrect command'.format(command)) - if cmd_line_args.operation == "execute_scripts": - configfiles = cmd_line_args.configfiles - index = cmd_line_args.index - # copy arguments from args to cmd_line_args - vars(cmd_line_args).update(vars(args)) - if cmd_line_args.operation == "execute_scripts": - cmd_line_args.configfiles = configfiles - cmd_line_args.index = index - if cmd_line_args.operation is None: - parser.print_help() - parser.exit(1) - operation_func = globals()[cmd_line_args.operation] - # each 'operation' is a module-level function of the same name - operation_func(esp, efuses, cmd_line_args) - - -def execute_scripts(esp, efuses, args): - efuses.batch_mode_cnt += 1 - del args.operation - scripts = args.scripts - del args.scripts - - for file in scripts: - with open(file.name, "r") as file: - exec(compile(file.read(), file.name, "exec")) - - if args.debug: - for block in efuses.blocks: - data = block.get_bitstring(from_read=False) - block.print_block(data, "regs_for_burn", args.debug) - - efuses.batch_mode_cnt -= 1 - if not efuses.burn_all(check_batch_mode=True): - return - print("Successful") diff --git a/tools/esptool_py/espefuse/efuse/esp32h2beta1/__init__.py b/tools/esptool_py/espefuse/efuse/esp32h4/__init__.py similarity index 74% rename from tools/esptool_py/espefuse/efuse/esp32h2beta1/__init__.py rename to tools/esptool_py/espefuse/efuse/esp32h4/__init__.py index a3b55a8023..2318517102 100644 --- a/tools/esptool_py/espefuse/efuse/esp32h2beta1/__init__.py +++ b/tools/esptool_py/espefuse/efuse/esp32h4/__init__.py @@ -1,3 +1,5 @@ from . import operations from .emulate_efuse_controller import EmulateEfuseController from .fields import EspEfuses + +commands = operations.ESP32H4Commands diff --git a/tools/esptool_py/espefuse/efuse/esp32h2beta1/emulate_efuse_controller.py b/tools/esptool_py/espefuse/efuse/esp32h4/emulate_efuse_controller.py similarity index 93% rename from tools/esptool_py/espefuse/efuse/esp32h2beta1/emulate_efuse_controller.py rename to tools/esptool_py/espefuse/efuse/esp32h4/emulate_efuse_controller.py index 1c336cbfea..aa468477ad 100644 --- a/tools/esptool_py/espefuse/efuse/esp32h2beta1/emulate_efuse_controller.py +++ b/tools/esptool_py/espefuse/efuse/esp32h4/emulate_efuse_controller.py @@ -1,6 +1,6 @@ -# This file describes eFuses controller for ESP32-H2 chip +# This file describes eFuses controller for ESP32-H4 chip # -# SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD +# SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD # # SPDX-License-Identifier: GPL-2.0-or-later @@ -13,7 +13,7 @@ class EmulateEfuseController(EmulateEfuseControllerBase): """The class for virtual efuse operation. Using for HOST_TEST.""" - CHIP_NAME = "ESP32-H2(beta1)" + CHIP_NAME = "ESP32-H4" mem = None debug = False @@ -33,7 +33,7 @@ def get_minor_chip_version(self): return 0 def get_crystal_freq(self): - return 32 # MHz (common for all chips) + return 32 # MHz def get_security_info(self): return { diff --git a/tools/esptool_py/espefuse/efuse/esp32c5beta3/fields.py b/tools/esptool_py/espefuse/efuse/esp32h4/fields.py similarity index 84% rename from tools/esptool_py/espefuse/efuse/esp32c5beta3/fields.py rename to tools/esptool_py/espefuse/efuse/esp32h4/fields.py index 351d73667a..498acbbac6 100644 --- a/tools/esptool_py/espefuse/efuse/esp32c5beta3/fields.py +++ b/tools/esptool_py/espefuse/efuse/esp32h4/fields.py @@ -1,15 +1,15 @@ -# This file describes eFuses for ESP32-C5 beta3 chip +# This file describes eFuses for ESP32-H4 chip # -# SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD +# SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD # # SPDX-License-Identifier: GPL-2.0-or-later import binascii import struct -import sys import time from bitstring import BitArray +from esptool.logger import log import esptool @@ -55,9 +55,6 @@ class EspEfuses(base_fields.EspEfusesBase): Wrapper object to manage the efuse fields in a connected ESP bootloader """ - debug = False - do_not_confirm = False - def __init__( self, esp, @@ -66,17 +63,15 @@ def __init__( do_not_confirm=False, extend_efuse_table=None, ): + super().__init__(esp, skip_connect, debug, do_not_confirm, extend_efuse_table) self.Blocks = EfuseDefineBlocks() self.Fields = EfuseDefineFields(extend_efuse_table) self.REGS = EfuseDefineRegisters self.BURN_BLOCK_DATA_NAMES = self.Blocks.get_burn_block_data_names() self.BLOCKS_FOR_KEYS = self.Blocks.get_blocks_for_keys() - self._esp = esp - self.debug = debug - self.do_not_confirm = do_not_confirm - if esp.CHIP_NAME != "ESP32-C5(beta3)": + if esp.CHIP_NAME != "ESP32-H4": raise esptool.FatalError( - "Expected the 'esp' param for ESP32-C5(beta3) chip but got for '%s'." + "Expected the 'esp' param for ESP32-H4 chip but got for '%s'." % (esp.CHIP_NAME) ) if not skip_connect: @@ -102,11 +97,11 @@ def __init__( for efuse in self.Fields.BLOCK2_CALIBRATION_EFUSES ] else: - # if self["BLK_VERSION_MINOR"].get() == 1: - # self.efuses += [ - # EfuseField.convert(self, efuse) - # for efuse in self.Fields.BLOCK2_CALIBRATION_EFUSES - # ] + if False: # self["BLK_VERSION_MINOR"].get() == 1: + self.efuses += [ + EfuseField.convert(self, efuse) + for efuse in self.Fields.BLOCK2_CALIBRATION_EFUSES + ] self.efuses += [ EfuseField.convert(self, efuse) for efuse in self.Fields.CALC ] @@ -136,14 +131,14 @@ def read_coding_scheme(self): self.coding_scheme = self.REGS.CODING_SCHEME_RS def print_status_regs(self): - print("") + log.print("") self.blocks[0].print_block(self.blocks[0].err_bitarray, "err__regs", debug=True) - print( + log.print( "{:27} 0x{:08x}".format( "EFUSE_RD_RS_ERR0_REG", self.read_reg(self.REGS.EFUSE_RD_RS_ERR0_REG) ) ) - print( + log.print( "{:27} 0x{:08x}".format( "EFUSE_RD_RS_ERR1_REG", self.read_reg(self.REGS.EFUSE_RD_RS_ERR1_REG) ) @@ -176,7 +171,7 @@ def wait_efuse_idle(self): # For PGM_CMD it is not necessary. return raise esptool.FatalError( - "Timed out waiting for Efuse controller command to complete" + "Timed out waiting for eFuse controller command to complete" ) def efuse_program(self, block): @@ -204,52 +199,43 @@ def efuse_read(self): try: self._esp = self.reconnect_chip(self._esp) except esptool.FatalError: - print("Can not re-connect to the chip") + log.print("Can not re-connect to the chip.") if not self["DIS_DOWNLOAD_MODE"].get() and self[ "DIS_DOWNLOAD_MODE" ].get(from_read=False): - print( + log.print( "This is the correct behavior as we are actually burning " - "DIS_DOWNLOAD_MODE which disables the connection to the chip" + "DIS_DOWNLOAD_MODE which disables the connection to the chip." ) - print("DIS_DOWNLOAD_MODE is enabled") - print("Successful") - sys.exit(0) # finish without errors + log.print("DIS_DOWNLOAD_MODE is enabled.") + log.print("Successful.") + exit(0) # finish without errors raise - print("Established a connection with the chip") + log.print("Established a connection with the chip.") if self._esp.secure_download_mode and not secure_download_mode_before: - print("Secure download mode is enabled") + log.print("Secure download mode is enabled.") if not self["ENABLE_SECURITY_DOWNLOAD"].get() and self[ "ENABLE_SECURITY_DOWNLOAD" ].get(from_read=False): - print( - "espefuse tool can not continue to work in Secure download mode" + log.print( + "espefuse can not continue to work in Secure download mode." ) - print("ENABLE_SECURITY_DOWNLOAD is enabled") - print("Successful") - sys.exit(0) # finish without errors + log.print("ENABLE_SECURITY_DOWNLOAD is enabled.") + log.print("Successful.") + exit(0) # finish without errors raise def set_efuse_timing(self): """Set timing registers for burning efuses""" # Configure clock apb_freq = self.get_crystal_freq() - if apb_freq not in [40, 48]: + if apb_freq != 32: raise esptool.FatalError( - "The eFuse supports only xtal=40M and 48M (xtal was %d)" % apb_freq + "The eFuse supports only xtal=32M (xtal was %d)" % apb_freq ) - self.update_reg(self.REGS.EFUSE_DAC_CONF_REG, self.REGS.EFUSE_DAC_NUM_M, 0xFF) - self.update_reg( - self.REGS.EFUSE_DAC_CONF_REG, self.REGS.EFUSE_DAC_CLK_DIV_M, 0x28 - ) - self.update_reg( - self.REGS.EFUSE_WR_TIM_CONF1_REG, self.REGS.EFUSE_PWR_ON_NUM_M, 0x3000 - ) - self.update_reg( - self.REGS.EFUSE_WR_TIM_CONF2_REG, self.REGS.EFUSE_PWR_OFF_NUM_M, 0x190 - ) + # TODO: [ESP32H4] IDF-12268 def get_coding_scheme_warnings(self, silent=False): """Check if the coding scheme has detected any errors.""" @@ -280,9 +266,9 @@ def get_coding_scheme_warnings(self, silent=False): block.num_errors = (reg_value >> err_num_offs) & err_num_mask ret_fail |= block.fail if not silent and (block.fail or block.num_errors): - print( - "Error(s) in BLOCK%d [ERRORS:%d FAIL:%d]" - % (block.id, block.num_errors, block.fail) + log.print( + f"Error(s) in BLOCK{block.id} " + f"[ERRORS:{block.num_errors} FAIL:{block.fail}]." ) if (self.debug or ret_fail) and not silent: self.print_status_regs() @@ -307,11 +293,8 @@ def convert(parent, efuse): class EfuseWafer(EfuseField): def get(self, from_read=True): - hi_bits = self.parent["WAFER_VERSION_MINOR_HI"].get(from_read) - assert self.parent["WAFER_VERSION_MINOR_HI"].bit_len == 1 - lo_bits = self.parent["WAFER_VERSION_MINOR_LO"].get(from_read) - assert self.parent["WAFER_VERSION_MINOR_LO"].bit_len == 3 - return (hi_bits << 3) + lo_bits + # TODO: [ESP32H4] IDF-12268 + return 0 def save(self, new_value): raise esptool.FatalError("Burning %s is not supported" % self.name) @@ -385,10 +368,8 @@ def get(self, from_read=True): def save(self, new_value): def print_field(e, new_value): - print( - " - '{}' ({}) {} -> {}".format( - e.name, e.description, e.get_bitstring(), new_value - ) + log.print( + f" - '{e.name}' ({e.description}) {e.get_bitstring()} -> {new_value}" ) if self.name == "CUSTOM_MAC": @@ -403,10 +384,12 @@ def print_field(e, new_value): # fmt: off class EfuseKeyPurposeField(EfuseField): + # TODO: [ESP32H4] IDF-12268 need check KEY_PURPOSES = [ ("USER", 0, None, None, "no_need_rd_protect"), # User purposes (software-only use) ("ECDSA_KEY", 1, None, "Reverse", "need_rd_protect"), # ECDSA key - ("RESERVED", 1, None, None, "no_need_rd_protect"), # Reserved + ("XTS_AES_256_KEY_1", 2, None, "Reverse", "need_rd_protect"), # XTS_AES_256_KEY_1 (flash/PSRAM encryption) + ("XTS_AES_256_KEY_2", 3, None, "Reverse", "need_rd_protect"), # XTS_AES_256_KEY_2 (flash/PSRAM encryption) ("XTS_AES_128_KEY", 4, None, "Reverse", "need_rd_protect"), # XTS_AES_128_KEY (flash/PSRAM encryption) ("HMAC_DOWN_ALL", 5, None, None, "need_rd_protect"), # HMAC Downstream mode ("HMAC_DOWN_JTAG", 6, None, None, "need_rd_protect"), # JTAG soft enable key (uses HMAC Downstream mode) @@ -415,8 +398,10 @@ class EfuseKeyPurposeField(EfuseField): ("SECURE_BOOT_DIGEST0", 9, "DIGEST", None, "no_need_rd_protect"), # SECURE_BOOT_DIGEST0 (Secure Boot key digest) ("SECURE_BOOT_DIGEST1", 10, "DIGEST", None, "no_need_rd_protect"), # SECURE_BOOT_DIGEST1 (Secure Boot key digest) ("SECURE_BOOT_DIGEST2", 11, "DIGEST", None, "no_need_rd_protect"), # SECURE_BOOT_DIGEST2 (Secure Boot key digest) + ("KM_INIT_KEY", 12, None, None, "need_rd_protect"), # init key that is used for the generation of AES/ECDSA key ] # fmt: on + KEY_PURPOSES_NAME = [name[0] for name in KEY_PURPOSES] DIGEST_KEY_PURPOSES = [name[0] for name in KEY_PURPOSES if name[2] == "DIGEST"] @@ -458,7 +443,4 @@ def get_name(self, raw_val): def save(self, new_value): raw_val = int(self.check_format(str(new_value))) - str_new_value = self.get_name(raw_val) - if self.name == "KEY_PURPOSE_5" and str_new_value.startswith("XTS_AES"): - raise esptool.FatalError(f"{self.name} can not have {str_new_value} key due to a hardware bug (please see TRM for more details)") return super(EfuseKeyPurposeField, self).save(raw_val) diff --git a/tools/esptool_py/espefuse/efuse/esp32s3beta2/mem_definition.py b/tools/esptool_py/espefuse/efuse/esp32h4/mem_definition.py similarity index 83% rename from tools/esptool_py/espefuse/efuse/esp32s3beta2/mem_definition.py rename to tools/esptool_py/espefuse/efuse/esp32h4/mem_definition.py index 0fb1ec8bad..cd87580938 100644 --- a/tools/esptool_py/espefuse/efuse/esp32s3beta2/mem_definition.py +++ b/tools/esptool_py/espefuse/efuse/esp32h4/mem_definition.py @@ -1,6 +1,6 @@ -# This file describes eFuses fields and registers for ESP32-S3(beta2) chip +# This file describes eFuses fields and registers for ESP32-H4 chip # -# SPDX-FileCopyrightText: 2020-2022 Espressif Systems (Shanghai) CO LTD +# SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD # # SPDX-License-Identifier: GPL-2.0-or-later @@ -17,29 +17,28 @@ class EfuseDefineRegisters(EfuseRegistersBase): - EFUSE_ADDR_MASK = 0x00000FFF EFUSE_MEM_SIZE = 0x01FC + 4 # EFUSE registers & command/conf values - DR_REG_EFUSE_BASE = 0x6001A000 + DR_REG_EFUSE_BASE = 0x600B1800 EFUSE_PGM_DATA0_REG = DR_REG_EFUSE_BASE EFUSE_CHECK_VALUE0_REG = DR_REG_EFUSE_BASE + 0x020 EFUSE_CLK_REG = DR_REG_EFUSE_BASE + 0x1C8 EFUSE_CONF_REG = DR_REG_EFUSE_BASE + 0x1CC - EFUSE_STATUS_REG = DR_REG_EFUSE_BASE + 0x1D0 - EFUSE_CMD_REG = DR_REG_EFUSE_BASE + 0x1D4 - EFUSE_RD_RS_ERR0_REG = DR_REG_EFUSE_BASE + 0x1C0 - EFUSE_RD_RS_ERR1_REG = DR_REG_EFUSE_BASE + 0x1C4 + EFUSE_STATUS_REG = DR_REG_EFUSE_BASE + 0x1D4 + EFUSE_CMD_REG = DR_REG_EFUSE_BASE + 0x1D8 + EFUSE_RD_RS_ERR0_REG = DR_REG_EFUSE_BASE + 0x190 + EFUSE_RD_RS_ERR1_REG = DR_REG_EFUSE_BASE + 0x194 EFUSE_RD_REPEAT_ERR0_REG = DR_REG_EFUSE_BASE + 0x17C EFUSE_RD_REPEAT_ERR1_REG = DR_REG_EFUSE_BASE + 0x180 EFUSE_RD_REPEAT_ERR2_REG = DR_REG_EFUSE_BASE + 0x184 EFUSE_RD_REPEAT_ERR3_REG = DR_REG_EFUSE_BASE + 0x188 EFUSE_RD_REPEAT_ERR4_REG = DR_REG_EFUSE_BASE + 0x18C - EFUSE_DAC_CONF_REG = DR_REG_EFUSE_BASE + 0x1E8 - EFUSE_RD_TIM_CONF_REG = DR_REG_EFUSE_BASE + 0x1EC + EFUSE_DAC_CONF_REG = DR_REG_EFUSE_BASE + 0x1EC + EFUSE_RD_TIM_CONF_REG = DR_REG_EFUSE_BASE + 0x1F0 EFUSE_WR_TIM_CONF1_REG = DR_REG_EFUSE_BASE + 0x1F4 EFUSE_WR_TIM_CONF2_REG = DR_REG_EFUSE_BASE + 0x1F8 - EFUSE_DATE_REG = DR_REG_EFUSE_BASE + 0x1FC + EFUSE_DATE_REG = DR_REG_EFUSE_BASE + 0x198 EFUSE_WRITE_OP_CODE = 0x5A5A EFUSE_READ_OP_CODE = 0x5AA5 EFUSE_PGM_CMD_MASK = 0x3 @@ -84,7 +83,7 @@ class EfuseDefineBlocks(EfuseBlocksBase): # List of efuse blocks # fmt: off BLOCKS = [ - # Name, Alias, Index, Read address, Write address, Write protect bit, Read protect bit, Len, key_purpose + # Name, Alias, Index, Read address, Write address, Write protect bit, Read protect bit, Len, key_purpose ("BLOCK0", [], 0, __base_rd_regs + 0x02C, __base_wr_regs, None, None, 6, None), ("MAC_SPI_8M_0", ["BLOCK1"], 1, __base_rd_regs + 0x044, __base_wr_regs, 20, None, 6, None), ("BLOCK_SYS_DATA", ["BLOCK2"], 2, __base_rd_regs + 0x05C, __base_wr_regs, 21, None, 8, None), @@ -118,7 +117,7 @@ def __init__(self, extend_efuse_table) -> None: self.KEYBLOCKS = [] - # if BLK_VERSION_MAJOR is 1, these efuse fields are in BLOCK2 + # if BLK_VERSION_MINOR is 1, these efuse fields are in BLOCK2 self.BLOCK2_CALIBRATION_EFUSES = [] self.CALC = [] @@ -128,7 +127,6 @@ def __init__(self, extend_efuse_table) -> None: file_name = file_name + ".yaml" dir_name, _ = os.path.split(dir_name) efuse_file = os.path.join(dir_name, "efuse_defs", file_name) - efuse_file = efuse_file.replace("esp32s3beta2", "esp32s3") with open(f"{efuse_file}", "r") as r_file: e_desc = yaml.safe_load(r_file) super().__init__(e_desc, extend_efuse_table) @@ -155,13 +153,13 @@ def __init__(self, extend_efuse_table) -> None: self.ALL_EFUSES[i] = None f = Field() - f.name = "WAFER_VERSION_MINOR" - f.block = 0 - f.bit_len = 4 - f.type = f"uint:{f.bit_len}" - f.category = "identity" - f.class_type = "wafer" - f.description = "calc WAFER VERSION MINOR = WAFER_VERSION_MINOR_HI << 3 + WAFER_VERSION_MINOR_LO (read only)" + f.name = "MAC_EUI64" + f.block = 1 + f.bit_len = 64 + f.type = f"bytes:{f.bit_len // 8}" + f.category = "MAC" + f.class_type = "mac" + f.description = "calc MAC_EUI64 = MAC[0]:MAC[1]:MAC[2]:MAC_EXT[0]:MAC_EXT[1]:MAC[3]:MAC[4]:MAC[5]" self.CALC.append(f) for efuse in self.ALL_EFUSES: diff --git a/tools/esptool_py/espefuse/efuse/esp32h4/operations.py b/tools/esptool_py/espefuse/efuse/esp32h4/operations.py new file mode 100644 index 0000000000..b7d3e7dfcc --- /dev/null +++ b/tools/esptool_py/espefuse/efuse/esp32h4/operations.py @@ -0,0 +1,305 @@ +# This file includes the operations with eFuses for ESP32-H4 chip +# +# SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD +# +# SPDX-License-Identifier: GPL-2.0-or-later + +from io import IOBase +from typing import BinaryIO +from esptool.logger import log +import rich_click as click + +import espsecure +import esptool + +from . import fields +from .mem_definition import EfuseDefineBlocks +from .. import util +from ..base_operations import ( + BaseCommands, + NonCompositeTuple, + TupleParameter, + add_force_write_always, + add_show_sensitive_info_option, + protect_options, +) + + +class ESP32H4Commands(BaseCommands): + CHIP_NAME = "ESP32-H4" + efuse_lib = fields.EspEfuses + + ################################### CLI definitions ################################### + + def add_cli_commands(self, cli: click.Group): + super().add_cli_commands(cli) + blocks_for_keys = EfuseDefineBlocks().get_blocks_for_keys() + + @cli.command( + "burn-key", + help="Burn the key block with the specified name. Arguments are groups of block name, " + "key file (containing 256 bits of binary key data) and key purpose.\n\n" + f"Block is one of: [{', '.join(blocks_for_keys)}]\n\n" + f"Key purpose is one of: [{', '.join(fields.EfuseKeyPurposeField.KEY_PURPOSES_NAME)}]", + ) + @click.argument( + "block_keyfile_keypurpose", + metavar=" ", + cls=TupleParameter, + required=True, + nargs=-1, + max_arity=len(blocks_for_keys), + type=NonCompositeTuple( + [ + click.Choice(blocks_for_keys), + click.File("rb"), + click.Choice(fields.EfuseKeyPurposeField.KEY_PURPOSES_NAME), + ] + ), + ) + @protect_options + @add_force_write_always + @add_show_sensitive_info_option + @click.pass_context + def burn_key_cli(ctx, **kwargs): + """Burn the key block with the specified name""" + kwargs.pop("force_write_always") + block, keyfile, keypurpose = zip(*kwargs.pop("block_keyfile_keypurpose")) + kwargs["show_sensitive_info"] = ctx.show_sensitive_info + self.burn_key(block, keyfile, keypurpose, **kwargs) + + @cli.command( + "burn-key-digest", + short_help="Parse a RSA public key and burn the digest.", + help="Parse a RSA public key and burn the digest to key eFuse block.\n\n" + f"Block is one of: [{', '.join(blocks_for_keys)}]\n\n" + f"Key purpose is one of: [{', '.join(fields.EfuseKeyPurposeField.DIGEST_KEY_PURPOSES)}]", + ) + @click.argument( + "block_keyfile_keypurpose", + metavar=" ", + cls=TupleParameter, + required=True, + nargs=-1, + max_arity=len(blocks_for_keys), + type=NonCompositeTuple( + [ + click.Choice(blocks_for_keys), + click.File("rb"), + click.Choice(fields.EfuseKeyPurposeField.DIGEST_KEY_PURPOSES), + ] + ), + ) + @protect_options + @add_force_write_always + @add_show_sensitive_info_option + @click.pass_context + def burn_key_digest_cli(ctx, **kwargs): + kwargs.pop("force_write_always") + block, keyfile, keypurpose = zip(*kwargs.pop("block_keyfile_keypurpose")) + kwargs["show_sensitive_info"] = ctx.show_sensitive_info + self.burn_key_digest(block, keyfile, keypurpose, **kwargs) + + ###################################### Commands ###################################### + + def adc_info(self): + # TODO: [ESP32H4] Add ADC info support + log.print("Not supported yet.") + + def burn_key( + self, + blocks: list[str], + keyfiles: list[BinaryIO], + keypurposes: list[str], + no_write_protect: bool = False, + no_read_protect: bool = False, + show_sensitive_info: bool = False, + digest: list[bytes] | None = None, + ): + """Burn the key block with the specified name. Arguments are groups of block name, + key file (containing 256 bits of binary key data) and key purpose. + + Args: + blocks: List of eFuse block names to burn keys to. + keyfiles: List of open files to read key data from. + keypurposes: List of key purposes to burn. + no_write_protect: If True, the write protection will NOT be enabled. + no_read_protect: If True, the read protection will NOT be enabled. + show_sensitive_info: If True, the sensitive information will be shown. + digest: List of digests to burn. + """ + datafile_list: list[BinaryIO] | list[bytes] + if digest is None: + datafile_list = keyfiles[ + 0 : len([name for name in keyfiles if name is not None]) : + ] + else: + datafile_list = digest[ + 0 : len([name for name in digest if name is not None]) : + ] + block_name_list = blocks[ + 0 : len([name for name in blocks if name is not None]) : + ] + keypurpose_list = keypurposes[ + 0 : len([name for name in keypurposes if name is not None]) : + ] + + util.check_duplicate_name_in_list(block_name_list) + if len(block_name_list) != len(datafile_list) or len(block_name_list) != len( + keypurpose_list + ): + raise esptool.FatalError( + "The number of blocks (%d), datafile (%d) and keypurpose (%d) should be the same." + % (len(block_name_list), len(datafile_list), len(keypurpose_list)) + ) + + log.print("Burn keys to blocks:") + for block_name, datafile, keypurpose in zip( + block_name_list, datafile_list, keypurpose_list + ): + efuse = None + for block in self.efuses.blocks: + if block_name == block.name or block_name in block.alias: + efuse = self.efuses[block.name] + if efuse is None: + raise esptool.FatalError(f"Unknown block name - {block_name}.") + num_bytes = efuse.bit_len // 8 + + block_num = self.efuses.get_index_block_by_name(block_name) + block = self.efuses.blocks[block_num] + + if isinstance(datafile, IOBase): + if keypurpose == "ECDSA_KEY": + sk = espsecure._load_ecdsa_signing_key(datafile) # type: ignore + data = espsecure.get_ecdsa_signing_key_raw_bytes(sk) + if len(data) == 24: + # the private key is 24 bytes long for NIST192p, and 8 bytes of padding + data = b"\x00" * 8 + data + else: + data = datafile.read() + datafile.close() + else: + data = datafile + + log.print(f" - {efuse.name}", end=" ") + revers_msg = None + if self.efuses[block.key_purpose_name].need_reverse(keypurpose): + revers_msg = ( + f"\tReversing byte order for {keypurpose} hardware peripheral..." + ) + data = data[::-1] + log.print( + "-> [{}]".format( + util.hexify(data, " ") + if show_sensitive_info + else " ".join(["??"] * len(data)) + ) + ) + if revers_msg: + log.print(revers_msg) + if len(data) != num_bytes: + raise esptool.FatalError( + f"Incorrect key file size {len(data)}. Key file must be {num_bytes}" + f" bytes ({num_bytes * 8} bits) of raw binary key data." + ) + + if self.efuses[block.key_purpose_name].need_rd_protect(keypurpose): + read_protect = False if no_read_protect else True + else: + read_protect = False + write_protect = not no_write_protect + + # using eFuse instead of a block gives the advantage of checking it as the whole field. + efuse.save(data) + + disable_wr_protect_key_purpose = False + if self.efuses[block.key_purpose_name].get() != keypurpose: + if self.efuses[block.key_purpose_name].is_writeable(): + log.print( + f"\t'{block.key_purpose_name}': " + f"'{self.efuses[block.key_purpose_name].get()}' -> '{keypurpose}'." + ) + self.efuses[block.key_purpose_name].save(keypurpose) + disable_wr_protect_key_purpose = True + else: + raise esptool.FatalError( + f"It is not possible to change '{block.key_purpose_name}' " + f"to '{keypurpose}' because write protection bit is set." + ) + else: + log.print(f"\t'{block.key_purpose_name}' is already '{keypurpose}'.") + if self.efuses[block.key_purpose_name].is_writeable(): + disable_wr_protect_key_purpose = True + + if disable_wr_protect_key_purpose: + log.print(f"\tDisabling write to '{block.key_purpose_name}'...") + self.efuses[block.key_purpose_name].disable_write() + + if read_protect: + log.print("\tDisabling read to key block...") + efuse.disable_read() + + if write_protect: + log.print("\tDisabling write to key block...") + efuse.disable_write() + log.print("") + + if not write_protect: + log.print("Keys will remain writeable (due to --no-write-protect).") + if no_read_protect: + log.print("Keys will remain readable (due to --no-read-protect).") + + if not self.efuses.burn_all(check_batch_mode=True): + return + log.print("Successful.") + + def burn_key_digest( + self, + blocks: list[str], + keyfiles: list[BinaryIO], + keypurposes: list[str], + no_write_protect: bool = False, + no_read_protect: bool = False, + show_sensitive_info: bool = False, + ): + """Parse a RSA public key and burn the digest to key eFuse block. + + Args: + blocks: List of eFuse block names to burn keys to. + keyfiles: List of open files to read key data from. + keypurposes: List of key purposes to burn. + no_write_protect: If True, the write protection will NOT be enabled. + no_read_protect: If True, the read protection will NOT be enabled. + show_sensitive_info: If True, the sensitive information will be shown. + """ + digest_list = [] + datafile_list = keyfiles[ + 0 : len([name for name in keyfiles if name is not None]) : + ] + block_list = blocks[0 : len([block for block in blocks if block is not None]) :] + + for block_name, datafile in zip(block_list, datafile_list): + efuse = None + for block in self.efuses.blocks: + if block_name == block.name or block_name in block.alias: + efuse = self.efuses[block.name] + if efuse is None: + raise esptool.FatalError(f"Unknown block name - {block_name}.") + num_bytes = efuse.bit_len // 8 + digest = espsecure._digest_sbv2_public_key(datafile) + if len(digest) != num_bytes: + raise esptool.FatalError( + f"Incorrect digest size {len(digest)}. Digest must be {num_bytes} " + f"bytes ({num_bytes * 8} bits) of raw binary key data." + ) + digest_list.append(digest) + + self.burn_key( + block_list, + datafile_list, + keypurposes, + no_write_protect, + no_read_protect, + show_sensitive_info, + digest=digest_list, + ) diff --git a/tools/esptool_py/espefuse/efuse/esp32p4/__init__.py b/tools/esptool_py/espefuse/efuse/esp32p4/__init__.py index a3b55a8023..10143c20ed 100644 --- a/tools/esptool_py/espefuse/efuse/esp32p4/__init__.py +++ b/tools/esptool_py/espefuse/efuse/esp32p4/__init__.py @@ -1,3 +1,5 @@ from . import operations from .emulate_efuse_controller import EmulateEfuseController from .fields import EspEfuses + +commands = operations.ESP32P4Commands diff --git a/tools/esptool_py/espefuse/efuse/esp32p4/fields.py b/tools/esptool_py/espefuse/efuse/esp32p4/fields.py index e28d788dc8..1bbea20185 100644 --- a/tools/esptool_py/espefuse/efuse/esp32p4/fields.py +++ b/tools/esptool_py/espefuse/efuse/esp32p4/fields.py @@ -10,6 +10,7 @@ import time from bitstring import BitArray +from esptool.logger import log import esptool @@ -55,9 +56,6 @@ class EspEfuses(base_fields.EspEfusesBase): Wrapper object to manage the efuse fields in a connected ESP bootloader """ - debug = False - do_not_confirm = False - def __init__( self, esp, @@ -66,14 +64,12 @@ def __init__( do_not_confirm=False, extend_efuse_table=None, ): + super().__init__(esp, skip_connect, debug, do_not_confirm, extend_efuse_table) self.Blocks = EfuseDefineBlocks() self.Fields = EfuseDefineFields(extend_efuse_table) self.REGS = EfuseDefineRegisters self.BURN_BLOCK_DATA_NAMES = self.Blocks.get_burn_block_data_names() self.BLOCKS_FOR_KEYS = self.Blocks.get_blocks_for_keys() - self._esp = esp - self.debug = debug - self.do_not_confirm = do_not_confirm if esp.CHIP_NAME != "ESP32-P4": raise esptool.FatalError( "Expected the 'esp' param for ESP32-P4 chip but got for '%s'." @@ -102,12 +98,11 @@ def __init__( for efuse in self.Fields.BLOCK2_CALIBRATION_EFUSES ] else: - # TODO add processing of self.Fields.BLOCK2_CALIBRATION_EFUSES - # if self["BLK_VERSION_MINOR"].get() == 1: - # self.efuses += [ - # EfuseField.convert(self, efuse) - # for efuse in self.Fields.BLOCK2_CALIBRATION_EFUSES - # ] + if self.get_block_version() >= 1: + self.efuses += [ + EfuseField.convert(self, efuse) + for efuse in self.Fields.BLOCK2_CALIBRATION_EFUSES + ] self.efuses += [ EfuseField.convert(self, efuse) for efuse in self.Fields.CALC ] @@ -137,14 +132,14 @@ def read_coding_scheme(self): self.coding_scheme = self.REGS.CODING_SCHEME_RS def print_status_regs(self): - print("") + log.print("") self.blocks[0].print_block(self.blocks[0].err_bitarray, "err__regs", debug=True) - print( + log.print( "{:27} 0x{:08x}".format( "EFUSE_RD_RS_ERR0_REG", self.read_reg(self.REGS.EFUSE_RD_RS_ERR0_REG) ) ) - print( + log.print( "{:27} 0x{:08x}".format( "EFUSE_RD_RS_ERR1_REG", self.read_reg(self.REGS.EFUSE_RD_RS_ERR1_REG) ) @@ -177,7 +172,7 @@ def wait_efuse_idle(self): # For PGM_CMD it is not necessary. return raise esptool.FatalError( - "Timed out waiting for Efuse controller command to complete" + "Timed out waiting for eFuse controller command to complete" ) def efuse_program(self, block): @@ -205,30 +200,30 @@ def efuse_read(self): try: self._esp = self.reconnect_chip(self._esp) except esptool.FatalError: - print("Can not re-connect to the chip") + log.print("Can not re-connect to the chip.") if not self["DIS_DOWNLOAD_MODE"].get() and self[ "DIS_DOWNLOAD_MODE" ].get(from_read=False): - print( + log.print( "This is the correct behavior as we are actually burning " - "DIS_DOWNLOAD_MODE which disables the connection to the chip" + "DIS_DOWNLOAD_MODE which disables the connection to the chip." ) - print("DIS_DOWNLOAD_MODE is enabled") - print("Successful") + log.print("DIS_DOWNLOAD_MODE is enabled.") + log.print("Successful.") sys.exit(0) # finish without errors raise - print("Established a connection with the chip") + log.print("Established a connection with the chip.") if self._esp.secure_download_mode and not secure_download_mode_before: - print("Secure download mode is enabled") + log.print("Secure download mode is enabled.") if not self["ENABLE_SECURITY_DOWNLOAD"].get() and self[ "ENABLE_SECURITY_DOWNLOAD" ].get(from_read=False): - print( - "espefuse tool can not continue to work in Secure download mode" + log.print( + "espefuse can not continue to work in Secure download mode." ) - print("ENABLE_SECURITY_DOWNLOAD is enabled") - print("Successful") + log.print("ENABLE_SECURITY_DOWNLOAD is enabled.") + log.print("Successful.") sys.exit(0) # finish without errors raise @@ -271,9 +266,9 @@ def get_coding_scheme_warnings(self, silent=False): block.num_errors = (reg_value >> err_num_offs) & err_num_mask ret_fail |= block.fail if not silent and (block.fail or block.num_errors): - print( - "Error(s) in BLOCK%d [ERRORS:%d FAIL:%d]" - % (block.id, block.num_errors, block.fail) + log.print( + f"Error(s) in BLOCK{block.id} " + f"[ERRORS:{block.num_errors} FAIL:{block.fail}]." ) if (self.debug or ret_fail) and not silent: self.print_status_regs() @@ -292,9 +287,22 @@ def convert(parent, efuse): "keypurpose": EfuseKeyPurposeField, "t_sensor": EfuseTempSensor, "adc_tp": EfuseAdcPointCalibration, + "wafer": EfuseWafer, }.get(efuse.class_type, EfuseField)(parent, efuse) +class EfuseWafer(EfuseField): + def get(self, from_read=True): + hi_bits = self.parent["WAFER_VERSION_MAJOR_HI"].get(from_read) + assert self.parent["WAFER_VERSION_MAJOR_HI"].bit_len == 1 + lo_bits = self.parent["WAFER_VERSION_MAJOR_LO"].get(from_read) + assert self.parent["WAFER_VERSION_MAJOR_LO"].bit_len == 2 + return (hi_bits << 2) + lo_bits + + def save(self, new_value): + raise esptool.FatalError(f"Burning {self.name} is not supported") + + class EfuseTempSensor(EfuseField): def get(self, from_read=True): value = self.get_bitstring(from_read) @@ -342,7 +350,7 @@ def check_format(self, new_value_str): def check(self): errs, fail = self.parent.get_block_errors(self.block) if errs != 0 or fail: - output = "Block%d has ERRORS:%d FAIL:%d" % (self.block, errs, fail) + output = f"Block{self.block} has ERRORS:{errs} FAIL:{fail}." else: output = "OK" return "(" + output + ")" @@ -363,10 +371,8 @@ def get(self, from_read=True): def save(self, new_value): def print_field(e, new_value): - print( - " - '{}' ({}) {} -> {}".format( - e.name, e.description, e.get_bitstring(), new_value - ) + log.print( + f" - '{e.name}' ({e.description}) {e.get_bitstring()} -> {new_value}" ) if self.name == "CUSTOM_MAC": @@ -376,7 +382,7 @@ def print_field(e, new_value): else: # Writing the BLOCK1 (MAC_SPI_8M_0) default MAC is not possible, # as it's written in the factory. - raise esptool.FatalError(f"Burning {self.name} is not supported") + raise esptool.FatalError(f"Burning {self.name} is not supported.") # fmt: off @@ -411,9 +417,9 @@ def check_format(self, new_value_str): break if raw_val.isdigit(): if int(raw_val) not in [p[1] for p in self.KEY_PURPOSES if p[1] > 0]: - raise esptool.FatalError("'%s' can not be set (value out of range)" % raw_val) + raise esptool.FatalError(f"'{raw_val}' can not be set (value out of range).") else: - raise esptool.FatalError("'%s' unknown name" % raw_val) + raise esptool.FatalError(f"'{raw_val}' unknown name.") return raw_val def need_reverse(self, new_key_purpose): diff --git a/tools/esptool_py/espefuse/efuse/esp32p4/mem_definition.py b/tools/esptool_py/espefuse/efuse/esp32p4/mem_definition.py index c1427e516a..ebd0c9187b 100644 --- a/tools/esptool_py/espefuse/efuse/esp32p4/mem_definition.py +++ b/tools/esptool_py/espefuse/efuse/esp32p4/mem_definition.py @@ -12,8 +12,8 @@ EfuseBlocksBase, EfuseFieldsBase, EfuseRegistersBase, + Field, ) -from typing import List class EfuseDefineRegisters(EfuseRegistersBase): @@ -114,13 +114,9 @@ class EfuseDefineFields(EfuseFieldsBase): def __init__(self, extend_efuse_table) -> None: # List of efuse fields from TRM the chapter eFuse Controller. self.EFUSES = [] - self.KEYBLOCKS = [] - - # if BLK_VERSION_MINOR is 1, these efuse fields are in BLOCK2 self.BLOCK2_CALIBRATION_EFUSES = [] - - self.CALC: List = [] + self.CALC: list = [] dir_name = os.path.dirname(os.path.abspath(__file__)) dir_name, file_name = os.path.split(dir_name) @@ -152,6 +148,16 @@ def __init__(self, extend_efuse_table) -> None: self.BLOCK2_CALIBRATION_EFUSES.append(efuse) self.ALL_EFUSES[i] = None + f = Field() + f.name = "WAFER_VERSION_MAJOR" + f.block = 0 + f.bit_len = 3 + f.type = f"uint:{f.bit_len}" + f.category = "identity" + f.class_type = "wafer" + f.description = "calc WAFER VERSION MAJOR from (WAFER_VERSION_MAJOR_HI << 2) + WAFER_VERSION_MAJOR_LO (read only)" + self.CALC.append(f) + for efuse in self.ALL_EFUSES: if efuse is not None: self.EFUSES.append(efuse) diff --git a/tools/esptool_py/espefuse/efuse/esp32p4/operations.py b/tools/esptool_py/espefuse/efuse/esp32p4/operations.py index b24a735121..e659f3291a 100644 --- a/tools/esptool_py/espefuse/efuse/esp32p4/operations.py +++ b/tools/esptool_py/espefuse/efuse/esp32p4/operations.py @@ -1,458 +1,318 @@ # This file includes the operations with eFuses for ESP32-P4 chip # -# SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD +# SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD # # SPDX-License-Identifier: GPL-2.0-or-later -import argparse import io -import os # noqa: F401. It is used in IDF scripts -import traceback +from typing import BinaryIO +from esptool.logger import log +import rich_click as click import espsecure - import esptool from . import fields +from .mem_definition import EfuseDefineBlocks from .. import util from ..base_operations import ( - add_common_commands, + BaseCommands, + NonCompositeTuple, + TupleParameter, add_force_write_always, add_show_sensitive_info_option, - burn_bit, - burn_block_data, - burn_efuse, - check_error, - dump, - read_protect_efuse, - summary, - write_protect_efuse, + protect_options, ) -def protect_options(p): - p.add_argument( - "--no-write-protect", - help="Disable write-protecting of the key. The key remains writable. " - "(The keys use the RS coding scheme that does not support " - "post-write data changes. Forced write can damage RS encoding bits.) " - "The write-protecting of keypurposes does not depend on the option, " - "it will be set anyway.", - action="store_true", - ) - p.add_argument( - "--no-read-protect", - help="Disable read-protecting of the key. The key remains readable software." - "The key with keypurpose[USER, RESERVED and *_DIGEST] " - "will remain readable anyway. For the rest keypurposes the read-protection " - "will be defined the option (Read-protect by default).", - action="store_true", - ) +class ESP32P4Commands(BaseCommands): + CHIP_NAME = "ESP32-P4" + efuse_lib = fields.EspEfuses + ################################### CLI definitions ################################### -def add_commands(subparsers, efuses): - add_common_commands(subparsers, efuses) - burn_key = subparsers.add_parser( - "burn_key", help="Burn the key block with the specified name" - ) - protect_options(burn_key) - add_force_write_always(burn_key) - add_show_sensitive_info_option(burn_key) - burn_key.add_argument( - "block", - help="Key block to burn", - action="append", - choices=efuses.BLOCKS_FOR_KEYS, - ) - burn_key.add_argument( - "keyfile", - help="File containing 256 bits of binary key data. For the ECDSA_KEY purpose use PEM file.", - action="append", - type=argparse.FileType("rb"), - ) - burn_key.add_argument( - "keypurpose", - help="Purpose to set.", - action="append", - choices=fields.EfuseKeyPurposeField.KEY_PURPOSES_NAME, - ) - for _ in efuses.BLOCKS_FOR_KEYS: - burn_key.add_argument( - "block", - help="Key block to burn", - nargs="?", - action="append", - metavar="BLOCK", - choices=efuses.BLOCKS_FOR_KEYS, - ) - burn_key.add_argument( - "keyfile", - help="File containing 256 bits of binary key data. For the ECDSA_KEY purpose use PEM file.", - nargs="?", - action="append", - metavar="KEYFILE", - type=argparse.FileType("rb"), - ) - burn_key.add_argument( - "keypurpose", - help="Purpose to set.", - nargs="?", - action="append", - metavar="KEYPURPOSE", - choices=fields.EfuseKeyPurposeField.KEY_PURPOSES_NAME, - ) + def add_cli_commands(self, cli: click.Group): + super().add_cli_commands(cli) + blocks_for_keys = EfuseDefineBlocks().get_blocks_for_keys() - burn_key_digest = subparsers.add_parser( - "burn_key_digest", - help="Parse a RSA public key and burn the digest to key efuse block", - ) - protect_options(burn_key_digest) - add_force_write_always(burn_key_digest) - add_show_sensitive_info_option(burn_key_digest) - burn_key_digest.add_argument( - "block", - help="Key block to burn", - action="append", - choices=efuses.BLOCKS_FOR_KEYS, - ) - burn_key_digest.add_argument( - "keyfile", - help="Key file to digest (PEM format)", - action="append", - type=argparse.FileType("rb"), - ) - burn_key_digest.add_argument( - "keypurpose", - help="Purpose to set.", - action="append", - choices=fields.EfuseKeyPurposeField.DIGEST_KEY_PURPOSES, - ) - for _ in efuses.BLOCKS_FOR_KEYS: - burn_key_digest.add_argument( - "block", - help="Key block to burn", - nargs="?", - action="append", - metavar="BLOCK", - choices=efuses.BLOCKS_FOR_KEYS, + @cli.command( + "burn-key", + short_help="Burn a key to a key eFuse block.", + help="Burn a key to a key eFuse block. Arguments are groups of block name, " + "key file (containing 256 bits of binary key data) and key purpose.\n\n" + f"Block is one of: [{', '.join(blocks_for_keys)}]\n\n" + f"Key purpose is one of: [{', '.join(fields.EfuseKeyPurposeField.KEY_PURPOSES_NAME)}]", ) - burn_key_digest.add_argument( - "keyfile", - help="Key file to digest (PEM format)", - nargs="?", - action="append", - metavar="KEYFILE", - type=argparse.FileType("rb"), + @click.argument( + "block_keyfile_keypurpose", + metavar=" ", + cls=TupleParameter, + required=True, + nargs=-1, + max_arity=len(blocks_for_keys), + type=NonCompositeTuple( + [ + click.Choice(blocks_for_keys), + click.File("rb"), + click.Choice(fields.EfuseKeyPurposeField.KEY_PURPOSES_NAME), + ] + ), ) - burn_key_digest.add_argument( - "keypurpose", - help="Purpose to set.", - nargs="?", - action="append", - metavar="KEYPURPOSE", - choices=fields.EfuseKeyPurposeField.DIGEST_KEY_PURPOSES, + @protect_options + @add_force_write_always + @add_show_sensitive_info_option + @click.pass_context + def burn_key_cli(ctx, **kwargs): + kwargs.pop("force_write_always") + block, keyfile, keypurpose = zip(*kwargs.pop("block_keyfile_keypurpose")) + kwargs["show_sensitive_info"] = ctx.show_sensitive_info + self.burn_key(block, keyfile, keypurpose, **kwargs) + + @cli.command( + "burn-key-digest", + short_help="Burn a digest to a key eFuse block.", + help="Burn a digest to a key eFuse block. Arguments are groups of block name, " + "key file (containing 256 bits of binary key data) and key purpose.\n\n" + f"Block is one of: [{', '.join(blocks_for_keys)}]\n\n" + f"Key purpose is one of: [{', '.join(fields.EfuseKeyPurposeField.DIGEST_KEY_PURPOSES)}]", ) - - p = subparsers.add_parser( - "set_flash_voltage", - help="Permanently set the internal flash voltage regulator " - "to either 1.8V, 3.3V or OFF. " - "This means GPIO45 can be high or low at reset without " - "changing the flash voltage.", - ) - p.add_argument("voltage", help="Voltage selection", choices=["1.8V", "3.3V", "OFF"]) - - p = subparsers.add_parser( - "burn_custom_mac", help="Burn a 48-bit Custom MAC Address to EFUSE BLOCK3." - ) - p.add_argument( - "mac", - help="Custom MAC Address to burn given in hexadecimal format with bytes " - "separated by colons (e.g. AA:CD:EF:01:02:03).", - type=fields.base_fields.CheckArgValue(efuses, "CUSTOM_MAC"), - ) - add_force_write_always(p) - - p = subparsers.add_parser("get_custom_mac", help="Prints the Custom MAC Address.") - - -def burn_custom_mac(esp, efuses, args): - print("Not supported yet") - - -def get_custom_mac(esp, efuses, args): - print("Not supported yet") - - -def set_flash_voltage(esp, efuses, args): - raise esptool.FatalError("set_flash_voltage is not supported!") - - -def adc_info(esp, efuses, args): - print("not supported yet") - - -def key_block_is_unused(block, key_purpose_block): - if not block.is_readable() or not block.is_writeable(): - return False - - if key_purpose_block.get() != "USER" or not key_purpose_block.is_writeable(): - return False - - if not block.get_bitstring().all(False): - return False - - return True - - -def get_next_key_block(efuses, current_key_block, block_name_list): - key_blocks = [b for b in efuses.blocks if b.key_purpose_name] - start = key_blocks.index(current_key_block) - - # Sort key blocks so that we pick the next free block (and loop around if necessary) - key_blocks = key_blocks[start:] + key_blocks[0:start] - - # Exclude any other blocks that will be be burned - key_blocks = [b for b in key_blocks if b.name not in block_name_list] - - for block in key_blocks: - key_purpose_block = efuses[block.key_purpose_name] - if key_block_is_unused(block, key_purpose_block): - return block - - return None - - -def split_512_bit_key(efuses, block_name_list, datafile_list, keypurpose_list): - i = keypurpose_list.index("XTS_AES_256_KEY") - block_name = block_name_list[i] - - block_num = efuses.get_index_block_by_name(block_name) - block = efuses.blocks[block_num] - - data = datafile_list[i].read() - if len(data) != 64: - raise esptool.FatalError( - "Incorrect key file size %d, XTS_AES_256_KEY should be 64 bytes" % len(data) + @click.argument( + "block_keyfile_keypurpose", + metavar=" ", + cls=TupleParameter, + required=True, + nargs=-1, + max_arity=len(blocks_for_keys), + type=NonCompositeTuple( + [ + click.Choice(blocks_for_keys), + click.File("rb"), + click.Choice(fields.EfuseKeyPurposeField.DIGEST_KEY_PURPOSES), + ] + ), ) - - key_block_2 = get_next_key_block(efuses, block, block_name_list) - if not key_block_2: - raise esptool.FatalError("XTS_AES_256_KEY requires two free keyblocks") - - keypurpose_list.append("XTS_AES_256_KEY_1") - datafile_list.append(io.BytesIO(data[:32])) - block_name_list.append(block_name) - - keypurpose_list.append("XTS_AES_256_KEY_2") - datafile_list.append(io.BytesIO(data[32:])) - block_name_list.append(key_block_2.name) - - keypurpose_list.pop(i) - datafile_list.pop(i) - block_name_list.pop(i) - - -def burn_key(esp, efuses, args, digest=None): - if digest is None: - datafile_list = args.keyfile[ - 0 : len([name for name in args.keyfile if name is not None]) : - ] - else: - datafile_list = digest[0 : len([name for name in digest if name is not None]) :] - efuses.force_write_always = args.force_write_always - block_name_list = args.block[ - 0 : len([name for name in args.block if name is not None]) : - ] - keypurpose_list = args.keypurpose[ - 0 : len([name for name in args.keypurpose if name is not None]) : - ] - - if "XTS_AES_256_KEY" in keypurpose_list: - # XTS_AES_256_KEY is not an actual HW key purpose, needs to be split into - # XTS_AES_256_KEY_1 and XTS_AES_256_KEY_2 - split_512_bit_key(efuses, block_name_list, datafile_list, keypurpose_list) - - util.check_duplicate_name_in_list(block_name_list) - if len(block_name_list) != len(datafile_list) or len(block_name_list) != len( - keypurpose_list + @protect_options + @add_force_write_always + @add_show_sensitive_info_option + @click.pass_context + def burn_key_digest_cli(ctx, **kwargs): + kwargs.pop("force_write_always") + block, keyfile, keypurpose = zip(*kwargs.pop("block_keyfile_keypurpose")) + kwargs["show_sensitive_info"] = ctx.show_sensitive_info + self.burn_key_digest(block, keyfile, keypurpose, **kwargs) + + ###################################### Commands ###################################### + + def adc_info(self): + log.print("Block version:", self.efuses.get_block_version()) + if self.efuses.get_block_version() >= 1: + for efuse in self.efuses: + if efuse.category == "calibration": + log.print(f"{efuse.name:<30} = ", self.efuses[efuse.name].get()) + + def burn_key( + self, + blocks: list[str], + keyfiles: list[BinaryIO], + keypurposes: list[str], + no_write_protect: bool = False, + no_read_protect: bool = False, + show_sensitive_info: bool = False, + digest: list[bytes] | None = None, ): - raise esptool.FatalError( - "The number of blocks (%d), datafile (%d) and keypurpose (%d) " - "should be the same." - % (len(block_name_list), len(datafile_list), len(keypurpose_list)) - ) - - print("Burn keys to blocks:") - for block_name, datafile, keypurpose in zip( - block_name_list, datafile_list, keypurpose_list - ): - efuse = None - for block in efuses.blocks: - if block_name == block.name or block_name in block.alias: - efuse = efuses[block.name] - if efuse is None: - raise esptool.FatalError("Unknown block name - %s" % (block_name)) - num_bytes = efuse.bit_len // 8 - - block_num = efuses.get_index_block_by_name(block_name) - block = efuses.blocks[block_num] - + """Burn the key block with the specified name. Arguments are groups of block name, + key file (containing 256 bits of binary key data) and key purpose. + + Args: + blocks: List of eFuse block names to burn keys to. + keyfiles: List of open files to read key data from. + keypurposes: List of key purposes to burn. + no_write_protect: If True, the write protection will NOT be enabled. + no_read_protect: If True, the read protection will NOT be enabled. + show_sensitive_info: If True, the sensitive information will be shown. + digest: List of digests to burn. + """ + datafile_list: list[BinaryIO] | list[bytes] if digest is None: - if keypurpose == "ECDSA_KEY": - sk = espsecure.load_ecdsa_signing_key(datafile) - data = sk.to_string() - if len(data) == 24: - # the private key is 24 bytes long for NIST192p, add 8 bytes of padding - data = b"\x00" * 8 + data - else: - data = datafile.read() + datafile_list = keyfiles[ + 0 : len([name for name in keyfiles if name is not None]) : + ] else: - data = datafile + datafile_list = digest[ + 0 : len([name for name in digest if name is not None]) : + ] + block_name_list = blocks[ + 0 : len([name for name in blocks if name is not None]) : + ] + keypurpose_list = keypurposes[ + 0 : len([name for name in keypurposes if name is not None]) : + ] - print(" - %s" % (efuse.name), end=" ") - revers_msg = None - if efuses[block.key_purpose_name].need_reverse(keypurpose): - revers_msg = f"\tReversing byte order for {keypurpose} hardware peripheral" - data = data[::-1] - print( - "-> [{}]".format( - util.hexify(data, " ") - if args.show_sensitive_info - else " ".join(["??"] * len(data)) + if "XTS_AES_256_KEY" in keypurpose_list: + # XTS_AES_256_KEY is not an actual HW key purpose, needs to be split into + # XTS_AES_256_KEY_1 and XTS_AES_256_KEY_2 + block_name_list, datafile_list, keypurpose_list = self._split_512_bit_key( + block_name_list, + datafile_list, # type: ignore + keypurpose_list, ) - ) - if revers_msg: - print(revers_msg) - if len(data) != num_bytes: + + util.check_duplicate_name_in_list(block_name_list) + if len(block_name_list) != len(datafile_list) or len(block_name_list) != len( + keypurpose_list + ): raise esptool.FatalError( - "Incorrect key file size %d. Key file must be %d bytes (%d bits) " - "of raw binary key data." % (len(data), num_bytes, num_bytes * 8) + "The number of blocks (%d), datafile (%d) and keypurpose (%d) should be the same." + % (len(block_name_list), len(datafile_list), len(keypurpose_list)) ) - if efuses[block.key_purpose_name].need_rd_protect(keypurpose): - read_protect = False if args.no_read_protect else True - else: - read_protect = False - write_protect = not args.no_write_protect + log.print("Burn keys to blocks:") + for block_name, datafile, keypurpose in zip( + block_name_list, datafile_list, keypurpose_list + ): + efuse = None + for block in self.efuses.blocks: + if block_name == block.name or block_name in block.alias: + efuse = self.efuses[block.name] + if efuse is None: + raise esptool.FatalError(f"Unknown block name - {block_name}.") + num_bytes = efuse.bit_len // 8 + + block_num = self.efuses.get_index_block_by_name(block_name) + block = self.efuses.blocks[block_num] + + if isinstance(datafile, io.IOBase): + if keypurpose == "ECDSA_KEY": + sk = espsecure.load_ecdsa_signing_key(datafile) # type: ignore + data = espsecure.get_ecdsa_signing_key_raw_bytes(sk) + if len(data) == 24: + # the private key is 24 bytes long for NIST192p, add 8 bytes of padding + data = b"\x00" * 8 + data + else: + data = datafile.read() + datafile.close() + else: + data = datafile - # using efuse instead of a block gives the advantage of checking it as the whole field. - efuse.save(data) + log.print(f" - {efuse.name}", end=" ") + revers_msg = None + if self.efuses[block.key_purpose_name].need_reverse(keypurpose): + revers_msg = ( + f"\tReversing byte order for {keypurpose} hardware peripheral..." + ) + data = data[::-1] + log.print( + "-> [{}]".format( + util.hexify(data, " ") + if show_sensitive_info + else " ".join(["??"] * len(data)) + ) + ) + if revers_msg: + log.print(revers_msg) + if len(data) != num_bytes: + raise esptool.FatalError( + f"Incorrect key file size {len(data)}. Key file must be {num_bytes} " + f"bytes ({num_bytes * 8} bits) of raw binary key data." + ) - disable_wr_protect_key_purpose = False - if efuses[block.key_purpose_name].get() != keypurpose: - if efuses[block.key_purpose_name].is_writeable(): - print( - "\t'%s': '%s' -> '%s'." - % ( - block.key_purpose_name, - efuses[block.key_purpose_name].get(), - keypurpose, + if self.efuses[block.key_purpose_name].need_rd_protect(keypurpose): + read_protect = False if no_read_protect else True + else: + read_protect = False + write_protect = not no_write_protect + + # using eFuse instead of a block gives the advantage of checking it as the whole field. + efuse.save(data) + + disable_wr_protect_key_purpose = False + if self.efuses[block.key_purpose_name].get() != keypurpose: + if self.efuses[block.key_purpose_name].is_writeable(): + log.print( + f"\t'{block.key_purpose_name}': " + f"'{self.efuses[block.key_purpose_name].get()}' -> '{keypurpose}'." + ) + self.efuses[block.key_purpose_name].save(keypurpose) + disable_wr_protect_key_purpose = True + else: + raise esptool.FatalError( + f"It is not possible to change '{block.key_purpose_name}' " + f"to '{keypurpose}' because write protection bit is set." ) - ) - efuses[block.key_purpose_name].save(keypurpose) - disable_wr_protect_key_purpose = True else: + log.print(f"\t'{block.key_purpose_name}' is already '{keypurpose}'.") + if self.efuses[block.key_purpose_name].is_writeable(): + disable_wr_protect_key_purpose = True + + if disable_wr_protect_key_purpose: + log.print(f"\tDisabling write to '{block.key_purpose_name}'...") + self.efuses[block.key_purpose_name].disable_write() + + if read_protect: + log.print("\tDisabling read to key block...") + efuse.disable_read() + + if write_protect: + log.print("\tDisabling write to key block...") + efuse.disable_write() + log.print("") + + if not write_protect: + log.print("Keys will remain writeable (due to --no-write-protect).") + if no_read_protect: + log.print("Keys will remain readable (due to --no-read-protect).") + + if not self.efuses.burn_all(check_batch_mode=True): + return + log.print("Successful.") + + def burn_key_digest( + self, + blocks: list[str], + keyfiles: list[BinaryIO], + keypurposes: list[str], + no_write_protect: bool = False, + no_read_protect: bool = False, + show_sensitive_info: bool = False, + ): + """Parse a RSA public key and burn the digest to key eFuse block. + + Args: + blocks: List of eFuse block names to burn keys to. + keyfiles: List of open files to read key data from. + keypurposes: List of key purposes to burn. + no_write_protect: If True, the write protection will NOT be enabled. + no_read_protect: If True, the read protection will NOT be enabled. + show_sensitive_info: If True, the sensitive information will be shown. + """ + digest_list = [] + datafile_list = keyfiles[ + 0 : len([name for name in keyfiles if name is not None]) : + ] + block_list = blocks[0 : len([block for block in blocks if block is not None]) :] + + for block_name, datafile in zip(block_list, datafile_list): + efuse = None + for block in self.efuses.blocks: + if block_name == block.name or block_name in block.alias: + efuse = self.efuses[block.name] + if efuse is None: + raise esptool.FatalError(f"Unknown block name - {block_name}.") + num_bytes = efuse.bit_len // 8 + digest = espsecure._digest_sbv2_public_key(datafile) + if len(digest) != num_bytes: raise esptool.FatalError( - "It is not possible to change '%s' to '%s' " - "because write protection bit is set." - % (block.key_purpose_name, keypurpose) + f"Incorrect digest size {len(digest)}. Digest must be {num_bytes} " + f"bytes ({num_bytes * 8} bits) of raw binary key data." ) - else: - print("\t'%s' is already '%s'." % (block.key_purpose_name, keypurpose)) - if efuses[block.key_purpose_name].is_writeable(): - disable_wr_protect_key_purpose = True - - if disable_wr_protect_key_purpose: - print("\tDisabling write to '%s'." % block.key_purpose_name) - efuses[block.key_purpose_name].disable_write() - - if read_protect: - print("\tDisabling read to key block") - efuse.disable_read() - - if write_protect: - print("\tDisabling write to key block") - efuse.disable_write() - print("") - - if not write_protect: - print("Keys will remain writeable (due to --no-write-protect)") - if args.no_read_protect: - print("Keys will remain readable (due to --no-read-protect)") - - if not efuses.burn_all(check_batch_mode=True): - return - print("Successful") - - -def burn_key_digest(esp, efuses, args): - digest_list = [] - datafile_list = args.keyfile[ - 0 : len([name for name in args.keyfile if name is not None]) : - ] - block_list = args.block[ - 0 : len([block for block in args.block if block is not None]) : - ] - for block_name, datafile in zip(block_list, datafile_list): - efuse = None - for block in efuses.blocks: - if block_name == block.name or block_name in block.alias: - efuse = efuses[block.name] - if efuse is None: - raise esptool.FatalError("Unknown block name - %s" % (block_name)) - num_bytes = efuse.bit_len // 8 - digest = espsecure._digest_sbv2_public_key(datafile) - if len(digest) != num_bytes: - raise esptool.FatalError( - "Incorrect digest size %d. Digest must be %d bytes (%d bits) " - "of raw binary key data." % (len(digest), num_bytes, num_bytes * 8) - ) - digest_list.append(digest) - burn_key(esp, efuses, args, digest=digest_list) - - -def espefuse(esp, efuses, args, command): - parser = argparse.ArgumentParser() - subparsers = parser.add_subparsers(dest="operation") - add_commands(subparsers, efuses) - try: - cmd_line_args = parser.parse_args(command.split()) - except SystemExit: - traceback.print_stack() - raise esptool.FatalError('"{}" - incorrect command'.format(command)) - if cmd_line_args.operation == "execute_scripts": - configfiles = cmd_line_args.configfiles - index = cmd_line_args.index - # copy arguments from args to cmd_line_args - vars(cmd_line_args).update(vars(args)) - if cmd_line_args.operation == "execute_scripts": - cmd_line_args.configfiles = configfiles - cmd_line_args.index = index - if cmd_line_args.operation is None: - parser.print_help() - parser.exit(1) - operation_func = globals()[cmd_line_args.operation] - # each 'operation' is a module-level function of the same name - operation_func(esp, efuses, cmd_line_args) - - -def execute_scripts(esp, efuses, args): - efuses.batch_mode_cnt += 1 - del args.operation - scripts = args.scripts - del args.scripts - - for file in scripts: - with open(file.name, "r") as file: - exec(compile(file.read(), file.name, "exec")) - - if args.debug: - for block in efuses.blocks: - data = block.get_bitstring(from_read=False) - block.print_block(data, "regs_for_burn", args.debug) - - efuses.batch_mode_cnt -= 1 - if not efuses.burn_all(check_batch_mode=True): - return - print("Successful") + digest_list.append(digest) + + self.burn_key( + block_list, + datafile_list, + keypurposes, + no_write_protect, + no_read_protect, + show_sensitive_info, + digest=digest_list, + ) diff --git a/tools/esptool_py/espefuse/efuse/esp32s2/__init__.py b/tools/esptool_py/espefuse/efuse/esp32s2/__init__.py index a3b55a8023..208e35edfd 100644 --- a/tools/esptool_py/espefuse/efuse/esp32s2/__init__.py +++ b/tools/esptool_py/espefuse/efuse/esp32s2/__init__.py @@ -1,3 +1,5 @@ from . import operations from .emulate_efuse_controller import EmulateEfuseController from .fields import EspEfuses + +commands = operations.ESP32S2Commands diff --git a/tools/esptool_py/espefuse/efuse/esp32s2/fields.py b/tools/esptool_py/espefuse/efuse/esp32s2/fields.py index 1339fdb143..d773e76d7a 100644 --- a/tools/esptool_py/espefuse/efuse/esp32s2/fields.py +++ b/tools/esptool_py/espefuse/efuse/esp32s2/fields.py @@ -10,6 +10,7 @@ import time from bitstring import BitArray +from esptool.logger import log import esptool @@ -55,9 +56,6 @@ class EspEfuses(base_fields.EspEfusesBase): Wrapper object to manage the efuse fields in a connected ESP bootloader """ - debug = False - do_not_confirm = False - def __init__( self, esp, @@ -66,14 +64,12 @@ def __init__( do_not_confirm=False, extend_efuse_table=None, ): + super().__init__(esp, skip_connect, debug, do_not_confirm, extend_efuse_table) self.Blocks = EfuseDefineBlocks() self.Fields = EfuseDefineFields(extend_efuse_table) self.REGS = EfuseDefineRegisters self.BURN_BLOCK_DATA_NAMES = self.Blocks.get_burn_block_data_names() self.BLOCKS_FOR_KEYS = self.Blocks.get_blocks_for_keys() - self._esp = esp - self.debug = debug - self.do_not_confirm = do_not_confirm if esp.CHIP_NAME != "ESP32-S2": raise esptool.FatalError( "Expected the 'esp' param for ESP32-S2 chip but got for '%s'." @@ -102,7 +98,7 @@ def __init__( for efuse in self.Fields.BLOCK2_CALIBRATION_EFUSES ] else: - if self["BLK_VERSION_MINOR"].get() == 1: + if self.get_block_version() >= 1: self.efuses += [ EfuseField.convert(self, efuse) for efuse in self.Fields.BLOCK2_CALIBRATION_EFUSES @@ -136,14 +132,14 @@ def read_coding_scheme(self): self.coding_scheme = self.REGS.CODING_SCHEME_RS def print_status_regs(self): - print("") + log.print("") self.blocks[0].print_block(self.blocks[0].err_bitarray, "err__regs", debug=True) - print( + log.print( "{:27} 0x{:08x}".format( "EFUSE_RD_RS_ERR0_REG", self.read_reg(self.REGS.EFUSE_RD_RS_ERR0_REG) ) ) - print( + log.print( "{:27} 0x{:08x}".format( "EFUSE_RD_RS_ERR1_REG", self.read_reg(self.REGS.EFUSE_RD_RS_ERR1_REG) ) @@ -176,7 +172,7 @@ def wait_efuse_idle(self): # For PGM_CMD it is not necessary. return raise esptool.FatalError( - "Timed out waiting for Efuse controller command to complete" + "Timed out waiting for eFuse controller command to complete" ) def efuse_program(self, block): @@ -204,30 +200,30 @@ def efuse_read(self): try: self._esp = self.reconnect_chip(self._esp) except esptool.FatalError: - print("Can not re-connect to the chip") + log.print("Can not re-connect to the chip.") if not self["DIS_DOWNLOAD_MODE"].get() and self[ "DIS_DOWNLOAD_MODE" ].get(from_read=False): - print( + log.print( "This is the correct behavior as we are actually burning " - "DIS_DOWNLOAD_MODE which disables the connection to the chip" + "DIS_DOWNLOAD_MODE which disables the connection to the chip." ) - print("DIS_DOWNLOAD_MODE is enabled") - print("Successful") + log.print("DIS_DOWNLOAD_MODE is enabled.") + log.print("Successful.") sys.exit(0) # finish without errors raise - print("Established a connection with the chip") + log.print("Established a connection with the chip.") if self._esp.secure_download_mode and not secure_download_mode_before: - print("Secure download mode is enabled") + log.print("Secure download mode is enabled.") if not self["ENABLE_SECURITY_DOWNLOAD"].get() and self[ "ENABLE_SECURITY_DOWNLOAD" ].get(from_read=False): - print( - "espefuse tool can not continue to work in Secure download mode" + log.print( + "espefuse can not continue to work in Secure download mode." ) - print("ENABLE_SECURITY_DOWNLOAD is enabled") - print("Successful") + log.print("ENABLE_SECURITY_DOWNLOAD is enabled.") + log.print("Successful.") sys.exit(0) # finish without errors raise @@ -319,9 +315,9 @@ def get_coding_scheme_warnings(self, silent=False): block.num_errors = (reg_value >> err_num_offs) & err_num_mask ret_fail |= block.fail if not silent and (block.fail or block.num_errors): - print( - "Error(s) in BLOCK%d [ERRORS:%d FAIL:%d]" - % (block.id, block.num_errors, block.fail) + log.print( + f"Error(s) in BLOCK{block.id} " + f"[ERRORS:{block.num_errors} FAIL:{block.fail}]." ) if (self.debug or ret_fail) and not silent: self.print_status_regs() @@ -410,7 +406,7 @@ def check_format(self, new_value_str): def check(self): errs, fail = self.parent.get_block_errors(self.block) if errs != 0 or fail: - output = "Block%d has ERRORS:%d FAIL:%d" % (self.block, errs, fail) + output = f"Block{self.block} has ERRORS:{errs} FAIL:{fail}." else: output = "OK" return "(" + output + ")" @@ -424,10 +420,8 @@ def get(self, from_read=True): def save(self, new_value): def print_field(e, new_value): - print( - " - '{}' ({}) {} -> {}".format( - e.name, e.description, e.get_bitstring(), new_value - ) + log.print( + f" - '{e.name}' ({e.description}) {e.get_bitstring()} -> {new_value}" ) if self.name == "CUSTOM_MAC": diff --git a/tools/esptool_py/espefuse/efuse/esp32s2/mem_definition.py b/tools/esptool_py/espefuse/efuse/esp32s2/mem_definition.py index 4799751db9..a5888ba5d5 100644 --- a/tools/esptool_py/espefuse/efuse/esp32s2/mem_definition.py +++ b/tools/esptool_py/espefuse/efuse/esp32s2/mem_definition.py @@ -153,12 +153,8 @@ class EfuseDefineFields(EfuseFieldsBase): def __init__(self, extend_efuse_table) -> None: # List of efuse fields from TRM the chapter eFuse Controller. self.EFUSES = [] - self.KEYBLOCKS = [] - - # if BLK_VERSION_MINOR is 1, these efuse fields are in BLOCK2 self.BLOCK2_CALIBRATION_EFUSES = [] - self.CALC = [] dir_name = os.path.dirname(os.path.abspath(__file__)) diff --git a/tools/esptool_py/espefuse/efuse/esp32s2/operations.py b/tools/esptool_py/espefuse/efuse/esp32s2/operations.py index 3f015e2216..a841b6fda4 100644 --- a/tools/esptool_py/espefuse/efuse/esp32s2/operations.py +++ b/tools/esptool_py/espefuse/efuse/esp32s2/operations.py @@ -1,521 +1,384 @@ # This file includes the operations with eFuses for ESP32S2 chip # -# SPDX-FileCopyrightText: 2020-2022 Espressif Systems (Shanghai) CO LTD +# SPDX-FileCopyrightText: 2020-2025 Espressif Systems (Shanghai) CO LTD # # SPDX-License-Identifier: GPL-2.0-or-later -import argparse import io -import os # noqa: F401. It is used in IDF scripts -import traceback +from typing import BinaryIO +from esptool.logger import log -import espsecure +import rich_click as click +import espsecure import esptool from . import fields +from .mem_definition import EfuseDefineBlocks from .. import util from ..base_operations import ( - add_common_commands, + BaseCommands, + NonCompositeTuple, + TupleParameter, add_force_write_always, add_show_sensitive_info_option, - burn_bit, - burn_block_data, - burn_efuse, - check_error, - dump, - read_protect_efuse, - summary, - write_protect_efuse, + protect_options, ) -def protect_options(p): - p.add_argument( - "--no-write-protect", - help="Disable write-protecting of the key. The key remains writable. " - "(The keys use the RS coding scheme that does not support post-write " - "data changes. Forced write can damage RS encoding bits.) " - "The write-protecting of keypurposes does not depend on the option, " - "it will be set anyway.", - action="store_true", - ) - p.add_argument( - "--no-read-protect", - help="Disable read-protecting of the key. The key remains readable software." - "The key with keypurpose[USER, RESERVED and *_DIGEST] " - "will remain readable anyway. For the rest keypurposes the read-protection " - "will be defined the option (Read-protect by default).", - action="store_true", - ) - - -def add_commands(subparsers, efuses): - add_common_commands(subparsers, efuses) - burn_key = subparsers.add_parser( - "burn_key", help="Burn the key block with the specified name" - ) - protect_options(burn_key) - add_force_write_always(burn_key) - add_show_sensitive_info_option(burn_key) - burn_key.add_argument( - "block", - help="Key block to burn", - action="append", - choices=efuses.BLOCKS_FOR_KEYS, - ) - burn_key.add_argument( - "keyfile", - help="File containing 256 bits of binary key data", - action="append", - type=argparse.FileType("rb"), - ) - burn_key.add_argument( - "keypurpose", - help="Purpose to set.", - action="append", - choices=fields.EfuseKeyPurposeField.KEY_PURPOSES_NAME, - ) - for _ in efuses.BLOCKS_FOR_KEYS: - burn_key.add_argument( - "block", - help="Key block to burn", - nargs="?", - action="append", - metavar="BLOCK", - choices=efuses.BLOCKS_FOR_KEYS, - ) - burn_key.add_argument( - "keyfile", - help="File containing 256 bits of binary key data", - nargs="?", - action="append", - metavar="KEYFILE", - type=argparse.FileType("rb"), - ) - burn_key.add_argument( - "keypurpose", - help="Purpose to set.", - nargs="?", - action="append", - metavar="KEYPURPOSE", - choices=fields.EfuseKeyPurposeField.KEY_PURPOSES_NAME, - ) +class ESP32S2Commands(BaseCommands): + CHIP_NAME = "ESP32-S2" + efuse_lib = fields.EspEfuses - burn_key_digest = subparsers.add_parser( - "burn_key_digest", - help="Parse a RSA public key and burn the digest to key efuse block", - ) - protect_options(burn_key_digest) - add_force_write_always(burn_key_digest) - add_show_sensitive_info_option(burn_key_digest) - burn_key_digest.add_argument( - "block", - help="Key block to burn", - action="append", - choices=efuses.BLOCKS_FOR_KEYS, - ) - burn_key_digest.add_argument( - "keyfile", - help="Key file to digest (PEM format)", - action="append", - type=argparse.FileType("rb"), - ) - burn_key_digest.add_argument( - "keypurpose", - help="Purpose to set.", - action="append", - choices=fields.EfuseKeyPurposeField.DIGEST_KEY_PURPOSES, - ) - for _ in efuses.BLOCKS_FOR_KEYS: - burn_key_digest.add_argument( - "block", - help="Key block to burn", - nargs="?", - action="append", - metavar="BLOCK", - choices=efuses.BLOCKS_FOR_KEYS, - ) - burn_key_digest.add_argument( - "keyfile", - help="Key file to digest (PEM format)", - nargs="?", - action="append", - metavar="KEYFILE", - type=argparse.FileType("rb"), - ) - burn_key_digest.add_argument( - "keypurpose", - help="Purpose to set.", - nargs="?", - action="append", - metavar="KEYPURPOSE", - choices=fields.EfuseKeyPurposeField.DIGEST_KEY_PURPOSES, - ) + ################################### CLI definitions ################################### - p = subparsers.add_parser( - "set_flash_voltage", - help="Permanently set the internal flash voltage regulator " - "to either 1.8V, 3.3V or OFF. " - "This means GPIO45 can be high or low at reset without " - "changing the flash voltage.", - ) - p.add_argument("voltage", help="Voltage selection", choices=["1.8V", "3.3V", "OFF"]) - - p = subparsers.add_parser( - "burn_custom_mac", help="Burn a 48-bit Custom MAC Address to EFUSE BLOCK3." - ) - p.add_argument( - "mac", - help="Custom MAC Address to burn given in hexadecimal format with bytes " - "separated by colons (e.g. AA:CD:EF:01:02:03).", - type=fields.base_fields.CheckArgValue(efuses, "CUSTOM_MAC"), - ) - add_force_write_always(p) - - p = subparsers.add_parser("get_custom_mac", help="Prints the Custom MAC Address.") - - -def burn_custom_mac(esp, efuses, args): - efuses["CUSTOM_MAC"].save(args.mac) - if not efuses.burn_all(check_batch_mode=True): - return - get_custom_mac(esp, efuses, args) - print("Successful") - - -def get_custom_mac(esp, efuses, args): - print("Custom MAC Address: {}".format(efuses["CUSTOM_MAC"].get())) - - -def set_flash_voltage(esp, efuses, args): - sdio_force = efuses["VDD_SPI_FORCE"] - sdio_tieh = efuses["VDD_SPI_TIEH"] - sdio_reg = efuses["VDD_SPI_XPD"] - - # check efuses aren't burned in a way which makes this impossible - if args.voltage == "OFF" and sdio_reg.get() != 0: - raise esptool.FatalError( - "Can't set flash regulator to OFF as VDD_SPI_XPD efuse is already burned" - ) + def add_cli_commands(self, cli: click.Group): + super().add_cli_commands(cli) + blocks_for_keys = EfuseDefineBlocks().get_blocks_for_keys() - if args.voltage == "1.8V" and sdio_tieh.get() != 0: - raise esptool.FatalError( - "Can't set regulator to 1.8V is VDD_SPI_TIEH efuse is already burned" + @cli.command( + "burn-key", + help="Burn the key block with the specified name. Arguments are groups of block name, " + "key file (containing 256 bits of binary key data) and key purpose.\n\n" + f"Block is one of: [{', '.join(blocks_for_keys)}]\n\n" + f"Key purpose is one of: [{', '.join(fields.EfuseKeyPurposeField.KEY_PURPOSES_NAME)}]", ) - - if args.voltage == "OFF": - msg = "Disable internal flash voltage regulator (VDD_SPI). SPI flash will " - "need to be powered from an external source.\n" - "The following efuse is burned: VDD_SPI_FORCE.\n" - "It is possible to later re-enable the internal regulator (%s) " % ( - "to 3.3V" if sdio_tieh.get() != 0 else "to 1.8V or 3.3V" + @click.argument( + "block_keyfile_keypurpose", + metavar=" ", + cls=TupleParameter, + required=True, + nargs=-1, + max_arity=len(blocks_for_keys), + type=NonCompositeTuple( + [ + click.Choice(blocks_for_keys), + click.File("rb"), + click.Choice(fields.EfuseKeyPurposeField.KEY_PURPOSES_NAME), + ] + ), ) - "by burning an additional efuse" - elif args.voltage == "1.8V": - msg = "Set internal flash voltage regulator (VDD_SPI) to 1.8V.\n" - "The following efuses are burned: VDD_SPI_FORCE, VDD_SPI_XPD.\n" - "It is possible to later increase the voltage to 3.3V (permanently) " - "by burning additional efuse VDD_SPI_TIEH" - elif args.voltage == "3.3V": - msg = "Enable internal flash voltage regulator (VDD_SPI) to 3.3V.\n" - "The following efuses are burned: VDD_SPI_FORCE, VDD_SPI_XPD, VDD_SPI_TIEH." - print(msg) - - sdio_force.save(1) # Disable GPIO45 - if args.voltage != "OFF": - sdio_reg.save(1) # Enable internal regulator - if args.voltage == "3.3V": - sdio_tieh.save(1) - print("VDD_SPI setting complete.") - - if not efuses.burn_all(check_batch_mode=True): - return - print("Successful") - - -def adc_info(esp, efuses, args): - print("") - # fmt: off - if efuses["BLK_VERSION_MINOR"].get() == 1: - print("Temperature Sensor Calibration = {}C".format(efuses["TEMP_CALIB"].get())) - print("TADC_CALIB = {}C".format(efuses["ADC_CALIB"].get())) - print("RTCCALIB_V1IDX_A10H = ", efuses["RTCCALIB_V1IDX_A10H"].get()) - print("RTCCALIB_V1IDX_A11H = ", efuses["RTCCALIB_V1IDX_A11H"].get()) - print("RTCCALIB_V1IDX_A12H = ", efuses["RTCCALIB_V1IDX_A12H"].get()) - print("RTCCALIB_V1IDX_A13H = ", efuses["RTCCALIB_V1IDX_A13H"].get()) - print("RTCCALIB_V1IDX_A20H = ", efuses["RTCCALIB_V1IDX_A20H"].get()) - print("RTCCALIB_V1IDX_A21H = ", efuses["RTCCALIB_V1IDX_A21H"].get()) - print("RTCCALIB_V1IDX_A22H = ", efuses["RTCCALIB_V1IDX_A22H"].get()) - print("RTCCALIB_V1IDX_A23H = ", efuses["RTCCALIB_V1IDX_A23H"].get()) - print("RTCCALIB_V1IDX_A10L = ", efuses["RTCCALIB_V1IDX_A10L"].get()) - print("RTCCALIB_V1IDX_A11L = ", efuses["RTCCALIB_V1IDX_A11L"].get()) - print("RTCCALIB_V1IDX_A12L = ", efuses["RTCCALIB_V1IDX_A12L"].get()) - print("RTCCALIB_V1IDX_A13L = ", efuses["RTCCALIB_V1IDX_A13L"].get()) - print("RTCCALIB_V1IDX_A20L = ", efuses["RTCCALIB_V1IDX_A20L"].get()) - print("RTCCALIB_V1IDX_A21L = ", efuses["RTCCALIB_V1IDX_A21L"].get()) - print("RTCCALIB_V1IDX_A22L = ", efuses["RTCCALIB_V1IDX_A22L"].get()) - print("RTCCALIB_V1IDX_A23L = ", efuses["RTCCALIB_V1IDX_A23L"].get()) - else: - print("BLK_VERSION_MINOR = ", efuses["BLK_VERSION_MINOR"].get_meaning()) - # fmt: on - - -def key_block_is_unused(block, key_purpose_block): - if not block.is_readable() or not block.is_writeable(): - return False - - if key_purpose_block.get() != "USER" or not key_purpose_block.is_writeable(): - return False - - if not block.get_bitstring().all(False): - return False - - return True - - -def get_next_key_block(efuses, current_key_block, block_name_list): - key_blocks = [b for b in efuses.blocks if b.key_purpose_name] - start = key_blocks.index(current_key_block) - - # Sort key blocks so that we pick the next free block (and loop around if necessary) - key_blocks = key_blocks[start:] + key_blocks[0:start] - - # Exclude any other blocks that will be be burned - key_blocks = [b for b in key_blocks if b.name not in block_name_list] - - for block in key_blocks: - key_purpose_block = efuses[block.key_purpose_name] - if key_block_is_unused(block, key_purpose_block): - return block - - return None - - -def split_512_bit_key(efuses, block_name_list, datafile_list, keypurpose_list): - i = keypurpose_list.index("XTS_AES_256_KEY") - block_name = block_name_list[i] - - block_num = efuses.get_index_block_by_name(block_name) - block = efuses.blocks[block_num] - - data = datafile_list[i].read() - if len(data) != 64: - raise esptool.FatalError( - "Incorrect key file size %d, XTS_AES_256_KEY should be 64 bytes" % len(data) + @protect_options + @add_force_write_always + @add_show_sensitive_info_option + @click.pass_context + def burn_key_cli(ctx, **kwargs): + kwargs.pop("force_write_always") + block, keyfile, keypurpose = zip(*kwargs.pop("block_keyfile_keypurpose")) + kwargs["show_sensitive_info"] = ctx.show_sensitive_info + self.burn_key(block, keyfile, keypurpose, **kwargs) + + @cli.command( + "burn-key-digest", + help="Burn the key block with the specified name. Arguments are groups of block name, " + "key file (containing 256 bits of binary key data) and key purpose.\n\n" + f"Block is one of: [{', '.join(blocks_for_keys)}]\n\n" + f"Key purpose is one of: [{', '.join(fields.EfuseKeyPurposeField.KEY_PURPOSES_NAME)}]", ) + @click.argument( + "block_keyfile_keypurpose", + metavar=" ", + cls=TupleParameter, + required=True, + nargs=-1, + max_arity=len(blocks_for_keys), + type=NonCompositeTuple( + [ + click.Choice(blocks_for_keys), + click.File("rb"), + click.Choice(fields.EfuseKeyPurposeField.DIGEST_KEY_PURPOSES), + ] + ), + ) + @protect_options + @add_force_write_always + @add_show_sensitive_info_option + @click.pass_context + def burn_key_digest_cli(ctx, **kwargs): + kwargs.pop("force_write_always") + block, keyfile, keypurpose = zip(*kwargs.pop("block_keyfile_keypurpose")) + kwargs["show_sensitive_info"] = ctx.show_sensitive_info + self.burn_key_digest(block, keyfile, keypurpose, **kwargs) + + @cli.command( + "set-flash-voltage", + short_help="Permanently set the internal flash voltage regulator.", + ) + @click.argument("voltage", type=click.Choice(["1.8V", "3.3V", "OFF"])) + def set_flash_voltage_cli(voltage): + """Permanently set the internal flash voltage regulator to either 1.8V, 3.3V or OFF. + This means GPIO45 can be high or low at reset without changing the flash voltage.""" + self.set_flash_voltage(voltage) - key_block_2 = get_next_key_block(efuses, block, block_name_list) - if not key_block_2: - raise esptool.FatalError("XTS_AES_256_KEY requires two free keyblocks") - - keypurpose_list.append("XTS_AES_256_KEY_1") - datafile_list.append(io.BytesIO(data[:32])) - block_name_list.append(block_name) + ###################################### Commands ###################################### - keypurpose_list.append("XTS_AES_256_KEY_2") - datafile_list.append(io.BytesIO(data[32:])) - block_name_list.append(key_block_2.name) + def set_flash_voltage(self, voltage: str): + sdio_force = self.efuses["VDD_SPI_FORCE"] + sdio_tieh = self.efuses["VDD_SPI_TIEH"] + sdio_reg = self.efuses["VDD_SPI_XPD"] - keypurpose_list.pop(i) - datafile_list.pop(i) - block_name_list.pop(i) + # check efuses aren't burned in a way which makes this impossible + if voltage == "OFF" and sdio_reg.get() != 0: + raise esptool.FatalError( + "Can't set flash regulator to OFF as VDD_SPI_XPD eFuse is already burned" + ) + if voltage == "1.8V" and sdio_tieh.get() != 0: + raise esptool.FatalError( + "Can't set regulator to 1.8V is VDD_SPI_TIEH eFuse is already burned" + ) -def burn_key(esp, efuses, args, digest=None): - if digest is None: - datafile_list = args.keyfile[ - 0 : len([name for name in args.keyfile if name is not None]) : - ] - else: - datafile_list = digest[0 : len([name for name in digest if name is not None]) :] - efuses.force_write_always = args.force_write_always - block_name_list = args.block[ - 0 : len([name for name in args.block if name is not None]) : - ] - keypurpose_list = args.keypurpose[ - 0 : len([name for name in args.keypurpose if name is not None]) : - ] - - if "XTS_AES_256_KEY" in keypurpose_list: - # XTS_AES_256_KEY is not an actual HW key purpose, needs to be split into - # XTS_AES_256_KEY_1 and XTS_AES_256_KEY_2 - split_512_bit_key(efuses, block_name_list, datafile_list, keypurpose_list) - - util.check_duplicate_name_in_list(block_name_list) - if len(block_name_list) != len(datafile_list) or len(block_name_list) != len( - keypurpose_list - ): - raise esptool.FatalError( - "The number of blocks (%d), datafile (%d) and keypurpose (%d) " - "should be the same." - % (len(block_name_list), len(datafile_list), len(keypurpose_list)) - ) + if voltage == "OFF": + log.print( + "Disable internal flash voltage regulator (VDD_SPI). " + "SPI flash will need to be powered from an external source.\n" + "The following eFuse is burned: VDD_SPI_FORCE.\n" + "It is possible to later re-enable the internal regulator" + f"{'to 3.3V' if sdio_tieh.get() != 0 else 'to 1.8V or 3.3V'}" + "by burning an additional eFuse" + ) + elif voltage == "1.8V": + log.print( + "Set internal flash voltage regulator (VDD_SPI) to 1.8V.\n" + "The following eFuses are burned: VDD_SPI_FORCE, VDD_SPI_XPD.\n" + "It is possible to later increase the voltage to 3.3V (permanently) " + "by burning additional eFuse VDD_SPI_TIEH" + ) + elif voltage == "3.3V": + log.print( + "Enable internal flash voltage regulator (VDD_SPI) to 3.3V.\n" + "The following eFuses are burned: VDD_SPI_FORCE, VDD_SPI_XPD, VDD_SPI_TIEH." + ) - print("Burn keys to blocks:") - for block_name, datafile, keypurpose in zip( - block_name_list, datafile_list, keypurpose_list + sdio_force.save(1) # Disable GPIO45 + if voltage != "OFF": + sdio_reg.save(1) # Enable internal regulator + if voltage == "3.3V": + sdio_tieh.save(1) + log.print("VDD_SPI setting complete.") + + if not self.efuses.burn_all(check_batch_mode=True): + return + log.print("Successful.") + + def adc_info(self): + log.print("Block version:", self.efuses.get_block_version()) + if self.efuses.get_block_version() >= 1: + # fmt: off + log.print(f"Temperature Sensor Calibration = {self.efuses['TEMP_CALIB'].get()}C") + log.print(f"TADC_CALIB = {self.efuses['ADC_CALIB'].get()}C") + log.print("RTCCALIB_V1IDX_A10H = ", self.efuses["RTCCALIB_V1IDX_A10H"].get()) + log.print("RTCCALIB_V1IDX_A11H = ", self.efuses["RTCCALIB_V1IDX_A11H"].get()) + log.print("RTCCALIB_V1IDX_A12H = ", self.efuses["RTCCALIB_V1IDX_A12H"].get()) + log.print("RTCCALIB_V1IDX_A13H = ", self.efuses["RTCCALIB_V1IDX_A13H"].get()) + log.print("RTCCALIB_V1IDX_A20H = ", self.efuses["RTCCALIB_V1IDX_A20H"].get()) + log.print("RTCCALIB_V1IDX_A21H = ", self.efuses["RTCCALIB_V1IDX_A21H"].get()) + log.print("RTCCALIB_V1IDX_A22H = ", self.efuses["RTCCALIB_V1IDX_A22H"].get()) + log.print("RTCCALIB_V1IDX_A23H = ", self.efuses["RTCCALIB_V1IDX_A23H"].get()) + log.print("RTCCALIB_V1IDX_A10L = ", self.efuses["RTCCALIB_V1IDX_A10L"].get()) + log.print("RTCCALIB_V1IDX_A11L = ", self.efuses["RTCCALIB_V1IDX_A11L"].get()) + log.print("RTCCALIB_V1IDX_A12L = ", self.efuses["RTCCALIB_V1IDX_A12L"].get()) + log.print("RTCCALIB_V1IDX_A13L = ", self.efuses["RTCCALIB_V1IDX_A13L"].get()) + log.print("RTCCALIB_V1IDX_A20L = ", self.efuses["RTCCALIB_V1IDX_A20L"].get()) + log.print("RTCCALIB_V1IDX_A21L = ", self.efuses["RTCCALIB_V1IDX_A21L"].get()) + log.print("RTCCALIB_V1IDX_A22L = ", self.efuses["RTCCALIB_V1IDX_A22L"].get()) + log.print("RTCCALIB_V1IDX_A23L = ", self.efuses["RTCCALIB_V1IDX_A23L"].get()) + # fmt: on + + def burn_key( + self, + blocks: list[str], + keyfiles: list[BinaryIO], + keypurposes: list[str], + no_write_protect: bool = False, + no_read_protect: bool = False, + show_sensitive_info: bool = False, + digest: list[bytes] | None = None, ): - efuse = None - for block in efuses.blocks: - if block_name == block.name or block_name in block.alias: - efuse = efuses[block.name] - if efuse is None: - raise esptool.FatalError("Unknown block name - %s" % (block_name)) - num_bytes = efuse.bit_len // 8 - - block_num = efuses.get_index_block_by_name(block_name) - block = efuses.blocks[block_num] - + """Burn the key block with the specified name. Arguments are groups of block name, + key file (containing 256 bits of binary key data) and key purpose. + + Args: + blocks: List of eFuse block names to burn keys to. + keyfiles: List of open files to read key data from. + keypurposes: List of key purposes to burn. + no_write_protect: If True, the write protection will NOT be enabled. + no_read_protect: If True, the read protection will NOT be enabled. + show_sensitive_info: If True, the sensitive information will be shown. + digest: List of digests to burn. + """ + datafile_list: list[BinaryIO] | list[bytes] if digest is None: - data = datafile.read() + datafile_list = keyfiles[ + 0 : len([name for name in keyfiles if name is not None]) : + ] else: - data = datafile - - print(" - %s" % (efuse.name), end=" ") - revers_msg = None - if efuses[block.key_purpose_name].need_reverse(keypurpose): - revers_msg = "\tReversing byte order for AES-XTS hardware peripheral" - data = data[::-1] - print( - "-> [{}]".format( - util.hexify(data, " ") - if args.show_sensitive_info - else " ".join(["??"] * len(data)) + datafile_list = digest[ + 0 : len([name for name in digest if name is not None]) : + ] + block_name_list = blocks[ + 0 : len([name for name in blocks if name is not None]) : + ] + keypurpose_list = keypurposes[ + 0 : len([name for name in keypurposes if name is not None]) : + ] + + if "XTS_AES_256_KEY" in keypurpose_list: + # XTS_AES_256_KEY is not an actual HW key purpose, needs to be split into + # XTS_AES_256_KEY_1 and XTS_AES_256_KEY_2 + block_name_list, datafile_list, keypurpose_list = self._split_512_bit_key( + block_name_list, + datafile_list, # type: ignore + keypurpose_list, ) - ) - if revers_msg: - print(revers_msg) - if len(data) != num_bytes: + + util.check_duplicate_name_in_list(block_name_list) + if len(block_name_list) != len(datafile_list) or len(block_name_list) != len( + keypurpose_list + ): raise esptool.FatalError( - "Incorrect key file size %d. Key file must be %d bytes (%d bits) " - "of raw binary key data." % (len(data), num_bytes, num_bytes * 8) + "The number of blocks (%d), datafile (%d) and keypurpose (%d) should be the same." + % (len(block_name_list), len(datafile_list), len(keypurpose_list)) ) - if efuses[block.key_purpose_name].need_rd_protect(keypurpose): - read_protect = False if args.no_read_protect else True - else: - read_protect = False - write_protect = not args.no_write_protect - - # using efuse instead of a block gives the advantage of - # checking it as the whole field. - efuse.save(data) - - disable_wr_protect_key_purpose = False - if efuses[block.key_purpose_name].get() != keypurpose: - if efuses[block.key_purpose_name].is_writeable(): - print( - "\t'%s': '%s' -> '%s'." - % ( - block.key_purpose_name, - efuses[block.key_purpose_name].get(), - keypurpose, - ) + log.print("Burn keys to blocks:") + for block_name, datafile, keypurpose in zip( + block_name_list, datafile_list, keypurpose_list + ): + efuse = None + for block in self.efuses.blocks: + if block_name == block.name or block_name in block.alias: + efuse = self.efuses[block.name] + if efuse is None: + raise esptool.FatalError(f"Unknown block name - {block_name}.") + num_bytes = efuse.bit_len // 8 + + block_num = self.efuses.get_index_block_by_name(block_name) + block = self.efuses.blocks[block_num] + + if isinstance(datafile, io.IOBase): + data = datafile.read() + datafile.close() + else: + data = datafile # type: ignore # this is safe but mypy still complains + + log.print(f" - {efuse.name}", end=" ") + revers_msg = None + if self.efuses[block.key_purpose_name].need_reverse(keypurpose): + revers_msg = "\tReversing byte order for AES-XTS hardware peripheral..." + data = data[::-1] + log.print( + "-> [{}]".format( + util.hexify(data, " ") + if show_sensitive_info + else " ".join(["??"] * len(data)) ) - efuses[block.key_purpose_name].save(keypurpose) - disable_wr_protect_key_purpose = True + ) + if revers_msg: + log.print(revers_msg) + if len(data) != num_bytes: + raise esptool.FatalError( + f"Incorrect key file size {len(data)}. Key file must be {num_bytes} " + f"bytes ({num_bytes * 8} bits) of raw binary key data." + ) + + if self.efuses[block.key_purpose_name].need_rd_protect(keypurpose): + read_protect = False if no_read_protect else True + else: + read_protect = False + write_protect = not no_write_protect + + # using eFuse instead of a block gives the advantage of checking it as the whole field. + efuse.save(data) + + disable_wr_protect_key_purpose = False + if self.efuses[block.key_purpose_name].get() != keypurpose: + if self.efuses[block.key_purpose_name].is_writeable(): + log.print( + f"\t'{block.key_purpose_name}': " + f"'{self.efuses[block.key_purpose_name].get()}' -> '{keypurpose}'." + ) + self.efuses[block.key_purpose_name].save(keypurpose) + disable_wr_protect_key_purpose = True + else: + raise esptool.FatalError( + f"It is not possible to change '{block.key_purpose_name}' " + f"to '{keypurpose}' because write protection bit is set." + ) else: + log.print(f"\t'{block.key_purpose_name}' is already '{keypurpose}'.") + if self.efuses[block.key_purpose_name].is_writeable(): + disable_wr_protect_key_purpose = True + + if disable_wr_protect_key_purpose: + log.print(f"\tDisabling write to '{block.key_purpose_name}'...") + self.efuses[block.key_purpose_name].disable_write() + + if read_protect: + log.print("\tDisabling read to key block...") + efuse.disable_read() + + if write_protect: + log.print("\tDisabling write to key block...") + efuse.disable_write() + log.print("") + + if not write_protect: + log.print("Keys will remain writeable (due to --no-write-protect).") + if no_read_protect: + log.print("Keys will remain readable (due to --no-read-protect).") + + if not self.efuses.burn_all(check_batch_mode=True): + return + log.print("Successful.") + + def burn_key_digest( + self, + blocks: list[str], + keyfiles: list[BinaryIO], + keypurposes: list[str], + no_write_protect: bool = False, + no_read_protect: bool = False, + show_sensitive_info: bool = False, + ): + """Parse a RSA public key and burn the digest to key eFuse block. + + Args: + blocks: List of eFuse block names to burn keys to. + keyfiles: List of open files to read key data from. + keypurposes: List of key purposes to burn. + no_write_protect: If True, the write protection will NOT be enabled. + no_read_protect: If True, the read protection will NOT be enabled. + show_sensitive_info: If True, the sensitive information will be shown. + """ + digest_list = [] + datafile_list = keyfiles[ + 0 : len([name for name in keyfiles if name is not None]) : + ] + block_list = blocks[0 : len([block for block in blocks if block is not None]) :] + + for block_name, datafile in zip(block_list, datafile_list): + efuse = None + for block in self.efuses.blocks: + if block_name == block.name or block_name in block.alias: + efuse = self.efuses[block.name] + if efuse is None: + raise esptool.FatalError(f"Unknown block name - {block_name}.") + num_bytes = efuse.bit_len // 8 + digest = espsecure._digest_sbv2_public_key(datafile) + if len(digest) != num_bytes: raise esptool.FatalError( - "It is not possible to change '%s' to '%s' because " - "write protection bit is set." - % (block.key_purpose_name, keypurpose) + f"Incorrect digest size {len(digest)}. Digest must be {num_bytes} " + f"bytes ({num_bytes * 8} bits) of raw binary key data." ) - else: - print("\t'%s' is already '%s'." % (block.key_purpose_name, keypurpose)) - if efuses[block.key_purpose_name].is_writeable(): - disable_wr_protect_key_purpose = True - - if disable_wr_protect_key_purpose: - print("\tDisabling write to '%s'." % block.key_purpose_name) - efuses[block.key_purpose_name].disable_write() - - if read_protect: - print("\tDisabling read to key block") - efuse.disable_read() - - if write_protect: - print("\tDisabling write to key block") - efuse.disable_write() - print("") - - if not write_protect: - print("Keys will remain writeable (due to --no-write-protect)") - if args.no_read_protect: - print("Keys will remain readable (due to --no-read-protect)") - - if not efuses.burn_all(check_batch_mode=True): - return - print("Successful") - - -def burn_key_digest(esp, efuses, args): - digest_list = [] - datafile_list = args.keyfile[ - 0 : len([name for name in args.keyfile if name is not None]) : - ] - block_list = args.block[ - 0 : len([block for block in args.block if block is not None]) : - ] - for block_name, datafile in zip(block_list, datafile_list): - efuse = None - for block in efuses.blocks: - if block_name == block.name or block_name in block.alias: - efuse = efuses[block.name] - if efuse is None: - raise esptool.FatalError("Unknown block name - %s" % (block_name)) - num_bytes = efuse.bit_len // 8 - digest = espsecure._digest_sbv2_public_key(datafile) - if len(digest) != num_bytes: - raise esptool.FatalError( - "Incorrect digest size %d. Digest must be %d bytes (%d bits) of raw " - "binary key data." % (len(digest), num_bytes, num_bytes * 8) - ) - digest_list.append(digest) - burn_key(esp, efuses, args, digest=digest_list) - - -def espefuse(esp, efuses, args, command): - parser = argparse.ArgumentParser() - subparsers = parser.add_subparsers(dest="operation") - add_commands(subparsers, efuses) - try: - cmd_line_args = parser.parse_args(command.split()) - except SystemExit: - traceback.print_stack() - raise esptool.FatalError('"{}" - incorrect command'.format(command)) - if cmd_line_args.operation == "execute_scripts": - configfiles = cmd_line_args.configfiles - index = cmd_line_args.index - # copy arguments from args to cmd_line_args - vars(cmd_line_args).update(vars(args)) - if cmd_line_args.operation == "execute_scripts": - cmd_line_args.configfiles = configfiles - cmd_line_args.index = index - if cmd_line_args.operation is None: - parser.print_help() - parser.exit(1) - operation_func = globals()[cmd_line_args.operation] - # each 'operation' is a module-level function of the same name - operation_func(esp, efuses, cmd_line_args) - - -def execute_scripts(esp, efuses, args): - efuses.batch_mode_cnt += 1 - del args.operation - scripts = args.scripts - del args.scripts - - for file in scripts: - with open(file.name, "r") as file: - exec(compile(file.read(), file.name, "exec")) - - if args.debug: - for block in efuses.blocks: - data = block.get_bitstring(from_read=False) - block.print_block(data, "regs_for_burn", args.debug) - - efuses.batch_mode_cnt -= 1 - if not efuses.burn_all(check_batch_mode=True): - return - print("Successful") + digest_list.append(digest) + + self.burn_key( + block_list, + datafile_list, + keypurposes, + no_write_protect, + no_read_protect, + show_sensitive_info, + digest=digest_list, + ) diff --git a/tools/esptool_py/espefuse/efuse/esp32s3/__init__.py b/tools/esptool_py/espefuse/efuse/esp32s3/__init__.py index a3b55a8023..3f3d435552 100644 --- a/tools/esptool_py/espefuse/efuse/esp32s3/__init__.py +++ b/tools/esptool_py/espefuse/efuse/esp32s3/__init__.py @@ -1,3 +1,5 @@ from . import operations from .emulate_efuse_controller import EmulateEfuseController from .fields import EspEfuses + +commands = operations.ESP32S3Commands diff --git a/tools/esptool_py/espefuse/efuse/esp32s3/fields.py b/tools/esptool_py/espefuse/efuse/esp32s3/fields.py index 9bb4eeaf30..07c4f19899 100644 --- a/tools/esptool_py/espefuse/efuse/esp32s3/fields.py +++ b/tools/esptool_py/espefuse/efuse/esp32s3/fields.py @@ -10,6 +10,7 @@ import time from bitstring import BitArray +from esptool.logger import log import esptool @@ -55,9 +56,6 @@ class EspEfuses(base_fields.EspEfusesBase): Wrapper object to manage the efuse fields in a connected ESP bootloader """ - debug = False - do_not_confirm = False - def __init__( self, esp, @@ -66,14 +64,12 @@ def __init__( do_not_confirm=False, extend_efuse_table=None, ): + super().__init__(esp, skip_connect, debug, do_not_confirm, extend_efuse_table) self.Blocks = EfuseDefineBlocks() self.Fields = EfuseDefineFields(extend_efuse_table) self.REGS = EfuseDefineRegisters self.BURN_BLOCK_DATA_NAMES = self.Blocks.get_burn_block_data_names() self.BLOCKS_FOR_KEYS = self.Blocks.get_blocks_for_keys() - self._esp = esp - self.debug = debug - self.do_not_confirm = do_not_confirm if esp.CHIP_NAME != "ESP32-S3": raise esptool.FatalError( "Expected the 'esp' param for ESP32-S3 chip but got for '%s'." @@ -102,7 +98,7 @@ def __init__( for efuse in self.Fields.BLOCK2_CALIBRATION_EFUSES ] else: - if self["BLK_VERSION_MAJOR"].get() == 1: + if self.get_block_version() >= 100: self.efuses += [ EfuseField.convert(self, efuse) for efuse in self.Fields.BLOCK2_CALIBRATION_EFUSES @@ -136,14 +132,14 @@ def read_coding_scheme(self): self.coding_scheme = self.REGS.CODING_SCHEME_RS def print_status_regs(self): - print("") + log.print("") self.blocks[0].print_block(self.blocks[0].err_bitarray, "err__regs", debug=True) - print( + log.print( "{:27} 0x{:08x}".format( "EFUSE_RD_RS_ERR0_REG", self.read_reg(self.REGS.EFUSE_RD_RS_ERR0_REG) ) ) - print( + log.print( "{:27} 0x{:08x}".format( "EFUSE_RD_RS_ERR1_REG", self.read_reg(self.REGS.EFUSE_RD_RS_ERR1_REG) ) @@ -176,7 +172,7 @@ def wait_efuse_idle(self): # For PGM_CMD it is not necessary. return raise esptool.FatalError( - "Timed out waiting for Efuse controller command to complete" + "Timed out waiting for eFuse controller command to complete" ) def efuse_program(self, block): @@ -204,30 +200,30 @@ def efuse_read(self): try: self._esp = self.reconnect_chip(self._esp) except esptool.FatalError: - print("Can not re-connect to the chip") + log.print("Can not re-connect to the chip.") if not self["DIS_DOWNLOAD_MODE"].get() and self[ "DIS_DOWNLOAD_MODE" ].get(from_read=False): - print( + log.print( "This is the correct behavior as we are actually burning " - "DIS_DOWNLOAD_MODE which disables the connection to the chip" + "DIS_DOWNLOAD_MODE which disables the connection to the chip." ) - print("DIS_DOWNLOAD_MODE is enabled") - print("Successful") + log.print("DIS_DOWNLOAD_MODE is enabled.") + log.print("Successful.") sys.exit(0) # finish without errors raise - print("Established a connection with the chip") + log.print("Established a connection with the chip.") if self._esp.secure_download_mode and not secure_download_mode_before: - print("Secure download mode is enabled") + log.print("Secure download mode is enabled.") if not self["ENABLE_SECURITY_DOWNLOAD"].get() and self[ "ENABLE_SECURITY_DOWNLOAD" ].get(from_read=False): - print( - "espefuse tool can not continue to work in Secure download mode" + log.print( + "espefuse can not continue to work in Secure download mode." ) - print("ENABLE_SECURITY_DOWNLOAD is enabled") - print("Successful") + log.print("ENABLE_SECURITY_DOWNLOAD is enabled.") + log.print("Successful.") sys.exit(0) # finish without errors raise @@ -280,9 +276,9 @@ def get_coding_scheme_warnings(self, silent=False): block.num_errors = (reg_value >> err_num_offs) & err_num_mask ret_fail |= block.fail if not silent and (block.fail or block.num_errors): - print( - "Error(s) in BLOCK%d [ERRORS:%d FAIL:%d]" - % (block.id, block.num_errors, block.fail) + log.print( + f"Error(s) in BLOCK{block.id} " + f"[ERRORS:{block.num_errors} FAIL:{block.fail}]." ) if (self.debug or ret_fail) and not silent: self.print_status_regs() @@ -319,8 +315,9 @@ def is_efuses_incompatible_for_burn(self): and self["DIS_USB_SERIAL_JTAG"].get(from_read=False) ) ): - print( - "DIS_USB_JTAG and DIS_USB_SERIAL_JTAG cannot be set together due to a bug in the ROM bootloader!" + log.print( + "DIS_USB_JTAG and DIS_USB_SERIAL_JTAG cannot be set together " + "due to a bug in the ROM bootloader!" ) return True return False @@ -335,9 +332,22 @@ def convert(parent, efuse): "t_sensor": EfuseTempSensor, "adc_tp": EfuseAdcPointCalibration, "wafer": EfuseWafer, + "psram_cap": EfusePsramCap, }.get(efuse.class_type, EfuseField)(parent, efuse) +class EfusePsramCap(EfuseField): + def get(self, from_read=True): + hi_bits = self.parent["PSRAM_CAP_3"].get(from_read) + assert self.parent["PSRAM_CAP_3"].bit_len == 1 + lo_bits = self.parent["PSRAM_CAP"].get(from_read) + assert self.parent["PSRAM_CAP"].bit_len == 2 + return (hi_bits << 2) + lo_bits + + def save(self, new_value): + raise esptool.FatalError("Burning %s is not supported" % self.name) + + class EfuseWafer(EfuseField): def get(self, from_read=True): hi_bits = self.parent["WAFER_VERSION_MINOR_HI"].get(from_read) @@ -407,10 +417,8 @@ def get(self, from_read=True): def save(self, new_value): def print_field(e, new_value): - print( - " - '{}' ({}) {} -> {}".format( - e.name, e.description, e.get_bitstring(), new_value - ) + log.print( + f" - '{e.name}' ({e.description}) {e.get_bitstring()} -> {new_value}" ) if self.name == "CUSTOM_MAC": @@ -420,7 +428,7 @@ def print_field(e, new_value): else: # Writing the BLOCK1 (MAC_SPI_8M_0) default MAC is not sensible, # as it's written in the factory. - raise esptool.FatalError("Writing Factory MAC address is not supported") + raise esptool.FatalError("Writing Factory MAC address is not supported.") # fmt: off @@ -455,9 +463,9 @@ def check_format(self, new_value_str): break if raw_val.isdigit(): if int(raw_val) not in [p[1] for p in self.KEY_PURPOSES if p[1] > 0]: - raise esptool.FatalError("'%s' can not be set (value out of range)" % raw_val) + raise esptool.FatalError(f"'{raw_val}' can not be set (value out of range).") else: - raise esptool.FatalError("'%s' unknown name" % raw_val) + raise esptool.FatalError(f"'{raw_val}' unknown name.") return raw_val def need_reverse(self, new_key_purpose): diff --git a/tools/esptool_py/espefuse/efuse/esp32s3/mem_definition.py b/tools/esptool_py/espefuse/efuse/esp32s3/mem_definition.py index 11aecfa651..361cbb9719 100644 --- a/tools/esptool_py/espefuse/efuse/esp32s3/mem_definition.py +++ b/tools/esptool_py/espefuse/efuse/esp32s3/mem_definition.py @@ -115,12 +115,8 @@ class EfuseDefineFields(EfuseFieldsBase): def __init__(self, extend_efuse_table) -> None: # List of efuse fields from TRM the chapter eFuse Controller. self.EFUSES = [] - self.KEYBLOCKS = [] - - # if BLK_VERSION_MAJOR is 1, these efuse fields are in BLOCK2 self.BLOCK2_CALIBRATION_EFUSES = [] - self.CALC = [] dir_name = os.path.dirname(os.path.abspath(__file__)) @@ -163,6 +159,16 @@ def __init__(self, extend_efuse_table) -> None: f.description = "calc WAFER VERSION MINOR = WAFER_VERSION_MINOR_HI << 3 + WAFER_VERSION_MINOR_LO (read only)" self.CALC.append(f) + f = Field() + f.name = "PSRAM_CAPACITY" + f.block = 0 + f.bit_len = 3 + f.type = f"uint:{f.bit_len}" + f.category = "identity" + f.class_type = "psram_cap" + f.description = "calc as = PSRAM_CAP_3 << 2 + PSRAM_CAP (read only)" + self.CALC.append(f) + for efuse in self.ALL_EFUSES: if efuse is not None: self.EFUSES.append(efuse) diff --git a/tools/esptool_py/espefuse/efuse/esp32s3/operations.py b/tools/esptool_py/espefuse/efuse/esp32s3/operations.py index 912ae3f0c0..021e4d8734 100644 --- a/tools/esptool_py/espefuse/efuse/esp32s3/operations.py +++ b/tools/esptool_py/espefuse/efuse/esp32s3/operations.py @@ -1,521 +1,388 @@ # This file includes the operations with eFuses for ESP32-S3 chip # -# SPDX-FileCopyrightText: 2020-2022 Espressif Systems (Shanghai) CO LTD +# SPDX-FileCopyrightText: 2020-2025 Espressif Systems (Shanghai) CO LTD # # SPDX-License-Identifier: GPL-2.0-or-later -import argparse import io -import os # noqa: F401. It is used in IDF scripts -import traceback +from typing import BinaryIO -import espsecure +from esptool.logger import log +import rich_click as click +import espsecure import esptool from . import fields +from .mem_definition import EfuseDefineBlocks from .. import util from ..base_operations import ( - add_common_commands, + BaseCommands, + TupleParameter, + NonCompositeTuple, add_force_write_always, add_show_sensitive_info_option, - burn_bit, - burn_block_data, - burn_efuse, - check_error, - dump, - read_protect_efuse, - summary, - write_protect_efuse, + protect_options, ) -def protect_options(p): - p.add_argument( - "--no-write-protect", - help="Disable write-protecting of the key. The key remains writable. " - "(The keys use the RS coding scheme that does not support post-write " - "data changes. Forced write can damage RS encoding bits.) " - "The write-protecting of keypurposes does not depend on the option, " - "it will be set anyway.", - action="store_true", - ) - p.add_argument( - "--no-read-protect", - help="Disable read-protecting of the key. The key remains readable software." - "The key with keypurpose[USER, RESERVED and *_DIGEST] " - "will remain readable anyway. " - "For the rest keypurposes the read-protection will be defined the option " - "(Read-protect by default).", - action="store_true", - ) - - -def add_commands(subparsers, efuses): - add_common_commands(subparsers, efuses) - burn_key = subparsers.add_parser( - "burn_key", help="Burn the key block with the specified name" - ) - protect_options(burn_key) - add_force_write_always(burn_key) - add_show_sensitive_info_option(burn_key) - burn_key.add_argument( - "block", - help="Key block to burn", - action="append", - choices=efuses.BLOCKS_FOR_KEYS, - ) - burn_key.add_argument( - "keyfile", - help="File containing 256 bits of binary key data", - action="append", - type=argparse.FileType("rb"), - ) - burn_key.add_argument( - "keypurpose", - help="Purpose to set.", - action="append", - choices=fields.EfuseKeyPurposeField.KEY_PURPOSES_NAME, - ) - for _ in efuses.BLOCKS_FOR_KEYS: - burn_key.add_argument( - "block", - help="Key block to burn", - nargs="?", - action="append", - metavar="BLOCK", - choices=efuses.BLOCKS_FOR_KEYS, - ) - burn_key.add_argument( - "keyfile", - help="File containing 256 bits of binary key data", - nargs="?", - action="append", - metavar="KEYFILE", - type=argparse.FileType("rb"), - ) - burn_key.add_argument( - "keypurpose", - help="Purpose to set.", - nargs="?", - action="append", - metavar="KEYPURPOSE", - choices=fields.EfuseKeyPurposeField.KEY_PURPOSES_NAME, - ) +class ESP32S3Commands(BaseCommands): + CHIP_NAME = "ESP32-S3" + efuse_lib = fields.EspEfuses - burn_key_digest = subparsers.add_parser( - "burn_key_digest", - help="Parse a RSA public key and burn the digest to key efuse block", - ) - protect_options(burn_key_digest) - add_force_write_always(burn_key_digest) - add_show_sensitive_info_option(burn_key_digest) - burn_key_digest.add_argument( - "block", - help="Key block to burn", - action="append", - choices=efuses.BLOCKS_FOR_KEYS, - ) - burn_key_digest.add_argument( - "keyfile", - help="Key file to digest (PEM format)", - action="append", - type=argparse.FileType("rb"), - ) - burn_key_digest.add_argument( - "keypurpose", - help="Purpose to set.", - action="append", - choices=fields.EfuseKeyPurposeField.DIGEST_KEY_PURPOSES, - ) - for _ in efuses.BLOCKS_FOR_KEYS: - burn_key_digest.add_argument( - "block", - help="Key block to burn", - nargs="?", - action="append", - metavar="BLOCK", - choices=efuses.BLOCKS_FOR_KEYS, - ) - burn_key_digest.add_argument( - "keyfile", - help="Key file to digest (PEM format)", - nargs="?", - action="append", - metavar="KEYFILE", - type=argparse.FileType("rb"), - ) - burn_key_digest.add_argument( - "keypurpose", - help="Purpose to set.", - nargs="?", - action="append", - metavar="KEYPURPOSE", - choices=fields.EfuseKeyPurposeField.DIGEST_KEY_PURPOSES, - ) + ################################### CLI definitions ################################### - p = subparsers.add_parser( - "set_flash_voltage", - help="Permanently set the internal flash voltage regulator " - "to either 1.8V, 3.3V or OFF. This means GPIO45 can be high or low at reset " - "without changing the flash voltage.", - ) - p.add_argument("voltage", help="Voltage selection", choices=["1.8V", "3.3V", "OFF"]) - - p = subparsers.add_parser( - "burn_custom_mac", help="Burn a 48-bit Custom MAC Address to EFUSE BLOCK3." - ) - p.add_argument( - "mac", - help="Custom MAC Address to burn given in hexadecimal format with " - "bytes separated by colons (e.g. AA:CD:EF:01:02:03).", - type=fields.base_fields.CheckArgValue(efuses, "CUSTOM_MAC"), - ) - add_force_write_always(p) - - p = subparsers.add_parser("get_custom_mac", help="Prints the Custom MAC Address.") - - -def burn_custom_mac(esp, efuses, args): - efuses["CUSTOM_MAC"].save(args.mac) - if not efuses.burn_all(check_batch_mode=True): - return - get_custom_mac(esp, efuses, args) - print("Successful") - - -def get_custom_mac(esp, efuses, args): - print("Custom MAC Address: {}".format(efuses["CUSTOM_MAC"].get())) - - -def set_flash_voltage(esp, efuses, args): - sdio_force = efuses["VDD_SPI_FORCE"] - sdio_tieh = efuses["VDD_SPI_TIEH"] - sdio_reg = efuses["VDD_SPI_XPD"] - - # check efuses aren't burned in a way which makes this impossible - if args.voltage == "OFF" and sdio_reg.get() != 0: - raise esptool.FatalError( - "Can't set flash regulator to OFF as VDD_SPI_XPD efuse is already burned" - ) + def add_cli_commands(self, cli: click.Group): + super().add_cli_commands(cli) + blocks_for_keys = EfuseDefineBlocks().get_blocks_for_keys() - if args.voltage == "1.8V" and sdio_tieh.get() != 0: - raise esptool.FatalError( - "Can't set regulator to 1.8V is VDD_SPI_TIEH efuse is already burned" + @cli.command( + "burn-key", + help="Burn the key block with the specified name. Arguments are groups of block name, " + "key file (containing 256 bits of binary key data) and key purpose.\n\n" + f"Block is one of: [{', '.join(blocks_for_keys)}]\n\n" + f"Key purpose is one of: [{', '.join(fields.EfuseKeyPurposeField.KEY_PURPOSES_NAME)}]", ) - - if args.voltage == "OFF": - msg = "Disable internal flash voltage regulator (VDD_SPI). " - "SPI flash will need to be powered from an external source.\n" - "The following efuse is burned: VDD_SPI_FORCE.\n" - "It is possible to later re-enable the internal regulator (%s) " % ( - "to 3.3V" if sdio_tieh.get() != 0 else "to 1.8V or 3.3V" + @click.argument( + "block_keyfile_keypurpose", + metavar=" ", + cls=TupleParameter, + required=True, + nargs=-1, + max_arity=len(blocks_for_keys), + type=NonCompositeTuple( + [ + click.Choice(blocks_for_keys), + click.File("rb"), + click.Choice(fields.EfuseKeyPurposeField.KEY_PURPOSES_NAME), + ] + ), ) - "by burning an additional efuse" - elif args.voltage == "1.8V": - msg = "Set internal flash voltage regulator (VDD_SPI) to 1.8V.\n" - "The following efuses are burned: VDD_SPI_FORCE, VDD_SPI_XPD.\n" - "It is possible to later increase the voltage to 3.3V (permanently) " - "by burning additional efuse VDD_SPI_TIEH" - elif args.voltage == "3.3V": - msg = "Enable internal flash voltage regulator (VDD_SPI) to 3.3V.\n" - "The following efuses are burned: VDD_SPI_FORCE, VDD_SPI_XPD, VDD_SPI_TIEH." - print(msg) - - sdio_force.save(1) # Disable GPIO45 - if args.voltage != "OFF": - sdio_reg.save(1) # Enable internal regulator - if args.voltage == "3.3V": - sdio_tieh.save(1) - print("VDD_SPI setting complete.") - if not efuses.burn_all(check_batch_mode=True): - return - print("Successful") - - -def adc_info(esp, efuses, args): - print("") - # fmt: off - if efuses["BLK_VERSION_MAJOR"].get() == 1: - print("Temperature Sensor Calibration = {}C".format(efuses["TEMP_CALIB"].get())) - print("ADC OCode = ", efuses["OCODE"].get()) - print("ADC1:") - print("INIT_CODE_ATTEN0 = ", efuses["ADC1_INIT_CODE_ATTEN0"].get()) - print("INIT_CODE_ATTEN1 = ", efuses["ADC1_INIT_CODE_ATTEN1"].get()) - print("INIT_CODE_ATTEN2 = ", efuses["ADC1_INIT_CODE_ATTEN2"].get()) - print("INIT_CODE_ATTEN3 = ", efuses["ADC1_INIT_CODE_ATTEN3"].get()) - print("CAL_VOL_ATTEN0 = ", efuses["ADC1_CAL_VOL_ATTEN0"].get()) - print("CAL_VOL_ATTEN1 = ", efuses["ADC1_CAL_VOL_ATTEN1"].get()) - print("CAL_VOL_ATTEN2 = ", efuses["ADC1_CAL_VOL_ATTEN2"].get()) - print("CAL_VOL_ATTEN3 = ", efuses["ADC1_CAL_VOL_ATTEN3"].get()) - print("ADC2:") - print("INIT_CODE_ATTEN0 = ", efuses["ADC2_INIT_CODE_ATTEN0"].get()) - print("INIT_CODE_ATTEN1 = ", efuses["ADC2_INIT_CODE_ATTEN1"].get()) - print("INIT_CODE_ATTEN2 = ", efuses["ADC2_INIT_CODE_ATTEN2"].get()) - print("INIT_CODE_ATTEN3 = ", efuses["ADC2_INIT_CODE_ATTEN3"].get()) - print("CAL_VOL_ATTEN0 = ", efuses["ADC2_CAL_VOL_ATTEN0"].get()) - print("CAL_VOL_ATTEN1 = ", efuses["ADC2_CAL_VOL_ATTEN1"].get()) - print("CAL_VOL_ATTEN2 = ", efuses["ADC2_CAL_VOL_ATTEN2"].get()) - else: - print("BLK_VERSION_MAJOR = ", efuses["BLK_VERSION_MAJOR"].get_meaning()) - # fmt: on - - -def key_block_is_unused(block, key_purpose_block): - if not block.is_readable() or not block.is_writeable(): - return False - - if key_purpose_block.get() != "USER" or not key_purpose_block.is_writeable(): - return False - - if not block.get_bitstring().all(False): - return False - - return True - - -def get_next_key_block(efuses, current_key_block, block_name_list): - key_blocks = [b for b in efuses.blocks if b.key_purpose_name] - start = key_blocks.index(current_key_block) - - # Sort key blocks so that we pick the next free block (and loop around if necessary) - key_blocks = key_blocks[start:] + key_blocks[0:start] - - # Exclude any other blocks that will be be burned - key_blocks = [b for b in key_blocks if b.name not in block_name_list] - - for block in key_blocks: - key_purpose_block = efuses[block.key_purpose_name] - if key_block_is_unused(block, key_purpose_block): - return block - - return None - - -def split_512_bit_key(efuses, block_name_list, datafile_list, keypurpose_list): - i = keypurpose_list.index("XTS_AES_256_KEY") - block_name = block_name_list[i] - - block_num = efuses.get_index_block_by_name(block_name) - block = efuses.blocks[block_num] - - data = datafile_list[i].read() - if len(data) != 64: - raise esptool.FatalError( - "Incorrect key file size %d, XTS_AES_256_KEY should be 64 bytes" % len(data) + @protect_options + @add_force_write_always + @add_show_sensitive_info_option + @click.pass_context + def burn_key_cli(ctx, **kwargs): + """Burn the key block with the specified name""" + kwargs.pop("force_write_always") + block, keyfile, keypurpose = zip(*kwargs.pop("block_keyfile_keypurpose")) + kwargs["show_sensitive_info"] = ctx.show_sensitive_info + self.burn_key(block, keyfile, keypurpose, **kwargs) + + @cli.command( + "burn-key-digest", + help="Burn the key block with the specified name. Arguments are groups of block name, " + "key file (containing 256 bits of binary key data) and key purpose.\n\n" + f"Block is one of: [{', '.join(blocks_for_keys)}]\n\n" + f"Key purpose is one of: [{', '.join(fields.EfuseKeyPurposeField.DIGEST_KEY_PURPOSES)}]", ) + @click.argument( + "block_keyfile_keypurpose", + metavar=" ", + cls=TupleParameter, + required=True, + nargs=-1, + max_arity=len(blocks_for_keys), + type=NonCompositeTuple( + [ + click.Choice(blocks_for_keys), + click.File("rb"), + click.Choice(fields.EfuseKeyPurposeField.DIGEST_KEY_PURPOSES), + ] + ), + ) + @protect_options + @add_force_write_always + @add_show_sensitive_info_option + @click.pass_context + def burn_key_digest_cli(ctx, **kwargs): + """Parse a RSA public key and burn the digest to key eFuse block""" + kwargs.pop("force_write_always") + block, keyfile, keypurpose = zip(*kwargs.pop("block_keyfile_keypurpose")) + kwargs["show_sensitive_info"] = ctx.show_sensitive_info + self.burn_key_digest(block, keyfile, keypurpose, **kwargs) + + @cli.command( + "set-flash-voltage", + short_help="Permanently set the internal flash voltage regulator.", + ) + @click.argument("voltage", type=click.Choice(["1.8V", "3.3V", "OFF"])) + def set_flash_voltage_cli(voltage): + """Permanently set the internal flash voltage regulator to either 1.8V, 3.3V or OFF. + This means GPIO45 can be high or low at reset without changing the flash voltage.""" + self.set_flash_voltage(voltage) - key_block_2 = get_next_key_block(efuses, block, block_name_list) - if not key_block_2: - raise esptool.FatalError("XTS_AES_256_KEY requires two free keyblocks") - - keypurpose_list.append("XTS_AES_256_KEY_1") - datafile_list.append(io.BytesIO(data[:32])) - block_name_list.append(block_name) + ###################################### Commands ###################################### - keypurpose_list.append("XTS_AES_256_KEY_2") - datafile_list.append(io.BytesIO(data[32:])) - block_name_list.append(key_block_2.name) + def set_flash_voltage(self, voltage: str): + sdio_force = self.efuses["VDD_SPI_FORCE"] + sdio_tieh = self.efuses["VDD_SPI_TIEH"] + sdio_reg = self.efuses["VDD_SPI_XPD"] - keypurpose_list.pop(i) - datafile_list.pop(i) - block_name_list.pop(i) + # check efuses aren't burned in a way which makes this impossible + if voltage == "OFF" and sdio_reg.get() != 0: + raise esptool.FatalError( + "Can't set flash regulator to OFF as VDD_SPI_XPD eFuse is already burned" + ) + if voltage == "1.8V" and sdio_tieh.get() != 0: + raise esptool.FatalError( + "Can't set regulator to 1.8V is VDD_SPI_TIEH eFuse is already burned" + ) -def burn_key(esp, efuses, args, digest=None): - if digest is None: - datafile_list = args.keyfile[ - 0 : len([name for name in args.keyfile if name is not None]) : - ] - else: - datafile_list = digest[0 : len([name for name in digest if name is not None]) :] - efuses.force_write_always = args.force_write_always - block_name_list = args.block[ - 0 : len([name for name in args.block if name is not None]) : - ] - keypurpose_list = args.keypurpose[ - 0 : len([name for name in args.keypurpose if name is not None]) : - ] - - if "XTS_AES_256_KEY" in keypurpose_list: - # XTS_AES_256_KEY is not an actual HW key purpose, needs to be split into - # XTS_AES_256_KEY_1 and XTS_AES_256_KEY_2 - split_512_bit_key(efuses, block_name_list, datafile_list, keypurpose_list) - - util.check_duplicate_name_in_list(block_name_list) - if len(block_name_list) != len(datafile_list) or len(block_name_list) != len( - keypurpose_list - ): - raise esptool.FatalError( - "The number of blocks (%d), datafile (%d) and keypurpose (%d) " - "should be the same." - % (len(block_name_list), len(datafile_list), len(keypurpose_list)) - ) + if voltage == "OFF": + log.print( + "Disable internal flash voltage regulator (VDD_SPI). " + "SPI flash will need to be powered from an external source.\n" + "The following eFuse is burned: VDD_SPI_FORCE.\n" + "It is possible to later re-enable the internal regulator" + f"{'to 3.3V' if sdio_tieh.get() != 0 else 'to 1.8V or 3.3V'}" + "by burning an additional eFuse" + ) + elif voltage == "1.8V": + log.print( + "Set internal flash voltage regulator (VDD_SPI) to 1.8V.\n" + "The following eFuses are burned: VDD_SPI_FORCE, VDD_SPI_XPD.\n" + "It is possible to later increase the voltage to 3.3V (permanently) " + "by burning additional eFuse VDD_SPI_TIEH" + ) + elif voltage == "3.3V": + log.print( + "Enable internal flash voltage regulator (VDD_SPI) to 3.3V.\n" + "The following eFuses are burned: VDD_SPI_FORCE, VDD_SPI_XPD, VDD_SPI_TIEH." + ) - print("Burn keys to blocks:") - for block_name, datafile, keypurpose in zip( - block_name_list, datafile_list, keypurpose_list + sdio_force.save(1) # Disable GPIO45 + if voltage != "OFF": + sdio_reg.save(1) # Enable internal regulator + if voltage == "3.3V": + sdio_tieh.save(1) + log.print("VDD_SPI setting complete.") + + if not self.efuses.burn_all(check_batch_mode=True): + return + log.print("Successful.") + + def adc_info(self): + log.print("") + log.print("Block version:", self.efuses.get_block_version()) + if self.efuses.get_block_version() >= 100: + # fmt: off + log.print(f"Temperature Sensor Calibration = {self.efuses['TEMP_CALIB'].get()}C") + log.print("ADC OCode = ", self.efuses["OCODE"].get()) + log.print("ADC1:") + log.print("INIT_CODE_ATTEN0 = ", self.efuses["ADC1_INIT_CODE_ATTEN0"].get()) + log.print("INIT_CODE_ATTEN1 = ", self.efuses["ADC1_INIT_CODE_ATTEN1"].get()) + log.print("INIT_CODE_ATTEN2 = ", self.efuses["ADC1_INIT_CODE_ATTEN2"].get()) + log.print("INIT_CODE_ATTEN3 = ", self.efuses["ADC1_INIT_CODE_ATTEN3"].get()) + log.print("CAL_VOL_ATTEN0 = ", self.efuses["ADC1_CAL_VOL_ATTEN0"].get()) + log.print("CAL_VOL_ATTEN1 = ", self.efuses["ADC1_CAL_VOL_ATTEN1"].get()) + log.print("CAL_VOL_ATTEN2 = ", self.efuses["ADC1_CAL_VOL_ATTEN2"].get()) + log.print("CAL_VOL_ATTEN3 = ", self.efuses["ADC1_CAL_VOL_ATTEN3"].get()) + log.print("ADC2:") + log.print("INIT_CODE_ATTEN0 = ", self.efuses["ADC2_INIT_CODE_ATTEN0"].get()) + log.print("INIT_CODE_ATTEN1 = ", self.efuses["ADC2_INIT_CODE_ATTEN1"].get()) + log.print("INIT_CODE_ATTEN2 = ", self.efuses["ADC2_INIT_CODE_ATTEN2"].get()) + log.print("INIT_CODE_ATTEN3 = ", self.efuses["ADC2_INIT_CODE_ATTEN3"].get()) + log.print("CAL_VOL_ATTEN0 = ", self.efuses["ADC2_CAL_VOL_ATTEN0"].get()) + log.print("CAL_VOL_ATTEN1 = ", self.efuses["ADC2_CAL_VOL_ATTEN1"].get()) + log.print("CAL_VOL_ATTEN2 = ", self.efuses["ADC2_CAL_VOL_ATTEN2"].get()) + # fmt: on + + def burn_key( + self, + blocks: list[str], + keyfiles: list[BinaryIO], + keypurposes: list[str], + no_write_protect: bool = False, + no_read_protect: bool = False, + show_sensitive_info: bool = False, + digest: list[bytes] | None = None, ): - efuse = None - for block in efuses.blocks: - if block_name == block.name or block_name in block.alias: - efuse = efuses[block.name] - if efuse is None: - raise esptool.FatalError("Unknown block name - %s" % (block_name)) - num_bytes = efuse.bit_len // 8 - - block_num = efuses.get_index_block_by_name(block_name) - block = efuses.blocks[block_num] - + """Burn the key block with the specified name. Arguments are groups of block name, + key file (containing 256 bits of binary key data) and key purpose. + + Args: + blocks: List of eFuse block names to burn keys to. + keyfiles: List of open files to read key data from. + keypurposes: List of key purposes to burn. + no_write_protect: If True, the write protection will NOT be enabled. + no_read_protect: If True, the read protection will NOT be enabled. + show_sensitive_info: If True, the sensitive information will be shown. + digest: List of digests to burn. + """ + datafile_list: list[BinaryIO] | list[bytes] if digest is None: - data = datafile.read() + datafile_list = keyfiles[ + 0 : len([name for name in keyfiles if name is not None]) : + ] else: - data = datafile - - print(" - %s" % (efuse.name), end=" ") - revers_msg = None - if efuses[block.key_purpose_name].need_reverse(keypurpose): - revers_msg = "\tReversing byte order for AES-XTS hardware peripheral" - data = data[::-1] - print( - "-> [{}]".format( - util.hexify(data, " ") - if args.show_sensitive_info - else " ".join(["??"] * len(data)) + datafile_list = digest[ + 0 : len([name for name in digest if name is not None]) : + ] + block_name_list = blocks[ + 0 : len([name for name in blocks if name is not None]) : + ] + keypurpose_list = keypurposes[ + 0 : len([name for name in keypurposes if name is not None]) : + ] + + if "XTS_AES_256_KEY" in keypurpose_list: + # XTS_AES_256_KEY is not an actual HW key purpose, needs to be split into + # XTS_AES_256_KEY_1 and XTS_AES_256_KEY_2 + block_name_list, datafile_list, keypurpose_list = self._split_512_bit_key( + block_name_list, + datafile_list, # type: ignore + keypurpose_list, ) - ) - if revers_msg: - print(revers_msg) - if len(data) != num_bytes: + + util.check_duplicate_name_in_list(block_name_list) + if len(block_name_list) != len(datafile_list) or len(block_name_list) != len( + keypurpose_list + ): raise esptool.FatalError( - "Incorrect key file size %d. Key file must be %d bytes (%d bits) " - "of raw binary key data." % (len(data), num_bytes, num_bytes * 8) + "The number of blocks (%d), datafile (%d) and keypurpose (%d) should be the same." + % (len(block_name_list), len(datafile_list), len(keypurpose_list)) ) - if efuses[block.key_purpose_name].need_rd_protect(keypurpose): - read_protect = False if args.no_read_protect else True - else: - read_protect = False - write_protect = not args.no_write_protect - - # using efuse instead of a block gives the advantage of - # checking it as the whole field. - efuse.save(data) - - disable_wr_protect_key_purpose = False - if efuses[block.key_purpose_name].get() != keypurpose: - if efuses[block.key_purpose_name].is_writeable(): - print( - "\t'%s': '%s' -> '%s'." - % ( - block.key_purpose_name, - efuses[block.key_purpose_name].get(), - keypurpose, - ) + log.print("Burn keys to blocks:") + for block_name, datafile, keypurpose in zip( + block_name_list, datafile_list, keypurpose_list + ): + efuse = None + for blk in self.efuses.blocks: + if block_name == blk.name or block_name in blk.alias: + efuse = self.efuses[blk.name] + if efuse is None: + raise esptool.FatalError(f"Unknown block name - {block_name}.") + num_bytes = efuse.bit_len // 8 + + block_num = self.efuses.get_index_block_by_name(block_name) + block = self.efuses.blocks[block_num] + + if isinstance(datafile, io.IOBase): + data = datafile.read() + datafile.close() + else: + data = datafile # type: ignore # this is safe but mypy still complains + + log.print(f" - {efuse.name}", end=" ") + revers_msg = None + if self.efuses[block.key_purpose_name].need_reverse(keypurpose): + revers_msg = "\tReversing byte order for AES-XTS hardware peripheral..." + data = data[::-1] + log.print( + "-> [{}]".format( + util.hexify(data, " ") + if show_sensitive_info + else " ".join(["??"] * len(data)) ) - efuses[block.key_purpose_name].save(keypurpose) - disable_wr_protect_key_purpose = True + ) + if revers_msg: + log.print(revers_msg) + if len(data) != num_bytes: + raise esptool.FatalError( + f"Incorrect key file size {len(data)}. Key file must be {num_bytes} " + f"bytes ({num_bytes * 8} bits) of raw binary key data." + ) + + if self.efuses[block.key_purpose_name].need_rd_protect(keypurpose): + read_protect = False if no_read_protect else True + else: + read_protect = False + write_protect = not no_write_protect + + # using eFuse instead of a block gives the advantage of checking it as the whole field. + efuse.save(data) + + disable_wr_protect_key_purpose = False + if self.efuses[block.key_purpose_name].get() != keypurpose: + if self.efuses[block.key_purpose_name].is_writeable(): + log.print( + f"\t'{block.key_purpose_name}': " + f"'{self.efuses[block.key_purpose_name].get()}' -> '{keypurpose}'." + ) + self.efuses[block.key_purpose_name].save(keypurpose) + disable_wr_protect_key_purpose = True + else: + raise esptool.FatalError( + f"It is not possible to change '{block.key_purpose_name}' " + f"to '{keypurpose}' because write protection bit is set." + ) else: + log.print(f"\t'{block.key_purpose_name}' is already '{keypurpose}'.") + if self.efuses[block.key_purpose_name].is_writeable(): + disable_wr_protect_key_purpose = True + + if disable_wr_protect_key_purpose: + log.print(f"\tDisabling write to '{block.key_purpose_name}'...") + self.efuses[block.key_purpose_name].disable_write() + + if read_protect: + log.print("\tDisabling read to key block...") + efuse.disable_read() + + if write_protect: + log.print("\tDisabling write to key block...") + efuse.disable_write() + log.print("") + + if not write_protect: + log.print("Keys will remain writeable (due to --no-write-protect).") + if no_read_protect: + log.print("Keys will remain readable (due to --no-read-protect).") + + if not self.efuses.burn_all(check_batch_mode=True): + return + log.print("Successful.") + + def burn_key_digest( + self, + blocks: list[str], + keyfiles: list[BinaryIO], + keypurposes: list[str], + no_write_protect: bool = False, + no_read_protect: bool = False, + show_sensitive_info: bool = False, + ): + """Parse a RSA public key and burn the digest to key eFuse block. + + Args: + blocks: List of eFuse block names to burn keys to. + keyfiles: List of open files to read key data from. + keypurposes: List of key purposes to burn. + no_write_protect: If True, the write protection will NOT be enabled. + no_read_protect: If True, the read protection will NOT be enabled. + show_sensitive_info: If True, the sensitive information will be shown. + """ + digest_list = [] + datafile_list = keyfiles[ + 0 : len([name for name in keyfiles if name is not None]) : + ] + block_list = blocks[0 : len([block for block in blocks if block is not None]) :] + + for block_name, datafile in zip(block_list, datafile_list): + efuse = None + for blk in self.efuses.blocks: + if block_name == blk.name or block_name in blk.alias: + efuse = self.efuses[blk.name] + if efuse is None: + raise esptool.FatalError(f"Unknown block name - {block_name}.") + num_bytes = efuse.bit_len // 8 + digest = espsecure._digest_sbv2_public_key(datafile) + if len(digest) != num_bytes: raise esptool.FatalError( - "It is not possible to change '%s' to '%s' because " - "write protection bit is set." - % (block.key_purpose_name, keypurpose) + "Incorrect digest size %d. Digest must be %d bytes (%d bits) " + "of raw binary key data." % (len(digest), num_bytes, num_bytes * 8) ) - else: - print("\t'%s' is already '%s'." % (block.key_purpose_name, keypurpose)) - if efuses[block.key_purpose_name].is_writeable(): - disable_wr_protect_key_purpose = True - - if disable_wr_protect_key_purpose: - print("\tDisabling write to '%s'." % block.key_purpose_name) - efuses[block.key_purpose_name].disable_write() - - if read_protect: - print("\tDisabling read to key block") - efuse.disable_read() - - if write_protect: - print("\tDisabling write to key block") - efuse.disable_write() - print("") - - if not write_protect: - print("Keys will remain writeable (due to --no-write-protect)") - if args.no_read_protect: - print("Keys will remain readable (due to --no-read-protect)") - - if not efuses.burn_all(check_batch_mode=True): - return - print("Successful") - - -def burn_key_digest(esp, efuses, args): - digest_list = [] - datafile_list = args.keyfile[ - 0 : len([name for name in args.keyfile if name is not None]) : - ] - block_list = args.block[ - 0 : len([block for block in args.block if block is not None]) : - ] - for block_name, datafile in zip(block_list, datafile_list): - efuse = None - for block in efuses.blocks: - if block_name == block.name or block_name in block.alias: - efuse = efuses[block.name] - if efuse is None: - raise esptool.FatalError("Unknown block name - %s" % (block_name)) - num_bytes = efuse.bit_len // 8 - digest = espsecure._digest_sbv2_public_key(datafile) - if len(digest) != num_bytes: - raise esptool.FatalError( - "Incorrect digest size %d. Digest must be %d bytes (%d bits) " - "of raw binary key data." % (len(digest), num_bytes, num_bytes * 8) - ) - digest_list.append(digest) - burn_key(esp, efuses, args, digest=digest_list) - - -def espefuse(esp, efuses, args, command): - parser = argparse.ArgumentParser() - subparsers = parser.add_subparsers(dest="operation") - add_commands(subparsers, efuses) - try: - cmd_line_args = parser.parse_args(command.split()) - except SystemExit: - traceback.print_stack() - raise esptool.FatalError('"{}" - incorrect command'.format(command)) - if cmd_line_args.operation == "execute_scripts": - configfiles = cmd_line_args.configfiles - index = cmd_line_args.index - # copy arguments from args to cmd_line_args - vars(cmd_line_args).update(vars(args)) - if cmd_line_args.operation == "execute_scripts": - cmd_line_args.configfiles = configfiles - cmd_line_args.index = index - if cmd_line_args.operation is None: - parser.print_help() - parser.exit(1) - operation_func = globals()[cmd_line_args.operation] - # each 'operation' is a module-level function of the same name - operation_func(esp, efuses, cmd_line_args) - - -def execute_scripts(esp, efuses, args): - efuses.batch_mode_cnt += 1 - del args.operation - scripts = args.scripts - del args.scripts - - for file in scripts: - with open(file.name, "r") as file: - exec(compile(file.read(), file.name, "exec")) - - if args.debug: - for block in efuses.blocks: - data = block.get_bitstring(from_read=False) - block.print_block(data, "regs_for_burn", args.debug) - - efuses.batch_mode_cnt -= 1 - if not efuses.burn_all(check_batch_mode=True): - return - print("Successful") + digest_list.append(digest) + + self.burn_key( + block_list, + datafile_list, + keypurposes, + no_write_protect, + no_read_protect, + show_sensitive_info, + digest=digest_list, + ) diff --git a/tools/esptool_py/espefuse/efuse/esp32s3beta2/__init__.py b/tools/esptool_py/espefuse/efuse/esp32s3beta2/__init__.py deleted file mode 100644 index a3b55a8023..0000000000 --- a/tools/esptool_py/espefuse/efuse/esp32s3beta2/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -from . import operations -from .emulate_efuse_controller import EmulateEfuseController -from .fields import EspEfuses diff --git a/tools/esptool_py/espefuse/efuse/esp32s3beta2/emulate_efuse_controller.py b/tools/esptool_py/espefuse/efuse/esp32s3beta2/emulate_efuse_controller.py deleted file mode 100644 index 949fc562b9..0000000000 --- a/tools/esptool_py/espefuse/efuse/esp32s3beta2/emulate_efuse_controller.py +++ /dev/null @@ -1,92 +0,0 @@ -# This file describes eFuses controller for ESP32-S3(beta2) chip -# -# SPDX-FileCopyrightText: 2020-2022 Espressif Systems (Shanghai) CO LTD -# -# SPDX-License-Identifier: GPL-2.0-or-later - -import reedsolo - -from .mem_definition import EfuseDefineBlocks, EfuseDefineFields, EfuseDefineRegisters -from ..emulate_efuse_controller_base import EmulateEfuseControllerBase, FatalError - - -class EmulateEfuseController(EmulateEfuseControllerBase): - """The class for virtual efuse operation. Using for HOST_TEST.""" - - CHIP_NAME = "ESP32-S3(beta2)" - mem = None - debug = False - - def __init__(self, efuse_file=None, debug=False): - self.Blocks = EfuseDefineBlocks - self.Fields = EfuseDefineFields(None) - self.REGS = EfuseDefineRegisters - super(EmulateEfuseController, self).__init__(efuse_file, debug) - self.write_reg(self.REGS.EFUSE_CMD_REG, 0) - - """ esptool method start >>""" - - def get_major_chip_version(self): - return 0 - - def get_minor_chip_version(self): - return 2 - - def get_crystal_freq(self): - return 40 # MHz (common for all chips) - - def get_security_info(self): - return { - "flags": 0, - "flash_crypt_cnt": 0, - "key_purposes": 0, - "chip_id": 0, - "api_version": 0, - } - - """ << esptool method end """ - - def handle_writing_event(self, addr, value): - if addr == self.REGS.EFUSE_CMD_REG: - if value & self.REGS.EFUSE_PGM_CMD: - self.copy_blocks_wr_regs_to_rd_regs(updated_block=(value >> 2) & 0xF) - self.clean_blocks_wr_regs() - self.check_rd_protection_area() - self.write_reg(addr, 0) - self.write_reg(self.REGS.EFUSE_CMD_REG, 0) - elif value == self.REGS.EFUSE_READ_CMD: - self.write_reg(addr, 0) - self.write_reg(self.REGS.EFUSE_CMD_REG, 0) - self.save_to_file() - - def get_bitlen_of_block(self, blk, wr=False): - if blk.id == 0: - if wr: - return 32 * 8 - else: - return 32 * blk.len - else: - if wr: - rs_coding = 32 * 3 - return 32 * 8 + rs_coding - else: - return 32 * blk.len - - def handle_coding_scheme(self, blk, data): - if blk.id != 0: - # CODING_SCHEME RS applied only for all blocks except BLK0. - coded_bytes = 12 - data.pos = coded_bytes * 8 - plain_data = data.readlist("32*uint:8")[::-1] - # takes 32 bytes - # apply RS encoding - rs = reedsolo.RSCodec(coded_bytes) - # 32 byte of data + 12 bytes RS - calc_encoded_data = list(rs.encode([x for x in plain_data])) - data.pos = 0 - if calc_encoded_data != data.readlist("44*uint:8")[::-1]: - raise FatalError("Error in coding scheme data") - data = data[coded_bytes * 8 :] - if blk.len < 8: - data = data[(8 - blk.len) * 32 :] - return data diff --git a/tools/esptool_py/espefuse/efuse/esp32s3beta2/fields.py b/tools/esptool_py/espefuse/efuse/esp32s3beta2/fields.py deleted file mode 100644 index 28e03e9cfe..0000000000 --- a/tools/esptool_py/espefuse/efuse/esp32s3beta2/fields.py +++ /dev/null @@ -1,489 +0,0 @@ -# This file describes eFuses for ESP32-S3 chip -# -# SPDX-FileCopyrightText: 2020-2022 Espressif Systems (Shanghai) CO LTD -# -# SPDX-License-Identifier: GPL-2.0-or-later - -import binascii -import struct -import sys -import time - -from bitstring import BitArray - -import esptool - -import reedsolo - -from .mem_definition import EfuseDefineBlocks, EfuseDefineFields, EfuseDefineRegisters -from .. import base_fields -from .. import util - - -class EfuseBlock(base_fields.EfuseBlockBase): - def len_of_burn_unit(self): - # The writing register window is 8 registers for any blocks. - # len in bytes - return 8 * 4 - - def __init__(self, parent, param, skip_read=False): - parent.read_coding_scheme() - super(EfuseBlock, self).__init__(parent, param, skip_read=skip_read) - - def apply_coding_scheme(self): - data = self.get_raw(from_read=False)[::-1] - if len(data) < self.len_of_burn_unit(): - add_empty_bytes = self.len_of_burn_unit() - len(data) - data = data + (b"\x00" * add_empty_bytes) - if self.get_coding_scheme() == self.parent.REGS.CODING_SCHEME_RS: - # takes 32 bytes - # apply RS encoding - rs = reedsolo.RSCodec(12) - # 32 byte of data + 12 bytes RS - encoded_data = rs.encode([x for x in data]) - words = struct.unpack("<" + "I" * 11, encoded_data) - # returns 11 words (8 words of data + 3 words of RS coding) - else: - # takes 32 bytes - words = struct.unpack("<" + ("I" * (len(data) // 4)), data) - # returns 8 words - return words - - -class EspEfuses(base_fields.EspEfusesBase): - """ - Wrapper object to manage the efuse fields in a connected ESP bootloader - """ - - debug = False - do_not_confirm = False - - def __init__( - self, - esp, - skip_connect=False, - debug=False, - do_not_confirm=False, - extend_efuse_table=None, - ): - self.Blocks = EfuseDefineBlocks() - self.Fields = EfuseDefineFields(extend_efuse_table) - self.REGS = EfuseDefineRegisters - self.BURN_BLOCK_DATA_NAMES = self.Blocks.get_burn_block_data_names() - self.BLOCKS_FOR_KEYS = self.Blocks.get_blocks_for_keys() - self._esp = esp - self.debug = debug - self.do_not_confirm = do_not_confirm - if esp.CHIP_NAME != "ESP32-S3(beta2)": - raise esptool.FatalError( - "Expected the 'esp' param for ESP32-S3(beta2) chip but got for '%s'." - % (esp.CHIP_NAME) - ) - if not skip_connect: - flags = self._esp.get_security_info()["flags"] - GET_SECURITY_INFO_FLAG_SECURE_DOWNLOAD_ENABLE = 1 << 2 - if flags & GET_SECURITY_INFO_FLAG_SECURE_DOWNLOAD_ENABLE: - raise esptool.FatalError( - "Secure Download Mode is enabled. The tool can not read eFuses." - ) - self.blocks = [ - EfuseBlock(self, self.Blocks.get(block), skip_read=skip_connect) - for block in self.Blocks.BLOCKS - ] - if not skip_connect: - self.get_coding_scheme_warnings() - self.efuses = [EfuseField.convert(self, efuse) for efuse in self.Fields.EFUSES] - self.efuses += [ - EfuseField.convert(self, efuse) for efuse in self.Fields.KEYBLOCKS - ] - if skip_connect: - self.efuses += [ - EfuseField.convert(self, efuse) - for efuse in self.Fields.BLOCK2_CALIBRATION_EFUSES - ] - else: - if self["BLK_VERSION_MAJOR"].get() == 1: - self.efuses += [ - EfuseField.convert(self, efuse) - for efuse in self.Fields.BLOCK2_CALIBRATION_EFUSES - ] - self.efuses += [ - EfuseField.convert(self, efuse) for efuse in self.Fields.CALC - ] - - def __getitem__(self, efuse_name): - """Return the efuse field with the given name""" - for e in self.efuses: - if efuse_name == e.name or any(x == efuse_name for x in e.alt_names): - return e - new_fields = False - for efuse in self.Fields.BLOCK2_CALIBRATION_EFUSES: - if efuse.name == efuse_name or any( - x == efuse_name for x in efuse.alt_names - ): - self.efuses += [ - EfuseField.convert(self, efuse) - for efuse in self.Fields.BLOCK2_CALIBRATION_EFUSES - ] - new_fields = True - if new_fields: - for e in self.efuses: - if efuse_name == e.name or any(x == efuse_name for x in e.alt_names): - return e - raise KeyError - - def read_coding_scheme(self): - self.coding_scheme = self.REGS.CODING_SCHEME_RS - - def print_status_regs(self): - print("") - self.blocks[0].print_block(self.blocks[0].err_bitarray, "err__regs", debug=True) - print( - "{:27} 0x{:08x}".format( - "EFUSE_RD_RS_ERR0_REG", self.read_reg(self.REGS.EFUSE_RD_RS_ERR0_REG) - ) - ) - print( - "{:27} 0x{:08x}".format( - "EFUSE_RD_RS_ERR1_REG", self.read_reg(self.REGS.EFUSE_RD_RS_ERR1_REG) - ) - ) - - def efuse_controller_setup(self): - self.set_efuse_timing() - self.clear_pgm_registers() - self.wait_efuse_idle() - - def write_efuses(self, block): - self.efuse_program(block) - return self.get_coding_scheme_warnings(silent=True) - - def clear_pgm_registers(self): - self.wait_efuse_idle() - for r in range( - self.REGS.EFUSE_PGM_DATA0_REG, self.REGS.EFUSE_PGM_DATA0_REG + 32, 4 - ): - self.write_reg(r, 0) - - def wait_efuse_idle(self): - deadline = time.time() + self.REGS.EFUSE_BURN_TIMEOUT - while time.time() < deadline: - cmds = self.REGS.EFUSE_PGM_CMD | self.REGS.EFUSE_READ_CMD - if self.read_reg(self.REGS.EFUSE_CMD_REG) & cmds == 0: - if self.read_reg(self.REGS.EFUSE_CMD_REG) & cmds == 0: - # Due to a hardware error, we have to read READ_CMD again - # to make sure the efuse clock is normal. - # For PGM_CMD it is not necessary. - return - raise esptool.FatalError( - "Timed out waiting for Efuse controller command to complete" - ) - - def efuse_program(self, block): - self.wait_efuse_idle() - self.write_reg(self.REGS.EFUSE_CONF_REG, self.REGS.EFUSE_WRITE_OP_CODE) - self.write_reg(self.REGS.EFUSE_CMD_REG, self.REGS.EFUSE_PGM_CMD | (block << 2)) - self.wait_efuse_idle() - self.clear_pgm_registers() - self.efuse_read() - - def efuse_read(self): - self.wait_efuse_idle() - self.write_reg(self.REGS.EFUSE_CONF_REG, self.REGS.EFUSE_READ_OP_CODE) - # need to add a delay after triggering EFUSE_READ_CMD, as ROM loader checks some - # efuse registers after each command is completed - # if ENABLE_SECURITY_DOWNLOAD or DIS_DOWNLOAD_MODE is enabled by the current cmd, then we need to try to reconnect to the chip. - try: - self.write_reg( - self.REGS.EFUSE_CMD_REG, self.REGS.EFUSE_READ_CMD, delay_after_us=1000 - ) - self.wait_efuse_idle() - except esptool.FatalError: - secure_download_mode_before = self._esp.secure_download_mode - - try: - self._esp = self.reconnect_chip(self._esp) - except esptool.FatalError: - print("Can not re-connect to the chip") - if not self["DIS_DOWNLOAD_MODE"].get() and self[ - "DIS_DOWNLOAD_MODE" - ].get(from_read=False): - print( - "This is the correct behavior as we are actually burning " - "DIS_DOWNLOAD_MODE which disables the connection to the chip" - ) - print("DIS_DOWNLOAD_MODE is enabled") - print("Successful") - sys.exit(0) # finish without errors - raise - - print("Established a connection with the chip") - if self._esp.secure_download_mode and not secure_download_mode_before: - print("Secure download mode is enabled") - if not self["ENABLE_SECURITY_DOWNLOAD"].get() and self[ - "ENABLE_SECURITY_DOWNLOAD" - ].get(from_read=False): - print( - "espefuse tool can not continue to work in Secure download mode" - ) - print("ENABLE_SECURITY_DOWNLOAD is enabled") - print("Successful") - sys.exit(0) # finish without errors - raise - - def set_efuse_timing(self): - """Set timing registers for burning efuses""" - # Configure clock - apb_freq = self.get_crystal_freq() - if apb_freq != 40: - raise esptool.FatalError( - "The eFuse supports only xtal=40M (xtal was %d)" % apb_freq - ) - - self.update_reg(self.REGS.EFUSE_DAC_CONF_REG, self.REGS.EFUSE_DAC_NUM_M, 0xFF) - self.update_reg( - self.REGS.EFUSE_DAC_CONF_REG, self.REGS.EFUSE_DAC_CLK_DIV_M, 0x28 - ) - self.update_reg( - self.REGS.EFUSE_WR_TIM_CONF1_REG, self.REGS.EFUSE_PWR_ON_NUM_M, 0x3000 - ) - self.update_reg( - self.REGS.EFUSE_WR_TIM_CONF2_REG, self.REGS.EFUSE_PWR_OFF_NUM_M, 0x190 - ) - - def get_coding_scheme_warnings(self, silent=False): - """Check if the coding scheme has detected any errors.""" - old_addr_reg = 0 - reg_value = 0 - ret_fail = False - for block in self.blocks: - if block.id == 0: - words = [ - self.read_reg(self.REGS.EFUSE_RD_REPEAT_ERR0_REG + offs * 4) - for offs in range(5) - ] - block.err_bitarray.pos = 0 - for word in reversed(words): - block.err_bitarray.overwrite(BitArray("uint:32=%d" % word)) - block.num_errors = block.err_bitarray.count(True) - block.fail = block.num_errors != 0 - else: - addr_reg, err_num_mask, err_num_offs, fail_bit = self.REGS.BLOCK_ERRORS[ - block.id - ] - if err_num_mask is None or err_num_offs is None or fail_bit is None: - continue - if addr_reg != old_addr_reg: - old_addr_reg = addr_reg - reg_value = self.read_reg(addr_reg) - block.fail = reg_value & (1 << fail_bit) != 0 - block.num_errors = (reg_value >> err_num_offs) & err_num_mask - ret_fail |= block.fail - if not silent and (block.fail or block.num_errors): - print( - "Error(s) in BLOCK%d [ERRORS:%d FAIL:%d]" - % (block.id, block.num_errors, block.fail) - ) - if (self.debug or ret_fail) and not silent: - self.print_status_regs() - return ret_fail - - def summary(self): - if self["VDD_SPI_FORCE"].get() == 0: - output = "Flash voltage (VDD_SPI) determined by GPIO45 on reset " - output += "(GPIO45=High: VDD_SPI pin is powered from internal 1.8V LDO\n" - output += "GPIO45=Low or NC: VDD_SPI pin is powered directly from " - output += "VDD3P3_RTC_IO via resistor Rspi. " - output += "Typically this voltage is 3.3 V)." - elif self["VDD_SPI_XPD"].get() == 0: - output = "Flash voltage (VDD_SPI) internal regulator disabled by efuse." - elif self["VDD_SPI_TIEH"].get() == 0: - output = "Flash voltage (VDD_SPI) set to 1.8V by efuse." - else: - output = "Flash voltage (VDD_SPI) set to 3.3V by efuse." - return output - - def is_efuses_incompatible_for_burn(self): - # getting chip version: self._esp.get_chip_revision() - if ( - ( - self["DIS_USB_JTAG"].get(from_read=True) - and self["DIS_USB_SERIAL_JTAG"].get(from_read=False) - ) - or ( - self["DIS_USB_JTAG"].get(from_read=False) - and self["DIS_USB_SERIAL_JTAG"].get(from_read=True) - ) - or ( - self["DIS_USB_JTAG"].get(from_read=False) - and self["DIS_USB_SERIAL_JTAG"].get(from_read=False) - ) - ): - print( - "DIS_USB_JTAG and DIS_USB_SERIAL_JTAG cannot be set together due to a bug in the ROM bootloader" - ) - return True - return False - - -class EfuseField(base_fields.EfuseFieldBase): - @staticmethod - def convert(parent, efuse): - return { - "mac": EfuseMacField, - "keypurpose": EfuseKeyPurposeField, - "t_sensor": EfuseTempSensor, - "adc_tp": EfuseAdcPointCalibration, - "wafer": EfuseWafer, - }.get(efuse.class_type, EfuseField)(parent, efuse) - - -class EfuseWafer(EfuseField): - def get(self, from_read=True): - hi_bits = self.parent["WAFER_VERSION_MINOR_HI"].get(from_read) - assert self.parent["WAFER_VERSION_MINOR_HI"].bit_len == 1 - lo_bits = self.parent["WAFER_VERSION_MINOR_LO"].get(from_read) - assert self.parent["WAFER_VERSION_MINOR_LO"].bit_len == 3 - return (hi_bits << 3) + lo_bits - - def save(self, new_value): - raise esptool.FatalError("Burning %s is not supported" % self.name) - - -class EfuseTempSensor(EfuseField): - def get(self, from_read=True): - value = self.get_bitstring(from_read) - sig = -1 if value[0] else 1 - return sig * value[1:].uint * 0.1 - - -class EfuseAdcPointCalibration(EfuseField): - def get(self, from_read=True): - STEP_SIZE = 4 - value = self.get_bitstring(from_read) - sig = -1 if value[0] else 1 - return sig * value[1:].uint * STEP_SIZE - - -class EfuseMacField(EfuseField): - def check_format(self, new_value_str): - if new_value_str is None: - raise esptool.FatalError( - "Required MAC Address in AA:CD:EF:01:02:03 format!" - ) - if new_value_str.count(":") != 5: - raise esptool.FatalError( - "MAC Address needs to be a 6-byte hexadecimal format " - "separated by colons (:)!" - ) - hexad = new_value_str.replace(":", "") - if len(hexad) != 12: - raise esptool.FatalError( - "MAC Address needs to be a 6-byte hexadecimal number " - "(12 hexadecimal characters)!" - ) - # order of bytearray = b'\xaa\xcd\xef\x01\x02\x03', - bindata = binascii.unhexlify(hexad) - # unicast address check according to - # https://tools.ietf.org/html/rfc7042#section-2.1 - if esptool.util.byte(bindata, 0) & 0x01: - raise esptool.FatalError("Custom MAC must be a unicast MAC!") - return bindata - - def check(self): - errs, fail = self.parent.get_block_errors(self.block) - if errs != 0 or fail: - output = "Block%d has ERRORS:%d FAIL:%d" % (self.block, errs, fail) - else: - output = "OK" - return "(" + output + ")" - - def get(self, from_read=True): - if self.name == "CUSTOM_MAC": - mac = self.get_raw(from_read)[::-1] - else: - mac = self.get_raw(from_read) - return "%s %s" % (util.hexify(mac, ":"), self.check()) - - def save(self, new_value): - def print_field(e, new_value): - print( - " - '{}' ({}) {} -> {}".format( - e.name, e.description, e.get_bitstring(), new_value - ) - ) - - if self.name == "CUSTOM_MAC": - bitarray_mac = self.convert_to_bitstring(new_value) - print_field(self, bitarray_mac) - super(EfuseMacField, self).save(new_value) - else: - # Writing the BLOCK1 (MAC_SPI_8M_0) default MAC is not possible, - # as it's written in the factory. - raise esptool.FatalError("Writing Factory MAC address is not supported") - - -# fmt: off -class EfuseKeyPurposeField(EfuseField): - KEY_PURPOSES = [ - ("USER", 0, None, None, "no_need_rd_protect"), # User purposes (software-only use) - ("RESERVED", 1, None, None, "no_need_rd_protect"), # Reserved - ("XTS_AES_256_KEY_1", 2, None, "Reverse", "need_rd_protect"), # XTS_AES_256_KEY_1 (flash/PSRAM encryption) - ("XTS_AES_256_KEY_2", 3, None, "Reverse", "need_rd_protect"), # XTS_AES_256_KEY_2 (flash/PSRAM encryption) - ("XTS_AES_128_KEY", 4, None, "Reverse", "need_rd_protect"), # XTS_AES_128_KEY (flash/PSRAM encryption) - ("HMAC_DOWN_ALL", 5, None, None, "need_rd_protect"), # HMAC Downstream mode - ("HMAC_DOWN_JTAG", 6, None, None, "need_rd_protect"), # JTAG soft enable key (uses HMAC Downstream mode) - ("HMAC_DOWN_DIGITAL_SIGNATURE", 7, None, None, "need_rd_protect"), # Digital Signature peripheral key (uses HMAC Downstream mode) - ("HMAC_UP", 8, None, None, "need_rd_protect"), # HMAC Upstream mode - ("SECURE_BOOT_DIGEST0", 9, "DIGEST", None, "no_need_rd_protect"), # SECURE_BOOT_DIGEST0 (Secure Boot key digest) - ("SECURE_BOOT_DIGEST1", 10, "DIGEST", None, "no_need_rd_protect"), # SECURE_BOOT_DIGEST1 (Secure Boot key digest) - ("SECURE_BOOT_DIGEST2", 11, "DIGEST", None, "no_need_rd_protect"), # SECURE_BOOT_DIGEST2 (Secure Boot key digest) - ("XTS_AES_256_KEY", -1, "VIRTUAL", None, "no_need_rd_protect"), # Virtual purpose splits to XTS_AES_256_KEY_1 and XTS_AES_256_KEY_2 - ] -# fmt: on - - KEY_PURPOSES_NAME = [name[0] for name in KEY_PURPOSES] - DIGEST_KEY_PURPOSES = [name[0] for name in KEY_PURPOSES if name[2] == "DIGEST"] - - def check_format(self, new_value_str): - # str convert to int: "XTS_AES_128_KEY" - > str(4) - # if int: 4 -> str(4) - raw_val = new_value_str - for purpose_name in self.KEY_PURPOSES: - if purpose_name[0] == new_value_str: - raw_val = str(purpose_name[1]) - break - if raw_val.isdigit(): - if int(raw_val) not in [p[1] for p in self.KEY_PURPOSES if p[1] > 0]: - raise esptool.FatalError("'%s' can not be set (value out of range)" % raw_val) - else: - raise esptool.FatalError("'%s' unknown name" % raw_val) - return raw_val - - def need_reverse(self, new_key_purpose): - for key in self.KEY_PURPOSES: - if key[0] == new_key_purpose: - return key[3] == "Reverse" - - def need_rd_protect(self, new_key_purpose): - for key in self.KEY_PURPOSES: - if key[0] == new_key_purpose: - return key[4] == "need_rd_protect" - - def get(self, from_read=True): - for p in self.KEY_PURPOSES: - if p[1] == self.get_raw(from_read): - return p[0] - return "FORBIDDEN_STATE" - - def get_name(self, raw_val): - for key in self.KEY_PURPOSES: - if key[1] == raw_val: - return key[0] - - def save(self, new_value): - raw_val = int(self.check_format(str(new_value))) - str_new_value = self.get_name(raw_val) - if self.name == "KEY_PURPOSE_5" and str_new_value.startswith("XTS_AES"): - raise esptool.FatalError(f"{self.name} can not have {str_new_value} key due to a hardware bug (please see TRM for more details)") - return super(EfuseKeyPurposeField, self).save(raw_val) diff --git a/tools/esptool_py/espefuse/efuse/esp32s3beta2/operations.py b/tools/esptool_py/espefuse/efuse/esp32s3beta2/operations.py deleted file mode 100644 index 229a929023..0000000000 --- a/tools/esptool_py/espefuse/efuse/esp32s3beta2/operations.py +++ /dev/null @@ -1,521 +0,0 @@ -# This file includes the operations with eFuses for ESP32-S3(beta2) chip -# -# SPDX-FileCopyrightText: 2020-2022 Espressif Systems (Shanghai) CO LTD -# -# SPDX-License-Identifier: GPL-2.0-or-later - -import argparse -import io -import os # noqa: F401. It is used in IDF scripts -import traceback - -import espsecure - -import esptool - -from . import fields -from .. import util -from ..base_operations import ( - add_common_commands, - add_force_write_always, - add_show_sensitive_info_option, - burn_bit, - burn_block_data, - burn_efuse, - check_error, - dump, - read_protect_efuse, - summary, - write_protect_efuse, -) - - -def protect_options(p): - p.add_argument( - "--no-write-protect", - help="Disable write-protecting of the key. The key remains writable. " - "(The keys use the RS coding scheme that does not support post-write " - "data changes. Forced write can damage RS encoding bits.) " - "The write-protecting of keypurposes does not depend on the option, " - "it will be set anyway.", - action="store_true", - ) - p.add_argument( - "--no-read-protect", - help="Disable read-protecting of the key. The key remains readable software." - "The key with keypurpose[USER, RESERVED and *_DIGEST] " - "will remain readable anyway. " - "For the rest keypurposes the read-protection will be defined the option " - "(Read-protect by default).", - action="store_true", - ) - - -def add_commands(subparsers, efuses): - add_common_commands(subparsers, efuses) - burn_key = subparsers.add_parser( - "burn_key", help="Burn the key block with the specified name" - ) - protect_options(burn_key) - add_force_write_always(burn_key) - add_show_sensitive_info_option(burn_key) - burn_key.add_argument( - "block", - help="Key block to burn", - action="append", - choices=efuses.BLOCKS_FOR_KEYS, - ) - burn_key.add_argument( - "keyfile", - help="File containing 256 bits of binary key data", - action="append", - type=argparse.FileType("rb"), - ) - burn_key.add_argument( - "keypurpose", - help="Purpose to set.", - action="append", - choices=fields.EfuseKeyPurposeField.KEY_PURPOSES_NAME, - ) - for _ in efuses.BLOCKS_FOR_KEYS: - burn_key.add_argument( - "block", - help="Key block to burn", - nargs="?", - action="append", - metavar="BLOCK", - choices=efuses.BLOCKS_FOR_KEYS, - ) - burn_key.add_argument( - "keyfile", - help="File containing 256 bits of binary key data", - nargs="?", - action="append", - metavar="KEYFILE", - type=argparse.FileType("rb"), - ) - burn_key.add_argument( - "keypurpose", - help="Purpose to set.", - nargs="?", - action="append", - metavar="KEYPURPOSE", - choices=fields.EfuseKeyPurposeField.KEY_PURPOSES_NAME, - ) - - burn_key_digest = subparsers.add_parser( - "burn_key_digest", - help="Parse a RSA public key and burn the digest to key efuse block", - ) - protect_options(burn_key_digest) - add_force_write_always(burn_key_digest) - add_show_sensitive_info_option(burn_key_digest) - burn_key_digest.add_argument( - "block", - help="Key block to burn", - action="append", - choices=efuses.BLOCKS_FOR_KEYS, - ) - burn_key_digest.add_argument( - "keyfile", - help="Key file to digest (PEM format)", - action="append", - type=argparse.FileType("rb"), - ) - burn_key_digest.add_argument( - "keypurpose", - help="Purpose to set.", - action="append", - choices=fields.EfuseKeyPurposeField.DIGEST_KEY_PURPOSES, - ) - for _ in efuses.BLOCKS_FOR_KEYS: - burn_key_digest.add_argument( - "block", - help="Key block to burn", - nargs="?", - action="append", - metavar="BLOCK", - choices=efuses.BLOCKS_FOR_KEYS, - ) - burn_key_digest.add_argument( - "keyfile", - help="Key file to digest (PEM format)", - nargs="?", - action="append", - metavar="KEYFILE", - type=argparse.FileType("rb"), - ) - burn_key_digest.add_argument( - "keypurpose", - help="Purpose to set.", - nargs="?", - action="append", - metavar="KEYPURPOSE", - choices=fields.EfuseKeyPurposeField.DIGEST_KEY_PURPOSES, - ) - - p = subparsers.add_parser( - "set_flash_voltage", - help="Permanently set the internal flash voltage regulator " - "to either 1.8V, 3.3V or OFF. This means GPIO45 can be high or low at reset " - "without changing the flash voltage.", - ) - p.add_argument("voltage", help="Voltage selection", choices=["1.8V", "3.3V", "OFF"]) - - p = subparsers.add_parser( - "burn_custom_mac", help="Burn a 48-bit Custom MAC Address to EFUSE BLOCK3." - ) - p.add_argument( - "mac", - help="Custom MAC Address to burn given in hexadecimal format with bytes " - "separated by colons (e.g. AA:CD:EF:01:02:03).", - type=fields.base_fields.CheckArgValue(efuses, "CUSTOM_MAC"), - ) - add_force_write_always(p) - - p = subparsers.add_parser("get_custom_mac", help="Prints the Custom MAC Address.") - - -def burn_custom_mac(esp, efuses, args): - efuses["CUSTOM_MAC"].save(args.mac) - if not efuses.burn_all(check_batch_mode=True): - return - get_custom_mac(esp, efuses, args) - print("Successful") - - -def get_custom_mac(esp, efuses, args): - print("Custom MAC Address: {}".format(efuses["CUSTOM_MAC"].get())) - - -def set_flash_voltage(esp, efuses, args): - sdio_force = efuses["VDD_SPI_FORCE"] - sdio_tieh = efuses["VDD_SPI_TIEH"] - sdio_reg = efuses["VDD_SPI_XPD"] - - # check efuses aren't burned in a way which makes this impossible - if args.voltage == "OFF" and sdio_reg.get() != 0: - raise esptool.FatalError( - "Can't set flash regulator to OFF as VDD_SPI_XPD efuse is already burned" - ) - - if args.voltage == "1.8V" and sdio_tieh.get() != 0: - raise esptool.FatalError( - "Can't set regulator to 1.8V is VDD_SPI_TIEH efuse is already burned" - ) - - if args.voltage == "OFF": - msg = "Disable internal flash voltage regulator (VDD_SPI). " - "SPI flash will need to be powered from an external source.\n" - "The following efuse is burned: VDD_SPI_FORCE.\n" - "It is possible to later re-enable the internal regulator (%s) " % ( - "to 3.3V" if sdio_tieh.get() != 0 else "to 1.8V or 3.3V" - ) - "by burning an additional efuse" - elif args.voltage == "1.8V": - msg = "Set internal flash voltage regulator (VDD_SPI) to 1.8V.\n" - "The following efuses are burned: VDD_SPI_FORCE, VDD_SPI_XPD.\n" - "It is possible to later increase the voltage to 3.3V (permanently) " - "by burning additional efuse VDD_SPI_TIEH" - elif args.voltage == "3.3V": - msg = "Enable internal flash voltage regulator (VDD_SPI) to 3.3V.\n" - "The following efuses are burned: VDD_SPI_FORCE, VDD_SPI_XPD, VDD_SPI_TIEH." - print(msg) - - sdio_force.save(1) # Disable GPIO45 - if args.voltage != "OFF": - sdio_reg.save(1) # Enable internal regulator - if args.voltage == "3.3V": - sdio_tieh.save(1) - print("VDD_SPI setting complete.") - if not efuses.burn_all(check_batch_mode=True): - return - print("Successful") - - -def adc_info(esp, efuses, args): - print("") - # fmt: off - if efuses["BLK_VERSION_MAJOR"].get() == 1: - print("Temperature Sensor Calibration = {}C".format(efuses["TEMP_CALIB"].get())) - print("ADC OCode = ", efuses["OCODE"].get()) - print("ADC1:") - print("INIT_CODE_ATTEN0 = ", efuses["ADC1_INIT_CODE_ATTEN0"].get()) - print("INIT_CODE_ATTEN1 = ", efuses["ADC1_INIT_CODE_ATTEN1"].get()) - print("INIT_CODE_ATTEN2 = ", efuses["ADC1_INIT_CODE_ATTEN2"].get()) - print("INIT_CODE_ATTEN3 = ", efuses["ADC1_INIT_CODE_ATTEN3"].get()) - print("CAL_VOL_ATTEN0 = ", efuses["ADC1_CAL_VOL_ATTEN0"].get()) - print("CAL_VOL_ATTEN1 = ", efuses["ADC1_CAL_VOL_ATTEN1"].get()) - print("CAL_VOL_ATTEN2 = ", efuses["ADC1_CAL_VOL_ATTEN2"].get()) - print("CAL_VOL_ATTEN3 = ", efuses["ADC1_CAL_VOL_ATTEN3"].get()) - print("ADC2:") - print("INIT_CODE_ATTEN0 = ", efuses["ADC2_INIT_CODE_ATTEN0"].get()) - print("INIT_CODE_ATTEN1 = ", efuses["ADC2_INIT_CODE_ATTEN1"].get()) - print("INIT_CODE_ATTEN2 = ", efuses["ADC2_INIT_CODE_ATTEN2"].get()) - print("INIT_CODE_ATTEN3 = ", efuses["ADC2_INIT_CODE_ATTEN3"].get()) - print("CAL_VOL_ATTEN0 = ", efuses["ADC2_CAL_VOL_ATTEN0"].get()) - print("CAL_VOL_ATTEN1 = ", efuses["ADC2_CAL_VOL_ATTEN1"].get()) - print("CAL_VOL_ATTEN2 = ", efuses["ADC2_CAL_VOL_ATTEN2"].get()) - else: - print("BLK_VERSION_MAJOR = ", efuses["BLK_VERSION_MAJOR"].get_meaning()) - # fmt: on - - -def key_block_is_unused(block, key_purpose_block): - if not block.is_readable() or not block.is_writeable(): - return False - - if key_purpose_block.get() != "USER" or not key_purpose_block.is_writeable(): - return False - - if not block.get_bitstring().all(False): - return False - - return True - - -def get_next_key_block(efuses, current_key_block, block_name_list): - key_blocks = [b for b in efuses.blocks if b.key_purpose_name] - start = key_blocks.index(current_key_block) - - # Sort key blocks so that we pick the next free block (and loop around if necessary) - key_blocks = key_blocks[start:] + key_blocks[0:start] - - # Exclude any other blocks that will be be burned - key_blocks = [b for b in key_blocks if b.name not in block_name_list] - - for block in key_blocks: - key_purpose_block = efuses[block.key_purpose_name] - if key_block_is_unused(block, key_purpose_block): - return block - - return None - - -def split_512_bit_key(efuses, block_name_list, datafile_list, keypurpose_list): - i = keypurpose_list.index("XTS_AES_256_KEY") - block_name = block_name_list[i] - - block_num = efuses.get_index_block_by_name(block_name) - block = efuses.blocks[block_num] - - data = datafile_list[i].read() - if len(data) != 64: - raise esptool.FatalError( - "Incorrect key file size %d, XTS_AES_256_KEY should be 64 bytes" % len(data) - ) - - key_block_2 = get_next_key_block(efuses, block, block_name_list) - if not key_block_2: - raise esptool.FatalError("XTS_AES_256_KEY requires two free keyblocks") - - keypurpose_list.append("XTS_AES_256_KEY_1") - datafile_list.append(io.BytesIO(data[:32])) - block_name_list.append(block_name) - - keypurpose_list.append("XTS_AES_256_KEY_2") - datafile_list.append(io.BytesIO(data[32:])) - block_name_list.append(key_block_2.name) - - keypurpose_list.pop(i) - datafile_list.pop(i) - block_name_list.pop(i) - - -def burn_key(esp, efuses, args, digest=None): - if digest is None: - datafile_list = args.keyfile[ - 0 : len([name for name in args.keyfile if name is not None]) : - ] - else: - datafile_list = digest[0 : len([name for name in digest if name is not None]) :] - efuses.force_write_always = args.force_write_always - block_name_list = args.block[ - 0 : len([name for name in args.block if name is not None]) : - ] - keypurpose_list = args.keypurpose[ - 0 : len([name for name in args.keypurpose if name is not None]) : - ] - - if "XTS_AES_256_KEY" in keypurpose_list: - # XTS_AES_256_KEY is not an actual HW key purpose, needs to be split into - # XTS_AES_256_KEY_1 and XTS_AES_256_KEY_2 - split_512_bit_key(efuses, block_name_list, datafile_list, keypurpose_list) - - util.check_duplicate_name_in_list(block_name_list) - if len(block_name_list) != len(datafile_list) or len(block_name_list) != len( - keypurpose_list - ): - raise esptool.FatalError( - "The number of blocks (%d), datafile (%d) and keypurpose (%d) " - "should be the same." - % (len(block_name_list), len(datafile_list), len(keypurpose_list)) - ) - - print("Burn keys to blocks:") - for block_name, datafile, keypurpose in zip( - block_name_list, datafile_list, keypurpose_list - ): - efuse = None - for block in efuses.blocks: - if block_name == block.name or block_name in block.alias: - efuse = efuses[block.name] - if efuse is None: - raise esptool.FatalError("Unknown block name - %s" % (block_name)) - num_bytes = efuse.bit_len // 8 - - block_num = efuses.get_index_block_by_name(block_name) - block = efuses.blocks[block_num] - - if digest is None: - data = datafile.read() - else: - data = datafile - - print(" - %s" % (efuse.name), end=" ") - revers_msg = None - if efuses[block.key_purpose_name].need_reverse(keypurpose): - revers_msg = "\tReversing byte order for AES-XTS hardware peripheral" - data = data[::-1] - print( - "-> [{}]".format( - util.hexify(data, " ") - if args.show_sensitive_info - else " ".join(["??"] * len(data)) - ) - ) - if revers_msg: - print(revers_msg) - if len(data) != num_bytes: - raise esptool.FatalError( - "Incorrect key file size %d. Key file must be %d bytes (%d bits) " - "of raw binary key data." % (len(data), num_bytes, num_bytes * 8) - ) - - if efuses[block.key_purpose_name].need_rd_protect(keypurpose): - read_protect = False if args.no_read_protect else True - else: - read_protect = False - write_protect = not args.no_write_protect - - # using efuse instead of a block gives the advantage of - # checking it as the whole field. - efuse.save(data) - - disable_wr_protect_key_purpose = False - if efuses[block.key_purpose_name].get() != keypurpose: - if efuses[block.key_purpose_name].is_writeable(): - print( - "\t'%s': '%s' -> '%s'." - % ( - block.key_purpose_name, - efuses[block.key_purpose_name].get(), - keypurpose, - ) - ) - efuses[block.key_purpose_name].save(keypurpose) - disable_wr_protect_key_purpose = True - else: - raise esptool.FatalError( - "It is not possible to change '%s' to '%s' because " - "write protection bit is set." - % (block.key_purpose_name, keypurpose) - ) - else: - print("\t'%s' is already '%s'." % (block.key_purpose_name, keypurpose)) - if efuses[block.key_purpose_name].is_writeable(): - disable_wr_protect_key_purpose = True - - if disable_wr_protect_key_purpose: - print("\tDisabling write to '%s'." % block.key_purpose_name) - efuses[block.key_purpose_name].disable_write() - - if read_protect: - print("\tDisabling read to key block") - efuse.disable_read() - - if write_protect: - print("\tDisabling write to key block") - efuse.disable_write() - print("") - - if not write_protect: - print("Keys will remain writeable (due to --no-write-protect)") - if args.no_read_protect: - print("Keys will remain readable (due to --no-read-protect)") - - if not efuses.burn_all(check_batch_mode=True): - return - print("Successful") - - -def burn_key_digest(esp, efuses, args): - digest_list = [] - datafile_list = args.keyfile[ - 0 : len([name for name in args.keyfile if name is not None]) : - ] - block_list = args.block[ - 0 : len([block for block in args.block if block is not None]) : - ] - for block_name, datafile in zip(block_list, datafile_list): - efuse = None - for block in efuses.blocks: - if block_name == block.name or block_name in block.alias: - efuse = efuses[block.name] - if efuse is None: - raise esptool.FatalError("Unknown block name - %s" % (block_name)) - num_bytes = efuse.bit_len // 8 - digest = espsecure._digest_sbv2_public_key(datafile) - if len(digest) != num_bytes: - raise esptool.FatalError( - "Incorrect digest size %d. Digest must be %d bytes (%d bits) " - "of raw binary key data." % (len(digest), num_bytes, num_bytes * 8) - ) - digest_list.append(digest) - burn_key(esp, efuses, args, digest=digest_list) - - -def espefuse(esp, efuses, args, command): - parser = argparse.ArgumentParser() - subparsers = parser.add_subparsers(dest="operation") - add_commands(subparsers, efuses) - try: - cmd_line_args = parser.parse_args(command.split()) - except SystemExit: - traceback.print_stack() - raise esptool.FatalError('"{}" - incorrect command'.format(command)) - if cmd_line_args.operation == "execute_scripts": - configfiles = cmd_line_args.configfiles - index = cmd_line_args.index - # copy arguments from args to cmd_line_args - vars(cmd_line_args).update(vars(args)) - if cmd_line_args.operation == "execute_scripts": - cmd_line_args.configfiles = configfiles - cmd_line_args.index = index - if cmd_line_args.operation is None: - parser.print_help() - parser.exit(1) - operation_func = globals()[cmd_line_args.operation] - # each 'operation' is a module-level function of the same name - operation_func(esp, efuses, cmd_line_args) - - -def execute_scripts(esp, efuses, args): - efuses.batch_mode_cnt += 1 - del args.operation - scripts = args.scripts - del args.scripts - - for file in scripts: - with open(file.name, "r") as file: - exec(compile(file.read(), file.name, "exec")) - - if args.debug: - for block in efuses.blocks: - data = block.get_bitstring(from_read=False) - block.print_block(data, "regs_for_burn", args.debug) - - efuses.batch_mode_cnt -= 1 - if not efuses.burn_all(check_batch_mode=True): - return - print("Successful") diff --git a/tools/esptool_py/espefuse/efuse/mem_definition_base.py b/tools/esptool_py/espefuse/efuse/mem_definition_base.py index f6e2bdc0b2..07f58df2fe 100644 --- a/tools/esptool_py/espefuse/efuse/mem_definition_base.py +++ b/tools/esptool_py/espefuse/efuse/mem_definition_base.py @@ -6,7 +6,7 @@ from collections import Counter, namedtuple import esptool -from typing import Optional, List +from esptool.logger import log from .csv_table_parser import CSVFuseTable @@ -23,7 +23,7 @@ class EfuseRegistersBase(object): class EfuseBlocksBase(object): - BLOCKS: Optional[List] = None + BLOCKS: list = [] NamedtupleBlock = namedtuple( "NamedtupleBlock", "name alias id rd_addr wr_addr write_disable_bit " @@ -53,10 +53,10 @@ class Field: word = None pos = None bit_len = 0 - alt_names: List[str] = [] + alt_names: list[str] = [] type = "" write_disable_bit = None - read_disable_bit = None + read_disable_bit: list[int] | None = None category = "config" class_type = "" description = "" @@ -65,7 +65,7 @@ class Field: class EfuseFieldsBase(object): def __init__(self, e_desc, extend_efuse_table_file) -> None: - self.ALL_EFUSES: List = [] + self.ALL_EFUSES: list = [] def set_category_and_class_type(efuse, name): def includes(name, names): @@ -140,7 +140,20 @@ def includes(name, names): if name == "OPTIONAL_UNIQUE_ID": efuse.class_type = "keyblock" - elif includes(name, ["ADC", "LDO", "DBIAS", "_HVT", "CALIB", "OCODE"]): + elif includes( + name, + [ + "ADC", + "LDO", + "DBIAS", + "_HVT", + "CALIB", + "OCODE", + "TEMPERATURE", + "LSLP", + "DSLP", + ], + ): efuse.category = "calibration" if name == "ADC_VREF": efuse.class_type = "vref" @@ -186,7 +199,7 @@ def check_name_duplicates(self): name_counts = Counter(names) duplicates = {name for name, count in name_counts.items() if count > 1} if duplicates: - print("Names that are not unique: " + ", ".join(duplicates)) + log.print("Names that are not unique: " + ", ".join(duplicates)) raise esptool.FatalError("Duplicate names found in eFuses") def extend_efuses(self, extend_efuse_table_file): diff --git a/tools/esptool_py/espefuse/efuse/util.py b/tools/esptool_py/espefuse/efuse/util.py index 004e03b295..cb9547022a 100644 --- a/tools/esptool_py/espefuse/efuse/util.py +++ b/tools/esptool_py/espefuse/efuse/util.py @@ -20,9 +20,7 @@ def popcnt(b): def check_duplicate_name_in_list(name_list): duples_name = [name for i, name in enumerate(name_list) if name in name_list[:i]] if duples_name != []: - raise esptool.FatalError( - "Found repeated {} in the name list".format(duples_name) - ) + raise esptool.FatalError(f"Found repeated {duples_name} in the name list.") class SdkConfig(object): diff --git a/tools/esptool_py/espefuse/efuse_defs/esp32c5.yaml b/tools/esptool_py/espefuse/efuse_defs/esp32c5.yaml index 31af46a56d..2200b94b8e 100644 --- a/tools/esptool_py/espefuse/efuse_defs/esp32c5.yaml +++ b/tools/esptool_py/espefuse/efuse_defs/esp32c5.yaml @@ -1,104 +1,123 @@ -VER_NO: b09fa417de505238a601eddce188b696 +VER_NO: 31c7fe3f5f4e0a55b178a57126c0aca7 EFUSES: - WR_DIS : {show: y, blk : 0, word: 0, pos : 0, len : 32, start : 0, type : 'uint:32', wr_dis: null, rd_dis: null, alt : '', dict : '', desc: Disable programming of individual eFuses, rloc: EFUSE_RD_WR_DIS0_REG, bloc: 'B0,B1,B2,B3'} - RD_DIS : {show: y, blk : 0, word: 1, pos : 0, len : 7, start : 32, type : 'uint:7', wr_dis : 0, rd_dis: null, alt : '', dict : '', desc: Disable reading from BlOCK4-10, rloc: 'EFUSE_RD_REPEAT_DATA0_REG[6:0]', bloc: 'B4[6:0]'} - RESERVE_0_39 : {show: n, blk : 0, word: 1, pos : 7, len : 1, start : 39, type : bool, wr_dis: null, rd_dis: null, alt : '', dict : '', desc: Reserved; it was created by set_missed_fields_in_regs func, rloc: 'EFUSE_RD_REPEAT_DATA0_REG[7]', bloc: 'B4[7]'} - DIS_ICACHE : {show: y, blk : 0, word: 1, pos : 8, len : 1, start : 40, type : bool, wr_dis : 2, rd_dis: null, alt : '', dict : '', desc: 'Represents whether icache is disabled or enabled.\\ 1: disabled\\ 0: enabled\\', rloc: 'EFUSE_RD_REPEAT_DATA0_REG[8]', bloc: 'B5[0]'} - DIS_USB_JTAG : {show: y, blk : 0, word: 1, pos : 9, len : 1, start : 41, type : bool, wr_dis : 2, rd_dis: null, alt : '', dict : '', desc: 'Represents whether the function of usb switch to jtag is disabled or enabled.\\ 1: disabled\\ 0: enabled\\', rloc: 'EFUSE_RD_REPEAT_DATA0_REG[9]', bloc: 'B5[1]'} - RESERVE_0_42 : {show: n, blk : 0, word: 1, pos: 10, len : 1, start : 42, type : bool, wr_dis: null, rd_dis: null, alt : '', dict : '', desc: Reserved; it was created by set_missed_fields_in_regs func, rloc: 'EFUSE_RD_REPEAT_DATA0_REG[10]', bloc: 'B5[2]'} - DIS_USB_SERIAL_JTAG : {show: n, blk : 0, word: 1, pos: 11, len : 1, start : 43, type : bool, wr_dis : 2, rd_dis: null, alt : '', dict : '', desc: 'Represents whether USB-Serial-JTAG is disabled or enabled.\\ 1: disabled\\ 0: enabled\\', rloc: 'EFUSE_RD_REPEAT_DATA0_REG[11]', bloc: 'B5[3]'} - DIS_FORCE_DOWNLOAD : {show: y, blk : 0, word: 1, pos: 12, len : 1, start : 44, type : bool, wr_dis : 2, rd_dis: null, alt : '', dict : '', desc: 'Represents whether the function that forces chip into download mode is disabled or enabled.\\ 1: disabled\\ 0: enabled\\', rloc: 'EFUSE_RD_REPEAT_DATA0_REG[12]', bloc: 'B5[4]'} - SPI_DOWNLOAD_MSPI_DIS : {show: y, blk : 0, word: 1, pos: 13, len : 1, start : 45, type : bool, wr_dis : 2, rd_dis: null, alt : '', dict : '', desc: 'Represents whether SPI0 controller during boot_mode_download is disabled or enabled.\\ 1: disabled\\ 0: enabled\\', rloc: 'EFUSE_RD_REPEAT_DATA0_REG[13]', bloc: 'B5[5]'} - DIS_TWAI : {show: y, blk : 0, word: 1, pos: 14, len : 1, start : 46, type : bool, wr_dis : 2, rd_dis: null, alt : '', dict : '', desc: 'Represents whether TWAI function is disabled or enabled.\\ 1: disabled\\ 0: enabled\\', rloc: 'EFUSE_RD_REPEAT_DATA0_REG[14]', bloc: 'B5[6]'} - JTAG_SEL_ENABLE : {show: y, blk : 0, word: 1, pos: 15, len : 1, start : 47, type : bool, wr_dis : 2, rd_dis: null, alt : '', dict : '', desc: 'Represents whether the selection between usb_to_jtag and pad_to_jtag through strapping gpio15 when both EFUSE_DIS_PAD_JTAG and EFUSE_DIS_USB_JTAG are equal to 0 is enabled or disabled.\\ 1: enabled\\ 0: disabled\\', rloc: 'EFUSE_RD_REPEAT_DATA0_REG[15]', bloc: 'B5[7]'} - SOFT_DIS_JTAG : {show: y, blk : 0, word: 1, pos: 16, len : 3, start : 48, type : 'uint:3', wr_dis : 31, rd_dis: null, alt : '', dict : '', desc: 'Represents whether JTAG is disabled in soft way.\\ Odd number: disabled\\ Even number: enabled\\', rloc: 'EFUSE_RD_REPEAT_DATA0_REG[18:16]', bloc: 'B6[2:0]'} - DIS_PAD_JTAG : {show: y, blk : 0, word: 1, pos: 19, len : 1, start : 51, type : bool, wr_dis : 2, rd_dis: null, alt : '', dict : '', desc: 'Represents whether JTAG is disabled in the hard way(permanently).\\ 1: disabled\\ 0: enabled\\', rloc: 'EFUSE_RD_REPEAT_DATA0_REG[19]', bloc: 'B6[3]'} - DIS_DOWNLOAD_MANUAL_ENCRYPT : {show: y, blk : 0, word: 1, pos: 20, len : 1, start : 52, type : bool, wr_dis : 2, rd_dis: null, alt : '', dict : '', desc: 'Represents whether flash encrypt function is disabled or enabled(except in SPI boot mode).\\ 1: disabled\\ 0: enabled\\', rloc: 'EFUSE_RD_REPEAT_DATA0_REG[20]', bloc: 'B6[4]'} - USB_DREFH : {show: n, blk : 0, word: 1, pos: 21, len : 2, start : 53, type : 'uint:2', wr_dis : 30, rd_dis: null, alt : '', dict : '', desc: Represents the single-end input threshold vrefh; 1.76 V to 2 V with step of 80 mV, rloc: 'EFUSE_RD_REPEAT_DATA0_REG[22:21]', bloc: 'B6[6:5]'} - USB_DREFL : {show: n, blk : 0, word: 1, pos: 23, len : 2, start : 55, type : 'uint:2', wr_dis : 30, rd_dis: null, alt : '', dict : '', desc: Represents the single-end input threshold vrefl; 1.76 V to 2 V with step of 80 mV, rloc: 'EFUSE_RD_REPEAT_DATA0_REG[24:23]', bloc: 'B6[7],B7[0]'} - USB_EXCHG_PINS : {show: y, blk : 0, word: 1, pos: 25, len : 1, start : 57, type : bool, wr_dis : 30, rd_dis: null, alt : '', dict : '', desc: 'Represents whether the D+ and D- pins is exchanged.\\ 1: exchanged\\ 0: not exchanged\\', rloc: 'EFUSE_RD_REPEAT_DATA0_REG[25]', bloc: 'B7[1]'} - VDD_SPI_AS_GPIO : {show: y, blk : 0, word: 1, pos: 26, len : 1, start : 58, type : bool, wr_dis : 30, rd_dis: null, alt : '', dict : '', desc: 'Represents whether vdd spi pin is functioned as gpio.\\ 1: functioned\\ 0: not functioned\\', rloc: 'EFUSE_RD_REPEAT_DATA0_REG[26]', bloc: 'B7[2]'} - RESERVE_0_59 : {show: n, blk : 0, word: 1, pos: 27, len : 5, start : 59, type : 'uint:5', wr_dis: null, rd_dis: null, alt : '', dict : '', desc: Reserved; it was created by set_missed_fields_in_regs func, rloc: 'EFUSE_RD_REPEAT_DATA0_REG[31:27]', bloc: 'B7[7:3]'} - KM_DISABLE_DEPLOY_MODE : {show: y, blk : 0, word: 2, pos : 0, len : 4, start : 64, type : 'uint:4', wr_dis : 1, rd_dis: null, alt : '', dict : '', desc: 'Represents whether the deploy mode of key manager is disable or not. \\ 1: disabled \\ 0: enabled.\\', rloc: 'EFUSE_RD_REPEAT_DATA1_REG[3:0]', bloc: 'B8[3:0]'} - KM_RND_SWITCH_CYCLE : {show: y, blk : 0, word: 2, pos : 4, len : 2, start : 68, type : 'uint:2', wr_dis : 1, rd_dis: null, alt : '', dict : '', desc: 'Set the bits to control key manager random number switch cycle. 0: control by register. 1: 8 km clk cycles. 2: 16 km cycles. 3: 32 km cycles', rloc: 'EFUSE_RD_REPEAT_DATA1_REG[5:4]', bloc: 'B8[5:4]'} - KM_DEPLOY_ONLY_ONCE : {show: y, blk : 0, word: 2, pos : 6, len : 4, start : 70, type : 'uint:4', wr_dis : 1, rd_dis: null, alt : '', dict : '', desc: 'Set each bit to control whether corresponding key can only be deployed once. 1 is true; 0 is false. bit 0: ecsda; bit 1: xts; bit2: hmac; bit3: ds', rloc: 'EFUSE_RD_REPEAT_DATA1_REG[9:6]', bloc: 'B8[7:6],B9[1:0]'} - FORCE_USE_KEY_MANAGER_KEY : {show: y, blk : 0, word: 2, pos: 10, len : 4, start : 74, type : 'uint:4', wr_dis : 1, rd_dis: null, alt : '', dict : '', desc: 'Set each bit to control whether corresponding key must come from key manager. 1 is true; 0 is false. bit 0: ecsda; bit 1: xts; bit2: hmac; bit3: ds', rloc: 'EFUSE_RD_REPEAT_DATA1_REG[13:10]', bloc: 'B9[5:2]'} - FORCE_DISABLE_SW_INIT_KEY : {show: y, blk : 0, word: 2, pos: 14, len : 1, start : 78, type : bool, wr_dis : 1, rd_dis: null, alt : '', dict : '', desc: Set this bit to disable software written init key; and force use efuse_init_key, rloc: 'EFUSE_RD_REPEAT_DATA1_REG[14]', bloc: 'B9[6]'} - RESERVE_0_79 : {show: n, blk : 0, word: 2, pos: 15, len : 1, start : 79, type : bool, wr_dis: null, rd_dis: null, alt : '', dict : '', desc: Reserved; it was created by set_missed_fields_in_regs func, rloc: 'EFUSE_RD_REPEAT_DATA1_REG[15]', bloc: 'B9[7]'} - WDT_DELAY_SEL : {show: y, blk : 0, word: 2, pos: 16, len : 2, start : 80, type : 'uint:2', wr_dis : 3, rd_dis: null, alt : '', dict : '', desc: 'Represents the threshold level of the RTC watchdog STG0 timeout.\\ 0: Original threshold configuration value of STG0 *2 \\1: Original threshold configuration value of STG0 *4 \\2: Original threshold configuration value of STG0 *8 \\3: Original threshold configuration value of STG0 *16 \\', rloc: 'EFUSE_RD_REPEAT_DATA1_REG[17:16]', bloc: 'B10[1:0]'} - SPI_BOOT_CRYPT_CNT : {show: y, blk : 0, word: 2, pos: 18, len : 3, start : 82, type : 'uint:3', wr_dis : 4, rd_dis: null, alt : '', dict: '{0: "Disable", 1: "Enable", 3: "Disable", 7: "Enable"}', desc: Enables flash encryption when 1 or 3 bits are set and disables otherwise, rloc: 'EFUSE_RD_REPEAT_DATA1_REG[20:18]', bloc: 'B10[4:2]'} - SECURE_BOOT_KEY_REVOKE0 : {show: y, blk : 0, word: 2, pos: 21, len : 1, start : 85, type : bool, wr_dis : 5, rd_dis: null, alt : '', dict : '', desc: Revoke 1st secure boot key, rloc: 'EFUSE_RD_REPEAT_DATA1_REG[21]', bloc: 'B10[5]'} - SECURE_BOOT_KEY_REVOKE1 : {show: y, blk : 0, word: 2, pos: 22, len : 1, start : 86, type : bool, wr_dis : 6, rd_dis: null, alt : '', dict : '', desc: Revoke 2nd secure boot key, rloc: 'EFUSE_RD_REPEAT_DATA1_REG[22]', bloc: 'B10[6]'} - SECURE_BOOT_KEY_REVOKE2 : {show: y, blk : 0, word: 2, pos: 23, len : 1, start : 87, type : bool, wr_dis : 7, rd_dis: null, alt : '', dict : '', desc: Revoke 3rd secure boot key, rloc: 'EFUSE_RD_REPEAT_DATA1_REG[23]', bloc: 'B10[7]'} - KEY_PURPOSE_0 : {show: y, blk : 0, word: 2, pos: 24, len : 4, start : 88, type : 'uint:4', wr_dis : 8, rd_dis: null, alt : KEY0_PURPOSE, dict : '', desc: Represents the purpose of Key0, rloc: 'EFUSE_RD_REPEAT_DATA1_REG[27:24]', bloc: 'B11[3:0]'} - KEY_PURPOSE_1 : {show: y, blk : 0, word: 2, pos: 28, len : 4, start : 92, type : 'uint:4', wr_dis : 9, rd_dis: null, alt : KEY1_PURPOSE, dict : '', desc: Represents the purpose of Key1, rloc: 'EFUSE_RD_REPEAT_DATA1_REG[31:28]', bloc: 'B11[7:4]'} - KEY_PURPOSE_2 : {show: y, blk : 0, word: 3, pos : 0, len : 4, start : 96, type : 'uint:4', wr_dis : 10, rd_dis: null, alt : KEY2_PURPOSE, dict : '', desc: Represents the purpose of Key2, rloc: 'EFUSE_RD_REPEAT_DATA2_REG[3:0]', bloc: 'B12[3:0]'} - KEY_PURPOSE_3 : {show: y, blk : 0, word: 3, pos : 4, len : 4, start: 100, type : 'uint:4', wr_dis : 11, rd_dis: null, alt : KEY3_PURPOSE, dict : '', desc: Represents the purpose of Key3, rloc: 'EFUSE_RD_REPEAT_DATA2_REG[7:4]', bloc: 'B12[7:4]'} - KEY_PURPOSE_4 : {show: y, blk : 0, word: 3, pos : 8, len : 4, start: 104, type : 'uint:4', wr_dis : 12, rd_dis: null, alt : KEY4_PURPOSE, dict : '', desc: Represents the purpose of Key4, rloc: 'EFUSE_RD_REPEAT_DATA2_REG[11:8]', bloc: 'B13[3:0]'} - KEY_PURPOSE_5 : {show: y, blk : 0, word: 3, pos: 12, len : 4, start: 108, type : 'uint:4', wr_dis : 13, rd_dis: null, alt : KEY5_PURPOSE, dict : '', desc: Represents the purpose of Key5, rloc: 'EFUSE_RD_REPEAT_DATA2_REG[15:12]', bloc: 'B13[7:4]'} - SEC_DPA_LEVEL : {show: y, blk : 0, word: 3, pos: 16, len : 2, start: 112, type : 'uint:2', wr_dis : 14, rd_dis: null, alt : '', dict : '', desc: Represents the spa secure level by configuring the clock random divide mode, rloc: 'EFUSE_RD_REPEAT_DATA2_REG[17:16]', bloc: 'B14[1:0]'} - RESERVE_0_114 : {show: n, blk : 0, word: 3, pos: 18, len : 2, start: 114, type : 'uint:2', wr_dis: null, rd_dis: null, alt : '', dict : '', desc: Reserved; it was created by set_missed_fields_in_regs func, rloc: 'EFUSE_RD_REPEAT_DATA2_REG[19:18]', bloc: 'B14[3:2]'} - SECURE_BOOT_EN : {show: y, blk : 0, word: 3, pos: 20, len : 1, start: 116, type : bool, wr_dis : 15, rd_dis: null, alt : '', dict : '', desc: 'Represents whether secure boot is enabled or disabled.\\ 1: enabled\\ 0: disabled\\', rloc: 'EFUSE_RD_REPEAT_DATA2_REG[20]', bloc: 'B14[4]'} - SECURE_BOOT_AGGRESSIVE_REVOKE : {show: y, blk : 0, word: 3, pos: 21, len : 1, start: 117, type : bool, wr_dis : 16, rd_dis: null, alt : '', dict : '', desc: 'Represents whether revoking aggressive secure boot is enabled or disabled.\\ 1: enabled.\\ 0: disabled\\', rloc: 'EFUSE_RD_REPEAT_DATA2_REG[21]', bloc: 'B14[5]'} - RESERVE_0_118 : {show: n, blk : 0, word: 3, pos: 22, len : 5, start: 118, type : 'uint:5', wr_dis: null, rd_dis: null, alt : '', dict : '', desc: Reserved; it was created by set_missed_fields_in_regs func, rloc: 'EFUSE_RD_REPEAT_DATA2_REG[26:22]', bloc: 'B14[7:6],B15[2:0]'} - KM_XTS_KEY_LENGTH_256 : {show: y, blk : 0, word: 3, pos: 27, len : 1, start: 123, type : bool, wr_dis : 1, rd_dis: null, alt : '', dict : '', desc: Set this bitto configure flash encryption use xts-128 key. else use xts-256 key, rloc: 'EFUSE_RD_REPEAT_DATA2_REG[27]', bloc: 'B15[3]'} - FLASH_TPUW : {show: y, blk : 0, word: 3, pos: 28, len : 4, start: 124, type : 'uint:4', wr_dis : 18, rd_dis: null, alt : '', dict : '', desc: Represents the flash waiting time after power-up; in unit of ms. When the value less than 15; the waiting time is the programmed value. Otherwise; the waiting time is 2 times the programmed value, rloc: 'EFUSE_RD_REPEAT_DATA2_REG[31:28]', bloc: 'B15[7:4]'} - DIS_DOWNLOAD_MODE : {show: y, blk : 0, word: 4, pos : 0, len : 1, start: 128, type : bool, wr_dis : 18, rd_dis: null, alt : '', dict : '', desc: 'Represents whether Download mode is disabled or enabled.\\ 1: disabled\\ 0: enabled\\', rloc: 'EFUSE_RD_REPEAT_DATA3_REG[0]', bloc: 'B16[0]'} - DIS_DIRECT_BOOT : {show: y, blk : 0, word: 4, pos : 1, len : 1, start: 129, type : bool, wr_dis : 18, rd_dis: null, alt : '', dict : '', desc: 'Represents whether direct boot mode is disabled or enabled.\\ 1: disabled\\ 0: enabled\\', rloc: 'EFUSE_RD_REPEAT_DATA3_REG[1]', bloc: 'B16[1]'} - DIS_USB_SERIAL_JTAG_ROM_PRINT : {show: y, blk : 0, word: 4, pos : 2, len : 1, start: 130, type : bool, wr_dis : 18, rd_dis: null, alt : '', dict : '', desc: 'Represents whether print from USB-Serial-JTAG is disabled or enabled.\\ 1: disabled\\ 0: enabled\\', rloc: 'EFUSE_RD_REPEAT_DATA3_REG[2]', bloc: 'B16[2]'} - LOCK_KM_KEY : {show: y, blk : 0, word: 4, pos : 3, len : 1, start: 131, type : bool, wr_dis : 1, rd_dis: null, alt : '', dict : '', desc: 'Represetns whether to lock the efuse xts key.\\ 1. Lock\\ 0: Unlock\\', rloc: 'EFUSE_RD_REPEAT_DATA3_REG[3]', bloc: 'B16[3]'} - DIS_USB_SERIAL_JTAG_DOWNLOAD_MODE: {show: y, blk : 0, word: 4, pos : 4, len : 1, start: 132, type : bool, wr_dis : 18, rd_dis: null, alt : '', dict : '', desc: 'Represents whether the USB-Serial-JTAG download function is disabled or enabled.\\ 1: Disable\\ 0: Enable\\', rloc: 'EFUSE_RD_REPEAT_DATA3_REG[4]', bloc: 'B16[4]'} - ENABLE_SECURITY_DOWNLOAD : {show: y, blk : 0, word: 4, pos : 5, len : 1, start: 133, type : bool, wr_dis : 18, rd_dis: null, alt : '', dict : '', desc: 'Represents whether security download is enabled or disabled.\\ 1: enabled\\ 0: disabled\\', rloc: 'EFUSE_RD_REPEAT_DATA3_REG[5]', bloc: 'B16[5]'} - UART_PRINT_CONTROL : {show: y, blk : 0, word: 4, pos : 6, len : 2, start: 134, type : 'uint:2', wr_dis : 18, rd_dis: null, alt : '', dict: '{0: "Enable", 1: "Enable when GPIO8 is low at reset", 2: "Enable when GPIO8 is high at reset", 3: "Disable"}', desc: Set the default UARTboot message output mode, rloc: 'EFUSE_RD_REPEAT_DATA3_REG[7:6]', bloc: 'B16[7:6]'} - FORCE_SEND_RESUME : {show: y, blk : 0, word: 4, pos : 8, len : 1, start: 136, type : bool, wr_dis : 18, rd_dis: null, alt : '', dict : '', desc: 'Represents whether ROM code is forced to send a resume command during SPI boot.\\ 1: forced\\ 0:not forced\\', rloc: 'EFUSE_RD_REPEAT_DATA3_REG[8]', bloc: 'B17[0]'} - SECURE_VERSION : {show: y, blk : 0, word: 4, pos : 9, len : 16, start: 137, type : 'uint:16', wr_dis : 18, rd_dis: null, alt : '', dict : '', desc: Represents the version used by ESP-IDF anti-rollback feature, rloc: 'EFUSE_RD_REPEAT_DATA3_REG[24:9]', bloc: 'B17[7:1],B18,B19[0]'} - SECURE_BOOT_DISABLE_FAST_WAKE : {show: y, blk : 0, word: 4, pos: 25, len : 1, start: 153, type : bool, wr_dis : 18, rd_dis: null, alt : '', dict : '', desc: 'Represents whether FAST VERIFY ON WAKE is disabled or enabled when Secure Boot is enabled.\\ 1: disabled\\ 0: enabled\\', rloc: 'EFUSE_RD_REPEAT_DATA3_REG[25]', bloc: 'B19[1]'} - HYS_EN_PAD : {show: y, blk : 0, word: 4, pos: 26, len : 1, start: 154, type : bool, wr_dis : 2, rd_dis: null, alt : '', dict : '', desc: 'Represents whether the hysteresis function of corresponding PAD is enabled.\\ 1: enabled\\ 0:disabled\\', rloc: 'EFUSE_RD_REPEAT_DATA3_REG[26]', bloc: 'B19[2]'} - XTS_DPA_PSEUDO_LEVEL : {show: y, blk : 0, word: 4, pos: 27, len : 2, start: 155, type : 'uint:2', wr_dis : 14, rd_dis: null, alt : '', dict : '', desc: 'Represents the pseudo round level of xts-aes anti-dpa attack.\\ 3: High.\\ 2: Moderate 1. Low\\ 0: Disabled\\', rloc: 'EFUSE_RD_REPEAT_DATA3_REG[28:27]', bloc: 'B19[4:3]'} - XTS_DPA_CLK_ENABLE : {show: y, blk : 0, word: 4, pos: 29, len : 1, start: 157, type : bool, wr_dis : 14, rd_dis: null, alt : '', dict : '', desc: 'Represents whether xts-aes anti-dpa attack clock is enabled.\\ 1. Enable.\\ 0: Disable.\\', rloc: 'EFUSE_RD_REPEAT_DATA3_REG[29]', bloc: 'B19[5]'} - RESERVE_0_158 : {show: n, blk : 0, word: 4, pos: 30, len : 2, start: 158, type : 'uint:2', wr_dis: null, rd_dis: null, alt : '', dict : '', desc: Reserved; it was created by set_missed_fields_in_regs func, rloc: 'EFUSE_RD_REPEAT_DATA3_REG[31:30]', bloc: 'B19[7:6]'} - HUK_GEN_STATE : {show: y, blk : 0, word: 5, pos : 0, len : 9, start: 160, type : 'uint:9', wr_dis : 19, rd_dis: null, alt : '', dict : '', desc: Set the bits to control validation of HUK generate mode.\\ Odd of 1 is invalid.\\ Even of 1 is valid.\\, rloc: 'EFUSE_RD_REPEAT_DATA4_REG[8:0]', bloc: 'B20,B21[0]'} - XTAL_48M_SEL : {show: y, blk : 0, word: 5, pos : 9, len : 3, start: 169, type : 'uint:3', wr_dis : 17, rd_dis: null, alt : '', dict : '', desc: 'Represents whether XTAL frequency is 48MHz or not. If not; 40MHz XTAL will be used. If this field contains Odd number bit 1: Enable 48MHz XTAL\ Even number bit 1: Enable 40MHz XTAL', rloc: 'EFUSE_RD_REPEAT_DATA4_REG[11:9]', bloc: 'B21[3:1]'} - XTAL_48M_SEL_MODE : {show: y, blk : 0, word: 5, pos: 12, len : 1, start: 172, type : bool, wr_dis : 17, rd_dis: null, alt : '', dict : '', desc: 'Specify the XTAL frequency selection is decided by eFuse or strapping-PAD-state. 1: eFuse\\ 0: strapping-PAD-state', rloc: 'EFUSE_RD_REPEAT_DATA4_REG[12]', bloc: 'B21[4]'} - ECDSA_DISABLE_P192 : {show: y, blk : 0, word: 5, pos: 13, len : 1, start: 173, type : bool, wr_dis : 14, rd_dis: null, alt : '', dict : '', desc: 'Represents whether to disable P192 curve in ECDSA.\\ 1: Disabled.\\ 0: Not disable', rloc: 'EFUSE_RD_REPEAT_DATA4_REG[13]', bloc: 'B21[5]'} - ECC_FORCE_CONST_TIME : {show: y, blk : 0, word: 5, pos: 14, len : 1, start: 174, type : bool, wr_dis : 14, rd_dis: null, alt : '', dict : '', desc: 'Represents whether to force ecc to use const-time calculation mode. \\ 1: Enable. \\ 0: Disable', rloc: 'EFUSE_RD_REPEAT_DATA4_REG[14]', bloc: 'B21[6]'} - RESERVE_0_175 : {show: n, blk : 0, word: 5, pos: 15, len : 17, start: 175, type : 'uint:17', wr_dis: null, rd_dis: null, alt : '', dict : '', desc: Reserved; it was created by set_missed_fields_in_regs func, rloc: 'EFUSE_RD_REPEAT_DATA4_REG[31:15]', bloc: 'B21[7],B22,B23'} - MAC : {show: y, blk : 1, word: 0, pos : 0, len : 48, start : 0, type : 'bytes:6', wr_dis : 20, rd_dis: null, alt : MAC_FACTORY, dict : '', desc: MAC address, rloc: EFUSE_RD_MAC_SYS0_REG, bloc: 'B0,B1,B2,B3,B4,B5'} - MAC_EXT : {show: y, blk : 1, word: 1, pos: 16, len : 16, start : 48, type : 'bytes:2', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: Represents the extended bits of MAC address, rloc: 'EFUSE_RD_MAC_SYS1_REG[31:16]', bloc: 'B6,B7'} - WAFER_VERSION_MINOR : {show: y, blk : 1, word: 2, pos : 0, len : 4, start : 64, type : 'uint:4', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: Minor chip version, rloc: 'EFUSE_RD_MAC_SYS2_REG[3:0]', bloc: 'B8[3:0]'} - WAFER_VERSION_MAJOR : {show: y, blk : 1, word: 2, pos : 4, len : 2, start : 68, type : 'uint:2', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: Minor chip version, rloc: 'EFUSE_RD_MAC_SYS2_REG[5:4]', bloc: 'B8[5:4]'} - DISABLE_WAFER_VERSION_MAJOR : {show: y, blk : 1, word: 2, pos : 6, len : 1, start : 70, type : bool, wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: Disables check of wafer version major, rloc: 'EFUSE_RD_MAC_SYS2_REG[6]', bloc: 'B8[6]'} - DISABLE_BLK_VERSION_MAJOR : {show: y, blk : 1, word: 2, pos : 7, len : 1, start : 71, type : bool, wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: Disables check of blk version major, rloc: 'EFUSE_RD_MAC_SYS2_REG[7]', bloc: 'B8[7]'} - BLK_VERSION_MINOR : {show: y, blk : 1, word: 2, pos : 8, len : 3, start : 72, type : 'uint:3', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: BLK_VERSION_MINOR of BLOCK2, rloc: 'EFUSE_RD_MAC_SYS2_REG[10:8]', bloc: 'B9[2:0]'} - BLK_VERSION_MAJOR : {show: y, blk : 1, word: 2, pos: 11, len : 2, start : 75, type : 'uint:2', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: BLK_VERSION_MAJOR of BLOCK2, rloc: 'EFUSE_RD_MAC_SYS2_REG[12:11]', bloc: 'B9[4:3]'} - FLASH_CAP : {show: y, blk : 1, word: 2, pos: 13, len : 3, start : 77, type : 'uint:3', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: Flash capacity, rloc: 'EFUSE_RD_MAC_SYS2_REG[15:13]', bloc: 'B9[7:5]'} - FLASH_VENDOR : {show: y, blk : 1, word: 2, pos: 16, len : 3, start : 80, type : 'uint:3', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: Flash vendor, rloc: 'EFUSE_RD_MAC_SYS2_REG[18:16]', bloc: 'B10[2:0]'} - PSRAM_CAP : {show: y, blk : 1, word: 2, pos: 19, len : 3, start : 83, type : 'uint:3', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: Psram capacity, rloc: 'EFUSE_RD_MAC_SYS2_REG[21:19]', bloc: 'B10[5:3]'} - PSRAM_VENDOR : {show: y, blk : 1, word: 2, pos: 22, len : 2, start : 86, type : 'uint:2', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: Psram vendor, rloc: 'EFUSE_RD_MAC_SYS2_REG[23:22]', bloc: 'B10[7:6]'} - TEMP : {show: y, blk : 1, word: 2, pos: 24, len : 2, start : 88, type : 'uint:2', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: Temp (die embedded inside), rloc: 'EFUSE_RD_MAC_SYS2_REG[25:24]', bloc: 'B11[1:0]'} - PKG_VERSION : {show: y, blk : 1, word: 2, pos: 26, len : 3, start : 90, type : 'uint:3', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: Package version, rloc: 'EFUSE_RD_MAC_SYS2_REG[28:26]', bloc: 'B11[4:2]'} - PA_TRIM_VERSION : {show: y, blk : 1, word: 2, pos: 29, len : 3, start : 93, type : 'uint:3', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: PADC CAL PA trim version, rloc: 'EFUSE_RD_MAC_SYS2_REG[31:29]', bloc: 'B11[7:5]'} - TRIM_N_BIAS : {show: y, blk : 1, word: 3, pos : 0, len : 5, start : 96, type : 'uint:5', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: PADC CAL N bias, rloc: 'EFUSE_RD_MAC_SYS3_REG[4:0]', bloc: 'B12[4:0]'} - TRIM_P_BIAS : {show: y, blk : 1, word: 3, pos : 5, len : 5, start: 101, type : 'uint:5', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: PADC CAL P bias, rloc: 'EFUSE_RD_MAC_SYS3_REG[9:5]', bloc: 'B12[7:5],B13[1:0]'} - RESERVED_1_106 : {show: n, blk : 1, word: 3, pos: 10, len : 8, start: 106, type : 'uint:8', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: reserved, rloc: 'EFUSE_RD_MAC_SYS3_REG[17:10]', bloc: 'B13[7:2],B14[1:0]'} - SYS_DATA_PART0_0 : {show: n, blk : 1, word: 3, pos: 18, len : 14, start: 114, type : 'uint:14', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: Represents the first 14-bit of zeroth part of system data, rloc: 'EFUSE_RD_MAC_SYS3_REG[31:18]', bloc: 'B14[7:2],B15'} - SYS_DATA_PART0_1 : {show: n, blk : 1, word: 4, pos : 0, len : 32, start: 128, type : 'uint:32', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: Represents the first 14-bit of zeroth part of system data, rloc: EFUSE_RD_MAC_SYS4_REG, bloc: 'B16,B17,B18,B19'} - SYS_DATA_PART0_2 : {show: n, blk : 1, word: 5, pos : 0, len : 32, start: 160, type : 'uint:32', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: Represents the second 32-bit of zeroth part of system data, rloc: EFUSE_RD_MAC_SYS5_REG, bloc: 'B20,B21,B22,B23'} - OPTIONAL_UNIQUE_ID : {show: y, blk : 2, word: 0, pos : 0, len: 128, start : 0, type: 'bytes:16', wr_dis : 21, rd_dis: null, alt : '', dict : '', desc: Optional unique 128-bit ID, rloc: EFUSE_RD_SYS_PART1_DATA0_REG, bloc: 'B0,B1,B2,B3,B4,B5,B6,B7,B8,B9,B10,B11,B12,B13,B14,B15'} - RESERVED_2_128 : {show: n, blk : 2, word: 4, pos : 0, len : 9, start: 128, type : 'uint:9', wr_dis : 21, rd_dis: null, alt : '', dict : '', desc: reserved, rloc: 'EFUSE_RD_SYS_PART1_DATA4_REG[8:0]', bloc: 'B16,B17[0]'} - OCODE : {show: y, blk : 2, word: 4, pos : 9, len : 8, start: 137, type : 'uint:8', wr_dis : 21, rd_dis: null, alt : '', dict : '', desc: ADC OCode, rloc: 'EFUSE_RD_SYS_PART1_DATA4_REG[16:9]', bloc: 'B17[7:1],B18[0]'} - RESERVED_2_145 : {show: n, blk : 2, word: 4, pos: 17, len : 15, start: 145, type : 'uint:15', wr_dis : 21, rd_dis: null, alt : '', dict : '', desc: reserved, rloc: 'EFUSE_RD_SYS_PART1_DATA4_REG[31:17]', bloc: 'B18[7:1],B19'} - SYS_DATA_PART1_5 : {show: n, blk : 2, word: 5, pos : 0, len : 32, start: 160, type : 'uint:32', wr_dis : 21, rd_dis: null, alt : '', dict : '', desc: Represents the zeroth 32-bit of first part of system data, rloc: EFUSE_RD_SYS_PART1_DATA5_REG, bloc: 'B20,B21,B22,B23'} - SYS_DATA_PART1_6 : {show: n, blk : 2, word: 6, pos : 0, len : 32, start: 192, type : 'uint:32', wr_dis : 21, rd_dis: null, alt : '', dict : '', desc: Represents the zeroth 32-bit of first part of system data, rloc: EFUSE_RD_SYS_PART1_DATA6_REG, bloc: 'B24,B25,B26,B27'} - SYS_DATA_PART1_7 : {show: n, blk : 2, word: 7, pos : 0, len : 32, start: 224, type : 'uint:32', wr_dis : 21, rd_dis: null, alt : '', dict : '', desc: Represents the zeroth 32-bit of first part of system data, rloc: EFUSE_RD_SYS_PART1_DATA7_REG, bloc: 'B28,B29,B30,B31'} - BLOCK_USR_DATA : {show: y, blk : 3, word: 0, pos : 0, len: 192, start : 0, type: 'bytes:24', wr_dis : 22, rd_dis: null, alt : USER_DATA, dict : '', desc: User data, rloc: EFUSE_RD_USR_DATA0_REG, bloc: 'B0,B1,B2,B3,B4,B5,B6,B7,B8,B9,B10,B11,B12,B13,B14,B15,B16,B17,B18,B19,B20,B21,B22,B23'} - RESERVED_3_192 : {show: n, blk : 3, word: 6, pos : 0, len : 8, start: 192, type : 'uint:8', wr_dis : 22, rd_dis: null, alt : '', dict : '', desc: reserved, rloc: 'EFUSE_RD_USR_DATA6_REG[7:0]', bloc: B24} - CUSTOM_MAC : {show: y, blk : 3, word: 6, pos : 8, len : 48, start: 200, type : 'bytes:6', wr_dis : 22, rd_dis: null, alt: MAC_CUSTOM USER_DATA_MAC_CUSTOM, dict : '', desc: Custom MAC, rloc: 'EFUSE_RD_USR_DATA6_REG[31:8]', bloc: 'B25,B26,B27,B28,B29,B30'} - RESERVED_3_248 : {show: n, blk : 3, word: 7, pos: 24, len : 8, start: 248, type : 'uint:8', wr_dis : 22, rd_dis: null, alt : '', dict : '', desc: reserved, rloc: 'EFUSE_RD_USR_DATA7_REG[31:24]', bloc: B31} - BLOCK_KEY0 : {show: y, blk : 4, word: 0, pos : 0, len: 256, start : 0, type: 'bytes:32', wr_dis : 23, rd_dis : 0, alt : KEY0, dict : '', desc: Key0 or user data, rloc: EFUSE_RD_KEY0_DATA0_REG, bloc: 'B0,B1,B2,B3,B4,B5,B6,B7,B8,B9,B10,B11,B12,B13,B14,B15,B16,B17,B18,B19,B20,B21,B22,B23,B24,B25,B26,B27,B28,B29,B30,B31'} - BLOCK_KEY1 : {show: y, blk : 5, word: 0, pos : 0, len: 256, start : 0, type: 'bytes:32', wr_dis : 24, rd_dis : 1, alt : KEY1, dict : '', desc: Key1 or user data, rloc: EFUSE_RD_KEY1_DATA0_REG, bloc: 'B0,B1,B2,B3,B4,B5,B6,B7,B8,B9,B10,B11,B12,B13,B14,B15,B16,B17,B18,B19,B20,B21,B22,B23,B24,B25,B26,B27,B28,B29,B30,B31'} - BLOCK_KEY2 : {show: y, blk : 6, word: 0, pos : 0, len: 256, start : 0, type: 'bytes:32', wr_dis : 25, rd_dis : 2, alt : KEY2, dict : '', desc: Key2 or user data, rloc: EFUSE_RD_KEY2_DATA0_REG, bloc: 'B0,B1,B2,B3,B4,B5,B6,B7,B8,B9,B10,B11,B12,B13,B14,B15,B16,B17,B18,B19,B20,B21,B22,B23,B24,B25,B26,B27,B28,B29,B30,B31'} - BLOCK_KEY3 : {show: y, blk : 7, word: 0, pos : 0, len: 256, start : 0, type: 'bytes:32', wr_dis : 26, rd_dis : 3, alt : KEY3, dict : '', desc: Key3 or user data, rloc: EFUSE_RD_KEY3_DATA0_REG, bloc: 'B0,B1,B2,B3,B4,B5,B6,B7,B8,B9,B10,B11,B12,B13,B14,B15,B16,B17,B18,B19,B20,B21,B22,B23,B24,B25,B26,B27,B28,B29,B30,B31'} - BLOCK_KEY4 : {show: y, blk : 8, word: 0, pos : 0, len: 256, start : 0, type: 'bytes:32', wr_dis : 27, rd_dis : 4, alt : KEY4, dict : '', desc: Key4 or user data, rloc: EFUSE_RD_KEY4_DATA0_REG, bloc: 'B0,B1,B2,B3,B4,B5,B6,B7,B8,B9,B10,B11,B12,B13,B14,B15,B16,B17,B18,B19,B20,B21,B22,B23,B24,B25,B26,B27,B28,B29,B30,B31'} - BLOCK_KEY5 : {show: y, blk : 9, word: 0, pos : 0, len: 256, start : 0, type: 'bytes:32', wr_dis : 28, rd_dis : 5, alt : KEY5, dict : '', desc: Key5 or user data, rloc: EFUSE_RD_KEY5_DATA0_REG, bloc: 'B0,B1,B2,B3,B4,B5,B6,B7,B8,B9,B10,B11,B12,B13,B14,B15,B16,B17,B18,B19,B20,B21,B22,B23,B24,B25,B26,B27,B28,B29,B30,B31'} - BLOCK_SYS_DATA2 : {show: y, blk: 10, word: 0, pos : 0, len: 256, start : 0, type: 'bytes:32', wr_dis : 29, rd_dis : 6, alt : SYS_DATA_PART2, dict : '', desc: System data part 2 (reserved), rloc: EFUSE_RD_SYS_PART2_DATA0_REG, bloc: 'B0,B1,B2,B3,B4,B5,B6,B7,B8,B9,B10,B11,B12,B13,B14,B15,B16,B17,B18,B19,B20,B21,B22,B23,B24,B25,B26,B27,B28,B29,B30,B31'} + WR_DIS : {show: y, blk : 0, word: 0, pos : 0, len : 32, start : 0, type : 'uint:32', wr_dis: null, rd_dis: null, alt : '', dict : '', desc: Disable programming of individual eFuses, rloc: EFUSE_RD_WR_DIS_REG, bloc: 'B0,B1,B2,B3'} + RD_DIS : {show: y, blk : 0, word: 1, pos : 0, len : 7, start : 32, type : 'uint:7', wr_dis : 0, rd_dis: null, alt : '', dict : '', desc: Disable reading from BlOCK4-10, rloc: 'EFUSE_RD_REPEAT_DATA0_REG[6:0]', bloc: 'B4[6:0]'} + BOOTLOADER_ANTI_ROLLBACK_SECURE_VERSION_HI: {show: y, blk : 0, word: 1, pos : 7, len : 1, start : 39, type : bool, wr_dis: null, rd_dis: null, alt : '', dict : '', desc: Represents the anti-rollback secure version of the 2nd stage bootloader used by the ROM bootloader (the high part of the field), rloc: 'EFUSE_RD_REPEAT_DATA0_REG[7]', bloc: 'B4[7]'} + DIS_ICACHE : {show: y, blk : 0, word: 1, pos : 8, len : 1, start : 40, type : bool, wr_dis : 2, rd_dis: null, alt : '', dict : '', desc: 'Represents whether cache is disabled. 1: Disabled 0: Enabled', rloc: 'EFUSE_RD_REPEAT_DATA0_REG[8]', bloc: 'B5[0]'} + DIS_USB_JTAG : {show: y, blk : 0, word: 1, pos : 9, len : 1, start : 41, type : bool, wr_dis : 2, rd_dis: null, alt : '', dict : '', desc: 'Represents whether the USB-to-JTAG function in USB Serial/JTAG is disabled. Note that \hyperref[fielddesc:EFUSEDISUSBJTAG]{EFUSE\_DIS\_USB\_JTAG} is available only when \hyperref[fielddesc:EFUSEDISUSBSERIALJTAG]{EFUSE\_DIS\_USB\_SERIAL\_JTAG} is configured to 0. For more information; please refer to Chapter \ref{mod:bootctrl} \textit{\nameref{mod:bootctrl}}.1: Disabled0: Enabled', rloc: 'EFUSE_RD_REPEAT_DATA0_REG[9]', bloc: 'B5[1]'} + BOOTLOADER_ANTI_ROLLBACK_EN : {show: y, blk : 0, word: 1, pos: 10, len : 1, start : 42, type : bool, wr_dis: null, rd_dis: null, alt : '', dict : '', desc: 'Represents whether the ani-rollback check for the 2nd stage bootloader is enabled.1: Enabled0: Disabled', rloc: 'EFUSE_RD_REPEAT_DATA0_REG[10]', bloc: 'B5[2]'} + DIS_USB_SERIAL_JTAG : {show: n, blk : 0, word: 1, pos: 11, len : 1, start : 43, type : bool, wr_dis : 2, rd_dis: null, alt : '', dict : '', desc: 'Represents whether USB Serial/JTAG is disabled.1: Disabled0: Enabled', rloc: 'EFUSE_RD_REPEAT_DATA0_REG[11]', bloc: 'B5[3]'} + DIS_FORCE_DOWNLOAD : {show: y, blk : 0, word: 1, pos: 12, len : 1, start : 44, type : bool, wr_dis : 2, rd_dis: null, alt : '', dict : '', desc: 'Represents whether the function that forces chip into Download mode is disabled. 1: Disabled0: Enabled', rloc: 'EFUSE_RD_REPEAT_DATA0_REG[12]', bloc: 'B5[4]'} + SPI_DOWNLOAD_MSPI_DIS : {show: y, blk : 0, word: 1, pos: 13, len : 1, start : 45, type : bool, wr_dis : 2, rd_dis: null, alt : '', dict : '', desc: 'Represents whether SPI0 controller during boot\_mode\_download is disabled.0: Enabled1: Disabled', rloc: 'EFUSE_RD_REPEAT_DATA0_REG[13]', bloc: 'B5[5]'} + DIS_TWAI : {show: y, blk : 0, word: 1, pos: 14, len : 1, start : 46, type : bool, wr_dis : 2, rd_dis: null, alt : '', dict : '', desc: "Represents whether TWAI$^\xAE$ function is disabled.1: Disabled0: Enabled", rloc: 'EFUSE_RD_REPEAT_DATA0_REG[14]', bloc: 'B5[6]'} + JTAG_SEL_ENABLE : {show: y, blk : 0, word: 1, pos: 15, len : 1, start : 47, type : bool, wr_dis : 2, rd_dis: null, alt : '', dict : '', desc: 'Represents whether the selection of a JTAG signal source through the strapping pin value is enabled when all of \hyperref[fielddesc:EFUSEDISPADJTAG]{EFUSE\_DIS\_PAD\_JTAG}; \hyperref[fielddesc:EFUSEDISUSBJTAG]{EFUSE\_DIS\_USB\_JTAG} and \hyperref[fielddesc:EFUSEDISUSBSERIALJTAG]{EFUSE\_DIS\_USB\_SERIAL\_JTAG} are configured to 0. For more information; please refer to Chapter \ref{mod:bootctrl} \textit{\nameref{mod:bootctrl}}.1: Enabled0: Disabled', rloc: 'EFUSE_RD_REPEAT_DATA0_REG[15]', bloc: 'B5[7]'} + SOFT_DIS_JTAG : {show: y, blk : 0, word: 1, pos: 16, len : 3, start : 48, type : 'uint:3', wr_dis : 31, rd_dis: null, alt : '', dict : '', desc: 'Represents whether PAD JTAG is disabled in the soft way. It can be restarted via HMAC. Odd count of bits with a value of 1: DisabledEven count of bits with a value of 1: Enabled', rloc: 'EFUSE_RD_REPEAT_DATA0_REG[18:16]', bloc: 'B6[2:0]'} + DIS_PAD_JTAG : {show: y, blk : 0, word: 1, pos: 19, len : 1, start : 51, type : bool, wr_dis : 2, rd_dis: null, alt : '', dict : '', desc: 'Represents whether PAD JTAG is disabled in the hard way (permanently).1: Disabled0: Enabled', rloc: 'EFUSE_RD_REPEAT_DATA0_REG[19]', bloc: 'B6[3]'} + DIS_DOWNLOAD_MANUAL_ENCRYPT : {show: y, blk : 0, word: 1, pos: 20, len : 1, start : 52, type : bool, wr_dis : 2, rd_dis: null, alt : '', dict : '', desc: 'Represents whether flash encryption is disabled (except in SPI boot mode).1: Disabled0: Enabled', rloc: 'EFUSE_RD_REPEAT_DATA0_REG[20]', bloc: 'B6[4]'} + USB_DREFH : {show: n, blk : 0, word: 1, pos: 21, len : 2, start : 53, type : 'uint:2', wr_dis : 30, rd_dis: null, alt : '', dict : '', desc: Represents the single-end input threshold vrefh; 1.76 V to 2 V with step of 80 mV, rloc: 'EFUSE_RD_REPEAT_DATA0_REG[22:21]', bloc: 'B6[6:5]'} + USB_DREFL : {show: n, blk : 0, word: 1, pos: 23, len : 2, start : 55, type : 'uint:2', wr_dis : 30, rd_dis: null, alt : '', dict : '', desc: Represents the single-end input threshold vrefl; 1.76 V to 2 V with step of 80 mV, rloc: 'EFUSE_RD_REPEAT_DATA0_REG[24:23]', bloc: 'B6[7],B7[0]'} + USB_EXCHG_PINS : {show: y, blk : 0, word: 1, pos: 25, len : 1, start : 57, type : bool, wr_dis : 30, rd_dis: null, alt : '', dict : '', desc: 'Represents whether the D+ and D- pins is exchanged.1: Exchanged0: Not exchanged', rloc: 'EFUSE_RD_REPEAT_DATA0_REG[25]', bloc: 'B7[1]'} + VDD_SPI_AS_GPIO : {show: y, blk : 0, word: 1, pos: 26, len : 1, start : 58, type : bool, wr_dis : 30, rd_dis: null, alt : '', dict : '', desc: 'Represents whether VDD SPI pin is functioned as GPIO.1: Functioned0: Not functioned', rloc: 'EFUSE_RD_REPEAT_DATA0_REG[26]', bloc: 'B7[2]'} + WDT_DELAY_SEL : {show: y, blk : 0, word: 1, pos: 27, len : 2, start : 59, type : 'uint:2', wr_dis : 3, rd_dis: null, alt : '', dict : '', desc: "Represents RTC watchdog timeout threshold.0: The originally configured STG0 threshold \xD7 21: The originally configured STG0 threshold \xD7 42: The originally configured STG0 threshold \xD7 83: The originally configured STG0 threshold \xD7 16", rloc: 'EFUSE_RD_REPEAT_DATA0_REG[28:27]', bloc: 'B7[4:3]'} + BOOTLOADER_ANTI_ROLLBACK_SECURE_VERSION_LO: {show: y, blk : 0, word: 1, pos: 29, len : 3, start : 61, type : 'uint:3', wr_dis: null, rd_dis: null, alt : '', dict : '', desc: Represents the anti-rollback secure version of the 2nd stage bootloader used by the ROM bootloader (the low part of the field), rloc: 'EFUSE_RD_REPEAT_DATA0_REG[31:29]', bloc: 'B7[7:5]'} + KM_DISABLE_DEPLOY_MODE : {show: y, blk : 0, word: 2, pos : 0, len : 4, start : 64, type : 'uint:4', wr_dis : 1, rd_dis: null, alt : '', dict : '', desc: 'Represents whether the new key deployment of key manager is disabled. Bit0: Represents whether the new ECDSA key deployment is disabled0: Enabled1: DisabledBit1: Represents whether the new XTS-AES (flash and PSRAM) key deployment is disabled0: Enabled1: DisabledBit2: Represents whether the new HMAC key deployment is disabled0: Enabled1: DisabledBit3: Represents whether the new DS key deployment is disabled0: Enabled1: Disabled', rloc: 'EFUSE_RD_REPEAT_DATA1_REG[3:0]', bloc: 'B8[3:0]'} + KM_RND_SWITCH_CYCLE : {show: y, blk : 0, word: 2, pos : 4, len : 2, start : 68, type : 'uint:2', wr_dis : 1, rd_dis: null, alt : '', dict : '', desc: 'Represents the cycle at which the Key Manager switches random numbers.0: Controlled by the \hyperref[fielddesc:KEYMNGRNDSWITCHCYCLE]{KEYMNG\_RND\_SWITCH\_CYCLE} register. For more information; please refer to Chapter \ref{mod:keymng} \textit{\nameref{mod:keymng}}1: 8 Key Manager clock cycles2: 16 Key Manager clock cycles3: 32 Key Manager clock cycles', rloc: 'EFUSE_RD_REPEAT_DATA1_REG[5:4]', bloc: 'B8[5:4]'} + KM_DEPLOY_ONLY_ONCE : {show: y, blk : 0, word: 2, pos : 6, len : 4, start : 70, type : 'uint:4', wr_dis : 1, rd_dis: null, alt : '', dict : '', desc: 'Represents whether the corresponding key can be deployed only once.Bit0: Represents whether the ECDSA key can be deployed only once0: The key can be deployed multiple times1: The key can be deployed only onceBit1: Represents whether the XTS-AES (flash and PSRAM) key can be deployed only once0: The key can be deployed multiple times1: The key can be deployed only onceBit2: Represents whether the HMAC key can be deployed only once0: The key can be deployed multiple times1: The key can be deployed only onceBit3: Represents whether the DS key can be deployed only once0: The key can be deployed multiple times1: The key can be deployed only once', rloc: 'EFUSE_RD_REPEAT_DATA1_REG[9:6]', bloc: 'B8[7:6],B9[1:0]'} + FORCE_USE_KEY_MANAGER_KEY : {show: y, blk : 0, word: 2, pos: 10, len : 4, start : 74, type : 'uint:4', wr_dis : 1, rd_dis: null, alt : '', dict : '', desc: 'Represents whether the corresponding key must come from Key Manager. Bit0: Represents whether the ECDSA key must come from Key Manager.0: The key does not need to come from Key Manager1: The key must come from Key ManagerBit1: Represents whether the XTS-AES (flash and PSRAM) key must come from Key Manager.0: The key does not need to come from Key Manager1: The key must come from Key ManagerBit2: Represents whether the HMAC key must come from Key Manager.0: The key does not need to come from Key Manager1: The key must come from Key ManagerBit3: Represents whether the DS key must come from Key Manager.0: The key does not need to come from Key Manager1: The key must come from Key Manager', rloc: 'EFUSE_RD_REPEAT_DATA1_REG[13:10]', bloc: 'B9[5:2]'} + FORCE_DISABLE_SW_INIT_KEY : {show: y, blk : 0, word: 2, pos: 14, len : 1, start : 78, type : bool, wr_dis : 1, rd_dis: null, alt : '', dict : '', desc: 'Represents whether to disable the use of the initialization key written by software and instead force use efuse\_init\_key.0: Enable1: Disable', rloc: 'EFUSE_RD_REPEAT_DATA1_REG[14]', bloc: 'B9[6]'} + BOOTLOADER_ANTI_ROLLBACK_UPDATE_IN_ROM : {show: y, blk : 0, word: 2, pos: 15, len : 1, start : 79, type : bool, wr_dis: null, rd_dis: null, alt : '', dict : '', desc: 'Represents whether the ani-rollback SECURE_VERSION will be updated from the ROM bootloader.1: Enable0: Disable', rloc: 'EFUSE_RD_REPEAT_DATA1_REG[15]', bloc: 'B9[7]'} + SPI_BOOT_CRYPT_CNT : {show: y, blk : 0, word: 2, pos: 16, len : 3, start : 80, type : 'uint:3', wr_dis : 4, rd_dis: null, alt : '', dict: '{0: "Disable", 1: "Enable", 3: "Disable", 7: "Enable"}', desc: Enables flash encryption when 1 or 3 bits are set and disables otherwise, rloc: 'EFUSE_RD_REPEAT_DATA1_REG[18:16]', bloc: 'B10[2:0]'} + SECURE_BOOT_KEY_REVOKE0 : {show: y, blk : 0, word: 2, pos: 19, len : 1, start : 83, type : bool, wr_dis : 5, rd_dis: null, alt : '', dict : '', desc: Revoke 1st secure boot key, rloc: 'EFUSE_RD_REPEAT_DATA1_REG[19]', bloc: 'B10[3]'} + SECURE_BOOT_KEY_REVOKE1 : {show: y, blk : 0, word: 2, pos: 20, len : 1, start : 84, type : bool, wr_dis : 6, rd_dis: null, alt : '', dict : '', desc: Revoke 2nd secure boot key, rloc: 'EFUSE_RD_REPEAT_DATA1_REG[20]', bloc: 'B10[4]'} + SECURE_BOOT_KEY_REVOKE2 : {show: y, blk : 0, word: 2, pos: 21, len : 1, start : 85, type : bool, wr_dis : 7, rd_dis: null, alt : '', dict : '', desc: Revoke 3rd secure boot key, rloc: 'EFUSE_RD_REPEAT_DATA1_REG[21]', bloc: 'B10[5]'} + KEY_PURPOSE_0 : {show: y, blk : 0, word: 2, pos: 22, len : 5, start : 86, type : 'uint:5', wr_dis : 8, rd_dis: null, alt : KEY0_PURPOSE, dict : '', desc: 'Represents the purpose of Key0. See Table \ref{tab:efuse-key-purpose}', rloc: 'EFUSE_RD_REPEAT_DATA1_REG[26:22]', bloc: 'B10[7:6],B11[2:0]'} + KEY_PURPOSE_1 : {show: y, blk : 0, word: 2, pos: 27, len : 5, start : 91, type : 'uint:5', wr_dis : 9, rd_dis: null, alt : KEY1_PURPOSE, dict : '', desc: 'Represents the purpose of Key1. See Table \ref{tab:efuse-key-purpose}', rloc: 'EFUSE_RD_REPEAT_DATA1_REG[31:27]', bloc: 'B11[7:3]'} + KEY_PURPOSE_2 : {show: y, blk : 0, word: 3, pos : 0, len : 5, start : 96, type : 'uint:5', wr_dis : 10, rd_dis: null, alt : KEY2_PURPOSE, dict : '', desc: 'Represents the purpose of Key2. See Table \ref{tab:efuse-key-purpose}', rloc: 'EFUSE_RD_REPEAT_DATA2_REG[4:0]', bloc: 'B12[4:0]'} + KEY_PURPOSE_3 : {show: y, blk : 0, word: 3, pos : 5, len : 5, start: 101, type : 'uint:5', wr_dis : 11, rd_dis: null, alt : KEY3_PURPOSE, dict : '', desc: 'Represents the purpose of Key3. See Table \ref{tab:efuse-key-purpose}', rloc: 'EFUSE_RD_REPEAT_DATA2_REG[9:5]', bloc: 'B12[7:5],B13[1:0]'} + KEY_PURPOSE_4 : {show: y, blk : 0, word: 3, pos: 10, len : 5, start: 106, type : 'uint:5', wr_dis : 12, rd_dis: null, alt : KEY4_PURPOSE, dict : '', desc: 'Represents the purpose of Key4. See Table \ref{tab:efuse-key-purpose}', rloc: 'EFUSE_RD_REPEAT_DATA2_REG[14:10]', bloc: 'B13[6:2]'} + KEY_PURPOSE_5 : {show: y, blk : 0, word: 3, pos: 15, len : 5, start: 111, type : 'uint:5', wr_dis : 13, rd_dis: null, alt : KEY5_PURPOSE, dict : '', desc: 'Represents the purpose of Key5. See Table \ref{tab:efuse-key-purpose}', rloc: 'EFUSE_RD_REPEAT_DATA2_REG[19:15]', bloc: 'B13[7],B14[3:0]'} + SEC_DPA_LEVEL : {show: y, blk : 0, word: 3, pos: 20, len : 2, start: 116, type : 'uint:2', wr_dis : 14, rd_dis: null, alt : '', dict : '', desc: 'Represents the security level of anti-DPA attack. The level is adjusted by configuring the clock random frequency division mode.0: Security level is SEC\_DPA\_OFF1: Security level is SEC\_DPA\_LOW2: Security level is SEC\_DPA\_MIDDLE3: Security level is SEC\_DPA\_HIGHFor more information; please refer to Chapter \ref{mod:sysreg} \textit{\nameref{mod:sysreg}} > Section \ref{sec:sysreg-anti-dpa-attack-security-control} \textit{\nameref{sec:sysreg-anti-dpa-attack-security-control}}.', rloc: 'EFUSE_RD_REPEAT_DATA2_REG[21:20]', bloc: 'B14[5:4]'} + RECOVERY_BOOTLOADER_FLASH_SECTOR_HI : {show: y, blk : 0, word: 3, pos: 22, len : 3, start: 118, type : 'uint:3', wr_dis: null, rd_dis: null, alt : '', dict : '', desc: Represents the starting flash sector (flash sector size is 0x1000) of the recovery bootloader used by the ROM bootloader If the primary bootloader fails. 0 and 0xFFF - this feature is disabled. (The high part of the field), rloc: 'EFUSE_RD_REPEAT_DATA2_REG[24:22]', bloc: 'B14[7:6],B15[0]'} + SECURE_BOOT_EN : {show: y, blk : 0, word: 3, pos: 25, len : 1, start: 121, type : bool, wr_dis : 15, rd_dis: null, alt : '', dict : '', desc: 'Represents whether Secure Boot is enabled.1: Enabled0: Disabled', rloc: 'EFUSE_RD_REPEAT_DATA2_REG[25]', bloc: 'B15[1]'} + SECURE_BOOT_AGGRESSIVE_REVOKE : {show: y, blk : 0, word: 3, pos: 26, len : 1, start: 122, type : bool, wr_dis : 16, rd_dis: null, alt : '', dict : '', desc: 'Represents whether aggressive revocation of Secure Boot is enabled.1: Enabled0: Disabled', rloc: 'EFUSE_RD_REPEAT_DATA2_REG[26]', bloc: 'B15[2]'} + KM_XTS_KEY_LENGTH_256 : {show: y, blk : 0, word: 3, pos: 27, len : 1, start: 123, type : bool, wr_dis : 1, rd_dis: null, alt : '', dict : '', desc: 'Represents which key flash encryption uses.0: XTS-AES-256 key1: XTS-AES-128 key', rloc: 'EFUSE_RD_REPEAT_DATA2_REG[27]', bloc: 'B15[3]'} + FLASH_TPUW : {show: y, blk : 0, word: 3, pos: 28, len : 4, start: 124, type : 'uint:4', wr_dis : 18, rd_dis: null, alt : '', dict : '', desc: 'Represents the flash waiting time after power-up. Measurement unit: ms. When the value is less than 15; the waiting time is the programmed value. Otherwise; the waiting time is a fixed value; i.e. 30 ms', rloc: 'EFUSE_RD_REPEAT_DATA2_REG[31:28]', bloc: 'B15[7:4]'} + DIS_DOWNLOAD_MODE : {show: y, blk : 0, word: 4, pos : 0, len : 1, start: 128, type : bool, wr_dis : 18, rd_dis: null, alt : '', dict : '', desc: 'Represents whether Download mode is disable or enable. 1. Disable 0: Enable', rloc: 'EFUSE_RD_REPEAT_DATA3_REG[0]', bloc: 'B16[0]'} + DIS_DIRECT_BOOT : {show: y, blk : 0, word: 4, pos : 1, len : 1, start: 129, type : bool, wr_dis : 18, rd_dis: null, alt : '', dict : '', desc: 'Represents whether direct boot mode is disabled or enabled. 1. Disable 0: Enable', rloc: 'EFUSE_RD_REPEAT_DATA3_REG[1]', bloc: 'B16[1]'} + DIS_USB_SERIAL_JTAG_ROM_PRINT : {show: y, blk : 0, word: 4, pos : 2, len : 1, start: 130, type : bool, wr_dis : 18, rd_dis: null, alt : '', dict : '', desc: 'Represents whether print from USB-Serial-JTAG is disabled or enabled. 1. Disable 0: Enable', rloc: 'EFUSE_RD_REPEAT_DATA3_REG[2]', bloc: 'B16[2]'} + LOCK_KM_KEY : {show: y, blk : 0, word: 4, pos : 3, len : 1, start: 131, type : bool, wr_dis : 1, rd_dis: null, alt : '', dict : '', desc: 'Represents whether the keys in the Key Manager are locked after deployment.0: Not locked1: Locked', rloc: 'EFUSE_RD_REPEAT_DATA3_REG[3]', bloc: 'B16[3]'} + DIS_USB_SERIAL_JTAG_DOWNLOAD_MODE : {show: y, blk : 0, word: 4, pos : 4, len : 1, start: 132, type : bool, wr_dis : 18, rd_dis: null, alt : '', dict : '', desc: 'Represents whether the USB-Serial-JTAG download function is disabled or enabled. 1: Disable 0: Enable', rloc: 'EFUSE_RD_REPEAT_DATA3_REG[4]', bloc: 'B16[4]'} + ENABLE_SECURITY_DOWNLOAD : {show: y, blk : 0, word: 4, pos : 5, len : 1, start: 133, type : bool, wr_dis : 18, rd_dis: null, alt : '', dict : '', desc: 'Represents whether security download is enabled. Only downloading into flash is supported. Reading/writing RAM or registers is not supported (i.e. stub download is not supported).1: Enabled0: Disabled', rloc: 'EFUSE_RD_REPEAT_DATA3_REG[5]', bloc: 'B16[5]'} + UART_PRINT_CONTROL : {show: y, blk : 0, word: 4, pos : 6, len : 2, start: 134, type : 'uint:2', wr_dis : 18, rd_dis: null, alt : '', dict: '{0: "Enable", 1: "Enable when GPIO8 is low at reset", 2: "Enable when GPIO8 is high at reset", 3: "Disable"}', desc: Set the default UARTboot message output mode, rloc: 'EFUSE_RD_REPEAT_DATA3_REG[7:6]', bloc: 'B16[7:6]'} + FORCE_SEND_RESUME : {show: y, blk : 0, word: 4, pos : 8, len : 1, start: 136, type : bool, wr_dis : 18, rd_dis: null, alt : '', dict : '', desc: 'Represents whether ROM code is forced to send a resume command during SPI boot.1: Forced. 0: Not forced.', rloc: 'EFUSE_RD_REPEAT_DATA3_REG[8]', bloc: 'B17[0]'} + SECURE_VERSION : {show: y, blk : 0, word: 4, pos : 9, len : 9, start: 137, type : 'uint:9', wr_dis : 18, rd_dis: null, alt : '', dict : '', desc: Represents the app secure version used by ESP-IDF anti-rollback feature, rloc: 'EFUSE_RD_REPEAT_DATA3_REG[17:9]', bloc: 'B17[7:1],B18[1:0]'} + RESERVE_0_146 : {show: n, blk : 0, word: 4, pos: 18, len : 7, start: 146, type : 'uint:7', wr_dis: null, rd_dis: null, alt : '', dict : '', desc: Reserved; it was created by set_missed_fields_in_regs func, rloc: 'EFUSE_RD_REPEAT_DATA3_REG[24:18]', bloc: 'B18[7:2],B19[0]'} + SECURE_BOOT_DISABLE_FAST_WAKE : {show: y, blk : 0, word: 4, pos: 25, len : 1, start: 153, type : bool, wr_dis : 18, rd_dis: null, alt : '', dict : '', desc: 'Represents whether FAST VERIFY ON WAKE is disabled when Secure Boot is enabled.1: Disabled0: Enabled', rloc: 'EFUSE_RD_REPEAT_DATA3_REG[25]', bloc: 'B19[1]'} + HYS_EN_PAD : {show: y, blk : 0, word: 4, pos: 26, len : 1, start: 154, type : bool, wr_dis : 2, rd_dis: null, alt : '', dict : '', desc: "Represents whether the hysteresis function of PAD0 \u2013 PAD27 is enabled.1: Enabled0: Disabled", rloc: 'EFUSE_RD_REPEAT_DATA3_REG[26]', bloc: 'B19[2]'} + XTS_DPA_PSEUDO_LEVEL : {show: y, blk : 0, word: 4, pos: 27, len : 2, start: 155, type : 'uint:2', wr_dis : 14, rd_dis: null, alt : '', dict : '', desc: 'Represents the pseudo round level of XTS-AES anti-DPA attack.0: Disabled1: Low2: Moderate3: High', rloc: 'EFUSE_RD_REPEAT_DATA3_REG[28:27]', bloc: 'B19[4:3]'} + XTS_DPA_CLK_ENABLE : {show: y, blk : 0, word: 4, pos: 29, len : 1, start: 157, type : bool, wr_dis : 14, rd_dis: null, alt : '', dict : '', desc: 'Represents whether XTS-AES anti-DPA attack clock is enabled.0: Disable1: Enabled', rloc: 'EFUSE_RD_REPEAT_DATA3_REG[29]', bloc: 'B19[5]'} + RESERVE_0_158 : {show: n, blk : 0, word: 4, pos: 30, len : 1, start: 158, type : bool, wr_dis: null, rd_dis: null, alt : '', dict : '', desc: Reserved; it was created by set_missed_fields_in_regs func, rloc: 'EFUSE_RD_REPEAT_DATA3_REG[30]', bloc: 'B19[6]'} + SECURE_BOOT_SHA384_EN : {show: y, blk : 0, word: 4, pos: 31, len : 1, start: 159, type : bool, wr_dis : 14, rd_dis: null, alt : '', dict : '', desc: Represents if the chip supports Secure Boot using SHA-384, rloc: 'EFUSE_RD_REPEAT_DATA3_REG[31]', bloc: 'B19[7]'} + HUK_GEN_STATE : {show: y, blk : 0, word: 5, pos : 0, len : 9, start: 160, type : 'uint:9', wr_dis : 19, rd_dis: null, alt : '', dict : '', desc: 'Represents whether the HUK generate mode is valid.Odd count of bits with a value of 1: InvalidEven count of bits with a value of 1: Valid', rloc: 'EFUSE_RD_REPEAT_DATA4_REG[8:0]', bloc: 'B20,B21[0]'} + XTAL_48M_SEL : {show: y, blk : 0, word: 5, pos : 9, len : 3, start: 169, type : 'uint:3', wr_dis : 17, rd_dis: null, alt : '', dict : '', desc: 'Represents whether XTAL frequency is 48MHz or not. If not; 40MHz XTAL will be used. If this field contains Odd number bit 1: Enable 48MHz XTAL\ Even number bit 1: Enable 40MHz XTAL', rloc: 'EFUSE_RD_REPEAT_DATA4_REG[11:9]', bloc: 'B21[3:1]'} + XTAL_48M_SEL_MODE : {show: y, blk : 0, word: 5, pos: 12, len : 1, start: 172, type : bool, wr_dis : 17, rd_dis: null, alt : '', dict : '', desc: 'Represents what determines the XTAL frequency in \textbf{Joint Download Boot} mode. For more information; please refer to Chapter \ref{mod:bootctrl} \textit{\nameref{mod:bootctrl}}.0: Strapping PAD state1: \hyperref[fielddesc:EFUSEXTAL48MSEL]{EFUSE\_XTAL\_48M\_SEL} in eFuse', rloc: 'EFUSE_RD_REPEAT_DATA4_REG[12]', bloc: 'B21[4]'} + ECC_FORCE_CONST_TIME : {show: y, blk : 0, word: 5, pos: 13, len : 1, start: 173, type : bool, wr_dis : 14, rd_dis: null, alt : '', dict : '', desc: 'Represents whether to force ECC to use constant-time mode for point multiplication calculation. 0: Not force1: Force', rloc: 'EFUSE_RD_REPEAT_DATA4_REG[13]', bloc: 'B21[5]'} + RECOVERY_BOOTLOADER_FLASH_SECTOR_LO : {show: y, blk : 0, word: 5, pos: 14, len : 9, start: 174, type : 'uint:9', wr_dis: null, rd_dis: null, alt : '', dict : '', desc: Represents the starting flash sector (flash sector size is 0x1000) of the recovery bootloader used by the ROM bootloader If the primary bootloader fails. 0 and 0xFFF - this feature is disabled. (The low part of the field), rloc: 'EFUSE_RD_REPEAT_DATA4_REG[22:14]', bloc: 'B21[7:6],B22[6:0]'} + RESERVE_0_183 : {show: n, blk : 0, word: 5, pos: 23, len : 9, start: 183, type : 'uint:9', wr_dis: null, rd_dis: null, alt : '', dict : '', desc: Reserved; it was created by set_missed_fields_in_regs func, rloc: 'EFUSE_RD_REPEAT_DATA4_REG[31:23]', bloc: 'B22[7],B23'} + MAC : {show: y, blk : 1, word: 0, pos : 0, len : 48, start : 0, type : 'bytes:6', wr_dis : 20, rd_dis: null, alt : MAC_FACTORY, dict : '', desc: MAC address, rloc: EFUSE_RD_MAC_SYS0_REG, bloc: 'B0,B1,B2,B3,B4,B5'} + MAC_EXT : {show: y, blk : 1, word: 1, pos: 16, len : 16, start : 48, type : 'bytes:2', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: Represents the extended bits of MAC address, rloc: 'EFUSE_RD_MAC_SYS1_REG[31:16]', bloc: 'B6,B7'} + WAFER_VERSION_MINOR : {show: y, blk : 1, word: 2, pos : 0, len : 4, start : 64, type : 'uint:4', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: Minor chip version, rloc: 'EFUSE_RD_MAC_SYS2_REG[3:0]', bloc: 'B8[3:0]'} + WAFER_VERSION_MAJOR : {show: y, blk : 1, word: 2, pos : 4, len : 2, start : 68, type : 'uint:2', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: Minor chip version, rloc: 'EFUSE_RD_MAC_SYS2_REG[5:4]', bloc: 'B8[5:4]'} + DISABLE_WAFER_VERSION_MAJOR : {show: y, blk : 1, word: 2, pos : 6, len : 1, start : 70, type : bool, wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: Disables check of wafer version major, rloc: 'EFUSE_RD_MAC_SYS2_REG[6]', bloc: 'B8[6]'} + DISABLE_BLK_VERSION_MAJOR : {show: y, blk : 1, word: 2, pos : 7, len : 1, start : 71, type : bool, wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: Disables check of blk version major, rloc: 'EFUSE_RD_MAC_SYS2_REG[7]', bloc: 'B8[7]'} + BLK_VERSION_MINOR : {show: y, blk : 1, word: 2, pos : 8, len : 3, start : 72, type : 'uint:3', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: BLK_VERSION_MINOR of BLOCK2, rloc: 'EFUSE_RD_MAC_SYS2_REG[10:8]', bloc: 'B9[2:0]'} + BLK_VERSION_MAJOR : {show: y, blk : 1, word: 2, pos: 11, len : 2, start : 75, type : 'uint:2', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: BLK_VERSION_MAJOR of BLOCK2, rloc: 'EFUSE_RD_MAC_SYS2_REG[12:11]', bloc: 'B9[4:3]'} + FLASH_CAP : {show: y, blk : 1, word: 2, pos: 13, len : 3, start : 77, type : 'uint:3', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: Flash capacity, rloc: 'EFUSE_RD_MAC_SYS2_REG[15:13]', bloc: 'B9[7:5]'} + FLASH_VENDOR : {show: y, blk : 1, word: 2, pos: 16, len : 3, start : 80, type : 'uint:3', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: Flash vendor, rloc: 'EFUSE_RD_MAC_SYS2_REG[18:16]', bloc: 'B10[2:0]'} + PSRAM_CAP : {show: y, blk : 1, word: 2, pos: 19, len : 3, start : 83, type : 'uint:3', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: Psram capacity, rloc: 'EFUSE_RD_MAC_SYS2_REG[21:19]', bloc: 'B10[5:3]'} + PSRAM_VENDOR : {show: y, blk : 1, word: 2, pos: 22, len : 2, start : 86, type : 'uint:2', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: Psram vendor, rloc: 'EFUSE_RD_MAC_SYS2_REG[23:22]', bloc: 'B10[7:6]'} + TEMP : {show: y, blk : 1, word: 2, pos: 24, len : 2, start : 88, type : 'uint:2', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: Temp (die embedded inside), rloc: 'EFUSE_RD_MAC_SYS2_REG[25:24]', bloc: 'B11[1:0]'} + PKG_VERSION : {show: y, blk : 1, word: 2, pos: 26, len : 3, start : 90, type : 'uint:3', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: Package version, rloc: 'EFUSE_RD_MAC_SYS2_REG[28:26]', bloc: 'B11[4:2]'} + PA_TRIM_VERSION : {show: y, blk : 1, word: 2, pos: 29, len : 3, start : 93, type : 'uint:3', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: PADC CAL PA trim version, rloc: 'EFUSE_RD_MAC_SYS2_REG[31:29]', bloc: 'B11[7:5]'} + TRIM_N_BIAS : {show: y, blk : 1, word: 3, pos : 0, len : 5, start : 96, type : 'uint:5', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: PADC CAL N bias, rloc: 'EFUSE_RD_MAC_SYS3_REG[4:0]', bloc: 'B12[4:0]'} + TRIM_P_BIAS : {show: y, blk : 1, word: 3, pos : 5, len : 5, start: 101, type : 'uint:5', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: PADC CAL P bias, rloc: 'EFUSE_RD_MAC_SYS3_REG[9:5]', bloc: 'B12[7:5],B13[1:0]'} + ACTIVE_HP_DBIAS : {show: y, blk : 1, word: 3, pos: 10, len : 4, start: 106, type : 'uint:4', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: Active HP DBIAS of fixed voltage, rloc: 'EFUSE_RD_MAC_SYS3_REG[13:10]', bloc: 'B13[5:2]'} + ACTIVE_LP_DBIAS : {show: y, blk : 1, word: 3, pos: 14, len : 4, start: 110, type : 'uint:4', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: Active LP DBIAS of fixed voltage, rloc: 'EFUSE_RD_MAC_SYS3_REG[17:14]', bloc: 'B13[7:6],B14[1:0]'} + LSLP_HP_DBG : {show: y, blk : 1, word: 3, pos: 18, len : 2, start: 114, type : 'uint:2', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: LSLP HP DBG of fixed voltage, rloc: 'EFUSE_RD_MAC_SYS3_REG[19:18]', bloc: 'B14[3:2]'} + LSLP_HP_DBIAS : {show: y, blk : 1, word: 3, pos: 20, len : 4, start: 116, type : 'uint:4', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: LSLP HP DBIAS of fixed voltage, rloc: 'EFUSE_RD_MAC_SYS3_REG[23:20]', bloc: 'B14[7:4]'} + DSLP_LP_DBG : {show: y, blk : 1, word: 3, pos: 24, len : 4, start: 120, type : 'uint:4', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: DSLP LP DBG of fixed voltage, rloc: 'EFUSE_RD_MAC_SYS3_REG[27:24]', bloc: 'B15[3:0]'} + DSLP_LP_DBIAS : {show: y, blk : 1, word: 3, pos: 28, len : 5, start: 124, type : 'uint:5', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: DSLP LP DBIAS of fixed voltage, rloc: 'EFUSE_RD_MAC_SYS3_REG[31:28]', bloc: 'B15[7:4],B16[0]'} + LP_HP_DBIAS_VOL_GAP : {show: y, blk : 1, word: 4, pos : 1, len : 5, start: 129, type : 'uint:5', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: DBIAS gap between LP and HP, rloc: 'EFUSE_RD_MAC_SYS4_REG[5:1]', bloc: 'B16[5:1]'} + REF_CURR_CODE : {show: y, blk : 1, word: 4, pos : 6, len : 4, start: 134, type : 'uint:4', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: REF PADC Calibration Curr, rloc: 'EFUSE_RD_MAC_SYS4_REG[9:6]', bloc: 'B16[7:6],B17[1:0]'} + RES_TUNE_CODE : {show: y, blk : 1, word: 4, pos: 10, len : 5, start: 138, type : 'uint:5', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: RES PADC Calibration Tune, rloc: 'EFUSE_RD_MAC_SYS4_REG[14:10]', bloc: 'B17[6:2]'} + RESERVED_1_143 : {show: n, blk : 1, word: 4, pos: 15, len : 17, start: 143, type : 'uint:17', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: reserved, rloc: 'EFUSE_RD_MAC_SYS4_REG[31:15]', bloc: 'B17[7],B18,B19'} + SYS_DATA_PART0_2 : {show: n, blk : 1, word: 5, pos : 0, len : 32, start: 160, type : 'uint:32', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: Represents the third 32-bit of zeroth part of system data, rloc: EFUSE_RD_MAC_SYS5_REG, bloc: 'B20,B21,B22,B23'} + OPTIONAL_UNIQUE_ID : {show: y, blk : 2, word: 0, pos : 0, len: 128, start : 0, type: 'bytes:16', wr_dis : 21, rd_dis: null, alt : '', dict : '', desc: Optional unique 128-bit ID, rloc: EFUSE_RD_SYS_PART1_DATA0_REG, bloc: 'B0,B1,B2,B3,B4,B5,B6,B7,B8,B9,B10,B11,B12,B13,B14,B15'} + TEMPERATURE_SENSOR : {show: y, blk : 2, word: 4, pos : 0, len : 9, start: 128, type : 'uint:9', wr_dis : 21, rd_dis: null, alt : '', dict : '', desc: Temperature calibration data, rloc: 'EFUSE_RD_SYS_PART1_DATA4_REG[8:0]', bloc: 'B16,B17[0]'} + OCODE : {show: y, blk : 2, word: 4, pos : 9, len : 8, start: 137, type : 'uint:8', wr_dis : 21, rd_dis: null, alt : '', dict : '', desc: ADC OCode, rloc: 'EFUSE_RD_SYS_PART1_DATA4_REG[16:9]', bloc: 'B17[7:1],B18[0]'} + ADC1_AVE_INITCODE_ATTEN0 : {show: y, blk : 2, word: 4, pos: 17, len : 10, start: 145, type : 'uint:10', wr_dis : 21, rd_dis: null, alt : '', dict : '', desc: Average initcode of ADC1 atten0, rloc: 'EFUSE_RD_SYS_PART1_DATA4_REG[26:17]', bloc: 'B18[7:1],B19[2:0]'} + ADC1_AVE_INITCODE_ATTEN1 : {show: y, blk : 2, word: 4, pos: 27, len : 10, start: 155, type : 'uint:10', wr_dis : 21, rd_dis: null, alt : '', dict : '', desc: Average initcode of ADC1 atten0, rloc: 'EFUSE_RD_SYS_PART1_DATA4_REG[31:27]', bloc: 'B19[7:3],B20[4:0]'} + ADC1_AVE_INITCODE_ATTEN2 : {show: y, blk : 2, word: 5, pos : 5, len : 10, start: 165, type : 'uint:10', wr_dis : 21, rd_dis: null, alt : '', dict : '', desc: Average initcode of ADC1 atten0, rloc: 'EFUSE_RD_SYS_PART1_DATA5_REG[14:5]', bloc: 'B20[7:5],B21[6:0]'} + ADC1_AVE_INITCODE_ATTEN3 : {show: y, blk : 2, word: 5, pos: 15, len : 10, start: 175, type : 'uint:10', wr_dis : 21, rd_dis: null, alt : '', dict : '', desc: Average initcode of ADC1 atten0, rloc: 'EFUSE_RD_SYS_PART1_DATA5_REG[24:15]', bloc: 'B21[7],B22,B23[0]'} + ADC1_HI_DOUT_ATTEN0 : {show: y, blk : 2, word: 5, pos: 25, len : 10, start: 185, type : 'uint:10', wr_dis : 21, rd_dis: null, alt : '', dict : '', desc: HI DOUT of ADC1 atten0, rloc: 'EFUSE_RD_SYS_PART1_DATA5_REG[31:25]', bloc: 'B23[7:1],B24[2:0]'} + ADC1_HI_DOUT_ATTEN1 : {show: y, blk : 2, word: 6, pos : 3, len : 10, start: 195, type : 'uint:10', wr_dis : 21, rd_dis: null, alt : '', dict : '', desc: HI DOUT of ADC1 atten1, rloc: 'EFUSE_RD_SYS_PART1_DATA6_REG[12:3]', bloc: 'B24[7:3],B25[4:0]'} + ADC1_HI_DOUT_ATTEN2 : {show: y, blk : 2, word: 6, pos: 13, len : 10, start: 205, type : 'uint:10', wr_dis : 21, rd_dis: null, alt : '', dict : '', desc: HI DOUT of ADC1 atten2, rloc: 'EFUSE_RD_SYS_PART1_DATA6_REG[22:13]', bloc: 'B25[7:5],B26[6:0]'} + ADC1_HI_DOUT_ATTEN3 : {show: y, blk : 2, word: 6, pos: 23, len : 10, start: 215, type : 'uint:10', wr_dis : 21, rd_dis: null, alt : '', dict : '', desc: HI DOUT of ADC1 atten3, rloc: 'EFUSE_RD_SYS_PART1_DATA6_REG[31:23]', bloc: 'B26[7],B27,B28[0]'} + ADC1_CH0_ATTEN0_INITCODE_DIFF : {show: y, blk : 2, word: 7, pos : 1, len : 4, start: 225, type : 'uint:4', wr_dis : 21, rd_dis: null, alt : '', dict : '', desc: Gap between ADC1 CH0 and average initcode, rloc: 'EFUSE_RD_SYS_PART1_DATA7_REG[4:1]', bloc: 'B28[4:1]'} + ADC1_CH1_ATTEN0_INITCODE_DIFF : {show: y, blk : 2, word: 7, pos : 5, len : 4, start: 229, type : 'uint:4', wr_dis : 21, rd_dis: null, alt : '', dict : '', desc: Gap between ADC1 CH1 and average initcode, rloc: 'EFUSE_RD_SYS_PART1_DATA7_REG[8:5]', bloc: 'B28[7:5],B29[0]'} + ADC1_CH2_ATTEN0_INITCODE_DIFF : {show: y, blk : 2, word: 7, pos : 9, len : 4, start: 233, type : 'uint:4', wr_dis : 21, rd_dis: null, alt : '', dict : '', desc: Gap between ADC1 CH2 and average initcode, rloc: 'EFUSE_RD_SYS_PART1_DATA7_REG[12:9]', bloc: 'B29[4:1]'} + ADC1_CH3_ATTEN0_INITCODE_DIFF : {show: y, blk : 2, word: 7, pos: 13, len : 4, start: 237, type : 'uint:4', wr_dis : 21, rd_dis: null, alt : '', dict : '', desc: Gap between ADC1 CH3 and average initcode, rloc: 'EFUSE_RD_SYS_PART1_DATA7_REG[16:13]', bloc: 'B29[7:5],B30[0]'} + ADC1_CH4_ATTEN0_INITCODE_DIFF : {show: y, blk : 2, word: 7, pos: 17, len : 4, start: 241, type : 'uint:4', wr_dis : 21, rd_dis: null, alt : '', dict : '', desc: Gap between ADC1 CH4 and average initcode, rloc: 'EFUSE_RD_SYS_PART1_DATA7_REG[20:17]', bloc: 'B30[4:1]'} + ADC1_CH5_ATTEN0_INITCODE_DIFF : {show: y, blk : 2, word: 7, pos: 21, len : 4, start: 245, type : 'uint:4', wr_dis : 21, rd_dis: null, alt : '', dict : '', desc: Gap between ADC1 CH5 and average initcode, rloc: 'EFUSE_RD_SYS_PART1_DATA7_REG[24:21]', bloc: 'B30[7:5],B31[0]'} + RESERVED_2_249 : {show: n, blk : 2, word: 7, pos: 25, len : 7, start: 249, type : 'uint:7', wr_dis : 21, rd_dis: null, alt : '', dict : '', desc: reserved, rloc: 'EFUSE_RD_SYS_PART1_DATA7_REG[31:25]', bloc: 'B31[7:1]'} + BLOCK_USR_DATA : {show: y, blk : 3, word: 0, pos : 0, len: 192, start : 0, type: 'bytes:24', wr_dis : 22, rd_dis: null, alt : USER_DATA, dict : '', desc: User data, rloc: EFUSE_RD_USR_DATA0_REG, bloc: 'B0,B1,B2,B3,B4,B5,B6,B7,B8,B9,B10,B11,B12,B13,B14,B15,B16,B17,B18,B19,B20,B21,B22,B23'} + RESERVED_3_192 : {show: n, blk : 3, word: 6, pos : 0, len : 8, start: 192, type : 'uint:8', wr_dis : 22, rd_dis: null, alt : '', dict : '', desc: reserved, rloc: 'EFUSE_RD_USR_DATA6_REG[7:0]', bloc: B24} + CUSTOM_MAC : {show: y, blk : 3, word: 6, pos : 8, len : 48, start: 200, type : 'bytes:6', wr_dis : 22, rd_dis: null, alt: MAC_CUSTOM USER_DATA_MAC_CUSTOM, dict : '', desc: Custom MAC, rloc: 'EFUSE_RD_USR_DATA6_REG[31:8]', bloc: 'B25,B26,B27,B28,B29,B30'} + RESERVED_3_248 : {show: n, blk : 3, word: 7, pos: 24, len : 8, start: 248, type : 'uint:8', wr_dis : 22, rd_dis: null, alt : '', dict : '', desc: reserved, rloc: 'EFUSE_RD_USR_DATA7_REG[31:24]', bloc: B31} + BLOCK_KEY0 : {show: y, blk : 4, word: 0, pos : 0, len: 256, start : 0, type: 'bytes:32', wr_dis : 23, rd_dis : 0, alt : KEY0, dict : '', desc: Key0 or user data, rloc: EFUSE_RD_KEY0_DATA0_REG, bloc: 'B0,B1,B2,B3,B4,B5,B6,B7,B8,B9,B10,B11,B12,B13,B14,B15,B16,B17,B18,B19,B20,B21,B22,B23,B24,B25,B26,B27,B28,B29,B30,B31'} + BLOCK_KEY1 : {show: y, blk : 5, word: 0, pos : 0, len: 256, start : 0, type: 'bytes:32', wr_dis : 24, rd_dis : 1, alt : KEY1, dict : '', desc: Key1 or user data, rloc: EFUSE_RD_KEY1_DATA0_REG, bloc: 'B0,B1,B2,B3,B4,B5,B6,B7,B8,B9,B10,B11,B12,B13,B14,B15,B16,B17,B18,B19,B20,B21,B22,B23,B24,B25,B26,B27,B28,B29,B30,B31'} + BLOCK_KEY2 : {show: y, blk : 6, word: 0, pos : 0, len: 256, start : 0, type: 'bytes:32', wr_dis : 25, rd_dis : 2, alt : KEY2, dict : '', desc: Key2 or user data, rloc: EFUSE_RD_KEY2_DATA0_REG, bloc: 'B0,B1,B2,B3,B4,B5,B6,B7,B8,B9,B10,B11,B12,B13,B14,B15,B16,B17,B18,B19,B20,B21,B22,B23,B24,B25,B26,B27,B28,B29,B30,B31'} + BLOCK_KEY3 : {show: y, blk : 7, word: 0, pos : 0, len: 256, start : 0, type: 'bytes:32', wr_dis : 26, rd_dis : 3, alt : KEY3, dict : '', desc: Key3 or user data, rloc: EFUSE_RD_KEY3_DATA0_REG, bloc: 'B0,B1,B2,B3,B4,B5,B6,B7,B8,B9,B10,B11,B12,B13,B14,B15,B16,B17,B18,B19,B20,B21,B22,B23,B24,B25,B26,B27,B28,B29,B30,B31'} + BLOCK_KEY4 : {show: y, blk : 8, word: 0, pos : 0, len: 256, start : 0, type: 'bytes:32', wr_dis : 27, rd_dis : 4, alt : KEY4, dict : '', desc: Key4 or user data, rloc: EFUSE_RD_KEY4_DATA0_REG, bloc: 'B0,B1,B2,B3,B4,B5,B6,B7,B8,B9,B10,B11,B12,B13,B14,B15,B16,B17,B18,B19,B20,B21,B22,B23,B24,B25,B26,B27,B28,B29,B30,B31'} + BLOCK_KEY5 : {show: y, blk : 9, word: 0, pos : 0, len: 256, start : 0, type: 'bytes:32', wr_dis : 28, rd_dis : 5, alt : KEY5, dict : '', desc: Key5 or user data, rloc: EFUSE_RD_KEY5_DATA0_REG, bloc: 'B0,B1,B2,B3,B4,B5,B6,B7,B8,B9,B10,B11,B12,B13,B14,B15,B16,B17,B18,B19,B20,B21,B22,B23,B24,B25,B26,B27,B28,B29,B30,B31'} + BLOCK_SYS_DATA2 : {show: y, blk: 10, word: 0, pos : 0, len: 256, start : 0, type: 'bytes:32', wr_dis : 29, rd_dis : 6, alt : SYS_DATA_PART2, dict : '', desc: System data part 2 (reserved), rloc: EFUSE_RD_SYS_PART2_DATA0_REG, bloc: 'B0,B1,B2,B3,B4,B5,B6,B7,B8,B9,B10,B11,B12,B13,B14,B15,B16,B17,B18,B19,B20,B21,B22,B23,B24,B25,B26,B27,B28,B29,B30,B31'} diff --git a/tools/esptool_py/espefuse/efuse_defs/esp32c61.yaml b/tools/esptool_py/espefuse/efuse_defs/esp32c61.yaml index 3cbd2660e3..4ad5d951a1 100644 --- a/tools/esptool_py/espefuse/efuse_defs/esp32c61.yaml +++ b/tools/esptool_py/espefuse/efuse_defs/esp32c61.yaml @@ -1,84 +1,105 @@ -VER_NO: e564f8042b56a475a7714bb28ecdadfa +VER_NO: d435ade68d90ef96b0522478b2d8ba75 EFUSES: - WR_DIS : {show: y, blk : 0, word: 0, pos : 0, len : 32, start : 0, type : 'uint:32', wr_dis: null, rd_dis: null, alt : '', dict : '', desc: Disable programming of individual eFuses, rloc: EFUSE_RD_WR_DIS0_REG, bloc: 'B0,B1,B2,B3'} - RD_DIS : {show: y, blk : 0, word: 1, pos : 0, len : 7, start : 32, type : 'uint:7', wr_dis : 0, rd_dis: null, alt : '', dict : '', desc: Disable reading from BlOCK4-10, rloc: 'EFUSE_RD_REPEAT_DATA0_REG[6:0]', bloc: 'B4[6:0]'} - DIS_ICACHE : {show: y, blk : 0, word: 1, pos : 7, len : 1, start : 39, type : bool, wr_dis : 2, rd_dis: null, alt : '', dict : '', desc: 'Represents whether icache is disabled or enabled.\\ 1: disabled\\ 0: enabled\\', rloc: 'EFUSE_RD_REPEAT_DATA0_REG[7]', bloc: 'B4[7]'} - DIS_USB_JTAG : {show: y, blk : 0, word: 1, pos : 8, len : 1, start : 40, type : bool, wr_dis : 2, rd_dis: null, alt : '', dict : '', desc: 'Represents whether the function of usb switch to jtag is disabled or enabled.\\ 1: disabled\\ 0: enabled\\', rloc: 'EFUSE_RD_REPEAT_DATA0_REG[8]', bloc: 'B5[0]'} - DIS_USB_SERIAL_JTAG : {show: n, blk : 0, word: 1, pos : 9, len : 1, start : 41, type : bool, wr_dis : 2, rd_dis: null, alt : '', dict : '', desc: 'Represents whether USB-Serial-JTAG is disabled or enabled.\\ 1: disabled\\ 0: enabled\\', rloc: 'EFUSE_RD_REPEAT_DATA0_REG[9]', bloc: 'B5[1]'} - DIS_FORCE_DOWNLOAD : {show: y, blk : 0, word: 1, pos: 10, len : 1, start : 42, type : bool, wr_dis : 2, rd_dis: null, alt : '', dict : '', desc: 'Represents whether the function that forces chip into download mode is disabled or enabled.\\ 1: disabled\\ 0: enabled\\', rloc: 'EFUSE_RD_REPEAT_DATA0_REG[10]', bloc: 'B5[2]'} - SPI_DOWNLOAD_MSPI_DIS : {show: y, blk : 0, word: 1, pos: 11, len : 1, start : 43, type : bool, wr_dis : 2, rd_dis: null, alt : '', dict : '', desc: 'Represents whether SPI0 controller during boot_mode_download is disabled or enabled.\\ 1: disabled\\ 0: enabled\\', rloc: 'EFUSE_RD_REPEAT_DATA0_REG[11]', bloc: 'B5[3]'} - JTAG_SEL_ENABLE : {show: y, blk : 0, word: 1, pos: 12, len : 1, start : 44, type : bool, wr_dis : 2, rd_dis: null, alt : '', dict : '', desc: 'Represents whether the selection between usb_to_jtag and pad_to_jtag through strapping gpio15 when both EFUSE_DIS_PAD_JTAG and EFUSE_DIS_USB_JTAG are equal to 0 is enabled or disabled.\\ 1: enabled\\ 0: disabled\\', rloc: 'EFUSE_RD_REPEAT_DATA0_REG[12]', bloc: 'B5[4]'} - DIS_PAD_JTAG : {show: y, blk : 0, word: 1, pos: 13, len : 1, start : 45, type : bool, wr_dis : 2, rd_dis: null, alt : '', dict : '', desc: 'Represents whether JTAG is disabled in the hard way(permanently).\\ 1: disabled\\ 0: enabled\\', rloc: 'EFUSE_RD_REPEAT_DATA0_REG[13]', bloc: 'B5[5]'} - DIS_DOWNLOAD_MANUAL_ENCRYPT : {show: y, blk : 0, word: 1, pos: 14, len : 1, start : 46, type : bool, wr_dis : 2, rd_dis: null, alt : '', dict : '', desc: 'Represents whether flash encrypt function is disabled or enabled(except in SPI boot mode).\\ 1: disabled\\ 0: enabled\\', rloc: 'EFUSE_RD_REPEAT_DATA0_REG[14]', bloc: 'B5[6]'} - USB_DREFH : {show: n, blk : 0, word: 1, pos: 15, len : 2, start : 47, type : 'uint:2', wr_dis : 30, rd_dis: null, alt : '', dict : '', desc: Represents the single-end input threshold vrefh; 1.76 V to 2 V with step of 80 mV, rloc: 'EFUSE_RD_REPEAT_DATA0_REG[16:15]', bloc: 'B5[7],B6[0]'} - USB_DREFL : {show: n, blk : 0, word: 1, pos: 17, len : 2, start : 49, type : 'uint:2', wr_dis : 30, rd_dis: null, alt : '', dict : '', desc: Represents the single-end input threshold vrefl; 1.76 V to 2 V with step of 80 mV, rloc: 'EFUSE_RD_REPEAT_DATA0_REG[18:17]', bloc: 'B6[2:1]'} - USB_EXCHG_PINS : {show: y, blk : 0, word: 1, pos: 19, len : 1, start : 51, type : bool, wr_dis : 30, rd_dis: null, alt : '', dict : '', desc: 'Represents whether the D+ and D- pins is exchanged.\\ 1: exchanged\\ 0: not exchanged\\', rloc: 'EFUSE_RD_REPEAT_DATA0_REG[19]', bloc: 'B6[3]'} - VDD_SPI_AS_GPIO : {show: y, blk : 0, word: 1, pos: 20, len : 1, start : 52, type : bool, wr_dis : 30, rd_dis: null, alt : '', dict : '', desc: 'Represents whether vdd spi pin is functioned as gpio.\\ 1: functioned\\ 0: not functioned\\', rloc: 'EFUSE_RD_REPEAT_DATA0_REG[20]', bloc: 'B6[4]'} - WDT_DELAY_SEL : {show: y, blk : 0, word: 1, pos: 21, len : 2, start : 53, type : 'uint:2', wr_dis : 3, rd_dis: null, alt : '', dict : '', desc: 'Represents the threshold level of the RTC watchdog STG0 timeout.\\ 0: Original threshold configuration value of STG0 *2 \\1: Original threshold configuration value of STG0 *4 \\2: Original threshold configuration value of STG0 *8 \\3: Original threshold configuration value of STG0 *16 \\', rloc: 'EFUSE_RD_REPEAT_DATA0_REG[22:21]', bloc: 'B6[6:5]'} - SPI_BOOT_CRYPT_CNT : {show: y, blk : 0, word: 1, pos: 23, len : 3, start : 55, type : 'uint:3', wr_dis : 4, rd_dis: null, alt : '', dict: '{0: "Disable", 1: "Enable", 3: "Disable", 7: "Enable"}', desc: Enables flash encryption when 1 or 3 bits are set and disables otherwise, rloc: 'EFUSE_RD_REPEAT_DATA0_REG[25:23]', bloc: 'B6[7],B7[1:0]'} - SECURE_BOOT_KEY_REVOKE0 : {show: y, blk : 0, word: 1, pos: 26, len : 1, start : 58, type : bool, wr_dis : 5, rd_dis: null, alt : '', dict : '', desc: Revoke 1st secure boot key, rloc: 'EFUSE_RD_REPEAT_DATA0_REG[26]', bloc: 'B7[2]'} - SECURE_BOOT_KEY_REVOKE1 : {show: y, blk : 0, word: 1, pos: 27, len : 1, start : 59, type : bool, wr_dis : 6, rd_dis: null, alt : '', dict : '', desc: Revoke 2nd secure boot key, rloc: 'EFUSE_RD_REPEAT_DATA0_REG[27]', bloc: 'B7[3]'} - SECURE_BOOT_KEY_REVOKE2 : {show: y, blk : 0, word: 1, pos: 28, len : 1, start : 60, type : bool, wr_dis : 7, rd_dis: null, alt : '', dict : '', desc: Revoke 3rd secure boot key, rloc: 'EFUSE_RD_REPEAT_DATA0_REG[28]', bloc: 'B7[4]'} - RESERVE_0_61 : {show: n, blk : 0, word: 1, pos: 29, len : 3, start : 61, type : 'uint:3', wr_dis: null, rd_dis: null, alt : '', dict : '', desc: Reserved; it was created by set_missed_fields_in_regs func, rloc: 'EFUSE_RD_REPEAT_DATA0_REG[31:29]', bloc: 'B7[7:5]'} - KEY_PURPOSE_0 : {show: y, blk : 0, word: 2, pos : 0, len : 4, start : 64, type : 'uint:4', wr_dis : 8, rd_dis: null, alt : KEY0_PURPOSE, dict : '', desc: Represents the purpose of Key0, rloc: 'EFUSE_RD_REPEAT_DATA1_REG[3:0]', bloc: 'B8[3:0]'} - KEY_PURPOSE_1 : {show: y, blk : 0, word: 2, pos : 4, len : 4, start : 68, type : 'uint:4', wr_dis : 9, rd_dis: null, alt : KEY1_PURPOSE, dict : '', desc: Represents the purpose of Key1, rloc: 'EFUSE_RD_REPEAT_DATA1_REG[7:4]', bloc: 'B8[7:4]'} - KEY_PURPOSE_2 : {show: y, blk : 0, word: 2, pos : 8, len : 4, start : 72, type : 'uint:4', wr_dis : 10, rd_dis: null, alt : KEY2_PURPOSE, dict : '', desc: Represents the purpose of Key2, rloc: 'EFUSE_RD_REPEAT_DATA1_REG[11:8]', bloc: 'B9[3:0]'} - KEY_PURPOSE_3 : {show: y, blk : 0, word: 2, pos: 12, len : 4, start : 76, type : 'uint:4', wr_dis : 11, rd_dis: null, alt : KEY3_PURPOSE, dict : '', desc: Represents the purpose of Key3, rloc: 'EFUSE_RD_REPEAT_DATA1_REG[15:12]', bloc: 'B9[7:4]'} - KEY_PURPOSE_4 : {show: y, blk : 0, word: 2, pos: 16, len : 4, start : 80, type : 'uint:4', wr_dis : 12, rd_dis: null, alt : KEY4_PURPOSE, dict : '', desc: Represents the purpose of Key4, rloc: 'EFUSE_RD_REPEAT_DATA1_REG[19:16]', bloc: 'B10[3:0]'} - KEY_PURPOSE_5 : {show: y, blk : 0, word: 2, pos: 20, len : 4, start : 84, type : 'uint:4', wr_dis : 13, rd_dis: null, alt : KEY5_PURPOSE, dict : '', desc: Represents the purpose of Key5, rloc: 'EFUSE_RD_REPEAT_DATA1_REG[23:20]', bloc: 'B10[7:4]'} - SEC_DPA_LEVEL : {show: y, blk : 0, word: 2, pos: 24, len : 2, start : 88, type : 'uint:2', wr_dis : 14, rd_dis: null, alt : '', dict : '', desc: Represents the spa secure level by configuring the clock random divide mode, rloc: 'EFUSE_RD_REPEAT_DATA1_REG[25:24]', bloc: 'B11[1:0]'} - SECURE_BOOT_EN : {show: y, blk : 0, word: 2, pos: 26, len : 1, start : 90, type : bool, wr_dis : 15, rd_dis: null, alt : '', dict : '', desc: 'Represents whether secure boot is enabled or disabled.\\ 1: enabled\\ 0: disabled\\', rloc: 'EFUSE_RD_REPEAT_DATA1_REG[26]', bloc: 'B11[2]'} - SECURE_BOOT_AGGRESSIVE_REVOKE : {show: y, blk : 0, word: 2, pos: 27, len : 1, start : 91, type : bool, wr_dis : 16, rd_dis: null, alt : '', dict : '', desc: 'Represents whether revoking aggressive secure boot is enabled or disabled.\\ 1: enabled.\\ 0: disabled\\', rloc: 'EFUSE_RD_REPEAT_DATA1_REG[27]', bloc: 'B11[3]'} - FLASH_TPUW : {show: y, blk : 0, word: 2, pos: 28, len : 4, start : 92, type : 'uint:4', wr_dis : 18, rd_dis: null, alt : '', dict : '', desc: Represents the flash waiting time after power-up; in unit of ms. When the value less than 15; the waiting time is programmed value. Otherwise; the waiting time is 2 times the programmed value, rloc: 'EFUSE_RD_REPEAT_DATA1_REG[31:28]', bloc: 'B11[7:4]'} - DIS_DOWNLOAD_MODE : {show: y, blk : 0, word: 3, pos : 0, len : 1, start : 96, type : bool, wr_dis : 18, rd_dis: null, alt : '', dict : '', desc: 'Represents whether Download mode is disable or enable.\\ 1. Disable\\ 0: Enable\\', rloc: 'EFUSE_RD_REPEAT_DATA2_REG[0]', bloc: 'B12[0]'} - DIS_DIRECT_BOOT : {show: y, blk : 0, word: 3, pos : 1, len : 1, start : 97, type : bool, wr_dis : 18, rd_dis: null, alt : '', dict : '', desc: 'Represents whether direct boot mode is disabled or enabled.\\ 1. Disable\\ 0: Enable\\', rloc: 'EFUSE_RD_REPEAT_DATA2_REG[1]', bloc: 'B12[1]'} - DIS_USB_SERIAL_JTAG_ROM_PRINT : {show: y, blk : 0, word: 3, pos : 2, len : 1, start : 98, type : bool, wr_dis : 18, rd_dis: null, alt : '', dict : '', desc: 'Represents whether print from USB-Serial-JTAG is disabled or enabled.\\ 1. Disable\\ 0: Enable\\', rloc: 'EFUSE_RD_REPEAT_DATA2_REG[2]', bloc: 'B12[2]'} - DIS_USB_SERIAL_JTAG_DOWNLOAD_MODE: {show: y, blk : 0, word: 3, pos : 3, len : 1, start : 99, type : bool, wr_dis : 18, rd_dis: null, alt : '', dict : '', desc: 'Represents whether the USB-Serial-JTAG download function is disabled or enabled.\\ 1: Disable\\ 0: Enable\\', rloc: 'EFUSE_RD_REPEAT_DATA2_REG[3]', bloc: 'B12[3]'} - ENABLE_SECURITY_DOWNLOAD : {show: y, blk : 0, word: 3, pos : 4, len : 1, start: 100, type : bool, wr_dis : 18, rd_dis: null, alt : '', dict : '', desc: 'Represents whether security download is enabled or disabled.\\ 1: Enable\\ 0: Disable\\', rloc: 'EFUSE_RD_REPEAT_DATA2_REG[4]', bloc: 'B12[4]'} - UART_PRINT_CONTROL : {show: y, blk : 0, word: 3, pos : 5, len : 2, start: 101, type : 'uint:2', wr_dis : 18, rd_dis: null, alt : '', dict : '', desc: Represents the types of UART printing, rloc: 'EFUSE_RD_REPEAT_DATA2_REG[6:5]', bloc: 'B12[6:5]'} - FORCE_SEND_RESUME : {show: y, blk : 0, word: 3, pos : 7, len : 1, start: 103, type : bool, wr_dis : 18, rd_dis: null, alt : '', dict : '', desc: Represents whether ROM code is forced to send a resume command during SPI boot, rloc: 'EFUSE_RD_REPEAT_DATA2_REG[7]', bloc: 'B12[7]'} - SECURE_VERSION : {show: y, blk : 0, word: 3, pos : 8, len : 16, start: 104, type : 'uint:16', wr_dis : 18, rd_dis: null, alt : '', dict : '', desc: Represents the version used by ESP-IDF anti-rollback feature, rloc: 'EFUSE_RD_REPEAT_DATA2_REG[23:8]', bloc: 'B13,B14'} - SECURE_BOOT_DISABLE_FAST_WAKE : {show: y, blk : 0, word: 3, pos: 24, len : 1, start: 120, type : bool, wr_dis : 18, rd_dis: null, alt : '', dict : '', desc: Represents whether FAST_VERIFY_ON_WAKE is disable or enable when Secure Boot is enable, rloc: 'EFUSE_RD_REPEAT_DATA2_REG[24]', bloc: 'B15[0]'} - HYS_EN_PAD : {show: y, blk : 0, word: 3, pos: 25, len : 1, start: 121, type : bool, wr_dis : 2, rd_dis: null, alt : '', dict : '', desc: 'Represents whether the hysteresis function of corresponding PAD is enabled.\\ 1: enabled\\ 0:disabled\\', rloc: 'EFUSE_RD_REPEAT_DATA2_REG[25]', bloc: 'B15[1]'} - XTS_DPA_CLK_ENABLE : {show: y, blk : 0, word: 3, pos: 26, len : 1, start: 122, type : bool, wr_dis : 14, rd_dis: null, alt : '', dict : '', desc: 'Represents whether anti-dpa attack clock function is enabled.\\ 1. Enable\\ 0: Disable\\', rloc: 'EFUSE_RD_REPEAT_DATA2_REG[26]', bloc: 'B15[2]'} - XTS_DPA_PSEUDO_LEVEL : {show: y, blk : 0, word: 3, pos: 27, len : 2, start: 123, type : 'uint:2', wr_dis : 14, rd_dis: null, alt : '', dict : '', desc: 'Represents the anti-dpa attack pseudo function level.\\ 3:High\\ 2: Moderate\\ 1: Low\\ 0: Decided by register configuration\\', rloc: 'EFUSE_RD_REPEAT_DATA2_REG[28:27]', bloc: 'B15[4:3]'} - DIS_WIFI6 : {show: y, blk : 0, word: 3, pos: 29, len : 1, start: 125, type : bool, wr_dis : 2, rd_dis: null, alt : '', dict : '', desc: 'Represents whether the WiFi 6 feature is enable or disable.\\ 1: WiFi 6 is disable\\ 0: WiFi 6 is enabled.\\', rloc: 'EFUSE_RD_REPEAT_DATA2_REG[29]', bloc: 'B15[5]'} - ECDSA_DISABLE_P192 : {show: y, blk : 0, word: 3, pos: 30, len : 1, start: 126, type : bool, wr_dis : 14, rd_dis: null, alt : '', dict : '', desc: 'Represents whether to disable P192 curve in ECDSA.\\ 1: Disabled.\\ 0: Not disable', rloc: 'EFUSE_RD_REPEAT_DATA2_REG[30]', bloc: 'B15[6]'} - ECC_FORCE_CONST_TIME : {show: y, blk : 0, word: 3, pos: 31, len : 1, start: 127, type : bool, wr_dis : 14, rd_dis: null, alt : '', dict : '', desc: 'Represents whether to force ecc to use const-time calculation mode. \\ 1: Enable. \\ 0: Disable', rloc: 'EFUSE_RD_REPEAT_DATA2_REG[31]', bloc: 'B15[7]'} - REPEAT_DATA3 : {show: n, blk : 0, word: 4, pos : 0, len : 32, start: 128, type : 'uint:32', wr_dis: null, rd_dis: null, alt : '', dict : '', desc: Reserved, rloc: EFUSE_RD_REPEAT_DATA3_REG, bloc: 'B16,B17,B18,B19'} - REPEAT_DATA4 : {show: n, blk : 0, word: 5, pos : 0, len : 32, start: 160, type : 'uint:32', wr_dis: null, rd_dis: null, alt : '', dict : '', desc: Reserved, rloc: EFUSE_RD_REPEAT_DATA4_REG, bloc: 'B20,B21,B22,B23'} - MAC : {show: y, blk : 1, word: 0, pos : 0, len : 48, start : 0, type : 'bytes:6', wr_dis : 20, rd_dis: null, alt : MAC_FACTORY, dict : '', desc: MAC address, rloc: EFUSE_RD_MAC_SYS0_REG, bloc: 'B0,B1,B2,B3,B4,B5'} - C61_NO_EXTENTION : {show: n, blk : 1, word: 1, pos: 16, len : 16, start : 48, type : 'uint:16', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: Reserved, rloc: 'EFUSE_RD_MAC_SYS1_REG[31:16]', bloc: 'B6,B7'} - WAFER_VERSION_MINOR : {show: y, blk : 1, word: 2, pos : 0, len : 4, start : 64, type : 'uint:4', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: Minor chip version, rloc: 'EFUSE_RD_MAC_SYS2_REG[3:0]', bloc: 'B8[3:0]'} - WAFER_VERSION_MAJOR : {show: y, blk : 1, word: 2, pos : 4, len : 2, start : 68, type : 'uint:2', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: Major chip version, rloc: 'EFUSE_RD_MAC_SYS2_REG[5:4]', bloc: 'B8[5:4]'} - DISABLE_WAFER_VERSION_MAJOR : {show: y, blk : 1, word: 2, pos : 6, len : 1, start : 70, type : bool, wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: Disables check of wafer version major, rloc: 'EFUSE_RD_MAC_SYS2_REG[6]', bloc: 'B8[6]'} - DISABLE_BLK_VERSION_MAJOR : {show: y, blk : 1, word: 2, pos : 7, len : 1, start : 71, type : bool, wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: Disables check of blk version major, rloc: 'EFUSE_RD_MAC_SYS2_REG[7]', bloc: 'B8[7]'} - BLK_VERSION_MINOR : {show: y, blk : 1, word: 2, pos : 8, len : 3, start : 72, type : 'uint:3', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: BLK_VERSION_MINOR of BLOCK2, rloc: 'EFUSE_RD_MAC_SYS2_REG[10:8]', bloc: 'B9[2:0]'} - BLK_VERSION_MAJOR : {show: y, blk : 1, word: 2, pos: 11, len : 2, start : 75, type : 'uint:2', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: BLK_VERSION_MAJOR of BLOCK2, rloc: 'EFUSE_RD_MAC_SYS2_REG[12:11]', bloc: 'B9[4:3]'} - FLASH_CAP : {show: y, blk : 1, word: 2, pos: 13, len : 3, start : 77, type : 'uint:3', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: Flash capacity, rloc: 'EFUSE_RD_MAC_SYS2_REG[15:13]', bloc: 'B9[7:5]'} - FLASH_VENDOR : {show: y, blk : 1, word: 2, pos: 16, len : 3, start : 80, type : 'uint:3', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: Flash vendor, rloc: 'EFUSE_RD_MAC_SYS2_REG[18:16]', bloc: 'B10[2:0]'} - PSRAM_CAP : {show: y, blk : 1, word: 2, pos: 19, len : 3, start : 83, type : 'uint:3', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: PSRAM capacity, rloc: 'EFUSE_RD_MAC_SYS2_REG[21:19]', bloc: 'B10[5:3]'} - PSRAM_VENDOR : {show: y, blk : 1, word: 2, pos: 22, len : 2, start : 86, type : 'uint:2', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: PSRAM vendor, rloc: 'EFUSE_RD_MAC_SYS2_REG[23:22]', bloc: 'B10[7:6]'} - TEMP : {show: y, blk : 1, word: 2, pos: 24, len : 2, start : 88, type : 'uint:2', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: Temperature, rloc: 'EFUSE_RD_MAC_SYS2_REG[25:24]', bloc: 'B11[1:0]'} - PKG_VERSION : {show: y, blk : 1, word: 2, pos: 26, len : 3, start : 90, type : 'uint:3', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: Package version, rloc: 'EFUSE_RD_MAC_SYS2_REG[28:26]', bloc: 'B11[4:2]'} - RESERVED_1_93 : {show: n, blk : 1, word: 2, pos: 29, len : 3, start : 93, type : 'uint:3', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: reserved, rloc: 'EFUSE_RD_MAC_SYS2_REG[31:29]', bloc: 'B11[7:5]'} - MAC_RESERVED_2 : {show: n, blk : 1, word: 3, pos : 0, len : 18, start : 96, type : 'uint:18', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: Reserved, rloc: 'EFUSE_RD_MAC_SYS3_REG[17:0]', bloc: 'B12,B13,B14[1:0]'} - SYS_DATA_PART0_0 : {show: n, blk : 1, word: 3, pos: 18, len : 14, start: 114, type : 'uint:14', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: Represents the first 14-bit of zeroth part of system data, rloc: 'EFUSE_RD_MAC_SYS3_REG[31:18]', bloc: 'B14[7:2],B15'} - SYS_DATA_PART0_1 : {show: n, blk : 1, word: 4, pos : 0, len : 32, start: 128, type : 'uint:32', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: Represents the first 14-bit of zeroth part of system data, rloc: EFUSE_RD_MAC_SYS4_REG, bloc: 'B16,B17,B18,B19'} - SYS_DATA_PART0_2 : {show: n, blk : 1, word: 5, pos : 0, len : 32, start: 160, type : 'uint:32', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: Represents the second 32-bit of zeroth part of system data, rloc: EFUSE_RD_MAC_SYS5_REG, bloc: 'B20,B21,B22,B23'} - OPTIONAL_UNIQUE_ID : {show: y, blk : 2, word: 0, pos : 0, len: 128, start : 0, type: 'bytes:16', wr_dis : 21, rd_dis: null, alt : '', dict : '', desc: Optional unique 128-bit ID, rloc: EFUSE_RD_SYS_PART1_DATA0_REG, bloc: 'B0,B1,B2,B3,B4,B5,B6,B7,B8,B9,B10,B11,B12,B13,B14,B15'} - SYS_DATA_PART1_4 : {show: n, blk : 2, word: 4, pos : 0, len : 32, start: 128, type : 'uint:32', wr_dis : 21, rd_dis: null, alt : '', dict : '', desc: Represents the zeroth 32-bit of first part of system data, rloc: EFUSE_RD_SYS_PART1_DATA4_REG, bloc: 'B16,B17,B18,B19'} - SYS_DATA_PART1_5 : {show: n, blk : 2, word: 5, pos : 0, len : 32, start: 160, type : 'uint:32', wr_dis : 21, rd_dis: null, alt : '', dict : '', desc: Represents the zeroth 32-bit of first part of system data, rloc: EFUSE_RD_SYS_PART1_DATA5_REG, bloc: 'B20,B21,B22,B23'} - SYS_DATA_PART1_6 : {show: n, blk : 2, word: 6, pos : 0, len : 32, start: 192, type : 'uint:32', wr_dis : 21, rd_dis: null, alt : '', dict : '', desc: Represents the zeroth 32-bit of first part of system data, rloc: EFUSE_RD_SYS_PART1_DATA6_REG, bloc: 'B24,B25,B26,B27'} - SYS_DATA_PART1_7 : {show: n, blk : 2, word: 7, pos : 0, len : 32, start: 224, type : 'uint:32', wr_dis : 21, rd_dis: null, alt : '', dict : '', desc: Represents the zeroth 32-bit of first part of system data, rloc: EFUSE_RD_SYS_PART1_DATA7_REG, bloc: 'B28,B29,B30,B31'} - BLOCK_USR_DATA : {show: y, blk : 3, word: 0, pos : 0, len: 192, start : 0, type: 'bytes:24', wr_dis : 22, rd_dis: null, alt : USER_DATA, dict : '', desc: User data, rloc: EFUSE_RD_USR_DATA0_REG, bloc: 'B0,B1,B2,B3,B4,B5,B6,B7,B8,B9,B10,B11,B12,B13,B14,B15,B16,B17,B18,B19,B20,B21,B22,B23'} - RESERVED_3_192 : {show: n, blk : 3, word: 6, pos : 0, len : 8, start: 192, type : 'uint:8', wr_dis : 22, rd_dis: null, alt : '', dict : '', desc: reserved, rloc: 'EFUSE_RD_USR_DATA6_REG[7:0]', bloc: B24} - CUSTOM_MAC : {show: y, blk : 3, word: 6, pos : 8, len : 48, start: 200, type : 'bytes:6', wr_dis : 22, rd_dis: null, alt: MAC_CUSTOM USER_DATA_MAC_CUSTOM, dict : '', desc: Custom MAC, rloc: 'EFUSE_RD_USR_DATA6_REG[31:8]', bloc: 'B25,B26,B27,B28,B29,B30'} - RESERVED_3_248 : {show: n, blk : 3, word: 7, pos: 24, len : 8, start: 248, type : 'uint:8', wr_dis : 22, rd_dis: null, alt : '', dict : '', desc: reserved, rloc: 'EFUSE_RD_USR_DATA7_REG[31:24]', bloc: B31} - BLOCK_KEY0 : {show: y, blk : 4, word: 0, pos : 0, len: 256, start : 0, type: 'bytes:32', wr_dis : 23, rd_dis : 0, alt : KEY0, dict : '', desc: Key0 or user data, rloc: EFUSE_RD_KEY0_DATA0_REG, bloc: 'B0,B1,B2,B3,B4,B5,B6,B7,B8,B9,B10,B11,B12,B13,B14,B15,B16,B17,B18,B19,B20,B21,B22,B23,B24,B25,B26,B27,B28,B29,B30,B31'} - BLOCK_KEY1 : {show: y, blk : 5, word: 0, pos : 0, len: 256, start : 0, type: 'bytes:32', wr_dis : 24, rd_dis : 1, alt : KEY1, dict : '', desc: Key1 or user data, rloc: EFUSE_RD_KEY1_DATA0_REG, bloc: 'B0,B1,B2,B3,B4,B5,B6,B7,B8,B9,B10,B11,B12,B13,B14,B15,B16,B17,B18,B19,B20,B21,B22,B23,B24,B25,B26,B27,B28,B29,B30,B31'} - BLOCK_KEY2 : {show: y, blk : 6, word: 0, pos : 0, len: 256, start : 0, type: 'bytes:32', wr_dis : 25, rd_dis : 2, alt : KEY2, dict : '', desc: Key2 or user data, rloc: EFUSE_RD_KEY2_DATA0_REG, bloc: 'B0,B1,B2,B3,B4,B5,B6,B7,B8,B9,B10,B11,B12,B13,B14,B15,B16,B17,B18,B19,B20,B21,B22,B23,B24,B25,B26,B27,B28,B29,B30,B31'} - BLOCK_KEY3 : {show: y, blk : 7, word: 0, pos : 0, len: 256, start : 0, type: 'bytes:32', wr_dis : 26, rd_dis : 3, alt : KEY3, dict : '', desc: Key3 or user data, rloc: EFUSE_RD_KEY3_DATA0_REG, bloc: 'B0,B1,B2,B3,B4,B5,B6,B7,B8,B9,B10,B11,B12,B13,B14,B15,B16,B17,B18,B19,B20,B21,B22,B23,B24,B25,B26,B27,B28,B29,B30,B31'} - BLOCK_KEY4 : {show: y, blk : 8, word: 0, pos : 0, len: 256, start : 0, type: 'bytes:32', wr_dis : 27, rd_dis : 4, alt : KEY4, dict : '', desc: Key4 or user data, rloc: EFUSE_RD_KEY4_DATA0_REG, bloc: 'B0,B1,B2,B3,B4,B5,B6,B7,B8,B9,B10,B11,B12,B13,B14,B15,B16,B17,B18,B19,B20,B21,B22,B23,B24,B25,B26,B27,B28,B29,B30,B31'} - BLOCK_KEY5 : {show: y, blk : 9, word: 0, pos : 0, len: 256, start : 0, type: 'bytes:32', wr_dis : 28, rd_dis : 5, alt : KEY5, dict : '', desc: Key5 or user data, rloc: EFUSE_RD_KEY5_DATA0_REG, bloc: 'B0,B1,B2,B3,B4,B5,B6,B7,B8,B9,B10,B11,B12,B13,B14,B15,B16,B17,B18,B19,B20,B21,B22,B23,B24,B25,B26,B27,B28,B29,B30,B31'} - BLOCK_SYS_DATA2 : {show: y, blk: 10, word: 0, pos : 0, len: 256, start : 0, type: 'bytes:32', wr_dis : 29, rd_dis : 6, alt : SYS_DATA_PART2, dict : '', desc: System data part 2 (reserved), rloc: EFUSE_RD_SYS_PART2_DATA0_REG, bloc: 'B0,B1,B2,B3,B4,B5,B6,B7,B8,B9,B10,B11,B12,B13,B14,B15,B16,B17,B18,B19,B20,B21,B22,B23,B24,B25,B26,B27,B28,B29,B30,B31'} + WR_DIS : {show: y, blk : 0, word: 0, pos : 0, len : 32, start : 0, type : 'uint:32', wr_dis: null, rd_dis: null, alt : '', dict : '', desc: Disable programming of individual eFuses, rloc: EFUSE_RD_WR_DIS0_REG, bloc: 'B0,B1,B2,B3'} + RD_DIS : {show: y, blk : 0, word: 1, pos : 0, len : 7, start : 32, type : 'uint:7', wr_dis : 0, rd_dis: null, alt : '', dict : '', desc: Disable reading from BlOCK4-10, rloc: 'EFUSE_RD_REPEAT_DATA0_REG[6:0]', bloc: 'B4[6:0]'} + DIS_ICACHE : {show: y, blk : 0, word: 1, pos : 7, len : 1, start : 39, type : bool, wr_dis : 2, rd_dis: null, alt : '', dict : '', desc: 'Represents whether cache is disabled. 1: Disabled 0: Enabled.', rloc: 'EFUSE_RD_REPEAT_DATA0_REG[7]', bloc: 'B4[7]'} + DIS_USB_JTAG : {show: y, blk : 0, word: 1, pos : 8, len : 1, start : 40, type : bool, wr_dis : 2, rd_dis: null, alt : '', dict : '', desc: 'Represents whether the function of usb switch to jtag is disabled or enabled. 1: disabled 0: enabled', rloc: 'EFUSE_RD_REPEAT_DATA0_REG[8]', bloc: 'B5[0]'} + DIS_USB_SERIAL_JTAG : {show: n, blk : 0, word: 1, pos : 9, len : 1, start : 41, type : bool, wr_dis : 2, rd_dis: null, alt : '', dict : '', desc: 'Represents whether USB-Serial-JTAG is disabled or enabled. 1: disabled 0: enabled', rloc: 'EFUSE_RD_REPEAT_DATA0_REG[9]', bloc: 'B5[1]'} + DIS_FORCE_DOWNLOAD : {show: y, blk : 0, word: 1, pos: 10, len : 1, start : 42, type : bool, wr_dis : 2, rd_dis: null, alt : '', dict : '', desc: 'Represents whether the function that forces chip into download mode is disabled or enabled. 1: disabled 0: enabled', rloc: 'EFUSE_RD_REPEAT_DATA0_REG[10]', bloc: 'B5[2]'} + SPI_DOWNLOAD_MSPI_DIS : {show: y, blk : 0, word: 1, pos: 11, len : 1, start : 43, type : bool, wr_dis : 2, rd_dis: null, alt : '', dict : '', desc: 'Represents whether SPI0 controller during boot_mode_download is disabled or enabled. 1: disabled 0: enabled', rloc: 'EFUSE_RD_REPEAT_DATA0_REG[11]', bloc: 'B5[3]'} + JTAG_SEL_ENABLE : {show: y, blk : 0, word: 1, pos: 12, len : 1, start : 44, type : bool, wr_dis : 2, rd_dis: null, alt : '', dict : '', desc: 'Represents whether the selection between usb_to_jtag and pad_to_jtag through strapping gpio15 when both EFUSE_DIS_PAD_JTAG and EFUSE_DIS_USB_JTAG are equal to 0 is enabled or disabled. 1: enabled 0: disabled', rloc: 'EFUSE_RD_REPEAT_DATA0_REG[12]', bloc: 'B5[4]'} + DIS_PAD_JTAG : {show: y, blk : 0, word: 1, pos: 13, len : 1, start : 45, type : bool, wr_dis : 2, rd_dis: null, alt : '', dict : '', desc: 'Represents whether JTAG is disabled in the hard way(permanently). 1: disabled 0: enabled', rloc: 'EFUSE_RD_REPEAT_DATA0_REG[13]', bloc: 'B5[5]'} + DIS_DOWNLOAD_MANUAL_ENCRYPT : {show: y, blk : 0, word: 1, pos: 14, len : 1, start : 46, type : bool, wr_dis : 2, rd_dis: null, alt : '', dict : '', desc: 'Represents whether flash encrypt function is disabled or enabled(except in SPI boot mode). 1: disabled 0: enabled', rloc: 'EFUSE_RD_REPEAT_DATA0_REG[14]', bloc: 'B5[6]'} + USB_DREFH : {show: n, blk : 0, word: 1, pos: 15, len : 2, start : 47, type : 'uint:2', wr_dis : 30, rd_dis: null, alt : '', dict : '', desc: Represents the single-end input threshold vrefh of USB_SERIAL_JTAG PHY; 1.76 V to 2 V with step of 80 mV, rloc: 'EFUSE_RD_REPEAT_DATA0_REG[16:15]', bloc: 'B5[7],B6[0]'} + USB_DREFL : {show: n, blk : 0, word: 1, pos: 17, len : 2, start : 49, type : 'uint:2', wr_dis : 30, rd_dis: null, alt : '', dict : '', desc: Represents the single-end input threshold vrefl of USB_SERIAL_JTAG PHY; 1.76 V to 2 V with step of 80 mV, rloc: 'EFUSE_RD_REPEAT_DATA0_REG[18:17]', bloc: 'B6[2:1]'} + USB_EXCHG_PINS : {show: y, blk : 0, word: 1, pos: 19, len : 1, start : 51, type : bool, wr_dis : 30, rd_dis: null, alt : '', dict : '', desc: 'Represents whether the D+ and D- pins of USB_SERIAL_JTAG PHY is exchanged. 1: exchanged 0: not exchanged', rloc: 'EFUSE_RD_REPEAT_DATA0_REG[19]', bloc: 'B6[3]'} + VDD_SPI_AS_GPIO : {show: y, blk : 0, word: 1, pos: 20, len : 1, start : 52, type : bool, wr_dis : 30, rd_dis: null, alt : '', dict : '', desc: 'Represents whether vdd spi pin is functioned as gpio. 1: functioned 0: not functioned', rloc: 'EFUSE_RD_REPEAT_DATA0_REG[20]', bloc: 'B6[4]'} + WDT_DELAY_SEL : {show: y, blk : 0, word: 1, pos: 21, len : 2, start : 53, type : 'uint:2', wr_dis : 3, rd_dis: null, alt : '', dict : '', desc: lp wdt timeout threshold at startup = initial timeout value * (2 ^ (EFUSE_WDT_DELAY_SEL + 1)), rloc: 'EFUSE_RD_REPEAT_DATA0_REG[22:21]', bloc: 'B6[6:5]'} + SPI_BOOT_CRYPT_CNT : {show: y, blk : 0, word: 1, pos: 23, len : 3, start : 55, type : 'uint:3', wr_dis : 4, rd_dis: null, alt : '', dict: '{0: "Disable", 1: "Enable", 3: "Disable", 7: "Enable"}', desc: Enables flash encryption when 1 or 3 bits are set and disables otherwise, rloc: 'EFUSE_RD_REPEAT_DATA0_REG[25:23]', bloc: 'B6[7],B7[1:0]'} + SECURE_BOOT_KEY_REVOKE0 : {show: y, blk : 0, word: 1, pos: 26, len : 1, start : 58, type : bool, wr_dis : 5, rd_dis: null, alt : '', dict : '', desc: Revoke 1st secure boot key, rloc: 'EFUSE_RD_REPEAT_DATA0_REG[26]', bloc: 'B7[2]'} + SECURE_BOOT_KEY_REVOKE1 : {show: y, blk : 0, word: 1, pos: 27, len : 1, start : 59, type : bool, wr_dis : 6, rd_dis: null, alt : '', dict : '', desc: Revoke 2nd secure boot key, rloc: 'EFUSE_RD_REPEAT_DATA0_REG[27]', bloc: 'B7[3]'} + SECURE_BOOT_KEY_REVOKE2 : {show: y, blk : 0, word: 1, pos: 28, len : 1, start : 60, type : bool, wr_dis : 7, rd_dis: null, alt : '', dict : '', desc: Revoke 3rd secure boot key, rloc: 'EFUSE_RD_REPEAT_DATA0_REG[28]', bloc: 'B7[4]'} + RESERVE_0_61 : {show: n, blk : 0, word: 1, pos: 29, len : 3, start : 61, type : 'uint:3', wr_dis: null, rd_dis: null, alt : '', dict : '', desc: Reserved; it was created by set_missed_fields_in_regs func, rloc: 'EFUSE_RD_REPEAT_DATA0_REG[31:29]', bloc: 'B7[7:5]'} + KEY_PURPOSE_0 : {show: y, blk : 0, word: 2, pos : 0, len : 4, start : 64, type : 'uint:4', wr_dis : 8, rd_dis: null, alt : KEY0_PURPOSE, dict : '', desc: Represents the purpose of Key0, rloc: 'EFUSE_RD_REPEAT_DATA1_REG[3:0]', bloc: 'B8[3:0]'} + KEY_PURPOSE_1 : {show: y, blk : 0, word: 2, pos : 4, len : 4, start : 68, type : 'uint:4', wr_dis : 9, rd_dis: null, alt : KEY1_PURPOSE, dict : '', desc: Represents the purpose of Key1, rloc: 'EFUSE_RD_REPEAT_DATA1_REG[7:4]', bloc: 'B8[7:4]'} + KEY_PURPOSE_2 : {show: y, blk : 0, word: 2, pos : 8, len : 4, start : 72, type : 'uint:4', wr_dis : 10, rd_dis: null, alt : KEY2_PURPOSE, dict : '', desc: Represents the purpose of Key2, rloc: 'EFUSE_RD_REPEAT_DATA1_REG[11:8]', bloc: 'B9[3:0]'} + KEY_PURPOSE_3 : {show: y, blk : 0, word: 2, pos: 12, len : 4, start : 76, type : 'uint:4', wr_dis : 11, rd_dis: null, alt : KEY3_PURPOSE, dict : '', desc: Represents the purpose of Key3, rloc: 'EFUSE_RD_REPEAT_DATA1_REG[15:12]', bloc: 'B9[7:4]'} + KEY_PURPOSE_4 : {show: y, blk : 0, word: 2, pos: 16, len : 4, start : 80, type : 'uint:4', wr_dis : 12, rd_dis: null, alt : KEY4_PURPOSE, dict : '', desc: Represents the purpose of Key4, rloc: 'EFUSE_RD_REPEAT_DATA1_REG[19:16]', bloc: 'B10[3:0]'} + KEY_PURPOSE_5 : {show: y, blk : 0, word: 2, pos: 20, len : 4, start : 84, type : 'uint:4', wr_dis : 13, rd_dis: null, alt : KEY5_PURPOSE, dict : '', desc: Represents the purpose of Key5, rloc: 'EFUSE_RD_REPEAT_DATA1_REG[23:20]', bloc: 'B10[7:4]'} + SEC_DPA_LEVEL : {show: y, blk : 0, word: 2, pos: 24, len : 2, start : 88, type : 'uint:2', wr_dis : 14, rd_dis: null, alt : '', dict : '', desc: Represents the spa secure level by configuring the clock random divide mode, rloc: 'EFUSE_RD_REPEAT_DATA1_REG[25:24]', bloc: 'B11[1:0]'} + SECURE_BOOT_EN : {show: y, blk : 0, word: 2, pos: 26, len : 1, start : 90, type : bool, wr_dis : 15, rd_dis: null, alt : '', dict : '', desc: 'Represents whether secure boot is enabled or disabled. 1. Enable 0: Disable', rloc: 'EFUSE_RD_REPEAT_DATA1_REG[26]', bloc: 'B11[2]'} + SECURE_BOOT_AGGRESSIVE_REVOKE : {show: y, blk : 0, word: 2, pos: 27, len : 1, start : 91, type : bool, wr_dis : 16, rd_dis: null, alt : '', dict : '', desc: 'Represents whether revoking aggressive secure boot is enabled or disabled. 1. Enable 0: Disable', rloc: 'EFUSE_RD_REPEAT_DATA1_REG[27]', bloc: 'B11[3]'} + FLASH_TPUW : {show: y, blk : 0, word: 2, pos: 28, len : 4, start : 92, type : 'uint:4', wr_dis : 18, rd_dis: null, alt : '', dict : '', desc: Represents the flash waiting time after power-up; in unit of ms. When the value less than 15; the waiting time is programmed value. Otherwise; the waiting time is 2 times the programmed value, rloc: 'EFUSE_RD_REPEAT_DATA1_REG[31:28]', bloc: 'B11[7:4]'} + DIS_DOWNLOAD_MODE : {show: y, blk : 0, word: 3, pos : 0, len : 1, start : 96, type : bool, wr_dis : 18, rd_dis: null, alt : '', dict : '', desc: 'Represents whether Download mode is disable or enable. 1. Disable 0: Enable', rloc: 'EFUSE_RD_REPEAT_DATA2_REG[0]', bloc: 'B12[0]'} + DIS_DIRECT_BOOT : {show: y, blk : 0, word: 3, pos : 1, len : 1, start : 97, type : bool, wr_dis : 18, rd_dis: null, alt : '', dict : '', desc: 'Represents whether direct boot mode is disabled or enabled. 1. Disable 0: Enable', rloc: 'EFUSE_RD_REPEAT_DATA2_REG[1]', bloc: 'B12[1]'} + DIS_USB_SERIAL_JTAG_ROM_PRINT : {show: y, blk : 0, word: 3, pos : 2, len : 1, start : 98, type : bool, wr_dis : 18, rd_dis: null, alt : '', dict : '', desc: 'Represents whether print from USB-Serial-JTAG is disabled or enabled. 1. Disable 0: Enable', rloc: 'EFUSE_RD_REPEAT_DATA2_REG[2]', bloc: 'B12[2]'} + DIS_USB_SERIAL_JTAG_DOWNLOAD_MODE : {show: y, blk : 0, word: 3, pos : 3, len : 1, start : 99, type : bool, wr_dis : 18, rd_dis: null, alt : '', dict : '', desc: 'Represents whether the USB-Serial-JTAG download function is disabled or enabled. 1: Disable 0: Enable', rloc: 'EFUSE_RD_REPEAT_DATA2_REG[3]', bloc: 'B12[3]'} + ENABLE_SECURITY_DOWNLOAD : {show: y, blk : 0, word: 3, pos : 4, len : 1, start: 100, type : bool, wr_dis : 18, rd_dis: null, alt : '', dict : '', desc: 'Represents whether security download is enabled or disabled. 1: Enable 0: Disable', rloc: 'EFUSE_RD_REPEAT_DATA2_REG[4]', bloc: 'B12[4]'} + UART_PRINT_CONTROL : {show: y, blk : 0, word: 3, pos : 5, len : 2, start: 101, type : 'uint:2', wr_dis : 18, rd_dis: null, alt : '', dict : '', desc: Represents the types of UART printing, rloc: 'EFUSE_RD_REPEAT_DATA2_REG[6:5]', bloc: 'B12[6:5]'} + FORCE_SEND_RESUME : {show: y, blk : 0, word: 3, pos : 7, len : 1, start: 103, type : bool, wr_dis : 18, rd_dis: null, alt : '', dict : '', desc: Represents whether ROM code is forced to send a resume command during SPI boot, rloc: 'EFUSE_RD_REPEAT_DATA2_REG[7]', bloc: 'B12[7]'} + SECURE_VERSION : {show: y, blk : 0, word: 3, pos : 8, len : 16, start: 104, type : 'uint:16', wr_dis : 18, rd_dis: null, alt : '', dict : '', desc: Represents the version used by ESP-IDF anti-rollback feature, rloc: 'EFUSE_RD_REPEAT_DATA2_REG[23:8]', bloc: 'B13,B14'} + SECURE_BOOT_DISABLE_FAST_WAKE : {show: y, blk : 0, word: 3, pos: 24, len : 1, start: 120, type : bool, wr_dis : 18, rd_dis: null, alt : '', dict : '', desc: Represents whether FAST_VERIFY_ON_WAKE is disable or enable when Secure Boot is enable, rloc: 'EFUSE_RD_REPEAT_DATA2_REG[24]', bloc: 'B15[0]'} + HYS_EN_PAD : {show: y, blk : 0, word: 3, pos: 25, len : 1, start: 121, type : bool, wr_dis : 2, rd_dis: null, alt : '', dict : '', desc: Set bits to enable hysteresis function of PAD0~27, rloc: 'EFUSE_RD_REPEAT_DATA2_REG[25]', bloc: 'B15[1]'} + XTS_DPA_CLK_ENABLE : {show: y, blk : 0, word: 3, pos: 26, len : 1, start: 122, type : bool, wr_dis : 14, rd_dis: null, alt : '', dict : '', desc: 'Represents whether xts-aes anti-dpa attack clock is enabled. 1. Enable. 0: Disable.', rloc: 'EFUSE_RD_REPEAT_DATA2_REG[26]', bloc: 'B15[2]'} + XTS_DPA_PSEUDO_LEVEL : {show: y, blk : 0, word: 3, pos: 27, len : 2, start: 123, type : 'uint:2', wr_dis : 14, rd_dis: null, alt : '', dict : '', desc: 'Represents the pseudo round level of xts-aes anti-dpa attack. 3: High. 2: Moderate 1. Low 0: Disabled', rloc: 'EFUSE_RD_REPEAT_DATA2_REG[28:27]', bloc: 'B15[4:3]'} + DIS_WIFI6 : {show: y, blk : 0, word: 3, pos: 29, len : 1, start: 125, type : bool, wr_dis : 2, rd_dis: null, alt : '', dict : '', desc: 'Represents whether the WIFI6 feature is enable or disabled. 1: WIFI6 is disable; 0: WIFI6 is enabled', rloc: 'EFUSE_RD_REPEAT_DATA2_REG[29]', bloc: 'B15[5]'} + ECDSA_DISABLE_P192 : {show: y, blk : 0, word: 3, pos: 30, len : 1, start: 126, type : bool, wr_dis : 14, rd_dis: null, alt : '', dict : '', desc: 'Represents whether to disable P192 curve in ECDSA. 1: Disabled. 0: Not disabled', rloc: 'EFUSE_RD_REPEAT_DATA2_REG[30]', bloc: 'B15[6]'} + ECC_FORCE_CONST_TIME : {show: y, blk : 0, word: 3, pos: 31, len : 1, start: 127, type : bool, wr_dis : 14, rd_dis: null, alt : '', dict : '', desc: 'Represents whether to force ecc to use const-time calculation mode. 1: Enable. 0: Disable', rloc: 'EFUSE_RD_REPEAT_DATA2_REG[31]', bloc: 'B15[7]'} + BOOTLOADER_ANTI_ROLLBACK_SECURE_VERSION: {show: y, blk : 0, word: 4, pos : 0, len : 4, start: 128, type : 'uint:4', wr_dis: null, rd_dis: null, alt : '', dict : '', desc: Represents the anti-rollback secure version of the 2nd stage bootloader used by the ROM bootloader, rloc: 'EFUSE_RD_REPEAT_DATA3_REG[3:0]', bloc: 'B16[3:0]'} + BOOTLOADER_ANTI_ROLLBACK_EN : {show: y, blk : 0, word: 4, pos : 4, len : 1, start: 132, type : bool, wr_dis: null, rd_dis: null, alt : '', dict : '', desc: 'Represents whether the ani-rollback check for the 2nd stage bootloader is enabled.1: Enabled0: Disabled', rloc: 'EFUSE_RD_REPEAT_DATA3_REG[4]', bloc: 'B16[4]'} + BOOTLOADER_ANTI_ROLLBACK_UPDATE_IN_ROM : {show: y, blk : 0, word: 4, pos : 5, len : 1, start: 133, type : bool, wr_dis: null, rd_dis: null, alt : '', dict : '', desc: 'Represents whether the ani-rollback SECURE_VERSION will be updated from the ROM bootloader.1: Enable0: Disable', rloc: 'EFUSE_RD_REPEAT_DATA3_REG[5]', bloc: 'B16[5]'} + RECOVERY_BOOTLOADER_FLASH_SECTOR : {show: y, blk : 0, word: 4, pos : 6, len : 12, start: 134, type : 'uint:12', wr_dis: null, rd_dis: null, alt : '', dict : '', desc: Represents the starting flash sector (flash sector size is 0x1000) of the recovery bootloader used by the ROM bootloader If the primary bootloader fails. 0 and 0xFFF - this feature is disabled, rloc: 'EFUSE_RD_REPEAT_DATA3_REG[17:6]', bloc: 'B16[7:6],B17,B18[1:0]'} + RESERVE_0_146 : {show: n, blk : 0, word: 4, pos: 18, len : 14, start: 146, type : 'uint:14', wr_dis: null, rd_dis: null, alt : '', dict : '', desc: Reserved; it was created by set_missed_fields_in_regs func, rloc: 'EFUSE_RD_REPEAT_DATA3_REG[31:18]', bloc: 'B18[7:2],B19'} + REPEAT_DATA4 : {show: y, blk : 0, word: 5, pos : 0, len : 24, start: 160, type : 'uint:24', wr_dis: null, rd_dis: null, alt : '', dict : '', desc: Reserved, rloc: 'EFUSE_RD_REPEAT_DATA4_REG[23:0]', bloc: 'B20,B21,B22'} + RESERVE_0_184 : {show: n, blk : 0, word: 5, pos: 24, len : 8, start: 184, type : 'uint:8', wr_dis: null, rd_dis: null, alt : '', dict : '', desc: Reserved; it was created by set_missed_fields_in_regs func, rloc: 'EFUSE_RD_REPEAT_DATA4_REG[31:24]', bloc: B23} + MAC : {show: y, blk : 1, word: 0, pos : 0, len : 48, start : 0, type : 'bytes:6', wr_dis : 20, rd_dis: null, alt : MAC_FACTORY, dict : '', desc: MAC address, rloc: EFUSE_RD_MAC_SYS0_REG, bloc: 'B0,B1,B2,B3,B4,B5'} + RESERVE_1_48 : {show: n, blk : 1, word: 1, pos: 16, len : 16, start : 48, type : 'uint:16', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: Reserved; it was created by set_missed_fields_in_regs func, rloc: 'EFUSE_RD_MAC_SYS1_REG[31:16]', bloc: 'B6,B7'} + WAFER_VERSION_MINOR : {show: y, blk : 1, word: 2, pos : 0, len : 4, start : 64, type : 'uint:4', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: Minor chip version, rloc: 'EFUSE_RD_MAC_SYS2_REG[3:0]', bloc: 'B8[3:0]'} + WAFER_VERSION_MAJOR : {show: y, blk : 1, word: 2, pos : 4, len : 2, start : 68, type : 'uint:2', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: Major chip version, rloc: 'EFUSE_RD_MAC_SYS2_REG[5:4]', bloc: 'B8[5:4]'} + DISABLE_WAFER_VERSION_MAJOR : {show: y, blk : 1, word: 2, pos : 6, len : 1, start : 70, type : bool, wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: Disables check of wafer version major, rloc: 'EFUSE_RD_MAC_SYS2_REG[6]', bloc: 'B8[6]'} + DISABLE_BLK_VERSION_MAJOR : {show: y, blk : 1, word: 2, pos : 7, len : 1, start : 71, type : bool, wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: Disables check of blk version major, rloc: 'EFUSE_RD_MAC_SYS2_REG[7]', bloc: 'B8[7]'} + BLK_VERSION_MINOR : {show: y, blk : 1, word: 2, pos : 8, len : 3, start : 72, type : 'uint:3', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: BLK_VERSION_MINOR of BLOCK2, rloc: 'EFUSE_RD_MAC_SYS2_REG[10:8]', bloc: 'B9[2:0]'} + BLK_VERSION_MAJOR : {show: y, blk : 1, word: 2, pos: 11, len : 2, start : 75, type : 'uint:2', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: BLK_VERSION_MAJOR of BLOCK2, rloc: 'EFUSE_RD_MAC_SYS2_REG[12:11]', bloc: 'B9[4:3]'} + FLASH_CAP : {show: y, blk : 1, word: 2, pos: 13, len : 3, start : 77, type : 'uint:3', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: Flash capacity, rloc: 'EFUSE_RD_MAC_SYS2_REG[15:13]', bloc: 'B9[7:5]'} + FLASH_VENDOR : {show: y, blk : 1, word: 2, pos: 16, len : 3, start : 80, type : 'uint:3', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: Flash vendor, rloc: 'EFUSE_RD_MAC_SYS2_REG[18:16]', bloc: 'B10[2:0]'} + PSRAM_CAP : {show: y, blk : 1, word: 2, pos: 19, len : 3, start : 83, type : 'uint:3', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: PSRAM capacity, rloc: 'EFUSE_RD_MAC_SYS2_REG[21:19]', bloc: 'B10[5:3]'} + PSRAM_VENDOR : {show: y, blk : 1, word: 2, pos: 22, len : 2, start : 86, type : 'uint:2', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: PSRAM vendor, rloc: 'EFUSE_RD_MAC_SYS2_REG[23:22]', bloc: 'B10[7:6]'} + TEMP : {show: y, blk : 1, word: 2, pos: 24, len : 2, start : 88, type : 'uint:2', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: Temperature, rloc: 'EFUSE_RD_MAC_SYS2_REG[25:24]', bloc: 'B11[1:0]'} + PKG_VERSION : {show: y, blk : 1, word: 2, pos: 26, len : 3, start : 90, type : 'uint:3', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: Package version, rloc: 'EFUSE_RD_MAC_SYS2_REG[28:26]', bloc: 'B11[4:2]'} + ACTIVE_HP_DBIAS : {show: y, blk : 1, word: 2, pos: 29, len : 4, start : 93, type : 'uint:4', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: Active HP DBIAS of fixed voltage, rloc: 'EFUSE_RD_MAC_SYS2_REG[31:29]', bloc: 'B11[7:5],B12[0]'} + ACTIVE_LP_DBIAS : {show: y, blk : 1, word: 3, pos : 1, len : 4, start : 97, type : 'uint:4', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: Active LP DBIAS of fixed voltage, rloc: 'EFUSE_RD_MAC_SYS3_REG[4:1]', bloc: 'B12[4:1]'} + LSLP_HP_DBG : {show: y, blk : 1, word: 3, pos : 5, len : 2, start: 101, type : 'uint:2', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: LSLP HP DBG of fixed voltage, rloc: 'EFUSE_RD_MAC_SYS3_REG[6:5]', bloc: 'B12[6:5]'} + LSLP_HP_DBIAS : {show: y, blk : 1, word: 3, pos : 7, len : 4, start: 103, type : 'uint:4', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: LSLP HP DBIAS of fixed voltage, rloc: 'EFUSE_RD_MAC_SYS3_REG[10:7]', bloc: 'B12[7],B13[2:0]'} + DSLP_LP_DBG : {show: y, blk : 1, word: 3, pos: 11, len : 4, start: 107, type : 'uint:4', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: DSLP LP DBG of fixed voltage, rloc: 'EFUSE_RD_MAC_SYS3_REG[14:11]', bloc: 'B13[6:3]'} + DSLP_LP_DBIAS : {show: y, blk : 1, word: 3, pos: 15, len : 5, start: 111, type : 'uint:5', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: DSLP LP DBIAS of fixed voltage, rloc: 'EFUSE_RD_MAC_SYS3_REG[19:15]', bloc: 'B13[7],B14[3:0]'} + LP_HP_DBIAS_VOL_GAP : {show: y, blk : 1, word: 3, pos: 20, len : 5, start: 116, type : 'uint:5', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: DBIAS gap between LP and HP, rloc: 'EFUSE_RD_MAC_SYS3_REG[24:20]', bloc: 'B14[7:4],B15[0]'} + RESERVED_1_121 : {show: n, blk : 1, word: 3, pos: 25, len : 7, start: 121, type : 'uint:7', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: reserved, rloc: 'EFUSE_RD_MAC_SYS3_REG[31:25]', bloc: 'B15[7:1]'} + SYS_DATA_PART0_1 : {show: n, blk : 1, word: 4, pos : 0, len : 32, start: 128, type : 'uint:32', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: Represents the first 14-bit of zeroth part of system data, rloc: EFUSE_RD_MAC_SYS4_REG, bloc: 'B16,B17,B18,B19'} + SYS_DATA_PART0_2 : {show: n, blk : 1, word: 5, pos : 0, len : 32, start: 160, type : 'uint:32', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: Represents the second 32-bit of zeroth part of system data, rloc: EFUSE_RD_MAC_SYS5_REG, bloc: 'B20,B21,B22,B23'} + OPTIONAL_UNIQUE_ID : {show: y, blk : 2, word: 0, pos : 0, len: 128, start : 0, type: 'bytes:16', wr_dis : 21, rd_dis: null, alt : '', dict : '', desc: Optional unique 128-bit ID, rloc: EFUSE_RD_SYS_PART1_DATA0_REG, bloc: 'B0,B1,B2,B3,B4,B5,B6,B7,B8,B9,B10,B11,B12,B13,B14,B15'} + TEMPERATURE_SENSOR : {show: y, blk : 2, word: 4, pos : 0, len : 9, start: 128, type : 'uint:9', wr_dis : 21, rd_dis: null, alt : '', dict : '', desc: Temperature calibration data, rloc: 'EFUSE_RD_SYS_PART1_DATA4_REG[8:0]', bloc: 'B16,B17[0]'} + OCODE : {show: y, blk : 2, word: 4, pos : 9, len : 8, start: 137, type : 'uint:8', wr_dis : 21, rd_dis: null, alt : '', dict : '', desc: ADC OCode calibration, rloc: 'EFUSE_RD_SYS_PART1_DATA4_REG[16:9]', bloc: 'B17[7:1],B18[0]'} + ADC1_AVE_INIT_CODE_ATTEN0 : {show: y, blk : 2, word: 4, pos: 17, len : 10, start: 145, type : 'uint:10', wr_dis : 21, rd_dis: null, alt : '', dict : '', desc: Average initcode of ADC1 atten0, rloc: 'EFUSE_RD_SYS_PART1_DATA4_REG[26:17]', bloc: 'B18[7:1],B19[2:0]'} + ADC1_AVE_INIT_CODE_ATTEN1 : {show: y, blk : 2, word: 4, pos: 27, len : 10, start: 155, type : 'uint:10', wr_dis : 21, rd_dis: null, alt : '', dict : '', desc: Average initcode of ADC1 atten1, rloc: 'EFUSE_RD_SYS_PART1_DATA4_REG[31:27]', bloc: 'B19[7:3],B20[4:0]'} + ADC1_AVE_INIT_CODE_ATTEN2 : {show: y, blk : 2, word: 5, pos : 5, len : 10, start: 165, type : 'uint:10', wr_dis : 21, rd_dis: null, alt : '', dict : '', desc: Average initcode of ADC1 atten2, rloc: 'EFUSE_RD_SYS_PART1_DATA5_REG[14:5]', bloc: 'B20[7:5],B21[6:0]'} + ADC1_AVE_INIT_CODE_ATTEN3 : {show: y, blk : 2, word: 5, pos: 15, len : 10, start: 175, type : 'uint:10', wr_dis : 21, rd_dis: null, alt : '', dict : '', desc: Average initcode of ADC1 atten3, rloc: 'EFUSE_RD_SYS_PART1_DATA5_REG[24:15]', bloc: 'B21[7],B22,B23[0]'} + ADC1_HI_DOUT_ATTEN0 : {show: y, blk : 2, word: 5, pos: 25, len : 10, start: 185, type : 'uint:10', wr_dis : 21, rd_dis: null, alt : '', dict : '', desc: HI_DOUT of ADC1 atten0, rloc: 'EFUSE_RD_SYS_PART1_DATA5_REG[31:25]', bloc: 'B23[7:1],B24[2:0]'} + ADC1_HI_DOUT_ATTEN1 : {show: y, blk : 2, word: 6, pos : 3, len : 10, start: 195, type : 'uint:10', wr_dis : 21, rd_dis: null, alt : '', dict : '', desc: HI_DOUT of ADC1 atten1, rloc: 'EFUSE_RD_SYS_PART1_DATA6_REG[12:3]', bloc: 'B24[7:3],B25[4:0]'} + ADC1_HI_DOUT_ATTEN2 : {show: y, blk : 2, word: 6, pos: 13, len : 10, start: 205, type : 'uint:10', wr_dis : 21, rd_dis: null, alt : '', dict : '', desc: HI_DOUT of ADC1 atten2, rloc: 'EFUSE_RD_SYS_PART1_DATA6_REG[22:13]', bloc: 'B25[7:5],B26[6:0]'} + ADC1_HI_DOUT_ATTEN3 : {show: y, blk : 2, word: 6, pos: 23, len : 10, start: 215, type : 'uint:10', wr_dis : 21, rd_dis: null, alt : '', dict : '', desc: HI_DOUT of ADC1 atten3, rloc: 'EFUSE_RD_SYS_PART1_DATA6_REG[31:23]', bloc: 'B26[7],B27,B28[0]'} + ADC1_CH0_ATTEN0_INITCODE_DIFF : {show: y, blk : 2, word: 7, pos : 1, len : 4, start: 225, type : 'uint:4', wr_dis : 21, rd_dis: null, alt : '', dict : '', desc: Gap between ADC1 CH0 and average initcode, rloc: 'EFUSE_RD_SYS_PART1_DATA7_REG[4:1]', bloc: 'B28[4:1]'} + ADC1_CH1_ATTEN0_INITCODE_DIFF : {show: y, blk : 2, word: 7, pos : 5, len : 4, start: 229, type : 'uint:4', wr_dis : 21, rd_dis: null, alt : '', dict : '', desc: Gap between ADC1 CH1 and average initcode, rloc: 'EFUSE_RD_SYS_PART1_DATA7_REG[8:5]', bloc: 'B28[7:5],B29[0]'} + ADC1_CH2_ATTEN0_INITCODE_DIFF : {show: y, blk : 2, word: 7, pos : 9, len : 4, start: 233, type : 'uint:4', wr_dis : 21, rd_dis: null, alt : '', dict : '', desc: Gap between ADC1 CH2 and average initcode, rloc: 'EFUSE_RD_SYS_PART1_DATA7_REG[12:9]', bloc: 'B29[4:1]'} + ADC1_CH3_ATTEN0_INITCODE_DIFF : {show: y, blk : 2, word: 7, pos: 13, len : 4, start: 237, type : 'uint:4', wr_dis : 21, rd_dis: null, alt : '', dict : '', desc: Gap between ADC1 CH3 and average initcode, rloc: 'EFUSE_RD_SYS_PART1_DATA7_REG[16:13]', bloc: 'B29[7:5],B30[0]'} + RESERVED_2_241 : {show: n, blk : 2, word: 7, pos: 17, len : 15, start: 241, type : 'uint:15', wr_dis : 21, rd_dis: null, alt : '', dict : '', desc: reserved, rloc: 'EFUSE_RD_SYS_PART1_DATA7_REG[31:17]', bloc: 'B30[7:1],B31'} + BLOCK_USR_DATA : {show: y, blk : 3, word: 0, pos : 0, len: 192, start : 0, type: 'bytes:24', wr_dis : 22, rd_dis: null, alt : USER_DATA, dict : '', desc: User data, rloc: EFUSE_RD_USR_DATA0_REG, bloc: 'B0,B1,B2,B3,B4,B5,B6,B7,B8,B9,B10,B11,B12,B13,B14,B15,B16,B17,B18,B19,B20,B21,B22,B23'} + RESERVED_3_192 : {show: n, blk : 3, word: 6, pos : 0, len : 8, start: 192, type : 'uint:8', wr_dis : 22, rd_dis: null, alt : '', dict : '', desc: reserved, rloc: 'EFUSE_RD_USR_DATA6_REG[7:0]', bloc: B24} + CUSTOM_MAC : {show: y, blk : 3, word: 6, pos : 8, len : 48, start: 200, type : 'bytes:6', wr_dis : 22, rd_dis: null, alt: MAC_CUSTOM USER_DATA_MAC_CUSTOM, dict : '', desc: Custom MAC, rloc: 'EFUSE_RD_USR_DATA6_REG[31:8]', bloc: 'B25,B26,B27,B28,B29,B30'} + RESERVED_3_248 : {show: n, blk : 3, word: 7, pos: 24, len : 8, start: 248, type : 'uint:8', wr_dis : 22, rd_dis: null, alt : '', dict : '', desc: reserved, rloc: 'EFUSE_RD_USR_DATA7_REG[31:24]', bloc: B31} + BLOCK_KEY0 : {show: y, blk : 4, word: 0, pos : 0, len: 256, start : 0, type: 'bytes:32', wr_dis : 23, rd_dis : 0, alt : KEY0, dict : '', desc: Key0 or user data, rloc: EFUSE_RD_KEY0_DATA0_REG, bloc: 'B0,B1,B2,B3,B4,B5,B6,B7,B8,B9,B10,B11,B12,B13,B14,B15,B16,B17,B18,B19,B20,B21,B22,B23,B24,B25,B26,B27,B28,B29,B30,B31'} + BLOCK_KEY1 : {show: y, blk : 5, word: 0, pos : 0, len: 256, start : 0, type: 'bytes:32', wr_dis : 24, rd_dis : 1, alt : KEY1, dict : '', desc: Key1 or user data, rloc: EFUSE_RD_KEY1_DATA0_REG, bloc: 'B0,B1,B2,B3,B4,B5,B6,B7,B8,B9,B10,B11,B12,B13,B14,B15,B16,B17,B18,B19,B20,B21,B22,B23,B24,B25,B26,B27,B28,B29,B30,B31'} + BLOCK_KEY2 : {show: y, blk : 6, word: 0, pos : 0, len: 256, start : 0, type: 'bytes:32', wr_dis : 25, rd_dis : 2, alt : KEY2, dict : '', desc: Key2 or user data, rloc: EFUSE_RD_KEY2_DATA0_REG, bloc: 'B0,B1,B2,B3,B4,B5,B6,B7,B8,B9,B10,B11,B12,B13,B14,B15,B16,B17,B18,B19,B20,B21,B22,B23,B24,B25,B26,B27,B28,B29,B30,B31'} + BLOCK_KEY3 : {show: y, blk : 7, word: 0, pos : 0, len: 256, start : 0, type: 'bytes:32', wr_dis : 26, rd_dis : 3, alt : KEY3, dict : '', desc: Key3 or user data, rloc: EFUSE_RD_KEY3_DATA0_REG, bloc: 'B0,B1,B2,B3,B4,B5,B6,B7,B8,B9,B10,B11,B12,B13,B14,B15,B16,B17,B18,B19,B20,B21,B22,B23,B24,B25,B26,B27,B28,B29,B30,B31'} + BLOCK_KEY4 : {show: y, blk : 8, word: 0, pos : 0, len: 256, start : 0, type: 'bytes:32', wr_dis : 27, rd_dis : 4, alt : KEY4, dict : '', desc: Key4 or user data, rloc: EFUSE_RD_KEY4_DATA0_REG, bloc: 'B0,B1,B2,B3,B4,B5,B6,B7,B8,B9,B10,B11,B12,B13,B14,B15,B16,B17,B18,B19,B20,B21,B22,B23,B24,B25,B26,B27,B28,B29,B30,B31'} + BLOCK_KEY5 : {show: y, blk : 9, word: 0, pos : 0, len: 256, start : 0, type: 'bytes:32', wr_dis : 28, rd_dis : 5, alt : KEY5, dict : '', desc: Key5 or user data, rloc: EFUSE_RD_KEY5_DATA0_REG, bloc: 'B0,B1,B2,B3,B4,B5,B6,B7,B8,B9,B10,B11,B12,B13,B14,B15,B16,B17,B18,B19,B20,B21,B22,B23,B24,B25,B26,B27,B28,B29,B30,B31'} + BLOCK_SYS_DATA2 : {show: y, blk: 10, word: 0, pos : 0, len: 256, start : 0, type: 'bytes:32', wr_dis : 29, rd_dis : 6, alt : SYS_DATA_PART2, dict : '', desc: System data part 2 (reserved), rloc: EFUSE_RD_SYS_PART2_DATA0_REG, bloc: 'B0,B1,B2,B3,B4,B5,B6,B7,B8,B9,B10,B11,B12,B13,B14,B15,B16,B17,B18,B19,B20,B21,B22,B23,B24,B25,B26,B27,B28,B29,B30,B31'} diff --git a/tools/esptool_py/espefuse/efuse_defs/esp32h2.yaml b/tools/esptool_py/espefuse/efuse_defs/esp32h2.yaml index 7dddf5108e..ecd3df3e9d 100644 --- a/tools/esptool_py/espefuse/efuse_defs/esp32h2.yaml +++ b/tools/esptool_py/espefuse/efuse_defs/esp32h2.yaml @@ -1,4 +1,4 @@ -VER_NO: ef562916e77cf77203c1a4c0cff35ac5 +VER_NO: 44563d2af4ebdba4db6c0a34a50c94f9 EFUSES: WR_DIS : {show: y, blk : 0, word: 0, pos : 0, len : 32, start : 0, type : 'uint:32', wr_dis: null, rd_dis: null, alt : '', dict : '', desc: Disable programming of individual eFuses, rloc: EFUSE_RD_WR_DIS_REG, bloc: 'B0,B1,B2,B3'} RD_DIS : {show: y, blk : 0, word: 1, pos : 0, len : 7, start : 32, type : 'uint:7', wr_dis : 0, rd_dis: null, alt : '', dict : '', desc: Disable reading from BlOCK4-10, rloc: 'EFUSE_RD_REPEAT_DATA0_REG[6:0]', bloc: 'B4[6:0]'} @@ -18,9 +18,9 @@ EFUSES: USB_DREFL : {show: n, blk : 0, word: 1, pos: 23, len : 2, start : 55, type : 'uint:2', wr_dis : 30, rd_dis: null, alt : '', dict : '', desc: Represents the single-end input threshold vrefl; 1.76 V to 2 V with step of 80 mV, rloc: 'EFUSE_RD_REPEAT_DATA0_REG[24:23]', bloc: 'B6[7],B7[0]'} USB_EXCHG_PINS : {show: y, blk : 0, word: 1, pos: 25, len : 1, start : 57, type : bool, wr_dis : 30, rd_dis: null, alt : '', dict : '', desc: 'Represents whether the D+ and D- pins is exchanged. 1: exchanged. 0: not exchanged', rloc: 'EFUSE_RD_REPEAT_DATA0_REG[25]', bloc: 'B7[1]'} VDD_SPI_AS_GPIO : {show: y, blk : 0, word: 1, pos: 26, len : 1, start : 58, type : bool, wr_dis : 30, rd_dis: null, alt : '', dict : '', desc: 'Represents whether vdd spi pin is functioned as gpio. 1: functioned. 0: not functioned', rloc: 'EFUSE_RD_REPEAT_DATA0_REG[26]', bloc: 'B7[2]'} - RPT4_RESERVED0_2 : {show: n, blk : 0, word: 1, pos: 27, len : 2, start : 59, type : 'uint:2', wr_dis: null, rd_dis: null, alt : '', dict : '', desc: Reserved, rloc: 'EFUSE_RD_REPEAT_DATA0_REG[28:27]', bloc: 'B7[4:3]'} - RPT4_RESERVED0_1 : {show: n, blk : 0, word: 1, pos: 29, len : 1, start : 61, type : bool, wr_dis: null, rd_dis: null, alt : '', dict : '', desc: Reserved, rloc: 'EFUSE_RD_REPEAT_DATA0_REG[29]', bloc: 'B7[5]'} - RPT4_RESERVED0_0 : {show: n, blk : 0, word: 1, pos: 30, len : 2, start : 62, type : 'uint:2', wr_dis: null, rd_dis: null, alt : '', dict : '', desc: Reserved, rloc: 'EFUSE_RD_REPEAT_DATA0_REG[31:30]', bloc: 'B7[7:6]'} + ECDSA_CURVE_MODE : {show: y, blk : 0, word: 1, pos: 27, len : 2, start : 59, type : 'uint:2', wr_dis : 17, rd_dis: null, alt : '', dict : '', desc: 'Configures the curve of ECDSA calculation: 0: only enable P256. 1: only enable P192. 2: both enable P256 and P192. 3: only enable P256', rloc: 'EFUSE_RD_REPEAT_DATA0_REG[28:27]', bloc: 'B7[4:3]'} + ECC_FORCE_CONST_TIME : {show: y, blk : 0, word: 1, pos: 29, len : 1, start : 61, type : bool, wr_dis : 17, rd_dis: null, alt : '', dict : '', desc: Set this bit to permanently turn on ECC const-time mode, rloc: 'EFUSE_RD_REPEAT_DATA0_REG[29]', bloc: 'B7[5]'} + XTS_DPA_PSEUDO_LEVEL : {show: y, blk : 0, word: 1, pos: 30, len : 2, start : 62, type : 'uint:2', wr_dis : 14, rd_dis: null, alt : '', dict : '', desc: 'Set this bit to control the xts pseudo-round anti-dpa attack function: 0: controlled by register. 1-3: the higher the value is; the more pseudo-rounds are inserted to the xts-aes calculation', rloc: 'EFUSE_RD_REPEAT_DATA0_REG[31:30]', bloc: 'B7[7:6]'} RPT4_RESERVED1_1 : {show: n, blk : 0, word: 2, pos : 0, len : 16, start : 64, type : 'uint:16', wr_dis: null, rd_dis: null, alt : '', dict : '', desc: Reserved, rloc: 'EFUSE_RD_REPEAT_DATA1_REG[15:0]', bloc: 'B8,B9'} WDT_DELAY_SEL : {show: y, blk : 0, word: 2, pos: 16, len : 2, start : 80, type : 'uint:2', wr_dis : 3, rd_dis: null, alt : '', dict : '', desc: 'Represents whether RTC watchdog timeout threshold is selected at startup. 1: selected. 0: not selected', rloc: 'EFUSE_RD_REPEAT_DATA1_REG[17:16]', bloc: 'B10[1:0]'} SPI_BOOT_CRYPT_CNT : {show: y, blk : 0, word: 2, pos: 18, len : 3, start : 82, type : 'uint:3', wr_dis : 4, rd_dis: null, alt : '', dict: '{0: "Disable", 1: "Enable", 3: "Disable", 7: "Enable"}', desc: Enables flash encryption when 1 or 3 bits are set and disables otherwise, rloc: 'EFUSE_RD_REPEAT_DATA1_REG[20:18]', bloc: 'B10[4:2]'} @@ -34,11 +34,12 @@ EFUSES: KEY_PURPOSE_4 : {show: y, blk : 0, word: 3, pos : 8, len : 4, start: 104, type : 'uint:4', wr_dis : 12, rd_dis: null, alt : KEY4_PURPOSE, dict : '', desc: Represents the purpose of Key4, rloc: 'EFUSE_RD_REPEAT_DATA2_REG[11:8]', bloc: 'B13[3:0]'} KEY_PURPOSE_5 : {show: y, blk : 0, word: 3, pos: 12, len : 4, start: 108, type : 'uint:4', wr_dis : 13, rd_dis: null, alt : KEY5_PURPOSE, dict : '', desc: Represents the purpose of Key5, rloc: 'EFUSE_RD_REPEAT_DATA2_REG[15:12]', bloc: 'B13[7:4]'} SEC_DPA_LEVEL : {show: y, blk : 0, word: 3, pos: 16, len : 2, start: 112, type : 'uint:2', wr_dis : 14, rd_dis: null, alt : '', dict : '', desc: Represents the spa secure level by configuring the clock random divide mode, rloc: 'EFUSE_RD_REPEAT_DATA2_REG[17:16]', bloc: 'B14[1:0]'} - ECDSA_FORCE_USE_HARDWARE_K : {show: y, blk : 0, word: 3, pos: 18, len : 1, start: 114, type : bool, wr_dis : 17, rd_dis: null, alt : '', dict : '', desc: 'Represents whether hardware random number k is forced used in ESDCA. 1: force used. 0: not force used', rloc: 'EFUSE_RD_REPEAT_DATA2_REG[18]', bloc: 'B14[2]'} + RESERVE_0_114 : {show: n, blk : 0, word: 3, pos: 18, len : 1, start: 114, type : bool, wr_dis : 17, rd_dis: null, alt : '', dict : '', desc: Reserved, rloc: 'EFUSE_RD_REPEAT_DATA2_REG[18]', bloc: 'B14[2]'} CRYPT_DPA_ENABLE : {show: y, blk : 0, word: 3, pos: 19, len : 1, start: 115, type : bool, wr_dis : 14, rd_dis: null, alt : '', dict : '', desc: 'Represents whether anti-dpa attack is enabled. 1:enabled. 0: disabled', rloc: 'EFUSE_RD_REPEAT_DATA2_REG[19]', bloc: 'B14[3]'} SECURE_BOOT_EN : {show: y, blk : 0, word: 3, pos: 20, len : 1, start: 116, type : bool, wr_dis : 15, rd_dis: null, alt : '', dict : '', desc: 'Represents whether secure boot is enabled or disabled. 1: enabled. 0: disabled', rloc: 'EFUSE_RD_REPEAT_DATA2_REG[20]', bloc: 'B14[4]'} SECURE_BOOT_AGGRESSIVE_REVOKE : {show: y, blk : 0, word: 3, pos: 21, len : 1, start: 117, type : bool, wr_dis : 16, rd_dis: null, alt : '', dict : '', desc: 'Represents whether revoking aggressive secure boot is enabled or disabled. 1: enabled. 0: disabled', rloc: 'EFUSE_RD_REPEAT_DATA2_REG[21]', bloc: 'B14[5]'} - RPT4_RESERVED2_0 : {show: n, blk : 0, word: 3, pos: 22, len : 6, start: 118, type : 'uint:6', wr_dis: null, rd_dis: null, alt : '', dict : '', desc: Reserved, rloc: 'EFUSE_RD_REPEAT_DATA2_REG[27:22]', bloc: 'B14[7:6],B15[3:0]'} + POWERGLITCH_EN1 : {show: y, blk : 0, word: 3, pos: 22, len : 5, start: 118, type : 'uint:5', wr_dis : 2, rd_dis: null, alt : '', dict : '', desc: Set these bits to enable power glitch function when chip power on, rloc: 'EFUSE_RD_REPEAT_DATA2_REG[26:22]', bloc: 'B14[7:6],B15[2:0]'} + RESERVED_0_123 : {show: n, blk : 0, word: 3, pos: 27, len : 1, start: 123, type : bool, wr_dis: null, rd_dis: null, alt : '', dict : '', desc: reserved, rloc: 'EFUSE_RD_REPEAT_DATA2_REG[27]', bloc: 'B15[3]'} FLASH_TPUW : {show: y, blk : 0, word: 3, pos: 28, len : 4, start: 124, type : 'uint:4', wr_dis : 18, rd_dis: null, alt : '', dict : '', desc: Represents the flash waiting time after power-up; in unit of ms. When the value less than 15; the waiting time is the programmed value. Otherwise; the waiting time is 2 times the programmed value, rloc: 'EFUSE_RD_REPEAT_DATA2_REG[31:28]', bloc: 'B15[7:4]'} DIS_DOWNLOAD_MODE : {show: y, blk : 0, word: 4, pos : 0, len : 1, start: 128, type : bool, wr_dis : 18, rd_dis: null, alt : '', dict : '', desc: 'Represents whether Download mode is disabled or enabled. 1: disabled. 0: enabled', rloc: 'EFUSE_RD_REPEAT_DATA3_REG[0]', bloc: 'B16[0]'} DIS_DIRECT_BOOT : {show: y, blk : 0, word: 4, pos : 1, len : 1, start: 129, type : bool, wr_dis : 18, rd_dis: null, alt : '', dict : '', desc: 'Represents whether direct boot mode is disabled or enabled. 1: disabled. 0: enabled', rloc: 'EFUSE_RD_REPEAT_DATA3_REG[1]', bloc: 'B16[1]'} diff --git a/tools/esptool_py/espefuse/efuse_defs/esp32c5beta3.yaml b/tools/esptool_py/espefuse/efuse_defs/esp32h21.yaml similarity index 55% rename from tools/esptool_py/espefuse/efuse_defs/esp32c5beta3.yaml rename to tools/esptool_py/espefuse/efuse_defs/esp32h21.yaml index 31af46a56d..878b44651e 100644 --- a/tools/esptool_py/espefuse/efuse_defs/esp32c5beta3.yaml +++ b/tools/esptool_py/espefuse/efuse_defs/esp32h21.yaml @@ -1,31 +1,28 @@ -VER_NO: b09fa417de505238a601eddce188b696 +VER_NO: ef562916e77cf77203c1a4c0cff35ac5 EFUSES: - WR_DIS : {show: y, blk : 0, word: 0, pos : 0, len : 32, start : 0, type : 'uint:32', wr_dis: null, rd_dis: null, alt : '', dict : '', desc: Disable programming of individual eFuses, rloc: EFUSE_RD_WR_DIS0_REG, bloc: 'B0,B1,B2,B3'} + WR_DIS : {show: y, blk : 0, word: 0, pos : 0, len : 32, start : 0, type : 'uint:32', wr_dis: null, rd_dis: null, alt : '', dict : '', desc: Disable programming of individual eFuses, rloc: EFUSE_RD_WR_DIS_REG, bloc: 'B0,B1,B2,B3'} RD_DIS : {show: y, blk : 0, word: 1, pos : 0, len : 7, start : 32, type : 'uint:7', wr_dis : 0, rd_dis: null, alt : '', dict : '', desc: Disable reading from BlOCK4-10, rloc: 'EFUSE_RD_REPEAT_DATA0_REG[6:0]', bloc: 'B4[6:0]'} - RESERVE_0_39 : {show: n, blk : 0, word: 1, pos : 7, len : 1, start : 39, type : bool, wr_dis: null, rd_dis: null, alt : '', dict : '', desc: Reserved; it was created by set_missed_fields_in_regs func, rloc: 'EFUSE_RD_REPEAT_DATA0_REG[7]', bloc: 'B4[7]'} - DIS_ICACHE : {show: y, blk : 0, word: 1, pos : 8, len : 1, start : 40, type : bool, wr_dis : 2, rd_dis: null, alt : '', dict : '', desc: 'Represents whether icache is disabled or enabled.\\ 1: disabled\\ 0: enabled\\', rloc: 'EFUSE_RD_REPEAT_DATA0_REG[8]', bloc: 'B5[0]'} - DIS_USB_JTAG : {show: y, blk : 0, word: 1, pos : 9, len : 1, start : 41, type : bool, wr_dis : 2, rd_dis: null, alt : '', dict : '', desc: 'Represents whether the function of usb switch to jtag is disabled or enabled.\\ 1: disabled\\ 0: enabled\\', rloc: 'EFUSE_RD_REPEAT_DATA0_REG[9]', bloc: 'B5[1]'} - RESERVE_0_42 : {show: n, blk : 0, word: 1, pos: 10, len : 1, start : 42, type : bool, wr_dis: null, rd_dis: null, alt : '', dict : '', desc: Reserved; it was created by set_missed_fields_in_regs func, rloc: 'EFUSE_RD_REPEAT_DATA0_REG[10]', bloc: 'B5[2]'} - DIS_USB_SERIAL_JTAG : {show: n, blk : 0, word: 1, pos: 11, len : 1, start : 43, type : bool, wr_dis : 2, rd_dis: null, alt : '', dict : '', desc: 'Represents whether USB-Serial-JTAG is disabled or enabled.\\ 1: disabled\\ 0: enabled\\', rloc: 'EFUSE_RD_REPEAT_DATA0_REG[11]', bloc: 'B5[3]'} - DIS_FORCE_DOWNLOAD : {show: y, blk : 0, word: 1, pos: 12, len : 1, start : 44, type : bool, wr_dis : 2, rd_dis: null, alt : '', dict : '', desc: 'Represents whether the function that forces chip into download mode is disabled or enabled.\\ 1: disabled\\ 0: enabled\\', rloc: 'EFUSE_RD_REPEAT_DATA0_REG[12]', bloc: 'B5[4]'} - SPI_DOWNLOAD_MSPI_DIS : {show: y, blk : 0, word: 1, pos: 13, len : 1, start : 45, type : bool, wr_dis : 2, rd_dis: null, alt : '', dict : '', desc: 'Represents whether SPI0 controller during boot_mode_download is disabled or enabled.\\ 1: disabled\\ 0: enabled\\', rloc: 'EFUSE_RD_REPEAT_DATA0_REG[13]', bloc: 'B5[5]'} - DIS_TWAI : {show: y, blk : 0, word: 1, pos: 14, len : 1, start : 46, type : bool, wr_dis : 2, rd_dis: null, alt : '', dict : '', desc: 'Represents whether TWAI function is disabled or enabled.\\ 1: disabled\\ 0: enabled\\', rloc: 'EFUSE_RD_REPEAT_DATA0_REG[14]', bloc: 'B5[6]'} - JTAG_SEL_ENABLE : {show: y, blk : 0, word: 1, pos: 15, len : 1, start : 47, type : bool, wr_dis : 2, rd_dis: null, alt : '', dict : '', desc: 'Represents whether the selection between usb_to_jtag and pad_to_jtag through strapping gpio15 when both EFUSE_DIS_PAD_JTAG and EFUSE_DIS_USB_JTAG are equal to 0 is enabled or disabled.\\ 1: enabled\\ 0: disabled\\', rloc: 'EFUSE_RD_REPEAT_DATA0_REG[15]', bloc: 'B5[7]'} - SOFT_DIS_JTAG : {show: y, blk : 0, word: 1, pos: 16, len : 3, start : 48, type : 'uint:3', wr_dis : 31, rd_dis: null, alt : '', dict : '', desc: 'Represents whether JTAG is disabled in soft way.\\ Odd number: disabled\\ Even number: enabled\\', rloc: 'EFUSE_RD_REPEAT_DATA0_REG[18:16]', bloc: 'B6[2:0]'} - DIS_PAD_JTAG : {show: y, blk : 0, word: 1, pos: 19, len : 1, start : 51, type : bool, wr_dis : 2, rd_dis: null, alt : '', dict : '', desc: 'Represents whether JTAG is disabled in the hard way(permanently).\\ 1: disabled\\ 0: enabled\\', rloc: 'EFUSE_RD_REPEAT_DATA0_REG[19]', bloc: 'B6[3]'} - DIS_DOWNLOAD_MANUAL_ENCRYPT : {show: y, blk : 0, word: 1, pos: 20, len : 1, start : 52, type : bool, wr_dis : 2, rd_dis: null, alt : '', dict : '', desc: 'Represents whether flash encrypt function is disabled or enabled(except in SPI boot mode).\\ 1: disabled\\ 0: enabled\\', rloc: 'EFUSE_RD_REPEAT_DATA0_REG[20]', bloc: 'B6[4]'} + RPT4_RESERVED0_4 : {show: n, blk : 0, word: 1, pos : 7, len : 1, start : 39, type : bool, wr_dis: null, rd_dis: null, alt : '', dict : '', desc: Reserved, rloc: 'EFUSE_RD_REPEAT_DATA0_REG[7]', bloc: 'B4[7]'} + DIS_ICACHE : {show: y, blk : 0, word: 1, pos : 8, len : 1, start : 40, type : bool, wr_dis : 2, rd_dis: null, alt : '', dict : '', desc: 'Represents whether icache is disabled or enabled. 1: disabled. 0: enabled', rloc: 'EFUSE_RD_REPEAT_DATA0_REG[8]', bloc: 'B5[0]'} + DIS_USB_JTAG : {show: y, blk : 0, word: 1, pos : 9, len : 1, start : 41, type : bool, wr_dis : 2, rd_dis: null, alt : '', dict : '', desc: 'Represents whether the function of usb switch to jtag is disabled or enabled. 1: disabled. 0: enabled', rloc: 'EFUSE_RD_REPEAT_DATA0_REG[9]', bloc: 'B5[1]'} + POWERGLITCH_EN : {show: y, blk : 0, word: 1, pos: 10, len : 1, start : 42, type : bool, wr_dis : 2, rd_dis: null, alt : '', dict : '', desc: 'Represents whether power glitch function is enabled. 1: enabled. 0: disabled', rloc: 'EFUSE_RD_REPEAT_DATA0_REG[10]', bloc: 'B5[2]'} + DIS_USB_SERIAL_JTAG : {show: n, blk : 0, word: 1, pos: 11, len : 1, start : 43, type : bool, wr_dis : 2, rd_dis: null, alt : '', dict : '', desc: 'Represents whether USB-Serial-JTAG is disabled or enabled. 1: disabled. 0: enabled', rloc: 'EFUSE_RD_REPEAT_DATA0_REG[11]', bloc: 'B5[3]'} + DIS_FORCE_DOWNLOAD : {show: y, blk : 0, word: 1, pos: 12, len : 1, start : 44, type : bool, wr_dis : 2, rd_dis: null, alt : '', dict : '', desc: 'Represents whether the function that forces chip into download mode is disabled or enabled. 1: disabled. 0: enabled', rloc: 'EFUSE_RD_REPEAT_DATA0_REG[12]', bloc: 'B5[4]'} + SPI_DOWNLOAD_MSPI_DIS : {show: y, blk : 0, word: 1, pos: 13, len : 1, start : 45, type : bool, wr_dis : 2, rd_dis: null, alt : '', dict : '', desc: 'Represents whether SPI0 controller during boot_mode_download is disabled or enabled. 1: disabled. 0: enabled', rloc: 'EFUSE_RD_REPEAT_DATA0_REG[13]', bloc: 'B5[5]'} + DIS_TWAI : {show: y, blk : 0, word: 1, pos: 14, len : 1, start : 46, type : bool, wr_dis : 2, rd_dis: null, alt : DIS_CAN, dict : '', desc: 'Represents whether TWAI function is disabled or enabled. 1: disabled. 0: enabled', rloc: 'EFUSE_RD_REPEAT_DATA0_REG[14]', bloc: 'B5[6]'} + JTAG_SEL_ENABLE : {show: y, blk : 0, word: 1, pos: 15, len : 1, start : 47, type : bool, wr_dis : 2, rd_dis: null, alt : '', dict : '', desc: Set this bit to enable selection between usb_to_jtag and pad_to_jtag through strapping gpio25 when both EFUSE_DIS_PAD_JTAG and EFUSE_DIS_USB_JTAG are equal to 0, rloc: 'EFUSE_RD_REPEAT_DATA0_REG[15]', bloc: 'B5[7]'} + SOFT_DIS_JTAG : {show: y, blk : 0, word: 1, pos: 16, len : 3, start : 48, type : 'uint:3', wr_dis : 31, rd_dis: null, alt : '', dict : '', desc: 'Represents whether JTAG is disabled in soft way. Odd number: disabled. Even number: enabled', rloc: 'EFUSE_RD_REPEAT_DATA0_REG[18:16]', bloc: 'B6[2:0]'} + DIS_PAD_JTAG : {show: y, blk : 0, word: 1, pos: 19, len : 1, start : 51, type : bool, wr_dis : 2, rd_dis: null, alt : '', dict : '', desc: 'Represents whether JTAG is disabled in the hard way(permanently). 1: disabled. 0: enabled', rloc: 'EFUSE_RD_REPEAT_DATA0_REG[19]', bloc: 'B6[3]'} + DIS_DOWNLOAD_MANUAL_ENCRYPT : {show: y, blk : 0, word: 1, pos: 20, len : 1, start : 52, type : bool, wr_dis : 2, rd_dis: null, alt : '', dict : '', desc: 'Represents whether flash encrypt function is disabled or enabled(except in SPI boot mode). 1: disabled. 0: enabled', rloc: 'EFUSE_RD_REPEAT_DATA0_REG[20]', bloc: 'B6[4]'} USB_DREFH : {show: n, blk : 0, word: 1, pos: 21, len : 2, start : 53, type : 'uint:2', wr_dis : 30, rd_dis: null, alt : '', dict : '', desc: Represents the single-end input threshold vrefh; 1.76 V to 2 V with step of 80 mV, rloc: 'EFUSE_RD_REPEAT_DATA0_REG[22:21]', bloc: 'B6[6:5]'} USB_DREFL : {show: n, blk : 0, word: 1, pos: 23, len : 2, start : 55, type : 'uint:2', wr_dis : 30, rd_dis: null, alt : '', dict : '', desc: Represents the single-end input threshold vrefl; 1.76 V to 2 V with step of 80 mV, rloc: 'EFUSE_RD_REPEAT_DATA0_REG[24:23]', bloc: 'B6[7],B7[0]'} - USB_EXCHG_PINS : {show: y, blk : 0, word: 1, pos: 25, len : 1, start : 57, type : bool, wr_dis : 30, rd_dis: null, alt : '', dict : '', desc: 'Represents whether the D+ and D- pins is exchanged.\\ 1: exchanged\\ 0: not exchanged\\', rloc: 'EFUSE_RD_REPEAT_DATA0_REG[25]', bloc: 'B7[1]'} - VDD_SPI_AS_GPIO : {show: y, blk : 0, word: 1, pos: 26, len : 1, start : 58, type : bool, wr_dis : 30, rd_dis: null, alt : '', dict : '', desc: 'Represents whether vdd spi pin is functioned as gpio.\\ 1: functioned\\ 0: not functioned\\', rloc: 'EFUSE_RD_REPEAT_DATA0_REG[26]', bloc: 'B7[2]'} - RESERVE_0_59 : {show: n, blk : 0, word: 1, pos: 27, len : 5, start : 59, type : 'uint:5', wr_dis: null, rd_dis: null, alt : '', dict : '', desc: Reserved; it was created by set_missed_fields_in_regs func, rloc: 'EFUSE_RD_REPEAT_DATA0_REG[31:27]', bloc: 'B7[7:3]'} - KM_DISABLE_DEPLOY_MODE : {show: y, blk : 0, word: 2, pos : 0, len : 4, start : 64, type : 'uint:4', wr_dis : 1, rd_dis: null, alt : '', dict : '', desc: 'Represents whether the deploy mode of key manager is disable or not. \\ 1: disabled \\ 0: enabled.\\', rloc: 'EFUSE_RD_REPEAT_DATA1_REG[3:0]', bloc: 'B8[3:0]'} - KM_RND_SWITCH_CYCLE : {show: y, blk : 0, word: 2, pos : 4, len : 2, start : 68, type : 'uint:2', wr_dis : 1, rd_dis: null, alt : '', dict : '', desc: 'Set the bits to control key manager random number switch cycle. 0: control by register. 1: 8 km clk cycles. 2: 16 km cycles. 3: 32 km cycles', rloc: 'EFUSE_RD_REPEAT_DATA1_REG[5:4]', bloc: 'B8[5:4]'} - KM_DEPLOY_ONLY_ONCE : {show: y, blk : 0, word: 2, pos : 6, len : 4, start : 70, type : 'uint:4', wr_dis : 1, rd_dis: null, alt : '', dict : '', desc: 'Set each bit to control whether corresponding key can only be deployed once. 1 is true; 0 is false. bit 0: ecsda; bit 1: xts; bit2: hmac; bit3: ds', rloc: 'EFUSE_RD_REPEAT_DATA1_REG[9:6]', bloc: 'B8[7:6],B9[1:0]'} - FORCE_USE_KEY_MANAGER_KEY : {show: y, blk : 0, word: 2, pos: 10, len : 4, start : 74, type : 'uint:4', wr_dis : 1, rd_dis: null, alt : '', dict : '', desc: 'Set each bit to control whether corresponding key must come from key manager. 1 is true; 0 is false. bit 0: ecsda; bit 1: xts; bit2: hmac; bit3: ds', rloc: 'EFUSE_RD_REPEAT_DATA1_REG[13:10]', bloc: 'B9[5:2]'} - FORCE_DISABLE_SW_INIT_KEY : {show: y, blk : 0, word: 2, pos: 14, len : 1, start : 78, type : bool, wr_dis : 1, rd_dis: null, alt : '', dict : '', desc: Set this bit to disable software written init key; and force use efuse_init_key, rloc: 'EFUSE_RD_REPEAT_DATA1_REG[14]', bloc: 'B9[6]'} - RESERVE_0_79 : {show: n, blk : 0, word: 2, pos: 15, len : 1, start : 79, type : bool, wr_dis: null, rd_dis: null, alt : '', dict : '', desc: Reserved; it was created by set_missed_fields_in_regs func, rloc: 'EFUSE_RD_REPEAT_DATA1_REG[15]', bloc: 'B9[7]'} - WDT_DELAY_SEL : {show: y, blk : 0, word: 2, pos: 16, len : 2, start : 80, type : 'uint:2', wr_dis : 3, rd_dis: null, alt : '', dict : '', desc: 'Represents the threshold level of the RTC watchdog STG0 timeout.\\ 0: Original threshold configuration value of STG0 *2 \\1: Original threshold configuration value of STG0 *4 \\2: Original threshold configuration value of STG0 *8 \\3: Original threshold configuration value of STG0 *16 \\', rloc: 'EFUSE_RD_REPEAT_DATA1_REG[17:16]', bloc: 'B10[1:0]'} + USB_EXCHG_PINS : {show: y, blk : 0, word: 1, pos: 25, len : 1, start : 57, type : bool, wr_dis : 30, rd_dis: null, alt : '', dict : '', desc: 'Represents whether the D+ and D- pins is exchanged. 1: exchanged. 0: not exchanged', rloc: 'EFUSE_RD_REPEAT_DATA0_REG[25]', bloc: 'B7[1]'} + VDD_SPI_AS_GPIO : {show: y, blk : 0, word: 1, pos: 26, len : 1, start : 58, type : bool, wr_dis : 30, rd_dis: null, alt : '', dict : '', desc: 'Represents whether vdd spi pin is functioned as gpio. 1: functioned. 0: not functioned', rloc: 'EFUSE_RD_REPEAT_DATA0_REG[26]', bloc: 'B7[2]'} + RPT4_RESERVED0_2 : {show: y, blk : 0, word: 1, pos: 27, len : 2, start : 59, type : 'uint:2', wr_dis: null, rd_dis: null, alt : '', dict : '', desc: Reserved, rloc: 'EFUSE_RD_REPEAT_DATA0_REG[28:27]', bloc: 'B7[4:3]'} + RPT4_RESERVED0_1 : {show: y, blk : 0, word: 1, pos: 29, len : 1, start : 61, type : bool, wr_dis: null, rd_dis: null, alt : '', dict : '', desc: Reserved, rloc: 'EFUSE_RD_REPEAT_DATA0_REG[29]', bloc: 'B7[5]'} + RPT4_RESERVED0_0 : {show: n, blk : 0, word: 1, pos: 30, len : 2, start : 62, type : 'uint:2', wr_dis: null, rd_dis: null, alt : '', dict : '', desc: Reserved, rloc: 'EFUSE_RD_REPEAT_DATA0_REG[31:30]', bloc: 'B7[7:6]'} + RPT4_RESERVED1_1 : {show: n, blk : 0, word: 2, pos : 0, len : 16, start : 64, type : 'uint:16', wr_dis: null, rd_dis: null, alt : '', dict : '', desc: Reserved, rloc: 'EFUSE_RD_REPEAT_DATA1_REG[15:0]', bloc: 'B8,B9'} + WDT_DELAY_SEL : {show: y, blk : 0, word: 2, pos: 16, len : 2, start : 80, type : 'uint:2', wr_dis : 3, rd_dis: null, alt : '', dict : '', desc: 'Represents whether RTC watchdog timeout threshold is selected at startup. 1: selected. 0: not selected', rloc: 'EFUSE_RD_REPEAT_DATA1_REG[17:16]', bloc: 'B10[1:0]'} SPI_BOOT_CRYPT_CNT : {show: y, blk : 0, word: 2, pos: 18, len : 3, start : 82, type : 'uint:3', wr_dis : 4, rd_dis: null, alt : '', dict: '{0: "Disable", 1: "Enable", 3: "Disable", 7: "Enable"}', desc: Enables flash encryption when 1 or 3 bits are set and disables otherwise, rloc: 'EFUSE_RD_REPEAT_DATA1_REG[20:18]', bloc: 'B10[4:2]'} SECURE_BOOT_KEY_REVOKE0 : {show: y, blk : 0, word: 2, pos: 21, len : 1, start : 85, type : bool, wr_dis : 5, rd_dis: null, alt : '', dict : '', desc: Revoke 1st secure boot key, rloc: 'EFUSE_RD_REPEAT_DATA1_REG[21]', bloc: 'B10[5]'} SECURE_BOOT_KEY_REVOKE1 : {show: y, blk : 0, word: 2, pos: 22, len : 1, start : 86, type : bool, wr_dis : 6, rd_dis: null, alt : '', dict : '', desc: Revoke 2nd secure boot key, rloc: 'EFUSE_RD_REPEAT_DATA1_REG[22]', bloc: 'B10[6]'} @@ -37,60 +34,65 @@ EFUSES: KEY_PURPOSE_4 : {show: y, blk : 0, word: 3, pos : 8, len : 4, start: 104, type : 'uint:4', wr_dis : 12, rd_dis: null, alt : KEY4_PURPOSE, dict : '', desc: Represents the purpose of Key4, rloc: 'EFUSE_RD_REPEAT_DATA2_REG[11:8]', bloc: 'B13[3:0]'} KEY_PURPOSE_5 : {show: y, blk : 0, word: 3, pos: 12, len : 4, start: 108, type : 'uint:4', wr_dis : 13, rd_dis: null, alt : KEY5_PURPOSE, dict : '', desc: Represents the purpose of Key5, rloc: 'EFUSE_RD_REPEAT_DATA2_REG[15:12]', bloc: 'B13[7:4]'} SEC_DPA_LEVEL : {show: y, blk : 0, word: 3, pos: 16, len : 2, start: 112, type : 'uint:2', wr_dis : 14, rd_dis: null, alt : '', dict : '', desc: Represents the spa secure level by configuring the clock random divide mode, rloc: 'EFUSE_RD_REPEAT_DATA2_REG[17:16]', bloc: 'B14[1:0]'} - RESERVE_0_114 : {show: n, blk : 0, word: 3, pos: 18, len : 2, start: 114, type : 'uint:2', wr_dis: null, rd_dis: null, alt : '', dict : '', desc: Reserved; it was created by set_missed_fields_in_regs func, rloc: 'EFUSE_RD_REPEAT_DATA2_REG[19:18]', bloc: 'B14[3:2]'} - SECURE_BOOT_EN : {show: y, blk : 0, word: 3, pos: 20, len : 1, start: 116, type : bool, wr_dis : 15, rd_dis: null, alt : '', dict : '', desc: 'Represents whether secure boot is enabled or disabled.\\ 1: enabled\\ 0: disabled\\', rloc: 'EFUSE_RD_REPEAT_DATA2_REG[20]', bloc: 'B14[4]'} - SECURE_BOOT_AGGRESSIVE_REVOKE : {show: y, blk : 0, word: 3, pos: 21, len : 1, start: 117, type : bool, wr_dis : 16, rd_dis: null, alt : '', dict : '', desc: 'Represents whether revoking aggressive secure boot is enabled or disabled.\\ 1: enabled.\\ 0: disabled\\', rloc: 'EFUSE_RD_REPEAT_DATA2_REG[21]', bloc: 'B14[5]'} - RESERVE_0_118 : {show: n, blk : 0, word: 3, pos: 22, len : 5, start: 118, type : 'uint:5', wr_dis: null, rd_dis: null, alt : '', dict : '', desc: Reserved; it was created by set_missed_fields_in_regs func, rloc: 'EFUSE_RD_REPEAT_DATA2_REG[26:22]', bloc: 'B14[7:6],B15[2:0]'} - KM_XTS_KEY_LENGTH_256 : {show: y, blk : 0, word: 3, pos: 27, len : 1, start: 123, type : bool, wr_dis : 1, rd_dis: null, alt : '', dict : '', desc: Set this bitto configure flash encryption use xts-128 key. else use xts-256 key, rloc: 'EFUSE_RD_REPEAT_DATA2_REG[27]', bloc: 'B15[3]'} + ECDSA_FORCE_USE_HARDWARE_K : {show: y, blk : 0, word: 3, pos: 18, len : 1, start: 114, type : bool, wr_dis : 17, rd_dis: null, alt : '', dict : '', desc: 'Represents whether hardware random number k is forced used in ESDCA. 1: force used. 0: not force used', rloc: 'EFUSE_RD_REPEAT_DATA2_REG[18]', bloc: 'B14[2]'} + CRYPT_DPA_ENABLE : {show: y, blk : 0, word: 3, pos: 19, len : 1, start: 115, type : bool, wr_dis : 14, rd_dis: null, alt : '', dict : '', desc: 'Represents whether anti-dpa attack is enabled. 1:enabled. 0: disabled', rloc: 'EFUSE_RD_REPEAT_DATA2_REG[19]', bloc: 'B14[3]'} + SECURE_BOOT_EN : {show: y, blk : 0, word: 3, pos: 20, len : 1, start: 116, type : bool, wr_dis : 15, rd_dis: null, alt : '', dict : '', desc: 'Represents whether secure boot is enabled or disabled. 1: enabled. 0: disabled', rloc: 'EFUSE_RD_REPEAT_DATA2_REG[20]', bloc: 'B14[4]'} + SECURE_BOOT_AGGRESSIVE_REVOKE : {show: y, blk : 0, word: 3, pos: 21, len : 1, start: 117, type : bool, wr_dis : 16, rd_dis: null, alt : '', dict : '', desc: 'Represents whether revoking aggressive secure boot is enabled or disabled. 1: enabled. 0: disabled', rloc: 'EFUSE_RD_REPEAT_DATA2_REG[21]', bloc: 'B14[5]'} + RPT4_RESERVED2_0 : {show: n, blk : 0, word: 3, pos: 22, len : 6, start: 118, type : 'uint:6', wr_dis: null, rd_dis: null, alt : '', dict : '', desc: Reserved, rloc: 'EFUSE_RD_REPEAT_DATA2_REG[27:22]', bloc: 'B14[7:6],B15[3:0]'} FLASH_TPUW : {show: y, blk : 0, word: 3, pos: 28, len : 4, start: 124, type : 'uint:4', wr_dis : 18, rd_dis: null, alt : '', dict : '', desc: Represents the flash waiting time after power-up; in unit of ms. When the value less than 15; the waiting time is the programmed value. Otherwise; the waiting time is 2 times the programmed value, rloc: 'EFUSE_RD_REPEAT_DATA2_REG[31:28]', bloc: 'B15[7:4]'} - DIS_DOWNLOAD_MODE : {show: y, blk : 0, word: 4, pos : 0, len : 1, start: 128, type : bool, wr_dis : 18, rd_dis: null, alt : '', dict : '', desc: 'Represents whether Download mode is disabled or enabled.\\ 1: disabled\\ 0: enabled\\', rloc: 'EFUSE_RD_REPEAT_DATA3_REG[0]', bloc: 'B16[0]'} - DIS_DIRECT_BOOT : {show: y, blk : 0, word: 4, pos : 1, len : 1, start: 129, type : bool, wr_dis : 18, rd_dis: null, alt : '', dict : '', desc: 'Represents whether direct boot mode is disabled or enabled.\\ 1: disabled\\ 0: enabled\\', rloc: 'EFUSE_RD_REPEAT_DATA3_REG[1]', bloc: 'B16[1]'} - DIS_USB_SERIAL_JTAG_ROM_PRINT : {show: y, blk : 0, word: 4, pos : 2, len : 1, start: 130, type : bool, wr_dis : 18, rd_dis: null, alt : '', dict : '', desc: 'Represents whether print from USB-Serial-JTAG is disabled or enabled.\\ 1: disabled\\ 0: enabled\\', rloc: 'EFUSE_RD_REPEAT_DATA3_REG[2]', bloc: 'B16[2]'} - LOCK_KM_KEY : {show: y, blk : 0, word: 4, pos : 3, len : 1, start: 131, type : bool, wr_dis : 1, rd_dis: null, alt : '', dict : '', desc: 'Represetns whether to lock the efuse xts key.\\ 1. Lock\\ 0: Unlock\\', rloc: 'EFUSE_RD_REPEAT_DATA3_REG[3]', bloc: 'B16[3]'} - DIS_USB_SERIAL_JTAG_DOWNLOAD_MODE: {show: y, blk : 0, word: 4, pos : 4, len : 1, start: 132, type : bool, wr_dis : 18, rd_dis: null, alt : '', dict : '', desc: 'Represents whether the USB-Serial-JTAG download function is disabled or enabled.\\ 1: Disable\\ 0: Enable\\', rloc: 'EFUSE_RD_REPEAT_DATA3_REG[4]', bloc: 'B16[4]'} - ENABLE_SECURITY_DOWNLOAD : {show: y, blk : 0, word: 4, pos : 5, len : 1, start: 133, type : bool, wr_dis : 18, rd_dis: null, alt : '', dict : '', desc: 'Represents whether security download is enabled or disabled.\\ 1: enabled\\ 0: disabled\\', rloc: 'EFUSE_RD_REPEAT_DATA3_REG[5]', bloc: 'B16[5]'} + DIS_DOWNLOAD_MODE : {show: y, blk : 0, word: 4, pos : 0, len : 1, start: 128, type : bool, wr_dis : 18, rd_dis: null, alt : '', dict : '', desc: 'Represents whether Download mode is disabled or enabled. 1: disabled. 0: enabled', rloc: 'EFUSE_RD_REPEAT_DATA3_REG[0]', bloc: 'B16[0]'} + DIS_DIRECT_BOOT : {show: y, blk : 0, word: 4, pos : 1, len : 1, start: 129, type : bool, wr_dis : 18, rd_dis: null, alt : '', dict : '', desc: 'Represents whether direct boot mode is disabled or enabled. 1: disabled. 0: enabled', rloc: 'EFUSE_RD_REPEAT_DATA3_REG[1]', bloc: 'B16[1]'} + DIS_USB_SERIAL_JTAG_ROM_PRINT : {show: y, blk : 0, word: 4, pos : 2, len : 1, start: 130, type : bool, wr_dis : 18, rd_dis: null, alt : DIS_USB_PRINT, dict : '', desc: Set this bit to disable USB-Serial-JTAG print during rom boot, rloc: 'EFUSE_RD_REPEAT_DATA3_REG[2]', bloc: 'B16[2]'} + RPT4_RESERVED3_5 : {show: n, blk : 0, word: 4, pos : 3, len : 1, start: 131, type : bool, wr_dis: null, rd_dis: null, alt : '', dict : '', desc: Reserved, rloc: 'EFUSE_RD_REPEAT_DATA3_REG[3]', bloc: 'B16[3]'} + DIS_USB_SERIAL_JTAG_DOWNLOAD_MODE: {show: y, blk : 0, word: 4, pos : 4, len : 1, start: 132, type : bool, wr_dis : 18, rd_dis: null, alt : '', dict : '', desc: 'Represents whether the USB-Serial-JTAG download function is disabled or enabled. 1: disabled. 0: enabled', rloc: 'EFUSE_RD_REPEAT_DATA3_REG[4]', bloc: 'B16[4]'} + ENABLE_SECURITY_DOWNLOAD : {show: y, blk : 0, word: 4, pos : 5, len : 1, start: 133, type : bool, wr_dis : 18, rd_dis: null, alt : '', dict : '', desc: 'Represents whether security download is enabled or disabled. 1: enabled. 0: disabled', rloc: 'EFUSE_RD_REPEAT_DATA3_REG[5]', bloc: 'B16[5]'} UART_PRINT_CONTROL : {show: y, blk : 0, word: 4, pos : 6, len : 2, start: 134, type : 'uint:2', wr_dis : 18, rd_dis: null, alt : '', dict: '{0: "Enable", 1: "Enable when GPIO8 is low at reset", 2: "Enable when GPIO8 is high at reset", 3: "Disable"}', desc: Set the default UARTboot message output mode, rloc: 'EFUSE_RD_REPEAT_DATA3_REG[7:6]', bloc: 'B16[7:6]'} - FORCE_SEND_RESUME : {show: y, blk : 0, word: 4, pos : 8, len : 1, start: 136, type : bool, wr_dis : 18, rd_dis: null, alt : '', dict : '', desc: 'Represents whether ROM code is forced to send a resume command during SPI boot.\\ 1: forced\\ 0:not forced\\', rloc: 'EFUSE_RD_REPEAT_DATA3_REG[8]', bloc: 'B17[0]'} + FORCE_SEND_RESUME : {show: y, blk : 0, word: 4, pos : 8, len : 1, start: 136, type : bool, wr_dis : 18, rd_dis: null, alt : '', dict : '', desc: 'Represents whether ROM code is forced to send a resume command during SPI boot. 1: forced. 0:not forced', rloc: 'EFUSE_RD_REPEAT_DATA3_REG[8]', bloc: 'B17[0]'} SECURE_VERSION : {show: y, blk : 0, word: 4, pos : 9, len : 16, start: 137, type : 'uint:16', wr_dis : 18, rd_dis: null, alt : '', dict : '', desc: Represents the version used by ESP-IDF anti-rollback feature, rloc: 'EFUSE_RD_REPEAT_DATA3_REG[24:9]', bloc: 'B17[7:1],B18,B19[0]'} - SECURE_BOOT_DISABLE_FAST_WAKE : {show: y, blk : 0, word: 4, pos: 25, len : 1, start: 153, type : bool, wr_dis : 18, rd_dis: null, alt : '', dict : '', desc: 'Represents whether FAST VERIFY ON WAKE is disabled or enabled when Secure Boot is enabled.\\ 1: disabled\\ 0: enabled\\', rloc: 'EFUSE_RD_REPEAT_DATA3_REG[25]', bloc: 'B19[1]'} - HYS_EN_PAD : {show: y, blk : 0, word: 4, pos: 26, len : 1, start: 154, type : bool, wr_dis : 2, rd_dis: null, alt : '', dict : '', desc: 'Represents whether the hysteresis function of corresponding PAD is enabled.\\ 1: enabled\\ 0:disabled\\', rloc: 'EFUSE_RD_REPEAT_DATA3_REG[26]', bloc: 'B19[2]'} - XTS_DPA_PSEUDO_LEVEL : {show: y, blk : 0, word: 4, pos: 27, len : 2, start: 155, type : 'uint:2', wr_dis : 14, rd_dis: null, alt : '', dict : '', desc: 'Represents the pseudo round level of xts-aes anti-dpa attack.\\ 3: High.\\ 2: Moderate 1. Low\\ 0: Disabled\\', rloc: 'EFUSE_RD_REPEAT_DATA3_REG[28:27]', bloc: 'B19[4:3]'} - XTS_DPA_CLK_ENABLE : {show: y, blk : 0, word: 4, pos: 29, len : 1, start: 157, type : bool, wr_dis : 14, rd_dis: null, alt : '', dict : '', desc: 'Represents whether xts-aes anti-dpa attack clock is enabled.\\ 1. Enable.\\ 0: Disable.\\', rloc: 'EFUSE_RD_REPEAT_DATA3_REG[29]', bloc: 'B19[5]'} - RESERVE_0_158 : {show: n, blk : 0, word: 4, pos: 30, len : 2, start: 158, type : 'uint:2', wr_dis: null, rd_dis: null, alt : '', dict : '', desc: Reserved; it was created by set_missed_fields_in_regs func, rloc: 'EFUSE_RD_REPEAT_DATA3_REG[31:30]', bloc: 'B19[7:6]'} - HUK_GEN_STATE : {show: y, blk : 0, word: 5, pos : 0, len : 9, start: 160, type : 'uint:9', wr_dis : 19, rd_dis: null, alt : '', dict : '', desc: Set the bits to control validation of HUK generate mode.\\ Odd of 1 is invalid.\\ Even of 1 is valid.\\, rloc: 'EFUSE_RD_REPEAT_DATA4_REG[8:0]', bloc: 'B20,B21[0]'} - XTAL_48M_SEL : {show: y, blk : 0, word: 5, pos : 9, len : 3, start: 169, type : 'uint:3', wr_dis : 17, rd_dis: null, alt : '', dict : '', desc: 'Represents whether XTAL frequency is 48MHz or not. If not; 40MHz XTAL will be used. If this field contains Odd number bit 1: Enable 48MHz XTAL\ Even number bit 1: Enable 40MHz XTAL', rloc: 'EFUSE_RD_REPEAT_DATA4_REG[11:9]', bloc: 'B21[3:1]'} - XTAL_48M_SEL_MODE : {show: y, blk : 0, word: 5, pos: 12, len : 1, start: 172, type : bool, wr_dis : 17, rd_dis: null, alt : '', dict : '', desc: 'Specify the XTAL frequency selection is decided by eFuse or strapping-PAD-state. 1: eFuse\\ 0: strapping-PAD-state', rloc: 'EFUSE_RD_REPEAT_DATA4_REG[12]', bloc: 'B21[4]'} - ECDSA_DISABLE_P192 : {show: y, blk : 0, word: 5, pos: 13, len : 1, start: 173, type : bool, wr_dis : 14, rd_dis: null, alt : '', dict : '', desc: 'Represents whether to disable P192 curve in ECDSA.\\ 1: Disabled.\\ 0: Not disable', rloc: 'EFUSE_RD_REPEAT_DATA4_REG[13]', bloc: 'B21[5]'} - ECC_FORCE_CONST_TIME : {show: y, blk : 0, word: 5, pos: 14, len : 1, start: 174, type : bool, wr_dis : 14, rd_dis: null, alt : '', dict : '', desc: 'Represents whether to force ecc to use const-time calculation mode. \\ 1: Enable. \\ 0: Disable', rloc: 'EFUSE_RD_REPEAT_DATA4_REG[14]', bloc: 'B21[6]'} - RESERVE_0_175 : {show: n, blk : 0, word: 5, pos: 15, len : 17, start: 175, type : 'uint:17', wr_dis: null, rd_dis: null, alt : '', dict : '', desc: Reserved; it was created by set_missed_fields_in_regs func, rloc: 'EFUSE_RD_REPEAT_DATA4_REG[31:15]', bloc: 'B21[7],B22,B23'} - MAC : {show: y, blk : 1, word: 0, pos : 0, len : 48, start : 0, type : 'bytes:6', wr_dis : 20, rd_dis: null, alt : MAC_FACTORY, dict : '', desc: MAC address, rloc: EFUSE_RD_MAC_SYS0_REG, bloc: 'B0,B1,B2,B3,B4,B5'} - MAC_EXT : {show: y, blk : 1, word: 1, pos: 16, len : 16, start : 48, type : 'bytes:2', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: Represents the extended bits of MAC address, rloc: 'EFUSE_RD_MAC_SYS1_REG[31:16]', bloc: 'B6,B7'} - WAFER_VERSION_MINOR : {show: y, blk : 1, word: 2, pos : 0, len : 4, start : 64, type : 'uint:4', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: Minor chip version, rloc: 'EFUSE_RD_MAC_SYS2_REG[3:0]', bloc: 'B8[3:0]'} - WAFER_VERSION_MAJOR : {show: y, blk : 1, word: 2, pos : 4, len : 2, start : 68, type : 'uint:2', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: Minor chip version, rloc: 'EFUSE_RD_MAC_SYS2_REG[5:4]', bloc: 'B8[5:4]'} - DISABLE_WAFER_VERSION_MAJOR : {show: y, blk : 1, word: 2, pos : 6, len : 1, start : 70, type : bool, wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: Disables check of wafer version major, rloc: 'EFUSE_RD_MAC_SYS2_REG[6]', bloc: 'B8[6]'} - DISABLE_BLK_VERSION_MAJOR : {show: y, blk : 1, word: 2, pos : 7, len : 1, start : 71, type : bool, wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: Disables check of blk version major, rloc: 'EFUSE_RD_MAC_SYS2_REG[7]', bloc: 'B8[7]'} - BLK_VERSION_MINOR : {show: y, blk : 1, word: 2, pos : 8, len : 3, start : 72, type : 'uint:3', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: BLK_VERSION_MINOR of BLOCK2, rloc: 'EFUSE_RD_MAC_SYS2_REG[10:8]', bloc: 'B9[2:0]'} - BLK_VERSION_MAJOR : {show: y, blk : 1, word: 2, pos: 11, len : 2, start : 75, type : 'uint:2', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: BLK_VERSION_MAJOR of BLOCK2, rloc: 'EFUSE_RD_MAC_SYS2_REG[12:11]', bloc: 'B9[4:3]'} - FLASH_CAP : {show: y, blk : 1, word: 2, pos: 13, len : 3, start : 77, type : 'uint:3', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: Flash capacity, rloc: 'EFUSE_RD_MAC_SYS2_REG[15:13]', bloc: 'B9[7:5]'} - FLASH_VENDOR : {show: y, blk : 1, word: 2, pos: 16, len : 3, start : 80, type : 'uint:3', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: Flash vendor, rloc: 'EFUSE_RD_MAC_SYS2_REG[18:16]', bloc: 'B10[2:0]'} - PSRAM_CAP : {show: y, blk : 1, word: 2, pos: 19, len : 3, start : 83, type : 'uint:3', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: Psram capacity, rloc: 'EFUSE_RD_MAC_SYS2_REG[21:19]', bloc: 'B10[5:3]'} - PSRAM_VENDOR : {show: y, blk : 1, word: 2, pos: 22, len : 2, start : 86, type : 'uint:2', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: Psram vendor, rloc: 'EFUSE_RD_MAC_SYS2_REG[23:22]', bloc: 'B10[7:6]'} - TEMP : {show: y, blk : 1, word: 2, pos: 24, len : 2, start : 88, type : 'uint:2', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: Temp (die embedded inside), rloc: 'EFUSE_RD_MAC_SYS2_REG[25:24]', bloc: 'B11[1:0]'} - PKG_VERSION : {show: y, blk : 1, word: 2, pos: 26, len : 3, start : 90, type : 'uint:3', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: Package version, rloc: 'EFUSE_RD_MAC_SYS2_REG[28:26]', bloc: 'B11[4:2]'} - PA_TRIM_VERSION : {show: y, blk : 1, word: 2, pos: 29, len : 3, start : 93, type : 'uint:3', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: PADC CAL PA trim version, rloc: 'EFUSE_RD_MAC_SYS2_REG[31:29]', bloc: 'B11[7:5]'} - TRIM_N_BIAS : {show: y, blk : 1, word: 3, pos : 0, len : 5, start : 96, type : 'uint:5', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: PADC CAL N bias, rloc: 'EFUSE_RD_MAC_SYS3_REG[4:0]', bloc: 'B12[4:0]'} - TRIM_P_BIAS : {show: y, blk : 1, word: 3, pos : 5, len : 5, start: 101, type : 'uint:5', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: PADC CAL P bias, rloc: 'EFUSE_RD_MAC_SYS3_REG[9:5]', bloc: 'B12[7:5],B13[1:0]'} - RESERVED_1_106 : {show: n, blk : 1, word: 3, pos: 10, len : 8, start: 106, type : 'uint:8', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: reserved, rloc: 'EFUSE_RD_MAC_SYS3_REG[17:10]', bloc: 'B13[7:2],B14[1:0]'} - SYS_DATA_PART0_0 : {show: n, blk : 1, word: 3, pos: 18, len : 14, start: 114, type : 'uint:14', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: Represents the first 14-bit of zeroth part of system data, rloc: 'EFUSE_RD_MAC_SYS3_REG[31:18]', bloc: 'B14[7:2],B15'} - SYS_DATA_PART0_1 : {show: n, blk : 1, word: 4, pos : 0, len : 32, start: 128, type : 'uint:32', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: Represents the first 14-bit of zeroth part of system data, rloc: EFUSE_RD_MAC_SYS4_REG, bloc: 'B16,B17,B18,B19'} - SYS_DATA_PART0_2 : {show: n, blk : 1, word: 5, pos : 0, len : 32, start: 160, type : 'uint:32', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: Represents the second 32-bit of zeroth part of system data, rloc: EFUSE_RD_MAC_SYS5_REG, bloc: 'B20,B21,B22,B23'} + SECURE_BOOT_DISABLE_FAST_WAKE : {show: y, blk : 0, word: 4, pos: 25, len : 1, start: 153, type : bool, wr_dis : 18, rd_dis: null, alt : '', dict : '', desc: 'Represents whether FAST VERIFY ON WAKE is disabled or enabled when Secure Boot is enabled. 1: disabled. 0: enabled', rloc: 'EFUSE_RD_REPEAT_DATA3_REG[25]', bloc: 'B19[1]'} + HYS_EN_PAD0 : {show: y, blk : 0, word: 4, pos: 26, len : 6, start: 154, type : 'uint:6', wr_dis : 19, rd_dis: null, alt : '', dict : '', desc: Set bits to enable hysteresis function of PAD0~5, rloc: 'EFUSE_RD_REPEAT_DATA3_REG[31:26]', bloc: 'B19[7:2]'} + HYS_EN_PAD1 : {show: y, blk : 0, word: 5, pos : 0, len : 22, start: 160, type : 'uint:22', wr_dis : 19, rd_dis: null, alt : '', dict : '', desc: Set bits to enable hysteresis function of PAD6~27, rloc: 'EFUSE_RD_REPEAT_DATA4_REG[21:0]', bloc: 'B20,B21,B22[5:0]'} + RPT4_RESERVED4_1 : {show: n, blk : 0, word: 5, pos: 22, len : 2, start: 182, type : 'uint:2', wr_dis: null, rd_dis: null, alt : '', dict : '', desc: Reserved, rloc: 'EFUSE_RD_REPEAT_DATA4_REG[23:22]', bloc: 'B22[7:6]'} + RPT4_RESERVED4_0 : {show: n, blk : 0, word: 5, pos: 24, len : 8, start: 184, type : 'uint:8', wr_dis: null, rd_dis: null, alt : '', dict : '', desc: Reserved, rloc: 'EFUSE_RD_REPEAT_DATA4_REG[31:24]', bloc: B23} + MAC : {show: y, blk : 1, word: 0, pos : 0, len : 48, start : 0, type : 'bytes:6', wr_dis : 20, rd_dis: null, alt : MAC_FACTORY, dict : '', desc: MAC address, rloc: EFUSE_RD_MAC_SYS_0_REG, bloc: 'B0,B1,B2,B3,B4,B5'} + MAC_EXT : {show: y, blk : 1, word: 1, pos: 16, len : 16, start : 48, type : 'bytes:2', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: Stores the extended bits of MAC address, rloc: 'EFUSE_RD_MAC_SYS_1_REG[31:16]', bloc: 'B6,B7'} + RXIQ_VERSION : {show: y, blk : 1, word: 2, pos : 0, len : 3, start : 64, type : 'uint:3', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: Stores RF Calibration data. RXIQ version, rloc: 'EFUSE_RD_MAC_SYS_2_REG[2:0]', bloc: 'B8[2:0]'} + RXIQ_0 : {show: y, blk : 1, word: 2, pos : 3, len : 7, start : 67, type : 'uint:7', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: Stores RF Calibration data. RXIQ data 0, rloc: 'EFUSE_RD_MAC_SYS_2_REG[9:3]', bloc: 'B8[7:3],B9[1:0]'} + RXIQ_1 : {show: y, blk : 1, word: 2, pos: 10, len : 7, start : 74, type : 'uint:7', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: Stores RF Calibration data. RXIQ data 1, rloc: 'EFUSE_RD_MAC_SYS_2_REG[16:10]', bloc: 'B9[7:2],B10[0]'} + ACTIVE_HP_DBIAS : {show: y, blk : 1, word: 2, pos: 17, len : 5, start : 81, type : 'uint:5', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: Stores the PMU active hp dbias, rloc: 'EFUSE_RD_MAC_SYS_2_REG[21:17]', bloc: 'B10[5:1]'} + ACTIVE_LP_DBIAS : {show: y, blk : 1, word: 2, pos: 22, len : 5, start : 86, type : 'uint:5', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: Stores the PMU active lp dbias, rloc: 'EFUSE_RD_MAC_SYS_2_REG[26:22]', bloc: 'B10[7:6],B11[2:0]'} + DSLP_DBIAS : {show: y, blk : 1, word: 2, pos: 27, len : 4, start : 91, type : 'uint:4', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: Stores the PMU sleep dbias, rloc: 'EFUSE_RD_MAC_SYS_2_REG[30:27]', bloc: 'B11[6:3]'} + DBIAS_VOL_GAP : {show: y, blk : 1, word: 2, pos: 31, len : 5, start : 95, type : 'uint:5', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: Stores the low 1 bit of dbias_vol_gap, rloc: 'EFUSE_RD_MAC_SYS_2_REG[31]', bloc: 'B11[7],B12[3:0]'} + MAC_RESERVED_2 : {show: n, blk : 1, word: 3, pos : 4, len : 14, start: 100, type : 'uint:14', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: Reserved, rloc: 'EFUSE_RD_MAC_SYS_3_REG[17:4]', bloc: 'B12[7:4],B13,B14[1:0]'} + WAFER_VERSION_MINOR : {show: y, blk : 1, word: 3, pos: 18, len : 3, start: 114, type : 'uint:3', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: Stores the wafer version minor, rloc: 'EFUSE_RD_MAC_SYS_3_REG[20:18]', bloc: 'B14[4:2]'} + WAFER_VERSION_MAJOR : {show: y, blk : 1, word: 3, pos: 21, len : 2, start: 117, type : 'uint:2', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: Stores the wafer version major, rloc: 'EFUSE_RD_MAC_SYS_3_REG[22:21]', bloc: 'B14[6:5]'} + DISABLE_WAFER_VERSION_MAJOR : {show: y, blk : 1, word: 3, pos: 23, len : 1, start: 119, type : bool, wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: Disables check of wafer version major, rloc: 'EFUSE_RD_MAC_SYS_3_REG[23]', bloc: 'B14[7]'} + FLASH_CAP : {show: y, blk : 1, word: 3, pos: 24, len : 3, start: 120, type : 'uint:3', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: Stores the flash cap, rloc: 'EFUSE_RD_MAC_SYS_3_REG[26:24]', bloc: 'B15[2:0]'} + FLASH_TEMP : {show: y, blk : 1, word: 3, pos: 27, len : 2, start: 123, type : 'uint:2', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: Stores the flash temp, rloc: 'EFUSE_RD_MAC_SYS_3_REG[28:27]', bloc: 'B15[4:3]'} + FLASH_VENDOR : {show: y, blk : 1, word: 3, pos: 29, len : 3, start: 125, type : 'uint:3', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: Stores the flash vendor, rloc: 'EFUSE_RD_MAC_SYS_3_REG[31:29]', bloc: 'B15[7:5]'} + PKG_VERSION : {show: y, blk : 1, word: 4, pos : 0, len : 3, start: 128, type : 'uint:3', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: Package version, rloc: 'EFUSE_RD_MAC_SYS_4_REG[2:0]', bloc: 'B16[2:0]'} + RESERVED_1_131 : {show: n, blk : 1, word: 4, pos : 3, len : 29, start: 131, type : 'uint:29', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: reserved, rloc: 'EFUSE_RD_MAC_SYS_4_REG[31:3]', bloc: 'B16[7:3],B17,B18,B19'} + SYS_DATA_PART0_2 : {show: n, blk : 1, word: 5, pos : 0, len : 32, start: 160, type : 'uint:32', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: Stores the second 32 bits of the zeroth part of system data, rloc: EFUSE_RD_MAC_SYS_5_REG, bloc: 'B20,B21,B22,B23'} OPTIONAL_UNIQUE_ID : {show: y, blk : 2, word: 0, pos : 0, len: 128, start : 0, type: 'bytes:16', wr_dis : 21, rd_dis: null, alt : '', dict : '', desc: Optional unique 128-bit ID, rloc: EFUSE_RD_SYS_PART1_DATA0_REG, bloc: 'B0,B1,B2,B3,B4,B5,B6,B7,B8,B9,B10,B11,B12,B13,B14,B15'} - RESERVED_2_128 : {show: n, blk : 2, word: 4, pos : 0, len : 9, start: 128, type : 'uint:9', wr_dis : 21, rd_dis: null, alt : '', dict : '', desc: reserved, rloc: 'EFUSE_RD_SYS_PART1_DATA4_REG[8:0]', bloc: 'B16,B17[0]'} - OCODE : {show: y, blk : 2, word: 4, pos : 9, len : 8, start: 137, type : 'uint:8', wr_dis : 21, rd_dis: null, alt : '', dict : '', desc: ADC OCode, rloc: 'EFUSE_RD_SYS_PART1_DATA4_REG[16:9]', bloc: 'B17[7:1],B18[0]'} - RESERVED_2_145 : {show: n, blk : 2, word: 4, pos: 17, len : 15, start: 145, type : 'uint:15', wr_dis : 21, rd_dis: null, alt : '', dict : '', desc: reserved, rloc: 'EFUSE_RD_SYS_PART1_DATA4_REG[31:17]', bloc: 'B18[7:1],B19'} - SYS_DATA_PART1_5 : {show: n, blk : 2, word: 5, pos : 0, len : 32, start: 160, type : 'uint:32', wr_dis : 21, rd_dis: null, alt : '', dict : '', desc: Represents the zeroth 32-bit of first part of system data, rloc: EFUSE_RD_SYS_PART1_DATA5_REG, bloc: 'B20,B21,B22,B23'} - SYS_DATA_PART1_6 : {show: n, blk : 2, word: 6, pos : 0, len : 32, start: 192, type : 'uint:32', wr_dis : 21, rd_dis: null, alt : '', dict : '', desc: Represents the zeroth 32-bit of first part of system data, rloc: EFUSE_RD_SYS_PART1_DATA6_REG, bloc: 'B24,B25,B26,B27'} - SYS_DATA_PART1_7 : {show: n, blk : 2, word: 7, pos : 0, len : 32, start: 224, type : 'uint:32', wr_dis : 21, rd_dis: null, alt : '', dict : '', desc: Represents the zeroth 32-bit of first part of system data, rloc: EFUSE_RD_SYS_PART1_DATA7_REG, bloc: 'B28,B29,B30,B31'} + RESERVED_2_128 : {show: n, blk : 2, word: 4, pos : 0, len : 2, start: 128, type : 'uint:2', wr_dis : 21, rd_dis: null, alt : '', dict : '', desc: reserved, rloc: 'EFUSE_RD_SYS_PART1_DATA4_REG[1:0]', bloc: 'B16[1:0]'} + BLK_VERSION_MINOR : {show: y, blk : 2, word: 4, pos : 2, len : 3, start: 130, type : 'uint:3', wr_dis : 21, rd_dis: null, alt : '', dict : '', desc: 'BLK_VERSION_MINOR of BLOCK2. 1: RF Calibration data in BLOCK1', rloc: 'EFUSE_RD_SYS_PART1_DATA4_REG[4:2]', bloc: 'B16[4:2]'} + BLK_VERSION_MAJOR : {show: y, blk : 2, word: 4, pos : 5, len : 2, start: 133, type : 'uint:2', wr_dis : 21, rd_dis: null, alt : '', dict : '', desc: BLK_VERSION_MAJOR of BLOCK2, rloc: 'EFUSE_RD_SYS_PART1_DATA4_REG[6:5]', bloc: 'B16[6:5]'} + DISABLE_BLK_VERSION_MAJOR : {show: y, blk : 2, word: 4, pos : 7, len : 1, start: 135, type : bool, wr_dis : 21, rd_dis: null, alt : '', dict : '', desc: Disables check of blk version major, rloc: 'EFUSE_RD_SYS_PART1_DATA4_REG[7]', bloc: 'B16[7]'} + TEMP_CALIB : {show: y, blk : 2, word: 4, pos : 8, len : 9, start: 136, type : 'uint:9', wr_dis : 21, rd_dis: null, alt : '', dict : '', desc: Temperature calibration data, rloc: 'EFUSE_RD_SYS_PART1_DATA4_REG[16:8]', bloc: 'B17,B18[0]'} + ADC1_AVE_INITCODE_ATTEN0 : {show: y, blk : 2, word: 4, pos: 17, len : 10, start: 145, type : 'uint:10', wr_dis : 21, rd_dis: null, alt : '', dict : '', desc: ADC1 calibration data, rloc: 'EFUSE_RD_SYS_PART1_DATA4_REG[26:17]', bloc: 'B18[7:1],B19[2:0]'} + ADC1_AVE_INITCODE_ATTEN1 : {show: y, blk : 2, word: 4, pos: 27, len : 10, start: 155, type : 'uint:10', wr_dis : 21, rd_dis: null, alt : '', dict : '', desc: ADC1 calibration data, rloc: 'EFUSE_RD_SYS_PART1_DATA4_REG[31:27]', bloc: 'B19[7:3],B20[4:0]'} + ADC1_AVE_INITCODE_ATTEN2 : {show: y, blk : 2, word: 5, pos : 5, len : 10, start: 165, type : 'uint:10', wr_dis : 21, rd_dis: null, alt : '', dict : '', desc: ADC1 calibration data, rloc: 'EFUSE_RD_SYS_PART1_DATA5_REG[14:5]', bloc: 'B20[7:5],B21[6:0]'} + ADC1_AVE_INITCODE_ATTEN3 : {show: y, blk : 2, word: 5, pos: 15, len : 10, start: 175, type : 'uint:10', wr_dis : 21, rd_dis: null, alt : '', dict : '', desc: ADC1 calibration data, rloc: 'EFUSE_RD_SYS_PART1_DATA5_REG[24:15]', bloc: 'B21[7],B22,B23[0]'} + ADC1_HI_DOUT_ATTEN0 : {show: y, blk : 2, word: 5, pos: 25, len : 10, start: 185, type : 'uint:10', wr_dis : 21, rd_dis: null, alt : '', dict : '', desc: ADC1 calibration data, rloc: 'EFUSE_RD_SYS_PART1_DATA5_REG[31:25]', bloc: 'B23[7:1],B24[2:0]'} + ADC1_HI_DOUT_ATTEN1 : {show: y, blk : 2, word: 6, pos : 3, len : 10, start: 195, type : 'uint:10', wr_dis : 21, rd_dis: null, alt : '', dict : '', desc: ADC1 calibration data, rloc: 'EFUSE_RD_SYS_PART1_DATA6_REG[12:3]', bloc: 'B24[7:3],B25[4:0]'} + ADC1_HI_DOUT_ATTEN2 : {show: y, blk : 2, word: 6, pos: 13, len : 10, start: 205, type : 'uint:10', wr_dis : 21, rd_dis: null, alt : '', dict : '', desc: ADC1 calibration data, rloc: 'EFUSE_RD_SYS_PART1_DATA6_REG[22:13]', bloc: 'B25[7:5],B26[6:0]'} + ADC1_HI_DOUT_ATTEN3 : {show: y, blk : 2, word: 6, pos: 23, len : 10, start: 215, type : 'uint:10', wr_dis : 21, rd_dis: null, alt : '', dict : '', desc: ADC1 calibration data, rloc: 'EFUSE_RD_SYS_PART1_DATA6_REG[31:23]', bloc: 'B26[7],B27,B28[0]'} + ADC1_CH0_ATTEN0_INITCODE_DIFF : {show: y, blk : 2, word: 7, pos : 1, len : 4, start: 225, type : 'uint:4', wr_dis : 21, rd_dis: null, alt : '', dict : '', desc: ADC1 calibration data, rloc: 'EFUSE_RD_SYS_PART1_DATA7_REG[4:1]', bloc: 'B28[4:1]'} + ADC1_CH1_ATTEN0_INITCODE_DIFF : {show: y, blk : 2, word: 7, pos : 5, len : 4, start: 229, type : 'uint:4', wr_dis : 21, rd_dis: null, alt : '', dict : '', desc: ADC1 calibration data, rloc: 'EFUSE_RD_SYS_PART1_DATA7_REG[8:5]', bloc: 'B28[7:5],B29[0]'} + ADC1_CH2_ATTEN0_INITCODE_DIFF : {show: y, blk : 2, word: 7, pos : 9, len : 4, start: 233, type : 'uint:4', wr_dis : 21, rd_dis: null, alt : '', dict : '', desc: ADC1 calibration data, rloc: 'EFUSE_RD_SYS_PART1_DATA7_REG[12:9]', bloc: 'B29[4:1]'} + ADC1_CH3_ATTEN0_INITCODE_DIFF : {show: y, blk : 2, word: 7, pos: 13, len : 4, start: 237, type : 'uint:4', wr_dis : 21, rd_dis: null, alt : '', dict : '', desc: ADC1 calibration data, rloc: 'EFUSE_RD_SYS_PART1_DATA7_REG[16:13]', bloc: 'B29[7:5],B30[0]'} + ADC1_CH4_ATTEN0_INITCODE_DIFF : {show: y, blk : 2, word: 7, pos: 17, len : 4, start: 241, type : 'uint:4', wr_dis : 21, rd_dis: null, alt : '', dict : '', desc: ADC1 calibration data, rloc: 'EFUSE_RD_SYS_PART1_DATA7_REG[20:17]', bloc: 'B30[4:1]'} + RESERVED_2_245 : {show: n, blk : 2, word: 7, pos: 21, len : 11, start: 245, type : 'uint:11', wr_dis : 21, rd_dis: null, alt : '', dict : '', desc: reserved, rloc: 'EFUSE_RD_SYS_PART1_DATA7_REG[31:21]', bloc: 'B30[7:5],B31'} BLOCK_USR_DATA : {show: y, blk : 3, word: 0, pos : 0, len: 192, start : 0, type: 'bytes:24', wr_dis : 22, rd_dis: null, alt : USER_DATA, dict : '', desc: User data, rloc: EFUSE_RD_USR_DATA0_REG, bloc: 'B0,B1,B2,B3,B4,B5,B6,B7,B8,B9,B10,B11,B12,B13,B14,B15,B16,B17,B18,B19,B20,B21,B22,B23'} RESERVED_3_192 : {show: n, blk : 3, word: 6, pos : 0, len : 8, start: 192, type : 'uint:8', wr_dis : 22, rd_dis: null, alt : '', dict : '', desc: reserved, rloc: 'EFUSE_RD_USR_DATA6_REG[7:0]', bloc: B24} CUSTOM_MAC : {show: y, blk : 3, word: 6, pos : 8, len : 48, start: 200, type : 'bytes:6', wr_dis : 22, rd_dis: null, alt: MAC_CUSTOM USER_DATA_MAC_CUSTOM, dict : '', desc: Custom MAC, rloc: 'EFUSE_RD_USR_DATA6_REG[31:8]', bloc: 'B25,B26,B27,B28,B29,B30'} diff --git a/tools/esptool_py/espefuse/efuse_defs/esp32h2_v0.0_v1.1.yaml b/tools/esptool_py/espefuse/efuse_defs/esp32h2_v0.0_v1.1.yaml new file mode 100644 index 0000000000..228df47fb5 --- /dev/null +++ b/tools/esptool_py/espefuse/efuse_defs/esp32h2_v0.0_v1.1.yaml @@ -0,0 +1,3 @@ +VER_NO: 44563d2af4ebdba4db6c0a34a50c94f9 +EFUSES: + ECDSA_FORCE_USE_HARDWARE_K : {show: y, blk : 0, word: 3, pos: 18, len : 1, start: 114, type : bool, wr_dis : 17, rd_dis: null, alt : '', dict : '', desc: 'Represents whether hardware random number k is forced used in ESDCA. 1: force used. 0: not force used', rloc: 'EFUSE_RD_REPEAT_DATA2_REG[18]', bloc: 'B14[2]'} diff --git a/tools/esptool_py/espefuse/efuse_defs/esp32h4.yaml b/tools/esptool_py/espefuse/efuse_defs/esp32h4.yaml new file mode 100644 index 0000000000..ed81481292 --- /dev/null +++ b/tools/esptool_py/espefuse/efuse_defs/esp32h4.yaml @@ -0,0 +1,92 @@ +VER_NO: 7bc342bad0952907e1db21112d258c6b +EFUSES: + WR_DIS : {show: y, blk : 0, word: 0, pos : 0, len : 32, start : 0, type : 'uint:32', wr_dis: null, rd_dis: null, alt : '', dict : '', desc: Disable programming of individual eFuses, rloc: EFUSE_RD_WR_DIS0_REG, bloc: 'B0,B1,B2,B3'} + RD_DIS : {show: y, blk : 0, word: 1, pos : 0, len : 7, start : 32, type : 'uint:7', wr_dis : 0, rd_dis: null, alt : '', dict : '', desc: Disable reading from BlOCK4-10, rloc: 'EFUSE_RD_REPEAT_DATA0_REG[6:0]', bloc: 'B4[6:0]'} + DIS_USB_JTAG : {show: y, blk : 0, word: 1, pos : 7, len : 1, start : 39, type : bool, wr_dis : 2, rd_dis: null, alt : '', dict : '', desc: 'Represents whether the function of usb switch to jtag is disabled or enabled. 1: disabled 0: enabled', rloc: 'EFUSE_RD_REPEAT_DATA0_REG[7]', bloc: 'B4[7]'} + RESERVE_0_40 : {show: n, blk : 0, word: 1, pos : 8, len : 1, start : 40, type : bool, wr_dis: null, rd_dis: null, alt : '', dict : '', desc: Reserved; it was created by set_missed_fields_in_regs func, rloc: 'EFUSE_RD_REPEAT_DATA0_REG[8]', bloc: 'B5[0]'} + DIS_FORCE_DOWNLOAD : {show: y, blk : 0, word: 1, pos : 9, len : 1, start : 41, type : bool, wr_dis : 2, rd_dis: null, alt : '', dict : '', desc: 'Represents whether the function that forces chip into download mode is disabled or enabled. 1: disabled 0: enabled', rloc: 'EFUSE_RD_REPEAT_DATA0_REG[9]', bloc: 'B5[1]'} + SPI_DOWNLOAD_MSPI_DIS : {show: y, blk : 0, word: 1, pos: 10, len : 1, start : 42, type : bool, wr_dis : 2, rd_dis: null, alt : '', dict : '', desc: 'Represents whether SPI0 controller during boot_mode_download is disabled or enabled. 1: disabled 0: enabled', rloc: 'EFUSE_RD_REPEAT_DATA0_REG[10]', bloc: 'B5[2]'} + DIS_TWAI : {show: y, blk : 0, word: 1, pos: 11, len : 1, start : 43, type : bool, wr_dis : 2, rd_dis: null, alt : '', dict : '', desc: 'Represents whether TWAI function is disabled or enabled. 1: disabled 0: enabled', rloc: 'EFUSE_RD_REPEAT_DATA0_REG[11]', bloc: 'B5[3]'} + JTAG_SEL_ENABLE : {show: y, blk : 0, word: 1, pos: 12, len : 1, start : 44, type : bool, wr_dis : 2, rd_dis: null, alt : '', dict : '', desc: 'Represents whether the selection between usb_to_jtag and pad_to_jtag through strapping gpio15 when both EFUSE_DIS_PAD_JTAG and EFUSE_DIS_USB_JTAG are equal to 0 is enabled or disabled. 1: enabled 0: disabled', rloc: 'EFUSE_RD_REPEAT_DATA0_REG[12]', bloc: 'B5[4]'} + DIS_PAD_JTAG : {show: y, blk : 0, word: 1, pos: 13, len : 1, start : 45, type : bool, wr_dis : 2, rd_dis: null, alt : '', dict : '', desc: 'Represents whether JTAG is disabled in the hard way(permanently). 1: disabled 0: enabled', rloc: 'EFUSE_RD_REPEAT_DATA0_REG[13]', bloc: 'B5[5]'} + DIS_DOWNLOAD_MANUAL_ENCRYPT : {show: y, blk : 0, word: 1, pos: 14, len : 1, start : 46, type : bool, wr_dis : 2, rd_dis: null, alt : '', dict : '', desc: 'Represents whether flash encrypt function is disabled or enabled(except in SPI boot mode). 1: disabled 0: enabled', rloc: 'EFUSE_RD_REPEAT_DATA0_REG[14]', bloc: 'B5[6]'} + RESERVE_0_47 : {show: n, blk : 0, word: 1, pos: 15, len : 3, start : 47, type : 'uint:3', wr_dis: null, rd_dis: null, alt : '', dict : '', desc: Reserved; it was created by set_missed_fields_in_regs func, rloc: 'EFUSE_RD_REPEAT_DATA0_REG[17:15]', bloc: 'B5[7],B6[1:0]'} + PVT_GLITCH_EN : {show: y, blk : 0, word: 1, pos: 18, len : 1, start : 50, type : bool, wr_dis: null, rd_dis: null, alt : '', dict : '', desc: 'Represents whether to enable PVT power glitch monitor function.1:Enable. 0:Disable', rloc: 'EFUSE_RD_REPEAT_DATA0_REG[18]', bloc: 'B6[2]'} + RESERVE_0_51 : {show: n, blk : 0, word: 1, pos: 19, len : 1, start : 51, type : bool, wr_dis: null, rd_dis: null, alt : '', dict : '', desc: Reserved; it was created by set_missed_fields_in_regs func, rloc: 'EFUSE_RD_REPEAT_DATA0_REG[19]', bloc: 'B6[3]'} + PVT_GLITCH_MODE : {show: y, blk : 0, word: 1, pos: 20, len : 2, start : 52, type : 'uint:2', wr_dis: null, rd_dis: null, alt : '', dict : '', desc: Use to configure glitch mode, rloc: 'EFUSE_RD_REPEAT_DATA0_REG[21:20]', bloc: 'B6[5:4]'} + DIS_CORE1 : {show: y, blk : 0, word: 1, pos: 22, len : 1, start : 54, type : bool, wr_dis: null, rd_dis: null, alt : '', dict : '', desc: 'Represents whether the CPU-Core1 is disabled. 1: Disabled. 0: Not disable', rloc: 'EFUSE_RD_REPEAT_DATA0_REG[22]', bloc: 'B6[6]'} + SPI_BOOT_CRYPT_CNT : {show: y, blk : 0, word: 1, pos: 23, len : 3, start : 55, type : 'uint:3', wr_dis : 4, rd_dis: null, alt : '', dict: '{0: "Disable", 1: "Enable", 3: "Disable", 7: "Enable"}', desc: Enables flash encryption when 1 or 3 bits are set and disables otherwise, rloc: 'EFUSE_RD_REPEAT_DATA0_REG[25:23]', bloc: 'B6[7],B7[1:0]'} + SECURE_BOOT_KEY_REVOKE0 : {show: y, blk : 0, word: 1, pos: 26, len : 1, start : 58, type : bool, wr_dis : 5, rd_dis: null, alt : '', dict : '', desc: Revoke 1st secure boot key, rloc: 'EFUSE_RD_REPEAT_DATA0_REG[26]', bloc: 'B7[2]'} + SECURE_BOOT_KEY_REVOKE1 : {show: y, blk : 0, word: 1, pos: 27, len : 1, start : 59, type : bool, wr_dis : 6, rd_dis: null, alt : '', dict : '', desc: Revoke 2nd secure boot key, rloc: 'EFUSE_RD_REPEAT_DATA0_REG[27]', bloc: 'B7[3]'} + SECURE_BOOT_KEY_REVOKE2 : {show: y, blk : 0, word: 1, pos: 28, len : 1, start : 60, type : bool, wr_dis : 7, rd_dis: null, alt : '', dict : '', desc: Revoke 3rd secure boot key, rloc: 'EFUSE_RD_REPEAT_DATA0_REG[28]', bloc: 'B7[4]'} + RESERVE_0_61 : {show: n, blk : 0, word: 1, pos: 29, len : 3, start : 61, type : 'uint:3', wr_dis: null, rd_dis: null, alt : '', dict : '', desc: Reserved; it was created by set_missed_fields_in_regs func, rloc: 'EFUSE_RD_REPEAT_DATA0_REG[31:29]', bloc: 'B7[7:5]'} + KEY_PURPOSE_0 : {show: y, blk : 0, word: 2, pos : 0, len : 5, start : 64, type : 'uint:5', wr_dis : 8, rd_dis: null, alt : KEY0_PURPOSE, dict : '', desc: Represents the purpose of Key0, rloc: 'EFUSE_RD_REPEAT_DATA1_REG[4:0]', bloc: 'B8[4:0]'} + KEY_PURPOSE_1 : {show: y, blk : 0, word: 2, pos : 5, len : 5, start : 69, type : 'uint:5', wr_dis : 9, rd_dis: null, alt : KEY1_PURPOSE, dict : '', desc: Represents the purpose of Key1, rloc: 'EFUSE_RD_REPEAT_DATA1_REG[9:5]', bloc: 'B8[7:5],B9[1:0]'} + KEY_PURPOSE_2 : {show: y, blk : 0, word: 2, pos: 10, len : 5, start : 74, type : 'uint:5', wr_dis : 10, rd_dis: null, alt : KEY2_PURPOSE, dict : '', desc: Represents the purpose of Key2, rloc: 'EFUSE_RD_REPEAT_DATA1_REG[14:10]', bloc: 'B9[6:2]'} + KEY_PURPOSE_3 : {show: y, blk : 0, word: 2, pos: 15, len : 5, start : 79, type : 'uint:5', wr_dis : 11, rd_dis: null, alt : KEY3_PURPOSE, dict : '', desc: Represents the purpose of Key3, rloc: 'EFUSE_RD_REPEAT_DATA1_REG[19:15]', bloc: 'B9[7],B10[3:0]'} + KEY_PURPOSE_4 : {show: y, blk : 0, word: 2, pos: 20, len : 5, start : 84, type : 'uint:5', wr_dis : 12, rd_dis: null, alt : KEY4_PURPOSE, dict : '', desc: Represents the purpose of Key4, rloc: 'EFUSE_RD_REPEAT_DATA1_REG[24:20]', bloc: 'B10[7:4],B11[0]'} + KEY_PURPOSE_5 : {show: y, blk : 0, word: 2, pos: 25, len : 5, start : 89, type : 'uint:5', wr_dis : 13, rd_dis: null, alt : KEY5_PURPOSE, dict : '', desc: Represents the purpose of Key5, rloc: 'EFUSE_RD_REPEAT_DATA1_REG[29:25]', bloc: 'B11[5:1]'} + SEC_DPA_LEVEL : {show: y, blk : 0, word: 2, pos: 30, len : 2, start : 94, type : 'uint:2', wr_dis : 14, rd_dis: null, alt : '', dict : '', desc: Represents the spa secure level by configuring the clock random divide mode, rloc: 'EFUSE_RD_REPEAT_DATA1_REG[31:30]', bloc: 'B11[7:6]'} + XTS_DPA_PSEUDO_LEVEL : {show: y, blk : 0, word: 3, pos : 0, len : 2, start : 96, type : 'uint:2', wr_dis : 14, rd_dis: null, alt : '', dict : '', desc: 'Represents the pseudo round level of xts-aes anti-dpa attack. 3: High. 2: Moderate 1. Low 0: Disabled', rloc: 'EFUSE_RD_REPEAT_DATA2_REG[1:0]', bloc: 'B12[1:0]'} + XTS_DPA_CLK_ENABLE : {show: y, blk : 0, word: 3, pos : 2, len : 1, start : 98, type : bool, wr_dis : 14, rd_dis: null, alt : '', dict : '', desc: 'Represents whether xts-aes anti-dpa attack clock is enabled. 1. Enable. 0: Disable.', rloc: 'EFUSE_RD_REPEAT_DATA2_REG[2]', bloc: 'B12[2]'} + ECC_FORCE_CONST_TIME : {show: y, blk : 0, word: 3, pos : 3, len : 1, start : 99, type : bool, wr_dis : 14, rd_dis: null, alt : '', dict : '', desc: 'Represents whether to force ecc to use const-time calculation mode. 1: Enable. 0: Disable', rloc: 'EFUSE_RD_REPEAT_DATA2_REG[3]', bloc: 'B12[3]'} + ECDSA_P384_ENABLE : {show: y, blk : 0, word: 3, pos : 4, len : 1, start: 100, type : bool, wr_dis: null, rd_dis: null, alt : '', dict : '', desc: Represents if the chip supports ECDSA P384, rloc: 'EFUSE_RD_REPEAT_DATA2_REG[4]', bloc: 'B12[4]'} + SECURE_BOOT_EN : {show: y, blk : 0, word: 3, pos : 5, len : 1, start: 101, type : bool, wr_dis : 15, rd_dis: null, alt : '', dict : '', desc: 'Represents whether secure boot is enabled or disabled. 1: enabled 0: disabled', rloc: 'EFUSE_RD_REPEAT_DATA2_REG[5]', bloc: 'B12[5]'} + SECURE_BOOT_AGGRESSIVE_REVOKE : {show: y, blk : 0, word: 3, pos : 6, len : 1, start: 102, type : bool, wr_dis : 16, rd_dis: null, alt : '', dict : '', desc: 'Represents whether revoking aggressive secure boot is enabled or disabled. 1: enabled. 0: disabled', rloc: 'EFUSE_RD_REPEAT_DATA2_REG[6]', bloc: 'B12[6]'} + KM_DISABLE_DEPLOY_MODE : {show: y, blk : 0, word: 3, pos : 7, len : 5, start: 103, type : 'uint:5', wr_dis : 1, rd_dis: null, alt : '', dict : '', desc: 'Represents whether the new key deployment of key manager is disabled. Bit0: Represents whether the new ECDSA key deployment is disabled0: Enabled1: DisabledBit1: Represents whether the new XTS-AES (flash and PSRAM) key deployment is disabled0: Enabled1: DisabledBit2: Represents whether the new HMAC key deployment is disabled0: Enabled1: DisabledBit3: Represents whether the new DS key deployment is disabled0: Enabled1: Disabled', rloc: 'EFUSE_RD_REPEAT_DATA2_REG[11:7]', bloc: 'B12[7],B13[3:0]'} + KM_RND_SWITCH_CYCLE : {show: y, blk : 0, word: 3, pos: 12, len : 2, start: 108, type : 'uint:2', wr_dis : 1, rd_dis: null, alt : '', dict : '', desc: 'Represents the cycle at which the Key Manager switches random numbers.0: Controlled by the \hyperref[fielddesc:KEYMNGRNDSWITCHCYCLE]{KEYMNG\_RND\_SWITCH\_CYCLE} register. For more information; please refer to Chapter \ref{mod:keymng} \textit{\nameref{mod:keymng}}1: 8 Key Manager clock cycles2: 16 Key Manager clock cycles3: 32 Key Manager clock cycles', rloc: 'EFUSE_RD_REPEAT_DATA2_REG[13:12]', bloc: 'B13[5:4]'} + KM_DEPLOY_ONLY_ONCE : {show: y, blk : 0, word: 3, pos: 14, len : 5, start: 110, type : 'uint:5', wr_dis : 1, rd_dis: null, alt : '', dict : '', desc: 'Represents whether the corresponding key can be deployed only once.Bit0: Represents whether the ECDSA key can be deployed only once0: The key can be deployed multiple times1: The key can be deployed only onceBit1: Represents whether the XTS-AES (flash and PSRAM) key can be deployed only once0: The key can be deployed multiple times1: The key can be deployed only onceBit2: Represents whether the HMAC key can be deployed only once0: The key can be deployed multiple times1: The key can be deployed only onceBit3: Represents whether the DS key can be deployed only once0: The key can be deployed multiple times1: The key can be deployed only once', rloc: 'EFUSE_RD_REPEAT_DATA2_REG[18:14]', bloc: 'B13[7:6],B14[2:0]'} + FORCE_USE_KEY_MANAGER_KEY : {show: y, blk : 0, word: 3, pos: 19, len : 5, start: 115, type : 'uint:5', wr_dis : 1, rd_dis: null, alt : '', dict : '', desc: 'Represents whether the corresponding key must come from Key Manager. Bit0: Represents whether the ECDSA key must come from Key Manager.0: The key does not need to come from Key Manager1: The key must come from Key ManagerBit1: Represents whether the XTS-AES (flash and PSRAM) key must come from Key Manager.0: The key does not need to come from Key Manager1: The key must come from Key ManagerBit2: Represents whether the HMAC key must come from Key Manager.0: The key does not need to come from Key Manager1: The key must come from Key ManagerBit3: Represents whether the DS key must come from Key Manager.0: The key does not need to come from Key Manager1: The key must come from Key Manager', rloc: 'EFUSE_RD_REPEAT_DATA2_REG[23:19]', bloc: 'B14[7:3]'} + FORCE_DISABLE_SW_INIT_KEY : {show: y, blk : 0, word: 3, pos: 24, len : 1, start: 120, type : bool, wr_dis : 1, rd_dis: null, alt : '', dict : '', desc: 'Represents whether to disable the use of the initialization key written by software and instead force use efuse\_init\_key.0: Enable1: Disable', rloc: 'EFUSE_RD_REPEAT_DATA2_REG[24]', bloc: 'B15[0]'} + KM_XTS_KEY_LENGTH_256 : {show: y, blk : 0, word: 3, pos: 25, len : 1, start: 121, type : bool, wr_dis : 1, rd_dis: null, alt : '', dict : '', desc: 'Represents which key flash encryption uses.0: XTS-AES-256 key1: XTS-AES-128 key', rloc: 'EFUSE_RD_REPEAT_DATA2_REG[25]', bloc: 'B15[1]'} + LOCK_KM_KEY : {show: y, blk : 0, word: 3, pos: 26, len : 1, start: 122, type : bool, wr_dis : 1, rd_dis: null, alt : '', dict : '', desc: 'Represents whether the keys in the Key Manager are locked after deployment.0: Not locked1: Locked', rloc: 'EFUSE_RD_REPEAT_DATA2_REG[26]', bloc: 'B15[2]'} + FLASH_TPUW : {show: y, blk : 0, word: 3, pos: 27, len : 3, start: 123, type : 'uint:3', wr_dis : 18, rd_dis: null, alt : '', dict : '', desc: Represents the flash waiting time after power-up; in unit of ms. When the value less than 15; the waiting time is the programmed value. Otherwise; the waiting time is 2 times the programmed value, rloc: 'EFUSE_RD_REPEAT_DATA2_REG[29:27]', bloc: 'B15[5:3]'} + RESERVE_0_126 : {show: n, blk : 0, word: 3, pos: 30, len : 1, start: 126, type : bool, wr_dis: null, rd_dis: null, alt : '', dict : '', desc: Reserved; it was created by set_missed_fields_in_regs func, rloc: 'EFUSE_RD_REPEAT_DATA2_REG[30]', bloc: 'B15[6]'} + DIS_DOWNLOAD_MODE : {show: y, blk : 0, word: 3, pos: 31, len : 1, start: 127, type : bool, wr_dis : 18, rd_dis: null, alt : '', dict : '', desc: 'Represents whether Download mode is disabled or enabled. 1: disabled 0: enabled', rloc: 'EFUSE_RD_REPEAT_DATA2_REG[31]', bloc: 'B15[7]'} + DIS_DIRECT_BOOT : {show: y, blk : 0, word: 4, pos : 0, len : 1, start: 128, type : bool, wr_dis : 18, rd_dis: null, alt : '', dict : '', desc: 'Represents whether direct boot mode is disabled or enabled. 1: disabled 0: enabled', rloc: 'EFUSE_RD_REPEAT_DATA3_REG[0]', bloc: 'B16[0]'} + DIS_USB_SERIAL_JTAG_ROM_PRINT : {show: y, blk : 0, word: 4, pos : 1, len : 1, start: 129, type : bool, wr_dis : 18, rd_dis: null, alt : '', dict : '', desc: 'Represents whether print from USB-Serial-JTAG is disabled or enabled. 1: disabled 0: enabled', rloc: 'EFUSE_RD_REPEAT_DATA3_REG[1]', bloc: 'B16[1]'} + DIS_USB_SERIAL_JTAG_DOWNLOAD_MODE: {show: y, blk : 0, word: 4, pos : 2, len : 1, start: 130, type : bool, wr_dis : 18, rd_dis: null, alt : '', dict : '', desc: 'Represents whether the USB-Serial-JTAG download function is disabled or enabled. 1: Disable 0: Enable', rloc: 'EFUSE_RD_REPEAT_DATA3_REG[2]', bloc: 'B16[2]'} + ENABLE_SECURITY_DOWNLOAD : {show: y, blk : 0, word: 4, pos : 3, len : 1, start: 131, type : bool, wr_dis : 18, rd_dis: null, alt : '', dict : '', desc: 'Represents whether security download is enabled or disabled. 1: enabled 0: disabled', rloc: 'EFUSE_RD_REPEAT_DATA3_REG[3]', bloc: 'B16[3]'} + UART_PRINT_CONTROL : {show: y, blk : 0, word: 4, pos : 4, len : 2, start: 132, type : 'uint:2', wr_dis : 18, rd_dis: null, alt : '', dict : '', desc: 'Represents the type of UART printing. 00: force enable printing 01: enable printing when GPIO8 is reset at low level 10: enable printing when GPIO8 is reset at high level 11: force disable printing', rloc: 'EFUSE_RD_REPEAT_DATA3_REG[5:4]', bloc: 'B16[5:4]'} + FORCE_SEND_RESUME : {show: y, blk : 0, word: 4, pos : 6, len : 1, start: 134, type : bool, wr_dis : 18, rd_dis: null, alt : '', dict : '', desc: 'Represents whether ROM code is forced to send a resume command during SPI boot. 1: forced 0:not forced', rloc: 'EFUSE_RD_REPEAT_DATA3_REG[6]', bloc: 'B16[6]'} + SECURE_VERSION : {show: y, blk : 0, word: 4, pos : 7, len : 16, start: 135, type : 'uint:16', wr_dis : 18, rd_dis: null, alt : '', dict : '', desc: Represents the version used by ESP-IDF anti-rollback feature, rloc: 'EFUSE_RD_REPEAT_DATA3_REG[22:7]', bloc: 'B16[7],B17,B18[6:0]'} + HUK_GEN_STATE : {show: y, blk : 0, word: 4, pos: 23, len : 5, start: 151, type : 'uint:5', wr_dis : 19, rd_dis: null, alt : '', dict : '', desc: 'Represents whether the HUK generate mode is valid.Odd count of bits with a value of 1: InvalidEven count of bits with a value of 1: Valid', rloc: 'EFUSE_RD_REPEAT_DATA3_REG[27:23]', bloc: 'B18[7],B19[3:0]'} + FLASH_LDO_EFUSE_SEL : {show: y, blk : 0, word: 4, pos: 28, len : 1, start: 156, type : bool, wr_dis: null, rd_dis: null, alt : '', dict : '', desc: 'Represents whether to select efuse control flash ldo default voltage. 1 : efuse 0 : strapping', rloc: 'EFUSE_RD_REPEAT_DATA3_REG[28]', bloc: 'B19[4]'} + RESERVE_0_157 : {show: n, blk : 0, word: 4, pos: 29, len : 3, start: 157, type : 'uint:3', wr_dis: null, rd_dis: null, alt : '', dict : '', desc: Reserved; it was created by set_missed_fields_in_regs func, rloc: 'EFUSE_RD_REPEAT_DATA3_REG[31:29]', bloc: 'B19[7:5]'} + RESERVE_0_160 : {show: n, blk : 0, word: 5, pos : 0, len : 8, start: 160, type : 'uint:8', wr_dis: null, rd_dis: null, alt : '', dict : '', desc: Reserved; it was created by set_missed_fields_in_regs func, rloc: 'EFUSE_RD_REPEAT_DATA4_REG[7:0]', bloc: B20} + USB_EXCHG_PINS : {show: y, blk : 0, word: 5, pos : 8, len : 1, start: 168, type : bool, wr_dis : 30, rd_dis: null, alt : '', dict : '', desc: 'Represents whether the D+ and D- pins of USB_SERIAL_JTAG PHY is exchanged. 1: exchanged 0: not exchanged', rloc: 'EFUSE_RD_REPEAT_DATA4_REG[8]', bloc: 'B21[0]'} + USB_OTG_FS_EXCHG_PINS : {show: y, blk : 0, word: 5, pos : 9, len : 1, start: 169, type : bool, wr_dis: null, rd_dis: null, alt : '', dict : '', desc: 'Represents whether the D+ and D- pins of USB_OTG_FS PHY is exchanged. 1: exchanged 0: not exchanged', rloc: 'EFUSE_RD_REPEAT_DATA4_REG[9]', bloc: 'B21[1]'} + USB_PHY_SEL : {show: y, blk : 0, word: 5, pos: 10, len : 1, start: 170, type : bool, wr_dis: null, rd_dis: null, alt : '', dict : '', desc: 'Represents whether to exchange the USB_SERIAL_JTAG PHY with USB_OTG_FS PHY. 1: exchanged. 0: not exchanged', rloc: 'EFUSE_RD_REPEAT_DATA4_REG[10]', bloc: 'B21[2]'} + SOFT_DIS_JTAG : {show: y, blk : 0, word: 5, pos: 11, len : 3, start: 171, type : 'uint:3', wr_dis : 31, rd_dis: null, alt : '', dict : '', desc: 'Represents whether JTAG is disabled in soft way. Odd number: disabled Even number: enabled', rloc: 'EFUSE_RD_REPEAT_DATA4_REG[13:11]', bloc: 'B21[5:3]'} + IO_LDO_ADJUST : {show: y, blk : 0, word: 5, pos: 14, len : 8, start: 174, type : 'uint:8', wr_dis: null, rd_dis: null, alt : '', dict : '', desc: Represents configuration of IO LDO mode and voltage., rloc: 'EFUSE_RD_REPEAT_DATA4_REG[21:14]', bloc: 'B21[7:6],B22[5:0]'} + IO_LDO_1P8 : {show: y, blk : 0, word: 5, pos: 22, len : 1, start: 182, type : bool, wr_dis: null, rd_dis: null, alt : '', dict : '', desc: 'Represents select IO LDO voltage to 1.8V or 3.3V. 1: 1.8V 0: 3.3V', rloc: 'EFUSE_RD_REPEAT_DATA4_REG[22]', bloc: 'B22[6]'} + DCDC_CCM_EN : {show: y, blk : 0, word: 5, pos: 23, len : 1, start: 183, type : bool, wr_dis: null, rd_dis: null, alt : '', dict : '', desc: Represents whether change DCDC to CCM mode, rloc: 'EFUSE_RD_REPEAT_DATA4_REG[23]', bloc: 'B22[7]'} + RESERVE_0_184 : {show: n, blk : 0, word: 5, pos: 24, len : 8, start: 184, type : 'uint:8', wr_dis: null, rd_dis: null, alt : '', dict : '', desc: Reserved; it was created by set_missed_fields_in_regs func, rloc: 'EFUSE_RD_REPEAT_DATA4_REG[31:24]', bloc: B23} + MAC : {show: y, blk : 1, word: 0, pos : 0, len : 48, start : 0, type : 'bytes:6', wr_dis : 20, rd_dis: null, alt : MAC_FACTORY, dict : '', desc: MAC address, rloc: EFUSE_RD_MAC_SYS0_REG, bloc: 'B0,B1,B2,B3,B4,B5'} + MAC_EXT : {show: y, blk : 1, word: 1, pos: 16, len : 16, start : 48, type : 'bytes:2', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: Represents the extended bits of MAC address, rloc: 'EFUSE_RD_MAC_SYS1_REG[31:16]', bloc: 'B6,B7'} + PVT_LIMIT : {show: y, blk : 1, word: 2, pos : 0, len : 16, start : 64, type : 'uint:16', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: Power glitch monitor threthold, rloc: 'EFUSE_RD_MAC_SYS2_REG[15:0]', bloc: 'B8,B9'} + PVT_CELL_SELECT : {show: y, blk : 1, word: 2, pos: 16, len : 7, start : 80, type : 'uint:7', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: Power glitch monitor PVT cell select, rloc: 'EFUSE_RD_MAC_SYS2_REG[22:16]', bloc: 'B10[6:0]'} + PVT_PUMP_LIMIT : {show: y, blk : 1, word: 2, pos: 23, len : 8, start : 87, type : 'uint:8', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: Use to configure voltage monitor limit for charge pump, rloc: 'EFUSE_RD_MAC_SYS2_REG[30:23]', bloc: 'B10[7],B11[6:0]'} + RESERVE_1_95 : {show: n, blk : 1, word: 2, pos: 31, len : 1, start : 95, type : bool, wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: Reserved; it was created by set_missed_fields_in_regs func, rloc: 'EFUSE_RD_MAC_SYS2_REG[31]', bloc: 'B11[7]'} + PUMP_DRV : {show: y, blk : 1, word: 3, pos : 0, len : 4, start : 96, type : 'uint:4', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: Use to configure charge pump voltage gain, rloc: 'EFUSE_RD_MAC_SYS3_REG[3:0]', bloc: 'B12[3:0]'} + WDT_DELAY_SEL : {show: y, blk : 1, word: 3, pos : 4, len : 2, start: 100, type : 'uint:2', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: 'Represents the threshold level of the RTC watchdog STG0 timeout. 0: Original threshold configuration value of STG0 *2 1: Original threshold configuration value of STG0 *4 2: Original threshold configuration value of STG0 *8 3: Original threshold configuration value of STG0 *16 ', rloc: 'EFUSE_RD_MAC_SYS3_REG[5:4]', bloc: 'B12[5:4]'} + HYS_EN_PAD : {show: y, blk : 1, word: 3, pos : 6, len : 1, start: 102, type : bool, wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: 'Represents whether the hysteresis function of corresponding PAD is enabled. 1: enabled 0:disabled', rloc: 'EFUSE_RD_MAC_SYS3_REG[6]', bloc: 'B12[6]'} + PVT_GLITCH_CHARGE_RESET : {show: y, blk : 1, word: 3, pos : 7, len : 1, start: 103, type : bool, wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: 'Represents whether to trigger reset or charge pump when PVT power glitch happened.1:Trigger charge pump. 0:Trigger reset', rloc: 'EFUSE_RD_MAC_SYS3_REG[7]', bloc: 'B12[7]'} + RESERVE_1_104 : {show: n, blk : 1, word: 3, pos : 8, len : 1, start: 104, type : bool, wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: Reserved; it was created by set_missed_fields_in_regs func, rloc: 'EFUSE_RD_MAC_SYS3_REG[8]', bloc: 'B13[0]'} + VDD_SPI_LDO_ADJUST : {show: y, blk : 1, word: 3, pos : 9, len : 8, start: 105, type : 'uint:8', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: Represents configuration of FLASH LDO mode and voltage., rloc: 'EFUSE_RD_MAC_SYS3_REG[16:9]', bloc: 'B13[7:1],B14[0]'} + FLASH_LDO_POWER_SEL : {show: y, blk : 1, word: 3, pos: 17, len : 1, start: 113, type : bool, wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: 'Represents which flash ldo be select: 1: FLASH LDO 1P2 0 : FLASH LDO 1P8', rloc: 'EFUSE_RD_MAC_SYS3_REG[17]', bloc: 'B14[1]'} + SYS_DATA_PART0_0 : {show: n, blk : 1, word: 3, pos: 18, len : 14, start: 114, type : 'uint:14', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: Represents the first 14-bit of zeroth part of system data, rloc: 'EFUSE_RD_MAC_SYS3_REG[31:18]', bloc: 'B14[7:2],B15'} + SYS_DATA_PART0_1 : {show: n, blk : 1, word: 4, pos : 0, len : 32, start: 128, type : 'uint:32', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: Represents the first 14-bit of zeroth part of system data, rloc: EFUSE_RD_MAC_SYS4_REG, bloc: 'B16,B17,B18,B19'} + SYS_DATA_PART0_2 : {show: n, blk : 1, word: 5, pos : 0, len : 32, start: 160, type : 'uint:32', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: Represents the second 32-bit of zeroth part of system data, rloc: EFUSE_RD_MAC_SYS5_REG, bloc: 'B20,B21,B22,B23'} + SYS_DATA_PART1_0 : {show: n, blk : 2, word: 0, pos : 0, len: 256, start : 0, type: 'bytes:32', wr_dis : 21, rd_dis: null, alt : '', dict : '', desc: Represents the zeroth 32-bit of first part of system data, rloc: EFUSE_RD_SYS_PART1_DATA0_REG, bloc: 'B0,B1,B2,B3,B4,B5,B6,B7,B8,B9,B10,B11,B12,B13,B14,B15,B16,B17,B18,B19,B20,B21,B22,B23,B24,B25,B26,B27,B28,B29,B30,B31'} + BLOCK_USR_DATA : {show: y, blk : 3, word: 0, pos : 0, len: 192, start : 0, type: 'bytes:24', wr_dis : 22, rd_dis: null, alt : USER_DATA, dict : '', desc: User data, rloc: EFUSE_RD_USR_DATA0_REG, bloc: 'B0,B1,B2,B3,B4,B5,B6,B7,B8,B9,B10,B11,B12,B13,B14,B15,B16,B17,B18,B19,B20,B21,B22,B23'} + RESERVED_3_192 : {show: n, blk : 3, word: 6, pos : 0, len : 8, start: 192, type : 'uint:8', wr_dis : 22, rd_dis: null, alt : '', dict : '', desc: reserved, rloc: 'EFUSE_RD_USR_DATA6_REG[7:0]', bloc: B24} + CUSTOM_MAC : {show: y, blk : 3, word: 6, pos : 8, len : 48, start: 200, type : 'bytes:6', wr_dis : 22, rd_dis: null, alt: MAC_CUSTOM USER_DATA_MAC_CUSTOM, dict : '', desc: Custom MAC, rloc: 'EFUSE_RD_USR_DATA6_REG[31:8]', bloc: 'B25,B26,B27,B28,B29,B30'} + RESERVED_3_248 : {show: n, blk : 3, word: 7, pos: 24, len : 8, start: 248, type : 'uint:8', wr_dis : 22, rd_dis: null, alt : '', dict : '', desc: reserved, rloc: 'EFUSE_RD_USR_DATA7_REG[31:24]', bloc: B31} + BLOCK_KEY0 : {show: y, blk : 4, word: 0, pos : 0, len: 256, start : 0, type: 'bytes:32', wr_dis : 23, rd_dis : 0, alt : KEY0, dict : '', desc: Key0 or user data, rloc: EFUSE_RD_KEY0_DATA0_REG, bloc: 'B0,B1,B2,B3,B4,B5,B6,B7,B8,B9,B10,B11,B12,B13,B14,B15,B16,B17,B18,B19,B20,B21,B22,B23,B24,B25,B26,B27,B28,B29,B30,B31'} + BLOCK_KEY1 : {show: y, blk : 5, word: 0, pos : 0, len: 256, start : 0, type: 'bytes:32', wr_dis : 24, rd_dis : 1, alt : KEY1, dict : '', desc: Key1 or user data, rloc: EFUSE_RD_KEY1_DATA0_REG, bloc: 'B0,B1,B2,B3,B4,B5,B6,B7,B8,B9,B10,B11,B12,B13,B14,B15,B16,B17,B18,B19,B20,B21,B22,B23,B24,B25,B26,B27,B28,B29,B30,B31'} + BLOCK_KEY2 : {show: y, blk : 6, word: 0, pos : 0, len: 256, start : 0, type: 'bytes:32', wr_dis : 25, rd_dis : 2, alt : KEY2, dict : '', desc: Key2 or user data, rloc: EFUSE_RD_KEY2_DATA0_REG, bloc: 'B0,B1,B2,B3,B4,B5,B6,B7,B8,B9,B10,B11,B12,B13,B14,B15,B16,B17,B18,B19,B20,B21,B22,B23,B24,B25,B26,B27,B28,B29,B30,B31'} + BLOCK_KEY3 : {show: y, blk : 7, word: 0, pos : 0, len: 256, start : 0, type: 'bytes:32', wr_dis : 26, rd_dis : 3, alt : KEY3, dict : '', desc: Key3 or user data, rloc: EFUSE_RD_KEY3_DATA0_REG, bloc: 'B0,B1,B2,B3,B4,B5,B6,B7,B8,B9,B10,B11,B12,B13,B14,B15,B16,B17,B18,B19,B20,B21,B22,B23,B24,B25,B26,B27,B28,B29,B30,B31'} + BLOCK_KEY4 : {show: y, blk : 8, word: 0, pos : 0, len: 256, start : 0, type: 'bytes:32', wr_dis : 27, rd_dis : 4, alt : KEY4, dict : '', desc: Key4 or user data, rloc: EFUSE_RD_KEY4_DATA0_REG, bloc: 'B0,B1,B2,B3,B4,B5,B6,B7,B8,B9,B10,B11,B12,B13,B14,B15,B16,B17,B18,B19,B20,B21,B22,B23,B24,B25,B26,B27,B28,B29,B30,B31'} + BLOCK_KEY5 : {show: y, blk : 9, word: 0, pos : 0, len: 256, start : 0, type: 'bytes:32', wr_dis : 28, rd_dis : 5, alt : KEY5, dict : '', desc: Key5 or user data, rloc: EFUSE_RD_KEY5_DATA0_REG, bloc: 'B0,B1,B2,B3,B4,B5,B6,B7,B8,B9,B10,B11,B12,B13,B14,B15,B16,B17,B18,B19,B20,B21,B22,B23,B24,B25,B26,B27,B28,B29,B30,B31'} + BLOCK_SYS_DATA2 : {show: y, blk: 10, word: 0, pos : 0, len: 256, start : 0, type: 'bytes:32', wr_dis : 29, rd_dis : 6, alt : SYS_DATA_PART2, dict : '', desc: System data part 2 (reserved), rloc: EFUSE_RD_SYS_PART2_DATA0_REG, bloc: 'B0,B1,B2,B3,B4,B5,B6,B7,B8,B9,B10,B11,B12,B13,B14,B15,B16,B17,B18,B19,B20,B21,B22,B23,B24,B25,B26,B27,B28,B29,B30,B31'} diff --git a/tools/esptool_py/espefuse/efuse_defs/esp32p4.yaml b/tools/esptool_py/espefuse/efuse_defs/esp32p4.yaml index e4ffea60d7..d002552a4f 100644 --- a/tools/esptool_py/espefuse/efuse_defs/esp32p4.yaml +++ b/tools/esptool_py/espefuse/efuse_defs/esp32p4.yaml @@ -1,4 +1,4 @@ -VER_NO: d4a48929387e281bd05db8cfb3a85f60 +VER_NO: f7765f0ac3faf4b54f8c1f064307522c EFUSES: WR_DIS : {show: y, blk : 0, word: 0, pos : 0, len : 32, start : 0, type : 'uint:32', wr_dis: null, rd_dis: null, alt : '', dict : '', desc: Disable programming of individual eFuses, rloc: EFUSE_RD_WR_DIS_REG, bloc: 'B0,B1,B2,B3'} RD_DIS : {show: y, blk : 0, word: 1, pos : 0, len : 7, start : 32, type : 'uint:7', wr_dis : 0, rd_dis: null, alt : '', dict : '', desc: Disable reading from BlOCK4-10, rloc: 'EFUSE_RD_REPEAT_DATA0_REG[6:0]', bloc: 'B4[6:0]'} @@ -10,7 +10,7 @@ EFUSES: DIS_FORCE_DOWNLOAD : {show: y, blk : 0, word: 1, pos: 12, len : 1, start : 44, type : bool, wr_dis : 2, rd_dis: null, alt : '', dict : '', desc: 'Represents whether the function that forces chip into download mode is disabled or enabled. 1: disabled. 0: enabled', rloc: 'EFUSE_RD_REPEAT_DATA0_REG[12]', bloc: 'B5[4]'} SPI_DOWNLOAD_MSPI_DIS : {show: y, blk : 0, word: 1, pos: 13, len : 1, start : 45, type : bool, wr_dis : 2, rd_dis: null, alt : '', dict : '', desc: Set this bit to disable accessing MSPI flash/MSPI ram by SYS AXI matrix during boot_mode_download, rloc: 'EFUSE_RD_REPEAT_DATA0_REG[13]', bloc: 'B5[5]'} DIS_TWAI : {show: y, blk : 0, word: 1, pos: 14, len : 1, start : 46, type : bool, wr_dis : 2, rd_dis: null, alt : '', dict : '', desc: 'Represents whether TWAI function is disabled or enabled. 1: disabled. 0: enabled', rloc: 'EFUSE_RD_REPEAT_DATA0_REG[14]', bloc: 'B5[6]'} - JTAG_SEL_ENABLE : {show: y, blk : 0, word: 1, pos: 15, len : 1, start : 47, type : bool, wr_dis : 2, rd_dis: null, alt : '', dict : '', desc: 'Represents whether the selection between usb_to_jtag and pad_to_jtag through strapping gpio15 when both EFUSE_DIS_PAD_JTAG and EFUSE_DIS_USB_JTAG are equal to 0 is enabled or disabled. 1: enabled. 0: disabled', rloc: 'EFUSE_RD_REPEAT_DATA0_REG[15]', bloc: 'B5[7]'} + JTAG_SEL_ENABLE : {show: y, blk : 0, word: 1, pos: 15, len : 1, start : 47, type : bool, wr_dis : 2, rd_dis: null, alt : '', dict : '', desc: 'Represents whether the selection between usb_to_jtag and pad_to_jtag through strapping gpio34 when both EFUSE_DIS_PAD_JTAG and EFUSE_DIS_USB_JTAG are equal to 0 is enabled or disabled. 1: enabled. 0: disabled', rloc: 'EFUSE_RD_REPEAT_DATA0_REG[15]', bloc: 'B5[7]'} SOFT_DIS_JTAG : {show: y, blk : 0, word: 1, pos: 16, len : 3, start : 48, type : 'uint:3', wr_dis : 31, rd_dis: null, alt : '', dict : '', desc: 'Represents whether JTAG is disabled in soft way. Odd number: disabled. Even number: enabled', rloc: 'EFUSE_RD_REPEAT_DATA0_REG[18:16]', bloc: 'B6[2:0]'} DIS_PAD_JTAG : {show: y, blk : 0, word: 1, pos: 19, len : 1, start : 51, type : bool, wr_dis : 2, rd_dis: null, alt : '', dict : '', desc: 'Represents whether JTAG is disabled in the hard way(permanently). 1: disabled. 0: enabled', rloc: 'EFUSE_RD_REPEAT_DATA0_REG[19]', bloc: 'B6[3]'} DIS_DOWNLOAD_MANUAL_ENCRYPT : {show: y, blk : 0, word: 1, pos: 20, len : 1, start : 52, type : bool, wr_dis : 2, rd_dis: null, alt : '', dict : '', desc: 'Represents whether flash encrypt function is disabled or enabled(except in SPI boot mode). 1: disabled. 0: enabled', rloc: 'EFUSE_RD_REPEAT_DATA0_REG[20]', bloc: 'B6[4]'} @@ -74,7 +74,7 @@ EFUSES: MAC : {show: y, blk : 1, word: 0, pos : 0, len : 48, start : 0, type : 'bytes:6', wr_dis : 20, rd_dis: null, alt : MAC_FACTORY, dict : '', desc: MAC address, rloc: EFUSE_RD_MAC_SYS_0_REG, bloc: 'B0,B1,B2,B3,B4,B5'} RESERVED_1_16 : {show: n, blk : 1, word: 1, pos: 16, len : 16, start : 48, type : 'uint:16', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: Stores the extended bits of MAC address, rloc: 'EFUSE_RD_MAC_SYS_1_REG[31:16]', bloc: 'B6,B7'} WAFER_VERSION_MINOR : {show: y, blk : 1, word: 2, pos : 0, len : 4, start : 64, type : 'uint:4', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: Minor chip version, rloc: 'EFUSE_RD_MAC_SYS_2_REG[3:0]', bloc: 'B8[3:0]'} - WAFER_VERSION_MAJOR : {show: y, blk : 1, word: 2, pos : 4, len : 2, start : 68, type : 'uint:2', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: Major chip version, rloc: 'EFUSE_RD_MAC_SYS_2_REG[5:4]', bloc: 'B8[5:4]'} + WAFER_VERSION_MAJOR_LO : {show: y, blk : 1, word: 2, pos : 4, len : 2, start : 68, type : 'uint:2', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: Major chip version (lower 2 bits), rloc: 'EFUSE_RD_MAC_SYS_2_REG[5:4]', bloc: 'B8[5:4]'} DISABLE_WAFER_VERSION_MAJOR : {show: y, blk : 1, word: 2, pos : 6, len : 1, start : 70, type : bool, wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: Disables check of wafer version major, rloc: 'EFUSE_RD_MAC_SYS_2_REG[6]', bloc: 'B8[6]'} DISABLE_BLK_VERSION_MAJOR : {show: y, blk : 1, word: 2, pos : 7, len : 1, start : 71, type : bool, wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: Disables check of blk version major, rloc: 'EFUSE_RD_MAC_SYS_2_REG[7]', bloc: 'B8[7]'} BLK_VERSION_MINOR : {show: y, blk : 1, word: 2, pos : 8, len : 3, start : 72, type : 'uint:3', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: BLK_VERSION_MINOR of BLOCK2, rloc: 'EFUSE_RD_MAC_SYS_2_REG[10:8]', bloc: 'B9[2:0]'} @@ -83,16 +83,39 @@ EFUSES: TEMP : {show: y, blk : 1, word: 2, pos: 16, len : 2, start : 80, type : 'uint:2', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: Operating temperature of the ESP chip, rloc: 'EFUSE_RD_MAC_SYS_2_REG[17:16]', bloc: 'B10[1:0]'} PSRAM_VENDOR : {show: y, blk : 1, word: 2, pos: 18, len : 2, start : 82, type : 'uint:2', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: PSRAM vendor, rloc: 'EFUSE_RD_MAC_SYS_2_REG[19:18]', bloc: 'B10[3:2]'} PKG_VERSION : {show: y, blk : 1, word: 2, pos: 20, len : 3, start : 84, type : 'uint:3', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: Package version, rloc: 'EFUSE_RD_MAC_SYS_2_REG[22:20]', bloc: 'B10[6:4]'} - RESERVED_1_87 : {show: n, blk : 1, word: 2, pos: 23, len : 9, start : 87, type : 'uint:9', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: reserved, rloc: 'EFUSE_RD_MAC_SYS_2_REG[31:23]', bloc: 'B10[7],B11'} - MAC_RESERVED_2 : {show: n, blk : 1, word: 3, pos : 0, len : 18, start : 96, type : 'uint:18', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: Reserved, rloc: 'EFUSE_RD_MAC_SYS_3_REG[17:0]', bloc: 'B12,B13,B14[1:0]'} - SYS_DATA_PART0_0 : {show: n, blk : 1, word: 3, pos: 18, len : 14, start: 114, type : 'uint:14', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: Stores the first 14 bits of the zeroth part of system data, rloc: 'EFUSE_RD_MAC_SYS_3_REG[31:18]', bloc: 'B14[7:2],B15'} - SYS_DATA_PART0_1 : {show: n, blk : 1, word: 4, pos : 0, len : 32, start: 128, type : 'uint:32', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: Stores the first 32 bits of the zeroth part of system data, rloc: EFUSE_RD_MAC_SYS_4_REG, bloc: 'B16,B17,B18,B19'} - SYS_DATA_PART0_2 : {show: n, blk : 1, word: 5, pos : 0, len : 32, start: 160, type : 'uint:32', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: Stores the second 32 bits of the zeroth part of system data, rloc: EFUSE_RD_MAC_SYS_5_REG, bloc: 'B20,B21,B22,B23'} + WAFER_VERSION_MAJOR_HI : {show: y, blk : 1, word: 2, pos: 23, len : 1, start : 87, type : bool, wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: Major chip version (MSB), rloc: 'EFUSE_RD_MAC_SYS_2_REG[23]', bloc: 'B10[7]'} + LDO_VO1_DREF : {show: y, blk : 1, word: 2, pos: 24, len : 4, start : 88, type : 'uint:4', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: Output VO1 parameter, rloc: 'EFUSE_RD_MAC_SYS_2_REG[27:24]', bloc: 'B11[3:0]'} + LDO_VO2_DREF : {show: y, blk : 1, word: 2, pos: 28, len : 4, start : 92, type : 'uint:4', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: Output VO2 parameter, rloc: 'EFUSE_RD_MAC_SYS_2_REG[31:28]', bloc: 'B11[7:4]'} + LDO_VO1_MUL : {show: y, blk : 1, word: 3, pos : 0, len : 3, start : 96, type : 'uint:3', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: Output VO1 parameter, rloc: 'EFUSE_RD_MAC_SYS_3_REG[2:0]', bloc: 'B12[2:0]'} + LDO_VO2_MUL : {show: y, blk : 1, word: 3, pos : 3, len : 3, start : 99, type : 'uint:3', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: Output VO2 parameter, rloc: 'EFUSE_RD_MAC_SYS_3_REG[5:3]', bloc: 'B12[5:3]'} + LDO_VO3_K : {show: y, blk : 1, word: 3, pos : 6, len : 8, start: 102, type : 'uint:8', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: Output VO3 calibration parameter, rloc: 'EFUSE_RD_MAC_SYS_3_REG[13:6]', bloc: 'B12[7:6],B13[5:0]'} + LDO_VO3_VOS : {show: y, blk : 1, word: 3, pos: 14, len : 6, start: 110, type : 'uint:6', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: Output VO3 calibration parameter, rloc: 'EFUSE_RD_MAC_SYS_3_REG[19:14]', bloc: 'B13[7:6],B14[3:0]'} + LDO_VO3_C : {show: y, blk : 1, word: 3, pos: 20, len : 6, start: 116, type : 'uint:6', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: Output VO3 calibration parameter, rloc: 'EFUSE_RD_MAC_SYS_3_REG[25:20]', bloc: 'B14[7:4],B15[1:0]'} + LDO_VO4_K : {show: y, blk : 1, word: 3, pos: 26, len : 8, start: 122, type : 'uint:8', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: Output VO4 calibration parameter, rloc: 'EFUSE_RD_MAC_SYS_3_REG[31:26]', bloc: 'B15[7:2],B16[1:0]'} + LDO_VO4_VOS : {show: y, blk : 1, word: 4, pos : 2, len : 6, start: 130, type : 'uint:6', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: Output VO4 calibration parameter, rloc: 'EFUSE_RD_MAC_SYS_4_REG[7:2]', bloc: 'B16[7:2]'} + LDO_VO4_C : {show: y, blk : 1, word: 4, pos : 8, len : 6, start: 136, type : 'uint:6', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: Output VO4 calibration parameter, rloc: 'EFUSE_RD_MAC_SYS_4_REG[13:8]', bloc: 'B17[5:0]'} + RESERVED_1_142 : {show: n, blk : 1, word: 4, pos: 14, len : 2, start: 142, type : 'uint:2', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: reserved, rloc: 'EFUSE_RD_MAC_SYS_4_REG[15:14]', bloc: 'B17[7:6]'} + ACTIVE_HP_DBIAS : {show: y, blk : 1, word: 4, pos: 16, len : 4, start: 144, type : 'uint:4', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: Active HP DBIAS of fixed voltage, rloc: 'EFUSE_RD_MAC_SYS_4_REG[19:16]', bloc: 'B18[3:0]'} + ACTIVE_LP_DBIAS : {show: y, blk : 1, word: 4, pos: 20, len : 4, start: 148, type : 'uint:4', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: Active LP DBIAS of fixed voltage, rloc: 'EFUSE_RD_MAC_SYS_4_REG[23:20]', bloc: 'B18[7:4]'} + LSLP_HP_DBIAS : {show: y, blk : 1, word: 4, pos: 24, len : 4, start: 152, type : 'uint:4', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: LSLP HP DBIAS of fixed voltage, rloc: 'EFUSE_RD_MAC_SYS_4_REG[27:24]', bloc: 'B19[3:0]'} + DSLP_DBG : {show: y, blk : 1, word: 4, pos: 28, len : 4, start: 156, type : 'uint:4', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: DSLP BDG of fixed voltage, rloc: 'EFUSE_RD_MAC_SYS_4_REG[31:28]', bloc: 'B19[7:4]'} + DSLP_LP_DBIAS : {show: y, blk : 1, word: 5, pos : 0, len : 5, start: 160, type : 'uint:5', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: DSLP LP DBIAS of fixed voltage, rloc: 'EFUSE_RD_MAC_SYS_5_REG[4:0]', bloc: 'B20[4:0]'} + LP_DCDC_DBIAS_VOL_GAP : {show: y, blk : 1, word: 5, pos : 5, len : 5, start: 165, type : 'uint:5', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: DBIAS gap between LP and DCDC, rloc: 'EFUSE_RD_MAC_SYS_5_REG[9:5]', bloc: 'B20[7:5],B21[1:0]'} + RESERVED_1_170 : {show: n, blk : 1, word: 5, pos: 10, len : 22, start: 170, type : 'uint:22', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: reserved, rloc: 'EFUSE_RD_MAC_SYS_5_REG[31:10]', bloc: 'B21[7:2],B22,B23'} OPTIONAL_UNIQUE_ID : {show: y, blk : 2, word: 0, pos : 0, len: 128, start : 0, type: 'bytes:16', wr_dis : 21, rd_dis: null, alt : '', dict : '', desc: Optional unique 128-bit ID, rloc: EFUSE_RD_SYS_PART1_DATA0_REG, bloc: 'B0,B1,B2,B3,B4,B5,B6,B7,B8,B9,B10,B11,B12,B13,B14,B15'} - SYS_DATA_PART1_4 : {show: n, blk : 2, word: 4, pos : 0, len : 32, start: 128, type : 'uint:32', wr_dis : 21, rd_dis: null, alt : '', dict : '', desc: Stores the fourth 32 bits of the first part of system data, rloc: EFUSE_RD_SYS_PART1_DATA4_REG, bloc: 'B16,B17,B18,B19'} - SYS_DATA_PART1_5 : {show: n, blk : 2, word: 5, pos : 0, len : 32, start: 160, type : 'uint:32', wr_dis : 21, rd_dis: null, alt : '', dict : '', desc: Stores the fifth 32 bits of the first part of system data, rloc: EFUSE_RD_SYS_PART1_DATA5_REG, bloc: 'B20,B21,B22,B23'} - SYS_DATA_PART1_6 : {show: n, blk : 2, word: 6, pos : 0, len : 32, start: 192, type : 'uint:32', wr_dis : 21, rd_dis: null, alt : '', dict : '', desc: Stores the sixth 32 bits of the first part of system data, rloc: EFUSE_RD_SYS_PART1_DATA6_REG, bloc: 'B24,B25,B26,B27'} - SYS_DATA_PART1_7 : {show: n, blk : 2, word: 7, pos : 0, len : 32, start: 224, type : 'uint:32', wr_dis : 21, rd_dis: null, alt : '', dict : '', desc: Stores the seventh 32 bits of the first part of system data, rloc: EFUSE_RD_SYS_PART1_DATA7_REG, bloc: 'B28,B29,B30,B31'} + ADC1_AVE_INITCODE_ATTEN0 : {show: y, blk : 2, word: 4, pos : 0, len : 10, start: 128, type : 'uint:10', wr_dis : 21, rd_dis: null, alt : '', dict : '', desc: Average initcode of ADC1 atten0, rloc: 'EFUSE_RD_SYS_PART1_DATA4_REG[9:0]', bloc: 'B16,B17[1:0]'} + ADC1_AVE_INITCODE_ATTEN1 : {show: y, blk : 2, word: 4, pos: 10, len : 10, start: 138, type : 'uint:10', wr_dis : 21, rd_dis: null, alt : '', dict : '', desc: Average initcode of ADC1 atten1, rloc: 'EFUSE_RD_SYS_PART1_DATA4_REG[19:10]', bloc: 'B17[7:2],B18[3:0]'} + ADC1_AVE_INITCODE_ATTEN2 : {show: y, blk : 2, word: 4, pos: 20, len : 10, start: 148, type : 'uint:10', wr_dis : 21, rd_dis: null, alt : '', dict : '', desc: Average initcode of ADC1 atten2, rloc: 'EFUSE_RD_SYS_PART1_DATA4_REG[29:20]', bloc: 'B18[7:4],B19[5:0]'} + ADC1_AVE_INITCODE_ATTEN3 : {show: y, blk : 2, word: 4, pos: 30, len : 10, start: 158, type : 'uint:10', wr_dis : 21, rd_dis: null, alt : '', dict : '', desc: Average initcode of ADC1 atten3, rloc: 'EFUSE_RD_SYS_PART1_DATA4_REG[31:30]', bloc: 'B19[7:6],B20'} + ADC2_AVE_INITCODE_ATTEN0 : {show: y, blk : 2, word: 5, pos : 8, len : 10, start: 168, type : 'uint:10', wr_dis : 21, rd_dis: null, alt : '', dict : '', desc: Average initcode of ADC2 atten0, rloc: 'EFUSE_RD_SYS_PART1_DATA5_REG[17:8]', bloc: 'B21,B22[1:0]'} + ADC2_AVE_INITCODE_ATTEN1 : {show: y, blk : 2, word: 5, pos: 18, len : 10, start: 178, type : 'uint:10', wr_dis : 21, rd_dis: null, alt : '', dict : '', desc: Average initcode of ADC2 atten1, rloc: 'EFUSE_RD_SYS_PART1_DATA5_REG[27:18]', bloc: 'B22[7:2],B23[3:0]'} + ADC2_AVE_INITCODE_ATTEN2 : {show: y, blk : 2, word: 5, pos: 28, len : 10, start: 188, type : 'uint:10', wr_dis : 21, rd_dis: null, alt : '', dict : '', desc: Average initcode of ADC2 atten2, rloc: 'EFUSE_RD_SYS_PART1_DATA5_REG[31:28]', bloc: 'B23[7:4],B24[5:0]'} + ADC2_AVE_INITCODE_ATTEN3 : {show: y, blk : 2, word: 6, pos : 6, len : 10, start: 198, type : 'uint:10', wr_dis : 21, rd_dis: null, alt : '', dict : '', desc: Average initcode of ADC2 atten3, rloc: 'EFUSE_RD_SYS_PART1_DATA6_REG[15:6]', bloc: 'B24[7:6],B25'} + ADC1_HI_DOUT_ATTEN0 : {show: y, blk : 2, word: 6, pos: 16, len : 10, start: 208, type : 'uint:10', wr_dis : 21, rd_dis: null, alt : '', dict : '', desc: HI_DOUT of ADC1 atten0, rloc: 'EFUSE_RD_SYS_PART1_DATA6_REG[25:16]', bloc: 'B26,B27[1:0]'} + ADC1_HI_DOUT_ATTEN1 : {show: y, blk : 2, word: 6, pos: 26, len : 10, start: 218, type : 'uint:10', wr_dis : 21, rd_dis: null, alt : '', dict : '', desc: HI_DOUT of ADC1 atten1, rloc: 'EFUSE_RD_SYS_PART1_DATA6_REG[31:26]', bloc: 'B27[7:2],B28[3:0]'} + ADC1_HI_DOUT_ATTEN2 : {show: y, blk : 2, word: 7, pos : 4, len : 10, start: 228, type : 'uint:10', wr_dis : 21, rd_dis: null, alt : '', dict : '', desc: HI_DOUT of ADC1 atten2, rloc: 'EFUSE_RD_SYS_PART1_DATA7_REG[13:4]', bloc: 'B28[7:4],B29[5:0]'} + ADC1_HI_DOUT_ATTEN3 : {show: y, blk : 2, word: 7, pos: 14, len : 10, start: 238, type : 'uint:10', wr_dis : 21, rd_dis: null, alt : '', dict : '', desc: HI_DOUT of ADC1 atten3, rloc: 'EFUSE_RD_SYS_PART1_DATA7_REG[23:14]', bloc: 'B29[7:6],B30'} + RESERVED_2_248 : {show: n, blk : 2, word: 7, pos: 24, len : 8, start: 248, type : 'uint:8', wr_dis : 21, rd_dis: null, alt : '', dict : '', desc: reserved, rloc: 'EFUSE_RD_SYS_PART1_DATA7_REG[31:24]', bloc: B31} BLOCK_USR_DATA : {show: y, blk : 3, word: 0, pos : 0, len: 192, start : 0, type: 'bytes:24', wr_dis : 22, rd_dis: null, alt : USER_DATA, dict : '', desc: User data, rloc: EFUSE_RD_USR_DATA0_REG, bloc: 'B0,B1,B2,B3,B4,B5,B6,B7,B8,B9,B10,B11,B12,B13,B14,B15,B16,B17,B18,B19,B20,B21,B22,B23'} RESERVED_3_192 : {show: n, blk : 3, word: 6, pos : 0, len : 8, start: 192, type : 'uint:8', wr_dis : 22, rd_dis: null, alt : '', dict : '', desc: reserved, rloc: 'EFUSE_RD_USR_DATA6_REG[7:0]', bloc: B24} CUSTOM_MAC : {show: y, blk : 3, word: 6, pos : 8, len : 48, start: 200, type : 'bytes:6', wr_dis : 22, rd_dis: null, alt: MAC_CUSTOM USER_DATA_MAC_CUSTOM, dict : '', desc: Custom MAC, rloc: 'EFUSE_RD_USR_DATA6_REG[31:8]', bloc: 'B25,B26,B27,B28,B29,B30'} @@ -103,4 +126,27 @@ EFUSES: BLOCK_KEY3 : {show: y, blk : 7, word: 0, pos : 0, len: 256, start : 0, type: 'bytes:32', wr_dis : 26, rd_dis : 3, alt : KEY3, dict : '', desc: Key3 or user data, rloc: EFUSE_RD_KEY3_DATA0_REG, bloc: 'B0,B1,B2,B3,B4,B5,B6,B7,B8,B9,B10,B11,B12,B13,B14,B15,B16,B17,B18,B19,B20,B21,B22,B23,B24,B25,B26,B27,B28,B29,B30,B31'} BLOCK_KEY4 : {show: y, blk : 8, word: 0, pos : 0, len: 256, start : 0, type: 'bytes:32', wr_dis : 27, rd_dis : 4, alt : KEY4, dict : '', desc: Key4 or user data, rloc: EFUSE_RD_KEY4_DATA0_REG, bloc: 'B0,B1,B2,B3,B4,B5,B6,B7,B8,B9,B10,B11,B12,B13,B14,B15,B16,B17,B18,B19,B20,B21,B22,B23,B24,B25,B26,B27,B28,B29,B30,B31'} BLOCK_KEY5 : {show: y, blk : 9, word: 0, pos : 0, len: 256, start : 0, type: 'bytes:32', wr_dis : 28, rd_dis : 5, alt : KEY5, dict : '', desc: Key5 or user data, rloc: EFUSE_RD_KEY5_DATA0_REG, bloc: 'B0,B1,B2,B3,B4,B5,B6,B7,B8,B9,B10,B11,B12,B13,B14,B15,B16,B17,B18,B19,B20,B21,B22,B23,B24,B25,B26,B27,B28,B29,B30,B31'} - BLOCK_SYS_DATA2 : {show: y, blk: 10, word: 0, pos : 0, len: 256, start : 0, type: 'bytes:32', wr_dis : 29, rd_dis : 6, alt : SYS_DATA_PART2, dict : '', desc: System data part 2 (reserved), rloc: EFUSE_RD_SYS_PART2_DATA0_REG, bloc: 'B0,B1,B2,B3,B4,B5,B6,B7,B8,B9,B10,B11,B12,B13,B14,B15,B16,B17,B18,B19,B20,B21,B22,B23,B24,B25,B26,B27,B28,B29,B30,B31'} + ADC2_HI_DOUT_ATTEN0 : {show: y, blk: 10, word: 0, pos : 0, len : 10, start : 0, type : 'uint:10', wr_dis : 29, rd_dis : 6, alt : '', dict : '', desc: HI_DOUT of ADC2 atten0, rloc: 'EFUSE_RD_SYS_PART2_DATA0_REG[9:0]', bloc: 'B0,B1[1:0]'} + ADC2_HI_DOUT_ATTEN1 : {show: y, blk: 10, word: 0, pos: 10, len : 10, start : 10, type : 'uint:10', wr_dis : 29, rd_dis : 6, alt : '', dict : '', desc: HI_DOUT of ADC2 atten1, rloc: 'EFUSE_RD_SYS_PART2_DATA0_REG[19:10]', bloc: 'B1[7:2],B2[3:0]'} + ADC2_HI_DOUT_ATTEN2 : {show: y, blk: 10, word: 0, pos: 20, len : 10, start : 20, type : 'uint:10', wr_dis : 29, rd_dis : 6, alt : '', dict : '', desc: HI_DOUT of ADC2 atten2, rloc: 'EFUSE_RD_SYS_PART2_DATA0_REG[29:20]', bloc: 'B2[7:4],B3[5:0]'} + ADC2_HI_DOUT_ATTEN3 : {show: y, blk: 10, word: 0, pos: 30, len : 10, start : 30, type : 'uint:10', wr_dis : 29, rd_dis : 6, alt : '', dict : '', desc: HI_DOUT of ADC2 atten3, rloc: 'EFUSE_RD_SYS_PART2_DATA0_REG[31:30]', bloc: 'B3[7:6],B4'} + ADC1_CH0_ATTEN0_INITCODE_DIFF : {show: y, blk: 10, word: 1, pos : 8, len : 4, start : 40, type : 'uint:4', wr_dis : 29, rd_dis : 6, alt : '', dict : '', desc: Gap between ADC1_ch0 and average initcode, rloc: 'EFUSE_RD_SYS_PART2_DATA1_REG[11:8]', bloc: 'B5[3:0]'} + ADC1_CH1_ATTEN0_INITCODE_DIFF : {show: y, blk: 10, word: 1, pos: 12, len : 4, start : 44, type : 'uint:4', wr_dis : 29, rd_dis : 6, alt : '', dict : '', desc: Gap between ADC1_ch1 and average initcode, rloc: 'EFUSE_RD_SYS_PART2_DATA1_REG[15:12]', bloc: 'B5[7:4]'} + ADC1_CH2_ATTEN0_INITCODE_DIFF : {show: y, blk: 10, word: 1, pos: 16, len : 4, start : 48, type : 'uint:4', wr_dis : 29, rd_dis : 6, alt : '', dict : '', desc: Gap between ADC1_ch2 and average initcode, rloc: 'EFUSE_RD_SYS_PART2_DATA1_REG[19:16]', bloc: 'B6[3:0]'} + ADC1_CH3_ATTEN0_INITCODE_DIFF : {show: y, blk: 10, word: 1, pos: 20, len : 4, start : 52, type : 'uint:4', wr_dis : 29, rd_dis : 6, alt : '', dict : '', desc: Gap between ADC1_ch3 and average initcode, rloc: 'EFUSE_RD_SYS_PART2_DATA1_REG[23:20]', bloc: 'B6[7:4]'} + ADC1_CH4_ATTEN0_INITCODE_DIFF : {show: y, blk: 10, word: 1, pos: 24, len : 4, start : 56, type : 'uint:4', wr_dis : 29, rd_dis : 6, alt : '', dict : '', desc: Gap between ADC1_ch4 and average initcode, rloc: 'EFUSE_RD_SYS_PART2_DATA1_REG[27:24]', bloc: 'B7[3:0]'} + ADC1_CH5_ATTEN0_INITCODE_DIFF : {show: y, blk: 10, word: 1, pos: 28, len : 4, start : 60, type : 'uint:4', wr_dis : 29, rd_dis : 6, alt : '', dict : '', desc: Gap between ADC1_ch5 and average initcode, rloc: 'EFUSE_RD_SYS_PART2_DATA1_REG[31:28]', bloc: 'B7[7:4]'} + ADC1_CH6_ATTEN0_INITCODE_DIFF : {show: y, blk: 10, word: 2, pos : 0, len : 4, start : 64, type : 'uint:4', wr_dis : 29, rd_dis : 6, alt : '', dict : '', desc: Gap between ADC1_ch6 and average initcode, rloc: 'EFUSE_RD_SYS_PART2_DATA2_REG[3:0]', bloc: 'B8[3:0]'} + ADC1_CH7_ATTEN0_INITCODE_DIFF : {show: y, blk: 10, word: 2, pos : 4, len : 4, start : 68, type : 'uint:4', wr_dis : 29, rd_dis : 6, alt : '', dict : '', desc: Gap between ADC1_ch7 and average initcode, rloc: 'EFUSE_RD_SYS_PART2_DATA2_REG[7:4]', bloc: 'B8[7:4]'} + ADC2_CH0_ATTEN0_INITCODE_DIFF : {show: y, blk: 10, word: 2, pos : 8, len : 4, start : 72, type : 'uint:4', wr_dis : 29, rd_dis : 6, alt : '', dict : '', desc: Gap between ADC2_ch0 and average initcode, rloc: 'EFUSE_RD_SYS_PART2_DATA2_REG[11:8]', bloc: 'B9[3:0]'} + ADC2_CH1_ATTEN0_INITCODE_DIFF : {show: y, blk: 10, word: 2, pos: 12, len : 4, start : 76, type : 'uint:4', wr_dis : 29, rd_dis : 6, alt : '', dict : '', desc: Gap between ADC2_ch1 and average initcode, rloc: 'EFUSE_RD_SYS_PART2_DATA2_REG[15:12]', bloc: 'B9[7:4]'} + ADC2_CH2_ATTEN0_INITCODE_DIFF : {show: y, blk: 10, word: 2, pos: 16, len : 4, start : 80, type : 'uint:4', wr_dis : 29, rd_dis : 6, alt : '', dict : '', desc: Gap between ADC2_ch2 and average initcode, rloc: 'EFUSE_RD_SYS_PART2_DATA2_REG[19:16]', bloc: 'B10[3:0]'} + ADC2_CH3_ATTEN0_INITCODE_DIFF : {show: y, blk: 10, word: 2, pos: 20, len : 4, start : 84, type : 'uint:4', wr_dis : 29, rd_dis : 6, alt : '', dict : '', desc: Gap between ADC2_ch3 and average initcode, rloc: 'EFUSE_RD_SYS_PART2_DATA2_REG[23:20]', bloc: 'B10[7:4]'} + ADC2_CH4_ATTEN0_INITCODE_DIFF : {show: y, blk: 10, word: 2, pos: 24, len : 4, start : 88, type : 'uint:4', wr_dis : 29, rd_dis : 6, alt : '', dict : '', desc: Gap between ADC2_ch4 and average initcode, rloc: 'EFUSE_RD_SYS_PART2_DATA2_REG[27:24]', bloc: 'B11[3:0]'} + ADC2_CH5_ATTEN0_INITCODE_DIFF : {show: y, blk: 10, word: 2, pos: 28, len : 4, start : 92, type : 'uint:4', wr_dis : 29, rd_dis : 6, alt : '', dict : '', desc: Gap between ADC2_ch5 and average initcode, rloc: 'EFUSE_RD_SYS_PART2_DATA2_REG[31:28]', bloc: 'B11[7:4]'} + TEMPERATURE_SENSOR : {show: y, blk: 10, word: 3, pos : 0, len : 9, start : 96, type : 'uint:9', wr_dis : 29, rd_dis : 6, alt : '', dict : '', desc: Temperature calibration data, rloc: 'EFUSE_RD_SYS_PART2_DATA3_REG[8:0]', bloc: 'B12,B13[0]'} + RESERVED_10_105 : {show: n, blk: 10, word: 3, pos : 9, len : 23, start: 105, type : 'uint:23', wr_dis : 29, rd_dis : 6, alt : '', dict : '', desc: reserved, rloc: 'EFUSE_RD_SYS_PART2_DATA3_REG[31:9]', bloc: 'B13[7:1],B14,B15'} + SYS_DATA_PART2_4 : {show: n, blk: 10, word: 4, pos : 0, len : 32, start: 128, type : 'uint:32', wr_dis : 29, rd_dis : 6, alt : '', dict : '', desc: Stores the $nth 32 bits of the 2nd part of system data, rloc: EFUSE_RD_SYS_PART2_DATA4_REG, bloc: 'B16,B17,B18,B19'} + SYS_DATA_PART2_5 : {show: n, blk: 10, word: 5, pos : 0, len : 32, start: 160, type : 'uint:32', wr_dis : 29, rd_dis : 6, alt : '', dict : '', desc: Stores the $nth 32 bits of the 2nd part of system data, rloc: EFUSE_RD_SYS_PART2_DATA5_REG, bloc: 'B20,B21,B22,B23'} + SYS_DATA_PART2_6 : {show: n, blk: 10, word: 6, pos : 0, len : 32, start: 192, type : 'uint:32', wr_dis : 29, rd_dis : 6, alt : '', dict : '', desc: Stores the $nth 32 bits of the 2nd part of system data, rloc: EFUSE_RD_SYS_PART2_DATA6_REG, bloc: 'B24,B25,B26,B27'} + SYS_DATA_PART2_7 : {show: n, blk: 10, word: 7, pos : 0, len : 32, start: 224, type : 'uint:32', wr_dis : 29, rd_dis : 6, alt : '', dict : '', desc: Stores the $nth 32 bits of the 2nd part of system data, rloc: EFUSE_RD_SYS_PART2_DATA7_REG, bloc: 'B28,B29,B30,B31'} diff --git a/tools/esptool_py/espefuse/efuse_defs/esp32s3.yaml b/tools/esptool_py/espefuse/efuse_defs/esp32s3.yaml index 4d4c69511d..dcafa868f4 100644 --- a/tools/esptool_py/espefuse/efuse_defs/esp32s3.yaml +++ b/tools/esptool_py/espefuse/efuse_defs/esp32s3.yaml @@ -1,4 +1,4 @@ -VER_NO: f75f74727101326a187188a23f4a6c70 +VER_NO: 7127dd097e72bb90d0b790d460993126 EFUSES: WR_DIS : {show: y, blk : 0, word: 0, pos : 0, len : 32, start : 0, type : 'uint:32', wr_dis: null, rd_dis: null, alt : '', dict : '', desc: Disable programming of individual eFuses, rloc: EFUSE_RD_WR_DIS_REG, bloc: 'B0,B1,B2,B3'} RD_DIS : {show: y, blk : 0, word: 1, pos : 0, len : 7, start : 32, type : 'uint:7', wr_dis : 0, rd_dis: null, alt : '', dict : '', desc: Disable reading from BlOCK4-10, rloc: 'EFUSE_RD_REPEAT_DATA0_REG[6:0]', bloc: 'B4[6:0]'} @@ -47,7 +47,7 @@ EFUSES: SECURE_BOOT_AGGRESSIVE_REVOKE : {show: y, blk : 0, word: 3, pos: 21, len : 1, start: 117, type : bool, wr_dis : 16, rd_dis: null, alt : '', dict : '', desc: Set this bit to enable revoking aggressive secure boot, rloc: 'EFUSE_RD_REPEAT_DATA2_REG[21]', bloc: 'B14[5]'} DIS_USB_JTAG : {show: y, blk : 0, word: 3, pos: 22, len : 1, start: 118, type : bool, wr_dis : 2, rd_dis: null, alt : '', dict : '', desc: Set this bit to disable function of usb switch to jtag in module of usb device, rloc: 'EFUSE_RD_REPEAT_DATA2_REG[22]', bloc: 'B14[6]'} DIS_USB_SERIAL_JTAG : {show: y, blk : 0, word: 3, pos: 23, len : 1, start: 119, type : bool, wr_dis : 2, rd_dis: null, alt : DIS_USB_DEVICE, dict : '', desc: Set this bit to disable usb device, rloc: 'EFUSE_RD_REPEAT_DATA2_REG[23]', bloc: 'B14[7]'} - STRAP_JTAG_SEL : {show: y, blk : 0, word: 3, pos: 24, len : 1, start: 120, type : bool, wr_dis : 2, rd_dis: null, alt : '', dict : '', desc: Set this bit to enable selection between usb_to_jtag and pad_to_jtag through strapping gpio10 when both reg_dis_usb_jtag and reg_dis_pad_jtag are equal to 0, rloc: 'EFUSE_RD_REPEAT_DATA2_REG[24]', bloc: 'B15[0]'} + STRAP_JTAG_SEL : {show: y, blk : 0, word: 3, pos: 24, len : 1, start: 120, type : bool, wr_dis : 2, rd_dis: null, alt : '', dict : '', desc: Set this bit to enable selection between usb_to_jtag and pad_to_jtag through strapping gpio3 when both reg_dis_usb_jtag and reg_dis_pad_jtag are equal to 0, rloc: 'EFUSE_RD_REPEAT_DATA2_REG[24]', bloc: 'B15[0]'} USB_PHY_SEL : {show: y, blk : 0, word: 3, pos: 25, len : 1, start: 121, type : bool, wr_dis : 2, rd_dis: null, alt : '', dict: '{0: "internal PHY is assigned to USB Device while external PHY is assigned to USB OTG", 1: "internal PHY is assigned to USB OTG while external PHY is assigned to USB Device"}', desc: This bit is used to switch internal PHY and external PHY for USB OTG and USB Device, rloc: 'EFUSE_RD_REPEAT_DATA2_REG[25]', bloc: 'B15[1]'} POWER_GLITCH_DSENSE : {show: n, blk : 0, word: 3, pos: 26, len : 2, start: 122, type : 'uint:2', wr_dis : 17, rd_dis: null, alt : '', dict : '', desc: Sample delay configuration of power glitch, rloc: 'EFUSE_RD_REPEAT_DATA2_REG[27:26]', bloc: 'B15[3:2]'} FLASH_TPUW : {show: y, blk : 0, word: 3, pos: 28, len : 4, start: 124, type : 'uint:4', wr_dis : 18, rd_dis: null, alt : '', dict : '', desc: Configures flash waiting time after power-up; in unit of ms. If the value is less than 15; the waiting time is the configurable value. Otherwise; the waiting time is twice the configurable value, rloc: 'EFUSE_RD_REPEAT_DATA2_REG[31:28]', bloc: 'B15[7:4]'} @@ -87,7 +87,7 @@ EFUSES: FLASH_CAP : {show: y, blk : 1, word: 3, pos: 27, len : 3, start: 123, type : 'uint:3', wr_dis : 20, rd_dis: null, alt : '', dict: '{0: "None", 1: "8M", 2: "4M"}', desc: Flash capacity, rloc: 'EFUSE_RD_MAC_SPI_SYS_3_REG[29:27]', bloc: 'B15[5:3]'} FLASH_TEMP : {show: y, blk : 1, word: 3, pos: 30, len : 2, start: 126, type : 'uint:2', wr_dis : 20, rd_dis: null, alt : '', dict: '{0: "None", 1: "105C", 2: "85C"}', desc: Flash temperature, rloc: 'EFUSE_RD_MAC_SPI_SYS_3_REG[31:30]', bloc: 'B15[7:6]'} FLASH_VENDOR : {show: y, blk : 1, word: 4, pos : 0, len : 3, start: 128, type : 'uint:3', wr_dis : 20, rd_dis: null, alt : '', dict: '{0: "None", 1: "XMC", 2: "GD", 3: "FM", 4: "TT", 5: "BY"}', desc: Flash vendor, rloc: 'EFUSE_RD_MAC_SPI_SYS_4_REG[2:0]', bloc: 'B16[2:0]'} - PSRAM_CAP : {show: y, blk : 1, word: 4, pos : 3, len : 2, start: 131, type : 'uint:2', wr_dis : 20, rd_dis: null, alt : '', dict: '{0: "None", 1: "8M", 2: "2M"}', desc: PSRAM capacity, rloc: 'EFUSE_RD_MAC_SPI_SYS_4_REG[4:3]', bloc: 'B16[4:3]'} + PSRAM_CAP : {show: y, blk : 1, word: 4, pos : 3, len : 2, start: 131, type : 'uint:2', wr_dis : 20, rd_dis: null, alt : '', dict: '{0: "None", 1: "8M", 2: "2M", 3: "16M", 4: "4M"}', desc: PSRAM capacity, rloc: 'EFUSE_RD_MAC_SPI_SYS_4_REG[4:3]', bloc: 'B16[4:3]'} PSRAM_TEMP : {show: y, blk : 1, word: 4, pos : 5, len : 2, start: 133, type : 'uint:2', wr_dis : 20, rd_dis: null, alt : '', dict: '{0: "None", 1: "105C", 2: "85C"}', desc: PSRAM temperature, rloc: 'EFUSE_RD_MAC_SPI_SYS_4_REG[6:5]', bloc: 'B16[6:5]'} PSRAM_VENDOR : {show: y, blk : 1, word: 4, pos : 7, len : 2, start: 135, type : 'uint:2', wr_dis : 20, rd_dis: null, alt : '', dict: '{0: "None", 1: "AP_3v3", 2: "AP_1v8"}', desc: PSRAM vendor, rloc: 'EFUSE_RD_MAC_SPI_SYS_4_REG[8:7]', bloc: 'B16[7],B17[0]'} RESERVED_1_137 : {show: n, blk : 1, word: 4, pos : 9, len : 4, start: 137, type : 'uint:4', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: reserved, rloc: 'EFUSE_RD_MAC_SPI_SYS_4_REG[12:9]', bloc: 'B17[4:1]'} @@ -96,7 +96,9 @@ EFUSES: V_RTC_DBIAS20 : {show: y, blk : 1, word: 4, pos: 27, len : 8, start: 155, type : 'uint:8', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: BLOCK1 voltage of rtc dbias20, rloc: 'EFUSE_RD_MAC_SPI_SYS_4_REG[31:27]', bloc: 'B19[7:3],B20[2:0]'} V_DIG_DBIAS20 : {show: y, blk : 1, word: 5, pos : 3, len : 8, start: 163, type : 'uint:8', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: BLOCK1 voltage of digital dbias20, rloc: 'EFUSE_RD_MAC_SPI_SYS_5_REG[10:3]', bloc: 'B20[7:3],B21[2:0]'} DIG_DBIAS_HVT : {show: y, blk : 1, word: 5, pos: 11, len : 5, start: 171, type : 'uint:5', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: BLOCK1 digital dbias when hvt, rloc: 'EFUSE_RD_MAC_SPI_SYS_5_REG[15:11]', bloc: 'B21[7:3]'} - RESERVED_1_176 : {show: n, blk : 1, word: 5, pos: 16, len : 7, start: 176, type : 'uint:7', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: reserved, rloc: 'EFUSE_RD_MAC_SPI_SYS_5_REG[22:16]', bloc: 'B22[6:0]'} + RESERVED_1_176 : {show: n, blk : 1, word: 5, pos: 16, len : 3, start: 176, type : 'uint:3', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: reserved, rloc: 'EFUSE_RD_MAC_SPI_SYS_5_REG[18:16]', bloc: 'B22[2:0]'} + PSRAM_CAP_3 : {show: y, blk : 1, word: 5, pos: 19, len : 1, start: 179, type : bool, wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: PSRAM capacity bit 3, rloc: 'EFUSE_RD_MAC_SPI_SYS_5_REG[19]', bloc: 'B22[3]'} + RESERVED_1_180 : {show: n, blk : 1, word: 5, pos: 20, len : 3, start: 180, type : 'uint:3', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: reserved, rloc: 'EFUSE_RD_MAC_SPI_SYS_5_REG[22:20]', bloc: 'B22[6:4]'} WAFER_VERSION_MINOR_HI : {show: y, blk : 1, word: 5, pos: 23, len : 1, start: 183, type : bool, wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: WAFER_VERSION_MINOR most significant bit, rloc: 'EFUSE_RD_MAC_SPI_SYS_5_REG[23]', bloc: 'B22[7]'} WAFER_VERSION_MAJOR : {show: y, blk : 1, word: 5, pos: 24, len : 2, start: 184, type : 'uint:2', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: WAFER_VERSION_MAJOR, rloc: 'EFUSE_RD_MAC_SPI_SYS_5_REG[25:24]', bloc: 'B23[1:0]'} ADC2_CAL_VOL_ATTEN3 : {show: y, blk : 1, word: 5, pos: 26, len : 6, start: 186, type : 'uint:6', wr_dis : 20, rd_dis: null, alt : '', dict : '', desc: ADC2 calibration voltage at atten3, rloc: 'EFUSE_RD_MAC_SPI_SYS_5_REG[31:26]', bloc: 'B23[7:2]'} diff --git a/tools/esptool_py/espefuse/efuse_interface.py b/tools/esptool_py/espefuse/efuse_interface.py new file mode 100644 index 0000000000..b496796e11 --- /dev/null +++ b/tools/esptool_py/espefuse/efuse_interface.py @@ -0,0 +1,197 @@ +# SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD +# +# SPDX-License-Identifier: GPL-2.0-or-later + +from dataclasses import dataclass +from io import StringIO +from typing import Any + +from espefuse.efuse.base_operations import BaseCommands +from espefuse.efuse.emulate_efuse_controller_base import EmulateEfuseControllerBase +import esptool +from esptool.util import strip_chip_name + +import espefuse.efuse.esp32 as esp32_efuse +import espefuse.efuse.esp32c2 as esp32c2_efuse +import espefuse.efuse.esp32c3 as esp32c3_efuse +import espefuse.efuse.esp32c5 as esp32c5_efuse +import espefuse.efuse.esp32c6 as esp32c6_efuse +import espefuse.efuse.esp32c61 as esp32c61_efuse +import espefuse.efuse.esp32h2 as esp32h2_efuse +import espefuse.efuse.esp32h21 as esp32h21_efuse +import espefuse.efuse.esp32h4 as esp32h4_efuse +import espefuse.efuse.esp32p4 as esp32p4_efuse +import espefuse.efuse.esp32s2 as esp32s2_efuse +import espefuse.efuse.esp32s3 as esp32s3_efuse + + +@dataclass +class DefChip: + efuse_lib: Any + chip_class: type[esptool.ESPLoader] + + +SUPPORTED_BURN_COMMANDS = [ + "read-protect-efuse", + "write-protect-efuse", + "burn-efuse", + "burn-block-data", + "burn-bit", + "burn-key", + "burn-key-digest", + "burn-custom-mac", + "set-flash-voltage", +] + +SUPPORTED_READ_COMMANDS = [ + "summary", + "dump", + "get-custom-mac", + "adc-info", + "check-error", +] + +DEPRECATED_COMMANDS = ["execute-scripts"] + +SUPPORTED_COMMANDS = ( + SUPPORTED_READ_COMMANDS + SUPPORTED_BURN_COMMANDS + DEPRECATED_COMMANDS +) + +SUPPORTED_CHIPS = { + "esp32": DefChip(esp32_efuse, esptool.targets.ESP32ROM), + "esp32c2": DefChip(esp32c2_efuse, esptool.targets.ESP32C2ROM), + "esp32c3": DefChip(esp32c3_efuse, esptool.targets.ESP32C3ROM), + "esp32c6": DefChip(esp32c6_efuse, esptool.targets.ESP32C6ROM), + "esp32c61": DefChip(esp32c61_efuse, esptool.targets.ESP32C61ROM), + "esp32c5": DefChip(esp32c5_efuse, esptool.targets.ESP32C5ROM), + "esp32h2": DefChip(esp32h2_efuse, esptool.targets.ESP32H2ROM), + "esp32h21": DefChip(esp32h21_efuse, esptool.targets.ESP32H21ROM), + "esp32h4": DefChip(esp32h4_efuse, esptool.targets.ESP32H4ROM), + "esp32p4": DefChip(esp32p4_efuse, esptool.targets.ESP32P4ROM), + "esp32s2": DefChip(esp32s2_efuse, esptool.targets.ESP32S2ROM), + "esp32s3": DefChip(esp32s3_efuse, esptool.targets.ESP32S3ROM), +} + + +def _get_command_class(chip_name: str) -> BaseCommands: + return SUPPORTED_CHIPS[chip_name].efuse_lib.commands() # type: ignore + + +def init_commands( + port: str | None = None, + baud: int = 115200, + before: str = "default-reset", + chip: str = "auto", + esp: esptool.ESPLoader | EmulateEfuseControllerBase | None = None, + **kwargs: Any, +) -> BaseCommands: + """Get the ESP eFuse commands class for the given chip + This function will establish a connection to the chip and + return the ESP eFuse commands class with initialized chip + and eFuse values. + + Either esp or port should be provided. If both are provided, esp will be used. + If neither is provided, the function will create a mock ESPLoader object for tests. + + Args: + port: The port to connect to the chip + baud: The baud rate to connect to the chip + before: The reset mode to use before connecting to the chip + chip: The chip to use. + esp: Optional ESPLoader object to use. If provided, the port, baud, before, and + chip arguments will be ignored. If provided, user has to take care of + closing the port. + + Keyword Args: + skip_connect (bool): Whether to skip connecting to the chip. Default is False. + virt (bool): Whether to use virtual mode. Default is False. + debug (bool): Whether to enable debug mode. Default is False. + virt_efuse_file (str): The file to save the eFuse values to. Default is None. + do_not_confirm (bool): Whether to skip confirmation before burning eFuse. + Default is False. + extend_efuse_table (str): The file to extend the eFuse table from. + Default is None. + batch_mode (bool): Whether to enable batch mode. Default is False. + + Returns: + The ESP eFuse commands class + """ + skip_connect = kwargs.get("skip_connect", False) + virt = kwargs.get("virt", False) + debug = kwargs.get("debug", False) + virt_efuse_file = kwargs.get("virt_efuse_file", None) + do_not_confirm = kwargs.get("do_not_confirm", False) + extend_efuse_table = kwargs.get("extend_efuse_table", None) + external_esp = esp is not None + batch_mode = kwargs.get("batch_mode", False) + + if esp is None: + esp = get_esp( + port, baud, before, chip, skip_connect, virt, debug, virt_efuse_file + ) + + commands = _get_command_class(strip_chip_name(esp.CHIP_NAME)) + commands.esp = esp + commands.external_esp = external_esp + commands.get_efuses( + skip_connect=skip_connect, + debug_mode=debug, + do_not_confirm=do_not_confirm, + extend_efuse_table=extend_efuse_table, + ) + if batch_mode: + commands.use_batch_mode() + return commands + + +def get_esp( + port: str | None = None, + baud: int = 115200, + before: str = "default-reset", + chip: str = "auto", + skip_connect: bool = False, + virt: bool = False, + debug: bool = False, + virt_efuse_file: str | None = None, +) -> esptool.ESPLoader | EmulateEfuseControllerBase: + """Get the ESPLoader object for the given chip. + Uses :func:`esptool.cmds.detect_chip` function. + + Args: + port: The port to connect to the chip + baud: The baud rate to connect to the chip + before: The reset mode to use before connecting to the chip + Supported values are: "default-reset", "usb-reset", "no-reset", + "no-reset-no-sync" + chip: The chip to use + skip_connect: Whether to skip connecting to the chip + virt: Whether to use virtual mode + debug: Whether to enable debug mode + virt_efuse_file: The file to save the eFuse values to + + Returns: + The ESPLoader object or EmulateEfuseController object + """ + if chip not in ["auto"] + list(SUPPORTED_CHIPS.keys()): + raise esptool.FatalError(f"get_esp: Unsupported chip ({chip})") + + if virt: + efuse = SUPPORTED_CHIPS.get(chip, SUPPORTED_CHIPS["esp32"]).efuse_lib + return efuse.EmulateEfuseController(virt_efuse_file, debug) # type: ignore + + if chip == "auto" and not skip_connect: + if port is None: + raise esptool.FatalError( + "get_esp: Port is required when chip is 'auto' to detect the chip" + ) + return esptool.detect_chip(port, baud, before) + + esp = SUPPORTED_CHIPS.get(chip, SUPPORTED_CHIPS["esp32"]).chip_class( + port if not skip_connect else StringIO(), # type: ignore + baud, + ) + if not skip_connect: + esp.connect(before) + if esp.sync_stub_detected: + esp = esp.STUB_CLASS(esp) # type: ignore + return esp diff --git a/tools/esptool_py/espsecure/__init__.py b/tools/esptool_py/espsecure/__init__.py index 81688c104d..2906124b01 100755 --- a/tools/esptool_py/espsecure/__init__.py +++ b/tools/esptool_py/espsecure/__init__.py @@ -1,8 +1,9 @@ -# SPDX-FileCopyrightText: 2016-2023 Espressif Systems (Shanghai) CO LTD +# SPDX-FileCopyrightText: 2016-2025 Espressif Systems (Shanghai) CO LTD # # SPDX-License-Identifier: GPL-2.0-or-later -# PYTHON_ARGCOMPLETE_OK -import argparse +import configparser +from dataclasses import dataclass +import rich_click as click import hashlib import operator import os @@ -10,8 +11,7 @@ import sys import tempfile import zlib -from collections import namedtuple -from io import IOBase +from typing import IO from cryptography import exceptions from cryptography.hazmat.backends import default_backend @@ -21,9 +21,10 @@ from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes from cryptography.utils import int_to_bytes -import ecdsa +from esptool.logger import log import esptool +from esptool.util import check_deprecated_py_suffix SIG_BLOCK_MAGIC = 0xE7 @@ -46,26 +47,28 @@ ) -def get_chunks(source, chunk_len): +def get_chunks(source: bytes, chunk_len: int): """Returns an iterator over 'chunk_len' chunks of 'source'""" return (source[i : i + chunk_len] for i in range(0, len(source), chunk_len)) -def endian_swap_words(source): +def endian_swap_words(source: bytes) -> bytes: """Endian-swap each word in 'source' bitstring""" assert len(source) % 4 == 0 words = "I" * (len(source) // 4) return struct.pack("<" + words, *struct.unpack(">" + words, source)) -def swap_word_order(source): +def swap_word_order(source: bytes) -> bytes: """Swap the order of the words in 'source' bitstring""" assert len(source) % 4 == 0 words = "I" * (len(source) // 4) return struct.pack(words, *reversed(struct.unpack(words, source))) -def _load_hardware_key(keyfile): +def _load_hardware_key( + keyfile: IO, is_flash_encryption_key: bool, aes_xts: bool = False +): """Load a 128/256/512-bit key, similar to stored in efuse, from a file 128-bit keys will be extended to 256-bit using the SHA256 of the key @@ -75,41 +78,56 @@ def _load_hardware_key(keyfile): key = keyfile.read() if len(key) not in [16, 24, 32, 64]: raise esptool.FatalError( - "Key file contains wrong length (%d bytes), 16, 24, 32 or 64 expected." - % len(key) + f"Key file contains wrong length ({len(key)} bytes), " + "16, 24, 32 or 64 expected." ) + if is_flash_encryption_key: + if aes_xts: + if len(key) not in [16, 32, 64]: + raise esptool.FatalError( + "AES_XTS supports only 128, 256, and 512-bit keys. " + f"Provided key is {len(key) * 8} bits." + ) + else: + if len(key) not in [24, 32]: + raise esptool.FatalError( + "ESP32 supports only 192 and 256-bit keys. Provided key is " + f"{len(key) * 8} bits. Use --aes_xts for other chips." + ) if len(key) == 16: key = _sha256_digest(key) - print("Using 128-bit key (extended)") + log.print("Using 128-bit key (extended).") elif len(key) == 24: key = key + key[8:16] assert len(key) == 32 - print("Using 192-bit key (extended)") + log.print("Using 192-bit key (extended).") elif len(key) == 32: - print("Using 256-bit key") + log.print("Using 256-bit key.") else: - print("Using 512-bit key") + log.print("Using 512-bit key.") return key -def digest_secure_bootloader(args): +def digest_secure_bootloader( + keyfile: IO, output: str | None, iv_file: IO | None, image: IO +): """Calculate the digest of a bootloader image, in the same way the hardware secure boot engine would do so. Can be used with a pre-loaded key to update a secure bootloader.""" - _check_output_is_not_input(args.keyfile, args.output) - _check_output_is_not_input(args.image, args.output) - _check_output_is_not_input(args.iv, args.output) - if args.iv is not None: - print("WARNING: --iv argument is for TESTING PURPOSES ONLY") - iv = args.iv.read(128) + _check_output_is_not_input(keyfile, output) + _check_output_is_not_input(image, output) + _check_output_is_not_input(iv_file, output) + if iv_file is not None: + log.warning("--iv argument is for TESTING PURPOSES ONLY") + iv = iv_file.read(128) else: iv = os.urandom(128) - plaintext_image = args.image.read() - args.image.seek(0) + plaintext_image = image.read() + image.seek(0) # secure boot engine reads in 128 byte blocks (ie SHA512 block # size), but also doesn't look for any appended SHA-256 digest - fw_image = esptool.bin_image.ESP32FirmwareImage(args.image) + fw_image = esptool.bin_image.ESP32FirmwareImage(image) if fw_image.append_digest: if len(plaintext_image) % 128 <= 32: # ROM bootloader will read to the end of the 128 byte block, but not @@ -120,7 +138,7 @@ def digest_secure_bootloader(args): # if image isn't 128 byte multiple then pad with 0xFF (ie unwritten flash) # as this is what the secure boot engine will see if len(plaintext_image) % 128 != 0: - plaintext_image += b"\xFF" * (128 - (len(plaintext_image) % 128)) + plaintext_image += b"\xff" * (128 - (len(plaintext_image) % 128)) plaintext = iv + plaintext_image @@ -129,7 +147,7 @@ def digest_secure_bootloader(args): # produce the digest. Each block in/out of ECB is reordered # (due to hardware quirks not for security.) - key = _load_hardware_key(args.keyfile) + key = _load_hardware_key(keyfile, False) backend = default_backend() cipher = Cipher(algorithms.AES(key), modes.ECB(), backend=backend) encryptor = cipher.encryptor() @@ -145,38 +163,49 @@ def digest_secure_bootloader(args): # Python hashlib can build each SHA block internally digest.update(block[::-1]) - if args.output is None: - args.output = os.path.splitext(args.image.name)[0] + "-digest-0x0000.bin" - with open(args.output, "wb") as f: + if output is None: + output = os.path.splitext(image.name)[0] + "-digest-0x0000.bin" + with open(output, "wb") as f: f.write(iv) - digest = digest.digest() - for word in get_chunks(digest, 4): + for word in get_chunks(digest.digest(), 4): f.write(word[::-1]) # swap word order in the result - f.write(b"\xFF" * (0x1000 - f.tell())) # pad to 0x1000 + f.write(b"\xff" * (0x1000 - f.tell())) # pad to 0x1000 f.write(plaintext_image) - print("digest+image written to %s" % args.output) + log.print(f'Digest + image written to "{output}"') + + +def _generate_ecdsa_signing_key(curve_id: ec.EllipticCurve, keyfile: str): + if curve_id not in [ec.SECP192R1, ec.SECP256R1, ec.SECP384R1]: + raise ValueError( + f"Unsupported curve: {curve_id}, " + "only NIST192p, NIST256p, NIST384p are supported." + ) + private_key = ec.generate_private_key(curve_id()) + pem = private_key.private_bytes( + encoding=serialization.Encoding.PEM, + format=serialization.PrivateFormat.TraditionalOpenSSL, + encryption_algorithm=serialization.NoEncryption(), + ) -def _generate_ecdsa_signing_key(curve_id, keyfile): - sk = ecdsa.SigningKey.generate(curve=curve_id) with open(keyfile, "wb") as f: - f.write(sk.to_pem()) + f.write(pem) -def generate_signing_key(args): - if os.path.exists(args.keyfile): - raise esptool.FatalError("ERROR: Key file %s already exists" % args.keyfile) - if args.version == "1": - if hasattr(args, "scheme"): - if args.scheme != "ecdsa256" and args.scheme is not None: - raise esptool.FatalError("ERROR: V1 only supports ECDSA256") +def generate_signing_key(version: int, scheme: str | None, keyfile: str): + if os.path.exists(keyfile): + raise esptool.FatalError(f"ERROR: Key file {keyfile} already exists.") + if version == "1": + if scheme is not None: + if scheme != "ecdsa256" and scheme is not None: + raise esptool.FatalError("ERROR: V1 only supports ECDSA256.") """ Generate an ECDSA signing key for signing secure boot images (post-bootloader) """ - _generate_ecdsa_signing_key(ecdsa.NIST256p, args.keyfile) - print("ECDSA NIST256p private key in PEM format written to %s" % args.keyfile) - elif args.version == "2": - if args.scheme == "rsa3072" or args.scheme is None: + _generate_ecdsa_signing_key(ec.SECP256R1, keyfile) + log.print(f'ECDSA NIST256p private key in PEM format written to "{keyfile}".') + elif version == "2": + if scheme == "rsa3072" or scheme is None: """Generate a RSA 3072 signing key for signing secure boot images""" private_key = rsa.generate_private_key( public_exponent=65537, key_size=3072, backend=default_backend() @@ -185,68 +214,80 @@ def generate_signing_key(args): format=serialization.PrivateFormat.TraditionalOpenSSL, encryption_algorithm=serialization.NoEncryption(), ) - with open(args.keyfile, "wb") as f: + with open(keyfile, "wb") as f: f.write(private_key) - print(f"RSA 3072 private key in PEM format written to {args.keyfile}") - elif args.scheme == "ecdsa192": + log.print(f'RSA 3072 private key in PEM format written to "{keyfile}".') + elif scheme == "ecdsa192": """Generate a ECDSA 192 signing key for signing secure boot images""" - _generate_ecdsa_signing_key(ecdsa.NIST192p, args.keyfile) - print(f"ECDSA NIST192p private key in PEM format written to {args.keyfile}") - elif args.scheme == "ecdsa256": + _generate_ecdsa_signing_key(ec.SECP192R1, keyfile) + log.print( + f'ECDSA NIST192p private key in PEM format written to "{keyfile}".' + ) + elif scheme == "ecdsa256": """Generate a ECDSA 256 signing key for signing secure boot images""" - _generate_ecdsa_signing_key(ecdsa.NIST256p, args.keyfile) - print(f"ECDSA NIST256p private key in PEM format written to {args.keyfile}") - elif args.scheme == "ecdsa384": + _generate_ecdsa_signing_key(ec.SECP256R1, keyfile) + log.print( + f'ECDSA NIST256p private key in PEM format written to "{keyfile}".' + ) + elif scheme == "ecdsa384": """Generate a ECDSA 384 signing key for signing secure boot images""" - _generate_ecdsa_signing_key(ecdsa.NIST384p, args.keyfile) - print(f"ECDSA NIST384p private key in PEM format written to {args.keyfile}") + _generate_ecdsa_signing_key(ec.SECP384R1, keyfile) + log.print( + f'ECDSA NIST384p private key in PEM format written to "{keyfile}".' + ) else: - raise esptool.FatalError("ERROR: Unsupported signing scheme {args.scheme}") + raise esptool.FatalError(f"ERROR: Unsupported signing scheme {scheme}.") -def load_ecdsa_signing_key(keyfile): +def load_ecdsa_signing_key(keyfile: IO) -> ec.EllipticCurvePrivateKey: """Load ECDSA signing key""" try: - sk = ecdsa.SigningKey.from_pem(keyfile.read()) + sk = serialization.load_pem_private_key( + keyfile.read(), password=None, backend=default_backend() + ) except ValueError: raise esptool.FatalError( "Incorrect ECDSA private key specified. " "Please check algorithm and/or format." ) - if sk.curve not in [ecdsa.NIST192p, ecdsa.NIST256p]: - raise esptool.FatalError("Supports NIST192p and NIST256p keys only") + if not isinstance(sk.curve, (ec.SECP192R1, ec.SECP256R1)): + raise esptool.FatalError("Supports NIST192p and NIST256p keys only.") return sk -def _load_ecdsa_signing_key(keyfile): +def _load_ecdsa_signing_key(keyfile: IO) -> ec.EllipticCurvePrivateKey: """Load ECDSA signing key for Secure Boot V1 only""" sk = load_ecdsa_signing_key(keyfile) - if sk.curve != ecdsa.NIST256p: + if not isinstance(sk.curve, ec.SECP256R1): raise esptool.FatalError( "Signing key uses incorrect curve. ESP32 Secure Boot only supports " - "NIST256p (openssl calls this curve 'prime256v1')" + "NIST256p (openssl calls this curve 'prime256v1')." ) return sk -def _load_ecdsa_verifying_key(keyfile): +def _load_ecdsa_verifying_key(keyfile: IO) -> ec.EllipticCurvePublicKey: """Load ECDSA verifying key for Secure Boot V1 only""" try: - vk = ecdsa.VerifyingKey.from_pem(keyfile.read()) + vk = serialization.load_pem_public_key( + keyfile.read(), backend=default_backend() + ) except ValueError: raise esptool.FatalError( "Incorrect ECDSA public key specified. " "Please check algorithm and/or format." ) - if vk.curve != ecdsa.NIST256p: + if not isinstance(vk.curve, ec.SECP256R1): raise esptool.FatalError( "Signing key uses incorrect curve. ESP32 Secure Boot only supports " - "NIST256p (openssl calls this curve 'prime256v1')" + "NIST256p (openssl calls this curve 'prime256v1')." ) return vk -def _load_sbv2_signing_key(keydata): +def _load_sbv2_signing_key( + keydata: bytes, +) -> rsa.RSAPrivateKey | ec.EllipticCurvePrivateKey: """ Load Secure Boot V2 signing key @@ -258,22 +299,23 @@ def _load_sbv2_signing_key(keydata): if isinstance(sk, rsa.RSAPrivateKey): if sk.key_size != 3072: raise esptool.FatalError( - "Key file has length %d bits. Secure boot v2 only supports RSA-3072." - % sk.key_size + f"Key file has length {sk.key_size} bits. Secure boot v2 only " + "supports RSA-3072." ) return sk if isinstance(sk, ec.EllipticCurvePrivateKey): if not isinstance(sk.curve, (ec.SECP192R1, ec.SECP256R1, ec.SECP384R1)): raise esptool.FatalError( "Key file uses incorrect curve. Secure Boot V2 + ECDSA only supports " - "NIST192p, NIST256p, NIST384p (aka prime192v1 / secp192r1, prime256v1 / secp256r1, secp384r1)" + "NIST192p, NIST256p, NIST384p (aka prime192v1 / secp192r1, " + "prime256v1 / secp256r1, secp384r1)." ) return sk - raise esptool.FatalError("Unsupported signing key for Secure Boot V2") + raise esptool.FatalError("Unsupported signing key for Secure Boot V2.") -def _load_sbv2_pub_key(keydata): +def _load_sbv2_pub_key(keydata: bytes) -> rsa.RSAPublicKey | ec.EllipticCurvePublicKey: """ Load Secure Boot V2 public key, can be rsa.RSAPublicKey or ec.EllipticCurvePublicKey """ @@ -281,22 +323,23 @@ def _load_sbv2_pub_key(keydata): if isinstance(vk, rsa.RSAPublicKey): if vk.key_size != 3072: raise esptool.FatalError( - "Key file has length %d bits. Secure boot v2 only supports RSA-3072." - % vk.key_size + f"Key file has length {vk.key_size} bits. Secure boot v2 only " + "supports RSA-3072." ) return vk if isinstance(vk, ec.EllipticCurvePublicKey): if not isinstance(vk.curve, (ec.SECP192R1, ec.SECP256R1, ec.SECP384R1)): raise esptool.FatalError( "Key file uses incorrect curve. Secure Boot V2 + ECDSA only supports " - "NIST192p, NIST256p, NIST384p (aka prime192v1 / secp192r1, prime256v1 / secp256r1, secp384r1)" + "NIST192p, NIST256p, NIST384p (aka prime192v1 / secp192r1, " + "prime256v1 / secp256r1, secp384r1)." ) return vk - raise esptool.FatalError("Unsupported public key for Secure Boot V2") + raise esptool.FatalError("Unsupported public key for Secure Boot V2.") -def _get_sbv2_pub_key(keyfile): +def _get_sbv2_pub_key(keyfile: IO) -> rsa.RSAPublicKey | ec.EllipticCurvePublicKey: key_data = keyfile.read() if ( b"-BEGIN RSA PRIVATE KEY" in key_data @@ -309,15 +352,23 @@ def _get_sbv2_pub_key(keyfile): else: raise esptool.FatalError( "Verification key does not appear to be an RSA Private or " - "Public key in PEM format. Unsupported" + "Public key in PEM format. Unsupported." ) return vk -def _get_sbv2_rsa_primitives(public_key): - primitives = namedtuple("primitives", ["n", "e", "m", "rinv"]) +@dataclass +class Primitives: + n: int + e: int + m: int + rinv: int + + +def _get_sbv2_rsa_primitives(public_key: rsa.RSAPublicKey) -> Primitives: + primitives = Primitives(0, 0, 0, 0) numbers = public_key.public_numbers() - primitives.n = numbers.n # + primitives.n = numbers.n primitives.e = numbers.e # two public key components # Note: this cheats and calls a private 'rsa' method to get the modular @@ -329,76 +380,127 @@ def _get_sbv2_rsa_primitives(public_key): return primitives -def _microecc_format(a, b, curve_len): +def _microecc_format(a: int, b: int, curve_len: int) -> bytes: """ Given two numbers (curve coordinates or (r,s) signature), write them out as a little-endian byte sequence suitable for micro-ecc "native little endian" mode """ byte_len = int(curve_len / 8) - ab = int_to_bytes(a, byte_len)[::-1] + int_to_bytes(b, byte_len)[::-1] + ab: bytes = int_to_bytes(a, byte_len)[::-1] + int_to_bytes(b, byte_len)[::-1] assert len(ab) in [48, 64, 96] return ab -def sign_data(args): - if args.keyfile: - _check_output_is_not_input(args.keyfile, args.output) - _check_output_is_not_input(args.datafile, args.output) - if args.version == "1": - return sign_secure_boot_v1(args) - elif args.version == "2": - return sign_secure_boot_v2(args) +def sign_data( + version: int, + keyfile: list[IO], + output: str | None, + append_signatures: bool, + hsm: bool, + hsm_config: IO | None, + pub_key: list[IO], + signature: list[IO], + datafile: IO, +): + if keyfile: + for file in keyfile: + _check_output_is_not_input(file, output) + _check_output_is_not_input(datafile, output) + if version == "1": + return sign_secure_boot_v1(keyfile, output, hsm, pub_key, signature, datafile) + elif version == "2": + return sign_secure_boot_v2( + keyfile, + output, + append_signatures, + hsm, + hsm_config, + pub_key, + signature, + datafile, + ) -def sign_secure_boot_v1(args): +def sign_secure_boot_v1( + keyfile: list[IO], + output: str | None, + hsm: bool, + pub_key: list[IO], + signatures: list[IO], + datafile: IO, +): """ Sign a data file with a ECDSA private key, append binary signature to file contents """ - binary_content = args.datafile.read() + binary_content = datafile.read() - if args.hsm: + if hsm: raise esptool.FatalError( "Secure Boot V1 does not support signing using an " "external Hardware Security Module (HSM)" ) - if args.signature: - print("Pre-calculated signatures found") - if len(args.pub_key) > 1: - raise esptool.FatalError("Secure Boot V1 only supports one signing key") - signature = args.signature[0].read() + if signatures: + log.print("Pre-calculated signatures found...") + if len(pub_key) > 1: + raise esptool.FatalError("Secure Boot V1 only supports one signing key.") + raw_signature = signatures[0].read() + # Signature needs to be DER-encoded for verification + r = int.from_bytes(raw_signature[:32], "big") + s = int.from_bytes(raw_signature[32:], "big") + signature = utils.encode_dss_signature(r, s) # get verifying/public key - vk = _load_ecdsa_verifying_key(args.pub_key[0]) + vk = _load_ecdsa_verifying_key(pub_key[0]) else: - if len(args.keyfile) > 1: - raise esptool.FatalError("Secure Boot V1 only supports one signing key") - sk = _load_ecdsa_signing_key(args.keyfile[0]) + if len(keyfile) > 1: + raise esptool.FatalError("Secure Boot V1 only supports one signing key.") + sk = _load_ecdsa_signing_key(keyfile[0]) - # calculate signature of binary data - signature = sk.sign_deterministic(binary_content, hashlib.sha256) + # calculate signature of binary data, returns DER-encoded signature + signature = sk.sign( + binary_content, ec.ECDSA(hashes.SHA256(), deterministic_signing=True) + ) # get verifying/public key - vk = sk.get_verifying_key() + vk = sk.public_key() # back-verify signature - vk.verify(signature, binary_content, hashlib.sha256) # throws exception on failure - if args.output is None or os.path.abspath(args.output) == os.path.abspath( - args.datafile.name + vk.verify( + signature, binary_content, ec.ECDSA(hashes.SHA256()) + ) # throws exception on failure + + # Secure boot signature block stores raw signature bytes, create raw signature + r, s = utils.decode_dss_signature(signature) + r_bytes = r.to_bytes(32, byteorder="big") + s_bytes = s.to_bytes(32, byteorder="big") + signature = r_bytes + s_bytes + + if output is None or os.path.abspath(output) == os.path.abspath( + datafile.name ): # append signature to input file - args.datafile.close() - outfile = open(args.datafile.name, "ab") + datafile.close() + outfile = open(datafile.name, "ab") else: # write file & signature to new file - outfile = open(args.output, "wb") + outfile = open(output, "wb") outfile.write(binary_content) outfile.write( struct.pack("I", 0) ) # Version indicator, allow for different curves/formats later outfile.write(signature) outfile.close() - print("Signed %d bytes of data from %s" % (len(binary_content), args.datafile.name)) - - -def sign_secure_boot_v2(args): + log.print(f'Signed {len(binary_content)} bytes of data from "{datafile.name}".') + + +def sign_secure_boot_v2( + keyfile: list[IO], + output: str | None, + append_signatures: bool, + hsm: bool, + hsm_config: IO | None, + pub_key: list[IO], + signature: list[IO], + datafile: IO, +): """ Sign a firmware app image with an RSA private key using RSA-PSS, or ECDSA private key using P192 or P256 or P384. @@ -406,15 +508,12 @@ def sign_secure_boot_v2(args): Write output file with a Secure Boot V2 header appended. """ SIG_BLOCK_MAX_COUNT = 3 - contents = args.datafile.read() + contents = datafile.read() sig_block_num = 0 signature_sector = b"" - signature = args.signature - pub_key = args.pub_key - if len(contents) % SECTOR_SIZE != 0: - if args.signature: + if signature: raise esptool.FatalError( "Secure Boot V2 requires the signature block to start " "from a 4KB aligned sector " @@ -422,13 +521,13 @@ def sign_secure_boot_v2(args): ) else: pad_by = SECTOR_SIZE - (len(contents) % SECTOR_SIZE) - print( + log.print( f"Padding data contents by {pad_by} bytes " - "so signature sector aligns at sector boundary" + "so signature sector aligns at sector boundary." ) contents += b"\xff" * pad_by - elif args.append_signatures: + elif append_signatures: while sig_block_num < SIG_BLOCK_MAX_COUNT: sig_block = validate_signature_block(contents, sig_block_num) if sig_block is None: @@ -439,62 +538,62 @@ def sign_secure_boot_v2(args): sig_block_num += 1 if len(signature_sector) % SIG_BLOCK_SIZE != 0: - raise esptool.FatalError("Incorrect signature sector size") + raise esptool.FatalError("Incorrect signature sector size.") if sig_block_num == 0: - print( + log.print( "No valid signature blocks found. " "Discarding --append-signature and proceeding to sign the image afresh." ) else: - print( + log.print( f"{sig_block_num} valid signature block(s) already present " "in the signature sector." ) if sig_block_num == SIG_BLOCK_MAX_COUNT: raise esptool.FatalError( - f"Upto {SIG_BLOCK_MAX_COUNT} signature blocks are supported. " - "(For ESP32-ECO3 only 1 signature block is supported)" + f"Up to {SIG_BLOCK_MAX_COUNT} signature blocks are supported " + "(For ESP32-ECO3 only 1 signature block is supported)." ) # Signature stripped off the content # (the legitimate blocks are included in signature_sector) contents = contents[: len(contents) - SECTOR_SIZE] - if args.hsm: - if args.hsm_config is None: + if hsm: + if hsm_config is None: raise esptool.FatalError( "Config file is required to generate signature using an external HSM." ) - import espsecure.esp_hsm_sign as hsm + import espsecure.esp_hsm_sign as hsm_sign try: - config = hsm.read_hsm_config(args.hsm_config) + config = hsm_sign.read_hsm_config(hsm_config) except Exception as e: - raise esptool.FatalError(f"Incorrect HSM config file format ({e})") - if pub_key is None: + raise esptool.FatalError(f"Incorrect HSM config file format ({e}).") + if len(pub_key) == 0: pub_key = extract_pubkey_from_hsm(config) signature = generate_signature_using_hsm(config, contents) if signature: - print("Pre-calculated signatures found") + log.print("Pre-calculated signatures found...") key_count = len(pub_key) if len(signature) != key_count: raise esptool.FatalError( f"Number of public keys ({key_count}) not equal to " - f"the number of signatures {len(signature)}." + f"the number of signatures ({len(signature)})." ) else: - key_count = len(args.keyfile) + key_count = len(keyfile) empty_signature_blocks = SIG_BLOCK_MAX_COUNT - sig_block_num if key_count > empty_signature_blocks: raise esptool.FatalError( - f"Number of keys({key_count}) more than the empty signature blocks." - f"({empty_signature_blocks})" + f"Number of keys ({key_count}) more than the empty signature blocks " + f"({empty_signature_blocks})." ) - print(f"{key_count} signing key(s) found.") + log.print(f"{key_count} signing key(s) found.") # Generate signature block using pre-calculated signatures if signature: @@ -503,12 +602,10 @@ def sign_secure_boot_v2(args): ) # Generate signature block by signing using private keys else: - signature_block = generate_signature_block_using_private_key( - args.keyfile, contents - ) + signature_block = generate_signature_block_using_private_key(keyfile, contents) if signature_block is None or len(signature_block) == 0: - raise esptool.FatalError("Signature Block generation failed") + raise esptool.FatalError("Signature Block generation failed.") signature_sector += signature_block @@ -517,7 +614,7 @@ def sign_secure_boot_v2(args): and len(signature_sector) > SIG_BLOCK_SIZE * 3 and len(signature_sector) % SIG_BLOCK_SIZE != 0 ): - raise esptool.FatalError("Incorrect signature sector generation") + raise esptool.FatalError("Incorrect signature sector generation.") total_sig_blocks = len(signature_sector) // SIG_BLOCK_SIZE @@ -526,21 +623,23 @@ def sign_secure_boot_v2(args): b"\xff" * (SECTOR_SIZE - len(signature_sector)) ) if len(signature_sector) != SECTOR_SIZE: - raise esptool.FatalError("Incorrect signature sector size") + raise esptool.FatalError("Incorrect signature sector size.") # Write to output file, or append to existing file - if args.output is None: - args.datafile.close() - args.output = args.datafile.name - with open(args.output, "wb") as f: + if output is None: + datafile.close() + output = datafile.name + with open(output, "wb") as f: f.write(contents + signature_sector) - print( - f"Signed {len(contents)} bytes of data from {args.datafile.name}. " + log.print( + f'Signed {len(contents)} bytes of data from "{datafile.name}". ' f"Signature sector now has {total_sig_blocks} signature blocks." ) -def generate_signature_using_hsm(config, contents): +def generate_signature_using_hsm( + config: configparser.SectionProxy, contents: bytes +) -> list[IO]: import espsecure.esp_hsm_sign as hsm session = hsm.establish_session(config) @@ -556,13 +655,13 @@ def generate_signature_using_hsm(config, contents): def generate_signature_block_using_pre_calculated_signature( - signature, pub_key, contents -): + signature: list[IO], pub_key: list[IO], contents: bytes +) -> bytes: signature_blocks = b"" for sig, pk in zip(signature, pub_key): try: public_key = _get_sbv2_pub_key(pk) - signature = sig.read() + sig_bytes = sig.read() if isinstance(public_key, rsa.RSAPublicKey): # Calculate digest of data file digest = _sha256_digest(contents) @@ -570,14 +669,14 @@ def generate_signature_block_using_pre_calculated_signature( rsa_primitives = _get_sbv2_rsa_primitives(public_key) # Verify the signature public_key.verify( - signature, + sig_bytes, digest, padding.PSS(mgf=padding.MGF1(hashes.SHA256()), salt_length=32), utils.Prehashed(hashes.SHA256()), ) signature_block = generate_rsa_signature_block( - digest, rsa_primitives, signature + digest, rsa_primitives, sig_bytes ) else: # ECDSA signature @@ -602,11 +701,11 @@ def generate_signature_block_using_pre_calculated_signature( # Verify the signature public_key.verify( - signature, digest, ec.ECDSA(utils.Prehashed(hash_type)) + sig_bytes, digest, ec.ECDSA(utils.Prehashed(hash_type)) ) pubkey_point = _microecc_format(numbers.x, numbers.y, curve_len) - r, s = utils.decode_dss_signature(signature) + r, s = utils.decode_dss_signature(sig_bytes) signature_rs = _microecc_format(r, s, curve_len) signature_block = generate_ecdsa_signature_block( digest, curve_id, pubkey_point, signature_rs @@ -615,19 +714,21 @@ def generate_signature_block_using_pre_calculated_signature( raise esptool.FatalError( "Signature verification failed: Invalid Signature\n" "The pre-calculated signature has not been signed " - "using the given public key" + "using the given public key." ) signature_block += struct.pack(" bytes: signature_blocks = b"" for keyfile in keyfiles: private_key = _load_sbv2_signing_key(keyfile.read()) @@ -683,13 +784,15 @@ def generate_signature_block_using_private_key(keyfiles, contents): signature_block += b"\x00" * 16 # padding if len(signature_block) != SIG_BLOCK_SIZE: - raise esptool.FatalError("Incorrect signature block size") + raise esptool.FatalError("Incorrect signature block size.") signature_blocks += signature_block return signature_blocks -def generate_rsa_signature_block(digest, rsa_primitives, signature): +def generate_rsa_signature_block( + digest: bytes, rsa_primitives: Primitives, signature: bytes +) -> bytes: """ Encode in rsa signature block format @@ -712,7 +815,9 @@ def generate_rsa_signature_block(digest, rsa_primitives, signature): return signature_block -def generate_ecdsa_signature_block(digest, curve_id, pubkey_point, signature_rs): +def generate_ecdsa_signature_block( + digest: bytes, curve_id: int, pubkey_point: bytes, signature_rs: bytes +) -> bytes: """ Encode in rsa signature block format @@ -750,54 +855,68 @@ def generate_ecdsa_signature_block(digest, curve_id, pubkey_point, signature_rs) return signature_block -def verify_signature(args): - if args.version == "1": - return verify_signature_v1(args) - elif args.version == "2": - return verify_signature_v2(args) +def verify_signature( + version: int, + hsm: bool, + hsm_config: IO | None, + keyfile: IO, + datafile: IO, +): + if version == "1": + return verify_signature_v1(keyfile, datafile) + elif version == "2": + return verify_signature_v2(hsm, hsm_config, keyfile, datafile) -def verify_signature_v1(args): +def verify_signature_v1(keyfile: IO, datafile: IO): """Verify a previously signed binary image, using the ECDSA public key""" - key_data = args.keyfile.read() + key_data = keyfile.read() if b"-BEGIN EC PRIVATE KEY" in key_data: - sk = ecdsa.SigningKey.from_pem(key_data) - vk = sk.get_verifying_key() + sk = serialization.load_pem_private_key( + key_data, password=None, backend=default_backend() + ) + vk = sk.public_key() elif b"-BEGIN PUBLIC KEY" in key_data: - vk = ecdsa.VerifyingKey.from_pem(key_data) - elif len(key_data) == 64: - vk = ecdsa.VerifyingKey.from_string(key_data, curve=ecdsa.NIST256p) + vk = serialization.load_pem_public_key(key_data, backend=default_backend()) + elif len(key_data) == 64: # Raw public key bytes + x = int.from_bytes(key_data[:32], byteorder="big") # x coordinates + y = int.from_bytes(key_data[32:], byteorder="big") # y coordinates + numbers = ec.EllipticCurvePublicNumbers(x, y, ec.SECP256R1()) + vk = numbers.public_key(backend=default_backend()) else: raise esptool.FatalError( "Verification key does not appear to be an EC key in PEM format " - "or binary EC public key data. Unsupported" + "or binary EC public key data. Unsupported." ) - if vk.curve != ecdsa.NIST256p: + if not isinstance(vk.curve, ec.SECP256R1): raise esptool.FatalError( "Public key uses incorrect curve. ESP32 Secure Boot only supports " - "NIST256p (openssl calls this curve 'prime256v1" + "NIST256p (openssl calls this curve 'prime256v1')." ) - binary_content = args.datafile.read() + binary_content = datafile.read() data = binary_content[0:-68] sig_version, signature = struct.unpack("I64s", binary_content[-68:]) if sig_version != 0: raise esptool.FatalError( - "Signature block has version %d. This version of espsecure " - "only supports version 0." % sig_version + f"Signature block has version {sig_version}. This version of espsecure " + "only supports version 0." ) - print("Verifying %d bytes of data" % len(data)) + log.print(f"Verifying {len(data)} bytes of data...") try: - if vk.verify(signature, data, hashlib.sha256): - print("Signature is valid") - else: - raise esptool.FatalError("Signature is not valid") - except ecdsa.keys.BadSignatureError: - raise esptool.FatalError("Signature is not valid") + # Convert raw signature to DER format + r = int.from_bytes(signature[:32], byteorder="big") + s = int.from_bytes(signature[32:], byteorder="big") + der_signature = utils.encode_dss_signature(r, s) + vk.verify(der_signature, data, ec.ECDSA(hashes.SHA256())) + log.print("Signature is valid.") + except exceptions.InvalidSignature: + raise esptool.FatalError("Signature is not valid.") -def validate_signature_block(image_content, sig_blk_num): + +def validate_signature_block(image_content: bytes, sig_blk_num: int) -> bytes | None: offset = -SECTOR_SIZE + sig_blk_num * SIG_BLOCK_SIZE sig_blk = image_content[offset : offset + SIG_BLOCK_SIZE] assert len(sig_blk) == SIG_BLOCK_SIZE @@ -818,25 +937,24 @@ def validate_signature_block(image_content, sig_blk_num): if is_invalid_block or blk_crc != calc_crc & 0xFFFFFFFF: # Signature block invalid return None key_type = "RSA" if version == SIG_BLOCK_VERSION_RSA else "ECDSA" - print(f"Signature block {sig_blk_num} is valid ({key_type}).") + log.print(f"Signature block {sig_blk_num} is valid ({key_type}).") return sig_blk -def verify_signature_v2(args): +def verify_signature_v2(hsm: bool, hsm_config: IO | None, keyfile: IO, datafile: IO): """Verify a previously signed binary image, using the RSA or ECDSA public key""" - keyfile = args.keyfile - if args.hsm: - if args.hsm_config is None: + if hsm: + if hsm_config is None: raise esptool.FatalError( "Config file is required to extract public key from an external HSM." ) - import espsecure.esp_hsm_sign as hsm + import espsecure.esp_hsm_sign as hsm_sign try: - config = hsm.read_hsm_config(args.hsm_config) + config = hsm_sign.read_hsm_config(hsm_config) except Exception as e: - raise esptool.FatalError(f"Incorrect HSM config file format ({e})") + raise esptool.FatalError(f"Incorrect HSM config file format ({e}).") # get public key from HSM keyfile = extract_pubkey_from_hsm(config)[0] @@ -847,7 +965,7 @@ def verify_signature_v2(args): elif isinstance(vk, ec.EllipticCurvePublicKey): SIG_BLOCK_MAX_COUNT = 1 - image_content = args.datafile.read() + image_content = datafile.read() if len(image_content) < SECTOR_SIZE or len(image_content) % SECTOR_SIZE != 0: raise esptool.FatalError( "Invalid datafile. Data size should be non-zero & a multiple of 4096." @@ -858,7 +976,7 @@ def verify_signature_v2(args): for sig_blk_num in range(SIG_BLOCK_MAX_COUNT): sig_blk = validate_signature_block(image_content, sig_blk_num) if sig_blk is None: - print(f"Signature block {sig_blk_num} invalid. Skipping.") + log.print(f"Signature block {sig_blk_num} invalid. Skipping.") continue _, version, ecdsa_sha_version = struct.unpack(" list[IO]: import espsecure.esp_hsm_sign as hsm session = hsm.establish_session(config) @@ -994,14 +1108,14 @@ def _sha384_digest(contents): return digest.digest() -def signature_info_v2(args): +def signature_info_v2(datafile: IO): """ Validates the signature block and prints the RSA/ECDSA public key digest for valid blocks """ SIG_BLOCK_MAX_COUNT = 3 - image_content = args.datafile.read() + image_content = datafile.read() if len(image_content) < SECTOR_SIZE or len(image_content) % SECTOR_SIZE != 0: raise esptool.FatalError( "Invalid datafile. Data size should be non-zero & a multiple of 4096." @@ -1010,9 +1124,9 @@ def signature_info_v2(args): for sig_blk_num in range(SIG_BLOCK_MAX_COUNT): sig_blk = validate_signature_block(image_content, sig_blk_num) if sig_blk is None: - print( - "Signature block %d absent/invalid. Skipping checking next blocks." - % sig_blk_num + log.print( + f"Signature block {sig_blk_num} absent/invalid. Skipping checking " + "next blocks..." ) return @@ -1027,31 +1141,32 @@ def signature_info_v2(args): if sig_data[2] != digest: raise esptool.FatalError( - "Digest in signature block %d doesn't match the image digest." - % (sig_blk_num) + f"Digest in signature block {sig_blk_num} doesn't match " + "the image digest." ) offset = -SECTOR_SIZE + sig_blk_num * SIG_BLOCK_SIZE - sig_blk = image_content[offset : offset + SIG_BLOCK_SIZE] + sig_block = image_content[offset : offset + SIG_BLOCK_SIZE] if sig_data[1] == SIG_BLOCK_VERSION_RSA: - key_digest = _sha256_digest(sig_blk[36:812]) + key_digest = _sha256_digest(sig_block[36:812]) elif sig_data[1] == SIG_BLOCK_VERSION_ECDSA: if ecdsa_sha_version == ECDSA_SHA_384: - key_digest = _sha256_digest(sig_blk[52:149]) + key_digest = _sha256_digest(sig_block[52:149]) else: - key_digest = _sha256_digest(sig_blk[36:101]) + key_digest = _sha256_digest(sig_block[36:101]) else: raise esptool.FatalError( - "Unsupported scheme in signature block %d" % (sig_blk_num) + f"Unsupported scheme in signature block {sig_blk_num}." ) - print( - "Public key digest for block %d: %s" - % (sig_blk_num, " ".join("{:02x}".format(c) for c in bytearray(key_digest))) + log.print( + f"Public key digest for block {sig_blk_num}: ".join( + f"{c:02x}" for c in bytearray(key_digest) + ) ) -def _digest_sbv2_public_key(keyfile): +def _digest_sbv2_public_key(keyfile: IO) -> bytes: public_key = _get_sbv2_pub_key(keyfile) if isinstance(public_key, rsa.RSAPublicKey): @@ -1100,39 +1215,32 @@ def _digest_sbv2_public_key(keyfile): return hashlib.sha256(binary_format).digest() -def digest_sbv2_public_key(args): - _check_output_is_not_input(args.keyfile, args.output) - public_key_digest = _digest_sbv2_public_key(args.keyfile) - with open(args.output, "wb") as f: - print( - "Writing the public key digest of %s to %s." - % (args.keyfile.name, args.output) - ) +def digest_sbv2_public_key(keyfile: IO, output: str): + _check_output_is_not_input(keyfile, output) + public_key_digest = _digest_sbv2_public_key(keyfile) + with open(output, "wb") as f: + log.print(f'Writing the public key digest of "{keyfile.name}" to "{output}".') f.write(public_key_digest) -def digest_rsa_public_key(args): - # Kept for compatibility purpose - digest_sbv2_public_key(args) +def get_ecdsa_signing_key_raw_bytes(sk): + return sk.private_numbers().private_value.to_bytes( + length=(sk.key_size + 7) // 8, byteorder="big" + ) -def digest_private_key(args): - _check_output_is_not_input(args.keyfile, args.digest_file) - sk = _load_ecdsa_signing_key(args.keyfile) - repr(sk.to_string()) - digest = hashlib.sha256() - digest.update(sk.to_string()) - result = digest.digest() - if args.keylen == 192: +def digest_private_key(keyfile: IO, keylen: int, digest_file: IO): + _check_output_is_not_input(keyfile, digest_file) + sk = _load_ecdsa_signing_key(keyfile) + private_bytes = get_ecdsa_signing_key_raw_bytes(sk) + result = hashlib.sha256(private_bytes).digest() + if keylen == 192: result = result[0:24] - args.digest_file.write(result) - print( - "SHA-256 digest of private key %s%s written to %s" - % ( - args.keyfile.name, - "" if args.keylen == 256 else " (truncated to 192 bits)", - args.digest_file.name, - ) + digest_file.write(result) + len_msg = "" if keylen == 256 else " (truncated to 192 bits)" + log.print( + f'SHA-256 digest of private key "{keyfile.name}"{len_msg} ' + f'written to "{digest_file.name}".' ) @@ -1162,23 +1270,7 @@ def digest_private_key(args): # fmt: on -def _flash_encryption_tweak_range(flash_crypt_config=0xF): - """Return a list of the bit indexes that the "key tweak" applies to, - as determined by the FLASH_CRYPT_CONFIG 4 bit efuse value. - """ - tweak_range = [] - if (flash_crypt_config & 1) != 0: - tweak_range += range(67) - if (flash_crypt_config & 2) != 0: - tweak_range += range(67, 132) - if (flash_crypt_config & 4) != 0: - tweak_range += range(132, 195) - if (flash_crypt_config & 8) != 0: - tweak_range += range(195, 256) - return tweak_range - - -def _flash_encryption_tweak_range_bits(flash_crypt_config=0xF): +def _flash_encryption_tweak_range_bits(flash_crypt_config: int = 0xF) -> int: """Return bits (in reverse order) that the "key tweak" applies to, as determined by the FLASH_CRYPT_CONFIG 4 bit efuse value. """ @@ -1210,7 +1302,7 @@ def _flash_encryption_tweak_range_bits(flash_crypt_config=0xF): mul2_mask = 0x000000000000007FE00000000000000FF000000000000007E00000000000000F -def _flash_encryption_tweak_key(key, offset, tweak_range): +def _flash_encryption_tweak_key(key: int, offset: int, tweak_range: int) -> bytes: """Apply XOR "tweak" values to the key, derived from flash offset 'offset'. This matches the ESP32 hardware flash encryption. @@ -1225,23 +1317,35 @@ def _flash_encryption_tweak_key(key, offset, tweak_range): return int.to_bytes(key, length=32, byteorder="big", signed=False) -def generate_flash_encryption_key(args): - print("Writing %d random bits to key file %s" % (args.keylen, args.key_file.name)) - args.key_file.write(os.urandom(args.keylen // 8)) - - def _flash_encryption_operation_esp32( - output_file, input_file, flash_address, keyfile, flash_crypt_conf, do_decrypt + output_file: IO, + input_file: IO, + flash_address: int, + keyfile: IO, + flash_crypt_conf: int, + do_decrypt: bool, ): - key = _load_hardware_key(keyfile) + """ + Perform flash encryption or decryption operation for ESP32. + + This function handles the encryption or decryption of flash data for ESP32 chip. + It reads data from the input file, processes it in 16-byte blocks, and writes the + processed data to the output file. The function ensures that the key length is + either 192 or 256 bits, as required by the ESP32 chip. It also checks that the flash + address is a multiple of 16. + + Note: This function is specific to the ESP32 chip. For other chips, use the + --aes_xts flag to call the correct function. + """ + key = _load_hardware_key(keyfile, True, aes_xts=False) if flash_address % 16 != 0: raise esptool.FatalError( - "Starting flash address 0x%x must be a multiple of 16" % flash_address + f"Starting flash address {flash_address:#x} must be a multiple of 16." ) if flash_crypt_conf == 0: - print("WARNING: Setting FLASH_CRYPT_CONF to zero is not recommended") + log.warning("Setting FLASH_CRYPT_CONF to zero is not recommended.") tweak_range = _flash_encryption_tweak_range_bits(flash_crypt_conf) key = int.from_bytes(key, byteorder="big", signed=False) @@ -1256,12 +1360,12 @@ def _flash_encryption_operation_esp32( break elif len(block) < 16: if do_decrypt: - raise esptool.FatalError("Data length is not a multiple of 16 bytes") + raise esptool.FatalError("Data length is not a multiple of 16 bytes.") pad = 16 - len(block) block = block + os.urandom(pad) - print( - "Note: Padding with %d bytes of random data " - "(encrypted data must be multiple of 16 bytes long)" % pad + log.print( + f"Note: Padding with {pad} bytes of random data " + "(encrypted data must be multiple of 16 bytes long)." ) if block_offs % 32 == 0 or cipher is None: @@ -1308,7 +1412,7 @@ def _flash_encryption_operation_esp32( def _flash_encryption_operation_aes_xts( - output_file, input_file, flash_address, keyfile, do_decrypt + output_file: IO, input_file: IO, flash_address: int, keyfile: IO, do_decrypt: bool ): """ Apply the AES-XTS algorithm with the hardware addressing scheme used by Espressif @@ -1322,21 +1426,21 @@ def _flash_encryption_operation_aes_xts( """ backend = default_backend() - key = _load_hardware_key(keyfile) + key = _load_hardware_key(keyfile, True, aes_xts=True) indata = input_file.read() if flash_address % 16 != 0: raise esptool.FatalError( - "Starting flash address 0x%x must be a multiple of 16" % flash_address + f"Starting flash address {flash_address:#x} must be a multiple of 16." ) if len(indata) % 16 != 0: raise esptool.FatalError( - "Input data length (%d) must be a multiple of 16" % len(indata) + f"Input data length ({len(indata)}) must be a multiple of 16." ) if len(indata) == 0: - raise esptool.FatalError("Input data must be longer than 0") + raise esptool.FatalError("Input data must be longer than 0.") # left pad for a 1024-bit aligned address pad_left = flash_address % 0x80 @@ -1350,24 +1454,22 @@ def _flash_encryption_operation_aes_xts( inblocks = _split_blocks(indata, 0x80) # split into 1024 bit blocks - output = [] + output_list = [] for inblock in inblocks: # for each block tweak = struct.pack(" 0: - if not self.file_obj: - self.file_obj = open(self.path, "wb") - self.file_obj.write(payload) +@cli.command("digest-private-key") +@click.option( + "--keyfile", + "-k", + type=click.File("rb"), + required=True, + help="Private key file (PEM format) to generate a digest from.", +) +@click.option( + "--keylen", + "-l", + type=int, + default=256, + help="Length of private key digest file to generate (in bits). 3/4 Coding Scheme " + "requires 192 bit key.", +) +@click.argument("digest-file", type=click.File("wb", lazy=True)) +def digest_private_key_cli(keyfile, keylen, digest_file): + """Generate a SHA-256 digest of the private signing key.""" + digest_private_key(keyfile, keylen, digest_file) + + +@cli.command("generate-flash-encryption-key") +@click.option( + "--keylen", + "-l", + type=int, + default=256, + help="Length of private key digest file to generate (in bits). 3/4 Coding Scheme " + "requires 192 bit key.", +) +@click.argument("key-file", type=click.File("wb", lazy=True)) +def generate_flash_encryption_key(keylen: int, key_file: IO): + """Generate a development-use flash encryption key with random data.""" + log.print(f'Writing {keylen} random bits to key file "{key_file.name}".') + key_file.write(os.urandom(keylen // 8)) + + +@cli.command("decrypt-flash-data") +@click.option( + "--keyfile", + "-k", + type=click.File("rb"), + required=True, + help="File with flash encryption key.", +) +@click.option( + "--output", + "-o", + type=click.File("wb", lazy=True), + required=True, + help="Output file for plaintext data.", +) +@click.option( + "--address", + "-a", + type=esptool.cli_util.AnyIntType(), + required=True, + help="Address offset in flash that file was read from.", +) +@click.option( + "--flash-crypt-conf", + type=esptool.cli_util.AnyIntType(), + default=0xF, + help="Override FLASH_CRYPT_CONF eFuse value (default is 0xF) (applicable only for " + "ESP32).", +) +@click.option( + "--aes-xts", + "-x", + is_flag=True, + help="Decrypt data using AES-XTS (not applicable for ESP32).", +) +@click.argument("encrypted-file", type=click.File("rb")) +def decrypt_flash_data_cli( + keyfile, output, address, flash_crypt_conf, aes_xts, encrypted_file +): + """Decrypt some data read from encrypted flash (using known key).""" + decrypt_flash_data( + keyfile, output, address, flash_crypt_conf, aes_xts, encrypted_file + ) - def close(self): - if self.file_obj: - self.file_obj.close() - self.file_obj = None - @property - def name(self): - return self.path +@cli.command("encrypt-flash-data") +@click.option( + "--keyfile", + "-k", + type=click.File("rb"), + required=True, + help="File with flash encryption key.", +) +@click.option( + "--output", + "-o", + type=click.File("wb", lazy=True), + required=True, + help="Output file for encrypted data.", +) +@click.option( + "--address", + "-a", + type=esptool.cli_util.AnyIntType(), + help="Address offset in flash where file will be flashed.", + required=True, +) +@click.option( + "--flash-crypt-conf", + type=esptool.cli_util.AnyIntType(), + default=0xF, + help="Override FLASH_CRYPT_CONF eFuse value (default is 0xF) (applicable only for " + "ESP32).", +) +@click.option( + "--aes-xts", + "-x", + is_flag=True, + help="Encrypt data using AES-XTS (not applicable for ESP32).", +) +@click.argument("plaintext-file", type=click.File("rb")) +def encrypt_flash_data_cli( + keyfile, output, address, flash_crypt_conf, aes_xts, plaintext_file +): + """Encrypt some data suitable for encrypted flash (using known key).""" + encrypt_flash_data( + keyfile, output, address, flash_crypt_conf, aes_xts, plaintext_file + ) -def main(custom_commandline=None): +def main(argv: list[str] | None = None): """ Main function for espsecure - custom_commandline - Optional override for default arguments parsing + argv - Optional override for default arguments parsing (that uses sys.argv), can be a list of custom arguments as strings. Arguments and their values need to be added as individual items to the list e.g. "--port /dev/ttyUSB1" thus becomes ['--port', '/dev/ttyUSB1']. """ - parser = argparse.ArgumentParser( - description="espsecure.py v%s - ESP32 Secure Boot & Flash Encryption tool" - % esptool.__version__, - prog="espsecure", - ) - - subparsers = parser.add_subparsers( - dest="operation", help="Run espsecure.py {command} -h for additional help" - ) - - p = subparsers.add_parser( - "digest_secure_bootloader", - help="Take a bootloader binary image and a secure boot key, " - "and output a combined digest+binary suitable for flashing along " - "with the precalculated secure boot key.", - ) - p.add_argument( - "--keyfile", - "-k", - help="256 bit key for secure boot digest.", - type=argparse.FileType("rb"), - required=True, - ) - p.add_argument("--output", "-o", help="Output file for signed digest image.") - p.add_argument( - "--iv", - help="128 byte IV file. Supply a file for testing purposes only, " - "if not supplied an IV will be randomly generated.", - type=argparse.FileType("rb"), - ) - p.add_argument( - "image", - help="Bootloader image file to calculate digest from", - type=argparse.FileType("rb"), - ) - - p = subparsers.add_parser( - "generate_signing_key", - help="Generate a private key for signing secure boot images " - "as per the secure boot version. " - "Key file is generated in PEM format, " - "Secure Boot V1 - ECDSA NIST256p private key. " - "Secure Boot V2 - RSA 3072, ECDSA NIST384p, ECDSA NIST256p, ECDSA NIST192p private key.", - ) - p.add_argument( - "--version", - "-v", - help="Version of the secure boot signing scheme to use.", - choices=["1", "2"], - default="1", - ) - p.add_argument( - "--scheme", - "-s", - help="Scheme of secure boot signing.", - choices=["rsa3072", "ecdsa192", "ecdsa256", "ecdsa384"], - required=False, - ) - p.add_argument( - "keyfile", help="Filename for private key file (embedded public key)" - ) - - p = subparsers.add_parser( - "sign_data", - help="Sign a data file for use with secure boot. " - "Signing algorithm is deterministic ECDSA w/ SHA-512 (V1) " - "or either RSA-PSS or ECDSA w/ SHA-256 or ECDSA w/ SHA-384 (V2).", - ) - p.add_argument( - "--version", - "-v", - help="Version of the secure boot signing scheme to use.", - choices=["1", "2"], - required=True, - ) - p.add_argument( - "--keyfile", - "-k", - help="Private key file for signing. Key is in PEM format.", - type=argparse.FileType("rb"), - nargs="+", - ) - p.add_argument( - "--append_signatures", - "-a", - help="Append signature block(s) to already signed image. " - "Not valid for ESP32 and ESP32-C2.", - action="store_true", - ) - p.add_argument( - "--hsm", - help="Use an external Hardware Security Module " - "to generate signature using PKCS#11 interface.", - action="store_true", - ) - p.add_argument( - "--hsm-config", - help="Config file for the external Hardware Security Module " - "to be used to generate signature.", - default=None, - ) - p.add_argument( - "--pub-key", - help="Public key files corresponding to the private key used to generate " - "the pre-calculated signatures. Keys should be in PEM format.", - type=argparse.FileType("rb"), - nargs="+", - ) - p.add_argument( - "--signature", - help="Pre-calculated signatures. " - "Signatures generated using external private keys e.g. keys stored in HSM.", - type=argparse.FileType("rb"), - nargs="+", - default=None, - ) - p.add_argument( - "--output", - "-o", - help="Output file for signed digest image. Default is to sign the input file.", - ) - p.add_argument( - "datafile", - help="File to sign. For version 1, this can be any file. " - "For version 2, this must be a valid app image.", - type=argparse.FileType("rb"), - ) - - p = subparsers.add_parser( - "verify_signature", - help='Verify a data file previously signed by "sign_data", ' - "using the public key.", - ) - p.add_argument( - "--version", - "-v", - help="Version of the secure boot scheme to use.", - choices=["1", "2"], - required=True, - ) - p.add_argument( - "--hsm", - help="Use an external Hardware Security Module " - "to verify signature using PKCS#11 interface.", - action="store_true", - ) - p.add_argument( - "--hsm-config", - help="Config file for the external Hardware Security Module " - "to be used to verify signature.", - default=None, - ) - p.add_argument( - "--keyfile", - "-k", - help="Public key file for verification. " - "Can be private or public key in PEM format.", - type=argparse.FileType("rb"), - ) - p.add_argument( - "datafile", - help="Signed data file to verify signature.", - type=argparse.FileType("rb"), - ) - - p = subparsers.add_parser( - "extract_public_key", - help="Extract the public verification key for signatures, " - "save it as a raw binary file.", - ) - p.add_argument( - "--version", - "-v", - help="Version of the secure boot signing scheme to use.", - choices=["1", "2"], - default="1", - ) - p.add_argument( - "--keyfile", - "-k", - help="Private key file (PEM format) to extract the " - "public verification key from.", - type=argparse.FileType("rb"), - required=True, - ) - p.add_argument( - "public_keyfile", help="File to save new public key into", type=OutFileType() - ) - - # Kept for compatibility purpose. We can deprecate this in a future release - p = subparsers.add_parser( - "digest_rsa_public_key", - help="Generate an SHA-256 digest of the RSA public key. " - "This digest is burned into the eFuse and asserts the legitimacy " - "of the public key for Secure boot v2.", - ) - p.add_argument( - "--keyfile", - "-k", - help="Public key file for verification. " - "Can be private or public key in PEM format.", - type=argparse.FileType("rb"), - required=True, - ) - p.add_argument("--output", "-o", help="Output file for the digest.", required=True) - - p = subparsers.add_parser( - "digest_sbv2_public_key", - help="Generate an SHA-256 digest of the public key. " - "This digest is burned into the eFuse and asserts the legitimacy " - "of the public key for Secure boot v2.", - ) - p.add_argument( - "--keyfile", - "-k", - help="Public key file for verification. " - "Can be private or public key in PEM format.", - type=argparse.FileType("rb"), - required=True, - ) - p.add_argument("--output", "-o", help="Output file for the digest.", required=True) - - p = subparsers.add_parser( - "signature_info_v2", - help="Reads the signature block and provides the signature block information.", - ) - p.add_argument( - "datafile", - help="Secure boot v2 signed data file.", - type=argparse.FileType("rb"), - ) - - p = subparsers.add_parser( - "digest_private_key", - help="Generate an SHA-256 digest of the private signing key. " - "This can be used as a reproducible secure bootloader (only secure boot v1) " - "or flash encryption key.", - ) - p.add_argument( - "--keyfile", - "-k", - help="Private key file (PEM format) to generate a digest from.", - type=argparse.FileType("rb"), - required=True, - ) - p.add_argument( - "--keylen", - "-l", - help="Length of private key digest file to generate (in bits). " - "3/4 Coding Scheme requires 192 bit key.", - choices=[192, 256], - default=256, - type=int, - ) - p.add_argument( - "digest_file", help="File to write 32 byte digest into", type=OutFileType() - ) - - p = subparsers.add_parser( - "generate_flash_encryption_key", - help="Generate a development-use flash encryption key with random data.", - ) - p.add_argument( - "--keylen", - "-l", - help="Length of private key digest file to generate (in bits). " - "3/4 Coding Scheme requires 192 bit key.", - choices=[128, 192, 256, 512], - default=256, - type=int, - ) - p.add_argument( - "key_file", - help="File to write 16, 24, 32 or 64 byte key into", - type=OutFileType(), - ) - - p = subparsers.add_parser( - "decrypt_flash_data", - help="Decrypt some data read from encrypted flash (using known key)", - ) - p.add_argument( - "encrypted_file", - help="File with encrypted flash contents", - type=argparse.FileType("rb"), - ) - p.add_argument( - "--aes_xts", - "-x", - help="Decrypt data using AES-XTS as used on " - "ESP32-S2, ESP32-C2, ESP32-C3, ESP32-C6, ESP32-C5, ESP32-C61 and ESP32-P4", - action="store_true", - ) - p.add_argument( - "--keyfile", - "-k", - help="File with flash encryption key", - type=argparse.FileType("rb"), - required=True, - ) - p.add_argument( - "--output", - "-o", - help="Output file for plaintext data.", - type=OutFileType(), - required=True, - ) - p.add_argument( - "--address", - "-a", - help="Address offset in flash that file was read from.", - required=True, - type=esptool.arg_auto_int, - ) - p.add_argument( - "--flash_crypt_conf", - help="Override FLASH_CRYPT_CONF efuse value (default is 0XF).", - required=False, - default=0xF, - type=esptool.arg_auto_int, - ) - - p = subparsers.add_parser( - "encrypt_flash_data", - help="Encrypt some data suitable for encrypted flash (using known key)", - ) - p.add_argument( - "--aes_xts", - "-x", - help="Encrypt data using AES-XTS as used on " - "ESP32-S2, ESP32-C2, ESP32-C3, ESP32-C6, ESP32-C5, ESP32-C61 and ESP32-P4", - action="store_true", - ) - p.add_argument( - "--keyfile", - "-k", - help="File with flash encryption key", - type=argparse.FileType("rb"), - required=True, - ) - p.add_argument( - "--output", - "-o", - help="Output file for encrypted data.", - type=OutFileType(), - required=True, - ) - p.add_argument( - "--address", - "-a", - help="Address offset in flash where file will be flashed.", - required=True, - type=esptool.arg_auto_int, - ) - p.add_argument( - "--flash_crypt_conf", - help="Override FLASH_CRYPT_CONF efuse value (default is 0XF).", - required=False, - default=0xF, - type=esptool.arg_auto_int, - ) - p.add_argument( - "plaintext_file", - help="File with plaintext content for encrypting", - type=argparse.FileType("rb"), - ) - - # Enable argcomplete only on Unix-like systems - if sys.platform != "win32": - try: - import argcomplete - - argcomplete.autocomplete(parser) - except ImportError: - pass - - args = parser.parse_args(custom_commandline) - print("espsecure.py v%s" % esptool.__version__) - if args.operation is None: - parser.print_help() - parser.exit(1) - - try: - # each 'operation' is a module-level function of the same name - operation_func = globals()[args.operation] - operation_func(args) - finally: - for arg_name in vars(args): - obj = getattr(args, arg_name) - if isinstance(obj, (OutFileType, IOBase)): - obj.close() - elif isinstance(obj, list): - for f in [o for o in obj if isinstance(o, IOBase)]: - f.close() + cli(args=argv) def _main(): + check_deprecated_py_suffix(__name__) try: main() except esptool.FatalError as e: - print("\nA fatal error occurred: %s" % e) + log.error(f"\nA fatal error occurred: {e}") sys.exit(2) except ValueError as e: try: if [arg for arg in e.args if "Could not deserialize key data." in arg]: - print( + log.error( "Note: This error originates from the cryptography module. " "It is likely not a problem with espsecure, " "please make sure you are using a compatible OpenSSL backend." ) finally: raise + except KeyboardInterrupt: + log.error("KeyboardInterrupt: Run cancelled by user.") + sys.exit(2) if __name__ == "__main__": diff --git a/tools/esptool_py/espsecure/esp_hsm_sign/__init__.py b/tools/esptool_py/espsecure/esp_hsm_sign/__init__.py index d255116adf..c2e300d306 100644 --- a/tools/esptool_py/espsecure/esp_hsm_sign/__init__.py +++ b/tools/esptool_py/espsecure/esp_hsm_sign/__init__.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD +# SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD # # SPDX-License-Identifier: GPL-2.0-or-later @@ -6,7 +6,9 @@ import configparser import os import sys +from esptool.logger import log from getpass import getpass +from typing import IO try: import pkcs11 @@ -20,13 +22,12 @@ import cryptography.hazmat.primitives.asymmetric.ec as EC import cryptography.hazmat.primitives.asymmetric.rsa as RSA +import cryptography.hazmat.primitives.asymmetric.utils as utils -import ecdsa - -def read_hsm_config(configfile): +def read_hsm_config(configfile: IO) -> configparser.SectionProxy: config = configparser.ConfigParser() - config.read(configfile) + config.read_file(configfile) section = "hsm_config" if not config.has_section(section): @@ -46,13 +47,13 @@ def read_hsm_config(configfile): return config[section] -def establish_session(config): - print("Trying to establish a session with the HSM.") +def establish_session(config: configparser.SectionProxy) -> pkcs11.Session: + log.print("Trying to establish a session with the HSM...") try: if os.path.exists(config["pkcs11_lib"]): lib = pkcs11.lib(config["pkcs11_lib"]) else: - print(f'LIB file does not exist at {config["pkcs11_lib"]}') + log.error(f'LIB file does not exist at "{config["pkcs11_lib"]}".') sys.exit(1) for slot in lib.get_slots(token_present=True): if slot.slot_id == int(config["slot"]): @@ -60,36 +61,40 @@ def establish_session(config): token = slot.get_token() session = token.open(rw=True, user_pin=config["credentials"]) - print(f'Session creation successful with HSM slot {int(config["slot"])}.') + log.print(f"Session creation successful with HSM slot {int(config['slot'])}.") return session except pkcs11.exceptions.PKCS11Error as e: handle_exceptions(e) - print("Session establishment failed") + log.error("Session establishment failed.") sys.exit(1) -def get_privkey_info(session, config): +def get_privkey_info( + session: pkcs11.Session, config: configparser.SectionProxy +) -> pkcs11.Key: try: private_key = session.get_key( object_class=pkcs11.constants.ObjectClass.PRIVATE_KEY, label=config["label"] ) - print(f'Got private key metadata with label {config["label"]}.') + log.print(f"Got private key metadata with label {config['label']}.") return private_key except pkcs11.exceptions.PKCS11Error as e: handle_exceptions(e) - print("Failed to get the private key") + log.error("Failed to get the private key.") sys.exit(1) -def get_pubkey(session, config): - print("Trying to extract public key from the HSM.") +def get_pubkey( + session: pkcs11.Session, config: configparser.SectionProxy +) -> EC.EllipticCurvePublicKey | RSA.RSAPublicKey: + log.print("Trying to extract public key from the HSM...") try: if "label_pubkey" in config: public_key_label = config["label_pubkey"] else: - print( + log.print( "Config option 'label_pubkey' not found, " "using config option 'label' for public key." ) @@ -107,56 +112,64 @@ def get_pubkey(session, config): public_key = RSA.RSAPublicNumbers(e, n).public_key() elif public_key.key_type == pkcs11.mechanisms.KeyType.EC: - ecpoints, _ = ecdsa.der.remove_octet_string( - public_key[pkcs11.Attribute.EC_POINT] - ) + # EC_POINT is encoded as an octet string + # First byte is "0x04" indicating uncompressed point format + # followed by length bytes + ec_point_der = public_key[pkcs11.Attribute.EC_POINT] + if ec_point_der[0] != 0x04: # octet string tag + raise ValueError( + "Invalid EC_POINT encoding. " + f"Wanted type 'octetstring' (0x04), got {ec_point_der[0]:#02x}." + ) + length = ec_point_der[1] + ecpoints = ec_point_der[2 : 2 + length] public_key = EC.EllipticCurvePublicKey.from_encoded_point( EC.SECP256R1(), ecpoints ) else: - print("Incorrect public key algorithm") + log.error("Incorrect public key algorithm.") sys.exit(1) - print(f"Got public key with label {public_key_label}.") + log.print(f"Got public key with label {public_key_label}.") return public_key except pkcs11.exceptions.PKCS11Error as e: handle_exceptions(e) - print("Failed to extract the public key") + log.error("Failed to extract the public key.") sys.exit(1) -def sign_payload(private_key, payload): +def sign_payload(private_key: pkcs11.Key, payload: bytes) -> bytes: try: - print("Signing payload using the HSM.") + log.print("Signing payload using the HSM...") key_type = private_key.key_type mechanism, mechanism_params = get_mechanism(key_type) - signature = private_key.sign( + signature: bytes = private_key.sign( data=payload, mechanism=mechanism, mechanism_param=mechanism_params ) if len(signature) != 0: - print("Signature generation successful.") + log.print("Signature generation successful.") if key_type == pkcs11.mechanisms.KeyType.EC: r = int(binascii.hexlify(signature[:32]), 16) s = int(binascii.hexlify(signature[32:]), 16) - # der encoding in case of ecdsa signatures - signature = ecdsa.der.encode_sequence( - ecdsa.der.encode_integer(r), ecdsa.der.encode_integer(s) - ) + # ECDSA signature is encoded as a DER sequence + signature = utils.encode_dss_signature(r, s) return signature except pkcs11.exceptions.PKCS11Error as e: handle_exceptions(e, mechanism) - print("Payload Signing Failed") + log.error("Payload signing failed.") sys.exit(1) -def get_mechanism(key_type): +def get_mechanism( + key_type: pkcs11.mechanisms.KeyType, +) -> tuple[pkcs11.mechanisms.Mechanism, tuple | None]: if key_type == pkcs11.mechanisms.KeyType.RSA: return pkcs11.mechanisms.Mechanism.SHA256_RSA_PKCS_PSS, ( pkcs11.mechanisms.Mechanism.SHA256, @@ -166,15 +179,15 @@ def get_mechanism(key_type): elif key_type == pkcs11.mechanisms.KeyType.EC: return pkcs11.mechanisms.Mechanism.ECDSA_SHA256, None else: - print("Invalid signing key mechanism") + log.error("Invalid signing key mechanism.") sys.exit(1) -def close_connection(session): +def close_connection(session: pkcs11.Session): try: session.close() - print("Connection closed successfully") + log.print("Connection closed successfully.") except pkcs11.exceptions.PKCS11Error as e: handle_exceptions(e) - print("Failed to close the HSM session") + log.error("Failed to close the HSM session.") sys.exit(1) diff --git a/tools/esptool_py/espsecure/esp_hsm_sign/exceptions.py b/tools/esptool_py/espsecure/esp_hsm_sign/exceptions.py index 47ba8e3b03..07a6414a57 100644 --- a/tools/esptool_py/espsecure/esp_hsm_sign/exceptions.py +++ b/tools/esptool_py/espsecure/esp_hsm_sign/exceptions.py @@ -1,7 +1,9 @@ -# SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD +# SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD # # SPDX-License-Identifier: GPL-2.0-or-later +from esptool.logger import log + from pkcs11.exceptions import ( AlreadyInitialized, AnotherUserAlreadyLoggedIn, @@ -20,31 +22,33 @@ def handle_exceptions(e, info=""): exception_type = e.__class__ if exception_type == MechanismInvalid: - print("The External HSM does not support the given mechanism", info) + log.error(f"The External HSM does not support the given mechanism: {info}") elif exception_type == FunctionFailed: - print( - "Please ensure proper configuration, privileges and environment variables" + log.error( + "Please ensure proper configuration, privileges and environment variables." ) elif exception_type == AlreadyInitialized: - print("pkcs11 is already initialized with another library") + log.error("pkcs11 is already initialized with another library.") elif exception_type == AnotherUserAlreadyLoggedIn: - print("Another User has been already logged in") + log.error("Another User has been already logged in.") elif exception_type == ArgumentsBad: - print("Please check the arguments supplied to the function") + log.error("Please check the arguments supplied to the function.") elif exception_type == DomainParamsInvalid: - print("Invalid or unsupported domain parameters were supplied to the function") + log.error( + "Invalid or unsupported domain parameters were supplied to the function." + ) elif exception_type == DeviceRemoved: - print( + log.error( "The token has been removed from its slot during " - "the execution of the function" + "the execution of the function." ) elif exception_type == NoSuchToken: - print("No such token found") + log.error("No such token found.") elif exception_type == NoSuchKey: - print("No such key found") + log.error("No such key found.") elif exception_type == OperationNotInitialized: - print("Operation not Initialized") + log.error("Operation not initialized.") elif exception_type == SessionClosed: - print("Session already closed") + log.error("Session already closed.") else: - print(e.__class__, info) + log.error(f"{e.__class__}: {info}") diff --git a/tools/esptool_py/esptool/__init__.py b/tools/esptool_py/esptool/__init__.py index 7f919bc3f4..1060dae31c 100644 --- a/tools/esptool_py/esptool/__init__.py +++ b/tools/esptool_py/esptool/__init__.py @@ -1,8 +1,8 @@ -# SPDX-FileCopyrightText: 2014-2022 Fredrik Ahlberg, Angus Gratton, +# SPDX-FileCopyrightText: 2014-2025 Fredrik Ahlberg, Angus Gratton, # Espressif Systems (Shanghai) CO LTD, other contributors as noted. # # SPDX-License-Identifier: GPL-2.0-or-later -# PYTHON_ARGCOMPLETE_OK + __all__ = [ "chip_id", "detect_chip", @@ -11,16 +11,19 @@ "erase_flash", "erase_region", "flash_id", + "attach_flash", "get_security_info", "image_info", "load_ram", - "make_image", "merge_bin", "read_flash", "read_flash_status", + "read_flash_sfdp", "read_mac", "read_mem", + "reset_chip", "run", + "run_stub", "verify_flash", "version", "write_flash", @@ -28,19 +31,17 @@ "write_mem", ] -__version__ = "4.8.1" +__version__ = "5.0.0" -import argparse -import inspect import os import shlex import sys import time import traceback +import rich_click as click +import typing as t -from esptool.bin_image import intel_hex_to_bin from esptool.cmds import ( - DETECTED_FLASH_SIZES, chip_id, detect_chip, detect_flash_size, @@ -48,18 +49,20 @@ elf2image, erase_flash, erase_region, + attach_flash, flash_id, read_flash_sfdp, get_security_info, image_info, load_ram, - make_image, merge_bin, read_flash, read_flash_status, read_mac, read_mem, + reset_chip, run, + run_stub, verify_flash, version, write_flash, @@ -74,1019 +77,976 @@ ESPLoader, list_ports, ) +from esptool.logger import log from esptool.targets import CHIP_DEFS, CHIP_LIST, ESP32ROM from esptool.util import ( FatalError, NotImplementedInROMError, + check_deprecated_py_suffix, flash_size_bytes, - strip_chip_name, ) from itertools import chain, cycle, repeat import serial +from esptool.cli_util import ( + AutoSizeType, + Group, + AddrFilenameArg, + AutoChunkSizeType, + ChipType, + AnyIntType, + OptionEatAll, + MutuallyExclusiveOption, + ResetModeType, + SpiConnectionType, + AutoHex2BinType, + AddrFilenamePairType, + parse_port_filters, + parse_size_arg, +) -def main(argv=None, esp=None): - """ - Main function for esptool - - argv - Optional override for default arguments parsing (that uses sys.argv), - can be a list of custom arguments as strings. Arguments and their values - need to be added as individual items to the list - e.g. "-b 115200" thus becomes ['-b', '115200']. - - esp - Optional override of the connected device previously - returned by get_default_connected_device() - """ - - external_esp = esp is not None - - parser = argparse.ArgumentParser( - description="esptool.py v%s - Espressif chips ROM Bootloader Utility" - % __version__, - prog="esptool", - ) - - parser.add_argument( - "--chip", - "-c", - help="Target chip type", - type=strip_chip_name, - choices=["auto"] + CHIP_LIST, - default=os.environ.get("ESPTOOL_CHIP", "auto"), - ) - - parser.add_argument( - "--port", - "-p", - help="Serial port device", - default=os.environ.get("ESPTOOL_PORT", None), - ) - - parser.add_argument( - "--baud", - "-b", - help="Serial port baud rate used when flashing/reading", - type=arg_auto_int, - default=os.environ.get("ESPTOOL_BAUD", ESPLoader.ESP_ROM_BAUD), - ) - - parser.add_argument( - "--port-filter", - action="append", - help="Serial port device filter, can be vid=NUMBER, pid=NUMBER, name=SUBSTRING", - type=str, - default=[], - ) - - parser.add_argument( - "--before", - help="What to do before connecting to the chip", - choices=["default_reset", "usb_reset", "no_reset", "no_reset_no_sync"], - default=os.environ.get("ESPTOOL_BEFORE", "default_reset"), - ) - - parser.add_argument( - "--after", - "-a", - help="What to do after esptool.py is finished", - choices=["hard_reset", "soft_reset", "no_reset", "no_reset_stub"], - default=os.environ.get("ESPTOOL_AFTER", "hard_reset"), - ) - - parser.add_argument( - "--no-stub", - help="Disable launching the flasher stub, only talk to ROM bootloader. " - "Some features will not be available.", - action="store_true", - ) - - # --stub-version can be set with --no-stub so the tests wouldn't fail if this option is implied globally - parser.add_argument( - "--stub-version", - default=os.environ.get("ESPTOOL_STUB_VERSION", StubFlasher.STUB_SUBDIRS[0]), - choices=StubFlasher.STUB_SUBDIRS, - # not a public option and is not subject to the semantic versioning policy - help=argparse.SUPPRESS, - ) - - parser.add_argument( - "--trace", - "-t", - help="Enable trace-level output of esptool.py interactions.", - action="store_true", - ) - - parser.add_argument( - "--override-vddsdio", - help="Override ESP32 VDDSDIO internal voltage regulator (use with care)", - choices=ESP32ROM.OVERRIDE_VDDSDIO_CHOICES, - nargs="?", - ) - - parser.add_argument( - "--connect-attempts", - help=( - "Number of attempts to connect, negative or 0 for infinite. " - "Default: %d." % DEFAULT_CONNECT_ATTEMPTS - ), - type=int, - default=os.environ.get("ESPTOOL_CONNECT_ATTEMPTS", DEFAULT_CONNECT_ATTEMPTS), - ) +# Show arguments in the help output, this was default in argparse +click.rich_click.SHOW_ARGUMENTS = True +# Force alignment of commands table with groups +click.rich_click.STYLE_COMMANDS_TABLE_COLUMN_WIDTH_RATIO = (1, 3) +# Option group definitions, used for grouping options in the help output +# Similar to 'add_argument_group' from argparse +click.rich_click.OPTION_GROUPS = { + "* merge-bin": [ + { + "name": "UF2 options", + "options": [ + "--chunk-size", + "--md5-disable", + ], + }, + { + "name": "RAW options", + "options": [ + "--target-offset", + "--pad-to-size", + ], + }, + ], + "*": [ + { + "name": "Flash options", + "options": [ + "--flash-freq", + "--flash-mode", + "--flash-size", + "--spi-connection", + ], + } + ], +} +click.rich_click.COMMAND_GROUPS = { + "*": [ + { + "name": "Basic commands", + "commands": [ + "write-flash", + "read-flash", + "erase-flash", + "erase-region", + "read-mac", + "flash-id", + "elf2image", + "image-info", + "merge-bin", + "version", + ], + }, + { + "name": "Advanced commands", + "commands": [ + "verify-flash", + "load-ram", + "dump-mem", + "read-mem", + "write-mem", + "read-flash-status", + "write-flash-status", + "read-flash-sfdp", + "get-security-info", + "chip-id", + "run", + ], + }, + ], +} - subparsers = parser.add_subparsers( - dest="operation", help="Run esptool.py {command} -h for additional help" - ) +################################### REUSABLE OPTIONS ################################### - def add_spi_connection_arg(parent): - parent.add_argument( - "--spi-connection", - "-sc", - help="Override default SPI Flash connection. " - "Value can be SPI, HSPI or a comma-separated list of 5 I/O numbers " - "to use for SPI flash (CLK,Q,D,HD,CS). Not supported with ESP8266.", - action=SpiConnectionAction, - ) - parser_load_ram = subparsers.add_parser( - "load_ram", help="Download an image to RAM and execute" - ) - parser_load_ram.add_argument( - "filename", help="Firmware image", action=AutoHex2BinAction - ) +def add_spi_connection_arg(function): + function = click.option( + "--spi-connection", + "-sc", + help="Override default SPI flash memory connection. " + "Value can be SPI, HSPI or a comma-separated list of 5 I/O numbers " + "to use for SPI flash (CLK,Q,D,HD,CS). Not supported with ESP8266.", + type=SpiConnectionType(), + )(function) + return function - parser_dump_mem = subparsers.add_parser( - "dump_mem", help="Dump arbitrary memory to disk" - ) - parser_dump_mem.add_argument("address", help="Base address", type=arg_auto_int) - parser_dump_mem.add_argument( - "size", help="Size of region to dump", type=arg_auto_int - ) - parser_dump_mem.add_argument("filename", help="Name of binary dump") - parser_read_mem = subparsers.add_parser( - "read_mem", help="Read arbitrary memory location" - ) - parser_read_mem.add_argument("address", help="Address to read", type=arg_auto_int) +def add_spi_flash_options( + allow_keep: bool = False, auto_detect: bool = False, size_only: bool = False +) -> t.Callable: + """Add common parser arguments for SPI flash properties""" - parser_write_mem = subparsers.add_parser( - "write_mem", help="Read-modify-write to arbitrary memory location" - ) - parser_write_mem.add_argument("address", help="Address to write", type=arg_auto_int) - parser_write_mem.add_argument("value", help="Value", type=arg_auto_int) - parser_write_mem.add_argument( - "mask", - help="Mask of bits to write", - type=arg_auto_int, - nargs="?", - default="0xFFFFFFFF", - ) + extra_keep_args = ["keep"] if allow_keep else [] - 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""" - extra_keep_args = ["keep"] if allow_keep else [] - - if auto_detect and allow_keep: - extra_fs_message = ", detect, or keep" - flash_sizes = ["detect", "keep"] - elif auto_detect: - extra_fs_message = ", or detect" - flash_sizes = ["detect"] - elif allow_keep: - extra_fs_message = ", or keep" - flash_sizes = ["keep"] - else: - extra_fs_message = "" - flash_sizes = [] + flash_sizes = [] + if auto_detect: + flash_sizes.append("detect") + if allow_keep: + flash_sizes.append("keep") + def wrapper(function): if not size_only: - parent.add_argument( - "--flash_freq", + function = click.option( + "--flash-freq", "-ff", - help="SPI Flash frequency", - choices=extra_keep_args - + [ - "80m", - "60m", - "48m", - "40m", - "30m", - "26m", - "24m", - "20m", - "16m", - "15m", - "12m", - ], + help="SPI flash memory frequency.", + type=click.Choice( + extra_keep_args + + [ + "80m", + "60m", + "48m", + "40m", + "30m", + "26m", + "24m", + "20m", + "16m", + "15m", + "12m", + ] + ), default=os.environ.get("ESPTOOL_FF", "keep" if allow_keep else None), - ) - parent.add_argument( - "--flash_mode", + )(function) + function = click.option( + "--flash-mode", "-fm", - help="SPI Flash mode", - choices=extra_keep_args + ["qio", "qout", "dio", "dout"], + help="SPI flash memory mode.", + type=click.Choice(extra_keep_args + ["qio", "qout", "dio", "dout"]), default=os.environ.get("ESPTOOL_FM", "keep" if allow_keep else "qio"), - ) + )(function) - parent.add_argument( - "--flash_size", + function = click.option( + "--flash-size", "-fs", - help="SPI Flash size in MegaBytes " - "(1MB, 2MB, 4MB, 8MB, 16MB, 32MB, 64MB, 128MB) " - "plus ESP8266-only (256KB, 512KB, 2MB-c1, 4MB-c1)" + extra_fs_message, - choices=flash_sizes - + [ - "256KB", - "512KB", - "1MB", - "2MB", - "2MB-c1", - "4MB", - "4MB-c1", - "8MB", - "16MB", - "32MB", - "64MB", - "128MB", - ], + help="SPI flash memory size. " + "ESP8266-only sizes: 256KB, 512KB, 2MB-c1, 4MB-c1.", + type=click.Choice( + flash_sizes + + [ + "256KB", + "512KB", + "1MB", + "2MB", + "2MB-c1", + "4MB", + "4MB-c1", + "8MB", + "16MB", + "32MB", + "64MB", + "128MB", + ] + ), default=os.environ.get("ESPTOOL_FS", "keep" if allow_keep else "1MB"), - ) - add_spi_connection_arg(parent) + )(function) + return function - parser_write_flash = subparsers.add_parser( - "write_flash", help="Write a binary blob to flash" - ) + return wrapper - parser_write_flash.add_argument( - "addr_filename", - metavar="
", - help="Address followed by binary filename, separated by space", - action=AddrFilenamePairAction, - ) - parser_write_flash.add_argument( - "--erase-all", - "-e", - help="Erase all regions of flash (not just write areas) before programming", - action="store_true", - ) - add_spi_flash_subparsers(parser_write_flash, allow_keep=True, auto_detect=True) - parser_write_flash.add_argument( - "--no-progress", "-p", help="Suppress progress output", action="store_true" - ) - parser_write_flash.add_argument( - "--verify", - help="Verify just-written data on flash " - "(mostly superfluous, data is read back during flashing)", - action="store_true", - ) - parser_write_flash.add_argument( - "--encrypt", - help="Apply flash encryption when writing data " - "(required correct efuse settings)", - action="store_true", - ) - # In order to not break backward compatibility, - # our list of encrypted files to flash is a new parameter - parser_write_flash.add_argument( - "--encrypt-files", - metavar="
", - help="Files to be encrypted on the flash. " - "Address followed by binary filename, separated by space.", - action=AddrFilenamePairAction, - ) - parser_write_flash.add_argument( - "--ignore-flash-encryption-efuse-setting", - help="Ignore flash encryption efuse settings ", - action="store_true", - ) - parser_write_flash.add_argument( - "--force", - help="Force write, skip security and compatibility checks. Use with caution!", - action="store_true", - ) - - compress_args = parser_write_flash.add_mutually_exclusive_group(required=False) - compress_args.add_argument( - "--compress", - "-z", - help="Compress data in transfer (default unless --no-stub is specified)", - action="store_true", - default=None, - ) - compress_args.add_argument( - "--no-compress", - "-u", - help="Disable data compression during transfer " - "(default if --no-stub is specified)", - action="store_true", - ) - - subparsers.add_parser("run", help="Run application code in flash") - - parser_image_info = subparsers.add_parser( - "image_info", help="Dump headers from a binary file (bootloader or application)" - ) - parser_image_info.add_argument( - "filename", help="Image file to parse", action=AutoHex2BinAction - ) - parser_image_info.add_argument( - "--version", - "-v", - help="Output format version (1 - legacy, 2 - extended)", - choices=["1", "2"], - default="1", - ) - - parser_make_image = subparsers.add_parser( - "make_image", help="Create an application image from binary files" - ) - parser_make_image.add_argument("output", help="Output image file") - parser_make_image.add_argument( - "--segfile", "-f", action="append", help="Segment input file" - ) - parser_make_image.add_argument( - "--segaddr", - "-a", - action="append", - help="Segment base address", - type=arg_auto_int, - ) - parser_make_image.add_argument( - "--entrypoint", - "-e", - help="Address of entry point", - type=arg_auto_int, - default=0, - ) - - parser_elf2image = subparsers.add_parser( - "elf2image", help="Create an application image from ELF file" - ) - parser_elf2image.add_argument("input", help="Input ELF file") - parser_elf2image.add_argument( - "--output", - "-o", - help="Output filename prefix (for version 1 image), " - "or filename (for version 2 single image)", - type=str, - ) - parser_elf2image.add_argument( - "--version", - "-e", - help="Output image version", - choices=["1", "2", "3"], - default="1", - ) - parser_elf2image.add_argument( - # it kept for compatibility - # Minimum chip revision (deprecated, consider using --min-rev-full) - "--min-rev", - "-r", - help=argparse.SUPPRESS, - type=int, - choices=range(256), - metavar="{0, ... 255}", - default=0, - ) - parser_elf2image.add_argument( - "--min-rev-full", - help="Minimal chip revision (in format: major * 100 + minor)", - type=int, - choices=range(65536), - metavar="{0, ... 65535}", - default=0, - ) - parser_elf2image.add_argument( - "--max-rev-full", - help="Maximal chip revision (in format: major * 100 + minor)", - type=int, - choices=range(65536), - metavar="{0, ... 65535}", - default=65535, - ) - parser_elf2image.add_argument( - "--secure-pad", - action="store_true", - help="Pad image so once signed it will end on a 64KB boundary. " - "For Secure Boot v1 images only.", - ) - parser_elf2image.add_argument( - "--secure-pad-v2", - action="store_true", - help="Pad image to 64KB, so once signed its signature sector will" - "start at the next 64K block. For Secure Boot v2 images only.", - ) - parser_elf2image.add_argument( - "--elf-sha256-offset", - help="If set, insert SHA256 hash (32 bytes) of the input ELF file " - "at specified offset in the binary.", - type=arg_auto_int, - default=None, - ) - parser_elf2image.add_argument( - "--dont-append-digest", - dest="append_digest", - help="Don't append a SHA256 digest of the entire image after the checksum. " - "This argument is not supported and ignored for ESP8266.", - action="store_false", - default=True, - ) - parser_elf2image.add_argument( - "--use_segments", - help="If set, ELF segments will be used instead of ELF sections " - "to generate the image.", - action="store_true", - ) - parser_elf2image.add_argument( - "--flash-mmu-page-size", - help="Change flash MMU page size.", - choices=["64KB", "32KB", "16KB", "8KB"], - ) - parser_elf2image.add_argument( - "--pad-to-size", - help="The block size with which the final binary image after padding " - "must be aligned to. Value 0xFF is used for padding, similar to erase_flash", - default=None, - ) - parser_elf2image.add_argument( - "--ram-only-header", - help="Order segments of the output so IRAM and DRAM are placed at the " - "beginning and force the main header segment number to RAM segments " - "quantity. This will make the other segments invisible to the ROM " - "loader. Use this argument with care because the ROM loader will load " - "only the RAM segments although the other segments being present in " - "the output. Implies --dont-append-digest", - action="store_true", - default=None, - ) +def check_flash_size(esp: ESPLoader, address: int, size: int) -> None: + # Check if we are writing/erasing/reading past 16MB boundary + if ( + not (esp.IS_STUB and esp.CHIP_NAME in ["ESP32-S3", "ESP32-P4"]) + and address + size > 0x1000000 + ): + raise FatalError( + f"Can't access flash regions larger than 16MB " + f"(set size {size:#x} from address {address:#010x} goes past 16MB " + f"by {address + size - 0x1000000:#x} bytes)." + ) + # Check if we are writing/reading past detected flash size + if not esp.secure_download_mode: + detected_size_str = detect_flash_size(esp) + if not detected_size_str: + return + detected_size = flash_size_bytes(detected_size_str) + if address + size > detected_size: + raise FatalError( + f"Can't access flash regions larger than detected flash size " + f"(set size {size:#x} from address {address:#010x} goes past " + f"{detected_size_str} by {address + size - detected_size:#x} bytes)." + ) - add_spi_flash_subparsers(parser_elf2image, allow_keep=False, auto_detect=False) - subparsers.add_parser("read_mac", help="Read MAC address from OTP ROM") +############################### GLOBAL OPTIONS AND MAIN ############################### - subparsers.add_parser("chip_id", help="Read Chip ID from OTP ROM") - parser_flash_id = subparsers.add_parser( - "flash_id", help="Read SPI flash manufacturer and device ID" - ) - add_spi_connection_arg(parser_flash_id) +@click.group( + cls=Group, + no_args_is_help=True, + context_settings=dict(help_option_names=["-h", "--help"], max_content_width=120), + help=f"esptool v{__version__} - serial utility for flashing, provisioning, " + "and interacting with Espressif SoCs.", +) +@click.option( + "--chip", + "-c", + type=ChipType(["auto"] + CHIP_LIST), + default=os.environ.get("ESPTOOL_CHIP", "auto"), + help="Target chip type.", +) +@click.option( + "--port", + "-p", + type=click.Path(), + default=os.environ.get("ESPTOOL_PORT", None), + help="Serial port device.", +) +@click.option( + "--baud", + "-b", + type=AnyIntType(), + default=os.environ.get("ESPTOOL_BAUD", ESPLoader.ESP_ROM_BAUD), + help="Serial port baud rate used when flashing/reading.", +) +@click.option( + "--port-filter", + multiple=True, + type=str, + cls=OptionEatAll, + help="Serial port device filter, can be vid=NUMBER, pid=NUMBER, name=SUBSTRING, " + "serial=SUBSTRING.", +) +@click.option( + "--before", + type=ResetModeType(["default-reset", "usb-reset", "no-reset", "no-reset-no-sync"]), + default=os.environ.get("ESPTOOL_BEFORE", "default-reset"), + help="Which reset to perform before connecting to the chip.", +) +@click.option( + "--after", + "-a", + type=ResetModeType( + ["hard-reset", "soft-reset", "no-reset", "no-reset-stub", "watchdog-reset"] + ), + default=os.environ.get("ESPTOOL_AFTER", "hard-reset"), + help="Which reset to perform after operation is finished.", +) +@click.option( + "--no-stub", + is_flag=True, + help="Disable launching the flasher stub, only talk to ROM bootloader. " + "Some features will not be available.", +) +# --stub-version can be set with --no-stub so the tests wouldn't fail if this option +# is implied globally +@click.option( + "--stub-version", + default=os.environ.get("ESPTOOL_STUB_VERSION", "1"), + type=click.Choice(["1", "2"]), + # not a public option and is not subject to the semantic versioning policy + hidden=True, +) +@click.option( + "--trace", + "-t", + is_flag=True, + help="Enable trace-level output of esptool interactions.", +) +@click.option( + "--verbose", + "-v", + is_flag=True, + help="Print all output, disable collapsing output stages.", +) +@click.option( + "--silent", + "-s", + is_flag=True, + help="Silence all output except for errors.", +) +@click.option( + "--override-vddsdio", + type=click.Choice(ESP32ROM.OVERRIDE_VDDSDIO_CHOICES), + help="Override ESP32 VDDSDIO internal voltage regulator (use with care).", +) +@click.option( + "--connect-attempts", + type=int, + default=os.environ.get("ESPTOOL_CONNECT_ATTEMPTS", DEFAULT_CONNECT_ATTEMPTS), + help=f"Number of attempts to connect, negative or 0 for infinite. " + f"Default: {DEFAULT_CONNECT_ATTEMPTS}.", +) +@click.pass_context +def cli( + ctx, + **kwargs, +): + ctx.ensure_object(dict) + ctx.obj.update(kwargs) + if ctx.obj["verbose"] and ctx.obj["silent"]: + raise FatalError( + "Cannot use both --verbose and --silent options at the same time." + ) + if ctx.obj["trace"] and ctx.obj["silent"]: + raise FatalError( + "Cannot use both --trace and --silent options at the same time." + ) + if ctx.obj["verbose"]: + log.set_verbosity("verbose") + elif ctx.obj["silent"]: + log.set_verbosity("silent") + ctx.obj["invoked_subcommand"] = ctx.invoked_subcommand + ctx.obj["esp"] = getattr(ctx, "esp", None) + log.print(f"esptool v{__version__}") + load_config_file(verbose=True) - parser_read_status = subparsers.add_parser( - "read_flash_status", help="Read SPI flash status register" - ) - add_spi_connection_arg(parser_read_status) - parser_read_status.add_argument( - "--bytes", - help="Number of bytes to read (1-3)", - type=int, - choices=[1, 2, 3], - default=2, - ) +def prepare_esp_object(ctx): + """Prepare ESP object for operation""" + StubFlasher.set_stub_subdir(ctx.obj["stub_version"]) + # Commands that require an ESP object (flash read/write, etc.) + # 1) Get the ESP object + ####################### - parser_write_status = subparsers.add_parser( - "write_flash_status", help="Write SPI flash status register" - ) + # Disable output stage collapsing, colors, and overwriting in trace mode + if ctx.obj["trace"]: + log._smart_features = False - add_spi_connection_arg(parser_write_status) - parser_write_status.add_argument( - "--non-volatile", - help="Write non-volatile bits (use with caution)", - action="store_true", - ) - parser_write_status.add_argument( - "--bytes", - help="Number of status bytes to write (1-3)", - type=int, - choices=[1, 2, 3], - default=2, - ) - parser_write_status.add_argument("value", help="New value", type=arg_auto_int) + log.stage() - parser_read_flash = subparsers.add_parser( - "read_flash", help="Read SPI flash content" - ) - 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( - "size", - help="Size of region to dump. Use `ALL` to read to the end of flash.", - type=arg_auto_size, - ) - parser_read_flash.add_argument("filename", help="Name of binary dump") - parser_read_flash.add_argument( - "--no-progress", "-p", help="Suppress progress output", action="store_true" - ) + if ctx.obj["before"] != "no-reset-no-sync": + initial_baud = min( + ESPLoader.ESP_ROM_BAUD, ctx.obj["baud"] + ) # don't sync faster than the default baud rate + else: + initial_baud = ctx.obj["baud"] - parser_verify_flash = subparsers.add_parser( - "verify_flash", help="Verify a binary blob against flash" - ) - parser_verify_flash.add_argument( - "addr_filename", - help="Address and binary file to verify there, separated by space", - action=AddrFilenamePairAction, + if ctx.obj["port"] is None: + filters = parse_port_filters(ctx.obj["port_filter"]) + ser_list = get_port_list(*filters) + log.print(f"Found {len(ser_list)} serial ports...") + else: + ser_list = [ctx.obj["port"]] + open_port_attempts = os.environ.get( + "ESPTOOL_OPEN_PORT_ATTEMPTS", DEFAULT_OPEN_PORT_ATTEMPTS ) - parser_verify_flash.add_argument( - "--diff", "-d", help="Show differences", choices=["no", "yes"], default="no" + try: + open_port_attempts = int(open_port_attempts) + except ValueError: + raise SystemExit("Invalid value for ESPTOOL_OPEN_PORT_ATTEMPTS.") + + esp = ctx.obj.get("esp", None) + ctx.obj["external_esp"] = esp is not None + if open_port_attempts != 1: + if ctx.obj["port"] is None or ctx.obj["chip"] == "auto": + log.warning( + "The ESPTOOL_OPEN_PORT_ATTEMPTS (open_port_attempts) option " + "can only be used with --port and --chip arguments." + ) + else: + esp = esp or connect_loop( + ctx.obj["port"], + initial_baud, + ctx.obj["chip"], + open_port_attempts, + ctx.obj["trace"], + ctx.obj["before"], + ) + esp = esp or get_default_connected_device( + ser_list, + port=ctx.obj["port"], + connect_attempts=ctx.obj["connect_attempts"], + initial_baud=initial_baud, + chip=ctx.obj["chip"], + trace=ctx.obj["trace"], + before=ctx.obj["before"], ) - add_spi_flash_subparsers(parser_verify_flash, allow_keep=True, auto_detect=True) - parser_erase_flash = subparsers.add_parser( - "erase_flash", help="Perform Chip Erase on SPI flash" - ) - parser_erase_flash.add_argument( - "--force", - help="Erase flash even if security features are enabled. Use with caution!", - action="store_true", - ) - add_spi_connection_arg(parser_erase_flash) + if esp is None: + raise FatalError( + "Could not connect to an Espressif device " + f"on any of the {len(ser_list)} available serial ports." + ) - parser_erase_region = subparsers.add_parser( - "erase_region", help="Erase a region of the flash" - ) - parser_erase_region.add_argument( - "--force", - help="Erase region even if security features are enabled. Use with caution!", - action="store_true", - ) - add_spi_connection_arg(parser_erase_region) - parser_erase_region.add_argument( - "address", help="Start address (must be multiple of 4096)", type=arg_auto_int - ) - parser_erase_region.add_argument( - "size", - help="Size of region to erase (must be multiple of 4096). " - "Use `ALL` to erase to the end of flash.", - type=arg_auto_size, - ) + log.stage(finish=True) + log.print(f"Connected to {esp.CHIP_NAME} on {esp._port.port}:") - parser_read_flash_sfdp = subparsers.add_parser( - "read_flash_sfdp", - help="Read SPI flash SFDP (Serial Flash Discoverable Parameters)", - ) - add_spi_flash_subparsers(parser_read_flash_sfdp, allow_keep=True, auto_detect=True) - parser_read_flash_sfdp.add_argument("addr", type=arg_auto_int) - parser_read_flash_sfdp.add_argument("bytes", type=int) + # 2) Print the chip info + ######################## - parser_merge_bin = subparsers.add_parser( - "merge_bin", - help="Merge multiple raw binary files into a single file for later flashing", - ) + if esp.secure_download_mode: + log.print(f"{'Chip type:':<20}{esp.CHIP_NAME} in Secure Download Mode") + else: + log.print(f"{'Chip type:':<20}{esp.get_chip_description()}") + log.print(f"{'Features:':<20}{', '.join(esp.get_chip_features())}") + log.print(f"{'Crystal frequency:':<20}{esp.get_crystal_freq()}MHz") + usb_mode = esp.get_usb_mode() + if usb_mode is not None: + log.print(f"{'USB mode:':<20}{usb_mode}") + read_mac(esp) + log.print() + + # 3) Perform sanity checks + ########################## + + if esp.secure_download_mode and ctx.obj["invoked_subcommand"] not in ( + "get-security-info", + "write-flash", + "erase-region", + ): + raise FatalError( + f"The '{ctx.obj['invoked_subcommand']}' command is not available " + "in Secure Download Mode." + ) - parser_merge_bin.add_argument( - "--output", "-o", help="Output filename", type=str, required=True - ) - parser_merge_bin.add_argument( - "--format", - "-f", - help="Format of the output file", - choices=["raw", "uf2", "hex"], - default="raw", - ) - uf2_group = parser_merge_bin.add_argument_group("UF2 format") - uf2_group.add_argument( - "--chunk-size", - help="Specify the used data part of the 512 byte UF2 block. " - "A common value is 256. By default the largest possible value will be used.", - default=None, - type=arg_auto_chunk_size, - ) - uf2_group.add_argument( - "--md5-disable", - help="Disable MD5 checksum in UF2 output", - action="store_true", - ) - add_spi_flash_subparsers(parser_merge_bin, allow_keep=True, auto_detect=False) - - raw_group = parser_merge_bin.add_argument_group("RAW format") - raw_group.add_argument( - "--target-offset", - "-t", - help="Target offset where the output file will be flashed", - type=arg_auto_int, - default=0, - ) - raw_group.add_argument( - "--fill-flash-size", - help="If set, the final binary file will be padded with FF " - "bytes up to this flash size.", - choices=[ - "256KB", - "512KB", - "1MB", - "2MB", - "4MB", - "8MB", - "16MB", - "32MB", - "64MB", - "128MB", - ], - ) - parser_merge_bin.add_argument( - "addr_filename", - metavar="
", - help="Address followed by binary filename, separated by space", - action=AddrFilenamePairAction, - ) + # 4) Upload the stub flasher + ############################ - subparsers.add_parser("get_security_info", help="Get some security-related data") + if not ctx.obj["no_stub"]: + esp = run_stub(esp) - subparsers.add_parser("version", help="Print esptool version") + # 5) Configure the baud rate and voltage regulator + ################################################## - # internal sanity check - every operation matches a module function of the same name - for operation in subparsers.choices.keys(): - assert operation in globals(), "%s should be a module function" % operation + if ctx.obj["override_vddsdio"]: + esp.override_vddsdio(ctx.obj["override_vddsdio"]) - # Enable argcomplete only on Unix-like systems - if sys.platform != "win32": + if ctx.obj["baud"] > initial_baud: try: - import argcomplete + esp.change_baud(ctx.obj["baud"]) + except NotImplementedInROMError: + log.warning( + f"ROM doesn't support changing baud rate. " + f"Keeping initial baud rate {initial_baud}." + ) - argcomplete.autocomplete(parser) - except ImportError: - pass + # 6) Prepare to run the operation + ################################# + # Running operation is done inside each command function, as they have different + # arguments and behaviour + # Prepare object for operation (commands) + ctx.obj["esp"] = esp + log.print() + + # 7) Attach the onboard/external flash chip and perform command + ############################################################### + # This will follow in command-specific functions or argument processing decorators + # After the command is done (either successfully or with an error), the following + # teardown function will be called + + @ctx.call_on_close + def teardown(): + """Common teardown for all commands with chip - reset chip and close port""" + # 8) Close all open files + ######################### + for f in getattr(ctx, "_open_files", []): + f.close() + + # 9) Reset the chip + ################### + log.print() + # Handle post-operation behaviour (reset or other) + if ctx.obj["invoked_subcommand"] == "load-ram": + # the ESP is now running the loaded image, so let it run + log.print("Exiting immediately.") + else: + reset_chip(esp, ctx.obj["after"]) - argv = expand_file_arguments(argv or sys.argv[1:]) + # 10) Finish and close the port + ############################## - args = parser.parse_args(argv) - print("esptool.py v%s" % __version__) - load_config_file(verbose=True) + if not ctx.obj["external_esp"]: + esp._port.close() - StubFlasher.set_preferred_stub_subdir(args.stub_version) - - # Parse filter arguments into separate lists - args.filterVids = [] - args.filterPids = [] - args.filterNames = [] - for f in args.port_filter: - kvp = f.split("=") - if len(kvp) != 2: - raise FatalError("Option --port-filter argument must consist of key=value") - if kvp[0] == "vid": - args.filterVids.append(arg_auto_int(kvp[1])) - elif kvp[0] == "pid": - args.filterPids.append(arg_auto_int(kvp[1])) - elif kvp[0] == "name": - args.filterNames.append(kvp[1]) - else: - raise FatalError("Option --port-filter argument key not recognized") - # operation function can take 1 arg (args), 2 args (esp, arg) - # or be a member function of the ESPLoader class. +###################################### COMMANDS ####################################### - if args.operation is None: - parser.print_help() - sys.exit(1) +@cli.command("load-ram") +@click.argument("filename", type=AutoHex2BinType()) +@click.pass_context +def load_ram_cli(ctx, filename: list[tuple[int | None, t.IO[bytes]]]): + """Download an image to RAM and execute.""" + if len(filename) > 1: + raise FatalError( + "Merged binary image detected. " + "Only one file can be specified for the load-ram command." + ) + prepare_esp_object(ctx) + load_ram(ctx.obj["esp"], filename[0][1].name) + + +@cli.command("dump-mem") +@click.argument("address", type=AnyIntType()) +@click.argument("size", type=AutoSizeType(allow_all=False)) +@click.argument("output", type=click.Path()) +@click.pass_context +def dump_mem_cli(ctx, address, size, output): + """Dump arbitrary memory to a file.""" + prepare_esp_object(ctx) + dump_mem(ctx.obj["esp"], address, size, output) + + +@cli.command("read-mem") +@click.argument("address", type=AnyIntType()) +@click.pass_context +def read_mem_cli(ctx, address): + """Read arbitrary memory location.""" + prepare_esp_object(ctx) + read_mem(ctx.obj["esp"], address) + + +@cli.command("write-mem") +@click.argument("address", type=AnyIntType()) +@click.argument("value", type=AnyIntType()) +@click.argument("mask", type=AnyIntType(), default=0xFFFFFFFF) +@click.pass_context +def write_mem_cli(ctx, address, value, mask): + """Modify or write to arbitrary memory location.""" + prepare_esp_object(ctx) + write_mem(ctx.obj["esp"], address, value, mask) + + +@cli.command(name="write-flash") +@click.argument("addr-filename", nargs=-1, required=True, cls=AddrFilenameArg) +@click.option( + "--erase-all", + "-e", + is_flag=True, + help="Erase all regions of flash (not just write areas) before programming.", +) +@click.option("--no-progress", "-p", is_flag=True, help="Suppress progress output.") +@click.option( + "--encrypt", + is_flag=True, + help="Apply flash encryption when writing data (required correct eFuse settings).", +) +@click.option( + "--encrypt-files", + type=AddrFilenamePairType(), + cls=OptionEatAll, + help="Files to be encrypted during flashing. The address is followed by binary " + "filename, separated by space.", +) +@click.option( + "--ignore-flash-enc-efuse", + is_flag=True, + help="Ignore flash encryption eFuse settings.", +) +@click.option( + "--force", + is_flag=True, + help="Force write, skip security and compatibility checks. Use with caution!", +) +@click.option( + "--compress", + "-z", + is_flag=True, + help="Compress data during transfer (default unless --no-stub is specified).", + exclusive_with=["no-compress"], + cls=MutuallyExclusiveOption, +) +@click.option( + "--no-compress", + "-u", + is_flag=True, + default=False, + help="Disable data compression during transfer (default if --no-stub is specified)", + exclusive_with=["compress"], + cls=MutuallyExclusiveOption, +) +@add_spi_flash_options(allow_keep=True, auto_detect=True) +@add_spi_connection_arg +@click.pass_context +def write_flash_cli(ctx, addr_filename, **kwargs): + """Write a binary blob to flash. The address is followed by binary filename, + separated by space.""" # Forbid the usage of both --encrypt, which means encrypt all the given files, # and --encrypt-files, which represents the list of files to encrypt. # The reason is that allowing both at the same time increases the chances of # having contradictory lists (e.g. one file not available in one of list). - if ( - args.operation == "write_flash" - and args.encrypt - and args.encrypt_files is not None - ): + if kwargs["encrypt"] and kwargs["encrypt_files"] is not None: raise FatalError( "Options --encrypt and --encrypt-files " "must not be specified at the same time." ) + prepare_esp_object(ctx) + attach_flash(ctx.obj["esp"], kwargs.pop("spi_connection", None)) + write_flash(ctx.obj["esp"], addr_filename, **kwargs) + + +@cli.command("run") +@click.pass_context +def run_cli(ctx): + """Run application code loaded in flash.""" + prepare_esp_object(ctx) + attach_flash(ctx.obj["esp"]) + run(ctx.obj["esp"]) + + +@cli.command("image-info") +@click.argument("filename", type=AutoHex2BinType()) +@click.pass_context +def image_info_cli(ctx, filename: list[tuple[int | None, t.IO[bytes]]]): + """Print information about a firmware image (bootloader or application).""" + chip = None if ctx.obj["chip"] == "auto" else ctx.obj["chip"] + if len(filename) == 1: + image_info(filename[0][1].name, chip=chip) + else: + image_info(filename, chip=chip) # type: ignore - operation_func = globals()[args.operation] - operation_args = inspect.getfullargspec(operation_func).args - - if ( - operation_args[0] == "esp" - ): # operation function takes an ESPLoader connection object - if args.before != "no_reset_no_sync": - initial_baud = min( - ESPLoader.ESP_ROM_BAUD, args.baud - ) # don't sync faster than the default baud rate - else: - initial_baud = args.baud - if args.port is None: - ser_list = get_port_list(args.filterVids, args.filterPids, args.filterNames) - print("Found %d serial ports" % len(ser_list)) - else: - ser_list = [args.port] - open_port_attempts = os.environ.get( - "ESPTOOL_OPEN_PORT_ATTEMPTS", DEFAULT_OPEN_PORT_ATTEMPTS +@cli.command("elf2image") +@click.argument("filename", type=click.Path(exists=True)) +@click.option( + "--output", + "-o", + type=str, + help="Output filename or filename prefix (for ESP8266 v1 image).", +) +@click.option( + "--version", + "-e", + type=click.Choice(["1", "2", "3"]), + default="1", + help="Output image version.", +) +@click.option( + # Kept for compatibility + # Minimum chip revision (deprecated, consider using --min-rev-full) + "--min-rev", + "-r", + type=click.IntRange(0, 256), + default=0, + hidden=True, +) +@click.option( + "--min-rev-full", + type=click.IntRange(0, 65536), + default=0, + help="Minimal chip revision (in format: major * 100 + minor).", +) +@click.option( + "--max-rev-full", + type=click.IntRange(0, 65536), + default=65535, + help="Maximal chip revision (in format: major * 100 + minor).", +) +@click.option( + "--secure-pad", + is_flag=True, + help="Pad image so once signed it will end on a 64KB boundary. For Secure Boot " + "v1 images only.", +) +@click.option( + "--secure-pad-v2", + is_flag=True, + help="Pad image to 64KB, so once signed its signature sector will start at the " + "next 64K block. For Secure Boot v2 images only.", +) +@click.option( + "--elf-sha256-offset", + type=AnyIntType(), + default=None, + help="If set, insert SHA256 hash (32 bytes) of the input ELF file at specified " + "offset in the binary.", +) +@click.option( + "--dont-append-digest", + is_flag=True, + default=False, + help="Don't append a SHA256 digest of the entire image after the checksum. " + "This argument is not supported and ignored for ESP8266.", +) +@click.option( + "--use-segments", + is_flag=True, + help="If set, ELF segments will be used instead of ELF sections to generate the " + "image.", +) +@click.option( + "--flash-mmu-page-size", + type=click.Choice(["64KB", "32KB", "16KB", "8KB"]), + help="Change flash MMU page size.", +) +@click.option( + "--pad-to-size", + type=int, + default=None, + help="The block size to pad the final binary image to. " + "Value 0xFF is used for padding.", +) +@click.option( + "--ram-only-header", + is_flag=True, + help="Order segments so IRAM and DRAM are placed at the beginning " + "and force the main header segment number to RAM segments quantity. This will " + "make the other segments invisible to the ROM loader. Use with " + "care, the ROM loader will only load the RAM segments although the other " + "segments being present in the output. Implies --dont-append-digest.", +) +@add_spi_flash_options(allow_keep=False, auto_detect=False) +@click.pass_context +def elf2image_cli(ctx, filename, **kwargs): + """Create an application image from ELF file""" + if ctx.obj["chip"] == "auto": + raise FatalError( + f"Specify the --chip argument (choose from {', '.join(CHIP_LIST)})." ) - try: - open_port_attempts = int(open_port_attempts) - except ValueError: - raise SystemExit("Invalid value for ESPTOOL_OPEN_PORT_ATTEMPTS") - if open_port_attempts != 1: - if args.port is None or args.chip == "auto": - print( - "WARNING: The ESPTOOL_OPEN_PORT_ATTEMPTS (open_port_attempts) option can only be used with --port and --chip arguments." - ) - else: - esp = esp or connect_loop( - args.port, - initial_baud, - args.chip, - open_port_attempts, - args.trace, - args.before, - ) - esp = esp or get_default_connected_device( - ser_list, - port=args.port, - connect_attempts=args.connect_attempts, - initial_baud=initial_baud, - chip=args.chip, - trace=args.trace, - before=args.before, + append_digest = not kwargs.pop("dont_append_digest", False) + output = kwargs.pop("output", None) + output = "auto" if output is None else output + elf2image(filename, ctx.obj["chip"], output, append_digest=append_digest, **kwargs) + + +@cli.command("read-mac") +@click.pass_context +def read_mac_cli(ctx): + """Print the device MAC address.""" + prepare_esp_object(ctx) + read_mac(ctx.obj["esp"]) + + +@cli.command("chip-id") +@click.pass_context +def chip_id_cli(ctx): + """Print the device chip ID.""" + prepare_esp_object(ctx) + chip_id(ctx.obj["esp"]) + + +@cli.command("flash-id") +@add_spi_connection_arg +@click.pass_context +def flash_id_cli(ctx, **kwargs): + """Print the SPI flash memory manufacturer and device ID.""" + prepare_esp_object(ctx) + attach_flash(ctx.obj["esp"], kwargs.pop("spi_connection", None)) + flash_id(ctx.obj["esp"]) + + +@cli.command("read-flash-status") +@click.option( + "--bytes", + type=click.Choice(["1", "2", "3"]), + default="2", + help="Number of status bytes to read (1-3).", +) +@add_spi_connection_arg +@click.pass_context +def read_flash_status_cli(ctx, bytes, **kwargs): + """Read SPI flash memory status register.""" + prepare_esp_object(ctx) + attach_flash(ctx.obj["esp"], kwargs.pop("spi_connection", None)) + read_flash_status(ctx.obj["esp"], int(bytes)) + + +@cli.command("write-flash-status") +@click.option( + "--non-volatile", + is_flag=True, + help="Write non-volatile bits (use with caution).", +) +@click.option( + "--bytes", + type=click.Choice(["1", "2", "3"]), + default="2", + help="Number of status bytes to write (1-3).", +) +@click.argument("value", type=AnyIntType()) +@add_spi_connection_arg +@click.pass_context +def write_flash_status_cli(ctx, value, bytes, **kwargs): + """Write SPI flash memory status register.""" + prepare_esp_object(ctx) + attach_flash(ctx.obj["esp"], kwargs.pop("spi_connection", None)) + write_flash_status(ctx.obj["esp"], value, int(bytes), **kwargs) + + +@cli.command("read-flash") +@click.argument("address", type=AnyIntType()) +@click.argument("size", type=AutoSizeType()) +@click.argument("output", type=click.Path()) +@click.option("--no-progress", "-p", is_flag=True, help="Suppress progress output.") +@add_spi_flash_options(allow_keep=True, auto_detect=True, size_only=True) +@add_spi_connection_arg +@click.pass_context +def read_flash_cli(ctx, address, size, output, **kwargs): + """Read SPI flash memory content.""" + prepare_esp_object(ctx) + attach_flash(ctx.obj["esp"], kwargs.pop("spi_connection", None)) + size = parse_size_arg(ctx.obj["esp"], size) + check_flash_size(ctx.obj["esp"], address, size) + read_flash(ctx.obj["esp"], address, size, output, **kwargs) + + +@cli.command("verify-flash") +@click.argument("addr-filename", nargs=-1, required=True, cls=AddrFilenameArg) +@click.option("--diff", "-d", is_flag=True, help="Show differences.") +@add_spi_flash_options(allow_keep=True, auto_detect=True) +@add_spi_connection_arg +@click.pass_context +def verify_flash_cli(ctx, addr_filename, diff, **kwargs): + """Verify a binary blob against the flash memory content.""" + prepare_esp_object(ctx) + attach_flash(ctx.obj["esp"], kwargs.pop("spi_connection", None)) + verify_flash(ctx.obj["esp"], addr_filename, diff=diff, **kwargs) + + +@cli.command("erase-flash") +@click.option( + "--force", + is_flag=True, + help="Erase flash even if security features are enabled. Use with caution!", +) +@add_spi_connection_arg +@click.pass_context +def erase_flash_cli(ctx, force, **kwargs): + """Erase the SPI flash memory.""" + prepare_esp_object(ctx) + attach_flash(ctx.obj["esp"], kwargs.pop("spi_connection", None)) + erase_flash(ctx.obj["esp"], force) + + +@cli.command("erase-region") +@click.option( + "--force", + is_flag=True, + help="Erase region even if security features are enabled. Use with caution!", +) +@click.argument("address", type=AnyIntType()) +@click.argument("size", type=AutoSizeType()) +@click.option( + "--force", + is_flag=True, + help="Erase region even if security features are enabled. Use with caution!", +) +@add_spi_connection_arg +@click.pass_context +def erase_region_cli(ctx, address, size, force, **kwargs): + """Erase a region of the SPI flash memory.""" + prepare_esp_object(ctx) + attach_flash(ctx.obj["esp"], kwargs.pop("spi_connection", None)) + size = parse_size_arg(ctx.obj["esp"], size) + check_flash_size(ctx.obj["esp"], address, size) + erase_region(ctx.obj["esp"], address, size, force) + + +@cli.command("read-flash-sfdp") +@click.argument("address", type=AnyIntType()) +@click.argument("bytes", type=AnyIntType()) +@add_spi_flash_options(allow_keep=True, auto_detect=True) +@add_spi_connection_arg +@click.pass_context +def read_flash_sfdp_cli(ctx, address, bytes, **kwargs): + """Read SPI flash SFDP (Serial Flash Discoverable Parameters).""" + prepare_esp_object(ctx) + attach_flash(ctx.obj["esp"], kwargs.pop("spi_connection", None)) + read_flash_sfdp(ctx.obj["esp"], address, bytes) + + +@cli.command("merge-bin") +@click.argument("addr-filename", nargs=-1, required=True, cls=AddrFilenameArg) +@click.option("--output", "-o", type=str, required=True, help="Output filename.") +@click.option( + "--format", + "-f", + type=click.Choice(["raw", "uf2", "hex"]), + default="raw", + help="Format of the output file.", +) +@click.option( # UF2 only + "--chunk-size", + type=AutoChunkSizeType(), + help="Specify the used data part of the 512 byte UF2 block. A common value is 256. " + "By default the largest possible value will be used.", +) +@click.option( # UF2 only + "--md5-disable", + is_flag=True, + help="Disable MD5 checksum in UF2 output.", +) +@click.option( # RAW only + "--target-offset", + "-t", + type=AnyIntType(), + default=0, + help="Target offset where the output file will be flashed.", +) +@click.option( # RAW only + "--pad-to-size", + type=click.Choice( + ["256KB", "512KB", "1MB", "2MB", "4MB", "8MB", "16MB", "32MB", "64MB", "128MB"] + ), + help="If set, the final binary file will be padded with 0xFF bytes up to this flash" + " size.", +) +@add_spi_flash_options(allow_keep=True, auto_detect=False) +@click.pass_context +def merge_bin_cli(ctx, addr_filename, **kwargs): + """Merge multiple raw binary files into a single flashable file.""" + if ctx.obj["chip"] == "auto": + raise FatalError( + f"Specify the --chip argument (choose from {', '.join(CHIP_LIST)})." ) + merge_bin(addr_filename, chip=ctx.obj["chip"], **kwargs) - if esp is None: - raise FatalError( - "Could not connect to an Espressif device " - "on any of the %d available serial ports." % len(ser_list) - ) - - if esp.secure_download_mode: - print("Chip is %s in Secure Download Mode" % esp.CHIP_NAME) - else: - print("Chip is %s" % (esp.get_chip_description())) - print("Features: %s" % ", ".join(esp.get_chip_features())) - print("Crystal is %dMHz" % esp.get_crystal_freq()) - read_mac(esp, args) - - if not args.no_stub: - if esp.secure_download_mode: - print( - "WARNING: Stub loader is not supported in Secure Download Mode, " - "setting --no-stub" - ) - args.no_stub = True - elif not esp.IS_STUB and esp.stub_is_disabled: - print( - "WARNING: Stub loader has been disabled for compatibility, " - "setting --no-stub" - ) - args.no_stub = True - else: - try: - esp = esp.run_stub() - except Exception: - # The CH9102 bridge (PID: 0x55D4) can have issues on MacOS - if sys.platform == "darwin" and esp._get_pid() == 0x55D4: - print( - "\nNote: If issues persist, " - "try installing the WCH USB-to-Serial MacOS driver." - ) - raise - - if args.override_vddsdio: - esp.override_vddsdio(args.override_vddsdio) - - if args.baud > initial_baud: - try: - esp.change_baud(args.baud) - except NotImplementedInROMError: - print( - "WARNING: ROM doesn't support changing baud rate. " - "Keeping initial baud rate %d" % initial_baud - ) - - def _define_spi_conn(spi_connection): - """Prepare SPI configuration string and value for flash_spi_attach()""" - clk, q, d, hd, cs = spi_connection - spi_config_txt = f"CLK:{clk}, Q:{q}, D:{d}, HD:{hd}, CS:{cs}" - value = (hd << 24) | (cs << 18) | (d << 12) | (q << 6) | clk - return spi_config_txt, value - - # Override the common SPI flash parameter stuff if configured to do so - if hasattr(args, "spi_connection") and args.spi_connection is not None: - spi_config = args.spi_connection - if args.spi_connection == "SPI": - value = 0 - elif args.spi_connection == "HSPI": - value = 1 - else: - esp.check_spi_connection(args.spi_connection) - # Encode the pin numbers as a 32-bit integer with packed 6-bit values, - # the same way the ESP ROM takes them - spi_config, value = _define_spi_conn(args.spi_connection) - print(f"Configuring SPI flash mode ({spi_config})...") - esp.flash_spi_attach(value) - elif args.no_stub: - if esp.CHIP_NAME != "ESP32" or esp.secure_download_mode: - print("Enabling default SPI flash mode...") - # ROM loader doesn't enable flash unless we explicitly do it - esp.flash_spi_attach(0) - else: - # ROM doesn't attach in-package flash chips - spi_chip_pads = esp.get_chip_spi_pads() - spi_config_txt, value = _define_spi_conn(spi_chip_pads) - if spi_chip_pads != (0, 0, 0, 0, 0): - print( - "Attaching flash from eFuses' SPI pads configuration" - f"({spi_config_txt})..." - ) - else: - print("Enabling default SPI flash mode...") - esp.flash_spi_attach(value) - - # XMC chip startup sequence - XMC_VENDOR_ID = 0x20 - - def is_xmc_chip_strict(): - id = esp.flash_id() - rdid = ((id & 0xFF) << 16) | ((id >> 16) & 0xFF) | (id & 0xFF00) - - vendor_id = (rdid >> 16) & 0xFF - mfid = (rdid >> 8) & 0xFF - cpid = rdid & 0xFF - - if vendor_id != XMC_VENDOR_ID: - return False - - matched = False - if mfid == 0x40: - if cpid >= 0x13 and cpid <= 0x20: - matched = True - elif mfid == 0x41: - if cpid >= 0x17 and cpid <= 0x20: - matched = True - elif mfid == 0x50: - if cpid >= 0x15 and cpid <= 0x16: - matched = True - return matched - - def flash_xmc_startup(): - # If the RDID value is a valid XMC one, may skip the flow - fast_check = True - if fast_check and is_xmc_chip_strict(): - return # Successful XMC flash chip boot-up detected by RDID, skipping. - - sfdp_mfid_addr = 0x10 - mf_id = esp.read_spiflash_sfdp(sfdp_mfid_addr, 8) - if mf_id != XMC_VENDOR_ID: # Non-XMC chip detected by SFDP Read, skipping. - return - - print( - "WARNING: XMC flash chip boot-up failure detected! " - "Running XMC25QHxxC startup flow" - ) - esp.run_spiflash_command(0xB9) # Enter DPD - esp.run_spiflash_command(0x79) # Enter UDPD - esp.run_spiflash_command(0xFF) # Exit UDPD - time.sleep(0.002) # Delay tXUDPD - esp.run_spiflash_command(0xAB) # Release Power-Down - time.sleep(0.00002) - # Check for success - if not is_xmc_chip_strict(): - print("WARNING: XMC flash boot-up fix failed.") - print("XMC flash chip boot-up fix successful!") - - # Check flash chip connection - if not esp.secure_download_mode: - try: - flash_id = esp.flash_id() - if flash_id in (0xFFFFFF, 0x000000): - print( - "WARNING: Failed to communicate with the flash chip, " - "read/write operations will fail. " - "Try checking the chip connections or removing " - "any other hardware connected to IOs." - ) - if ( - hasattr(args, "spi_connection") - and args.spi_connection is not None - ): - print( - "Some GPIO pins might be used by other peripherals, " - "try using another --spi-connection combination." - ) - - except FatalError as e: - raise FatalError(f"Unable to verify flash chip connection ({e}).") - - # Check if XMC SPI flash chip booted-up successfully, fix if not - if not esp.secure_download_mode: - try: - flash_xmc_startup() - except FatalError as e: - esp.trace(f"Unable to perform XMC flash chip startup sequence ({e}).") - - if hasattr(args, "flash_size"): - print("Configuring flash size...") - if args.flash_size == "detect": - flash_size = detect_flash_size(esp, args) - elif args.flash_size == "keep": - flash_size = detect_flash_size(esp, args=None) - if not esp.IS_STUB: - print( - "WARNING: In case of failure, please set a specific --flash_size." - ) - else: - flash_size = args.flash_size - - if flash_size is not None: # Secure download mode - esp.flash_set_parameters(flash_size_bytes(flash_size)) - # Check if stub supports chosen flash size - if ( - esp.IS_STUB - and esp.CHIP_NAME != "ESP32-S3" - and flash_size_bytes(flash_size) > 16 * 1024 * 1024 - ): - print( - "WARNING: Flasher stub doesn't fully support flash size larger " - "than 16MB, in case of failure use --no-stub." - ) - - if getattr(args, "size", "") == "all": - if esp.secure_download_mode: - raise FatalError( - "Detecting flash size is not supported in secure download mode. " - "Set an exact size value." - ) - # detect flash size - flash_id = esp.flash_id() - size_id = flash_id >> 16 - size_str = DETECTED_FLASH_SIZES.get(size_id) - if size_str is None: - raise FatalError( - "Detecting flash size failed. Set an exact size value." - ) - print(f"Detected flash size: {size_str}") - args.size = flash_size_bytes(size_str) - - if esp.IS_STUB and hasattr(args, "address") and hasattr(args, "size"): - if esp.CHIP_NAME != "ESP32-S3" and args.address + args.size > 0x1000000: - print( - "WARNING: Flasher stub doesn't fully support flash size larger " - "than 16MB, in case of failure use --no-stub." - ) - try: - operation_func(esp, args) - finally: - try: # Clean up AddrFilenamePairAction files - for address, argfile in args.addr_filename: - argfile.close() - except AttributeError: - pass - - # Handle post-operation behaviour (reset or other) - if operation_func == load_ram: - # the ESP is now running the loaded image, so let it run - print("Exiting immediately.") - elif args.after == "hard_reset": - esp.hard_reset() - elif args.after == "soft_reset": - print("Soft resetting...") - # flash_finish will trigger a soft reset - esp.soft_reset(False) - elif args.after == "no_reset_stub": - print("Staying in flasher stub.") - else: # args.after == 'no_reset' - print("Staying in bootloader.") - if esp.IS_STUB: - esp.soft_reset(True) # exit stub back to ROM loader - - if not external_esp: - esp._port.close() - - else: - operation_func(args) +@cli.command("get-security-info") +@click.pass_context +def get_security_info_cli(ctx): + """Print security information report.""" + prepare_esp_object(ctx) + get_security_info(ctx.obj["esp"]) -def arg_auto_int(x): - return int(x, 0) +@cli.command("version") +def version_cli(): + """Print esptool version.""" + version() -def arg_auto_size(x): - x = x.lower() - return x if x == "all" else arg_auto_int(x) +def main(argv: list[str] | None = None, esp: ESPLoader | None = None): + """ + Main function for esptool + argv - Optional override for default arguments parsing (that uses sys.argv), + can be a list of custom arguments as strings. Arguments and their values + need to be added as individual items to the list + e.g. "-b 115200" thus becomes ['-b', '115200']. -def arg_auto_chunk_size(string: str) -> int: - num = int(string, 0) - if num & 3 != 0: - raise argparse.ArgumentTypeError("Chunk size should be a 4-byte aligned number") - return num + esp - Optional override of the connected device previously + returned by get_default_connected_device() + """ + args = expand_file_arguments(argv or sys.argv[1:]) + cli(args=args, esp=esp) -def get_port_list(vids=[], pids=[], names=[]): +def get_port_list( + vids: list[str] = [], + pids: list[str] = [], + names: list[str] = [], + serials: list[str] = [], +) -> list[str]: if list_ports is None: raise FatalError( "Listing all serial ports is currently not available. " - "Please try to specify the port when running esptool.py or update " - "the pyserial package to the latest version" + "Please try to specify the port when running esptool or update " + "the pyserial package to the latest version." ) ports = [] for port in list_ports.comports(): @@ -1102,11 +1062,16 @@ def get_port_list(vids=[], pids=[], names=[]): port.name is None or all(name not in port.name for name in names) ): continue + if serials and ( + port.serial_number is None + or all(serial not in port.serial_number for serial in serials) + ): + continue ports.append(port.device) return sorted(ports) -def expand_file_arguments(argv): +def expand_file_arguments(argv: list[str]) -> list[str]: """ Any argument starting with "@" gets replaced with all values read from a text file. Text file arguments can be split by newline or by space. @@ -1124,7 +1089,7 @@ def expand_file_arguments(argv): else: new_args.append(arg) if expanded: - print(f"esptool.py {' '.join(new_args)}") + log.print(f"esptool {' '.join(new_args)}") return new_args return argv @@ -1135,11 +1100,11 @@ def connect_loop( chip: str, max_retries: int, trace: bool = False, - before: str = "default_reset", + before: str = "default-reset", ): chip_class = CHIP_DEFS[chip] esp = None - print(f"Serial port {port}") + log.print(f"Serial port {port}:") first = True ten_cycle = cycle(chain(repeat(False, 9), (True,))) @@ -1152,7 +1117,7 @@ def connect_loop( esp = chip_class(port, initial_baud, trace) if not first: # break the retrying line - print("") + log.print("") esp.connect(before) return esp except ( @@ -1165,29 +1130,29 @@ def connect_loop( esp._port.close() esp = None if first: - print(err) - print("Retrying failed connection", end="", flush=True) + log.print(err) + log.print("Retrying failed connection", end="", flush=True) first = False if last: raise err if every_tenth: # print a dot every second - print(".", end="", flush=True) + log.print(".", end="", flush=True) time.sleep(0.1) def get_default_connected_device( - serial_list, - port, - connect_attempts, - initial_baud, - chip="auto", - trace=False, - before="default_reset", + serial_list: list[str], + port: str, + connect_attempts: int, + initial_baud: int, + chip: str = "auto", + trace: bool = False, + before: str = "default-reset", ): _esp = None for each_port in reversed(serial_list): - print("Serial port %s" % each_port) + log.print(f"Serial port {each_port}:") try: if chip == "auto": _esp = detect_chip( @@ -1201,135 +1166,38 @@ def get_default_connected_device( except (FatalError, OSError) as err: if port is not None: raise - print("%s failed to connect: %s" % (each_port, err)) + log.error(f"{each_port} failed to connect: {err}") if _esp and _esp._port: _esp._port.close() _esp = None return _esp -class SpiConnectionAction(argparse.Action): - """ - Custom action to parse 'spi connection' override. - Values are SPI, HSPI, or a sequence of 5 pin numbers separated by commas. - """ - - def __call__(self, parser, namespace, value, option_string=None): - if value.upper() in ["SPI", "HSPI"]: - values = value.upper() - elif "," in value: - values = value.split(",") - if len(values) != 5: - raise argparse.ArgumentError( - self, - f"{value} is not a valid list of comma-separate pin numbers. " - "Must be 5 numbers - CLK,Q,D,HD,CS.", - ) - try: - values = tuple(int(v, 0) for v in values) - except ValueError: - raise argparse.ArgumentError( - self, - f"{values} is not a valid argument. " - "All pins must be numeric values", - ) - else: - raise argparse.ArgumentError( - self, - f"{value} is not a valid spi-connection value. " - "Values are SPI, HSPI, or a sequence of 5 pin numbers - CLK,Q,D,HD,CS.", - ) - setattr(namespace, self.dest, values) - - -class AutoHex2BinAction(argparse.Action): - """Custom parser class for auto conversion of input files from hex to bin""" - - def __call__(self, parser, namespace, value, option_string=None): - try: - with open(value, "rb") as f: - # if hex file was detected replace hex file with converted temp bin - # otherwise keep the original file - value = intel_hex_to_bin(f).name - except IOError as e: - raise argparse.ArgumentError(self, e) - setattr(namespace, self.dest, value) - - -class AddrFilenamePairAction(argparse.Action): - """Custom parser class for the address/filename pairs passed as arguments""" - - def __init__(self, option_strings, dest, nargs="+", **kwargs): - super(AddrFilenamePairAction, self).__init__( - option_strings, dest, nargs, **kwargs - ) - - def __call__(self, parser, namespace, values, option_string=None): - # validate pair arguments - pairs = [] - for i in range(0, len(values), 2): - try: - address = int(values[i], 0) - except ValueError: - raise argparse.ArgumentError( - self, 'Address "%s" must be a number' % values[i] - ) - try: - argfile = open(values[i + 1], "rb") - except IOError as e: - raise argparse.ArgumentError(self, e) - except IndexError: - raise argparse.ArgumentError( - self, - "Must be pairs of an address " - "and the binary filename to write there", - ) - # check for intel hex files and convert them to bin - argfile = intel_hex_to_bin(argfile, address) - pairs.append((address, argfile)) - - # Sort the addresses and check for overlapping - end = 0 - for address, argfile in sorted(pairs, key=lambda x: x[0]): - argfile.seek(0, 2) # seek to end - size = argfile.tell() - argfile.seek(0) - sector_start = address & ~(ESPLoader.FLASH_SECTOR_SIZE - 1) - sector_end = ( - (address + size + ESPLoader.FLASH_SECTOR_SIZE - 1) - & ~(ESPLoader.FLASH_SECTOR_SIZE - 1) - ) - 1 - if sector_start < end: - message = "Detected overlap at address: 0x%x for file: %s" % ( - address, - argfile.name, - ) - raise argparse.ArgumentError(self, message) - end = sector_end - setattr(namespace, self.dest, pairs) - - def _main(): + check_deprecated_py_suffix(__name__) try: main() except FatalError as e: - print(f"\nA fatal error occurred: {e}") + log.error(f"\nA fatal error occurred: {e}") sys.exit(2) except serial.serialutil.SerialException as e: - print(f"\nA serial exception error occurred: {e}") - print( + log.error(f"\nA serial exception error occurred: {e}") + log.error( "Note: This error originates from pySerial. " "It is likely not a problem with esptool, " "but with the hardware connection or drivers." ) - print( + log.error( "For troubleshooting steps visit: " "https://docs.espressif.com/projects/esptool/en/latest/troubleshooting.html" ) sys.exit(1) except StopIteration: - print(traceback.format_exc()) - print("A fatal error occurred: The chip stopped responding.") + log.error(traceback.format_exc()) + log.error("A fatal error occurred: The chip stopped responding.") + sys.exit(2) + except KeyboardInterrupt: + log.error("KeyboardInterrupt: Run cancelled by user.") sys.exit(2) diff --git a/tools/esptool_py/esptool/bin_image.py b/tools/esptool_py/esptool/bin_image.py index 7ac9ed3c9c..8e51d8b9cf 100644 --- a/tools/esptool_py/esptool/bin_image.py +++ b/tools/esptool_py/esptool/bin_image.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2014-2022 Fredrik Ahlberg, Angus Gratton, +# SPDX-FileCopyrightText: 2014-2025 Fredrik Ahlberg, Angus Gratton, # Espressif Systems (Shanghai) CO LTD, other contributors as noted. # # SPDX-License-Identifier: GPL-2.0-or-later @@ -11,30 +11,28 @@ import re import struct import tempfile -from typing import IO, Optional +from typing import IO from intelhex import HexRecordError, IntelHex from .loader import ESPLoader +from .logger import log from .targets import ( ESP32C2ROM, ESP32C3ROM, ESP32C5ROM, - ESP32C5BETA3ROM, - ESP32C6BETAROM, ESP32C6ROM, ESP32C61ROM, - ESP32H2BETA1ROM, - ESP32H2BETA2ROM, ESP32H2ROM, + ESP32H21ROM, + ESP32H4ROM, ESP32P4ROM, ESP32ROM, ESP32S2ROM, - ESP32S3BETA2ROM, ESP32S3ROM, ESP8266ROM, ) -from .util import FatalError, byte, pad_to +from .util import FatalError, byte, ImageSource, get_bytes, pad_to def align_file_position(f, size): @@ -43,9 +41,46 @@ def align_file_position(f, size): f.seek(align, 1) -def intel_hex_to_bin(file: IO[bytes], start_addr: Optional[int] = None) -> IO[bytes]: - """Convert IntelHex file to temp binary file with padding from start_addr - If hex file was detected return temp bin file object; input file otherwise""" +def _find_subsequences(addresses: list[int]) -> list[tuple[int, int]]: + """Find continuous subsequences in a list of addresses""" + if not addresses: + return [] + + sorted_seq = sorted(addresses) + + subsequences = [] + start = sorted_seq[0] + + for prev, num in zip(sorted_seq, sorted_seq[1:]): + if num != prev + 1: + # Found a gap, save the current subsequence + subsequences.append((start, prev)) + start = num + + # Add the last subsequence + subsequences.append((start, sorted_seq[-1])) + + return subsequences + + +def _split_intel_hex_file(ih: IntelHex) -> list[tuple[int, IO[bytes]]]: + """Split an IntelHex file into multiple temporary binary files based on the gaps + in the addresses""" + subsequences = _find_subsequences(ih.addresses()) + bins: list[tuple[int, IO[bytes]]] = [] + for start, end in subsequences: + bin = tempfile.NamedTemporaryFile(suffix=".bin", delete=False) + ih.tobinfile(bin, start=start, end=end) + bin.seek(0) # make sure the file is at the beginning + bins.append((start, bin)) + return bins + + +def intel_hex_to_bin( + file: IO[bytes], start_addr: int | None = None +) -> list[tuple[int | None, IO[bytes]]]: + """Convert IntelHex file to list of temp binary files + If not hex file return input file otherwise""" INTEL_HEX_MAGIC = b":" magic = file.read(1) file.seek(0) @@ -54,61 +89,51 @@ def intel_hex_to_bin(file: IO[bytes], start_addr: Optional[int] = None) -> IO[by ih = IntelHex() ih.loadhex(file.name) file.close() - bin = tempfile.NamedTemporaryFile(suffix=".bin", delete=False) - ih.tobinfile(bin, start=start_addr) - return bin + return _split_intel_hex_file(ih) # type: ignore else: - return file + return [(start_addr, file)] except (HexRecordError, UnicodeDecodeError): # file started with HEX magic but the rest was not according to the standard - return file + return [(start_addr, file)] -def LoadFirmwareImage(chip, image_file): +def LoadFirmwareImage(chip: str, image_data: ImageSource): """ Load a firmware image. Can be for any supported SoC. ESP8266 images will be examined to determine if they are original ROM firmware images (ESP8266ROMFirmwareImage) or "v2" OTA bootloader images. - Returns a BaseFirmwareImage subclass, either ESP8266ROMFirmwareImage (v1) - or ESP8266V2FirmwareImage (v2). + Returns a BaseFirmwareImage subclass. """ - - def select_image_class(f, chip): - chip = re.sub(r"[-()]", "", chip.lower()) - if chip != "esp8266": - return { - "esp32": ESP32FirmwareImage, - "esp32s2": ESP32S2FirmwareImage, - "esp32s3beta2": ESP32S3BETA2FirmwareImage, - "esp32s3": ESP32S3FirmwareImage, - "esp32c3": ESP32C3FirmwareImage, - "esp32c6beta": ESP32C6BETAFirmwareImage, - "esp32h2beta1": ESP32H2BETA1FirmwareImage, - "esp32h2beta2": ESP32H2BETA2FirmwareImage, - "esp32c2": ESP32C2FirmwareImage, - "esp32c6": ESP32C6FirmwareImage, - "esp32c61": ESP32C61FirmwareImage, - "esp32c5": ESP32C5FirmwareImage, - "esp32c5beta3": ESP32C5BETA3FirmwareImage, - "esp32h2": ESP32H2FirmwareImage, - "esp32p4": ESP32P4FirmwareImage, - }[chip](f) - else: # Otherwise, ESP8266 so look at magic to determine the image type - magic = ord(f.read(1)) - f.seek(0) - if magic == ESPLoader.ESP_IMAGE_MAGIC: - return ESP8266ROMFirmwareImage(f) - elif magic == ESP8266V2FirmwareImage.IMAGE_V2_MAGIC: - return ESP8266V2FirmwareImage(f) - else: - raise FatalError("Invalid image magic number: %d" % magic) - - if isinstance(image_file, str): - with open(image_file, "rb") as f: - return select_image_class(f, chip) - return select_image_class(image_file, chip) + data, _ = get_bytes(image_data) + f = io.BytesIO(data) + chip = re.sub(r"[-()]", "", chip.lower()) + if chip == "esp8266": + # Look at the magic number to determine the ESP8266 image type + magic = ord(f.read(1)) + f.seek(0) + if magic == ESPLoader.ESP_IMAGE_MAGIC: + return ESP8266ROMFirmwareImage(f) + elif magic == ESP8266V2FirmwareImage.IMAGE_V2_MAGIC: + return ESP8266V2FirmwareImage(f) + else: + raise FatalError(f"Invalid image magic number: {magic}") + else: + return { + "esp32": ESP32FirmwareImage, + "esp32s2": ESP32S2FirmwareImage, + "esp32s3": ESP32S3FirmwareImage, + "esp32c3": ESP32C3FirmwareImage, + "esp32c2": ESP32C2FirmwareImage, + "esp32c6": ESP32C6FirmwareImage, + "esp32c61": ESP32C61FirmwareImage, + "esp32c5": ESP32C5FirmwareImage, + "esp32h2": ESP32H2FirmwareImage, + "esp32h21": ESP32H21FirmwareImage, + "esp32p4": ESP32P4FirmwareImage, + "esp32h4": ESP32H4FirmwareImage, + }[chip](f) class ImageSegment(object): @@ -164,14 +189,22 @@ def get_memory_type(self, image): def pad_to_alignment(self, alignment): self.data = pad_to(self.data, alignment, b"\x00") - def addr_align(self, alignment): + def end_addr_if_aligned(self, alignment): + """ + Return the segment end address as it would be if + aligned as requested by the argument. + """ end_addr = self.addr + len(self.data) addr_mod = end_addr % alignment if addr_mod != 0: end_addr += alignment - addr_mod return end_addr - def pad_to_addr(self, addr): + def pad_until_addr(self, addr): + """ + Pad the segment with `0x00` starting with segment address + until the address given by the argument. + """ pad = addr - (self.addr + len(self.data)) if pad > 0: self.data += b"\x00" * pad @@ -192,9 +225,8 @@ def __repr__(self): class BaseFirmwareImage(object): SEG_HEADER_LEN = 8 SHA256_DIGEST_LEN = 32 - ELF_FLAG_WRITE = 0x1 - ELF_FLAG_READ = 0x2 - ELF_FLAG_EXEC = 0x4 + IROM_ALIGN = 0 + MMU_PAGE_SIZE_CONF: tuple[int, ...] = () """ Base class with common firmware image functions """ @@ -243,7 +275,7 @@ def load_segment(self, f, is_irom_segment=False): def warn_if_unusual_segment(self, offset, size, is_irom_segment): if not is_irom_segment: if offset > 0x40200000 or offset < 0x3FFE0000 or size > 65536: - print("WARNING: Suspicious segment 0x%x, length %d" % (offset, size)) + log.warning(f"Suspicious segment {offset:#x}, length {size}") def maybe_patch_segment_data(self, f, segment_data): """ @@ -287,13 +319,26 @@ def maybe_patch_segment_data(self, f, segment_data): ) return segment_data - def save_segment(self, f, segment, checksum=None): + def save_segment(self, f, segment, checksum=None, segment_name=None): """ Save the next segment to the image file, return next checksum value if provided """ segment_data = self.maybe_patch_segment_data(f, segment.data) - f.write(struct.pack("= SIXTEEN_MB: + raise FatalError( + f"Invalid {segment_name} segment length {segment_len:#x}. " + "The 16 MB limit has been exceeded." + ) + f.write(struct.pack(" tuple[bytes | None, bytes] | None: + irom_data: bytes | None = None + other_data: bytes | None = None + + # Handle IROM data irom_segment = self.get_irom_segment() if irom_segment is not None: - with open( - "%s0x%05x.bin" - % (basename, irom_segment.addr - ESP8266ROM.IROM_MAP_START), - "wb", - ) as f: - f.write(irom_segment.data) - - # everything but IROM goes at 0x00000 in an image file - normal_segments = self.get_non_irom_segments() - with open("%s0x00000.bin" % basename, "wb") as f: + irom_data = irom_segment.data + + # Handle other segments (everything but IROM) + with io.BytesIO() as f: # Use BytesIO to write to memory + normal_segments = self.get_non_irom_segments() self.write_common_header(f, normal_segments) checksum = ESPLoader.ESP_CHECKSUM_MAGIC for segment in normal_segments: checksum = self.save_segment(f, segment, checksum) self.append_checksum(f, checksum) + other_data = f.getvalue() # Get the bytes from BytesIO + + if filename is not None: + # Write IROM data to a file + if irom_data is not None: + offset = irom_segment.addr - ESP8266ROM.IROM_MAP_START + with open(f"{filename}{offset:#07x}.bin", "wb") as f: + f.write(irom_data) + # Write other data to a file + if other_data is not None: + with open(f"{filename}{0:#07x}.bin", "wb") as f: + f.write(other_data) + return None + else: + return (irom_data, other_data) + ESP8266ROM.BOOTLOADER_IMAGE = ESP8266ROMFirmwareImage @@ -518,9 +588,8 @@ def __init__(self, load_file=None): if segments != self.IMAGE_V2_SEGMENT: # segment count is not really segment count here, # but we expect to see '4' - print( - 'Warning: V2 header has unexpected "segment" count %d (usually 4)' - % segments + log.warning( + f'V2 header has unexpected "segment" count {segments} (usually 4)' ) # irom segment comes before the second header @@ -540,22 +609,22 @@ def __init__(self, load_file=None): segments = self.load_common_header(load_file, ESPLoader.ESP_IMAGE_MAGIC) if first_flash_mode != self.flash_mode: - print( - "WARNING: Flash mode value in first header (0x%02x) disagrees " - "with second (0x%02x). Using second value." - % (first_flash_mode, self.flash_mode) + log.warning( + f"Flash mode value in first header ({first_flash_mode:#04x}) " + f"disagrees with second ({self.flash_mode:#04x}). " + "Using second value." ) if first_flash_size_freq != self.flash_size_freq: - print( - "WARNING: Flash size/freq value in first header (0x%02x) disagrees " - "with second (0x%02x). Using second value." - % (first_flash_size_freq, self.flash_size_freq) + log.warning( + "Flash size/freq value in first header " + f"({first_flash_size_freq:#04x}) disagrees with second " + f"({self.flash_size_freq:#04x}). Using second value." ) if first_entrypoint != self.entrypoint: - print( - "WARNING: Entrypoint address in first header (0x%08x) disagrees " - "with second header (0x%08x). Using second value." - % (first_entrypoint, self.entrypoint) + log.warning( + f"Entrypoint address in first header ({first_entrypoint:#010x}) " + f"disagrees with second header ({self.entrypoint:#010x}). " + "Using second value." ) # load all the usual segments @@ -577,8 +646,8 @@ def default_output_name(self, input_file): irom_offs & ~(ESPLoader.FLASH_SECTOR_SIZE - 1), ) - def save(self, filename): - with open(filename, "wb") as f: + def save(self, filename: str | None) -> bytes | None: + with io.BytesIO() as f: # Write to memory first # Save first header for irom0 segment f.write( struct.pack( @@ -608,13 +677,20 @@ def save(self, filename): checksum = self.save_segment(f, segment, checksum) self.append_checksum(f, checksum) - # calculate a crc32 of entire file and append - # (algorithm used by recent 8266 SDK bootloaders) - with open(filename, "rb") as f: + # Calculate CRC32 of the entire file and append + f.seek(0) # Move to the start of the BytesIO buffer crc = esp8266_crc32(f.read()) - with open(filename, "ab") as f: f.write(struct.pack(b" bytes | None: total_segments = 0 with io.BytesIO() as f: # write file to memory first self.write_common_header(f, self.segments) @@ -755,10 +831,10 @@ def save(self, filename): for segment in flash_segments[1:]: if segment.addr // self.IROM_ALIGN == last_addr // self.IROM_ALIGN: raise FatalError( - "Segment loaded at 0x%08x lands in same 64KB flash mapping " - "as segment loaded at 0x%08x. Can't generate binary. " + f"Segment loaded at {segment.addr:#010x} lands in same " + f"{self.IROM_ALIGN // 1024} KB flash mapping as segment " + f"loaded at {last_addr:#010x}. Can't generate binary. " "Suggest changing linker script or ELF to merge sections." - % (segment.addr, last_addr) ) last_addr = segment.addr @@ -787,7 +863,7 @@ def get_alignment_data_needed(segment): # and checksum (ROM bootloader will only care for RAM segments and its # correct checksums) for segment in ram_segments: - checksum = self.save_segment(f, segment, checksum) + checksum = self.save_segment(f, segment, checksum, segment.name) total_segments += 1 self.append_checksum(f, checksum) @@ -805,7 +881,7 @@ def get_alignment_data_needed(segment): pad_len -= self.ROM_LOADER.BOOTLOADER_FLASH_OFFSET pad_segment = ImageSegment(0, b"\x00" * pad_len, f.tell()) - self.save_segment(f, pad_segment) + self.save_segment(f, pad_segment, None, segment.name) total_segments += 1 # check the alignment assert (f.tell() + 8 + self.ROM_LOADER.BOOTLOADER_FLASH_OFFSET) % ( @@ -817,7 +893,7 @@ def get_alignment_data_needed(segment): self.save_flash_segment(f, segment) total_segments += 1 else: # not self.ram_only_header - # try to fit each flash segment on a 64kB aligned boundary + # try to fit each flash segment on a MMU page size aligned boundary # by padding with parts of the non-flash segments... while len(flash_segments) > 0: segment = flash_segments[0] @@ -829,7 +905,9 @@ def get_alignment_data_needed(segment): ram_segments.pop(0) else: pad_segment = ImageSegment(0, b"\x00" * pad_len, f.tell()) - checksum = self.save_segment(f, pad_segment, checksum) + checksum = self.save_segment( + f, pad_segment, checksum, segment.name + ) total_segments += 1 else: # write the flash segment @@ -842,12 +920,12 @@ def get_alignment_data_needed(segment): # flash segments all written, so write any remaining RAM segments for segment in ram_segments: - checksum = self.save_segment(f, segment, checksum) + checksum = self.save_segment(f, segment, checksum, segment.name) total_segments += 1 if self.secure_pad: - # pad the image so that after signing it will end on a a 64KB boundary. - # This ensures all mapped flash content will be verified. + # pad the image so that after signing it will end on a a MMU page size + # boundary. This ensures all mapped flash content will be verified. if not self.append_digest: raise FatalError( "secure_pad only applies if a SHA-256 digest " @@ -865,7 +943,7 @@ def get_alignment_data_needed(segment): elif self.secure_pad == "2": # Secure Boot V2 # after checksum: SHA-256 digest + # signature sector, - # but we place signature sector after the 64KB boundary + # but we place signature sector after the MMU page size boundary space_after_checksum = 32 pad_len = ( self.IROM_ALIGN - align_past - checksum_space - space_after_checksum @@ -906,8 +984,14 @@ def get_alignment_data_needed(segment): pad_by = self.pad_to_size - (image_length % self.pad_to_size) f.write(b"\xff" * pad_by) - with open(filename, "wb") as real_file: - real_file.write(f.getvalue()) + if filename is not None: + # Write the content to a real file + with open(filename, "wb") as real_file: + real_file.write(f.getvalue()) + return None + else: + # Return the bytes if no filename is provided + return f.getvalue() def load_extended_header(self, load_file): def split_byte(n): @@ -926,12 +1010,10 @@ def split_byte(n): self.chip_id = fields[4] if self.chip_id != self.ROM_LOADER.IMAGE_CHIP_ID: - print( - ( - "Unexpected chip id in image. Expected %d but value was %d. " - "Is this image for a different chip model?" - ) - % (self.ROM_LOADER.IMAGE_CHIP_ID, self.chip_id) + log.warning( + f"Unexpected chip ID in image. Expected {self.ROM_LOADER.IMAGE_CHIP_ID}" + f" but value was {self.chip_id}. Is this image for a different " + "chip model?" ) self.min_rev = fields[5] @@ -978,7 +1060,7 @@ class ESP8266V3FirmwareImage(ESP32FirmwareImage): def is_flash_addr(self, addr): return addr > ESP8266ROM.IROM_MAP_START - def save(self, filename): + def save(self, filename: str | None) -> bytes | None: total_segments = 0 with io.BytesIO() as f: # write file to memory first self.write_common_header(f, self.segments) @@ -1006,14 +1088,14 @@ def save(self, filename): for segment in flash_segments[1:]: if segment.addr // self.IROM_ALIGN == last_addr // self.IROM_ALIGN: raise FatalError( - "Segment loaded at 0x%08x lands in same 64KB flash mapping " - "as segment loaded at 0x%08x. Can't generate binary. " + f"Segment loaded at {segment.addr:#010x} lands in same " + f"{self.IROM_ALIGN // 1024} KB flash mapping as segment " + f"loaded at {last_addr:#010x}. Can't generate binary. " "Suggest changing linker script or ELF to merge sections." - % (segment.addr, last_addr) ) last_addr = segment.addr - # try to fit each flash segment on a 64kB aligned boundary + # try to fit each flash segment on a MMU page size aligned boundary # by padding with parts of the non-flash segments... while len(flash_segments) > 0: segment = flash_segments[0] @@ -1046,8 +1128,14 @@ def save(self, filename): digest.update(f.read(image_length)) f.write(digest.digest()) - with open(filename, "wb") as real_file: - real_file.write(f.getvalue()) + if filename is not None: + # Write the content to a real file + with open(filename, "wb") as real_file: + real_file.write(f.getvalue()) + return None + else: + # Return the bytes if no filename is provided + return f.getvalue() def load_extended_header(self, load_file): def split_byte(n): @@ -1074,9 +1162,9 @@ def split_byte(n): # remaining fields in the middle should all be zero if any(f for f in fields[4:15] if f != 0): - print( - "Warning: some reserved header fields have non-zero values. " - "This image may be from a newer esptool.py?" + log.warning( + "Some reserved header fields have non-zero values. " + "This image may be from a newer esptool?" ) @@ -1092,15 +1180,6 @@ class ESP32S2FirmwareImage(ESP32FirmwareImage): ESP32S2ROM.BOOTLOADER_IMAGE = ESP32S2FirmwareImage -class ESP32S3BETA2FirmwareImage(ESP32FirmwareImage): - """ESP32S3 Firmware Image almost exactly the same as ESP32FirmwareImage""" - - ROM_LOADER = ESP32S3BETA2ROM - - -ESP32S3BETA2ROM.BOOTLOADER_IMAGE = ESP32S3BETA2FirmwareImage - - class ESP32S3FirmwareImage(ESP32FirmwareImage): """ESP32S3 Firmware Image almost exactly the same as ESP32FirmwareImage""" @@ -1119,45 +1198,11 @@ class ESP32C3FirmwareImage(ESP32FirmwareImage): ESP32C3ROM.BOOTLOADER_IMAGE = ESP32C3FirmwareImage -class ESP32C6BETAFirmwareImage(ESP32FirmwareImage): - """ESP32C6 Firmware Image almost exactly the same as ESP32FirmwareImage""" - - ROM_LOADER = ESP32C6BETAROM - - -ESP32C6BETAROM.BOOTLOADER_IMAGE = ESP32C6BETAFirmwareImage - - -class ESP32H2BETA1FirmwareImage(ESP32FirmwareImage): - """ESP32H2 Firmware Image almost exactly the same as ESP32FirmwareImage""" - - ROM_LOADER = ESP32H2BETA1ROM - - -ESP32H2BETA1ROM.BOOTLOADER_IMAGE = ESP32H2BETA1FirmwareImage - - -class ESP32H2BETA2FirmwareImage(ESP32FirmwareImage): - """ESP32H2 Firmware Image almost exactly the same as ESP32FirmwareImage""" - - ROM_LOADER = ESP32H2BETA2ROM - - -ESP32H2BETA2ROM.BOOTLOADER_IMAGE = ESP32H2BETA2FirmwareImage - - class ESP32C2FirmwareImage(ESP32FirmwareImage): """ESP32C2 Firmware Image almost exactly the same as ESP32FirmwareImage""" ROM_LOADER = ESP32C2ROM - - def set_mmu_page_size(self, size): - if size not in [16384, 32768, 65536]: - raise FatalError( - "{} bytes is not a valid ESP32-C2 page size, " - "select from 64KB, 32KB, 16KB.".format(size) - ) - self.IROM_ALIGN = size + MMU_PAGE_SIZE_CONF = (16384, 32768, 65536) ESP32C2ROM.BOOTLOADER_IMAGE = ESP32C2FirmwareImage @@ -1167,14 +1212,7 @@ class ESP32C6FirmwareImage(ESP32FirmwareImage): """ESP32C6 Firmware Image almost exactly the same as ESP32FirmwareImage""" ROM_LOADER = ESP32C6ROM - - def set_mmu_page_size(self, size): - if size not in [8192, 16384, 32768, 65536]: - raise FatalError( - "{} bytes is not a valid ESP32-C6 page size, " - "select from 64KB, 32KB, 16KB, 8KB.".format(size) - ) - self.IROM_ALIGN = size + MMU_PAGE_SIZE_CONF = (8192, 16384, 32768, 65536) ESP32C6ROM.BOOTLOADER_IMAGE = ESP32C6FirmwareImage @@ -1189,8 +1227,8 @@ class ESP32C61FirmwareImage(ESP32C6FirmwareImage): ESP32C61ROM.BOOTLOADER_IMAGE = ESP32C61FirmwareImage -class ESP32C5FirmwareImage(ESP32C6FirmwareImage): - """ESP32C5 Firmware Image almost exactly the same as ESP32C6FirmwareImage""" +class ESP32C5FirmwareImage(ESP32FirmwareImage): + """ESP32C5 Firmware Image almost exactly the same as ESP32FirmwareImage""" ROM_LOADER = ESP32C5ROM @@ -1198,13 +1236,21 @@ class ESP32C5FirmwareImage(ESP32C6FirmwareImage): ESP32C5ROM.BOOTLOADER_IMAGE = ESP32C5FirmwareImage -class ESP32C5BETA3FirmwareImage(ESP32C6FirmwareImage): - """ESP32C5BETA3 Firmware Image almost exactly the same as ESP32C6FirmwareImage""" +class ESP32H4FirmwareImage(ESP32FirmwareImage): + """ESP32H4 Firmware Image almost exactly the same as ESP32FirmwareImage""" + + ROM_LOADER = ESP32H4ROM - ROM_LOADER = ESP32C5BETA3ROM + def set_mmu_page_size(self, size): + if size not in [8192, 16384, 32768, 65536]: + raise FatalError( + "{} bytes is not a valid ESP32-H4 page size, " + "select from 64KB, 32KB, 16KB, 8KB.".format(size) + ) + self.IROM_ALIGN = size -ESP32C5BETA3ROM.BOOTLOADER_IMAGE = ESP32C5BETA3FirmwareImage +ESP32H4ROM.BOOTLOADER_IMAGE = ESP32H4FirmwareImage class ESP32P4FirmwareImage(ESP32FirmwareImage): @@ -1225,6 +1271,15 @@ class ESP32H2FirmwareImage(ESP32C6FirmwareImage): ESP32H2ROM.BOOTLOADER_IMAGE = ESP32H2FirmwareImage +class ESP32H21FirmwareImage(ESP32C6FirmwareImage): + """ESP32H21 Firmware Image almost exactly the same as ESP32FirmwareImage""" + + ROM_LOADER = ESP32H21ROM + + +ESP32H21ROM.BOOTLOADER_IMAGE = ESP32H21FirmwareImage + + class ELFFile(object): SEC_TYPE_PROGBITS = 0x01 SEC_TYPE_STRTAB = 0x03 @@ -1239,11 +1294,10 @@ class ELFFile(object): SEG_TYPE_LOAD = 0x01 LEN_SEG_HEADER = 0x20 - def __init__(self, name): - # Load sections from the ELF file - self.name = name - with open(self.name, "rb") as f: - self._read_elf_file(f) + def __init__(self, data): + self.data, self.name = get_bytes(data) + f = io.BytesIO(self.data) + self._read_elf_file(f) def get_section(self, section_name): for s in self.sections: @@ -1254,6 +1308,7 @@ def get_section(self, section_name): def _read_elf_file(self, f): # read the ELF file header LEN_FILE_HEADER = 0x34 + source = "Image" if self.name is None else f"'{self.name}'" try: ( ident, @@ -1271,25 +1326,23 @@ def _read_elf_file(self, f): shnum, shstrndx, ) = struct.unpack("<16sHHLLLLLHHHHHH", f.read(LEN_FILE_HEADER)) - except struct.error as e: - raise FatalError( - "Failed to read a valid ELF header from %s: %s" % (self.name, e) - ) + except struct.error as e: + raise FatalError(f"{source} does not have a valid ELF header: {e}") if byte(ident, 0) != 0x7F or ident[1:4] != b"ELF": - raise FatalError("%s has invalid ELF magic header" % self.name) + raise FatalError(f"{source} has invalid ELF magic header") if machine not in [0x5E, 0xF3]: raise FatalError( - "%s does not appear to be an Xtensa or an RISCV ELF file. " - "e_machine=%04x" % (self.name, machine) + f"{source} does not appear to be an Xtensa or an RISCV ELF image. " + f"(e_machine = {machine:#06x})" ) if shentsize != self.LEN_SEC_HEADER: raise FatalError( - "%s has unexpected section header entry size 0x%x (not 0x%x)" - % (self.name, shentsize, self.LEN_SEC_HEADER) + f"{source} has unexpected section header entry size {shentsize:#x} " + f"(not {self.LEN_SEC_HEADER:#x})" ) if shnum == 0: - raise FatalError("%s has 0 section headers" % (self.name)) + raise FatalError(f"{source} has 0 section headers") self._read_sections(f, shoff, shnum, shstrndx) self._read_segments(f, _phoff, _phnum, shstrndx) @@ -1299,13 +1352,13 @@ def _read_sections(self, f, section_header_offs, section_header_count, shstrndx) section_header = f.read(len_bytes) if len(section_header) == 0: raise FatalError( - "No section header found at offset %04x in ELF file." - % section_header_offs + f"No section header found at offset {section_header_offs:#06x} " + "in ELF image." ) if len(section_header) != (len_bytes): raise FatalError( - "Only read 0x%x bytes from section header (expected 0x%x.) " - "Truncated ELF file?" % (len(section_header), len_bytes) + f"Only read {len(section_header):#x} bytes from section header " + f"(expected {len_bytes:#x}). Truncated ELF image?" ) # walk through the section header and extract all sections @@ -1319,8 +1372,8 @@ def read_section_header(offs): lma, sec_offs, size, - link, - info, + _, + _, align, ) = struct.unpack_from(" 0 ] self.segments = prog_segments @@ -1419,6 +1470,6 @@ def read_data(offs, size): def sha256(self): # return SHA256 hash of the input ELF file sha256 = hashlib.sha256() - with open(self.name, "rb") as f: - sha256.update(f.read()) + f = io.BytesIO(self.data) + sha256.update(f.read()) return sha256.digest() diff --git a/tools/esptool_py/esptool/cli_util.py b/tools/esptool_py/esptool/cli_util.py new file mode 100644 index 0000000000..647c011d18 --- /dev/null +++ b/tools/esptool_py/esptool/cli_util.py @@ -0,0 +1,428 @@ +# SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD +# +# SPDX-License-Identifier: GPL-2.0-or-later + + +import rich_click as click + +from esptool.bin_image import ESPLoader, intel_hex_to_bin +from esptool.cmds import detect_flash_size +from esptool.util import FatalError, flash_size_bytes, strip_chip_name +from esptool.logger import log +from typing import IO, Any + +################################ Custom types ################################# + + +class ChipType(click.Choice): + """Custom type to accept chip names in any case and with or without hyphen""" + + def convert( + self, value: str, param: click.Parameter | None, ctx: click.Context + ) -> Any: + value = strip_chip_name(value) + return super().convert(value, param, ctx) + + +class ResetModeType(click.Choice): + """Custom type to accept reset mode names with underscores as separators + for compatibility with v4""" + + def convert(self, value: str, param: click.Parameter, ctx: click.Context) -> Any: + if "_" in value: + new_value = value.replace("_", "-") + if new_value not in self.choices: + raise click.BadParameter(f"{value} is not a valid reset mode.") + log.warning( + f"Deprecated: Choice '{value}' for option '--{param.name}' is " + f"deprecated. Use '{new_value}' instead." + ) + return new_value + return super().convert(value, param, ctx) + + +class AnyIntType(click.ParamType): + """Custom type to parse any integer value - decimal, hex, octal, or binary""" + + name = "integer" + + def convert( + self, value: str, param: click.Parameter | None, ctx: click.Context + ) -> int: + if isinstance(value, int): # default value is already an int + return value + try: + return arg_auto_int(value) + except ValueError: + raise click.BadParameter(f"{value!r} is not a valid integer.") + + +class AutoSizeType(AnyIntType): + """Similar to AnyIntType but allows 'k', 'M' suffixes for kilo(1024), Mega(1024^2) + and 'all' as a value to e.g. read whole flash""" + + def __init__(self, allow_all: bool = True): + self.allow_all = allow_all + super().__init__() + + def convert( + self, value: str, param: click.Parameter | None, ctx: click.Context + ) -> Any: + if self.allow_all and value.lower() == "all": + return value + # Handle suffixes like 'k', 'M' for kilo, mega + if value[-1] in ("k", "M"): + try: + num = arg_auto_int(value[:-1]) + except ValueError: + raise click.BadParameter(f"{value!r} is not a valid integer") + if value[-1] == "k": + num *= 1024 + elif value[-1] == "M": + num *= 1024 * 1024 + return num + return super().convert(value, param, ctx) + + +class AutoChunkSizeType(AnyIntType): + """Custom type for chunk size that must be 4-byte aligned""" + + name = "integer" + + def convert( + self, value: str, param: click.Parameter | None, ctx: click.Context + ) -> int: + num = super().convert(value, param, ctx) + if num & 3 != 0: + raise click.BadParameter("Chunk size should be a 4-byte aligned number.") + return num + + +class SpiConnectionType(click.ParamType): + """ + Custom type to parse 'spi connection' override. + Values are SPI, HSPI, or a sequence of 5 pin numbers separated by commas. + """ + + name = "spi-connection" + + def convert( + self, value: str, param: click.Parameter | None, ctx: click.Context + ) -> str | tuple[int, int, int, int, int]: + if value.upper() in ["SPI", "HSPI"]: + return value.upper() + elif "," in value: + values = value.split(",") + if len(values) != 5: + raise click.BadParameter( + f"{value} is not a valid list of comma-separated pin numbers. " + "Must be 5 numbers - CLK,Q,D,HD,CS.", + ) + try: + return tuple(arg_auto_int(v) for v in values) # type: ignore + except ValueError: + raise click.BadParameter( + f"{values} is not a valid argument. " + "All pins must be numeric values.", + ) + else: + raise click.BadParameter( + f"{value} is not a valid spi-connection value. " + "Values are SPI, HSPI, or a sequence of 5 pin numbers - CLK,Q,D,HD,CS.", + ) + + +class AutoHex2BinType(click.Path): + """Custom type for auto conversion of input files from hex to bin""" + + def __init__(self, exists=True): + super().__init__(exists=exists) + + def convert( + self, value: str, param: click.Parameter | None, ctx: click.Context + ) -> list[tuple[int | None, IO[bytes]]]: + try: + with open(value, "rb") as f: + # if hex file was detected replace hex file with converted temp bin + # otherwise keep the original file + return intel_hex_to_bin(f) + except IOError as e: + raise click.BadParameter(str(e)) + + +class AddrFilenamePairType(click.Path): + """Custom type for the address/filename pairs passed as arguments""" + + name = "addr-filename-pair" + + def get_metavar(self, param): + return "
" + + def convert( + self, + value: list[str], + param: click.Parameter | None, + ctx: click.Context, + ): + if len(value) % 2 != 0: + raise click.BadParameter( + "Must be pairs of an address and the binary filename to write there.", + ) + if len(value) == 0: + return value + + pairs: list[tuple[int, IO[bytes]]] = [] + for i in range(0, len(value), 2): + try: + address = arg_auto_int(value[i]) + except ValueError: + raise click.BadParameter(f'Address "{value[i]}" must be a number.') + try: + # Store file handle in context for later cleanup + if not hasattr(ctx, "_open_files"): + ctx._open_files = [] + argfile_f = open(value[i + 1], "rb") + ctx._open_files.append(argfile_f) + except IOError as e: + raise click.BadParameter(str(e)) + # check for intel hex files and convert them to bin + argfile_list = intel_hex_to_bin(argfile_f, address) + pairs.extend(argfile_list) # type: ignore + + # Sort the addresses and check for overlapping + end = 0 + for address, argfile in sorted(pairs, key=lambda x: x[0]): + argfile.seek(0, 2) # seek to end + size = argfile.tell() + argfile.seek(0) + sector_start = address & ~(ESPLoader.FLASH_SECTOR_SIZE - 1) + sector_end = ( + (address + size + ESPLoader.FLASH_SECTOR_SIZE - 1) + & ~(ESPLoader.FLASH_SECTOR_SIZE - 1) + ) - 1 + if sector_start < end: + raise click.BadParameter( + f"Detected overlap at address: " + f"{address:#x} for file: {argfile.name}.", + ) + end = sector_end + return pairs + + +########################### Custom option/argument ############################ + + +class Group(click.RichGroup): + DEPRECATED_OPTIONS = { + "--flash_size": "--flash-size", + "--flash_freq": "--flash-freq", + "--flash_mode": "--flash-mode", + "--use_segments": "--use-segments", + "--ignore_flash_encryption_efuse_setting": "--ignore-flash-enc-efuse", + "--fill-flash-size": "--pad-to-size", + } + + def __call__(self, esp: ESPLoader | None = None, *args, **kwargs): + self._esp = esp # store the external esp object in the group + return super().__call__(*args, **kwargs) + + def _replace_deprecated_args(self, args: list[str]) -> list[str]: + new_args = [] + for arg in args: + if arg in self.DEPRECATED_OPTIONS.keys(): + # Replace underscores with hyphens in option names + new_name = self.DEPRECATED_OPTIONS[arg] + if new_name != arg: + log.warning( + f"Deprecated: Option '{arg}' is deprecated. " + f"Use '{new_name}' instead." + ) + arg = new_name + new_args.append(arg) + return new_args + + def parse_args(self, ctx: click.Context, args: list[str]): + """Set a flag if --help is used to skip the main""" + ctx.esp = self._esp + ctx._commands_list = self.list_commands(ctx) # used for EatAllOptions + args = self._replace_deprecated_args(args) + return super().parse_args(ctx, args) + + def get_command(self, ctx: click.Context, cmd_name: str) -> click.Command | None: + """Allow dash and underscore for commands for compatibility with v4""" + rv = click.Group.get_command(self, ctx, cmd_name) + if rv is not None: + return rv + for cmd in self.list_commands(ctx): + cmd_alias = cmd.replace("-", "_") + if cmd_alias == cmd_name: + log.warning( + f"Deprecated: Command '{cmd_name}' is deprecated. " + f"Use '{cmd}' instead." + ) + return click.Group.get_command(self, ctx, cmd) + return None + + def resolve_command( + self, ctx: click.Context, args: list[str] + ) -> tuple[str | None, click.Command | None, list[str]]: + # always return the full command name + _, cmd, args = super().resolve_command(ctx, args) + if cmd is None: + return None, None, args + return cmd.name, cmd, args + + +class AddrFilenameArg(click.Argument): + """Parse arguments as list instead of each value individually""" + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.type = AddrFilenamePairType() + + def type_cast_value(self, ctx: click.Context, value: list[str]): + return self.type.convert(value, None, ctx) + + +class OptionEatAll(click.Option): + """Grab all arguments up to the next option/command. + Imitates argparse nargs='*' for options.""" + + def __init__(self, *args, **kwargs): + super(OptionEatAll, self).__init__(*args, **kwargs) + self._previous_parser_process = None + self._eat_all_parser = None + # Set the metavar dynamically based on the type's metavar + if self.type and hasattr(self.type, "name"): + self.metavar = f"[{self.type.get_metavar(None) or self.type.name.upper()}]" + + def add_to_parser(self, parser, ctx): + def parser_process(value, state): + # Method to hook into the parser.process + done = False + value = [value] + # Grab everything up to the next option/command + while state.rargs and not done: + for prefix in self._eat_all_parser.prefixes: + if state.rargs[0].startswith(prefix): + done = True + break + if state.rargs[0] in self._commands_list: + done = True + if not done: + value.append(state.rargs.pop(0)) + + # Call the original parser process method on the rest of the arguments + self._previous_parser_process(value, state) + + retval = super(OptionEatAll, self).add_to_parser(parser, ctx) + for name in self.opts: + # Get the parser for the current option + current_parser = parser._long_opt.get(name) or parser._short_opt.get(name) + if current_parser: + # Replace the parser.process with our hook + self._eat_all_parser = current_parser + self._previous_parser_process = current_parser.process + current_parser.process = parser_process + # Avoid reading commands as arguments if this class was used before cmd + self._commands_list = getattr(ctx, "_commands_list", []) + break + return retval + + +class MutuallyExclusiveOption(click.Option): + """Custom option class to enforce mutually exclusive options in click. + Similar to argparse function `add_mutually_exclusive_group`. + + This class ensures that certain options cannot be used together by raising + a UsageError if mutually exclusive options are provided. + + For example, `--compress` and `--no-compress` are mutually exclusive options. + """ + + def __init__(self, *args, **kwargs): + self.mutually_exclusive = set(kwargs.pop("exclusive_with", [])) + if self.mutually_exclusive: + ex_str = ", ".join( + [self._to_option_name(opt) for opt in self.mutually_exclusive] + ) + kwargs["help"] = ( + f"{kwargs.get('help', '')} NOTE: This argument is mutually exclusive " + f"with arguments: {ex_str}." + ) + super(MutuallyExclusiveOption, self).__init__(*args, **kwargs) + + def _to_option_name(self, name: str) -> str: + """Convert dictionary entry for option ('my_name') to click option name + ('--my-name'). Add '--' prefix and replace '_' with '-'. This is assuming + options don't use '_'.""" + return f"--{name.replace('_', '-')}" + + def handle_parse_result(self, ctx, opts, args): + if self.mutually_exclusive.intersection(opts) and self.name in opts: + options = ", ".join( + [self._to_option_name(opt) for opt in self.mutually_exclusive] + ) + raise click.UsageError( + f"Illegal usage: {self._to_option_name(self.name)} is mutually " + f"exclusive with arguments: {options}." + ) + return super(MutuallyExclusiveOption, self).handle_parse_result(ctx, opts, args) + + +############################## Helper functions ############################### + + +def arg_auto_int(x: str) -> int: + """Parse an integer value in any base""" + return int(x, 0) + + +def parse_port_filters( + value: list[str], +) -> tuple[list[int], list[int], list[str], list[str]]: + """Parse port filter arguments into separate lists for each filter type""" + filterVids = [] + filterPids = [] + filterNames = [] + filterSerials = [] + for f in value: + kvp = f.split("=") + if len(kvp) != 2: + FatalError("Option --port-filter argument must consist of key=value.") + if kvp[0] == "vid": + filterVids.append(arg_auto_int(kvp[1])) + elif kvp[0] == "pid": + filterPids.append(arg_auto_int(kvp[1])) + elif kvp[0] == "name": + filterNames.append(kvp[1]) + elif kvp[0] == "serial": + filterSerials.append(kvp[1]) + else: + raise FatalError("Option --port-filter argument key not recognized.") + return filterVids, filterPids, filterNames, filterSerials + + +def parse_size_arg(esp: ESPLoader, size: int | str) -> int: + """Parse the flash size argument and return the size in bytes""" + if isinstance(size, int): + if not esp.secure_download_mode: + detected_size = flash_size_bytes(detect_flash_size(esp)) + if detected_size and size > detected_size: + raise FatalError( + f"Specified size {size:#x} is greater than detected flash size " + f"{detected_size:#x}.", + ) + return size + if size.lower() != "all": + raise FatalError(f"Invalid size value: {size}. Use an integer or 'all'.") + if esp.secure_download_mode: + raise FatalError( + "Detecting flash size is not supported in secure download mode. " + "Set an exact size value.", + ) + size_str = detect_flash_size(esp) + if size_str is None: + raise FatalError("Detecting flash size failed. Set an exact size value.") + log.print(f"Detected flash size: {size_str}") + return flash_size_bytes(size_str) # type: ignore # size_str is not None diff --git a/tools/esptool_py/esptool/cmds.py b/tools/esptool_py/esptool/cmds.py index 4948c9890f..213dee84a3 100644 --- a/tools/esptool_py/esptool/cmds.py +++ b/tools/esptool_py/esptool/cmds.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2014-2022 Fredrik Ahlberg, Angus Gratton, +# SPDX-FileCopyrightText: 2014-2025 Fredrik Ahlberg, Angus Gratton, # Espressif Systems (Shanghai) CO LTD, other contributors as noted. # # SPDX-License-Identifier: GPL-2.0-or-later @@ -14,8 +14,9 @@ from intelhex import IntelHex from serial import SerialException +from typing import cast -from .bin_image import ELFFile, ImageSegment, LoadFirmwareImage +from .bin_image import ELFFile, LoadFirmwareImage from .bin_image import ( ESP8266ROMFirmwareImage, ESP8266V2FirmwareImage, @@ -28,6 +29,8 @@ ESPLoader, timeout_per_mb, ) +from .logger import log + from .targets import CHIP_DEFS, CHIP_LIST, ROM_LIST from .uf2_writer import UF2Writer from .util import ( @@ -39,12 +42,28 @@ from .util import ( div_roundup, flash_size_bytes, - get_file_size, hexify, + ImageSource, + get_bytes, + get_key_from_value, pad_to, - print_overwrite, + sanitize_string, ) + +# Vendors with different detection logic +ADESTO_VENDOR_ID = 0x1F +XMC_VENDOR_ID = 0x20 + +DETECTED_FLASH_SIZES_ADESTO = { + 0x04: "512KB", + 0x05: "1MB", + 0x06: "2MB", + 0x07: "4MB", + 0x08: "8MB", + 0x09: "16MB", +} + DETECTED_FLASH_SIZES = { 0x12: "256KB", 0x13: "512KB", @@ -71,195 +90,328 @@ 0x3A: "64MB", } -FLASH_MODES = {"qio": 0, "qout": 1, "dio": 2, "dout": 3} +FLASH_MODES = { + "qio": 0, + "qout": 1, + "dio": 2, + "dout": 3, +} def detect_chip( - port=ESPLoader.DEFAULT_PORT, - baud=ESPLoader.ESP_ROM_BAUD, - connect_mode="default_reset", - trace_enabled=False, - connect_attempts=DEFAULT_CONNECT_ATTEMPTS, -): - """Use serial access to detect the chip type. - - First, get_security_info command is sent to detect the ID of the chip - (supported only by ESP32-C3 and later, works even in the Secure Download Mode). - If this fails, we reconnect and fall-back to reading the magic number. - It's mapped at a specific ROM address and has a different value on each chip model. - This way we use one memory read and compare it to the magic number for each chip. - - This routine automatically performs ESPLoader.connect() (passing - connect_mode parameter) as part of querying the chip. + port: str = ESPLoader.DEFAULT_PORT, + baud: int = ESPLoader.ESP_ROM_BAUD, + connect_mode: str = "default-reset", + trace_enabled: bool = False, + connect_attempts: int = DEFAULT_CONNECT_ATTEMPTS, +) -> ESPLoader: + """ + Detect the type of ESP device connected via serial, + connect to it, and return an active ESPLoader object. + + Args: + port: The serial port to use for communication. + baud: The baud rate for serial communication. + connect_mode: The chip reset method to perform when connecting to the ESP device + (``"default-reset"``, ``"usb-reset"``, + ``"no-reset"``, ``"no-reset-no-sync"``) + trace_enabled: Enables or disables tracing for debugging purposes. + connect_attempts: Number of connection attempts before failing. + + Returns: + An initialized instance of the detected chip class ready for use. """ inst = None detect_port = ESPLoader(port, baud, trace_enabled=trace_enabled) if detect_port.serial_port.startswith("rfc2217:"): detect_port.USES_RFC2217 = True detect_port.connect(connect_mode, connect_attempts, detecting=True) + + def check_if_stub(instance: ESPLoader) -> ESPLoader: + log.print(f" {instance.CHIP_NAME}") + if detect_port.sync_stub_detected and instance.STUB_CLASS is not None: + instance = instance.STUB_CLASS(instance) + instance.sync_stub_detected = True + return instance + + """ + First, get-security-info command is sent to detect the ID of the chip + (supported only by ESP32-C3 and later, works even in the Secure Download Mode). + If this fails, we reconnect and fall-back to reading the magic number. + It's mapped at a specific ROM address and has a different value on each chip model. + This way we use one memory read and compare it to the magic number for each chip. + """ try: - print("Detecting chip type...", end="") + log.print("Detecting chip type...", end="", flush=True) chip_id = detect_port.get_chip_id() - for cls in [ - n for n in ROM_LIST if n.CHIP_NAME not in ("ESP8266", "ESP32", "ESP32-S2") - ]: - # cmd not supported on ESP8266 and ESP32 + ESP32-S2 doesn't return chip_id + for cls in ROM_LIST: + # cmd not supported on ESP8266 and ESP32 + ESP32-S2 doesn't return chip-id + if cls.USES_MAGIC_VALUE: + continue if chip_id == cls.IMAGE_CHIP_ID: inst = cls(detect_port._port, baud, trace_enabled=trace_enabled) - try: - inst.read_reg( - ESPLoader.CHIP_DETECT_MAGIC_REG_ADDR - ) # Dummy read to check Secure Download mode - except UnsupportedCommandError: - inst.secure_download_mode = True + si = inst.get_security_info() + inst.secure_download_mode = si["parsed_flags"]["SECURE_DOWNLOAD_ENABLE"] + inst = check_if_stub(inst) inst._post_connect() break else: err_msg = f"Unexpected chip ID value {chip_id}." - except (UnsupportedCommandError, struct.error, FatalError) as e: + except (UnsupportedCommandError, FatalError): # UnsupportedCommandError: ESP8266/ESP32 ROM - # struct.error: ESP32-S2 - # FatalError: ESP8266/ESP32 STUB - print(" Unsupported detection protocol, switching and trying again...") + # FatalError: ESP8266/ESP32 STUB or ESP32-S2 try: - # ESP32/ESP8266 are reset after an unsupported command, need to reconnect - # (not needed on ESP32-S2) - if not isinstance(e, struct.error): - detect_port.connect( - connect_mode, connect_attempts, detecting=True, warnings=False - ) - print("Detecting chip type...", end="") - sys.stdout.flush() chip_magic_value = detect_port.read_reg( ESPLoader.CHIP_DETECT_MAGIC_REG_ADDR ) - - for cls in ROM_LIST: - if chip_magic_value in cls.CHIP_DETECT_MAGIC_VALUE: - inst = cls(detect_port._port, baud, trace_enabled=trace_enabled) - inst._post_connect() - inst.check_chip_id() - break - else: - err_msg = f"Unexpected chip magic value {chip_magic_value:#010x}." except UnsupportedCommandError: - raise FatalError( - "Unsupported Command Error received. " - "Probably this means Secure Download Mode is enabled, " - "autodetection will not work. Need to manually specify the chip." + # Only ESP32-S2 does not support chip id detection + # and supports secure download mode + inst = CHIP_DEFS["esp32s2"]( + detect_port._port, baud, trace_enabled=trace_enabled ) - finally: - if inst is not None: - print(" %s" % inst.CHIP_NAME, end="") - if detect_port.sync_stub_detected: - inst = inst.STUB_CLASS(inst) - inst.sync_stub_detected = True - print("") # end line + si = inst.get_security_info() + inst.secure_download_mode = si["parsed_flags"]["SECURE_DOWNLOAD_ENABLE"] + inst = check_if_stub(inst) + inst._post_connect() return inst + except FatalError: + log.print(" Autodetection failed, trying again...") + detect_port.connect( + connect_mode, connect_attempts, detecting=True, warnings=False + ) + log.print("Detecting chip type...", end="", flush=True) + chip_magic_value = detect_port.read_reg( + ESPLoader.CHIP_DETECT_MAGIC_REG_ADDR + ) + + for cls in ROM_LIST: + if not cls.USES_MAGIC_VALUE: + continue + if chip_magic_value == cls.MAGIC_VALUE: + inst = cls(detect_port._port, baud, trace_enabled=trace_enabled) + inst = check_if_stub(inst) + inst._post_connect() + break + else: + err_msg = f"Unexpected chip magic value {chip_magic_value:#010x}." + + if inst is not None: + return inst + raise FatalError( f"{err_msg} Failed to autodetect chip type." "\nProbably it is unsupported by this version of esptool." ) -# "Operation" commands, executable at command line. One function each -# -# Each function takes either two args (, ) or a single -# argument. +# Commands that require an ESP object +##################################### -def load_ram(esp, args): - image = LoadFirmwareImage(esp.CHIP_NAME, args.filename) +def load_ram(esp: ESPLoader, input: ImageSource) -> None: + """ + Load a firmware image into RAM and execute it on the ESP device. - print("RAM boot...") - for seg in image.segments: + Args: + esp: Initiated esp object connected to a real device. + input: Path to the firmware image file, opened file-like object, + or the image data as bytes. + """ + data, source = get_bytes(input) + image = LoadFirmwareImage(esp.CHIP_NAME, data) + + log.stage() + source = "image" if source is None else f"'{source}'" + log.print(f"Loading {source} to RAM...") + for i, seg in enumerate(image.segments, start=1): size = len(seg.data) - print("Downloading %d bytes at %08x..." % (size, seg.addr), end=" ") - sys.stdout.flush() + log.progress_bar( + cur_iter=i, + total_iters=len(image.segments), + prefix=f"Downloading {size} bytes at {seg.addr:#010x} ", + suffix="...", + ) + esp.mem_begin( size, div_roundup(size, esp.ESP_RAM_BLOCK), esp.ESP_RAM_BLOCK, seg.addr ) - seq = 0 while len(seg.data) > 0: esp.mem_block(seg.data[0 : esp.ESP_RAM_BLOCK], seq) seg.data = seg.data[esp.ESP_RAM_BLOCK :] seq += 1 - print("done!") - - print("All segments done, executing at %08x" % image.entrypoint) + log.stage(finish=True) + log.print( + f"Loaded {len(image.segments)} segments from {source} to RAM, " + f"executing at {image.entrypoint:#010x}." + ) esp.mem_finish(image.entrypoint) -def read_mem(esp, args): - print("0x%08x = 0x%08x" % (args.address, esp.read_reg(args.address))) +def read_mem(esp: ESPLoader, address: int) -> None: + """ + Read and display a 32-bit value from a memory address on the ESP device. + Args: + esp: Initiated esp object connected to a real device. + address: Memory address to read from (32-bit aligned). + """ + log.print(f"{address:#010x} = {esp.read_reg(address):#010x}") -def write_mem(esp, args): - esp.write_reg(args.address, args.value, args.mask, 0) - print("Wrote %08x, mask %08x to %08x" % (args.value, args.mask, args.address)) +def write_mem(esp: ESPLoader, address: int, value: int, mask: int = 0xFFFFFFFF) -> None: + """ + Write a 32-bit value to a memory address on the ESP device with optional bitmask. -def dump_mem(esp, args): - with open(args.filename, "wb") as f: - for i in range(args.size // 4): - d = esp.read_reg(args.address + (i * 4)) - f.write(struct.pack(b"> 16 - flash_size = DETECTED_FLASH_SIZES.get(size_id) - if args is not None and args.flash_size == "detect": - if flash_size is None: - flash_size = "4MB" - print( - "WARNING: Could not auto-detect Flash size " - f"(FlashID={flash_id:#x}, SizeID={size_id:#x}), defaulting to 4MB" +def dump_mem( + esp: ESPLoader, address: int, size: int, output: str | None = None +) -> bytes | None: + """ + Dump a block of memory from the ESP device. + + Args: + esp: Initiated esp object connected to a real device. + address: Starting memory address to dump from. + size: Number of bytes to dump. + output: Path to output file for binary data. If None, returns the data. + + Returns: + Memory dump as bytes if output is None; + otherwise, returns None after writing to file. + """ + data = io.BytesIO() # Use BytesIO to store the memory dump + log.stage() + log.print( + f"Dumping {size} bytes from {address:#010x}" + + (f" to file '{output}'..." if output else "...") + ) + t = time.time() + # Read the memory in 4-byte chunks. + for i in range(size // 4): + cur_addr = address + (i * 4) + d = esp.read_reg(cur_addr) + data.write(struct.pack(" 0.0 else "" + dest_msg = f" to '{output}'" if output else "" + log.stage(finish=True) + log.print( + f"Dumped {data.tell()} bytes from {address:#010x} in {t:.1f} seconds" + f"{speed_msg}{dest_msg}." + ) + if output: + with open(output, "wb") as f: + f.write(data.getvalue()) + return None + else: + return data.getvalue() + + +def _get_flash_info(esp: ESPLoader, cache: bool = True) -> tuple[int, int, str | None]: + """ + Get the flash memory chip information including vendor ID, device ID, and + flash size. + + Args: + esp: Initiated esp object connected to a real device. + cache: Whether to use cached flash ID (default: True). + + Returns: + Tuple containing (vendor_id, device_id, flash_size) + """ + flash_id = esp.flash_id(cache=cache) + vendor_id = flash_id & 0xFF + # Swap the bytes of the device ID by taking the high byte first, then the low byte + device_id = ((flash_id >> 16) & 0xFF) | ((flash_id >> 8) & 0xFF) << 8 + + if vendor_id == ADESTO_VENDOR_ID: + # Lower 5 bits of second byte of flash_id is size_id + size_id = (flash_id >> 8) & 0x1F + flash_size = DETECTED_FLASH_SIZES_ADESTO.get(size_id) + else: + size_id = flash_id >> 16 + flash_size = DETECTED_FLASH_SIZES.get(size_id) + + return vendor_id, device_id, flash_size + + +def detect_flash_size(esp: ESPLoader) -> str | None: + """ + Detect the flash size of the connected ESP device. + + Args: + esp: Initiated esp object connected to a real device. + + Returns: + Detected flash size in bytes, or None if unrecognized. + """ + if esp.secure_download_mode: + raise FatalError( + "Detecting flash size is not supported in secure download mode. " + "Need to manually specify flash size." + ) + _, _, flash_size = _get_flash_info(esp) return flash_size -def _update_image_flash_params(esp, address, args, image): +def _update_image_flash_params(esp, address, flash_freq, flash_mode, flash_size, image): """ - Modify the flash mode & size bytes if this looks like an executable bootloader image + Update the flash mode, size, and freq parameters in a bootloader image, + if applicable. + + Args: + esp (ESPLoader): ESPLoader object that provides device-specific attributes + (e.g., BOOTLOADER_FLASH_OFFSET, ESP_IMAGE_MAGIC, CHIP_NAME) and methods for + image verification and parameter parsing. + address (int): The flash memory address where the image is to be written. + flash_freq (str, optional): Flash frequency setting + (``"keep"`` to retain current). + flash_mode (str, optional): Flash mode setting + (``"keep"`` to retain current). + flash_size (str, optional): Flash size setting + (``"keep"`` to retain current). + image (bytes): The image data that may contain an executable bootloader image. + + Returns: + bytes: The modified image data with updated flash parameters + (and recalculated SHA256 digest, if applicable), + or the original image if no modifications were performed. """ if len(image) < 8: return image # not long enough to be a bootloader image - - # unpack the (potential) image header - magic, _, flash_mode, flash_size_freq = struct.unpack("BBBB", image[:4]) if address != esp.BOOTLOADER_FLASH_OFFSET: return image # not flashing bootloader offset, so don't modify this - - if (args.flash_mode, args.flash_freq, args.flash_size) == ("keep",) * 3: + if (flash_mode, flash_freq, flash_size) == ("keep",) * 3: return image # all settings are 'keep', not modifying anything + # unpack the (potential) image header + magic, _, img_flash_mode, img_flash_size_freq = struct.unpack("BBBB", image[:4]) + # easy check if this is an image: does it start with a magic byte? if magic != esp.ESP_IMAGE_MAGIC: - print( - "Warning: Image file at 0x%x doesn't look like an image file, " - "so not changing any flash settings." % address + log.warning( + f"Image file at {address:#x} doesn't look like an image file, " + "so not changing any flash settings." ) return image @@ -270,31 +422,33 @@ def _update_image_flash_params(esp, address, args, image): test_image = esp.BOOTLOADER_IMAGE(io.BytesIO(image)) test_image.verify() except Exception: - print( - "Warning: Image file at 0x%x is not a valid %s image, " - "so not changing any flash settings." % (address, esp.CHIP_NAME) + log.warning( + f"Image file at {address:#x} is not a valid {esp.CHIP_NAME} image," + " so not changing any flash settings." ) return image # After the 8-byte header comes the extended header for chips others than ESP8266. - # The 15th byte of the extended header indicates if the image is protected by - # a SHA256 checksum. In that case we recalculate the SHA digest after modifying the header. - sha_appended = args.chip != "esp8266" and image[8 + 15] == 1 + # The 15th byte of the extended header indicates if the image is protected by SHA256 + # checksum. In that case we recalculate the SHA digest after modifying the header. + sha_appended = esp.CHIP_NAME != "esp8266" and image[8 + 15] == 1 - if args.flash_mode != "keep": - flash_mode = FLASH_MODES[args.flash_mode] + if flash_mode != "keep": + img_flash_mode = FLASH_MODES[flash_mode] - flash_freq = flash_size_freq & 0x0F - if args.flash_freq != "keep": - flash_freq = esp.parse_flash_freq_arg(args.flash_freq) + img_flash_freq = img_flash_size_freq & 0x0F + if flash_freq != "keep": + img_flash_freq = esp.parse_flash_freq_arg(flash_freq) - flash_size = flash_size_freq & 0xF0 - if args.flash_size != "keep": - flash_size = esp.parse_flash_size_arg(args.flash_size) + img_flash_size = img_flash_size_freq & 0xF0 + if flash_size != "keep": + img_flash_size = esp.parse_flash_size_arg(flash_size) - flash_params = struct.pack(b"BB", flash_mode, flash_size + flash_freq) + flash_params = struct.pack(b"BB", img_flash_mode, img_flash_size + img_flash_freq) if flash_params != image[2:4]: - print("Flash params set to 0x%04x" % struct.unpack(">H", flash_params)) + log.print( + f"Flash parameters set to {struct.unpack('>H', flash_params)[0]:#06x}." + ) image = image[0:2] + flash_params + image[4:] # recalculate the SHA digest if it was appended @@ -317,17 +471,17 @@ def _update_image_flash_params(esp, address, args, image): ) ) - # get the SHA digest newly stored in the image and compare it to the calculated one + # get SHA digest newly stored in the image and compare it to the calculated one image_stored_sha = image[ image_object.data_length : image_object.data_length + image_object.SHA256_DIGEST_LEN ] if hexify(sha_digest_calculated) == hexify(image_stored_sha): - print("SHA digest in image updated") + log.print("SHA digest in image updated.") else: - print( - "WARNING: SHA recalculation for binary failed!\n" + log.warning( + "SHA recalculation for binary failed!\n" f"\tExpected calculated SHA: {hexify(sha_digest_calculated)}\n" f"\tSHA stored in binary: {hexify(image_stored_sha)}" ) @@ -335,36 +489,85 @@ def _update_image_flash_params(esp, address, args, image): return image -def write_flash(esp, args): - # set args.compress based on default behaviour: - # -> if either --compress or --no-compress is set, honour that - # -> otherwise, set --compress unless --no-stub is set - if args.compress is None and not args.no_compress: - args.compress = not args.no_stub - - if not args.force and esp.CHIP_NAME != "ESP8266" and not esp.secure_download_mode: +def write_flash( + esp: ESPLoader, + addr_data: list[tuple[int, ImageSource]], + flash_freq: str = "keep", + flash_mode: str = "keep", + flash_size: str = "keep", + **kwargs, +) -> None: + """ + Write firmware or data to the SPI flash memory of an ESP device. + + Args: + esp: Initiated esp object connected to a real device. + addr_data: List of (address, data) tuples specifying where + to write each file or data in flash memory. The data can be + a file path (str), bytes, or a file-like object. + flash_freq: Flash frequency to set in the bootloader image header + (``"keep"`` to retain current). + flash_mode: Flash mode to set in the bootloader image header + (``"keep"`` to retain current). + flash_size: Flash size to set in the bootloader image header + (``"keep"`` to retain current). + + Keyword Args: + erase_all (bool): Erase the entire flash before writing. + encrypt (bool): Encrypt all files during flashing. + encrypt_files (list[tuple[int, ImageSource]] | None): List of + (address, data) tuples for files to encrypt individually. + compress (bool): Compress data before flashing. + no_compress (bool): Don't compress data before flashing. + force (bool): Ignore safety checks (e.g., overwriting bootloader, flash size). + ignore_flash_enc_efuse (bool): Ignore flash encryption eFuse settings. + no_progress (bool): Disable progress updates. + """ + # Normalize addr_data to use bytes + norm_addr_data = [(addr, get_bytes(data)) for addr, data in addr_data] + + # Set default values of optional arguments + erase_all: bool = kwargs.get("erase_all", False) + encrypt: bool = kwargs.get("encrypt", False) + encrypt_files: list[tuple[int, ImageSource]] | None = kwargs.get( + "encrypt_files", None + ) + compress: bool = kwargs.get("compress", False) + no_compress: bool = kwargs.get("no_compress", False) + force: bool = kwargs.get("force", False) + ignore_flash_enc_efuse: bool = kwargs.get("ignore_flash_enc_efuse", False) + no_progress: bool = kwargs.get("no_progress", False) + + # set compress based on default behaviour: + # -> if either "compress" or "no_compress" is set, honour that + # -> otherwise, set "compress" unless the stub flasher is disabled + if not compress and not no_compress: + compress = esp.IS_STUB + + if not force and esp.CHIP_NAME != "ESP8266" and not esp.secure_download_mode: # Check if secure boot is active if esp.get_secure_boot_enabled(): - for address, _ in args.addr_filename: + for address, _ in norm_addr_data: if address < 0x8000: raise FatalError( "Secure Boot detected, writing to flash regions < 0x8000 " "is disabled to protect the bootloader. " - "Use --force to override, " + "Use the force argument to override, " "please use with caution, otherwise it may brick your device!" ) # Check if chip_id and min_rev in image are valid for the target in use - for _, argfile in args.addr_filename: + for _, (data, name) in norm_addr_data: try: - image = LoadFirmwareImage(esp.CHIP_NAME, argfile) + image = LoadFirmwareImage(esp.CHIP_NAME, data) except (FatalError, struct.error, RuntimeError): continue - finally: - argfile.seek(0) # LoadFirmwareImage changes the file handle position if image.chip_id != esp.IMAGE_CHIP_ID: + msg = ( + "Input does not contain" if name is None else f"'{name}' is not an" + ) raise FatalError( - f"{argfile.name} is not an {esp.CHIP_NAME} image. " - "Use --force to flash anyway." + f"{msg} an {esp.CHIP_NAME} image. " + "Use the force argument to flash anyway." ) # this logic below decides which min_rev to use, min_rev or min/max_rev_full @@ -382,7 +585,7 @@ def write_flash(esp, args): if use_rev_full_fields: rev = esp.get_chip_revision() if rev < image.min_rev_full or rev > image.max_rev_full: - error_str = f"{argfile.name} requires chip revision in range " + error_str = f"'{name}' requires chip revision in range " error_str += ( f"[v{image.min_rev_full // 100}.{image.min_rev_full % 100} - " ) @@ -393,7 +596,9 @@ def write_flash(esp, args): f"v{image.max_rev_full // 100}.{image.max_rev_full % 100}] " ) error_str += f"(this chip is revision v{rev // 100}.{rev % 100})" - raise FatalError(f"{error_str}. Use --force to flash anyway.") + raise FatalError( + f"{error_str}. Use the force argument to flash anyway." + ) else: # In IDF, image.min_rev is set based on Kconfig option. # For C3 chip, image.min_rev is the Minor revision @@ -404,14 +609,14 @@ def write_flash(esp, args): rev = esp.get_major_chip_version() if rev < image.min_rev: raise FatalError( - f"{argfile.name} requires chip revision " + f"'{name}' requires chip revision " f"{image.min_rev} or higher (this chip is revision {rev}). " - "Use --force to flash anyway." + "Use the force argument to flash anyway." ) # In case we have encrypted files to write, # we first do few sanity checks before actual flash - if args.encrypt or args.encrypt_files is not None: + if encrypt or encrypt_files is not None: do_write = True if not esp.secure_download_mode: @@ -426,33 +631,40 @@ def write_flash(esp, args): crypt_cfg_efuse = esp.get_flash_crypt_config() if crypt_cfg_efuse is not None and crypt_cfg_efuse != 0xF: - print("Unexpected FLASH_CRYPT_CONFIG value: 0x%x" % (crypt_cfg_efuse)) + log.print(f"Unexpected FLASH_CRYPT_CONFIG value: {crypt_cfg_efuse:#x}") do_write = False enc_key_valid = esp.is_flash_encryption_key_valid() if not enc_key_valid: - print("Flash encryption key is not programmed") + log.print("Flash encryption key is not programmed.") do_write = False # Determine which files list contain the ones to encrypt - files_to_encrypt = args.addr_filename if args.encrypt else args.encrypt_files + files_to_encrypt = ( + norm_addr_data + if encrypt is not None + else [(addr, get_bytes(data)) for addr, data in encrypt_files] + ) - for address, argfile in files_to_encrypt: - if address % esp.FLASH_ENCRYPTED_WRITE_ALIGN: - print( - "File %s address 0x%x is not %d byte aligned, can't flash encrypted" - % (argfile.name, address, esp.FLASH_ENCRYPTED_WRITE_ALIGN) - ) - do_write = False + if files_to_encrypt is not None: + for address, (data, name) in files_to_encrypt: + if address % esp.FLASH_ENCRYPTED_WRITE_ALIGN: + source = "Input image" if name is None else f"'{name}'" + log.warning( + f"{source} (address {address:#x}) is not " + f"{esp.FLASH_ENCRYPTED_WRITE_ALIGN} byte aligned, " + "can't flash encrypted." + ) + do_write = False - if not do_write and not args.ignore_flash_encryption_efuse_setting: + if not do_write and not ignore_flash_enc_efuse: raise FatalError( "Can't perform encrypted flash write, " - "consult Flash Encryption documentation for more information" + "consult Flash Encryption documentation for more information." ) else: - if not args.force and esp.CHIP_NAME != "ESP8266": + if not force and esp.CHIP_NAME != "ESP8266": # ESP32 does not support `get_security_info()` and `secure_download_mode` if ( esp.CHIP_NAME != "ESP32" @@ -463,7 +675,7 @@ def write_flash(esp, args): "WARNING: Detected flash encryption and " "secure download mode enabled.\n" "Flashing plaintext binary may brick your device! " - "Use --force to override the warning." + "Use the force argument to override the warning." ) if ( @@ -475,56 +687,53 @@ def write_flash(esp, args): "WARNING: Detected flash encryption enabled and " "download manual encrypt disabled.\n" "Flashing plaintext binary may brick your device! " - "Use --force to override the warning." + "Use the force argument to override the warning." ) + flash_size = _set_flash_parameters(esp, flash_size) # Set flash size parameters + set_flash_size = ( - flash_size_bytes(args.flash_size) - if args.flash_size not in ["detect", "keep"] - else None + flash_size_bytes(flash_size) if flash_size not in ["detect", "keep"] else None ) if esp.secure_download_mode: flash_end = set_flash_size else: # Check against real flash chip size if not in SDM flash_end_str = detect_flash_size(esp) flash_end = flash_size_bytes(flash_end_str) - if set_flash_size and set_flash_size > flash_end: - print( - f"WARNING: Set --flash_size {args.flash_size} " + if set_flash_size and flash_end and set_flash_size > flash_end: + log.warning( + f"Set flash_size {flash_size} " f"is larger than the available flash size of {flash_end_str}." ) - # Verify file sizes fit in the set --flash_size, or real flash size if smaller - flash_end = min(set_flash_size, flash_end) if set_flash_size else flash_end + # Verify file sizes fit in the set flash_size, or real flash size if smaller + flash_end = ( + min(set_flash_size, flash_end) if set_flash_size and flash_end else flash_end + ) if flash_end is not None: - for address, argfile in args.addr_filename: - argfile.seek(0, os.SEEK_END) - if address + argfile.tell() > flash_end: + for address, (data, name) in norm_addr_data: + if address + len(data) > flash_end: + source = "Input image" if name is None else f"File '{name}'" raise FatalError( - f"File {argfile.name} (length {argfile.tell()}) at offset " - f"{address} will not fit in {flash_end} bytes of flash. " - "Change the --flash_size argument, or flashing address." + f"{source} (length {len(data)}) at offset " + f"{address:#010x} will not fit in {flash_end} bytes of flash. " + "Change the flash_size argument or flashing address." ) - argfile.seek(0) - if args.erase_all: - erase_flash(esp, args) + if erase_all: + erase_flash(esp) else: - for address, argfile in args.addr_filename: - argfile.seek(0, os.SEEK_END) - write_end = address + argfile.tell() - argfile.seek(0) + for address, (data, _) in norm_addr_data: + write_end = address + len(data) bytes_over = address % esp.FLASH_SECTOR_SIZE if bytes_over != 0: - print( - "WARNING: Flash address {:#010x} is not aligned " - "to a {:#x} byte flash sector. " - "{:#x} bytes before this address will be erased.".format( - address, esp.FLASH_SECTOR_SIZE, bytes_over - ) + log.note( + f"Flash address {address:#010x} is not aligned " + f"to a {esp.FLASH_SECTOR_SIZE:#x} byte flash sector. " + f"{bytes_over:#x} bytes before this address will be erased." ) # Print the address range of to-be-erased flash memory region - print( + log.print( "Flash will be erased from {:#010x} to {:#010x}...".format( address - bytes_over, div_roundup(write_end, esp.FLASH_SECTOR_SIZE) @@ -533,29 +742,28 @@ def write_flash(esp, args): ) ) - """ Create a list describing all the files we have to flash. + """ + Create a list describing all the files we have to flash. Each entry holds an "encrypt" flag marking whether the file needs encryption or not. This list needs to be sorted. - First, append to each entry of our addr_filename list the flag args.encrypt - E.g., if addr_filename is [(0x1000, "partition.bin"), (0x8000, "bootloader")], + First, append to each entry of our addr_data list the flag "encrypt" + E.g., if addr_data is [(0x1000, "partition.bin"), (0x8000, "bootloader")], all_files will be [ - (0x1000, "partition.bin", args.encrypt), - (0x8000, "bootloader", args.encrypt) + (0x1000, data, "partition.bin", encrypt), + (0x8000, data, "bootloader", encrypt) ], - where, of course, args.encrypt is either True or False + where, of course, encrypt is either True or False """ - all_files = [ - (offs, filename, args.encrypt) for (offs, filename) in args.addr_filename - ] + all_files = [(addr, data, name, encrypt) for (addr, (data, name)) in norm_addr_data] """ Now do the same with encrypt_files list, if defined. In this case, the flag is True """ - if args.encrypt_files is not None: + if encrypt_files is not None: encrypted_files_flag = [ - (offs, filename, True) for (offs, filename) in args.encrypt_files + (addr, *get_bytes(data), True) for (addr, data) in encrypt_files ] # Concatenate both lists and sort them. @@ -564,71 +772,80 @@ def write_flash(esp, args): # let's use sorted. all_files = sorted(all_files + encrypted_files_flag, key=lambda x: x[0]) - for address, argfile, encrypted in all_files: - compress = args.compress + for address, data, name, encrypted in all_files: + compress = compress # Check whether we can compress the current file before flashing if compress and encrypted: - print("\nWARNING: - compress and encrypt options are mutually exclusive ") - print("Will flash %s uncompressed" % argfile.name) + source = "input bytes" if name is None else f"'{name}'" + log.print("\n") + log.warning("Compress and encrypt options are mutually exclusive.") + log.print(f"Will flash {source} uncompressed.") compress = False - image = argfile.read() + image = data if len(image) == 0: - print("WARNING: File %s is empty" % argfile.name) + log.warning( + "Input bytes are empty." if name is None else f"'{name}' is empty." + ) continue image = pad_to(image, esp.FLASH_ENCRYPTED_WRITE_ALIGN if encrypted else 4) - if args.no_stub: - print("Erasing flash...") + if not esp.IS_STUB: + log.print("Erasing flash...") # It is not possible to write to not aligned addresses without stub, # so there are added 0xFF (erase) bytes at the beginning of the image # to align it. bytes_over = address % esp.FLASH_SECTOR_SIZE address -= bytes_over - image = b"\xFF" * bytes_over + image + image = b"\xff" * bytes_over + image if not esp.secure_download_mode and not esp.get_secure_boot_enabled(): - image = _update_image_flash_params(esp, address, args, image) + image = _update_image_flash_params( + esp, address, flash_freq, flash_mode, flash_size, image + ) else: - print( - "WARNING: Security features enabled, so not changing any flash settings." + log.warning( + "Security features enabled, so not changing any flash settings." ) calcmd5 = hashlib.md5(image).hexdigest() uncsize = len(image) if compress: uncimage = image image = zlib.compress(uncimage, 9) + compsize = len(image) original_image = image # Save the whole image in case retry is needed # Try again if reconnect was successful + log.stage() for attempt in range(1, esp.WRITE_FLASH_ATTEMPTS + 1): try: if compress: # Decompress the compressed binary a block at a time, # to dynamically calculate the timeout based on the real write size decompress = zlib.decompressobj() - blocks = esp.flash_defl_begin(uncsize, len(image), address) + esp.flash_defl_begin(uncsize, compsize, address) else: - blocks = esp.flash_begin( - uncsize, address, begin_rom_encrypted=encrypted - ) - argfile.seek(0) # in case we need it again + esp.flash_begin(uncsize, address, begin_rom_encrypted=encrypted) seq = 0 bytes_sent = 0 # bytes sent on wire bytes_written = 0 # bytes written to flash t = time.time() timeout = DEFAULT_TIMEOUT - - while len(image) > 0: - print_overwrite( - "Writing at 0x%08x... (%d %%)" - % (address + bytes_written, 100 * (seq + 1) // blocks) - ) - sys.stdout.flush() + image_size = compsize if compress else uncsize + while len(image) >= 0: + if not no_progress: + log.progress_bar( + cur_iter=image_size - len(image), + total_iters=image_size, + prefix=f"Writing at {address + bytes_written:#010x} ", + suffix=f" {bytes_sent}/{image_size} bytes...", + ) + if len(image) == 0: # All data sent, print 100% progress and end + break block = image[0 : esp.FLASH_WRITE_SIZE] if compress: # feeding each compressed block into the decompressor lets us @@ -642,7 +859,8 @@ def write_flash(esp, args): ), ) if not esp.IS_STUB: - timeout = block_timeout # ROM code writes block to flash before ACKing + # ROM code writes block to flash before ACKing + timeout = block_timeout esp.flash_defl_block(block, seq, timeout=timeout) if esp.IS_STUB: # Stub ACKs when block is received, @@ -662,16 +880,17 @@ def write_flash(esp, args): break except SerialException: if attempt == esp.WRITE_FLASH_ATTEMPTS or encrypted: - # Already retried once or encrypted mode is disabled because of security reasons + # Already retried once or encrypted mode is disabled because of + # security reasons raise - print("\nLost connection, retrying...") + log.print("\nLost connection, retrying...") esp._port.close() - print("Waiting for the chip to reconnect", end="") + log.print("Waiting for the chip to reconnect", end="") for _ in range(DEFAULT_CONNECT_ATTEMPTS): try: time.sleep(1) esp._port.open() - print() # Print new line which was suppressed by print(".") + log.print() # Print new line which was suppressed by print(".") esp.connect() if esp.IS_STUB: # Hack to bypass the stub overwrite check @@ -681,8 +900,7 @@ def write_flash(esp, args): image = original_image break except SerialException: - print(".", end="") - sys.stdout.flush() + log.print(".", end="", flush=True) else: raise # Reconnect limit reached @@ -694,40 +912,41 @@ def write_flash(esp, args): t = time.time() - t speed_msg = "" + log.stage(finish=True) if compress: if t > 0.0: - speed_msg = " (effective %.1f kbit/s)" % (uncsize / t * 8 / 1000) - print_overwrite( - "Wrote %d bytes (%d compressed) at 0x%08x in %.1f seconds%s..." - % (uncsize, bytes_sent, address, t, speed_msg), - last_line=True, + speed_msg = f" ({uncsize / t * 8 / 1000:.1f} kbit/s)" + log.print( + f"Wrote {uncsize} bytes ({bytes_sent} compressed) " + f"at {address:#010x} in {t:.1f} seconds{speed_msg}." ) else: if t > 0.0: speed_msg = " (%.1f kbit/s)" % (bytes_written / t * 8 / 1000) - print_overwrite( - "Wrote %d bytes at 0x%08x in %.1f seconds%s..." - % (bytes_written, address, t, speed_msg), - last_line=True, + log.print( + f"Wrote {bytes_written} bytes at {address:#010x} in {t:.1f} " + f"seconds{speed_msg}." ) if not encrypted and not esp.secure_download_mode: try: res = esp.flash_md5sum(address, uncsize) if res != calcmd5: - print("File md5: %s" % calcmd5) - print("Flash md5: %s" % res) - print( - "MD5 of 0xFF is %s" - % (hashlib.md5(b"\xff" * uncsize).hexdigest()) - ) + log.print(f"Input MD5: {calcmd5}") + log.print(f"Flash MD5: {res}") + if res == hashlib.md5(b"\xff" * uncsize).hexdigest(): + raise FatalError( + "Write failed, the written flash region is empty." + ) raise FatalError("MD5 of file does not match data in flash!") else: - print("Hash of data verified.") + log.print("Hash of data verified.") except NotImplementedInROMError: pass - - print("\nLeaving...") + else: + log.print( + "Cannot verify written data if encrypted or in secure download mode." + ) if esp.IS_STUB: # skip sending flash_finish to ROM loader here, @@ -735,592 +954,556 @@ def write_flash(esp, args): esp.flash_begin(0, 0) # Get the "encrypted" flag for the last file flashed - # Note: all_files list contains triplets like: - # (address: Integer, filename: String, encrypted: Boolean) - last_file_encrypted = all_files[-1][2] + # Note: all_files list contains quadruplets like: + # (address: int, filename: str | None, data: bytes, encrypted: bool) + last_file_encrypted = all_files[-1][3] # Check whether the last file flashed was compressed or not - if args.compress and not last_file_encrypted: + if compress and not last_file_encrypted: esp.flash_defl_finish(False) else: esp.flash_finish(False) - if args.verify: - print("Verifying just-written flash...") - print( - "(This option is deprecated, " - "flash contents are now always read back after flashing.)" - ) - # If some encrypted files have been flashed, - # print a warning saying that we won't check them - if args.encrypt or args.encrypt_files is not None: - print("WARNING: - cannot verify encrypted files, they will be ignored") - # Call verify_flash function only if there is at least - # one non-encrypted file flashed - if not args.encrypt: - verify_flash(esp, args) - - -def image_info(args): - def v2(): - def get_key_from_value(dict, val): - """Get key from value in dictionary""" - for key, value in dict.items(): - if value == val: - return key - return None - - print() - title = "{} image header".format(args.chip.upper()) - print(title) - print("=" * len(title)) - print("Image version: {}".format(image.version)) - print( - "Entry point: {:#8x}".format(image.entrypoint) - if image.entrypoint != 0 - else "Entry point not set" - ) - - print("Segments: {}".format(len(image.segments))) - - # Flash size - flash_s_bits = image.flash_size_freq & 0xF0 # high four bits - flash_s = get_key_from_value(image.ROM_LOADER.FLASH_SIZES, flash_s_bits) - print( - "Flash size: {}".format(flash_s) - if flash_s is not None - else "WARNING: Invalid flash size ({:#02x})".format(flash_s_bits) - ) - - # Flash frequency - flash_fr_bits = image.flash_size_freq & 0x0F # low four bits - flash_fr = get_key_from_value(image.ROM_LOADER.FLASH_FREQUENCY, flash_fr_bits) - print( - "Flash freq: {}".format(flash_fr) - if flash_fr is not None - else "WARNING: Invalid flash frequency ({:#02x})".format(flash_fr_bits) - ) - - # Flash mode - flash_mode = get_key_from_value(FLASH_MODES, image.flash_mode) - print( - "Flash mode: {}".format(flash_mode.upper()) - if flash_mode is not None - else "WARNING: Invalid flash mode ({})".format(image.flash_mode) - ) - - # Extended header (ESP32 and later only) - if args.chip != "esp8266": - print() - title = "{} extended image header".format(args.chip.upper()) - print(title) - print("=" * len(title)) - print( - f"WP pin: {image.wp_pin:#02x}", - *["(disabled)"] if image.wp_pin == image.WP_PIN_DISABLED else [], - ) - print( - "Flash pins drive settings: " - "clk_drv: {:#02x}, q_drv: {:#02x}, d_drv: {:#02x}, " - "cs0_drv: {:#02x}, hd_drv: {:#02x}, wp_drv: {:#02x}".format( - image.clk_drv, - image.q_drv, - image.d_drv, - image.cs_drv, - image.hd_drv, - image.wp_drv, - ) - ) - try: - chip = next( - chip - for chip in CHIP_DEFS.values() - if getattr(chip, "IMAGE_CHIP_ID", None) == image.chip_id - ) - print(f"Chip ID: {image.chip_id} ({chip.CHIP_NAME})") - except StopIteration: - print(f"Chip ID: {image.chip_id} (Unknown ID)") - print( - "Minimal chip revision: " - f"v{image.min_rev_full // 100}.{image.min_rev_full % 100}, " - f"(legacy min_rev = {image.min_rev})" - ) - print( - "Maximal chip revision: " - f"v{image.max_rev_full // 100}.{image.max_rev_full % 100}" - ) - print() - - # Segments overview - title = "Segments information" - print(title) - print("=" * len(title)) - headers_str = "{:>7} {:>7} {:>10} {:>10} {:10}" - print( - headers_str.format( - "Segment", "Length", "Load addr", "File offs", "Memory types" - ) - ) - print( - "{} {} {} {} {}".format("-" * 7, "-" * 7, "-" * 10, "-" * 10, "-" * 12) - ) - format_str = "{:7} {:#07x} {:#010x} {:#010x} {}" - app_desc = None - bootloader_desc = None - for idx, seg in enumerate(image.segments): - segs = seg.get_memory_type(image) - seg_name = ", ".join(segs) - if "DROM" in segs: # The DROM segment starts with the esp_app_desc_t struct - app_desc = seg.data[:256] - elif "DRAM" in segs: - # The DRAM segment starts with the esp_bootloader_desc_t struct - if len(seg.data) >= 80: - bootloader_desc = seg.data[:80] - print( - format_str.format(idx, len(seg.data), seg.addr, seg.file_offs, seg_name) - ) - print() - - # Footer - title = f"{args.chip.upper()} image footer" - print(title) - print("=" * len(title)) - calc_checksum = image.calculate_checksum() - print( - "Checksum: {:#02x} ({})".format( - image.checksum, - ( - "valid" - if image.checksum == calc_checksum - else "invalid - calculated {:02x}".format(calc_checksum) - ), - ) - ) - try: - digest_msg = "Not appended" - if image.append_digest: - is_valid = image.stored_digest == image.calc_digest - digest_msg = "{} ({})".format( - hexify(image.calc_digest, uppercase=False), - "valid" if is_valid else "invalid", - ) - print("Validation hash: {}".format(digest_msg)) - except AttributeError: - pass # ESP8266 image has no append_digest field - - if app_desc: - APP_DESC_STRUCT_FMT = " None: + """ + Read and display the MAC address of the ESP device. - # append_digest, either 0 or 1 - if extended_header[-1] not in [0, 1]: - raise FatalError("Append digest field not 0 or 1") + Args: + esp: Initiated esp object connected to a real device. + """ - chip_id = int.from_bytes(extended_header[4:5], "little") - for rom in [n for n in ROM_LIST if n.CHIP_NAME != "ESP8266"]: - if chip_id == rom.IMAGE_CHIP_ID: - args.chip = rom.CHIP_NAME - break - else: - raise FatalError(f"Unknown image chip ID ({chip_id})") - except FatalError: - args.chip = "esp8266" + def print_mac(label, mac): + log.print(f"{label + ':':<20}{':'.join(f'{x:02x}' for x in mac)}") - print(f"Detected image type: {args.chip.upper()}") + eui64 = esp.read_mac("EUI64") + if eui64: + print_mac("MAC", eui64) + print_mac("BASE MAC", esp.read_mac("BASE_MAC")) + print_mac("MAC_EXT", esp.read_mac("MAC_EXT")) + else: + print_mac("MAC", esp.read_mac("BASE_MAC")) - image = LoadFirmwareImage(args.chip, args.filename) - if args.version == "2": - v2() - return +def chip_id(esp: ESPLoader) -> None: + """ + Read and display the Chip ID of the ESP device if available, + otherwise fall back to displaying the MAC address. - print("Image version: {}".format(image.version)) - print( - "Entry point: {:8x}".format(image.entrypoint) - if image.entrypoint != 0 - else "Entry point not set" - ) - print("{} segments".format(len(image.segments))) - print() - idx = 0 - for seg in image.segments: - idx += 1 - segs = seg.get_memory_type(image) - seg_name = ",".join(segs) - print("Segment {}: {} [{}]".format(idx, seg, seg_name)) - calc_checksum = image.calculate_checksum() - print( - "Checksum: {:02x} ({})".format( - image.checksum, - ( - "valid" - if image.checksum == calc_checksum - else "invalid - calculated {:02x}".format(calc_checksum) - ), - ) - ) + Args: + esp: Initiated esp object connected to a real device. + """ try: - digest_msg = "Not appended" - if image.append_digest: - is_valid = image.stored_digest == image.calc_digest - digest_msg = "{} ({})".format( - hexify(image.calc_digest, uppercase=False), - "valid" if is_valid else "invalid", - ) - print("Validation Hash: {}".format(digest_msg)) - except AttributeError: - pass # ESP8266 image has no append_digest field - - -def make_image(args): - print("Creating {} image...".format(args.chip)) - image = ESP8266ROMFirmwareImage() - if len(args.segfile) == 0: - raise FatalError("No segments specified") - if len(args.segfile) != len(args.segaddr): - raise FatalError( - "Number of specified files does not match number of specified addresses" - ) - for seg, addr in zip(args.segfile, args.segaddr): - with open(seg, "rb") as f: - data = f.read() - image.segments.append(ImageSegment(addr, data)) - image.entrypoint = args.entrypoint - image.save(args.output) - print("Successfully created {} image.".format(args.chip)) - + chipid = esp.chip_id() + log.print(f"Chip ID: {chipid:#010x}") + except NotSupportedError: + log.warning(f"{esp.CHIP_NAME} has no chip ID. Reading MAC address instead.") + read_mac(esp) -def elf2image(args): - e = ELFFile(args.input) - if args.chip == "auto": # Default to ESP8266 for backwards compatibility - args.chip = "esp8266" - print("Creating {} image...".format(args.chip)) +def attach_flash( + esp: ESPLoader, + spi_connection: (tuple[int, int, int, int, int] | str) | None = None, +) -> None: + """ + Configure and attach a SPI flash memory chip to the ESP device, + verify the connection. + All following flash operations will be performed on the attached flash chip. + + Args: + esp: Initiated esp object connected to a real device. + spi_connection: Custom SPI connection configuration. + This can either be a tuple containing five pin numbers + ``(CLK, Q, D, HD, CS)`` for manual configuration + or a string (``"SPI"`` or ``"HSPI"``) representing a pre-defined config. + If not provided, the default flash connection is used. + """ - if args.chip != "esp8266": - image = CHIP_DEFS[args.chip].BOOTLOADER_IMAGE() - if args.chip == "esp32" and args.secure_pad: - image.secure_pad = "1" - if args.secure_pad_v2: - image.secure_pad = "2" - image.min_rev = args.min_rev - image.min_rev_full = args.min_rev_full - image.max_rev_full = args.max_rev_full - image.ram_only_header = args.ram_only_header - if image.ram_only_header: - image.append_digest = False + def _define_spi_conn(spi_connection): + """Prepare SPI configuration string and value for flash_spi_attach()""" + clk, q, d, hd, cs = spi_connection + spi_config_txt = f"CLK:{clk}, Q:{q}, D:{d}, HD:{hd}, CS:{cs}" + value = (hd << 24) | (cs << 18) | (d << 12) | (q << 6) | clk + return spi_config_txt, value + + # Override the common SPI flash parameter stuff if configured to do so + if spi_connection is not None: + spi_config = spi_connection + if spi_connection == "SPI": + value = 0 + elif spi_connection == "HSPI": + value = 1 else: - image.append_digest = args.append_digest - elif args.version == "1": # ESP8266 - image = ESP8266ROMFirmwareImage() - elif args.version == "2": - image = ESP8266V2FirmwareImage() - else: - image = ESP8266V3FirmwareImage() - image.entrypoint = e.entrypoint - image.flash_mode = FLASH_MODES[args.flash_mode] - - if args.flash_mmu_page_size: - image.set_mmu_page_size(flash_size_bytes(args.flash_mmu_page_size)) - - # ELFSection is a subclass of ImageSegment, so can use interchangeably - image.segments = e.segments if args.use_segments else e.sections - if args.pad_to_size: - image.pad_to_size = flash_size_bytes(args.pad_to_size) - image.flash_size_freq = image.ROM_LOADER.parse_flash_size_arg(args.flash_size) - image.flash_size_freq += image.ROM_LOADER.parse_flash_freq_arg(args.flash_freq) - - if args.elf_sha256_offset: - image.elf_sha256 = e.sha256() - image.elf_sha256_offset = args.elf_sha256_offset - - if args.ram_only_header: - print( - "Image has only RAM segments visible. " - "ROM segments are hidden and SHA256 digest is not appended." + esp.check_spi_connection(spi_connection) + # Encode the pin numbers as a 32-bit integer with packed 6-bit values, + # the same way the ESP ROM takes them + spi_config, value = _define_spi_conn(spi_connection) + log.print(f"Configuring SPI flash mode ({spi_config})...") + esp.flash_spi_attach(value) + elif not esp.IS_STUB: + if esp.CHIP_NAME != "ESP32" or esp.secure_download_mode: + log.print("Enabling default SPI flash mode...") + # ROM loader doesn't enable flash unless we explicitly do it + esp.flash_spi_attach(0) + else: + # ROM doesn't attach in-package flash chips + spi_chip_pads = esp.get_chip_spi_pads() + spi_config_txt, value = _define_spi_conn(spi_chip_pads) + if spi_chip_pads != (0, 0, 0, 0, 0): + log.print( + "Attaching flash from eFuses' SPI pads configuration " + f"({spi_config_txt})..." + ) + else: + log.print("Enabling default SPI flash mode...") + esp.flash_spi_attach(value) + + def is_xmc_chip_strict(): + # Read ID without cache, because it should be different after the XMC startup + vendor_id, device_id, _ = _get_flash_info(esp, False) + if vendor_id != XMC_VENDOR_ID: + return False + + mfid = (device_id >> 8) & 0xFF + cpid = device_id & 0xFF + + matched = False + if mfid == 0x40: + if cpid >= 0x13 and cpid <= 0x20: + matched = True + elif mfid == 0x41: + if cpid >= 0x17 and cpid <= 0x20: + matched = True + elif mfid == 0x50: + if cpid >= 0x15 and cpid <= 0x16: + matched = True + return matched + + def flash_xmc_startup(): + # If the RDID value is a valid XMC one, may skip the flow + fast_check = True + if fast_check and is_xmc_chip_strict(): + return # Successful XMC flash chip boot-up detected by RDID, skipping. + + sfdp_mfid_addr = 0x10 + mf_id = esp.read_spiflash_sfdp(sfdp_mfid_addr, 8) + if mf_id != XMC_VENDOR_ID: # Non-XMC chip detected by SFDP Read, skipping. + return + + log.warning( + "XMC flash chip boot-up failure detected! Running XMC25QHxxC startup flow." ) - image.sort_segments() - - before = len(image.segments) - image.merge_adjacent_segments() - if len(image.segments) != before: - delta = before - len(image.segments) - print("Merged %d ELF section%s" % (delta, "s" if delta > 1 else "")) + esp.run_spiflash_command(0xB9) # Enter DPD + esp.run_spiflash_command(0x79) # Enter UDPD + esp.run_spiflash_command(0xFF) # Exit UDPD + time.sleep(0.002) # Delay tXUDPD + esp.run_spiflash_command(0xAB) # Release Power-Down + time.sleep(0.00002) + # Check for success + if not is_xmc_chip_strict(): + log.warning("XMC flash boot-up fix failed.") + log.print("XMC flash chip boot-up fix successful!") + + # Check if XMC SPI flash chip booted-up successfully, fix if not + if not esp.secure_download_mode: + try: + flash_xmc_startup() + except FatalError as e: + esp.trace(f"Unable to perform XMC flash chip startup sequence ({e}).") - image.verify() + # Check flash chip connection + if not esp.secure_download_mode: + try: + flash_id = esp.flash_id() + if flash_id in (0xFFFFFF, 0x000000, 0xFFFF3F): + log.warning( + "Failed to communicate with the flash chip, " + "read/write operations will fail. " + "Try checking the chip connections or removing " + "any other hardware connected to IOs." + ) + if spi_connection is not None: + log.note( + "Some GPIO pins might be used by other peripherals, try using " + "another combination of pins for SPI flash connection." + ) - if args.output is None: - args.output = image.default_output_name(args.input) - image.save(args.output) + except FatalError as e: + raise FatalError(f"Unable to verify flash chip connection ({e}).") - print("Successfully created {} image.".format(args.chip)) +def _set_flash_parameters(esp, flash_size="keep"): + """ + Configure the ESP device's flash memory parameters based on the selected flash size. + + Must be called after attach_flash() and before any flash read/write operations. + It supports three modes of operation based on the flash_size argument: + - "detect": Automatically detects the flash size + (with a fallback to 4MB if detection fails) + - "keep": Leaves the flash parameters unchanged in the image header, + but configures the SPI flash chip with its detected size (if possible) + - Explicit size (e.g., "4MB", "8MB", etc.): Directly uses the specified flash size + + Args: + esp (ESPLoader): Initiated esp object connected to a real device. + flash_size (str, optional): The flash size setting to use. Can be "detect", + "keep", or an explicit flash size value + (default: "keep"). + + Returns: + str | Any: Returns "keep" if flash_size was "keep", or the flash size value + used for configuration. In "detect" mode, this is the auto-detected + flash size (or "4MB" as a fallback). + """ -def read_mac(esp, args): - def print_mac(label, mac): - print("%s: %s" % (label, ":".join(map(lambda x: "%02x" % x, mac)))) + log.print("Configuring flash size...") + keep = flash_size == "keep" - eui64 = esp.read_mac("EUI64") - if eui64: - print_mac("MAC", eui64) - print_mac("BASE MAC", esp.read_mac("BASE_MAC")) - print_mac("MAC_EXT", esp.read_mac("MAC_EXT")) - else: - print_mac("MAC", esp.read_mac("BASE_MAC")) + # Determine flash size + if flash_size == "detect": + flash_size = detect_flash_size(esp) + if flash_size is None: + log.warning("Could not auto-detect flash size, defaulting to 4MB.") + flash_size = "4MB" + else: + log.print(f"Auto-detected flash size: {flash_size}") + elif flash_size == "keep": + # Set flash size will not change in image header, + # but the flash chip should be configured with the real size if possible + flash_size = None if esp.secure_download_mode else detect_flash_size(esp) + if not esp.IS_STUB: + log.note("In case of failure, please set a specific flash size.") + + # Set flash parameters + if flash_size is not None: # Not "keep" in secure download mode + esp.flash_set_parameters(flash_size_bytes(flash_size)) + # Check if stub/ROM supports chosen flash size + if ( + not (esp.IS_STUB and esp.CHIP_NAME in ["ESP32-S3", "ESP32-P4"]) + and flash_size_bytes(flash_size) > 16 * 1024 * 1024 + ): + log.note( + "Flash sizes larger than than 16MB are not fully supported. " + "Change the flash size argument in case of a failure." + ) + return "keep" if keep else flash_size -def chip_id(esp, args): - try: - chipid = esp.chip_id() - print("Chip ID: 0x%08x" % chipid) - except NotSupportedError: - print("Warning: %s has no Chip ID. Reading MAC instead." % esp.CHIP_NAME) - read_mac(esp, args) +def erase_flash(esp: ESPLoader, force: bool = False) -> None: + """ + Erase the SPI flash memory of the ESP device. -def erase_flash(esp, args): - if not args.force and esp.CHIP_NAME != "ESP8266" and not esp.secure_download_mode: + Args: + esp: Initiated esp object connected to a real device. + force: Bypass the security checks for flash encryption and secure boot. + """ + if not force and esp.CHIP_NAME != "ESP8266" and not esp.secure_download_mode: if esp.get_flash_encryption_enabled() or esp.get_secure_boot_enabled(): raise FatalError( "Active security features detected, " "erasing flash is disabled as a safety measure. " - "Use --force to override, " + "Use the force argument to override, " "please use with caution, otherwise it may brick your device!" ) - print("Erasing flash (this may take a while)...") + log.stage() + log.print("Erasing flash memory (this may take a while)...") + if esp.CHIP_NAME != "ESP8266" and not esp.IS_STUB: + log.note( + "You can use the erase-region command in ROM bootloader " + "mode to erase a specific region." + ) t = time.time() esp.erase_flash() - print("Chip erase completed successfully in %.1fs" % (time.time() - t)) + log.stage(finish=True) + log.print(f"Flash memory erased successfully in {time.time() - t:.1f} seconds.") + +def erase_region(esp: ESPLoader, address: int, size: int, force: bool = False) -> None: + """ + Erase a specific region of the SPI flash memory of the ESP device. -def erase_region(esp, args): - if not args.force and esp.CHIP_NAME != "ESP8266" and not esp.secure_download_mode: + Args: + esp: Initiated esp object connected to a real device. + address: The starting address from which to begin erasing. + size: The total number of bytes to erase. + force: Bypass the security checks for flash encryption and secure boot. + """ + if address % ESPLoader.FLASH_SECTOR_SIZE != 0: + raise FatalError( + f"Offset to erase from must be a multiple of {ESPLoader.FLASH_SECTOR_SIZE}." + ) + if size % ESPLoader.FLASH_SECTOR_SIZE != 0: + raise FatalError( + "Size of data to erase must be a multiple of " + f"{ESPLoader.FLASH_SECTOR_SIZE}." + ) + if not force and esp.CHIP_NAME != "ESP8266" and not esp.secure_download_mode: if esp.get_flash_encryption_enabled() or esp.get_secure_boot_enabled(): raise FatalError( "Active security features detected, " "erasing flash is disabled as a safety measure. " - "Use --force to override, " + "Use the force argument to override, " "please use with caution, otherwise it may brick your device!" ) - print("Erasing region (may be slow depending on size)...") + log.stage() + log.print( + "Erasing flash memory region (this may take a while depending on size)..." + ) t = time.time() - esp.erase_region(args.address, args.size) - print("Erase completed successfully in %.1f seconds." % (time.time() - t)) + if esp.CHIP_NAME != "ESP8266" and not esp.IS_STUB: + # flash_begin triggers a flash erase, enabling erasing in ROM and SDM + esp.flash_begin(size, address, logging=False) + else: + esp.erase_region(address, size) + log.stage(finish=True) + log.print( + f"Flash memory region erased successfully in {time.time() - t:.1f} seconds." + ) + +def run(esp: ESPLoader) -> None: + """ + Execute the firmware loaded on the ESP device. -def run(esp, args): + Args: + esp: Initiated esp object connected to a real device. + """ esp.run() -def detect_flash_id(esp): - flash_id = esp.flash_id() - print("Manufacturer: %02x" % (flash_id & 0xFF)) - flid_lowbyte = (flash_id >> 16) & 0xFF - print("Device: %02x%02x" % ((flash_id >> 8) & 0xFF, flid_lowbyte)) - print( - "Detected flash size: %s" % (DETECTED_FLASH_SIZES.get(flid_lowbyte, "Unknown")) - ) +def print_flash_id(esp: ESPLoader) -> None: + """ + Read and display the SPI flash memory chip ID and related information. + + Args: + esp: Initiated esp object connected to a real device. + """ + manufacturer_id, device_id, flash_size = _get_flash_info(esp) + log.print(f"Manufacturer: {manufacturer_id:02x}") + log.print(f"Device: {device_id:04x}") + log.print(f"Detected flash size: {flash_size or 'Unknown'}") -def flash_id(esp, args): - detect_flash_id(esp) +def flash_id(esp: ESPLoader) -> None: + """ + Read and display the SPI flash memory chip identification and configuration details, + such as the manufacturer ID, device ID, detected flash size, type, and voltage. + + Args: + esp: Initiated esp object connected to a real device. + """ + title = "Flash Memory Information:" + log.print(title) + log.print("=" * len(title)) + print_flash_id(esp) flash_type = esp.flash_type() flash_type_dict = {0: "quad (4 data lines)", 1: "octal (8 data lines)"} flash_type_str = flash_type_dict.get(flash_type) if flash_type_str: - print(f"Flash type set in eFuse: {flash_type_str}") - esp.get_flash_voltage() + log.print(f"Flash type set in eFuse: {flash_type_str}") + try: + esp.get_flash_voltage() + except NotSupportedError: + pass # Ignore if not supported -def read_flash_sfdp(esp, args): - detect_flash_id(esp) +def read_flash_sfdp(esp: ESPLoader, address: int, bytes: int = 1) -> None: + """ + Read and display the Serial Flash Discoverable Parameters (SFDP) + from the flash memory. - sfdp = esp.read_spiflash_sfdp(args.addr, args.bytes * 8) - print(f"SFDP[{args.addr}..{args.addr+args.bytes-1}]: ", end="") - for i in range(args.bytes): - print(f"{sfdp&0xff:02X} ", end="") + Args: + esp: Initiated esp object connected to a real device. + address: Starting address in the SFDP region to read from. + bytes: Number of bytes to read (1-4). + """ + if not (1 <= bytes <= 4): + raise FatalError("Invalid number of bytes to read from SFDP (1-4).") + print_flash_id(esp) + sfdp = esp.read_spiflash_sfdp(address, bytes * 8) + log.print(f"Flash memory SFDP[{address}..{address + bytes - 1}]: ", end="") + for _ in range(bytes): + log.print(f"{sfdp & 0xFF:#04x} ", end="") sfdp = sfdp >> 8 - print() + log.print() -def read_flash(esp, args): - if args.no_progress: +def read_flash( + esp: ESPLoader, + address: int, + size: int, + output: str | None = None, + flash_size: str = "keep", + no_progress: bool = False, +) -> bytes | None: + """ + Read a specified region of SPI flash memory of an ESP device + and optionally save it to a file. + + Args: + esp: Initiated esp object connected to a real device. + address: The starting address in flash memory to read from. + size: The number of bytes to read. + output: The name of the file to save the read data. + If None, the function returns the data. + flash_size: Flash size setting, needs to be set only when + the stub flasher is disabled. + Options: ``"detect"``: auto-detect flash size with fallback to 4MB, + ``"keep"``: auto-detect but skip setting parameters in SDM, + Explicit size: use the specified flash size. + no_progress: Disable printing progress. + + Returns: + The read flash data as bytes if output is None; otherwise, + returns None after writing to file. + """ + _set_flash_parameters(esp, flash_size) + if no_progress: flash_progress = None else: - def flash_progress(progress, length): - msg = "%d (%d %%)" % (progress, progress * 100.0 / length) - padding = "\b" * len(msg) - if progress == length: - padding = "\n" - sys.stdout.write(msg + padding) - sys.stdout.flush() + def flash_progress(progress, length, offset): + log.progress_bar( + cur_iter=progress, + total_iters=length, + prefix=f"Reading from {offset + progress:#010x} ", + suffix=f" {progress}/{length} bytes...", + ) + log.stage() t = time.time() - data = esp.read_flash(args.address, args.size, flash_progress) + data = esp.read_flash(address, size, flash_progress) t = time.time() - t speed_msg = " ({:.1f} kbit/s)".format(len(data) / t * 8 / 1000) if t > 0.0 else "" - print_overwrite( - "Read {:d} bytes at {:#010x} in {:.1f} seconds{}...".format( - len(data), args.address, t, speed_msg - ), - last_line=True, + dest_msg = f" to '{output}'" if output else "" + log.stage(finish=True) + log.print( + f"Read {len(data)} bytes from {address:#010x} in {t:.1f} seconds" + f"{speed_msg}{dest_msg}." ) - with open(args.filename, "wb") as f: - f.write(data) + if output: + with open(output, "wb") as f: + f.write(data) + return None + else: + return data -def verify_flash(esp, args): - differences = False +def verify_flash( + esp: ESPLoader, + addr_data: list[tuple[int, ImageSource]], + flash_freq: str = "keep", + flash_mode: str = "keep", + flash_size: str = "keep", + diff: bool = False, +) -> None: + """ + Verify the contents of the SPI flash memory against the provided binary files + or byte data. + + Args: + esp: Initiated esp object connected to a real device. + addr_data: List of (address, data) tuples specifying what + parts of flash memory to verify. The data can be + a file path (str), bytes, or a file-like object. + flash_freq: Flash frequency setting (``"keep"`` to retain current). + flash_mode: Flash mode setting (``"keep"`` to retain current). + flash_size: Flash size setting (``"keep"`` to retain current). + diff: If True, perform a byte-by-byte comparison on failure. + """ + flash_size = _set_flash_parameters(esp, flash_size) # Set flash size parameters + mismatch = False - for address, argfile in args.addr_filename: - image = pad_to(argfile.read(), 4) - argfile.seek(0) # rewind in case we need it again + for address, data in addr_data: + data, source = get_bytes(data) + image = pad_to(data, 4) - image = _update_image_flash_params(esp, address, args, image) + image = _update_image_flash_params( + esp, address, flash_freq, flash_mode, flash_size, image + ) image_size = len(image) - print( - "Verifying 0x%x (%d) bytes @ 0x%08x in flash against %s..." - % (image_size, image_size, address, argfile.name) + source = "input bytes" if source is None else f"'{source}'" + log.print( + f"Verifying {image_size:#x} ({image_size}) bytes " + f"at {address:#010x} in flash against {source}..." ) # Try digest first, only read if there are differences. digest = esp.flash_md5sum(address, image_size) expected_digest = hashlib.md5(image).hexdigest() if digest == expected_digest: - print("-- verify OK (digest matched)") + log.print("Verification successful (digest matched).") continue else: - differences = True - if getattr(args, "diff", "no") != "yes": - print("-- verify FAILED (digest mismatch)") + mismatch = True + if not diff: + log.print("Verification failed (digest mismatch).") continue flash = esp.read_flash(address, image_size) assert flash != image - diff = [i for i in range(image_size) if flash[i] != image[i]] - print( - "-- verify FAILED: %d differences, first @ 0x%08x" - % (len(diff), address + diff[0]) + differences = [i for i in range(image_size) if flash[i] != image[i]] + log.print( + f"Verification failed: {len(differences)} differences, " + f"first at {address + differences[0]:#010x}:" ) - for d in diff: + for d in differences: flash_byte = flash[d] image_byte = image[d] - print(" %08x %02x %02x" % (address + d, flash_byte, image_byte)) - if differences: - raise FatalError("Verify failed.") - - -def read_flash_status(esp, args): - print("Status value: 0x%04x" % esp.read_status(args.bytes)) - - -def write_flash_status(esp, args): - fmt = "0x%%0%dx" % (args.bytes * 2) - args.value = args.value & ((1 << (args.bytes * 8)) - 1) - print(("Initial flash status: " + fmt) % esp.read_status(args.bytes)) - print(("Setting flash status: " + fmt) % args.value) - esp.write_status(args.value, args.bytes, args.non_volatile) - print(("After flash status: " + fmt) % esp.read_status(args.bytes)) - - -# The following mapping was taken from the ROM code -# This mapping is same across all targets in the ROM -SECURITY_INFO_FLAG_MAP = { - "SECURE_BOOT_EN": (1 << 0), - "SECURE_BOOT_AGGRESSIVE_REVOKE": (1 << 1), - "SECURE_DOWNLOAD_ENABLE": (1 << 2), - "SECURE_BOOT_KEY_REVOKE0": (1 << 3), - "SECURE_BOOT_KEY_REVOKE1": (1 << 4), - "SECURE_BOOT_KEY_REVOKE2": (1 << 5), - "SOFT_DIS_JTAG": (1 << 6), - "HARD_DIS_JTAG": (1 << 7), - "DIS_USB": (1 << 8), - "DIS_DOWNLOAD_DCACHE": (1 << 9), - "DIS_DOWNLOAD_ICACHE": (1 << 10), -} + log.print(f" {address + d:#010x} {flash_byte:02x} {image_byte:02x}") + if mismatch: + raise FatalError("Verification failed.") -# Get the status of respective security flag -def get_security_flag_status(flag_name, flags_value): - try: - return (flags_value & SECURITY_INFO_FLAG_MAP[flag_name]) != 0 - except KeyError: - raise ValueError(f"Invalid flag name: {flag_name}") +def read_flash_status(esp: ESPLoader, bytes: int = 2) -> None: + """ + Read and print the status register value of the SPI flash memory. + + Args: + esp: Initiated esp object connected to a real device. + bytes: Number of bytes to read. + """ + log.print(f"Flash memory status: {esp.read_status(bytes):#06x}") -def get_security_info(esp, args): +def write_flash_status( + esp: ESPLoader, value: int, bytes: int = 2, non_volatile: bool = False +) -> None: + """ + Write a new value to the SPI flash memory status register and verify the update. + + Args: + esp: Initiated esp object connected to a real device. + value: The new status register value to write. + bytes: Number of bytes to write. + non_volatile: If True, allows non-volatile status register bits + to be written. + """ + fmt = f"0x%0{bytes * 2}x" + value = value & ((1 << (bytes * 8)) - 1) + log.print(f"Initial flash memory status: {fmt % esp.read_status(bytes)}") + log.print(f"Setting flash memory status: {fmt % value}") + esp.write_status(value, bytes, non_volatile) + log.print(f"After flash memory status: {fmt % esp.read_status(bytes)}") + + +def get_security_info(esp: ESPLoader) -> None: + """ + Read and display security-related information about the ESP device. + + Args: + esp: Initiated esp object connected to a real device. + """ si = esp.get_security_info() - print() + parsed_flags = si["parsed_flags"] + title = "Security Information:" - print(title) - print("=" * len(title)) - print("Flags: {:#010x} ({})".format(si["flags"], bin(si["flags"]))) + log.print(title) + log.print("=" * len(title)) + log.print("Flags: {:#010x} ({})".format(si["flags"], bin(si["flags"]))) if esp.KEY_PURPOSES: - print(f"Key Purposes: {si['key_purposes']}") + log.print(f"Key Purposes: {si['key_purposes']}") desc = "\n ".join( [ f"BLOCK_KEY{key_num} - {esp.KEY_PURPOSES.get(purpose, 'UNKNOWN')}" @@ -1328,17 +1511,15 @@ def get_security_info(esp, args): if key_num <= esp.EFUSE_MAX_KEY ] ) - print(f" {desc}") + log.print(f" {desc}") if si["chip_id"] is not None and si["api_version"] is not None: - print("Chip ID: {}".format(si["chip_id"])) - print("API Version: {}".format(si["api_version"])) + log.print("Chip ID: {}".format(si["chip_id"])) + log.print("API Version: {}".format(si["api_version"])) - flags = si["flags"] - - if get_security_flag_status("SECURE_BOOT_EN", flags): - print("Secure Boot: Enabled") - if get_security_flag_status("SECURE_BOOT_AGGRESSIVE_REVOKE", flags): - print("Secure Boot Aggressive key revocation: Enabled") + if parsed_flags["SECURE_BOOT_EN"]: + log.print("Secure Boot: Enabled") + if parsed_flags["SECURE_BOOT_AGGRESSIVE_REVOKE"]: + log.print("Secure Boot Aggressive key revocation: Enabled") revoked_keys = [] for i, key in enumerate( @@ -1348,127 +1529,817 @@ def get_security_info(esp, args): "SECURE_BOOT_KEY_REVOKE2", ] ): - if get_security_flag_status(key, flags): + if parsed_flags[key]: revoked_keys.append(i) if len(revoked_keys) > 0: - print("Secure Boot Key Revocation Status:\n") + log.print("Secure Boot Key Revocation Status:\n") for i in revoked_keys: - print(f"\tSecure Boot Key{i} is Revoked\n") + log.print(f"\tSecure Boot Key{i} is Revoked\n") else: - print("Secure Boot: Disabled") + log.print("Secure Boot: Disabled") flash_crypt_cnt = bin(si["flash_crypt_cnt"]) if (flash_crypt_cnt.count("1") % 2) != 0: - print("Flash Encryption: Enabled") + log.print("Flash Encryption: Enabled") else: - print("Flash Encryption: Disabled") + log.print("Flash Encryption: Disabled") CRYPT_CNT_STRING = "SPI Boot Crypt Count (SPI_BOOT_CRYPT_CNT)" if esp.CHIP_NAME == "esp32": CRYPT_CNT_STRING = "Flash Crypt Count (FLASH_CRYPT_CNT)" - print(f"{CRYPT_CNT_STRING}: {si['flash_crypt_cnt']:#x}") + log.print(f"{CRYPT_CNT_STRING}: {si['flash_crypt_cnt']:#x}") - if get_security_flag_status("DIS_DOWNLOAD_DCACHE", flags): - print("Dcache in UART download mode: Disabled") + if parsed_flags["DIS_DOWNLOAD_DCACHE"]: + log.print("Dcache in UART download mode: Disabled") - if get_security_flag_status("DIS_DOWNLOAD_ICACHE", flags): - print("Icache in UART download mode: Disabled") + if parsed_flags["DIS_DOWNLOAD_ICACHE"]: + log.print("Icache in UART download mode: Disabled") - hard_dis_jtag = get_security_flag_status("HARD_DIS_JTAG", flags) - soft_dis_jtag = get_security_flag_status("SOFT_DIS_JTAG", flags) + hard_dis_jtag = parsed_flags["HARD_DIS_JTAG"] + soft_dis_jtag = parsed_flags["SOFT_DIS_JTAG"] if hard_dis_jtag: - print("JTAG: Permanently Disabled") + log.print("JTAG: Permanently Disabled") elif soft_dis_jtag: - print("JTAG: Software Access Disabled") - if get_security_flag_status("DIS_USB", flags): - print("USB Access: Disabled") + log.print("JTAG: Software Access Disabled") + if parsed_flags["DIS_USB"]: + log.print("USB Access: Disabled") + + +def reset_chip(esp: ESPLoader, reset_mode: str = "hard-reset") -> None: + """ + Reset the ESP device. + + Args: + esp: Initiated esp object connected to a real device. + reset_mode: Reset mode to use ( + ``"hard-reset"``: perform a hard reset using the RTS control line, + ``"soft-reset"``: perform a soft reset, + ``"no-reset"``: stay in bootloader, + ``"no-reset-stub"``: stay in flasher stub, + ``"watchdog-reset"``: perform a hard reset utilizing a software watchdog. + ) + + """ + if reset_mode == "hard-reset": + esp.hard_reset() + elif reset_mode == "soft-reset": + log.print("Soft resetting...") + # flash_finish will trigger a soft reset + esp.soft_reset(False) + elif reset_mode == "no-reset-stub": + log.print("Staying in flasher stub.") + elif reset_mode == "watchdog-reset": + if esp.secure_download_mode: + log.warning( + "Watchdog hard reset is not supported in Secure Download Mode, " + "attempting classic hard reset instead." + ) + esp.hard_reset() + else: + esp.watchdog_reset() + elif reset_mode == "no-reset": + log.print("Staying in bootloader.") + if esp.IS_STUB: + esp.soft_reset(True) # Exit the stub flasher back to ROM loader + else: + raise FatalError(f"Invalid reset mode: {reset_mode}") + + +def run_stub(esp: ESPLoader) -> ESPLoader: + """ + Load and execute the stub loader on the ESP device. If stub loading + is not supported or is explicitly disabled, warnings are logged. + + Args: + esp: Initiated esp object connected to a real device. + + Returns: + The esp instance, either as a stub child class in a state + where the stub has been executed, or in its original state + if the stub loader is disabled or unsupported. + """ + if esp.secure_download_mode: + log.warning( + "Stub flasher is not supported in Secure Download Mode, " + "it has been disabled. Set --no-stub to suppress this warning." + ) + elif not esp.IS_STUB and esp.stub_is_disabled: + log.warning( + "Stub flasher has been disabled for compatibility, " + "set --no-stub to suppress this warning." + ) + elif esp.CHIP_NAME in [ + "ESP32-H21", + "ESP32-H4", + ]: # TODO: [ESP32H21] IDF-11509 [ESP32H4] IDF-12271 + log.warning( + f"Stub flasher is not yet supported on {esp.CHIP_NAME}, " + "it has been disabled. Set --no-stub to suppress this warning." + ) + else: + try: + return esp.run_stub() + except Exception: + # The CH9102 bridge (PID: 0x55D4) can have issues on MacOS + if sys.platform == "darwin" and esp._get_pid() == 0x55D4: + log.print() + log.note( + "If issues persist, " + "try installing the WCH USB-to-Serial MacOS driver." + ) + raise + return esp + + +# Commands that don't require an ESP object (image manipulation, etc.) +###################################################################### + + +def _parse_app_info(app_info_segment): + """ + Check if correct magic word is present in the app_info and parse the app_info struct + """ + app_info = app_info_segment[:256] + # More info about the app_info struct can be found at: + # https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-reference/system/app_image_format.html#application-description + APP_DESC_STRUCT_FMT = " None: + """ + Display detailed information about an ESP firmware image. + + Args: + input: Path to the firmware image file, opened file-like object, + or the image data as bytes. If a list of tuples is provided, + each tuple contains an offset and an image data as bytes. Used for + merged binary images. + chip: Target ESP device type (e.g., ``"esp32"``). If None, the chip + type will be automatically detected from the image header. + """ + if isinstance(input, list): + log.print("Merged binary image detected. Processing each file individually.") + for i, file in enumerate(input): + data, _ = get_bytes(file[1]) + + offset_str = hex(file[0]) if file[0] is not None else "unknown" + line = ( + f"Processing file {i + 1}/{len(input)}, " + f"offset: {offset_str}, size: {len(data)} bytes" + ) + log.print() + log.print("=" * len(line)) + log.print(line) + log.print("=" * len(line)) + + try: + detected_chip = _parse_image_info_header(data, chip) + except Exception as e: + log.error(f"Error processing file {i + 1}/{len(input)}: {e}") + log.error("Probably not a valid firmware image (e.g. partition table).") + continue + + if ( + i == 0 and chip is None + ): # We don't need to print the image type for each file + log.print(f"Detected image type: {detected_chip.upper()}") + chip = detected_chip + _print_image_info(detected_chip, data) + + else: + data, _ = get_bytes(input) + detected_chip = _parse_image_info_header(data, chip) + + log.print(f"Image size: {len(data)} bytes") + if chip is None: + log.print(f"Detected image type: {detected_chip.upper()}") + + _print_image_info(detected_chip, data) + +def _parse_image_info_header(data: bytes, chip: str | None = None) -> str: + """Parse the image info header and return the chip type.""" + stream = io.BytesIO(data) + common_header = stream.read(8) + if chip is None: + extended_header = stream.read(16) + stream.seek(0) -def merge_bin(args): + # Check magic number try: - chip_class = CHIP_DEFS[args.chip] + magic = common_header[0] + except IndexError: + raise FatalError("Image is empty.") + if magic not in [ + ESPLoader.ESP_IMAGE_MAGIC, + ESP8266V2FirmwareImage.IMAGE_V2_MAGIC, + ]: + raise FatalError( + f"This is not a valid image (invalid magic number: {magic:#x})." + ) + + if chip is None: + try: + # append_digest, either 0 or 1 + if extended_header[-1] not in [0, 1]: + raise FatalError("Append digest field not 0 or 1.") + + chip_id = int.from_bytes(extended_header[4:5], "little") + for rom in ROM_LIST: + if chip_id == rom.IMAGE_CHIP_ID: + chip = rom.CHIP_NAME + break + else: + raise FatalError(f"Unknown image chip ID ({chip_id}).") + except FatalError: + chip = "esp8266" + + return chip + + +def _print_image_info(chip: str, data: bytes) -> None: + image = LoadFirmwareImage(chip, data) + + log.print() + title = f"{chip.upper()} Image Header" + log.print(title) + log.print("=" * len(title)) + log.print(f"Image version: {image.version}") + log.print( + f"Entry point: {image.entrypoint:#8x}" + if image.entrypoint != 0 + else "Entry point not set" + ) + + log.print(f"Segments: {len(image.segments)}") + + # Flash size + flash_s_bits = image.flash_size_freq & 0xF0 # high four bits + flash_s = get_key_from_value(image.ROM_LOADER.FLASH_SIZES, flash_s_bits) + if flash_s is not None: + log.print(f"Flash size: {flash_s}") + else: + log.warning(f"Invalid flash size ({flash_s_bits:#02x})") + + # Flash frequency + flash_fr_bits = image.flash_size_freq & 0x0F # low four bits + flash_fr = get_key_from_value(image.ROM_LOADER.FLASH_FREQUENCY, flash_fr_bits) + if flash_fr is not None: + log.print(f"Flash freq: {flash_fr}") + else: + log.warning(f"Invalid flash frequency ({flash_fr_bits:#02x})") + + # Flash mode + flash_mode = get_key_from_value(FLASH_MODES, image.flash_mode) + if flash_mode is not None: + log.print(f"Flash mode: {flash_mode.upper()}") + else: + log.warning(f"Invalid flash mode ({image.flash_mode})") + + # Extended header (ESP32 and later only) + if chip != "esp8266": + log.print() + title = f"{chip.upper()} Extended Image Header" + log.print(title) + log.print("=" * len(title)) + log.print( + f"WP pin: {image.wp_pin:#02x}", + *["(disabled)"] if image.wp_pin == image.WP_PIN_DISABLED else [], + ) + log.print( + "Flash pins drive settings: " + "clk_drv: {:#02x}, q_drv: {:#02x}, d_drv: {:#02x}, " + "cs0_drv: {:#02x}, hd_drv: {:#02x}, wp_drv: {:#02x}".format( + image.clk_drv, + image.q_drv, + image.d_drv, + image.cs_drv, + image.hd_drv, + image.wp_drv, + ) + ) + try: + chip_class = next( + chip + for chip in CHIP_DEFS.values() + if getattr(chip, "IMAGE_CHIP_ID", None) == image.chip_id + ) + log.print(f"Chip ID: {image.chip_id} ({chip_class.CHIP_NAME})") + except StopIteration: + log.print(f"Chip ID: {image.chip_id} (Unknown ID)") + log.print( + "Minimal chip revision: " + f"v{image.min_rev_full // 100}.{image.min_rev_full % 100}, " + f"(legacy min_rev = {image.min_rev})" + ) + log.print( + "Maximal chip revision: " + f"v{image.max_rev_full // 100}.{image.max_rev_full % 100}" + ) + log.print() + + # Segments overview + title = "Segments Information" + log.print(title) + log.print("=" * len(title)) + headers_str = "{:>7} {:>7} {:>10} {:>10} {:10}" + log.print( + headers_str.format( + "Segment", "Length", "Load addr", "File offs", "Memory types" + ) + ) + log.print(f"{'-' * 7} {'-' * 7} {'-' * 10} {'-' * 10} {'-' * 12}") + format_str = "{:7} {:#07x} {:#010x} {:#010x} {}" + app_desc_seg = None + bootloader_desc_seg = None + for idx, seg in enumerate(image.segments): + segs = seg.get_memory_type(image) + seg_name = ", ".join(segs) + # The DROM segment starts with the esp_app_desc_t struct + if "DROM" in segs and app_desc_seg is None: + app_desc_seg = seg.data + elif "DRAM" in segs: + # The DRAM segment starts with the esp_bootloader_desc_t struct + if len(seg.data) >= 80: + bootloader_desc_seg = seg.data + log.print( + format_str.format(idx, len(seg.data), seg.addr, seg.file_offs, seg_name) + ) + log.print() + + # Footer + title = f"{chip.upper()} Image Footer" + log.print(title) + log.print("=" * len(title)) + calc_checksum = image.calculate_checksum() + log.print( + "Checksum: {:#04x} ({})".format( + image.checksum, + ( + "valid" + if image.checksum == calc_checksum + else f"invalid - calculated {calc_checksum:#04x}" + ), + ) + ) + try: + digest_msg = "Not appended" + if image.append_digest: + is_valid = image.stored_digest == image.calc_digest + digest_msg = "{} ({})".format( + hexify(image.calc_digest, uppercase=False), + "valid" if is_valid else "invalid", + ) + log.print(f"Validation hash: {digest_msg}") + except AttributeError: + pass # ESP8266 image has no append_digest field + + if app_desc_seg: + app_desc = _parse_app_info(app_desc_seg) + if app_desc: + log.print() + title = "Application Information" + log.print(title) + log.print("=" * len(title)) + log.print(f"Project name: {app_desc['project_name']}") + log.print(f"App version: {app_desc['version']}") + log.print(f"Compile time: {app_desc['date']} {app_desc['time']}") + log.print(f"ELF file SHA256: {app_desc['app_elf_sha256']}") + log.print(f"ESP-IDF: {app_desc['idf_ver']}") + log.print( + f"Minimal eFuse block revision: {app_desc['min_efuse_blk_rev_full']}" + ) + log.print( + f"Maximal eFuse block revision: {app_desc['max_efuse_blk_rev_full']}" + ) + if app_desc["mmu_page_size"]: + log.print(f"MMU page size: {app_desc['mmu_page_size']}") + log.print(f"Secure version: {app_desc['secure_version']}") + + elif bootloader_desc_seg: + bootloader_desc = _parse_bootloader_info(bootloader_desc_seg) + if bootloader_desc: + log.print() + title = "Bootloader Information" + log.print(title) + log.print("=" * len(title)) + log.print(f"Bootloader version: {bootloader_desc['version']}") + log.print(f"ESP-IDF: {bootloader_desc['idf_ver']}") + log.print(f"Compile time: {bootloader_desc['date_time']}") + + +def merge_bin( + addr_data: list[tuple[int, ImageSource]], + chip: str, + output: str | None = None, + flash_freq: str = "keep", + flash_mode: str = "keep", + flash_size: str = "keep", + format: str = "raw", + **kwargs, +) -> bytes | None: + """ + Merge multiple binary files into a single output file for flashing to an ESP device. + + Take multiple binary files along with their flash addresses and merge them + into a unified binary in either raw, UF2, or Intel HEX format. + Also apply necessary flash parameters and ensure correct alignment for flashing. + + Args: + addr_data: List of (address, data) tuples specifying where + to write each file or data in flash memory. The data can be + a file path (str), bytes, or a file-like object. + chip: Target ESP device type (e.g., ``"esp32"``). + output: Path to the output file where the merged binary will be written. + If None, the merged binary will be returned as bytes. + flash_freq: Flash frequency to set in the image header + (``"keep"`` to retain current). + flash_mode: Flash mode to set in the image header + (``"keep"`` to retain current). + flash_size: Flash size to set in the image header + (``"keep"`` to retain current). + format: Output format (``"raw"``, ``"uf2"``, or ``"hex"``). + + Keyword Args: + target_offset (int): Starting offset for the merged output. + pad_to_size (str | None): If specified, pad the output to a specific flash size. + chunk_size (int | None): Chunk size for UF2 format. + md5_disable (bool): If True, disable MD5 checks in UF2 format. + + Returns: + The merged binary data as bytes if output is None; otherwise, + returns None after writing to file. + """ + + # Set default values of optional arguments + target_offset: int = kwargs.get("target_offset", 0) + pad_to_size: str | None = kwargs.get("pad_to_size", None) + chunk_size: int | None = kwargs.get("chunk_size", None) + md5_disable: bool = kwargs.get("md5_disable", False) + + if format not in ["raw", "uf2", "hex"]: + raise FatalError( + f"Invalid format: '{format}', choose from 'raw', 'uf2', 'hex'." + ) + + if output is None and format in ["uf2", "hex"]: + raise FatalError(f"Output file must be specified with {format.upper()} format.") + + try: + chip_class = CHIP_DEFS[chip] except KeyError: - msg = ( - "Please specify the chip argument" - if args.chip == "auto" - else f"Invalid chip choice: '{args.chip}'" + raise FatalError( + f"Invalid chip choice: '{chip}' (choose from {', '.join(CHIP_LIST)})." ) - msg = f"{msg} (choose from {', '.join(CHIP_LIST)})" - raise FatalError(msg) # sort the files by offset. # The AddrFilenamePairAction has already checked for overlap - input_files = sorted(args.addr_filename, key=lambda x: x[0]) - if not input_files: - raise FatalError("No input files specified") - first_addr = input_files[0][0] - if first_addr < args.target_offset: + addr_data = sorted(addr_data, key=lambda x: x[0]) + if not addr_data: + raise FatalError("No input data.") + first_addr = addr_data[0][0] + if first_addr < target_offset: raise FatalError( - f"Output file target offset is {args.target_offset:#x}. " - f"Input file offset {first_addr:#x} is before this." + f"Output data target offset is {target_offset:#x}. " + f"Input data offset {first_addr:#x} is before this." ) - if args.format == "uf2": + if output is not None and format == "uf2": with UF2Writer( chip_class.UF2_FAMILY_ID, - args.output, - args.chunk_size, - md5_enabled=not args.md5_disable, + output, + chunk_size, + md5_enabled=not md5_disable, ) as writer: - for addr, argfile in input_files: - print(f"Adding {argfile.name} at {addr:#x}") - image = argfile.read() - image = _update_image_flash_params(chip_class, addr, args, image) + for addr, data in addr_data: + image, source = get_bytes(data) + source = "bytes" if source is None else f"'{source}'" + log.print(f"Adding {source} at {addr:#x}...") + image = _update_image_flash_params( + chip_class, addr, flash_freq, flash_mode, flash_size, image + ) writer.add_file(addr, image) - print( - f"Wrote {os.path.getsize(args.output):#x} bytes to file {args.output}, " - f"ready to be flashed with any ESP USB Bridge" + log.print( + f"Wrote {os.path.getsize(output):#x} bytes to file '{output}', " + f"ready to be flashed with any ESP USB Bridge." ) - elif args.format == "raw": - with open(args.output, "wb") as of: + elif format == "raw": + of = io.BytesIO() if output is None else open(output, "wb") + try: def pad_to(flash_offs): # account for output file offset if there is any - of.write(b"\xff" * (flash_offs - args.target_offset - of.tell())) + of.write(b"\xff" * (flash_offs - target_offset - of.tell())) - for addr, argfile in input_files: + for addr, data in addr_data: pad_to(addr) - image = argfile.read() - image = _update_image_flash_params(chip_class, addr, args, image) + image, _ = get_bytes(data) + image = _update_image_flash_params( + chip_class, addr, flash_freq, flash_mode, flash_size, image + ) of.write(image) - if args.fill_flash_size: - pad_to(flash_size_bytes(args.fill_flash_size)) - print( - f"Wrote {of.tell():#x} bytes to file {args.output}, " - f"ready to flash to offset {args.target_offset:#x}" + if pad_to_size: + pad_to(flash_size_bytes(pad_to_size)) + size = of.tell() + finally: + if output is not None: + of.close() + + if output is None and isinstance(of, io.BytesIO): + log.print( + f"Merged {size:#x} bytes, ready to flash to offset {target_offset:#x}." + ) + return of.getvalue() + else: + log.print( + f"Wrote {size:#x} bytes to file '{output}', " + f"ready to flash to offset {target_offset:#x}." ) - elif args.format == "hex": + return None + + elif output is not None and format == "hex": out = IntelHex() - if len(input_files) == 1: - print( - "WARNING: Only one input file specified, output may include " + if len(addr_data) == 1: + log.warning( + "Only one input file specified, output may include " "additional padding if input file was previously merged. " "Please refer to the documentation for more information: " "https://docs.espressif.com/projects/esptool/en/latest/esptool/basic-commands.html#hex-output-format" # noqa E501 ) - for addr, argfile in input_files: + for addr, data in addr_data: ihex = IntelHex() - image = argfile.read() - image = _update_image_flash_params(chip_class, addr, args, image) + image, _ = get_bytes(data) + image = _update_image_flash_params( + chip_class, addr, flash_freq, flash_mode, flash_size, image + ) ihex.frombytes(image, addr) out.merge(ihex) - out.write_hex_file(args.output) - print( - f"Wrote {os.path.getsize(args.output):#x} bytes to file {args.output}, " - f"ready to flash to offset {args.target_offset:#x}" + out.write_hex_file(output) + log.print( + f"Wrote {os.path.getsize(output):#x} bytes to file '{output}', " + f"ready to flash to offset {target_offset:#x}." ) + return None + + +def elf2image( + input: ImageSource, + chip: str, + output: str | None = None, + flash_freq: str | None = None, + flash_mode: str = "qio", + flash_size: str = "1MB", + **kwargs, +) -> bytes | tuple[bytes | None, bytes] | None: + """ + Convert ELF data into a firmware image suitable for flashing onto an ESP device. + + Args: + input: Path to the ELF file to convert, opened file-like object, + or the ELF data as bytes. + chip: Target ESP device type. + output: Path to save the generated firmware image. If "auto", a default + pre-defined path is used. If None, the image is not written to a file, + but returned as bytes. + flash_freq: Flash frequency to set in the image header. + flash_mode: Flash mode to set in the image header. + flash_size: Flash size to set in the image header. + + Keyword Args: + version (int): ESP8266-only, firmware image version. + min_rev (int): Minimum chip revision required in legacy format. + min_rev_full (int): Minimum chip revision required in extended format. + max_rev_full (int): Maximum chip revision allowed in extended format. + secure_pad (bool): ESP32-only, enable secure padding. + secure_pad_v2 (bool): Enable version 2 secure padding. + elf_sha256_offset (int): Offset for storing the ELF file's SHA-256 hash. + append_digest (bool): Whether to append a digest to the firmware image. + use_segments (bool): Use ELF segments instead of sections. + flash_mmu_page_size (str): MMU page size for flash mapping. + pad_to_size (str): Pad the final image to a specific flash size. + ram_only_header (bool): Include only RAM segments and no SHA-256 hash. + + Returns: + The firmware image as bytes if output is None; otherwise, + returns None after writing to file. + When ESP8266 V1 image is generated, returns a tuple of bytes + of IROM data and the rest if output is None; otherwise, + returns None after writing to two files. + """ + # Set default values of optional arguments + version: int = kwargs.get("version", 1) + min_rev: int = kwargs.get("min_rev", 0) + min_rev_full: int = kwargs.get("min_rev_full", 0) + max_rev_full: int = kwargs.get("max_rev_full", 65535) + secure_pad: bool = kwargs.get("secure_pad", False) + secure_pad_v2: bool = kwargs.get("secure_pad_v2", False) + elf_sha256_offset: int | None = kwargs.get("elf_sha256_offset", None) + append_digest: bool = kwargs.get("append_digest", True) + use_segments: bool = kwargs.get("use_segments", False) + flash_mmu_page_size: str | None = kwargs.get("flash_mmu_page_size", None) + pad_to_size: str | None = kwargs.get("pad_to_size", None) + ram_only_header: bool = kwargs.get("ram_only_header", False) + + if chip not in CHIP_LIST: + raise FatalError( + f"Invalid chip choice: '{chip}' (choose from {', '.join(CHIP_LIST)})." + ) -def version(args): + data, source = get_bytes(input) + e = ELFFile(data) + log.print(f"Creating {chip.upper()} image...") + if chip != "esp8266": + bootloader_image = CHIP_DEFS[chip].BOOTLOADER_IMAGE + if bootloader_image is None: + raise FatalError(f"Missing bootloader image definition for {chip}.") + else: + image = bootloader_image() + if chip == "esp32" and secure_pad: + image.secure_pad = "1" + if secure_pad_v2: + image.secure_pad = "2" + image.min_rev = min_rev + image.min_rev_full = min_rev_full + image.max_rev_full = max_rev_full + image.ram_only_header = ram_only_header + if image.ram_only_header: + image.append_digest = False + else: + image.append_digest = append_digest + elif version == "1": # ESP8266 + image = ESP8266ROMFirmwareImage() + elif version == "2": + image = ESP8266V2FirmwareImage() + else: + image = ESP8266V3FirmwareImage() + image.entrypoint = e.entrypoint + image.flash_mode = FLASH_MODES[flash_mode] + + if flash_mmu_page_size: + image.set_mmu_page_size(flash_size_bytes(flash_mmu_page_size)) + else: + appdesc_seg = None + for seg in e.sections: + if ".flash.appdesc" in seg.name: + appdesc_seg = seg + break + # If ELF file contains an app description segment, which is in the flash memory + # (RAM build has it too, but does not have MMU page size), + # and chip has configurable MMU page size. + if ( + appdesc_seg + and image.is_flash_addr(appdesc_seg.addr) + and image.MMU_PAGE_SIZE_CONF + ): + app_desc = _parse_app_info(appdesc_seg.data) + if app_desc: + # MMU page size is set in app description segment since ESP-IDF v5.4 + if app_desc["mmu_page_size"]: + image.set_mmu_page_size(flash_size_bytes(app_desc["mmu_page_size"])) + # Try to set the correct MMU page size based on the app description + # starting address which, without image + extended header (24 bytes) + # and segment header (8 bytes), should be aligned to MMU page size. + else: + for mmu_page_size in reversed(image.MMU_PAGE_SIZE_CONF): + if (appdesc_seg.addr - 24 - 8) % mmu_page_size == 0: + image.set_mmu_page_size(mmu_page_size) + log.print( + "MMU page size not specified, set to " + f"{image.IROM_ALIGN // 1024} KB" + ) + break + else: + log.warning( + "App description segment is not aligned to MMU page size, " + "probably linker script issue or wrong MMU page size. " + "Try to set MMU page size parameter manually." + ) + + # ELFSection is a subclass of ImageSegment, so can use interchangeably + image.segments = e.segments if use_segments else e.sections + if pad_to_size: + image.pad_to_size = flash_size_bytes(pad_to_size) + image.flash_size_freq = image.ROM_LOADER.parse_flash_size_arg(flash_size) + image.flash_size_freq += image.ROM_LOADER.parse_flash_freq_arg(flash_freq) + + if elf_sha256_offset: + image.elf_sha256 = e.sha256() + image.elf_sha256_offset = elf_sha256_offset + else: + # If ELF file contains an app_desc section and it is in flash, + # put the SHA256 digest at correct offset. + # If it is flash build, it should always be 0xB0. + appdesc_segs = [seg for seg in image.segments if ".flash.appdesc" in seg.name] + if appdesc_segs and image.is_flash_addr(appdesc_segs[0].addr): + image.elf_sha256 = e.sha256() + image.elf_sha256_offset = 0xB0 + + if ram_only_header: + log.print( + "Image has only RAM segments visible. " + "ROM segments are hidden and SHA256 digest is not appended." + ) + image.sort_segments() + + before = len(image.segments) + image.merge_adjacent_segments() + if len(image.segments) != before: + delta = before - len(image.segments) + log.print(f"Merged {delta} ELF section{'s' if delta > 1 else ''}.") + + image.verify() + log.print(f"Successfully created {chip.upper()} image.") + + if output == "auto": + source = f"{chip}_image" if source is None else source + output = image.default_output_name(source) + return cast(bytes | tuple[bytes | None, bytes] | None, image.save(output)) + + +def version() -> None: + """ + Print the current esptool version. + """ from . import __version__ - print(__version__) + log.print(__version__) diff --git a/tools/esptool_py/esptool/config.py b/tools/esptool_py/esptool/config.py index ebbe3b8eed..ebb59389aa 100644 --- a/tools/esptool_py/esptool/config.py +++ b/tools/esptool_py/esptool/config.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2014-2023 Espressif Systems (Shanghai) CO LTD, +# SPDX-FileCopyrightText: 2014-2025 Espressif Systems (Shanghai) CO LTD, # other contributors as noted. # # SPDX-License-Identifier: GPL-2.0-or-later @@ -6,6 +6,8 @@ import configparser import os +from .logger import log + CONFIG_OPTIONS = [ "timeout", "chip_erase_timeout", @@ -21,6 +23,7 @@ "reset_delay", "open_port_attempts", "custom_reset_sequence", + "custom_hard_reset_sequence", ] @@ -39,7 +42,7 @@ def _validate_config_file(file_path, verbose=False): no_of_unknown_opts = len(unknown_opts) if no_of_unknown_opts > 0: suffix = "s" if no_of_unknown_opts > 1 else "" - print( + log.note( "Ignoring unknown config file option{}: {}".format( suffix, ", ".join(unknown_opts) ) @@ -47,7 +50,7 @@ def _validate_config_file(file_path, verbose=False): return True except (UnicodeDecodeError, configparser.Error) as e: if verbose: - print(f"Ignoring invalid config file {file_path}: {e}") + log.note(f"Ignoring invalid config file {file_path}: {e}") return False @@ -86,7 +89,7 @@ def load_config_file(verbose=False): cfg.read(cfg_file_path) if verbose: msg = " (set with ESPTOOL_CFGFILE)" if set_with_env_var else "" - print( + log.print( f"Loaded custom configuration from " f"{os.path.abspath(cfg_file_path)}{msg}" ) diff --git a/tools/esptool_py/esptool/loader.py b/tools/esptool_py/esptool/loader.py index ca3ab9329d..adf59cdff2 100644 --- a/tools/esptool_py/esptool/loader.py +++ b/tools/esptool_py/esptool/loader.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2014-2023 Fredrik Ahlberg, Angus Gratton, +# SPDX-FileCopyrightText: 2014-2025 Fredrik Ahlberg, Angus Gratton, # Espressif Systems (Shanghai) CO LTD, other contributors as noted. # # SPDX-License-Identifier: GPL-2.0-or-later @@ -13,10 +13,9 @@ import struct import sys import time -from typing import Optional - from .config import load_config_file +from .logger import log from .reset import ( ClassicReset, CustomReset, @@ -25,15 +24,27 @@ USBJTAGSerialReset, UnixTightReset, ) -from .util import FatalError, NotImplementedInROMError, UnsupportedCommandError -from .util import byte, hexify, mask_to_shift, pad_to, strip_chip_name +from .util import ( + FatalError, + NotImplementedInROMError, + NotSupportedError, + UnsupportedCommandError, +) +from .util import ( + byte, + get_key_from_value, + hexify, + mask_to_shift, + pad_to, + strip_chip_name, +) try: import serial except ImportError: - print( - "Pyserial is not installed for %s. " - "Check the README for installation instructions." % (sys.executable) + log.error( + f"PySerial is not installed for {sys.executable}. " + "Check the documentation for installation instructions." ) raise @@ -42,7 +53,7 @@ try: if "serialization" in serial.__doc__ and "deserialization" in serial.__doc__: raise ImportError( - "esptool.py depends on pyserial, but there is a conflict with a currently " + "esptool depends on pySerial, but there is a conflict with a currently " "installed package named 'serial'.\n" "You may work around this by 'pip uninstall serial; pip install pyserial' " "but this may break other installed Python software " @@ -53,20 +64,20 @@ " for discussion of the underlying issue(s)." ) except TypeError: - pass # __doc__ returns None for pyserial + pass # __doc__ returns None for pySerial try: import serial.tools.list_ports as list_ports except ImportError: - print( - "The installed version (%s) of pyserial appears to be too old for esptool.py " - "(Python interpreter %s). Check the README for installation instructions." - % (serial.VERSION, sys.executable) + log.error( + f"The installed version ({serial.VERSION}) of pySerial appears to be too old " + f"for esptool (Python interpreter {sys.executable}). " + "Check the documentation for installation instructions." ) raise except Exception: if sys.platform == "darwin": - # swallow the exception, this is a known issue in pyserial+macOS Big Sur preview + # swallow the exception, this is a known issue in pySerial+macOS Big Sur preview # ref https://github.com/espressif/esptool/issues/540 list_ports = None else: @@ -90,7 +101,7 @@ ERASE_REGION_TIMEOUT_PER_MB = cfg.getfloat("erase_region_timeout_per_mb", 30) # Timeout (per megabyte) for erasing and writing data ERASE_WRITE_TIMEOUT_PER_MB = cfg.getfloat("erase_write_timeout_per_mb", 40) -# Short timeout for ESP_MEM_END, as it may never respond +# Short timeout for MEM_END, as it may never respond MEM_END_ROM_TIMEOUT = cfg.getfloat("mem_end_rom_timeout", 0.2) # Timeout for serial port write DEFAULT_SERIAL_WRITE_TIMEOUT = cfg.getfloat("serial_write_timeout", 10) @@ -143,17 +154,10 @@ def stub_and_esp32_function_only(func): ) -def esp32s3_or_newer_function_only(func): - """Attribute for a function only supported by ESP32S3 and later chips ROM""" - return check_supported_function( - func, lambda o: o.CHIP_NAME not in ["ESP8266", "ESP32", "ESP32-S2"] - ) - - class StubFlasher: STUB_DIR = os.path.join(os.path.dirname(__file__), "targets", "stub_flasher") # directories will be searched in the order of STUB_SUBDIRS - STUB_SUBDIRS = ["1", "2"] + STUB_SUBDIRS = ["1"] def __init__(self, chip_name): with open(self.get_json_path(chip_name)) as json_file: @@ -178,19 +182,20 @@ def get_json_path(self, chip_name): json_path = os.path.join(self.STUB_DIR, subdir, f"{chip_name}.json") if os.path.exists(json_path): if i: - print( - f"Warning: Stub version {self.STUB_SUBDIRS[0]} doesn't exist, using {subdir} instead" + log.warning( + f"Stub version {self.STUB_SUBDIRS[0]} doesn't exist, " + f"using {subdir} instead" ) return json_path else: - raise FileNotFoundError(f"Stub flasher JSON file for {chip_name} not found") + raise FileNotFoundError( + f"Stub flasher JSON file for {chip_name} not found." + ) @classmethod - def set_preferred_stub_subdir(cls, subdir): - if subdir in cls.STUB_SUBDIRS: - cls.STUB_SUBDIRS.remove(subdir) - cls.STUB_SUBDIRS.insert(0, subdir) + def set_stub_subdir(cls, subdir): + cls.STUB_SUBDIRS = [subdir] class ESPLoader(object): @@ -206,45 +211,50 @@ class ESPLoader(object): CHIP_NAME = "Espressif device" IS_STUB = False - STUB_CLASS: Optional[object] = None - BOOTLOADER_IMAGE: Optional[object] = None + STUB_CLASS: type["ESPLoader"] | None = None + BOOTLOADER_IMAGE: type | None = None + IMAGE_CHIP_ID: int | None = None + + # Chip uses magic number for chip type autodetection + USES_MAGIC_VALUE = True + MAGIC_VALUE: int | None = None + + UF2_FAMILY_ID: int = 0x0 DEFAULT_PORT = "/dev/ttyUSB0" USES_RFC2217 = False - # Commands supported by ESP8266 ROM bootloader - ESP_FLASH_BEGIN = 0x02 - ESP_FLASH_DATA = 0x03 - ESP_FLASH_END = 0x04 - ESP_MEM_BEGIN = 0x05 - ESP_MEM_END = 0x06 - ESP_MEM_DATA = 0x07 - ESP_SYNC = 0x08 - ESP_WRITE_REG = 0x09 - ESP_READ_REG = 0x0A - - # Some commands supported by ESP32 and later chips ROM bootloader (or -8266 w/ stub) - ESP_SPI_SET_PARAMS = 0x0B - ESP_SPI_ATTACH = 0x0D - ESP_READ_FLASH_SLOW = 0x0E # ROM only, much slower than the stub flash read - ESP_CHANGE_BAUDRATE = 0x0F - ESP_FLASH_DEFL_BEGIN = 0x10 - ESP_FLASH_DEFL_DATA = 0x11 - ESP_FLASH_DEFL_END = 0x12 - ESP_SPI_FLASH_MD5 = 0x13 - - # Commands supported by ESP32-S2 and later chips ROM bootloader only - ESP_GET_SECURITY_INFO = 0x14 - - # Some commands supported by stub only - ESP_ERASE_FLASH = 0xD0 - ESP_ERASE_REGION = 0xD1 - ESP_READ_FLASH = 0xD2 - ESP_RUN_USER_CODE = 0xD3 - - # Flash encryption encrypted data command - ESP_FLASH_ENCRYPT_DATA = 0xD4 + ESP_CMDS = { + # Commands supported by ESP8266 ROM bootloader + "FLASH_BEGIN": 0x02, + "FLASH_DATA": 0x03, + "FLASH_END": 0x04, + "MEM_BEGIN": 0x05, + "MEM_END": 0x06, + "MEM_DATA": 0x07, + "SYNC": 0x08, + "WRITE_REG": 0x09, + "READ_REG": 0x0A, + # Commands supported by ESP32 and later chips ROM bootloader (or -8266 w/ stub) + "SPI_SET_PARAMS": 0x0B, + "SPI_ATTACH": 0x0D, + "READ_FLASH_SLOW": 0x0E, # ROM only, much slower than the stub flash read + "CHANGE_BAUDRATE": 0x0F, + "FLASH_DEFL_BEGIN": 0x10, + "FLASH_DEFL_DATA": 0x11, + "FLASH_DEFL_END": 0x12, + "SPI_FLASH_MD5": 0x13, + # Commands supported by ESP32-S2 and later chips ROM bootloader only + "GET_SECURITY_INFO": 0x14, + # Some commands supported by stub only + "ERASE_FLASH": 0xD0, + "ERASE_REGION": 0xD1, + "READ_FLASH": 0xD2, + "RUN_USER_CODE": 0xD3, + # Flash encryption encrypted data command + "FLASH_ENCRYPT_DATA": 0xD4, + } # Response code(s) sent by ROM ROM_INVALID_RECV_MSG = 0x05 # response if an invalid message is received @@ -268,7 +278,8 @@ class ESPLoader(object): UART_DATE_REG_ADDR = 0x60000078 - # Whether the SPI peripheral sends from MSB of 32-bit register, or the MSB of valid LSB bits. + # Whether the SPI peripheral sends from MSB of 32-bit register, or the MSB of valid + # LSB bits. SPI_ADDR_REG_MSB = True # This ROM address has a different value on each chip model @@ -280,16 +291,13 @@ class ESPLoader(object): IROM_MAP_START = 0x40200000 IROM_MAP_END = 0x40300000 - # The number of bytes in the UART response that signify command status - STATUS_BYTES_LENGTH = 2 - # Bootloader flashing offset BOOTLOADER_FLASH_OFFSET = 0x0 # ROM supports an encrypted flashing mode SUPPORTS_ENCRYPTED_FLASH = False - # Response to ESP_SYNC might indicate that flasher stub is running + # Response to SYNC might indicate that flasher stub is running # instead of the ROM bootloader sync_stub_detected = False @@ -297,11 +305,22 @@ class ESPLoader(object): USB_JTAG_SERIAL_PID = 0x1001 # Chip IDs that are no longer supported by esptool - UNSUPPORTED_CHIPS = {6: "ESP32-S3(beta 3)"} + UNSUPPORTED_CHIPS = { + 4: "ESP32-S3(beta2)", + 6: "ESP32-S3(beta3)", + 7: "ESP32-C6(beta)", + 10: "ESP32-H2(beta1)", + 14: "ESP32-H2(beta2)", + 17: "ESP32-C5(beta3)", + } # Number of attempts to write flash data WRITE_FLASH_ATTEMPTS = 2 + FLASH_ENCRYPTED_WRITE_ALIGN = 16 + KEY_PURPOSES: dict[int, str] = {} + EFUSE_MAX_KEY = 5 + def __init__(self, port=DEFAULT_PORT, baud=ESP_ROM_BAUD, trace_enabled=False): """Base constructor for ESPLoader bootloader interaction @@ -323,9 +342,9 @@ def __init__(self, port=DEFAULT_PORT, baud=ESP_ROM_BAUD, trace_enabled=False): # Device-and-runtime-specific cache self.cache = { "flash_id": None, - "chip_id": None, "uart_no": None, "usb_pid": None, + "security_info": None, } if isinstance(port, str): @@ -403,8 +422,7 @@ def _set_port_baudrate(self, baud): self._port.baudrate = baud except IOError: raise FatalError( - "Failed to set baud rate %d. The driver may not support this rate." - % baud + f"Failed to set baud rate {baud}. The driver may not support this rate." ) def read(self): @@ -418,10 +436,10 @@ def write(self, packet): + (packet.replace(b"\xdb", b"\xdb\xdd").replace(b"\xc0", b"\xdb\xdc")) + b"\xc0" ) - self.trace("Write %d bytes: %s", len(buf), HexFormatter(buf)) + self.trace(f"{f'Write {len(buf)} bytes:':<21} {HexFormatter(buf)}") self._port.write(buf) - def trace(self, message, *format_args): + def trace(self, message, newline=False): if self._trace_enabled: now = time.time() try: @@ -429,8 +447,8 @@ def trace(self, message, *format_args): except AttributeError: delta = 0.0 self._last_trace = now - prefix = "TRACE +%.3f " % delta - print(prefix + (message % format_args)) + prefix = f" TRACE +{delta:.3f} " + log.print("\n" if newline else "", f"{prefix} {message}") @staticmethod def checksum(data, state=ESP_CHECKSUM_MAGIC): @@ -457,13 +475,10 @@ def command( try: if op is not None: self.trace( - "command op=0x%02x data len=%s wait_response=%d " - "timeout=%.3f data=%s", - op, - len(data), - 1 if wait_response else 0, - timeout, - HexFormatter(data), + f"--- Cmd {get_key_from_value(self.ESP_CMDS, op)} ({op:#04x}) | " + f"data_len {len(data)} | wait_response {1 if wait_response else 0}" + f" | timeout {timeout:.3f} | data {HexFormatter(data)} ---", + newline=True, ) pkt = struct.pack(b" self.STATUS_BYTES_LENGTH: - return data[: -self.STATUS_BYTES_LENGTH] + # Execute the command and get the result + val, data = self.command(op, data, chk, timeout=timeout) + + # Check if we have enough data, + # including the expected response data and status bytes + if len(data) < resp_data_len + STATUS_BYTES_LENGTH: + # If we don't have enough data, check the first 2 bytes as status + status_bytes = data[0:2] + # Only care if the first byte is non-zero. + # If it is, the second byte is a reason. + if status_bytes[0] != 0: + raise FatalError.WithResult(f"Failed to {op_description}", status_bytes) + else: + raise FatalError( + f"Failed to {op_description}. " + f"Only got {len(data)} byte status response." + ) + # The status bytes are positioned after the expected response data + # (first two bytes after resp_data_len are the status bytes) + status_bytes = data[resp_data_len : resp_data_len + STATUS_BYTES_LENGTH] + # Only care if the first byte is non-zero. + # If it is, the second byte is a reason. + if status_bytes[0] != 0: + raise FatalError.WithResult(f"Failed to {op_description}", status_bytes) + + if resp_data_len > 0: + return data[:resp_data_len] else: - # otherwise, just return the 'val' field which comes from the reply header - # (this is used by read_reg) return val def flush_input(self): @@ -537,7 +571,9 @@ def flush_input(self): def sync(self): val, _ = self.command( - self.ESP_SYNC, b"\x07\x07\x12\x20" + 32 * b"\x55", timeout=SYNC_TIMEOUT + self.ESP_CMDS["SYNC"], + b"\x07\x07\x12\x20" + 32 * b"\x55", + timeout=SYNC_TIMEOUT, ) # ROM bootloaders send some non-zero "val" response. The flasher stub sends 0. @@ -554,7 +590,7 @@ def _get_pid(self): return self.cache["usb_pid"] if list_ports is None: - print( + log.print( "\nListing all serial ports is currently not available. " "Can't get device PID." ) @@ -563,7 +599,7 @@ def _get_pid(self): # Pyserial only identifies regular ports, URL handlers are not supported if not active_port.lower().startswith(("com", "/dev/")): - print( + log.print( "\nDevice PID identification is only supported on " "COM and /dev/ serial ports." ) @@ -582,12 +618,12 @@ def _get_pid(self): if p.device in active_ports: self.cache["usb_pid"] = p.pid return p.pid - print( + log.print( f"\nFailed to get PID of a device on {active_port}, " "using standard reset sequence." ) - def _connect_attempt(self, reset_strategy, mode="default_reset"): + def _connect_attempt(self, reset_strategy, mode="default-reset"): """A single connection attempt""" last_error = None boot_log_detected = False @@ -595,10 +631,10 @@ def _connect_attempt(self, reset_strategy, mode="default_reset"): # If we're doing no_sync, we're likely communicating as a pass through # with an intermediate device to the ESP32 - if mode == "no_reset_no_sync": + if mode == "no-reset-no-sync": return last_error - if mode != "no_reset": + if mode != "no-reset": if not self.USES_RFC2217: # Might block on rfc2217 ports # Empty serial buffer to isolate boot log self._port.reset_input_buffer() @@ -623,8 +659,7 @@ def _connect_attempt(self, reset_strategy, mode="default_reset"): self.sync() return None except FatalError as e: - print(".", end="") - sys.stdout.flush() + log.print(".", end="", flush=True) time.sleep(0.05) last_error = e @@ -677,7 +712,7 @@ def _construct_reset_strategy_sequence(self, mode): delay = extra_delay = 7 # USB-JTAG/Serial mode - if mode == "usb_reset" or self._get_pid() == self.USB_JTAG_SERIAL_PID: + if mode == "usb-reset" or self._get_pid() == self.USB_JTAG_SERIAL_PID: return (USBJTAGSerialReset(self._port),) # USB-to-Serial bridge @@ -696,29 +731,28 @@ def _construct_reset_strategy_sequence(self, mode): def connect( self, - mode="default_reset", + mode="default-reset", attempts=DEFAULT_CONNECT_ATTEMPTS, detecting=False, warnings=True, ): """Try connecting repeatedly until successful, or giving up""" - if warnings and mode in ["no_reset", "no_reset_no_sync"]: - print( - 'WARNING: Pre-connection option "{}" was selected.'.format(mode), + if warnings and mode in ["no-reset", "no-reset-no-sync"]: + log.note( + f'Pre-connection option "{mode}" was selected. ' "Connection may fail if the chip is not in bootloader " - "or flasher stub mode.", + "or flasher stub mode." ) if self._port.name.startswith("socket:"): - mode = "no_reset" # not possible to toggle DTR/RTS over a TCP socket - print( - "Note: It's not possible to reset the chip over a TCP socket. " + mode = "no-reset" # not possible to toggle DTR/RTS over a TCP socket + log.note( + "It's not possible to reset the chip over a TCP socket. " "Automatic resetting to bootloader has been disabled, " "reset the chip manually." ) - print("Connecting...", end="") - sys.stdout.flush() + log.print("Connecting...", end="", flush=True) last_error = None reset_sequence = self._construct_reset_strategy_sequence(mode) @@ -731,17 +765,17 @@ def connect( if last_error is None: break finally: - print("") # end 'Connecting...' line + log.print("") # end 'Connecting...' line if last_error is not None: additional_msg = "" if self.CHIP_NAME == "ESP32-C2" and self._port.baudrate < 115200: additional_msg = ( - "\nNote: Please set a higher baud rate (--baud)" + "\nNote: Please set a higher baud rate" " if ESP32-C2 doesn't connect" " (at least 115200 Bd is recommended)." ) - + self._port.close() raise FatalError( "Failed to connect to {}: {}" f"{additional_msg}" @@ -752,41 +786,80 @@ def connect( ) if not detecting: - try: - from .targets import ROM_LIST - - # check the date code registers match what we expect to see - chip_magic_value = self.read_reg(ESPLoader.CHIP_DETECT_MAGIC_REG_ADDR) - if chip_magic_value not in self.CHIP_DETECT_MAGIC_VALUE: - actually = None - for cls in ROM_LIST: - if chip_magic_value in cls.CHIP_DETECT_MAGIC_VALUE: - actually = cls - break - if warnings and actually is None: - print( - "WARNING: This chip doesn't appear to be a %s " - "(chip magic value 0x%08x). " - "Probably it is unsupported by this version of esptool." - % (self.CHIP_NAME, chip_magic_value) - ) - else: - raise FatalError( - "This chip is %s not %s. Wrong --chip argument?" - % (actually.CHIP_NAME, self.CHIP_NAME) - ) - except UnsupportedCommandError: - self.secure_download_mode = True + from .targets import ROM_LIST + # Check if chip supports reading chip ID from the get-security-info command try: - self.check_chip_id() - except UnsupportedCommandError: - # Fix for ROM not responding in SDM, reconnect and try again - if self.secure_download_mode: - self._connect_attempt(mode, reset_sequence[0]) - self.check_chip_id() + # get_chip_id() raises FatalError if the chip does not have a chip ID + # (ESP32-S2) + chip_id = self.get_chip_id() + si = self.get_security_info() + self.secure_download_mode = si["parsed_flags"]["SECURE_DOWNLOAD_ENABLE"] + except (UnsupportedCommandError, FatalError): + chip_id = None + # Try to read the chip magic value to verify the chip type + # (ESP8266, ESP32, ESP32-S2) + try: + chip_magic_value = self.read_reg( + ESPLoader.CHIP_DETECT_MAGIC_REG_ADDR + ) + except UnsupportedCommandError: + # If the chip does not support reading the chip magic value, + # it is ESP32-S2 in SDM + chip_magic_value = None + self.secure_download_mode = True + + detected = None + chip_arg_wrong = False + + # If we can read chip ID (ESP32-S3 and later), verify the ID + if chip_id and (self.USES_MAGIC_VALUE or chip_id != self.IMAGE_CHIP_ID): + chip_arg_wrong = True + for cls in ROM_LIST: + if not cls.USES_MAGIC_VALUE and chip_id == cls.IMAGE_CHIP_ID: + detected = cls + break + # If we can't read chip ID (ESP8266, ESP32, ESP32-S2), + # try to verify the chip by magic value + elif ( + not chip_id + and not self.secure_download_mode + and (not self.USES_MAGIC_VALUE or chip_magic_value != self.MAGIC_VALUE) + ): + chip_arg_wrong = True + for cls in ROM_LIST: + if cls.USES_MAGIC_VALUE and chip_magic_value == cls.MAGIC_VALUE: + detected = cls + break + # If we can't read chip ID and the chip is in SDM, it is ESP32-S2 + elif ( + not chip_id + and self.secure_download_mode + and self.CHIP_NAME != "ESP32-S2" + ): + chip_arg_wrong = True + detected = "ESP32-S2" + + if chip_arg_wrong: + if warnings and detected is None: + specifier = ( + f"(read chip ID {chip_id})" + if chip_id + else f"(read chip magic value {chip_magic_value:#08x})" + ) + log.warning( + f"This chip doesn't appear to be an {self.CHIP_NAME} " + f"{specifier}. Probably it is unsupported by this version " + "of esptool. Will attempt to continue anyway." + ) else: - raise + chip_type = ( + detected if isinstance(detected, str) else detected.CHIP_NAME + ) + raise FatalError( + f"This chip is {chip_type}, not {self.CHIP_NAME}. " + "Wrong chip argument?" + ) self._post_connect() def _post_connect(self): @@ -798,17 +871,10 @@ def _post_connect(self): def read_reg(self, addr, timeout=DEFAULT_TIMEOUT): """Read memory address in target""" - # we don't call check_command here because read_reg() function is called - # when detecting chip type, and the way we check for success - # (STATUS_BYTES_LENGTH) is different for different chip types (!) - val, data = self.command( - self.ESP_READ_REG, struct.pack(" stub_start: raise FatalError( - "Software loader is resident at 0x%08x-0x%08x. " - "Can't load binary at overlapping address range 0x%08x-0x%08x. " - "Either change binary loading address, or use the --no-stub " - "option to disable the software loader." - % (stub_start, stub_end, load_start, load_end) + "Stub flasher is resident at " + f"{stub_start:#010x}-{stub_end:#010x}. " + "Can't load binary at overlapping address range " + f"{load_start:#010x}-{load_end:#010x}. Either change binary " + "loading address, or disable the stub flasher." ) return self.check_command( "enter RAM download mode", - self.ESP_MEM_BEGIN, + self.ESP_CMDS["MEM_BEGIN"], struct.pack(" "ESPLoader": + log.stage() if stub is None: stub = StubFlasher(self.CHIP_NAME) if self.sync_stub_detected: - print("Stub is already running. No upload is necessary.") - return self.STUB_CLASS(self) + log.stage(finish=True) + log.print("Stub flasher is already running. No upload is necessary.") + return self.STUB_CLASS(self) if self.STUB_CLASS is not None else self # Upload - print("Uploading stub...") + log.print("Uploading stub flasher...") for field in [stub.text, stub.data]: if field is not None: offs = stub.text_start if field == stub.text else stub.data_start @@ -1066,21 +1271,22 @@ def run_stub(self, stub=None): from_offs = seq * self.ESP_RAM_BLOCK to_offs = from_offs + self.ESP_RAM_BLOCK self.mem_block(field[from_offs:to_offs], seq) - print("Running stub...") + log.print("Running stub flasher...") self.mem_finish(stub.entry) try: p = self.read() except StopIteration: raise FatalError( - "Failed to start stub. There was no response." + "Failed to start stub flasher. There was no response." "\nTry increasing timeouts, for more information see: " "https://docs.espressif.com/projects/esptool/en/latest/esptool/configuration-file.html" # noqa E501 ) if p != b"OHAI": - raise FatalError(f"Failed to start stub. Unexpected response: {p}") - print("Stub running...") - return self.STUB_CLASS(self) + raise FatalError(f"Failed to start stub flasher. Unexpected response: {p}") + log.stage(finish=True) + log.print("Stub flasher running.") + return self.STUB_CLASS(self) if self.STUB_CLASS is not None else self @stub_and_esp32_function_only def flash_defl_begin(self, size, compsize, offset): @@ -1105,7 +1311,7 @@ def flash_defl_begin(self, size, compsize, offset): timeout = timeout_per_mb( ERASE_REGION_TIMEOUT_PER_MB, write_size ) # ROM performs the erase up front - print("Compressed %d bytes to %d..." % (size, compsize)) + log.print(f"Compressed {size} bytes to {compsize}...") params = struct.pack( " bytes: raise NotImplementedInROMError(self, self.read_flash_slow) - def read_flash(self, offset, length, progress_fn=None): + def read_flash(self, offset, length, progress_fn=None) -> bytes: if not self.IS_STUB: return self.read_flash_slow(offset, length, progress_fn) # ROM-only routine # issue a standard bootloader command to trigger the read self.check_command( "read flash", - self.ESP_READ_FLASH, + self.ESP_CMDS["READ_FLASH"], struct.pack(" length: - raise FatalError("Read more than expected") + raise FatalError("Read more than expected.") digest_frame = self.read() if len(digest_frame) != 16: - raise FatalError("Expected digest, got: %s" % hexify(digest_frame)) + raise FatalError(f"Expected digest, got: {hexify(digest_frame)}") expected_digest = hexify(digest_frame).upper() digest = hashlib.md5(data).hexdigest().upper() if digest != expected_digest: raise FatalError( - "Digest mismatch: expected %s, got %s" % (expected_digest, digest) + f"Digest mismatch: expected {expected_digest}, got {digest}" ) return data @@ -1256,15 +1463,15 @@ def flash_spi_attach(self, hspi_arg): ESP8266 ROM does this when you send flash_begin, ESP32 ROM has it as a SPI command. """ - # last 3 bytes in ESP_SPI_ATTACH argument are reserved values + # last 3 bytes in SPI_ATTACH argument are reserved values arg = struct.pack(" 64: raise FatalError( - "Writing more than 64 bytes of data with one SPI " - "command is unsupported" + "Writing more than 64 bytes of data with one SPI command is unsupported" ) data_bits = len(data) * 8 @@ -1518,16 +1724,20 @@ def get_crystal_freq(self): else: norm_xtal = 26 if abs(norm_xtal - est_xtal) > 1: - print( - "WARNING: Detected crystal freq %.2fMHz is quite different to " - "normalized freq %dMHz. Unsupported crystal in use?" - % (est_xtal, norm_xtal) + log.warning( + f"Detected crystal freq {est_xtal:.2f} MHz is quite different to " + f"normalized freq {norm_xtal} MHz. Unsupported crystal in use?" ) + return norm_xtal - def hard_reset(self): - print("Hard resetting via RTS pin...") - HardReset(self._port)() + def hard_reset(self, uses_usb=False): + log.print("Hard resetting via RTS pin...") + cfg_custom_hard_reset_sequence = cfg.get("custom_hard_reset_sequence") + if cfg_custom_hard_reset_sequence is not None: + CustomReset(self._port, cfg_custom_hard_reset_sequence)() + else: + HardReset(self._port, uses_usb)() def soft_reset(self, stay_in_bootloader): if not self.IS_STUB: @@ -1550,24 +1760,33 @@ def soft_reset(self, stay_in_bootloader): else: # running user code from stub loader requires some hacks # in the stub loader - self.command(self.ESP_RUN_USER_CODE, wait_response=False) + self.command(self.ESP_CMDS["RUN_USER_CODE"], wait_response=False) - def check_chip_id(self): - try: - chip_id = self.get_chip_id() - if chip_id != self.IMAGE_CHIP_ID: - print( - "WARNING: Chip ID {} ({}) doesn't match expected Chip ID {}. " - "esptool may not work correctly.".format( - chip_id, - self.UNSUPPORTED_CHIPS.get(chip_id, "Unknown"), - self.IMAGE_CHIP_ID, - ) - ) - # Try to flash anyways by disabling stub - self.stub_is_disabled = True - except NotImplementedInROMError: - pass + def watchdog_reset(self): + log.note( + f"Watchdog hard reset is not supported on {self.CHIP_NAME}, " + "attempting classic hard reset instead." + ) + self.hard_reset() + + +class StubMixin: + """ + Mixin class bundling the stub loader-specific properties. + Not intended for direct instantiation. + A child class (e.g. ESP32StubLoader) uses multiple inheritance + to combine this mixin class (StubMixin) with a parent class (e.g. ESP32ROM). + """ + + FLASH_WRITE_SIZE = 0x4000 # Default value, can be overridden + IS_STUB = True + + def __init__(self, rom_loader): + self.secure_download_mode = rom_loader.secure_download_mode + self._port = rom_loader._port + self._trace_enabled = rom_loader._trace_enabled + self.cache = rom_loader.cache + self.flush_input() # resets _slip_reader def slip_reader(port, trace_function): @@ -1604,7 +1823,7 @@ def detect_panic_handler(input): if i is not None ] cause = f" {cause[0]}" if len(cause) else "" - msg = f"Guru Meditation Error detected{cause}" + msg = f"Guru Meditation Error detected{cause}." raise FatalError(msg) partial_packet = None @@ -1621,28 +1840,29 @@ def detect_panic_handler(input): else "No serial data received." ) else: # fail during packet transfer - msg = "Packet content transfer stopped (received {} bytes)".format( - len(partial_packet) - ) + msg = "Packet content transfer stopped " + f"(received {len(partial_packet)} bytes)." trace_function(msg) raise FatalError(msg) - trace_function("Read %d bytes: %s", len(read_bytes), HexFormatter(read_bytes)) + trace_function( + f"{f'Read {len(read_bytes)} bytes:':<21} {HexFormatter(read_bytes)}" + ) for b in read_bytes: b = bytes([b]) if partial_packet is None: # waiting for packet header if b == b"\xc0": partial_packet = b"" else: - trace_function("Read invalid data: %s", HexFormatter(read_bytes)) + trace_function(f"Read invalid data: {HexFormatter(read_bytes)}") remaining_data = port.read(port.inWaiting()) trace_function( - "Remaining data in serial buffer: %s", - HexFormatter(remaining_data), + "Remaining data in serial buffer: " + f"{HexFormatter(remaining_data)}", ) detect_panic_handler(read_bytes + remaining_data) raise FatalError( - "Invalid head of packet (0x%s): " - "Possible serial noise or corruption." % hexify(b) + f"Invalid head of packet (0x{hexify(b)}): " + "Possible serial noise or corruption." ) elif in_escape: # part-way through escape sequence in_escape = False @@ -1651,18 +1871,18 @@ def detect_panic_handler(input): elif b == b"\xdd": partial_packet += b"\xdb" else: - trace_function("Read invalid data: %s", HexFormatter(read_bytes)) + trace_function(f"Read invalid data: {HexFormatter(read_bytes)}") remaining_data = port.read(port.inWaiting()) trace_function( - "Remaining data in serial buffer: %s", - HexFormatter(remaining_data), + "Remaining data in serial buffer: " + f"{HexFormatter(remaining_data)}" ) detect_panic_handler(read_bytes + remaining_data) - raise FatalError("Invalid SLIP escape (0xdb, 0x%s)" % (hexify(b))) + raise FatalError(f"Invalid SLIP escape (0xdb, 0x{hexify(b)}).") elif b == b"\xdb": # start of escape sequence in_escape = True elif b == b"\xc0": # end of packet - trace_function("Received full packet: %s", HexFormatter(partial_packet)) + trace_function(f"Received full packet: {HexFormatter(partial_packet)}") yield partial_packet partial_packet = None successful_slip = True diff --git a/tools/esptool_py/esptool/logger.py b/tools/esptool_py/esptool/logger.py new file mode 100644 index 0000000000..b4ea21545e --- /dev/null +++ b/tools/esptool_py/esptool/logger.py @@ -0,0 +1,273 @@ +# SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD +# +# SPDX-License-Identifier: GPL-2.0-or-later + +from abc import ABC, abstractmethod +import sys +import os + + +class TemplateLogger(ABC): + @abstractmethod + def print(self, *args, **kwargs): + """ + Log a plain message. + """ + pass + + @abstractmethod + def note(self, message: str): + """ + Log a Note: message. + """ + pass + + @abstractmethod + def warning(self, message: str): + """ + Log a Warning: message. + """ + pass + + @abstractmethod + def error(self, message: str): + """ + Log an error message. + """ + pass + + @abstractmethod + def stage(self, finish: bool = False): + """ + Start or finish a new collapsible stage. + """ + pass + + @abstractmethod + def progress_bar( + self, + cur_iter: int, + total_iters: int, + prefix: str = "", + suffix: str = "", + bar_length: int = 30, + ): + """ + Print a progress bar. + """ + pass + + @abstractmethod + def set_verbosity(self, verbosity: str): + """ + Set the verbosity level. + """ + pass + + +class EsptoolLogger(TemplateLogger): + ansi_red: str = "" + ansi_yellow: str = "" + ansi_blue: str = "" + ansi_normal: str = "" + ansi_clear: str = "" + ansi_line_up: str = "" + ansi_line_clear: str = "" + + _stage_active: bool = False + _newline_count: int = 0 + _kept_lines: list[str] = [] + + _smart_features: bool = False + _verbosity: str | None = None + _print_anyway: bool = False + + def __new__(cls): + """ + Singleton to ensure only one instance of the logger exists. + """ + if not hasattr(cls, "instance"): + cls.instance = super(EsptoolLogger, cls).__new__(cls) + cls.instance.set_verbosity("auto") + return cls.instance + + @classmethod + def _del(cls) -> None: + if hasattr(cls, "instance"): + del cls.instance + + @classmethod + def _set_smart_features(cls, override: bool | None = None): + # Check for smart terminal and color support + if override is not None: + cls.instance._smart_features = override + else: + is_tty = hasattr(sys.stdout, "isatty") and sys.stdout.isatty() + term_supports_color = os.getenv("TERM", "").lower() in ( + "xterm", + "xterm-256color", + "screen", + "screen-256color", + "linux", + "vt100", + ) + no_color = os.getenv("NO_COLOR", "").strip().lower() in ("1", "true", "yes") + + # Determine if colors should be enabled + cls.instance._smart_features = ( + is_tty or term_supports_color and not no_color + ) + # Handle Windows specifically + if sys.platform == "win32" and cls.instance._smart_features: + try: + from colorama import init + + init() # Enable ANSI support on Windows + except ImportError: + cls.instance._smart_features = False + + if cls.instance._smart_features: + cls.instance.ansi_red = "\033[1;31m" + cls.instance.ansi_yellow = "\033[0;33m" + cls.instance.ansi_blue = "\033[1;36m" + cls.instance.ansi_normal = "\033[0m" + cls.instance.ansi_clear = "\033[K" + cls.instance.ansi_line_up = "\033[1A" + cls.instance.ansi_line_clear = "\x1b[2K" + else: + cls.instance.ansi_red = "" + cls.instance.ansi_yellow = "" + cls.instance.ansi_blue = "" + cls.instance.ansi_normal = "" + cls.instance.ansi_clear = "" + cls.instance.ansi_line_up = "" + cls.instance.ansi_line_clear = "" + + def print(self, *args, **kwargs): + """ + Log a plain message. Count newlines if in a collapsing stage. + """ + if self._verbosity == "silent" and not self._print_anyway: + return + if self._stage_active: + # Count the number of newlines in the message + message = "".join(map(str, args)) + self._newline_count += message.count("\n") + if kwargs.get("end", "\n") == "\n": + self._newline_count += 1 + print(*args, **kwargs) + self._print_anyway = False + + def note(self, message: str): + """ + Log a Note: message in blue and white. + """ + formatted_message = f"{self.ansi_blue}Note:{self.ansi_normal} {message}" + if self._stage_active: + self._kept_lines.append(formatted_message) + self.print(formatted_message) + + def warning(self, message: str): + """ + Log a Warning: message in yellow and white. + """ + formatted_message = f"{self.ansi_yellow}Warning:{self.ansi_normal} {message}" + if self._stage_active: + self._kept_lines.append(formatted_message) + self.print(formatted_message) + + def error(self, message: str): + """ + Log an error message in red to stderr. + """ + formatted_message = f"{self.ansi_red}{message}{self.ansi_normal}" + self._print_anyway = True + self.print(formatted_message, file=sys.stderr) + + def stage(self, finish: bool = False): + """ + Start or finish a collapsible stage. + Any log messages printed between the start and finish will be deleted + when the stage is successfully finished. + Warnings and notes will be saved and printed at the end of the stage. + If terminal doesn't support ANSI escape codes, no collapsing happens. + """ + if finish: + if not self._stage_active: + return + # Deactivate stage to stop collecting input + self._stage_active = False + + if self._smart_features: + # Delete printed lines + self.print( + f"{self.ansi_line_up}{self.ansi_line_clear}" + * (self._newline_count), + end="", + flush=True, + ) + # Print saved warnings and notes + for line in self._kept_lines: + self.print(line) + + # Clean the buffers for next stage + self._kept_lines.clear() + self._newline_count = 0 + else: + self._stage_active = True + + def progress_bar( + self, + cur_iter: int, + total_iters: int, + prefix: str = "", + suffix: str = "", + bar_length: int = 30, + ): + """ + Call in a loop to print a progress bar overwriting itself in place. + If terminal doesn't support ANSI escape codes, no overwriting happens. + """ + filled = int(bar_length * cur_iter // total_iters) + if filled == bar_length: + bar = "=" * bar_length + elif filled == 0: + bar = " " * bar_length + else: + bar = f"{'=' * (filled - 1)}>{' ' * (bar_length - filled)}" + + percent = f"{100 * (cur_iter / float(total_iters)):.1f}" + self.print( + f"\r{self.ansi_clear}{prefix}[{bar}] {percent:>5}%{suffix} ", + end="\n" if not self._smart_features or cur_iter == total_iters else "", + flush=True, + ) + + def set_logger(self, new_logger): + self.__class__ = new_logger.__class__ + + def set_verbosity(self, verbosity: str): + """ + Set the verbosity level to one of the following: + - "auto": Enable smart terminal features and colors if supported by the terminal + - "verbose": Enable verbose output (no collapsing output) + - "silent": Disable all output except errors + - "compact": Enable smart terminal features and colors even if not supported + """ + if verbosity == self._verbosity: + return + + self._verbosity = verbosity + if verbosity == "auto": + self._set_smart_features() + elif verbosity == "verbose": + self._set_smart_features(override=False) + elif verbosity == "silent": + pass + elif verbosity == "compact": + self._set_smart_features(override=True) + else: + raise ValueError(f"Invalid verbosity level: {verbosity}") + + +log = EsptoolLogger() diff --git a/tools/esptool_py/esptool/reset.py b/tools/esptool_py/esptool/reset.py index ef91e4bdc1..2a782e7b71 100644 --- a/tools/esptool_py/esptool/reset.py +++ b/tools/esptool_py/esptool/reset.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2014-2023 Fredrik Ahlberg, Angus Gratton, +# SPDX-FileCopyrightText: 2014-2025 Fredrik Ahlberg, Angus Gratton, # Espressif Systems (Shanghai) CO LTD, other contributors as noted. # # SPDX-License-Identifier: GPL-2.0-or-later @@ -8,6 +8,7 @@ import struct import time +from .logger import log from .util import FatalError, PrintOnce # Used for resetting into bootloader on Unix-like systems @@ -27,7 +28,7 @@ class ResetStrategy(object): - print_once = PrintOnce() + print_once = PrintOnce(log.warning) def __init__(self, port, reset_delay=DEFAULT_RESET_DELAY): self.port = port @@ -50,10 +51,10 @@ def __call__(self): # ENOTTY for TIOCMSET; EINVAL for TIOCMGET if e.errno in [errno.ENOTTY, errno.EINVAL]: self.print_once( - "WARNING: Chip was NOT reset. Setting RTS/DTR lines is not " - f"supported for port '{self.port.name}'. Set --before and --after " - "arguments to 'no_reset' and switch to bootloader manually to " - "avoid this warning." + "Chip was NOT reset. Setting RTS/DTR lines is not " + f"supported for port '{self.port.name}'. Set --before and " + "--after arguments to 'no-reset' and switch to bootloader " + "manually to avoid this warning." ) break elif not retry: @@ -205,5 +206,5 @@ def _parse_string_to_seq(self, seq_str): cmds = seq_str.split("|") fn_calls_list = [self.format_dict[cmd[0]].format(cmd[1:]) for cmd in cmds] except Exception as e: - raise FatalError(f'Invalid "custom_reset_sequence" option format: {e}') + raise FatalError(f"Invalid custom reset sequence option format: {e}") return "\n".join(fn_calls_list) diff --git a/tools/esptool_py/esptool/targets/__init__.py b/tools/esptool_py/esptool/targets/__init__.py index 30c08605d7..ea5c8d7aef 100644 --- a/tools/esptool_py/esptool/targets/__init__.py +++ b/tools/esptool_py/esptool/targets/__init__.py @@ -2,17 +2,14 @@ from .esp32c2 import ESP32C2ROM from .esp32c3 import ESP32C3ROM from .esp32c5 import ESP32C5ROM -from .esp32c5beta3 import ESP32C5BETA3ROM from .esp32c6 import ESP32C6ROM from .esp32c61 import ESP32C61ROM -from .esp32c6beta import ESP32C6BETAROM from .esp32h2 import ESP32H2ROM -from .esp32h2beta1 import ESP32H2BETA1ROM -from .esp32h2beta2 import ESP32H2BETA2ROM +from .esp32h21 import ESP32H21ROM +from .esp32h4 import ESP32H4ROM from .esp32p4 import ESP32P4ROM from .esp32s2 import ESP32S2ROM from .esp32s3 import ESP32S3ROM -from .esp32s3beta2 import ESP32S3BETA2ROM from .esp8266 import ESP8266ROM @@ -20,19 +17,16 @@ "esp8266": ESP8266ROM, "esp32": ESP32ROM, "esp32s2": ESP32S2ROM, - "esp32s3beta2": ESP32S3BETA2ROM, "esp32s3": ESP32S3ROM, "esp32c3": ESP32C3ROM, - "esp32c6beta": ESP32C6BETAROM, - "esp32h2beta1": ESP32H2BETA1ROM, - "esp32h2beta2": ESP32H2BETA2ROM, "esp32c2": ESP32C2ROM, "esp32c6": ESP32C6ROM, "esp32c61": ESP32C61ROM, "esp32c5": ESP32C5ROM, - "esp32c5beta3": ESP32C5BETA3ROM, "esp32h2": ESP32H2ROM, + "esp32h21": ESP32H21ROM, "esp32p4": ESP32P4ROM, + "esp32h4": ESP32H4ROM, } CHIP_LIST = list(CHIP_DEFS.keys()) diff --git a/tools/esptool_py/esptool/targets/esp32.py b/tools/esptool_py/esptool/targets/esp32.py index aef531a0d6..6ab879a69b 100644 --- a/tools/esptool_py/esptool/targets/esp32.py +++ b/tools/esptool_py/esptool/targets/esp32.py @@ -1,14 +1,14 @@ -# SPDX-FileCopyrightText: 2014-2022 Fredrik Ahlberg, Angus Gratton, +# SPDX-FileCopyrightText: 2014-2025 Fredrik Ahlberg, Angus Gratton, # Espressif Systems (Shanghai) CO LTD, other contributors as noted. # # SPDX-License-Identifier: GPL-2.0-or-later import struct import time -from typing import Dict, Optional -from ..loader import ESPLoader -from ..util import FatalError, NotSupportedError +from ..loader import ESPLoader, StubMixin +from ..logger import log +from ..util import FatalError class ESP32ROM(ESPLoader): @@ -16,9 +16,8 @@ class ESP32ROM(ESPLoader): CHIP_NAME = "ESP32" IMAGE_CHIP_ID = 0 - IS_STUB = False - CHIP_DETECT_MAGIC_VALUE = [0x00F01D83] + MAGIC_VALUE = 0x00F01D83 IROM_MAP_START = 0x400D0000 IROM_MAP_END = 0x40400000 @@ -26,9 +25,6 @@ class ESP32ROM(ESPLoader): DROM_MAP_START = 0x3F400000 DROM_MAP_END = 0x3F800000 - # ESP32 uses a 4 byte status reply - STATUS_BYTES_LENGTH = 4 - SPI_REG_BASE = 0x3FF42000 SPI_USR_OFFS = 0x1C SPI_USR1_OFFS = 0x20 @@ -125,8 +121,6 @@ class ESP32ROM(ESPLoader): UF2_FAMILY_ID = 0x1C5F21B0 - KEY_PURPOSES: Dict[int, str] = {} - """ Try to read the BLOCK1 (encryption key) and check if it is valid """ def is_flash_encryption_key_valid(self): @@ -201,9 +195,6 @@ def get_pkg_version(self): pkg_version += ((word3 >> 2) & 0x1) << 3 return pkg_version - def get_chip_revision(self): - return self.get_major_chip_version() * 100 + self.get_minor_chip_version() - def get_minor_chip_version(self): return (self.read_efuse(5) >> 24) & 0x3 @@ -237,12 +228,12 @@ def get_chip_description(self): 5: "ESP32-PICO-V3" if rev3 else "ESP32-PICO-D4", 6: "ESP32-PICO-V3-02", 7: "ESP32-D0WDR2-V3", - }.get(pkg_version, "unknown ESP32") + }.get(pkg_version, "Unknown ESP32") return f"{chip_name} (revision v{major_rev}.{minor_rev})" def get_chip_features(self): - features = ["WiFi"] + features = ["Wi-Fi"] word3 = self.read_efuse(3) # names of variables in this section are lowercase @@ -255,9 +246,9 @@ def get_chip_features(self): chip_ver_dis_app_cpu = word3 & (1 << 0) if chip_ver_dis_app_cpu: - features += ["Single Core"] + features += ["Single Core + LP Core"] else: - features += ["Dual Core"] + features += ["Dual Core + LP Core"] chip_cpu_freq_rated = word3 & (1 << 13) if chip_cpu_freq_rated: @@ -277,7 +268,7 @@ def get_chip_features(self): word4 = self.read_efuse(4) adc_vref = (word4 >> 8) & 0x1F if adc_vref: - features += ["VRef calibration in efuse"] + features += ["Vref calibration in eFuse"] blk3_part_res = word3 >> 14 & 0x1 if blk3_part_res: @@ -315,9 +306,6 @@ def read_efuse(self, n): """Read the nth word of the ESP3x EFUSE region.""" return self.read_reg(self.EFUSE_RD_REG_BASE + (4 * n)) - def chip_id(self): - raise NotSupportedError(self, "Function chip_id") - def read_mac(self, mac_type="BASE_MAC"): """Read MAC from EFUSE region""" if mac_type != "BASE_MAC": @@ -330,7 +318,7 @@ def read_mac(self, mac_type="BASE_MAC"): def get_erase_size(self, offset, size): return size - def _get_efuse_flash_voltage(self) -> Optional[str]: + def _get_efuse_flash_voltage(self) -> str | None: efuse = self.read_reg(self.EFUSE_VDD_SPI_REG) # check efuse setting if efuse & (self.VDD_SPI_FORCE | self.VDD_SPI_XPD | self.VDD_SPI_TIEH): @@ -341,7 +329,7 @@ def _get_efuse_flash_voltage(self) -> Optional[str]: return "OFF" return None - def _get_rtc_cntl_flash_voltage(self) -> Optional[str]: + def _get_rtc_cntl_flash_voltage(self) -> str | None: reg = self.read_reg(self.RTC_CNTL_SDIO_CONF_REG) # check if override is set in RTC_CNTL_SDIO_CONF_REG if reg & self.RTC_CNTL_SDIO_FORCE: @@ -365,16 +353,18 @@ def get_flash_voltage(self): strap_reg &= self.GPIO_STRAP_VDDSPI_MASK voltage = "1.8V" if strap_reg else "3.3V" source = "a strapping pin" - print(f"Flash voltage set by {source} to {voltage}") + log.print(f"Flash voltage set by {source}: {voltage}") def override_vddsdio(self, new_voltage): new_voltage = new_voltage.upper() if new_voltage not in self.OVERRIDE_VDDSDIO_CHOICES: raise FatalError( - f"The only accepted VDDSDIO overrides are {', '.join(self.OVERRIDE_VDDSDIO_CHOICES)}" + "The only accepted VDDSDIO overrides are , ".join( + self.OVERRIDE_VDDSDIO_CHOICES + ) ) # RTC_CNTL_SDIO_TIEH is not used here, setting TIEH=1 would set 3.3V output, - # not safe for esptool.py to do + # not safe for esptool to do reg_val = self.RTC_CNTL_SDIO_FORCE # override efuse setting reg_val |= self.RTC_CNTL_SDIO_PD_EN @@ -387,7 +377,7 @@ def override_vddsdio(self, new_voltage): | self.RTC_CNTL_DREFL_SDIO_M ) # boost voltage self.write_reg(self.RTC_CNTL_SDIO_CONF_REG, reg_val) - print("VDDSDIO regulator set to %s" % new_voltage) + log.print(f"VDDSDIO regulator set to {new_voltage}.") def read_flash_slow(self, offset, length, progress_fn): BLOCK_LEN = 64 # ROM read limit per command (this limit is why it's so slow) @@ -398,24 +388,23 @@ def read_flash_slow(self, offset, length, progress_fn): try: r = self.check_command( "read flash block", - self.ESP_READ_FLASH_SLOW, + self.ESP_CMDS["READ_FLASH_SLOW"], struct.pack(" 33000000 else 26000000 false_rom_baud = int(baud * rom_calculated_freq // valid_freq) - print(f"Changing baud rate to {baud}") - self.command(self.ESP_CHANGE_BAUDRATE, struct.pack("> 16) & 0xF @@ -113,11 +119,12 @@ def change_baud(self, baud): # a 26 MHz XTAL. false_rom_baud = baud * 40 // 26 - print(f"Changing baud rate to {baud}") + log.print(f"Changing baud rate to {baud}...") self.command( - self.ESP_CHANGE_BAUDRATE, struct.pack("> self.PCR_SYSCLK_XTAL_FREQ_S def hard_reset(self): - print("Hard resetting via RTS pin...") - HardReset(self._port, self.uses_usb_jtag_serial())() + ESPLoader.hard_reset(self, self.uses_usb_jtag_serial()) def change_baud(self, baud): if not self.IS_STUB: crystal_freq_rom_expect = self.get_crystal_freq_rom_expect() crystal_freq_detect = self.get_crystal_freq() - print( - f"ROM expects crystal freq: {crystal_freq_rom_expect} MHz, detected {crystal_freq_detect} MHz" + log.print( + f"ROM expects crystal freq: {crystal_freq_rom_expect} MHz, " + f"detected {crystal_freq_detect} MHz." ) baud_rate = baud # If detect the XTAL is 48MHz, but the ROM code expects it to be 40MHz @@ -149,42 +157,59 @@ def change_baud(self, baud): ESPLoader.change_baud(self, baud_rate) return - print(f"Changing baud rate to {baud_rate}") - self.command(self.ESP_CHANGE_BAUDRATE, struct.pack(" self.EFUSE_MAX_KEY: + raise FatalError( + f"Valid key block numbers must be in range 0-{self.EFUSE_MAX_KEY}" + ) + + reg, shift = [ + (self.EFUSE_PURPOSE_KEY0_REG, self.EFUSE_PURPOSE_KEY0_SHIFT), + (self.EFUSE_PURPOSE_KEY1_REG, self.EFUSE_PURPOSE_KEY1_SHIFT), + (self.EFUSE_PURPOSE_KEY2_REG, self.EFUSE_PURPOSE_KEY2_SHIFT), + (self.EFUSE_PURPOSE_KEY3_REG, self.EFUSE_PURPOSE_KEY3_SHIFT), + (self.EFUSE_PURPOSE_KEY4_REG, self.EFUSE_PURPOSE_KEY4_SHIFT), + (self.EFUSE_PURPOSE_KEY5_REG, self.EFUSE_PURPOSE_KEY5_SHIFT), + ][key_block] + return (self.read_reg(reg) >> shift) & 0x1F + + def is_flash_encryption_key_valid(self): + # Need to see an AES-128 key + purposes = [ + self.get_key_block_purpose(b) for b in range(self.EFUSE_MAX_KEY + 1) + ] + + return any(p == self.PURPOSE_VAL_XTS_AES128_KEY for p in purposes) + def check_spi_connection(self, spi_connection): if not set(spi_connection).issubset(set(range(0, 29))): raise FatalError("SPI Pin numbers must be in the range 0-28.") if any([v for v in spi_connection if v in [13, 14]]): - print( - "WARNING: GPIO pins 13 and 14 are used by USB-Serial/JTAG, " + log.warning( + "GPIO pins 13 and 14 are used by USB-Serial/JTAG, " "consider using other pins for SPI flash connection." ) + def watchdog_reset(self): + # Watchdog reset disabled in parent (ESP32-C6) ROM, re-enable it + ESP32C3ROM.watchdog_reset(self) -class ESP32C5StubLoader(ESP32C5ROM): - """Access class for ESP32C5 stub loader, runs on top of ROM. - - (Basically the same as ESP32StubLoader, but different base class. - Can possibly be made into a mixin.) - """ - FLASH_WRITE_SIZE = 0x4000 # matches MAX_WRITE_BLOCK in stub_loader.c - STATUS_BYTES_LENGTH = 2 # same as ESP8266, different to ESP32 ROM - IS_STUB = True +class ESP32C5StubLoader(StubMixin, ESP32C5ROM): + """Stub loader for ESP32-C5, runs on top of ROM.""" - def __init__(self, rom_loader): - self.secure_download_mode = rom_loader.secure_download_mode - self._port = rom_loader._port - self._trace_enabled = rom_loader._trace_enabled - self.cache = rom_loader.cache - self.flush_input() # resets _slip_reader + pass ESP32C5ROM.STUB_CLASS = ESP32C5StubLoader diff --git a/tools/esptool_py/esptool/targets/esp32c5beta3.py b/tools/esptool_py/esptool/targets/esp32c5beta3.py deleted file mode 100644 index 66b09ce66b..0000000000 --- a/tools/esptool_py/esptool/targets/esp32c5beta3.py +++ /dev/null @@ -1,129 +0,0 @@ -# SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD -# -# SPDX-License-Identifier: GPL-2.0-or-later - -import struct -import time -from typing import Dict - -from .esp32c6 import ESP32C6ROM -from ..loader import ESPLoader - - -class ESP32C5BETA3ROM(ESP32C6ROM): - CHIP_NAME = "ESP32-C5(beta3)" - IMAGE_CHIP_ID = 17 - - IROM_MAP_START = 0x41000000 - IROM_MAP_END = 0x41800000 - DROM_MAP_START = 0x41000000 - DROM_MAP_END = 0x41800000 - - # Magic value for ESP32C5(beta3) - CHIP_DETECT_MAGIC_VALUE = [0xE10D8082] - - FLASH_FREQUENCY = { - "80m": 0xF, - "40m": 0x0, - "20m": 0x2, - } - - MEMORY_MAP = [ - [0x00000000, 0x00010000, "PADDING"], - [0x41800000, 0x42000000, "DROM"], - [0x40800000, 0x40880000, "DRAM"], - [0x40800000, 0x40880000, "BYTE_ACCESSIBLE"], - [0x4004A000, 0x40050000, "DROM_MASK"], - [0x40000000, 0x4004A000, "IROM_MASK"], - [0x41000000, 0x41800000, "IROM"], - [0x40800000, 0x40880000, "IRAM"], - [0x50000000, 0x50004000, "RTC_IRAM"], - [0x50000000, 0x50004000, "RTC_DRAM"], - [0x600FE000, 0x60100000, "MEM_INTERNAL2"], - ] - - EFUSE_MAX_KEY = 5 - KEY_PURPOSES: Dict[int, str] = { - 0: "USER/EMPTY", - 1: "ECDSA_KEY", - 2: "XTS_AES_256_KEY_1", - 3: "XTS_AES_256_KEY_2", - 4: "XTS_AES_128_KEY", - 5: "HMAC_DOWN_ALL", - 6: "HMAC_DOWN_JTAG", - 7: "HMAC_DOWN_DIGITAL_SIGNATURE", - 8: "HMAC_UP", - 9: "SECURE_BOOT_DIGEST0", - 10: "SECURE_BOOT_DIGEST1", - 11: "SECURE_BOOT_DIGEST2", - 12: "KM_INIT_KEY", - } - - def get_pkg_version(self): - num_word = 2 - return (self.read_reg(self.EFUSE_BLOCK1_ADDR + (4 * num_word)) >> 26) & 0x07 - - def get_minor_chip_version(self): - num_word = 2 - return (self.read_reg(self.EFUSE_BLOCK1_ADDR + (4 * num_word)) >> 0) & 0x0F - - def get_major_chip_version(self): - num_word = 2 - return (self.read_reg(self.EFUSE_BLOCK1_ADDR + (4 * num_word)) >> 4) & 0x03 - - def get_chip_description(self): - chip_name = { - 0: "ESP32-C5 beta3 (QFN40)", - }.get(self.get_pkg_version(), "unknown ESP32-C5 beta3") - major_rev = self.get_major_chip_version() - minor_rev = self.get_minor_chip_version() - return f"{chip_name} (revision v{major_rev}.{minor_rev})" - - def get_crystal_freq(self): - # The crystal detection algorithm of ESP32/ESP8266 - # works for ESP32-C5 beta3 as well. - return ESPLoader.get_crystal_freq(self) - - def change_baud(self, baud): - rom_with_48M_XTAL = not self.IS_STUB and self.get_crystal_freq() == 48 - if rom_with_48M_XTAL: - # The code is copied over from ESPLoader.change_baud(). - # Probably this is just a temporary solution until the next chip revision. - - # The ROM code thinks it uses a 40 MHz XTAL. Recompute the baud rate - # in order to trick the ROM code to set the correct baud rate for - # a 48 MHz XTAL. - false_rom_baud = baud * 40 // 48 - - print(f"Changing baud rate to {baud}") - self.command( - self.ESP_CHANGE_BAUDRATE, struct.pack(" self.EFUSE_MAX_KEY: raise FatalError( @@ -188,29 +186,21 @@ def check_spi_connection(self, spi_connection): if not set(spi_connection).issubset(set(range(0, 31))): raise FatalError("SPI Pin numbers must be in the range 0-30.") if any([v for v in spi_connection if v in [12, 13]]): - print( - "WARNING: GPIO pins 12 and 13 are used by USB-Serial/JTAG, " + log.warning( + "GPIO pins 12 and 13 are used by USB-Serial/JTAG, " "consider using other pins for SPI flash connection." ) + def watchdog_reset(self): + # Bug in the USB-Serial/JTAG controller can cause the port to disappear + # if watchdog reset happens, disable it on ESP32-C6 + ESPLoader.watchdog_reset(self) -class ESP32C6StubLoader(ESP32C6ROM): - """Access class for ESP32C6 stub loader, runs on top of ROM. - - (Basically the same as ESP32StubLoader, but different base class. - Can possibly be made into a mixin.) - """ - FLASH_WRITE_SIZE = 0x4000 # matches MAX_WRITE_BLOCK in stub_loader.c - STATUS_BYTES_LENGTH = 2 # same as ESP8266, different to ESP32 ROM - IS_STUB = True +class ESP32C6StubLoader(StubMixin, ESP32C6ROM): + """Stub loader for ESP32-C6, runs on top of ROM.""" - def __init__(self, rom_loader): - self.secure_download_mode = rom_loader.secure_download_mode - self._port = rom_loader._port - self._trace_enabled = rom_loader._trace_enabled - self.cache = rom_loader.cache - self.flush_input() # resets _slip_reader + pass ESP32C6ROM.STUB_CLASS = ESP32C6StubLoader diff --git a/tools/esptool_py/esptool/targets/esp32c61.py b/tools/esptool_py/esptool/targets/esp32c61.py index 2132bda3fd..18b7356af9 100644 --- a/tools/esptool_py/esptool/targets/esp32c61.py +++ b/tools/esptool_py/esptool/targets/esp32c61.py @@ -1,20 +1,19 @@ -# SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD +# SPDX-FileCopyrightText: 2024-2025 Fredrik Ahlberg, Angus Gratton, +# Espressif Systems (Shanghai) CO LTD, other contributors as noted. # # SPDX-License-Identifier: GPL-2.0-or-later import struct -from typing import Dict +from .esp32c3 import ESP32C3ROM from .esp32c6 import ESP32C6ROM +from ..loader import StubMixin class ESP32C61ROM(ESP32C6ROM): CHIP_NAME = "ESP32-C61" IMAGE_CHIP_ID = 20 - # Magic value for ESP32C61 - CHIP_DETECT_MAGIC_VALUE = [0x33F0206F, 0x2421606F] - UART_DATE_REG_ADDR = 0x60000000 + 0x7C EFUSE_BASE = 0x600B4800 @@ -53,12 +52,12 @@ class ESP32C61ROM(ESP32C6ROM): MEMORY_MAP = [ [0x00000000, 0x00010000, "PADDING"], - [0x41800000, 0x42000000, "DROM"], + [0x42000000, 0x44000000, "DROM"], [0x40800000, 0x40860000, "DRAM"], [0x40800000, 0x40860000, "BYTE_ACCESSIBLE"], [0x4004AC00, 0x40050000, "DROM_MASK"], [0x40000000, 0x4004AC00, "IROM_MASK"], - [0x41000000, 0x41800000, "IROM"], + [0x42000000, 0x44000000, "IROM"], [0x40800000, 0x40860000, "IRAM"], [0x50000000, 0x50004000, "RTC_IRAM"], [0x50000000, 0x50004000, "RTC_DRAM"], @@ -67,8 +66,7 @@ class ESP32C61ROM(ESP32C6ROM): UF2_FAMILY_ID = 0x77D850C4 - EFUSE_MAX_KEY = 5 - KEY_PURPOSES: Dict[int, str] = { + KEY_PURPOSES: dict[int, str] = { 0: "USER/EMPTY", 1: "ECDSA_KEY", 2: "XTS_AES_256_KEY_1", @@ -102,13 +100,13 @@ def get_major_chip_version(self): def get_chip_description(self): chip_name = { 0: "ESP32-C61", - }.get(self.get_pkg_version(), "unknown ESP32-C61") + }.get(self.get_pkg_version(), "Unknown ESP32-C61") major_rev = self.get_major_chip_version() minor_rev = self.get_minor_chip_version() return f"{chip_name} (revision v{major_rev}.{minor_rev})" def get_chip_features(self): - return ["WiFi 6", "BT 5"] + return ["Wi-Fi 6", "BT 5 (LE)", "Single Core", "160MHz"] def read_mac(self, mac_type="BASE_MAC"): """Read MAC from EFUSE region""" @@ -121,24 +119,15 @@ def read_mac(self, mac_type="BASE_MAC"): } return macs.get(mac_type, None) + def watchdog_reset(self): + # Watchdog reset disabled in parent (ESP32-C6) ROM, re-enable it + ESP32C3ROM.watchdog_reset(self) -class ESP32C61StubLoader(ESP32C61ROM): - """Access class for ESP32C61 stub loader, runs on top of ROM. - - (Basically the same as ESP32StubLoader, but different base class. - Can possibly be made into a mixin.) - """ - FLASH_WRITE_SIZE = 0x4000 # matches MAX_WRITE_BLOCK in stub_loader.c - STATUS_BYTES_LENGTH = 2 # same as ESP8266, different to ESP32 ROM - IS_STUB = True +class ESP32C61StubLoader(StubMixin, ESP32C61ROM): + """Stub loader for ESP32-C61, runs on top of ROM.""" - def __init__(self, rom_loader): - self.secure_download_mode = rom_loader.secure_download_mode - self._port = rom_loader._port - self._trace_enabled = rom_loader._trace_enabled - self.cache = rom_loader.cache - self.flush_input() # resets _slip_reader + pass ESP32C61ROM.STUB_CLASS = ESP32C61StubLoader diff --git a/tools/esptool_py/esptool/targets/esp32c6beta.py b/tools/esptool_py/esptool/targets/esp32c6beta.py deleted file mode 100644 index b6e100bb42..0000000000 --- a/tools/esptool_py/esptool/targets/esp32c6beta.py +++ /dev/null @@ -1,27 +0,0 @@ -# SPDX-FileCopyrightText: 2014-2022 Fredrik Ahlberg, Angus Gratton, -# Espressif Systems (Shanghai) CO LTD, other contributors as noted. -# -# SPDX-License-Identifier: GPL-2.0-or-later - -from .esp32c3 import ESP32C3ROM - - -class ESP32C6BETAROM(ESP32C3ROM): - CHIP_NAME = "ESP32-C6(beta)" - IMAGE_CHIP_ID = 7 - - CHIP_DETECT_MAGIC_VALUE = [0x0DA1806F] - - UART_DATE_REG_ADDR = 0x00000500 - - def get_chip_description(self): - chip_name = { - 0: "ESP32-C6 (QFN40)", - 1: "ESP32-C6FH4 (QFN32)", - }.get(self.get_pkg_version(), "unknown ESP32-C6") - major_rev = self.get_major_chip_version() - minor_rev = self.get_minor_chip_version() - return f"{chip_name} (revision v{major_rev}.{minor_rev})" - - def _post_connect(self): - pass diff --git a/tools/esptool_py/esptool/targets/esp32h2.py b/tools/esptool_py/esptool/targets/esp32h2.py index da7d34a589..a47583383d 100644 --- a/tools/esptool_py/esptool/targets/esp32h2.py +++ b/tools/esptool_py/esptool/targets/esp32h2.py @@ -1,11 +1,11 @@ -# SPDX-FileCopyrightText: 2022 Fredrik Ahlberg, Angus Gratton, +# SPDX-FileCopyrightText: 2024-2025 Fredrik Ahlberg, Angus Gratton, # Espressif Systems (Shanghai) CO LTD, other contributors as noted. # # SPDX-License-Identifier: GPL-2.0-or-later -from typing import Dict - from .esp32c6 import ESP32C6ROM +from ..loader import ESPLoader, StubMixin +from ..logger import log from ..util import FatalError @@ -13,11 +13,9 @@ class ESP32H2ROM(ESP32C6ROM): CHIP_NAME = "ESP32-H2" IMAGE_CHIP_ID = 16 - # Magic value for ESP32H2 - CHIP_DETECT_MAGIC_VALUE = [0xD7B73E80] - DR_REG_LP_WDT_BASE = 0x600B1C00 RTC_CNTL_WDTCONFIG0_REG = DR_REG_LP_WDT_BASE + 0x0 # LP_WDT_RWDT_CONFIG0_REG + RTC_CNTL_WDTCONFIG1_REG = DR_REG_LP_WDT_BASE + 0x0004 # LP_WDT_RWDT_CONFIG1_REG RTC_CNTL_WDTWPROTECT_REG = DR_REG_LP_WDT_BASE + 0x001C # LP_WDT_RWDT_WPROTECT_REG RTC_CNTL_SWD_CONF_REG = DR_REG_LP_WDT_BASE + 0x0020 # LP_WDT_SWD_CONFIG_REG @@ -25,6 +23,9 @@ class ESP32H2ROM(ESP32C6ROM): RTC_CNTL_SWD_WPROTECT_REG = DR_REG_LP_WDT_BASE + 0x0024 # LP_WDT_SWD_WPROTECT_REG RTC_CNTL_SWD_WKEY = 0x50D83AA1 # LP_WDT_SWD_WKEY, same as WDT key in this case + UARTDEV_BUF_NO = 0x4084FEFC # Variable in ROM .bss which indicates the port in use + UARTDEV_BUF_NO_USB_JTAG_SERIAL = 3 # The above var when USB-JTAG/Serial is used + FLASH_FREQUENCY = { "48m": 0xF, "24m": 0x0, @@ -34,8 +35,7 @@ class ESP32H2ROM(ESP32C6ROM): UF2_FAMILY_ID = 0x332726F6 - EFUSE_MAX_KEY = 5 - KEY_PURPOSES: Dict[int, str] = { + KEY_PURPOSES: dict[int, str] = { 0: "USER/EMPTY", 1: "ECDSA_KEY", 2: "XTS_AES_256_KEY_1", @@ -65,45 +65,36 @@ def get_major_chip_version(self): def get_chip_description(self): chip_name = { 0: "ESP32-H2", - }.get(self.get_pkg_version(), "unknown ESP32-H2") + }.get(self.get_pkg_version(), "Unknown ESP32-H2") major_rev = self.get_major_chip_version() minor_rev = self.get_minor_chip_version() return f"{chip_name} (revision v{major_rev}.{minor_rev})" def get_chip_features(self): - return ["BLE", "IEEE802.15.4"] + return ["BT 5 (LE)", "IEEE802.15.4", "Single Core", "96MHz"] def get_crystal_freq(self): # ESP32H2 XTAL is fixed to 32MHz return 32 + # Watchdog reset is not supported on ESP32-H2 + def watchdog_reset(self): + ESPLoader.watchdog_reset(self) + def check_spi_connection(self, spi_connection): if not set(spi_connection).issubset(set(range(0, 28))): raise FatalError("SPI Pin numbers must be in the range 0-27.") if any([v for v in spi_connection if v in [26, 27]]): - print( - "WARNING: GPIO pins 26 and 27 are used by USB-Serial/JTAG, " + log.warning( + "GPIO pins 26 and 27 are used by USB-Serial/JTAG, " "consider using other pins for SPI flash connection." ) -class ESP32H2StubLoader(ESP32H2ROM): - """Access class for ESP32H2 stub loader, runs on top of ROM. - - (Basically the same as ESP32StubLoader, but different base class. - Can possibly be made into a mixin.) - """ - - FLASH_WRITE_SIZE = 0x4000 # matches MAX_WRITE_BLOCK in stub_loader.c - STATUS_BYTES_LENGTH = 2 # same as ESP8266, different to ESP32 ROM - IS_STUB = True +class ESP32H2StubLoader(StubMixin, ESP32H2ROM): + """Stub loader for ESP32-H2, runs on top of ROM.""" - def __init__(self, rom_loader): - self.secure_download_mode = rom_loader.secure_download_mode - self._port = rom_loader._port - self._trace_enabled = rom_loader._trace_enabled - self.cache = rom_loader.cache - self.flush_input() # resets _slip_reader + pass ESP32H2ROM.STUB_CLASS = ESP32H2StubLoader diff --git a/tools/esptool_py/esptool/targets/esp32h21.py b/tools/esptool_py/esptool/targets/esp32h21.py new file mode 100644 index 0000000000..ad96920535 --- /dev/null +++ b/tools/esptool_py/esptool/targets/esp32h21.py @@ -0,0 +1,96 @@ +# SPDX-FileCopyrightText: 2024-2025 Fredrik Ahlberg, Angus Gratton, +# Espressif Systems (Shanghai) CO LTD, other contributors as noted. +# +# SPDX-License-Identifier: GPL-2.0-or-later + + +from .esp32h2 import ESP32H2ROM +from ..loader import StubMixin +from ..logger import log +from ..util import FatalError + + +class ESP32H21ROM(ESP32H2ROM): + CHIP_NAME = "ESP32-H21" + IMAGE_CHIP_ID = 25 + + UF2_FAMILY_ID = 0xB6DD00AF + + DR_REG_LP_WDT_BASE = 0x600B1C00 + RTC_CNTL_WDTCONFIG0_REG = DR_REG_LP_WDT_BASE + 0x0 # LP_WDT_RWDT_CONFIG0_REG + RTC_CNTL_WDTWPROTECT_REG = DR_REG_LP_WDT_BASE + 0x001C # LP_WDT_RWDT_WPROTECT_REG + + RTC_CNTL_SWD_CONF_REG = DR_REG_LP_WDT_BASE + 0x0020 # LP_WDT_SWD_CONFIG_REG + RTC_CNTL_SWD_AUTO_FEED_EN = 1 << 18 + RTC_CNTL_SWD_WPROTECT_REG = DR_REG_LP_WDT_BASE + 0x0024 # LP_WDT_SWD_WPROTECT_REG + RTC_CNTL_SWD_WKEY = 0x50D83AA1 # LP_WDT_SWD_WKEY, same as WDT key in this case + + EFUSE_BASE = 0x600B4000 + EFUSE_BLOCK1_ADDR = EFUSE_BASE + 0x044 + MAC_EFUSE_REG = EFUSE_BASE + 0x044 + + EFUSE_RD_REG_BASE = EFUSE_BASE + 0x030 # BLOCK0 read base address + + EFUSE_PURPOSE_KEY0_REG = EFUSE_BASE + 0x34 + EFUSE_PURPOSE_KEY0_SHIFT = 24 + EFUSE_PURPOSE_KEY1_REG = EFUSE_BASE + 0x34 + EFUSE_PURPOSE_KEY1_SHIFT = 28 + EFUSE_PURPOSE_KEY2_REG = EFUSE_BASE + 0x38 + EFUSE_PURPOSE_KEY2_SHIFT = 0 + EFUSE_PURPOSE_KEY3_REG = EFUSE_BASE + 0x38 + EFUSE_PURPOSE_KEY3_SHIFT = 4 + EFUSE_PURPOSE_KEY4_REG = EFUSE_BASE + 0x38 + EFUSE_PURPOSE_KEY4_SHIFT = 8 + EFUSE_PURPOSE_KEY5_REG = EFUSE_BASE + 0x38 + EFUSE_PURPOSE_KEY5_SHIFT = 12 + + EFUSE_DIS_DOWNLOAD_MANUAL_ENCRYPT_REG = EFUSE_RD_REG_BASE + EFUSE_DIS_DOWNLOAD_MANUAL_ENCRYPT = 1 << 20 + + EFUSE_SPI_BOOT_CRYPT_CNT_REG = EFUSE_BASE + 0x034 + EFUSE_SPI_BOOT_CRYPT_CNT_MASK = 0x7 << 18 + + EFUSE_SECURE_BOOT_EN_REG = EFUSE_BASE + 0x038 + EFUSE_SECURE_BOOT_EN_MASK = 1 << 20 + + def get_pkg_version(self): + return 0 + + def get_minor_chip_version(self): + return 0 + + def get_major_chip_version(self): + return 0 + + def get_chip_description(self): + chip_name = { + 0: "ESP32-H21", + }.get(self.get_pkg_version(), "Unknown ESP32-H21") + major_rev = self.get_major_chip_version() + minor_rev = self.get_minor_chip_version() + return f"{chip_name} (revision v{major_rev}.{minor_rev})" + + def get_chip_features(self): + return ["BT 5 (LE)", "IEEE802.15.4", "Single Core", "96MHz"] + + def get_crystal_freq(self): + # ESP32H21 XTAL is fixed to 32MHz + return 32 + + def check_spi_connection(self, spi_connection): + if not set(spi_connection).issubset(set(range(0, 28))): + raise FatalError("SPI Pin numbers must be in the range 0-27.") + if any([v for v in spi_connection if v in [26, 27]]): + log.warning( + "GPIO pins 26 and 27 are used by USB-Serial/JTAG, " + "consider using other pins for SPI flash connection." + ) + + +class ESP32H21StubLoader(StubMixin, ESP32H21ROM): + """Stub loader for ESP32-H21, runs on top of ROM.""" + + pass + + +ESP32H21ROM.STUB_CLASS = ESP32H21StubLoader diff --git a/tools/esptool_py/esptool/targets/esp32h2beta1.py b/tools/esptool_py/esptool/targets/esp32h2beta1.py deleted file mode 100644 index 999a16e08d..0000000000 --- a/tools/esptool_py/esptool/targets/esp32h2beta1.py +++ /dev/null @@ -1,186 +0,0 @@ -# SPDX-FileCopyrightText: 2014-2022 Fredrik Ahlberg, Angus Gratton, -# Espressif Systems (Shanghai) CO LTD, other contributors as noted. -# -# SPDX-License-Identifier: GPL-2.0-or-later - -import struct -from typing import Dict - -from .esp32c3 import ESP32C3ROM -from ..util import FatalError, NotImplementedInROMError - -from typing import List - - -class ESP32H2BETA1ROM(ESP32C3ROM): - CHIP_NAME = "ESP32-H2(beta1)" - IMAGE_CHIP_ID = 10 - - IROM_MAP_START = 0x42000000 - IROM_MAP_END = 0x42800000 - DROM_MAP_START = 0x3C000000 - DROM_MAP_END = 0x3C800000 - - SPI_REG_BASE = 0x60002000 - SPI_USR_OFFS = 0x18 - SPI_USR1_OFFS = 0x1C - SPI_USR2_OFFS = 0x20 - SPI_MOSI_DLEN_OFFS = 0x24 - SPI_MISO_DLEN_OFFS = 0x28 - SPI_W0_OFFS = 0x58 - - BOOTLOADER_FLASH_OFFSET = 0x0 - - CHIP_DETECT_MAGIC_VALUE = [0xCA26CC22] - - UART_DATE_REG_ADDR = 0x60000000 + 0x7C - - EFUSE_BASE = 0x6001A000 - EFUSE_BLOCK1_ADDR = EFUSE_BASE + 0x044 - MAC_EFUSE_REG = EFUSE_BASE + 0x044 - - EFUSE_RD_REG_BASE = EFUSE_BASE + 0x030 # BLOCK0 read base address - - EFUSE_PURPOSE_KEY0_REG = EFUSE_BASE + 0x34 - EFUSE_PURPOSE_KEY0_SHIFT = 24 - EFUSE_PURPOSE_KEY1_REG = EFUSE_BASE + 0x34 - EFUSE_PURPOSE_KEY1_SHIFT = 28 - EFUSE_PURPOSE_KEY2_REG = EFUSE_BASE + 0x38 - EFUSE_PURPOSE_KEY2_SHIFT = 0 - EFUSE_PURPOSE_KEY3_REG = EFUSE_BASE + 0x38 - EFUSE_PURPOSE_KEY3_SHIFT = 4 - EFUSE_PURPOSE_KEY4_REG = EFUSE_BASE + 0x38 - EFUSE_PURPOSE_KEY4_SHIFT = 8 - EFUSE_PURPOSE_KEY5_REG = EFUSE_BASE + 0x38 - EFUSE_PURPOSE_KEY5_SHIFT = 12 - - EFUSE_DIS_DOWNLOAD_MANUAL_ENCRYPT_REG = EFUSE_RD_REG_BASE - EFUSE_DIS_DOWNLOAD_MANUAL_ENCRYPT = 1 << 20 - - EFUSE_SPI_BOOT_CRYPT_CNT_REG = EFUSE_BASE + 0x034 - EFUSE_SPI_BOOT_CRYPT_CNT_MASK = 0x7 << 18 - - EFUSE_SECURE_BOOT_EN_REG = EFUSE_BASE + 0x038 - EFUSE_SECURE_BOOT_EN_MASK = 1 << 20 - - PURPOSE_VAL_XTS_AES128_KEY = 4 - - SUPPORTS_ENCRYPTED_FLASH = True - - FLASH_ENCRYPTED_WRITE_ALIGN = 16 - - MEMORY_MAP: List = [] - - FLASH_FREQUENCY = { - "48m": 0xF, - "24m": 0x0, - "16m": 0x1, - "12m": 0x2, - } - - EFUSE_MAX_KEY = 5 - KEY_PURPOSES: Dict[int, str] = { - 0: "USER/EMPTY", - 1: "ECDSA_KEY", - 2: "RESERVED", - 4: "XTS_AES_128_KEY", - 5: "HMAC_DOWN_ALL", - 6: "HMAC_DOWN_JTAG", - 7: "HMAC_DOWN_DIGITAL_SIGNATURE", - 8: "HMAC_UP", - 9: "SECURE_BOOT_DIGEST0", - 10: "SECURE_BOOT_DIGEST1", - 11: "SECURE_BOOT_DIGEST2", - } - - def get_pkg_version(self): - num_word = 4 - return (self.read_reg(self.EFUSE_BLOCK1_ADDR + (4 * num_word)) >> 0) & 0x07 - - def get_minor_chip_version(self): - num_word = 3 - return (self.read_reg(self.EFUSE_BLOCK1_ADDR + (4 * num_word)) >> 18) & 0x07 - - def get_major_chip_version(self): - num_word = 3 - return (self.read_reg(self.EFUSE_BLOCK1_ADDR + (4 * num_word)) >> 21) & 0x03 - - def get_chip_description(self): - chip_name = { - 0: "ESP32-H2", - }.get(self.get_pkg_version(), "unknown ESP32-H2") - major_rev = self.get_major_chip_version() - minor_rev = self.get_minor_chip_version() - return f"{chip_name} (revision v{major_rev}.{minor_rev})" - - def get_chip_features(self): - return ["BLE", "IEEE802.15.4"] - - def get_crystal_freq(self): - return 32 - - def override_vddsdio(self, new_voltage): - raise NotImplementedInROMError( - "VDD_SDIO overrides are not supported for ESP32-H2" - ) - - def read_mac(self, mac_type="BASE_MAC"): - """Read MAC from EFUSE region""" - if mac_type != "BASE_MAC": - return None - mac0 = self.read_reg(self.MAC_EFUSE_REG) - mac1 = self.read_reg(self.MAC_EFUSE_REG + 4) # only bottom 16 bits are MAC - bitstring = struct.pack(">II", mac1, mac0)[2:] - return tuple(bitstring) - - def get_flash_crypt_config(self): - return None # doesn't exist on ESP32-H2 - - def get_key_block_purpose(self, key_block): - if key_block < 0 or key_block > self.EFUSE_MAX_KEY: - raise FatalError( - f"Valid key block numbers must be in range 0-{self.EFUSE_MAX_KEY}" - ) - - reg, shift = [ - (self.EFUSE_PURPOSE_KEY0_REG, self.EFUSE_PURPOSE_KEY0_SHIFT), - (self.EFUSE_PURPOSE_KEY1_REG, self.EFUSE_PURPOSE_KEY1_SHIFT), - (self.EFUSE_PURPOSE_KEY2_REG, self.EFUSE_PURPOSE_KEY2_SHIFT), - (self.EFUSE_PURPOSE_KEY3_REG, self.EFUSE_PURPOSE_KEY3_SHIFT), - (self.EFUSE_PURPOSE_KEY4_REG, self.EFUSE_PURPOSE_KEY4_SHIFT), - (self.EFUSE_PURPOSE_KEY5_REG, self.EFUSE_PURPOSE_KEY5_SHIFT), - ][key_block] - return (self.read_reg(reg) >> shift) & 0xF - - def is_flash_encryption_key_valid(self): - # Need to see an AES-128 key - purposes = [ - self.get_key_block_purpose(b) for b in range(self.EFUSE_MAX_KEY + 1) - ] - - return any(p == self.PURPOSE_VAL_XTS_AES128_KEY for p in purposes) - - def _post_connect(self): - pass - - -class ESP32H2BETA1StubLoader(ESP32H2BETA1ROM): - """Access class for ESP32H2BETA1 stub loader, runs on top of ROM. - - (Basically the same as ESP32StubLoader, but different base class. - Can possibly be made into a mixin.) - """ - - FLASH_WRITE_SIZE = 0x4000 # matches MAX_WRITE_BLOCK in stub_loader.c - STATUS_BYTES_LENGTH = 2 # same as ESP8266, different to ESP32 ROM - IS_STUB = True - - def __init__(self, rom_loader): - self.secure_download_mode = rom_loader.secure_download_mode - self._port = rom_loader._port - self._trace_enabled = rom_loader._trace_enabled - self.cache = rom_loader.cache - self.flush_input() # resets _slip_reader - - -ESP32H2BETA1ROM.STUB_CLASS = ESP32H2BETA1StubLoader diff --git a/tools/esptool_py/esptool/targets/esp32h2beta2.py b/tools/esptool_py/esptool/targets/esp32h2beta2.py deleted file mode 100644 index 6fa8f587c7..0000000000 --- a/tools/esptool_py/esptool/targets/esp32h2beta2.py +++ /dev/null @@ -1,43 +0,0 @@ -# SPDX-FileCopyrightText: 2014-2022 Fredrik Ahlberg, Angus Gratton, -# Espressif Systems (Shanghai) CO LTD, other contributors as noted. -# -# SPDX-License-Identifier: GPL-2.0-or-later - -from .esp32h2beta1 import ESP32H2BETA1ROM - - -class ESP32H2BETA2ROM(ESP32H2BETA1ROM): - CHIP_NAME = "ESP32-H2(beta2)" - IMAGE_CHIP_ID = 14 - - CHIP_DETECT_MAGIC_VALUE = [0x6881B06F] - - def get_chip_description(self): - chip_name = { - 1: "ESP32-H2(beta2)", - }.get(self.get_pkg_version(), "unknown ESP32-H2") - major_rev = self.get_major_chip_version() - minor_rev = self.get_minor_chip_version() - return f"{chip_name} (revision v{major_rev}.{minor_rev})" - - -class ESP32H2BETA2StubLoader(ESP32H2BETA2ROM): - """Access class for ESP32H2BETA2 stub loader, runs on top of ROM. - - (Basically the same as ESP32StubLoader, but different base class. - Can possibly be made into a mixin.) - """ - - FLASH_WRITE_SIZE = 0x4000 # matches MAX_WRITE_BLOCK in stub_loader.c - STATUS_BYTES_LENGTH = 2 # same as ESP8266, different to ESP32 ROM - IS_STUB = True - - def __init__(self, rom_loader): - self.secure_download_mode = rom_loader.secure_download_mode - self._port = rom_loader._port - self._trace_enabled = rom_loader._trace_enabled - self.cache = rom_loader.cache - self.flush_input() # resets _slip_reader - - -ESP32H2BETA2ROM.STUB_CLASS = ESP32H2BETA2StubLoader diff --git a/tools/esptool_py/esptool/targets/esp32h4.py b/tools/esptool_py/esptool/targets/esp32h4.py new file mode 100644 index 0000000000..15edc4c3b1 --- /dev/null +++ b/tools/esptool_py/esptool/targets/esp32h4.py @@ -0,0 +1,201 @@ +# SPDX-FileCopyrightText: 2025 Fredrik Ahlberg, Angus Gratton, +# Espressif Systems (Shanghai) CO LTD, other contributors as noted. +# +# SPDX-License-Identifier: GPL-2.0-or-later + +import struct + +from .esp32c3 import ESP32C3ROM +from ..loader import ESPLoader, StubMixin +from ..logger import log +from ..util import FatalError + + +class ESP32H4ROM(ESP32C3ROM): + CHIP_NAME = "ESP32-H4" + IMAGE_CHIP_ID = 28 + + IROM_MAP_START = 0x42000000 + IROM_MAP_END = 0x42800000 + DROM_MAP_START = 0x42800000 + DROM_MAP_END = 0x43000000 + + BOOTLOADER_FLASH_OFFSET = 0x2000 + + SPI_REG_BASE = 0x60099000 + SPI_USR_OFFS = 0x18 + SPI_USR1_OFFS = 0x1C + SPI_USR2_OFFS = 0x20 + SPI_MOSI_DLEN_OFFS = 0x24 + SPI_MISO_DLEN_OFFS = 0x28 + SPI_W0_OFFS = 0x58 + + UART_DATE_REG_ADDR = 0x60012000 + 0x7C + + EFUSE_BASE = 0x600B1800 + EFUSE_BLOCK1_ADDR = EFUSE_BASE + 0x044 + MAC_EFUSE_REG = EFUSE_BASE + 0x044 + + EFUSE_RD_REG_BASE = EFUSE_BASE + 0x030 # BLOCK0 read base address + + EFUSE_PURPOSE_KEY0_REG = EFUSE_BASE + 0x34 + EFUSE_PURPOSE_KEY0_SHIFT = 0 + EFUSE_PURPOSE_KEY1_REG = EFUSE_BASE + 0x34 + EFUSE_PURPOSE_KEY1_SHIFT = 5 + EFUSE_PURPOSE_KEY2_REG = EFUSE_BASE + 0x34 + EFUSE_PURPOSE_KEY2_SHIFT = 10 + EFUSE_PURPOSE_KEY3_REG = EFUSE_BASE + 0x34 + EFUSE_PURPOSE_KEY3_SHIFT = 15 + EFUSE_PURPOSE_KEY4_REG = EFUSE_BASE + 0x34 + EFUSE_PURPOSE_KEY4_SHIFT = 20 + EFUSE_PURPOSE_KEY5_REG = EFUSE_BASE + 0x34 + EFUSE_PURPOSE_KEY5_SHIFT = 25 + + EFUSE_DIS_DOWNLOAD_MANUAL_ENCRYPT_REG = EFUSE_RD_REG_BASE + EFUSE_DIS_DOWNLOAD_MANUAL_ENCRYPT = 1 << 14 + + EFUSE_SPI_BOOT_CRYPT_CNT_REG = EFUSE_BASE + 0x030 + EFUSE_SPI_BOOT_CRYPT_CNT_MASK = 0x7 << 23 + + EFUSE_SECURE_BOOT_EN_REG = EFUSE_BASE + 0x038 + EFUSE_SECURE_BOOT_EN_MASK = 1 << 5 + + EFUSE_FORCE_USE_KM_KEY_REG = EFUSE_BASE + 0x038 + EFUSE_FORCE_USE_KM_KEY_MASK = 0xF << 19 + + PURPOSE_VAL_XTS_AES128_KEY = 4 + + SUPPORTS_ENCRYPTED_FLASH = True + + FLASH_ENCRYPTED_WRITE_ALIGN = 16 + + UARTDEV_BUF_NO = 0x4087F580 # Variable in ROM .bss which indicates the port in use + UARTDEV_BUF_NO_USB_JTAG_SERIAL = 3 # The above var when USB-JTAG/Serial is used + + DR_REG_LP_WDT_BASE = 0x600B5400 + RTC_CNTL_WDTCONFIG0_REG = DR_REG_LP_WDT_BASE + 0x0 # LP_WDT_RWDT_CONFIG0_REG + RTC_CNTL_WDTWPROTECT_REG = DR_REG_LP_WDT_BASE + 0x0018 # LP_WDT_RWDT_WPROTECT_REG + + RTC_CNTL_SWD_CONF_REG = DR_REG_LP_WDT_BASE + 0x001C # LP_WDT_SWD_CONFIG_REG + RTC_CNTL_SWD_AUTO_FEED_EN = 1 << 18 + RTC_CNTL_SWD_WPROTECT_REG = DR_REG_LP_WDT_BASE + 0x0020 # LP_WDT_SWD_WPROTECT_REG + RTC_CNTL_SWD_WKEY = 0x50D83AA1 # LP_WDT_SWD_WKEY, same as WDT key in this case + + PCR_SYSCLK_CONF_REG = 0x60096110 + PCR_SYSCLK_XTAL_FREQ_V = 0x7F << 24 + PCR_SYSCLK_XTAL_FREQ_S = 24 + + FLASH_FREQUENCY = { + "48m": 0x0, + "24m": 0x0, + "16m": 0x1, + "12m": 0x2, + } + + MEMORY_MAP = [ + [0x00000000, 0x00010000, "PADDING"], + [0x42800000, 0x43000000, "DROM"], + [0x40800000, 0x40880000, "DRAM"], + [0x40800000, 0x40880000, "BYTE_ACCESSIBLE"], + [0x4004AC00, 0x40050000, "DROM_MASK"], + [0x40000000, 0x4004AC00, "IROM_MASK"], + [0x42000000, 0x42800000, "IROM"], + [0x40800000, 0x40880000, "IRAM"], + [0x50000000, 0x50004000, "RTC_IRAM"], + [0x50000000, 0x50004000, "RTC_DRAM"], + [0x600FE000, 0x60100000, "MEM_INTERNAL2"], + ] + + UF2_FAMILY_ID = 0x9E0BAA8A + + # not alloc yet, return 0 + def get_pkg_version(self): + return 0 + + def get_minor_chip_version(self): + return 0 + + def get_major_chip_version(self): + return 0 + + def get_chip_description(self): + chip_name = { + 0: "ESP32-H4 (QFN40)", + }.get(self.get_pkg_version(), "Unknown ESP32-H4") + major_rev = self.get_major_chip_version() + minor_rev = self.get_minor_chip_version() + return f"{chip_name} (revision v{major_rev}.{minor_rev})" + + def get_chip_features(self): + return ["BT 5 (LE)", "IEEE802.15.4", "Dual Core", "96MHz"] + + def get_crystal_freq(self): + # ESP32H4 XTAL is fixed to 32MHz + return 32 + + def change_baud(self, baud): + ESPLoader.change_baud(self, baud) + + def read_mac(self, mac_type="BASE_MAC"): + """Read MAC from EFUSE region""" + mac0 = self.read_reg(self.MAC_EFUSE_REG) + mac1 = self.read_reg(self.MAC_EFUSE_REG + 4) # only bottom 16 bits are MAC + base_mac = struct.pack(">II", mac1, mac0)[2:] + ext_mac = struct.pack(">H", (mac1 >> 16) & 0xFFFF) + eui64 = base_mac[0:3] + ext_mac + base_mac[3:6] + # BASE MAC: 60:55:f9:f7:2c:a2 + # EUI64 MAC: 60:55:f9:ff:fe:f7:2c:a2 + # EXT_MAC: ff:fe + macs = { + "BASE_MAC": tuple(base_mac), + "EUI64": tuple(eui64), + "MAC_EXT": tuple(ext_mac), + } + return macs.get(mac_type, None) + + def get_flash_crypt_config(self): + return None # doesn't exist on ESP32-H4 + + def get_secure_boot_enabled(self): + return ( + self.read_reg(self.EFUSE_SECURE_BOOT_EN_REG) + & self.EFUSE_SECURE_BOOT_EN_MASK + ) + + def get_key_block_purpose(self, key_block): + if key_block < 0 or key_block > 5: + raise FatalError("Valid key block numbers must be in range 0-5") + + reg, shift = [ + (self.EFUSE_PURPOSE_KEY0_REG, self.EFUSE_PURPOSE_KEY0_SHIFT), + (self.EFUSE_PURPOSE_KEY1_REG, self.EFUSE_PURPOSE_KEY1_SHIFT), + (self.EFUSE_PURPOSE_KEY2_REG, self.EFUSE_PURPOSE_KEY2_SHIFT), + (self.EFUSE_PURPOSE_KEY3_REG, self.EFUSE_PURPOSE_KEY3_SHIFT), + (self.EFUSE_PURPOSE_KEY4_REG, self.EFUSE_PURPOSE_KEY4_SHIFT), + (self.EFUSE_PURPOSE_KEY5_REG, self.EFUSE_PURPOSE_KEY5_SHIFT), + ][key_block] + return (self.read_reg(reg) >> shift) & 0x1F + + def is_flash_encryption_key_valid(self): + # Need to see an AES-128 key + purposes = [self.get_key_block_purpose(b) for b in range(6)] + + return any(p == self.PURPOSE_VAL_XTS_AES128_KEY for p in purposes) + + def check_spi_connection(self, spi_connection): + if not set(spi_connection).issubset(set(range(0, 40))): + raise FatalError("SPI Pin numbers must be in the range 0-39.") + if any([v for v in spi_connection if v in [13, 14]]): + log.warning( + "GPIO pins 13 and 14 are used by USB-Serial/JTAG, " + "consider using other pins for SPI flash connection." + ) + + +class ESP32H4StubLoader(StubMixin, ESP32H4ROM): + """Stub loader for ESP32-H4, runs on top of ROM.""" + + pass + + +ESP32H4ROM.STUB_CLASS = ESP32H4StubLoader diff --git a/tools/esptool_py/esptool/targets/esp32p4.py b/tools/esptool_py/esptool/targets/esp32p4.py index 2b0a06498b..fbd839fa14 100644 --- a/tools/esptool_py/esptool/targets/esp32p4.py +++ b/tools/esptool_py/esptool/targets/esp32p4.py @@ -1,14 +1,15 @@ -# SPDX-FileCopyrightText: 2023 Fredrik Ahlberg, Angus Gratton, +# SPDX-FileCopyrightText: 2024-2025 Fredrik Ahlberg, Angus Gratton, # Espressif Systems (Shanghai) CO LTD, other contributors as noted. # # SPDX-License-Identifier: GPL-2.0-or-later import struct -from typing import Dict +from time import sleep from .esp32 import ESP32ROM -from ..loader import ESPLoader -from ..util import FatalError, NotImplementedInROMError +from ..loader import ESPLoader, StubMixin +from ..logger import log +from ..util import FatalError, NotSupportedError class ESP32P4ROM(ESP32ROM): @@ -22,8 +23,6 @@ class ESP32P4ROM(ESP32ROM): BOOTLOADER_FLASH_OFFSET = 0x2000 # First 2 sectors are reserved for FE purposes - CHIP_DETECT_MAGIC_VALUE = [0x0, 0x0ADDBAD0] - UART_DATE_REG_ADDR = 0x500CA000 + 0x8C EFUSE_BASE = 0x5012D000 @@ -40,6 +39,8 @@ class ESP32P4ROM(ESP32ROM): SPI_ADDR_REG_MSB = False + USES_MAGIC_VALUE = False + EFUSE_RD_REG_BASE = EFUSE_BASE + 0x030 # BLOCK0 read base address EFUSE_PURPOSE_KEY0_REG = EFUSE_BASE + 0x34 @@ -68,10 +69,21 @@ class ESP32P4ROM(ESP32ROM): PURPOSE_VAL_XTS_AES256_KEY_2 = 3 PURPOSE_VAL_XTS_AES128_KEY = 4 + USB_RAM_BLOCK = 0x800 # Max block size USB-OTG is used + + GPIO_STRAP_REG = 0x500E0038 + GPIO_STRAP_SPI_BOOT_MASK = 0x8 # Not download mode + RTC_CNTL_OPTION1_REG = 0x50110008 + RTC_CNTL_FORCE_DOWNLOAD_BOOT_MASK = 0x4 # Is download mode forced over USB? + SUPPORTS_ENCRYPTED_FLASH = True FLASH_ENCRYPTED_WRITE_ALIGN = 16 + UARTDEV_BUF_NO = 0x4FF3FEC8 # Variable in ROM .bss which indicates the port in use + UARTDEV_BUF_NO_USB_OTG = 5 # The above var when USB-OTG is used + UARTDEV_BUF_NO_USB_JTAG_SERIAL = 6 # The above var when USB-JTAG/Serial is used + MEMORY_MAP = [ [0x00000000, 0x00010000, "PADDING"], [0x40000000, 0x4C000000, "DROM"], @@ -88,8 +100,7 @@ class ESP32P4ROM(ESP32ROM): UF2_FAMILY_ID = 0x3D308E94 - EFUSE_MAX_KEY = 5 - KEY_PURPOSES: Dict[int, str] = { + KEY_PURPOSES: dict[int, str] = { 0: "USER/EMPTY", 1: "ECDSA_KEY", 2: "XTS_AES_256_KEY_1", @@ -105,6 +116,17 @@ class ESP32P4ROM(ESP32ROM): 12: "KM_INIT_KEY", } + DR_REG_LP_WDT_BASE = 0x50116000 + RTC_CNTL_WDTCONFIG0_REG = DR_REG_LP_WDT_BASE + 0x0 # LP_WDT_CONFIG0_REG + RTC_CNTL_WDTCONFIG1_REG = DR_REG_LP_WDT_BASE + 0x0004 # LP_WDT_CONFIG1_REG + RTC_CNTL_WDTWPROTECT_REG = DR_REG_LP_WDT_BASE + 0x0018 # LP_WDT_WPROTECT_REG + RTC_CNTL_WDT_WKEY = 0x50D83AA1 + + RTC_CNTL_SWD_CONF_REG = DR_REG_LP_WDT_BASE + 0x001C # RTC_WDT_SWD_CONFIG_REG + RTC_CNTL_SWD_AUTO_FEED_EN = 1 << 18 + RTC_CNTL_SWD_WPROTECT_REG = DR_REG_LP_WDT_BASE + 0x0020 # RTC_WDT_SWD_WPROTECT_REG + RTC_CNTL_SWD_WKEY = 0x50D83AA1 # RTC_WDT_SWD_WKEY, same as WDT key in this case + def get_pkg_version(self): num_word = 2 return (self.read_reg(self.EFUSE_BLOCK1_ADDR + (4 * num_word)) >> 20) & 0x07 @@ -115,30 +137,29 @@ def get_minor_chip_version(self): def get_major_chip_version(self): num_word = 2 - return (self.read_reg(self.EFUSE_BLOCK1_ADDR + (4 * num_word)) >> 4) & 0x03 + word = self.read_reg(self.EFUSE_BLOCK1_ADDR + (4 * num_word)) + return (((word >> 23) & 1) << 2) | ((word >> 4) & 0x03) def get_chip_description(self): chip_name = { 0: "ESP32-P4", - }.get(self.get_pkg_version(), "unknown ESP32-P4") + }.get(self.get_pkg_version(), "Unknown ESP32-P4") major_rev = self.get_major_chip_version() minor_rev = self.get_minor_chip_version() return f"{chip_name} (revision v{major_rev}.{minor_rev})" def get_chip_features(self): - return ["High-Performance MCU"] + return ["Dual Core + LP Core", "400MHz"] def get_crystal_freq(self): # ESP32P4 XTAL is fixed to 40MHz return 40 def get_flash_voltage(self): - pass # not supported on ESP32-P4 + raise NotSupportedError(self, "Reading flash voltage") def override_vddsdio(self, new_voltage): - raise NotImplementedInROMError( - "VDD_SDIO overrides are not supported for ESP32-P4" - ) + raise NotSupportedError(self, "Overriding VDDSDIO") def read_mac(self, mac_type="BASE_MAC"): """Read MAC from EFUSE region""" @@ -191,38 +212,79 @@ def change_baud(self, baud): ESPLoader.change_baud(self, baud) def _post_connect(self): - pass - # TODO: Disable watchdogs when USB modes are supported in the stub - # if not self.sync_stub_detected: # Don't run if stub is reused - # self.disable_watchdogs() + if self.uses_usb_otg(): + self.ESP_RAM_BLOCK = self.USB_RAM_BLOCK + if not self.sync_stub_detected: # Don't run if stub is reused + self.disable_watchdogs() + + def uses_usb_otg(self): + """ + Check the UARTDEV_BUF_NO register to see if USB-OTG console is being used + """ + if self.secure_download_mode: + return False # can't detect native USB in secure download mode + return self.get_uart_no() == self.UARTDEV_BUF_NO_USB_OTG + + def uses_usb_jtag_serial(self): + """ + Check the UARTDEV_BUF_NO register to see if USB-JTAG/Serial is being used + """ + if self.secure_download_mode: + return False # can't detect USB-JTAG/Serial in secure download mode + return self.get_uart_no() == self.UARTDEV_BUF_NO_USB_JTAG_SERIAL + + def disable_watchdogs(self): + # When USB-JTAG/Serial is used, the RTC WDT and SWD watchdog are not reset + # and can then reset the board during flashing. Disable them. + if self.uses_usb_jtag_serial(): + # Disable RTC WDT + self.write_reg(self.RTC_CNTL_WDTWPROTECT_REG, self.RTC_CNTL_SWD_WKEY) + self.write_reg(self.RTC_CNTL_WDTCONFIG0_REG, 0) + self.write_reg(self.RTC_CNTL_WDTWPROTECT_REG, 0) + + # Automatically feed SWD + self.write_reg(self.RTC_CNTL_SWD_WPROTECT_REG, self.RTC_CNTL_SWD_WKEY) + self.write_reg( + self.RTC_CNTL_SWD_CONF_REG, + self.read_reg(self.RTC_CNTL_SWD_CONF_REG) + | self.RTC_CNTL_SWD_AUTO_FEED_EN, + ) + self.write_reg(self.RTC_CNTL_SWD_WPROTECT_REG, 0) def check_spi_connection(self, spi_connection): if not set(spi_connection).issubset(set(range(0, 55))): raise FatalError("SPI Pin numbers must be in the range 0-54.") if any([v for v in spi_connection if v in [24, 25]]): - print( - "WARNING: GPIO pins 24 and 25 are used by USB-Serial/JTAG, " + log.warning( + "GPIO pins 24 and 25 are used by USB-Serial/JTAG, " "consider using other pins for SPI flash connection." ) + def watchdog_reset(self): + log.print("Hard resetting with a watchdog...") + self.write_reg(self.RTC_CNTL_WDTWPROTECT_REG, self.RTC_CNTL_WDT_WKEY) # unlock + self.write_reg(self.RTC_CNTL_WDTCONFIG1_REG, 2000) # set WDT timeout + self.write_reg( + self.RTC_CNTL_WDTCONFIG0_REG, (1 << 31) | (5 << 28) | (1 << 8) | 2 + ) # enable WDT + self.write_reg(self.RTC_CNTL_WDTWPROTECT_REG, 0) # lock + sleep(0.5) # wait for reset to take effect -class ESP32P4StubLoader(ESP32P4ROM): - """Access class for ESP32P4 stub loader, runs on top of ROM. + def hard_reset(self): + if self.uses_usb_otg(): + self.watchdog_reset() + else: + ESPLoader.hard_reset(self) - (Basically the same as ESP32StubLoader, but different base class. - Can possibly be made into a mixin.) - """ - FLASH_WRITE_SIZE = 0x4000 # matches MAX_WRITE_BLOCK in stub_loader.c - STATUS_BYTES_LENGTH = 2 # same as ESP8266, different to ESP32 ROM - IS_STUB = True +class ESP32P4StubLoader(StubMixin, ESP32P4ROM): + """Stub loader for ESP32-P4, runs on top of ROM.""" def __init__(self, rom_loader): - self.secure_download_mode = rom_loader.secure_download_mode - self._port = rom_loader._port - self._trace_enabled = rom_loader._trace_enabled - self.cache = rom_loader.cache - self.flush_input() # resets _slip_reader + super().__init__(rom_loader) # Initialize the mixin + if rom_loader.uses_usb_otg(): + self.ESP_RAM_BLOCK = self.USB_RAM_BLOCK + self.FLASH_WRITE_SIZE = self.USB_RAM_BLOCK ESP32P4ROM.STUB_CLASS = ESP32P4StubLoader diff --git a/tools/esptool_py/esptool/targets/esp32s2.py b/tools/esptool_py/esptool/targets/esp32s2.py index e16f532f09..dbc07921de 100644 --- a/tools/esptool_py/esptool/targets/esp32s2.py +++ b/tools/esptool_py/esptool/targets/esp32s2.py @@ -1,16 +1,15 @@ -# SPDX-FileCopyrightText: 2014-2023 Fredrik Ahlberg, Angus Gratton, +# SPDX-FileCopyrightText: 2014-2025 Fredrik Ahlberg, Angus Gratton, # Espressif Systems (Shanghai) CO LTD, other contributors as noted. # # SPDX-License-Identifier: GPL-2.0-or-later -import os import struct -from typing import Dict +from time import sleep from .esp32 import ESP32ROM -from ..loader import ESPLoader -from ..reset import HardReset -from ..util import FatalError, NotImplementedInROMError +from ..loader import ESPLoader, StubMixin +from ..logger import log +from ..util import FatalError, NotSupportedError class ESP32S2ROM(ESP32ROM): @@ -22,7 +21,7 @@ class ESP32S2ROM(ESP32ROM): DROM_MAP_START = 0x3F000000 DROM_MAP_END = 0x3F3F0000 - CHIP_DETECT_MAGIC_VALUE = [0x000007C6] + MAGIC_VALUE = 0x000007C6 SPI_REG_BASE = 0x3F402000 SPI_USR_OFFS = 0x18 @@ -83,11 +82,17 @@ class ESP32S2ROM(ESP32ROM): USB_RAM_BLOCK = 0x800 # Max block size USB-OTG is used GPIO_STRAP_REG = 0x3F404038 - GPIO_STRAP_SPI_BOOT_MASK = 0x8 # Not download mode + GPIO_STRAP_SPI_BOOT_MASK = 1 << 3 # Not download mode GPIO_STRAP_VDDSPI_MASK = 1 << 4 RTC_CNTL_OPTION1_REG = 0x3F408128 RTC_CNTL_FORCE_DOWNLOAD_BOOT_MASK = 0x1 # Is download mode forced over USB? + RTCCNTL_BASE_REG = 0x3F408000 + RTC_CNTL_WDTCONFIG0_REG = RTCCNTL_BASE_REG + 0x0094 + RTC_CNTL_WDTCONFIG1_REG = RTCCNTL_BASE_REG + 0x0098 + RTC_CNTL_WDTWPROTECT_REG = RTCCNTL_BASE_REG + 0x00AC + RTC_CNTL_WDT_WKEY = 0x50D83AA1 + MEMORY_MAP = [ [0x00000000, 0x00010000, "PADDING"], [0x3F000000, 0x3FF80000, "DROM"], @@ -110,8 +115,7 @@ class ESP32S2ROM(ESP32ROM): UF2_FAMILY_ID = 0xBFDD4EEE - EFUSE_MAX_KEY = 5 - KEY_PURPOSES: Dict[int, str] = { + KEY_PURPOSES: dict[int, str] = { 0: "USER/EMPTY", 1: "RESERVED", 2: "XTS_AES_256_KEY_1", @@ -169,17 +173,14 @@ def get_chip_description(self): 100: "ESP32-S2R2", }.get( self.get_flash_cap() + self.get_psram_cap() * 100, - "unknown ESP32-S2", + "Unknown ESP32-S2", ) major_rev = self.get_major_chip_version() minor_rev = self.get_minor_chip_version() return f"{chip_name} (revision v{major_rev}.{minor_rev})" def get_chip_features(self): - features = ["WiFi"] - - if self.secure_download_mode: - features += ["Secure Download Mode Enabled"] + features = ["Wi-Fi", "Single Core", "240MHz"] flash_version = { 0: "No Embedded Flash", @@ -197,9 +198,9 @@ def get_chip_features(self): block2_version = { 0: "No calibration in BLK2 of efuse", - 1: "ADC and temperature sensor calibration in BLK2 of efuse V1", - 2: "ADC and temperature sensor calibration in BLK2 of efuse V2", - }.get(self.get_block2_version(), "Unknown Calibration in BLK2") + 1: "ADC and temperature sensor calibration in BLK2 of eFuse V1", + 2: "ADC and temperature sensor calibration in BLK2 of eFuse V2", + }.get(self.get_block2_version(), "Unknown calibration in BLK2") features += [block2_version] return features @@ -212,9 +213,7 @@ def _get_rtc_cntl_flash_voltage(self): return None # not supported on ESP32-S2 def override_vddsdio(self, new_voltage): - raise NotImplementedInROMError( - "VDD_SDIO overrides are not supported for ESP32-S2" - ) + raise NotSupportedError(self, "Overriding VDDSDIO") def read_mac(self, mac_type="BASE_MAC"): """Read MAC from EFUSE region""" @@ -283,35 +282,30 @@ def _post_connect(self): if self.uses_usb_otg(): self.ESP_RAM_BLOCK = self.USB_RAM_BLOCK - def _check_if_can_reset(self): - """ - Check the strapping register to see if we can reset out of download mode. - """ - if os.getenv("ESPTOOL_TESTING") is not None: - print("ESPTOOL_TESTING is set, ignoring strapping mode check") - # Esptool tests over USB-OTG run with GPIO0 strapped low, - # don't complain in this case. - return - strap_reg = self.read_reg(self.GPIO_STRAP_REG) - force_dl_reg = self.read_reg(self.RTC_CNTL_OPTION1_REG) - if ( - strap_reg & self.GPIO_STRAP_SPI_BOOT_MASK == 0 - and force_dl_reg & self.RTC_CNTL_FORCE_DOWNLOAD_BOOT_MASK == 0 - ): - raise SystemExit( - f"Error: {self.get_chip_description()} chip was placed into download " - "mode using GPIO0.\nesptool.py can not exit the download mode over " - "USB. To run the app, reset the chip manually.\n" - "To suppress this note, set --after option to 'no_reset'." - ) + def watchdog_reset(self): + log.print("Hard resetting with a watchdog...") + self.write_reg(self.RTC_CNTL_WDTWPROTECT_REG, self.RTC_CNTL_WDT_WKEY) # unlock + self.write_reg(self.RTC_CNTL_WDTCONFIG1_REG, 2000) # set WDT timeout + self.write_reg( + self.RTC_CNTL_WDTCONFIG0_REG, (1 << 31) | (5 << 28) | (1 << 8) | 2 + ) # enable WDT + self.write_reg(self.RTC_CNTL_WDTWPROTECT_REG, 0) # lock + sleep(0.5) # wait for reset to take effect def hard_reset(self): uses_usb_otg = self.uses_usb_otg() if uses_usb_otg: - self._check_if_can_reset() - - print("Hard resetting via RTS pin...") - HardReset(self._port, uses_usb_otg)() + # Check the strapping register to see if we can perform a watchdog reset + strap_reg = self.read_reg(self.GPIO_STRAP_REG) + force_dl_reg = self.read_reg(self.RTC_CNTL_OPTION1_REG) + if ( + strap_reg & self.GPIO_STRAP_SPI_BOOT_MASK == 0 # GPIO0 low + and force_dl_reg & self.RTC_CNTL_FORCE_DOWNLOAD_BOOT_MASK == 0 + ): + self.watchdog_reset() + return + + ESPLoader.hard_reset(self, uses_usb_otg) def change_baud(self, baud): ESPLoader.change_baud(self, baud) @@ -320,30 +314,17 @@ def check_spi_connection(self, spi_connection): if not set(spi_connection).issubset(set(range(0, 22)) | set(range(26, 47))): raise FatalError("SPI Pin numbers must be in the range 0-21, or 26-46.") if any([v for v in spi_connection if v in [19, 20]]): - print( - "WARNING: GPIO pins 19 and 20 are used by USB-OTG, " + log.warning( + "GPIO pins 19 and 20 are used by USB-OTG, " "consider using other pins for SPI flash connection." ) -class ESP32S2StubLoader(ESP32S2ROM): - """Access class for ESP32-S2 stub loader, runs on top of ROM. - - (Basically the same as ESP32StubLoader, but different base class. - Can possibly be made into a mixin.) - """ - - FLASH_WRITE_SIZE = 0x4000 # matches MAX_WRITE_BLOCK in stub_loader.c - STATUS_BYTES_LENGTH = 2 # same as ESP8266, different to ESP32 ROM - IS_STUB = True +class ESP32S2StubLoader(StubMixin, ESP32S2ROM): + """Stub loader for ESP32-S2, runs on top of ROM.""" def __init__(self, rom_loader): - self.secure_download_mode = rom_loader.secure_download_mode - self._port = rom_loader._port - self._trace_enabled = rom_loader._trace_enabled - self.cache = rom_loader.cache - self.flush_input() # resets _slip_reader - + super().__init__(rom_loader) # Initialize the mixin if rom_loader.uses_usb_otg(): self.ESP_RAM_BLOCK = self.USB_RAM_BLOCK self.FLASH_WRITE_SIZE = self.USB_RAM_BLOCK diff --git a/tools/esptool_py/esptool/targets/esp32s3.py b/tools/esptool_py/esptool/targets/esp32s3.py index fb0f23a2f3..a8d6ea2394 100644 --- a/tools/esptool_py/esptool/targets/esp32s3.py +++ b/tools/esptool_py/esptool/targets/esp32s3.py @@ -1,16 +1,15 @@ -# SPDX-FileCopyrightText: 2014-2023 Fredrik Ahlberg, Angus Gratton, +# SPDX-FileCopyrightText: 2014-2025 Fredrik Ahlberg, Angus Gratton, # Espressif Systems (Shanghai) CO LTD, other contributors as noted. # # SPDX-License-Identifier: GPL-2.0-or-later -import os import struct -from typing import Dict +from time import sleep from .esp32 import ESP32ROM -from ..loader import ESPLoader -from ..reset import HardReset -from ..util import FatalError, NotImplementedInROMError +from ..loader import ESPLoader, StubMixin +from ..logger import log +from ..util import FatalError, NotSupportedError class ESP32S3ROM(ESP32ROM): @@ -18,8 +17,6 @@ class ESP32S3ROM(ESP32ROM): IMAGE_CHIP_ID = 9 - CHIP_DETECT_MAGIC_VALUE = [0x9] - IROM_MAP_START = 0x42000000 IROM_MAP_END = 0x44000000 DROM_MAP_START = 0x3C000000 @@ -37,6 +34,8 @@ class ESP32S3ROM(ESP32ROM): SPI_ADDR_REG_MSB = False + USES_MAGIC_VALUE = False + BOOTLOADER_FLASH_OFFSET = 0x0 SUPPORTS_ENCRYPTED_FLASH = True @@ -91,13 +90,14 @@ class ESP32S3ROM(ESP32ROM): RTC_CNTL_SWD_WKEY = 0x8F1D312A RTC_CNTL_WDTCONFIG0_REG = RTCCNTL_BASE_REG + 0x0098 + RTC_CNTL_WDTCONFIG1_REG = RTCCNTL_BASE_REG + 0x009C RTC_CNTL_WDTWPROTECT_REG = RTCCNTL_BASE_REG + 0x00B0 RTC_CNTL_WDT_WKEY = 0x50D83AA1 USB_RAM_BLOCK = 0x800 # Max block size USB-OTG is used GPIO_STRAP_REG = 0x60004038 - GPIO_STRAP_SPI_BOOT_MASK = 0x8 # Not download mode + GPIO_STRAP_SPI_BOOT_MASK = 1 << 3 # Not download mode GPIO_STRAP_VDDSPI_MASK = 1 << 4 RTC_CNTL_OPTION1_REG = 0x6000812C RTC_CNTL_FORCE_DOWNLOAD_BOOT_MASK = 0x1 # Is download mode forced over USB? @@ -126,8 +126,7 @@ class ESP32S3ROM(ESP32ROM): UF2_FAMILY_ID = 0xC47E5767 - EFUSE_MAX_KEY = 5 - KEY_PURPOSES: Dict[int, str] = { + KEY_PURPOSES: dict[int, str] = { 0: "USER/EMPTY", 1: "RESERVED", 2: "XTS_AES_256_KEY_1", @@ -195,7 +194,7 @@ def get_chip_description(self): chip_name = { 0: "ESP32-S3 (QFN56)", 1: "ESP32-S3-PICO-1 (LGA56)", - }.get(pkg_version, "unknown ESP32-S3") + }.get(pkg_version, "Unknown ESP32-S3") return f"{chip_name} (revision v{major_rev}.{minor_rev})" @@ -210,7 +209,12 @@ def get_flash_vendor(self): def get_psram_cap(self): num_word = 4 - return (self.read_reg(self.EFUSE_BLOCK1_ADDR + (4 * num_word)) >> 3) & 0x03 + psram_cap = (self.read_reg(self.EFUSE_BLOCK1_ADDR + (4 * num_word)) >> 3) & 0x03 + num_word = 5 + psram_cap_hi_bit = ( + self.read_reg(self.EFUSE_BLOCK1_ADDR + (4 * num_word)) >> 19 + ) & 0x01 + return (psram_cap_hi_bit << 2) | psram_cap def get_psram_vendor(self): num_word = 4 @@ -218,7 +222,7 @@ def get_psram_vendor(self): return {1: "AP_3v3", 2: "AP_1v8"}.get(vendor_id, "") def get_chip_features(self): - features = ["WiFi", "BLE"] + features = ["Wi-Fi", "BT 5 (LE)", "Dual Core + LP Core", "240MHz"] flash = { 0: None, @@ -232,6 +236,8 @@ def get_chip_features(self): 0: None, 1: "Embedded PSRAM 8MB", 2: "Embedded PSRAM 2MB", + 3: "Embedded PSRAM 16MB", + 4: "Embedded PSRAM 4MB", }.get(self.get_psram_cap(), "Unknown Embedded PSRAM") if psram is not None: features += [psram + f" ({self.get_psram_vendor()})"] @@ -284,9 +290,7 @@ def _get_rtc_cntl_flash_voltage(self): return None # not supported on ESP32-S3 def override_vddsdio(self, new_voltage): - raise NotImplementedInROMError( - "VDD_SDIO overrides are not supported for ESP32-S3" - ) + raise NotSupportedError(self, "Overriding VDDSDIO") def read_mac(self, mac_type="BASE_MAC"): """Read MAC from EFUSE region""" @@ -345,45 +349,41 @@ def _post_connect(self): if not self.sync_stub_detected: # Don't run if stub is reused self.disable_watchdogs() - def _check_if_can_reset(self): - """ - Check the strapping register to see if we can reset out of download mode. - """ - if os.getenv("ESPTOOL_TESTING") is not None: - print("ESPTOOL_TESTING is set, ignoring strapping mode check") - # Esptool tests over USB-OTG run with GPIO0 strapped low, - # don't complain in this case. - return - strap_reg = self.read_reg(self.GPIO_STRAP_REG) - force_dl_reg = self.read_reg(self.RTC_CNTL_OPTION1_REG) - if ( - strap_reg & self.GPIO_STRAP_SPI_BOOT_MASK == 0 - and force_dl_reg & self.RTC_CNTL_FORCE_DOWNLOAD_BOOT_MASK == 0 - ): - raise SystemExit( - f"Error: {self.get_chip_description()} chip was placed into download " - "mode using GPIO0.\nesptool.py can not exit the download mode over " - "USB. To run the app, reset the chip manually.\n" - "To suppress this note, set --after option to 'no_reset'." - ) + def watchdog_reset(self): + log.print("Hard resetting with a watchdog...") + self.write_reg(self.RTC_CNTL_WDTWPROTECT_REG, self.RTC_CNTL_WDT_WKEY) # unlock + self.write_reg(self.RTC_CNTL_WDTCONFIG1_REG, 2000) # set WDT timeout + self.write_reg( + self.RTC_CNTL_WDTCONFIG0_REG, (1 << 31) | (5 << 28) | (1 << 8) | 2 + ) # enable WDT + self.write_reg(self.RTC_CNTL_WDTWPROTECT_REG, 0) # lock + sleep(0.5) # wait for reset to take effect def hard_reset(self): - uses_usb_otg = self.uses_usb_otg() - if uses_usb_otg: - self._check_if_can_reset() - try: - # Clear force download boot mode to avoid the chip being stuck in download mode after reset - # workaround for issue: https://github.com/espressif/arduino-esp32/issues/6762 + # Clear force download boot mode to avoid chip being stuck in download mode + # after reset. Workaround for issue: + # https://github.com/espressif/arduino-esp32/issues/6762 self.write_reg( self.RTC_CNTL_OPTION1_REG, 0, self.RTC_CNTL_FORCE_DOWNLOAD_BOOT_MASK ) except Exception: - # Skip if response was not valid and proceed to reset; e.g. when monitoring while resetting + # Skip invalid response and continue reset (can happen when monitoring + # during reset) pass - - print("Hard resetting via RTS pin...") - HardReset(self._port, uses_usb_otg)() + uses_usb_otg = self.uses_usb_otg() + if uses_usb_otg: + # Check the strapping register to see if we can perform a watchdog reset + strap_reg = self.read_reg(self.GPIO_STRAP_REG) + force_dl_reg = self.read_reg(self.RTC_CNTL_OPTION1_REG) + if ( + strap_reg & self.GPIO_STRAP_SPI_BOOT_MASK == 0 # GPIO0 low + and force_dl_reg & self.RTC_CNTL_FORCE_DOWNLOAD_BOOT_MASK == 0 + ): + self.watchdog_reset() + return + + ESPLoader.hard_reset(self, uses_usb_otg) def change_baud(self, baud): ESPLoader.change_baud(self, baud) @@ -394,30 +394,17 @@ def check_spi_connection(self, spi_connection): if spi_connection[3] > 46: # hd_gpio_num must be <= SPI_GPIO_NUM_LIMIT (46) raise FatalError("SPI HD Pin number must be <= 46.") if any([v for v in spi_connection if v in [19, 20]]): - print( - "WARNING: GPIO pins 19 and 20 are used by USB-Serial/JTAG and USB-OTG, " + log.warning( + "GPIO pins 19 and 20 are used by USB-Serial/JTAG and USB-OTG, " "consider using other pins for SPI flash connection." ) -class ESP32S3StubLoader(ESP32S3ROM): - """Access class for ESP32S3 stub loader, runs on top of ROM. - - (Basically the same as ESP32StubLoader, but different base class. - Can possibly be made into a mixin.) - """ - - FLASH_WRITE_SIZE = 0x4000 # matches MAX_WRITE_BLOCK in stub_loader.c - STATUS_BYTES_LENGTH = 2 # same as ESP8266, different to ESP32 ROM - IS_STUB = True +class ESP32S3StubLoader(StubMixin, ESP32S3ROM): + """Stub loader for ESP32-S3, runs on top of ROM.""" def __init__(self, rom_loader): - self.secure_download_mode = rom_loader.secure_download_mode - self._port = rom_loader._port - self._trace_enabled = rom_loader._trace_enabled - self.cache = rom_loader.cache - self.flush_input() # resets _slip_reader - + super().__init__(rom_loader) # Initialize the mixin if rom_loader.uses_usb_otg(): self.ESP_RAM_BLOCK = self.USB_RAM_BLOCK self.FLASH_WRITE_SIZE = self.USB_RAM_BLOCK diff --git a/tools/esptool_py/esptool/targets/esp32s3beta2.py b/tools/esptool_py/esptool/targets/esp32s3beta2.py deleted file mode 100644 index f91bb3cb24..0000000000 --- a/tools/esptool_py/esptool/targets/esp32s3beta2.py +++ /dev/null @@ -1,37 +0,0 @@ -# SPDX-FileCopyrightText: 2014-2022 Fredrik Ahlberg, Angus Gratton, -# Espressif Systems (Shanghai) CO LTD, other contributors as noted. -# -# SPDX-License-Identifier: GPL-2.0-or-later - -from .esp32s3 import ESP32S3ROM - - -class ESP32S3BETA2ROM(ESP32S3ROM): - CHIP_NAME = "ESP32-S3(beta2)" - IMAGE_CHIP_ID = 4 - - CHIP_DETECT_MAGIC_VALUE = [0xEB004136] - - EFUSE_BASE = 0x6001A000 # BLOCK0 read base address - - -class ESP32S3BETA2StubLoader(ESP32S3BETA2ROM): - """Access class for ESP32S3 stub loader, runs on top of ROM. - - (Basically the same as ESP32StubLoader, but different base class. - Can possibly be made into a mixin.) - """ - - FLASH_WRITE_SIZE = 0x4000 # matches MAX_WRITE_BLOCK in stub_loader.c - STATUS_BYTES_LENGTH = 2 # same as ESP8266, different to ESP32 ROM - IS_STUB = True - - def __init__(self, rom_loader): - self.secure_download_mode = rom_loader.secure_download_mode - self._port = rom_loader._port - self._trace_enabled = rom_loader._trace_enabled - self.cache = rom_loader.cache - self.flush_input() # resets _slip_reader - - -ESP32S3BETA2ROM.STUB_CLASS = ESP32S3BETA2StubLoader diff --git a/tools/esptool_py/esptool/targets/esp8266.py b/tools/esptool_py/esptool/targets/esp8266.py index 9f8d7c17d5..31d278b266 100644 --- a/tools/esptool_py/esptool/targets/esp8266.py +++ b/tools/esptool_py/esptool/targets/esp8266.py @@ -1,19 +1,18 @@ -# SPDX-FileCopyrightText: 2014-2022 Fredrik Ahlberg, Angus Gratton, +# SPDX-FileCopyrightText: 2014-2025 Fredrik Ahlberg, Angus Gratton, # Espressif Systems (Shanghai) CO LTD, other contributors as noted. # # SPDX-License-Identifier: GPL-2.0-or-later -from ..loader import ESPLoader -from ..util import FatalError, NotSupportedError +from ..loader import ESPLoader, StubMixin +from ..util import FatalError class ESP8266ROM(ESPLoader): """Access class for ESP8266 ROM bootloader""" CHIP_NAME = "ESP8266" - IS_STUB = False - CHIP_DETECT_MAGIC_VALUE = [0xFFF0C101] + MAGIC_VALUE = 0xFFF0C101 # OTP ROM addresses ESP_OTP_MAC0 = 0x3FF00050 @@ -107,7 +106,7 @@ def get_chip_description(self): return "ESP8266EX" def get_chip_features(self): - features = ["WiFi"] + features = ["Wi-Fi", "160MHz"] if "ESP8285" in self.get_chip_description(): features += ["Embedded Flash"] return features @@ -169,31 +168,9 @@ def get_erase_size(self, offset, size): else: return (num_sectors - head_sectors) * sector_size - def get_flash_voltage(self): - pass # not supported on ESP8266 - def override_vddsdio(self, new_voltage): - raise NotSupportedError(self, "Overriding VDDSDIO") - - def check_spi_connection(self, spi_connection): - raise NotSupportedError(self, "Setting --spi-connection") - - def get_secure_boot_enabled(self): - return False # ESP8266 doesn't have security features - - -class ESP8266StubLoader(ESP8266ROM): - """Access class for ESP8266 stub loader, runs on top of ROM.""" - - FLASH_WRITE_SIZE = 0x4000 # matches MAX_WRITE_BLOCK in stub_loader.c - IS_STUB = True - - def __init__(self, rom_loader): - self.secure_download_mode = rom_loader.secure_download_mode - self._port = rom_loader._port - self._trace_enabled = rom_loader._trace_enabled - self.cache = rom_loader.cache - self.flush_input() # resets _slip_reader +class ESP8266StubLoader(StubMixin, ESP8266ROM): + """Stub loader for ESP8266, runs on top of ROM.""" def get_erase_size(self, offset, size): return size # stub doesn't have same size bug as ROM loader diff --git a/tools/esptool_py/esptool/targets/stub_flasher/1/README.md b/tools/esptool_py/esptool/targets/stub_flasher/1/README.md index 44e3ca3157..8284ab5177 100644 --- a/tools/esptool_py/esptool/targets/stub_flasher/1/README.md +++ b/tools/esptool_py/esptool/targets/stub_flasher/1/README.md @@ -1,3 +1,3 @@ # Licensing -The binaries in JSON format distributed in this directory are released as Free Software under GNU General Public License Version 2 or later. They were released at https://github.com/espressif/esptool-legacy-flasher-stub/releases/tag/v1.3.0 from where the sources can be obtained. +The binaries in JSON format distributed in this directory are released as Free Software under GNU General Public License Version 2 or later. They were released at https://github.com/espressif/esptool-legacy-flasher-stub/releases/tag/v1.6.0 from where the sources can be obtained. diff --git a/tools/esptool_py/esptool/targets/stub_flasher/1/esp32.json b/tools/esptool_py/esptool/targets/stub_flasher/1/esp32.json index 56221e30bd..f1e1d8d8c3 100644 --- a/tools/esptool_py/esptool/targets/stub_flasher/1/esp32.json +++ b/tools/esptool_py/esptool/targets/stub_flasher/1/esp32.json @@ -1,8 +1,8 @@ { - "entry": 1074521580, - "text": "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", + "entry": 1074521568, + "text": "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", "text_start": 1074520064, - "data": "DMD8P+znC0B/6AtAZ+0LQAbpC0Cf6AtABukLQGXpC0CC6gtA9OoLQJ3qC0CV5wtAGuoLQHTqC0CI6QtAGOsLQLDpC0AY6wtAbegLQMroC0AG6QtAZekLQIXoC0DI6wtAKe0LQLjmC0BL7QtAuOYLQLjmC0C45gtAuOYLQLjmC0C45gtAuOYLQLjmC0Bv6wtAuOYLQEnsC0Ap7QtA", + "data": "DMD8P93nC0Bz6AtAK+0LQPXoC0CW6AtA9egLQE7pC0BT6gtAyeoLQG7qC0CJ5wtA/+kLQEjqC0Bs6QtA6uoLQJTpC0Dq6gtAaugLQLvoC0D16AtATukLQHzoC0Cc6wtA7+wLQKrmC0AP7QtAquYLQKrmC0Cq5gtAquYLQKrmC0Cq5gtAquYLQKrmC0BL6wtAquYLQB7sC0Dv7AtA", "data_start": 1073605544, "bss_start": 1073528832 } \ No newline at end of file diff --git a/tools/esptool_py/esptool/targets/stub_flasher/1/esp32c2.json b/tools/esptool_py/esptool/targets/stub_flasher/1/esp32c2.json index f10ec7b48e..6a7ba77d33 100644 --- a/tools/esptool_py/esptool/targets/stub_flasher/1/esp32c2.json +++ b/tools/esptool_py/esptool/targets/stub_flasher/1/esp32c2.json @@ -1,8 +1,8 @@ { - "entry": 1077413304, - "text": "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", + "entry": 1077413160, + "text": "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", "text_start": 1077411840, - "data": "DEDKP+AIOEAsCThAhAk4QFIKOEC+CjhAbAo4QKgHOEAOCjhATgo4QJgJOEBYBzhAzAk4QFgHOEC6CDhA/gg4QCwJOECECThAzAg4QBIIOEBCCDhAyAg4QBYNOEAsCThA1gs4QMoMOECkBjhA9Aw4QKQGOECkBjhApAY4QKQGOECkBjhApAY4QKQGOECkBjhAcgs4QKQGOEDyCzhAygw4QA==", + "data": "DEDKPygIOECACDhAEAk4QPIJOEBeCjhADAo4QBAHOECuCThA7gk4QCwJOEDABjhAYAk4QMAGOEACCDhARgg4QIAIOEAQCThAFAg4QD4HOEByBzhAEAg4QLQMOECACDhAeAs4QGgMOEAMBjhAkgw4QAwGOEAMBjhADAY4QAwGOEAMBjhADAY4QAwGOEAMBjhAFAs4QAwGOECUCzhAaAw4QA==", "data_start": 1070295976, "bss_start": 1070219264 } \ No newline at end of file diff --git a/tools/esptool_py/esptool/targets/stub_flasher/1/esp32c3.json b/tools/esptool_py/esptool/targets/stub_flasher/1/esp32c3.json index 788ae646df..5c1aeebf57 100644 --- a/tools/esptool_py/esptool/targets/stub_flasher/1/esp32c3.json +++ b/tools/esptool_py/esptool/targets/stub_flasher/1/esp32c3.json @@ -1,8 +1,8 @@ { - "entry": 1077413584, - "text": "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", + "entry": 1077413408, + "text": "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", "text_start": 1077411840, - "data": "GEDIP8AKOEAQCzhAaAs4QDYMOECiDDhAUAw4QHIJOEDyCzhAMgw4QHwLOEAiCThAsAs4QCIJOECaCjhA4Ao4QBALOEBoCzhArAo4QNYJOEAgCjhAqAo4QPoOOEAQCzhAug04QLIOOEBiCDhA2g44QGIIOEBiCDhAYgg4QGIIOEBiCDhAYgg4QGIIOEBiCDhAVg04QGIIOEDYDThAsg44QA==", + "data": "GEDIP+gJOEBECjhA1Ao4QLYLOEAiDDhA0As4QLwIOEByCzhAsgs4QPAKOEBsCDhAJAs4QGwIOEDCCThACAo4QEQKOEDUCjhA1Ak4QOQIOEAwCThA0Ak4QHYOOEBECjhAPA04QC4OOECsBzhAVg44QKwHOECsBzhArAc4QKwHOECsBzhArAc4QKwHOECsBzhA2Aw4QKwHOEBaDThALg44QA==", "data_start": 1070164916, "bss_start": 1070088192 } \ No newline at end of file diff --git a/tools/esptool_py/esptool/targets/stub_flasher/1/esp32c5.json b/tools/esptool_py/esptool/targets/stub_flasher/1/esp32c5.json index 871a95d5e1..b9e8069097 100644 --- a/tools/esptool_py/esptool/targets/stub_flasher/1/esp32c5.json +++ b/tools/esptool_py/esptool/targets/stub_flasher/1/esp32c5.json @@ -1,8 +1,8 @@ { - "entry": 1082132164, - "text": "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", + "entry": 1082131984, + "text": "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", "text_start": 1082130432, - "data": "FACEQG4KgEC+CoBAFguAQOQLgEBQDIBA/guAQDoJgECgC4BA4AuAQCoLgEDqCIBAXguAQOoIgEBICoBAjgqAQL4KgEAWC4BAWgqAQJ4JgEDOCYBAVgqAQKgOgEC+CoBAaA2AQGAOgEAqCIBAiA6AQCoIgEAqCIBAKgiAQCoIgEAqCIBAKgiAQCoIgEAqCIBABA2AQCoIgECGDYBAYA6AQA==", + "data": "FACEQJAJgEDsCYBAfAqAQF4LgEDKC4BAeAuAQH4IgEAaC4BAWguAQJgKgEAuCIBAzAqAQC4IgEBqCYBAsAmAQOwJgEB8CoBAfAmAQKYIgEDaCIBAeAmAQB4OgEDsCYBA5AyAQNYNgEBuB4BA/g2AQG4HgEBuB4BAbgeAQG4HgEBuB4BAbgeAQG4HgEBuB4BAgAyAQG4HgEACDYBA1g2AQA==", "data_start": 1082469296, "bss_start": 1082392576 } \ No newline at end of file diff --git a/tools/esptool_py/esptool/targets/stub_flasher/1/esp32c5beta3.json b/tools/esptool_py/esptool/targets/stub_flasher/1/esp32c5beta3.json deleted file mode 100644 index c41e549ca9..0000000000 --- a/tools/esptool_py/esptool/targets/stub_flasher/1/esp32c5beta3.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "entry": 1082131910, - "text": "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", - "text_start": 1082130432, - "data": "DACEQO4IgEA6CYBAkgmAQGAKgEDMCoBAegqAQLYHgEAcCoBAXAqAQKYJgEBmB4BA2gmAQGYHgEDICIBADAmAQDoJgECSCYBA2giAQCAIgEBQCIBA1giAQCQNgEA6CYBA5AuAQNgMgECyBoBAAg2AQLIGgECyBoBAsgaAQLIGgECyBoBAsgaAQLIGgECyBoBAgAuAQLIGgEAADIBA2AyAQA==", - "data_start": 1082469288, - "bss_start": 1082392576 -} \ No newline at end of file diff --git a/tools/esptool_py/esptool/targets/stub_flasher/1/esp32c6.json b/tools/esptool_py/esptool/targets/stub_flasher/1/esp32c6.json index b903b35215..ff82d3e5ab 100644 --- a/tools/esptool_py/esptool/targets/stub_flasher/1/esp32c6.json +++ b/tools/esptool_py/esptool/targets/stub_flasher/1/esp32c6.json @@ -1,8 +1,8 @@ { - "entry": 1082132164, - "text": "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", + "entry": 1082131984, + "text": "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", "text_start": 1082130432, - "data": "FACEQHIKgEDCCoBAGguAQOgLgEBUDIBAAgyAQD4JgECkC4BA5AuAQC4LgEDuCIBAYguAQO4IgEBMCoBAkgqAQMIKgEAaC4BAXgqAQKIJgEDSCYBAWgqAQKwOgEDCCoBAbA2AQGQOgEAuCIBAjA6AQC4IgEAuCIBALgiAQC4IgEAuCIBALgiAQC4IgEAuCIBACA2AQC4IgECKDYBAZA6AQA==", + "data": "FACEQJIJgEDuCYBAfgqAQGALgEDMC4BAeguAQIAIgEAcC4BAXAuAQJoKgEAwCIBAzgqAQDAIgEBsCYBAsgmAQO4JgEB+CoBAfgmAQKgIgEDcCIBAegmAQCAOgEDuCYBA5gyAQNgNgEBwB4BAAA6AQHAHgEBwB4BAcAeAQHAHgEBwB4BAcAeAQHAHgEBwB4BAggyAQHAHgEAEDYBA2A2AQA==", "data_start": 1082469296, "bss_start": 1082392576 } \ No newline at end of file diff --git a/tools/esptool_py/esptool/targets/stub_flasher/1/esp32c61.json b/tools/esptool_py/esptool/targets/stub_flasher/1/esp32c61.json index 2a95414c8d..354ce70118 100644 --- a/tools/esptool_py/esptool/targets/stub_flasher/1/esp32c61.json +++ b/tools/esptool_py/esptool/targets/stub_flasher/1/esp32c61.json @@ -1,8 +1,8 @@ { - "entry": 1082132164, - "text": "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", + "entry": 1082131984, + "text": "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", "text_start": 1082130432, - "data": "FECAQHQKgEDECoBAHAuAQOoLgEBWDIBABAyAQEAJgECmC4BA5guAQDALgEDwCIBAZAuAQPAIgEBOCoBAlAqAQMQKgEAcC4BAYAqAQKQJgEDUCYBAXAqAQK4OgEDECoBAbg2AQGYOgEAwCIBAjg6AQDAIgEAwCIBAMAiAQDAIgEAwCIBAMAiAQDAIgEAwCIBACg2AQDAIgECMDYBAZg6AQA==", + "data": "FECAQJYJgEDyCYBAggqAQGQLgEDQC4BAfguAQIQIgEAgC4BAYAuAQJ4KgEA0CIBA0gqAQDQIgEBwCYBAtgmAQPIJgECCCoBAggmAQKwIgEDgCIBAfgmAQCQOgEDyCYBA6gyAQNwNgEB0B4BABA6AQHQHgEB0B4BAdAeAQHQHgEB0B4BAdAeAQHQHgEB0B4BAhgyAQHQHgEAIDYBA3A2AQA==", "data_start": 1082223536, "bss_start": 1082146816 } \ No newline at end of file diff --git a/tools/esptool_py/esptool/targets/stub_flasher/1/esp32c6beta.json b/tools/esptool_py/esptool/targets/stub_flasher/1/esp32c6beta.json deleted file mode 100644 index 7fd5c0ec6c..0000000000 --- a/tools/esptool_py/esptool/targets/stub_flasher/1/esp32c6beta.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "entry": 1077413318, - "text": "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", - "text_start": 1077411840, - "data": "DEDIP/gIOEBECThAnAk4QGoKOEDWCjhAhAo4QMAHOEAmCjhAZgo4QLAJOEBwBzhA5Ak4QHAHOEDSCDhAFgk4QEQJOECcCThA5Ag4QCoIOEBaCDhA4Ag4QC4NOEBECThA7gs4QOIMOEC8BjhADA04QLwGOEC8BjhAvAY4QLwGOEC8BjhAvAY4QLwGOEC8BjhAigs4QLwGOEAKDDhA4gw4QA==", - "data_start": 1070164904, - "bss_start": 1070088192 -} \ No newline at end of file diff --git a/tools/esptool_py/esptool/targets/stub_flasher/1/esp32h2.json b/tools/esptool_py/esptool/targets/stub_flasher/1/esp32h2.json index 24964cde64..66c4998911 100644 --- a/tools/esptool_py/esptool/targets/stub_flasher/1/esp32h2.json +++ b/tools/esptool_py/esptool/targets/stub_flasher/1/esp32h2.json @@ -1,8 +1,8 @@ { - "entry": 1082132164, - "text": "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", + "entry": 1082131984, + "text": "QRG39wBgIsQmwkrAEUcGxrcEg0DYyz6JM4TnAJOEBAAcQJGLmeeyQCJEkkQCSUEBgoADJQkAnEATdfUPgpfNtwERtwcAYE7Gg6mHAErINwmDQCbKUsQGziLMk4THAT6KEwkJAIBAE3T0DxnIAyUKAIMnCQB9FBN19Q+Cl2X43bfyQGJEtwcAYCOoNwHSREJJskkiSgVhgoCTBwAMkEEqh2MY9QCFRwXGI6AFAHlVgoCFRmMH1gAJRWMNpgB9VYKAQgWTB7ANQYVjE/cCiUecwfW3EwbADWMVxwCUwT6FgoCTB9AN4xz3/JTBEwWwDYKAtzWEQEERk4WFugbGcT9jTQUEtzeEQJOHB7IDpwcIg9ZHCBOGFgAjkscINpcjAKcAA9dHCJFnk4cHBGMa9wI3t4NAEwcHsqFnupcDpgcIt/aDQJOGBrZjH+YAI6bHCCOg1wgjkgcIIaD5V+MK9fyyQEEBgoAjptcII6DnCN23NzcAYBMHRwUcQ52L9f83JwBgEwdHBRxDnYv1/4KAQREGxvk/NzcAYLcGAAgjJgcCkwfHAhTDFEP9/ohDskATRfX/BYlBAYKAQREGxsk/fd23NwBgNwcAQJjDmEN9/7JAQQGCgEERJsK3hINAk4REAUrAA6kEAQbGIsRjCQkERTcxxb1HAURj1icBgER9jBM0FABdP7U3mES3BwABPoaTFscAGcA3BoAA/Rf1j7c2AGDcwpDCnEL9/5MH9P/Fm8EHMwn5QD6XI6gkAZjEskAiRJJEAklBAYKAAREGzhU3NwWFQGwAQRWXAID/54CA8qqHBUWd57JHk/cHID7GsTe3NwBgmEe3BkAANwWFQFWPmMeyRUEVlwCA/+eA4O8zNaAA8kAFYYKAQRG3h4NABsaTh0cBBUcjgOcAE9fFAJjHBWd9F8zDyMf5jTqVqpWxgYzLI6oHAFE3GcETBVAMskBBAYKAAREizDeEg0ATBEQBJspERAbOSshOxmPzlQCuhLHAAylEAKqJJpkTWckAHEhjVfAAHERjXvkCWTV93UhAJobOhZcAgP/ngEDjE3X1DwHFkwdADFzIXECml1zAXESFj1zE8kBiRNJEQkmySQVhgoBRPW2/QREGxpcAgP/ngODWA0WFAbJAdRUTNRUAQQGCgEERBsbFNw3FtweDQJOHBwDUQ5nON2cJYBMHxxAcQzcG/f99FvGPNwYDAPGO1Y8cw7JAQQGCgEERBsZtNxHBDUWyQEEBFwOA/2cAI81BEQbGJsIixKqElwCA/+eAgMpZNw3FNwSDQBMEBACDV4QAhQfCB8GDIxT0AJO39wOBx5OHBPSB500/IxQEALJAIkSSREEBgoBBEQbGEwcADGMa5QATBbANZTcTBcANskBBAXm/EwewDeMb5f5RPxMF0A31t0ERIsQmwgbGKoSzBLUAYxeUALJAIkSSREEBgoADRQQABQRNP+23dXEixSbD0twGx0rBzt4TAQGAEwEBgKqEKAguhAVqlwCA/+eAYCsN5CgALAiXAID/54AAKygAwUVNNwFFhWIWkbpAKkSaRApJ9llmWklhgoAiiWNzigAFaUqGjBgmhZcAgP/ngGDKE3X1DwHtSoaMGCgIlwCA/+eAYCbKlDMEJEFdtxMFMAZdvxMFAAzpvTVxIs1Ox1LFVsPe3gbPJstKyVrBEwEBgBMBAYCqiS6Ksoq2iwLCqTWAGLcHAgAZ4ZMHAAI+hZcAgP/ngEAghWdj4lcPKAiXAID/54AAIAFJAytE+WNiaQtjYUsDcahxP6aFIoXlNVE/JoaihSgIlwCA/+eAwB2mmSaZY3VJA7MHaUFj8XcDswQqQWPzmgDWhCaGooVOhZcAgP/ngAC+E3X1D1XdIywE+IFEeVujCQT4EwUxAJcAgP/ngKCtdfkDRTT5LAAJNpMXBQFjwgcCk7dEAJHPhWeThwcHppeKl5OHB4CThweAI4qn+IUEwbfjH2X7kUfjjvT0KAAsCJcAgP/ngCAV3T3BRSgAiTX9NY0zkwcAAhnBtwcCAD6FlwCA/+eAIBKFYhaR+kBqRNpESkm6SSpKmkoKS/ZbDWGCgLdXQUkZcZOH94QBRYbeotym2srYztbS1NbS2tDezuLM5srqyO7GPs6XAID/54DAqAkzDcE3ZwlgEwfHEBxDtwaDQCOi9gC3Bv3//Rb1j8Fm1Y8cw/k5Bc23JwtgN0fYUJOHx8ETBxeqmMO3JgtgI6AGwCOgBwCTh0bCmMMThwbCFEM3BgQA0Y4UwyOgBwC3B4NANzeEQJOHBwATBwe7IaAjoAcAkQfj7ef+CT2RRWgIuTspNbe3g0CThweyoWm+mSOg+Qg3CYNAtweAQBMJCQCThwcPIyD5AKk5YwQFELcHAWBFRSOqpwiFRZcAgP/ngKD+twWAQAFGk4UFAEVFlwCA/+eAoP+39wBgEUeYyzcFAgCXAID/54Dg/rcXCWCIX4FFt4SDQHGJYRUTNRUAlwCA/+eAYKlBZpMH9v8TBwAQhWa3BQABAUWThEQBtzqEQA1qlwCA/+eAYJ+TigrBJpqDp8kI9d8Dq8kIhUcjpgkIIwLxAoNHGwAJRyMT4QKjAvECAtRNR2OB5whRR2OP5wYpR2Of5wCDRzsAA0crAKIH2Y8RR2OW5wCDJ4sAnEM+1DEzoUVIEKE5g0c7AANHKwCiB9mPEWdBB2N09wQTBbAN6TYTBcAN0TYTBeAOfT75OUG3twWAQAFGk4UFBBVFlwCA/+eAoPC3BwBg2EcTBQACE2cXENjHMbfJRyMT8QJNtwNHGwDRRmPn5gKFRmPm5gCBSxME8A8RpHkXE3f3D8lG4+jm/rc2hEAKB5OGRrs2lxhDAoeTBgcDk/b2DxFG42nW/BMH9wITd/cPjUZj7+YEtzaEQAoHk4YGwDaXGEMChxMHQAJjl+cOAtQdRAFFMT4BRYU2JTkdOaFFSBB9FEE2dfSBSwFEUaqJ63AQgUUBRZcAgP/ngMCAAcUFRIFLtarRRWgQqT4BRNW/BUTl+5cAgP/ngOCEMzSgAM23IUfjnuf8gyuLAAMkywCz54sA0gfp95E6optx8RnEM4WLQJMXBQHBg4HrQWxjYYwCFegzNIAAbbcxgZcAgP/ngGCCFe0TBASAEwQEgMG/M4WLQEGBlwCA/+eAAIEF5TMEhEHptzOFi0AxgZfwf//ngGB/Ae0TBASAEwQEgFW/EwRQA0W/EwRgA223EwRwA1W3IUfjiufygUsTBAAMyaBBR82/QUcFROOd5/KDJcsAAyWLAF08mbdBRwVE45Pn8gMnCwGRZ2Pk5ySDJUsBAyWLAO/wn44dt0FHBUTjk+fwgycLARFnY2T3IgMnywCDJUsBAyWLADOE5wLv8B+Mt4eDQJOHRwENZyOsBwC6lyOkh7DttTeHg0ATB0cBg0YHAGOGBhiDJosAwRcTBAAMY5P2AEBLAUeTBvAOY073BINHWwADR0sAgUuiB9mPA0drAEIHXY+DR3sA4gfZj2Od9hoTdfQPVToT9fsPfTJZNOMUBNKDRxsASUdjavcaCUfjfPfQ9ReT9/cPPUfjZvfQigfWl5xDgoczBusAA0aGAQUHsY5hv7eHg0CTh0cBA8cHAHXP2EdjFAcWwEsjgAcAFbVhR2OW5wKDJ8sBAyeLAYMmSwEDJgsBgyXLAAMliwCX8H//54AAaqqLMzSgAJW/gUsFRL23EUcFROOV5963lgBguErld/0XBWZ9j1GPAyWLALjKt5YAYPhCgUV9j1GP+MK3lgBg+Ep9j1GP+Mq3lgBguEL5j9GPvMKX8H//54AgbHWzE/f3AOMZB+QT3EcAEwSLAIFL/Vzj+YvXSESX8H//54CgUBhEVEAQQPmOYweXARxCE0f3/32P2Y4UwoULQQTZvxFHAb1BRwVE45zn1IMniwADJ0sBIyj5ACMm6QC5swMnyQAThgf/EecBzoFLEwRgDH21gyYJAWPmxgaNi+OdB9yDJgkBgUWBR2PrxwDjjQXOnY4+lyMo2QAjJukA7bGzBfsAiE2zBfcAkQeIwYVF6b8hRwVE45bnzgMkCQEZwBMEgAwjKAkAIyYJACWzgUsTBCAMsbUTBBAMmbWBSxMEgAw9vYFLEwSQDB29EwcgDWOD5wwTB0AN45/ntANEOwCDRysAIgRdjJfwf//ngCBPg6vEAEEUY3N0AaKL440LssBAYQtelDGAnEhjVfAAnERjWvQK7/Dv03XdyEBehtqFl/B//+eAIEsBxZMHQAzcyNxA3pfcwNxEs4d3QdzEl/B//+eAAErFvAllEwUFcYMrywADJIsAl/B//+eAADu3BwBg2Eu3BgABwRaTV0cBEgd1j72L2Y+zh3cDAUWz1YcCl/B//+eAIDwTBYA+l/B//+eAoDdNtIMmSwEDJgsBgyXLAAMliwDv8C//cbSDRTsAg0crABMFiwGiBd2NwRXv8I/dlbzv8E/NgbcDRDsAg0crACIEXYzcREEUgeeTN1QAjcu3PYRAN4yDQDcNg0BhC4VLk40NuxMMTAGTDE0BCcTcRJnDY0twAWPTCwiTB3AMGaCTB5AM3Mg5vAMoirADpw0AItAzOAQBBgizB+xABQg6xj7WQsTv8C/GMkciSDeFg0DahXwQ5oYQEBMFxQKX8H//54AAN4JXAyeKsIOlDQAdjB2PPpuyVyMk6rCqi76VI6C9AOF3s4WVQa6XkcNB8RMFTQHv8C/RI6CdAY2/45QLmtxE44EHmpMHgAytv4MniwDjmgeY7/BP2wllEwUFcZfwf//ngGAl7/DP1pfwf//ngKApjboDJMsA4wYElu/wz9gTBYA+l/B//+eAACPv8G/UApSJuu/w79P2UGZU1lRGWbZZJlqWWgZb9ktmTNZMRk22TQlhgoAAAA==", "text_start": 1082130432, - "data": "FACDQHIKgEDCCoBAGguAQOgLgEBUDIBAAgyAQD4JgECkC4BA5AuAQC4LgEDuCIBAYguAQO4IgEBMCoBAkgqAQMIKgEAaC4BAXgqAQKIJgEDSCYBAWgqAQKwOgEDCCoBAbA2AQGQOgEAuCIBAjA6AQC4IgEAuCIBALgiAQC4IgEAuCIBALgiAQC4IgEAuCIBACA2AQC4IgECKDYBAZA6AQA==", + "data": "FACDQJIJgEDuCYBAfgqAQGALgEDMC4BAeguAQIAIgEAcC4BAXAuAQJoKgEAwCIBAzgqAQDAIgEBsCYBAsgmAQO4JgEB+CoBAfgmAQKgIgEDcCIBAegmAQCAOgEDuCYBA5gyAQNgNgEBwB4BAAA6AQHAHgEBwB4BAcAeAQHAHgEBwB4BAcAeAQHAHgEBwB4BAggyAQHAHgEAEDYBA2A2AQA==", "data_start": 1082403760, "bss_start": 1082327040 } \ No newline at end of file diff --git a/tools/esptool_py/esptool/targets/stub_flasher/1/esp32h2beta1.json b/tools/esptool_py/esptool/targets/stub_flasher/1/esp32h2beta1.json deleted file mode 100644 index 03e110c5c2..0000000000 --- a/tools/esptool_py/esptool/targets/stub_flasher/1/esp32h2beta1.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "entry": 1077413318, - "text": "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", - "text_start": 1077411840, - "data": "DEDIP/gIOEBECThAnAk4QGoKOEDWCjhAhAo4QMAHOEAmCjhAZgo4QLAJOEBwBzhA5Ak4QHAHOEDSCDhAFgk4QEQJOECcCThA5Ag4QCoIOEBaCDhA4Ag4QC4NOEBECThA7gs4QOIMOEC8BjhADA04QLwGOEC8BjhAvAY4QLwGOEC8BjhAvAY4QLwGOEC8BjhAigs4QLwGOEAKDDhA4gw4QA==", - "data_start": 1070164904, - "bss_start": 1070088192 -} \ No newline at end of file diff --git a/tools/esptool_py/esptool/targets/stub_flasher/1/esp32h2beta2.json b/tools/esptool_py/esptool/targets/stub_flasher/1/esp32h2beta2.json deleted file mode 100644 index ce3afe7ac0..0000000000 --- a/tools/esptool_py/esptool/targets/stub_flasher/1/esp32h2beta2.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "entry": 1077413318, - "text": "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", - "text_start": 1077411840, - "data": "DEDIP/gIOEBECThAnAk4QGoKOEDWCjhAhAo4QMAHOEAmCjhAZgo4QLAJOEBwBzhA5Ak4QHAHOEDSCDhAFgk4QEQJOECcCThA5Ag4QCoIOEBaCDhA4Ag4QC4NOEBECThA7gs4QOIMOEC8BjhADA04QLwGOEC8BjhAvAY4QLwGOEC8BjhAvAY4QLwGOEC8BjhAigs4QLwGOEAKDDhA4gw4QA==", - "data_start": 1070164904, - "bss_start": 1070088192 -} \ No newline at end of file diff --git a/tools/esptool_py/esptool/targets/stub_flasher/1/esp32p4.json b/tools/esptool_py/esptool/targets/stub_flasher/1/esp32p4.json index 6f37e91b27..8b61274af5 100644 --- a/tools/esptool_py/esptool/targets/stub_flasher/1/esp32p4.json +++ b/tools/esptool_py/esptool/targets/stub_flasher/1/esp32p4.json @@ -1,8 +1,8 @@ { - "entry": 1341195918, - "text": "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", + "entry": 1341196642, + "text": "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", "text_start": 1341194240, - "data": "EAD1TwYK8U9WCvFPrgrxT4QL8U/wC/FPngvxT9QI8U9AC/FPgAvxT8IK8U+ECPFP9grxT4QI8U/gCfFPJgrxT1YK8U+uCvFP8gnxTzgJ8U9oCfFP7gnxT0AO8U9WCvFPCA3xTwAO8U/EB/FPJA7xT8QH8U/EB/FPxAfxT8QH8U/EB/FPxAfxT8QH8U/EB/FPpAzxT8QH8U8mDfFPAA7xTw==", - "data_start": 1341533100, + "data": "YAD1T3gO8U/GDvFPZA/xT0oQ8U+kEPFPXBDxT8oM8U/+D/FPRhDxT4IP8U96DPFPqg/xT3oM8U9UDvFPkg7xT8YO8U9kD/FPZg7xT/QM8U8oDfFPYg7xT3YU8U/GDvFPGBLxTzYU8U8eC/FPWhTxTx4L8U8eC/FPHgvxTx4L8U8eC/FPHgvxTx4L8U8eC/FPthHxTx4L8U9SE/FPNhTxTw==", + "data_start": 1341533180, "bss_start": 1341456384 } \ No newline at end of file diff --git a/tools/esptool_py/esptool/targets/stub_flasher/1/esp32s2.json b/tools/esptool_py/esptool/targets/stub_flasher/1/esp32s2.json index 68de613890..f1e5014787 100644 --- a/tools/esptool_py/esptool/targets/stub_flasher/1/esp32s2.json +++ b/tools/esptool_py/esptool/targets/stub_flasher/1/esp32s2.json @@ -1,8 +1,8 @@ { - "entry": 1073907716, - "text": "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", + "entry": 1073907752, + "text": "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", "text_start": 1073905664, - "data": "WAD9P0uLAkDdiwJA8pACQGaMAkD+iwJAZowCQMWMAkDejQJAUY4CQPmNAkDVigJAd40CQNCNAkDojAJAdI4CQBCNAkB0jgJAy4sCQCqMAkBmjAJAxYwCQOOLAkAXiwJAN48CQKqQAkDqiQJA0ZACQOqJAkDqiQJA6okCQOqJAkDqiQJA6okCQOqJAkDqiQJA1I4CQOqJAkDJjwJAqpACQA==", + "data": "WAD9P2aLAkD7iwJA0pACQH2MAkAejAJAfYwCQNaMAkDbjQJAUY4CQPaNAkDxigJAh40CQNCNAkD0jAJAco4CQByNAkByjgJA8osCQEOMAkB9jAJA1owCQASMAkAyiwJALI8CQI6QAkAGigJAsZACQAaKAkAGigJABooCQAaKAkAGigJABooCQAaKAkAGigJA0o4CQAaKAkC8jwJAjpACQA==", "data_start": 1073622012, "bss_start": 1073545216 } \ No newline at end of file diff --git a/tools/esptool_py/esptool/targets/stub_flasher/1/esp32s3.json b/tools/esptool_py/esptool/targets/stub_flasher/1/esp32s3.json index 484a8832fd..26d80f6c41 100644 --- a/tools/esptool_py/esptool/targets/stub_flasher/1/esp32s3.json +++ b/tools/esptool_py/esptool/targets/stub_flasher/1/esp32s3.json @@ -1,8 +1,8 @@ { - "entry": 1077381760, - "text": "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", + "entry": 1077381852, + "text": "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", "text_start": 1077379072, - "data": "XADKP16ON0AzjzdAR5Q3QL2PN0BTjzdAvY83QB2QN0A6kTdArJE3QFWRN0DpjTdA0JA3QCyRN0BAkDdA0JE3QGiQN0DQkTdAIY83QH6PN0C9jzdAHZA3QDmPN0AqjjdAkJI3QA2UN0AAjTdALZQ3QACNN0AAjTdAAI03QACNN0AAjTdAAI03QACNN0AAjTdAKpI3QACNN0AlkzdADZQ3QAQInwAAAAAAAAAYAQQIBQAAAAAAAAAIAQQIBgAAAAAAAAAAAQQIIQAAAAAAIAAAEQQI3AAAAAAAIAAAEQQIDAAAAAAAIAAAAQQIEgAAAAAAIAAAESAoDAAQAQAA", + "data": "XADKP6qON0B/jzdAo5U3QA2QN0CijzdADZA3QGaQN0BnkTdA4JE3QISRN0A5jjdAF5E3QFyRN0CEkDdAAZI3QKyQN0ABkjdAdo83QM+PN0ANkDdAZpA3QIiPN0B6jjdAvJI3QGeVN0BSjTdAh5U3QFKNN0BSjTdAUo03QFKNN0BSjTdAUo03QFKNN0BSjTdAX5I3QFKNN0CUlDdAZ5U3QAQInwAAAAAAAAAYAQQIBQAAAAAAAAAIAQQIBgAAAAAAAAAAAQQIIQAAAAAAIAAAEQQI3AAAAAAAIAAAEQQIDAAAAAAAIAAAAQQIEgAAAAAAIAAAESAoDAAQAQAA", "data_start": 1070279676, "bss_start": 1070202880 } \ No newline at end of file diff --git a/tools/esptool_py/esptool/targets/stub_flasher/1/esp32s3beta2.json b/tools/esptool_py/esptool/targets/stub_flasher/1/esp32s3beta2.json deleted file mode 100644 index da770f7b97..0000000000 --- a/tools/esptool_py/esptool/targets/stub_flasher/1/esp32s3beta2.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "entry": 1077380596, - "text": "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", - "text_start": 1077379072, - "data": "DADKPxeIN0CriDdAw403QDeJN0DLiDdAN4k3QJaJN0C2ijdAKIs3QNGKN0ChhzdASIo3QKiKN0C5iTdATIs3QOGJN0BMizdAmYg3QPiIN0A3iTdAlok3QLGIN0DjhzdABIw3QIWNN0DAhjdAp403QMCGN0DAhjdAwIY3QMCGN0DAhjdAwIY3QMCGN0DAhjdAqYs3QMCGN0CZjDdAhY03QA==", - "data_start": 1070279592, - "bss_start": 1070202880 -} \ No newline at end of file diff --git a/tools/esptool_py/esptool/targets/stub_flasher/2/LICENSE-APACHE b/tools/esptool_py/esptool/targets/stub_flasher/2/LICENSE-APACHE index f8e5e5ea03..d11f8e7ae8 100644 --- a/tools/esptool_py/esptool/targets/stub_flasher/2/LICENSE-APACHE +++ b/tools/esptool_py/esptool/targets/stub_flasher/2/LICENSE-APACHE @@ -1,201 +1,201 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - -1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - -2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - -3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - -4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - -5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - -6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - -7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - -8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - -9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - -END OF TERMS AND CONDITIONS - -APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - -Copyright [yyyy] [name of copyright owner] - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. \ No newline at end of file + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2025 Espressif Systems (Shanghai) CO LTD + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/tools/esptool_py/esptool/targets/stub_flasher/2/LICENSE-MIT b/tools/esptool_py/esptool/targets/stub_flasher/2/LICENSE-MIT index 3e8a085340..73068b768c 100644 --- a/tools/esptool_py/esptool/targets/stub_flasher/2/LICENSE-MIT +++ b/tools/esptool_py/esptool/targets/stub_flasher/2/LICENSE-MIT @@ -1,25 +1,21 @@ -Copyright 2022 esp-rs +MIT License -Permission is hereby granted, free of charge, to any -person obtaining a copy of this software and associated -documentation files (the "Software"), to deal in the -Software without restriction, including without -limitation the rights to use, copy, modify, merge, -publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software -is furnished to do so, subject to the following -conditions: +Copyright (c) 2025 Espressif Systems (Shanghai) CO LTD -The above copyright notice and this permission notice -shall be included in all copies or substantial portions -of the Software. +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF -ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED -TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A -PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT -SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR -IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -DEALINGS IN THE SOFTWARE. +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/tools/esptool_py/esptool/targets/stub_flasher/2/README.md b/tools/esptool_py/esptool/targets/stub_flasher/2/README.md index eae371e43f..76742396d1 100644 --- a/tools/esptool_py/esptool/targets/stub_flasher/2/README.md +++ b/tools/esptool_py/esptool/targets/stub_flasher/2/README.md @@ -1,3 +1,3 @@ # Licensing -The binaries in JSON format distributed in this directory are dual licensed under the Apache License Version 2.0 or the MIT license. They were released at https://github.com/esp-rs/esp-flasher-stub/releases/tag/v0.3.0 from where the sources can be obtained. +The binaries in JSON format distributed in this directory are dual licensed under the Apache License Version 2.0 or the MIT license. They were released at https://github.com/espressif/esp-flasher-stub/releases/tag/v0.1.0 from where the sources can be obtained. diff --git a/tools/esptool_py/esptool/targets/stub_flasher/2/esp32.json b/tools/esptool_py/esptool/targets/stub_flasher/2/esp32.json index 8e6bd05380..efb590a102 100644 --- a/tools/esptool_py/esptool/targets/stub_flasher/2/esp32.json +++ b/tools/esptool_py/esptool/targets/stub_flasher/2/esp32.json @@ -1 +1,5 @@ -{"entry":1074274996,"text":"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GTAMEzIhGjAEEzIhGzAQEzIhHDAREzIhHTAgEzIhHjAhEzIhHzAiEzIhIDAjEzIhITDq8zIhIjDr8zIhIzDs8zIhJDDo8zIhJTDp8wMBJhMBJyMBKDMBKUMBKlMBK2MBLHMBLYMBLpMBL6MBMLMBMcMBMtMBM+MBNPMBNSIhBDIhBUIhBlIhB2IhCHIhCYIhCpIhC6IhDLIhDcIhDtIhD+IhEPIhEYAAAPBBABABIBLR/wJhAwDRSQDmAwJhAQDoAwJhEwDuAwJhFACxAwJhAADBSQDRAwJhAoXe/wF5/gDmExAgAGIhEyZGCBBxIFUoAEYEAAF0/gDmExAgAGKgARBxIJWd/4Xt/wIhAQDmEwIhAACxEwIhAhIhAxAgAAAwAPBBABABIBLR/wJhAwDRSQDmAwJhAQDoAwJhEwDuAwJhFADAAwJhAADBSQDXAwJhAgXX/2IhExBxIJUhAAXo/wIhAQDmEwIhAACxEwIhAhIhAxAgAAAyAPBBAAAQASAS0f8CYQMA0UkAwgMCYQEAsgMCYQAAwUkA0gMCYQJF0v8BSv4A5hMQIABioAIQcSDVkv/F4v8CIQEAwhMCIQAAshMCIQISIQMQIAAQMgDwQQAQASAS0f8CYQMA0UkAwwMCYQEAswMCYQAAwUkA0wMCYQIFzf8BM/4A5hMQIABioAMQcSCVjf+F3f8CIQEAwxMCIQAAsxMCIQISIQMQIAAQMwDwQQAQASAS0f8CYQMA0UkAxAMCYQEAtAMCYQAAwUkA1AMCYQLFx/8BIf4A5hMQIABioAQQcSDVwv9F2P8CIQEAxBMCIQAAtBMCIQISIQMQIAAQNADwQQAQASAS0f8CYQMA0UkAxQMCYQEAtQMCYQAAwUkA1QMCYQKFwv8BDf4A5hMQIABioAUQcSCVvv8F0/8CIQEAxRMCIQAAtRMCIQISIQMQIAAQNQDwQQAQASAS0f8CYQMA0UkAxgMCYQEAtgMCYQAAwUkA1gMCYQJFvf8B+f0A5hMQIABioAYQcSBVuv/Fzf8CIQEAxhMCIQAAthMCIQISIQMQIAAQNgDwQQAQASAS0f8CYQMA0UkAxwMCYQEAtwMCYQAAwUkA1wMCYQIFuP8B5f0A5hMQIABioAcQcSAVtv+FyP8CIQEAxxMCIQAAtxMCIQISIQMQIAAQNwDwQQA2QQCBv/2tAr0D4AgAHfAANkEA8EEAAADkJwhA5CcIQOQnCEDkJwhA5CcIQOQnCEDkJwhA5CcIQOQnCEDkJwhAAAAAAAAAAADkJwhA5CcIQOQnCEDkJwhA5CcIQOQnCEDkJwhA5CcIQOQnCEDkJwhA5CcIQOQnCEDkJwhA5CcIQOQnCEDkJwhA5CcIQOQnCEDkJwhA5CcIQOQnCEDkJwhA5CcIQOQnCEDkJwhA5CcIQOQnCEDkJwhA5CcIQOQnCEDkJwhA5CcIQOQnCEDkJwhA5CcIQOQnCEDkJwhA5CcIQOQnCEDkJwhA5CcIQOQnCEDkJwhA5CcIQOQnCEDkJwhA5CcIQOQnCEDkJwhA5CcIQOQnCEDkJwhA5CcIQOQnCEDkJwhA5CcIQOQnCEA=","text_start":1074266112,"data":"5hMIQO0UCEBGFQhA5hMIQKsVCEDtFAhAGhYIQFEWCEChFghAABcIQKkeCEAMFwhAqR4IQD4XCEDmEwhA7RQIQEYVCEDoFwhAlRwIQN4UCEAWGQhAaRkIQKIVCEDtFAhATisIQA4pCEAGLAhABiwIQAYsCEA5KwhABiwIQAYsCEA/KwhARSsIQEsrCEDA29zb3QA6ADsAPAA9AD4APwBAAEEAAAAAAAAA/zcGAAAAOAAAiMAoAAAAUwAAAYQAAAAAAEAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAwAAAAEAAAABAAAAAAAAAAMAAAAAAAAAAQAAAAEAAAACAAAAAgAAAAIAAAADAAAAAwAAAAAAAAAAAAAAAAAAAAMAAAAAAAAAAwAAAAAAAAAAAAAAAAABAAIAAwAEAAUABgAHAAgACQBFAEUADAANAA4ADwAQABEAEgATABQAFQAWABcAGAAZABoAGwAcAB0AHgAfACAAIQAiACMAJAAlACYAJwAoACkAKgArACwALQAuAC8AMAAxADIAMwA0ADUANgA3ADgAOQA6ADsAPAA9AD4APwBAAEEAQgBDAEQAAAAAAQAA","data_start":1073414144} \ No newline at end of file +{ + "entry": 1074520064, + "text": "NmEADAgQoSCJARARIOUAAKgBjEoQESBlAQAd8DZhAH0BKQeoByUCAD3wHfA2YQB9ASkHqAflAQA98B3wNmEAfQEpBz3wHfAANmEAfQEpBz3wHfAANmEAfQEpBz3wHfAA", + "text_start": 1074520064 +} \ No newline at end of file diff --git a/tools/esptool_py/esptool/targets/stub_flasher/2/esp32c2.json b/tools/esptool_py/esptool/targets/stub_flasher/2/esp32c2.json index 72c2ac6cca..cd15fc27c3 100644 --- a/tools/esptool_py/esptool/targets/stub_flasher/2/esp32c2.json +++ b/tools/esptool_py/esptool/targets/stub_flasher/2/esp32c2.json @@ -1 +1,5 @@ -{"entry":1077411840,"text":"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E7wEBBOEBPyTBQAEs4qVQJO8FABRwQoFNpUDKoUMBUWBRSKGlwAAAOeAgKIqhK6JBUWBRVaGlwAAAOeA4KETBgAEY+PEACKFY+PEAM6FE3r6ABOE/P+zeaQAbYwFRYFFJoaXAAAA54CgnrMGgEEz9qYA7Y4SCigIKprShMhAjEDYRJxEVY3RjUGPs+c3AZzE2MSMwMjAsagFRYFFJoaXAAAA54DgmqqJLooFRYFFIoaXAAAA54DAmSqLLoQFRYFFVoaXAAAA54AgmRMGAARj48QAooVj48QAWoUzBoBBs3ZGATN2NgH9HDP0vACz+awAMksTRfT/k8X5/5PG9v8TRvb/M3nJADN93QCz/b0As/urAFJGtyYMYI21OUWiRWNttRgTlSUAtwXLP5OFhQoulQhBwUUSRmNxtRgSBSwILpVMQQhBAUkBS7P7xQCCRTN8tQA3tXwHkwwVUzcFyz8TDQUIkw0ABDNlLAGz5WsBTY1jCQUQYxsJAjMFYEEzdasAMwWVA22BapUDRQUAEwUFAmMJDAKzBYBBs3W8ALOFlQPtgeqVg8QFAA2oMwUgQTN1qQAzBZUDbYFqlQNFBQDjGwz8swVwQbP1uwCzhZUD7YHqlYPFBQCThAUCs2V8AZnhkwQFBCaFl/D//+eAYBGTFQUBwYGThWX9kcXCRZcAAADngOALBUWBRSaGlwAAAOeAIISqia6KE4YE/AVFgUWXAAAA54DggiqKLoQzhp1ABUWBRZcAAADngCCCY+O0AaKFY+O0AVKFE7YEBDMGwECzdlYBM3Y2ARO3FAB9F/mNeY0TRfX/k8X1/xNG9v+Txvb/s/vbADN8zAAze7sAM3mpAN21CAKDIMUEIEVkQQMpBQSDKcUDAyqFA4MqRQMDKwUDgyvFAgMshQKDLEUCAy0FAoMtxQFxYYKAAABCBUGBNyY4QBMGBmsKBTKVHEE3JThAEwXlo2OEpwAuhYKHAACqhQlFFwMAAGcAI8CqhQ1FFwMAAGcAY7+qhRFFFwMAAGcAo76qhRVFFwMAAGcA472qhRlFFwMAAGcAI72qhR1FFwMAAGcAY7yqhSFFFwMAAGcAo7uqhSVFFwMAAGcA47qqhSlFFwMAAGcAI7qqhS1FFwMAAGcAY7mqhTFFFwMAAGcAo7iqhTVFFwMAAGcA47eqhTlFFwMAAGcAI7eqhT1FFwMAAGcAY7YAAD4aOEA+GjhAPho4QD4aOEA+GjhAPho4QD4aOEA+GjhAPho4QD4aOEA+GjhAPho4QD4aOEA+GjhAPho4QD4aOEA+GjhAPho4QD4aOEA+GjhAPho4QD4aOEA+GjhAPho4QD4aOEA+GjhAPho4QD4aOEA+GjhAPho4QD4aOEA+GjhAPho4QD4aOEA+GjhAPho4QD4aOEA+GjhAPho4QD4aOEA+GjhAPho4QA==","text_start":1077411840,"data":"0As4QKIMOEDeDDhA0As4QIoOOECiDDhATA04QLQNOEDoDjhAFA84QOIUOEAyDThA4hQ4QOgNOEDQCzhAogw4QN4MOEBeDzhAgA04QI4MOED4EThAZBA4QCgNOECiDDhAAAEcAh0OGAMeFhQPGREECB8bDRcVExAHGgwSBgsFCgnA29zb3QAAAAEAAAACAAAAAwAAAAQAAAAFAAAABgAAAAcAAAAIAAAACQAAAAoAAAALAAAADAAAAA0AAAAOAAAADwAAAD4aOEA+GjhAAAAAAD4aOEA+GjhAPho4QAAAAAA+GjhAPho4QD4aOEAAAAAAPho4QAQAAAAEAAAABAAAAAQAAAAMAAAABAAAAAwAAAAEAAAABAAAAAwAAABAAAAAgAAAAAAIAAAAAAAQQAAAAAAgAAAEAAAABAAAACAAAAACAAAACAAAAAgAAAAIAAAACAAAABAAAAAIAAAAEAAAAAgAAAAIAAAAEAAAAL////9///////f//////++//////9////v////7////3/////3///8=","data_start":1070268448} \ No newline at end of file +{ + "entry": 1077411840, + "text": "ARFoAAbOAsY5IDJFEcEVIPJABWGCgAERBs4izAAQIyak/gMlxP49KAEA8kBiRAVhgoABEQbOIswAECMmpP4DJcT+JSgBAPJAYkQFYYKAAREGziLMABAjJqT+AQDyQGJEBWGCgAERBs4izAAQIyak/gEA8kBiRAVhgoABEQbOIswAECMmpP4BAPJAYkQFYYKA", + "text_start": 1077411840 +} \ No newline at end of file diff --git a/tools/esptool_py/esptool/targets/stub_flasher/2/esp32c3.json b/tools/esptool_py/esptool/targets/stub_flasher/2/esp32c3.json index 97538d65a1..cd15fc27c3 100644 --- a/tools/esptool_py/esptool/targets/stub_flasher/2/esp32c3.json +++ b/tools/esptool_py/esptool/targets/stub_flasher/2/esp32c3.json @@ -1 +1,5 @@ -{"entry":1077411840,"text":"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YwsFGGObDQIzBXBBM/WrADMFZQNtgTKVA0UFABMFBQJjCQkCswUgQbN1uQCzhWUD7YGylYPEBQANqDMFsEEz9a0AMwVlA22BMpUDRQUA4xsJ/LMFoEGzdb0As4VlA+2BspWDxQUAk4QFArNlqQGZ4ZMEBQQTlSQAVY0IQRO8BAQThAT8kwUABLOKlUCTvBQAUcEKBTaVAypFEQVFgUUihpcAAADngICiKoSuiQVFgUVWhpcAAADngOChEwYABGPjxAAihWPjxADOhRN6+gAThPz/s3mkAG2MBUWBRSaGlwAAAOeAoJ6zBoBBM/amAO2OEgooCCqa0oTIQIxA2EScRFWN0Y1Bj7PnNwGcxNjEjMDIwLGoBUWBRSaGlwAAAOeA4JqqiS6KBUWBRSKGlwAAAOeAwJkqiy6EBUWBRVaGlwAAAOeAIJkTBgAEY+PEAKKFY+PEAFqFMwaAQbN2RgEzdjYB/Rwz9LwAs/msADJLE0X0/5PF+f+Txvb/E0b2/zN5yQAzfd0As/29ALP7qwBSRrcmDGCNtTlFokVjbbUYE5UlALcFyT+ThYUKLpUIQcFFEkZjcbUYEgUsCC6VTEEIQQFJAUuz+8UAgkUzfLUAN7V8B5MMFVM3Bck/Ew0FCJMNAAQzZSwBs+VrAU2NYwkFEGMbCQIzBWBBM3WrADMFlQNtgWqVA0UFABMFBQJjCQwCswWAQbN1vACzhZUD7YHqlYPEBQANqDMFIEEzdakAMwWVA22BapUDRQUA4xsM/LMFcEGz9bsAs4WVA+2B6pWDxQUAk4QFArNlfAGZ4ZMEBQQmhZfw///ngKDokxUFAcGBk4Ul/JHFwkWXAAAA54DgCwVFgUUmhpcAAADngCCEqomuihOGBPwFRYFFlwAAAOeA4IIqii6EM4adQAVFgUWXAAAA54AggmPjtAGihWPjtAFShRO2BAQzBsBAs3ZWATN2NgETtxQAfRf5jXmNE0X1/5PF9f8TRvb/k8b2/7P72wAzfMwAM3u7ADN5qQDdtQgCgyDFBCBFZEEDKQUEgynFAwMqhQODKkUDAysFA4MrxQIDLIUCgyxFAgMtBQKDLcUBcWGCgAAAQgVBgTc2OEATBgarCgUylRxBNyU4QBMFBddjhKcALoWChwAAqoUJRRcDAABnACPAqoUNRRcDAABnAGO/qoURRRcDAABnAKO+qoUVRRcDAABnAOO9qoUZRRcDAABnACO9qoUdRRcDAABnAGO8qoUhRRcDAABnAKO7qoUlRRcDAABnAOO6qoUpRRcDAABnACO6qoUtRRcDAABnAGO5qoUxRRcDAABnAKO4qoU1RRcDAABnAOO3qoU5RRcDAABnACO3qoU9RRcDAABnAGO2AABwHThAcB04QHAdOEBwHThAcB04QHAdOEBwHThAcB04QHAdOEBwHThAcB04QHAdOEBwHThAcB04QHAdOEBwHThAcB04QHAdOEBwHThAcB04QHAdOEBwHThAcB04QHAdOEBwHThAcB04QHAdOEBwHThAcB04QHAdOEBwHThAcB04QHAdOEBwHThAcB04QHAdOEBwHThAcB04QHAdOEBwHThAcB04QHAdOEBwHThAcB04QHAdOEBwHThAcB04QHAdOEBwHThAcB04QHAdOEBwHThAcB04QHAdOEBwHThAcB04QHAdOEBwHThAcB04QHAdOEBwHThAcB04QA==","text_start":1077411840,"data":"4Aw4QLYNOEDyDThA4Aw4QJwPOEC2DThAXg44QMYOOED6DzhAJhA4QJwKOEBEDjhAnAo4QPoOOEDgDDhAtg04QPINOEBwEDhAkg44QKINOEAKEzhAdhE4QDoOOEC2DThAAAEcAh0OGAMeFhQPGREECB8bDRcVExAHGgwSBgsFCgnA29zb3QAAAAEAAAACAAAAAwAAAAQAAAAFAAAABgAAAAcAAAAIAAAACQAAAAoAAAALAAAADAAAAA0AAAAOAAAADwAAAHAdOEBwHThAAAAAAHAdOEBwHThAcB04QAAAAABwHThAcB04QHAdOEAAAAAAcB04QA==","data_start":1070137376} \ No newline at end of file +{ + "entry": 1077411840, + "text": "ARFoAAbOAsY5IDJFEcEVIPJABWGCgAERBs4izAAQIyak/gMlxP49KAEA8kBiRAVhgoABEQbOIswAECMmpP4DJcT+JSgBAPJAYkQFYYKAAREGziLMABAjJqT+AQDyQGJEBWGCgAERBs4izAAQIyak/gEA8kBiRAVhgoABEQbOIswAECMmpP4BAPJAYkQFYYKA", + "text_start": 1077411840 +} \ No newline at end of file diff --git a/tools/esptool_py/esptool/targets/stub_flasher/2/esp32c5.json b/tools/esptool_py/esptool/targets/stub_flasher/2/esp32c5.json new file mode 100644 index 0000000000..5033ef2cf0 --- /dev/null +++ b/tools/esptool_py/esptool/targets/stub_flasher/2/esp32c5.json @@ -0,0 +1,5 @@ +{ + "entry": 1082130432, + "text": "ARFoAAbOAsY5IDJFEcEVIPJABWGCgAERBs4izAAQIyak/gMlxP49KAEA8kBiRAVhgoABEQbOIswAECMmpP4DJcT+JSgBAPJAYkQFYYKAAREGziLMABAjJqT+AQDyQGJEBWGCgAERBs4izAAQIyak/gEA8kBiRAVhgoABEQbOIswAECMmpP4BAPJAYkQFYYKA", + "text_start": 1082130432 +} \ No newline at end of file diff --git a/tools/esptool_py/esptool/targets/stub_flasher/2/esp32c6.json b/tools/esptool_py/esptool/targets/stub_flasher/2/esp32c6.json index 25c7710657..5033ef2cf0 100644 --- a/tools/esptool_py/esptool/targets/stub_flasher/2/esp32c6.json +++ b/tools/esptool_py/esptool/targets/stub_flasher/2/esp32c6.json @@ -1 +1,5 @@ -{"entry":1082130432,"text":"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lwAAAOeAYJIihZcAAADngACUhUUihZcAAADngACUhUUihZcAAADngACUIoWBRZcAAADngECQIoWBRZcAAADngECQSkVFjSrJABECywLNAtG3BABAJs8ihZcAAADngOCShUUihZcAAADngKCNhUUihZcAAADngKChhUUihZcAAADngKCNClUzdSUBRY2q1CrRAtkIGYVFlwAAAOeAgI0IGZcAAADngKCNCBmXAAAA54DAjQgZgUWXAAAA54CAiAgZhUWXAAAA54CAnAgZhUWXAAAA54CAiALTIBEC1QLXSBGBRZcAAADngACLGlUzdXUB3t4q00gRlwAAAOeAgIFIEZcAAADngKCBIoWXAAAA54BAiSKFlwAAAOeAYIkihZcAAADngICJKlWDRcEKM3W1ATNlhQGq1irVLtdBRSrbSBmpRZfw///ngOBISBmtRZfw///ngCBIWlW3RY///RVtjbcFEABNjSrbSBn1RZfw///ngEBGAt0oGZcAAADngKCEKBmXAAAA54CghCgZlwAAAOeAoIQoGZcAAADngKCEKBmXAAAA54CghCgZlwAAAOeAoIQoGZcAAADngKCEKBmXAAAA54CghCgZlwAAAOeAoIRKXFpVqs5qVarMKkUq0DpFKtJaRSrYakUq1npFKtQaVSreAsVkAQLHAskoAYVFl/D//+eAQHAoAZfw///ngOBxKkUzdWUBKsUoAYVFl/D//+eAIHIoAYFFl/D//+eA4HIoAZfw///ngMBtKAGX8P//54DgbYVFJoWX8P//54CgboVFJoWX8P//54CgbiaFl/D//+eAwG4mhYFFl/D//+eAwG4mhYFFl/D//+eAwG5KRTN1NQEqyQQRAssCzQLPAtEmhZfw///ngEBvJoWBRZfw///ngABqhUUmhZfw///ngAB+hUUmhZfw///ngABqClVKxDN9JQFq0QLTJBEC1QLXSBGBRZfw///ngOBrGlUzdXUBKtNIEZfw///ngIBiSBGX8P//54CgYiaFl/D//+eAQGomhZfw///ngGBqJoWX8P//54CAaipVM3W1AYNFwQo3BgAIUY2qyirVLtcTBQAgKtkIGalFl/D//+eAoCkIGbFFl/D//+eA4CgIGbVFl/D//+eAIChKVbcFceD9FW2NtwWAEk2NKtkIGflFl/D//+eAQCYIGf1Fl/D//+eAgCUC20gZ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nMTYxIzAyMCxqAVFgUUmhpcAAADngGCNqokuigVFgUUihpcAAADngECMKosuhAVFgUVWhpcAAADngKCLEwYABGPjxACihWPjxABahTMGkEGzdkYBM3Y2Af0dM/S9ALP5rQBySxNF9P+Txfn/k8b2/xNG9v+z+8sAM3nZADN9vQAzfKwAEla5vUlF4kVjYLUaE5UlALdFgECThcUOLpUIQcFF0kZjdLUYEgUsEC6VDEVQQQhBAUkz+9UAskWze7YAwkUzfLUAN7V8B5MMFVM3RYBAEw1FDJMNAAQzZWwBs+UrAU2NYwkFEGMbCwIzBSBBM3WpADMFlQNtgWqVA0UFABMFBQJjCQwCswWAQbN1vACzhZUD7YHqlYPEBQANqDMFYEEzdasAMwWVA22BapUDRQUA4xsM/LMFcEGz9bsAs4WVA+2B6pWDxQUAk4QFArNlfAGZ4ZMEBQQmhZfg///ngGC3kxUFAcGBk4U1+5HFglWXAAAA54DgCwVFgUUmhpfw///ngIB2qomuihOGBPwFRYFFl/D//+eAQHUqii6EM4adQAVFgUWX8P//54CAdGPjtAGihWPjtAFShRO2BAQzBsBAs3ZWATN2NgETtxQAfRf5jXmNE0X1/5PF9f8TRvb/k8b2/7P72wAzfMwAM3m5ADN7qwDdtQgCgyDFBSBNZEkDKQUFgynFBAMqhQSDKkUEAysFBIMrxQMDLIUDgyxFAwMtBQODLcUCNWGCgAAAQgVBgTdGgEATBgbvCgUylRxBNzWAQBMFxQ1jhKcALoWChwAAqoUJRRcDAABnAGO/qoUNRRcDAABnAKO+qoURRRcDAABnAOO9qoUVRRcDAABnACO9qoUZRRcDAABnAGO8qoUdRRcDAABnAKO7qoUhRRcDAABnAOO6qoUlRRcDAABnACO6qoUpRRcDAABnAGO5qoUtRRcDAABnAKO4qoUxRRcDAABnAOO3qoU1RRcDAABnACO3qoU5RRcDAABnAGO2qoU9RRcDAABnAKO1qoVBRRcDAABnAOO0qoVFRRcDAABnACO0qoVJRRcDAABnAGOzqoVNRRcDAABnAKOyAADcMIBA3DCAQNwwgEDcMIBA3DCAQNwwgEDcMIBA3DCAQNwwgEDcMIBA3DCAQNwwgEDcMIBA3DCAQNwwgEDcMIBA3DCAQNwwgEDcMIBA3DCAQNwwgEDcMIBA3DCAQNwwgEDcMIBA3DCAQNwwgEDcMIBA3DCAQNwwgEDcMIBA3DCAQNwwgEDcMIBA3DCAQNwwgEDcMIBA3DCAQNwwgEDcMIBA3DCAQNwwgEDcMIBA3DCAQNwwgEDcMIBA3DCAQNwwgEDcMIBA3DCAQNwwgEDcMIBA3DCAQNwwgEDcMIBA3DCAQNwwgEDcMIBA3DCAQNwwgEDcMIBA3DCAQNwwgEDcMIBA3DCAQNwwgEDcMIBA3DCAQNwwgEDcMIBA3DCAQNwwgEDcMIBA3DCAQNwwgEDcMIBA3DCAQA==","text_start":1082130432,"data":"4AuAQLYMgEDyDIBA4AuAQJwOgEC2DIBAXg2AQMYNgED6DoBAJg+AQPYUgEBEDYBA9hSAQPoNgEDgC4BAtgyAQPIMgEBwD4BAkg2AQKIMgEAKEoBAdhCAQDoNgEC2DIBA3////9/////f////f////+/////f////3//////+//8gAAAAIAAAACAAAACAAAAAEAAAACAAAAAgAAAAAAEAAAABHAIdDhgDHhYUDxkRBAgfGw0XFRMQBxoMEgYLBQoJwNvc290AAAABAAAAAgAAAAAAAAAAAAAAAwAAAAQAAAAAAAAAAAAAAAUAAAAGAAAABwAAAAgAAAAJAAAACgAAAAsAAAAMAAAADQAAAA4AAAAPAAAAAQAAAAIAAAAFAAAABgAAAAkAAAAKAAAACwAAAAwAAAANAAAADgAAAA8AAAAQAAAAEQAAABIAAAATAAAA3DCAQNwwgEAAAAAA3DCAQNwwgEDcMIBAAAAAANwwgEDcMIBA3DCAQAAAAADcMIBA","data_start":1082146852} \ No newline at end of file +{ + "entry": 1082130432, + "text": "ARFoAAbOAsY5IDJFEcEVIPJABWGCgAERBs4izAAQIyak/gMlxP49KAEA8kBiRAVhgoABEQbOIswAECMmpP4DJcT+JSgBAPJAYkQFYYKAAREGziLMABAjJqT+AQDyQGJEBWGCgAERBs4izAAQIyak/gEA8kBiRAVhgoABEQbOIswAECMmpP4BAPJAYkQFYYKA", + "text_start": 1082130432 +} \ No newline at end of file diff --git a/tools/esptool_py/esptool/targets/stub_flasher/2/esp32c61.json b/tools/esptool_py/esptool/targets/stub_flasher/2/esp32c61.json new file mode 100644 index 0000000000..5033ef2cf0 --- /dev/null +++ b/tools/esptool_py/esptool/targets/stub_flasher/2/esp32c61.json @@ -0,0 +1,5 @@ +{ + "entry": 1082130432, + "text": "ARFoAAbOAsY5IDJFEcEVIPJABWGCgAERBs4izAAQIyak/gMlxP49KAEA8kBiRAVhgoABEQbOIswAECMmpP4DJcT+JSgBAPJAYkQFYYKAAREGziLMABAjJqT+AQDyQGJEBWGCgAERBs4izAAQIyak/gEA8kBiRAVhgoABEQbOIswAECMmpP4BAPJAYkQFYYKA", + "text_start": 1082130432 +} \ No newline at end of file diff --git a/tools/esptool_py/esptool/targets/stub_flasher/2/esp32h2.json b/tools/esptool_py/esptool/targets/stub_flasher/2/esp32h2.json index 310e523e2b..5033ef2cf0 100644 --- a/tools/esptool_py/esptool/targets/stub_flasher/2/esp32h2.json +++ b/tools/esptool_py/esptool/targets/stub_flasher/2/esp32h2.json @@ -1 +1,5 @@ -{"entry":1082130432,"text":"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","text_start":1082130432,"data":"vAuAQJIMgEDODIBAvAuAQHgOgECSDIBAOg2AQKINgEDWDoBAAg+AQNIUgEAgDYBA0hSAQNYNgEC8C4BAkgyAQM4MgEBMD4BAbg2AQH4MgEDmEYBAUhCAQBYNgECSDIBAAAIAAAACAAAAAgAAAAgAAAABAAAAAgAAAAIAAAAQAAD//f////3////9////9/////7////9/////f///+///wABHAIdDhgDHhYUDxkRBAgfGw0XFRMQBxoMEgYLBQoJwNvc290AAAABAAAAAgAAAAAAAAAAAAAAAwAAAAQAAAAAAAAAAAAAAAUAAAAGAAAABwAAAAgAAAAJAAAACgAAAAsAAAAMAAAADQAAAA4AAAAPAAAAAQAAAAIAAAAFAAAABgAAAAkAAAAKAAAACwAAAAwAAAANAAAADgAAAA8AAAAQAAAAEQAAABIAAAATAAAAKBuAQCgbgEAAAAAAKBuAQCgbgEAoG4BAAAAAACgbgEAoG4BAKBuAQAAAAAAoG4BA","data_start":1082141160} \ No newline at end of file +{ + "entry": 1082130432, + "text": "ARFoAAbOAsY5IDJFEcEVIPJABWGCgAERBs4izAAQIyak/gMlxP49KAEA8kBiRAVhgoABEQbOIswAECMmpP4DJcT+JSgBAPJAYkQFYYKAAREGziLMABAjJqT+AQDyQGJEBWGCgAERBs4izAAQIyak/gEA8kBiRAVhgoABEQbOIswAECMmpP4BAPJAYkQFYYKA", + "text_start": 1082130432 +} \ No newline at end of file diff --git a/tools/esptool_py/esptool/targets/stub_flasher/2/esp32p4.json b/tools/esptool_py/esptool/targets/stub_flasher/2/esp32p4.json new file mode 100644 index 0000000000..f8c7868ebe --- /dev/null +++ b/tools/esptool_py/esptool/targets/stub_flasher/2/esp32p4.json @@ -0,0 +1,5 @@ +{ + "entry": 1341194240, + "text": "ARFoAAbOAsY5IDJFEcEVIPJABWGCgAERBs4izAAQIyak/gMlxP49KAEA8kBiRAVhgoABEQbOIswAECMmpP4DJcT+JSgBAPJAYkQFYYKAAREGziLMABAjJqT+AQDyQGJEBWGCgAERBs4izAAQIyak/gEA8kBiRAVhgoABEQbOIswAECMmpP4BAPJAYkQFYYKA", + "text_start": 1341194240 +} \ No newline at end of file diff --git a/tools/esptool_py/esptool/targets/stub_flasher/2/esp32s2.json b/tools/esptool_py/esptool/targets/stub_flasher/2/esp32s2.json index 23ffd983c7..aef0fd5005 100644 --- a/tools/esptool_py/esptool/targets/stub_flasher/2/esp32s2.json +++ b/tools/esptool_py/esptool/targets/stub_flasher/2/esp32s2.json @@ -1 +1,5 @@ -{"entry":1073913140,"text":"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5hMQIABioAUQcSCV0P8F3P8CIQEAxRMCIQAAtRMCIQISIQMQIAAQNQDwQQAQASAS0f8CYQMA0UkAxgMCYQEAtgMCYQAAwUkA1gMCYQJFz/8BR/4A5hMQIABioAYQcSBVzP/F1v8CIQEAxhMCIQAAthMCIQISIQMQIAAQNgDwQQAQASAS0f8CYQMA0UkAxwMCYQEAtwMCYQAAwUkA1wMCYQIFyv8BM/4A5hMQIABioAcQcSAVyP+F0f8CIQEAxxMCIQAAtxMCIQISIQMQIAAQNwDwQQA2QQCBEP6tAr0D4AgAHfAANkEA8EEAAAAEowJABKMCQASjAkAEowJABKMCQASjAkAEowJABKMCQASjAkAEowJABKMCQASjAkAEowJABKMCQASjAkAEowJABKMCQASjAkAEowJABKMCQASjAkAEowJABKMCQASjAkAEowJABKMCQASjAkAEowJABKMCQASjAkAEowJABKMCQASjAkAEowJABKMCQASjAkAEowJABKMCQASjAkAEowJABKMCQAAAAAAAAAAAAAAAAAAAAAAEowJABKMCQASjAkAEowJABKMCQASjAkAEowJABKMCQASjAkAEowJABKMCQASjAkAEowJABKMCQASjAkAEowJABKMCQASjAkAEowJABKMCQASjAkAEowJABKMCQASjAkAEowJABKMCQASjAkAEowJABKMCQAAAAAAEowJABKMCQASjAkAEowJABKMCQASjAkAEowJABKMCQASjAkAAAAAABKMCQASjAkAEowJABKMCQASjAkAAAAAABKMCQASjAkAEowJABKMCQA==","text_start":1073905664,"data":"a5ACQG+RAkAbkgJAa5ACQGuSAkBvkQJA2pICQBCTAkBgkwJAvpMCQMCaAkDtkwJAwJoCQByUAkBrkAJAb5ECQBuSAkDGlAJA0pUCQF2RAkAClgJAWJYCQFmYAkBvkQJAvKYCQCKkAkADpwJAA6cCQAOnAkCnpgJAA6cCQAOnAkCtpgJAs6YCQLmmAkDA29zb3QA+AD8AQABBAEIAQwBEAEUARwBIAEkAAAAAAP83BgAAADgAAIjAKAAAAFMAAAGEAAAAAABAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAMAAAABAAAAAQAAAAAAAAADAAAAAAAAAAEAAAABAAAAAgAAAAIAAAACAAAAAwAAAAMAAAAAAAAAAAAAAAAAAAADAAAAAAAAAAMAAAAAAAAAAAAAAAAAAQACAAMABAAFAAYABwAIAAkACgALAAwADQAOAA8AEAARABIAEwAUABUAFgAXABgAGQAaABsAHAAdAB4AHwAgACEAIgAjACQAJQAmACcAKABfAF8AXwBfAC0ALgAvADAAMQAyADMANAA1ADYANwA4ADkAOgA7ADwAPQA+AD8AQABBAEIAQwBEAEUARgBHAEgASQBfAEsATABNAE4ATwBQAFEAUgBTAF8AVQBWAFcAWABZAF8AWwBcAF0AXgAAAA==","data_start":1073464320} \ No newline at end of file +{ + "entry": 1073905664, + "text": "NmEADAgQoSCJARARIOUAAKgBjEoQESBlAQAd8DZhAH0BKQeoByUCAD3wHfA2YQB9ASkHqAflAQA98B3wNmEAfQEpBz3wHfAANmEAfQEpBz3wHfAANmEAfQEpBz3wHfAA", + "text_start": 1073905664 +} \ No newline at end of file diff --git a/tools/esptool_py/esptool/targets/stub_flasher/2/esp32s3.json b/tools/esptool_py/esptool/targets/stub_flasher/2/esp32s3.json index 8be985b1b7..ea3f955ecc 100644 --- a/tools/esptool_py/esptool/targets/stub_flasher/2/esp32s3.json +++ b/tools/esptool_py/esptool/targets/stub_flasher/2/esp32s3.json @@ -1 +1,5 @@ -{"entry":1077391268,"text":"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HTAgEzIhHjAhEzIhHzAiEzIhIDAjEzIhJDDo8zIhJTDp8wMBJhMBJyMBKDMBKUMBKlMBK2MBLHMBLYMBLpMBL6MBMLMBMcMBMtMBM+MBNPMBNSIhBDIhBUIhBlIhB2IhCHIhCYIhCpIhC6IhDLIhDcIhDtIhD+IhEPIhEYAAAPBBAD3wEAEgEtH/AmEDANFJAOYDAmEBAOgDAmETAO4DAmEUALEDAmEAAMFJANEDAmECxeD/Adj+AOYTECAAYiETJkYIEHEgVSgARgQAAdP+AOYTECAAYqABEHEgVbX/he7/AiEBAOYTAiEAALETAiECEiEDECAAADAA8EEAEAEgEtH/AmEDANFJAOYDAmEBAOgDAmETAO4DAmEUAMADAmEAAMFJANcDAmECRdn/YiETEHEglSEABen/AiEBAOYTAiEAALETAiECEiEDECAAADIA8EEAABABIBLR/wJhAwDRSQDCAwJhAQCyAwJhAADBSQDSAwJhAoXU/wGp/gDmExAgAGKgAhBxIJWq/8Xj/wIhAQDCEwIhAACyEwIhAhIhAxAgABAyAPBBABABIBLR/wJhAwDRSQDDAwJhAQCzAwJhAADBSQDTAwJhAkXP/wGS/gDmExAgAGKgAxBxIFWl/4Xe/wIhAQDDEwIhAACzEwIhAhIhAxAgABAzAPBBABABIBLR/wJhAwDRSQDEAwJhAQC0AwJhAADBSQDUAwJhAgXK/wGA/gDmExAgAGKgBBBxINW//0XZ/wIhAQDEEwIhAAC0EwIhAhIhAxAgABA0APBBABABIBLR/wJhAwDRSQDFAwJhAQC1AwJhAADBSQDVAwJhAsXE/wFs/gDmExAgAGKgBRBxIJW7/wXU/wIhAQDFEwIhAAC1EwIhAhIhAxAgABA1APBBABABIBLR/wJhAwDRSQDGAwJhAQC2AwJhAADBSQDWAwJhAoW//wFY/gDmExAgAGKgBhBxIFW3/8XO/wIhAQDGEwIhAAC2EwIhAhIhAxAgABA2APBBABABIBLR/wJhAwDRSQDHAwJhAQC3AwJhAADBSQDXAwJhAkW6/wFE/gDmExAgAGKgBxBxIBWz/4XJ/wIhAQDHEwIhAAC3EwIhAhIhAxAgABA3APBBADZBAIEQ/q0CvQPgCAAd8AA2QQDwQQAAAISsN0CErDdAhKw3QISsN0CErDdAhKw3QISsN0CErDdAhKw3QISsN0CErDdAhKw3QISsN0CErDdAhKw3QISsN0CErDdAhKw3QISsN0CErDdAhKw3QISsN0CErDdAAAAAAISsN0CErDdAhKw3QISsN0CErDdAhKw3QISsN0CErDdAhKw3QAAAAAAAAAAAhKw3QISsN0CErDdAhKw3QISsN0CErDdAhKw3QISsN0CErDdAhKw3QISsN0AAAAAAhKw3QISsN0CErDdAhKw3QISsN0CErDdAhKw3QISsN0CErDdAhKw3QISsN0CErDdAhKw3QISsN0CErDdAhKw3QISsN0CErDdAhKw3QISsN0CErDdAhKw3QISsN0CErDdAhKw3QISsN0CErDdAhKw3QISsN0CErDdAhKw3QAAAAACErDdAhKw3QISsN0CErDdAhKw3QISsN0CErDdAhKw3QISsN0CErDdAhKw3QISsN0CErDdAhKw3QISsN0CErDdAhKw3QISsN0CErDdAhKw3QA==","text_start":1077379072,"data":"lZQ3QJmVN0BFljdAlZQ3QJWWN0CZlTdABJc3QDqXN0CKlzdA6Jc3QOmeN0AXmDdA6Z43QEaYN0CVlDdAmZU3QEWWN0DvmDdA+5k3QIeVN0ArmjdAgZo3QIGcN0CZlTdATK43QN+tN0BTrjdAU643QFOuN0A3rjdAU643QFOuN0A9rjdAQ643QEmuN0DA29zb3QAAAAAAAAD/NwYAAAA4AACIwCgAAABTAAABhAAAAAAAQAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAADAAAAAQAAAAEAAAAAAAAAAwAAAAAAAAABAAAAAQAAAAIAAAACAAAAAgAAAAMAAAADAAAAAAAAAAAAAAAAAAAAAwAAAAAAAAADAAAAAAAAAAAAAAAAAAEAAgADAAQABQAGAAcACAAJAAoACwAMAA0ADgAPABAAEQASABMAFAAVABYAYwAYABkAGgAbABwAHQAeAB8AIABjAGMAIwAkACUAJgAnACgAKQAqACsALAAtAGMALwAwADEAMgAzADQANQA2ADcAOAA5ADoAOwA8AD0APgA/AEAAQQBCAEMARABFAEYARwBIAEkASgBLAEwATQBjAE8AUABRAFIAUwBUAFUAVgBXAFgAWQBaAFsAXABdAF4AXwBgAGEAYgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAA==","data_start":1070137376} \ No newline at end of file +{ + "entry": 1077379072, + "text": "NmEADAgQoSCJARARIOUAAKgBjEoQESBlAQAd8DZhAH0BKQeoByUCAD3wHfA2YQB9ASkHqAflAQA98B3wNmEAfQEpBz3wHfAANmEAfQEpBz3wHfAANmEAfQEpBz3wHfAA", + "text_start": 1077379072 +} \ No newline at end of file diff --git a/tools/esptool_py/esptool/targets/stub_flasher/2/esp8266.json b/tools/esptool_py/esptool/targets/stub_flasher/2/esp8266.json new file mode 100644 index 0000000000..209c43c1ee --- /dev/null +++ b/tools/esptool_py/esptool/targets/stub_flasher/2/esp8266.json @@ -0,0 +1,5 @@ +{ + "entry": 1074843652, + "text": "qBAAQAH//0YAAAAAEsHgIqAAImEALQECYQcFAQAoAYwShQIACHESwSAN8AASweAJcflh/QEpDygPRQQAPfAdDwhx+GESwSAN8AAAABLB4Alx+WH9ASkPKA+FAwA98B0PCHH4YRLBIA3wAAAAEsHg+XH9ASkPPfAdD/hxEsEgDfASweD5cf0BKQ898B0P+HESwSAN8BLB4Plx/QEpDz3wHQ/4cRLBIA3w", + "text_start": 1074843648 +} \ No newline at end of file diff --git a/tools/esptool_py/esptool/targets/stub_flasher/stub_flasher_32.json b/tools/esptool_py/esptool/targets/stub_flasher/stub_flasher_32.json deleted file mode 100644 index 56221e30bd..0000000000 --- a/tools/esptool_py/esptool/targets/stub_flasher/stub_flasher_32.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "entry": 1074521580, - "text": "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", - "text_start": 1074520064, - "data": "DMD8P+znC0B/6AtAZ+0LQAbpC0Cf6AtABukLQGXpC0CC6gtA9OoLQJ3qC0CV5wtAGuoLQHTqC0CI6QtAGOsLQLDpC0AY6wtAbegLQMroC0AG6QtAZekLQIXoC0DI6wtAKe0LQLjmC0BL7QtAuOYLQLjmC0C45gtAuOYLQLjmC0C45gtAuOYLQLjmC0Bv6wtAuOYLQEnsC0Ap7QtA", - "data_start": 1073605544, - "bss_start": 1073528832 -} \ No newline at end of file diff --git a/tools/esptool_py/esptool/targets/stub_flasher/stub_flasher_32c2.json b/tools/esptool_py/esptool/targets/stub_flasher/stub_flasher_32c2.json deleted file mode 100644 index f10ec7b48e..0000000000 --- a/tools/esptool_py/esptool/targets/stub_flasher/stub_flasher_32c2.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "entry": 1077413304, - "text": "ARG3BwBgTsaDqYcASsg3Sco/JspSxAbOIsy3BABgfVoTCQkAwEwTdPQ/DeDyQGJEI6g0AUJJ0kSySSJKBWGCgIhAgycJABN19Q+Cl30U4xlE/8m/EwcADJRBqodjGOUAhUeFxiOgBQB5VYKABUdjh+YACUZjjcYAfVWCgEIFEwewDUGFY5XnAolHnMH1t5MGwA1jFtUAmMETBQAMgoCTBtANfVVjldcAmMETBbANgoC3dcs/QRGThQW6BsZhP2NFBQa3d8s/k4eHsQOnBwgD1kcIE3X1D5MGFgDCBsGCI5LXCDKXIwCnAAPXRwiRZ5OHBwRjHvcCN/fKPxMHh7GhZ7qXA6YHCLc2yz+3d8s/k4eHsZOGhrVjH+YAI6bHCCOg1wgjkgcIIaD5V+MG9fyyQEEBgoAjptcII6DnCN23NycAYHxLnYv1/zc3AGB8S52L9f+CgEERBsbdN7cnAGAjpgcCNwcACJjDmEN9/8hXskATRfX/BYlBAYKAQREGxtk/fd03BwBAtycAYJjDNycAYBxD/f+yQEEBgoBBESLEN8TKP5MHxABKwAOpBwEGxibCYwoJBEU3OcW9RxMExACBRGPWJwEERL2Ik7QUAH03hT8cRDcGgAATl8cAmeA3BgABt/b/AHWPtyYAYNjCkMKYQn3/QUeR4AVHMwnpQLqXIygkARzEskAiRJJEAklBAYKAQREGxhMHAAxjEOUCEwWwDZcAyP/ngIDjEwXADbJAQQEXA8j/ZwCD4hMHsA3jGOX+lwDI/+eAgOETBdANxbdBESLEJsIGxiqEswS1AGMXlACyQCJEkkRBAYKAA0UEAAUERTfttxMFAAwXA8j/ZwAD3nVxJsPO3v10hWn9cpOEhPqThwkHIsVKwdLc1tqmlwbHFpGzhCcAKokmhS6ElzDI/+eAgJOThwkHBWqKl7OKR0Ep5AVnfXUTBIX5kwcHB6KXM4QnABMFhfqTBwcHqpeihTOFJwCXMMj/54CAkCKFwUW5PwFFhWIWkbpAKkSaRApJ9llmWtZaSWGCgKKJY3OKAIVpTobWhUqFlwDI/+eAQOITdfUPAe1OhtaFJoWXMMj/54DAi06ZMwQ0QVm3EwUwBlW/cXH9ck7PUs1Wy17HBtci1SbTStFayWLFZsNqwe7eqokWkRMFAAIuirKKtosCwpcAyP/ngEBIhWdj7FcRhWR9dBMEhPqThwQHopczhCcAIoWXMMj/54AghX17Eww7+ZMMi/kThwQHk4cEB2KX5pcBSTMMJwCzjCcAEk1je00JY3GpA3mgfTWmhYgYSTVdNSaGjBgihZcwyP/ngCCBppkmmWN1SQOzB6lBY/F3A7MEKkFj85oA1oQmhowYToWXAMj/54Dg0xN19Q9V3QLEgUR5XY1NowEBAGKFlwDI/+eAYMR9+QNFMQDmhS0xY04FAOPinf6FZ5OHBweml4qX2pcjiqf4hQT5t+MWpf2RR+OG9PYFZ311kwcHBxMEhfmilzOEJwATBYX6kwcHB6qXM4UnAKKFlyDI/+eAgHflOyKFwUXxM8U7EwUAApcAyP/ngOA2hWIWkbpQKlSaVApZ+klqStpKSku6SypMmkwKTfZdTWGCgAERBs4izFExNwTOP2wAEwVE/5cAyP/ngKDKqocFRZXnskeT9wcgPsZ5OTcnAGAcR7cGQAATBUT/1Y8cx7JFlwDI/+eAIMgzNaAA8kBiRAVhgoBBEbfHyj8GxpOHxwAFRyOA5wAT18UAmMcFZ30XzMPIx/mNOpWqlbGBjMsjqgcAQTcZwRMFUAyyQEEBgoABESLMN8TKP5MHxAAmysRHTsYGzkrIqokTBMQAY/OVAK6EqcADKUQAJpkTWckAHEhjVfAAHERjXvkC4T593UhAJobOhZcAyP/ngCC7E3X1DwHFkwdADFzIXECml1zAXESFj1zE8kBiRNJEQkmySQVhgoDdNm2/t1dBSRlxk4f3hAFFPs6G3qLcptrK2M7W0tTW0trQ3s7izObK6sjuxpcAyP/ngICtt0fKPzd3yz+ThwcAEweHumPg5xSlOZFFaAixMYU5t/fKP5OHh7EhZz6XIyD3CLcFOEC3BzhAAUaThwcLk4UFADdJyj8VRSMg+QCXAMj/54DgGzcHAGBcRxMFAAK3xMo/k+cXEFzHlwDI/+eAoBq3RwBgiF+BRbd5yz9xiWEVEzUVAJcAyP/ngOCwwWf9FxMHABCFZkFmtwUAAQFFk4TEALdKyj8NapcAyP/ngOCrk4mJsRMJCQATi8oAJpqDp8kI9d+Dq8kIhUcjpgkIIwLxAoPHGwAJRyMT4QKjAvECAtRNR2OL5wZRR2OJ5wYpR2Of5wCDxzsAA8crAKIH2Y8RR2OW5wCDp4sAnEM+1EE2oUVIEJE+g8c7AAPHKwCiB9mPEWdBB2N+9wITBbANlwDI/+eAQJQTBcANlwDI/+eAgJMTBeAOlwDI/+eAwJKBNr23I6AHAJEHbb3JRyMT8QJ9twPHGwDRRmPn5gKFRmPm5gABTBME8A+dqHkXE3f3D8lG4+jm/rd2yz8KB5OGxro2lxhDAoeTBgcDk/b2DxFG42nW/BMH9wITd/cPjUZj7uYIt3bLPwoHk4aGvzaXGEMChxMHQAJjmucQAtQdRAFFlwDI/+eAIIoBRYE8TTxFPKFFSBB9FEk0ffABTAFEE3X0DyU8E3X8Dw08UTzjEQTsg8cbAElHY2X3MAlH43n36vUXk/f3Dz1H42P36jd3yz+KBxMHh8C6l5xDgocFRJ3rcBCBRQFFlwDI/+eAQIkd4dFFaBAVNAFEMagFRIHvlwDI/+eAwI0zNKAAKaAhR2OF5wAFRAFMYbcDrIsAA6TLALNnjADSB/X3mTll9cFsIpz9HH19MwWMQF3cs3eVAZXjwWwzBYxAY+aMAv18MwWMQF3QMYGXAMj/54Bgil35ZpT1tzGBlwDI/+eAYIld8WqU0bdBgZcAyP/ngKCIWfkzBJRBwbchR+OK5/ABTBMEAAw5t0FHzb9BRwVE453n9oOlywADpYsAVTK5v0FHBUTjk+f2A6cLAZFnY+jnHoOlSwEDpYsAMTGBt0FHBUTjlOf0g6cLARFnY2n3HAOnywCDpUsBA6WLADOE5wLdNiOsBAAjJIqwCb8DxwQAYwMHFAOniwDBFxMEAAxjE/cAwEgBR5MG8A5jRvcCg8dbAAPHSwABTKIH2Y8Dx2sAQgddj4PHewDiB9mP44T25hMEEAyFtTOG6wADRoYBBQexjuG3g8cEAP3H3ERjnQcUwEgjgAQAVb1hR2OW5wKDp8sBA6eLAYOmSwEDpgsBg6XLAAOliwCX8Mf/54BgeSqMMzSgAAG9AUwFRCm1EUcFROOd5+a3lwBgtENld30XBWb5jtGOA6WLALTDtEeBRfmO0Y60x/RD+Y7RjvTD1F91j1GP2N+X8Mf/54BAdwW1E/f3AOMXB+qT3EcAE4SLAAFMfV3jd5zbSESX8Mf/54DAYRhEVEAQQPmOYwenARxCE0f3/32P2Y4UwgUMQQTZvxFHtbVBRwVE45rn3oOniwADp0sBIyT5ACMi6QDJs4MlSQDBF5Hlic8BTBMEYAyhuwMniQBjZvcGE/c3AOMbB+IDKIkAAUYBRzMF6ECzhuUAY2n3AOMHBtIjJKkAIyLZAA2zM4brABBOEQeQwgVG6b8hRwVE45Tn2AMkiQAZwBMEgAwjJAkAIyIJADM0gAC9swFMEwQgDMW5AUwTBIAM5bEBTBMEkAzFsRMHIA1jg+cMEwdADeOR57oDxDsAg8crACIEXYyX8Mf/54BgXwOsxABBFGNzhAEijOMPDLbAQGKUMYCcSGNV8ACcRGNa9Arv8I/hdd3IQGKGk4WLAZfwx//ngGBbAcWTB0AM3MjcQOKX3MDcRLOHh0HcxJfwx//ngEBaFb4JZRMFBXEDrMsAA6SLAJfwx//ngEBMtwcAYNhLtwYAAcEWk1dHARIHdY+9i9mPs4eHAwFFs9WHApfwx//ngOBMEwWAPpfwx//ngOBI3bSDpksBA6YLAYOlywADpYsA7/Av98G8g8U7AIPHKwAThYsBogXdjcEVqTptvO/w79qBtwPEOwCDxysAE4yLASIEXYzcREEUxeORR4VLY/6HCJMHkAzcyHm0A6cNACLQBUizh+xAPtaDJ4qwY3P0AA1IQsY6xO/wb9YiRzJIN8XKP+KFfBCThsoAEBATBUUCl/DH/+eA4Ek398o/kwjHAIJXA6eIsIOlDQAdjB2PPpyyVyOk6LCqi76VI6C9AJOHygCdjQHFoWdjlvUAWoVdOCOgbQEJxNxEmcPjQHD5Y98LAJMHcAyFv4VLt33LP7fMyj+TjY26k4zMAOm/45ULntxE44IHnpMHgAyxt4OniwDjmwecAUWX8Mf/54DAOQllEwUFcZfwx//ngCA2l/DH/+eA4DlNugOkywDjBgSaAUWX8Mf/54AgNxMFgD6X8Mf/54CgMwKUQbr2UGZU1lRGWbZZJlqWWgZb9ktmTNZMRk22TQlhgoA=", - "text_start": 1077411840, - "data": "DEDKP+AIOEAsCThAhAk4QFIKOEC+CjhAbAo4QKgHOEAOCjhATgo4QJgJOEBYBzhAzAk4QFgHOEC6CDhA/gg4QCwJOECECThAzAg4QBIIOEBCCDhAyAg4QBYNOEAsCThA1gs4QMoMOECkBjhA9Aw4QKQGOECkBjhApAY4QKQGOECkBjhApAY4QKQGOECkBjhAcgs4QKQGOEDyCzhAygw4QA==", - "data_start": 1070295976, - "bss_start": 1070219264 -} \ No newline at end of file diff --git a/tools/esptool_py/esptool/targets/stub_flasher/stub_flasher_32c3.json b/tools/esptool_py/esptool/targets/stub_flasher/stub_flasher_32c3.json deleted file mode 100644 index 788ae646df..0000000000 --- a/tools/esptool_py/esptool/targets/stub_flasher/stub_flasher_32c3.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "entry": 1077413584, - "text": "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", - "text_start": 1077411840, - "data": "GEDIP8AKOEAQCzhAaAs4QDYMOECiDDhAUAw4QHIJOEDyCzhAMgw4QHwLOEAiCThAsAs4QCIJOECaCjhA4Ao4QBALOEBoCzhArAo4QNYJOEAgCjhAqAo4QPoOOEAQCzhAug04QLIOOEBiCDhA2g44QGIIOEBiCDhAYgg4QGIIOEBiCDhAYgg4QGIIOEBiCDhAVg04QGIIOEDYDThAsg44QA==", - "data_start": 1070164916, - "bss_start": 1070088192 -} \ No newline at end of file diff --git a/tools/esptool_py/esptool/targets/stub_flasher/stub_flasher_32c5beta3.json b/tools/esptool_py/esptool/targets/stub_flasher/stub_flasher_32c5beta3.json deleted file mode 100644 index 5266fcdc3c..0000000000 --- a/tools/esptool_py/esptool/targets/stub_flasher/stub_flasher_32c5beta3.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "entry": 1082132164, - "text": "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", - "text_start": 1082130432, - "data": "FACEQGwKgEC8CoBAFAuAQOILgEBODIBA/AuAQDgJgECeC4BA3guAQCgLgEDoCIBAXAuAQOgIgEBGCoBAjAqAQLwKgEAUC4BAWAqAQJwJgEDMCYBAVAqAQKYOgEC8CoBAZg2AQF4OgEAoCIBAhg6AQCgIgEAoCIBAKAiAQCgIgEAoCIBAKAiAQCgIgEAoCIBAAg2AQCgIgECEDYBAXg6AQA==", - "data_start": 1082469296, - "bss_start": 1082392576 -} \ No newline at end of file diff --git a/tools/esptool_py/esptool/targets/stub_flasher/stub_flasher_32c6.json b/tools/esptool_py/esptool/targets/stub_flasher/stub_flasher_32c6.json deleted file mode 100644 index b903b35215..0000000000 --- a/tools/esptool_py/esptool/targets/stub_flasher/stub_flasher_32c6.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "entry": 1082132164, - "text": "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", - "text_start": 1082130432, - "data": "FACEQHIKgEDCCoBAGguAQOgLgEBUDIBAAgyAQD4JgECkC4BA5AuAQC4LgEDuCIBAYguAQO4IgEBMCoBAkgqAQMIKgEAaC4BAXgqAQKIJgEDSCYBAWgqAQKwOgEDCCoBAbA2AQGQOgEAuCIBAjA6AQC4IgEAuCIBALgiAQC4IgEAuCIBALgiAQC4IgEAuCIBACA2AQC4IgECKDYBAZA6AQA==", - "data_start": 1082469296, - "bss_start": 1082392576 -} \ No newline at end of file diff --git a/tools/esptool_py/esptool/targets/stub_flasher/stub_flasher_32c6beta.json b/tools/esptool_py/esptool/targets/stub_flasher/stub_flasher_32c6beta.json deleted file mode 100644 index 7fd5c0ec6c..0000000000 --- a/tools/esptool_py/esptool/targets/stub_flasher/stub_flasher_32c6beta.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "entry": 1077413318, - "text": "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", - "text_start": 1077411840, - "data": "DEDIP/gIOEBECThAnAk4QGoKOEDWCjhAhAo4QMAHOEAmCjhAZgo4QLAJOEBwBzhA5Ak4QHAHOEDSCDhAFgk4QEQJOECcCThA5Ag4QCoIOEBaCDhA4Ag4QC4NOEBECThA7gs4QOIMOEC8BjhADA04QLwGOEC8BjhAvAY4QLwGOEC8BjhAvAY4QLwGOEC8BjhAigs4QLwGOEAKDDhA4gw4QA==", - "data_start": 1070164904, - "bss_start": 1070088192 -} \ No newline at end of file diff --git a/tools/esptool_py/esptool/targets/stub_flasher/stub_flasher_32h2.json b/tools/esptool_py/esptool/targets/stub_flasher/stub_flasher_32h2.json deleted file mode 100644 index 24964cde64..0000000000 --- a/tools/esptool_py/esptool/targets/stub_flasher/stub_flasher_32h2.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "entry": 1082132164, - "text": "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", - "text_start": 1082130432, - "data": "FACDQHIKgEDCCoBAGguAQOgLgEBUDIBAAgyAQD4JgECkC4BA5AuAQC4LgEDuCIBAYguAQO4IgEBMCoBAkgqAQMIKgEAaC4BAXgqAQKIJgEDSCYBAWgqAQKwOgEDCCoBAbA2AQGQOgEAuCIBAjA6AQC4IgEAuCIBALgiAQC4IgEAuCIBALgiAQC4IgEAuCIBACA2AQC4IgECKDYBAZA6AQA==", - "data_start": 1082403760, - "bss_start": 1082327040 -} \ No newline at end of file diff --git a/tools/esptool_py/esptool/targets/stub_flasher/stub_flasher_32h2beta1.json b/tools/esptool_py/esptool/targets/stub_flasher/stub_flasher_32h2beta1.json deleted file mode 100644 index 03e110c5c2..0000000000 --- a/tools/esptool_py/esptool/targets/stub_flasher/stub_flasher_32h2beta1.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "entry": 1077413318, - "text": "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", - "text_start": 1077411840, - "data": "DEDIP/gIOEBECThAnAk4QGoKOEDWCjhAhAo4QMAHOEAmCjhAZgo4QLAJOEBwBzhA5Ak4QHAHOEDSCDhAFgk4QEQJOECcCThA5Ag4QCoIOEBaCDhA4Ag4QC4NOEBECThA7gs4QOIMOEC8BjhADA04QLwGOEC8BjhAvAY4QLwGOEC8BjhAvAY4QLwGOEC8BjhAigs4QLwGOEAKDDhA4gw4QA==", - "data_start": 1070164904, - "bss_start": 1070088192 -} \ No newline at end of file diff --git a/tools/esptool_py/esptool/targets/stub_flasher/stub_flasher_32h2beta2.json b/tools/esptool_py/esptool/targets/stub_flasher/stub_flasher_32h2beta2.json deleted file mode 100644 index ce3afe7ac0..0000000000 --- a/tools/esptool_py/esptool/targets/stub_flasher/stub_flasher_32h2beta2.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "entry": 1077413318, - "text": "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", - "text_start": 1077411840, - "data": "DEDIP/gIOEBECThAnAk4QGoKOEDWCjhAhAo4QMAHOEAmCjhAZgo4QLAJOEBwBzhA5Ak4QHAHOEDSCDhAFgk4QEQJOECcCThA5Ag4QCoIOEBaCDhA4Ag4QC4NOEBECThA7gs4QOIMOEC8BjhADA04QLwGOEC8BjhAvAY4QLwGOEC8BjhAvAY4QLwGOEC8BjhAigs4QLwGOEAKDDhA4gw4QA==", - "data_start": 1070164904, - "bss_start": 1070088192 -} \ No newline at end of file diff --git a/tools/esptool_py/esptool/targets/stub_flasher/stub_flasher_32p4.json b/tools/esptool_py/esptool/targets/stub_flasher/stub_flasher_32p4.json deleted file mode 100644 index 6f37e91b27..0000000000 --- a/tools/esptool_py/esptool/targets/stub_flasher/stub_flasher_32p4.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "entry": 1341195918, - "text": "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", - "text_start": 1341194240, - "data": "EAD1TwYK8U9WCvFPrgrxT4QL8U/wC/FPngvxT9QI8U9AC/FPgAvxT8IK8U+ECPFP9grxT4QI8U/gCfFPJgrxT1YK8U+uCvFP8gnxTzgJ8U9oCfFP7gnxT0AO8U9WCvFPCA3xTwAO8U/EB/FPJA7xT8QH8U/EB/FPxAfxT8QH8U/EB/FPxAfxT8QH8U/EB/FPpAzxT8QH8U8mDfFPAA7xTw==", - "data_start": 1341533100, - "bss_start": 1341456384 -} \ No newline at end of file diff --git a/tools/esptool_py/esptool/targets/stub_flasher/stub_flasher_32s2.json b/tools/esptool_py/esptool/targets/stub_flasher/stub_flasher_32s2.json deleted file mode 100644 index 68de613890..0000000000 --- a/tools/esptool_py/esptool/targets/stub_flasher/stub_flasher_32s2.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "entry": 1073907716, - "text": "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", - "text_start": 1073905664, - "data": "WAD9P0uLAkDdiwJA8pACQGaMAkD+iwJAZowCQMWMAkDejQJAUY4CQPmNAkDVigJAd40CQNCNAkDojAJAdI4CQBCNAkB0jgJAy4sCQCqMAkBmjAJAxYwCQOOLAkAXiwJAN48CQKqQAkDqiQJA0ZACQOqJAkDqiQJA6okCQOqJAkDqiQJA6okCQOqJAkDqiQJA1I4CQOqJAkDJjwJAqpACQA==", - "data_start": 1073622012, - "bss_start": 1073545216 -} \ No newline at end of file diff --git a/tools/esptool_py/esptool/targets/stub_flasher/stub_flasher_32s3.json b/tools/esptool_py/esptool/targets/stub_flasher/stub_flasher_32s3.json deleted file mode 100644 index 484a8832fd..0000000000 --- a/tools/esptool_py/esptool/targets/stub_flasher/stub_flasher_32s3.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "entry": 1077381760, - "text": "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", - "text_start": 1077379072, - "data": "XADKP16ON0AzjzdAR5Q3QL2PN0BTjzdAvY83QB2QN0A6kTdArJE3QFWRN0DpjTdA0JA3QCyRN0BAkDdA0JE3QGiQN0DQkTdAIY83QH6PN0C9jzdAHZA3QDmPN0AqjjdAkJI3QA2UN0AAjTdALZQ3QACNN0AAjTdAAI03QACNN0AAjTdAAI03QACNN0AAjTdAKpI3QACNN0AlkzdADZQ3QAQInwAAAAAAAAAYAQQIBQAAAAAAAAAIAQQIBgAAAAAAAAAAAQQIIQAAAAAAIAAAEQQI3AAAAAAAIAAAEQQIDAAAAAAAIAAAAQQIEgAAAAAAIAAAESAoDAAQAQAA", - "data_start": 1070279676, - "bss_start": 1070202880 -} \ No newline at end of file diff --git a/tools/esptool_py/esptool/targets/stub_flasher/stub_flasher_32s3beta2.json b/tools/esptool_py/esptool/targets/stub_flasher/stub_flasher_32s3beta2.json deleted file mode 100644 index da770f7b97..0000000000 --- a/tools/esptool_py/esptool/targets/stub_flasher/stub_flasher_32s3beta2.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "entry": 1077380596, - "text": "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", - "text_start": 1077379072, - "data": "DADKPxeIN0CriDdAw403QDeJN0DLiDdAN4k3QJaJN0C2ijdAKIs3QNGKN0ChhzdASIo3QKiKN0C5iTdATIs3QOGJN0BMizdAmYg3QPiIN0A3iTdAlok3QLGIN0DjhzdABIw3QIWNN0DAhjdAp403QMCGN0DAhjdAwIY3QMCGN0DAhjdAwIY3QMCGN0DAhjdAqYs3QMCGN0CZjDdAhY03QA==", - "data_start": 1070279592, - "bss_start": 1070202880 -} \ No newline at end of file diff --git a/tools/esptool_py/esptool/targets/stub_flasher/stub_flasher_8266.json b/tools/esptool_py/esptool/targets/stub_flasher/stub_flasher_8266.json deleted file mode 100644 index f68ffef926..0000000000 --- a/tools/esptool_py/esptool/targets/stub_flasher/stub_flasher_8266.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "entry": 1074843652, - "text": "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", - "text_start": 1074843648, - "data": "CIH+PwUFBAACAwcAAwMLANTXEEAL2BBAOdgQQNbYEECF5xBAOtkQQJDZEEDc2RBAhecQQKLaEEAf2xBA4NsQQIXnEECF5xBAeNwQQIXnEEBV3xBAHOAQQFfgEECF5xBAhecQQPPgEECF5xBA2+EQQIHiEEDA4xBAf+QQQFDlEECF5xBAhecQQIXnEECF5xBAfuYQQIXnEEB05xBAsN0QQKnYEEDC5RBAydoQQBvaEECF5xBACOcQQE/nEECF5xBAhecQQIXnEECF5xBAhecQQIXnEECF5xBAhecQQELaEEB/2hBA2uUQQAEAAAACAAAAAwAAAAQAAAAFAAAABwAAAAkAAAANAAAAEQAAABkAAAAhAAAAMQAAAEEAAABhAAAAgQAAAMEAAAABAQAAgQEAAAECAAABAwAAAQQAAAEGAAABCAAAAQwAAAEQAAABGAAAASAAAAEwAAABQAAAAWAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAABAAAAAgAAAAIAAAADAAAAAwAAAAQAAAAEAAAABQAAAAUAAAAGAAAABgAAAAcAAAAHAAAACAAAAAgAAAAJAAAACQAAAAoAAAAKAAAACwAAAAsAAAAMAAAADAAAAA0AAAANAAAAAAAAAAAAAAADAAAABAAAAAUAAAAGAAAABwAAAAgAAAAJAAAACgAAAAsAAAANAAAADwAAABEAAAATAAAAFwAAABsAAAAfAAAAIwAAACsAAAAzAAAAOwAAAEMAAABTAAAAYwAAAHMAAACDAAAAowAAAMMAAADjAAAAAgEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAQAAAAEAAAABAAAAAgAAAAIAAAACAAAAAgAAAAMAAAADAAAAAwAAAAMAAAAEAAAABAAAAAQAAAAEAAAABQAAAAUAAAAFAAAABQAAAAAAAAAAAAAAAAAAABAREgAIBwkGCgULBAwDDQIOAQ8AAQEAAAEAAAAEAAAA", - "data_start": 1073720488, - "bss_start": 1073643776 -} \ No newline at end of file diff --git a/tools/esptool_py/esptool/uf2_writer.py b/tools/esptool_py/esptool/uf2_writer.py index 81772d4249..e972fa2231 100644 --- a/tools/esptool_py/esptool/uf2_writer.py +++ b/tools/esptool_py/esptool/uf2_writer.py @@ -1,11 +1,9 @@ -# SPDX-FileCopyrightText: 2020-2023 Espressif Systems (Shanghai) CO LTD +# SPDX-FileCopyrightText: 2020-2025 Espressif Systems (Shanghai) CO LTD # SPDX-License-Identifier: GPL-2.0-or-later # Code was originally licensed under Apache 2.0 before the release of ESP-IDF v5.2 import hashlib -import os import struct -from typing import List from esptool.util import div_roundup @@ -25,8 +23,8 @@ class UF2Writer(object): def __init__( self, chip_id: int, - output_file: os.PathLike, - chunk_size: int, + output_file: str, + chunk_size: int | None, md5_enabled: bool = True, ) -> None: if not md5_enabled: @@ -44,7 +42,7 @@ def __init__( def __enter__(self) -> "UF2Writer": return self - def __exit__(self, exc_type: str, exc_val: int, exc_tb: List) -> None: + def __exit__(self, exc_type: str, exc_val: int, exc_tb: list) -> None: if self.f: self.f.close() diff --git a/tools/esptool_py/esptool/util.py b/tools/esptool_py/esptool/util.py index 1527618854..73e448c82a 100644 --- a/tools/esptool_py/esptool/util.py +++ b/tools/esptool_py/esptool/util.py @@ -1,12 +1,16 @@ -# SPDX-FileCopyrightText: 2014-2022 Fredrik Ahlberg, Angus Gratton, +# SPDX-FileCopyrightText: 2014-2025 Fredrik Ahlberg, Angus Gratton, # Espressif Systems (Shanghai) CO LTD, other contributors as noted. # # SPDX-License-Identifier: GPL-2.0-or-later - +from __future__ import annotations import os import re import struct -import sys + +from typing import IO, TypeAlias + +# Define a custom type for the input +ImageSource: TypeAlias = str | bytes | IO[bytes] def byte(bitstr, index): @@ -31,7 +35,7 @@ def div_roundup(a, b): def flash_size_bytes(size): - """Given a flash size of the type passed in args.flash_size + """Given a flash size of the type passed in size (ie 512KB or 1MB) then return the size in bytes. """ if size is None: @@ -41,7 +45,7 @@ def flash_size_bytes(size): elif "KB" in size: return int(size[: size.index("KB")]) * 1024 else: - raise FatalError("Unknown size %s" % size) + raise FatalError(f"Unknown size {size}") def hexify(s, uppercase=True): @@ -49,7 +53,7 @@ def hexify(s, uppercase=True): return "".join(format_str % c for c in s) -def pad_to(data, alignment, pad_character=b"\xFF"): +def pad_to(data, alignment, pad_character=b"\xff"): """Pad to the next alignment boundary""" pad_mod = len(data) % alignment if pad_mod != 0: @@ -57,23 +61,6 @@ def pad_to(data, alignment, pad_character=b"\xFF"): return data -def print_overwrite(message, last_line=False): - """Print a message, overwriting the currently printed line. - - If last_line is False, don't append a newline at the end - (expecting another subsequent call will overwrite this one.) - - After a sequence of calls with last_line=False, call once with last_line=True. - - If output is not a TTY (for example redirected a pipe), - no overwriting happens and this function is the same as print(). - """ - if hasattr(sys.stdout, "isatty") and sys.stdout.isatty(): - print("\r%s" % message, end="\n" if last_line else "") - else: - print(message) - - def expand_chip_name(chip_name): """Change chip name to official form, e.g. `esp32s3beta2` -> `ESP32-S3(beta2)`""" # Put "-" after "esp32" @@ -99,17 +86,73 @@ def get_file_size(path_to_file): return file_size +def sanitize_string(byte_string): + return byte_string.decode("utf-8").replace("\0", "") + + +def get_bytes(input: ImageSource) -> tuple[bytes, str | None]: + """ + Normalize the input (file path, bytes, or an opened file-like object) into bytes + and provide a name of the source. + + Args: + input: The input file path, bytes, or an opened file-like object. + + Returns: + A tuple containing the normalized bytes and the source of the input. + """ + if isinstance(input, str): + with open(input, "rb") as f: + data = f.read() + source = input + elif isinstance(input, bytes): + data = input + source = None + elif hasattr(input, "read") and hasattr(input, "write") and hasattr(input, "close"): + pos = input.tell() + data = input.read() + input.seek(pos) # Reset the file pointer + source = input.name + else: + raise FatalError(f"Invalid input type {type(input)}") + return data, source + + +def get_key_from_value(dict, val): + """ + Get key from value in dictionary, assumes unique values in dictionary + """ + for key, value in dict.items(): + if value == val: + return key + return None + + +def check_deprecated_py_suffix(module_name: str) -> None: + """Check if called with deprecated .py suffix""" + import sys + from esptool import log + + script_name = sys.argv[0] if sys.argv else "" + if script_name.endswith(module_name + ".py"): + log.warning( + f"DEPRECATED: '{module_name}.py' is deprecated. Please use '{module_name}' " + "instead. The '.py' suffix will be removed in a future major release." + ) + + class PrintOnce: """ Class for printing messages just once. Can be useful when running in a loop """ - def __init__(self) -> None: + def __init__(self, print_callback) -> None: self.already_printed = False + self.print_callback = print_callback def __call__(self, text) -> None: if not self.already_printed: - print(text) + self.print_callback(text) self.already_printed = True diff --git a/tools/esptool_py/flasher_stub/Makefile b/tools/esptool_py/flasher_stub/Makefile deleted file mode 100644 index 1d78f4d0cc..0000000000 --- a/tools/esptool_py/flasher_stub/Makefile +++ /dev/null @@ -1,187 +0,0 @@ -# Makefile to compile the flasher stub program -# -# Note that YOU DO NOT NEED TO COMPILE THIS IN ORDER TO JUST USE -# esptool.py - a precompiled version is included in esptool.py, -# so if you don't want to modify the stub code then you are good to go. -# -# See the comments in the top of the Makefile for parameters that -# you probably want to override. -# -# Copyright (c) 2016 Cesanta Software Limited & Angus Gratton -# All rights reserved -# -# -# This program is free software; you can redistribute it and/or modify it under -# the terms of the GNU General Public License as published by the Free Software -# Foundation; either version 2 of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License along with -# this program; if not, write to the Free Software Foundation, Inc., 51 Franklin -# Street, Fifth Floor, Boston, MA 02110-1301 USA. - -# Adapted from Cesanta's original Makefile at -# https://github.com/cesanta/fnc/tree/master/common/platforms/esp8266/stubs - -# Override these variables on the command line -# or set them in a local.mk --include local.mk - -# Prefix for each cross compiler (can include a directory path) -# These can be overridden via environment variables or on the make command line -CROSS_8266 ?= xtensa-lx106-elf- -CROSS_32 ?= xtensa-esp32-elf- -CROSS_32S2 ?= xtensa-esp32s2-elf- -CROSS_32S3 ?= xtensa-esp32s3-elf- -CROSS_ESPRISCV32 ?= riscv32-esp-elf- - -# extra CFLAGS to be passed on the compiler, in addition to the stock ones -EXTRA_CFLAGS ?= -EXTRA_CFLAGS_ESPRISCV32 ?= - -# Python command to invoke wrap_stub.py -WRAP_STUB ?= ./wrap_stub.py - -# Pass V=1 to see the commands being executed by make -ifneq ("$(V)","1") -Q = @ -endif - -STUB = stub_flasher -SRCS = stub_flasher.c slip.c stub_commands.c stub_write_flash.c stub_io.c -SRCS_8266 = miniz.c - -BUILD_DIR = build -ESPTOOL_STUBS_DIR = ../esptool/targets/stub_flasher - -STUB_ELF_8266 = $(BUILD_DIR)/$(STUB)_8266.elf -STUB_ELF_32 = $(BUILD_DIR)/$(STUB)_32.elf -STUB_ELF_32S2 = $(BUILD_DIR)/$(STUB)_32s2.elf -STUB_ELF_32S3_BETA_2 = $(BUILD_DIR)/$(STUB)_32s3beta2.elf -STUB_ELF_32S3 = $(BUILD_DIR)/$(STUB)_32s3.elf -STUB_ELF_32C3 = $(BUILD_DIR)/$(STUB)_32c3.elf -STUB_ELF_32C6BETA = $(BUILD_DIR)/$(STUB)_32c6beta.elf -STUB_ELF_32H2_BETA_1 = $(BUILD_DIR)/$(STUB)_32h2beta1.elf -STUB_ELF_32H2_BETA_2 = $(BUILD_DIR)/$(STUB)_32h2beta2.elf -STUB_ELF_32C2 = $(BUILD_DIR)/$(STUB)_32c2.elf -STUB_ELF_32C6 = $(BUILD_DIR)/$(STUB)_32c6.elf -STUB_ELF_32C5_BETA_3 = $(BUILD_DIR)/$(STUB)_32c5beta3.elf -STUB_ELF_32H2 = $(BUILD_DIR)/$(STUB)_32h2.elf -STUB_ELF_32P4 = $(BUILD_DIR)/$(STUB)_32p4.elf - -STUBS_ELF = -ifneq ($(WITHOUT_ESP8266),1) -STUBS_ELF += \ - $(STUB_ELF_8266) -endif - -ifneq ($(WITHOUT_ESP32_XTENSA),1) -STUBS_ELF += \ - $(STUB_ELF_32) \ - $(STUB_ELF_32S2) \ - $(STUB_ELF_32S3_BETA_2) \ - $(STUB_ELF_32S3) -endif - -ifneq ($(WITHOUT_ESP32_RISCV32),1) -STUBS_ELF += \ - $(STUB_ELF_32C3) \ - $(STUB_ELF_32C6BETA) \ - $(STUB_ELF_32H2_BETA_1) \ - $(STUB_ELF_32H2_BETA_2) \ - $(STUB_ELF_32C2) \ - $(STUB_ELF_32C6) \ - $(STUB_ELF_32C5_BETA_3) \ - $(STUB_ELF_32H2) \ - $(STUB_ELF_32P4) -endif - -.PHONY: all clean install - -all: $(STUBS_ELF:.elf=.json) - -install: $(patsubst $(BUILD_DIR)/%.elf,$(ESPTOOL_STUBS_DIR)/%.json,$(STUBS_ELF)) - -$(BUILD_DIR): - $(Q) mkdir $@ - -$(BUILD_DIR)/%.json: $(BUILD_DIR)/%.elf - @echo " WRAP $^ -> $(BUILD_DIR)" - $(Q) $(WRAP_STUB) $^ - -$(ESPTOOL_STUBS_DIR)/%.json: $(BUILD_DIR)/%.json - @echo " INSTALL $^ -> $@" - $(Q) cp $^ $@ - -CFLAGS = -std=c99 -Wall -Werror -Os \ - -mtext-section-literals -mlongcalls -nostdlib -fno-builtin -flto \ - -Wl,-static -g -ffunction-sections -Wl,--gc-sections -Iinclude -Lld \ - $(EXTRA_CFLAGS) -CFLAGS_ESPRISCV32 = -std=c99 -Wall -Werror -Os \ - -march=rv32imc -mabi=ilp32 -msmall-data-limit=0 \ - -nostdlib -fno-builtin -flto \ - -Wl,-static -g -ffunction-sections -Wl,--gc-sections -Iinclude -Lld \ - $(EXTRA_CFLAGS_ESPRISCV32) -LDLIBS = -lgcc - -$(STUB_ELF_8266): $(SRCS) $(SRCS_8266) $(BUILD_DIR) ld/stub_8266.ld | Makefile - @echo " CC(8266) $^ -> $@" - $(Q) $(CROSS_8266)gcc $(CFLAGS) -DESP8266=1 -Tstub_8266.ld -Wl,-Map=$(@:.elf=.map) -o $@ $(filter %.c, $^) $(LDLIBS) - -$(STUB_ELF_32): $(SRCS) $(BUILD_DIR) ld/stub_32.ld | Makefile - @echo " CC(32) $^ -> $@" - $(Q) $(CROSS_32)gcc $(CFLAGS) -DESP32=1 -Tstub_32.ld -Wl,-Map=$(@:.elf=.map) -o $@ $(filter %.c, $^) $(LDLIBS) - -$(STUB_ELF_32S2): $(SRCS) $(BUILD_DIR) ld/stub_32s2.ld - @echo " CC(32S2) $^ -> $@" - $(Q) $(CROSS_32S2)gcc $(CFLAGS) -DESP32S2=1 -Tstub_32s2.ld -Wl,-Map=$(@:.elf=.map) -o $@ $(filter %.c, $^) $(LDLIBS) - -$(STUB_ELF_32S3_BETA_2): $(SRCS) $(BUILD_DIR) ld/stub_32s3_beta_2.ld - @echo " CC(32S3) $^ -> $@" - $(Q) $(CROSS_32S3)gcc $(CFLAGS) -DESP32S3BETA2=1 -Tstub_32s3_beta_2.ld -Wl,-Map=$(@:.elf=.map) -o $@ $(filter %.c, $^) $(LDLIBS) - -$(STUB_ELF_32S3): $(SRCS) $(BUILD_DIR) ld/stub_32s3.ld - @echo " CC(32S3) $^ -> $@" - $(Q) $(CROSS_32S3)gcc $(CFLAGS) -DESP32S3=1 -Tstub_32s3.ld -Wl,-Map=$(@:.elf=.map) -o $@ $(filter %.c, $^) $(LDLIBS) - -$(STUB_ELF_32C3): $(SRCS) $(BUILD_DIR) ld/stub_32c3.ld - @echo " CC(32C3) $^ -> $@" - $(Q) $(CROSS_ESPRISCV32)gcc $(CFLAGS_ESPRISCV32) -DESP32C3=1 -Tstub_32c3.ld -Wl,-Map=$(@:.elf=.map) -o $@ $(filter %.c, $^) $(LDLIBS) - -$(STUB_ELF_32C6BETA): $(SRCS) $(BUILD_DIR) ld/stub_32c6_beta.ld - @echo " CC(32C6BETA) $^ -> $@" - $(Q) $(CROSS_ESPRISCV32)gcc $(CFLAGS_ESPRISCV32) -DESP32C6BETA=1 -Tstub_32c6_beta.ld -Wl,-Map=$(@:.elf=.map) -o $@ $(filter %.c, $^) $(LDLIBS) - -$(STUB_ELF_32H2_BETA_1): $(SRCS) $(BUILD_DIR) ld/stub_32h2_beta_1.ld - @echo " CC(32H2BETA1) $^ -> $@" - $(Q) $(CROSS_ESPRISCV32)gcc $(CFLAGS_ESPRISCV32) -DESP32H2BETA1=1 -Tstub_32h2_beta_1.ld -Wl,-Map=$(@:.elf=.map) -o $@ $(filter %.c, $^) $(LDLIBS) - -$(STUB_ELF_32H2_BETA_2): $(SRCS) $(BUILD_DIR) ld/stub_32h2_beta_2.ld - @echo " CC(32H2BETA2) $^ -> $@" - $(Q) $(CROSS_ESPRISCV32)gcc $(CFLAGS_ESPRISCV32) -DESP32H2BETA2=1 -Tstub_32h2_beta_2.ld -Wl,-Map=$(@:.elf=.map) -o $@ $(filter %.c, $^) $(LDLIBS) - -$(STUB_ELF_32C2): $(SRCS) $(BUILD_DIR) ld/stub_32c2.ld - @echo " CC(32C2) $^ -> $@" - $(Q) $(CROSS_ESPRISCV32)gcc $(CFLAGS_ESPRISCV32) -DESP32C2=1 -Tstub_32c2.ld -Wl,-Map=$(@:.elf=.map) -o $@ $(filter %.c, $^) $(LDLIBS) - -$(STUB_ELF_32C6): $(SRCS) $(BUILD_DIR) ld/stub_32c6.ld - @echo " CC(32C6) $^ -> $@" - $(Q) $(CROSS_ESPRISCV32)gcc $(CFLAGS_ESPRISCV32) -DESP32C6=1 -Tstub_32c6.ld -Wl,-Map=$(@:.elf=.map) -o $@ $(filter %.c, $^) $(LDLIBS) - -$(STUB_ELF_32C5_BETA_3): $(SRCS) $(BUILD_DIR) ld/stub_32c5_beta_3.ld - @echo " CC(32C5BETA3) $^ -> $@" - $(Q) $(CROSS_ESPRISCV32)gcc $(CFLAGS_ESPRISCV32) -DESP32C5BETA3=1 -Tstub_32c5_beta_3.ld -Wl,-Map=$(@:.elf=.map) -o $@ $(filter %.c, $^) $(LDLIBS) - -$(STUB_ELF_32H2): $(SRCS) $(BUILD_DIR) ld/stub_32h2.ld - @echo " CC(32H2) $^ -> $@" - $(Q) $(CROSS_ESPRISCV32)gcc $(CFLAGS_ESPRISCV32) -DESP32H2=1 -Tstub_32h2.ld -Wl,-Map=$(@:.elf=.map) -o $@ $(filter %.c, $^) $(LDLIBS) - -$(STUB_ELF_32P4): $(SRCS) $(BUILD_DIR) ld/stub_32p4.ld - @echo " CC(32P4) $^ -> $@" - $(Q) $(CROSS_ESPRISCV32)gcc $(CFLAGS_ESPRISCV32) -DESP32P4=1 -Tstub_32p4.ld -Wl,-Map=$(@:.elf=.map) -o $@ $(filter %.c, $^) $(LDLIBS) - -clean: - $(Q) rm -rf $(BUILD_DIR) diff --git a/tools/esptool_py/flasher_stub/README.md b/tools/esptool_py/flasher_stub/README.md deleted file mode 100644 index 052909c3f5..0000000000 --- a/tools/esptool_py/flasher_stub/README.md +++ /dev/null @@ -1,41 +0,0 @@ -This is the source of the software flasher stub. - -esptool.py loads the flasher stub into memory and executes it to: - -* Add features that the Espressif chips bootloader ROMs do not have. - -* Add features to the ESP8266 bootloader ROM which are only in the ROM of newer chips. - -* Improve flashing performance over the ROM bootloaders. - -* Work around bugs in the ESP8266 ROM bootloader. - -Thanks to [Cesanta](http://cesanta.com/) who provided the original ESP8266 stub loader upon which this loader is based. - -# To Use - -The stub loader is already automatically integrated into esptool.py. You don't need to do anything special to use it. - -# To Build - -If you want to build the stub to test modifications or updates, here's how: - -* You will need an ESP8266 gcc toolchain (xtensa-lx106-elf-) and toolchains for ESP32 and later chips (xtensa-esp32-elf-, riscv32-esp-elf-) on your PATH. If you are developing the stub flasher and plan to send a pull request, please use the latest toolchains available. - -* Set the environment variables SDK_PATH to the path to an ESP8266 IoT NON-OS SDK directory (last stub was built with SDK v1.5.1). - -* Set the environment variable IDF_PATH to the path to an ESP-IDF directory. - -* Set any other environment variables you'd like to override in the Makefile. - -* To build type `make`. To build only for the ESP32 family, type `make WITHOUT_ESP8266=1` (this negates the need of an ESP8266 toolchain). - -Activating an ESP-IDF environment takes care of most of these steps (only the ESP8266 gcc toolchain has to be manually added to PATH). - -# To Test - -To test the built stub, you can run `make install` (or `make install WITHOUT_ESP8266=1`), which will update the stubs in `esptool.py` to the newly compiled ones. Or there are some convenience wrappers to make testing quicker to iterate on: - -* Running `esptool_test_stub.py` is the same as running `esptool.py`, only it uses the just-compiled stubs from the build directory. - -* Running `run_tests_with_stub.sh` is the same as running `pytest test/test_esptool.py`, only it uses the just-compiled stubs from the build directory. See the [Automated Integration Tests](https://docs.espressif.com/projects/esptool/en/latest/contributing.html#automated-integration-tests) docs for more information. diff --git a/tools/esptool_py/flasher_stub/compare_stubs.py b/tools/esptool_py/flasher_stub/compare_stubs.py deleted file mode 100755 index 74843f0fb4..0000000000 --- a/tools/esptool_py/flasher_stub/compare_stubs.py +++ /dev/null @@ -1,97 +0,0 @@ -#!/usr/bin/env python -# -# SPDX-FileCopyrightText: 2014-2022 Fredrik Ahlberg, Angus Gratton, -# Espressif Systems (Shanghai) CO LTD, other contributors as noted. -# -# SPDX-License-Identifier: GPL-2.0-or-later - -import os -import sys - -import esptool - -# Compare the esptool stub loaders to freshly built ones in the build directory -# -# (Used by CI to verify the stubs are up to date.) - -THIS_SCRIPT_DIR = os.path.dirname(__file__) -STUB_DIR = "../esptool/targets/stub_flasher/" -BUILD_DIR = "build/" -JSON_NAME = "stub_flasher_{}.json" - - -def diff(path_to_new, path_to_old): - output = "" - new = esptool.loader.StubFlasher(path_to_new) - old = esptool.loader.StubFlasher(path_to_old) - - if new.data_start != old.data_start: - output += " Data start: New {:#x}, old {:#x} \n".format( - new.data_start, old.data_start - ) - if new.text_start != old.text_start: - output += " Text start: New {:#x}, old {:#x} \n".format( - new.text_start, old.text_start - ) - if new.entry != old.entry: - output += " Entrypoint: New {:#x}, old {:#x} \n".format(new.entry, old.entry) - - # data - if new.data != old.data: - if len(new.data) == len(old.data): - for i, (new_b, old_b) in enumerate(zip(new.data, old.data)): - if new_b != old_b: - output += " Data byte {:#x}: new {:#04x} old {:#04x} \n".format( - i, new_b, old_b - ) - else: - output += " Data length: New {} bytes, old {} bytes \n".format( - len(new.data), len(old.data) - ) - - # text - if new.text != old.text: - if len(new.text) == len(old.text): - for i, (new_b, old_b) in enumerate(zip(new.text, old.text)): - if new_b != old_b: - output += " Text byte {:#x}: new {:#04x} old {:#04x} \n".format( - i, new_b, old_b - ) - else: - output += " Text length: New {} bytes, old {} bytes \n".format( - len(new.text), len(old.text) - ) - return output - - -if __name__ == "__main__": - same = True - for chip in esptool.CHIP_LIST: - print("Comparing {} stub: ".format(chip), end="") - # TODO: [ESP32C5] ESPTOOL-825 remove when supported stub flasher - # TODO: [ESP32C61] IDF-9241 remove when supported stub flasher - if chip in ["esp32c5", "esp32c61"]: - print(f"{chip} has not supported stub yet, skipping...") - continue - - chip = chip.replace("esp", "") - old = os.path.join(THIS_SCRIPT_DIR, STUB_DIR, JSON_NAME.format(chip)) - new = os.path.join(THIS_SCRIPT_DIR, BUILD_DIR, JSON_NAME.format(chip)) - - output = diff(new, old) - if output != "": - same = False - print("FAIL") - print( - " Mismatch: {} json file in esptool/targets/stub_flasher/ differs " - "from the just-built stub".format("esp" + chip) - ) - print(output) - else: - print("OK") - - if not same: - sys.exit(1) - else: - print("Stub flasher json files are the same") - sys.exit(0) diff --git a/tools/esptool_py/flasher_stub/esptool_test_stub.py b/tools/esptool_py/flasher_stub/esptool_test_stub.py deleted file mode 100755 index 691495e11b..0000000000 --- a/tools/esptool_py/flasher_stub/esptool_test_stub.py +++ /dev/null @@ -1,36 +0,0 @@ -#!/usr/bin/env python -# -# SPDX-FileCopyrightText: 2014-2022 Fredrik Ahlberg, Angus Gratton, -# Espressif Systems (Shanghai) CO LTD, other contributors as noted. -# -# SPDX-License-Identifier: GPL-2.0-or-later -# -# Trivial wrapper program to run esptool.py using the just-compiled -# flasher stub in the build/ subdirectory -# -# For use when developing new flasher_stubs, not important otherwise. - -import os.path -import sys - -THIS_DIR = os.path.dirname(__file__) -STUBS_BUILD_DIR = os.path.join(THIS_DIR, "build/") - -sys.path.append("..") -import esptool # noqa: E402 - -# Python hackiness: change the path to stub json files in the context of the esptool -# module, so it edits the esptool's global variables -exec( - "loader.STUBS_DIR = '{}'".format(STUBS_BUILD_DIR), - esptool.__dict__, - esptool.__dict__, -) - - -if __name__ == "__main__": - try: - esptool.main() - except esptool.FatalError as e: - print("\nA fatal error occurred: %s" % e) - sys.exit(2) diff --git a/tools/esptool_py/flasher_stub/include/miniz.h b/tools/esptool_py/flasher_stub/include/miniz.h deleted file mode 100644 index bf1554a06e..0000000000 --- a/tools/esptool_py/flasher_stub/include/miniz.h +++ /dev/null @@ -1,1342 +0,0 @@ -/* miniz.c 2.1.0 - public domain deflate/inflate, zlib-subset, ZIP reading/writing/appending, PNG writing - See "unlicense" statement at the end of this file. - Rich Geldreich , last updated Oct. 13, 2013 - Implements RFC 1950: http://www.ietf.org/rfc/rfc1950.txt and RFC 1951: http://www.ietf.org/rfc/rfc1951.txt - - Most API's defined in miniz.c are optional. For example, to disable the archive related functions just define - MINIZ_NO_ARCHIVE_APIS, or to get rid of all stdio usage define MINIZ_NO_STDIO (see the list below for more macros). - - * Low-level Deflate/Inflate implementation notes: - - Compression: Use the "tdefl" API's. The compressor supports raw, static, and dynamic blocks, lazy or - greedy parsing, match length filtering, RLE-only, and Huffman-only streams. It performs and compresses - approximately as well as zlib. - - Decompression: Use the "tinfl" API's. The entire decompressor is implemented as a single function - coroutine: see tinfl_decompress(). It supports decompression into a 32KB (or larger power of 2) wrapping buffer, or into a memory - block large enough to hold the entire file. - - The low-level tdefl/tinfl API's do not make any use of dynamic memory allocation. - - * zlib-style API notes: - - miniz.c implements a fairly large subset of zlib. There's enough functionality present for it to be a drop-in - zlib replacement in many apps: - The z_stream struct, optional memory allocation callbacks - deflateInit/deflateInit2/deflate/deflateReset/deflateEnd/deflateBound - inflateInit/inflateInit2/inflate/inflateReset/inflateEnd - compress, compress2, compressBound, uncompress - CRC-32, Adler-32 - Using modern, minimal code size, CPU cache friendly routines. - Supports raw deflate streams or standard zlib streams with adler-32 checking. - - Limitations: - The callback API's are not implemented yet. No support for gzip headers or zlib static dictionaries. - I've tried to closely emulate zlib's various flavors of stream flushing and return status codes, but - there are no guarantees that miniz.c pulls this off perfectly. - - * PNG writing: See the tdefl_write_image_to_png_file_in_memory() function, originally written by - Alex Evans. Supports 1-4 bytes/pixel images. - - * ZIP archive API notes: - - The ZIP archive API's where designed with simplicity and efficiency in mind, with just enough abstraction to - get the job done with minimal fuss. There are simple API's to retrieve file information, read files from - existing archives, create new archives, append new files to existing archives, or clone archive data from - one archive to another. It supports archives located in memory or the heap, on disk (using stdio.h), - or you can specify custom file read/write callbacks. - - - Archive reading: Just call this function to read a single file from a disk archive: - - void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename, const char *pArchive_name, - size_t *pSize, mz_uint zip_flags); - - For more complex cases, use the "mz_zip_reader" functions. Upon opening an archive, the entire central - directory is located and read as-is into memory, and subsequent file access only occurs when reading individual files. - - - Archives file scanning: The simple way is to use this function to scan a loaded archive for a specific file: - - int mz_zip_reader_locate_file(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags); - - The locate operation can optionally check file comments too, which (as one example) can be used to identify - multiple versions of the same file in an archive. This function uses a simple linear search through the central - directory, so it's not very fast. - - Alternately, you can iterate through all the files in an archive (using mz_zip_reader_get_num_files()) and - retrieve detailed info on each file by calling mz_zip_reader_file_stat(). - - - Archive creation: Use the "mz_zip_writer" functions. The ZIP writer immediately writes compressed file data - to disk and builds an exact image of the central directory in memory. The central directory image is written - all at once at the end of the archive file when the archive is finalized. - - The archive writer can optionally align each file's local header and file data to any power of 2 alignment, - which can be useful when the archive will be read from optical media. Also, the writer supports placing - arbitrary data blobs at the very beginning of ZIP archives. Archives written using either feature are still - readable by any ZIP tool. - - - Archive appending: The simple way to add a single file to an archive is to call this function: - - mz_bool mz_zip_add_mem_to_archive_file_in_place(const char *pZip_filename, const char *pArchive_name, - const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags); - - The archive will be created if it doesn't already exist, otherwise it'll be appended to. - Note the appending is done in-place and is not an atomic operation, so if something goes wrong - during the operation it's possible the archive could be left without a central directory (although the local - file headers and file data will be fine, so the archive will be recoverable). - - For more complex archive modification scenarios: - 1. The safest way is to use a mz_zip_reader to read the existing archive, cloning only those bits you want to - preserve into a new archive using using the mz_zip_writer_add_from_zip_reader() function (which compiles the - compressed file data as-is). When you're done, delete the old archive and rename the newly written archive, and - you're done. This is safe but requires a bunch of temporary disk space or heap memory. - - 2. Or, you can convert an mz_zip_reader in-place to an mz_zip_writer using mz_zip_writer_init_from_reader(), - append new files as needed, then finalize the archive which will write an updated central directory to the - original archive. (This is basically what mz_zip_add_mem_to_archive_file_in_place() does.) There's a - possibility that the archive's central directory could be lost with this method if anything goes wrong, though. - - - ZIP archive support limitations: - No zip64 or spanning support. Extraction functions can only handle unencrypted, stored or deflated files. - Requires streams capable of seeking. - - * This is a header file library, like stb_image.c. To get only a header file, either cut and paste the - below header, or create miniz.h, #define MINIZ_HEADER_FILE_ONLY, and then include miniz.c from it. - - * Important: For best perf. be sure to customize the below macros for your target platform: - #define MINIZ_USE_UNALIGNED_LOADS_AND_STORES 1 - #define MINIZ_LITTLE_ENDIAN 1 - #define MINIZ_HAS_64BIT_REGISTERS 1 - - * On platforms using glibc, Be sure to "#define _LARGEFILE64_SOURCE 1" before including miniz.c to ensure miniz - uses the 64-bit variants: fopen64(), stat64(), etc. Otherwise you won't be able to process large files - (i.e. 32-bit stat() fails for me on files > 0x7FFFFFFF bytes). -*/ -#pragma once - -/* Hardcoded options for Xtensa - JD */ -#define MINIZ_USE_UNALIGNED_LOADS_AND_STORES 0 -#define MINIZ_LITTLE_ENDIAN 1 - - - - - -/* Defines to completely disable specific portions of miniz.c: - If all macros here are defined the only functionality remaining will be CRC-32, adler-32, tinfl, and tdefl. */ - -/* Define MINIZ_NO_STDIO to disable all usage and any functions which rely on stdio for file I/O. */ -#define MINIZ_NO_STDIO - -/* If MINIZ_NO_TIME is specified then the ZIP archive functions will not be able to get the current time, or */ -/* get/set file times, and the C run-time funcs that get/set times won't be called. */ -/* The current downside is the times written to your archives will be from 1979. */ -#define MINIZ_NO_TIME - -/* Define MINIZ_NO_ARCHIVE_APIS to disable all ZIP archive API's. */ -#define MINIZ_NO_ARCHIVE_APIS - -/* Define MINIZ_NO_ARCHIVE_WRITING_APIS to disable all writing related ZIP archive API's. */ -#define MINIZ_NO_ARCHIVE_WRITING_APIS - -/* Define MINIZ_NO_ZLIB_APIS to remove all ZLIB-style compression/decompression API's. */ -#define MINIZ_NO_ZLIB_APIS - -/* Define MINIZ_NO_ZLIB_COMPATIBLE_NAME to disable zlib names, to prevent conflicts against stock zlib. */ -#define MINIZ_NO_ZLIB_COMPATIBLE_NAMES - -/* Define MINIZ_NO_MALLOC to disable all calls to malloc, free, and realloc. - Note if MINIZ_NO_MALLOC is defined then the user must always provide custom user alloc/free/realloc - callbacks to the zlib and archive API's, and a few stand-alone helper API's which don't provide custom user - functions (such as tdefl_compress_mem_to_heap() and tinfl_decompress_mem_to_heap()) won't work. */ -#define MINIZ_NO_MALLOC - -#if defined(__TINYC__) && (defined(__linux) || defined(__linux__)) -/* TODO: Work around "error: include file 'sys\utime.h' when compiling with tcc on Linux */ -#define MINIZ_NO_TIME -#endif - -#include - -#if !defined(MINIZ_NO_TIME) && !defined(MINIZ_NO_ARCHIVE_APIS) -#include -#endif - -#if defined(_M_IX86) || defined(_M_X64) || defined(__i386__) || defined(__i386) || defined(__i486__) || defined(__i486) || defined(i386) || defined(__ia64__) || defined(__x86_64__) -/* MINIZ_X86_OR_X64_CPU is only used to help set the below macros. */ -#define MINIZ_X86_OR_X64_CPU 1 -#else -#define MINIZ_X86_OR_X64_CPU 0 -#endif - -#if (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) || MINIZ_X86_OR_X64_CPU -/* Set MINIZ_LITTLE_ENDIAN to 1 if the processor is little endian. */ -#define MINIZ_LITTLE_ENDIAN 1 -#else -#define MINIZ_LITTLE_ENDIAN 0 -#endif - -/* Set MINIZ_USE_UNALIGNED_LOADS_AND_STORES only if not set */ -#if !defined(MINIZ_USE_UNALIGNED_LOADS_AND_STORES) -#if MINIZ_X86_OR_X64_CPU -/* Set MINIZ_USE_UNALIGNED_LOADS_AND_STORES to 1 on CPU's that permit efficient integer loads and stores from unaligned addresses. */ -#define MINIZ_USE_UNALIGNED_LOADS_AND_STORES 1 -#define MINIZ_UNALIGNED_USE_MEMCPY -#else -#define MINIZ_USE_UNALIGNED_LOADS_AND_STORES 0 -#endif -#endif - -#if defined(_M_X64) || defined(_WIN64) || defined(__MINGW64__) || defined(_LP64) || defined(__LP64__) || defined(__ia64__) || defined(__x86_64__) -/* Set MINIZ_HAS_64BIT_REGISTERS to 1 if operations on 64-bit integers are reasonably fast (and don't involve compiler generated calls to helper functions). */ -#define MINIZ_HAS_64BIT_REGISTERS 1 -#else -#define MINIZ_HAS_64BIT_REGISTERS 0 -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -/* ------------------- zlib-style API Definitions. */ - -/* For more compatibility with zlib, miniz.c uses unsigned long for some parameters/struct members. Beware: mz_ulong can be either 32 or 64-bits! */ -typedef unsigned long mz_ulong; - -/* mz_free() internally uses the MZ_FREE() macro (which by default calls free() unless you've modified the MZ_MALLOC macro) to release a block allocated from the heap. */ -void mz_free(void *p); - -#define MZ_ADLER32_INIT (1) -/* mz_adler32() returns the initial adler-32 value to use when called with ptr==NULL. */ -mz_ulong mz_adler32(mz_ulong adler, const unsigned char *ptr, size_t buf_len); - -#define MZ_CRC32_INIT (0) -/* mz_crc32() returns the initial CRC-32 value to use when called with ptr==NULL. */ -mz_ulong mz_crc32(mz_ulong crc, const unsigned char *ptr, size_t buf_len); - -/* Compression strategies. */ -enum -{ - MZ_DEFAULT_STRATEGY = 0, - MZ_FILTERED = 1, - MZ_HUFFMAN_ONLY = 2, - MZ_RLE = 3, - MZ_FIXED = 4 -}; - -/* Method */ -#define MZ_DEFLATED 8 - -/* Heap allocation callbacks. -Note that mz_alloc_func parameter types purpsosely differ from zlib's: items/size is size_t, not unsigned long. */ -typedef void *(*mz_alloc_func)(void *opaque, size_t items, size_t size); -typedef void (*mz_free_func)(void *opaque, void *address); -typedef void *(*mz_realloc_func)(void *opaque, void *address, size_t items, size_t size); - -/* Compression levels: 0-9 are the standard zlib-style levels, 10 is best possible compression (not zlib compatible, and may be very slow), MZ_DEFAULT_COMPRESSION=MZ_DEFAULT_LEVEL. */ -enum -{ - MZ_NO_COMPRESSION = 0, - MZ_BEST_SPEED = 1, - MZ_BEST_COMPRESSION = 9, - MZ_UBER_COMPRESSION = 10, - MZ_DEFAULT_LEVEL = 6, - MZ_DEFAULT_COMPRESSION = -1 -}; - -#define MZ_VERSION "10.1.0" -#define MZ_VERNUM 0xA100 -#define MZ_VER_MAJOR 10 -#define MZ_VER_MINOR 1 -#define MZ_VER_REVISION 0 -#define MZ_VER_SUBREVISION 0 - -#ifndef MINIZ_NO_ZLIB_APIS - -/* Flush values. For typical usage you only need MZ_NO_FLUSH and MZ_FINISH. The other values are for advanced use (refer to the zlib docs). */ -enum -{ - MZ_NO_FLUSH = 0, - MZ_PARTIAL_FLUSH = 1, - MZ_SYNC_FLUSH = 2, - MZ_FULL_FLUSH = 3, - MZ_FINISH = 4, - MZ_BLOCK = 5 -}; - -/* Return status codes. MZ_PARAM_ERROR is non-standard. */ -enum -{ - MZ_OK = 0, - MZ_STREAM_END = 1, - MZ_NEED_DICT = 2, - MZ_ERRNO = -1, - MZ_STREAM_ERROR = -2, - MZ_DATA_ERROR = -3, - MZ_MEM_ERROR = -4, - MZ_BUF_ERROR = -5, - MZ_VERSION_ERROR = -6, - MZ_PARAM_ERROR = -10000 -}; - -/* Window bits */ -#define MZ_DEFAULT_WINDOW_BITS 15 - -struct mz_internal_state; - -/* Compression/decompression stream struct. */ -typedef struct mz_stream_s -{ - const unsigned char *next_in; /* pointer to next byte to read */ - unsigned int avail_in; /* number of bytes available at next_in */ - mz_ulong total_in; /* total number of bytes consumed so far */ - - unsigned char *next_out; /* pointer to next byte to write */ - unsigned int avail_out; /* number of bytes that can be written to next_out */ - mz_ulong total_out; /* total number of bytes produced so far */ - - char *msg; /* error msg (unused) */ - struct mz_internal_state *state; /* internal state, allocated by zalloc/zfree */ - - mz_alloc_func zalloc; /* optional heap allocation function (defaults to malloc) */ - mz_free_func zfree; /* optional heap free function (defaults to free) */ - void *opaque; /* heap alloc function user pointer */ - - int data_type; /* data_type (unused) */ - mz_ulong adler; /* adler32 of the source or uncompressed data */ - mz_ulong reserved; /* not used */ -} mz_stream; - -typedef mz_stream *mz_streamp; - -/* Returns the version string of miniz.c. */ -const char *mz_version(void); - -/* mz_deflateInit() initializes a compressor with default options: */ -/* Parameters: */ -/* pStream must point to an initialized mz_stream struct. */ -/* level must be between [MZ_NO_COMPRESSION, MZ_BEST_COMPRESSION]. */ -/* level 1 enables a specially optimized compression function that's been optimized purely for performance, not ratio. */ -/* (This special func. is currently only enabled when MINIZ_USE_UNALIGNED_LOADS_AND_STORES and MINIZ_LITTLE_ENDIAN are defined.) */ -/* Return values: */ -/* MZ_OK on success. */ -/* MZ_STREAM_ERROR if the stream is bogus. */ -/* MZ_PARAM_ERROR if the input parameters are bogus. */ -/* MZ_MEM_ERROR on out of memory. */ -int mz_deflateInit(mz_streamp pStream, int level); - -/* mz_deflateInit2() is like mz_deflate(), except with more control: */ -/* Additional parameters: */ -/* method must be MZ_DEFLATED */ -/* window_bits must be MZ_DEFAULT_WINDOW_BITS (to wrap the deflate stream with zlib header/adler-32 footer) or -MZ_DEFAULT_WINDOW_BITS (raw deflate/no header or footer) */ -/* mem_level must be between [1, 9] (it's checked but ignored by miniz.c) */ -int mz_deflateInit2(mz_streamp pStream, int level, int method, int window_bits, int mem_level, int strategy); - -/* Quickly resets a compressor without having to reallocate anything. Same as calling mz_deflateEnd() followed by mz_deflateInit()/mz_deflateInit2(). */ -int mz_deflateReset(mz_streamp pStream); - -/* mz_deflate() compresses the input to output, consuming as much of the input and producing as much output as possible. */ -/* Parameters: */ -/* pStream is the stream to read from and write to. You must initialize/update the next_in, avail_in, next_out, and avail_out members. */ -/* flush may be MZ_NO_FLUSH, MZ_PARTIAL_FLUSH/MZ_SYNC_FLUSH, MZ_FULL_FLUSH, or MZ_FINISH. */ -/* Return values: */ -/* MZ_OK on success (when flushing, or if more input is needed but not available, and/or there's more output to be written but the output buffer is full). */ -/* MZ_STREAM_END if all input has been consumed and all output bytes have been written. Don't call mz_deflate() on the stream anymore. */ -/* MZ_STREAM_ERROR if the stream is bogus. */ -/* MZ_PARAM_ERROR if one of the parameters is invalid. */ -/* MZ_BUF_ERROR if no forward progress is possible because the input and/or output buffers are empty. (Fill up the input buffer or free up some output space and try again.) */ -int mz_deflate(mz_streamp pStream, int flush); - -/* mz_deflateEnd() deinitializes a compressor: */ -/* Return values: */ -/* MZ_OK on success. */ -/* MZ_STREAM_ERROR if the stream is bogus. */ -int mz_deflateEnd(mz_streamp pStream); - -/* mz_deflateBound() returns a (very) conservative upper bound on the amount of data that could be generated by deflate(), assuming flush is set to only MZ_NO_FLUSH or MZ_FINISH. */ -mz_ulong mz_deflateBound(mz_streamp pStream, mz_ulong source_len); - -/* Single-call compression functions mz_compress() and mz_compress2(): */ -/* Returns MZ_OK on success, or one of the error codes from mz_deflate() on failure. */ -int mz_compress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len); -int mz_compress2(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len, int level); - -/* mz_compressBound() returns a (very) conservative upper bound on the amount of data that could be generated by calling mz_compress(). */ -mz_ulong mz_compressBound(mz_ulong source_len); - -/* Initializes a decompressor. */ -int mz_inflateInit(mz_streamp pStream); - -/* mz_inflateInit2() is like mz_inflateInit() with an additional option that controls the window size and whether or not the stream has been wrapped with a zlib header/footer: */ -/* window_bits must be MZ_DEFAULT_WINDOW_BITS (to parse zlib header/footer) or -MZ_DEFAULT_WINDOW_BITS (raw deflate). */ -int mz_inflateInit2(mz_streamp pStream, int window_bits); - -/* Quickly resets a compressor without having to reallocate anything. Same as calling mz_inflateEnd() followed by mz_inflateInit()/mz_inflateInit2(). */ -int mz_inflateReset(mz_streamp pStream); - -/* Decompresses the input stream to the output, consuming only as much of the input as needed, and writing as much to the output as possible. */ -/* Parameters: */ -/* pStream is the stream to read from and write to. You must initialize/update the next_in, avail_in, next_out, and avail_out members. */ -/* flush may be MZ_NO_FLUSH, MZ_SYNC_FLUSH, or MZ_FINISH. */ -/* On the first call, if flush is MZ_FINISH it's assumed the input and output buffers are both sized large enough to decompress the entire stream in a single call (this is slightly faster). */ -/* MZ_FINISH implies that there are no more source bytes available beside what's already in the input buffer, and that the output buffer is large enough to hold the rest of the decompressed data. */ -/* Return values: */ -/* MZ_OK on success. Either more input is needed but not available, and/or there's more output to be written but the output buffer is full. */ -/* MZ_STREAM_END if all needed input has been consumed and all output bytes have been written. For zlib streams, the adler-32 of the decompressed data has also been verified. */ -/* MZ_STREAM_ERROR if the stream is bogus. */ -/* MZ_DATA_ERROR if the deflate stream is invalid. */ -/* MZ_PARAM_ERROR if one of the parameters is invalid. */ -/* MZ_BUF_ERROR if no forward progress is possible because the input buffer is empty but the inflater needs more input to continue, or if the output buffer is not large enough. Call mz_inflate() again */ -/* with more input data, or with more room in the output buffer (except when using single call decompression, described above). */ -int mz_inflate(mz_streamp pStream, int flush); - -/* Deinitializes a decompressor. */ -int mz_inflateEnd(mz_streamp pStream); - -/* Single-call decompression. */ -/* Returns MZ_OK on success, or one of the error codes from mz_inflate() on failure. */ -int mz_uncompress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len); - -/* Returns a string description of the specified error code, or NULL if the error code is invalid. */ -const char *mz_error(int err); - -/* Redefine zlib-compatible names to miniz equivalents, so miniz.c can be used as a drop-in replacement for the subset of zlib that miniz.c supports. */ -/* Define MINIZ_NO_ZLIB_COMPATIBLE_NAMES to disable zlib-compatibility if you use zlib in the same project. */ -#ifndef MINIZ_NO_ZLIB_COMPATIBLE_NAMES -typedef unsigned char Byte; -typedef unsigned int uInt; -typedef mz_ulong uLong; -typedef Byte Bytef; -typedef uInt uIntf; -typedef char charf; -typedef int intf; -typedef void *voidpf; -typedef uLong uLongf; -typedef void *voidp; -typedef void *const voidpc; -#define Z_NULL 0 -#define Z_NO_FLUSH MZ_NO_FLUSH -#define Z_PARTIAL_FLUSH MZ_PARTIAL_FLUSH -#define Z_SYNC_FLUSH MZ_SYNC_FLUSH -#define Z_FULL_FLUSH MZ_FULL_FLUSH -#define Z_FINISH MZ_FINISH -#define Z_BLOCK MZ_BLOCK -#define Z_OK MZ_OK -#define Z_STREAM_END MZ_STREAM_END -#define Z_NEED_DICT MZ_NEED_DICT -#define Z_ERRNO MZ_ERRNO -#define Z_STREAM_ERROR MZ_STREAM_ERROR -#define Z_DATA_ERROR MZ_DATA_ERROR -#define Z_MEM_ERROR MZ_MEM_ERROR -#define Z_BUF_ERROR MZ_BUF_ERROR -#define Z_VERSION_ERROR MZ_VERSION_ERROR -#define Z_PARAM_ERROR MZ_PARAM_ERROR -#define Z_NO_COMPRESSION MZ_NO_COMPRESSION -#define Z_BEST_SPEED MZ_BEST_SPEED -#define Z_BEST_COMPRESSION MZ_BEST_COMPRESSION -#define Z_DEFAULT_COMPRESSION MZ_DEFAULT_COMPRESSION -#define Z_DEFAULT_STRATEGY MZ_DEFAULT_STRATEGY -#define Z_FILTERED MZ_FILTERED -#define Z_HUFFMAN_ONLY MZ_HUFFMAN_ONLY -#define Z_RLE MZ_RLE -#define Z_FIXED MZ_FIXED -#define Z_DEFLATED MZ_DEFLATED -#define Z_DEFAULT_WINDOW_BITS MZ_DEFAULT_WINDOW_BITS -#define alloc_func mz_alloc_func -#define free_func mz_free_func -#define internal_state mz_internal_state -#define z_stream mz_stream -#define deflateInit mz_deflateInit -#define deflateInit2 mz_deflateInit2 -#define deflateReset mz_deflateReset -#define deflate mz_deflate -#define deflateEnd mz_deflateEnd -#define deflateBound mz_deflateBound -#define compress mz_compress -#define compress2 mz_compress2 -#define compressBound mz_compressBound -#define inflateInit mz_inflateInit -#define inflateInit2 mz_inflateInit2 -#define inflateReset mz_inflateReset -#define inflate mz_inflate -#define inflateEnd mz_inflateEnd -#define uncompress mz_uncompress -#define crc32 mz_crc32 -#define adler32 mz_adler32 -#define MAX_WBITS 15 -#define MAX_MEM_LEVEL 9 -#define zError mz_error -#define ZLIB_VERSION MZ_VERSION -#define ZLIB_VERNUM MZ_VERNUM -#define ZLIB_VER_MAJOR MZ_VER_MAJOR -#define ZLIB_VER_MINOR MZ_VER_MINOR -#define ZLIB_VER_REVISION MZ_VER_REVISION -#define ZLIB_VER_SUBREVISION MZ_VER_SUBREVISION -#define zlibVersion mz_version -#define zlib_version mz_version() -#endif /* #ifndef MINIZ_NO_ZLIB_COMPATIBLE_NAMES */ - -#endif /* MINIZ_NO_ZLIB_APIS */ - -#ifdef __cplusplus -} -#endif -#pragma once -#include -#include -#include -#include - -/* ------------------- Types and macros */ -typedef unsigned char mz_uint8; -typedef signed short mz_int16; -typedef unsigned short mz_uint16; -typedef unsigned int mz_uint32; -typedef unsigned int mz_uint; -typedef int64_t mz_int64; -typedef uint64_t mz_uint64; -typedef int mz_bool; - -#define MZ_FALSE (0) -#define MZ_TRUE (1) - -/* Works around MSVC's spammy "warning C4127: conditional expression is constant" message. */ -#ifdef _MSC_VER -#define MZ_MACRO_END while (0, 0) -#else -#define MZ_MACRO_END while (0) -#endif - -#ifdef MINIZ_NO_STDIO -#define MZ_FILE void * -#else -#include -#define MZ_FILE FILE -#endif /* #ifdef MINIZ_NO_STDIO */ - -#ifdef MINIZ_NO_TIME -typedef struct mz_dummy_time_t_tag -{ - int m_dummy; -} mz_dummy_time_t; -#define MZ_TIME_T mz_dummy_time_t -#else -#define MZ_TIME_T time_t -#endif - -#define MZ_ASSERT(x) - -#ifdef MINIZ_NO_MALLOC -#define MZ_MALLOC(x) NULL -#define MZ_FREE(x) (void)x, ((void)0) -#define MZ_REALLOC(p, x) NULL -#else -#define MZ_MALLOC(x) malloc(x) -#define MZ_FREE(x) free(x) -#define MZ_REALLOC(p, x) realloc(p, x) -#endif - -#define MZ_MAX(a, b) (((a) > (b)) ? (a) : (b)) -#define MZ_MIN(a, b) (((a) < (b)) ? (a) : (b)) -#define MZ_CLEAR_OBJ(obj) memset(&(obj), 0, sizeof(obj)) - -#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN -#define MZ_READ_LE16(p) *((const mz_uint16 *)(p)) -#define MZ_READ_LE32(p) *((const mz_uint32 *)(p)) -#else -#define MZ_READ_LE16(p) ((mz_uint32)(((const mz_uint8 *)(p))[0]) | ((mz_uint32)(((const mz_uint8 *)(p))[1]) << 8U)) -#define MZ_READ_LE32(p) ((mz_uint32)(((const mz_uint8 *)(p))[0]) | ((mz_uint32)(((const mz_uint8 *)(p))[1]) << 8U) | ((mz_uint32)(((const mz_uint8 *)(p))[2]) << 16U) | ((mz_uint32)(((const mz_uint8 *)(p))[3]) << 24U)) -#endif - -#define MZ_READ_LE64(p) (((mz_uint64)MZ_READ_LE32(p)) | (((mz_uint64)MZ_READ_LE32((const mz_uint8 *)(p) + sizeof(mz_uint32))) << 32U)) - -#ifdef _MSC_VER -#define MZ_FORCEINLINE __forceinline -#elif defined(__GNUC__) -#define MZ_FORCEINLINE __inline__ __attribute__((__always_inline__)) -#else -#define MZ_FORCEINLINE inline -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -extern void *miniz_def_alloc_func(void *opaque, size_t items, size_t size); -extern void miniz_def_free_func(void *opaque, void *address); -extern void *miniz_def_realloc_func(void *opaque, void *address, size_t items, size_t size); - -#define MZ_UINT16_MAX (0xFFFFU) -#define MZ_UINT32_MAX (0xFFFFFFFFU) - -#ifdef __cplusplus -} -#endif -#pragma once - - -#ifdef __cplusplus -extern "C" { -#endif -/* ------------------- Low-level Compression API Definitions */ - -/* Set TDEFL_LESS_MEMORY to 1 to use less memory (compression will be slightly slower, and raw/dynamic blocks will be output more frequently). */ -#define TDEFL_LESS_MEMORY 1 - -/* tdefl_init() compression flags logically OR'd together (low 12 bits contain the max. number of probes per dictionary search): */ -/* TDEFL_DEFAULT_MAX_PROBES: The compressor defaults to 128 dictionary probes per dictionary search. 0=Huffman only, 1=Huffman+LZ (fastest/crap compression), 4095=Huffman+LZ (slowest/best compression). */ -enum -{ - TDEFL_HUFFMAN_ONLY = 0, - TDEFL_DEFAULT_MAX_PROBES = 128, - TDEFL_MAX_PROBES_MASK = 0xFFF -}; - -/* TDEFL_WRITE_ZLIB_HEADER: If set, the compressor outputs a zlib header before the deflate data, and the Adler-32 of the source data at the end. Otherwise, you'll get raw deflate data. */ -/* TDEFL_COMPUTE_ADLER32: Always compute the adler-32 of the input data (even when not writing zlib headers). */ -/* TDEFL_GREEDY_PARSING_FLAG: Set to use faster greedy parsing, instead of more efficient lazy parsing. */ -/* TDEFL_NONDETERMINISTIC_PARSING_FLAG: Enable to decrease the compressor's initialization time to the minimum, but the output may vary from run to run given the same input (depending on the contents of memory). */ -/* TDEFL_RLE_MATCHES: Only look for RLE matches (matches with a distance of 1) */ -/* TDEFL_FILTER_MATCHES: Discards matches <= 5 chars if enabled. */ -/* TDEFL_FORCE_ALL_STATIC_BLOCKS: Disable usage of optimized Huffman tables. */ -/* TDEFL_FORCE_ALL_RAW_BLOCKS: Only use raw (uncompressed) deflate blocks. */ -/* The low 12 bits are reserved to control the max # of hash probes per dictionary lookup (see TDEFL_MAX_PROBES_MASK). */ -enum -{ - TDEFL_WRITE_ZLIB_HEADER = 0x01000, - TDEFL_COMPUTE_ADLER32 = 0x02000, - TDEFL_GREEDY_PARSING_FLAG = 0x04000, - TDEFL_NONDETERMINISTIC_PARSING_FLAG = 0x08000, - TDEFL_RLE_MATCHES = 0x10000, - TDEFL_FILTER_MATCHES = 0x20000, - TDEFL_FORCE_ALL_STATIC_BLOCKS = 0x40000, - TDEFL_FORCE_ALL_RAW_BLOCKS = 0x80000 -}; - -/* High level compression functions: */ -/* tdefl_compress_mem_to_heap() compresses a block in memory to a heap block allocated via malloc(). */ -/* On entry: */ -/* pSrc_buf, src_buf_len: Pointer and size of source block to compress. */ -/* flags: The max match finder probes (default is 128) logically OR'd against the above flags. Higher probes are slower but improve compression. */ -/* On return: */ -/* Function returns a pointer to the compressed data, or NULL on failure. */ -/* *pOut_len will be set to the compressed data's size, which could be larger than src_buf_len on incompressible data. */ -/* The caller must free() the returned block when it's no longer needed. */ -void *tdefl_compress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags); - -/* tdefl_compress_mem_to_mem() compresses a block in memory to another block in memory. */ -/* Returns 0 on failure. */ -size_t tdefl_compress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags); - -/* Compresses an image to a compressed PNG file in memory. */ -/* On entry: */ -/* pImage, w, h, and num_chans describe the image to compress. num_chans may be 1, 2, 3, or 4. */ -/* The image pitch in bytes per scanline will be w*num_chans. The leftmost pixel on the top scanline is stored first in memory. */ -/* level may range from [0,10], use MZ_NO_COMPRESSION, MZ_BEST_SPEED, MZ_BEST_COMPRESSION, etc. or a decent default is MZ_DEFAULT_LEVEL */ -/* If flip is true, the image will be flipped on the Y axis (useful for OpenGL apps). */ -/* On return: */ -/* Function returns a pointer to the compressed data, or NULL on failure. */ -/* *pLen_out will be set to the size of the PNG image file. */ -/* The caller must mz_free() the returned heap block (which will typically be larger than *pLen_out) when it's no longer needed. */ -void *tdefl_write_image_to_png_file_in_memory_ex(const void *pImage, int w, int h, int num_chans, size_t *pLen_out, mz_uint level, mz_bool flip); -void *tdefl_write_image_to_png_file_in_memory(const void *pImage, int w, int h, int num_chans, size_t *pLen_out); - -/* Output stream interface. The compressor uses this interface to write compressed data. It'll typically be called TDEFL_OUT_BUF_SIZE at a time. */ -typedef mz_bool (*tdefl_put_buf_func_ptr)(const void *pBuf, int len, void *pUser); - -/* tdefl_compress_mem_to_output() compresses a block to an output stream. The above helpers use this function internally. */ -mz_bool tdefl_compress_mem_to_output(const void *pBuf, size_t buf_len, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags); - -enum -{ - TDEFL_MAX_HUFF_TABLES = 3, - TDEFL_MAX_HUFF_SYMBOLS_0 = 288, - TDEFL_MAX_HUFF_SYMBOLS_1 = 32, - TDEFL_MAX_HUFF_SYMBOLS_2 = 19, - TDEFL_LZ_DICT_SIZE = (8*1024), - TDEFL_LZ_DICT_SIZE_MASK = TDEFL_LZ_DICT_SIZE - 1, - TDEFL_MIN_MATCH_LEN = 3, - TDEFL_MAX_MATCH_LEN = 258 -}; - -/* TDEFL_OUT_BUF_SIZE MUST be large enough to hold a single entire compressed output block (using static/fixed Huffman codes). */ -#if TDEFL_LESS_MEMORY -enum -{ - TDEFL_LZ_CODE_BUF_SIZE = 8 * 1024, - TDEFL_OUT_BUF_SIZE = (TDEFL_LZ_CODE_BUF_SIZE * 13) / 10, - TDEFL_MAX_HUFF_SYMBOLS = 288, - TDEFL_LZ_HASH_BITS = 12, - TDEFL_LEVEL1_HASH_SIZE_MASK = 4095, - TDEFL_LZ_HASH_SHIFT = (TDEFL_LZ_HASH_BITS + 2) / 3, - TDEFL_LZ_HASH_SIZE = 1 << TDEFL_LZ_HASH_BITS -}; -#else -enum -{ - TDEFL_LZ_CODE_BUF_SIZE = 64 * 1024, - TDEFL_OUT_BUF_SIZE = (TDEFL_LZ_CODE_BUF_SIZE * 13) / 10, - TDEFL_MAX_HUFF_SYMBOLS = 288, - TDEFL_LZ_HASH_BITS = 15, - TDEFL_LEVEL1_HASH_SIZE_MASK = 4095, - TDEFL_LZ_HASH_SHIFT = (TDEFL_LZ_HASH_BITS + 2) / 3, - TDEFL_LZ_HASH_SIZE = 1 << TDEFL_LZ_HASH_BITS -}; -#endif - -/* The low-level tdefl functions below may be used directly if the above helper functions aren't flexible enough. The low-level functions don't make any heap allocations, unlike the above helper functions. */ -typedef enum { - TDEFL_STATUS_BAD_PARAM = -2, - TDEFL_STATUS_PUT_BUF_FAILED = -1, - TDEFL_STATUS_OKAY = 0, - TDEFL_STATUS_DONE = 1 -} tdefl_status; - -/* Must map to MZ_NO_FLUSH, MZ_SYNC_FLUSH, etc. enums */ -typedef enum { - TDEFL_NO_FLUSH = 0, - TDEFL_SYNC_FLUSH = 2, - TDEFL_FULL_FLUSH = 3, - TDEFL_FINISH = 4 -} tdefl_flush; - -/* tdefl's compression state structure. */ -typedef struct -{ - tdefl_put_buf_func_ptr m_pPut_buf_func; - void *m_pPut_buf_user; - mz_uint m_flags, m_max_probes[2]; - int m_greedy_parsing; - mz_uint m_adler32, m_lookahead_pos, m_lookahead_size, m_dict_size; - mz_uint8 *m_pLZ_code_buf, *m_pLZ_flags, *m_pOutput_buf, *m_pOutput_buf_end; - mz_uint m_num_flags_left, m_total_lz_bytes, m_lz_code_buf_dict_pos, m_bits_in, m_bit_buffer; - mz_uint m_saved_match_dist, m_saved_match_len, m_saved_lit, m_output_flush_ofs, m_output_flush_remaining, m_finished, m_block_index, m_wants_to_finish; - tdefl_status m_prev_return_status; - const void *m_pIn_buf; - void *m_pOut_buf; - size_t *m_pIn_buf_size, *m_pOut_buf_size; - tdefl_flush m_flush; - const mz_uint8 *m_pSrc; - size_t m_src_buf_left, m_out_buf_ofs; - mz_uint8 m_dict[TDEFL_LZ_DICT_SIZE + TDEFL_MAX_MATCH_LEN - 1]; - mz_uint16 m_huff_count[TDEFL_MAX_HUFF_TABLES][TDEFL_MAX_HUFF_SYMBOLS]; - mz_uint16 m_huff_codes[TDEFL_MAX_HUFF_TABLES][TDEFL_MAX_HUFF_SYMBOLS]; - mz_uint8 m_huff_code_sizes[TDEFL_MAX_HUFF_TABLES][TDEFL_MAX_HUFF_SYMBOLS]; - mz_uint8 m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE]; - mz_uint16 m_next[TDEFL_LZ_DICT_SIZE]; - mz_uint16 m_hash[TDEFL_LZ_HASH_SIZE]; - mz_uint8 m_output_buf[TDEFL_OUT_BUF_SIZE]; -} tdefl_compressor; - -/* Initializes the compressor. */ -/* There is no corresponding deinit() function because the tdefl API's do not dynamically allocate memory. */ -/* pBut_buf_func: If NULL, output data will be supplied to the specified callback. In this case, the user should call the tdefl_compress_buffer() API for compression. */ -/* If pBut_buf_func is NULL the user should always call the tdefl_compress() API. */ -/* flags: See the above enums (TDEFL_HUFFMAN_ONLY, TDEFL_WRITE_ZLIB_HEADER, etc.) */ -tdefl_status tdefl_init(tdefl_compressor *d, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags); - -/* Compresses a block of data, consuming as much of the specified input buffer as possible, and writing as much compressed data to the specified output buffer as possible. */ -tdefl_status tdefl_compress(tdefl_compressor *d, const void *pIn_buf, size_t *pIn_buf_size, void *pOut_buf, size_t *pOut_buf_size, tdefl_flush flush); - -/* tdefl_compress_buffer() is only usable when the tdefl_init() is called with a non-NULL tdefl_put_buf_func_ptr. */ -/* tdefl_compress_buffer() always consumes the entire input buffer. */ -tdefl_status tdefl_compress_buffer(tdefl_compressor *d, const void *pIn_buf, size_t in_buf_size, tdefl_flush flush); - -tdefl_status tdefl_get_prev_return_status(tdefl_compressor *d); -mz_uint32 tdefl_get_adler32(tdefl_compressor *d); - -/* Create tdefl_compress() flags given zlib-style compression parameters. */ -/* level may range from [0,10] (where 10 is absolute max compression, but may be much slower on some files) */ -/* window_bits may be -15 (raw deflate) or 15 (zlib) */ -/* strategy may be either MZ_DEFAULT_STRATEGY, MZ_FILTERED, MZ_HUFFMAN_ONLY, MZ_RLE, or MZ_FIXED */ -mz_uint tdefl_create_comp_flags_from_zip_params(int level, int window_bits, int strategy); - -#ifndef MINIZ_NO_MALLOC -/* Allocate the tdefl_compressor structure in C so that */ -/* non-C language bindings to tdefl_ API don't need to worry about */ -/* structure size and allocation mechanism. */ -tdefl_compressor *tdefl_compressor_alloc(void); -void tdefl_compressor_free(tdefl_compressor *pComp); -#endif - -#ifdef __cplusplus -} -#endif -#pragma once - -/* ------------------- Low-level Decompression API Definitions */ - -#ifdef __cplusplus -extern "C" { -#endif -/* Decompression flags used by tinfl_decompress(). */ -/* TINFL_FLAG_PARSE_ZLIB_HEADER: If set, the input has a valid zlib header and ends with an adler32 checksum (it's a valid zlib stream). Otherwise, the input is a raw deflate stream. */ -/* TINFL_FLAG_HAS_MORE_INPUT: If set, there are more input bytes available beyond the end of the supplied input buffer. If clear, the input buffer contains all remaining input. */ -/* TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF: If set, the output buffer is large enough to hold the entire decompressed stream. If clear, the output buffer is at least the size of the dictionary (typically 32KB). */ -/* TINFL_FLAG_COMPUTE_ADLER32: Force adler-32 checksum computation of the decompressed bytes. */ -enum -{ - TINFL_FLAG_PARSE_ZLIB_HEADER = 1, - TINFL_FLAG_HAS_MORE_INPUT = 2, - TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF = 4, - TINFL_FLAG_COMPUTE_ADLER32 = 8 -}; - -/* High level decompression functions: */ -/* tinfl_decompress_mem_to_heap() decompresses a block in memory to a heap block allocated via malloc(). */ -/* On entry: */ -/* pSrc_buf, src_buf_len: Pointer and size of the Deflate or zlib source data to decompress. */ -/* On return: */ -/* Function returns a pointer to the decompressed data, or NULL on failure. */ -/* *pOut_len will be set to the decompressed data's size, which could be larger than src_buf_len on incompressible data. */ -/* The caller must call mz_free() on the returned block when it's no longer needed. */ -void *tinfl_decompress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags); - -/* tinfl_decompress_mem_to_mem() decompresses a block in memory to another block in memory. */ -/* Returns TINFL_DECOMPRESS_MEM_TO_MEM_FAILED on failure, or the number of bytes written on success. */ -#define TINFL_DECOMPRESS_MEM_TO_MEM_FAILED ((size_t)(-1)) -size_t tinfl_decompress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags); - -/* tinfl_decompress_mem_to_callback() decompresses a block in memory to an internal 32KB buffer, and a user provided callback function will be called to flush the buffer. */ -/* Returns 1 on success or 0 on failure. */ -typedef int (*tinfl_put_buf_func_ptr)(const void *pBuf, int len, void *pUser); -int tinfl_decompress_mem_to_callback(const void *pIn_buf, size_t *pIn_buf_size, tinfl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags); - -struct tinfl_decompressor_tag; -typedef struct tinfl_decompressor_tag tinfl_decompressor; - -#ifndef MINIZ_NO_MALLOC -/* Allocate the tinfl_decompressor structure in C so that */ -/* non-C language bindings to tinfl_ API don't need to worry about */ -/* structure size and allocation mechanism. */ -tinfl_decompressor *tinfl_decompressor_alloc(void); -void tinfl_decompressor_free(tinfl_decompressor *pDecomp); -#endif - -/* Max size of LZ dictionary. */ -#define TINFL_LZ_DICT_SIZE 32768 - -/* Return status. */ -typedef enum { - /* This flags indicates the inflator needs 1 or more input bytes to make forward progress, but the caller is indicating that no more are available. The compressed data */ - /* is probably corrupted. If you call the inflator again with more bytes it'll try to continue processing the input but this is a BAD sign (either the data is corrupted or you called it incorrectly). */ - /* If you call it again with no input you'll just get TINFL_STATUS_FAILED_CANNOT_MAKE_PROGRESS again. */ - TINFL_STATUS_FAILED_CANNOT_MAKE_PROGRESS = -4, - - /* This flag indicates that one or more of the input parameters was obviously bogus. (You can try calling it again, but if you get this error the calling code is wrong.) */ - TINFL_STATUS_BAD_PARAM = -3, - - /* This flags indicate the inflator is finished but the adler32 check of the uncompressed data didn't match. If you call it again it'll return TINFL_STATUS_DONE. */ - TINFL_STATUS_ADLER32_MISMATCH = -2, - - /* This flags indicate the inflator has somehow failed (bad code, corrupted input, etc.). If you call it again without resetting via tinfl_init() it it'll just keep on returning the same status failure code. */ - TINFL_STATUS_FAILED = -1, - - /* Any status code less than TINFL_STATUS_DONE must indicate a failure. */ - - /* This flag indicates the inflator has returned every byte of uncompressed data that it can, has consumed every byte that it needed, has successfully reached the end of the deflate stream, and */ - /* if zlib headers and adler32 checking enabled that it has successfully checked the uncompressed data's adler32. If you call it again you'll just get TINFL_STATUS_DONE over and over again. */ - TINFL_STATUS_DONE = 0, - - /* This flag indicates the inflator MUST have more input data (even 1 byte) before it can make any more forward progress, or you need to clear the TINFL_FLAG_HAS_MORE_INPUT */ - /* flag on the next call if you don't have any more source data. If the source data was somehow corrupted it's also possible (but unlikely) for the inflator to keep on demanding input to */ - /* proceed, so be sure to properly set the TINFL_FLAG_HAS_MORE_INPUT flag. */ - TINFL_STATUS_NEEDS_MORE_INPUT = 1, - - /* This flag indicates the inflator definitely has 1 or more bytes of uncompressed data available, but it cannot write this data into the output buffer. */ - /* Note if the source compressed data was corrupted it's possible for the inflator to return a lot of uncompressed data to the caller. I've been assuming you know how much uncompressed data to expect */ - /* (either exact or worst case) and will stop calling the inflator and fail after receiving too much. In pure streaming scenarios where you have no idea how many bytes to expect this may not be possible */ - /* so I may need to add some code to address this. */ - TINFL_STATUS_HAS_MORE_OUTPUT = 2 -} tinfl_status; - -/* Initializes the decompressor to its initial state. */ -#define tinfl_init(r) \ - do \ - { \ - (r)->m_state = 0; \ - } \ - MZ_MACRO_END -#define tinfl_get_adler32(r) (r)->m_check_adler32 - -/* Main low-level decompressor coroutine function. This is the only function actually needed for decompression. All the other functions are just high-level helpers for improved usability. */ -/* This is a universal API, i.e. it can be used as a building block to build any desired higher level decompression API. In the limit case, it can be called once per every byte input or output. */ -tinfl_status tinfl_decompress(tinfl_decompressor *r, const mz_uint8 *pIn_buf_next, size_t *pIn_buf_size, mz_uint8 *pOut_buf_start, mz_uint8 *pOut_buf_next, size_t *pOut_buf_size, const mz_uint32 decomp_flags); - -/* Internal/private bits follow. */ -enum -{ - TINFL_MAX_HUFF_TABLES = 3, - TINFL_MAX_HUFF_SYMBOLS_0 = 288, - TINFL_MAX_HUFF_SYMBOLS_1 = 32, - TINFL_MAX_HUFF_SYMBOLS_2 = 19, - TINFL_FAST_LOOKUP_BITS = 10, - TINFL_FAST_LOOKUP_SIZE = 1 << TINFL_FAST_LOOKUP_BITS -}; - -typedef struct -{ - mz_uint8 m_code_size[TINFL_MAX_HUFF_SYMBOLS_0]; - mz_int16 m_look_up[TINFL_FAST_LOOKUP_SIZE], m_tree[TINFL_MAX_HUFF_SYMBOLS_0 * 2]; -} tinfl_huff_table; - -#if MINIZ_HAS_64BIT_REGISTERS -#define TINFL_USE_64BIT_BITBUF 1 -#else -#define TINFL_USE_64BIT_BITBUF 0 -#endif - -#if TINFL_USE_64BIT_BITBUF -typedef mz_uint64 tinfl_bit_buf_t; -#define TINFL_BITBUF_SIZE (64) -#else -typedef mz_uint32 tinfl_bit_buf_t; -#define TINFL_BITBUF_SIZE (32) -#endif - -struct tinfl_decompressor_tag -{ - mz_uint32 m_state, m_num_bits, m_zhdr0, m_zhdr1, m_z_adler32, m_final, m_type, m_check_adler32, m_dist, m_counter, m_num_extra, m_table_sizes[TINFL_MAX_HUFF_TABLES]; - tinfl_bit_buf_t m_bit_buf; - size_t m_dist_from_out_buf_start; - tinfl_huff_table m_tables[TINFL_MAX_HUFF_TABLES]; - mz_uint8 m_raw_header[4], m_len_codes[TINFL_MAX_HUFF_SYMBOLS_0 + TINFL_MAX_HUFF_SYMBOLS_1 + 137]; -}; - -#ifdef __cplusplus -} -#endif - -#pragma once - - -/* ------------------- ZIP archive reading/writing */ - -#ifndef MINIZ_NO_ARCHIVE_APIS - -#ifdef __cplusplus -extern "C" { -#endif - -enum -{ - /* Note: These enums can be reduced as needed to save memory or stack space - they are pretty conservative. */ - MZ_ZIP_MAX_IO_BUF_SIZE = 64 * 1024, - MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE = 512, - MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE = 512 -}; - -typedef struct -{ - /* Central directory file index. */ - mz_uint32 m_file_index; - - /* Byte offset of this entry in the archive's central directory. Note we currently only support up to UINT_MAX or less bytes in the central dir. */ - mz_uint64 m_central_dir_ofs; - - /* These fields are copied directly from the zip's central dir. */ - mz_uint16 m_version_made_by; - mz_uint16 m_version_needed; - mz_uint16 m_bit_flag; - mz_uint16 m_method; - -#ifndef MINIZ_NO_TIME - MZ_TIME_T m_time; -#endif - - /* CRC-32 of uncompressed data. */ - mz_uint32 m_crc32; - - /* File's compressed size. */ - mz_uint64 m_comp_size; - - /* File's uncompressed size. Note, I've seen some old archives where directory entries had 512 bytes for their uncompressed sizes, but when you try to unpack them you actually get 0 bytes. */ - mz_uint64 m_uncomp_size; - - /* Zip internal and external file attributes. */ - mz_uint16 m_internal_attr; - mz_uint32 m_external_attr; - - /* Entry's local header file offset in bytes. */ - mz_uint64 m_local_header_ofs; - - /* Size of comment in bytes. */ - mz_uint32 m_comment_size; - - /* MZ_TRUE if the entry appears to be a directory. */ - mz_bool m_is_directory; - - /* MZ_TRUE if the entry uses encryption/strong encryption (which miniz_zip doesn't support) */ - mz_bool m_is_encrypted; - - /* MZ_TRUE if the file is not encrypted, a patch file, and if it uses a compression method we support. */ - mz_bool m_is_supported; - - /* Filename. If string ends in '/' it's a subdirectory entry. */ - /* Guaranteed to be zero terminated, may be truncated to fit. */ - char m_filename[MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE]; - - /* Comment field. */ - /* Guaranteed to be zero terminated, may be truncated to fit. */ - char m_comment[MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE]; - -} mz_zip_archive_file_stat; - -typedef size_t (*mz_file_read_func)(void *pOpaque, mz_uint64 file_ofs, void *pBuf, size_t n); -typedef size_t (*mz_file_write_func)(void *pOpaque, mz_uint64 file_ofs, const void *pBuf, size_t n); -typedef mz_bool (*mz_file_needs_keepalive)(void *pOpaque); - -struct mz_zip_internal_state_tag; -typedef struct mz_zip_internal_state_tag mz_zip_internal_state; - -typedef enum { - MZ_ZIP_MODE_INVALID = 0, - MZ_ZIP_MODE_READING = 1, - MZ_ZIP_MODE_WRITING = 2, - MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED = 3 -} mz_zip_mode; - -typedef enum { - MZ_ZIP_FLAG_CASE_SENSITIVE = 0x0100, - MZ_ZIP_FLAG_IGNORE_PATH = 0x0200, - MZ_ZIP_FLAG_COMPRESSED_DATA = 0x0400, - MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY = 0x0800, - MZ_ZIP_FLAG_VALIDATE_LOCATE_FILE_FLAG = 0x1000, /* if enabled, mz_zip_reader_locate_file() will be called on each file as its validated to ensure the func finds the file in the central dir (intended for testing) */ - MZ_ZIP_FLAG_VALIDATE_HEADERS_ONLY = 0x2000, /* validate the local headers, but don't decompress the entire file and check the crc32 */ - MZ_ZIP_FLAG_WRITE_ZIP64 = 0x4000, /* always use the zip64 file format, instead of the original zip file format with automatic switch to zip64. Use as flags parameter with mz_zip_writer_init*_v2 */ - MZ_ZIP_FLAG_WRITE_ALLOW_READING = 0x8000, - MZ_ZIP_FLAG_ASCII_FILENAME = 0x10000 -} mz_zip_flags; - -typedef enum { - MZ_ZIP_TYPE_INVALID = 0, - MZ_ZIP_TYPE_USER, - MZ_ZIP_TYPE_MEMORY, - MZ_ZIP_TYPE_HEAP, - MZ_ZIP_TYPE_FILE, - MZ_ZIP_TYPE_CFILE, - MZ_ZIP_TOTAL_TYPES -} mz_zip_type; - -/* miniz error codes. Be sure to update mz_zip_get_error_string() if you add or modify this enum. */ -typedef enum { - MZ_ZIP_NO_ERROR = 0, - MZ_ZIP_UNDEFINED_ERROR, - MZ_ZIP_TOO_MANY_FILES, - MZ_ZIP_FILE_TOO_LARGE, - MZ_ZIP_UNSUPPORTED_METHOD, - MZ_ZIP_UNSUPPORTED_ENCRYPTION, - MZ_ZIP_UNSUPPORTED_FEATURE, - MZ_ZIP_FAILED_FINDING_CENTRAL_DIR, - MZ_ZIP_NOT_AN_ARCHIVE, - MZ_ZIP_INVALID_HEADER_OR_CORRUPTED, - MZ_ZIP_UNSUPPORTED_MULTIDISK, - MZ_ZIP_DECOMPRESSION_FAILED, - MZ_ZIP_COMPRESSION_FAILED, - MZ_ZIP_UNEXPECTED_DECOMPRESSED_SIZE, - MZ_ZIP_CRC_CHECK_FAILED, - MZ_ZIP_UNSUPPORTED_CDIR_SIZE, - MZ_ZIP_ALLOC_FAILED, - MZ_ZIP_FILE_OPEN_FAILED, - MZ_ZIP_FILE_CREATE_FAILED, - MZ_ZIP_FILE_WRITE_FAILED, - MZ_ZIP_FILE_READ_FAILED, - MZ_ZIP_FILE_CLOSE_FAILED, - MZ_ZIP_FILE_SEEK_FAILED, - MZ_ZIP_FILE_STAT_FAILED, - MZ_ZIP_INVALID_PARAMETER, - MZ_ZIP_INVALID_FILENAME, - MZ_ZIP_BUF_TOO_SMALL, - MZ_ZIP_INTERNAL_ERROR, - MZ_ZIP_FILE_NOT_FOUND, - MZ_ZIP_ARCHIVE_TOO_LARGE, - MZ_ZIP_VALIDATION_FAILED, - MZ_ZIP_WRITE_CALLBACK_FAILED, - MZ_ZIP_TOTAL_ERRORS -} mz_zip_error; - -typedef struct -{ - mz_uint64 m_archive_size; - mz_uint64 m_central_directory_file_ofs; - - /* We only support up to UINT32_MAX files in zip64 mode. */ - mz_uint32 m_total_files; - mz_zip_mode m_zip_mode; - mz_zip_type m_zip_type; - mz_zip_error m_last_error; - - mz_uint64 m_file_offset_alignment; - - mz_alloc_func m_pAlloc; - mz_free_func m_pFree; - mz_realloc_func m_pRealloc; - void *m_pAlloc_opaque; - - mz_file_read_func m_pRead; - mz_file_write_func m_pWrite; - mz_file_needs_keepalive m_pNeeds_keepalive; - void *m_pIO_opaque; - - mz_zip_internal_state *m_pState; - -} mz_zip_archive; - -typedef struct -{ - mz_zip_archive *pZip; - mz_uint flags; - - int status; -#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS - mz_uint file_crc32; -#endif - mz_uint64 read_buf_size, read_buf_ofs, read_buf_avail, comp_remaining, out_buf_ofs, cur_file_ofs; - mz_zip_archive_file_stat file_stat; - void *pRead_buf; - void *pWrite_buf; - - size_t out_blk_remain; - - tinfl_decompressor inflator; - -} mz_zip_reader_extract_iter_state; - -/* -------- ZIP reading */ - -/* Inits a ZIP archive reader. */ -/* These functions read and validate the archive's central directory. */ -mz_bool mz_zip_reader_init(mz_zip_archive *pZip, mz_uint64 size, mz_uint flags); - -mz_bool mz_zip_reader_init_mem(mz_zip_archive *pZip, const void *pMem, size_t size, mz_uint flags); - -#ifndef MINIZ_NO_STDIO -/* Read a archive from a disk file. */ -/* file_start_ofs is the file offset where the archive actually begins, or 0. */ -/* actual_archive_size is the true total size of the archive, which may be smaller than the file's actual size on disk. If zero the entire file is treated as the archive. */ -mz_bool mz_zip_reader_init_file(mz_zip_archive *pZip, const char *pFilename, mz_uint32 flags); -mz_bool mz_zip_reader_init_file_v2(mz_zip_archive *pZip, const char *pFilename, mz_uint flags, mz_uint64 file_start_ofs, mz_uint64 archive_size); - -/* Read an archive from an already opened FILE, beginning at the current file position. */ -/* The archive is assumed to be archive_size bytes long. If archive_size is < 0, then the entire rest of the file is assumed to contain the archive. */ -/* The FILE will NOT be closed when mz_zip_reader_end() is called. */ -mz_bool mz_zip_reader_init_cfile(mz_zip_archive *pZip, MZ_FILE *pFile, mz_uint64 archive_size, mz_uint flags); -#endif - -/* Ends archive reading, freeing all allocations, and closing the input archive file if mz_zip_reader_init_file() was used. */ -mz_bool mz_zip_reader_end(mz_zip_archive *pZip); - -/* -------- ZIP reading or writing */ - -/* Clears a mz_zip_archive struct to all zeros. */ -/* Important: This must be done before passing the struct to any mz_zip functions. */ -void mz_zip_zero_struct(mz_zip_archive *pZip); - -mz_zip_mode mz_zip_get_mode(mz_zip_archive *pZip); -mz_zip_type mz_zip_get_type(mz_zip_archive *pZip); - -/* Returns the total number of files in the archive. */ -mz_uint mz_zip_reader_get_num_files(mz_zip_archive *pZip); - -mz_uint64 mz_zip_get_archive_size(mz_zip_archive *pZip); -mz_uint64 mz_zip_get_archive_file_start_offset(mz_zip_archive *pZip); -MZ_FILE *mz_zip_get_cfile(mz_zip_archive *pZip); - -/* Reads n bytes of raw archive data, starting at file offset file_ofs, to pBuf. */ -size_t mz_zip_read_archive_data(mz_zip_archive *pZip, mz_uint64 file_ofs, void *pBuf, size_t n); - -/* All mz_zip funcs set the m_last_error field in the mz_zip_archive struct. These functions retrieve/manipulate this field. */ -/* Note that the m_last_error functionality is not thread safe. */ -mz_zip_error mz_zip_set_last_error(mz_zip_archive *pZip, mz_zip_error err_num); -mz_zip_error mz_zip_peek_last_error(mz_zip_archive *pZip); -mz_zip_error mz_zip_clear_last_error(mz_zip_archive *pZip); -mz_zip_error mz_zip_get_last_error(mz_zip_archive *pZip); -const char *mz_zip_get_error_string(mz_zip_error mz_err); - -/* MZ_TRUE if the archive file entry is a directory entry. */ -mz_bool mz_zip_reader_is_file_a_directory(mz_zip_archive *pZip, mz_uint file_index); - -/* MZ_TRUE if the file is encrypted/strong encrypted. */ -mz_bool mz_zip_reader_is_file_encrypted(mz_zip_archive *pZip, mz_uint file_index); - -/* MZ_TRUE if the compression method is supported, and the file is not encrypted, and the file is not a compressed patch file. */ -mz_bool mz_zip_reader_is_file_supported(mz_zip_archive *pZip, mz_uint file_index); - -/* Retrieves the filename of an archive file entry. */ -/* Returns the number of bytes written to pFilename, or if filename_buf_size is 0 this function returns the number of bytes needed to fully store the filename. */ -mz_uint mz_zip_reader_get_filename(mz_zip_archive *pZip, mz_uint file_index, char *pFilename, mz_uint filename_buf_size); - -/* Attempts to locates a file in the archive's central directory. */ -/* Valid flags: MZ_ZIP_FLAG_CASE_SENSITIVE, MZ_ZIP_FLAG_IGNORE_PATH */ -/* Returns -1 if the file cannot be found. */ -int mz_zip_reader_locate_file(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags); -int mz_zip_reader_locate_file_v2(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags, mz_uint32 *file_index); - -/* Returns detailed information about an archive file entry. */ -mz_bool mz_zip_reader_file_stat(mz_zip_archive *pZip, mz_uint file_index, mz_zip_archive_file_stat *pStat); - -/* MZ_TRUE if the file is in zip64 format. */ -/* A file is considered zip64 if it contained a zip64 end of central directory marker, or if it contained any zip64 extended file information fields in the central directory. */ -mz_bool mz_zip_is_zip64(mz_zip_archive *pZip); - -/* Returns the total central directory size in bytes. */ -/* The current max supported size is <= MZ_UINT32_MAX. */ -size_t mz_zip_get_central_dir_size(mz_zip_archive *pZip); - -/* Extracts a archive file to a memory buffer using no memory allocation. */ -/* There must be at least enough room on the stack to store the inflator's state (~34KB or so). */ -mz_bool mz_zip_reader_extract_to_mem_no_alloc(mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size); -mz_bool mz_zip_reader_extract_file_to_mem_no_alloc(mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size); - -/* Extracts a archive file to a memory buffer. */ -mz_bool mz_zip_reader_extract_to_mem(mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, mz_uint flags); -mz_bool mz_zip_reader_extract_file_to_mem(mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, mz_uint flags); - -/* Extracts a archive file to a dynamically allocated heap buffer. */ -/* The memory will be allocated via the mz_zip_archive's alloc/realloc functions. */ -/* Returns NULL and sets the last error on failure. */ -void *mz_zip_reader_extract_to_heap(mz_zip_archive *pZip, mz_uint file_index, size_t *pSize, mz_uint flags); -void *mz_zip_reader_extract_file_to_heap(mz_zip_archive *pZip, const char *pFilename, size_t *pSize, mz_uint flags); - -/* Extracts a archive file using a callback function to output the file's data. */ -mz_bool mz_zip_reader_extract_to_callback(mz_zip_archive *pZip, mz_uint file_index, mz_file_write_func pCallback, void *pOpaque, mz_uint flags); -mz_bool mz_zip_reader_extract_file_to_callback(mz_zip_archive *pZip, const char *pFilename, mz_file_write_func pCallback, void *pOpaque, mz_uint flags); - -/* Extract a file iteratively */ -mz_zip_reader_extract_iter_state* mz_zip_reader_extract_iter_new(mz_zip_archive *pZip, mz_uint file_index, mz_uint flags); -mz_zip_reader_extract_iter_state* mz_zip_reader_extract_file_iter_new(mz_zip_archive *pZip, const char *pFilename, mz_uint flags); -size_t mz_zip_reader_extract_iter_read(mz_zip_reader_extract_iter_state* pState, void* pvBuf, size_t buf_size); -mz_bool mz_zip_reader_extract_iter_free(mz_zip_reader_extract_iter_state* pState); - -#ifndef MINIZ_NO_STDIO -/* Extracts a archive file to a disk file and sets its last accessed and modified times. */ -/* This function only extracts files, not archive directory records. */ -mz_bool mz_zip_reader_extract_to_file(mz_zip_archive *pZip, mz_uint file_index, const char *pDst_filename, mz_uint flags); -mz_bool mz_zip_reader_extract_file_to_file(mz_zip_archive *pZip, const char *pArchive_filename, const char *pDst_filename, mz_uint flags); - -/* Extracts a archive file starting at the current position in the destination FILE stream. */ -mz_bool mz_zip_reader_extract_to_cfile(mz_zip_archive *pZip, mz_uint file_index, MZ_FILE *File, mz_uint flags); -mz_bool mz_zip_reader_extract_file_to_cfile(mz_zip_archive *pZip, const char *pArchive_filename, MZ_FILE *pFile, mz_uint flags); -#endif - -#if 0 -/* TODO */ - typedef void *mz_zip_streaming_extract_state_ptr; - mz_zip_streaming_extract_state_ptr mz_zip_streaming_extract_begin(mz_zip_archive *pZip, mz_uint file_index, mz_uint flags); - uint64_t mz_zip_streaming_extract_get_size(mz_zip_archive *pZip, mz_zip_streaming_extract_state_ptr pState); - uint64_t mz_zip_streaming_extract_get_cur_ofs(mz_zip_archive *pZip, mz_zip_streaming_extract_state_ptr pState); - mz_bool mz_zip_streaming_extract_seek(mz_zip_archive *pZip, mz_zip_streaming_extract_state_ptr pState, uint64_t new_ofs); - size_t mz_zip_streaming_extract_read(mz_zip_archive *pZip, mz_zip_streaming_extract_state_ptr pState, void *pBuf, size_t buf_size); - mz_bool mz_zip_streaming_extract_end(mz_zip_archive *pZip, mz_zip_streaming_extract_state_ptr pState); -#endif - -/* This function compares the archive's local headers, the optional local zip64 extended information block, and the optional descriptor following the compressed data vs. the data in the central directory. */ -/* It also validates that each file can be successfully uncompressed unless the MZ_ZIP_FLAG_VALIDATE_HEADERS_ONLY is specified. */ -mz_bool mz_zip_validate_file(mz_zip_archive *pZip, mz_uint file_index, mz_uint flags); - -/* Validates an entire archive by calling mz_zip_validate_file() on each file. */ -mz_bool mz_zip_validate_archive(mz_zip_archive *pZip, mz_uint flags); - -/* Misc utils/helpers, valid for ZIP reading or writing */ -mz_bool mz_zip_validate_mem_archive(const void *pMem, size_t size, mz_uint flags, mz_zip_error *pErr); -mz_bool mz_zip_validate_file_archive(const char *pFilename, mz_uint flags, mz_zip_error *pErr); - -/* Universal end function - calls either mz_zip_reader_end() or mz_zip_writer_end(). */ -mz_bool mz_zip_end(mz_zip_archive *pZip); - -/* -------- ZIP writing */ - -#ifndef MINIZ_NO_ARCHIVE_WRITING_APIS - -/* Inits a ZIP archive writer. */ -/*Set pZip->m_pWrite (and pZip->m_pIO_opaque) before calling mz_zip_writer_init or mz_zip_writer_init_v2*/ -/*The output is streamable, i.e. file_ofs in mz_file_write_func always increases only by n*/ -mz_bool mz_zip_writer_init(mz_zip_archive *pZip, mz_uint64 existing_size); -mz_bool mz_zip_writer_init_v2(mz_zip_archive *pZip, mz_uint64 existing_size, mz_uint flags); - -mz_bool mz_zip_writer_init_heap(mz_zip_archive *pZip, size_t size_to_reserve_at_beginning, size_t initial_allocation_size); -mz_bool mz_zip_writer_init_heap_v2(mz_zip_archive *pZip, size_t size_to_reserve_at_beginning, size_t initial_allocation_size, mz_uint flags); - -#ifndef MINIZ_NO_STDIO -mz_bool mz_zip_writer_init_file(mz_zip_archive *pZip, const char *pFilename, mz_uint64 size_to_reserve_at_beginning); -mz_bool mz_zip_writer_init_file_v2(mz_zip_archive *pZip, const char *pFilename, mz_uint64 size_to_reserve_at_beginning, mz_uint flags); -mz_bool mz_zip_writer_init_cfile(mz_zip_archive *pZip, MZ_FILE *pFile, mz_uint flags); -#endif - -/* Converts a ZIP archive reader object into a writer object, to allow efficient in-place file appends to occur on an existing archive. */ -/* For archives opened using mz_zip_reader_init_file, pFilename must be the archive's filename so it can be reopened for writing. If the file can't be reopened, mz_zip_reader_end() will be called. */ -/* For archives opened using mz_zip_reader_init_mem, the memory block must be growable using the realloc callback (which defaults to realloc unless you've overridden it). */ -/* Finally, for archives opened using mz_zip_reader_init, the mz_zip_archive's user provided m_pWrite function cannot be NULL. */ -/* Note: In-place archive modification is not recommended unless you know what you're doing, because if execution stops or something goes wrong before */ -/* the archive is finalized the file's central directory will be hosed. */ -mz_bool mz_zip_writer_init_from_reader(mz_zip_archive *pZip, const char *pFilename); -mz_bool mz_zip_writer_init_from_reader_v2(mz_zip_archive *pZip, const char *pFilename, mz_uint flags); - -/* Adds the contents of a memory buffer to an archive. These functions record the current local time into the archive. */ -/* To add a directory entry, call this method with an archive name ending in a forwardslash with an empty buffer. */ -/* level_and_flags - compression level (0-10, see MZ_BEST_SPEED, MZ_BEST_COMPRESSION, etc.) logically OR'd with zero or more mz_zip_flags, or just set to MZ_DEFAULT_COMPRESSION. */ -mz_bool mz_zip_writer_add_mem(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, mz_uint level_and_flags); - -/* Like mz_zip_writer_add_mem(), except you can specify a file comment field, and optionally supply the function with already compressed data. */ -/* uncomp_size/uncomp_crc32 are only used if the MZ_ZIP_FLAG_COMPRESSED_DATA flag is specified. */ -mz_bool mz_zip_writer_add_mem_ex(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, - mz_uint64 uncomp_size, mz_uint32 uncomp_crc32); - -mz_bool mz_zip_writer_add_mem_ex_v2(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, - mz_uint64 uncomp_size, mz_uint32 uncomp_crc32, MZ_TIME_T *last_modified, const char *user_extra_data_local, mz_uint user_extra_data_local_len, - const char *user_extra_data_central, mz_uint user_extra_data_central_len); - -/* Adds the contents of a file to an archive. This function also records the disk file's modified time into the archive. */ -/* File data is supplied via a read callback function. User mz_zip_writer_add_(c)file to add a file directly.*/ -mz_bool mz_zip_writer_add_read_buf_callback(mz_zip_archive *pZip, const char *pArchive_name, mz_file_read_func read_callback, void* callback_opaque, mz_uint64 size_to_add, - const MZ_TIME_T *pFile_time, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, const char *user_extra_data_local, mz_uint user_extra_data_local_len, - const char *user_extra_data_central, mz_uint user_extra_data_central_len); - -#ifndef MINIZ_NO_STDIO -/* Adds the contents of a disk file to an archive. This function also records the disk file's modified time into the archive. */ -/* level_and_flags - compression level (0-10, see MZ_BEST_SPEED, MZ_BEST_COMPRESSION, etc.) logically OR'd with zero or more mz_zip_flags, or just set to MZ_DEFAULT_COMPRESSION. */ -mz_bool mz_zip_writer_add_file(mz_zip_archive *pZip, const char *pArchive_name, const char *pSrc_filename, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags); - -/* Like mz_zip_writer_add_file(), except the file data is read from the specified FILE stream. */ -mz_bool mz_zip_writer_add_cfile(mz_zip_archive *pZip, const char *pArchive_name, MZ_FILE *pSrc_file, mz_uint64 size_to_add, - const MZ_TIME_T *pFile_time, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, const char *user_extra_data_local, mz_uint user_extra_data_local_len, - const char *user_extra_data_central, mz_uint user_extra_data_central_len); -#endif - -/* Adds a file to an archive by fully cloning the data from another archive. */ -/* This function fully clones the source file's compressed data (no recompression), along with its full filename, extra data (it may add or modify the zip64 local header extra data field), and the optional descriptor following the compressed data. */ -mz_bool mz_zip_writer_add_from_zip_reader(mz_zip_archive *pZip, mz_zip_archive *pSource_zip, mz_uint src_file_index); - -/* Finalizes the archive by writing the central directory records followed by the end of central directory record. */ -/* After an archive is finalized, the only valid call on the mz_zip_archive struct is mz_zip_writer_end(). */ -/* An archive must be manually finalized by calling this function for it to be valid. */ -mz_bool mz_zip_writer_finalize_archive(mz_zip_archive *pZip); - -/* Finalizes a heap archive, returning a pointer to the heap block and its size. */ -/* The heap block will be allocated using the mz_zip_archive's alloc/realloc callbacks. */ -mz_bool mz_zip_writer_finalize_heap_archive(mz_zip_archive *pZip, void **ppBuf, size_t *pSize); - -/* Ends archive writing, freeing all allocations, and closing the output file if mz_zip_writer_init_file() was used. */ -/* Note for the archive to be valid, it *must* have been finalized before ending (this function will not do it for you). */ -mz_bool mz_zip_writer_end(mz_zip_archive *pZip); - -/* -------- Misc. high-level helper functions: */ - -/* mz_zip_add_mem_to_archive_file_in_place() efficiently (but not atomically) appends a memory blob to a ZIP archive. */ -/* Note this is NOT a fully safe operation. If it crashes or dies in some way your archive can be left in a screwed up state (without a central directory). */ -/* level_and_flags - compression level (0-10, see MZ_BEST_SPEED, MZ_BEST_COMPRESSION, etc.) logically OR'd with zero or more mz_zip_flags, or just set to MZ_DEFAULT_COMPRESSION. */ -/* TODO: Perhaps add an option to leave the existing central dir in place in case the add dies? We could then truncate the file (so the old central dir would be at the end) if something goes wrong. */ -mz_bool mz_zip_add_mem_to_archive_file_in_place(const char *pZip_filename, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags); -mz_bool mz_zip_add_mem_to_archive_file_in_place_v2(const char *pZip_filename, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, mz_zip_error *pErr); - -/* Reads a single file from an archive into a heap block. */ -/* If pComment is not NULL, only the file with the specified comment will be extracted. */ -/* Returns NULL on failure. */ -void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename, const char *pArchive_name, size_t *pSize, mz_uint flags); -void *mz_zip_extract_archive_file_to_heap_v2(const char *pZip_filename, const char *pArchive_name, const char *pComment, size_t *pSize, mz_uint flags, mz_zip_error *pErr); - -#endif /* #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS */ - -#ifdef __cplusplus -} -#endif - -#endif /* MINIZ_NO_ARCHIVE_APIS */ diff --git a/tools/esptool_py/flasher_stub/include/rom_functions.h b/tools/esptool_py/flasher_stub/include/rom_functions.h deleted file mode 100644 index 5c7d5a8d8c..0000000000 --- a/tools/esptool_py/flasher_stub/include/rom_functions.h +++ /dev/null @@ -1,356 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2016 Cesanta Software Limited - * - * SPDX-License-Identifier: GPL-2.0-or-later - * - * SPDX-FileContributor: 2016-2022 Espressif Systems (Shanghai) CO LTD - */ - -/* ROM function prototypes for functions in ROM which are - called by the flasher stubs. -*/ -#pragma once - -#include -#include "soc_support.h" - -int uart_rx_one_char(uint8_t *ch); -uint8_t uart_rx_one_char_block(); -int uart_tx_one_char(char ch); - -#if ESP32C6 || ESP32H2 || ESP32C5BETA3 || ESP32P4 -/* uart_tx_one_char doesn't send data to USB device serial, needs to be replaced */ -int uart_tx_one_char2(char ch); -#define uart_tx_one_char(ch) uart_tx_one_char2(ch) -#endif // ESP32C6 || ESP32H2 || ESP32C5BETA3 || ESP32P4 - -void uart_div_modify(uint32_t uart_no, uint32_t baud_div); - -void ets_delay_us(uint32_t us); - -typedef enum { SPI_FLASH_RESULT_OK = 0, - SPI_FLASH_RESULT_ERR = 1, - SPI_FLASH_RESULT_TIMEOUT = 2 } SpiFlashOpResult; - -SpiFlashOpResult SPILock(); -SpiFlashOpResult SPIUnlock(); -SpiFlashOpResult SPIRead(uint32_t addr, void *dst, uint32_t size); -SpiFlashOpResult SPIWrite(uint32_t addr, const uint8_t *src, uint32_t size); -SpiFlashOpResult SPIEraseChip(); -SpiFlashOpResult SPIEraseBlock(uint32_t block_num); -SpiFlashOpResult SPIEraseSector(uint32_t sector_num); -uint32_t SPI_read_status(); -uint32_t Wait_SPI_Idle(); -void spi_flash_attach(); - -void SelectSpiFunction(); -uint32_t SPIParamCfg(uint32_t deviceId, uint32_t chip_size, uint32_t block_size, uint32_t sector_size, uint32_t page_size, uint32_t status_mask); - -void ets_isr_mask(uint32_t ints); -void ets_isr_unmask(uint32_t ints); -void ets_set_user_start(void (*user_start_fn)()); - -void software_reset(); -void software_reset_cpu(int cpu_no); - -#ifdef ESP32C2 // ESP32C2 ROM uses mbedtls_md5 -struct MD5Context { // Called mbedtls_md5_context in ROM - uint32_t total[2]; // number of bytes processed - uint32_t state[4]; // intermediate digest state - unsigned char buffer[64]; // data block being processed -}; - -int mbedtls_md5_starts_ret(struct MD5Context *ctx); -int mbedtls_md5_update_ret(struct MD5Context *ctx, const unsigned char *input, size_t ilen); -int mbedtls_md5_finish_ret(struct MD5Context *ctx, unsigned char digest[16]); - -#define MD5Init(ctx) mbedtls_md5_starts_ret(ctx) -#define MD5Update(ctx, buf, n) mbedtls_md5_update_ret(ctx, buf, n) -#define MD5Final(digest, ctx) mbedtls_md5_finish_ret(ctx, digest) -#else // not ESP32C2 -struct MD5Context { - uint32_t buf[4]; - uint32_t bits[2]; - uint8_t in[64]; -}; - -void MD5Init(struct MD5Context *ctx); -void MD5Update(struct MD5Context *ctx, void *buf, uint32_t len); -void MD5Final(uint8_t digest[16], struct MD5Context *ctx); -#endif // not ESP32C2 - -typedef struct { - uint32_t device_id; - uint32_t chip_size; // chip size in bytes - uint32_t block_size; - uint32_t sector_size; - uint32_t page_size; - uint32_t status_mask; -} esp_rom_spiflash_chip_t; - - -typedef void (*int_handler_t)(void *arg); -int_handler_t ets_isr_attach(uint32_t int_num, int_handler_t handler, - void *arg); -/* Some ESP32-onwards ROM functions */ -#if ESP32_OR_LATER -void uart_tx_flush(int uart); -uint32_t ets_efuse_get_spiconfig(void); - -#if ESP32 -SpiFlashOpResult esp_rom_spiflash_write_encrypted(uint32_t addr, const uint8_t *src, uint32_t size); -#else -void SPI_Write_Encrypt_Enable(); -void SPI_Write_Encrypt_Disable(); -SpiFlashOpResult SPI_Encrypt_Write(uint32_t flash_addr, const void* data, uint32_t len); -#endif - -#if ESP32S2_OR_LATER -uint32_t GetSecurityInfoProc(int* pMsg, int* pnErr, uint8_t *buf); // pMsg and pnErr unused in ROM -#if ESP32C3 -extern uint32_t _rom_eco_version; // rom constant to define ECO version -uint32_t GetSecurityInfoProcNewEco(int* pMsg, int* pnErr, uint8_t *buf); // GetSecurityInfo for C3 ECO7+ -#endif // ESP32C3 -SpiFlashOpResult SPI_read_status_high(esp_rom_spiflash_chip_t *spi, uint32_t *status); -#else -/* Note: On ESP32 this was a static function whose first argument was elided by the - compiler. */ -SpiFlashOpResult SPI_read_status_high(uint32_t *status); -#endif - -SpiFlashOpResult SPI_write_status(esp_rom_spiflash_chip_t *spi, uint32_t status_value); - -void intr_matrix_set(int cpu_no, uint32_t module_num, uint32_t intr_num); -#endif /* ESP32_OR_LATER */ - -/* RISC-V-only ROM functions */ -#if IS_RISCV -void esprv_intc_int_set_priority(int intr_num, int priority); -#endif // IS_RISCV - -/* USB-OTG and USB-JTAG-Serial imports */ -#ifdef WITH_USB_OTG -#define ACM_BYTES_PER_TX 64 -#define ACM_STATUS_LINESTATE_CHANGED -1 -#define ACM_STATUS_RX -4 -#define LINE_CTRL_BAUD_RATE (1 << 0) -#define LINE_CTRL_RTS (1 << 1) -#define LINE_CTRL_DTR (1 << 2) -#define LINE_CTRL_DCD (1 << 3) -#define LINE_CTRL_DSR (1 << 4) -#define USBDC_PERSIST_ENA (1<<31) -void usb_dw_isr_handler(void* arg); -typedef void cdc_acm_device; -extern cdc_acm_device *uart_acm_dev; -typedef void(*uart_irq_callback_t)(cdc_acm_device *dev, int status); -void cdc_acm_irq_callback_set(cdc_acm_device *dev, uart_irq_callback_t cb); -void cdc_acm_irq_rx_enable(cdc_acm_device *dev); -void cdc_acm_irq_rx_disable(cdc_acm_device *dev); -int cdc_acm_fifo_read(cdc_acm_device *dev, uint8_t *rx_data, const int size); -int cdc_acm_fifo_fill(cdc_acm_device *dev, const uint8_t *tx_data, int len); -int cdc_acm_line_ctrl_get(cdc_acm_device *dev, uint32_t ctrl, uint32_t *val); -int cdc_acm_rx_fifo_cnt(cdc_acm_device *dev); -void cdc_acm_irq_state_enable(cdc_acm_device *dev); -void usb_dc_check_poll_for_interrupts(void); -void chip_usb_set_persist_flags(uint32_t flags); -int usb_dc_prepare_persist(void); -#endif // WITH_USB_OTG - -#if WITH_USB_JTAG_SERIAL || WITH_USB_OTG -typedef struct { - uint8_t *pRcvMsgBuff; - uint8_t *pWritePos; - uint8_t *pReadPos; - uint8_t TrigLvl; - int BuffState; -} RcvMsgBuff; - -typedef struct { - int baud_rate; - int data_bits; - int exist_parity; - int parity; - int stop_bits; - int flow_ctrl; - uint8_t buff_uart_no; - RcvMsgBuff rcv_buff; - int rcv_state; - int received; -} UartDevice; - -UartDevice * GetUartDevice(); -#endif // WITH_USB_JTAG_SERIAL || WITH_USB_OTG - -#if defined(ESP32S3) -#define BIT(nr) (1UL << (nr)) -#define ESP_ROM_OPIFLASH_SEL_CS0 (BIT(0)) - -typedef enum { - SPI_FLASH_QIO_MODE = 0, - SPI_FLASH_QOUT_MODE, - SPI_FLASH_DIO_MODE, - SPI_FLASH_DOUT_MODE, - SPI_FLASH_FASTRD_MODE, - SPI_FLASH_SLOWRD_MODE, - SPI_FLASH_OPI_STR_MODE, - SPI_FLASH_OPI_DTR_MODE, - SPI_FLASH_OOUT_MODE, - SPI_FLASH_OIO_STR_MODE, - SPI_FLASH_OIO_DTR_MODE, - SPI_FLASH_QPI_MODE, -} SpiFlashRdMode; - -typedef enum { - ESP_ROM_SPIFLASH_RESULT_OK, - ESP_ROM_SPIFLASH_RESULT_ERR, - ESP_ROM_SPIFLASH_RESULT_TIMEOUT -} esp_rom_spiflash_result_t; - -#define CMD_RDID 0x9F -#define CMD_RDSR 0x05 -#define CMD_WREN 0x06 -#define CMD_SECTOR_ERASE 0x20 -#define CMD_SECTOR_ERASE_4B 0x21 -#define CMD_FSTRD4B 0x0C -#define CMD_LARGE_BLOCK_ERASE 0xD8 -#define CMD_LARGE_BLOCK_ERASE_4B 0xDC -#define CMD_PROGRAM_PAGE_4B 0x12 - -#define OPIFLASH_DRIVER() { \ - .rdid = { \ - .mode = SPI_FLASH_FASTRD_MODE, \ - .cmd_bit_len = 8, \ - .cmd = CMD_RDID, \ - .addr = 0, \ - .addr_bit_len = 0, \ - .dummy_bit_len = 0, \ - .data_bit_len = 24, \ - .cs_sel = 0x1, \ - .is_pe = 0, \ - }, \ - .rdsr = { \ - .mode = SPI_FLASH_FASTRD_MODE, \ - .cmd_bit_len = 8, \ - .cmd = CMD_RDSR, \ - .addr = 0, \ - .addr_bit_len = 0, \ - .dummy_bit_len = 0, \ - .data_bit_len = 8, \ - .cs_sel = 0x1, \ - .is_pe = 0, \ - }, \ - .wren = { \ - .mode = SPI_FLASH_FASTRD_MODE, \ - .cmd_bit_len = 8, \ - .cmd = CMD_WREN, \ - .addr = 0, \ - .addr_bit_len = 0, \ - .dummy_bit_len = 0, \ - .data_bit_len = 0, \ - .cs_sel = 0x1, \ - .is_pe = 0, \ - }, \ - .se = { \ - .mode = SPI_FLASH_FASTRD_MODE, \ - .cmd_bit_len = 8, \ - .cmd = CMD_SECTOR_ERASE_4B, \ - .addr = 0, \ - .addr_bit_len = 32, \ - .dummy_bit_len = 0, \ - .data_bit_len = 0, \ - .cs_sel = 0x1, \ - .is_pe = 1, \ - }, \ - .be64k = { \ - .mode = SPI_FLASH_FASTRD_MODE, \ - .cmd_bit_len = 8, \ - .cmd = CMD_LARGE_BLOCK_ERASE_4B, \ - .addr = 0, \ - .addr_bit_len = 32, \ - .dummy_bit_len = 0, \ - .data_bit_len = 0, \ - .cs_sel = 0x1, \ - .is_pe = 1, \ - }, \ - .read = { \ - .mode = SPI_FLASH_FASTRD_MODE, \ - .cmd_bit_len = 8, \ - .cmd = CMD_FSTRD4B, \ - .addr = 0, \ - .addr_bit_len = 32, \ - .dummy_bit_len = 0, \ - .data_bit_len = 0, \ - .cs_sel = 0x1, \ - .is_pe = 0, \ - }, \ - .pp = { \ - .mode = SPI_FLASH_FASTRD_MODE, \ - .cmd_bit_len = 8, \ - .cmd = CMD_PROGRAM_PAGE_4B, \ - .addr = 0, \ - .addr_bit_len = 32, \ - .dummy_bit_len = 0, \ - .data_bit_len = 0, \ - .cs_sel = 0x1, \ - .is_pe = 1, \ - }, \ - .cache_rd_cmd = { \ - .addr_bit_len = 32, \ - .dummy_bit_len = 20*2, \ - .cmd = CMD_FSTRD4B, \ - .cmd_bit_len = 16, \ - .var_dummy_en = 1, \ - } \ -} - -#ifndef ESP32S3BETA2 -typedef struct { - uint8_t mode; - uint8_t cmd_bit_len; - uint16_t cmd; - uint32_t addr; - uint8_t addr_bit_len; - uint8_t dummy_bit_len; - uint8_t data_bit_len; - uint8_t cs_sel: 4; - uint8_t is_pe: 4; -} esp_rom_opiflash_cmd_t; - -typedef struct { - uint8_t addr_bit_len; - uint8_t dummy_bit_len; - uint16_t cmd; - uint8_t cmd_bit_len; - uint8_t var_dummy_en; -} esp_rom_opiflash_spi0rd_t; - -typedef struct { - esp_rom_opiflash_cmd_t rdid; - esp_rom_opiflash_cmd_t rdsr; - esp_rom_opiflash_cmd_t wren; - esp_rom_opiflash_cmd_t se; - esp_rom_opiflash_cmd_t be64k; - esp_rom_opiflash_cmd_t read; - esp_rom_opiflash_cmd_t pp; - esp_rom_opiflash_spi0rd_t cache_rd_cmd; -} esp_rom_opiflash_def_t; - -void esp_rom_opiflash_legacy_driver_init(const esp_rom_opiflash_def_t *flash_cmd_def); -bool ets_efuse_flash_octal_mode(void); -#endif //ESP32S3BETA2 - -void esp_rom_opiflash_exec_cmd(int spi_num, SpiFlashRdMode mode, - uint32_t cmd, int cmd_bit_len, - uint32_t addr, int addr_bit_len, - int dummy_bits, - uint8_t* mosi_data, int mosi_bit_len, - uint8_t* miso_data, int miso_bit_len, - uint32_t cs_mask, - bool is_write_erase_operation); - -esp_rom_spiflash_result_t esp_rom_opiflash_wait_idle(); -esp_rom_spiflash_result_t esp_rom_opiflash_wren(); -esp_rom_spiflash_result_t esp_rom_opiflash_erase_sector(uint32_t sector_num); -esp_rom_spiflash_result_t esp_rom_opiflash_erase_block_64k(uint32_t block_num); -SpiFlashOpResult SPI_write_enable(esp_rom_spiflash_chip_t *spi); -#endif // ESP32S3 diff --git a/tools/esptool_py/flasher_stub/include/slip.h b/tools/esptool_py/flasher_stub/include/slip.h deleted file mode 100644 index 17608e5fb9..0000000000 --- a/tools/esptool_py/flasher_stub/include/slip.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2016 Cesanta Software Limited - * - * SPDX-License-Identifier: GPL-2.0-or-later - * - * SPDX-FileContributor: 2016-2022 Espressif Systems (Shanghai) CO LTD - */ - -#ifndef SLIP_H_ -#define SLIP_H_ - -#include - -/* Send the SLIP frame begin/end delimiter. */ -void SLIP_send_frame_delimiter(void); - -/* Send a single character of SLIP frame data, escaped as per SLIP escaping. */ -void SLIP_send_frame_data(char ch); - -/* Send some SLIP frame data, escaped as per SLIP escaping. */ -void SLIP_send_frame_data_buf(const void *buf, uint32_t size); - -/* Send a full SLIP frame, with specified contents. */ -void SLIP_send(const void *pkt, uint32_t size); - -typedef enum { - SLIP_NO_FRAME, - SLIP_FRAME, - SLIP_FRAME_ESCAPING -} slip_state_t; - -int16_t SLIP_recv_byte(char byte, slip_state_t *state); - -#define SLIP_FINISHED_FRAME -2 -#define SLIP_NO_BYTE -1 - -/* Receive a SLIP frame, with specified contents. */ -uint32_t SLIP_recv(void *pkt, uint32_t max_len); - -#endif /* SLIP_H_ */ diff --git a/tools/esptool_py/flasher_stub/include/soc_support.h b/tools/esptool_py/flasher_stub/include/soc_support.h deleted file mode 100644 index eed774bdc2..0000000000 --- a/tools/esptool_py/flasher_stub/include/soc_support.h +++ /dev/null @@ -1,592 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2016-2022 Espressif Systems (Shanghai) CO LTD - * - * SPDX-License-Identifier: GPL-2.0-or-later - */ - -/* SoC-level support. - * - * Provide a unified register-level interface. - * - * This is the same information provided in the register headers - * of ESP8266 Non-OS SDK and ESP-IDF soc component, however - * only values that are needed for the flasher stub are included here. - * - */ -#pragma once - -#include -#include -#include - -#define READ_REG(REG) (*((volatile uint32_t *)(REG))) -#define WRITE_REG(REG, VAL) *((volatile uint32_t *)(REG)) = (VAL) -#define REG_SET_MASK(reg, mask) WRITE_REG((reg), (READ_REG(reg)|(mask))) -#define REG_CLR_MASK(reg, mask) WRITE_REG((reg), (READ_REG(reg)&(~(mask)))) -#define REG_SET_FIELD(_r, _f, _v) (WRITE_REG((_r),((READ_REG(_r) & ~((_f) << (_f##_S)))|(((_v) & (_f))<<(_f##_S))))) - -#define ESP32_OR_LATER !(ESP8266) -#define ESP32S2_OR_LATER !(ESP8266 || ESP32) -#define ESP32S3_OR_LATER !(ESP8266 || ESP32 || ESP32S2) - -/********************************************************** - * Per-SOC capabilities - */ -#ifdef ESP32S2 -#define WITH_USB_OTG 1 -#endif // ESP32S2 - -#ifdef ESP32C3 -#define WITH_USB_JTAG_SERIAL 1 -#define IS_RISCV 1 -#endif // ESP32C3 - -#ifdef ESP32S3 -#define WITH_USB_JTAG_SERIAL 1 -#define WITH_USB_OTG 1 -#endif // ESP32S3 - -#ifdef ESP32C5BETA3 -#define WITH_USB_JTAG_SERIAL 1 -#define IS_RISCV 1 -#endif // ESP32C5BETA3 - -#ifdef ESP32C6 -#define WITH_USB_JTAG_SERIAL 1 -#define IS_RISCV 1 -#endif // ESP32C6 - -#ifdef ESP32H2 -#define WITH_USB_JTAG_SERIAL 1 -#define IS_RISCV 1 -#endif // ESP32H2 - -#ifdef ESP32P4 -#define WITH_USB_JTAG_SERIAL 1 -// TODO: Add support for USB OTG when MP is available -// #define WITH_USB_OTG 1 -#define IS_RISCV 1 -#endif // ESP32P4 - -// Increase CPU freq to speed up read/write operations over USB -// Disabled on the S3 due to stability issues, would require dbias adjustment. -// https://github.com/espressif/esptool/issues/832, https://github.com/espressif/esptool/issues/808 -// Disabled for P4 because it is already running on high (360MHz) CPU frequency -#define USE_MAX_CPU_FREQ ((WITH_USB_JTAG_SERIAL || WITH_USB_OTG) && !ESP32S3 && !ESP32P4) - -// Later chips don't support ets_efuse_get_spiconfig. -#define SUPPORT_CONFIG_SPI (ESP32 || ESP32S2 || ESP32S3 || ESP32S3BETA2 || ESP32C3 || ESP32H2BETA1 || ESP32H2BETA2 || ESP32C6BETA) - -/********************************************************** - * Per-SOC based peripheral register base addresses - * Sync with reg_base.h in ESP-IDF - */ -#ifdef ESP8266 -#define UART_BASE_REG 0x60000000 /* UART0 */ -#define SPI_BASE_REG 0x60000200 /* SPI peripheral 0 */ -#endif - -#ifdef ESP32 -#define UART_BASE_REG 0x3ff40000 /* UART0 */ -#define SPI_BASE_REG 0x3ff42000 /* SPI peripheral 1, used for SPI flash */ -#define SPI0_BASE_REG 0x3ff43000 /* SPI peripheral 0, inner state machine */ -#define GPIO_BASE_REG 0x3ff44000 /* GPIO */ -#define DR_REG_IO_MUX_BASE 0x3ff49000 -#endif - -#ifdef ESP32S2 -#define UART_BASE_REG 0x60000000 /* UART0 */ -#define SPI_BASE_REG 0x3f402000 /* SPI peripheral 1, used for SPI flash */ -#define SPI0_BASE_REG 0x3f403000 /* SPI peripheral 0, inner state machine */ -#define GPIO_BASE_REG 0x3f404000 -#define USB_BASE_REG 0x60080000 -#define RTCCNTL_BASE_REG 0x3f408000 -#define SYSTEM_BASE_REG 0x3F4C0000 -#define DR_REG_IO_MUX_BASE 0x3f409000 -#endif - -#ifdef ESP32S3 -#define UART_BASE_REG 0x60000000 /* UART0 */ -#define SPI_BASE_REG 0x60002000 /* SPI peripheral 1, used for SPI flash */ -#define SPI0_BASE_REG 0x60003000 /* SPI peripheral 0, inner state machine */ -#define GPIO_BASE_REG 0x60004000 /* GPIO */ -#define USB_BASE_REG 0x60080000 -#define RTCCNTL_BASE_REG 0x60008000 /* RTC Control */ -#define USB_DEVICE_BASE_REG 0x60038000 -#define SYSTEM_BASE_REG 0x600C0000 -#define DR_REG_IO_MUX_BASE 0x60009000 -#endif - -#ifdef ESP32S3BETA2 -#define UART_BASE_REG 0x60000000 /* UART0 */ -#define SPI_BASE_REG 0x60002000 /* SPI peripheral 1, used for SPI flash */ -#define SPI0_BASE_REG 0x60003000 /* SPI peripheral 0, inner state machine */ -#define GPIO_BASE_REG 0x60004000 /* GPIO */ -#define USB_BASE_REG 0x60080000 -#define RTCCNTL_BASE_REG 0x60008000 /* RTC Control */ -#define USB_DEVICE_BASE_REG 0x60038000 -#define SYSTEM_BASE_REG 0x600C0000 -#define DR_REG_IO_MUX_BASE 0x60009000 -#endif - -#ifdef ESP32C3 -#define UART_BASE_REG 0x60000000 /* UART0 */ -#define SPI_BASE_REG 0x60002000 /* SPI peripheral 1, used for SPI flash */ -#define SPI0_BASE_REG 0x60003000 /* SPI peripheral 0, inner state machine */ -#define GPIO_BASE_REG 0x60004000 -#define RTCCNTL_BASE_REG 0x60008000 /* RTC Control */ -#define USB_DEVICE_BASE_REG 0x60043000 -#define SYSTEM_BASE_REG 0x600C0000 -#define DR_REG_IO_MUX_BASE 0x60009000 -#endif - -#ifdef ESP32C6BETA -#define UART_BASE_REG 0x60000000 /* UART0 */ -#define SPI_BASE_REG 0x60002000 /* SPI peripheral 1, used for SPI flash */ -#define SPI0_BASE_REG 0x60003000 /* SPI peripheral 0, inner state machine */ -#define GPIO_BASE_REG 0x60004000 -#define DR_REG_IO_MUX_BASE 0x60009000 -#endif - -#ifdef ESP32H2BETA1 -#define UART_BASE_REG 0x60000000 /* UART0 */ -#define SPI_BASE_REG 0x60002000 /* SPI peripheral 1, used for SPI flash */ -#define SPI0_BASE_REG 0x60003000 /* SPI peripheral 0, inner state machine */ -#define GPIO_BASE_REG 0x60004000 -#define RTCCNTL_BASE_REG 0x60008000 -#define DR_REG_IO_MUX_BASE 0x60009000 -#endif - -#ifdef ESP32H2BETA2 -#define UART_BASE_REG 0x60000000 /* UART0 */ -#define SPI_BASE_REG 0x60002000 /* SPI peripheral 1, used for SPI flash */ -#define SPI0_BASE_REG 0x60003000 /* SPI peripheral 0, inner state machine */ -#define GPIO_BASE_REG 0x60004000 -#define DR_REG_IO_MUX_BASE 0x60009000 -#endif - -#ifdef ESP32C2 -#define UART_BASE_REG 0x60000000 /* UART0 */ -#define SPI_BASE_REG 0x60002000 /* SPI peripheral 1, used for SPI flash */ -#define SPI0_BASE_REG 0x60003000 /* SPI peripheral 0, inner state machine */ -#define GPIO_BASE_REG 0x60004000 -#define DR_REG_IO_MUX_BASE 0x60009000 -#endif - -#if ESP32C6 || ESP32C5BETA3 -#define UART_BASE_REG 0x60000000 /* UART0 */ -#define SPI_BASE_REG 0x60003000 /* SPI peripheral 1, used for SPI flash */ -#define SPI0_BASE_REG 0x60002000 /* SPI peripheral 0, inner state machine */ -#define GPIO_BASE_REG 0x60091000 -#define USB_DEVICE_BASE_REG 0x6000F000 -#define DR_REG_PCR_BASE 0x60096000 -#define DR_REG_LP_WDT_BASE 0x600B1C00 -#define DR_REG_IO_MUX_BASE 0x60009000 -#endif - -#ifdef ESP32H2 -#define UART_BASE_REG 0x60000000 /* UART0 */ -#define SPI_BASE_REG 0x60003000 /* SPI peripheral 1, used for SPI flash */ -#define SPI0_BASE_REG 0x60002000 /* SPI peripheral 0, inner state machine */ -#define GPIO_BASE_REG 0x60091000 -#define USB_DEVICE_BASE_REG 0x6000F000 -#define DR_REG_PCR_BASE 0x60096000 -#define DR_REG_LP_WDT_BASE 0x600B1C00 -#define DR_REG_IO_MUX_BASE 0x60009000 -#endif - -#ifdef ESP32P4 -#define UART_BASE_REG 0x500CA000 /* UART0 */ -#define SPI_BASE_REG 0x5008D000 /* SPI peripheral 1, used for SPI flash */ -#define SPI0_BASE_REG 0x5008C000 /* SPI peripheral 0, inner state machine */ -#define GPIO_BASE_REG 0x500E0000 -#define USB_DEVICE_BASE_REG 0x500D2000 -#define DR_REG_LP_WDT_BASE 0x50116000 -#define DR_REG_IO_MUX_BASE 0x500E1000 -#endif - -/********************************************************** - * UART peripheral - * - * The features we use are basically the same on all chips - * - * Only UART0 is used - */ -#define UART_CLKDIV_REG(X) (UART_BASE_REG + 0x14) -#define UART_CLKDIV_M (0x000FFFFF) - -#if ESP32_OR_LATER -#define UART_CLKDIV_FRAG_S 20 -#define UART_CLKDIV_FRAG_V 0xF -#endif - -#define UART_FIFO(X) (UART_BASE_REG + 0x00) -#define UART_INT_ST(X) (UART_BASE_REG + 0x08) -#define UART_INT_ENA(X) (UART_BASE_REG + 0x0C) -#define UART_INT_CLR(X) (UART_BASE_REG + 0x10) -#define UART_STATUS(X) (UART_BASE_REG + 0x1C) - -#if ESP32S2_OR_LATER && !ESP32C6 && !ESP32H2 -#define UART_RXFIFO_CNT_M 0x3FF -#else -#define UART_RXFIFO_CNT_M 0xFF -#endif - -#define UART_RXFIFO_FULL_INT_ENA (1<<0) -#define UART_RXFIFO_TOUT_INT_ENA (1<<8) - -#define ETS_UART0_INUM 5 - - -/********************************************************** - * SPI peripheral - * - * The features we use are mostly the same on all chips - * except for W0 base address & option for 2-byte status command - * - * Only one SPI peripheral is used (0 on ESP8266, 1 on ESP32). - * On ESP32S2 && ESP32S3 this is called SPI_MEM_xxx index 1 - */ -#define SPI_CMD_REG (SPI_BASE_REG + 0x00) -#define SPI_FLASH_WREN (1<<30) -#define SPI_FLASH_RDSR (1<<27) -#define SPI_FLASH_SE (1<<24) -#define SPI_FLASH_BE (1<<23) - -#define SPI_ADDR_REG (SPI_BASE_REG + 0x04) - -#define SPI_CTRL_REG (SPI_BASE_REG + 0x08) -#if ESP32_OR_LATER -#define SPI_WRSR_2B (1<<22) -#endif - -#if ESP32S2_OR_LATER -#define SPI_RD_STATUS_REG (SPI_BASE_REG + 0x2C) -#else -#define SPI_RD_STATUS_REG (SPI_BASE_REG + 0x10) -#endif - -#ifdef ESP8266 -#define SPI_W0_REG (SPI_BASE_REG + 0x40) -#endif -#ifdef ESP32 -#define SPI_W0_REG (SPI_BASE_REG + 0x80) -#endif -#if ESP32S2_OR_LATER -#define SPI_W0_REG (SPI_BASE_REG + 0x58) -#endif - -#if ESP32S2_OR_LATER -#define SPI_EXT2_REG (SPI_BASE_REG + 0x54) /* renamed SPI_MEM_FSM_REG */ -#else -#define SPI_EXT2_REG (SPI_BASE_REG + 0xF8) -#endif - -#define SPI_ST 0x7 /* done state value */ - -#ifdef ESP32 -/* On ESP32 & newer the SPI peripherals are layered - * flash, this lets us check the state of the internal - * state machine under the SPI flash controller - */ -#define SPI0_EXT2_REG (SPI0_BASE_REG + 0xF8) -#endif -#if ESP32S2_OR_LATER -#define SPI0_EXT2_REG (SPI0_BASE_REG + 0x54) -#endif - -/********************************************************** - * GPIO peripheral - * - * We only need to read the strapping register on ESP32 or later - */ -#define GPIO_STRAP_REG (GPIO_BASE_REG + 0x38) - -/********************************************************** - * USB peripheral - */ - -#ifdef ESP32S2 -#define UART_USB_OTG 2 - -#define ETS_USB_INTR_SOURCE 48 -#define ETS_USB_INUM 9 /* arbitrary level 1 level interrupt */ -#endif // ESP32S2 - -#ifdef ESP32C3 -#define UART_USB_JTAG_SERIAL 3 - -#define DR_REG_INTERRUPT_CORE0_BASE 0x600c2000 -#define INTERRUPT_CORE0_USB_INTR_MAP_REG (DR_REG_INTERRUPT_CORE0_BASE + 0x068) /* USB-JTAG-Serial */ - -#define ETS_USB_INUM 17 /* arbitrary level 1 level interrupt */ -#endif // ESP32C3 - -#ifdef ESP32S3 -#define UART_USB_OTG 3 -#define UART_USB_JTAG_SERIAL 4 - -#define DR_REG_INTERRUPT_CORE0_BASE 0x600c2000 -#define INTERRUPT_CORE0_USB_INTR_MAP_REG (DR_REG_INTERRUPT_CORE0_BASE + 0x098) /* DWC-OTG */ -#define INTERRUPT_CORE0_USB_DEVICE_INT_MAP_REG (DR_REG_INTERRUPT_CORE0_BASE + 0x180) /* USB-JTAG-Serial */ - -#define ETS_USB_INUM 17 /* arbitrary level 1 level interrupt */ -#endif // ESP32S3 - -#if ESP32C6 || ESP32C5BETA3 -#define UART_USB_JTAG_SERIAL 3 - -#define DR_REG_INTERRUPT_MATRIX_BASE 0x60010000 -#define INTERRUPT_CORE0_USB_INTR_MAP_REG (DR_REG_INTERRUPT_MATRIX_BASE + 0xC0) /* USB-JTAG-Serial, INTMTX_CORE0_USB_INTR_MAP_REG */ - -#define ETS_USB_INUM 17 /* arbitrary level 1 level interrupt */ -#endif // ESP32C6 || ESP32C5BETA3 - -#ifdef ESP32H2 -#define UART_USB_JTAG_SERIAL 3 - -#define DR_REG_INTERRUPT_MATRIX_BASE 0x60010000 -#define INTERRUPT_CORE0_USB_INTR_MAP_REG (DR_REG_INTERRUPT_MATRIX_BASE + 0x94) /* USB-JTAG-Serial, INTMTX_CORE0_USB_INTR_MAP_REG */ - -#define ETS_USB_INUM 17 /* arbitrary level 1 level interrupt */ -#endif // ESP32H2 - -#if ESP32P4 -#define UART_USB_OTG 5 -#define UART_USB_JTAG_SERIAL 6 - -#define DR_REG_INTERRUPT_MATRIX_BASE 0x500D6000 -#define INTERRUPT_CORE0_USB_INTR_MAP_REG (DR_REG_INTERRUPT_MATRIX_BASE + 0x58) /* USB-JTAG-Serial, CORE0_USB_DEVICE_INT_MAP_REG */ - -#define CLIC_EXT_INTR_NUM_OFFSET 16 /* For CLIC first 16 interrupts are reserved as internal */ -#define ETS_USB_INUM 17 /* arbitrary level 1 level interrupt */ -#endif - -#ifdef WITH_USB_JTAG_SERIAL -#define USB_DEVICE_INT_ENA_REG (USB_DEVICE_BASE_REG + 0x010) -#define USB_DEVICE_INT_CLR_REG (USB_DEVICE_BASE_REG + 0x014) -#define USB_DEVICE_EP1_CONF_REG (USB_DEVICE_BASE_REG + 0x004) -#define USB_DEVICE_EP1_REG (USB_DEVICE_BASE_REG + 0x000) -#define USB_DEVICE_SERIAL_OUT_RECV_PKT_INT_CLR (1<<2) -#define USB_DEVICE_SERIAL_OUT_EP_DATA_AVAIL (1<<2) -#define USB_DEVICE_SERIAL_OUT_RECV_PKT_INT_ENA (1<<2) -#endif // WITH_USB_JTAG_SERIAL - -#define USB_GAHBCFG_REG (USB_BASE_REG + 0x8) -#define USB_GLBLLNTRMSK (1 << 0) - - -/********************************************************** - * RTC_CNTL peripheral - */ - -#ifdef ESP32S2 -#define RTC_CNTL_OPTION1_REG (RTCCNTL_BASE_REG + 0x0128) -#endif - -#ifdef ESP32S3 -#define RTC_CNTL_OPTION1_REG (RTCCNTL_BASE_REG + 0x012C) -#define RTC_CNTL_WDTCONFIG0_REG (RTCCNTL_BASE_REG + 0x0098) // RTC_CNTL_RTC_WDTCONFIG0_REG -#define RTC_CNTL_WDTWPROTECT_REG (RTCCNTL_BASE_REG + 0x00B0) // RTC_CNTL_RTC_WDTWPROTECT_REG -#define RTC_CNTL_SWD_CONF_REG (RTCCNTL_BASE_REG + 0x00B4) -#define RTC_CNTL_SWD_WPROTECT_REG (RTCCNTL_BASE_REG + 0x00B8) -#define RTC_CNTL_SWD_WKEY 0x8F1D312A -#define RTC_CNTL_SWD_AUTO_FEED_EN (1 << 31) -#endif - -#ifdef ESP32C3 -#define RTC_CNTL_WDTCONFIG0_REG (RTCCNTL_BASE_REG + 0x0090) -#define RTC_CNTL_WDTWPROTECT_REG (RTCCNTL_BASE_REG + 0x00A8) -#define RTC_CNTL_SWD_CONF_REG (RTCCNTL_BASE_REG + 0x00AC) -#define RTC_CNTL_SWD_WPROTECT_REG (RTCCNTL_BASE_REG + 0x00B0) -#define RTC_CNTL_SWD_WKEY 0x8F1D312A -#define RTC_CNTL_SWD_AUTO_FEED_EN (1 << 31) -#endif - -#if ESP32C6 || ESP32C5BETA3 || ESP32P4 -#define RTC_CNTL_WDTCONFIG0_REG (DR_REG_LP_WDT_BASE + 0x0) // LP_WDT_RWDT_CONFIG0_REG -#define RTC_CNTL_WDTWPROTECT_REG (DR_REG_LP_WDT_BASE + 0x0018) // LP_WDT_RWDT_WPROTECT_REG -#define RTC_CNTL_SWD_CONF_REG (DR_REG_LP_WDT_BASE + 0x001C) // LP_WDT_SWD_CONFIG_REG -#define RTC_CNTL_SWD_WPROTECT_REG (DR_REG_LP_WDT_BASE + 0x0020) // LP_WDT_SWD_WPROTECT_REG -#define RTC_CNTL_SWD_WKEY 0x50D83AA1 -#define RTC_CNTL_SWD_AUTO_FEED_EN (1 << 18) -#endif - -#ifdef ESP32H2 -#define RTC_CNTL_WDTCONFIG0_REG (DR_REG_LP_WDT_BASE + 0x0) // LP_WDT_RWDT_CONFIG0_REG -#define RTC_CNTL_WDTWPROTECT_REG (DR_REG_LP_WDT_BASE + 0x001C) // LP_WDT_RWDT_WPROTECT_REG -#define RTC_CNTL_SWD_CONF_REG (DR_REG_LP_WDT_BASE + 0x0020) // LP_WDT_SWD_CONFIG_REG -#define RTC_CNTL_SWD_WPROTECT_REG (DR_REG_LP_WDT_BASE + 0x0024) // LP_WDT_SWD_WPROTECT_REG -#define RTC_CNTL_SWD_WKEY 0x50D83AA1 -#define RTC_CNTL_SWD_AUTO_FEED_EN (1 << 18) -#endif - -#define RTC_CNTL_WDT_WKEY 0x50D83AA1 -#define RTC_CNTL_FORCE_DOWNLOAD_BOOT (1 << 0) - -/********************************************************** - * SYSTEM registers - */ - -#ifdef ESP32C3 -#define SYSTEM_CPU_PER_CONF_REG (SYSTEM_BASE_REG + 0x008) -#define SYSTEM_CPUPERIOD_SEL_M ((SYSTEM_CPUPERIOD_SEL_V)<<(SYSTEM_CPUPERIOD_SEL_S)) -#define SYSTEM_CPUPERIOD_SEL_V 0x3 -#define SYSTEM_CPUPERIOD_SEL_S 0 -#define SYSTEM_CPUPERIOD_MAX 1 // CPU_CLK frequency is 160 MHz - -#define SYSTEM_SYSCLK_CONF_REG (SYSTEM_BASE_REG + 0x058) -#define SYSTEM_SOC_CLK_SEL_M ((SYSTEM_SOC_CLK_SEL_V)<<(SYSTEM_SOC_CLK_SEL_S)) -#define SYSTEM_SOC_CLK_SEL_V 0x3 -#define SYSTEM_SOC_CLK_SEL_S 10 -#define SYSTEM_SOC_CLK_MAX 1 -#endif // ESP32C3 - -#ifdef ESP32S2 -#define SYSTEM_CPU_PER_CONF_REG (SYSTEM_BASE_REG + 0x018) -#define SYSTEM_CPUPERIOD_SEL_M ((SYSTEM_CPUPERIOD_SEL_V)<<(SYSTEM_CPUPERIOD_SEL_S)) -#define SYSTEM_CPUPERIOD_SEL_V 0x3 -#define SYSTEM_CPUPERIOD_SEL_S 0 -#define SYSTEM_CPUPERIOD_MAX 2 // CPU_CLK frequency is 240 MHz - -#define SYSTEM_SYSCLK_CONF_REG (SYSTEM_BASE_REG + 0x08C) -#define SYSTEM_SOC_CLK_SEL_M ((SYSTEM_SOC_CLK_SEL_V)<<(SYSTEM_SOC_CLK_SEL_S)) -#define SYSTEM_SOC_CLK_SEL_V 0x3 -#define SYSTEM_SOC_CLK_SEL_S 10 -#define SYSTEM_SOC_CLK_MAX 1 -#endif // ESP32S2 - -#ifdef ESP32C5BETA3 -#define PCR_SYSCLK_CONF_REG (DR_REG_PCR_BASE + 0x10c) -#define PCR_SOC_CLK_SEL_M ((PCR_SOC_CLK_SEL_V)<<(PCR_SOC_CLK_SEL_S)) -#define PCR_SOC_CLK_SEL_V 0x3 -#define PCR_SOC_CLK_SEL_S 16 -#define PCR_SOC_CLK_MAX 3 // CPU_CLK frequency is 240 MHz (source is PLL_F240_CLK) -#endif // ESP32C5BETA3 - -#ifdef ESP32C6 -#define PCR_SYSCLK_CONF_REG (DR_REG_PCR_BASE + 0x110) -#define PCR_SOC_CLK_SEL_M ((PCR_SOC_CLK_SEL_V)<<(PCR_SOC_CLK_SEL_S)) -#define PCR_SOC_CLK_SEL_V 0x3 -#define PCR_SOC_CLK_SEL_S 16 -#define PCR_SOC_CLK_MAX 1 // CPU_CLK frequency is 160 MHz (source is PLL_CLK) -#endif // ESP32C6 - -#ifdef ESP32H2 -#define PCR_SYSCLK_CONF_REG (DR_REG_PCR_BASE + 0x10c) -#define PCR_SOC_CLK_SEL_M ((PCR_SOC_CLK_SEL_V)<<(PCR_SOC_CLK_SEL_S)) -#define PCR_SOC_CLK_SEL_V 0x3 -#define PCR_SOC_CLK_SEL_S 16 -#define PCR_SOC_CLK_MAX 1 // CPU_CLK frequency is 160 MHz (source is PLL_CLK) -#endif // ESP32H2 - -/********************************************************** - * Per-SOC security info buffer size - */ - -#ifdef ESP32S2 -#define SECURITY_INFO_BYTES 12 /* doesn't include chip_id and api_version */ -#endif // ESP32S2 - -#if ESP32S3_OR_LATER -#define SECURITY_INFO_BYTES 20 -#endif // ESP32S3_OR_LATER - -/********************************************************** - * Per-SOC address of the rom_spiflash_legacy_funcs symbol in ROM - * Can be retrieved with gdb: "info address rom_spiflash_legacy_funcs" - */ - -#if ESP32 || ESP32S2 || ESP32S3 || ESP32S3BETA2 -#define ROM_SPIFLASH_LEGACY 0x3ffae270 -#endif // ESP32 || ESP32S2 || ESP32S3 || ESP32S3BETA2 - -#if ESP32C3 || ESP32C6BETA || ESP32C2 || ESP32C6 || ESP32C5BETA3 -#define ROM_SPIFLASH_LEGACY 0x3fcdfff4 -#endif // ESP32C3 || ESP32C6BETA || ESP32C2 || ESP32C6 - -#if ESP32H2BETA1 || ESP32H2BETA2 -#define ROM_SPIFLASH_LEGACY 0x3fcdfff0 -#endif // ESP32H2BETA1 || ESP32H2BETA2 - -#if ESP32H2 -#define ROM_SPIFLASH_LEGACY 0x4084fff0 -#endif // ESP32H2 - -#if ESP32P4 -#define ROM_SPIFLASH_LEGACY 0x4ff3ffec -#endif // ESP32P4 - -/********************************************************** - * IO-MUX peripheral - */ - -#define MCU_SEL 0x7 -#define MCU_SEL_S 12 - -#define PIN_FUNC_SELECT(PIN_NAME, FUNC) REG_SET_FIELD(PIN_NAME, MCU_SEL, FUNC) - -#if ESP32 -// PERIPHS_IO_MUX_SD_... -#define PERIPHS_IO_MUX_SPICLK_U (DR_REG_IO_MUX_BASE + 0x60) -#define PERIPHS_IO_MUX_SPID_U (DR_REG_IO_MUX_BASE + 0x68) -#define PERIPHS_IO_MUX_SPIQ_U (DR_REG_IO_MUX_BASE + 0x64) -#define PERIPHS_IO_MUX_SPICS0_U (DR_REG_IO_MUX_BASE + 0x5c) -#define FUNC_GPIO 2 -#endif // ESP32 - -#if ESP32S2 -#define PERIPHS_IO_MUX_SPICLK_U (DR_REG_IO_MUX_BASE + 0x7c) -#define PERIPHS_IO_MUX_SPIQ_U (DR_REG_IO_MUX_BASE + 0x80) -#define PERIPHS_IO_MUX_SPID_U (DR_REG_IO_MUX_BASE + 0x84) -#define PERIPHS_IO_MUX_SPICS0_U (DR_REG_IO_MUX_BASE + 0x78) -#define FUNC_GPIO 1 -#endif // ESP32S2 - -#if ESP32C3 -#define PERIPHS_IO_MUX_SPICLK_U (DR_REG_IO_MUX_BASE + 0x40) -#define PERIPHS_IO_MUX_SPIQ_U (DR_REG_IO_MUX_BASE + 0x48) -#define PERIPHS_IO_MUX_SPID_U (DR_REG_IO_MUX_BASE + 0x44) -#define PERIPHS_IO_MUX_SPICS0_U (DR_REG_IO_MUX_BASE + 0x3c) -#define FUNC_GPIO 1 -#endif // ESP32C3 - -#if ESP32S3 || ESP32S3BETA2 -#define PERIPHS_IO_MUX_SPICLK_U (DR_REG_IO_MUX_BASE + 0x7c) -#define PERIPHS_IO_MUX_SPIQ_U (DR_REG_IO_MUX_BASE + 0x80) -#define PERIPHS_IO_MUX_SPID_U (DR_REG_IO_MUX_BASE + 0x84) -#define PERIPHS_IO_MUX_SPICS0_U (DR_REG_IO_MUX_BASE + 0x78) -#define FUNC_GPIO 1 -#endif // ESP32S3 || ESP32S3BETA2 - -#if ESP32C2 -#define PERIPHS_IO_MUX_SPICLK_U (DR_REG_IO_MUX_BASE + 0x40) -#define PERIPHS_IO_MUX_SPIQ_U (DR_REG_IO_MUX_BASE + 0x48) -#define PERIPHS_IO_MUX_SPID_U (DR_REG_IO_MUX_BASE + 0x44) -#define PERIPHS_IO_MUX_SPICS0_U (DR_REG_IO_MUX_BASE + 0x3c) -#define FUNC_GPIO 1 -#endif // ESP32C2 - -#if ESP32C6 || ESP32C6BETA || ESP32C5BETA3 -#define PERIPHS_IO_MUX_SPICLK_U (DR_REG_IO_MUX_BASE + 0x78) -#define PERIPHS_IO_MUX_SPIQ_U (DR_REG_IO_MUX_BASE + 0x68) -#define PERIPHS_IO_MUX_SPID_U (DR_REG_IO_MUX_BASE + 0x7c) -#define PERIPHS_IO_MUX_SPICS0_U (DR_REG_IO_MUX_BASE + 0x64) -#define FUNC_GPIO 1 -#endif // ESP32C6 || ESP32C6BETA - -#if ESP32H2 || ESP32H2BETA1 || ESP32H2BETA2 -#define PERIPHS_IO_MUX_SPICLK_U (DR_REG_IO_MUX_BASE + 0x50) -#define PERIPHS_IO_MUX_SPIQ_U (DR_REG_IO_MUX_BASE + 0x44) -#define PERIPHS_IO_MUX_SPID_U (DR_REG_IO_MUX_BASE + 0x54) -#define PERIPHS_IO_MUX_SPICS0_U (DR_REG_IO_MUX_BASE + 0x40) -#define FUNC_GPIO 1 -#endif // ESP32H2 || ESP32H2BETA1 || ESP32H2BETA2 - -#if ESP32P4 -#define PERIPHS_IO_MUX_SPICLK_U (DR_REG_IO_MUX_BASE + 0x7c) -#define PERIPHS_IO_MUX_SPIQ_U (DR_REG_IO_MUX_BASE + 0x80) -#define PERIPHS_IO_MUX_SPID_U (DR_REG_IO_MUX_BASE + 0x84) -#define PERIPHS_IO_MUX_SPICS0_U (DR_REG_IO_MUX_BASE + 0x78) -#define FUNC_GPIO 1 -#endif // ESP32P4 diff --git a/tools/esptool_py/flasher_stub/include/stub_commands.h b/tools/esptool_py/flasher_stub/include/stub_commands.h deleted file mode 100644 index af943ecd72..0000000000 --- a/tools/esptool_py/flasher_stub/include/stub_commands.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2016-2022 Espressif Systems (Shanghai) CO LTD - * - * SPDX-License-Identifier: GPL-2.0-or-later - */ - -/* Flasher command handlers, called from stub_flasher.c - - Commands related to writing flash are in stub_write_flash_xxx. -*/ -#pragma once -#include "stub_flasher.h" -#include "rom_functions.h" -#include - -int handle_flash_erase(uint32_t addr, uint32_t len); - -void handle_flash_read(uint32_t addr, uint32_t len, uint32_t block_size, uint32_t max_in_flight); - -int handle_flash_get_md5sum(uint32_t addr, uint32_t len); - -int handle_flash_read_chip_id(); - -esp_command_error handle_spi_set_params(uint32_t *args, int *status); - -esp_command_error handle_spi_attach(uint32_t hspi_config_arg); - -esp_command_error handle_mem_begin(uint32_t size, uint32_t offset); - -esp_command_error handle_mem_data(void *data, uint32_t length); - -esp_command_error handle_mem_finish(void); - -typedef struct { - uint32_t addr; - uint32_t value; - uint32_t mask; - uint32_t delay_us; -} write_reg_args_t; - -esp_command_error handle_write_reg(const write_reg_args_t *cmd_buf, uint32_t num_commands); - -/* Get security info command only on ESP32S2 and later */ -#if ESP32S2_OR_LATER -esp_command_error handle_get_security_info(void); -#endif // ESP32S2_OR_LATER diff --git a/tools/esptool_py/flasher_stub/include/stub_flasher.h b/tools/esptool_py/flasher_stub/include/stub_flasher.h deleted file mode 100644 index 3cf1f63105..0000000000 --- a/tools/esptool_py/flasher_stub/include/stub_flasher.h +++ /dev/null @@ -1,110 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2016 Cesanta Software Limited - * - * SPDX-License-Identifier: GPL-2.0-or-later - * - * SPDX-FileContributor: 2016-2022 Espressif Systems (Shanghai) CO LTD - */ - -#pragma once -#include -#include - -/* Maximum write block size, used for various buffers. */ -#define MAX_WRITE_BLOCK 0x4000 - -/* Flash geometry constants */ -#define FLASH_SECTOR_SIZE 4096 -#define FLASH_BLOCK_SIZE 65536 -#define FLASH_PAGE_SIZE 256 -#define FLASH_STATUS_MASK 0xFFFF -#define SECTORS_PER_BLOCK (FLASH_BLOCK_SIZE / FLASH_SECTOR_SIZE) - -/* 32-bit addressing is supported only by ESP32S3 */ -#if defined(ESP32S3) && !defined(ESP32S3BETA2) -#define FLASH_MAX_SIZE 64*1024*1024 -extern bool large_flash_mode; -#else -#define FLASH_MAX_SIZE 16*1024*1024 -#endif - -/* Full set of protocol commands */ -typedef enum { - /* Commands supported by the ESP8266 & ESP32 bootloaders */ - ESP_FLASH_BEGIN = 0x02, - ESP_FLASH_DATA = 0x03, - ESP_FLASH_END = 0x04, - ESP_MEM_BEGIN = 0x05, - ESP_MEM_END = 0x06, - ESP_MEM_DATA = 0x07, - ESP_SYNC = 0x08, - ESP_WRITE_REG = 0x09, - ESP_READ_REG = 0x0a, - - /* Commands supported by the ESP32 bootloader */ - ESP_SPI_SET_PARAMS = 0x0b, - ESP_PIN_READ = 0x0c, /* ??? */ - ESP_SPI_ATTACH = 0x0d, - ESP_SPI_READ = 0x0e, - ESP_SET_BAUD = 0x0f, - ESP_FLASH_DEFLATED_BEGIN = 0x10, - ESP_FLASH_DEFLATED_DATA = 0x11, - ESP_FLASH_DEFLATED_END = 0x12, - ESP_FLASH_VERIFY_MD5 = 0x13, - - /* Commands supported by the ESP32S2 and later bootloaders */ - ESP_GET_SECURITY_INFO = 0x14, - - /* Stub-only commands */ - ESP_ERASE_FLASH = 0xD0, - ESP_ERASE_REGION = 0xD1, - ESP_READ_FLASH = 0xD2, - ESP_RUN_USER_CODE = 0xD3, - - /* Flash encryption debug mode supported command */ - ESP_FLASH_ENCRYPT_DATA = 0xD4, -} esp_command; - -/* Command request header */ -typedef struct __attribute__((packed)) { - uint8_t zero; - uint8_t op; /* maps to esp_command enum */ - uint16_t data_len; - int32_t checksum; - uint8_t data_buf[32]; /* actually variable length, determined by data_len */ -} esp_command_req_t; - -/* Command response header */ -typedef struct __attribute__((packed)) { - uint8_t resp; /* should be '1' */ - uint8_t op_ret; /* Should match 'op' */ - uint16_t len_ret; /* Length of result data (can be ignored as SLIP framing helps) */ - int32_t value; /* 32-bit response used by some commands */ -} esp_command_response_t; - - -/* command response has some (optional) data after it, then 2 (or 4 on ESP32 ROM) - bytes of status. - */ -typedef struct __attribute__((packed)) { - uint8_t error; /* non-zero = failed */ - uint8_t status; /* status of a failure */ -} esp_command_data_status_t; - -/* Error codes */ -typedef enum { - ESP_OK = 0, - - ESP_BAD_DATA_LEN = 0xC0, - ESP_BAD_DATA_CHECKSUM = 0xC1, - ESP_BAD_BLOCKSIZE = 0xC2, - ESP_INVALID_COMMAND = 0xC3, - ESP_FAILED_SPI_OP = 0xC4, - ESP_FAILED_SPI_UNLOCK = 0xC5, - ESP_NOT_IN_FLASH_MODE = 0xC6, - ESP_INFLATE_ERROR = 0xC7, - ESP_NOT_ENOUGH_DATA = 0xC8, - ESP_TOO_MUCH_DATA = 0xC9, - - ESP_CMD_NOT_IMPLEMENTED = 0xFF, -} esp_command_error; diff --git a/tools/esptool_py/flasher_stub/include/stub_io.h b/tools/esptool_py/flasher_stub/include/stub_io.h deleted file mode 100644 index 7c441c31f7..0000000000 --- a/tools/esptool_py/flasher_stub/include/stub_io.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2016 Cesanta Software Limited - * - * SPDX-License-Identifier: GPL-2.0-or-later - * - * SPDX-FileContributor: 2016-2022 Espressif Systems (Shanghai) CO LTD - */ - -#pragma once - -#include -#include - -/* Call to initialize the I/O (either UART or USB CDC at this point). - * The argument is a callback function which will handle received characters, - * when asynchronous (interrupt-driven) RX is used. - * It will be called in an interrupt context. - */ -void stub_io_init(void(*rx_cb_func)(char)); - -/* Enable or disable asynchronous (interrupt-driven) RX, for UART or USB. - * Currently needed only for the read_flash command. - */ -void stub_rx_async_enable(bool enable); - -/* Wrapper for either uart_tx_one_char or the USB CDC output function. - * (uart_tx_one_char in ROM can also handle USB CDC, but it is really - * slow because it flushes the FIFO after every byte). - */ -void stub_tx_one_char(char c); - -/* A blocking (polling) function to receive one character. - * Should only be used when async (interrupt-driven) RX is disabled. - * Currently only needed for the read_flash command. - */ -char stub_rx_one_char(void); - -/* Returns after making sure that all output has been sent to the host */ -void stub_tx_flush(void); - -/* Updates the baud rate divider based on the current baud rate (from host perspective) - * and the requested baud rate. - * No-op for USB CDC. - */ -void stub_io_set_baudrate(uint32_t current_baud, uint32_t new_baud); - -/* To be called periodically while waiting for a command. - * No-op for UART, handles DTR/RTS reset for USB CDC. - */ -void stub_io_idle_hook(void); - -/* Checks if USB-Serial/JTAG is being currently used. - */ -#if WITH_USB_JTAG_SERIAL -bool stub_uses_usb_jtag_serial(void); -#endif - -/* Checks if USB-OTG is being currently used. - */ -#if WITH_USB_OTG -bool stub_uses_usb_otg(void); -#endif diff --git a/tools/esptool_py/flasher_stub/include/stub_write_flash.h b/tools/esptool_py/flasher_stub/include/stub_write_flash.h deleted file mode 100644 index 9e1a7c25ca..0000000000 --- a/tools/esptool_py/flasher_stub/include/stub_write_flash.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2016-2022 Espressif Systems (Shanghai) CO LTD - * - * SPDX-License-Identifier: GPL-2.0-or-later - */ - -/* Flasher commands related to writing flash */ -#pragma once -#include "stub_flasher.h" -#include -#include "rom_functions.h" - -bool is_in_flash_mode(void); - -esp_command_error get_flash_error(void); - -esp_command_error handle_flash_begin(uint32_t total_size, uint32_t offset); - -esp_command_error handle_flash_deflated_begin(uint32_t uncompressed_size, uint32_t compressed_size, uint32_t offset); - -void handle_flash_data(void *data_buf, uint32_t length); - -#if !ESP8266 -void handle_flash_encrypt_data(void *data_buf, uint32_t length); -#endif - -void handle_flash_deflated_data(void *data_buf, uint32_t length); - -/* same command used for deflated or non-deflated mode */ -esp_command_error handle_flash_end(void); diff --git a/tools/esptool_py/flasher_stub/ld/rom_32.ld b/tools/esptool_py/flasher_stub/ld/rom_32.ld deleted file mode 100644 index 073eacfb13..0000000000 --- a/tools/esptool_py/flasher_stub/ld/rom_32.ld +++ /dev/null @@ -1,1782 +0,0 @@ -/* Taken from esp-idf */ -/* -ESP32 ROM address table -Generated for ROM with MD5sum: -ab8282ae908fe9e7a63fb2a4ac2df013 ../../rom_image/prorom.elf -*/ -PROVIDE ( abort = 0x4000bba4 ); -PROVIDE ( abs = 0x40056340 ); -PROVIDE ( __absvdi2 = 0x4006387c ); -PROVIDE ( __absvsi2 = 0x40063868 ); -PROVIDE ( Add2SelfBigHex256 = 0x40015b7c ); -PROVIDE ( AddBigHex256 = 0x40015b28 ); -PROVIDE ( AddBigHexModP256 = 0x40015c98 ); -PROVIDE ( __adddf3 = 0x40002590 ); -PROVIDE ( AddP256 = 0x40015c74 ); -PROVIDE ( AddPdiv2_256 = 0x40015ce0 ); -PROVIDE ( __addsf3 = 0x400020e8 ); -PROVIDE ( __addvdi3 = 0x40002cbc ); -PROVIDE ( __addvsi3 = 0x40002c98 ); -PROVIDE ( aes_128_cbc_decrypt = 0x4005cc7c ); -PROVIDE ( aes_128_cbc_encrypt = 0x4005cc18 ); -PROVIDE ( aes_unwrap = 0x4005ccf0 ); -PROVIDE ( app_gpio_arg = 0x3ffe003c ); -PROVIDE ( app_gpio_handler = 0x3ffe0040 ); -PROVIDE ( __ascii_wctomb = 0x40058ef0 ); -PROVIDE ( asctime = 0x40059588 ); -PROVIDE ( asctime_r = 0x40000ec8 ); -PROVIDE ( __ashldi3 = 0x4000c818 ); -PROVIDE ( __ashrdi3 = 0x4000c830 ); -PROVIDE ( atoi = 0x400566c4 ); -PROVIDE ( _atoi_r = 0x400566d4 ); -PROVIDE ( atol = 0x400566ec ); -PROVIDE ( _atol_r = 0x400566fc ); -PROVIDE ( base64_decode = 0x4005ced8 ); -PROVIDE ( base64_encode = 0x4005cdbc ); -PROVIDE ( BasePoint_x_256 = 0x3ff97488 ); -PROVIDE ( BasePoint_y_256 = 0x3ff97468 ); -PROVIDE ( bigHexInversion256 = 0x400168f0 ); -PROVIDE ( bigHexP256 = 0x3ff973bc ); -PROVIDE ( __bswapdi2 = 0x400649c4 ); -PROVIDE ( __bswapsi2 = 0x4006499c ); -PROVIDE ( btdm_r_ble_bt_handler_tab_p_get = 0x40019b0c ); -PROVIDE ( btdm_r_btdm_option_data_p_get = 0x40010004 ); -PROVIDE ( btdm_r_btdm_rom_version_get = 0x40010078 ); -PROVIDE ( btdm_r_data_init = 0x4001002c ); -PROVIDE ( btdm_r_import_rf_phy_func_p_get = 0x40054298 ); -PROVIDE ( btdm_r_ip_func_p_get = 0x40019af0 ); -PROVIDE ( btdm_r_ip_func_p_set = 0x40019afc ); -PROVIDE ( btdm_r_modules_func_p_get = 0x4005427c ); -PROVIDE ( btdm_r_modules_func_p_set = 0x40054270 ); -PROVIDE ( btdm_r_plf_func_p_set = 0x40054288 ); -PROVIDE ( bt_util_buf_env = 0x3ffb8bd4 ); -PROVIDE ( bzero = 0x4000c1f4 ); -PROVIDE ( cache_flash_mmu_set = 0x400095e0 ); -PROVIDE ( Cache_Flush = 0x40009a14 ); -PROVIDE ( Cache_Read_Disable = 0x40009ab8 ); -PROVIDE ( Cache_Read_Enable = 0x40009a84 ); -PROVIDE ( Cache_Read_Init = 0x40009950 ); -PROVIDE ( cache_sram_mmu_set = 0x400097f4 ); -/* This is static function, but can be used, not generated by script*/ -PROVIDE ( calc_rtc_memory_crc = 0x40008170 ); -PROVIDE ( calloc = 0x4000bee4 ); -PROVIDE ( _calloc_r = 0x4000bbf8 ); -PROVIDE ( check_pos = 0x400068b8 ); -PROVIDE ( _cleanup = 0x40001df8 ); -PROVIDE ( _cleanup_r = 0x40001d48 ); -PROVIDE ( __clear_cache = 0x40063860 ); -PROVIDE ( close = 0x40001778 ); -PROVIDE ( _close_r = 0x4000bd3c ); -PROVIDE ( __clrsbdi2 = 0x40064a38 ); -PROVIDE ( __clrsbsi2 = 0x40064a20 ); -PROVIDE ( __clzdi2 = 0x4000ca50 ); -PROVIDE ( __clzsi2 = 0x4000c7e8 ); -PROVIDE ( __cmpdi2 = 0x40063820 ); -PROVIDE ( co_default_bdaddr = 0x3ffae704 ); -PROVIDE ( co_null_bdaddr = 0x3ffb80e0 ); -PROVIDE ( co_sca2ppm = 0x3ff971e8 ); -PROVIDE ( crc16_be = 0x4005d09c ); -PROVIDE ( crc16_le = 0x4005d05c ); -PROVIDE ( crc32_be = 0x4005d024 ); -PROVIDE ( crc32_le = 0x4005cfec ); -PROVIDE ( crc8_be = 0x4005d114 ); -PROVIDE ( crc8_le = 0x4005d0e0 ); -PROVIDE ( creat = 0x40000e8c ); -PROVIDE ( ctime = 0x400595b0 ); -PROVIDE ( ctime_r = 0x400595c4 ); -PROVIDE ( _ctype_ = 0x3ff96354 ); -PROVIDE ( __ctype_ptr__ = 0x3ff96350 ); -PROVIDE ( __ctzdi2 = 0x4000ca64 ); -PROVIDE ( __ctzsi2 = 0x4000c7f0 ); -PROVIDE ( _data_end = 0x4000d5c8 ); -PROVIDE ( _data_end_btdm_rom = 0x4000d4f8 ); -PROVIDE ( _data_start = 0x4000d4f8 ); -PROVIDE ( _data_start_btdm_rom = 0x4000d4f4 ); -PROVIDE ( _data_start_btdm = 0x3ffae6e0); -PROVIDE ( _data_end_btdm = 0x3ffaff10); -PROVIDE ( _bss_start_btdm = 0x3ffb8000); -PROVIDE ( _bss_end_btdm = 0x3ffbff70); -PROVIDE ( _daylight = 0x3ffae0a4 ); -PROVIDE ( dbg_default_handler = 0x3ff97218 ); -PROVIDE ( dbg_state = 0x3ffb8d5d ); -PROVIDE ( DebugE256PublicKey_x = 0x3ff97428 ); -PROVIDE ( DebugE256PublicKey_y = 0x3ff97408 ); -PROVIDE ( DebugE256SecretKey = 0x3ff973e8 ); -PROVIDE ( _DebugExceptionVector = 0x40000280 ); -PROVIDE ( debug_timer = 0x3ffe042c ); -PROVIDE ( debug_timerfn = 0x3ffe0430 ); -PROVIDE ( dh_group14_generator = 0x3ff9ac60 ); -PROVIDE ( dh_group14_prime = 0x3ff9ab60 ); -PROVIDE ( dh_group15_generator = 0x3ff9ab5f ); -PROVIDE ( dh_group15_prime = 0x3ff9a9df ); -PROVIDE ( dh_group16_generator = 0x3ff9a9de ); -PROVIDE ( dh_group16_prime = 0x3ff9a7de ); -PROVIDE ( dh_group17_generator = 0x3ff9a7dd ); -PROVIDE ( dh_group17_prime = 0x3ff9a4dd ); -PROVIDE ( dh_group18_generator = 0x3ff9a4dc ); -PROVIDE ( dh_group18_prime = 0x3ff9a0dc ); -PROVIDE ( dh_group1_generator = 0x3ff9ae03 ); -PROVIDE ( dh_group1_prime = 0x3ff9ada3 ); -PROVIDE ( dh_group2_generator = 0x3ff9ada2 ); -PROVIDE ( dh_group2_prime = 0x3ff9ad22 ); -PROVIDE ( dh_group5_generator = 0x3ff9ad21 ); -PROVIDE ( dh_group5_prime = 0x3ff9ac61 ); -PROVIDE ( div = 0x40056348 ); -PROVIDE ( __divdc3 = 0x40064460 ); -PROVIDE ( __divdf3 = 0x40002954 ); -PROVIDE ( __divdi3 = 0x4000ca84 ); -PROVIDE ( __divsc3 = 0x40064200 ); -PROVIDE ( __divsf3 = 0x4000234c ); -PROVIDE ( __divsi3 = 0x4000c7b8 ); -PROVIDE ( _DoubleExceptionVector = 0x400003c0 ); -PROVIDE ( dummy_len_plus = 0x3ffae290 ); -PROVIDE ( __dummy_lock = 0x4000c728 ); -PROVIDE ( __dummy_lock_try = 0x4000c730 ); -PROVIDE ( ecc_env = 0x3ffb8d60 ); -PROVIDE ( ecc_Jacobian_InfinityPoint256 = 0x3ff972e8 ); -PROVIDE ( em_buf_env = 0x3ffb8d74 ); -PROVIDE ( environ = 0x3ffae0b4 ); -PROVIDE ( __env_lock = 0x40001fd4 ); -PROVIDE ( __env_unlock = 0x40001fe0 ); -PROVIDE ( __eqdf2 = 0x400636a8 ); -PROVIDE ( __eqsf2 = 0x40063374 ); -PROVIDE ( esp_crc8 = 0x4005d144 ); -PROVIDE ( _etext = 0x4000d66c ); -PROVIDE ( ets_aes_crypt = 0x4005c9b8 ); -PROVIDE ( ets_aes_disable = 0x4005c8f8 ); -PROVIDE ( ets_aes_enable = 0x4005c8cc ); -PROVIDE ( ets_aes_set_endian = 0x4005c928 ); -PROVIDE ( ets_aes_setkey_dec = 0x4005c994 ); -PROVIDE ( ets_aes_setkey_enc = 0x4005c97c ); -PROVIDE ( ets_bigint_disable = 0x4005c4e0 ); -PROVIDE ( ets_bigint_enable = 0x4005c498 ); -PROVIDE ( ets_bigint_mod_mult_getz = 0x4005c818 ); -PROVIDE ( ets_bigint_mod_mult_prepare = 0x4005c7b4 ); -PROVIDE ( ets_bigint_mod_power_getz = 0x4005c614 ); -PROVIDE ( ets_bigint_mod_power_prepare = 0x4005c54c ); -PROVIDE ( ets_bigint_montgomery_mult_getz = 0x4005c7a4 ); -PROVIDE ( ets_bigint_montgomery_mult_prepare = 0x4005c6fc ); -PROVIDE ( ets_bigint_mult_getz = 0x4005c6e8 ); -PROVIDE ( ets_bigint_mult_prepare = 0x4005c630 ); -PROVIDE ( ets_bigint_wait_finish = 0x4005c520 ); -PROVIDE ( ets_delay_us = 0x40008534 ); -PROVIDE ( ets_efuse_get_8M_clock = 0x40008710 ); -PROVIDE ( ets_efuse_get_spiconfig = 0x40008658 ); -PROVIDE ( ets_efuse_program_op = 0x40008628 ); -PROVIDE ( ets_efuse_read_op = 0x40008600 ); -PROVIDE ( ets_get_cpu_frequency = 0x4000855c ); -PROVIDE ( ets_get_detected_xtal_freq = 0x40008588 ); -PROVIDE ( ets_get_xtal_scale = 0x4000856c ); -PROVIDE ( ets_install_putc1 = 0x40007d18 ); -PROVIDE ( ets_install_putc2 = 0x40007d38 ); -PROVIDE ( ets_install_uart_printf = 0x40007d28 ); -PROVIDE ( ets_post = 0x4000673c ); -PROVIDE ( ets_printf = 0x40007d54 ); -PROVIDE ( ets_readySet_ = 0x3ffe01f0 ); -PROVIDE ( ets_run = 0x400066bc ); -PROVIDE ( ets_secure_boot_check = 0x4005cb40 ); -PROVIDE ( ets_secure_boot_check_finish = 0x4005cc04 ); -PROVIDE ( ets_secure_boot_check_start = 0x4005cbcc ); -PROVIDE ( ets_secure_boot_finish = 0x4005ca84 ); -PROVIDE ( ets_secure_boot_hash = 0x4005cad4 ); -PROVIDE ( ets_secure_boot_obtain = 0x4005cb14 ); -PROVIDE ( ets_secure_boot_rd_abstract = 0x4005cba8 ); -PROVIDE ( ets_secure_boot_rd_iv = 0x4005cb84 ); -PROVIDE ( ets_secure_boot_start = 0x4005ca34 ); -PROVIDE ( ets_set_appcpu_boot_addr = 0x4000689c ); -PROVIDE ( ets_set_idle_cb = 0x40006674 ); -PROVIDE ( ets_set_startup_callback = 0x4000688c ); -PROVIDE ( ets_set_user_start = 0x4000687c ); -PROVIDE ( ets_sha_disable = 0x4005c0a8 ); -PROVIDE ( ets_sha_enable = 0x4005c07c ); -PROVIDE ( ets_sha_finish = 0x4005c104 ); -PROVIDE ( ets_sha_init = 0x4005c0d4 ); -PROVIDE ( ets_sha_update = 0x4005c2a0 ); -PROVIDE ( ets_startup_callback = 0x3ffe0404 ); -PROVIDE ( ets_task = 0x40006688 ); -PROVIDE ( ets_timer_arm = 0x40008368 ); -PROVIDE ( ets_timer_arm_us = 0x400083ac ); -PROVIDE ( ets_timer_disarm = 0x400083ec ); -PROVIDE ( ets_timer_done = 0x40008428 ); -PROVIDE ( ets_timer_handler_isr = 0x40008454 ); -PROVIDE ( ets_timer_init = 0x400084e8 ); -PROVIDE ( ets_timer_setfn = 0x40008350 ); -PROVIDE ( ets_unpack_flash_code = 0x40007018 ); -PROVIDE ( ets_unpack_flash_code_legacy = 0x4000694c ); -PROVIDE ( ets_update_cpu_frequency = 0x40008550 ); -PROVIDE ( ets_waiti0 = 0x400067d8 ); -PROVIDE ( exc_cause_table = 0x3ff991d0 ); -PROVIDE ( _exit_r = 0x4000bd28 ); -PROVIDE ( __extendsfdf2 = 0x40002c34 ); -PROVIDE ( fclose = 0x400020ac ); -PROVIDE ( _fclose_r = 0x40001fec ); -PROVIDE ( fflush = 0x40059394 ); -PROVIDE ( _fflush_r = 0x40059320 ); -PROVIDE ( __ffsdi2 = 0x4000ca2c ); -PROVIDE ( __ffssi2 = 0x4000c804 ); -PROVIDE ( FilePacketSendDeflatedReqMsgProc = 0x40008b24 ); -PROVIDE ( FilePacketSendReqMsgProc = 0x40008860 ); -PROVIDE ( _findenv_r = 0x40001f44 ); -PROVIDE ( __fixdfdi = 0x40002ac4 ); -PROVIDE ( __fixdfsi = 0x40002a78 ); -PROVIDE ( __fixsfdi = 0x4000244c ); -PROVIDE ( __fixsfsi = 0x4000240c ); -PROVIDE ( __fixunsdfsi = 0x40002b30 ); -PROVIDE ( __fixunssfdi = 0x40002504 ); -PROVIDE ( __fixunssfsi = 0x400024ac ); -PROVIDE ( FlashDwnLdDeflatedStartMsgProc = 0x40008ad8 ); -PROVIDE ( FlashDwnLdParamCfgMsgProc = 0x4000891c ); -PROVIDE ( FlashDwnLdStartMsgProc = 0x40008820 ); -PROVIDE ( FlashDwnLdStopDeflatedReqMsgProc = 0x40008c18 ); -PROVIDE ( FlashDwnLdStopReqMsgProc = 0x400088ec ); -PROVIDE ( __floatdidf = 0x4000c988 ); -PROVIDE ( __floatdisf = 0x4000c8c0 ); -PROVIDE ( __floatsidf = 0x4000c944 ); -PROVIDE ( __floatsisf = 0x4000c870 ); -PROVIDE ( __floatundidf = 0x4000c978 ); -PROVIDE ( __floatundisf = 0x4000c8b0 ); -PROVIDE ( __floatunsidf = 0x4000c938 ); -PROVIDE ( __floatunsisf = 0x4000c864 ); -PROVIDE ( __fp_lock_all = 0x40001f1c ); -PROVIDE ( __fp_unlock_all = 0x40001f30 ); -PROVIDE ( fputwc = 0x40058ea8 ); -PROVIDE ( __fputwc = 0x40058da0 ); -PROVIDE ( _fputwc_r = 0x40058e4c ); -PROVIDE ( free = 0x4000beb8 ); -PROVIDE ( _free_r = 0x4000bbcc ); -PROVIDE ( _fstat_r = 0x4000bccc ); -PROVIDE ( _fwalk = 0x4000c738 ); -PROVIDE ( _fwalk_reent = 0x4000c770 ); -PROVIDE ( __gcc_bcmp = 0x40064a70 ); -PROVIDE ( __gedf2 = 0x40063768 ); -PROVIDE ( _GeneralException = 0x40000e14 ); -PROVIDE ( __gesf2 = 0x4006340c ); -PROVIDE ( __get_current_time_locale = 0x40001834 ); -PROVIDE ( _getenv_r = 0x40001fbc ); -PROVIDE ( _getpid_r = 0x4000bcfc ); -PROVIDE ( __getreent = 0x4000be8c ); -PROVIDE ( _gettimeofday_r = 0x4000bc58 ); -PROVIDE ( __gettzinfo = 0x40001fcc ); -PROVIDE ( GetUartDevice = 0x40009598 ); -PROVIDE ( GF_Jacobian_Point_Addition256 = 0x400163a4 ); -PROVIDE ( GF_Jacobian_Point_Double256 = 0x40016260 ); -PROVIDE ( GF_Point_Jacobian_To_Affine256 = 0x40016b0c ); -PROVIDE ( _global_impure_ptr = 0x3ffae0b0 ); -PROVIDE ( gmtime = 0x40059848 ); -PROVIDE ( gmtime_r = 0x40059868 ); -PROVIDE ( g_phyFuns_instance = 0x3ffae0c4 ); -PROVIDE ( g_rom_flashchip = 0x3ffae270 ); -PROVIDE ( gpio_init = 0x40009c20 ); -PROVIDE ( gpio_input_get = 0x40009b88 ); -PROVIDE ( gpio_input_get_high = 0x40009b9c ); -PROVIDE ( gpio_intr_ack = 0x40009dd4 ); -PROVIDE ( gpio_intr_ack_high = 0x40009e1c ); -PROVIDE ( gpio_intr_handler_register = 0x40009e6c ); -PROVIDE ( gpio_intr_pending = 0x40009cec ); -PROVIDE ( gpio_intr_pending_high = 0x40009cf8 ); -PROVIDE ( gpio_matrix_in = 0x40009edc ); -PROVIDE ( gpio_matrix_out = 0x40009f0c ); -PROVIDE ( gpio_output_set = 0x40009b24 ); -PROVIDE ( gpio_output_set_high = 0x40009b5c ); -PROVIDE ( gpio_pad_hold = 0x4000a734 ); -PROVIDE ( gpio_pad_pulldown = 0x4000a348 ); -PROVIDE ( gpio_pad_pullup = 0x4000a22c ); -PROVIDE ( gpio_pad_select_gpio = 0x40009fdc ); -PROVIDE ( gpio_pad_set_drv = 0x4000a11c ); -PROVIDE ( gpio_pad_unhold = 0x4000a484 ); -PROVIDE ( gpio_pending_mask = 0x3ffe0038 ); -PROVIDE ( gpio_pending_mask_high = 0x3ffe0044 ); -PROVIDE ( gpio_pin_intr_state_set = 0x40009d04 ); -PROVIDE ( gpio_pin_wakeup_disable = 0x40009eb0 ); -PROVIDE ( gpio_pin_wakeup_enable = 0x40009e7c ); -PROVIDE ( gpio_register_get = 0x40009cbc ); -PROVIDE ( gpio_register_set = 0x40009bbc ); -PROVIDE ( __gtdf2 = 0x400636dc ); -PROVIDE ( __gtsf2 = 0x400633a0 ); -PROVIDE ( gTxMsg = 0x3ffe0050 ); -PROVIDE ( hci_cmd_desc_root_tab = 0x3ff976d4 ); -PROVIDE ( hci_cmd_desc_tab_ctrl_bb = 0x3ff97b70 ); -PROVIDE ( hci_cmd_desc_tab_info_par = 0x3ff97b1c ); -PROVIDE ( hci_cmd_desc_tab_le = 0x3ff97870 ); -PROVIDE ( hci_cmd_desc_tab_lk_ctrl = 0x3ff97fc0 ); -PROVIDE ( hci_cmd_desc_tab_lk_pol = 0x3ff97f3c ); -PROVIDE ( hci_cmd_desc_tab_stat_par = 0x3ff97ac8 ); -PROVIDE ( hci_cmd_desc_tab_testing = 0x3ff97a98 ); -PROVIDE ( hci_cmd_desc_tab_vs = 0x3ff97714 ); -PROVIDE ( hci_command_handler = 0x4004c928 ); -PROVIDE ( hci_env = 0x3ffb9350 ); -PROVIDE ( hci_evt_dbg_desc_tab = 0x3ff9750c ); -PROVIDE ( hci_evt_desc_tab = 0x3ff9751c ); -PROVIDE ( hci_evt_le_desc_tab = 0x3ff974b4 ); -PROVIDE ( hci_fc_env = 0x3ffb9340 ); -PROVIDE ( hmac_md5 = 0x4005d264 ); -PROVIDE ( hmac_md5_vector = 0x4005d17c ); -PROVIDE ( hmac_sha1 = 0x40060acc ); -PROVIDE ( hmac_sha1_vector = 0x400609e4 ); -PROVIDE ( hmac_sha256 = 0x40060d58 ); -PROVIDE ( hmac_sha256_vector = 0x40060c84 ); -PROVIDE ( intr_matrix_set = 0x4000681c ); -PROVIDE ( isalnum = 0x40000f04 ); -PROVIDE ( isalpha = 0x40000f18 ); -PROVIDE ( isascii = 0x4000c20c ); -PROVIDE ( _isatty_r = 0x40000ea0 ); -PROVIDE ( isblank = 0x40000f2c ); -PROVIDE ( iscntrl = 0x40000f50 ); -PROVIDE ( isdigit = 0x40000f64 ); -PROVIDE ( isgraph = 0x40000f94 ); -PROVIDE ( islower = 0x40000f78 ); -PROVIDE ( isprint = 0x40000fa8 ); -PROVIDE ( ispunct = 0x40000fc0 ); -PROVIDE ( isspace = 0x40000fd4 ); -PROVIDE ( isupper = 0x40000fe8 ); -PROVIDE ( itoa = 0x400566b4 ); -PROVIDE ( __itoa = 0x40056678 ); -PROVIDE ( jd_decomp = 0x400613e8 ); -PROVIDE ( jd_prepare = 0x40060fa8 ); -PROVIDE ( ke_env = 0x3ffb93cc ); -PROVIDE ( _KernelExceptionVector = 0x40000300 ); -PROVIDE ( _kill_r = 0x4000bd10 ); -PROVIDE ( labs = 0x40056370 ); -PROVIDE ( lb_default_handler = 0x3ff982b8 ); -PROVIDE ( lb_default_state_tab_p_get = 0x4001c198 ); -PROVIDE ( lb_env = 0x3ffb9424 ); -PROVIDE ( lb_hci_cmd_handler_tab_p_get = 0x4001c18c ); -PROVIDE ( lb_state = 0x3ffb94e8 ); -PROVIDE ( lc_default_handler = 0x3ff98648 ); -PROVIDE ( lc_default_state_tab_p_get = 0x4002f494 ); -PROVIDE ( lc_env = 0x3ffb94ec ); -PROVIDE ( lc_hci_cmd_handler_tab_p_get = 0x4002f488 ); -PROVIDE ( lc_state = 0x3ffb9508 ); -PROVIDE ( ld_acl_br_sizes = 0x3ff98a2a ); -PROVIDE ( ld_acl_br_types = 0x3ff98a36 ); -PROVIDE ( ld_acl_edr_sizes = 0x3ff98a14 ); -PROVIDE ( ld_acl_edr_types = 0x3ff98a22 ); -PROVIDE ( ld_env = 0x3ffb9510 ); -PROVIDE ( ldiv = 0x40056378 ); -PROVIDE ( ld_pcm_settings_dft = 0x3ff98a0c ); -PROVIDE ( ld_sched_params = 0x3ffb96c0 ); -PROVIDE ( ld_sync_train_channels = 0x3ff98a3c ); -PROVIDE ( __ledf2 = 0x40063704 ); -PROVIDE ( __lesf2 = 0x400633c0 ); -PROVIDE ( _Level2FromVector = 0x40000954 ); -PROVIDE ( _Level2Vector = 0x40000180 ); -PROVIDE ( _Level3FromVector = 0x40000a28 ); -PROVIDE ( _Level3Vector = 0x400001c0 ); -PROVIDE ( _Level4FromVector = 0x40000af8 ); -PROVIDE ( _Level4Vector = 0x40000200 ); -PROVIDE ( _Level5FromVector = 0x40000c68 ); -PROVIDE ( _Level5Vector = 0x40000240 ); -PROVIDE ( _LevelOneInterrupt = 0x40000835 ); -PROVIDE ( _link_r = 0x4000bc9c ); -PROVIDE ( llc_default_handler = 0x3ff98b3c ); -PROVIDE ( llc_default_state_tab_p_get = 0x40046058 ); -PROVIDE ( llc_env = 0x3ffb96d0 ); -PROVIDE ( llc_hci_acl_data_tx_handler = 0x40042398 ); -PROVIDE ( llc_hci_cmd_handler_tab_p_get = 0x40042358 ); -PROVIDE ( llc_hci_command_handler = 0x40042360 ); -PROVIDE ( llcp_pdu_handler_tab_p_get = 0x40043f64 ); -PROVIDE ( llc_state = 0x3ffb96f8 ); -PROVIDE ( lldesc_build_chain = 0x4000a850 ); -PROVIDE ( lldesc_num2link = 0x4000a948 ); -PROVIDE ( lldesc_set_owner = 0x4000a974 ); -PROVIDE ( lld_evt_env = 0x3ffb9704 ); -PROVIDE ( lld_pdu_adv_pk_desc_tab = 0x3ff98c70 ); -PROVIDE ( lld_pdu_llcp_pk_desc_tab = 0x3ff98b68 ); -PROVIDE ( LLM_AA_CT1 = 0x3ff98d8a ); -PROVIDE ( LLM_AA_CT2 = 0x3ff98d88 ); -PROVIDE ( llm_default_handler = 0x3ff98d80 ); -PROVIDE ( llm_default_state_tab_p_get = 0x4004e718 ); -PROVIDE ( llm_hci_cmd_handler_tab_p_get = 0x4004c920 ); -PROVIDE ( llm_le_env = 0x3ffb976c ); -PROVIDE ( llm_local_cmds = 0x3ff98d38 ); -PROVIDE ( llm_local_data_len_values = 0x3ff98d1c ); -PROVIDE ( llm_local_le_feats = 0x3ff98d30 ); -PROVIDE ( llm_local_le_states = 0x3ff98d28 ); -PROVIDE ( llm_state = 0x3ffb985c ); -PROVIDE ( lm_default_handler = 0x3ff990e0 ); -PROVIDE ( lm_default_state_tab_p_get = 0x40054268 ); -PROVIDE ( lm_env = 0x3ffb9860 ); -PROVIDE ( lm_hci_cmd_handler_tab_p_get = 0x4005425c ); -PROVIDE ( lm_local_supp_feats = 0x3ff990ee ); -PROVIDE ( lm_n_page_tab = 0x3ff990e8 ); -PROVIDE ( lmp_desc_tab = 0x3ff96e6c ); -PROVIDE ( lmp_ext_desc_tab = 0x3ff96d9c ); -PROVIDE ( lm_state = 0x3ffb9a1c ); -PROVIDE ( __locale_charset = 0x40059540 ); -PROVIDE ( __locale_cjk_lang = 0x40059558 ); -PROVIDE ( localeconv = 0x4005957c ); -PROVIDE ( _localeconv_r = 0x40059560 ); -PROVIDE ( __locale_mb_cur_max = 0x40059548 ); -PROVIDE ( __locale_msgcharset = 0x40059550 ); -PROVIDE ( localtime = 0x400595dc ); -PROVIDE ( localtime_r = 0x400595fc ); -PROVIDE ( _lock_acquire = 0x4000be14 ); -PROVIDE ( _lock_acquire_recursive = 0x4000be28 ); -PROVIDE ( _lock_close = 0x4000bdec ); -PROVIDE ( _lock_close_recursive = 0x4000be00 ); -PROVIDE ( _lock_init = 0x4000bdc4 ); -PROVIDE ( _lock_init_recursive = 0x4000bdd8 ); -PROVIDE ( _lock_release = 0x4000be64 ); -PROVIDE ( _lock_release_recursive = 0x4000be78 ); -PROVIDE ( _lock_try_acquire = 0x4000be3c ); -PROVIDE ( _lock_try_acquire_recursive = 0x4000be50 ); -PROVIDE ( longjmp = 0x400562cc ); -PROVIDE ( _lseek_r = 0x4000bd8c ); -PROVIDE ( __lshrdi3 = 0x4000c84c ); -PROVIDE ( __ltdf2 = 0x40063790 ); -PROVIDE ( __ltsf2 = 0x4006342c ); -PROVIDE ( malloc = 0x4000bea0 ); -PROVIDE ( _malloc_r = 0x4000bbb4 ); -PROVIDE ( maxSecretKey_256 = 0x3ff97448 ); -PROVIDE ( __mb_cur_max = 0x3ff96530 ); -PROVIDE ( MD5Final = 0x4005db1c ); -PROVIDE ( MD5Init = 0x4005da7c ); -PROVIDE ( MD5Update = 0x4005da9c ); -PROVIDE ( md5_vector = 0x4005db80 ); -PROVIDE ( memccpy = 0x4000c220 ); -PROVIDE ( memchr = 0x4000c244 ); -PROVIDE ( memcmp = 0x4000c260 ); -PROVIDE ( memcpy = 0x4000c2c8 ); -PROVIDE ( MemDwnLdStartMsgProc = 0x40008948 ); -PROVIDE ( MemDwnLdStopReqMsgProc = 0x400089dc ); -PROVIDE ( memmove = 0x4000c3c0 ); -PROVIDE ( MemPacketSendReqMsgProc = 0x40008978 ); -PROVIDE ( memrchr = 0x4000c400 ); -PROVIDE ( memset = 0x4000c44c ); -PROVIDE ( mktime = 0x4005a5e8 ); -PROVIDE ( mmu_init = 0x400095a4 ); -PROVIDE ( __moddi3 = 0x4000cd4c ); -PROVIDE ( __modsi3 = 0x4000c7c0 ); -PROVIDE ( __month_lengths = 0x3ff9609c ); -PROVIDE ( __muldc3 = 0x40063bf4 ); -PROVIDE ( __muldf3 = 0x4006358c ); -PROVIDE ( __muldi3 = 0x4000c9fc ); -PROVIDE ( __mulsc3 = 0x40063934 ); -PROVIDE ( __mulsf3 = 0x400632c8 ); -PROVIDE ( __mulsi3 = 0x4000c7b0 ); -PROVIDE ( MultiplyBigHexByUint32_256 = 0x40016214 ); -PROVIDE ( MultiplyBigHexModP256 = 0x400160b8 ); -PROVIDE ( MultiplyByU32ModP256 = 0x40015fdc ); -PROVIDE ( multofup = 0x4000ab8c ); -PROVIDE ( __mulvdi3 = 0x40002d78 ); -PROVIDE ( __mulvsi3 = 0x40002d60 ); -PROVIDE ( mz_adler32 = 0x4005edbc ); -PROVIDE ( mz_crc32 = 0x4005ee88 ); -PROVIDE ( mz_free = 0x4005eed4 ); -PROVIDE ( __nedf2 = 0x400636a8 ); -PROVIDE ( __negdf2 = 0x400634a0 ); -PROVIDE ( __negdi2 = 0x4000ca14 ); -PROVIDE ( __negsf2 = 0x400020c0 ); -PROVIDE ( __negvdi2 = 0x40002e98 ); -PROVIDE ( __negvsi2 = 0x40002e78 ); -PROVIDE ( __nesf2 = 0x40063374 ); -PROVIDE ( _NMIExceptionVector = 0x400002c0 ); -PROVIDE ( notEqual256 = 0x40015b04 ); -PROVIDE ( __nsau_data = 0x3ff96544 ); -PROVIDE ( one_bits = 0x3ff971f8 ); -PROVIDE ( open = 0x4000178c ); -PROVIDE ( _open_r = 0x4000bd54 ); -PROVIDE ( __paritysi2 = 0x40002f3c ); -PROVIDE ( pbkdf2_sha1 = 0x40060ba4 ); -PROVIDE ( phy_get_romfuncs = 0x40004100 ); -PROVIDE ( __popcountdi2 = 0x40002ef8 ); -PROVIDE ( __popcountsi2 = 0x40002ed0 ); -PROVIDE ( __popcount_tab = 0x3ff96544 ); -PROVIDE ( __powidf2 = 0x400638d4 ); -PROVIDE ( __powisf2 = 0x4006389c ); -PROVIDE ( _Pri_4_HandlerAddress = 0x3ffe0648 ); -PROVIDE ( _Pri_5_HandlerAddress = 0x3ffe064c ); -PROVIDE ( qsort = 0x40056424 ); -PROVIDE ( _raise_r = 0x4000bc70 ); -PROVIDE ( rand = 0x40001058 ); -PROVIDE ( rand_r = 0x400010d4 ); -PROVIDE ( r_btdm_option_data = 0x3ffae6e0 ); -PROVIDE ( r_bt_util_buf_acl_rx_alloc = 0x40010218 ); -PROVIDE ( r_bt_util_buf_acl_rx_free = 0x40010234 ); -PROVIDE ( r_bt_util_buf_acl_tx_alloc = 0x40010268 ); -PROVIDE ( r_bt_util_buf_acl_tx_free = 0x40010280 ); -PROVIDE ( r_bt_util_buf_init = 0x400100e4 ); -PROVIDE ( r_bt_util_buf_lmp_tx_alloc = 0x400101d0 ); -PROVIDE ( r_bt_util_buf_lmp_tx_free = 0x400101ec ); -PROVIDE ( r_bt_util_buf_sync_clear = 0x400103c8 ); -PROVIDE ( r_bt_util_buf_sync_init = 0x400102c4 ); -PROVIDE ( r_bt_util_buf_sync_rx_alloc = 0x40010468 ); -PROVIDE ( r_bt_util_buf_sync_rx_free = 0x4001049c ); -PROVIDE ( r_bt_util_buf_sync_tx_alloc = 0x400103ec ); -PROVIDE ( r_bt_util_buf_sync_tx_free = 0x40010428 ); -PROVIDE ( rc4_skip = 0x40060928 ); -PROVIDE ( r_co_bdaddr_compare = 0x40014324 ); -PROVIDE ( r_co_bytes_to_string = 0x400142e4 ); -PROVIDE ( r_co_list_check_size_available = 0x400142c4 ); -PROVIDE ( r_co_list_extract = 0x4001404c ); -PROVIDE ( r_co_list_extract_after = 0x40014118 ); -PROVIDE ( r_co_list_find = 0x4001419c ); -PROVIDE ( r_co_list_init = 0x40013f14 ); -PROVIDE ( r_co_list_insert_after = 0x40014254 ); -PROVIDE ( r_co_list_insert_before = 0x40014200 ); -PROVIDE ( r_co_list_merge = 0x400141bc ); -PROVIDE ( r_co_list_pool_init = 0x40013f30 ); -PROVIDE ( r_co_list_pop_front = 0x40014028 ); -PROVIDE ( r_co_list_push_back = 0x40013fb8 ); -PROVIDE ( r_co_list_push_front = 0x40013ff4 ); -PROVIDE ( r_co_list_size = 0x400142ac ); -PROVIDE ( r_co_nb_good_channels = 0x40014360 ); -PROVIDE ( r_co_slot_to_duration = 0x40014348 ); -PROVIDE ( RcvMsg = 0x4000954c ); -PROVIDE ( r_dbg_init = 0x40014394 ); -PROVIDE ( r_dbg_platform_reset_complete = 0x400143d0 ); -PROVIDE ( r_dbg_swdiag_init = 0x40014470 ); -PROVIDE ( r_dbg_swdiag_read = 0x400144a4 ); -PROVIDE ( r_dbg_swdiag_write = 0x400144d0 ); -PROVIDE ( r_E1 = 0x400108e8 ); -PROVIDE ( r_E21 = 0x40010968 ); -PROVIDE ( r_E22 = 0x400109b4 ); -PROVIDE ( r_E3 = 0x40010a58 ); -PROVIDE ( r_ea_alarm_clear = 0x40015ab4 ); -PROVIDE ( r_ea_alarm_set = 0x40015a10 ); -PROVIDE ( read = 0x400017dc ); -PROVIDE ( _read_r = 0x4000bda8 ); -PROVIDE ( r_ea_elt_cancel = 0x400150d0 ); -PROVIDE ( r_ea_elt_create = 0x40015264 ); -PROVIDE ( r_ea_elt_insert = 0x400152a8 ); -PROVIDE ( r_ea_elt_remove = 0x400154f0 ); -PROVIDE ( r_ea_finetimer_isr = 0x400155d4 ); -PROVIDE ( r_ea_init = 0x40015228 ); -PROVIDE ( r_ea_interval_create = 0x4001555c ); -PROVIDE ( r_ea_interval_delete = 0x400155a8 ); -PROVIDE ( r_ea_interval_duration_req = 0x4001597c ); -PROVIDE ( r_ea_interval_insert = 0x4001557c ); -PROVIDE ( r_ea_interval_remove = 0x40015590 ); -PROVIDE ( realloc = 0x4000becc ); -PROVIDE ( _realloc_r = 0x4000bbe0 ); -PROVIDE ( r_ea_offset_req = 0x40015748 ); -PROVIDE ( r_ea_sleep_check = 0x40015928 ); -PROVIDE ( r_ea_sw_isr = 0x40015724 ); -PROVIDE ( r_ea_time_get_halfslot_rounded = 0x40015894 ); -PROVIDE ( r_ea_time_get_slot_rounded = 0x400158d4 ); -PROVIDE ( r_ecc_abort_key256_generation = 0x40017070 ); -PROVIDE ( r_ecc_generate_key256 = 0x40016e00 ); -PROVIDE ( r_ecc_gen_new_public_key = 0x400170c0 ); -PROVIDE ( r_ecc_gen_new_secret_key = 0x400170e4 ); -PROVIDE ( r_ecc_get_debug_Keys = 0x40017224 ); -PROVIDE ( r_ecc_init = 0x40016dbc ); -PROVIDE ( RecvBuff = 0x3ffe009c ); -PROVIDE ( recv_packet = 0x40009424 ); -PROVIDE ( r_em_buf_init = 0x4001729c ); -PROVIDE ( r_em_buf_rx_buff_addr_get = 0x400173e8 ); -PROVIDE ( r_em_buf_rx_free = 0x400173c4 ); -PROVIDE ( r_em_buf_tx_buff_addr_get = 0x40017404 ); -PROVIDE ( r_em_buf_tx_free = 0x4001741c ); -PROVIDE ( _rename_r = 0x4000bc28 ); -PROVIDE ( _ResetHandler = 0x40000450 ); -PROVIDE ( _ResetVector = 0x40000400 ); -PROVIDE ( r_F1_256 = 0x400133e4 ); -PROVIDE ( r_F2_256 = 0x40013568 ); -PROVIDE ( r_F3_256 = 0x40013664 ); -PROVIDE ( RFPLL_ICP_TABLE = 0x3ffb8b7c ); -PROVIDE ( r_G_256 = 0x40013470 ); -PROVIDE ( r_H3 = 0x40013760 ); -PROVIDE ( r_H4 = 0x40013830 ); -PROVIDE ( r_h4tl_init = 0x40017878 ); -PROVIDE ( r_h4tl_start = 0x40017924 ); -PROVIDE ( r_h4tl_stop = 0x40017934 ); -PROVIDE ( r_h4tl_write = 0x400178d0 ); -PROVIDE ( r_H5 = 0x400138dc ); -PROVIDE ( r_hashConcat = 0x40013a38 ); -PROVIDE ( r_hci_acl_tx_data_alloc = 0x4001951c ); -PROVIDE ( r_hci_acl_tx_data_received = 0x40019654 ); -PROVIDE ( r_hci_bt_acl_bdaddr_register = 0x40018900 ); -PROVIDE ( r_hci_bt_acl_bdaddr_unregister = 0x400189ac ); -PROVIDE ( r_hci_bt_acl_conhdl_register = 0x4001895c ); -PROVIDE ( r_hci_cmd_get_max_param_size = 0x400192d0 ); -PROVIDE ( r_hci_cmd_received = 0x400192f8 ); -PROVIDE ( r_hci_evt_filter_add = 0x40018a64 ); -PROVIDE ( r_hci_evt_mask_set = 0x400189e4 ); -PROVIDE ( r_hci_fc_acl_buf_size_set = 0x40017988 ); -PROVIDE ( r_hci_fc_acl_en = 0x400179d8 ); -PROVIDE ( r_hci_fc_acl_packet_sent = 0x40017a3c ); -PROVIDE ( r_hci_fc_check_host_available_nb_acl_packets = 0x40017aa4 ); -PROVIDE ( r_hci_fc_check_host_available_nb_sync_packets = 0x40017ac8 ); -PROVIDE ( r_hci_fc_host_nb_acl_pkts_complete = 0x40017a6c ); -PROVIDE ( r_hci_fc_host_nb_sync_pkts_complete = 0x40017a88 ); -PROVIDE ( r_hci_fc_init = 0x40017974 ); -PROVIDE ( r_hci_fc_sync_buf_size_set = 0x400179b0 ); -PROVIDE ( r_hci_fc_sync_en = 0x40017a30 ); -PROVIDE ( r_hci_fc_sync_packet_sent = 0x40017a54 ); -PROVIDE ( r_hci_init = 0x40018538 ); -PROVIDE ( r_hci_look_for_cmd_desc = 0x40018454 ); -PROVIDE ( r_hci_look_for_dbg_evt_desc = 0x400184c4 ); -PROVIDE ( r_hci_look_for_evt_desc = 0x400184a0 ); -PROVIDE ( r_hci_look_for_le_evt_desc = 0x400184e0 ); -PROVIDE ( r_hci_reset = 0x4001856c ); -PROVIDE ( r_hci_send_2_host = 0x400185bc ); -PROVIDE ( r_hci_sync_tx_data_alloc = 0x40019754 ); -PROVIDE ( r_hci_sync_tx_data_received = 0x400197c0 ); -PROVIDE ( r_hci_tl_init = 0x40019290 ); -PROVIDE ( r_hci_tl_send = 0x40019228 ); -PROVIDE ( r_hci_util_pack = 0x40019874 ); -PROVIDE ( r_hci_util_unpack = 0x40019998 ); -PROVIDE ( r_hci_voice_settings_get = 0x40018bdc ); -PROVIDE ( r_hci_voice_settings_set = 0x40018be8 ); -PROVIDE ( r_HMAC = 0x40013968 ); -PROVIDE ( r_import_rf_phy_func = 0x3ffb8354 ); -PROVIDE ( r_import_rf_phy_func_p = 0x3ffafd64 ); -PROVIDE ( r_ip_funcs = 0x3ffae710 ); -PROVIDE ( r_ip_funcs_p = 0x3ffae70c ); -PROVIDE ( r_ke_check_malloc = 0x40019de0 ); -PROVIDE ( r_ke_event_callback_set = 0x40019ba8 ); -PROVIDE ( r_ke_event_clear = 0x40019c2c ); -PROVIDE ( r_ke_event_flush = 0x40019ccc ); -PROVIDE ( r_ke_event_get = 0x40019c78 ); -PROVIDE ( r_ke_event_get_all = 0x40019cc0 ); -PROVIDE ( r_ke_event_init = 0x40019b90 ); -PROVIDE ( r_ke_event_schedule = 0x40019cdc ); -PROVIDE ( r_ke_event_set = 0x40019be0 ); -PROVIDE ( r_ke_flush = 0x4001a374 ); -PROVIDE ( r_ke_free = 0x4001a014 ); -PROVIDE ( r_ke_get_max_mem_usage = 0x4001a1c8 ); -PROVIDE ( r_ke_get_mem_usage = 0x4001a1a0 ); -PROVIDE ( r_ke_init = 0x4001a318 ); -PROVIDE ( r_ke_is_free = 0x4001a184 ); -PROVIDE ( r_ke_malloc = 0x40019eb4 ); -PROVIDE ( r_ke_mem_init = 0x40019d3c ); -PROVIDE ( r_ke_mem_is_empty = 0x40019d8c ); -PROVIDE ( r_ke_msg_alloc = 0x4001a1e0 ); -PROVIDE ( r_ke_msg_dest_id_get = 0x4001a2e0 ); -PROVIDE ( r_ke_msg_discard = 0x4001a850 ); -PROVIDE ( r_ke_msg_forward = 0x4001a290 ); -PROVIDE ( r_ke_msg_forward_new_id = 0x4001a2ac ); -PROVIDE ( r_ke_msg_free = 0x4001a2cc ); -PROVIDE ( r_ke_msg_in_queue = 0x4001a2f8 ); -PROVIDE ( r_ke_msg_save = 0x4001a858 ); -PROVIDE ( r_ke_msg_send = 0x4001a234 ); -PROVIDE ( r_ke_msg_send_basic = 0x4001a26c ); -PROVIDE ( r_ke_msg_src_id_get = 0x4001a2ec ); -PROVIDE ( r_ke_queue_extract = 0x40055fd0 ); -PROVIDE ( r_ke_queue_insert = 0x40056020 ); -PROVIDE ( r_ke_sleep_check = 0x4001a3d8 ); -PROVIDE ( r_ke_state_get = 0x4001a7d8 ); -PROVIDE ( r_ke_state_set = 0x4001a6fc ); -PROVIDE ( r_ke_stats_get = 0x4001a3f0 ); -PROVIDE ( r_ke_task_check = 0x4001a8a4 ); -PROVIDE ( r_ke_task_create = 0x4001a674 ); -PROVIDE ( r_ke_task_delete = 0x4001a6c0 ); -PROVIDE ( r_ke_task_init = 0x4001a650 ); -PROVIDE ( r_ke_task_msg_flush = 0x4001a860 ); -PROVIDE ( r_ke_timer_active = 0x4001ac08 ); -PROVIDE ( r_ke_timer_adjust_all = 0x4001ac30 ); -PROVIDE ( r_ke_timer_clear = 0x4001ab90 ); -PROVIDE ( r_ke_timer_init = 0x4001aa9c ); -PROVIDE ( r_ke_timer_set = 0x4001aac0 ); -PROVIDE ( r_ke_timer_sleep_check = 0x4001ac50 ); -PROVIDE ( r_KPrimC = 0x40010ad4 ); -PROVIDE ( r_lb_clk_adj_activate = 0x4001ae70 ); -PROVIDE ( r_lb_clk_adj_id_get = 0x4001af14 ); -PROVIDE ( r_lb_clk_adj_period_update = 0x4001af20 ); -PROVIDE ( r_lb_init = 0x4001acd4 ); -PROVIDE ( r_lb_mst_key = 0x4001afc0 ); -PROVIDE ( r_lb_mst_key_cmp = 0x4001af74 ); -PROVIDE ( r_lb_mst_key_restart_enc = 0x4001b0d4 ); -PROVIDE ( r_lb_mst_start_act_bcst_enc = 0x4001b198 ); -PROVIDE ( r_lb_mst_stop_act_bcst_enc = 0x4001b24c ); -PROVIDE ( r_lb_reset = 0x4001ad38 ); -PROVIDE ( r_lb_send_lmp = 0x4001adbc ); -PROVIDE ( r_lb_send_pdu_clk_adj = 0x4001af3c ); -PROVIDE ( r_lb_util_get_csb_mode = 0x4001ada4 ); -PROVIDE ( r_lb_util_get_nb_broadcast = 0x4001ad80 ); -PROVIDE ( r_lb_util_get_res_lt_addr = 0x4001ad98 ); -PROVIDE ( r_lb_util_set_nb_broadcast = 0x4001ad8c ); -PROVIDE ( r_lc_afh_set = 0x4001cc74 ); -PROVIDE ( r_lc_afh_start = 0x4001d240 ); -PROVIDE ( r_lc_auth_cmp = 0x4001cd54 ); -PROVIDE ( r_lc_calc_link_key = 0x4001ce7c ); -PROVIDE ( r_lc_chg_pkt_type_cmp = 0x4001d038 ); -PROVIDE ( r_lc_chg_pkt_type_cont = 0x4001cfbc ); -PROVIDE ( r_lc_chg_pkt_type_retry = 0x4001d0ac ); -PROVIDE ( r_lc_chk_to = 0x4001d2a8 ); -PROVIDE ( r_lc_cmd_stat_send = 0x4001c914 ); -PROVIDE ( r_lc_comb_key_svr = 0x4001d30c ); -PROVIDE ( r_lc_con_cmp = 0x4001d44c ); -PROVIDE ( r_lc_con_cmp_evt_send = 0x4001d4fc ); -PROVIDE ( r_lc_conn_seq_done = 0x40021334 ); -PROVIDE ( r_lc_detach = 0x4002037c ); -PROVIDE ( r_lc_dhkey = 0x4001d564 ); -PROVIDE ( r_lc_enc_cmp = 0x4001d8bc ); -PROVIDE ( r_lc_enc_key_refresh = 0x4001d720 ); -PROVIDE ( r_lc_end_chk_colli = 0x4001d858 ); -PROVIDE ( r_lc_end_of_sniff_nego = 0x4001d9a4 ); -PROVIDE ( r_lc_enter_sniff_mode = 0x4001ddb8 ); -PROVIDE ( r_lc_epr_change_lk = 0x4001db38 ); -PROVIDE ( r_lc_epr_cmp = 0x4001da88 ); -PROVIDE ( r_lc_epr_resp = 0x4001e0b4 ); -PROVIDE ( r_lc_epr_rsw_cmp = 0x4001dd40 ); -PROVIDE ( r_lc_ext_feat = 0x40020d6c ); -PROVIDE ( r_lc_feat = 0x40020984 ); -PROVIDE ( r_lc_hl_connect = 0x400209e8 ); -PROVIDE ( r_lc_init = 0x4001c948 ); -PROVIDE ( r_lc_init_calc_f3 = 0x4001deb0 ); -PROVIDE ( r_lc_initiator_epr = 0x4001e064 ); -PROVIDE ( r_lc_init_passkey_loop = 0x4001dfc0 ); -PROVIDE ( r_lc_init_start_mutual_auth = 0x4001df60 ); -PROVIDE ( r_lc_key_exch_end = 0x4001e140 ); -PROVIDE ( r_lc_legacy_pair = 0x4001e1c0 ); -PROVIDE ( r_lc_local_switch = 0x4001e22c ); -PROVIDE ( r_lc_local_trans_mode = 0x4001e2e4 ); -PROVIDE ( r_lc_local_untrans_mode = 0x4001e3a0 ); -PROVIDE ( r_lc_loc_auth = 0x40020ecc ); -PROVIDE ( r_lc_locepr_lkref = 0x4001d648 ); -PROVIDE ( r_lc_locepr_rsw = 0x4001d5d0 ); -PROVIDE ( r_lc_loc_sniff = 0x40020a6c ); -PROVIDE ( r_lc_max_slot_mgt = 0x4001e410 ); -PROVIDE ( r_lc_mst_key = 0x4001e7c0 ); -PROVIDE ( r_lc_mst_qos_done = 0x4001ea80 ); -PROVIDE ( r_lc_mst_send_mst_key = 0x4001e8f4 ); -PROVIDE ( r_lc_mutual_auth_end = 0x4001e670 ); -PROVIDE ( r_lc_mutual_auth_end2 = 0x4001e4f4 ); -PROVIDE ( r_lc_packet_type = 0x40021038 ); -PROVIDE ( r_lc_pair = 0x40020ddc ); -PROVIDE ( r_lc_pairing_cont = 0x4001eafc ); -PROVIDE ( r_lc_passkey_comm = 0x4001ed20 ); -PROVIDE ( r_lc_prepare_all_links_for_clk_adj = 0x40021430 ); -PROVIDE ( r_lc_proc_rcv_dhkey = 0x4001edec ); -PROVIDE ( r_lc_ptt = 0x4001ee2c ); -PROVIDE ( r_lc_ptt_cmp = 0x4001eeec ); -PROVIDE ( r_lc_qos_setup = 0x4001ef50 ); -PROVIDE ( r_lc_rd_rem_name = 0x4001efd0 ); -PROVIDE ( r_lc_release = 0x4001f8a8 ); -PROVIDE ( r_lc_rem_enc = 0x4001f124 ); -PROVIDE ( r_lc_rem_name_cont = 0x4001f290 ); -PROVIDE ( r_lc_rem_nego_trans_mode = 0x4001f1b4 ); -PROVIDE ( r_lc_rem_sniff = 0x40020ca4 ); -PROVIDE ( r_lc_rem_sniff_sub_rate = 0x40020b10 ); -PROVIDE ( r_lc_rem_switch = 0x4001f070 ); -PROVIDE ( r_lc_rem_trans_mode = 0x4001f314 ); -PROVIDE ( r_lc_rem_unsniff = 0x400207a0 ); -PROVIDE ( r_lc_rem_untrans_mode = 0x4001f36c ); -PROVIDE ( r_lc_reset = 0x4001c99c ); -PROVIDE ( r_lc_resp_auth = 0x4001f518 ); -PROVIDE ( r_lc_resp_calc_f3 = 0x4001f710 ); -PROVIDE ( r_lc_resp_num_comp = 0x40020074 ); -PROVIDE ( r_lc_resp_oob_nonce = 0x4001f694 ); -PROVIDE ( r_lc_resp_oob_wait_nonce = 0x4001f66c ); -PROVIDE ( r_lc_resp_pair = 0x400208a4 ); -PROVIDE ( r_lc_resp_sec_auth = 0x4001f4a0 ); -PROVIDE ( r_lc_resp_wait_dhkey_cont = 0x4001f86c ); -PROVIDE ( r_lc_restart_enc = 0x4001f8ec ); -PROVIDE ( r_lc_restart_enc_cont = 0x4001f940 ); -PROVIDE ( r_lc_restore_afh_reporting = 0x4001f028 ); -PROVIDE ( r_lc_restore_to = 0x4001f9e0 ); -PROVIDE ( r_lc_ret_sniff_max_slot_chg = 0x4001fa30 ); -PROVIDE ( r_lc_rsw_clean_up = 0x4001dc70 ); -PROVIDE ( r_lc_rsw_done = 0x4001db94 ); -PROVIDE ( r_lc_sco_baseband_ack = 0x40022b00 ); -PROVIDE ( r_lc_sco_detach = 0x40021e40 ); -PROVIDE ( r_lc_sco_host_accept = 0x40022118 ); -PROVIDE ( r_lc_sco_host_reject = 0x400222b8 ); -PROVIDE ( r_lc_sco_host_request = 0x40021f4c ); -PROVIDE ( r_lc_sco_host_request_disc = 0x4002235c ); -PROVIDE ( r_lc_sco_init = 0x40021dc8 ); -PROVIDE ( r_lc_sco_peer_accept = 0x40022780 ); -PROVIDE ( r_lc_sco_peer_accept_disc = 0x40022a08 ); -PROVIDE ( r_lc_sco_peer_reject = 0x40022824 ); -PROVIDE ( r_lc_sco_peer_reject_disc = 0x40022a8c ); -PROVIDE ( r_lc_sco_peer_request = 0x4002240c ); -PROVIDE ( r_lc_sco_peer_request_disc = 0x400228ec ); -PROVIDE ( r_lc_sco_release = 0x40021eec ); -PROVIDE ( r_lc_sco_reset = 0x40021dfc ); -PROVIDE ( r_lc_sco_timeout = 0x40022bd4 ); -PROVIDE ( r_lc_sec_auth_compute_sres = 0x4001f3ec ); -PROVIDE ( r_lc_semi_key_cmp = 0x40020294 ); -PROVIDE ( r_lc_send_enc_chg_evt = 0x4002134c ); -PROVIDE ( r_lc_send_enc_mode = 0x40020220 ); -PROVIDE ( r_lc_send_lmp = 0x4001c1a8 ); -PROVIDE ( r_lc_send_pdu_acc = 0x4001c21c ); -PROVIDE ( r_lc_send_pdu_acc_ext4 = 0x4001c240 ); -PROVIDE ( r_lc_send_pdu_au_rand = 0x4001c308 ); -PROVIDE ( r_lc_send_pdu_auto_rate = 0x4001c5d0 ); -PROVIDE ( r_lc_send_pdu_clk_adj_ack = 0x4001c46c ); -PROVIDE ( r_lc_send_pdu_clk_adj_req = 0x4001c494 ); -PROVIDE ( r_lc_send_pdu_comb_key = 0x4001c368 ); -PROVIDE ( r_lc_send_pdu_dhkey_chk = 0x4001c8e8 ); -PROVIDE ( r_lc_send_pdu_encaps_head = 0x4001c440 ); -PROVIDE ( r_lc_send_pdu_encaps_payl = 0x4001c410 ); -PROVIDE ( r_lc_send_pdu_enc_key_sz_req = 0x4001c670 ); -PROVIDE ( r_lc_send_pdu_esco_lk_rem_req = 0x4001c5a8 ); -PROVIDE ( r_lc_send_pdu_feats_ext_req = 0x4001c6ec ); -PROVIDE ( r_lc_send_pdu_feats_res = 0x4001c694 ); -PROVIDE ( r_lc_send_pdu_in_rand = 0x4001c338 ); -PROVIDE ( r_lc_send_pdu_io_cap_res = 0x4001c72c ); -PROVIDE ( r_lc_send_pdu_lsto = 0x4001c64c ); -PROVIDE ( r_lc_send_pdu_max_slot = 0x4001c3c8 ); -PROVIDE ( r_lc_send_pdu_max_slot_req = 0x4001c3ec ); -PROVIDE ( r_lc_send_pdu_not_acc = 0x4001c26c ); -PROVIDE ( r_lc_send_pdu_not_acc_ext4 = 0x4001c294 ); -PROVIDE ( r_lc_send_pdu_num_comp_fail = 0x4001c770 ); -PROVIDE ( r_lc_send_pdu_pause_enc_aes_req = 0x4001c794 ); -PROVIDE ( r_lc_send_pdu_paus_enc_req = 0x4001c7c0 ); -PROVIDE ( r_lc_send_pdu_ptt_req = 0x4001c4c0 ); -PROVIDE ( r_lc_send_pdu_qos_req = 0x4001c82c ); -PROVIDE ( r_lc_send_pdu_resu_enc_req = 0x4001c7e4 ); -PROVIDE ( r_lc_send_pdu_sco_lk_rem_req = 0x4001c580 ); -PROVIDE ( r_lc_send_pdu_set_afh = 0x4001c2c8 ); -PROVIDE ( r_lc_send_pdu_setup_cmp = 0x4001c808 ); -PROVIDE ( r_lc_send_pdu_slot_off = 0x4001c854 ); -PROVIDE ( r_lc_send_pdu_sniff_req = 0x4001c5f0 ); -PROVIDE ( r_lc_send_pdu_sp_cfm = 0x4001c518 ); -PROVIDE ( r_lc_send_pdu_sp_nb = 0x4001c4e8 ); -PROVIDE ( r_lc_send_pdu_sres = 0x4001c548 ); -PROVIDE ( r_lc_send_pdu_tim_acc = 0x4001c6cc ); -PROVIDE ( r_lc_send_pdu_unit_key = 0x4001c398 ); -PROVIDE ( r_lc_send_pdu_unsniff_req = 0x4001c894 ); -PROVIDE ( r_lc_send_pdu_vers_req = 0x4001c8b4 ); -PROVIDE ( r_lc_skip_hl_oob_req = 0x400201bc ); -PROVIDE ( r_lc_sniff_init = 0x40022cac ); -PROVIDE ( r_lc_sniff_max_slot_chg = 0x40020590 ); -PROVIDE ( r_lc_sniff_reset = 0x40022cc8 ); -PROVIDE ( r_lc_sniff_slot_unchange = 0x40021100 ); -PROVIDE ( r_lc_sniff_sub_mode = 0x400204fc ); -PROVIDE ( r_lc_sp_end = 0x400213a8 ); -PROVIDE ( r_lc_sp_fail = 0x40020470 ); -PROVIDE ( r_lc_sp_oob_tid_fail = 0x400204cc ); -PROVIDE ( r_lc_ssr_nego = 0x4002125c ); -PROVIDE ( r_lc_start = 0x4001ca28 ); -PROVIDE ( r_lc_start_enc = 0x4001fb28 ); -PROVIDE ( r_lc_start_enc_key_size = 0x4001fd9c ); -PROVIDE ( r_lc_start_key_exch = 0x4001fe10 ); -PROVIDE ( r_lc_start_lmp_to = 0x4001fae8 ); -PROVIDE ( r_lc_start_oob = 0x4001fffc ); -PROVIDE ( r_lc_start_passkey = 0x4001feac ); -PROVIDE ( r_lc_start_passkey_loop = 0x4001ff88 ); -PROVIDE ( r_lc_stop_afh_report = 0x40020184 ); -PROVIDE ( r_lc_stop_enc = 0x40020110 ); -PROVIDE ( r_lc_switch_cmp = 0x40020448 ); -PROVIDE ( r_lc_unit_key_svr = 0x400206d8 ); -PROVIDE ( r_lc_unsniff = 0x40020c50 ); -PROVIDE ( r_lc_unsniff_cmp = 0x40020810 ); -PROVIDE ( r_lc_unsniff_cont = 0x40020750 ); -PROVIDE ( r_lc_upd_to = 0x4002065c ); -PROVIDE ( r_lc_util_convert_pref_rate_to_packet_type = 0x4002f9b0 ); -PROVIDE ( r_lc_util_get_max_packet_size = 0x4002f4ac ); -PROVIDE ( r_lc_util_get_offset_clke = 0x4002f538 ); -PROVIDE ( r_lc_util_get_offset_clkn = 0x4002f51c ); -PROVIDE ( r_lc_util_set_loc_trans_coll = 0x4002f500 ); -PROVIDE ( r_lc_version = 0x40020a30 ); -PROVIDE ( r_ld_acl_active_hop_types_get = 0x40036e10 ); -PROVIDE ( r_ld_acl_afh_confirm = 0x40036d40 ); -PROVIDE ( r_ld_acl_afh_prepare = 0x40036c84 ); -PROVIDE ( r_ld_acl_afh_set = 0x40036b60 ); -PROVIDE ( r_ld_acl_allowed_tx_packet_types_set = 0x40036810 ); -PROVIDE ( r_ld_acl_bcst_rx_dec = 0x40036394 ); -PROVIDE ( r_ld_acl_bit_off_get = 0x40036b18 ); -PROVIDE ( r_ld_acl_clk_adj_set = 0x40036a00 ); -PROVIDE ( r_ld_acl_clk_off_get = 0x40036b00 ); -PROVIDE ( r_ld_acl_clk_set = 0x40036950 ); -PROVIDE ( r_ld_acl_clock_offset_get = 0x400364c0 ); -PROVIDE ( r_ld_acl_current_tx_power_get = 0x400368f0 ); -PROVIDE ( r_ld_acl_data_flush = 0x400357bc ); -PROVIDE ( r_ld_acl_data_tx = 0x4003544c ); -PROVIDE ( r_ld_acl_edr_set = 0x4003678c ); -PROVIDE ( r_ld_acl_enc_key_load = 0x40036404 ); -PROVIDE ( r_ld_acl_flow_off = 0x40035400 ); -PROVIDE ( r_ld_acl_flow_on = 0x4003541c ); -PROVIDE ( r_ld_acl_flush_timeout_get = 0x40035f9c ); -PROVIDE ( r_ld_acl_flush_timeout_set = 0x40035fe0 ); -PROVIDE ( r_ld_acl_init = 0x40034d08 ); -PROVIDE ( r_ld_acl_lmp_flush = 0x40035d80 ); -PROVIDE ( r_ld_acl_lmp_tx = 0x40035b34 ); -PROVIDE ( r_ld_acl_lsto_get = 0x400366b4 ); -PROVIDE ( r_ld_acl_lsto_set = 0x400366f8 ); -PROVIDE ( r_ld_acl_reset = 0x40034d24 ); -PROVIDE ( r_ld_acl_role_get = 0x40036b30 ); -PROVIDE ( r_ld_acl_rssi_delta_get = 0x40037028 ); -PROVIDE ( r_ld_acl_rsw_req = 0x40035e74 ); -PROVIDE ( r_ld_acl_rx_enc = 0x40036344 ); -PROVIDE ( r_ld_acl_rx_max_slot_get = 0x40036e58 ); -PROVIDE ( r_ld_acl_rx_max_slot_set = 0x40036ea0 ); -PROVIDE ( r_ld_acl_slot_offset_get = 0x4003653c ); -PROVIDE ( r_ld_acl_slot_offset_set = 0x40036658 ); -PROVIDE ( r_ld_acl_sniff = 0x4003617c ); -PROVIDE ( r_ld_acl_sniff_trans = 0x400360a8 ); -PROVIDE ( r_ld_acl_ssr_set = 0x40036274 ); -PROVIDE ( r_ld_acl_start = 0x40034ddc ); -PROVIDE ( r_ld_acl_stop = 0x4003532c ); -PROVIDE ( r_ld_acl_test_mode_set = 0x40036f24 ); -PROVIDE ( r_ld_acl_timing_accuracy_set = 0x4003673c ); -PROVIDE ( r_ld_acl_t_poll_get = 0x40036024 ); -PROVIDE ( r_ld_acl_t_poll_set = 0x40036068 ); -PROVIDE ( r_ld_acl_tx_enc = 0x400362f8 ); -PROVIDE ( r_ld_acl_unsniff = 0x400361e0 ); -PROVIDE ( r_ld_active_check = 0x4003cac4 ); -PROVIDE ( r_ld_afh_ch_assess_data_get = 0x4003caec ); -PROVIDE ( r_ld_bcst_acl_data_tx = 0x40038d3c ); -PROVIDE ( r_ld_bcst_acl_init = 0x40038bd0 ); -PROVIDE ( r_ld_bcst_acl_reset = 0x40038bdc ); -PROVIDE ( r_ld_bcst_acl_start = 0x4003882c ); -PROVIDE ( r_ld_bcst_afh_update = 0x40038f3c ); -PROVIDE ( r_ld_bcst_enc_key_load = 0x4003906c ); -PROVIDE ( r_ld_bcst_lmp_tx = 0x40038bf8 ); -PROVIDE ( r_ld_bcst_tx_enc = 0x40038ff8 ); -PROVIDE ( r_ld_bd_addr_get = 0x4003ca20 ); -PROVIDE ( r_ld_channel_assess = 0x4003c184 ); -PROVIDE ( r_ld_class_of_dev_get = 0x4003ca34 ); -PROVIDE ( r_ld_class_of_dev_set = 0x4003ca50 ); -PROVIDE ( r_ld_csb_rx_afh_update = 0x40039af4 ); -PROVIDE ( r_ld_csb_rx_init = 0x40039690 ); -PROVIDE ( r_ld_csb_rx_reset = 0x4003969c ); -PROVIDE ( r_ld_csb_rx_start = 0x4003972c ); -PROVIDE ( r_ld_csb_rx_stop = 0x40039bb8 ); -PROVIDE ( r_ld_csb_tx_afh_update = 0x4003a5fc ); -PROVIDE ( r_ld_csb_tx_clr_data = 0x4003a71c ); -PROVIDE ( r_ld_csb_tx_dis = 0x4003a5e8 ); -PROVIDE ( r_ld_csb_tx_en = 0x4003a1c0 ); -PROVIDE ( r_ld_csb_tx_init = 0x4003a0e8 ); -PROVIDE ( r_ld_csb_tx_reset = 0x4003a0f8 ); -PROVIDE ( r_ld_csb_tx_set_data = 0x4003a6c0 ); -PROVIDE ( r_ld_fm_clk_isr = 0x4003a7a8 ); -PROVIDE ( r_ld_fm_frame_isr = 0x4003a82c ); -PROVIDE ( r_ld_fm_init = 0x4003a760 ); -PROVIDE ( r_ld_fm_prog_check = 0x4003ab28 ); -PROVIDE ( r_ld_fm_prog_disable = 0x4003a984 ); -PROVIDE ( r_ld_fm_prog_enable = 0x4003a944 ); -PROVIDE ( r_ld_fm_prog_push = 0x4003a9d4 ); -PROVIDE ( r_ld_fm_reset = 0x4003a794 ); -PROVIDE ( r_ld_fm_rx_isr = 0x4003a7f4 ); -PROVIDE ( r_ld_fm_sket_isr = 0x4003a8a4 ); -PROVIDE ( r_ld_init = 0x4003c294 ); -PROVIDE ( r_ld_inq_init = 0x4003b15c ); -PROVIDE ( r_ld_inq_reset = 0x4003b168 ); -PROVIDE ( r_ld_inq_start = 0x4003b1f0 ); -PROVIDE ( r_ld_inq_stop = 0x4003b4f0 ); -PROVIDE ( r_ld_iscan_eir_get = 0x4003c118 ); -PROVIDE ( r_ld_iscan_eir_set = 0x4003bfa0 ); -PROVIDE ( r_ld_iscan_init = 0x4003b9f0 ); -PROVIDE ( r_ld_iscan_reset = 0x4003ba14 ); -PROVIDE ( r_ld_iscan_restart = 0x4003ba44 ); -PROVIDE ( r_ld_iscan_start = 0x4003bb28 ); -PROVIDE ( r_ld_iscan_stop = 0x4003bf1c ); -PROVIDE ( r_ld_iscan_tx_pwr_get = 0x4003c138 ); -PROVIDE ( r_ld_page_init = 0x4003d808 ); -PROVIDE ( r_ld_page_reset = 0x4003d814 ); -PROVIDE ( r_ld_page_start = 0x4003d848 ); -PROVIDE ( r_ld_page_stop = 0x4003da54 ); -PROVIDE ( r_ld_pca_coarse_clock_adjust = 0x4003e324 ); -PROVIDE ( r_ld_pca_init = 0x4003deb4 ); -PROVIDE ( r_ld_pca_initiate_clock_dragging = 0x4003e4ac ); -PROVIDE ( r_ld_pca_local_config = 0x4003df6c ); -PROVIDE ( r_ld_pca_mws_frame_sync = 0x4003e104 ); -PROVIDE ( r_ld_pca_mws_moment_offset_gt = 0x4003e278 ); -PROVIDE ( r_ld_pca_mws_moment_offset_lt = 0x4003e280 ); -PROVIDE ( r_ld_pca_reporting_enable = 0x4003e018 ); -PROVIDE ( r_ld_pca_reset = 0x4003df0c ); -PROVIDE ( r_ld_pca_update_target_offset = 0x4003e050 ); -PROVIDE ( r_ld_pscan_evt_handler = 0x4003f238 ); -PROVIDE ( r_ld_pscan_init = 0x4003f474 ); -PROVIDE ( r_ld_pscan_reset = 0x4003f498 ); -PROVIDE ( r_ld_pscan_restart = 0x4003f4b8 ); -PROVIDE ( r_ld_pscan_start = 0x4003f514 ); -PROVIDE ( r_ld_pscan_stop = 0x4003f618 ); -PROVIDE ( r_ld_read_clock = 0x4003c9e4 ); -PROVIDE ( r_ld_reset = 0x4003c714 ); -PROVIDE ( r_ld_sched_acl_add = 0x4003f978 ); -PROVIDE ( r_ld_sched_acl_remove = 0x4003f99c ); -PROVIDE ( r_ld_sched_compute = 0x4003f6f8 ); -PROVIDE ( r_ld_sched_init = 0x4003f7ac ); -PROVIDE ( r_ld_sched_inq_add = 0x4003f8a8 ); -PROVIDE ( r_ld_sched_inq_remove = 0x4003f8d0 ); -PROVIDE ( r_ld_sched_iscan_add = 0x4003f7e8 ); -PROVIDE ( r_ld_sched_iscan_remove = 0x4003f808 ); -PROVIDE ( r_ld_sched_page_add = 0x4003f910 ); -PROVIDE ( r_ld_sched_page_remove = 0x4003f938 ); -PROVIDE ( r_ld_sched_pscan_add = 0x4003f828 ); -PROVIDE ( r_ld_sched_pscan_remove = 0x4003f848 ); -PROVIDE ( r_ld_sched_reset = 0x4003f7d4 ); -PROVIDE ( r_ld_sched_sco_add = 0x4003fa4c ); -PROVIDE ( r_ld_sched_sco_remove = 0x4003fa9c ); -PROVIDE ( r_ld_sched_sniff_add = 0x4003f9c4 ); -PROVIDE ( r_ld_sched_sniff_remove = 0x4003fa0c ); -PROVIDE ( r_ld_sched_sscan_add = 0x4003f868 ); -PROVIDE ( r_ld_sched_sscan_remove = 0x4003f888 ); -PROVIDE ( r_ld_sco_audio_isr = 0x40037cc8 ); -PROVIDE ( r_ld_sco_data_tx = 0x40037ee8 ); -PROVIDE ( r_ld_sco_start = 0x40037110 ); -PROVIDE ( r_ld_sco_stop = 0x40037c40 ); -PROVIDE ( r_ld_sco_update = 0x40037a74 ); -PROVIDE ( r_ld_sscan_activated = 0x4004031c ); -PROVIDE ( r_ld_sscan_init = 0x400402f0 ); -PROVIDE ( r_ld_sscan_reset = 0x400402fc ); -PROVIDE ( r_ld_sscan_start = 0x40040384 ); -PROVIDE ( r_ld_strain_init = 0x400409f4 ); -PROVIDE ( r_ld_strain_reset = 0x40040a00 ); -PROVIDE ( r_ld_strain_start = 0x40040a8c ); -PROVIDE ( r_ld_strain_stop = 0x40040df0 ); -PROVIDE ( r_ld_timing_accuracy_get = 0x4003caac ); -PROVIDE ( r_ld_util_active_master_afh_map_get = 0x4004131c ); -PROVIDE ( r_ld_util_active_master_afh_map_set = 0x40041308 ); -PROVIDE ( r_ld_util_bch_create = 0x40040fcc ); -PROVIDE ( r_ld_util_fhs_pk = 0x400411c8 ); -PROVIDE ( r_ld_util_fhs_unpk = 0x40040e54 ); -PROVIDE ( r_ld_util_stp_pk = 0x400413f4 ); -PROVIDE ( r_ld_util_stp_unpk = 0x40041324 ); -PROVIDE ( r_ld_version_get = 0x4003ca6c ); -PROVIDE ( r_ld_wlcoex_set = 0x4003caf8 ); -PROVIDE ( r_llc_ch_assess_get_current_ch_map = 0x40041574 ); -PROVIDE ( r_llc_ch_assess_get_local_ch_map = 0x4004150c ); -PROVIDE ( r_llc_ch_assess_local = 0x40041494 ); -PROVIDE ( r_llc_ch_assess_merge_ch = 0x40041588 ); -PROVIDE ( r_llc_ch_assess_reass_ch = 0x400415c0 ); -PROVIDE ( r_llc_common_cmd_complete_send = 0x40044eac ); -PROVIDE ( r_llc_common_cmd_status_send = 0x40044ee0 ); -PROVIDE ( r_llc_common_enc_change_evt_send = 0x40044f6c ); -PROVIDE ( r_llc_common_enc_key_ref_comp_evt_send = 0x40044f38 ); -PROVIDE ( r_llc_common_flush_occurred_send = 0x40044f0c ); -PROVIDE ( r_llc_common_nb_of_pkt_comp_evt_send = 0x40045000 ); -PROVIDE ( r_llc_con_update_complete_send = 0x40044d68 ); -PROVIDE ( r_llc_con_update_finished = 0x4004518c ); -PROVIDE ( r_llc_con_update_ind = 0x40045038 ); -PROVIDE ( r_llc_discon_event_complete_send = 0x40044a30 ); -PROVIDE ( r_llc_end_evt_defer = 0x40046330 ); -PROVIDE ( r_llc_feats_rd_event_send = 0x40044e0c ); -PROVIDE ( r_llc_init = 0x40044778 ); -PROVIDE ( r_llc_le_con_cmp_evt_send = 0x40044a78 ); -PROVIDE ( r_llc_llcp_ch_map_update_pdu_send = 0x40043f94 ); -PROVIDE ( r_llc_llcp_con_param_req_pdu_send = 0x400442fc ); -PROVIDE ( r_llc_llcp_con_param_rsp_pdu_send = 0x40044358 ); -PROVIDE ( r_llc_llcp_con_update_pdu_send = 0x400442c4 ); -PROVIDE ( r_llc_llcp_enc_req_pdu_send = 0x40044064 ); -PROVIDE ( r_llc_llcp_enc_rsp_pdu_send = 0x40044160 ); -PROVIDE ( r_llc_llcp_feats_req_pdu_send = 0x400443b4 ); -PROVIDE ( r_llc_llcp_feats_rsp_pdu_send = 0x400443f0 ); -PROVIDE ( r_llc_llcp_get_autorize = 0x4004475c ); -PROVIDE ( r_llc_llcp_length_req_pdu_send = 0x40044574 ); -PROVIDE ( r_llc_llcp_length_rsp_pdu_send = 0x400445ac ); -PROVIDE ( r_llc_llcp_pause_enc_req_pdu_send = 0x40043fd8 ); -PROVIDE ( r_llc_llcp_pause_enc_rsp_pdu_send = 0x40044010 ); -PROVIDE ( r_llc_llcp_ping_req_pdu_send = 0x4004454c ); -PROVIDE ( r_llc_llcp_ping_rsp_pdu_send = 0x40044560 ); -PROVIDE ( r_llc_llcp_recv_handler = 0x40044678 ); -PROVIDE ( r_llc_llcp_reject_ind_pdu_send = 0x4004425c ); -PROVIDE ( r_llc_llcp_start_enc_req_pdu_send = 0x4004441c ); -PROVIDE ( r_llc_llcp_start_enc_rsp_pdu_send = 0x400441f8 ); -PROVIDE ( r_llc_llcp_terminate_ind_pdu_send = 0x400444b0 ); -PROVIDE ( r_llc_llcp_tester_send = 0x400445e4 ); -PROVIDE ( r_llc_llcp_unknown_rsp_send_pdu = 0x40044534 ); -PROVIDE ( r_llc_llcp_version_ind_pdu_send = 0x40043f6c ); -PROVIDE ( r_llc_lsto_con_update = 0x40045098 ); -PROVIDE ( r_llc_ltk_req_send = 0x40044dc0 ); -PROVIDE ( r_llc_map_update_finished = 0x40045260 ); -PROVIDE ( r_llc_map_update_ind = 0x400450f0 ); -PROVIDE ( r_llc_pdu_acl_tx_ack_defer = 0x400464dc ); -PROVIDE ( r_llc_pdu_defer = 0x40046528 ); -PROVIDE ( r_llc_pdu_llcp_tx_ack_defer = 0x400463ac ); -PROVIDE ( r_llc_reset = 0x400447b8 ); -PROVIDE ( r_llc_start = 0x400447f4 ); -PROVIDE ( r_llc_stop = 0x400449ac ); -PROVIDE ( r_llc_util_bw_mgt = 0x4004629c ); -PROVIDE ( r_llc_util_clear_operation_ptr = 0x40046234 ); -PROVIDE ( r_llc_util_dicon_procedure = 0x40046130 ); -PROVIDE ( r_llc_util_get_free_conhdl = 0x400460c8 ); -PROVIDE ( r_llc_util_get_nb_active_link = 0x40046100 ); -PROVIDE ( r_llc_util_set_auth_payl_to_margin = 0x400461f4 ); -PROVIDE ( r_llc_util_set_llcp_discard_enable = 0x400461c8 ); -PROVIDE ( r_llc_util_update_channel_map = 0x400461ac ); -PROVIDE ( r_llc_version_rd_event_send = 0x40044e60 ); -PROVIDE ( r_lld_adv_start = 0x40048b38 ); -PROVIDE ( r_lld_adv_stop = 0x40048ea0 ); -PROVIDE ( r_lld_ch_map_ind = 0x4004a2f4 ); -PROVIDE ( r_lld_con_param_req = 0x40049f0c ); -PROVIDE ( r_lld_con_param_rsp = 0x40049e00 ); -PROVIDE ( r_lld_con_start = 0x400491f8 ); -PROVIDE ( r_lld_con_stop = 0x40049fdc ); -PROVIDE ( r_lld_con_update_after_param_req = 0x40049bcc ); -PROVIDE ( r_lld_con_update_ind = 0x4004a30c ); -PROVIDE ( r_lld_con_update_req = 0x40049b60 ); -PROVIDE ( r_lld_core_reset = 0x40048a9c ); -PROVIDE ( r_lld_crypt_isr = 0x4004a324 ); -PROVIDE ( r_lld_evt_adv_create = 0x400481f4 ); -PROVIDE ( r_lld_evt_canceled = 0x400485c8 ); -PROVIDE ( r_lld_evt_channel_next = 0x40046aac ); -PROVIDE ( r_lld_evt_deffered_elt_handler = 0x400482bc ); -PROVIDE ( r_lld_evt_delete_elt_handler = 0x40046974 ); -PROVIDE ( r_lld_evt_delete_elt_push = 0x40046a3c ); -PROVIDE ( r_lld_evt_drift_compute = 0x40047670 ); -PROVIDE ( r_lld_evt_elt_delete = 0x40047538 ); -PROVIDE ( r_lld_evt_elt_insert = 0x400474c8 ); -PROVIDE ( r_lld_evt_end = 0x400483e8 ); -PROVIDE ( r_lld_evt_end_isr = 0x4004862c ); -PROVIDE ( r_lld_evt_init = 0x40046b3c ); -PROVIDE ( r_lld_evt_init_evt = 0x40046cd0 ); -PROVIDE ( r_lld_evt_move_to_master = 0x40047ba0 ); -PROVIDE ( r_lld_evt_move_to_slave = 0x40047e18 ); -PROVIDE ( r_lld_evt_prevent_stop = 0x40047adc ); -PROVIDE ( r_lld_evt_restart = 0x40046d50 ); -PROVIDE ( r_lld_evt_rx = 0x40048578 ); -PROVIDE ( r_lld_evt_rx_isr = 0x40048678 ); -PROVIDE ( r_lld_evt_scan_create = 0x40047ae8 ); -PROVIDE ( r_lld_evt_schedule = 0x40047908 ); -PROVIDE ( r_lld_evt_schedule_next = 0x400477dc ); -PROVIDE ( r_lld_evt_schedule_next_instant = 0x400476a8 ); -PROVIDE ( r_lld_evt_slave_update = 0x40048138 ); -PROVIDE ( r_lld_evt_update_create = 0x40047cd8 ); -PROVIDE ( r_lld_get_mode = 0x40049ff8 ); -PROVIDE ( r_lld_init = 0x4004873c ); -PROVIDE ( r_lld_move_to_master = 0x400499e0 ); -PROVIDE ( r_lld_move_to_slave = 0x4004a024 ); -PROVIDE ( r_lld_pdu_adv_pack = 0x4004b488 ); -PROVIDE ( r_lld_pdu_check = 0x4004ac34 ); -PROVIDE ( r_lld_pdu_data_send = 0x4004b018 ); -PROVIDE ( r_lld_pdu_data_tx_push = 0x4004aecc ); -PROVIDE ( r_lld_pdu_rx_handler = 0x4004b4d4 ); -PROVIDE ( r_lld_pdu_send_packet = 0x4004b774 ); -PROVIDE ( r_lld_pdu_tx_flush = 0x4004b414 ); -PROVIDE ( r_lld_pdu_tx_loop = 0x4004ae40 ); -PROVIDE ( r_lld_pdu_tx_prog = 0x4004b120 ); -PROVIDE ( r_lld_pdu_tx_push = 0x4004b080 ); -PROVIDE ( r_lld_ral_renew_req = 0x4004a73c ); -PROVIDE ( r_lld_scan_start = 0x40048ee0 ); -PROVIDE ( r_lld_scan_stop = 0x40049190 ); -PROVIDE ( r_lld_test_mode_rx = 0x4004a540 ); -PROVIDE ( r_lld_test_mode_tx = 0x4004a350 ); -PROVIDE ( r_lld_test_stop = 0x4004a710 ); -PROVIDE ( r_lld_util_anchor_point_move = 0x4004bacc ); -PROVIDE ( r_lld_util_compute_ce_max = 0x4004bc0c ); -PROVIDE ( r_lld_util_connection_param_set = 0x4004ba40 ); -PROVIDE ( r_lld_util_dle_set_cs_fields = 0x4004ba90 ); -PROVIDE ( r_lld_util_eff_tx_time_set = 0x4004bd88 ); -PROVIDE ( r_lld_util_elt_programmed = 0x4004bce0 ); -PROVIDE ( r_lld_util_flush_list = 0x4004bbd8 ); -PROVIDE ( r_lld_util_freq2chnl = 0x4004b9e4 ); -PROVIDE ( r_lld_util_get_bd_address = 0x4004b8ac ); -PROVIDE ( r_lld_util_get_local_offset = 0x4004ba10 ); -PROVIDE ( r_lld_util_get_peer_offset = 0x4004ba24 ); -PROVIDE ( r_lld_util_get_tx_pkt_cnt = 0x4004bd80 ); -PROVIDE ( r_lld_util_instant_get = 0x4004b890 ); -PROVIDE ( r_lld_util_instant_ongoing = 0x4004bbfc ); -PROVIDE ( r_lld_util_priority_set = 0x4004bd10 ); -PROVIDE ( r_lld_util_priority_update = 0x4004bd78 ); -PROVIDE ( r_lld_util_ral_force_rpa_renew = 0x4004b980 ); -PROVIDE ( r_lld_util_set_bd_address = 0x4004b8f8 ); -PROVIDE ( r_lld_wlcoex_set = 0x4004bd98 ); -PROVIDE ( r_llm_ble_ready = 0x4004cc34 ); -PROVIDE ( r_llm_common_cmd_complete_send = 0x4004d288 ); -PROVIDE ( r_llm_common_cmd_status_send = 0x4004d2b4 ); -PROVIDE ( r_llm_con_req_ind = 0x4004cc54 ); -PROVIDE ( r_llm_con_req_tx_cfm = 0x4004d158 ); -PROVIDE ( r_llm_create_con = 0x4004de78 ); -PROVIDE ( r_llm_encryption_done = 0x4004dff8 ); -PROVIDE ( r_llm_encryption_start = 0x4004e128 ); -PROVIDE ( r_llm_end_evt_defer = 0x4004eb6c ); -PROVIDE ( r_llm_init = 0x4004c9f8 ); -PROVIDE ( r_llm_le_adv_report_ind = 0x4004cdf4 ); -PROVIDE ( r_llm_pdu_defer = 0x4004ec48 ); -PROVIDE ( r_llm_ral_clear = 0x4004e1fc ); -PROVIDE ( r_llm_ral_dev_add = 0x4004e23c ); -PROVIDE ( r_llm_ral_dev_rm = 0x4004e3bc ); -PROVIDE ( r_llm_ral_get_rpa = 0x4004e400 ); -PROVIDE ( r_llm_ral_set_timeout = 0x4004e4a0 ); -PROVIDE ( r_llm_ral_update = 0x4004e4f8 ); -PROVIDE ( r_llm_set_adv_data = 0x4004d960 ); -PROVIDE ( r_llm_set_adv_en = 0x4004d7ec ); -PROVIDE ( r_llm_set_adv_param = 0x4004d5f4 ); -PROVIDE ( r_llm_set_scan_en = 0x4004db64 ); -PROVIDE ( r_llm_set_scan_param = 0x4004dac8 ); -PROVIDE ( r_llm_set_scan_rsp_data = 0x4004da14 ); -PROVIDE ( r_llm_test_mode_start_rx = 0x4004d534 ); -PROVIDE ( r_llm_test_mode_start_tx = 0x4004d2fc ); -PROVIDE ( r_llm_util_adv_data_update = 0x4004e8fc ); -PROVIDE ( r_llm_util_apply_bd_addr = 0x4004e868 ); -PROVIDE ( r_llm_util_bd_addr_in_ral = 0x4004eb08 ); -PROVIDE ( r_llm_util_bd_addr_in_wl = 0x4004e788 ); -PROVIDE ( r_llm_util_bd_addr_wl_position = 0x4004e720 ); -PROVIDE ( r_llm_util_bl_add = 0x4004e9ac ); -PROVIDE ( r_llm_util_bl_check = 0x4004e930 ); -PROVIDE ( r_llm_util_bl_rem = 0x4004ea70 ); -PROVIDE ( r_llm_util_check_address_validity = 0x4004e7e4 ); -PROVIDE ( r_llm_util_check_evt_mask = 0x4004e8b0 ); -PROVIDE ( r_llm_util_check_map_validity = 0x4004e800 ); -PROVIDE ( r_llm_util_get_channel_map = 0x4004e8d4 ); -PROVIDE ( r_llm_util_get_supp_features = 0x4004e8e8 ); -PROVIDE ( r_llm_util_set_public_addr = 0x4004e89c ); -PROVIDE ( r_llm_wl_clr = 0x4004dc54 ); -PROVIDE ( r_llm_wl_dev_add = 0x4004dcc0 ); -PROVIDE ( r_llm_wl_dev_add_hdl = 0x4004dd38 ); -PROVIDE ( r_llm_wl_dev_rem = 0x4004dcfc ); -PROVIDE ( r_llm_wl_dev_rem_hdl = 0x4004dde0 ); -PROVIDE ( r_lm_acl_disc = 0x4004f148 ); -PROVIDE ( r_LM_AddSniff = 0x40022d20 ); -PROVIDE ( r_lm_add_sync = 0x40051358 ); -PROVIDE ( r_lm_afh_activate_timer = 0x4004f444 ); -PROVIDE ( r_lm_afh_ch_ass_en_get = 0x4004f3f8 ); -PROVIDE ( r_lm_afh_host_ch_class_get = 0x4004f410 ); -PROVIDE ( r_lm_afh_master_ch_map_get = 0x4004f43c ); -PROVIDE ( r_lm_afh_peer_ch_class_set = 0x4004f418 ); -PROVIDE ( r_lm_check_active_sync = 0x40051334 ); -PROVIDE ( r_LM_CheckEdrFeatureRequest = 0x4002f90c ); -PROVIDE ( r_LM_CheckSwitchInstant = 0x4002f8c0 ); -PROVIDE ( r_lm_check_sync_hl_rsp = 0x4005169c ); -PROVIDE ( r_lm_clk_adj_ack_pending_clear = 0x4004f514 ); -PROVIDE ( r_lm_clk_adj_instant_pending_set = 0x4004f4d8 ); -PROVIDE ( r_LM_ComputePacketType = 0x4002f554 ); -PROVIDE ( r_LM_ComputeSniffSubRate = 0x400233ac ); -PROVIDE ( r_lm_debug_key_compare_192 = 0x4004f3a8 ); -PROVIDE ( r_lm_debug_key_compare_256 = 0x4004f3d0 ); -PROVIDE ( r_lm_dhkey_calc_init = 0x40013234 ); -PROVIDE ( r_lm_dhkey_compare = 0x400132d8 ); -PROVIDE ( r_lm_dut_mode_en_get = 0x4004f3ec ); -PROVIDE ( r_LM_ExtractMaxEncKeySize = 0x4001aca4 ); -PROVIDE ( r_lm_f1 = 0x40012bb8 ); -PROVIDE ( r_lm_f2 = 0x40012cfc ); -PROVIDE ( r_lm_f3 = 0x40013050 ); -PROVIDE ( r_lm_g = 0x40012f90 ); -PROVIDE ( r_LM_GetAFHSwitchInstant = 0x4002f86c ); -PROVIDE ( r_lm_get_auth_en = 0x4004f1ac ); -PROVIDE ( r_lm_get_common_pkt_types = 0x4002fa1c ); -PROVIDE ( r_LM_GetConnectionAcceptTimeout = 0x4004f1f4 ); -PROVIDE ( r_LM_GetFeature = 0x4002f924 ); -PROVIDE ( r_LM_GetLinkTimeout = 0x400233ec ); -PROVIDE ( r_LM_GetLocalNameSeg = 0x4004f200 ); -PROVIDE ( r_lm_get_loopback_mode = 0x4004f248 ); -PROVIDE ( r_LM_GetMasterEncKeySize = 0x4001b29c ); -PROVIDE ( r_LM_GetMasterEncRand = 0x4001b288 ); -PROVIDE ( r_LM_GetMasterKey = 0x4001b260 ); -PROVIDE ( r_LM_GetMasterKeyRand = 0x4001b274 ); -PROVIDE ( r_lm_get_min_sync_intv = 0x400517a8 ); -PROVIDE ( r_lm_get_nb_acl = 0x4004ef9c ); -PROVIDE ( r_lm_get_nb_sync_link = 0x4005179c ); -PROVIDE ( r_lm_get_nonce = 0x400131c4 ); -PROVIDE ( r_lm_get_oob_local_commit = 0x4004f374 ); -PROVIDE ( r_lm_get_oob_local_data_192 = 0x4004f2d4 ); -PROVIDE ( r_lm_get_oob_local_data_256 = 0x4004f318 ); -PROVIDE ( r_LM_GetPINType = 0x4004f1e8 ); -PROVIDE ( r_lm_get_priv_key_192 = 0x4004f278 ); -PROVIDE ( r_lm_get_priv_key_256 = 0x4004f2b8 ); -PROVIDE ( r_lm_get_pub_key_192 = 0x4004f258 ); -PROVIDE ( r_lm_get_pub_key_256 = 0x4004f298 ); -PROVIDE ( r_LM_GetQoSParam = 0x4002f6e0 ); -PROVIDE ( r_lm_get_sec_con_host_supp = 0x4004f1d4 ); -PROVIDE ( r_LM_GetSniffSubratingParam = 0x4002325c ); -PROVIDE ( r_lm_get_sp_en = 0x4004f1c0 ); -PROVIDE ( r_LM_GetSwitchInstant = 0x4002f7f8 ); -PROVIDE ( r_lm_get_synchdl = 0x4005175c ); -PROVIDE ( r_lm_get_sync_param = 0x400503b4 ); -PROVIDE ( r_lm_init = 0x4004ed34 ); -PROVIDE ( r_lm_init_sync = 0x400512d8 ); -PROVIDE ( r_lm_is_acl_con = 0x4004f47c ); -PROVIDE ( r_lm_is_acl_con_role = 0x4004f49c ); -PROVIDE ( r_lm_is_clk_adj_ack_pending = 0x4004f4e8 ); -PROVIDE ( r_lm_is_clk_adj_instant_pending = 0x4004f4c8 ); -PROVIDE ( r_lm_local_ext_fr_configured = 0x4004f540 ); -PROVIDE ( r_lm_look_for_stored_link_key = 0x4002f948 ); -PROVIDE ( r_lm_look_for_sync = 0x40051774 ); -PROVIDE ( r_lm_lt_addr_alloc = 0x4004ef1c ); -PROVIDE ( r_lm_lt_addr_free = 0x4004ef74 ); -PROVIDE ( r_lm_lt_addr_reserve = 0x4004ef48 ); -PROVIDE ( r_LM_MakeCof = 0x4002f84c ); -PROVIDE ( r_LM_MakeRandVec = 0x400112d8 ); -PROVIDE ( r_lm_master_clk_adj_req_handler = 0x40054180 ); -PROVIDE ( r_LM_MaxSlot = 0x4002f694 ); -PROVIDE ( r_lm_modif_sync = 0x40051578 ); -PROVIDE ( r_lm_n_is_zero = 0x40012170 ); -PROVIDE ( r_lm_num_clk_adj_ack_pending_set = 0x4004f500 ); -PROVIDE ( r_lm_oob_f1 = 0x40012e54 ); -PROVIDE ( r_lm_pca_sscan_link_get = 0x4004f560 ); -PROVIDE ( r_lm_pca_sscan_link_set = 0x4004f550 ); -PROVIDE ( r_lmp_pack = 0x4001135c ); -PROVIDE ( r_lmp_unpack = 0x4001149c ); -PROVIDE ( r_lm_read_features = 0x4004f0d8 ); -PROVIDE ( r_LM_RemoveSniff = 0x40023124 ); -PROVIDE ( r_LM_RemoveSniffSubrating = 0x400233c4 ); -PROVIDE ( r_lm_remove_sync = 0x400517c8 ); -PROVIDE ( r_lm_reset_sync = 0x40051304 ); -PROVIDE ( r_lm_role_switch_finished = 0x4004f028 ); -PROVIDE ( r_lm_role_switch_start = 0x4004efe0 ); -PROVIDE ( r_lm_sco_nego_end = 0x40051828 ); -PROVIDE ( r_LM_SniffSubrateNegoRequired = 0x40023334 ); -PROVIDE ( r_LM_SniffSubratingHlReq = 0x40023154 ); -PROVIDE ( r_LM_SniffSubratingPeerReq = 0x400231dc ); -PROVIDE ( r_lm_sp_debug_mode_get = 0x4004f398 ); -PROVIDE ( r_lm_sp_n192_convert_wnaf = 0x400123c0 ); -PROVIDE ( r_lm_sp_n_one = 0x400123a4 ); -PROVIDE ( r_lm_sp_p192_add = 0x40012828 ); -PROVIDE ( r_lm_sp_p192_dbl = 0x4001268c ); -PROVIDE ( r_lm_sp_p192_invert = 0x40012b6c ); -PROVIDE ( r_lm_sp_p192_point_jacobian_to_affine = 0x40012468 ); -PROVIDE ( r_lm_sp_p192_points_jacobian_to_affine = 0x400124e4 ); -PROVIDE ( r_lm_sp_p192_point_to_inf = 0x40012458 ); -PROVIDE ( r_lm_sp_pre_compute_points = 0x40012640 ); -PROVIDE ( r_lm_sp_sha256_calculate = 0x400121a0 ); -PROVIDE ( r_LM_SuppressAclPacket = 0x4002f658 ); -PROVIDE ( r_lm_sync_flow_ctrl_en_get = 0x4004f404 ); -PROVIDE ( r_LM_UpdateAclEdrPacketType = 0x4002f5d8 ); -PROVIDE ( r_LM_UpdateAclPacketType = 0x4002f584 ); -PROVIDE ( r_modules_funcs = 0x3ffafd6c ); -PROVIDE ( r_modules_funcs_p = 0x3ffafd68 ); -PROVIDE ( r_nvds_del = 0x400544c4 ); -PROVIDE ( r_nvds_get = 0x40054488 ); -PROVIDE ( r_nvds_init = 0x40054410 ); -PROVIDE ( r_nvds_lock = 0x400544fc ); -PROVIDE ( r_nvds_put = 0x40054534 ); -PROVIDE ( rom_abs_temp = 0x400054f0 ); -PROVIDE ( rom_bb_bss_bw_40_en = 0x4000401c ); -PROVIDE ( rom_bb_bss_cbw40_dig = 0x40003bac ); -PROVIDE ( rom_bb_rx_ht20_cen_bcov_en = 0x40003734 ); -PROVIDE ( rom_bb_tx_ht20_cen = 0x40003760 ); -PROVIDE ( rom_bb_wdg_test_en = 0x40003b70 ); -PROVIDE ( rom_cbw2040_cfg = 0x400040b0 ); -PROVIDE ( rom_check_noise_floor = 0x40003c78 ); -PROVIDE ( rom_chip_i2c_readReg = 0x40004110 ); -PROVIDE ( rom_chip_i2c_writeReg = 0x40004168 ); -PROVIDE ( rom_chip_v7_bt_init = 0x40004d8c ); -PROVIDE ( rom_chip_v7_rx_init = 0x40004cec ); -PROVIDE ( rom_chip_v7_rx_rifs_en = 0x40003d90 ); -PROVIDE ( rom_chip_v7_tx_init = 0x40004d18 ); -PROVIDE ( rom_clk_force_on_vit = 0x40003710 ); -PROVIDE ( rom_correct_rf_ana_gain = 0x400062a8 ); -PROVIDE ( rom_dc_iq_est = 0x400055c8 ); -PROVIDE ( rom_disable_agc = 0x40002fa4 ); -PROVIDE ( rom_enable_agc = 0x40002fcc ); -PROVIDE ( rom_en_pwdet = 0x4000506c ); -PROVIDE ( rom_gen_rx_gain_table = 0x40003e3c ); -PROVIDE ( rom_get_data_sat = 0x4000312c ); -PROVIDE ( rom_get_fm_sar_dout = 0x40005204 ); -PROVIDE ( rom_get_power_db = 0x40005fc8 ); -PROVIDE ( rom_get_pwctrl_correct = 0x400065d4 ); -PROVIDE ( rom_get_rfcal_rxiq_data = 0x40005bbc ); -PROVIDE ( rom_get_rf_gain_qdb = 0x40006290 ); -PROVIDE ( rom_get_sar_dout = 0x40006564 ); -PROVIDE ( rom_i2c_readReg = 0x40004148 ); -PROVIDE ( rom_i2c_readReg_Mask = 0x400041c0 ); -PROVIDE ( rom_i2c_writeReg = 0x400041a4 ); -PROVIDE ( rom_i2c_writeReg_Mask = 0x400041fc ); -PROVIDE ( rom_index_to_txbbgain = 0x40004df8 ); -PROVIDE ( rom_iq_est_disable = 0x40005590 ); -PROVIDE ( rom_iq_est_enable = 0x40005514 ); -PROVIDE ( rom_linear_to_db = 0x40005f64 ); -PROVIDE ( rom_loopback_mode_en = 0x400030f8 ); -PROVIDE ( rom_main = 0x400076c4 ); -PROVIDE ( rom_meas_tone_pwr_db = 0x40006004 ); -PROVIDE ( rom_mhz2ieee = 0x4000404c ); -PROVIDE ( rom_noise_floor_auto_set = 0x40003bdc ); -PROVIDE ( rom_pbus_debugmode = 0x40004458 ); -PROVIDE ( rom_pbus_force_mode = 0x40004270 ); -PROVIDE ( rom_pbus_force_test = 0x400043c0 ); -PROVIDE ( rom_pbus_rd = 0x40004414 ); -PROVIDE ( rom_pbus_rd_addr = 0x40004334 ); -PROVIDE ( rom_pbus_rd_shift = 0x40004374 ); -PROVIDE ( rom_pbus_rx_dco_cal = 0x40005620 ); -PROVIDE ( rom_pbus_set_dco = 0x40004638 ); -PROVIDE ( rom_pbus_set_rxgain = 0x40004480 ); -PROVIDE ( rom_pbus_workmode = 0x4000446c ); -PROVIDE ( rom_pbus_xpd_rx_off = 0x40004508 ); -PROVIDE ( rom_pbus_xpd_rx_on = 0x4000453c ); -PROVIDE ( rom_pbus_xpd_tx_off = 0x40004590 ); -PROVIDE ( rom_pbus_xpd_tx_on = 0x400045e0 ); -PROVIDE ( rom_phy_disable_agc = 0x40002f6c ); -PROVIDE ( rom_phy_disable_cca = 0x40003000 ); -PROVIDE ( rom_phy_enable_agc = 0x40002f88 ); -PROVIDE ( rom_phy_enable_cca = 0x4000302c ); -PROVIDE ( rom_phy_freq_correct = 0x40004b44 ); -PROVIDE ( rom_phyFuns = 0x3ffae0c0 ); -PROVIDE ( rom_phy_get_noisefloor = 0x40003c2c ); -PROVIDE ( rom_phy_get_vdd33 = 0x4000642c ); -PROVIDE ( rom_pow_usr = 0x40003044 ); -PROVIDE ( rom_read_sar_dout = 0x400051c0 ); -PROVIDE ( rom_restart_cal = 0x400046e0 ); -PROVIDE ( rom_rfcal_pwrctrl = 0x40006058 ); -PROVIDE ( rom_rfcal_rxiq = 0x40005b4c ); -PROVIDE ( rom_rfcal_txcap = 0x40005dec ); -PROVIDE ( rom_rfpll_reset = 0x40004680 ); -PROVIDE ( rom_rfpll_set_freq = 0x400047f8 ); -PROVIDE ( rom_rtc_mem_backup = 0x40003db4 ); -PROVIDE ( rom_rtc_mem_recovery = 0x40003df4 ); -PROVIDE ( rom_rx_gain_force = 0x4000351c ); -PROVIDE ( rom_rxiq_cover_mg_mp = 0x40005a68 ); -PROVIDE ( rom_rxiq_get_mis = 0x400058e4 ); -PROVIDE ( rom_rxiq_set_reg = 0x40005a00 ); -PROVIDE ( rom_set_cal_rxdc = 0x400030b8 ); -PROVIDE ( rom_set_chan_cal_interp = 0x40005ce0 ); -PROVIDE ( rom_set_channel_freq = 0x40004880 ); -PROVIDE ( rom_set_loopback_gain = 0x40003060 ); -PROVIDE ( rom_set_noise_floor = 0x40003d48 ); -PROVIDE ( rom_set_pbus_mem = 0x400031a4 ); -PROVIDE ( rom_set_rf_freq_offset = 0x40004ca8 ); -PROVIDE ( rom_set_rxclk_en = 0x40003594 ); -PROVIDE ( rom_set_txcap_reg = 0x40005d50 ); -PROVIDE ( rom_set_txclk_en = 0x40003564 ); -PROVIDE ( rom_spur_coef_cfg = 0x40003ac8 ); -PROVIDE ( rom_spur_reg_write_one_tone = 0x400037f0 ); -PROVIDE ( rom_start_tx_tone = 0x400036b4 ); -PROVIDE ( rom_start_tx_tone_step = 0x400035d0 ); -PROVIDE ( rom_stop_tx_tone = 0x40003f98 ); -PROVIDE ( _rom_store = 0x4000d66c ); -PROVIDE ( _rom_store_table = 0x4000d4f8 ); -PROVIDE ( rom_target_power_add_backoff = 0x40006268 ); -PROVIDE ( rom_tx_atten_set_interp = 0x400061cc ); -PROVIDE ( rom_txbbgain_to_index = 0x40004dc0 ); -PROVIDE ( rom_txcal_work_mode = 0x4000510c ); -PROVIDE ( rom_txdc_cal_init = 0x40004e10 ); -PROVIDE ( rom_txdc_cal_v70 = 0x40004ea4 ); -PROVIDE ( rom_txiq_cover = 0x4000538c ); -PROVIDE ( rom_txiq_get_mis_pwr = 0x400052dc ); -PROVIDE ( rom_txiq_set_reg = 0x40005154 ); -PROVIDE ( rom_tx_pwctrl_bg_init = 0x4000662c ); -PROVIDE ( rom_txtone_linear_pwr = 0x40005290 ); -PROVIDE ( rom_wait_rfpll_cal_end = 0x400047a8 ); -PROVIDE ( rom_write_gain_mem = 0x4000348c ); -PROVIDE ( rom_write_rfpll_sdm = 0x40004740 ); -PROVIDE ( roundup2 = 0x4000ab7c ); -PROVIDE ( r_plf_funcs_p = 0x3ffb8360 ); -PROVIDE ( r_rf_rw_bt_init = 0x40054868 ); -PROVIDE ( r_rf_rw_init = 0x40054b0c ); -PROVIDE ( r_rf_rw_le_init = 0x400549d0 ); -PROVIDE ( r_rwble_activity_ongoing_check = 0x40054d8c ); -PROVIDE ( r_rwble_init = 0x40054bf4 ); -PROVIDE ( r_rwble_isr = 0x40054e08 ); -PROVIDE ( r_rwble_reset = 0x40054ce8 ); -PROVIDE ( r_rwble_sleep_check = 0x40054d78 ); -PROVIDE ( r_rwble_version = 0x40054dac ); -PROVIDE ( r_rwbt_init = 0x40055160 ); -PROVIDE ( r_rwbt_isr = 0x40055248 ); -PROVIDE ( r_rwbt_reset = 0x400551bc ); -PROVIDE ( r_rwbt_sleep_check = 0x4005577c ); -PROVIDE ( r_rwbt_sleep_enter = 0x400557a4 ); -PROVIDE ( r_rwbt_sleep_wakeup = 0x400557fc ); -PROVIDE ( r_rwbt_sleep_wakeup_end = 0x400558cc ); -PROVIDE ( r_rwbt_version = 0x4005520c ); -PROVIDE ( r_rwip_assert_err = 0x40055f88 ); -PROVIDE ( r_rwip_check_wakeup_boundary = 0x400558fc ); -PROVIDE ( r_rwip_ext_wakeup_enable = 0x40055f3c ); -PROVIDE ( r_rwip_init = 0x4005595c ); -PROVIDE ( r_rwip_pca_clock_dragging_only = 0x40055f48 ); -PROVIDE ( r_rwip_prevent_sleep_clear = 0x40055ec8 ); -PROVIDE ( r_rwip_prevent_sleep_set = 0x40055e64 ); -PROVIDE ( r_rwip_reset = 0x40055ab8 ); -PROVIDE ( r_rwip_schedule = 0x40055b38 ); -PROVIDE ( r_rwip_sleep = 0x40055b5c ); -PROVIDE ( r_rwip_sleep_enable = 0x40055f30 ); -PROVIDE ( r_rwip_version = 0x40055b20 ); -PROVIDE ( r_rwip_wakeup = 0x40055dc4 ); -PROVIDE ( r_rwip_wakeup_delay_set = 0x40055e4c ); -PROVIDE ( r_rwip_wakeup_end = 0x40055e18 ); -PROVIDE ( r_rwip_wlcoex_set = 0x40055f60 ); -PROVIDE ( r_SHA_256 = 0x40013a90 ); -PROVIDE ( rtc_boot_control = 0x4000821c ); -PROVIDE ( rtc_get_reset_reason = 0x400081d4 ); -PROVIDE ( rtc_get_wakeup_cause = 0x400081f4 ); -PROVIDE ( rtc_select_apb_bridge = 0x40008288 ); -PROVIDE ( rwip_coex_cfg = 0x3ff9914c ); -PROVIDE ( rwip_priority = 0x3ff99159 ); -PROVIDE ( rwip_rf = 0x3ffbdb28 ); -PROVIDE ( rwip_rf_p_get = 0x400558f4 ); -PROVIDE ( r_XorKey = 0x400112c0 ); -PROVIDE ( sbrk = 0x400017f4 ); -PROVIDE ( _sbrk_r = 0x4000bce4 ); -PROVIDE ( __sccl = 0x4000c498 ); -PROVIDE ( __sclose = 0x400011b8 ); -PROVIDE ( SelectSpiFunction = 0x40061f84 ); -PROVIDE ( SelectSpiQIO = 0x40061ddc ); -PROVIDE ( SendMsg = 0x40009384 ); -PROVIDE ( send_packet = 0x40009340 ); -PROVIDE ( __seofread = 0x40001148 ); -PROVIDE ( setjmp = 0x40056268 ); -PROVIDE ( setlocale = 0x40059568 ); -PROVIDE ( _setlocale_r = 0x4005950c ); -PROVIDE ( set_rtc_memory_crc = 0x40008208 ); -PROVIDE ( SetSpiDrvs = 0x40061e78 ); -PROVIDE ( __sf_fake_stderr = 0x3ff96458 ); -PROVIDE ( __sf_fake_stdin = 0x3ff96498 ); -PROVIDE ( __sf_fake_stdout = 0x3ff96478 ); -PROVIDE ( __sflush_r = 0x400591e0 ); -PROVIDE ( __sfmoreglue = 0x40001dc8 ); -PROVIDE ( __sfp = 0x40001e90 ); -PROVIDE ( __sfp_lock_acquire = 0x40001e08 ); -PROVIDE ( __sfp_lock_release = 0x40001e14 ); -PROVIDE ( __sfputs_r = 0x40057790 ); -PROVIDE ( __sfvwrite_r = 0x4005893c ); -PROVIDE ( sha1_prf = 0x40060ae8 ); -PROVIDE ( sha1_vector = 0x40060b64 ); -PROVIDE ( sha256_prf = 0x40060d70 ); -PROVIDE ( sha256_vector = 0x40060e08 ); -PROVIDE ( sha_blk_bits = 0x3ff99290 ); -PROVIDE ( sha_blk_bits_bytes = 0x3ff99288 ); -PROVIDE ( sha_blk_hash_bytes = 0x3ff9928c ); -PROVIDE ( sig_matrix = 0x3ffae293 ); -PROVIDE ( __sinit = 0x40001e38 ); -PROVIDE ( __sinit_lock_acquire = 0x40001e20 ); -PROVIDE ( __sinit_lock_release = 0x40001e2c ); -PROVIDE ( sip_after_tx_complete = 0x4000b358 ); -PROVIDE ( sip_alloc_to_host_evt = 0x4000ab9c ); -PROVIDE ( sip_get_ptr = 0x4000b34c ); -PROVIDE ( sip_get_state = 0x4000ae2c ); -PROVIDE ( sip_init_attach = 0x4000ae58 ); -PROVIDE ( sip_install_rx_ctrl_cb = 0x4000ae10 ); -PROVIDE ( sip_install_rx_data_cb = 0x4000ae20 ); -PROVIDE ( sip_is_active = 0x4000b3c0 ); -PROVIDE ( sip_post_init = 0x4000aed8 ); -PROVIDE ( sip_reclaim_from_host_cmd = 0x4000adbc ); -PROVIDE ( sip_reclaim_tx_data_pkt = 0x4000ad5c ); -PROVIDE ( sip_send = 0x4000af54 ); -PROVIDE ( sip_to_host_chain_append = 0x4000aef8 ); -PROVIDE ( sip_to_host_evt_send_done = 0x4000ac04 ); -PROVIDE ( slc_add_credits = 0x4000baf4 ); -PROVIDE ( slc_enable = 0x4000b64c ); -PROVIDE ( slc_from_host_chain_fetch = 0x4000b7e8 ); -PROVIDE ( slc_from_host_chain_recycle = 0x4000bb10 ); -PROVIDE ( slc_has_pkt_to_host = 0x4000b5fc ); -PROVIDE ( slc_init_attach = 0x4000b918 ); -PROVIDE ( slc_init_credit = 0x4000badc ); -PROVIDE ( slc_reattach = 0x4000b62c ); -PROVIDE ( slc_send_to_host_chain = 0x4000b6a0 ); -PROVIDE ( slc_set_host_io_max_window = 0x4000b89c ); -PROVIDE ( slc_to_host_chain_recycle = 0x4000b758 ); -PROVIDE ( __smakebuf_r = 0x40059108 ); -PROVIDE ( software_reset = 0x4000824c ); -PROVIDE ( software_reset_cpu = 0x40008264 ); -PROVIDE ( specialModP256 = 0x4001600c ); -PROVIDE ( spi_cache_sram_init = 0x400626e4 ); -PROVIDE ( SPIClkConfig = 0x40062bc8 ); -PROVIDE ( SPI_Common_Command = 0x4006246c ); -PROVIDE ( spi_dummy_len_fix = 0x40061d90 ); -PROVIDE ( SPI_Encrypt_Write = 0x40062e78 ); -PROVIDE ( SPIEraseArea = 0x400631ac ); -PROVIDE ( SPIEraseBlock = 0x40062c4c ); -PROVIDE ( SPIEraseChip = 0x40062c14 ); -PROVIDE ( SPIEraseSector = 0x40062ccc ); -PROVIDE ( spi_flash_attach = 0x40062a6c ); -/* NB: SPIUnlock @ 0x400628b0 has been replaced with an updated - version in the "spi_flash" component */ -PROVIDE ( SPILock = 0x400628f0 ); -PROVIDE ( SPIMasterReadModeCnfig = 0x40062b64 ); -PROVIDE ( spi_modes = 0x3ff99270 ); -PROVIDE ( SPIParamCfg = 0x40063238 ); -PROVIDE ( SPI_Prepare_Encrypt_Data = 0x40062e1c ); -PROVIDE ( SPIRead = 0x40062ed8 ); -PROVIDE ( SPIReadModeCnfig = 0x40062944 ); -/* This is static function, but can be used, not generated by script*/ -PROVIDE ( SPI_read_status = 0x4006226c ); -/* This is static function, but can be used, not generated by script*/ -PROVIDE ( SPI_read_status_high = 0x40062448 ); -PROVIDE ( SPI_user_command_read = 0x400621b0 ); -PROVIDE ( SPI_flashchip_data = 0x3ffae270 ); -PROVIDE ( SPIWrite = 0x40062d50 ); -/* This is static function, but can be used, not generated by script*/ -PROVIDE ( SPI_write_enable = 0x40062320 ); -PROVIDE ( SPI_Write_Encrypt_Disable = 0x40062e60 ); -PROVIDE ( SPI_Write_Encrypt_Enable = 0x40062df4 ); -/* This is static function, but can be used, not generated by script*/ -PROVIDE ( SPI_write_status = 0x400622f0 ); -PROVIDE ( srand = 0x40001004 ); -PROVIDE ( __sread = 0x40001118 ); -PROVIDE ( __srefill_r = 0x400593d4 ); -PROVIDE ( __sseek = 0x40001184 ); -PROVIDE ( __ssprint_r = 0x40056ff8 ); -PROVIDE ( __ssputs_r = 0x40056f2c ); -PROVIDE ( __ssrefill_r = 0x40057fec ); -PROVIDE ( __stack = 0x3ffe3f20 ); -PROVIDE ( __stack_app = 0x3ffe7e30 ); -PROVIDE ( _stack_sentry = 0x3ffe1320 ); -PROVIDE ( _stack_sentry_app = 0x3ffe5230 ); -PROVIDE ( _start = 0x40000704 ); -PROVIDE ( start_tb_console = 0x4005a980 ); -PROVIDE ( _stat_r = 0x4000bcb4 ); -PROVIDE ( _stext = 0x40000560 ); -PROVIDE ( strcasecmp = 0x400011cc ); -PROVIDE ( strcasestr = 0x40001210 ); -PROVIDE ( strcat = 0x4000c518 ); -PROVIDE ( strchr = 0x4000c53c ); -PROVIDE ( strcmp = 0x40001274 ); -PROVIDE ( strcoll = 0x40001398 ); -PROVIDE ( strcpy = 0x400013ac ); -PROVIDE ( strcspn = 0x4000c558 ); -PROVIDE ( strdup = 0x4000143c ); -PROVIDE ( _strdup_r = 0x40001450 ); -PROVIDE ( strftime = 0x40059ab4 ); -PROVIDE ( strlcat = 0x40001470 ); -PROVIDE ( strlcpy = 0x4000c584 ); -PROVIDE ( strlen = 0x400014c0 ); -PROVIDE ( strlwr = 0x40001524 ); -PROVIDE ( strncasecmp = 0x40001550 ); -PROVIDE ( strncat = 0x4000c5c4 ); -PROVIDE ( strncmp = 0x4000c5f4 ); -PROVIDE ( strncpy = 0x400015d4 ); -PROVIDE ( strndup = 0x400016b0 ); -PROVIDE ( _strndup_r = 0x400016c4 ); -PROVIDE ( strnlen = 0x4000c628 ); -PROVIDE ( strrchr = 0x40001708 ); -PROVIDE ( strsep = 0x40001734 ); -PROVIDE ( strspn = 0x4000c648 ); -PROVIDE ( strstr = 0x4000c674 ); -PROVIDE ( __strtok_r = 0x4000c6a8 ); -PROVIDE ( strtok_r = 0x4000c70c ); -PROVIDE ( strtol = 0x4005681c ); -PROVIDE ( _strtol_r = 0x40056714 ); -PROVIDE ( strtoul = 0x4005692c ); -PROVIDE ( _strtoul_r = 0x40056834 ); -PROVIDE ( strupr = 0x4000174c ); -PROVIDE ( __subdf3 = 0x400026e4 ); -PROVIDE ( __submore = 0x40058f3c ); -PROVIDE ( __subsf3 = 0x400021d0 ); -PROVIDE ( SubtractBigHex256 = 0x40015bcc ); -PROVIDE ( SubtractBigHexMod256 = 0x40015e8c ); -PROVIDE ( SubtractBigHexUint32_256 = 0x40015f8c ); -PROVIDE ( SubtractFromSelfBigHex256 = 0x40015c20 ); -PROVIDE ( SubtractFromSelfBigHexSign256 = 0x40015dc8 ); -PROVIDE ( __subvdi3 = 0x40002d20 ); -PROVIDE ( __subvsi3 = 0x40002cf8 ); -PROVIDE ( _sungetc_r = 0x40057f6c ); -PROVIDE ( __swbuf = 0x40058cb4 ); -PROVIDE ( __swbuf_r = 0x40058bec ); -PROVIDE ( __swrite = 0x40001150 ); -PROVIDE ( __swsetup_r = 0x40058cc8 ); -PROVIDE ( sw_to_hw = 0x3ffb8d40 ); -PROVIDE ( _SyscallException = 0x400007cf ); -PROVIDE ( syscall_table_ptr_app = 0x3ffae020 ); -PROVIDE ( syscall_table_ptr_pro = 0x3ffae024 ); -PROVIDE ( _system_r = 0x4000bc10 ); -PROVIDE ( tdefl_compress = 0x400600bc ); -PROVIDE ( tdefl_compress_buffer = 0x400607f4 ); -PROVIDE ( tdefl_compress_mem_to_mem = 0x40060900 ); -PROVIDE ( tdefl_compress_mem_to_output = 0x400608e0 ); -PROVIDE ( tdefl_get_adler32 = 0x400608d8 ); -PROVIDE ( tdefl_get_prev_return_status = 0x400608d0 ); -PROVIDE ( tdefl_init = 0x40060810 ); -PROVIDE ( tdefl_write_image_to_png_file_in_memory = 0x4006091c ); -PROVIDE ( tdefl_write_image_to_png_file_in_memory_ex = 0x40060910 ); -PROVIDE ( time = 0x40001844 ); -PROVIDE ( __time_load_locale = 0x4000183c ); -PROVIDE ( times = 0x40001808 ); -PROVIDE ( _times_r = 0x4000bc40 ); -PROVIDE ( _timezone = 0x3ffae0a0 ); -PROVIDE ( tinfl_decompress = 0x4005ef30 ); -PROVIDE ( tinfl_decompress_mem_to_callback = 0x40060090 ); -PROVIDE ( tinfl_decompress_mem_to_mem = 0x40060050 ); -PROVIDE ( toascii = 0x4000c720 ); -PROVIDE ( tolower = 0x40001868 ); -PROVIDE ( toupper = 0x40001884 ); -PROVIDE ( __truncdfsf2 = 0x40002b90 ); -PROVIDE ( __tzcalc_limits = 0x400018a0 ); -PROVIDE ( __tz_lock = 0x40001a04 ); -PROVIDE ( _tzname = 0x3ffae030 ); -PROVIDE ( tzset = 0x40001a1c ); -PROVIDE ( _tzset_r = 0x40001a28 ); -PROVIDE ( __tz_unlock = 0x40001a10 ); -PROVIDE ( uartAttach = 0x40008fd0 ); -PROVIDE ( uart_baudrate_detect = 0x40009034 ); -PROVIDE ( uart_buff_switch = 0x400093c0 ); -PROVIDE ( UartConnCheck = 0x40008738 ); -PROVIDE ( UartConnectProc = 0x40008a04 ); -PROVIDE ( UartDev = 0x3ffe019c ); -PROVIDE ( uart_div_modify = 0x400090cc ); -PROVIDE ( UartDwnLdProc = 0x40008ce8 ); -PROVIDE ( UartGetCmdLn = 0x40009564 ); -PROVIDE ( Uart_Init = 0x40009120 ); -PROVIDE ( UartRegReadProc = 0x40008a58 ); -PROVIDE ( UartRegWriteProc = 0x40008a14 ); -PROVIDE ( uart_rx_intr_handler = 0x40008f4c ); -PROVIDE ( uart_rx_one_char = 0x400092d0 ); -PROVIDE ( uart_rx_one_char_block = 0x400092a4 ); -PROVIDE ( uart_rx_readbuff = 0x40009394 ); -PROVIDE ( UartRxString = 0x400092fc ); -PROVIDE ( UartSetBaudProc = 0x40008aac ); -PROVIDE ( UartSpiAttachProc = 0x40008a6c ); -PROVIDE ( UartSpiReadProc = 0x40008a80 ); -PROVIDE ( uart_tx_flush = 0x40009258 ); -/*PROVIDE ( uart_tx_one_char = 0x40009200 );*/ -/* Note: remapping this to uart_tx_one_char2, to keep consistency */ -PROVIDE ( uart_tx_one_char = 0x4000922c ); -PROVIDE ( uart_tx_one_char2 = 0x4000922c ); -PROVIDE ( uart_tx_switch = 0x40009028 ); -PROVIDE ( uart_tx_wait_idle = 0x40009278 ); -PROVIDE ( __ucmpdi2 = 0x40063840 ); -PROVIDE ( __udivdi3 = 0x4000cff8 ); -PROVIDE ( __udivmoddi4 = 0x40064ab0 ); -PROVIDE ( __udivsi3 = 0x4000c7c8 ); -PROVIDE ( __udiv_w_sdiv = 0x40064aa8 ); -PROVIDE ( __umoddi3 = 0x4000d280 ); -PROVIDE ( __umodsi3 = 0x4000c7d0 ); -PROVIDE ( __umulsidi3 = 0x4000c7d8 ); -PROVIDE ( ungetc = 0x400590f4 ); -PROVIDE ( _ungetc_r = 0x40058fa0 ); -PROVIDE ( _unlink_r = 0x4000bc84 ); -PROVIDE ( __unorddf2 = 0x400637f4 ); -PROVIDE ( __unordsf2 = 0x40063478 ); -PROVIDE ( user_code_start = 0x3ffe0400 ); -PROVIDE ( _UserExceptionVector = 0x40000340 ); -PROVIDE ( utoa = 0x40056258 ); -PROVIDE ( __utoa = 0x400561f0 ); -PROVIDE ( VerifyFlashMd5Proc = 0x40008c44 ); -PROVIDE ( veryBigHexP256 = 0x3ff9736c ); -PROVIDE ( wcrtomb = 0x40058920 ); -PROVIDE ( _wcrtomb_r = 0x400588d8 ); -PROVIDE ( __wctomb = 0x3ff96540 ); -PROVIDE ( _wctomb_r = 0x40058f14 ); -PROVIDE ( _WindowOverflow12 = 0x40000100 ); -PROVIDE ( _WindowOverflow4 = 0x40000000 ); -PROVIDE ( _WindowOverflow8 = 0x40000080 ); -PROVIDE ( _WindowUnderflow12 = 0x40000140 ); -PROVIDE ( _WindowUnderflow4 = 0x40000040 ); -PROVIDE ( _WindowUnderflow8 = 0x400000c0 ); -PROVIDE ( write = 0x4000181c ); -PROVIDE ( _write_r = 0x4000bd70 ); -PROVIDE ( xthal_bcopy = 0x4000c098 ); -PROVIDE ( xthal_copy123 = 0x4000c124 ); -PROVIDE ( xthal_get_ccompare = 0x4000c078 ); -PROVIDE ( xthal_get_ccount = 0x4000c050 ); -PROVIDE ( xthal_get_interrupt = 0x4000c1e4 ); -PROVIDE ( xthal_get_intread = 0x4000c1e4 ); -PROVIDE ( Xthal_intlevel = 0x3ff9c2b4 ); -PROVIDE ( xthal_memcpy = 0x4000c0bc ); -PROVIDE ( xthal_set_ccompare = 0x4000c058 ); -PROVIDE ( xthal_set_intclear = 0x4000c1ec ); -PROVIDE ( _xtos_set_intlevel = 0x4000bfdc ); -PROVIDE ( _xtos_alloca_handler = 0x40000010 ); -PROVIDE ( _xtos_cause3_handler = 0x40000dd8 ); -PROVIDE ( _xtos_c_handler_table = 0x3ffe0548 ); -PROVIDE ( _xtos_c_wrapper_handler = 0x40000de8 ); -PROVIDE ( _xtos_enabled = 0x3ffe0650 ); -PROVIDE ( _xtos_exc_handler_table = 0x3ffe0448 ); -PROVIDE ( _xtos_interrupt_mask_table = 0x3ffe0758 ); -PROVIDE ( _xtos_interrupt_table = 0x3ffe0658 ); -PROVIDE ( _xtos_ints_off = 0x4000bfac ); -PROVIDE ( _xtos_ints_on = 0x4000bf88 ); -PROVIDE ( _xtos_intstruct = 0x3ffe0650 ); -PROVIDE ( _xtos_l1int_handler = 0x40000814 ); -PROVIDE ( _xtos_p_none = 0x4000bfd4 ); -PROVIDE ( _xtos_restore_intlevel = 0x40000928 ); -PROVIDE ( _xtos_return_from_exc = 0x4000c034 ); -PROVIDE ( _xtos_set_exception_handler = 0x4000074c ); -PROVIDE ( _xtos_set_interrupt_handler = 0x4000bf78 ); -PROVIDE ( _xtos_set_interrupt_handler_arg = 0x4000bf34 ); -PROVIDE ( _xtos_set_min_intlevel = 0x4000bff8 ); -PROVIDE ( _xtos_set_vpri = 0x40000934 ); -PROVIDE ( _xtos_syscall_handler = 0x40000790 ); -PROVIDE ( _xtos_unhandled_exception = 0x4000c024 ); -PROVIDE ( _xtos_unhandled_interrupt = 0x4000c01c ); -PROVIDE ( _xtos_vpri_enabled = 0x3ffe0654 ); -PROVIDE ( ets_intr_count = 0x3ffe03fc ); -PROVIDE ( ets_intr_lock = 0x400067b0 ); -PROVIDE ( ets_intr_unlock = 0x400067c4 ); -PROVIDE ( ets_isr_attach = 0x400067ec ); -PROVIDE ( ets_isr_mask = 0x400067fc ); -PROVIDE ( ets_isr_unmask = 0x40006808 ); -/* Following are static data, but can be used, not generated by script <<<<< btdm data */ -PROVIDE ( ld_acl_env = 0x3ffb8258 ); -PROVIDE ( ld_active_ch_map = 0x3ffb8334 ); -PROVIDE ( ld_bcst_acl_env = 0x3ffb8274 ); -PROVIDE ( ld_csb_rx_env = 0x3ffb8278 ); -PROVIDE ( ld_csb_tx_env = 0x3ffb827c ); -PROVIDE ( ld_env = 0x3ffb9510 ); -PROVIDE ( ld_fm_env = 0x3ffb8284 ); -PROVIDE ( ld_inq_env = 0x3ffb82e4 ); -PROVIDE ( ld_iscan_env = 0x3ffb82e8 ); -PROVIDE ( ld_page_env = 0x3ffb82f0 ); -PROVIDE ( ld_pca_env = 0x3ffb82f4 ); -PROVIDE ( ld_pscan_env = 0x3ffb8308 ); -PROVIDE ( ld_sched_env = 0x3ffb830c ); -PROVIDE ( ld_sched_params = 0x3ffb96c0 ); -PROVIDE ( ld_sco_env = 0x3ffb824c ); -PROVIDE ( ld_sscan_env = 0x3ffb832c ); -PROVIDE ( ld_strain_env = 0x3ffb8330 ); - - -PROVIDE ( esp_rom_spiflash_write_encrypted = 0x40062e78 ); -/* Above are static data, but can be used, not generated by script >>>>> btdm data */ diff --git a/tools/esptool_py/flasher_stub/ld/rom_32c2.ld b/tools/esptool_py/flasher_stub/ld/rom_32c2.ld deleted file mode 100755 index ae11364972..0000000000 --- a/tools/esptool_py/flasher_stub/ld/rom_32c2.ld +++ /dev/null @@ -1,2960 +0,0 @@ -/* ROM function interface esp32c2.rom.ld for esp32c2 - * - * - * Generated from ./interface-esp8684.yml md5sum 6c4d0f3a9f2d0c93477024a1a8f13746 - * - * Compatible with ROM where ECO version equal or greater to 0. - * - * THIS FILE WAS AUTOMATICALLY GENERATED. DO NOT EDIT. - */ - -/*************************************** - Group common - ***************************************/ - -PROVIDE ( SPIWrite = esp_rom_spiflash_write); -PROVIDE ( SPI_read_status_high = esp_rom_spiflash_read_statushigh); -PROVIDE ( SPI_write_status = esp_rom_spiflash_write_status); -PROVIDE ( SPIRead = esp_rom_spiflash_read); -PROVIDE ( SPIParamCfg = esp_rom_spiflash_config_param); -PROVIDE ( SPIEraseChip = esp_rom_spiflash_erase_chip); -PROVIDE ( SPIEraseSector = esp_rom_spiflash_erase_sector); -PROVIDE ( SPIEraseBlock = esp_rom_spiflash_erase_block); -PROVIDE ( SPI_Write_Encrypt_Enable = esp_rom_spiflash_write_encrypted_enable); -PROVIDE ( SPI_Write_Encrypt_Disable = esp_rom_spiflash_write_encrypted_disable); -PROVIDE ( SPI_Encrypt_Write = esp_rom_spiflash_write_encrypted); - -PROVIDE ( mbedtls_md5_starts_ret = mbedtls_md5_starts_ret ); -PROVIDE ( mbedtls_md5_update_ret = mbedtls_md5_update_ret ); -PROVIDE ( mbedtls_md5_finish_ret = mbedtls_md5_finish_ret ); - -/*************************************** - Group common - ***************************************/ - -/* Functions */ -rtc_get_reset_reason = 0x40000018; -analog_super_wdt_reset_happened = 0x4000001c; -rtc_get_wakeup_cause = 0x40000020; -rtc_select_apb_bridge = 0x40000024; -rtc_unhold_all_pads = 0x40000028; -ets_is_print_boot = 0x4000002c; -ets_vprintf = 0x40000030; -ets_printf = 0x40000034; -ets_install_putc1 = 0x40000038; -ets_install_uart_printf = 0x4000003c; -ets_install_putc2 = 0x40000040; -PROVIDE( ets_delay_us = 0x40000044 ); -ets_get_stack_info = 0x40000048; -ets_install_lock = 0x4000004c; -UartRxString = 0x40000050; -UartGetCmdLn = 0x40000054; -uart_tx_one_char = 0x40000058; -uart_tx_one_char2 = 0x4000005c; -uart_rx_one_char = 0x40000060; -uart_rx_one_char_block = 0x40000064; -uart_rx_readbuff = 0x40000068; -uartAttach = 0x4000006c; -uart_tx_flush = 0x40000070; -uart_tx_wait_idle = 0x40000074; -uart_div_modify = 0x40000078; -ets_write_char_uart = 0x4000007c; -uart_tx_switch = 0x40000080; -multofup = 0x40000084; -software_reset = 0x40000088; -software_reset_cpu = 0x4000008c; -assist_debug_clock_enable = 0x40000090; -assist_debug_record_enable = 0x40000094; -clear_super_wdt_reset_flag = 0x40000098; -disable_default_watchdog = 0x4000009c; -send_packet = 0x400000a0; -recv_packet = 0x400000a4; -GetUartDevice = 0x400000a8; -UartDwnLdProc = 0x400000ac; -GetSecurityInfoProc = 0x400000b0; -Uart_Init = 0x400000b4; -ets_set_user_start = 0x400000b8; -/* Data (.data, .bss, .rodata) */ -ets_rom_layout_p = 0x3ff4fffc; -ets_ops_table_ptr = 0x3fcdfffc; - - -/*************************************** - Group miniz - ***************************************/ - -/* Functions */ -mz_adler32 = 0x400000bc; -mz_free = 0x400000c0; -tdefl_compress = 0x400000c4; -tdefl_compress_buffer = 0x400000c8; -tdefl_compress_mem_to_heap = 0x400000cc; -tdefl_compress_mem_to_mem = 0x400000d0; -tdefl_compress_mem_to_output = 0x400000d4; -tdefl_get_adler32 = 0x400000d8; -tdefl_get_prev_return_status = 0x400000dc; -tdefl_init = 0x400000e0; -tdefl_write_image_to_png_file_in_memory = 0x400000e4; -tdefl_write_image_to_png_file_in_memory_ex = 0x400000e8; -tinfl_decompress = 0x400000ec; -tinfl_decompress_mem_to_callback = 0x400000f0; -tinfl_decompress_mem_to_heap = 0x400000f4; -tinfl_decompress_mem_to_mem = 0x400000f8; - - -/*************************************** - Group spiflash_legacy - ***************************************/ - -/* Functions */ -PROVIDE( esp_rom_spiflash_wait_idle = 0x400000fc ); -PROVIDE( esp_rom_spiflash_write_encrypted = 0x40000100 ); -PROVIDE( esp_rom_spiflash_write_encrypted_dest = 0x40000104 ); -PROVIDE( esp_rom_spiflash_write_encrypted_enable = 0x40000108 ); -PROVIDE( esp_rom_spiflash_write_encrypted_disable = 0x4000010c ); -PROVIDE( esp_rom_spiflash_erase_chip = 0x40000110 ); -PROVIDE( _esp_rom_spiflash_erase_sector = 0x40000114 ); -PROVIDE( _esp_rom_spiflash_erase_block = 0x40000118 ); -PROVIDE( _esp_rom_spiflash_write = 0x4000011c ); -PROVIDE( _esp_rom_spiflash_read = 0x40000120 ); -PROVIDE( _esp_rom_spiflash_unlock = 0x40000124 ); -PROVIDE( _SPIEraseArea = 0x40000128 ); -PROVIDE( _SPI_write_enable = 0x4000012c ); -PROVIDE( esp_rom_spiflash_erase_sector = 0x40000130 ); -PROVIDE( esp_rom_spiflash_erase_block = 0x40000134 ); -PROVIDE( esp_rom_spiflash_write = 0x40000138 ); -PROVIDE( esp_rom_spiflash_read = 0x4000013c ); -PROVIDE( esp_rom_spiflash_unlock = 0x40000140 ); -PROVIDE( SPIEraseArea = 0x40000144 ); -PROVIDE( SPI_write_enable = 0x40000148 ); -PROVIDE( esp_rom_spiflash_config_param = 0x4000014c ); -PROVIDE( esp_rom_spiflash_read_user_cmd = 0x40000150 ); -PROVIDE( esp_rom_spiflash_select_qio_pins = 0x40000154 ); -PROVIDE( esp_rom_spi_flash_auto_sus_res = 0x40000158 ); -PROVIDE( esp_rom_spi_flash_send_resume = 0x4000015c ); -PROVIDE( esp_rom_spi_flash_update_id = 0x40000160 ); -PROVIDE( esp_rom_spiflash_config_clk = 0x40000164 ); -PROVIDE( esp_rom_spiflash_config_readmode = 0x40000168 ); -PROVIDE( esp_rom_spiflash_read_status = 0x4000016c ); -PROVIDE( esp_rom_spiflash_read_statushigh = 0x40000170 ); -PROVIDE( esp_rom_spiflash_write_status = 0x40000174 ); -PROVIDE( spi_flash_attach = 0x40000178 ); -PROVIDE( spi_flash_get_chip_size = 0x4000017c ); -PROVIDE( spi_flash_guard_set = 0x40000180 ); -PROVIDE( spi_flash_guard_get = 0x40000184 ); -PROVIDE( spi_flash_read_encrypted = 0x40000188 ); -PROVIDE( spi_flash_mmap_os_func_set = 0x4000018c ); -PROVIDE( spi_flash_mmap_page_num_init = 0x40000190 ); -PROVIDE( spi_flash_mmap = 0x40000194 ); -PROVIDE( spi_flash_mmap_pages = 0x40000198 ); -PROVIDE( spi_flash_munmap = 0x4000019c ); -PROVIDE( spi_flash_mmap_dump = 0x400001a0 ); -PROVIDE( spi_flash_check_and_flush_cache = 0x400001a4 ); -PROVIDE( spi_flash_mmap_get_free_pages = 0x400001a8 ); -PROVIDE( spi_flash_cache2phys = 0x400001ac ); -PROVIDE( spi_flash_phys2cache = 0x400001b0 ); -PROVIDE( spi_flash_disable_cache = 0x400001b4 ); -PROVIDE( spi_flash_restore_cache = 0x400001b8 ); -PROVIDE( spi_flash_cache_enabled = 0x400001bc ); -PROVIDE( spi_flash_enable_cache = 0x400001c0 ); -PROVIDE( spi_cache_mode_switch = 0x400001c4 ); -PROVIDE( spi_common_set_dummy_output = 0x400001c8 ); -PROVIDE( spi_common_set_flash_cs_timing = 0x400001cc ); -PROVIDE( esp_rom_spi_set_address_bit_len = 0x400001d0 ); -PROVIDE( esp_enable_cache_flash_wrap = 0x400001d4 ); -PROVIDE( SPILock = 0x400001d8 ); -PROVIDE( SPIMasterReadModeCnfig = 0x400001dc ); -PROVIDE( SPI_Common_Command = 0x400001e0 ); -PROVIDE( SPI_WakeUp = 0x400001e4 ); -PROVIDE( SPI_block_erase = 0x400001e8 ); -PROVIDE( SPI_chip_erase = 0x400001ec ); -PROVIDE( SPI_init = 0x400001f0 ); -PROVIDE( SPI_page_program = 0x400001f4 ); -PROVIDE( SPI_read_data = 0x400001f8 ); -PROVIDE( SPI_sector_erase = 0x400001fc ); -PROVIDE( SelectSpiFunction = 0x40000200 ); -PROVIDE( SetSpiDrvs = 0x40000204 ); -PROVIDE( Wait_SPI_Idle = 0x40000208 ); -PROVIDE( spi_dummy_len_fix = 0x4000020c ); -PROVIDE( Disable_QMode = 0x40000210 ); -PROVIDE( Enable_QMode = 0x40000214 ); -/* Data (.data, .bss, .rodata) */ -PROVIDE( rom_spiflash_legacy_funcs = 0x3fcdfff4 ); -PROVIDE( rom_spiflash_legacy_data = 0x3fcdfff0 ); -PROVIDE( g_flash_guard_ops = 0x3fcdfff8 ); - - -/*************************************** - Group hal_soc - ***************************************/ - -/* Functions */ -PROVIDE( spi_flash_hal_poll_cmd_done = 0x40000218 ); -PROVIDE( spi_flash_hal_device_config = 0x4000021c ); -PROVIDE( spi_flash_hal_configure_host_io_mode = 0x40000220 ); -PROVIDE( spi_flash_hal_common_command = 0x40000224 ); -PROVIDE( spi_flash_hal_read = 0x40000228 ); -PROVIDE( spi_flash_hal_erase_chip = 0x4000022c ); -PROVIDE( spi_flash_hal_erase_sector = 0x40000230 ); -PROVIDE( spi_flash_hal_erase_block = 0x40000234 ); -PROVIDE( spi_flash_hal_program_page = 0x40000238 ); -PROVIDE( spi_flash_hal_set_write_protect = 0x4000023c ); -PROVIDE( spi_flash_hal_host_idle = 0x40000240 ); -PROVIDE( spi_flash_hal_check_status = 0x40000244 ); -PROVIDE( spi_flash_hal_setup_read_suspend = 0x40000248 ); -PROVIDE( spi_flash_hal_setup_auto_suspend_mode = 0x4000024c ); -PROVIDE( spi_flash_hal_setup_auto_resume_mode = 0x40000250 ); -PROVIDE( spi_flash_hal_disable_auto_suspend_mode = 0x40000254 ); -PROVIDE( spi_flash_hal_disable_auto_resume_mode = 0x40000258 ); -PROVIDE( spi_flash_hal_resume = 0x4000025c ); -PROVIDE( spi_flash_hal_suspend = 0x40000260 ); -PROVIDE( spi_flash_encryption_hal_enable = 0x40000264 ); -PROVIDE( spi_flash_encryption_hal_disable = 0x40000268 ); -PROVIDE( spi_flash_encryption_hal_prepare = 0x4000026c ); -PROVIDE( spi_flash_encryption_hal_done = 0x40000270 ); -PROVIDE( spi_flash_encryption_hal_destroy = 0x40000274 ); -PROVIDE( spi_flash_encryption_hal_check = 0x40000278 ); -PROVIDE( wdt_hal_init = 0x4000027c ); -PROVIDE( wdt_hal_deinit = 0x40000280 ); -PROVIDE( wdt_hal_config_stage = 0x40000284 ); -PROVIDE( wdt_hal_write_protect_disable = 0x40000288 ); -PROVIDE( wdt_hal_write_protect_enable = 0x4000028c ); -PROVIDE( wdt_hal_enable = 0x40000290 ); -PROVIDE( wdt_hal_disable = 0x40000294 ); -PROVIDE( wdt_hal_handle_intr = 0x40000298 ); -PROVIDE( wdt_hal_feed = 0x4000029c ); -PROVIDE( wdt_hal_set_flashboot_en = 0x400002a0 ); -PROVIDE( wdt_hal_is_enabled = 0x400002a4 ); -PROVIDE( systimer_hal_init = 0x400002a8 ); -PROVIDE( systimer_hal_get_counter_value = 0x400002ac ); -PROVIDE( systimer_hal_get_time = 0x400002b0 ); -PROVIDE( systimer_hal_set_alarm_target = 0x400002b4 ); -PROVIDE( systimer_hal_set_alarm_period = 0x400002b8 ); -PROVIDE( systimer_hal_get_alarm_value = 0x400002bc ); -PROVIDE( systimer_hal_enable_alarm_int = 0x400002c0 ); -PROVIDE( systimer_hal_on_apb_freq_update = 0x400002c4 ); -PROVIDE( systimer_hal_counter_value_advance = 0x400002c8 ); -PROVIDE( systimer_hal_enable_counter = 0x400002cc ); -PROVIDE( systimer_hal_select_alarm_mode = 0x400002d0 ); -PROVIDE( systimer_hal_connect_alarm_counter = 0x400002d4 ); -PROVIDE( systimer_hal_counter_can_stall_by_cpu = 0x400002d8 ); - - -/*************************************** - Group heap - ***************************************/ - -/* Functions */ -PROVIDE( tlsf_create = 0x400002dc ); -PROVIDE( tlsf_create_with_pool = 0x400002e0 ); -PROVIDE( tlsf_get_pool = 0x400002e4 ); -PROVIDE( tlsf_add_pool = 0x400002e8 ); -PROVIDE( tlsf_remove_pool = 0x400002ec ); -PROVIDE( tlsf_malloc = 0x400002f0 ); -PROVIDE( tlsf_memalign = 0x400002f4 ); -PROVIDE( tlsf_memalign_offs = 0x400002f8 ); -PROVIDE( tlsf_realloc = 0x400002fc ); -PROVIDE( tlsf_free = 0x40000300 ); -PROVIDE( tlsf_block_size = 0x40000304 ); -PROVIDE( tlsf_size = 0x40000308 ); -PROVIDE( tlsf_align_size = 0x4000030c ); -PROVIDE( tlsf_block_size_min = 0x40000310 ); -PROVIDE( tlsf_block_size_max = 0x40000314 ); -PROVIDE( tlsf_pool_overhead = 0x40000318 ); -PROVIDE( tlsf_alloc_overhead = 0x4000031c ); -PROVIDE( tlsf_walk_pool = 0x40000320 ); -PROVIDE( tlsf_check = 0x40000324 ); -PROVIDE( tlsf_check_pool = 0x40000328 ); -PROVIDE( tlsf_poison_fill_pfunc_set = 0x4000032c ); -PROVIDE( multi_heap_get_block_address_impl = 0x40000330 ); -PROVIDE( multi_heap_get_allocated_size_impl = 0x40000334 ); -PROVIDE( multi_heap_register_impl = 0x40000338 ); -PROVIDE( multi_heap_set_lock = 0x4000033c ); -PROVIDE( multi_heap_mutex_init = 0x40000340 ); -PROVIDE( multi_heap_internal_lock = 0x40000344 ); -PROVIDE( multi_heap_internal_unlock = 0x40000348 ); -PROVIDE( multi_heap_get_first_block = 0x4000034c ); -PROVIDE( multi_heap_get_next_block = 0x40000350 ); -PROVIDE( multi_heap_is_free = 0x40000354 ); -PROVIDE( multi_heap_malloc_impl = 0x40000358 ); -PROVIDE( multi_heap_free_impl = 0x4000035c ); -PROVIDE( multi_heap_realloc_impl = 0x40000360 ); -PROVIDE( multi_heap_aligned_alloc_impl_offs = 0x40000364 ); -PROVIDE( multi_heap_aligned_alloc_impl = 0x40000368 ); -PROVIDE( multi_heap_check = 0x4000036c ); -PROVIDE( multi_heap_dump = 0x40000370 ); -PROVIDE( multi_heap_free_size_impl = 0x40000374 ); -PROVIDE( multi_heap_minimum_free_size_impl = 0x40000378 ); -PROVIDE( multi_heap_get_info_impl = 0x4000037c ); -/* Data (.data, .bss, .rodata) */ -PROVIDE( heap_tlsf_table_ptr = 0x3fcdffec ); - - -/*************************************** - Group spi_flash_chips - ***************************************/ - -/* Functions */ -PROVIDE( spi_flash_chip_generic_probe = 0x40000380 ); -PROVIDE( spi_flash_chip_generic_detect_size = 0x40000384 ); -PROVIDE( spi_flash_chip_generic_write = 0x40000388 ); -PROVIDE( spi_flash_chip_generic_write_encrypted = 0x4000038c ); -PROVIDE( spi_flash_chip_generic_set_write_protect = 0x40000390 ); -PROVIDE( spi_flash_common_write_status_16b_wrsr = 0x40000394 ); -PROVIDE( spi_flash_chip_generic_reset = 0x40000398 ); -PROVIDE( spi_flash_chip_generic_erase_chip = 0x4000039c ); -PROVIDE( spi_flash_chip_generic_erase_sector = 0x400003a0 ); -PROVIDE( spi_flash_chip_generic_erase_block = 0x400003a4 ); -PROVIDE( spi_flash_chip_generic_page_program = 0x400003a8 ); -PROVIDE( spi_flash_chip_generic_get_write_protect = 0x400003ac ); -PROVIDE( spi_flash_common_read_status_16b_rdsr_rdsr2 = 0x400003b0 ); -PROVIDE( spi_flash_chip_generic_read_reg = 0x400003b4 ); -PROVIDE( spi_flash_chip_generic_yield = 0x400003b8 ); -PROVIDE( spi_flash_generic_wait_host_idle = 0x400003bc ); -PROVIDE( spi_flash_chip_generic_wait_idle = 0x400003c0 ); -PROVIDE( spi_flash_chip_generic_config_host_io_mode = 0x400003c4 ); -PROVIDE( spi_flash_chip_generic_read = 0x400003c8 ); -PROVIDE( spi_flash_common_read_status_8b_rdsr2 = 0x400003cc ); -PROVIDE( spi_flash_chip_generic_get_io_mode = 0x400003d0 ); -PROVIDE( spi_flash_common_read_status_8b_rdsr = 0x400003d4 ); -PROVIDE( spi_flash_common_write_status_8b_wrsr = 0x400003d8 ); -PROVIDE( spi_flash_common_write_status_8b_wrsr2 = 0x400003dc ); -PROVIDE( spi_flash_common_set_io_mode = 0x400003e0 ); -PROVIDE( spi_flash_chip_generic_set_io_mode = 0x400003e4 ); -PROVIDE( spi_flash_chip_generic_read_unique_id = 0x400003e8 ); -PROVIDE( spi_flash_chip_generic_get_caps = 0x400003ec ); -PROVIDE( spi_flash_chip_generic_suspend_cmd_conf = 0x400003f0 ); -PROVIDE( spi_flash_chip_gd_get_io_mode = 0x400003f4 ); -PROVIDE( spi_flash_chip_gd_probe = 0x400003f8 ); -PROVIDE( spi_flash_chip_gd_set_io_mode = 0x400003fc ); -/* Data (.data, .bss, .rodata) */ -PROVIDE( spi_flash_chip_generic_config_data = 0x3fcdffe8 ); -PROVIDE( spi_flash_encryption = 0x3fcdffe4 ); - - -/*************************************** - Group memspi_host - ***************************************/ - -/* Functions */ -PROVIDE( memspi_host_read_id_hs = 0x40000400 ); -PROVIDE( memspi_host_read_status_hs = 0x40000404 ); -PROVIDE( memspi_host_flush_cache = 0x40000408 ); -PROVIDE( memspi_host_erase_chip = 0x4000040c ); -PROVIDE( memspi_host_erase_sector = 0x40000410 ); -PROVIDE( memspi_host_erase_block = 0x40000414 ); -PROVIDE( memspi_host_program_page = 0x40000418 ); -PROVIDE( memspi_host_read = 0x4000041c ); -PROVIDE( memspi_host_set_write_protect = 0x40000420 ); -PROVIDE( memspi_host_set_max_read_len = 0x40000424 ); -PROVIDE( memspi_host_read_data_slicer = 0x40000428 ); -PROVIDE( memspi_host_write_data_slicer = 0x4000042c ); - - -/*************************************** - Group esp_flash - ***************************************/ - -/* Functions */ -PROVIDE( esp_flash_chip_driver_initialized = 0x40000430 ); -PROVIDE( esp_flash_read_id = 0x40000434 ); -PROVIDE( esp_flash_get_size = 0x40000438 ); -PROVIDE( esp_flash_erase_chip = 0x4000043c ); -PROVIDE( esp_flash_erase_region = 0x40000440 ); -PROVIDE( esp_flash_get_chip_write_protect = 0x40000444 ); -PROVIDE( esp_flash_set_chip_write_protect = 0x40000448 ); -PROVIDE( esp_flash_get_protectable_regions = 0x4000044c ); -PROVIDE( esp_flash_get_protected_region = 0x40000450 ); -PROVIDE( esp_flash_set_protected_region = 0x40000454 ); -PROVIDE( esp_flash_read = 0x40000458 ); -PROVIDE( esp_flash_write = 0x4000045c ); -PROVIDE( esp_flash_write_encrypted = 0x40000460 ); -PROVIDE( esp_flash_read_encrypted = 0x40000464 ); -PROVIDE( esp_flash_get_io_mode = 0x40000468 ); -PROVIDE( esp_flash_set_io_mode = 0x4000046c ); -PROVIDE( spi_flash_boot_attach = 0x40000470 ); -PROVIDE( esp_flash_read_chip_id = 0x40000474 ); -PROVIDE( detect_spi_flash_chip = 0x40000478 ); -PROVIDE( esp_rom_spiflash_write_disable = 0x4000047c ); -PROVIDE( esp_flash_suspend_cmd_init = 0x40000480 ); -/* Data (.data, .bss, .rodata) */ -PROVIDE( esp_flash_default_chip = 0x3fcdffe0 ); -PROVIDE( esp_flash_api_funcs = 0x3fcdffdc ); - - -/*************************************** - Group cache - ***************************************/ - -/* Functions */ -PROVIDE( Cache_Get_ICache_Line_Size = 0x400006e0 ); -PROVIDE( Cache_Get_Mode = 0x400006e4 ); -PROVIDE( Cache_Address_Through_IBus = 0x400006e8 ); -PROVIDE( Cache_Address_Through_DBus = 0x400006ec ); -PROVIDE( Cache_Set_Default_Mode = 0x400006f0 ); -PROVIDE( Cache_Enable_Defalut_ICache_Mode = 0x400006f4 ); -PROVIDE( ROM_Boot_Cache_Init = 0x400006f8 ); -PROVIDE( MMU_Set_Page_Mode = 0x400006fc ); -PROVIDE( MMU_Get_Page_Mode = 0x40000700 ); -PROVIDE( Cache_Invalidate_ICache_Items = 0x40000704 ); -PROVIDE( Cache_Op_Addr = 0x40000708 ); -PROVIDE( Cache_Invalidate_Addr = 0x4000070c ); -PROVIDE( Cache_Invalidate_ICache_All = 0x40000710 ); -PROVIDE( Cache_Mask_All = 0x40000714 ); -PROVIDE( Cache_UnMask_Dram0 = 0x40000718 ); -PROVIDE( Cache_Disable_ICache = 0x4000071c ); -PROVIDE( Cache_Enable_ICache = 0x40000720 ); -PROVIDE( Cache_Suspend_ICache = 0x40000724 ); -PROVIDE( Cache_Resume_ICache = 0x40000728 ); -PROVIDE( Cache_Freeze_ICache_Enable = 0x4000072c ); -PROVIDE( Cache_Freeze_ICache_Disable = 0x40000730 ); -PROVIDE( Cache_Set_IDROM_MMU_Size = 0x40000734 ); -PROVIDE( Cache_Get_IROM_MMU_End = 0x40000738 ); -PROVIDE( Cache_Get_DROM_MMU_End = 0x4000073c ); -PROVIDE( Cache_Owner_Init = 0x40000740 ); -PROVIDE( Cache_Occupy_ICache_MEMORY = 0x40000744 ); -PROVIDE( Cache_MMU_Init = 0x40000748 ); -PROVIDE( Cache_Ibus_MMU_Set = 0x4000074c ); -PROVIDE( Cache_Dbus_MMU_Set = 0x40000750 ); -PROVIDE( Cache_Count_Flash_Pages = 0x40000754 ); -PROVIDE( Cache_Travel_Tag_Memory = 0x40000758 ); -PROVIDE( Cache_Get_Virtual_Addr = 0x4000075c ); -PROVIDE( Cache_Get_Memory_BaseAddr = 0x40000760 ); -PROVIDE( Cache_Get_Memory_Addr = 0x40000764 ); -PROVIDE( Cache_Get_Memory_value = 0x40000768 ); -/* Data (.data, .bss, .rodata) */ -PROVIDE( rom_cache_op_cb = 0x3fcdffd0 ); -PROVIDE( rom_cache_internal_table_ptr = 0x3fcdffcc ); - - -/*************************************** - Group clock - ***************************************/ - -/* Functions */ -ets_get_apb_freq = 0x4000076c; -ets_get_cpu_frequency = 0x40000770; -ets_update_cpu_frequency = 0x40000774; -ets_get_printf_channel = 0x40000778; -ets_get_xtal_div = 0x4000077c; -ets_set_xtal_div = 0x40000780; -ets_get_xtal_freq = 0x40000784; - - -/*************************************** - Group gpio - ***************************************/ - -/* Functions */ -gpio_input_get = 0x40000788; -gpio_matrix_in = 0x4000078c; -gpio_matrix_out = 0x40000790; -gpio_output_disable = 0x40000794; -gpio_output_enable = 0x40000798; -gpio_output_set = 0x4000079c; -gpio_pad_hold = 0x400007a0; -gpio_pad_input_disable = 0x400007a4; -gpio_pad_input_enable = 0x400007a8; -gpio_pad_pulldown = 0x400007ac; -gpio_pad_pullup = 0x400007b0; -gpio_pad_select_gpio = 0x400007b4; -gpio_pad_set_drv = 0x400007b8; -gpio_pad_unhold = 0x400007bc; -gpio_pin_wakeup_disable = 0x400007c0; -gpio_pin_wakeup_enable = 0x400007c4; -gpio_bypass_matrix_in = 0x400007c8; - - -/*************************************** - Group interrupts - ***************************************/ - -/* Functions */ -esprv_intc_int_set_priority = 0x400007cc; -esprv_intc_int_set_threshold = 0x400007d0; -esprv_intc_int_enable = 0x400007d4; -esprv_intc_int_disable = 0x400007d8; -esprv_intc_int_set_type = 0x400007dc; -PROVIDE( intr_handler_set = 0x400007e0 ); -intr_matrix_set = 0x400007e4; -ets_intr_lock = 0x400007e8; -ets_intr_unlock = 0x400007ec; -ets_isr_attach = 0x400007f0; -ets_isr_mask = 0x400007f4; -ets_isr_unmask = 0x400007f8; - - -/*************************************** - Group crypto - ***************************************/ - -/* Functions */ -crc32_le = 0x400007fc; -crc16_le = 0x40000800; -crc8_le = 0x40000804; -crc32_be = 0x40000808; -crc16_be = 0x4000080c; -crc8_be = 0x40000810; -esp_crc8 = 0x40000814; -ets_sha_enable = 0x40000818; -ets_sha_disable = 0x4000081c; -ets_sha_get_state = 0x40000820; -ets_sha_init = 0x40000824; -ets_sha_process = 0x40000828; -ets_sha_starts = 0x4000082c; -ets_sha_update = 0x40000830; -ets_sha_finish = 0x40000834; -ets_sha_clone = 0x40000838; -/* Data (.data, .bss, .rodata) */ -crc32_le_table_ptr = 0x3ff4fff8; -crc16_le_table_ptr = 0x3ff4fff4; -crc8_le_table_ptr = 0x3ff4fff0; -crc32_be_table_ptr = 0x3ff4ffec; -crc16_be_table_ptr = 0x3ff4ffe8; -crc8_be_table_ptr = 0x3ff4ffe4; - - -/*************************************** - Group efuse - ***************************************/ - -/* Functions */ -ets_efuse_read = 0x4000083c; -ets_efuse_program = 0x40000840; -ets_efuse_clear_program_registers = 0x40000844; -ets_efuse_write_key = 0x40000848; -ets_efuse_get_read_register_address = 0x4000084c; -ets_efuse_get_key_purpose = 0x40000850; -ets_efuse_key_block_unused = 0x40000854; -ets_efuse_find_unused_key_block = 0x40000858; -ets_efuse_rs_calculate = 0x4000085c; -ets_efuse_count_unused_key_blocks = 0x40000860; -ets_efuse_secure_boot_enabled = 0x40000864; -ets_efuse_secure_boot_aggressive_revoke_enabled = 0x40000868; -ets_efuse_cache_encryption_enabled = 0x4000086c; -ets_efuse_download_modes_disabled = 0x40000870; -ets_efuse_find_purpose = 0x40000874; -ets_efuse_force_send_resume = 0x40000878; -ets_efuse_get_flash_delay_us = 0x4000087c; -ets_efuse_get_mac = 0x40000880; -ets_efuse_get_uart_print_control = 0x40000884; -ets_efuse_direct_boot_mode_disabled = 0x40000888; -ets_efuse_security_download_modes_enabled = 0x4000088c; -ets_efuse_set_timing = 0x40000890; -ets_efuse_jtag_disabled = 0x40000894; - - -/*************************************** - Group secureboot - ***************************************/ - -/* Functions */ -ets_ecdsa_verify = 0x40000898; -ets_secure_boot_verify_bootloader_with_keys = 0x4000089c; -ets_secure_boot_verify_signature = 0x400008a0; -ets_secure_boot_read_key_digests = 0x400008a4; - - -/*************************************** - Group usb_uart - ***************************************/ - -/* Data (.data, .bss, .rodata) */ -g_uart_print = 0x3fcdffc9; -g_usb_print = 0x3fcdffc8; - - -/*************************************** - Group bluetooth - ***************************************/ - -/* Functions */ -ble_controller_rom_data_init = 0x40000aa8; -ble_osi_coex_funcs_register = 0x40000aac; -bt_rf_coex_cfg_get_default = 0x40000ab0; -bt_rf_coex_dft_pti_get_default = 0x40000ab4; -bt_rf_coex_hooks_p_set = 0x40000ab8; -r__os_mbuf_copypkthdr = 0x40000abc; -r__os_msys_find_pool = 0x40000ac0; -r_ble_controller_get_rom_compile_version = 0x40000ac4; -r_ble_hci_ram_hs_acl_tx = 0x40000ac8; -r_ble_hci_ram_hs_cmd_tx = 0x40000acc; -r_ble_hci_ram_ll_acl_tx = 0x40000ad0; -r_ble_hci_ram_ll_evt_tx = 0x40000ad4; -r_ble_hci_ram_reset = 0x40000ad8; -r_ble_hci_ram_set_acl_free_cb = 0x40000adc; -r_ble_hci_trans_acl_buf_alloc = 0x40000ae0; -r_ble_hci_trans_buf_alloc = 0x40000ae4; -r_ble_hci_trans_buf_free = 0x40000ae8; -r_ble_hci_trans_cfg_hs = 0x40000aec; -r_ble_hci_trans_cfg_ll = 0x40000af0; -r_ble_hci_trans_deinit = 0x40000af4; -r_ble_hci_trans_env_init = 0x40000af8; -r_ble_hci_trans_init = 0x40000afc; -r_ble_hci_uart_acl_tx = 0x40000b00; -r_ble_hci_uart_cmdevt_tx = 0x40000b04; -r_ble_hci_uart_config = 0x40000b08; -r_ble_hci_uart_free_pkt = 0x40000b0c; -r_ble_hci_uart_hs_acl_tx = 0x40000b10; -r_ble_hci_uart_hs_cmd_tx = 0x40000b14; -r_ble_hci_uart_ll_acl_tx = 0x40000b18; -r_ble_hci_uart_ll_evt_tx = 0x40000b1c; -r_ble_hci_uart_rx_acl = 0x40000b20; -r_ble_hci_uart_rx_char = 0x40000b24; -r_ble_hci_uart_rx_cmd = 0x40000b28; -r_ble_hci_uart_rx_evt = 0x40000b2c; -r_ble_hci_uart_rx_evt_cb = 0x40000b30; -r_ble_hci_uart_rx_le_evt = 0x40000b34; -r_ble_hci_uart_rx_pkt_type = 0x40000b38; -r_ble_hci_uart_rx_skip_acl = 0x40000b3c; -r_ble_hci_uart_rx_skip_cmd = 0x40000b40; -r_ble_hci_uart_rx_skip_evt = 0x40000b44; -r_ble_hci_uart_rx_sync_loss = 0x40000b48; -r_ble_hci_uart_set_acl_free_cb = 0x40000b4c; -r_ble_hci_uart_sync_lost = 0x40000b50; -r_ble_hci_uart_trans_reset = 0x40000b54; -r_ble_hci_uart_tx_char = 0x40000b58; -r_ble_hci_uart_tx_pkt_type = 0x40000b5c; -r_ble_hw_driver_deinit = 0x40000b60; -r_ble_hw_driver_env_init = 0x40000b64; -r_ble_hw_encrypt_block = 0x40000b68; -r_ble_hw_get_public_addr = 0x40000b6c; -r_ble_hw_get_static_addr = 0x40000b70; -r_ble_hw_periodiclist_add = 0x40000b74; -r_ble_hw_periodiclist_clear = 0x40000b78; -r_ble_hw_periodiclist_rmv = 0x40000b7c; -r_ble_hw_resolv_list_cur_entry = 0x40000b80; -r_ble_hw_resolv_list_get_cur_entry = 0x40000b84; -r_ble_hw_resolv_list_set = 0x40000b88; -r_ble_hw_rng_init = 0x40000b8c; -r_ble_hw_rng_start = 0x40000b90; -r_ble_hw_rng_stop = 0x40000b94; -r_ble_hw_rx_local_is_resolved = 0x40000b98; -r_ble_hw_rx_local_is_rpa = 0x40000b9c; -r_ble_hw_whitelist_add = 0x40000ba0; -r_ble_hw_whitelist_clear = 0x40000ba4; -r_ble_hw_whitelist_dev_num = 0x40000ba8; -r_ble_hw_whitelist_get_base = 0x40000bac; -r_ble_hw_whitelist_rmv = 0x40000bb0; -r_ble_hw_whitelist_search = 0x40000bb4; -r_ble_hw_whitelist_sort = 0x40000bb8; -r_ble_ll_acl_data_in = 0x40000bbc; -r_ble_ll_addr_is_id = 0x40000bc0; -r_ble_ll_addr_subtype = 0x40000bc4; -r_ble_ll_adv_active_chanset_clear = 0x40000bc8; -r_ble_ll_adv_active_chanset_is_pri = 0x40000bcc; -r_ble_ll_adv_active_chanset_is_sec = 0x40000bd0; -r_ble_ll_adv_active_chanset_set_pri = 0x40000bd4; -r_ble_ll_adv_active_chanset_set_sec = 0x40000bd8; -r_ble_ll_adv_aux_calculate = 0x40000bdc; -r_ble_ll_adv_aux_conn_rsp_pdu_make = 0x40000be0; -r_ble_ll_adv_aux_pdu_make = 0x40000be4; -r_ble_ll_adv_aux_scannable_pdu_make = 0x40000be8; -r_ble_ll_adv_aux_txed = 0x40000bec; -r_ble_ll_adv_can_chg_whitelist = 0x40000bf0; -r_ble_ll_adv_chk_rpa_timeout = 0x40000bf4; -r_ble_ll_adv_clear_all = 0x40000bf8; -r_ble_ll_adv_conn_req_rxd = 0x40000bfc; -r_ble_ll_adv_deinit = 0x40000c00; -r_ble_ll_adv_enabled = 0x40000c04; -r_ble_ll_adv_env_init = 0x40000c08; -r_ble_ll_adv_ext_set_adv_data = 0x40000c0c; -r_ble_ll_adv_ext_set_enable = 0x40000c10; -r_ble_ll_adv_ext_set_param = 0x40000c14; -r_ble_ll_adv_ext_set_scan_rsp = 0x40000c18; -r_ble_ll_adv_final_chan = 0x40000c1c; -r_ble_ll_adv_first_chan = 0x40000c20; -r_ble_ll_adv_flags_clear = 0x40000c24; -r_ble_ll_adv_flags_set = 0x40000c28; -r_ble_ll_adv_get_chan_num = 0x40000c2c; -r_ble_ll_adv_get_local_rpa = 0x40000c30; -r_ble_ll_adv_get_peer_rpa = 0x40000c34; -r_ble_ll_adv_hci_set_random_addr = 0x40000c38; -r_ble_ll_adv_init = 0x40000c3c; -r_ble_ll_adv_legacy_pdu_make = 0x40000c40; -r_ble_ll_adv_next_chan = 0x40000c44; -r_ble_ll_adv_pdu_make = 0x40000c48; -r_ble_ll_adv_periodic_check_data_itvl = 0x40000c4c; -r_ble_ll_adv_periodic_enable = 0x40000c50; -r_ble_ll_adv_periodic_estimate_data_itvl = 0x40000c54; -r_ble_ll_adv_periodic_send_sync_ind = 0x40000c58; -r_ble_ll_adv_periodic_set_data = 0x40000c5c; -r_ble_ll_adv_periodic_set_info_transfer = 0x40000c60; -r_ble_ll_adv_periodic_set_param = 0x40000c64; -r_ble_ll_adv_pre_process = 0x40000c68; -r_ble_ll_adv_put_acad_chM_update_ind = 0x40000c6c; -r_ble_ll_adv_put_aux_ptr = 0x40000c70; -r_ble_ll_adv_put_syncinfo = 0x40000c74; -r_ble_ll_adv_rd_max_adv_data_len = 0x40000c78; -r_ble_ll_adv_rd_sup_adv_sets = 0x40000c7c; -r_ble_ll_adv_read_txpwr = 0x40000c80; -r_ble_ll_adv_remove = 0x40000c84; -r_ble_ll_adv_reset = 0x40000c88; -r_ble_ll_adv_rpa_timeout = 0x40000c8c; -r_ble_ll_adv_rpa_update = 0x40000c90; -r_ble_ll_adv_rx_pkt_in = 0x40000c94; -r_ble_ll_adv_scan_req_rxd = 0x40000c98; -r_ble_ll_adv_scan_rsp_legacy_pdu_make = 0x40000c9c; -r_ble_ll_adv_scan_rsp_pdu_make = 0x40000ca0; -r_ble_ll_adv_scheduled = 0x40000ca4; -r_ble_ll_adv_send_conn_comp_ev = 0x40000ca8; -r_ble_ll_adv_set_adv_data = 0x40000cac; -r_ble_ll_adv_set_adv_params = 0x40000cb0; -r_ble_ll_adv_set_enable = 0x40000cb4; -r_ble_ll_adv_set_random_addr = 0x40000cb8; -r_ble_ll_adv_set_scan_rsp_data = 0x40000cbc; -r_ble_ll_adv_set_sched = 0x40000cc0; -r_ble_ll_adv_sm_deinit = 0x40000cc4; -r_ble_ll_adv_sm_event_init = 0x40000cc8; -r_ble_ll_adv_sm_find_configured = 0x40000ccc; -r_ble_ll_adv_sm_get = 0x40000cd0; -r_ble_ll_adv_sm_init = 0x40000cd4; -r_ble_ll_adv_sm_reset = 0x40000cd8; -r_ble_ll_adv_sm_start = 0x40000cdc; -r_ble_ll_adv_sm_start_periodic = 0x40000ce0; -r_ble_ll_adv_sm_stop = 0x40000ce4; -r_ble_ll_adv_sm_stop_limit_reached = 0x40000ce8; -r_ble_ll_adv_sm_stop_periodic = 0x40000cec; -r_ble_ll_adv_sm_stop_timeout = 0x40000cf0; -r_ble_ll_adv_sync_calculate = 0x40000cf4; -r_ble_ll_adv_sync_get_pdu_len = 0x40000cf8; -r_ble_ll_adv_sync_pdu_make = 0x40000cfc; -r_ble_ll_adv_update_adv_scan_rsp_data = 0x40000d00; -r_ble_ll_adv_update_data_mbuf = 0x40000d04; -r_ble_ll_adv_update_did = 0x40000d08; -r_ble_ll_adv_update_periodic_data = 0x40000d0c; -r_ble_ll_arr_pool_init = 0x40000d10; -r_ble_ll_auth_pyld_tmo_event_send = 0x40000d14; -r_ble_ll_calc_offset_ticks_us_for_rampup = 0x40000d18; -r_ble_ll_calc_session_key = 0x40000d1c; -r_ble_ll_calc_ticks_per_slot = 0x40000d20; -r_ble_ll_check_scan_params = 0x40000d24; -r_ble_ll_chk_txrx_octets = 0x40000d28; -r_ble_ll_chk_txrx_time = 0x40000d2c; -r_ble_ll_conn_adjust_pyld_len = 0x40000d30; -r_ble_ll_conn_auth_pyld_timer_cb = 0x40000d34; -r_ble_ll_conn_auth_pyld_timer_start = 0x40000d38; -r_ble_ll_conn_calc_dci = 0x40000d3c; -r_ble_ll_conn_calc_dci_csa1 = 0x40000d40; -r_ble_ll_conn_calc_itvl_ticks = 0x40000d44; -r_ble_ll_conn_chk_csm_flags = 0x40000d48; -r_ble_ll_conn_chk_phy_upd_start = 0x40000d4c; -r_ble_ll_conn_comp_event_send = 0x40000d50; -r_ble_ll_conn_connect_ind_pdu_make = 0x40000d54; -r_ble_ll_conn_create = 0x40000d58; -r_ble_ll_conn_create_cancel = 0x40000d5c; -r_ble_ll_conn_created = 0x40000d60; -r_ble_ll_conn_cth_flow_enable = 0x40000d64; -r_ble_ll_conn_cth_flow_error_fn = 0x40000d68; -r_ble_ll_conn_cth_flow_have_credit = 0x40000d6c; -r_ble_ll_conn_cth_flow_is_enabled = 0x40000d70; -r_ble_ll_conn_cth_flow_process_cmd = 0x40000d74; -r_ble_ll_conn_cth_flow_set_buffers = 0x40000d78; -r_ble_ll_conn_enqueue_pkt = 0x40000d7c; -r_ble_ll_conn_env_init = 0x40000d80; -r_ble_ll_conn_ext_master_init = 0x40000d84; -r_ble_ll_conn_find_active_conn = 0x40000d88; -r_ble_ll_conn_get_active_conn = 0x40000d8c; -r_ble_ll_conn_get_anchor = 0x40000d90; -r_ble_ll_conn_hcc_params_set_fallback = 0x40000d94; -r_ble_ll_conn_hci_cancel_conn_complete_event = 0x40000d98; -r_ble_ll_conn_hci_chk_conn_params = 0x40000d9c; -r_ble_ll_conn_hci_chk_scan_params = 0x40000da0; -r_ble_ll_conn_hci_disconnect_cmd = 0x40000da4; -r_ble_ll_conn_hci_le_ltk_neg_reply = 0x40000da8; -r_ble_ll_conn_hci_le_ltk_reply = 0x40000dac; -r_ble_ll_conn_hci_le_rd_phy = 0x40000db0; -r_ble_ll_conn_hci_le_set_phy = 0x40000db4; -r_ble_ll_conn_hci_le_start_encrypt = 0x40000db8; -r_ble_ll_conn_hci_param_nrr = 0x40000dbc; -r_ble_ll_conn_hci_param_rr = 0x40000dc0; -r_ble_ll_conn_hci_rd_auth_pyld_tmo = 0x40000dc4; -r_ble_ll_conn_hci_rd_chan_map = 0x40000dc8; -r_ble_ll_conn_hci_rd_rem_ver_cmd = 0x40000dcc; -r_ble_ll_conn_hci_rd_rssi = 0x40000dd0; -r_ble_ll_conn_hci_read_rem_features = 0x40000dd4; -r_ble_ll_conn_hci_set_chan_class = 0x40000dd8; -r_ble_ll_conn_hci_set_data_len = 0x40000ddc; -r_ble_ll_conn_hci_update = 0x40000de0; -r_ble_ll_conn_hci_wr_auth_pyld_tmo = 0x40000de4; -r_ble_ll_conn_init_phy = 0x40000de8; -r_ble_ll_conn_is_dev_connected = 0x40000dec; -r_ble_ll_conn_is_empty_pdu = 0x40000df0; -r_ble_ll_conn_is_lru = 0x40000df4; -r_ble_ll_conn_master_init = 0x40000df8; -r_ble_ll_conn_module_deinit = 0x40000dfc; -r_ble_ll_conn_module_init = 0x40000e00; -r_ble_ll_conn_module_reset = 0x40000e04; -r_ble_ll_conn_next_event = 0x40000e08; -r_ble_ll_conn_num_comp_pkts_event_send = 0x40000e0c; -r_ble_ll_conn_prepare_tx_pdu = 0x40000e10; -r_ble_ll_conn_process_conn_params = 0x40000e14; -r_ble_ll_conn_req_peer_sca = 0x40000e18; -r_ble_ll_conn_rx_data_pdu = 0x40000e1c; -r_ble_ll_conn_set_csa = 0x40000e20; -r_ble_ll_conn_set_ext_con_params = 0x40000e24; -r_ble_ll_conn_set_global_chanmap = 0x40000e28; -r_ble_ll_conn_set_phy = 0x40000e2c; -r_ble_ll_conn_set_txpwr_by_handle = 0x40000e30; -r_ble_ll_conn_set_unknown_rx_octets = 0x40000e34; -r_ble_ll_conn_slave_start = 0x40000e38; -r_ble_ll_conn_sm_get = 0x40000e3c; -r_ble_ll_conn_sm_new = 0x40000e40; -r_ble_ll_conn_sm_npl_deinit = 0x40000e44; -r_ble_ll_conn_sm_npl_init = 0x40000e48; -r_ble_ll_conn_tx_pkt_in = 0x40000e4c; -r_ble_ll_conn_update_eff_data_len = 0x40000e50; -r_ble_ll_ctrl_chanmap_req_make = 0x40000e54; -r_ble_ll_ctrl_chk_proc_start = 0x40000e58; -r_ble_ll_ctrl_conn_param_pdu_make = 0x40000e5c; -r_ble_ll_ctrl_conn_param_pdu_proc = 0x40000e60; -r_ble_ll_ctrl_conn_param_reply = 0x40000e64; -r_ble_ll_ctrl_conn_upd_make = 0x40000e68; -r_ble_ll_ctrl_datalen_upd_make = 0x40000e6c; -r_ble_ll_ctrl_enc_allowed_pdu = 0x40000e70; -r_ble_ll_ctrl_enc_allowed_pdu_rx = 0x40000e74; -r_ble_ll_ctrl_enc_allowed_pdu_tx = 0x40000e78; -r_ble_ll_ctrl_enc_req_make = 0x40000e7c; -r_ble_ll_ctrl_find_new_phy = 0x40000e80; -r_ble_ll_ctrl_initiate_dle = 0x40000e84; -r_ble_ll_ctrl_len_proc = 0x40000e88; -r_ble_ll_ctrl_min_used_chan_rsp = 0x40000e8c; -r_ble_ll_ctrl_phy_from_phy_mask = 0x40000e90; -r_ble_ll_ctrl_phy_req_rsp_make = 0x40000e94; -r_ble_ll_ctrl_phy_tx_transition_get = 0x40000e98; -r_ble_ll_ctrl_phy_update_cancel = 0x40000e9c; -r_ble_ll_ctrl_phy_update_ind_make = 0x40000ea0; -r_ble_ll_ctrl_phy_update_proc_complete = 0x40000ea4; -r_ble_ll_ctrl_proc_init = 0x40000ea8; -r_ble_ll_ctrl_proc_rsp_timer_cb = 0x40000eac; -r_ble_ll_ctrl_proc_start = 0x40000eb0; -r_ble_ll_ctrl_proc_stop = 0x40000eb4; -r_ble_ll_ctrl_proc_unk_rsp = 0x40000eb8; -r_ble_ll_ctrl_proc_with_instant_initiated = 0x40000ebc; -r_ble_ll_ctrl_rej_ext_ind_make = 0x40000ec0; -r_ble_ll_ctrl_reject_ind_send = 0x40000ec4; -r_ble_ll_ctrl_rx_chanmap_req = 0x40000ec8; -r_ble_ll_ctrl_rx_conn_param_req = 0x40000ecc; -r_ble_ll_ctrl_rx_conn_param_rsp = 0x40000ed0; -r_ble_ll_ctrl_rx_conn_update = 0x40000ed4; -r_ble_ll_ctrl_rx_enc_req = 0x40000ed8; -r_ble_ll_ctrl_rx_enc_rsp = 0x40000edc; -r_ble_ll_ctrl_rx_feature_req = 0x40000ee0; -r_ble_ll_ctrl_rx_feature_rsp = 0x40000ee4; -r_ble_ll_ctrl_rx_pause_enc_req = 0x40000ee8; -r_ble_ll_ctrl_rx_pause_enc_rsp = 0x40000eec; -r_ble_ll_ctrl_rx_pdu = 0x40000ef0; -r_ble_ll_ctrl_rx_periodic_sync_ind = 0x40000ef4; -r_ble_ll_ctrl_rx_phy_req = 0x40000ef8; -r_ble_ll_ctrl_rx_phy_rsp = 0x40000efc; -r_ble_ll_ctrl_rx_phy_update_ind = 0x40000f00; -r_ble_ll_ctrl_rx_ping_rsp = 0x40000f04; -r_ble_ll_ctrl_rx_reject_ind = 0x40000f08; -r_ble_ll_ctrl_rx_sca_req = 0x40000f0c; -r_ble_ll_ctrl_rx_sca_rsp = 0x40000f10; -r_ble_ll_ctrl_rx_start_enc_req = 0x40000f14; -r_ble_ll_ctrl_rx_start_enc_rsp = 0x40000f18; -r_ble_ll_ctrl_rx_version_ind = 0x40000f1c; -r_ble_ll_ctrl_sca_req_rsp_make = 0x40000f20; -r_ble_ll_ctrl_start_enc_send = 0x40000f24; -r_ble_ll_ctrl_start_rsp_timer = 0x40000f28; -r_ble_ll_ctrl_terminate_start = 0x40000f2c; -r_ble_ll_ctrl_tx_done = 0x40000f30; -r_ble_ll_ctrl_update_features = 0x40000f34; -r_ble_ll_ctrl_version_ind_make = 0x40000f38; -r_ble_ll_data_buffer_overflow = 0x40000f3c; -r_ble_ll_deinit = 0x40000f40; -r_ble_ll_disconn_comp_event_send = 0x40000f44; -r_ble_ll_env_init = 0x40000f48; -r_ble_ll_event_comp_pkts = 0x40000f4c; -r_ble_ll_event_dbuf_overflow = 0x40000f50; -r_ble_ll_event_send = 0x40000f54; -r_ble_ll_event_tx_pkt = 0x40000f58; -r_ble_ll_ext_adv_phy_mode_to_local_phy = 0x40000f5c; -r_ble_ll_ext_conn_create = 0x40000f60; -r_ble_ll_ext_scan_parse_adv_info = 0x40000f64; -r_ble_ll_ext_scan_parse_aux_ptr = 0x40000f68; -r_ble_ll_flush_pkt_queue = 0x40000f6c; -r_ble_ll_generate_dh_key_v1 = 0x40000f70; -r_ble_ll_generate_dh_key_v2 = 0x40000f74; -r_ble_ll_generic_data_init = 0x40000f78; -r_ble_ll_get_addr_type = 0x40000f7c; -r_ble_ll_get_chan_to_scan = 0x40000f80; -r_ble_ll_get_our_devaddr = 0x40000f84; -r_ble_ll_get_tx_pwr_compensation = 0x40000f88; -r_ble_ll_hci_acl_rx = 0x40000f8c; -r_ble_ll_hci_adv_mode_ext = 0x40000f90; -r_ble_ll_hci_adv_set_enable = 0x40000f94; -r_ble_ll_hci_cb_host_buf_size = 0x40000f98; -r_ble_ll_hci_cb_set_ctrlr_to_host_fc = 0x40000f9c; -r_ble_ll_hci_cb_set_event_mask = 0x40000fa0; -r_ble_ll_hci_cb_set_event_mask2 = 0x40000fa4; -r_ble_ll_hci_chk_phy_masks = 0x40000fa8; -r_ble_ll_hci_cmd_proc = 0x40000fac; -r_ble_ll_hci_cmd_rx = 0x40000fb0; -r_ble_ll_hci_ctlr_bb_cmd_proc = 0x40000fb4; -r_ble_ll_hci_deinit = 0x40000fb8; -r_ble_ll_hci_disconnect = 0x40000fbc; -r_ble_ll_hci_env_init = 0x40000fc0; -r_ble_ll_hci_ev_conn_update = 0x40000fc4; -r_ble_ll_hci_ev_databuf_overflow = 0x40000fc8; -r_ble_ll_hci_ev_datalen_chg = 0x40000fcc; -r_ble_ll_hci_ev_encrypt_chg = 0x40000fd0; -r_ble_ll_hci_ev_hw_err = 0x40000fd4; -r_ble_ll_hci_ev_le_csa = 0x40000fd8; -r_ble_ll_hci_ev_ltk_req = 0x40000fdc; -r_ble_ll_hci_ev_phy_update = 0x40000fe0; -r_ble_ll_hci_ev_rd_rem_used_feat = 0x40000fe4; -r_ble_ll_hci_ev_rd_rem_ver = 0x40000fe8; -r_ble_ll_hci_ev_rem_conn_parm_req = 0x40000fec; -r_ble_ll_hci_ev_sca_update = 0x40000ff0; -r_ble_ll_hci_ev_send_adv_set_terminated = 0x40000ff4; -r_ble_ll_hci_ev_send_scan_req_recv = 0x40000ff8; -r_ble_ll_hci_ev_send_scan_timeout = 0x40000ffc; -r_ble_ll_hci_ev_send_vendor_err = 0x40001000; -r_ble_ll_hci_event_send = 0x40001004; -r_ble_ll_hci_ext_scan_set_enable = 0x40001008; -r_ble_ll_hci_get_num_cmd_pkts = 0x4000100c; -r_ble_ll_hci_info_params_cmd_proc = 0x40001010; -r_ble_ll_hci_init = 0x40001014; -r_ble_ll_hci_init_support_cmd_base_on_lmp_ver = 0x40001018; -r_ble_ll_hci_is_event_enabled = 0x4000101c; -r_ble_ll_hci_is_le_event_enabled = 0x40001020; -r_ble_ll_hci_le_cmd_proc = 0x40001024; -r_ble_ll_hci_le_cmd_send_cmd_status = 0x40001028; -r_ble_ll_hci_le_encrypt = 0x4000102c; -r_ble_ll_hci_le_rand = 0x40001030; -r_ble_ll_hci_le_rd_max_data_len = 0x40001034; -r_ble_ll_hci_le_rd_sugg_data_len = 0x40001038; -r_ble_ll_hci_le_read_bufsize = 0x4000103c; -r_ble_ll_hci_le_read_local_features = 0x40001040; -r_ble_ll_hci_le_read_supp_states = 0x40001044; -r_ble_ll_hci_le_set_def_phy = 0x40001048; -r_ble_ll_hci_le_wr_sugg_data_len = 0x4000104c; -r_ble_ll_hci_link_ctrl_cmd_proc = 0x40001050; -r_ble_ll_hci_npl_init = 0x40001054; -r_ble_ll_hci_post_gen_dhkey_cmp_evt = 0x40001058; -r_ble_ll_hci_post_rd_p256_pubkey_cmp_evt = 0x4000105c; -r_ble_ll_hci_rd_bd_addr = 0x40001060; -r_ble_ll_hci_rd_local_supp_cmd = 0x40001064; -r_ble_ll_hci_rd_local_supp_feat = 0x40001068; -r_ble_ll_hci_rd_local_version = 0x4000106c; -r_ble_ll_hci_scan_set_enable = 0x40001070; -r_ble_ll_hci_send_adv_report = 0x40001074; -r_ble_ll_hci_send_dir_adv_report = 0x40001078; -r_ble_ll_hci_send_ext_adv_report = 0x4000107c; -r_ble_ll_hci_send_legacy_ext_adv_report = 0x40001080; -r_ble_ll_hci_send_noop = 0x40001084; -r_ble_ll_hci_set_adv_data = 0x40001088; -r_ble_ll_hci_set_le_event_mask = 0x4000108c; -r_ble_ll_hci_set_scan_rsp_data = 0x40001090; -r_ble_ll_hci_status_params_cmd_proc = 0x40001094; -r_ble_ll_hci_vs_cmd_proc = 0x40001098; -r_ble_ll_hci_vs_rd_static_addr = 0x4000109c; -r_ble_ll_hw_err_timer_cb = 0x400010a0; -r_ble_ll_hw_error = 0x400010a4; -r_ble_ll_init = 0x400010a8; -r_ble_ll_init_alloc_conn_comp_ev = 0x400010ac; -r_ble_ll_init_get_conn_comp_ev = 0x400010b0; -r_ble_ll_init_rx_pkt_in = 0x400010b4; -r_ble_ll_is_addr_empty = 0x400010b8; -r_ble_ll_is_controller_busy = 0x400010bc; -r_ble_ll_is_on_resolv_list = 0x400010c0; -r_ble_ll_is_our_devaddr = 0x400010c4; -r_ble_ll_is_rpa = 0x400010c8; -r_ble_ll_is_valid_adv_mode = 0x400010cc; -r_ble_ll_is_valid_own_addr_type = 0x400010d0; -r_ble_ll_is_valid_public_addr = 0x400010d4; -r_ble_ll_is_valid_random_addr = 0x400010d8; -r_ble_ll_mbuf_init = 0x400010dc; -r_ble_ll_misc_options_set = 0x400010e0; -r_ble_ll_modify_sca = 0x400010e4; -r_ble_ll_modify_sca_action = 0x400010e8; -r_ble_ll_pdu_max_tx_octets_get = 0x400010ec; -r_ble_ll_pdu_tx_time_get = 0x400010f0; -r_ble_ll_phy_to_phy_mode = 0x400010f4; -r_ble_ll_qa_enable = 0x400010f8; -r_ble_ll_rand = 0x400010fc; -r_ble_ll_rand_data_get = 0x40001100; -r_ble_ll_rand_deinit = 0x40001104; -r_ble_ll_rand_env_init = 0x40001108; -r_ble_ll_rand_init = 0x4000110c; -r_ble_ll_rand_prand_get = 0x40001110; -r_ble_ll_rand_sample = 0x40001114; -r_ble_ll_rand_start = 0x40001118; -r_ble_ll_read_local_p256_pub_key = 0x4000111c; -r_ble_ll_read_rf_path_compensation = 0x40001120; -r_ble_ll_read_supp_features = 0x40001124; -r_ble_ll_read_supp_states = 0x40001128; -r_ble_ll_read_tx_power = 0x4000112c; -r_ble_ll_reset = 0x40001130; -r_ble_ll_resolv_clear_all_pl_bit = 0x40001134; -r_ble_ll_resolv_clear_all_wl_bit = 0x40001138; -r_ble_ll_resolv_deinit = 0x4000113c; -r_ble_ll_resolv_enable_cmd = 0x40001140; -r_ble_ll_resolv_enabled = 0x40001144; -r_ble_ll_resolv_env_init = 0x40001148; -r_ble_ll_resolv_gen_priv_addr = 0x4000114c; -r_ble_ll_resolv_gen_rpa = 0x40001150; -r_ble_ll_resolv_get_addr_pointer = 0x40001154; -r_ble_ll_resolv_get_index = 0x40001158; -r_ble_ll_resolv_get_irk_pointer = 0x4000115c; -r_ble_ll_resolv_get_list = 0x40001160; -r_ble_ll_resolv_get_priv_addr = 0x40001164; -r_ble_ll_resolv_get_rpa_tmo = 0x40001168; -r_ble_ll_resolv_init = 0x4000116c; -r_ble_ll_resolv_irk_nonzero = 0x40001170; -r_ble_ll_resolv_list_add = 0x40001174; -r_ble_ll_resolv_list_chg_allowed = 0x40001178; -r_ble_ll_resolv_list_clr = 0x4000117c; -r_ble_ll_resolv_list_find = 0x40001180; -r_ble_ll_resolv_list_read_size = 0x40001184; -r_ble_ll_resolv_list_reset = 0x40001188; -r_ble_ll_resolv_list_rmv = 0x4000118c; -r_ble_ll_resolv_local_addr_rd = 0x40001190; -r_ble_ll_resolv_peer_addr_rd = 0x40001194; -r_ble_ll_resolv_peer_rpa_any = 0x40001198; -r_ble_ll_resolv_reset = 0x4000119c; -r_ble_ll_resolv_rpa = 0x400011a0; -r_ble_ll_resolv_rpa_timer_cb = 0x400011a4; -r_ble_ll_resolv_set_local_rpa = 0x400011a8; -r_ble_ll_resolv_set_peer_rpa = 0x400011ac; -r_ble_ll_resolv_set_rpa_tmo = 0x400011b0; -r_ble_ll_resolve_set_priv_mode = 0x400011b4; -r_ble_ll_rxpdu_alloc = 0x400011b8; -r_ble_ll_scan_add_scan_rsp_adv = 0x400011bc; -r_ble_ll_scan_adv_decode_addr = 0x400011c0; -r_ble_ll_scan_aux_data_ref = 0x400011c4; -r_ble_ll_scan_aux_data_unref = 0x400011c8; -r_ble_ll_scan_can_chg_whitelist = 0x400011cc; -r_ble_ll_scan_check_periodic_sync = 0x400011d0; -r_ble_ll_scan_classify_filter_aux_init = 0x400011d4; -r_ble_ll_scan_classify_filter_init = 0x400011d8; -r_ble_ll_scan_common_init = 0x400011dc; -r_ble_ll_scan_continue_en = 0x400011e0; -r_ble_ll_scan_deinit = 0x400011e4; -r_ble_ll_scan_dup_check_ext = 0x400011e8; -r_ble_ll_scan_dup_check_legacy = 0x400011ec; -r_ble_ll_scan_dup_move_to_head = 0x400011f0; -r_ble_ll_scan_dup_new = 0x400011f4; -r_ble_ll_scan_dup_update_ext = 0x400011f8; -r_ble_ll_scan_dup_update_legacy = 0x400011fc; -r_ble_ll_scan_enabled = 0x40001200; -r_ble_ll_scan_end_adv_evt = 0x40001204; -r_ble_ll_scan_env_init = 0x40001208; -r_ble_ll_scan_ext_initiator_start = 0x4000120c; -r_ble_ll_scan_get_addr_data_from_legacy = 0x40001210; -r_ble_ll_scan_get_addr_from_ext_adv = 0x40001214; -r_ble_ll_scan_get_cur_sm = 0x40001218; -r_ble_ll_scan_get_ext_adv_report = 0x4000121c; -r_ble_ll_scan_get_local_rpa = 0x40001220; -r_ble_ll_scan_get_next_adv_prim_chan = 0x40001224; -r_ble_ll_scan_get_peer_rpa = 0x40001228; -r_ble_ll_scan_have_rxd_scan_rsp = 0x4000122c; -r_ble_ll_scan_init = 0x40001230; -r_ble_ll_scan_initiator_start = 0x40001234; -r_ble_ll_scan_is_inside_window = 0x40001238; -r_ble_ll_scan_move_window_to = 0x4000123c; -r_ble_ll_scan_npl_reset = 0x40001240; -r_ble_ll_scan_parse_auxptr = 0x40001244; -r_ble_ll_scan_parse_ext_hdr = 0x40001248; -r_ble_ll_scan_pre_process = 0x4000124c; -r_ble_ll_scan_record_new_adv = 0x40001250; -r_ble_ll_scan_refresh_nrpa = 0x40001254; -r_ble_ll_scan_reset = 0x40001258; -r_ble_ll_scan_rx_pkt_in = 0x4000125c; -r_ble_ll_scan_rx_pkt_in_on_aux = 0x40001260; -r_ble_ll_scan_rx_pkt_in_on_legacy = 0x40001264; -r_ble_ll_scan_rx_pkt_in_restore_addr_data = 0x40001268; -r_ble_ll_scan_rxed = 0x4000126c; -r_ble_ll_scan_send_adv_report = 0x40001270; -r_ble_ll_scan_send_truncated = 0x40001274; -r_ble_ll_scan_set_enable = 0x40001278; -r_ble_ll_scan_set_peer_rpa = 0x4000127c; -r_ble_ll_scan_set_perfer_addr = 0x40001280; -r_ble_ll_scan_set_scan_params = 0x40001284; -r_ble_ll_scan_sm_start = 0x40001288; -r_ble_ll_scan_sm_stop = 0x4000128c; -r_ble_ll_scan_time_hci_to_ticks = 0x40001290; -r_ble_ll_scan_update_aux_data = 0x40001294; -r_ble_ll_scan_whitelist_enabled = 0x40001298; -r_ble_ll_set_default_privacy_mode = 0x4000129c; -r_ble_ll_set_default_sync_transfer_params = 0x400012a0; -r_ble_ll_set_ext_scan_params = 0x400012a4; -r_ble_ll_set_host_feat = 0x400012a8; -r_ble_ll_set_public_addr = 0x400012ac; -r_ble_ll_set_random_addr = 0x400012b0; -r_ble_ll_set_sync_transfer_params = 0x400012b4; -r_ble_ll_state_get = 0x400012b8; -r_ble_ll_state_set = 0x400012bc; -r_ble_ll_sync_adjust_ext_hdr = 0x400012c0; -r_ble_ll_sync_cancel = 0x400012c4; -r_ble_ll_sync_cancel_complete_event = 0x400012c8; -r_ble_ll_sync_check_acad = 0x400012cc; -r_ble_ll_sync_check_failed = 0x400012d0; -r_ble_ll_sync_create = 0x400012d4; -r_ble_ll_sync_deinit = 0x400012d8; -r_ble_ll_sync_enabled = 0x400012dc; -r_ble_ll_sync_env_init = 0x400012e0; -r_ble_ll_sync_est_event_failed = 0x400012e4; -r_ble_ll_sync_est_event_success = 0x400012e8; -r_ble_ll_sync_established = 0x400012ec; -r_ble_ll_sync_filter_enabled = 0x400012f0; -r_ble_ll_sync_find = 0x400012f4; -r_ble_ll_sync_get_cur_sm = 0x400012f8; -r_ble_ll_sync_get_handle = 0x400012fc; -r_ble_ll_sync_get_sm = 0x40001300; -r_ble_ll_sync_info_event = 0x40001304; -r_ble_ll_sync_init = 0x40001308; -r_ble_ll_sync_list_add = 0x4000130c; -r_ble_ll_sync_list_clear = 0x40001310; -r_ble_ll_sync_list_empty = 0x40001314; -r_ble_ll_sync_list_get_free = 0x40001318; -r_ble_ll_sync_list_remove = 0x4000131c; -r_ble_ll_sync_list_search = 0x40001320; -r_ble_ll_sync_list_size = 0x40001324; -r_ble_ll_sync_lost_event = 0x40001328; -r_ble_ll_sync_next_event = 0x4000132c; -r_ble_ll_sync_on_list = 0x40001330; -r_ble_ll_sync_parse_ext_hdr = 0x40001334; -r_ble_ll_sync_periodic_ind = 0x40001338; -r_ble_ll_sync_phy_mode_to_aux_phy = 0x4000133c; -r_ble_ll_sync_phy_mode_to_hci = 0x40001340; -r_ble_ll_sync_put_syncinfo = 0x40001344; -r_ble_ll_sync_receive_enable = 0x40001348; -r_ble_ll_sync_reserve = 0x4000134c; -r_ble_ll_sync_reset = 0x40001350; -r_ble_ll_sync_reset_sm = 0x40001354; -r_ble_ll_sync_rx_pkt_in = 0x40001358; -r_ble_ll_sync_send_per_adv_rpt = 0x4000135c; -r_ble_ll_sync_send_sync_ind = 0x40001360; -r_ble_ll_sync_send_truncated_per_adv_rpt = 0x40001364; -r_ble_ll_sync_sm_clear = 0x40001368; -r_ble_ll_sync_terminate = 0x4000136c; -r_ble_ll_sync_transfer = 0x40001370; -r_ble_ll_sync_transfer_get = 0x40001374; -r_ble_ll_sync_transfer_received = 0x40001378; -r_ble_ll_task = 0x4000137c; -r_ble_ll_trace_set_func = 0x40001380; -r_ble_ll_trace_u32 = 0x40001384; -r_ble_ll_trace_u32x2 = 0x40001388; -r_ble_ll_trace_u32x3 = 0x4000138c; -r_ble_ll_tx_flat_mbuf_pducb = 0x40001390; -r_ble_ll_tx_mbuf_pducb = 0x40001394; -r_ble_ll_tx_pkt_in = 0x40001398; -r_ble_ll_update_max_tx_octets_phy_mode = 0x4000139c; -r_ble_ll_usecs_to_ticks_round_up = 0x400013a0; -r_ble_ll_utils_calc_access_addr = 0x400013a4; -r_ble_ll_utils_calc_dci_csa2 = 0x400013a8; -r_ble_ll_utils_calc_num_used_chans = 0x400013ac; -r_ble_ll_utils_calc_window_widening = 0x400013b0; -r_ble_ll_utils_csa2_perm = 0x400013b4; -r_ble_ll_utils_csa2_prng = 0x400013b8; -r_ble_ll_utils_remapped_channel = 0x400013bc; -r_ble_ll_whitelist_add = 0x400013c0; -r_ble_ll_whitelist_chg_allowed = 0x400013c4; -r_ble_ll_whitelist_clear = 0x400013c8; -r_ble_ll_whitelist_read_size = 0x400013cc; -r_ble_ll_whitelist_rmv = 0x400013d0; -r_ble_ll_whitelist_search = 0x400013d4; -r_ble_ll_write_rf_path_compensation = 0x400013d8; -r_ble_lll_adv_aux_scannable_pdu_payload_len = 0x400013dc; -r_ble_lll_adv_aux_schedule = 0x400013e0; -r_ble_lll_adv_aux_schedule_first = 0x400013e4; -r_ble_lll_adv_aux_schedule_next = 0x400013e8; -r_ble_lll_adv_aux_scheduled = 0x400013ec; -r_ble_lll_adv_aux_set_start_time = 0x400013f0; -r_ble_lll_adv_coex_dpc_calc_pti_update_itvl = 0x400013f4; -r_ble_lll_adv_coex_dpc_process_pri = 0x400013f8; -r_ble_lll_adv_coex_dpc_process_sec = 0x400013fc; -r_ble_lll_adv_coex_dpc_pti_get = 0x40001400; -r_ble_lll_adv_coex_dpc_update = 0x40001404; -r_ble_lll_adv_coex_dpc_update_on_adv_start = 0x40001408; -r_ble_lll_adv_coex_dpc_update_on_aux_scheduled = 0x4000140c; -r_ble_lll_adv_coex_dpc_update_on_data_updated = 0x40001410; -r_ble_lll_adv_coex_dpc_update_on_event_end = 0x40001414; -r_ble_lll_adv_coex_dpc_update_on_event_scheduled = 0x40001418; -r_ble_lll_adv_done = 0x4000141c; -r_ble_lll_adv_drop_event = 0x40001420; -r_ble_lll_adv_event_done = 0x40001424; -r_ble_lll_adv_event_rmvd_from_sched = 0x40001428; -r_ble_lll_adv_ext_estimate_data_itvl = 0x4000142c; -r_ble_lll_adv_get_sec_pdu_len = 0x40001430; -r_ble_lll_adv_halt = 0x40001434; -r_ble_lll_adv_make_done = 0x40001438; -r_ble_lll_adv_periodic_done = 0x4000143c; -r_ble_lll_adv_periodic_event_done = 0x40001440; -r_ble_lll_adv_periodic_rmvd_from_sched = 0x40001444; -r_ble_lll_adv_periodic_schedule_first = 0x40001448; -r_ble_lll_adv_periodic_schedule_next = 0x4000144c; -r_ble_lll_adv_periodic_start = 0x40001450; -r_ble_lll_adv_periodic_stop = 0x40001454; -r_ble_lll_adv_pri_schedule_tx_pdu = 0x40001458; -r_ble_lll_adv_reschedule_event = 0x4000145c; -r_ble_lll_adv_reschedule_periodic_event = 0x40001460; -r_ble_lll_adv_rx_pkt_isr = 0x40001464; -r_ble_lll_adv_sec_done = 0x40001468; -r_ble_lll_adv_sec_event_done = 0x4000146c; -r_ble_lll_adv_sec_schedule_next_aux = 0x40001470; -r_ble_lll_adv_secondary_tx_start_cb = 0x40001474; -r_ble_lll_adv_sm_deinit = 0x40001478; -r_ble_lll_adv_sm_event_init = 0x4000147c; -r_ble_lll_adv_sm_event_restore = 0x40001480; -r_ble_lll_adv_sm_event_store = 0x40001484; -r_ble_lll_adv_sm_init = 0x40001488; -r_ble_lll_adv_sm_reset = 0x4000148c; -r_ble_lll_adv_start = 0x40001490; -r_ble_lll_adv_stop = 0x40001494; -r_ble_lll_adv_sync_next_scheduled = 0x40001498; -r_ble_lll_adv_sync_schedule = 0x4000149c; -r_ble_lll_adv_sync_tx_done = 0x400014a0; -r_ble_lll_adv_sync_tx_end = 0x400014a4; -r_ble_lll_adv_sync_tx_start_cb = 0x400014a8; -r_ble_lll_adv_tx_done = 0x400014ac; -r_ble_lll_adv_tx_start_cb = 0x400014b0; -r_ble_lll_adv_update_rsp_offset = 0x400014b4; -r_ble_lll_aux_scan_cb = 0x400014b8; -r_ble_lll_aux_scan_drop = 0x400014bc; -r_ble_lll_aux_scan_drop_event_cb = 0x400014c0; -r_ble_lll_calc_us_convert_tick_unit = 0x400014c4; -r_ble_lll_conn_append_tx_buffer = 0x400014c8; -r_ble_lll_conn_can_send_next_pdu = 0x400014cc; -r_ble_lll_conn_check_opcode_matched = 0x400014d0; -r_ble_lll_conn_coex_dpc_process = 0x400014d4; -r_ble_lll_conn_coex_dpc_pti_get = 0x400014d8; -r_ble_lll_conn_coex_dpc_update = 0x400014dc; -r_ble_lll_conn_coex_dpc_update_on_event_end = 0x400014e0; -r_ble_lll_conn_coex_dpc_update_on_event_scheduled = 0x400014e4; -r_ble_lll_conn_coex_dpc_update_on_event_started = 0x400014e8; -r_ble_lll_conn_cth_flow_alloc_credit = 0x400014ec; -r_ble_lll_conn_cth_flow_free_credit = 0x400014f0; -r_ble_lll_conn_current_sm_over = 0x400014f4; -r_ble_lll_conn_end = 0x400014f8; -r_ble_lll_conn_env_deinit = 0x400014fc; -r_ble_lll_conn_env_init = 0x40001500; -r_ble_lll_conn_event_end = 0x40001504; -r_ble_lll_conn_event_end_timer_cb = 0x40001508; -r_ble_lll_conn_event_halt = 0x4000150c; -r_ble_lll_conn_event_is_over = 0x40001510; -r_ble_lll_conn_event_start_cb = 0x40001514; -r_ble_lll_conn_free_rx_mbuf = 0x40001518; -r_ble_lll_conn_get_addr_info_from_rx_buf = 0x4000151c; -r_ble_lll_conn_get_ce_end_time = 0x40001520; -r_ble_lll_conn_get_next_sched_time = 0x40001524; -r_ble_lll_conn_get_rx_mbuf = 0x40001528; -r_ble_lll_conn_halt = 0x4000152c; -r_ble_lll_conn_master_common_init = 0x40001530; -r_ble_lll_conn_master_new = 0x40001534; -r_ble_lll_conn_module_deinit = 0x40001538; -r_ble_lll_conn_module_init = 0x4000153c; -r_ble_lll_conn_module_reset = 0x40001540; -r_ble_lll_conn_no_mem_evt_pre_cb = 0x40001544; -r_ble_lll_conn_pre_process = 0x40001548; -r_ble_lll_conn_process_acked_pdu = 0x4000154c; -r_ble_lll_conn_process_in_isr = 0x40001550; -r_ble_lll_conn_recv_ack = 0x40001554; -r_ble_lll_conn_recv_valid_packet = 0x40001558; -r_ble_lll_conn_reset_pending_sched = 0x4000155c; -r_ble_lll_conn_rx_pkt_isr = 0x40001560; -r_ble_lll_conn_sched_next_anchor = 0x40001564; -r_ble_lll_conn_sched_next_event = 0x40001568; -r_ble_lll_conn_set_slave_flow_control = 0x4000156c; -r_ble_lll_conn_slave_new = 0x40001570; -r_ble_lll_conn_sm_new = 0x40001574; -r_ble_lll_conn_sm_npl_deinit = 0x40001578; -r_ble_lll_conn_sm_npl_init = 0x4000157c; -r_ble_lll_conn_superversion_timer_cb = 0x40001580; -r_ble_lll_conn_timeout = 0x40001584; -r_ble_lll_conn_update_anchor = 0x40001588; -r_ble_lll_conn_update_conn_ind_params = 0x4000158c; -r_ble_lll_conn_update_encryption = 0x40001590; -r_ble_lll_conn_update_tx_buffer = 0x40001594; -r_ble_lll_deinit = 0x40001598; -r_ble_lll_dtm_calculate_itvl = 0x4000159c; -r_ble_lll_dtm_ctx_free = 0x400015a0; -r_ble_lll_dtm_deinit = 0x400015a4; -r_ble_lll_dtm_end_test = 0x400015a8; -r_ble_lll_dtm_ev_rx_restart_cb = 0x400015ac; -r_ble_lll_dtm_ev_tx_resched_cb = 0x400015b0; -r_ble_lll_dtm_init = 0x400015b4; -r_ble_lll_dtm_reset = 0x400015b8; -r_ble_lll_dtm_rx_create_ctx = 0x400015bc; -r_ble_lll_dtm_rx_isr_end = 0x400015c0; -r_ble_lll_dtm_rx_isr_start = 0x400015c4; -r_ble_lll_dtm_rx_pkt_in = 0x400015c8; -r_ble_lll_dtm_rx_sched_cb = 0x400015cc; -r_ble_lll_dtm_rx_start = 0x400015d0; -r_ble_lll_dtm_rx_test = 0x400015d4; -r_ble_lll_dtm_set_next = 0x400015d8; -r_ble_lll_dtm_tx_create_ctx = 0x400015dc; -r_ble_lll_dtm_tx_done = 0x400015e0; -r_ble_lll_dtm_tx_sched_cb = 0x400015e4; -r_ble_lll_dtm_tx_test = 0x400015e8; -r_ble_lll_dtm_wfr_timer_exp = 0x400015ec; -r_ble_lll_event_rx_pkt = 0x400015f0; -r_ble_lll_ext_scan_coex_dpc_process = 0x400015f4; -r_ble_lll_ext_scan_coex_dpc_pti_get = 0x400015f8; -r_ble_lll_ext_scan_coex_dpc_update = 0x400015fc; -r_ble_lll_ext_scan_coex_dpc_update_on_start = 0x40001600; -r_ble_lll_hci_dtm_rx_test = 0x40001604; -r_ble_lll_hci_dtm_rx_test_v2 = 0x40001608; -r_ble_lll_hci_dtm_tx_test = 0x4000160c; -r_ble_lll_hci_dtm_tx_test_ext = 0x40001610; -r_ble_lll_hci_dtm_tx_test_v2 = 0x40001614; -r_ble_lll_hci_dtm_tx_test_v2_ext = 0x40001618; -r_ble_lll_init = 0x4000161c; -r_ble_lll_init_pre_process = 0x40001620; -r_ble_lll_init_rx_pkt_isr = 0x40001624; -r_ble_lll_per_adv_coex_dpc_calc_pti_update_itvl = 0x40001628; -r_ble_lll_per_adv_coex_dpc_process = 0x4000162c; -r_ble_lll_per_adv_coex_dpc_pti_get = 0x40001630; -r_ble_lll_per_adv_coex_dpc_update = 0x40001634; -r_ble_lll_per_adv_coex_dpc_update_on_data_updated = 0x40001638; -r_ble_lll_per_adv_coex_dpc_update_on_scheduled = 0x4000163c; -r_ble_lll_per_adv_coex_dpc_update_on_start = 0x40001640; -r_ble_lll_reset = 0x40001644; -r_ble_lll_rfmgmt_controller_sleep_en = 0x40001648; -r_ble_lll_rfmgmt_deinit = 0x4000164c; -r_ble_lll_rfmgmt_disable = 0x40001650; -r_ble_lll_rfmgmt_enable = 0x40001654; -r_ble_lll_rfmgmt_enable_now = 0x40001658; -r_ble_lll_rfmgmt_init = 0x4000165c; -r_ble_lll_rfmgmt_is_enabled = 0x40001660; -r_ble_lll_rfmgmt_release = 0x40001664; -r_ble_lll_rfmgmt_release_ev = 0x40001668; -r_ble_lll_rfmgmt_reset = 0x4000166c; -r_ble_lll_rfmgmt_scan_changed = 0x40001670; -r_ble_lll_rfmgmt_sched_changed = 0x40001674; -r_ble_lll_rfmgmt_set_sleep_cb = 0x40001678; -r_ble_lll_rfmgmt_ticks_to_enabled = 0x4000167c; -r_ble_lll_rfmgmt_timer_exp = 0x40001680; -r_ble_lll_rfmgmt_timer_reschedule = 0x40001684; -r_ble_lll_rx_pdu_in = 0x40001688; -r_ble_lll_rx_pkt_in = 0x4000168c; -r_ble_lll_rx_pkt_isr = 0x40001690; -r_ble_lll_scan_abort_aux_sched = 0x40001694; -r_ble_lll_scan_aux_data_free = 0x40001698; -r_ble_lll_scan_chk_resume = 0x4000169c; -r_ble_lll_scan_clean_cur_aux_data = 0x400016a0; -r_ble_lll_scan_coex_event_cb = 0x400016a4; -r_ble_lll_scan_common_init = 0x400016a8; -r_ble_lll_scan_deinit = 0x400016ac; -r_ble_lll_scan_duration_period_timers_restart = 0x400016b0; -r_ble_lll_scan_duration_period_timers_stop = 0x400016b4; -r_ble_lll_scan_duration_timer_cb = 0x400016b8; -r_ble_lll_scan_event_proc = 0x400016bc; -r_ble_lll_scan_ext_adv_init = 0x400016c0; -r_ble_lll_scan_halt = 0x400016c4; -r_ble_lll_scan_has_sent_scan_req = 0x400016c8; -r_ble_lll_scan_init = 0x400016cc; -r_ble_lll_scan_npl_init = 0x400016d0; -r_ble_lll_scan_npl_reset = 0x400016d4; -r_ble_lll_scan_npl_restore = 0x400016d8; -r_ble_lll_scan_npl_store = 0x400016dc; -r_ble_lll_scan_period_timer_cb = 0x400016e0; -r_ble_lll_scan_process_adv_in_isr = 0x400016e4; -r_ble_lll_scan_process_rsp_in_isr = 0x400016e8; -r_ble_lll_scan_req_backoff = 0x400016ec; -r_ble_lll_scan_restart = 0x400016f0; -r_ble_lll_scan_rx_isr_on_aux = 0x400016f4; -r_ble_lll_scan_rx_isr_on_legacy = 0x400016f8; -r_ble_lll_scan_rx_pkt_isr = 0x400016fc; -r_ble_lll_scan_sched_next_aux = 0x40001700; -r_ble_lll_scan_sched_remove = 0x40001704; -r_ble_lll_scan_start = 0x40001708; -r_ble_lll_scan_start_rx = 0x4000170c; -r_ble_lll_scan_stop = 0x40001710; -r_ble_lll_scan_targeta_is_matched = 0x40001714; -r_ble_lll_scan_timer_cb = 0x40001718; -r_ble_lll_sched_adv_new = 0x4000171c; -r_ble_lll_sched_adv_resched_pdu = 0x40001720; -r_ble_lll_sched_adv_reschedule = 0x40001724; -r_ble_lll_sched_aux_scan = 0x40001728; -r_ble_lll_sched_conn_overlap = 0x4000172c; -r_ble_lll_sched_conn_reschedule = 0x40001730; -r_ble_lll_sched_deinit = 0x40001734; -r_ble_lll_sched_dtm = 0x40001738; -r_ble_lll_sched_env_init = 0x4000173c; -r_ble_lll_sched_execute_check = 0x40001740; -r_ble_lll_sched_execute_item = 0x40001744; -r_ble_lll_sched_init = 0x40001748; -r_ble_lll_sched_insert_if_empty = 0x4000174c; -r_ble_lll_sched_is_overlap = 0x40001750; -r_ble_lll_sched_master_new = 0x40001754; -r_ble_lll_sched_next_time = 0x40001758; -r_ble_lll_sched_overlaps_current = 0x4000175c; -r_ble_lll_sched_periodic_adv = 0x40001760; -r_ble_lll_sched_rmv_elem = 0x40001764; -r_ble_lll_sched_rmv_elem_type = 0x40001768; -r_ble_lll_sched_run = 0x4000176c; -r_ble_lll_sched_scan_req_over_aux_ptr = 0x40001770; -r_ble_lll_sched_slave_new = 0x40001774; -r_ble_lll_sched_stop = 0x40001778; -r_ble_lll_sched_sync = 0x4000177c; -r_ble_lll_sched_sync_overlaps_current = 0x40001780; -r_ble_lll_sched_sync_reschedule = 0x40001784; -r_ble_lll_sync_chain_start_cb = 0x40001788; -r_ble_lll_sync_coex_dpc_process = 0x4000178c; -r_ble_lll_sync_coex_dpc_pti_get = 0x40001790; -r_ble_lll_sync_coex_dpc_update = 0x40001794; -r_ble_lll_sync_current_sm_over = 0x40001798; -r_ble_lll_sync_deinit = 0x4000179c; -r_ble_lll_sync_event_end = 0x400017a0; -r_ble_lll_sync_event_end_cb = 0x400017a4; -r_ble_lll_sync_event_start_cb = 0x400017a8; -r_ble_lll_sync_get_event_end_time = 0x400017ac; -r_ble_lll_sync_halt = 0x400017b0; -r_ble_lll_sync_init = 0x400017b4; -r_ble_lll_sync_new = 0x400017b8; -r_ble_lll_sync_reset = 0x400017bc; -r_ble_lll_sync_reset_sm = 0x400017c0; -r_ble_lll_sync_rmvd_from_sched = 0x400017c4; -r_ble_lll_sync_rx_pkt_isr = 0x400017c8; -r_ble_lll_sync_schedule_chain = 0x400017cc; -r_ble_lll_sync_stop = 0x400017d0; -r_ble_lll_sync_trnasfer_sched = 0x400017d4; -r_ble_phy_access_addr_get = 0x400017d8; -r_ble_phy_calculate_rxtx_ifs = 0x400017dc; -r_ble_phy_calculate_rxwindow = 0x400017e0; -r_ble_phy_calculate_txrx_ifs = 0x400017e4; -r_ble_phy_check_bb_status = 0x400017e8; -r_ble_phy_complete_rx_info = 0x400017ec; -r_ble_phy_config_access_addr = 0x400017f0; -r_ble_phy_data_make = 0x400017f4; -r_ble_phy_disable = 0x400017f8; -r_ble_phy_disable_irq = 0x400017fc; -r_ble_phy_disable_whitening = 0x40001800; -r_ble_phy_enable_whitening = 0x40001804; -r_ble_phy_encrypt_disable = 0x40001808; -r_ble_phy_env_init = 0x4000180c; -r_ble_phy_get_current_phy = 0x40001810; -r_ble_phy_get_packet_counter = 0x40001814; -r_ble_phy_get_packet_status = 0x40001818; -r_ble_phy_get_pyld_time_offset = 0x4000181c; -r_ble_phy_get_rx_phy_mode = 0x40001820; -r_ble_phy_get_seq_end_st = 0x40001824; -r_ble_phy_init = 0x40001828; -r_ble_phy_isr = 0x4000182c; -r_ble_phy_max_data_pdu_pyld = 0x40001830; -r_ble_phy_mode_config = 0x40001834; -r_ble_phy_mode_convert = 0x40001838; -r_ble_phy_mode_write = 0x4000183c; -r_ble_phy_module_deinit = 0x40001840; -r_ble_phy_module_init = 0x40001844; -r_ble_phy_monitor_bb_sync = 0x40001848; -r_ble_phy_reset_bb_monitor = 0x4000184c; -r_ble_phy_resolv_list_disable = 0x40001850; -r_ble_phy_resolv_list_enable = 0x40001854; -r_ble_phy_restart_sequence = 0x40001858; -r_ble_phy_rx_set_start_time_forcibly = 0x4000185c; -r_ble_phy_rxpdu_copy = 0x40001860; -r_ble_phy_seq_encrypt_enable = 0x40001864; -r_ble_phy_seq_encrypt_set_pkt_cntr = 0x40001868; -r_ble_phy_sequence_end_isr = 0x4000186c; -r_ble_phy_sequence_get_mode = 0x40001870; -r_ble_phy_sequence_is_running = 0x40001874; -r_ble_phy_sequence_is_waiting_rsp = 0x40001878; -r_ble_phy_sequence_single_end = 0x4000187c; -r_ble_phy_sequence_tx_end_invoke = 0x40001880; -r_ble_phy_sequence_update_conn_ind_params = 0x40001884; -r_ble_phy_set_adv_mode = 0x40001888; -r_ble_phy_set_coex_pti = 0x4000188c; -r_ble_phy_set_conn_ind_pdu = 0x40001890; -r_ble_phy_set_conn_mode = 0x40001894; -r_ble_phy_set_dev_address = 0x40001898; -r_ble_phy_set_rx_pwr_compensation = 0x4000189c; -r_ble_phy_set_rxhdr = 0x400018a0; -r_ble_phy_set_scan_mode = 0x400018a4; -r_ble_phy_set_sequence_mode = 0x400018a8; -r_ble_phy_set_single_packet_rx_sequence = 0x400018ac; -r_ble_phy_set_single_packet_tx_sequence = 0x400018b0; -r_ble_phy_set_tx_rx_transition = 0x400018b4; -r_ble_phy_set_txend_cb = 0x400018b8; -r_ble_phy_setchan = 0x400018bc; -r_ble_phy_start_rx_immediately = 0x400018c0; -r_ble_phy_state_get = 0x400018c4; -r_ble_phy_timer_config_start_time = 0x400018c8; -r_ble_phy_timer_start_now = 0x400018cc; -r_ble_phy_timer_stop = 0x400018d0; -r_ble_phy_tx_set_start_time = 0x400018d4; -r_ble_phy_txpower_round = 0x400018d8; -r_ble_phy_txpwr_set = 0x400018dc; -r_ble_phy_update_conn_sequence = 0x400018e0; -r_ble_phy_update_encryption = 0x400018e4; -r_ble_phy_update_ifs = 0x400018e8; -r_ble_phy_xcvr_state_get = 0x400018ec; -r_ble_plf_set_log_level = 0x400018f0; -r_ble_rtc_wake_up_cpu_init = 0x400018f4; -r_ble_rtc_wake_up_state_clr = 0x400018f8; -r_ble_vendor_hci_register = 0x400018fc; -r_bt_rf_coex_cfg_set = 0x40001900; -r_bt_rf_coex_coded_txrx_time_upper_lim = 0x40001904; -r_bt_rf_coex_dft_pti_set = 0x40001908; -r_bt_rf_coex_hook_deinit = 0x4000190c; -r_bt_rf_coex_hook_init = 0x40001910; -r_bt_rf_coex_hook_st_set = 0x40001914; -r_bt_rf_coex_hooks_p_set_default = 0x40001918; -r_btdm_disable_adv_delay = 0x4000191c; -r_btdm_switch_phy_coded = 0x40001920; -r_esp_wait_disabled = 0x40001924; -r_get_be16 = 0x40001928; -r_get_be24 = 0x4000192c; -r_get_be32 = 0x40001930; -r_get_be64 = 0x40001934; -r_get_le16 = 0x40001938; -r_get_le24 = 0x4000193c; -r_get_le32 = 0x40001940; -r_get_le64 = 0x40001944; -r_get_local_irk_offset = 0x40001948; -r_get_local_rpa_offset = 0x4000194c; -r_get_max_skip = 0x40001950; -r_get_peer_id_offset = 0x40001954; -r_get_peer_irk_offset = 0x40001958; -r_get_peer_rpa_offset = 0x4000195c; -r_hal_rtc_intr_init = 0x40001960; -r_hal_rtc_irq_handler = 0x40001964; -r_hal_timer_deinit = 0x40001968; -r_hal_timer_disable_irq = 0x4000196c; -r_hal_timer_env_init = 0x40001970; -r_hal_timer_init = 0x40001974; -r_hal_timer_process = 0x40001978; -r_hal_timer_read = 0x4000197c; -r_hal_timer_read_tick = 0x40001980; -r_hal_timer_set_cb = 0x40001984; -r_hal_timer_set_exp_tick = 0x40001988; -r_hal_timer_start = 0x4000198c; -r_hal_timer_start_at = 0x40001990; -r_hal_timer_stop = 0x40001994; -r_hal_timer_task_start = 0x40001998; -r_ll_assert = 0x4000199c; -r_mem_init_mbuf_pool = 0x400019a0; -r_mem_malloc_mbuf_pool = 0x400019a4; -r_mem_malloc_mbufpkt_pool = 0x400019a8; -r_mem_malloc_mempool = 0x400019ac; -r_mem_malloc_mempool_ext = 0x400019b0; -r_mem_malloc_mempool_gen = 0x400019b4; -r_mem_pullup_obj = 0x400019b8; -r_mem_split_frag = 0x400019bc; -r_os_cputime_get32 = 0x400019c0; -r_os_cputime_ticks_to_usecs = 0x400019c4; -r_os_cputime_timer_init = 0x400019c8; -r_os_cputime_timer_relative = 0x400019cc; -r_os_cputime_timer_start = 0x400019d0; -r_os_cputime_timer_stop = 0x400019d4; -r_os_cputime_usecs_to_ticks = 0x400019d8; -r_os_mbuf_adj = 0x400019dc; -r_os_mbuf_append = 0x400019e0; -r_os_mbuf_appendfrom = 0x400019e4; -r_os_mbuf_cmpf = 0x400019e8; -r_os_mbuf_cmpm = 0x400019ec; -r_os_mbuf_concat = 0x400019f0; -r_os_mbuf_copydata = 0x400019f4; -r_os_mbuf_copyinto = 0x400019f8; -r_os_mbuf_dup = 0x400019fc; -r_os_mbuf_extend = 0x40001a00; -r_os_mbuf_free = 0x40001a04; -r_os_mbuf_free_chain = 0x40001a08; -r_os_mbuf_get = 0x40001a0c; -r_os_mbuf_get_pkthdr = 0x40001a10; -r_os_mbuf_leadingspace = 0x40001a14; -r_os_mbuf_len = 0x40001a18; -r_os_mbuf_off = 0x40001a1c; -r_os_mbuf_pack_chains = 0x40001a20; -r_os_mbuf_pool_init = 0x40001a24; -r_os_mbuf_prepend = 0x40001a28; -r_os_mbuf_prepend_pullup = 0x40001a2c; -r_os_mbuf_pullup = 0x40001a30; -r_os_mbuf_trailingspace = 0x40001a34; -r_os_mbuf_trim_front = 0x40001a38; -r_os_mbuf_widen = 0x40001a3c; -r_os_memblock_from = 0x40001a40; -r_os_memblock_get = 0x40001a44; -r_os_memblock_put = 0x40001a48; -r_os_memblock_put_from_cb = 0x40001a4c; -r_os_mempool_clear = 0x40001a50; -r_os_mempool_ext_clear = 0x40001a54; -r_os_mempool_ext_init = 0x40001a58; -r_os_mempool_info_get_next = 0x40001a5c; -r_os_mempool_init = 0x40001a60; -r_os_mempool_init_internal = 0x40001a64; -r_os_mempool_is_sane = 0x40001a68; -r_os_mempool_module_init = 0x40001a6c; -r_os_mempool_unregister = 0x40001a70; -r_os_mqueue_get = 0x40001a74; -r_os_mqueue_init = 0x40001a78; -r_os_mqueue_put = 0x40001a7c; -r_os_msys_count = 0x40001a80; -r_os_msys_get = 0x40001a84; -r_os_msys_get_pkthdr = 0x40001a88; -r_os_msys_num_free = 0x40001a8c; -r_os_msys_register = 0x40001a90; -r_os_msys_reset = 0x40001a94; -r_pri_phy_valid = 0x40001a98; -r_put_be16 = 0x40001a9c; -r_put_be24 = 0x40001aa0; -r_put_be32 = 0x40001aa4; -r_put_be64 = 0x40001aa8; -r_put_le16 = 0x40001aac; -r_put_le24 = 0x40001ab0; -r_put_le32 = 0x40001ab4; -r_put_le64 = 0x40001ab8; -r_rtc0_timer_handler = 0x40001abc; -r_sdkconfig_get_opts = 0x40001ac0; -r_sdkconfig_set_opts = 0x40001ac4; -r_sec_phy_valid = 0x40001ac8; -r_swap_buf = 0x40001acc; -r_swap_in_place = 0x40001ad0; -/* Data (.data, .bss, .rodata) */ -ble_lll_dtm_module_env_p = 0x3fcdffc4; -g_ble_lll_dtm_prbs15_data = 0x3ff4fee4; -g_ble_lll_dtm_prbs9_data = 0x3ff4fde4; -g_channel_rf_to_index = 0x3ff4fdbc; -g_ble_lll_rfmgmt_data = 0x3fcdff7c; -g_ble_sleep_enter_cb = 0x3fcdff78; -g_ble_sleep_exit_cb = 0x3fcdff74; -ble_lll_sched_env_p = 0x3fcdff70; -ble_ll_env_p = 0x3fcdff6c; -g_ble_ll_pdu_header_tx_time_ro = 0x3ff4fdb4; -ble_ll_adv_env_p = 0x3fcdff68; -ble_ll_conn_env_p = 0x3fcdff64; -ble_ll_conn_required_phy_mask = 0x3ff4fdb0; -ble_ll_valid_conn_phy_mask = 0x3ff4fdaf; -g_ble_ll_ctrl_pkt_lengths_ro = 0x3ff4fd8c; -ble_ll_hci_env_p = 0x3fcdff60; -g_debug_le_private_key = 0x3ff4fd6c; -g_ecc_key = 0x3fcdfefc; -ble_ll_rand_env_p = 0x3fcdfef8; -ble_ll_resolv_env_p = 0x3fcdfef4; -g_ble_ll_resolve_hdr = 0x3fcdfeec; -g_device_mode_default = 0x3fcdfe68; -ble_ll_scan_classify_filter_aux_check_cb = 0x3fcdfee8; -ble_ll_scan_classify_filter_check_cb = 0x3fcdfee4; -ble_ll_scan_env_p = 0x3fcdfee0; -g_ble_ll_supp_cmds_ro = 0x3ff4fd3c; -ble_ll_sync_env_p = 0x3fcdfedc; -g_ble_sca_ppm_tbl_ro = 0x3ff4fd2c; -priv_config_opts = 0x3fcdfe48; -ble_hci_uart_reset_cmd = 0x3ff4fd28; -ble_hci_trans_env_p = 0x3fcdfed8; -ble_hci_trans_mode = 0x3fcdfe44; -ble_hci_trans_funcs_ptr = 0x3fcdfed4; -r_ble_lll_stub_funcs_ptr = 0x3fcdfed0; -r_ble_stub_funcs_ptr = 0x3fcdfecc; -r_ext_funcs_p = 0x3fcdfec8; -r_npl_funcs = 0x3fcdfec4; -ble_hw_env_p = 0x3fcdfec0; -ble_phy_module_env_p = 0x3fcdfebc; -g_ble_phy_chan_freq_ro = 0x3ff4fd00; -g_ble_phy_mode_pkt_start_off_ro = 0x3ff4fcf8; -g_ble_phy_rxtx_ifs_compensation_ro = 0x3ff4fce8; -g_ble_phy_t_rxaddrdelay_ro = 0x3ff4fce4; -g_ble_phy_t_rxenddelay_ro = 0x3ff4fce0; -g_ble_phy_t_txdelay_ro = 0x3ff4fcdc; -g_ble_phy_t_txenddelay_ro = 0x3ff4fcd8; -g_ble_phy_txrx_ifs_compensation_ro = 0x3ff4fcc8; -hal_timer_env_p = 0x3fcdfeb8; -r_osi_coex_funcs_p = 0x3fcdfeb4; -bt_rf_coex_hooks = 0x3fcdfeac; -bt_rf_coex_hooks_p = 0x3fcdfea8; -coex_hook_st_group_tab = 0x3ff4fcbc; -coex_hook_st_group_to_coex_schm_st_tab = 0x3ff4fcb8; -s_ble_act_count_by_group = 0x3fcdfea4; -s_ble_coex_st_map = 0x3fcdfe90; -bt_rf_coex_cfg_cb = 0x3fcdfe74; -bt_rf_coex_cfg_p = 0x3fcdfe70; -bt_rf_coex_cfg_rom = 0x3ff4fc9c; -bt_rf_coex_pti_dft_p = 0x3fcdfe6c; -bt_rf_coex_pti_dft_rom = 0x3fcdfe04; -conn_dynamic_pti_param_rom = 0x3ff4fc84; -conn_phy_coded_max_data_time_param_rom = 0x3ff4fc80; -ext_adv_dynamic_pti_param_rom = 0x3ff4fc4c; -ext_scan_dynamic_param_rom = 0x3ff4fc14; -legacy_adv_dynamic_pti_param_rom = 0x3ff4fbf4; -per_adv_dynamic_pti_param_rom = 0x3ff4fbd8; -sync_dynamic_param_rom = 0x3ff4fbc0; -g_ble_plf_log_level = 0x3fcdfe00; -g_msys_pool_list = 0x3fcdfdf8; -g_os_mempool_list = 0x3fcdfdf0; - - -/*************************************** - Group rom_pp - ***************************************/ - -/* Functions */ -esp_pp_rom_version_get = 0x40001ad4; -RC_GetBlockAckTime = 0x40001ad8; -ebuf_list_remove = 0x40001adc; -esf_buf_alloc = 0x40001ae0; -esf_buf_alloc_dynamic = 0x40001ae4; -esf_buf_recycle = 0x40001ae8; -GetAccess = 0x40001aec; -hal_mac_is_low_rate_enabled = 0x40001af0; -hal_mac_tx_get_blockack = 0x40001af4; -hal_mac_tx_set_ppdu = 0x40001af8; -ic_get_trc = 0x40001afc; -ic_mac_deinit = 0x40001b00; -ic_mac_init = 0x40001b04; -ic_interface_enabled = 0x40001b08; -is_lmac_idle = 0x40001b0c; -lmacAdjustTimestamp = 0x40001b10; -lmacDiscardAgedMSDU = 0x40001b14; -lmacDiscardMSDU = 0x40001b18; -lmacEndFrameExchangeSequence = 0x40001b1c; -lmacIsIdle = 0x40001b20; -lmacIsLongFrame = 0x40001b24; -lmacMSDUAged = 0x40001b28; -lmacPostTxComplete = 0x40001b2c; -lmacProcessAllTxTimeout = 0x40001b30; -lmacProcessCollisions = 0x40001b34; -lmacProcessRxSucData = 0x40001b38; -lmacReachLongLimit = 0x40001b3c; -lmacReachShortLimit = 0x40001b40; -lmacRecycleMPDU = 0x40001b44; -lmacRxDone = 0x40001b48; -lmacSetTxFrame = 0x40001b4c; -lmacTxDone = 0x40001b50; -lmacTxFrame = 0x40001b54; -mac_tx_set_duration = 0x40001b58; -mac_tx_set_htsig = 0x40001b5c; -mac_tx_set_plcp0 = 0x40001b60; -mac_tx_set_plcp1 = 0x40001b64; -mac_tx_set_plcp2 = 0x40001b68; -pm_check_state = 0x40001b6c; -pm_disable_dream_timer = 0x40001b70; -pm_disable_sleep_delay_timer = 0x40001b74; -pm_dream = 0x40001b78; -pm_mac_wakeup = 0x40001b7c; -pm_mac_sleep = 0x40001b80; -pm_enable_active_timer = 0x40001b84; -pm_enable_sleep_delay_timer = 0x40001b88; -pm_local_tsf_process = 0x40001b8c; -pm_set_beacon_filter = 0x40001b90; -pm_is_in_wifi_slice_threshold = 0x40001b94; -pm_is_waked = 0x40001b98; -pm_keep_alive = 0x40001b9c; -pm_on_beacon_rx = 0x40001ba0; -pm_on_data_rx = 0x40001ba4; -pm_on_tbtt = 0x40001ba8; -pm_parse_beacon = 0x40001bac; -pm_process_tim = 0x40001bb0; -pm_rx_beacon_process = 0x40001bb4; -pm_rx_data_process = 0x40001bb8; -pm_sleep = 0x40001bbc; -pm_sleep_for = 0x40001bc0; -pm_tbtt_process = 0x40001bc4; -ppAMPDU2Normal = 0x40001bc8; -ppAssembleAMPDU = 0x40001bcc; -ppCalFrameTimes = 0x40001bd0; -ppCalSubFrameLength = 0x40001bd4; -ppCalTxAMPDULength = 0x40001bd8; -ppCheckTxAMPDUlength = 0x40001bdc; -ppDequeueRxq_Locked = 0x40001be0; -ppDequeueTxQ = 0x40001be4; -ppEmptyDelimiterLength = 0x40001be8; -ppEnqueueRxq = 0x40001bec; -ppEnqueueTxDone = 0x40001bf0; -ppGetTxQFirstAvail_Locked = 0x40001bf4; -ppGetTxframe = 0x40001bf8; -ppMapTxQueue = 0x40001bfc; -ppProcTxSecFrame = 0x40001c00; -ppProcessRxPktHdr = 0x40001c04; -ppProcessTxQ = 0x40001c08; -ppRecordBarRRC = 0x40001c0c; -lmacRequestTxopQueue = 0x40001c10; -lmacReleaseTxopQueue = 0x40001c14; -ppRecycleAmpdu = 0x40001c18; -ppRecycleRxPkt = 0x40001c1c; -ppResortTxAMPDU = 0x40001c20; -ppResumeTxAMPDU = 0x40001c24; -ppRxFragmentProc = 0x40001c28; -ppRxPkt = 0x40001c2c; -ppRxProtoProc = 0x40001c30; -ppSearchTxQueue = 0x40001c34; -ppSearchTxframe = 0x40001c38; -ppSelectNextQueue = 0x40001c3c; -ppSubFromAMPDU = 0x40001c40; -ppTask = 0x40001c44; -ppTxPkt = 0x40001c48; -ppTxProtoProc = 0x40001c4c; -ppTxqUpdateBitmap = 0x40001c50; -pp_coex_tx_request = 0x40001c54; -pp_hdrsize = 0x40001c58; -pp_post = 0x40001c5c; -pp_process_hmac_waiting_txq = 0x40001c60; -rcGetAmpduSched = 0x40001c64; -rcUpdateRxDone = 0x40001c68; -rc_get_trc = 0x40001c6c; -rc_get_trc_by_index = 0x40001c70; -rcAmpduLowerRate = 0x40001c74; -rcampduuprate = 0x40001c78; -rcClearCurAMPDUSched = 0x40001c7c; -rcClearCurSched = 0x40001c80; -rcClearCurStat = 0x40001c84; -rcGetSched = 0x40001c88; -rcLowerSched = 0x40001c8c; -rcSetTxAmpduLimit = 0x40001c90; -rcTxUpdatePer = 0x40001c94; -rcUpdateAckSnr = 0x40001c98; -rcUpdateRate = 0x40001c9c; -rcUpdateTxDone = 0x40001ca0; -rcUpdateTxDoneAmpdu2 = 0x40001ca4; -rcUpSched = 0x40001ca8; -rssi_margin = 0x40001cac; -rx11NRate2AMPDULimit = 0x40001cb0; -TRC_AMPDU_PER_DOWN_THRESHOLD = 0x40001cb4; -TRC_AMPDU_PER_UP_THRESHOLD = 0x40001cb8; -trc_calc_duration = 0x40001cbc; -trc_isTxAmpduOperational = 0x40001cc0; -trc_onAmpduOp = 0x40001cc4; -TRC_PER_IS_GOOD = 0x40001cc8; -trc_SetTxAmpduState = 0x40001ccc; -trc_tid_isTxAmpduOperational = 0x40001cd0; -trcAmpduSetState = 0x40001cd4; -wDevCheckBlockError = 0x40001cd8; -wDev_AppendRxBlocks = 0x40001cdc; -wDev_DiscardFrame = 0x40001ce0; -wDev_GetNoiseFloor = 0x40001ce4; -wDev_IndicateAmpdu = 0x40001ce8; -wDev_IndicateFrame = 0x40001cec; -wdev_mac_reg_load = 0x40001cf0; -wdev_mac_reg_store = 0x40001cf4; -wdev_mac_special_reg_load = 0x40001cf8; -wdev_mac_special_reg_store = 0x40001cfc; -wdev_mac_wakeup = 0x40001d00; -wdev_mac_sleep = 0x40001d04; -wDev_ProcessFiq = 0x40001d08; -wDev_ProcessRxSucData = 0x40001d0c; -wdevProcessRxSucDataAll = 0x40001d10; -wdev_csi_len_align = 0x40001d14; -ppDequeueTxDone_Locked = 0x40001d18; -ppProcTxDone = 0x40001d1c; -pm_tx_data_done_process = 0x40001d20; -config_is_cache_tx_buf_enabled = 0x40001d24; -ppMapWaitTxq = 0x40001d28; -ppProcessWaitingQueue = 0x40001d2c; -ppDisableQueue = 0x40001d30; -pm_allow_tx = 0x40001d34; -wdev_is_data_in_rxlist = 0x40001d38; -ppProcTxCallback = 0x40001d3c; -pm_is_open = 0x40001d40; -pm_wake_up = 0x40001d44; -pm_wake_done = 0x40001d48; -pm_disable_disconnected_sleep_delay_timer = 0x40001d4c; -pm_enable_disconnected_sleep_delay_timer = 0x40001d50; -hal_mac_get_txq_state = 0x40001d54; -hal_mac_clr_txq_state = 0x40001d58; -hal_mac_tx_set_cca = 0x40001d5c; -hal_mac_set_txq_invalid = 0x40001d60; -hal_mac_txq_disable = 0x40001d64; -hal_mac_is_txq_enabled = 0x40001d68; -hal_mac_get_txq_pmd = 0x40001d6c; -lmacDiscardFrameExchangeSequence = 0x40001d70; -lmacDisableTransmit = 0x40001d74; -lmacProcessTxTimeout = 0x40001d78; -lmacProcessTxSuccess = 0x40001d7c; -lmacProcessCollision = 0x40001d80; -lmacProcessTxRtsError = 0x40001d84; -lmacProcessCtsTimeout = 0x40001d88; -lmacProcessTxComplete = 0x40001d8c; -lmacProcessAckTimeout = 0x40001d90; -lmacProcessTxError = 0x40001d94; -lmacProcessTxseckiderr = 0x40001d98; -rcReachRetryLimit = 0x40001d9c; -lmacProcessShortRetryFail = 0x40001da0; -lmacEndRetryAMPDUFail = 0x40001da4; -ppFillAMPDUBar = 0x40001da8; -rcGetRate = 0x40001dac; -ppReSendBar = 0x40001db0; -lmacProcessLongRetryFail = 0x40001db4; -lmacRetryTxFrame = 0x40001db8; -lmacProcessCollisions_task = 0x40001dbc; -lmacProcessTxopQComplete = 0x40001dc0; -lmacInitAc = 0x40001dc4; -lmacInit = 0x40001dc8; -mac_tx_set_txop_q = 0x40001dcc; -hal_init = 0x40001dd0; -hal_mac_rx_set_policy = 0x40001dd4; -hal_mac_set_bssid = 0x40001dd8; -mac_rx_policy_init = 0x40001ddc; -mac_txrx_init = 0x40001de0; -mac_rxbuf_init = 0x40001de4; -mac_last_rxbuf_init = 0x40001de8; -hal_attenna_init = 0x40001dec; -hal_timer_update_by_rtc = 0x40001df0; -hal_coex_pti_init = 0x40001df4; -lmac_stop_hw_txq = 0x40001df8; -ppDirectRecycleAmpdu = 0x40001dfc; -esp_wifi_internal_set_rts = 0x40001e00; -esp_wifi_internal_get_rts = 0x40001e04; -ppTxFragmentProc = 0x40001e08; -esf_buf_setup = 0x40001e0c; -hal_agreement_add_rx_ba = 0x40001e10; -hal_agreement_del_rx_ba = 0x40001e14; -hal_crypto_set_key_entry = 0x40001e18; -hal_crypto_get_key_entry = 0x40001e1c; -hal_crypto_clr_key_entry = 0x40001e20; -config_get_wifi_task_stack_size = 0x40001e24; -pp_create_task = 0x40001e28; -hal_set_sta_tsf_wakeup = 0x40001e2c; -hal_set_rx_beacon_pti = 0x40001e30; -pm_start = 0x40001e34; -pm_stop = 0x40001e38; -hal_disable_sta_tbtt = 0x40001e3c; -ppCalTxopDur = 0x40001e40; -wDev_IndicateCtrlFrame = 0x40001e44; -hal_enable_sta_tbtt = 0x40001e48; -hal_set_sta_tbtt = 0x40001e4c; -pm_update_next_tbtt = 0x40001e50; -pm_set_sleep_type = 0x40001e54; -wDev_Rxbuf_Init = 0x40001e58; -wDev_Rxbuf_Deinit = 0x40001e5c; -ppCalTkipMic = 0x40001e60; -wDev_SnifferRxData = 0x40001e64; -hal_crypto_enable = 0x40001e68; -hal_crypto_disable = 0x40001e6c; -wDev_Insert_KeyEntry = 0x40001e70; -wDev_remove_KeyEntry = 0x40001e74; -rc_enable_trc = 0x40001e78; -rc_set_per_conn_fix_rate = 0x40001e7c; -wdev_csi_rx_process = 0x40001e80; -wDev_SnifferRxAmpdu = 0x40001e84; -hal_mac_tsf_reset = 0x40001e88; -dbg_lmac_statis_dump = 0x40001e8c; -dbg_lmac_rxtx_statis_dump = 0x40001e90; -dbg_lmac_hw_statis_dump = 0x40001e94; -dbg_lmac_diag_statis_dump = 0x40001e98; -dbg_lmac_ps_statis_dump = 0x40001e9c; -pp_timer_do_process = 0x40001ea0; -rcUpdateAMPDUParam = 0x40001ea4; -rcUpdatePhyMode = 0x40001ea8; -rcGetHighestRateIdx = 0x40001eac; -pm_tx_null_data_done_process = 0x40001eb0; -pm_tx_data_process = 0x40001eb4; -pm_attach = 0x40001eb8; -pm_coex_schm_process = 0x40001ebc; -ppInitTxq = 0x40001ec0; -pp_attach = 0x40001ec4; -pp_deattach = 0x40001ec8; -pm_on_probe_resp_rx = 0x40001ecc; -hal_set_sta_tsf = 0x40001ed0; -ic_update_sta_tsf = 0x40001ed4; -ic_tx_pkt = 0x40001ed8; -pm_send_probe_stop = 0x40001edc; -pm_send_probe_start = 0x40001ee0; -pm_on_coex_schm_process_restart = 0x40001ee4; -hal_mac_set_rxq_policy = 0x40001ee8; -hal_sniffer_enable = 0x40001eec; -hal_sniffer_disable = 0x40001ef0; -hal_sniffer_rx_set_promis = 0x40001ef4; -hal_sniffer_rx_clr_statistics = 0x40001ef8; -hal_sniffer_set_promis_misc_pkt = 0x40001efc; -tsf_hal_set_tsf_enable = 0x40001f00; -tsf_hal_set_tsf_disable = 0x40001f04; -tsf_hal_is_tsf_enabled = 0x40001f08; -tsf_hal_set_modem_wakeup_early_time = 0x40001f0c; -tsf_hal_get_counter_value = 0x40001f10; -tsf_hal_set_counter_value = 0x40001f14; -tsf_hal_get_time = 0x40001f18; -tsf_hal_set_time = 0x40001f1c; -tsf_hal_set_tbtt_enable = 0x40001f20; -tsf_hal_set_tbtt_disable = 0x40001f24; -tsf_hal_set_tbtt_intr_enable = 0x40001f28; -tsf_hal_set_tbtt_intr_disable = 0x40001f2c; -tsf_hal_set_tbtt_soc_wakeup_enable = 0x40001f30; -tsf_hal_set_tbtt_soc_wakeup_disable = 0x40001f34; -tsf_hal_set_tbtt_start_time = 0x40001f38; -tsf_hal_set_tbtt_early_time = 0x40001f3c; -tsf_hal_set_tbtt_interval = 0x40001f40; -tsf_hal_get_tbtt_interval = 0x40001f44; -tsf_hal_set_timer_enable = 0x40001f48; -tsf_hal_set_timer_disable = 0x40001f4c; -tsf_hal_set_timer_target = 0x40001f50; -tsf_hal_get_timer_target = 0x40001f54; -tsf_hal_set_timer_intr_enable = 0x40001f58; -tsf_hal_set_timer_intr_disable = 0x40001f5c; -tsf_hal_set_timer_soc_wakeup_enable = 0x40001f60; -tsf_hal_set_timer_soc_wakeup_disable = 0x40001f64; -pm_disconnected_wake = 0x40001f68; -pm_get_connectionless_status = 0x40001f6c; -pm_update_by_connectionless_status = 0x40001f70; -pm_connectionless_wake_interval_timeout_process = 0x40001f74; -pm_connectionless_wake_window_timeout_process = 0x40001f78; -/* Data (.data, .bss, .rodata) */ -our_instances_ptr = 0x3ff4fbbc; -pTxRx = 0x3fcdfdec; -lmacConfMib_ptr = 0x3fcdfde8; -our_wait_eb = 0x3fcdfde4; -our_tx_eb = 0x3fcdfde0; -pp_wdev_funcs = 0x3fcdfddc; -g_osi_funcs_p = 0x3fcdfdd8; -wDevCtrl_ptr = 0x3fcdfdd4; -g_wdev_last_desc_reset_ptr = 0x3ff4fbb8; -wDevMacSleep_ptr = 0x3fcdfdd0; -g_lmac_cnt_ptr = 0x3fcdfdcc; -our_controls_ptr = 0x3ff4fbb4; -pp_sig_cnt_ptr = 0x3fcdfdc8; -g_eb_list_desc_ptr = 0x3fcdfdc4; -s_fragment_ptr = 0x3fcdfdc0; -if_ctrl_ptr = 0x3fcdfdbc; -g_intr_lock_mux = 0x3fcdfdb8; -g_wifi_global_lock = 0x3fcdfdb4; -s_wifi_queue = 0x3fcdfdb0; -pp_task_hdl = 0x3fcdfdac; -s_pp_task_create_sem = 0x3fcdfda8; -s_pp_task_del_sem = 0x3fcdfda4; -g_wifi_menuconfig_ptr = 0x3fcdfda0; -xphyQueue = 0x3fcdfd9c; -ap_no_lr_ptr = 0x3fcdfd98; -rc11BSchedTbl_ptr = 0x3fcdfd94; -rc11NSchedTbl_ptr = 0x3fcdfd90; -rcLoRaSchedTbl_ptr = 0x3fcdfd8c; -BasicOFDMSched_ptr = 0x3fcdfd88; -trc_ctl_ptr = 0x3fcdfd84; -g_pm_cnt_ptr = 0x3fcdfd80; -g_pm_ptr = 0x3fcdfd7c; -g_pm_cfg_ptr = 0x3fcdfd78; -g_esp_mesh_quick_funcs_ptr = 0x3fcdfd74; -g_txop_queue_status_ptr = 0x3fcdfd70; -g_mac_sleep_en_ptr = 0x3fcdfd6c; -g_mesh_is_root_ptr = 0x3fcdfd68; -g_mesh_topology_ptr = 0x3fcdfd64; -g_mesh_init_ps_type_ptr = 0x3fcdfd60; -g_mesh_is_started_ptr = 0x3fcdfd5c; -g_config_func = 0x3fcdfd58; -g_net80211_tx_func = 0x3fcdfd54; -g_timer_func = 0x3fcdfd50; -s_michael_mic_failure_cb = 0x3fcdfd4c; -wifi_sta_rx_probe_req = 0x3fcdfd48; -g_tx_done_cb_func = 0x3fcdfd44; -g_per_conn_trc = 0x3fcdfd28; -s_encap_amsdu_func = 0x3fcdfd24; -bars = 0x3fcdfc84; -eb_txdesc_space = 0x3fcdfbf4; -eb_space = 0x3fcdfb54; -g_pd_mac_in_light_sleep = 0x3fcdfb50; -s_fix_rate_mask = 0x3fcdfb4c; -s_fix_rate = 0x3fcdfb44; -g_wdev_csi_rx = 0x3fcdfb40; -g_wdev_csi_rx_ctx = 0x3fcdfb3c; -BcnSendTick = 0x3fcdfb38; -g_pp_timer_info_ptr = 0x3fcdfb34; -rcP2P11NSchedTbl_ptr = 0x3fcdfb30; -rcP2P11GSchedTbl_ptr = 0x3fcdfb2c; -rc11GSchedTbl_ptr = 0x3fcdfb28; - - -/*************************************** - Group rom_net80211 - ***************************************/ - -/* Functions */ -esp_net80211_rom_version_get = 0x40001f7c; -ampdu_dispatch = 0x40001f80; -ampdu_dispatch_all = 0x40001f84; -ampdu_dispatch_as_many_as_possible = 0x40001f88; -ampdu_dispatch_movement = 0x40001f8c; -ampdu_dispatch_upto = 0x40001f90; -chm_is_at_home_channel = 0x40001f94; -cnx_node_is_existing = 0x40001f98; -cnx_node_search = 0x40001f9c; -ic_ebuf_recycle_rx = 0x40001fa0; -ic_ebuf_recycle_tx = 0x40001fa4; -ic_reset_rx_ba = 0x40001fa8; -ieee80211_align_eb = 0x40001fac; -ieee80211_ampdu_reorder = 0x40001fb0; -ieee80211_ampdu_start_age_timer = 0x40001fb4; -ieee80211_encap_esfbuf = 0x40001fb8; -ieee80211_is_tx_allowed = 0x40001fbc; -ieee80211_output_pending_eb = 0x40001fc0; -ieee80211_output_process = 0x40001fc4; -ieee80211_set_tx_desc = 0x40001fc8; -sta_input = 0x40001fcc; -wifi_get_macaddr = 0x40001fd0; -wifi_rf_phy_disable = 0x40001fd4; -wifi_rf_phy_enable = 0x40001fd8; -ic_ebuf_alloc = 0x40001fdc; -ieee80211_classify = 0x40001fe0; -ieee80211_copy_eb_header = 0x40001fe4; -ieee80211_recycle_cache_eb = 0x40001fe8; -ieee80211_search_node = 0x40001fec; -roundup2 = 0x40001ff0; -ieee80211_crypto_encap = 0x40001ff4; -ieee80211_crypto_decap = 0x40001ff8; -ieee80211_decap = 0x40001ffc; -ieee80211_set_tx_pti = 0x40002000; -wifi_is_started = 0x40002004; -ieee80211_gettid = 0x40002008; -ieee80211_ccmp_decrypt = 0x4000200c; -ieee80211_ccmp_encrypt = 0x40002010; -ccmp_encap = 0x40002014; -ccmp_decap = 0x40002018; -tkip_encap = 0x4000201c; -tkip_decap = 0x40002020; -wep_encap = 0x40002024; -wep_decap = 0x40002028; -dbg_hmac_rxtx_statis_dump = 0x4000202c; -dbg_hmac_statis_dump = 0x40002030; -ieee80211_send_action_vendor_spec = 0x40002034; -ieee80211_send_mgmt = 0x40002038; -ieee80211_auth_construct = 0x4000203c; -ieee80211_deauth_construct = 0x40002040; -ieee80211_disassoc_construct = 0x40002044; -ieee80211_vnd_lora_ie_size = 0x40002048; -ieee80211_vnd_ie_size = 0x4000204c; -ieee80211_add_ssid = 0x40002050; -ieee80211_add_rates = 0x40002054; -ieee80211_add_xrates = 0x40002058; -ieee80211_is_ht_cipher = 0x4000205c; -ieee80211_assoc_req_construct = 0x40002060; -ieee80211_assoc_resp_construct = 0x40002064; -ieee80211_setup_lr_rates = 0x40002068; -ieee80211_ht_node_init = 0x4000206c; -ieee80211_is_support_rate = 0x40002070; -ieee80211_setup_rates = 0x40002074; -ieee80211_is_lr_only = 0x40002078; -ieee80211_setup_phy_mode = 0x4000207c; -ieee80211_sta_is_connected = 0x40002080; -current_task_is_wifi_task = 0x40002084; -wifi_get_init_state = 0x40002088; -ieee80211_timer_process = 0x4000208c; -cnx_coexist_timeout = 0x40002090; -sta_recv_mgmt = 0x40002094; -ieee80211_send_setup = 0x40002098; -ieee80211_send_probereq = 0x4000209c; -sta_auth_open = 0x400020a0; -sta_auth_shared = 0x400020a4; -sta_auth_sae = 0x400020a8; -cnx_coexist_timeout_process = 0x400020ac; -ieee80211_alloc_challenge = 0x400020b0; -cnx_assoc_timeout = 0x400020b4; -ieee80211_vnd_ie_set = 0x400020b8; -ieee80211_vnd_lora_ie_set = 0x400020bc; -ieee80211_add_wme_param = 0x400020c0; -ieee80211_add_dsparams = 0x400020c4; -ieee80211_add_csa = 0x400020c8; -ieee80211_add_extcap = 0x400020cc; -ieee80211_regdomain_get_country = 0x400020d0; -ieee80211_add_countryie = 0x400020d4; -ieee80211_alloc_proberesp = 0x400020d8; -ieee80211_amsdu_adjust_head = 0x400020dc; -ieee80211_amsdu_adjust_last_length = 0x400020e0; -ieee80211_amsdu_send_check = 0x400020e4; -ieee80211_amsdu_encap_check = 0x400020e8; -ieee80211_amsdu_length_check = 0x400020ec; -ieee80211_encap_amsdu = 0x400020f0; -ieee80211_output_raw_process = 0x400020f4; -esp_wifi_80211_tx = 0x400020f8; -ieee80211_raw_frame_sanity_check = 0x400020fc; -ieee80211_crypto_aes_128_cmac_encrypt = 0x40002100; -ieee80211_crypto_aes_128_cmac_decrypt = 0x40002104; -ieee80211_alloc_tx_buf = 0x40002108; -ieee80211_output_do = 0x4000210c; -ieee80211_send_nulldata = 0x40002110; -ieee80211_setup_robust_mgmtframe = 0x40002114; -ieee80211_mgmt_output = 0x40002118; -ieee80211_encap_null_data = 0x4000211c; -ieee80211_send_deauth = 0x40002120; -ieee80211_alloc_deauth = 0x40002124; -ieee80211_send_proberesp = 0x40002128; -ieee80211_tx_mgt_cb = 0x4000212c; -ieee80211_getcapinfo = 0x40002130; -sta_rx_csa = 0x40002134; -sta_send_sa_query_req = 0x40002138; -sta_send_sa_query_resp = 0x4000213c; -sta_recv_sa_query_req = 0x40002140; -sta_recv_sa_query_resp = 0x40002144; -ieee80211_parse_beacon = 0x40002148; -ieee80211_set_max_rate = 0x4000214c; -ic_set_sta = 0x40002150; -ieee80211_match_security = 0x40002154; -ieee80211_parse_wpa = 0x40002158; -ieee80211_parse_rsn = 0x4000215c; -ieee80211_add_assoc_req_ies = 0x40002160; -ieee80211_add_probe_req_ies = 0x40002164; -/* Data (.data, .bss, .rodata) */ -net80211_funcs = 0x3fcdfb24; -g_scan = 0x3fcdfb20; -g_chm = 0x3fcdfb1c; -g_ic_ptr = 0x3fcdfb18; -g_hmac_cnt_ptr = 0x3fcdfaf4; -g_tx_cacheq_ptr = 0x3fcdfb14; -s_netstack_free = 0x3fcdfb10; -mesh_rxcb = 0x3fcdfb0c; -sta_rxcb = 0x3fcdfb08; -ccmp_ptr = 0x3fcdfb04; -s_wifi_nvs_ptr = 0x3fcdfb00; -tkip_ptr = 0x3fcdfafc; -wep_ptr = 0x3fcdfaf8; -g_hmac_cnt_ptr = 0x3fcdfaf4; -g_misc_nvs = 0x3fcdfaf0; -s_wifi_init_state = 0x3fcdfac0; -s_wifi_task_hdl = 0x3fcdfaec; -in_rssi_adjust = 0x3fcdfae8; -rssi_saved = 0x3fcdfae0; -rssi_index = 0x3fcdfadc; -s_sa_query_retries = 0x3fcdfad8; -s_sa_query_success = 0x3fcdfad5; -g_sta_connected_flag = 0x3fcdfad4; -wpa_crypto_funcs_ptr = 0x3fcdfad0; -s_netstack_ref = 0x3fcdfacc; -sta_csa_timer_ptr = 0x3fcdfac8; -s_trans_id = 0x3fcdfac4; - - -/*************************************** - Group rom_coexist - ***************************************/ - -/* Functions */ -esp_coex_rom_version_get = 0x40002168; -coex_bt_release = 0x4000216c; -coex_bt_request = 0x40002170; -coex_core_ble_conn_dyn_prio_get = 0x40002174; -coex_core_event_duration_get = 0x40002178; -coex_core_pti_get = 0x4000217c; -coex_core_release = 0x40002180; -coex_core_request = 0x40002184; -coex_core_status_get = 0x40002188; -coex_core_timer_idx_get = 0x4000218c; -coex_event_duration_get = 0x40002190; -coex_hw_timer_disable = 0x40002194; -coex_hw_timer_enable = 0x40002198; -coex_hw_timer_set = 0x4000219c; -coex_schm_interval_set = 0x400021a0; -coex_schm_lock = 0x400021a4; -coex_schm_unlock = 0x400021a8; -coex_status_get = 0x400021ac; -coex_wifi_release = 0x400021b0; -esp_coex_ble_conn_dynamic_prio_get = 0x400021b4; -coex_hw_timer_tick_get = 0x400021b8; -/* Data (.data, .bss, .rodata) */ -coex_env_ptr = 0x3fcdfabc; -coex_pti_tab_ptr = 0x3fcdfab8; -coex_schm_env_ptr = 0x3fcdfab4; -coexist_funcs = 0x3fcdfab0; -g_coa_funcs_p = 0x3fcdfaac; -g_coex_param_ptr = 0x3fcdfaa8; - - -/*************************************** - Group rom_phy - ***************************************/ - -/* Functions */ -phy_param_addr = 0x400021bc; -phy_get_romfuncs = 0x400021c0; -chip729_phyrom_version = 0x400021c4; -chip729_phyrom_version_num = 0x400021c8; -rom_get_rc_dout = 0x400021cc; -rc_cal = 0x400021d0; -phy_analog_delay_cal = 0x400021d4; -phy_rx_rifs_en = 0x400021d8; -phy_current_level_set = 0x400021dc; -phy_bbpll_en_usb = 0x400021e0; -phy_bt_power_track = 0x400021e4; -phy_xpd_tsens = 0x400021e8; -bb_wdt_rst_enable = 0x400021ec; -bb_wdt_int_enable = 0x400021f0; -bb_wdt_timeout_clear = 0x400021f4; -bb_wdt_get_status = 0x400021f8; -rom_enter_critical_phy = 0x400021fc; -rom_exit_critical_phy = 0x40002200; -rom_bb_bss_cbw40 = 0x40002204; -rom_set_chan_reg = 0x40002208; -abs_temp = 0x4000220c; -set_chan_cal_interp = 0x40002210; -loopback_mode_en = 0x40002214; -get_data_sat = 0x40002218; -phy_byte_to_word = 0x4000221c; -phy_get_rx_freq = 0x40002220; -i2c_master_reset = 0x40002224; -chan14_mic_enable = 0x40002228; -chan14_mic_cfg = 0x4000222c; -set_adc_rand = 0x40002230; -phy_set_most_tpw = 0x40002234; -phy_get_most_tpw = 0x40002238; -esp_tx_state_out = 0x4000223c; -phy_get_adc_rand = 0x40002240; -phy_internal_delay = 0x40002244; -phy_ftm_comp = 0x40002248; -phy_11p_set = 0x4000224c; -phy_freq_mem_backup = 0x40002250; -ant_dft_cfg = 0x40002254; -ant_wifitx_cfg = 0x40002258; -ant_wifirx_cfg = 0x4000225c; -ant_bttx_cfg = 0x40002260; -ant_btrx_cfg = 0x40002264; -phy_chan_dump_cfg = 0x40002268; -phy_enable_low_rate = 0x4000226c; -phy_disable_low_rate = 0x40002270; -phy_dig_reg_backup = 0x40002274; -phy_chan_filt_set = 0x40002278; -phy_rx11blr_cfg = 0x4000227c; -set_cca = 0x40002280; -set_rx_sense = 0x40002284; -rx_gain_force = 0x40002288; -rom_phy_en_hw_set_freq = 0x4000228c; -rom_phy_dis_hw_set_freq = 0x40002290; -wr_rf_freq_mem = 0x40002294; -freq_i2c_write_set = 0x40002298; -write_pll_cap_mem = 0x4000229c; -pll_dac_mem_update = 0x400022a0; -pll_cap_mem_update = 0x400022a4; -get_rf_freq_cap = 0x400022a8; -get_rf_freq_init = 0x400022ac; -freq_get_i2c_data = 0x400022b0; -freq_i2c_data_write = 0x400022b4; -set_chan_freq_hw_init = 0x400022b8; -set_chan_freq_sw_start = 0x400022bc; -rom_get_i2c_read_mask = 0x400022c0; -rom_get_i2c_mst0_mask = 0x400022c4; -rom_get_i2c_hostid = 0x400022c8; -rom_chip_i2c_readReg_org = 0x400022cc; -rom_chip_i2c_readReg = 0x400022d0; -rom_i2c_paral_set_mst0 = 0x400022d4; -rom_i2c_paral_set_read = 0x400022d8; -rom_i2c_paral_read = 0x400022dc; -rom_i2c_paral_write = 0x400022e0; -rom_i2c_paral_write_num = 0x400022e4; -rom_i2c_paral_write_mask = 0x400022e8; -rom_i2c_readReg = 0x400022ec; -rom_chip_i2c_writeReg = 0x400022f0; -rom_i2c_writeReg = 0x400022f4; -rom_i2c_readReg_Mask = 0x400022f8; -rom_i2c_writeReg_Mask = 0x400022fc; -rom_set_txcap_reg = 0x40002300; -i2c_sar2_init_code = 0x40002304; -phy_i2c_init1 = 0x40002308; -phy_i2c_init2 = 0x4000230c; -phy_get_i2c_data = 0x40002310; -bias_reg_set = 0x40002314; -i2c_rc_cal_set = 0x40002318; -i2c_bbpll_set = 0x4000231c; -rom_phy_xpd_rf = 0x40002320; -phy_wakeup_init_rom = 0x40002324; -register_chipv7_phy_init_param = 0x40002328; -phy_reg_init = 0x4000232c; -phy_close_rf_rom = 0x40002330; -rom_pbus_force_mode = 0x40002334; -rom_pbus_rd_addr = 0x40002338; -rom_pbus_rd_shift = 0x4000233c; -rom_pbus_force_test = 0x40002340; -rom_pbus_rd = 0x40002344; -rom_pbus_debugmode = 0x40002348; -rom_pbus_workmode = 0x4000234c; -rom_pbus_set_rxgain = 0x40002350; -rom_pbus_xpd_rx_off = 0x40002354; -rom_pbus_xpd_rx_on = 0x40002358; -rom_pbus_xpd_tx_off = 0x4000235c; -rom_pbus_xpd_tx_on = 0x40002360; -rom_pbus_set_dco = 0x40002364; -rom_set_loopback_gain = 0x40002368; -rom_txcal_debuge_mode = 0x4000236c; -rom_txcal_work_mode = 0x40002370; -set_pbus_mem = 0x40002374; -rom_pwdet_sar2_init = 0x40002378; -rom_en_pwdet = 0x4000237c; -rom_get_sar_sig_ref = 0x40002380; -rom_pwdet_tone_start = 0x40002384; -rom_get_tone_sar_dout = 0x40002388; -rom_get_fm_sar_dout = 0x4000238c; -rom_txtone_linear_pwr = 0x40002390; -rom_get_power_db = 0x40002394; -rom_meas_tone_pwr_db = 0x40002398; -rom_pkdet_vol_start = 0x4000239c; -rom_read_sar_dout = 0x400023a0; -rom_read_sar2_code = 0x400023a4; -rom_get_sar2_vol = 0x400023a8; -rom_get_pll_vol = 0x400023ac; -rom_tx_pwctrl_bg_init = 0x400023b0; -rom_phy_pwdet_always_en = 0x400023b4; -rom_phy_pwdet_onetime_en = 0x400023b8; -linear_to_db = 0x400023bc; -rom_disable_agc = 0x400023c0; -rom_enable_agc = 0x400023c4; -rom_disable_wifi_agc = 0x400023c8; -rom_enable_wifi_agc = 0x400023cc; -rom_write_gain_mem = 0x400023d0; -rom_bb_bss_cbw40_dig = 0x400023d4; -rom_cbw2040_cfg = 0x400023d8; -rom_mac_tx_chan_offset = 0x400023dc; -rom_tx_paon_set = 0x400023e0; -rom_i2cmst_reg_init = 0x400023e4; -rom_bt_gain_offset = 0x400023e8; -rom_fe_reg_init = 0x400023ec; -rom_mac_enable_bb = 0x400023f0; -rom_bb_wdg_cfg = 0x400023f4; -rom_fe_txrx_reset = 0x400023f8; -rom_set_rx_comp = 0x400023fc; -rom_write_chan_freq = 0x40002400; -rom_agc_reg_init = 0x40002404; -rom_bb_reg_init = 0x40002408; -rom_write_txrate_power_offset = 0x4000240c; -rom_open_i2c_xpd = 0x40002410; -rom_txiq_set_reg = 0x40002414; -rom_rxiq_set_reg = 0x40002418; -rom_phy_bbpll_cal = 0x4000241c; -phy_disable_cca = 0x40002420; -phy_enable_cca = 0x40002424; -force_txon = 0x40002428; -set_txclk_en = 0x4000242c; -set_rxclk_en = 0x40002430; -start_tx_tone_step = 0x40002434; -stop_tx_tone = 0x40002438; -bb_wdg_test_en = 0x4000243c; -noise_floor_auto_set = 0x40002440; -read_hw_noisefloor = 0x40002444; -iq_corr_enable = 0x40002448; -bt_tx_dig_gain = 0x4000244c; -wifi_tx_dig_reg = 0x40002450; -wifi_agc_sat_gain = 0x40002454; -phy_ant_init = 0x40002458; -phy_set_bbfreq_init = 0x4000245c; -wifi_fbw_sel = 0x40002460; -phy_rx_sense_set = 0x40002464; -tx_state_set = 0x40002468; -phy_close_pa = 0x4000246c; -bt_filter_reg = 0x40002470; -phy_freq_correct = 0x40002474; -set_pbus_reg = 0x40002478; -wifi_rifs_mode_en = 0x4000247c; -rfagc_disable = 0x40002480; -rom_restart_cal = 0x40002484; -rom_write_rfpll_sdm = 0x40002488; -rom_wait_rfpll_cal_end = 0x4000248c; -rom_rfpll_set_freq = 0x40002490; -rom_rfpll_cap_init_cal = 0x40002494; -rom_set_rfpll_freq = 0x40002498; -rom_write_pll_cap = 0x4000249c; -rom_read_pll_cap = 0x400024a0; -mhz2ieee = 0x400024a4; -chan_to_freq = 0x400024a8; -set_rf_freq_offset = 0x400024ac; -set_channel_rfpll_freq = 0x400024b0; -rfpll_cap_correct = 0x400024b4; -phy_set_freq = 0x400024b8; -correct_rfpll_offset = 0x400024bc; -pll_vol_cal = 0x400024c0; -chip_v7_set_chan_misc = 0x400024c4; -chip_v7_set_chan = 0x400024c8; -chip_v7_set_chan_offset = 0x400024cc; -chip_v7_set_chan_ana = 0x400024d0; -set_chanfreq = 0x400024d4; -rom_rxiq_cover_mg_mp = 0x400024d8; -rom_rfcal_rxiq = 0x400024dc; -rom_get_rfcal_rxiq_data = 0x400024e0; -rom_pbus_rx_dco_cal = 0x400024e4; -rom_rxdc_est_min = 0x400024e8; -rom_pbus_rx_dco_cal_1step = 0x400024ec; -rom_set_lb_txiq = 0x400024f0; -rom_set_rx_gain_cal_iq = 0x400024f4; -rom_set_rx_gain_cal_dc = 0x400024f8; -iq_est_enable = 0x400024fc; -iq_est_disable = 0x40002500; -dc_iq_est = 0x40002504; -set_cal_rxdc = 0x40002508; -rxiq_get_mis = 0x4000250c; -spur_reg_write_one_tone = 0x40002510; -spur_cal = 0x40002514; -spur_coef_cfg = 0x40002518; -gen_rx_gain_table = 0x4000251c; -wr_rx_gain_mem = 0x40002520; -set_rx_gain_param = 0x40002524; -set_rx_gain_table = 0x40002528; -rom_tester_wifi_cali = 0x4000252c; -esp_recover_efuse_data = 0x40002530; -bt_track_pll_cap = 0x40002534; -rfpll_cap_track = 0x40002538; -phy_param_track = 0x4000253c; -txpwr_correct = 0x40002540; -txpwr_cal_track = 0x40002544; -tx_pwctrl_background = 0x40002548; -bt_track_tx_power = 0x4000254c; -wifi_track_tx_power = 0x40002550; -rom_code_to_temp = 0x40002554; -rom_tsens_index_to_dac = 0x40002558; -rom_tsens_index_to_offset = 0x4000255c; -rom_tsens_dac_cal = 0x40002560; -rom_tsens_code_read = 0x40002564; -rom_tsens_temp_read = 0x40002568; -rom_temp_to_power = 0x4000256c; -tsens_read_init = 0x40002570; -get_temp_init = 0x40002574; -rom_txiq_cover = 0x40002578; -rom_rfcal_txiq = 0x4000257c; -rom_get_power_atten = 0x40002580; -rom_tx_pwctrl_init_cal = 0x40002584; -bt_txdc_cal = 0x40002588; -bt_txiq_cal = 0x4000258c; -txiq_cal_init = 0x40002590; -txdc_cal_init = 0x40002594; -txdc_cal_v70 = 0x40002598; -txiq_get_mis_pwr = 0x4000259c; -pwdet_ref_code = 0x400025a0; -pwdet_code_cal = 0x400025a4; -rfcal_txcap = 0x400025a8; -tx_cap_init = 0x400025ac; -rfcal_pwrctrl = 0x400025b0; -tx_pwctrl_init = 0x400025b4; -bt_tx_pwctrl_init = 0x400025b8; -bt_txpwr_freq = 0x400025bc; -rom_txbbgain_to_index = 0x400025c0; -rom_index_to_txbbgain = 0x400025c4; -rom_bt_index_to_bb = 0x400025c8; -rom_bt_bb_to_index = 0x400025cc; -rom_bt_get_tx_gain = 0x400025d0; -rom_get_tx_gain_value = 0x400025d4; -rom_wifi_get_tx_gain = 0x400025d8; -rom_set_tx_gain_mem = 0x400025dc; -rom_get_rate_fcc_index = 0x400025e0; -rom_get_chan_target_power = 0x400025e4; -rom_wifi_tx_dig_gain = 0x400025e8; -rom_wifi_set_tx_gain = 0x400025ec; -rom_bt_set_tx_gain = 0x400025f0; -wifi_11g_rate_chg = 0x400025f4; -bt_chan_pwr_interp = 0x400025f8; -bt_tx_gain_init = 0x400025fc; -/* Data (.data, .bss, .rodata) */ -phy_param_rom = 0x3fcdfaa4; - - -/*************************************** - Group rom_btbb - ***************************************/ - -/* Functions */ -bt_agc_gain_offset = 0x40002600; -bt_agc_gain_max = 0x40002604; -bt_set_rx_comp = 0x40002608; -bt_agc_gain_set = 0x4000260c; -bt_agc_rssi_thresh = 0x40002610; -bt_agc_target_set = 0x40002614; -bt_agc_restart_set = 0x40002618; -bt_agc_recorrect_set = 0x4000261c; -bt_agc_detect_set = 0x40002620; -bt_bb_rx_correlator_set = 0x40002624; -bt_bb_rx_dpo_set = 0x40002628; -bt_bb_rx_filter_sel = 0x4000262c; -bt_bb_rx_set1 = 0x40002630; -bt_bb_v2_rx_set = 0x40002634; -bt_bb_v2_tx_set = 0x40002638; -bt_bb_tx_cca_set = 0x4000263c; -bt_bb_tx_cca_period = 0x40002640; -bt_bb_tx_cca_fifo_reset = 0x40002644; -bt_bb_tx_cca_fifo_empty = 0x40002648; -bt_bb_tx_cca_fifo_full = 0x4000264c; -bt_bb_tx_cca_fifo_count = 0x40002650; -bt_bb_tx_cca_fifo_read = 0x40002654; -coex_pti_v2 = 0x40002658; -bt_bb_set_le_tx_on_delay = 0x4000265c; -bt_bb_set_corr_thresh_le = 0x40002660; - -/* ROM function interface esp8684.rom.mbedtls.ld for esp8684 - * - * - * Generated from ./interface-esp8684.yml md5sum c679b6ed5e9f0a9c3e7b93e5e0f2a1a3 - * - * Compatible with ROM where ECO version equal or greater to 1. - * - * THIS FILE WAS AUTOMATICALLY GENERATED. DO NOT EDIT. - */ - -/*************************************** - Group rom_mbedtls - ***************************************/ - -/* Functions */ -mbedtls_aes_init = 0x40002664; -ssl_write_client_hello = 0x40002668; -ssl_parse_server_hello = 0x4000266c; -ssl_parse_server_key_exchange = 0x40002670; -ssl_parse_certificate_request = 0x40002674; -ssl_parse_server_hello_done = 0x40002678; -ssl_write_client_key_exchange = 0x4000267c; -ssl_write_certificate_verify = 0x40002680; -ssl_parse_new_session_ticket = 0x40002684; -mbedtls_aes_free = 0x40002688; -mbedtls_aes_setkey_enc = 0x4000268c; -mbedtls_aes_setkey_dec = 0x40002690; -mbedtls_aes_crypt_ecb = 0x40002694; -mbedtls_aes_crypt_cbc = 0x40002698; -mbedtls_internal_aes_encrypt = 0x4000269c; -mbedtls_internal_aes_decrypt = 0x400026a0; -mbedtls_asn1_get_len = 0x400026a4; -mbedtls_asn1_get_tag = 0x400026a8; -mbedtls_asn1_get_bool = 0x400026ac; -mbedtls_asn1_get_int = 0x400026b0; -mbedtls_asn1_get_bitstring = 0x400026b4; -mbedtls_asn1_get_bitstring_null = 0x400026b8; -mbedtls_asn1_get_sequence_of = 0x400026bc; -mbedtls_asn1_get_mpi = 0x400026c0; -mbedtls_asn1_get_alg = 0x400026c4; -mbedtls_asn1_get_alg_null = 0x400026c8; -mbedtls_asn1_write_len = 0x400026cc; -mbedtls_asn1_write_tag = 0x400026d0; -mbedtls_asn1_write_mpi = 0x400026d4; -mbedtls_base64_decode = 0x400026d8; -mbedtls_mpi_init = 0x400026dc; -mbedtls_mpi_free = 0x400026e0; -mbedtls_mpi_grow = 0x400026e4; -mbedtls_mpi_shrink = 0x400026e8; -mbedtls_mpi_copy = 0x400026ec; -mbedtls_mpi_safe_cond_assign = 0x400026f0; -mbedtls_mpi_safe_cond_swap = 0x400026f4; -mbedtls_mpi_lset = 0x400026f8; -mbedtls_mpi_get_bit = 0x400026fc; -mbedtls_mpi_set_bit = 0x40002700; -mbedtls_mpi_lsb = 0x40002704; -mbedtls_mpi_bitlen = 0x40002708; -mbedtls_mpi_size = 0x4000270c; -mbedtls_mpi_read_binary = 0x40002710; -mbedtls_mpi_write_binary = 0x40002714; -mbedtls_mpi_shift_l = 0x40002718; -mbedtls_mpi_shift_r = 0x4000271c; -mbedtls_mpi_cmp_abs = 0x40002720; -mbedtls_mpi_cmp_mpi = 0x40002724; -mbedtls_mpi_lt_mpi_ct = 0x40002728; -mbedtls_mpi_cmp_int = 0x4000272c; -mbedtls_mpi_add_abs = 0x40002730; -mbedtls_mpi_sub_abs = 0x40002734; -mbedtls_mpi_add_mpi = 0x40002738; -mbedtls_mpi_sub_mpi = 0x4000273c; -mbedtls_mpi_add_int = 0x40002740; -mbedtls_mpi_sub_int = 0x40002744; -mbedtls_mpi_mul_mpi = 0x40002748; -mbedtls_mpi_mul_int = 0x4000274c; -mbedtls_mpi_div_mpi = 0x40002750; -mbedtls_mpi_div_int = 0x40002754; -mbedtls_mpi_mod_mpi = 0x40002758; -mbedtls_mpi_mod_int = 0x4000275c; -mbedtls_mpi_exp_mod = 0x40002760; -mbedtls_mpi_fill_random = 0x40002764; -mbedtls_mpi_gcd = 0x40002768; -mbedtls_mpi_inv_mod = 0x4000276c; -mbedtls_mpi_is_prime_ext = 0x40002770; -mbedtls_ccm_star_encrypt_and_tag = 0x40002774; -mbedtls_ccm_star_auth_decrypt = 0x40002778; -mbedtls_cipher_init = 0x4000277c; -mbedtls_cipher_set_padding_mode = 0x40002780; -mbedtls_cipher_reset = 0x40002784; -mbedtls_cipher_finish = 0x40002788; -mbedtls_cipher_crypt = 0x4000278c; -mbedtls_cipher_cmac_starts = 0x40002790; -mbedtls_cipher_cmac_update = 0x40002794; -mbedtls_cipher_cmac_finish = 0x40002798; -mbedtls_ctr_drbg_init = 0x4000279c; -mbedtls_ctr_drbg_seed = 0x400027a0; -mbedtls_ctr_drbg_free = 0x400027a4; -mbedtls_ctr_drbg_reseed = 0x400027a8; -mbedtls_ctr_drbg_random_with_add = 0x400027ac; -mbedtls_ctr_drbg_random = 0x400027b0; -mbedtls_dhm_init = 0x400027b4; -mbedtls_dhm_read_params = 0x400027b8; -mbedtls_dhm_make_public = 0x400027bc; -mbedtls_dhm_calc_secret = 0x400027c0; -mbedtls_dhm_free = 0x400027c4; -mbedtls_ecdh_init = 0x400027c8; -mbedtls_ecdh_setup = 0x400027cc; -mbedtls_ecdh_free = 0x400027d0; -mbedtls_ecdh_read_params = 0x400027d4; -mbedtls_ecdh_get_params = 0x400027d8; -mbedtls_ecdh_make_public = 0x400027dc; -mbedtls_ecdh_calc_secret = 0x400027e0; -mbedtls_ecdh_enable_restart = 0x400027e4; -mbedtls_ecdsa_write_signature = 0x400027e8; -mbedtls_ecdsa_write_signature_restartable = 0x400027ec; -mbedtls_ecdsa_read_signature = 0x400027f0; -mbedtls_ecdsa_read_signature_restartable = 0x400027f4; -mbedtls_ecdsa_from_keypair = 0x400027f8; -mbedtls_ecdsa_init = 0x400027fc; -mbedtls_ecdsa_free = 0x40002800; -mbedtls_ecdsa_restart_init = 0x40002804; -mbedtls_ecdsa_restart_free = 0x40002808; -mbedtls_ecjpake_init = 0x4000280c; -mbedtls_ecjpake_check = 0x40002810; -mbedtls_ecjpake_write_round_one = 0x40002814; -mbedtls_ecjpake_read_round_one = 0x40002818; -mbedtls_ecjpake_write_round_two = 0x4000281c; -mbedtls_ecjpake_read_round_two = 0x40002820; -mbedtls_ecjpake_derive_secret = 0x40002824; -mbedtls_ecjpake_free = 0x40002828; -mbedtls_ecp_check_budget = 0x4000282c; -mbedtls_ecp_restart_is_enabled = 0x40002830; -mbedtls_ecp_curve_list = 0x40002834; -mbedtls_ecp_grp_id_list = 0x40002838; -mbedtls_ecp_curve_info_from_grp_id = 0x4000283c; -mbedtls_ecp_curve_info_from_tls_id = 0x40002840; -mbedtls_ecp_point_init = 0x40002844; -mbedtls_ecp_group_init = 0x40002848; -mbedtls_ecp_keypair_init = 0x4000284c; -mbedtls_ecp_point_free = 0x40002850; -mbedtls_ecp_group_free = 0x40002854; -mbedtls_ecp_keypair_free = 0x40002858; -mbedtls_ecp_restart_init = 0x4000285c; -mbedtls_ecp_restart_free = 0x40002860; -mbedtls_ecp_copy = 0x40002864; -mbedtls_ecp_group_copy = 0x40002868; -mbedtls_ecp_set_zero = 0x4000286c; -mbedtls_ecp_is_zero = 0x40002870; -mbedtls_ecp_point_cmp = 0x40002874; -mbedtls_ecp_point_write_binary = 0x40002878; -mbedtls_ecp_point_read_binary = 0x4000287c; -mbedtls_ecp_tls_read_point = 0x40002880; -mbedtls_ecp_tls_write_point = 0x40002884; -mbedtls_ecp_group_load = 0x40002888; -mbedtls_ecp_tls_read_group = 0x4000288c; -mbedtls_ecp_tls_read_group_id = 0x40002890; -mbedtls_ecp_tls_write_group = 0x40002894; -mbedtls_ecp_mul = 0x40002898; -mbedtls_ecp_mul_restartable = 0x4000289c; -mbedtls_ecp_muladd = 0x400028a0; -mbedtls_ecp_muladd_restartable = 0x400028a4; -mbedtls_ecp_check_pubkey = 0x400028a8; -mbedtls_ecp_check_privkey = 0x400028ac; -mbedtls_ecp_gen_privkey = 0x400028b0; -mbedtls_ecp_gen_keypair_base = 0x400028b4; -mbedtls_ecp_check_pub_priv = 0x400028b8; -mbedtls_entropy_add_source = 0x400028bc; -mbedtls_entropy_func = 0x400028c0; -mbedtls_gcm_crypt_and_tag = 0x400028c4; -mbedtls_gcm_starts = 0x400028c8; -mbedtls_gcm_update = 0x400028cc; -mbedtls_gcm_finish = 0x400028d0; -mbedtls_hmac_drbg_init = 0x400028d4; -mbedtls_hmac_drbg_seed_buf = 0x400028d8; -mbedtls_hmac_drbg_update_ret = 0x400028dc; -mbedtls_hmac_drbg_reseed = 0x400028e0; -mbedtls_hmac_drbg_random_with_add = 0x400028e4; -mbedtls_hmac_drbg_random = 0x400028e8; -mbedtls_hmac_drbg_free = 0x400028ec; -mbedtls_md_list = 0x400028f0; -mbedtls_md_init = 0x400028f4; -mbedtls_md_free = 0x400028f8; -mbedtls_md_setup = 0x400028fc; -mbedtls_md_clone = 0x40002900; -mbedtls_md_get_size = 0x40002904; -mbedtls_md_get_type = 0x40002908; -mbedtls_md_starts = 0x4000290c; -mbedtls_md_update = 0x40002910; -mbedtls_md_finish = 0x40002914; -mbedtls_md = 0x40002918; -mbedtls_md_hmac_starts = 0x4000291c; -mbedtls_md_hmac_update = 0x40002920; -mbedtls_md_hmac_finish = 0x40002924; -mbedtls_md_hmac_reset = 0x40002928; -mbedtls_oid_get_x509_ext_type = 0x4000292c; -mbedtls_oid_get_pk_alg = 0x40002930; -mbedtls_oid_get_ec_grp = 0x40002934; -mbedtls_oid_get_sig_alg = 0x40002938; -mbedtls_oid_get_md_alg = 0x4000293c; -mbedtls_oid_get_md_hmac = 0x40002940; -mbedtls_oid_get_oid_by_md = 0x40002944; -mbedtls_oid_get_cipher_alg = 0x40002948; -mbedtls_oid_get_pkcs12_pbe_alg = 0x4000294c; -mbedtls_pem_init = 0x40002950; -mbedtls_pem_free = 0x40002954; -mbedtls_pkcs12_pbe_sha1_rc4_128 = 0x40002958; -mbedtls_pkcs12_pbe = 0x4000295c; -mbedtls_pkcs12_derivation = 0x40002960; -mbedtls_pkcs5_pbes2 = 0x40002964; -mbedtls_pkcs5_pbkdf2_hmac = 0x40002968; -mbedtls_pk_info_from_type = 0x4000296c; -mbedtls_pk_init = 0x40002970; -mbedtls_pk_free = 0x40002974; -mbedtls_pk_restart_init = 0x40002978; -mbedtls_pk_restart_free = 0x4000297c; -mbedtls_pk_setup = 0x40002980; -mbedtls_pk_can_do = 0x40002984; -mbedtls_pk_verify = 0x40002988; -mbedtls_pk_verify_restartable = 0x4000298c; -mbedtls_pk_verify_ext = 0x40002990; -mbedtls_pk_sign_restartable = 0x40002994; -mbedtls_pk_encrypt = 0x40002998; -mbedtls_pk_get_type = 0x4000299c; -mbedtls_pk_parse_subpubkey = 0x400029a0; -mbedtls_rsa_init = 0x400029a4; -mbedtls_rsa_import = 0x400029a8; -mbedtls_rsa_import_raw = 0x400029ac; -mbedtls_rsa_complete = 0x400029b0; -mbedtls_rsa_set_padding = 0x400029b4; -mbedtls_rsa_get_len = 0x400029b8; -mbedtls_rsa_check_pubkey = 0x400029bc; -mbedtls_rsa_check_privkey = 0x400029c0; -mbedtls_rsa_check_pub_priv = 0x400029c4; -mbedtls_rsa_public = 0x400029c8; -mbedtls_rsa_private = 0x400029cc; -mbedtls_rsa_pkcs1_encrypt = 0x400029d0; -mbedtls_rsa_rsaes_pkcs1_v15_encrypt = 0x400029d4; -mbedtls_rsa_rsaes_oaep_encrypt = 0x400029d8; -mbedtls_rsa_pkcs1_decrypt = 0x400029dc; -mbedtls_rsa_rsaes_pkcs1_v15_decrypt = 0x400029e0; -mbedtls_rsa_rsaes_oaep_decrypt = 0x400029e4; -mbedtls_rsa_pkcs1_sign = 0x400029e8; -mbedtls_rsa_rsassa_pkcs1_v15_sign = 0x400029ec; -mbedtls_rsa_rsassa_pss_sign = 0x400029f0; -mbedtls_rsa_pkcs1_verify = 0x400029f4; -mbedtls_rsa_rsassa_pkcs1_v15_verify = 0x400029f8; -mbedtls_rsa_rsassa_pss_verify = 0x400029fc; -mbedtls_rsa_rsassa_pss_verify_ext = 0x40002a00; -mbedtls_rsa_free = 0x40002a04; -mbedtls_rsa_deduce_primes = 0x40002a08; -mbedtls_rsa_deduce_private_exponent = 0x40002a0c; -mbedtls_rsa_deduce_crt = 0x40002a10; -mbedtls_rsa_validate_params = 0x40002a14; -mbedtls_rsa_validate_crt = 0x40002a18; -mbedtls_sha1_init = 0x40002a1c; -mbedtls_sha1_free = 0x40002a20; -mbedtls_sha1_clone = 0x40002a24; -mbedtls_sha1_starts_ret = 0x40002a28; -mbedtls_sha1_finish_ret = 0x40002a2c; -mbedtls_sha256_init = 0x40002a30; -mbedtls_sha256_free = 0x40002a34; -mbedtls_sha256_clone = 0x40002a38; -mbedtls_sha256_starts_ret = 0x40002a3c; -mbedtls_sha256_finish_ret = 0x40002a40; -mbedtls_sha256_ret = 0x40002a44; -mbedtls_sha512_init = 0x40002a48; -mbedtls_sha512_free = 0x40002a4c; -mbedtls_sha512_clone = 0x40002a50; -mbedtls_sha512_starts_ret = 0x40002a54; -mbedtls_sha512_update_ret = 0x40002a58; -mbedtls_sha512_finish_ret = 0x40002a5c; -mbedtls_internal_sha512_process = 0x40002a60; -mbedtls_sha512_ret = 0x40002a64; -mbedtls_ssl_conf_endpoint = 0x40002a68; -mbedtls_ssl_conf_transport = 0x40002a6c; -mbedtls_ssl_set_bio = 0x40002a70; -mbedtls_ssl_conf_dh_param_bin = 0x40002a74; -mbedtls_ssl_get_max_frag_len = 0x40002a78; -mbedtls_ssl_get_max_out_record_payload = 0x40002a7c; -mbedtls_ssl_handshake = 0x40002a80; -mbedtls_ssl_handshake_step = 0x40002a84; -mbedtls_ssl_renegotiate = 0x40002a88; -mbedtls_ssl_send_alert_message = 0x40002a8c; -mbedtls_ssl_config_defaults = 0x40002a90; -mbedtls_ssl_session_init = 0x40002a94; -mbedtls_ssl_session_free = 0x40002a98; -mbedtls_ssl_transform_free = 0x40002a9c; -mbedtls_ssl_handshake_free = 0x40002aa0; -mbedtls_ssl_handshake_client_step = 0x40002aa4; -mbedtls_ssl_handshake_wrapup = 0x40002aa8; -mbedtls_ssl_derive_keys = 0x40002aac; -mbedtls_ssl_handle_message_type = 0x40002ab0; -mbedtls_ssl_prepare_handshake_record = 0x40002ab4; -mbedtls_ssl_update_handshake_status = 0x40002ab8; -mbedtls_ssl_read_record = 0x40002abc; -mbedtls_ssl_fetch_input = 0x40002ac0; -mbedtls_ssl_write_handshake_msg = 0x40002ac4; -mbedtls_ssl_write_record = 0x40002ac8; -mbedtls_ssl_flush_output = 0x40002acc; -mbedtls_ssl_parse_certificate = 0x40002ad0; -mbedtls_ssl_write_certificate = 0x40002ad4; -mbedtls_ssl_parse_change_cipher_spec = 0x40002ad8; -mbedtls_ssl_write_change_cipher_spec = 0x40002adc; -mbedtls_ssl_parse_finished = 0x40002ae0; -mbedtls_ssl_write_finished = 0x40002ae4; -mbedtls_ssl_optimize_checksum = 0x40002ae8; -mbedtls_ssl_psk_derive_premaster = 0x40002aec; -mbedtls_ssl_sig_from_pk = 0x40002af0; -mbedtls_ssl_pk_alg_from_sig = 0x40002af4; -mbedtls_ssl_md_alg_from_hash = 0x40002af8; -mbedtls_ssl_hash_from_md_alg = 0x40002afc; -mbedtls_ssl_check_curve = 0x40002b00; -mbedtls_ssl_check_sig_hash = 0x40002b04; -mbedtls_ssl_write_version = 0x40002b08; -mbedtls_ssl_read_version = 0x40002b0c; -mbedtls_ssl_get_key_exchange_md_ssl_tls = 0x40002b10; -mbedtls_ssl_get_key_exchange_md_tls1_2 = 0x40002b14; -mbedtls_ssl_cf_hmac = 0x40002b18; -mbedtls_ssl_cf_memcpy_offset = 0x40002b1c; -mbedtls_x509_crt_parse_der = 0x40002b20; -mbedtls_x509_crt_verify_restartable = 0x40002b24; -mbedtls_x509_crt_check_key_usage = 0x40002b28; -mbedtls_x509_crt_check_extended_key_usage = 0x40002b2c; -mbedtls_x509_crt_is_revoked = 0x40002b30; -mbedtls_x509_crt_init = 0x40002b34; -mbedtls_x509_crt_free = 0x40002b38; -mbedtls_x509_crt_restart_init = 0x40002b3c; -mbedtls_x509_crt_restart_free = 0x40002b40; -mbedtls_x509_get_name = 0x40002b44; -mbedtls_x509_get_alg_null = 0x40002b48; -mbedtls_x509_get_alg = 0x40002b4c; -mbedtls_x509_get_rsassa_pss_params = 0x40002b50; -mbedtls_x509_get_sig = 0x40002b54; -mbedtls_x509_get_sig_alg = 0x40002b58; -mbedtls_x509_get_time = 0x40002b5c; -mbedtls_x509_get_serial = 0x40002b60; -mbedtls_x509_get_ext = 0x40002b64; -mbedtls_aes_xts_init = 0x40002b68; -mbedtls_aes_xts_free = 0x40002b6c; -mbedtls_aes_xts_setkey_enc = 0x40002b70; -mbedtls_aes_xts_setkey_dec = 0x40002b74; -mbedtls_aes_crypt_xts = 0x40002b78; -mbedtls_aes_crypt_cfb128 = 0x40002b7c; -mbedtls_aes_crypt_ofb = 0x40002b80; -mbedtls_aes_crypt_ctr = 0x40002b84; -mbedtls_arc4_init = 0x40002b88; -mbedtls_arc4_free = 0x40002b8c; -mbedtls_arc4_setup = 0x40002b90; -mbedtls_arc4_crypt = 0x40002b94; -mbedtls_ccm_init = 0x40002b98; -mbedtls_ccm_setkey = 0x40002b9c; -mbedtls_ccm_free = 0x40002ba0; -mbedtls_ccm_encrypt_and_tag = 0x40002ba4; -mbedtls_ccm_auth_decrypt = 0x40002ba8; -mbedtls_dhm_make_params = 0x40002bac; -mbedtls_dhm_set_group = 0x40002bb0; -mbedtls_dhm_read_public = 0x40002bb4; -mbedtls_ecdh_make_params = 0x40002bb8; -mbedtls_ecdh_read_public = 0x40002bbc; -mbedtls_entropy_init = 0x40002bc0; -mbedtls_entropy_free = 0x40002bc4; -mbedtls_gcm_init = 0x40002bc8; -mbedtls_gcm_setkey = 0x40002bcc; -mbedtls_gcm_auth_decrypt = 0x40002bd0; -mbedtls_gcm_free = 0x40002bd4; -mbedtls_md5_init = 0x40002bd8; -mbedtls_md5_free = 0x40002bdc; -mbedtls_md5_clone = 0x40002be0; -mbedtls_md5_starts_ret = 0x40002be4; -mbedtls_md5_update_ret = 0x40002be8; -mbedtls_md5_finish_ret = 0x40002bec; -mbedtls_internal_md5_process = 0x40002bf0; -mbedtls_md5_ret = 0x40002bf4; -mbedtls_pk_get_bitlen = 0x40002bf8; -mbedtls_pk_sign = 0x40002bfc; -mbedtls_pk_decrypt = 0x40002c00; -mbedtls_pk_parse_key = 0x40002c04; -mbedtls_sha1_ret = 0x40002c08; -mbedtls_ssl_init = 0x40002c0c; -mbedtls_ssl_setup = 0x40002c10; -mbedtls_ssl_conf_authmode = 0x40002c14; -mbedtls_ssl_conf_rng = 0x40002c18; -mbedtls_ssl_conf_ca_chain = 0x40002c1c; -mbedtls_ssl_conf_own_cert = 0x40002c20; -mbedtls_ssl_read = 0x40002c24; -mbedtls_ssl_write = 0x40002c28; -mbedtls_ssl_config_init = 0x40002c2c; -mbedtls_ssl_sig_hash_set_find = 0x40002c30; -mbedtls_ssl_sig_hash_set_add = 0x40002c34; -mbedtls_ssl_sig_hash_set_const_hash = 0x40002c38; -mbedtls_ssl_sig_from_pk_alg = 0x40002c3c; -mbedtls_ssl_set_calc_verify_md = 0x40002c40; -mbedtls_x509_crt_parse = 0x40002c44; -/* Data (.data, .bss, .rodata) */ -p_osi_mbedtls_rom_funcs = 0x3fcdfaa0; -mbedtls_x509_crt_profile_default = 0x3ff4fba4; -mbedtls_x509_crt_profile_suiteb = 0x3ff4fb94; -aes_FSb_ptr = 0x3fcdfa9c; -AES_RT0_ptr = 0x3fcdfa98; -AES_RT1_ptr = 0x3fcdfa94; -AES_RT2_ptr = 0x3fcdfa90; -AES_RT3_ptr = 0x3fcdfa8c; -AES_FT0_ptr = 0x3fcdfa88; -AES_FT1_ptr = 0x3fcdfa84; -AES_FT2_ptr = 0x3fcdfa80; -AES_FT3_ptr = 0x3fcdfa7c; -bignum_small_prime_ptr = 0x3fcdfa78; -sha512_K_ptr = 0x3fcdfa74; - diff --git a/tools/esptool_py/flasher_stub/ld/rom_32c3.ld b/tools/esptool_py/flasher_stub/ld/rom_32c3.ld deleted file mode 100755 index ecaaf49281..0000000000 --- a/tools/esptool_py/flasher_stub/ld/rom_32c3.ld +++ /dev/null @@ -1,2200 +0,0 @@ -/* ROM function interface esp32c3.rom.ld for esp32c3 - * - * - * Generated from ./interface-esp32c3.yml md5sum 93b28a9e1fe42d212018eb4336849208 - * - * Compatible with ROM where ECO version equal or greater to 0. - * - * THIS FILE WAS AUTOMATICALLY GENERATED. DO NOT EDIT. - */ - - -PROVIDE ( SPIWrite = esp_rom_spiflash_write); -PROVIDE ( SPI_read_status_high = esp_rom_spiflash_read_statushigh); -PROVIDE ( SPI_write_status = esp_rom_spiflash_write_status); -PROVIDE ( SPIRead = esp_rom_spiflash_read); -PROVIDE ( SPIParamCfg = esp_rom_spiflash_config_param); -PROVIDE ( SPIEraseChip = esp_rom_spiflash_erase_chip); -PROVIDE ( SPIEraseSector = esp_rom_spiflash_erase_sector); -PROVIDE ( SPIEraseBlock = esp_rom_spiflash_erase_block); -PROVIDE ( SPI_Write_Encrypt_Enable = esp_rom_spiflash_write_encrypted_enable); -PROVIDE ( SPI_Write_Encrypt_Disable = esp_rom_spiflash_write_encrypted_disable); -PROVIDE ( SPI_Encrypt_Write = esp_rom_spiflash_write_encrypted); - - -/*************************************** - Group common - ***************************************/ - -/* Functions */ -rtc_get_reset_reason = 0x40000018; -analog_super_wdt_reset_happened = 0x4000001c; -jtag_cpu_reset_happened = 0x40000020; -rtc_get_wakeup_cause = 0x40000024; -rtc_boot_control = 0x40000028; -rtc_select_apb_bridge = 0x4000002c; -rtc_unhold_all_pads = 0x40000030; -set_rtc_memory_crc = 0x40000034; -cacl_rtc_memory_crc = 0x40000038; -ets_is_print_boot = 0x4000003c; -ets_printf = 0x40000040; -ets_install_putc1 = 0x40000044; -ets_install_uart_printf = 0x40000048; -ets_install_putc2 = 0x4000004c; -PROVIDE( ets_delay_us = 0x40000050 ); -ets_get_stack_info = 0x40000054; -ets_install_lock = 0x40000058; -ets_backup_dma_copy = 0x4000005c; -ets_apb_backup_init_lock_func = 0x40000060; -UartRxString = 0x40000064; -uart_tx_one_char = 0x40000068; -uart_tx_one_char2 = 0x4000006c; -uart_rx_one_char = 0x40000070; -uart_rx_one_char_block = 0x40000074; -uart_rx_readbuff = 0x40000078; -uartAttach = 0x4000007c; -uart_tx_flush = 0x40000080; -uart_tx_wait_idle = 0x40000084; -uart_div_modify = 0x40000088; -multofup = 0x4000008c; -software_reset = 0x40000090; -software_reset_cpu = 0x40000094; -assist_debug_clock_enable = 0x40000098; -assist_debug_record_enable = 0x4000009c; -clear_super_wdt_reset_flag = 0x400000a0; -disable_default_watchdog = 0x400000a4; -send_packet = 0x400000a8; -recv_packet = 0x400000ac; -GetUartDevice = 0x400000b0; -GetSecurityInfoProc = 0x4004b9da; -GetSecurityInfoProcNewEco = 0x4004d51e; /* manually added from esp32c3eco7-20230720; new address of function for eco7+ */ -UartDwnLdProc = 0x400000b4; -Uart_Init = 0x400000b8; -ets_set_user_start = 0x400000bc; -/* Data (.data, .bss, .rodata) */ -ets_rom_layout_p = 0x3ff1fffc; -ets_ops_table_ptr = 0x3fcdfffc; - - -/*************************************** - Group miniz - ***************************************/ - -/* Functions */ -mz_adler32 = 0x400000c0; -mz_crc32 = 0x400000c4; -mz_free = 0x400000c8; -tdefl_compress = 0x400000cc; -tdefl_compress_buffer = 0x400000d0; -tdefl_compress_mem_to_heap = 0x400000d4; -tdefl_compress_mem_to_mem = 0x400000d8; -tdefl_compress_mem_to_output = 0x400000dc; -tdefl_get_adler32 = 0x400000e0; -tdefl_get_prev_return_status = 0x400000e4; -tdefl_init = 0x400000e8; -tdefl_write_image_to_png_file_in_memory = 0x400000ec; -tdefl_write_image_to_png_file_in_memory_ex = 0x400000f0; -tinfl_decompress = 0x400000f4; -tinfl_decompress_mem_to_callback = 0x400000f8; -tinfl_decompress_mem_to_heap = 0x400000fc; -tinfl_decompress_mem_to_mem = 0x40000100; - - -/*************************************** - Group tjpgd - ***************************************/ - -/* Functions */ -jd_prepare = 0x40000104; -jd_decomp = 0x40000108; - - -/*************************************** - Group spiflash_legacy - ***************************************/ - -/* Functions */ -PROVIDE( esp_rom_spiflash_wait_idle = 0x4000010c ); -PROVIDE( esp_rom_spiflash_write_encrypted = 0x40000110 ); -PROVIDE( esp_rom_spiflash_write_encrypted_dest = 0x40000114 ); -PROVIDE( esp_rom_spiflash_write_encrypted_enable = 0x40000118 ); -PROVIDE( esp_rom_spiflash_write_encrypted_disable = 0x4000011c ); -PROVIDE( esp_rom_spiflash_erase_chip = 0x40000120 ); -PROVIDE( esp_rom_spiflash_erase_block = 0x40000124 ); -PROVIDE( esp_rom_spiflash_erase_sector = 0x40000128 ); -PROVIDE( esp_rom_spiflash_write = 0x4000012c ); -PROVIDE( esp_rom_spiflash_read = 0x40000130 ); -PROVIDE( esp_rom_spiflash_config_param = 0x40000134 ); -PROVIDE( esp_rom_spiflash_read_user_cmd = 0x40000138 ); -PROVIDE( esp_rom_spiflash_select_qio_pins = 0x4000013c ); -PROVIDE( esp_rom_spiflash_unlock = 0x40000140 ); -PROVIDE( esp_rom_spi_flash_auto_sus_res = 0x40000144 ); -PROVIDE( esp_rom_spi_flash_send_resume = 0x40000148 ); -PROVIDE( esp_rom_spi_flash_update_id = 0x4000014c ); -PROVIDE( esp_rom_spiflash_config_clk = 0x40000150 ); -PROVIDE( esp_rom_spiflash_config_readmode = 0x40000154 ); -PROVIDE( esp_rom_spiflash_read_status = 0x40000158 ); -PROVIDE( esp_rom_spiflash_read_statushigh = 0x4000015c ); -PROVIDE( esp_rom_spiflash_write_status = 0x40000160 ); -PROVIDE( spi_flash_attach = 0x40000164 ); -PROVIDE( spi_flash_get_chip_size = 0x40000168 ); -PROVIDE( spi_flash_guard_set = 0x4000016c ); -PROVIDE( spi_flash_guard_get = 0x40000170 ); -PROVIDE( spi_flash_write_config_set = 0x40000174 ); -PROVIDE( spi_flash_write_config_get = 0x40000178 ); -PROVIDE( spi_flash_safe_write_address_func_set = 0x4000017c ); -PROVIDE( spi_flash_unlock = 0x40000180 ); -PROVIDE( spi_flash_erase_range = 0x40000184 ); -PROVIDE( spi_flash_erase_sector = 0x40000188 ); -PROVIDE( spi_flash_write = 0x4000018c ); -PROVIDE( spi_flash_read = 0x40000190 ); -PROVIDE( spi_flash_write_encrypted = 0x40000194 ); -PROVIDE( spi_flash_read_encrypted = 0x40000198 ); -PROVIDE( spi_flash_mmap_os_func_set = 0x4000019c ); -PROVIDE( spi_flash_mmap_page_num_init = 0x400001a0 ); -PROVIDE( spi_flash_mmap = 0x400001a4 ); -PROVIDE( spi_flash_mmap_pages = 0x400001a8 ); -PROVIDE( spi_flash_munmap = 0x400001ac ); -PROVIDE( spi_flash_mmap_dump = 0x400001b0 ); -PROVIDE( spi_flash_check_and_flush_cache = 0x400001b4 ); -PROVIDE( spi_flash_mmap_get_free_pages = 0x400001b8 ); -PROVIDE( spi_flash_cache2phys = 0x400001bc ); -PROVIDE( spi_flash_phys2cache = 0x400001c0 ); -PROVIDE( spi_flash_disable_cache = 0x400001c4 ); -PROVIDE( spi_flash_restore_cache = 0x400001c8 ); -PROVIDE( spi_flash_cache_enabled = 0x400001cc ); -PROVIDE( spi_flash_enable_cache = 0x400001d0 ); -PROVIDE( spi_cache_mode_switch = 0x400001d4 ); -PROVIDE( spi_common_set_dummy_output = 0x400001d8 ); -PROVIDE( spi_common_set_flash_cs_timing = 0x400001dc ); -PROVIDE( esp_enable_cache_flash_wrap = 0x400001e0 ); -PROVIDE( SPIEraseArea = 0x400001e4 ); -PROVIDE( SPILock = 0x400001e8 ); -PROVIDE( SPIMasterReadModeCnfig = 0x400001ec ); -PROVIDE( SPI_Common_Command = 0x400001f0 ); -PROVIDE( SPI_WakeUp = 0x400001f4 ); -PROVIDE( SPI_block_erase = 0x400001f8 ); -PROVIDE( SPI_chip_erase = 0x400001fc ); -PROVIDE( SPI_init = 0x40000200 ); -PROVIDE( SPI_page_program = 0x40000204 ); -PROVIDE( SPI_read_data = 0x40000208 ); -PROVIDE( SPI_sector_erase = 0x4000020c ); -PROVIDE( SPI_write_enable = 0x40000210 ); -PROVIDE( SelectSpiFunction = 0x40000214 ); -PROVIDE( SetSpiDrvs = 0x40000218 ); -PROVIDE( Wait_SPI_Idle = 0x4000021c ); -PROVIDE( spi_dummy_len_fix = 0x40000220 ); -PROVIDE( Disable_QMode = 0x40000224 ); -PROVIDE( Enable_QMode = 0x40000228 ); -/* Data (.data, .bss, .rodata) */ -PROVIDE( rom_spiflash_legacy_funcs = 0x3fcdfff4 ); -PROVIDE( rom_spiflash_legacy_data = 0x3fcdfff0 ); -PROVIDE( g_flash_guard_ops = 0x3fcdfff8 ); - - -/*************************************** - Group spi_flash_hal - ***************************************/ - -/* Functions */ -PROVIDE( spi_flash_hal_poll_cmd_done = 0x4000022c ); -PROVIDE( spi_flash_hal_device_config = 0x40000230 ); -PROVIDE( spi_flash_hal_configure_host_io_mode = 0x40000234 ); -PROVIDE( spi_flash_hal_common_command = 0x40000238 ); -PROVIDE( spi_flash_hal_read = 0x4000023c ); -PROVIDE( spi_flash_hal_erase_chip = 0x40000240 ); -PROVIDE( spi_flash_hal_erase_sector = 0x40000244 ); -PROVIDE( spi_flash_hal_erase_block = 0x40000248 ); -PROVIDE( spi_flash_hal_program_page = 0x4000024c ); -PROVIDE( spi_flash_hal_set_write_protect = 0x40000250 ); -PROVIDE( spi_flash_hal_host_idle = 0x40000254 ); - - -/*************************************** - Group spi_flash_chips - ***************************************/ - -/* Functions */ -PROVIDE( spi_flash_chip_generic_probe = 0x40000258 ); -PROVIDE( spi_flash_chip_generic_detect_size = 0x4000025c ); -PROVIDE( spi_flash_chip_generic_write = 0x40000260 ); -PROVIDE( spi_flash_chip_generic_write_encrypted = 0x40000264 ); -PROVIDE( spi_flash_chip_generic_set_write_protect = 0x40000268 ); -PROVIDE( spi_flash_common_write_status_16b_wrsr = 0x4000026c ); -PROVIDE( spi_flash_chip_generic_reset = 0x40000270 ); -PROVIDE( spi_flash_chip_generic_erase_chip = 0x40000274 ); -PROVIDE( spi_flash_chip_generic_erase_sector = 0x40000278 ); -PROVIDE( spi_flash_chip_generic_erase_block = 0x4000027c ); -PROVIDE( spi_flash_chip_generic_page_program = 0x40000280 ); -PROVIDE( spi_flash_chip_generic_get_write_protect = 0x40000284 ); -PROVIDE( spi_flash_common_read_status_16b_rdsr_rdsr2 = 0x40000288 ); -PROVIDE( spi_flash_chip_generic_read_reg = 0x4000028c ); -PROVIDE( spi_flash_chip_generic_yield = 0x40000290 ); -PROVIDE( spi_flash_generic_wait_host_idle = 0x40000294 ); -PROVIDE( spi_flash_chip_generic_wait_idle = 0x40000298 ); -PROVIDE( spi_flash_chip_generic_config_host_io_mode = 0x4000029c ); -PROVIDE( spi_flash_chip_generic_read = 0x400002a0 ); -PROVIDE( spi_flash_common_read_status_8b_rdsr2 = 0x400002a4 ); -PROVIDE( spi_flash_chip_generic_get_io_mode = 0x400002a8 ); -PROVIDE( spi_flash_common_read_status_8b_rdsr = 0x400002ac ); -PROVIDE( spi_flash_common_write_status_8b_wrsr = 0x400002b0 ); -PROVIDE( spi_flash_common_write_status_8b_wrsr2 = 0x400002b4 ); -PROVIDE( spi_flash_common_set_io_mode = 0x400002b8 ); -PROVIDE( spi_flash_chip_generic_set_io_mode = 0x400002bc ); -PROVIDE( spi_flash_chip_gd_get_io_mode = 0x400002c0 ); -PROVIDE( spi_flash_chip_gd_probe = 0x400002c4 ); -PROVIDE( spi_flash_chip_gd_set_io_mode = 0x400002c8 ); -/* Data (.data, .bss, .rodata) */ -PROVIDE( spi_flash_chip_generic_config_data = 0x3fcdffec ); - - -/*************************************** - Group memspi_host - ***************************************/ - -/* Functions */ -PROVIDE( memspi_host_read_id_hs = 0x400002cc ); -PROVIDE( memspi_host_read_status_hs = 0x400002d0 ); -PROVIDE( memspi_host_flush_cache = 0x400002d4 ); -PROVIDE( memspi_host_erase_chip = 0x400002d8 ); -PROVIDE( memspi_host_erase_sector = 0x400002dc ); -PROVIDE( memspi_host_erase_block = 0x400002e0 ); -PROVIDE( memspi_host_program_page = 0x400002e4 ); -PROVIDE( memspi_host_read = 0x400002e8 ); -PROVIDE( memspi_host_set_write_protect = 0x400002ec ); -PROVIDE( memspi_host_set_max_read_len = 0x400002f0 ); -PROVIDE( memspi_host_read_data_slicer = 0x400002f4 ); -PROVIDE( memspi_host_write_data_slicer = 0x400002f8 ); - - -/*************************************** - Group esp_flash - ***************************************/ - -/* Functions */ -PROVIDE( esp_flash_chip_driver_initialized = 0x400002fc ); -PROVIDE( esp_flash_read_id = 0x40000300 ); -PROVIDE( esp_flash_get_size = 0x40000304 ); -PROVIDE( esp_flash_erase_chip = 0x40000308 ); -PROVIDE( esp_flash_erase_region = 0x4000030c ); -PROVIDE( esp_flash_get_chip_write_protect = 0x40000310 ); -PROVIDE( esp_flash_set_chip_write_protect = 0x40000314 ); -PROVIDE( esp_flash_get_protectable_regions = 0x40000318 ); -PROVIDE( esp_flash_get_protected_region = 0x4000031c ); -PROVIDE( esp_flash_set_protected_region = 0x40000320 ); -PROVIDE( esp_flash_read = 0x40000324 ); -PROVIDE( esp_flash_write = 0x40000328 ); -PROVIDE( esp_flash_write_encrypted = 0x4000032c ); -PROVIDE( esp_flash_read_encrypted = 0x40000330 ); -PROVIDE( esp_flash_get_io_mode = 0x40000334 ); -PROVIDE( esp_flash_set_io_mode = 0x40000338 ); -PROVIDE( spi_flash_boot_attach = 0x4000033c ); -PROVIDE( spi_flash_dump_counters = 0x40000340 ); -PROVIDE( spi_flash_get_counters = 0x40000344 ); -PROVIDE( spi_flash_op_counters_config = 0x40000348 ); -PROVIDE( spi_flash_reset_counters = 0x4000034c ); -/* Data (.data, .bss, .rodata) */ -PROVIDE( esp_flash_default_chip = 0x3fcdffe8 ); -PROVIDE( esp_flash_api_funcs = 0x3fcdffe4 ); - - -/*************************************** - Group cache - ***************************************/ - -/* Functions */ -PROVIDE( Cache_Get_ICache_Line_Size = 0x400004b0 ); -PROVIDE( Cache_Get_Mode = 0x400004b4 ); -PROVIDE( Cache_Address_Through_IBus = 0x400004b8 ); -PROVIDE( Cache_Address_Through_DBus = 0x400004bc ); -PROVIDE( Cache_Set_Default_Mode = 0x400004c0 ); -PROVIDE( Cache_Enable_Defalut_ICache_Mode = 0x400004c4 ); -PROVIDE( ROM_Boot_Cache_Init = 0x400004c8 ); -PROVIDE( Cache_Invalidate_ICache_Items = 0x400004cc ); -PROVIDE( Cache_Op_Addr = 0x400004d0 ); -PROVIDE( Cache_Invalidate_Addr = 0x400004d4 ); -PROVIDE( Cache_Invalidate_ICache_All = 0x400004d8 ); -PROVIDE( Cache_Mask_All = 0x400004dc ); -PROVIDE( Cache_UnMask_Dram0 = 0x400004e0 ); -PROVIDE( Cache_Suspend_ICache_Autoload = 0x400004e4 ); -PROVIDE( Cache_Resume_ICache_Autoload = 0x400004e8 ); -PROVIDE( Cache_Start_ICache_Preload = 0x400004ec ); -PROVIDE( Cache_ICache_Preload_Done = 0x400004f0 ); -PROVIDE( Cache_End_ICache_Preload = 0x400004f4 ); -PROVIDE( Cache_Config_ICache_Autoload = 0x400004f8 ); -PROVIDE( Cache_Enable_ICache_Autoload = 0x400004fc ); -PROVIDE( Cache_Disable_ICache_Autoload = 0x40000500 ); -PROVIDE( Cache_Enable_ICache_PreLock = 0x40000504 ); -PROVIDE( Cache_Disable_ICache_PreLock = 0x40000508 ); -PROVIDE( Cache_Lock_ICache_Items = 0x4000050c ); -PROVIDE( Cache_Unlock_ICache_Items = 0x40000510 ); -PROVIDE( Cache_Lock_Addr = 0x40000514 ); -PROVIDE( Cache_Unlock_Addr = 0x40000518 ); -PROVIDE( Cache_Disable_ICache = 0x4000051c ); -PROVIDE( Cache_Enable_ICache = 0x40000520 ); -PROVIDE( Cache_Suspend_ICache = 0x40000524 ); -PROVIDE( Cache_Resume_ICache = 0x40000528 ); -PROVIDE( Cache_Freeze_ICache_Enable = 0x4000052c ); -PROVIDE( Cache_Freeze_ICache_Disable = 0x40000530 ); -PROVIDE( Cache_Pms_Lock = 0x40000534 ); -PROVIDE( Cache_Ibus_Pms_Set_Addr = 0x40000538 ); -PROVIDE( Cache_Ibus_Pms_Set_Attr = 0x4000053c ); -PROVIDE( Cache_Dbus_Pms_Set_Addr = 0x40000540 ); -PROVIDE( Cache_Dbus_Pms_Set_Attr = 0x40000544 ); -PROVIDE( Cache_Set_IDROM_MMU_Size = 0x40000548 ); -PROVIDE( Cache_Get_IROM_MMU_End = 0x4000054c ); -PROVIDE( Cache_Get_DROM_MMU_End = 0x40000550 ); -PROVIDE( Cache_Owner_Init = 0x40000554 ); -PROVIDE( Cache_Occupy_ICache_MEMORY = 0x40000558 ); -PROVIDE( Cache_MMU_Init = 0x4000055c ); -PROVIDE( Cache_Ibus_MMU_Set = 0x40000560 ); -PROVIDE( Cache_Dbus_MMU_Set = 0x40000564 ); -PROVIDE( Cache_Count_Flash_Pages = 0x40000568 ); -PROVIDE( Cache_Travel_Tag_Memory = 0x4000056c ); -PROVIDE( Cache_Get_Virtual_Addr = 0x40000570 ); -PROVIDE( Cache_Get_Memory_BaseAddr = 0x40000574 ); -PROVIDE( Cache_Get_Memory_Addr = 0x40000578 ); -PROVIDE( Cache_Get_Memory_value = 0x4000057c ); -/* Data (.data, .bss, .rodata) */ -PROVIDE( rom_cache_op_cb = 0x3fcdffd8 ); -PROVIDE( rom_cache_internal_table_ptr = 0x3fcdffd4 ); - - -/*************************************** - Group clock - ***************************************/ - -/* Functions */ -ets_get_apb_freq = 0x40000580; -ets_get_cpu_frequency = 0x40000584; -ets_update_cpu_frequency = 0x40000588; -ets_get_printf_channel = 0x4000058c; -ets_get_xtal_div = 0x40000590; -ets_set_xtal_div = 0x40000594; -ets_get_xtal_freq = 0x40000598; - - -/*************************************** - Group gpio - ***************************************/ - -/* Functions */ -gpio_input_get = 0x4000059c; -gpio_matrix_in = 0x400005a0; -gpio_matrix_out = 0x400005a4; -gpio_output_disable = 0x400005a8; -gpio_output_enable = 0x400005ac; -gpio_output_set = 0x400005b0; -gpio_pad_hold = 0x400005b4; -gpio_pad_input_disable = 0x400005b8; -gpio_pad_input_enable = 0x400005bc; -gpio_pad_pulldown = 0x400005c0; -gpio_pad_pullup = 0x400005c4; -gpio_pad_select_gpio = 0x400005c8; -gpio_pad_set_drv = 0x400005cc; -gpio_pad_unhold = 0x400005d0; -gpio_pin_wakeup_disable = 0x400005d4; -gpio_pin_wakeup_enable = 0x400005d8; -gpio_bypass_matrix_in = 0x400005dc; - - -/*************************************** - Group interrupts - ***************************************/ - -/* Functions */ -esprv_intc_int_set_priority = 0x400005e0; -esprv_intc_int_set_threshold = 0x400005e4; -esprv_intc_int_enable = 0x400005e8; -esprv_intc_int_disable = 0x400005ec; -esprv_intc_int_set_type = 0x400005f0; -intr_matrix_set = 0x400005f4; -ets_intr_lock = 0x400005f8; -ets_intr_unlock = 0x400005fc; -PROVIDE( intr_handler_set = 0x40000600 ); -ets_isr_attach = 0x40000604; -ets_isr_mask = 0x40000608; -ets_isr_unmask = 0x4000060c; - - -/*************************************** - Group crypto - ***************************************/ - -/* Functions */ -md5_vector = 0x40000610; -MD5Init = 0x40000614; -MD5Update = 0x40000618; -MD5Final = 0x4000061c; -hmac_md5_vector = 0x40000620; -hmac_md5 = 0x40000624; -crc32_le = 0x40000628; -crc32_be = 0x4000062c; -crc16_le = 0x40000630; -crc16_be = 0x40000634; -crc8_le = 0x40000638; -crc8_be = 0x4000063c; -esp_crc8 = 0x40000640; -ets_sha_enable = 0x40000644; -ets_sha_disable = 0x40000648; -ets_sha_get_state = 0x4000064c; -ets_sha_init = 0x40000650; -ets_sha_process = 0x40000654; -ets_sha_starts = 0x40000658; -ets_sha_update = 0x4000065c; -ets_sha_finish = 0x40000660; -ets_sha_clone = 0x40000664; -ets_hmac_enable = 0x40000668; -ets_hmac_disable = 0x4000066c; -ets_hmac_calculate_message = 0x40000670; -ets_hmac_calculate_downstream = 0x40000674; -ets_hmac_invalidate_downstream = 0x40000678; -ets_jtag_enable_temporarily = 0x4000067c; -ets_aes_enable = 0x40000680; -ets_aes_disable = 0x40000684; -ets_aes_setkey = 0x40000688; -ets_aes_block = 0x4000068c; -ets_bigint_enable = 0x40000690; -ets_bigint_disable = 0x40000694; -ets_bigint_multiply = 0x40000698; -ets_bigint_modmult = 0x4000069c; -ets_bigint_modexp = 0x400006a0; -ets_bigint_wait_finish = 0x400006a4; -ets_bigint_getz = 0x400006a8; -ets_ds_enable = 0x400006ac; -ets_ds_disable = 0x400006b0; -ets_ds_start_sign = 0x400006b4; -ets_ds_is_busy = 0x400006b8; -ets_ds_finish_sign = 0x400006bc; -ets_ds_encrypt_params = 0x400006c0; -ets_aes_setkey_dec = 0x400006c4; -ets_aes_setkey_enc = 0x400006c8; -ets_mgf1_sha256 = 0x400006cc; - - -/*************************************** - Group efuse - ***************************************/ - -/* Functions */ -ets_efuse_read = 0x400006d0; -ets_efuse_program = 0x400006d4; -ets_efuse_clear_program_registers = 0x400006d8; -ets_efuse_write_key = 0x400006dc; -ets_efuse_get_read_register_address = 0x400006e0; -ets_efuse_get_key_purpose = 0x400006e4; -ets_efuse_key_block_unused = 0x400006e8; -ets_efuse_find_unused_key_block = 0x400006ec; -ets_efuse_rs_calculate = 0x400006f0; -ets_efuse_count_unused_key_blocks = 0x400006f4; -ets_efuse_secure_boot_enabled = 0x400006f8; -ets_efuse_secure_boot_aggressive_revoke_enabled = 0x400006fc; -ets_efuse_cache_encryption_enabled = 0x40000700; -ets_efuse_download_modes_disabled = 0x40000704; -ets_efuse_find_purpose = 0x40000708; -ets_efuse_flash_opi_5pads_power_sel_vddspi = 0x4000070c; -ets_efuse_force_send_resume = 0x40000710; -ets_efuse_get_flash_delay_us = 0x40000714; -ets_efuse_get_mac = 0x40000718; -ets_efuse_get_spiconfig = 0x4000071c; -ets_efuse_usb_print_is_disabled = 0x40000720; -ets_efuse_get_uart_print_channel = 0x40000724; -ets_efuse_get_uart_print_control = 0x40000728; -ets_efuse_get_wp_pad = 0x4000072c; -ets_efuse_legacy_spi_boot_mode_disabled = 0x40000730; -ets_efuse_security_download_modes_enabled = 0x40000734; -ets_efuse_set_timing = 0x40000738; -ets_efuse_jtag_disabled = 0x4000073c; -ets_efuse_usb_download_mode_disabled = 0x40000740; -ets_efuse_usb_module_disabled = 0x40000744; -ets_efuse_usb_device_disabled = 0x40000748; - - -/*************************************** - Group secureboot - ***************************************/ - -/* Functions */ -ets_emsa_pss_verify = 0x4000074c; -ets_rsa_pss_verify = 0x40000750; -ets_secure_boot_verify_bootloader_with_keys = 0x40000754; -ets_secure_boot_verify_signature = 0x40000758; -ets_secure_boot_read_key_digests = 0x4000075c; -ets_secure_boot_revoke_public_key_digest = 0x40000760; - - -/*************************************** - Group usb_uart - ***************************************/ - -/* Functions */ -PROVIDE( usb_uart_rx_one_char = 0x400008cc ); -PROVIDE( usb_uart_rx_one_char_block = 0x400008d0 ); -PROVIDE( usb_uart_tx_flush = 0x400008d4 ); -PROVIDE( usb_uart_tx_one_char = 0x400008d8 ); -/* Data (.data, .bss, .rodata) */ -PROVIDE( g_uart_print = 0x3fcdffd1 ); -PROVIDE( g_usb_print = 0x3fcdffd0 ); - - -/*************************************** - Group bluetooth - ***************************************/ - -/* Functions */ -bt_rf_coex_get_dft_cfg = 0x400008dc; -bt_rf_coex_hooks_p_set = 0x400008e0; -btdm_con_maxevtime_cal_impl = 0x400008e4; -btdm_controller_get_compile_version_impl = 0x400008e8; -btdm_controller_rom_data_init = 0x400008ec; -btdm_dis_privacy_err_report_impl = 0x400008f0; -btdm_disable_adv_delay_impl = 0x400008f4; -btdm_enable_scan_continue_impl = 0x400008f8; -btdm_enable_scan_forever_impl = 0x400008fc; -btdm_get_power_state_impl = 0x40000900; -btdm_get_prevent_sleep_flag_impl = 0x40000904; -btdm_power_state_active_impl = 0x40000908; -btdm_switch_phy_coded_impl = 0x4000090c; -hci_acl_data_handler = 0x40000910; -hci_disconnect_cmd_handler = 0x40000914; -hci_le_con_upd_cmd_handler = 0x40000918; -hci_le_ltk_req_neg_reply_cmd_handler = 0x4000091c; -hci_le_ltk_req_reply_cmd_handler = 0x40000920; -hci_le_rd_chnl_map_cmd_handler = 0x40000924; -hci_le_rd_phy_cmd_handler = 0x40000928; -hci_le_rd_rem_feats_cmd_handler = 0x4000092c; -hci_le_rem_con_param_req_neg_reply_cmd_handler = 0x40000930; -hci_le_rem_con_param_req_reply_cmd_handler = 0x40000934; -hci_le_set_data_len_cmd_handler = 0x40000938; -hci_le_set_phy_cmd_handler = 0x4000093c; -hci_le_start_enc_cmd_handler = 0x40000940; -hci_rd_auth_payl_to_cmd_handler = 0x40000944; -hci_rd_rem_ver_info_cmd_handler = 0x40000948; -hci_rd_rssi_cmd_handler = 0x4000094c; -hci_rd_tx_pwr_lvl_cmd_handler = 0x40000950; -hci_vs_set_pref_slave_evt_dur_cmd_handler = 0x40000954; -hci_vs_set_pref_slave_latency_cmd_handler = 0x40000958; -hci_wr_auth_payl_to_cmd_handler = 0x4000095c; -ll_channel_map_ind_handler = 0x40000960; -ll_connection_param_req_handler = 0x40000964; -ll_connection_param_rsp_handler = 0x40000968; -ll_connection_update_ind_handler = 0x4000096c; -ll_enc_req_handler = 0x40000970; -ll_enc_rsp_handler = 0x40000974; -ll_feature_req_handler = 0x40000978; -ll_feature_rsp_handler = 0x4000097c; -ll_length_req_handler = 0x40000980; -ll_length_rsp_handler = 0x40000984; -ll_min_used_channels_ind_handler = 0x40000988; -ll_pause_enc_req_handler = 0x4000098c; -ll_pause_enc_rsp_handler = 0x40000990; -ll_phy_req_handler = 0x40000994; -ll_phy_rsp_handler = 0x40000998; -ll_phy_update_ind_handler = 0x4000099c; -ll_ping_req_handler = 0x400009a0; -ll_ping_rsp_handler = 0x400009a4; -ll_slave_feature_req_handler = 0x400009a8; -ll_start_enc_req_handler = 0x400009ac; -ll_start_enc_rsp_handler = 0x400009b0; -ll_terminate_ind_handler = 0x400009b4; -ll_version_ind_handler = 0x400009b8; -llc_auth_payl_nearly_to_handler = 0x400009bc; -llc_auth_payl_real_to_handler = 0x400009c0; -llc_encrypt_ind_handler = 0x400009c4; -llc_hci_command_handler_wrapper = 0x400009c8; -llc_ll_connection_param_req_pdu_send = 0x400009cc; -llc_ll_connection_param_rsp_pdu_send = 0x400009d0; -llc_ll_connection_update_ind_pdu_send = 0x400009d4; -llc_ll_enc_req_pdu_send = 0x400009d8; -llc_ll_enc_rsp_pdu_send = 0x400009dc; -llc_ll_feature_req_pdu_send = 0x400009e0; -llc_ll_feature_rsp_pdu_send = 0x400009e4; -llc_ll_length_req_pdu_send = 0x400009e8; -llc_ll_length_rsp_pdu_send = 0x400009ec; -llc_ll_pause_enc_req_pdu_send = 0x400009f0; -llc_ll_pause_enc_rsp_pdu_send = 0x400009f4; -llc_ll_phy_req_pdu_send = 0x400009f8; -llc_ll_phy_rsp_pdu_send = 0x400009fc; -llc_ll_ping_req_pdu_send = 0x40000a00; -llc_ll_ping_rsp_pdu_send = 0x40000a04; -llc_ll_start_enc_req_pdu_send = 0x40000a08; -llc_ll_start_enc_rsp_pdu_send = 0x40000a0c; -llc_ll_terminate_ind_pdu_send = 0x40000a10; -llc_ll_unknown_rsp_pdu_send = 0x40000a14; -llc_llcp_ch_map_update_ind_pdu_send = 0x40000a18; -llc_llcp_phy_upd_ind_pdu_send = 0x40000a1c; -llc_llcp_version_ind_pdu_send = 0x40000a20; -llc_op_ch_map_upd_ind_handler = 0x40000a24; -llc_op_con_upd_ind_handler = 0x40000a28; -llc_op_disconnect_ind_handler = 0x40000a2c; -llc_op_dl_upd_ind_handler = 0x40000a30; -llc_op_encrypt_ind_handler = 0x40000a34; -llc_op_feats_exch_ind_handler = 0x40000a38; -llc_op_le_ping_ind_handler = 0x40000a3c; -llc_op_phy_upd_ind_handler = 0x40000a40; -llc_op_ver_exch_ind_handler = 0x40000a44; -llc_stopped_ind_handler = 0x40000a48; -lld_acl_rx_ind_handler = 0x40000a4c; -lld_acl_tx_cfm_handler = 0x40000a50; -lld_adv_end_ind_handler = 0x40000a54; -lld_adv_rep_ind_handler = 0x40000a58; -lld_ch_map_upd_cfm_handler = 0x40000a5c; -lld_con_estab_ind_handler = 0x40000a60; -lld_con_evt_sd_evt_time_set = 0x40000a64; -lld_con_offset_upd_ind_handler = 0x40000a68; -lld_con_param_upd_cfm_handler = 0x40000a6c; -lld_disc_ind_handler = 0x40000a70; -lld_init_end_ind_handler = 0x40000a74; -lld_llcp_rx_ind_handler_wrapper = 0x40000a78; -lld_llcp_tx_cfm_handler = 0x40000a7c; -lld_per_adv_end_ind_handler = 0x40000a80; -lld_per_adv_rep_ind_handler = 0x40000a84; -lld_per_adv_rx_end_ind_handler = 0x40000a88; -lld_phy_coded_500k_get = 0x40000a8c; -lld_phy_upd_cfm_handler = 0x40000a90; -lld_scan_end_ind_handler = 0x40000a94; -lld_scan_req_ind_handler = 0x40000a98; -lld_sync_start_req_handler = 0x40000a9c; -lld_test_end_ind_handler = 0x40000aa0; -lld_update_rxbuf_handler = 0x40000aa4; -llm_ch_map_update_ind_handler = 0x40000aa8; -llm_hci_command_handler_wrapper = 0x40000aac; -llm_scan_period_to_handler = 0x40000ab0; -r_Add2SelfBigHex256 = 0x40000ab4; -r_AddBigHex256 = 0x40000ab8; -r_AddBigHexModP256 = 0x40000abc; -r_AddP256 = 0x40000ac0; -r_AddPdiv2_256 = 0x40000ac4; -r_GF_Jacobian_Point_Addition256 = 0x40000ac8; -r_GF_Jacobian_Point_Double256 = 0x40000acc; -r_GF_Point_Jacobian_To_Affine256 = 0x40000ad0; -r_MultiplyBigHexByUint32_256 = 0x40000ad4; -r_MultiplyBigHexModP256 = 0x40000ad8; -r_MultiplyByU16ModP256 = 0x40000adc; -r_SubtractBigHex256 = 0x40000ae0; -r_SubtractBigHexMod256 = 0x40000ae4; -r_SubtractBigHexUint32_256 = 0x40000ae8; -r_SubtractFromSelfBigHex256 = 0x40000aec; -r_SubtractFromSelfBigHexSign256 = 0x40000af0; -r_aes_alloc = 0x40000af4; -r_aes_ccm_continue = 0x40000af8; -r_aes_ccm_process_e = 0x40000afc; -r_aes_ccm_xor_128_lsb = 0x40000b00; -r_aes_ccm_xor_128_msb = 0x40000b04; -r_aes_cmac_continue = 0x40000b08; -r_aes_cmac_start = 0x40000b0c; -r_aes_k1_continue = 0x40000b10; -r_aes_k2_continue = 0x40000b14; -r_aes_k3_continue = 0x40000b18; -r_aes_k4_continue = 0x40000b1c; -r_aes_shift_left_128 = 0x40000b20; -r_aes_start = 0x40000b24; -r_aes_xor_128 = 0x40000b28; -r_assert_err = 0x40000b2c; -r_assert_param = 0x40000b30; -r_assert_warn = 0x40000b34; -r_bigHexInversion256 = 0x40000b38; -r_ble_sw_cca_check_isr = 0x40000b3c; -r_ble_util_buf_acl_tx_alloc = 0x40000b40; -r_ble_util_buf_acl_tx_elt_get = 0x40000b44; -r_ble_util_buf_acl_tx_free = 0x40000b48; -r_ble_util_buf_acl_tx_free_in_isr = 0x40000b4c; -r_ble_util_buf_adv_tx_alloc = 0x40000b50; -r_ble_util_buf_adv_tx_free = 0x40000b54; -r_ble_util_buf_adv_tx_free_in_isr = 0x40000b58; -r_ble_util_buf_env_deinit = 0x40000b5c; -r_ble_util_buf_env_init = 0x40000b60; -r_ble_util_buf_get_rx_buf_nb = 0x40000b64; -r_ble_util_buf_get_rx_buf_size = 0x40000b68; -r_ble_util_buf_llcp_tx_alloc = 0x40000b6c; -r_ble_util_buf_llcp_tx_free = 0x40000b70; -r_ble_util_buf_rx_alloc = 0x40000b74; -r_ble_util_buf_rx_alloc_in_isr = 0x40000b78; -r_ble_util_buf_rx_free = 0x40000b7c; -r_ble_util_buf_rx_free_in_isr = 0x40000b80; -r_ble_util_buf_set_rx_buf_nb = 0x40000b84; -r_ble_util_buf_set_rx_buf_size = 0x40000b88; -r_ble_util_data_rx_buf_reset = 0x40000b8c; -r_bt_bb_get_intr_mask = 0x40000b90; -r_bt_bb_intr_clear = 0x40000b94; -r_bt_bb_intr_mask_set = 0x40000b98; -r_bt_bb_isr = 0x40000b9c; -r_bt_rf_coex_cfg_set = 0x40000ba0; -r_bt_rf_coex_conn_dynamic_pti_en_get = 0x40000ba4; -r_bt_rf_coex_conn_phy_coded_data_time_limit_en_get = 0x40000ba8; -r_bt_rf_coex_ext_adv_dynamic_pti_en_get = 0x40000bac; -r_bt_rf_coex_ext_scan_dynamic_pti_en_get = 0x40000bb0; -r_bt_rf_coex_legacy_adv_dynamic_pti_en_get = 0x40000bb4; -r_bt_rf_coex_per_adv_dynamic_pti_en_get = 0x40000bb8; -r_bt_rf_coex_pti_table_get = 0x40000bbc; -r_bt_rf_coex_st_param_get = 0x40000bc0; -r_bt_rf_coex_st_param_set = 0x40000bc4; -r_bt_rf_coex_sync_scan_dynamic_pti_en_get = 0x40000bc8; -r_bt_rma_apply_rule_cs_fmt = 0x40000bcc; -r_bt_rma_apply_rule_cs_idx = 0x40000bd0; -r_bt_rma_configure = 0x40000bd4; -r_bt_rma_deregister_rule_cs_fmt = 0x40000bd8; -r_bt_rma_deregister_rule_cs_idx = 0x40000bdc; -r_bt_rma_get_ant_by_act = 0x40000be0; -r_bt_rma_init = 0x40000be4; -r_bt_rma_register_rule_cs_fmt = 0x40000be8; -r_bt_rma_register_rule_cs_idx = 0x40000bec; -r_bt_rtp_apply_rule_cs_fmt = 0x40000bf0; -r_bt_rtp_apply_rule_cs_idx = 0x40000bf4; -r_bt_rtp_deregister_rule_cs_fmt = 0x40000bf8; -r_bt_rtp_deregister_rule_cs_idx = 0x40000bfc; -r_bt_rtp_get_txpwr_idx_by_act = 0x40000c00; -r_bt_rtp_init = 0x40000c04; -r_bt_rtp_register_rule_cs_fmt = 0x40000c08; -r_bt_rtp_register_rule_cs_idx = 0x40000c0c; -r_btdm_isr = 0x40000c10; -r_btdm_task_post = 0x40000c14; -r_btdm_task_post_from_isr = 0x40000c18; -r_btdm_task_recycle = 0x40000c1c; -r_cali_phase_match_p = 0x40000c20; -r_cmp_abs_time = 0x40000c24; -r_cmp_dest_id = 0x40000c28; -r_cmp_timer_id = 0x40000c2c; -r_co_bdaddr_compare = 0x40000c30; -r_co_ble_pkt_dur_in_us = 0x40000c34; -r_co_list_extract = 0x40000c38; -r_co_list_extract_after = 0x40000c3c; -r_co_list_extract_sublist = 0x40000c40; -r_co_list_find = 0x40000c44; -r_co_list_init = 0x40000c48; -r_co_list_insert_after = 0x40000c4c; -r_co_list_insert_before = 0x40000c50; -r_co_list_merge = 0x40000c54; -r_co_list_pool_init = 0x40000c58; -r_co_list_pop_front = 0x40000c5c; -r_co_list_push_back = 0x40000c60; -r_co_list_push_back_sublist = 0x40000c64; -r_co_list_push_front = 0x40000c68; -r_co_list_size = 0x40000c6c; -r_co_nb_good_le_channels = 0x40000c70; -r_co_util_pack = 0x40000c74; -r_co_util_read_array_size = 0x40000c78; -r_co_util_unpack = 0x40000c7c; -r_dbg_env_deinit = 0x40000c80; -r_dbg_env_init = 0x40000c84; -r_dbg_platform_reset_complete = 0x40000c88; -r_dl_upd_proc_start = 0x40000c8c; -r_dump_data = 0x40000c90; -r_ecc_abort_key256_generation = 0x40000c94; -r_ecc_gen_new_public_key = 0x40000c98; -r_ecc_gen_new_secret_key = 0x40000c9c; -r_ecc_generate_key256 = 0x40000ca0; -r_ecc_get_debug_Keys = 0x40000ca4; -r_ecc_init = 0x40000ca8; -r_ecc_is_valid_point = 0x40000cac; -r_ecc_multiplication_event_handler = 0x40000cb0; -r_ecc_point_multiplication_win_256 = 0x40000cb4; -r_emi_alloc_em_mapping_by_offset = 0x40000cb8; -r_emi_base_reg_lut_show = 0x40000cbc; -r_emi_em_base_reg_show = 0x40000cc0; -r_emi_free_em_mapping_by_offset = 0x40000cc4; -r_emi_get_em_mapping_idx_by_offset = 0x40000cc8; -r_emi_get_mem_addr_by_offset = 0x40000ccc; -r_emi_overwrite_em_mapping_by_offset = 0x40000cd0; -r_esp_vendor_hci_command_handler = 0x40000cd4; -r_get_stack_usage = 0x40000cd8; -r_h4tl_acl_hdr_rx_evt_handler = 0x40000cdc; -r_h4tl_cmd_hdr_rx_evt_handler = 0x40000ce0; -r_h4tl_cmd_pld_rx_evt_handler = 0x40000ce4; -r_h4tl_eif_io_event_post = 0x40000ce8; -r_h4tl_eif_register = 0x40000cec; -r_h4tl_init = 0x40000cf0; -r_h4tl_out_of_sync = 0x40000cf4; -r_h4tl_out_of_sync_check = 0x40000cf8; -r_h4tl_read_hdr = 0x40000cfc; -r_h4tl_read_next_out_of_sync = 0x40000d00; -r_h4tl_read_payl = 0x40000d04; -r_h4tl_read_start = 0x40000d08; -r_h4tl_rx_acl_hdr_extract = 0x40000d0c; -r_h4tl_rx_cmd_hdr_extract = 0x40000d10; -r_h4tl_rx_done = 0x40000d14; -r_h4tl_start = 0x40000d18; -r_h4tl_stop = 0x40000d1c; -r_h4tl_tx_done = 0x40000d20; -r_h4tl_tx_evt_handler = 0x40000d24; -r_h4tl_write = 0x40000d28; -r_hci_acl_tx_data_alloc = 0x40000d2c; -r_hci_acl_tx_data_received = 0x40000d30; -r_hci_basic_cmd_send_2_controller = 0x40000d34; -r_hci_ble_adv_report_filter_check = 0x40000d38; -r_hci_ble_adv_report_tx_check = 0x40000d3c; -r_hci_ble_conhdl_register = 0x40000d40; -r_hci_ble_conhdl_unregister = 0x40000d44; -r_hci_build_acl_data = 0x40000d48; -r_hci_build_cc_evt = 0x40000d4c; -r_hci_build_cs_evt = 0x40000d50; -r_hci_build_evt = 0x40000d54; -r_hci_build_le_evt = 0x40000d58; -r_hci_cmd_get_max_param_size = 0x40000d5c; -r_hci_cmd_received = 0x40000d60; -r_hci_cmd_reject = 0x40000d64; -r_hci_evt_mask_check = 0x40000d68; -r_hci_evt_mask_set = 0x40000d6c; -r_hci_fc_acl_buf_size_set = 0x40000d70; -r_hci_fc_acl_en = 0x40000d74; -r_hci_fc_acl_packet_sent = 0x40000d78; -r_hci_fc_check_host_available_nb_acl_packets = 0x40000d7c; -r_hci_fc_host_nb_acl_pkts_complete = 0x40000d80; -r_hci_fc_init = 0x40000d84; -r_hci_look_for_cmd_desc = 0x40000d88; -r_hci_look_for_evt_desc = 0x40000d8c; -r_hci_look_for_le_evt_desc = 0x40000d90; -r_hci_look_for_le_evt_desc_esp = 0x40000d94; -r_hci_pack_bytes = 0x40000d98; -r_hci_register_vendor_desc_tab = 0x40000d9c; -r_hci_send_2_controller = 0x40000da0; -r_hci_send_2_host = 0x40000da4; -r_hci_tl_c2h_data_flow_on = 0x40000da8; -r_hci_tl_cmd_hdr_rx_evt_handler = 0x40000dac; -r_hci_tl_cmd_pld_rx_evt_handler = 0x40000db0; -r_hci_tl_get_pkt = 0x40000db4; -r_hci_tl_hci_pkt_handler = 0x40000db8; -r_hci_tl_hci_tx_done_evt_handler = 0x40000dbc; -r_hci_tl_inc_nb_h2c_cmd_pkts = 0x40000dc0; -r_hci_tl_save_pkt = 0x40000dc4; -r_hci_tl_send = 0x40000dc8; -r_hci_tx_done = 0x40000dcc; -r_hci_tx_start = 0x40000dd0; -r_hci_tx_trigger = 0x40000dd4; -r_isValidSecretKey_256 = 0x40000dd8; -r_ke_check_malloc = 0x40000ddc; -r_ke_event_callback_set = 0x40000de0; -r_ke_event_clear = 0x40000de4; -r_ke_event_flush = 0x40000de8; -r_ke_event_get = 0x40000dec; -r_ke_event_get_all = 0x40000df0; -r_ke_event_init = 0x40000df4; -r_ke_event_schedule = 0x40000df8; -r_ke_event_set = 0x40000dfc; -r_ke_flush = 0x40000e00; -r_ke_free = 0x40000e04; -r_ke_handler_search = 0x40000e08; -r_ke_init = 0x40000e0c; -r_ke_is_free = 0x40000e10; -r_ke_malloc = 0x40000e14; -r_ke_mem_init = 0x40000e18; -r_ke_mem_is_empty = 0x40000e1c; -r_ke_mem_is_in_heap = 0x40000e20; -r_ke_msg_alloc = 0x40000e24; -r_ke_msg_dest_id_get = 0x40000e28; -r_ke_msg_discard = 0x40000e2c; -r_ke_msg_forward = 0x40000e30; -r_ke_msg_forward_new_id = 0x40000e34; -r_ke_msg_free = 0x40000e38; -r_ke_msg_in_queue = 0x40000e3c; -r_ke_msg_save = 0x40000e40; -r_ke_msg_send = 0x40000e44; -r_ke_msg_send_basic = 0x40000e48; -r_ke_msg_src_id_get = 0x40000e4c; -r_ke_queue_extract = 0x40000e50; -r_ke_queue_insert = 0x40000e54; -r_ke_sleep_check = 0x40000e58; -r_ke_state_get = 0x40000e5c; -r_ke_state_set = 0x40000e60; -r_ke_task_check = 0x40000e64; -r_ke_task_create = 0x40000e68; -r_ke_task_delete = 0x40000e6c; -r_ke_task_handler_get = 0x40000e70; -r_ke_task_init = 0x40000e74; -r_ke_task_msg_flush = 0x40000e78; -r_ke_task_saved_update = 0x40000e7c; -r_ke_task_schedule = 0x40000e80; -r_ke_time = 0x40000e84; -r_ke_time_cmp = 0x40000e88; -r_ke_time_past = 0x40000e8c; -r_ke_timer_active = 0x40000e90; -r_ke_timer_adjust_all = 0x40000e94; -r_ke_timer_clear = 0x40000e98; -r_ke_timer_init = 0x40000e9c; -r_ke_timer_schedule = 0x40000ea0; -r_ke_timer_set = 0x40000ea4; -r_led_init = 0x40000ea8; -r_led_set_all = 0x40000eac; -r_llc_aes_res_cb = 0x40000eb0; -r_llc_ch_map_up_proc_err_cb = 0x40000eb4; -r_llc_cleanup = 0x40000eb8; -r_llc_cmd_cmp_send = 0x40000ebc; -r_llc_cmd_stat_send = 0x40000ec0; -r_llc_con_move_cbk = 0x40000ec4; -r_llc_con_plan_set_update = 0x40000ec8; -r_llc_con_upd_param_in_range = 0x40000ecc; -r_llc_disconnect = 0x40000ed0; -r_llc_disconnect_end = 0x40000ed4; -r_llc_disconnect_proc_continue = 0x40000ed8; -r_llc_disconnect_proc_err_cb = 0x40000edc; -r_llc_dl_chg_check = 0x40000ee0; -r_llc_dle_proc_err_cb = 0x40000ee4; -r_llc_feats_exch_proc_err_cb = 0x40000ee8; -r_llc_hci_cmd_handler_tab_p_get = 0x40000eec; -r_llc_hci_command_handler = 0x40000ef0; -r_llc_hci_con_param_req_evt_send = 0x40000ef4; -r_llc_hci_con_upd_info_send = 0x40000ef8; -r_llc_hci_disconnected_dis = 0x40000efc; -r_llc_hci_dl_upd_info_send = 0x40000f00; -r_llc_hci_enc_evt_send = 0x40000f04; -r_llc_hci_feats_info_send = 0x40000f08; -r_llc_hci_le_phy_upd_cmp_evt_send = 0x40000f0c; -r_llc_hci_ltk_request_evt_send = 0x40000f10; -r_llc_hci_nb_cmp_pkts_evt_send = 0x40000f14; -r_llc_hci_version_info_send = 0x40000f18; -r_llc_init_term_proc = 0x40000f1c; -r_llc_iv_skd_rand_gen = 0x40000f20; -r_llc_le_ping_proc_continue = 0x40000f24; -r_llc_le_ping_proc_err_cb = 0x40000f28; -r_llc_le_ping_restart = 0x40000f2c; -r_llc_le_ping_set = 0x40000f30; -r_llc_ll_pause_enc_rsp_ack_handler = 0x40000f34; -r_llc_ll_reject_ind_ack_handler = 0x40000f38; -r_llc_ll_reject_ind_pdu_send = 0x40000f3c; -r_llc_ll_start_enc_rsp_ack_handler = 0x40000f40; -r_llc_ll_terminate_ind_ack = 0x40000f44; -r_llc_ll_unknown_ind_handler = 0x40000f48; -r_llc_llcp_send = 0x40000f4c; -r_llc_llcp_state_set = 0x40000f50; -r_llc_llcp_trans_timer_set = 0x40000f54; -r_llc_llcp_tx_check = 0x40000f58; -r_llc_loc_ch_map_proc_continue = 0x40000f5c; -r_llc_loc_con_upd_proc_continue = 0x40000f60; -r_llc_loc_con_upd_proc_err_cb = 0x40000f64; -r_llc_loc_dl_upd_proc_continue = 0x40000f68; -r_llc_loc_encrypt_proc_continue = 0x40000f6c; -r_llc_loc_encrypt_proc_err_cb = 0x40000f70; -r_llc_loc_feats_exch_proc_continue = 0x40000f74; -r_llc_loc_phy_upd_proc_continue = 0x40000f78; -r_llc_loc_phy_upd_proc_err_cb = 0x40000f7c; -r_llc_msg_handler_tab_p_get = 0x40000f80; -r_llc_pref_param_compute = 0x40000f84; -r_llc_proc_collision_check = 0x40000f88; -r_llc_proc_err_ind = 0x40000f8c; -r_llc_proc_get = 0x40000f90; -r_llc_proc_id_get = 0x40000f94; -r_llc_proc_reg = 0x40000f98; -r_llc_proc_state_get = 0x40000f9c; -r_llc_proc_state_set = 0x40000fa0; -r_llc_proc_timer_pause_set = 0x40000fa4; -r_llc_proc_timer_set = 0x40000fa8; -r_llc_proc_unreg = 0x40000fac; -r_llc_rem_ch_map_proc_continue = 0x40000fb0; -r_llc_rem_con_upd_proc_continue = 0x40000fb4; -r_llc_rem_con_upd_proc_err_cb = 0x40000fb8; -r_llc_rem_dl_upd_proc = 0x40000fbc; -r_llc_rem_encrypt_proc_continue = 0x40000fc0; -r_llc_rem_encrypt_proc_err_cb = 0x40000fc4; -r_llc_rem_phy_upd_proc_continue = 0x40000fc8; -r_llc_rem_phy_upd_proc_err_cb = 0x40000fcc; -r_llc_role_get = 0x40000fd0; -r_llc_sk_gen = 0x40000fd4; -r_llc_start = 0x40000fd8; -r_llc_stop = 0x40000fdc; -r_llc_ver_exch_loc_proc_continue = 0x40000fe0; -r_llc_ver_proc_err_cb = 0x40000fe4; -r_llcp_pdu_handler_tab_p_get = 0x40000fe8; -r_lld_aa_gen = 0x40000fec; -r_lld_adv_adv_data_set = 0x40000ff0; -r_lld_adv_adv_data_update = 0x40000ff4; -r_lld_adv_aux_ch_idx_set = 0x40000ff8; -r_lld_adv_aux_evt_canceled_cbk = 0x40000ffc; -r_lld_adv_aux_evt_start_cbk = 0x40001000; -r_lld_adv_coex_check_ext_adv_synced = 0x40001004; -r_lld_adv_coex_env_reset = 0x40001008; -r_lld_adv_duration_update = 0x4000100c; -r_lld_adv_dynamic_pti_process = 0x40001010; -r_lld_adv_end = 0x40001014; -r_lld_adv_evt_canceled_cbk = 0x40001018; -r_lld_adv_evt_start_cbk = 0x4000101c; -r_lld_adv_ext_chain_construct = 0x40001020; -r_lld_adv_ext_pkt_prepare = 0x40001024; -r_lld_adv_frm_cbk = 0x40001028; -r_lld_adv_frm_isr = 0x4000102c; -r_lld_adv_frm_skip_isr = 0x40001030; -r_lld_adv_init = 0x40001034; -r_lld_adv_pkt_rx = 0x40001038; -r_lld_adv_pkt_rx_connect_ind = 0x4000103c; -r_lld_adv_pkt_rx_send_scan_req_evt = 0x40001040; -r_lld_adv_rand_addr_update = 0x40001044; -r_lld_adv_restart = 0x40001048; -r_lld_adv_scan_rsp_data_set = 0x4000104c; -r_lld_adv_scan_rsp_data_update = 0x40001050; -r_lld_adv_set_tx_power = 0x40001054; -r_lld_adv_start = 0x40001058; -r_lld_adv_stop = 0x4000105c; -r_lld_adv_sync_info_set = 0x40001060; -r_lld_adv_sync_info_update = 0x40001064; -r_lld_calc_aux_rx = 0x40001068; -r_lld_cca_alloc = 0x4000106c; -r_lld_cca_data_reset = 0x40001070; -r_lld_cca_free = 0x40001074; -r_lld_ch_assess_data_get = 0x40001078; -r_lld_ch_idx_get = 0x4000107c; -r_lld_ch_map_set = 0x40001080; -r_lld_channel_assess = 0x40001084; -r_lld_con_activity_act_offset_compute = 0x40001088; -r_lld_con_activity_offset_compute = 0x4000108c; -r_lld_con_ch_map_update = 0x40001090; -r_lld_con_cleanup = 0x40001094; -r_lld_con_current_tx_power_get = 0x40001098; -r_lld_con_data_flow_set = 0x4000109c; -r_lld_con_data_len_update = 0x400010a0; -r_lld_con_data_tx = 0x400010a4; -r_lld_con_enc_key_load = 0x400010a8; -r_lld_con_event_counter_get = 0x400010ac; -r_lld_con_evt_canceled_cbk = 0x400010b0; -r_lld_con_evt_duration_min_get = 0x400010b4; -r_lld_con_evt_max_eff_time_cal = 0x400010b8; -r_lld_con_evt_sd_evt_time_get = 0x400010bc; -r_lld_con_evt_start_cbk = 0x400010c0; -r_lld_con_evt_time_update = 0x400010c4; -r_lld_con_free_all_tx_buf = 0x400010c8; -r_lld_con_frm_cbk = 0x400010cc; -r_lld_con_frm_isr = 0x400010d0; -r_lld_con_frm_skip_isr = 0x400010d4; -r_lld_con_init = 0x400010d8; -r_lld_con_llcp_tx = 0x400010dc; -r_lld_con_max_lat_calc = 0x400010e0; -r_lld_con_offset_get = 0x400010e4; -r_lld_con_param_update = 0x400010e8; -r_lld_con_phys_update = 0x400010ec; -r_lld_con_pref_slave_evt_dur_set = 0x400010f0; -r_lld_con_pref_slave_latency_set = 0x400010f4; -r_lld_con_rssi_get = 0x400010f8; -r_lld_con_rx = 0x400010fc; -r_lld_con_rx_channel_assess = 0x40001100; -r_lld_con_rx_enc = 0x40001104; -r_lld_con_rx_isr = 0x40001108; -r_lld_con_rx_link_info_check = 0x4000110c; -r_lld_con_rx_llcp_check = 0x40001110; -r_lld_con_rx_sync_time_update = 0x40001114; -r_lld_con_sched = 0x40001118; -r_lld_con_set_tx_power = 0x4000111c; -r_lld_con_start = 0x40001120; -r_lld_con_stop = 0x40001124; -r_lld_con_tx = 0x40001128; -r_lld_con_tx_enc = 0x4000112c; -r_lld_con_tx_isr = 0x40001130; -r_lld_con_tx_len_update = 0x40001134; -r_lld_con_tx_len_update_for_intv = 0x40001138; -r_lld_con_tx_len_update_for_rate = 0x4000113c; -r_lld_con_tx_prog = 0x40001140; -r_lld_conn_dynamic_pti_process = 0x40001144; -r_lld_continue_scan_rx_isr_end_process = 0x40001148; -r_lld_ext_scan_dynamic_pti_process = 0x4000114c; -r_lld_hw_cca_end_isr = 0x40001150; -r_lld_hw_cca_evt_handler = 0x40001154; -r_lld_hw_cca_isr = 0x40001158; -r_lld_init_cal_anchor_point = 0x4000115c; -r_lld_init_compute_winoffset = 0x40001160; -r_lld_init_connect_req_pack = 0x40001164; -r_lld_init_end = 0x40001168; -r_lld_init_evt_canceled_cbk = 0x4000116c; -r_lld_init_evt_start_cbk = 0x40001170; -r_lld_init_frm_cbk = 0x40001174; -r_lld_init_frm_eof_isr = 0x40001178; -r_lld_init_frm_skip_isr = 0x4000117c; -r_lld_init_init = 0x40001180; -r_lld_init_process_pkt_rx = 0x40001184; -r_lld_init_process_pkt_rx_adv_ext_ind = 0x40001188; -r_lld_init_process_pkt_rx_adv_ind_or_direct_ind = 0x4000118c; -r_lld_init_process_pkt_rx_aux_connect_rsp = 0x40001190; -r_lld_init_process_pkt_tx = 0x40001194; -r_lld_init_process_pkt_tx_cal_con_timestamp = 0x40001198; -r_lld_init_sched = 0x4000119c; -r_lld_init_set_tx_power = 0x400011a0; -r_lld_init_start = 0x400011a4; -r_lld_init_stop = 0x400011a8; -r_lld_instant_proc_end = 0x400011ac; -r_lld_llcp_rx_ind_handler = 0x400011b0; -r_lld_per_adv_ch_map_update = 0x400011b4; -r_lld_per_adv_chain_construct = 0x400011b8; -r_lld_per_adv_cleanup = 0x400011bc; -r_lld_per_adv_coex_env_reset = 0x400011c0; -r_lld_per_adv_data_set = 0x400011c4; -r_lld_per_adv_data_update = 0x400011c8; -r_lld_per_adv_dynamic_pti_process = 0x400011cc; -r_lld_per_adv_evt_canceled_cbk = 0x400011d0; -r_lld_per_adv_evt_start_cbk = 0x400011d4; -r_lld_per_adv_ext_pkt_prepare = 0x400011d8; -r_lld_per_adv_frm_cbk = 0x400011dc; -r_lld_per_adv_frm_isr = 0x400011e0; -r_lld_per_adv_frm_skip_isr = 0x400011e4; -r_lld_per_adv_init = 0x400011e8; -r_lld_per_adv_init_info_get = 0x400011ec; -r_lld_per_adv_list_add = 0x400011f0; -r_lld_per_adv_list_rem = 0x400011f4; -r_lld_per_adv_sched = 0x400011f8; -r_lld_per_adv_set_tx_power = 0x400011fc; -r_lld_per_adv_start = 0x40001200; -r_lld_per_adv_stop = 0x40001204; -r_lld_per_adv_sync_info_get = 0x40001208; -r_lld_process_cca_data = 0x4000120c; -r_lld_ral_search = 0x40001210; -r_lld_read_clock = 0x40001214; -r_lld_res_list_add = 0x40001218; -r_lld_res_list_clear = 0x4000121c; -r_lld_res_list_is_empty = 0x40001220; -r_lld_res_list_local_rpa_get = 0x40001224; -r_lld_res_list_peer_rpa_get = 0x40001228; -r_lld_res_list_peer_update = 0x4000122c; -r_lld_res_list_priv_mode_update = 0x40001230; -r_lld_res_list_rem = 0x40001234; -r_lld_reset_reg = 0x40001238; -r_lld_rpa_renew = 0x4000123c; -r_lld_rpa_renew_evt_canceled_cbk = 0x40001240; -r_lld_rpa_renew_evt_start_cbk = 0x40001244; -r_lld_rpa_renew_instant_cbk = 0x40001248; -r_lld_rxdesc_check = 0x4000124c; -r_lld_rxdesc_free = 0x40001250; -r_lld_scan_create_sync = 0x40001254; -r_lld_scan_create_sync_cancel = 0x40001258; -r_lld_scan_end = 0x4000125c; -r_lld_scan_evt_canceled_cbk = 0x40001260; -r_lld_scan_evt_start_cbk = 0x40001264; -r_lld_scan_frm_cbk = 0x40001268; -r_lld_scan_frm_eof_isr = 0x4000126c; -r_lld_scan_frm_rx_isr = 0x40001270; -r_lld_scan_frm_skip_isr = 0x40001274; -r_lld_scan_init = 0x40001278; -r_lld_scan_params_update = 0x4000127c; -r_lld_scan_process_pkt_rx = 0x40001280; -r_lld_scan_process_pkt_rx_adv_rep = 0x40001284; -r_lld_scan_process_pkt_rx_aux_adv_ind = 0x40001288; -r_lld_scan_process_pkt_rx_aux_chain_ind = 0x4000128c; -r_lld_scan_process_pkt_rx_aux_scan_rsp = 0x40001290; -r_lld_scan_process_pkt_rx_ext_adv = 0x40001294; -r_lld_scan_process_pkt_rx_ext_adv_ind = 0x40001298; -r_lld_scan_process_pkt_rx_legacy_adv = 0x4000129c; -r_lld_scan_restart = 0x400012a0; -r_lld_scan_sched = 0x400012a4; -r_lld_scan_set_tx_power = 0x400012a8; -r_lld_scan_start = 0x400012ac; -r_lld_scan_stop = 0x400012b0; -r_lld_scan_sync_accept = 0x400012b4; -r_lld_scan_sync_info_unpack = 0x400012b8; -r_lld_scan_trunc_ind = 0x400012bc; -r_lld_sw_cca_evt_handler = 0x400012c0; -r_lld_sw_cca_isr = 0x400012c4; -r_lld_sync_ch_map_update = 0x400012c8; -r_lld_sync_cleanup = 0x400012cc; -r_lld_sync_evt_canceled_cbk = 0x400012d0; -r_lld_sync_evt_start_cbk = 0x400012d4; -r_lld_sync_frm_cbk = 0x400012d8; -r_lld_sync_frm_eof_isr = 0x400012dc; -r_lld_sync_frm_rx_isr = 0x400012e0; -r_lld_sync_frm_skip_isr = 0x400012e4; -r_lld_sync_init = 0x400012e8; -r_lld_sync_process_pkt_rx = 0x400012ec; -r_lld_sync_process_pkt_rx_aux_sync_ind = 0x400012f0; -r_lld_sync_process_pkt_rx_pkt_check = 0x400012f4; -r_lld_sync_scan_dynamic_pti_process = 0x400012f8; -r_lld_sync_sched = 0x400012fc; -r_lld_sync_start = 0x40001300; -r_lld_sync_stop = 0x40001304; -r_lld_sync_trunc_ind = 0x40001308; -r_lld_test_cleanup = 0x4000130c; -r_lld_test_evt_canceled_cbk = 0x40001310; -r_lld_test_evt_start_cbk = 0x40001314; -r_lld_test_freq2chnl = 0x40001318; -r_lld_test_frm_cbk = 0x4000131c; -r_lld_test_frm_isr = 0x40001320; -r_lld_test_init = 0x40001324; -r_lld_test_rx_isr = 0x40001328; -r_lld_test_set_tx_power = 0x4000132c; -r_lld_test_start = 0x40001330; -r_lld_test_stop = 0x40001334; -r_lld_update_rxbuf = 0x40001338; -r_lld_update_rxbuf_isr = 0x4000133c; -r_lld_white_list_add = 0x40001340; -r_lld_white_list_rem = 0x40001344; -r_llm_activity_free_get = 0x40001348; -r_llm_activity_free_set = 0x4000134c; -r_llm_activity_syncing_get = 0x40001350; -r_llm_adv_con_len_check = 0x40001354; -r_llm_adv_hdl_to_id = 0x40001358; -r_llm_adv_rep_flow_control_check = 0x4000135c; -r_llm_adv_rep_flow_control_update = 0x40001360; -r_llm_adv_reports_list_check = 0x40001364; -r_llm_adv_set_all_release = 0x40001368; -r_llm_adv_set_dft_params = 0x4000136c; -r_llm_adv_set_release = 0x40001370; -r_llm_aes_res_cb = 0x40001374; -r_llm_ble_update_adv_flow_control = 0x40001378; -r_llm_ch_map_update = 0x4000137c; -r_llm_cmd_cmp_send = 0x40001380; -r_llm_cmd_stat_send = 0x40001384; -r_llm_dev_list_empty_entry = 0x40001388; -r_llm_dev_list_search = 0x4000138c; -r_llm_env_adv_dup_filt_deinit = 0x40001390; -r_llm_env_adv_dup_filt_init = 0x40001394; -r_llm_init_ble_adv_report_flow_contol = 0x40001398; -r_llm_is_dev_connected = 0x4000139c; -r_llm_is_dev_synced = 0x400013a0; -r_llm_is_non_con_act_ongoing_check = 0x400013a4; -r_llm_is_wl_accessible = 0x400013a8; -r_llm_le_evt_mask_check = 0x400013ac; -r_llm_le_features_get = 0x400013b0; -r_llm_link_disc = 0x400013b4; -r_llm_master_ch_map_get = 0x400013b8; -r_llm_msg_handler_tab_p_get = 0x400013bc; -r_llm_no_activity = 0x400013c0; -r_llm_per_adv_slot_dur = 0x400013c4; -r_llm_plan_elt_get = 0x400013c8; -r_llm_rx_path_comp_get = 0x400013cc; -r_llm_scan_start = 0x400013d0; -r_llm_scan_sync_acad_attach = 0x400013d4; -r_llm_scan_sync_acad_detach = 0x400013d8; -r_llm_send_adv_lost_event_to_host = 0x400013dc; -r_llm_tx_path_comp_get = 0x400013e0; -r_misc_deinit = 0x400013e4; -r_misc_free_em_buf_in_isr = 0x400013e8; -r_misc_init = 0x400013ec; -r_misc_msg_handler_tab_p_get = 0x400013f0; -r_notEqual256 = 0x400013f4; -r_phy_upd_proc_start = 0x400013f8; -r_platform_reset = 0x400013fc; -r_register_esp_vendor_cmd_handler = 0x40001400; -r_rf_em_init = 0x40001404; -r_rf_force_agc_enable = 0x40001408; -r_rf_reg_rd = 0x4000140c; -r_rf_reg_wr = 0x40001410; -r_rf_reset = 0x40001414; -r_rf_rssi_convert = 0x40001418; -r_rf_rw_v9_le_disable = 0x4000141c; -r_rf_rw_v9_le_enable = 0x40001420; -r_rf_sleep = 0x40001424; -r_rf_txpwr_cs_get = 0x40001428; -r_rf_txpwr_dbm_get = 0x4000142c; -r_rf_util_cs_fmt_convert = 0x40001430; -r_rw_crypto_aes_ccm = 0x40001434; -r_rw_crypto_aes_encrypt = 0x40001438; -r_rw_crypto_aes_init = 0x4000143c; -r_rw_crypto_aes_k1 = 0x40001440; -r_rw_crypto_aes_k2 = 0x40001444; -r_rw_crypto_aes_k3 = 0x40001448; -r_rw_crypto_aes_k4 = 0x4000144c; -r_rw_crypto_aes_rand = 0x40001450; -r_rw_crypto_aes_result_handler = 0x40001454; -r_rw_crypto_aes_s1 = 0x40001458; -r_rw_cryto_aes_cmac = 0x4000145c; -r_rw_v9_init_em_radio_table = 0x40001460; -r_rwble_isr = 0x40001464; -r_rwble_sleep_enter = 0x40001468; -r_rwble_sleep_wakeup_end = 0x4000146c; -r_rwbtdm_isr_wrapper = 0x40001470; -r_rwip_active_check = 0x40001474; -r_rwip_aes_encrypt = 0x40001478; -r_rwip_assert = 0x4000147c; -r_rwip_crypt_evt_handler = 0x40001480; -r_rwip_crypt_isr_handler = 0x40001484; -r_rwip_eif_get = 0x40001488; -r_rwip_half_slot_2_lpcycles = 0x4000148c; -r_rwip_hus_2_lpcycles = 0x40001490; -r_rwip_isr = 0x40001494; -r_rwip_lpcycles_2_hus = 0x40001498; -r_rwip_prevent_sleep_clear = 0x4000149c; -r_rwip_prevent_sleep_set = 0x400014a0; -r_rwip_schedule = 0x400014a4; -r_rwip_sleep = 0x400014a8; -r_rwip_sw_int_handler = 0x400014ac; -r_rwip_sw_int_req = 0x400014b0; -r_rwip_time_get = 0x400014b4; -r_rwip_timer_10ms_handler = 0x400014b8; -r_rwip_timer_10ms_set = 0x400014bc; -r_rwip_timer_hs_handler = 0x400014c0; -r_rwip_timer_hs_set = 0x400014c4; -r_rwip_timer_hus_handler = 0x400014c8; -r_rwip_timer_hus_set = 0x400014cc; -r_rwip_wakeup = 0x400014d0; -r_rwip_wakeup_end = 0x400014d4; -r_rwip_wlcoex_set = 0x400014d8; -r_sch_alarm_clear = 0x400014dc; -r_sch_alarm_init = 0x400014e0; -r_sch_alarm_prog = 0x400014e4; -r_sch_alarm_set = 0x400014e8; -r_sch_alarm_timer_isr = 0x400014ec; -r_sch_arb_conflict_check = 0x400014f0; -r_sch_arb_elt_cancel = 0x400014f4; -r_sch_arb_event_start_isr = 0x400014f8; -r_sch_arb_init = 0x400014fc; -r_sch_arb_insert = 0x40001500; -r_sch_arb_prog_timer = 0x40001504; -r_sch_arb_remove = 0x40001508; -r_sch_arb_sw_isr = 0x4000150c; -r_sch_plan_chk = 0x40001510; -r_sch_plan_clock_wrap_offset_update = 0x40001514; -r_sch_plan_init = 0x40001518; -r_sch_plan_interval_req = 0x4000151c; -r_sch_plan_offset_max_calc = 0x40001520; -r_sch_plan_offset_req = 0x40001524; -r_sch_plan_position_range_compute = 0x40001528; -r_sch_plan_rem = 0x4000152c; -r_sch_plan_req = 0x40001530; -r_sch_plan_set = 0x40001534; -r_sch_prog_end_isr = 0x40001538; -r_sch_prog_init = 0x4000153c; -r_sch_prog_push = 0x40001540; -r_sch_prog_rx_isr = 0x40001544; -r_sch_prog_skip_isr = 0x40001548; -r_sch_prog_tx_isr = 0x4000154c; -r_sch_slice_bg_add = 0x40001550; -r_sch_slice_bg_remove = 0x40001554; -r_sch_slice_compute = 0x40001558; -r_sch_slice_fg_add = 0x4000155c; -r_sch_slice_fg_remove = 0x40001560; -r_sch_slice_init = 0x40001564; -r_sch_slice_per_add = 0x40001568; -r_sch_slice_per_remove = 0x4000156c; -r_sdk_config_get_bt_sleep_enable = 0x40001570; -r_sdk_config_get_hl_derived_opts = 0x40001574; -r_sdk_config_get_opts = 0x40001578; -r_sdk_config_get_priv_opts = 0x4000157c; -r_sdk_config_set_bt_sleep_enable = 0x40001580; -r_sdk_config_set_hl_derived_opts = 0x40001584; -r_sdk_config_set_opts = 0x40001588; -r_specialModP256 = 0x4000158c; -r_unloaded_area_init = 0x40001590; -r_vhci_flow_off = 0x40001594; -r_vhci_flow_on = 0x40001598; -r_vhci_notify_host_send_available = 0x4000159c; -r_vhci_send_to_host = 0x400015a0; -r_vnd_hci_command_handler = 0x400015a4; -r_vshci_init = 0x400015a8; -vnd_hci_command_handler_wrapper = 0x400015ac; -/* Data (.data, .bss, .rodata) */ -bt_rf_coex_cfg_p = 0x3fcdffcc; -bt_rf_coex_hooks_p = 0x3fcdffc8; -btdm_env_p = 0x3fcdffc4; -g_rw_controller_task_handle = 0x3fcdffc0; -g_rw_init_sem = 0x3fcdffbc; -g_rw_schd_queue = 0x3fcdffb8; -lld_init_env = 0x3fcdffb4; -lld_rpa_renew_env = 0x3fcdffb0; -lld_scan_env = 0x3fcdffac; -lld_scan_sync_env = 0x3fcdffa8; -lld_test_env = 0x3fcdffa4; -p_ble_util_buf_env = 0x3fcdffa0; -p_lld_env = 0x3fcdff9c; -p_llm_env = 0x3fcdff98; -r_h4tl_eif_p = 0x3fcdff94; -r_hli_funcs_p = 0x3fcdff90; -r_ip_funcs_p = 0x3fcdff8c; -r_modules_funcs_p = 0x3fcdff88; -r_osi_funcs_p = 0x3fcdff84; -r_plf_funcs_p = 0x3fcdff80; -vhci_env_p = 0x3fcdff7c; -aa_gen = 0x3fcdff78; -aes_env = 0x3fcdff6c; -bt_rf_coex_cfg_cb = 0x3fcdff1c; -btdm_pwr_state = 0x3fcdff18; -btdm_slp_err = 0x3fcdff14; -ecc_env = 0x3fcdff0c; -esp_handler = 0x3fcdff04; -esp_vendor_cmd = 0x3fcdfefc; -g_adv_delay_dis = 0x3fcdfef8; -g_conflict_elt = 0x3fcdfef4; -g_eif_api = 0x3fcdfee4; -g_event_empty = 0x3fcdfed8; -g_llc_state = 0x3fcdfecc; -g_llm_state = 0x3fcdfec8; -g_max_evt_env = 0x3fcdfec4; -g_misc_state = 0x3fcdfec0; -g_rma_rule_db = 0x3fcdfea4; -g_rtp_rule_db = 0x3fcdfe88; -g_scan_forever = 0x3fcdfe85; -g_time_msb = 0x3fcdfe84; -h4tl_env = 0x3fcdfe5c; -hci_env = 0x3fcdfe38; -hci_ext_host = 0x3fcdfe34; -hci_fc_env = 0x3fcdfe2c; -hci_tl_env = 0x3fcdfe00; -ke_env = 0x3fcdfdd0; -ke_event_env = 0x3fcdfd90; -ke_task_env = 0x3fcdfd14; -llc_env = 0x3fcdfcec; -lld_adv_env = 0x3fcdfcc4; -lld_con_env = 0x3fcdfc9c; -lld_exp_sync_pos_tab = 0x3fcdfc94; -lld_per_adv_env = 0x3fcdfc6c; -lld_sync_env = 0x3fcdfc44; -llm_le_adv_flow_env = 0x3fcdfc38; -rw_sleep_enable = 0x3fcdfc34; -rwble_env = 0x3fcdfc2c; -rwip_env = 0x3fcdfc10; -rwip_param = 0x3fcdfc04; -rwip_prog_delay = 0x3fcdfc00; -rwip_rf = 0x3fcdfbc8; -sch_alarm_env = 0x3fcdfbc0; -sch_arb_env = 0x3fcdfbac; -sch_plan_env = 0x3fcdfba4; -sch_prog_env = 0x3fcdfaa0; -sch_slice_env = 0x3fcdfa40; -sch_slice_params = 0x3fcdfa38; -timer_env = 0x3fcdfa30; -unloaded_area = 0x3fcdfa2c; -vshci_state = 0x3fcdfa28; -TASK_DESC_LLC = 0x3fcdfa1c; -TASK_DESC_LLM = 0x3fcdfa10; -TASK_DESC_VSHCI = 0x3fcdfa04; -co_default_bdaddr = 0x3fcdf9fc; -dbg_assert_block = 0x3fcdf9f8; -g_bt_plf_log_level = 0x3fcdf9f4; -hci_cmd_desc_tab_vs_esp = 0x3fcdf9d0; -hci_command_handler_tab_esp = 0x3fcdf9b8; -privacy_en = 0x3fcdf9b4; -sdk_cfg_priv_opts = 0x3fcdf96c; -BasePoint_x_256 = 0x3ff1ffdc; -BasePoint_y_256 = 0x3ff1ffbc; -DebugE256PublicKey_x = 0x3ff1ff9c; -DebugE256PublicKey_y = 0x3ff1ff7c; -DebugE256SecretKey = 0x3ff1ff5c; -ECC_4Win_Look_up_table = 0x3ff1f7a0; -LLM_AA_CT1 = 0x3ff1f79c; -LLM_AA_CT2 = 0x3ff1f798; -RF_TX_PW_CONV_TBL = 0x3ff1f790; -TASK_DESC_MISC = 0x3ff1f784; -adv_evt_prop2type = 0x3ff1f768; -adv_evt_type2prop = 0x3ff1f760; -aes_cmac_zero = 0x3ff1f750; -aes_k2_salt = 0x3ff1f740; -aes_k3_id64 = 0x3ff1f738; -aes_k3_salt = 0x3ff1f728; -aes_k4_id6 = 0x3ff1f724; -aes_k4_salt = 0x3ff1f714; -bigHexP256 = 0x3ff1f6e8; -byte_tx_time = 0x3ff1f6e0; -co_null_bdaddr = 0x3ff1f6d8; -co_phy_mask_to_rate = 0x3ff1f6d0; -co_phy_mask_to_value = 0x3ff1f6c8; -co_phy_to_rate = 0x3ff1f6c4; -co_phy_value_to_mask = 0x3ff1f6c0; -co_rate_to_byte_dur_us = 0x3ff1f6b8; -co_rate_to_phy = 0x3ff1f6b0; -co_rate_to_phy_mask = 0x3ff1f6ac; -co_sca2ppm = 0x3ff1f69c; -coef_B = 0x3ff1f670; -connect_req_dur_tab = 0x3ff1f668; -ecc_Jacobian_InfinityPoint256 = 0x3ff1f5e4; -em_base_reg_lut = 0x3ff1f518; -fixed_tx_time = 0x3ff1f510; -h4tl_msgtype2hdrlen = 0x3ff1f508; -hci_cmd_desc_root_tab = 0x3ff1f4d8; -hci_cmd_desc_tab_ctrl_bb = 0x3ff1f46c; -hci_cmd_desc_tab_info_par = 0x3ff1f43c; -hci_cmd_desc_tab_le = 0x3ff1f0a0; -hci_cmd_desc_tab_lk_ctrl = 0x3ff1f088; -hci_cmd_desc_tab_stat_par = 0x3ff1f07c; -hci_cmd_desc_tab_vs = 0x3ff1f040; -hci_evt_desc_tab = 0x3ff1eff8; -hci_evt_le_desc_tab = 0x3ff1ef58; -hci_evt_le_desc_tab_esp = 0x3ff1ef50; -hci_rsvd_evt_msk = 0x3ff1ef48; -lld_aux_phy_to_rate = 0x3ff1ef44; -lld_init_max_aux_dur_tab = 0x3ff1ef3c; -lld_scan_map_legacy_pdu_to_evt_type = 0x3ff1ef34; -lld_scan_max_aux_dur_tab = 0x3ff1ef2c; -lld_sync_max_aux_dur_tab = 0x3ff1ef24; -llm_local_le_feats = 0x3ff1ef1c; -llm_local_le_states = 0x3ff1ef14; -llm_local_supp_cmds = 0x3ff1eeec; -maxSecretKey_256 = 0x3ff1eecc; -max_data_tx_time = 0x3ff1eec4; -one_bits = 0x3ff1eeb4; -rwip_coex_cfg = 0x3ff1eeac; -rwip_priority = 0x3ff1ee94; -veryBigHexP256 = 0x3ff1ee48; - - -/*************************************** - Group rom_pp - ***************************************/ - -/* Functions */ -esp_pp_rom_version_get = 0x400015b0; -RC_GetBlockAckTime = 0x400015b4; -ebuf_list_remove = 0x400015b8; -esf_buf_alloc = 0x400015bc; -esf_buf_alloc_dynamic = 0x400015c0; -esf_buf_recycle = 0x400015c4; -GetAccess = 0x400015c8; -hal_mac_is_low_rate_enabled = 0x400015cc; -hal_mac_tx_get_blockack = 0x400015d0; -hal_mac_tx_set_ppdu = 0x400015d4; -ic_get_trc = 0x400015d8; -ic_mac_deinit = 0x400015dc; -ic_mac_init = 0x400015e0; -ic_interface_enabled = 0x400015e4; -is_lmac_idle = 0x400015e8; -lmacAdjustTimestamp = 0x400015ec; -lmacDiscardAgedMSDU = 0x400015f0; -lmacDiscardMSDU = 0x400015f4; -lmacEndFrameExchangeSequence = 0x400015f8; -lmacIsIdle = 0x400015fc; -lmacIsLongFrame = 0x40001600; -lmacMSDUAged = 0x40001604; -lmacPostTxComplete = 0x40001608; -lmacProcessAllTxTimeout = 0x4000160c; -lmacProcessCollisions = 0x40001610; -lmacProcessRxSucData = 0x40001614; -lmacReachLongLimit = 0x40001618; -lmacReachShortLimit = 0x4000161c; -lmacRecycleMPDU = 0x40001620; -lmacRxDone = 0x40001624; -lmacSetTxFrame = 0x40001628; -lmacTxDone = 0x4000162c; -lmacTxFrame = 0x40001630; -mac_tx_set_duration = 0x40001634; -mac_tx_set_htsig = 0x40001638; -mac_tx_set_plcp0 = 0x4000163c; -mac_tx_set_plcp1 = 0x40001640; -mac_tx_set_plcp2 = 0x40001644; -pm_check_state = 0x40001648; -pm_disable_dream_timer = 0x4000164c; -pm_disable_sleep_delay_timer = 0x40001650; -pm_dream = 0x40001654; -pm_mac_wakeup = 0x40001658; -pm_mac_sleep = 0x4000165c; -pm_enable_active_timer = 0x40001660; -pm_enable_sleep_delay_timer = 0x40001664; -pm_local_tsf_process = 0x40001668; -pm_set_beacon_filter = 0x4000166c; -pm_is_in_wifi_slice_threshold = 0x40001670; -pm_is_waked = 0x40001674; -pm_keep_alive = 0x40001678; -pm_on_beacon_rx = 0x4000167c; -pm_on_data_rx = 0x40001680; -pm_on_tbtt = 0x40001684; -pm_parse_beacon = 0x40001688; -pm_process_tim = 0x4000168c; -pm_rx_beacon_process = 0x40001690; -pm_rx_data_process = 0x40001694; -pm_sleep = 0x40001698; -pm_sleep_for = 0x4000169c; -pm_tbtt_process = 0x400016a0; -ppAMPDU2Normal = 0x400016a4; -ppAssembleAMPDU = 0x400016a8; -ppCalFrameTimes = 0x400016ac; -ppCalSubFrameLength = 0x400016b0; -ppCalTxAMPDULength = 0x400016b4; -ppCheckTxAMPDUlength = 0x400016b8; -ppDequeueRxq_Locked = 0x400016bc; -ppDequeueTxQ = 0x400016c0; -ppEmptyDelimiterLength = 0x400016c4; -ppEnqueueRxq = 0x400016c8; -ppEnqueueTxDone = 0x400016cc; -ppGetTxQFirstAvail_Locked = 0x400016d0; -ppGetTxframe = 0x400016d4; -ppMapTxQueue = 0x400016d8; -ppProcTxSecFrame = 0x400016dc; -ppProcessRxPktHdr = 0x400016e0; -ppProcessTxQ = 0x400016e4; -ppRecordBarRRC = 0x400016e8; -lmacRequestTxopQueue = 0x400016ec; -lmacReleaseTxopQueue = 0x400016f0; -ppRecycleAmpdu = 0x400016f4; -ppRecycleRxPkt = 0x400016f8; -ppResortTxAMPDU = 0x400016fc; -ppResumeTxAMPDU = 0x40001700; -ppRxFragmentProc = 0x40001704; -ppRxPkt = 0x40001708; -ppRxProtoProc = 0x4000170c; -ppSearchTxQueue = 0x40001710; -ppSearchTxframe = 0x40001714; -ppSelectNextQueue = 0x40001718; -ppSubFromAMPDU = 0x4000171c; -ppTask = 0x40001720; -ppTxPkt = 0x40001724; -ppTxProtoProc = 0x40001728; -ppTxqUpdateBitmap = 0x4000172c; -pp_coex_tx_request = 0x40001730; -pp_hdrsize = 0x40001734; -pp_post = 0x40001738; -pp_process_hmac_waiting_txq = 0x4000173c; -rcGetAmpduSched = 0x40001740; -rcUpdateRxDone = 0x40001744; -rc_get_trc = 0x40001748; -rc_get_trc_by_index = 0x4000174c; -rcAmpduLowerRate = 0x40001750; -rcampduuprate = 0x40001754; -rcClearCurAMPDUSched = 0x40001758; -rcClearCurSched = 0x4000175c; -rcClearCurStat = 0x40001760; -rcGetSched = 0x40001764; -rcLowerSched = 0x40001768; -rcSetTxAmpduLimit = 0x4000176c; -rcTxUpdatePer = 0x40001770; -rcUpdateAckSnr = 0x40001774; -rcUpdateRate = 0x40001778; -rcUpdateTxDone = 0x4000177c; -rcUpdateTxDoneAmpdu2 = 0x40001780; -rcUpSched = 0x40001784; -rssi_margin = 0x40001788; -rx11NRate2AMPDULimit = 0x4000178c; -TRC_AMPDU_PER_DOWN_THRESHOLD = 0x40001790; -TRC_AMPDU_PER_UP_THRESHOLD = 0x40001794; -trc_calc_duration = 0x40001798; -trc_isTxAmpduOperational = 0x4000179c; -trc_onAmpduOp = 0x400017a0; -TRC_PER_IS_GOOD = 0x400017a4; -trc_SetTxAmpduState = 0x400017a8; -trc_tid_isTxAmpduOperational = 0x400017ac; -trcAmpduSetState = 0x400017b0; -wDevCheckBlockError = 0x400017b4; -wDev_AppendRxBlocks = 0x400017b8; -wDev_DiscardFrame = 0x400017bc; -wDev_GetNoiseFloor = 0x400017c0; -wDev_IndicateAmpdu = 0x400017c4; -wDev_IndicateFrame = 0x400017c8; -wdev_bank_store = 0x400017cc; -wdev_bank_load = 0x400017d0; -wdev_mac_reg_load = 0x400017d4; -wdev_mac_reg_store = 0x400017d8; -wdev_mac_special_reg_load = 0x400017dc; -wdev_mac_special_reg_store = 0x400017e0; -wdev_mac_wakeup = 0x400017e4; -wdev_mac_sleep = 0x400017e8; -hal_mac_is_dma_enable = 0x400017ec; -wDev_ProcessFiq = 0x400017f0; -wDev_ProcessRxSucData = 0x400017f4; -wdevProcessRxSucDataAll = 0x400017f8; -wdev_csi_len_align = 0x400017fc; -ppDequeueTxDone_Locked = 0x40001800; -ppProcTxDone = 0x40001804; -pm_tx_data_done_process = 0x40001808; -config_is_cache_tx_buf_enabled = 0x4000180c; -ppMapWaitTxq = 0x40001810; -ppProcessWaitingQueue = 0x40001814; -ppDisableQueue = 0x40001818; -pm_allow_tx = 0x4000181c; -/* Data (.data, .bss, .rodata) */ -our_instances_ptr = 0x3ff1ee44; -pTxRx = 0x3fcdf968; -lmacConfMib_ptr = 0x3fcdf964; -our_wait_eb = 0x3fcdf960; -our_tx_eb = 0x3fcdf95c; -pp_wdev_funcs = 0x3fcdf958; -g_osi_funcs_p = 0x3fcdf954; -wDevCtrl_ptr = 0x3fcdf950; -g_wdev_last_desc_reset_ptr = 0x3ff1ee40; -wDevMacSleep_ptr = 0x3fcdf94c; -g_lmac_cnt_ptr = 0x3fcdf948; -our_controls_ptr = 0x3ff1ee3c; -pp_sig_cnt_ptr = 0x3fcdf944; -g_eb_list_desc_ptr = 0x3fcdf940; -s_fragment_ptr = 0x3fcdf93c; -if_ctrl_ptr = 0x3fcdf938; -g_intr_lock_mux = 0x3fcdf934; -g_wifi_global_lock = 0x3fcdf930; -s_wifi_queue = 0x3fcdf92c; -pp_task_hdl = 0x3fcdf928; -s_pp_task_create_sem = 0x3fcdf924; -s_pp_task_del_sem = 0x3fcdf920; -g_wifi_menuconfig_ptr = 0x3fcdf91c; -xphyQueue = 0x3fcdf918; -ap_no_lr_ptr = 0x3fcdf914; -rc11BSchedTbl_ptr = 0x3fcdf910; -rc11NSchedTbl_ptr = 0x3fcdf90c; -rcLoRaSchedTbl_ptr = 0x3fcdf908; -BasicOFDMSched_ptr = 0x3fcdf904; -trc_ctl_ptr = 0x3fcdf900; -g_pm_cnt_ptr = 0x3fcdf8fc; -g_pm_ptr = 0x3fcdf8f8; -g_pm_cfg_ptr = 0x3fcdf8f4; -g_esp_mesh_quick_funcs_ptr = 0x3fcdf8f0; -g_txop_queue_status_ptr = 0x3fcdf8ec; -g_mac_sleep_en_ptr = 0x3fcdf8e8; -g_mesh_is_root_ptr = 0x3fcdf8e4; -g_mesh_topology_ptr = 0x3fcdf8e0; -g_mesh_init_ps_type_ptr = 0x3fcdf8dc; -g_mesh_is_started_ptr = 0x3fcdf8d8; -g_config_func = 0x3fcdf8d4; -g_net80211_tx_func = 0x3fcdf8d0; -g_timer_func = 0x3fcdf8cc; -s_michael_mic_failure_cb = 0x3fcdf8c8; -wifi_sta_rx_probe_req = 0x3fcdf8c4; -g_tx_done_cb_func = 0x3fcdf8c0; -g_per_conn_trc = 0x3fcdf874; -s_encap_amsdu_func = 0x3fcdf870; - - -/*************************************** - Group rom_net80211 - ***************************************/ - -/* Functions */ -esp_net80211_rom_version_get = 0x40001820; -ampdu_dispatch = 0x40001824; -ampdu_dispatch_all = 0x40001828; -ampdu_dispatch_as_many_as_possible = 0x4000182c; -ampdu_dispatch_movement = 0x40001830; -ampdu_dispatch_upto = 0x40001834; -chm_is_at_home_channel = 0x40001838; -cnx_node_is_existing = 0x4000183c; -cnx_node_search = 0x40001840; -ic_ebuf_recycle_rx = 0x40001844; -ic_ebuf_recycle_tx = 0x40001848; -ic_reset_rx_ba = 0x4000184c; -ieee80211_align_eb = 0x40001850; -ieee80211_ampdu_reorder = 0x40001854; -ieee80211_ampdu_start_age_timer = 0x40001858; -ieee80211_encap_esfbuf = 0x4000185c; -ieee80211_is_tx_allowed = 0x40001860; -ieee80211_output_pending_eb = 0x40001864; -ieee80211_output_process = 0x40001868; -ieee80211_set_tx_desc = 0x4000186c; -sta_input = 0x40001870; -wifi_get_macaddr = 0x40001874; -wifi_rf_phy_disable = 0x40001878; -wifi_rf_phy_enable = 0x4000187c; -ic_ebuf_alloc = 0x40001880; -ieee80211_classify = 0x40001884; -ieee80211_copy_eb_header = 0x40001888; -ieee80211_recycle_cache_eb = 0x4000188c; -ieee80211_search_node = 0x40001890; -roundup2 = 0x40001894; -ieee80211_crypto_encap = 0x40001898; -ieee80211_crypto_decap = 0x4000189c; -ieee80211_decap = 0x400018a0; -ieee80211_set_tx_pti = 0x400018a4; -wifi_is_started = 0x400018a8; -/* Data (.data, .bss, .rodata) */ -net80211_funcs = 0x3fcdf86c; -g_scan = 0x3fcdf868; -g_chm = 0x3fcdf864; -g_ic_ptr = 0x3fcdf860; -g_hmac_cnt_ptr = 0x3fcdf85c; -g_tx_cacheq_ptr = 0x3fcdf858; -s_netstack_free = 0x3fcdf854; -mesh_rxcb = 0x3fcdf850; -sta_rxcb = 0x3fcdf84c; - - -/*************************************** - Group rom_coexist - ***************************************/ - -/* Functions */ -esp_coex_rom_version_get = 0x400018ac; -coex_bt_release = 0x400018b0; -coex_bt_request = 0x400018b4; -coex_core_ble_conn_dyn_prio_get = 0x400018b8; -coex_core_event_duration_get = 0x400018bc; -coex_core_pti_get = 0x400018c0; -coex_core_release = 0x400018c4; -coex_core_request = 0x400018c8; -coex_core_status_get = 0x400018cc; -coex_core_timer_idx_get = 0x400018d0; -coex_event_duration_get = 0x400018d4; -coex_hw_timer_disable = 0x400018d8; -coex_hw_timer_enable = 0x400018dc; -coex_hw_timer_set = 0x400018e0; -coex_schm_interval_set = 0x400018e4; -coex_schm_lock = 0x400018e8; -coex_schm_unlock = 0x400018ec; -coex_status_get = 0x400018f0; -coex_wifi_release = 0x400018f4; -esp_coex_ble_conn_dynamic_prio_get = 0x400018f8; -/* Data (.data, .bss, .rodata) */ -coex_env_ptr = 0x3fcdf848; -coex_pti_tab_ptr = 0x3fcdf844; -coex_schm_env_ptr = 0x3fcdf840; -coexist_funcs = 0x3fcdf83c; -g_coa_funcs_p = 0x3fcdf838; -g_coex_param_ptr = 0x3fcdf834; - - -/*************************************** - Group rom_phy - ***************************************/ - -/* Functions */ -phy_get_romfuncs = 0x400018fc; -rom_abs_temp = 0x40001900; -rom_bb_bss_cbw40_dig = 0x40001904; -rom_bb_wdg_test_en = 0x40001908; -rom_bb_wdt_get_status = 0x4000190c; -rom_bb_wdt_int_enable = 0x40001910; -rom_bb_wdt_rst_enable = 0x40001914; -rom_bb_wdt_timeout_clear = 0x40001918; -rom_cbw2040_cfg = 0x4000191c; -rom_check_noise_floor = 0x40001920; -rom_chip_i2c_readReg = 0x40001924; -rom_chip_i2c_writeReg = 0x40001928; -rom_correct_rf_ana_gain = 0x4000192c; -rom_dc_iq_est = 0x40001930; -rom_disable_agc = 0x40001934; -rom_en_pwdet = 0x40001938; -rom_enable_agc = 0x4000193c; -rom_get_bbgain_db = 0x40001940; -rom_get_data_sat = 0x40001944; -rom_get_i2c_read_mask = 0x40001948; -rom_get_pwctrl_correct = 0x4000194c; -rom_get_rf_gain_qdb = 0x40001950; -rom_i2c_readReg = 0x40001954; -rom_i2c_readReg_Mask = 0x40001958; -rom_i2c_writeReg = 0x4000195c; -rom_i2c_writeReg_Mask = 0x40001960; -rom_index_to_txbbgain = 0x40001964; -rom_iq_est_disable = 0x40001968; -rom_iq_est_enable = 0x4000196c; -rom_linear_to_db = 0x40001970; -rom_loopback_mode_en = 0x40001974; -rom_mhz2ieee = 0x40001978; -rom_noise_floor_auto_set = 0x4000197c; -rom_pbus_debugmode = 0x40001980; -rom_pbus_force_mode = 0x40001984; -rom_pbus_force_test = 0x40001988; -rom_pbus_rd = 0x4000198c; -rom_pbus_rd_addr = 0x40001990; -rom_pbus_rd_shift = 0x40001994; -rom_pbus_set_dco = 0x40001998; -rom_pbus_set_rxgain = 0x4000199c; -rom_pbus_workmode = 0x400019a0; -rom_pbus_xpd_rx_off = 0x400019a4; -rom_pbus_xpd_rx_on = 0x400019a8; -rom_pbus_xpd_tx_off = 0x400019ac; -rom_pbus_xpd_tx_on = 0x400019b0; -rom_phy_byte_to_word = 0x400019b4; -rom_phy_disable_cca = 0x400019b8; -rom_phy_enable_cca = 0x400019bc; -rom_phy_get_noisefloor = 0x400019c0; -rom_phy_get_rx_freq = 0x400019c4; -rom_phy_set_bbfreq_init = 0x400019c8; -rom_pow_usr = 0x400019cc; -rom_pwdet_sar2_init = 0x400019d0; -rom_read_hw_noisefloor = 0x400019d4; -rom_read_sar_dout = 0x400019d8; -rom_set_cal_rxdc = 0x400019dc; -rom_set_chan_cal_interp = 0x400019e0; -rom_set_loopback_gain = 0x400019e4; -rom_set_noise_floor = 0x400019e8; -rom_set_rxclk_en = 0x400019ec; -rom_set_tx_dig_gain = 0x400019f0; -rom_set_txcap_reg = 0x400019f4; -rom_set_txclk_en = 0x400019f8; -rom_spur_cal = 0x400019fc; -rom_spur_reg_write_one_tone = 0x40001a00; -rom_target_power_add_backoff = 0x40001a04; -rom_tx_pwctrl_bg_init = 0x40001a08; -rom_txbbgain_to_index = 0x40001a0c; -rom_wifi_11g_rate_chg = 0x40001a10; -rom_write_gain_mem = 0x40001a14; -chip726_phyrom_version = 0x40001a18; -rom_disable_wifi_agc = 0x40001a1c; -rom_enable_wifi_agc = 0x40001a20; -rom_set_tx_gain_table = 0x40001a24; -rom_bt_index_to_bb = 0x40001a28; -rom_bt_bb_to_index = 0x40001a2c; -rom_wr_bt_tx_atten = 0x40001a30; -rom_wr_bt_tx_gain_mem = 0x40001a34; -rom_spur_coef_cfg = 0x40001a38; -rom_bb_bss_cbw40 = 0x40001a3c; -rom_set_cca = 0x40001a40; -rom_tx_paon_set = 0x40001a44; -rom_i2cmst_reg_init = 0x40001a48; -rom_iq_corr_enable = 0x40001a4c; -rom_fe_reg_init = 0x40001a50; -rom_agc_reg_init = 0x40001a54; -rom_bb_reg_init = 0x40001a58; -rom_mac_enable_bb = 0x40001a5c; -rom_bb_wdg_cfg = 0x40001a60; -rom_force_txon = 0x40001a64; -rom_fe_txrx_reset = 0x40001a68; -rom_set_rx_comp = 0x40001a6c; -rom_set_pbus_reg = 0x40001a70; -rom_write_chan_freq = 0x40001a74; -rom_phy_xpd_rf = 0x40001a78; -rom_set_xpd_sar = 0x40001a7c; -rom_write_dac_gain2 = 0x40001a80; -rom_rtc_sar2_init = 0x40001a84; -rom_get_target_power_offset = 0x40001a88; -rom_write_txrate_power_offset = 0x40001a8c; -rom_get_rate_fcc_index = 0x40001a90; -rom_get_rate_target_power = 0x40001a94; -rom_write_wifi_dig_gain = 0x40001a98; -rom_bt_correct_rf_ana_gain = 0x40001a9c; -rom_pkdet_vol_start = 0x40001aa0; -rom_read_sar2_code = 0x40001aa4; -rom_get_sar2_vol = 0x40001aa8; -rom_get_pll_vol = 0x40001aac; -rom_get_phy_target_power = 0x40001ab0; -rom_temp_to_power = 0x40001ab4; -rom_phy_track_pll_cap = 0x40001ab8; -rom_phy_pwdet_always_en = 0x40001abc; -rom_phy_pwdet_onetime_en = 0x40001ac0; -rom_get_i2c_mst0_mask = 0x40001ac4; -rom_get_i2c_hostid = 0x40001ac8; -rom_enter_critical_phy = 0x40001acc; -rom_exit_critical_phy = 0x40001ad0; -rom_chip_i2c_readReg_org = 0x40001ad4; -rom_i2c_paral_set_mst0 = 0x40001ad8; -rom_i2c_paral_set_read = 0x40001adc; -rom_i2c_paral_read = 0x40001ae0; -rom_i2c_paral_write = 0x40001ae4; -rom_i2c_paral_write_num = 0x40001ae8; -rom_i2c_paral_write_mask = 0x40001aec; -rom_bb_bss_cbw40_ana = 0x40001af0; -rom_chan_to_freq = 0x40001af4; -rom_open_i2c_xpd = 0x40001af8; -rom_dac_rate_set = 0x40001afc; -rom_tsens_read_init = 0x40001b00; -rom_tsens_code_read = 0x40001b04; -rom_tsens_index_to_dac = 0x40001b08; -rom_tsens_index_to_offset = 0x40001b0c; -rom_tsens_dac_cal = 0x40001b10; -rom_code_to_temp = 0x40001b14; -rom_write_pll_cap_mem = 0x40001b18; -rom_pll_correct_dcap = 0x40001b1c; -rom_phy_en_hw_set_freq = 0x40001b20; -rom_phy_dis_hw_set_freq = 0x40001b24; -rom_pll_vol_cal = 0x40001b28; - - - - -/* ROM function interface esp32c3.rom.libgcc.ld for esp32c3 - * - * - * Generated from ./interface-esp32c3.yml md5sum 93b28a9e1fe42d212018eb4336849208 - * - * Compatible with ROM where ECO version equal or greater to 0. - * - * THIS FILE WAS AUTOMATICALLY GENERATED. DO NOT EDIT. - */ - -/*************************************** - Group libgcc - ***************************************/ - -/* Functions */ -__absvdi2 = 0x40000764; -__absvsi2 = 0x40000768; -__adddf3 = 0x4000076c; -__addsf3 = 0x40000770; -__addvdi3 = 0x40000774; -__addvsi3 = 0x40000778; -__ashldi3 = 0x4000077c; -__ashrdi3 = 0x40000780; -__bswapdi2 = 0x40000784; -__bswapsi2 = 0x40000788; -__clear_cache = 0x4000078c; -__clrsbdi2 = 0x40000790; -__clrsbsi2 = 0x40000794; -__clzdi2 = 0x40000798; -__clzsi2 = 0x4000079c; -__cmpdi2 = 0x400007a0; -__ctzdi2 = 0x400007a4; -__ctzsi2 = 0x400007a8; -__divdc3 = 0x400007ac; -__divdf3 = 0x400007b0; -__divdi3 = 0x400007b4; -__divsc3 = 0x400007b8; -__divsf3 = 0x400007bc; -__divsi3 = 0x400007c0; -__eqdf2 = 0x400007c4; -__eqsf2 = 0x400007c8; -__extendsfdf2 = 0x400007cc; -__ffsdi2 = 0x400007d0; -__ffssi2 = 0x400007d4; -__fixdfdi = 0x400007d8; -__fixdfsi = 0x400007dc; -__fixsfdi = 0x400007e0; -__fixsfsi = 0x400007e4; -__fixunsdfsi = 0x400007e8; -__fixunssfdi = 0x400007ec; -__fixunssfsi = 0x400007f0; -__floatdidf = 0x400007f4; -__floatdisf = 0x400007f8; -__floatsidf = 0x400007fc; -__floatsisf = 0x40000800; -__floatundidf = 0x40000804; -__floatundisf = 0x40000808; -__floatunsidf = 0x4000080c; -__floatunsisf = 0x40000810; -__gcc_bcmp = 0x40000814; -__gedf2 = 0x40000818; -__gesf2 = 0x4000081c; -__gtdf2 = 0x40000820; -__gtsf2 = 0x40000824; -__ledf2 = 0x40000828; -__lesf2 = 0x4000082c; -__lshrdi3 = 0x40000830; -__ltdf2 = 0x40000834; -__ltsf2 = 0x40000838; -__moddi3 = 0x4000083c; -__modsi3 = 0x40000840; -__muldc3 = 0x40000844; -__muldf3 = 0x40000848; -__muldi3 = 0x4000084c; -__mulsc3 = 0x40000850; -__mulsf3 = 0x40000854; -__mulsi3 = 0x40000858; -__mulvdi3 = 0x4000085c; -__mulvsi3 = 0x40000860; -__nedf2 = 0x40000864; -__negdf2 = 0x40000868; -__negdi2 = 0x4000086c; -__negsf2 = 0x40000870; -__negvdi2 = 0x40000874; -__negvsi2 = 0x40000878; -__nesf2 = 0x4000087c; -__paritysi2 = 0x40000880; -__popcountdi2 = 0x40000884; -__popcountsi2 = 0x40000888; -__powidf2 = 0x4000088c; -__powisf2 = 0x40000890; -__subdf3 = 0x40000894; -__subsf3 = 0x40000898; -__subvdi3 = 0x4000089c; -__subvsi3 = 0x400008a0; -__truncdfsf2 = 0x400008a4; -__ucmpdi2 = 0x400008a8; -__udivdi3 = 0x400008ac; -__udivmoddi4 = 0x400008b0; -__udivsi3 = 0x400008b4; -__udiv_w_sdiv = 0x400008b8; -__umoddi3 = 0x400008bc; -__umodsi3 = 0x400008c0; -__unorddf2 = 0x400008c4; -__unordsf2 = 0x400008c8; - - - -/* ROM function interface esp32c3.rom.newlib-nano.ld for esp32c3 - * - * - * Generated from ./interface-esp32c3.yml md5sum 93b28a9e1fe42d212018eb4336849208 - * - * Compatible with ROM where ECO version equal or greater to 0. - * - * THIS FILE WAS AUTOMATICALLY GENERATED. DO NOT EDIT. - */ - -/*************************************** - Group newlib_nano_format - ***************************************/ - -/* Functions */ -__sprint_r = 0x40000480; -_fiprintf_r = 0x40000484; -_fprintf_r = 0x40000488; -_printf_common = 0x4000048c; -_printf_i = 0x40000490; -_vfiprintf_r = 0x40000494; -_vfprintf_r = 0x40000498; -fiprintf = 0x4000049c; -fprintf = 0x400004a0; -printf = 0x400004a4; -vfiprintf = 0x400004a8; -vfprintf = 0x400004ac; - - - - -/* ROM function interface esp32c3.rom.newlib.ld for esp32c3 - * - * - * Generated from ./interface-esp32c3.yml md5sum 93b28a9e1fe42d212018eb4336849208 - * - * Compatible with ROM where ECO version equal or greater to 0. - * - * THIS FILE WAS AUTOMATICALLY GENERATED. DO NOT EDIT. - */ - -/*************************************** - Group newlib - ***************************************/ - -/* Functions */ -esp_rom_newlib_init_common_mutexes = 0x40000350; -memset = 0x40000354; -memcpy = 0x40000358; -memmove = 0x4000035c; -memcmp = 0x40000360; -strcpy = 0x40000364; -strncpy = 0x40000368; -strcmp = 0x4000036c; -strncmp = 0x40000370; -strlen = 0x40000374; -strstr = 0x40000378; -bzero = 0x4000037c; -_isatty_r = 0x40000380; -sbrk = 0x40000384; -isalnum = 0x40000388; -isalpha = 0x4000038c; -isascii = 0x40000390; -isblank = 0x40000394; -iscntrl = 0x40000398; -isdigit = 0x4000039c; -islower = 0x400003a0; -isgraph = 0x400003a4; -isprint = 0x400003a8; -ispunct = 0x400003ac; -isspace = 0x400003b0; -isupper = 0x400003b4; -toupper = 0x400003b8; -tolower = 0x400003bc; -toascii = 0x400003c0; -memccpy = 0x400003c4; -memchr = 0x400003c8; -memrchr = 0x400003cc; -strcasecmp = 0x400003d0; -strcasestr = 0x400003d4; -strcat = 0x400003d8; -strdup = 0x400003dc; -strchr = 0x400003e0; -strcspn = 0x400003e4; -strcoll = 0x400003e8; -strlcat = 0x400003ec; -strlcpy = 0x400003f0; -strlwr = 0x400003f4; -strncasecmp = 0x400003f8; -strncat = 0x400003fc; -strndup = 0x40000400; -strnlen = 0x40000404; -strrchr = 0x40000408; -strsep = 0x4000040c; -strspn = 0x40000410; -strtok_r = 0x40000414; -strupr = 0x40000418; -longjmp = 0x4000041c; -setjmp = 0x40000420; -abs = 0x40000424; -div = 0x40000428; -labs = 0x4000042c; -ldiv = 0x40000430; -qsort = 0x40000434; -rand_r = 0x40000438; -rand = 0x4000043c; -srand = 0x40000440; -utoa = 0x40000444; -itoa = 0x40000448; -atoi = 0x4000044c; -atol = 0x40000450; -strtol = 0x40000454; -strtoul = 0x40000458; -PROVIDE( fflush = 0x4000045c ); -PROVIDE( _fflush_r = 0x40000460 ); -PROVIDE( _fwalk = 0x40000464 ); -PROVIDE( _fwalk_reent = 0x40000468 ); -PROVIDE( __smakebuf_r = 0x4000046c ); -PROVIDE( __swhatbuf_r = 0x40000470 ); -PROVIDE( __swbuf_r = 0x40000474 ); -__swbuf = 0x40000478; -PROVIDE( __swsetup_r = 0x4000047c ); -/* Data (.data, .bss, .rodata) */ -syscall_table_ptr = 0x3fcdffe0; -_global_impure_ptr = 0x3fcdffdc; - - - -/* ROM version variables for esp32c3 - * - * These addresses should be compatible with any ROM version for this chip. - * - * THIS FILE WAS AUTOMATICALLY GENERATED. DO NOT EDIT. - */ -_rom_chip_id = 0x40000010; -_rom_eco_version = 0x40000014; diff --git a/tools/esptool_py/flasher_stub/ld/rom_32c5_beta_3.ld b/tools/esptool_py/flasher_stub/ld/rom_32c5_beta_3.ld deleted file mode 100755 index d9c3d3e5e0..0000000000 --- a/tools/esptool_py/flasher_stub/ld/rom_32c5_beta_3.ld +++ /dev/null @@ -1,429 +0,0 @@ -/* ROM function interface esp32c5.rom.ld for esp32c5 - * - * - * Generated from ./target/esp32c5/interface-esp32c5.yml md5sum 2476337377df636dda217b0b3c1a63db - * - * Compatible with ROM where ECO version equal or greater to 0. - * - * THIS FILE WAS AUTOMATICALLY GENERATED. DO NOT EDIT. - */ - -/*************************************** - Group common - ***************************************/ - -PROVIDE ( SPIWrite = esp_rom_spiflash_write); -PROVIDE ( SPI_read_status_high = esp_rom_spiflash_read_statushigh); -PROVIDE ( SPI_write_status = esp_rom_spiflash_write_status); -PROVIDE ( SPIRead = esp_rom_spiflash_read); -PROVIDE ( SPIParamCfg = esp_rom_spiflash_config_param); -PROVIDE ( SPIEraseChip = esp_rom_spiflash_erase_chip); -PROVIDE ( SPIEraseSector = esp_rom_spiflash_erase_sector); -PROVIDE ( SPIEraseBlock = esp_rom_spiflash_erase_block); -PROVIDE ( SPI_Write_Encrypt_Enable = esp_rom_spiflash_write_encrypted_enable); -PROVIDE ( SPI_Write_Encrypt_Disable = esp_rom_spiflash_write_encrypted_disable); -PROVIDE ( SPI_Encrypt_Write = esp_rom_spiflash_write_encrypted); - -/*************************************** - Group common - ***************************************/ - -/* Functions */ -rtc_get_reset_reason = 0x40000018; -rtc_get_wakeup_cause = 0x4000001c; -pmu_enable_unhold_pads = 0x40000020; -ets_printf = 0x40000024; -ets_install_putc1 = 0x40000028; -ets_install_putc2 = 0x4000002c; -ets_install_uart_printf = 0x40000030; -ets_install_usb_printf = 0x40000034; -ets_get_printf_channel = 0x40000038; -ets_delay_us = 0x4000003c; -ets_get_cpu_frequency = 0x40000040; -ets_update_cpu_frequency = 0x40000044; -ets_install_lock = 0x40000048; -UartRxString = 0x4000004c; -UartGetCmdLn = 0x40000050; -uart_tx_one_char = 0x40000054; -uart_tx_one_char2 = 0x40000058; -uart_tx_one_char3 = 0x4000005c; -uart_rx_one_char = 0x40000060; -uart_rx_one_char_block = 0x40000064; -uart_rx_intr_handler = 0x40000068; -uart_rx_readbuff = 0x4000006c; -uartAttach = 0x40000070; -uart_tx_flush = 0x40000074; -uart_tx_wait_idle = 0x40000078; -uart_div_modify = 0x4000007c; -ets_write_char_uart = 0x40000080; -uart_tx_switch = 0x40000084; -uart_buff_switch = 0x40000088; -roundup2 = 0x4000008c; -multofup = 0x40000090; -software_reset = 0x40000094; -software_reset_cpu = 0x40000098; -ets_clk_assist_debug_clock_enable = 0x4000009c; -clear_super_wdt_reset_flag = 0x400000a0; -disable_default_watchdog = 0x400000a4; -esp_rom_set_rtc_wake_addr = 0x400000a8; -esp_rom_get_rtc_wake_addr = 0x400000ac; -send_packet = 0x400000b0; -recv_packet = 0x400000b4; -GetUartDevice = 0x400000b8; -UartDwnLdProc = 0x400000bc; -GetSecurityInfoProc = 0x400000c0; -Uart_Init = 0x400000c4; -ets_set_user_start = 0x400000c8; -/* Data (.data, .bss, .rodata) */ -ets_rom_layout_p = 0x4004fffc; -ets_ops_table_ptr = 0x4087fff8; -g_saved_pc = 0x4087fffc; - - -/*************************************** - Group miniz - ***************************************/ - -/* Functions */ -mz_adler32 = 0x400000cc; -mz_free = 0x400000d0; -tdefl_compress = 0x400000d4; -tdefl_compress_buffer = 0x400000d8; -tdefl_compress_mem_to_heap = 0x400000dc; -tdefl_compress_mem_to_mem = 0x400000e0; -tdefl_compress_mem_to_output = 0x400000e4; -tdefl_get_adler32 = 0x400000e8; -tdefl_get_prev_return_status = 0x400000ec; -tdefl_init = 0x400000f0; -tdefl_write_image_to_png_file_in_memory = 0x400000f4; -tdefl_write_image_to_png_file_in_memory_ex = 0x400000f8; -tinfl_decompress = 0x400000fc; -tinfl_decompress_mem_to_callback = 0x40000100; -tinfl_decompress_mem_to_heap = 0x40000104; -tinfl_decompress_mem_to_mem = 0x40000108; - - -/*************************************** - Group spiflash_legacy - ***************************************/ - -/* Functions */ -esp_rom_spiflash_wait_idle = 0x4000010c; -esp_rom_spiflash_write_encrypted = 0x40000110; -esp_rom_spiflash_write_encrypted_dest = 0x40000114; -esp_rom_spiflash_write_encrypted_enable = 0x40000118; -esp_rom_spiflash_write_encrypted_disable = 0x4000011c; -esp_rom_spiflash_erase_chip = 0x40000120; -_esp_rom_spiflash_erase_sector = 0x40000124; -_esp_rom_spiflash_erase_block = 0x40000128; -_esp_rom_spiflash_write = 0x4000012c; -_esp_rom_spiflash_read = 0x40000130; -_esp_rom_spiflash_unlock = 0x40000134; -_SPIEraseArea = 0x40000138; -_SPI_write_enable = 0x4000013c; -esp_rom_spiflash_erase_sector = 0x40000140; -esp_rom_spiflash_erase_block = 0x40000144; -esp_rom_spiflash_write = 0x40000148; -esp_rom_spiflash_read = 0x4000014c; -esp_rom_spiflash_unlock = 0x40000150; -SPIEraseArea = 0x40000154; -SPI_write_enable = 0x40000158; -esp_rom_spiflash_config_param = 0x4000015c; -esp_rom_spiflash_read_user_cmd = 0x40000160; -esp_rom_spiflash_select_qio_pins = 0x40000164; -esp_rom_spi_flash_auto_sus_res = 0x40000168; -esp_rom_spi_flash_send_resume = 0x4000016c; -esp_rom_spi_flash_update_id = 0x40000170; -esp_rom_spiflash_config_clk = 0x40000174; -esp_rom_spiflash_config_readmode = 0x40000178; -esp_rom_spiflash_read_status = 0x4000017c; -esp_rom_spiflash_read_statushigh = 0x40000180; -esp_rom_spiflash_write_status = 0x40000184; -esp_rom_spiflash_write_disable = 0x40000188; -spi_cache_mode_switch = 0x4000018c; -spi_common_set_dummy_output = 0x40000190; -spi_common_set_flash_cs_timing = 0x40000194; -esp_rom_spi_set_address_bit_len = 0x40000198; -SPILock = 0x4000019c; -SPIMasterReadModeCnfig = 0x400001a0; -SPI_Common_Command = 0x400001a4; -SPI_WakeUp = 0x400001a8; -SPI_block_erase = 0x400001ac; -SPI_chip_erase = 0x400001b0; -SPI_init = 0x400001b4; -SPI_page_program = 0x400001b8; -SPI_read_data = 0x400001bc; -SPI_sector_erase = 0x400001c0; -SelectSpiFunction = 0x400001c4; -SetSpiDrvs = 0x400001c8; -Wait_SPI_Idle = 0x400001cc; -spi_dummy_len_fix = 0x400001d0; -Disable_QMode = 0x400001d4; -Enable_QMode = 0x400001d8; -spi_flash_attach = 0x400001dc; -spi_flash_get_chip_size = 0x400001e0; -spi_flash_guard_set = 0x400001e4; -spi_flash_guard_get = 0x400001e8; -spi_flash_read_encrypted = 0x400001ec; -/* Data (.data, .bss, .rodata) */ -rom_spiflash_legacy_funcs = 0x4087fff0; -rom_spiflash_legacy_data = 0x4087ffec; -g_flash_guard_ops = 0x4087fff4; - - -/*************************************** - Group hal_wdt - ***************************************/ - -/* Functions */ -wdt_hal_init = 0x40000390; -wdt_hal_deinit = 0x40000394; -wdt_hal_config_stage = 0x40000398; -wdt_hal_write_protect_disable = 0x4000039c; -wdt_hal_write_protect_enable = 0x400003a0; -wdt_hal_enable = 0x400003a4; -wdt_hal_disable = 0x400003a8; -wdt_hal_handle_intr = 0x400003ac; -wdt_hal_feed = 0x400003b0; -wdt_hal_set_flashboot_en = 0x400003b4; -wdt_hal_is_enabled = 0x400003b8; - - -/*************************************** - Group hal_systimer - ***************************************/ - -/* Functions */ -systimer_hal_init = 0x400003bc; -systimer_hal_deinit = 0x400003c0; -systimer_hal_set_tick_rate_ops = 0x400003c4; -systimer_hal_get_counter_value = 0x400003c8; -systimer_hal_get_time = 0x400003cc; -systimer_hal_set_alarm_target = 0x400003d0; -systimer_hal_set_alarm_period = 0x400003d4; -systimer_hal_get_alarm_value = 0x400003d8; -systimer_hal_enable_alarm_int = 0x400003dc; -systimer_hal_on_apb_freq_update = 0x400003e0; -systimer_hal_counter_value_advance = 0x400003e4; -systimer_hal_enable_counter = 0x400003e8; -systimer_hal_select_alarm_mode = 0x400003ec; -systimer_hal_connect_alarm_counter = 0x400003f0; -systimer_hal_counter_can_stall_by_cpu = 0x400003f4; - - -/*************************************** - Group cache - ***************************************/ - -/* Functions */ -Cache_Get_ICache_Line_Size = 0x40000624; -Cache_Get_Mode = 0x40000628; -Cache_Address_Through_Cache = 0x4000062c; -ROM_Boot_Cache_Init = 0x40000630; -MMU_Set_Page_Mode = 0x40000634; -MMU_Get_Page_Mode = 0x40000638; -Cache_Invalidate_ICache_Items = 0x4000063c; -Cache_Op_Addr = 0x40000640; -Cache_Invalidate_Addr = 0x40000644; -Cache_Invalidate_ICache_All = 0x40000648; -Cache_Mask_All = 0x4000064c; -Cache_UnMask_Dram0 = 0x40000650; -Cache_Suspend_ICache_Autoload = 0x40000654; -Cache_Resume_ICache_Autoload = 0x40000658; -Cache_Start_ICache_Preload = 0x4000065c; -Cache_ICache_Preload_Done = 0x40000660; -Cache_End_ICache_Preload = 0x40000664; -Cache_Config_ICache_Autoload = 0x40000668; -Cache_Enable_ICache_Autoload = 0x4000066c; -Cache_Disable_ICache_Autoload = 0x40000670; -Cache_Enable_ICache_PreLock = 0x40000674; -Cache_Disable_ICache_PreLock = 0x40000678; -Cache_Lock_ICache_Items = 0x4000067c; -Cache_Unlock_ICache_Items = 0x40000680; -Cache_Lock_Addr = 0x40000684; -Cache_Unlock_Addr = 0x40000688; -Cache_Disable_ICache = 0x4000068c; -Cache_Enable_ICache = 0x40000690; -Cache_Suspend_ICache = 0x40000694; -Cache_Resume_ICache = 0x40000698; -Cache_Freeze_ICache_Enable = 0x4000069c; -Cache_Freeze_ICache_Disable = 0x400006a0; -Cache_Set_IDROM_MMU_Size = 0x400006a4; -Cache_Get_IROM_MMU_End = 0x400006a8; -Cache_Get_DROM_MMU_End = 0x400006ac; -Cache_MMU_Init = 0x400006b0; -Cache_MSPI_MMU_Set = 0x400006b4; -Cache_MSPI_MMU_Set_Secure = 0x400006b8; -Cache_Travel_Tag_Memory = 0x400006bc; -Cache_Get_Virtual_Addr = 0x400006c0; -/* Data (.data, .bss, .rodata) */ -rom_cache_op_cb = 0x4087ffcc; -rom_cache_internal_table_ptr = 0x4087ffc8; - - -/*************************************** - Group clock - ***************************************/ - -/* Functions */ -ets_clk_get_xtal_freq = 0x400006c4; -ets_clk_get_cpu_freq = 0x400006c8; - - -/*************************************** - Group gpio - ***************************************/ - -/* Functions */ -gpio_set_output_level = 0x400006cc; -gpio_get_input_level = 0x400006d0; -gpio_matrix_in = 0x400006d4; -gpio_matrix_out = 0x400006d8; -gpio_bypass_matrix_in = 0x400006dc; -gpio_output_disable = 0x400006e0; -gpio_output_enable = 0x400006e4; -gpio_pad_input_disable = 0x400006e8; -gpio_pad_input_enable = 0x400006ec; -gpio_pad_pulldown = 0x400006f0; -gpio_pad_pullup = 0x400006f4; -gpio_pad_select_gpio = 0x400006f8; -gpio_pad_set_drv = 0x400006fc; -gpio_pad_unhold = 0x40000700; -gpio_pad_hold = 0x40000704; - - -/*************************************** - Group interrupts - ***************************************/ - -/* Functions */ -esprv_intc_int_set_priority = 0x40000708; -esprv_intc_int_set_threshold = 0x4000070c; -esprv_intc_int_enable = 0x40000710; -esprv_intc_int_disable = 0x40000714; -esprv_intc_int_set_type = 0x40000718; -PROVIDE( intr_handler_set = 0x4000071c ); -intr_matrix_set = 0x40000720; -ets_intr_lock = 0x40000724; -ets_intr_unlock = 0x40000728; -ets_isr_attach = 0x4000072c; -ets_isr_mask = 0x40000730; -ets_isr_unmask = 0x40000734; - - -/*************************************** - Group crypto - ***************************************/ - -/* Functions */ -md5_vector = 0x40000738; -MD5Init = 0x4000073c; -MD5Update = 0x40000740; -MD5Final = 0x40000744; -crc32_le = 0x40000748; -crc16_le = 0x4000074c; -crc8_le = 0x40000750; -crc32_be = 0x40000754; -crc16_be = 0x40000758; -crc8_be = 0x4000075c; -esp_crc8 = 0x40000760; -ets_sha_enable = 0x40000764; -ets_sha_disable = 0x40000768; -ets_sha_get_state = 0x4000076c; -ets_sha_init = 0x40000770; -ets_sha_process = 0x40000774; -ets_sha_starts = 0x40000778; -ets_sha_update = 0x4000077c; -ets_sha_finish = 0x40000780; -ets_sha_clone = 0x40000784; -ets_hmac_enable = 0x40000788; -ets_hmac_disable = 0x4000078c; -ets_hmac_calculate_message = 0x40000790; -ets_hmac_calculate_downstream = 0x40000794; -ets_hmac_invalidate_downstream = 0x40000798; -ets_jtag_enable_temporarily = 0x4000079c; -ets_aes_enable = 0x400007a0; -ets_aes_disable = 0x400007a4; -ets_aes_setkey = 0x400007a8; -ets_aes_block = 0x400007ac; -ets_aes_setkey_dec = 0x400007b0; -ets_aes_setkey_enc = 0x400007b4; -ets_bigint_enable = 0x400007b8; -ets_bigint_disable = 0x400007bc; -ets_bigint_multiply = 0x400007c0; -ets_bigint_modmult = 0x400007c4; -ets_bigint_modexp = 0x400007c8; -ets_bigint_wait_finish = 0x400007cc; -ets_bigint_getz = 0x400007d0; -ets_ds_enable = 0x400007d4; -ets_ds_disable = 0x400007d8; -ets_ds_start_sign = 0x400007dc; -ets_ds_is_busy = 0x400007e0; -ets_ds_finish_sign = 0x400007e4; -ets_ds_encrypt_params = 0x400007e8; -ets_mgf1_sha256 = 0x400007ec; -/* Data (.data, .bss, .rodata) */ -crc32_le_table_ptr = 0x4004fff8; -crc16_le_table_ptr = 0x4004fff4; -crc8_le_table_ptr = 0x4004fff0; -crc32_be_table_ptr = 0x4004ffec; -crc16_be_table_ptr = 0x4004ffe8; -crc8_be_table_ptr = 0x4004ffe4; - - -/*************************************** - Group efuse - ***************************************/ - -/* Functions */ -ets_efuse_read = 0x400007f0; -ets_efuse_program = 0x400007f4; -ets_efuse_clear_program_registers = 0x400007f8; -ets_efuse_write_key = 0x400007fc; -ets_efuse_get_read_register_address = 0x40000800; -ets_efuse_get_key_purpose = 0x40000804; -ets_efuse_key_block_unused = 0x40000808; -ets_efuse_find_unused_key_block = 0x4000080c; -ets_efuse_rs_calculate = 0x40000810; -ets_efuse_count_unused_key_blocks = 0x40000814; -ets_efuse_secure_boot_enabled = 0x40000818; -ets_efuse_secure_boot_aggressive_revoke_enabled = 0x4000081c; -ets_efuse_cache_encryption_enabled = 0x40000820; -ets_efuse_download_modes_disabled = 0x40000824; -ets_efuse_find_purpose = 0x40000828; -ets_efuse_force_send_resume = 0x4000082c; -ets_efuse_get_flash_delay_us = 0x40000830; -ets_efuse_get_uart_print_control = 0x40000834; -ets_efuse_direct_boot_mode_disabled = 0x40000838; -ets_efuse_security_download_modes_enabled = 0x4000083c; -ets_efuse_jtag_disabled = 0x40000840; -ets_efuse_usb_print_is_disabled = 0x40000844; -ets_efuse_usb_download_mode_disabled = 0x40000848; -ets_efuse_usb_device_disabled = 0x4000084c; -ets_efuse_secure_boot_fast_wake_enabled = 0x40000850; - - -/*************************************** - Group secureboot - ***************************************/ - -/* Functions */ -ets_emsa_pss_verify = 0x40000854; -ets_rsa_pss_verify = 0x40000858; -ets_ecdsa_verify = 0x4000085c; -ets_secure_boot_verify_bootloader_with_keys = 0x40000860; -ets_secure_boot_verify_signature = 0x40000864; -ets_secure_boot_read_key_digests = 0x40000868; -ets_secure_boot_revoke_public_key_digest = 0x4000086c; - - -/*************************************** - Group usb_device_uart - ***************************************/ - -/* Functions */ -usb_serial_device_rx_one_char = 0x40000a6c; -usb_serial_device_rx_one_char_block = 0x40000a70; -usb_serial_device_tx_flush = 0x40000a74; -usb_serial_device_tx_one_char = 0x40000a78; - diff --git a/tools/esptool_py/flasher_stub/ld/rom_32c6.ld b/tools/esptool_py/flasher_stub/ld/rom_32c6.ld deleted file mode 100755 index 47466e9770..0000000000 --- a/tools/esptool_py/flasher_stub/ld/rom_32c6.ld +++ /dev/null @@ -1,487 +0,0 @@ -/* ROM function interface esp32c6.rom.ld for esp32c6 - * - * - * Generated from ./target/esp32c6/interface-esp32c6.yml md5sum 626e7f1bf23e87c38db8c3f22a53407b - * - * Compatible with ROM where ECO version equal or greater to 0. - * - * THIS FILE WAS AUTOMATICALLY GENERATED. DO NOT EDIT. - */ - -/*************************************** - Group common - ***************************************/ - -PROVIDE ( SPIWrite = esp_rom_spiflash_write); -PROVIDE ( SPI_read_status_high = esp_rom_spiflash_read_statushigh); -PROVIDE ( SPI_write_status = esp_rom_spiflash_write_status); -PROVIDE ( SPIRead = esp_rom_spiflash_read); -PROVIDE ( SPIParamCfg = esp_rom_spiflash_config_param); -PROVIDE ( SPIEraseChip = esp_rom_spiflash_erase_chip); -PROVIDE ( SPIEraseSector = esp_rom_spiflash_erase_sector); -PROVIDE ( SPIEraseBlock = esp_rom_spiflash_erase_block); -PROVIDE ( SPI_Write_Encrypt_Enable = esp_rom_spiflash_write_encrypted_enable); -PROVIDE ( SPI_Write_Encrypt_Disable = esp_rom_spiflash_write_encrypted_disable); -PROVIDE ( SPI_Encrypt_Write = esp_rom_spiflash_write_encrypted); - -/*************************************** - Group common - ***************************************/ - -/* Functions */ -rtc_get_reset_reason = 0x40000018; -analog_super_wdt_reset_happened = 0x4000001c; -rtc_get_wakeup_cause = 0x40000020; -rtc_unhold_all_pads = 0x40000024; -ets_printf = 0x40000028; -ets_install_putc1 = 0x4000002c; -ets_install_putc2 = 0x40000030; -ets_install_uart_printf = 0x40000034; -ets_install_usb_printf = 0x40000038; -ets_get_printf_channel = 0x4000003c; -ets_delay_us = 0x40000040; -ets_get_cpu_frequency = 0x40000044; -ets_update_cpu_frequency = 0x40000048; -ets_install_lock = 0x4000004c; -UartRxString = 0x40000050; -UartGetCmdLn = 0x40000054; -uart_tx_one_char = 0x40000058; -uart_tx_one_char2 = 0x4000005c; -uart_rx_one_char = 0x40000060; -uart_rx_one_char_block = 0x40000064; -uart_rx_intr_handler = 0x40000068; -uart_rx_readbuff = 0x4000006c; -uartAttach = 0x40000070; -uart_tx_flush = 0x40000074; -uart_tx_wait_idle = 0x40000078; -uart_div_modify = 0x4000007c; -ets_write_char_uart = 0x40000080; -uart_tx_switch = 0x40000084; -roundup2 = 0x40000088; -multofup = 0x4000008c; -software_reset = 0x40000090; -software_reset_cpu = 0x40000094; -ets_clk_assist_debug_clock_enable = 0x40000098; -clear_super_wdt_reset_flag = 0x4000009c; -disable_default_watchdog = 0x400000a0; -esp_rom_set_rtc_wake_addr = 0x400000a4; -esp_rom_get_rtc_wake_addr = 0x400000a8; -send_packet = 0x400000ac; -recv_packet = 0x400000b0; -GetUartDevice = 0x400000b4; -UartDwnLdProc = 0x400000b8; -GetSecurityInfoProc = 0x400000bc; -Uart_Init = 0x400000c0; -ets_set_user_start = 0x400000c4; -/* Data (.data, .bss, .rodata) */ -ets_rom_layout_p = 0x4004fffc; -ets_ops_table_ptr = 0x4087fff8; -g_saved_pc = 0x4087fffc; - - -/*************************************** - Group miniz - ***************************************/ - -/* Functions */ -mz_adler32 = 0x400000c8; -mz_free = 0x400000cc; -tdefl_compress = 0x400000d0; -tdefl_compress_buffer = 0x400000d4; -tdefl_compress_mem_to_heap = 0x400000d8; -tdefl_compress_mem_to_mem = 0x400000dc; -tdefl_compress_mem_to_output = 0x400000e0; -tdefl_get_adler32 = 0x400000e4; -tdefl_get_prev_return_status = 0x400000e8; -tdefl_init = 0x400000ec; -tdefl_write_image_to_png_file_in_memory = 0x400000f0; -tdefl_write_image_to_png_file_in_memory_ex = 0x400000f4; -tinfl_decompress = 0x400000f8; -tinfl_decompress_mem_to_callback = 0x400000fc; -tinfl_decompress_mem_to_heap = 0x40000100; -tinfl_decompress_mem_to_mem = 0x40000104; - - -/*************************************** - Group tjpgd - ***************************************/ - -/* Functions */ -jd_prepare = 0x40000108; -jd_decomp = 0x4000010c; - - -/*************************************** - Group spiflash_legacy - ***************************************/ - -/* Functions */ -esp_rom_spiflash_wait_idle = 0x40000110; -esp_rom_spiflash_write_encrypted = 0x40000114; -esp_rom_spiflash_write_encrypted_dest = 0x40000118; -esp_rom_spiflash_write_encrypted_enable = 0x4000011c; -esp_rom_spiflash_write_encrypted_disable = 0x40000120; -esp_rom_spiflash_erase_chip = 0x40000124; -_esp_rom_spiflash_erase_sector = 0x40000128; -_esp_rom_spiflash_erase_block = 0x4000012c; -_esp_rom_spiflash_write = 0x40000130; -_esp_rom_spiflash_read = 0x40000134; -_esp_rom_spiflash_unlock = 0x40000138; -_SPIEraseArea = 0x4000013c; -_SPI_write_enable = 0x40000140; -esp_rom_spiflash_erase_sector = 0x40000144; -esp_rom_spiflash_erase_block = 0x40000148; -esp_rom_spiflash_write = 0x4000014c; -esp_rom_spiflash_read = 0x40000150; -esp_rom_spiflash_unlock = 0x40000154; -SPIEraseArea = 0x40000158; -SPI_write_enable = 0x4000015c; -esp_rom_spiflash_config_param = 0x40000160; -esp_rom_spiflash_read_user_cmd = 0x40000164; -esp_rom_spiflash_select_qio_pins = 0x40000168; -esp_rom_spi_flash_auto_sus_res = 0x4000016c; -esp_rom_spi_flash_send_resume = 0x40000170; -esp_rom_spi_flash_update_id = 0x40000174; -esp_rom_spiflash_config_clk = 0x40000178; -esp_rom_spiflash_config_readmode = 0x4000017c; -esp_rom_spiflash_read_status = 0x40000180; -esp_rom_spiflash_read_statushigh = 0x40000184; -esp_rom_spiflash_write_status = 0x40000188; -spi_cache_mode_switch = 0x4000018c; -spi_common_set_dummy_output = 0x40000190; -spi_common_set_flash_cs_timing = 0x40000194; -esp_rom_spi_set_address_bit_len = 0x40000198; -SPILock = 0x4000019c; -SPIMasterReadModeCnfig = 0x400001a0; -SPI_Common_Command = 0x400001a4; -SPI_WakeUp = 0x400001a8; -SPI_block_erase = 0x400001ac; -SPI_chip_erase = 0x400001b0; -SPI_init = 0x400001b4; -SPI_page_program = 0x400001b8; -SPI_read_data = 0x400001bc; -SPI_sector_erase = 0x400001c0; -SelectSpiFunction = 0x400001c4; -SetSpiDrvs = 0x400001c8; -Wait_SPI_Idle = 0x400001cc; -spi_dummy_len_fix = 0x400001d0; -Disable_QMode = 0x400001d4; -Enable_QMode = 0x400001d8; -spi_flash_attach = 0x400001dc; -spi_flash_get_chip_size = 0x400001e0; -spi_flash_guard_set = 0x400001e4; -spi_flash_guard_get = 0x400001e8; -spi_flash_read_encrypted = 0x400001ec; -/* Data (.data, .bss, .rodata) */ -rom_spiflash_legacy_funcs = 0x4087fff0; -rom_spiflash_legacy_data = 0x4087ffec; -g_flash_guard_ops = 0x4087fff4; - - -/*************************************** - Group hal_wdt - ***************************************/ - -/* Functions */ -wdt_hal_init = 0x40000394; -wdt_hal_deinit = 0x40000398; -wdt_hal_config_stage = 0x4000039c; -wdt_hal_write_protect_disable = 0x400003a0; -wdt_hal_write_protect_enable = 0x400003a4; -wdt_hal_enable = 0x400003a8; -wdt_hal_disable = 0x400003ac; -wdt_hal_handle_intr = 0x400003b0; -wdt_hal_feed = 0x400003b4; -wdt_hal_set_flashboot_en = 0x400003b8; -wdt_hal_is_enabled = 0x400003bc; - - -/*************************************** - Group hal_systimer - ***************************************/ - -/* Functions */ -systimer_hal_init = 0x400003c0; -systimer_hal_deinit = 0x400003c4; -systimer_hal_set_tick_rate_ops = 0x400003c8; -systimer_hal_get_counter_value = 0x400003cc; -systimer_hal_get_time = 0x400003d0; -systimer_hal_set_alarm_target = 0x400003d4; -systimer_hal_set_alarm_period = 0x400003d8; -systimer_hal_get_alarm_value = 0x400003dc; -systimer_hal_enable_alarm_int = 0x400003e0; -systimer_hal_on_apb_freq_update = 0x400003e4; -systimer_hal_counter_value_advance = 0x400003e8; -systimer_hal_enable_counter = 0x400003ec; -systimer_hal_select_alarm_mode = 0x400003f0; -systimer_hal_connect_alarm_counter = 0x400003f4; -systimer_hal_counter_can_stall_by_cpu = 0x400003f8; - - -/*************************************** - Group cache - ***************************************/ - -/* Functions */ -Cache_Get_ICache_Line_Size = 0x40000628; -Cache_Get_Mode = 0x4000062c; -Cache_Address_Through_Cache = 0x40000630; -ROM_Boot_Cache_Init = 0x40000634; -MMU_Set_Page_Mode = 0x40000638; -MMU_Get_Page_Mode = 0x4000063c; -Cache_Invalidate_ICache_Items = 0x40000640; -Cache_Op_Addr = 0x40000644; -Cache_Invalidate_Addr = 0x40000648; -Cache_Invalidate_ICache_All = 0x4000064c; -Cache_Mask_All = 0x40000650; -Cache_UnMask_Dram0 = 0x40000654; -Cache_Suspend_ICache_Autoload = 0x40000658; -Cache_Resume_ICache_Autoload = 0x4000065c; -Cache_Start_ICache_Preload = 0x40000660; -Cache_ICache_Preload_Done = 0x40000664; -Cache_End_ICache_Preload = 0x40000668; -Cache_Config_ICache_Autoload = 0x4000066c; -Cache_Enable_ICache_Autoload = 0x40000670; -Cache_Disable_ICache_Autoload = 0x40000674; -Cache_Enable_ICache_PreLock = 0x40000678; -Cache_Disable_ICache_PreLock = 0x4000067c; -Cache_Lock_ICache_Items = 0x40000680; -Cache_Unlock_ICache_Items = 0x40000684; -Cache_Lock_Addr = 0x40000688; -Cache_Unlock_Addr = 0x4000068c; -Cache_Disable_ICache = 0x40000690; -Cache_Enable_ICache = 0x40000694; -Cache_Suspend_ICache = 0x40000698; -Cache_Resume_ICache = 0x4000069c; -Cache_Freeze_ICache_Enable = 0x400006a0; -Cache_Freeze_ICache_Disable = 0x400006a4; -Cache_Set_IDROM_MMU_Size = 0x400006a8; -Cache_Get_IROM_MMU_End = 0x400006ac; -Cache_Get_DROM_MMU_End = 0x400006b0; -Cache_MMU_Init = 0x400006b4; -Cache_MSPI_MMU_Set = 0x400006b8; -Cache_Travel_Tag_Memory = 0x400006bc; -Cache_Get_Virtual_Addr = 0x400006c0; -/* Data (.data, .bss, .rodata) */ -rom_cache_op_cb = 0x4087ffcc; -rom_cache_internal_table_ptr = 0x4087ffc8; - - -/*************************************** - Group clock - ***************************************/ - -/* Functions */ -ets_clk_get_xtal_freq = 0x400006c4; -ets_clk_get_cpu_freq = 0x400006c8; -ets_clk_apb_wait_ready = 0x400006cc; -ets_clk_mspi_apb_wait_ready = 0x400006d0; - - -/*************************************** - Group gpio - ***************************************/ - -/* Functions */ -gpio_input_get = 0x400006d4; -gpio_matrix_in = 0x400006d8; -gpio_matrix_out = 0x400006dc; -gpio_output_disable = 0x400006e0; -gpio_output_enable = 0x400006e4; -gpio_output_set = 0x400006e8; -gpio_pad_hold = 0x400006ec; -gpio_pad_input_disable = 0x400006f0; -gpio_pad_input_enable = 0x400006f4; -gpio_pad_pulldown = 0x400006f8; -gpio_pad_pullup = 0x400006fc; -gpio_pad_select_gpio = 0x40000700; -gpio_pad_set_drv = 0x40000704; -gpio_pad_unhold = 0x40000708; -gpio_pin_wakeup_disable = 0x4000070c; -gpio_pin_wakeup_enable = 0x40000710; -gpio_bypass_matrix_in = 0x40000714; - - -/*************************************** - Group interrupts - ***************************************/ - -/* Functions */ -esprv_intc_int_set_priority = 0x40000718; -esprv_intc_int_set_threshold = 0x4000071c; -esprv_intc_int_enable = 0x40000720; -esprv_intc_int_disable = 0x40000724; -esprv_intc_int_set_type = 0x40000728; -PROVIDE( intr_handler_set = 0x4000072c ); -intr_matrix_set = 0x40000730; -ets_intr_lock = 0x40000734; -ets_intr_unlock = 0x40000738; -ets_isr_attach = 0x4000073c; -ets_isr_mask = 0x40000740; -ets_isr_unmask = 0x40000744; - - -/*************************************** - Group crypto - ***************************************/ - -/* Functions */ -md5_vector = 0x40000748; -MD5Init = 0x4000074c; -MD5Update = 0x40000750; -MD5Final = 0x40000754; -crc32_le = 0x40000758; -crc16_le = 0x4000075c; -crc8_le = 0x40000760; -crc32_be = 0x40000764; -crc16_be = 0x40000768; -crc8_be = 0x4000076c; -esp_crc8 = 0x40000770; -ets_sha_enable = 0x40000774; -ets_sha_disable = 0x40000778; -ets_sha_get_state = 0x4000077c; -ets_sha_init = 0x40000780; -ets_sha_process = 0x40000784; -ets_sha_starts = 0x40000788; -ets_sha_update = 0x4000078c; -ets_sha_finish = 0x40000790; -ets_sha_clone = 0x40000794; -ets_hmac_enable = 0x40000798; -ets_hmac_disable = 0x4000079c; -ets_hmac_calculate_message = 0x400007a0; -ets_hmac_calculate_downstream = 0x400007a4; -ets_hmac_invalidate_downstream = 0x400007a8; -ets_jtag_enable_temporarily = 0x400007ac; -ets_aes_enable = 0x400007b0; -ets_aes_disable = 0x400007b4; -ets_aes_setkey = 0x400007b8; -ets_aes_block = 0x400007bc; -ets_aes_setkey_dec = 0x400007c0; -ets_aes_setkey_enc = 0x400007c4; -ets_bigint_enable = 0x400007c8; -ets_bigint_disable = 0x400007cc; -ets_bigint_multiply = 0x400007d0; -ets_bigint_modmult = 0x400007d4; -ets_bigint_modexp = 0x400007d8; -ets_bigint_wait_finish = 0x400007dc; -ets_bigint_getz = 0x400007e0; -ets_ds_enable = 0x400007e4; -ets_ds_disable = 0x400007e8; -ets_ds_start_sign = 0x400007ec; -ets_ds_is_busy = 0x400007f0; -ets_ds_finish_sign = 0x400007f4; -ets_ds_encrypt_params = 0x400007f8; -ets_mgf1_sha256 = 0x400007fc; -/* Data (.data, .bss, .rodata) */ -crc32_le_table_ptr = 0x4004fff8; -crc16_le_table_ptr = 0x4004fff4; -crc8_le_table_ptr = 0x4004fff0; -crc32_be_table_ptr = 0x4004ffec; -crc16_be_table_ptr = 0x4004ffe8; -crc8_be_table_ptr = 0x4004ffe4; - - -/*************************************** - Group efuse - ***************************************/ - -/* Functions */ -ets_efuse_read = 0x40000800; -ets_efuse_program = 0x40000804; -ets_efuse_clear_program_registers = 0x40000808; -ets_efuse_write_key = 0x4000080c; -ets_efuse_get_read_register_address = 0x40000810; -ets_efuse_get_key_purpose = 0x40000814; -ets_efuse_key_block_unused = 0x40000818; -ets_efuse_find_unused_key_block = 0x4000081c; -ets_efuse_rs_calculate = 0x40000820; -ets_efuse_count_unused_key_blocks = 0x40000824; -ets_efuse_secure_boot_enabled = 0x40000828; -ets_efuse_secure_boot_aggressive_revoke_enabled = 0x4000082c; -ets_efuse_cache_encryption_enabled = 0x40000830; -ets_efuse_download_modes_disabled = 0x40000834; -ets_efuse_find_purpose = 0x40000838; -ets_efuse_force_send_resume = 0x4000083c; -ets_efuse_get_flash_delay_us = 0x40000840; -ets_efuse_get_mac = 0x40000844; -ets_efuse_get_uart_print_control = 0x40000848; -ets_efuse_direct_boot_mode_disabled = 0x4000084c; -ets_efuse_security_download_modes_enabled = 0x40000850; -ets_efuse_set_timing = 0x40000854; -ets_efuse_jtag_disabled = 0x40000858; -ets_efuse_usb_print_is_disabled = 0x4000085c; -ets_efuse_usb_download_mode_disabled = 0x40000860; -ets_efuse_usb_device_disabled = 0x40000864; -ets_efuse_secure_boot_fast_wake_enabled = 0x40000868; - - -/*************************************** - Group secureboot - ***************************************/ - -/* Functions */ -ets_emsa_pss_verify = 0x4000086c; -ets_rsa_pss_verify = 0x40000870; -ets_secure_boot_verify_bootloader_with_keys = 0x40000874; -ets_secure_boot_verify_signature = 0x40000878; -ets_secure_boot_read_key_digests = 0x4000087c; -ets_secure_boot_revoke_public_key_digest = 0x40000880; - - -/*************************************** - Group usb_device_uart - ***************************************/ - -/* Functions */ -usb_serial_device_rx_one_char = 0x40000a80; -usb_serial_device_rx_one_char_block = 0x40000a84; -usb_serial_device_tx_flush = 0x40000a88; -usb_serial_device_tx_one_char = 0x40000a8c; - - -/*************************************** - Group lldesc - ***************************************/ - -/* Functions */ -lldesc_build_chain = 0x40000a90; - - -/*************************************** - Group sip - ***************************************/ - -/* Functions */ -sip_after_tx_complete = 0x40000a94; -sip_alloc_to_host_evt = 0x40000a98; -sip_download_begin = 0x40000a9c; -sip_get_ptr = 0x40000aa0; -sip_get_state = 0x40000aa4; -sip_init_attach = 0x40000aa8; -sip_install_rx_ctrl_cb = 0x40000aac; -sip_install_rx_data_cb = 0x40000ab0; -sip_is_active = 0x40000ab4; -sip_post_init = 0x40000ab8; -sip_reclaim_from_host_cmd = 0x40000abc; -sip_reclaim_tx_data_pkt = 0x40000ac0; -sip_send = 0x40000ac4; -sip_to_host_chain_append = 0x40000ac8; -sip_to_host_evt_send_done = 0x40000acc; - - -/*************************************** - Group slc - ***************************************/ - -/* Functions */ -slc_add_credits = 0x40000ad0; -slc_enable = 0x40000ad4; -slc_from_host_chain_fetch = 0x40000ad8; -slc_from_host_chain_recycle = 0x40000adc; -slc_has_pkt_to_host = 0x40000ae0; -slc_init_attach = 0x40000ae4; -slc_init_credit = 0x40000ae8; -slc_reattach = 0x40000aec; -slc_send_to_host_chain = 0x40000af0; -slc_set_host_io_max_window = 0x40000af4; -slc_to_host_chain_recycle = 0x40000af8; diff --git a/tools/esptool_py/flasher_stub/ld/rom_32c6_beta.ld b/tools/esptool_py/flasher_stub/ld/rom_32c6_beta.ld deleted file mode 100755 index ad801af612..0000000000 --- a/tools/esptool_py/flasher_stub/ld/rom_32c6_beta.ld +++ /dev/null @@ -1,1951 +0,0 @@ -/* ROM function interface esp32c6.rom.ld for esp32c6 - * - * - * Generated from ./interface-esp32c6.yml md5sum e7196719ebc959e6dd2f61dec2db53e0 - * - * Compatible with ROM where ECO version equal or greater to 0. - * - * THIS FILE WAS AUTOMATICALLY GENERATED. DO NOT EDIT. - */ - - -PROVIDE ( SPIWrite = esp_rom_spiflash_write); -PROVIDE ( SPI_read_status_high = esp_rom_spiflash_read_statushigh); -PROVIDE ( SPI_write_status = esp_rom_spiflash_write_status); -PROVIDE ( SPIRead = esp_rom_spiflash_read); -PROVIDE ( SPIParamCfg = esp_rom_spiflash_config_param); -PROVIDE ( SPIEraseChip = esp_rom_spiflash_erase_chip); -PROVIDE ( SPIEraseSector = esp_rom_spiflash_erase_sector); -PROVIDE ( SPIEraseBlock = esp_rom_spiflash_erase_block); -PROVIDE ( SPI_Write_Encrypt_Enable = esp_rom_spiflash_write_encrypted_enable); -PROVIDE ( SPI_Write_Encrypt_Disable = esp_rom_spiflash_write_encrypted_disable); -PROVIDE ( SPI_Encrypt_Write = esp_rom_spiflash_write_encrypted); - - -/*************************************** - Group common - ***************************************/ - -/* Functions */ -rtc_get_reset_reason = 0x40000018; -analog_super_wdt_reset_happened = 0x4000001c; -jtag_cpu_reset_happened = 0x40000020; -rtc_get_wakeup_cause = 0x40000024; -rtc_select_apb_bridge = 0x40000028; -rtc_unhold_all_pads = 0x4000002c; -ets_is_print_boot = 0x40000030; -ets_printf = 0x40000034; -ets_install_putc1 = 0x40000038; -ets_install_uart_printf = 0x4000003c; -ets_install_putc2 = 0x40000040; -PROVIDE( ets_delay_us = 0x40000044 ); -ets_get_stack_info = 0x40000048; -ets_install_lock = 0x4000004c; -ets_backup_dma_copy = 0x40000050; -ets_apb_backup_init_lock_func = 0x40000054; -UartRxString = 0x40000058; -uart_tx_one_char = 0x4000005c; -uart_tx_one_char2 = 0x40000060; -uart_rx_one_char = 0x40000064; -uart_rx_one_char_block = 0x40000068; -uart_rx_readbuff = 0x4000006c; -uartAttach = 0x40000070; -uart_tx_flush = 0x40000074; -uart_tx_wait_idle = 0x40000078; -uart_div_modify = 0x4000007c; -multofup = 0x40000080; -software_reset = 0x40000084; -software_reset_cpu = 0x40000088; -assist_debug_clock_enable = 0x4000008c; -assist_debug_record_enable = 0x40000090; -clear_super_wdt_reset_flag = 0x40000094; -disable_default_watchdog = 0x40000098; -esp_rom_set_rtc_wake_addr = 0x4000009c; -esp_rom_get_rtc_wake_addr = 0x400000a0; -send_packet = 0x400000a4; -recv_packet = 0x400000a8; -GetUartDevice = 0x400000ac; -GetSecurityInfoProc = 0x4004b172; -UartDwnLdProc = 0x400000b0; -Uart_Init = 0x400000b4; -ets_set_user_start = 0x400000b8; -/* Data (.data, .bss, .rodata) */ -ets_rom_layout_p = 0x3ff1fffc; -ets_ops_table_ptr = 0x3fcdfffc; - - -/*************************************** - Group miniz - ***************************************/ - -/* Functions */ -mz_adler32 = 0x400000bc; -mz_crc32 = 0x400000c0; -mz_free = 0x400000c4; -tdefl_compress = 0x400000c8; -tdefl_compress_buffer = 0x400000cc; -tdefl_compress_mem_to_heap = 0x400000d0; -tdefl_compress_mem_to_mem = 0x400000d4; -tdefl_compress_mem_to_output = 0x400000d8; -tdefl_get_adler32 = 0x400000dc; -tdefl_get_prev_return_status = 0x400000e0; -tdefl_init = 0x400000e4; -tdefl_write_image_to_png_file_in_memory = 0x400000e8; -tdefl_write_image_to_png_file_in_memory_ex = 0x400000ec; -tinfl_decompress = 0x400000f0; -tinfl_decompress_mem_to_callback = 0x400000f4; -tinfl_decompress_mem_to_heap = 0x400000f8; -tinfl_decompress_mem_to_mem = 0x400000fc; - - -/*************************************** - Group tjpgd - ***************************************/ - -/* Functions */ -jd_prepare = 0x40000100; -jd_decomp = 0x40000104; - - -/*************************************** - Group spiflash_legacy - ***************************************/ - -/* Functions */ -PROVIDE( esp_rom_spiflash_wait_idle = 0x40000108 ); -PROVIDE( esp_rom_spiflash_write_encrypted = 0x4000010c ); -PROVIDE( esp_rom_spiflash_write_encrypted_dest = 0x40000110 ); -PROVIDE( esp_rom_spiflash_write_encrypted_enable = 0x40000114 ); -PROVIDE( esp_rom_spiflash_write_encrypted_disable = 0x40000118 ); -PROVIDE( esp_rom_spiflash_erase_chip = 0x4000011c ); -PROVIDE( esp_rom_spiflash_erase_block = 0x40000120 ); -PROVIDE( esp_rom_spiflash_erase_sector = 0x40000124 ); -PROVIDE( esp_rom_spiflash_write = 0x40000128 ); -PROVIDE( esp_rom_spiflash_read = 0x4000012c ); -PROVIDE( esp_rom_spiflash_config_param = 0x40000130 ); -PROVIDE( esp_rom_spiflash_read_user_cmd = 0x40000134 ); -PROVIDE( esp_rom_spiflash_select_qio_pins = 0x40000138 ); -PROVIDE( esp_rom_spiflash_unlock = 0x4000013c ); -PROVIDE( esp_rom_spi_flash_auto_sus_res = 0x40000140 ); -PROVIDE( esp_rom_spi_flash_send_resume = 0x40000144 ); -PROVIDE( esp_rom_spi_flash_update_id = 0x40000148 ); -PROVIDE( esp_rom_spiflash_config_clk = 0x4000014c ); -PROVIDE( esp_rom_spiflash_config_readmode = 0x40000150 ); -PROVIDE( esp_rom_spiflash_read_status = 0x40000154 ); -PROVIDE( esp_rom_spiflash_read_statushigh = 0x40000158 ); -PROVIDE( esp_rom_spiflash_write_status = 0x4000015c ); -PROVIDE( spi_flash_attach = 0x40000160 ); -PROVIDE( spi_flash_get_chip_size = 0x40000164 ); -PROVIDE( spi_flash_guard_set = 0x40000168 ); -PROVIDE( spi_flash_guard_get = 0x4000016c ); -PROVIDE( spi_flash_write_config_set = 0x40000170 ); -PROVIDE( spi_flash_write_config_get = 0x40000174 ); -PROVIDE( spi_flash_safe_write_address_func_set = 0x40000178 ); -PROVIDE( spi_flash_unlock = 0x4000017c ); -PROVIDE( spi_flash_erase_range = 0x40000180 ); -PROVIDE( spi_flash_erase_sector = 0x40000184 ); -PROVIDE( spi_flash_write = 0x40000188 ); -PROVIDE( spi_flash_read = 0x4000018c ); -PROVIDE( spi_flash_write_encrypted = 0x40000190 ); -PROVIDE( spi_flash_read_encrypted = 0x40000194 ); -PROVIDE( spi_flash_mmap_os_func_set = 0x40000198 ); -PROVIDE( spi_flash_mmap_page_num_init = 0x4000019c ); -PROVIDE( spi_flash_mmap = 0x400001a0 ); -PROVIDE( spi_flash_mmap_pages = 0x400001a4 ); -PROVIDE( spi_flash_munmap = 0x400001a8 ); -PROVIDE( spi_flash_mmap_dump = 0x400001ac ); -PROVIDE( spi_flash_check_and_flush_cache = 0x400001b0 ); -PROVIDE( spi_flash_mmap_get_free_pages = 0x400001b4 ); -PROVIDE( spi_flash_cache2phys = 0x400001b8 ); -PROVIDE( spi_flash_phys2cache = 0x400001bc ); -PROVIDE( spi_flash_disable_cache = 0x400001c0 ); -PROVIDE( spi_flash_restore_cache = 0x400001c4 ); -PROVIDE( spi_flash_cache_enabled = 0x400001c8 ); -PROVIDE( spi_flash_enable_cache = 0x400001cc ); -PROVIDE( spi_cache_mode_switch = 0x400001d0 ); -PROVIDE( spi_common_set_dummy_output = 0x400001d4 ); -PROVIDE( spi_common_set_flash_cs_timing = 0x400001d8 ); -PROVIDE( esp_enable_cache_flash_wrap = 0x400001dc ); -PROVIDE( SPIEraseArea = 0x400001e0 ); -PROVIDE( SPILock = 0x400001e4 ); -PROVIDE( SPIMasterReadModeCnfig = 0x400001e8 ); -PROVIDE( SPI_Common_Command = 0x400001ec ); -PROVIDE( SPI_WakeUp = 0x400001f0 ); -PROVIDE( SPI_block_erase = 0x400001f4 ); -PROVIDE( SPI_chip_erase = 0x400001f8 ); -PROVIDE( SPI_init = 0x400001fc ); -PROVIDE( SPI_page_program = 0x40000200 ); -PROVIDE( SPI_read_data = 0x40000204 ); -PROVIDE( SPI_sector_erase = 0x40000208 ); -PROVIDE( SPI_write_enable = 0x4000020c ); -PROVIDE( SelectSpiFunction = 0x40000210 ); -PROVIDE( SetSpiDrvs = 0x40000214 ); -PROVIDE( Wait_SPI_Idle = 0x40000218 ); -PROVIDE( spi_dummy_len_fix = 0x4000021c ); -PROVIDE( Disable_QMode = 0x40000220 ); -PROVIDE( Enable_QMode = 0x40000224 ); -/* Data (.data, .bss, .rodata) */ -PROVIDE( rom_spiflash_legacy_funcs = 0x3fcdfff4 ); -PROVIDE( rom_spiflash_legacy_data = 0x3fcdfff0 ); -PROVIDE( g_flash_guard_ops = 0x3fcdfff8 ); - - -/*************************************** - Group spi_flash_hal - ***************************************/ - -/* Functions */ -PROVIDE( spi_flash_hal_poll_cmd_done = 0x40000228 ); -PROVIDE( spi_flash_hal_device_config = 0x4000022c ); -PROVIDE( spi_flash_hal_configure_host_io_mode = 0x40000230 ); -PROVIDE( spi_flash_hal_common_command = 0x40000234 ); -PROVIDE( spi_flash_hal_read = 0x40000238 ); -PROVIDE( spi_flash_hal_erase_chip = 0x4000023c ); -PROVIDE( spi_flash_hal_erase_sector = 0x40000240 ); -PROVIDE( spi_flash_hal_erase_block = 0x40000244 ); -PROVIDE( spi_flash_hal_program_page = 0x40000248 ); -PROVIDE( spi_flash_hal_set_write_protect = 0x4000024c ); -PROVIDE( spi_flash_hal_host_idle = 0x40000250 ); - - -/*************************************** - Group spi_flash_chips - ***************************************/ - -/* Functions */ -PROVIDE( spi_flash_chip_generic_probe = 0x40000254 ); -PROVIDE( spi_flash_chip_generic_detect_size = 0x40000258 ); -PROVIDE( spi_flash_chip_generic_write = 0x4000025c ); -PROVIDE( spi_flash_chip_generic_write_encrypted = 0x40000260 ); -PROVIDE( spi_flash_chip_generic_set_write_protect = 0x40000264 ); -PROVIDE( spi_flash_common_write_status_16b_wrsr = 0x40000268 ); -PROVIDE( spi_flash_chip_generic_reset = 0x4000026c ); -PROVIDE( spi_flash_chip_generic_erase_chip = 0x40000270 ); -PROVIDE( spi_flash_chip_generic_erase_sector = 0x40000274 ); -PROVIDE( spi_flash_chip_generic_erase_block = 0x40000278 ); -PROVIDE( spi_flash_chip_generic_page_program = 0x4000027c ); -PROVIDE( spi_flash_chip_generic_get_write_protect = 0x40000280 ); -PROVIDE( spi_flash_common_read_status_16b_rdsr_rdsr2 = 0x40000284 ); -PROVIDE( spi_flash_chip_generic_read_reg = 0x40000288 ); -PROVIDE( spi_flash_chip_generic_yield = 0x4000028c ); -PROVIDE( spi_flash_generic_wait_host_idle = 0x40000290 ); -PROVIDE( spi_flash_chip_generic_wait_idle = 0x40000294 ); -PROVIDE( spi_flash_chip_generic_config_host_io_mode = 0x40000298 ); -PROVIDE( spi_flash_chip_generic_read = 0x4000029c ); -PROVIDE( spi_flash_common_read_status_8b_rdsr2 = 0x400002a0 ); -PROVIDE( spi_flash_chip_generic_get_io_mode = 0x400002a4 ); -PROVIDE( spi_flash_common_read_status_8b_rdsr = 0x400002a8 ); -PROVIDE( spi_flash_common_write_status_8b_wrsr = 0x400002ac ); -PROVIDE( spi_flash_common_write_status_8b_wrsr2 = 0x400002b0 ); -PROVIDE( spi_flash_common_set_io_mode = 0x400002b4 ); -PROVIDE( spi_flash_chip_generic_set_io_mode = 0x400002b8 ); -PROVIDE( spi_flash_chip_gd_get_io_mode = 0x400002bc ); -PROVIDE( spi_flash_chip_gd_probe = 0x400002c0 ); -PROVIDE( spi_flash_chip_gd_set_io_mode = 0x400002c4 ); -/* Data (.data, .bss, .rodata) */ -PROVIDE( spi_flash_chip_generic_config_data = 0x3fcdffec ); - - -/*************************************** - Group memspi_host - ***************************************/ - -/* Functions */ -PROVIDE( memspi_host_read_id_hs = 0x400002c8 ); -PROVIDE( memspi_host_read_status_hs = 0x400002cc ); -PROVIDE( memspi_host_flush_cache = 0x400002d0 ); -PROVIDE( memspi_host_erase_chip = 0x400002d4 ); -PROVIDE( memspi_host_erase_sector = 0x400002d8 ); -PROVIDE( memspi_host_erase_block = 0x400002dc ); -PROVIDE( memspi_host_program_page = 0x400002e0 ); -PROVIDE( memspi_host_read = 0x400002e4 ); -PROVIDE( memspi_host_set_write_protect = 0x400002e8 ); -PROVIDE( memspi_host_set_max_read_len = 0x400002ec ); -PROVIDE( memspi_host_read_data_slicer = 0x400002f0 ); -PROVIDE( memspi_host_write_data_slicer = 0x400002f4 ); - - -/*************************************** - Group esp_flash - ***************************************/ - -/* Functions */ -PROVIDE( esp_flash_chip_driver_initialized = 0x400002f8 ); -PROVIDE( esp_flash_read_id = 0x400002fc ); -PROVIDE( esp_flash_get_size = 0x40000300 ); -PROVIDE( esp_flash_erase_chip = 0x40000304 ); -PROVIDE( esp_flash_erase_region = 0x40000308 ); -PROVIDE( esp_flash_get_chip_write_protect = 0x4000030c ); -PROVIDE( esp_flash_set_chip_write_protect = 0x40000310 ); -PROVIDE( esp_flash_get_protectable_regions = 0x40000314 ); -PROVIDE( esp_flash_get_protected_region = 0x40000318 ); -PROVIDE( esp_flash_set_protected_region = 0x4000031c ); -PROVIDE( esp_flash_read = 0x40000320 ); -PROVIDE( esp_flash_write = 0x40000324 ); -PROVIDE( esp_flash_write_encrypted = 0x40000328 ); -PROVIDE( esp_flash_read_encrypted = 0x4000032c ); -PROVIDE( esp_flash_get_io_mode = 0x40000330 ); -PROVIDE( esp_flash_set_io_mode = 0x40000334 ); -PROVIDE( spi_flash_boot_attach = 0x40000338 ); -PROVIDE( spi_flash_dump_counters = 0x4000033c ); -PROVIDE( spi_flash_get_counters = 0x40000340 ); -PROVIDE( spi_flash_op_counters_config = 0x40000344 ); -PROVIDE( spi_flash_reset_counters = 0x40000348 ); -/* Data (.data, .bss, .rodata) */ -PROVIDE( esp_flash_default_chip = 0x3fcdffe8 ); -PROVIDE( esp_flash_api_funcs = 0x3fcdffe4 ); - - -/*************************************** - Group cache - ***************************************/ - -/* Functions */ -PROVIDE( Cache_Get_ICache_Line_Size = 0x400004ac ); -PROVIDE( Cache_Get_Mode = 0x400004b0 ); -PROVIDE( Cache_Address_Through_IBus = 0x400004b4 ); -PROVIDE( Cache_Address_Through_DBus = 0x400004b8 ); -PROVIDE( Cache_Set_Default_Mode = 0x400004bc ); -PROVIDE( Cache_Enable_Defalut_ICache_Mode = 0x400004c0 ); -PROVIDE( ROM_Boot_Cache_Init = 0x400004c4 ); -PROVIDE( Cache_Invalidate_ICache_Items = 0x400004c8 ); -PROVIDE( Cache_Op_Addr = 0x400004cc ); -PROVIDE( Cache_Invalidate_Addr = 0x400004d0 ); -PROVIDE( Cache_Invalidate_ICache_All = 0x400004d4 ); -PROVIDE( Cache_Mask_All = 0x400004d8 ); -PROVIDE( Cache_UnMask_Dram0 = 0x400004dc ); -PROVIDE( Cache_Suspend_ICache_Autoload = 0x400004e0 ); -PROVIDE( Cache_Resume_ICache_Autoload = 0x400004e4 ); -PROVIDE( Cache_Start_ICache_Preload = 0x400004e8 ); -PROVIDE( Cache_ICache_Preload_Done = 0x400004ec ); -PROVIDE( Cache_End_ICache_Preload = 0x400004f0 ); -PROVIDE( Cache_Config_ICache_Autoload = 0x400004f4 ); -PROVIDE( Cache_Enable_ICache_Autoload = 0x400004f8 ); -PROVIDE( Cache_Disable_ICache_Autoload = 0x400004fc ); -PROVIDE( Cache_Enable_ICache_PreLock = 0x40000500 ); -PROVIDE( Cache_Disable_ICache_PreLock = 0x40000504 ); -PROVIDE( Cache_Lock_ICache_Items = 0x40000508 ); -PROVIDE( Cache_Unlock_ICache_Items = 0x4000050c ); -PROVIDE( Cache_Lock_Addr = 0x40000510 ); -PROVIDE( Cache_Unlock_Addr = 0x40000514 ); -PROVIDE( Cache_Disable_ICache = 0x40000518 ); -PROVIDE( Cache_Enable_ICache = 0x4000051c ); -PROVIDE( Cache_Suspend_ICache = 0x40000520 ); -PROVIDE( Cache_Resume_ICache = 0x40000524 ); -PROVIDE( Cache_Freeze_ICache_Enable = 0x40000528 ); -PROVIDE( Cache_Freeze_ICache_Disable = 0x4000052c ); -PROVIDE( Cache_Pms_Lock = 0x40000530 ); -PROVIDE( Cache_Ibus_Pms_Set_Addr = 0x40000534 ); -PROVIDE( Cache_Ibus_Pms_Set_Attr = 0x40000538 ); -PROVIDE( Cache_Dbus_Pms_Set_Addr = 0x4000053c ); -PROVIDE( Cache_Dbus_Pms_Set_Attr = 0x40000540 ); -PROVIDE( Cache_Set_IDROM_MMU_Size = 0x40000544 ); -PROVIDE( Cache_Get_IROM_MMU_End = 0x40000548 ); -PROVIDE( Cache_Get_DROM_MMU_End = 0x4000054c ); -PROVIDE( Cache_Owner_Init = 0x40000550 ); -PROVIDE( Cache_Occupy_ICache_MEMORY = 0x40000554 ); -PROVIDE( Cache_MMU_Init = 0x40000558 ); -PROVIDE( Cache_Ibus_MMU_Set = 0x4000055c ); -PROVIDE( Cache_Dbus_MMU_Set = 0x40000560 ); -PROVIDE( Cache_Count_Flash_Pages = 0x40000564 ); -PROVIDE( Cache_Travel_Tag_Memory = 0x40000568 ); -PROVIDE( Cache_Get_Virtual_Addr = 0x4000056c ); -PROVIDE( Cache_Get_Memory_BaseAddr = 0x40000570 ); -PROVIDE( Cache_Get_Memory_Addr = 0x40000574 ); -PROVIDE( Cache_Get_Memory_value = 0x40000578 ); -/* Data (.data, .bss, .rodata) */ -PROVIDE( rom_cache_op_cb = 0x3fcdffd8 ); -PROVIDE( rom_cache_internal_table_ptr = 0x3fcdffd4 ); - - -/*************************************** - Group clock - ***************************************/ - -/* Functions */ -ets_get_apb_freq = 0x4000057c; -ets_get_cpu_frequency = 0x40000580; -ets_update_cpu_frequency = 0x40000584; -ets_get_printf_channel = 0x40000588; -ets_get_xtal_div = 0x4000058c; -ets_set_xtal_div = 0x40000590; -ets_get_xtal_freq = 0x40000594; - - -/*************************************** - Group gpio - ***************************************/ - -/* Functions */ -gpio_input_get = 0x40000598; -gpio_matrix_in = 0x4000059c; -gpio_matrix_out = 0x400005a0; -gpio_output_disable = 0x400005a4; -gpio_output_enable = 0x400005a8; -gpio_output_set = 0x400005ac; -gpio_pad_hold = 0x400005b0; -gpio_pad_input_disable = 0x400005b4; -gpio_pad_input_enable = 0x400005b8; -gpio_pad_pulldown = 0x400005bc; -gpio_pad_pullup = 0x400005c0; -gpio_pad_select_gpio = 0x400005c4; -gpio_pad_set_drv = 0x400005c8; -gpio_pad_unhold = 0x400005cc; -gpio_pin_wakeup_disable = 0x400005d0; -gpio_pin_wakeup_enable = 0x400005d4; -gpio_bypass_matrix_in = 0x400005d8; - - -/*************************************** - Group interrupts - ***************************************/ - -/* Functions */ -esprv_intc_int_set_priority = 0x400005dc; -esprv_intc_int_set_threshold = 0x400005e0; -esprv_intc_int_enable = 0x400005e4; -esprv_intc_int_disable = 0x400005e8; -esprv_intc_int_set_type = 0x400005ec; -intr_matrix_set = 0x400005f0; -ets_intr_lock = 0x400005f4; -ets_intr_unlock = 0x400005f8; -PROVIDE( intr_handler_set = 0x400005fc ); -ets_isr_attach = 0x40000600; -ets_isr_mask = 0x40000604; -ets_isr_unmask = 0x40000608; - - -/*************************************** - Group crypto - ***************************************/ - -/* Functions */ -md5_vector = 0x4000060c; -MD5Init = 0x40000610; -MD5Update = 0x40000614; -MD5Final = 0x40000618; -hmac_md5_vector = 0x4000061c; -hmac_md5 = 0x40000620; -crc32_le = 0x40000624; -crc32_be = 0x40000628; -crc16_le = 0x4000062c; -crc16_be = 0x40000630; -crc8_le = 0x40000634; -crc8_be = 0x40000638; -esp_crc8 = 0x4000063c; -ets_sha_enable = 0x40000640; -ets_sha_disable = 0x40000644; -ets_sha_get_state = 0x40000648; -ets_sha_init = 0x4000064c; -ets_sha_process = 0x40000650; -ets_sha_starts = 0x40000654; -ets_sha_update = 0x40000658; -ets_sha_finish = 0x4000065c; -ets_sha_clone = 0x40000660; -ets_hmac_enable = 0x40000664; -ets_hmac_disable = 0x40000668; -ets_hmac_calculate_message = 0x4000066c; -ets_hmac_calculate_downstream = 0x40000670; -ets_hmac_invalidate_downstream = 0x40000674; -ets_jtag_enable_temporarily = 0x40000678; -ets_aes_enable = 0x4000067c; -ets_aes_disable = 0x40000680; -ets_aes_setkey = 0x40000684; -ets_aes_block = 0x40000688; -ets_bigint_enable = 0x4000068c; -ets_bigint_disable = 0x40000690; -ets_bigint_multiply = 0x40000694; -ets_bigint_modmult = 0x40000698; -ets_bigint_modexp = 0x4000069c; -ets_bigint_wait_finish = 0x400006a0; -ets_bigint_getz = 0x400006a4; -ets_ds_enable = 0x400006a8; -ets_ds_disable = 0x400006ac; -ets_ds_start_sign = 0x400006b0; -ets_ds_is_busy = 0x400006b4; -ets_ds_finish_sign = 0x400006b8; -ets_ds_encrypt_params = 0x400006bc; -ets_aes_setkey_dec = 0x400006c0; -ets_aes_setkey_enc = 0x400006c4; -ets_mgf1_sha256 = 0x400006c8; - - -/*************************************** - Group efuse - ***************************************/ - -/* Functions */ -ets_efuse_read = 0x400006cc; -ets_efuse_program = 0x400006d0; -ets_efuse_clear_program_registers = 0x400006d4; -ets_efuse_write_key = 0x400006d8; -ets_efuse_get_read_register_address = 0x400006dc; -ets_efuse_get_key_purpose = 0x400006e0; -ets_efuse_key_block_unused = 0x400006e4; -ets_efuse_find_unused_key_block = 0x400006e8; -ets_efuse_rs_calculate = 0x400006ec; -ets_efuse_count_unused_key_blocks = 0x400006f0; -ets_efuse_secure_boot_enabled = 0x400006f4; -ets_efuse_secure_boot_aggressive_revoke_enabled = 0x400006f8; -ets_efuse_cache_encryption_enabled = 0x400006fc; -ets_efuse_download_modes_disabled = 0x40000700; -ets_efuse_find_purpose = 0x40000704; -ets_efuse_flash_opi_5pads_power_sel_vddspi = 0x40000708; -ets_efuse_force_send_resume = 0x4000070c; -ets_efuse_get_flash_delay_us = 0x40000710; -ets_efuse_get_mac = 0x40000714; -ets_efuse_get_spiconfig = 0x40000718; -ets_efuse_usb_print_is_disabled = 0x4000071c; -ets_efuse_get_uart_print_channel = 0x40000720; -ets_efuse_get_uart_print_control = 0x40000724; -ets_efuse_get_wp_pad = 0x40000728; -ets_efuse_legacy_spi_boot_mode_disabled = 0x4000072c; -ets_efuse_security_download_modes_enabled = 0x40000730; -ets_efuse_set_timing = 0x40000734; -ets_efuse_jtag_disabled = 0x40000738; -ets_efuse_usb_download_mode_disabled = 0x4000073c; -ets_efuse_usb_module_disabled = 0x40000740; -ets_efuse_usb_device_disabled = 0x40000744; - - -/*************************************** - Group secureboot - ***************************************/ - -/* Functions */ -ets_emsa_pss_verify = 0x40000748; -ets_rsa_pss_verify = 0x4000074c; -ets_secure_boot_verify_bootloader_with_keys = 0x40000750; -ets_secure_boot_verify_signature = 0x40000754; -ets_secure_boot_read_key_digests = 0x40000758; -ets_secure_boot_revoke_public_key_digest = 0x4000075c; - - -/*************************************** - Group usb_uart - ***************************************/ - -/* Functions */ -PROVIDE( usb_uart_rx_one_char = 0x400008c8 ); -PROVIDE( usb_uart_rx_one_char_block = 0x400008cc ); -PROVIDE( usb_uart_tx_flush = 0x400008d0 ); -PROVIDE( usb_uart_tx_one_char = 0x400008d4 ); -/* Data (.data, .bss, .rodata) */ -PROVIDE( g_uart_print = 0x3fcdffd1 ); -PROVIDE( g_usb_print = 0x3fcdffd0 ); - - -/*************************************** - Group bluetooth - ***************************************/ - -/* Functions */ -bt_rf_coex_get_dft_cfg = 0x400008d8; -bt_rf_coex_hooks_p_set = 0x400008dc; -btdm_con_maxevtime_cal_impl = 0x400008e0; -btdm_controller_get_compile_version_impl = 0x400008e4; -btdm_controller_rom_data_init = 0x400008e8; -btdm_dis_privacy_err_report_impl = 0x400008ec; -btdm_disable_adv_delay_impl = 0x400008f0; -btdm_enable_scan_continue_impl = 0x400008f4; -btdm_enable_scan_forever_impl = 0x400008f8; -btdm_get_power_state_impl = 0x400008fc; -btdm_get_prevent_sleep_flag_impl = 0x40000900; -btdm_power_state_active_impl = 0x40000904; -btdm_switch_phy_coded_impl = 0x40000908; -hci_acl_data_handler = 0x4000090c; -hci_disconnect_cmd_handler = 0x40000910; -hci_le_con_upd_cmd_handler = 0x40000914; -hci_le_ltk_req_neg_reply_cmd_handler = 0x40000918; -hci_le_ltk_req_reply_cmd_handler = 0x4000091c; -hci_le_rd_chnl_map_cmd_handler = 0x40000920; -hci_le_rd_phy_cmd_handler = 0x40000924; -hci_le_rd_rem_feats_cmd_handler = 0x40000928; -hci_le_rem_con_param_req_neg_reply_cmd_handler = 0x4000092c; -hci_le_rem_con_param_req_reply_cmd_handler = 0x40000930; -hci_le_set_data_len_cmd_handler = 0x40000934; -hci_le_set_phy_cmd_handler = 0x40000938; -hci_le_start_enc_cmd_handler = 0x4000093c; -hci_rd_auth_payl_to_cmd_handler = 0x40000940; -hci_rd_rem_ver_info_cmd_handler = 0x40000944; -hci_rd_rssi_cmd_handler = 0x40000948; -hci_rd_tx_pwr_lvl_cmd_handler = 0x4000094c; -hci_vs_set_pref_slave_evt_dur_cmd_handler = 0x40000950; -hci_vs_set_pref_slave_latency_cmd_handler = 0x40000954; -hci_wr_auth_payl_to_cmd_handler = 0x40000958; -ll_channel_map_ind_handler = 0x4000095c; -ll_connection_param_req_handler = 0x40000960; -ll_connection_param_rsp_handler = 0x40000964; -ll_connection_update_ind_handler = 0x40000968; -ll_enc_req_handler = 0x4000096c; -ll_enc_rsp_handler = 0x40000970; -ll_feature_req_handler = 0x40000974; -ll_feature_rsp_handler = 0x40000978; -ll_length_req_handler = 0x4000097c; -ll_length_rsp_handler = 0x40000980; -ll_min_used_channels_ind_handler = 0x40000984; -ll_pause_enc_req_handler = 0x40000988; -ll_pause_enc_rsp_handler = 0x4000098c; -ll_phy_req_handler = 0x40000990; -ll_phy_rsp_handler = 0x40000994; -ll_phy_update_ind_handler = 0x40000998; -ll_ping_req_handler = 0x4000099c; -ll_ping_rsp_handler = 0x400009a0; -ll_slave_feature_req_handler = 0x400009a4; -ll_start_enc_req_handler = 0x400009a8; -ll_start_enc_rsp_handler = 0x400009ac; -ll_terminate_ind_handler = 0x400009b0; -ll_version_ind_handler = 0x400009b4; -llc_auth_payl_nearly_to_handler = 0x400009b8; -llc_auth_payl_real_to_handler = 0x400009bc; -llc_encrypt_ind_handler = 0x400009c0; -llc_hci_command_handler_wrapper = 0x400009c4; -llc_ll_connection_param_req_pdu_send = 0x400009c8; -llc_ll_connection_param_rsp_pdu_send = 0x400009cc; -llc_ll_connection_update_ind_pdu_send = 0x400009d0; -llc_ll_enc_req_pdu_send = 0x400009d4; -llc_ll_enc_rsp_pdu_send = 0x400009d8; -llc_ll_feature_req_pdu_send = 0x400009dc; -llc_ll_feature_rsp_pdu_send = 0x400009e0; -llc_ll_length_req_pdu_send = 0x400009e4; -llc_ll_length_rsp_pdu_send = 0x400009e8; -llc_ll_pause_enc_req_pdu_send = 0x400009ec; -llc_ll_pause_enc_rsp_pdu_send = 0x400009f0; -llc_ll_phy_req_pdu_send = 0x400009f4; -llc_ll_phy_rsp_pdu_send = 0x400009f8; -llc_ll_ping_req_pdu_send = 0x400009fc; -llc_ll_ping_rsp_pdu_send = 0x40000a00; -llc_ll_start_enc_req_pdu_send = 0x40000a04; -llc_ll_start_enc_rsp_pdu_send = 0x40000a08; -llc_ll_terminate_ind_pdu_send = 0x40000a0c; -llc_ll_unknown_rsp_pdu_send = 0x40000a10; -llc_llcp_ch_map_update_ind_pdu_send = 0x40000a14; -llc_llcp_phy_upd_ind_pdu_send = 0x40000a18; -llc_llcp_version_ind_pdu_send = 0x40000a1c; -llc_op_ch_map_upd_ind_handler = 0x40000a20; -llc_op_con_upd_ind_handler = 0x40000a24; -llc_op_disconnect_ind_handler = 0x40000a28; -llc_op_dl_upd_ind_handler = 0x40000a2c; -llc_op_encrypt_ind_handler = 0x40000a30; -llc_op_feats_exch_ind_handler = 0x40000a34; -llc_op_le_ping_ind_handler = 0x40000a38; -llc_op_phy_upd_ind_handler = 0x40000a3c; -llc_op_ver_exch_ind_handler = 0x40000a40; -llc_stopped_ind_handler = 0x40000a44; -lld_acl_rx_ind_handler = 0x40000a48; -lld_acl_tx_cfm_handler = 0x40000a4c; -lld_adv_end_ind_handler = 0x40000a50; -lld_adv_rep_ind_handler = 0x40000a54; -lld_ch_map_upd_cfm_handler = 0x40000a58; -lld_con_estab_ind_handler = 0x40000a5c; -lld_con_evt_sd_evt_time_set = 0x40000a60; -lld_con_offset_upd_ind_handler = 0x40000a64; -lld_con_param_upd_cfm_handler = 0x40000a68; -lld_disc_ind_handler = 0x40000a6c; -lld_init_end_ind_handler = 0x40000a70; -lld_llcp_rx_ind_handler_wrapper = 0x40000a74; -lld_llcp_tx_cfm_handler = 0x40000a78; -lld_per_adv_end_ind_handler = 0x40000a7c; -lld_per_adv_rep_ind_handler = 0x40000a80; -lld_per_adv_rx_end_ind_handler = 0x40000a84; -lld_phy_coded_500k_get = 0x40000a88; -lld_phy_upd_cfm_handler = 0x40000a8c; -lld_scan_end_ind_handler = 0x40000a90; -lld_scan_req_ind_handler = 0x40000a94; -lld_sync_start_req_handler = 0x40000a98; -lld_test_end_ind_handler = 0x40000a9c; -lld_update_rxbuf_handler = 0x40000aa0; -llm_ch_map_update_ind_handler = 0x40000aa4; -llm_hci_command_handler_wrapper = 0x40000aa8; -llm_scan_period_to_handler = 0x40000aac; -r_Add2SelfBigHex256 = 0x40000ab0; -r_AddBigHex256 = 0x40000ab4; -r_AddBigHexModP256 = 0x40000ab8; -r_AddP256 = 0x40000abc; -r_AddPdiv2_256 = 0x40000ac0; -r_GF_Jacobian_Point_Addition256 = 0x40000ac4; -r_GF_Jacobian_Point_Double256 = 0x40000ac8; -r_GF_Point_Jacobian_To_Affine256 = 0x40000acc; -r_MultiplyBigHexByUint32_256 = 0x40000ad0; -r_MultiplyBigHexModP256 = 0x40000ad4; -r_MultiplyByU16ModP256 = 0x40000ad8; -r_SubtractBigHex256 = 0x40000adc; -r_SubtractBigHexMod256 = 0x40000ae0; -r_SubtractBigHexUint32_256 = 0x40000ae4; -r_SubtractFromSelfBigHex256 = 0x40000ae8; -r_SubtractFromSelfBigHexSign256 = 0x40000aec; -r_aes_alloc = 0x40000af0; -r_aes_ccm_continue = 0x40000af4; -r_aes_ccm_process_e = 0x40000af8; -r_aes_ccm_xor_128_lsb = 0x40000afc; -r_aes_ccm_xor_128_msb = 0x40000b00; -r_aes_cmac_continue = 0x40000b04; -r_aes_cmac_start = 0x40000b08; -r_aes_k1_continue = 0x40000b0c; -r_aes_k2_continue = 0x40000b10; -r_aes_k3_continue = 0x40000b14; -r_aes_k4_continue = 0x40000b18; -r_aes_shift_left_128 = 0x40000b1c; -r_aes_start = 0x40000b20; -r_aes_xor_128 = 0x40000b24; -r_assert_err = 0x40000b28; -r_assert_param = 0x40000b2c; -r_assert_warn = 0x40000b30; -r_bigHexInversion256 = 0x40000b34; -r_ble_sw_cca_check_isr = 0x40000b38; -r_ble_util_buf_acl_tx_alloc = 0x40000b3c; -r_ble_util_buf_acl_tx_elt_get = 0x40000b40; -r_ble_util_buf_acl_tx_free = 0x40000b44; -r_ble_util_buf_acl_tx_free_in_isr = 0x40000b48; -r_ble_util_buf_adv_tx_alloc = 0x40000b4c; -r_ble_util_buf_adv_tx_free = 0x40000b50; -r_ble_util_buf_adv_tx_free_in_isr = 0x40000b54; -r_ble_util_buf_env_deinit = 0x40000b58; -r_ble_util_buf_env_init = 0x40000b5c; -r_ble_util_buf_get_rx_buf_nb = 0x40000b60; -r_ble_util_buf_get_rx_buf_size = 0x40000b64; -r_ble_util_buf_llcp_tx_alloc = 0x40000b68; -r_ble_util_buf_llcp_tx_free = 0x40000b6c; -r_ble_util_buf_rx_alloc = 0x40000b70; -r_ble_util_buf_rx_alloc_in_isr = 0x40000b74; -r_ble_util_buf_rx_free = 0x40000b78; -r_ble_util_buf_rx_free_in_isr = 0x40000b7c; -r_ble_util_buf_set_rx_buf_nb = 0x40000b80; -r_ble_util_buf_set_rx_buf_size = 0x40000b84; -r_ble_util_data_rx_buf_reset = 0x40000b88; -r_bt_bb_get_intr_mask = 0x40000b8c; -r_bt_bb_intr_clear = 0x40000b90; -r_bt_bb_intr_mask_set = 0x40000b94; -r_bt_bb_isr = 0x40000b98; -r_bt_rf_coex_cfg_set = 0x40000b9c; -r_bt_rf_coex_conn_dynamic_pti_en_get = 0x40000ba0; -r_bt_rf_coex_conn_phy_coded_data_time_limit_en_get = 0x40000ba4; -r_bt_rf_coex_ext_adv_dynamic_pti_en_get = 0x40000ba8; -r_bt_rf_coex_ext_scan_dynamic_pti_en_get = 0x40000bac; -r_bt_rf_coex_legacy_adv_dynamic_pti_en_get = 0x40000bb0; -r_bt_rf_coex_per_adv_dynamic_pti_en_get = 0x40000bb4; -r_bt_rf_coex_pti_table_get = 0x40000bb8; -r_bt_rf_coex_st_param_get = 0x40000bbc; -r_bt_rf_coex_st_param_set = 0x40000bc0; -r_bt_rf_coex_sync_scan_dynamic_pti_en_get = 0x40000bc4; -r_bt_rma_apply_rule_cs_fmt = 0x40000bc8; -r_bt_rma_apply_rule_cs_idx = 0x40000bcc; -r_bt_rma_configure = 0x40000bd0; -r_bt_rma_deregister_rule_cs_fmt = 0x40000bd4; -r_bt_rma_deregister_rule_cs_idx = 0x40000bd8; -r_bt_rma_get_ant_by_act = 0x40000bdc; -r_bt_rma_init = 0x40000be0; -r_bt_rma_register_rule_cs_fmt = 0x40000be4; -r_bt_rma_register_rule_cs_idx = 0x40000be8; -r_bt_rtp_apply_rule_cs_fmt = 0x40000bec; -r_bt_rtp_apply_rule_cs_idx = 0x40000bf0; -r_bt_rtp_deregister_rule_cs_fmt = 0x40000bf4; -r_bt_rtp_deregister_rule_cs_idx = 0x40000bf8; -r_bt_rtp_get_txpwr_idx_by_act = 0x40000bfc; -r_bt_rtp_init = 0x40000c00; -r_bt_rtp_register_rule_cs_fmt = 0x40000c04; -r_bt_rtp_register_rule_cs_idx = 0x40000c08; -r_btdm_isr = 0x40000c0c; -r_btdm_task_post = 0x40000c10; -r_btdm_task_post_from_isr = 0x40000c14; -r_btdm_task_recycle = 0x40000c18; -r_cali_phase_match_p = 0x40000c1c; -r_cmp_abs_time = 0x40000c20; -r_cmp_dest_id = 0x40000c24; -r_cmp_timer_id = 0x40000c28; -r_co_bdaddr_compare = 0x40000c2c; -r_co_ble_pkt_dur_in_us = 0x40000c30; -r_co_list_extract = 0x40000c34; -r_co_list_extract_after = 0x40000c38; -r_co_list_extract_sublist = 0x40000c3c; -r_co_list_find = 0x40000c40; -r_co_list_init = 0x40000c44; -r_co_list_insert_after = 0x40000c48; -r_co_list_insert_before = 0x40000c4c; -r_co_list_merge = 0x40000c50; -r_co_list_pool_init = 0x40000c54; -r_co_list_pop_front = 0x40000c58; -r_co_list_push_back = 0x40000c5c; -r_co_list_push_back_sublist = 0x40000c60; -r_co_list_push_front = 0x40000c64; -r_co_list_size = 0x40000c68; -r_co_nb_good_le_channels = 0x40000c6c; -r_co_util_pack = 0x40000c70; -r_co_util_read_array_size = 0x40000c74; -r_co_util_unpack = 0x40000c78; -r_dbg_env_deinit = 0x40000c7c; -r_dbg_env_init = 0x40000c80; -r_dbg_platform_reset_complete = 0x40000c84; -r_dl_upd_proc_start = 0x40000c88; -r_dump_data = 0x40000c8c; -r_ecc_abort_key256_generation = 0x40000c90; -r_ecc_gen_new_public_key = 0x40000c94; -r_ecc_gen_new_secret_key = 0x40000c98; -r_ecc_generate_key256 = 0x40000c9c; -r_ecc_get_debug_Keys = 0x40000ca0; -r_ecc_init = 0x40000ca4; -r_ecc_is_valid_point = 0x40000ca8; -r_ecc_multiplication_event_handler = 0x40000cac; -r_ecc_point_multiplication_win_256 = 0x40000cb0; -r_emi_alloc_em_mapping_by_offset = 0x40000cb4; -r_emi_base_reg_lut_show = 0x40000cb8; -r_emi_em_base_reg_show = 0x40000cbc; -r_emi_free_em_mapping_by_offset = 0x40000cc0; -r_emi_get_em_mapping_idx_by_offset = 0x40000cc4; -r_emi_get_mem_addr_by_offset = 0x40000cc8; -r_emi_overwrite_em_mapping_by_offset = 0x40000ccc; -r_esp_vendor_hci_command_handler = 0x40000cd0; -r_get_stack_usage = 0x40000cd4; -r_h4tl_acl_hdr_rx_evt_handler = 0x40000cd8; -r_h4tl_cmd_hdr_rx_evt_handler = 0x40000cdc; -r_h4tl_cmd_pld_rx_evt_handler = 0x40000ce0; -r_h4tl_eif_io_event_post = 0x40000ce4; -r_h4tl_eif_register = 0x40000ce8; -r_h4tl_init = 0x40000cec; -r_h4tl_out_of_sync = 0x40000cf0; -r_h4tl_out_of_sync_check = 0x40000cf4; -r_h4tl_read_hdr = 0x40000cf8; -r_h4tl_read_next_out_of_sync = 0x40000cfc; -r_h4tl_read_payl = 0x40000d00; -r_h4tl_read_start = 0x40000d04; -r_h4tl_rx_acl_hdr_extract = 0x40000d08; -r_h4tl_rx_cmd_hdr_extract = 0x40000d0c; -r_h4tl_rx_done = 0x40000d10; -r_h4tl_start = 0x40000d14; -r_h4tl_stop = 0x40000d18; -r_h4tl_tx_done = 0x40000d1c; -r_h4tl_tx_evt_handler = 0x40000d20; -r_h4tl_write = 0x40000d24; -r_hci_acl_tx_data_alloc = 0x40000d28; -r_hci_acl_tx_data_received = 0x40000d2c; -r_hci_basic_cmd_send_2_controller = 0x40000d30; -r_hci_ble_adv_report_filter_check = 0x40000d34; -r_hci_ble_adv_report_tx_check = 0x40000d38; -r_hci_ble_conhdl_register = 0x40000d3c; -r_hci_ble_conhdl_unregister = 0x40000d40; -r_hci_build_acl_data = 0x40000d44; -r_hci_build_cc_evt = 0x40000d48; -r_hci_build_cs_evt = 0x40000d4c; -r_hci_build_evt = 0x40000d50; -r_hci_build_le_evt = 0x40000d54; -r_hci_cmd_get_max_param_size = 0x40000d58; -r_hci_cmd_received = 0x40000d5c; -r_hci_cmd_reject = 0x40000d60; -r_hci_evt_mask_check = 0x40000d64; -r_hci_evt_mask_set = 0x40000d68; -r_hci_fc_acl_buf_size_set = 0x40000d6c; -r_hci_fc_acl_en = 0x40000d70; -r_hci_fc_acl_packet_sent = 0x40000d74; -r_hci_fc_check_host_available_nb_acl_packets = 0x40000d78; -r_hci_fc_host_nb_acl_pkts_complete = 0x40000d7c; -r_hci_fc_init = 0x40000d80; -r_hci_look_for_cmd_desc = 0x40000d84; -r_hci_look_for_evt_desc = 0x40000d88; -r_hci_look_for_le_evt_desc = 0x40000d8c; -r_hci_look_for_le_evt_desc_esp = 0x40000d90; -r_hci_pack_bytes = 0x40000d94; -r_hci_register_vendor_desc_tab = 0x40000d98; -r_hci_send_2_controller = 0x40000d9c; -r_hci_send_2_host = 0x40000da0; -r_hci_tl_c2h_data_flow_on = 0x40000da4; -r_hci_tl_cmd_hdr_rx_evt_handler = 0x40000da8; -r_hci_tl_cmd_pld_rx_evt_handler = 0x40000dac; -r_hci_tl_get_pkt = 0x40000db0; -r_hci_tl_hci_pkt_handler = 0x40000db4; -r_hci_tl_hci_tx_done_evt_handler = 0x40000db8; -r_hci_tl_inc_nb_h2c_cmd_pkts = 0x40000dbc; -r_hci_tl_save_pkt = 0x40000dc0; -r_hci_tl_send = 0x40000dc4; -r_hci_tx_done = 0x40000dc8; -r_hci_tx_start = 0x40000dcc; -r_hci_tx_trigger = 0x40000dd0; -r_isValidSecretKey_256 = 0x40000dd4; -r_ke_check_malloc = 0x40000dd8; -r_ke_event_callback_set = 0x40000ddc; -r_ke_event_clear = 0x40000de0; -r_ke_event_flush = 0x40000de4; -r_ke_event_get = 0x40000de8; -r_ke_event_get_all = 0x40000dec; -r_ke_event_init = 0x40000df0; -r_ke_event_schedule = 0x40000df4; -r_ke_event_set = 0x40000df8; -r_ke_flush = 0x40000dfc; -r_ke_free = 0x40000e00; -r_ke_handler_search = 0x40000e04; -r_ke_init = 0x40000e08; -r_ke_is_free = 0x40000e0c; -r_ke_malloc = 0x40000e10; -r_ke_mem_init = 0x40000e14; -r_ke_mem_is_empty = 0x40000e18; -r_ke_mem_is_in_heap = 0x40000e1c; -r_ke_msg_alloc = 0x40000e20; -r_ke_msg_dest_id_get = 0x40000e24; -r_ke_msg_discard = 0x40000e28; -r_ke_msg_forward = 0x40000e2c; -r_ke_msg_forward_new_id = 0x40000e30; -r_ke_msg_free = 0x40000e34; -r_ke_msg_in_queue = 0x40000e38; -r_ke_msg_save = 0x40000e3c; -r_ke_msg_send = 0x40000e40; -r_ke_msg_send_basic = 0x40000e44; -r_ke_msg_src_id_get = 0x40000e48; -r_ke_queue_extract = 0x40000e4c; -r_ke_queue_insert = 0x40000e50; -r_ke_sleep_check = 0x40000e54; -r_ke_state_get = 0x40000e58; -r_ke_state_set = 0x40000e5c; -r_ke_task_check = 0x40000e60; -r_ke_task_create = 0x40000e64; -r_ke_task_delete = 0x40000e68; -r_ke_task_handler_get = 0x40000e6c; -r_ke_task_init = 0x40000e70; -r_ke_task_msg_flush = 0x40000e74; -r_ke_task_saved_update = 0x40000e78; -r_ke_task_schedule = 0x40000e7c; -r_ke_time = 0x40000e80; -r_ke_time_cmp = 0x40000e84; -r_ke_time_past = 0x40000e88; -r_ke_timer_active = 0x40000e8c; -r_ke_timer_adjust_all = 0x40000e90; -r_ke_timer_clear = 0x40000e94; -r_ke_timer_init = 0x40000e98; -r_ke_timer_schedule = 0x40000e9c; -r_ke_timer_set = 0x40000ea0; -r_led_init = 0x40000ea4; -r_led_set_all = 0x40000ea8; -r_llc_aes_res_cb = 0x40000eac; -r_llc_ch_map_up_proc_err_cb = 0x40000eb0; -r_llc_cleanup = 0x40000eb4; -r_llc_cmd_cmp_send = 0x40000eb8; -r_llc_cmd_stat_send = 0x40000ebc; -r_llc_con_move_cbk = 0x40000ec0; -r_llc_con_plan_set_update = 0x40000ec4; -r_llc_con_upd_param_in_range = 0x40000ec8; -r_llc_disconnect = 0x40000ecc; -r_llc_disconnect_end = 0x40000ed0; -r_llc_disconnect_proc_continue = 0x40000ed4; -r_llc_disconnect_proc_err_cb = 0x40000ed8; -r_llc_dl_chg_check = 0x40000edc; -r_llc_dle_proc_err_cb = 0x40000ee0; -r_llc_feats_exch_proc_err_cb = 0x40000ee4; -r_llc_hci_cmd_handler_tab_p_get = 0x40000ee8; -r_llc_hci_command_handler = 0x40000eec; -r_llc_hci_con_param_req_evt_send = 0x40000ef0; -r_llc_hci_con_upd_info_send = 0x40000ef4; -r_llc_hci_disconnected_dis = 0x40000ef8; -r_llc_hci_dl_upd_info_send = 0x40000efc; -r_llc_hci_enc_evt_send = 0x40000f00; -r_llc_hci_feats_info_send = 0x40000f04; -r_llc_hci_le_phy_upd_cmp_evt_send = 0x40000f08; -r_llc_hci_ltk_request_evt_send = 0x40000f0c; -r_llc_hci_nb_cmp_pkts_evt_send = 0x40000f10; -r_llc_hci_version_info_send = 0x40000f14; -r_llc_init_term_proc = 0x40000f18; -r_llc_iv_skd_rand_gen = 0x40000f1c; -r_llc_le_ping_proc_continue = 0x40000f20; -r_llc_le_ping_proc_err_cb = 0x40000f24; -r_llc_le_ping_restart = 0x40000f28; -r_llc_le_ping_set = 0x40000f2c; -r_llc_ll_pause_enc_rsp_ack_handler = 0x40000f30; -r_llc_ll_reject_ind_ack_handler = 0x40000f34; -r_llc_ll_reject_ind_pdu_send = 0x40000f38; -r_llc_ll_start_enc_rsp_ack_handler = 0x40000f3c; -r_llc_ll_terminate_ind_ack = 0x40000f40; -r_llc_ll_unknown_ind_handler = 0x40000f44; -r_llc_llcp_send = 0x40000f48; -r_llc_llcp_state_set = 0x40000f4c; -r_llc_llcp_trans_timer_set = 0x40000f50; -r_llc_llcp_tx_check = 0x40000f54; -r_llc_loc_ch_map_proc_continue = 0x40000f58; -r_llc_loc_con_upd_proc_continue = 0x40000f5c; -r_llc_loc_con_upd_proc_err_cb = 0x40000f60; -r_llc_loc_dl_upd_proc_continue = 0x40000f64; -r_llc_loc_encrypt_proc_continue = 0x40000f68; -r_llc_loc_encrypt_proc_err_cb = 0x40000f6c; -r_llc_loc_feats_exch_proc_continue = 0x40000f70; -r_llc_loc_phy_upd_proc_continue = 0x40000f74; -r_llc_loc_phy_upd_proc_err_cb = 0x40000f78; -r_llc_msg_handler_tab_p_get = 0x40000f7c; -r_llc_pref_param_compute = 0x40000f80; -r_llc_proc_collision_check = 0x40000f84; -r_llc_proc_err_ind = 0x40000f88; -r_llc_proc_get = 0x40000f8c; -r_llc_proc_id_get = 0x40000f90; -r_llc_proc_reg = 0x40000f94; -r_llc_proc_state_get = 0x40000f98; -r_llc_proc_state_set = 0x40000f9c; -r_llc_proc_timer_pause_set = 0x40000fa0; -r_llc_proc_timer_set = 0x40000fa4; -r_llc_proc_unreg = 0x40000fa8; -r_llc_rem_ch_map_proc_continue = 0x40000fac; -r_llc_rem_con_upd_proc_continue = 0x40000fb0; -r_llc_rem_con_upd_proc_err_cb = 0x40000fb4; -r_llc_rem_dl_upd_proc = 0x40000fb8; -r_llc_rem_encrypt_proc_continue = 0x40000fbc; -r_llc_rem_encrypt_proc_err_cb = 0x40000fc0; -r_llc_rem_phy_upd_proc_continue = 0x40000fc4; -r_llc_rem_phy_upd_proc_err_cb = 0x40000fc8; -r_llc_role_get = 0x40000fcc; -r_llc_sk_gen = 0x40000fd0; -r_llc_start = 0x40000fd4; -r_llc_stop = 0x40000fd8; -r_llc_ver_exch_loc_proc_continue = 0x40000fdc; -r_llc_ver_proc_err_cb = 0x40000fe0; -r_llcp_pdu_handler_tab_p_get = 0x40000fe4; -r_lld_aa_gen = 0x40000fe8; -r_lld_adv_adv_data_set = 0x40000fec; -r_lld_adv_adv_data_update = 0x40000ff0; -r_lld_adv_aux_ch_idx_set = 0x40000ff4; -r_lld_adv_aux_evt_canceled_cbk = 0x40000ff8; -r_lld_adv_aux_evt_start_cbk = 0x40000ffc; -r_lld_adv_coex_check_ext_adv_synced = 0x40001000; -r_lld_adv_coex_env_reset = 0x40001004; -r_lld_adv_duration_update = 0x40001008; -r_lld_adv_dynamic_pti_process = 0x4000100c; -r_lld_adv_end = 0x40001010; -r_lld_adv_evt_canceled_cbk = 0x40001014; -r_lld_adv_evt_start_cbk = 0x40001018; -r_lld_adv_ext_chain_construct = 0x4000101c; -r_lld_adv_ext_pkt_prepare = 0x40001020; -r_lld_adv_frm_cbk = 0x40001024; -r_lld_adv_frm_isr = 0x40001028; -r_lld_adv_frm_skip_isr = 0x4000102c; -r_lld_adv_init = 0x40001030; -r_lld_adv_pkt_rx = 0x40001034; -r_lld_adv_pkt_rx_connect_ind = 0x40001038; -r_lld_adv_pkt_rx_send_scan_req_evt = 0x4000103c; -r_lld_adv_rand_addr_update = 0x40001040; -r_lld_adv_restart = 0x40001044; -r_lld_adv_scan_rsp_data_set = 0x40001048; -r_lld_adv_scan_rsp_data_update = 0x4000104c; -r_lld_adv_set_tx_power = 0x40001050; -r_lld_adv_start = 0x40001054; -r_lld_adv_stop = 0x40001058; -r_lld_adv_sync_info_set = 0x4000105c; -r_lld_adv_sync_info_update = 0x40001060; -r_lld_calc_aux_rx = 0x40001064; -r_lld_cca_alloc = 0x40001068; -r_lld_cca_data_reset = 0x4000106c; -r_lld_cca_free = 0x40001070; -r_lld_ch_assess_data_get = 0x40001074; -r_lld_ch_idx_get = 0x40001078; -r_lld_ch_map_set = 0x4000107c; -r_lld_channel_assess = 0x40001080; -r_lld_con_activity_act_offset_compute = 0x40001084; -r_lld_con_activity_offset_compute = 0x40001088; -r_lld_con_ch_map_update = 0x4000108c; -r_lld_con_cleanup = 0x40001090; -r_lld_con_current_tx_power_get = 0x40001094; -r_lld_con_data_flow_set = 0x40001098; -r_lld_con_data_len_update = 0x4000109c; -r_lld_con_data_tx = 0x400010a0; -r_lld_con_enc_key_load = 0x400010a4; -r_lld_con_event_counter_get = 0x400010a8; -r_lld_con_evt_canceled_cbk = 0x400010ac; -r_lld_con_evt_duration_min_get = 0x400010b0; -r_lld_con_evt_max_eff_time_cal = 0x400010b4; -r_lld_con_evt_sd_evt_time_get = 0x400010b8; -r_lld_con_evt_start_cbk = 0x400010bc; -r_lld_con_evt_time_update = 0x400010c0; -r_lld_con_free_all_tx_buf = 0x400010c4; -r_lld_con_frm_cbk = 0x400010c8; -r_lld_con_frm_isr = 0x400010cc; -r_lld_con_frm_skip_isr = 0x400010d0; -r_lld_con_init = 0x400010d4; -r_lld_con_llcp_tx = 0x400010d8; -r_lld_con_max_lat_calc = 0x400010dc; -r_lld_con_offset_get = 0x400010e0; -r_lld_con_param_update = 0x400010e4; -r_lld_con_phys_update = 0x400010e8; -r_lld_con_pref_slave_evt_dur_set = 0x400010ec; -r_lld_con_pref_slave_latency_set = 0x400010f0; -r_lld_con_rssi_get = 0x400010f4; -r_lld_con_rx = 0x400010f8; -r_lld_con_rx_channel_assess = 0x400010fc; -r_lld_con_rx_enc = 0x40001100; -r_lld_con_rx_isr = 0x40001104; -r_lld_con_rx_link_info_check = 0x40001108; -r_lld_con_rx_llcp_check = 0x4000110c; -r_lld_con_rx_sync_time_update = 0x40001110; -r_lld_con_sched = 0x40001114; -r_lld_con_set_tx_power = 0x40001118; -r_lld_con_start = 0x4000111c; -r_lld_con_stop = 0x40001120; -r_lld_con_tx = 0x40001124; -r_lld_con_tx_enc = 0x40001128; -r_lld_con_tx_isr = 0x4000112c; -r_lld_con_tx_len_update = 0x40001130; -r_lld_con_tx_len_update_for_intv = 0x40001134; -r_lld_con_tx_len_update_for_rate = 0x40001138; -r_lld_con_tx_prog = 0x4000113c; -r_lld_conn_dynamic_pti_process = 0x40001140; -r_lld_continue_scan_rx_isr_end_process = 0x40001144; -r_lld_ext_scan_dynamic_pti_process = 0x40001148; -r_lld_hw_cca_end_isr = 0x4000114c; -r_lld_hw_cca_evt_handler = 0x40001150; -r_lld_hw_cca_isr = 0x40001154; -r_lld_init_cal_anchor_point = 0x40001158; -r_lld_init_compute_winoffset = 0x4000115c; -r_lld_init_connect_req_pack = 0x40001160; -r_lld_init_end = 0x40001164; -r_lld_init_evt_canceled_cbk = 0x40001168; -r_lld_init_evt_start_cbk = 0x4000116c; -r_lld_init_frm_cbk = 0x40001170; -r_lld_init_frm_eof_isr = 0x40001174; -r_lld_init_frm_skip_isr = 0x40001178; -r_lld_init_init = 0x4000117c; -r_lld_init_process_pkt_rx = 0x40001180; -r_lld_init_process_pkt_rx_adv_ext_ind = 0x40001184; -r_lld_init_process_pkt_rx_adv_ind_or_direct_ind = 0x40001188; -r_lld_init_process_pkt_rx_aux_connect_rsp = 0x4000118c; -r_lld_init_process_pkt_tx = 0x40001190; -r_lld_init_process_pkt_tx_cal_con_timestamp = 0x40001194; -r_lld_init_sched = 0x40001198; -r_lld_init_set_tx_power = 0x4000119c; -r_lld_init_start = 0x400011a0; -r_lld_init_stop = 0x400011a4; -r_lld_instant_proc_end = 0x400011a8; -r_lld_llcp_rx_ind_handler = 0x400011ac; -r_lld_per_adv_ch_map_update = 0x400011b0; -r_lld_per_adv_chain_construct = 0x400011b4; -r_lld_per_adv_cleanup = 0x400011b8; -r_lld_per_adv_coex_env_reset = 0x400011bc; -r_lld_per_adv_data_set = 0x400011c0; -r_lld_per_adv_data_update = 0x400011c4; -r_lld_per_adv_dynamic_pti_process = 0x400011c8; -r_lld_per_adv_evt_canceled_cbk = 0x400011cc; -r_lld_per_adv_evt_start_cbk = 0x400011d0; -r_lld_per_adv_ext_pkt_prepare = 0x400011d4; -r_lld_per_adv_frm_cbk = 0x400011d8; -r_lld_per_adv_frm_isr = 0x400011dc; -r_lld_per_adv_frm_skip_isr = 0x400011e0; -r_lld_per_adv_init = 0x400011e4; -r_lld_per_adv_init_info_get = 0x400011e8; -r_lld_per_adv_list_add = 0x400011ec; -r_lld_per_adv_list_rem = 0x400011f0; -r_lld_per_adv_sched = 0x400011f4; -r_lld_per_adv_set_tx_power = 0x400011f8; -r_lld_per_adv_start = 0x400011fc; -r_lld_per_adv_stop = 0x40001200; -r_lld_per_adv_sync_info_get = 0x40001204; -r_lld_process_cca_data = 0x40001208; -r_lld_ral_search = 0x4000120c; -r_lld_read_clock = 0x40001210; -r_lld_res_list_add = 0x40001214; -r_lld_res_list_clear = 0x40001218; -r_lld_res_list_is_empty = 0x4000121c; -r_lld_res_list_local_rpa_get = 0x40001220; -r_lld_res_list_peer_rpa_get = 0x40001224; -r_lld_res_list_peer_update = 0x40001228; -r_lld_res_list_priv_mode_update = 0x4000122c; -r_lld_res_list_rem = 0x40001230; -r_lld_reset_reg = 0x40001234; -r_lld_rpa_renew = 0x40001238; -r_lld_rpa_renew_evt_canceled_cbk = 0x4000123c; -r_lld_rpa_renew_evt_start_cbk = 0x40001240; -r_lld_rpa_renew_instant_cbk = 0x40001244; -r_lld_rxdesc_check = 0x40001248; -r_lld_rxdesc_free = 0x4000124c; -r_lld_scan_create_sync = 0x40001250; -r_lld_scan_create_sync_cancel = 0x40001254; -r_lld_scan_end = 0x40001258; -r_lld_scan_evt_canceled_cbk = 0x4000125c; -r_lld_scan_evt_start_cbk = 0x40001260; -r_lld_scan_frm_cbk = 0x40001264; -r_lld_scan_frm_eof_isr = 0x40001268; -r_lld_scan_frm_rx_isr = 0x4000126c; -r_lld_scan_frm_skip_isr = 0x40001270; -r_lld_scan_init = 0x40001274; -r_lld_scan_params_update = 0x40001278; -r_lld_scan_process_pkt_rx = 0x4000127c; -r_lld_scan_process_pkt_rx_adv_rep = 0x40001280; -r_lld_scan_process_pkt_rx_aux_adv_ind = 0x40001284; -r_lld_scan_process_pkt_rx_aux_chain_ind = 0x40001288; -r_lld_scan_process_pkt_rx_aux_scan_rsp = 0x4000128c; -r_lld_scan_process_pkt_rx_ext_adv = 0x40001290; -r_lld_scan_process_pkt_rx_ext_adv_ind = 0x40001294; -r_lld_scan_process_pkt_rx_legacy_adv = 0x40001298; -r_lld_scan_restart = 0x4000129c; -r_lld_scan_sched = 0x400012a0; -r_lld_scan_set_tx_power = 0x400012a4; -r_lld_scan_start = 0x400012a8; -r_lld_scan_stop = 0x400012ac; -r_lld_scan_sync_accept = 0x400012b0; -r_lld_scan_sync_info_unpack = 0x400012b4; -r_lld_scan_trunc_ind = 0x400012b8; -r_lld_sw_cca_evt_handler = 0x400012bc; -r_lld_sw_cca_isr = 0x400012c0; -r_lld_sync_ch_map_update = 0x400012c4; -r_lld_sync_cleanup = 0x400012c8; -r_lld_sync_evt_canceled_cbk = 0x400012cc; -r_lld_sync_evt_start_cbk = 0x400012d0; -r_lld_sync_frm_cbk = 0x400012d4; -r_lld_sync_frm_eof_isr = 0x400012d8; -r_lld_sync_frm_rx_isr = 0x400012dc; -r_lld_sync_frm_skip_isr = 0x400012e0; -r_lld_sync_init = 0x400012e4; -r_lld_sync_process_pkt_rx = 0x400012e8; -r_lld_sync_process_pkt_rx_aux_sync_ind = 0x400012ec; -r_lld_sync_process_pkt_rx_pkt_check = 0x400012f0; -r_lld_sync_scan_dynamic_pti_process = 0x400012f4; -r_lld_sync_sched = 0x400012f8; -r_lld_sync_start = 0x400012fc; -r_lld_sync_stop = 0x40001300; -r_lld_sync_trunc_ind = 0x40001304; -r_lld_test_cleanup = 0x40001308; -r_lld_test_evt_canceled_cbk = 0x4000130c; -r_lld_test_evt_start_cbk = 0x40001310; -r_lld_test_freq2chnl = 0x40001314; -r_lld_test_frm_cbk = 0x40001318; -r_lld_test_frm_isr = 0x4000131c; -r_lld_test_init = 0x40001320; -r_lld_test_rx_isr = 0x40001324; -r_lld_test_set_tx_power = 0x40001328; -r_lld_test_start = 0x4000132c; -r_lld_test_stop = 0x40001330; -r_lld_update_rxbuf = 0x40001334; -r_lld_update_rxbuf_isr = 0x40001338; -r_lld_white_list_add = 0x4000133c; -r_lld_white_list_rem = 0x40001340; -r_llm_activity_free_get = 0x40001344; -r_llm_activity_free_set = 0x40001348; -r_llm_activity_syncing_get = 0x4000134c; -r_llm_adv_con_len_check = 0x40001350; -r_llm_adv_hdl_to_id = 0x40001354; -r_llm_adv_rep_flow_control_check = 0x40001358; -r_llm_adv_rep_flow_control_update = 0x4000135c; -r_llm_adv_reports_list_check = 0x40001360; -r_llm_adv_set_all_release = 0x40001364; -r_llm_adv_set_dft_params = 0x40001368; -r_llm_adv_set_release = 0x4000136c; -r_llm_aes_res_cb = 0x40001370; -r_llm_ble_update_adv_flow_control = 0x40001374; -r_llm_ch_map_update = 0x40001378; -r_llm_cmd_cmp_send = 0x4000137c; -r_llm_cmd_stat_send = 0x40001380; -r_llm_dev_list_empty_entry = 0x40001384; -r_llm_dev_list_search = 0x40001388; -r_llm_env_adv_dup_filt_deinit = 0x4000138c; -r_llm_env_adv_dup_filt_init = 0x40001390; -r_llm_init_ble_adv_report_flow_contol = 0x40001394; -r_llm_is_dev_connected = 0x40001398; -r_llm_is_dev_synced = 0x4000139c; -r_llm_is_non_con_act_ongoing_check = 0x400013a0; -r_llm_is_wl_accessible = 0x400013a4; -r_llm_le_evt_mask_check = 0x400013a8; -r_llm_le_features_get = 0x400013ac; -r_llm_link_disc = 0x400013b0; -r_llm_master_ch_map_get = 0x400013b4; -r_llm_msg_handler_tab_p_get = 0x400013b8; -r_llm_no_activity = 0x400013bc; -r_llm_per_adv_slot_dur = 0x400013c0; -r_llm_plan_elt_get = 0x400013c4; -r_llm_rx_path_comp_get = 0x400013c8; -r_llm_scan_start = 0x400013cc; -r_llm_scan_sync_acad_attach = 0x400013d0; -r_llm_scan_sync_acad_detach = 0x400013d4; -r_llm_send_adv_lost_event_to_host = 0x400013d8; -r_llm_tx_path_comp_get = 0x400013dc; -r_misc_deinit = 0x400013e0; -r_misc_free_em_buf_in_isr = 0x400013e4; -r_misc_init = 0x400013e8; -r_misc_msg_handler_tab_p_get = 0x400013ec; -r_notEqual256 = 0x400013f0; -r_phy_upd_proc_start = 0x400013f4; -r_platform_reset = 0x400013f8; -r_register_esp_vendor_cmd_handler = 0x400013fc; -r_rf_em_init = 0x40001400; -r_rf_force_agc_enable = 0x40001404; -r_rf_reg_rd = 0x40001408; -r_rf_reg_wr = 0x4000140c; -r_rf_reset = 0x40001410; -r_rf_rssi_convert = 0x40001414; -r_rf_rw_v9_le_disable = 0x40001418; -r_rf_rw_v9_le_enable = 0x4000141c; -r_rf_sleep = 0x40001420; -r_rf_txpwr_cs_get = 0x40001424; -r_rf_txpwr_dbm_get = 0x40001428; -r_rf_util_cs_fmt_convert = 0x4000142c; -r_rw_crypto_aes_ccm = 0x40001430; -r_rw_crypto_aes_encrypt = 0x40001434; -r_rw_crypto_aes_init = 0x40001438; -r_rw_crypto_aes_k1 = 0x4000143c; -r_rw_crypto_aes_k2 = 0x40001440; -r_rw_crypto_aes_k3 = 0x40001444; -r_rw_crypto_aes_k4 = 0x40001448; -r_rw_crypto_aes_rand = 0x4000144c; -r_rw_crypto_aes_result_handler = 0x40001450; -r_rw_crypto_aes_s1 = 0x40001454; -r_rw_cryto_aes_cmac = 0x40001458; -r_rw_v9_init_em_radio_table = 0x4000145c; -r_rwble_isr = 0x40001460; -r_rwble_sleep_enter = 0x40001464; -r_rwble_sleep_wakeup_end = 0x40001468; -r_rwbtdm_isr_wrapper = 0x4000146c; -r_rwip_active_check = 0x40001470; -r_rwip_aes_encrypt = 0x40001474; -r_rwip_assert = 0x40001478; -r_rwip_crypt_evt_handler = 0x4000147c; -r_rwip_crypt_isr_handler = 0x40001480; -r_rwip_eif_get = 0x40001484; -r_rwip_half_slot_2_lpcycles = 0x40001488; -r_rwip_hus_2_lpcycles = 0x4000148c; -r_rwip_isr = 0x40001490; -r_rwip_lpcycles_2_hus = 0x40001494; -r_rwip_prevent_sleep_clear = 0x40001498; -r_rwip_prevent_sleep_set = 0x4000149c; -r_rwip_schedule = 0x400014a0; -r_rwip_sleep = 0x400014a4; -r_rwip_sw_int_handler = 0x400014a8; -r_rwip_sw_int_req = 0x400014ac; -r_rwip_time_get = 0x400014b0; -r_rwip_timer_10ms_handler = 0x400014b4; -r_rwip_timer_10ms_set = 0x400014b8; -r_rwip_timer_hs_handler = 0x400014bc; -r_rwip_timer_hs_set = 0x400014c0; -r_rwip_timer_hus_handler = 0x400014c4; -r_rwip_timer_hus_set = 0x400014c8; -r_rwip_wakeup = 0x400014cc; -r_rwip_wakeup_end = 0x400014d0; -r_rwip_wlcoex_set = 0x400014d4; -r_sch_alarm_clear = 0x400014d8; -r_sch_alarm_init = 0x400014dc; -r_sch_alarm_prog = 0x400014e0; -r_sch_alarm_set = 0x400014e4; -r_sch_alarm_timer_isr = 0x400014e8; -r_sch_arb_conflict_check = 0x400014ec; -r_sch_arb_elt_cancel = 0x400014f0; -r_sch_arb_event_start_isr = 0x400014f4; -r_sch_arb_init = 0x400014f8; -r_sch_arb_insert = 0x400014fc; -r_sch_arb_prog_timer = 0x40001500; -r_sch_arb_remove = 0x40001504; -r_sch_arb_sw_isr = 0x40001508; -r_sch_plan_chk = 0x4000150c; -r_sch_plan_clock_wrap_offset_update = 0x40001510; -r_sch_plan_init = 0x40001514; -r_sch_plan_interval_req = 0x40001518; -r_sch_plan_offset_max_calc = 0x4000151c; -r_sch_plan_offset_req = 0x40001520; -r_sch_plan_position_range_compute = 0x40001524; -r_sch_plan_rem = 0x40001528; -r_sch_plan_req = 0x4000152c; -r_sch_plan_set = 0x40001530; -r_sch_prog_end_isr = 0x40001534; -r_sch_prog_init = 0x40001538; -r_sch_prog_push = 0x4000153c; -r_sch_prog_rx_isr = 0x40001540; -r_sch_prog_skip_isr = 0x40001544; -r_sch_prog_tx_isr = 0x40001548; -r_sch_slice_bg_add = 0x4000154c; -r_sch_slice_bg_remove = 0x40001550; -r_sch_slice_compute = 0x40001554; -r_sch_slice_fg_add = 0x40001558; -r_sch_slice_fg_remove = 0x4000155c; -r_sch_slice_init = 0x40001560; -r_sch_slice_per_add = 0x40001564; -r_sch_slice_per_remove = 0x40001568; -r_sdk_config_get_bt_sleep_enable = 0x4000156c; -r_sdk_config_get_hl_derived_opts = 0x40001570; -r_sdk_config_get_opts = 0x40001574; -r_sdk_config_get_priv_opts = 0x40001578; -r_sdk_config_set_bt_sleep_enable = 0x4000157c; -r_sdk_config_set_hl_derived_opts = 0x40001580; -r_sdk_config_set_opts = 0x40001584; -r_specialModP256 = 0x40001588; -r_unloaded_area_init = 0x4000158c; -r_vhci_flow_off = 0x40001590; -r_vhci_flow_on = 0x40001594; -r_vhci_notify_host_send_available = 0x40001598; -r_vhci_send_to_host = 0x4000159c; -r_vnd_hci_command_handler = 0x400015a0; -r_vshci_init = 0x400015a4; -vnd_hci_command_handler_wrapper = 0x400015a8; -/* Data (.data, .bss, .rodata) */ -bt_rf_coex_cfg_p = 0x3fcdffcc; -bt_rf_coex_hooks_p = 0x3fcdffc8; -btdm_env_p = 0x3fcdffc4; -g_rw_controller_task_handle = 0x3fcdffc0; -g_rw_init_sem = 0x3fcdffbc; -g_rw_schd_queue = 0x3fcdffb8; -lld_init_env = 0x3fcdffb4; -lld_rpa_renew_env = 0x3fcdffb0; -lld_scan_env = 0x3fcdffac; -lld_scan_sync_env = 0x3fcdffa8; -lld_test_env = 0x3fcdffa4; -p_ble_util_buf_env = 0x3fcdffa0; -p_lld_env = 0x3fcdff9c; -p_llm_env = 0x3fcdff98; -r_h4tl_eif_p = 0x3fcdff94; -r_hli_funcs_p = 0x3fcdff90; -r_ip_funcs_p = 0x3fcdff8c; -r_modules_funcs_p = 0x3fcdff88; -r_osi_funcs_p = 0x3fcdff84; -r_plf_funcs_p = 0x3fcdff80; -vhci_env_p = 0x3fcdff7c; -aa_gen = 0x3fcdff78; -aes_env = 0x3fcdff6c; -bt_rf_coex_cfg_cb = 0x3fcdff1c; -btdm_pwr_state = 0x3fcdff18; -btdm_slp_err = 0x3fcdff14; -ecc_env = 0x3fcdff0c; -esp_handler = 0x3fcdff04; -esp_vendor_cmd = 0x3fcdfefc; -g_adv_delay_dis = 0x3fcdfef8; -g_conflict_elt = 0x3fcdfef4; -g_eif_api = 0x3fcdfee4; -g_event_empty = 0x3fcdfed8; -g_llc_state = 0x3fcdfecc; -g_llm_state = 0x3fcdfec8; -g_max_evt_env = 0x3fcdfec4; -g_misc_state = 0x3fcdfec0; -g_rma_rule_db = 0x3fcdfea4; -g_rtp_rule_db = 0x3fcdfe88; -g_scan_forever = 0x3fcdfe85; -g_time_msb = 0x3fcdfe84; -h4tl_env = 0x3fcdfe5c; -hci_env = 0x3fcdfe38; -hci_ext_host = 0x3fcdfe34; -hci_fc_env = 0x3fcdfe2c; -hci_tl_env = 0x3fcdfe00; -ke_env = 0x3fcdfdd0; -ke_event_env = 0x3fcdfd90; -ke_task_env = 0x3fcdfd14; -llc_env = 0x3fcdfcec; -lld_adv_env = 0x3fcdfcc4; -lld_con_env = 0x3fcdfc9c; -lld_exp_sync_pos_tab = 0x3fcdfc94; -lld_per_adv_env = 0x3fcdfc6c; -lld_sync_env = 0x3fcdfc44; -llm_le_adv_flow_env = 0x3fcdfc38; -rw_sleep_enable = 0x3fcdfc34; -rwble_env = 0x3fcdfc2c; -rwip_env = 0x3fcdfc10; -rwip_param = 0x3fcdfc04; -rwip_prog_delay = 0x3fcdfc00; -rwip_rf = 0x3fcdfbc8; -sch_alarm_env = 0x3fcdfbc0; -sch_arb_env = 0x3fcdfbac; -sch_plan_env = 0x3fcdfba4; -sch_prog_env = 0x3fcdfaa0; -sch_slice_env = 0x3fcdfa40; -sch_slice_params = 0x3fcdfa38; -timer_env = 0x3fcdfa30; -unloaded_area = 0x3fcdfa2c; -vshci_state = 0x3fcdfa28; -TASK_DESC_LLC = 0x3fcdfa1c; -TASK_DESC_LLM = 0x3fcdfa10; -TASK_DESC_VSHCI = 0x3fcdfa04; -co_default_bdaddr = 0x3fcdf9fc; -dbg_assert_block = 0x3fcdf9f8; -g_bt_plf_log_level = 0x3fcdf9f4; -hci_cmd_desc_tab_vs_esp = 0x3fcdf9d0; -hci_command_handler_tab_esp = 0x3fcdf9b8; -privacy_en = 0x3fcdf9b4; -sdk_cfg_priv_opts = 0x3fcdf96c; -BasePoint_x_256 = 0x3ff1ffdc; -BasePoint_y_256 = 0x3ff1ffbc; -DebugE256PublicKey_x = 0x3ff1ff9c; -DebugE256PublicKey_y = 0x3ff1ff7c; -DebugE256SecretKey = 0x3ff1ff5c; -ECC_4Win_Look_up_table = 0x3ff1f7a0; -LLM_AA_CT1 = 0x3ff1f79c; -LLM_AA_CT2 = 0x3ff1f798; -RF_TX_PW_CONV_TBL = 0x3ff1f790; -TASK_DESC_MISC = 0x3ff1f784; -adv_evt_prop2type = 0x3ff1f768; -adv_evt_type2prop = 0x3ff1f760; -aes_cmac_zero = 0x3ff1f750; -aes_k2_salt = 0x3ff1f740; -aes_k3_id64 = 0x3ff1f738; -aes_k3_salt = 0x3ff1f728; -aes_k4_id6 = 0x3ff1f724; -aes_k4_salt = 0x3ff1f714; -bigHexP256 = 0x3ff1f6e8; -byte_tx_time = 0x3ff1f6e0; -co_null_bdaddr = 0x3ff1f6d8; -co_phy_mask_to_rate = 0x3ff1f6d0; -co_phy_mask_to_value = 0x3ff1f6c8; -co_phy_to_rate = 0x3ff1f6c4; -co_phy_value_to_mask = 0x3ff1f6c0; -co_rate_to_byte_dur_us = 0x3ff1f6b8; -co_rate_to_phy = 0x3ff1f6b0; -co_rate_to_phy_mask = 0x3ff1f6ac; -co_sca2ppm = 0x3ff1f69c; -coef_B = 0x3ff1f670; -connect_req_dur_tab = 0x3ff1f668; -ecc_Jacobian_InfinityPoint256 = 0x3ff1f5e4; -em_base_reg_lut = 0x3ff1f518; -fixed_tx_time = 0x3ff1f510; -h4tl_msgtype2hdrlen = 0x3ff1f508; -hci_cmd_desc_root_tab = 0x3ff1f4d8; -hci_cmd_desc_tab_ctrl_bb = 0x3ff1f46c; -hci_cmd_desc_tab_info_par = 0x3ff1f43c; -hci_cmd_desc_tab_le = 0x3ff1f0a0; -hci_cmd_desc_tab_lk_ctrl = 0x3ff1f088; -hci_cmd_desc_tab_stat_par = 0x3ff1f07c; -hci_cmd_desc_tab_vs = 0x3ff1f040; -hci_evt_desc_tab = 0x3ff1eff8; -hci_evt_le_desc_tab = 0x3ff1ef58; -hci_evt_le_desc_tab_esp = 0x3ff1ef50; -hci_rsvd_evt_msk = 0x3ff1ef48; -lld_aux_phy_to_rate = 0x3ff1ef44; -lld_init_max_aux_dur_tab = 0x3ff1ef3c; -lld_scan_map_legacy_pdu_to_evt_type = 0x3ff1ef34; -lld_scan_max_aux_dur_tab = 0x3ff1ef2c; -lld_sync_max_aux_dur_tab = 0x3ff1ef24; -llm_local_le_feats = 0x3ff1ef1c; -llm_local_le_states = 0x3ff1ef14; -llm_local_supp_cmds = 0x3ff1eeec; -maxSecretKey_256 = 0x3ff1eecc; -max_data_tx_time = 0x3ff1eec4; -one_bits = 0x3ff1eeb4; -rwip_coex_cfg = 0x3ff1eeac; -rwip_priority = 0x3ff1ee94; -veryBigHexP256 = 0x3ff1ee48; - - -/*************************************** - Group rom_pp - ***************************************/ - -/* Functions */ -esp_pp_rom_version_get = 0x400015ac; -RC_GetBlockAckTime = 0x400015b0; -ebuf_list_remove = 0x400015b4; -esf_buf_alloc = 0x400015b8; -esf_buf_alloc_dynamic = 0x400015bc; -esf_buf_recycle = 0x400015c0; -GetAccess = 0x400015c4; -hal_mac_is_low_rate_enabled = 0x400015c8; -hal_mac_tx_get_blockack = 0x400015cc; -hal_mac_tx_set_ppdu = 0x400015d0; -ic_get_trc = 0x400015d4; -ic_mac_deinit = 0x400015d8; -ic_mac_init = 0x400015dc; -ic_interface_enabled = 0x400015e0; -is_lmac_idle = 0x400015e4; -lmacAdjustTimestamp = 0x400015e8; -lmacDiscardAgedMSDU = 0x400015ec; -lmacDiscardMSDU = 0x400015f0; -lmacEndFrameExchangeSequence = 0x400015f4; -lmacIsIdle = 0x400015f8; -lmacIsLongFrame = 0x400015fc; -lmacMSDUAged = 0x40001600; -lmacPostTxComplete = 0x40001604; -lmacProcessAllTxTimeout = 0x40001608; -lmacProcessCollisions = 0x4000160c; -lmacProcessRxSucData = 0x40001610; -lmacReachLongLimit = 0x40001614; -lmacReachShortLimit = 0x40001618; -lmacRecycleMPDU = 0x4000161c; -lmacRxDone = 0x40001620; -lmacSetTxFrame = 0x40001624; -lmacTxDone = 0x40001628; -lmacTxFrame = 0x4000162c; -mac_tx_set_duration = 0x40001630; -mac_tx_set_htsig = 0x40001634; -mac_tx_set_plcp0 = 0x40001638; -mac_tx_set_plcp1 = 0x4000163c; -mac_tx_set_plcp2 = 0x40001640; -pm_check_state = 0x40001644; -pm_disable_dream_timer = 0x40001648; -pm_disable_sleep_delay_timer = 0x4000164c; -pm_dream = 0x40001650; -pm_mac_wakeup = 0x40001654; -pm_mac_sleep = 0x40001658; -pm_enable_active_timer = 0x4000165c; -pm_enable_sleep_delay_timer = 0x40001660; -pm_local_tsf_process = 0x40001664; -pm_set_beacon_filter = 0x40001668; -pm_is_in_wifi_slice_threshold = 0x4000166c; -pm_is_waked = 0x40001670; -pm_keep_alive = 0x40001674; -pm_on_beacon_rx = 0x40001678; -pm_on_data_rx = 0x4000167c; -pm_on_tbtt = 0x40001680; -pm_parse_beacon = 0x40001684; -pm_process_tim = 0x40001688; -pm_rx_beacon_process = 0x4000168c; -pm_rx_data_process = 0x40001690; -pm_sleep = 0x40001694; -pm_sleep_for = 0x40001698; -pm_tbtt_process = 0x4000169c; -ppAMPDU2Normal = 0x400016a0; -ppAssembleAMPDU = 0x400016a4; -ppCalFrameTimes = 0x400016a8; -ppCalSubFrameLength = 0x400016ac; -ppCalTxAMPDULength = 0x400016b0; -ppCheckTxAMPDUlength = 0x400016b4; -ppDequeueRxq_Locked = 0x400016b8; -ppDequeueTxQ = 0x400016bc; -ppEmptyDelimiterLength = 0x400016c0; -ppEnqueueRxq = 0x400016c4; -ppEnqueueTxDone = 0x400016c8; -ppGetTxQFirstAvail_Locked = 0x400016cc; -ppGetTxframe = 0x400016d0; -ppMapTxQueue = 0x400016d4; -ppProcTxSecFrame = 0x400016d8; -ppProcessRxPktHdr = 0x400016dc; -ppProcessTxQ = 0x400016e0; -ppRecordBarRRC = 0x400016e4; -lmacRequestTxopQueue = 0x400016e8; -lmacReleaseTxopQueue = 0x400016ec; -ppRecycleAmpdu = 0x400016f0; -ppRecycleRxPkt = 0x400016f4; -ppResortTxAMPDU = 0x400016f8; -ppResumeTxAMPDU = 0x400016fc; -ppRxFragmentProc = 0x40001700; -ppRxPkt = 0x40001704; -ppRxProtoProc = 0x40001708; -ppSearchTxQueue = 0x4000170c; -ppSearchTxframe = 0x40001710; -ppSelectNextQueue = 0x40001714; -ppSubFromAMPDU = 0x40001718; -ppTask = 0x4000171c; -ppTxPkt = 0x40001720; -ppTxProtoProc = 0x40001724; -ppTxqUpdateBitmap = 0x40001728; -pp_coex_tx_request = 0x4000172c; -pp_hdrsize = 0x40001730; -pp_post = 0x40001734; -pp_process_hmac_waiting_txq = 0x40001738; -rcGetAmpduSched = 0x4000173c; -rcUpdateRxDone = 0x40001740; -rc_get_trc = 0x40001744; -rc_get_trc_by_index = 0x40001748; -rcAmpduLowerRate = 0x4000174c; -rcampduuprate = 0x40001750; -rcClearCurAMPDUSched = 0x40001754; -rcClearCurSched = 0x40001758; -rcClearCurStat = 0x4000175c; -rcGetSched = 0x40001760; -rcLowerSched = 0x40001764; -rcSetTxAmpduLimit = 0x40001768; -rcTxUpdatePer = 0x4000176c; -rcUpdateAckSnr = 0x40001770; -rcUpdateRate = 0x40001774; -rcUpdateTxDone = 0x40001778; -rcUpdateTxDoneAmpdu2 = 0x4000177c; -rcUpSched = 0x40001780; -rssi_margin = 0x40001784; -rx11NRate2AMPDULimit = 0x40001788; -TRC_AMPDU_PER_DOWN_THRESHOLD = 0x4000178c; -TRC_AMPDU_PER_UP_THRESHOLD = 0x40001790; -trc_calc_duration = 0x40001794; -trc_isTxAmpduOperational = 0x40001798; -trc_onAmpduOp = 0x4000179c; -TRC_PER_IS_GOOD = 0x400017a0; -trc_SetTxAmpduState = 0x400017a4; -trc_tid_isTxAmpduOperational = 0x400017a8; -trcAmpduSetState = 0x400017ac; -wDevCheckBlockError = 0x400017b0; -wDev_AppendRxBlocks = 0x400017b4; -wDev_DiscardFrame = 0x400017b8; -wDev_GetNoiseFloor = 0x400017bc; -wDev_IndicateAmpdu = 0x400017c0; -wDev_IndicateFrame = 0x400017c4; -wdev_bank_store = 0x400017c8; -wdev_bank_load = 0x400017cc; -wdev_mac_reg_load = 0x400017d0; -wdev_mac_reg_store = 0x400017d4; -wdev_mac_special_reg_load = 0x400017d8; -wdev_mac_special_reg_store = 0x400017dc; -wdev_mac_wakeup = 0x400017e0; -wdev_mac_sleep = 0x400017e4; -hal_mac_is_dma_enable = 0x400017e8; -wDev_ProcessFiq = 0x400017ec; -wDev_ProcessRxSucData = 0x400017f0; -wdevProcessRxSucDataAll = 0x400017f4; -wdev_csi_len_align = 0x400017f8; -ppDequeueTxDone_Locked = 0x400017fc; -ppProcTxDone = 0x40001800; -pm_tx_data_done_process = 0x40001804; -config_is_cache_tx_buf_enabled = 0x40001808; -ppMapWaitTxq = 0x4000180c; -ppProcessWaitingQueue = 0x40001810; -ppDisableQueue = 0x40001814; -pm_allow_tx = 0x40001818; -/* Data (.data, .bss, .rodata) */ -our_instances_ptr = 0x3ff1ee44; -pTxRx = 0x3fcdf968; -lmacConfMib_ptr = 0x3fcdf964; -our_wait_eb = 0x3fcdf960; -our_tx_eb = 0x3fcdf95c; -pp_wdev_funcs = 0x3fcdf958; -g_osi_funcs_p = 0x3fcdf954; -wDevCtrl_ptr = 0x3fcdf950; -g_wdev_last_desc_reset_ptr = 0x3ff1ee40; -wDevMacSleep_ptr = 0x3fcdf94c; -g_lmac_cnt_ptr = 0x3fcdf948; -our_controls_ptr = 0x3ff1ee3c; -pp_sig_cnt_ptr = 0x3fcdf944; -g_eb_list_desc_ptr = 0x3fcdf940; -s_fragment_ptr = 0x3fcdf93c; -if_ctrl_ptr = 0x3fcdf938; -g_intr_lock_mux = 0x3fcdf934; -g_wifi_global_lock = 0x3fcdf930; -s_wifi_queue = 0x3fcdf92c; -pp_task_hdl = 0x3fcdf928; -s_pp_task_create_sem = 0x3fcdf924; -s_pp_task_del_sem = 0x3fcdf920; -g_wifi_menuconfig_ptr = 0x3fcdf91c; -xphyQueue = 0x3fcdf918; -ap_no_lr_ptr = 0x3fcdf914; -rc11BSchedTbl_ptr = 0x3fcdf910; -rc11NSchedTbl_ptr = 0x3fcdf90c; -rcLoRaSchedTbl_ptr = 0x3fcdf908; -BasicOFDMSched_ptr = 0x3fcdf904; -trc_ctl_ptr = 0x3fcdf900; -g_pm_cnt_ptr = 0x3fcdf8fc; -g_pm_ptr = 0x3fcdf8f8; -g_pm_cfg_ptr = 0x3fcdf8f4; -g_esp_mesh_quick_funcs_ptr = 0x3fcdf8f0; -g_txop_queue_status_ptr = 0x3fcdf8ec; -g_mac_sleep_en_ptr = 0x3fcdf8e8; -g_mesh_is_root_ptr = 0x3fcdf8e4; -g_mesh_topology_ptr = 0x3fcdf8e0; -g_mesh_init_ps_type_ptr = 0x3fcdf8dc; -g_mesh_is_started_ptr = 0x3fcdf8d8; -g_config_func = 0x3fcdf8d4; -g_net80211_tx_func = 0x3fcdf8d0; -g_timer_func = 0x3fcdf8cc; -s_michael_mic_failure_cb = 0x3fcdf8c8; -wifi_sta_rx_probe_req = 0x3fcdf8c4; -g_tx_done_cb_func = 0x3fcdf8c0; -g_per_conn_trc = 0x3fcdf874; -s_encap_amsdu_func = 0x3fcdf870; - - -/*************************************** - Group rom_net80211 - ***************************************/ - -/* Functions */ -esp_net80211_rom_version_get = 0x4000181c; -ampdu_dispatch = 0x40001820; -ampdu_dispatch_all = 0x40001824; -ampdu_dispatch_as_many_as_possible = 0x40001828; -ampdu_dispatch_movement = 0x4000182c; -ampdu_dispatch_upto = 0x40001830; -chm_is_at_home_channel = 0x40001834; -cnx_node_is_existing = 0x40001838; -cnx_node_search = 0x4000183c; -ic_ebuf_recycle_rx = 0x40001840; -ic_ebuf_recycle_tx = 0x40001844; -ic_reset_rx_ba = 0x40001848; -ieee80211_align_eb = 0x4000184c; -ieee80211_ampdu_reorder = 0x40001850; -ieee80211_ampdu_start_age_timer = 0x40001854; -ieee80211_encap_esfbuf = 0x40001858; -ieee80211_is_tx_allowed = 0x4000185c; -ieee80211_output_pending_eb = 0x40001860; -ieee80211_output_process = 0x40001864; -ieee80211_set_tx_desc = 0x40001868; -sta_input = 0x4000186c; -wifi_get_macaddr = 0x40001870; -wifi_rf_phy_disable = 0x40001874; -wifi_rf_phy_enable = 0x40001878; -ic_ebuf_alloc = 0x4000187c; -ieee80211_classify = 0x40001880; -ieee80211_copy_eb_header = 0x40001884; -ieee80211_recycle_cache_eb = 0x40001888; -ieee80211_search_node = 0x4000188c; -roundup2 = 0x40001890; -ieee80211_crypto_encap = 0x40001894; -ieee80211_crypto_decap = 0x40001898; -ieee80211_decap = 0x4000189c; -ieee80211_set_tx_pti = 0x400018a0; -wifi_is_started = 0x400018a4; -/* Data (.data, .bss, .rodata) */ -net80211_funcs = 0x3fcdf86c; -g_scan = 0x3fcdf868; -g_chm = 0x3fcdf864; -g_ic_ptr = 0x3fcdf860; -g_hmac_cnt_ptr = 0x3fcdf85c; -g_tx_cacheq_ptr = 0x3fcdf858; -s_netstack_free = 0x3fcdf854; -mesh_rxcb = 0x3fcdf850; -sta_rxcb = 0x3fcdf84c; - - -/*************************************** - Group rom_coexist - ***************************************/ - -/* Functions */ -esp_coex_rom_version_get = 0x400018a8; -coex_bt_release = 0x400018ac; -coex_bt_request = 0x400018b0; -coex_core_ble_conn_dyn_prio_get = 0x400018b4; -coex_core_event_duration_get = 0x400018b8; -coex_core_pti_get = 0x400018bc; -coex_core_release = 0x400018c0; -coex_core_request = 0x400018c4; -coex_core_status_get = 0x400018c8; -coex_core_timer_idx_get = 0x400018cc; -coex_event_duration_get = 0x400018d0; -coex_hw_timer_disable = 0x400018d4; -coex_hw_timer_enable = 0x400018d8; -coex_hw_timer_set = 0x400018dc; -coex_schm_interval_set = 0x400018e0; -coex_schm_lock = 0x400018e4; -coex_schm_unlock = 0x400018e8; -coex_status_get = 0x400018ec; -coex_wifi_release = 0x400018f0; -esp_coex_ble_conn_dynamic_prio_get = 0x400018f4; -/* Data (.data, .bss, .rodata) */ -coex_env_ptr = 0x3fcdf848; -coex_pti_tab_ptr = 0x3fcdf844; -coex_schm_env_ptr = 0x3fcdf840; -coexist_funcs = 0x3fcdf83c; -g_coa_funcs_p = 0x3fcdf838; -g_coex_param_ptr = 0x3fcdf834; - - -/*************************************** - Group rom_phy - ***************************************/ - -/* Functions */ -phy_get_romfuncs = 0x400018f8; -rom_abs_temp = 0x400018fc; -rom_bb_bss_cbw40_dig = 0x40001900; -rom_bb_wdg_test_en = 0x40001904; -rom_bb_wdt_get_status = 0x40001908; -rom_bb_wdt_int_enable = 0x4000190c; -rom_bb_wdt_rst_enable = 0x40001910; -rom_bb_wdt_timeout_clear = 0x40001914; -rom_cbw2040_cfg = 0x40001918; -rom_check_noise_floor = 0x4000191c; -rom_chip_i2c_readReg = 0x40001920; -rom_chip_i2c_writeReg = 0x40001924; -rom_correct_rf_ana_gain = 0x40001928; -rom_dc_iq_est = 0x4000192c; -rom_disable_agc = 0x40001930; -rom_en_pwdet = 0x40001934; -rom_enable_agc = 0x40001938; -rom_get_bbgain_db = 0x4000193c; -rom_get_data_sat = 0x40001940; -rom_get_i2c_read_mask = 0x40001944; -rom_get_pwctrl_correct = 0x40001948; -rom_get_rf_gain_qdb = 0x4000194c; -rom_i2c_readReg = 0x40001950; -rom_i2c_readReg_Mask = 0x40001954; -rom_i2c_writeReg = 0x40001958; -rom_i2c_writeReg_Mask = 0x4000195c; -rom_index_to_txbbgain = 0x40001960; -rom_iq_est_disable = 0x40001964; -rom_iq_est_enable = 0x40001968; -rom_linear_to_db = 0x4000196c; -rom_loopback_mode_en = 0x40001970; -rom_mhz2ieee = 0x40001974; -rom_noise_floor_auto_set = 0x40001978; -rom_pbus_debugmode = 0x4000197c; -rom_pbus_force_mode = 0x40001980; -rom_pbus_force_test = 0x40001984; -rom_pbus_rd = 0x40001988; -rom_pbus_rd_addr = 0x4000198c; -rom_pbus_rd_shift = 0x40001990; -rom_pbus_set_dco = 0x40001994; -rom_pbus_set_rxgain = 0x40001998; -rom_pbus_workmode = 0x4000199c; -rom_pbus_xpd_rx_off = 0x400019a0; -rom_pbus_xpd_rx_on = 0x400019a4; -rom_pbus_xpd_tx_off = 0x400019a8; -rom_pbus_xpd_tx_on = 0x400019ac; -rom_phy_byte_to_word = 0x400019b0; -rom_phy_disable_cca = 0x400019b4; -rom_phy_enable_cca = 0x400019b8; -rom_phy_get_noisefloor = 0x400019bc; -rom_phy_get_rx_freq = 0x400019c0; -rom_phy_set_bbfreq_init = 0x400019c4; -rom_pow_usr = 0x400019c8; -rom_pwdet_sar2_init = 0x400019cc; -rom_read_hw_noisefloor = 0x400019d0; -rom_read_sar_dout = 0x400019d4; -rom_set_cal_rxdc = 0x400019d8; -rom_set_chan_cal_interp = 0x400019dc; -rom_set_loopback_gain = 0x400019e0; -rom_set_noise_floor = 0x400019e4; -rom_set_rxclk_en = 0x400019e8; -rom_set_tx_dig_gain = 0x400019ec; -rom_set_txcap_reg = 0x400019f0; -rom_set_txclk_en = 0x400019f4; -rom_spur_cal = 0x400019f8; -rom_spur_reg_write_one_tone = 0x400019fc; -rom_target_power_add_backoff = 0x40001a00; -rom_tx_pwctrl_bg_init = 0x40001a04; -rom_txbbgain_to_index = 0x40001a08; -rom_wifi_11g_rate_chg = 0x40001a0c; -rom_write_gain_mem = 0x40001a10; -chip726_phyrom_version = 0x40001a14; -rom_disable_wifi_agc = 0x40001a18; -rom_enable_wifi_agc = 0x40001a1c; -rom_set_tx_gain_table = 0x40001a20; -rom_bt_index_to_bb = 0x40001a24; -rom_bt_bb_to_index = 0x40001a28; -rom_wr_bt_tx_atten = 0x40001a2c; -rom_wr_bt_tx_gain_mem = 0x40001a30; -rom_spur_coef_cfg = 0x40001a34; -rom_bb_bss_cbw40 = 0x40001a38; -rom_set_cca = 0x40001a3c; -rom_tx_paon_set = 0x40001a40; -rom_i2cmst_reg_init = 0x40001a44; -rom_iq_corr_enable = 0x40001a48; -rom_fe_reg_init = 0x40001a4c; -rom_agc_reg_init = 0x40001a50; -rom_bb_reg_init = 0x40001a54; -rom_mac_enable_bb = 0x40001a58; -rom_bb_wdg_cfg = 0x40001a5c; -rom_force_txon = 0x40001a60; -rom_fe_txrx_reset = 0x40001a64; -rom_set_rx_comp = 0x40001a68; -rom_set_pbus_reg = 0x40001a6c; -rom_write_chan_freq = 0x40001a70; -rom_phy_xpd_rf = 0x40001a74; -rom_set_xpd_sar = 0x40001a78; -rom_write_dac_gain2 = 0x40001a7c; -rom_rtc_sar2_init = 0x40001a80; -rom_get_target_power_offset = 0x40001a84; -rom_write_txrate_power_offset = 0x40001a88; -rom_get_rate_fcc_index = 0x40001a8c; -rom_get_rate_target_power = 0x40001a90; -rom_write_wifi_dig_gain = 0x40001a94; -rom_bt_correct_rf_ana_gain = 0x40001a98; -rom_pkdet_vol_start = 0x40001a9c; -rom_read_sar2_code = 0x40001aa0; -rom_get_sar2_vol = 0x40001aa4; -rom_get_pll_vol = 0x40001aa8; -rom_get_phy_target_power = 0x40001aac; -rom_temp_to_power = 0x40001ab0; -rom_phy_track_pll_cap = 0x40001ab4; -rom_phy_pwdet_always_en = 0x40001ab8; -rom_phy_pwdet_onetime_en = 0x40001abc; -rom_get_i2c_mst0_mask = 0x40001ac0; -rom_get_i2c_hostid = 0x40001ac4; -rom_enter_critical_phy = 0x40001ac8; -rom_exit_critical_phy = 0x40001acc; -rom_chip_i2c_readReg_org = 0x40001ad0; -rom_i2c_paral_set_mst0 = 0x40001ad4; -rom_i2c_paral_set_read = 0x40001ad8; -rom_i2c_paral_read = 0x40001adc; -rom_i2c_paral_write = 0x40001ae0; -rom_i2c_paral_write_num = 0x40001ae4; -rom_i2c_paral_write_mask = 0x40001ae8; -rom_bb_bss_cbw40_ana = 0x40001aec; -rom_chan_to_freq = 0x40001af0; -rom_open_i2c_xpd = 0x40001af4; -rom_dac_rate_set = 0x40001af8; -rom_tsens_read_init = 0x40001afc; -rom_tsens_code_read = 0x40001b00; -rom_tsens_index_to_dac = 0x40001b04; -rom_tsens_index_to_offset = 0x40001b08; -rom_tsens_dac_cal = 0x40001b0c; -rom_code_to_temp = 0x40001b10; -rom_write_pll_cap_mem = 0x40001b14; -rom_pll_correct_dcap = 0x40001b18; -rom_phy_en_hw_set_freq = 0x40001b1c; -rom_phy_dis_hw_set_freq = 0x40001b20; -rom_pll_vol_cal = 0x40001b24; - diff --git a/tools/esptool_py/flasher_stub/ld/rom_32h2.ld b/tools/esptool_py/flasher_stub/ld/rom_32h2.ld deleted file mode 100755 index accb0adcf5..0000000000 --- a/tools/esptool_py/flasher_stub/ld/rom_32h2.ld +++ /dev/null @@ -1,428 +0,0 @@ -/* ROM function interface esp32h2.rom.ld for esp32h2 - * - * - * Generated from ./target/esp32h2/interface-esp32h2.yml md5sum c0ad4e113e5b29bb9d799f10f03edbc1 - * - * Compatible with ROM where ECO version equal or greater to 0. - * - * THIS FILE WAS AUTOMATICALLY GENERATED. DO NOT EDIT. - */ - -/*************************************** - Group common - ***************************************/ - -PROVIDE ( SPIWrite = esp_rom_spiflash_write); -PROVIDE ( SPI_read_status_high = esp_rom_spiflash_read_statushigh); -PROVIDE ( SPI_write_status = esp_rom_spiflash_write_status); -PROVIDE ( SPIRead = esp_rom_spiflash_read); -PROVIDE ( SPIParamCfg = esp_rom_spiflash_config_param); -PROVIDE ( SPIEraseChip = esp_rom_spiflash_erase_chip); -PROVIDE ( SPIEraseSector = esp_rom_spiflash_erase_sector); -PROVIDE ( SPIEraseBlock = esp_rom_spiflash_erase_block); -PROVIDE ( SPI_Write_Encrypt_Enable = esp_rom_spiflash_write_encrypted_enable); -PROVIDE ( SPI_Write_Encrypt_Disable = esp_rom_spiflash_write_encrypted_disable); -PROVIDE ( SPI_Encrypt_Write = esp_rom_spiflash_write_encrypted); - -/*************************************** - Group common - ***************************************/ - -/* Functions */ -rtc_get_reset_reason = 0x40000018; -analog_super_wdt_reset_happened = 0x4000001c; -rtc_get_wakeup_cause = 0x40000020; -rtc_unhold_all_pads = 0x40000024; -ets_printf = 0x40000028; -ets_install_putc1 = 0x4000002c; -ets_install_putc2 = 0x40000030; -ets_install_uart_printf = 0x40000034; -ets_install_usb_printf = 0x40000038; -ets_get_printf_channel = 0x4000003c; -ets_delay_us = 0x40000040; -ets_get_cpu_frequency = 0x40000044; -ets_update_cpu_frequency = 0x40000048; -ets_install_lock = 0x4000004c; -UartRxString = 0x40000050; -UartGetCmdLn = 0x40000054; -uart_tx_one_char = 0x40000058; -uart_tx_one_char2 = 0x4000005c; -uart_rx_one_char = 0x40000060; -uart_rx_one_char_block = 0x40000064; -uart_rx_intr_handler = 0x40000068; -uart_rx_readbuff = 0x4000006c; -uartAttach = 0x40000070; -uart_tx_flush = 0x40000074; -uart_tx_wait_idle = 0x40000078; -uart_div_modify = 0x4000007c; -ets_write_char_uart = 0x40000080; -uart_tx_switch = 0x40000084; -roundup2 = 0x40000088; -multofup = 0x4000008c; -software_reset = 0x40000090; -software_reset_cpu = 0x40000094; -ets_clk_assist_debug_clock_enable = 0x40000098; -clear_super_wdt_reset_flag = 0x4000009c; -disable_default_watchdog = 0x400000a0; -esp_rom_set_rtc_wake_addr = 0x400000a4; -esp_rom_get_rtc_wake_addr = 0x400000a8; -send_packet = 0x400000ac; -recv_packet = 0x400000b0; -GetUartDevice = 0x400000b4; -UartDwnLdProc = 0x400000b8; -GetSecurityInfoProc = 0x400000bc; -Uart_Init = 0x400000c0; -ets_set_user_start = 0x400000c4; -/* Data (.data, .bss, .rodata) */ -ets_rom_layout_p = 0x4001fffc; -ets_ops_table_ptr = 0x4084fff8; -g_saved_pc = 0x4084fffc; - - -/*************************************** - Group miniz - ***************************************/ - -/* Functions */ -mz_adler32 = 0x400000c8; -mz_free = 0x400000cc; -tdefl_compress = 0x400000d0; -tdefl_compress_buffer = 0x400000d4; -tdefl_compress_mem_to_heap = 0x400000d8; -tdefl_compress_mem_to_mem = 0x400000dc; -tdefl_compress_mem_to_output = 0x400000e0; -tdefl_get_adler32 = 0x400000e4; -tdefl_get_prev_return_status = 0x400000e8; -tdefl_init = 0x400000ec; -tdefl_write_image_to_png_file_in_memory = 0x400000f0; -tdefl_write_image_to_png_file_in_memory_ex = 0x400000f4; -tinfl_decompress = 0x400000f8; -tinfl_decompress_mem_to_callback = 0x400000fc; -tinfl_decompress_mem_to_heap = 0x40000100; -tinfl_decompress_mem_to_mem = 0x40000104; - - -/*************************************** - Group spiflash_legacy - ***************************************/ - -/* Functions */ -esp_rom_spiflash_wait_idle = 0x40000108; -esp_rom_spiflash_write_encrypted = 0x4000010c; -esp_rom_spiflash_write_encrypted_dest = 0x40000110; -esp_rom_spiflash_write_encrypted_enable = 0x40000114; -esp_rom_spiflash_write_encrypted_disable = 0x40000118; -esp_rom_spiflash_erase_chip = 0x4000011c; -_esp_rom_spiflash_erase_sector = 0x40000120; -_esp_rom_spiflash_erase_block = 0x40000124; -_esp_rom_spiflash_write = 0x40000128; -_esp_rom_spiflash_read = 0x4000012c; -_esp_rom_spiflash_unlock = 0x40000130; -_SPIEraseArea = 0x40000134; -_SPI_write_enable = 0x40000138; -esp_rom_spiflash_erase_sector = 0x4000013c; -esp_rom_spiflash_erase_block = 0x40000140; -esp_rom_spiflash_write = 0x40000144; -esp_rom_spiflash_read = 0x40000148; -esp_rom_spiflash_unlock = 0x4000014c; -SPIEraseArea = 0x40000150; -SPI_write_enable = 0x40000154; -esp_rom_spiflash_config_param = 0x40000158; -esp_rom_spiflash_read_user_cmd = 0x4000015c; -esp_rom_spiflash_select_qio_pins = 0x40000160; -esp_rom_spi_flash_auto_sus_res = 0x40000164; -esp_rom_spi_flash_send_resume = 0x40000168; -esp_rom_spi_flash_update_id = 0x4000016c; -esp_rom_spiflash_config_clk = 0x40000170; -esp_rom_spiflash_config_readmode = 0x40000174; -esp_rom_spiflash_read_status = 0x40000178; -esp_rom_spiflash_read_statushigh = 0x4000017c; -esp_rom_spiflash_write_status = 0x40000180; -spi_cache_mode_switch = 0x40000184; -spi_common_set_dummy_output = 0x40000188; -spi_common_set_flash_cs_timing = 0x4000018c; -esp_rom_spi_set_address_bit_len = 0x40000190; -SPILock = 0x40000194; -SPIMasterReadModeCnfig = 0x40000198; -SPI_Common_Command = 0x4000019c; -SPI_WakeUp = 0x400001a0; -SPI_block_erase = 0x400001a4; -SPI_chip_erase = 0x400001a8; -SPI_init = 0x400001ac; -SPI_page_program = 0x400001b0; -SPI_read_data = 0x400001b4; -SPI_sector_erase = 0x400001b8; -SelectSpiFunction = 0x400001bc; -SetSpiDrvs = 0x400001c0; -Wait_SPI_Idle = 0x400001c4; -spi_dummy_len_fix = 0x400001c8; -Disable_QMode = 0x400001cc; -Enable_QMode = 0x400001d0; -spi_flash_attach = 0x400001d4; -spi_flash_get_chip_size = 0x400001d8; -spi_flash_guard_set = 0x400001dc; -spi_flash_guard_get = 0x400001e0; -spi_flash_read_encrypted = 0x400001e4; -/* Data (.data, .bss, .rodata) */ -rom_spiflash_legacy_funcs = 0x4084fff0; -rom_spiflash_legacy_data = 0x4084ffec; -g_flash_guard_ops = 0x4084fff4; - - -/*************************************** - Group hal_wdt - ***************************************/ - -/* Functions */ -wdt_hal_init = 0x4000038c; -wdt_hal_deinit = 0x40000390; -wdt_hal_config_stage = 0x40000394; -wdt_hal_write_protect_disable = 0x40000398; -wdt_hal_write_protect_enable = 0x4000039c; -wdt_hal_enable = 0x400003a0; -wdt_hal_disable = 0x400003a4; -wdt_hal_handle_intr = 0x400003a8; -wdt_hal_feed = 0x400003ac; -wdt_hal_set_flashboot_en = 0x400003b0; -wdt_hal_is_enabled = 0x400003b4; - - -/*************************************** - Group hal_systimer - ***************************************/ - -/* Functions */ -systimer_hal_init = 0x400003b8; -systimer_hal_deinit = 0x400003bc; -systimer_hal_set_tick_rate_ops = 0x400003c0; -systimer_hal_get_counter_value = 0x400003c4; -systimer_hal_get_time = 0x400003c8; -systimer_hal_set_alarm_target = 0x400003cc; -systimer_hal_set_alarm_period = 0x400003d0; -systimer_hal_get_alarm_value = 0x400003d4; -systimer_hal_enable_alarm_int = 0x400003d8; -systimer_hal_on_apb_freq_update = 0x400003dc; -systimer_hal_counter_value_advance = 0x400003e0; -systimer_hal_enable_counter = 0x400003e4; -systimer_hal_select_alarm_mode = 0x400003e8; -systimer_hal_connect_alarm_counter = 0x400003ec; -systimer_hal_counter_can_stall_by_cpu = 0x400003f0; - - -/*************************************** - Group cache - ***************************************/ - -/* Functions */ -Cache_Get_ICache_Line_Size = 0x400005fc; -Cache_Get_Mode = 0x40000600; -Cache_Address_Through_Cache = 0x40000604; -ROM_Boot_Cache_Init = 0x40000608; -MMU_Set_Page_Mode = 0x4000060c; -MMU_Get_Page_Mode = 0x40000610; -Cache_Invalidate_ICache_Items = 0x40000614; -Cache_Op_Addr = 0x40000618; -Cache_Invalidate_Addr = 0x4000061c; -Cache_Invalidate_ICache_All = 0x40000620; -Cache_Mask_All = 0x40000624; -Cache_UnMask_Dram0 = 0x40000628; -Cache_Suspend_ICache_Autoload = 0x4000062c; -Cache_Resume_ICache_Autoload = 0x40000630; -Cache_Start_ICache_Preload = 0x40000634; -Cache_ICache_Preload_Done = 0x40000638; -Cache_End_ICache_Preload = 0x4000063c; -Cache_Config_ICache_Autoload = 0x40000640; -Cache_Enable_ICache_Autoload = 0x40000644; -Cache_Disable_ICache_Autoload = 0x40000648; -Cache_Enable_ICache_PreLock = 0x4000064c; -Cache_Disable_ICache_PreLock = 0x40000650; -Cache_Lock_ICache_Items = 0x40000654; -Cache_Unlock_ICache_Items = 0x40000658; -Cache_Lock_Addr = 0x4000065c; -Cache_Unlock_Addr = 0x40000660; -Cache_Disable_ICache = 0x40000664; -Cache_Enable_ICache = 0x40000668; -Cache_Suspend_ICache = 0x4000066c; -Cache_Resume_ICache = 0x40000670; -Cache_Freeze_ICache_Enable = 0x40000674; -Cache_Freeze_ICache_Disable = 0x40000678; -Cache_Set_IDROM_MMU_Size = 0x4000067c; -Cache_Get_IROM_MMU_End = 0x40000680; -Cache_Get_DROM_MMU_End = 0x40000684; -Cache_MMU_Init = 0x40000688; -Cache_MSPI_MMU_Set = 0x4000068c; -Cache_Travel_Tag_Memory = 0x40000690; -Cache_Get_Virtual_Addr = 0x40000694; -/* Data (.data, .bss, .rodata) */ -rom_cache_op_cb = 0x4084ffcc; -rom_cache_internal_table_ptr = 0x4084ffc8; - - -/*************************************** - Group clock - ***************************************/ - -/* Functions */ -ets_clk_get_xtal_freq = 0x40000698; -ets_clk_get_cpu_freq = 0x4000069c; - - -/*************************************** - Group gpio - ***************************************/ - -/* Functions */ -gpio_input_get = 0x400006a0; -gpio_matrix_in = 0x400006a4; -gpio_matrix_out = 0x400006a8; -gpio_output_disable = 0x400006ac; -gpio_output_enable = 0x400006b0; -gpio_output_set = 0x400006b4; -gpio_pad_hold = 0x400006b8; -gpio_pad_input_disable = 0x400006bc; -gpio_pad_input_enable = 0x400006c0; -gpio_pad_pulldown = 0x400006c4; -gpio_pad_pullup = 0x400006c8; -gpio_pad_select_gpio = 0x400006cc; -gpio_pad_set_drv = 0x400006d0; -gpio_pad_unhold = 0x400006d4; -gpio_pin_wakeup_disable = 0x400006d8; -gpio_pin_wakeup_enable = 0x400006dc; -gpio_bypass_matrix_in = 0x400006e0; - - -/*************************************** - Group interrupts - ***************************************/ - -/* Functions */ -esprv_intc_int_set_priority = 0x400006e4; -esprv_intc_int_set_threshold = 0x400006e8; -esprv_intc_int_enable = 0x400006ec; -esprv_intc_int_disable = 0x400006f0; -esprv_intc_int_set_type = 0x400006f4; -PROVIDE( intr_handler_set = 0x400006f8 ); -intr_matrix_set = 0x400006fc; -ets_intr_lock = 0x40000700; -ets_intr_unlock = 0x40000704; -ets_isr_attach = 0x40000708; -ets_isr_mask = 0x4000070c; -ets_isr_unmask = 0x40000710; - - -/*************************************** - Group crypto - ***************************************/ - -/* Functions */ -md5_vector = 0x40000714; -MD5Init = 0x40000718; -MD5Update = 0x4000071c; -MD5Final = 0x40000720; -crc32_le = 0x40000724; -crc16_le = 0x40000728; -crc8_le = 0x4000072c; -crc32_be = 0x40000730; -crc16_be = 0x40000734; -crc8_be = 0x40000738; -esp_crc8 = 0x4000073c; -ets_sha_enable = 0x40000740; -ets_sha_disable = 0x40000744; -ets_sha_get_state = 0x40000748; -ets_sha_init = 0x4000074c; -ets_sha_process = 0x40000750; -ets_sha_starts = 0x40000754; -ets_sha_update = 0x40000758; -ets_sha_finish = 0x4000075c; -ets_sha_clone = 0x40000760; -ets_hmac_enable = 0x40000764; -ets_hmac_disable = 0x40000768; -ets_hmac_calculate_message = 0x4000076c; -ets_hmac_calculate_downstream = 0x40000770; -ets_hmac_invalidate_downstream = 0x40000774; -ets_jtag_enable_temporarily = 0x40000778; -ets_aes_enable = 0x4000077c; -ets_aes_disable = 0x40000780; -ets_aes_setkey = 0x40000784; -ets_aes_block = 0x40000788; -ets_aes_setkey_dec = 0x4000078c; -ets_aes_setkey_enc = 0x40000790; -ets_bigint_enable = 0x40000794; -ets_bigint_disable = 0x40000798; -ets_bigint_multiply = 0x4000079c; -ets_bigint_modmult = 0x400007a0; -ets_bigint_modexp = 0x400007a4; -ets_bigint_wait_finish = 0x400007a8; -ets_bigint_getz = 0x400007ac; -ets_ds_enable = 0x400007b0; -ets_ds_disable = 0x400007b4; -ets_ds_start_sign = 0x400007b8; -ets_ds_is_busy = 0x400007bc; -ets_ds_finish_sign = 0x400007c0; -ets_ds_encrypt_params = 0x400007c4; -ets_mgf1_sha256 = 0x400007c8; -/* Data (.data, .bss, .rodata) */ -crc32_le_table_ptr = 0x4001fff8; -crc16_le_table_ptr = 0x4001fff4; -crc8_le_table_ptr = 0x4001fff0; -crc32_be_table_ptr = 0x4001ffec; -crc16_be_table_ptr = 0x4001ffe8; -crc8_be_table_ptr = 0x4001ffe4; - - -/*************************************** - Group efuse - ***************************************/ - -/* Functions */ -ets_efuse_read = 0x400007cc; -ets_efuse_program = 0x400007d0; -ets_efuse_clear_program_registers = 0x400007d4; -ets_efuse_write_key = 0x400007d8; -ets_efuse_get_read_register_address = 0x400007dc; -ets_efuse_get_key_purpose = 0x400007e0; -ets_efuse_key_block_unused = 0x400007e4; -ets_efuse_find_unused_key_block = 0x400007e8; -ets_efuse_rs_calculate = 0x400007ec; -ets_efuse_count_unused_key_blocks = 0x400007f0; -ets_efuse_secure_boot_enabled = 0x400007f4; -ets_efuse_secure_boot_aggressive_revoke_enabled = 0x400007f8; -ets_efuse_cache_encryption_enabled = 0x400007fc; -ets_efuse_download_modes_disabled = 0x40000800; -ets_efuse_find_purpose = 0x40000804; -ets_efuse_force_send_resume = 0x40000808; -ets_efuse_get_flash_delay_us = 0x4000080c; -ets_efuse_get_mac = 0x40000810; -ets_efuse_get_uart_print_control = 0x40000814; -ets_efuse_direct_boot_mode_disabled = 0x40000818; -ets_efuse_security_download_modes_enabled = 0x4000081c; -ets_efuse_jtag_disabled = 0x40000820; -ets_efuse_usb_print_is_disabled = 0x40000824; -ets_efuse_usb_download_mode_disabled = 0x40000828; -ets_efuse_usb_device_disabled = 0x4000082c; -ets_efuse_secure_boot_fast_wake_enabled = 0x40000830; - - -/*************************************** - Group secureboot - ***************************************/ - -/* Functions */ -ets_emsa_pss_verify = 0x40000834; -ets_rsa_pss_verify = 0x40000838; -ets_ecdsa_verify = 0x4000083c; -ets_secure_boot_verify_bootloader_with_keys = 0x40000840; -ets_secure_boot_verify_signature = 0x40000844; -ets_secure_boot_read_key_digests = 0x40000848; -ets_secure_boot_revoke_public_key_digest = 0x4000084c; - - -/*************************************** - Group usb_device_uart - ***************************************/ - -/* Functions */ -usb_serial_device_rx_one_char = 0x400009c0; -usb_serial_device_rx_one_char_block = 0x400009c4; -usb_serial_device_tx_flush = 0x400009c8; -usb_serial_device_tx_one_char = 0x400009cc; diff --git a/tools/esptool_py/flasher_stub/ld/rom_32h2_beta_1.ld b/tools/esptool_py/flasher_stub/ld/rom_32h2_beta_1.ld deleted file mode 100644 index f05eed2127..0000000000 --- a/tools/esptool_py/flasher_stub/ld/rom_32h2_beta_1.ld +++ /dev/null @@ -1,731 +0,0 @@ -/* ROM function interface esp32h2.rom.ld for esp32h2 - * - * - * Generated from ./interface-esp32b1z.yml md5sum a8cce65aa1422e5781ad0d729ef0a0a6 - * - * Compatible with ROM where ECO version equal or greater to 0. - * - * THIS FILE WAS AUTOMATICALLY GENERATED. DO NOT EDIT. - */ - - -PROVIDE ( SPIWrite = esp_rom_spiflash_write); -PROVIDE ( SPI_read_status_high = esp_rom_spiflash_read_statushigh); -PROVIDE ( SPI_write_status = esp_rom_spiflash_write_status); -PROVIDE ( SPIRead = esp_rom_spiflash_read); -PROVIDE ( SPIParamCfg = esp_rom_spiflash_config_param); -PROVIDE ( SPIEraseChip = esp_rom_spiflash_erase_chip); -PROVIDE ( SPIEraseSector = esp_rom_spiflash_erase_sector); -PROVIDE ( SPIEraseBlock = esp_rom_spiflash_erase_block); -PROVIDE ( SPI_Write_Encrypt_Enable = esp_rom_spiflash_write_encrypted_enable); -PROVIDE ( SPI_Write_Encrypt_Disable = esp_rom_spiflash_write_encrypted_disable); -PROVIDE ( SPI_Encrypt_Write = esp_rom_spiflash_write_encrypted); - - -/*************************************** - Group common - ***************************************/ - -/* Functions */ -rtc_get_reset_reason = 0x40000018; -analog_super_wdt_reset_happened = 0x4000001c; -jtag_cpu_reset_happened = 0x40000020; -rtc_get_wakeup_cause = 0x40000024; -rtc_select_apb_bridge = 0x40000028; -rtc_unhold_all_pads = 0x4000002c; -ets_is_print_boot = 0x40000030; -ets_printf = 0x40000034; -ets_install_putc1 = 0x40000038; -ets_install_uart_printf = 0x4000003c; -ets_install_putc2 = 0x40000040; -PROVIDE( ets_delay_us = 0x40000044 ); -ets_get_stack_info = 0x40000048; -ets_install_lock = 0x4000004c; -ets_backup_dma_copy = 0x40000050; -ets_apb_backup_init_lock_func = 0x40000054; -UartRxString = 0x40000058; -uart_tx_one_char = 0x4000005c; -uart_tx_one_char2 = 0x40000060; -uart_rx_one_char = 0x40000064; -uart_rx_one_char_block = 0x40000068; -uart_rx_readbuff = 0x4000006c; -uartAttach = 0x40000070; -uart_tx_flush = 0x40000074; -uart_tx_wait_idle = 0x40000078; -uart_div_modify = 0x4000007c; -multofup = 0x40000080; -software_reset = 0x40000084; -software_reset_cpu = 0x40000088; -assist_debug_clock_enable = 0x4000008c; -assist_debug_record_enable = 0x40000090; -clear_super_wdt_reset_flag = 0x40000094; -disable_default_watchdog = 0x40000098; -esp_rom_set_rtc_wake_addr = 0x4000009c; -esp_rom_get_rtc_wake_addr = 0x400000a0; -send_packet = 0x400000a4; -recv_packet = 0x400000a8; -GetUartDevice = 0x400000ac; -GetSecurityInfoProc = 0x400120b2; -UartDwnLdProc = 0x400000b0; -Uart_Init = 0x400000b4; -ets_set_user_start = 0x400000b8; -/* Data (.data, .bss, .rodata) */ -ets_rom_layout_p = 0x3ff1fffc; -ets_ops_table_ptr = 0x3fcdfffc; - - -/*************************************** - Group miniz - ***************************************/ - -/* Functions */ -mz_adler32 = 0x400000bc; -mz_crc32 = 0x400000c0; -mz_free = 0x400000c4; -tdefl_compress = 0x400000c8; -tdefl_compress_buffer = 0x400000cc; -tdefl_compress_mem_to_heap = 0x400000d0; -tdefl_compress_mem_to_mem = 0x400000d4; -tdefl_compress_mem_to_output = 0x400000d8; -tdefl_get_adler32 = 0x400000dc; -tdefl_get_prev_return_status = 0x400000e0; -tdefl_init = 0x400000e4; -tdefl_write_image_to_png_file_in_memory = 0x400000e8; -tdefl_write_image_to_png_file_in_memory_ex = 0x400000ec; -tinfl_decompress = 0x400000f0; -tinfl_decompress_mem_to_callback = 0x400000f4; -tinfl_decompress_mem_to_heap = 0x400000f8; -tinfl_decompress_mem_to_mem = 0x400000fc; - - -/*************************************** - Group tjpgd - ***************************************/ - -/* Functions */ -jd_prepare = 0x40000100; -jd_decomp = 0x40000104; - - -/*************************************** - Group esp-dsp - ***************************************/ - -/* Data (.data, .bss, .rodata) */ -dsps_fft2r_w_table_fc32_1024 = 0x3fcdfff8; - - -/*************************************** - Group spiflash_legacy - ***************************************/ - -/* Functions */ -PROVIDE( esp_rom_spiflash_wait_idle = 0x40000108 ); -PROVIDE( esp_rom_spiflash_write_encrypted = 0x4000010c ); -PROVIDE( esp_rom_spiflash_write_encrypted_dest = 0x40000110 ); -PROVIDE( esp_rom_spiflash_write_encrypted_enable = 0x40000114 ); -PROVIDE( esp_rom_spiflash_write_encrypted_disable = 0x40000118 ); -PROVIDE( esp_rom_spiflash_erase_chip = 0x4000011c ); -PROVIDE( esp_rom_spiflash_erase_block = 0x40000120 ); -PROVIDE( esp_rom_spiflash_erase_sector = 0x40000124 ); -PROVIDE( esp_rom_spiflash_write = 0x40000128 ); -PROVIDE( esp_rom_spiflash_read = 0x4000012c ); -PROVIDE( esp_rom_spiflash_config_param = 0x40000130 ); -PROVIDE( esp_rom_spiflash_read_user_cmd = 0x40000134 ); -PROVIDE( esp_rom_spiflash_select_qio_pins = 0x40000138 ); -PROVIDE( esp_rom_spiflash_unlock = 0x4000013c ); -PROVIDE( esp_rom_spi_flash_auto_sus_res = 0x40000140 ); -PROVIDE( esp_rom_spi_flash_send_resume = 0x40000144 ); -PROVIDE( esp_rom_spi_flash_update_id = 0x40000148 ); -PROVIDE( esp_rom_spiflash_config_clk = 0x4000014c ); -PROVIDE( esp_rom_spiflash_config_readmode = 0x40000150 ); -PROVIDE( esp_rom_spiflash_read_status = 0x40000154 ); -PROVIDE( esp_rom_spiflash_read_statushigh = 0x40000158 ); -PROVIDE( esp_rom_spiflash_write_status = 0x4000015c ); -PROVIDE( spi_flash_attach = 0x40000160 ); -PROVIDE( spi_flash_get_chip_size = 0x40000164 ); -PROVIDE( spi_flash_guard_set = 0x40000168 ); -PROVIDE( spi_flash_guard_get = 0x4000016c ); -PROVIDE( spi_flash_write_config_set = 0x40000170 ); -PROVIDE( spi_flash_write_config_get = 0x40000174 ); -PROVIDE( spi_flash_safe_write_address_func_set = 0x40000178 ); -PROVIDE( spi_flash_unlock = 0x4000017c ); -PROVIDE( spi_flash_erase_range = 0x40000180 ); -PROVIDE( spi_flash_erase_sector = 0x40000184 ); -PROVIDE( spi_flash_write = 0x40000188 ); -PROVIDE( spi_flash_read = 0x4000018c ); -PROVIDE( spi_flash_write_encrypted = 0x40000190 ); -PROVIDE( spi_flash_read_encrypted = 0x40000194 ); -PROVIDE( spi_flash_mmap_os_func_set = 0x40000198 ); -PROVIDE( spi_flash_mmap_page_num_init = 0x4000019c ); -PROVIDE( spi_flash_mmap = 0x400001a0 ); -PROVIDE( spi_flash_mmap_pages = 0x400001a4 ); -PROVIDE( spi_flash_munmap = 0x400001a8 ); -PROVIDE( spi_flash_mmap_dump = 0x400001ac ); -PROVIDE( spi_flash_check_and_flush_cache = 0x400001b0 ); -PROVIDE( spi_flash_mmap_get_free_pages = 0x400001b4 ); -PROVIDE( spi_flash_cache2phys = 0x400001b8 ); -PROVIDE( spi_flash_phys2cache = 0x400001bc ); -PROVIDE( spi_flash_disable_cache = 0x400001c0 ); -PROVIDE( spi_flash_restore_cache = 0x400001c4 ); -PROVIDE( spi_flash_cache_enabled = 0x400001c8 ); -PROVIDE( spi_flash_enable_cache = 0x400001cc ); -PROVIDE( spi_cache_mode_switch = 0x400001d0 ); -PROVIDE( spi_common_set_dummy_output = 0x400001d4 ); -PROVIDE( spi_common_set_flash_cs_timing = 0x400001d8 ); -PROVIDE( esp_enable_cache_flash_wrap = 0x400001dc ); -PROVIDE( SPIEraseArea = 0x400001e0 ); -PROVIDE( SPILock = 0x400001e4 ); -PROVIDE( SPIMasterReadModeCnfig = 0x400001e8 ); -PROVIDE( SPI_Common_Command = 0x400001ec ); -PROVIDE( SPI_WakeUp = 0x400001f0 ); -PROVIDE( SPI_block_erase = 0x400001f4 ); -PROVIDE( SPI_chip_erase = 0x400001f8 ); -PROVIDE( SPI_init = 0x400001fc ); -PROVIDE( SPI_page_program = 0x40000200 ); -PROVIDE( SPI_read_data = 0x40000204 ); -PROVIDE( SPI_sector_erase = 0x40000208 ); -PROVIDE( SPI_write_enable = 0x4000020c ); -PROVIDE( SelectSpiFunction = 0x40000210 ); -PROVIDE( SetSpiDrvs = 0x40000214 ); -PROVIDE( Wait_SPI_Idle = 0x40000218 ); -PROVIDE( spi_dummy_len_fix = 0x4000021c ); -PROVIDE( Disable_QMode = 0x40000220 ); -PROVIDE( Enable_QMode = 0x40000224 ); -/* Data (.data, .bss, .rodata) */ -PROVIDE( rom_spiflash_legacy_funcs = 0x3fcdfff0 ); -PROVIDE( rom_spiflash_legacy_data = 0x3fcdffec ); -PROVIDE( g_flash_guard_ops = 0x3fcdfff4 ); - - -/*************************************** - Group hal_soc - ***************************************/ - -/* Functions */ -PROVIDE( spi_flash_hal_poll_cmd_done = 0x40000228 ); -PROVIDE( spi_flash_hal_device_config = 0x4000022c ); -PROVIDE( spi_flash_hal_configure_host_io_mode = 0x40000230 ); -PROVIDE( spi_flash_hal_common_command = 0x40000234 ); -PROVIDE( spi_flash_hal_read = 0x40000238 ); -PROVIDE( spi_flash_hal_erase_chip = 0x4000023c ); -PROVIDE( spi_flash_hal_erase_sector = 0x40000240 ); -PROVIDE( spi_flash_hal_erase_block = 0x40000244 ); -PROVIDE( spi_flash_hal_program_page = 0x40000248 ); -PROVIDE( spi_flash_hal_set_write_protect = 0x4000024c ); -PROVIDE( spi_flash_hal_host_idle = 0x40000250 ); - - -/*************************************** - Group spi_flash_chips - ***************************************/ - -/* Functions */ -PROVIDE( spi_flash_chip_generic_probe = 0x40000254 ); -PROVIDE( spi_flash_chip_generic_detect_size = 0x40000258 ); -PROVIDE( spi_flash_chip_generic_write = 0x4000025c ); -PROVIDE( spi_flash_chip_generic_write_encrypted = 0x40000260 ); -PROVIDE( spi_flash_chip_generic_set_write_protect = 0x40000264 ); -PROVIDE( spi_flash_common_write_status_16b_wrsr = 0x40000268 ); -PROVIDE( spi_flash_chip_generic_reset = 0x4000026c ); -PROVIDE( spi_flash_chip_generic_erase_chip = 0x40000270 ); -PROVIDE( spi_flash_chip_generic_erase_sector = 0x40000274 ); -PROVIDE( spi_flash_chip_generic_erase_block = 0x40000278 ); -PROVIDE( spi_flash_chip_generic_page_program = 0x4000027c ); -PROVIDE( spi_flash_chip_generic_get_write_protect = 0x40000280 ); -PROVIDE( spi_flash_common_read_status_16b_rdsr_rdsr2 = 0x40000284 ); -PROVIDE( spi_flash_chip_generic_read_reg = 0x40000288 ); -PROVIDE( spi_flash_chip_generic_yield = 0x4000028c ); -PROVIDE( spi_flash_generic_wait_host_idle = 0x40000290 ); -PROVIDE( spi_flash_chip_generic_wait_idle = 0x40000294 ); -PROVIDE( spi_flash_chip_generic_config_host_io_mode = 0x40000298 ); -PROVIDE( spi_flash_chip_generic_read = 0x4000029c ); -PROVIDE( spi_flash_common_read_status_8b_rdsr2 = 0x400002a0 ); -PROVIDE( spi_flash_chip_generic_get_io_mode = 0x400002a4 ); -PROVIDE( spi_flash_common_read_status_8b_rdsr = 0x400002a8 ); -PROVIDE( spi_flash_common_write_status_8b_wrsr = 0x400002ac ); -PROVIDE( spi_flash_common_write_status_8b_wrsr2 = 0x400002b0 ); -PROVIDE( spi_flash_common_set_io_mode = 0x400002b4 ); -PROVIDE( spi_flash_chip_generic_set_io_mode = 0x400002b8 ); -PROVIDE( spi_flash_chip_gd_get_io_mode = 0x400002bc ); -PROVIDE( spi_flash_chip_gd_probe = 0x400002c0 ); -PROVIDE( spi_flash_chip_gd_set_io_mode = 0x400002c4 ); -/* Data (.data, .bss, .rodata) */ -PROVIDE( spi_flash_chip_generic_config_data = 0x3fcdffe8 ); - - -/*************************************** - Group memspi_host - ***************************************/ - -/* Functions */ -PROVIDE( memspi_host_read_id_hs = 0x400002c8 ); -PROVIDE( memspi_host_read_status_hs = 0x400002cc ); -PROVIDE( memspi_host_flush_cache = 0x400002d0 ); -PROVIDE( memspi_host_erase_chip = 0x400002d4 ); -PROVIDE( memspi_host_erase_sector = 0x400002d8 ); -PROVIDE( memspi_host_erase_block = 0x400002dc ); -PROVIDE( memspi_host_program_page = 0x400002e0 ); -PROVIDE( memspi_host_read = 0x400002e4 ); -PROVIDE( memspi_host_set_write_protect = 0x400002e8 ); -PROVIDE( memspi_host_set_max_read_len = 0x400002ec ); -PROVIDE( memspi_host_read_data_slicer = 0x400002f0 ); -PROVIDE( memspi_host_write_data_slicer = 0x400002f4 ); - - -/*************************************** - Group esp_flash - ***************************************/ - -/* Functions */ -PROVIDE( esp_flash_chip_driver_initialized = 0x400002f8 ); -PROVIDE( esp_flash_read_id = 0x400002fc ); -PROVIDE( esp_flash_get_size = 0x40000300 ); -PROVIDE( esp_flash_erase_chip = 0x40000304 ); -PROVIDE( esp_flash_erase_region = 0x40000308 ); -PROVIDE( esp_flash_get_chip_write_protect = 0x4000030c ); -PROVIDE( esp_flash_set_chip_write_protect = 0x40000310 ); -PROVIDE( esp_flash_get_protectable_regions = 0x40000314 ); -PROVIDE( esp_flash_get_protected_region = 0x40000318 ); -PROVIDE( esp_flash_set_protected_region = 0x4000031c ); -PROVIDE( esp_flash_read = 0x40000320 ); -PROVIDE( esp_flash_write = 0x40000324 ); -PROVIDE( esp_flash_write_encrypted = 0x40000328 ); -PROVIDE( esp_flash_read_encrypted = 0x4000032c ); -PROVIDE( esp_flash_get_io_mode = 0x40000330 ); -PROVIDE( esp_flash_set_io_mode = 0x40000334 ); -PROVIDE( spi_flash_boot_attach = 0x40000338 ); -PROVIDE( spi_flash_dump_counters = 0x4000033c ); -PROVIDE( spi_flash_get_counters = 0x40000340 ); -PROVIDE( spi_flash_op_counters_config = 0x40000344 ); -PROVIDE( spi_flash_reset_counters = 0x40000348 ); -PROVIDE( esp_flash_read_chip_id = 0x4000034c ); -PROVIDE( detect_spi_flash_chip = 0x40000350 ); -PROVIDE( esp_rom_spiflash_write_disable = 0x40000354 ); -/* Data (.data, .bss, .rodata) */ -PROVIDE( esp_flash_default_chip = 0x3fcdffe4 ); -PROVIDE( esp_flash_api_funcs = 0x3fcdffe0 ); - - -/*************************************** - Group cache - ***************************************/ - -/* Functions */ -PROVIDE( Cache_Get_ICache_Line_Size = 0x400004b8 ); -PROVIDE( Cache_Get_Mode = 0x400004bc ); -PROVIDE( Cache_Address_Through_IBus = 0x400004c0 ); -PROVIDE( Cache_Address_Through_DBus = 0x400004c4 ); -PROVIDE( Cache_Set_Default_Mode = 0x400004c8 ); -PROVIDE( Cache_Enable_Defalut_ICache_Mode = 0x400004cc ); -PROVIDE( ROM_Boot_Cache_Init = 0x400004d0 ); -PROVIDE( Cache_Invalidate_ICache_Items = 0x400004d4 ); -PROVIDE( Cache_Op_Addr = 0x400004d8 ); -PROVIDE( Cache_Invalidate_Addr = 0x400004dc ); -PROVIDE( Cache_Invalidate_ICache_All = 0x400004e0 ); -PROVIDE( Cache_Mask_All = 0x400004e4 ); -PROVIDE( Cache_UnMask_Dram0 = 0x400004e8 ); -PROVIDE( Cache_Suspend_ICache_Autoload = 0x400004ec ); -PROVIDE( Cache_Resume_ICache_Autoload = 0x400004f0 ); -PROVIDE( Cache_Start_ICache_Preload = 0x400004f4 ); -PROVIDE( Cache_ICache_Preload_Done = 0x400004f8 ); -PROVIDE( Cache_End_ICache_Preload = 0x400004fc ); -PROVIDE( Cache_Config_ICache_Autoload = 0x40000500 ); -PROVIDE( Cache_Enable_ICache_Autoload = 0x40000504 ); -PROVIDE( Cache_Disable_ICache_Autoload = 0x40000508 ); -PROVIDE( Cache_Enable_ICache_PreLock = 0x4000050c ); -PROVIDE( Cache_Disable_ICache_PreLock = 0x40000510 ); -PROVIDE( Cache_Lock_ICache_Items = 0x40000514 ); -PROVIDE( Cache_Unlock_ICache_Items = 0x40000518 ); -PROVIDE( Cache_Lock_Addr = 0x4000051c ); -PROVIDE( Cache_Unlock_Addr = 0x40000520 ); -PROVIDE( Cache_Disable_ICache = 0x40000524 ); -PROVIDE( Cache_Enable_ICache = 0x40000528 ); -PROVIDE( Cache_Suspend_ICache = 0x4000052c ); -PROVIDE( Cache_Resume_ICache = 0x40000530 ); -PROVIDE( Cache_Freeze_ICache_Enable = 0x40000534 ); -PROVIDE( Cache_Freeze_ICache_Disable = 0x40000538 ); -PROVIDE( Cache_Pms_Lock = 0x4000053c ); -PROVIDE( Cache_Ibus_Pms_Set_Addr = 0x40000540 ); -PROVIDE( Cache_Ibus_Pms_Set_Attr = 0x40000544 ); -PROVIDE( Cache_Dbus_Pms_Set_Addr = 0x40000548 ); -PROVIDE( Cache_Dbus_Pms_Set_Attr = 0x4000054c ); -PROVIDE( Cache_Set_IDROM_MMU_Size = 0x40000550 ); -PROVIDE( Cache_Get_IROM_MMU_End = 0x40000554 ); -PROVIDE( Cache_Get_DROM_MMU_End = 0x40000558 ); -PROVIDE( Cache_Owner_Init = 0x4000055c ); -PROVIDE( Cache_Occupy_ICache_MEMORY = 0x40000560 ); -PROVIDE( Cache_MMU_Init = 0x40000564 ); -PROVIDE( Cache_Ibus_MMU_Set = 0x40000568 ); -PROVIDE( Cache_Dbus_MMU_Set = 0x4000056c ); -PROVIDE( Cache_Count_Flash_Pages = 0x40000570 ); -PROVIDE( Cache_Travel_Tag_Memory = 0x40000574 ); -PROVIDE( Cache_Get_Virtual_Addr = 0x40000578 ); -PROVIDE( Cache_Get_Memory_BaseAddr = 0x4000057c ); -PROVIDE( Cache_Get_Memory_Addr = 0x40000580 ); -PROVIDE( Cache_Get_Memory_value = 0x40000584 ); -/* Data (.data, .bss, .rodata) */ -PROVIDE( rom_cache_op_cb = 0x3fcdffd4 ); -PROVIDE( rom_cache_internal_table_ptr = 0x3fcdffd0 ); - - -/*************************************** - Group clock - ***************************************/ - -/* Functions */ -ets_get_apb_freq = 0x40000588; -ets_get_cpu_frequency = 0x4000058c; -ets_update_cpu_frequency = 0x40000590; -ets_get_printf_channel = 0x40000594; -ets_get_xtal_div = 0x40000598; -ets_set_xtal_div = 0x4000059c; -ets_get_xtal_freq = 0x400005a0; - - -/*************************************** - Group gpio - ***************************************/ - -/* Functions */ -gpio_input_get = 0x400005a4; -gpio_matrix_in = 0x400005a8; -gpio_matrix_out = 0x400005ac; -gpio_output_disable = 0x400005b0; -gpio_output_enable = 0x400005b4; -gpio_output_set = 0x400005b8; -gpio_pad_hold = 0x400005bc; -gpio_pad_input_disable = 0x400005c0; -gpio_pad_input_enable = 0x400005c4; -gpio_pad_pulldown = 0x400005c8; -gpio_pad_pullup = 0x400005cc; -gpio_pad_select_gpio = 0x400005d0; -gpio_pad_set_drv = 0x400005d4; -gpio_pad_unhold = 0x400005d8; -gpio_pin_wakeup_disable = 0x400005dc; -gpio_pin_wakeup_enable = 0x400005e0; -gpio_bypass_matrix_in = 0x400005e4; - - -/*************************************** - Group interrupts - ***************************************/ - -/* Functions */ -esprv_intc_int_set_priority = 0x400005e8; -esprv_intc_int_set_threshold = 0x400005ec; -esprv_intc_int_enable = 0x400005f0; -esprv_intc_int_disable = 0x400005f4; -esprv_intc_int_set_type = 0x400005f8; -intr_matrix_set = 0x400005fc; -ets_intr_lock = 0x40000600; -ets_intr_unlock = 0x40000604; -PROVIDE( intr_handler_set = 0x40000608 ); -ets_isr_attach = 0x4000060c; -ets_isr_mask = 0x40000610; -ets_isr_unmask = 0x40000614; - - -/*************************************** - Group crypto - ***************************************/ - -/* Functions */ -md5_vector = 0x40000618; -MD5Init = 0x4000061c; -MD5Update = 0x40000620; -MD5Final = 0x40000624; -hmac_md5_vector = 0x40000628; -hmac_md5 = 0x4000062c; -crc32_le = 0x40000630; -crc32_be = 0x40000634; -crc16_le = 0x40000638; -crc16_be = 0x4000063c; -crc8_le = 0x40000640; -crc8_be = 0x40000644; -esp_crc8 = 0x40000648; -ets_sha_enable = 0x4000064c; -ets_sha_disable = 0x40000650; -ets_sha_get_state = 0x40000654; -ets_sha_init = 0x40000658; -ets_sha_process = 0x4000065c; -ets_sha_starts = 0x40000660; -ets_sha_update = 0x40000664; -ets_sha_finish = 0x40000668; -ets_sha_clone = 0x4000066c; -ets_hmac_enable = 0x40000670; -ets_hmac_disable = 0x40000674; -ets_hmac_calculate_message = 0x40000678; -ets_hmac_calculate_downstream = 0x4000067c; -ets_hmac_invalidate_downstream = 0x40000680; -ets_jtag_enable_temporarily = 0x40000684; -ets_aes_enable = 0x40000688; -ets_aes_disable = 0x4000068c; -ets_aes_setkey = 0x40000690; -ets_aes_block = 0x40000694; -ets_bigint_enable = 0x40000698; -ets_bigint_disable = 0x4000069c; -ets_bigint_multiply = 0x400006a0; -ets_bigint_modmult = 0x400006a4; -ets_bigint_modexp = 0x400006a8; -ets_bigint_wait_finish = 0x400006ac; -ets_bigint_getz = 0x400006b0; -ets_ds_enable = 0x400006b4; -ets_ds_disable = 0x400006b8; -ets_ds_start_sign = 0x400006bc; -ets_ds_is_busy = 0x400006c0; -ets_ds_finish_sign = 0x400006c4; -ets_ds_encrypt_params = 0x400006c8; -ets_aes_setkey_dec = 0x400006cc; -ets_aes_setkey_enc = 0x400006d0; -ets_mgf1_sha256 = 0x400006d4; - - -/*************************************** - Group efuse - ***************************************/ - -/* Functions */ -ets_efuse_read = 0x400006d8; -ets_efuse_program = 0x400006dc; -ets_efuse_clear_program_registers = 0x400006e0; -ets_efuse_write_key = 0x400006e4; -ets_efuse_get_read_register_address = 0x400006e8; -ets_efuse_get_key_purpose = 0x400006ec; -ets_efuse_key_block_unused = 0x400006f0; -ets_efuse_find_unused_key_block = 0x400006f4; -ets_efuse_rs_calculate = 0x400006f8; -ets_efuse_count_unused_key_blocks = 0x400006fc; -ets_efuse_secure_boot_enabled = 0x40000700; -ets_efuse_secure_boot_aggressive_revoke_enabled = 0x40000704; -ets_efuse_cache_encryption_enabled = 0x40000708; -ets_efuse_download_modes_disabled = 0x4000070c; -ets_efuse_find_purpose = 0x40000710; -ets_efuse_flash_opi_5pads_power_sel_vddspi = 0x40000714; -ets_efuse_force_send_resume = 0x40000718; -ets_efuse_get_flash_delay_us = 0x4000071c; -ets_efuse_get_mac = 0x40000720; -ets_efuse_get_spiconfig = 0x40000724; -ets_efuse_usb_print_is_disabled = 0x40000728; -ets_efuse_get_uart_print_channel = 0x4000072c; -ets_efuse_get_uart_print_control = 0x40000730; -ets_efuse_get_wp_pad = 0x40000734; -ets_efuse_direct_boot_mode_disabled = 0x40000738; -ets_efuse_security_download_modes_enabled = 0x4000073c; -ets_efuse_set_timing = 0x40000740; -ets_efuse_jtag_disabled = 0x40000744; -ets_efuse_usb_download_mode_disabled = 0x40000748; -ets_efuse_usb_module_disabled = 0x4000074c; -ets_efuse_usb_device_disabled = 0x40000750; -ets_efuse_secure_boot_fast_wake_enabled = 0x40000754; - - -/*************************************** - Group secureboot - ***************************************/ - -/* Functions */ -ets_emsa_pss_verify = 0x40000758; -ets_rsa_pss_verify = 0x4000075c; -ets_secure_boot_verify_bootloader_with_keys = 0x40000760; -ets_secure_boot_verify_signature = 0x40000764; -ets_secure_boot_read_key_digests = 0x40000768; -ets_secure_boot_revoke_public_key_digest = 0x4000076c; - - -/*************************************** - Group usb_uart - ***************************************/ - -/* Functions */ -PROVIDE( usb_uart_device_rx_one_char = 0x400008d8 ); -PROVIDE( usb_uart_device_rx_one_char_block = 0x400008dc ); -PROVIDE( usb_uart_device_tx_flush = 0x400008e0 ); -PROVIDE( usb_uart_device_tx_one_char = 0x400008e4 ); -/* Data (.data, .bss, .rodata) */ -PROVIDE( g_uart_print = 0x3fcdffcd ); -PROVIDE( g_usb_print = 0x3fcdffcc ); - - -/*************************************** - Group rom_phy - ***************************************/ - -/* Functions */ -phy_get_romfuncs = 0x400008e8; -rom_abs_temp = 0x400008ec; -rom_bb_bss_cbw40_dig = 0x400008f0; -rom_bb_wdg_test_en = 0x400008f4; -rom_bb_wdt_get_status = 0x400008f8; -rom_bb_wdt_int_enable = 0x400008fc; -rom_bb_wdt_rst_enable = 0x40000900; -rom_bb_wdt_timeout_clear = 0x40000904; -rom_cbw2040_cfg = 0x40000908; -rom_check_noise_floor = 0x4000090c; -rom_chip_i2c_readReg = 0x40000910; -rom_chip_i2c_writeReg = 0x40000914; -rom_correct_rf_ana_gain = 0x40000918; -rom_dc_iq_est = 0x4000091c; -rom_disable_agc = 0x40000920; -rom_en_pwdet = 0x40000924; -rom_enable_agc = 0x40000928; -rom_get_bbgain_db = 0x4000092c; -rom_get_data_sat = 0x40000930; -rom_get_i2c_read_mask = 0x40000934; -rom_get_pwctrl_correct = 0x40000938; -rom_get_rf_gain_qdb = 0x4000093c; -rom_i2c_readReg = 0x40000940; -rom_i2c_readReg_Mask = 0x40000944; -rom_i2c_writeReg = 0x40000948; -rom_i2c_writeReg_Mask = 0x4000094c; -rom_index_to_txbbgain = 0x40000950; -rom_iq_est_disable = 0x40000954; -rom_iq_est_enable = 0x40000958; -rom_linear_to_db = 0x4000095c; -rom_loopback_mode_en = 0x40000960; -rom_mhz2ieee = 0x40000964; -rom_noise_floor_auto_set = 0x40000968; -rom_pbus_debugmode = 0x4000096c; -rom_pbus_force_mode = 0x40000970; -rom_pbus_force_test = 0x40000974; -rom_pbus_rd = 0x40000978; -rom_pbus_rd_addr = 0x4000097c; -rom_pbus_rd_shift = 0x40000980; -rom_pbus_set_dco = 0x40000984; -rom_pbus_set_rxgain = 0x40000988; -rom_pbus_workmode = 0x4000098c; -rom_pbus_xpd_rx_off = 0x40000990; -rom_pbus_xpd_rx_on = 0x40000994; -rom_pbus_xpd_tx_off = 0x40000998; -rom_pbus_xpd_tx_on = 0x4000099c; -rom_phy_byte_to_word = 0x400009a0; -rom_phy_disable_cca = 0x400009a4; -rom_phy_enable_cca = 0x400009a8; -rom_phy_get_noisefloor = 0x400009ac; -rom_phy_get_rx_freq = 0x400009b0; -rom_phy_set_bbfreq_init = 0x400009b4; -rom_pow_usr = 0x400009b8; -rom_pwdet_sar2_init = 0x400009bc; -rom_read_hw_noisefloor = 0x400009c0; -rom_read_sar_dout = 0x400009c4; -rom_set_cal_rxdc = 0x400009c8; -rom_set_chan_cal_interp = 0x400009cc; -rom_set_loopback_gain = 0x400009d0; -rom_set_noise_floor = 0x400009d4; -rom_set_rxclk_en = 0x400009d8; -rom_set_tx_dig_gain = 0x400009dc; -rom_set_txcap_reg = 0x400009e0; -rom_set_txclk_en = 0x400009e4; -rom_spur_cal = 0x400009e8; -rom_spur_reg_write_one_tone = 0x400009ec; -rom_target_power_add_backoff = 0x400009f0; -rom_tx_pwctrl_bg_init = 0x400009f4; -rom_txbbgain_to_index = 0x400009f8; -rom_wifi_11g_rate_chg = 0x400009fc; -rom_write_gain_mem = 0x40000a00; -chip726_phyrom_version = 0x40000a04; -rom_disable_wifi_agc = 0x40000a08; -rom_enable_wifi_agc = 0x40000a0c; -rom_set_tx_gain_table = 0x40000a10; -rom_bt_index_to_bb = 0x40000a14; -rom_bt_bb_to_index = 0x40000a18; -rom_wr_bt_tx_atten = 0x40000a1c; -rom_wr_bt_tx_gain_mem = 0x40000a20; -rom_spur_coef_cfg = 0x40000a24; -rom_bb_bss_cbw40 = 0x40000a28; -rom_set_cca = 0x40000a2c; -rom_tx_paon_set = 0x40000a30; -rom_i2cmst_reg_init = 0x40000a34; -rom_iq_corr_enable = 0x40000a38; -rom_fe_reg_init = 0x40000a3c; -rom_agc_reg_init = 0x40000a40; -rom_bb_reg_init = 0x40000a44; -rom_mac_enable_bb = 0x40000a48; -rom_bb_wdg_cfg = 0x40000a4c; -rom_force_txon = 0x40000a50; -rom_fe_txrx_reset = 0x40000a54; -rom_set_rx_comp = 0x40000a58; -rom_set_pbus_reg = 0x40000a5c; -rom_write_chan_freq = 0x40000a60; -rom_phy_xpd_rf = 0x40000a64; -rom_set_xpd_sar = 0x40000a68; -rom_write_dac_gain2 = 0x40000a6c; -rom_rtc_sar2_init = 0x40000a70; -rom_get_target_power_offset = 0x40000a74; -rom_write_txrate_power_offset = 0x40000a78; -rom_get_rate_fcc_index = 0x40000a7c; -rom_get_rate_target_power = 0x40000a80; -rom_write_wifi_dig_gain = 0x40000a84; -rom_bt_correct_rf_ana_gain = 0x40000a88; -rom_pkdet_vol_start = 0x40000a8c; -rom_read_sar2_code = 0x40000a90; -rom_get_sar2_vol = 0x40000a94; -rom_get_pll_vol = 0x40000a98; -rom_get_phy_target_power = 0x40000a9c; -rom_temp_to_power = 0x40000aa0; -rom_phy_track_pll_cap = 0x40000aa4; -rom_phy_pwdet_always_en = 0x40000aa8; -rom_phy_pwdet_onetime_en = 0x40000aac; -rom_get_i2c_mst0_mask = 0x40000ab0; -rom_get_i2c_hostid = 0x40000ab4; -rom_enter_critical_phy = 0x40000ab8; -rom_exit_critical_phy = 0x40000abc; -rom_chip_i2c_readReg_org = 0x40000ac0; -rom_i2c_paral_set_mst0 = 0x40000ac4; -rom_i2c_paral_set_read = 0x40000ac8; -rom_i2c_paral_read = 0x40000acc; -rom_i2c_paral_write = 0x40000ad0; -rom_i2c_paral_write_num = 0x40000ad4; -rom_i2c_paral_write_mask = 0x40000ad8; -rom_bb_bss_cbw40_ana = 0x40000adc; -rom_chan_to_freq = 0x40000ae0; -rom_open_i2c_xpd = 0x40000ae4; -rom_dac_rate_set = 0x40000ae8; -rom_tsens_read_init = 0x40000aec; -rom_tsens_code_read = 0x40000af0; -rom_tsens_index_to_dac = 0x40000af4; -rom_tsens_index_to_offset = 0x40000af8; -rom_tsens_dac_cal = 0x40000afc; -rom_code_to_temp = 0x40000b00; -rom_write_pll_cap_mem = 0x40000b04; -rom_pll_correct_dcap = 0x40000b08; -rom_phy_en_hw_set_freq = 0x40000b0c; -rom_phy_dis_hw_set_freq = 0x40000b10; -rom_pll_vol_cal = 0x40000b14; -rom_wrtie_pll_cap = 0x40000b18; -rom_set_tx_gain_mem = 0x40000b1c; -rom_bt_tx_dig_gain = 0x40000b20; -rom_bt_get_tx_gain = 0x40000b24; -rom_get_chan_target_power = 0x40000b28; -rom_get_tx_gain_value = 0x40000b2c; -rom_wifi_tx_dig_gain = 0x40000b30; -rom_wifi_get_tx_gain = 0x40000b34; -rom_fe_i2c_reg_renew = 0x40000b38; -rom_wifi_agc_sat_gain = 0x40000b3c; -rom_i2c_master_reset = 0x40000b40; -rom_bt_filter_reg = 0x40000b44; -rom_phy_bbpll_cal = 0x40000b48; -rom_i2c_sar2_init_code = 0x40000b4c; -rom_phy_param_addr = 0x40000b50; -rom_phy_reg_init = 0x40000b54; -rom_set_chan_reg = 0x40000b58; -rom_phy_wakeup_init = 0x40000b5c; -rom_phy_i2c_init1 = 0x40000b60; -rom_tsens_temp_read = 0x40000b64; -rom_bt_track_pll_cap = 0x40000b68; -rom_wifi_track_pll_cap = 0x40000b6c; -rom_wifi_set_tx_gain = 0x40000b70; -rom_txpwr_cal_track = 0x40000b74; -rom_tx_pwctrl_background = 0x40000b78; -rom_bt_set_tx_gain = 0x40000b7c; -rom_noise_check_loop = 0x40000b80; -rom_phy_close_rf = 0x40000b84; -rom_phy_xpd_tsens = 0x40000b88; -rom_phy_freq_mem_backup = 0x40000b8c; -rom_phy_ant_init = 0x40000b90; -rom_bt_track_tx_power = 0x40000b94; -rom_wifi_track_tx_power = 0x40000b98; -rom_phy_dig_reg_backup = 0x40000b9c; -chip726_phyrom_version_num = 0x40000ba0; -/* Data (.data, .bss, .rodata) */ -phy_param_rom = 0x3fcdffc8; diff --git a/tools/esptool_py/flasher_stub/ld/rom_32h2_beta_2.ld b/tools/esptool_py/flasher_stub/ld/rom_32h2_beta_2.ld deleted file mode 100644 index 81d8df7a12..0000000000 --- a/tools/esptool_py/flasher_stub/ld/rom_32h2_beta_2.ld +++ /dev/null @@ -1,1714 +0,0 @@ -/* ROM function interface esp32h2.rom.ld for esp32h2 - * - * - * Generated from ./target/esp32h2/interface-esp32h2.yml md5sum da4c474a48c097d4ac9acad67f70fda6 - * - * Compatible with ROM where ECO version equal or greater to 0. - * - * THIS FILE WAS AUTOMATICALLY GENERATED. DO NOT EDIT. - */ - - -PROVIDE ( SPIWrite = esp_rom_spiflash_write); -PROVIDE ( SPI_read_status_high = esp_rom_spiflash_read_statushigh); -PROVIDE ( SPI_write_status = esp_rom_spiflash_write_status); -PROVIDE ( SPIRead = esp_rom_spiflash_read); -PROVIDE ( SPIParamCfg = esp_rom_spiflash_config_param); -PROVIDE ( SPIEraseChip = esp_rom_spiflash_erase_chip); -PROVIDE ( SPIEraseSector = esp_rom_spiflash_erase_sector); -PROVIDE ( SPIEraseBlock = esp_rom_spiflash_erase_block); -PROVIDE ( SPI_Write_Encrypt_Enable = esp_rom_spiflash_write_encrypted_enable); -PROVIDE ( SPI_Write_Encrypt_Disable = esp_rom_spiflash_write_encrypted_disable); -PROVIDE ( SPI_Encrypt_Write = esp_rom_spiflash_write_encrypted); - - - -/*************************************** - Group common - ***************************************/ - -/* Functions */ -rtc_get_reset_reason = 0x40000018; -analog_super_wdt_reset_happened = 0x4000001c; -rtc_get_wakeup_cause = 0x40000020; -rtc_select_apb_bridge = 0x40000024; -rtc_unhold_all_pads = 0x40000028; -ets_is_print_boot = 0x4000002c; -ets_printf = 0x40000030; -ets_install_putc1 = 0x40000034; -ets_install_uart_printf = 0x40000038; -ets_install_putc2 = 0x4000003c; -PROVIDE( ets_delay_us = 0x40000040 ); -ets_install_lock = 0x40000044; -ets_backup_dma_copy = 0x40000048; -ets_apb_backup_init_lock_func = 0x4000004c; -UartRxString = 0x40000050; -UartGetCmdLn = 0x40000054; -uart_tx_one_char = 0x40000058; -uart_tx_one_char2 = 0x4000005c; -uart_rx_one_char = 0x40000060; -uart_rx_one_char_block = 0x40000064; -uart_rx_readbuff = 0x40000068; -uartAttach = 0x4000006c; -uart_tx_flush = 0x40000070; -uart_tx_wait_idle = 0x40000074; -uart_div_modify = 0x40000078; -ets_write_char_uart = 0x4000007c; -uart_tx_switch = 0x40000080; -multofup = 0x40000084; -software_reset = 0x40000088; -software_reset_cpu = 0x4000008c; -assist_debug_clock_enable = 0x40000090; -assist_debug_record_enable = 0x40000094; -clear_super_wdt_reset_flag = 0x40000098; -disable_default_watchdog = 0x4000009c; -esp_rom_set_rtc_wake_addr = 0x400000a0; -esp_rom_get_rtc_wake_addr = 0x400000a4; -send_packet = 0x400000a8; -recv_packet = 0x400000ac; -GetUartDevice = 0x400000b0; -UartDwnLdProc = 0x400000b4; -GetSecurityInfoProc = 0x400000b8; -Uart_Init = 0x400000bc; -ets_set_user_start = 0x400000c0; -/* Data (.data, .bss, .rodata) */ -ets_rom_layout_p = 0x3ff1fffc; -ets_ops_table_ptr = 0x3fcdfff8; -g_uart_print = 0x3fcdfffd; -g_usb_print = 0x3fcdfffc; - - -/*************************************** - Group miniz - ***************************************/ - -/* Functions */ -mz_adler32 = 0x400000c4; -mz_free = 0x400000c8; -tdefl_compress = 0x400000cc; -tdefl_compress_buffer = 0x400000d0; -tdefl_compress_mem_to_heap = 0x400000d4; -tdefl_compress_mem_to_mem = 0x400000d8; -tdefl_compress_mem_to_output = 0x400000dc; -tdefl_get_adler32 = 0x400000e0; -tdefl_get_prev_return_status = 0x400000e4; -tdefl_init = 0x400000e8; -tdefl_write_image_to_png_file_in_memory = 0x400000ec; -tdefl_write_image_to_png_file_in_memory_ex = 0x400000f0; -tinfl_decompress = 0x400000f4; -tinfl_decompress_mem_to_callback = 0x400000f8; -tinfl_decompress_mem_to_heap = 0x400000fc; -tinfl_decompress_mem_to_mem = 0x40000100; - - -/*************************************** - Group tjpgd - ***************************************/ - -/* Functions */ -jd_prepare = 0x40000104; -jd_decomp = 0x40000108; - - -/*************************************** - Group spiflash_legacy - ***************************************/ - -/* Functions */ -PROVIDE( esp_rom_spiflash_wait_idle = 0x4000010c ); -PROVIDE( esp_rom_spiflash_write_encrypted = 0x40000110 ); -PROVIDE( esp_rom_spiflash_write_encrypted_dest = 0x40000114 ); -PROVIDE( esp_rom_spiflash_write_encrypted_enable = 0x40000118 ); -PROVIDE( esp_rom_spiflash_write_encrypted_disable = 0x4000011c ); -PROVIDE( esp_rom_spiflash_erase_chip = 0x40000120 ); -PROVIDE( _esp_rom_spiflash_erase_sector = 0x40000124 ); -PROVIDE( _esp_rom_spiflash_erase_block = 0x40000128 ); -PROVIDE( _esp_rom_spiflash_write = 0x4000012c ); -PROVIDE( _esp_rom_spiflash_read = 0x40000130 ); -PROVIDE( _esp_rom_spiflash_unlock = 0x40000134 ); -PROVIDE( _SPIEraseArea = 0x40000138 ); -PROVIDE( _SPI_write_enable = 0x4000013c ); -PROVIDE( esp_rom_spiflash_erase_sector = 0x40000140 ); -PROVIDE( esp_rom_spiflash_erase_block = 0x40000144 ); -PROVIDE( esp_rom_spiflash_write = 0x40000148 ); -PROVIDE( esp_rom_spiflash_read = 0x4000014c ); -PROVIDE( esp_rom_spiflash_unlock = 0x40000150 ); -PROVIDE( SPIEraseArea = 0x40000154 ); -PROVIDE( SPI_write_enable = 0x40000158 ); -PROVIDE( esp_rom_spiflash_config_param = 0x4000015c ); -PROVIDE( esp_rom_spiflash_read_user_cmd = 0x40000160 ); -PROVIDE( esp_rom_spiflash_select_qio_pins = 0x40000164 ); -PROVIDE( esp_rom_spi_flash_auto_sus_res = 0x40000168 ); -PROVIDE( esp_rom_spi_flash_send_resume = 0x4000016c ); -PROVIDE( esp_rom_spi_flash_update_id = 0x40000170 ); -PROVIDE( esp_rom_spiflash_config_clk = 0x40000174 ); -PROVIDE( esp_rom_spiflash_config_readmode = 0x40000178 ); -PROVIDE( esp_rom_spiflash_read_status = 0x4000017c ); -PROVIDE( esp_rom_spiflash_read_statushigh = 0x40000180 ); -PROVIDE( esp_rom_spiflash_write_status = 0x40000184 ); -PROVIDE( spi_flash_attach = 0x40000188 ); -PROVIDE( spi_flash_get_chip_size = 0x4000018c ); -PROVIDE( spi_flash_guard_set = 0x40000190 ); -PROVIDE( spi_flash_guard_get = 0x40000194 ); -PROVIDE( spi_flash_read_encrypted = 0x40000198 ); -PROVIDE( spi_flash_mmap_os_func_set = 0x4000019c ); -PROVIDE( spi_flash_mmap_page_num_init = 0x400001a0 ); -PROVIDE( spi_flash_mmap = 0x400001a4 ); -PROVIDE( spi_flash_mmap_pages = 0x400001a8 ); -PROVIDE( spi_flash_munmap = 0x400001ac ); -PROVIDE( spi_flash_mmap_dump = 0x400001b0 ); -PROVIDE( spi_flash_check_and_flush_cache = 0x400001b4 ); -PROVIDE( spi_flash_mmap_get_free_pages = 0x400001b8 ); -PROVIDE( spi_flash_cache2phys = 0x400001bc ); -PROVIDE( spi_flash_phys2cache = 0x400001c0 ); -PROVIDE( spi_flash_disable_cache = 0x400001c4 ); -PROVIDE( spi_flash_restore_cache = 0x400001c8 ); -PROVIDE( spi_flash_cache_enabled = 0x400001cc ); -PROVIDE( spi_flash_enable_cache = 0x400001d0 ); -PROVIDE( spi_cache_mode_switch = 0x400001d4 ); -PROVIDE( spi_common_set_dummy_output = 0x400001d8 ); -PROVIDE( spi_common_set_flash_cs_timing = 0x400001dc ); -PROVIDE( esp_rom_spi_set_address_bit_len = 0x400001e0 ); -PROVIDE( esp_enable_cache_flash_wrap = 0x400001e4 ); -PROVIDE( SPILock = 0x400001e8 ); -PROVIDE( SPIMasterReadModeCnfig = 0x400001ec ); -PROVIDE( SPI_Common_Command = 0x400001f0 ); -PROVIDE( SPI_WakeUp = 0x400001f4 ); -PROVIDE( SPI_block_erase = 0x400001f8 ); -PROVIDE( SPI_chip_erase = 0x400001fc ); -PROVIDE( SPI_init = 0x40000200 ); -PROVIDE( SPI_page_program = 0x40000204 ); -PROVIDE( SPI_read_data = 0x40000208 ); -PROVIDE( SPI_sector_erase = 0x4000020c ); -PROVIDE( SelectSpiFunction = 0x40000210 ); -PROVIDE( SetSpiDrvs = 0x40000214 ); -PROVIDE( Wait_SPI_Idle = 0x40000218 ); -PROVIDE( spi_dummy_len_fix = 0x4000021c ); -PROVIDE( Disable_QMode = 0x40000220 ); -PROVIDE( Enable_QMode = 0x40000224 ); -/* Data (.data, .bss, .rodata) */ -PROVIDE( rom_spiflash_legacy_funcs = 0x3fcdfff0 ); -PROVIDE( rom_spiflash_legacy_data = 0x3fcdffec ); -PROVIDE( g_flash_guard_ops = 0x3fcdfff4 ); - - -/*************************************** - Group hal_soc - ***************************************/ - -/* Functions */ -PROVIDE( spi_flash_hal_poll_cmd_done = 0x40000228 ); -PROVIDE( spi_flash_hal_device_config = 0x4000022c ); -PROVIDE( spi_flash_hal_configure_host_io_mode = 0x40000230 ); -PROVIDE( spi_flash_hal_common_command = 0x40000234 ); -PROVIDE( spi_flash_hal_read = 0x40000238 ); -PROVIDE( spi_flash_hal_erase_chip = 0x4000023c ); -PROVIDE( spi_flash_hal_erase_sector = 0x40000240 ); -PROVIDE( spi_flash_hal_erase_block = 0x40000244 ); -PROVIDE( spi_flash_hal_program_page = 0x40000248 ); -PROVIDE( spi_flash_hal_set_write_protect = 0x4000024c ); -PROVIDE( spi_flash_hal_host_idle = 0x40000250 ); -PROVIDE( spi_flash_hal_check_status = 0x40000254 ); -PROVIDE( spi_flash_hal_setup_read_suspend = 0x40000258 ); -PROVIDE( spi_flash_hal_setup_auto_suspend_mode = 0x4000025c ); -PROVIDE( spi_flash_hal_setup_auto_resume_mode = 0x40000260 ); -PROVIDE( spi_flash_hal_disable_auto_suspend_mode = 0x40000264 ); -PROVIDE( spi_flash_hal_disable_auto_resume_mode = 0x40000268 ); -PROVIDE( spi_flash_hal_resume = 0x4000026c ); -PROVIDE( spi_flash_hal_suspend = 0x40000270 ); -PROVIDE( spi_flash_encryption_hal_enable = 0x40000274 ); -PROVIDE( spi_flash_encryption_hal_disable = 0x40000278 ); -PROVIDE( spi_flash_encryption_hal_prepare = 0x4000027c ); -PROVIDE( spi_flash_encryption_hal_done = 0x40000280 ); -PROVIDE( spi_flash_encryption_hal_destroy = 0x40000284 ); -PROVIDE( spi_flash_encryption_hal_check = 0x40000288 ); -PROVIDE( wdt_hal_init = 0x4000028c ); -PROVIDE( wdt_hal_deinit = 0x40000290 ); -PROVIDE( wdt_hal_config_stage = 0x40000294 ); -PROVIDE( wdt_hal_write_protect_disable = 0x40000298 ); -PROVIDE( wdt_hal_write_protect_enable = 0x4000029c ); -PROVIDE( wdt_hal_enable = 0x400002a0 ); -PROVIDE( wdt_hal_disable = 0x400002a4 ); -PROVIDE( wdt_hal_handle_intr = 0x400002a8 ); -PROVIDE( wdt_hal_feed = 0x400002ac ); -PROVIDE( wdt_hal_set_flashboot_en = 0x400002b0 ); -PROVIDE( wdt_hal_is_enabled = 0x400002b4 ); -PROVIDE( systimer_hal_init = 0x400002b8 ); -PROVIDE( systimer_hal_get_counter_value = 0x400002bc ); -PROVIDE( systimer_hal_get_time = 0x400002c0 ); -PROVIDE( systimer_hal_set_alarm_target = 0x400002c4 ); -PROVIDE( systimer_hal_set_alarm_period = 0x400002c8 ); -PROVIDE( systimer_hal_get_alarm_value = 0x400002cc ); -PROVIDE( systimer_hal_enable_alarm_int = 0x400002d0 ); -PROVIDE( systimer_hal_on_apb_freq_update = 0x400002d4 ); -PROVIDE( systimer_hal_counter_value_advance = 0x400002d8 ); -PROVIDE( systimer_hal_enable_counter = 0x400002dc ); -PROVIDE( systimer_hal_select_alarm_mode = 0x400002e0 ); -PROVIDE( systimer_hal_connect_alarm_counter = 0x400002e4 ); -PROVIDE( systimer_hal_counter_can_stall_by_cpu = 0x400002e8 ); - - -/*************************************** - Group heap - ***************************************/ - -/* Functions */ -PROVIDE( tlsf_create = 0x400002ec ); -PROVIDE( tlsf_create_with_pool = 0x400002f0 ); -PROVIDE( tlsf_get_pool = 0x400002f4 ); -PROVIDE( tlsf_add_pool = 0x400002f8 ); -PROVIDE( tlsf_remove_pool = 0x400002fc ); -PROVIDE( tlsf_malloc = 0x40000300 ); -PROVIDE( tlsf_memalign = 0x40000304 ); -PROVIDE( tlsf_memalign_offs = 0x40000308 ); -PROVIDE( tlsf_realloc = 0x4000030c ); -PROVIDE( tlsf_free = 0x40000310 ); -PROVIDE( tlsf_block_size = 0x40000314 ); -PROVIDE( tlsf_size = 0x40000318 ); -PROVIDE( tlsf_align_size = 0x4000031c ); -PROVIDE( tlsf_block_size_min = 0x40000320 ); -PROVIDE( tlsf_block_size_max = 0x40000324 ); -PROVIDE( tlsf_pool_overhead = 0x40000328 ); -PROVIDE( tlsf_alloc_overhead = 0x4000032c ); -PROVIDE( tlsf_walk_pool = 0x40000330 ); -PROVIDE( tlsf_check = 0x40000334 ); -PROVIDE( tlsf_check_pool = 0x40000338 ); -PROVIDE( tlsf_poison_fill_pfunc_set = 0x4000033c ); -PROVIDE( multi_heap_get_block_address_impl = 0x40000340 ); -PROVIDE( multi_heap_get_allocated_size_impl = 0x40000344 ); -PROVIDE( multi_heap_register_impl = 0x40000348 ); -PROVIDE( multi_heap_set_lock = 0x4000034c ); -PROVIDE( multi_heap_mutex_init = 0x40000350 ); -PROVIDE( multi_heap_internal_lock = 0x40000354 ); -PROVIDE( multi_heap_internal_unlock = 0x40000358 ); -PROVIDE( multi_heap_get_first_block = 0x4000035c ); -PROVIDE( multi_heap_get_next_block = 0x40000360 ); -PROVIDE( multi_heap_is_free = 0x40000364 ); -PROVIDE( multi_heap_malloc_impl = 0x40000368 ); -PROVIDE( multi_heap_free_impl = 0x4000036c ); -PROVIDE( multi_heap_realloc_impl = 0x40000370 ); -PROVIDE( multi_heap_aligned_alloc_impl_offs = 0x40000374 ); -PROVIDE( multi_heap_aligned_alloc_impl = 0x40000378 ); -PROVIDE( multi_heap_check = 0x4000037c ); -PROVIDE( multi_heap_dump = 0x40000380 ); -PROVIDE( multi_heap_free_size_impl = 0x40000384 ); -PROVIDE( multi_heap_minimum_free_size_impl = 0x40000388 ); -PROVIDE( multi_heap_get_info_impl = 0x4000038c ); -/* Data (.data, .bss, .rodata) */ -PROVIDE( heap_tlsf_table_ptr = 0x3fcdffe8 ); - - -/*************************************** - Group spi_flash_chips - ***************************************/ - -/* Functions */ -PROVIDE( spi_flash_chip_generic_probe = 0x40000390 ); -PROVIDE( spi_flash_chip_generic_detect_size = 0x40000394 ); -PROVIDE( spi_flash_chip_generic_write = 0x40000398 ); -PROVIDE( spi_flash_chip_generic_write_encrypted = 0x4000039c ); -PROVIDE( spi_flash_chip_generic_set_write_protect = 0x400003a0 ); -PROVIDE( spi_flash_common_write_status_16b_wrsr = 0x400003a4 ); -PROVIDE( spi_flash_chip_generic_reset = 0x400003a8 ); -PROVIDE( spi_flash_chip_generic_erase_chip = 0x400003ac ); -PROVIDE( spi_flash_chip_generic_erase_sector = 0x400003b0 ); -PROVIDE( spi_flash_chip_generic_erase_block = 0x400003b4 ); -PROVIDE( spi_flash_chip_generic_page_program = 0x400003b8 ); -PROVIDE( spi_flash_chip_generic_get_write_protect = 0x400003bc ); -PROVIDE( spi_flash_common_read_status_16b_rdsr_rdsr2 = 0x400003c0 ); -PROVIDE( spi_flash_chip_generic_read_reg = 0x400003c4 ); -PROVIDE( spi_flash_chip_generic_yield = 0x400003c8 ); -PROVIDE( spi_flash_generic_wait_host_idle = 0x400003cc ); -PROVIDE( spi_flash_chip_generic_wait_idle = 0x400003d0 ); -PROVIDE( spi_flash_chip_generic_config_host_io_mode = 0x400003d4 ); -PROVIDE( spi_flash_chip_generic_read = 0x400003d8 ); -PROVIDE( spi_flash_common_read_status_8b_rdsr2 = 0x400003dc ); -PROVIDE( spi_flash_chip_generic_get_io_mode = 0x400003e0 ); -PROVIDE( spi_flash_common_read_status_8b_rdsr = 0x400003e4 ); -PROVIDE( spi_flash_common_write_status_8b_wrsr = 0x400003e8 ); -PROVIDE( spi_flash_common_write_status_8b_wrsr2 = 0x400003ec ); -PROVIDE( spi_flash_common_set_io_mode = 0x400003f0 ); -PROVIDE( spi_flash_chip_generic_set_io_mode = 0x400003f4 ); -PROVIDE( spi_flash_chip_generic_read_unique_id = 0x400003f8 ); -PROVIDE( spi_flash_chip_generic_get_caps = 0x400003fc ); -PROVIDE( spi_flash_chip_generic_suspend_cmd_conf = 0x40000400 ); -PROVIDE( spi_flash_chip_gd_get_io_mode = 0x40000404 ); -PROVIDE( spi_flash_chip_gd_probe = 0x40000408 ); -PROVIDE( spi_flash_chip_gd_set_io_mode = 0x4000040c ); -/* Data (.data, .bss, .rodata) */ -PROVIDE( spi_flash_chip_generic_config_data = 0x3fcdffe4 ); -PROVIDE( spi_flash_encryption = 0x3fcdffe0 ); - - -/*************************************** - Group memspi_host - ***************************************/ - -/* Functions */ -PROVIDE( memspi_host_read_id_hs = 0x40000410 ); -PROVIDE( memspi_host_read_status_hs = 0x40000414 ); -PROVIDE( memspi_host_flush_cache = 0x40000418 ); -PROVIDE( memspi_host_erase_chip = 0x4000041c ); -PROVIDE( memspi_host_erase_sector = 0x40000420 ); -PROVIDE( memspi_host_erase_block = 0x40000424 ); -PROVIDE( memspi_host_program_page = 0x40000428 ); -PROVIDE( memspi_host_read = 0x4000042c ); -PROVIDE( memspi_host_set_write_protect = 0x40000430 ); -PROVIDE( memspi_host_set_max_read_len = 0x40000434 ); -PROVIDE( memspi_host_read_data_slicer = 0x40000438 ); -PROVIDE( memspi_host_write_data_slicer = 0x4000043c ); - - -/*************************************** - Group esp_flash - ***************************************/ - -/* Functions */ -PROVIDE( esp_flash_chip_driver_initialized = 0x40000440 ); -PROVIDE( esp_flash_read_id = 0x40000444 ); -PROVIDE( esp_flash_get_size = 0x40000448 ); -PROVIDE( esp_flash_erase_chip = 0x4000044c ); -PROVIDE( esp_flash_erase_region = 0x40000450 ); -PROVIDE( esp_flash_get_chip_write_protect = 0x40000454 ); -PROVIDE( esp_flash_set_chip_write_protect = 0x40000458 ); -PROVIDE( esp_flash_get_protectable_regions = 0x4000045c ); -PROVIDE( esp_flash_get_protected_region = 0x40000460 ); -PROVIDE( esp_flash_set_protected_region = 0x40000464 ); -PROVIDE( esp_flash_read = 0x40000468 ); -PROVIDE( esp_flash_write = 0x4000046c ); -PROVIDE( esp_flash_write_encrypted = 0x40000470 ); -PROVIDE( esp_flash_read_encrypted = 0x40000474 ); -PROVIDE( esp_flash_get_io_mode = 0x40000478 ); -PROVIDE( esp_flash_set_io_mode = 0x4000047c ); -PROVIDE( spi_flash_boot_attach = 0x40000480 ); -PROVIDE( esp_flash_read_chip_id = 0x40000484 ); -PROVIDE( detect_spi_flash_chip = 0x40000488 ); -PROVIDE( esp_rom_spiflash_write_disable = 0x4000048c ); -PROVIDE( esp_flash_suspend_cmd_init = 0x40000490 ); -/* Data (.data, .bss, .rodata) */ -PROVIDE( esp_flash_default_chip = 0x3fcdffdc ); -PROVIDE( esp_flash_api_funcs = 0x3fcdffd8 ); - - -/*************************************** - Group cache - ***************************************/ - -/* Functions */ -PROVIDE( Cache_Get_ICache_Line_Size = 0x400006f0 ); -PROVIDE( Cache_Get_Mode = 0x400006f4 ); -PROVIDE( Cache_Address_Through_IBus = 0x400006f8 ); -PROVIDE( Cache_Address_Through_DBus = 0x400006fc ); -PROVIDE( Cache_Set_Default_Mode = 0x40000700 ); -PROVIDE( Cache_Enable_Defalut_ICache_Mode = 0x40000704 ); -PROVIDE( ROM_Boot_Cache_Init = 0x40000708 ); -PROVIDE( Cache_Invalidate_ICache_Items = 0x4000070c ); -PROVIDE( Cache_Op_Addr = 0x40000710 ); -PROVIDE( Cache_Invalidate_Addr = 0x40000714 ); -PROVIDE( Cache_Invalidate_ICache_All = 0x40000718 ); -PROVIDE( Cache_Mask_All = 0x4000071c ); -PROVIDE( Cache_UnMask_Dram0 = 0x40000720 ); -PROVIDE( Cache_Suspend_ICache_Autoload = 0x40000724 ); -PROVIDE( Cache_Resume_ICache_Autoload = 0x40000728 ); -PROVIDE( Cache_Start_ICache_Preload = 0x4000072c ); -PROVIDE( Cache_ICache_Preload_Done = 0x40000730 ); -PROVIDE( Cache_End_ICache_Preload = 0x40000734 ); -PROVIDE( Cache_Config_ICache_Autoload = 0x40000738 ); -PROVIDE( Cache_Enable_ICache_Autoload = 0x4000073c ); -PROVIDE( Cache_Disable_ICache_Autoload = 0x40000740 ); -PROVIDE( Cache_Enable_ICache_PreLock = 0x40000744 ); -PROVIDE( Cache_Disable_ICache_PreLock = 0x40000748 ); -PROVIDE( Cache_Lock_ICache_Items = 0x4000074c ); -PROVIDE( Cache_Unlock_ICache_Items = 0x40000750 ); -PROVIDE( Cache_Lock_Addr = 0x40000754 ); -PROVIDE( Cache_Unlock_Addr = 0x40000758 ); -PROVIDE( Cache_Disable_ICache = 0x4000075c ); -PROVIDE( Cache_Enable_ICache = 0x40000760 ); -PROVIDE( Cache_Suspend_ICache = 0x40000764 ); -PROVIDE( Cache_Resume_ICache = 0x40000768 ); -PROVIDE( Cache_Freeze_ICache_Enable = 0x4000076c ); -PROVIDE( Cache_Freeze_ICache_Disable = 0x40000770 ); -PROVIDE( Cache_Pms_Lock = 0x40000774 ); -PROVIDE( Cache_Ibus_Pms_Set_Addr = 0x40000778 ); -PROVIDE( Cache_Ibus_Pms_Set_Attr = 0x4000077c ); -PROVIDE( Cache_Dbus_Pms_Set_Addr = 0x40000780 ); -PROVIDE( Cache_Dbus_Pms_Set_Attr = 0x40000784 ); -PROVIDE( Cache_Set_IDROM_MMU_Size = 0x40000788 ); -PROVIDE( Cache_Get_IROM_MMU_End = 0x4000078c ); -PROVIDE( Cache_Get_DROM_MMU_End = 0x40000790 ); -PROVIDE( Cache_Owner_Init = 0x40000794 ); -PROVIDE( Cache_Occupy_ICache_MEMORY = 0x40000798 ); -PROVIDE( Cache_MMU_Init = 0x4000079c ); -PROVIDE( Cache_Ibus_MMU_Set = 0x400007a0 ); -PROVIDE( Cache_Dbus_MMU_Set = 0x400007a4 ); -PROVIDE( Cache_Count_Flash_Pages = 0x400007a8 ); -PROVIDE( Cache_Travel_Tag_Memory = 0x400007ac ); -PROVIDE( Cache_Get_Virtual_Addr = 0x400007b0 ); -PROVIDE( Cache_Get_Memory_BaseAddr = 0x400007b4 ); -PROVIDE( Cache_Get_Memory_Addr = 0x400007b8 ); -PROVIDE( Cache_Get_Memory_value = 0x400007bc ); -/* Data (.data, .bss, .rodata) */ -PROVIDE( rom_cache_op_cb = 0x3fcdffcc ); -PROVIDE( rom_cache_internal_table_ptr = 0x3fcdffc8 ); - - -/*************************************** - Group clock - ***************************************/ - -/* Functions */ -ets_get_apb_freq = 0x400007c0; -ets_get_cpu_frequency = 0x400007c4; -ets_update_cpu_frequency = 0x400007c8; -ets_get_printf_channel = 0x400007cc; -ets_get_xtal_div = 0x400007d0; -ets_set_xtal_div = 0x400007d4; -ets_get_xtal_freq = 0x400007d8; - - -/*************************************** - Group gpio - ***************************************/ - -/* Functions */ -gpio_input_get = 0x400007dc; -gpio_matrix_in = 0x400007e0; -gpio_matrix_out = 0x400007e4; -gpio_output_disable = 0x400007e8; -gpio_output_enable = 0x400007ec; -gpio_output_set = 0x400007f0; -gpio_pad_hold = 0x400007f4; -gpio_pad_input_disable = 0x400007f8; -gpio_pad_input_enable = 0x400007fc; -gpio_pad_pulldown = 0x40000800; -gpio_pad_pullup = 0x40000804; -gpio_pad_select_gpio = 0x40000808; -gpio_pad_set_drv = 0x4000080c; -gpio_pad_unhold = 0x40000810; -gpio_pin_wakeup_disable = 0x40000814; -gpio_pin_wakeup_enable = 0x40000818; -gpio_bypass_matrix_in = 0x4000081c; - - -/*************************************** - Group interrupts - ***************************************/ - -/* Functions */ -esprv_intc_int_set_priority = 0x40000820; -esprv_intc_int_set_threshold = 0x40000824; -esprv_intc_int_enable = 0x40000828; -esprv_intc_int_disable = 0x4000082c; -esprv_intc_int_set_type = 0x40000830; -PROVIDE( intr_handler_set = 0x40000834 ); -intr_matrix_set = 0x40000838; -ets_intr_lock = 0x4000083c; -ets_intr_unlock = 0x40000840; -ets_isr_attach = 0x40000844; -ets_isr_mask = 0x40000848; -ets_isr_unmask = 0x4000084c; - - -/*************************************** - Group crypto - ***************************************/ - -/* Functions */ -md5_vector = 0x40000850; -MD5Init = 0x40000854; -MD5Update = 0x40000858; -MD5Final = 0x4000085c; -crc32_le = 0x40000860; -crc16_le = 0x40000864; -crc8_le = 0x40000868; -crc32_be = 0x4000086c; -crc16_be = 0x40000870; -crc8_be = 0x40000874; -esp_crc8 = 0x40000878; -ets_sha_enable = 0x4000087c; -ets_sha_disable = 0x40000880; -ets_sha_get_state = 0x40000884; -ets_sha_init = 0x40000888; -ets_sha_process = 0x4000088c; -ets_sha_starts = 0x40000890; -ets_sha_update = 0x40000894; -ets_sha_finish = 0x40000898; -ets_sha_clone = 0x4000089c; -ets_hmac_enable = 0x400008a0; -ets_hmac_disable = 0x400008a4; -ets_hmac_calculate_message = 0x400008a8; -ets_hmac_calculate_downstream = 0x400008ac; -ets_hmac_invalidate_downstream = 0x400008b0; -ets_jtag_enable_temporarily = 0x400008b4; -ets_aes_enable = 0x400008b8; -ets_aes_disable = 0x400008bc; -ets_aes_setkey = 0x400008c0; -ets_aes_block = 0x400008c4; -ets_aes_setkey_dec = 0x400008c8; -ets_aes_setkey_enc = 0x400008cc; -ets_bigint_enable = 0x400008d0; -ets_bigint_disable = 0x400008d4; -ets_bigint_multiply = 0x400008d8; -ets_bigint_modmult = 0x400008dc; -ets_bigint_modexp = 0x400008e0; -ets_bigint_wait_finish = 0x400008e4; -ets_bigint_getz = 0x400008e8; -ets_ds_enable = 0x400008ec; -ets_ds_disable = 0x400008f0; -ets_ds_start_sign = 0x400008f4; -ets_ds_is_busy = 0x400008f8; -ets_ds_finish_sign = 0x400008fc; -ets_ds_encrypt_params = 0x40000900; -ets_mgf1_sha256 = 0x40000904; -/* Data (.data, .bss, .rodata) */ -crc32_le_table_ptr = 0x3ff1fff8; -crc16_le_table_ptr = 0x3ff1fff4; -crc8_le_table_ptr = 0x3ff1fff0; -crc32_be_table_ptr = 0x3ff1ffec; -crc16_be_table_ptr = 0x3ff1ffe8; -crc8_be_table_ptr = 0x3ff1ffe4; - - -/*************************************** - Group efuse - ***************************************/ - -/* Functions */ -ets_efuse_read = 0x40000908; -ets_efuse_program = 0x4000090c; -ets_efuse_clear_program_registers = 0x40000910; -ets_efuse_write_key = 0x40000914; -ets_efuse_get_read_register_address = 0x40000918; -ets_efuse_get_key_purpose = 0x4000091c; -ets_efuse_key_block_unused = 0x40000920; -ets_efuse_find_unused_key_block = 0x40000924; -ets_efuse_rs_calculate = 0x40000928; -ets_efuse_count_unused_key_blocks = 0x4000092c; -ets_efuse_secure_boot_enabled = 0x40000930; -ets_efuse_secure_boot_aggressive_revoke_enabled = 0x40000934; -ets_efuse_cache_encryption_enabled = 0x40000938; -ets_efuse_download_modes_disabled = 0x4000093c; -ets_efuse_find_purpose = 0x40000940; -ets_efuse_force_send_resume = 0x40000944; -ets_efuse_get_flash_delay_us = 0x40000948; -ets_efuse_get_mac = 0x4000094c; -ets_efuse_get_uart_print_control = 0x40000950; -ets_efuse_direct_boot_mode_disabled = 0x40000954; -ets_efuse_security_download_modes_enabled = 0x40000958; -ets_efuse_set_timing = 0x4000095c; -ets_efuse_jtag_disabled = 0x40000960; -ets_efuse_get_spiconfig = 0x40000964; -ets_efuse_get_wp_pad = 0x40000968; -ets_efuse_usb_print_is_disabled = 0x4000096c; -ets_efuse_usb_download_mode_disabled = 0x40000970; -ets_efuse_usb_module_disabled = 0x40000974; -ets_efuse_usb_device_disabled = 0x40000978; -ets_efuse_secure_boot_fast_wake_enabled = 0x4000097c; - - -/*************************************** - Group secureboot - ***************************************/ - -/* Functions */ -ets_emsa_pss_verify = 0x40000980; -ets_rsa_pss_verify = 0x40000984; -ets_secure_boot_verify_bootloader_with_keys = 0x40000988; -ets_secure_boot_verify_signature = 0x4000098c; -ets_secure_boot_read_key_digests = 0x40000990; -ets_secure_boot_revoke_public_key_digest = 0x40000994; - - -/*************************************** - Group btdm - ***************************************/ - -/* Functions */ -ble_controller_rom_data_init = 0x40000b08; -ble_osi_coex_funcs_register = 0x40000b0c; -bt_rf_coex_cfg_get_default = 0x40000b10; -bt_rf_coex_dft_pti_get_default = 0x40000b14; -bt_rf_coex_hooks_p_set = 0x40000b18; -r__os_mbuf_copypkthdr = 0x40000b1c; -r__os_msys_find_pool = 0x40000b20; -r_ble_controller_get_rom_compile_version = 0x40000b24; -r_ble_hci_ram_hs_acl_tx = 0x40000b28; -r_ble_hci_ram_hs_cmd_tx = 0x40000b2c; -r_ble_hci_ram_ll_acl_tx = 0x40000b30; -r_ble_hci_ram_ll_evt_tx = 0x40000b34; -r_ble_hci_ram_reset = 0x40000b38; -r_ble_hci_ram_set_acl_free_cb = 0x40000b3c; -r_ble_hci_trans_acl_buf_alloc = 0x40000b40; -r_ble_hci_trans_buf_alloc = 0x40000b44; -r_ble_hci_trans_buf_free = 0x40000b48; -r_ble_hci_trans_cfg_hs = 0x40000b4c; -r_ble_hci_trans_cfg_ll = 0x40000b50; -r_ble_hci_trans_deinit = 0x40000b54; -r_ble_hci_trans_env_init = 0x40000b58; -r_ble_hci_trans_init = 0x40000b5c; -r_ble_hci_uart_acl_tx = 0x40000b60; -r_ble_hci_uart_cmdevt_tx = 0x40000b64; -r_ble_hci_uart_config = 0x40000b68; -r_ble_hci_uart_free_pkt = 0x40000b6c; -r_ble_hci_uart_hs_acl_tx = 0x40000b70; -r_ble_hci_uart_hs_cmd_tx = 0x40000b74; -r_ble_hci_uart_ll_acl_tx = 0x40000b78; -r_ble_hci_uart_ll_evt_tx = 0x40000b7c; -r_ble_hci_uart_rx_acl = 0x40000b80; -r_ble_hci_uart_rx_char = 0x40000b84; -r_ble_hci_uart_rx_cmd = 0x40000b88; -r_ble_hci_uart_rx_evt = 0x40000b8c; -r_ble_hci_uart_rx_evt_cb = 0x40000b90; -r_ble_hci_uart_rx_le_evt = 0x40000b94; -r_ble_hci_uart_rx_pkt_type = 0x40000b98; -r_ble_hci_uart_rx_skip_acl = 0x40000b9c; -r_ble_hci_uart_rx_skip_cmd = 0x40000ba0; -r_ble_hci_uart_rx_skip_evt = 0x40000ba4; -r_ble_hci_uart_rx_sync_loss = 0x40000ba8; -r_ble_hci_uart_set_acl_free_cb = 0x40000bac; -r_ble_hci_uart_sync_lost = 0x40000bb0; -r_ble_hci_uart_trans_reset = 0x40000bb4; -r_ble_hci_uart_tx_char = 0x40000bb8; -r_ble_hci_uart_tx_pkt_type = 0x40000bbc; -r_ble_hw_driver_deinit = 0x40000bc0; -r_ble_hw_driver_env_init = 0x40000bc4; -r_ble_hw_encrypt_block = 0x40000bc8; -r_ble_hw_get_public_addr = 0x40000bcc; -r_ble_hw_get_static_addr = 0x40000bd0; -r_ble_hw_periodiclist_add = 0x40000bd4; -r_ble_hw_periodiclist_clear = 0x40000bd8; -r_ble_hw_periodiclist_rmv = 0x40000bdc; -r_ble_hw_resolv_list_cur_entry = 0x40000be0; -r_ble_hw_resolv_list_match = 0x40000be4; -r_ble_hw_resolv_list_set = 0x40000be8; -r_ble_hw_rng_init = 0x40000bec; -r_ble_hw_rng_start = 0x40000bf0; -r_ble_hw_rng_stop = 0x40000bf4; -r_ble_hw_rx_local_is_rpa = 0x40000bf8; -r_ble_hw_whitelist_add = 0x40000bfc; -r_ble_hw_whitelist_clear = 0x40000c00; -r_ble_hw_whitelist_dev_num = 0x40000c04; -r_ble_hw_whitelist_get_base = 0x40000c08; -r_ble_hw_whitelist_rmv = 0x40000c0c; -r_ble_hw_whitelist_search = 0x40000c10; -r_ble_hw_whitelist_sort = 0x40000c14; -r_ble_ll_acl_data_in = 0x40000c18; -r_ble_ll_addr_is_id = 0x40000c1c; -r_ble_ll_addr_subtype = 0x40000c20; -r_ble_ll_adv_active_chanset_clear = 0x40000c24; -r_ble_ll_adv_active_chanset_is_pri = 0x40000c28; -r_ble_ll_adv_active_chanset_is_sec = 0x40000c2c; -r_ble_ll_adv_active_chanset_set_pri = 0x40000c30; -r_ble_ll_adv_active_chanset_set_sec = 0x40000c34; -r_ble_ll_adv_aux_calculate = 0x40000c38; -r_ble_ll_adv_aux_conn_rsp_pdu_make = 0x40000c3c; -r_ble_ll_adv_aux_pdu_make = 0x40000c40; -r_ble_ll_adv_aux_scannable_pdu_make = 0x40000c44; -r_ble_ll_adv_aux_scannable_pdu_payload_len = 0x40000c48; -r_ble_ll_adv_aux_schedule = 0x40000c4c; -r_ble_ll_adv_aux_schedule_first = 0x40000c50; -r_ble_ll_adv_aux_schedule_next = 0x40000c54; -r_ble_ll_adv_aux_scheduled = 0x40000c58; -r_ble_ll_adv_aux_set_start_time = 0x40000c5c; -r_ble_ll_adv_aux_txed = 0x40000c60; -r_ble_ll_adv_can_chg_whitelist = 0x40000c64; -r_ble_ll_adv_chk_rpa_timeout = 0x40000c68; -r_ble_ll_adv_clear_all = 0x40000c6c; -r_ble_ll_adv_coex_dpc_calc_pti_update_itvl = 0x40000c70; -r_ble_ll_adv_coex_dpc_process_pri = 0x40000c74; -r_ble_ll_adv_coex_dpc_process_sec = 0x40000c78; -r_ble_ll_adv_coex_dpc_pti_get = 0x40000c7c; -r_ble_ll_adv_coex_dpc_update = 0x40000c80; -r_ble_ll_adv_coex_dpc_update_on_adv_start = 0x40000c84; -r_ble_ll_adv_coex_dpc_update_on_aux_scheduled = 0x40000c88; -r_ble_ll_adv_coex_dpc_update_on_data_updated = 0x40000c8c; -r_ble_ll_adv_coex_dpc_update_on_event_end = 0x40000c90; -r_ble_ll_adv_coex_dpc_update_on_event_scheduled = 0x40000c94; -r_ble_ll_adv_conn_req_rxd = 0x40000c98; -r_ble_ll_adv_deinit = 0x40000c9c; -r_ble_ll_adv_done = 0x40000ca0; -r_ble_ll_adv_drop_event = 0x40000ca4; -r_ble_ll_adv_enabled = 0x40000ca8; -r_ble_ll_adv_env_init = 0x40000cac; -r_ble_ll_adv_event_done = 0x40000cb0; -r_ble_ll_adv_event_rmvd_from_sched = 0x40000cb4; -r_ble_ll_adv_ext_estimate_data_itvl = 0x40000cb8; -r_ble_ll_adv_ext_set_adv_data = 0x40000cbc; -r_ble_ll_adv_ext_set_enable = 0x40000cc0; -r_ble_ll_adv_ext_set_param = 0x40000cc4; -r_ble_ll_adv_ext_set_scan_rsp = 0x40000cc8; -r_ble_ll_adv_final_chan = 0x40000ccc; -r_ble_ll_adv_first_chan = 0x40000cd0; -r_ble_ll_adv_flags_clear = 0x40000cd4; -r_ble_ll_adv_flags_set = 0x40000cd8; -r_ble_ll_adv_get_local_rpa = 0x40000cdc; -r_ble_ll_adv_get_peer_rpa = 0x40000ce0; -r_ble_ll_adv_get_sec_pdu_len = 0x40000ce4; -r_ble_ll_adv_halt = 0x40000ce8; -r_ble_ll_adv_hci_set_random_addr = 0x40000cec; -r_ble_ll_adv_init = 0x40000cf0; -r_ble_ll_adv_legacy_pdu_make = 0x40000cf4; -r_ble_ll_adv_make_done = 0x40000cf8; -r_ble_ll_adv_pdu_make = 0x40000cfc; -r_ble_ll_adv_periodic_check_data_itvl = 0x40000d00; -r_ble_ll_adv_periodic_done = 0x40000d04; -r_ble_ll_adv_periodic_enable = 0x40000d08; -r_ble_ll_adv_periodic_estimate_data_itvl = 0x40000d0c; -r_ble_ll_adv_periodic_event_done = 0x40000d10; -r_ble_ll_adv_periodic_rmvd_from_sched = 0x40000d14; -r_ble_ll_adv_periodic_schedule_first = 0x40000d18; -r_ble_ll_adv_periodic_schedule_next = 0x40000d1c; -r_ble_ll_adv_periodic_send_sync_ind = 0x40000d20; -r_ble_ll_adv_periodic_set_data = 0x40000d24; -r_ble_ll_adv_periodic_set_info_transfer = 0x40000d28; -r_ble_ll_adv_periodic_set_param = 0x40000d2c; -r_ble_ll_adv_put_aux_ptr = 0x40000d30; -r_ble_ll_adv_put_syncinfo = 0x40000d34; -r_ble_ll_adv_rd_max_adv_data_len = 0x40000d38; -r_ble_ll_adv_rd_sup_adv_sets = 0x40000d3c; -r_ble_ll_adv_read_txpwr = 0x40000d40; -r_ble_ll_adv_remove = 0x40000d44; -r_ble_ll_adv_reschedule_event = 0x40000d48; -r_ble_ll_adv_reschedule_periodic_event = 0x40000d4c; -r_ble_ll_adv_reset = 0x40000d50; -r_ble_ll_adv_rpa_timeout = 0x40000d54; -r_ble_ll_adv_rpa_update = 0x40000d58; -r_ble_ll_adv_rx_isr_end = 0x40000d5c; -r_ble_ll_adv_rx_isr_start = 0x40000d60; -r_ble_ll_adv_rx_pkt_in = 0x40000d64; -r_ble_ll_adv_rx_req = 0x40000d68; -r_ble_ll_adv_scan_rsp_legacy_pdu_make = 0x40000d6c; -r_ble_ll_adv_scan_rsp_pdu_make = 0x40000d70; -r_ble_ll_adv_scheduled = 0x40000d74; -r_ble_ll_adv_sec_done = 0x40000d78; -r_ble_ll_adv_sec_event_done = 0x40000d7c; -r_ble_ll_adv_secondary_tx_start_cb = 0x40000d80; -r_ble_ll_adv_send_conn_comp_ev = 0x40000d84; -r_ble_ll_adv_set_adv_data = 0x40000d88; -r_ble_ll_adv_set_adv_params = 0x40000d8c; -r_ble_ll_adv_set_enable = 0x40000d90; -r_ble_ll_adv_set_random_addr = 0x40000d94; -r_ble_ll_adv_set_scan_rsp_data = 0x40000d98; -r_ble_ll_adv_set_sched = 0x40000d9c; -r_ble_ll_adv_sm_deinit = 0x40000da0; -r_ble_ll_adv_sm_event_init = 0x40000da4; -r_ble_ll_adv_sm_event_restore = 0x40000da8; -r_ble_ll_adv_sm_event_store = 0x40000dac; -r_ble_ll_adv_sm_find_configured = 0x40000db0; -r_ble_ll_adv_sm_get = 0x40000db4; -r_ble_ll_adv_sm_init = 0x40000db8; -r_ble_ll_adv_sm_reset = 0x40000dbc; -r_ble_ll_adv_sm_start = 0x40000dc0; -r_ble_ll_adv_sm_start_periodic = 0x40000dc4; -r_ble_ll_adv_sm_stop = 0x40000dc8; -r_ble_ll_adv_sm_stop_limit_reached = 0x40000dcc; -r_ble_ll_adv_sm_stop_periodic = 0x40000dd0; -r_ble_ll_adv_sm_stop_timeout = 0x40000dd4; -r_ble_ll_adv_sync_calculate = 0x40000dd8; -r_ble_ll_adv_sync_get_pdu_len = 0x40000ddc; -r_ble_ll_adv_sync_next_scheduled = 0x40000de0; -r_ble_ll_adv_sync_pdu_make = 0x40000de4; -r_ble_ll_adv_sync_schedule = 0x40000de8; -r_ble_ll_adv_sync_tx_done = 0x40000dec; -r_ble_ll_adv_sync_tx_end = 0x40000df0; -r_ble_ll_adv_sync_tx_start_cb = 0x40000df4; -r_ble_ll_adv_tx_done = 0x40000df8; -r_ble_ll_adv_tx_start_cb = 0x40000dfc; -r_ble_ll_adv_update_adv_scan_rsp_data = 0x40000e00; -r_ble_ll_adv_update_data_mbuf = 0x40000e04; -r_ble_ll_adv_update_did = 0x40000e08; -r_ble_ll_adv_update_periodic_data = 0x40000e0c; -r_ble_ll_adv_update_rsp_offset = 0x40000e10; -r_ble_ll_adv_wfr_timer_exp = 0x40000e14; -r_ble_ll_arr_pool_init = 0x40000e18; -r_ble_ll_auth_pyld_tmo_event_send = 0x40000e1c; -r_ble_ll_aux_scan_cb = 0x40000e20; -r_ble_ll_aux_scan_drop = 0x40000e24; -r_ble_ll_aux_scan_drop_event_cb = 0x40000e28; -r_ble_ll_calc_offset_ticks_us_for_rampup = 0x40000e2c; -r_ble_ll_calc_session_key = 0x40000e30; -r_ble_ll_calc_ticks_per_slot = 0x40000e34; -r_ble_ll_calc_us_convert_tick_unit = 0x40000e38; -r_ble_ll_check_scan_params = 0x40000e3c; -r_ble_ll_chk_txrx_octets = 0x40000e40; -r_ble_ll_chk_txrx_time = 0x40000e44; -r_ble_ll_conn_adjust_pyld_len = 0x40000e48; -r_ble_ll_conn_auth_pyld_timer_cb = 0x40000e4c; -r_ble_ll_conn_auth_pyld_timer_start = 0x40000e50; -r_ble_ll_conn_calc_dci = 0x40000e54; -r_ble_ll_conn_calc_dci_csa1 = 0x40000e58; -r_ble_ll_conn_calc_itvl_ticks = 0x40000e5c; -r_ble_ll_conn_can_send_next_pdu = 0x40000e60; -r_ble_ll_conn_chk_csm_flags = 0x40000e64; -r_ble_ll_conn_chk_phy_upd_start = 0x40000e68; -r_ble_ll_conn_coex_dpc_process = 0x40000e6c; -r_ble_ll_conn_coex_dpc_pti_get = 0x40000e70; -r_ble_ll_conn_coex_dpc_update = 0x40000e74; -r_ble_ll_conn_coex_dpc_update_on_event_scheduled = 0x40000e78; -r_ble_ll_conn_comp_event_send = 0x40000e7c; -r_ble_ll_conn_connect_ind_pdu_make = 0x40000e80; -r_ble_ll_conn_create = 0x40000e84; -r_ble_ll_conn_create_cancel = 0x40000e88; -r_ble_ll_conn_created = 0x40000e8c; -r_ble_ll_conn_cth_flow_alloc_credit = 0x40000e90; -r_ble_ll_conn_cth_flow_enable = 0x40000e94; -r_ble_ll_conn_cth_flow_error_fn = 0x40000e98; -r_ble_ll_conn_cth_flow_free_credit = 0x40000e9c; -r_ble_ll_conn_cth_flow_have_credit = 0x40000ea0; -r_ble_ll_conn_cth_flow_is_enabled = 0x40000ea4; -r_ble_ll_conn_cth_flow_process_cmd = 0x40000ea8; -r_ble_ll_conn_cth_flow_set_buffers = 0x40000eac; -r_ble_ll_conn_cur_pducb = 0x40000eb0; -r_ble_ll_conn_current_sm_over = 0x40000eb4; -r_ble_ll_conn_end = 0x40000eb8; -r_ble_ll_conn_enqueue_pkt = 0x40000ebc; -r_ble_ll_conn_env_init = 0x40000ec0; -r_ble_ll_conn_event_end = 0x40000ec4; -r_ble_ll_conn_event_end_timer_cb = 0x40000ec8; -r_ble_ll_conn_event_halt = 0x40000ecc; -r_ble_ll_conn_event_is_over = 0x40000ed0; -r_ble_ll_conn_event_start_cb = 0x40000ed4; -r_ble_ll_conn_ext_master_init = 0x40000ed8; -r_ble_ll_conn_ext_set_params = 0x40000edc; -r_ble_ll_conn_find_active_conn = 0x40000ee0; -r_ble_ll_conn_get_anchor = 0x40000ee4; -r_ble_ll_conn_get_ce_end_time = 0x40000ee8; -r_ble_ll_conn_get_new_pdu = 0x40000eec; -r_ble_ll_conn_get_next_sched_time = 0x40000ef0; -r_ble_ll_conn_halt = 0x40000ef4; -r_ble_ll_conn_hcc_params_set_fallback = 0x40000ef8; -r_ble_ll_conn_hci_cancel_conn_complete_event = 0x40000efc; -r_ble_ll_conn_hci_chk_conn_params = 0x40000f00; -r_ble_ll_conn_hci_chk_scan_params = 0x40000f04; -r_ble_ll_conn_hci_disconnect_cmd = 0x40000f08; -r_ble_ll_conn_hci_le_ltk_neg_reply = 0x40000f0c; -r_ble_ll_conn_hci_le_ltk_reply = 0x40000f10; -r_ble_ll_conn_hci_le_rd_phy = 0x40000f14; -r_ble_ll_conn_hci_le_set_phy = 0x40000f18; -r_ble_ll_conn_hci_le_start_encrypt = 0x40000f1c; -r_ble_ll_conn_hci_param_nrr = 0x40000f20; -r_ble_ll_conn_hci_param_rr = 0x40000f24; -r_ble_ll_conn_hci_rd_auth_pyld_tmo = 0x40000f28; -r_ble_ll_conn_hci_rd_chan_map = 0x40000f2c; -r_ble_ll_conn_hci_rd_rem_ver_cmd = 0x40000f30; -r_ble_ll_conn_hci_rd_rssi = 0x40000f34; -r_ble_ll_conn_hci_read_rem_features = 0x40000f38; -r_ble_ll_conn_hci_set_chan_class = 0x40000f3c; -r_ble_ll_conn_hci_set_data_len = 0x40000f40; -r_ble_ll_conn_hci_update = 0x40000f44; -r_ble_ll_conn_hci_wr_auth_pyld_tmo = 0x40000f48; -r_ble_ll_conn_init_pending_aux_conn_rsp = 0x40000f4c; -r_ble_ll_conn_init_phy = 0x40000f50; -r_ble_ll_conn_init_wfr_timer_exp = 0x40000f54; -r_ble_ll_conn_is_empty_pdu = 0x40000f58; -r_ble_ll_conn_is_lru = 0x40000f5c; -r_ble_ll_conn_master_common_init = 0x40000f60; -r_ble_ll_conn_master_init = 0x40000f64; -r_ble_ll_conn_module_deinit = 0x40000f68; -r_ble_ll_conn_module_init = 0x40000f6c; -r_ble_ll_conn_module_reset = 0x40000f70; -r_ble_ll_conn_new_pducb = 0x40000f74; -r_ble_ll_conn_next_event = 0x40000f78; -r_ble_ll_conn_num_comp_pkts_event_send = 0x40000f7c; -r_ble_ll_conn_process_conn_params = 0x40000f80; -r_ble_ll_conn_recv_ack = 0x40000f84; -r_ble_ll_conn_reset_pending_aux_conn_rsp = 0x40000f88; -r_ble_ll_conn_rx_data_pdu = 0x40000f8c; -r_ble_ll_conn_rx_isr_end = 0x40000f90; -r_ble_ll_conn_rx_isr_start = 0x40000f94; -r_ble_ll_conn_rxend_unencrypt = 0x40000f98; -r_ble_ll_conn_set_csa = 0x40000f9c; -r_ble_ll_conn_set_global_chanmap = 0x40000fa0; -r_ble_ll_conn_set_md_flag = 0x40000fa4; -r_ble_ll_conn_set_phy = 0x40000fa8; -r_ble_ll_conn_set_slave_flow_control = 0x40000fac; -r_ble_ll_conn_set_txpwr_by_handle = 0x40000fb0; -r_ble_ll_conn_set_unknown_rx_octets = 0x40000fb4; -r_ble_ll_conn_slave_start = 0x40000fb8; -r_ble_ll_conn_sm_get = 0x40000fbc; -r_ble_ll_conn_sm_new = 0x40000fc0; -r_ble_ll_conn_sm_npl_deinit = 0x40000fc4; -r_ble_ll_conn_sm_npl_init = 0x40000fc8; -r_ble_ll_conn_start_rx_encrypt = 0x40000fcc; -r_ble_ll_conn_start_rx_unencrypt = 0x40000fd0; -r_ble_ll_conn_timeout = 0x40000fd4; -r_ble_ll_conn_tx_pdu = 0x40000fd8; -r_ble_ll_conn_tx_pkt_in = 0x40000fdc; -r_ble_ll_conn_txend_encrypt = 0x40000fe0; -r_ble_ll_conn_update_conn_params = 0x40000fe4; -r_ble_ll_conn_update_eff_data_len = 0x40000fe8; -r_ble_ll_conn_update_new_pdu_len = 0x40000fec; -r_ble_ll_conn_wait_txend = 0x40000ff0; -r_ble_ll_conn_wfr_timer_exp = 0x40000ff4; -r_ble_ll_copy_data = 0x40000ff8; -r_ble_ll_ctrl_chanmap_req_make = 0x40000ffc; -r_ble_ll_ctrl_chk_proc_start = 0x40001000; -r_ble_ll_ctrl_conn_param_pdu_make = 0x40001004; -r_ble_ll_ctrl_conn_param_pdu_proc = 0x40001008; -r_ble_ll_ctrl_conn_param_reply = 0x4000100c; -r_ble_ll_ctrl_conn_upd_make = 0x40001010; -r_ble_ll_ctrl_datalen_upd_make = 0x40001014; -r_ble_ll_ctrl_enc_allowed_pdu = 0x40001018; -r_ble_ll_ctrl_enc_allowed_pdu_rx = 0x4000101c; -r_ble_ll_ctrl_enc_allowed_pdu_tx = 0x40001020; -r_ble_ll_ctrl_enc_req_make = 0x40001024; -r_ble_ll_ctrl_find_new_phy = 0x40001028; -r_ble_ll_ctrl_initiate_dle = 0x4000102c; -r_ble_ll_ctrl_is_start_enc_rsp = 0x40001030; -r_ble_ll_ctrl_is_terminate_ind = 0x40001034; -r_ble_ll_ctrl_len_proc = 0x40001038; -r_ble_ll_ctrl_phy_from_phy_mask = 0x4000103c; -r_ble_ll_ctrl_phy_req_rsp_make = 0x40001040; -r_ble_ll_ctrl_phy_tx_transition_get = 0x40001044; -r_ble_ll_ctrl_phy_update_cancel = 0x40001048; -r_ble_ll_ctrl_phy_update_ind_make = 0x4000104c; -r_ble_ll_ctrl_phy_update_proc_complete = 0x40001050; -r_ble_ll_ctrl_proc_init = 0x40001054; -r_ble_ll_ctrl_proc_rsp_timer_cb = 0x40001058; -r_ble_ll_ctrl_proc_start = 0x4000105c; -r_ble_ll_ctrl_proc_stop = 0x40001060; -r_ble_ll_ctrl_proc_unk_rsp = 0x40001064; -r_ble_ll_ctrl_proc_with_instant_initiated = 0x40001068; -r_ble_ll_ctrl_rej_ext_ind_make = 0x4000106c; -r_ble_ll_ctrl_reject_ind_send = 0x40001070; -r_ble_ll_ctrl_rx_chanmap_req = 0x40001074; -r_ble_ll_ctrl_rx_conn_param_req = 0x40001078; -r_ble_ll_ctrl_rx_conn_param_rsp = 0x4000107c; -r_ble_ll_ctrl_rx_conn_update = 0x40001080; -r_ble_ll_ctrl_rx_enc_req = 0x40001084; -r_ble_ll_ctrl_rx_enc_rsp = 0x40001088; -r_ble_ll_ctrl_rx_feature_req = 0x4000108c; -r_ble_ll_ctrl_rx_feature_rsp = 0x40001090; -r_ble_ll_ctrl_rx_pause_enc_req = 0x40001094; -r_ble_ll_ctrl_rx_pause_enc_rsp = 0x40001098; -r_ble_ll_ctrl_rx_pdu = 0x4000109c; -r_ble_ll_ctrl_rx_periodic_sync_ind = 0x400010a0; -r_ble_ll_ctrl_rx_phy_req = 0x400010a4; -r_ble_ll_ctrl_rx_phy_rsp = 0x400010a8; -r_ble_ll_ctrl_rx_phy_update_ind = 0x400010ac; -r_ble_ll_ctrl_rx_ping_rsp = 0x400010b0; -r_ble_ll_ctrl_rx_reject_ind = 0x400010b4; -r_ble_ll_ctrl_rx_start_enc_req = 0x400010b8; -r_ble_ll_ctrl_rx_start_enc_rsp = 0x400010bc; -r_ble_ll_ctrl_rx_version_ind = 0x400010c0; -r_ble_ll_ctrl_start_enc_send = 0x400010c4; -r_ble_ll_ctrl_start_rsp_timer = 0x400010c8; -r_ble_ll_ctrl_terminate_start = 0x400010cc; -r_ble_ll_ctrl_tx_done = 0x400010d0; -r_ble_ll_ctrl_update_features = 0x400010d4; -r_ble_ll_ctrl_version_ind_make = 0x400010d8; -r_ble_ll_data_buffer_overflow = 0x400010dc; -r_ble_ll_deinit = 0x400010e0; -r_ble_ll_disconn_comp_event_send = 0x400010e4; -r_ble_ll_dtm_calculate_itvl = 0x400010e8; -r_ble_ll_dtm_ctx_free = 0x400010ec; -r_ble_ll_dtm_deinit = 0x400010f0; -r_ble_ll_dtm_end_test = 0x400010f4; -r_ble_ll_dtm_ev_rx_restart_cb = 0x400010f8; -r_ble_ll_dtm_ev_tx_resched_cb = 0x400010fc; -r_ble_ll_dtm_init = 0x40001100; -r_ble_ll_dtm_reset = 0x40001104; -r_ble_ll_dtm_rx_create_ctx = 0x40001108; -r_ble_ll_dtm_rx_isr_end = 0x4000110c; -r_ble_ll_dtm_rx_isr_start = 0x40001110; -r_ble_ll_dtm_rx_pkt_in = 0x40001114; -r_ble_ll_dtm_rx_sched_cb = 0x40001118; -r_ble_ll_dtm_rx_start = 0x4000111c; -r_ble_ll_dtm_rx_test = 0x40001120; -r_ble_ll_dtm_set_next = 0x40001124; -r_ble_ll_dtm_tx_create_ctx = 0x40001128; -r_ble_ll_dtm_tx_done = 0x4000112c; -r_ble_ll_dtm_tx_sched_cb = 0x40001130; -r_ble_ll_dtm_tx_test = 0x40001134; -r_ble_ll_dtm_wfr_timer_exp = 0x40001138; -r_ble_ll_env_init = 0x4000113c; -r_ble_ll_event_comp_pkts = 0x40001140; -r_ble_ll_event_dbuf_overflow = 0x40001144; -r_ble_ll_event_rx_pkt = 0x40001148; -r_ble_ll_event_send = 0x4000114c; -r_ble_ll_event_tx_pkt = 0x40001150; -r_ble_ll_ext_adv_phy_mode_to_local_phy = 0x40001154; -r_ble_ll_ext_conn_create = 0x40001158; -r_ble_ll_ext_scan_coex_dpc_process = 0x4000115c; -r_ble_ll_ext_scan_coex_dpc_pti_get = 0x40001160; -r_ble_ll_ext_scan_coex_dpc_update = 0x40001164; -r_ble_ll_ext_scan_coex_dpc_update_on_start = 0x40001168; -r_ble_ll_ext_scan_parse_adv_info = 0x4000116c; -r_ble_ll_ext_scan_parse_aux_ptr = 0x40001170; -r_ble_ll_flush_pkt_queue = 0x40001174; -r_ble_ll_generic_data_init = 0x40001178; -r_ble_ll_get_addr_type = 0x4000117c; -r_ble_ll_get_chan_to_scan = 0x40001180; -r_ble_ll_get_our_devaddr = 0x40001184; -r_ble_ll_get_tx_pwr_compensation = 0x40001188; -r_ble_ll_hci_acl_rx = 0x4000118c; -r_ble_ll_hci_adv_mode_ext = 0x40001190; -r_ble_ll_hci_adv_set_enable = 0x40001194; -r_ble_ll_hci_cb_host_buf_size = 0x40001198; -r_ble_ll_hci_cb_set_ctrlr_to_host_fc = 0x4000119c; -r_ble_ll_hci_cb_set_event_mask = 0x400011a0; -r_ble_ll_hci_cb_set_event_mask2 = 0x400011a4; -r_ble_ll_hci_chk_phy_masks = 0x400011a8; -r_ble_ll_hci_cmd_proc = 0x400011ac; -r_ble_ll_hci_cmd_rx = 0x400011b0; -r_ble_ll_hci_ctlr_bb_cmd_proc = 0x400011b4; -r_ble_ll_hci_deinit = 0x400011b8; -r_ble_ll_hci_disconnect = 0x400011bc; -r_ble_ll_hci_dtm_rx_test = 0x400011c0; -r_ble_ll_hci_dtm_rx_test_v2 = 0x400011c4; -r_ble_ll_hci_dtm_tx_test = 0x400011c8; -r_ble_ll_hci_dtm_tx_test_ext = 0x400011cc; -r_ble_ll_hci_dtm_tx_test_v2 = 0x400011d0; -r_ble_ll_hci_dtm_tx_test_v2_ext = 0x400011d4; -r_ble_ll_hci_env_init = 0x400011d8; -r_ble_ll_hci_ev_conn_update = 0x400011dc; -r_ble_ll_hci_ev_databuf_overflow = 0x400011e0; -r_ble_ll_hci_ev_datalen_chg = 0x400011e4; -r_ble_ll_hci_ev_encrypt_chg = 0x400011e8; -r_ble_ll_hci_ev_hw_err = 0x400011ec; -r_ble_ll_hci_ev_le_csa = 0x400011f0; -r_ble_ll_hci_ev_ltk_req = 0x400011f4; -r_ble_ll_hci_ev_phy_update = 0x400011f8; -r_ble_ll_hci_ev_rd_rem_used_feat = 0x400011fc; -r_ble_ll_hci_ev_rd_rem_ver = 0x40001200; -r_ble_ll_hci_ev_rem_conn_parm_req = 0x40001204; -r_ble_ll_hci_ev_send_adv_set_terminated = 0x40001208; -r_ble_ll_hci_ev_send_scan_req_recv = 0x4000120c; -r_ble_ll_hci_ev_send_scan_timeout = 0x40001210; -r_ble_ll_hci_ev_send_vendor_err = 0x40001214; -r_ble_ll_hci_event_send = 0x40001218; -r_ble_ll_hci_ext_scan_set_enable = 0x4000121c; -r_ble_ll_hci_get_num_cmd_pkts = 0x40001220; -r_ble_ll_hci_info_params_cmd_proc = 0x40001224; -r_ble_ll_hci_init = 0x40001228; -r_ble_ll_hci_is_event_enabled = 0x4000122c; -r_ble_ll_hci_is_le_event_enabled = 0x40001230; -r_ble_ll_hci_le_cmd_proc = 0x40001234; -r_ble_ll_hci_le_cmd_send_cmd_status = 0x40001238; -r_ble_ll_hci_le_encrypt = 0x4000123c; -r_ble_ll_hci_le_rand = 0x40001240; -r_ble_ll_hci_le_rd_max_data_len = 0x40001244; -r_ble_ll_hci_le_rd_sugg_data_len = 0x40001248; -r_ble_ll_hci_le_read_bufsize = 0x4000124c; -r_ble_ll_hci_le_read_local_features = 0x40001250; -r_ble_ll_hci_le_read_supp_states = 0x40001254; -r_ble_ll_hci_le_set_def_phy = 0x40001258; -r_ble_ll_hci_le_wr_sugg_data_len = 0x4000125c; -r_ble_ll_hci_link_ctrl_cmd_proc = 0x40001260; -r_ble_ll_hci_npl_init = 0x40001264; -r_ble_ll_hci_rd_bd_addr = 0x40001268; -r_ble_ll_hci_rd_local_supp_cmd = 0x4000126c; -r_ble_ll_hci_rd_local_supp_feat = 0x40001270; -r_ble_ll_hci_rd_local_version = 0x40001274; -r_ble_ll_hci_scan_set_enable = 0x40001278; -r_ble_ll_hci_send_adv_report = 0x4000127c; -r_ble_ll_hci_send_dir_adv_report = 0x40001280; -r_ble_ll_hci_send_ext_adv_report = 0x40001284; -r_ble_ll_hci_send_legacy_ext_adv_report = 0x40001288; -r_ble_ll_hci_send_noop = 0x4000128c; -r_ble_ll_hci_set_adv_data = 0x40001290; -r_ble_ll_hci_set_le_event_mask = 0x40001294; -r_ble_ll_hci_set_scan_rsp_data = 0x40001298; -r_ble_ll_hci_status_params_cmd_proc = 0x4000129c; -r_ble_ll_hci_vs_cmd_proc = 0x400012a0; -r_ble_ll_hci_vs_rd_static_addr = 0x400012a4; -r_ble_ll_hw_err_timer_cb = 0x400012a8; -r_ble_ll_hw_error = 0x400012ac; -r_ble_ll_init = 0x400012b0; -r_ble_ll_init_alloc_conn_comp_ev = 0x400012b4; -r_ble_ll_init_get_conn_comp_ev = 0x400012b8; -r_ble_ll_init_rx_isr_end = 0x400012bc; -r_ble_ll_init_rx_isr_start = 0x400012c0; -r_ble_ll_init_rx_pkt_in = 0x400012c4; -r_ble_ll_is_addr_empty = 0x400012c8; -r_ble_ll_is_controller_busy = 0x400012cc; -r_ble_ll_is_on_resolv_list = 0x400012d0; -r_ble_ll_is_our_devaddr = 0x400012d4; -r_ble_ll_is_rpa = 0x400012d8; -r_ble_ll_is_valid_adv_mode = 0x400012dc; -r_ble_ll_is_valid_own_addr_type = 0x400012e0; -r_ble_ll_is_valid_public_addr = 0x400012e4; -r_ble_ll_is_valid_random_addr = 0x400012e8; -r_ble_ll_mbuf_init = 0x400012ec; -r_ble_ll_misc_options_set = 0x400012f0; -r_ble_ll_pdu_max_tx_octets_get = 0x400012f4; -r_ble_ll_pdu_tx_time_get = 0x400012f8; -r_ble_ll_per_adv_coex_dpc_calc_pti_update_itvl = 0x400012fc; -r_ble_ll_per_adv_coex_dpc_process = 0x40001300; -r_ble_ll_per_adv_coex_dpc_pti_get = 0x40001304; -r_ble_ll_per_adv_coex_dpc_update = 0x40001308; -r_ble_ll_per_adv_coex_dpc_update_on_data_updated = 0x4000130c; -r_ble_ll_per_adv_coex_dpc_update_on_scheduled = 0x40001310; -r_ble_ll_per_adv_coex_dpc_update_on_start = 0x40001314; -r_ble_ll_phy_to_phy_mode = 0x40001318; -r_ble_ll_process_rx_data = 0x4000131c; -r_ble_ll_qa_enable = 0x40001320; -r_ble_ll_rand = 0x40001324; -r_ble_ll_rand_data_get = 0x40001328; -r_ble_ll_rand_deinit = 0x4000132c; -r_ble_ll_rand_env_init = 0x40001330; -r_ble_ll_rand_init = 0x40001334; -r_ble_ll_rand_prand_get = 0x40001338; -r_ble_ll_rand_sample = 0x4000133c; -r_ble_ll_rand_start = 0x40001340; -r_ble_ll_read_rf_path_compensation = 0x40001344; -r_ble_ll_read_supp_features = 0x40001348; -r_ble_ll_read_supp_states = 0x4000134c; -r_ble_ll_read_tx_power = 0x40001350; -r_ble_ll_reset = 0x40001354; -r_ble_ll_resolv_clear_all_pl_bit = 0x40001358; -r_ble_ll_resolv_clear_all_wl_bit = 0x4000135c; -r_ble_ll_resolv_deinit = 0x40001360; -r_ble_ll_resolv_enable_cmd = 0x40001364; -r_ble_ll_resolv_enabled = 0x40001368; -r_ble_ll_resolv_env_init = 0x4000136c; -r_ble_ll_resolv_gen_priv_addr = 0x40001370; -r_ble_ll_resolv_gen_rpa = 0x40001374; -r_ble_ll_resolv_get_addr_pointer = 0x40001378; -r_ble_ll_resolv_get_entry = 0x4000137c; -r_ble_ll_resolv_get_index = 0x40001380; -r_ble_ll_resolv_get_irk_pointer = 0x40001384; -r_ble_ll_resolv_get_list = 0x40001388; -r_ble_ll_resolv_get_priv_addr = 0x4000138c; -r_ble_ll_resolv_get_rpa_tmo = 0x40001390; -r_ble_ll_resolv_init = 0x40001394; -r_ble_ll_resolv_irk_nonzero = 0x40001398; -r_ble_ll_resolv_list_add = 0x4000139c; -r_ble_ll_resolv_list_chg_allowed = 0x400013a0; -r_ble_ll_resolv_list_clr = 0x400013a4; -r_ble_ll_resolv_list_find = 0x400013a8; -r_ble_ll_resolv_list_read_size = 0x400013ac; -r_ble_ll_resolv_list_reset = 0x400013b0; -r_ble_ll_resolv_list_rmv = 0x400013b4; -r_ble_ll_resolv_local_addr_rd = 0x400013b8; -r_ble_ll_resolv_peer_addr_rd = 0x400013bc; -r_ble_ll_resolv_peer_rpa_any = 0x400013c0; -r_ble_ll_resolv_reset = 0x400013c4; -r_ble_ll_resolv_rpa = 0x400013c8; -r_ble_ll_resolv_rpa_timer_cb = 0x400013cc; -r_ble_ll_resolv_set_local_rpa = 0x400013d0; -r_ble_ll_resolv_set_peer_rpa = 0x400013d4; -r_ble_ll_resolv_set_rpa_tmo = 0x400013d8; -r_ble_ll_resolve_set_priv_mode = 0x400013dc; -r_ble_ll_rfmgmt_controller_sleep_en = 0x400013e0; -r_ble_ll_rfmgmt_deinit = 0x400013e4; -r_ble_ll_rfmgmt_disable = 0x400013e8; -r_ble_ll_rfmgmt_enable = 0x400013ec; -r_ble_ll_rfmgmt_enable_now = 0x400013f0; -r_ble_ll_rfmgmt_init = 0x400013f4; -r_ble_ll_rfmgmt_is_enabled = 0x400013f8; -r_ble_ll_rfmgmt_release = 0x400013fc; -r_ble_ll_rfmgmt_release_ev = 0x40001400; -r_ble_ll_rfmgmt_reset = 0x40001404; -r_ble_ll_rfmgmt_scan_changed = 0x40001408; -r_ble_ll_rfmgmt_sched_changed = 0x4000140c; -r_ble_ll_rfmgmt_set_sleep_cb = 0x40001410; -r_ble_ll_rfmgmt_ticks_to_enabled = 0x40001414; -r_ble_ll_rfmgmt_timer_exp = 0x40001418; -r_ble_ll_rfmgmt_timer_reschedule = 0x4000141c; -r_ble_ll_rx_end = 0x40001420; -r_ble_ll_rx_pdu_in = 0x40001424; -r_ble_ll_rx_pkt_in = 0x40001428; -r_ble_ll_rx_start = 0x4000142c; -r_ble_ll_rxpdu_alloc = 0x40001430; -r_ble_ll_scan_add_scan_rsp_adv = 0x40001434; -r_ble_ll_scan_adv_decode_addr = 0x40001438; -r_ble_ll_scan_aux_data_free = 0x4000143c; -r_ble_ll_scan_aux_data_ref = 0x40001440; -r_ble_ll_scan_aux_data_unref = 0x40001444; -r_ble_ll_scan_can_chg_whitelist = 0x40001448; -r_ble_ll_scan_check_periodic_sync = 0x4000144c; -r_ble_ll_scan_chk_resume = 0x40001450; -r_ble_ll_scan_clean_cur_aux_data = 0x40001454; -r_ble_ll_scan_common_init = 0x40001458; -r_ble_ll_scan_continue_en = 0x4000145c; -r_ble_ll_scan_deinit = 0x40001460; -r_ble_ll_scan_dup_check_ext = 0x40001464; -r_ble_ll_scan_dup_check_legacy = 0x40001468; -r_ble_ll_scan_dup_move_to_head = 0x4000146c; -r_ble_ll_scan_dup_new = 0x40001470; -r_ble_ll_scan_dup_update_ext = 0x40001474; -r_ble_ll_scan_dup_update_legacy = 0x40001478; -r_ble_ll_scan_duration_period_timers_restart = 0x4000147c; -r_ble_ll_scan_duration_timer_cb = 0x40001480; -r_ble_ll_scan_enabled = 0x40001484; -r_ble_ll_scan_end_adv_evt = 0x40001488; -r_ble_ll_scan_env_init = 0x4000148c; -r_ble_ll_scan_event_proc = 0x40001490; -r_ble_ll_scan_ext_adv_init = 0x40001494; -r_ble_ll_scan_ext_initiator_start = 0x40001498; -r_ble_ll_scan_get_addr_data_from_legacy = 0x4000149c; -r_ble_ll_scan_get_addr_from_ext_adv = 0x400014a0; -r_ble_ll_scan_get_cur_sm = 0x400014a4; -r_ble_ll_scan_get_ext_adv_report = 0x400014a8; -r_ble_ll_scan_get_local_rpa = 0x400014ac; -r_ble_ll_scan_get_next_adv_prim_chan = 0x400014b0; -r_ble_ll_scan_get_pdu_data = 0x400014b4; -r_ble_ll_scan_get_peer_rpa = 0x400014b8; -r_ble_ll_scan_halt = 0x400014bc; -r_ble_ll_scan_has_sent_scan_req = 0x400014c0; -r_ble_ll_scan_have_rxd_scan_rsp = 0x400014c4; -r_ble_ll_scan_init = 0x400014c8; -r_ble_ll_scan_initiator_start = 0x400014cc; -r_ble_ll_scan_interrupted = 0x400014d0; -r_ble_ll_scan_interrupted_event_cb = 0x400014d4; -r_ble_ll_scan_is_inside_window = 0x400014d8; -r_ble_ll_scan_move_window_to = 0x400014dc; -r_ble_ll_scan_npl_init = 0x400014e0; -r_ble_ll_scan_npl_reset = 0x400014e4; -r_ble_ll_scan_npl_restore = 0x400014e8; -r_ble_ll_scan_npl_store = 0x400014ec; -r_ble_ll_scan_parse_ext_hdr = 0x400014f0; -r_ble_ll_scan_period_timer_cb = 0x400014f4; -r_ble_ll_scan_record_new_adv = 0x400014f8; -r_ble_ll_scan_refresh_nrpa = 0x400014fc; -r_ble_ll_scan_req_backoff = 0x40001500; -r_ble_ll_scan_reset = 0x40001504; -r_ble_ll_scan_rx_filter = 0x40001508; -r_ble_ll_scan_rx_isr_end = 0x4000150c; -r_ble_ll_scan_rx_isr_on_aux = 0x40001510; -r_ble_ll_scan_rx_isr_on_legacy = 0x40001514; -r_ble_ll_scan_rx_isr_start = 0x40001518; -r_ble_ll_scan_rx_pkt_in = 0x4000151c; -r_ble_ll_scan_rx_pkt_in_on_aux = 0x40001520; -r_ble_ll_scan_rx_pkt_in_on_legacy = 0x40001524; -r_ble_ll_scan_rx_pkt_in_restore_addr_data = 0x40001528; -r_ble_ll_scan_rxed = 0x4000152c; -r_ble_ll_scan_sched_remove = 0x40001530; -r_ble_ll_scan_send_adv_report = 0x40001534; -r_ble_ll_scan_send_truncated = 0x40001538; -r_ble_ll_scan_set_enable = 0x4000153c; -r_ble_ll_scan_set_peer_rpa = 0x40001540; -r_ble_ll_scan_set_scan_params = 0x40001544; -r_ble_ll_scan_sm_start = 0x40001548; -r_ble_ll_scan_sm_stop = 0x4000154c; -r_ble_ll_scan_start = 0x40001550; -r_ble_ll_scan_time_hci_to_ticks = 0x40001554; -r_ble_ll_scan_timer_cb = 0x40001558; -r_ble_ll_scan_update_aux_data = 0x4000155c; -r_ble_ll_scan_wfr_timer_exp = 0x40001560; -r_ble_ll_scan_whitelist_enabled = 0x40001564; -r_ble_ll_sched_adv_new = 0x40001568; -r_ble_ll_sched_adv_resched_pdu = 0x4000156c; -r_ble_ll_sched_adv_reschedule = 0x40001570; -r_ble_ll_sched_aux_scan = 0x40001574; -r_ble_ll_sched_conn_overlap = 0x40001578; -r_ble_ll_sched_conn_reschedule = 0x4000157c; -r_ble_ll_sched_deinit = 0x40001580; -r_ble_ll_sched_dtm = 0x40001584; -r_ble_ll_sched_env_init = 0x40001588; -r_ble_ll_sched_execute_item = 0x4000158c; -r_ble_ll_sched_init = 0x40001590; -r_ble_ll_sched_insert_if_empty = 0x40001594; -r_ble_ll_sched_is_overlap = 0x40001598; -r_ble_ll_sched_master_new = 0x4000159c; -r_ble_ll_sched_next_time = 0x400015a0; -r_ble_ll_sched_overlaps_current = 0x400015a4; -r_ble_ll_sched_periodic_adv = 0x400015a8; -r_ble_ll_sched_rmv_elem = 0x400015ac; -r_ble_ll_sched_rmv_elem_type = 0x400015b0; -r_ble_ll_sched_run = 0x400015b4; -r_ble_ll_sched_scan_req_over_aux_ptr = 0x400015b8; -r_ble_ll_sched_slave_new = 0x400015bc; -r_ble_ll_sched_stop = 0x400015c0; -r_ble_ll_sched_sync = 0x400015c4; -r_ble_ll_sched_sync_overlaps_current = 0x400015c8; -r_ble_ll_sched_sync_reschedule = 0x400015cc; -r_ble_ll_set_default_privacy_mode = 0x400015d0; -r_ble_ll_set_default_sync_transfer_params = 0x400015d4; -r_ble_ll_set_ext_scan_params = 0x400015d8; -r_ble_ll_set_host_feat = 0x400015dc; -r_ble_ll_set_public_addr = 0x400015e0; -r_ble_ll_set_random_addr = 0x400015e4; -r_ble_ll_set_sync_transfer_params = 0x400015e8; -r_ble_ll_slave_rx_isr_end = 0x400015ec; -r_ble_ll_state_get = 0x400015f0; -r_ble_ll_state_set = 0x400015f4; -r_ble_ll_sync_adjust_ext_hdr = 0x400015f8; -r_ble_ll_sync_cancel = 0x400015fc; -r_ble_ll_sync_cancel_complete_event = 0x40001600; -r_ble_ll_sync_chain_start_cb = 0x40001604; -r_ble_ll_sync_check_acad = 0x40001608; -r_ble_ll_sync_check_failed = 0x4000160c; -r_ble_ll_sync_coex_dpc_process = 0x40001610; -r_ble_ll_sync_coex_dpc_pti_get = 0x40001614; -r_ble_ll_sync_coex_dpc_update = 0x40001618; -r_ble_ll_sync_create = 0x4000161c; -r_ble_ll_sync_current_sm_over = 0x40001620; -r_ble_ll_sync_deinit = 0x40001624; -r_ble_ll_sync_enabled = 0x40001628; -r_ble_ll_sync_env_init = 0x4000162c; -r_ble_ll_sync_est_event_failed = 0x40001630; -r_ble_ll_sync_est_event_success = 0x40001634; -r_ble_ll_sync_established = 0x40001638; -r_ble_ll_sync_event_end = 0x4000163c; -r_ble_ll_sync_event_start_cb = 0x40001640; -r_ble_ll_sync_filter_enabled = 0x40001644; -r_ble_ll_sync_find = 0x40001648; -r_ble_ll_sync_get_cur_sm = 0x4000164c; -r_ble_ll_sync_get_event_end_time = 0x40001650; -r_ble_ll_sync_get_handle = 0x40001654; -r_ble_ll_sync_halt = 0x40001658; -r_ble_ll_sync_has_been_reported = 0x4000165c; -r_ble_ll_sync_info_event = 0x40001660; -r_ble_ll_sync_init = 0x40001664; -r_ble_ll_sync_list_add = 0x40001668; -r_ble_ll_sync_list_clear = 0x4000166c; -r_ble_ll_sync_list_empty = 0x40001670; -r_ble_ll_sync_list_get_free = 0x40001674; -r_ble_ll_sync_list_remove = 0x40001678; -r_ble_ll_sync_list_search = 0x4000167c; -r_ble_ll_sync_list_size = 0x40001680; -r_ble_ll_sync_lost_event = 0x40001684; -r_ble_ll_sync_next_event = 0x40001688; -r_ble_ll_sync_on_list = 0x4000168c; -r_ble_ll_sync_parse_aux_ptr = 0x40001690; -r_ble_ll_sync_parse_ext_hdr = 0x40001694; -r_ble_ll_sync_periodic_ind = 0x40001698; -r_ble_ll_sync_phy_mode_to_aux_phy = 0x4000169c; -r_ble_ll_sync_phy_mode_to_hci = 0x400016a0; -r_ble_ll_sync_put_syncinfo = 0x400016a4; -r_ble_ll_sync_reserve = 0x400016a8; -r_ble_ll_sync_reset = 0x400016ac; -r_ble_ll_sync_reset_sm = 0x400016b0; -r_ble_ll_sync_rmvd_from_sched = 0x400016b4; -r_ble_ll_sync_rx_isr_end = 0x400016b8; -r_ble_ll_sync_rx_isr_start = 0x400016bc; -r_ble_ll_sync_rx_pkt_in = 0x400016c0; -r_ble_ll_sync_schedule_chain = 0x400016c4; -r_ble_ll_sync_send_per_adv_rpt = 0x400016c8; -r_ble_ll_sync_send_sync_ind = 0x400016cc; -r_ble_ll_sync_send_truncated_per_adv_rpt = 0x400016d0; -r_ble_ll_sync_sm_clear = 0x400016d4; -r_ble_ll_sync_terminate = 0x400016d8; -r_ble_ll_sync_transfer = 0x400016dc; -r_ble_ll_sync_transfer_get = 0x400016e0; -r_ble_ll_sync_transfer_received = 0x400016e4; -r_ble_ll_sync_wfr_timer_exp = 0x400016e8; -r_ble_ll_task = 0x400016ec; -r_ble_ll_trace_set_func = 0x400016f0; -r_ble_ll_trace_u32 = 0x400016f4; -r_ble_ll_trace_u32x2 = 0x400016f8; -r_ble_ll_trace_u32x3 = 0x400016fc; -r_ble_ll_tx_flat_mbuf_pducb = 0x40001700; -r_ble_ll_tx_mbuf_pducb = 0x40001704; -r_ble_ll_tx_pkt_in = 0x40001708; -r_ble_ll_update_max_tx_octets_phy_mode = 0x4000170c; -r_ble_ll_usecs_to_ticks_round_up = 0x40001710; -r_ble_ll_utils_calc_access_addr = 0x40001714; -r_ble_ll_utils_calc_dci_csa2 = 0x40001718; -r_ble_ll_utils_calc_num_used_chans = 0x4000171c; -r_ble_ll_utils_calc_window_widening = 0x40001720; -r_ble_ll_utils_csa2_perm = 0x40001724; -r_ble_ll_utils_csa2_prng = 0x40001728; -r_ble_ll_utils_remapped_channel = 0x4000172c; -r_ble_ll_wfr_timer_exp = 0x40001730; -r_ble_ll_whitelist_add = 0x40001734; -r_ble_ll_whitelist_chg_allowed = 0x40001738; -r_ble_ll_whitelist_clear = 0x4000173c; -r_ble_ll_whitelist_read_size = 0x40001740; -r_ble_ll_whitelist_rmv = 0x40001744; -r_ble_ll_whitelist_search = 0x40001748; -r_ble_ll_write_rf_path_compensation = 0x4000174c; -r_ble_phy_access_addr_get = 0x40001750; -r_ble_phy_bb_bug_is_triggered = 0x40001754; -r_ble_phy_calculate_rxtx_ifs = 0x40001758; -r_ble_phy_calculate_rxwindow = 0x4000175c; -r_ble_phy_calculate_txrx_ifs = 0x40001760; -r_ble_phy_config_access_addr = 0x40001764; -r_ble_phy_data_make = 0x40001768; -r_ble_phy_disable = 0x4000176c; -r_ble_phy_disable_irq = 0x40001770; -r_ble_phy_disable_whitening = 0x40001774; -r_ble_phy_enable_scan_seq_immediately = 0x40001778; -r_ble_phy_enable_whitening = 0x4000177c; -r_ble_phy_encrypt_disable = 0x40001780; -r_ble_phy_env_init = 0x40001784; -r_ble_phy_get_current_phy = 0x40001788; -r_ble_phy_get_packet_counter = 0x4000178c; -r_ble_phy_get_packet_status = 0x40001790; -r_ble_phy_get_pyld_time_offset = 0x40001794; -r_ble_phy_get_rx_phy_mode = 0x40001798; -r_ble_phy_init = 0x4000179c; -r_ble_phy_isr = 0x400017a0; -r_ble_phy_max_data_pdu_pyld = 0x400017a4; -r_ble_phy_mode_config = 0x400017a8; -r_ble_phy_mode_convert = 0x400017ac; -r_ble_phy_mode_write = 0x400017b0; -r_ble_phy_module_deinit = 0x400017b4; -r_ble_phy_module_init = 0x400017b8; -r_ble_phy_monitor_bb_sync = 0x400017bc; -r_ble_phy_need_to_report = 0x400017c0; -r_ble_phy_pkt_received = 0x400017c4; -r_ble_phy_reset_bb_monitor = 0x400017c8; -r_ble_phy_resolv_list_disable = 0x400017cc; -r_ble_phy_resolv_list_enable = 0x400017d0; -r_ble_phy_restart_sequence = 0x400017d4; -r_ble_phy_rfclk_disable = 0x400017d8; -r_ble_phy_rfclk_enable = 0x400017dc; -r_ble_phy_rx_is_expected = 0x400017e0; -r_ble_phy_rxpdu_copy = 0x400017e4; -r_ble_phy_scan_set_start_time = 0x400017e8; -r_ble_phy_seq_encrypt_enable = 0x400017ec; -r_ble_phy_seq_encrypt_set_pkt_cntr = 0x400017f0; -r_ble_phy_sequence_adv_end = 0x400017f4; -r_ble_phy_sequence_copy_rx_flags = 0x400017f8; -r_ble_phy_sequence_end_isr = 0x400017fc; -r_ble_phy_sequence_get_mode = 0x40001800; -r_ble_phy_sequence_get_state = 0x40001804; -r_ble_phy_sequence_init_end = 0x40001808; -r_ble_phy_sequence_is_running = 0x4000180c; -r_ble_phy_sequence_is_waiting_rsp = 0x40001810; -r_ble_phy_sequence_isr_copy_data = 0x40001814; -r_ble_phy_sequence_master_end = 0x40001818; -r_ble_phy_sequence_rx_end_isr = 0x4000181c; -r_ble_phy_sequence_scan_end = 0x40001820; -r_ble_phy_sequence_single_end = 0x40001824; -r_ble_phy_sequence_slave_end = 0x40001828; -r_ble_phy_sequence_tx_end_invoke = 0x4000182c; -r_ble_phy_sequence_update_conn_params = 0x40001830; -r_ble_phy_set_adv_sequence = 0x40001834; -r_ble_phy_set_coex_pti = 0x40001838; -r_ble_phy_set_dev_address = 0x4000183c; -r_ble_phy_set_master_sequence = 0x40001840; -r_ble_phy_set_rx_pwr_compensation = 0x40001844; -r_ble_phy_set_rxhdr_flags = 0x40001848; -r_ble_phy_set_rxhdr_info = 0x4000184c; -r_ble_phy_set_scan_sequence = 0x40001850; -r_ble_phy_set_single_packet_rx_sequence = 0x40001854; -r_ble_phy_set_single_packet_tx_sequence = 0x40001858; -r_ble_phy_set_slave_sequence = 0x4000185c; -r_ble_phy_set_txend_cb = 0x40001860; -r_ble_phy_setchan = 0x40001864; -r_ble_phy_slave_set_start_time = 0x40001868; -r_ble_phy_state_get = 0x4000186c; -r_ble_phy_timer_config_start_time = 0x40001870; -r_ble_phy_timer_start_now = 0x40001874; -r_ble_phy_timer_stop = 0x40001878; -r_ble_phy_tx_set_start_time = 0x4000187c; -r_ble_phy_txpower_round = 0x40001880; -r_ble_phy_txpwr_set = 0x40001884; -r_ble_phy_wfr_enable = 0x40001888; -r_ble_phy_xcvr_state_get = 0x4000188c; -r_ble_plf_set_log_level = 0x40001890; -r_ble_vendor_hci_register = 0x40001894; -r_bleonly_os_tick_init = 0x40001898; -r_bt_rf_coex_cfg_set = 0x4000189c; -r_bt_rf_coex_coded_txrx_time_upper_lim = 0x400018a0; -r_bt_rf_coex_dft_pti_set = 0x400018a4; -r_bt_rf_coex_hook_deinit = 0x400018a8; -r_bt_rf_coex_hook_init = 0x400018ac; -r_bt_rf_coex_hook_st_set = 0x400018b0; -r_bt_rf_coex_hooks_p_set_default = 0x400018b4; -r_btdm_disable_adv_delay = 0x400018b8; -r_btdm_switch_phy_coded = 0x400018bc; -r_esp_wait_disabled = 0x400018c0; -r_get_be16 = 0x400018c4; -r_get_be24 = 0x400018c8; -r_get_be32 = 0x400018cc; -r_get_be64 = 0x400018d0; -r_get_le16 = 0x400018d4; -r_get_le24 = 0x400018d8; -r_get_le32 = 0x400018dc; -r_get_le64 = 0x400018e0; -r_get_local_irk_offset = 0x400018e4; -r_get_local_rpa_offset = 0x400018e8; -r_get_max_skip = 0x400018ec; -r_get_peer_id_offset = 0x400018f0; -r_get_peer_irk_offset = 0x400018f4; -r_get_peer_rpa_offset = 0x400018f8; -r_hal_os_tick_read_tick = 0x400018fc; -r_hal_os_tick_set_exp_tick = 0x40001900; -r_hal_rtc_intr_init = 0x40001904; -r_hal_rtc_irq_handler = 0x40001908; -r_hal_timer_deinit = 0x4000190c; -r_hal_timer_disable_irq = 0x40001910; -r_hal_timer_env_init = 0x40001914; -r_hal_timer_init = 0x40001918; -r_hal_timer_process = 0x4000191c; -r_hal_timer_read = 0x40001920; -r_hal_timer_read_tick = 0x40001924; -r_hal_timer_set_cb = 0x40001928; -r_hal_timer_set_exp_tick = 0x4000192c; -r_hal_timer_start = 0x40001930; -r_hal_timer_start_at = 0x40001934; -r_hal_timer_stop = 0x40001938; -r_hal_timer_task_start = 0x4000193c; -r_ll_assert = 0x40001940; -r_mem_init_mbuf_pool = 0x40001944; -r_mem_malloc_mbuf_pool = 0x40001948; -r_mem_malloc_mbufpkt_pool = 0x4000194c; -r_mem_malloc_mempool = 0x40001950; -r_mem_malloc_mempool_ext = 0x40001954; -r_mem_malloc_mempool_gen = 0x40001958; -r_mem_pullup_obj = 0x4000195c; -r_mem_split_frag = 0x40001960; -r_os_cputime_delay_ticks = 0x40001964; -r_os_cputime_delay_usecs = 0x40001968; -r_os_cputime_get32 = 0x4000196c; -r_os_cputime_ticks_to_usecs = 0x40001970; -r_os_cputime_timer_init = 0x40001974; -r_os_cputime_timer_relative = 0x40001978; -r_os_cputime_timer_start = 0x4000197c; -r_os_cputime_timer_stop = 0x40001980; -r_os_cputime_usecs_to_ticks = 0x40001984; -r_os_mbuf_adj = 0x40001988; -r_os_mbuf_append = 0x4000198c; -r_os_mbuf_appendfrom = 0x40001990; -r_os_mbuf_cmpf = 0x40001994; -r_os_mbuf_cmpm = 0x40001998; -r_os_mbuf_concat = 0x4000199c; -r_os_mbuf_copydata = 0x400019a0; -r_os_mbuf_copyinto = 0x400019a4; -r_os_mbuf_dup = 0x400019a8; -r_os_mbuf_extend = 0x400019ac; -r_os_mbuf_free = 0x400019b0; -r_os_mbuf_free_chain = 0x400019b4; -r_os_mbuf_get = 0x400019b8; -r_os_mbuf_get_pkthdr = 0x400019bc; -r_os_mbuf_len = 0x400019c0; -r_os_mbuf_off = 0x400019c4; -r_os_mbuf_pack_chains = 0x400019c8; -r_os_mbuf_pool_init = 0x400019cc; -r_os_mbuf_prepend = 0x400019d0; -r_os_mbuf_prepend_pullup = 0x400019d4; -r_os_mbuf_pullup = 0x400019d8; -r_os_mbuf_trim_front = 0x400019dc; -r_os_mbuf_widen = 0x400019e0; -r_os_memblock_from = 0x400019e4; -r_os_memblock_get = 0x400019e8; -r_os_memblock_put = 0x400019ec; -r_os_memblock_put_from_cb = 0x400019f0; -r_os_mempool_clear = 0x400019f4; -r_os_mempool_ext_clear = 0x400019f8; -r_os_mempool_ext_init = 0x400019fc; -r_os_mempool_info_get_next = 0x40001a00; -r_os_mempool_init = 0x40001a04; -r_os_mempool_init_internal = 0x40001a08; -r_os_mempool_is_sane = 0x40001a0c; -r_os_mempool_module_init = 0x40001a10; -r_os_mempool_unregister = 0x40001a14; -r_os_mqueue_get = 0x40001a18; -r_os_mqueue_init = 0x40001a1c; -r_os_mqueue_put = 0x40001a20; -r_os_msys_count = 0x40001a24; -r_os_msys_get = 0x40001a28; -r_os_msys_get_pkthdr = 0x40001a2c; -r_os_msys_num_free = 0x40001a30; -r_os_msys_register = 0x40001a34; -r_os_msys_reset = 0x40001a38; -r_os_tick_idle = 0x40001a3c; -r_pri_phy_valid = 0x40001a40; -r_put_be16 = 0x40001a44; -r_put_be24 = 0x40001a48; -r_put_be32 = 0x40001a4c; -r_put_be64 = 0x40001a50; -r_put_le16 = 0x40001a54; -r_put_le24 = 0x40001a58; -r_put_le32 = 0x40001a5c; -r_put_le64 = 0x40001a60; -r_rtc0_timer_handler = 0x40001a64; -r_rtc1_timer_handler = 0x40001a68; -r_sdkconfig_get_opts = 0x40001a6c; -r_sdkconfig_set_opts = 0x40001a70; -r_sec_phy_valid = 0x40001a74; -r_sub24 = 0x40001a78; -r_swap_buf = 0x40001a7c; -r_swap_in_place = 0x40001a80; -/* Data (.data, .bss, .rodata) */ -ble_hci_uart_reset_cmd = 0x3ff1ffe0; -ble_hci_trans_env_p = 0x3fcdffc4; -ble_hci_trans_mode = 0x3fcdfebc; -ble_ll_adv_env_p = 0x3fcdffc0; -ble_ll_conn_env_p = 0x3fcdffbc; -g_ble_ll_conn_cth_flow = 0x3fcdffb4; -g_ble_ll_conn_cth_flow_error_ev = 0x3fcdffb0; -g_ble_ll_ctrl_pkt_lengths_ro = 0x3ff1ffbc; -ble_ll_dtm_module_env_p = 0x3fcdffac; -channel_rf_to_index = 0x3ff1ff94; -g_ble_ll_dtm_prbs15_data = 0x3ff1fe94; -g_ble_ll_dtm_prbs9_data = 0x3ff1fd94; -ble_ll_hci_env_p = 0x3fcdffa8; -ble_ll_rand_env_p = 0x3fcdffa4; -ble_ll_resolv_env_p = 0x3fcdffa0; -g_ble_ll_resolve_hdr = 0x3fcdff98; -g_device_mode_default = 0x3fcdfeba; -g_ble_ll_rfmgmt_data = 0x3fcdff50; -g_ble_sleep_enter_cb = 0x3fcdff4c; -g_ble_sleep_exit_cb = 0x3fcdff48; -g_rfclk_enabled = 0x3fcdff44; -ble_ll_scan_env_p = 0x3fcdff40; -ble_ll_sched_env_p = 0x3fcdff3c; -g_ble_ll_supp_cmds_ro = 0x3ff1fd64; -ble_ll_sync_env_p = 0x3fcdff38; -g_ble_sca_ppm_tbl_ro = 0x3ff1fd54; -ble_ll_env_p = 0x3fcdff34; -g_ble_ll_pdu_header_tx_time_ro = 0x3ff1fd4c; -priv_config_opts = 0x3fcdfea4; -ble_hci_trans_funcs_ptr = 0x3fcdff30; -r_ble_stub_funcs_ptr = 0x3fcdff2c; -r_ext_funcs_p = 0x3fcdff28; -r_npl_funcs = 0x3fcdff24; -ble_hw_env_p = 0x3fcdff20; -ble_phy_module_env_p = 0x3fcdff1c; -g_ble_phy_chan_freq_ro = 0x3ff1fd24; -g_ble_phy_mode_pkt_start_off_ro = 0x3ff1fd1c; -g_ble_phy_rxtx_ifs_compensation_ro = 0x3ff1fd0c; -g_ble_phy_t_rxaddrdelay_ro = 0x3ff1fd08; -g_ble_phy_t_rxenddelay_ro = 0x3ff1fd04; -g_ble_phy_t_txdelay_ro = 0x3ff1fd00; -g_ble_phy_t_txenddelay_ro = 0x3ff1fcfc; -g_ble_phy_txrx_ifs_compensation_ro = 0x3ff1fcec; -hal_timer_env_p = 0x3fcdff18; -g_hal_os_tick = 0x3fcdff0c; -r_osi_coex_funcs_p = 0x3fcdff08; -bt_rf_coex_hooks = 0x3fcdff00; -bt_rf_coex_hooks_p = 0x3fcdfefc; -coex_hook_st_group_tab = 0x3ff1fce0; -coex_hook_st_group_to_coex_schm_st_tab = 0x3ff1fcdc; -s_ble_act_count_by_group = 0x3fcdfef8; -s_ble_coex_st_map = 0x3fcdfee4; -bt_rf_coex_cfg_cb = 0x3fcdfec8; -bt_rf_coex_cfg_p = 0x3fcdfec4; -bt_rf_coex_cfg_rom = 0x3ff1fcc0; -bt_rf_coex_pti_dft_p = 0x3fcdfec0; -bt_rf_coex_pti_dft_rom = 0x3fcdfe64; -conn_dynamic_pti_param_rom = 0x3ff1fca8; -conn_phy_coded_max_data_time_param_rom = 0x3ff1fca4; -ext_adv_dynamic_pti_param_rom = 0x3ff1fc70; -ext_scan_dynamic_param_rom = 0x3ff1fc38; -legacy_adv_dynamic_pti_param_rom = 0x3ff1fc18; -per_adv_dynamic_pti_param_rom = 0x3ff1fbfc; -sync_dynamic_param_rom = 0x3ff1fbe4; -g_ble_plf_log_level = 0x3fcdfe60; -g_msys_pool_list = 0x3fcdfe58; -g_os_mempool_list = 0x3fcdfe50; - - -/*************************************** - Group rom_phy - ***************************************/ - -/* Functions */ -phy_param_addr = 0x40001a84; -phy_get_romfuncs = 0x40001a88; -chip729_phyrom_version = 0x40001a8c; -chip729_phyrom_version_num = 0x40001a90; -rom_get_i2c_read_mask = 0x40001c6c; -rom_get_i2c_mst0_mask = 0x40001c70; -rom_get_i2c_hostid = 0x40001c74; -rom_chip_i2c_readReg_org = 0x40001c78; -rom_chip_i2c_readReg = 0x40001c7c; -rom_i2c_paral_set_mst0 = 0x40001c80; -rom_i2c_paral_set_read = 0x40001c84; -rom_i2c_paral_read = 0x40001c88; -rom_i2c_paral_write = 0x40001c8c; -rom_i2c_paral_write_num = 0x40001c90; -rom_i2c_paral_write_mask = 0x40001c94; -rom_i2c_readReg = 0x40001c98; -rom_chip_i2c_writeReg = 0x40001c9c; -rom_i2c_writeReg = 0x40001ca0; -rom_i2c_readReg_Mask = 0x40001ca4; -rom_i2c_writeReg_Mask = 0x40001ca8; -/* Data (.data, .bss, .rodata) */ -phy_param_rom = 0x3fcdfe4c; diff --git a/tools/esptool_py/flasher_stub/ld/rom_32p4.ld b/tools/esptool_py/flasher_stub/ld/rom_32p4.ld deleted file mode 100644 index 51ac8cded6..0000000000 --- a/tools/esptool_py/flasher_stub/ld/rom_32p4.ld +++ /dev/null @@ -1,619 +0,0 @@ -/* ROM function interface esp32p4.rom.ld for esp32p4 - * - * - * Generated from ./target/esp32p4/interface-esp32p4.yml md5sum f6516bd9708d890f63db87f8aed53ca7 - * - * Compatible with ROM where ECO version equal or greater to 0. - * - * THIS FILE WAS AUTOMATICALLY GENERATED. DO NOT EDIT. - */ - -/*************************************** - Group common - ***************************************/ - -PROVIDE ( SPIWrite = esp_rom_spiflash_write); -PROVIDE ( SPI_read_status_high = esp_rom_spiflash_read_statushigh); -PROVIDE ( SPI_write_status = esp_rom_spiflash_write_status); -PROVIDE ( SPIRead = esp_rom_spiflash_read); -PROVIDE ( SPIParamCfg = esp_rom_spiflash_config_param); -PROVIDE ( SPIEraseChip = esp_rom_spiflash_erase_chip); -PROVIDE ( SPIEraseSector = esp_rom_spiflash_erase_sector); -PROVIDE ( SPIEraseBlock = esp_rom_spiflash_erase_block); -PROVIDE ( SPI_Write_Encrypt_Enable = esp_rom_spiflash_write_encrypted_enable); -PROVIDE ( SPI_Write_Encrypt_Disable = esp_rom_spiflash_write_encrypted_disable); -PROVIDE ( SPI_Encrypt_Write = esp_rom_spiflash_write_encrypted); - -/*************************************** - Group common - ***************************************/ - -/* Functions */ -rtc_get_reset_reason = 0x4fc00018; -rtc_get_wakeup_cause = 0x4fc0001c; -pmu_enable_unhold_pads = 0x4fc00020; -ets_printf = 0x4fc00024; -ets_install_putc1 = 0x4fc00028; -ets_install_putc2 = 0x4fc0002c; -ets_install_uart_printf = 0x4fc00030; -ets_install_usb_printf = 0x4fc00034; -ets_get_printf_channel = 0x4fc00038; -ets_delay_us = 0x4fc0003c; -ets_get_cpu_frequency = 0x4fc00040; -ets_update_cpu_frequency = 0x4fc00044; -ets_install_lock = 0x4fc00048; -UartRxString = 0x4fc0004c; -UartGetCmdLn = 0x4fc00050; -uart_tx_one_char = 0x4fc00054; -uart_tx_one_char2 = 0x4fc00058; -uart_tx_one_char3 = 0x4fc0005c; -uart_rx_one_char = 0x4fc00060; -uart_rx_one_char_block = 0x4fc00064; -uart_rx_intr_handler = 0x4fc00068; -uart_rx_readbuff = 0x4fc0006c; -uartAttach = 0x4fc00070; -uart_tx_flush = 0x4fc00074; -uart_tx_wait_idle = 0x4fc00078; -uart_div_modify = 0x4fc0007c; -ets_write_char_uart = 0x4fc00080; -uart_tx_switch = 0x4fc00084; -uart_buff_switch = 0x4fc00088; -roundup2 = 0x4fc0008c; -multofup = 0x4fc00090; -software_reset = 0x4fc00094; -software_reset_cpu = 0x4fc00098; -ets_clk_assist_debug_clock_enable = 0x4fc0009c; -clear_super_wdt_reset_flag = 0x4fc000a0; -disable_default_watchdog = 0x4fc000a4; -ets_set_appcpu_boot_addr = 0x4fc000a8; -send_packet = 0x4fc000ac; -recv_packet = 0x4fc000b0; -GetUartDevice = 0x4fc000b4; -UartDwnLdProc = 0x4fc000b8; -GetSecurityInfoProc = 0x4fc000bc; -Uart_Init = 0x4fc000c0; -ets_set_user_start = 0x4fc000c4; -/* Data (.data, .bss, .rodata) */ -ets_rom_layout_p = 0x4fc1fffc; -ets_ops_table_ptr = 0x4ff3fff4; -g_saved_pc = 0x4ff3fff8; - - -/*************************************** - Group miniz - ***************************************/ - -/* Functions */ -mz_adler32 = 0x4fc000c8; -mz_free = 0x4fc000cc; -tdefl_compress = 0x4fc000d0; -tdefl_compress_buffer = 0x4fc000d4; -tdefl_compress_mem_to_heap = 0x4fc000d8; -tdefl_compress_mem_to_mem = 0x4fc000dc; -tdefl_compress_mem_to_output = 0x4fc000e0; -tdefl_get_adler32 = 0x4fc000e4; -tdefl_get_prev_return_status = 0x4fc000e8; -tdefl_init = 0x4fc000ec; -tdefl_write_image_to_png_file_in_memory = 0x4fc000f0; -tdefl_write_image_to_png_file_in_memory_ex = 0x4fc000f4; -tinfl_decompress = 0x4fc000f8; -tinfl_decompress_mem_to_callback = 0x4fc000fc; -tinfl_decompress_mem_to_heap = 0x4fc00100; -tinfl_decompress_mem_to_mem = 0x4fc00104; - - -/*************************************** - Group spi_extmem_common - ***************************************/ - -/* Functions */ -esp_rom_spi_cmd_config = 0x4fc00108; -esp_rom_spi_cmd_start = 0x4fc0010c; -esp_rom_spi_set_op_mode = 0x4fc00110; -esp_rom_spi_set_dtr_swap_mode = 0x4fc00114; - - -/*************************************** - Group spiflash_legacy - ***************************************/ - -/* Functions */ -esp_rom_spiflash_wait_idle = 0x4fc00118; -esp_rom_spiflash_write_encrypted = 0x4fc0011c; -esp_rom_spiflash_write_encrypted_dest = 0x4fc00120; -esp_rom_spiflash_write_encrypted_enable = 0x4fc00124; -esp_rom_spiflash_write_encrypted_disable = 0x4fc00128; -esp_rom_spiflash_erase_chip = 0x4fc0012c; -_esp_rom_spiflash_erase_sector = 0x4fc00130; -_esp_rom_spiflash_erase_block = 0x4fc00134; -_esp_rom_spiflash_write = 0x4fc00138; -_esp_rom_spiflash_read = 0x4fc0013c; -_esp_rom_spiflash_unlock = 0x4fc00140; -_SPIEraseArea = 0x4fc00144; -_SPI_write_enable = 0x4fc00148; -esp_rom_spiflash_erase_sector = 0x4fc0014c; -esp_rom_spiflash_erase_block = 0x4fc00150; -esp_rom_spiflash_write = 0x4fc00154; -esp_rom_spiflash_read = 0x4fc00158; -esp_rom_spiflash_unlock = 0x4fc0015c; -SPIEraseArea = 0x4fc00160; -SPI_write_enable = 0x4fc00164; -esp_rom_spiflash_config_param = 0x4fc00168; -esp_rom_spiflash_read_user_cmd = 0x4fc0016c; -esp_rom_spiflash_select_qio_pins = 0x4fc00170; -esp_rom_spi_flash_auto_sus_res = 0x4fc00174; -esp_rom_spi_flash_send_resume = 0x4fc00178; -esp_rom_spi_flash_update_id = 0x4fc0017c; -esp_rom_spiflash_config_clk = 0x4fc00180; -esp_rom_spiflash_config_readmode = 0x4fc00184; -esp_rom_spiflash_read_status = 0x4fc00188; -esp_rom_spiflash_read_statushigh = 0x4fc0018c; -esp_rom_spiflash_write_status = 0x4fc00190; -esp_rom_spiflash_write_disable = 0x4fc00194; -spi_cache_mode_switch = 0x4fc00198; -spi_common_set_dummy_output = 0x4fc0019c; -spi_common_set_flash_cs_timing = 0x4fc001a0; -esp_rom_spi_set_address_bit_len = 0x4fc001a4; -SPILock = 0x4fc001a8; -SPIMasterReadModeCnfig = 0x4fc001ac; -SPI_Common_Command = 0x4fc001b0; -SPI_WakeUp = 0x4fc001b4; -SPI_block_erase = 0x4fc001b8; -SPI_chip_erase = 0x4fc001bc; -SPI_init = 0x4fc001c0; -SPI_page_program = 0x4fc001c4; -SPI_read_data = 0x4fc001c8; -SPI_sector_erase = 0x4fc001cc; -SelectSpiFunction = 0x4fc001d0; -SetSpiDrvs = 0x4fc001d4; -Wait_SPI_Idle = 0x4fc001d8; -spi_dummy_len_fix = 0x4fc001dc; -Disable_QMode = 0x4fc001e0; -Enable_QMode = 0x4fc001e4; -spi_flash_attach = 0x4fc001e8; -spi_flash_get_chip_size = 0x4fc001ec; -spi_flash_guard_set = 0x4fc001f0; -spi_flash_guard_get = 0x4fc001f4; -spi_flash_read_encrypted = 0x4fc001f8; -/* Data (.data, .bss, .rodata) */ -rom_spiflash_legacy_funcs = 0x4ff3ffec; -rom_spiflash_legacy_data = 0x4ff3ffe8; -g_flash_guard_ops = 0x4ff3fff0; - - -/*************************************** - Group hal_systimer - ***************************************/ - -/* Functions */ -systimer_hal_init = 0x4fc00228; -systimer_hal_deinit = 0x4fc0022c; -systimer_hal_set_tick_rate_ops = 0x4fc00230; -systimer_hal_get_counter_value = 0x4fc00234; -systimer_hal_get_time = 0x4fc00238; -systimer_hal_set_alarm_target = 0x4fc0023c; -systimer_hal_set_alarm_period = 0x4fc00240; -systimer_hal_get_alarm_value = 0x4fc00244; -systimer_hal_enable_alarm_int = 0x4fc00248; -systimer_hal_on_apb_freq_update = 0x4fc0024c; -systimer_hal_counter_value_advance = 0x4fc00250; -systimer_hal_enable_counter = 0x4fc00254; -systimer_hal_select_alarm_mode = 0x4fc00258; -systimer_hal_connect_alarm_counter = 0x4fc0025c; -systimer_hal_counter_can_stall_by_cpu = 0x4fc00260; - - -/*************************************** - Group cache - ***************************************/ - -/* Functions */ -Cache_Get_L1_ICache_Line_Size = 0x4fc003c4; -Cache_Get_L1_DCache_Line_Size = 0x4fc003c8; -Cache_Get_L2_Cache_Line_Size = 0x4fc003cc; -Cache_Get_Mode = 0x4fc003d0; -Cache_Set_L2_Cache_Mode = 0x4fc003d4; -Cache_Address_Through_Cache = 0x4fc003d8; -ROM_Boot_Cache_Init = 0x4fc003dc; -Cache_Sync_Addr = 0x4fc003e0; -Cache_Invalidate_Addr = 0x4fc003e4; -Cache_Invalidate_Addr_Gid = 0x4fc003e8; -Cache_Clean_Addr = 0x4fc003ec; -Cache_Clean_Addr_Gid = 0x4fc003f0; -Cache_WriteBack_Addr = 0x4fc003f4; -Cache_WriteBack_Addr_Gid = 0x4fc003f8; -Cache_WriteBack_Invalidate_Addr = 0x4fc003fc; -Cache_WriteBack_Invalidate_Addr_Gid = 0x4fc00400; -Cache_Invalidate_All = 0x4fc00404; -Cache_Invalidate_All_Gid = 0x4fc00408; -Cache_Clean_All = 0x4fc0040c; -Cache_Clean_All_Gid = 0x4fc00410; -Cache_WriteBack_All = 0x4fc00414; -Cache_WriteBack_All_Gid = 0x4fc00418; -Cache_WriteBack_Invalidate_All = 0x4fc0041c; -Cache_WriteBack_Invalidate_All_Gid = 0x4fc00420; -Cache_Mask_All = 0x4fc00424; -Cache_Suspend_L1_CORE0_ICache_Autoload = 0x4fc00428; -Cache_Resume_L1_CORE0_ICache_Autoload = 0x4fc0042c; -Cache_Suspend_L1_CORE1_ICache_Autoload = 0x4fc00430; -Cache_Resume_L1_CORE1_ICache_Autoload = 0x4fc00434; -Cache_Suspend_L1_DCache_Autoload = 0x4fc00438; -Cache_Resume_L1_DCache_Autoload = 0x4fc0043c; -Cache_Suspend_L2_Cache_Autoload = 0x4fc00440; -Cache_Resume_L2_Cache_Autoload = 0x4fc00444; -Cache_Start_L1_CORE0_ICache_Preload = 0x4fc00448; -Cache_L1_CORE0_ICache_Preload_Done = 0x4fc0044c; -Cache_End_L1_CORE0_ICache_Preload = 0x4fc00450; -Cache_Start_L1_CORE1_ICache_Preload = 0x4fc00454; -Cache_L1_CORE1_ICache_Preload_Done = 0x4fc00458; -Cache_End_L1_CORE1_ICache_Preload = 0x4fc0045c; -Cache_Start_L1_DCache_Preload = 0x4fc00460; -Cache_L1_DCache_Preload_Done = 0x4fc00464; -Cache_End_L1_DCache_Preload = 0x4fc00468; -Cache_Start_L2_Cache_Preload = 0x4fc0046c; -Cache_L2_Cache_Preload_Done = 0x4fc00470; -Cache_End_L2_Cache_Preload = 0x4fc00474; -Cache_Config_L1_CORE0_ICache_Autoload = 0x4fc00478; -Cache_Enable_L1_CORE0_ICache_Autoload = 0x4fc0047c; -Cache_Disable_L1_CORE0_ICache_Autoload = 0x4fc00480; -Cache_Config_L1_CORE1_ICache_Autoload = 0x4fc00484; -Cache_Enable_L1_CORE1_ICache_Autoload = 0x4fc00488; -Cache_Disable_L1_CORE1_ICache_Autoload = 0x4fc0048c; -Cache_Config_L1_DCache_Autoload = 0x4fc00490; -Cache_Enable_L1_DCache_Autoload = 0x4fc00494; -Cache_Disable_L1_DCache_Autoload = 0x4fc00498; -Cache_Config_L2_Cache_Autoload = 0x4fc0049c; -Cache_Enable_L2_Cache_Autoload = 0x4fc004a0; -Cache_Disable_L2_Cache_Autoload = 0x4fc004a4; -Cache_Enable_L1_CORE0_ICache_PreLock = 0x4fc004a8; -Cache_Disable_L1_CORE0_ICache_PreLock = 0x4fc004ac; -Cache_Enable_L1_CORE1_ICache_PreLock = 0x4fc004b0; -Cache_Disable_L1_CORE1_ICache_PreLock = 0x4fc004b4; -Cache_Enable_L1_DCache_PreLock = 0x4fc004b8; -Cache_Disable_L1_DCache_PreLock = 0x4fc004bc; -Cache_Enable_L2_Cache_PreLock = 0x4fc004c0; -Cache_Disable_L2_Cache_PreLock = 0x4fc004c4; -Cache_Lock_Addr = 0x4fc004c8; -Cache_Unlock_Addr = 0x4fc004cc; -Cache_Disable_L1_CORE0_ICache = 0x4fc004d0; -Cache_Enable_L1_CORE0_ICache = 0x4fc004d4; -Cache_Suspend_L1_CORE0_ICache = 0x4fc004d8; -Cache_Resume_L1_CORE0_ICache = 0x4fc004dc; -Cache_Disable_L1_CORE1_ICache = 0x4fc004e0; -Cache_Enable_L1_CORE1_ICache = 0x4fc004e4; -Cache_Suspend_L1_CORE1_ICache = 0x4fc004e8; -Cache_Resume_L1_CORE1_ICache = 0x4fc004ec; -Cache_Disable_L1_DCache = 0x4fc004f0; -Cache_Enable_L1_DCache = 0x4fc004f4; -Cache_Suspend_L1_DCache = 0x4fc004f8; -Cache_Resume_L1_DCache = 0x4fc004fc; -Cache_Disable_L2_Cache = 0x4fc00500; -Cache_Enable_L2_Cache = 0x4fc00504; -Cache_Suspend_L2_Cache = 0x4fc00508; -Cache_Resume_L2_Cache = 0x4fc0050c; -Cache_FLASH_MMU_Init = 0x4fc00510; -Cache_PSRAM_MMU_Init = 0x4fc00514; -Cache_FLASH_MMU_Set = 0x4fc00518; -Cache_FLASH_MMU_Set_Secure = 0x4fc0051c; -Cache_PSRAM_MMU_Set = 0x4fc00520; -Cache_PSRAM_MMU_Set_Secure = 0x4fc00524; -Cache_Count_Flash_Pages = 0x4fc00528; -Cache_Flash_To_SPIRAM_Copy = 0x4fc0052c; -Cache_Travel_Tag_Memory = 0x4fc00530; -Cache_Travel_Tag_Memory2 = 0x4fc00534; -Cache_Get_Virtual_Addr = 0x4fc00538; -Cache_Set_IDROM_MMU_Size = 0x4fc0053c; -flash2spiram_instruction_offset = 0x4fc00540; -flash2spiram_rodata_offset = 0x4fc00544; -flash_instr_rodata_start_page = 0x4fc00548; -flash_instr_rodata_end_page = 0x4fc0054c; -Cache_Set_IDROM_MMU_Info = 0x4fc00550; -Cache_Get_IROM_MMU_End = 0x4fc00554; -Cache_Get_DROM_MMU_End = 0x4fc00558; -/* Data (.data, .bss, .rodata) */ -rom_cache_op_cb = 0x4ff3ffdc; -rom_cache_internal_table_ptr = 0x4ff3ffd8; - - -/*************************************** - Group clock - ***************************************/ - -/* Functions */ -ets_clk_get_xtal_freq = 0x4fc0055c; -ets_clk_get_cpu_freq = 0x4fc00560; - - -/*************************************** - Group gpio - ***************************************/ - -/* Functions */ -gpio_set_output_level = 0x4fc00564; -gpio_get_input_level = 0x4fc00568; -gpio_matrix_in = 0x4fc0056c; -gpio_matrix_out = 0x4fc00570; -gpio_bypass_matrix_in = 0x4fc00574; -gpio_output_disable = 0x4fc00578; -gpio_output_enable = 0x4fc0057c; -gpio_pad_input_disable = 0x4fc00580; -gpio_pad_input_enable = 0x4fc00584; -gpio_pad_pulldown = 0x4fc00588; -gpio_pad_pullup = 0x4fc0058c; -gpio_pad_select_gpio = 0x4fc00590; -gpio_pad_set_drv = 0x4fc00594; -gpio_pad_unhold = 0x4fc00598; -gpio_pad_hold = 0x4fc0059c; -gpio_lppad_select_mux = 0x4fc005a0; -gpio_ded_pad_set_drv = 0x4fc005a4; -gpio_ded_pad_pullup = 0x4fc005a8; -gpio_ded_pad_pulldown = 0x4fc005ac; -gpio_ded_pad_hold = 0x4fc005b0; -gpio_ded_pad_unhold = 0x4fc005b4; - - -/*************************************** - Group interrupts - ***************************************/ - -/* Functions */ -esprv_intc_int_set_priority = 0x4fc005b8; -esprv_intc_int_set_threshold = 0x4fc005bc; -esprv_intc_int_enable = 0x4fc005c0; -esprv_intc_int_disable = 0x4fc005c4; -esprv_intc_int_set_type = 0x4fc005c8; -PROVIDE( intr_handler_set = 0x4fc005cc ); -intr_matrix_set = 0x4fc005d0; -ets_intr_lock = 0x4fc005d4; -ets_intr_unlock = 0x4fc005d8; -ets_isr_attach = 0x4fc005dc; -ets_isr_mask = 0x4fc005e0; -ets_isr_unmask = 0x4fc005e4; - - -/*************************************** - Group crypto - ***************************************/ - -/* Functions */ -md5_vector = 0x4fc005e8; -MD5Init = 0x4fc005ec; -MD5Update = 0x4fc005f0; -MD5Final = 0x4fc005f4; -crc32_le = 0x4fc005f8; -crc16_le = 0x4fc005fc; -crc8_le = 0x4fc00600; -crc32_be = 0x4fc00604; -crc16_be = 0x4fc00608; -crc8_be = 0x4fc0060c; -esp_crc8 = 0x4fc00610; -ets_sha_enable = 0x4fc00614; -ets_sha_disable = 0x4fc00618; -ets_sha_get_state = 0x4fc0061c; -ets_sha_init = 0x4fc00620; -ets_sha_process = 0x4fc00624; -ets_sha_starts = 0x4fc00628; -ets_sha_update = 0x4fc0062c; -ets_sha_finish = 0x4fc00630; -ets_sha_clone = 0x4fc00634; -ets_hmac_enable = 0x4fc00638; -ets_hmac_disable = 0x4fc0063c; -ets_hmac_calculate_message = 0x4fc00640; -ets_hmac_calculate_downstream = 0x4fc00644; -ets_hmac_invalidate_downstream = 0x4fc00648; -ets_jtag_enable_temporarily = 0x4fc0064c; -ets_aes_enable = 0x4fc00650; -ets_aes_disable = 0x4fc00654; -ets_aes_setkey = 0x4fc00658; -ets_aes_block = 0x4fc0065c; -ets_aes_setkey_dec = 0x4fc00660; -ets_aes_setkey_enc = 0x4fc00664; -ets_bigint_enable = 0x4fc00668; -ets_bigint_disable = 0x4fc0066c; -ets_bigint_multiply = 0x4fc00670; -ets_bigint_modmult = 0x4fc00674; -ets_bigint_modexp = 0x4fc00678; -ets_bigint_wait_finish = 0x4fc0067c; -ets_bigint_getz = 0x4fc00680; -ets_ds_enable = 0x4fc00684; -ets_ds_disable = 0x4fc00688; -ets_ds_start_sign = 0x4fc0068c; -ets_ds_is_busy = 0x4fc00690; -ets_ds_finish_sign = 0x4fc00694; -ets_ds_encrypt_params = 0x4fc00698; -ets_mgf1_sha256 = 0x4fc0069c; -/* Data (.data, .bss, .rodata) */ -crc32_le_table_ptr = 0x4fc1fff8; -crc16_le_table_ptr = 0x4fc1fff4; -crc8_le_table_ptr = 0x4fc1fff0; -crc32_be_table_ptr = 0x4fc1ffec; -crc16_be_table_ptr = 0x4fc1ffe8; -crc8_be_table_ptr = 0x4fc1ffe4; - - -/*************************************** - Group efuse - ***************************************/ - -/* Functions */ -ets_efuse_read = 0x4fc006a0; -ets_efuse_program = 0x4fc006a4; -ets_efuse_clear_program_registers = 0x4fc006a8; -ets_efuse_write_key = 0x4fc006ac; -ets_efuse_get_read_register_address = 0x4fc006b0; -ets_efuse_get_key_purpose = 0x4fc006b4; -ets_efuse_key_block_unused = 0x4fc006b8; -ets_efuse_find_unused_key_block = 0x4fc006bc; -ets_efuse_rs_calculate = 0x4fc006c0; -ets_efuse_count_unused_key_blocks = 0x4fc006c4; -ets_efuse_secure_boot_enabled = 0x4fc006c8; -ets_efuse_secure_boot_aggressive_revoke_enabled = 0x4fc006cc; -ets_efuse_cache_encryption_enabled = 0x4fc006d0; -ets_efuse_download_modes_disabled = 0x4fc006d4; -ets_efuse_find_purpose = 0x4fc006d8; -ets_efuse_force_send_resume = 0x4fc006dc; -ets_efuse_get_flash_delay_us = 0x4fc006e0; -ets_efuse_get_uart_print_control = 0x4fc006e4; -ets_efuse_direct_boot_mode_disabled = 0x4fc006e8; -ets_efuse_security_download_modes_enabled = 0x4fc006ec; -ets_efuse_jtag_disabled = 0x4fc006f0; -ets_efuse_usb_print_is_disabled = 0x4fc006f4; -ets_efuse_usb_download_mode_disabled = 0x4fc006f8; -ets_efuse_usb_device_disabled = 0x4fc006fc; -ets_efuse_get_km_huk_gen_state = 0x4fc00700; -ets_efuse_get_km_deploy_only_once = 0x4fc00704; -ets_efuse_get_force_use_km_key = 0x4fc00708; -ets_efuse_xts_key_length_256 = 0x4fc0070c; -ets_efuse_get_km_key_lock = 0x4fc00710; - - -/*************************************** - Group key_mgr - ***************************************/ - -/* Functions */ -esp_rom_check_recover_key = 0x4fc00714; -esp_rom_km_huk_conf = 0x4fc00718; -esp_rom_km_huk_risk = 0x4fc0071c; - - -/*************************************** - Group secureboot - ***************************************/ - -/* Functions */ -ets_emsa_pss_verify = 0x4fc00720; -ets_rsa_pss_verify = 0x4fc00724; -ets_ecdsa_verify = 0x4fc00728; -ets_secure_boot_verify_bootloader_with_keys = 0x4fc0072c; -ets_secure_boot_verify_signature = 0x4fc00730; -ets_secure_boot_read_key_digests = 0x4fc00734; -ets_secure_boot_revoke_public_key_digest = 0x4fc00738; - - -/*************************************** - Group usb_device_uart - ***************************************/ - -/* Functions */ -usb_serial_device_rx_one_char = 0x4fc008b0; -usb_serial_device_rx_one_char_block = 0x4fc008b4; -usb_serial_device_tx_flush = 0x4fc008b8; -usb_serial_device_tx_one_char = 0x4fc008bc; - - -/*************************************** - Group usb_dwcotg_uart - ***************************************/ - -/* Functions */ -Uart_Init_USB = 0x4fc008c0; -usb_serial_otg_rx_one_char = 0x4fc008c4; -usb_serial_otg_rx_one_char_block = 0x4fc008c8; -usb_serial_otg_tx_flush = 0x4fc008cc; -usb_serial_otg_tx_one_char = 0x4fc008d0; -/* Data (.data, .bss, .rodata) */ -uart_acm_dev = 0x4ff3ffd4; - - -/*************************************** - Group usb_dwcotg_module - ***************************************/ - -/* Functions */ -cdc_acm_class_handle_req = 0x4fc008d4; -cdc_acm_init = 0x4fc008d8; -cdc_acm_fifo_fill = 0x4fc008dc; -cdc_acm_rx_fifo_cnt = 0x4fc008e0; -cdc_acm_fifo_read = 0x4fc008e4; -cdc_acm_irq_tx_enable = 0x4fc008e8; -cdc_acm_irq_tx_disable = 0x4fc008ec; -cdc_acm_irq_state_enable = 0x4fc008f0; -cdc_acm_irq_state_disable = 0x4fc008f4; -cdc_acm_irq_tx_ready = 0x4fc008f8; -cdc_acm_irq_rx_enable = 0x4fc008fc; -cdc_acm_irq_rx_disable = 0x4fc00900; -cdc_acm_irq_rx_ready = 0x4fc00904; -cdc_acm_irq_is_pending = 0x4fc00908; -cdc_acm_irq_callback_set = 0x4fc0090c; -cdc_acm_line_ctrl_set = 0x4fc00910; -cdc_acm_line_ctrl_get = 0x4fc00914; -cdc_acm_poll_out = 0x4fc00918; -chip_usb_dw_did_persist = 0x4fc0091c; -chip_usb_dw_init = 0x4fc00920; -chip_usb_detach = 0x4fc00924; -chip_usb_dw_prepare_persist = 0x4fc00928; -chip_usb_get_persist_flags = 0x4fc0092c; -chip_usb_set_persist_flags = 0x4fc00930; -cpio_start = 0x4fc00934; -cpio_feed = 0x4fc00938; -cpio_done = 0x4fc0093c; -cpio_destroy = 0x4fc00940; -dfu_flash_init = 0x4fc00944; -dfu_flash_erase = 0x4fc00948; -dfu_flash_program = 0x4fc0094c; -dfu_flash_read = 0x4fc00950; -dfu_flash_attach = 0x4fc00954; -dfu_cpio_callback = 0x4fc00958; -dfu_updater_get_err = 0x4fc0095c; -dfu_updater_clear_err = 0x4fc00960; -dfu_updater_enable = 0x4fc00964; -dfu_updater_begin = 0x4fc00968; -dfu_updater_feed = 0x4fc0096c; -dfu_updater_end = 0x4fc00970; -dfu_updater_set_raw_addr = 0x4fc00974; -dfu_updater_flash_read = 0x4fc00978; -usb_dc_prepare_persist = 0x4fc0097c; -usb_dw_isr_handler = 0x4fc00980; -usb_dc_attach = 0x4fc00984; -usb_dc_detach = 0x4fc00988; -usb_dc_reset = 0x4fc0098c; -usb_dc_set_address = 0x4fc00990; -usb_dc_ep_check_cap = 0x4fc00994; -usb_dc_ep_configure = 0x4fc00998; -usb_dc_ep_set_stall = 0x4fc0099c; -usb_dc_ep_clear_stall = 0x4fc009a0; -usb_dc_ep_halt = 0x4fc009a4; -usb_dc_ep_is_stalled = 0x4fc009a8; -usb_dc_ep_enable = 0x4fc009ac; -usb_dc_ep_disable = 0x4fc009b0; -usb_dc_ep_flush = 0x4fc009b4; -usb_dc_ep_write_would_block = 0x4fc009b8; -usb_dc_ep_write = 0x4fc009bc; -usb_dc_ep_read_wait = 0x4fc009c0; -usb_dc_ep_read_continue = 0x4fc009c4; -usb_dc_ep_read = 0x4fc009c8; -usb_dc_ep_set_callback = 0x4fc009cc; -usb_dc_set_status_callback = 0x4fc009d0; -usb_dc_ep_mps = 0x4fc009d4; -usb_dc_check_poll_for_interrupts = 0x4fc009d8; -mac_addr_to_serial_str_desc = 0x4fc009dc; -usb_set_current_descriptor = 0x4fc009e0; -usb_get_descriptor = 0x4fc009e4; -usb_dev_resume = 0x4fc009e8; -usb_dev_get_configuration = 0x4fc009ec; -usb_set_config = 0x4fc009f0; -usb_deconfig = 0x4fc009f4; -usb_enable = 0x4fc009f8; -usb_disable = 0x4fc009fc; -usb_write_would_block = 0x4fc00a00; -usb_write = 0x4fc00a04; -usb_read = 0x4fc00a08; -usb_ep_set_stall = 0x4fc00a0c; -usb_ep_clear_stall = 0x4fc00a10; -usb_ep_read_wait = 0x4fc00a14; -usb_ep_read_continue = 0x4fc00a18; -usb_transfer_ep_callback = 0x4fc00a1c; -usb_transfer = 0x4fc00a20; -usb_cancel_transfer = 0x4fc00a24; -usb_transfer_sync = 0x4fc00a28; -usb_dfu_set_detach_cb = 0x4fc00a2c; -dfu_class_handle_req = 0x4fc00a30; -dfu_status_cb = 0x4fc00a34; -dfu_custom_handle_req = 0x4fc00a38; -usb_dfu_init = 0x4fc00a3c; -usb_dfu_force_detach = 0x4fc00a40; -usb_dev_deinit = 0x4fc00a44; -usb_dw_ctrl_deinit = 0x4fc00a48; -/* Data (.data, .bss, .rodata) */ -s_usb_osglue = 0x4ff3ffc8; diff --git a/tools/esptool_py/flasher_stub/ld/rom_32s2.ld b/tools/esptool_py/flasher_stub/ld/rom_32s2.ld deleted file mode 100755 index 399aa0f671..0000000000 --- a/tools/esptool_py/flasher_stub/ld/rom_32s2.ld +++ /dev/null @@ -1,1064 +0,0 @@ -/* -ESP32S2 ROM address table -Generated for ROM with MD5sum: -0a2c7ec5109c17884606d23b47045796 /home/jack/esp-rom/rom//.output/eagle/release/image/eagle.pro.rom.out -*/ -PROVIDE ( abort = 0x40019fb4 ); -PROVIDE ( abs = 0x40000618 ); -PROVIDE ( __absvdi2 = 0x40005ad8 ); -PROVIDE ( __absvsi2 = 0x40005ac4 ); -PROVIDE ( acm_config_descr = 0x3ffaef0f ); -PROVIDE ( acm_usb_descriptors = 0x3ffaee68 ); -PROVIDE ( __adddf3 = 0x40008660 ); -PROVIDE ( __addsf3 = 0x400081b8 ); -PROVIDE ( __addvdi3 = 0x40008d90 ); -PROVIDE ( __addvsi3 = 0x40008d6c ); -PROVIDE ( __ascii_mbtowc = 0x40007a04 ); -PROVIDE ( __ascii_wctomb = 0x400018d0 ); -PROVIDE ( __ashldi3 = 0x4001b000 ); -PROVIDE ( __ashrdi3 = 0x4001b018 ); -PROVIDE ( __assert = 0x4001a430 ); -PROVIDE ( __assert_func = 0x4001a408 ); -PROVIDE ( boot_prepare = 0x4000f348 ); -PROVIDE ( __bswapdi2 = 0x40006d34 ); -PROVIDE ( __bswapsi2 = 0x40006d0c ); -PROVIDE ( bzero = 0x400078c8 ); -PROVIDE ( Cache_Address_Through_DCache = 0x400180f0 ); -PROVIDE ( Cache_Address_Through_ICache = 0x400180bc ); -PROVIDE ( Cache_Allocate_SRAM = 0x40018d6c ); -PROVIDE ( Cache_Clean_Addr = 0x40018370 ); -PROVIDE ( Cache_Clean_All = 0x40018438 ); -PROVIDE ( Cache_Clean_Items = 0x40018250 ); -PROVIDE ( Cache_Config_DCache_Autoload = 0x40018794 ); -PROVIDE ( Cache_Config_ICache_Autoload = 0x40018664 ); -PROVIDE ( Cache_Count_Flash_Pages = 0x40018f70 ); -PROVIDE ( Cache_Dbus_MMU_Set = 0x40018eb0 ); -PROVIDE ( Cache_DCache_Preload_Done = 0x40018630 ); -PROVIDE ( Cache_Disable_DCache = 0x40018c68 ); -PROVIDE ( Cache_Disable_DCache_Autoload = 0x4001888c ); -PROVIDE ( Cache_Disable_DCache_PreLock = 0x40018a5c ); -PROVIDE ( Cache_Disable_ICache = 0x40018c2c ); -PROVIDE ( Cache_Disable_ICache_Autoload = 0x4001875c ); -PROVIDE ( Cache_Disable_ICache_PreLock = 0x4001892c ); -PROVIDE ( Cache_Enable_DCache = 0x40018d58 ); -PROVIDE ( Cache_Enable_DCache_Autoload = 0x40018874 ); -PROVIDE ( Cache_Enable_DCache_PreLock = 0x400189f0 ); -PROVIDE ( Cache_Enable_Defalut_DCache_Mode = 0x40018170 ); -PROVIDE ( Cache_Enable_ICache = 0x40018cf8 ); -PROVIDE ( Cache_Enable_ICache_Autoload = 0x40018744 ); -PROVIDE ( Cache_Enable_ICache_PreLock = 0x400188c0 ); -PROVIDE ( Cache_End_DCache_Preload = 0x40018644 ); -PROVIDE ( Cache_End_ICache_Preload = 0x400185b0 ); -PROVIDE ( Cache_Flash_To_SPIRAM_Copy = 0x40018fc4 ); -PROVIDE ( Cache_Get_DCache_Line_Size = 0x40017fd8 ); -PROVIDE ( Cache_Get_ICache_Line_Size = 0x40017fbc ); -PROVIDE ( Cache_Get_Memory_Addr = 0x4001929c ); -PROVIDE ( Cache_Get_Memory_BaseAddr = 0x40019244 ); -PROVIDE ( Cache_Get_Memory_value = 0x400192d8 ); -PROVIDE ( Cache_Get_Mode = 0x40017ff0 ); -PROVIDE ( Cache_Get_Virtual_Addr = 0x40019210 ); -PROVIDE ( Cache_Ibus_MMU_Set = 0x40018df4 ); -PROVIDE ( Cache_ICache_Preload_Done = 0x4001859c ); -PROVIDE ( Cache_Invalidate_Addr = 0x400182e4 ); -PROVIDE ( Cache_Invalidate_DCache_All = 0x4001842c ); -PROVIDE ( Cache_Invalidate_DCache_Items = 0x40018208 ); -PROVIDE ( Cache_Invalidate_ICache_All = 0x40018420 ); -PROVIDE ( Cache_Invalidate_ICache_Items = 0x400181b8 ); -PROVIDE ( Cache_Lock_Addr = 0x40018b10 ); -PROVIDE ( Cache_Lock_DCache_Items = 0x40018a80 ); -PROVIDE ( Cache_Lock_ICache_Items = 0x40018950 ); -PROVIDE ( Cache_Mask_All = 0x40018458 ); -PROVIDE ( cache_memory_baseaddrs = 0x3ffaf020 ); -PROVIDE ( Cache_MMU_Init = 0x40018dd8 ); -PROVIDE ( Cache_Resume_DCache = 0x40018d3c ); -PROVIDE ( Cache_Resume_DCache_Autoload = 0x4001850c ); -PROVIDE ( Cache_Resume_ICache = 0x40018cdc ); -PROVIDE ( Cache_Resume_ICache_Autoload = 0x400184c4 ); -PROVIDE ( Cache_Set_DCache_Mode = 0x40018074 ); -PROVIDE ( Cache_Set_Default_Mode = 0x4001810c ); -PROVIDE ( Cache_Set_ICache_Mode = 0x4001803c ); -PROVIDE ( Cache_Start_DCache_Preload = 0x400185c4 ); -PROVIDE ( Cache_Start_ICache_Preload = 0x40018530 ); -PROVIDE ( Cache_Suspend_DCache = 0x40018d04 ); -PROVIDE ( Cache_Suspend_DCache_Autoload = 0x400184e0 ); -PROVIDE ( Cache_Suspend_ICache = 0x40018ca4 ); -PROVIDE ( Cache_Suspend_ICache_Autoload = 0x40018498 ); -PROVIDE ( Cache_Travel_Tag_Memory = 0x4001908c ); -PROVIDE ( Cache_Unlock_Addr = 0x40018b9c ); -PROVIDE ( Cache_Unlock_DCache_Items = 0x40018ac8 ); -PROVIDE ( Cache_Unlock_ICache_Items = 0x40018998 ); -PROVIDE ( Cache_UnMask_Drom0 = 0x40018480 ); -PROVIDE ( Cache_WriteBack_Addr = 0x400183c8 ); -PROVIDE ( Cache_WriteBack_All = 0x40018444 ); -PROVIDE ( Cache_WriteBack_Items = 0x40018298 ); -PROVIDE ( cacl_rtc_memory_crc = 0x4000ffa0 ); -PROVIDE ( calloc = 0x4001a2f4 ); -PROVIDE ( _calloc_r = 0x4001a008 ); -PROVIDE ( cdc_acm_class_handle_req = 0x40013050 ); -PROVIDE ( cdc_acm_config = 0x3ffffa10 ); -PROVIDE ( cdc_acm_dev = 0x3ffffce8 ); -PROVIDE ( cdc_acm_fifo_fill = 0x4001318c ); -PROVIDE ( cdc_acm_fifo_read = 0x40013200 ); -PROVIDE ( cdc_acm_init = 0x40013144 ); -PROVIDE ( cdc_acm_irq_callback_set = 0x400132d4 ); -PROVIDE ( cdc_acm_irq_is_pending = 0x400132b0 ); -PROVIDE ( cdc_acm_irq_rx_disable = 0x40013290 ); -PROVIDE ( cdc_acm_irq_rx_enable = 0x40013284 ); -PROVIDE ( cdc_acm_irq_rx_ready = 0x4001329c ); -PROVIDE ( cdc_acm_irq_state_disable = 0x40013264 ); -PROVIDE ( cdc_acm_irq_state_enable = 0x40013258 ); -PROVIDE ( cdc_acm_irq_tx_disable = 0x4001324c ); -PROVIDE ( cdc_acm_irq_tx_enable = 0x40013240 ); -PROVIDE ( cdc_acm_irq_tx_ready = 0x40013270 ); -PROVIDE ( cdc_acm_line_ctrl_get = 0x40013330 ); -PROVIDE ( cdc_acm_line_ctrl_set = 0x400132dc ); -PROVIDE ( cdc_acm_poll_out = 0x40013360 ); -PROVIDE ( cdc_acm_rx_fifo_cnt = 0x400131ec ); -PROVIDE ( chip723_phyrom_version = 0x4000a8a8 ); -PROVIDE ( chip_usb_detach = 0x40013508 ); -PROVIDE ( chip_usb_dw_did_persist = 0x4001337c ); -PROVIDE ( chip_usb_dw_init = 0x400133bc ); -PROVIDE ( chip_usb_dw_prepare_persist = 0x40013588 ); -PROVIDE ( chip_usb_get_persist_flags = 0x400135d8 ); -PROVIDE ( chip_usb_set_persist_flags = 0x400135e8 ); -PROVIDE ( _cleanup = 0x4001a4f8 ); -PROVIDE ( _cleanup_r = 0x4001a480 ); -PROVIDE ( __clear_cache = 0x40005abc ); -PROVIDE ( close = 0x400080b0 ); -PROVIDE ( _close_r = 0x4001a14c ); -PROVIDE ( __clrsbdi2 = 0x40006da8 ); -PROVIDE ( __clrsbsi2 = 0x40006d90 ); -PROVIDE ( __clzdi2 = 0x4001b238 ); -PROVIDE ( __clzsi2 = 0x4001afd0 ); -PROVIDE ( __cmpdi2 = 0x40005a7c ); -PROVIDE ( context = 0x3fffeb34 ); -PROVIDE ( cpio_destroy = 0x4001599c ); -PROVIDE ( cpio_done = 0x40015968 ); -PROVIDE ( cpio_feed = 0x40015668 ); -PROVIDE ( cpio_start = 0x4001561c ); -PROVIDE ( crc16_le = 0x40011a10 ); -PROVIDE ( crc32_le = 0x400119dc ); -PROVIDE ( crc8_le = 0x40011a4c ); -PROVIDE ( creat = 0x4000788c ); -PROVIDE ( _ctype_ = 0x3ffac76c ); -PROVIDE ( __ctzdi2 = 0x4001b24c ); -PROVIDE ( __ctzsi2 = 0x4001afd8 ); -PROVIDE ( _cvt = 0x4000f9b8 ); -PROVIDE ( _data_end_all_pro = 0x3fffff98 ); -PROVIDE ( _data_end_c = 0x3ffffd80 ); -PROVIDE ( _data_end_ets = 0x3fffe710 ); -PROVIDE ( _data_end_ets_delay = 0x3ffffd74 ); -PROVIDE ( _data_end_ets_printf = 0x3ffffd5c ); -PROVIDE ( _data_end_newlib = 0x3ffffd74 ); -PROVIDE ( _data_end_phyrom = 0x3fffff98 ); -PROVIDE ( _data_end_sip = 0x3fffeb70 ); -PROVIDE ( _data_end_slc = 0x3fffeb70 ); -PROVIDE ( _data_end_spi_flash = 0x3ffffd54 ); -PROVIDE ( _data_end_spi_slave = 0x3fffeb30 ); -PROVIDE ( _data_end_uart = 0x3ffffcf4 ); -PROVIDE ( _data_end_usbdev = 0x3ffffa6c ); -PROVIDE ( _data_end_xtos = 0x3fffef88 ); -PROVIDE ( _data_start_all_pro = 0x3fffff98 ); -PROVIDE ( _data_start_c = 0x3ffffd7c ); -PROVIDE ( _data_start_ets = 0x3fffe710 ); -PROVIDE ( _data_start_ets_delay = 0x3ffffd70 ); -PROVIDE ( _data_start_ets_printf = 0x3ffffd5c ); -PROVIDE ( _data_start_newlib = 0x3ffffd74 ); -PROVIDE ( _data_start_phyrom = 0x3ffffd90 ); -PROVIDE ( _data_start_sip = 0x3fffeb70 ); -PROVIDE ( _data_start_slc = 0x3fffeb70 ); -PROVIDE ( _data_start_spi_flash = 0x3ffffd38 ); -PROVIDE ( _data_start_spi_slave = 0x3fffeb30 ); -PROVIDE ( _data_start_uart = 0x3ffffcf4 ); -PROVIDE ( _data_start_usbdev = 0x3ffffa10 ); -PROVIDE ( _data_start_xtos = 0x3fffeb70 ); -PROVIDE ( dbus_baseaddrs = 0x3ffaf030 ); -PROVIDE ( _DebugExceptionVector = 0x40000280 ); -PROVIDE ( _DebugExceptionVector_text_end = 0x4000028b ); -PROVIDE ( _DebugExceptionVector_text_start = 0x40000280 ); -PROVIDE ( __default_global_locale = 0x3ffac600 ); -PROVIDE ( dfu_class_handle_req = 0x400152f0 ); -PROVIDE ( dfu_config_descr = 0x3ffaeeb2 ); -PROVIDE ( dfu_cpio_callback = 0x4001360c ); -PROVIDE ( dfu_custom_handle_req = 0x40015568 ); -PROVIDE ( dfu_flash_attach = 0x40015a34 ); -PROVIDE ( dfu_flash_deinit = 0x400159b4 ); -PROVIDE ( dfu_flash_erase = 0x400159bc ); -PROVIDE ( dfu_flash_init = 0x400159a4 ); -PROVIDE ( dfu_flash_program = 0x400159d0 ); -PROVIDE ( dfu_flash_read = 0x40015a24 ); -PROVIDE ( dfu_status_cb = 0x40015514 ); -PROVIDE ( dfu_updater_begin = 0x40013858 ); -PROVIDE ( dfu_updater_clear_err = 0x40013810 ); -PROVIDE ( dfu_updater_enable = 0x40013828 ); -PROVIDE ( dfu_updater_end = 0x40013900 ); -PROVIDE ( dfu_updater_feed = 0x400138b4 ); -PROVIDE ( dfu_updater_flash_read = 0x400139e8 ); -PROVIDE ( dfu_updater_get_err = 0x400137fc ); -PROVIDE ( dfu_updater_set_raw_addr = 0x400139d4 ); -PROVIDE ( dfu_usb_descriptors = 0x3ffaee4c ); -PROVIDE ( dh_group14_generator = 0x3ffadfec ); -PROVIDE ( dh_group14_prime = 0x3ffadeec ); -PROVIDE ( dh_group15_generator = 0x3ffadeeb ); -PROVIDE ( dh_group15_prime = 0x3ffadd6b ); -PROVIDE ( dh_group16_generator = 0x3ffadd6a ); -PROVIDE ( dh_group16_prime = 0x3ffadb6a ); -PROVIDE ( dh_group17_generator = 0x3ffadb69 ); -PROVIDE ( dh_group17_prime = 0x3ffad869 ); -PROVIDE ( dh_group18_generator = 0x3ffad868 ); -PROVIDE ( dh_group18_prime = 0x3ffad468 ); -PROVIDE ( dh_group1_generator = 0x3ffae18f ); -PROVIDE ( dh_group1_prime = 0x3ffae12f ); -PROVIDE ( dh_group2_generator = 0x3ffae12e ); -PROVIDE ( dh_group2_prime = 0x3ffae0ae ); -PROVIDE ( dh_group5_generator = 0x3ffae0ad ); -PROVIDE ( dh_group5_prime = 0x3ffadfed ); -PROVIDE ( disable_default_watchdog = 0x4000f270 ); -PROVIDE ( Disable_QMode = 0x400166e0 ); -PROVIDE ( div = 0x40000620 ); -PROVIDE ( __divdc3 = 0x40006854 ); -PROVIDE ( __divdf3 = 0x40008a24 ); -PROVIDE ( __divdi3 = 0x4001b26c ); -PROVIDE ( __divsc3 = 0x40006544 ); -PROVIDE ( __divsf3 = 0x4000841c ); -PROVIDE ( __divsi3 = 0x4001afa0 ); -PROVIDE ( dmadesc_rx = 0x3fffeb4c ); -PROVIDE ( dmadesc_tx = 0x3fffeb40 ); -PROVIDE ( _DoubleExceptionVector = 0x400003c0 ); -PROVIDE ( _DoubleExceptionVector_text_end = 0x400003c6 ); -PROVIDE ( _DoubleExceptionVector_text_start = 0x400003c0 ); -PROVIDE ( _dram0_0_start = 0x3ffeab00 ); -PROVIDE ( _dram0_rtos_reserved_start = 0x3ffffa10 ); -PROVIDE ( dummy_len_plus = 0x3ffffd54 ); -PROVIDE ( Enable_QMode = 0x40016690 ); -PROVIDE ( __eqdf2 = 0x40005904 ); -PROVIDE ( __eqsf2 = 0x400055d0 ); -PROVIDE ( esp_crc8 = 0x40011a78 ); -PROVIDE ( esp_rom_config_pad_power_select = 0x40016e58 ); -PROVIDE ( esp_rom_opiflash_cache_mode_config = 0x40016754 ); -PROVIDE ( esp_rom_opiflash_exec_cmd = 0x40017e30 ); -PROVIDE ( esp_rom_opiflash_exit_continuous_read_mode = 0x40017ee8 ); -PROVIDE ( esp_rom_opiflash_mode_reset = 0x40017f90 ); -PROVIDE ( esp_rom_opiflash_pin_config = 0x400177f8 ); -PROVIDE ( esp_rom_opiflash_soft_reset = 0x40017f24 ); -PROVIDE ( esp_rom_spi_cmd_config = 0x40017c58 ); -PROVIDE ( esp_rom_spi_cmd_start = 0x40017ba8 ); -PROVIDE ( esp_rom_spi_flash_auto_sus_res = 0x400175e0 ); -PROVIDE ( esp_rom_spi_flash_auto_wait_idle = 0x4001751c ); -PROVIDE ( esp_rom_spi_flash_send_resume = 0x40017570 ); -PROVIDE ( esp_rom_spi_flash_update_id = 0x40016e44 ); -PROVIDE ( esp_rom_spi_reset_rw_mode = 0x40017984 ); -PROVIDE ( esp_rom_spi_set_dtr_swap_mode = 0x40017b60 ); -PROVIDE ( esp_rom_spi_set_op_mode = 0x400179e8 ); -PROVIDE ( _etext = 0x4001bed0 ); -PROVIDE ( ets_aes_block = 0x4000d610 ); -PROVIDE ( ets_aes_disable = 0x4000d4f8 ); -PROVIDE ( ets_aes_enable = 0x4000d4cc ); -PROVIDE ( ets_aes_set_endian = 0x4000d528 ); -PROVIDE ( ets_aes_setkey = 0x4000d594 ); -PROVIDE ( ets_aes_setkey_dec = 0x4000d5f0 ); -PROVIDE ( ets_aes_setkey_enc = 0x4000d5e0 ); -PROVIDE ( ets_bigint_disable = 0x4000d750 ); -PROVIDE ( ets_bigint_enable = 0x4000d708 ); -PROVIDE ( ets_bigint_getz = 0x4000d858 ); -PROVIDE ( ets_bigint_modexp = 0x4000d818 ); -PROVIDE ( ets_bigint_modmult = 0x4000d7f4 ); -PROVIDE ( ets_bigint_multiply = 0x4000d790 ); -PROVIDE ( ets_bigint_wait_finish = 0x4000d840 ); -PROVIDE ( ets_config_flash_by_image_hdr = 0x40010e40 ); -PROVIDE ( ets_delay_us = 0x4000d888 ); -PROVIDE ( ets_ds_disable = 0x4000d910 ); -PROVIDE ( ets_ds_enable = 0x4000d8e4 ); -PROVIDE ( ets_ds_encrypt_params = 0x4000da90 ); -PROVIDE ( ets_ds_finish_sign = 0x4000d9f8 ); -PROVIDE ( ets_ds_is_busy = 0x4000d93c ); -PROVIDE ( ets_ds_start_sign = 0x4000d96c ); -PROVIDE ( ets_efuse_cache_encryption_enabled = 0x4000e690 ); -PROVIDE ( ets_efuse_clear_program_registers = 0x4000e100 ); -PROVIDE ( ets_efuse_count_unused_key_blocks = 0x4000e2c4 ); -PROVIDE ( ets_efuse_download_modes_disabled = 0x4000e594 ); -PROVIDE ( ets_efuse_find_purpose = 0x4000e224 ); -PROVIDE ( ets_efuse_find_unused_key_block = 0x4000e2ac ); -PROVIDE ( ets_efuse_flash_opi_5pads_power_sel_vddspi = 0x4000e640 ); -PROVIDE ( ets_efuse_flash_opi_mode = 0x4000e650 ); -PROVIDE ( ets_efuse_force_send_resume = 0x4000e660 ); -PROVIDE ( ets_efuse_get_flash_delay_us = 0x4000e6d4 ); -PROVIDE ( ets_efuse_get_key_purpose = 0x4000e1b0 ); -PROVIDE ( ets_efuse_get_opiconfig = 0x4000e4fc ); -PROVIDE ( ets_efuse_get_read_register_address = 0x4000e18c ); -PROVIDE ( ets_efuse_get_spiconfig = 0x4000e4a0 ); -PROVIDE ( ets_efuse_get_uart_print_channel = 0x4000e5b4 ); -PROVIDE ( ets_efuse_get_uart_print_control = 0x4000e5a4 ); -PROVIDE ( ets_efuse_get_wp_pad = 0x4000e444 ); -PROVIDE ( ets_efuse_key_block_unused = 0x4000e250 ); -PROVIDE ( ets_efuse_legacy_spi_boot_mode_disabled = 0x4000e6b0 ); -PROVIDE ( ets_efuse_program = 0x4000e134 ); -PROVIDE ( ets_efuse_read = 0x4000e0c0 ); -PROVIDE ( ets_efuse_rs_calculate = 0x4000e6f8 ); -PROVIDE ( ets_efuse_secure_boot_aggressive_revoke_enabled = 0x4000e680 ); -PROVIDE ( ets_efuse_secure_boot_enabled = 0x4000e670 ); -PROVIDE ( ets_efuse_security_download_modes_enabled = 0x4000e5d4 ); -PROVIDE ( ets_efuse_set_timing = 0x4000df3c ); -PROVIDE ( ets_efuse_start = 0x4000e084 ); -PROVIDE ( ets_efuse_usb_download_mode_disabled = 0x4000e5f4 ); -PROVIDE ( ets_efuse_usb_force_nopersist = 0x4000e630 ); -PROVIDE ( ets_efuse_usb_module_disabled = 0x4000e5c4 ); -PROVIDE ( ets_efuse_usb_use_ext_phy = 0x4000e620 ); -PROVIDE ( ets_efuse_write_key = 0x4000e2f4 ); -PROVIDE ( ets_emsa_pss_verify = 0x40011818 ); -PROVIDE ( ets_get_apb_freq = 0x40010c58 ); -PROVIDE ( ets_get_cpu_frequency = 0x4000d8b0 ); -PROVIDE ( ets_get_printf_channel = 0x4000ff48 ); -PROVIDE ( ets_get_xtal_div = 0x40010bfc ); -PROVIDE ( ets_get_xtal_freq = 0x40010c38 ); -PROVIDE ( ets_hmac_calculate_downstream = 0x4000f120 ); -PROVIDE ( ets_hmac_calculate_message = 0x4000f020 ); -PROVIDE ( ets_hmac_disable = 0x4000eff4 ); -PROVIDE ( ets_hmac_enable = 0x4000efd8 ); -PROVIDE ( ets_hmac_invalidate_downstream = 0x4000f140 ); -PROVIDE ( ets_install_lock = 0x4000fea0 ); -PROVIDE ( ets_install_putc1 = 0x4000feb0 ); -PROVIDE ( ets_install_putc2 = 0x4000fed0 ); -PROVIDE ( ets_install_uart_printf = 0x4000fec0 ); -PROVIDE ( ets_intr_count = 0x3fffe710 ); -PROVIDE ( ets_intr_lock = 0x4000f168 ); -PROVIDE ( ets_intr_unlock = 0x4000f17c ); -PROVIDE ( ets_is_print_boot = 0x4000f2a0 ); -PROVIDE ( ets_isr_attach = 0x4000f1a4 ); -PROVIDE ( ets_isr_mask = 0x4000f1b4 ); -PROVIDE ( ets_isr_unmask = 0x4000f1c0 ); -PROVIDE ( ets_jtag_enable_temporarily = 0x4000e548 ); -PROVIDE ( ets_loader_map_range = 0x40010d4c ); -PROVIDE ( ets_mgf1_sha256 = 0x400117b0 ); -PROVIDE ( ets_printf = 0x4000fee0 ); -PROVIDE ( ets_printf_lock = 0x3ffffd64 ); -PROVIDE ( ets_printf_uart = 0x3ffffd5c ); -PROVIDE ( ets_printf_unlock = 0x3ffffd60 ); -PROVIDE ( ets_rsa_pss_verify = 0x4001191c ); -PROVIDE ( ets_run_flash_bootloader = 0x40010f58 ); -PROVIDE ( ets_secure_boot_read_key_digests = 0x400101ac ); -PROVIDE ( ets_secure_boot_revoke_public_key_digest = 0x4001025c ); -PROVIDE ( ets_secure_boot_verify_bootloader_with_keys = 0x40010444 ); -PROVIDE ( ets_secure_boot_verify_signature = 0x400102cc ); -PROVIDE ( ets_secure_boot_verify_stage_bootloader = 0x40010720 ); -PROVIDE ( ets_set_printf_channel = 0x4000ff3c ); -PROVIDE ( ets_set_user_start = 0x4000f25c ); -PROVIDE ( ets_set_xtal_div = 0x40010c18 ); -PROVIDE ( ets_sha_clone = 0x4001095c ); -PROVIDE ( ets_sha_disable = 0x400107b4 ); -PROVIDE ( ets_sha_enable = 0x40010788 ); -PROVIDE ( ets_sha_finish = 0x40010ab8 ); -PROVIDE ( ets_sha_get_state = 0x40010934 ); -PROVIDE ( ets_sha_init = 0x400107e0 ); -PROVIDE ( ets_sha_process = 0x40010988 ); -PROVIDE ( ets_sha_starts = 0x40010828 ); -PROVIDE ( ets_sha_update = 0x400109f8 ); -PROVIDE ( ets_startup_callback = 0x3fffe718 ); -PROVIDE ( ets_unpack_flash_code_legacy = 0x40011430 ); -PROVIDE ( ets_update_cpu_frequency = 0x4000d8a4 ); -PROVIDE ( ets_vprintf = 0x4000fa3c ); -PROVIDE ( ets_waiti0 = 0x4000f190 ); -PROVIDE ( ets_wdt_reset_cpu = 0x4001a82c ); -PROVIDE ( ets_write_char = 0x4000f974 ); -PROVIDE ( ets_write_char_uart = 0x4000f998 ); -PROVIDE ( exc_cause_table = 0x3ffacbe8 ); -PROVIDE ( _exit_r = 0x4001a138 ); -PROVIDE ( __extendsfdf2 = 0x40008d08 ); -PROVIDE ( fclose = 0x4001a804 ); -PROVIDE ( _fclose_r = 0x4001a714 ); -PROVIDE ( fflush = 0x40001bb8 ); -PROVIDE ( _fflush_r = 0x40001b30 ); -PROVIDE ( __ffsdi2 = 0x4001b214 ); -PROVIDE ( __ffssi2 = 0x4001afec ); -PROVIDE ( FilePacketSendDeflatedReqMsgProc = 0x40011ed8 ); -PROVIDE ( FilePacketSendReqMsgProc = 0x40011bd8 ); -PROVIDE ( fiprintf = 0x40000a3c ); -PROVIDE ( _fiprintf_r = 0x40000a18 ); -PROVIDE ( __fixdfdi = 0x40008b98 ); -PROVIDE ( __fixdfsi = 0x40008b4c ); -PROVIDE ( __fixsfdi = 0x4000851c ); -PROVIDE ( __fixsfsi = 0x400084dc ); -PROVIDE ( __fixunsdfsi = 0x40008c04 ); -PROVIDE ( __fixunssfdi = 0x400085d4 ); -PROVIDE ( __fixunssfsi = 0x4000857c ); -PROVIDE ( flashchip = 0x3ffffd38 ); -PROVIDE ( FlashDwnLdDeflatedStartMsgProc = 0x40011e80 ); -PROVIDE ( FlashDwnLdParamCfgMsgProc = 0x40011cc0 ); -PROVIDE ( FlashDwnLdStartMsgProc = 0x40011b74 ); -PROVIDE ( FlashDwnLdStopDeflatedReqMsgProc = 0x40011fd8 ); -PROVIDE ( FlashDwnLdStopReqMsgProc = 0x40011c90 ); -PROVIDE ( __floatdidf = 0x4001b170 ); -PROVIDE ( __floatdisf = 0x4001b0a8 ); -PROVIDE ( __floatsidf = 0x4001b12c ); -PROVIDE ( __floatsisf = 0x4001b058 ); -PROVIDE ( __floatundidf = 0x4001b160 ); -PROVIDE ( __floatundisf = 0x4001b098 ); -PROVIDE ( __floatunsidf = 0x4001b120 ); -PROVIDE ( __floatunsisf = 0x4001b04c ); -PROVIDE ( __fp_lock_all = 0x4001a638 ); -PROVIDE ( fprintf = 0x40000a3c ); -PROVIDE ( _fprintf_r = 0x40000a18 ); -PROVIDE ( __fp_unlock_all = 0x4001a64c ); -PROVIDE ( fputwc = 0x40001864 ); -PROVIDE ( __fputwc = 0x40001770 ); -PROVIDE ( _fputwc_r = 0x400017f8 ); -PROVIDE ( free = 0x4001a2c8 ); -PROVIDE ( _free_r = 0x40019fdc ); -PROVIDE ( _fstat_r = 0x4001a0dc ); -PROVIDE ( _fwalk = 0x4001bcec ); -PROVIDE ( _fwalk_reent = 0x4001bd24 ); -PROVIDE ( __gcc_bcmp = 0x40006de0 ); -PROVIDE ( __gedf2 = 0x400059c4 ); -PROVIDE ( general_device_descr = 0x3ffffa58 ); -PROVIDE ( _GeneralException = 0x400073cf ); -PROVIDE ( __gesf2 = 0x40005668 ); -PROVIDE ( get_id = 0x4001610c ); -PROVIDE ( _getpid_r = 0x4001a10c ); -PROVIDE ( __getreent = 0x4001a29c ); -PROVIDE ( GetSecurityInfoProc = 0x40012098 ); -PROVIDE ( _gettimeofday_r = 0x4001a068 ); -PROVIDE ( GetUartDevice = 0x40012f60 ); -PROVIDE ( _global_impure_ptr = 0x3ffffd8c ); -PROVIDE ( __global_locale_ptr = 0x3ffffd7c ); -PROVIDE ( g_phyFuns = 0x3ffffd90 ); -PROVIDE ( g_phyFuns_instance = 0x3ffffd94 ); -PROVIDE ( gpio_input_get = 0x400193a0 ); -PROVIDE ( gpio_input_get_high = 0x400193b4 ); -PROVIDE ( gpio_matrix_in = 0x40019430 ); -PROVIDE ( gpio_matrix_out = 0x40019460 ); -PROVIDE ( gpio_output_disable = 0x400194dc ); -PROVIDE ( gpio_output_enable = 0x400194b0 ); -PROVIDE ( gpio_output_set = 0x4001933c ); -PROVIDE ( gpio_output_set_high = 0x40019374 ); -PROVIDE ( gpio_pad_hold = 0x40019654 ); -PROVIDE ( gpio_pad_input_disable = 0x400195f0 ); -PROVIDE ( gpio_pad_input_enable = 0x400195cc ); -PROVIDE ( gpio_pad_pulldown = 0x40019598 ); -PROVIDE ( gpio_pad_pullup = 0x40019564 ); -PROVIDE ( gpio_pad_select_gpio = 0x40019510 ); -PROVIDE ( gpio_pad_set_drv = 0x40019538 ); -PROVIDE ( gpio_pad_unhold = 0x4001961c ); -PROVIDE ( gpio_pin_wakeup_disable = 0x40019404 ); -PROVIDE ( gpio_pin_wakeup_enable = 0x400193c8 ); -PROVIDE ( g_shared_buffers = 0x3ffeab04 ); -PROVIDE ( __gtdf2 = 0x40005938 ); -PROVIDE ( g_ticks_per_us = 0x3ffffd70 ); -PROVIDE ( __gtsf2 = 0x400055fc ); -PROVIDE ( hmac_md5 = 0x40005490 ); -PROVIDE ( hmac_md5_vector = 0x400053a0 ); -PROVIDE ( ibus_baseaddrs = 0x3ffaf03c ); -PROVIDE ( intr_matrix_set = 0x4000f1d0 ); -PROVIDE ( _iram0_text_end = 0x40000540 ); -PROVIDE ( _iram0_text_start = 0x40000540 ); -PROVIDE ( _iram1_text_end = 0x60021100 ); -PROVIDE ( _iram1_text_start = 0x60021100 ); -PROVIDE ( isalnum = 0x400078d8 ); -PROVIDE ( isalpha = 0x400078e8 ); -PROVIDE ( isascii = 0x4001aaec ); -PROVIDE ( _isatty_r = 0x400078a0 ); -PROVIDE ( isblank = 0x400078f8 ); -PROVIDE ( iscntrl = 0x40007918 ); -PROVIDE ( isdigit = 0x40007930 ); -PROVIDE ( isgraph = 0x40007968 ); -PROVIDE ( islower = 0x40007948 ); -PROVIDE ( isprint = 0x40007980 ); -PROVIDE ( ispunct = 0x40007994 ); -PROVIDE ( isspace = 0x400079ac ); -PROVIDE ( isupper = 0x400079c4 ); -PROVIDE ( _KernelExceptionVector = 0x40000300 ); -PROVIDE ( _KernelExceptionVector_text_end = 0x40000306 ); -PROVIDE ( _KernelExceptionVector_text_start = 0x40000300 ); -PROVIDE ( _kill_r = 0x4001a120 ); -PROVIDE ( labs = 0x40000648 ); -PROVIDE ( ldiv = 0x40000650 ); -PROVIDE ( __ledf2 = 0x40005960 ); -PROVIDE ( __lesf2 = 0x4000561c ); -PROVIDE ( _Level2FromVector = 0x400074f8 ); -PROVIDE ( _Level2HandlerLabel = 0x00000000 ); -PROVIDE ( _Level2InterruptVector_text_end = 0x40000186 ); -PROVIDE ( _Level2InterruptVector_text_start = 0x40000180 ); -PROVIDE ( _Level2Vector = 0x40000180 ); -PROVIDE ( _Level3FromVector = 0x40007594 ); -PROVIDE ( _Level3HandlerLabel = 0x00000000 ); -PROVIDE ( _Level3InterruptVector_text_end = 0x400001c6 ); -PROVIDE ( _Level3InterruptVector_text_start = 0x400001c0 ); -PROVIDE ( _Level3Vector = 0x400001c0 ); -PROVIDE ( _Level4FromVector = 0x4000762c ); -PROVIDE ( _Level4HandlerLabel = 0x00000000 ); -PROVIDE ( _Level4InterruptVector_text_end = 0x40000206 ); -PROVIDE ( _Level4InterruptVector_text_start = 0x40000200 ); -PROVIDE ( _Level4Vector = 0x40000200 ); -PROVIDE ( _Level5FromVector = 0x4000775c ); -PROVIDE ( _Level5HandlerLabel = 0x00000000 ); -PROVIDE ( _Level5InterruptVector_text_end = 0x40000246 ); -PROVIDE ( _Level5InterruptVector_text_start = 0x40000240 ); -PROVIDE ( _Level5Vector = 0x40000240 ); -PROVIDE ( _LevelOneInterrupt = 0x4000740a ); -PROVIDE ( _link_r = 0x4001a0ac ); -PROVIDE ( _lit4_end = 0x40000540 ); -PROVIDE ( _lit4_start = 0x40000540 ); -PROVIDE ( lldesc_build_chain = 0x4000907c ); -PROVIDE ( lldesc_num2link = 0x4000916c ); -PROVIDE ( lldesc_set_owner = 0x40009198 ); -PROVIDE ( lldesc_setup = 0x40019ed8 ); -PROVIDE ( __locale_ctype_ptr = 0x40001c2c ); -PROVIDE ( __locale_ctype_ptr_l = 0x40001c24 ); -PROVIDE ( __locale_mb_cur_max = 0x40001c0c ); -PROVIDE ( _lock_acquire = 0x4001a224 ); -PROVIDE ( _lock_acquire_recursive = 0x4001a238 ); -PROVIDE ( _lock_close = 0x4001a1fc ); -PROVIDE ( _lock_close_recursive = 0x4001a210 ); -PROVIDE ( _lock_init = 0x4001a1d4 ); -PROVIDE ( _lock_init_recursive = 0x4001a1e8 ); -PROVIDE ( _lock_release = 0x4001a274 ); -PROVIDE ( _lock_release_recursive = 0x4001a288 ); -PROVIDE ( _lock_try_acquire = 0x4001a24c ); -PROVIDE ( _lock_try_acquire_recursive = 0x4001a260 ); -PROVIDE ( longjmp = 0x400005a4 ); -PROVIDE ( _lseek_r = 0x4001a19c ); -PROVIDE ( __lshrdi3 = 0x4001b034 ); -PROVIDE ( __ltdf2 = 0x400059ec ); -PROVIDE ( __ltsf2 = 0x40005688 ); -PROVIDE ( main = 0x4000f6c4 ); -PROVIDE ( malloc = 0x4001a2b0 ); -PROVIDE ( _malloc_r = 0x40019fc4 ); -PROVIDE ( _mbtowc_r = 0x400079e0 ); -PROVIDE ( MD5Final = 0x4000530c ); -PROVIDE ( MD5Init = 0x4000526c ); -PROVIDE ( MD5Update = 0x4000528c ); -PROVIDE ( md5_vector = 0x40005374 ); -PROVIDE ( memccpy = 0x4001ab00 ); -PROVIDE ( memchr = 0x4001ab24 ); -PROVIDE ( memcmp = 0x4001ab40 ); -PROVIDE ( memcpy = 0x4001aba8 ); -PROVIDE ( MemDwnLdStartMsgProc = 0x40011cec ); -PROVIDE ( MemDwnLdStopReqMsgProc = 0x40011d80 ); -PROVIDE ( _memmap_cacheattr_bp_allvalid = 0x22222222 ); -PROVIDE ( _memmap_cacheattr_bp_base = 0x00000220 ); -PROVIDE ( _memmap_cacheattr_bp_strict = 0xfffff22f ); -PROVIDE ( _memmap_cacheattr_bp_trapnull = 0x2222222f ); -PROVIDE ( _memmap_cacheattr_reset = 0x2222211f ); -PROVIDE ( _memmap_cacheattr_unused_mask = 0xfffff00f ); -PROVIDE ( _memmap_cacheattr_wb_allvalid = 0x22222112 ); -PROVIDE ( _memmap_cacheattr_wba_trapnull = 0x2222211f ); -PROVIDE ( _memmap_cacheattr_wb_base = 0x00000110 ); -PROVIDE ( _memmap_cacheattr_wbna_trapnull = 0x2222211f ); -PROVIDE ( _memmap_cacheattr_wb_strict = 0xfffff11f ); -PROVIDE ( _memmap_cacheattr_wb_trapnull = 0x2222211f ); -PROVIDE ( _memmap_cacheattr_wt_allvalid = 0x22222112 ); -PROVIDE ( _memmap_cacheattr_wt_base = 0x00000110 ); -PROVIDE ( _memmap_cacheattr_wt_strict = 0xfffff11f ); -PROVIDE ( _memmap_cacheattr_wt_trapnull = 0x2222211f ); -PROVIDE ( _memmap_vecbase_reset = 0x40000000 ); -PROVIDE ( memmove = 0x4001acb0 ); -PROVIDE ( MemPacketSendReqMsgProc = 0x40011d1c ); -PROVIDE ( memrchr = 0x4001acec ); -PROVIDE ( memset = 0x4001ad3c ); -PROVIDE ( __moddi3 = 0x4001b534 ); -PROVIDE ( __modsi3 = 0x4001afa8 ); -PROVIDE ( __muldc3 = 0x40005f0c ); -PROVIDE ( __muldf3 = 0x400057e8 ); -PROVIDE ( __muldi3 = 0x4001b1e4 ); -PROVIDE ( __mulsc3 = 0x40005ba4 ); -PROVIDE ( __mulsf3 = 0x40005524 ); -PROVIDE ( __mulsi3 = 0x4001af98 ); -PROVIDE ( multofup = 0x4001bce0 ); -PROVIDE ( __mulvdi3 = 0x40008e50 ); -PROVIDE ( __mulvsi3 = 0x40008e38 ); -PROVIDE ( must_reset = 0x3ffffcf4 ); -PROVIDE ( mz_adler32 = 0x40002e90 ); -PROVIDE ( mz_crc32 = 0x40002f58 ); -PROVIDE ( mz_free = 0x40002fa4 ); -PROVIDE ( __nedf2 = 0x40005904 ); -PROVIDE ( __negdf2 = 0x400056fc ); -PROVIDE ( __negdi2 = 0x4001b1fc ); -PROVIDE ( __negsf2 = 0x40008190 ); -PROVIDE ( __negvdi2 = 0x40008f6c ); -PROVIDE ( __negvsi2 = 0x40008f4c ); -PROVIDE ( __nesf2 = 0x400055d0 ); -PROVIDE ( _NMIExceptionVector = 0x400002c0 ); -PROVIDE ( _NMIExceptionVector_text_end = 0x400002c3 ); -PROVIDE ( _NMIExceptionVector_text_start = 0x400002c0 ); -PROVIDE ( __nsau_data = 0x3ffac870 ); -PROVIDE ( open = 0x400080c4 ); -PROVIDE ( _open_r = 0x4001a164 ); -PROVIDE ( __packed = 0x3ffffcec ); -PROVIDE ( __paritysi2 = 0x40009038 ); -PROVIDE ( _PathLocale = 0x3ffffd80 ); -PROVIDE ( phy_get_romfuncs = 0x4000a88c ); -PROVIDE ( __popcountdi2 = 0x40008fe0 ); -PROVIDE ( __popcountsi2 = 0x40008fa8 ); -PROVIDE ( __popcount_tab = 0x3ffac870 ); -PROVIDE ( __powidf2 = 0x40005b40 ); -PROVIDE ( __powisf2 = 0x40005af8 ); -PROVIDE ( _Pri_4_HandlerAddress = 0x3fffed78 ); -PROVIDE ( _Pri_5_HandlerAddress = 0x3fffed7c ); -PROVIDE ( _printf_common = 0x40000e60 ); -PROVIDE ( _printf_float = 0x4001a30c ); -PROVIDE ( _printf_i = 0x40000f2c ); -PROVIDE ( pthread_setcancelstate = 0x40019fa8 ); -PROVIDE ( _putc1 = 0x3ffffd6c ); -PROVIDE ( _putc2 = 0x3ffffd68 ); -PROVIDE ( qsort = 0x400006f4 ); -PROVIDE ( _raise_r = 0x4001a080 ); -PROVIDE ( rand = 0x40007a78 ); -PROVIDE ( rand_r = 0x40007af4 ); -PROVIDE ( RcvMsg = 0x40012f10 ); -PROVIDE ( read = 0x40008114 ); -PROVIDE ( _read_r = 0x4001a1b8 ); -PROVIDE ( realloc = 0x4001a2dc ); -PROVIDE ( _realloc_r = 0x40019ff0 ); -PROVIDE ( recv_packet = 0x40012de8 ); -PROVIDE ( _rename_r = 0x4001a038 ); -PROVIDE ( _ResetHandler = 0x4000044c ); -PROVIDE ( _ResetVector = 0x40000400 ); -PROVIDE ( _ResetVector_literal_end = 0x40000540 ); -PROVIDE ( _ResetVector_literal_start = 0x40000540 ); -PROVIDE ( _ResetVector_text_end = 0x4000053d ); -PROVIDE ( _ResetVector_text_start = 0x40000400 ); -PROVIDE ( _rodata_end = 0x3ffaff2c ); -PROVIDE ( _rodata_start = 0x3ffac600 ); -PROVIDE ( rom_abs_temp = 0x4000c330 ); -PROVIDE ( rom_ant_btrx_cfg = 0x4000a0fc ); -PROVIDE ( rom_ant_bttx_cfg = 0x4000a0c0 ); -PROVIDE ( rom_ant_dft_cfg = 0x40009fc8 ); -PROVIDE ( rom_ant_wifirx_cfg = 0x4000a03c ); -PROVIDE ( rom_ant_wifitx_cfg = 0x40009ff8 ); -PROVIDE ( rom_bb_bss_cbw40_dig = 0x40009a84 ); -PROVIDE ( rom_bb_wdg_cfg = 0x40009eb8 ); -PROVIDE ( rom_bb_wdg_test_en = 0x40009a48 ); -PROVIDE ( rom_bb_wdt_get_status = 0x40009d18 ); -PROVIDE ( rom_bb_wdt_int_enable = 0x40009cd4 ); -PROVIDE ( rom_bb_wdt_rst_enable = 0x40009cb4 ); -PROVIDE ( rom_bb_wdt_timeout_clear = 0x40009cfc ); -PROVIDE ( rom_cbw2040_cfg = 0x4000a550 ); -PROVIDE ( rom_check_noise_floor = 0x40009b4c ); -PROVIDE ( rom_chip_i2c_readReg = 0x4000a8e4 ); -PROVIDE ( rom_chip_i2c_writeReg = 0x4000a960 ); -PROVIDE ( rom_correct_rf_ana_gain = 0x4000d2b4 ); -PROVIDE ( rom_dc_iq_est = 0x4000c414 ); -PROVIDE ( rom_disable_agc = 0x400091cc ); -PROVIDE ( rom_enable_agc = 0x400091e4 ); -PROVIDE ( rom_freq_get_i2c_data = 0x4000bb84 ); -PROVIDE ( rom_freq_i2c_set_wifi_data = 0x4000b948 ); -PROVIDE ( rom_freq_i2c_write_set = 0x4000b3bc ); -PROVIDE ( rom_gen_rx_gain_table = 0x4000a300 ); -PROVIDE ( rom_get_bbgain_db = 0x400094ec ); -PROVIDE ( rom_get_data_sat = 0x40009338 ); -PROVIDE ( rom_get_fm_sar_dout = 0x4000c024 ); -PROVIDE ( rom_get_i2c_read_mask = 0x4000a8c0 ); -PROVIDE ( rom_get_power_db = 0x4000ce28 ); -PROVIDE ( rom_get_pwctrl_correct = 0x4000d470 ); -PROVIDE ( rom_get_rfcal_rxiq_data = 0x4000cab0 ); -PROVIDE ( rom_get_rf_gain_qdb = 0x4000d29c ); -PROVIDE ( rom_get_sar_dout = 0x4000d400 ); -PROVIDE ( rom_i2c_clk_sel = 0x4000a788 ); -PROVIDE ( rom_i2c_readReg = 0x4000a940 ); -PROVIDE ( rom_i2c_readReg_Mask = 0x4000a9c4 ); -PROVIDE ( rom_i2c_writeReg = 0x4000a9a8 ); -PROVIDE ( rom_i2c_writeReg_Mask = 0x4000aa00 ); -PROVIDE ( rom_index_to_txbbgain = 0x4000bd10 ); -PROVIDE ( rom_iq_est_disable = 0x4000c3d8 ); -PROVIDE ( rom_iq_est_enable = 0x4000c358 ); -PROVIDE ( rom_linear_to_db = 0x4000cdbc ); -PROVIDE ( rom_loopback_mode_en = 0x40009304 ); -PROVIDE ( rom_mac_enable_bb = 0x40009e48 ); -PROVIDE ( rom_meas_tone_pwr_db = 0x4000ce64 ); -PROVIDE ( rom_mhz2ieee = 0x4000a4e8 ); -PROVIDE ( rom_noise_floor_auto_set = 0x40009ab4 ); -PROVIDE ( rom_pbus_debugmode = 0x4000ac70 ); -PROVIDE ( rom_pbus_force_mode = 0x4000aa6c ); -PROVIDE ( rom_pbus_force_test = 0x4000abd0 ); -PROVIDE ( rom_pbus_rd = 0x4000ac2c ); -PROVIDE ( rom_pbus_rd_addr = 0x4000ab34 ); -PROVIDE ( rom_pbus_rd_shift = 0x4000ab80 ); -PROVIDE ( rom_pbus_rx_dco_cal = 0x4000c49c ); -PROVIDE ( rom_pbus_set_dco = 0x4000ae2c ); -PROVIDE ( rom_pbus_set_rxgain = 0x4000ac98 ); -PROVIDE ( rom_pbus_workmode = 0x4000ac84 ); -PROVIDE ( rom_pbus_xpd_rx_off = 0x4000acfc ); -PROVIDE ( rom_pbus_xpd_rx_on = 0x4000ad30 ); -PROVIDE ( rom_pbus_xpd_tx_off = 0x4000ad84 ); -PROVIDE ( rom_pbus_xpd_tx_on = 0x4000add4 ); -PROVIDE ( rom_phy_ant_init = 0x40009f48 ); -PROVIDE ( rom_phy_byte_to_word = 0x40009d60 ); -PROVIDE ( rom_phy_chan_dump_cfg = 0x4000a180 ); -PROVIDE ( rom_phy_chan_filt_set = 0x4000a614 ); -PROVIDE ( rom_phy_close_pa = 0x4000a810 ); -PROVIDE ( rom_phy_disable_cca = 0x40009208 ); -PROVIDE ( rom_phy_disable_low_rate = 0x4000a2b8 ); -PROVIDE ( rom_phy_enable_cca = 0x40009234 ); -PROVIDE ( rom_phy_enable_low_rate = 0x4000a280 ); -PROVIDE ( rom_phy_freq_correct = 0x4000b0b4 ); -PROVIDE ( rom_phy_get_noisefloor = 0x40009b04 ); -PROVIDE ( rom_phy_get_rx_freq = 0x4000a6ac ); -PROVIDE ( rom_phy_get_tx_rate = 0x40009d50 ); -PROVIDE ( rom_phy_rx11blr_cfg = 0x40009c5c ); -PROVIDE ( rom_phy_rx_sense_set = 0x4000a704 ); -PROVIDE ( rom_phy_set_bbfreq_init = 0x4000d3d0 ); -PROVIDE ( rom_pll_correct_dcap = 0x4000bad4 ); -PROVIDE ( rom_pow_usr = 0x4000924c ); -PROVIDE ( rom_read_hw_noisefloor = 0x40009c38 ); -PROVIDE ( rom_read_sar_dout = 0x4000bfd4 ); -PROVIDE ( rom_restart_cal = 0x4000ae74 ); -PROVIDE ( rom_rfcal_pwrctrl = 0x4000d098 ); -PROVIDE ( rom_rfcal_rxiq = 0x4000ca3c ); -PROVIDE ( rom_rfcal_txcap = 0x4000ccac ); -PROVIDE ( rom_rfpll_set_freq = 0x4000afa4 ); -PROVIDE ( rom_rftx_init = 0x4000b24c ); -PROVIDE ( rom_rx_gain_force = 0x40009558 ); -PROVIDE ( rom_rxiq_cover_mg_mp = 0x4000c954 ); -PROVIDE ( rom_rxiq_get_mis = 0x4000c7d8 ); -PROVIDE ( rom_rxiq_set_reg = 0x4000c8ec ); -PROVIDE ( rom_set_cal_rxdc = 0x400092c4 ); -PROVIDE ( rom_set_cca = 0x4000a59c ); -PROVIDE ( rom_set_chan_cal_interp = 0x4000cba4 ); -PROVIDE ( rom_set_channel_freq = 0x4000b00c ); -PROVIDE ( rom_set_loopback_gain = 0x40009268 ); -PROVIDE ( rom_set_noise_floor = 0x40009bf4 ); -PROVIDE ( rom_set_pbus_mem = 0x40009380 ); -PROVIDE ( rom_set_rf_freq_offset = 0x4000b214 ); -PROVIDE ( rom_set_rxclk_en = 0x400095cc ); -PROVIDE ( rom_set_txcap_reg = 0x4000cc34 ); -PROVIDE ( rom_set_txclk_en = 0x4000959c ); -PROVIDE ( rom_set_tx_dig_gain = 0x40009514 ); -PROVIDE ( rom_set_xpd_sar = 0x40009f08 ); -PROVIDE ( rom_spur_cal = 0x4000a47c ); -PROVIDE ( rom_spur_reg_write_one_tone = 0x400097c4 ); -PROVIDE ( rom_start_tx_tone = 0x400096f0 ); -PROVIDE ( rom_start_tx_tone_step = 0x40009608 ); -PROVIDE ( rom_stop_tx_tone = 0x4000a428 ); -PROVIDE ( _rom_store = 0x4001bed0 ); -PROVIDE ( _rom_store_table = 0x4001bd64 ); -PROVIDE ( rom_target_power_add_backoff = 0x4000d278 ); -PROVIDE ( rom_txbbgain_to_index = 0x4000bce0 ); -PROVIDE ( rom_txcal_work_mode = 0x4000bf30 ); -PROVIDE ( rom_txdc_cal_init = 0x4000bd2c ); -PROVIDE ( rom_txdc_cal_v70 = 0x4000bdc0 ); -PROVIDE ( rom_txiq_cover = 0x4000c1ac ); -PROVIDE ( rom_txiq_get_mis_pwr = 0x4000c0f8 ); -PROVIDE ( rom_txiq_set_reg = 0x4000bf64 ); -PROVIDE ( rom_tx_paon_set = 0x40009db8 ); -PROVIDE ( rom_tx_pwr_backoff = 0x4000ceb8 ); -PROVIDE ( rom_txtone_linear_pwr = 0x4000c0b0 ); -PROVIDE ( rom_wait_rfpll_cal_end = 0x4000af3c ); -PROVIDE ( rom_wifi_11g_rate_chg = 0x4000d260 ); -PROVIDE ( rom_wifi_rifs_mode_en = 0x40009d2c ); -PROVIDE ( rom_write_dac_gain2 = 0x4000a210 ); -PROVIDE ( rom_write_gain_mem = 0x400094bc ); -PROVIDE ( rom_write_pll_cap_mem = 0x4000ba58 ); -PROVIDE ( rom_write_rfpll_sdm = 0x4000aed4 ); -PROVIDE ( rom_wr_rf_freq_mem = 0x4000b2f0 ); -PROVIDE ( roundup2 = 0x4001bcd0 ); -PROVIDE ( rtc_boot_control = 0x4001002c ); -PROVIDE ( rtc_get_reset_reason = 0x4000ff58 ); -PROVIDE ( rtc_get_wakeup_cause = 0x4000ff7c ); -PROVIDE ( rtc_select_apb_bridge = 0x400100a0 ); -PROVIDE ( sbrk = 0x4000812c ); -PROVIDE ( _sbrk_r = 0x4001a0f4 ); -PROVIDE ( _scanf_float = 0x4001a328 ); -PROVIDE ( s_cdcacm_old_rts = 0x3ffffd34 ); -PROVIDE ( __sclose = 0x4001a700 ); -PROVIDE ( SelectSpiFunction = 0x40015d08 ); -PROVIDE ( SelectSpiQIO = 0x40015b88 ); -PROVIDE ( SendMsg = 0x40012d0c ); -PROVIDE ( send_packet = 0x40012cc8 ); -PROVIDE ( __seofread = 0x4001a690 ); -PROVIDE ( setjmp = 0x40000540 ); -PROVIDE ( setlocale = 0x40001c44 ); -PROVIDE ( _setlocale_r = 0x40001bdc ); -PROVIDE ( set_rtc_memory_crc = 0x40010010 ); -PROVIDE ( SetSpiDrvs = 0x40015c18 ); -PROVIDE ( __sf_fake_stderr = 0x3ffaf08c ); -PROVIDE ( __sf_fake_stdin = 0x3ffaf0cc ); -PROVIDE ( __sf_fake_stdout = 0x3ffaf0ac ); -PROVIDE ( __sflush_r = 0x400019dc ); -PROVIDE ( __sfmoreglue = 0x4001a4c8 ); -PROVIDE ( __sfp = 0x4001a590 ); -PROVIDE ( __sfp_lock_acquire = 0x4001a508 ); -PROVIDE ( __sfp_lock_release = 0x4001a514 ); -PROVIDE ( __sfputs_r = 0x40000aa0 ); -PROVIDE ( __sfvwrite_r = 0x40001310 ); -PROVIDE ( sig_matrix = 0x3ffffd57 ); -PROVIDE ( __sinit = 0x4001a538 ); -PROVIDE ( __sinit_lock_acquire = 0x4001a520 ); -PROVIDE ( __sinit_lock_release = 0x4001a52c ); -PROVIDE ( __smakebuf_r = 0x40001954 ); -PROVIDE ( software_reset = 0x40010068 ); -PROVIDE ( software_reset_cpu = 0x40010080 ); -PROVIDE ( SPI_block_erase = 0x4001623c ); -PROVIDE ( spi_cache_mode_switch = 0x40016a00 ); -PROVIDE ( SPI_chip_erase = 0x400161b8 ); -PROVIDE ( SPIClkConfig = 0x400170a0 ); -PROVIDE ( SPI_Common_Command = 0x400162e8 ); -PROVIDE ( spi_common_set_flash_cs_timing = 0x40016c0c ); -PROVIDE ( spi_dummy_len_fix = 0x40015b50 ); -PROVIDE ( SPI_Encrypt_Write = 0x400177e0 ); -PROVIDE ( SPI_Encrypt_Write_Dest = 0x400176cc ); -PROVIDE ( SPIEraseArea = 0x40017470 ); -PROVIDE ( SPIEraseBlock = 0x4001710c ); -PROVIDE ( SPIEraseChip = 0x400170ec ); -PROVIDE ( SPIEraseSector = 0x4001716c ); -PROVIDE ( spi_flash_attach = 0x40017004 ); -PROVIDE ( spi_flash_boot_attach = 0x40016fc0 ); -PROVIDE ( spi_flash_check_suspend_cb = 0x3ffffd58 ); -PROVIDE ( SPI_flashchip_data = 0x3ffffd3c ); -PROVIDE ( spi_flash_set_check_suspend_cb = 0x40015b3c ); -PROVIDE ( SPI_init = 0x40016ce8 ); -PROVIDE ( SPILock = 0x40016ed4 ); -PROVIDE ( SPIMasterReadModeCnfig = 0x40017014 ); -PROVIDE ( SPI_page_program = 0x400165a8 ); -PROVIDE ( SPIParamCfg = 0x40017500 ); -PROVIDE ( SPIRead = 0x4001728c ); -PROVIDE ( SPI_read_data = 0x40015ed8 ); -PROVIDE ( SPIReadModeCnfig = 0x40016f1c ); -PROVIDE ( SPI_read_status = 0x40016084 ); -PROVIDE ( SPI_read_status_high = 0x40016284 ); -PROVIDE ( SPI_sector_erase = 0x400161ec ); -PROVIDE ( spi_slave_download = 0x4001998c ); -PROVIDE ( spi_slave_rom_check_conn = 0x40019724 ); -PROVIDE ( spi_slave_rom_init = 0x40019774 ); -PROVIDE ( spi_slave_rom_init_hw = 0x40019b5c ); -PROVIDE ( spi_slave_rom_intr_enable = 0x40019b3c ); -PROVIDE ( spi_slave_rom_rxdma_load = 0x40019da8 ); -PROVIDE ( spi_slave_rom_txdma_load = 0x40019e3c ); -PROVIDE ( SPIUnlock = 0x40016e88 ); -PROVIDE ( SPI_user_command_read = 0x40015fc8 ); -PROVIDE ( SPI_Wait_Idle = 0x40016680 ); -PROVIDE ( SPI_WakeUp = 0x400160f4 ); -PROVIDE ( SPIWrite = 0x400171cc ); -PROVIDE ( SPI_write_enable = 0x4001655c ); -PROVIDE ( SPI_Write_Encrypt_Disable = 0x40017694 ); -PROVIDE ( SPI_Write_Encrypt_Enable = 0x40017678 ); -PROVIDE ( SPI_write_status = 0x400162a4 ); -PROVIDE ( __sprint_r = 0x40000aec ); -PROVIDE ( srand = 0x40007a24 ); -PROVIDE ( __sread = 0x4001a660 ); -PROVIDE ( __sseek = 0x4001a6cc ); -PROVIDE ( __stack = 0x3fffe710 ); -PROVIDE ( _stack_sentry = 0x3fffc410 ); -PROVIDE ( _start = 0x4000726c ); -PROVIDE ( _stat_r = 0x4001a0c4 ); -PROVIDE ( _stext = 0x40007118 ); -PROVIDE ( strcasecmp = 0x40007b38 ); -PROVIDE ( strcasestr = 0x40007b7c ); -PROVIDE ( strcat = 0x4001ad90 ); -PROVIDE ( strchr = 0x4001adb0 ); -PROVIDE ( strcmp = 0x40007be4 ); -PROVIDE ( strcoll = 0x40007ce8 ); -PROVIDE ( strcpy = 0x40007cfc ); -PROVIDE ( strcspn = 0x4001adcc ); -PROVIDE ( strdup = 0x40007d84 ); -PROVIDE ( _strdup_r = 0x40007d98 ); -PROVIDE ( string0_descr = 0x3ffaeeae ); -PROVIDE ( strlcat = 0x40007db8 ); -PROVIDE ( strlcpy = 0x4001adf8 ); -PROVIDE ( strlen = 0x40007e08 ); -PROVIDE ( strlwr = 0x40007e68 ); -PROVIDE ( str_manu_descr = 0x3ffaee9a ); -PROVIDE ( strncasecmp = 0x40007e94 ); -PROVIDE ( strncat = 0x4001ae34 ); -PROVIDE ( strncmp = 0x4001ae64 ); -PROVIDE ( strncpy = 0x40007f20 ); -PROVIDE ( strndup = 0x40007fe8 ); -PROVIDE ( _strndup_r = 0x40007ffc ); -PROVIDE ( strnlen = 0x4001ae9c ); -PROVIDE ( str_prod_descr = 0x3ffaee88 ); -PROVIDE ( strrchr = 0x40008040 ); -PROVIDE ( strsep = 0x4000806c ); -PROVIDE ( str_serial_descr = 0x3ffaee84 ); -PROVIDE ( strspn = 0x4001aebc ); -PROVIDE ( strstr = 0x4001aee8 ); -PROVIDE ( __strtok_r = 0x4001af18 ); -PROVIDE ( strtok_r = 0x4001af7c ); -PROVIDE ( strupr = 0x40008084 ); -PROVIDE ( __subdf3 = 0x400087b4 ); -PROVIDE ( __subsf3 = 0x400082a0 ); -PROVIDE ( __subvdi3 = 0x40008df4 ); -PROVIDE ( __subvsi3 = 0x40008dd0 ); -PROVIDE ( s_usb_osglue = 0x3ffffcdc ); -PROVIDE ( __swbuf = 0x4000167c ); -PROVIDE ( __swbuf_r = 0x400015bc ); -PROVIDE ( __swhatbuf_r = 0x400018f8 ); -PROVIDE ( __swrite = 0x4001a698 ); -PROVIDE ( __swsetup_r = 0x40001690 ); -PROVIDE ( _SyscallException = 0x4000732a ); -PROVIDE ( syscall_table_ptr_app = 0x3ffffd74 ); -PROVIDE ( syscall_table_ptr_pro = 0x3ffffd78 ); -PROVIDE ( _system_r = 0x4001a020 ); -PROVIDE ( tdefl_compress = 0x400041dc ); -PROVIDE ( tdefl_compress_buffer = 0x40004938 ); -PROVIDE ( tdefl_compress_mem_to_mem = 0x40004a50 ); -PROVIDE ( tdefl_compress_mem_to_output = 0x40004a30 ); -PROVIDE ( tdefl_get_adler32 = 0x40004a28 ); -PROVIDE ( tdefl_get_prev_return_status = 0x40004a20 ); -PROVIDE ( tdefl_init = 0x40004954 ); -PROVIDE ( tdefl_write_image_to_png_file_in_memory = 0x40004a64 ); -PROVIDE ( tdefl_write_image_to_png_file_in_memory_ex = 0x40004a58 ); -PROVIDE ( _text_end = 0x4001bed0 ); -PROVIDE ( _text_start = 0x40007118 ); -PROVIDE ( _times_r = 0x4001a050 ); -PROVIDE ( tinfl_decompress = 0x40003000 ); -PROVIDE ( tinfl_decompress_mem_to_callback = 0x400041a8 ); -PROVIDE ( tinfl_decompress_mem_to_mem = 0x40004168 ); -PROVIDE ( toascii = 0x4001af90 ); -PROVIDE ( tolower = 0x40008158 ); -PROVIDE ( toupper = 0x40008174 ); -PROVIDE ( __truncdfsf2 = 0x40008c64 ); -PROVIDE ( uart_acm_dev = 0x3ffffcf8 ); -PROVIDE ( uartAttach = 0x40012890 ); -PROVIDE ( uart_baudrate_detect = 0x400128f0 ); -PROVIDE ( uart_buff_switch = 0x40012d64 ); -PROVIDE ( UartConnCheck = 0x40011ab4 ); -PROVIDE ( UartConnectProc = 0x40011da8 ); -PROVIDE ( UartDev = 0x3ffffcfc ); -PROVIDE ( UartDev_buff_uart_no = 0x3ffffd14 ); -PROVIDE ( uart_div_modify = 0x40012984 ); -PROVIDE ( uart_div_reinit = 0x400129d0 ); -PROVIDE ( UartDwnLdProc = 0x400121ac ); -PROVIDE ( UartGetCmdLn = 0x40012f28 ); -PROVIDE ( Uart_Init = 0x40012a04 ); -PROVIDE ( Uart_Init_USB = 0x40012818 ); -PROVIDE ( UartRegReadProc = 0x40011df8 ); -PROVIDE ( UartRegWriteProc = 0x40011db8 ); -PROVIDE ( uart_rx_intr_handler = 0x40012690 ); -PROVIDE ( uart_rx_one_char = 0x40012bf0 ); -PROVIDE ( uart_rx_one_char_block = 0x40012b9c ); -PROVIDE ( uart_rx_readbuff = 0x40012d1c ); -PROVIDE ( UartRxString = 0x40012c84 ); -PROVIDE ( UartSecureDwnLdProc = 0x40012464 ); -PROVIDE ( UartSetBaudProc = 0x40011e54 ); -PROVIDE ( UartSpiAttachProc = 0x40011e0c ); -PROVIDE ( UartSpiReadProc = 0x40011e28 ); -PROVIDE ( uart_tx_flush = 0x40012b40 ); -/* PROVIDE ( uart_tx_one_char = 0x40012b10 ); */ -/* Note: remapping this to uart_tx_one_char2, to keep consistency */ -PROVIDE ( uart_tx_one_char = 0x40012b28 ); -PROVIDE ( uart_tx_one_char2 = 0x40012b28 ); -PROVIDE ( uart_tx_switch = 0x400128e4 ); -PROVIDE ( uart_tx_wait_idle = 0x40012b6c ); -PROVIDE ( uart_usb_enable_reset_on_rts = 0x40012858 ); -PROVIDE ( Uart_USB_Send_Testament = 0x400127d8 ); -PROVIDE ( __ucmpdi2 = 0x40005a9c ); -PROVIDE ( __udivdi3 = 0x4001b7dc ); -PROVIDE ( __udivmoddi4 = 0x40006e20 ); -PROVIDE ( __udivsi3 = 0x4001afb0 ); -PROVIDE ( __udiv_w_sdiv = 0x40006e18 ); -PROVIDE ( __umoddi3 = 0x4001ba60 ); -PROVIDE ( __umodsi3 = 0x4001afb8 ); -PROVIDE ( __umulsidi3 = 0x4001afc0 ); -PROVIDE ( _unlink_r = 0x4001a094 ); -PROVIDE ( __unorddf2 = 0x40005a50 ); -PROVIDE ( __unordsf2 = 0x400056d4 ); -PROVIDE ( usb_cancel_transfer = 0x40015200 ); -PROVIDE ( usb_data_stuff = 0x3ffacc88 ); -PROVIDE ( usb_dc_attach = 0x40013ecc ); -PROVIDE ( usb_dc_check_poll_for_interrupts = 0x40014980 ); -PROVIDE ( usb_dc_detach = 0x40014010 ); -PROVIDE ( usb_dc_ep_check_cap = 0x40014094 ); -PROVIDE ( usb_dc_ep_clear_stall = 0x400142f0 ); -PROVIDE ( usb_dc_ep_configure = 0x400140d8 ); -PROVIDE ( usb_dc_ep_disable = 0x400144ec ); -PROVIDE ( usb_dc_ep_enable = 0x4001442c ); -PROVIDE ( usb_dc_ep_flush = 0x400145b8 ); -PROVIDE ( usb_dc_ep_halt = 0x4001435c ); -PROVIDE ( usb_dc_ep_is_stalled = 0x400143bc ); -PROVIDE ( usb_dc_ep_mps = 0x40014958 ); -PROVIDE ( usb_dc_ep_read = 0x400148d8 ); -PROVIDE ( usb_dc_ep_read_continue = 0x40014898 ); -PROVIDE ( usb_dc_ep_read_wait = 0x400147bc ); -PROVIDE ( usb_dc_ep_set_callback = 0x40014910 ); -PROVIDE ( usb_dc_ep_set_stall = 0x40014290 ); -PROVIDE ( usb_dc_ep_write = 0x40014684 ); -PROVIDE ( usb_dc_ep_write_would_block = 0x40014624 ); -PROVIDE ( usb_dc_prepare_persist = 0x40013bec ); -PROVIDE ( usb_dc_reset = 0x40014044 ); -PROVIDE ( usb_dc_set_address = 0x4001405c ); -PROVIDE ( usb_dc_set_status_callback = 0x4001494c ); -PROVIDE ( usb_deconfig = 0x40014fa8 ); -PROVIDE ( usb_dev_get_configuration = 0x40014f4c ); -PROVIDE ( usb_dev_resume = 0x40014f38 ); -PROVIDE ( usb_dfu_force_detach = 0x400155b0 ); -PROVIDE ( usb_dfu_init = 0x40015598 ); -PROVIDE ( usb_dfu_set_detach_cb = 0x400152dc ); -PROVIDE ( usb_disable = 0x40015058 ); -PROVIDE ( usb_dw_isr_handler = 0x40013c48 ); -PROVIDE ( usb_enable = 0x40014fc8 ); -PROVIDE ( usb_ep_clear_stall = 0x400150c8 ); -PROVIDE ( usb_ep_read_continue = 0x400150f0 ); -PROVIDE ( usb_ep_read_wait = 0x400150d8 ); -PROVIDE ( usb_ep_set_stall = 0x400150b8 ); -PROVIDE ( usb_get_descriptor = 0x400149c0 ); -PROVIDE ( usb_read = 0x400150a0 ); -PROVIDE ( usb_set_config = 0x40014f64 ); -PROVIDE ( usb_set_current_descriptor = 0x400149a8 ); -PROVIDE ( usb_transfer = 0x40015150 ); -PROVIDE ( usb_transfer_ep_callback = 0x40015100 ); -PROVIDE ( usb_transfer_sync = 0x40015250 ); -PROVIDE ( usb_write = 0x40015088 ); -PROVIDE ( usb_write_would_block = 0x40015078 ); -PROVIDE ( user_code_start = 0x3fffe714 ); -PROVIDE ( _UserExceptionVector = 0x40000340 ); -PROVIDE ( _UserExceptionVector_text_end = 0x40000357 ); -PROVIDE ( _UserExceptionVector_text_start = 0x40000340 ); -PROVIDE ( VerifyFlashMd5Proc = 0x40012004 ); -PROVIDE ( vfiprintf = 0x40000e40 ); -PROVIDE ( _vfiprintf_r = 0x40000b58 ); -PROVIDE ( vfprintf = 0x40000e40 ); -PROVIDE ( _vfprintf_r = 0x40000b58 ); -PROVIDE ( Wait_SPI_Idle = 0x40016188 ); -PROVIDE ( wcrtomb = 0x400012f4 ); -PROVIDE ( _wcrtomb_r = 0x400012a0 ); -PROVIDE ( _wctomb_r = 0x400018ac ); -PROVIDE ( _WindowOverflow12 = 0x40000100 ); -PROVIDE ( _WindowOverflow4 = 0x40000000 ); -PROVIDE ( _WindowOverflow8 = 0x40000080 ); -PROVIDE ( _WindowUnderflow12 = 0x40000140 ); -PROVIDE ( _WindowUnderflow4 = 0x40000040 ); -PROVIDE ( _WindowUnderflow8 = 0x400000c0 ); -PROVIDE ( _WindowVectors_text_end = 0x40000170 ); -PROVIDE ( _WindowVectors_text_start = 0x40000000 ); -PROVIDE ( write = 0x40008140 ); -PROVIDE ( _write_r = 0x4001a180 ); -PROVIDE ( __XT_EXCEPTION_DESCS__ = 0x3ffaff2c ); -PROVIDE ( __XT_EXCEPTION_DESCS_END__ = 0x3ffaff2c ); -PROVIDE ( __XT_EXCEPTION_TABLE__ = 0x3ffafe3a ); -PROVIDE ( xthal_bcopy = 0x4001a918 ); -PROVIDE ( xthal_copy123 = 0x4001a9ac ); -PROVIDE ( xthal_get_ccompare = 0x4001aabc ); -PROVIDE ( xthal_get_ccount = 0x4001aa90 ); -PROVIDE ( xthal_get_interrupt = 0x4001aadc ); -PROVIDE ( Xthal_intlevel = 0x3ffaf06c ); -PROVIDE ( xthal_memcpy = 0x4001a93c ); -PROVIDE ( xthal_set_ccompare = 0x4001aa98 ); -PROVIDE ( xthal_set_intclear = 0x4001aae4 ); -PROVIDE ( xthals_hw_configid0 = 0xc2ecfafe ); -PROVIDE ( xthals_hw_configid1 = 0x224787b1 ); -PROVIDE ( xthals_release_major = 0x00002ee0 ); -PROVIDE ( xthals_release_minor = 0x00000009 ); -PROVIDE ( _xtos_alloca_handler = 0x40000010 ); -PROVIDE ( xtos_cause3_handler = 0x40007370 ); -PROVIDE ( xtos_c_handler_table = 0x3fffec78 ); -PROVIDE ( xtos_c_wrapper_handler = 0x40007380 ); -PROVIDE ( _xtos_enabled = 0x3fffed80 ); -PROVIDE ( xtos_exc_handler_table = 0x3fffeb78 ); -PROVIDE ( xtos_interrupt_mask_table = 0x3fffee88 ); -PROVIDE ( xtos_interrupt_table = 0x3fffed88 ); -PROVIDE ( _xtos_ints_off = 0x4001a3e0 ); -PROVIDE ( _xtos_ints_on = 0x4001a3bc ); -PROVIDE ( _xtos_intstruct = 0x3fffed80 ); -PROVIDE ( _xtos_l1int_handler = 0x400073ec ); -PROVIDE ( xtos_p_none = 0x4001a8a0 ); -PROVIDE ( _xtos_restore_intlevel = 0x400074cc ); -PROVIDE ( _xtos_return_from_exc = 0x4001a8a8 ); -PROVIDE ( _xtos_set_exception_handler = 0x400072b4 ); -PROVIDE ( _xtos_set_interrupt_handler = 0x4001a380 ); -PROVIDE ( _xtos_set_interrupt_handler_arg = 0x4001a344 ); -PROVIDE ( _xtos_set_intlevel = 0x4001a8c0 ); -PROVIDE ( _xtos_set_min_intlevel = 0x4001a8dc ); -PROVIDE ( _xtos_set_vpri = 0x400074d8 ); -PROVIDE ( _xtos_syscall_handler = 0x400072fc ); -PROVIDE ( xtos_unhandled_exception = 0x4001a900 ); -PROVIDE ( xtos_unhandled_interrupt = 0x4001a910 ); -PROVIDE ( _xtos_vectors_ref_ = 0x00000000 ); -PROVIDE ( _xtos_vpri_enabled = 0x3fffed84 ); diff --git a/tools/esptool_py/flasher_stub/ld/rom_32s3.ld b/tools/esptool_py/flasher_stub/ld/rom_32s3.ld deleted file mode 100644 index 721824c1d0..0000000000 --- a/tools/esptool_py/flasher_stub/ld/rom_32s3.ld +++ /dev/null @@ -1,2285 +0,0 @@ -/* ROM function interface esp32s3.rom.ld for esp32s3 - * - * - * Generated from ./interface-esp32s3.yml md5sum 39c4ce259b11323b9404c192b01b712b - * - * Compatible with ROM where ECO version equal or greater to 0. - * - * THIS FILE WAS AUTOMATICALLY GENERATED. DO NOT EDIT. - */ - -PROVIDE ( SPIWrite = esp_rom_spiflash_write); -PROVIDE ( SPI_read_status_high = esp_rom_spiflash_read_statushigh); -PROVIDE ( SPI_write_status = esp_rom_spiflash_write_status); -PROVIDE ( SPIRead = esp_rom_spiflash_read); -PROVIDE ( SPIParamCfg = esp_rom_spiflash_config_param); -PROVIDE ( SPIEraseChip = esp_rom_spiflash_erase_chip); -PROVIDE ( SPIEraseSector = esp_rom_spiflash_erase_sector); -PROVIDE ( SPIEraseBlock = esp_rom_spiflash_erase_block); -PROVIDE ( SPI_Write_Encrypt_Enable = esp_rom_spiflash_write_encrypted_enable); -PROVIDE ( SPI_Write_Encrypt_Disable = esp_rom_spiflash_write_encrypted_disable); -PROVIDE ( SPI_Encrypt_Write = esp_rom_spiflash_write_encrypted); -PROVIDE ( opi_flash_wren = esp_rom_opiflash_wren); - - -/*************************************** - Group common - ***************************************/ - -/* Functions */ -rtc_get_reset_reason = 0x4000057c; -analog_super_wdt_reset_happened = 0x40000588; -jtag_cpu_reset_happened = 0x40000594; -rtc_get_wakeup_cause = 0x400005a0; -rtc_select_apb_bridge = 0x400005ac; -rtc_unhold_all_pads = 0x400005b8; -ets_is_print_boot = 0x400005c4; -ets_printf = 0x400005d0; -ets_install_putc1 = 0x400005dc; -ets_install_uart_printf = 0x400005e8; -ets_install_putc2 = 0x400005f4; -PROVIDE( ets_delay_us = 0x40000600 ); -ets_get_stack_info = 0x4000060c; -ets_install_lock = 0x40000618; -ets_backup_dma_copy = 0x40000624; -ets_apb_backup_init_lock_func = 0x40000630; -UartRxString = 0x4000063c; -uart_tx_one_char = 0x40000648; -uart_tx_one_char2 = 0x40000654; -uart_rx_one_char = 0x40000660; -uart_rx_one_char_block = 0x4000066c; -uart_rx_readbuff = 0x40000678; -uartAttach = 0x40000684; -uart_tx_flush = 0x40000690; -uart_tx_wait_idle = 0x4000069c; -uart_div_modify = 0x400006a8; -ets_write_char_uart = 0x400006b4; -uart_tx_switch = 0x400006c0; -multofup = 0x400006cc; -software_reset = 0x400006d8; -software_reset_cpu = 0x400006e4; -assist_debug_clock_enable = 0x400006f0; -assist_debug_record_enable = 0x400006fc; -clear_super_wdt_reset_flag = 0x40000708; -disable_default_watchdog = 0x40000714; -ets_set_appcpu_boot_addr = 0x40000720; -esp_rom_set_rtc_wake_addr = 0x4000072c; -esp_rom_get_rtc_wake_addr = 0x40000738; -send_packet = 0x40000744; -recv_packet = 0x40000750; -GetUartDevice = 0x4000075c; -GetSecurityInfoProc = 0x40048174; -UartDwnLdProc = 0x40000768; -Uart_Init = 0x40000774; -ets_set_user_start = 0x40000780; -/* Data (.data, .bss, .rodata) */ -ets_rom_layout_p = 0x3ff1fffc; -ets_ops_table_ptr = 0x3fcefffc; - - -/*************************************** - Group miniz - ***************************************/ - -/* Functions */ -mz_adler32 = 0x4000078c; -mz_crc32 = 0x40000798; -mz_free = 0x400007a4; -tdefl_compress = 0x400007b0; -tdefl_compress_buffer = 0x400007bc; -tdefl_compress_mem_to_heap = 0x400007c8; -tdefl_compress_mem_to_mem = 0x400007d4; -tdefl_compress_mem_to_output = 0x400007e0; -tdefl_get_adler32 = 0x400007ec; -tdefl_get_prev_return_status = 0x400007f8; -tdefl_init = 0x40000804; -tdefl_write_image_to_png_file_in_memory = 0x40000810; -tdefl_write_image_to_png_file_in_memory_ex = 0x4000081c; -tinfl_decompress = 0x40000828; -tinfl_decompress_mem_to_callback = 0x40000834; -tinfl_decompress_mem_to_heap = 0x40000840; -tinfl_decompress_mem_to_mem = 0x4000084c; - - -/*************************************** - Group tjpgd - ***************************************/ - -/* Functions */ -jd_prepare = 0x40000858; -jd_decomp = 0x40000864; - - -/*************************************** - Group esp-dsp - ***************************************/ - -/* Data (.data, .bss, .rodata) */ -dsps_fft2r_w_table_fc32_1024 = 0x3fcefff8; - - -/*************************************** - Group opi_flash - ***************************************/ - -/* Functions */ -PROVIDE( opi_flash_set_lock_func = 0x40000870 ); -PROVIDE( esp_rom_spi_cmd_config = 0x4000087c ); -PROVIDE( esp_rom_spi_cmd_start = 0x40000888 ); -PROVIDE( esp_rom_opiflash_pin_config = 0x40000894 ); -PROVIDE( esp_rom_spi_set_op_mode = 0x400008a0 ); -PROVIDE( esp_rom_opiflash_mode_reset = 0x400008ac ); -PROVIDE( esp_rom_opiflash_exec_cmd = 0x400008b8 ); -PROVIDE( esp_rom_opiflash_soft_reset = 0x400008c4 ); -PROVIDE( esp_rom_opiflash_read_id = 0x400008d0 ); -PROVIDE( esp_rom_opiflash_rdsr = 0x400008dc ); -PROVIDE( esp_rom_opiflash_wait_idle = 0x400008e8 ); -PROVIDE( esp_rom_opiflash_wren = 0x400008f4 ); -PROVIDE( esp_rom_opiflash_erase_sector = 0x40000900 ); -PROVIDE( esp_rom_opiflash_erase_block_64k = 0x4000090c ); -PROVIDE( esp_rom_opiflash_erase_area = 0x40000918 ); -PROVIDE( esp_rom_opiflash_read = 0x40000924 ); -PROVIDE( esp_rom_opiflash_write = 0x40000930 ); -PROVIDE( esp_rom_spi_set_dtr_swap_mode = 0x4000093c ); -PROVIDE( esp_rom_opiflash_exit_continuous_read_mode = 0x40000948 ); -PROVIDE( esp_rom_opiflash_legacy_driver_init = 0x40000954 ); -/* Data (.data, .bss, .rodata) */ -PROVIDE( rom_opiflash_cmd_def = 0x3fcefff4 ); -PROVIDE( rom_spi_usr_cmd_legacy_funcs = 0x3fcefff0 ); - - -/*************************************** - Group spiflash_legacy - ***************************************/ - -/* Functions */ -PROVIDE( esp_rom_spiflash_wait_idle = 0x40000960 ); -PROVIDE( esp_rom_spiflash_write_encrypted = 0x4000096c ); -PROVIDE( esp_rom_spiflash_write_encrypted_dest = 0x40000978 ); -PROVIDE( esp_rom_spiflash_write_encrypted_enable = 0x40000984 ); -PROVIDE( esp_rom_spiflash_write_encrypted_disable = 0x40000990 ); -PROVIDE( esp_rom_spiflash_erase_chip = 0x4000099c ); -PROVIDE( _esp_rom_spiflash_erase_sector = 0x400009a8 ); -PROVIDE( _esp_rom_spiflash_erase_block = 0x400009b4 ); -PROVIDE( _esp_rom_spiflash_write = 0x400009c0 ); -PROVIDE( _esp_rom_spiflash_read = 0x400009cc ); -PROVIDE( _esp_rom_spiflash_unlock = 0x400009d8 ); -PROVIDE( _SPIEraseArea = 0x400009e4 ); -PROVIDE( _SPI_write_enable = 0x400009f0 ); -PROVIDE( esp_rom_spiflash_erase_sector = 0x400009fc ); -PROVIDE( esp_rom_spiflash_erase_block = 0x40000a08 ); -PROVIDE( esp_rom_spiflash_write = 0x40000a14 ); -PROVIDE( esp_rom_spiflash_read = 0x40000a20 ); -PROVIDE( esp_rom_spiflash_unlock = 0x40000a2c ); -PROVIDE( SPIEraseArea = 0x40000a38 ); -PROVIDE( SPI_write_enable = 0x40000a44 ); -PROVIDE( esp_rom_spiflash_config_param = 0x40000a50 ); -PROVIDE( esp_rom_spiflash_read_user_cmd = 0x40000a5c ); -PROVIDE( esp_rom_spiflash_select_qio_pins = 0x40000a68 ); -PROVIDE( esp_rom_spi_flash_auto_sus_res = 0x40000a74 ); -PROVIDE( esp_rom_spi_flash_send_resume = 0x40000a80 ); -PROVIDE( esp_rom_spi_flash_update_id = 0x40000a8c ); -PROVIDE( esp_rom_spiflash_config_clk = 0x40000a98 ); -PROVIDE( esp_rom_spiflash_config_readmode = 0x40000aa4 ); -PROVIDE( esp_rom_spiflash_read_status = 0x40000ab0 ); -PROVIDE( esp_rom_spiflash_read_statushigh = 0x40000abc ); -PROVIDE( esp_rom_spiflash_write_status = 0x40000ac8 ); -PROVIDE( esp_rom_opiflash_cache_mode_config = 0x40000ad4 ); -PROVIDE( esp_rom_spiflash_auto_wait_idle = 0x40000ae0 ); -PROVIDE( spi_flash_attach = 0x40000aec ); -PROVIDE( spi_flash_get_chip_size = 0x40000af8 ); -PROVIDE( spi_flash_guard_set = 0x40000b04 ); -PROVIDE( spi_flash_guard_get = 0x40000b10 ); -PROVIDE( spi_flash_write_config_set = 0x40000b1c ); -PROVIDE( spi_flash_write_config_get = 0x40000b28 ); -PROVIDE( spi_flash_safe_write_address_func_set = 0x40000b34 ); -PROVIDE( spi_flash_unlock = 0x40000b40 ); -PROVIDE( spi_flash_erase_range = 0x40000b4c ); -PROVIDE( spi_flash_erase_sector = 0x40000b58 ); -PROVIDE( spi_flash_write = 0x40000b64 ); -PROVIDE( spi_flash_read = 0x40000b70 ); -PROVIDE( spi_flash_write_encrypted = 0x40000b7c ); -PROVIDE( spi_flash_read_encrypted = 0x40000b88 ); -PROVIDE( spi_flash_mmap_os_func_set = 0x40000b94 ); -PROVIDE( spi_flash_mmap_page_num_init = 0x40000ba0 ); -PROVIDE( spi_flash_mmap = 0x40000bac ); -PROVIDE( spi_flash_mmap_pages = 0x40000bb8 ); -PROVIDE( spi_flash_munmap = 0x40000bc4 ); -PROVIDE( spi_flash_mmap_dump = 0x40000bd0 ); -PROVIDE( spi_flash_check_and_flush_cache = 0x40000bdc ); -PROVIDE( spi_flash_mmap_get_free_pages = 0x40000be8 ); -PROVIDE( spi_flash_cache2phys = 0x40000bf4 ); -PROVIDE( spi_flash_phys2cache = 0x40000c00 ); -PROVIDE( spi_flash_disable_cache = 0x40000c0c ); -PROVIDE( spi_flash_restore_cache = 0x40000c18 ); -PROVIDE( spi_flash_cache_enabled = 0x40000c24 ); -PROVIDE( spi_flash_enable_cache = 0x40000c30 ); -PROVIDE( spi_cache_mode_switch = 0x40000c3c ); -PROVIDE( spi_common_set_dummy_output = 0x40000c48 ); -PROVIDE( spi_common_set_flash_cs_timing = 0x40000c54 ); -PROVIDE( esp_rom_spi_set_address_bit_len = 0x40000c60 ); -PROVIDE( esp_enable_cache_flash_wrap = 0x40000c6c ); -PROVIDE( SPILock = 0x40000c78 ); -PROVIDE( SPIMasterReadModeCnfig = 0x40000c84 ); -PROVIDE( SPI_Common_Command = 0x40000c90 ); -PROVIDE( SPI_WakeUp = 0x40000c9c ); -PROVIDE( SPI_block_erase = 0x40000ca8 ); -PROVIDE( SPI_chip_erase = 0x40000cb4 ); -PROVIDE( SPI_init = 0x40000cc0 ); -PROVIDE( SPI_page_program = 0x40000ccc ); -PROVIDE( SPI_read_data = 0x40000cd8 ); -PROVIDE( SPI_sector_erase = 0x40000ce4 ); -PROVIDE( SelectSpiFunction = 0x40000cf0 ); -PROVIDE( SetSpiDrvs = 0x40000cfc ); -PROVIDE( Wait_SPI_Idle = 0x40000d08 ); -PROVIDE( spi_dummy_len_fix = 0x40000d14 ); -PROVIDE( Disable_QMode = 0x40000d20 ); -PROVIDE( Enable_QMode = 0x40000d2c ); -/* Data (.data, .bss, .rodata) */ -PROVIDE( rom_spiflash_legacy_funcs = 0x3fceffe8 ); -PROVIDE( rom_spiflash_legacy_data = 0x3fceffe4 ); -PROVIDE( g_flash_guard_ops = 0x3fceffec ); - - -/*************************************** - Group hal_soc - ***************************************/ - -/* Functions */ -PROVIDE( spi_flash_hal_poll_cmd_done = 0x40000d38 ); -PROVIDE( spi_flash_hal_device_config = 0x40000d44 ); -PROVIDE( spi_flash_hal_configure_host_io_mode = 0x40000d50 ); -PROVIDE( spi_flash_hal_common_command = 0x40000d5c ); -PROVIDE( spi_flash_hal_read = 0x40000d68 ); -PROVIDE( spi_flash_hal_erase_chip = 0x40000d74 ); -PROVIDE( spi_flash_hal_erase_sector = 0x40000d80 ); -PROVIDE( spi_flash_hal_erase_block = 0x40000d8c ); -PROVIDE( spi_flash_hal_program_page = 0x40000d98 ); -PROVIDE( spi_flash_hal_set_write_protect = 0x40000da4 ); -PROVIDE( spi_flash_hal_host_idle = 0x40000db0 ); -PROVIDE( wdt_hal_init = 0x40000dbc ); -PROVIDE( wdt_hal_deinit = 0x40000dc8 ); -PROVIDE( wdt_hal_config_stage = 0x40000dd4 ); -PROVIDE( wdt_hal_write_protect_disable = 0x40000de0 ); -PROVIDE( wdt_hal_write_protect_enable = 0x40000dec ); -PROVIDE( wdt_hal_enable = 0x40000df8 ); -PROVIDE( wdt_hal_disable = 0x40000e04 ); -PROVIDE( wdt_hal_handle_intr = 0x40000e10 ); -PROVIDE( wdt_hal_feed = 0x40000e1c ); -PROVIDE( wdt_hal_set_flashboot_en = 0x40000e28 ); -PROVIDE( wdt_hal_is_enabled = 0x40000e34 ); -PROVIDE( systimer_hal_get_counter_value = 0x40000e40 ); -PROVIDE( systimer_hal_get_time = 0x40000e4c ); -PROVIDE( systimer_hal_set_alarm_target = 0x40000e58 ); -PROVIDE( systimer_hal_set_alarm_period = 0x40000e64 ); -PROVIDE( systimer_hal_get_alarm_value = 0x40000e70 ); -PROVIDE( systimer_hal_enable_alarm_int = 0x40000e7c ); -PROVIDE( systimer_hal_on_apb_freq_update = 0x40000e88 ); -PROVIDE( systimer_hal_counter_value_advance = 0x40000e94 ); -PROVIDE( systimer_hal_enable_counter = 0x40000ea0 ); -PROVIDE( systimer_hal_init = 0x40000eac ); -PROVIDE( systimer_hal_select_alarm_mode = 0x40000eb8 ); -PROVIDE( systimer_hal_connect_alarm_counter = 0x40000ec4 ); - - -/*************************************** - Group spi_flash_chips - ***************************************/ - -/* Functions */ -PROVIDE( spi_flash_chip_generic_probe = 0x40000ed0 ); -PROVIDE( spi_flash_chip_generic_detect_size = 0x40000edc ); -PROVIDE( spi_flash_chip_generic_write = 0x40000ee8 ); -PROVIDE( spi_flash_chip_generic_write_encrypted = 0x40000ef4 ); -PROVIDE( spi_flash_chip_generic_set_write_protect = 0x40000f00 ); -PROVIDE( spi_flash_common_write_status_16b_wrsr = 0x40000f0c ); -PROVIDE( spi_flash_chip_generic_reset = 0x40000f18 ); -PROVIDE( spi_flash_chip_generic_erase_chip = 0x40000f24 ); -PROVIDE( spi_flash_chip_generic_erase_sector = 0x40000f30 ); -PROVIDE( spi_flash_chip_generic_erase_block = 0x40000f3c ); -PROVIDE( spi_flash_chip_generic_page_program = 0x40000f48 ); -PROVIDE( spi_flash_chip_generic_get_write_protect = 0x40000f54 ); -PROVIDE( spi_flash_common_read_status_16b_rdsr_rdsr2 = 0x40000f60 ); -PROVIDE( spi_flash_chip_generic_read_reg = 0x40000f6c ); -PROVIDE( spi_flash_chip_generic_yield = 0x40000f78 ); -PROVIDE( spi_flash_generic_wait_host_idle = 0x40000f84 ); -PROVIDE( spi_flash_chip_generic_wait_idle = 0x40000f90 ); -PROVIDE( spi_flash_chip_generic_config_host_io_mode = 0x40000f9c ); -PROVIDE( spi_flash_chip_generic_read = 0x40000fa8 ); -PROVIDE( spi_flash_common_read_status_8b_rdsr2 = 0x40000fb4 ); -PROVIDE( spi_flash_chip_generic_get_io_mode = 0x40000fc0 ); -PROVIDE( spi_flash_common_read_status_8b_rdsr = 0x40000fcc ); -PROVIDE( spi_flash_common_write_status_8b_wrsr = 0x40000fd8 ); -PROVIDE( spi_flash_common_write_status_8b_wrsr2 = 0x40000fe4 ); -PROVIDE( spi_flash_common_set_io_mode = 0x40000ff0 ); -PROVIDE( spi_flash_chip_generic_set_io_mode = 0x40000ffc ); -PROVIDE( spi_flash_chip_gd_get_io_mode = 0x40001008 ); -PROVIDE( spi_flash_chip_gd_probe = 0x40001014 ); -PROVIDE( spi_flash_chip_gd_set_io_mode = 0x40001020 ); -/* Data (.data, .bss, .rodata) */ -PROVIDE( spi_flash_chip_generic_config_data = 0x3fceffe0 ); - - -/*************************************** - Group memspi_host - ***************************************/ - -/* Functions */ -PROVIDE( memspi_host_read_id_hs = 0x4000102c ); -PROVIDE( memspi_host_read_status_hs = 0x40001038 ); -PROVIDE( memspi_host_flush_cache = 0x40001044 ); -PROVIDE( memspi_host_erase_chip = 0x40001050 ); -PROVIDE( memspi_host_erase_sector = 0x4000105c ); -PROVIDE( memspi_host_erase_block = 0x40001068 ); -PROVIDE( memspi_host_program_page = 0x40001074 ); -PROVIDE( memspi_host_read = 0x40001080 ); -PROVIDE( memspi_host_set_write_protect = 0x4000108c ); -PROVIDE( memspi_host_set_max_read_len = 0x40001098 ); -PROVIDE( memspi_host_read_data_slicer = 0x400010a4 ); -PROVIDE( memspi_host_write_data_slicer = 0x400010b0 ); - - -/*************************************** - Group esp_flash - ***************************************/ - -/* Functions */ -PROVIDE( esp_flash_chip_driver_initialized = 0x400010bc ); -PROVIDE( esp_flash_read_id = 0x400010c8 ); -PROVIDE( esp_flash_get_size = 0x400010d4 ); -PROVIDE( esp_flash_erase_chip = 0x400010e0 ); -PROVIDE( esp_flash_erase_region = 0x400010ec ); -PROVIDE( esp_flash_get_chip_write_protect = 0x400010f8 ); -PROVIDE( esp_flash_set_chip_write_protect = 0x40001104 ); -PROVIDE( esp_flash_get_protectable_regions = 0x40001110 ); -PROVIDE( esp_flash_get_protected_region = 0x4000111c ); -PROVIDE( esp_flash_set_protected_region = 0x40001128 ); -PROVIDE( esp_flash_read = 0x40001134 ); -PROVIDE( esp_flash_write = 0x40001140 ); -PROVIDE( esp_flash_write_encrypted = 0x4000114c ); -PROVIDE( esp_flash_read_encrypted = 0x40001158 ); -PROVIDE( esp_flash_get_io_mode = 0x40001164 ); -PROVIDE( esp_flash_set_io_mode = 0x40001170 ); -PROVIDE( spi_flash_boot_attach = 0x4000117c ); -PROVIDE( spi_flash_dump_counters = 0x40001188 ); -PROVIDE( spi_flash_get_counters = 0x40001194 ); -PROVIDE( spi_flash_op_counters_config = 0x400011a0 ); -PROVIDE( spi_flash_reset_counters = 0x400011ac ); -PROVIDE( esp_flash_read_chip_id = 0x400011b8 ); -PROVIDE( detect_spi_flash_chip = 0x400011c4 ); -PROVIDE( esp_rom_spiflash_write_disable = 0x400011d0 ); -/* Data (.data, .bss, .rodata) */ -PROVIDE( esp_flash_default_chip = 0x3fceffdc ); -PROVIDE( esp_flash_api_funcs = 0x3fceffd8 ); - - -/*************************************** - Group cache - ***************************************/ - -/* Functions */ -PROVIDE( Cache_Get_ICache_Line_Size = 0x400015fc ); -PROVIDE( Cache_Get_DCache_Line_Size = 0x40001608 ); -PROVIDE( Cache_Get_Mode = 0x40001614 ); -PROVIDE( Cache_Set_ICache_Mode = 0x40001620 ); -PROVIDE( Cache_Set_DCache_Mode = 0x4000162c ); -PROVIDE( Cache_Address_Through_ICache = 0x40001638 ); -PROVIDE( Cache_Address_Through_DCache = 0x40001644 ); -PROVIDE( Cache_Set_Default_Mode = 0x40001650 ); -PROVIDE( Cache_Enable_Defalut_ICache_Mode = 0x4000165c ); -PROVIDE( ROM_Boot_Cache_Init = 0x40001668 ); -PROVIDE( Cache_Invalidate_ICache_Items = 0x40001674 ); -PROVIDE( Cache_Invalidate_DCache_Items = 0x40001680 ); -PROVIDE( Cache_Clean_Items = 0x4000168c ); -PROVIDE( Cache_WriteBack_Items = 0x40001698 ); -PROVIDE( Cache_Op_Addr = 0x400016a4 ); -PROVIDE( Cache_Invalidate_Addr = 0x400016b0 ); -PROVIDE( Cache_Clean_Addr = 0x400016bc ); -PROVIDE( Cache_WriteBack_Addr = 0x400016c8 ); -PROVIDE( Cache_Invalidate_ICache_All = 0x400016d4 ); -PROVIDE( Cache_Invalidate_DCache_All = 0x400016e0 ); -PROVIDE( Cache_Clean_All = 0x400016ec ); -PROVIDE( Cache_WriteBack_All = 0x400016f8 ); -PROVIDE( Cache_Mask_All = 0x40001704 ); -PROVIDE( Cache_UnMask_Dram0 = 0x40001710 ); -PROVIDE( Cache_Suspend_ICache_Autoload = 0x4000171c ); -PROVIDE( Cache_Resume_ICache_Autoload = 0x40001728 ); -PROVIDE( Cache_Suspend_DCache_Autoload = 0x40001734 ); -PROVIDE( Cache_Resume_DCache_Autoload = 0x40001740 ); -PROVIDE( Cache_Start_ICache_Preload = 0x4000174c ); -PROVIDE( Cache_ICache_Preload_Done = 0x40001758 ); -PROVIDE( Cache_End_ICache_Preload = 0x40001764 ); -PROVIDE( Cache_Start_DCache_Preload = 0x40001770 ); -PROVIDE( Cache_DCache_Preload_Done = 0x4000177c ); -PROVIDE( Cache_End_DCache_Preload = 0x40001788 ); -PROVIDE( Cache_Config_ICache_Autoload = 0x40001794 ); -PROVIDE( Cache_Config_ICache_Region_Autoload = 0x400017a0 ); -PROVIDE( Cache_Enable_ICache_Autoload = 0x400017ac ); -PROVIDE( Cache_Disable_ICache_Autoload = 0x400017b8 ); -PROVIDE( Cache_Config_DCache_Autoload = 0x400017c4 ); -PROVIDE( Cache_Config_DCache_Region_Autoload = 0x400017d0 ); -PROVIDE( Cache_Enable_DCache_Autoload = 0x400017dc ); -PROVIDE( Cache_Disable_DCache_Autoload = 0x400017e8 ); -PROVIDE( Cache_Enable_ICache_PreLock = 0x400017f4 ); -PROVIDE( Cache_Disable_ICache_PreLock = 0x40001800 ); -PROVIDE( Cache_Lock_ICache_Items = 0x4000180c ); -PROVIDE( Cache_Unlock_ICache_Items = 0x40001818 ); -PROVIDE( Cache_Enable_DCache_PreLock = 0x40001824 ); -PROVIDE( Cache_Disable_DCache_PreLock = 0x40001830 ); -PROVIDE( Cache_Lock_DCache_Items = 0x4000183c ); -PROVIDE( Cache_Unlock_DCache_Items = 0x40001848 ); -PROVIDE( Cache_Lock_Addr = 0x40001854 ); -PROVIDE( Cache_Unlock_Addr = 0x40001860 ); -PROVIDE( Cache_Disable_ICache = 0x4000186c ); -PROVIDE( Cache_Enable_ICache = 0x40001878 ); -PROVIDE( Cache_Disable_DCache = 0x40001884 ); -PROVIDE( Cache_Enable_DCache = 0x40001890 ); -PROVIDE( Cache_Suspend_ICache = 0x4000189c ); -PROVIDE( Cache_Resume_ICache = 0x400018a8 ); -PROVIDE( Cache_Suspend_DCache = 0x400018b4 ); -PROVIDE( Cache_Resume_DCache = 0x400018c0 ); -PROVIDE( Cache_Occupy_Items = 0x400018cc ); -PROVIDE( Cache_Occupy_Addr = 0x400018d8 ); -PROVIDE( Cache_Freeze_ICache_Enable = 0x400018e4 ); -PROVIDE( Cache_Freeze_ICache_Disable = 0x400018f0 ); -PROVIDE( Cache_Freeze_DCache_Enable = 0x400018fc ); -PROVIDE( Cache_Freeze_DCache_Disable = 0x40001908 ); -PROVIDE( Cache_Set_IDROM_MMU_Size = 0x40001914 ); -PROVIDE( flash2spiram_instruction_offset = 0x40001920 ); -PROVIDE( flash2spiram_rodata_offset = 0x4000192c ); -PROVIDE( flash_instr_rodata_start_page = 0x40001938 ); -PROVIDE( flash_instr_rodata_end_page = 0x40001944 ); -PROVIDE( Cache_Set_IDROM_MMU_Info = 0x40001950 ); -PROVIDE( Cache_Get_IROM_MMU_End = 0x4000195c ); -PROVIDE( Cache_Get_DROM_MMU_End = 0x40001968 ); -PROVIDE( Cache_Owner_Init = 0x40001974 ); -PROVIDE( Cache_Occupy_ICache_MEMORY = 0x40001980 ); -PROVIDE( Cache_Occupy_DCache_MEMORY = 0x4000198c ); -PROVIDE( Cache_MMU_Init = 0x40001998 ); -PROVIDE( Cache_Ibus_MMU_Set = 0x400019a4 ); -PROVIDE( Cache_Dbus_MMU_Set = 0x400019b0 ); -PROVIDE( Cache_Count_Flash_Pages = 0x400019bc ); -PROVIDE( Cache_Flash_To_SPIRAM_Copy = 0x400019c8 ); -PROVIDE( Cache_Travel_Tag_Memory = 0x400019d4 ); -PROVIDE( Cache_Travel_Tag_Memory2 = 0x400019e0 ); -PROVIDE( Cache_Get_Virtual_Addr = 0x400019ec ); -PROVIDE( Cache_Get_Memory_BaseAddr = 0x400019f8 ); -PROVIDE( Cache_Get_Memory_Addr = 0x40001a04 ); -PROVIDE( Cache_Get_Memory_value = 0x40001a10 ); -PROVIDE( rom_config_instruction_cache_mode = 0x40001a1c ); -PROVIDE( rom_config_data_cache_mode = 0x40001a28 ); -/* Data (.data, .bss, .rodata) */ -PROVIDE( rom_cache_op_cb = 0x3fceffc8 ); -PROVIDE( rom_cache_internal_table_ptr = 0x3fceffc4 ); - - -/*************************************** - Group clock - ***************************************/ - -/* Functions */ -ets_get_apb_freq = 0x40001a34; -ets_get_cpu_frequency = 0x40001a40; -ets_update_cpu_frequency = 0x40001a4c; -ets_get_printf_channel = 0x40001a58; -ets_get_xtal_div = 0x40001a64; -ets_set_xtal_div = 0x40001a70; -ets_get_xtal_freq = 0x40001a7c; - - -/*************************************** - Group gpio - ***************************************/ - -/* Functions */ -gpio_input_get = 0x40001a88; -gpio_matrix_in = 0x40001a94; -gpio_matrix_out = 0x40001aa0; -gpio_output_disable = 0x40001aac; -gpio_output_enable = 0x40001ab8; -gpio_output_set = 0x40001ac4; -gpio_pad_hold = 0x40001ad0; -gpio_pad_input_disable = 0x40001adc; -gpio_pad_input_enable = 0x40001ae8; -gpio_pad_pulldown = 0x40001af4; -gpio_pad_pullup = 0x40001b00; -gpio_pad_select_gpio = 0x40001b0c; -gpio_pad_set_drv = 0x40001b18; -gpio_pad_unhold = 0x40001b24; -gpio_pin_wakeup_disable = 0x40001b30; -gpio_pin_wakeup_enable = 0x40001b3c; -gpio_bypass_matrix_in = 0x40001b48; - - -/*************************************** - Group interrupts - ***************************************/ - -/* Functions */ -intr_matrix_set = 0x40001b54; -ets_intr_lock = 0x40001b60; -ets_intr_unlock = 0x40001b6c; -ets_isr_attach = 0x40001b78; -ets_isr_mask = 0x40001b84; -ets_isr_unmask = 0x40001b90; - - -/*************************************** - Group xtos - ***************************************/ - -/* Functions */ -xthal_bcopy = 0x40001b9c; -xthal_memcpy = 0x40001ba8; -xthal_get_ccompare = 0x40001bb4; -xthal_set_ccompare = 0x40001bc0; -xthal_get_ccount = 0x40001bcc; -xthal_get_interrupt = 0x40001bd8; -xthal_set_intclear = 0x40001be4; -_xtos_ints_off = 0x40001bf0; -_xtos_ints_on = 0x40001bfc; -_xtos_restore_intlevel = 0x40001c08; -_xtos_set_exception_handler = 0x40001c14; -_xtos_set_interrupt_handler = 0x40001c20; -_xtos_set_interrupt_handler_arg = 0x40001c2c; -_xtos_set_intlevel = 0x40001c38; -_xtos_set_vpri = 0x40001c44; - - -/*************************************** - Group crypto - ***************************************/ - -/* Functions */ -md5_vector = 0x40001c50; -MD5Init = 0x40001c5c; -MD5Update = 0x40001c68; -MD5Final = 0x40001c74; -hmac_md5_vector = 0x40001c80; -hmac_md5 = 0x40001c8c; -crc32_le = 0x40001c98; -crc32_be = 0x40001ca4; -crc16_le = 0x40001cb0; -crc16_be = 0x40001cbc; -crc8_le = 0x40001cc8; -crc8_be = 0x40001cd4; -esp_crc8 = 0x40001ce0; -ets_sha_enable = 0x40001cec; -ets_sha_disable = 0x40001cf8; -ets_sha_get_state = 0x40001d04; -ets_sha_init = 0x40001d10; -ets_sha_process = 0x40001d1c; -ets_sha_starts = 0x40001d28; -ets_sha_update = 0x40001d34; -ets_sha_finish = 0x40001d40; -ets_sha_clone = 0x40001d4c; -ets_hmac_enable = 0x40001d58; -ets_hmac_disable = 0x40001d64; -ets_hmac_calculate_message = 0x40001d70; -ets_hmac_calculate_downstream = 0x40001d7c; -ets_hmac_invalidate_downstream = 0x40001d88; -ets_jtag_enable_temporarily = 0x40001d94; -ets_aes_enable = 0x40001da0; -ets_aes_disable = 0x40001dac; -ets_aes_setkey = 0x40001db8; -ets_aes_block = 0x40001dc4; -ets_bigint_enable = 0x40001dd0; -ets_bigint_disable = 0x40001ddc; -ets_bigint_multiply = 0x40001de8; -ets_bigint_modmult = 0x40001df4; -ets_bigint_modexp = 0x40001e00; -ets_bigint_wait_finish = 0x40001e0c; -ets_bigint_getz = 0x40001e18; -ets_ds_enable = 0x40001e24; -ets_ds_disable = 0x40001e30; -ets_ds_start_sign = 0x40001e3c; -ets_ds_is_busy = 0x40001e48; -ets_ds_finish_sign = 0x40001e54; -ets_ds_encrypt_params = 0x40001e60; -ets_aes_setkey_dec = 0x40001e6c; -ets_aes_setkey_enc = 0x40001e78; -ets_mgf1_sha256 = 0x40001e84; - - -/*************************************** - Group efuse - ***************************************/ - -/* Functions */ -ets_efuse_read = 0x40001e90; -ets_efuse_program = 0x40001e9c; -ets_efuse_clear_program_registers = 0x40001ea8; -ets_efuse_write_key = 0x40001eb4; -ets_efuse_get_read_register_address = 0x40001ec0; -ets_efuse_get_key_purpose = 0x40001ecc; -ets_efuse_key_block_unused = 0x40001ed8; -ets_efuse_find_unused_key_block = 0x40001ee4; -ets_efuse_rs_calculate = 0x40001ef0; -ets_efuse_count_unused_key_blocks = 0x40001efc; -ets_efuse_secure_boot_enabled = 0x40001f08; -ets_efuse_secure_boot_aggressive_revoke_enabled = 0x40001f14; -ets_efuse_cache_encryption_enabled = 0x40001f20; -ets_efuse_download_modes_disabled = 0x40001f2c; -ets_efuse_find_purpose = 0x40001f38; -ets_efuse_flash_opi_5pads_power_sel_vddspi = 0x40001f44; -ets_efuse_force_send_resume = 0x40001f50; -ets_efuse_get_flash_delay_us = 0x40001f5c; -ets_efuse_get_mac = 0x40001f68; -ets_efuse_get_spiconfig = 0x40001f74; -ets_efuse_usb_print_is_disabled = 0x40001f80; -ets_efuse_get_uart_print_channel = 0x40001f8c; -ets_efuse_get_uart_print_control = 0x40001f98; -ets_efuse_get_wp_pad = 0x40001fa4; -ets_efuse_legacy_spi_boot_mode_disabled = 0x40001fb0; -ets_efuse_security_download_modes_enabled = 0x40001fbc; -ets_efuse_set_timing = 0x40001fc8; -ets_efuse_jtag_disabled = 0x40001fd4; -ets_efuse_usb_download_mode_disabled = 0x40001fe0; -ets_efuse_usb_module_disabled = 0x40001fec; -ets_efuse_usb_device_disabled = 0x40001ff8; -ets_efuse_flash_octal_mode = 0x40002004; -ets_efuse_ecc_en = 0x40002010; -ets_efuse_ecc_flash_page_size = 0x4000201c; -ets_efuse_ecc_16to17_mode = 0x40002028; - - -/*************************************** - Group ecc - ***************************************/ - -/* Functions */ -ets_ecc_flash_enable = 0x40002034; -ets_ecc_flash_enable_all = 0x40002040; -ets_ecc_flash_disable = 0x4000204c; -ets_ecc_flash_disable_all = 0x40002058; -ets_ecc_get_flash_page_size = 0x40002064; -ets_ecc_set_flash_page_size = 0x40002070; -ets_ecc_set_flash_byte_mode = 0x4000207c; -ets_ecc_get_flash_byte_mode = 0x40002088; -ets_ecc_set_flash_range = 0x40002094; -ets_ecc_get_flash_range = 0x400020a0; -ets_ecc_sram_enable = 0x400020ac; -ets_ecc_sram_disable = 0x400020b8; -ets_ecc_sram_enable_all = 0x400020c4; -ets_ecc_sram_disable_all = 0x400020d0; -ets_ecc_get_sram_page_size = 0x400020dc; -ets_ecc_set_sram_page_size = 0x400020e8; -ets_ecc_get_sram_byte_mode = 0x400020f4; -ets_ecc_set_sram_byte_mode = 0x40002100; -ets_ecc_set_sram_range = 0x4000210c; -ets_ecc_get_sram_range = 0x40002118; -/* Data (.data, .bss, .rodata) */ -ets_ecc_table_ptr = 0x3fceffc0; - - -/*************************************** - Group secureboot - ***************************************/ - -/* Functions */ -ets_emsa_pss_verify = 0x40002124; -ets_rsa_pss_verify = 0x40002130; -ets_secure_boot_verify_bootloader_with_keys = 0x4000213c; -ets_secure_boot_verify_signature = 0x40002148; -ets_secure_boot_read_key_digests = 0x40002154; -ets_secure_boot_revoke_public_key_digest = 0x40002160; - - -/*************************************** - Group usb_uart - ***************************************/ - -/* Functions */ -PROVIDE( usb_uart_otg_rx_one_char = 0x400025a4 ); -PROVIDE( usb_uart_otg_rx_one_char_block = 0x400025b0 ); -PROVIDE( usb_uart_otg_tx_flush = 0x400025bc ); -PROVIDE( usb_uart_otg_tx_one_char = 0x400025c8 ); -PROVIDE( usb_uart_device_rx_one_char = 0x400025d4 ); -PROVIDE( usb_uart_device_rx_one_char_block = 0x400025e0 ); -PROVIDE( usb_uart_device_tx_flush = 0x400025ec ); -PROVIDE( usb_uart_device_tx_one_char = 0x400025f8 ); -PROVIDE( Uart_Init_USB = 0x40002604 ); -/* Data (.data, .bss, .rodata) */ -PROVIDE( uart_acm_dev = 0x3fceffbc ); -PROVIDE( g_uart_print = 0x3fceffb9 ); -PROVIDE( g_usb_print = 0x3fceffb8 ); - - -/*************************************** - Group usb_module - ***************************************/ - -/* Functions */ -cdc_acm_class_handle_req = 0x40002610; -cdc_acm_init = 0x4000261c; -cdc_acm_fifo_fill = 0x40002628; -cdc_acm_rx_fifo_cnt = 0x40002634; -cdc_acm_fifo_read = 0x40002640; -cdc_acm_irq_tx_enable = 0x4000264c; -cdc_acm_irq_tx_disable = 0x40002658; -cdc_acm_irq_state_enable = 0x40002664; -cdc_acm_irq_state_disable = 0x40002670; -cdc_acm_irq_tx_ready = 0x4000267c; -cdc_acm_irq_rx_enable = 0x40002688; -cdc_acm_irq_rx_disable = 0x40002694; -cdc_acm_irq_rx_ready = 0x400026a0; -cdc_acm_irq_is_pending = 0x400026ac; -cdc_acm_irq_callback_set = 0x400026b8; -cdc_acm_line_ctrl_set = 0x400026c4; -cdc_acm_line_ctrl_get = 0x400026d0; -cdc_acm_poll_out = 0x400026dc; -chip_usb_dw_did_persist = 0x400026e8; -chip_usb_dw_init = 0x400026f4; -chip_usb_detach = 0x40002700; -chip_usb_dw_prepare_persist = 0x4000270c; -chip_usb_get_persist_flags = 0x40002718; -chip_usb_set_persist_flags = 0x40002724; -cpio_start = 0x40002730; -cpio_feed = 0x4000273c; -cpio_done = 0x40002748; -cpio_destroy = 0x40002754; -dfu_flash_init = 0x40002760; -dfu_flash_erase = 0x4000276c; -dfu_flash_program = 0x40002778; -dfu_flash_read = 0x40002784; -dfu_flash_attach = 0x40002790; -dfu_cpio_callback = 0x4000279c; -dfu_updater_get_err = 0x400027a8; -dfu_updater_clear_err = 0x400027b4; -dfu_updater_enable = 0x400027c0; -dfu_updater_begin = 0x400027cc; -dfu_updater_feed = 0x400027d8; -dfu_updater_end = 0x400027e4; -dfu_updater_set_raw_addr = 0x400027f0; -dfu_updater_flash_read = 0x400027fc; -usb_dc_prepare_persist = 0x40002808; -usb_dw_isr_handler = 0x40002814; -usb_dc_attach = 0x40002820; -usb_dc_detach = 0x4000282c; -usb_dc_reset = 0x40002838; -usb_dc_set_address = 0x40002844; -usb_dc_ep_check_cap = 0x40002850; -usb_dc_ep_configure = 0x4000285c; -usb_dc_ep_set_stall = 0x40002868; -usb_dc_ep_clear_stall = 0x40002874; -usb_dc_ep_halt = 0x40002880; -usb_dc_ep_is_stalled = 0x4000288c; -usb_dc_ep_enable = 0x40002898; -usb_dc_ep_disable = 0x400028a4; -usb_dc_ep_flush = 0x400028b0; -usb_dc_ep_write_would_block = 0x400028bc; -usb_dc_ep_write = 0x400028c8; -usb_dc_ep_read_wait = 0x400028d4; -usb_dc_ep_read_continue = 0x400028e0; -usb_dc_ep_read = 0x400028ec; -usb_dc_ep_set_callback = 0x400028f8; -usb_dc_set_status_callback = 0x40002904; -usb_dc_ep_mps = 0x40002910; -usb_dc_check_poll_for_interrupts = 0x4000291c; -mac_addr_to_serial_str_desc = 0x40002928; -usb_set_current_descriptor = 0x40002934; -usb_get_descriptor = 0x40002940; -usb_dev_resume = 0x4000294c; -usb_dev_get_configuration = 0x40002958; -usb_set_config = 0x40002964; -usb_deconfig = 0x40002970; -usb_enable = 0x4000297c; -usb_disable = 0x40002988; -usb_write_would_block = 0x40002994; -usb_write = 0x400029a0; -usb_read = 0x400029ac; -usb_ep_set_stall = 0x400029b8; -usb_ep_clear_stall = 0x400029c4; -usb_ep_read_wait = 0x400029d0; -usb_ep_read_continue = 0x400029dc; -usb_transfer_ep_callback = 0x400029e8; -usb_transfer = 0x400029f4; -usb_cancel_transfer = 0x40002a00; -usb_transfer_sync = 0x40002a0c; -usb_dfu_set_detach_cb = 0x40002a18; -dfu_class_handle_req = 0x40002a24; -dfu_status_cb = 0x40002a30; -dfu_custom_handle_req = 0x40002a3c; -usb_dfu_init = 0x40002a48; -usb_dfu_force_detach = 0x40002a54; -usb_dev_deinit = 0x40002a60; -usb_dw_ctrl_deinit = 0x40002a6c; -/* Data (.data, .bss, .rodata) */ -s_usb_osglue = 0x3fceffac; - - -/*************************************** - Group bluetooth - ***************************************/ - -/* Functions */ -bt_rf_coex_get_dft_cfg = 0x40002a78; -bt_rf_coex_hooks_p_set = 0x40002a84; -btdm_con_maxevtime_cal_impl = 0x40002a90; -btdm_controller_get_compile_version_impl = 0x40002a9c; -btdm_controller_rom_data_init = 0x40002aa8; -btdm_dis_privacy_err_report_impl = 0x40002ab4; -btdm_disable_adv_delay_impl = 0x40002ac0; -btdm_enable_scan_continue_impl = 0x40002acc; -btdm_enable_scan_forever_impl = 0x40002ad8; -btdm_get_power_state_impl = 0x40002ae4; -btdm_get_prevent_sleep_flag_impl = 0x40002af0; -btdm_power_state_active_impl = 0x40002afc; -btdm_switch_phy_coded_impl = 0x40002b08; -hci_acl_data_handler = 0x40002b14; -hci_disconnect_cmd_handler = 0x40002b20; -hci_le_con_upd_cmd_handler = 0x40002b2c; -hci_le_ltk_req_neg_reply_cmd_handler = 0x40002b38; -hci_le_ltk_req_reply_cmd_handler = 0x40002b44; -hci_le_rd_chnl_map_cmd_handler = 0x40002b50; -hci_le_rd_phy_cmd_handler = 0x40002b5c; -hci_le_rd_rem_feats_cmd_handler = 0x40002b68; -hci_le_rem_con_param_req_neg_reply_cmd_handler = 0x40002b74; -hci_le_rem_con_param_req_reply_cmd_handler = 0x40002b80; -hci_le_set_data_len_cmd_handler = 0x40002b8c; -hci_le_set_phy_cmd_handler = 0x40002b98; -hci_le_start_enc_cmd_handler = 0x40002ba4; -hci_rd_auth_payl_to_cmd_handler = 0x40002bb0; -hci_rd_rem_ver_info_cmd_handler = 0x40002bbc; -hci_rd_rssi_cmd_handler = 0x40002bc8; -hci_rd_tx_pwr_lvl_cmd_handler = 0x40002bd4; -hci_vs_set_pref_slave_evt_dur_cmd_handler = 0x40002be0; -hci_vs_set_pref_slave_latency_cmd_handler = 0x40002bec; -hci_wr_auth_payl_to_cmd_handler = 0x40002bf8; -ll_channel_map_ind_handler = 0x40002c04; -ll_connection_param_req_handler = 0x40002c10; -ll_connection_param_rsp_handler = 0x40002c1c; -ll_connection_update_ind_handler = 0x40002c28; -ll_enc_req_handler = 0x40002c34; -ll_enc_rsp_handler = 0x40002c40; -ll_feature_req_handler = 0x40002c4c; -ll_feature_rsp_handler = 0x40002c58; -ll_length_req_handler = 0x40002c64; -ll_length_rsp_handler = 0x40002c70; -ll_min_used_channels_ind_handler = 0x40002c7c; -ll_pause_enc_req_handler = 0x40002c88; -ll_pause_enc_rsp_handler = 0x40002c94; -ll_phy_req_handler = 0x40002ca0; -ll_phy_rsp_handler = 0x40002cac; -ll_phy_update_ind_handler = 0x40002cb8; -ll_ping_req_handler = 0x40002cc4; -ll_ping_rsp_handler = 0x40002cd0; -ll_slave_feature_req_handler = 0x40002cdc; -ll_start_enc_req_handler = 0x40002ce8; -ll_start_enc_rsp_handler = 0x40002cf4; -ll_terminate_ind_handler = 0x40002d00; -ll_version_ind_handler = 0x40002d0c; -llc_auth_payl_nearly_to_handler = 0x40002d18; -llc_auth_payl_real_to_handler = 0x40002d24; -llc_encrypt_ind_handler = 0x40002d30; -llc_hci_command_handler_wrapper = 0x40002d3c; -llc_ll_connection_param_req_pdu_send = 0x40002d48; -llc_ll_connection_param_rsp_pdu_send = 0x40002d54; -llc_ll_connection_update_ind_pdu_send = 0x40002d60; -llc_ll_enc_req_pdu_send = 0x40002d6c; -llc_ll_enc_rsp_pdu_send = 0x40002d78; -llc_ll_feature_req_pdu_send = 0x40002d84; -llc_ll_feature_rsp_pdu_send = 0x40002d90; -llc_ll_length_req_pdu_send = 0x40002d9c; -llc_ll_length_rsp_pdu_send = 0x40002da8; -llc_ll_pause_enc_req_pdu_send = 0x40002db4; -llc_ll_pause_enc_rsp_pdu_send = 0x40002dc0; -llc_ll_phy_req_pdu_send = 0x40002dcc; -llc_ll_phy_rsp_pdu_send = 0x40002dd8; -llc_ll_ping_req_pdu_send = 0x40002de4; -llc_ll_ping_rsp_pdu_send = 0x40002df0; -llc_ll_start_enc_req_pdu_send = 0x40002dfc; -llc_ll_start_enc_rsp_pdu_send = 0x40002e08; -llc_ll_terminate_ind_pdu_send = 0x40002e14; -llc_ll_unknown_rsp_pdu_send = 0x40002e20; -llc_llcp_ch_map_update_ind_pdu_send = 0x40002e2c; -llc_llcp_phy_upd_ind_pdu_send = 0x40002e38; -llc_llcp_version_ind_pdu_send = 0x40002e44; -llc_op_ch_map_upd_ind_handler = 0x40002e50; -llc_op_con_upd_ind_handler = 0x40002e5c; -llc_op_disconnect_ind_handler = 0x40002e68; -llc_op_dl_upd_ind_handler = 0x40002e74; -llc_op_encrypt_ind_handler = 0x40002e80; -llc_op_feats_exch_ind_handler = 0x40002e8c; -llc_op_le_ping_ind_handler = 0x40002e98; -llc_op_phy_upd_ind_handler = 0x40002ea4; -llc_op_ver_exch_ind_handler = 0x40002eb0; -llc_stopped_ind_handler = 0x40002ebc; -lld_acl_rx_ind_handler = 0x40002ec8; -lld_acl_tx_cfm_handler = 0x40002ed4; -lld_adv_end_ind_handler = 0x40002ee0; -lld_adv_rep_ind_handler = 0x40002eec; -lld_ch_map_upd_cfm_handler = 0x40002ef8; -lld_con_estab_ind_handler = 0x40002f04; -lld_con_evt_sd_evt_time_set = 0x40002f10; -lld_con_offset_upd_ind_handler = 0x40002f1c; -lld_con_param_upd_cfm_handler = 0x40002f28; -lld_disc_ind_handler = 0x40002f34; -lld_init_end_ind_handler = 0x40002f40; -lld_llcp_rx_ind_handler_wrapper = 0x40002f4c; -lld_llcp_tx_cfm_handler = 0x40002f58; -lld_per_adv_end_ind_handler = 0x40002f64; -lld_per_adv_rep_ind_handler = 0x40002f70; -lld_per_adv_rx_end_ind_handler = 0x40002f7c; -lld_phy_coded_500k_get = 0x40002f88; -lld_phy_upd_cfm_handler = 0x40002f94; -lld_scan_end_ind_handler = 0x40002fa0; -lld_scan_req_ind_handler = 0x40002fac; -lld_sync_start_req_handler = 0x40002fb8; -lld_test_end_ind_handler = 0x40002fc4; -lld_update_rxbuf_handler = 0x40002fd0; -llm_ch_map_update_ind_handler = 0x40002fdc; -llm_hci_command_handler_wrapper = 0x40002fe8; -llm_scan_period_to_handler = 0x40002ff4; -r_Add2SelfBigHex256 = 0x40003000; -r_AddBigHex256 = 0x4000300c; -r_AddBigHexModP256 = 0x40003018; -r_AddP256 = 0x40003024; -r_AddPdiv2_256 = 0x40003030; -r_GF_Jacobian_Point_Addition256 = 0x4000303c; -r_GF_Jacobian_Point_Double256 = 0x40003048; -r_GF_Point_Jacobian_To_Affine256 = 0x40003054; -r_MultiplyBigHexByUint32_256 = 0x40003060; -r_MultiplyBigHexModP256 = 0x4000306c; -r_MultiplyByU16ModP256 = 0x40003078; -r_SubtractBigHex256 = 0x40003084; -r_SubtractBigHexMod256 = 0x40003090; -r_SubtractBigHexUint32_256 = 0x4000309c; -r_SubtractFromSelfBigHex256 = 0x400030a8; -r_SubtractFromSelfBigHexSign256 = 0x400030b4; -r_aes_alloc = 0x400030c0; -r_aes_ccm_continue = 0x400030cc; -r_aes_ccm_process_e = 0x400030d8; -r_aes_ccm_xor_128_lsb = 0x400030e4; -r_aes_ccm_xor_128_msb = 0x400030f0; -r_aes_cmac_continue = 0x400030fc; -r_aes_cmac_start = 0x40003108; -r_aes_k1_continue = 0x40003114; -r_aes_k2_continue = 0x40003120; -r_aes_k3_continue = 0x4000312c; -r_aes_k4_continue = 0x40003138; -r_aes_shift_left_128 = 0x40003144; -r_aes_start = 0x40003150; -r_aes_xor_128 = 0x4000315c; -r_assert_err = 0x40003168; -r_assert_param = 0x40003174; -r_assert_warn = 0x40003180; -r_bigHexInversion256 = 0x4000318c; -r_ble_sw_cca_check_isr = 0x40003198; -r_ble_util_buf_acl_tx_alloc = 0x400031a4; -r_ble_util_buf_acl_tx_elt_get = 0x400031b0; -r_ble_util_buf_acl_tx_free = 0x400031bc; -r_ble_util_buf_acl_tx_free_in_isr = 0x400031c8; -r_ble_util_buf_adv_tx_alloc = 0x400031d4; -r_ble_util_buf_adv_tx_free = 0x400031e0; -r_ble_util_buf_adv_tx_free_in_isr = 0x400031ec; -r_ble_util_buf_env_deinit = 0x400031f8; -r_ble_util_buf_env_init = 0x40003204; -r_ble_util_buf_get_rx_buf_nb = 0x40003210; -r_ble_util_buf_get_rx_buf_size = 0x4000321c; -r_ble_util_buf_llcp_tx_alloc = 0x40003228; -r_ble_util_buf_llcp_tx_free = 0x40003234; -r_ble_util_buf_rx_alloc = 0x40003240; -r_ble_util_buf_rx_alloc_in_isr = 0x4000324c; -r_ble_util_buf_rx_free = 0x40003258; -r_ble_util_buf_rx_free_in_isr = 0x40003264; -r_ble_util_buf_set_rx_buf_nb = 0x40003270; -r_ble_util_buf_set_rx_buf_size = 0x4000327c; -r_ble_util_data_rx_buf_reset = 0x40003288; -r_bt_bb_get_intr_mask = 0x40003294; -r_bt_bb_intr_clear = 0x400032a0; -r_bt_bb_intr_mask_set = 0x400032ac; -r_bt_bb_isr = 0x400032b8; -r_bt_rf_coex_cfg_set = 0x400032c4; -r_bt_rf_coex_conn_dynamic_pti_en_get = 0x400032d0; -r_bt_rf_coex_conn_phy_coded_data_time_limit_en_get = 0x400032dc; -r_bt_rf_coex_ext_adv_dynamic_pti_en_get = 0x400032e8; -r_bt_rf_coex_ext_scan_dynamic_pti_en_get = 0x400032f4; -r_bt_rf_coex_legacy_adv_dynamic_pti_en_get = 0x40003300; -r_bt_rf_coex_per_adv_dynamic_pti_en_get = 0x4000330c; -r_bt_rf_coex_pti_table_get = 0x40003318; -r_bt_rf_coex_st_param_get = 0x40003324; -r_bt_rf_coex_st_param_set = 0x40003330; -r_bt_rf_coex_sync_scan_dynamic_pti_en_get = 0x4000333c; -r_bt_rma_apply_rule_cs_fmt = 0x40003348; -r_bt_rma_apply_rule_cs_idx = 0x40003354; -r_bt_rma_configure = 0x40003360; -r_bt_rma_deregister_rule_cs_fmt = 0x4000336c; -r_bt_rma_deregister_rule_cs_idx = 0x40003378; -r_bt_rma_get_ant_by_act = 0x40003384; -r_bt_rma_init = 0x40003390; -r_bt_rma_register_rule_cs_fmt = 0x4000339c; -r_bt_rma_register_rule_cs_idx = 0x400033a8; -r_bt_rtp_apply_rule_cs_fmt = 0x400033b4; -r_bt_rtp_apply_rule_cs_idx = 0x400033c0; -r_bt_rtp_deregister_rule_cs_fmt = 0x400033cc; -r_bt_rtp_deregister_rule_cs_idx = 0x400033d8; -r_bt_rtp_get_txpwr_idx_by_act = 0x400033e4; -r_bt_rtp_init = 0x400033f0; -r_bt_rtp_register_rule_cs_fmt = 0x400033fc; -r_bt_rtp_register_rule_cs_idx = 0x40003408; -r_btdm_isr = 0x40003414; -r_btdm_task_post = 0x40003420; -r_btdm_task_post_from_isr = 0x4000342c; -r_btdm_task_recycle = 0x40003438; -r_cali_phase_match_p = 0x40003444; -r_cmp_abs_time = 0x40003450; -r_cmp_dest_id = 0x4000345c; -r_cmp_timer_id = 0x40003468; -r_co_bdaddr_compare = 0x40003474; -r_co_ble_pkt_dur_in_us = 0x40003480; -r_co_list_extract = 0x4000348c; -r_co_list_extract_after = 0x40003498; -r_co_list_extract_sublist = 0x400034a4; -r_co_list_find = 0x400034b0; -r_co_list_init = 0x400034bc; -r_co_list_insert_after = 0x400034c8; -r_co_list_insert_before = 0x400034d4; -r_co_list_merge = 0x400034e0; -r_co_list_pool_init = 0x400034ec; -r_co_list_pop_front = 0x400034f8; -r_co_list_push_back = 0x40003504; -r_co_list_push_back_sublist = 0x40003510; -r_co_list_push_front = 0x4000351c; -r_co_list_size = 0x40003528; -r_co_nb_good_le_channels = 0x40003534; -r_co_util_pack = 0x40003540; -r_co_util_read_array_size = 0x4000354c; -r_co_util_unpack = 0x40003558; -r_dbg_env_deinit = 0x40003564; -r_dbg_env_init = 0x40003570; -r_dbg_platform_reset_complete = 0x4000357c; -r_dl_upd_proc_start = 0x40003588; -r_dump_data = 0x40003594; -r_ecc_abort_key256_generation = 0x400035a0; -r_ecc_gen_new_public_key = 0x400035ac; -r_ecc_gen_new_secret_key = 0x400035b8; -r_ecc_generate_key256 = 0x400035c4; -r_ecc_get_debug_Keys = 0x400035d0; -r_ecc_init = 0x400035dc; -r_ecc_is_valid_point = 0x400035e8; -r_ecc_multiplication_event_handler = 0x400035f4; -r_ecc_point_multiplication_win_256 = 0x40003600; -r_emi_alloc_em_mapping_by_offset = 0x4000360c; -r_emi_base_reg_lut_show = 0x40003618; -r_emi_em_base_reg_show = 0x40003624; -r_emi_free_em_mapping_by_offset = 0x40003630; -r_emi_get_em_mapping_idx_by_offset = 0x4000363c; -r_emi_get_mem_addr_by_offset = 0x40003648; -r_emi_overwrite_em_mapping_by_offset = 0x40003654; -r_esp_vendor_hci_command_handler = 0x40003660; -r_get_stack_usage = 0x4000366c; -r_h4tl_acl_hdr_rx_evt_handler = 0x40003678; -r_h4tl_cmd_hdr_rx_evt_handler = 0x40003684; -r_h4tl_cmd_pld_rx_evt_handler = 0x40003690; -r_h4tl_eif_io_event_post = 0x4000369c; -r_h4tl_eif_register = 0x400036a8; -r_h4tl_init = 0x400036b4; -r_h4tl_out_of_sync = 0x400036c0; -r_h4tl_out_of_sync_check = 0x400036cc; -r_h4tl_read_hdr = 0x400036d8; -r_h4tl_read_next_out_of_sync = 0x400036e4; -r_h4tl_read_payl = 0x400036f0; -r_h4tl_read_start = 0x400036fc; -r_h4tl_rx_acl_hdr_extract = 0x40003708; -r_h4tl_rx_cmd_hdr_extract = 0x40003714; -r_h4tl_rx_done = 0x40003720; -r_h4tl_start = 0x4000372c; -r_h4tl_stop = 0x40003738; -r_h4tl_tx_done = 0x40003744; -r_h4tl_tx_evt_handler = 0x40003750; -r_h4tl_write = 0x4000375c; -r_hci_acl_tx_data_alloc = 0x40003768; -r_hci_acl_tx_data_received = 0x40003774; -r_hci_basic_cmd_send_2_controller = 0x40003780; -r_hci_ble_adv_report_filter_check = 0x4000378c; -r_hci_ble_adv_report_tx_check = 0x40003798; -r_hci_ble_conhdl_register = 0x400037a4; -r_hci_ble_conhdl_unregister = 0x400037b0; -r_hci_build_acl_data = 0x400037bc; -r_hci_build_cc_evt = 0x400037c8; -r_hci_build_cs_evt = 0x400037d4; -r_hci_build_evt = 0x400037e0; -r_hci_build_le_evt = 0x400037ec; -r_hci_cmd_get_max_param_size = 0x400037f8; -r_hci_cmd_received = 0x40003804; -r_hci_cmd_reject = 0x40003810; -r_hci_evt_mask_check = 0x4000381c; -r_hci_evt_mask_set = 0x40003828; -r_hci_fc_acl_buf_size_set = 0x40003834; -r_hci_fc_acl_en = 0x40003840; -r_hci_fc_acl_packet_sent = 0x4000384c; -r_hci_fc_check_host_available_nb_acl_packets = 0x40003858; -r_hci_fc_host_nb_acl_pkts_complete = 0x40003864; -r_hci_fc_init = 0x40003870; -r_hci_look_for_cmd_desc = 0x4000387c; -r_hci_look_for_evt_desc = 0x40003888; -r_hci_look_for_le_evt_desc = 0x40003894; -r_hci_look_for_le_evt_desc_esp = 0x400038a0; -r_hci_pack_bytes = 0x400038ac; -r_hci_register_vendor_desc_tab = 0x400038b8; -r_hci_send_2_controller = 0x400038c4; -r_hci_send_2_host = 0x400038d0; -r_hci_tl_c2h_data_flow_on = 0x400038dc; -r_hci_tl_cmd_hdr_rx_evt_handler = 0x400038e8; -r_hci_tl_cmd_pld_rx_evt_handler = 0x400038f4; -r_hci_tl_get_pkt = 0x40003900; -r_hci_tl_hci_pkt_handler = 0x4000390c; -r_hci_tl_hci_tx_done_evt_handler = 0x40003918; -r_hci_tl_inc_nb_h2c_cmd_pkts = 0x40003924; -r_hci_tl_save_pkt = 0x40003930; -r_hci_tl_send = 0x4000393c; -r_hci_tx_done = 0x40003948; -r_hci_tx_start = 0x40003954; -r_hci_tx_trigger = 0x40003960; -r_isValidSecretKey_256 = 0x4000396c; -r_ke_check_malloc = 0x40003978; -r_ke_event_callback_set = 0x40003984; -r_ke_event_clear = 0x40003990; -r_ke_event_flush = 0x4000399c; -r_ke_event_get = 0x400039a8; -r_ke_event_get_all = 0x400039b4; -r_ke_event_init = 0x400039c0; -r_ke_event_schedule = 0x400039cc; -r_ke_event_set = 0x400039d8; -r_ke_flush = 0x400039e4; -r_ke_free = 0x400039f0; -r_ke_handler_search = 0x400039fc; -r_ke_init = 0x40003a08; -r_ke_is_free = 0x40003a14; -r_ke_malloc = 0x40003a20; -r_ke_mem_init = 0x40003a2c; -r_ke_mem_is_empty = 0x40003a38; -r_ke_mem_is_in_heap = 0x40003a44; -r_ke_msg_alloc = 0x40003a50; -r_ke_msg_dest_id_get = 0x40003a5c; -r_ke_msg_discard = 0x40003a68; -r_ke_msg_forward = 0x40003a74; -r_ke_msg_forward_new_id = 0x40003a80; -r_ke_msg_free = 0x40003a8c; -r_ke_msg_in_queue = 0x40003a98; -r_ke_msg_save = 0x40003aa4; -r_ke_msg_send = 0x40003ab0; -r_ke_msg_send_basic = 0x40003abc; -r_ke_msg_src_id_get = 0x40003ac8; -r_ke_queue_extract = 0x40003ad4; -r_ke_queue_insert = 0x40003ae0; -r_ke_sleep_check = 0x40003aec; -r_ke_state_get = 0x40003af8; -r_ke_state_set = 0x40003b04; -r_ke_task_check = 0x40003b10; -r_ke_task_create = 0x40003b1c; -r_ke_task_delete = 0x40003b28; -r_ke_task_handler_get = 0x40003b34; -r_ke_task_init = 0x40003b40; -r_ke_task_msg_flush = 0x40003b4c; -r_ke_task_saved_update = 0x40003b58; -r_ke_task_schedule = 0x40003b64; -r_ke_time = 0x40003b70; -r_ke_time_cmp = 0x40003b7c; -r_ke_time_past = 0x40003b88; -r_ke_timer_active = 0x40003b94; -r_ke_timer_adjust_all = 0x40003ba0; -r_ke_timer_clear = 0x40003bac; -r_ke_timer_init = 0x40003bb8; -r_ke_timer_schedule = 0x40003bc4; -r_ke_timer_set = 0x40003bd0; -r_led_init = 0x40003bdc; -r_led_set_all = 0x40003be8; -r_llc_aes_res_cb = 0x40003bf4; -r_llc_ch_map_up_proc_err_cb = 0x40003c00; -r_llc_cleanup = 0x40003c0c; -r_llc_cmd_cmp_send = 0x40003c18; -r_llc_cmd_stat_send = 0x40003c24; -r_llc_con_move_cbk = 0x40003c30; -r_llc_con_plan_set_update = 0x40003c3c; -r_llc_con_upd_param_in_range = 0x40003c48; -r_llc_disconnect = 0x40003c54; -r_llc_disconnect_end = 0x40003c60; -r_llc_disconnect_proc_continue = 0x40003c6c; -r_llc_disconnect_proc_err_cb = 0x40003c78; -r_llc_dl_chg_check = 0x40003c84; -r_llc_dle_proc_err_cb = 0x40003c90; -r_llc_feats_exch_proc_err_cb = 0x40003c9c; -r_llc_hci_cmd_handler_tab_p_get = 0x40003ca8; -r_llc_hci_command_handler = 0x40003cb4; -r_llc_hci_con_param_req_evt_send = 0x40003cc0; -r_llc_hci_con_upd_info_send = 0x40003ccc; -r_llc_hci_disconnected_dis = 0x40003cd8; -r_llc_hci_dl_upd_info_send = 0x40003ce4; -r_llc_hci_enc_evt_send = 0x40003cf0; -r_llc_hci_feats_info_send = 0x40003cfc; -r_llc_hci_le_phy_upd_cmp_evt_send = 0x40003d08; -r_llc_hci_ltk_request_evt_send = 0x40003d14; -r_llc_hci_nb_cmp_pkts_evt_send = 0x40003d20; -r_llc_hci_version_info_send = 0x40003d2c; -r_llc_init_term_proc = 0x40003d38; -r_llc_iv_skd_rand_gen = 0x40003d44; -r_llc_le_ping_proc_continue = 0x40003d50; -r_llc_le_ping_proc_err_cb = 0x40003d5c; -r_llc_le_ping_restart = 0x40003d68; -r_llc_le_ping_set = 0x40003d74; -r_llc_ll_pause_enc_rsp_ack_handler = 0x40003d80; -r_llc_ll_reject_ind_ack_handler = 0x40003d8c; -r_llc_ll_reject_ind_pdu_send = 0x40003d98; -r_llc_ll_start_enc_rsp_ack_handler = 0x40003da4; -r_llc_ll_terminate_ind_ack = 0x40003db0; -r_llc_ll_unknown_ind_handler = 0x40003dbc; -r_llc_llcp_send = 0x40003dc8; -r_llc_llcp_state_set = 0x40003dd4; -r_llc_llcp_trans_timer_set = 0x40003de0; -r_llc_llcp_tx_check = 0x40003dec; -r_llc_loc_ch_map_proc_continue = 0x40003df8; -r_llc_loc_con_upd_proc_continue = 0x40003e04; -r_llc_loc_con_upd_proc_err_cb = 0x40003e10; -r_llc_loc_dl_upd_proc_continue = 0x40003e1c; -r_llc_loc_encrypt_proc_continue = 0x40003e28; -r_llc_loc_encrypt_proc_err_cb = 0x40003e34; -r_llc_loc_feats_exch_proc_continue = 0x40003e40; -r_llc_loc_phy_upd_proc_continue = 0x40003e4c; -r_llc_loc_phy_upd_proc_err_cb = 0x40003e58; -r_llc_msg_handler_tab_p_get = 0x40003e64; -r_llc_pref_param_compute = 0x40003e70; -r_llc_proc_collision_check = 0x40003e7c; -r_llc_proc_err_ind = 0x40003e88; -r_llc_proc_get = 0x40003e94; -r_llc_proc_id_get = 0x40003ea0; -r_llc_proc_reg = 0x40003eac; -r_llc_proc_state_get = 0x40003eb8; -r_llc_proc_state_set = 0x40003ec4; -r_llc_proc_timer_pause_set = 0x40003ed0; -r_llc_proc_timer_set = 0x40003edc; -r_llc_proc_unreg = 0x40003ee8; -r_llc_rem_ch_map_proc_continue = 0x40003ef4; -r_llc_rem_con_upd_proc_continue = 0x40003f00; -r_llc_rem_con_upd_proc_err_cb = 0x40003f0c; -r_llc_rem_dl_upd_proc = 0x40003f18; -r_llc_rem_encrypt_proc_continue = 0x40003f24; -r_llc_rem_encrypt_proc_err_cb = 0x40003f30; -r_llc_rem_phy_upd_proc_continue = 0x40003f3c; -r_llc_rem_phy_upd_proc_err_cb = 0x40003f48; -r_llc_role_get = 0x40003f54; -r_llc_sk_gen = 0x40003f60; -r_llc_start = 0x40003f6c; -r_llc_stop = 0x40003f78; -r_llc_ver_exch_loc_proc_continue = 0x40003f84; -r_llc_ver_proc_err_cb = 0x40003f90; -r_llcp_pdu_handler_tab_p_get = 0x40003f9c; -r_lld_aa_gen = 0x40003fa8; -r_lld_adv_adv_data_set = 0x40003fb4; -r_lld_adv_adv_data_update = 0x40003fc0; -r_lld_adv_aux_ch_idx_set = 0x40003fcc; -r_lld_adv_aux_evt_canceled_cbk = 0x40003fd8; -r_lld_adv_aux_evt_start_cbk = 0x40003fe4; -r_lld_adv_coex_check_ext_adv_synced = 0x40003ff0; -r_lld_adv_coex_env_reset = 0x40003ffc; -r_lld_adv_duration_update = 0x40004008; -r_lld_adv_dynamic_pti_process = 0x40004014; -r_lld_adv_end = 0x40004020; -r_lld_adv_evt_canceled_cbk = 0x4000402c; -r_lld_adv_evt_start_cbk = 0x40004038; -r_lld_adv_ext_chain_construct = 0x40004044; -r_lld_adv_ext_pkt_prepare = 0x40004050; -r_lld_adv_frm_cbk = 0x4000405c; -r_lld_adv_frm_isr = 0x40004068; -r_lld_adv_frm_skip_isr = 0x40004074; -r_lld_adv_init = 0x40004080; -r_lld_adv_pkt_rx = 0x4000408c; -r_lld_adv_pkt_rx_connect_ind = 0x40004098; -r_lld_adv_pkt_rx_send_scan_req_evt = 0x400040a4; -r_lld_adv_rand_addr_update = 0x400040b0; -r_lld_adv_restart = 0x400040bc; -r_lld_adv_scan_rsp_data_set = 0x400040c8; -r_lld_adv_scan_rsp_data_update = 0x400040d4; -r_lld_adv_set_tx_power = 0x400040e0; -r_lld_adv_start = 0x400040ec; -r_lld_adv_stop = 0x400040f8; -r_lld_adv_sync_info_set = 0x40004104; -r_lld_adv_sync_info_update = 0x40004110; -r_lld_calc_aux_rx = 0x4000411c; -r_lld_cca_alloc = 0x40004128; -r_lld_cca_data_reset = 0x40004134; -r_lld_cca_free = 0x40004140; -r_lld_ch_assess_data_get = 0x4000414c; -r_lld_ch_idx_get = 0x40004158; -r_lld_ch_map_set = 0x40004164; -r_lld_channel_assess = 0x40004170; -r_lld_con_activity_act_offset_compute = 0x4000417c; -r_lld_con_activity_offset_compute = 0x40004188; -r_lld_con_ch_map_update = 0x40004194; -r_lld_con_cleanup = 0x400041a0; -r_lld_con_current_tx_power_get = 0x400041ac; -r_lld_con_data_flow_set = 0x400041b8; -r_lld_con_data_len_update = 0x400041c4; -r_lld_con_data_tx = 0x400041d0; -r_lld_con_enc_key_load = 0x400041dc; -r_lld_con_event_counter_get = 0x400041e8; -r_lld_con_evt_canceled_cbk = 0x400041f4; -r_lld_con_evt_duration_min_get = 0x40004200; -r_lld_con_evt_max_eff_time_cal = 0x4000420c; -r_lld_con_evt_sd_evt_time_get = 0x40004218; -r_lld_con_evt_start_cbk = 0x40004224; -r_lld_con_evt_time_update = 0x40004230; -r_lld_con_free_all_tx_buf = 0x4000423c; -r_lld_con_frm_cbk = 0x40004248; -r_lld_con_frm_isr = 0x40004254; -r_lld_con_frm_skip_isr = 0x40004260; -r_lld_con_init = 0x4000426c; -r_lld_con_llcp_tx = 0x40004278; -r_lld_con_max_lat_calc = 0x40004284; -r_lld_con_offset_get = 0x40004290; -r_lld_con_param_update = 0x4000429c; -r_lld_con_phys_update = 0x400042a8; -r_lld_con_pref_slave_evt_dur_set = 0x400042b4; -r_lld_con_pref_slave_latency_set = 0x400042c0; -r_lld_con_rssi_get = 0x400042cc; -r_lld_con_rx = 0x400042d8; -r_lld_con_rx_channel_assess = 0x400042e4; -r_lld_con_rx_enc = 0x400042f0; -r_lld_con_rx_isr = 0x400042fc; -r_lld_con_rx_link_info_check = 0x40004308; -r_lld_con_rx_llcp_check = 0x40004314; -r_lld_con_rx_sync_time_update = 0x40004320; -r_lld_con_sched = 0x4000432c; -r_lld_con_set_tx_power = 0x40004338; -r_lld_con_start = 0x40004344; -r_lld_con_stop = 0x40004350; -r_lld_con_tx = 0x4000435c; -r_lld_con_tx_enc = 0x40004368; -r_lld_con_tx_isr = 0x40004374; -r_lld_con_tx_len_update = 0x40004380; -r_lld_con_tx_len_update_for_intv = 0x4000438c; -r_lld_con_tx_len_update_for_rate = 0x40004398; -r_lld_con_tx_prog = 0x400043a4; -r_lld_conn_dynamic_pti_process = 0x400043b0; -r_lld_continue_scan_rx_isr_end_process = 0x400043bc; -r_lld_ext_scan_dynamic_pti_process = 0x400043c8; -r_lld_hw_cca_end_isr = 0x400043d4; -r_lld_hw_cca_evt_handler = 0x400043e0; -r_lld_hw_cca_isr = 0x400043ec; -r_lld_init_cal_anchor_point = 0x400043f8; -r_lld_init_compute_winoffset = 0x40004404; -r_lld_init_connect_req_pack = 0x40004410; -r_lld_init_end = 0x4000441c; -r_lld_init_evt_canceled_cbk = 0x40004428; -r_lld_init_evt_start_cbk = 0x40004434; -r_lld_init_frm_cbk = 0x40004440; -r_lld_init_frm_eof_isr = 0x4000444c; -r_lld_init_frm_skip_isr = 0x40004458; -r_lld_init_init = 0x40004464; -r_lld_init_process_pkt_rx = 0x40004470; -r_lld_init_process_pkt_rx_adv_ext_ind = 0x4000447c; -r_lld_init_process_pkt_rx_adv_ind_or_direct_ind = 0x40004488; -r_lld_init_process_pkt_rx_aux_connect_rsp = 0x40004494; -r_lld_init_process_pkt_tx = 0x400044a0; -r_lld_init_process_pkt_tx_cal_con_timestamp = 0x400044ac; -r_lld_init_sched = 0x400044b8; -r_lld_init_set_tx_power = 0x400044c4; -r_lld_init_start = 0x400044d0; -r_lld_init_stop = 0x400044dc; -r_lld_instant_proc_end = 0x400044e8; -r_lld_llcp_rx_ind_handler = 0x400044f4; -r_lld_per_adv_ch_map_update = 0x40004500; -r_lld_per_adv_chain_construct = 0x4000450c; -r_lld_per_adv_cleanup = 0x40004518; -r_lld_per_adv_coex_env_reset = 0x40004524; -r_lld_per_adv_data_set = 0x40004530; -r_lld_per_adv_data_update = 0x4000453c; -r_lld_per_adv_dynamic_pti_process = 0x40004548; -r_lld_per_adv_evt_canceled_cbk = 0x40004554; -r_lld_per_adv_evt_start_cbk = 0x40004560; -r_lld_per_adv_ext_pkt_prepare = 0x4000456c; -r_lld_per_adv_frm_cbk = 0x40004578; -r_lld_per_adv_frm_isr = 0x40004584; -r_lld_per_adv_frm_skip_isr = 0x40004590; -r_lld_per_adv_init = 0x4000459c; -r_lld_per_adv_init_info_get = 0x400045a8; -r_lld_per_adv_list_add = 0x400045b4; -r_lld_per_adv_list_rem = 0x400045c0; -r_lld_per_adv_sched = 0x400045cc; -r_lld_per_adv_set_tx_power = 0x400045d8; -r_lld_per_adv_start = 0x400045e4; -r_lld_per_adv_stop = 0x400045f0; -r_lld_per_adv_sync_info_get = 0x400045fc; -r_lld_process_cca_data = 0x40004608; -r_lld_ral_search = 0x40004614; -r_lld_read_clock = 0x40004620; -r_lld_res_list_add = 0x4000462c; -r_lld_res_list_clear = 0x40004638; -r_lld_res_list_is_empty = 0x40004644; -r_lld_res_list_local_rpa_get = 0x40004650; -r_lld_res_list_peer_rpa_get = 0x4000465c; -r_lld_res_list_peer_update = 0x40004668; -r_lld_res_list_priv_mode_update = 0x40004674; -r_lld_res_list_rem = 0x40004680; -r_lld_reset_reg = 0x4000468c; -r_lld_rpa_renew = 0x40004698; -r_lld_rpa_renew_evt_canceled_cbk = 0x400046a4; -r_lld_rpa_renew_evt_start_cbk = 0x400046b0; -r_lld_rpa_renew_instant_cbk = 0x400046bc; -r_lld_rxdesc_check = 0x400046c8; -r_lld_rxdesc_free = 0x400046d4; -r_lld_scan_create_sync = 0x400046e0; -r_lld_scan_create_sync_cancel = 0x400046ec; -r_lld_scan_end = 0x400046f8; -r_lld_scan_evt_canceled_cbk = 0x40004704; -r_lld_scan_evt_start_cbk = 0x40004710; -r_lld_scan_frm_cbk = 0x4000471c; -r_lld_scan_frm_eof_isr = 0x40004728; -r_lld_scan_frm_rx_isr = 0x40004734; -r_lld_scan_frm_skip_isr = 0x40004740; -r_lld_scan_init = 0x4000474c; -r_lld_scan_params_update = 0x40004758; -r_lld_scan_process_pkt_rx = 0x40004764; -r_lld_scan_process_pkt_rx_adv_rep = 0x40004770; -r_lld_scan_process_pkt_rx_aux_adv_ind = 0x4000477c; -r_lld_scan_process_pkt_rx_aux_chain_ind = 0x40004788; -r_lld_scan_process_pkt_rx_aux_scan_rsp = 0x40004794; -r_lld_scan_process_pkt_rx_ext_adv = 0x400047a0; -r_lld_scan_process_pkt_rx_ext_adv_ind = 0x400047ac; -r_lld_scan_process_pkt_rx_legacy_adv = 0x400047b8; -r_lld_scan_restart = 0x400047c4; -r_lld_scan_sched = 0x400047d0; -r_lld_scan_set_tx_power = 0x400047dc; -r_lld_scan_start = 0x400047e8; -r_lld_scan_stop = 0x400047f4; -r_lld_scan_sync_accept = 0x40004800; -r_lld_scan_sync_info_unpack = 0x4000480c; -r_lld_scan_trunc_ind = 0x40004818; -r_lld_sw_cca_evt_handler = 0x40004824; -r_lld_sw_cca_isr = 0x40004830; -r_lld_sync_ch_map_update = 0x4000483c; -r_lld_sync_cleanup = 0x40004848; -r_lld_sync_evt_canceled_cbk = 0x40004854; -r_lld_sync_evt_start_cbk = 0x40004860; -r_lld_sync_frm_cbk = 0x4000486c; -r_lld_sync_frm_eof_isr = 0x40004878; -r_lld_sync_frm_rx_isr = 0x40004884; -r_lld_sync_frm_skip_isr = 0x40004890; -r_lld_sync_init = 0x4000489c; -r_lld_sync_process_pkt_rx = 0x400048a8; -r_lld_sync_process_pkt_rx_aux_sync_ind = 0x400048b4; -r_lld_sync_process_pkt_rx_pkt_check = 0x400048c0; -r_lld_sync_scan_dynamic_pti_process = 0x400048cc; -r_lld_sync_sched = 0x400048d8; -r_lld_sync_start = 0x400048e4; -r_lld_sync_stop = 0x400048f0; -r_lld_sync_trunc_ind = 0x400048fc; -r_lld_test_cleanup = 0x40004908; -r_lld_test_evt_canceled_cbk = 0x40004914; -r_lld_test_evt_start_cbk = 0x40004920; -r_lld_test_freq2chnl = 0x4000492c; -r_lld_test_frm_cbk = 0x40004938; -r_lld_test_frm_isr = 0x40004944; -r_lld_test_init = 0x40004950; -r_lld_test_rx_isr = 0x4000495c; -r_lld_test_set_tx_power = 0x40004968; -r_lld_test_start = 0x40004974; -r_lld_test_stop = 0x40004980; -r_lld_update_rxbuf = 0x4000498c; -r_lld_update_rxbuf_isr = 0x40004998; -r_lld_white_list_add = 0x400049a4; -r_lld_white_list_rem = 0x400049b0; -r_llm_activity_free_get = 0x400049bc; -r_llm_activity_free_set = 0x400049c8; -r_llm_activity_syncing_get = 0x400049d4; -r_llm_adv_con_len_check = 0x400049e0; -r_llm_adv_hdl_to_id = 0x400049ec; -r_llm_adv_rep_flow_control_check = 0x400049f8; -r_llm_adv_rep_flow_control_update = 0x40004a04; -r_llm_adv_reports_list_check = 0x40004a10; -r_llm_adv_set_all_release = 0x40004a1c; -r_llm_adv_set_dft_params = 0x40004a28; -r_llm_adv_set_release = 0x40004a34; -r_llm_aes_res_cb = 0x40004a40; -r_llm_ble_update_adv_flow_control = 0x40004a4c; -r_llm_ch_map_update = 0x40004a58; -r_llm_cmd_cmp_send = 0x40004a64; -r_llm_cmd_stat_send = 0x40004a70; -r_llm_dev_list_empty_entry = 0x40004a7c; -r_llm_dev_list_search = 0x40004a88; -r_llm_env_adv_dup_filt_deinit = 0x40004a94; -r_llm_env_adv_dup_filt_init = 0x40004aa0; -r_llm_init_ble_adv_report_flow_contol = 0x40004aac; -r_llm_is_dev_connected = 0x40004ab8; -r_llm_is_dev_synced = 0x40004ac4; -r_llm_is_non_con_act_ongoing_check = 0x40004ad0; -r_llm_is_wl_accessible = 0x40004adc; -r_llm_le_evt_mask_check = 0x40004ae8; -r_llm_le_features_get = 0x40004af4; -r_llm_link_disc = 0x40004b00; -r_llm_master_ch_map_get = 0x40004b0c; -r_llm_msg_handler_tab_p_get = 0x40004b18; -r_llm_no_activity = 0x40004b24; -r_llm_per_adv_slot_dur = 0x40004b30; -r_llm_plan_elt_get = 0x40004b3c; -r_llm_rx_path_comp_get = 0x40004b48; -r_llm_scan_start = 0x40004b54; -r_llm_scan_sync_acad_attach = 0x40004b60; -r_llm_scan_sync_acad_detach = 0x40004b6c; -r_llm_send_adv_lost_event_to_host = 0x40004b78; -r_llm_tx_path_comp_get = 0x40004b84; -r_misc_deinit = 0x40004b90; -r_misc_free_em_buf_in_isr = 0x40004b9c; -r_misc_init = 0x40004ba8; -r_misc_msg_handler_tab_p_get = 0x40004bb4; -r_notEqual256 = 0x40004bc0; -r_phy_upd_proc_start = 0x40004bcc; -r_platform_reset = 0x40004bd8; -r_register_esp_vendor_cmd_handler = 0x40004be4; -r_rf_em_init = 0x40004bf0; -r_rf_force_agc_enable = 0x40004bfc; -r_rf_reg_rd = 0x40004c08; -r_rf_reg_wr = 0x40004c14; -r_rf_reset = 0x40004c20; -r_rf_rssi_convert = 0x40004c2c; -r_rf_rw_v9_le_disable = 0x40004c38; -r_rf_rw_v9_le_enable = 0x40004c44; -r_rf_sleep = 0x40004c50; -r_rf_txpwr_cs_get = 0x40004c5c; -r_rf_txpwr_dbm_get = 0x40004c68; -r_rf_util_cs_fmt_convert = 0x40004c74; -r_rw_crypto_aes_ccm = 0x40004c80; -r_rw_crypto_aes_encrypt = 0x40004c8c; -r_rw_crypto_aes_init = 0x40004c98; -r_rw_crypto_aes_k1 = 0x40004ca4; -r_rw_crypto_aes_k2 = 0x40004cb0; -r_rw_crypto_aes_k3 = 0x40004cbc; -r_rw_crypto_aes_k4 = 0x40004cc8; -r_rw_crypto_aes_rand = 0x40004cd4; -r_rw_crypto_aes_result_handler = 0x40004ce0; -r_rw_crypto_aes_s1 = 0x40004cec; -r_rw_cryto_aes_cmac = 0x40004cf8; -r_rw_v9_init_em_radio_table = 0x40004d04; -r_rwble_isr = 0x40004d10; -r_rwble_sleep_enter = 0x40004d1c; -r_rwble_sleep_wakeup_end = 0x40004d28; -r_rwbtdm_isr_wrapper = 0x40004d34; -r_rwip_active_check = 0x40004d40; -r_rwip_aes_encrypt = 0x40004d4c; -r_rwip_assert = 0x40004d58; -r_rwip_crypt_evt_handler = 0x40004d64; -r_rwip_crypt_isr_handler = 0x40004d70; -r_rwip_eif_get = 0x40004d7c; -r_rwip_half_slot_2_lpcycles = 0x40004d88; -r_rwip_hus_2_lpcycles = 0x40004d94; -r_rwip_isr = 0x40004da0; -r_rwip_lpcycles_2_hus = 0x40004dac; -r_rwip_prevent_sleep_clear = 0x40004db8; -r_rwip_prevent_sleep_set = 0x40004dc4; -r_rwip_schedule = 0x40004dd0; -r_rwip_sleep = 0x40004ddc; -r_rwip_sw_int_handler = 0x40004de8; -r_rwip_sw_int_req = 0x40004df4; -r_rwip_time_get = 0x40004e00; -r_rwip_timer_10ms_handler = 0x40004e0c; -r_rwip_timer_10ms_set = 0x40004e18; -r_rwip_timer_hs_handler = 0x40004e24; -r_rwip_timer_hs_set = 0x40004e30; -r_rwip_timer_hus_handler = 0x40004e3c; -r_rwip_timer_hus_set = 0x40004e48; -r_rwip_wakeup = 0x40004e54; -r_rwip_wakeup_end = 0x40004e60; -r_rwip_wlcoex_set = 0x40004e6c; -r_sch_alarm_clear = 0x40004e78; -r_sch_alarm_init = 0x40004e84; -r_sch_alarm_prog = 0x40004e90; -r_sch_alarm_set = 0x40004e9c; -r_sch_alarm_timer_isr = 0x40004ea8; -r_sch_arb_conflict_check = 0x40004eb4; -r_sch_arb_elt_cancel = 0x40004ec0; -r_sch_arb_event_start_isr = 0x40004ecc; -r_sch_arb_init = 0x40004ed8; -r_sch_arb_insert = 0x40004ee4; -r_sch_arb_prog_timer = 0x40004ef0; -r_sch_arb_remove = 0x40004efc; -r_sch_arb_sw_isr = 0x40004f08; -r_sch_plan_chk = 0x40004f14; -r_sch_plan_clock_wrap_offset_update = 0x40004f20; -r_sch_plan_init = 0x40004f2c; -r_sch_plan_interval_req = 0x40004f38; -r_sch_plan_offset_max_calc = 0x40004f44; -r_sch_plan_offset_req = 0x40004f50; -r_sch_plan_position_range_compute = 0x40004f5c; -r_sch_plan_rem = 0x40004f68; -r_sch_plan_req = 0x40004f74; -r_sch_plan_set = 0x40004f80; -r_sch_prog_end_isr = 0x40004f8c; -r_sch_prog_init = 0x40004f98; -r_sch_prog_push = 0x40004fa4; -r_sch_prog_rx_isr = 0x40004fb0; -r_sch_prog_skip_isr = 0x40004fbc; -r_sch_prog_tx_isr = 0x40004fc8; -r_sch_slice_bg_add = 0x40004fd4; -r_sch_slice_bg_remove = 0x40004fe0; -r_sch_slice_compute = 0x40004fec; -r_sch_slice_fg_add = 0x40004ff8; -r_sch_slice_fg_remove = 0x40005004; -r_sch_slice_init = 0x40005010; -r_sch_slice_per_add = 0x4000501c; -r_sch_slice_per_remove = 0x40005028; -r_sdk_config_get_bt_sleep_enable = 0x40005034; -r_sdk_config_get_hl_derived_opts = 0x40005040; -r_sdk_config_get_opts = 0x4000504c; -r_sdk_config_get_priv_opts = 0x40005058; -r_sdk_config_set_bt_sleep_enable = 0x40005064; -r_sdk_config_set_hl_derived_opts = 0x40005070; -r_sdk_config_set_opts = 0x4000507c; -r_specialModP256 = 0x40005088; -r_unloaded_area_init = 0x40005094; -r_vhci_flow_off = 0x400050a0; -r_vhci_flow_on = 0x400050ac; -r_vhci_notify_host_send_available = 0x400050b8; -r_vhci_send_to_host = 0x400050c4; -r_vnd_hci_command_handler = 0x400050d0; -r_vshci_init = 0x400050dc; -vnd_hci_command_handler_wrapper = 0x400050e8; -r_lld_legacy_adv_dynamic_pti_get = 0x400050f4; -r_lld_legacy_adv_dynamic_pti_process = 0x40005100; -r_lld_ext_adv_dynamic_pti_get = 0x4000510c; -r_lld_ext_adv_dynamic_aux_pti_process = 0x40005118; -r_lld_ext_adv_dynamic_pti_process = 0x40005124; -r_lld_adv_ext_pkt_prepare_set = 0x40005130; -r_lld_adv_ext_chain_none_construct = 0x4000513c; -r_lld_adv_ext_chain_connectable_construct = 0x40005148; -r_lld_adv_ext_chain_scannable_construct = 0x40005154; -r_lld_adv_pkt_rx_connect_post = 0x40005160; -r_lld_adv_start_init_evt_param = 0x4000516c; -r_lld_adv_start_set_cs = 0x40005178; -r_lld_adv_start_update_filter_policy = 0x40005184; -r_lld_adv_start_schedule_asap = 0x40005190; -r_lld_con_tx_prog_new_packet_coex = 0x4000519c; -r_lld_con_tx_prog_new_packet = 0x400051a8; -r_lld_per_adv_dynamic_pti_get = 0x400051b4; -r_lld_per_adv_evt_start_chm_upd = 0x400051c0; -r_lld_ext_scan_dynamic_pti_get = 0x400051cc; -r_lld_scan_try_sched = 0x400051d8; -r_lld_sync_insert = 0x400051e4; -r_sch_prog_ble_push = 0x400051f0; -r_sch_prog_bt_push = 0x400051fc; -r_lld_init_evt_end_type_set = 0x40005208; -r_lld_init_evt_end_type_get = 0x40005214; -r_lld_adv_direct_adv_use_rpa_addr_state_set = 0x40005220; -r_lld_adv_direct_adv_use_rpa_addr_state_get = 0x4000522c; -r_lld_init_evt_end_type_check_state_set = 0x40005238; -r_lld_init_evt_end_type_check_state_get = 0x40005244; -/* Data (.data, .bss, .rodata) */ -bt_rf_coex_cfg_p = 0x3fceffa8; -bt_rf_coex_hooks_p = 0x3fceffa4; -btdm_env_p = 0x3fceffa0; -g_rw_controller_task_handle = 0x3fceff9c; -g_rw_init_sem = 0x3fceff98; -g_rw_schd_queue = 0x3fceff94; -lld_init_env = 0x3fceff90; -lld_rpa_renew_env = 0x3fceff8c; -lld_scan_env = 0x3fceff88; -lld_scan_sync_env = 0x3fceff84; -lld_test_env = 0x3fceff80; -p_ble_util_buf_env = 0x3fceff7c; -p_lld_env = 0x3fceff78; -p_llm_env = 0x3fceff74; -r_h4tl_eif_p = 0x3fceff70; -r_hli_funcs_p = 0x3fceff6c; -r_ip_funcs_p = 0x3fceff68; -r_modules_funcs_p = 0x3fceff64; -r_osi_funcs_p = 0x3fceff60; -r_plf_funcs_p = 0x3fceff5c; -vhci_env_p = 0x3fceff58; -aa_gen = 0x3fceff54; -aes_env = 0x3fceff48; -bt_rf_coex_cfg_cb = 0x3fcefef8; -btdm_pwr_state = 0x3fcefef4; -btdm_slp_err = 0x3fcefef0; -ecc_env = 0x3fcefee8; -esp_handler = 0x3fcefee0; -esp_vendor_cmd = 0x3fcefed8; -g_adv_delay_dis = 0x3fcefed4; -g_conflict_elt = 0x3fcefed0; -g_eif_api = 0x3fcefec0; -g_event_empty = 0x3fcefeb4; -g_llc_state = 0x3fcefeaa; -g_llm_state = 0x3fcefea9; -g_max_evt_env = 0x3fcefea7; -g_misc_state = 0x3fcefea6; -g_rma_rule_db = 0x3fcefe8a; -g_rtp_rule_db = 0x3fcefe6e; -g_scan_forever = 0x3fcefe6d; -g_time_msb = 0x3fcefe6c; -h4tl_env = 0x3fcefe44; -hci_env = 0x3fcefe21; -hci_ext_host = 0x3fcefe20; -hci_fc_env = 0x3fcefe18; -hci_tl_env = 0x3fcefdec; -ke_env = 0x3fcefdbc; -ke_event_env = 0x3fcefd7c; -ke_task_env = 0x3fcefd00; -llc_env = 0x3fcefcd8; -lld_adv_env = 0x3fcefcb0; -lld_con_env = 0x3fcefc88; -lld_exp_sync_pos_tab = 0x3fcefc80; -lld_per_adv_env = 0x3fcefc58; -lld_sync_env = 0x3fcefc30; -llm_le_adv_flow_env = 0x3fcefc24; -rw_sleep_enable = 0x3fcefc20; -rwble_env = 0x3fcefc18; -rwip_env = 0x3fcefbfc; -rwip_param = 0x3fcefbf0; -rwip_prog_delay = 0x3fcefbec; -rwip_rf = 0x3fcefbb4; -sch_alarm_env = 0x3fcefbac; -sch_arb_env = 0x3fcefb98; -sch_plan_env = 0x3fcefb90; -sch_prog_env = 0x3fcefa8c; -sch_slice_env = 0x3fcefa2c; -sch_slice_params = 0x3fcefa24; -timer_env = 0x3fcefa1c; -unloaded_area = 0x3fcefa18; -vshci_state = 0x3fcefa14; -TASK_DESC_LLC = 0x3fcefa08; -TASK_DESC_LLM = 0x3fcef9fc; -TASK_DESC_VSHCI = 0x3fcef9f0; -co_default_bdaddr = 0x3fcef9e8; -dbg_assert_block = 0x3fcef9e4; -g_bt_plf_log_level = 0x3fcef9e0; -hci_cmd_desc_tab_vs_esp = 0x3fcef9bc; -hci_command_handler_tab_esp = 0x3fcef9a4; -privacy_en = 0x3fcef9a0; -sdk_cfg_priv_opts = 0x3fcef958; -BasePoint_x_256 = 0x3ff1ffdc; -BasePoint_y_256 = 0x3ff1ffbc; -DebugE256PublicKey_x = 0x3ff1ff9c; -DebugE256PublicKey_y = 0x3ff1ff7c; -DebugE256SecretKey = 0x3ff1ff5c; -ECC_4Win_Look_up_table = 0x3ff1f7a0; -LLM_AA_CT1 = 0x3ff1f79a; -LLM_AA_CT2 = 0x3ff1f798; -RF_TX_PW_CONV_TBL = 0x3ff1f790; -TASK_DESC_MISC = 0x3ff1f784; -adv_evt_prop2type = 0x3ff1f766; -adv_evt_type2prop = 0x3ff1f761; -aes_cmac_zero = 0x3ff1f751; -aes_k2_salt = 0x3ff1f741; -aes_k3_id64 = 0x3ff1f73c; -aes_k3_salt = 0x3ff1f72c; -aes_k4_id6 = 0x3ff1f728; -aes_k4_salt = 0x3ff1f718; -bigHexP256 = 0x3ff1f6ec; -byte_tx_time = 0x3ff1f6e2; -co_null_bdaddr = 0x3ff1f6dc; -co_phy_mask_to_rate = 0x3ff1f6d7; -co_phy_mask_to_value = 0x3ff1f6d2; -co_phy_to_rate = 0x3ff1f6ce; -co_phy_value_to_mask = 0x3ff1f6ca; -co_rate_to_byte_dur_us = 0x3ff1f6c5; -co_rate_to_phy = 0x3ff1f6c0; -co_rate_to_phy_mask = 0x3ff1f6bc; -co_sca2ppm = 0x3ff1f6ac; -coef_B = 0x3ff1f680; -connect_req_dur_tab = 0x3ff1f678; -ecc_Jacobian_InfinityPoint256 = 0x3ff1f5f4; -em_base_reg_lut = 0x3ff1f526; -fixed_tx_time = 0x3ff1f51e; -h4tl_msgtype2hdrlen = 0x3ff1f518; -hci_cmd_desc_root_tab = 0x3ff1f4e8; -hci_cmd_desc_tab_ctrl_bb = 0x3ff1f47c; -hci_cmd_desc_tab_info_par = 0x3ff1f44c; -hci_cmd_desc_tab_le = 0x3ff1f0b0; -hci_cmd_desc_tab_lk_ctrl = 0x3ff1f098; -hci_cmd_desc_tab_stat_par = 0x3ff1f08c; -hci_cmd_desc_tab_vs = 0x3ff1f050; -hci_evt_desc_tab = 0x3ff1f008; -hci_evt_le_desc_tab = 0x3ff1ef68; -hci_evt_le_desc_tab_esp = 0x3ff1ef60; -hci_rsvd_evt_msk = 0x3ff1ef57; -lld_aux_phy_to_rate = 0x3ff1ef54; -lld_init_max_aux_dur_tab = 0x3ff1ef4c; -lld_scan_map_legacy_pdu_to_evt_type = 0x3ff1ef44; -lld_scan_max_aux_dur_tab = 0x3ff1ef3c; -lld_sync_max_aux_dur_tab = 0x3ff1ef34; -llm_local_le_feats = 0x3ff1ef2c; -llm_local_le_states = 0x3ff1ef24; -llm_local_supp_cmds = 0x3ff1eefc; -maxSecretKey_256 = 0x3ff1eedc; -max_data_tx_time = 0x3ff1eed4; -one_bits = 0x3ff1eec3; -rwip_coex_cfg = 0x3ff1eebe; -rwip_priority = 0x3ff1eea8; -veryBigHexP256 = 0x3ff1ee5c; - - -/*************************************** - Group rom_pp - ***************************************/ - -/* Functions */ -esp_pp_rom_version_get = 0x40005250; -RC_GetBlockAckTime = 0x4000525c; -ebuf_list_remove = 0x40005268; -esf_buf_alloc = 0x40005274; -esf_buf_alloc_dynamic = 0x40005280; -esf_buf_recycle = 0x4000528c; -GetAccess = 0x40005298; -hal_mac_is_low_rate_enabled = 0x400052a4; -hal_mac_tx_get_blockack = 0x400052b0; -hal_mac_tx_set_ppdu = 0x400052bc; -ic_get_trc = 0x400052c8; -ic_mac_deinit = 0x400052d4; -ic_mac_init = 0x400052e0; -ic_interface_enabled = 0x400052ec; -is_lmac_idle = 0x400052f8; -lmacAdjustTimestamp = 0x40005304; -lmacDiscardAgedMSDU = 0x40005310; -lmacDiscardMSDU = 0x4000531c; -lmacEndFrameExchangeSequence = 0x40005328; -lmacIsIdle = 0x40005334; -lmacIsLongFrame = 0x40005340; -lmacMSDUAged = 0x4000534c; -lmacPostTxComplete = 0x40005358; -lmacProcessAllTxTimeout = 0x40005364; -lmacProcessCollisions = 0x40005370; -lmacProcessRxSucData = 0x4000537c; -lmacReachLongLimit = 0x40005388; -lmacReachShortLimit = 0x40005394; -lmacRecycleMPDU = 0x400053a0; -lmacRxDone = 0x400053ac; -lmacSetTxFrame = 0x400053b8; -lmacTxDone = 0x400053c4; -lmacTxFrame = 0x400053d0; -mac_tx_set_duration = 0x400053dc; -mac_tx_set_htsig = 0x400053e8; -mac_tx_set_plcp0 = 0x400053f4; -mac_tx_set_plcp1 = 0x40005400; -mac_tx_set_plcp2 = 0x4000540c; -pm_check_state = 0x40005418; -pm_disable_dream_timer = 0x40005424; -pm_disable_sleep_delay_timer = 0x40005430; -pm_dream = 0x4000543c; -pm_mac_wakeup = 0x40005448; -pm_mac_sleep = 0x40005454; -pm_enable_active_timer = 0x40005460; -pm_enable_sleep_delay_timer = 0x4000546c; -pm_local_tsf_process = 0x40005478; -pm_set_beacon_filter = 0x40005484; -pm_is_in_wifi_slice_threshold = 0x40005490; -pm_is_waked = 0x4000549c; -pm_keep_alive = 0x400054a8; -pm_on_beacon_rx = 0x400054b4; -pm_on_data_rx = 0x400054c0; -pm_on_tbtt = 0x400054cc; -pm_parse_beacon = 0x400054d8; -pm_process_tim = 0x400054e4; -pm_rx_beacon_process = 0x400054f0; -pm_rx_data_process = 0x400054fc; -pm_sleep = 0x40005508; -pm_sleep_for = 0x40005514; -pm_tbtt_process = 0x40005520; -ppAMPDU2Normal = 0x4000552c; -ppAssembleAMPDU = 0x40005538; -ppCalFrameTimes = 0x40005544; -ppCalSubFrameLength = 0x40005550; -ppCalTxAMPDULength = 0x4000555c; -ppCheckTxAMPDUlength = 0x40005568; -ppDequeueRxq_Locked = 0x40005574; -ppDequeueTxQ = 0x40005580; -ppEmptyDelimiterLength = 0x4000558c; -ppEnqueueRxq = 0x40005598; -ppEnqueueTxDone = 0x400055a4; -ppGetTxQFirstAvail_Locked = 0x400055b0; -ppGetTxframe = 0x400055bc; -ppMapTxQueue = 0x400055c8; -ppProcTxSecFrame = 0x400055d4; -ppProcessRxPktHdr = 0x400055e0; -ppProcessTxQ = 0x400055ec; -ppRecordBarRRC = 0x400055f8; -lmacRequestTxopQueue = 0x40005604; -lmacReleaseTxopQueue = 0x40005610; -ppRecycleAmpdu = 0x4000561c; -ppRecycleRxPkt = 0x40005628; -ppResortTxAMPDU = 0x40005634; -ppResumeTxAMPDU = 0x40005640; -ppRxFragmentProc = 0x4000564c; -ppRxPkt = 0x40005658; -ppRxProtoProc = 0x40005664; -ppSearchTxQueue = 0x40005670; -ppSearchTxframe = 0x4000567c; -ppSelectNextQueue = 0x40005688; -ppSubFromAMPDU = 0x40005694; -ppTask = 0x400056a0; -ppTxPkt = 0x400056ac; -ppTxProtoProc = 0x400056b8; -ppTxqUpdateBitmap = 0x400056c4; -pp_coex_tx_request = 0x400056d0; -pp_hdrsize = 0x400056dc; -pp_post = 0x400056e8; -pp_process_hmac_waiting_txq = 0x400056f4; -rcGetAmpduSched = 0x40005700; -rcUpdateRxDone = 0x4000570c; -rc_get_trc = 0x40005718; -rc_get_trc_by_index = 0x40005724; -rcAmpduLowerRate = 0x40005730; -rcampduuprate = 0x4000573c; -rcClearCurAMPDUSched = 0x40005748; -rcClearCurSched = 0x40005754; -rcClearCurStat = 0x40005760; -rcGetSched = 0x4000576c; -rcLowerSched = 0x40005778; -rcSetTxAmpduLimit = 0x40005784; -rcTxUpdatePer = 0x40005790; -rcUpdateAckSnr = 0x4000579c; -rcUpdateRate = 0x400057a8; -rcUpdateTxDone = 0x400057b4; -rcUpdateTxDoneAmpdu2 = 0x400057c0; -rcUpSched = 0x400057cc; -rssi_margin = 0x400057d8; -rx11NRate2AMPDULimit = 0x400057e4; -TRC_AMPDU_PER_DOWN_THRESHOLD = 0x400057f0; -TRC_AMPDU_PER_UP_THRESHOLD = 0x400057fc; -trc_calc_duration = 0x40005808; -trc_isTxAmpduOperational = 0x40005814; -trc_onAmpduOp = 0x40005820; -TRC_PER_IS_GOOD = 0x4000582c; -trc_SetTxAmpduState = 0x40005838; -trc_tid_isTxAmpduOperational = 0x40005844; -trcAmpduSetState = 0x40005850; -wDevCheckBlockError = 0x4000585c; -wDev_AppendRxBlocks = 0x40005868; -wDev_DiscardFrame = 0x40005874; -wDev_GetNoiseFloor = 0x40005880; -wDev_IndicateAmpdu = 0x4000588c; -wDev_IndicateFrame = 0x40005898; -wdev_bank_store = 0x400058a4; -wdev_bank_load = 0x400058b0; -wdev_mac_reg_load = 0x400058bc; -wdev_mac_reg_store = 0x400058c8; -wdev_mac_special_reg_load = 0x400058d4; -wdev_mac_special_reg_store = 0x400058e0; -wdev_mac_wakeup = 0x400058ec; -wdev_mac_sleep = 0x400058f8; -hal_mac_is_dma_enable = 0x40005904; -wDev_ProcessFiq = 0x40005910; -wDev_ProcessRxSucData = 0x4000591c; -wdevProcessRxSucDataAll = 0x40005928; -wdev_csi_len_align = 0x40005934; -ppDequeueTxDone_Locked = 0x40005940; -ppProcTxDone = 0x4000594c; -pm_tx_data_done_process = 0x40005958; -config_is_cache_tx_buf_enabled = 0x40005964; -ppMapWaitTxq = 0x40005970; -ppProcessWaitingQueue = 0x4000597c; -ppDisableQueue = 0x40005988; -pm_allow_tx = 0x40005994; -wdev_is_data_in_rxlist = 0x400059a0; -ppProcTxCallback = 0x400059ac; -/* Data (.data, .bss, .rodata) */ -our_instances_ptr = 0x3ff1ee58; -pTxRx = 0x3fcef954; -lmacConfMib_ptr = 0x3fcef950; -our_wait_eb = 0x3fcef94c; -our_tx_eb = 0x3fcef948; -pp_wdev_funcs = 0x3fcef944; -g_osi_funcs_p = 0x3fcef940; -wDevCtrl_ptr = 0x3fcef93c; -g_wdev_last_desc_reset_ptr = 0x3ff1ee54; -wDevMacSleep_ptr = 0x3fcef938; -g_lmac_cnt_ptr = 0x3fcef934; -our_controls_ptr = 0x3ff1ee50; -pp_sig_cnt_ptr = 0x3fcef930; -g_eb_list_desc_ptr = 0x3fcef92c; -s_fragment_ptr = 0x3fcef928; -if_ctrl_ptr = 0x3fcef924; -g_intr_lock_mux = 0x3fcef920; -g_wifi_global_lock = 0x3fcef91c; -s_wifi_queue = 0x3fcef918; -pp_task_hdl = 0x3fcef914; -s_pp_task_create_sem = 0x3fcef910; -s_pp_task_del_sem = 0x3fcef90c; -g_wifi_menuconfig_ptr = 0x3fcef908; -xphyQueue = 0x3fcef904; -ap_no_lr_ptr = 0x3fcef900; -rc11BSchedTbl_ptr = 0x3fcef8fc; -rc11NSchedTbl_ptr = 0x3fcef8f8; -rcLoRaSchedTbl_ptr = 0x3fcef8f4; -BasicOFDMSched_ptr = 0x3fcef8f0; -trc_ctl_ptr = 0x3fcef8ec; -g_pm_cnt_ptr = 0x3fcef8e8; -g_pm_ptr = 0x3fcef8e4; -g_pm_cfg_ptr = 0x3fcef8e0; -g_esp_mesh_quick_funcs_ptr = 0x3fcef8dc; -g_txop_queue_status_ptr = 0x3fcef8d8; -g_mac_sleep_en_ptr = 0x3fcef8d4; -g_mesh_is_root_ptr = 0x3fcef8d0; -g_mesh_topology_ptr = 0x3fcef8cc; -g_mesh_init_ps_type_ptr = 0x3fcef8c8; -g_mesh_is_started_ptr = 0x3fcef8c4; -g_config_func = 0x3fcef8c0; -g_net80211_tx_func = 0x3fcef8bc; -g_timer_func = 0x3fcef8b8; -s_michael_mic_failure_cb = 0x3fcef8b4; -wifi_sta_rx_probe_req = 0x3fcef8b0; -g_tx_done_cb_func = 0x3fcef8ac; -g_per_conn_trc = 0x3fcef860; -s_encap_amsdu_func = 0x3fcef85c; - - -/*************************************** - Group rom_net80211 - ***************************************/ - -/* Functions */ -esp_net80211_rom_version_get = 0x400059b8; -ampdu_dispatch = 0x400059c4; -ampdu_dispatch_all = 0x400059d0; -ampdu_dispatch_as_many_as_possible = 0x400059dc; -ampdu_dispatch_movement = 0x400059e8; -ampdu_dispatch_upto = 0x400059f4; -chm_is_at_home_channel = 0x40005a00; -cnx_node_is_existing = 0x40005a0c; -cnx_node_search = 0x40005a18; -ic_ebuf_recycle_rx = 0x40005a24; -ic_ebuf_recycle_tx = 0x40005a30; -ic_reset_rx_ba = 0x40005a3c; -ieee80211_align_eb = 0x40005a48; -ieee80211_ampdu_reorder = 0x40005a54; -ieee80211_ampdu_start_age_timer = 0x40005a60; -ieee80211_encap_esfbuf = 0x40005a6c; -ieee80211_is_tx_allowed = 0x40005a78; -ieee80211_output_pending_eb = 0x40005a84; -ieee80211_output_process = 0x40005a90; -ieee80211_set_tx_desc = 0x40005a9c; -sta_input = 0x40005aa8; -wifi_get_macaddr = 0x40005ab4; -wifi_rf_phy_disable = 0x40005ac0; -wifi_rf_phy_enable = 0x40005acc; -ic_ebuf_alloc = 0x40005ad8; -ieee80211_classify = 0x40005ae4; -ieee80211_copy_eb_header = 0x40005af0; -ieee80211_recycle_cache_eb = 0x40005afc; -ieee80211_search_node = 0x40005b08; -roundup2 = 0x40005b14; -ieee80211_crypto_encap = 0x40005b20; -ieee80211_crypto_decap = 0x40005b2c; -ieee80211_decap = 0x40005b38; -ieee80211_set_tx_pti = 0x40005b44; -wifi_is_started = 0x40005b50; -ieee80211_gettid = 0x40005b5c; -/* Data (.data, .bss, .rodata) */ -net80211_funcs = 0x3fcef858; -g_scan = 0x3fcef854; -g_chm = 0x3fcef850; -g_ic_ptr = 0x3fcef84c; -g_hmac_cnt_ptr = 0x3fcef848; -g_tx_cacheq_ptr = 0x3fcef844; -s_netstack_free = 0x3fcef840; -mesh_rxcb = 0x3fcef83c; -sta_rxcb = 0x3fcef838; - - -/*************************************** - Group rom_coexist - ***************************************/ - -/* Functions */ -esp_coex_rom_version_get = 0x40005b68; -coex_bt_release = 0x40005b74; -coex_bt_request = 0x40005b80; -coex_core_ble_conn_dyn_prio_get = 0x40005b8c; -coex_core_event_duration_get = 0x40005b98; -coex_core_pti_get = 0x40005ba4; -coex_core_release = 0x40005bb0; -coex_core_request = 0x40005bbc; -coex_core_status_get = 0x40005bc8; -coex_core_timer_idx_get = 0x40005bd4; -coex_event_duration_get = 0x40005be0; -coex_hw_timer_disable = 0x40005bec; -coex_hw_timer_enable = 0x40005bf8; -coex_hw_timer_set = 0x40005c04; -coex_schm_interval_set = 0x40005c10; -coex_schm_lock = 0x40005c1c; -coex_schm_unlock = 0x40005c28; -coex_status_get = 0x40005c34; -coex_wifi_release = 0x40005c40; -esp_coex_ble_conn_dynamic_prio_get = 0x40005c4c; -/* Data (.data, .bss, .rodata) */ -coex_env_ptr = 0x3fcef834; -coex_pti_tab_ptr = 0x3fcef830; -coex_schm_env_ptr = 0x3fcef82c; -coexist_funcs = 0x3fcef828; -g_coa_funcs_p = 0x3fcef824; -g_coex_param_ptr = 0x3fcef820; - - -/*************************************** - Group rom_phy - ***************************************/ - -/* Functions */ -phy_get_romfuncs = 0x40005c58; -rom_abs_temp = 0x40005c64; -rom_bb_bss_cbw40_dig = 0x40005c70; -rom_bb_wdg_test_en = 0x40005c7c; -rom_bb_wdt_get_status = 0x40005c88; -rom_bb_wdt_int_enable = 0x40005c94; -rom_bb_wdt_rst_enable = 0x40005ca0; -rom_bb_wdt_timeout_clear = 0x40005cac; -rom_cbw2040_cfg = 0x40005cb8; -rom_check_noise_floor = 0x40005cc4; -rom_chip_i2c_readReg = 0x40005cd0; -rom_chip_i2c_writeReg = 0x40005cdc; -rom_dc_iq_est = 0x40005ce8; -rom_disable_agc = 0x40005cf4; -rom_en_pwdet = 0x40005d00; -rom_enable_agc = 0x40005d0c; -rom_get_bbgain_db = 0x40005d18; -rom_get_data_sat = 0x40005d24; -rom_get_i2c_read_mask = 0x40005d30; -rom_get_pwctrl_correct = 0x40005d3c; -rom_i2c_readReg = 0x40005d48; -rom_i2c_readReg_Mask = 0x40005d54; -rom_i2c_writeReg = 0x40005d60; -rom_i2c_writeReg_Mask = 0x40005d6c; -rom_index_to_txbbgain = 0x40005d78; -rom_iq_est_disable = 0x40005d84; -rom_iq_est_enable = 0x40005d90; -rom_linear_to_db = 0x40005d9c; -rom_loopback_mode_en = 0x40005da8; -rom_mhz2ieee = 0x40005db4; -rom_noise_floor_auto_set = 0x40005dc0; -rom_pbus_debugmode = 0x40005dcc; -rom_pbus_force_mode = 0x40005dd8; -rom_pbus_force_test = 0x40005de4; -rom_pbus_rd = 0x40005df0; -rom_pbus_rd_addr = 0x40005dfc; -rom_pbus_rd_shift = 0x40005e08; -rom_pbus_set_dco = 0x40005e14; -rom_pbus_set_rxgain = 0x40005e20; -rom_pbus_workmode = 0x40005e2c; -rom_pbus_xpd_rx_off = 0x40005e38; -rom_pbus_xpd_rx_on = 0x40005e44; -rom_pbus_xpd_tx_off = 0x40005e50; -rom_pbus_xpd_tx_on = 0x40005e5c; -rom_phy_byte_to_word = 0x40005e68; -rom_phy_disable_cca = 0x40005e74; -rom_phy_enable_cca = 0x40005e80; -rom_phy_get_noisefloor = 0x40005e8c; -rom_phy_get_rx_freq = 0x40005e98; -rom_phy_set_bbfreq_init = 0x40005ea4; -rom_pow_usr = 0x40005eb0; -rom_pwdet_sar2_init = 0x40005ebc; -rom_read_hw_noisefloor = 0x40005ec8; -rom_read_sar_dout = 0x40005ed4; -rom_set_cal_rxdc = 0x40005ee0; -rom_set_chan_cal_interp = 0x40005eec; -rom_set_loopback_gain = 0x40005ef8; -rom_set_noise_floor = 0x40005f04; -rom_set_rxclk_en = 0x40005f10; -rom_set_tx_dig_gain = 0x40005f1c; -rom_set_txcap_reg = 0x40005f28; -rom_set_txclk_en = 0x40005f34; -rom_spur_cal = 0x40005f40; -rom_spur_reg_write_one_tone = 0x40005f4c; -rom_target_power_add_backoff = 0x40005f58; -rom_tx_pwctrl_bg_init = 0x40005f64; -rom_txbbgain_to_index = 0x40005f70; -rom_wifi_11g_rate_chg = 0x40005f7c; -rom_write_gain_mem = 0x40005f88; -chip728_phyrom_version = 0x40005f94; -rom_disable_wifi_agc = 0x40005fa0; -rom_enable_wifi_agc = 0x40005fac; -rom_bt_index_to_bb = 0x40005fb8; -rom_bt_bb_to_index = 0x40005fc4; -rom_spur_coef_cfg = 0x40005fd0; -rom_bb_bss_cbw40 = 0x40005fdc; -rom_set_cca = 0x40005fe8; -rom_tx_paon_set = 0x40005ff4; -rom_i2cmst_reg_init = 0x40006000; -rom_iq_corr_enable = 0x4000600c; -rom_fe_reg_init = 0x40006018; -rom_agc_reg_init = 0x40006024; -rom_bb_reg_init = 0x40006030; -rom_mac_enable_bb = 0x4000603c; -rom_bb_wdg_cfg = 0x40006048; -rom_force_txon = 0x40006054; -rom_fe_txrx_reset = 0x40006060; -rom_set_rx_comp = 0x4000606c; -rom_set_pbus_reg = 0x40006078; -rom_write_chan_freq = 0x40006084; -rom_phy_xpd_rf = 0x40006090; -rom_set_xpd_sar = 0x4000609c; -rom_get_target_power_offset = 0x400060a8; -rom_write_txrate_power_offset = 0x400060b4; -rom_get_rate_fcc_index = 0x400060c0; -rom_get_rate_target_power = 0x400060cc; -rom_pkdet_vol_start = 0x400060d8; -rom_read_sar2_code = 0x400060e4; -rom_get_sar2_vol = 0x400060f0; -rom_get_pll_vol = 0x400060fc; -rom_get_phy_target_power = 0x40006108; -rom_temp_to_power = 0x40006114; -rom_phy_track_pll_cap = 0x40006120; -rom_phy_pwdet_always_en = 0x4000612c; -rom_phy_pwdet_onetime_en = 0x40006138; -rom_get_i2c_mst0_mask = 0x40006144; -rom_get_i2c_hostid = 0x40006150; -rom_enter_critical_phy = 0x4000615c; -rom_exit_critical_phy = 0x40006168; -rom_chip_i2c_readReg_org = 0x40006174; -rom_i2c_paral_set_mst0 = 0x40006180; -rom_i2c_paral_set_read = 0x4000618c; -rom_i2c_paral_read = 0x40006198; -rom_i2c_paral_write = 0x400061a4; -rom_i2c_paral_write_num = 0x400061b0; -rom_i2c_paral_write_mask = 0x400061bc; -rom_bb_bss_cbw40_ana = 0x400061c8; -rom_chan_to_freq = 0x400061d4; -rom_open_i2c_xpd = 0x400061e0; -rom_dac_rate_set = 0x400061ec; -rom_tsens_read_init = 0x400061f8; -rom_tsens_code_read = 0x40006204; -rom_tsens_index_to_dac = 0x40006210; -rom_tsens_index_to_offset = 0x4000621c; -rom_tsens_dac_cal = 0x40006228; -rom_code_to_temp = 0x40006234; -rom_write_pll_cap_mem = 0x40006240; -rom_pll_correct_dcap = 0x4000624c; -rom_phy_en_hw_set_freq = 0x40006258; -rom_phy_dis_hw_set_freq = 0x40006264; -rom_pll_vol_cal = 0x40006270; -rom_wrtie_pll_cap = 0x4000627c; -rom_set_tx_gain_mem = 0x40006288; -rom_bt_tx_dig_gain = 0x40006294; -rom_bt_get_tx_gain = 0x400062a0; -rom_get_chan_target_power = 0x400062ac; -rom_get_tx_gain_value = 0x400062b8; -rom_wifi_tx_dig_gain = 0x400062c4; -rom_wifi_get_tx_gain = 0x400062d0; -rom_fe_i2c_reg_renew = 0x400062dc; -rom_wifi_agc_sat_gain = 0x400062e8; -rom_i2c_master_reset = 0x400062f4; -rom_bt_filter_reg = 0x40006300; -rom_phy_bbpll_cal = 0x4000630c; -rom_i2c_sar2_init_code = 0x40006318; -rom_phy_param_addr = 0x40006324; -rom_phy_reg_init = 0x40006330; -rom_set_chan_reg = 0x4000633c; -rom_phy_wakeup_init = 0x40006348; -rom_phy_i2c_init1 = 0x40006354; -rom_tsens_temp_read = 0x40006360; -rom_bt_track_pll_cap = 0x4000636c; -rom_wifi_track_pll_cap = 0x40006378; -rom_wifi_set_tx_gain = 0x40006384; -rom_txpwr_cal_track = 0x40006390; -rom_tx_pwctrl_background = 0x4000639c; -rom_bt_set_tx_gain = 0x400063a8; -rom_noise_check_loop = 0x400063b4; -rom_phy_close_rf = 0x400063c0; -rom_phy_xpd_tsens = 0x400063cc; -rom_phy_freq_mem_backup = 0x400063d8; -rom_phy_ant_init = 0x400063e4; -rom_bt_track_tx_power = 0x400063f0; -rom_wifi_track_tx_power = 0x400063fc; -rom_phy_dig_reg_backup = 0x40006408; -chip728_phyrom_version_num = 0x40006414; -rom_mac_tx_chan_offset = 0x40006420; -rom_rx_gain_force = 0x4000642c; -/* Data (.data, .bss, .rodata) */ -phy_param_rom = 0x3fcef81c; diff --git a/tools/esptool_py/flasher_stub/ld/rom_32s3_beta_2.ld b/tools/esptool_py/flasher_stub/ld/rom_32s3_beta_2.ld deleted file mode 100644 index eb2ce03153..0000000000 --- a/tools/esptool_py/flasher_stub/ld/rom_32s3_beta_2.ld +++ /dev/null @@ -1,2397 +0,0 @@ -/* -ESP32-S3 ROM address table -Generated for ROM with MD5sum: -d20fb231463ce337432b1fa9cba0b3c9 eagle.pro.rom.out -*/ -PROVIDE ( aa_gen = 0x3fcefa9c ); -PROVIDE ( abort = 0x400544a4 ); -PROVIDE ( abs = 0x40032344 ); -PROVIDE ( __absvdi2 = 0x40037f14 ); -PROVIDE ( __absvsi2 = 0x40037f00 ); -PROVIDE ( acm_config_descr = 0x3ff0c257 ); -PROVIDE ( acm_usb_descriptors = 0x3ff0c1b4 ); -PROVIDE ( __adddf3 = 0x4003bd5c ); -PROVIDE ( __addsf3 = 0x4003b9f0 ); -PROVIDE ( __addvdi3 = 0x4003c488 ); -PROVIDE ( __addvsi3 = 0x4003c464 ); -PROVIDE ( aes_cmac_zero = 0x3ff07782 ); -PROVIDE ( aes_env = 0x3fcef8c4 ); -PROVIDE ( aes_k2_salt = 0x3ff07792 ); -PROVIDE ( aes_k3_id64 = 0x3ff077a2 ); -PROVIDE ( aes_k3_salt = 0x3ff077a7 ); -PROVIDE ( aes_k4_id6 = 0x3ff077b7 ); -PROVIDE ( aes_k4_salt = 0x3ff077bb ); -PROVIDE ( analog_super_wdt_reset = 0x3fcefcc6 ); -PROVIDE ( analog_super_wdt_reset_happened = 0x40045a3c ); -PROVIDE ( __ascii_mbtowc = 0x40039ec4 ); -PROVIDE ( __ascii_wctomb = 0x40033cb0 ); -PROVIDE ( __ashldi3 = 0x40055928 ); -PROVIDE ( __ashrdi3 = 0x40055940 ); -PROVIDE ( __assert = 0x40054a5c ); -PROVIDE ( __assert_func = 0x40054a30 ); -PROVIDE ( atoi = 0x40032984 ); -PROVIDE ( _atoi_r = 0x40032994 ); -PROVIDE ( atol = 0x400329ac ); -PROVIDE ( _atol_r = 0x400329bc ); -PROVIDE ( BasePoint_x_256 = 0x3ff08238 ); -PROVIDE ( BasePoint_y_256 = 0x3ff08218 ); -PROVIDE ( bigHexP256 = 0x3ff08140 ); -PROVIDE ( boot_prepare = 0x40044ef4 ); -PROVIDE ( __bswapdi2 = 0x40039054 ); -PROVIDE ( __bswapsi2 = 0x4003902c ); -PROVIDE ( btdm_con_maxevtime_cal_impl = 0x40017018 ); -PROVIDE ( btdm_controller_get_compile_version_impl = 0x40001234 ); -PROVIDE ( btdm_disable_adv_delay_impl = 0x40014788 ); -PROVIDE ( btdm_dis_privacy_err_report_impl = 0x4001ddb0 ); -PROVIDE ( btdm_enable_scan_continue_impl = 0x4001d7f8 ); -PROVIDE ( btdm_enable_scan_forever_impl = 0x4002344c ); -PROVIDE ( btdm_env_p = 0x3fcef464 ); -PROVIDE ( btdm_get_power_state_impl = 0x4002ffbc ); -PROVIDE ( btdm_get_prevent_sleep_flag_impl = 0x4002ffc8 ); -PROVIDE ( btdm_power_state_active_impl = 0x4002ffa8 ); -PROVIDE ( btdm_pwr_state = 0x3fcefb90 ); -PROVIDE ( btdm_slp_err = 0x3fcefb48 ); -PROVIDE ( btdm_switch_phy_coded_impl = 0x4001d77c ); -PROVIDE ( bt_rf_coex_cfg_cb = 0x3fcefad0 ); -PROVIDE ( bt_rf_coex_cfg_p = 0x3fcefacc ); -PROVIDE ( bt_rf_coex_get_dft_cfg = 0x4002e518 ); -PROVIDE ( bt_rf_coex_hooks_p = 0x3fcef694 ); -PROVIDE ( bt_rf_coex_hooks_p_set = 0x4002e4e4 ); -PROVIDE ( byte_tx_time = 0x3ff08d44 ); -PROVIDE ( bzero = 0x40039d84 ); -PROVIDE ( Cache_Address_Through_DCache = 0x40051ebc ); -PROVIDE ( Cache_Address_Through_ICache = 0x40051ea4 ); -PROVIDE ( Cache_Clean_Addr = 0x40052458 ); -PROVIDE ( Cache_Clean_All = 0x40052518 ); -PROVIDE ( Cache_Clean_Items = 0x40051fe8 ); -PROVIDE ( Cache_Config_DCache_Autoload = 0x40052828 ); -PROVIDE ( Cache_Config_ICache_Autoload = 0x400526dc ); -PROVIDE ( Cache_Count_Flash_Pages = 0x40053088 ); -PROVIDE ( Cache_Dbus_MMU_Set = 0x40053004 ); -PROVIDE ( Cache_DCache_Preload_Done = 0x400526a0 ); -PROVIDE ( Cache_Disable_DCache = 0x40052be4 ); -PROVIDE ( Cache_Disable_DCache_Autoload = 0x40052924 ); -PROVIDE ( Cache_Disable_DCache_PreLock = 0x40052a74 ); -PROVIDE ( Cache_Disable_ICache = 0x40052b70 ); -PROVIDE ( Cache_Disable_ICache_Autoload = 0x400527d8 ); -PROVIDE ( Cache_Disable_ICache_PreLock = 0x400529dc ); -PROVIDE ( Cache_Enable_DCache = 0x40052c34 ); -PROVIDE ( Cache_Enable_DCache_Autoload = 0x4005290c ); -PROVIDE ( Cache_Enable_DCache_PreLock = 0x40052a0c ); -PROVIDE ( Cache_Enable_Defalut_ICache_Mode = 0x40051f1c ); -PROVIDE ( Cache_Enable_ICache = 0x40052bc0 ); -PROVIDE ( Cache_Enable_ICache_Autoload = 0x400527c0 ); -PROVIDE ( Cache_Enable_ICache_PreLock = 0x40052974 ); -PROVIDE ( Cache_End_DCache_Preload = 0x400526b4 ); -PROVIDE ( Cache_End_ICache_Preload = 0x40052614 ); -PROVIDE ( Cache_Flash_To_SPIRAM_Copy = 0x400530e4 ); -PROVIDE ( Cache_Freeze_DCache_Disable = 0x40052390 ); -PROVIDE ( Cache_Freeze_DCache_Enable = 0x40052354 ); -PROVIDE ( Cache_Freeze_ICache_Disable = 0x4005232c ); -PROVIDE ( Cache_Freeze_ICache_Enable = 0x400522f0 ); -PROVIDE ( Cache_Get_DCache_Line_Size = 0x40051d90 ); -PROVIDE ( Cache_Get_DROM_MMU_End = 0x40052e9c ); -PROVIDE ( Cache_Get_ICache_Line_Size = 0x40051d78 ); -PROVIDE ( Cache_Get_IROM_MMU_End = 0x40052e90 ); -PROVIDE ( Cache_Get_Memory_Addr = 0x4005352c ); -PROVIDE ( Cache_Get_Memory_BaseAddr = 0x400534b8 ); -PROVIDE ( Cache_Get_Memory_value = 0x40053574 ); -PROVIDE ( Cache_Get_Mode = 0x40051dac ); -PROVIDE ( Cache_Get_Virtual_Addr = 0x40053480 ); -PROVIDE ( Cache_Ibus_MMU_Set = 0x40052f80 ); -PROVIDE ( Cache_ICache_Preload_Done = 0x40052600 ); -PROVIDE ( cache_internal_table_ptr = 0x3fcefc70 ); -PROVIDE ( Cache_Invalidate_Addr = 0x400523ec ); -PROVIDE ( Cache_Invalidate_DCache_All = 0x40052504 ); -PROVIDE ( Cache_Invalidate_DCache_Items = 0x40051fa0 ); -PROVIDE ( Cache_Invalidate_ICache_All = 0x400524f0 ); -PROVIDE ( Cache_Invalidate_ICache_Items = 0x40051f4c ); -PROVIDE ( Cache_Lock_Addr = 0x40052a94 ); -PROVIDE ( Cache_Lock_DCache_Items = 0x40052214 ); -PROVIDE ( Cache_Lock_ICache_Items = 0x40052180 ); -PROVIDE ( Cache_Mask_All = 0x40052548 ); -PROVIDE ( cache_memory_baseaddrs = 0x3ff0c4c4 ); -PROVIDE ( Cache_MMU_Init = 0x40052f64 ); -PROVIDE ( Cache_Occupy_Addr = 0x40052d70 ); -PROVIDE ( Cache_Occupy_DCache_MEMORY = 0x40052f18 ); -PROVIDE ( Cache_Occupy_ICache_MEMORY = 0x40052ed4 ); -PROVIDE ( Cache_Occupy_Items = 0x400522a8 ); -PROVIDE ( Cache_Op_Addr = 0x4005207c ); -PROVIDE ( cache_op_cb = 0x3fcefc7c ); -PROVIDE ( Cache_Owner_Init = 0x40052eb4 ); -PROVIDE ( Cache_Resume_DCache = 0x40052d38 ); -PROVIDE ( Cache_Resume_DCache_Autoload = 0x400523d0 ); -PROVIDE ( Cache_Resume_ICache = 0x40052cac ); -PROVIDE ( Cache_Resume_ICache_Autoload = 0x400523b4 ); -PROVIDE ( Cache_Set_DCache_Mode = 0x40051e68 ); -PROVIDE ( Cache_Set_Default_Mode = 0x40051ed4 ); -PROVIDE ( Cache_Set_ICache_Mode = 0x40051e14 ); -PROVIDE ( Cache_Set_IDROM_MMU_Info = 0x40052e6c ); -PROVIDE ( Cache_Set_IDROM_MMU_Size = 0x40052dd0 ); -PROVIDE ( Cache_Start_DCache_Preload = 0x40052634 ); -PROVIDE ( Cache_Start_ICache_Preload = 0x40052594 ); -PROVIDE ( Cache_Suspend_DCache = 0x40052ce4 ); -PROVIDE ( Cache_Suspend_DCache_Autoload = 0x40052140 ); -PROVIDE ( Cache_Suspend_ICache = 0x40052c58 ); -PROVIDE ( Cache_Suspend_ICache_Autoload = 0x40052108 ); -PROVIDE ( Cache_Travel_Tag_Memory = 0x400531c0 ); -PROVIDE ( Cache_Unlock_Addr = 0x40052b00 ); -PROVIDE ( Cache_Unlock_DCache_Items = 0x40052258 ); -PROVIDE ( Cache_Unlock_ICache_Items = 0x400521c4 ); -PROVIDE ( Cache_UnMask_Dram0 = 0x40052570 ); -PROVIDE ( Cache_WriteBack_Addr = 0x400524a4 ); -PROVIDE ( Cache_WriteBack_All = 0x4005252c ); -PROVIDE ( Cache_WriteBack_Items = 0x40052030 ); -PROVIDE ( cacl_rtc_memory_crc = 0x40045b04 ); -PROVIDE ( calloc = 0x400547e4 ); -PROVIDE ( _calloc_r = 0x400544f8 ); -PROVIDE ( cdc_acm_class_handle_req = 0x40049da4 ); -PROVIDE ( cdc_acm_config = 0x3fcef044 ); -PROVIDE ( cdc_acm_dev = 0x3fcef340 ); -PROVIDE ( cdc_acm_fifo_fill = 0x40049ee0 ); -PROVIDE ( cdc_acm_fifo_read = 0x40049f54 ); -PROVIDE ( cdc_acm_init = 0x40049e98 ); -PROVIDE ( cdc_acm_irq_callback_set = 0x4004a028 ); -PROVIDE ( cdc_acm_irq_is_pending = 0x4004a004 ); -PROVIDE ( cdc_acm_irq_rx_disable = 0x40049fe4 ); -PROVIDE ( cdc_acm_irq_rx_enable = 0x40049fd8 ); -PROVIDE ( cdc_acm_irq_rx_ready = 0x40049ff0 ); -PROVIDE ( cdc_acm_irq_state_disable = 0x40049fb8 ); -PROVIDE ( cdc_acm_irq_state_enable = 0x40049fac ); -PROVIDE ( cdc_acm_irq_tx_disable = 0x40049fa0 ); -PROVIDE ( cdc_acm_irq_tx_enable = 0x40049f94 ); -PROVIDE ( cdc_acm_irq_tx_ready = 0x40049fc4 ); -PROVIDE ( cdc_acm_line_ctrl_get = 0x4004a084 ); -PROVIDE ( cdc_acm_line_ctrl_set = 0x4004a030 ); -PROVIDE ( cdc_acm_poll_out = 0x4004a0b4 ); -PROVIDE ( cdc_acm_rx_fifo_cnt = 0x40049f40 ); -PROVIDE ( chip725_phyrom_version = 0x4003edec ); -PROVIDE ( chip_usb_detach = 0x4004a250 ); -PROVIDE ( chip_usb_dw_did_persist = 0x4004a0d0 ); -PROVIDE ( chip_usb_dw_init = 0x4004a104 ); -PROVIDE ( chip_usb_dw_prepare_persist = 0x4004a2cc ); -PROVIDE ( chip_usb_get_persist_flags = 0x4004a31c ); -PROVIDE ( chip_usb_set_persist_flags = 0x4004a32c ); -PROVIDE ( _cleanup = 0x40054ae4 ); -PROVIDE ( _cleanup_r = 0x40054a6c ); -PROVIDE ( __clear_cache = 0x40037ef8 ); -PROVIDE ( clear_super_wdt_reset_flag = 0x40045bc8 ); -PROVIDE ( close = 0x4003b8ec ); -PROVIDE ( _close_r = 0x4005463c ); -PROVIDE ( __clrsbdi2 = 0x400390c8 ); -PROVIDE ( __clrsbsi2 = 0x400390b0 ); -PROVIDE ( __clzdi2 = 0x40055bbc ); -PROVIDE ( __clzsi2 = 0x400558f8 ); -PROVIDE ( __cmpdi2 = 0x40037eb8 ); -PROVIDE ( co_default_bdaddr = 0x3fcef398 ); -PROVIDE ( coef_B = 0x3ff0816c ); -PROVIDE ( connect_req_dur_tab = 0x3ff08d4c ); -PROVIDE ( context = 0x3fcee134 ); -PROVIDE ( co_null_bdaddr = 0x3ff077ec ); -PROVIDE ( co_phy_mask_to_rate = 0x3ff077d1 ); -PROVIDE ( co_phy_mask_to_value = 0x3ff077de ); -PROVIDE ( co_phy_to_rate = 0x3ff077e3 ); -PROVIDE ( co_phy_value_to_mask = 0x3ff077da ); -PROVIDE ( co_rate_to_byte_dur_us = 0x3ff077cc ); -PROVIDE ( co_rate_to_phy = 0x3ff077e7 ); -PROVIDE ( co_rate_to_phy_mask = 0x3ff077d6 ); -PROVIDE ( co_sca2ppm = 0x3ff077f2 ); -PROVIDE ( cpio_destroy = 0x4004c76c ); -PROVIDE ( cpio_done = 0x4004c738 ); -PROVIDE ( cpio_feed = 0x4004c438 ); -PROVIDE ( cpio_start = 0x4004c3ec ); -PROVIDE ( crc16_be = 0x400477b8 ); -PROVIDE ( crc16_le = 0x4004777c ); -PROVIDE ( crc32_be = 0x40047748 ); -PROVIDE ( crc32_le = 0x40047714 ); -PROVIDE ( crc8_be = 0x40047828 ); -PROVIDE ( crc8_le = 0x400477f8 ); -PROVIDE ( creat = 0x40039d48 ); -PROVIDE ( _ctype_ = 0x3ff0732c ); -PROVIDE ( __ctzdi2 = 0x40055bd0 ); -PROVIDE ( __ctzsi2 = 0x40055900 ); -PROVIDE ( _cvt = 0x40045498 ); -PROVIDE ( _data_end_all_app = 0x3fcefff0 ); -PROVIDE ( _data_end_all_pro = 0x3fcefff0 ); -PROVIDE ( _data_end_btdm = 0x3fcef454 ); -PROVIDE ( _data_end_btdm_rom = 0x40056700 ); -PROVIDE ( _data_end_c = 0x3fcefcd0 ); -PROVIDE ( _data_end_cache = 0x3fcefc7c ); -PROVIDE ( _data_end_ets = 0x3fced910 ); -PROVIDE ( _data_end_ets_delay = 0x3fcefcc4 ); -PROVIDE ( _data_end_ets_printf = 0x3fcefcac ); -PROVIDE ( _data_end_ets_rtc = 0x3fcefcc4 ); -PROVIDE ( _data_end_newlib = 0x3fcefcc8 ); -PROVIDE ( _data_end_opi_flash = 0x3fcefca4 ); -PROVIDE ( _data_end_phyrom = 0x3fcefff0 ); -PROVIDE ( _data_end_sip = 0x3fcee174 ); -PROVIDE ( _data_end_slc = 0x3fcee174 ); -PROVIDE ( _data_end_spi_flash = 0x3fcefc10 ); -PROVIDE ( _data_end_spi_slave = 0x3fcee130 ); -PROVIDE ( _data_end_uart = 0x3fcef34c ); -PROVIDE ( _data_end_usbdev = 0x3fcef0c4 ); -PROVIDE ( _data_end_xtos = 0x3fcee590 ); -PROVIDE ( _data_start_all_app = 0x3fcefff0 ); -PROVIDE ( _data_start_all_pro = 0x3fcefff0 ); -PROVIDE ( _data_start_btdm = 0x3fcef390 ); -PROVIDE ( _data_start_btdm_rom = 0x400566fc ); -PROVIDE ( _data_start_c = 0x3fcefccc ); -PROVIDE ( _data_start_cache = 0x3fcefc70 ); -PROVIDE ( _data_start_ets = 0x3fced910 ); -PROVIDE ( _data_start_ets_delay = 0x3fcefcc0 ); -PROVIDE ( _data_start_ets_printf = 0x3fcefcac ); -PROVIDE ( _data_start_ets_rtc = 0x3fcefcc4 ); -PROVIDE ( _data_start_newlib = 0x3fcefcc8 ); -PROVIDE ( _data_start_opi_flash = 0x3fcefca4 ); -PROVIDE ( _data_start_phyrom = 0x3fcefce0 ); -PROVIDE ( _data_start_sip = 0x3fcee174 ); -PROVIDE ( _data_start_slc = 0x3fcee174 ); -PROVIDE ( _data_start_spi_flash = 0x3fcefba8 ); -PROVIDE ( _data_start_spi_slave = 0x3fcee130 ); -PROVIDE ( _data_start_uart = 0x3fcef34c ); -PROVIDE ( _data_start_usbdev = 0x3fcef044 ); -PROVIDE ( _data_start_xtos = 0x3fcee174 ); -PROVIDE ( dbg_sch_plan_act = 0x3fcef914 ); -PROVIDE ( dbg_sch_plan_move_id = 0x3fcef968 ); -PROVIDE ( dbg_state = 0x3fcef96a ); -PROVIDE ( dbg_trc_env = 0x3fcef970 ); -PROVIDE ( dbg_trc_tl_env = 0x3fcef978 ); -PROVIDE ( dbus_baseaddrs = 0x3ff0c4d4 ); -PROVIDE ( DebugE256PublicKey_x = 0x3ff081d8 ); -PROVIDE ( DebugE256PublicKey_y = 0x3ff081b8 ); -PROVIDE ( DebugE256SecretKey = 0x3ff08198 ); -PROVIDE ( _DebugExceptionVector = 0x40000280 ); -PROVIDE ( _DebugExceptionVector_text_end = 0x4000028b ); -PROVIDE ( _DebugExceptionVector_text_start = 0x40000280 ); -PROVIDE ( __default_global_locale = 0x3ff071c0 ); -PROVIDE ( dfu_class_handle_req = 0x4004c0c0 ); -PROVIDE ( dfu_config_descr = 0x3ff0c1fa ); -PROVIDE ( dfu_cpio_callback = 0x4004a34c ); -PROVIDE ( dfu_custom_handle_req = 0x4004c338 ); -PROVIDE ( dfu_flash_attach = 0x4004c804 ); -PROVIDE ( dfu_flash_deinit = 0x4004c784 ); -PROVIDE ( dfu_flash_erase = 0x4004c78c ); -PROVIDE ( dfu_flash_init = 0x4004c774 ); -PROVIDE ( dfu_flash_program = 0x4004c7a0 ); -PROVIDE ( dfu_flash_read = 0x4004c7f4 ); -PROVIDE ( dfu_status_cb = 0x4004c2e4 ); -PROVIDE ( dfu_updater_begin = 0x4004a594 ); -PROVIDE ( dfu_updater_clear_err = 0x4004a550 ); -PROVIDE ( dfu_updater_enable = 0x4004a568 ); -PROVIDE ( dfu_updater_end = 0x4004a640 ); -PROVIDE ( dfu_updater_feed = 0x4004a5f4 ); -PROVIDE ( dfu_updater_flash_read = 0x4004a728 ); -PROVIDE ( dfu_updater_get_err = 0x4004a53c ); -PROVIDE ( dfu_updater_set_raw_addr = 0x4004a714 ); -PROVIDE ( dfu_usb_descriptors = 0x3ff0c198 ); -PROVIDE ( dh_group14_generator = 0x3ff0adf0 ); -PROVIDE ( dh_group14_prime = 0x3ff0acf0 ); -PROVIDE ( dh_group15_generator = 0x3ff0acef ); -PROVIDE ( dh_group15_prime = 0x3ff0ab6f ); -PROVIDE ( dh_group16_generator = 0x3ff0ab6e ); -PROVIDE ( dh_group16_prime = 0x3ff0a96e ); -PROVIDE ( dh_group17_generator = 0x3ff0a96d ); -PROVIDE ( dh_group17_prime = 0x3ff0a66d ); -PROVIDE ( dh_group18_generator = 0x3ff0a66c ); -PROVIDE ( dh_group18_prime = 0x3ff0a26c ); -PROVIDE ( dh_group1_generator = 0x3ff0af93 ); -PROVIDE ( dh_group1_prime = 0x3ff0af33 ); -PROVIDE ( dh_group2_generator = 0x3ff0af32 ); -PROVIDE ( dh_group2_prime = 0x3ff0aeb2 ); -PROVIDE ( dh_group5_generator = 0x3ff0aeb1 ); -PROVIDE ( dh_group5_prime = 0x3ff0adf1 ); -PROVIDE ( disable_default_watchdog = 0x40044e20 ); -PROVIDE ( Disable_QMode = 0x4004d6d0 ); -PROVIDE ( div = 0x4003234c ); -PROVIDE ( __divdc3 = 0x40038b74 ); -PROVIDE ( __divdf3 = 0x4003c120 ); -PROVIDE ( __divdi3 = 0x40055bf0 ); -PROVIDE ( __divsc3 = 0x400388d4 ); -PROVIDE ( __divsf3 = 0x40055974 ); -PROVIDE ( __divsi3 = 0x400558c8 ); -PROVIDE ( dmadesc_rx = 0x3fcee150 ); -PROVIDE ( dmadesc_tx = 0x3fcee144 ); -PROVIDE ( _DoubleExceptionVector = 0x400003c0 ); -PROVIDE ( _DoubleExceptionVector_text_end = 0x400003c6 ); -PROVIDE ( _DoubleExceptionVector_text_start = 0x400003c0 ); -PROVIDE ( _dram0_0_start = 0x3fcd8000 ); -PROVIDE ( _dram0_rtos_reserved_start = 0x3fcef044 ); -PROVIDE ( dummy_len_plus = 0x3fcefc10 ); -PROVIDE ( ECC_4Win_Look_up_table = 0x3ff078b4 ); -PROVIDE ( ecc_env = 0x3fcef984 ); -PROVIDE ( ecc_Jacobian_InfinityPoint256 = 0x3ff08070 ); -PROVIDE ( em_base_reg_lut = 0x3ff08258 ); -PROVIDE ( Enable_QMode = 0x4004d680 ); -PROVIDE ( __eqdf2 = 0x40037d40 ); -PROVIDE ( __eqsf2 = 0x40037a0c ); -PROVIDE ( esp_crc8 = 0x40047854 ); -PROVIDE ( esp_flash_chip_driver_initialized = 0x4004e88c ); -PROVIDE ( esp_flash_erase_chip = 0x4004e998 ); -PROVIDE ( esp_flash_erase_region = 0x4004ea00 ); -PROVIDE ( esp_flash_get_chip_write_protect = 0x4004eb70 ); -PROVIDE ( esp_flash_get_io_mode = 0x4004efa4 ); -PROVIDE ( esp_flash_get_protectable_regions = 0x4004ec00 ); -PROVIDE ( esp_flash_get_protected_region = 0x4004ec4c ); -PROVIDE ( esp_flash_get_size = 0x4004e938 ); -PROVIDE ( esp_flash_read = 0x4004ed7c ); -PROVIDE ( esp_flash_read_chip_id = 0x4004e8a0 ); -PROVIDE ( esp_flash_read_encrypted = 0x4004ef80 ); -PROVIDE ( esp_flash_read_id = 0x4004e8e8 ); -PROVIDE ( esp_flash_set_chip_write_protect = 0x4004ebb8 ); -PROVIDE ( esp_flash_set_io_mode = 0x4004effc ); -PROVIDE ( esp_flash_set_protected_region = 0x4004ecd4 ); -PROVIDE ( esp_flash_write = 0x4004ee74 ); -PROVIDE ( esp_flash_write_encrypted = 0x4004ef48 ); -PROVIDE ( esp_handler = 0x3fcef46c ); -PROVIDE ( esp_rom_config_pad_power_select = 0x4004de78 ); -PROVIDE ( esp_rom_flash_ecc_init = 0x4004deac ); -PROVIDE ( esp_rom_opiflash_cache_mode_config = 0x4004d744 ); -PROVIDE ( esp_rom_opiflash_erase_area = 0x40051acc ); -PROVIDE ( esp_rom_opiflash_erase_block_64k = 0x40051a9c ); -PROVIDE ( esp_rom_opiflash_erase_sector = 0x40051a68 ); -PROVIDE ( esp_rom_opiflash_exec_cmd = 0x400515e0 ); -PROVIDE ( esp_rom_opiflash_exit_continuous_read_mode = 0x4005168c ); -PROVIDE ( esp_rom_opiflash_lock_acquire_cb = 0x3fcefca8 ); -PROVIDE ( esp_rom_opiflash_lock_release_cb = 0x3fcefca4 ); -PROVIDE ( esp_rom_opiflash_mode_reset = 0x40051734 ); -PROVIDE ( esp_rom_opiflash_pin_config = 0x40050f58 ); -PROVIDE ( esp_rom_opiflash_rdcr2 = 0x40051898 ); -PROVIDE ( esp_rom_opiflash_rdsr = 0x400517d8 ); -PROVIDE ( esp_rom_opiflash_read = 0x40051bd4 ); -PROVIDE ( esp_rom_opiflash_read_id = 0x40051760 ); -PROVIDE ( esp_rom_opiflash_set_mode = 0x40051d58 ); -PROVIDE ( esp_rom_opiflash_soft_reset = 0x400516c8 ); -PROVIDE ( esp_rom_opiflash_wait_idle = 0x4005182c ); -PROVIDE ( esp_rom_opiflash_wrcr2 = 0x40051904 ); -PROVIDE ( esp_rom_opiflash_write = 0x40051d0c ); -PROVIDE ( esp_rom_spi_cmd_config = 0x40051390 ); -PROVIDE ( esp_rom_spi_cmd_start = 0x400512bc ); -PROVIDE ( esp_rom_spi_flash_auto_sus_res = 0x4004e75c ); -PROVIDE ( esp_rom_spi_flash_auto_wait_idle = 0x4004e68c ); -PROVIDE ( esp_rom_spi_flash_send_resume = 0x4004e6e0 ); -PROVIDE ( esp_rom_spi_flash_update_id = 0x4004de64 ); -PROVIDE ( esp_rom_spi_reset_rw_mode = 0x40051084 ); -PROVIDE ( esp_rom_spi_set_dtr_swap_mode = 0x40051274 ); -PROVIDE ( esp_rom_spi_set_op_mode = 0x400510e8 ); -PROVIDE ( esp_vendor_cmd = 0x3fcef4c0 ); -PROVIDE ( _etext = 0x400568d0 ); -PROVIDE ( ets_aes_block = 0x40042ed0 ); -PROVIDE ( ets_aes_disable = 0x40042e30 ); -PROVIDE ( ets_aes_enable = 0x40042e04 ); -PROVIDE ( ets_aes_setkey = 0x40042e64 ); -PROVIDE ( ets_aes_setkey_dec = 0x40042eb0 ); -PROVIDE ( ets_aes_setkey_enc = 0x40042ea0 ); -PROVIDE ( ets_bigint_disable = 0x40043010 ); -PROVIDE ( ets_bigint_enable = 0x40042fc8 ); -PROVIDE ( ets_bigint_getz = 0x40043118 ); -PROVIDE ( ets_bigint_modexp = 0x400430d8 ); -PROVIDE ( ets_bigint_modmult = 0x400430b4 ); -PROVIDE ( ets_bigint_multiply = 0x40043050 ); -PROVIDE ( ets_bigint_wait_finish = 0x40043100 ); -PROVIDE ( ets_config_flash_by_image_hdr = 0x40046b10 ); -PROVIDE ( ets_delay_us = 0x40043148 ); -PROVIDE ( ets_ds_disable = 0x400431d0 ); -PROVIDE ( ets_ds_enable = 0x400431a4 ); -PROVIDE ( ets_ds_encrypt_params = 0x40043320 ); -PROVIDE ( ets_ds_finish_sign = 0x400432b8 ); -PROVIDE ( ets_ds_is_busy = 0x400431fc ); -PROVIDE ( ets_ds_start_sign = 0x4004322c ); -PROVIDE ( ets_ecc_flash_disable = 0x40054ef0 ); -PROVIDE ( ets_ecc_flash_disable_all = 0x40054f10 ); -PROVIDE ( ets_ecc_flash_enable = 0x40054eb4 ); -PROVIDE ( ets_ecc_flash_enable_all = 0x40054ed4 ); -PROVIDE ( ets_ecc_get_flash_byte_mode = 0x40054fc4 ); -PROVIDE ( ets_ecc_get_flash_page_size = 0x40054f30 ); -PROVIDE ( ets_ecc_get_flash_range = 0x40055008 ); -PROVIDE ( ets_ecc_get_sram_byte_mode = 0x4005514c ); -PROVIDE ( ets_ecc_get_sram_page_size = 0x400550a4 ); -PROVIDE ( ets_ecc_get_sram_range = 0x40055160 ); -PROVIDE ( ets_ecc_set_flash_byte_mode = 0x40054f90 ); -PROVIDE ( ets_ecc_set_flash_page_size = 0x40054f50 ); -PROVIDE ( ets_ecc_set_flash_range = 0x40054fd8 ); -PROVIDE ( ets_ecc_set_sram_byte_mode = 0x40055118 ); -PROVIDE ( ets_ecc_set_sram_page_size = 0x400550c0 ); -PROVIDE ( ets_ecc_set_sram_range = 0x40055180 ); -PROVIDE ( ets_ecc_sram_disable = 0x4005504c ); -PROVIDE ( ets_ecc_sram_disable_all = 0x40055088 ); -PROVIDE ( ets_ecc_sram_enable = 0x4005502c ); -PROVIDE ( ets_ecc_sram_enable_all = 0x4005506c ); -PROVIDE ( ets_efuse_cache_encryption_enabled = 0x40043cb8 ); -PROVIDE ( ets_efuse_clear_program_registers = 0x400436c0 ); -PROVIDE ( ets_efuse_count_unused_key_blocks = 0x40043884 ); -PROVIDE ( ets_efuse_download_modes_disabled = 0x40043b94 ); -PROVIDE ( ets_efuse_ecc_16to17_mode = 0x40043c68 ); -PROVIDE ( ets_efuse_ecc_en = 0x40043c78 ); -PROVIDE ( ets_efuse_ecc_flash_page_size = 0x40043c88 ); -PROVIDE ( ets_efuse_find_purpose = 0x400437e4 ); -PROVIDE ( ets_efuse_find_unused_key_block = 0x4004386c ); -PROVIDE ( ets_efuse_flash_octal_mode = 0x40043c48 ); -PROVIDE ( ets_efuse_flash_opi_5pads_power_sel_vddspi = 0x40043c38 ); -PROVIDE ( ets_efuse_force_send_resume = 0x40043c58 ); -PROVIDE ( ets_efuse_get_flash_delay_us = 0x40043cfc ); -PROVIDE ( ets_efuse_get_key_purpose = 0x40043770 ); -PROVIDE ( ets_efuse_get_mac = 0x40043d24 ); -PROVIDE ( ets_efuse_get_opiconfig = 0x40043ac8 ); -PROVIDE ( ets_efuse_get_read_register_address = 0x4004374c ); -PROVIDE ( ets_efuse_get_spiconfig = 0x40043a6c ); -PROVIDE ( ets_efuse_get_uart_print_channel = 0x40043bb4 ); -PROVIDE ( ets_efuse_get_uart_print_control = 0x40043ba4 ); -PROVIDE ( ets_efuse_get_wp_pad = 0x40043a10 ); -PROVIDE ( ets_efuse_jtag_disabled = 0x40043b5c ); -PROVIDE ( ets_efuse_key_block_unused = 0x40043810 ); -PROVIDE ( ets_efuse_legacy_spi_boot_mode_disabled = 0x40043cd8 ); -PROVIDE ( ets_efuse_program = 0x400436f4 ); -PROVIDE ( ets_efuse_read = 0x40043678 ); -PROVIDE ( ets_efuse_rs_calculate = 0x40043d58 ); -PROVIDE ( ets_efuse_secure_boot_aggressive_revoke_enabled = 0x40043ca8 ); -PROVIDE ( ets_efuse_secure_boot_enabled = 0x40043c98 ); -PROVIDE ( ets_efuse_security_download_modes_enabled = 0x40043bd4 ); -PROVIDE ( ets_efuse_set_timing = 0x40043648 ); -PROVIDE ( ets_efuse_usb_download_mode_disabled = 0x40043bf4 ); -PROVIDE ( ets_efuse_usb_force_nopersist = 0x40043c30 ); -PROVIDE ( ets_efuse_usb_module_disabled = 0x40043bc4 ); -PROVIDE ( ets_efuse_usb_use_ext_phy = 0x40043c20 ); -PROVIDE ( ets_efuse_write_key = 0x400438bc ); -PROVIDE ( ets_emsa_pss_verify = 0x40047554 ); -PROVIDE ( ets_get_apb_freq = 0x40046918 ); -PROVIDE ( ets_get_cpu_frequency = 0x40043170 ); -PROVIDE ( ets_get_printf_channel = 0x40045a28 ); -PROVIDE ( ets_get_stack_info = 0x40045118 ); -PROVIDE ( ets_get_xtal_div = 0x400468b8 ); -PROVIDE ( ets_get_xtal_freq = 0x400468f4 ); -PROVIDE ( ets_hmac_calculate_downstream = 0x400447b4 ); -PROVIDE ( ets_hmac_calculate_message = 0x400446b4 ); -PROVIDE ( ets_hmac_disable = 0x40044688 ); -PROVIDE ( ets_hmac_enable = 0x4004466c ); -PROVIDE ( ets_hmac_invalidate_downstream = 0x400447d4 ); -PROVIDE ( ets_install_lock = 0x40045980 ); -PROVIDE ( ets_install_putc1 = 0x40045990 ); -PROVIDE ( ets_install_putc2 = 0x400459b0 ); -PROVIDE ( ets_install_uart_printf = 0x400459a0 ); -PROVIDE ( ets_intr_count = 0x3fced910 ); -PROVIDE ( ets_intr_lock = 0x400447fc ); -PROVIDE ( ets_intr_unlock = 0x40044810 ); -PROVIDE ( ets_is_print_boot = 0x40044e50 ); -PROVIDE ( ets_isr_attach = 0x40044838 ); -PROVIDE ( ets_isr_mask = 0x40044848 ); -PROVIDE ( ets_isr_unmask = 0x40044854 ); -PROVIDE ( ets_jtag_enable_temporarily = 0x40043b14 ); -PROVIDE ( ets_loader_map_range = 0x40046a24 ); -PROVIDE ( ets_mgf1_sha256 = 0x400474ec ); -PROVIDE ( ets_printf = 0x400459c0 ); -PROVIDE ( ets_printf_lock = 0x3fcefcb4 ); -PROVIDE ( ets_printf_uart = 0x3fcefcac ); -PROVIDE ( ets_printf_unlock = 0x3fcefcb0 ); -PROVIDE ( ets_rsa_pss_verify = 0x40047660 ); -PROVIDE ( ets_run_flash_bootloader = 0x40046c38 ); -PROVIDE ( ets_secure_boot_read_key_digests = 0x40045da4 ); -PROVIDE ( ets_secure_boot_revoke_public_key_digest = 0x40045e54 ); -PROVIDE ( ets_secure_boot_verify_bootloader_with_keys = 0x400460a0 ); -PROVIDE ( ets_secure_boot_verify_signature = 0x40046024 ); -PROVIDE ( ets_secure_boot_verify_stage_bootloader = 0x4004637c ); -PROVIDE ( ets_set_appcpu_boot_addr = 0x40044e08 ); -PROVIDE ( ets_set_printf_channel = 0x40045a1c ); -PROVIDE ( ets_set_user_start = 0x40044df8 ); -PROVIDE ( ets_set_xtal_div = 0x400468d4 ); -PROVIDE ( ets_sha_clone = 0x40046618 ); -PROVIDE ( ets_sha_disable = 0x40046470 ); -PROVIDE ( ets_sha_enable = 0x40046444 ); -PROVIDE ( ets_sha_finish = 0x40046774 ); -PROVIDE ( ets_sha_get_state = 0x400465f0 ); -PROVIDE ( ets_sha_init = 0x4004649c ); -PROVIDE ( ets_sha_process = 0x40046644 ); -PROVIDE ( ets_sha_starts = 0x400464e4 ); -PROVIDE ( ets_sha_update = 0x400466b4 ); -PROVIDE ( ets_startup_callback = 0x3fced918 ); -PROVIDE ( ets_unpack_flash_code_legacy = 0x4004716c ); -PROVIDE ( ets_update_cpu_frequency = 0x40043164 ); -PROVIDE ( ets_vprintf = 0x4004551c ); -PROVIDE ( ets_waiti0 = 0x40044824 ); -PROVIDE ( ets_wdt_reset_cpu = 0x400551c0 ); -PROVIDE ( ets_write_char = 0x40045454 ); -PROVIDE ( ets_write_char_uart = 0x40045478 ); -PROVIDE ( event_empty = 0x3fcef5cc ); -PROVIDE ( _exit_r = 0x40054628 ); -PROVIDE ( __extendsfdf2 = 0x4003c400 ); -PROVIDE ( fclose = 0x40054e9c ); -PROVIDE ( _fclose_r = 0x40054da4 ); -PROVIDE ( fflush = 0x40033fd8 ); -PROVIDE ( _fflush_r = 0x40033f50 ); -PROVIDE ( __ffsdi2 = 0x40055b98 ); -PROVIDE ( __ffssi2 = 0x40055914 ); -PROVIDE ( FilePacketSendDeflatedReqMsgProc = 0x40048a2c ); -PROVIDE ( FilePacketSendReqMsgProc = 0x40048708 ); -PROVIDE ( fiprintf = 0x40032cdc ); -PROVIDE ( _fiprintf_r = 0x40032cac ); -PROVIDE ( __fixdfdi = 0x4003c290 ); -PROVIDE ( __fixdfsi = 0x4003c244 ); -PROVIDE ( fixed_tx_time = 0x3ff08d3c ); -PROVIDE ( __fixsfdi = 0x4003bc18 ); -PROVIDE ( __fixsfsi = 0x4003bbd8 ); -PROVIDE ( __fixunsdfsi = 0x4003c2fc ); -PROVIDE ( __fixunssfdi = 0x4003bcd0 ); -PROVIDE ( __fixunssfsi = 0x4003bc78 ); -PROVIDE ( flash2spiram_instruction_offset = 0x40052e14 ); -PROVIDE ( flash2spiram_rodata_offset = 0x40052e24 ); -PROVIDE ( flashchip = 0x3fcefbac ); -PROVIDE ( FlashDwnLdDeflatedStartMsgProc = 0x400489d4 ); -PROVIDE ( FlashDwnLdParamCfgMsgProc = 0x400487f0 ); -PROVIDE ( FlashDwnLdStartMsgProc = 0x400486a4 ); -PROVIDE ( FlashDwnLdStopDeflatedReqMsgProc = 0x40048b28 ); -PROVIDE ( FlashDwnLdStopReqMsgProc = 0x400487c0 ); -PROVIDE ( flash_instr_rodata_end_page = 0x40052e4c ); -PROVIDE ( flash_instr_rodata_start_page = 0x40052e30 ); -PROVIDE ( __floatdidf = 0x40055af4 ); -PROVIDE ( __floatdisf = 0x40055a2c ); -PROVIDE ( __floatsidf = 0x40055ab0 ); -PROVIDE ( __floatsisf = 0x400559dc ); -PROVIDE ( __floatundidf = 0x40055ae4 ); -PROVIDE ( __floatundisf = 0x40055a1c ); -PROVIDE ( __floatunsidf = 0x40055aa4 ); -PROVIDE ( __floatunsisf = 0x400559d0 ); -PROVIDE ( __fp_lock_all = 0x40054cbc ); -PROVIDE ( fprintf = 0x40032cdc ); -PROVIDE ( _fprintf_r = 0x40032cac ); -PROVIDE ( __fp_unlock_all = 0x40054cd4 ); -PROVIDE ( fputwc = 0x40033c40 ); -PROVIDE ( __fputwc = 0x40033b2c ); -PROVIDE ( _fputwc_r = 0x40033bc0 ); -PROVIDE ( free = 0x400547b8 ); -PROVIDE ( _free_r = 0x400544cc ); -PROVIDE ( _fstat_r = 0x400545cc ); -PROVIDE ( _fwalk = 0x40056670 ); -PROVIDE ( _fwalk_reent = 0x400566b0 ); -PROVIDE ( g_bt_plf_log_level = 0x3fcef394 ); -PROVIDE ( __gcc_bcmp = 0x40039100 ); -PROVIDE ( __gedf2 = 0x40037e00 ); -PROVIDE ( general_device_descr = 0x3fcef0b2 ); -PROVIDE ( _GeneralException = 0x40039758 ); -PROVIDE ( __gesf2 = 0x40037aa4 ); -PROVIDE ( get_id = 0x4004d0dc ); -PROVIDE ( _getpid_r = 0x400545fc ); -PROVIDE ( __getreent = 0x4005478c ); -PROVIDE ( GetSecurityInfoProc = 0x40048bf4 ); -PROVIDE ( _gettimeofday_r = 0x40054558 ); -PROVIDE ( GetUartDevice = 0x40049cb4 ); -PROVIDE ( g_flash_guard_ops = 0x3fcefc34 ); -PROVIDE ( _global_impure_ptr = 0x3fcefcdc ); -PROVIDE ( __global_locale_ptr = 0x3fcefccc ); -PROVIDE ( g_phyFuns = 0x3fcefce0 ); -PROVIDE ( g_phyFuns_instance = 0x3fcefce4 ); -PROVIDE ( gpio_bypass_matrix_in = 0x4005370c ); -PROVIDE ( gpio_input_get = 0x40053680 ); -PROVIDE ( gpio_input_get_high = 0x40053694 ); -PROVIDE ( gpio_matrix_in = 0x4005372c ); -PROVIDE ( gpio_matrix_out = 0x4005375c ); -PROVIDE ( gpio_output_disable = 0x400537dc ); -PROVIDE ( gpio_output_enable = 0x400537b0 ); -PROVIDE ( gpio_output_set = 0x4005361c ); -PROVIDE ( gpio_output_set_high = 0x40053654 ); -PROVIDE ( gpio_pad_hold = 0x40053950 ); -PROVIDE ( gpio_pad_input_disable = 0x400538ec ); -PROVIDE ( gpio_pad_input_enable = 0x400538c8 ); -PROVIDE ( gpio_pad_pulldown = 0x40053894 ); -PROVIDE ( gpio_pad_pullup = 0x40053860 ); -PROVIDE ( gpio_pad_select_gpio = 0x4005380c ); -PROVIDE ( gpio_pad_set_drv = 0x40053834 ); -PROVIDE ( gpio_pad_unhold = 0x40053918 ); -PROVIDE ( gpio_pin_wakeup_disable = 0x400536e0 ); -PROVIDE ( gpio_pin_wakeup_enable = 0x400536a8 ); -PROVIDE ( g_rw_controller_task_handle = 0x3fcef8b8 ); -PROVIDE ( g_rw_init_sem = 0x3fcef8c0 ); -PROVIDE ( g_rw_schd_queue = 0x3fcef8bc ); -PROVIDE ( g_shared_buffers = 0x3fcd8004 ); -PROVIDE ( __gtdf2 = 0x40037d74 ); -PROVIDE ( g_ticks_per_us = 0x3fcefcc0 ); -PROVIDE ( __gtsf2 = 0x40037a38 ); -PROVIDE ( hci_acl_data_handler = 0x4000ed70 ); -PROVIDE ( hci_cmd_desc_root_tab = 0x3ff08434 ); -PROVIDE ( hci_cmd_desc_tab_ctrl_bb = 0x3ff08974 ); -PROVIDE ( hci_cmd_desc_tab_info_par = 0x3ff08944 ); -PROVIDE ( hci_cmd_desc_tab_le = 0x3ff0859c ); -PROVIDE ( hci_cmd_desc_tab_lk_ctrl = 0x3ff089e0 ); -PROVIDE ( hci_cmd_desc_tab_stat_par = 0x3ff08938 ); -PROVIDE ( hci_cmd_desc_tab_vs = 0x3ff08464 ); -PROVIDE ( hci_cmd_desc_tab_vs_esp = 0x3fcef3c4 ); -PROVIDE ( hci_dbg_llcp_discard_cmd_handler = 0x4000c3a0 ); -PROVIDE ( hci_dbg_send_llcp_cmd_handler = 0x4000f934 ); -PROVIDE ( hci_disconnect_cmd_handler = 0x4000c824 ); -PROVIDE ( hci_env = 0x3fcef99d ); -PROVIDE ( hci_evt_dbg_desc_tab = 0x3ff083e4 ); -PROVIDE ( hci_evt_desc_tab = 0x3ff083ec ); -PROVIDE ( hci_evt_le_desc_tab = 0x3ff08344 ); -PROVIDE ( hci_evt_le_desc_tab_esp = 0x3ff0833c ); -PROVIDE ( hci_ext_host = 0x3fcef99c ); -PROVIDE ( hci_le_add_dev_to_per_adv_list_cmd_handler = 0x4002ca68 ); -PROVIDE ( hci_le_clear_adv_sets_cmd_handler = 0x40028e6c ); -PROVIDE ( hci_le_clear_per_adv_list_cmd_handler = 0x4002cc74 ); -PROVIDE ( hci_le_con_upd_cmd_handler = 0x4000bbb8 ); -PROVIDE ( hci_le_create_con_cancel_cmd_handler = 0x4002b060 ); -PROVIDE ( hci_le_create_con_cmd_handler = 0x4002a914 ); -PROVIDE ( hci_le_ext_create_con_cmd_handler = 0x4002ac78 ); -PROVIDE ( hci_le_ltk_req_neg_reply_cmd_handler = 0x4000e278 ); -PROVIDE ( hci_le_ltk_req_reply_cmd_handler = 0x4000e1d8 ); -PROVIDE ( hci_le_per_adv_create_sync_cancel_cmd_handler = 0x4002c87c ); -PROVIDE ( hci_le_per_adv_create_sync_cmd_handler = 0x4002c710 ); -PROVIDE ( hci_le_per_adv_term_sync_cmd_handler = 0x4002c9dc ); -PROVIDE ( hci_le_rd_adv_ch_tx_pw_cmd_handler = 0x40026f30 ); -PROVIDE ( hci_le_rd_chnl_map_cmd_handler = 0x4000aaa4 ); -PROVIDE ( hci_le_rd_max_adv_data_len_cmd_handler = 0x40028d04 ); -PROVIDE ( hci_le_rd_nb_supp_adv_sets_cmd_handler = 0x40028d4c ); -PROVIDE ( hci_le_rd_per_adv_list_size_cmd_handler = 0x4002cd08 ); -PROVIDE ( hci_le_rd_phy_cmd_handler = 0x40010eb0 ); -PROVIDE ( hci_le_rd_rem_feats_cmd_handler = 0x4000e8f8 ); -PROVIDE ( hci_le_rem_con_param_req_neg_reply_cmd_handler = 0x4000bdd0 ); -PROVIDE ( hci_le_rem_con_param_req_reply_cmd_handler = 0x4000bd20 ); -PROVIDE ( hci_le_rmv_adv_set_cmd_handler = 0x40028dd0 ); -PROVIDE ( hci_le_rmv_dev_from_per_adv_list_cmd_handler = 0x4002cb7c ); -PROVIDE ( hci_le_set_adv_data_cmd_handler = 0x400271c0 ); -PROVIDE ( hci_le_set_adv_en_cmd_handler = 0x400273c8 ); -PROVIDE ( hci_le_set_adv_param_cmd_handler = 0x40026f94 ); -PROVIDE ( hci_le_set_adv_set_rand_addr_cmd_handler = 0x40027970 ); -PROVIDE ( hci_le_set_data_len_cmd_handler = 0x4000cf90 ); -PROVIDE ( hci_le_set_ext_adv_data_cmd_handler = 0x40027a2c ); -PROVIDE ( hci_le_set_ext_adv_en_cmd_handler = 0x40028038 ); -PROVIDE ( hci_le_set_ext_adv_param_cmd_handler = 0x4002768c ); -PROVIDE ( hci_le_set_ext_scan_en_cmd_handler = 0x4002c368 ); -PROVIDE ( hci_le_set_ext_scan_param_cmd_handler = 0x4002c1f0 ); -PROVIDE ( hci_le_set_ext_scan_rsp_data_cmd_handler = 0x40027d44 ); -PROVIDE ( hci_le_set_per_adv_data_cmd_handler = 0x40028844 ); -PROVIDE ( hci_le_set_per_adv_en_cmd_handler = 0x40028a88 ); -PROVIDE ( hci_le_set_per_adv_param_cmd_handler = 0x400286bc ); -PROVIDE ( hci_le_set_phy_cmd_handler = 0x40010f1c ); -PROVIDE ( hci_le_set_scan_en_cmd_handler = 0x4002bf34 ); -PROVIDE ( hci_le_set_scan_param_cmd_handler = 0x4002bda0 ); -PROVIDE ( hci_le_set_scan_rsp_data_cmd_handler = 0x400272c4 ); -PROVIDE ( hci_le_start_enc_cmd_handler = 0x4000e0dc ); -PROVIDE ( hci_rd_auth_payl_to_cmd_handler = 0x4000f0ec ); -PROVIDE ( hci_rd_rem_ver_info_cmd_handler = 0x4001157c ); -PROVIDE ( hci_rd_rssi_cmd_handler = 0x4000eb18 ); -PROVIDE ( hci_rd_tx_pwr_lvl_cmd_handler = 0x4000ea74 ); -PROVIDE ( hci_tl_env = 0x3fcef9c0 ); -PROVIDE ( hci_vs_set_pref_slave_evt_dur_cmd_handler = 0x4000ec04 ); -PROVIDE ( hci_vs_set_pref_slave_latency_cmd_handler = 0x4000ebb0 ); -PROVIDE ( hci_wr_auth_payl_to_cmd_handler = 0x4000f158 ); -PROVIDE ( hmac_md5 = 0x400378cc ); -PROVIDE ( hmac_md5_vector = 0x400377d4 ); -PROVIDE ( ibus_baseaddrs = 0x3ff0c4d8 ); -PROVIDE ( intr_matrix_set = 0x40044868 ); -PROVIDE ( _iram0_text_end = 0x4000056c ); -PROVIDE ( _iram0_text_start = 0x4000056c ); -PROVIDE ( _iram1_text_end = 0x60021100 ); -PROVIDE ( _iram1_text_start = 0x60021100 ); -PROVIDE ( isalnum = 0x40039d94 ); -PROVIDE ( isalpha = 0x40039da4 ); -PROVIDE ( isascii = 0x4005546c ); -PROVIDE ( _isatty_r = 0x40039d5c ); -PROVIDE ( isblank = 0x40039db4 ); -PROVIDE ( iscntrl = 0x40039dd4 ); -PROVIDE ( isdigit = 0x40039dec ); -PROVIDE ( isgraph = 0x40039e24 ); -PROVIDE ( islower = 0x40039e04 ); -PROVIDE ( isprint = 0x40039e3c ); -PROVIDE ( ispunct = 0x40039e50 ); -PROVIDE ( isspace = 0x40039e68 ); -PROVIDE ( isupper = 0x40039e80 ); -PROVIDE ( itoa = 0x40032974 ); -PROVIDE ( __itoa = 0x40032938 ); -PROVIDE ( jd_decomp = 0x40047e30 ); -PROVIDE ( jd_prepare = 0x400479e0 ); -PROVIDE ( jtag_appcpu_reset = 0x3fcefcc4 ); -PROVIDE ( jtag_cpu_reset_happened = 0x40045a78 ); -PROVIDE ( jtag_procpu_reset = 0x3fcefcc5 ); -PROVIDE ( ke_env = 0x3fcefa04 ); -PROVIDE ( _KernelExceptionVector = 0x40000300 ); -PROVIDE ( _KernelExceptionVector_text_end = 0x40000306 ); -PROVIDE ( _KernelExceptionVector_text_start = 0x40000300 ); -PROVIDE ( _kill_r = 0x40054610 ); -PROVIDE ( labs = 0x40032370 ); -PROVIDE ( ldiv = 0x40032378 ); -PROVIDE ( __ledf2 = 0x40037d9c ); -PROVIDE ( __lesf2 = 0x40037a58 ); -PROVIDE ( _Level2FromVector = 0x400398cc ); -PROVIDE ( _Level2HandlerLabel = 0x00000000 ); -PROVIDE ( _Level2InterruptVector_text_end = 0x40000186 ); -PROVIDE ( _Level2InterruptVector_text_start = 0x40000180 ); -PROVIDE ( _Level2Vector = 0x40000180 ); -PROVIDE ( _Level3FromVector = 0x4003999c ); -PROVIDE ( _Level3HandlerLabel = 0x00000000 ); -PROVIDE ( _Level3InterruptVector_text_end = 0x400001c6 ); -PROVIDE ( _Level3InterruptVector_text_start = 0x400001c0 ); -PROVIDE ( _Level3Vector = 0x400001c0 ); -PROVIDE ( _Level4FromVector = 0x40039a68 ); -PROVIDE ( _Level4HandlerLabel = 0x00000000 ); -PROVIDE ( _Level4InterruptVector_text_end = 0x40000206 ); -PROVIDE ( _Level4InterruptVector_text_start = 0x40000200 ); -PROVIDE ( _Level4Vector = 0x40000200 ); -PROVIDE ( _Level5FromVector = 0x40039bd8 ); -PROVIDE ( _Level5HandlerLabel = 0x00000000 ); -PROVIDE ( _Level5InterruptVector_text_end = 0x40000246 ); -PROVIDE ( _Level5InterruptVector_text_start = 0x40000240 ); -PROVIDE ( _Level5Vector = 0x40000240 ); -PROVIDE ( _LevelOneInterrupt = 0x400397ae ); -PROVIDE ( _link_r = 0x4005459c ); -PROVIDE ( _lit4_end = 0x4000056c ); -PROVIDE ( _lit4_start = 0x4000056c ); -PROVIDE ( llc_auth_payl_nearly_to_handler = 0x4000f234 ); -PROVIDE ( llc_auth_payl_real_to_handler = 0x4000f2b0 ); -PROVIDE ( llc_encrypt_ind_handler = 0x4000e344 ); -PROVIDE ( llc_env = 0x3fcefa64 ); -PROVIDE ( ll_channel_map_ind_handler = 0x4000a934 ); -PROVIDE ( llc_hci_command_handler_wrapper = 0x4000ed44 ); -PROVIDE ( llc_ll_connection_param_req_pdu_send = 0x4000ae9c ); -PROVIDE ( llc_ll_connection_param_rsp_pdu_send = 0x4000b220 ); -PROVIDE ( llc_ll_connection_update_ind_pdu_send = 0x4000ae58 ); -PROVIDE ( llc_llcp_ch_map_update_ind_pdu_send = 0x4000a718 ); -PROVIDE ( llc_llcp_phy_upd_ind_pdu_send = 0x40010584 ); -PROVIDE ( llc_llcp_version_ind_pdu_send = 0x400112cc ); -PROVIDE ( llc_ll_enc_req_pdu_send = 0x4000d2b0 ); -PROVIDE ( llc_ll_enc_rsp_pdu_send = 0x4000d304 ); -PROVIDE ( llc_ll_feature_req_pdu_send = 0x4000e574 ); -PROVIDE ( llc_ll_feature_rsp_pdu_send = 0x4000e5cc ); -PROVIDE ( llc_ll_length_req_pdu_send = 0x4000c99c ); -PROVIDE ( llc_ll_length_rsp_pdu_send = 0x4000c9c8 ); -PROVIDE ( llc_ll_pause_enc_req_pdu_send = 0x4000d270 ); -PROVIDE ( llc_ll_pause_enc_rsp_pdu_send = 0x4000d290 ); -PROVIDE ( llc_ll_phy_req_pdu_send = 0x40010268 ); -PROVIDE ( llc_ll_phy_rsp_pdu_send = 0x40010290 ); -PROVIDE ( llc_ll_ping_req_pdu_send = 0x4000efc4 ); -PROVIDE ( llc_ll_ping_rsp_pdu_send = 0x4000f088 ); -PROVIDE ( llc_ll_start_enc_req_pdu_send = 0x4000d348 ); -PROVIDE ( llc_ll_start_enc_rsp_pdu_send = 0x4000d368 ); -PROVIDE ( llc_ll_terminate_ind_pdu_send = 0x4000c444 ); -PROVIDE ( llc_ll_unknown_rsp_pdu_send = 0x4000f460 ); -PROVIDE ( ll_connection_param_req_handler = 0x4000b9ec ); -PROVIDE ( ll_connection_param_rsp_handler = 0x4000bb0c ); -PROVIDE ( ll_connection_update_ind_handler = 0x4000b850 ); -PROVIDE ( llc_op_ch_map_upd_ind_handler = 0x4000ab10 ); -PROVIDE ( llc_op_con_upd_ind_handler = 0x4000be4c ); -PROVIDE ( llc_op_disconnect_ind_handler = 0x4000c744 ); -PROVIDE ( llc_op_dl_upd_ind_handler = 0x4000d0c8 ); -PROVIDE ( llc_op_encrypt_ind_handler = 0x4000e4e8 ); -PROVIDE ( llc_op_feats_exch_ind_handler = 0x4000e9dc ); -PROVIDE ( llc_op_le_ping_ind_handler = 0x4000f1c4 ); -PROVIDE ( llc_op_phy_upd_ind_handler = 0x400110d4 ); -PROVIDE ( llc_op_ver_exch_ind_handler = 0x4001147c ); -PROVIDE ( llc_stopped_ind_handler = 0x4000c6e8 ); -PROVIDE ( lld_acl_rx_ind_handler = 0x4000ee78 ); -PROVIDE ( lld_acl_tx_cfm_handler = 0x4000ef4c ); -PROVIDE ( lld_adv_end_ind_handler = 0x40028fd4 ); -PROVIDE ( lld_adv_rep_ind_handler = 0x4002cfb0 ); -PROVIDE ( lld_ch_map_upd_cfm_handler = 0x4000ac18 ); -PROVIDE ( lld_con_estab_ind_handler = 0x4000c048 ); -PROVIDE ( lld_con_evt_sd_evt_time_set = 0x4001aa08 ); -PROVIDE ( lld_con_offset_upd_ind_handler = 0x4000c100 ); -PROVIDE ( lld_con_param_upd_cfm_handler = 0x4000bf50 ); -PROVIDE ( lld_disc_ind_handler = 0x4000c608 ); -PROVIDE ( lldesc_build_chain = 0x4003c774 ); -PROVIDE ( lldesc_num2link = 0x4003c864 ); -PROVIDE ( lldesc_set_owner = 0x4003c890 ); -PROVIDE ( lldesc_setup = 0x400543c8 ); -PROVIDE ( lld_exp_sync_pos_tab = 0x3fcefa90 ); -PROVIDE ( lld_init_end_ind_handler = 0x4002b140 ); -PROVIDE ( lld_init_max_aux_dur_tab = 0x3ff08d54 ); -PROVIDE ( lld_llcp_rx_ind_handler_wrapper = 0x4000f88c ); -PROVIDE ( lld_llcp_tx_cfm_handler = 0x4000f8ac ); -PROVIDE ( lld_per_adv_end_ind_handler = 0x40029710 ); -PROVIDE ( lld_per_adv_rep_ind_handler = 0x4002d5e4 ); -PROVIDE ( lld_per_adv_rx_end_ind_handler = 0x4002d9c0 ); -PROVIDE ( lld_phy_coded_500k_get = 0x4001d76c ); -PROVIDE ( lld_phy_upd_cfm_handler = 0x400111cc ); -PROVIDE ( lld_rpa_renew_env = 0x3fcefa8c ); -PROVIDE ( lld_scan_end_ind_handler = 0x4002dbc4 ); -PROVIDE ( lld_scan_map_legacy_pdu_to_evt_type = 0x3ff08d64 ); -PROVIDE ( lld_scan_max_aux_dur_tab = 0x3ff08d6c ); -PROVIDE ( lld_scan_req_ind_handler = 0x40028f2c ); -PROVIDE ( lld_sync_env = 0x3fcefaa0 ); -PROVIDE ( lld_sync_max_aux_dur_tab = 0x3ff08d74 ); -PROVIDE ( lld_sync_start_req_handler = 0x4002d4d0 ); -PROVIDE ( lld_test_end_ind_handler = 0x4002ddb8 ); -PROVIDE ( lld_update_rxbuf_handler = 0x4001e69c ); -PROVIDE ( ll_enc_req_handler = 0x4000de54 ); -PROVIDE ( ll_enc_rsp_handler = 0x4000df64 ); -PROVIDE ( ll_feature_req_handler = 0x4000e7d4 ); -PROVIDE ( ll_feature_rsp_handler = 0x4000e884 ); -PROVIDE ( ll_length_req_handler = 0x4000ce78 ); -PROVIDE ( ll_length_rsp_handler = 0x4000cefc ); -PROVIDE ( LLM_AA_CT1 = 0x3ff08d61 ); -PROVIDE ( LLM_AA_CT2 = 0x3ff08d5f ); -PROVIDE ( llm_ch_map_update_ind_handler = 0x4000ab84 ); -PROVIDE ( llm_hci_command_handler_wrapper = 0x4002a8e8 ); -PROVIDE ( ll_min_used_channels_ind_handler = 0x4000aa08 ); -PROVIDE ( llm_scan_period_to_handler = 0x4002cedc ); -PROVIDE ( ll_pause_enc_req_handler = 0x4000dd50 ); -PROVIDE ( ll_pause_enc_rsp_handler = 0x4000dddc ); -PROVIDE ( ll_phy_req_handler = 0x40010c70 ); -PROVIDE ( ll_phy_rsp_handler = 0x40010d50 ); -PROVIDE ( ll_phy_update_ind_handler = 0x40010de8 ); -PROVIDE ( ll_ping_req_handler = 0x4000f0a8 ); -PROVIDE ( ll_ping_rsp_handler = 0x4000f0b8 ); -PROVIDE ( ll_slave_feature_req_handler = 0x4000e82c ); -PROVIDE ( ll_start_enc_req_handler = 0x4000e004 ); -PROVIDE ( ll_start_enc_rsp_handler = 0x4000e070 ); -PROVIDE ( ll_terminate_ind_handler = 0x4000c5b4 ); -PROVIDE ( ll_version_ind_handler = 0x4001150c ); -PROVIDE ( __locale_ctype_ptr = 0x40034050 ); -PROVIDE ( __locale_ctype_ptr_l = 0x40034048 ); -PROVIDE ( __locale_mb_cur_max = 0x40034030 ); -PROVIDE ( _lock_acquire = 0x40054714 ); -PROVIDE ( _lock_acquire_recursive = 0x40054728 ); -PROVIDE ( _lock_close = 0x400546ec ); -PROVIDE ( _lock_close_recursive = 0x40054700 ); -PROVIDE ( _lock_init = 0x400546c4 ); -PROVIDE ( _lock_init_recursive = 0x400546d8 ); -PROVIDE ( _lock_release = 0x40054764 ); -PROVIDE ( _lock_release_recursive = 0x40054778 ); -PROVIDE ( _lock_try_acquire = 0x4005473c ); -PROVIDE ( _lock_try_acquire_recursive = 0x40054750 ); -PROVIDE ( longjmp = 0x400322d0 ); -PROVIDE ( _lseek_r = 0x4005468c ); -PROVIDE ( __lshrdi3 = 0x4005595c ); -PROVIDE ( __ltdf2 = 0x40037e28 ); -PROVIDE ( __ltsf2 = 0x40037ac4 ); -PROVIDE ( mac_addr_to_serial_str_desc = 0x4004b6f8 ); -PROVIDE ( main = 0x40045170 ); -PROVIDE ( malloc = 0x400547a0 ); -PROVIDE ( _malloc_r = 0x400544b4 ); -PROVIDE ( max_data_tx_time = 0x3ff08d34 ); -PROVIDE ( maxSecretKey_256 = 0x3ff081f8 ); -PROVIDE ( _mbtowc_r = 0x40039e9c ); -PROVIDE ( MD5Final = 0x40037740 ); -PROVIDE ( MD5Init = 0x400376a0 ); -PROVIDE ( MD5Update = 0x400376c0 ); -PROVIDE ( md5_vector = 0x400377a8 ); -PROVIDE ( memccpy = 0x40039ee8 ); -PROVIDE ( memchr = 0x40039f5c ); -PROVIDE ( memcmp = 0x40055480 ); -PROVIDE ( memcpy = 0x40055528 ); -PROVIDE ( MemDwnLdStartMsgProc = 0x4004881c ); -PROVIDE ( MemDwnLdStopReqMsgProc = 0x400488b0 ); -PROVIDE ( _memmap_cacheattr_bp_allvalid = 0x22222222 ); -PROVIDE ( _memmap_cacheattr_bp_base = 0x00000220 ); -PROVIDE ( _memmap_cacheattr_bp_strict = 0xfffff22f ); -PROVIDE ( _memmap_cacheattr_bp_trapnull = 0x2222222f ); -PROVIDE ( _memmap_cacheattr_reset = 0x2222211f ); -PROVIDE ( _memmap_cacheattr_unused_mask = 0xfffff00f ); -PROVIDE ( _memmap_cacheattr_wb_allvalid = 0x22222112 ); -PROVIDE ( _memmap_cacheattr_wba_trapnull = 0x2222211f ); -PROVIDE ( _memmap_cacheattr_wb_base = 0x00000110 ); -PROVIDE ( _memmap_cacheattr_wbna_trapnull = 0x2222211f ); -PROVIDE ( _memmap_cacheattr_wb_strict = 0xfffff11f ); -PROVIDE ( _memmap_cacheattr_wb_trapnull = 0x2222211f ); -PROVIDE ( _memmap_cacheattr_wt_allvalid = 0x22222112 ); -PROVIDE ( _memmap_cacheattr_wt_base = 0x00000110 ); -PROVIDE ( _memmap_cacheattr_wt_strict = 0xfffff11f ); -PROVIDE ( _memmap_cacheattr_wt_trapnull = 0x2222211f ); -PROVIDE ( _memmap_vecbase_reset = 0x40000000 ); -PROVIDE ( memmove = 0x40055620 ); -PROVIDE ( MemPacketSendReqMsgProc = 0x4004884c ); -PROVIDE ( memrchr = 0x40039ff8 ); -PROVIDE ( memset = 0x40055710 ); -PROVIDE ( memspi_host_erase_block = 0x4004ca10 ); -PROVIDE ( memspi_host_erase_chip = 0x4004c9c8 ); -PROVIDE ( memspi_host_erase_sector = 0x4004c9e8 ); -PROVIDE ( memspi_host_flush_cache = 0x4004c9ac ); -PROVIDE ( memspi_host_program_page = 0x4004ca38 ); -PROVIDE ( memspi_host_read = 0x4004ca64 ); -PROVIDE ( memspi_host_read_data_slicer = 0x4004cae8 ); -PROVIDE ( memspi_host_read_id_hs = 0x4004c90c ); -PROVIDE ( memspi_host_read_status_hs = 0x4004c974 ); -PROVIDE ( memspi_host_set_write_protect = 0x4004ca90 ); -PROVIDE ( memspi_host_write_data_slicer = 0x4004cab8 ); -PROVIDE ( __moddi3 = 0x40055eb8 ); -PROVIDE ( __modsi3 = 0x400558d0 ); -PROVIDE ( __muldc3 = 0x4003829c ); -PROVIDE ( __muldf3 = 0x40037c24 ); -PROVIDE ( __muldi3 = 0x40055b68 ); -PROVIDE ( __mulsc3 = 0x40037fd8 ); -PROVIDE ( __mulsf3 = 0x40037960 ); -PROVIDE ( __mulsi3 = 0x400558c0 ); -PROVIDE ( multofup = 0x40056664 ); -PROVIDE ( __mulvdi3 = 0x4003c548 ); -PROVIDE ( __mulvsi3 = 0x4003c530 ); -PROVIDE ( must_reset = 0x3fcef34c ); -PROVIDE ( mz_adler32 = 0x400352c4 ); -PROVIDE ( mz_crc32 = 0x4003538c ); -PROVIDE ( mz_free = 0x400353d8 ); -PROVIDE ( __nedf2 = 0x40037d40 ); -PROVIDE ( __negdf2 = 0x40037b38 ); -PROVIDE ( __negdi2 = 0x40055b80 ); -PROVIDE ( __negsf2 = 0x4003b9c8 ); -PROVIDE ( __negvdi2 = 0x4003c664 ); -PROVIDE ( __negvsi2 = 0x4003c644 ); -PROVIDE ( __nesf2 = 0x40037a0c ); -PROVIDE ( _NMIExceptionVector = 0x400002c0 ); -PROVIDE ( _NMIExceptionVector_text_end = 0x400002c3 ); -PROVIDE ( _NMIExceptionVector_text_start = 0x400002c0 ); -PROVIDE ( __nsau_data = 0x3ff07430 ); -PROVIDE ( one_bits = 0x3ff07802 ); -PROVIDE ( open = 0x4003b900 ); -PROVIDE ( _open_r = 0x40054654 ); -PROVIDE ( opi_flash_conf_cmd = 0x400515a0 ); -PROVIDE ( opi_flash_cpu_read = 0x40051b4c ); -PROVIDE ( opi_flash_erase_internal = 0x40051a04 ); -PROVIDE ( opi_flash_page_program_internal = 0x40051c18 ); -PROVIDE ( opi_flash_set_lock_func = 0x40051590 ); -PROVIDE ( _opi_flash_wren = 0x40051844 ); -PROVIDE ( opi_flash_wren = 0x40051874 ); -PROVIDE ( _opi_flash_write = 0x40051c98 ); -PROVIDE ( __packed = 0x3fcef344 ); -PROVIDE ( __paritysi2 = 0x4003c730 ); -PROVIDE ( _PathLocale = 0x3fcefcd0 ); -PROVIDE ( p_ble_util_buf_env = 0x3fcef8e0 ); -PROVIDE ( p_dbg_trc_mem_env = 0x3fcef96c ); -PROVIDE ( phy_get_romfuncs = 0x4003edd0 ); -PROVIDE ( p_lld_env = 0x3fcefa98 ); -PROVIDE ( p_llm_env = 0x3fcefac8 ); -PROVIDE ( __popcountdi2 = 0x4003c6d8 ); -PROVIDE ( __popcountsi2 = 0x4003c6a0 ); -PROVIDE ( __popcount_tab = 0x3ff07430 ); -PROVIDE ( __powidf2 = 0x40037f74 ); -PROVIDE ( __powisf2 = 0x40037f34 ); -PROVIDE ( _Pri_4_HandlerAddress = 0x3fcee37c ); -PROVIDE ( _Pri_5_HandlerAddress = 0x3fcee380 ); -PROVIDE ( _printf_common = 0x40033114 ); -PROVIDE ( _printf_float = 0x400547fc ); -PROVIDE ( _printf_i = 0x40033214 ); -PROVIDE ( print_other_reset_reason = 0x400450e4 ); -PROVIDE ( privacy_en = 0x3fcef3f4 ); -PROVIDE ( pthread_setcancelstate = 0x40054498 ); -PROVIDE ( _putc1 = 0x3fcefcbc ); -PROVIDE ( _putc2 = 0x3fcefcb8 ); -PROVIDE ( qsort = 0x4003239c ); -PROVIDE ( r_Add2SelfBigHex256 = 0x400041e0 ); -PROVIDE ( r_AddBigHex256 = 0x40004128 ); -PROVIDE ( r_AddBigHexModP256 = 0x4000417c ); -PROVIDE ( r_AddP256 = 0x400042c4 ); -PROVIDE ( r_AddPdiv2_256 = 0x400042f4 ); -PROVIDE ( r_aes_alloc = 0x40000e78 ); -PROVIDE ( r_aes_ccm_continue = 0x400005e0 ); -PROVIDE ( r_aes_ccm_process_e = 0x400006f8 ); -PROVIDE ( r_aes_ccm_xor_128_lsb = 0x4000056c ); -PROVIDE ( r_aes_ccm_xor_128_msb = 0x400005a4 ); -PROVIDE ( r_aes_cmac_continue = 0x400009b8 ); -PROVIDE ( r_aes_cmac_start = 0x4000097c ); -PROVIDE ( r_aes_k1_continue = 0x40000b20 ); -PROVIDE ( r_aes_k2_continue = 0x40000ba8 ); -PROVIDE ( r_aes_k3_continue = 0x40000d1c ); -PROVIDE ( r_aes_k4_continue = 0x40000da0 ); -PROVIDE ( r_aes_shift_left_128 = 0x40001000 ); -PROVIDE ( r_aes_start = 0x40000e98 ); -PROVIDE ( r_aes_xor_128 = 0x40000fd8 ); -PROVIDE ( _raise_r = 0x40054570 ); -PROVIDE ( rand = 0x4003a0e4 ); -PROVIDE ( rand_r = 0x4003a170 ); -PROVIDE ( r_assert_err = 0x4000106c ); -PROVIDE ( r_assert_param = 0x400010b8 ); -PROVIDE ( r_assert_warn = 0x40001104 ); -PROVIDE ( r_bigHexInversion256 = 0x40005248 ); -PROVIDE ( r_ble_sw_cca_check_isr = 0x4002ebb8 ); -PROVIDE ( r_ble_util_buf_acl_tx_alloc = 0x400015c4 ); -PROVIDE ( r_ble_util_buf_acl_tx_elt_get = 0x40001668 ); -PROVIDE ( r_ble_util_buf_acl_tx_free = 0x400016a4 ); -PROVIDE ( r_ble_util_buf_acl_tx_free_in_isr = 0x40001734 ); -PROVIDE ( r_ble_util_buf_adv_tx_alloc = 0x400017b4 ); -PROVIDE ( r_ble_util_buf_adv_tx_free = 0x40001828 ); -PROVIDE ( r_ble_util_buf_adv_tx_free_in_isr = 0x40001894 ); -PROVIDE ( r_ble_util_buf_env_deinit = 0x40001260 ); -PROVIDE ( r_ble_util_buf_env_init = 0x40001240 ); -PROVIDE ( r_ble_util_buf_get_rx_buf_nb = 0x40001280 ); -PROVIDE ( r_ble_util_buf_get_rx_buf_size = 0x40001290 ); -PROVIDE ( r_ble_util_buf_llcp_tx_alloc = 0x40001308 ); -PROVIDE ( r_ble_util_buf_llcp_tx_free = 0x40001334 ); -PROVIDE ( r_ble_util_buf_rx_alloc = 0x40001420 ); -PROVIDE ( r_ble_util_buf_rx_alloc_in_isr = 0x40001508 ); -PROVIDE ( r_ble_util_buf_rx_free = 0x40001480 ); -PROVIDE ( r_ble_util_buf_rx_free_in_isr = 0x40001564 ); -PROVIDE ( r_ble_util_buf_set_rx_buf_nb = 0x400012a8 ); -PROVIDE ( r_ble_util_buf_set_rx_buf_size = 0x400012dc ); -PROVIDE ( r_ble_util_data_rx_buf_reset = 0x400013a0 ); -PROVIDE ( r_bt_bb_get_intr_mask = 0x400093e8 ); -PROVIDE ( r_bt_bb_intr_clear = 0x400093d8 ); -PROVIDE ( r_bt_bb_intr_mask_set = 0x400093c4 ); -PROVIDE ( r_bt_bb_isr = 0x4000940c ); -PROVIDE ( r_btdm_isr = 0x4000948c ); -PROVIDE ( r_btdm_task_post = 0x40031f44 ); -PROVIDE ( r_btdm_task_post_from_isr = 0x40031f00 ); -PROVIDE ( r_btdm_task_recycle = 0x40031fc0 ); -PROVIDE ( r_bt_rf_coex_cfg_set = 0x4002e4f4 ); -PROVIDE ( r_bt_rf_coex_conn_dynamic_pti_en_get = 0x4002e57c ); -PROVIDE ( r_bt_rf_coex_conn_phy_coded_data_time_limit_en_get = 0x4002e60c ); -PROVIDE ( r_bt_rf_coex_ext_adv_dynamic_pti_en_get = 0x4002e5d4 ); -PROVIDE ( r_bt_rf_coex_ext_scan_dynamic_pti_en_get = 0x4002e598 ); -PROVIDE ( r_bt_rf_coex_legacy_adv_dynamic_pti_en_get = 0x4002e560 ); -PROVIDE ( r_bt_rf_coex_per_adv_dynamic_pti_en_get = 0x4002e5f0 ); -PROVIDE ( r_bt_rf_coex_pti_table_get = 0x4002e62c ); -PROVIDE ( r_bt_rf_coex_st_param_get = 0x4002e544 ); -PROVIDE ( r_bt_rf_coex_st_param_set = 0x4002e520 ); -PROVIDE ( r_bt_rf_coex_sync_scan_dynamic_pti_en_get = 0x4002e5b4 ); -PROVIDE ( r_bt_rma_apply_rule_cs_fmt = 0x4002e840 ); -PROVIDE ( r_bt_rma_apply_rule_cs_idx = 0x4002e910 ); -PROVIDE ( r_bt_rma_configure = 0x4002e764 ); -PROVIDE ( r_bt_rma_deregister_rule_cs_fmt = 0x4002e7f8 ); -PROVIDE ( r_bt_rma_deregister_rule_cs_idx = 0x4002e8d4 ); -PROVIDE ( r_bt_rma_get_ant_by_act = 0x4002e948 ); -PROVIDE ( r_bt_rma_init = 0x4002e74c ); -PROVIDE ( r_bt_rma_register_rule_cs_fmt = 0x4002e798 ); -PROVIDE ( r_bt_rma_register_rule_cs_idx = 0x4002e884 ); -PROVIDE ( r_bt_rtp_apply_rule_cs_fmt = 0x4002ea50 ); -PROVIDE ( r_bt_rtp_apply_rule_cs_idx = 0x4002eb10 ); -PROVIDE ( r_bt_rtp_deregister_rule_cs_fmt = 0x4002ea08 ); -PROVIDE ( r_bt_rtp_deregister_rule_cs_idx = 0x4002ead4 ); -PROVIDE ( r_bt_rtp_get_txpwr_idx_by_act = 0x4002eb40 ); -PROVIDE ( r_bt_rtp_init = 0x4002e9a0 ); -PROVIDE ( r_bt_rtp_register_rule_cs_fmt = 0x4002e9b4 ); -PROVIDE ( r_bt_rtp_register_rule_cs_idx = 0x4002ea8c ); -PROVIDE ( r_cali_phase_match_p = 0x40001af8 ); -PROVIDE ( r_cmp_abs_time = 0x4000a31c ); -PROVIDE ( r_cmp_dest_id = 0x40009de0 ); -PROVIDE ( r_cmp_timer_id = 0x4000a340 ); -PROVIDE ( r_co_bdaddr_compare = 0x400020ac ); -PROVIDE ( r_co_ble_pkt_dur_in_us = 0x400025e8 ); -PROVIDE ( r_co_bytes_to_string = 0x40002074 ); -PROVIDE ( r_co_list_extract = 0x40001d88 ); -PROVIDE ( r_co_list_extract_after = 0x40001e28 ); -PROVIDE ( r_co_list_extract_sublist = 0x40001eac ); -PROVIDE ( r_co_list_find = 0x40001ef0 ); -PROVIDE ( r_co_list_init = 0x40001c4c ); -PROVIDE ( r_co_list_insert_after = 0x40001fa8 ); -PROVIDE ( r_co_list_insert_before = 0x40001f50 ); -PROVIDE ( r_co_list_merge = 0x40001f0c ); -PROVIDE ( r_co_list_pool_init = 0x40001c60 ); -PROVIDE ( r_co_list_pop_front = 0x40001d64 ); -PROVIDE ( r_co_list_push_back = 0x40001c94 ); -PROVIDE ( r_co_list_push_back_sublist = 0x40001cd8 ); -PROVIDE ( r_co_list_push_front = 0x40001d30 ); -PROVIDE ( r_co_list_size = 0x40002000 ); -PROVIDE ( r_co_nb_good_le_channels = 0x400020d0 ); -PROVIDE ( r_co_util_pack = 0x4000210c ); -PROVIDE ( r_co_util_read_array_size = 0x40002020 ); -PROVIDE ( r_co_util_unpack = 0x4000236c ); -PROVIDE ( RcvMsg = 0x40049c64 ); -PROVIDE ( r_dbg_env_deinit = 0x40002650 ); -PROVIDE ( r_dbg_env_init = 0x4000263c ); -PROVIDE ( r_dbg_esp_vendor_hci_command_handler = 0x40002fcc ); -PROVIDE ( r_dbg_hci_cmd_handler_tab_p_get = 0x40002fa8 ); -PROVIDE ( r_dbg_hci_command_handler = 0x40003010 ); -PROVIDE ( r_dbg_init = 0x40002664 ); -PROVIDE ( r_dbg_msg_handler_tab_p_get = 0x40003088 ); -PROVIDE ( r_dbg_platform_reset_complete = 0x400026a8 ); -PROVIDE ( r_dbg_register_esp_vendor_cmd_handler = 0x40002fb8 ); -PROVIDE ( r_dbg_sch_plan_move = 0x40002f98 ); -PROVIDE ( r_dbg_swdiag_init = 0x4000276c ); -PROVIDE ( r_dbg_swdiag_read = 0x400027a4 ); -PROVIDE ( r_dbg_swdiag_update = 0x400026f8 ); -PROVIDE ( r_dbg_swdiag_write = 0x400027cc ); -PROVIDE ( r_dbg_trc_cfg_received = 0x4000405c ); -PROVIDE ( r_dbg_trc_ke_evt_cbk = 0x40003248 ); -PROVIDE ( r_dbg_trc_mem_alloc = 0x400030e4 ); -PROVIDE ( r_dbg_trc_mem_dealloc = 0x400031dc ); -PROVIDE ( r_dbg_trc_mem_read = 0x4000318c ); -PROVIDE ( r_dbg_trc_mem_writing_allowed = 0x40003094 ); -PROVIDE ( r_dbg_trc_pay_buff_get = 0x400040d0 ); -PROVIDE ( r_dbg_trc_req_acl_rx_pdu = 0x40003dac ); -PROVIDE ( r_dbg_trc_req_acl_tx_pdu = 0x40003e08 ); -PROVIDE ( r_dbg_trc_req_adv_rx_pdu = 0x40003974 ); -PROVIDE ( r_dbg_trc_req_adv_tx_pdu = 0x400039fc ); -PROVIDE ( r_dbg_trc_req_cs_ble = 0x400035c4 ); -PROVIDE ( r_dbg_trc_req_custom = 0x40003ed0 ); -PROVIDE ( r_dbg_trc_req_deep_sleep = 0x400033f8 ); -PROVIDE ( r_dbg_trc_req_et_prog = 0x400034b0 ); -PROVIDE ( r_dbg_trc_req_evt_cnt = 0x40003524 ); -PROVIDE ( r_dbg_trc_req_frm_cmp = 0x40003568 ); -PROVIDE ( r_dbg_trc_req_hci_cmd = 0x400038c8 ); -PROVIDE ( r_dbg_trc_req_hci_evt = 0x4000391c ); -PROVIDE ( r_dbg_trc_req_init_rx_pdu = 0x40003ae0 ); -PROVIDE ( r_dbg_trc_req_init_tx_pdu = 0x40003b74 ); -PROVIDE ( r_dbg_trc_req_ke_evt = 0x40003360 ); -PROVIDE ( r_dbg_trc_req_ke_msg_handled = 0x400032ac ); -PROVIDE ( r_dbg_trc_req_ke_msg_send = 0x40003268 ); -PROVIDE ( r_dbg_trc_req_ke_tmr = 0x40003304 ); -PROVIDE ( r_dbg_trc_req_l2cap = 0x400036b0 ); -PROVIDE ( r_dbg_trc_req_l2cap_ack = 0x40003710 ); -PROVIDE ( r_dbg_trc_req_llcp = 0x40003664 ); -PROVIDE ( r_dbg_trc_req_llc_state_trans = 0x40003878 ); -PROVIDE ( r_dbg_trc_req_mem = 0x4000339c ); -PROVIDE ( r_dbg_trc_req_rx_desc = 0x40003610 ); -PROVIDE ( r_dbg_trc_req_scan_rx_pdu = 0x40003c0c ); -PROVIDE ( r_dbg_trc_req_scan_tx_pdu = 0x40003cc8 ); -PROVIDE ( r_dbg_trc_req_sch_arb = 0x400037bc ); -PROVIDE ( r_dbg_trc_req_sch_arb_insert = 0x40003754 ); -PROVIDE ( r_dbg_trc_req_sch_arb_shift = 0x40003800 ); -PROVIDE ( r_dbg_trc_req_sw_ass = 0x40003428 ); -PROVIDE ( r_dbg_trc_tx_done = 0x40004014 ); -PROVIDE ( r_dbg_trc_tx_start = 0x40003fb8 ); -PROVIDE ( r_dbg_trc_tx_trigger = 0x40004040 ); -PROVIDE ( r_dl_upd_proc_start = 0x4000d160 ); -PROVIDE ( r_dump_data = 0x40001144 ); -PROVIDE ( read = 0x4003b94c ); -PROVIDE ( _read_r = 0x400546a8 ); -PROVIDE ( realloc = 0x400547cc ); -PROVIDE ( _realloc_r = 0x400544e0 ); -PROVIDE ( r_ecc_abort_key256_generation = 0x40005fec ); -PROVIDE ( r_ecc_generate_key256 = 0x40005d18 ); -PROVIDE ( r_ecc_gen_new_public_key = 0x4000604c ); -PROVIDE ( r_ecc_gen_new_secret_key = 0x40006070 ); -PROVIDE ( r_ecc_get_debug_Keys = 0x4000618c ); -PROVIDE ( r_ecc_init = 0x40005ca4 ); -PROVIDE ( r_ecc_is_valid_point = 0x40005930 ); -PROVIDE ( r_ecc_multiplication_event_handler = 0x40005a64 ); -PROVIDE ( r_ecc_point_multiplication_win_256 = 0x400054dc ); -PROVIDE ( recv_packet = 0x40049b3c ); -PROVIDE ( r_emi_alloc_em_mapping_by_offset = 0x40006534 ); -PROVIDE ( r_emi_base_reg_lut_show = 0x400062b8 ); -PROVIDE ( r_emi_em_base_reg_show = 0x40006258 ); -PROVIDE ( r_emi_free_em_mapping_by_offset = 0x400066f0 ); -PROVIDE ( r_emi_get_em_mapping_idx_by_offset = 0x400063d8 ); -PROVIDE ( r_emi_get_mem_addr_by_offset = 0x40006300 ); -PROVIDE ( r_emi_overwrite_em_mapping_by_offset = 0x40006424 ); -PROVIDE ( _rename_r = 0x40054528 ); -PROVIDE ( _ResetHandler = 0x40000454 ); -PROVIDE ( _ResetVector = 0x40000400 ); -PROVIDE ( _ResetVector_literal_end = 0x4000056c ); -PROVIDE ( _ResetVector_literal_start = 0x4000056c ); -PROVIDE ( _ResetVector_text_end = 0x40000569 ); -PROVIDE ( _ResetVector_text_start = 0x40000400 ); -PROVIDE ( r_flash_env_deinit = 0x4000696c ); -PROVIDE ( r_flash_env_init = 0x4000693c ); -PROVIDE ( r_flash_erase = 0x40006a34 ); -PROVIDE ( r_flash_identify = 0x400069d4 ); -PROVIDE ( r_flash_init = 0x40006990 ); -PROVIDE ( r_flash_read = 0x40006a9c ); -PROVIDE ( r_flash_unlock = 0x40006928 ); -PROVIDE ( r_flash_unlocksector = 0x40006920 ); -PROVIDE ( r_flash_write = 0x40006a68 ); -PROVIDE ( r_flash_writebyte = 0x40006904 ); -PROVIDE ( r_get_stack_usage = 0x4000118c ); -PROVIDE ( r_GF_Jacobian_Point_Addition256 = 0x400049d0 ); -PROVIDE ( r_GF_Jacobian_Point_Double256 = 0x40004f54 ); -PROVIDE ( r_GF_Point_Jacobian_To_Affine256 = 0x400051b0 ); -PROVIDE ( r_h4tl_acl_hdr_rx_evt_handler = 0x40007074 ); -PROVIDE ( r_h4tl_cmd_hdr_rx_evt_handler = 0x40006fb0 ); -PROVIDE ( r_h4tl_cmd_pld_rx_evt_handler = 0x4000702c ); -PROVIDE ( r_h4tl_eif_io_event_post = 0x40006234 ); -PROVIDE ( r_h4tl_eif_p = 0x3fcef474 ); -PROVIDE ( r_h4tl_eif_register = 0x400061dc ); -PROVIDE ( r_h4tl_init = 0x400070f8 ); -PROVIDE ( r_h4tl_out_of_sync = 0x40006bac ); -PROVIDE ( r_h4tl_out_of_sync_check = 0x40006c04 ); -PROVIDE ( r_h4tl_read_hdr = 0x40006b3c ); -PROVIDE ( r_h4tl_read_next_out_of_sync = 0x40006b88 ); -PROVIDE ( r_h4tl_read_payl = 0x40006b68 ); -PROVIDE ( r_h4tl_read_start = 0x40006b10 ); -PROVIDE ( r_h4tl_rx_acl_hdr_extract = 0x40006aec ); -PROVIDE ( r_h4tl_rx_cmd_hdr_extract = 0x40006ad0 ); -PROVIDE ( r_h4tl_rx_done = 0x40006d84 ); -PROVIDE ( r_h4tl_start = 0x40007200 ); -PROVIDE ( r_h4tl_stop = 0x40007210 ); -PROVIDE ( r_h4tl_tx_done = 0x40006cb0 ); -PROVIDE ( r_h4tl_tx_evt_handler = 0x40006cec ); -PROVIDE ( r_h4tl_write = 0x40007170 ); -PROVIDE ( r_hci_acl_tx_data_alloc = 0x400092a8 ); -PROVIDE ( r_hci_acl_tx_data_received = 0x40009344 ); -PROVIDE ( r_hci_basic_cmd_send_2_controller = 0x400082b0 ); -PROVIDE ( r_hci_ble_adv_report_filter_check = 0x40008420 ); -PROVIDE ( r_hci_ble_adv_report_tx_check = 0x4000866c ); -PROVIDE ( r_hci_ble_conhdl_register = 0x400082dc ); -PROVIDE ( r_hci_ble_conhdl_unregister = 0x40008334 ); -PROVIDE ( r_hci_build_acl_data = 0x40008b60 ); -PROVIDE ( r_hci_build_cc_evt = 0x40008854 ); -PROVIDE ( r_hci_build_cs_evt = 0x40008820 ); -PROVIDE ( r_hci_build_dbg_evt = 0x400089f4 ); -PROVIDE ( r_hci_build_evt = 0x40008918 ); -PROVIDE ( r_hci_build_le_evt = 0x40008aa4 ); -PROVIDE ( r_hci_cmd_get_max_param_size = 0x40009030 ); -PROVIDE ( r_hci_cmd_received = 0x40009054 ); -PROVIDE ( r_hci_cmd_reject = 0x400086f8 ); -PROVIDE ( r_hci_evt_mask_check = 0x40007f28 ); -PROVIDE ( r_hci_evt_mask_set = 0x40008394 ); -PROVIDE ( r_hci_fc_acl_buf_size_set = 0x40007260 ); -PROVIDE ( r_hci_fc_acl_en = 0x40007280 ); -PROVIDE ( r_hci_fc_acl_packet_sent = 0x400072c0 ); -PROVIDE ( r_hci_fc_check_host_available_nb_acl_packets = 0x400072fc ); -PROVIDE ( r_hci_fc_host_nb_acl_pkts_complete = 0x400072d8 ); -PROVIDE ( r_hci_fc_init = 0x4000724c ); -PROVIDE ( r_hci_look_for_cmd_desc = 0x40007e1c ); -PROVIDE ( r_hci_look_for_dbg_evt_desc = 0x40007ec8 ); -PROVIDE ( r_hci_look_for_evt_desc = 0x40007e9c ); -PROVIDE ( r_hci_look_for_le_evt_desc = 0x40007ee0 ); -PROVIDE ( r_hci_look_for_le_evt_desc_esp = 0x40007f0c ); -PROVIDE ( r_hci_pack_bytes = 0x40007de4 ); -PROVIDE ( r_hci_register_vendor_desc_tab = 0x40007dd0 ); -PROVIDE ( r_hci_send_2_controller = 0x400081d0 ); -PROVIDE ( r_hci_send_2_host = 0x40007fe4 ); -PROVIDE ( r_hci_tl_c2h_data_flow_on = 0x40008dfc ); -PROVIDE ( r_hci_tl_cmd_hdr_rx_evt_handler = 0x40008ec8 ); -PROVIDE ( r_hci_tl_cmd_pld_rx_evt_handler = 0x40008f1c ); -PROVIDE ( r_hci_tl_get_pkt = 0x40008ebc ); -PROVIDE ( r_hci_tl_hci_pkt_handler = 0x40008f74 ); -PROVIDE ( r_hci_tl_hci_tx_done_evt_handler = 0x40009010 ); -PROVIDE ( r_hci_tl_inc_nb_h2c_cmd_pkts = 0x40008e6c ); -PROVIDE ( r_hci_tl_save_pkt = 0x40008e88 ); -PROVIDE ( r_hci_tl_send = 0x40008e14 ); -PROVIDE ( r_hci_tx_done = 0x40008d1c ); -PROVIDE ( r_hci_tx_start = 0x40008b90 ); -PROVIDE ( r_hci_tx_trigger = 0x40008de0 ); -PROVIDE ( r_hli_funcs_p = 0x3fcef4c8 ); -PROVIDE ( r_ip_funcs_p = 0x3fcef4cc ); -PROVIDE ( r_isValidSecretKey_256 = 0x400040dc ); -PROVIDE ( r_ke_check_malloc = 0x40009740 ); -PROVIDE ( r_ke_event_callback_set = 0x400094d4 ); -PROVIDE ( r_ke_event_clear = 0x40009568 ); -PROVIDE ( r_ke_event_flush = 0x4000960c ); -PROVIDE ( r_ke_event_get = 0x400095b4 ); -PROVIDE ( r_ke_event_get_all = 0x40009600 ); -PROVIDE ( r_ke_event_init = 0x400094bc ); -PROVIDE ( r_ke_event_schedule = 0x4000961c ); -PROVIDE ( r_ke_event_set = 0x4000950c ); -PROVIDE ( r_ke_flush = 0x40009d4c ); -PROVIDE ( r_ke_free = 0x400099b4 ); -PROVIDE ( r_ke_get_max_mem_usage = 0x40009b9c ); -PROVIDE ( r_ke_get_mem_usage = 0x40009b74 ); -PROVIDE ( r_ke_handler_search = 0x40009e54 ); -PROVIDE ( r_ke_init = 0x40009cf4 ); -PROVIDE ( r_ke_is_free = 0x40009b58 ); -PROVIDE ( r_ke_malloc = 0x40009808 ); -PROVIDE ( r_ke_mem_init = 0x400096b8 ); -PROVIDE ( r_ke_mem_is_empty = 0x400096f0 ); -PROVIDE ( r_ke_msg_alloc = 0x40009bb4 ); -PROVIDE ( r_ke_msg_dest_id_get = 0x40009cbc ); -PROVIDE ( r_ke_msg_discard = 0x4000a258 ); -PROVIDE ( r_ke_msg_forward = 0x40009c6c ); -PROVIDE ( r_ke_msg_forward_new_id = 0x40009c88 ); -PROVIDE ( r_ke_msg_free = 0x40009ca8 ); -PROVIDE ( r_ke_msg_in_queue = 0x40009cd4 ); -PROVIDE ( r_ke_msg_save = 0x4000a260 ); -PROVIDE ( r_ke_msg_send = 0x40009c08 ); -PROVIDE ( r_ke_msg_send_basic = 0x40009c48 ); -PROVIDE ( r_ke_msg_src_id_get = 0x40009cc8 ); -PROVIDE ( r_ke_queue_extract = 0x400320d8 ); -PROVIDE ( r_ke_queue_insert = 0x40032128 ); -PROVIDE ( r_ke_sleep_check = 0x40009da8 ); -PROVIDE ( r_ke_state_get = 0x4000a1d8 ); -PROVIDE ( r_ke_state_set = 0x4000a134 ); -PROVIDE ( r_ke_stats_get = 0x40009dc0 ); -PROVIDE ( r_ke_task_check = 0x4000a2ac ); -PROVIDE ( r_ke_task_create = 0x4000a0b4 ); -PROVIDE ( r_ke_task_delete = 0x4000a100 ); -PROVIDE ( r_ke_task_handler_get = 0x40009ec0 ); -PROVIDE ( r_ke_task_init = 0x4000a090 ); -PROVIDE ( r_ke_task_msg_flush = 0x4000a268 ); -PROVIDE ( r_ke_task_saved_update = 0x40009df4 ); -PROVIDE ( r_ke_task_schedule = 0x40009f34 ); -PROVIDE ( r_ke_time = 0x4000a458 ); -PROVIDE ( r_ke_time_cmp = 0x4000a2e0 ); -PROVIDE ( r_ke_time_past = 0x4000a300 ); -PROVIDE ( r_ke_timer_active = 0x4000a600 ); -PROVIDE ( r_ke_timer_adjust_all = 0x4000a628 ); -PROVIDE ( r_ke_timer_clear = 0x4000a574 ); -PROVIDE ( r_ke_timer_init = 0x4000a440 ); -PROVIDE ( r_ke_timer_schedule = 0x4000a360 ); -PROVIDE ( r_ke_timer_set = 0x4000a490 ); -PROVIDE ( r_led_init = 0x40032160 ); -PROVIDE ( r_led_set_all = 0x40032168 ); -PROVIDE ( r_llc_aes_res_cb = 0x4000d1e8 ); -PROVIDE ( r_llc_ch_map_up_proc_err_cb = 0x4000a8c0 ); -PROVIDE ( r_llc_cleanup = 0x4000fa20 ); -PROVIDE ( r_llc_cmd_cmp_send = 0x4000ec9c ); -PROVIDE ( r_llc_cmd_stat_send = 0x4000ecd0 ); -PROVIDE ( r_llc_con_move_cbk = 0x4000c1e8 ); -PROVIDE ( r_llc_con_plan_set_update = 0x4000b534 ); -PROVIDE ( r_llc_con_upd_param_in_range = 0x4000ac70 ); -PROVIDE ( r_llc_disconnect = 0x4000c8fc ); -PROVIDE ( r_llc_disconnect_end = 0x4000c40c ); -PROVIDE ( r_llc_disconnect_proc_continue = 0x4000c46c ); -PROVIDE ( r_llc_disconnect_proc_err_cb = 0x4000c57c ); -PROVIDE ( r_llc_dl_chg_check = 0x40010b7c ); -PROVIDE ( r_llc_dle_proc_err_cb = 0x4000cdec ); -PROVIDE ( r_llc_feats_exch_proc_err_cb = 0x4000e758 ); -PROVIDE ( r_llc_hci_cmd_handler_tab_p_get = 0x4000ed00 ); -PROVIDE ( r_llc_hci_command_handler = 0x4000ed08 ); -PROVIDE ( r_llc_hci_con_param_req_evt_send = 0x4000b4e4 ); -PROVIDE ( r_llc_hci_con_upd_info_send = 0x4000b674 ); -PROVIDE ( r_llc_hci_disconnected_dis = 0x4000c808 ); -PROVIDE ( r_llc_hci_dl_upd_info_send = 0x4000c9f4 ); -PROVIDE ( r_llc_hci_enc_evt_send = 0x4000dc08 ); -PROVIDE ( r_llc_hci_feats_info_send = 0x4000e624 ); -PROVIDE ( r_llc_hci_le_phy_upd_cmp_evt_send = 0x40010a3c ); -PROVIDE ( r_llc_hci_ltk_request_evt_send = 0x4000dbc4 ); -PROVIDE ( r_llc_hci_nb_cmp_pkts_evt_send = 0x4000ec64 ); -PROVIDE ( r_llc_hci_version_info_send = 0x40011300 ); -PROVIDE ( r_llc_init_term_proc = 0x4000c940 ); -PROVIDE ( r_llc_iv_skd_rand_gen = 0x4000d228 ); -PROVIDE ( r_llc_le_ping_proc_continue = 0x4000efe4 ); -PROVIDE ( r_llc_le_ping_proc_err_cb = 0x4000ef6c ); -PROVIDE ( r_llc_le_ping_restart = 0x4000f314 ); -PROVIDE ( r_llc_le_ping_set = 0x4000f358 ); -PROVIDE ( r_llc_llcp_send = 0x4000f4f8 ); -PROVIDE ( r_llc_llcp_state_set = 0x4000fd84 ); -PROVIDE ( r_llc_llcp_trans_timer_set = 0x4000f9a8 ); -PROVIDE ( r_llc_llcp_tx_check = 0x4000f5bc ); -PROVIDE ( r_llc_ll_pause_enc_rsp_ack_handler = 0x4000db34 ); -PROVIDE ( r_llc_ll_reject_ind_ack_handler = 0x4000db94 ); -PROVIDE ( r_llc_ll_reject_ind_pdu_send = 0x4000f494 ); -PROVIDE ( r_llc_ll_start_enc_rsp_ack_handler = 0x4000db64 ); -PROVIDE ( r_llc_ll_terminate_ind_ack = 0x4000c564 ); -PROVIDE ( r_llc_ll_unknown_ind_handler = 0x4000f484 ); -PROVIDE ( r_llc_loc_ch_map_proc_continue = 0x4000a748 ); -PROVIDE ( r_llc_loc_con_upd_proc_continue = 0x4000af0c ); -PROVIDE ( r_llc_loc_con_upd_proc_err_cb = 0x4000b770 ); -PROVIDE ( r_llc_loc_dl_upd_proc_continue = 0x4000ca4c ); -PROVIDE ( r_llc_loc_encrypt_proc_continue = 0x4000d38c ); -PROVIDE ( r_llc_loc_encrypt_proc_err_cb = 0x4000dc58 ); -PROVIDE ( r_llc_loc_feats_exch_proc_continue = 0x4000e66c ); -PROVIDE ( r_llc_loc_phy_upd_proc_continue = 0x400105b0 ); -PROVIDE ( r_llc_loc_phy_upd_proc_err_cb = 0x40010ab8 ); -PROVIDE ( r_llc_msg_handler_tab_p_get = 0x400112c4 ); -PROVIDE ( r_llcp_pdu_handler_tab_p_get = 0x4000f458 ); -PROVIDE ( r_llc_pref_param_compute = 0x4000acf4 ); -PROVIDE ( r_llc_proc_collision_check = 0x4001022c ); -PROVIDE ( r_llc_proc_err_ind = 0x40010080 ); -PROVIDE ( r_llc_proc_get = 0x4001004c ); -PROVIDE ( r_llc_proc_id_get = 0x4000ffe8 ); -PROVIDE ( r_llc_proc_reg = 0x4000fea4 ); -PROVIDE ( r_llc_proc_state_get = 0x40010020 ); -PROVIDE ( r_llc_proc_state_set = 0x40010028 ); -PROVIDE ( r_llc_proc_timer_pause_set = 0x4001017c ); -PROVIDE ( r_llc_proc_timer_set = 0x400100c4 ); -PROVIDE ( r_llc_proc_unreg = 0x4000ff44 ); -PROVIDE ( r_llc_rem_ch_map_proc_continue = 0x4000a64c ); -PROVIDE ( r_llc_rem_con_upd_proc_continue = 0x4000b288 ); -PROVIDE ( r_llc_rem_con_upd_proc_err_cb = 0x4000b810 ); -PROVIDE ( r_llc_rem_dl_upd_proc = 0x4000cc74 ); -PROVIDE ( r_llc_rem_encrypt_proc_continue = 0x4000d734 ); -PROVIDE ( r_llc_rem_encrypt_proc_err_cb = 0x4000dcf4 ); -PROVIDE ( r_llc_rem_phy_upd_proc_continue = 0x400102c4 ); -PROVIDE ( r_llc_rem_phy_upd_proc_err_cb = 0x40010b44 ); -PROVIDE ( r_llc_role_get = 0x4000fd48 ); -PROVIDE ( r_llc_sk_gen = 0x4000d248 ); -PROVIDE ( r_llc_start = 0x4000fb10 ); -PROVIDE ( r_llc_stop = 0x4000fab4 ); -PROVIDE ( r_llc_ver_exch_loc_proc_continue = 0x4001134c ); -PROVIDE ( r_llc_ver_proc_err_cb = 0x40011444 ); -PROVIDE ( r_lld_aa_gen = 0x4001e1c4 ); -PROVIDE ( r_lld_adv_adv_data_set = 0x4001349c ); -PROVIDE ( r_lld_adv_adv_data_update = 0x40016978 ); -PROVIDE ( r_lld_adv_aux_ch_idx_set = 0x400124dc ); -PROVIDE ( r_lld_adv_aux_evt_canceled_cbk = 0x400148f8 ); -PROVIDE ( r_lld_adv_aux_evt_start_cbk = 0x400144ac ); -PROVIDE ( r_lld_adv_coex_check_ext_adv_synced = 0x40016c7c ); -PROVIDE ( r_lld_adv_coex_env_reset = 0x4001163c ); -PROVIDE ( r_lld_adv_duration_update = 0x40016a80 ); -PROVIDE ( r_lld_adv_dynamic_pti_process = 0x400116bc ); -PROVIDE ( r_lld_adv_end = 0x400121e0 ); -PROVIDE ( r_lld_adv_evt_canceled_cbk = 0x4001479c ); -PROVIDE ( r_lld_adv_evt_start_cbk = 0x4001411c ); -PROVIDE ( r_lld_adv_ext_chain_construct = 0x40012c7c ); -PROVIDE ( r_lld_adv_ext_pkt_prepare = 0x40012688 ); -PROVIDE ( r_lld_adv_frm_cbk = 0x40015060 ); -PROVIDE ( r_lld_adv_frm_isr = 0x40014aac ); -PROVIDE ( r_lld_adv_frm_skip_isr = 0x40014ea8 ); -PROVIDE ( r_lld_adv_init = 0x400150b0 ); -PROVIDE ( r_lld_adv_pkt_rx = 0x40014040 ); -PROVIDE ( r_lld_adv_pkt_rx_connect_ind = 0x400139ac ); -PROVIDE ( r_lld_adv_pkt_rx_send_scan_req_evt = 0x40013ee8 ); -PROVIDE ( r_lld_adv_rand_addr_update = 0x40016af0 ); -PROVIDE ( r_lld_adv_restart = 0x40016bb4 ); -PROVIDE ( r_lld_adv_scan_rsp_data_set = 0x40013730 ); -PROVIDE ( r_lld_adv_scan_rsp_data_update = 0x400169fc ); -PROVIDE ( r_lld_adv_set_tx_power = 0x4001217c ); -PROVIDE ( r_lld_adv_start = 0x4001519c ); -PROVIDE ( r_lld_adv_stop = 0x40016890 ); -PROVIDE ( r_lld_adv_sync_info_set = 0x400122a4 ); -PROVIDE ( r_lld_adv_sync_info_update = 0x40016c2c ); -PROVIDE ( r_lld_calc_aux_rx = 0x4001e27c ); -PROVIDE ( r_lld_cca_alloc = 0x4001e944 ); -PROVIDE ( r_lld_cca_data_reset = 0x4001ea04 ); -PROVIDE ( r_lld_cca_free = 0x4001e9a0 ); -PROVIDE ( r_lld_channel_assess = 0x4001d704 ); -PROVIDE ( r_lld_ch_assess_data_get = 0x4001d830 ); -PROVIDE ( r_lld_ch_idx_get = 0x4001e454 ); -PROVIDE ( r_lld_ch_map_set = 0x4001e408 ); -PROVIDE ( r_lld_con_activity_act_offset_compute = 0x4001a3c0 ); -PROVIDE ( r_lld_con_activity_offset_compute = 0x4001a4b0 ); -PROVIDE ( r_lld_con_ch_map_update = 0x4001a18c ); -PROVIDE ( r_lld_con_cleanup = 0x40017368 ); -PROVIDE ( r_lld_con_current_tx_power_get = 0x4001a77c ); -PROVIDE ( r_lld_con_data_flow_set = 0x40019fe4 ); -PROVIDE ( r_lld_con_data_len_update = 0x4001a1e8 ); -PROVIDE ( r_lld_con_data_tx = 0x40019e34 ); -PROVIDE ( r_lld_con_enc_key_load = 0x4001a654 ); -PROVIDE ( r_lld_con_event_counter_get = 0x4001a38c ); -PROVIDE ( r_lld_con_evt_canceled_cbk = 0x40018c5c ); -PROVIDE ( r_lld_con_evt_duration_min_get = 0x40017330 ); -PROVIDE ( r_lld_con_evt_max_eff_time_cal = 0x4001702c ); -PROVIDE ( r_lld_con_evt_sd_evt_time_get = 0x4001aa70 ); -PROVIDE ( r_lld_con_evt_start_cbk = 0x400187d0 ); -PROVIDE ( r_lld_con_evt_time_update = 0x40017060 ); -PROVIDE ( r_lld_con_free_all_tx_buf = 0x4001a9ac ); -PROVIDE ( r_lld_con_frm_cbk = 0x40019160 ); -PROVIDE ( r_lld_con_frm_isr = 0x40018d40 ); -PROVIDE ( r_lld_con_frm_skip_isr = 0x40019050 ); -PROVIDE ( r_lld_con_init = 0x4001a95c ); -PROVIDE ( r_lld_con_llcp_tx = 0x40019c74 ); -PROVIDE ( r_lld_con_max_lat_calc = 0x40016f04 ); -PROVIDE ( r_lld_conn_dynamic_pti_process = 0x40016cb0 ); -PROVIDE ( r_lld_con_offset_get = 0x4001a830 ); -PROVIDE ( r_lld_con_param_update = 0x4001a0dc ); -PROVIDE ( r_lld_con_phys_update = 0x4001a24c ); -PROVIDE ( r_lld_con_pref_slave_evt_dur_set = 0x4001a8f4 ); -PROVIDE ( r_lld_con_pref_slave_latency_set = 0x4001a8a4 ); -PROVIDE ( r_lld_con_rssi_get = 0x4001a7ec ); -PROVIDE ( r_lld_con_rx = 0x40017de4 ); -PROVIDE ( r_lld_con_rx_channel_assess = 0x4001798c ); -PROVIDE ( r_lld_con_rx_enc = 0x4001a5e8 ); -PROVIDE ( r_lld_con_rx_isr = 0x40018f14 ); -PROVIDE ( r_lld_con_rx_link_info_check = 0x40017bcc ); -PROVIDE ( r_lld_con_rx_llcp_check = 0x40017a0c ); -PROVIDE ( r_lld_con_rx_sync_time_update = 0x40017c94 ); -PROVIDE ( r_lld_con_sched = 0x400175c8 ); -PROVIDE ( r_lld_con_set_tx_power = 0x40016e94 ); -PROVIDE ( r_lld_con_start = 0x400191f8 ); -PROVIDE ( r_lld_con_stop = 0x40019be8 ); -PROVIDE ( r_lld_continue_scan_rx_isr_end_process = 0x40021060 ); -PROVIDE ( r_lld_con_tx = 0x40017f50 ); -PROVIDE ( r_lld_con_tx_enc = 0x4001a578 ); -PROVIDE ( r_lld_con_tx_isr = 0x40018fa4 ); -PROVIDE ( r_lld_con_tx_len_update = 0x40016f98 ); -PROVIDE ( r_lld_con_tx_len_update_for_intv = 0x4001a2d4 ); -PROVIDE ( r_lld_con_tx_len_update_for_rate = 0x4001a31c ); -PROVIDE ( r_lld_con_tx_prog = 0x400182d0 ); -PROVIDE ( r_lld_ext_scan_dynamic_pti_process = 0x40020bb4 ); -PROVIDE ( r_lld_hw_cca_end_isr = 0x4001eb90 ); -PROVIDE ( r_lld_hw_cca_evt_handler = 0x4001eb44 ); -PROVIDE ( r_lld_hw_cca_isr = 0x4001eb64 ); -PROVIDE ( r_lld_init_cal_anchor_point = 0x4001b6d4 ); -PROVIDE ( r_lld_init_compute_winoffset = 0x4001ac0c ); -PROVIDE ( r_lld_init_connect_req_pack = 0x4001c134 ); -PROVIDE ( r_lld_init_end = 0x4001aafc ); -PROVIDE ( r_lld_init_evt_canceled_cbk = 0x4001c010 ); -PROVIDE ( r_lld_init_evt_start_cbk = 0x4001bda4 ); -PROVIDE ( r_lld_init_frm_cbk = 0x4001bcc4 ); -PROVIDE ( r_lld_init_frm_eof_isr = 0x4001ba0c ); -PROVIDE ( r_lld_init_frm_skip_isr = 0x4001bb84 ); -PROVIDE ( r_lld_init_init = 0x4001c1c0 ); -PROVIDE ( r_lld_init_process_pkt_rx = 0x4001b51c ); -PROVIDE ( r_lld_init_process_pkt_rx_adv_ext_ind = 0x4001b1b4 ); -PROVIDE ( r_lld_init_process_pkt_rx_adv_ind_or_direct_ind = 0x4001aff4 ); -PROVIDE ( r_lld_init_process_pkt_rx_aux_connect_rsp = 0x4001b33c ); -PROVIDE ( r_lld_init_process_pkt_tx = 0x4001b7b0 ); -PROVIDE ( r_lld_init_process_pkt_tx_cal_con_timestamp = 0x4001b6e4 ); -PROVIDE ( r_lld_init_sched = 0x4001ac68 ); -PROVIDE ( r_lld_init_set_tx_power = 0x4001aab4 ); -PROVIDE ( r_lld_init_start = 0x4001c270 ); -PROVIDE ( r_lld_init_stop = 0x4001d0d0 ); -PROVIDE ( r_lld_instant_proc_end = 0x400174f8 ); -PROVIDE ( r_lld_llcp_rx_ind_handler = 0x4000f6d0 ); -PROVIDE ( r_lld_per_adv_chain_construct = 0x4001f50c ); -PROVIDE ( r_lld_per_adv_ch_map_update = 0x40020b48 ); -PROVIDE ( r_lld_per_adv_cleanup = 0x4001ef68 ); -PROVIDE ( r_lld_per_adv_coex_env_reset = 0x4001eb9c ); -PROVIDE ( r_lld_per_adv_data_set = 0x4001f730 ); -PROVIDE ( r_lld_per_adv_data_update = 0x40020a2c ); -PROVIDE ( r_lld_per_adv_dynamic_pti_process = 0x4001ebd4 ); -PROVIDE ( r_lld_per_adv_evt_canceled_cbk = 0x4001fbf4 ); -PROVIDE ( r_lld_per_adv_evt_start_cbk = 0x4001f7b4 ); -PROVIDE ( r_lld_per_adv_ext_pkt_prepare = 0x4001f0a0 ); -PROVIDE ( r_lld_per_adv_frm_cbk = 0x40020094 ); -PROVIDE ( r_lld_per_adv_frm_isr = 0x4001fca0 ); -PROVIDE ( r_lld_per_adv_frm_skip_isr = 0x4001ff88 ); -PROVIDE ( r_lld_per_adv_init = 0x400200e4 ); -PROVIDE ( r_lld_per_adv_init_info_get = 0x40020ae8 ); -PROVIDE ( r_lld_per_adv_list_add = 0x4001db28 ); -PROVIDE ( r_lld_per_adv_list_rem = 0x4001dc8c ); -PROVIDE ( r_lld_per_adv_sched = 0x4001eff0 ); -PROVIDE ( r_lld_per_adv_set_tx_power = 0x4001ef8c ); -PROVIDE ( r_lld_per_adv_start = 0x40020164 ); -PROVIDE ( r_lld_per_adv_stop = 0x4002096c ); -PROVIDE ( r_lld_per_adv_sync_info_get = 0x40020a94 ); -PROVIDE ( r_lld_process_cca_data = 0x4001ea5c ); -PROVIDE ( r_lld_ral_search = 0x4001d160 ); -PROVIDE ( r_lld_read_clock = 0x4001d81c ); -PROVIDE ( r_lld_reg_rd = 0x4001e188 ); -PROVIDE ( r_lld_reg_wr = 0x4001e1a0 ); -PROVIDE ( r_lld_reset_reg = 0x4001d7b0 ); -PROVIDE ( r_lld_res_list_add = 0x4001ddc8 ); -PROVIDE ( r_lld_res_list_clear = 0x4001dd70 ); -PROVIDE ( r_lld_res_list_is_empty = 0x4001e154 ); -PROVIDE ( r_lld_res_list_local_rpa_get = 0x4001e0ec ); -PROVIDE ( r_lld_res_list_peer_rpa_get = 0x4001e084 ); -PROVIDE ( r_lld_res_list_peer_update = 0x4001e014 ); -PROVIDE ( r_lld_res_list_priv_mode_update = 0x4001df9c ); -PROVIDE ( r_lld_res_list_rem = 0x4001df40 ); -PROVIDE ( r_lld_rpa_renew = 0x4001d844 ); -PROVIDE ( r_lld_rpa_renew_evt_canceled_cbk = 0x4001d370 ); -PROVIDE ( r_lld_rpa_renew_evt_start_cbk = 0x4001d2ec ); -PROVIDE ( r_lld_rpa_renew_instant_cbk = 0x4001d1e4 ); -PROVIDE ( r_lld_rxdesc_check = 0x4001d5ac ); -PROVIDE ( r_lld_rxdesc_free = 0x4001d3c4 ); -PROVIDE ( r_lld_scan_create_sync = 0x40024240 ); -PROVIDE ( r_lld_scan_create_sync_cancel = 0x400242ac ); -PROVIDE ( r_lld_scan_end = 0x40020f40 ); -PROVIDE ( r_lld_scan_evt_canceled_cbk = 0x400231d8 ); -PROVIDE ( r_lld_scan_evt_start_cbk = 0x40022fa0 ); -PROVIDE ( r_lld_scan_frm_cbk = 0x40022f20 ); -PROVIDE ( r_lld_scan_frm_eof_isr = 0x40022b80 ); -PROVIDE ( r_lld_scan_frm_rx_isr = 0x40022d24 ); -PROVIDE ( r_lld_scan_frm_skip_isr = 0x40022dc4 ); -PROVIDE ( r_lld_scan_init = 0x40023314 ); -PROVIDE ( r_lld_scan_params_update = 0x400241ec ); -PROVIDE ( r_lld_scan_process_pkt_rx = 0x40021fec ); -PROVIDE ( r_lld_scan_process_pkt_rx_adv_rep = 0x400211e8 ); -PROVIDE ( r_lld_scan_process_pkt_rx_aux_adv_ind = 0x40021684 ); -PROVIDE ( r_lld_scan_process_pkt_rx_aux_chain_ind = 0x40021cf8 ); -PROVIDE ( r_lld_scan_process_pkt_rx_aux_scan_rsp = 0x40021b64 ); -PROVIDE ( r_lld_scan_process_pkt_rx_ext_adv = 0x40021eac ); -PROVIDE ( r_lld_scan_process_pkt_rx_ext_adv_ind = 0x40021414 ); -PROVIDE ( r_lld_scan_process_pkt_rx_legacy_adv = 0x400210b4 ); -PROVIDE ( r_lld_scan_restart = 0x4002337c ); -PROVIDE ( r_lld_scan_sched = 0x40022544 ); -PROVIDE ( r_lld_scan_set_tx_power = 0x40020edc ); -PROVIDE ( r_lld_scan_start = 0x4002349c ); -PROVIDE ( r_lld_scan_stop = 0x40024160 ); -PROVIDE ( r_lld_scan_sync_accept = 0x4002232c ); -PROVIDE ( r_lld_scan_sync_info_unpack = 0x40022230 ); -PROVIDE ( r_lld_scan_trunc_ind = 0x400221dc ); -PROVIDE ( r_lld_sw_cca_evt_handler = 0x4001eaf8 ); -PROVIDE ( r_lld_sw_cca_isr = 0x4001eb18 ); -PROVIDE ( r_lld_sync_ch_map_update = 0x40025e84 ); -PROVIDE ( r_lld_sync_cleanup = 0x40024520 ); -PROVIDE ( r_lld_sync_evt_canceled_cbk = 0x4002568c ); -PROVIDE ( r_lld_sync_evt_start_cbk = 0x400254e0 ); -PROVIDE ( r_lld_sync_frm_cbk = 0x4002545c ); -PROVIDE ( r_lld_sync_frm_eof_isr = 0x400251a8 ); -PROVIDE ( r_lld_sync_frm_rx_isr = 0x400252fc ); -PROVIDE ( r_lld_sync_frm_skip_isr = 0x4002538c ); -PROVIDE ( r_lld_sync_init = 0x40025754 ); -PROVIDE ( r_lld_sync_process_pkt_rx = 0x40024ad0 ); -PROVIDE ( r_lld_sync_process_pkt_rx_aux_sync_ind = 0x400245d4 ); -PROVIDE ( r_lld_sync_process_pkt_rx_pkt_check = 0x40024720 ); -PROVIDE ( r_lld_sync_scan_dynamic_pti_process = 0x40024304 ); -PROVIDE ( r_lld_sync_sched = 0x40024bd8 ); -PROVIDE ( r_lld_sync_start = 0x400257bc ); -PROVIDE ( r_lld_sync_stop = 0x40025ec4 ); -PROVIDE ( r_lld_sync_trunc_ind = 0x40024574 ); -PROVIDE ( r_lld_test_cleanup = 0x40025fdc ); -PROVIDE ( r_lld_test_evt_canceled_cbk = 0x400261a8 ); -PROVIDE ( r_lld_test_evt_start_cbk = 0x40026060 ); -PROVIDE ( r_lld_test_freq2chnl = 0x4002601c ); -PROVIDE ( r_lld_test_frm_cbk = 0x40026344 ); -PROVIDE ( r_lld_test_frm_isr = 0x40026268 ); -PROVIDE ( r_lld_test_init = 0x40026aec ); -PROVIDE ( r_lld_test_rx_isr = 0x40026228 ); -PROVIDE ( r_lld_test_set_tx_power = 0x40025f78 ); -PROVIDE ( r_lld_test_start = 0x400263b4 ); -PROVIDE ( r_lld_test_stop = 0x40026a1c ); -PROVIDE ( r_lld_update_rxbuf = 0x4001e4ac ); -PROVIDE ( r_lld_update_rxbuf_isr = 0x4001e638 ); -PROVIDE ( r_lld_white_list_add = 0x4001d8e0 ); -PROVIDE ( r_lld_white_list_rem = 0x4001da40 ); -PROVIDE ( r_llm_activity_free_get = 0x4002bb5c ); -PROVIDE ( r_llm_activity_free_set = 0x4002bc20 ); -PROVIDE ( r_llm_activity_syncing_get = 0x4002bc60 ); -PROVIDE ( r_llm_adv_con_len_check = 0x40026cd8 ); -PROVIDE ( r_llm_adv_hdl_to_id = 0x40026ebc ); -PROVIDE ( r_llm_adv_rep_flow_control_check = 0x4002cf3c ); -PROVIDE ( r_llm_adv_rep_flow_control_update = 0x4002cf78 ); -PROVIDE ( r_llm_adv_reports_list_check = 0x4002cdf0 ); -PROVIDE ( r_llm_adv_set_all_release = 0x4002975c ); -PROVIDE ( r_llm_adv_set_dft_params = 0x40026dc8 ); -PROVIDE ( r_llm_adv_set_release = 0x40026b18 ); -PROVIDE ( r_llm_aes_res_cb = 0x4002a870 ); -PROVIDE ( r_llm_ble_update_adv_flow_control = 0x4002cdd8 ); -PROVIDE ( r_llm_ch_map_update = 0x4002b9c4 ); -PROVIDE ( r_llm_cmd_cmp_send = 0x4002b674 ); -PROVIDE ( r_llm_cmd_stat_send = 0x4002b6bc ); -PROVIDE ( r_llm_dev_list_empty_entry = 0x4002b7f8 ); -PROVIDE ( r_llm_dev_list_search = 0x4002b81c ); -PROVIDE ( r_llm_env_adv_dup_filt_deinit = 0x4002dd90 ); -PROVIDE ( r_llm_env_adv_dup_filt_init = 0x4002dd38 ); -PROVIDE ( r_llm_hci_cmd_handler_tab_p_get = 0x4002a8a8 ); -PROVIDE ( r_llm_hci_command_handler = 0x4002a8b0 ); -PROVIDE ( r_llm_init_ble_adv_report_flow_contol = 0x4002cda4 ); -PROVIDE ( r_llm_is_dev_connected = 0x4002b6e8 ); -PROVIDE ( r_llm_is_dev_synced = 0x4002b76c ); -PROVIDE ( r_llm_is_non_con_act_ongoing_check = 0x4002a7d4 ); -PROVIDE ( r_llm_is_wl_accessible = 0x4002a76c ); -PROVIDE ( r_llm_le_evt_mask_check = 0x4002b958 ); -PROVIDE ( r_llm_le_features_get = 0x4002b980 ); -PROVIDE ( r_llm_link_disc = 0x4002b868 ); -PROVIDE ( r_llm_master_ch_map_get = 0x4002b948 ); -PROVIDE ( r_llm_msg_handler_tab_p_get = 0x4002df30 ); -PROVIDE ( r_llm_no_activity = 0x4002a820 ); -PROVIDE ( r_llm_per_adv_slot_dur = 0x40026d3c ); -PROVIDE ( r_llm_plan_elt_get = 0x4002b9a8 ); -PROVIDE ( r_llm_rx_path_comp_get = 0x4002b998 ); -PROVIDE ( r_llm_scan_start = 0x4002bca0 ); -PROVIDE ( r_llm_scan_sync_acad_attach = 0x4002dcb0 ); -PROVIDE ( r_llm_scan_sync_acad_detach = 0x4002dcf8 ); -PROVIDE ( r_llm_send_adv_lost_event_to_host = 0x4002cd54 ); -PROVIDE ( r_llm_tx_path_comp_get = 0x4002b988 ); -PROVIDE ( r_misc_deinit = 0x4002df94 ); -PROVIDE ( r_misc_free_em_buf_in_isr = 0x4002dfa8 ); -PROVIDE ( r_misc_init = 0x4002df78 ); -PROVIDE ( r_misc_msg_handler_tab_p_get = 0x4002df6c ); -PROVIDE ( r_modules_funcs_p = 0x3fcef66c ); -PROVIDE ( r_MultiplyBigHexByUint32_256 = 0x400047fc ); -PROVIDE ( r_MultiplyBigHexModP256 = 0x40004698 ); -PROVIDE ( r_MultiplyByU16ModP256 = 0x40004948 ); -PROVIDE ( r_notEqual256 = 0x400049a4 ); -PROVIDE ( r_nvds_browse_tag = 0x4002e088 ); -PROVIDE ( r_nvds_del = 0x4002e314 ); -PROVIDE ( r_nvds_erase = 0x4002e164 ); -PROVIDE ( r_nvds_get = 0x4002e2c4 ); -PROVIDE ( r_nvds_init = 0x4002e240 ); -PROVIDE ( r_nvds_init_memory = 0x4002e184 ); -PROVIDE ( r_nvds_is_magic_number_ok = 0x4002e010 ); -PROVIDE ( r_nvds_lock = 0x4002e35c ); -PROVIDE ( r_nvds_null_init = 0x4002e0cc ); -PROVIDE ( r_nvds_purge = 0x4002e1a8 ); -PROVIDE ( r_nvds_put = 0x4002e3a4 ); -PROVIDE ( r_nvds_read = 0x4002e0f4 ); -PROVIDE ( r_nvds_walk_tag = 0x4002e040 ); -PROVIDE ( r_nvds_write = 0x4002e12c ); -PROVIDE ( _rodata_end = 0x3ff0fff0 ); -PROVIDE ( rodata_reserved_end = 0x3fcefca0 ); -PROVIDE ( rodata_reserved_start = 0x3fcefc9c ); -PROVIDE ( _rodata_start = 0x3ff071c0 ); -PROVIDE ( rom_abs_temp = 0x40041394 ); -PROVIDE ( rom_agc_reg_init = 0x4003de00 ); -PROVIDE ( rom_ant_btrx_cfg = 0x4003e44c ); -PROVIDE ( rom_ant_bttx_cfg = 0x4003e410 ); -PROVIDE ( rom_ant_dft_cfg = 0x4003e320 ); -PROVIDE ( rom_ant_wifirx_cfg = 0x4003e388 ); -PROVIDE ( rom_ant_wifitx_cfg = 0x4003e348 ); -PROVIDE ( rom_bb_bss_cbw40 = 0x4003ea3c ); -PROVIDE ( rom_bb_bss_cbw40_ana = 0x4003f91c ); -PROVIDE ( rom_bb_bss_cbw40_dig = 0x4003d564 ); -PROVIDE ( rom_bb_reg_init = 0x4003e07c ); -PROVIDE ( rom_bb_wdg_cfg = 0x4003e174 ); -PROVIDE ( rom_bb_wdg_test_en = 0x4003d528 ); -PROVIDE ( rom_bb_wdt_get_status = 0x4003d9d8 ); -PROVIDE ( rom_bb_wdt_int_enable = 0x4003d994 ); -PROVIDE ( rom_bb_wdt_rst_enable = 0x4003d974 ); -PROVIDE ( rom_bb_wdt_timeout_clear = 0x4003d9bc ); -PROVIDE ( rom_bt_bb_to_index = 0x4003ce5c ); -PROVIDE ( rom_bt_correct_rf_ana_gain = 0x40042874 ); -PROVIDE ( rom_bt_index_to_bb = 0x4003ce40 ); -PROVIDE ( rom_cbw2040_cfg = 0x4003e9d4 ); -PROVIDE ( rom_chan_to_freq = 0x4003f9d4 ); -PROVIDE ( rom_check_noise_floor = 0x4003d62c ); -PROVIDE ( rom_chip_i2c_readReg = 0x4003ee28 ); -PROVIDE ( rom_chip_i2c_writeReg = 0x4003eea0 ); -PROVIDE ( rom_chip_wait_idle_interval = 0x3fcefc04 ); -PROVIDE ( rom_code_to_temp = 0x40040648 ); -PROVIDE ( rom_config_data_cache_mode = 0x4004f188 ); -PROVIDE ( rom_config_instruction_cache_mode = 0x4004f138 ); -PROVIDE ( rom_correct_rf_ana_gain = 0x40042758 ); -PROVIDE ( rom_correct_rfpll_offset = 0x4003fd3c ); -PROVIDE ( rom_dac_rate_set = 0x4003fc44 ); -PROVIDE ( rom_dc_iq_est = 0x40041470 ); -PROVIDE ( rom_disable_agc = 0x4003c8c4 ); -PROVIDE ( rom_disable_wifi_agc = 0x4003c944 ); -PROVIDE ( rom_enable_agc = 0x4003c8ec ); -PROVIDE ( rom_enable_cache_flash_wrap = 0x4004f0c0 ); -PROVIDE ( rom_enable_cache_spiram_wrap = 0x4004f0fc ); -PROVIDE ( rom_enable_wifi_agc = 0x4003c98c ); -PROVIDE ( rom_en_pwdet = 0x40040eac ); -PROVIDE ( rom_esp_flash_default_chip = 0x3fcefc14 ); -PROVIDE ( rom_fe_reg_init = 0x4003dc84 ); -PROVIDE ( rom_fe_txrx_reset = 0x4003e1a8 ); -PROVIDE ( rom_flash_chip_dummy = 0x3fcefc0c ); -PROVIDE ( rom_force_txon = 0x4003ebbc ); -PROVIDE ( rom_freq_get_i2c_data = 0x40040778 ); -PROVIDE ( rom_freq_i2c_write_set = 0x4003fe9c ); -PROVIDE ( rom_gen_rx_gain_table = 0x4003e7a8 ); -PROVIDE ( rom_get_bbgain_db = 0x4003ce78 ); -PROVIDE ( rom_get_bias_ref_code = 0x4004297c ); -PROVIDE ( rom_get_data_sat = 0x4003cb08 ); -PROVIDE ( rom_get_fm_sar_dout = 0x400410fc ); -PROVIDE ( rom_get_i2c_read_mask = 0x4003ee04 ); -PROVIDE ( rom_get_phy_target_power = 0x40042c20 ); -PROVIDE ( rom_get_pll_ref_code = 0x40040914 ); -PROVIDE ( rom_get_pll_vol = 0x40042adc ); -PROVIDE ( rom_get_power_atten = 0x40041f0c ); -PROVIDE ( rom_get_power_db = 0x40042044 ); -PROVIDE ( rom_get_pwctrl_correct = 0x40042ba8 ); -PROVIDE ( rom_get_rate_fcc_index = 0x400425fc ); -PROVIDE ( rom_get_rate_target_power = 0x4004267c ); -PROVIDE ( rom_get_rc_dout = 0x40041c50 ); -PROVIDE ( rom_get_rfcal_rxiq_data = 0x40041b64 ); -PROVIDE ( rom_get_rf_gain_qdb = 0x40042740 ); -PROVIDE ( rom_get_sar2_vol = 0x40042a08 ); -PROVIDE ( rom_get_sar_sig_ref = 0x40040fc4 ); -PROVIDE ( rom_get_target_power_offset = 0x40042498 ); -PROVIDE ( rom_get_tone_sar_dout = 0x40041088 ); -PROVIDE ( rom_host_delay_interval = 0x3fcefc08 ); -PROVIDE ( rom_i2c_bbtop_init = 0x4003f774 ); -PROVIDE ( rom_i2c_clk_sel = 0x4003ecd4 ); -PROVIDE ( rom_i2cmst_reg_init = 0x4003daf8 ); -PROVIDE ( rom_i2c_readReg = 0x4003ee84 ); -PROVIDE ( rom_i2c_readReg_Mask = 0x4003ef04 ); -PROVIDE ( rom_i2c_sar2_init_code = 0x4003fbe8 ); -PROVIDE ( rom_i2c_writeReg = 0x4003eee8 ); -PROVIDE ( rom_i2c_writeReg_Mask = 0x4003ef40 ); -PROVIDE ( rom_index_to_txbbgain = 0x40040b10 ); -PROVIDE ( rom_iq_corr_enable = 0x4003dc10 ); -PROVIDE ( rom_iq_est_disable = 0x40041434 ); -PROVIDE ( rom_iq_est_enable = 0x400413b4 ); -PROVIDE ( rom_linear_to_db = 0x40041fd8 ); -PROVIDE ( rom_loopback_mode_en = 0x4003cad4 ); -PROVIDE ( rom_mac_enable_bb = 0x4003e134 ); -PROVIDE ( rom_mac_tx_chan_offset = 0x4003e9fc ); -PROVIDE ( rom_meas_tone_pwr_db = 0x40042080 ); -PROVIDE ( rom_mhz2ieee = 0x4003e990 ); -PROVIDE ( rom_noise_floor_auto_set = 0x4003d594 ); -PROVIDE ( rom_open_i2c_xpd = 0x4003fc1c ); -PROVIDE ( rom_pbus_debugmode = 0x4003f1b4 ); -PROVIDE ( rom_pbus_force_mode = 0x4003efb0 ); -PROVIDE ( rom_pbus_force_test = 0x4003f114 ); -PROVIDE ( rom_pbus_rd = 0x4003f170 ); -PROVIDE ( rom_pbus_rd_addr = 0x4003f078 ); -PROVIDE ( rom_pbus_rd_shift = 0x4003f0c4 ); -PROVIDE ( rom_pbus_rx_dco_cal = 0x400414f8 ); -PROVIDE ( rom_pbus_set_dco = 0x4003f370 ); -PROVIDE ( rom_pbus_set_rxgain = 0x4003f1dc ); -PROVIDE ( rom_pbus_workmode = 0x4003f1c8 ); -PROVIDE ( rom_pbus_xpd_rx_off = 0x4003f240 ); -PROVIDE ( rom_pbus_xpd_rx_on = 0x4003f274 ); -PROVIDE ( rom_pbus_xpd_tx_off = 0x4003f2c8 ); -PROVIDE ( rom_pbus_xpd_tx_on = 0x4003f318 ); -PROVIDE ( rom_phy_ant_init = 0x4003e2d4 ); -PROVIDE ( rom_phy_byte_to_word = 0x4003da20 ); -PROVIDE ( rom_phy_chan_dump_cfg = 0x4003e548 ); -PROVIDE ( rom_phy_chan_filt_set = 0x4003eb28 ); -PROVIDE ( rom_phy_close_pa = 0x4003ed54 ); -PROVIDE ( rom_phy_disable_cca = 0x4003c9dc ); -PROVIDE ( rom_phy_disable_low_rate = 0x4003e760 ); -PROVIDE ( rom_phy_dis_hw_set_freq = 0x400408d8 ); -PROVIDE ( rom_phy_enable_cca = 0x4003ca08 ); -PROVIDE ( rom_phy_enable_low_rate = 0x4003e728 ); -PROVIDE ( rom_phy_freq_correct = 0x4003f5dc ); -PROVIDE ( rom_phy_get_fetx_delay = 0x4003fa08 ); -PROVIDE ( rom_phy_get_noisefloor = 0x4003d5e4 ); -PROVIDE ( rom_phy_get_rx_freq = 0x4003ec10 ); -PROVIDE ( rom_phy_get_tx_rate = 0x4003da10 ); -PROVIDE ( rom_phy_get_vdd33 = 0x400428f4 ); -PROVIDE ( rom_phy_i2c_init = 0x4003fac8 ); -PROVIDE ( rom_phy_pwdet_always_en = 0x40042c90 ); -PROVIDE ( rom_phy_pwdet_onetime_en = 0x40042ccc ); -PROVIDE ( rom_phy_rx11blr_cfg = 0x4003d91c ); -PROVIDE ( rom_phy_rx_sense_set = 0x4003ec58 ); -PROVIDE ( rom_phy_set_bbfreq_init = 0x40042b30 ); -PROVIDE ( rom_pll_correct_dcap = 0x400406ec ); -PROVIDE ( rom_pll_vol_cal = 0x40040948 ); -PROVIDE ( rom_pocket_sar_power = 0x40042b60 ); -PROVIDE ( rom_pow_usr = 0x4003ca20 ); -PROVIDE ( rom_pwdet_force_start = 0x40040ff0 ); -PROVIDE ( rom_pwdet_sar2_init = 0x40040e08 ); -PROVIDE ( rom_read_hw_noisefloor = 0x4003d6d0 ); -PROVIDE ( rom_read_sar2_code = 0x400429e8 ); -PROVIDE ( rom_read_sar_dout = 0x40040fb4 ); -PROVIDE ( rom_restart_cal = 0x4003f3c0 ); -PROVIDE ( rom_rfcal_pwrctrl = 0x400422b4 ); -PROVIDE ( rom_rfcal_rxiq = 0x40041af0 ); -PROVIDE ( rom_rfcal_txcap = 0x40041dfc ); -PROVIDE ( rom_rfpll_init = 0x4003f3b8 ); -PROVIDE ( rom_rfpll_set_freq = 0x4003f4cc ); -PROVIDE ( rom_rftx_init = 0x4003fa28 ); -PROVIDE ( rom_rtc_sar2_init = 0x40040d48 ); -PROVIDE ( rom_rxdc_est_min = 0x40041820 ); -PROVIDE ( rom_rx_gain_force = 0x4003d038 ); -PROVIDE ( rom_rxiq_cover_mg_mp = 0x40041a0c ); -PROVIDE ( rom_rxiq_get_mis = 0x40041874 ); -PROVIDE ( rom_rxiq_set_reg = 0x40041988 ); -PROVIDE ( rom_set_adc_rand = 0x4003e5dc ); -PROVIDE ( rom_set_cal_rxdc = 0x4003ca94 ); -PROVIDE ( rom_set_cca = 0x4003eac4 ); -PROVIDE ( rom_set_chan_cal_interp = 0x40041d20 ); -PROVIDE ( rom_set_channel_freq = 0x4003f534 ); -PROVIDE ( rom_set_loopback_gain = 0x4003ca38 ); -PROVIDE ( rom_set_noise_floor = 0x4003d6e8 ); -PROVIDE ( rom_set_pbus_mem = 0x4003cb78 ); -PROVIDE ( rom_set_pbus_reg = 0x4003e25c ); -PROVIDE ( rom_set_rf_freq_offset = 0x4003f73c ); -PROVIDE ( rom_set_rfpll_freq = 0x4003fce8 ); -PROVIDE ( rom_set_rxclk_en = 0x4003d0ac ); -PROVIDE ( rom_set_rx_comp = 0x4003e1d4 ); -PROVIDE ( rom_set_rx_sense = 0x4003d75c ); -PROVIDE ( rom_set_txcap_reg = 0x40041d74 ); -PROVIDE ( rom_set_txclk_en = 0x4003d07c ); -PROVIDE ( rom_set_tx_dig_gain = 0x4003cff4 ); -PROVIDE ( rom_set_tx_gain_table = 0x4003cd94 ); -PROVIDE ( rom_set_xpd_sar = 0x4003e290 ); -PROVIDE ( rom_spiflash_api_funcs = 0x3fcefbf4 ); -PROVIDE ( rom_spi_flash_cache2phys = 0x400505cc ); -PROVIDE ( rom_spi_flash_cache_enabled = 0x4004f08c ); -PROVIDE ( rom_spi_flash_check_and_flush_cache = 0x4005070c ); -PROVIDE ( rom_spi_flash_disable_cache = 0x4004f054 ); -PROVIDE ( rom_spi_flash_dump_counters = 0x40050850 ); -PROVIDE ( rom_spi_flash_enable_cache = 0x4004f0ac ); -PROVIDE ( rom_spi_flash_erase_range = 0x40050974 ); -PROVIDE ( rom_spi_flash_erase_sector = 0x40050a7c ); -PROVIDE ( rom_spi_flash_get_chip_size = 0x4005087c ); -PROVIDE ( rom_spi_flash_get_counters = 0x40050820 ); -PROVIDE ( rom_spi_flash_guard_get = 0x400508bc ); -PROVIDE ( rom_spi_flash_guard_set = 0x400508b0 ); -PROVIDE ( rom_spi_flash_hal_max_read_len = 0x3fcefba8 ); -PROVIDE ( rom_spi_flash_mmap = 0x400503b0 ); -PROVIDE ( rom_spi_flash_mmap_dump = 0x400504f4 ); -PROVIDE ( rom_spi_flash_mmap_get_free_pages = 0x40050550 ); -PROVIDE ( rom_spi_flash_mmap_os_func_set = 0x4005016c ); -PROVIDE ( rom_spi_flash_mmap_page_num_init = 0x4005017c ); -PROVIDE ( rom_spi_flash_mmap_pages = 0x400501cc ); -PROVIDE ( rom_spi_flash_munmap = 0x40050444 ); -PROVIDE ( rom_spi_flash_op_counters_config = 0x40050810 ); -PROVIDE ( rom_spi_flash_phys2cache = 0x40050660 ); -PROVIDE ( rom_spi_flash_read = 0x40050c4c ); -PROVIDE ( rom_spi_flash_read_encrypted = 0x40050f00 ); -PROVIDE ( rom_spi_flash_reset_counters = 0x40050828 ); -PROVIDE ( rom_spi_flash_restore_cache = 0x4004f070 ); -PROVIDE ( rom_spi_flash_safe_write_address_func_set = 0x400508c8 ); -PROVIDE ( rom_spi_flash_unlock = 0x400508d8 ); -PROVIDE ( rom_spi_flash_write = 0x40050a90 ); -PROVIDE ( rom_spi_flash_write_config_get = 0x400508a8 ); -PROVIDE ( rom_spi_flash_write_config_set = 0x4005088c ); -PROVIDE ( rom_spi_flash_write_encrypted = 0x40050e7c ); -PROVIDE ( rom_spur_cal = 0x4003e924 ); -PROVIDE ( rom_spur_reg_write_one_tone = 0x4003d2a4 ); -PROVIDE ( rom_start_tx_tone = 0x4003d1d0 ); -PROVIDE ( rom_start_tx_tone_step = 0x4003d0e8 ); -PROVIDE ( rom_stop_tx_tone = 0x4003e8d0 ); -PROVIDE ( _rom_store = 0x400568d0 ); -PROVIDE ( _rom_store_table = 0x40056700 ); -PROVIDE ( rom_target_power_add_backoff = 0x4004271c ); -PROVIDE ( rom_temp_to_power = 0x40042c5c ); -PROVIDE ( rom_test_rx_gain_cal = 0x40042d14 ); -PROVIDE ( rom_tsens_code_read = 0x40040554 ); -PROVIDE ( rom_tsens_dac_cal = 0x400405cc ); -PROVIDE ( rom_tsens_index_to_dac = 0x40040590 ); -PROVIDE ( rom_tsens_index_to_offset = 0x400405ac ); -PROVIDE ( rom_tsens_read_init = 0x40040434 ); -PROVIDE ( rom_txbbgain_to_index = 0x40040ae0 ); -PROVIDE ( rom_txcal_work_mode = 0x40040f14 ); -PROVIDE ( rom_txdc_cal_init = 0x40040b2c ); -PROVIDE ( rom_txdc_cal_v70 = 0x40040bc0 ); -PROVIDE ( rom_txiq_cover = 0x40041218 ); -PROVIDE ( rom_txiq_get_mis_pwr = 0x4004116c ); -PROVIDE ( rom_txiq_set_reg = 0x40040f44 ); -PROVIDE ( rom_tx_paon_set = 0x4003da6c ); -PROVIDE ( rom_tx_pwctrl_bg_init = 0x40042bfc ); -PROVIDE ( rom_tx_pwr_backoff = 0x400420d4 ); -PROVIDE ( rom_tx_state_set = 0x4003e4dc ); -PROVIDE ( rom_txtone_linear_pwr = 0x4004111c ); -PROVIDE ( rom_wait_rfpll_cal_end = 0x4003f488 ); -PROVIDE ( rom_wifi_11g_rate_chg = 0x4004247c ); -PROVIDE ( rom_wifi_rifs_mode_en = 0x4003d9ec ); -PROVIDE ( rom_wr_bt_tx_atten = 0x4003ceb0 ); -PROVIDE ( rom_wr_bt_tx_gain_mem = 0x4003cf48 ); -PROVIDE ( rom_write_dac_gain2 = 0x4003e6b8 ); -PROVIDE ( rom_write_gain_mem = 0x4003cd60 ); -PROVIDE ( rom_write_pll_cap_mem = 0x40040688 ); -PROVIDE ( rom_write_rfpll_sdm = 0x4003f420 ); -PROVIDE ( rom_write_txrate_power_offset = 0x40042510 ); -PROVIDE ( rom_write_wifi_dig_gain = 0x400426b8 ); -PROVIDE ( rom_wr_rf_freq_mem = 0x4003fdd0 ); -PROVIDE ( r_osi_funcs_p = 0x3fcef68c ); -PROVIDE ( roundup2 = 0x40056654 ); -PROVIDE ( r_phy_upd_proc_start = 0x40011220 ); -PROVIDE ( r_platform_reset = 0x400011a4 ); -PROVIDE ( r_plf_funcs_p = 0x3fcef690 ); -PROVIDE ( r_readbyte = 0x400068f4 ); -PROVIDE ( r_rf_em_init = 0x4002e65c ); -PROVIDE ( r_rf_force_agc_enable = 0x4002e714 ); -PROVIDE ( r_rf_reg_rd = 0x4002e648 ); -PROVIDE ( r_rf_reg_wr = 0x4002e650 ); -PROVIDE ( r_rf_reset = 0x4002e70c ); -PROVIDE ( r_rf_rssi_convert = 0x4002e69c ); -PROVIDE ( r_rf_rw_v9_le_disable = 0x40001ac8 ); -PROVIDE ( r_rf_rw_v9_le_enable = 0x40001ab0 ); -PROVIDE ( r_rf_sleep = 0x4002e730 ); -PROVIDE ( r_rf_txpwr_cs_get = 0x4002e6a8 ); -PROVIDE ( r_rf_txpwr_dbm_get = 0x4002e71c ); -PROVIDE ( r_rf_util_cs_fmt_convert = 0x4002eb88 ); -PROVIDE ( r_rwble_isr = 0x4002ec44 ); -PROVIDE ( r_rwble_sleep_enter = 0x4002f014 ); -PROVIDE ( r_rwble_sleep_wakeup_end = 0x4002f058 ); -PROVIDE ( r_rwbtdm_isr_wrapper = 0x4000949c ); -PROVIDE ( r_rw_crypto_aes_ccm = 0x400008c8 ); -PROVIDE ( r_rw_crypto_aes_encrypt = 0x40000ecc ); -PROVIDE ( r_rw_crypto_aes_init = 0x40000e34 ); -PROVIDE ( r_rw_crypto_aes_k1 = 0x40000b68 ); -PROVIDE ( r_rw_crypto_aes_k2 = 0x40000cc0 ); -PROVIDE ( r_rw_crypto_aes_k3 = 0x40000d68 ); -PROVIDE ( r_rw_crypto_aes_k4 = 0x40000dfc ); -PROVIDE ( r_rw_crypto_aes_rand = 0x40000f3c ); -PROVIDE ( r_rw_crypto_aes_result_handler = 0x40000f70 ); -PROVIDE ( r_rw_crypto_aes_s1 = 0x40001030 ); -PROVIDE ( r_rw_cryto_aes_cmac = 0x40000948 ); -PROVIDE ( r_rwip_active_check = 0x4002f90c ); -PROVIDE ( r_rwip_aes_encrypt = 0x4002faf8 ); -PROVIDE ( r_rwip_assert = 0x40030080 ); -PROVIDE ( r_rwip_crypt_evt_handler = 0x4002f1d8 ); -PROVIDE ( r_rwip_crypt_isr_handler = 0x4002f214 ); -PROVIDE ( r_rwip_eif_get = 0x400011f4 ); -PROVIDE ( r_rwip_half_slot_2_lpcycles = 0x4002f114 ); -PROVIDE ( r_rwip_hus_2_lpcycles = 0x4002f0dc ); -PROVIDE ( r_rwip_isr = 0x4002fc4c ); -PROVIDE ( r_rwip_lpcycles_2_hus = 0x4002f084 ); -PROVIDE ( r_rwip_prevent_sleep_clear = 0x4002f8e0 ); -PROVIDE ( r_rwip_prevent_sleep_set = 0x4002f8b8 ); -PROVIDE ( r_rwip_schedule = 0x4002ffd4 ); -PROVIDE ( r_rwip_sleep = 0x4002f520 ); -PROVIDE ( r_rwip_sw_int_handler = 0x4002f244 ); -PROVIDE ( r_rwip_sw_int_req = 0x4002fc08 ); -PROVIDE ( r_rwip_time_get = 0x4002f4c0 ); -PROVIDE ( r_rwip_timer_10ms_handler = 0x4002f1ac ); -PROVIDE ( r_rwip_timer_10ms_set = 0x4002f924 ); -PROVIDE ( r_rwip_timer_hs_handler = 0x4002f150 ); -PROVIDE ( r_rwip_timer_hs_set = 0x4002f9b0 ); -PROVIDE ( r_rwip_timer_hus_handler = 0x4002f17c ); -PROVIDE ( r_rwip_timer_hus_set = 0x4002fa30 ); -PROVIDE ( r_rwip_wakeup = 0x4002f288 ); -PROVIDE ( r_rwip_wakeup_end = 0x4002f3a0 ); -PROVIDE ( r_rwip_wlcoex_set = 0x4002fffc ); -PROVIDE ( r_rw_v9_init_em_radio_table = 0x40001900 ); -PROVIDE ( r_sch_alarm_clear = 0x40030234 ); -PROVIDE ( r_sch_alarm_init = 0x40030100 ); -PROVIDE ( r_sch_alarm_prog = 0x400300a4 ); -PROVIDE ( r_sch_alarm_set = 0x40030190 ); -PROVIDE ( r_sch_alarm_timer_isr = 0x40030124 ); -PROVIDE ( r_sch_arb_conflict_check = 0x4003028c ); -PROVIDE ( r_sch_arb_elt_cancel = 0x4003039c ); -PROVIDE ( r_sch_arb_event_start_isr = 0x40030a50 ); -PROVIDE ( r_sch_arb_init = 0x40030604 ); -PROVIDE ( r_sch_arb_insert = 0x40030640 ); -PROVIDE ( r_sch_arb_prog_timer = 0x4003052c ); -PROVIDE ( r_sch_arb_remove = 0x40030970 ); -PROVIDE ( r_sch_arb_sw_isr = 0x40030bd0 ); -PROVIDE ( r_sch_plan_chk = 0x400310c8 ); -PROVIDE ( r_sch_plan_clock_wrap_offset_update = 0x40030c98 ); -PROVIDE ( r_sch_plan_init = 0x40030fbc ); -PROVIDE ( r_sch_plan_interval_req = 0x40030f40 ); -PROVIDE ( r_sch_plan_offset_max_calc = 0x40030ccc ); -PROVIDE ( r_sch_plan_offset_req = 0x40030d68 ); -PROVIDE ( r_sch_plan_position_range_compute = 0x400310e8 ); -PROVIDE ( r_sch_plan_rem = 0x4003106c ); -PROVIDE ( r_sch_plan_req = 0x40031080 ); -PROVIDE ( r_sch_plan_set = 0x40030fe4 ); -PROVIDE ( r_sch_prog_end_isr = 0x4003159c ); -PROVIDE ( r_sch_prog_init = 0x400311f4 ); -PROVIDE ( r_sch_prog_push = 0x40031770 ); -PROVIDE ( r_sch_prog_rx_isr = 0x40031288 ); -PROVIDE ( r_sch_prog_skip_isr = 0x40031434 ); -PROVIDE ( r_sch_prog_tx_isr = 0x4003135c ); -PROVIDE ( r_sch_slice_bg_add = 0x40031cf4 ); -PROVIDE ( r_sch_slice_bg_remove = 0x40031d1c ); -PROVIDE ( r_sch_slice_compute = 0x40031bec ); -PROVIDE ( r_sch_slice_fg_add = 0x40031d48 ); -PROVIDE ( r_sch_slice_fg_remove = 0x40031d90 ); -PROVIDE ( r_sch_slice_init = 0x40031ca8 ); -PROVIDE ( r_sch_slice_per_add = 0x40031df0 ); -PROVIDE ( r_sch_slice_per_remove = 0x40031e44 ); -PROVIDE ( r_sdk_config_get_bt_sleep_enable = 0x40031ef0 ); -PROVIDE ( r_sdk_config_get_hl_derived_opts = 0x40031e9c ); -PROVIDE ( r_sdk_config_get_opts = 0x40031ebc ); -PROVIDE ( r_sdk_config_get_priv_opts = 0x40031ed8 ); -PROVIDE ( r_sdk_config_set_bt_sleep_enable = 0x40031ee4 ); -PROVIDE ( r_sdk_config_set_hl_derived_opts = 0x40031ea4 ); -PROVIDE ( r_sdk_config_set_opts = 0x40031ec4 ); -PROVIDE ( r_specialModP256 = 0x40004854 ); -PROVIDE ( r_SubtractBigHex256 = 0x40004224 ); -PROVIDE ( r_SubtractBigHexMod256 = 0x400044c4 ); -PROVIDE ( r_SubtractBigHexUint32_256 = 0x40004630 ); -PROVIDE ( r_SubtractFromSelfBigHex256 = 0x40004278 ); -PROVIDE ( r_SubtractFromSelfBigHexSign256 = 0x400043d4 ); -PROVIDE ( rtc_boot_control = 0x40045b90 ); -PROVIDE ( rtc_get_reset_reason = 0x40045abc ); -PROVIDE ( rtc_get_wakeup_cause = 0x40045ae0 ); -PROVIDE ( rtc_select_apb_bridge = 0x40045c24 ); -PROVIDE ( r_unloaded_area_init = 0x40001060 ); -PROVIDE ( r_vhci_flow_off = 0x4003200c ); -PROVIDE ( r_vhci_flow_on = 0x40032034 ); -PROVIDE ( r_vhci_notify_host_send_available = 0x40031fdc ); -PROVIDE ( r_vhci_send_to_host = 0x40032084 ); -PROVIDE ( r_vnd_hci_command_handler = 0x4000304c ); -PROVIDE ( rwble_env = 0x3fcefb20 ); -PROVIDE ( rwip_coex_cfg = 0x3ff091bb ); -PROVIDE ( rwip_env = 0x3fcefb28 ); -PROVIDE ( rwip_param = 0x3fcefb84 ); -PROVIDE ( rwip_priority = 0x3ff091c0 ); -PROVIDE ( rwip_prog_delay = 0x3fcefb44 ); -PROVIDE ( rwip_rf = 0x3fcefb4c ); -PROVIDE ( r_writebyte = 0x400068e4 ); -PROVIDE ( sbrk = 0x4003b964 ); -PROVIDE ( _sbrk_r = 0x400545e4 ); -PROVIDE ( _scanf_float = 0x40054818 ); -PROVIDE ( s_cdcacm_old_rts = 0x3fcef38c ); -PROVIDE ( sch_slice_params = 0x3fcefb94 ); -PROVIDE ( __sclose = 0x40054d90 ); -PROVIDE ( sdk_cfg_priv_opts = 0x3fcef40c ); -PROVIDE ( SelectSpiFunction = 0x4004cd2c ); -PROVIDE ( SelectSpiQIO = 0x4004cbb4 ); -PROVIDE ( SendMsg = 0x40049a44 ); -PROVIDE ( send_packet = 0x40049a00 ); -PROVIDE ( __seofread = 0x40054d1c ); -PROVIDE ( setjmp = 0x4003226c ); -PROVIDE ( setlocale = 0x40034068 ); -PROVIDE ( _setlocale_r = 0x40033ffc ); -PROVIDE ( set_rtc_memory_crc = 0x40045b74 ); -PROVIDE ( SetSpiDrvs = 0x4004cc48 ); -PROVIDE ( __sf_fake_stderr = 0x3ff0c524 ); -PROVIDE ( __sf_fake_stdin = 0x3ff0c564 ); -PROVIDE ( __sf_fake_stdout = 0x3ff0c544 ); -PROVIDE ( __sflush_r = 0x40033dc8 ); -PROVIDE ( __sfmoreglue = 0x40054ab4 ); -PROVIDE ( __sfp = 0x40054bdc ); -PROVIDE ( __sfp_lock_acquire = 0x40054c8c ); -PROVIDE ( __sfp_lock_release = 0x40054c98 ); -PROVIDE ( __sfputs_r = 0x40032d44 ); -PROVIDE ( __sfvwrite_r = 0x40033674 ); -PROVIDE ( sig_matrix = 0x3fcefc13 ); -PROVIDE ( __sinit = 0x40054af4 ); -PROVIDE ( __sinit_lock_acquire = 0x40054ca4 ); -PROVIDE ( __sinit_lock_release = 0x40054cb0 ); -PROVIDE ( __smakebuf_r = 0x40033d28 ); -PROVIDE ( software_reset = 0x40045bec ); -PROVIDE ( software_reset_cpu = 0x40045c04 ); -PROVIDE ( SPI_block_erase = 0x4004d214 ); -PROVIDE ( spi_cache_mode_switch = 0x4004d9f0 ); -PROVIDE ( SPI_chip_erase = 0x4004d188 ); -PROVIDE ( SPIClkConfig = 0x4004e198 ); -PROVIDE ( SPI_Common_Command = 0x4004d2bc ); -PROVIDE ( spi_common_set_dummy_output = 0x4004dcac ); -PROVIDE ( spi_common_set_flash_cs_timing = 0x4004dbf8 ); -PROVIDE ( spi_dummy_len_fix = 0x4004cb30 ); -PROVIDE ( SPI_Encrypt_Write = 0x4004fa5c ); -PROVIDE ( SPI_Encrypt_Write_Dest = 0x4004f908 ); -PROVIDE ( SPIEraseArea = 0x4004e5cc ); -PROVIDE ( SPIEraseBlock = 0x4004e204 ); -PROVIDE ( SPIEraseChip = 0x4004e1e4 ); -PROVIDE ( SPIEraseSector = 0x4004e278 ); -PROVIDE ( spi_flash_attach = 0x4004e100 ); -PROVIDE ( spi_flash_boot_attach = 0x4004e0a0 ); -PROVIDE ( SPI_flashchip_data = 0x3fcefbdc ); -PROVIDE ( spi_flash_chip_gd_get_io_mode = 0x4004f248 ); -PROVIDE ( spi_flash_chip_gd_probe = 0x4004f1d8 ); -PROVIDE ( spi_flash_chip_gd_set_io_mode = 0x4004f20c ); -PROVIDE ( spi_flash_chip_generic_config_host_io_mode = 0x4004f6e0 ); -PROVIDE ( spi_flash_chip_generic_detect_size = 0x4004f368 ); -PROVIDE ( spi_flash_chip_generic_erase_block = 0x4004f454 ); -PROVIDE ( spi_flash_chip_generic_erase_chip = 0x4004f39c ); -PROVIDE ( spi_flash_chip_generic_erase_sector = 0x4004f3f8 ); -PROVIDE ( spi_flash_chip_generic_get_io_mode = 0x4004f7d4 ); -PROVIDE ( spi_flash_chip_generic_get_write_protect = 0x4004f5e0 ); -PROVIDE ( spi_flash_chip_generic_page_program = 0x4004f4b0 ); -PROVIDE ( spi_flash_chip_generic_probe = 0x4004f30c ); -PROVIDE ( spi_flash_chip_generic_read = 0x4004f740 ); -PROVIDE ( spi_flash_chip_generic_reset = 0x4004f314 ); -PROVIDE ( spi_flash_chip_generic_set_io_mode = 0x4004f898 ); -PROVIDE ( spi_flash_chip_generic_set_write_protect = 0x4004f594 ); -PROVIDE ( spi_flash_chip_generic_wait_idle = 0x4004f660 ); -PROVIDE ( spi_flash_chip_generic_write = 0x4004f4e4 ); -PROVIDE ( spi_flash_chip_generic_write_encrypted = 0x4004f58c ); -PROVIDE ( spi_flash_common_read_status_16b_rdsr_rdsr2 = 0x4004f2dc ); -PROVIDE ( spi_flash_common_read_status_8b_rdsr = 0x4004f7f0 ); -PROVIDE ( spi_flash_common_read_status_8b_rdsr2 = 0x4004f7c4 ); -PROVIDE ( spi_flash_common_set_io_mode = 0x4004f828 ); -PROVIDE ( spi_flash_common_write_status_16b_wrsr = 0x4004f294 ); -PROVIDE ( spi_flash_common_write_status_8b_wrsr = 0x4004f800 ); -PROVIDE ( spi_flash_common_write_status_8b_wrsr2 = 0x4004f814 ); -PROVIDE ( SPI_flash_func = 0x3fcefbb0 ); -PROVIDE ( spi_flash_generic_wait_host_idle = 0x4004f61c ); -PROVIDE ( spi_flash_hal_common_command = 0x4004fd8c ); -PROVIDE ( spi_flash_hal_configure_host_io_mode = 0x4004fbac ); -PROVIDE ( spi_flash_hal_device_config = 0x4004fb44 ); -PROVIDE ( spi_flash_hal_erase_block = 0x4004ff94 ); -PROVIDE ( spi_flash_hal_erase_chip = 0x4004ff1c ); -PROVIDE ( spi_flash_hal_erase_sector = 0x4004ff40 ); -PROVIDE ( spi_flash_hal_host_idle = 0x40050088 ); -PROVIDE ( spi_flash_hal_poll_cmd_done = 0x4004fb1c ); -PROVIDE ( spi_flash_hal_program_page = 0x4004ffe0 ); -PROVIDE ( spi_flash_hal_read = 0x4004fe8c ); -PROVIDE ( spi_flash_hal_set_write_protect = 0x40050054 ); -PROVIDE ( spi_flash_set_check_suspend_cb = 0x4004cb1c ); -PROVIDE ( SPI_init = 0x4004dcf0 ); -PROVIDE ( SPILock = 0x4004dfb0 ); -PROVIDE ( SPIMasterReadModeCnfig = 0x4004e110 ); -PROVIDE ( SPIMEM0 = 0x60003000 ); -PROVIDE ( SPIMEM1 = 0x60002000 ); -PROVIDE ( SPI_page_program = 0x4004d584 ); -PROVIDE ( SPIParamCfg = 0x4004e670 ); -PROVIDE ( SPIRead = 0x4004e3cc ); -PROVIDE ( SPI_read_data = 0x4004cea8 ); -PROVIDE ( SPIReadModeCnfig = 0x4004dff8 ); -PROVIDE ( SPI_read_status = 0x4004d054 ); -PROVIDE ( SPI_read_status_high = 0x4004d258 ); -PROVIDE ( SPI_sector_erase = 0x4004d1c0 ); -PROVIDE ( spi_set_dummy_output = 0x4004cb64 ); -PROVIDE ( spi_slave_download = 0x40053df0 ); -PROVIDE ( spi_slave_rom_check_conn = 0x40053a60 ); -PROVIDE ( spi_slave_rom_init = 0x40053ab0 ); -PROVIDE ( spi_slave_rom_init_hw = 0x40053fd8 ); -PROVIDE ( spi_slave_rom_intr_enable = 0x40053fa0 ); -PROVIDE ( spi_slave_rom_rxdma_load = 0x400542a4 ); -PROVIDE ( spi_slave_rom_txdma_load = 0x4005433c ); -PROVIDE ( SPIUnlock = 0x4004df54 ); -PROVIDE ( SPI_user_command_read = 0x4004cf98 ); -PROVIDE ( SPI_Wait_Idle = 0x4004d664 ); -PROVIDE ( SPI_WakeUp = 0x4004d0c4 ); -PROVIDE ( SPIWrite = 0x4004e2ec ); -PROVIDE ( SPI_write_enable = 0x4004d530 ); -PROVIDE ( SPI_Write_Encrypt_Disable = 0x4004f8d0 ); -PROVIDE ( SPI_Write_Encrypt_Enable = 0x4004f8b4 ); -PROVIDE ( SPI_write_status = 0x4004d278 ); -PROVIDE ( __sprint_r = 0x40032d90 ); -PROVIDE ( srand = 0x4003a094 ); -PROVIDE ( __sread = 0x40054cec ); -PROVIDE ( __sseek = 0x40054d5c ); -PROVIDE ( __stack = 0x3fceb910 ); -PROVIDE ( __stack_app = 0x3fced910 ); -PROVIDE ( _stack_sentry = 0x3fce9910 ); -PROVIDE ( _stack_sentry_app = 0x3fceb910 ); -PROVIDE ( _start = 0x4003959c ); -PROVIDE ( _stat_r = 0x400545b4 ); -PROVIDE ( _stext = 0x40039438 ); -PROVIDE ( strcasecmp = 0x4003a1bc ); -PROVIDE ( strcasestr = 0x4003a850 ); -PROVIDE ( strcat = 0x4003aba8 ); -PROVIDE ( strchr = 0x4003abec ); -PROVIDE ( strcmp = 0x4003acd8 ); -PROVIDE ( strcoll = 0x4003adfc ); -PROVIDE ( strcpy = 0x4003ae10 ); -PROVIDE ( strcspn = 0x4005575c ); -PROVIDE ( strdup = 0x4003aea0 ); -PROVIDE ( _strdup_r = 0x4003aeb4 ); -PROVIDE ( string0_descr = 0x3ff0c1f6 ); -PROVIDE ( strlcat = 0x4003aed4 ); -PROVIDE ( strlcpy = 0x40055798 ); -PROVIDE ( strlen = 0x4003af3c ); -PROVIDE ( strlwr = 0x4003afa0 ); -PROVIDE ( str_manu_descr = 0x3ff0c1e2 ); -PROVIDE ( strncasecmp = 0x4003afd0 ); -PROVIDE ( strncat = 0x4003b028 ); -PROVIDE ( strncmp = 0x4003b088 ); -PROVIDE ( strncpy = 0x4003b178 ); -PROVIDE ( strndup = 0x4003b254 ); -PROVIDE ( _strndup_r = 0x4003b268 ); -PROVIDE ( strnlen = 0x400557d8 ); -PROVIDE ( str_prod_descr = 0x3ff0c1d0 ); -PROVIDE ( strrchr = 0x4003b2b8 ); -PROVIDE ( strsep = 0x4003b2e4 ); -PROVIDE ( str_serial_descr = 0x3fcef08c ); -PROVIDE ( strspn = 0x4005580c ); -PROVIDE ( strstr = 0x4003b674 ); -PROVIDE ( __strtok_r = 0x40055848 ); -PROVIDE ( strtok_r = 0x400558a4 ); -PROVIDE ( strtol = 0x40032b14 ); -PROVIDE ( strtol_l = 0x40032afc ); -PROVIDE ( _strtol_r = 0x40032ad8 ); -PROVIDE ( strtoul = 0x40032c84 ); -PROVIDE ( strtoul_l = 0x40032c6c ); -PROVIDE ( _strtoul_r = 0x40032c48 ); -PROVIDE ( strupr = 0x4003b8bc ); -PROVIDE ( __subdf3 = 0x4003beb0 ); -PROVIDE ( __subsf3 = 0x4003bad8 ); -PROVIDE ( __subvdi3 = 0x4003c4ec ); -PROVIDE ( __subvsi3 = 0x4003c4c8 ); -PROVIDE ( s_usb_osglue = 0x3fcef334 ); -PROVIDE ( __swbuf = 0x40033a34 ); -PROVIDE ( __swbuf_r = 0x4003396c ); -PROVIDE ( __swhatbuf_r = 0x40033cd4 ); -PROVIDE ( __swrite = 0x40054d24 ); -PROVIDE ( __swsetup_r = 0x40033a48 ); -PROVIDE ( sw_to_hw = 0x3fcef8e4 ); -PROVIDE ( _SyscallException = 0x40039677 ); -PROVIDE ( syscall_table_ptr = 0x3fcefcc8 ); -PROVIDE ( _system_r = 0x40054510 ); -PROVIDE ( TASK_DESC_DBG = 0x3fcef3a0 ); -PROVIDE ( TASK_DESC_LLC = 0x3fcef3e8 ); -PROVIDE ( TASK_DESC_LLM = 0x3fcef3f8 ); -PROVIDE ( TASK_DESC_MISC = 0x3ff090d8 ); -PROVIDE ( tdefl_compress = 0x40036610 ); -PROVIDE ( tdefl_compress_buffer = 0x40036d6c ); -PROVIDE ( tdefl_compress_mem_to_mem = 0x40036e84 ); -PROVIDE ( tdefl_compress_mem_to_output = 0x40036e64 ); -PROVIDE ( tdefl_get_adler32 = 0x40036e5c ); -PROVIDE ( tdefl_get_prev_return_status = 0x40036e54 ); -PROVIDE ( tdefl_init = 0x40036d88 ); -PROVIDE ( tdefl_write_image_to_png_file_in_memory = 0x40036e98 ); -PROVIDE ( tdefl_write_image_to_png_file_in_memory_ex = 0x40036e8c ); -PROVIDE ( _text_end = 0x400568d0 ); -PROVIDE ( _text_end_btdm_rom = 0x40032170 ); -PROVIDE ( _text_start = 0x40039438 ); -PROVIDE ( _text_start_btdm_rom = 0x4000056c ); -PROVIDE ( timer_env = 0x3fcefb9c ); -PROVIDE ( _times_r = 0x40054540 ); -PROVIDE ( tinfl_decompress = 0x4003542c ); -PROVIDE ( tinfl_decompress_mem_to_callback = 0x400365e4 ); -PROVIDE ( tinfl_decompress_mem_to_mem = 0x400365a4 ); -PROVIDE ( toascii = 0x400558b8 ); -PROVIDE ( tolower = 0x4003b990 ); -PROVIDE ( toupper = 0x4003b9ac ); -PROVIDE ( __truncdfsf2 = 0x4003c35c ); -PROVIDE ( uart_acm_dev = 0x3fcef350 ); -PROVIDE ( uartAttach = 0x40049414 ); -PROVIDE ( uart_baudrate_detect = 0x40049474 ); -PROVIDE ( uart_buff_switch = 0x40049a9c ); -PROVIDE ( UartConnCheck = 0x400485d8 ); -PROVIDE ( UartConnectProc = 0x400488d8 ); -PROVIDE ( UartDev = 0x3fcef354 ); -PROVIDE ( uart_div_modify = 0x40049568 ); -PROVIDE ( uart_div_reinit = 0x400495e0 ); -PROVIDE ( UartDwnLdProc = 0x40048d10 ); -PROVIDE ( UartGetCmdLn = 0x40049c7c ); -PROVIDE ( Uart_Init = 0x40049624 ); -PROVIDE ( Uart_Init_USB = 0x4004939c ); -PROVIDE ( UartRegReadProc = 0x4004893c ); -PROVIDE ( UartRegWriteProc = 0x400488e8 ); -PROVIDE ( uart_rx_intr_handler = 0x400491ec ); -PROVIDE ( uart_rx_one_char = 0x40049918 ); -PROVIDE ( uart_rx_one_char_block = 0x400498bc ); -PROVIDE ( uart_rx_readbuff = 0x40049a54 ); -PROVIDE ( UartRxString = 0x400499bc ); -PROVIDE ( UartSecureDwnLdProc = 0x40048fd8 ); -PROVIDE ( UartSetBaudProc = 0x400489b0 ); -PROVIDE ( UartSpiAttachProc = 0x40048964 ); -PROVIDE ( UartSpiReadProc = 0x40048980 ); -PROVIDE ( uart_tx_flush = 0x40049850 ); -PROVIDE ( uart_tx_one_char = 0x40049820 ); -PROVIDE ( uart_tx_one_char2 = 0x40049838 ); -PROVIDE ( uart_tx_switch = 0x40049468 ); -PROVIDE ( uart_tx_wait_idle = 0x40049884 ); -PROVIDE ( uart_usb_enable_reset_on_rts = 0x400493dc ); -PROVIDE ( Uart_USB_Send_Testament = 0x4004935c ); -PROVIDE ( __ucmpdi2 = 0x40037ed8 ); -PROVIDE ( __udivdi3 = 0x40056160 ); -PROVIDE ( __udivmoddi4 = 0x40039140 ); -PROVIDE ( __udivsi3 = 0x400558d8 ); -PROVIDE ( __udiv_w_sdiv = 0x40039138 ); -PROVIDE ( __umoddi3 = 0x400563e4 ); -PROVIDE ( __umodsi3 = 0x400558e0 ); -PROVIDE ( __umulsidi3 = 0x400558e8 ); -PROVIDE ( _unlink_r = 0x40054584 ); -PROVIDE ( unloaded_area = 0x3fcef8dc ); -PROVIDE ( __unorddf2 = 0x40037e8c ); -PROVIDE ( __unordsf2 = 0x40037b10 ); -PROVIDE ( usb_cancel_transfer = 0x4004bfd0 ); -PROVIDE ( usb_data_stuff = 0x3ff0938c ); -PROVIDE ( usb_dc_attach = 0x4004ac1c ); -PROVIDE ( usb_dc_check_poll_for_interrupts = 0x4004b6d0 ); -PROVIDE ( usb_dc_detach = 0x4004ad60 ); -PROVIDE ( usb_dc_ep_check_cap = 0x4004ade4 ); -PROVIDE ( usb_dc_ep_clear_stall = 0x4004b040 ); -PROVIDE ( usb_dc_ep_configure = 0x4004ae28 ); -PROVIDE ( usb_dc_ep_disable = 0x4004b23c ); -PROVIDE ( usb_dc_ep_enable = 0x4004b17c ); -PROVIDE ( usb_dc_ep_flush = 0x4004b308 ); -PROVIDE ( usb_dc_ep_halt = 0x4004b0ac ); -PROVIDE ( usb_dc_ep_is_stalled = 0x4004b10c ); -PROVIDE ( usb_dc_ep_mps = 0x4004b6a8 ); -PROVIDE ( usb_dc_ep_read = 0x4004b628 ); -PROVIDE ( usb_dc_ep_read_continue = 0x4004b5e8 ); -PROVIDE ( usb_dc_ep_read_wait = 0x4004b50c ); -PROVIDE ( usb_dc_ep_set_callback = 0x4004b660 ); -PROVIDE ( usb_dc_ep_set_stall = 0x4004afe0 ); -PROVIDE ( usb_dc_ep_write = 0x4004b3d4 ); -PROVIDE ( usb_dc_ep_write_would_block = 0x4004b374 ); -PROVIDE ( usb_dc_prepare_persist = 0x4004a92c ); -PROVIDE ( usb_dc_reset = 0x4004ad94 ); -PROVIDE ( usb_dc_set_address = 0x4004adac ); -PROVIDE ( usb_dc_set_status_callback = 0x4004b69c ); -PROVIDE ( usb_deconfig = 0x4004bd70 ); -PROVIDE ( usb_dev_get_configuration = 0x4004bd14 ); -PROVIDE ( usb_dev_resume = 0x4004bd00 ); -PROVIDE ( usb_dfu_force_detach = 0x4004c380 ); -PROVIDE ( usb_dfu_init = 0x4004c368 ); -PROVIDE ( usb_dfu_set_detach_cb = 0x4004c0ac ); -PROVIDE ( usb_disable = 0x4004be20 ); -PROVIDE ( usb_dw_isr_handler = 0x4004a98c ); -PROVIDE ( usb_enable = 0x4004bd90 ); -PROVIDE ( usb_ep_clear_stall = 0x4004be90 ); -PROVIDE ( usb_ep_read_continue = 0x4004beb8 ); -PROVIDE ( usb_ep_read_wait = 0x4004bea0 ); -PROVIDE ( usb_ep_set_stall = 0x4004be80 ); -PROVIDE ( usb_get_descriptor = 0x4004b77c ); -PROVIDE ( usb_read = 0x4004be68 ); -PROVIDE ( usb_set_config = 0x4004bd2c ); -PROVIDE ( usb_set_current_descriptor = 0x4004b764 ); -PROVIDE ( usb_transfer = 0x4004bf1c ); -PROVIDE ( usb_transfer_ep_callback = 0x4004bec8 ); -PROVIDE ( usb_transfer_sync = 0x4004c020 ); -PROVIDE ( usb_write = 0x4004be50 ); -PROVIDE ( usb_write_would_block = 0x4004be40 ); -PROVIDE ( user_code_start = 0x3fced914 ); -PROVIDE ( _UserExceptionVector = 0x40000340 ); -PROVIDE ( _UserExceptionVector_text_end = 0x40000365 ); -PROVIDE ( _UserExceptionVector_text_start = 0x40000340 ); -PROVIDE ( utoa = 0x4003225c ); -PROVIDE ( __utoa = 0x400321f4 ); -PROVIDE ( VerifyFlashMd5Proc = 0x40048b58 ); -PROVIDE ( veryBigHexP256 = 0x3ff080f4 ); -PROVIDE ( vfiprintf = 0x400330f4 ); -PROVIDE ( _vfiprintf_r = 0x40032df8 ); -PROVIDE ( vflash_mem = 0x3fcef998 ); -PROVIDE ( vfprintf = 0x400330f4 ); -PROVIDE ( _vfprintf_r = 0x40032df8 ); -PROVIDE ( vhci_env_p = 0x3fcefba4 ); -PROVIDE ( vnd_hci_command_handler_wrapper = 0x40002f20 ); -PROVIDE ( Wait_SPI_Idle = 0x4004d158 ); -PROVIDE ( wcrtomb = 0x40033618 ); -PROVIDE ( _wcrtomb_r = 0x400335c0 ); -PROVIDE ( _wctomb_r = 0x40033c88 ); -PROVIDE ( _WindowOverflow12 = 0x40000100 ); -PROVIDE ( _WindowOverflow4 = 0x40000000 ); -PROVIDE ( _WindowOverflow8 = 0x40000080 ); -PROVIDE ( _WindowUnderflow12 = 0x40000140 ); -PROVIDE ( _WindowUnderflow4 = 0x40000040 ); -PROVIDE ( _WindowUnderflow8 = 0x400000c0 ); -PROVIDE ( _WindowVectors_text_end = 0x40000170 ); -PROVIDE ( _WindowVectors_text_start = 0x40000000 ); -PROVIDE ( write = 0x4003b978 ); -PROVIDE ( _write_r = 0x40054670 ); -PROVIDE ( __XT_EXCEPTION_DESCS__ = 0x3ff0fff0 ); -PROVIDE ( __XT_EXCEPTION_DESCS_END__ = 0x3ff0fff0 ); -PROVIDE ( __XT_EXCEPTION_TABLE__ = 0x3ff0ff00 ); -PROVIDE ( xthal_bcopy = 0x400552ac ); -PROVIDE ( xthal_copy123 = 0x40055338 ); -PROVIDE ( xthal_get_ccompare = 0x4005543c ); -PROVIDE ( xthal_get_ccount = 0x40055410 ); -PROVIDE ( xthal_get_interrupt = 0x4005545c ); -PROVIDE ( Xthal_intlevel = 0x3ff0c504 ); -PROVIDE ( xthal_memcpy = 0x400552d0 ); -PROVIDE ( xthal_set_ccompare = 0x40055418 ); -PROVIDE ( xthal_set_intclear = 0x40055464 ); -PROVIDE ( xthals_hw_configid0 = 0xc2f0fffe ); -PROVIDE ( xthals_hw_configid1 = 0x23086d67 ); -PROVIDE ( xthal_spill_registers_into_stack_nw = 0x400548f8 ); -PROVIDE ( xthals_release_major = 0x00002ee0 ); -PROVIDE ( xthals_release_minor = 0x0000000c ); -PROVIDE ( xthal_window_spill = 0x40054a0c ); -PROVIDE ( xthal_window_spill_nw = 0x400548f8 ); -PROVIDE ( _xtos_alloca_handler = 0x40000010 ); -PROVIDE ( xtos_cause3_handler = 0x400396bc ); -PROVIDE ( xtos_c_handler_table = 0x3fcee27c ); -PROVIDE ( xtos_c_wrapper_handler = 0x400396cc ); -PROVIDE ( _xtos_enabled = 0x3fcee388 ); -PROVIDE ( xtos_exc_handler_table = 0x3fcee17c ); -PROVIDE ( xtos_interrupt_mask_table = 0x3fcee490 ); -PROVIDE ( xtos_interrupt_table = 0x3fcee390 ); -PROVIDE ( _xtos_ints_off = 0x400548d0 ); -PROVIDE ( _xtos_ints_on = 0x400548ac ); -PROVIDE ( _xtos_intstruct = 0x3fcee388 ); -PROVIDE ( _xtos_l1int_handler = 0x40039790 ); -PROVIDE ( xtos_p_none = 0x40055234 ); -PROVIDE ( _xtos_restore_intlevel = 0x400398a0 ); -PROVIDE ( _xtos_return_from_exc = 0x4005523c ); -PROVIDE ( _xtos_set_exception_handler = 0x400395f0 ); -PROVIDE ( _xtos_set_interrupt_handler = 0x40054870 ); -PROVIDE ( _xtos_set_interrupt_handler_arg = 0x40054834 ); -PROVIDE ( _xtos_set_intlevel = 0x40055254 ); -PROVIDE ( _xtos_set_min_intlevel = 0x40055270 ); -PROVIDE ( _xtos_set_vpri = 0x400398ac ); -PROVIDE ( _xtos_syscall_handler = 0x40039638 ); -PROVIDE ( xtos_unhandled_exception = 0x40055294 ); -PROVIDE ( xtos_unhandled_interrupt = 0x400552a4 ); -PROVIDE ( _xtos_vectors_ref_ = 0x00000000 ); -PROVIDE ( _xtos_vpri_enabled = 0x3fcee38c ); diff --git a/tools/esptool_py/flasher_stub/ld/rom_8266.ld b/tools/esptool_py/flasher_stub/ld/rom_8266.ld deleted file mode 100644 index 9269fa2de5..0000000000 --- a/tools/esptool_py/flasher_stub/ld/rom_8266.ld +++ /dev/null @@ -1,351 +0,0 @@ -PROVIDE ( Cache_Read_Disable = 0x400047f0 ); -PROVIDE ( Cache_Read_Enable = 0x40004678 ); -PROVIDE ( FilePacketSendReqMsgProc = 0x400035a0 ); -PROVIDE ( FlashDwnLdParamCfgMsgProc = 0x4000368c ); -PROVIDE ( FlashDwnLdStartMsgProc = 0x40003538 ); -PROVIDE ( FlashDwnLdStopReqMsgProc = 0x40003658 ); -PROVIDE ( GetUartDevice = 0x40003f4c ); -PROVIDE ( MD5Final = 0x40009900 ); -PROVIDE ( MD5Init = 0x40009818 ); -PROVIDE ( MD5Update = 0x40009834 ); -PROVIDE ( MemDwnLdStartMsgProc = 0x400036c4 ); -PROVIDE ( MemDwnLdStopReqMsgProc = 0x4000377c ); -PROVIDE ( MemPacketSendReqMsgProc = 0x400036f0 ); -PROVIDE ( RcvMsg = 0x40003eac ); -PROVIDE ( SHA1Final = 0x4000b648 ); -PROVIDE ( SHA1Init = 0x4000b584 ); -PROVIDE ( SHA1Transform = 0x4000a364 ); -PROVIDE ( SHA1Update = 0x4000b5a8 ); -PROVIDE ( SPI_read_status = 0x400043c8 ); -PROVIDE ( SPI_write_status = 0x40004400 ); -PROVIDE ( SPI_write_enable = 0x4000443c ); -PROVIDE ( Wait_SPI_Idle = 0x4000448c ); -PROVIDE ( Enable_QMode = 0x400044c0 ); -PROVIDE ( SPIEraseArea = 0x40004b44 ); -PROVIDE ( SPIEraseBlock = 0x400049b4 ); -PROVIDE ( SPIEraseChip = 0x40004984 ); -PROVIDE ( SPIEraseSector = 0x40004a00 ); -PROVIDE ( SPILock = 0x400048a8 ); -PROVIDE ( SPIParamCfg = 0x40004c2c ); -PROVIDE ( SPIRead = 0x40004b1c ); -PROVIDE ( SPIReadModeCnfig = 0x400048ec ); -PROVIDE ( SPIUnlock = 0x40004878 ); -PROVIDE ( SPIWrite = 0x40004a4c ); -PROVIDE ( SelectSpiFunction = 0x40003f58 ); -PROVIDE ( SendMsg = 0x40003cf4 ); -PROVIDE ( UartConnCheck = 0x40003230 ); -PROVIDE ( UartConnectProc = 0x400037a0 ); -PROVIDE ( UartDwnLdProc = 0x40003368 ); -PROVIDE ( UartGetCmdLn = 0x40003ef4 ); -PROVIDE ( UartRegReadProc = 0x4000381c ); -PROVIDE ( UartRegWriteProc = 0x400037ac ); -PROVIDE ( UartRxString = 0x40003c30 ); -PROVIDE ( Uart_Init = 0x40003a14 ); -PROVIDE ( _DebugExceptionVector = 0x40000010 ); -PROVIDE ( _DoubleExceptionVector = 0x40000070 ); -PROVIDE ( _KernelExceptionVector = 0x40000030 ); -PROVIDE ( _NMIExceptionVector = 0x40000020 ); -PROVIDE ( _ResetHandler = 0x400000a4 ); -PROVIDE ( _ResetVector = 0x40000080 ); -PROVIDE ( _UserExceptionVector = 0x40000050 ); -PROVIDE ( __adddf3 = 0x4000c538 ); -PROVIDE ( __addsf3 = 0x4000c180 ); -PROVIDE ( __divdf3 = 0x4000cb94 ); -PROVIDE ( __divdi3 = 0x4000ce60 ); -PROVIDE ( __divsi3 = 0x4000dc88 ); -PROVIDE ( __extendsfdf2 = 0x4000cdfc ); -PROVIDE ( __fixdfsi = 0x4000ccb8 ); -PROVIDE ( __fixunsdfsi = 0x4000cd00 ); -PROVIDE ( __fixunssfsi = 0x4000c4c4 ); -PROVIDE ( __floatsidf = 0x4000e2f0 ); -PROVIDE ( __floatsisf = 0x4000e2ac ); -PROVIDE ( __floatunsidf = 0x4000e2e8 ); -PROVIDE ( __floatunsisf = 0x4000e2a4 ); -PROVIDE ( __muldf3 = 0x4000c8f0 ); -PROVIDE ( __muldi3 = 0x40000650 ); -PROVIDE ( __mulsf3 = 0x4000c3dc ); -PROVIDE ( __subdf3 = 0x4000c688 ); -PROVIDE ( __subsf3 = 0x4000c268 ); -PROVIDE ( __truncdfsf2 = 0x4000cd5c ); -PROVIDE ( __udivdi3 = 0x4000d310 ); -PROVIDE ( __udivsi3 = 0x4000e21c ); -PROVIDE ( __umoddi3 = 0x4000d770 ); -PROVIDE ( __umodsi3 = 0x4000e268 ); -PROVIDE ( __umulsidi3 = 0x4000dcf0 ); -PROVIDE ( _rom_store = 0x4000e388 ); -PROVIDE ( _rom_store_table = 0x4000e328 ); -PROVIDE ( _start = 0x4000042c ); -PROVIDE ( _xtos_alloca_handler = 0x4000dbe0 ); -PROVIDE ( _xtos_c_wrapper_handler = 0x40000598 ); -PROVIDE ( _xtos_cause3_handler = 0x40000590 ); -PROVIDE ( _xtos_ints_off = 0x4000bda4 ); -PROVIDE ( _xtos_ints_on = 0x4000bd84 ); -PROVIDE ( _xtos_l1int_handler = 0x4000048c ); -PROVIDE ( _xtos_p_none = 0x4000dbf8 ); -PROVIDE ( _xtos_restore_intlevel = 0x4000056c ); -PROVIDE ( _xtos_return_from_exc = 0x4000dc54 ); -PROVIDE ( _xtos_set_exception_handler = 0x40000454 ); -PROVIDE ( _xtos_set_interrupt_handler = 0x4000bd70 ); -PROVIDE ( _xtos_set_interrupt_handler_arg = 0x4000bd28 ); -PROVIDE ( _xtos_set_intlevel = 0x4000dbfc ); -PROVIDE ( _xtos_set_min_intlevel = 0x4000dc18 ); -PROVIDE ( _xtos_set_vpri = 0x40000574 ); -PROVIDE ( _xtos_syscall_handler = 0x4000dbe4 ); -PROVIDE ( _xtos_unhandled_exception = 0x4000dc44 ); -PROVIDE ( _xtos_unhandled_interrupt = 0x4000dc3c ); -PROVIDE ( aes_decrypt = 0x400092d4 ); -PROVIDE ( aes_decrypt_deinit = 0x400092e4 ); -PROVIDE ( aes_decrypt_init = 0x40008ea4 ); -PROVIDE ( aes_unwrap = 0x40009410 ); -PROVIDE ( base64_decode = 0x40009648 ); -PROVIDE ( base64_encode = 0x400094fc ); -PROVIDE ( bzero = 0x4000de84 ); -PROVIDE ( cmd_parse = 0x40000814 ); -PROVIDE ( conv_str_decimal = 0x40000b24 ); -PROVIDE ( conv_str_hex = 0x40000cb8 ); -PROVIDE ( convert_para_str = 0x40000a60 ); -PROVIDE ( dtm_get_intr_mask = 0x400026d0 ); -PROVIDE ( dtm_params_init = 0x4000269c ); -PROVIDE ( dtm_set_intr_mask = 0x400026c8 ); -PROVIDE ( dtm_set_params = 0x400026dc ); -PROVIDE ( eprintf = 0x40001d14 ); -PROVIDE ( eprintf_init_buf = 0x40001cb8 ); -PROVIDE ( eprintf_to_host = 0x40001d48 ); -PROVIDE ( est_get_printf_buf_remain_len = 0x40002494 ); -PROVIDE ( est_reset_printf_buf_len = 0x4000249c ); -PROVIDE ( ets_bzero = 0x40002ae8 ); -PROVIDE ( ets_char2xdigit = 0x40002b74 ); -PROVIDE ( ets_delay_us = 0x40002ecc ); -PROVIDE ( ets_enter_sleep = 0x400027b8 ); -PROVIDE ( ets_external_printf = 0x40002578 ); -PROVIDE ( ets_get_cpu_frequency = 0x40002f0c ); -PROVIDE ( ets_getc = 0x40002bcc ); -PROVIDE ( ets_install_external_printf = 0x40002450 ); -PROVIDE ( ets_install_putc1 = 0x4000242c ); -PROVIDE ( ets_install_putc2 = 0x4000248c ); -PROVIDE ( ets_install_uart_printf = 0x40002438 ); -PROVIDE ( ets_intr_lock = 0x40000f74 ); -PROVIDE ( ets_intr_unlock = 0x40000f80 ); -PROVIDE ( ets_isr_attach = 0x40000f88 ); -PROVIDE ( ets_isr_mask = 0x40000f98 ); -PROVIDE ( ets_isr_unmask = 0x40000fa8 ); -PROVIDE ( ets_memcmp = 0x400018d4 ); -PROVIDE ( ets_memcpy = 0x400018b4 ); -PROVIDE ( ets_memmove = 0x400018c4 ); -PROVIDE ( ets_memset = 0x400018a4 ); -PROVIDE ( ets_post = 0x40000e24 ); -PROVIDE ( ets_printf = 0x400024cc ); -PROVIDE ( ets_putc = 0x40002be8 ); -PROVIDE ( ets_rtc_int_register = 0x40002a40 ); -PROVIDE ( ets_run = 0x40000e04 ); -PROVIDE ( ets_set_idle_cb = 0x40000dc0 ); -PROVIDE ( ets_set_user_start = 0x40000fbc ); -PROVIDE ( ets_str2macaddr = 0x40002af8 ); -PROVIDE ( ets_strcmp = 0x40002aa8 ); -PROVIDE ( ets_strcpy = 0x40002a88 ); -PROVIDE ( ets_strlen = 0x40002ac8 ); -PROVIDE ( ets_strncmp = 0x40002ab8 ); -PROVIDE ( ets_strncpy = 0x40002a98 ); -PROVIDE ( ets_strstr = 0x40002ad8 ); -PROVIDE ( ets_task = 0x40000dd0 ); -PROVIDE ( ets_timer_arm = 0x40002cc4 ); -PROVIDE ( ets_timer_disarm = 0x40002d40 ); -PROVIDE ( ets_timer_done = 0x40002d80 ); -PROVIDE ( ets_timer_handler_isr = 0x40002da8 ); -PROVIDE ( ets_timer_init = 0x40002e68 ); -PROVIDE ( ets_timer_setfn = 0x40002c48 ); -PROVIDE ( ets_uart_printf = 0x40002544 ); -PROVIDE ( ets_update_cpu_frequency = 0x40002f04 ); -PROVIDE ( ets_vprintf = 0x40001f00 ); -PROVIDE ( ets_wdt_disable = 0x400030f0 ); -PROVIDE ( ets_wdt_enable = 0x40002fa0 ); -PROVIDE ( ets_wdt_get_mode = 0x40002f34 ); -PROVIDE ( ets_wdt_init = 0x40003170 ); -PROVIDE ( ets_wdt_restore = 0x40003158 ); -PROVIDE ( ets_write_char = 0x40001da0 ); -PROVIDE ( get_first_seg = 0x4000091c ); -PROVIDE ( gpio_init = 0x40004c50 ); -PROVIDE ( gpio_input_get = 0x40004cf0 ); -PROVIDE ( gpio_intr_ack = 0x40004dcc ); -PROVIDE ( gpio_intr_handler_register = 0x40004e28 ); -PROVIDE ( gpio_intr_pending = 0x40004d88 ); -PROVIDE ( gpio_intr_test = 0x40004efc ); -PROVIDE ( gpio_output_set = 0x40004cd0 ); -PROVIDE ( gpio_pin_intr_state_set = 0x40004d90 ); -PROVIDE ( gpio_pin_wakeup_disable = 0x40004ed4 ); -PROVIDE ( gpio_pin_wakeup_enable = 0x40004e90 ); -PROVIDE ( gpio_register_get = 0x40004d5c ); -PROVIDE ( gpio_register_set = 0x40004d04 ); -PROVIDE ( hmac_md5 = 0x4000a2cc ); -PROVIDE ( hmac_md5_vector = 0x4000a160 ); -PROVIDE ( hmac_sha1 = 0x4000ba28 ); -PROVIDE ( hmac_sha1_vector = 0x4000b8b4 ); -PROVIDE ( lldesc_build_chain = 0x40004f40 ); -PROVIDE ( lldesc_num2link = 0x40005050 ); -PROVIDE ( lldesc_set_owner = 0x4000507c ); -PROVIDE ( main = 0x40000fec ); -PROVIDE ( md5_vector = 0x400097ac ); -PROVIDE ( mem_calloc = 0x40001c2c ); -PROVIDE ( mem_free = 0x400019e0 ); -PROVIDE ( mem_init = 0x40001998 ); -PROVIDE ( mem_malloc = 0x40001b40 ); -PROVIDE ( mem_realloc = 0x40001c6c ); -PROVIDE ( mem_trim = 0x40001a14 ); -PROVIDE ( mem_zalloc = 0x40001c58 ); -PROVIDE ( memcmp = 0x4000dea8 ); -PROVIDE ( memcpy = 0x4000df48 ); -PROVIDE ( memmove = 0x4000e04c ); -PROVIDE ( memset = 0x4000e190 ); -PROVIDE ( multofup = 0x400031c0 ); -PROVIDE ( pbkdf2_sha1 = 0x4000b840 ); -PROVIDE ( phy_get_romfuncs = 0x40006b08 ); -PROVIDE ( rand = 0x40000600 ); -PROVIDE ( rc4_skip = 0x4000dd68 ); -PROVIDE ( recv_packet = 0x40003d08 ); -PROVIDE ( remove_head_space = 0x40000a04 ); -PROVIDE ( rijndaelKeySetupDec = 0x40008dd0 ); -PROVIDE ( rijndaelKeySetupEnc = 0x40009300 ); -PROVIDE ( rom_abs_temp = 0x400060c0 ); -PROVIDE ( rom_ana_inf_gating_en = 0x40006b10 ); -PROVIDE ( rom_cal_tos_v50 = 0x40007a28 ); -PROVIDE ( rom_chip_50_set_channel = 0x40006f84 ); -PROVIDE ( rom_chip_v5_disable_cca = 0x400060d0 ); -PROVIDE ( rom_chip_v5_enable_cca = 0x400060ec ); -PROVIDE ( rom_chip_v5_rx_init = 0x4000711c ); -PROVIDE ( rom_chip_v5_sense_backoff = 0x4000610c ); -PROVIDE ( rom_chip_v5_tx_init = 0x4000718c ); -PROVIDE ( rom_dc_iq_est = 0x4000615c ); -PROVIDE ( rom_en_pwdet = 0x400061b8 ); -PROVIDE ( rom_get_bb_atten = 0x40006238 ); -PROVIDE ( rom_get_corr_power = 0x40006260 ); -PROVIDE ( rom_get_fm_sar_dout = 0x400062dc ); -PROVIDE ( rom_get_noisefloor = 0x40006394 ); -PROVIDE ( rom_get_power_db = 0x400063b0 ); -PROVIDE ( rom_i2c_readReg = 0x40007268 ); -PROVIDE ( rom_i2c_readReg_Mask = 0x4000729c ); -PROVIDE ( rom_i2c_writeReg = 0x400072d8 ); -PROVIDE ( rom_i2c_writeReg_Mask = 0x4000730c ); -PROVIDE ( rom_iq_est_disable = 0x40006400 ); -PROVIDE ( rom_iq_est_enable = 0x40006430 ); -PROVIDE ( rom_linear_to_db = 0x40006484 ); -PROVIDE ( rom_mhz2ieee = 0x400065a4 ); -PROVIDE ( rom_pbus_dco___SA2 = 0x40007bf0 ); -PROVIDE ( rom_pbus_debugmode = 0x4000737c ); -PROVIDE ( rom_pbus_enter_debugmode = 0x40007410 ); -PROVIDE ( rom_pbus_exit_debugmode = 0x40007448 ); -PROVIDE ( rom_pbus_force_test = 0x4000747c ); -PROVIDE ( rom_pbus_rd = 0x400074d8 ); -PROVIDE ( rom_pbus_set_rxgain = 0x4000754c ); -PROVIDE ( rom_pbus_set_txgain = 0x40007610 ); -PROVIDE ( rom_pbus_workmode = 0x40007648 ); -PROVIDE ( rom_pbus_xpd_rx_off = 0x40007688 ); -PROVIDE ( rom_pbus_xpd_rx_on = 0x400076cc ); -PROVIDE ( rom_pbus_xpd_tx_off = 0x400076fc ); -PROVIDE ( rom_pbus_xpd_tx_on = 0x40007740 ); -PROVIDE ( rom_pbus_xpd_tx_on__low_gain = 0x400077a0 ); -PROVIDE ( rom_phy_reset_req = 0x40007804 ); -PROVIDE ( rom_restart_cal = 0x4000781c ); -PROVIDE ( rom_rfcal_pwrctrl = 0x40007eb4 ); -PROVIDE ( rom_rfcal_rxiq = 0x4000804c ); -PROVIDE ( rom_rfcal_rxiq_set_reg = 0x40008264 ); -PROVIDE ( rom_rfcal_txcap = 0x40008388 ); -PROVIDE ( rom_rfcal_txiq = 0x40008610 ); -PROVIDE ( rom_rfcal_txiq_cover = 0x400088b8 ); -PROVIDE ( rom_rfcal_txiq_set_reg = 0x40008a70 ); -PROVIDE ( rom_rfpll_reset = 0x40007868 ); -PROVIDE ( rom_rfpll_set_freq = 0x40007968 ); -PROVIDE ( rom_rxiq_cover_mg_mp = 0x40008b6c ); -PROVIDE ( rom_rxiq_get_mis = 0x40006628 ); -PROVIDE ( rom_sar_init = 0x40006738 ); -PROVIDE ( rom_set_ana_inf_tx_scale = 0x4000678c ); -PROVIDE ( rom_set_channel_freq = 0x40006c50 ); -PROVIDE ( rom_set_loopback_gain = 0x400067c8 ); -PROVIDE ( rom_set_noise_floor = 0x40006830 ); -PROVIDE ( rom_set_rxclk_en = 0x40006550 ); -PROVIDE ( rom_set_txbb_atten = 0x40008c6c ); -PROVIDE ( rom_set_txclk_en = 0x4000650c ); -PROVIDE ( rom_set_txiq_cal = 0x40008d34 ); -PROVIDE ( rom_start_noisefloor = 0x40006874 ); -PROVIDE ( rom_start_tx_tone = 0x400068b4 ); -PROVIDE ( rom_stop_tx_tone = 0x4000698c ); -PROVIDE ( rom_tx_mac_disable = 0x40006a98 ); -PROVIDE ( rom_tx_mac_enable = 0x40006ad4 ); -PROVIDE ( rom_txtone_linear_pwr = 0x40006a1c ); -PROVIDE ( rom_write_rfpll_sdm = 0x400078dc ); -PROVIDE ( roundup2 = 0x400031b4 ); -PROVIDE ( rtc_enter_sleep = 0x40002870 ); -PROVIDE ( rtc_get_reset_reason = 0x400025e0 ); -PROVIDE ( rtc_intr_handler = 0x400029ec ); -PROVIDE ( rtc_set_sleep_mode = 0x40002668 ); -PROVIDE ( save_rxbcn_mactime = 0x400027a4 ); -PROVIDE ( save_tsf_us = 0x400027ac ); -PROVIDE ( send_packet = 0x40003c80 ); -PROVIDE ( sha1_prf = 0x4000ba48 ); -PROVIDE ( sha1_vector = 0x4000a2ec ); -PROVIDE ( sip_alloc_to_host_evt = 0x40005180 ); -PROVIDE ( sip_get_ptr = 0x400058a8 ); -PROVIDE ( sip_get_state = 0x40005668 ); -PROVIDE ( sip_init_attach = 0x4000567c ); -PROVIDE ( sip_install_rx_ctrl_cb = 0x4000544c ); -PROVIDE ( sip_install_rx_data_cb = 0x4000545c ); -PROVIDE ( sip_post = 0x400050fc ); -PROVIDE ( sip_post_init = 0x400056c4 ); -PROVIDE ( sip_reclaim_from_host_cmd = 0x4000534c ); -PROVIDE ( sip_reclaim_tx_data_pkt = 0x400052c0 ); -PROVIDE ( sip_send = 0x40005808 ); -PROVIDE ( sip_to_host_chain_append = 0x40005864 ); -PROVIDE ( sip_to_host_evt_send_done = 0x40005234 ); -PROVIDE ( slc_add_credits = 0x400060ac ); -PROVIDE ( slc_enable = 0x40005d90 ); -PROVIDE ( slc_from_host_chain_fetch = 0x40005f24 ); -PROVIDE ( slc_from_host_chain_recycle = 0x40005e94 ); -PROVIDE ( slc_init_attach = 0x40005c50 ); -PROVIDE ( slc_init_credit = 0x4000608c ); -PROVIDE ( slc_pause_from_host = 0x40006014 ); -PROVIDE ( slc_reattach = 0x40005c1c ); -PROVIDE ( slc_resume_from_host = 0x4000603c ); -PROVIDE ( slc_select_tohost_gpio = 0x40005dc0 ); -PROVIDE ( slc_select_tohost_gpio_mode = 0x40005db8 ); -PROVIDE ( slc_send_to_host_chain = 0x40005de4 ); -PROVIDE ( slc_set_host_io_max_window = 0x40006068 ); -PROVIDE ( slc_to_host_chain_recycle = 0x40005f10 ); -PROVIDE ( software_reset = 0x4000264c ); -PROVIDE ( spi_flash_attach = 0x40004644 ); -PROVIDE ( srand = 0x400005f0 ); -PROVIDE ( strcmp = 0x4000bdc8 ); -PROVIDE ( strcpy = 0x4000bec8 ); -PROVIDE ( strlen = 0x4000bf4c ); -PROVIDE ( strncmp = 0x4000bfa8 ); -PROVIDE ( strncpy = 0x4000c0a0 ); -PROVIDE ( strstr = 0x4000e1e0 ); -PROVIDE ( timer_insert = 0x40002c64 ); -PROVIDE ( uartAttach = 0x4000383c ); -PROVIDE ( uart_baudrate_detect = 0x40003924 ); -PROVIDE ( uart_buff_switch = 0x400038a4 ); -PROVIDE ( uart_div_modify = 0x400039d8 ); -PROVIDE ( uart_rx_intr_handler = 0x40003bbc ); -PROVIDE ( uart_rx_one_char = 0x40003b8c ); -PROVIDE ( uart_rx_one_char_block = 0x40003b64 ); -PROVIDE ( uart_rx_readbuff = 0x40003ec8 ); -PROVIDE ( uart_tx_one_char = 0x40003b30 ); -PROVIDE ( wepkey_128 = 0x4000bc40 ); -PROVIDE ( wepkey_64 = 0x4000bb3c ); -PROVIDE ( xthal_bcopy = 0x40000688 ); -PROVIDE ( xthal_copy123 = 0x4000074c ); -PROVIDE ( xthal_get_ccompare = 0x4000dd4c ); -PROVIDE ( xthal_get_ccount = 0x4000dd38 ); -PROVIDE ( xthal_get_interrupt = 0x4000dd58 ); -PROVIDE ( xthal_get_intread = 0x4000dd58 ); -PROVIDE ( xthal_memcpy = 0x400006c4 ); -PROVIDE ( xthal_set_ccompare = 0x4000dd40 ); -PROVIDE ( xthal_set_intclear = 0x4000dd60 ); -PROVIDE ( xthal_spill_registers_into_stack_nw = 0x4000e320 ); -PROVIDE ( xthal_window_spill = 0x4000e324 ); -PROVIDE ( xthal_window_spill_nw = 0x4000e320 ); - -PROVIDE ( Te0 = 0x3fffccf0 ); -PROVIDE ( Td0 = 0x3fffd100 ); -PROVIDE ( Td4s = 0x3fffd500); -PROVIDE ( rcons = 0x3fffd0f0); -PROVIDE ( UartDev = 0x3fffde10 ); -PROVIDE ( flashchip = 0x3fffc714); diff --git a/tools/esptool_py/flasher_stub/ld/stub_32.ld b/tools/esptool_py/flasher_stub/ld/stub_32.ld deleted file mode 100644 index 9ab8255858..0000000000 --- a/tools/esptool_py/flasher_stub/ld/stub_32.ld +++ /dev/null @@ -1,29 +0,0 @@ -/* Note: stub is deliberately loaded close to the very top - of available RAM, to reduce change of colliding with anything - else... */ -MEMORY { - iram : org = 0x400BE000, len = 0x1000 - dram : org = 0x3ffcc000, len = 0x14000 -} - -ENTRY(stub_main) - -SECTIONS { - .text : ALIGN(4) { - *(.literal) - *(.text .text.*) - } > iram - - .bss : ALIGN(4) { - _bss_start = ABSOLUTE(.); - *(.bss) - _bss_end = ABSOLUTE(.); - } > dram - - .data : ALIGN(4) { - *(.data) - *(.rodata .rodata.*) - } > dram -} - -INCLUDE "rom_32.ld" diff --git a/tools/esptool_py/flasher_stub/ld/stub_32c2.ld b/tools/esptool_py/flasher_stub/ld/stub_32c2.ld deleted file mode 100644 index e0c0ec4edf..0000000000 --- a/tools/esptool_py/flasher_stub/ld/stub_32c2.ld +++ /dev/null @@ -1,26 +0,0 @@ -MEMORY { - iram : org = 0x40380000, len = 0x4000 - dram : org = 0x3FCA4000, len = 0x18000 -} - -ENTRY(stub_main) - -SECTIONS { - .text : ALIGN(4) { - *(.literal) - *(.text .text.*) - } > iram - - .bss : ALIGN(4) { - _bss_start = ABSOLUTE(.); - *(.bss) - _bss_end = ABSOLUTE(.); - } > dram - - .data : ALIGN(4) { - *(.data) - *(.rodata .rodata.*) - } > dram -} - -INCLUDE "rom_32c2.ld" diff --git a/tools/esptool_py/flasher_stub/ld/stub_32c3.ld b/tools/esptool_py/flasher_stub/ld/stub_32c3.ld deleted file mode 100644 index dc9d4201e3..0000000000 --- a/tools/esptool_py/flasher_stub/ld/stub_32c3.ld +++ /dev/null @@ -1,26 +0,0 @@ -MEMORY { - iram : org = 0x40380000, len = 0x4000 - dram : org = 0x3FC84000, len = 0x18000 -} - -ENTRY(stub_main) - -SECTIONS { - .text : ALIGN(4) { - *(.literal) - *(.text .text.*) - } > iram - - .bss : ALIGN(4) { - _bss_start = ABSOLUTE(.); - *(.bss) - _bss_end = ABSOLUTE(.); - } > dram - - .data : ALIGN(4) { - *(.data) - *(.rodata .rodata.*) - } > dram -} - -INCLUDE "rom_32c3.ld" diff --git a/tools/esptool_py/flasher_stub/ld/stub_32c5_beta_3.ld b/tools/esptool_py/flasher_stub/ld/stub_32c5_beta_3.ld deleted file mode 100644 index e1133674e9..0000000000 --- a/tools/esptool_py/flasher_stub/ld/stub_32c5_beta_3.ld +++ /dev/null @@ -1,26 +0,0 @@ -MEMORY { - iram : org = 0x40800000, len = 0x4000 - dram : org = 0x40840000, len = 0x18000 -} - -ENTRY(stub_main) - -SECTIONS { - .text : ALIGN(4) { - *(.literal) - *(.text .text.*) - } > iram - - .bss : ALIGN(4) { - _bss_start = ABSOLUTE(.); - *(.bss) - _bss_end = ABSOLUTE(.); - } > dram - - .data : ALIGN(4) { - *(.data) - *(.rodata .rodata.*) - } > dram -} - -INCLUDE "rom_32c5_beta_3.ld" diff --git a/tools/esptool_py/flasher_stub/ld/stub_32c6.ld b/tools/esptool_py/flasher_stub/ld/stub_32c6.ld deleted file mode 100644 index 91b8d3137a..0000000000 --- a/tools/esptool_py/flasher_stub/ld/stub_32c6.ld +++ /dev/null @@ -1,26 +0,0 @@ -MEMORY { - iram : org = 0x40800000, len = 0x4000 - dram : org = 0x40840000, len = 0x18000 -} - -ENTRY(stub_main) - -SECTIONS { - .text : ALIGN(4) { - *(.literal) - *(.text .text.*) - } > iram - - .bss : ALIGN(4) { - _bss_start = ABSOLUTE(.); - *(.bss) - _bss_end = ABSOLUTE(.); - } > dram - - .data : ALIGN(4) { - *(.data) - *(.rodata .rodata.*) - } > dram -} - -INCLUDE "rom_32c6.ld" diff --git a/tools/esptool_py/flasher_stub/ld/stub_32c6_beta.ld b/tools/esptool_py/flasher_stub/ld/stub_32c6_beta.ld deleted file mode 100644 index 5acb1029b3..0000000000 --- a/tools/esptool_py/flasher_stub/ld/stub_32c6_beta.ld +++ /dev/null @@ -1,26 +0,0 @@ -MEMORY { - iram : org = 0x40380000, len = 0x4000 - dram : org = 0x3FC84000, len = 0x18000 -} - -ENTRY(stub_main) - -SECTIONS { - .text : ALIGN(4) { - *(.literal) - *(.text .text.*) - } > iram - - .bss : ALIGN(4) { - _bss_start = ABSOLUTE(.); - *(.bss) - _bss_end = ABSOLUTE(.); - } > dram - - .data : ALIGN(4) { - *(.data) - *(.rodata .rodata.*) - } > dram -} - -INCLUDE "rom_32c6_beta.ld" diff --git a/tools/esptool_py/flasher_stub/ld/stub_32h2.ld b/tools/esptool_py/flasher_stub/ld/stub_32h2.ld deleted file mode 100644 index c94f5939e8..0000000000 --- a/tools/esptool_py/flasher_stub/ld/stub_32h2.ld +++ /dev/null @@ -1,26 +0,0 @@ -MEMORY { - iram : org = 0x40800000, len = 0x4000 - dram : org = 0x40830000, len = 0x18000 -} - -ENTRY(stub_main) - -SECTIONS { - .text : ALIGN(4) { - *(.literal) - *(.text .text.*) - } > iram - - .bss : ALIGN(4) { - _bss_start = ABSOLUTE(.); - *(.bss) - _bss_end = ABSOLUTE(.); - } > dram - - .data : ALIGN(4) { - *(.data) - *(.rodata .rodata.*) - } > dram -} - -INCLUDE "rom_32h2.ld" diff --git a/tools/esptool_py/flasher_stub/ld/stub_32h2_beta_1.ld b/tools/esptool_py/flasher_stub/ld/stub_32h2_beta_1.ld deleted file mode 100644 index 62b16372c6..0000000000 --- a/tools/esptool_py/flasher_stub/ld/stub_32h2_beta_1.ld +++ /dev/null @@ -1,26 +0,0 @@ -MEMORY { - iram : org = 0x40380000, len = 0x4000 - dram : org = 0x3FC84000, len = 0x18000 -} - -ENTRY(stub_main) - -SECTIONS { - .text : ALIGN(4) { - *(.literal) - *(.text .text.*) - } > iram - - .bss : ALIGN(4) { - _bss_start = ABSOLUTE(.); - *(.bss) - _bss_end = ABSOLUTE(.); - } > dram - - .data : ALIGN(4) { - *(.data) - *(.rodata .rodata.*) - } > dram -} - -INCLUDE "rom_32h2_beta_1.ld" diff --git a/tools/esptool_py/flasher_stub/ld/stub_32h2_beta_2.ld b/tools/esptool_py/flasher_stub/ld/stub_32h2_beta_2.ld deleted file mode 100644 index 903b497eec..0000000000 --- a/tools/esptool_py/flasher_stub/ld/stub_32h2_beta_2.ld +++ /dev/null @@ -1,26 +0,0 @@ -MEMORY { - iram : org = 0x40380000, len = 0x4000 - dram : org = 0x3FC84000, len = 0x18000 -} - -ENTRY(stub_main) - -SECTIONS { - .text : ALIGN(4) { - *(.literal) - *(.text .text.*) - } > iram - - .bss : ALIGN(4) { - _bss_start = ABSOLUTE(.); - *(.bss) - _bss_end = ABSOLUTE(.); - } > dram - - .data : ALIGN(4) { - *(.data) - *(.rodata .rodata.*) - } > dram -} - -INCLUDE "rom_32h2_beta_2.ld" diff --git a/tools/esptool_py/flasher_stub/ld/stub_32p4.ld b/tools/esptool_py/flasher_stub/ld/stub_32p4.ld deleted file mode 100644 index bf7e46a4e1..0000000000 --- a/tools/esptool_py/flasher_stub/ld/stub_32p4.ld +++ /dev/null @@ -1,26 +0,0 @@ -MEMORY { - iram : org = 0x4FF10000, len = 0x4000 - dram : org = 0x4FF50000, len = 0x18000 -} - -ENTRY(stub_main) - -SECTIONS { - .text : ALIGN(4) { - *(.literal) - *(.text .text.*) - } > iram - - .bss : ALIGN(4) { - _bss_start = ABSOLUTE(.); - *(.bss) - _bss_end = ABSOLUTE(.); - } > dram - - .data : ALIGN(4) { - *(.data) - *(.rodata .rodata.*) - } > dram -} - -INCLUDE "rom_32p4.ld" diff --git a/tools/esptool_py/flasher_stub/ld/stub_32s2.ld b/tools/esptool_py/flasher_stub/ld/stub_32s2.ld deleted file mode 100644 index ccec2b79c7..0000000000 --- a/tools/esptool_py/flasher_stub/ld/stub_32s2.ld +++ /dev/null @@ -1,26 +0,0 @@ -MEMORY { - iram : org = 0x40028000, len = 0x18000 - dram : org = 0x3FFD0000, len = 0x28000 -} - -ENTRY(stub_main) - -SECTIONS { - .text : ALIGN(4) { - *(.literal) - *(.text .text.*) - } > iram - - .bss : ALIGN(4) { - _bss_start = ABSOLUTE(.); - *(.bss) - _bss_end = ABSOLUTE(.); - } > dram - - .data : ALIGN(4) { - *(.data) - *(.rodata .rodata.*) - } > dram -} - -INCLUDE "rom_32s2.ld" diff --git a/tools/esptool_py/flasher_stub/ld/stub_32s3.ld b/tools/esptool_py/flasher_stub/ld/stub_32s3.ld deleted file mode 100644 index 98cce22848..0000000000 --- a/tools/esptool_py/flasher_stub/ld/stub_32s3.ld +++ /dev/null @@ -1,26 +0,0 @@ -MEMORY { - iram : org = 0x40378000, len = 0x18000 - dram : org = 0x3FCA0000, len = 0x28000 -} - -ENTRY(stub_main) - -SECTIONS { - .text : ALIGN(4) { - *(.literal) - *(.text .text.*) - } > iram - - .bss : ALIGN(4) { - _bss_start = ABSOLUTE(.); - *(.bss) - _bss_end = ABSOLUTE(.); - } > dram - - .data : ALIGN(4) { - *(.data) - *(.rodata .rodata.*) - } > dram -} - -INCLUDE "rom_32s3.ld" diff --git a/tools/esptool_py/flasher_stub/ld/stub_32s3_beta_2.ld b/tools/esptool_py/flasher_stub/ld/stub_32s3_beta_2.ld deleted file mode 100644 index 5105e30d91..0000000000 --- a/tools/esptool_py/flasher_stub/ld/stub_32s3_beta_2.ld +++ /dev/null @@ -1,26 +0,0 @@ -MEMORY { - iram : org = 0x40378000, len = 0x18000 - dram : org = 0x3FCA0000, len = 0x28000 -} - -ENTRY(stub_main) - -SECTIONS { - .text : ALIGN(4) { - *(.literal) - *(.text .text.*) - } > iram - - .bss : ALIGN(4) { - _bss_start = ABSOLUTE(.); - *(.bss) - _bss_end = ABSOLUTE(.); - } > dram - - .data : ALIGN(4) { - *(.data) - *(.rodata .rodata.*) - } > dram -} - -INCLUDE "rom_32s3_beta_2.ld" diff --git a/tools/esptool_py/flasher_stub/ld/stub_8266.ld b/tools/esptool_py/flasher_stub/ld/stub_8266.ld deleted file mode 100644 index a42b9b25e2..0000000000 --- a/tools/esptool_py/flasher_stub/ld/stub_8266.ld +++ /dev/null @@ -1,32 +0,0 @@ -/* Note: stub is deliberately loaded close to the very top - of available RAM, to reduce change of colliding with anything - else... */ -MEMORY { - iram : org = 0x4010D000, len = 0x2100 - dram : org = 0x3FFE8100, len = 0x13f00 -} - -ENTRY(stub_main_8266) - -SECTIONS { - .text : ALIGN(4) { - *(.literal) - *(.text .text.*) - } > iram - - .bss : ALIGN(4) { - _bss_start = ABSOLUTE(.); - *(.bss) - _bss_end = ABSOLUTE(.); - } > dram - - .data : ALIGN(4) { - *(.data) - *(.rodata .rodata.*) - } > dram -} - -INCLUDE "rom_8266.ld" - -PROVIDE(SPIFlashModeConfig = 0x40004568); -PROVIDE(SPIParamCfg = 0x40004c2c); diff --git a/tools/esptool_py/flasher_stub/miniz.c b/tools/esptool_py/flasher_stub/miniz.c deleted file mode 100644 index 9ded4c75ab..0000000000 --- a/tools/esptool_py/flasher_stub/miniz.c +++ /dev/null @@ -1,7657 +0,0 @@ -/************************************************************************** - * - * Copyright 2013-2014 RAD Game Tools and Valve Software - * Copyright 2010-2014 Rich Geldreich and Tenacious Software LLC - * All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - **************************************************************************/ - -#include "miniz.h" - -typedef unsigned char mz_validate_uint16[sizeof(mz_uint16) == 2 ? 1 : -1]; -typedef unsigned char mz_validate_uint32[sizeof(mz_uint32) == 4 ? 1 : -1]; -typedef unsigned char mz_validate_uint64[sizeof(mz_uint64) == 8 ? 1 : -1]; - -#ifdef __cplusplus -extern "C" { -#endif - -/* ------------------- zlib-style API's */ - -mz_ulong mz_adler32(mz_ulong adler, const unsigned char *ptr, size_t buf_len) -{ - mz_uint32 i, s1 = (mz_uint32)(adler & 0xffff), s2 = (mz_uint32)(adler >> 16); - size_t block_len = buf_len % 5552; - if (!ptr) - return MZ_ADLER32_INIT; - while (buf_len) - { - for (i = 0; i + 7 < block_len; i += 8, ptr += 8) - { - s1 += ptr[0], s2 += s1; - s1 += ptr[1], s2 += s1; - s1 += ptr[2], s2 += s1; - s1 += ptr[3], s2 += s1; - s1 += ptr[4], s2 += s1; - s1 += ptr[5], s2 += s1; - s1 += ptr[6], s2 += s1; - s1 += ptr[7], s2 += s1; - } - for (; i < block_len; ++i) - s1 += *ptr++, s2 += s1; - s1 %= 65521U, s2 %= 65521U; - buf_len -= block_len; - block_len = 5552; - } - return (s2 << 16) + s1; -} - -/* Karl Malbrain's compact CRC-32. See "A compact CCITT crc16 and crc32 C implementation that balances processor cache usage against speed": http://www.geocities.com/malbrain/ */ -#if 0 - mz_ulong mz_crc32(mz_ulong crc, const mz_uint8 *ptr, size_t buf_len) - { - static const mz_uint32 s_crc32[16] = { 0, 0x1db71064, 0x3b6e20c8, 0x26d930ac, 0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c, - 0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c, 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c }; - mz_uint32 crcu32 = (mz_uint32)crc; - if (!ptr) - return MZ_CRC32_INIT; - crcu32 = ~crcu32; - while (buf_len--) - { - mz_uint8 b = *ptr++; - crcu32 = (crcu32 >> 4) ^ s_crc32[(crcu32 & 0xF) ^ (b & 0xF)]; - crcu32 = (crcu32 >> 4) ^ s_crc32[(crcu32 & 0xF) ^ (b >> 4)]; - } - return ~crcu32; - } -#else -/* Faster, but larger CPU cache footprint. - */ -mz_ulong mz_crc32(mz_ulong crc, const mz_uint8 *ptr, size_t buf_len) -{ - static const mz_uint32 s_crc_table[256] = - { - 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, - 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, - 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, - 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, - 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4, - 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C, - 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, 0x26D930AC, - 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, - 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, - 0xB6662D3D, 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, - 0x9FBFE4A5, 0xE8B8D433, 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, - 0x086D3D2D, 0x91646C97, 0xE6635C01, 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, - 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, - 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, 0x4DB26158, 0x3AB551CE, - 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, - 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, - 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, - 0xCE61E49F, 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, - 0xB7BD5C3B, 0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, - 0x9DD277AF, 0x04DB2615, 0x73DC1683, 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, - 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, 0xF00F9344, 0x8708A3D2, 0x1E01F268, - 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, - 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, - 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, - 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, - 0x4669BE79, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, - 0x220216B9, 0x5505262F, 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, - 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, - 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, - 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242, - 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, 0x88085AE6, - 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, - 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, - 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, - 0x47B2CF7F, 0x30B5FFE9, 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, - 0xCDD70693, 0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, - 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D - }; - - mz_uint32 crc32 = (mz_uint32)crc ^ 0xFFFFFFFF; - const mz_uint8 *pByte_buf = (const mz_uint8 *)ptr; - - while (buf_len >= 4) - { - crc32 = (crc32 >> 8) ^ s_crc_table[(crc32 ^ pByte_buf[0]) & 0xFF]; - crc32 = (crc32 >> 8) ^ s_crc_table[(crc32 ^ pByte_buf[1]) & 0xFF]; - crc32 = (crc32 >> 8) ^ s_crc_table[(crc32 ^ pByte_buf[2]) & 0xFF]; - crc32 = (crc32 >> 8) ^ s_crc_table[(crc32 ^ pByte_buf[3]) & 0xFF]; - pByte_buf += 4; - buf_len -= 4; - } - - while (buf_len) - { - crc32 = (crc32 >> 8) ^ s_crc_table[(crc32 ^ pByte_buf[0]) & 0xFF]; - ++pByte_buf; - --buf_len; - } - - return ~crc32; -} -#endif - -void mz_free(void *p) -{ - MZ_FREE(p); -} - -void *miniz_def_alloc_func(void *opaque, size_t items, size_t size) -{ - (void)opaque, (void)items, (void)size; - return MZ_MALLOC(items * size); -} -void miniz_def_free_func(void *opaque, void *address) -{ - (void)opaque, (void)address; - MZ_FREE(address); -} -void *miniz_def_realloc_func(void *opaque, void *address, size_t items, size_t size) -{ - (void)opaque, (void)address, (void)items, (void)size; - return MZ_REALLOC(address, items * size); -} - -const char *mz_version(void) -{ - return MZ_VERSION; -} - -#ifndef MINIZ_NO_ZLIB_APIS - -int mz_deflateInit(mz_streamp pStream, int level) -{ - return mz_deflateInit2(pStream, level, MZ_DEFLATED, MZ_DEFAULT_WINDOW_BITS, 9, MZ_DEFAULT_STRATEGY); -} - -int mz_deflateInit2(mz_streamp pStream, int level, int method, int window_bits, int mem_level, int strategy) -{ - tdefl_compressor *pComp; - mz_uint comp_flags = TDEFL_COMPUTE_ADLER32 | tdefl_create_comp_flags_from_zip_params(level, window_bits, strategy); - - if (!pStream) - return MZ_STREAM_ERROR; - if ((method != MZ_DEFLATED) || ((mem_level < 1) || (mem_level > 9)) || ((window_bits != MZ_DEFAULT_WINDOW_BITS) && (-window_bits != MZ_DEFAULT_WINDOW_BITS))) - return MZ_PARAM_ERROR; - - pStream->data_type = 0; - pStream->adler = MZ_ADLER32_INIT; - pStream->msg = NULL; - pStream->reserved = 0; - pStream->total_in = 0; - pStream->total_out = 0; - if (!pStream->zalloc) - pStream->zalloc = miniz_def_alloc_func; - if (!pStream->zfree) - pStream->zfree = miniz_def_free_func; - - pComp = (tdefl_compressor *)pStream->zalloc(pStream->opaque, 1, sizeof(tdefl_compressor)); - if (!pComp) - return MZ_MEM_ERROR; - - pStream->state = (struct mz_internal_state *)pComp; - - if (tdefl_init(pComp, NULL, NULL, comp_flags) != TDEFL_STATUS_OKAY) - { - mz_deflateEnd(pStream); - return MZ_PARAM_ERROR; - } - - return MZ_OK; -} - -int mz_deflateReset(mz_streamp pStream) -{ - if ((!pStream) || (!pStream->state) || (!pStream->zalloc) || (!pStream->zfree)) - return MZ_STREAM_ERROR; - pStream->total_in = pStream->total_out = 0; - tdefl_init((tdefl_compressor *)pStream->state, NULL, NULL, ((tdefl_compressor *)pStream->state)->m_flags); - return MZ_OK; -} - -int mz_deflate(mz_streamp pStream, int flush) -{ - size_t in_bytes, out_bytes; - mz_ulong orig_total_in, orig_total_out; - int mz_status = MZ_OK; - - if ((!pStream) || (!pStream->state) || (flush < 0) || (flush > MZ_FINISH) || (!pStream->next_out)) - return MZ_STREAM_ERROR; - if (!pStream->avail_out) - return MZ_BUF_ERROR; - - if (flush == MZ_PARTIAL_FLUSH) - flush = MZ_SYNC_FLUSH; - - if (((tdefl_compressor *)pStream->state)->m_prev_return_status == TDEFL_STATUS_DONE) - return (flush == MZ_FINISH) ? MZ_STREAM_END : MZ_BUF_ERROR; - - orig_total_in = pStream->total_in; - orig_total_out = pStream->total_out; - for (;;) - { - tdefl_status defl_status; - in_bytes = pStream->avail_in; - out_bytes = pStream->avail_out; - - defl_status = tdefl_compress((tdefl_compressor *)pStream->state, pStream->next_in, &in_bytes, pStream->next_out, &out_bytes, (tdefl_flush)flush); - pStream->next_in += (mz_uint)in_bytes; - pStream->avail_in -= (mz_uint)in_bytes; - pStream->total_in += (mz_uint)in_bytes; - pStream->adler = tdefl_get_adler32((tdefl_compressor *)pStream->state); - - pStream->next_out += (mz_uint)out_bytes; - pStream->avail_out -= (mz_uint)out_bytes; - pStream->total_out += (mz_uint)out_bytes; - - if (defl_status < 0) - { - mz_status = MZ_STREAM_ERROR; - break; - } - else if (defl_status == TDEFL_STATUS_DONE) - { - mz_status = MZ_STREAM_END; - break; - } - else if (!pStream->avail_out) - break; - else if ((!pStream->avail_in) && (flush != MZ_FINISH)) - { - if ((flush) || (pStream->total_in != orig_total_in) || (pStream->total_out != orig_total_out)) - break; - return MZ_BUF_ERROR; /* Can't make forward progress without some input. - */ - } - } - return mz_status; -} - -int mz_deflateEnd(mz_streamp pStream) -{ - if (!pStream) - return MZ_STREAM_ERROR; - if (pStream->state) - { - pStream->zfree(pStream->opaque, pStream->state); - pStream->state = NULL; - } - return MZ_OK; -} - -mz_ulong mz_deflateBound(mz_streamp pStream, mz_ulong source_len) -{ - (void)pStream; - /* This is really over conservative. (And lame, but it's actually pretty tricky to compute a true upper bound given the way tdefl's blocking works.) */ - return MZ_MAX(128 + (source_len * 110) / 100, 128 + source_len + ((source_len / (31 * 1024)) + 1) * 5); -} - -int mz_compress2(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len, int level) -{ - int status; - mz_stream stream; - memset(&stream, 0, sizeof(stream)); - - /* In case mz_ulong is 64-bits (argh I hate longs). */ - if ((source_len | *pDest_len) > 0xFFFFFFFFU) - return MZ_PARAM_ERROR; - - stream.next_in = pSource; - stream.avail_in = (mz_uint32)source_len; - stream.next_out = pDest; - stream.avail_out = (mz_uint32)*pDest_len; - - status = mz_deflateInit(&stream, level); - if (status != MZ_OK) - return status; - - status = mz_deflate(&stream, MZ_FINISH); - if (status != MZ_STREAM_END) - { - mz_deflateEnd(&stream); - return (status == MZ_OK) ? MZ_BUF_ERROR : status; - } - - *pDest_len = stream.total_out; - return mz_deflateEnd(&stream); -} - -int mz_compress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len) -{ - return mz_compress2(pDest, pDest_len, pSource, source_len, MZ_DEFAULT_COMPRESSION); -} - -mz_ulong mz_compressBound(mz_ulong source_len) -{ - return mz_deflateBound(NULL, source_len); -} - -typedef struct -{ - tinfl_decompressor m_decomp; - mz_uint m_dict_ofs, m_dict_avail, m_first_call, m_has_flushed; - int m_window_bits; - mz_uint8 m_dict[TINFL_LZ_DICT_SIZE]; - tinfl_status m_last_status; -} inflate_state; - -int mz_inflateInit2(mz_streamp pStream, int window_bits) -{ - inflate_state *pDecomp; - if (!pStream) - return MZ_STREAM_ERROR; - if ((window_bits != MZ_DEFAULT_WINDOW_BITS) && (-window_bits != MZ_DEFAULT_WINDOW_BITS)) - return MZ_PARAM_ERROR; - - pStream->data_type = 0; - pStream->adler = 0; - pStream->msg = NULL; - pStream->total_in = 0; - pStream->total_out = 0; - pStream->reserved = 0; - if (!pStream->zalloc) - pStream->zalloc = miniz_def_alloc_func; - if (!pStream->zfree) - pStream->zfree = miniz_def_free_func; - - pDecomp = (inflate_state *)pStream->zalloc(pStream->opaque, 1, sizeof(inflate_state)); - if (!pDecomp) - return MZ_MEM_ERROR; - - pStream->state = (struct mz_internal_state *)pDecomp; - - tinfl_init(&pDecomp->m_decomp); - pDecomp->m_dict_ofs = 0; - pDecomp->m_dict_avail = 0; - pDecomp->m_last_status = TINFL_STATUS_NEEDS_MORE_INPUT; - pDecomp->m_first_call = 1; - pDecomp->m_has_flushed = 0; - pDecomp->m_window_bits = window_bits; - - return MZ_OK; -} - -int mz_inflateInit(mz_streamp pStream) -{ - return mz_inflateInit2(pStream, MZ_DEFAULT_WINDOW_BITS); -} - -int mz_inflateReset(mz_streamp pStream) -{ - inflate_state *pDecomp; - if (!pStream) - return MZ_STREAM_ERROR; - - pStream->data_type = 0; - pStream->adler = 0; - pStream->msg = NULL; - pStream->total_in = 0; - pStream->total_out = 0; - pStream->reserved = 0; - - pDecomp = (inflate_state *)pStream->state; - - tinfl_init(&pDecomp->m_decomp); - pDecomp->m_dict_ofs = 0; - pDecomp->m_dict_avail = 0; - pDecomp->m_last_status = TINFL_STATUS_NEEDS_MORE_INPUT; - pDecomp->m_first_call = 1; - pDecomp->m_has_flushed = 0; - /* pDecomp->m_window_bits = window_bits */; - - return MZ_OK; -} - -int mz_inflate(mz_streamp pStream, int flush) -{ - inflate_state *pState; - mz_uint n, first_call, decomp_flags = TINFL_FLAG_COMPUTE_ADLER32; - size_t in_bytes, out_bytes, orig_avail_in; - tinfl_status status; - - if ((!pStream) || (!pStream->state)) - return MZ_STREAM_ERROR; - if (flush == MZ_PARTIAL_FLUSH) - flush = MZ_SYNC_FLUSH; - if ((flush) && (flush != MZ_SYNC_FLUSH) && (flush != MZ_FINISH)) - return MZ_STREAM_ERROR; - - pState = (inflate_state *)pStream->state; - if (pState->m_window_bits > 0) - decomp_flags |= TINFL_FLAG_PARSE_ZLIB_HEADER; - orig_avail_in = pStream->avail_in; - - first_call = pState->m_first_call; - pState->m_first_call = 0; - if (pState->m_last_status < 0) - return MZ_DATA_ERROR; - - if (pState->m_has_flushed && (flush != MZ_FINISH)) - return MZ_STREAM_ERROR; - pState->m_has_flushed |= (flush == MZ_FINISH); - - if ((flush == MZ_FINISH) && (first_call)) - { - /* MZ_FINISH on the first call implies that the input and output buffers are large enough to hold the entire compressed/decompressed file. */ - decomp_flags |= TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF; - in_bytes = pStream->avail_in; - out_bytes = pStream->avail_out; - status = tinfl_decompress(&pState->m_decomp, pStream->next_in, &in_bytes, pStream->next_out, pStream->next_out, &out_bytes, decomp_flags); - pState->m_last_status = status; - pStream->next_in += (mz_uint)in_bytes; - pStream->avail_in -= (mz_uint)in_bytes; - pStream->total_in += (mz_uint)in_bytes; - pStream->adler = tinfl_get_adler32(&pState->m_decomp); - pStream->next_out += (mz_uint)out_bytes; - pStream->avail_out -= (mz_uint)out_bytes; - pStream->total_out += (mz_uint)out_bytes; - - if (status < 0) - return MZ_DATA_ERROR; - else if (status != TINFL_STATUS_DONE) - { - pState->m_last_status = TINFL_STATUS_FAILED; - return MZ_BUF_ERROR; - } - return MZ_STREAM_END; - } - /* flush != MZ_FINISH then we must assume there's more input. */ - if (flush != MZ_FINISH) - decomp_flags |= TINFL_FLAG_HAS_MORE_INPUT; - - if (pState->m_dict_avail) - { - n = MZ_MIN(pState->m_dict_avail, pStream->avail_out); - memcpy(pStream->next_out, pState->m_dict + pState->m_dict_ofs, n); - pStream->next_out += n; - pStream->avail_out -= n; - pStream->total_out += n; - pState->m_dict_avail -= n; - pState->m_dict_ofs = (pState->m_dict_ofs + n) & (TINFL_LZ_DICT_SIZE - 1); - return ((pState->m_last_status == TINFL_STATUS_DONE) && (!pState->m_dict_avail)) ? MZ_STREAM_END : MZ_OK; - } - - for (;;) - { - in_bytes = pStream->avail_in; - out_bytes = TINFL_LZ_DICT_SIZE - pState->m_dict_ofs; - - status = tinfl_decompress(&pState->m_decomp, pStream->next_in, &in_bytes, pState->m_dict, pState->m_dict + pState->m_dict_ofs, &out_bytes, decomp_flags); - pState->m_last_status = status; - - pStream->next_in += (mz_uint)in_bytes; - pStream->avail_in -= (mz_uint)in_bytes; - pStream->total_in += (mz_uint)in_bytes; - pStream->adler = tinfl_get_adler32(&pState->m_decomp); - - pState->m_dict_avail = (mz_uint)out_bytes; - - n = MZ_MIN(pState->m_dict_avail, pStream->avail_out); - memcpy(pStream->next_out, pState->m_dict + pState->m_dict_ofs, n); - pStream->next_out += n; - pStream->avail_out -= n; - pStream->total_out += n; - pState->m_dict_avail -= n; - pState->m_dict_ofs = (pState->m_dict_ofs + n) & (TINFL_LZ_DICT_SIZE - 1); - - if (status < 0) - return MZ_DATA_ERROR; /* Stream is corrupted (there could be some uncompressed data left in the output dictionary - oh well). */ - else if ((status == TINFL_STATUS_NEEDS_MORE_INPUT) && (!orig_avail_in)) - return MZ_BUF_ERROR; /* Signal caller that we can't make forward progress without supplying more input or by setting flush to MZ_FINISH. */ - else if (flush == MZ_FINISH) - { - /* The output buffer MUST be large to hold the remaining uncompressed data when flush==MZ_FINISH. */ - if (status == TINFL_STATUS_DONE) - return pState->m_dict_avail ? MZ_BUF_ERROR : MZ_STREAM_END; - /* status here must be TINFL_STATUS_HAS_MORE_OUTPUT, which means there's at least 1 more byte on the way. If there's no more room left in the output buffer then something is wrong. */ - else if (!pStream->avail_out) - return MZ_BUF_ERROR; - } - else if ((status == TINFL_STATUS_DONE) || (!pStream->avail_in) || (!pStream->avail_out) || (pState->m_dict_avail)) - break; - } - - return ((status == TINFL_STATUS_DONE) && (!pState->m_dict_avail)) ? MZ_STREAM_END : MZ_OK; -} - -int mz_inflateEnd(mz_streamp pStream) -{ - if (!pStream) - return MZ_STREAM_ERROR; - if (pStream->state) - { - pStream->zfree(pStream->opaque, pStream->state); - pStream->state = NULL; - } - return MZ_OK; -} - -int mz_uncompress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len) -{ - mz_stream stream; - int status; - memset(&stream, 0, sizeof(stream)); - - /* In case mz_ulong is 64-bits (argh I hate longs). */ - if ((source_len | *pDest_len) > 0xFFFFFFFFU) - return MZ_PARAM_ERROR; - - stream.next_in = pSource; - stream.avail_in = (mz_uint32)source_len; - stream.next_out = pDest; - stream.avail_out = (mz_uint32)*pDest_len; - - status = mz_inflateInit(&stream); - if (status != MZ_OK) - return status; - - status = mz_inflate(&stream, MZ_FINISH); - if (status != MZ_STREAM_END) - { - mz_inflateEnd(&stream); - return ((status == MZ_BUF_ERROR) && (!stream.avail_in)) ? MZ_DATA_ERROR : status; - } - *pDest_len = stream.total_out; - - return mz_inflateEnd(&stream); -} - -const char *mz_error(int err) -{ - static struct - { - int m_err; - const char *m_pDesc; - } s_error_descs[] = - { - { MZ_OK, "" }, { MZ_STREAM_END, "stream end" }, { MZ_NEED_DICT, "need dictionary" }, { MZ_ERRNO, "file error" }, { MZ_STREAM_ERROR, "stream error" }, { MZ_DATA_ERROR, "data error" }, { MZ_MEM_ERROR, "out of memory" }, { MZ_BUF_ERROR, "buf error" }, { MZ_VERSION_ERROR, "version error" }, { MZ_PARAM_ERROR, "parameter error" } - }; - mz_uint i; - for (i = 0; i < sizeof(s_error_descs) / sizeof(s_error_descs[0]); ++i) - if (s_error_descs[i].m_err == err) - return s_error_descs[i].m_pDesc; - return NULL; -} - -#endif /*MINIZ_NO_ZLIB_APIS */ - -#ifdef __cplusplus -} -#endif - -/* - This is free and unencumbered software released into the public domain. - - Anyone is free to copy, modify, publish, use, compile, sell, or - distribute this software, either in source code form or as a compiled - binary, for any purpose, commercial or non-commercial, and by any - means. - - In jurisdictions that recognize copyright laws, the author or authors - of this software dedicate any and all copyright interest in the - software to the public domain. We make this dedication for the benefit - of the public at large and to the detriment of our heirs and - successors. We intend this dedication to be an overt act of - relinquishment in perpetuity of all present and future rights to this - software under copyright law. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR - OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - OTHER DEALINGS IN THE SOFTWARE. - - For more information, please refer to -*/ -/************************************************************************** - * - * Copyright 2013-2014 RAD Game Tools and Valve Software - * Copyright 2010-2014 Rich Geldreich and Tenacious Software LLC - * All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - **************************************************************************/ - - - - -#ifdef __cplusplus -extern "C" { -#endif - -/* ------------------- Low-level Compression (independent from all decompression API's) */ - -/* Purposely making these tables static for faster init and thread safety. */ -static const mz_uint16 s_tdefl_len_sym[256] = - { - 257, 258, 259, 260, 261, 262, 263, 264, 265, 265, 266, 266, 267, 267, 268, 268, 269, 269, 269, 269, 270, 270, 270, 270, 271, 271, 271, 271, 272, 272, 272, 272, - 273, 273, 273, 273, 273, 273, 273, 273, 274, 274, 274, 274, 274, 274, 274, 274, 275, 275, 275, 275, 275, 275, 275, 275, 276, 276, 276, 276, 276, 276, 276, 276, - 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, - 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, - 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, - 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, - 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, - 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 285 - }; - -static const mz_uint8 s_tdefl_len_extra[256] = - { - 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0 - }; - -static const mz_uint8 s_tdefl_small_dist_sym[512] = - { - 0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, - 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, - 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17 - }; - -static const mz_uint8 s_tdefl_small_dist_extra[512] = - { - 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, - 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, - 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 7, 7, 7, 7, 7 - }; - -static const mz_uint8 s_tdefl_large_dist_sym[128] = - { - 0, 0, 18, 19, 20, 20, 21, 21, 22, 22, 22, 22, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, - 28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29 - }; - -static const mz_uint8 s_tdefl_large_dist_extra[128] = - { - 0, 0, 8, 8, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, - 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13 - }; - -/* Radix sorts tdefl_sym_freq[] array by 16-bit key m_key. Returns ptr to sorted values. */ -typedef struct -{ - mz_uint16 m_key, m_sym_index; -} tdefl_sym_freq; -static tdefl_sym_freq *tdefl_radix_sort_syms(mz_uint num_syms, tdefl_sym_freq *pSyms0, tdefl_sym_freq *pSyms1) -{ - mz_uint32 total_passes = 2, pass_shift, pass, i, hist[256 * 2]; - tdefl_sym_freq *pCur_syms = pSyms0, *pNew_syms = pSyms1; - MZ_CLEAR_OBJ(hist); - for (i = 0; i < num_syms; i++) - { - mz_uint freq = pSyms0[i].m_key; - hist[freq & 0xFF]++; - hist[256 + ((freq >> 8) & 0xFF)]++; - } - while ((total_passes > 1) && (num_syms == hist[(total_passes - 1) * 256])) - total_passes--; - for (pass_shift = 0, pass = 0; pass < total_passes; pass++, pass_shift += 8) - { - const mz_uint32 *pHist = &hist[pass << 8]; - mz_uint offsets[256], cur_ofs = 0; - for (i = 0; i < 256; i++) - { - offsets[i] = cur_ofs; - cur_ofs += pHist[i]; - } - for (i = 0; i < num_syms; i++) - pNew_syms[offsets[(pCur_syms[i].m_key >> pass_shift) & 0xFF]++] = pCur_syms[i]; - { - tdefl_sym_freq *t = pCur_syms; - pCur_syms = pNew_syms; - pNew_syms = t; - } - } - return pCur_syms; -} - -/* tdefl_calculate_minimum_redundancy() originally written by: Alistair Moffat, alistair@cs.mu.oz.au, Jyrki Katajainen, jyrki@diku.dk, November 1996. */ -static void tdefl_calculate_minimum_redundancy(tdefl_sym_freq *A, int n) -{ - int root, leaf, next, avbl, used, dpth; - if (n == 0) - return; - else if (n == 1) - { - A[0].m_key = 1; - return; - } - A[0].m_key += A[1].m_key; - root = 0; - leaf = 2; - for (next = 1; next < n - 1; next++) - { - if (leaf >= n || A[root].m_key < A[leaf].m_key) - { - A[next].m_key = A[root].m_key; - A[root++].m_key = (mz_uint16)next; - } - else - A[next].m_key = A[leaf++].m_key; - if (leaf >= n || (root < next && A[root].m_key < A[leaf].m_key)) - { - A[next].m_key = (mz_uint16)(A[next].m_key + A[root].m_key); - A[root++].m_key = (mz_uint16)next; - } - else - A[next].m_key = (mz_uint16)(A[next].m_key + A[leaf++].m_key); - } - A[n - 2].m_key = 0; - for (next = n - 3; next >= 0; next--) - A[next].m_key = A[A[next].m_key].m_key + 1; - avbl = 1; - used = dpth = 0; - root = n - 2; - next = n - 1; - while (avbl > 0) - { - while (root >= 0 && (int)A[root].m_key == dpth) - { - used++; - root--; - } - while (avbl > used) - { - A[next--].m_key = (mz_uint16)(dpth); - avbl--; - } - avbl = 2 * used; - dpth++; - used = 0; - } -} - -/* Limits canonical Huffman code table's max code size. */ -enum -{ - TDEFL_MAX_SUPPORTED_HUFF_CODESIZE = 32 -}; -static void tdefl_huffman_enforce_max_code_size(int *pNum_codes, int code_list_len, int max_code_size) -{ - int i; - mz_uint32 total = 0; - if (code_list_len <= 1) - return; - for (i = max_code_size + 1; i <= TDEFL_MAX_SUPPORTED_HUFF_CODESIZE; i++) - pNum_codes[max_code_size] += pNum_codes[i]; - for (i = max_code_size; i > 0; i--) - total += (((mz_uint32)pNum_codes[i]) << (max_code_size - i)); - while (total != (1UL << max_code_size)) - { - pNum_codes[max_code_size]--; - for (i = max_code_size - 1; i > 0; i--) - if (pNum_codes[i]) - { - pNum_codes[i]--; - pNum_codes[i + 1] += 2; - break; - } - total--; - } -} - -static void tdefl_optimize_huffman_table(tdefl_compressor *d, int table_num, int table_len, int code_size_limit, int static_table) -{ - int i, j, l, num_codes[1 + TDEFL_MAX_SUPPORTED_HUFF_CODESIZE]; - mz_uint next_code[TDEFL_MAX_SUPPORTED_HUFF_CODESIZE + 1]; - MZ_CLEAR_OBJ(num_codes); - if (static_table) - { - for (i = 0; i < table_len; i++) - num_codes[d->m_huff_code_sizes[table_num][i]]++; - } - else - { - tdefl_sym_freq syms0[TDEFL_MAX_HUFF_SYMBOLS], syms1[TDEFL_MAX_HUFF_SYMBOLS], *pSyms; - int num_used_syms = 0; - const mz_uint16 *pSym_count = &d->m_huff_count[table_num][0]; - for (i = 0; i < table_len; i++) - if (pSym_count[i]) - { - syms0[num_used_syms].m_key = (mz_uint16)pSym_count[i]; - syms0[num_used_syms++].m_sym_index = (mz_uint16)i; - } - - pSyms = tdefl_radix_sort_syms(num_used_syms, syms0, syms1); - tdefl_calculate_minimum_redundancy(pSyms, num_used_syms); - - for (i = 0; i < num_used_syms; i++) - num_codes[pSyms[i].m_key]++; - - tdefl_huffman_enforce_max_code_size(num_codes, num_used_syms, code_size_limit); - - MZ_CLEAR_OBJ(d->m_huff_code_sizes[table_num]); - MZ_CLEAR_OBJ(d->m_huff_codes[table_num]); - for (i = 1, j = num_used_syms; i <= code_size_limit; i++) - for (l = num_codes[i]; l > 0; l--) - d->m_huff_code_sizes[table_num][pSyms[--j].m_sym_index] = (mz_uint8)(i); - } - - next_code[1] = 0; - for (j = 0, i = 2; i <= code_size_limit; i++) - next_code[i] = j = ((j + num_codes[i - 1]) << 1); - - for (i = 0; i < table_len; i++) - { - mz_uint rev_code = 0, code, code_size; - if ((code_size = d->m_huff_code_sizes[table_num][i]) == 0) - continue; - code = next_code[code_size]++; - for (l = code_size; l > 0; l--, code >>= 1) - rev_code = (rev_code << 1) | (code & 1); - d->m_huff_codes[table_num][i] = (mz_uint16)rev_code; - } -} - -#define TDEFL_PUT_BITS(b, l) \ - do \ - { \ - mz_uint bits = b; \ - mz_uint len = l; \ - MZ_ASSERT(bits <= ((1U << len) - 1U)); \ - d->m_bit_buffer |= (bits << d->m_bits_in); \ - d->m_bits_in += len; \ - while (d->m_bits_in >= 8) \ - { \ - if (d->m_pOutput_buf < d->m_pOutput_buf_end) \ - *d->m_pOutput_buf++ = (mz_uint8)(d->m_bit_buffer); \ - d->m_bit_buffer >>= 8; \ - d->m_bits_in -= 8; \ - } \ - } \ - MZ_MACRO_END - -#define TDEFL_RLE_PREV_CODE_SIZE() \ - { \ - if (rle_repeat_count) \ - { \ - if (rle_repeat_count < 3) \ - { \ - d->m_huff_count[2][prev_code_size] = (mz_uint16)(d->m_huff_count[2][prev_code_size] + rle_repeat_count); \ - while (rle_repeat_count--) \ - packed_code_sizes[num_packed_code_sizes++] = prev_code_size; \ - } \ - else \ - { \ - d->m_huff_count[2][16] = (mz_uint16)(d->m_huff_count[2][16] + 1); \ - packed_code_sizes[num_packed_code_sizes++] = 16; \ - packed_code_sizes[num_packed_code_sizes++] = (mz_uint8)(rle_repeat_count - 3); \ - } \ - rle_repeat_count = 0; \ - } \ - } - -#define TDEFL_RLE_ZERO_CODE_SIZE() \ - { \ - if (rle_z_count) \ - { \ - if (rle_z_count < 3) \ - { \ - d->m_huff_count[2][0] = (mz_uint16)(d->m_huff_count[2][0] + rle_z_count); \ - while (rle_z_count--) \ - packed_code_sizes[num_packed_code_sizes++] = 0; \ - } \ - else if (rle_z_count <= 10) \ - { \ - d->m_huff_count[2][17] = (mz_uint16)(d->m_huff_count[2][17] + 1); \ - packed_code_sizes[num_packed_code_sizes++] = 17; \ - packed_code_sizes[num_packed_code_sizes++] = (mz_uint8)(rle_z_count - 3); \ - } \ - else \ - { \ - d->m_huff_count[2][18] = (mz_uint16)(d->m_huff_count[2][18] + 1); \ - packed_code_sizes[num_packed_code_sizes++] = 18; \ - packed_code_sizes[num_packed_code_sizes++] = (mz_uint8)(rle_z_count - 11); \ - } \ - rle_z_count = 0; \ - } \ - } - -static mz_uint8 s_tdefl_packed_code_size_syms_swizzle[] = { 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 }; - -static void tdefl_start_dynamic_block(tdefl_compressor *d) -{ - int num_lit_codes, num_dist_codes, num_bit_lengths; - mz_uint i, total_code_sizes_to_pack, num_packed_code_sizes, rle_z_count, rle_repeat_count, packed_code_sizes_index; - mz_uint8 code_sizes_to_pack[TDEFL_MAX_HUFF_SYMBOLS_0 + TDEFL_MAX_HUFF_SYMBOLS_1], packed_code_sizes[TDEFL_MAX_HUFF_SYMBOLS_0 + TDEFL_MAX_HUFF_SYMBOLS_1], prev_code_size = 0xFF; - - d->m_huff_count[0][256] = 1; - - tdefl_optimize_huffman_table(d, 0, TDEFL_MAX_HUFF_SYMBOLS_0, 15, MZ_FALSE); - tdefl_optimize_huffman_table(d, 1, TDEFL_MAX_HUFF_SYMBOLS_1, 15, MZ_FALSE); - - for (num_lit_codes = 286; num_lit_codes > 257; num_lit_codes--) - if (d->m_huff_code_sizes[0][num_lit_codes - 1]) - break; - for (num_dist_codes = 30; num_dist_codes > 1; num_dist_codes--) - if (d->m_huff_code_sizes[1][num_dist_codes - 1]) - break; - - memcpy(code_sizes_to_pack, &d->m_huff_code_sizes[0][0], num_lit_codes); - memcpy(code_sizes_to_pack + num_lit_codes, &d->m_huff_code_sizes[1][0], num_dist_codes); - total_code_sizes_to_pack = num_lit_codes + num_dist_codes; - num_packed_code_sizes = 0; - rle_z_count = 0; - rle_repeat_count = 0; - - memset(&d->m_huff_count[2][0], 0, sizeof(d->m_huff_count[2][0]) * TDEFL_MAX_HUFF_SYMBOLS_2); - for (i = 0; i < total_code_sizes_to_pack; i++) - { - mz_uint8 code_size = code_sizes_to_pack[i]; - if (!code_size) - { - TDEFL_RLE_PREV_CODE_SIZE(); - if (++rle_z_count == 138) - { - TDEFL_RLE_ZERO_CODE_SIZE(); - } - } - else - { - TDEFL_RLE_ZERO_CODE_SIZE(); - if (code_size != prev_code_size) - { - TDEFL_RLE_PREV_CODE_SIZE(); - d->m_huff_count[2][code_size] = (mz_uint16)(d->m_huff_count[2][code_size] + 1); - packed_code_sizes[num_packed_code_sizes++] = code_size; - } - else if (++rle_repeat_count == 6) - { - TDEFL_RLE_PREV_CODE_SIZE(); - } - } - prev_code_size = code_size; - } - if (rle_repeat_count) - { - TDEFL_RLE_PREV_CODE_SIZE(); - } - else - { - TDEFL_RLE_ZERO_CODE_SIZE(); - } - - tdefl_optimize_huffman_table(d, 2, TDEFL_MAX_HUFF_SYMBOLS_2, 7, MZ_FALSE); - - TDEFL_PUT_BITS(2, 2); - - TDEFL_PUT_BITS(num_lit_codes - 257, 5); - TDEFL_PUT_BITS(num_dist_codes - 1, 5); - - for (num_bit_lengths = 18; num_bit_lengths >= 0; num_bit_lengths--) - if (d->m_huff_code_sizes[2][s_tdefl_packed_code_size_syms_swizzle[num_bit_lengths]]) - break; - num_bit_lengths = MZ_MAX(4, (num_bit_lengths + 1)); - TDEFL_PUT_BITS(num_bit_lengths - 4, 4); - for (i = 0; (int)i < num_bit_lengths; i++) - TDEFL_PUT_BITS(d->m_huff_code_sizes[2][s_tdefl_packed_code_size_syms_swizzle[i]], 3); - - for (packed_code_sizes_index = 0; packed_code_sizes_index < num_packed_code_sizes;) - { - mz_uint code = packed_code_sizes[packed_code_sizes_index++]; - MZ_ASSERT(code < TDEFL_MAX_HUFF_SYMBOLS_2); - TDEFL_PUT_BITS(d->m_huff_codes[2][code], d->m_huff_code_sizes[2][code]); - if (code >= 16) - TDEFL_PUT_BITS(packed_code_sizes[packed_code_sizes_index++], "\02\03\07"[code - 16]); - } -} - -static void tdefl_start_static_block(tdefl_compressor *d) -{ - mz_uint i; - mz_uint8 *p = &d->m_huff_code_sizes[0][0]; - - for (i = 0; i <= 143; ++i) - *p++ = 8; - for (; i <= 255; ++i) - *p++ = 9; - for (; i <= 279; ++i) - *p++ = 7; - for (; i <= 287; ++i) - *p++ = 8; - - memset(d->m_huff_code_sizes[1], 5, 32); - - tdefl_optimize_huffman_table(d, 0, 288, 15, MZ_TRUE); - tdefl_optimize_huffman_table(d, 1, 32, 15, MZ_TRUE); - - TDEFL_PUT_BITS(1, 2); -} - -static const mz_uint mz_bitmasks[17] = { 0x0000, 0x0001, 0x0003, 0x0007, 0x000F, 0x001F, 0x003F, 0x007F, 0x00FF, 0x01FF, 0x03FF, 0x07FF, 0x0FFF, 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF }; - -#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN && MINIZ_HAS_64BIT_REGISTERS -static mz_bool tdefl_compress_lz_codes(tdefl_compressor *d) -{ - mz_uint flags; - mz_uint8 *pLZ_codes; - mz_uint8 *pOutput_buf = d->m_pOutput_buf; - mz_uint8 *pLZ_code_buf_end = d->m_pLZ_code_buf; - mz_uint64 bit_buffer = d->m_bit_buffer; - mz_uint bits_in = d->m_bits_in; - -#define TDEFL_PUT_BITS_FAST(b, l) \ - { \ - bit_buffer |= (((mz_uint64)(b)) << bits_in); \ - bits_in += (l); \ - } - - flags = 1; - for (pLZ_codes = d->m_lz_code_buf; pLZ_codes < pLZ_code_buf_end; flags >>= 1) - { - if (flags == 1) - flags = *pLZ_codes++ | 0x100; - - if (flags & 1) - { - mz_uint s0, s1, n0, n1, sym, num_extra_bits; - mz_uint match_len = pLZ_codes[0], match_dist = *(const mz_uint16 *)(pLZ_codes + 1); - pLZ_codes += 3; - - MZ_ASSERT(d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]); - TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][s_tdefl_len_sym[match_len]], d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]); - TDEFL_PUT_BITS_FAST(match_len & mz_bitmasks[s_tdefl_len_extra[match_len]], s_tdefl_len_extra[match_len]); - - /* This sequence coaxes MSVC into using cmov's vs. jmp's. */ - s0 = s_tdefl_small_dist_sym[match_dist & 511]; - n0 = s_tdefl_small_dist_extra[match_dist & 511]; - s1 = s_tdefl_large_dist_sym[match_dist >> 8]; - n1 = s_tdefl_large_dist_extra[match_dist >> 8]; - sym = (match_dist < 512) ? s0 : s1; - num_extra_bits = (match_dist < 512) ? n0 : n1; - - MZ_ASSERT(d->m_huff_code_sizes[1][sym]); - TDEFL_PUT_BITS_FAST(d->m_huff_codes[1][sym], d->m_huff_code_sizes[1][sym]); - TDEFL_PUT_BITS_FAST(match_dist & mz_bitmasks[num_extra_bits], num_extra_bits); - } - else - { - mz_uint lit = *pLZ_codes++; - MZ_ASSERT(d->m_huff_code_sizes[0][lit]); - TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][lit], d->m_huff_code_sizes[0][lit]); - - if (((flags & 2) == 0) && (pLZ_codes < pLZ_code_buf_end)) - { - flags >>= 1; - lit = *pLZ_codes++; - MZ_ASSERT(d->m_huff_code_sizes[0][lit]); - TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][lit], d->m_huff_code_sizes[0][lit]); - - if (((flags & 2) == 0) && (pLZ_codes < pLZ_code_buf_end)) - { - flags >>= 1; - lit = *pLZ_codes++; - MZ_ASSERT(d->m_huff_code_sizes[0][lit]); - TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][lit], d->m_huff_code_sizes[0][lit]); - } - } - } - - if (pOutput_buf >= d->m_pOutput_buf_end) - return MZ_FALSE; - - *(mz_uint64 *)pOutput_buf = bit_buffer; - pOutput_buf += (bits_in >> 3); - bit_buffer >>= (bits_in & ~7); - bits_in &= 7; - } - -#undef TDEFL_PUT_BITS_FAST - - d->m_pOutput_buf = pOutput_buf; - d->m_bits_in = 0; - d->m_bit_buffer = 0; - - while (bits_in) - { - mz_uint32 n = MZ_MIN(bits_in, 16); - TDEFL_PUT_BITS((mz_uint)bit_buffer & mz_bitmasks[n], n); - bit_buffer >>= n; - bits_in -= n; - } - - TDEFL_PUT_BITS(d->m_huff_codes[0][256], d->m_huff_code_sizes[0][256]); - - return (d->m_pOutput_buf < d->m_pOutput_buf_end); -} -#else -static mz_bool tdefl_compress_lz_codes(tdefl_compressor *d) -{ - mz_uint flags; - mz_uint8 *pLZ_codes; - - flags = 1; - for (pLZ_codes = d->m_lz_code_buf; pLZ_codes < d->m_pLZ_code_buf; flags >>= 1) - { - if (flags == 1) - flags = *pLZ_codes++ | 0x100; - if (flags & 1) - { - mz_uint sym, num_extra_bits; - mz_uint match_len = pLZ_codes[0], match_dist = (pLZ_codes[1] | (pLZ_codes[2] << 8)); - pLZ_codes += 3; - - MZ_ASSERT(d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]); - TDEFL_PUT_BITS(d->m_huff_codes[0][s_tdefl_len_sym[match_len]], d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]); - TDEFL_PUT_BITS(match_len & mz_bitmasks[s_tdefl_len_extra[match_len]], s_tdefl_len_extra[match_len]); - - if (match_dist < 512) - { - sym = s_tdefl_small_dist_sym[match_dist]; - num_extra_bits = s_tdefl_small_dist_extra[match_dist]; - } - else - { - sym = s_tdefl_large_dist_sym[match_dist >> 8]; - num_extra_bits = s_tdefl_large_dist_extra[match_dist >> 8]; - } - MZ_ASSERT(d->m_huff_code_sizes[1][sym]); - TDEFL_PUT_BITS(d->m_huff_codes[1][sym], d->m_huff_code_sizes[1][sym]); - TDEFL_PUT_BITS(match_dist & mz_bitmasks[num_extra_bits], num_extra_bits); - } - else - { - mz_uint lit = *pLZ_codes++; - MZ_ASSERT(d->m_huff_code_sizes[0][lit]); - TDEFL_PUT_BITS(d->m_huff_codes[0][lit], d->m_huff_code_sizes[0][lit]); - } - } - - TDEFL_PUT_BITS(d->m_huff_codes[0][256], d->m_huff_code_sizes[0][256]); - - return (d->m_pOutput_buf < d->m_pOutput_buf_end); -} -#endif /* MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN && MINIZ_HAS_64BIT_REGISTERS */ - -static mz_bool tdefl_compress_block(tdefl_compressor *d, mz_bool static_block) -{ - if (static_block) - tdefl_start_static_block(d); - else - tdefl_start_dynamic_block(d); - return tdefl_compress_lz_codes(d); -} - -static int tdefl_flush_block(tdefl_compressor *d, int flush) -{ - mz_uint saved_bit_buf, saved_bits_in; - mz_uint8 *pSaved_output_buf; - mz_bool comp_block_succeeded = MZ_FALSE; - int n, use_raw_block = ((d->m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS) != 0) && (d->m_lookahead_pos - d->m_lz_code_buf_dict_pos) <= d->m_dict_size; - mz_uint8 *pOutput_buf_start = ((d->m_pPut_buf_func == NULL) && ((*d->m_pOut_buf_size - d->m_out_buf_ofs) >= TDEFL_OUT_BUF_SIZE)) ? ((mz_uint8 *)d->m_pOut_buf + d->m_out_buf_ofs) : d->m_output_buf; - - d->m_pOutput_buf = pOutput_buf_start; - d->m_pOutput_buf_end = d->m_pOutput_buf + TDEFL_OUT_BUF_SIZE - 16; - - MZ_ASSERT(!d->m_output_flush_remaining); - d->m_output_flush_ofs = 0; - d->m_output_flush_remaining = 0; - - *d->m_pLZ_flags = (mz_uint8)(*d->m_pLZ_flags >> d->m_num_flags_left); - d->m_pLZ_code_buf -= (d->m_num_flags_left == 8); - - if ((d->m_flags & TDEFL_WRITE_ZLIB_HEADER) && (!d->m_block_index)) - { - TDEFL_PUT_BITS(0x78, 8); - TDEFL_PUT_BITS(0x01, 8); - } - - TDEFL_PUT_BITS(flush == TDEFL_FINISH, 1); - - pSaved_output_buf = d->m_pOutput_buf; - saved_bit_buf = d->m_bit_buffer; - saved_bits_in = d->m_bits_in; - - if (!use_raw_block) - comp_block_succeeded = tdefl_compress_block(d, (d->m_flags & TDEFL_FORCE_ALL_STATIC_BLOCKS) || (d->m_total_lz_bytes < 48)); - - /* If the block gets expanded, forget the current contents of the output buffer and send a raw block instead. */ - if (((use_raw_block) || ((d->m_total_lz_bytes) && ((d->m_pOutput_buf - pSaved_output_buf + 1U) >= d->m_total_lz_bytes))) && - ((d->m_lookahead_pos - d->m_lz_code_buf_dict_pos) <= d->m_dict_size)) - { - mz_uint i; - d->m_pOutput_buf = pSaved_output_buf; - d->m_bit_buffer = saved_bit_buf, d->m_bits_in = saved_bits_in; - TDEFL_PUT_BITS(0, 2); - if (d->m_bits_in) - { - TDEFL_PUT_BITS(0, 8 - d->m_bits_in); - } - for (i = 2; i; --i, d->m_total_lz_bytes ^= 0xFFFF) - { - TDEFL_PUT_BITS(d->m_total_lz_bytes & 0xFFFF, 16); - } - for (i = 0; i < d->m_total_lz_bytes; ++i) - { - TDEFL_PUT_BITS(d->m_dict[(d->m_lz_code_buf_dict_pos + i) & TDEFL_LZ_DICT_SIZE_MASK], 8); - } - } - /* Check for the extremely unlikely (if not impossible) case of the compressed block not fitting into the output buffer when using dynamic codes. */ - else if (!comp_block_succeeded) - { - d->m_pOutput_buf = pSaved_output_buf; - d->m_bit_buffer = saved_bit_buf, d->m_bits_in = saved_bits_in; - tdefl_compress_block(d, MZ_TRUE); - } - - if (flush) - { - if (flush == TDEFL_FINISH) - { - if (d->m_bits_in) - { - TDEFL_PUT_BITS(0, 8 - d->m_bits_in); - } - if (d->m_flags & TDEFL_WRITE_ZLIB_HEADER) - { - mz_uint i, a = d->m_adler32; - for (i = 0; i < 4; i++) - { - TDEFL_PUT_BITS((a >> 24) & 0xFF, 8); - a <<= 8; - } - } - } - else - { - mz_uint i, z = 0; - TDEFL_PUT_BITS(0, 3); - if (d->m_bits_in) - { - TDEFL_PUT_BITS(0, 8 - d->m_bits_in); - } - for (i = 2; i; --i, z ^= 0xFFFF) - { - TDEFL_PUT_BITS(z & 0xFFFF, 16); - } - } - } - - MZ_ASSERT(d->m_pOutput_buf < d->m_pOutput_buf_end); - - memset(&d->m_huff_count[0][0], 0, sizeof(d->m_huff_count[0][0]) * TDEFL_MAX_HUFF_SYMBOLS_0); - memset(&d->m_huff_count[1][0], 0, sizeof(d->m_huff_count[1][0]) * TDEFL_MAX_HUFF_SYMBOLS_1); - - d->m_pLZ_code_buf = d->m_lz_code_buf + 1; - d->m_pLZ_flags = d->m_lz_code_buf; - d->m_num_flags_left = 8; - d->m_lz_code_buf_dict_pos += d->m_total_lz_bytes; - d->m_total_lz_bytes = 0; - d->m_block_index++; - - if ((n = (int)(d->m_pOutput_buf - pOutput_buf_start)) != 0) - { - if (d->m_pPut_buf_func) - { - *d->m_pIn_buf_size = d->m_pSrc - (const mz_uint8 *)d->m_pIn_buf; - if (!(*d->m_pPut_buf_func)(d->m_output_buf, n, d->m_pPut_buf_user)) - return (d->m_prev_return_status = TDEFL_STATUS_PUT_BUF_FAILED); - } - else if (pOutput_buf_start == d->m_output_buf) - { - int bytes_to_copy = (int)MZ_MIN((size_t)n, (size_t)(*d->m_pOut_buf_size - d->m_out_buf_ofs)); - memcpy((mz_uint8 *)d->m_pOut_buf + d->m_out_buf_ofs, d->m_output_buf, bytes_to_copy); - d->m_out_buf_ofs += bytes_to_copy; - if ((n -= bytes_to_copy) != 0) - { - d->m_output_flush_ofs = bytes_to_copy; - d->m_output_flush_remaining = n; - } - } - else - { - d->m_out_buf_ofs += n; - } - } - - return d->m_output_flush_remaining; -} - -#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES -#ifdef MINIZ_UNALIGNED_USE_MEMCPY -static mz_uint16 TDEFL_READ_UNALIGNED_WORD(const mz_uint8* p) -{ - mz_uint16 ret; - memcpy(&ret, p, sizeof(mz_uint16)); - return ret; -} -static mz_uint16 TDEFL_READ_UNALIGNED_WORD2(const mz_uint16* p) -{ - mz_uint16 ret; - memcpy(&ret, p, sizeof(mz_uint16)); - return ret; -} -#else -#define TDEFL_READ_UNALIGNED_WORD(p) *(const mz_uint16 *)(p) -#define TDEFL_READ_UNALIGNED_WORD2(p) *(const mz_uint16 *)(p) -#endif -static MZ_FORCEINLINE void tdefl_find_match(tdefl_compressor *d, mz_uint lookahead_pos, mz_uint max_dist, mz_uint max_match_len, mz_uint *pMatch_dist, mz_uint *pMatch_len) -{ - mz_uint dist, pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK, match_len = *pMatch_len, probe_pos = pos, next_probe_pos, probe_len; - mz_uint num_probes_left = d->m_max_probes[match_len >= 32]; - const mz_uint16 *s = (const mz_uint16 *)(d->m_dict + pos), *p, *q; - mz_uint16 c01 = TDEFL_READ_UNALIGNED_WORD(&d->m_dict[pos + match_len - 1]), s01 = TDEFL_READ_UNALIGNED_WORD2(s); - MZ_ASSERT(max_match_len <= TDEFL_MAX_MATCH_LEN); - if (max_match_len <= match_len) - return; - for (;;) - { - for (;;) - { - if (--num_probes_left == 0) - return; -#define TDEFL_PROBE \ - next_probe_pos = d->m_next[probe_pos]; \ - if ((!next_probe_pos) || ((dist = (mz_uint16)(lookahead_pos - next_probe_pos)) > max_dist)) \ - return; \ - probe_pos = next_probe_pos & TDEFL_LZ_DICT_SIZE_MASK; \ - if (TDEFL_READ_UNALIGNED_WORD(&d->m_dict[probe_pos + match_len - 1]) == c01) \ - break; - TDEFL_PROBE; - TDEFL_PROBE; - TDEFL_PROBE; - } - if (!dist) - break; - q = (const mz_uint16 *)(d->m_dict + probe_pos); - if (TDEFL_READ_UNALIGNED_WORD2(q) != s01) - continue; - p = s; - probe_len = 32; - do - { - } while ((TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) && (TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) && - (TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) && (TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) && (--probe_len > 0)); - if (!probe_len) - { - *pMatch_dist = dist; - *pMatch_len = MZ_MIN(max_match_len, (mz_uint)TDEFL_MAX_MATCH_LEN); - break; - } - else if ((probe_len = ((mz_uint)(p - s) * 2) + (mz_uint)(*(const mz_uint8 *)p == *(const mz_uint8 *)q)) > match_len) - { - *pMatch_dist = dist; - if ((*pMatch_len = match_len = MZ_MIN(max_match_len, probe_len)) == max_match_len) - break; - c01 = TDEFL_READ_UNALIGNED_WORD(&d->m_dict[pos + match_len - 1]); - } - } -} -#else -static MZ_FORCEINLINE void tdefl_find_match(tdefl_compressor *d, mz_uint lookahead_pos, mz_uint max_dist, mz_uint max_match_len, mz_uint *pMatch_dist, mz_uint *pMatch_len) -{ - mz_uint dist, pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK, match_len = *pMatch_len, probe_pos = pos, next_probe_pos, probe_len; - mz_uint num_probes_left = d->m_max_probes[match_len >= 32]; - const mz_uint8 *s = d->m_dict + pos, *p, *q; - mz_uint8 c0 = d->m_dict[pos + match_len], c1 = d->m_dict[pos + match_len - 1]; - MZ_ASSERT(max_match_len <= TDEFL_MAX_MATCH_LEN); - if (max_match_len <= match_len) - return; - for (;;) - { - for (;;) - { - if (--num_probes_left == 0) - return; -#define TDEFL_PROBE \ - next_probe_pos = d->m_next[probe_pos]; \ - if ((!next_probe_pos) || ((dist = (mz_uint16)(lookahead_pos - next_probe_pos)) > max_dist)) \ - return; \ - probe_pos = next_probe_pos & TDEFL_LZ_DICT_SIZE_MASK; \ - if ((d->m_dict[probe_pos + match_len] == c0) && (d->m_dict[probe_pos + match_len - 1] == c1)) \ - break; - TDEFL_PROBE; - TDEFL_PROBE; - TDEFL_PROBE; - } - if (!dist) - break; - p = s; - q = d->m_dict + probe_pos; - for (probe_len = 0; probe_len < max_match_len; probe_len++) - if (*p++ != *q++) - break; - if (probe_len > match_len) - { - *pMatch_dist = dist; - if ((*pMatch_len = match_len = probe_len) == max_match_len) - return; - c0 = d->m_dict[pos + match_len]; - c1 = d->m_dict[pos + match_len - 1]; - } - } -} -#endif /* #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES */ - -#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN -#ifdef MINIZ_UNALIGNED_USE_MEMCPY -static mz_uint32 TDEFL_READ_UNALIGNED_WORD32(const mz_uint8* p) -{ - mz_uint32 ret; - memcpy(&ret, p, sizeof(mz_uint32)); - return ret; -} -#else -#define TDEFL_READ_UNALIGNED_WORD32(p) *(const mz_uint32 *)(p) -#endif -static mz_bool tdefl_compress_fast(tdefl_compressor *d) -{ - /* Faster, minimally featured LZRW1-style match+parse loop with better register utilization. Intended for applications where raw throughput is valued more highly than ratio. */ - mz_uint lookahead_pos = d->m_lookahead_pos, lookahead_size = d->m_lookahead_size, dict_size = d->m_dict_size, total_lz_bytes = d->m_total_lz_bytes, num_flags_left = d->m_num_flags_left; - mz_uint8 *pLZ_code_buf = d->m_pLZ_code_buf, *pLZ_flags = d->m_pLZ_flags; - mz_uint cur_pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK; - - while ((d->m_src_buf_left) || ((d->m_flush) && (lookahead_size))) - { - const mz_uint TDEFL_COMP_FAST_LOOKAHEAD_SIZE = 4096; - mz_uint dst_pos = (lookahead_pos + lookahead_size) & TDEFL_LZ_DICT_SIZE_MASK; - mz_uint num_bytes_to_process = (mz_uint)MZ_MIN(d->m_src_buf_left, TDEFL_COMP_FAST_LOOKAHEAD_SIZE - lookahead_size); - d->m_src_buf_left -= num_bytes_to_process; - lookahead_size += num_bytes_to_process; - - while (num_bytes_to_process) - { - mz_uint32 n = MZ_MIN(TDEFL_LZ_DICT_SIZE - dst_pos, num_bytes_to_process); - memcpy(d->m_dict + dst_pos, d->m_pSrc, n); - if (dst_pos < (TDEFL_MAX_MATCH_LEN - 1)) - memcpy(d->m_dict + TDEFL_LZ_DICT_SIZE + dst_pos, d->m_pSrc, MZ_MIN(n, (TDEFL_MAX_MATCH_LEN - 1) - dst_pos)); - d->m_pSrc += n; - dst_pos = (dst_pos + n) & TDEFL_LZ_DICT_SIZE_MASK; - num_bytes_to_process -= n; - } - - dict_size = MZ_MIN(TDEFL_LZ_DICT_SIZE - lookahead_size, dict_size); - if ((!d->m_flush) && (lookahead_size < TDEFL_COMP_FAST_LOOKAHEAD_SIZE)) - break; - - while (lookahead_size >= 4) - { - mz_uint cur_match_dist, cur_match_len = 1; - mz_uint8 *pCur_dict = d->m_dict + cur_pos; - mz_uint first_trigram = TDEFL_READ_UNALIGNED_WORD32(pCur_dict) & 0xFFFFFF; - mz_uint hash = (first_trigram ^ (first_trigram >> (24 - (TDEFL_LZ_HASH_BITS - 8)))) & TDEFL_LEVEL1_HASH_SIZE_MASK; - mz_uint probe_pos = d->m_hash[hash]; - d->m_hash[hash] = (mz_uint16)lookahead_pos; - - if (((cur_match_dist = (mz_uint16)(lookahead_pos - probe_pos)) <= dict_size) && ((TDEFL_READ_UNALIGNED_WORD32(d->m_dict + (probe_pos &= TDEFL_LZ_DICT_SIZE_MASK)) & 0xFFFFFF) == first_trigram)) - { - const mz_uint16 *p = (const mz_uint16 *)pCur_dict; - const mz_uint16 *q = (const mz_uint16 *)(d->m_dict + probe_pos); - mz_uint32 probe_len = 32; - do - { - } while ((TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) && (TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) && - (TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) && (TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) && (--probe_len > 0)); - cur_match_len = ((mz_uint)(p - (const mz_uint16 *)pCur_dict) * 2) + (mz_uint)(*(const mz_uint8 *)p == *(const mz_uint8 *)q); - if (!probe_len) - cur_match_len = cur_match_dist ? TDEFL_MAX_MATCH_LEN : 0; - - if ((cur_match_len < TDEFL_MIN_MATCH_LEN) || ((cur_match_len == TDEFL_MIN_MATCH_LEN) && (cur_match_dist >= 8U * 1024U))) - { - cur_match_len = 1; - *pLZ_code_buf++ = (mz_uint8)first_trigram; - *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1); - d->m_huff_count[0][(mz_uint8)first_trigram]++; - } - else - { - mz_uint32 s0, s1; - cur_match_len = MZ_MIN(cur_match_len, lookahead_size); - - MZ_ASSERT((cur_match_len >= TDEFL_MIN_MATCH_LEN) && (cur_match_dist >= 1) && (cur_match_dist <= TDEFL_LZ_DICT_SIZE)); - - cur_match_dist--; - - pLZ_code_buf[0] = (mz_uint8)(cur_match_len - TDEFL_MIN_MATCH_LEN); -#ifdef MINIZ_UNALIGNED_USE_MEMCPY - memcpy(&pLZ_code_buf[1], &cur_match_dist, sizeof(cur_match_dist)); -#else - *(mz_uint16 *)(&pLZ_code_buf[1]) = (mz_uint16)cur_match_dist; -#endif - pLZ_code_buf += 3; - *pLZ_flags = (mz_uint8)((*pLZ_flags >> 1) | 0x80); - - s0 = s_tdefl_small_dist_sym[cur_match_dist & 511]; - s1 = s_tdefl_large_dist_sym[cur_match_dist >> 8]; - d->m_huff_count[1][(cur_match_dist < 512) ? s0 : s1]++; - - d->m_huff_count[0][s_tdefl_len_sym[cur_match_len - TDEFL_MIN_MATCH_LEN]]++; - } - } - else - { - *pLZ_code_buf++ = (mz_uint8)first_trigram; - *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1); - d->m_huff_count[0][(mz_uint8)first_trigram]++; - } - - if (--num_flags_left == 0) - { - num_flags_left = 8; - pLZ_flags = pLZ_code_buf++; - } - - total_lz_bytes += cur_match_len; - lookahead_pos += cur_match_len; - dict_size = MZ_MIN(dict_size + cur_match_len, (mz_uint)TDEFL_LZ_DICT_SIZE); - cur_pos = (cur_pos + cur_match_len) & TDEFL_LZ_DICT_SIZE_MASK; - MZ_ASSERT(lookahead_size >= cur_match_len); - lookahead_size -= cur_match_len; - - if (pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8]) - { - int n; - d->m_lookahead_pos = lookahead_pos; - d->m_lookahead_size = lookahead_size; - d->m_dict_size = dict_size; - d->m_total_lz_bytes = total_lz_bytes; - d->m_pLZ_code_buf = pLZ_code_buf; - d->m_pLZ_flags = pLZ_flags; - d->m_num_flags_left = num_flags_left; - if ((n = tdefl_flush_block(d, 0)) != 0) - return (n < 0) ? MZ_FALSE : MZ_TRUE; - total_lz_bytes = d->m_total_lz_bytes; - pLZ_code_buf = d->m_pLZ_code_buf; - pLZ_flags = d->m_pLZ_flags; - num_flags_left = d->m_num_flags_left; - } - } - - while (lookahead_size) - { - mz_uint8 lit = d->m_dict[cur_pos]; - - total_lz_bytes++; - *pLZ_code_buf++ = lit; - *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1); - if (--num_flags_left == 0) - { - num_flags_left = 8; - pLZ_flags = pLZ_code_buf++; - } - - d->m_huff_count[0][lit]++; - - lookahead_pos++; - dict_size = MZ_MIN(dict_size + 1, (mz_uint)TDEFL_LZ_DICT_SIZE); - cur_pos = (cur_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK; - lookahead_size--; - - if (pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8]) - { - int n; - d->m_lookahead_pos = lookahead_pos; - d->m_lookahead_size = lookahead_size; - d->m_dict_size = dict_size; - d->m_total_lz_bytes = total_lz_bytes; - d->m_pLZ_code_buf = pLZ_code_buf; - d->m_pLZ_flags = pLZ_flags; - d->m_num_flags_left = num_flags_left; - if ((n = tdefl_flush_block(d, 0)) != 0) - return (n < 0) ? MZ_FALSE : MZ_TRUE; - total_lz_bytes = d->m_total_lz_bytes; - pLZ_code_buf = d->m_pLZ_code_buf; - pLZ_flags = d->m_pLZ_flags; - num_flags_left = d->m_num_flags_left; - } - } - } - - d->m_lookahead_pos = lookahead_pos; - d->m_lookahead_size = lookahead_size; - d->m_dict_size = dict_size; - d->m_total_lz_bytes = total_lz_bytes; - d->m_pLZ_code_buf = pLZ_code_buf; - d->m_pLZ_flags = pLZ_flags; - d->m_num_flags_left = num_flags_left; - return MZ_TRUE; -} -#endif /* MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN */ - -static MZ_FORCEINLINE void tdefl_record_literal(tdefl_compressor *d, mz_uint8 lit) -{ - d->m_total_lz_bytes++; - *d->m_pLZ_code_buf++ = lit; - *d->m_pLZ_flags = (mz_uint8)(*d->m_pLZ_flags >> 1); - if (--d->m_num_flags_left == 0) - { - d->m_num_flags_left = 8; - d->m_pLZ_flags = d->m_pLZ_code_buf++; - } - d->m_huff_count[0][lit]++; -} - -static MZ_FORCEINLINE void tdefl_record_match(tdefl_compressor *d, mz_uint match_len, mz_uint match_dist) -{ - mz_uint32 s0, s1; - - MZ_ASSERT((match_len >= TDEFL_MIN_MATCH_LEN) && (match_dist >= 1) && (match_dist <= TDEFL_LZ_DICT_SIZE)); - - d->m_total_lz_bytes += match_len; - - d->m_pLZ_code_buf[0] = (mz_uint8)(match_len - TDEFL_MIN_MATCH_LEN); - - match_dist -= 1; - d->m_pLZ_code_buf[1] = (mz_uint8)(match_dist & 0xFF); - d->m_pLZ_code_buf[2] = (mz_uint8)(match_dist >> 8); - d->m_pLZ_code_buf += 3; - - *d->m_pLZ_flags = (mz_uint8)((*d->m_pLZ_flags >> 1) | 0x80); - if (--d->m_num_flags_left == 0) - { - d->m_num_flags_left = 8; - d->m_pLZ_flags = d->m_pLZ_code_buf++; - } - - s0 = s_tdefl_small_dist_sym[match_dist & 511]; - s1 = s_tdefl_large_dist_sym[(match_dist >> 8) & 127]; - d->m_huff_count[1][(match_dist < 512) ? s0 : s1]++; - - if (match_len >= TDEFL_MIN_MATCH_LEN) - d->m_huff_count[0][s_tdefl_len_sym[match_len - TDEFL_MIN_MATCH_LEN]]++; -} - -static mz_bool tdefl_compress_normal(tdefl_compressor *d) -{ - const mz_uint8 *pSrc = d->m_pSrc; - size_t src_buf_left = d->m_src_buf_left; - tdefl_flush flush = d->m_flush; - - while ((src_buf_left) || ((flush) && (d->m_lookahead_size))) - { - mz_uint len_to_move, cur_match_dist, cur_match_len, cur_pos; - /* Update dictionary and hash chains. Keeps the lookahead size equal to TDEFL_MAX_MATCH_LEN. */ - if ((d->m_lookahead_size + d->m_dict_size) >= (TDEFL_MIN_MATCH_LEN - 1)) - { - mz_uint dst_pos = (d->m_lookahead_pos + d->m_lookahead_size) & TDEFL_LZ_DICT_SIZE_MASK, ins_pos = d->m_lookahead_pos + d->m_lookahead_size - 2; - mz_uint hash = (d->m_dict[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] << TDEFL_LZ_HASH_SHIFT) ^ d->m_dict[(ins_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK]; - mz_uint num_bytes_to_process = (mz_uint)MZ_MIN(src_buf_left, TDEFL_MAX_MATCH_LEN - d->m_lookahead_size); - const mz_uint8 *pSrc_end = pSrc + num_bytes_to_process; - src_buf_left -= num_bytes_to_process; - d->m_lookahead_size += num_bytes_to_process; - while (pSrc != pSrc_end) - { - mz_uint8 c = *pSrc++; - d->m_dict[dst_pos] = c; - if (dst_pos < (TDEFL_MAX_MATCH_LEN - 1)) - d->m_dict[TDEFL_LZ_DICT_SIZE + dst_pos] = c; - hash = ((hash << TDEFL_LZ_HASH_SHIFT) ^ c) & (TDEFL_LZ_HASH_SIZE - 1); - d->m_next[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] = d->m_hash[hash]; - d->m_hash[hash] = (mz_uint16)(ins_pos); - dst_pos = (dst_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK; - ins_pos++; - } - } - else - { - while ((src_buf_left) && (d->m_lookahead_size < TDEFL_MAX_MATCH_LEN)) - { - mz_uint8 c = *pSrc++; - mz_uint dst_pos = (d->m_lookahead_pos + d->m_lookahead_size) & TDEFL_LZ_DICT_SIZE_MASK; - src_buf_left--; - d->m_dict[dst_pos] = c; - if (dst_pos < (TDEFL_MAX_MATCH_LEN - 1)) - d->m_dict[TDEFL_LZ_DICT_SIZE + dst_pos] = c; - if ((++d->m_lookahead_size + d->m_dict_size) >= TDEFL_MIN_MATCH_LEN) - { - mz_uint ins_pos = d->m_lookahead_pos + (d->m_lookahead_size - 1) - 2; - mz_uint hash = ((d->m_dict[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] << (TDEFL_LZ_HASH_SHIFT * 2)) ^ (d->m_dict[(ins_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK] << TDEFL_LZ_HASH_SHIFT) ^ c) & (TDEFL_LZ_HASH_SIZE - 1); - d->m_next[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] = d->m_hash[hash]; - d->m_hash[hash] = (mz_uint16)(ins_pos); - } - } - } - d->m_dict_size = MZ_MIN(TDEFL_LZ_DICT_SIZE - d->m_lookahead_size, d->m_dict_size); - if ((!flush) && (d->m_lookahead_size < TDEFL_MAX_MATCH_LEN)) - break; - - /* Simple lazy/greedy parsing state machine. */ - len_to_move = 1; - cur_match_dist = 0; - cur_match_len = d->m_saved_match_len ? d->m_saved_match_len : (TDEFL_MIN_MATCH_LEN - 1); - cur_pos = d->m_lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK; - if (d->m_flags & (TDEFL_RLE_MATCHES | TDEFL_FORCE_ALL_RAW_BLOCKS)) - { - if ((d->m_dict_size) && (!(d->m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS))) - { - mz_uint8 c = d->m_dict[(cur_pos - 1) & TDEFL_LZ_DICT_SIZE_MASK]; - cur_match_len = 0; - while (cur_match_len < d->m_lookahead_size) - { - if (d->m_dict[cur_pos + cur_match_len] != c) - break; - cur_match_len++; - } - if (cur_match_len < TDEFL_MIN_MATCH_LEN) - cur_match_len = 0; - else - cur_match_dist = 1; - } - } - else - { - tdefl_find_match(d, d->m_lookahead_pos, d->m_dict_size, d->m_lookahead_size, &cur_match_dist, &cur_match_len); - } - if (((cur_match_len == TDEFL_MIN_MATCH_LEN) && (cur_match_dist >= 8U * 1024U)) || (cur_pos == cur_match_dist) || ((d->m_flags & TDEFL_FILTER_MATCHES) && (cur_match_len <= 5))) - { - cur_match_dist = cur_match_len = 0; - } - if (d->m_saved_match_len) - { - if (cur_match_len > d->m_saved_match_len) - { - tdefl_record_literal(d, (mz_uint8)d->m_saved_lit); - if (cur_match_len >= 128) - { - tdefl_record_match(d, cur_match_len, cur_match_dist); - d->m_saved_match_len = 0; - len_to_move = cur_match_len; - } - else - { - d->m_saved_lit = d->m_dict[cur_pos]; - d->m_saved_match_dist = cur_match_dist; - d->m_saved_match_len = cur_match_len; - } - } - else - { - tdefl_record_match(d, d->m_saved_match_len, d->m_saved_match_dist); - len_to_move = d->m_saved_match_len - 1; - d->m_saved_match_len = 0; - } - } - else if (!cur_match_dist) - tdefl_record_literal(d, d->m_dict[MZ_MIN(cur_pos, sizeof(d->m_dict) - 1)]); - else if ((d->m_greedy_parsing) || (d->m_flags & TDEFL_RLE_MATCHES) || (cur_match_len >= 128)) - { - tdefl_record_match(d, cur_match_len, cur_match_dist); - len_to_move = cur_match_len; - } - else - { - d->m_saved_lit = d->m_dict[MZ_MIN(cur_pos, sizeof(d->m_dict) - 1)]; - d->m_saved_match_dist = cur_match_dist; - d->m_saved_match_len = cur_match_len; - } - /* Move the lookahead forward by len_to_move bytes. */ - d->m_lookahead_pos += len_to_move; - MZ_ASSERT(d->m_lookahead_size >= len_to_move); - d->m_lookahead_size -= len_to_move; - d->m_dict_size = MZ_MIN(d->m_dict_size + len_to_move, (mz_uint)TDEFL_LZ_DICT_SIZE); - /* Check if it's time to flush the current LZ codes to the internal output buffer. */ - if ((d->m_pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8]) || - ((d->m_total_lz_bytes > 31 * 1024) && (((((mz_uint)(d->m_pLZ_code_buf - d->m_lz_code_buf) * 115) >> 7) >= d->m_total_lz_bytes) || (d->m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS)))) - { - int n; - d->m_pSrc = pSrc; - d->m_src_buf_left = src_buf_left; - if ((n = tdefl_flush_block(d, 0)) != 0) - return (n < 0) ? MZ_FALSE : MZ_TRUE; - } - } - - d->m_pSrc = pSrc; - d->m_src_buf_left = src_buf_left; - return MZ_TRUE; -} - -static tdefl_status tdefl_flush_output_buffer(tdefl_compressor *d) -{ - if (d->m_pIn_buf_size) - { - *d->m_pIn_buf_size = d->m_pSrc - (const mz_uint8 *)d->m_pIn_buf; - } - - if (d->m_pOut_buf_size) - { - size_t n = MZ_MIN(*d->m_pOut_buf_size - d->m_out_buf_ofs, d->m_output_flush_remaining); - memcpy((mz_uint8 *)d->m_pOut_buf + d->m_out_buf_ofs, d->m_output_buf + d->m_output_flush_ofs, n); - d->m_output_flush_ofs += (mz_uint)n; - d->m_output_flush_remaining -= (mz_uint)n; - d->m_out_buf_ofs += n; - - *d->m_pOut_buf_size = d->m_out_buf_ofs; - } - - return (d->m_finished && !d->m_output_flush_remaining) ? TDEFL_STATUS_DONE : TDEFL_STATUS_OKAY; -} - -tdefl_status tdefl_compress(tdefl_compressor *d, const void *pIn_buf, size_t *pIn_buf_size, void *pOut_buf, size_t *pOut_buf_size, tdefl_flush flush) -{ - if (!d) - { - if (pIn_buf_size) - *pIn_buf_size = 0; - if (pOut_buf_size) - *pOut_buf_size = 0; - return TDEFL_STATUS_BAD_PARAM; - } - - d->m_pIn_buf = pIn_buf; - d->m_pIn_buf_size = pIn_buf_size; - d->m_pOut_buf = pOut_buf; - d->m_pOut_buf_size = pOut_buf_size; - d->m_pSrc = (const mz_uint8 *)(pIn_buf); - d->m_src_buf_left = pIn_buf_size ? *pIn_buf_size : 0; - d->m_out_buf_ofs = 0; - d->m_flush = flush; - - if (((d->m_pPut_buf_func != NULL) == ((pOut_buf != NULL) || (pOut_buf_size != NULL))) || (d->m_prev_return_status != TDEFL_STATUS_OKAY) || - (d->m_wants_to_finish && (flush != TDEFL_FINISH)) || (pIn_buf_size && *pIn_buf_size && !pIn_buf) || (pOut_buf_size && *pOut_buf_size && !pOut_buf)) - { - if (pIn_buf_size) - *pIn_buf_size = 0; - if (pOut_buf_size) - *pOut_buf_size = 0; - return (d->m_prev_return_status = TDEFL_STATUS_BAD_PARAM); - } - d->m_wants_to_finish |= (flush == TDEFL_FINISH); - - if ((d->m_output_flush_remaining) || (d->m_finished)) - return (d->m_prev_return_status = tdefl_flush_output_buffer(d)); - -#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN - if (((d->m_flags & TDEFL_MAX_PROBES_MASK) == 1) && - ((d->m_flags & TDEFL_GREEDY_PARSING_FLAG) != 0) && - ((d->m_flags & (TDEFL_FILTER_MATCHES | TDEFL_FORCE_ALL_RAW_BLOCKS | TDEFL_RLE_MATCHES)) == 0)) - { - if (!tdefl_compress_fast(d)) - return d->m_prev_return_status; - } - else -#endif /* #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN */ - { - if (!tdefl_compress_normal(d)) - return d->m_prev_return_status; - } - - if ((d->m_flags & (TDEFL_WRITE_ZLIB_HEADER | TDEFL_COMPUTE_ADLER32)) && (pIn_buf)) - d->m_adler32 = (mz_uint32)mz_adler32(d->m_adler32, (const mz_uint8 *)pIn_buf, d->m_pSrc - (const mz_uint8 *)pIn_buf); - - if ((flush) && (!d->m_lookahead_size) && (!d->m_src_buf_left) && (!d->m_output_flush_remaining)) - { - if (tdefl_flush_block(d, flush) < 0) - return d->m_prev_return_status; - d->m_finished = (flush == TDEFL_FINISH); - if (flush == TDEFL_FULL_FLUSH) - { - MZ_CLEAR_OBJ(d->m_hash); - MZ_CLEAR_OBJ(d->m_next); - d->m_dict_size = 0; - } - } - - return (d->m_prev_return_status = tdefl_flush_output_buffer(d)); -} - -tdefl_status tdefl_compress_buffer(tdefl_compressor *d, const void *pIn_buf, size_t in_buf_size, tdefl_flush flush) -{ - MZ_ASSERT(d->m_pPut_buf_func); - return tdefl_compress(d, pIn_buf, &in_buf_size, NULL, NULL, flush); -} - -tdefl_status tdefl_init(tdefl_compressor *d, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags) -{ - d->m_pPut_buf_func = pPut_buf_func; - d->m_pPut_buf_user = pPut_buf_user; - d->m_flags = (mz_uint)(flags); - d->m_max_probes[0] = 1 + ((flags & 0xFFF) + 2) / 3; - d->m_greedy_parsing = (flags & TDEFL_GREEDY_PARSING_FLAG) != 0; - d->m_max_probes[1] = 1 + (((flags & 0xFFF) >> 2) + 2) / 3; - if (!(flags & TDEFL_NONDETERMINISTIC_PARSING_FLAG)) - MZ_CLEAR_OBJ(d->m_hash); - d->m_lookahead_pos = d->m_lookahead_size = d->m_dict_size = d->m_total_lz_bytes = d->m_lz_code_buf_dict_pos = d->m_bits_in = 0; - d->m_output_flush_ofs = d->m_output_flush_remaining = d->m_finished = d->m_block_index = d->m_bit_buffer = d->m_wants_to_finish = 0; - d->m_pLZ_code_buf = d->m_lz_code_buf + 1; - d->m_pLZ_flags = d->m_lz_code_buf; - d->m_num_flags_left = 8; - d->m_pOutput_buf = d->m_output_buf; - d->m_pOutput_buf_end = d->m_output_buf; - d->m_prev_return_status = TDEFL_STATUS_OKAY; - d->m_saved_match_dist = d->m_saved_match_len = d->m_saved_lit = 0; - d->m_adler32 = 1; - d->m_pIn_buf = NULL; - d->m_pOut_buf = NULL; - d->m_pIn_buf_size = NULL; - d->m_pOut_buf_size = NULL; - d->m_flush = TDEFL_NO_FLUSH; - d->m_pSrc = NULL; - d->m_src_buf_left = 0; - d->m_out_buf_ofs = 0; - if (!(flags & TDEFL_NONDETERMINISTIC_PARSING_FLAG)) - MZ_CLEAR_OBJ(d->m_dict); - memset(&d->m_huff_count[0][0], 0, sizeof(d->m_huff_count[0][0]) * TDEFL_MAX_HUFF_SYMBOLS_0); - memset(&d->m_huff_count[1][0], 0, sizeof(d->m_huff_count[1][0]) * TDEFL_MAX_HUFF_SYMBOLS_1); - return TDEFL_STATUS_OKAY; -} - -tdefl_status tdefl_get_prev_return_status(tdefl_compressor *d) -{ - return d->m_prev_return_status; -} - -mz_uint32 tdefl_get_adler32(tdefl_compressor *d) -{ - return d->m_adler32; -} - -mz_bool tdefl_compress_mem_to_output(const void *pBuf, size_t buf_len, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags) -{ - tdefl_compressor *pComp; - mz_bool succeeded; - if (((buf_len) && (!pBuf)) || (!pPut_buf_func)) - return MZ_FALSE; - pComp = (tdefl_compressor *)MZ_MALLOC(sizeof(tdefl_compressor)); - if (!pComp) - return MZ_FALSE; - succeeded = (tdefl_init(pComp, pPut_buf_func, pPut_buf_user, flags) == TDEFL_STATUS_OKAY); - succeeded = succeeded && (tdefl_compress_buffer(pComp, pBuf, buf_len, TDEFL_FINISH) == TDEFL_STATUS_DONE); - MZ_FREE(pComp); - return succeeded; -} - -typedef struct -{ - size_t m_size, m_capacity; - mz_uint8 *m_pBuf; - mz_bool m_expandable; -} tdefl_output_buffer; - -static mz_bool tdefl_output_buffer_putter(const void *pBuf, int len, void *pUser) -{ - tdefl_output_buffer *p = (tdefl_output_buffer *)pUser; - size_t new_size = p->m_size + len; - if (new_size > p->m_capacity) - { - size_t new_capacity = p->m_capacity; - mz_uint8 *pNew_buf; - if (!p->m_expandable) - return MZ_FALSE; - do - { - new_capacity = MZ_MAX(128U, new_capacity << 1U); - } while (new_size > new_capacity); - pNew_buf = (mz_uint8 *)MZ_REALLOC(p->m_pBuf, new_capacity); - if (!pNew_buf) - return MZ_FALSE; - p->m_pBuf = pNew_buf; - p->m_capacity = new_capacity; - } - memcpy((mz_uint8 *)p->m_pBuf + p->m_size, pBuf, len); - p->m_size = new_size; - return MZ_TRUE; -} - -void *tdefl_compress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags) -{ - tdefl_output_buffer out_buf; - MZ_CLEAR_OBJ(out_buf); - if (!pOut_len) - return MZ_FALSE; - else - *pOut_len = 0; - out_buf.m_expandable = MZ_TRUE; - if (!tdefl_compress_mem_to_output(pSrc_buf, src_buf_len, tdefl_output_buffer_putter, &out_buf, flags)) - return NULL; - *pOut_len = out_buf.m_size; - return out_buf.m_pBuf; -} - -size_t tdefl_compress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags) -{ - tdefl_output_buffer out_buf; - MZ_CLEAR_OBJ(out_buf); - if (!pOut_buf) - return 0; - out_buf.m_pBuf = (mz_uint8 *)pOut_buf; - out_buf.m_capacity = out_buf_len; - if (!tdefl_compress_mem_to_output(pSrc_buf, src_buf_len, tdefl_output_buffer_putter, &out_buf, flags)) - return 0; - return out_buf.m_size; -} - -static const mz_uint s_tdefl_num_probes[11] = { 0, 1, 6, 32, 16, 32, 128, 256, 512, 768, 1500 }; - -/* level may actually range from [0,10] (10 is a "hidden" max level, where we want a bit more compression and it's fine if throughput to fall off a cliff on some files). */ -mz_uint tdefl_create_comp_flags_from_zip_params(int level, int window_bits, int strategy) -{ - mz_uint comp_flags = s_tdefl_num_probes[(level >= 0) ? MZ_MIN(10, level) : MZ_DEFAULT_LEVEL] | ((level <= 3) ? TDEFL_GREEDY_PARSING_FLAG : 0); - if (window_bits > 0) - comp_flags |= TDEFL_WRITE_ZLIB_HEADER; - - if (!level) - comp_flags |= TDEFL_FORCE_ALL_RAW_BLOCKS; - else if (strategy == MZ_FILTERED) - comp_flags |= TDEFL_FILTER_MATCHES; - else if (strategy == MZ_HUFFMAN_ONLY) - comp_flags &= ~TDEFL_MAX_PROBES_MASK; - else if (strategy == MZ_FIXED) - comp_flags |= TDEFL_FORCE_ALL_STATIC_BLOCKS; - else if (strategy == MZ_RLE) - comp_flags |= TDEFL_RLE_MATCHES; - - return comp_flags; -} - -#ifdef _MSC_VER -#pragma warning(push) -#pragma warning(disable : 4204) /* nonstandard extension used : non-constant aggregate initializer (also supported by GNU C and C99, so no big deal) */ -#endif - -/* Simple PNG writer function by Alex Evans, 2011. Released into the public domain: https://gist.github.com/908299, more context at - http://altdevblogaday.org/2011/04/06/a-smaller-jpg-encoder/. - This is actually a modification of Alex's original code so PNG files generated by this function pass pngcheck. */ -void *tdefl_write_image_to_png_file_in_memory_ex(const void *pImage, int w, int h, int num_chans, size_t *pLen_out, mz_uint level, mz_bool flip) -{ - /* Using a local copy of this array here in case MINIZ_NO_ZLIB_APIS was defined. */ - static const mz_uint s_tdefl_png_num_probes[11] = { 0, 1, 6, 32, 16, 32, 128, 256, 512, 768, 1500 }; - tdefl_compressor *pComp = (tdefl_compressor *)MZ_MALLOC(sizeof(tdefl_compressor)); - tdefl_output_buffer out_buf; - int i, bpl = w * num_chans, y, z; - mz_uint32 c; - *pLen_out = 0; - if (!pComp) - return NULL; - MZ_CLEAR_OBJ(out_buf); - out_buf.m_expandable = MZ_TRUE; - out_buf.m_capacity = 57 + MZ_MAX(64, (1 + bpl) * h); - if (NULL == (out_buf.m_pBuf = (mz_uint8 *)MZ_MALLOC(out_buf.m_capacity))) - { - MZ_FREE(pComp); - return NULL; - } - /* write dummy header */ - for (z = 41; z; --z) - tdefl_output_buffer_putter(&z, 1, &out_buf); - /* compress image data */ - tdefl_init(pComp, tdefl_output_buffer_putter, &out_buf, s_tdefl_png_num_probes[MZ_MIN(10, level)] | TDEFL_WRITE_ZLIB_HEADER); - for (y = 0; y < h; ++y) - { - tdefl_compress_buffer(pComp, &z, 1, TDEFL_NO_FLUSH); - tdefl_compress_buffer(pComp, (mz_uint8 *)pImage + (flip ? (h - 1 - y) : y) * bpl, bpl, TDEFL_NO_FLUSH); - } - if (tdefl_compress_buffer(pComp, NULL, 0, TDEFL_FINISH) != TDEFL_STATUS_DONE) - { - MZ_FREE(pComp); - MZ_FREE(out_buf.m_pBuf); - return NULL; - } - /* write real header */ - *pLen_out = out_buf.m_size - 41; - { - static const mz_uint8 chans[] = { 0x00, 0x00, 0x04, 0x02, 0x06 }; - mz_uint8 pnghdr[41] = { 0x89, 0x50, 0x4e, 0x47, 0x0d, - 0x0a, 0x1a, 0x0a, 0x00, 0x00, - 0x00, 0x0d, 0x49, 0x48, 0x44, - 0x52, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x08, - 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x49, 0x44, 0x41, - 0x54 }; - pnghdr[18] = (mz_uint8)(w >> 8); - pnghdr[19] = (mz_uint8)w; - pnghdr[22] = (mz_uint8)(h >> 8); - pnghdr[23] = (mz_uint8)h; - pnghdr[25] = chans[num_chans]; - pnghdr[33] = (mz_uint8)(*pLen_out >> 24); - pnghdr[34] = (mz_uint8)(*pLen_out >> 16); - pnghdr[35] = (mz_uint8)(*pLen_out >> 8); - pnghdr[36] = (mz_uint8)*pLen_out; - c = (mz_uint32)mz_crc32(MZ_CRC32_INIT, pnghdr + 12, 17); - for (i = 0; i < 4; ++i, c <<= 8) - ((mz_uint8 *)(pnghdr + 29))[i] = (mz_uint8)(c >> 24); - memcpy(out_buf.m_pBuf, pnghdr, 41); - } - /* write footer (IDAT CRC-32, followed by IEND chunk) */ - if (!tdefl_output_buffer_putter("\0\0\0\0\0\0\0\0\x49\x45\x4e\x44\xae\x42\x60\x82", 16, &out_buf)) - { - *pLen_out = 0; - MZ_FREE(pComp); - MZ_FREE(out_buf.m_pBuf); - return NULL; - } - c = (mz_uint32)mz_crc32(MZ_CRC32_INIT, out_buf.m_pBuf + 41 - 4, *pLen_out + 4); - for (i = 0; i < 4; ++i, c <<= 8) - (out_buf.m_pBuf + out_buf.m_size - 16)[i] = (mz_uint8)(c >> 24); - /* compute final size of file, grab compressed data buffer and return */ - *pLen_out += 57; - MZ_FREE(pComp); - return out_buf.m_pBuf; -} -void *tdefl_write_image_to_png_file_in_memory(const void *pImage, int w, int h, int num_chans, size_t *pLen_out) -{ - /* Level 6 corresponds to TDEFL_DEFAULT_MAX_PROBES or MZ_DEFAULT_LEVEL (but we can't depend on MZ_DEFAULT_LEVEL being available in case the zlib API's where #defined out) */ - return tdefl_write_image_to_png_file_in_memory_ex(pImage, w, h, num_chans, pLen_out, 6, MZ_FALSE); -} - -#ifndef MINIZ_NO_MALLOC -/* Allocate the tdefl_compressor and tinfl_decompressor structures in C so that */ -/* non-C language bindings to tdefL_ and tinfl_ API don't need to worry about */ -/* structure size and allocation mechanism. */ -tdefl_compressor *tdefl_compressor_alloc() -{ - return (tdefl_compressor *)MZ_MALLOC(sizeof(tdefl_compressor)); -} - -void tdefl_compressor_free(tdefl_compressor *pComp) -{ - MZ_FREE(pComp); -} -#endif - -#ifdef _MSC_VER -#pragma warning(pop) -#endif - -#ifdef __cplusplus -} -#endif -/************************************************************************** - * - * Copyright 2013-2014 RAD Game Tools and Valve Software - * Copyright 2010-2014 Rich Geldreich and Tenacious Software LLC - * All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - **************************************************************************/ - - - -#ifdef __cplusplus -extern "C" { -#endif - -/* ------------------- Low-level Decompression (completely independent from all compression API's) */ - -#define TINFL_MEMCPY(d, s, l) memcpy(d, s, l) -#define TINFL_MEMSET(p, c, l) memset(p, c, l) - -#define TINFL_CR_BEGIN \ - switch (r->m_state) \ - { \ - case 0: -#define TINFL_CR_RETURN(state_index, result) \ - do \ - { \ - status = result; \ - r->m_state = state_index; \ - goto common_exit; \ - case state_index:; \ - } \ - MZ_MACRO_END -#define TINFL_CR_RETURN_FOREVER(state_index, result) \ - do \ - { \ - for (;;) \ - { \ - TINFL_CR_RETURN(state_index, result); \ - } \ - } \ - MZ_MACRO_END -#define TINFL_CR_FINISH } - -#define TINFL_GET_BYTE(state_index, c) \ - do \ - { \ - while (pIn_buf_cur >= pIn_buf_end) \ - { \ - TINFL_CR_RETURN(state_index, (decomp_flags & TINFL_FLAG_HAS_MORE_INPUT) ? TINFL_STATUS_NEEDS_MORE_INPUT : TINFL_STATUS_FAILED_CANNOT_MAKE_PROGRESS); \ - } \ - c = *pIn_buf_cur++; \ - } \ - MZ_MACRO_END - -#define TINFL_NEED_BITS(state_index, n) \ - do \ - { \ - mz_uint c; \ - TINFL_GET_BYTE(state_index, c); \ - bit_buf |= (((tinfl_bit_buf_t)c) << num_bits); \ - num_bits += 8; \ - } while (num_bits < (mz_uint)(n)) -#define TINFL_SKIP_BITS(state_index, n) \ - do \ - { \ - if (num_bits < (mz_uint)(n)) \ - { \ - TINFL_NEED_BITS(state_index, n); \ - } \ - bit_buf >>= (n); \ - num_bits -= (n); \ - } \ - MZ_MACRO_END -#define TINFL_GET_BITS(state_index, b, n) \ - do \ - { \ - if (num_bits < (mz_uint)(n)) \ - { \ - TINFL_NEED_BITS(state_index, n); \ - } \ - b = bit_buf & ((1 << (n)) - 1); \ - bit_buf >>= (n); \ - num_bits -= (n); \ - } \ - MZ_MACRO_END - -/* TINFL_HUFF_BITBUF_FILL() is only used rarely, when the number of bytes remaining in the input buffer falls below 2. */ -/* It reads just enough bytes from the input stream that are needed to decode the next Huffman code (and absolutely no more). It works by trying to fully decode a */ -/* Huffman code by using whatever bits are currently present in the bit buffer. If this fails, it reads another byte, and tries again until it succeeds or until the */ -/* bit buffer contains >=15 bits (deflate's max. Huffman code size). */ -#define TINFL_HUFF_BITBUF_FILL(state_index, pHuff) \ - do \ - { \ - temp = (pHuff)->m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]; \ - if (temp >= 0) \ - { \ - code_len = temp >> 9; \ - if ((code_len) && (num_bits >= code_len)) \ - break; \ - } \ - else if (num_bits > TINFL_FAST_LOOKUP_BITS) \ - { \ - code_len = TINFL_FAST_LOOKUP_BITS; \ - do \ - { \ - temp = (pHuff)->m_tree[~temp + ((bit_buf >> code_len++) & 1)]; \ - } while ((temp < 0) && (num_bits >= (code_len + 1))); \ - if (temp >= 0) \ - break; \ - } \ - TINFL_GET_BYTE(state_index, c); \ - bit_buf |= (((tinfl_bit_buf_t)c) << num_bits); \ - num_bits += 8; \ - } while (num_bits < 15); - -/* TINFL_HUFF_DECODE() decodes the next Huffman coded symbol. It's more complex than you would initially expect because the zlib API expects the decompressor to never read */ -/* beyond the final byte of the deflate stream. (In other words, when this macro wants to read another byte from the input, it REALLY needs another byte in order to fully */ -/* decode the next Huffman code.) Handling this properly is particularly important on raw deflate (non-zlib) streams, which aren't followed by a byte aligned adler-32. */ -/* The slow path is only executed at the very end of the input buffer. */ -/* v1.16: The original macro handled the case at the very end of the passed-in input buffer, but we also need to handle the case where the user passes in 1+zillion bytes */ -/* following the deflate data and our non-conservative read-ahead path won't kick in here on this code. This is much trickier. */ -#define TINFL_HUFF_DECODE(state_index, sym, pHuff) \ - do \ - { \ - int temp; \ - mz_uint code_len, c; \ - if (num_bits < 15) \ - { \ - if ((pIn_buf_end - pIn_buf_cur) < 2) \ - { \ - TINFL_HUFF_BITBUF_FILL(state_index, pHuff); \ - } \ - else \ - { \ - bit_buf |= (((tinfl_bit_buf_t)pIn_buf_cur[0]) << num_bits) | (((tinfl_bit_buf_t)pIn_buf_cur[1]) << (num_bits + 8)); \ - pIn_buf_cur += 2; \ - num_bits += 16; \ - } \ - } \ - if ((temp = (pHuff)->m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0) \ - code_len = temp >> 9, temp &= 511; \ - else \ - { \ - code_len = TINFL_FAST_LOOKUP_BITS; \ - do \ - { \ - temp = (pHuff)->m_tree[~temp + ((bit_buf >> code_len++) & 1)]; \ - } while (temp < 0); \ - } \ - sym = temp; \ - bit_buf >>= code_len; \ - num_bits -= code_len; \ - } \ - MZ_MACRO_END - -tinfl_status tinfl_decompress(tinfl_decompressor *r, const mz_uint8 *pIn_buf_next, size_t *pIn_buf_size, mz_uint8 *pOut_buf_start, mz_uint8 *pOut_buf_next, size_t *pOut_buf_size, const mz_uint32 decomp_flags) -{ - static const int s_length_base[31] = { 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0 }; - static const int s_length_extra[31] = { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 0, 0 }; - static const int s_dist_base[32] = { 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577, 0, 0 }; - static const int s_dist_extra[32] = { 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13 }; - static const mz_uint8 s_length_dezigzag[19] = { 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 }; - static const int s_min_table_sizes[3] = { 257, 1, 4 }; - - tinfl_status status = TINFL_STATUS_FAILED; - mz_uint32 num_bits, dist, counter, num_extra; - tinfl_bit_buf_t bit_buf; - const mz_uint8 *pIn_buf_cur = pIn_buf_next, *const pIn_buf_end = pIn_buf_next + *pIn_buf_size; - mz_uint8 *pOut_buf_cur = pOut_buf_next, *const pOut_buf_end = pOut_buf_next + *pOut_buf_size; - size_t out_buf_size_mask = (decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF) ? (size_t)-1 : ((pOut_buf_next - pOut_buf_start) + *pOut_buf_size) - 1, dist_from_out_buf_start; - - /* Ensure the output buffer's size is a power of 2, unless the output buffer is large enough to hold the entire output file (in which case it doesn't matter). */ - if (((out_buf_size_mask + 1) & out_buf_size_mask) || (pOut_buf_next < pOut_buf_start)) - { - *pIn_buf_size = *pOut_buf_size = 0; - return TINFL_STATUS_BAD_PARAM; - } - - num_bits = r->m_num_bits; - bit_buf = r->m_bit_buf; - dist = r->m_dist; - counter = r->m_counter; - num_extra = r->m_num_extra; - dist_from_out_buf_start = r->m_dist_from_out_buf_start; - TINFL_CR_BEGIN - - bit_buf = num_bits = dist = counter = num_extra = r->m_zhdr0 = r->m_zhdr1 = 0; - r->m_z_adler32 = r->m_check_adler32 = 1; - if (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER) - { - TINFL_GET_BYTE(1, r->m_zhdr0); - TINFL_GET_BYTE(2, r->m_zhdr1); - counter = (((r->m_zhdr0 * 256 + r->m_zhdr1) % 31 != 0) || (r->m_zhdr1 & 32) || ((r->m_zhdr0 & 15) != 8)); - if (!(decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF)) - counter |= (((1U << (8U + (r->m_zhdr0 >> 4))) > 32768U) || ((out_buf_size_mask + 1) < (size_t)(1U << (8U + (r->m_zhdr0 >> 4))))); - if (counter) - { - TINFL_CR_RETURN_FOREVER(36, TINFL_STATUS_FAILED); - } - } - - do - { - TINFL_GET_BITS(3, r->m_final, 3); - r->m_type = r->m_final >> 1; - if (r->m_type == 0) - { - TINFL_SKIP_BITS(5, num_bits & 7); - for (counter = 0; counter < 4; ++counter) - { - if (num_bits) - TINFL_GET_BITS(6, r->m_raw_header[counter], 8); - else - TINFL_GET_BYTE(7, r->m_raw_header[counter]); - } - if ((counter = (r->m_raw_header[0] | (r->m_raw_header[1] << 8))) != (mz_uint)(0xFFFF ^ (r->m_raw_header[2] | (r->m_raw_header[3] << 8)))) - { - TINFL_CR_RETURN_FOREVER(39, TINFL_STATUS_FAILED); - } - while ((counter) && (num_bits)) - { - TINFL_GET_BITS(51, dist, 8); - while (pOut_buf_cur >= pOut_buf_end) - { - TINFL_CR_RETURN(52, TINFL_STATUS_HAS_MORE_OUTPUT); - } - *pOut_buf_cur++ = (mz_uint8)dist; - counter--; - } - while (counter) - { - size_t n; - while (pOut_buf_cur >= pOut_buf_end) - { - TINFL_CR_RETURN(9, TINFL_STATUS_HAS_MORE_OUTPUT); - } - while (pIn_buf_cur >= pIn_buf_end) - { - TINFL_CR_RETURN(38, (decomp_flags & TINFL_FLAG_HAS_MORE_INPUT) ? TINFL_STATUS_NEEDS_MORE_INPUT : TINFL_STATUS_FAILED_CANNOT_MAKE_PROGRESS); - } - n = MZ_MIN(MZ_MIN((size_t)(pOut_buf_end - pOut_buf_cur), (size_t)(pIn_buf_end - pIn_buf_cur)), counter); - TINFL_MEMCPY(pOut_buf_cur, pIn_buf_cur, n); - pIn_buf_cur += n; - pOut_buf_cur += n; - counter -= (mz_uint)n; - } - } - else if (r->m_type == 3) - { - TINFL_CR_RETURN_FOREVER(10, TINFL_STATUS_FAILED); - } - else - { - if (r->m_type == 1) - { - mz_uint8 *p = r->m_tables[0].m_code_size; - mz_uint i; - r->m_table_sizes[0] = 288; - r->m_table_sizes[1] = 32; - TINFL_MEMSET(r->m_tables[1].m_code_size, 5, 32); - for (i = 0; i <= 143; ++i) - *p++ = 8; - for (; i <= 255; ++i) - *p++ = 9; - for (; i <= 279; ++i) - *p++ = 7; - for (; i <= 287; ++i) - *p++ = 8; - } - else - { - for (counter = 0; counter < 3; counter++) - { - TINFL_GET_BITS(11, r->m_table_sizes[counter], "\05\05\04"[counter]); - r->m_table_sizes[counter] += s_min_table_sizes[counter]; - } - MZ_CLEAR_OBJ(r->m_tables[2].m_code_size); - for (counter = 0; counter < r->m_table_sizes[2]; counter++) - { - mz_uint s; - TINFL_GET_BITS(14, s, 3); - r->m_tables[2].m_code_size[s_length_dezigzag[counter]] = (mz_uint8)s; - } - r->m_table_sizes[2] = 19; - } - for (; (int)r->m_type >= 0; r->m_type--) - { - int tree_next, tree_cur; - tinfl_huff_table *pTable; - mz_uint i, j, used_syms, total, sym_index, next_code[17], total_syms[16]; - pTable = &r->m_tables[r->m_type]; - MZ_CLEAR_OBJ(total_syms); - MZ_CLEAR_OBJ(pTable->m_look_up); - MZ_CLEAR_OBJ(pTable->m_tree); - for (i = 0; i < r->m_table_sizes[r->m_type]; ++i) - total_syms[pTable->m_code_size[i]]++; - used_syms = 0, total = 0; - next_code[0] = next_code[1] = 0; - for (i = 1; i <= 15; ++i) - { - used_syms += total_syms[i]; - next_code[i + 1] = (total = ((total + total_syms[i]) << 1)); - } - if ((65536 != total) && (used_syms > 1)) - { - TINFL_CR_RETURN_FOREVER(35, TINFL_STATUS_FAILED); - } - for (tree_next = -1, sym_index = 0; sym_index < r->m_table_sizes[r->m_type]; ++sym_index) - { - mz_uint rev_code = 0, l, cur_code, code_size = pTable->m_code_size[sym_index]; - if (!code_size) - continue; - cur_code = next_code[code_size]++; - for (l = code_size; l > 0; l--, cur_code >>= 1) - rev_code = (rev_code << 1) | (cur_code & 1); - if (code_size <= TINFL_FAST_LOOKUP_BITS) - { - mz_int16 k = (mz_int16)((code_size << 9) | sym_index); - while (rev_code < TINFL_FAST_LOOKUP_SIZE) - { - pTable->m_look_up[rev_code] = k; - rev_code += (1 << code_size); - } - continue; - } - if (0 == (tree_cur = pTable->m_look_up[rev_code & (TINFL_FAST_LOOKUP_SIZE - 1)])) - { - pTable->m_look_up[rev_code & (TINFL_FAST_LOOKUP_SIZE - 1)] = (mz_int16)tree_next; - tree_cur = tree_next; - tree_next -= 2; - } - rev_code >>= (TINFL_FAST_LOOKUP_BITS - 1); - for (j = code_size; j > (TINFL_FAST_LOOKUP_BITS + 1); j--) - { - tree_cur -= ((rev_code >>= 1) & 1); - if (!pTable->m_tree[-tree_cur - 1]) - { - pTable->m_tree[-tree_cur - 1] = (mz_int16)tree_next; - tree_cur = tree_next; - tree_next -= 2; - } - else - tree_cur = pTable->m_tree[-tree_cur - 1]; - } - tree_cur -= ((rev_code >>= 1) & 1); - pTable->m_tree[-tree_cur - 1] = (mz_int16)sym_index; - } - if (r->m_type == 2) - { - for (counter = 0; counter < (r->m_table_sizes[0] + r->m_table_sizes[1]);) - { - mz_uint s; - TINFL_HUFF_DECODE(16, dist, &r->m_tables[2]); - if (dist < 16) - { - r->m_len_codes[counter++] = (mz_uint8)dist; - continue; - } - if ((dist == 16) && (!counter)) - { - TINFL_CR_RETURN_FOREVER(17, TINFL_STATUS_FAILED); - } - num_extra = "\02\03\07"[dist - 16]; - TINFL_GET_BITS(18, s, num_extra); - s += "\03\03\013"[dist - 16]; - TINFL_MEMSET(r->m_len_codes + counter, (dist == 16) ? r->m_len_codes[counter - 1] : 0, s); - counter += s; - } - if ((r->m_table_sizes[0] + r->m_table_sizes[1]) != counter) - { - TINFL_CR_RETURN_FOREVER(21, TINFL_STATUS_FAILED); - } - TINFL_MEMCPY(r->m_tables[0].m_code_size, r->m_len_codes, r->m_table_sizes[0]); - TINFL_MEMCPY(r->m_tables[1].m_code_size, r->m_len_codes + r->m_table_sizes[0], r->m_table_sizes[1]); - } - } - for (;;) - { - mz_uint8 *pSrc; - for (;;) - { - if (((pIn_buf_end - pIn_buf_cur) < 4) || ((pOut_buf_end - pOut_buf_cur) < 2)) - { - TINFL_HUFF_DECODE(23, counter, &r->m_tables[0]); - if (counter >= 256) - break; - while (pOut_buf_cur >= pOut_buf_end) - { - TINFL_CR_RETURN(24, TINFL_STATUS_HAS_MORE_OUTPUT); - } - *pOut_buf_cur++ = (mz_uint8)counter; - } - else - { - int sym2; - mz_uint code_len; -#if TINFL_USE_64BIT_BITBUF - if (num_bits < 30) - { - bit_buf |= (((tinfl_bit_buf_t)MZ_READ_LE32(pIn_buf_cur)) << num_bits); - pIn_buf_cur += 4; - num_bits += 32; - } -#else - if (num_bits < 15) - { - bit_buf |= (((tinfl_bit_buf_t)MZ_READ_LE16(pIn_buf_cur)) << num_bits); - pIn_buf_cur += 2; - num_bits += 16; - } -#endif - if ((sym2 = r->m_tables[0].m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0) - code_len = sym2 >> 9; - else - { - code_len = TINFL_FAST_LOOKUP_BITS; - do - { - sym2 = r->m_tables[0].m_tree[~sym2 + ((bit_buf >> code_len++) & 1)]; - } while (sym2 < 0); - } - counter = sym2; - bit_buf >>= code_len; - num_bits -= code_len; - if (counter & 256) - break; - -#if !TINFL_USE_64BIT_BITBUF - if (num_bits < 15) - { - bit_buf |= (((tinfl_bit_buf_t)MZ_READ_LE16(pIn_buf_cur)) << num_bits); - pIn_buf_cur += 2; - num_bits += 16; - } -#endif - if ((sym2 = r->m_tables[0].m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0) - code_len = sym2 >> 9; - else - { - code_len = TINFL_FAST_LOOKUP_BITS; - do - { - sym2 = r->m_tables[0].m_tree[~sym2 + ((bit_buf >> code_len++) & 1)]; - } while (sym2 < 0); - } - bit_buf >>= code_len; - num_bits -= code_len; - - pOut_buf_cur[0] = (mz_uint8)counter; - if (sym2 & 256) - { - pOut_buf_cur++; - counter = sym2; - break; - } - pOut_buf_cur[1] = (mz_uint8)sym2; - pOut_buf_cur += 2; - } - } - if ((counter &= 511) == 256) - break; - - num_extra = s_length_extra[counter - 257]; - counter = s_length_base[counter - 257]; - if (num_extra) - { - mz_uint extra_bits; - TINFL_GET_BITS(25, extra_bits, num_extra); - counter += extra_bits; - } - - TINFL_HUFF_DECODE(26, dist, &r->m_tables[1]); - num_extra = s_dist_extra[dist]; - dist = s_dist_base[dist]; - if (num_extra) - { - mz_uint extra_bits; - TINFL_GET_BITS(27, extra_bits, num_extra); - dist += extra_bits; - } - - dist_from_out_buf_start = pOut_buf_cur - pOut_buf_start; - if ((dist > dist_from_out_buf_start) && (decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF)) - { - TINFL_CR_RETURN_FOREVER(37, TINFL_STATUS_FAILED); - } - - pSrc = pOut_buf_start + ((dist_from_out_buf_start - dist) & out_buf_size_mask); - - if ((MZ_MAX(pOut_buf_cur, pSrc) + counter) > pOut_buf_end) - { - while (counter--) - { - while (pOut_buf_cur >= pOut_buf_end) - { - TINFL_CR_RETURN(53, TINFL_STATUS_HAS_MORE_OUTPUT); - } - *pOut_buf_cur++ = pOut_buf_start[(dist_from_out_buf_start++ - dist) & out_buf_size_mask]; - } - continue; - } -#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES - else if ((counter >= 9) && (counter <= dist)) - { - const mz_uint8 *pSrc_end = pSrc + (counter & ~7); - do - { -#ifdef MINIZ_UNALIGNED_USE_MEMCPY - memcpy(pOut_buf_cur, pSrc, sizeof(mz_uint32)*2); -#else - ((mz_uint32 *)pOut_buf_cur)[0] = ((const mz_uint32 *)pSrc)[0]; - ((mz_uint32 *)pOut_buf_cur)[1] = ((const mz_uint32 *)pSrc)[1]; -#endif - pOut_buf_cur += 8; - } while ((pSrc += 8) < pSrc_end); - if ((counter &= 7) < 3) - { - if (counter) - { - pOut_buf_cur[0] = pSrc[0]; - if (counter > 1) - pOut_buf_cur[1] = pSrc[1]; - pOut_buf_cur += counter; - } - continue; - } - } -#endif - while(counter>2) - { - pOut_buf_cur[0] = pSrc[0]; - pOut_buf_cur[1] = pSrc[1]; - pOut_buf_cur[2] = pSrc[2]; - pOut_buf_cur += 3; - pSrc += 3; - counter -= 3; - } - if (counter > 0) - { - pOut_buf_cur[0] = pSrc[0]; - if (counter > 1) - pOut_buf_cur[1] = pSrc[1]; - pOut_buf_cur += counter; - } - } - } - } while (!(r->m_final & 1)); - - /* Ensure byte alignment and put back any bytes from the bitbuf if we've looked ahead too far on gzip, or other Deflate streams followed by arbitrary data. */ - /* I'm being super conservative here. A number of simplifications can be made to the byte alignment part, and the Adler32 check shouldn't ever need to worry about reading from the bitbuf now. */ - TINFL_SKIP_BITS(32, num_bits & 7); - while ((pIn_buf_cur > pIn_buf_next) && (num_bits >= 8)) - { - --pIn_buf_cur; - num_bits -= 8; - } - bit_buf &= (tinfl_bit_buf_t)((((mz_uint64)1) << num_bits) - (mz_uint64)1); - MZ_ASSERT(!num_bits); /* if this assert fires then we've read beyond the end of non-deflate/zlib streams with following data (such as gzip streams). */ - - if (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER) - { - for (counter = 0; counter < 4; ++counter) - { - mz_uint s; - if (num_bits) - TINFL_GET_BITS(41, s, 8); - else - TINFL_GET_BYTE(42, s); - r->m_z_adler32 = (r->m_z_adler32 << 8) | s; - } - } - TINFL_CR_RETURN_FOREVER(34, TINFL_STATUS_DONE); - - TINFL_CR_FINISH - -common_exit: - /* As long as we aren't telling the caller that we NEED more input to make forward progress: */ - /* Put back any bytes from the bitbuf in case we've looked ahead too far on gzip, or other Deflate streams followed by arbitrary data. */ - /* We need to be very careful here to NOT push back any bytes we definitely know we need to make forward progress, though, or we'll lock the caller up into an inf loop. */ - if ((status != TINFL_STATUS_NEEDS_MORE_INPUT) && (status != TINFL_STATUS_FAILED_CANNOT_MAKE_PROGRESS)) - { - while ((pIn_buf_cur > pIn_buf_next) && (num_bits >= 8)) - { - --pIn_buf_cur; - num_bits -= 8; - } - } - r->m_num_bits = num_bits; - r->m_bit_buf = bit_buf & (tinfl_bit_buf_t)((((mz_uint64)1) << num_bits) - (mz_uint64)1); - r->m_dist = dist; - r->m_counter = counter; - r->m_num_extra = num_extra; - r->m_dist_from_out_buf_start = dist_from_out_buf_start; - *pIn_buf_size = pIn_buf_cur - pIn_buf_next; - *pOut_buf_size = pOut_buf_cur - pOut_buf_next; - if ((decomp_flags & (TINFL_FLAG_PARSE_ZLIB_HEADER | TINFL_FLAG_COMPUTE_ADLER32)) && (status >= 0)) - { - const mz_uint8 *ptr = pOut_buf_next; - size_t buf_len = *pOut_buf_size; - mz_uint32 i, s1 = r->m_check_adler32 & 0xffff, s2 = r->m_check_adler32 >> 16; - size_t block_len = buf_len % 5552; - while (buf_len) - { - for (i = 0; i + 7 < block_len; i += 8, ptr += 8) - { - s1 += ptr[0], s2 += s1; - s1 += ptr[1], s2 += s1; - s1 += ptr[2], s2 += s1; - s1 += ptr[3], s2 += s1; - s1 += ptr[4], s2 += s1; - s1 += ptr[5], s2 += s1; - s1 += ptr[6], s2 += s1; - s1 += ptr[7], s2 += s1; - } - for (; i < block_len; ++i) - s1 += *ptr++, s2 += s1; - s1 %= 65521U, s2 %= 65521U; - buf_len -= block_len; - block_len = 5552; - } - r->m_check_adler32 = (s2 << 16) + s1; - if ((status == TINFL_STATUS_DONE) && (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER) && (r->m_check_adler32 != r->m_z_adler32)) - status = TINFL_STATUS_ADLER32_MISMATCH; - } - return status; -} - -/* Higher level helper functions. */ -void *tinfl_decompress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags) -{ - tinfl_decompressor decomp; - void *pBuf = NULL, *pNew_buf; - size_t src_buf_ofs = 0, out_buf_capacity = 0; - *pOut_len = 0; - tinfl_init(&decomp); - for (;;) - { - size_t src_buf_size = src_buf_len - src_buf_ofs, dst_buf_size = out_buf_capacity - *pOut_len, new_out_buf_capacity; - tinfl_status status = tinfl_decompress(&decomp, (const mz_uint8 *)pSrc_buf + src_buf_ofs, &src_buf_size, (mz_uint8 *)pBuf, pBuf ? (mz_uint8 *)pBuf + *pOut_len : NULL, &dst_buf_size, - (flags & ~TINFL_FLAG_HAS_MORE_INPUT) | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF); - if ((status < 0) || (status == TINFL_STATUS_NEEDS_MORE_INPUT)) - { - MZ_FREE(pBuf); - *pOut_len = 0; - return NULL; - } - src_buf_ofs += src_buf_size; - *pOut_len += dst_buf_size; - if (status == TINFL_STATUS_DONE) - break; - new_out_buf_capacity = out_buf_capacity * 2; - if (new_out_buf_capacity < 128) - new_out_buf_capacity = 128; - pNew_buf = MZ_REALLOC(pBuf, new_out_buf_capacity); - if (!pNew_buf) - { - MZ_FREE(pBuf); - *pOut_len = 0; - return NULL; - } - pBuf = pNew_buf; - out_buf_capacity = new_out_buf_capacity; - } - return pBuf; -} - -size_t tinfl_decompress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags) -{ - tinfl_decompressor decomp; - tinfl_status status; - tinfl_init(&decomp); - status = tinfl_decompress(&decomp, (const mz_uint8 *)pSrc_buf, &src_buf_len, (mz_uint8 *)pOut_buf, (mz_uint8 *)pOut_buf, &out_buf_len, (flags & ~TINFL_FLAG_HAS_MORE_INPUT) | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF); - return (status != TINFL_STATUS_DONE) ? TINFL_DECOMPRESS_MEM_TO_MEM_FAILED : out_buf_len; -} - -int tinfl_decompress_mem_to_callback(const void *pIn_buf, size_t *pIn_buf_size, tinfl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags) -{ - int result = 0; - tinfl_decompressor decomp; - mz_uint8 *pDict = (mz_uint8 *)MZ_MALLOC(TINFL_LZ_DICT_SIZE); - size_t in_buf_ofs = 0, dict_ofs = 0; - if (!pDict) - return TINFL_STATUS_FAILED; - tinfl_init(&decomp); - for (;;) - { - size_t in_buf_size = *pIn_buf_size - in_buf_ofs, dst_buf_size = TINFL_LZ_DICT_SIZE - dict_ofs; - tinfl_status status = tinfl_decompress(&decomp, (const mz_uint8 *)pIn_buf + in_buf_ofs, &in_buf_size, pDict, pDict + dict_ofs, &dst_buf_size, - (flags & ~(TINFL_FLAG_HAS_MORE_INPUT | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF))); - in_buf_ofs += in_buf_size; - if ((dst_buf_size) && (!(*pPut_buf_func)(pDict + dict_ofs, (int)dst_buf_size, pPut_buf_user))) - break; - if (status != TINFL_STATUS_HAS_MORE_OUTPUT) - { - result = (status == TINFL_STATUS_DONE); - break; - } - dict_ofs = (dict_ofs + dst_buf_size) & (TINFL_LZ_DICT_SIZE - 1); - } - MZ_FREE(pDict); - *pIn_buf_size = in_buf_ofs; - return result; -} - -#ifndef MINIZ_NO_MALLOC -tinfl_decompressor *tinfl_decompressor_alloc() -{ - tinfl_decompressor *pDecomp = (tinfl_decompressor *)MZ_MALLOC(sizeof(tinfl_decompressor)); - if (pDecomp) - tinfl_init(pDecomp); - return pDecomp; -} - -void tinfl_decompressor_free(tinfl_decompressor *pDecomp) -{ - MZ_FREE(pDecomp); -} -#endif - -#ifdef __cplusplus -} -#endif -/************************************************************************** - * - * Copyright 2013-2014 RAD Game Tools and Valve Software - * Copyright 2010-2014 Rich Geldreich and Tenacious Software LLC - * Copyright 2016 Martin Raiber - * All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - **************************************************************************/ - - -#ifndef MINIZ_NO_ARCHIVE_APIS - -#ifdef __cplusplus -extern "C" { -#endif - -/* ------------------- .ZIP archive reading */ - -#ifdef MINIZ_NO_STDIO -#define MZ_FILE void * -#else -#include - -#if defined(_MSC_VER) || defined(__MINGW64__) -static FILE *mz_fopen(const char *pFilename, const char *pMode) -{ - FILE *pFile = NULL; - fopen_s(&pFile, pFilename, pMode); - return pFile; -} -static FILE *mz_freopen(const char *pPath, const char *pMode, FILE *pStream) -{ - FILE *pFile = NULL; - if (freopen_s(&pFile, pPath, pMode, pStream)) - return NULL; - return pFile; -} -#ifndef MINIZ_NO_TIME -#include -#endif -#define MZ_FOPEN mz_fopen -#define MZ_FCLOSE fclose -#define MZ_FREAD fread -#define MZ_FWRITE fwrite -#define MZ_FTELL64 _ftelli64 -#define MZ_FSEEK64 _fseeki64 -#define MZ_FILE_STAT_STRUCT _stat64 -#define MZ_FILE_STAT _stat64 -#define MZ_FFLUSH fflush -#define MZ_FREOPEN mz_freopen -#define MZ_DELETE_FILE remove -#elif defined(__MINGW32__) -#ifndef MINIZ_NO_TIME -#include -#endif -#define MZ_FOPEN(f, m) fopen(f, m) -#define MZ_FCLOSE fclose -#define MZ_FREAD fread -#define MZ_FWRITE fwrite -#define MZ_FTELL64 ftello64 -#define MZ_FSEEK64 fseeko64 -#define MZ_FILE_STAT_STRUCT _stat -#define MZ_FILE_STAT _stat -#define MZ_FFLUSH fflush -#define MZ_FREOPEN(f, m, s) freopen(f, m, s) -#define MZ_DELETE_FILE remove -#elif defined(__TINYC__) -#ifndef MINIZ_NO_TIME -#include -#endif -#define MZ_FOPEN(f, m) fopen(f, m) -#define MZ_FCLOSE fclose -#define MZ_FREAD fread -#define MZ_FWRITE fwrite -#define MZ_FTELL64 ftell -#define MZ_FSEEK64 fseek -#define MZ_FILE_STAT_STRUCT stat -#define MZ_FILE_STAT stat -#define MZ_FFLUSH fflush -#define MZ_FREOPEN(f, m, s) freopen(f, m, s) -#define MZ_DELETE_FILE remove -#elif defined(__GNUC__) && defined(_LARGEFILE64_SOURCE) -#ifndef MINIZ_NO_TIME -#include -#endif -#define MZ_FOPEN(f, m) fopen64(f, m) -#define MZ_FCLOSE fclose -#define MZ_FREAD fread -#define MZ_FWRITE fwrite -#define MZ_FTELL64 ftello64 -#define MZ_FSEEK64 fseeko64 -#define MZ_FILE_STAT_STRUCT stat64 -#define MZ_FILE_STAT stat64 -#define MZ_FFLUSH fflush -#define MZ_FREOPEN(p, m, s) freopen64(p, m, s) -#define MZ_DELETE_FILE remove -#elif defined(__APPLE__) -#ifndef MINIZ_NO_TIME -#include -#endif -#define MZ_FOPEN(f, m) fopen(f, m) -#define MZ_FCLOSE fclose -#define MZ_FREAD fread -#define MZ_FWRITE fwrite -#define MZ_FTELL64 ftello -#define MZ_FSEEK64 fseeko -#define MZ_FILE_STAT_STRUCT stat -#define MZ_FILE_STAT stat -#define MZ_FFLUSH fflush -#define MZ_FREOPEN(p, m, s) freopen(p, m, s) -#define MZ_DELETE_FILE remove - -#else -#pragma message("Using fopen, ftello, fseeko, stat() etc. path for file I/O - this path may not support large files.") -#ifndef MINIZ_NO_TIME -#include -#endif -#define MZ_FOPEN(f, m) fopen(f, m) -#define MZ_FCLOSE fclose -#define MZ_FREAD fread -#define MZ_FWRITE fwrite -#ifdef __STRICT_ANSI__ -#define MZ_FTELL64 ftell -#define MZ_FSEEK64 fseek -#else -#define MZ_FTELL64 ftello -#define MZ_FSEEK64 fseeko -#endif -#define MZ_FILE_STAT_STRUCT stat -#define MZ_FILE_STAT stat -#define MZ_FFLUSH fflush -#define MZ_FREOPEN(f, m, s) freopen(f, m, s) -#define MZ_DELETE_FILE remove -#endif /* #ifdef _MSC_VER */ -#endif /* #ifdef MINIZ_NO_STDIO */ - -#define MZ_TOLOWER(c) ((((c) >= 'A') && ((c) <= 'Z')) ? ((c) - 'A' + 'a') : (c)) - -/* Various ZIP archive enums. To completely avoid cross platform compiler alignment and platform endian issues, miniz.c doesn't use structs for any of this stuff. */ -enum -{ - /* ZIP archive identifiers and record sizes */ - MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG = 0x06054b50, - MZ_ZIP_CENTRAL_DIR_HEADER_SIG = 0x02014b50, - MZ_ZIP_LOCAL_DIR_HEADER_SIG = 0x04034b50, - MZ_ZIP_LOCAL_DIR_HEADER_SIZE = 30, - MZ_ZIP_CENTRAL_DIR_HEADER_SIZE = 46, - MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE = 22, - - /* ZIP64 archive identifier and record sizes */ - MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIG = 0x06064b50, - MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIG = 0x07064b50, - MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE = 56, - MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE = 20, - MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID = 0x0001, - MZ_ZIP_DATA_DESCRIPTOR_ID = 0x08074b50, - MZ_ZIP_DATA_DESCRIPTER_SIZE64 = 24, - MZ_ZIP_DATA_DESCRIPTER_SIZE32 = 16, - - /* Central directory header record offsets */ - MZ_ZIP_CDH_SIG_OFS = 0, - MZ_ZIP_CDH_VERSION_MADE_BY_OFS = 4, - MZ_ZIP_CDH_VERSION_NEEDED_OFS = 6, - MZ_ZIP_CDH_BIT_FLAG_OFS = 8, - MZ_ZIP_CDH_METHOD_OFS = 10, - MZ_ZIP_CDH_FILE_TIME_OFS = 12, - MZ_ZIP_CDH_FILE_DATE_OFS = 14, - MZ_ZIP_CDH_CRC32_OFS = 16, - MZ_ZIP_CDH_COMPRESSED_SIZE_OFS = 20, - MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS = 24, - MZ_ZIP_CDH_FILENAME_LEN_OFS = 28, - MZ_ZIP_CDH_EXTRA_LEN_OFS = 30, - MZ_ZIP_CDH_COMMENT_LEN_OFS = 32, - MZ_ZIP_CDH_DISK_START_OFS = 34, - MZ_ZIP_CDH_INTERNAL_ATTR_OFS = 36, - MZ_ZIP_CDH_EXTERNAL_ATTR_OFS = 38, - MZ_ZIP_CDH_LOCAL_HEADER_OFS = 42, - - /* Local directory header offsets */ - MZ_ZIP_LDH_SIG_OFS = 0, - MZ_ZIP_LDH_VERSION_NEEDED_OFS = 4, - MZ_ZIP_LDH_BIT_FLAG_OFS = 6, - MZ_ZIP_LDH_METHOD_OFS = 8, - MZ_ZIP_LDH_FILE_TIME_OFS = 10, - MZ_ZIP_LDH_FILE_DATE_OFS = 12, - MZ_ZIP_LDH_CRC32_OFS = 14, - MZ_ZIP_LDH_COMPRESSED_SIZE_OFS = 18, - MZ_ZIP_LDH_DECOMPRESSED_SIZE_OFS = 22, - MZ_ZIP_LDH_FILENAME_LEN_OFS = 26, - MZ_ZIP_LDH_EXTRA_LEN_OFS = 28, - MZ_ZIP_LDH_BIT_FLAG_HAS_LOCATOR = 1 << 3, - - /* End of central directory offsets */ - MZ_ZIP_ECDH_SIG_OFS = 0, - MZ_ZIP_ECDH_NUM_THIS_DISK_OFS = 4, - MZ_ZIP_ECDH_NUM_DISK_CDIR_OFS = 6, - MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS = 8, - MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS = 10, - MZ_ZIP_ECDH_CDIR_SIZE_OFS = 12, - MZ_ZIP_ECDH_CDIR_OFS_OFS = 16, - MZ_ZIP_ECDH_COMMENT_SIZE_OFS = 20, - - /* ZIP64 End of central directory locator offsets */ - MZ_ZIP64_ECDL_SIG_OFS = 0, /* 4 bytes */ - MZ_ZIP64_ECDL_NUM_DISK_CDIR_OFS = 4, /* 4 bytes */ - MZ_ZIP64_ECDL_REL_OFS_TO_ZIP64_ECDR_OFS = 8, /* 8 bytes */ - MZ_ZIP64_ECDL_TOTAL_NUMBER_OF_DISKS_OFS = 16, /* 4 bytes */ - - /* ZIP64 End of central directory header offsets */ - MZ_ZIP64_ECDH_SIG_OFS = 0, /* 4 bytes */ - MZ_ZIP64_ECDH_SIZE_OF_RECORD_OFS = 4, /* 8 bytes */ - MZ_ZIP64_ECDH_VERSION_MADE_BY_OFS = 12, /* 2 bytes */ - MZ_ZIP64_ECDH_VERSION_NEEDED_OFS = 14, /* 2 bytes */ - MZ_ZIP64_ECDH_NUM_THIS_DISK_OFS = 16, /* 4 bytes */ - MZ_ZIP64_ECDH_NUM_DISK_CDIR_OFS = 20, /* 4 bytes */ - MZ_ZIP64_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS = 24, /* 8 bytes */ - MZ_ZIP64_ECDH_CDIR_TOTAL_ENTRIES_OFS = 32, /* 8 bytes */ - MZ_ZIP64_ECDH_CDIR_SIZE_OFS = 40, /* 8 bytes */ - MZ_ZIP64_ECDH_CDIR_OFS_OFS = 48, /* 8 bytes */ - MZ_ZIP_VERSION_MADE_BY_DOS_FILESYSTEM_ID = 0, - MZ_ZIP_DOS_DIR_ATTRIBUTE_BITFLAG = 0x10, - MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED = 1, - MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_COMPRESSED_PATCH_FLAG = 32, - MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION = 64, - MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_LOCAL_DIR_IS_MASKED = 8192, - MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_UTF8 = 1 << 11 -}; - -typedef struct -{ - void *m_p; - size_t m_size, m_capacity; - mz_uint m_element_size; -} mz_zip_array; - -struct mz_zip_internal_state_tag -{ - mz_zip_array m_central_dir; - mz_zip_array m_central_dir_offsets; - mz_zip_array m_sorted_central_dir_offsets; - - /* The flags passed in when the archive is initially opened. */ - uint32_t m_init_flags; - - /* MZ_TRUE if the archive has a zip64 end of central directory headers, etc. */ - mz_bool m_zip64; - - /* MZ_TRUE if we found zip64 extended info in the central directory (m_zip64 will also be slammed to true too, even if we didn't find a zip64 end of central dir header, etc.) */ - mz_bool m_zip64_has_extended_info_fields; - - /* These fields are used by the file, FILE, memory, and memory/heap read/write helpers. */ - MZ_FILE *m_pFile; - mz_uint64 m_file_archive_start_ofs; - - void *m_pMem; - size_t m_mem_size; - size_t m_mem_capacity; -}; - -#define MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(array_ptr, element_size) (array_ptr)->m_element_size = element_size - -#if defined(DEBUG) || defined(_DEBUG) || defined(NDEBUG) -static MZ_FORCEINLINE mz_uint mz_zip_array_range_check(const mz_zip_array *pArray, mz_uint index) -{ - MZ_ASSERT(index < pArray->m_size); - return index; -} -#define MZ_ZIP_ARRAY_ELEMENT(array_ptr, element_type, index) ((element_type *)((array_ptr)->m_p))[mz_zip_array_range_check(array_ptr, index)] -#else -#define MZ_ZIP_ARRAY_ELEMENT(array_ptr, element_type, index) ((element_type *)((array_ptr)->m_p))[index] -#endif - -static MZ_FORCEINLINE void mz_zip_array_init(mz_zip_array *pArray, mz_uint32 element_size) -{ - memset(pArray, 0, sizeof(mz_zip_array)); - pArray->m_element_size = element_size; -} - -static MZ_FORCEINLINE void mz_zip_array_clear(mz_zip_archive *pZip, mz_zip_array *pArray) -{ - pZip->m_pFree(pZip->m_pAlloc_opaque, pArray->m_p); - memset(pArray, 0, sizeof(mz_zip_array)); -} - -static mz_bool mz_zip_array_ensure_capacity(mz_zip_archive *pZip, mz_zip_array *pArray, size_t min_new_capacity, mz_uint growing) -{ - void *pNew_p; - size_t new_capacity = min_new_capacity; - MZ_ASSERT(pArray->m_element_size); - if (pArray->m_capacity >= min_new_capacity) - return MZ_TRUE; - if (growing) - { - new_capacity = MZ_MAX(1, pArray->m_capacity); - while (new_capacity < min_new_capacity) - new_capacity *= 2; - } - if (NULL == (pNew_p = pZip->m_pRealloc(pZip->m_pAlloc_opaque, pArray->m_p, pArray->m_element_size, new_capacity))) - return MZ_FALSE; - pArray->m_p = pNew_p; - pArray->m_capacity = new_capacity; - return MZ_TRUE; -} - -static MZ_FORCEINLINE mz_bool mz_zip_array_reserve(mz_zip_archive *pZip, mz_zip_array *pArray, size_t new_capacity, mz_uint growing) -{ - if (new_capacity > pArray->m_capacity) - { - if (!mz_zip_array_ensure_capacity(pZip, pArray, new_capacity, growing)) - return MZ_FALSE; - } - return MZ_TRUE; -} - -static MZ_FORCEINLINE mz_bool mz_zip_array_resize(mz_zip_archive *pZip, mz_zip_array *pArray, size_t new_size, mz_uint growing) -{ - if (new_size > pArray->m_capacity) - { - if (!mz_zip_array_ensure_capacity(pZip, pArray, new_size, growing)) - return MZ_FALSE; - } - pArray->m_size = new_size; - return MZ_TRUE; -} - -static MZ_FORCEINLINE mz_bool mz_zip_array_ensure_room(mz_zip_archive *pZip, mz_zip_array *pArray, size_t n) -{ - return mz_zip_array_reserve(pZip, pArray, pArray->m_size + n, MZ_TRUE); -} - -static MZ_FORCEINLINE mz_bool mz_zip_array_push_back(mz_zip_archive *pZip, mz_zip_array *pArray, const void *pElements, size_t n) -{ - size_t orig_size = pArray->m_size; - if (!mz_zip_array_resize(pZip, pArray, orig_size + n, MZ_TRUE)) - return MZ_FALSE; - if (n > 0) - memcpy((mz_uint8 *)pArray->m_p + orig_size * pArray->m_element_size, pElements, n * pArray->m_element_size); - return MZ_TRUE; -} - -#ifndef MINIZ_NO_TIME -static MZ_TIME_T mz_zip_dos_to_time_t(int dos_time, int dos_date) -{ - struct tm tm; - memset(&tm, 0, sizeof(tm)); - tm.tm_isdst = -1; - tm.tm_year = ((dos_date >> 9) & 127) + 1980 - 1900; - tm.tm_mon = ((dos_date >> 5) & 15) - 1; - tm.tm_mday = dos_date & 31; - tm.tm_hour = (dos_time >> 11) & 31; - tm.tm_min = (dos_time >> 5) & 63; - tm.tm_sec = (dos_time << 1) & 62; - return mktime(&tm); -} - -#ifndef MINIZ_NO_ARCHIVE_WRITING_APIS -static void mz_zip_time_t_to_dos_time(MZ_TIME_T time, mz_uint16 *pDOS_time, mz_uint16 *pDOS_date) -{ -#ifdef _MSC_VER - struct tm tm_struct; - struct tm *tm = &tm_struct; - errno_t err = localtime_s(tm, &time); - if (err) - { - *pDOS_date = 0; - *pDOS_time = 0; - return; - } -#else - struct tm *tm = localtime(&time); -#endif /* #ifdef _MSC_VER */ - - *pDOS_time = (mz_uint16)(((tm->tm_hour) << 11) + ((tm->tm_min) << 5) + ((tm->tm_sec) >> 1)); - *pDOS_date = (mz_uint16)(((tm->tm_year + 1900 - 1980) << 9) + ((tm->tm_mon + 1) << 5) + tm->tm_mday); -} -#endif /* MINIZ_NO_ARCHIVE_WRITING_APIS */ - -#ifndef MINIZ_NO_STDIO -#ifndef MINIZ_NO_ARCHIVE_WRITING_APIS -static mz_bool mz_zip_get_file_modified_time(const char *pFilename, MZ_TIME_T *pTime) -{ - struct MZ_FILE_STAT_STRUCT file_stat; - - /* On Linux with x86 glibc, this call will fail on large files (I think >= 0x80000000 bytes) unless you compiled with _LARGEFILE64_SOURCE. Argh. */ - if (MZ_FILE_STAT(pFilename, &file_stat) != 0) - return MZ_FALSE; - - *pTime = file_stat.st_mtime; - - return MZ_TRUE; -} -#endif /* #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS*/ - -static mz_bool mz_zip_set_file_times(const char *pFilename, MZ_TIME_T access_time, MZ_TIME_T modified_time) -{ - struct utimbuf t; - - memset(&t, 0, sizeof(t)); - t.actime = access_time; - t.modtime = modified_time; - - return !utime(pFilename, &t); -} -#endif /* #ifndef MINIZ_NO_STDIO */ -#endif /* #ifndef MINIZ_NO_TIME */ - -static MZ_FORCEINLINE mz_bool mz_zip_set_error(mz_zip_archive *pZip, mz_zip_error err_num) -{ - if (pZip) - pZip->m_last_error = err_num; - return MZ_FALSE; -} - -static mz_bool mz_zip_reader_init_internal(mz_zip_archive *pZip, mz_uint flags) -{ - (void)flags; - if ((!pZip) || (pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_INVALID)) - return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - - if (!pZip->m_pAlloc) - pZip->m_pAlloc = miniz_def_alloc_func; - if (!pZip->m_pFree) - pZip->m_pFree = miniz_def_free_func; - if (!pZip->m_pRealloc) - pZip->m_pRealloc = miniz_def_realloc_func; - - pZip->m_archive_size = 0; - pZip->m_central_directory_file_ofs = 0; - pZip->m_total_files = 0; - pZip->m_last_error = MZ_ZIP_NO_ERROR; - - if (NULL == (pZip->m_pState = (mz_zip_internal_state *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(mz_zip_internal_state)))) - return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); - - memset(pZip->m_pState, 0, sizeof(mz_zip_internal_state)); - MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir, sizeof(mz_uint8)); - MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir_offsets, sizeof(mz_uint32)); - MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_sorted_central_dir_offsets, sizeof(mz_uint32)); - pZip->m_pState->m_init_flags = flags; - pZip->m_pState->m_zip64 = MZ_FALSE; - pZip->m_pState->m_zip64_has_extended_info_fields = MZ_FALSE; - - pZip->m_zip_mode = MZ_ZIP_MODE_READING; - - return MZ_TRUE; -} - -static MZ_FORCEINLINE mz_bool mz_zip_reader_filename_less(const mz_zip_array *pCentral_dir_array, const mz_zip_array *pCentral_dir_offsets, mz_uint l_index, mz_uint r_index) -{ - const mz_uint8 *pL = &MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_array, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32, l_index)), *pE; - const mz_uint8 *pR = &MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_array, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32, r_index)); - mz_uint l_len = MZ_READ_LE16(pL + MZ_ZIP_CDH_FILENAME_LEN_OFS), r_len = MZ_READ_LE16(pR + MZ_ZIP_CDH_FILENAME_LEN_OFS); - mz_uint8 l = 0, r = 0; - pL += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; - pR += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; - pE = pL + MZ_MIN(l_len, r_len); - while (pL < pE) - { - if ((l = MZ_TOLOWER(*pL)) != (r = MZ_TOLOWER(*pR))) - break; - pL++; - pR++; - } - return (pL == pE) ? (l_len < r_len) : (l < r); -} - -#define MZ_SWAP_UINT32(a, b) \ - do \ - { \ - mz_uint32 t = a; \ - a = b; \ - b = t; \ - } \ - MZ_MACRO_END - -/* Heap sort of lowercased filenames, used to help accelerate plain central directory searches by mz_zip_reader_locate_file(). (Could also use qsort(), but it could allocate memory.) */ -static void mz_zip_reader_sort_central_dir_offsets_by_filename(mz_zip_archive *pZip) -{ - mz_zip_internal_state *pState = pZip->m_pState; - const mz_zip_array *pCentral_dir_offsets = &pState->m_central_dir_offsets; - const mz_zip_array *pCentral_dir = &pState->m_central_dir; - mz_uint32 *pIndices; - mz_uint32 start, end; - const mz_uint32 size = pZip->m_total_files; - - if (size <= 1U) - return; - - pIndices = &MZ_ZIP_ARRAY_ELEMENT(&pState->m_sorted_central_dir_offsets, mz_uint32, 0); - - start = (size - 2U) >> 1U; - for (;;) - { - mz_uint64 child, root = start; - for (;;) - { - if ((child = (root << 1U) + 1U) >= size) - break; - child += (((child + 1U) < size) && (mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[child], pIndices[child + 1U]))); - if (!mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[root], pIndices[child])) - break; - MZ_SWAP_UINT32(pIndices[root], pIndices[child]); - root = child; - } - if (!start) - break; - start--; - } - - end = size - 1; - while (end > 0) - { - mz_uint64 child, root = 0; - MZ_SWAP_UINT32(pIndices[end], pIndices[0]); - for (;;) - { - if ((child = (root << 1U) + 1U) >= end) - break; - child += (((child + 1U) < end) && mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[child], pIndices[child + 1U])); - if (!mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[root], pIndices[child])) - break; - MZ_SWAP_UINT32(pIndices[root], pIndices[child]); - root = child; - } - end--; - } -} - -static mz_bool mz_zip_reader_locate_header_sig(mz_zip_archive *pZip, mz_uint32 record_sig, mz_uint32 record_size, mz_int64 *pOfs) -{ - mz_int64 cur_file_ofs; - mz_uint32 buf_u32[4096 / sizeof(mz_uint32)]; - mz_uint8 *pBuf = (mz_uint8 *)buf_u32; - - /* Basic sanity checks - reject files which are too small */ - if (pZip->m_archive_size < record_size) - return MZ_FALSE; - - /* Find the record by scanning the file from the end towards the beginning. */ - cur_file_ofs = MZ_MAX((mz_int64)pZip->m_archive_size - (mz_int64)sizeof(buf_u32), 0); - for (;;) - { - int i, n = (int)MZ_MIN(sizeof(buf_u32), pZip->m_archive_size - cur_file_ofs); - - if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, n) != (mz_uint)n) - return MZ_FALSE; - - for (i = n - 4; i >= 0; --i) - { - mz_uint s = MZ_READ_LE32(pBuf + i); - if (s == record_sig) - { - if ((pZip->m_archive_size - (cur_file_ofs + i)) >= record_size) - break; - } - } - - if (i >= 0) - { - cur_file_ofs += i; - break; - } - - /* Give up if we've searched the entire file, or we've gone back "too far" (~64kb) */ - if ((!cur_file_ofs) || ((pZip->m_archive_size - cur_file_ofs) >= (MZ_UINT16_MAX + record_size))) - return MZ_FALSE; - - cur_file_ofs = MZ_MAX(cur_file_ofs - (sizeof(buf_u32) - 3), 0); - } - - *pOfs = cur_file_ofs; - return MZ_TRUE; -} - -static mz_bool mz_zip_reader_read_central_dir(mz_zip_archive *pZip, mz_uint flags) -{ - mz_uint cdir_size = 0, cdir_entries_on_this_disk = 0, num_this_disk = 0, cdir_disk_index = 0; - mz_uint64 cdir_ofs = 0; - mz_int64 cur_file_ofs = 0; - const mz_uint8 *p; - - mz_uint32 buf_u32[4096 / sizeof(mz_uint32)]; - mz_uint8 *pBuf = (mz_uint8 *)buf_u32; - mz_bool sort_central_dir = ((flags & MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY) == 0); - mz_uint32 zip64_end_of_central_dir_locator_u32[(MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; - mz_uint8 *pZip64_locator = (mz_uint8 *)zip64_end_of_central_dir_locator_u32; - - mz_uint32 zip64_end_of_central_dir_header_u32[(MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; - mz_uint8 *pZip64_end_of_central_dir = (mz_uint8 *)zip64_end_of_central_dir_header_u32; - - mz_uint64 zip64_end_of_central_dir_ofs = 0; - - /* Basic sanity checks - reject files which are too small, and check the first 4 bytes of the file to make sure a local header is there. */ - if (pZip->m_archive_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) - return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE); - - if (!mz_zip_reader_locate_header_sig(pZip, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE, &cur_file_ofs)) - return mz_zip_set_error(pZip, MZ_ZIP_FAILED_FINDING_CENTRAL_DIR); - - /* Read and verify the end of central directory record. */ - if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) != MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) - return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); - - if (MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_SIG_OFS) != MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG) - return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE); - - if (cur_file_ofs >= (MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE + MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE)) - { - if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs - MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE, pZip64_locator, MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE) == MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE) - { - if (MZ_READ_LE32(pZip64_locator + MZ_ZIP64_ECDL_SIG_OFS) == MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIG) - { - zip64_end_of_central_dir_ofs = MZ_READ_LE64(pZip64_locator + MZ_ZIP64_ECDL_REL_OFS_TO_ZIP64_ECDR_OFS); - if (zip64_end_of_central_dir_ofs > (pZip->m_archive_size - MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE)) - return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE); - - if (pZip->m_pRead(pZip->m_pIO_opaque, zip64_end_of_central_dir_ofs, pZip64_end_of_central_dir, MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE) == MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE) - { - if (MZ_READ_LE32(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_SIG_OFS) == MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIG) - { - pZip->m_pState->m_zip64 = MZ_TRUE; - } - } - } - } - } - - pZip->m_total_files = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS); - cdir_entries_on_this_disk = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS); - num_this_disk = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_NUM_THIS_DISK_OFS); - cdir_disk_index = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_NUM_DISK_CDIR_OFS); - cdir_size = MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_CDIR_SIZE_OFS); - cdir_ofs = MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_CDIR_OFS_OFS); - - if (pZip->m_pState->m_zip64) - { - mz_uint32 zip64_total_num_of_disks = MZ_READ_LE32(pZip64_locator + MZ_ZIP64_ECDL_TOTAL_NUMBER_OF_DISKS_OFS); - mz_uint64 zip64_cdir_total_entries = MZ_READ_LE64(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_CDIR_TOTAL_ENTRIES_OFS); - mz_uint64 zip64_cdir_total_entries_on_this_disk = MZ_READ_LE64(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS); - mz_uint64 zip64_size_of_end_of_central_dir_record = MZ_READ_LE64(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_SIZE_OF_RECORD_OFS); - mz_uint64 zip64_size_of_central_directory = MZ_READ_LE64(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_CDIR_SIZE_OFS); - - if (zip64_size_of_end_of_central_dir_record < (MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE - 12)) - return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); - - if (zip64_total_num_of_disks != 1U) - return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_MULTIDISK); - - /* Check for miniz's practical limits */ - if (zip64_cdir_total_entries > MZ_UINT32_MAX) - return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); - - pZip->m_total_files = (mz_uint32)zip64_cdir_total_entries; - - if (zip64_cdir_total_entries_on_this_disk > MZ_UINT32_MAX) - return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); - - cdir_entries_on_this_disk = (mz_uint32)zip64_cdir_total_entries_on_this_disk; - - /* Check for miniz's current practical limits (sorry, this should be enough for millions of files) */ - if (zip64_size_of_central_directory > MZ_UINT32_MAX) - return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE); - - cdir_size = (mz_uint32)zip64_size_of_central_directory; - - num_this_disk = MZ_READ_LE32(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_NUM_THIS_DISK_OFS); - - cdir_disk_index = MZ_READ_LE32(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_NUM_DISK_CDIR_OFS); - - cdir_ofs = MZ_READ_LE64(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_CDIR_OFS_OFS); - } - - if (pZip->m_total_files != cdir_entries_on_this_disk) - return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_MULTIDISK); - - if (((num_this_disk | cdir_disk_index) != 0) && ((num_this_disk != 1) || (cdir_disk_index != 1))) - return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_MULTIDISK); - - if (cdir_size < pZip->m_total_files * MZ_ZIP_CENTRAL_DIR_HEADER_SIZE) - return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); - - if ((cdir_ofs + (mz_uint64)cdir_size) > pZip->m_archive_size) - return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); - - pZip->m_central_directory_file_ofs = cdir_ofs; - - if (pZip->m_total_files) - { - mz_uint i, n; - /* Read the entire central directory into a heap block, and allocate another heap block to hold the unsorted central dir file record offsets, and possibly another to hold the sorted indices. */ - if ((!mz_zip_array_resize(pZip, &pZip->m_pState->m_central_dir, cdir_size, MZ_FALSE)) || - (!mz_zip_array_resize(pZip, &pZip->m_pState->m_central_dir_offsets, pZip->m_total_files, MZ_FALSE))) - return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); - - if (sort_central_dir) - { - if (!mz_zip_array_resize(pZip, &pZip->m_pState->m_sorted_central_dir_offsets, pZip->m_total_files, MZ_FALSE)) - return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); - } - - if (pZip->m_pRead(pZip->m_pIO_opaque, cdir_ofs, pZip->m_pState->m_central_dir.m_p, cdir_size) != cdir_size) - return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); - - /* Now create an index into the central directory file records, do some basic sanity checking on each record */ - p = (const mz_uint8 *)pZip->m_pState->m_central_dir.m_p; - for (n = cdir_size, i = 0; i < pZip->m_total_files; ++i) - { - mz_uint total_header_size, disk_index, bit_flags, filename_size, ext_data_size; - mz_uint64 comp_size, decomp_size, local_header_ofs; - - if ((n < MZ_ZIP_CENTRAL_DIR_HEADER_SIZE) || (MZ_READ_LE32(p) != MZ_ZIP_CENTRAL_DIR_HEADER_SIG)) - return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); - - MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, i) = (mz_uint32)(p - (const mz_uint8 *)pZip->m_pState->m_central_dir.m_p); - - if (sort_central_dir) - MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_sorted_central_dir_offsets, mz_uint32, i) = i; - - comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS); - decomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS); - local_header_ofs = MZ_READ_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS); - filename_size = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS); - ext_data_size = MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS); - - if ((!pZip->m_pState->m_zip64_has_extended_info_fields) && - (ext_data_size) && - (MZ_MAX(MZ_MAX(comp_size, decomp_size), local_header_ofs) == MZ_UINT32_MAX)) - { - /* Attempt to find zip64 extended information field in the entry's extra data */ - mz_uint32 extra_size_remaining = ext_data_size; - - if (extra_size_remaining) - { - const mz_uint8 *pExtra_data; - void* buf = NULL; - - if (MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_size + ext_data_size > n) - { - buf = MZ_MALLOC(ext_data_size); - if(buf==NULL) - return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); - - if (pZip->m_pRead(pZip->m_pIO_opaque, cdir_ofs + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_size, buf, ext_data_size) != ext_data_size) - { - MZ_FREE(buf); - return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); - } - - pExtra_data = (mz_uint8*)buf; - } - else - { - pExtra_data = p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_size; - } - - do - { - mz_uint32 field_id; - mz_uint32 field_data_size; - - if (extra_size_remaining < (sizeof(mz_uint16) * 2)) - { - MZ_FREE(buf); - return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); - } - - field_id = MZ_READ_LE16(pExtra_data); - field_data_size = MZ_READ_LE16(pExtra_data + sizeof(mz_uint16)); - - if ((field_data_size + sizeof(mz_uint16) * 2) > extra_size_remaining) - { - MZ_FREE(buf); - return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); - } - - if (field_id == MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID) - { - /* Ok, the archive didn't have any zip64 headers but it uses a zip64 extended information field so mark it as zip64 anyway (this can occur with infozip's zip util when it reads compresses files from stdin). */ - pZip->m_pState->m_zip64 = MZ_TRUE; - pZip->m_pState->m_zip64_has_extended_info_fields = MZ_TRUE; - break; - } - - pExtra_data += sizeof(mz_uint16) * 2 + field_data_size; - extra_size_remaining = extra_size_remaining - sizeof(mz_uint16) * 2 - field_data_size; - } while (extra_size_remaining); - - MZ_FREE(buf); - } - } - - /* I've seen archives that aren't marked as zip64 that uses zip64 ext data, argh */ - if ((comp_size != MZ_UINT32_MAX) && (decomp_size != MZ_UINT32_MAX)) - { - if (((!MZ_READ_LE32(p + MZ_ZIP_CDH_METHOD_OFS)) && (decomp_size != comp_size)) || (decomp_size && !comp_size)) - return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); - } - - disk_index = MZ_READ_LE16(p + MZ_ZIP_CDH_DISK_START_OFS); - if ((disk_index == MZ_UINT16_MAX) || ((disk_index != num_this_disk) && (disk_index != 1))) - return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_MULTIDISK); - - if (comp_size != MZ_UINT32_MAX) - { - if (((mz_uint64)MZ_READ_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS) + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + comp_size) > pZip->m_archive_size) - return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); - } - - bit_flags = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS); - if (bit_flags & MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_LOCAL_DIR_IS_MASKED) - return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION); - - if ((total_header_size = MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS) + MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS) + MZ_READ_LE16(p + MZ_ZIP_CDH_COMMENT_LEN_OFS)) > n) - return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); - - n -= total_header_size; - p += total_header_size; - } - } - - if (sort_central_dir) - mz_zip_reader_sort_central_dir_offsets_by_filename(pZip); - - return MZ_TRUE; -} - -void mz_zip_zero_struct(mz_zip_archive *pZip) -{ - if (pZip) - MZ_CLEAR_OBJ(*pZip); -} - -static mz_bool mz_zip_reader_end_internal(mz_zip_archive *pZip, mz_bool set_last_error) -{ - mz_bool status = MZ_TRUE; - - if (!pZip) - return MZ_FALSE; - - if ((!pZip->m_pState) || (!pZip->m_pAlloc) || (!pZip->m_pFree) || (pZip->m_zip_mode != MZ_ZIP_MODE_READING)) - { - if (set_last_error) - pZip->m_last_error = MZ_ZIP_INVALID_PARAMETER; - - return MZ_FALSE; - } - - if (pZip->m_pState) - { - mz_zip_internal_state *pState = pZip->m_pState; - pZip->m_pState = NULL; - - mz_zip_array_clear(pZip, &pState->m_central_dir); - mz_zip_array_clear(pZip, &pState->m_central_dir_offsets); - mz_zip_array_clear(pZip, &pState->m_sorted_central_dir_offsets); - -#ifndef MINIZ_NO_STDIO - if (pState->m_pFile) - { - if (pZip->m_zip_type == MZ_ZIP_TYPE_FILE) - { - if (MZ_FCLOSE(pState->m_pFile) == EOF) - { - if (set_last_error) - pZip->m_last_error = MZ_ZIP_FILE_CLOSE_FAILED; - status = MZ_FALSE; - } - } - pState->m_pFile = NULL; - } -#endif /* #ifndef MINIZ_NO_STDIO */ - - pZip->m_pFree(pZip->m_pAlloc_opaque, pState); - } - pZip->m_zip_mode = MZ_ZIP_MODE_INVALID; - - return status; -} - -mz_bool mz_zip_reader_end(mz_zip_archive *pZip) -{ - return mz_zip_reader_end_internal(pZip, MZ_TRUE); -} -mz_bool mz_zip_reader_init(mz_zip_archive *pZip, mz_uint64 size, mz_uint flags) -{ - if ((!pZip) || (!pZip->m_pRead)) - return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - - if (!mz_zip_reader_init_internal(pZip, flags)) - return MZ_FALSE; - - pZip->m_zip_type = MZ_ZIP_TYPE_USER; - pZip->m_archive_size = size; - - if (!mz_zip_reader_read_central_dir(pZip, flags)) - { - mz_zip_reader_end_internal(pZip, MZ_FALSE); - return MZ_FALSE; - } - - return MZ_TRUE; -} - -static size_t mz_zip_mem_read_func(void *pOpaque, mz_uint64 file_ofs, void *pBuf, size_t n) -{ - mz_zip_archive *pZip = (mz_zip_archive *)pOpaque; - size_t s = (file_ofs >= pZip->m_archive_size) ? 0 : (size_t)MZ_MIN(pZip->m_archive_size - file_ofs, n); - memcpy(pBuf, (const mz_uint8 *)pZip->m_pState->m_pMem + file_ofs, s); - return s; -} - -mz_bool mz_zip_reader_init_mem(mz_zip_archive *pZip, const void *pMem, size_t size, mz_uint flags) -{ - if (!pMem) - return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - - if (size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) - return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE); - - if (!mz_zip_reader_init_internal(pZip, flags)) - return MZ_FALSE; - - pZip->m_zip_type = MZ_ZIP_TYPE_MEMORY; - pZip->m_archive_size = size; - pZip->m_pRead = mz_zip_mem_read_func; - pZip->m_pIO_opaque = pZip; - pZip->m_pNeeds_keepalive = NULL; - -#ifdef __cplusplus - pZip->m_pState->m_pMem = const_cast(pMem); -#else - pZip->m_pState->m_pMem = (void *)pMem; -#endif - - pZip->m_pState->m_mem_size = size; - - if (!mz_zip_reader_read_central_dir(pZip, flags)) - { - mz_zip_reader_end_internal(pZip, MZ_FALSE); - return MZ_FALSE; - } - - return MZ_TRUE; -} - -#ifndef MINIZ_NO_STDIO -static size_t mz_zip_file_read_func(void *pOpaque, mz_uint64 file_ofs, void *pBuf, size_t n) -{ - mz_zip_archive *pZip = (mz_zip_archive *)pOpaque; - mz_int64 cur_ofs = MZ_FTELL64(pZip->m_pState->m_pFile); - - file_ofs += pZip->m_pState->m_file_archive_start_ofs; - - if (((mz_int64)file_ofs < 0) || (((cur_ofs != (mz_int64)file_ofs)) && (MZ_FSEEK64(pZip->m_pState->m_pFile, (mz_int64)file_ofs, SEEK_SET)))) - return 0; - - return MZ_FREAD(pBuf, 1, n, pZip->m_pState->m_pFile); -} - -mz_bool mz_zip_reader_init_file(mz_zip_archive *pZip, const char *pFilename, mz_uint32 flags) -{ - return mz_zip_reader_init_file_v2(pZip, pFilename, flags, 0, 0); -} - -mz_bool mz_zip_reader_init_file_v2(mz_zip_archive *pZip, const char *pFilename, mz_uint flags, mz_uint64 file_start_ofs, mz_uint64 archive_size) -{ - mz_uint64 file_size; - MZ_FILE *pFile; - - if ((!pZip) || (!pFilename) || ((archive_size) && (archive_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE))) - return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - - pFile = MZ_FOPEN(pFilename, "rb"); - if (!pFile) - return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED); - - file_size = archive_size; - if (!file_size) - { - if (MZ_FSEEK64(pFile, 0, SEEK_END)) - { - MZ_FCLOSE(pFile); - return mz_zip_set_error(pZip, MZ_ZIP_FILE_SEEK_FAILED); - } - - file_size = MZ_FTELL64(pFile); - } - - /* TODO: Better sanity check archive_size and the # of actual remaining bytes */ - - if (file_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) - { - MZ_FCLOSE(pFile); - return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE); - } - - if (!mz_zip_reader_init_internal(pZip, flags)) - { - MZ_FCLOSE(pFile); - return MZ_FALSE; - } - - pZip->m_zip_type = MZ_ZIP_TYPE_FILE; - pZip->m_pRead = mz_zip_file_read_func; - pZip->m_pIO_opaque = pZip; - pZip->m_pState->m_pFile = pFile; - pZip->m_archive_size = file_size; - pZip->m_pState->m_file_archive_start_ofs = file_start_ofs; - - if (!mz_zip_reader_read_central_dir(pZip, flags)) - { - mz_zip_reader_end_internal(pZip, MZ_FALSE); - return MZ_FALSE; - } - - return MZ_TRUE; -} - -mz_bool mz_zip_reader_init_cfile(mz_zip_archive *pZip, MZ_FILE *pFile, mz_uint64 archive_size, mz_uint flags) -{ - mz_uint64 cur_file_ofs; - - if ((!pZip) || (!pFile)) - return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED); - - cur_file_ofs = MZ_FTELL64(pFile); - - if (!archive_size) - { - if (MZ_FSEEK64(pFile, 0, SEEK_END)) - return mz_zip_set_error(pZip, MZ_ZIP_FILE_SEEK_FAILED); - - archive_size = MZ_FTELL64(pFile) - cur_file_ofs; - - if (archive_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) - return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE); - } - - if (!mz_zip_reader_init_internal(pZip, flags)) - return MZ_FALSE; - - pZip->m_zip_type = MZ_ZIP_TYPE_CFILE; - pZip->m_pRead = mz_zip_file_read_func; - - pZip->m_pIO_opaque = pZip; - pZip->m_pState->m_pFile = pFile; - pZip->m_archive_size = archive_size; - pZip->m_pState->m_file_archive_start_ofs = cur_file_ofs; - - if (!mz_zip_reader_read_central_dir(pZip, flags)) - { - mz_zip_reader_end_internal(pZip, MZ_FALSE); - return MZ_FALSE; - } - - return MZ_TRUE; -} - -#endif /* #ifndef MINIZ_NO_STDIO */ - -static MZ_FORCEINLINE const mz_uint8 *mz_zip_get_cdh(mz_zip_archive *pZip, mz_uint file_index) -{ - if ((!pZip) || (!pZip->m_pState) || (file_index >= pZip->m_total_files)) - return NULL; - return &MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, file_index)); -} - -mz_bool mz_zip_reader_is_file_encrypted(mz_zip_archive *pZip, mz_uint file_index) -{ - mz_uint m_bit_flag; - const mz_uint8 *p = mz_zip_get_cdh(pZip, file_index); - if (!p) - { - mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - return MZ_FALSE; - } - - m_bit_flag = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS); - return (m_bit_flag & (MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION)) != 0; -} - -mz_bool mz_zip_reader_is_file_supported(mz_zip_archive *pZip, mz_uint file_index) -{ - mz_uint bit_flag; - mz_uint method; - - const mz_uint8 *p = mz_zip_get_cdh(pZip, file_index); - if (!p) - { - mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - return MZ_FALSE; - } - - method = MZ_READ_LE16(p + MZ_ZIP_CDH_METHOD_OFS); - bit_flag = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS); - - if ((method != 0) && (method != MZ_DEFLATED)) - { - mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_METHOD); - return MZ_FALSE; - } - - if (bit_flag & (MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION)) - { - mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION); - return MZ_FALSE; - } - - if (bit_flag & MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_COMPRESSED_PATCH_FLAG) - { - mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_FEATURE); - return MZ_FALSE; - } - - return MZ_TRUE; -} - -mz_bool mz_zip_reader_is_file_a_directory(mz_zip_archive *pZip, mz_uint file_index) -{ - mz_uint filename_len, attribute_mapping_id, external_attr; - const mz_uint8 *p = mz_zip_get_cdh(pZip, file_index); - if (!p) - { - mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - return MZ_FALSE; - } - - filename_len = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS); - if (filename_len) - { - if (*(p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_len - 1) == '/') - return MZ_TRUE; - } - - /* Bugfix: This code was also checking if the internal attribute was non-zero, which wasn't correct. */ - /* Most/all zip writers (hopefully) set DOS file/directory attributes in the low 16-bits, so check for the DOS directory flag and ignore the source OS ID in the created by field. */ - /* FIXME: Remove this check? Is it necessary - we already check the filename. */ - attribute_mapping_id = MZ_READ_LE16(p + MZ_ZIP_CDH_VERSION_MADE_BY_OFS) >> 8; - (void)attribute_mapping_id; - - external_attr = MZ_READ_LE32(p + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS); - if ((external_attr & MZ_ZIP_DOS_DIR_ATTRIBUTE_BITFLAG) != 0) - { - return MZ_TRUE; - } - - return MZ_FALSE; -} - -static mz_bool mz_zip_file_stat_internal(mz_zip_archive *pZip, mz_uint file_index, const mz_uint8 *pCentral_dir_header, mz_zip_archive_file_stat *pStat, mz_bool *pFound_zip64_extra_data) -{ - mz_uint n; - const mz_uint8 *p = pCentral_dir_header; - - if (pFound_zip64_extra_data) - *pFound_zip64_extra_data = MZ_FALSE; - - if ((!p) || (!pStat)) - return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - - /* Extract fields from the central directory record. */ - pStat->m_file_index = file_index; - pStat->m_central_dir_ofs = MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, file_index); - pStat->m_version_made_by = MZ_READ_LE16(p + MZ_ZIP_CDH_VERSION_MADE_BY_OFS); - pStat->m_version_needed = MZ_READ_LE16(p + MZ_ZIP_CDH_VERSION_NEEDED_OFS); - pStat->m_bit_flag = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS); - pStat->m_method = MZ_READ_LE16(p + MZ_ZIP_CDH_METHOD_OFS); -#ifndef MINIZ_NO_TIME - pStat->m_time = mz_zip_dos_to_time_t(MZ_READ_LE16(p + MZ_ZIP_CDH_FILE_TIME_OFS), MZ_READ_LE16(p + MZ_ZIP_CDH_FILE_DATE_OFS)); -#endif - pStat->m_crc32 = MZ_READ_LE32(p + MZ_ZIP_CDH_CRC32_OFS); - pStat->m_comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS); - pStat->m_uncomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS); - pStat->m_internal_attr = MZ_READ_LE16(p + MZ_ZIP_CDH_INTERNAL_ATTR_OFS); - pStat->m_external_attr = MZ_READ_LE32(p + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS); - pStat->m_local_header_ofs = MZ_READ_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS); - - /* Copy as much of the filename and comment as possible. */ - n = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS); - n = MZ_MIN(n, MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE - 1); - memcpy(pStat->m_filename, p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, n); - pStat->m_filename[n] = '\0'; - - n = MZ_READ_LE16(p + MZ_ZIP_CDH_COMMENT_LEN_OFS); - n = MZ_MIN(n, MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE - 1); - pStat->m_comment_size = n; - memcpy(pStat->m_comment, p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS) + MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS), n); - pStat->m_comment[n] = '\0'; - - /* Set some flags for convienance */ - pStat->m_is_directory = mz_zip_reader_is_file_a_directory(pZip, file_index); - pStat->m_is_encrypted = mz_zip_reader_is_file_encrypted(pZip, file_index); - pStat->m_is_supported = mz_zip_reader_is_file_supported(pZip, file_index); - - /* See if we need to read any zip64 extended information fields. */ - /* Confusingly, these zip64 fields can be present even on non-zip64 archives (Debian zip on a huge files from stdin piped to stdout creates them). */ - if (MZ_MAX(MZ_MAX(pStat->m_comp_size, pStat->m_uncomp_size), pStat->m_local_header_ofs) == MZ_UINT32_MAX) - { - /* Attempt to find zip64 extended information field in the entry's extra data */ - mz_uint32 extra_size_remaining = MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS); - - if (extra_size_remaining) - { - const mz_uint8 *pExtra_data = p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS); - - do - { - mz_uint32 field_id; - mz_uint32 field_data_size; - - if (extra_size_remaining < (sizeof(mz_uint16) * 2)) - return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); - - field_id = MZ_READ_LE16(pExtra_data); - field_data_size = MZ_READ_LE16(pExtra_data + sizeof(mz_uint16)); - - if ((field_data_size + sizeof(mz_uint16) * 2) > extra_size_remaining) - return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); - - if (field_id == MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID) - { - const mz_uint8 *pField_data = pExtra_data + sizeof(mz_uint16) * 2; - mz_uint32 field_data_remaining = field_data_size; - - if (pFound_zip64_extra_data) - *pFound_zip64_extra_data = MZ_TRUE; - - if (pStat->m_uncomp_size == MZ_UINT32_MAX) - { - if (field_data_remaining < sizeof(mz_uint64)) - return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); - - pStat->m_uncomp_size = MZ_READ_LE64(pField_data); - pField_data += sizeof(mz_uint64); - field_data_remaining -= sizeof(mz_uint64); - } - - if (pStat->m_comp_size == MZ_UINT32_MAX) - { - if (field_data_remaining < sizeof(mz_uint64)) - return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); - - pStat->m_comp_size = MZ_READ_LE64(pField_data); - pField_data += sizeof(mz_uint64); - field_data_remaining -= sizeof(mz_uint64); - } - - if (pStat->m_local_header_ofs == MZ_UINT32_MAX) - { - if (field_data_remaining < sizeof(mz_uint64)) - return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); - - pStat->m_local_header_ofs = MZ_READ_LE64(pField_data); - pField_data += sizeof(mz_uint64); - field_data_remaining -= sizeof(mz_uint64); - } - - break; - } - - pExtra_data += sizeof(mz_uint16) * 2 + field_data_size; - extra_size_remaining = extra_size_remaining - sizeof(mz_uint16) * 2 - field_data_size; - } while (extra_size_remaining); - } - } - - return MZ_TRUE; -} - -static MZ_FORCEINLINE mz_bool mz_zip_string_equal(const char *pA, const char *pB, mz_uint len, mz_uint flags) -{ - mz_uint i; - if (flags & MZ_ZIP_FLAG_CASE_SENSITIVE) - return 0 == memcmp(pA, pB, len); - for (i = 0; i < len; ++i) - if (MZ_TOLOWER(pA[i]) != MZ_TOLOWER(pB[i])) - return MZ_FALSE; - return MZ_TRUE; -} - -static MZ_FORCEINLINE int mz_zip_filename_compare(const mz_zip_array *pCentral_dir_array, const mz_zip_array *pCentral_dir_offsets, mz_uint l_index, const char *pR, mz_uint r_len) -{ - const mz_uint8 *pL = &MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_array, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32, l_index)), *pE; - mz_uint l_len = MZ_READ_LE16(pL + MZ_ZIP_CDH_FILENAME_LEN_OFS); - mz_uint8 l = 0, r = 0; - pL += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; - pE = pL + MZ_MIN(l_len, r_len); - while (pL < pE) - { - if ((l = MZ_TOLOWER(*pL)) != (r = MZ_TOLOWER(*pR))) - break; - pL++; - pR++; - } - return (pL == pE) ? (int)(l_len - r_len) : (l - r); -} - -static mz_bool mz_zip_locate_file_binary_search(mz_zip_archive *pZip, const char *pFilename, mz_uint32 *pIndex) -{ - mz_zip_internal_state *pState = pZip->m_pState; - const mz_zip_array *pCentral_dir_offsets = &pState->m_central_dir_offsets; - const mz_zip_array *pCentral_dir = &pState->m_central_dir; - mz_uint32 *pIndices = &MZ_ZIP_ARRAY_ELEMENT(&pState->m_sorted_central_dir_offsets, mz_uint32, 0); - const uint32_t size = pZip->m_total_files; - const mz_uint filename_len = (mz_uint)strlen(pFilename); - - if (pIndex) - *pIndex = 0; - - if (size) - { - /* yes I could use uint32_t's, but then we would have to add some special case checks in the loop, argh, and */ - /* honestly the major expense here on 32-bit CPU's will still be the filename compare */ - mz_int64 l = 0, h = (mz_int64)size - 1; - - while (l <= h) - { - mz_int64 m = l + ((h - l) >> 1); - uint32_t file_index = pIndices[(uint32_t)m]; - - int comp = mz_zip_filename_compare(pCentral_dir, pCentral_dir_offsets, file_index, pFilename, filename_len); - if (!comp) - { - if (pIndex) - *pIndex = file_index; - return MZ_TRUE; - } - else if (comp < 0) - l = m + 1; - else - h = m - 1; - } - } - - return mz_zip_set_error(pZip, MZ_ZIP_FILE_NOT_FOUND); -} - -int mz_zip_reader_locate_file(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags) -{ - mz_uint32 index; - if (!mz_zip_reader_locate_file_v2(pZip, pName, pComment, flags, &index)) - return -1; - else - return (int)index; -} - -mz_bool mz_zip_reader_locate_file_v2(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags, mz_uint32 *pIndex) -{ - mz_uint file_index; - size_t name_len, comment_len; - - if (pIndex) - *pIndex = 0; - - if ((!pZip) || (!pZip->m_pState) || (!pName)) - return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - - /* See if we can use a binary search */ - if (((pZip->m_pState->m_init_flags & MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY) == 0) && - (pZip->m_zip_mode == MZ_ZIP_MODE_READING) && - ((flags & (MZ_ZIP_FLAG_IGNORE_PATH | MZ_ZIP_FLAG_CASE_SENSITIVE)) == 0) && (!pComment) && (pZip->m_pState->m_sorted_central_dir_offsets.m_size)) - { - return mz_zip_locate_file_binary_search(pZip, pName, pIndex); - } - - /* Locate the entry by scanning the entire central directory */ - name_len = strlen(pName); - if (name_len > MZ_UINT16_MAX) - return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - - comment_len = pComment ? strlen(pComment) : 0; - if (comment_len > MZ_UINT16_MAX) - return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - - for (file_index = 0; file_index < pZip->m_total_files; file_index++) - { - const mz_uint8 *pHeader = &MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, file_index)); - mz_uint filename_len = MZ_READ_LE16(pHeader + MZ_ZIP_CDH_FILENAME_LEN_OFS); - const char *pFilename = (const char *)pHeader + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; - if (filename_len < name_len) - continue; - if (comment_len) - { - mz_uint file_extra_len = MZ_READ_LE16(pHeader + MZ_ZIP_CDH_EXTRA_LEN_OFS), file_comment_len = MZ_READ_LE16(pHeader + MZ_ZIP_CDH_COMMENT_LEN_OFS); - const char *pFile_comment = pFilename + filename_len + file_extra_len; - if ((file_comment_len != comment_len) || (!mz_zip_string_equal(pComment, pFile_comment, file_comment_len, flags))) - continue; - } - if ((flags & MZ_ZIP_FLAG_IGNORE_PATH) && (filename_len)) - { - int ofs = filename_len - 1; - do - { - if ((pFilename[ofs] == '/') || (pFilename[ofs] == '\\') || (pFilename[ofs] == ':')) - break; - } while (--ofs >= 0); - ofs++; - pFilename += ofs; - filename_len -= ofs; - } - if ((filename_len == name_len) && (mz_zip_string_equal(pName, pFilename, filename_len, flags))) - { - if (pIndex) - *pIndex = file_index; - return MZ_TRUE; - } - } - - return mz_zip_set_error(pZip, MZ_ZIP_FILE_NOT_FOUND); -} - -mz_bool mz_zip_reader_extract_to_mem_no_alloc(mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size) -{ - int status = TINFL_STATUS_DONE; - mz_uint64 needed_size, cur_file_ofs, comp_remaining, out_buf_ofs = 0, read_buf_size, read_buf_ofs = 0, read_buf_avail; - mz_zip_archive_file_stat file_stat; - void *pRead_buf; - mz_uint32 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; - mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32; - tinfl_decompressor inflator; - - if ((!pZip) || (!pZip->m_pState) || ((buf_size) && (!pBuf)) || ((user_read_buf_size) && (!pUser_read_buf)) || (!pZip->m_pRead)) - return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - - if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat)) - return MZ_FALSE; - - /* A directory or zero length file */ - if ((file_stat.m_is_directory) || (!file_stat.m_comp_size)) - return MZ_TRUE; - - /* Encryption and patch files are not supported. */ - if (file_stat.m_bit_flag & (MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_COMPRESSED_PATCH_FLAG)) - return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION); - - /* This function only supports decompressing stored and deflate. */ - if ((!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (file_stat.m_method != 0) && (file_stat.m_method != MZ_DEFLATED)) - return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_METHOD); - - /* Ensure supplied output buffer is large enough. */ - needed_size = (flags & MZ_ZIP_FLAG_COMPRESSED_DATA) ? file_stat.m_comp_size : file_stat.m_uncomp_size; - if (buf_size < needed_size) - return mz_zip_set_error(pZip, MZ_ZIP_BUF_TOO_SMALL); - - /* Read and parse the local directory entry. */ - cur_file_ofs = file_stat.m_local_header_ofs; - if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE) - return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); - - if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG) - return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); - - cur_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS); - if ((cur_file_ofs + file_stat.m_comp_size) > pZip->m_archive_size) - return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); - - if ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!file_stat.m_method)) - { - /* The file is stored or the caller has requested the compressed data. */ - if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, (size_t)needed_size) != needed_size) - return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); - -#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS - if ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) == 0) - { - if (mz_crc32(MZ_CRC32_INIT, (const mz_uint8 *)pBuf, (size_t)file_stat.m_uncomp_size) != file_stat.m_crc32) - return mz_zip_set_error(pZip, MZ_ZIP_CRC_CHECK_FAILED); - } -#endif - - return MZ_TRUE; - } - - /* Decompress the file either directly from memory or from a file input buffer. */ - tinfl_init(&inflator); - - if (pZip->m_pState->m_pMem) - { - /* Read directly from the archive in memory. */ - pRead_buf = (mz_uint8 *)pZip->m_pState->m_pMem + cur_file_ofs; - read_buf_size = read_buf_avail = file_stat.m_comp_size; - comp_remaining = 0; - } - else if (pUser_read_buf) - { - /* Use a user provided read buffer. */ - if (!user_read_buf_size) - return MZ_FALSE; - pRead_buf = (mz_uint8 *)pUser_read_buf; - read_buf_size = user_read_buf_size; - read_buf_avail = 0; - comp_remaining = file_stat.m_comp_size; - } - else - { - /* Temporarily allocate a read buffer. */ - read_buf_size = MZ_MIN(file_stat.m_comp_size, (mz_uint64)MZ_ZIP_MAX_IO_BUF_SIZE); - if (((sizeof(size_t) == sizeof(mz_uint32))) && (read_buf_size > 0x7FFFFFFF)) - return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); - - if (NULL == (pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)read_buf_size))) - return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); - - read_buf_avail = 0; - comp_remaining = file_stat.m_comp_size; - } - - do - { - /* The size_t cast here should be OK because we've verified that the output buffer is >= file_stat.m_uncomp_size above */ - size_t in_buf_size, out_buf_size = (size_t)(file_stat.m_uncomp_size - out_buf_ofs); - if ((!read_buf_avail) && (!pZip->m_pState->m_pMem)) - { - read_buf_avail = MZ_MIN(read_buf_size, comp_remaining); - if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail) - { - status = TINFL_STATUS_FAILED; - mz_zip_set_error(pZip, MZ_ZIP_DECOMPRESSION_FAILED); - break; - } - cur_file_ofs += read_buf_avail; - comp_remaining -= read_buf_avail; - read_buf_ofs = 0; - } - in_buf_size = (size_t)read_buf_avail; - status = tinfl_decompress(&inflator, (mz_uint8 *)pRead_buf + read_buf_ofs, &in_buf_size, (mz_uint8 *)pBuf, (mz_uint8 *)pBuf + out_buf_ofs, &out_buf_size, TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF | (comp_remaining ? TINFL_FLAG_HAS_MORE_INPUT : 0)); - read_buf_avail -= in_buf_size; - read_buf_ofs += in_buf_size; - out_buf_ofs += out_buf_size; - } while (status == TINFL_STATUS_NEEDS_MORE_INPUT); - - if (status == TINFL_STATUS_DONE) - { - /* Make sure the entire file was decompressed, and check its CRC. */ - if (out_buf_ofs != file_stat.m_uncomp_size) - { - mz_zip_set_error(pZip, MZ_ZIP_UNEXPECTED_DECOMPRESSED_SIZE); - status = TINFL_STATUS_FAILED; - } -#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS - else if (mz_crc32(MZ_CRC32_INIT, (const mz_uint8 *)pBuf, (size_t)file_stat.m_uncomp_size) != file_stat.m_crc32) - { - mz_zip_set_error(pZip, MZ_ZIP_CRC_CHECK_FAILED); - status = TINFL_STATUS_FAILED; - } -#endif - } - - if ((!pZip->m_pState->m_pMem) && (!pUser_read_buf)) - pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); - - return status == TINFL_STATUS_DONE; -} - -mz_bool mz_zip_reader_extract_file_to_mem_no_alloc(mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size) -{ - mz_uint32 file_index; - if (!mz_zip_reader_locate_file_v2(pZip, pFilename, NULL, flags, &file_index)) - return MZ_FALSE; - return mz_zip_reader_extract_to_mem_no_alloc(pZip, file_index, pBuf, buf_size, flags, pUser_read_buf, user_read_buf_size); -} - -mz_bool mz_zip_reader_extract_to_mem(mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, mz_uint flags) -{ - return mz_zip_reader_extract_to_mem_no_alloc(pZip, file_index, pBuf, buf_size, flags, NULL, 0); -} - -mz_bool mz_zip_reader_extract_file_to_mem(mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, mz_uint flags) -{ - return mz_zip_reader_extract_file_to_mem_no_alloc(pZip, pFilename, pBuf, buf_size, flags, NULL, 0); -} - -void *mz_zip_reader_extract_to_heap(mz_zip_archive *pZip, mz_uint file_index, size_t *pSize, mz_uint flags) -{ - mz_uint64 comp_size, uncomp_size, alloc_size; - const mz_uint8 *p = mz_zip_get_cdh(pZip, file_index); - void *pBuf; - - if (pSize) - *pSize = 0; - - if (!p) - { - mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - return NULL; - } - - comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS); - uncomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS); - - alloc_size = (flags & MZ_ZIP_FLAG_COMPRESSED_DATA) ? comp_size : uncomp_size; - if (((sizeof(size_t) == sizeof(mz_uint32))) && (alloc_size > 0x7FFFFFFF)) - { - mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); - return NULL; - } - - if (NULL == (pBuf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)alloc_size))) - { - mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); - return NULL; - } - - if (!mz_zip_reader_extract_to_mem(pZip, file_index, pBuf, (size_t)alloc_size, flags)) - { - pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); - return NULL; - } - - if (pSize) - *pSize = (size_t)alloc_size; - return pBuf; -} - -void *mz_zip_reader_extract_file_to_heap(mz_zip_archive *pZip, const char *pFilename, size_t *pSize, mz_uint flags) -{ - mz_uint32 file_index; - if (!mz_zip_reader_locate_file_v2(pZip, pFilename, NULL, flags, &file_index)) - { - if (pSize) - *pSize = 0; - return MZ_FALSE; - } - return mz_zip_reader_extract_to_heap(pZip, file_index, pSize, flags); -} - -mz_bool mz_zip_reader_extract_to_callback(mz_zip_archive *pZip, mz_uint file_index, mz_file_write_func pCallback, void *pOpaque, mz_uint flags) -{ - int status = TINFL_STATUS_DONE; - mz_uint file_crc32 = MZ_CRC32_INIT; - mz_uint64 read_buf_size, read_buf_ofs = 0, read_buf_avail, comp_remaining, out_buf_ofs = 0, cur_file_ofs; - mz_zip_archive_file_stat file_stat; - void *pRead_buf = NULL; - void *pWrite_buf = NULL; - mz_uint32 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; - mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32; - - if ((!pZip) || (!pZip->m_pState) || (!pCallback) || (!pZip->m_pRead)) - return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - - if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat)) - return MZ_FALSE; - - /* A directory or zero length file */ - if ((file_stat.m_is_directory) || (!file_stat.m_comp_size)) - return MZ_TRUE; - - /* Encryption and patch files are not supported. */ - if (file_stat.m_bit_flag & (MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_COMPRESSED_PATCH_FLAG)) - return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION); - - /* This function only supports decompressing stored and deflate. */ - if ((!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (file_stat.m_method != 0) && (file_stat.m_method != MZ_DEFLATED)) - return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_METHOD); - - /* Read and do some minimal validation of the local directory entry (this doesn't crack the zip64 stuff, which we already have from the central dir) */ - cur_file_ofs = file_stat.m_local_header_ofs; - if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE) - return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); - - if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG) - return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); - - cur_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS); - if ((cur_file_ofs + file_stat.m_comp_size) > pZip->m_archive_size) - return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); - - /* Decompress the file either directly from memory or from a file input buffer. */ - if (pZip->m_pState->m_pMem) - { - pRead_buf = (mz_uint8 *)pZip->m_pState->m_pMem + cur_file_ofs; - read_buf_size = read_buf_avail = file_stat.m_comp_size; - comp_remaining = 0; - } - else - { - read_buf_size = MZ_MIN(file_stat.m_comp_size, (mz_uint64)MZ_ZIP_MAX_IO_BUF_SIZE); - if (NULL == (pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)read_buf_size))) - return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); - - read_buf_avail = 0; - comp_remaining = file_stat.m_comp_size; - } - - if ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!file_stat.m_method)) - { - /* The file is stored or the caller has requested the compressed data. */ - if (pZip->m_pState->m_pMem) - { - if (((sizeof(size_t) == sizeof(mz_uint32))) && (file_stat.m_comp_size > MZ_UINT32_MAX)) - return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); - - if (pCallback(pOpaque, out_buf_ofs, pRead_buf, (size_t)file_stat.m_comp_size) != file_stat.m_comp_size) - { - mz_zip_set_error(pZip, MZ_ZIP_WRITE_CALLBACK_FAILED); - status = TINFL_STATUS_FAILED; - } - else if (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) - { -#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS - file_crc32 = (mz_uint32)mz_crc32(file_crc32, (const mz_uint8 *)pRead_buf, (size_t)file_stat.m_comp_size); -#endif - } - - cur_file_ofs += file_stat.m_comp_size; - out_buf_ofs += file_stat.m_comp_size; - comp_remaining = 0; - } - else - { - while (comp_remaining) - { - read_buf_avail = MZ_MIN(read_buf_size, comp_remaining); - if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail) - { - mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); - status = TINFL_STATUS_FAILED; - break; - } - -#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS - if (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) - { - file_crc32 = (mz_uint32)mz_crc32(file_crc32, (const mz_uint8 *)pRead_buf, (size_t)read_buf_avail); - } -#endif - - if (pCallback(pOpaque, out_buf_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail) - { - mz_zip_set_error(pZip, MZ_ZIP_WRITE_CALLBACK_FAILED); - status = TINFL_STATUS_FAILED; - break; - } - - cur_file_ofs += read_buf_avail; - out_buf_ofs += read_buf_avail; - comp_remaining -= read_buf_avail; - } - } - } - else - { - tinfl_decompressor inflator; - tinfl_init(&inflator); - - if (NULL == (pWrite_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, TINFL_LZ_DICT_SIZE))) - { - mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); - status = TINFL_STATUS_FAILED; - } - else - { - do - { - mz_uint8 *pWrite_buf_cur = (mz_uint8 *)pWrite_buf + (out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1)); - size_t in_buf_size, out_buf_size = TINFL_LZ_DICT_SIZE - (out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1)); - if ((!read_buf_avail) && (!pZip->m_pState->m_pMem)) - { - read_buf_avail = MZ_MIN(read_buf_size, comp_remaining); - if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail) - { - mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); - status = TINFL_STATUS_FAILED; - break; - } - cur_file_ofs += read_buf_avail; - comp_remaining -= read_buf_avail; - read_buf_ofs = 0; - } - - in_buf_size = (size_t)read_buf_avail; - status = tinfl_decompress(&inflator, (const mz_uint8 *)pRead_buf + read_buf_ofs, &in_buf_size, (mz_uint8 *)pWrite_buf, pWrite_buf_cur, &out_buf_size, comp_remaining ? TINFL_FLAG_HAS_MORE_INPUT : 0); - read_buf_avail -= in_buf_size; - read_buf_ofs += in_buf_size; - - if (out_buf_size) - { - if (pCallback(pOpaque, out_buf_ofs, pWrite_buf_cur, out_buf_size) != out_buf_size) - { - mz_zip_set_error(pZip, MZ_ZIP_WRITE_CALLBACK_FAILED); - status = TINFL_STATUS_FAILED; - break; - } - -#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS - file_crc32 = (mz_uint32)mz_crc32(file_crc32, pWrite_buf_cur, out_buf_size); -#endif - if ((out_buf_ofs += out_buf_size) > file_stat.m_uncomp_size) - { - mz_zip_set_error(pZip, MZ_ZIP_DECOMPRESSION_FAILED); - status = TINFL_STATUS_FAILED; - break; - } - } - } while ((status == TINFL_STATUS_NEEDS_MORE_INPUT) || (status == TINFL_STATUS_HAS_MORE_OUTPUT)); - } - } - - if ((status == TINFL_STATUS_DONE) && (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA))) - { - /* Make sure the entire file was decompressed, and check its CRC. */ - if (out_buf_ofs != file_stat.m_uncomp_size) - { - mz_zip_set_error(pZip, MZ_ZIP_UNEXPECTED_DECOMPRESSED_SIZE); - status = TINFL_STATUS_FAILED; - } -#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS - else if (file_crc32 != file_stat.m_crc32) - { - mz_zip_set_error(pZip, MZ_ZIP_DECOMPRESSION_FAILED); - status = TINFL_STATUS_FAILED; - } -#endif - } - - if (!pZip->m_pState->m_pMem) - pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); - - if (pWrite_buf) - pZip->m_pFree(pZip->m_pAlloc_opaque, pWrite_buf); - - return status == TINFL_STATUS_DONE; -} - -mz_bool mz_zip_reader_extract_file_to_callback(mz_zip_archive *pZip, const char *pFilename, mz_file_write_func pCallback, void *pOpaque, mz_uint flags) -{ - mz_uint32 file_index; - if (!mz_zip_reader_locate_file_v2(pZip, pFilename, NULL, flags, &file_index)) - return MZ_FALSE; - - return mz_zip_reader_extract_to_callback(pZip, file_index, pCallback, pOpaque, flags); -} - -mz_zip_reader_extract_iter_state* mz_zip_reader_extract_iter_new(mz_zip_archive *pZip, mz_uint file_index, mz_uint flags) -{ - mz_zip_reader_extract_iter_state *pState; - mz_uint32 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; - mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32; - - /* Argument sanity check */ - if ((!pZip) || (!pZip->m_pState)) - return NULL; - - /* Allocate an iterator status structure */ - pState = (mz_zip_reader_extract_iter_state*)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(mz_zip_reader_extract_iter_state)); - if (!pState) - { - mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); - return NULL; - } - - /* Fetch file details */ - if (!mz_zip_reader_file_stat(pZip, file_index, &pState->file_stat)) - { - pZip->m_pFree(pZip->m_pAlloc_opaque, pState); - return NULL; - } - - /* Encryption and patch files are not supported. */ - if (pState->file_stat.m_bit_flag & (MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_COMPRESSED_PATCH_FLAG)) - { - mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION); - pZip->m_pFree(pZip->m_pAlloc_opaque, pState); - return NULL; - } - - /* This function only supports decompressing stored and deflate. */ - if ((!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (pState->file_stat.m_method != 0) && (pState->file_stat.m_method != MZ_DEFLATED)) - { - mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_METHOD); - pZip->m_pFree(pZip->m_pAlloc_opaque, pState); - return NULL; - } - - /* Init state - save args */ - pState->pZip = pZip; - pState->flags = flags; - - /* Init state - reset variables to defaults */ - pState->status = TINFL_STATUS_DONE; -#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS - pState->file_crc32 = MZ_CRC32_INIT; -#endif - pState->read_buf_ofs = 0; - pState->out_buf_ofs = 0; - pState->pRead_buf = NULL; - pState->pWrite_buf = NULL; - pState->out_blk_remain = 0; - - /* Read and parse the local directory entry. */ - pState->cur_file_ofs = pState->file_stat.m_local_header_ofs; - if (pZip->m_pRead(pZip->m_pIO_opaque, pState->cur_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE) - { - mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); - pZip->m_pFree(pZip->m_pAlloc_opaque, pState); - return NULL; - } - - if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG) - { - mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); - pZip->m_pFree(pZip->m_pAlloc_opaque, pState); - return NULL; - } - - pState->cur_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS); - if ((pState->cur_file_ofs + pState->file_stat.m_comp_size) > pZip->m_archive_size) - { - mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); - pZip->m_pFree(pZip->m_pAlloc_opaque, pState); - return NULL; - } - - /* Decompress the file either directly from memory or from a file input buffer. */ - if (pZip->m_pState->m_pMem) - { - pState->pRead_buf = (mz_uint8 *)pZip->m_pState->m_pMem + pState->cur_file_ofs; - pState->read_buf_size = pState->read_buf_avail = pState->file_stat.m_comp_size; - pState->comp_remaining = pState->file_stat.m_comp_size; - } - else - { - if (!((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!pState->file_stat.m_method))) - { - /* Decompression required, therefore intermediate read buffer required */ - pState->read_buf_size = MZ_MIN(pState->file_stat.m_comp_size, MZ_ZIP_MAX_IO_BUF_SIZE); - if (NULL == (pState->pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)pState->read_buf_size))) - { - mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); - pZip->m_pFree(pZip->m_pAlloc_opaque, pState); - return NULL; - } - } - else - { - /* Decompression not required - we will be reading directly into user buffer, no temp buf required */ - pState->read_buf_size = 0; - } - pState->read_buf_avail = 0; - pState->comp_remaining = pState->file_stat.m_comp_size; - } - - if (!((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!pState->file_stat.m_method))) - { - /* Decompression required, init decompressor */ - tinfl_init( &pState->inflator ); - - /* Allocate write buffer */ - if (NULL == (pState->pWrite_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, TINFL_LZ_DICT_SIZE))) - { - mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); - if (pState->pRead_buf) - pZip->m_pFree(pZip->m_pAlloc_opaque, pState->pRead_buf); - pZip->m_pFree(pZip->m_pAlloc_opaque, pState); - return NULL; - } - } - - return pState; -} - -mz_zip_reader_extract_iter_state* mz_zip_reader_extract_file_iter_new(mz_zip_archive *pZip, const char *pFilename, mz_uint flags) -{ - mz_uint32 file_index; - - /* Locate file index by name */ - if (!mz_zip_reader_locate_file_v2(pZip, pFilename, NULL, flags, &file_index)) - return NULL; - - /* Construct iterator */ - return mz_zip_reader_extract_iter_new(pZip, file_index, flags); -} - -size_t mz_zip_reader_extract_iter_read(mz_zip_reader_extract_iter_state* pState, void* pvBuf, size_t buf_size) -{ - size_t copied_to_caller = 0; - - /* Argument sanity check */ - if ((!pState) || (!pState->pZip) || (!pState->pZip->m_pState) || (!pvBuf)) - return 0; - - if ((pState->flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!pState->file_stat.m_method)) - { - /* The file is stored or the caller has requested the compressed data, calc amount to return. */ - copied_to_caller = (size_t)MZ_MIN( buf_size, pState->comp_remaining ); - - /* Zip is in memory....or requires reading from a file? */ - if (pState->pZip->m_pState->m_pMem) - { - /* Copy data to caller's buffer */ - memcpy( pvBuf, pState->pRead_buf, copied_to_caller ); - pState->pRead_buf = ((mz_uint8*)pState->pRead_buf) + copied_to_caller; - } - else - { - /* Read directly into caller's buffer */ - if (pState->pZip->m_pRead(pState->pZip->m_pIO_opaque, pState->cur_file_ofs, pvBuf, copied_to_caller) != copied_to_caller) - { - /* Failed to read all that was asked for, flag failure and alert user */ - mz_zip_set_error(pState->pZip, MZ_ZIP_FILE_READ_FAILED); - pState->status = TINFL_STATUS_FAILED; - copied_to_caller = 0; - } - } - -#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS - /* Compute CRC if not returning compressed data only */ - if (!(pState->flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) - pState->file_crc32 = (mz_uint32)mz_crc32(pState->file_crc32, (const mz_uint8 *)pvBuf, copied_to_caller); -#endif - - /* Advance offsets, dec counters */ - pState->cur_file_ofs += copied_to_caller; - pState->out_buf_ofs += copied_to_caller; - pState->comp_remaining -= copied_to_caller; - } - else - { - do - { - /* Calc ptr to write buffer - given current output pos and block size */ - mz_uint8 *pWrite_buf_cur = (mz_uint8 *)pState->pWrite_buf + (pState->out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1)); - - /* Calc max output size - given current output pos and block size */ - size_t in_buf_size, out_buf_size = TINFL_LZ_DICT_SIZE - (pState->out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1)); - - if (!pState->out_blk_remain) - { - /* Read more data from file if none available (and reading from file) */ - if ((!pState->read_buf_avail) && (!pState->pZip->m_pState->m_pMem)) - { - /* Calc read size */ - pState->read_buf_avail = MZ_MIN(pState->read_buf_size, pState->comp_remaining); - if (pState->pZip->m_pRead(pState->pZip->m_pIO_opaque, pState->cur_file_ofs, pState->pRead_buf, (size_t)pState->read_buf_avail) != pState->read_buf_avail) - { - mz_zip_set_error(pState->pZip, MZ_ZIP_FILE_READ_FAILED); - pState->status = TINFL_STATUS_FAILED; - break; - } - - /* Advance offsets, dec counters */ - pState->cur_file_ofs += pState->read_buf_avail; - pState->comp_remaining -= pState->read_buf_avail; - pState->read_buf_ofs = 0; - } - - /* Perform decompression */ - in_buf_size = (size_t)pState->read_buf_avail; - pState->status = tinfl_decompress(&pState->inflator, (const mz_uint8 *)pState->pRead_buf + pState->read_buf_ofs, &in_buf_size, (mz_uint8 *)pState->pWrite_buf, pWrite_buf_cur, &out_buf_size, pState->comp_remaining ? TINFL_FLAG_HAS_MORE_INPUT : 0); - pState->read_buf_avail -= in_buf_size; - pState->read_buf_ofs += in_buf_size; - - /* Update current output block size remaining */ - pState->out_blk_remain = out_buf_size; - } - - if (pState->out_blk_remain) - { - /* Calc amount to return. */ - size_t to_copy = MZ_MIN( (buf_size - copied_to_caller), pState->out_blk_remain ); - - /* Copy data to caller's buffer */ - memcpy( (uint8_t*)pvBuf + copied_to_caller, pWrite_buf_cur, to_copy ); - -#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS - /* Perform CRC */ - pState->file_crc32 = (mz_uint32)mz_crc32(pState->file_crc32, pWrite_buf_cur, to_copy); -#endif - - /* Decrement data consumed from block */ - pState->out_blk_remain -= to_copy; - - /* Inc output offset, while performing sanity check */ - if ((pState->out_buf_ofs += to_copy) > pState->file_stat.m_uncomp_size) - { - mz_zip_set_error(pState->pZip, MZ_ZIP_DECOMPRESSION_FAILED); - pState->status = TINFL_STATUS_FAILED; - break; - } - - /* Increment counter of data copied to caller */ - copied_to_caller += to_copy; - } - } while ( (copied_to_caller < buf_size) && ((pState->status == TINFL_STATUS_NEEDS_MORE_INPUT) || (pState->status == TINFL_STATUS_HAS_MORE_OUTPUT)) ); - } - - /* Return how many bytes were copied into user buffer */ - return copied_to_caller; -} - -mz_bool mz_zip_reader_extract_iter_free(mz_zip_reader_extract_iter_state* pState) -{ - int status; - - /* Argument sanity check */ - if ((!pState) || (!pState->pZip) || (!pState->pZip->m_pState)) - return MZ_FALSE; - - /* Was decompression completed and requested? */ - if ((pState->status == TINFL_STATUS_DONE) && (!(pState->flags & MZ_ZIP_FLAG_COMPRESSED_DATA))) - { - /* Make sure the entire file was decompressed, and check its CRC. */ - if (pState->out_buf_ofs != pState->file_stat.m_uncomp_size) - { - mz_zip_set_error(pState->pZip, MZ_ZIP_UNEXPECTED_DECOMPRESSED_SIZE); - pState->status = TINFL_STATUS_FAILED; - } -#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS - else if (pState->file_crc32 != pState->file_stat.m_crc32) - { - mz_zip_set_error(pState->pZip, MZ_ZIP_DECOMPRESSION_FAILED); - pState->status = TINFL_STATUS_FAILED; - } -#endif - } - - /* Free buffers */ - if (!pState->pZip->m_pState->m_pMem) - pState->pZip->m_pFree(pState->pZip->m_pAlloc_opaque, pState->pRead_buf); - if (pState->pWrite_buf) - pState->pZip->m_pFree(pState->pZip->m_pAlloc_opaque, pState->pWrite_buf); - - /* Save status */ - status = pState->status; - - /* Free context */ - pState->pZip->m_pFree(pState->pZip->m_pAlloc_opaque, pState); - - return status == TINFL_STATUS_DONE; -} - -#ifndef MINIZ_NO_STDIO -static size_t mz_zip_file_write_callback(void *pOpaque, mz_uint64 ofs, const void *pBuf, size_t n) -{ - (void)ofs; - - return MZ_FWRITE(pBuf, 1, n, (MZ_FILE *)pOpaque); -} - -mz_bool mz_zip_reader_extract_to_file(mz_zip_archive *pZip, mz_uint file_index, const char *pDst_filename, mz_uint flags) -{ - mz_bool status; - mz_zip_archive_file_stat file_stat; - MZ_FILE *pFile; - - if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat)) - return MZ_FALSE; - - if ((file_stat.m_is_directory) || (!file_stat.m_is_supported)) - return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_FEATURE); - - pFile = MZ_FOPEN(pDst_filename, "wb"); - if (!pFile) - return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED); - - status = mz_zip_reader_extract_to_callback(pZip, file_index, mz_zip_file_write_callback, pFile, flags); - - if (MZ_FCLOSE(pFile) == EOF) - { - if (status) - mz_zip_set_error(pZip, MZ_ZIP_FILE_CLOSE_FAILED); - - status = MZ_FALSE; - } - -#if !defined(MINIZ_NO_TIME) && !defined(MINIZ_NO_STDIO) - if (status) - mz_zip_set_file_times(pDst_filename, file_stat.m_time, file_stat.m_time); -#endif - - return status; -} - -mz_bool mz_zip_reader_extract_file_to_file(mz_zip_archive *pZip, const char *pArchive_filename, const char *pDst_filename, mz_uint flags) -{ - mz_uint32 file_index; - if (!mz_zip_reader_locate_file_v2(pZip, pArchive_filename, NULL, flags, &file_index)) - return MZ_FALSE; - - return mz_zip_reader_extract_to_file(pZip, file_index, pDst_filename, flags); -} - -mz_bool mz_zip_reader_extract_to_cfile(mz_zip_archive *pZip, mz_uint file_index, MZ_FILE *pFile, mz_uint flags) -{ - mz_zip_archive_file_stat file_stat; - - if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat)) - return MZ_FALSE; - - if ((file_stat.m_is_directory) || (!file_stat.m_is_supported)) - return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_FEATURE); - - return mz_zip_reader_extract_to_callback(pZip, file_index, mz_zip_file_write_callback, pFile, flags); -} - -mz_bool mz_zip_reader_extract_file_to_cfile(mz_zip_archive *pZip, const char *pArchive_filename, MZ_FILE *pFile, mz_uint flags) -{ - mz_uint32 file_index; - if (!mz_zip_reader_locate_file_v2(pZip, pArchive_filename, NULL, flags, &file_index)) - return MZ_FALSE; - - return mz_zip_reader_extract_to_cfile(pZip, file_index, pFile, flags); -} -#endif /* #ifndef MINIZ_NO_STDIO */ - -static size_t mz_zip_compute_crc32_callback(void *pOpaque, mz_uint64 file_ofs, const void *pBuf, size_t n) -{ - mz_uint32 *p = (mz_uint32 *)pOpaque; - (void)file_ofs; - *p = (mz_uint32)mz_crc32(*p, (const mz_uint8 *)pBuf, n); - return n; -} - -mz_bool mz_zip_validate_file(mz_zip_archive *pZip, mz_uint file_index, mz_uint flags) -{ - mz_zip_archive_file_stat file_stat; - mz_zip_internal_state *pState; - const mz_uint8 *pCentral_dir_header; - mz_bool found_zip64_ext_data_in_cdir = MZ_FALSE; - mz_bool found_zip64_ext_data_in_ldir = MZ_FALSE; - mz_uint32 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; - mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32; - mz_uint64 local_header_ofs = 0; - mz_uint32 local_header_filename_len, local_header_extra_len, local_header_crc32; - mz_uint64 local_header_comp_size, local_header_uncomp_size; - mz_uint32 uncomp_crc32 = MZ_CRC32_INIT; - mz_bool has_data_descriptor; - mz_uint32 local_header_bit_flags; - - mz_zip_array file_data_array; - mz_zip_array_init(&file_data_array, 1); - - if ((!pZip) || (!pZip->m_pState) || (!pZip->m_pAlloc) || (!pZip->m_pFree) || (!pZip->m_pRead)) - return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - - if (file_index > pZip->m_total_files) - return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - - pState = pZip->m_pState; - - pCentral_dir_header = mz_zip_get_cdh(pZip, file_index); - - if (!mz_zip_file_stat_internal(pZip, file_index, pCentral_dir_header, &file_stat, &found_zip64_ext_data_in_cdir)) - return MZ_FALSE; - - /* A directory or zero length file */ - if ((file_stat.m_is_directory) || (!file_stat.m_uncomp_size)) - return MZ_TRUE; - - /* Encryption and patch files are not supported. */ - if (file_stat.m_is_encrypted) - return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION); - - /* This function only supports stored and deflate. */ - if ((file_stat.m_method != 0) && (file_stat.m_method != MZ_DEFLATED)) - return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_METHOD); - - if (!file_stat.m_is_supported) - return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_FEATURE); - - /* Read and parse the local directory entry. */ - local_header_ofs = file_stat.m_local_header_ofs; - if (pZip->m_pRead(pZip->m_pIO_opaque, local_header_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE) - return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); - - if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG) - return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); - - local_header_filename_len = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS); - local_header_extra_len = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS); - local_header_comp_size = MZ_READ_LE32(pLocal_header + MZ_ZIP_LDH_COMPRESSED_SIZE_OFS); - local_header_uncomp_size = MZ_READ_LE32(pLocal_header + MZ_ZIP_LDH_DECOMPRESSED_SIZE_OFS); - local_header_crc32 = MZ_READ_LE32(pLocal_header + MZ_ZIP_LDH_CRC32_OFS); - local_header_bit_flags = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_BIT_FLAG_OFS); - has_data_descriptor = (local_header_bit_flags & 8) != 0; - - if (local_header_filename_len != strlen(file_stat.m_filename)) - return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); - - if ((local_header_ofs + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + local_header_filename_len + local_header_extra_len + file_stat.m_comp_size) > pZip->m_archive_size) - return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); - - if (!mz_zip_array_resize(pZip, &file_data_array, MZ_MAX(local_header_filename_len, local_header_extra_len), MZ_FALSE)) - return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); - - if (local_header_filename_len) - { - if (pZip->m_pRead(pZip->m_pIO_opaque, local_header_ofs + MZ_ZIP_LOCAL_DIR_HEADER_SIZE, file_data_array.m_p, local_header_filename_len) != local_header_filename_len) - { - mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); - goto handle_failure; - } - - /* I've seen 1 archive that had the same pathname, but used backslashes in the local dir and forward slashes in the central dir. Do we care about this? For now, this case will fail validation. */ - if (memcmp(file_stat.m_filename, file_data_array.m_p, local_header_filename_len) != 0) - { - mz_zip_set_error(pZip, MZ_ZIP_VALIDATION_FAILED); - goto handle_failure; - } - } - - if ((local_header_extra_len) && ((local_header_comp_size == MZ_UINT32_MAX) || (local_header_uncomp_size == MZ_UINT32_MAX))) - { - mz_uint32 extra_size_remaining = local_header_extra_len; - const mz_uint8 *pExtra_data = (const mz_uint8 *)file_data_array.m_p; - - if (pZip->m_pRead(pZip->m_pIO_opaque, local_header_ofs + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + local_header_filename_len, file_data_array.m_p, local_header_extra_len) != local_header_extra_len) - { - mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); - goto handle_failure; - } - - do - { - mz_uint32 field_id, field_data_size, field_total_size; - - if (extra_size_remaining < (sizeof(mz_uint16) * 2)) - return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); - - field_id = MZ_READ_LE16(pExtra_data); - field_data_size = MZ_READ_LE16(pExtra_data + sizeof(mz_uint16)); - field_total_size = field_data_size + sizeof(mz_uint16) * 2; - - if (field_total_size > extra_size_remaining) - return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); - - if (field_id == MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID) - { - const mz_uint8 *pSrc_field_data = pExtra_data + sizeof(mz_uint32); - - if (field_data_size < sizeof(mz_uint64) * 2) - { - mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); - goto handle_failure; - } - - local_header_uncomp_size = MZ_READ_LE64(pSrc_field_data); - local_header_comp_size = MZ_READ_LE64(pSrc_field_data + sizeof(mz_uint64)); - - found_zip64_ext_data_in_ldir = MZ_TRUE; - break; - } - - pExtra_data += field_total_size; - extra_size_remaining -= field_total_size; - } while (extra_size_remaining); - } - - /* TODO: parse local header extra data when local_header_comp_size is 0xFFFFFFFF! (big_descriptor.zip) */ - /* I've seen zips in the wild with the data descriptor bit set, but proper local header values and bogus data descriptors */ - if ((has_data_descriptor) && (!local_header_comp_size) && (!local_header_crc32)) - { - mz_uint8 descriptor_buf[32]; - mz_bool has_id; - const mz_uint8 *pSrc; - mz_uint32 file_crc32; - mz_uint64 comp_size = 0, uncomp_size = 0; - - mz_uint32 num_descriptor_uint32s = ((pState->m_zip64) || (found_zip64_ext_data_in_ldir)) ? 6 : 4; - - if (pZip->m_pRead(pZip->m_pIO_opaque, local_header_ofs + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + local_header_filename_len + local_header_extra_len + file_stat.m_comp_size, descriptor_buf, sizeof(mz_uint32) * num_descriptor_uint32s) != (sizeof(mz_uint32) * num_descriptor_uint32s)) - { - mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); - goto handle_failure; - } - - has_id = (MZ_READ_LE32(descriptor_buf) == MZ_ZIP_DATA_DESCRIPTOR_ID); - pSrc = has_id ? (descriptor_buf + sizeof(mz_uint32)) : descriptor_buf; - - file_crc32 = MZ_READ_LE32(pSrc); - - if ((pState->m_zip64) || (found_zip64_ext_data_in_ldir)) - { - comp_size = MZ_READ_LE64(pSrc + sizeof(mz_uint32)); - uncomp_size = MZ_READ_LE64(pSrc + sizeof(mz_uint32) + sizeof(mz_uint64)); - } - else - { - comp_size = MZ_READ_LE32(pSrc + sizeof(mz_uint32)); - uncomp_size = MZ_READ_LE32(pSrc + sizeof(mz_uint32) + sizeof(mz_uint32)); - } - - if ((file_crc32 != file_stat.m_crc32) || (comp_size != file_stat.m_comp_size) || (uncomp_size != file_stat.m_uncomp_size)) - { - mz_zip_set_error(pZip, MZ_ZIP_VALIDATION_FAILED); - goto handle_failure; - } - } - else - { - if ((local_header_crc32 != file_stat.m_crc32) || (local_header_comp_size != file_stat.m_comp_size) || (local_header_uncomp_size != file_stat.m_uncomp_size)) - { - mz_zip_set_error(pZip, MZ_ZIP_VALIDATION_FAILED); - goto handle_failure; - } - } - - mz_zip_array_clear(pZip, &file_data_array); - - if ((flags & MZ_ZIP_FLAG_VALIDATE_HEADERS_ONLY) == 0) - { - if (!mz_zip_reader_extract_to_callback(pZip, file_index, mz_zip_compute_crc32_callback, &uncomp_crc32, 0)) - return MZ_FALSE; - - /* 1 more check to be sure, although the extract checks too. */ - if (uncomp_crc32 != file_stat.m_crc32) - { - mz_zip_set_error(pZip, MZ_ZIP_VALIDATION_FAILED); - return MZ_FALSE; - } - } - - return MZ_TRUE; - -handle_failure: - mz_zip_array_clear(pZip, &file_data_array); - return MZ_FALSE; -} - -mz_bool mz_zip_validate_archive(mz_zip_archive *pZip, mz_uint flags) -{ - mz_zip_internal_state *pState; - uint32_t i; - - if ((!pZip) || (!pZip->m_pState) || (!pZip->m_pAlloc) || (!pZip->m_pFree) || (!pZip->m_pRead)) - return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - - pState = pZip->m_pState; - - /* Basic sanity checks */ - if (!pState->m_zip64) - { - if (pZip->m_total_files > MZ_UINT16_MAX) - return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); - - if (pZip->m_archive_size > MZ_UINT32_MAX) - return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); - } - else - { - if (pZip->m_total_files >= MZ_UINT32_MAX) - return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); - - if (pState->m_central_dir.m_size >= MZ_UINT32_MAX) - return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); - } - - for (i = 0; i < pZip->m_total_files; i++) - { - if (MZ_ZIP_FLAG_VALIDATE_LOCATE_FILE_FLAG & flags) - { - mz_uint32 found_index; - mz_zip_archive_file_stat stat; - - if (!mz_zip_reader_file_stat(pZip, i, &stat)) - return MZ_FALSE; - - if (!mz_zip_reader_locate_file_v2(pZip, stat.m_filename, NULL, 0, &found_index)) - return MZ_FALSE; - - /* This check can fail if there are duplicate filenames in the archive (which we don't check for when writing - that's up to the user) */ - if (found_index != i) - return mz_zip_set_error(pZip, MZ_ZIP_VALIDATION_FAILED); - } - - if (!mz_zip_validate_file(pZip, i, flags)) - return MZ_FALSE; - } - - return MZ_TRUE; -} - -mz_bool mz_zip_validate_mem_archive(const void *pMem, size_t size, mz_uint flags, mz_zip_error *pErr) -{ - mz_bool success = MZ_TRUE; - mz_zip_archive zip; - mz_zip_error actual_err = MZ_ZIP_NO_ERROR; - - if ((!pMem) || (!size)) - { - if (pErr) - *pErr = MZ_ZIP_INVALID_PARAMETER; - return MZ_FALSE; - } - - mz_zip_zero_struct(&zip); - - if (!mz_zip_reader_init_mem(&zip, pMem, size, flags)) - { - if (pErr) - *pErr = zip.m_last_error; - return MZ_FALSE; - } - - if (!mz_zip_validate_archive(&zip, flags)) - { - actual_err = zip.m_last_error; - success = MZ_FALSE; - } - - if (!mz_zip_reader_end_internal(&zip, success)) - { - if (!actual_err) - actual_err = zip.m_last_error; - success = MZ_FALSE; - } - - if (pErr) - *pErr = actual_err; - - return success; -} - -#ifndef MINIZ_NO_STDIO -mz_bool mz_zip_validate_file_archive(const char *pFilename, mz_uint flags, mz_zip_error *pErr) -{ - mz_bool success = MZ_TRUE; - mz_zip_archive zip; - mz_zip_error actual_err = MZ_ZIP_NO_ERROR; - - if (!pFilename) - { - if (pErr) - *pErr = MZ_ZIP_INVALID_PARAMETER; - return MZ_FALSE; - } - - mz_zip_zero_struct(&zip); - - if (!mz_zip_reader_init_file_v2(&zip, pFilename, flags, 0, 0)) - { - if (pErr) - *pErr = zip.m_last_error; - return MZ_FALSE; - } - - if (!mz_zip_validate_archive(&zip, flags)) - { - actual_err = zip.m_last_error; - success = MZ_FALSE; - } - - if (!mz_zip_reader_end_internal(&zip, success)) - { - if (!actual_err) - actual_err = zip.m_last_error; - success = MZ_FALSE; - } - - if (pErr) - *pErr = actual_err; - - return success; -} -#endif /* #ifndef MINIZ_NO_STDIO */ - -/* ------------------- .ZIP archive writing */ - -#ifndef MINIZ_NO_ARCHIVE_WRITING_APIS - -static MZ_FORCEINLINE void mz_write_le16(mz_uint8 *p, mz_uint16 v) -{ - p[0] = (mz_uint8)v; - p[1] = (mz_uint8)(v >> 8); -} -static MZ_FORCEINLINE void mz_write_le32(mz_uint8 *p, mz_uint32 v) -{ - p[0] = (mz_uint8)v; - p[1] = (mz_uint8)(v >> 8); - p[2] = (mz_uint8)(v >> 16); - p[3] = (mz_uint8)(v >> 24); -} -static MZ_FORCEINLINE void mz_write_le64(mz_uint8 *p, mz_uint64 v) -{ - mz_write_le32(p, (mz_uint32)v); - mz_write_le32(p + sizeof(mz_uint32), (mz_uint32)(v >> 32)); -} - -#define MZ_WRITE_LE16(p, v) mz_write_le16((mz_uint8 *)(p), (mz_uint16)(v)) -#define MZ_WRITE_LE32(p, v) mz_write_le32((mz_uint8 *)(p), (mz_uint32)(v)) -#define MZ_WRITE_LE64(p, v) mz_write_le64((mz_uint8 *)(p), (mz_uint64)(v)) - -static size_t mz_zip_heap_write_func(void *pOpaque, mz_uint64 file_ofs, const void *pBuf, size_t n) -{ - mz_zip_archive *pZip = (mz_zip_archive *)pOpaque; - mz_zip_internal_state *pState = pZip->m_pState; - mz_uint64 new_size = MZ_MAX(file_ofs + n, pState->m_mem_size); - - if (!n) - return 0; - - /* An allocation this big is likely to just fail on 32-bit systems, so don't even go there. */ - if ((sizeof(size_t) == sizeof(mz_uint32)) && (new_size > 0x7FFFFFFF)) - { - mz_zip_set_error(pZip, MZ_ZIP_FILE_TOO_LARGE); - return 0; - } - - if (new_size > pState->m_mem_capacity) - { - void *pNew_block; - size_t new_capacity = MZ_MAX(64, pState->m_mem_capacity); - - while (new_capacity < new_size) - new_capacity *= 2; - - if (NULL == (pNew_block = pZip->m_pRealloc(pZip->m_pAlloc_opaque, pState->m_pMem, 1, new_capacity))) - { - mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); - return 0; - } - - pState->m_pMem = pNew_block; - pState->m_mem_capacity = new_capacity; - } - memcpy((mz_uint8 *)pState->m_pMem + file_ofs, pBuf, n); - pState->m_mem_size = (size_t)new_size; - return n; -} - -static mz_bool mz_zip_writer_end_internal(mz_zip_archive *pZip, mz_bool set_last_error) -{ - mz_zip_internal_state *pState; - mz_bool status = MZ_TRUE; - - if ((!pZip) || (!pZip->m_pState) || (!pZip->m_pAlloc) || (!pZip->m_pFree) || ((pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) && (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED))) - { - if (set_last_error) - mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - return MZ_FALSE; - } - - pState = pZip->m_pState; - pZip->m_pState = NULL; - mz_zip_array_clear(pZip, &pState->m_central_dir); - mz_zip_array_clear(pZip, &pState->m_central_dir_offsets); - mz_zip_array_clear(pZip, &pState->m_sorted_central_dir_offsets); - -#ifndef MINIZ_NO_STDIO - if (pState->m_pFile) - { - if (pZip->m_zip_type == MZ_ZIP_TYPE_FILE) - { - if (MZ_FCLOSE(pState->m_pFile) == EOF) - { - if (set_last_error) - mz_zip_set_error(pZip, MZ_ZIP_FILE_CLOSE_FAILED); - status = MZ_FALSE; - } - } - - pState->m_pFile = NULL; - } -#endif /* #ifndef MINIZ_NO_STDIO */ - - if ((pZip->m_pWrite == mz_zip_heap_write_func) && (pState->m_pMem)) - { - pZip->m_pFree(pZip->m_pAlloc_opaque, pState->m_pMem); - pState->m_pMem = NULL; - } - - pZip->m_pFree(pZip->m_pAlloc_opaque, pState); - pZip->m_zip_mode = MZ_ZIP_MODE_INVALID; - return status; -} - -mz_bool mz_zip_writer_init_v2(mz_zip_archive *pZip, mz_uint64 existing_size, mz_uint flags) -{ - mz_bool zip64 = (flags & MZ_ZIP_FLAG_WRITE_ZIP64) != 0; - - if ((!pZip) || (pZip->m_pState) || (!pZip->m_pWrite) || (pZip->m_zip_mode != MZ_ZIP_MODE_INVALID)) - return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - - if (flags & MZ_ZIP_FLAG_WRITE_ALLOW_READING) - { - if (!pZip->m_pRead) - return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - } - - if (pZip->m_file_offset_alignment) - { - /* Ensure user specified file offset alignment is a power of 2. */ - if (pZip->m_file_offset_alignment & (pZip->m_file_offset_alignment - 1)) - return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - } - - if (!pZip->m_pAlloc) - pZip->m_pAlloc = miniz_def_alloc_func; - if (!pZip->m_pFree) - pZip->m_pFree = miniz_def_free_func; - if (!pZip->m_pRealloc) - pZip->m_pRealloc = miniz_def_realloc_func; - - pZip->m_archive_size = existing_size; - pZip->m_central_directory_file_ofs = 0; - pZip->m_total_files = 0; - - if (NULL == (pZip->m_pState = (mz_zip_internal_state *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(mz_zip_internal_state)))) - return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); - - memset(pZip->m_pState, 0, sizeof(mz_zip_internal_state)); - - MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir, sizeof(mz_uint8)); - MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir_offsets, sizeof(mz_uint32)); - MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_sorted_central_dir_offsets, sizeof(mz_uint32)); - - pZip->m_pState->m_zip64 = zip64; - pZip->m_pState->m_zip64_has_extended_info_fields = zip64; - - pZip->m_zip_type = MZ_ZIP_TYPE_USER; - pZip->m_zip_mode = MZ_ZIP_MODE_WRITING; - - return MZ_TRUE; -} - -mz_bool mz_zip_writer_init(mz_zip_archive *pZip, mz_uint64 existing_size) -{ - return mz_zip_writer_init_v2(pZip, existing_size, 0); -} - -mz_bool mz_zip_writer_init_heap_v2(mz_zip_archive *pZip, size_t size_to_reserve_at_beginning, size_t initial_allocation_size, mz_uint flags) -{ - pZip->m_pWrite = mz_zip_heap_write_func; - pZip->m_pNeeds_keepalive = NULL; - - if (flags & MZ_ZIP_FLAG_WRITE_ALLOW_READING) - pZip->m_pRead = mz_zip_mem_read_func; - - pZip->m_pIO_opaque = pZip; - - if (!mz_zip_writer_init_v2(pZip, size_to_reserve_at_beginning, flags)) - return MZ_FALSE; - - pZip->m_zip_type = MZ_ZIP_TYPE_HEAP; - - if (0 != (initial_allocation_size = MZ_MAX(initial_allocation_size, size_to_reserve_at_beginning))) - { - if (NULL == (pZip->m_pState->m_pMem = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, initial_allocation_size))) - { - mz_zip_writer_end_internal(pZip, MZ_FALSE); - return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); - } - pZip->m_pState->m_mem_capacity = initial_allocation_size; - } - - return MZ_TRUE; -} - -mz_bool mz_zip_writer_init_heap(mz_zip_archive *pZip, size_t size_to_reserve_at_beginning, size_t initial_allocation_size) -{ - return mz_zip_writer_init_heap_v2(pZip, size_to_reserve_at_beginning, initial_allocation_size, 0); -} - -#ifndef MINIZ_NO_STDIO -static size_t mz_zip_file_write_func(void *pOpaque, mz_uint64 file_ofs, const void *pBuf, size_t n) -{ - mz_zip_archive *pZip = (mz_zip_archive *)pOpaque; - mz_int64 cur_ofs = MZ_FTELL64(pZip->m_pState->m_pFile); - - file_ofs += pZip->m_pState->m_file_archive_start_ofs; - - if (((mz_int64)file_ofs < 0) || (((cur_ofs != (mz_int64)file_ofs)) && (MZ_FSEEK64(pZip->m_pState->m_pFile, (mz_int64)file_ofs, SEEK_SET)))) - { - mz_zip_set_error(pZip, MZ_ZIP_FILE_SEEK_FAILED); - return 0; - } - - return MZ_FWRITE(pBuf, 1, n, pZip->m_pState->m_pFile); -} - -mz_bool mz_zip_writer_init_file(mz_zip_archive *pZip, const char *pFilename, mz_uint64 size_to_reserve_at_beginning) -{ - return mz_zip_writer_init_file_v2(pZip, pFilename, size_to_reserve_at_beginning, 0); -} - -mz_bool mz_zip_writer_init_file_v2(mz_zip_archive *pZip, const char *pFilename, mz_uint64 size_to_reserve_at_beginning, mz_uint flags) -{ - MZ_FILE *pFile; - - pZip->m_pWrite = mz_zip_file_write_func; - pZip->m_pNeeds_keepalive = NULL; - - if (flags & MZ_ZIP_FLAG_WRITE_ALLOW_READING) - pZip->m_pRead = mz_zip_file_read_func; - - pZip->m_pIO_opaque = pZip; - - if (!mz_zip_writer_init_v2(pZip, size_to_reserve_at_beginning, flags)) - return MZ_FALSE; - - if (NULL == (pFile = MZ_FOPEN(pFilename, (flags & MZ_ZIP_FLAG_WRITE_ALLOW_READING) ? "w+b" : "wb"))) - { - mz_zip_writer_end(pZip); - return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED); - } - - pZip->m_pState->m_pFile = pFile; - pZip->m_zip_type = MZ_ZIP_TYPE_FILE; - - if (size_to_reserve_at_beginning) - { - mz_uint64 cur_ofs = 0; - char buf[4096]; - - MZ_CLEAR_OBJ(buf); - - do - { - size_t n = (size_t)MZ_MIN(sizeof(buf), size_to_reserve_at_beginning); - if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_ofs, buf, n) != n) - { - mz_zip_writer_end(pZip); - return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); - } - cur_ofs += n; - size_to_reserve_at_beginning -= n; - } while (size_to_reserve_at_beginning); - } - - return MZ_TRUE; -} - -mz_bool mz_zip_writer_init_cfile(mz_zip_archive *pZip, MZ_FILE *pFile, mz_uint flags) -{ - pZip->m_pWrite = mz_zip_file_write_func; - pZip->m_pNeeds_keepalive = NULL; - - if (flags & MZ_ZIP_FLAG_WRITE_ALLOW_READING) - pZip->m_pRead = mz_zip_file_read_func; - - pZip->m_pIO_opaque = pZip; - - if (!mz_zip_writer_init_v2(pZip, 0, flags)) - return MZ_FALSE; - - pZip->m_pState->m_pFile = pFile; - pZip->m_pState->m_file_archive_start_ofs = MZ_FTELL64(pZip->m_pState->m_pFile); - pZip->m_zip_type = MZ_ZIP_TYPE_CFILE; - - return MZ_TRUE; -} -#endif /* #ifndef MINIZ_NO_STDIO */ - -mz_bool mz_zip_writer_init_from_reader_v2(mz_zip_archive *pZip, const char *pFilename, mz_uint flags) -{ - mz_zip_internal_state *pState; - - if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_READING)) - return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - - if (flags & MZ_ZIP_FLAG_WRITE_ZIP64) - { - /* We don't support converting a non-zip64 file to zip64 - this seems like more trouble than it's worth. (What about the existing 32-bit data descriptors that could follow the compressed data?) */ - if (!pZip->m_pState->m_zip64) - return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - } - - /* No sense in trying to write to an archive that's already at the support max size */ - if (pZip->m_pState->m_zip64) - { - if (pZip->m_total_files == MZ_UINT32_MAX) - return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); - } - else - { - if (pZip->m_total_files == MZ_UINT16_MAX) - return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); - - if ((pZip->m_archive_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + MZ_ZIP_LOCAL_DIR_HEADER_SIZE) > MZ_UINT32_MAX) - return mz_zip_set_error(pZip, MZ_ZIP_FILE_TOO_LARGE); - } - - pState = pZip->m_pState; - - if (pState->m_pFile) - { -#ifdef MINIZ_NO_STDIO - (void)pFilename; - return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); -#else - if (pZip->m_pIO_opaque != pZip) - return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - - if (pZip->m_zip_type == MZ_ZIP_TYPE_FILE) - { - if (!pFilename) - return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - - /* Archive is being read from stdio and was originally opened only for reading. Try to reopen as writable. */ - if (NULL == (pState->m_pFile = MZ_FREOPEN(pFilename, "r+b", pState->m_pFile))) - { - /* The mz_zip_archive is now in a bogus state because pState->m_pFile is NULL, so just close it. */ - mz_zip_reader_end_internal(pZip, MZ_FALSE); - return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED); - } - } - - pZip->m_pWrite = mz_zip_file_write_func; - pZip->m_pNeeds_keepalive = NULL; -#endif /* #ifdef MINIZ_NO_STDIO */ - } - else if (pState->m_pMem) - { - /* Archive lives in a memory block. Assume it's from the heap that we can resize using the realloc callback. */ - if (pZip->m_pIO_opaque != pZip) - return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - - pState->m_mem_capacity = pState->m_mem_size; - pZip->m_pWrite = mz_zip_heap_write_func; - pZip->m_pNeeds_keepalive = NULL; - } - /* Archive is being read via a user provided read function - make sure the user has specified a write function too. */ - else if (!pZip->m_pWrite) - return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - - /* Start writing new files at the archive's current central directory location. */ - /* TODO: We could add a flag that lets the user start writing immediately AFTER the existing central dir - this would be safer. */ - pZip->m_archive_size = pZip->m_central_directory_file_ofs; - pZip->m_central_directory_file_ofs = 0; - - /* Clear the sorted central dir offsets, they aren't useful or maintained now. */ - /* Even though we're now in write mode, files can still be extracted and verified, but file locates will be slow. */ - /* TODO: We could easily maintain the sorted central directory offsets. */ - mz_zip_array_clear(pZip, &pZip->m_pState->m_sorted_central_dir_offsets); - - pZip->m_zip_mode = MZ_ZIP_MODE_WRITING; - - return MZ_TRUE; -} - -mz_bool mz_zip_writer_init_from_reader(mz_zip_archive *pZip, const char *pFilename) -{ - return mz_zip_writer_init_from_reader_v2(pZip, pFilename, 0); -} - -/* TODO: pArchive_name is a terrible name here! */ -mz_bool mz_zip_writer_add_mem(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, mz_uint level_and_flags) -{ - return mz_zip_writer_add_mem_ex(pZip, pArchive_name, pBuf, buf_size, NULL, 0, level_and_flags, 0, 0); -} - -typedef struct -{ - mz_zip_archive *m_pZip; - mz_uint64 m_cur_archive_file_ofs; - mz_uint64 m_comp_size; -} mz_zip_writer_add_state; - -static mz_bool mz_zip_writer_add_put_buf_callback(const void *pBuf, int len, void *pUser) -{ - mz_zip_writer_add_state *pState = (mz_zip_writer_add_state *)pUser; - if ((int)pState->m_pZip->m_pWrite(pState->m_pZip->m_pIO_opaque, pState->m_cur_archive_file_ofs, pBuf, len) != len) - return MZ_FALSE; - - pState->m_cur_archive_file_ofs += len; - pState->m_comp_size += len; - return MZ_TRUE; -} - -#define MZ_ZIP64_MAX_LOCAL_EXTRA_FIELD_SIZE (sizeof(mz_uint16) * 2 + sizeof(mz_uint64) * 2) -#define MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE (sizeof(mz_uint16) * 2 + sizeof(mz_uint64) * 3) -static mz_uint32 mz_zip_writer_create_zip64_extra_data(mz_uint8 *pBuf, mz_uint64 *pUncomp_size, mz_uint64 *pComp_size, mz_uint64 *pLocal_header_ofs) -{ - mz_uint8 *pDst = pBuf; - mz_uint32 field_size = 0; - - MZ_WRITE_LE16(pDst + 0, MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID); - MZ_WRITE_LE16(pDst + 2, 0); - pDst += sizeof(mz_uint16) * 2; - - if (pUncomp_size) - { - MZ_WRITE_LE64(pDst, *pUncomp_size); - pDst += sizeof(mz_uint64); - field_size += sizeof(mz_uint64); - } - - if (pComp_size) - { - MZ_WRITE_LE64(pDst, *pComp_size); - pDst += sizeof(mz_uint64); - field_size += sizeof(mz_uint64); - } - - if (pLocal_header_ofs) - { - MZ_WRITE_LE64(pDst, *pLocal_header_ofs); - pDst += sizeof(mz_uint64); - field_size += sizeof(mz_uint64); - } - - MZ_WRITE_LE16(pBuf + 2, field_size); - - return (mz_uint32)(pDst - pBuf); -} - -static mz_bool mz_zip_writer_create_local_dir_header(mz_zip_archive *pZip, mz_uint8 *pDst, mz_uint16 filename_size, mz_uint16 extra_size, mz_uint64 uncomp_size, mz_uint64 comp_size, mz_uint32 uncomp_crc32, mz_uint16 method, mz_uint16 bit_flags, mz_uint16 dos_time, mz_uint16 dos_date) -{ - (void)pZip; - memset(pDst, 0, MZ_ZIP_LOCAL_DIR_HEADER_SIZE); - MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_SIG_OFS, MZ_ZIP_LOCAL_DIR_HEADER_SIG); - MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_VERSION_NEEDED_OFS, method ? 20 : 0); - MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_BIT_FLAG_OFS, bit_flags); - MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_METHOD_OFS, method); - MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILE_TIME_OFS, dos_time); - MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILE_DATE_OFS, dos_date); - MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_CRC32_OFS, uncomp_crc32); - MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_COMPRESSED_SIZE_OFS, MZ_MIN(comp_size, MZ_UINT32_MAX)); - MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_DECOMPRESSED_SIZE_OFS, MZ_MIN(uncomp_size, MZ_UINT32_MAX)); - MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILENAME_LEN_OFS, filename_size); - MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_EXTRA_LEN_OFS, extra_size); - return MZ_TRUE; -} - -static mz_bool mz_zip_writer_create_central_dir_header(mz_zip_archive *pZip, mz_uint8 *pDst, - mz_uint16 filename_size, mz_uint16 extra_size, mz_uint16 comment_size, - mz_uint64 uncomp_size, mz_uint64 comp_size, mz_uint32 uncomp_crc32, - mz_uint16 method, mz_uint16 bit_flags, mz_uint16 dos_time, mz_uint16 dos_date, - mz_uint64 local_header_ofs, mz_uint32 ext_attributes) -{ - (void)pZip; - memset(pDst, 0, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE); - MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_SIG_OFS, MZ_ZIP_CENTRAL_DIR_HEADER_SIG); - MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_VERSION_NEEDED_OFS, method ? 20 : 0); - MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_BIT_FLAG_OFS, bit_flags); - MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_METHOD_OFS, method); - MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_FILE_TIME_OFS, dos_time); - MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_FILE_DATE_OFS, dos_date); - MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_CRC32_OFS, uncomp_crc32); - MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS, MZ_MIN(comp_size, MZ_UINT32_MAX)); - MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS, MZ_MIN(uncomp_size, MZ_UINT32_MAX)); - MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_FILENAME_LEN_OFS, filename_size); - MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_EXTRA_LEN_OFS, extra_size); - MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_COMMENT_LEN_OFS, comment_size); - MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS, ext_attributes); - MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_LOCAL_HEADER_OFS, MZ_MIN(local_header_ofs, MZ_UINT32_MAX)); - return MZ_TRUE; -} - -static mz_bool mz_zip_writer_add_to_central_dir(mz_zip_archive *pZip, const char *pFilename, mz_uint16 filename_size, - const void *pExtra, mz_uint16 extra_size, const void *pComment, mz_uint16 comment_size, - mz_uint64 uncomp_size, mz_uint64 comp_size, mz_uint32 uncomp_crc32, - mz_uint16 method, mz_uint16 bit_flags, mz_uint16 dos_time, mz_uint16 dos_date, - mz_uint64 local_header_ofs, mz_uint32 ext_attributes, - const char *user_extra_data, mz_uint user_extra_data_len) -{ - mz_zip_internal_state *pState = pZip->m_pState; - mz_uint32 central_dir_ofs = (mz_uint32)pState->m_central_dir.m_size; - size_t orig_central_dir_size = pState->m_central_dir.m_size; - mz_uint8 central_dir_header[MZ_ZIP_CENTRAL_DIR_HEADER_SIZE]; - - if (!pZip->m_pState->m_zip64) - { - if (local_header_ofs > 0xFFFFFFFF) - return mz_zip_set_error(pZip, MZ_ZIP_FILE_TOO_LARGE); - } - - /* miniz doesn't support central dirs >= MZ_UINT32_MAX bytes yet */ - if (((mz_uint64)pState->m_central_dir.m_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_size + extra_size + user_extra_data_len + comment_size) >= MZ_UINT32_MAX) - return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE); - - if (!mz_zip_writer_create_central_dir_header(pZip, central_dir_header, filename_size, (mz_uint16)(extra_size + user_extra_data_len), comment_size, uncomp_size, comp_size, uncomp_crc32, method, bit_flags, dos_time, dos_date, local_header_ofs, ext_attributes)) - return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); - - if ((!mz_zip_array_push_back(pZip, &pState->m_central_dir, central_dir_header, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE)) || - (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pFilename, filename_size)) || - (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pExtra, extra_size)) || - (!mz_zip_array_push_back(pZip, &pState->m_central_dir, user_extra_data, user_extra_data_len)) || - (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pComment, comment_size)) || - (!mz_zip_array_push_back(pZip, &pState->m_central_dir_offsets, ¢ral_dir_ofs, 1))) - { - /* Try to resize the central directory array back into its original state. */ - mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE); - return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); - } - - return MZ_TRUE; -} - -static mz_bool mz_zip_writer_validate_archive_name(const char *pArchive_name) -{ - /* Basic ZIP archive filename validity checks: Valid filenames cannot start with a forward slash, cannot contain a drive letter, and cannot use DOS-style backward slashes. */ - if (*pArchive_name == '/') - return MZ_FALSE; - - /* Making sure the name does not contain drive letters or DOS style backward slashes is the responsibility of the program using miniz*/ - - return MZ_TRUE; -} - -static mz_uint mz_zip_writer_compute_padding_needed_for_file_alignment(mz_zip_archive *pZip) -{ - mz_uint32 n; - if (!pZip->m_file_offset_alignment) - return 0; - n = (mz_uint32)(pZip->m_archive_size & (pZip->m_file_offset_alignment - 1)); - return (mz_uint)((pZip->m_file_offset_alignment - n) & (pZip->m_file_offset_alignment - 1)); -} - -static mz_bool mz_zip_writer_write_zeros(mz_zip_archive *pZip, mz_uint64 cur_file_ofs, mz_uint32 n) -{ - char buf[4096]; - memset(buf, 0, MZ_MIN(sizeof(buf), n)); - while (n) - { - mz_uint32 s = MZ_MIN(sizeof(buf), n); - if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_file_ofs, buf, s) != s) - return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); - - cur_file_ofs += s; - n -= s; - } - return MZ_TRUE; -} - -mz_bool mz_zip_writer_add_mem_ex(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, - mz_uint64 uncomp_size, mz_uint32 uncomp_crc32) -{ - return mz_zip_writer_add_mem_ex_v2(pZip, pArchive_name, pBuf, buf_size, pComment, comment_size, level_and_flags, uncomp_size, uncomp_crc32, NULL, NULL, 0, NULL, 0); -} - -mz_bool mz_zip_writer_add_mem_ex_v2(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, - mz_uint level_and_flags, mz_uint64 uncomp_size, mz_uint32 uncomp_crc32, MZ_TIME_T *last_modified, - const char *user_extra_data, mz_uint user_extra_data_len, const char *user_extra_data_central, mz_uint user_extra_data_central_len) -{ - mz_uint16 method = 0, dos_time = 0, dos_date = 0; - mz_uint level, ext_attributes = 0, num_alignment_padding_bytes; - mz_uint64 local_dir_header_ofs = pZip->m_archive_size, cur_archive_file_ofs = pZip->m_archive_size, comp_size = 0; - size_t archive_name_size; - mz_uint8 local_dir_header[MZ_ZIP_LOCAL_DIR_HEADER_SIZE]; - tdefl_compressor *pComp = NULL; - mz_bool store_data_uncompressed; - mz_zip_internal_state *pState; - mz_uint8 *pExtra_data = NULL; - mz_uint32 extra_size = 0; - mz_uint8 extra_data[MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE]; - mz_uint16 bit_flags = 0; - - if ((int)level_and_flags < 0) - level_and_flags = MZ_DEFAULT_LEVEL; - - if (uncomp_size || (buf_size && !(level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA))) - bit_flags |= MZ_ZIP_LDH_BIT_FLAG_HAS_LOCATOR; - - if (!(level_and_flags & MZ_ZIP_FLAG_ASCII_FILENAME)) - bit_flags |= MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_UTF8; - - level = level_and_flags & 0xF; - store_data_uncompressed = ((!level) || (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)); - - if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) || ((buf_size) && (!pBuf)) || (!pArchive_name) || ((comment_size) && (!pComment)) || (level > MZ_UBER_COMPRESSION)) - return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - - pState = pZip->m_pState; - - if (pState->m_zip64) - { - if (pZip->m_total_files == MZ_UINT32_MAX) - return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); - } - else - { - if (pZip->m_total_files == MZ_UINT16_MAX) - { - pState->m_zip64 = MZ_TRUE; - /*return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); */ - } - if ((buf_size > 0xFFFFFFFF) || (uncomp_size > 0xFFFFFFFF)) - { - pState->m_zip64 = MZ_TRUE; - /*return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); */ - } - } - - if ((!(level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (uncomp_size)) - return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - - if (!mz_zip_writer_validate_archive_name(pArchive_name)) - return mz_zip_set_error(pZip, MZ_ZIP_INVALID_FILENAME); - -#ifndef MINIZ_NO_TIME - if (last_modified != NULL) - { - mz_zip_time_t_to_dos_time(*last_modified, &dos_time, &dos_date); - } - else - { - MZ_TIME_T cur_time; - time(&cur_time); - mz_zip_time_t_to_dos_time(cur_time, &dos_time, &dos_date); - } -#endif /* #ifndef MINIZ_NO_TIME */ - - if (!(level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) - { - uncomp_crc32 = (mz_uint32)mz_crc32(MZ_CRC32_INIT, (const mz_uint8 *)pBuf, buf_size); - uncomp_size = buf_size; - if (uncomp_size <= 3) - { - level = 0; - store_data_uncompressed = MZ_TRUE; - } - } - - archive_name_size = strlen(pArchive_name); - if (archive_name_size > MZ_UINT16_MAX) - return mz_zip_set_error(pZip, MZ_ZIP_INVALID_FILENAME); - - num_alignment_padding_bytes = mz_zip_writer_compute_padding_needed_for_file_alignment(pZip); - - /* miniz doesn't support central dirs >= MZ_UINT32_MAX bytes yet */ - if (((mz_uint64)pState->m_central_dir.m_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + archive_name_size + MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE + comment_size) >= MZ_UINT32_MAX) - return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE); - - if (!pState->m_zip64) - { - /* Bail early if the archive would obviously become too large */ - if ((pZip->m_archive_size + num_alignment_padding_bytes + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + archive_name_size - + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + archive_name_size + comment_size + user_extra_data_len + - pState->m_central_dir.m_size + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE + user_extra_data_central_len - + MZ_ZIP_DATA_DESCRIPTER_SIZE32) > 0xFFFFFFFF) - { - pState->m_zip64 = MZ_TRUE; - /*return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); */ - } - } - - if ((archive_name_size) && (pArchive_name[archive_name_size - 1] == '/')) - { - /* Set DOS Subdirectory attribute bit. */ - ext_attributes |= MZ_ZIP_DOS_DIR_ATTRIBUTE_BITFLAG; - - /* Subdirectories cannot contain data. */ - if ((buf_size) || (uncomp_size)) - return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - } - - /* Try to do any allocations before writing to the archive, so if an allocation fails the file remains unmodified. (A good idea if we're doing an in-place modification.) */ - if ((!mz_zip_array_ensure_room(pZip, &pState->m_central_dir, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + archive_name_size + comment_size + (pState->m_zip64 ? MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE : 0))) || (!mz_zip_array_ensure_room(pZip, &pState->m_central_dir_offsets, 1))) - return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); - - if ((!store_data_uncompressed) && (buf_size)) - { - if (NULL == (pComp = (tdefl_compressor *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(tdefl_compressor)))) - return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); - } - - if (!mz_zip_writer_write_zeros(pZip, cur_archive_file_ofs, num_alignment_padding_bytes)) - { - pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); - return MZ_FALSE; - } - - local_dir_header_ofs += num_alignment_padding_bytes; - if (pZip->m_file_offset_alignment) - { - MZ_ASSERT((local_dir_header_ofs & (pZip->m_file_offset_alignment - 1)) == 0); - } - cur_archive_file_ofs += num_alignment_padding_bytes; - - MZ_CLEAR_OBJ(local_dir_header); - - if (!store_data_uncompressed || (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) - { - method = MZ_DEFLATED; - } - - if (pState->m_zip64) - { - if (uncomp_size >= MZ_UINT32_MAX || local_dir_header_ofs >= MZ_UINT32_MAX) - { - pExtra_data = extra_data; - extra_size = mz_zip_writer_create_zip64_extra_data(extra_data, (uncomp_size >= MZ_UINT32_MAX) ? &uncomp_size : NULL, - (uncomp_size >= MZ_UINT32_MAX) ? &comp_size : NULL, (local_dir_header_ofs >= MZ_UINT32_MAX) ? &local_dir_header_ofs : NULL); - } - - if (!mz_zip_writer_create_local_dir_header(pZip, local_dir_header, (mz_uint16)archive_name_size, (mz_uint16)(extra_size + user_extra_data_len), 0, 0, 0, method, bit_flags, dos_time, dos_date)) - return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); - - if (pZip->m_pWrite(pZip->m_pIO_opaque, local_dir_header_ofs, local_dir_header, sizeof(local_dir_header)) != sizeof(local_dir_header)) - return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); - - cur_archive_file_ofs += sizeof(local_dir_header); - - if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name, archive_name_size) != archive_name_size) - { - pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); - return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); - } - cur_archive_file_ofs += archive_name_size; - - if (pExtra_data != NULL) - { - if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, extra_data, extra_size) != extra_size) - return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); - - cur_archive_file_ofs += extra_size; - } - } - else - { - if ((comp_size > MZ_UINT32_MAX) || (cur_archive_file_ofs > MZ_UINT32_MAX)) - return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); - if (!mz_zip_writer_create_local_dir_header(pZip, local_dir_header, (mz_uint16)archive_name_size, (mz_uint16)user_extra_data_len, 0, 0, 0, method, bit_flags, dos_time, dos_date)) - return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); - - if (pZip->m_pWrite(pZip->m_pIO_opaque, local_dir_header_ofs, local_dir_header, sizeof(local_dir_header)) != sizeof(local_dir_header)) - return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); - - cur_archive_file_ofs += sizeof(local_dir_header); - - if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name, archive_name_size) != archive_name_size) - { - pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); - return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); - } - cur_archive_file_ofs += archive_name_size; - } - - if (user_extra_data_len > 0) - { - if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, user_extra_data, user_extra_data_len) != user_extra_data_len) - return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); - - cur_archive_file_ofs += user_extra_data_len; - } - - if (store_data_uncompressed) - { - if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pBuf, buf_size) != buf_size) - { - pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); - return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); - } - - cur_archive_file_ofs += buf_size; - comp_size = buf_size; - } - else if (buf_size) - { - mz_zip_writer_add_state state; - - state.m_pZip = pZip; - state.m_cur_archive_file_ofs = cur_archive_file_ofs; - state.m_comp_size = 0; - - if ((tdefl_init(pComp, mz_zip_writer_add_put_buf_callback, &state, tdefl_create_comp_flags_from_zip_params(level, -15, MZ_DEFAULT_STRATEGY)) != TDEFL_STATUS_OKAY) || - (tdefl_compress_buffer(pComp, pBuf, buf_size, TDEFL_FINISH) != TDEFL_STATUS_DONE)) - { - pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); - return mz_zip_set_error(pZip, MZ_ZIP_COMPRESSION_FAILED); - } - - comp_size = state.m_comp_size; - cur_archive_file_ofs = state.m_cur_archive_file_ofs; - } - - pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); - pComp = NULL; - - if (uncomp_size) - { - mz_uint8 local_dir_footer[MZ_ZIP_DATA_DESCRIPTER_SIZE64]; - mz_uint32 local_dir_footer_size = MZ_ZIP_DATA_DESCRIPTER_SIZE32; - - MZ_ASSERT(bit_flags & MZ_ZIP_LDH_BIT_FLAG_HAS_LOCATOR); - - MZ_WRITE_LE32(local_dir_footer + 0, MZ_ZIP_DATA_DESCRIPTOR_ID); - MZ_WRITE_LE32(local_dir_footer + 4, uncomp_crc32); - if (pExtra_data == NULL) - { - if (comp_size > MZ_UINT32_MAX) - return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); - - MZ_WRITE_LE32(local_dir_footer + 8, comp_size); - MZ_WRITE_LE32(local_dir_footer + 12, uncomp_size); - } - else - { - MZ_WRITE_LE64(local_dir_footer + 8, comp_size); - MZ_WRITE_LE64(local_dir_footer + 16, uncomp_size); - local_dir_footer_size = MZ_ZIP_DATA_DESCRIPTER_SIZE64; - } - - if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, local_dir_footer, local_dir_footer_size) != local_dir_footer_size) - return MZ_FALSE; - - cur_archive_file_ofs += local_dir_footer_size; - } - - if (pExtra_data != NULL) - { - extra_size = mz_zip_writer_create_zip64_extra_data(extra_data, (uncomp_size >= MZ_UINT32_MAX) ? &uncomp_size : NULL, - (uncomp_size >= MZ_UINT32_MAX) ? &comp_size : NULL, (local_dir_header_ofs >= MZ_UINT32_MAX) ? &local_dir_header_ofs : NULL); - } - - if (!mz_zip_writer_add_to_central_dir(pZip, pArchive_name, (mz_uint16)archive_name_size, pExtra_data, (mz_uint16)extra_size, pComment, - comment_size, uncomp_size, comp_size, uncomp_crc32, method, bit_flags, dos_time, dos_date, local_dir_header_ofs, ext_attributes, - user_extra_data_central, user_extra_data_central_len)) - return MZ_FALSE; - - pZip->m_total_files++; - pZip->m_archive_size = cur_archive_file_ofs; - - return MZ_TRUE; -} - -mz_bool mz_zip_writer_add_read_buf_callback(mz_zip_archive *pZip, const char *pArchive_name, mz_file_read_func read_callback, void* callback_opaque, mz_uint64 size_to_add, const MZ_TIME_T *pFile_time, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, - const char *user_extra_data, mz_uint user_extra_data_len, const char *user_extra_data_central, mz_uint user_extra_data_central_len) -{ - mz_uint16 gen_flags = MZ_ZIP_LDH_BIT_FLAG_HAS_LOCATOR; - mz_uint uncomp_crc32 = MZ_CRC32_INIT, level, num_alignment_padding_bytes; - mz_uint16 method = 0, dos_time = 0, dos_date = 0, ext_attributes = 0; - mz_uint64 local_dir_header_ofs, cur_archive_file_ofs = pZip->m_archive_size, uncomp_size = size_to_add, comp_size = 0; - size_t archive_name_size; - mz_uint8 local_dir_header[MZ_ZIP_LOCAL_DIR_HEADER_SIZE]; - mz_uint8 *pExtra_data = NULL; - mz_uint32 extra_size = 0; - mz_uint8 extra_data[MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE]; - mz_zip_internal_state *pState; - mz_uint64 file_ofs = 0; - - if (!(level_and_flags & MZ_ZIP_FLAG_ASCII_FILENAME)) - gen_flags |= MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_UTF8; - - if ((int)level_and_flags < 0) - level_and_flags = MZ_DEFAULT_LEVEL; - level = level_and_flags & 0xF; - - /* Sanity checks */ - if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) || (!pArchive_name) || ((comment_size) && (!pComment)) || (level > MZ_UBER_COMPRESSION)) - return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - - pState = pZip->m_pState; - - if ((!pState->m_zip64) && (uncomp_size > MZ_UINT32_MAX)) - { - /* Source file is too large for non-zip64 */ - /*return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); */ - pState->m_zip64 = MZ_TRUE; - } - - /* We could support this, but why? */ - if (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA) - return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - - if (!mz_zip_writer_validate_archive_name(pArchive_name)) - return mz_zip_set_error(pZip, MZ_ZIP_INVALID_FILENAME); - - if (pState->m_zip64) - { - if (pZip->m_total_files == MZ_UINT32_MAX) - return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); - } - else - { - if (pZip->m_total_files == MZ_UINT16_MAX) - { - pState->m_zip64 = MZ_TRUE; - /*return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); */ - } - } - - archive_name_size = strlen(pArchive_name); - if (archive_name_size > MZ_UINT16_MAX) - return mz_zip_set_error(pZip, MZ_ZIP_INVALID_FILENAME); - - num_alignment_padding_bytes = mz_zip_writer_compute_padding_needed_for_file_alignment(pZip); - - /* miniz doesn't support central dirs >= MZ_UINT32_MAX bytes yet */ - if (((mz_uint64)pState->m_central_dir.m_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + archive_name_size + MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE + comment_size) >= MZ_UINT32_MAX) - return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE); - - if (!pState->m_zip64) - { - /* Bail early if the archive would obviously become too large */ - if ((pZip->m_archive_size + num_alignment_padding_bytes + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + archive_name_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE - + archive_name_size + comment_size + user_extra_data_len + pState->m_central_dir.m_size + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE + 1024 - + MZ_ZIP_DATA_DESCRIPTER_SIZE32 + user_extra_data_central_len) > 0xFFFFFFFF) - { - pState->m_zip64 = MZ_TRUE; - /*return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); */ - } - } - -#ifndef MINIZ_NO_TIME - if (pFile_time) - { - mz_zip_time_t_to_dos_time(*pFile_time, &dos_time, &dos_date); - } -#endif - - if (uncomp_size <= 3) - level = 0; - - if (!mz_zip_writer_write_zeros(pZip, cur_archive_file_ofs, num_alignment_padding_bytes)) - { - return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); - } - - cur_archive_file_ofs += num_alignment_padding_bytes; - local_dir_header_ofs = cur_archive_file_ofs; - - if (pZip->m_file_offset_alignment) - { - MZ_ASSERT((cur_archive_file_ofs & (pZip->m_file_offset_alignment - 1)) == 0); - } - - if (uncomp_size && level) - { - method = MZ_DEFLATED; - } - - MZ_CLEAR_OBJ(local_dir_header); - if (pState->m_zip64) - { - if (uncomp_size >= MZ_UINT32_MAX || local_dir_header_ofs >= MZ_UINT32_MAX) - { - pExtra_data = extra_data; - extra_size = mz_zip_writer_create_zip64_extra_data(extra_data, (uncomp_size >= MZ_UINT32_MAX) ? &uncomp_size : NULL, - (uncomp_size >= MZ_UINT32_MAX) ? &comp_size : NULL, (local_dir_header_ofs >= MZ_UINT32_MAX) ? &local_dir_header_ofs : NULL); - } - - if (!mz_zip_writer_create_local_dir_header(pZip, local_dir_header, (mz_uint16)archive_name_size, (mz_uint16)(extra_size + user_extra_data_len), 0, 0, 0, method, gen_flags, dos_time, dos_date)) - return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); - - if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, local_dir_header, sizeof(local_dir_header)) != sizeof(local_dir_header)) - return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); - - cur_archive_file_ofs += sizeof(local_dir_header); - - if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name, archive_name_size) != archive_name_size) - { - return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); - } - - cur_archive_file_ofs += archive_name_size; - - if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, extra_data, extra_size) != extra_size) - return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); - - cur_archive_file_ofs += extra_size; - } - else - { - if ((comp_size > MZ_UINT32_MAX) || (cur_archive_file_ofs > MZ_UINT32_MAX)) - return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); - if (!mz_zip_writer_create_local_dir_header(pZip, local_dir_header, (mz_uint16)archive_name_size, (mz_uint16)user_extra_data_len, 0, 0, 0, method, gen_flags, dos_time, dos_date)) - return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); - - if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, local_dir_header, sizeof(local_dir_header)) != sizeof(local_dir_header)) - return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); - - cur_archive_file_ofs += sizeof(local_dir_header); - - if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name, archive_name_size) != archive_name_size) - { - return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); - } - - cur_archive_file_ofs += archive_name_size; - } - - if (user_extra_data_len > 0) - { - if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, user_extra_data, user_extra_data_len) != user_extra_data_len) - return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); - - cur_archive_file_ofs += user_extra_data_len; - } - - if (uncomp_size) - { - mz_uint64 uncomp_remaining = uncomp_size; - void *pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, MZ_ZIP_MAX_IO_BUF_SIZE); - if (!pRead_buf) - { - return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); - } - - if (!level) - { - while (uncomp_remaining) - { - mz_uint n = (mz_uint)MZ_MIN((mz_uint64)MZ_ZIP_MAX_IO_BUF_SIZE, uncomp_remaining); - if ((read_callback(callback_opaque, file_ofs, pRead_buf, n) != n) || (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pRead_buf, n) != n)) - { - pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); - return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); - } - file_ofs += n; - uncomp_crc32 = (mz_uint32)mz_crc32(uncomp_crc32, (const mz_uint8 *)pRead_buf, n); - uncomp_remaining -= n; - cur_archive_file_ofs += n; - } - comp_size = uncomp_size; - } - else - { - mz_bool result = MZ_FALSE; - mz_zip_writer_add_state state; - tdefl_compressor *pComp = (tdefl_compressor *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(tdefl_compressor)); - if (!pComp) - { - pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); - return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); - } - - state.m_pZip = pZip; - state.m_cur_archive_file_ofs = cur_archive_file_ofs; - state.m_comp_size = 0; - - if (tdefl_init(pComp, mz_zip_writer_add_put_buf_callback, &state, tdefl_create_comp_flags_from_zip_params(level, -15, MZ_DEFAULT_STRATEGY)) != TDEFL_STATUS_OKAY) - { - pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); - pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); - return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); - } - - for (;;) - { - size_t in_buf_size = (mz_uint32)MZ_MIN(uncomp_remaining, (mz_uint64)MZ_ZIP_MAX_IO_BUF_SIZE); - tdefl_status status; - tdefl_flush flush = TDEFL_NO_FLUSH; - - if (read_callback(callback_opaque, file_ofs, pRead_buf, in_buf_size)!= in_buf_size) - { - mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); - break; - } - - file_ofs += in_buf_size; - uncomp_crc32 = (mz_uint32)mz_crc32(uncomp_crc32, (const mz_uint8 *)pRead_buf, in_buf_size); - uncomp_remaining -= in_buf_size; - - if (pZip->m_pNeeds_keepalive != NULL && pZip->m_pNeeds_keepalive(pZip->m_pIO_opaque)) - flush = TDEFL_FULL_FLUSH; - - status = tdefl_compress_buffer(pComp, pRead_buf, in_buf_size, uncomp_remaining ? flush : TDEFL_FINISH); - if (status == TDEFL_STATUS_DONE) - { - result = MZ_TRUE; - break; - } - else if (status != TDEFL_STATUS_OKAY) - { - mz_zip_set_error(pZip, MZ_ZIP_COMPRESSION_FAILED); - break; - } - } - - pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); - - if (!result) - { - pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); - return MZ_FALSE; - } - - comp_size = state.m_comp_size; - cur_archive_file_ofs = state.m_cur_archive_file_ofs; - } - - pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); - } - - { - mz_uint8 local_dir_footer[MZ_ZIP_DATA_DESCRIPTER_SIZE64]; - mz_uint32 local_dir_footer_size = MZ_ZIP_DATA_DESCRIPTER_SIZE32; - - MZ_WRITE_LE32(local_dir_footer + 0, MZ_ZIP_DATA_DESCRIPTOR_ID); - MZ_WRITE_LE32(local_dir_footer + 4, uncomp_crc32); - if (pExtra_data == NULL) - { - if (comp_size > MZ_UINT32_MAX) - return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); - - MZ_WRITE_LE32(local_dir_footer + 8, comp_size); - MZ_WRITE_LE32(local_dir_footer + 12, uncomp_size); - } - else - { - MZ_WRITE_LE64(local_dir_footer + 8, comp_size); - MZ_WRITE_LE64(local_dir_footer + 16, uncomp_size); - local_dir_footer_size = MZ_ZIP_DATA_DESCRIPTER_SIZE64; - } - - if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, local_dir_footer, local_dir_footer_size) != local_dir_footer_size) - return MZ_FALSE; - - cur_archive_file_ofs += local_dir_footer_size; - } - - if (pExtra_data != NULL) - { - extra_size = mz_zip_writer_create_zip64_extra_data(extra_data, (uncomp_size >= MZ_UINT32_MAX) ? &uncomp_size : NULL, - (uncomp_size >= MZ_UINT32_MAX) ? &comp_size : NULL, (local_dir_header_ofs >= MZ_UINT32_MAX) ? &local_dir_header_ofs : NULL); - } - - if (!mz_zip_writer_add_to_central_dir(pZip, pArchive_name, (mz_uint16)archive_name_size, pExtra_data, (mz_uint16)extra_size, pComment, comment_size, - uncomp_size, comp_size, uncomp_crc32, method, gen_flags, dos_time, dos_date, local_dir_header_ofs, ext_attributes, - user_extra_data_central, user_extra_data_central_len)) - return MZ_FALSE; - - pZip->m_total_files++; - pZip->m_archive_size = cur_archive_file_ofs; - - return MZ_TRUE; -} - -#ifndef MINIZ_NO_STDIO - -static size_t mz_file_read_func_stdio(void *pOpaque, mz_uint64 file_ofs, void *pBuf, size_t n) -{ - MZ_FILE *pSrc_file = (MZ_FILE *)pOpaque; - mz_int64 cur_ofs = MZ_FTELL64(pSrc_file); - - if (((mz_int64)file_ofs < 0) || (((cur_ofs != (mz_int64)file_ofs)) && (MZ_FSEEK64(pSrc_file, (mz_int64)file_ofs, SEEK_SET)))) - return 0; - - return MZ_FREAD(pBuf, 1, n, pSrc_file); -} - -mz_bool mz_zip_writer_add_cfile(mz_zip_archive *pZip, const char *pArchive_name, MZ_FILE *pSrc_file, mz_uint64 size_to_add, const MZ_TIME_T *pFile_time, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, - const char *user_extra_data, mz_uint user_extra_data_len, const char *user_extra_data_central, mz_uint user_extra_data_central_len) -{ - return mz_zip_writer_add_read_buf_callback(pZip, pArchive_name, mz_file_read_func_stdio, pSrc_file, size_to_add, pFile_time, pComment, comment_size, level_and_flags, - user_extra_data, user_extra_data_len, user_extra_data_central, user_extra_data_central_len); -} - -mz_bool mz_zip_writer_add_file(mz_zip_archive *pZip, const char *pArchive_name, const char *pSrc_filename, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags) -{ - MZ_FILE *pSrc_file = NULL; - mz_uint64 uncomp_size = 0; - MZ_TIME_T file_modified_time; - MZ_TIME_T *pFile_time = NULL; - mz_bool status; - - memset(&file_modified_time, 0, sizeof(file_modified_time)); - -#if !defined(MINIZ_NO_TIME) && !defined(MINIZ_NO_STDIO) - pFile_time = &file_modified_time; - if (!mz_zip_get_file_modified_time(pSrc_filename, &file_modified_time)) - return mz_zip_set_error(pZip, MZ_ZIP_FILE_STAT_FAILED); -#endif - - pSrc_file = MZ_FOPEN(pSrc_filename, "rb"); - if (!pSrc_file) - return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED); - - MZ_FSEEK64(pSrc_file, 0, SEEK_END); - uncomp_size = MZ_FTELL64(pSrc_file); - MZ_FSEEK64(pSrc_file, 0, SEEK_SET); - - status = mz_zip_writer_add_cfile(pZip, pArchive_name, pSrc_file, uncomp_size, pFile_time, pComment, comment_size, level_and_flags, NULL, 0, NULL, 0); - - MZ_FCLOSE(pSrc_file); - - return status; -} -#endif /* #ifndef MINIZ_NO_STDIO */ - -static mz_bool mz_zip_writer_update_zip64_extension_block(mz_zip_array *pNew_ext, mz_zip_archive *pZip, const mz_uint8 *pExt, uint32_t ext_len, mz_uint64 *pComp_size, mz_uint64 *pUncomp_size, mz_uint64 *pLocal_header_ofs, mz_uint32 *pDisk_start) -{ - /* + 64 should be enough for any new zip64 data */ - if (!mz_zip_array_reserve(pZip, pNew_ext, ext_len + 64, MZ_FALSE)) - return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); - - mz_zip_array_resize(pZip, pNew_ext, 0, MZ_FALSE); - - if ((pUncomp_size) || (pComp_size) || (pLocal_header_ofs) || (pDisk_start)) - { - mz_uint8 new_ext_block[64]; - mz_uint8 *pDst = new_ext_block; - mz_write_le16(pDst, MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID); - mz_write_le16(pDst + sizeof(mz_uint16), 0); - pDst += sizeof(mz_uint16) * 2; - - if (pUncomp_size) - { - mz_write_le64(pDst, *pUncomp_size); - pDst += sizeof(mz_uint64); - } - - if (pComp_size) - { - mz_write_le64(pDst, *pComp_size); - pDst += sizeof(mz_uint64); - } - - if (pLocal_header_ofs) - { - mz_write_le64(pDst, *pLocal_header_ofs); - pDst += sizeof(mz_uint64); - } - - if (pDisk_start) - { - mz_write_le32(pDst, *pDisk_start); - pDst += sizeof(mz_uint32); - } - - mz_write_le16(new_ext_block + sizeof(mz_uint16), (mz_uint16)((pDst - new_ext_block) - sizeof(mz_uint16) * 2)); - - if (!mz_zip_array_push_back(pZip, pNew_ext, new_ext_block, pDst - new_ext_block)) - return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); - } - - if ((pExt) && (ext_len)) - { - mz_uint32 extra_size_remaining = ext_len; - const mz_uint8 *pExtra_data = pExt; - - do - { - mz_uint32 field_id, field_data_size, field_total_size; - - if (extra_size_remaining < (sizeof(mz_uint16) * 2)) - return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); - - field_id = MZ_READ_LE16(pExtra_data); - field_data_size = MZ_READ_LE16(pExtra_data + sizeof(mz_uint16)); - field_total_size = field_data_size + sizeof(mz_uint16) * 2; - - if (field_total_size > extra_size_remaining) - return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); - - if (field_id != MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID) - { - if (!mz_zip_array_push_back(pZip, pNew_ext, pExtra_data, field_total_size)) - return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); - } - - pExtra_data += field_total_size; - extra_size_remaining -= field_total_size; - } while (extra_size_remaining); - } - - return MZ_TRUE; -} - -/* TODO: This func is now pretty freakin complex due to zip64, split it up? */ -mz_bool mz_zip_writer_add_from_zip_reader(mz_zip_archive *pZip, mz_zip_archive *pSource_zip, mz_uint src_file_index) -{ - mz_uint n, bit_flags, num_alignment_padding_bytes, src_central_dir_following_data_size; - mz_uint64 src_archive_bytes_remaining, local_dir_header_ofs; - mz_uint64 cur_src_file_ofs, cur_dst_file_ofs; - mz_uint32 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; - mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32; - mz_uint8 new_central_header[MZ_ZIP_CENTRAL_DIR_HEADER_SIZE]; - size_t orig_central_dir_size; - mz_zip_internal_state *pState; - void *pBuf; - const mz_uint8 *pSrc_central_header; - mz_zip_archive_file_stat src_file_stat; - mz_uint32 src_filename_len, src_comment_len, src_ext_len; - mz_uint32 local_header_filename_size, local_header_extra_len; - mz_uint64 local_header_comp_size, local_header_uncomp_size; - mz_bool found_zip64_ext_data_in_ldir = MZ_FALSE; - - /* Sanity checks */ - if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) || (!pSource_zip->m_pRead)) - return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - - pState = pZip->m_pState; - - /* Don't support copying files from zip64 archives to non-zip64, even though in some cases this is possible */ - if ((pSource_zip->m_pState->m_zip64) && (!pZip->m_pState->m_zip64)) - return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - - /* Get pointer to the source central dir header and crack it */ - if (NULL == (pSrc_central_header = mz_zip_get_cdh(pSource_zip, src_file_index))) - return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - - if (MZ_READ_LE32(pSrc_central_header + MZ_ZIP_CDH_SIG_OFS) != MZ_ZIP_CENTRAL_DIR_HEADER_SIG) - return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); - - src_filename_len = MZ_READ_LE16(pSrc_central_header + MZ_ZIP_CDH_FILENAME_LEN_OFS); - src_comment_len = MZ_READ_LE16(pSrc_central_header + MZ_ZIP_CDH_COMMENT_LEN_OFS); - src_ext_len = MZ_READ_LE16(pSrc_central_header + MZ_ZIP_CDH_EXTRA_LEN_OFS); - src_central_dir_following_data_size = src_filename_len + src_ext_len + src_comment_len; - - /* TODO: We don't support central dir's >= MZ_UINT32_MAX bytes right now (+32 fudge factor in case we need to add more extra data) */ - if ((pState->m_central_dir.m_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + src_central_dir_following_data_size + 32) >= MZ_UINT32_MAX) - return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE); - - num_alignment_padding_bytes = mz_zip_writer_compute_padding_needed_for_file_alignment(pZip); - - if (!pState->m_zip64) - { - if (pZip->m_total_files == MZ_UINT16_MAX) - return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); - } - else - { - /* TODO: Our zip64 support still has some 32-bit limits that may not be worth fixing. */ - if (pZip->m_total_files == MZ_UINT32_MAX) - return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); - } - - if (!mz_zip_file_stat_internal(pSource_zip, src_file_index, pSrc_central_header, &src_file_stat, NULL)) - return MZ_FALSE; - - cur_src_file_ofs = src_file_stat.m_local_header_ofs; - cur_dst_file_ofs = pZip->m_archive_size; - - /* Read the source archive's local dir header */ - if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, cur_src_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE) - return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); - - if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG) - return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); - - cur_src_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE; - - /* Compute the total size we need to copy (filename+extra data+compressed data) */ - local_header_filename_size = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS); - local_header_extra_len = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS); - local_header_comp_size = MZ_READ_LE32(pLocal_header + MZ_ZIP_LDH_COMPRESSED_SIZE_OFS); - local_header_uncomp_size = MZ_READ_LE32(pLocal_header + MZ_ZIP_LDH_DECOMPRESSED_SIZE_OFS); - src_archive_bytes_remaining = local_header_filename_size + local_header_extra_len + src_file_stat.m_comp_size; - - /* Try to find a zip64 extended information field */ - if ((local_header_extra_len) && ((local_header_comp_size == MZ_UINT32_MAX) || (local_header_uncomp_size == MZ_UINT32_MAX))) - { - mz_zip_array file_data_array; - const mz_uint8 *pExtra_data; - mz_uint32 extra_size_remaining = local_header_extra_len; - - mz_zip_array_init(&file_data_array, 1); - if (!mz_zip_array_resize(pZip, &file_data_array, local_header_extra_len, MZ_FALSE)) - { - return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); - } - - if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, src_file_stat.m_local_header_ofs + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + local_header_filename_size, file_data_array.m_p, local_header_extra_len) != local_header_extra_len) - { - mz_zip_array_clear(pZip, &file_data_array); - return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); - } - - pExtra_data = (const mz_uint8 *)file_data_array.m_p; - - do - { - mz_uint32 field_id, field_data_size, field_total_size; - - if (extra_size_remaining < (sizeof(mz_uint16) * 2)) - { - mz_zip_array_clear(pZip, &file_data_array); - return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); - } - - field_id = MZ_READ_LE16(pExtra_data); - field_data_size = MZ_READ_LE16(pExtra_data + sizeof(mz_uint16)); - field_total_size = field_data_size + sizeof(mz_uint16) * 2; - - if (field_total_size > extra_size_remaining) - { - mz_zip_array_clear(pZip, &file_data_array); - return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); - } - - if (field_id == MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID) - { - const mz_uint8 *pSrc_field_data = pExtra_data + sizeof(mz_uint32); - - if (field_data_size < sizeof(mz_uint64) * 2) - { - mz_zip_array_clear(pZip, &file_data_array); - return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); - } - - local_header_uncomp_size = MZ_READ_LE64(pSrc_field_data); - local_header_comp_size = MZ_READ_LE64(pSrc_field_data + sizeof(mz_uint64)); /* may be 0 if there's a descriptor */ - - found_zip64_ext_data_in_ldir = MZ_TRUE; - break; - } - - pExtra_data += field_total_size; - extra_size_remaining -= field_total_size; - } while (extra_size_remaining); - - mz_zip_array_clear(pZip, &file_data_array); - } - - if (!pState->m_zip64) - { - /* Try to detect if the new archive will most likely wind up too big and bail early (+(sizeof(mz_uint32) * 4) is for the optional descriptor which could be present, +64 is a fudge factor). */ - /* We also check when the archive is finalized so this doesn't need to be perfect. */ - mz_uint64 approx_new_archive_size = cur_dst_file_ofs + num_alignment_padding_bytes + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + src_archive_bytes_remaining + (sizeof(mz_uint32) * 4) + - pState->m_central_dir.m_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + src_central_dir_following_data_size + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE + 64; - - if (approx_new_archive_size >= MZ_UINT32_MAX) - return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); - } - - /* Write dest archive padding */ - if (!mz_zip_writer_write_zeros(pZip, cur_dst_file_ofs, num_alignment_padding_bytes)) - return MZ_FALSE; - - cur_dst_file_ofs += num_alignment_padding_bytes; - - local_dir_header_ofs = cur_dst_file_ofs; - if (pZip->m_file_offset_alignment) - { - MZ_ASSERT((local_dir_header_ofs & (pZip->m_file_offset_alignment - 1)) == 0); - } - - /* The original zip's local header+ext block doesn't change, even with zip64, so we can just copy it over to the dest zip */ - if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_dst_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE) - return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); - - cur_dst_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE; - - /* Copy over the source archive bytes to the dest archive, also ensure we have enough buf space to handle optional data descriptor */ - if (NULL == (pBuf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)MZ_MAX(32U, MZ_MIN((mz_uint64)MZ_ZIP_MAX_IO_BUF_SIZE, src_archive_bytes_remaining))))) - return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); - - while (src_archive_bytes_remaining) - { - n = (mz_uint)MZ_MIN((mz_uint64)MZ_ZIP_MAX_IO_BUF_SIZE, src_archive_bytes_remaining); - if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, cur_src_file_ofs, pBuf, n) != n) - { - pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); - return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); - } - cur_src_file_ofs += n; - - if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_dst_file_ofs, pBuf, n) != n) - { - pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); - return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); - } - cur_dst_file_ofs += n; - - src_archive_bytes_remaining -= n; - } - - /* Now deal with the optional data descriptor */ - bit_flags = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_BIT_FLAG_OFS); - if (bit_flags & 8) - { - /* Copy data descriptor */ - if ((pSource_zip->m_pState->m_zip64) || (found_zip64_ext_data_in_ldir)) - { - /* src is zip64, dest must be zip64 */ - - /* name uint32_t's */ - /* id 1 (optional in zip64?) */ - /* crc 1 */ - /* comp_size 2 */ - /* uncomp_size 2 */ - if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, cur_src_file_ofs, pBuf, (sizeof(mz_uint32) * 6)) != (sizeof(mz_uint32) * 6)) - { - pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); - return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); - } - - n = sizeof(mz_uint32) * ((MZ_READ_LE32(pBuf) == MZ_ZIP_DATA_DESCRIPTOR_ID) ? 6 : 5); - } - else - { - /* src is NOT zip64 */ - mz_bool has_id; - - if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, cur_src_file_ofs, pBuf, sizeof(mz_uint32) * 4) != sizeof(mz_uint32) * 4) - { - pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); - return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); - } - - has_id = (MZ_READ_LE32(pBuf) == MZ_ZIP_DATA_DESCRIPTOR_ID); - - if (pZip->m_pState->m_zip64) - { - /* dest is zip64, so upgrade the data descriptor */ - const mz_uint32 *pSrc_descriptor = (const mz_uint32 *)((const mz_uint8 *)pBuf + (has_id ? sizeof(mz_uint32) : 0)); - const mz_uint32 src_crc32 = pSrc_descriptor[0]; - const mz_uint64 src_comp_size = pSrc_descriptor[1]; - const mz_uint64 src_uncomp_size = pSrc_descriptor[2]; - - mz_write_le32((mz_uint8 *)pBuf, MZ_ZIP_DATA_DESCRIPTOR_ID); - mz_write_le32((mz_uint8 *)pBuf + sizeof(mz_uint32) * 1, src_crc32); - mz_write_le64((mz_uint8 *)pBuf + sizeof(mz_uint32) * 2, src_comp_size); - mz_write_le64((mz_uint8 *)pBuf + sizeof(mz_uint32) * 4, src_uncomp_size); - - n = sizeof(mz_uint32) * 6; - } - else - { - /* dest is NOT zip64, just copy it as-is */ - n = sizeof(mz_uint32) * (has_id ? 4 : 3); - } - } - - if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_dst_file_ofs, pBuf, n) != n) - { - pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); - return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); - } - - cur_src_file_ofs += n; - cur_dst_file_ofs += n; - } - pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); - - /* Finally, add the new central dir header */ - orig_central_dir_size = pState->m_central_dir.m_size; - - memcpy(new_central_header, pSrc_central_header, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE); - - if (pState->m_zip64) - { - /* This is the painful part: We need to write a new central dir header + ext block with updated zip64 fields, and ensure the old fields (if any) are not included. */ - const mz_uint8 *pSrc_ext = pSrc_central_header + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + src_filename_len; - mz_zip_array new_ext_block; - - mz_zip_array_init(&new_ext_block, sizeof(mz_uint8)); - - MZ_WRITE_LE32(new_central_header + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS, MZ_UINT32_MAX); - MZ_WRITE_LE32(new_central_header + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS, MZ_UINT32_MAX); - MZ_WRITE_LE32(new_central_header + MZ_ZIP_CDH_LOCAL_HEADER_OFS, MZ_UINT32_MAX); - - if (!mz_zip_writer_update_zip64_extension_block(&new_ext_block, pZip, pSrc_ext, src_ext_len, &src_file_stat.m_comp_size, &src_file_stat.m_uncomp_size, &local_dir_header_ofs, NULL)) - { - mz_zip_array_clear(pZip, &new_ext_block); - return MZ_FALSE; - } - - MZ_WRITE_LE16(new_central_header + MZ_ZIP_CDH_EXTRA_LEN_OFS, new_ext_block.m_size); - - if (!mz_zip_array_push_back(pZip, &pState->m_central_dir, new_central_header, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE)) - { - mz_zip_array_clear(pZip, &new_ext_block); - return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); - } - - if (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pSrc_central_header + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, src_filename_len)) - { - mz_zip_array_clear(pZip, &new_ext_block); - mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE); - return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); - } - - if (!mz_zip_array_push_back(pZip, &pState->m_central_dir, new_ext_block.m_p, new_ext_block.m_size)) - { - mz_zip_array_clear(pZip, &new_ext_block); - mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE); - return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); - } - - if (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pSrc_central_header + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + src_filename_len + src_ext_len, src_comment_len)) - { - mz_zip_array_clear(pZip, &new_ext_block); - mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE); - return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); - } - - mz_zip_array_clear(pZip, &new_ext_block); - } - else - { - /* sanity checks */ - if (cur_dst_file_ofs > MZ_UINT32_MAX) - return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); - - if (local_dir_header_ofs >= MZ_UINT32_MAX) - return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); - - MZ_WRITE_LE32(new_central_header + MZ_ZIP_CDH_LOCAL_HEADER_OFS, local_dir_header_ofs); - - if (!mz_zip_array_push_back(pZip, &pState->m_central_dir, new_central_header, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE)) - return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); - - if (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pSrc_central_header + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, src_central_dir_following_data_size)) - { - mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE); - return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); - } - } - - /* This shouldn't trigger unless we screwed up during the initial sanity checks */ - if (pState->m_central_dir.m_size >= MZ_UINT32_MAX) - { - /* TODO: Support central dirs >= 32-bits in size */ - mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE); - return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE); - } - - n = (mz_uint32)orig_central_dir_size; - if (!mz_zip_array_push_back(pZip, &pState->m_central_dir_offsets, &n, 1)) - { - mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE); - return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); - } - - pZip->m_total_files++; - pZip->m_archive_size = cur_dst_file_ofs; - - return MZ_TRUE; -} - -mz_bool mz_zip_writer_finalize_archive(mz_zip_archive *pZip) -{ - mz_zip_internal_state *pState; - mz_uint64 central_dir_ofs, central_dir_size; - mz_uint8 hdr[256]; - - if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING)) - return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - - pState = pZip->m_pState; - - if (pState->m_zip64) - { - if ((pZip->m_total_files > MZ_UINT32_MAX) || (pState->m_central_dir.m_size >= MZ_UINT32_MAX)) - return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); - } - else - { - if ((pZip->m_total_files > MZ_UINT16_MAX) || ((pZip->m_archive_size + pState->m_central_dir.m_size + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) > MZ_UINT32_MAX)) - return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); - } - - central_dir_ofs = 0; - central_dir_size = 0; - if (pZip->m_total_files) - { - /* Write central directory */ - central_dir_ofs = pZip->m_archive_size; - central_dir_size = pState->m_central_dir.m_size; - pZip->m_central_directory_file_ofs = central_dir_ofs; - if (pZip->m_pWrite(pZip->m_pIO_opaque, central_dir_ofs, pState->m_central_dir.m_p, (size_t)central_dir_size) != central_dir_size) - return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); - - pZip->m_archive_size += central_dir_size; - } - - if (pState->m_zip64) - { - /* Write zip64 end of central directory header */ - mz_uint64 rel_ofs_to_zip64_ecdr = pZip->m_archive_size; - - MZ_CLEAR_OBJ(hdr); - MZ_WRITE_LE32(hdr + MZ_ZIP64_ECDH_SIG_OFS, MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIG); - MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDH_SIZE_OF_RECORD_OFS, MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE - sizeof(mz_uint32) - sizeof(mz_uint64)); - MZ_WRITE_LE16(hdr + MZ_ZIP64_ECDH_VERSION_MADE_BY_OFS, 0x031E); /* TODO: always Unix */ - MZ_WRITE_LE16(hdr + MZ_ZIP64_ECDH_VERSION_NEEDED_OFS, 0x002D); - MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS, pZip->m_total_files); - MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDH_CDIR_TOTAL_ENTRIES_OFS, pZip->m_total_files); - MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDH_CDIR_SIZE_OFS, central_dir_size); - MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDH_CDIR_OFS_OFS, central_dir_ofs); - if (pZip->m_pWrite(pZip->m_pIO_opaque, pZip->m_archive_size, hdr, MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE) != MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE) - return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); - - pZip->m_archive_size += MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE; - - /* Write zip64 end of central directory locator */ - MZ_CLEAR_OBJ(hdr); - MZ_WRITE_LE32(hdr + MZ_ZIP64_ECDL_SIG_OFS, MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIG); - MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDL_REL_OFS_TO_ZIP64_ECDR_OFS, rel_ofs_to_zip64_ecdr); - MZ_WRITE_LE32(hdr + MZ_ZIP64_ECDL_TOTAL_NUMBER_OF_DISKS_OFS, 1); - if (pZip->m_pWrite(pZip->m_pIO_opaque, pZip->m_archive_size, hdr, MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE) != MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE) - return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); - - pZip->m_archive_size += MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE; - } - - /* Write end of central directory record */ - MZ_CLEAR_OBJ(hdr); - MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_SIG_OFS, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG); - MZ_WRITE_LE16(hdr + MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS, MZ_MIN(MZ_UINT16_MAX, pZip->m_total_files)); - MZ_WRITE_LE16(hdr + MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS, MZ_MIN(MZ_UINT16_MAX, pZip->m_total_files)); - MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_CDIR_SIZE_OFS, MZ_MIN(MZ_UINT32_MAX, central_dir_size)); - MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_CDIR_OFS_OFS, MZ_MIN(MZ_UINT32_MAX, central_dir_ofs)); - - if (pZip->m_pWrite(pZip->m_pIO_opaque, pZip->m_archive_size, hdr, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) != MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) - return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); - -#ifndef MINIZ_NO_STDIO - if ((pState->m_pFile) && (MZ_FFLUSH(pState->m_pFile) == EOF)) - return mz_zip_set_error(pZip, MZ_ZIP_FILE_CLOSE_FAILED); -#endif /* #ifndef MINIZ_NO_STDIO */ - - pZip->m_archive_size += MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE; - - pZip->m_zip_mode = MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED; - return MZ_TRUE; -} - -mz_bool mz_zip_writer_finalize_heap_archive(mz_zip_archive *pZip, void **ppBuf, size_t *pSize) -{ - if ((!ppBuf) || (!pSize)) - return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - - *ppBuf = NULL; - *pSize = 0; - - if ((!pZip) || (!pZip->m_pState)) - return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - - if (pZip->m_pWrite != mz_zip_heap_write_func) - return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - - if (!mz_zip_writer_finalize_archive(pZip)) - return MZ_FALSE; - - *ppBuf = pZip->m_pState->m_pMem; - *pSize = pZip->m_pState->m_mem_size; - pZip->m_pState->m_pMem = NULL; - pZip->m_pState->m_mem_size = pZip->m_pState->m_mem_capacity = 0; - - return MZ_TRUE; -} - -mz_bool mz_zip_writer_end(mz_zip_archive *pZip) -{ - return mz_zip_writer_end_internal(pZip, MZ_TRUE); -} - -#ifndef MINIZ_NO_STDIO -mz_bool mz_zip_add_mem_to_archive_file_in_place(const char *pZip_filename, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags) -{ - return mz_zip_add_mem_to_archive_file_in_place_v2(pZip_filename, pArchive_name, pBuf, buf_size, pComment, comment_size, level_and_flags, NULL); -} - -mz_bool mz_zip_add_mem_to_archive_file_in_place_v2(const char *pZip_filename, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, mz_zip_error *pErr) -{ - mz_bool status, created_new_archive = MZ_FALSE; - mz_zip_archive zip_archive; - struct MZ_FILE_STAT_STRUCT file_stat; - mz_zip_error actual_err = MZ_ZIP_NO_ERROR; - - mz_zip_zero_struct(&zip_archive); - if ((int)level_and_flags < 0) - level_and_flags = MZ_DEFAULT_LEVEL; - - if ((!pZip_filename) || (!pArchive_name) || ((buf_size) && (!pBuf)) || ((comment_size) && (!pComment)) || ((level_and_flags & 0xF) > MZ_UBER_COMPRESSION)) - { - if (pErr) - *pErr = MZ_ZIP_INVALID_PARAMETER; - return MZ_FALSE; - } - - if (!mz_zip_writer_validate_archive_name(pArchive_name)) - { - if (pErr) - *pErr = MZ_ZIP_INVALID_FILENAME; - return MZ_FALSE; - } - - /* Important: The regular non-64 bit version of stat() can fail here if the file is very large, which could cause the archive to be overwritten. */ - /* So be sure to compile with _LARGEFILE64_SOURCE 1 */ - if (MZ_FILE_STAT(pZip_filename, &file_stat) != 0) - { - /* Create a new archive. */ - if (!mz_zip_writer_init_file_v2(&zip_archive, pZip_filename, 0, level_and_flags)) - { - if (pErr) - *pErr = zip_archive.m_last_error; - return MZ_FALSE; - } - - created_new_archive = MZ_TRUE; - } - else - { - /* Append to an existing archive. */ - if (!mz_zip_reader_init_file_v2(&zip_archive, pZip_filename, level_and_flags | MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY, 0, 0)) - { - if (pErr) - *pErr = zip_archive.m_last_error; - return MZ_FALSE; - } - - if (!mz_zip_writer_init_from_reader_v2(&zip_archive, pZip_filename, level_and_flags)) - { - if (pErr) - *pErr = zip_archive.m_last_error; - - mz_zip_reader_end_internal(&zip_archive, MZ_FALSE); - - return MZ_FALSE; - } - } - - status = mz_zip_writer_add_mem_ex(&zip_archive, pArchive_name, pBuf, buf_size, pComment, comment_size, level_and_flags, 0, 0); - actual_err = zip_archive.m_last_error; - - /* Always finalize, even if adding failed for some reason, so we have a valid central directory. (This may not always succeed, but we can try.) */ - if (!mz_zip_writer_finalize_archive(&zip_archive)) - { - if (!actual_err) - actual_err = zip_archive.m_last_error; - - status = MZ_FALSE; - } - - if (!mz_zip_writer_end_internal(&zip_archive, status)) - { - if (!actual_err) - actual_err = zip_archive.m_last_error; - - status = MZ_FALSE; - } - - if ((!status) && (created_new_archive)) - { - /* It's a new archive and something went wrong, so just delete it. */ - int ignoredStatus = MZ_DELETE_FILE(pZip_filename); - (void)ignoredStatus; - } - - if (pErr) - *pErr = actual_err; - - return status; -} - -void *mz_zip_extract_archive_file_to_heap_v2(const char *pZip_filename, const char *pArchive_name, const char *pComment, size_t *pSize, mz_uint flags, mz_zip_error *pErr) -{ - mz_uint32 file_index; - mz_zip_archive zip_archive; - void *p = NULL; - - if (pSize) - *pSize = 0; - - if ((!pZip_filename) || (!pArchive_name)) - { - if (pErr) - *pErr = MZ_ZIP_INVALID_PARAMETER; - - return NULL; - } - - mz_zip_zero_struct(&zip_archive); - if (!mz_zip_reader_init_file_v2(&zip_archive, pZip_filename, flags | MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY, 0, 0)) - { - if (pErr) - *pErr = zip_archive.m_last_error; - - return NULL; - } - - if (mz_zip_reader_locate_file_v2(&zip_archive, pArchive_name, pComment, flags, &file_index)) - { - p = mz_zip_reader_extract_to_heap(&zip_archive, file_index, pSize, flags); - } - - mz_zip_reader_end_internal(&zip_archive, p != NULL); - - if (pErr) - *pErr = zip_archive.m_last_error; - - return p; -} - -void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename, const char *pArchive_name, size_t *pSize, mz_uint flags) -{ - return mz_zip_extract_archive_file_to_heap_v2(pZip_filename, pArchive_name, NULL, pSize, flags, NULL); -} - -#endif /* #ifndef MINIZ_NO_STDIO */ - -#endif /* #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS */ - -/* ------------------- Misc utils */ - -mz_zip_mode mz_zip_get_mode(mz_zip_archive *pZip) -{ - return pZip ? pZip->m_zip_mode : MZ_ZIP_MODE_INVALID; -} - -mz_zip_type mz_zip_get_type(mz_zip_archive *pZip) -{ - return pZip ? pZip->m_zip_type : MZ_ZIP_TYPE_INVALID; -} - -mz_zip_error mz_zip_set_last_error(mz_zip_archive *pZip, mz_zip_error err_num) -{ - mz_zip_error prev_err; - - if (!pZip) - return MZ_ZIP_INVALID_PARAMETER; - - prev_err = pZip->m_last_error; - - pZip->m_last_error = err_num; - return prev_err; -} - -mz_zip_error mz_zip_peek_last_error(mz_zip_archive *pZip) -{ - if (!pZip) - return MZ_ZIP_INVALID_PARAMETER; - - return pZip->m_last_error; -} - -mz_zip_error mz_zip_clear_last_error(mz_zip_archive *pZip) -{ - return mz_zip_set_last_error(pZip, MZ_ZIP_NO_ERROR); -} - -mz_zip_error mz_zip_get_last_error(mz_zip_archive *pZip) -{ - mz_zip_error prev_err; - - if (!pZip) - return MZ_ZIP_INVALID_PARAMETER; - - prev_err = pZip->m_last_error; - - pZip->m_last_error = MZ_ZIP_NO_ERROR; - return prev_err; -} - -const char *mz_zip_get_error_string(mz_zip_error mz_err) -{ - switch (mz_err) - { - case MZ_ZIP_NO_ERROR: - return "no error"; - case MZ_ZIP_UNDEFINED_ERROR: - return "undefined error"; - case MZ_ZIP_TOO_MANY_FILES: - return "too many files"; - case MZ_ZIP_FILE_TOO_LARGE: - return "file too large"; - case MZ_ZIP_UNSUPPORTED_METHOD: - return "unsupported method"; - case MZ_ZIP_UNSUPPORTED_ENCRYPTION: - return "unsupported encryption"; - case MZ_ZIP_UNSUPPORTED_FEATURE: - return "unsupported feature"; - case MZ_ZIP_FAILED_FINDING_CENTRAL_DIR: - return "failed finding central directory"; - case MZ_ZIP_NOT_AN_ARCHIVE: - return "not a ZIP archive"; - case MZ_ZIP_INVALID_HEADER_OR_CORRUPTED: - return "invalid header or archive is corrupted"; - case MZ_ZIP_UNSUPPORTED_MULTIDISK: - return "unsupported multidisk archive"; - case MZ_ZIP_DECOMPRESSION_FAILED: - return "decompression failed or archive is corrupted"; - case MZ_ZIP_COMPRESSION_FAILED: - return "compression failed"; - case MZ_ZIP_UNEXPECTED_DECOMPRESSED_SIZE: - return "unexpected decompressed size"; - case MZ_ZIP_CRC_CHECK_FAILED: - return "CRC-32 check failed"; - case MZ_ZIP_UNSUPPORTED_CDIR_SIZE: - return "unsupported central directory size"; - case MZ_ZIP_ALLOC_FAILED: - return "allocation failed"; - case MZ_ZIP_FILE_OPEN_FAILED: - return "file open failed"; - case MZ_ZIP_FILE_CREATE_FAILED: - return "file create failed"; - case MZ_ZIP_FILE_WRITE_FAILED: - return "file write failed"; - case MZ_ZIP_FILE_READ_FAILED: - return "file read failed"; - case MZ_ZIP_FILE_CLOSE_FAILED: - return "file close failed"; - case MZ_ZIP_FILE_SEEK_FAILED: - return "file seek failed"; - case MZ_ZIP_FILE_STAT_FAILED: - return "file stat failed"; - case MZ_ZIP_INVALID_PARAMETER: - return "invalid parameter"; - case MZ_ZIP_INVALID_FILENAME: - return "invalid filename"; - case MZ_ZIP_BUF_TOO_SMALL: - return "buffer too small"; - case MZ_ZIP_INTERNAL_ERROR: - return "internal error"; - case MZ_ZIP_FILE_NOT_FOUND: - return "file not found"; - case MZ_ZIP_ARCHIVE_TOO_LARGE: - return "archive is too large"; - case MZ_ZIP_VALIDATION_FAILED: - return "validation failed"; - case MZ_ZIP_WRITE_CALLBACK_FAILED: - return "write calledback failed"; - default: - break; - } - - return "unknown error"; -} - -/* Note: Just because the archive is not zip64 doesn't necessarily mean it doesn't have Zip64 extended information extra field, argh. */ -mz_bool mz_zip_is_zip64(mz_zip_archive *pZip) -{ - if ((!pZip) || (!pZip->m_pState)) - return MZ_FALSE; - - return pZip->m_pState->m_zip64; -} - -size_t mz_zip_get_central_dir_size(mz_zip_archive *pZip) -{ - if ((!pZip) || (!pZip->m_pState)) - return 0; - - return pZip->m_pState->m_central_dir.m_size; -} - -mz_uint mz_zip_reader_get_num_files(mz_zip_archive *pZip) -{ - return pZip ? pZip->m_total_files : 0; -} - -mz_uint64 mz_zip_get_archive_size(mz_zip_archive *pZip) -{ - if (!pZip) - return 0; - return pZip->m_archive_size; -} - -mz_uint64 mz_zip_get_archive_file_start_offset(mz_zip_archive *pZip) -{ - if ((!pZip) || (!pZip->m_pState)) - return 0; - return pZip->m_pState->m_file_archive_start_ofs; -} - -MZ_FILE *mz_zip_get_cfile(mz_zip_archive *pZip) -{ - if ((!pZip) || (!pZip->m_pState)) - return 0; - return pZip->m_pState->m_pFile; -} - -size_t mz_zip_read_archive_data(mz_zip_archive *pZip, mz_uint64 file_ofs, void *pBuf, size_t n) -{ - if ((!pZip) || (!pZip->m_pState) || (!pBuf) || (!pZip->m_pRead)) - return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - - return pZip->m_pRead(pZip->m_pIO_opaque, file_ofs, pBuf, n); -} - -mz_uint mz_zip_reader_get_filename(mz_zip_archive *pZip, mz_uint file_index, char *pFilename, mz_uint filename_buf_size) -{ - mz_uint n; - const mz_uint8 *p = mz_zip_get_cdh(pZip, file_index); - if (!p) - { - if (filename_buf_size) - pFilename[0] = '\0'; - mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - return 0; - } - n = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS); - if (filename_buf_size) - { - n = MZ_MIN(n, filename_buf_size - 1); - memcpy(pFilename, p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, n); - pFilename[n] = '\0'; - } - return n + 1; -} - -mz_bool mz_zip_reader_file_stat(mz_zip_archive *pZip, mz_uint file_index, mz_zip_archive_file_stat *pStat) -{ - return mz_zip_file_stat_internal(pZip, file_index, mz_zip_get_cdh(pZip, file_index), pStat, NULL); -} - -mz_bool mz_zip_end(mz_zip_archive *pZip) -{ - if (!pZip) - return MZ_FALSE; - - if (pZip->m_zip_mode == MZ_ZIP_MODE_READING) - return mz_zip_reader_end(pZip); -#ifndef MINIZ_NO_ARCHIVE_WRITING_APIS - else if ((pZip->m_zip_mode == MZ_ZIP_MODE_WRITING) || (pZip->m_zip_mode == MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED)) - return mz_zip_writer_end(pZip); -#endif - - return MZ_FALSE; -} - -#ifdef __cplusplus -} -#endif - -#endif /*#ifndef MINIZ_NO_ARCHIVE_APIS*/ diff --git a/tools/esptool_py/flasher_stub/run_tests_with_stub.sh b/tools/esptool_py/flasher_stub/run_tests_with_stub.sh deleted file mode 100755 index bb1b07a492..0000000000 --- a/tools/esptool_py/flasher_stub/run_tests_with_stub.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/sh -# -# Run "pytest test/test_esptool.py" using the newly compiled stub, for quick tests -# -# Usage same as "pytest test/test_esptool.py --port --chip --baud " - -THISDIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) - -export ESPTOOL_PY="${THISDIR}/esptool_test_stub.py" -pytest ${THISDIR}/../test/test_esptool.py $@ diff --git a/tools/esptool_py/flasher_stub/slip.c b/tools/esptool_py/flasher_stub/slip.c deleted file mode 100644 index ddd8f265ee..0000000000 --- a/tools/esptool_py/flasher_stub/slip.c +++ /dev/null @@ -1,94 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2016 Cesanta Software Limited - * - * SPDX-License-Identifier: GPL-2.0-or-later - * - * SPDX-FileContributor: 2016-2022 Espressif Systems (Shanghai) CO LTD - */ - -#include -#include "slip.h" -#include "stub_io.h" - -void SLIP_send_frame_delimiter(void) { - stub_tx_one_char('\xc0'); -} - -void SLIP_send_frame_data(char ch) { - if(ch == '\xc0') { - stub_tx_one_char('\xdb'); - stub_tx_one_char('\xdc'); - } else if (ch == '\xdb') { - stub_tx_one_char('\xdb'); - stub_tx_one_char('\xdd'); - } else { - stub_tx_one_char(ch); - } -} - -void SLIP_send_frame_data_buf(const void *buf, uint32_t size) { - const uint8_t *buf_c = (const uint8_t *)buf; - for(int i = 0; i < size; i++) { - SLIP_send_frame_data(buf_c[i]); - } -} - -void SLIP_send(const void *pkt, uint32_t size) { - SLIP_send_frame_delimiter(); - SLIP_send_frame_data_buf(pkt, size); - SLIP_send_frame_delimiter(); -} - -int16_t SLIP_recv_byte(char byte, slip_state_t *state) -{ - if (byte == '\xc0') { - if (*state == SLIP_NO_FRAME) { - *state = SLIP_FRAME; - return SLIP_NO_BYTE; - } else { - *state = SLIP_NO_FRAME; - return SLIP_FINISHED_FRAME; - } - } - - switch(*state) { - case SLIP_NO_FRAME: - return SLIP_NO_BYTE; - case SLIP_FRAME: - if (byte == '\xdb') { - *state = SLIP_FRAME_ESCAPING; - return SLIP_NO_BYTE; - } - return byte; - case SLIP_FRAME_ESCAPING: - if (byte == '\xdc') { - *state = SLIP_FRAME; - return '\xc0'; - } - if (byte == '\xdd') { - *state = SLIP_FRAME; - return '\xdb'; - } - return SLIP_NO_BYTE; /* actually a framing error */ - } - return SLIP_NO_BYTE; /* actually a framing error */ -} - -/* This function is needed for the synchornous I/O case, - * which is only flash_read command at the moment. - */ -uint32_t SLIP_recv(void *pkt, uint32_t max_len) { - uint32_t len = 0; - slip_state_t state = SLIP_NO_FRAME; - uint8_t *p = (uint8_t *) pkt; - - int16_t r; - do { - r = SLIP_recv_byte(stub_rx_one_char(), &state); - if(r >= 0 && len < max_len) { - p[len++] = (uint8_t)r; - } - } while(r != SLIP_FINISHED_FRAME); - - return len; -} diff --git a/tools/esptool_py/flasher_stub/stub_commands.c b/tools/esptool_py/flasher_stub/stub_commands.c deleted file mode 100644 index f2b658245e..0000000000 --- a/tools/esptool_py/flasher_stub/stub_commands.c +++ /dev/null @@ -1,279 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2019-2022 Espressif Systems (Shanghai) CO LTD - * - * SPDX-License-Identifier: GPL-2.0-or-later - */ - -#include -#include "stub_commands.h" -#include "stub_flasher.h" -#include "rom_functions.h" -#include "slip.h" -#include "soc_support.h" -#include "stub_io.h" - -#if defined(ESP32S3) && !defined(ESP32S3BETA2) -static esp_rom_spiflash_result_t SPIRead4B(int spi_num, uint32_t flash_addr, uint8_t* buf, int len) -{ - uint8_t cmd_len = 8; - - esp_rom_opiflash_wait_idle(); - while (len > 0) { - int rd_length; - if (len > 16 ) { //16 = read_sub_len - rd_length = 16; - } else { - rd_length = len; - } - esp_rom_opiflash_exec_cmd(spi_num, SPI_FLASH_FASTRD_MODE, - CMD_FSTRD4B, cmd_len, - flash_addr, 32, - 8, - NULL, 0, - buf, 8 * rd_length, - ESP_ROM_OPIFLASH_SEL_CS0, - false); - - len -= rd_length; - buf += rd_length; - flash_addr += rd_length; - } - return ESP_ROM_SPIFLASH_RESULT_OK; -} -#endif // ESP32S3 - -int handle_flash_erase(uint32_t addr, uint32_t len) { - if (addr % FLASH_SECTOR_SIZE != 0) return 0x32; - if (len % FLASH_SECTOR_SIZE != 0) return 0x33; - if (SPIUnlock() != 0) return 0x34; - - while (len > 0 && (addr % FLASH_BLOCK_SIZE != 0)) { - #if defined(ESP32S3) && !defined(ESP32S3BETA2) - if (large_flash_mode) { - if (esp_rom_opiflash_erase_sector(addr / FLASH_SECTOR_SIZE) != 0) return 0x35; - } else { - if (SPIEraseSector(addr / FLASH_SECTOR_SIZE) != 0) return 0x35; - } - #else - if (SPIEraseSector(addr / FLASH_SECTOR_SIZE) != 0) return 0x35; - #endif // ESP32S3 - len -= FLASH_SECTOR_SIZE; - addr += FLASH_SECTOR_SIZE; - } - - while (len > FLASH_BLOCK_SIZE) { - #if defined(ESP32S3) && !defined(ESP32S3BETA2) - if (large_flash_mode) { - if (esp_rom_opiflash_erase_block_64k(addr / FLASH_BLOCK_SIZE) != 0) return 0x36; - } else { - if (SPIEraseBlock(addr / FLASH_BLOCK_SIZE) != 0) return 0x36; - } - #else - if (SPIEraseBlock(addr / FLASH_BLOCK_SIZE) != 0) return 0x36; - #endif // ESP32S3 - len -= FLASH_BLOCK_SIZE; - addr += FLASH_BLOCK_SIZE; - } - - while (len > 0) { - #if defined(ESP32S3) && !defined(ESP32S3BETA2) - if (large_flash_mode) { - if (esp_rom_opiflash_erase_sector(addr / FLASH_SECTOR_SIZE) != 0) return 0x37; - } else { - if (SPIEraseSector(addr / FLASH_SECTOR_SIZE) != 0) return 0x37; - } - #else - if (SPIEraseSector(addr / FLASH_SECTOR_SIZE) != 0) return 0x37; - #endif // ESP32S3 - len -= FLASH_SECTOR_SIZE; - addr += FLASH_SECTOR_SIZE; - } - - return 0; -} - -void handle_flash_read(uint32_t addr, uint32_t len, uint32_t block_size, - uint32_t max_in_flight) { - uint8_t buf[FLASH_SECTOR_SIZE]; - uint8_t digest[16]; - struct MD5Context ctx; - uint32_t num_sent = 0, num_acked = 0; - uint8_t res = 0; - - /* This is one routine where we still do synchronous I/O */ - stub_rx_async_enable(false); - - if (block_size > sizeof(buf)) { - return; - } - MD5Init(&ctx); - while (num_acked < len && num_acked <= num_sent) { - while (num_sent < len && num_sent - num_acked < max_in_flight) { - uint32_t n = len - num_sent; - if (n > block_size) n = block_size; - #if defined(ESP32S3) && !defined(ESP32S3BETA2) - if (large_flash_mode) { - res = SPIRead4B(1, addr, buf, n); - } else { - res = SPIRead(addr, (uint32_t *)buf, n); - } - #else - res = SPIRead(addr, (uint32_t *)buf, n); - #endif // ESP32S3 - if (res != 0) { - break; - } - SLIP_send(buf, n); - MD5Update(&ctx, buf, n); - addr += n; - num_sent += n; - } - int r = SLIP_recv(&num_acked, sizeof(num_acked)); - if (r != 4) { - break; - } - } - MD5Final(digest, &ctx); - SLIP_send(digest, sizeof(digest)); - - /* Go back to async RX */ - stub_rx_async_enable(true); -} - -int handle_flash_get_md5sum(uint32_t addr, uint32_t len) { - uint8_t buf[FLASH_SECTOR_SIZE]; - uint8_t digest[16]; - uint8_t res = 0; - struct MD5Context ctx; - MD5Init(&ctx); - while (len > 0) { - uint32_t n = len; - if (n > FLASH_SECTOR_SIZE) { - n = FLASH_SECTOR_SIZE; - } - #if defined(ESP32S3) && !defined(ESP32S3BETA2) - if (large_flash_mode) { - res = SPIRead4B(1, addr, buf, n); - } else { - res = SPIRead(addr, (uint32_t *)buf, n); - } - #else - res = SPIRead(addr, (uint32_t *)buf, n); - #endif // ESP32S3 - if (res != 0) { - return 0x63; - } - MD5Update(&ctx, buf, n); - addr += n; - len -= n; - } - MD5Final(digest, &ctx); - /* ESP32 ROM sends as hex, but we just send raw bytes - esptool.py can handle either. */ - SLIP_send_frame_data_buf(digest, sizeof(digest)); - return 0; -} - -esp_command_error handle_spi_set_params(uint32_t *args, int *status) -{ - *status = SPIParamCfg(args[0], args[1], args[2], args[3], args[4], args[5]); - return *status ? ESP_FAILED_SPI_OP : ESP_OK; -} - -esp_command_error handle_spi_attach(uint32_t hspi_config_arg) -{ -#ifdef ESP8266 - /* ESP8266 doesn't yet support SPI flash on HSPI, but could: - see https://github.com/themadinventor/esptool/issues/98 */ - SelectSpiFunction(); -#else - /* Stub calls spi_flash_attach automatically when it boots, - therefore, we need to "unattach" the flash before attaching again - with different configuration to avoid issues. */ - - // Configure the SPI flash pins back as classic GPIOs - PIN_FUNC_SELECT(PERIPHS_IO_MUX_SPICLK_U, FUNC_GPIO); - PIN_FUNC_SELECT(PERIPHS_IO_MUX_SPIQ_U, FUNC_GPIO); - PIN_FUNC_SELECT(PERIPHS_IO_MUX_SPID_U, FUNC_GPIO); - PIN_FUNC_SELECT(PERIPHS_IO_MUX_SPICS0_U, FUNC_GPIO); - - /* spi_flash_attach calls SelectSpiFunction() and another - function to initialise SPI flash interface. - - Second argument 'legacy' mode is not currently supported. - */ - spi_flash_attach(hspi_config_arg, 0); -#endif - return ESP_OK; /* neither function/attach command takes an arg */ -} - -static uint32_t *mem_offset; -static uint32_t mem_remaining; - -esp_command_error handle_mem_begin(uint32_t size, uint32_t offset) -{ - mem_offset = (uint32_t *)offset; - mem_remaining = size; - return ESP_OK; -} - -esp_command_error handle_mem_data(void *data, uint32_t length) -{ - uint32_t *data_words = (uint32_t *)data; - if (mem_offset == NULL && length > 0) { - return ESP_NOT_IN_FLASH_MODE; - } - if (length > mem_remaining) { - return ESP_TOO_MUCH_DATA; - } - if (length % 4 != 0) { - return ESP_BAD_DATA_LEN; - } - - for(int i = 0; i < length; i+= 4) { - *mem_offset++ = *data_words++; - mem_remaining -= 4; - } - return ESP_OK; -} - -esp_command_error handle_mem_finish() -{ - esp_command_error res = mem_remaining > 0 ? ESP_NOT_ENOUGH_DATA : ESP_OK; - mem_remaining = 0; - mem_offset = NULL; - return res; -} - -esp_command_error handle_write_reg(const write_reg_args_t *cmds, uint32_t num_commands) -{ - for (uint32_t i = 0; i < num_commands; i++) { - const write_reg_args_t *cmd = &cmds[i]; - ets_delay_us(cmd->delay_us); - uint32_t v = cmd->value & cmd->mask; - if (cmd->mask != UINT32_MAX) { - v |= READ_REG(cmd->addr) & ~cmd->mask; - } - WRITE_REG(cmd->addr, v); - } - return ESP_OK; -} - -#if ESP32S2_OR_LATER -esp_command_error handle_get_security_info() -{ - uint8_t buf[SECURITY_INFO_BYTES]; - esp_command_error ret; - - #ifdef ESP32C3 - if (_rom_eco_version >= 7) - ret = GetSecurityInfoProcNewEco(NULL, NULL, buf); - else - ret = GetSecurityInfoProc(NULL, NULL, buf); - #else - ret = GetSecurityInfoProc(NULL, NULL, buf); - #endif // ESP32C3 - if (ret == ESP_OK) - SLIP_send_frame_data_buf(buf, sizeof(buf)); - return ret; -} -#endif // ESP32S2_OR_LATER diff --git a/tools/esptool_py/flasher_stub/stub_flasher.c b/tools/esptool_py/flasher_stub/stub_flasher.c deleted file mode 100644 index 445e425676..0000000000 --- a/tools/esptool_py/flasher_stub/stub_flasher.c +++ /dev/null @@ -1,540 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2016 Cesanta Software Limited - * - * SPDX-License-Identifier: GPL-2.0-or-later - * - * SPDX-FileContributor: 2016-2022 Espressif Systems (Shanghai) CO LTD - */ - -/* - * Main flasher stub logic - * - * This stub uses the same SLIP framing and basic command/response structure - * as the in-ROM flasher program, but with some enhanced - * functions and also standardizes the flasher features between different chips. - * - * Actual command handlers are implemented in stub_commands.c - */ -#include -#include "stub_flasher.h" -#include "rom_functions.h" -#include "slip.h" -#include "stub_commands.h" -#include "stub_write_flash.h" -#include "stub_io.h" -#include "soc_support.h" - -/* Buffers for reading from UART. Data is read double-buffered, so - we can read into one buffer while handling data from the other one - (used for flashing throughput.) */ -typedef struct { - uint8_t buf_a[MAX_WRITE_BLOCK+64]; - uint8_t buf_b[MAX_WRITE_BLOCK+64]; - volatile uint8_t *reading_buf; /* Pointer to buf_a, or buf_b - which are we reading_buf? */ - uint16_t read; /* how many bytes have we read in the frame */ - slip_state_t state; - esp_command_req_t *command; /* Pointer to buf_a or buf_b as latest command received */ -} uart_buf_t; -static volatile uart_buf_t ub; - -/* esptool protocol "checksum" is XOR of 0xef and each byte of - data payload. */ -static uint8_t calculate_checksum(uint8_t *buf, int length) -{ - uint8_t res = 0xef; - for(int i = 0; i < length; i++) { - res ^= buf[i]; - } - return res; -} - -#if USE_MAX_CPU_FREQ -static bool can_use_max_cpu_freq() -{ - /* Check if any of available USB modes are being used. */ - #if WITH_USB_OTG && !WITH_USB_JTAG_SERIAL - return stub_uses_usb_otg(); - #elif !WITH_USB_OTG && WITH_USB_JTAG_SERIAL - return stub_uses_usb_jtag_serial(); - #elif WITH_USB_OTG && WITH_USB_JTAG_SERIAL - return stub_uses_usb_otg() || stub_uses_usb_jtag_serial(); - #else - return false; - #endif -} - -#if ESP32C6 || ESP32H2 || ESP32C5BETA3 -static uint32_t pcr_sysclk_conf_reg = 0; -#else -static uint32_t cpu_per_conf_reg = 0; -static uint32_t sysclk_conf_reg = 0; -#endif - -static void set_max_cpu_freq() -{ - if (can_use_max_cpu_freq()) - { - /* Set CPU frequency to max. This also increases SPI speed. */ - #if ESP32C6 || ESP32H2 || ESP32C5BETA3 - pcr_sysclk_conf_reg = READ_REG(PCR_SYSCLK_CONF_REG); - WRITE_REG(PCR_SYSCLK_CONF_REG, (pcr_sysclk_conf_reg & ~PCR_SOC_CLK_SEL_M) | (PCR_SOC_CLK_MAX << PCR_SOC_CLK_SEL_S)); - #else - cpu_per_conf_reg = READ_REG(SYSTEM_CPU_PER_CONF_REG); - sysclk_conf_reg = READ_REG(SYSTEM_SYSCLK_CONF_REG); - WRITE_REG(SYSTEM_SYSCLK_CONF_REG, (sysclk_conf_reg & ~SYSTEM_SOC_CLK_SEL_M) | (SYSTEM_SOC_CLK_MAX << SYSTEM_SOC_CLK_SEL_S)); - ets_delay_us(100); /* Leave some time for the change to settle, needed for ESP32-S3 */ - WRITE_REG(SYSTEM_CPU_PER_CONF_REG, (cpu_per_conf_reg & ~SYSTEM_CPUPERIOD_SEL_M) | (SYSTEM_CPUPERIOD_MAX << SYSTEM_CPUPERIOD_SEL_S)); - #endif - } -} - -static void reset_cpu_freq() -{ - /* Restore saved sysclk_conf and cpu_per_conf registers. - Use only if set_max_cpu_freq() has been called. */ - #if ESP32C6 || ESP32H2 || ESP32C5BETA3 - if (can_use_max_cpu_freq() && pcr_sysclk_conf_reg != 0) - { - WRITE_REG(PCR_SYSCLK_CONF_REG, (READ_REG(PCR_SYSCLK_CONF_REG) & ~PCR_SOC_CLK_SEL_M) | (pcr_sysclk_conf_reg & PCR_SOC_CLK_SEL_M)); - } - #else - if (can_use_max_cpu_freq() && sysclk_conf_reg != 0 && cpu_per_conf_reg != 0) - { - WRITE_REG(SYSTEM_CPU_PER_CONF_REG, (READ_REG(SYSTEM_CPU_PER_CONF_REG) & ~SYSTEM_CPUPERIOD_SEL_M) | (cpu_per_conf_reg & SYSTEM_CPUPERIOD_SEL_M)); - WRITE_REG(SYSTEM_SYSCLK_CONF_REG, (READ_REG(SYSTEM_SYSCLK_CONF_REG) & ~SYSTEM_SOC_CLK_SEL_M) | (sysclk_conf_reg & SYSTEM_SOC_CLK_SEL_M)); - } - #endif -} -#endif // USE_MAX_CPU_FREQ - -#if WITH_USB_JTAG_SERIAL -static void disable_watchdogs() -{ - if (stub_uses_usb_jtag_serial()) - { - WRITE_REG(RTC_CNTL_WDTWPROTECT_REG, RTC_CNTL_WDT_WKEY); // Disable write protection - WRITE_REG(RTC_CNTL_WDTCONFIG0_REG, 0x0); // Disable RTC watchdog - WRITE_REG(RTC_CNTL_WDTWPROTECT_REG, 0x0); // Re-enable write protection - - WRITE_REG(RTC_CNTL_SWD_WPROTECT_REG, RTC_CNTL_SWD_WKEY); // Disable write protection - REG_SET_MASK(RTC_CNTL_SWD_CONF_REG, RTC_CNTL_SWD_AUTO_FEED_EN); // Autofeed super watchdog - WRITE_REG(RTC_CNTL_SWD_WPROTECT_REG, 0x0); // Re-enable write protection - } -} -#endif // WITH_USB_JTAG_SERIAL - -#if ESP32S3 && !ESP32S3BETA2 -bool large_flash_mode = false; - -bool flash_larger_than_16mb() -{ - uint32_t flash_id; - esp_rom_opiflash_exec_cmd(1, SPI_FLASH_FASTRD_MODE, - CMD_RDID, 8, - 0, 0, - 0, - NULL, 0, - (uint8_t *)&flash_id, 24, - ESP_ROM_OPIFLASH_SEL_CS0, - false); - - uint8_t flid_lowbyte = (flash_id >> 16) & 0xFF; - return ((flid_lowbyte >= 0x19 && flid_lowbyte < 0x30) || (flid_lowbyte >= 0x39)); // See DETECTED_FLASH_SIZES in esptool -} -#endif // ESP32S3 - -static void stub_handle_rx_byte(char byte) -{ - int16_t r = SLIP_recv_byte(byte, (slip_state_t *)&ub.state); - if (r >= 0) { - ub.reading_buf[ub.read++] = (uint8_t) r; - if (ub.read == MAX_WRITE_BLOCK+64) { - /* shouldn't happen unless there are data errors */ - r = SLIP_FINISHED_FRAME; - } - } - if (r == SLIP_FINISHED_FRAME) { - /* end of frame, set 'command' - to be processed by main thread */ - if(ub.reading_buf == ub.buf_a) { - ub.command = (esp_command_req_t *)ub.buf_a; - ub.reading_buf = ub.buf_b; - } else { - ub.command = (esp_command_req_t *)ub.buf_b; - ub.reading_buf = ub.buf_a; - } - ub.read = 0; - } -} - -static esp_command_error verify_data_len(esp_command_req_t *command, uint8_t len) -{ - return (command->data_len == len) ? ESP_OK : ESP_BAD_DATA_LEN; -} - -void cmd_loop() { - while(1) { - /* Wait for a command */ - while(ub.command == NULL) { - stub_io_idle_hook(); - } - esp_command_req_t *command = ub.command; - ub.command = NULL; - /* provide easy access for 32-bit data words */ - uint32_t *data_words = (uint32_t *)command->data_buf; - - /* Send command response header */ - esp_command_response_t resp = { - .resp = 1, - .op_ret = command->op, - .len_ret = 2, /* esptool.py checks this length */ - .value = 0, - }; - - /* Some commands need to set resp.len_ret or resp.value before it is sent back */ - switch(command->op) { - case ESP_READ_REG: - if (command->data_len == 4) { - resp.value = READ_REG(data_words[0]); - } - break; - case ESP_FLASH_VERIFY_MD5: - resp.len_ret = 16 + 2; /* Will sent 16 bytes of data with MD5 value */ - break; - #if ESP32S2_OR_LATER - case ESP_GET_SECURITY_INFO: - resp.len_ret = SECURITY_INFO_BYTES; /* Buffer size varies */ - break; - #endif // ESP32S2_OR_LATER - default: - break; - } - - /* Send the command response */ - SLIP_send_frame_delimiter(); - SLIP_send_frame_data_buf(&resp, sizeof(esp_command_response_t)); - - if(command->data_len > MAX_WRITE_BLOCK+16) { - SLIP_send_frame_data(ESP_BAD_DATA_LEN); - SLIP_send_frame_data(0xEE); - SLIP_send_frame_delimiter(); - continue; - } - - /* ... ESP_FLASH_VERIFY_MD5 and ESP_GET_SECURITY_INFO will insert - * in-frame response data between here and when we send the - * status bytes at the end of the frame */ - - esp_command_error error = ESP_CMD_NOT_IMPLEMENTED; - int status = 0; - - /* First stage of command processing - before sending error/status */ - switch (command->op) { - case ESP_SYNC: - /* Bootloader responds to the SYNC request with eight identical SYNC responses. Stub flasher should react - * the same way so SYNC could be possible with the flasher stub as well. This helps in cases when the chip - * cannot be reset and the flasher stub keeps running. */ - error = verify_data_len(command, 36); - - if (error == ESP_OK) { - /* resp.value remains 0 which esptool.py can use to detect the flasher stub */ - resp.value = 0; - for (int i = 0; i < 7; ++i) { - SLIP_send_frame_data(error); - SLIP_send_frame_data(status); - SLIP_send_frame_delimiter(); /* end the previous frame */ - - SLIP_send_frame_delimiter(); /* start new frame */ - SLIP_send_frame_data_buf(&resp, sizeof(esp_command_response_t)); - } - /* The last frame is ended outside of the "switch case" at the same place regular one-response frames are - * ended. */ - } - break; - #if ESP32S2_OR_LATER - case ESP_GET_SECURITY_INFO: - error = verify_data_len(command, 0) || handle_get_security_info(); - break; - #endif // ESP32S2_OR_LATER - case ESP_ERASE_FLASH: - error = verify_data_len(command, 0) || SPIEraseChip(); - break; - case ESP_ERASE_REGION: - /* Params for ERASE_REGION are addr, len */ - error = verify_data_len(command, 8) || handle_flash_erase(data_words[0], data_words[1]); - break; - case ESP_SET_BAUD: - /* ESP_SET_BAUD sends two args, new and old baud rates */ - error = verify_data_len(command, 8); - /* actual baud setting happens after we send the reply */ - break; - case ESP_READ_FLASH: - error = verify_data_len(command, 16); - /* actual data is sent after we send the reply */ - break; - case ESP_FLASH_VERIFY_MD5: - /* unsure why the MD5 command has 4 params but we only pass 2 of them, - but this is in ESP32 ROM so we can't mess with it. - */ - error = verify_data_len(command, 16) || handle_flash_get_md5sum(data_words[0], data_words[1]); - break; - case ESP_FLASH_BEGIN: - /* parameters (interpreted differently to ROM flasher): - 0 - erase_size (used as total size to write) - 1 - num_blocks (ignored) - 2 - block_size (should be MAX_WRITE_BLOCK, relies on num_blocks * block_size >= erase_size) - 3 - offset (used as-is) - */ - if (command->data_len == 16 && data_words[2] > MAX_WRITE_BLOCK) { - error = ESP_BAD_BLOCKSIZE; - } else { - error = verify_data_len(command, 16) || handle_flash_begin(data_words[0], data_words[3]); - } - break; - case ESP_FLASH_DEFLATED_BEGIN: - /* parameters: - 0 - uncompressed size - 1 - num_blocks (based on compressed size) - 2 - block_size (should be MAX_WRITE_BLOCK, total bytes over serial = num_blocks * block_size) - 3 - offset (used as-is) - */ - if (command->data_len == 16 && data_words[2] > MAX_WRITE_BLOCK) { - error = ESP_BAD_BLOCKSIZE; - } else { - error = verify_data_len(command, 16) || handle_flash_deflated_begin(data_words[0], data_words[1] * data_words[2], data_words[3]); - } - break; - case ESP_FLASH_DATA: - case ESP_FLASH_DEFLATED_DATA: -#if !ESP8266 - case ESP_FLASH_ENCRYPT_DATA: -#endif - - /* ACK DATA commands immediately, then process them a few lines down, - allowing next command to buffer */ - if(is_in_flash_mode()) { - error = get_flash_error(); - int payload_len = command->data_len - 16; - if (data_words[0] != payload_len) { - /* First byte of data payload header is length (repeated) as a word */ - error = ESP_BAD_DATA_LEN; - } - uint8_t data_checksum = calculate_checksum(command->data_buf + 16, payload_len); - if (data_checksum != command->checksum) { - error = ESP_BAD_DATA_CHECKSUM; - } - } - else { - error = ESP_NOT_IN_FLASH_MODE; - } - break; - case ESP_FLASH_END: - case ESP_FLASH_DEFLATED_END: - error = handle_flash_end(); - break; - case ESP_SPI_SET_PARAMS: - /* data params: fl_id, total_size, block_size, sector_Size, page_size, status_mask */ - error = verify_data_len(command, 24) || handle_spi_set_params(data_words, &status); - break; - case ESP_SPI_ATTACH: - /* parameter is 'hspi mode' (0, 1 or a pin mask for ESP32. Ignored on ESP8266.) */ - error = verify_data_len(command, 4) || handle_spi_attach(data_words[0]); - break; - case ESP_WRITE_REG: - /* The write_reg command can pass multiple write operations in a sequence */ - if (command->data_len % sizeof(write_reg_args_t) != 0) { - error = ESP_BAD_DATA_LEN; - } else { - error = handle_write_reg((const write_reg_args_t *)data_words, command->data_len/sizeof(write_reg_args_t)); - } - break; - case ESP_READ_REG: - /* actual READ_REG operation happens higher up */ - error = verify_data_len(command, 4); - break; - case ESP_MEM_BEGIN: - error = verify_data_len(command, 16) || handle_mem_begin(data_words[0], data_words[3]); - break; - case ESP_MEM_DATA: - error = handle_mem_data(command->data_buf + 16, command->data_len - 16); - break; - case ESP_MEM_END: - error = verify_data_len(command, 8) || handle_mem_finish(); - break; - case ESP_RUN_USER_CODE: - /* Returning from here will run user code, ie standard boot process - - This command does not send a response. - */ - return; - } - - SLIP_send_frame_data(error); - SLIP_send_frame_data(status); - SLIP_send_frame_delimiter(); - - /* Some commands need to do things after after sending this response */ - if (error == ESP_OK) { - switch(command->op) { - case ESP_SET_BAUD: - stub_io_set_baudrate(data_words[1], data_words[0]); - break; - case ESP_READ_FLASH: - /* args are: offset, length, block_size, max_in_flight */ - handle_flash_read(data_words[0], data_words[1], data_words[2], - data_words[3]); - break; - case ESP_FLASH_DATA: - /* drop into flashing mode, discard 16 byte payload header */ - handle_flash_data(command->data_buf + 16, command->data_len - 16); - break; -#if !ESP8266 - case ESP_FLASH_ENCRYPT_DATA: - /* write encrypted data */ - handle_flash_encrypt_data(command->data_buf + 16, command->data_len -16); - break; -#endif - case ESP_FLASH_DEFLATED_DATA: - handle_flash_deflated_data(command->data_buf + 16, command->data_len - 16); - break; - case ESP_FLASH_DEFLATED_END: - case ESP_FLASH_END: - /* passing 0 as parameter for ESP_FLASH_END means reboot now */ - if (data_words[0] == 0) { - /* Flush the FLASH_END response before rebooting */ - stub_tx_flush(); - ets_delay_us(10000); - #if USE_MAX_CPU_FREQ - reset_cpu_freq(); - #endif // USE_MAX_CPU_FREQ - software_reset(); - } - break; - case ESP_MEM_END: - if (data_words[1] != 0) { - void (*entrypoint_fn)(void) = (void (*))data_words[1]; - /* Make sure the command response has been flushed out - of the UART before we run the new code */ - stub_tx_flush(); - ets_delay_us(1000); - /* this is a little different from the ROM loader, - which exits the loader routine and _then_ calls this - function. But for our purposes so far, having a bit of - extra stuff on the stack doesn't really matter. - */ - #if USE_MAX_CPU_FREQ - reset_cpu_freq(); - #endif // USE_MAX_CPU_FREQ - entrypoint_fn(); - } - break; - } - } - } -} - - -extern uint32_t _bss_start; -extern uint32_t _bss_end; - -void __attribute__((used)) stub_main(); - - -#ifdef ESP8266 -__asm__ ( - ".global stub_main_8266\n" - ".literal_position\n" - ".align 4\n" - "stub_main_8266:\n" -/* ESP8266 wrapper for "stub_main()" manipulates the return address in - * a0, so 'return' from here runs user code. - * - * After setting a0, we jump directly to stub_main_inner() which is a - * normal C function - * - * Adapted from similar approach used by Cesanta Software for ESP8266 - * flasher stub. - * - */ - "movi a0, 0x400010a8;" - "j stub_main;"); -#endif - -/* This function is called from stub_main, with return address - reset to point to user code. */ -void stub_main() -{ - const uint32_t greeting = 0x4941484f; /* OHAI */ - - /* This points to stub_main now, clear for next boot. */ - ets_set_user_start(0); - - /* Increase CPU frequency and flashing speed if supported. */ - #if USE_MAX_CPU_FREQ - set_max_cpu_freq(); - #endif // USE_MAX_CPU_FREQ - - /* Disable all watchdogs to prevent the chip from resetting during longer operations. */ - #if WITH_USB_JTAG_SERIAL - disable_watchdogs(); - #endif // WITH_USB_JTAG_SERIAL - - /* Zero the bss region. */ - for(uint32_t *p = &_bss_start; p < &_bss_end; p++) { - *p = 0; - } - - /* Send the OHAI greeting, stub will be reported as running. */ - SLIP_send(&greeting, 4); - - /* Configure the interrupts for receiving data from esptool on the host. */ - ub.reading_buf = ub.buf_a; - stub_io_init(&stub_handle_rx_byte); - - /* Configure default SPI flash functionality. - Can be overridden later by esptool.py. */ - #ifdef ESP8266 - SelectSpiFunction(); - spi_flash_attach(); - #else - #if SUPPORT_CONFIG_SPI - uint32_t spiconfig = ets_efuse_get_spiconfig(); - #else - uint32_t spiconfig = 0; - #endif // SUPPORT_CONFIG_SPI - uint32_t strapping = READ_REG(GPIO_STRAP_REG); - /* If GPIO1 (U0TXD) is pulled low and no other boot mode is - set in efuse, assume HSPI flash mode (same as normal boot) - */ - if (spiconfig == 0 && (strapping & 0x1c) == 0x08) { - spiconfig = 1; /* HSPI flash mode */ - } - spi_flash_attach(spiconfig, 0); - #endif // ESP8266 - - /* Initialize the OPI flash driver if supported. */ - #if ESP32S3 && !ESP32S3BETA2 - large_flash_mode = ets_efuse_flash_octal_mode() || flash_larger_than_16mb(); - - // Initialize OPI flash driver only when flash is detected octal or quad larger than 16MB. - // Otherwise, we don't need to initialize such a driver - if (large_flash_mode) { - static const esp_rom_opiflash_def_t flash_driver = OPIFLASH_DRIVER(); - esp_rom_opiflash_legacy_driver_init(&flash_driver); - esp_rom_opiflash_wait_idle(); - } - #endif //ESP32S3 && !ESP32S3BETA2 - SPIParamCfg(0, FLASH_MAX_SIZE, FLASH_BLOCK_SIZE, FLASH_SECTOR_SIZE, - FLASH_PAGE_SIZE, FLASH_STATUS_MASK); - - /* Configurations are done, now run the loop to receive and handle commands. */ - cmd_loop(); - - /* If cmd_loop returns, it's due to ESP_RUN_USER_CODE command. */ - /* Decrease CPU frequency back to the saved value before the stub flasher returns. */ - #if USE_MAX_CPU_FREQ - reset_cpu_freq(); - #endif // USE_MAX_CPU_FREQ - - return; -} diff --git a/tools/esptool_py/flasher_stub/stub_io.c b/tools/esptool_py/flasher_stub/stub_io.c deleted file mode 100644 index f86f67e7ac..0000000000 --- a/tools/esptool_py/flasher_stub/stub_io.c +++ /dev/null @@ -1,313 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2016 Cesanta Software Limited - * - * SPDX-License-Identifier: GPL-2.0-or-later - * - * SPDX-FileContributor: 2016-2022 Espressif Systems (Shanghai) CO LTD - */ - -#include -#include "stub_io.h" -#include "rom_functions.h" -#include "soc_support.h" - - -#define UART_RX_INTS (UART_RXFIFO_FULL_INT_ENA | UART_RXFIFO_TOUT_INT_ENA) - - -static void(*s_rx_cb_func)(char); -#ifdef WITH_USB_OTG -static uint32_t s_cdcacm_old_rts; -static volatile bool s_cdcacm_reset_requested; -static char s_cdcacm_txbuf[ACM_BYTES_PER_TX]; -static size_t s_cdcacm_txpos; -#endif // WITH_USB_OTG - - -void uart_isr(void *arg) { - uint32_t int_st = READ_REG(UART_INT_ST(0)); - while (1) { - uint32_t fifo_len = READ_REG(UART_STATUS(0)) & UART_RXFIFO_CNT_M; - if (fifo_len == 0) { - break; - } - while (fifo_len-- > 0) { - uint8_t byte = READ_REG(UART_FIFO(0)) & 0xff; - (*s_rx_cb_func)(byte); - } - } - WRITE_REG(UART_INT_CLR(0), int_st); -} - -#if WITH_USB_JTAG_SERIAL -bool stub_uses_usb_jtag_serial(void) -{ - UartDevice *uart = GetUartDevice(); - - /* buff_uart_no indicates which UART is used for SLIP communication) */ - return uart->buff_uart_no == UART_USB_JTAG_SERIAL; -} - -void jtag_serial_isr(void *arg) -{ - WRITE_REG(USB_DEVICE_INT_CLR_REG, USB_DEVICE_SERIAL_OUT_RECV_PKT_INT_CLR); //ack interrupt - while (READ_REG(USB_DEVICE_EP1_CONF_REG) & USB_DEVICE_SERIAL_OUT_EP_DATA_AVAIL) - { - uint8_t byte = READ_REG(USB_DEVICE_EP1_REG); - (*s_rx_cb_func)(byte); - } -} -#endif // WITH_USB_JTAG_SERIAL - -static void stub_configure_rx_uart(void) -{ - /* All UART reads come via uart_isr or jtag_serial_isr */ -#if WITH_USB_JTAG_SERIAL - if (stub_uses_usb_jtag_serial()) { - #if IS_RISCV - #if ESP32P4 - WRITE_REG(INTERRUPT_CORE0_USB_INTR_MAP_REG, ETS_USB_INUM + CLIC_EXT_INTR_NUM_OFFSET); - #else - WRITE_REG(INTERRUPT_CORE0_USB_INTR_MAP_REG, ETS_USB_INUM); // Route USB interrupt to CPU - #endif - esprv_intc_int_set_priority(ETS_USB_INUM, 1); - #else - WRITE_REG(INTERRUPT_CORE0_USB_DEVICE_INT_MAP_REG, ETS_USB_INUM); - #endif // IS_RISCV - ets_isr_attach(ETS_USB_INUM, jtag_serial_isr, NULL); - WRITE_REG(USB_DEVICE_INT_ENA_REG, USB_DEVICE_SERIAL_OUT_RECV_PKT_INT_ENA); - ets_isr_unmask(1 << ETS_USB_INUM); - return; - } -#endif // WITH_USB_JTAG_SERIAL - ets_isr_attach(ETS_UART0_INUM, uart_isr, NULL); - REG_SET_MASK(UART_INT_ENA(0), UART_RX_INTS); - ets_isr_unmask(1 << ETS_UART0_INUM); -} - -#ifdef WITH_USB_OTG - -void stub_cdcacm_cb(cdc_acm_device *dev, int status) -{ - if (status == ACM_STATUS_RX) { - while (cdc_acm_rx_fifo_cnt(uart_acm_dev) > 0) { - uint8_t c; - cdc_acm_fifo_read(uart_acm_dev, &c, 1); - (*s_rx_cb_func)((char) c); - } - } else if (status == ACM_STATUS_LINESTATE_CHANGED) { - uint32_t rts = 0; - cdc_acm_line_ctrl_get(dev, LINE_CTRL_RTS, &rts); - if (rts == 0 && s_cdcacm_old_rts == 1) { - s_cdcacm_reset_requested = true; - } - s_cdcacm_old_rts = rts; - } -} - -static void stub_cdcacm_flush(void) -{ - cdc_acm_fifo_fill(uart_acm_dev, (const uint8_t *) s_cdcacm_txbuf, s_cdcacm_txpos); - /* return value ignored — if bootloader fails to log something, proceed anyway */ - s_cdcacm_txpos = 0; -} - -static void stub_cdcacm_write_char(char ch) -{ - s_cdcacm_txbuf[s_cdcacm_txpos++] = ch; - if (ch == '\xc0' || s_cdcacm_txpos == sizeof(s_cdcacm_txbuf)) { - stub_cdcacm_flush(); - } -} - -bool stub_uses_usb_otg(void) -{ - UartDevice *uart = GetUartDevice(); - - /* buff_uart_no indicates which UART is used for SLIP communication) */ - return uart->buff_uart_no == UART_USB_OTG; -} - -#ifdef ESP32S3 -static void usb_dw_isr_handler_wrapper(void *arg) -{ - /* ISR handler wrapper added as a workaround for the failure of compressed flashing using USB OTG. - * - * LoadStoreException happens inside the first call of tinfl_decompress() where the a13 register gets corrupted by - * the address of usb_dw_isr_handler(). The corruption probably still happens with this workaround but because of - * the nested call another register window is used. - * - * Other possible workarounds: - * - wait at least 25 ms before the tinfl_decompress() so usb_dw_isr_handler() would finish and not corrupt the - * pointer inside of tinfl_decompress(), or - * - disable the USB interrupt during tinfl_decompress(). - */ - usb_dw_isr_handler(arg); -} -#else -#define usb_dw_isr_handler_wrapper usb_dw_isr_handler -#endif //ESP32S3 - -static void stub_configure_rx_usb(void) -{ - cdc_acm_line_ctrl_get(uart_acm_dev, LINE_CTRL_RTS, &s_cdcacm_old_rts); - #if ESP32S2 - intr_matrix_set(0, ETS_USB_INTR_SOURCE, ETS_USB_INUM); - #elif ESP32S3 - WRITE_REG(INTERRUPT_CORE0_USB_INTR_MAP_REG, ETS_USB_INUM); - #endif - ets_isr_attach(ETS_USB_INUM, usb_dw_isr_handler_wrapper, NULL); - ets_isr_unmask(1 << ETS_USB_INUM); - cdc_acm_irq_callback_set(uart_acm_dev, &stub_cdcacm_cb); - cdc_acm_irq_rx_enable(uart_acm_dev); - cdc_acm_irq_state_enable(uart_acm_dev); - REG_SET_MASK(USB_GAHBCFG_REG, USB_GLBLLNTRMSK); -} -#endif // WITH_USB_OTG - -void stub_tx_one_char(char c) -{ -#if WITH_USB_OTG - if (stub_uses_usb_otg()) { - stub_cdcacm_write_char(c); - return; - } -#endif // WITH_USB_OTG - uart_tx_one_char(c); -#if WITH_USB_JTAG_SERIAL - static unsigned short transferred_without_flush = 0; - if (stub_uses_usb_jtag_serial()){ - // Defer flushing until we have a (full - 1) packet or a end of packet (0xc0) byte to increase throughput. - // Note that deferring flushing until we have a full packet can cause hang-ups on some platforms. - ++transferred_without_flush; - if (c == '\xc0' || transferred_without_flush >= 63) { - stub_tx_flush(); - transferred_without_flush = 0; - } - } -#endif // WITH_USB_JTAG_SERIAL -} - -void stub_tx_flush(void) -{ -#if WITH_USB_OTG - if (stub_uses_usb_otg()) { - if (s_cdcacm_txpos > 0) { - stub_cdcacm_flush(); - } - } -#endif // WITH_USB_OTG -#if WITH_USB_JTAG_SERIAL - if (stub_uses_usb_jtag_serial()){ - uart_tx_flush(UART_USB_JTAG_SERIAL); - return; - } -#endif // WITH_USB_JTAG_SERIAL -#if ESP32_OR_LATER - uart_tx_flush(0); -#endif -} - -char stub_rx_one_char(void) -{ - char c = 0; - /* Using uart_rx_one_char here instead of uart_rx_one_char_block, - * because the latter simply returns (char) 0 if no bytes - * are available, when used with USB CDC. - */ - while (uart_rx_one_char((uint8_t*) &c) != 0) { } - return c; -} - -void stub_rx_async_enable(bool enable) -{ - uint32_t mask; -#if WITH_USB_OTG - if (stub_uses_usb_otg()) { - mask = 1 << ETS_USB_INUM; - if (enable) { - cdc_acm_irq_rx_enable(uart_acm_dev); - ets_isr_unmask(mask); - } else { - ets_isr_mask(mask); - cdc_acm_irq_rx_disable(uart_acm_dev); - } - return; - } -#endif // WITH_USB_OTG -#if WITH_USB_JTAG_SERIAL - mask = stub_uses_usb_jtag_serial() ? 1 << ETS_USB_INUM : 1 << ETS_UART0_INUM; -#else - mask = 1 << ETS_UART0_INUM; -#endif - if (enable) { - ets_isr_unmask(mask); - } else { - ets_isr_mask(mask); - } -} - -void stub_io_idle_hook(void) -{ -#if WITH_USB_OTG - if (s_cdcacm_reset_requested) - { - s_cdcacm_reset_requested = false; - ets_isr_mask(1 << ETS_USB_INUM); - ets_delay_us(10000); - /* Handle the last few interrupts as they come in before the USB peripheral is idle */ - usb_dc_check_poll_for_interrupts(); - REG_CLR_MASK(RTC_CNTL_OPTION1_REG, RTC_CNTL_FORCE_DOWNLOAD_BOOT); - chip_usb_set_persist_flags(USBDC_PERSIST_ENA); - usb_dc_prepare_persist(); - software_reset_cpu(0); - } -#endif // WITH_USB_OTG -} - -void stub_io_init(void(*rx_cb_func)(char)) -{ - s_rx_cb_func = rx_cb_func; -#if WITH_USB_OTG - if (stub_uses_usb_otg()) { - stub_configure_rx_usb(); - return; - } -#endif // WITH_USB_OTG - stub_configure_rx_uart(); -} - -static uint32_t get_new_uart_divider(uint32_t current_baud, uint32_t new_baud) -{ - uint32_t master_freq; - /* ESP32 has ROM code to detect the crystal freq but ESP8266 does not have this... - So instead we use the previously auto-synced 115200 baud rate (which we know - is correct wrt the relative crystal accuracy of the ESP & the USB/serial adapter). - From this we can estimate crystal freq, and update for a new baud rate relative to that. - */ - uint32_t uart_reg = READ_REG(UART_CLKDIV_REG(0)); - uint32_t uart_div = uart_reg & UART_CLKDIV_M; -#if ESP32_OR_LATER - // account for fractional part of divider (bottom 4 bits) - uint32_t fraction = (uart_reg >> UART_CLKDIV_FRAG_S) & UART_CLKDIV_FRAG_V; - uart_div = (uart_div << 4) + fraction; -#endif - master_freq = uart_div * current_baud; - return master_freq / new_baud; -} - -void stub_io_set_baudrate(uint32_t current_baud, uint32_t new_baud) -{ -#if WITH_USB_OTG - /* Technically no harm in increasing UART baud rate when communicating over USB, - * however for debugging the USB part it is occasionally useful to ets_printf - * something to UART. Not changing the baud rate helps in such case. - */ - if (stub_uses_usb_otg()) { - return; - } -#endif // WITH_USB_OTG - ets_delay_us(10000); - uart_div_modify(0, get_new_uart_divider(current_baud, new_baud)); - ets_delay_us(1000); -} diff --git a/tools/esptool_py/flasher_stub/stub_write_flash.c b/tools/esptool_py/flasher_stub/stub_write_flash.c deleted file mode 100644 index e925d9f74f..0000000000 --- a/tools/esptool_py/flasher_stub/stub_write_flash.c +++ /dev/null @@ -1,480 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2016 Cesanta Software Limited - * - * SPDX-License-Identifier: GPL-2.0-or-later - * - * SPDX-FileContributor: 2016-2022 Espressif Systems (Shanghai) CO LTD - */ - -#include "soc_support.h" -#include "stub_write_flash.h" -#include "stub_flasher.h" -#include "rom_functions.h" -#include "miniz.h" - -/* local flashing state - - This is wrapped in a structure because gcc 4.8 - generates significantly more code for ESP32 - if they are static variables (literal pool, I think!) -*/ -static struct { - /* set by flash_begin, cleared by flash_end */ - bool in_flash_mode; - /* offset of next SPI write */ - uint32_t next_write; - /* sector number for next erase */ - int next_erase_sector; - /* number of output bytes remaining to write */ - uint32_t remaining; - /* number of sectors remaining to erase */ - int remaining_erase_sector; - /* last error generated by a data packet */ - esp_command_error last_error; - - /* inflator state for deflate write */ - tinfl_decompressor inflator; - /* number of compressed bytes remaining to read */ - uint32_t remaining_compressed; -} fs; - -/* SPI status bits */ -static const uint32_t STATUS_WIP_BIT = (1 << 0); -#if ESP32_OR_LATER -static const uint32_t STATUS_QIE_BIT = (1 << 9); /* Quad Enable */ -#endif - -bool is_in_flash_mode(void) -{ - return fs.in_flash_mode; -} - -esp_command_error get_flash_error(void) -{ - return fs.last_error; -} - -/* Wait for the SPI state machine to be ready, - ie no command in progress in the internal host. -*/ -inline static void spi_wait_ready(void) -{ - /* Wait for SPI state machine ready */ - while((READ_REG(SPI_EXT2_REG) & SPI_ST)) - { } -#if ESP32_OR_LATER - while(READ_REG(SPI0_EXT2_REG) & SPI_ST) - { } -#endif -} - -/* Returns true if the spiflash is ready for its next write - operation. - - Doesn't block, except for the SPI state machine to finish - any previous SPI host operation. -*/ -static bool spiflash_is_ready(void) -{ - spi_wait_ready(); - WRITE_REG(SPI_RD_STATUS_REG, 0); - /* Issue read status command */ - WRITE_REG(SPI_CMD_REG, SPI_FLASH_RDSR); - while(READ_REG(SPI_CMD_REG) != 0) - { } - uint32_t status_value = READ_REG(SPI_RD_STATUS_REG); - return (status_value & STATUS_WIP_BIT) == 0; -} - -static void spi_write_enable(void) -{ - while(!spiflash_is_ready()) - { } - WRITE_REG(SPI_CMD_REG, SPI_FLASH_WREN); - while(READ_REG(SPI_CMD_REG) != 0) - { } -} - -#if ESP32_OR_LATER -static esp_rom_spiflash_chip_t *flashchip = (esp_rom_spiflash_chip_t *)ROM_SPIFLASH_LEGACY; - -/* Stub version of SPIUnlock() that replaces version in ROM. - - This works around a bug where SPIUnlock sometimes reads the wrong - high status byte (RDSR2 result) and then copies it back to the - flash status, causing lock bit CMP or Status Register Protect ` to - become set. - */ -SpiFlashOpResult SPIUnlock(void) -{ - uint32_t status; - - spi_wait_ready(); /* ROM SPI_read_status_high() doesn't wait for this */ -#if ESP32S2_OR_LATER - if (SPI_read_status_high(flashchip, &status) != SPI_FLASH_RESULT_OK) { - return SPI_FLASH_RESULT_ERR; - } -#else - if (SPI_read_status_high(&status) != SPI_FLASH_RESULT_OK) { - return SPI_FLASH_RESULT_ERR; - } -#endif // ESP32S2_OR_LATER - - /* Clear all bits except QIE, if it is set. - (This is different from ROM SPIUnlock, which keeps all bits as-is.) - */ - status &= STATUS_QIE_BIT; - - spi_write_enable(); - - REG_SET_MASK(SPI_CTRL_REG, SPI_WRSR_2B); - if (SPI_write_status(flashchip, status) != SPI_FLASH_RESULT_OK) { - return SPI_FLASH_RESULT_ERR; - } - - return SPI_FLASH_RESULT_OK; -} -#endif // ESP32_OR_LATER - -#if defined(ESP32S3) && !defined(ESP32S3BETA2) -static esp_rom_spiflash_result_t page_program_internal(int spi_num, uint32_t spi_addr, uint8_t* addr_source, uint32_t byte_length) -{ - uint32_t temp_addr; - int32_t temp_bl; - esp_rom_opiflash_wait_idle(); - temp_addr = spi_addr; - temp_bl = byte_length; - uint32_t temp_len = 0; - - const uint16_t cmd = CMD_PROGRAM_PAGE_4B; - uint8_t cmd_len = 8; - int dummy = 0; - - while (temp_bl > 0 ) { - esp_rom_opiflash_wren(); - temp_len = (temp_bl >= 32) ? 32 : temp_bl; //32 = write_sub_len - esp_rom_opiflash_exec_cmd(spi_num, SPI_FLASH_FASTRD_MODE, - cmd, cmd_len, - temp_addr, 32, - dummy, - addr_source, 8 * temp_len, - NULL, 0, - ESP_ROM_OPIFLASH_SEL_CS0, - true); - esp_rom_opiflash_wait_idle(); - addr_source += temp_len; - temp_addr += temp_len; - temp_bl -= temp_len; - } - return ESP_ROM_SPIFLASH_RESULT_OK; -} -#endif // ESP32S3 - -#if defined(ESP32S3) && !defined(ESP32S3BETA2) -static esp_rom_spiflash_result_t SPIWrite4B(int spi_num, uint32_t target, uint8_t *src_addr, int32_t len) -{ - uint32_t page_size = 256; - uint32_t pgm_len, pgm_num; - uint8_t i; - - esp_rom_opiflash_wait_idle(); - pgm_len = page_size - (target % page_size); - if (len < pgm_len) { - page_program_internal(spi_num, target, src_addr, len); - } else { - page_program_internal(spi_num, target, src_addr, pgm_len); - //whole page program - pgm_num = (len - pgm_len) / page_size; - for (i = 0; i < pgm_num; i++) { - page_program_internal(spi_num, target + pgm_len, (src_addr + pgm_len), page_size); - pgm_len += page_size; - } - //remain parts to program - page_program_internal(spi_num, target + pgm_len, (src_addr + pgm_len), len - pgm_len); - } - esp_rom_opiflash_wait_idle(); - return ESP_ROM_SPIFLASH_RESULT_OK; -} -#endif // defined(ESP32S3) && !defined(ESP32S3BETA2) - -esp_command_error handle_flash_begin(uint32_t total_size, uint32_t offset) { - fs.in_flash_mode = true; - fs.next_write = offset; - fs.next_erase_sector = offset / FLASH_SECTOR_SIZE; - fs.remaining = total_size; - fs.remaining_erase_sector = ((offset % FLASH_SECTOR_SIZE) + total_size + FLASH_SECTOR_SIZE - 1) / FLASH_SECTOR_SIZE; - fs.last_error = ESP_OK; - -#if defined(ESP32S3) && !defined(ESP32S3BETA2) - if (large_flash_mode) { - esp_rom_opiflash_wait_idle(); - } else { - if (SPIUnlock() != 0) { - return ESP_FAILED_SPI_UNLOCK; - } - } -#else - if (SPIUnlock() != 0) { - return ESP_FAILED_SPI_UNLOCK; - } -#endif //defined(ESP32S3) and !defined(ESP32S3BETA2) - - return ESP_OK; -} - -esp_command_error handle_flash_deflated_begin(uint32_t uncompressed_size, uint32_t compressed_size, uint32_t offset) { - esp_command_error err = handle_flash_begin(uncompressed_size, offset); - tinfl_init(&fs.inflator); - fs.remaining_compressed = compressed_size; - return err; -} - -/* Erase the next sector or block (depending if we're at a block boundary). - - Updates fs.next_erase_sector & fs.remaining_erase_sector on success. - - If nothing left to erase, returns immediately. - - Returns immediately if SPI flash not yet ready for a write operation. - - Does not wait for the erase to complete - the next SPI operation - should check if a write operation is currently in progress. - */ -static void start_next_erase(void) -{ - bool block_erase = false; - - if(fs.remaining_erase_sector == 0) - return; /* nothing left to erase */ - if(!spiflash_is_ready()) - return; /* don't wait for flash to be ready, caller will call again if needed */ - - if(fs.remaining_erase_sector >= SECTORS_PER_BLOCK - && fs.next_erase_sector % SECTORS_PER_BLOCK == 0) { - /* perform a 64KB block erase if we have space for it */ - block_erase = true; - } - - spi_write_enable(); - spi_wait_ready(); - #if defined(ESP32S3) && !defined(ESP32S3BETA2) - if (large_flash_mode) { - if (block_erase) { - if (fs.next_erase_sector * FLASH_SECTOR_SIZE < (1 << 24)) { - esp_rom_opiflash_wait_idle(); - esp_rom_opiflash_wren(); - - esp_rom_opiflash_exec_cmd(1, SPI_FLASH_SLOWRD_MODE, - CMD_LARGE_BLOCK_ERASE, 8, - fs.next_erase_sector * FLASH_SECTOR_SIZE, 24, - 0, - NULL, 0, - NULL, 0, - 1, - true); - esp_rom_opiflash_wait_idle(); - } else { - esp_rom_opiflash_erase_block_64k(fs.next_erase_sector / SECTORS_PER_BLOCK); - } - } - else { - if (fs.next_erase_sector * FLASH_SECTOR_SIZE < (1 << 24)) { - esp_rom_opiflash_wait_idle(); - esp_rom_opiflash_wren(); - - esp_rom_opiflash_exec_cmd(1, SPI_FLASH_SLOWRD_MODE, - CMD_SECTOR_ERASE, 8, - fs.next_erase_sector * FLASH_SECTOR_SIZE, 24, - 0, - NULL, 0, - NULL, 0, - 1, - true); - esp_rom_opiflash_wait_idle(); - } else { - esp_rom_opiflash_erase_sector(fs.next_erase_sector); - } - } - } else { - uint32_t addr = fs.next_erase_sector * FLASH_SECTOR_SIZE; - uint32_t command = block_erase ? SPI_FLASH_BE : SPI_FLASH_SE; /* block erase, 64KB : sector erase, 4KB */ - WRITE_REG(SPI_ADDR_REG, addr & 0xffffff); - WRITE_REG(SPI_CMD_REG, command); - while(READ_REG(SPI_CMD_REG) != 0) { } - } - #else - uint32_t addr = fs.next_erase_sector * FLASH_SECTOR_SIZE; - uint32_t command = block_erase ? SPI_FLASH_BE : SPI_FLASH_SE; /* block erase, 64KB : sector erase, 4KB */ - WRITE_REG(SPI_ADDR_REG, addr & 0xffffff); - WRITE_REG(SPI_CMD_REG, command); - while(READ_REG(SPI_CMD_REG) != 0) { } - #endif // defined(ESP32S3) && !defined(ESP32S3BETA2) - - uint32_t sectors_to_erase = block_erase ? SECTORS_PER_BLOCK : 1; - fs.remaining_erase_sector -= sectors_to_erase; - fs.next_erase_sector += sectors_to_erase; -} - -/* Write data to flash (either direct for non-compressed upload, or - freshly decompressed.) Erases as it goes. - - Updates fs.remaining_erase_sector, fs.next_write, and fs.remaining -*/ -void handle_flash_data(void *data_buf, uint32_t length) { - int last_sector; - uint8_t res = 0; - - if (length > fs.remaining) { - /* Trim the final block, as it may have padding beyond - the length we are writing */ - length = fs.remaining; - } - - if (length == 0) { - return; - } - - /* what sector is this write going to end in? - make sure we've erased at least that far. - */ - last_sector = (fs.next_write + length) / FLASH_SECTOR_SIZE; - while(fs.remaining_erase_sector > 0 && fs.next_erase_sector <= last_sector) { - start_next_erase(); - } - while(!spiflash_is_ready()) - {} - - /* do the actual write */ - #if defined(ESP32S3) && !defined(ESP32S3BETA2) - if (large_flash_mode){ - res = SPIWrite4B(1, fs.next_write, data_buf, length); - } else { - res = SPIWrite(fs.next_write, data_buf, length); - } - #else - res = SPIWrite(fs.next_write, data_buf, length); - #endif // defined(ESP32S3) && !defined(ESP32S3BETA2) - if (res != 0) - fs.last_error = ESP_FAILED_SPI_OP; - fs.next_write += length; - fs.remaining -= length; -} - -#if !ESP8266 -/* Write encrypted data to flash (either direct for non-compressed upload, or - freshly decompressed.) Erases as it goes. - - Updates fs.remaining_erase_sector, fs.next_write, and fs.remaining -*/ -void handle_flash_encrypt_data(void *data_buf, uint32_t length) { - int last_sector; - int res; - -#if ESP32S2_OR_LATER - SPI_Write_Encrypt_Enable(); -#endif - - if (length > fs.remaining) { - /* Trim the final block, as it may have padding beyond - the length we are writing */ - length = fs.remaining; - } - - if (length == 0) { - return; - } - - /* what sector is this write going to end in? - make sure we've erased at least that far. - */ - last_sector = (fs.next_write + length) / FLASH_SECTOR_SIZE; - while(fs.remaining_erase_sector > 0 && fs.next_erase_sector <= last_sector) { - start_next_erase(); - } - while(!spiflash_is_ready()) - {} - - /* do the actual write */ -#if ESP32 - res = esp_rom_spiflash_write_encrypted(fs.next_write, data_buf, length); -#else - res = SPI_Encrypt_Write(fs.next_write, data_buf, length); -#endif - - if (res) { - fs.last_error = ESP_FAILED_SPI_OP; - } - fs.next_write += length; - fs.remaining -= length; - -#if ESP32S2_OR_LATER - SPI_Write_Encrypt_Disable(); -#endif -} - -#endif // !ESP8266 - -void handle_flash_deflated_data(void *data_buf, uint32_t length) { - /* if all data has been uploaded and another block comes, - accept it only if it is part of a 4-byte Adler-32 checksum */ - if (fs.remaining == 0 && length > 4) { - fs.last_error = ESP_TOO_MUCH_DATA; - return; - } - - static uint8_t out_buf[32768]; - static uint8_t *next_out = out_buf; - int status = TINFL_STATUS_NEEDS_MORE_INPUT; - - while(length > 0 && fs.remaining > 0 && status > TINFL_STATUS_DONE) { - size_t in_bytes = length; /* input remaining */ - size_t out_bytes = out_buf + sizeof(out_buf) - next_out; /* output space remaining */ - int flags = TINFL_FLAG_PARSE_ZLIB_HEADER; - if(fs.remaining_compressed > length) { - flags |= TINFL_FLAG_HAS_MORE_INPUT; - } - - /* start an opportunistic erase: decompressing takes time, so might as - well be running a SPI erase in the background. */ - start_next_erase(); - - status = tinfl_decompress(&fs.inflator, data_buf, &in_bytes, - out_buf, next_out, &out_bytes, - flags); - - fs.remaining_compressed -= in_bytes; - length -= in_bytes; - data_buf += in_bytes; - - next_out += out_bytes; - size_t bytes_in_out_buf = next_out - out_buf; - if (status == TINFL_STATUS_DONE || bytes_in_out_buf == sizeof(out_buf)) { - // Output buffer full, or done - handle_flash_data(out_buf, bytes_in_out_buf); - next_out = out_buf; - } - } // while - - if (status < TINFL_STATUS_DONE) { - /* error won't get sent back to esptool.py until next block is sent */ - fs.last_error = ESP_INFLATE_ERROR; - } - - if (status == TINFL_STATUS_DONE && fs.remaining > 0) { - fs.last_error = ESP_NOT_ENOUGH_DATA; - } -} - -esp_command_error handle_flash_end(void) -{ - if (!fs.in_flash_mode) { - return ESP_NOT_IN_FLASH_MODE; - } - - if (fs.remaining > 0) { - return ESP_NOT_ENOUGH_DATA; - } - - fs.in_flash_mode = false; - return fs.last_error; -} diff --git a/tools/esptool_py/flasher_stub/wrap_stub.py b/tools/esptool_py/flasher_stub/wrap_stub.py deleted file mode 100755 index f63db4f25a..0000000000 --- a/tools/esptool_py/flasher_stub/wrap_stub.py +++ /dev/null @@ -1,90 +0,0 @@ -#!/usr/bin/env python -# -# SPDX-FileCopyrightText: 2016 Cesanta Software Limited -# -# SPDX-License-Identifier: GPL-2.0-or-later -# -# SPDX-FileContributor: 2016-2022 Espressif Systems (Shanghai) CO LTD - -import argparse -import base64 -import json -import os -import os.path -import sys - -sys.path.append("..") -import esptool # noqa: E402 - -THIS_DIR = os.path.dirname(__file__) -BUILD_DIR = os.path.join(THIS_DIR, "build") - - -def wrap_stub(elf_file): - """Wrap an ELF file into a stub JSON dict""" - print("Wrapping ELF file %s..." % elf_file) - - e = esptool.bin_image.ELFFile(elf_file) - - text_section = e.get_section(".text") - stub = { - "entry": e.entrypoint, - "text": text_section.data, - "text_start": text_section.addr, - } - try: - data_section = e.get_section(".data") - stub["data"] = data_section.data - stub["data_start"] = data_section.addr - except ValueError: - pass - - for s in e.nobits_sections: - if s.name == ".bss": - stub["bss_start"] = s.addr - - # Pad text with NOPs to mod 4. - if len(stub["text"]) % 4 != 0: - stub["text"] += (4 - (len(stub["text"]) % 4)) * "\0" - - print( - "Stub text: %d @ 0x%08x, data: %d @ 0x%08x, entry @ 0x%x" - % ( - len(stub["text"]), - stub["text_start"], - len(stub.get("data", "")), - stub.get("data_start", 0), - stub["entry"], - ), - file=sys.stderr, - ) - - return stub - - -def write_json_files(stubs_dict): - class BytesEncoder(json.JSONEncoder): - def default(self, obj): - if isinstance(obj, bytes): - return base64.b64encode(obj).decode("ascii") - return json.JSONEncoder.default(self, obj) - - for filename, stub_data in stubs_dict.items(): - with open(os.path.join(BUILD_DIR, filename), "w") as outfile: - json.dump(stub_data, outfile, cls=BytesEncoder, indent=4) - - -def stub_name(filename): - """Return a dictionary key for the stub with filename 'filename'""" - return os.path.splitext(os.path.basename(filename))[0] + ".json" - - -if __name__ == "__main__": - parser = argparse.ArgumentParser() - parser.add_argument("elf_files", nargs="+", help="Stub ELF files to convert") - args = parser.parse_args() - - stubs = dict( - (stub_name(elf_file), wrap_stub(elf_file)) for elf_file in args.elf_files - ) - write_json_files(stubs) diff --git a/tools/esptool_py/pyproject.toml b/tools/esptool_py/pyproject.toml index 96eb71a059..2079bb95a0 100644 --- a/tools/esptool_py/pyproject.toml +++ b/tools/esptool_py/pyproject.toml @@ -11,7 +11,7 @@ ] readme = {file = "README.md", content-type = "text/markdown"} license = {text = "GPLv2+"} - description = "A serial utility to communicate & flash code to Espressif chips." + description = "A serial utility for flashing, provisioning, and interacting with Espressif SoCs." classifiers = [ "Development Status :: 5 - Production/Stable", "Intended Audience :: Developers", @@ -22,25 +22,23 @@ "Topic :: Software Development :: Embedded Systems", "Environment :: Console", "License :: OSI Approved :: GNU General Public License v2 or later (GPLv2+)", - "Programming Language :: Python :: 3.7", - "Programming Language :: Python :: 3.8", - "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", ] - requires-python = ">=3.7" + requires-python = ">=3.10" dynamic = ["version", "scripts"] dependencies = [ "bitstring>=3.1.6,!=4.2.0", - "cryptography>=2.1.4", - "ecdsa>=0.16.0", + "cryptography>=43.0.0", "pyserial>=3.3", "reedsolo>=1.5.3,<1.8", "PyYAML>=5.1", "intelhex", - 'argcomplete>=3; sys_platform != "win32"', + "rich_click", + "click<8.2.0", ] [project.urls] @@ -58,9 +56,13 @@ "pytest", "pytest-rerunfailures", "requests", - "commitizen", + "czespressif", ] hsm = ["python-pkcs11"] + docs = [ + "esp-docs~=1.10", + "sphinx-tabs", + ] [tool.setuptools] include-package-data = true @@ -75,7 +77,8 @@ version = {attr = "esptool.__init__.__version__"} [tool.commitizen] - version = "4.8.1" + name = "czespressif" + version = "5.0.0" update_changelog_on_bump = true tag_format = "v$version" changelog_start_rev = "v4.2.1" @@ -85,19 +88,7 @@ version_files = [ "esptool/__init__.py:__version__" ] - change_type_order = [ - "BREAKING CHANGE", - "New Features", - "Bug Fixes", - "Code Refactoring", - "Performance Improvements" - ] -[tool.commitizen.change_type_map] - feat = "New Features" - fix = "Bug Fixes" - refactor = "Code Refactoring" - perf = "Performance Improvements" [tool.codespell] skip = '*.bin,*test/images/efuse/*,*docs/en/espefuse/inc/*' @@ -108,7 +99,7 @@ disallow_incomplete_defs = false # Disallows defining functions with incomplete type annotations disallow_untyped_defs = false # Disallows defining functions without type annotations or with incomplete type annotations ignore_missing_imports = true # Suppress error messages about imports that cannot be resolved - python_version = "3.7" # Specifies the Python version used to parse and check the target program + python_version = "3.10" # Specifies the Python version used to parse and check the target program warn_no_return = true # Shows errors for missing return statements on some execution paths warn_return_any = true # Shows a warning when returning a value with type Any from a function declared with a non- Any return type @@ -122,18 +113,14 @@ ] line-length = 88 - - select = ['E', 'F', 'W'] - ignore = ["E203"] - - target-version = "py37" + target-version = "py310" [tool.ruff.lint] # Enable Pyflakes (`F`) and a subset of the pycodestyle (`E`) codes by default. # Unlike Flake8, Ruff doesn't enable pycodestyle warnings (`W`) or # McCabe complexity (`C901`) by default. - select = ["E4", "E7", "E9", "F"] - ignore = [] + select = ['E', 'F', 'W'] + ignore = ["E203"] # Allow fix for all enabled rules (when `--fix`) is provided. fixable = ["ALL"] diff --git a/tools/esptool_py/setup.py b/tools/esptool_py/setup.py index 0ba8099218..6dfef4f9dd 100644 --- a/tools/esptool_py/setup.py +++ b/tools/esptool_py/setup.py @@ -2,12 +2,25 @@ from setuptools import setup if os.name != "nt": + # For backward compatibility with py suffix scripts = ["esptool.py", "espefuse.py", "espsecure.py", "esp_rfc2217_server.py"] - entry_points = {} + entry_points = { + "console_scripts": [ + "esptool=esptool.__init__:_main", + "espsecure=espsecure.__init__:_main", + "espefuse=espefuse.__init__:_main", + "esp_rfc2217_server=esp_rfc2217_server.__init__:main", + ], + } else: scripts = [] entry_points = { "console_scripts": [ + "esptool=esptool.__init__:_main", + "espsecure=espsecure.__init__:_main", + "espefuse=espefuse.__init__:_main", + "esp_rfc2217_server=esp_rfc2217_server.__init__:main", + # For backward compatibility with py suffix "esptool.py=esptool.__init__:_main", "espsecure.py=espsecure.__init__:_main", "espefuse.py=espefuse.__init__:_main", diff --git a/tools/esptool_py/test/README.md b/tools/esptool_py/test/README.md index aa1431880a..5aeb8e2701 100644 --- a/tools/esptool_py/test/README.md +++ b/tools/esptool_py/test/README.md @@ -1,3 +1,3 @@ -# esptool.py test suite +# esptool test suite -See the [Automated Integration Tests section in `esptool.py` documentation](https://docs.espressif.com/projects/esptool/en/latest/esp32/contributing.html#automated-integration-tests) to learn about the test suite and how to run it. +See the [Automated Integration Tests section in `esptool` documentation](https://docs.espressif.com/projects/esptool/en/latest/esp32/contributing.html#automated-integration-tests) to learn about the test suite and how to run it. diff --git a/tools/esptool_py/test/conftest.py b/tools/esptool_py/test/conftest.py index b87fe56248..9e64d199c8 100644 --- a/tools/esptool_py/test/conftest.py +++ b/tools/esptool_py/test/conftest.py @@ -1,4 +1,5 @@ import pytest +import os def pytest_addoption(parser): @@ -59,3 +60,11 @@ def need_to_install_package_err(): "Instructions: https://docs.espressif.com/projects/esptool/en/latest/" "contributing.html#development-setup" ) + + +@pytest.fixture(scope="session", autouse=True) +def set_terminal_properties(): + """Make sure terminal width is set to 120 columns and color is disabled for + consistent test output.""" + os.environ["COLUMNS"] = "120" + os.environ["NO_COLOR"] = "1" diff --git a/tools/esptool_py/test/efuse_scripts/efuse_burn1.py b/tools/esptool_py/test/efuse_scripts/efuse_burn1.py deleted file mode 100644 index ea337ed8bc..0000000000 --- a/tools/esptool_py/test/efuse_scripts/efuse_burn1.py +++ /dev/null @@ -1,18 +0,0 @@ -# flake8: noqa -# SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD -# -# SPDX-License-Identifier: GPL-2.0-or-later - -import json - -config = json.load(args.configfiles[0]) - - -assert args.index == 10, "Index should be 10" - -for cmd in config["burn_efuses1"]: - cmd = cmd.format(index=args.index) - print(cmd) - espefuse(esp, efuses, args, cmd) - -assert args.index == 10, "Index should be 10" diff --git a/tools/esptool_py/test/efuse_scripts/efuse_burn2.py b/tools/esptool_py/test/efuse_scripts/efuse_burn2.py deleted file mode 100644 index 559f2cdbea..0000000000 --- a/tools/esptool_py/test/efuse_scripts/efuse_burn2.py +++ /dev/null @@ -1,18 +0,0 @@ -# flake8: noqa -# SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD -# -# SPDX-License-Identifier: GPL-2.0-or-later - -import json - -config = json.load(args.configfiles[0]) - - -assert args.index == 28, "Should be index from the first script = 28" - -for cmd in config["burn_efuses2"]: - cmd = cmd.format(index=args.index) - print(cmd) - espefuse(esp, efuses, args, cmd) - -assert args.index == 28, "Should be index from the first script = 28" diff --git a/tools/esptool_py/test/efuse_scripts/esp32/config1.json b/tools/esptool_py/test/efuse_scripts/esp32/config1.json deleted file mode 100644 index 45f59311c7..0000000000 --- a/tools/esptool_py/test/efuse_scripts/esp32/config1.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "burn_efuses1": [ - "burn_bit BLOCK3 0 1 2 3 4 5 6 7 8 9 {index}", - "burn_bit BLOCK3 29 30 31" - ] -} \ No newline at end of file diff --git a/tools/esptool_py/test/efuse_scripts/esp32/config2.json b/tools/esptool_py/test/efuse_scripts/esp32/config2.json deleted file mode 100644 index d509222f35..0000000000 --- a/tools/esptool_py/test/efuse_scripts/esp32/config2.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "burn_efuses2": [ - "burn_bit BLOCK3 11 12 13 14 15 16 17 18 19", - "burn_bit BLOCK3 20 21 22 23 24 25 26 27 {index}", - "execute_scripts efuse_scripts/efuse_burn1.py --index 10 --configfiles efuse_scripts/esp32/config1.json", - "burn_bit BLOCK2 {index}" - ] -} \ No newline at end of file diff --git a/tools/esptool_py/test/efuse_scripts/esp32/execute_efuse_script.py b/tools/esptool_py/test/efuse_scripts/esp32/execute_efuse_script.py deleted file mode 100644 index becedd026f..0000000000 --- a/tools/esptool_py/test/efuse_scripts/esp32/execute_efuse_script.py +++ /dev/null @@ -1,50 +0,0 @@ -# flake8: noqa -# fmt: off -espefuse(esp, efuses, args, "burn_efuse JTAG_DISABLE 1 DISABLE_SDIO_HOST 1 CONSOLE_DEBUG_DISABLE 1") -espefuse(esp, efuses, args, "burn_key flash_encryption ../../images/efuse/256bit --no-protect-key") -espefuse(esp, efuses, args, "burn_key_digest ../../secure_images/rsa_secure_boot_signing_key.pem") -espefuse(esp, efuses, args, "burn_bit BLOCK3 64 66 69 72 78 82 83 90") -espefuse(esp, efuses, args, "burn_custom_mac AA:BB:CC:DD:EE:88") - -efuses.burn_all() - -espefuse(esp, efuses, args, "summary") -espefuse(esp, efuses, args, "adc_info") -espefuse(esp, efuses, args, "get_custom_mac") - - -# Checks written eFuses -if efuses["JTAG_DISABLE"].get() != 1: - raise esptool.FatalError("JTAG_DISABLE was not set") -if efuses["DISABLE_SDIO_HOST"].get() != 1: - raise esptool.FatalError("DISABLE_SDIO_HOST was not set") -if efuses["CONSOLE_DEBUG_DISABLE"].get() != 1: - raise esptool.FatalError("CONSOLE_DEBUG_DISABLE was not set") - - -if efuses["BLOCK1"].get_meaning() != "bf be bd bc bb ba b9 b8 b7 b6 b5 b4 b3 b2 b1 b0 af ae ad ac ab aa a9 a8 a7 a6 a5 a4 a3 a2 a1 a0": - raise esptool.FatalError("BLOCK1 was not set correctly") - -if not efuses["BLOCK1"].is_readable() or not efuses["BLOCK1"].is_writeable(): - raise esptool.FatalError("BLOCK1 should be readable and writeable") - - -if efuses["BLOCK2"].get_meaning() != "cb 27 91 a3 71 b0 c0 32 2b f7 37 04 78 ba 09 62 22 4c ab 1c f2 28 78 79 e4 29 67 3e 7d a8 44 63": - raise esptool.FatalError("BLOCK2 was not set correctly") - -if not efuses["BLOCK2"].is_readable() or efuses["BLOCK2"].is_writeable(): - raise esptool.FatalError("BLOCK2 should not be readable and not writeable") - - -if efuses["BLOCK3"].get_meaning() != "69 aa bb cc dd ee 88 00 25 41 0c 04 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00": - raise esptool.FatalError("BLOCK3 was not set correctly") - -if efuses["CUSTOM_MAC"].get_meaning() != "aa:bb:cc:dd:ee:88 (CRC 0x69 OK)": - raise esptool.FatalError("CUSTOM_MAC was not set correctly") - - -espefuse(esp, efuses, args, "read_protect_efuse BLOCK1") -espefuse(esp, efuses, args, "write_protect_efuse BLOCK1") -efuses.burn_all() -if efuses["BLOCK1"].is_readable() or efuses["BLOCK1"].is_writeable(): - raise esptool.FatalError("BLOCK_KEY0 should be not readable and not writeable") diff --git a/tools/esptool_py/test/efuse_scripts/esp32/execute_efuse_script2.py b/tools/esptool_py/test/efuse_scripts/esp32/execute_efuse_script2.py deleted file mode 100644 index e906f61d14..0000000000 --- a/tools/esptool_py/test/efuse_scripts/esp32/execute_efuse_script2.py +++ /dev/null @@ -1,23 +0,0 @@ -# flake8: noqa -# fmt: off -espefuse(esp, efuses, args, "burn_efuse JTAG_DISABLE 1 DISABLE_SDIO_HOST 1 CONSOLE_DEBUG_DISABLE 1") -if efuses["JTAG_DISABLE"].get() != 0: - raise esptool.FatalError("Burn should be at the end") - -espefuse(esp, efuses, args, "burn_key flash_encryption ../../images/efuse/256bit --no-protect-key") -if efuses["BLOCK1"].get_meaning() != "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00": - raise esptool.FatalError("Burn should be at the end") -if not efuses["BLOCK1"].is_readable() or not efuses["BLOCK1"].is_writeable(): - raise esptool.FatalError("Burn should be at the end") - -espefuse(esp, efuses, args, "burn_key_digest ../../secure_images/rsa_secure_boot_signing_key.pem") -if efuses["BLOCK2"].get_meaning() != "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00": - raise esptool.FatalError("Burn should be at the end") -if not efuses["BLOCK2"].is_readable() or not efuses["BLOCK2"].is_writeable(): - raise esptool.FatalError("Burn should be at the end") - -espefuse(esp, efuses, args, "burn_bit BLOCK3 64 66 69 72 78 82 83 90") -espefuse(esp, efuses, args, "burn_custom_mac AA:BB:CC:DD:EE:88") - -if efuses["BLOCK3"].get_meaning() != "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00": - raise esptool.FatalError("Burn should be at the end") diff --git a/tools/esptool_py/test/efuse_scripts/esp32xx/config1.json b/tools/esptool_py/test/efuse_scripts/esp32xx/config1.json deleted file mode 100644 index b2f1201733..0000000000 --- a/tools/esptool_py/test/efuse_scripts/esp32xx/config1.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "burn_efuses1": [ - "burn_bit BLOCK_KEY4 0 1 2 3 4 5 6 7 8 9 {index}", - "burn_bit BLOCK_KEY4 29 30 31" - ] -} \ No newline at end of file diff --git a/tools/esptool_py/test/efuse_scripts/esp32xx/config2.json b/tools/esptool_py/test/efuse_scripts/esp32xx/config2.json deleted file mode 100644 index d4d5c02346..0000000000 --- a/tools/esptool_py/test/efuse_scripts/esp32xx/config2.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "burn_efuses2": [ - "burn_bit BLOCK_KEY4 11 12 13 14 15 16 17 18 19", - "burn_bit BLOCK_KEY4 20 21 22 23 24 25 26 27 {index}", - "execute_scripts efuse_scripts/efuse_burn1.py --index 10 --configfiles efuse_scripts/esp32xx/config1.json", - "burn_bit BLOCK_KEY3 {index}" - ] -} \ No newline at end of file diff --git a/tools/esptool_py/test/efuse_scripts/esp32xx/execute_efuse_script.py b/tools/esptool_py/test/efuse_scripts/esp32xx/execute_efuse_script.py deleted file mode 100644 index 9ccb0e408c..0000000000 --- a/tools/esptool_py/test/efuse_scripts/esp32xx/execute_efuse_script.py +++ /dev/null @@ -1,64 +0,0 @@ -# flake8: noqa -# fmt: off -espefuse(esp, efuses, args, 'burn_efuse DIS_FORCE_DOWNLOAD 1 DIS_DOWNLOAD_MODE 1') -espefuse(esp, efuses, args, 'burn_bit BLOCK_USR_DATA 64 66 69 72 78 82 83 90') -espefuse(esp, efuses, args, 'read_protect_efuse BLOCK_SYS_DATA2') -espefuse(esp, efuses, args, 'write_protect_efuse BLOCK_SYS_DATA2') -espefuse(esp, efuses, args, 'burn_block_data BLOCK_KEY5 ../../images/efuse/256bit') -espefuse(esp, efuses, args, 'burn_key BLOCK_KEY0 ../../images/efuse/256bit XTS_AES_128_KEY --no-read-protect') -espefuse(esp, efuses, args, 'burn_key_digest BLOCK_KEY1 ../../secure_images/rsa_secure_boot_signing_key.pem SECURE_BOOT_DIGEST0') - -efuses.burn_all() - -espefuse(esp, efuses, args, 'summary') -espefuse(esp, efuses, args, 'adc_info') - - -# Checks written eFuses -if efuses["DIS_FORCE_DOWNLOAD"].get() != 1: - raise esptool.FatalError("DIS_FORCE_DOWNLOAD was not set") -if efuses["DIS_DOWNLOAD_MODE"].get() != 1: - raise esptool.FatalError("DIS_DOWNLOAD_MODE was not set") - -if efuses["BLOCK_USR_DATA"].get_meaning() != "00 00 00 00 00 00 00 00 25 41 0c 04 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00": - raise esptool.FatalError("BLOCK_USR_DATA was not set correctly") - - -if efuses["BLOCK_SYS_DATA2"].is_readable() or efuses["BLOCK_SYS_DATA2"].is_writeable(): - raise esptool.FatalError("BLOCK_SYS_DATA2 should be read and write protected") - - -if efuses["BLOCK_KEY5"].get_meaning() != "a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf": - raise esptool.FatalError("BLOCK_KEY5 was not set correctly") - - -if efuses["BLOCK_KEY0"].get_meaning() != "bf be bd bc bb ba b9 b8 b7 b6 b5 b4 b3 b2 b1 b0 af ae ad ac ab aa a9 a8 a7 a6 a5 a4 a3 a2 a1 a0": - raise esptool.FatalError("BLOCK_KEY0 was not set correctly") - -if not efuses["BLOCK_KEY0"].is_readable() or efuses["BLOCK_KEY0"].is_writeable(): - raise esptool.FatalError("BLOCK_KEY0 should be readable and not writable") - -if efuses["KEY_PURPOSE_0"].get_meaning() != "XTS_AES_128_KEY": - raise esptool.FatalError("KEY_PURPOSE_0 was not set XTS_AES_128_KEY") - -if efuses["KEY_PURPOSE_0"].is_writeable(): - raise esptool.FatalError("KEY_PURPOSE_0 should be write-protected") - - -if efuses["BLOCK_KEY1"].get_meaning() != "cb 27 91 a3 71 b0 c0 32 2b f7 37 04 78 ba 09 62 22 4c ab 1c f2 28 78 79 e4 29 67 3e 7d a8 44 63": - raise esptool.FatalError("BLOCK_KEY1 was not set correctly") - -if efuses["KEY_PURPOSE_1"].get_meaning() != "SECURE_BOOT_DIGEST0": - raise esptool.FatalError("KEY_PURPOSE_1 was not set SECURE_BOOT_DIGEST0") - -if efuses["KEY_PURPOSE_1"].is_writeable(): - raise esptool.FatalError("KEY_PURPOSE_1 should be write-protected") - -if not efuses["BLOCK_KEY1"].is_readable() or efuses["BLOCK_KEY1"].is_writeable(): - raise esptool.FatalError("BLOCK_KEY1 should be readable and not writable") - - -espefuse(esp, efuses, args, 'burn_key BLOCK_KEY0 ../../images/efuse/256bit XTS_AES_128_KEY') -efuses.burn_all() -if efuses["BLOCK_KEY0"].is_readable() or efuses["BLOCK_KEY0"].is_writeable(): - raise esptool.FatalError("BLOCK_KEY0 should be not readable and not writeable") diff --git a/tools/esptool_py/test/efuse_scripts/esp32xx/execute_efuse_script2.py b/tools/esptool_py/test/efuse_scripts/esp32xx/execute_efuse_script2.py deleted file mode 100644 index af01379eb5..0000000000 --- a/tools/esptool_py/test/efuse_scripts/esp32xx/execute_efuse_script2.py +++ /dev/null @@ -1,30 +0,0 @@ -# flake8: noqa -# fmt: off -espefuse(esp, efuses, args, 'burn_efuse DIS_FORCE_DOWNLOAD 1 DIS_DOWNLOAD_MODE 1') -if efuses["DIS_FORCE_DOWNLOAD"].get() != 0: - raise esptool.FatalError("Burn should be at the end") - -espefuse(esp, efuses, args, 'burn_bit BLOCK_USR_DATA 64 66 69 72 78 82 83 90') -if efuses["BLOCK_USR_DATA"].get_meaning() != "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00": - raise esptool.FatalError("Burn should be at the end") - -espefuse(esp, efuses, args, 'read_protect_efuse BLOCK_SYS_DATA2') -espefuse(esp, efuses, args, 'write_protect_efuse BLOCK_SYS_DATA2') -if not efuses["BLOCK_SYS_DATA2"].is_readable() or not efuses["BLOCK_SYS_DATA2"].is_writeable(): - raise esptool.FatalError("Burn should be at the end") - -espefuse(esp, efuses, args, 'burn_block_data BLOCK_KEY5 ../../images/efuse/256bit') -if efuses["BLOCK_KEY5"].get_meaning() != "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00": - raise esptool.FatalError("Burn should be at the end") - -espefuse(esp, efuses, args, 'burn_key BLOCK_KEY0 ../../images/efuse/256bit XTS_AES_128_KEY --no-read-protect') -if efuses["BLOCK_KEY0"].get_meaning() != "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00": - raise esptool.FatalError("Burn should be at the end") -if not efuses["BLOCK_KEY0"].is_readable() or not efuses["BLOCK_KEY0"].is_writeable(): - raise esptool.FatalError("Burn should be at the end") - -espefuse(esp, efuses, args, 'burn_key_digest BLOCK_KEY1 ../../secure_images/rsa_secure_boot_signing_key.pem SECURE_BOOT_DIGEST0') -if efuses["BLOCK_KEY1"].get_meaning() != "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00": - raise esptool.FatalError("Burn should be at the end") -if not efuses["BLOCK_KEY1"].is_readable() or not efuses["BLOCK_KEY1"].is_writeable(): - raise esptool.FatalError("Burn should be at the end") diff --git a/tools/esptool_py/test/elf2image/esp32-app-cust-ver-info.elf b/tools/esptool_py/test/elf2image/esp32-app-cust-ver-info.elf deleted file mode 100755 index 389dbbe99839d1198a41e6080c8eed87075b8e1a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2911132 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

RbV-vg71xC;S10w~~jli`s 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Ǝ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%0Dn;W~xnotSCPd*BFdt{C@~R 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®{LxWegZk0HBQgGU&KOElS_%Rp{MI@6}C)-(YZ#u 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

  • M!TC`wwdjY3dW*l54-G}7l9T8i-3CD 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�r*^4>?xls0H2F#Ry8jGpNq)yxdQOH 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%0D~Q?c{5aXVW7db)x0}CMHdDc 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%0DUzJ7WS1+$ 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%0D=ZmDJs!{AuwY5R)xiSg%7W;`lia_M*CY1c1)! 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%0Do+BB-r?-trM%cpF7~E%|ElVW8EG`Q_o-hg>%qOh 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%0DGwXuGM%8C_67O%E+ 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
    f`Pcl9nt?VB)N&F*I<}OfND~KFn`qf|3H$ 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⪻2m+ie7+szP>O6+gPa+BczY#1ckSXlY_t*AZ?sLvCkEQd@&L4Po(6Mz z4Yf~;DJDr{@MC6UW{Kh?Z{dcS+2SI7X2OYt?)M0&M9*JkT_!p+(Qciqm2OgtYOPPL z!8l^P@Ykp2B(*wrOh=ZE*=%2?9>gfN8zs)*ckixX|uOuh=vtV%2QBjQ|E|FmRLyAr|$ z8Lz<6xa`Jx(FF~zK?uyVU38a!^o4GYbGt;;KEjDa3r>UnS1E6Ct^Xa7@|pk4$&_qX ze&qEG#y?hrB{grs24q1LL?+(1bh}iEo^<<(XRJR_?R+KN6PCKCQ;^o2S5N_QY|CUd zWaJwcwh5qR9WFJ5X_YncZ+wC-(?3})YP1qWUS+WZ zR`|++I(9(TM64dZ{AWy-H*(+;RcITr1`Z+$5bboYk$div>*xBk+Mt%&!DGuTsO17$ zu;1Y&hi*MTg3E$_Fm+6Yamd*FP*!8)`BAJUjhu$R@;l8;dHEF{(QS|Ns^X^uDW-Lq zy6yVROjr=|t5BS_G19my0^02_;Cuxdwm?l2N(!_+4*==}^wyboJv(gbi1yyzFi3?d z!d9lxICPI@D9WaoI>&0Xx3W!{a$zgd{68#zfR1RBhweBYxo&@?Wk>ETIujK&1~}(p z1CZrWm*266+d_mNLn7FXO;$e#Th6Cd`?Z{?)dukDSIEWH1v0IGQ2LeN9GjJ;tnIrs zA!8Jr-DU-$cW#d>m?q2+Sxvm`G1gDNUKYXIuB{op`utGt$>yghWrRJc8Ow48C~AIi zhM{FLAsvy9J2c{GjgSG@)@bKs!jIF<>P*&j5d#Ze*=r`fFk>Y}{=DIXcRCm8o4$!= z0RD?xDr^1~%}XHmUCi>l2qBkPxRSKDvpwM`WgkyOd7^n&4*i_Q)>wtN@uszN#c>)* zqxNYyA*L7!<|;+}nWy}P_%ksZyZ8A-0~ot=9Nn$=Xu4%cX?e!I3EkClQ$Jd5+9uaz zQ8^k3ex{=5sB8sXg=gvK>US@#8zt!sKCoSd8hHz*ysu6Bg<&j&Hsc~zv$Ae-@loDt~1W+j~fZg*$%Lls%la-)Av!Ur%%)LqXDOh0u zd_dGfnn@?Jsi0UQ>U1Q=z`};j!qgTFubocX$08NJ!H1Yf>&J{BIHYRU+CoB?hKe0n zRdo*NPc{yu1KLygm%7sP^VsuQhP35zRFfWVi&_kr<1%KZNU^{!@1*{lz8uHl_L$F6 zC++`Uu4x|Wxa$iTur?{FbyE9%%v;m&o2F#aFQf&bURcbM#pDy>{K80owR&M$Np;SO z$C*3?OgxN=Q5kN>>@Ny8z$i5iwXtjPIW}x5q@Q+tzmIHogbzFOJ!P|*S!K1=^((py zneZZ~yJ1blKpi`OgWW2~{F*+I<_izIG?Bxn*c7O->F@dI2j>P^P+28{%UQ2 zdFvKf{fNHz9Kp|N0z6V=1UzGNA$G&CD|!5 zIdlUcK&S(eyG=%-PYd_eXYJm^7TL+eX$Eb%R?f)<@pS(N5gP(?4}IOTfGj!4ij#6+ zv9@;p(kUhLyMM;q;9AdMf;Q7zJk) zRaKq8w5K-ctFe_K%oLDkr*8`iIp3g?1jbiKVCVK%lir^&;8}1ASDHc(fK{P5LwsjvU2+W^#=(qB1AtV@MP%EL0p zR=NuN;K{q(;+CWQgkol4Y3paY>AV)-Y*6zlO(ud9uf3AfIqA}yiC;_ncI)f$;`?&HYogZ69_CTc``r`|4$C^rSHdh=een4y=fH*Vbcd?V!(`Iy`gdED6$cmdtV*oafX!TZmRxZv ztbu7Ckx{uyu>K#IJ9E&Q#z0QvR0r?rZt5vW;s(XQ?Orm}2QylO`

      @y(XB7Fyz3l(S#+h=1HiWv3Y+YaB}1GmL( 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

      fqIn?(S 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

      2SL2}+~b58I07BOv- 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 Nu&g`X&{xx7`ai#D^x^;j literal 0 HcmV?d00001 diff --git a/tools/esptool_py/test/images/efuse/256bit_3 b/tools/esptool_py/test/images/efuse/256bit_3 new file mode 100644 index 0000000000..a44d599808 --- /dev/null +++ b/tools/esptool_py/test/images/efuse/256bit_3 @@ -0,0 +1 @@ +w \ No newline at end of file diff --git a/tools/esptool_py/test/images/ram_helloworld/source/Makefile b/tools/esptool_py/test/images/ram_helloworld/source/Makefile index 0132b9ebee..1378440f2c 100644 --- a/tools/esptool_py/test/images/ram_helloworld/source/Makefile +++ b/tools/esptool_py/test/images/ram_helloworld/source/Makefile @@ -21,7 +21,6 @@ BUILD_DIR = build APP_ELF_8266 = $(BUILD_DIR)/$(APP)-esp8266.elf APP_ELF_32 = $(BUILD_DIR)/$(APP)-esp32.elf APP_ELF_32S2 = $(BUILD_DIR)/$(APP)-esp32s2.elf -APP_ELF_32S3_BETA_2 = $(BUILD_DIR)/$(APP)-esp32s3beta2.elf APP_ELF_32S3 = $(BUILD_DIR)/$(APP)-esp32s3.elf APP_ELF_32C3 = $(BUILD_DIR)/$(APP)-esp32c3.elf APP_ELF_32C2 = $(BUILD_DIR)/$(APP)-esp32c2.elf @@ -61,10 +60,6 @@ $(APP_ELF_32S2): $(SRCS) $(BUILD_DIR) ld/app_32s2.ld @echo " CC(32S2) $^ -> $@" $(Q) $(CROSS_32S2)gcc $(CFLAGS) -DESP32S2=1 -Tapp_32s2.ld -Wl,-Map=$(@:.elf=.map) -o $@ $(filter %.c, $^) $(LDLIBS) -$(APP_ELF_32S3_BETA_2): $(SRCS) $(BUILD_DIR) ld/app_32s3_beta_2.ld - @echo " CC(32S3) $^ -> $@" - $(Q) $(CROSS_32S3)gcc $(CFLAGS) -DESP32S3=1 -Tapp_32s3.ld -Wl,-Map=$(@:.elf=.map) -o $@ $(filter %.c, $^) $(LDLIBS) - $(APP_ELF_32S3): $(SRCS) $(BUILD_DIR) ld/app_32s3.ld @echo " CC(32S3) $^ -> $@" $(Q) $(CROSS_32S3)gcc $(CFLAGS) -DESP32S3=1 -Tapp_32s3.ld -Wl,-Map=$(@:.elf=.map) -o $@ $(filter %.c, $^) $(LDLIBS) diff --git a/tools/esptool_py/test/secure_images/bootloader_signed_v2.bin b/tools/esptool_py/test/secure_images/bootloader_signed_v2_rsa.bin similarity index 100% rename from tools/esptool_py/test/secure_images/bootloader_signed_v2.bin rename to tools/esptool_py/test/secure_images/bootloader_signed_v2_rsa.bin diff --git a/tools/esptool_py/test/secure_images/ecdsa_secure_boot_signing_key.pem b/tools/esptool_py/test/secure_images/ecdsa256_secure_boot_signing_key.pem similarity index 100% rename from tools/esptool_py/test/secure_images/ecdsa_secure_boot_signing_key.pem rename to tools/esptool_py/test/secure_images/ecdsa256_secure_boot_signing_key.pem diff --git a/tools/esptool_py/test/secure_images/ecdsa_secure_boot_signing_key2.pem b/tools/esptool_py/test/secure_images/ecdsa256_secure_boot_signing_key2.pem similarity index 100% rename from tools/esptool_py/test/secure_images/ecdsa_secure_boot_signing_key2.pem rename to tools/esptool_py/test/secure_images/ecdsa256_secure_boot_signing_key2.pem diff --git a/tools/esptool_py/test/secure_images/ecdsa_secure_boot_signing_key_pkcs8.pem b/tools/esptool_py/test/secure_images/ecdsa256_secure_boot_signing_key_pkcs8.pem similarity index 100% rename from tools/esptool_py/test/secure_images/ecdsa_secure_boot_signing_key_pkcs8.pem rename to tools/esptool_py/test/secure_images/ecdsa256_secure_boot_signing_key_pkcs8.pem diff --git a/tools/esptool_py/test/secure_images/ecdsa_secure_boot_signing_pubkey.pem b/tools/esptool_py/test/secure_images/ecdsa256_secure_boot_signing_pubkey.pem similarity index 100% rename from tools/esptool_py/test/secure_images/ecdsa_secure_boot_signing_pubkey.pem rename to tools/esptool_py/test/secure_images/ecdsa256_secure_boot_signing_pubkey.pem diff --git a/tools/esptool_py/test/secure_images/ecdsa_secure_boot_signing_pubkey2.pem b/tools/esptool_py/test/secure_images/ecdsa256_secure_boot_signing_pubkey2.pem similarity index 100% rename from tools/esptool_py/test/secure_images/ecdsa_secure_boot_signing_pubkey2.pem rename to tools/esptool_py/test/secure_images/ecdsa256_secure_boot_signing_pubkey2.pem diff --git a/tools/esptool_py/test/secure_images/ecdsa256_secure_boot_signing_pubkey_raw.bin b/tools/esptool_py/test/secure_images/ecdsa256_secure_boot_signing_pubkey_raw.bin new file mode 100644 index 0000000000..f390d03356 --- /dev/null +++ b/tools/esptool_py/test/secure_images/ecdsa256_secure_boot_signing_pubkey_raw.bin @@ -0,0 +1 @@ +4?>sE!bZyP4]ۧ7pmV8M' \ No newline at end of file diff --git a/tools/esptool_py/test/test_espefuse.py b/tools/esptool_py/test/test_espefuse.py index 2c7b626c4c..5b5178b4e1 100755 --- a/tools/esptool_py/test/test_espefuse.py +++ b/tools/esptool_py/test/test_espefuse.py @@ -1,8 +1,8 @@ -# HOST_TEST for espefuse.py using the pytest framework +# HOST_TEST for espefuse using the pytest framework # -# Supports esp32, esp32s2, esp32s3beta2, esp32s3, -# esp32c3, esp32h2beta1, esp32c2, esp32c6, esp32p4, -# esp32c61, esp32c5, esp32c5beta3. +# Supports esp32, esp32s2, esp32s3, esp32c3, +# esp32c2, esp32c6, esp32p4, esp32c61, +# esp32c5, # # How to use: # @@ -17,7 +17,7 @@ # - `pytest test_espefuse.py \ # --chip esp32 --port /dev/ttyUSB0 --reset-port /dev/ttyUSB1` # -# where - --port - a port for espefuse.py operation +# where - --port - a port for espefuse operation # - --reset-port - a port to clear efuses (connect RTS or DTR ->- J14 pin 39) # # Note: For FPGA with ESP32 image, you need to set an env variable ESPTOOL_ENV_FPGA to 1 @@ -39,7 +39,6 @@ TEST_DIR = os.path.abspath(os.path.dirname(__file__)) IMAGES_DIR = os.path.join(TEST_DIR, "images", "efuse") S_IMAGES_DIR = os.path.join(TEST_DIR, "secure_images") -EFUSE_S_DIR = os.path.join(TEST_DIR, "efuse_scripts") import pytest @@ -60,8 +59,13 @@ if arg_chip not in SUPPORTED_CHIPS: pytest.exit(f"{arg_chip} is not a supported target, choose from {SUPPORTED_CHIPS}") -print(f"\nHost tests of espefuse.py for {arg_chip}:") -print("Running espefuse.py tests...") +print(f"\nHost tests of espefuse for {arg_chip}:") +print("Running espefuse tests...") + +# The default value of the program name for argparse has changed in Python 3.14 +# https://docs.python.org/dev/whatsnew/3.14.html#argparse +ESPEFUSE_MODNAME = "python -m espefuse" +EMPTY_BLOCK = " ".join(["00"] * 32) # "00 00 ... 00" @pytest.mark.host_test @@ -76,8 +80,7 @@ def setup_method(self): self._set_target_wafer_version() else: self.base_cmd = ( - f"{sys.executable} -m espefuse --chip {arg_chip} " - f"--port {arg_port} -d" + f"{sys.executable} -m espefuse --chip {arg_chip} --port {arg_port} -d" ) self.reset_efuses() @@ -98,30 +101,25 @@ def reset_efuses(self): reset_port.rts = False def get_esptool(self): - if reset_port is not None: - import esptool - - esp = esptool.cmds.detect_chip(port=arg_port) - del esptool - else: - import espefuse + import espefuse - efuse = espefuse.SUPPORTED_CHIPS[arg_chip].efuse_lib - esp = efuse.EmulateEfuseController(self.efuse_file.name) - del espefuse - del efuse + esp = espefuse.get_esp( + port=arg_port, + virt=reset_port is None, + virt_efuse_file=self.efuse_file.name, + ) return esp def _set_34_coding_scheme(self): - self.espefuse_py("burn_efuse CODING_SCHEME 1") + self.espefuse_py("burn-efuse CODING_SCHEME 1") def _set_none_recovery_coding_scheme(self): - self.espefuse_py("burn_efuse CODING_SCHEME 3") + self.espefuse_py("burn-efuse CODING_SCHEME 3") def _set_target_wafer_version(self): # ESP32 has to be ECO3 (v3.0) for tests if arg_chip == "esp32": - self.espefuse_py("burn_efuse CHIP_VER_REV1 1 CHIP_VER_REV2 1") + self.espefuse_py("burn-efuse CHIP_VER_REV1 1 CHIP_VER_REV2 1") def check_data_block_in_log( self, log, file_path, repeat=1, reverse_order=False, offset=0 @@ -141,21 +139,38 @@ def espefuse_py(self, cmd, do_not_confirm=True, check_msg=None, ret_code=0): full_cmd = " ".join( [self.base_cmd, "--do-not-confirm" if do_not_confirm else "", cmd] ) + print("Running command: ", full_cmd) output = self._run_command(full_cmd, check_msg, ret_code) self._run_command( - " ".join([self.base_cmd, "check_error"]), "No errors detected", 0 + " ".join([self.base_cmd, "check-error"]), "No errors detected", 0 ) print(output) return output def _run_command(self, cmd, check_msg, ret_code): try: + env = os.environ.copy() + # Comprehensive color disabling and terminal size control + env.update( + # NO_COLOR and COLUMNS should be already set from conftest.py; + # We set them here for completeness and to avoid any mismatch. + # The rest is required only for espefuse tests in some edge cases + # (e.g. GH actions, etc.) + { + "NO_COLOR": "1", + "COLUMNS": "120", # Set terminal width for help output + "LINES": "24", # Some terminal may not apply COLUMNS without LINES + "TERM": "dumb", # Force terminal to dumb mode + } + ) p = subprocess.Popen( cmd.split(), shell=False, stdin=subprocess.PIPE, stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, universal_newlines=True, + env=env, ) output, _ = p.communicate() returncode = p.returncode @@ -173,27 +188,34 @@ def _run_command(self, cmd, check_msg, ret_code): class TestReadCommands(EfuseTestCase): def test_help(self): - self.espefuse_not_virt_py("--help", check_msg="usage: __main__.py [-h]") + self.espefuse_not_virt_py( + "--help", + check_msg=f"Usage: {ESPEFUSE_MODNAME} [OPTIONS] " + "COMMAND1 [ARGS]... [COMMAND2 [ARGS]...]...", + ) self.espefuse_not_virt_py(f"--chip {arg_chip} --help") - def test_help2(self): - self.espefuse_not_virt_py("", check_msg="usage: __main__.py [-h]", ret_code=1) - def test_dump(self): self.espefuse_py("dump -h") self.espefuse_py("dump") def test_dump_format_joint(self): tmp_file = tempfile.NamedTemporaryFile(delete=False) - self.espefuse_py(f"dump --format joint --file_name {tmp_file.name}") + self.espefuse_py(f"dump --format joint --file-name {tmp_file.name}") + + def test_dump_format_joint_stdout(self): + self.espefuse_py("dump --format joint") def test_dump_split_default(self): tmp_file = tempfile.NamedTemporaryFile(delete=False) - self.espefuse_py(f"dump --file_name {tmp_file.name}") + self.espefuse_py(f"dump --file-name {tmp_file.name}") + + def test_dump_format_split_stdout(self): + self.espefuse_py("dump --format split") def test_dump_split(self): tmp_file = tempfile.NamedTemporaryFile(delete=False) - self.espefuse_py(f"dump --format split --file_name {tmp_file.name}") + self.espefuse_py(f"dump --format split --file-name {tmp_file.name}") def test_summary(self): self.espefuse_py("summary -h") @@ -207,47 +229,44 @@ def test_summary_filter(self): self.espefuse_py("summary --format value_only MAC") self.espefuse_py( "summary --format value_only MAC WR_DIS", - check_msg="The 'value_only' format can be used exactly for one efuse.", + check_msg="The 'value_only' format can be used exactly for one eFuse.", ret_code=2, ) - @pytest.mark.skipif( - arg_chip == "esp32p4", reason="No Custom MAC Address defined yet" - ) def test_get_custom_mac(self): - self.espefuse_py("get_custom_mac -h") + self.espefuse_py("get-custom-mac -h") if arg_chip == "esp32": right_msg = "Custom MAC Address is not set in the device." else: right_msg = "Custom MAC Address: 00:00:00:00:00:00 (OK)" - self.espefuse_py("get_custom_mac", check_msg=right_msg) + self.espefuse_py("get-custom-mac", check_msg=right_msg) def test_adc_info(self): - self.espefuse_py("adc_info -h") - self.espefuse_py("adc_info") + self.espefuse_py("adc-info -h") + self.espefuse_py("adc-info") def test_adc_info_2(self): if arg_chip == "esp32": - self.espefuse_py("burn_efuse BLK3_PART_RESERVE 1") - elif arg_chip in ["esp32c3", "esp32s3", "esp32s3beta2"]: - self.espefuse_py("burn_efuse BLK_VERSION_MAJOR 1") + self.espefuse_py("burn-efuse BLK3_PART_RESERVE 1") + elif arg_chip in ["esp32c3", "esp32s3"]: + self.espefuse_py("burn-efuse BLK_VERSION_MAJOR 1") elif arg_chip in ["esp32c2", "esp32s2", "esp32c6"]: - self.espefuse_py("burn_efuse BLK_VERSION_MINOR 1") - elif arg_chip in ["esp32h2", "esp32h2beta1"]: - self.espefuse_py("burn_efuse BLK_VERSION_MINOR 2") - self.espefuse_py("adc_info") + self.espefuse_py("burn-efuse BLK_VERSION_MINOR 1") + elif arg_chip in ["esp32h2", "esp32p4"]: + self.espefuse_py("burn-efuse BLK_VERSION_MINOR 2") + self.espefuse_py("adc-info") def test_check_error(self): - self.espefuse_py("check_error -h") - self.espefuse_py("check_error") - self.espefuse_py("check_error --recovery") + self.espefuse_py("check-error -h") + self.espefuse_py("check-error") + self.espefuse_py("check-error --recovery") class TestReadProtectionCommands(EfuseTestCase): def test_read_protect_efuse(self): - self.espefuse_py("read_protect_efuse -h") + self.espefuse_py("read-protect-efuse -h") if arg_chip == "esp32": - cmd = "read_protect_efuse \ + cmd = "read-protect-efuse \ CODING_SCHEME \ MAC_VERSION \ BLOCK1 \ @@ -255,12 +274,12 @@ def test_read_protect_efuse(self): BLOCK3" count_protects = 5 elif arg_chip == "esp32c2": - cmd = "read_protect_efuse \ + cmd = "read-protect-efuse \ BLOCK_KEY0_LOW_128" count_protects = 1 else: self.espefuse_py( - "burn_efuse \ + "burn-efuse \ KEY_PURPOSE_0 HMAC_UP \ KEY_PURPOSE_1 XTS_AES_128_KEY \ KEY_PURPOSE_2 XTS_AES_128_KEY \ @@ -268,7 +287,7 @@ def test_read_protect_efuse(self): KEY_PURPOSE_4 HMAC_DOWN_JTAG \ KEY_PURPOSE_5 HMAC_DOWN_DIGITAL_SIGNATURE" ) - cmd = "read_protect_efuse \ + cmd = "read-protect-efuse \ BLOCK_KEY0 \ BLOCK_KEY1 \ BLOCK_KEY2 \ @@ -280,8 +299,11 @@ def test_read_protect_efuse(self): output = self.espefuse_py(cmd) assert count_protects == output.count("is already read protected") + @pytest.mark.skipif( + arg_chip == "esp32p4", reason="BLOCK_SYS_DATA2 is used by ADC calib" + ) def test_read_protect_efuse2(self): - self.espefuse_py("write_protect_efuse RD_DIS") + self.espefuse_py("write-protect-efuse RD_DIS") if arg_chip == "esp32": efuse_name = "CODING_SCHEME" elif arg_chip == "esp32c2": @@ -289,18 +311,18 @@ def test_read_protect_efuse2(self): else: efuse_name = "BLOCK_SYS_DATA2" self.espefuse_py( - f"read_protect_efuse {efuse_name}", - check_msg="A fatal error occurred: This efuse cannot be read-disabled " - "due the to RD_DIS field is already write-disabled", + f"read-protect-efuse {efuse_name}", + check_msg="A fatal error occurred: This eFuse cannot be read-disabled " + "due to the RD_DIS field being already write-disabled", ret_code=2, ) @pytest.mark.skipif(arg_chip != "esp32", reason="when the purpose of BLOCK2 is set") def test_read_protect_efuse3(self): - self.espefuse_py("burn_efuse ABS_DONE_1 1") - self.espefuse_py(f"burn_key BLOCK2 {IMAGES_DIR}/256bit") + self.espefuse_py("burn-efuse ABS_DONE_1 1") + self.espefuse_py(f"burn-key BLOCK2 {IMAGES_DIR}/256bit") self.espefuse_py( - "read_protect_efuse BLOCK2", + "read-protect-efuse BLOCK2", check_msg="Secure Boot V2 is on (ABS_DONE_1 = True), " "BLOCK2 must be readable, stop this operation!", ret_code=2, @@ -308,15 +330,15 @@ def test_read_protect_efuse3(self): def test_read_protect_efuse4(self): if arg_chip == "esp32": - self.espefuse_py(f"burn_key BLOCK2 {IMAGES_DIR}/256bit") + self.espefuse_py(f"burn-key BLOCK2 {IMAGES_DIR}/256bit") msg = "must be readable, please stop this operation!" - self.espefuse_py("read_protect_efuse BLOCK2", check_msg=msg) + self.espefuse_py("read-protect-efuse BLOCK2", check_msg=msg) elif arg_chip == "esp32c2": self.espefuse_py( - f"burn_key BLOCK_KEY0 {IMAGES_DIR}/128bit_key SECURE_BOOT_DIGEST" + f"burn-key BLOCK_KEY0 {IMAGES_DIR}/128bit_key SECURE_BOOT_DIGEST" ) self.espefuse_py( - "read_protect_efuse BLOCK_KEY0", + "read-protect-efuse BLOCK_KEY0", check_msg="A fatal error occurred: " "BLOCK_KEY0 must be readable, stop this operation!", ret_code=2, @@ -324,11 +346,11 @@ def test_read_protect_efuse4(self): else: key1_purpose = ( "USER" - if arg_chip in ["esp32p4", "esp32c61", "esp32c5", "esp32c5beta3"] + if arg_chip in ["esp32p4", "esp32c61", "esp32c5", "esp32h4"] else "RESERVED" ) self.espefuse_py( - f"burn_key BLOCK_KEY0 {IMAGES_DIR}/256bit USER \ + f"burn-key BLOCK_KEY0 {IMAGES_DIR}/256bit USER \ BLOCK_KEY1 {IMAGES_DIR}/256bit {key1_purpose} \ BLOCK_KEY2 {IMAGES_DIR}/256bit SECURE_BOOT_DIGEST0 \ BLOCK_KEY3 {IMAGES_DIR}/256bit SECURE_BOOT_DIGEST1 \ @@ -336,45 +358,45 @@ def test_read_protect_efuse4(self): BLOCK_KEY5 {IMAGES_DIR}/256bit HMAC_UP" ) self.espefuse_py( - "read_protect_efuse BLOCK_KEY0", + "read-protect-efuse BLOCK_KEY0", check_msg="A fatal error occurred: " "BLOCK_KEY0 must be readable, stop this operation!", ret_code=2, ) self.espefuse_py( - "read_protect_efuse BLOCK_KEY1", + "read-protect-efuse BLOCK_KEY1", check_msg="A fatal error occurred: " "BLOCK_KEY1 must be readable, stop this operation!", ret_code=2, ) self.espefuse_py( - "read_protect_efuse BLOCK_KEY2", + "read-protect-efuse BLOCK_KEY2", check_msg="A fatal error occurred: " "BLOCK_KEY2 must be readable, stop this operation!", ret_code=2, ) self.espefuse_py( - "read_protect_efuse BLOCK_KEY3", + "read-protect-efuse BLOCK_KEY3", check_msg="A fatal error occurred: " "BLOCK_KEY3 must be readable, stop this operation!", ret_code=2, ) self.espefuse_py( - "read_protect_efuse BLOCK_KEY4", + "read-protect-efuse BLOCK_KEY4", check_msg="A fatal error occurred: " "BLOCK_KEY4 must be readable, stop this operation!", ret_code=2, ) - self.espefuse_py("read_protect_efuse BLOCK_KEY5") + self.espefuse_py("read-protect-efuse BLOCK_KEY5") @pytest.mark.skipif( arg_chip != "esp32", - reason="system parameters efuse read-protection is supported only by esp32, " + reason="system parameters eFuse read-protection is supported only by esp32, " "other chips protect whole blocks", ) def test_burn_and_read_protect_efuse(self): self.espefuse_py( - "burn_efuse FLASH_CRYPT_CONFIG 15 RD_DIS 8", + "burn-efuse FLASH_CRYPT_CONFIG 15 RD_DIS 8", check_msg="Efuse FLASH_CRYPT_CONFIG is read-protected. " "Read back the burn value is not possible.", ) @@ -382,7 +404,7 @@ def test_burn_and_read_protect_efuse(self): class TestWriteProtectionCommands(EfuseTestCase): def test_write_protect_efuse(self): - self.espefuse_py("write_protect_efuse -h") + self.espefuse_py("write-protect-efuse -h") if arg_chip == "esp32": efuse_lists = """WR_DIS RD_DIS CODING_SCHEME XPD_SDIO_FORCE XPD_SDIO_REG XPD_SDIO_TIEH SPI_PAD_CONFIG_CLK @@ -398,7 +420,7 @@ def test_write_protect_efuse(self): SPI_BOOT_CRYPT_CNT""" efuse_lists2 = "RD_DIS KEY_PURPOSE_0 KEY_PURPOSE_2" else: - efuse_lists = """RD_DIS DIS_ICACHE DIS_FORCE_DOWNLOAD + efuse_lists = """RD_DIS DIS_FORCE_DOWNLOAD DIS_DOWNLOAD_MANUAL_ENCRYPT USB_EXCHG_PINS WDT_DELAY_SEL SPI_BOOT_CRYPT_CNT SECURE_BOOT_KEY_REVOKE0 SECURE_BOOT_KEY_REVOKE1 @@ -412,38 +434,37 @@ def test_write_protect_efuse(self): BLOCK_KEY2 BLOCK_KEY3 BLOCK_KEY4 BLOCK_KEY5""" if arg_chip not in [ "esp32h2", - "esp32h2beta1", "esp32c6", "esp32c61", "esp32c5", - "esp32c5beta3", + "esp32h21", + "esp32h4", ]: efuse_lists += """ DIS_DOWNLOAD_ICACHE SPI_PAD_CONFIG_CLK SPI_PAD_CONFIG_Q SPI_PAD_CONFIG_D SPI_PAD_CONFIG_CS SPI_PAD_CONFIG_HD SPI_PAD_CONFIG_WP SPI_PAD_CONFIG_DQS SPI_PAD_CONFIG_D4 SPI_PAD_CONFIG_D5 SPI_PAD_CONFIG_D6 SPI_PAD_CONFIG_D7""" - efuse_lists2 = "RD_DIS DIS_ICACHE" - self.espefuse_py(f"write_protect_efuse {efuse_lists}") - output = self.espefuse_py(f"write_protect_efuse {efuse_lists2}") - assert output.count("is already write protected") == 2 + efuse_lists2 = "RD_DIS" + self.espefuse_py(f"write-protect-efuse {efuse_lists}") + output = self.espefuse_py(f"write-protect-efuse {efuse_lists2}") + assert output.count("is already write protected") >= 1 def test_write_protect_efuse2(self): if arg_chip == "esp32": - self.espefuse_py("write_protect_efuse WR_DIS") + self.espefuse_py("write-protect-efuse WR_DIS") self.espefuse_py( - "write_protect_efuse CODING_SCHEME", - check_msg="A fatal error occurred: This efuse cannot be write-disabled " - "due to the WR_DIS field is already write-disabled", + "write-protect-efuse CODING_SCHEME", + check_msg="A fatal error occurred: This eFuse cannot be write-disabled " + "due to the WR_DIS field being already write-disabled", ret_code=2, ) -@pytest.mark.skipif(arg_chip == "esp32p4", reason="No Custom MAC Address defined yet") class TestBurnCustomMacCommands(EfuseTestCase): def test_burn_custom_mac(self): - self.espefuse_py("burn_custom_mac -h") - cmd = "burn_custom_mac AA:CD:EF:11:22:33" + self.espefuse_py("burn-custom-mac -h") + cmd = "burn-custom-mac AA:CD:EF:11:22:33" mac = "aa:cd:ef:11:22:33" if arg_chip == "esp32": self.espefuse_py( @@ -454,7 +475,7 @@ def test_burn_custom_mac(self): def test_burn_custom_mac2(self): self.espefuse_py( - "burn_custom_mac AA:CD:EF:11:22:33:44", + "burn-custom-mac AA:CD:EF:11:22:33:44", check_msg="A fatal error occurred: MAC Address needs to be a 6-byte " "hexadecimal format separated by colons (:)!", ret_code=2, @@ -462,7 +483,7 @@ def test_burn_custom_mac2(self): def test_burn_custom_mac3(self): self.espefuse_py( - "burn_custom_mac AB:CD:EF:11:22:33", + "burn-custom-mac AB:CD:EF:11:22:33", check_msg="A fatal error occurred: Custom MAC must be a unicast MAC!", ret_code=2, ) @@ -472,18 +493,18 @@ def test_burn_custom_mac3(self): ) def test_burn_custom_mac_with_34_coding_scheme(self): self._set_34_coding_scheme() - self.espefuse_py("burn_custom_mac -h") + self.espefuse_py("burn-custom-mac -h") self.espefuse_py( - "burn_custom_mac AA:CD:EF:01:02:03", + "burn-custom-mac AA:CD:EF:01:02:03", check_msg="Custom MAC Address version 1: aa:cd:ef:01:02:03 (CRC 0x56 OK)", ) self.espefuse_py( - "get_custom_mac", + "get-custom-mac", check_msg="Custom MAC Address version 1: aa:cd:ef:01:02:03 (CRC 0x56 OK)", ) self.espefuse_py( - "burn_custom_mac FE:22:33:44:55:66", + "burn-custom-mac FE:22:33:44:55:66", check_msg="New value contains some bits that cannot be cleared " "(value will be 0x675745ffeffe)", ret_code=2, @@ -501,65 +522,65 @@ def test_burn_custom_mac_with_34_coding_scheme(self): ) class TestSetFlashVoltageCommands(EfuseTestCase): def test_set_flash_voltage_1_8v(self): - self.espefuse_py("set_flash_voltage -h") + self.espefuse_py("set-flash-voltage -h") vdd = "VDD_SDIO" if arg_chip == "esp32" else "VDD_SPI" self.espefuse_py( - "set_flash_voltage 1.8V", + "set-flash-voltage 1.8V", check_msg=f"Set internal flash voltage regulator ({vdd}) to 1.8V.", ) if arg_chip == "esp32": error_msg = "A fatal error occurred: " - "Can't set flash regulator to OFF as XPD_SDIO_REG efuse is already burned" + "Can't set flash regulator to OFF as XPD_SDIO_REG eFuse is already burned" else: error_msg = "A fatal error occurred: " - "Can't set flash regulator to OFF as VDD_SPI_XPD efuse is already burned" + "Can't set flash regulator to OFF as VDD_SPI_XPD eFuse is already burned" self.espefuse_py( - "set_flash_voltage 3.3V", + "set-flash-voltage 3.3V", check_msg=f"Enable internal flash voltage regulator ({vdd}) to 3.3V.", ) - self.espefuse_py("set_flash_voltage OFF", check_msg=error_msg, ret_code=2) + self.espefuse_py("set-flash-voltage OFF", check_msg=error_msg, ret_code=2) def test_set_flash_voltage_3_3v(self): vdd = "VDD_SDIO" if arg_chip == "esp32" else "VDD_SPI" self.espefuse_py( - "set_flash_voltage 3.3V", + "set-flash-voltage 3.3V", check_msg=f"Enable internal flash voltage regulator ({vdd}) to 3.3V.", ) if arg_chip == "esp32": error_msg = "A fatal error occurred: " - "Can't set regulator to 1.8V is XPD_SDIO_TIEH efuse is already burned" + "Can't set regulator to 1.8V is XPD_SDIO_TIEH eFuse is already burned" else: error_msg = "A fatal error occurred: " - "Can't set regulator to 1.8V is VDD_SPI_TIEH efuse is already burned" - self.espefuse_py("set_flash_voltage 1.8V", check_msg=error_msg, ret_code=2) + "Can't set regulator to 1.8V is VDD_SPI_TIEH eFuse is already burned" + self.espefuse_py("set-flash-voltage 1.8V", check_msg=error_msg, ret_code=2) if arg_chip == "esp32": error_msg = "A fatal error occurred: " - "Can't set flash regulator to OFF as XPD_SDIO_REG efuse is already burned" + "Can't set flash regulator to OFF as XPD_SDIO_REG eFuse is already burned" else: error_msg = "A fatal error occurred: " - "Can't set flash regulator to OFF as VDD_SPI_XPD efuse is already burned" - self.espefuse_py("set_flash_voltage OFF", check_msg=error_msg, ret_code=2) + "Can't set flash regulator to OFF as VDD_SPI_XPD eFuse is already burned" + self.espefuse_py("set-flash-voltage OFF", check_msg=error_msg, ret_code=2) def test_set_flash_voltage_off(self): vdd = "VDD_SDIO" if arg_chip == "esp32" else "VDD_SPI" self.espefuse_py( - "set_flash_voltage OFF", + "set-flash-voltage OFF", check_msg=f"Disable internal flash voltage regulator ({vdd})", ) self.espefuse_py( - "set_flash_voltage 3.3V", + "set-flash-voltage 3.3V", check_msg=f"Enable internal flash voltage regulator ({vdd}) to 3.3V.", ) def test_set_flash_voltage_off2(self): vdd = "VDD_SDIO" if arg_chip == "esp32" else "VDD_SPI" self.espefuse_py( - "set_flash_voltage OFF", + "set-flash-voltage OFF", check_msg=f"Disable internal flash voltage regulator ({vdd})", ) self.espefuse_py( - "set_flash_voltage 1.8V", + "set-flash-voltage 1.8V", check_msg=f"Set internal flash voltage regulator ({vdd}) to 1.8V.", ) @@ -567,54 +588,54 @@ def test_set_flash_voltage_off2(self): @pytest.mark.skipif(arg_chip != "esp32c3", reason="Not necessary for all chips") class TestValueArgForBurnEfuseCommands(EfuseTestCase): def test_efuse_is_bool_given_none(self): - self.espefuse_py("burn_efuse SECURE_BOOT_KEY_REVOKE0") + self.espefuse_py("burn-efuse SECURE_BOOT_KEY_REVOKE0") def test_efuse_is_bool_given_0(self): self.espefuse_py( - "burn_efuse SECURE_BOOT_KEY_REVOKE0 0", + "burn-efuse SECURE_BOOT_KEY_REVOKE0 0", check_msg="A fatal error occurred: " - "New value is not accepted for efuse 'SECURE_BOOT_KEY_REVOKE0' " + "New value is not accepted for eFuse 'SECURE_BOOT_KEY_REVOKE0' " "(will always burn 0->1), given value=0", ret_code=2, ) def test_efuse_is_bool_given_2(self): self.espefuse_py( - "burn_efuse SECURE_BOOT_KEY_REVOKE0 2", + "burn-efuse SECURE_BOOT_KEY_REVOKE0 2", check_msg="A fatal error occurred: " - "New value is not accepted for efuse 'SECURE_BOOT_KEY_REVOKE0' " + "New value is not accepted for eFuse 'SECURE_BOOT_KEY_REVOKE0' " "(will always burn 0->1), given value=2", ret_code=2, ) def test_efuse_is_bytes_ok(self): self.espefuse_py( - "burn_efuse OPTIONAL_UNIQUE_ID 0x12345678123456781234567812345678" + "burn-efuse OPTIONAL_UNIQUE_ID 0x12345678123456781234567812345678" ) def test_efuse_is_bytes_given_short_val(self): self.espefuse_py( - "burn_efuse OPTIONAL_UNIQUE_ID 0x1234567812345678", + "burn-efuse OPTIONAL_UNIQUE_ID 0x1234567812345678", check_msg="A fatal error occurred: " - "The length of efuse 'OPTIONAL_UNIQUE_ID' (128 bits) " + "The length of eFuse 'OPTIONAL_UNIQUE_ID' (128 bits) " "(given len of the new value= 64 bits)", ret_code=2, ) def test_efuse_is_bytes_given_none(self): self.espefuse_py( - "burn_efuse OPTIONAL_UNIQUE_ID", + "burn-efuse OPTIONAL_UNIQUE_ID", check_msg="A fatal error occurred: " - "New value required for efuse 'OPTIONAL_UNIQUE_ID' (given None)", + "New value required for eFuse 'OPTIONAL_UNIQUE_ID' (given None)", ret_code=2, ) def test_efuse_is_int_ok(self): - self.espefuse_py("burn_efuse SPI_PAD_CONFIG_D 7") + self.espefuse_py("burn-efuse SPI_PAD_CONFIG_D 7") def test_efuse_is_int_given_out_of_range_val(self): self.espefuse_py( - "burn_efuse SPI_PAD_CONFIG_D 200", + "burn-efuse SPI_PAD_CONFIG_D 200", check_msg="A fatal error occurred: " "200 is too large an unsigned integer for a bitstring " "of length 6. The allowed range is [0, 63].", @@ -623,15 +644,15 @@ def test_efuse_is_int_given_out_of_range_val(self): def test_efuse_is_int_given_none(self): self.espefuse_py( - "burn_efuse SPI_PAD_CONFIG_D", + "burn-efuse SPI_PAD_CONFIG_D", check_msg="A fatal error occurred: " - "New value required for efuse 'SPI_PAD_CONFIG_D' (given None)", + "New value required for eFuse 'SPI_PAD_CONFIG_D' (given None)", ret_code=2, ) def test_efuse_is_int_given_0(self): self.espefuse_py( - "burn_efuse SPI_PAD_CONFIG_D 0", + "burn-efuse SPI_PAD_CONFIG_D 0", check_msg="A fatal error occurred: " "New value should not be 0 for 'SPI_PAD_CONFIG_D' " "(given value= 0)", @@ -640,7 +661,7 @@ def test_efuse_is_int_given_0(self): def test_efuse_is_bitcount_given_out_of_range_val(self): self.espefuse_py( - "burn_efuse SPI_BOOT_CRYPT_CNT 9", + "burn-efuse SPI_BOOT_CRYPT_CNT 9", check_msg="A fatal error occurred: " "9 is too large an unsigned integer for a bitstring " "of length 3. The allowed range is [0, 7].", @@ -648,11 +669,11 @@ def test_efuse_is_bitcount_given_out_of_range_val(self): ) def test_efuse_is_bitcount_given_increase_over_max(self): - self.espefuse_py("burn_efuse SPI_BOOT_CRYPT_CNT") - self.espefuse_py("burn_efuse SPI_BOOT_CRYPT_CNT") - self.espefuse_py("burn_efuse SPI_BOOT_CRYPT_CNT") + self.espefuse_py("burn-efuse SPI_BOOT_CRYPT_CNT") + self.espefuse_py("burn-efuse SPI_BOOT_CRYPT_CNT") + self.espefuse_py("burn-efuse SPI_BOOT_CRYPT_CNT") self.espefuse_py( - "burn_efuse SPI_BOOT_CRYPT_CNT", + "burn-efuse SPI_BOOT_CRYPT_CNT", check_msg="A fatal error occurred: " "15 is too large an unsigned integer for a bitstring " "of length 3. The allowed range is [0, 7].", @@ -667,51 +688,48 @@ class TestBurnEfuseCommands(EfuseTestCase): ) def test_set_spi_flash_pin_efuses(self): self.espefuse_py( - "burn_efuse SPI_PAD_CONFIG_HD 30", + "burn-efuse SPI_PAD_CONFIG_HD 30", check_msg="A fatal error occurred: " "IO pins 30 & 31 cannot be set for SPI flash. 0-29, 32 & 33 only.", ret_code=2, ) self.espefuse_py( - "burn_efuse SPI_PAD_CONFIG_Q 0x23", + "burn-efuse SPI_PAD_CONFIG_Q 0x23", check_msg="A fatal error occurred: " "IO pin 35 cannot be set for SPI flash. 0-29, 32 & 33 only.", ret_code=2, ) - output = self.espefuse_py("burn_efuse SPI_PAD_CONFIG_CS0 33") + output = self.espefuse_py("burn-efuse SPI_PAD_CONFIG_CS0 33") assert "(Override SD_CMD pad (GPIO11/SPICS0)) 0b00000 -> 0b11111" in output assert "BURN BLOCK0 - OK (all write block bits are set)" in output - @pytest.mark.skipif( - arg_chip == "esp32p4", reason="No Custom MAC Address defined yet" - ) def test_burn_mac_custom_efuse(self): crc_msg = "(OK)" - self.espefuse_py("burn_efuse -h") + self.espefuse_py("burn-efuse -h") if arg_chip == "esp32": self.espefuse_py( - "burn_efuse MAC AA:CD:EF:01:02:03", + "burn-efuse MAC AA:CD:EF:01:02:03", check_msg="Writing Factory MAC address is not supported", ret_code=2, ) - self.espefuse_py("burn_efuse MAC_VERSION 1") + self.espefuse_py("burn-efuse MAC_VERSION 1") crc_msg = "(CRC 0x56 OK)" if arg_chip == "esp32c2": - self.espefuse_py("burn_efuse CUSTOM_MAC_USED 1") - self.espefuse_py("burn_efuse -h") + self.espefuse_py("burn-efuse CUSTOM_MAC_USED 1") + self.espefuse_py("burn-efuse -h") self.espefuse_py( - "burn_efuse CUSTOM_MAC AB:CD:EF:01:02:03", + "burn-efuse CUSTOM_MAC AB:CD:EF:01:02:03", check_msg="A fatal error occurred: Custom MAC must be a unicast MAC!", ret_code=2, ) - self.espefuse_py("burn_efuse CUSTOM_MAC AA:CD:EF:01:02:03") - self.espefuse_py("get_custom_mac", check_msg=f"aa:cd:ef:01:02:03 {crc_msg}") + self.espefuse_py("burn-efuse CUSTOM_MAC AA:CD:EF:01:02:03") + self.espefuse_py("get-custom-mac", check_msg=f"aa:cd:ef:01:02:03 {crc_msg}") def test_burn_efuse(self): - self.espefuse_py("burn_efuse -h") + self.espefuse_py("burn-efuse -h") if arg_chip == "esp32": self.espefuse_py( - "burn_efuse \ + "burn-efuse \ CHIP_VER_REV2 1 \ DISABLE_DL_ENCRYPT 1 \ CONSOLE_DEBUG_DISABLE 1" @@ -720,7 +738,7 @@ def test_burn_efuse(self): blk2 = "BLOCK2" elif arg_chip == "esp32c2": self.espefuse_py( - "burn_efuse \ + "burn-efuse \ XTS_KEY_LENGTH_256 1 \ UART_PRINT_CONTROL 1 \ FORCE_SEND_RESUME 1" @@ -729,25 +747,25 @@ def test_burn_efuse(self): blk2 = None else: self.espefuse_py( - "burn_efuse \ + "burn-efuse \ SECURE_BOOT_EN 1 \ UART_PRINT_CONTROL 1" ) - if arg_chip not in ["esp32c5", "esp32c5beta3", "esp32c61"]: + if arg_chip not in ["esp32h21", "esp32h4"]: # chips having the OPTIONAL_UNIQUE_ID field self.espefuse_py( - "burn_efuse \ + "burn-efuse \ OPTIONAL_UNIQUE_ID 0x2328ad5ac9145f698f843a26d6eae168", check_msg="-> 0x2328ad5ac9145f698f843a26d6eae168", ) - output = self.espefuse_py("summary -d") + output = self.espefuse_py("-d summary") assert ( "read_regs: d6eae168 8f843a26 c9145f69 2328ad5a " "00000000 00000000 00000000 00000000" ) in output assert "= 68 e1 ea d6 26 3a 84 8f 69 5f 14 c9 5a ad 28 23 R/W" in output self.espefuse_py( - "burn_bit BLOCK_SYS_DATA 1", + "burn-bit BLOCK_SYS_DATA 1", check_msg="Burn into BLOCK_SYS_DATA is forbidden " "(RS coding scheme does not allow this).", ret_code=2, @@ -755,14 +773,14 @@ def test_burn_efuse(self): blk1 = "BLOCK_KEY1" blk2 = "BLOCK_KEY2" output = self.espefuse_py( - f"burn_efuse {blk1}" + f"burn-efuse {blk1}" + " 0x00010203040506070809111111111111111111111111111111110000112233FF" ) assert ( "-> 0x00010203040506070809111111111111111111111111111111110000112233ff" in output ) - output = self.espefuse_py("summary -d") + output = self.espefuse_py("-d summary") assert ( "read_regs: 112233ff 11110000 11111111 11111111 " "11111111 08091111 04050607 00010203" @@ -774,14 +792,14 @@ def test_burn_efuse(self): if blk2 is not None: output = self.espefuse_py( - f"burn_efuse {blk2}" + f"burn-efuse {blk2}" + " 00010203040506070809111111111111111111111111111111110000112233FF" ) assert ( "-> 0xff33221100001111111111111111111111111111111109080706050403020100" in output ) - output = self.espefuse_py("summary -d") + output = self.espefuse_py("-d summary") assert ( "read_regs: 03020100 07060504 11110908 11111111 " "11111111 11111111 00001111 ff332211" @@ -796,10 +814,10 @@ def test_burn_efuse(self): ) def test_burn_efuse_with_34_coding_scheme(self): self._set_34_coding_scheme() - self.espefuse_py("burn_efuse BLK3_PART_RESERVE 1") - self.espefuse_py("burn_efuse ADC1_TP_LOW 50") + self.espefuse_py("burn-efuse BLK3_PART_RESERVE 1") + self.espefuse_py("burn-efuse ADC1_TP_LOW 50") self.espefuse_py( - "burn_efuse ADC1_TP_HIGH 55", + "burn-efuse ADC1_TP_HIGH 55", check_msg="Burn into BLOCK3 is forbidden " "(3/4 coding scheme does not allow this)", ret_code=2, @@ -810,9 +828,9 @@ def test_burn_efuse_with_34_coding_scheme(self): ) def test_burn_efuse_with_34_coding_scheme2(self): self._set_34_coding_scheme() - self.espefuse_py("burn_efuse BLK3_PART_RESERVE 1") + self.espefuse_py("burn-efuse BLK3_PART_RESERVE 1") self.espefuse_py( - "burn_efuse \ + "burn-efuse \ ADC1_TP_LOW 50 \ ADC1_TP_HIGH 55 \ ADC2_TP_LOW 40 \ @@ -821,72 +839,72 @@ def test_burn_efuse_with_34_coding_scheme2(self): @pytest.mark.skipif( arg_chip != "esp32s3", - reason="Currently S3 only has this efuse incompatibility check", + reason="Currently S3 only has this eFuse incompatibility check", ) def test_burn_efuse_incompatibility_check(self): self.espefuse_py( - "burn_efuse DIS_USB_JTAG 1 DIS_USB_SERIAL_JTAG 1", + "burn-efuse DIS_USB_JTAG 1 DIS_USB_SERIAL_JTAG 1", check_msg="Incompatible eFuse settings detected, abort", ret_code=2, ) - self.espefuse_py("burn_efuse DIS_USB_JTAG 1") + self.espefuse_py("burn-efuse DIS_USB_JTAG 1") self.espefuse_py( - "burn_efuse DIS_USB_SERIAL_JTAG 1", + "burn-efuse DIS_USB_SERIAL_JTAG 1", check_msg="Incompatible eFuse settings detected, abort", ret_code=2, ) - self.espefuse_py("burn_efuse DIS_USB_SERIAL_JTAG 1 --force") + self.espefuse_py("burn-efuse DIS_USB_SERIAL_JTAG 1 --force") class TestBurnKeyCommands(EfuseTestCase): @pytest.mark.skipif(arg_chip != "esp32", reason="ESP32-only") def test_burn_key_3_key_blocks(self): - self.espefuse_py("burn_key -h") + self.espefuse_py("burn-key -h") self.espefuse_py( - f"burn_key BLOCK1 {IMAGES_DIR}/192bit", + f"burn-key BLOCK1 {IMAGES_DIR}/192bit", check_msg="A fatal error occurred: Incorrect key file size 24. " "Key file must be 32 bytes (256 bits) of raw binary key data.", ret_code=2, ) self.espefuse_py( - f"burn_key \ + f"burn-key \ BLOCK1 {IMAGES_DIR}/256bit \ BLOCK2 {IMAGES_DIR}/256bit_1 \ BLOCK3 {IMAGES_DIR}/256bit_2 --no-protect-key" ) - output = self.espefuse_py("summary -d") + output = self.espefuse_py("-d summary") self.check_data_block_in_log(output, f"{IMAGES_DIR}/256bit") self.check_data_block_in_log(output, f"{IMAGES_DIR}/256bit_1") self.check_data_block_in_log(output, f"{IMAGES_DIR}/256bit_2") self.espefuse_py( - f"burn_key \ + f"burn-key \ BLOCK1 {IMAGES_DIR}/256bit \ BLOCK2 {IMAGES_DIR}/256bit_1 \ BLOCK3 {IMAGES_DIR}/256bit_2" ) - output = self.espefuse_py("summary -d") + output = self.espefuse_py("-d summary") self.check_data_block_in_log(output, f"{IMAGES_DIR}/256bit") self.check_data_block_in_log(output, f"{IMAGES_DIR}/256bit_1") self.check_data_block_in_log(output, f"{IMAGES_DIR}/256bit_2") @pytest.mark.skipif(arg_chip != "esp32c2", reason="ESP32-C2-only") def test_burn_key_1_key_block(self): - self.espefuse_py("burn_key -h") + self.espefuse_py("burn-key -h") self.espefuse_py( - f"burn_key BLOCK_KEY0 {IMAGES_DIR}/128bit XTS_AES_128_KEY", + f"burn-key BLOCK_KEY0 {IMAGES_DIR}/128bit XTS_AES_128_KEY", check_msg="A fatal error occurred: Incorrect key file size 16. " "Key file must be 32 bytes (256 bits) of raw binary key data.", ret_code=2, ) self.espefuse_py( - f"burn_key BLOCK_KEY0 {IMAGES_DIR}/256bit XTS_AES_128_KEY --no-read-protect" + f"burn-key BLOCK_KEY0 {IMAGES_DIR}/256bit XTS_AES_128_KEY --no-read-protect" ) - output = self.espefuse_py("summary -d") + output = self.espefuse_py("-d summary") self.check_data_block_in_log(output, f"{IMAGES_DIR}/256bit", reverse_order=True) - self.espefuse_py(f"burn_key BLOCK_KEY0 {IMAGES_DIR}/256bit XTS_AES_128_KEY") - output = self.espefuse_py("summary -d") + self.espefuse_py(f"burn-key BLOCK_KEY0 {IMAGES_DIR}/256bit XTS_AES_128_KEY") + output = self.espefuse_py("-d summary") assert ( "[3 ] read_regs: 00000000 00000000 00000000 00000000 " "00000000 00000000 00000000 00000000" @@ -899,31 +917,31 @@ def test_burn_key_1_key_block(self): @pytest.mark.skipif(arg_chip != "esp32c2", reason="ESP32-C2-only") def test_burn_key_one_key_block_with_fe_and_sb_keys(self): - self.espefuse_py("burn_key -h") + self.espefuse_py("burn-key -h") self.espefuse_py( - f"burn_key BLOCK_KEY0 {IMAGES_DIR}/256bit XTS_AES_128_KEY \ + f"burn-key BLOCK_KEY0 {IMAGES_DIR}/256bit XTS_AES_128_KEY \ BLOCK_KEY0 {IMAGES_DIR}/128bit_key SECURE_BOOT_DIGEST", check_msg="A fatal error occurred: These keypurposes are incompatible " "['XTS_AES_128_KEY', 'SECURE_BOOT_DIGEST']", ret_code=2, ) self.espefuse_py( - f"burn_key BLOCK_KEY0 {IMAGES_DIR}/128bit_key " + f"burn-key BLOCK_KEY0 {IMAGES_DIR}/128bit_key " f"XTS_AES_128_KEY_DERIVED_FROM_128_EFUSE_BITS " f"BLOCK_KEY0 {IMAGES_DIR}/128bit_key SECURE_BOOT_DIGEST --no-read-protect" ) - output = self.espefuse_py("summary -d") + output = self.espefuse_py("-d summary") assert ( "[3 ] read_regs: 0c0d0e0f 08090a0b 04050607 00010203 " "03020100 07060504 0b0a0908 0f0e0d0c" ) in output self.espefuse_py( - f"burn_key BLOCK_KEY0 {IMAGES_DIR}/128bit_key " + f"burn-key BLOCK_KEY0 {IMAGES_DIR}/128bit_key " "XTS_AES_128_KEY_DERIVED_FROM_128_EFUSE_BITS " f"BLOCK_KEY0 {IMAGES_DIR}/128bit_key SECURE_BOOT_DIGEST" ) - output = self.espefuse_py("summary -d") + output = self.espefuse_py("-d summary") assert ( "[3 ] read_regs: 00000000 00000000 00000000 00000000 " "03020100 07060504 0b0a0908 0f0e0d0c" @@ -941,20 +959,17 @@ def test_burn_key_one_key_block_with_fe_and_sb_keys(self): not in [ "esp32s2", "esp32s3", - "esp32s3beta1", "esp32c3", - "esp32h2beta1", "esp32c6", "esp32h2", "esp32p4", "esp32c5", - "esp32c5beta3", "esp32c61", ], reason="Only chips with 6 keys", ) def test_burn_key_with_6_keys(self): - cmd = f"burn_key \ + cmd = f"burn-key \ BLOCK_KEY0 {IMAGES_DIR}/256bit XTS_AES_256_KEY_1 \ BLOCK_KEY1 {IMAGES_DIR}/256bit_1 XTS_AES_256_KEY_2 \ BLOCK_KEY2 {IMAGES_DIR}/256bit_2 XTS_AES_128_KEY" @@ -962,14 +977,12 @@ def test_burn_key_with_6_keys(self): "esp32c3", "esp32c6", "esp32h2", - "esp32h2beta1", "esp32c5", - "esp32c5beta3", ]: cmd = cmd.replace("XTS_AES_256_KEY_1", "XTS_AES_128_KEY") cmd = cmd.replace("XTS_AES_256_KEY_2", "XTS_AES_128_KEY") self.espefuse_py(cmd + " --no-read-protect --no-write-protect") - output = self.espefuse_py("summary -d") + output = self.espefuse_py("-d summary") self.check_data_block_in_log(output, f"{IMAGES_DIR}/256bit", reverse_order=True) self.check_data_block_in_log( output, f"{IMAGES_DIR}/256bit_1", reverse_order=True @@ -979,7 +992,7 @@ def test_burn_key_with_6_keys(self): ) self.espefuse_py(cmd) - output = self.espefuse_py("summary -d") + output = self.espefuse_py("-d summary") assert ( "[4 ] read_regs: 00000000 00000000 00000000 00000000 " "00000000 00000000 00000000 00000000" @@ -994,12 +1007,12 @@ def test_burn_key_with_6_keys(self): ) in output self.espefuse_py( - f"burn_key \ + f"burn-key \ BLOCK_KEY3 {IMAGES_DIR}/256bit SECURE_BOOT_DIGEST0 \ BLOCK_KEY4 {IMAGES_DIR}/256bit_1 SECURE_BOOT_DIGEST1 \ BLOCK_KEY5 {IMAGES_DIR}/256bit_2 SECURE_BOOT_DIGEST2" ) - output = self.espefuse_py("summary -d") + output = self.espefuse_py("-d summary") self.check_data_block_in_log(output, f"{IMAGES_DIR}/256bit") self.check_data_block_in_log(output, f"{IMAGES_DIR}/256bit_1") self.check_data_block_in_log(output, f"{IMAGES_DIR}/256bit_2") @@ -1010,29 +1023,29 @@ def test_burn_key_with_6_keys(self): def test_burn_key_with_34_coding_scheme(self): self._set_34_coding_scheme() self.espefuse_py( - f"burn_key BLOCK1 {IMAGES_DIR}/256bit", + f"burn-key BLOCK1 {IMAGES_DIR}/256bit", check_msg="A fatal error occurred: Incorrect key file size 32. " "Key file must be 24 bytes (192 bits) of raw binary key data.", ret_code=2, ) self.espefuse_py( - f"burn_key \ + f"burn-key \ BLOCK1 {IMAGES_DIR}/192bit \ BLOCK2 {IMAGES_DIR}/192bit_1 \ BLOCK3 {IMAGES_DIR}/192bit_2 --no-protect-key" ) - output = self.espefuse_py("summary -d") + output = self.espefuse_py("-d summary") self.check_data_block_in_log(output, f"{IMAGES_DIR}/192bit") self.check_data_block_in_log(output, f"{IMAGES_DIR}/192bit_1") self.check_data_block_in_log(output, f"{IMAGES_DIR}/192bit_2") self.espefuse_py( - f"burn_key \ + f"burn-key \ BLOCK1 {IMAGES_DIR}/192bit \ BLOCK2 {IMAGES_DIR}/192bit_1 \ BLOCK3 {IMAGES_DIR}/192bit_2" ) - output = self.espefuse_py("summary -d") + output = self.espefuse_py("-d summary") self.check_data_block_in_log(output, f"{IMAGES_DIR}/192bit") self.check_data_block_in_log(output, f"{IMAGES_DIR}/192bit_1") self.check_data_block_in_log(output, f"{IMAGES_DIR}/192bit_2") @@ -1043,11 +1056,11 @@ def test_burn_key_with_34_coding_scheme(self): ) def test_burn_key_512bit(self): self.espefuse_py( - f"burn_key \ + f"burn-key \ BLOCK_KEY0 {IMAGES_DIR}/256bit_1_256bit_2_combined \ XTS_AES_256_KEY --no-read-protect --no-write-protect" ) - output = self.espefuse_py("summary -d") + output = self.espefuse_py("-d summary") self.check_data_block_in_log( output, f"{IMAGES_DIR}/256bit_1", reverse_order=True ) @@ -1063,25 +1076,25 @@ def test_burn_key_512bit_non_consecutive_blocks(self): # Burn efuses separately to test different kinds # of "key used" detection criteria self.espefuse_py( - f"burn_key \ + f"burn-key \ BLOCK_KEY2 {IMAGES_DIR}/256bit XTS_AES_128_KEY" ) self.espefuse_py( - f"burn_key \ + f"burn-key \ BLOCK_KEY4 {IMAGES_DIR}/256bit SECURE_BOOT_DIGEST0" ) self.espefuse_py( - f"burn_key \ + f"burn-key \ BLOCK_KEY1 {IMAGES_DIR}/256bit_1_256bit_2_combined \ XTS_AES_256_KEY --no-read-protect --no-write-protect" ) self.espefuse_py( - f"burn_key \ + f"burn-key \ BLOCK_KEY5 {IMAGES_DIR}/256bit USER --no-read-protect --no-write-protect" ) # Second half of key should burn to first available key block (BLOCK_KEY5) - output = self.espefuse_py("summary -d") + output = self.espefuse_py("-d summary") self.check_data_block_in_log( output, f"{IMAGES_DIR}/256bit_1", reverse_order=True ) @@ -1104,7 +1117,7 @@ def test_burn_key_512bit_non_consecutive_blocks(self): ) def test_burn_key_512bit_non_consecutive_blocks_loop_around(self): self.espefuse_py( - f"burn_key \ + f"burn-key \ BLOCK_KEY2 {IMAGES_DIR}/256bit XTS_AES_128_KEY \ BLOCK_KEY3 {IMAGES_DIR}/256bit USER \ BLOCK_KEY4 {IMAGES_DIR}/256bit SECURE_BOOT_DIGEST0 \ @@ -1114,7 +1127,7 @@ def test_burn_key_512bit_non_consecutive_blocks_loop_around(self): ) # Second half of key should burn to first available key block (BLOCK_KEY0) - output = self.espefuse_py("summary -d") + output = self.espefuse_py("-d summary") self.check_data_block_in_log( output, f"{IMAGES_DIR}/256bit_1", reverse_order=True ) @@ -1132,18 +1145,18 @@ def test_burn_key_512bit_non_consecutive_blocks_loop_around(self): ) in output @pytest.mark.skipif( - arg_chip not in ["esp32h2", "esp32c5", "esp32c5beta3", "esp32c61", "esp32p4"], + arg_chip not in ["esp32h2", "esp32c5", "esp32c61", "esp32p4"], reason="These chips support ECDSA_KEY", ) def test_burn_key_ecdsa_key(self): self.espefuse_py( - f"burn_key \ + f"burn-key \ BLOCK_KEY0 {S_IMAGES_DIR}/ecdsa192_secure_boot_signing_key_v2.pem \ ECDSA_KEY \ BLOCK_KEY1 {S_IMAGES_DIR}/ecdsa256_secure_boot_signing_key_v2.pem \ ECDSA_KEY" ) - output = self.espefuse_py("summary -d") + output = self.espefuse_py("-d summary") assert 2 == output.count( "= ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? " "?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? -/-" @@ -1158,19 +1171,19 @@ def test_burn_key_ecdsa_key(self): ) in output @pytest.mark.skipif( - arg_chip not in ["esp32h2", "esp32c5", "esp32c5beta3", "esp32c61", "esp32p4"], + arg_chip not in ["esp32h2", "esp32c5", "esp32c61", "esp32p4"], reason="These chips support ECDSA_KEY", ) def test_burn_key_ecdsa_key_check_byte_order(self): self.espefuse_py( - f"burn_key \ + f"burn-key \ BLOCK_KEY0 {S_IMAGES_DIR}/ecdsa192_secure_boot_signing_key_v2.pem \ ECDSA_KEY \ BLOCK_KEY1 {S_IMAGES_DIR}/ecdsa256_secure_boot_signing_key_v2.pem \ ECDSA_KEY \ --no-read-protect" ) - output = self.espefuse_py("summary -d") + output = self.espefuse_py("-d summary") assert ( "= c8 c4 5d 62 9e 05 05 bd cb 04 a4 7c 06 f5 86 14 " "cb 23 81 23 95 b7 71 4f 00 00 00 00 00 00 00 00 R/-" @@ -1191,24 +1204,23 @@ def test_burn_key_ecdsa_key_check_byte_order(self): class TestBurnBlockDataCommands(EfuseTestCase): def test_burn_block_data_check_args(self): - self.espefuse_py("burn_block_data -h") + self.espefuse_py("burn-block-data -h") blk0 = "BLOCK0" blk1 = "BLOCK1" self.espefuse_py( - f"burn_block_data {blk0} {IMAGES_DIR}/224bit {blk1}", - check_msg="A fatal error occurred: " - "The number of block_name (2) and datafile (1) should be the same.", + f"burn-block-data {blk0} {IMAGES_DIR}/224bit {blk1}", + check_msg="Expected multiple of 2 values, got 3", ret_code=2, ) @pytest.mark.skipif(arg_chip != "esp32", reason="ESP32-only") def test_burn_block_data_with_3_key_blocks(self): self.espefuse_py( - f"burn_block_data \ + f"burn-block-data \ BLOCK0 {IMAGES_DIR}/224bit \ BLOCK3 {IMAGES_DIR}/256bit" ) - output = self.espefuse_py("summary -d") + output = self.espefuse_py("-d summary") assert ( "[3 ] read_regs: a3a2a1a0 a7a6a5a4 abaaa9a8 afaeadac " "b3b2b1b0 b7b6b5b4 bbbab9b8 bfbebdbc" @@ -1216,31 +1228,31 @@ def test_burn_block_data_with_3_key_blocks(self): self.check_data_block_in_log(output, f"{IMAGES_DIR}/256bit") self.espefuse_py( - f"burn_block_data \ + f"burn-block-data \ BLOCK2 {IMAGES_DIR}/256bit_1" ) self.check_data_block_in_log( - self.espefuse_py("summary -d"), f"{IMAGES_DIR}/256bit_1" + self.espefuse_py("-d summary"), f"{IMAGES_DIR}/256bit_1" ) self.espefuse_py( - f"burn_block_data \ + f"burn-block-data \ BLOCK1 {IMAGES_DIR}/256bit_2" ) self.check_data_block_in_log( - self.espefuse_py("summary -d"), f"{IMAGES_DIR}/256bit_2" + self.espefuse_py("-d summary"), f"{IMAGES_DIR}/256bit_2" ) @pytest.mark.skipif(arg_chip != "esp32c2", reason="ESP32-C2-only") def test_burn_block_data_with_1_key_block(self): self.espefuse_py( - f"burn_block_data \ + f"burn-block-data \ BLOCK0 {IMAGES_DIR}/64bit \ BLOCK1 {IMAGES_DIR}/96bit \ BLOCK2 {IMAGES_DIR}/256bit \ BLOCK3 {IMAGES_DIR}/256bit" ) - output = self.espefuse_py("summary -d") + output = self.espefuse_py("-d summary") assert "[0 ] read_regs: 00000001 0000000c" in output assert "[1 ] read_regs: 03020100 07060504 000a0908" in output assert ( @@ -1257,25 +1269,22 @@ def test_burn_block_data_with_1_key_block(self): not in [ "esp32s2", "esp32s3", - "esp32s3beta1", "esp32c3", - "esp32h2beta1", "esp32c6", "esp32h2", "esp32p4", "esp32c5", - "esp32c5beta3", "esp32c61", ], reason="Only chip with 6 keys", ) def test_burn_block_data_with_6_keys(self): self.espefuse_py( - f"burn_block_data \ + f"burn-block-data \ BLOCK0 {IMAGES_DIR}/192bit \ BLOCK3 {IMAGES_DIR}/256bit" ) - output = self.espefuse_py("summary -d") + output = self.espefuse_py("-d summary") assert ( "[0 ] read_regs: 00000000 07060500 00000908 00000000 13000000 00161514" in output @@ -1286,39 +1295,41 @@ def test_burn_block_data_with_6_keys(self): ) in output self.check_data_block_in_log(output, f"{IMAGES_DIR}/256bit") - self.espefuse_py( - f"burn_block_data \ - BLOCK10 {IMAGES_DIR}/256bit_1" - ) - self.check_data_block_in_log( - self.espefuse_py("summary -d"), f"{IMAGES_DIR}/256bit_1" - ) + if arg_chip != "esp32p4": + # BLOCK10 is free. In P4 it is used for ADC calib data. + self.espefuse_py( + f"burn-block-data \ + BLOCK10 {IMAGES_DIR}/256bit_3" + ) + self.check_data_block_in_log( + self.espefuse_py("-d summary"), f"{IMAGES_DIR}/256bit_3" + ) self.espefuse_py( - f"burn_block_data \ + f"burn-block-data \ BLOCK1 {IMAGES_DIR}/192bit \ BLOCK5 {IMAGES_DIR}/256bit_1 \ BLOCK6 {IMAGES_DIR}/256bit_2" ) - output = self.espefuse_py("summary -d") + output = self.espefuse_py("-d summary") assert ( "[1 ] read_regs: 00000000 07060500 00000908 00000000 13000000 00161514" in output ) self.check_data_block_in_log(output, f"{IMAGES_DIR}/256bit") - self.check_data_block_in_log(output, f"{IMAGES_DIR}/256bit_1", 2) + self.check_data_block_in_log(output, f"{IMAGES_DIR}/256bit_1") self.check_data_block_in_log(output, f"{IMAGES_DIR}/256bit_2") def test_burn_block_data_check_errors(self): self.espefuse_py( - f"burn_block_data \ + f"burn-block-data \ BLOCK2 {IMAGES_DIR}/192bit \ BLOCK2 {IMAGES_DIR}/192bit_1", check_msg="A fatal error occurred: Found repeated", ret_code=2, ) self.espefuse_py( - f"burn_block_data \ + f"burn-block-data \ BLOCK2 {IMAGES_DIR}/192bit \ BLOCK3 {IMAGES_DIR}/192bit_1 \ --offset 4", @@ -1327,12 +1338,12 @@ def test_burn_block_data_check_errors(self): ret_code=2, ) self.espefuse_py( - f"burn_block_data BLOCK0 {IMAGES_DIR}/192bit --offset 33", + f"burn-block-data BLOCK0 {IMAGES_DIR}/192bit --offset 33", check_msg="A fatal error occurred: Invalid offset: the block0 only holds", ret_code=2, ) self.espefuse_py( - f"burn_block_data BLOCK0 {IMAGES_DIR}/256bit --offset 4", + f"burn-block-data BLOCK0 {IMAGES_DIR}/256bit --offset 4", check_msg="A fatal error occurred: Data does not fit:", ret_code=2, ) @@ -1341,45 +1352,45 @@ def test_burn_block_data_check_errors(self): def test_burn_block_data_with_offset_for_3_key_blocks(self): offset = 1 self.espefuse_py( - f"burn_block_data --offset {offset} BLOCK0 {IMAGES_DIR}/192bit" + f"burn-block-data --offset {offset} BLOCK0 {IMAGES_DIR}/192bit" ) offset = 4 self.espefuse_py( - f"burn_block_data --offset {offset} BLOCK1 {IMAGES_DIR}/192bit_1" + f"burn-block-data --offset {offset} BLOCK1 {IMAGES_DIR}/192bit_1" ) self.check_data_block_in_log( - self.espefuse_py("summary -d"), f"{IMAGES_DIR}/192bit_1", offset=offset + self.espefuse_py("-d summary"), f"{IMAGES_DIR}/192bit_1", offset=offset ) offset = 6 self.espefuse_py( - f"burn_block_data --offset {offset} BLOCK2 {IMAGES_DIR}/192bit_2" + f"burn-block-data --offset {offset} BLOCK2 {IMAGES_DIR}/192bit_2" ) self.check_data_block_in_log( - self.espefuse_py("summary -d"), f"{IMAGES_DIR}/192bit_2", offset=offset + self.espefuse_py("-d summary"), f"{IMAGES_DIR}/192bit_2", offset=offset ) offset = 8 self.espefuse_py( - f"burn_block_data --offset {offset} BLOCK3 {IMAGES_DIR}/192bit_2" + f"burn-block-data --offset {offset} BLOCK3 {IMAGES_DIR}/192bit_2" ) self.check_data_block_in_log( - self.espefuse_py("summary -d"), f"{IMAGES_DIR}/192bit_2", offset=offset + self.espefuse_py("-d summary"), f"{IMAGES_DIR}/192bit_2", offset=offset ) @pytest.mark.skipif(arg_chip != "esp32c2", reason="ESP32-C2-only") def test_burn_block_data_with_offset_1_key_block(self): offset = 4 - self.espefuse_py(f"burn_block_data --offset {offset} BLOCK1 {IMAGES_DIR}/92bit") - output = self.espefuse_py("summary -d") + self.espefuse_py(f"burn-block-data --offset {offset} BLOCK1 {IMAGES_DIR}/92bit") + output = self.espefuse_py("-d summary") assert "[1 ] read_regs: 00000000 03020100 00060504" in output offset = 6 self.espefuse_py( - f"burn_block_data --offset {offset} BLOCK2 {IMAGES_DIR}/192bit_1" + f"burn-block-data --offset {offset} BLOCK2 {IMAGES_DIR}/192bit_1" ) - output = self.espefuse_py("summary -d") + output = self.espefuse_py("-d summary") assert ( "[2 ] read_regs: 00000000 00110000 05000000 09080706 " "0d0c0b0a 11100f0e 15141312 00002116" @@ -1387,10 +1398,10 @@ def test_burn_block_data_with_offset_1_key_block(self): offset = 8 self.espefuse_py( - f"burn_block_data --offset {offset} BLOCK3 {IMAGES_DIR}/192bit_2" + f"burn-block-data --offset {offset} BLOCK3 {IMAGES_DIR}/192bit_2" ) self.check_data_block_in_log( - self.espefuse_py("summary -d"), f"{IMAGES_DIR}/192bit_2", offset=offset + self.espefuse_py("-d summary"), f"{IMAGES_DIR}/192bit_2", offset=offset ) @pytest.mark.skipif( @@ -1398,14 +1409,11 @@ def test_burn_block_data_with_offset_1_key_block(self): not in [ "esp32s2", "esp32s3", - "esp32s3beta1", "esp32c3", - "esp32h2beta1", "esp32c6", "esp32h2", "esp32p4", "esp32c5", - "esp32c5beta3", "esp32c61", ], reason="Only chips with 6 keys", @@ -1413,26 +1421,26 @@ def test_burn_block_data_with_offset_1_key_block(self): def test_burn_block_data_with_offset_6_keys(self): offset = 4 self.espefuse_py( - f"burn_block_data --offset {offset} BLOCK_KEY0 {IMAGES_DIR}/192bit_1" + f"burn-block-data --offset {offset} BLOCK_KEY0 {IMAGES_DIR}/192bit_1" ) self.check_data_block_in_log( - self.espefuse_py("summary -d"), f"{IMAGES_DIR}/192bit_1", offset=offset + self.espefuse_py("-d summary"), f"{IMAGES_DIR}/192bit_1", offset=offset ) offset = 6 self.espefuse_py( - f"burn_block_data --offset {offset} BLOCK_KEY1 {IMAGES_DIR}/192bit_2" + f"burn-block-data --offset {offset} BLOCK_KEY1 {IMAGES_DIR}/192bit_2" ) self.check_data_block_in_log( - self.espefuse_py("summary -d"), f"{IMAGES_DIR}/192bit_2", offset=offset + self.espefuse_py("-d summary"), f"{IMAGES_DIR}/192bit_2", offset=offset ) offset = 8 self.espefuse_py( - f"burn_block_data --offset {offset} BLOCK_KEY2 {IMAGES_DIR}/192bit_2" + f"burn-block-data --offset {offset} BLOCK_KEY2 {IMAGES_DIR}/192bit_2" ) self.check_data_block_in_log( - self.espefuse_py("summary -d"), f"{IMAGES_DIR}/192bit_2", offset=offset + self.espefuse_py("-d summary"), f"{IMAGES_DIR}/192bit_2", offset=offset ) @pytest.mark.skipif( @@ -1441,19 +1449,19 @@ def test_burn_block_data_with_offset_6_keys(self): def test_burn_block_data_with_34_coding_scheme(self): self._set_34_coding_scheme() self.espefuse_py( - f"burn_block_data BLOCK1 {IMAGES_DIR}/256bit", + f"burn-block-data BLOCK1 {IMAGES_DIR}/256bit", check_msg="A fatal error occurred: Data does not fit: " "the block1 size is 24 bytes, data file is 32 bytes, offset 0", ret_code=2, ) self.espefuse_py( - f"burn_block_data \ + f"burn-block-data \ BLOCK1 {IMAGES_DIR}/192bit \ BLOCK2 {IMAGES_DIR}/192bit_1 \ BLOCK3 {IMAGES_DIR}/192bit_2" ) - output = self.espefuse_py("summary -d") + output = self.espefuse_py("-d summary") self.check_data_block_in_log(output, f"{IMAGES_DIR}/192bit") self.check_data_block_in_log(output, f"{IMAGES_DIR}/192bit_1") self.check_data_block_in_log(output, f"{IMAGES_DIR}/192bit_2") @@ -1466,59 +1474,59 @@ def test_burn_block_data_with_34_coding_scheme_and_offset(self): offset = 4 self.espefuse_py( - f"burn_block_data --offset {offset} BLOCK1 {IMAGES_DIR}/128bit" + f"burn-block-data --offset {offset} BLOCK1 {IMAGES_DIR}/128bit" ) self.check_data_block_in_log( - self.espefuse_py("summary -d"), f"{IMAGES_DIR}/128bit", offset=offset + self.espefuse_py("-d summary"), f"{IMAGES_DIR}/128bit", offset=offset ) offset = 6 self.espefuse_py( - f"burn_block_data --offset {offset} BLOCK2 {IMAGES_DIR}/128bit" + f"burn-block-data --offset {offset} BLOCK2 {IMAGES_DIR}/128bit" ) self.check_data_block_in_log( - self.espefuse_py("summary -d"), f"{IMAGES_DIR}/128bit", offset=offset + self.espefuse_py("-d summary"), f"{IMAGES_DIR}/128bit", offset=offset ) offset = 8 self.espefuse_py( - f"burn_block_data --offset {offset} BLOCK3 {IMAGES_DIR}/128bit" + f"burn-block-data --offset {offset} BLOCK3 {IMAGES_DIR}/128bit" ) self.check_data_block_in_log( - self.espefuse_py("summary -d"), f"{IMAGES_DIR}/128bit", offset=offset + self.espefuse_py("-d summary"), f"{IMAGES_DIR}/128bit", offset=offset ) @pytest.mark.skipif(arg_chip != "esp32", reason="ESP32-only, supports 2 key blocks") class TestBurnKeyDigestCommandsEsp32(EfuseTestCase): def test_burn_key_digest(self): - self.espefuse_py("burn_key_digest -h") + self.espefuse_py("burn-key-digest -h") esp = self.get_esptool() if esp.get_chip_revision() >= 300: self.espefuse_py( - f"burn_key_digest {S_IMAGES_DIR}/rsa_secure_boot_signing_key.pem" + f"burn-key-digest {S_IMAGES_DIR}/rsa_secure_boot_signing_key.pem" ) - output = self.espefuse_py("summary -d") + output = self.espefuse_py("-d summary") assert ( " = cb 27 91 a3 71 b0 c0 32 2b f7 37 04 78 ba 09 62 " "22 4c ab 1c f2 28 78 79 e4 29 67 3e 7d a8 44 63 R/-" ) in output else: self.espefuse_py( - f"burn_key_digest {S_IMAGES_DIR}/rsa_secure_boot_signing_key.pem", + f"burn-key-digest {S_IMAGES_DIR}/rsa_secure_boot_signing_key.pem", check_msg="Incorrect chip revision for Secure boot v2.", ret_code=2, ) def test_burn_key_from_digest(self): - # python espsecure.py digest_rsa_public_key + # python espsecure digest_rsa_public_key # --keyfile test/{S_IMAGES_DIR}/rsa_secure_boot_signing_key.pem # -o {S_IMAGES_DIR}/rsa_public_key_digest.bin self.espefuse_py( - f"burn_key \ + f"burn-key \ BLOCK2 {S_IMAGES_DIR}/rsa_public_key_digest.bin --no-protect-key" ) - output = self.espefuse_py("summary -d") + output = self.espefuse_py("-d summary") assert 1 == output.count( " = cb 27 91 a3 71 b0 c0 32 2b f7 37 04 78 ba 09 62 " "22 4c ab 1c f2 28 78 79 e4 29 67 3e 7d a8 44 63 R/W" @@ -1527,8 +1535,8 @@ def test_burn_key_from_digest(self): def test_burn_key_digest_with_34_coding_scheme(self): self._set_34_coding_scheme() self.espefuse_py( - f"burn_key_digest {S_IMAGES_DIR}/rsa_secure_boot_signing_key.pem", - check_msg="burn_key_digest only works with 'None' coding scheme", + f"burn-key-digest {S_IMAGES_DIR}/rsa_secure_boot_signing_key.pem", + check_msg="burn-key-digest only works with 'None' coding scheme", ret_code=2, ) @@ -1536,13 +1544,13 @@ def test_burn_key_digest_with_34_coding_scheme(self): @pytest.mark.skipif(arg_chip != "esp32c2", reason="ESP32-C2-only, supports 1 key block") class TestBurnKeyDigestCommandsEsp32C2(EfuseTestCase): def test_burn_key_digest1(self): - # python espsecure.py generate_signing_key --version 2 + # python espsecure generate_signing_key --version 2 # secure_images/ecdsa192_secure_boot_signing_key_v2.pem --scheme ecdsa192 - self.espefuse_py("burn_key_digest -h") + self.espefuse_py("burn-key-digest -h") self.espefuse_py( - f"burn_key_digest {S_IMAGES_DIR}/ecdsa192_secure_boot_signing_key_v2.pem" + f"burn-key-digest {S_IMAGES_DIR}/ecdsa192_secure_boot_signing_key_v2.pem" ) - output = self.espefuse_py("summary -d") + output = self.espefuse_py("-d summary") assert " = 1e 3d 15 16 96 ca 7f 22 a6 e8 8b d5 27 a0 3b 3b R/-" in output assert ( " = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 " @@ -1550,13 +1558,13 @@ def test_burn_key_digest1(self): ) in output def test_burn_key_digest2(self): - # python espsecure.py generate_signing_key --version 2 + # python espsecure generate_signing_key --version 2 # secure_images/ecdsa256_secure_boot_signing_key_v2.pem --scheme ecdsa256 - self.espefuse_py("burn_key_digest -h") + self.espefuse_py("burn-key-digest -h") self.espefuse_py( - f"burn_key_digest {S_IMAGES_DIR}/ecdsa256_secure_boot_signing_key_v2.pem" + f"burn-key-digest {S_IMAGES_DIR}/ecdsa256_secure_boot_signing_key_v2.pem" ) - output = self.espefuse_py("summary -d") + output = self.espefuse_py("-d summary") assert " = bf 0f 6a f6 8b d3 6d 8b 53 b3 da a9 33 f6 0a 04 R/-" in output assert ( " = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 " @@ -1564,28 +1572,28 @@ def test_burn_key_digest2(self): ) in output def test_burn_key_from_digest1(self): - # python espsecure.py digest_sbv2_public_key --keyfile + # python espsecure digest_sbv2_public_key --keyfile # secure_images/ecdsa192_secure_boot_signing_key_v2.pem # -o secure_images/ecdsa192_public_key_digest_v2.bin self.espefuse_py( - "burn_key BLOCK_KEY0 " + "burn-key BLOCK_KEY0 " f"{S_IMAGES_DIR}/ecdsa192_public_key_digest_v2.bin SECURE_BOOT_DIGEST" ) - output = self.espefuse_py("summary -d") + output = self.espefuse_py("-d summary") assert ( " = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 " "1e 3d 15 16 96 ca 7f 22 a6 e8 8b d5 27 a0 3b 3b R/-" ) in output def test_burn_key_from_digest2(self): - # python espsecure.py digest_sbv2_public_key --keyfile + # python espsecure digest_sbv2_public_key --keyfile # secure_images/ecdsa256_secure_boot_signing_key_v2.pem # -o secure_images/ecdsa256_public_key_digest_v2.bin self.espefuse_py( - "burn_key BLOCK_KEY0 " + "burn-key BLOCK_KEY0 " f"{S_IMAGES_DIR}/ecdsa256_public_key_digest_v2.bin SECURE_BOOT_DIGEST" ) - output = self.espefuse_py("summary -d") + output = self.espefuse_py("-d summary") assert ( " = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 " "bf 0f 6a f6 8b d3 6d 8b 53 b3 da a9 33 f6 0a 04 R/-" @@ -1597,34 +1605,30 @@ def test_burn_key_from_digest2(self): not in [ "esp32s2", "esp32s3", - "esp32s3beta1", "esp32c3", - "esp32h2beta1", "esp32c6", "esp32h2", "esp32p4", "esp32c5", - "esp32c5beta3", "esp32c61", ], reason="Supports 6 key blocks", ) class TestBurnKeyDigestCommands(EfuseTestCase): def test_burn_key_digest(self): - self.espefuse_py("burn_key_digest -h") + self.espefuse_py("burn-key-digest -h") self.espefuse_py( - f"burn_key_digest \ + f"burn-key-digest \ BLOCK_KEY0 \ {S_IMAGES_DIR}/rsa_secure_boot_signing_key.pem SECURE_BOOT_DIGEST0 \ BLOCK_KEY1 \ {S_IMAGES_DIR}/rsa_secure_boot_signing_key2.pem SECURE_BOOT_DIGEST1 \ BLOCK_KEY2 ", - check_msg="A fatal error occurred: The number of blocks (3), " - "datafile (2) and keypurpose (2) should be the same.", + check_msg="Expected multiple of 3 values, got 7", ret_code=2, ) self.espefuse_py( - f"burn_key_digest \ + f"burn-key-digest \ BLOCK_KEY0 \ {S_IMAGES_DIR}/rsa_secure_boot_signing_key.pem SECURE_BOOT_DIGEST0 \ BLOCK_KEY1 \ @@ -1632,7 +1636,7 @@ def test_burn_key_digest(self): BLOCK_KEY2 \ {S_IMAGES_DIR}/rsa_secure_boot_signing_key2.pem SECURE_BOOT_DIGEST2" ) - output = self.espefuse_py("summary -d") + output = self.espefuse_py("-d summary") assert 1 == output.count( " = cb 27 91 a3 71 b0 c0 32 2b f7 37 04 78 ba 09 62 " "22 4c ab 1c f2 28 78 79 e4 29 67 3e 7d a8 44 63 R/-" @@ -1643,25 +1647,25 @@ def test_burn_key_digest(self): ) def test_burn_key_from_digest(self): - # python espsecure.py digest_rsa_public_key + # python espsecure digest_rsa_public_key # --keyfile test/secure_images/rsa_secure_boot_signing_key.pem # -o secure_images/rsa_public_key_digest.bin self.espefuse_py( - f"burn_key \ + f"burn-key \ BLOCK_KEY0 {S_IMAGES_DIR}/rsa_public_key_digest.bin SECURE_BOOT_DIGEST0" ) - output = self.espefuse_py("summary -d") + output = self.espefuse_py("-d summary") assert 1 == output.count( " = cb 27 91 a3 71 b0 c0 32 2b f7 37 04 78 ba 09 62 " "22 4c ab 1c f2 28 78 79 e4 29 67 3e 7d a8 44 63 R/-" ) self.espefuse_py( - f"burn_key_digest \ + f"burn-key-digest \ BLOCK_KEY1 \ {S_IMAGES_DIR}/rsa_secure_boot_signing_key.pem SECURE_BOOT_DIGEST1" ) - output = self.espefuse_py("summary -d") + output = self.espefuse_py("-d summary") assert 2 == output.count( " = cb 27 91 a3 71 b0 c0 32 2b f7 37 04 78 ba 09 62 " "22 4c ab 1c f2 28 78 79 e4 29 67 3e 7d a8 44 63 R/-" @@ -1671,8 +1675,8 @@ def test_burn_key_from_digest(self): class TestBurnBitCommands(EfuseTestCase): @pytest.mark.skipif(arg_chip != "esp32", reason="ESP32-only") def test_burn_bit_for_chips_with_3_key_blocks(self): - self.espefuse_py("burn_bit -h") - self.espefuse_py("burn_bit BLOCK3 0 1 2 4 8 16 32 64 96 128 160 192 224 255") + self.espefuse_py("burn-bit -h") + self.espefuse_py("burn-bit BLOCK3 0 1 2 4 8 16 32 64 96 128 160 192 224 255") self.espefuse_py( "summary", check_msg="17 01 01 00 01 00 00 00 01 00 00 00 01 00 00 " @@ -1680,7 +1684,7 @@ def test_burn_bit_for_chips_with_3_key_blocks(self): ) self.espefuse_py( - "burn_bit BLOCK3 3 5 6 7 9 10 11 12 13 14 15 31 63 95 127 159 191 223 254" + "burn-bit BLOCK3 3 5 6 7 9 10 11 12 13 14 15 31 63 95 127 159 191 223 254" ) self.espefuse_py( "summary", @@ -1690,21 +1694,21 @@ def test_burn_bit_for_chips_with_3_key_blocks(self): @pytest.mark.skipif(arg_chip != "esp32c2", reason="ESP32-C2-only") def test_burn_bit_for_chips_with_1_key_block(self): - self.espefuse_py("burn_bit -h") - self.espefuse_py("burn_bit BLOCK3 0 1 2 4 8 16 32 64 96 128 160 192 224 255") + self.espefuse_py("burn-bit -h") + self.espefuse_py("burn-bit BLOCK3 0 1 2 4 8 16 32 64 96 128 160 192 224 255") self.espefuse_py( "summary", check_msg="17 01 01 00 01 00 00 00 01 00 00 00 01 00 " "00 00 01 00 00 00 01 00 00 00 01 00 00 00 01 00 00 80", ) self.espefuse_py( - "burn_bit BLOCK3 100", + "burn-bit BLOCK3 100", check_msg="Burn into BLOCK_KEY0 is forbidden " "(RS coding scheme does not allow this)", ret_code=2, ) - self.espefuse_py("burn_bit BLOCK0 0 1 2") + self.espefuse_py("burn-bit BLOCK0 0 1 2") self.espefuse_py("summary", check_msg="[0 ] read_regs: 00000007 00000000") @pytest.mark.skipif( @@ -1712,41 +1716,38 @@ def test_burn_bit_for_chips_with_1_key_block(self): not in [ "esp32s2", "esp32s3", - "esp32s3beta1", "esp32c3", - "esp32h2beta1", "esp32c6", "esp32h2", "esp32p4", "esp32c5", - "esp32c5beta3", "esp32c61", ], reason="Only chip with 6 keys", ) def test_burn_bit_for_chips_with_6_key_blocks(self): - self.espefuse_py("burn_bit -h") - self.espefuse_py("burn_bit BLOCK3 0 1 2 4 8 16 32 64 96 128 160 192 224 255") + self.espefuse_py("burn-bit -h") + self.espefuse_py("burn-bit BLOCK3 0 1 2 4 8 16 32 64 96 128 160 192 224 255") self.espefuse_py( "summary", check_msg="17 01 01 00 01 00 00 00 01 00 00 00 01 00 " "00 00 01 00 00 00 01 00 00 00 01 00 00 00 01 00 00 80", ) self.espefuse_py( - "burn_bit BLOCK3 100", + "burn-bit BLOCK3 100", check_msg="Burn into BLOCK_USR_DATA is forbidden " "(RS coding scheme does not allow this)", ret_code=2, ) - self.espefuse_py("burn_bit BLOCK0 13") + self.espefuse_py("burn-bit BLOCK0 13") self.espefuse_py( "summary", check_msg="[0 ] read_regs: 00002000 00000000 00000000 " "00000000 00000000 00000000", ) - self.espefuse_py("burn_bit BLOCK0 24") + self.espefuse_py("burn-bit BLOCK0 24") self.espefuse_py( "summary", check_msg="[0 ] read_regs: 01002000 00000000 00000000 " @@ -1758,14 +1759,14 @@ def test_burn_bit_for_chips_with_6_key_blocks(self): ) def test_burn_bit_with_34_coding_scheme(self): self._set_34_coding_scheme() - self.espefuse_py("burn_bit BLOCK3 0 1 2 4 8 16 32 64 96 128 160 191") + self.espefuse_py("burn-bit BLOCK3 0 1 2 4 8 16 32 64 96 128 160 191") self.espefuse_py( "summary", check_msg="17 01 01 00 01 00 00 00 01 00 00 00 01 00 " "00 00 01 00 00 00 01 00 00 80", ) self.espefuse_py( - "burn_bit BLOCK3 17", + "burn-bit BLOCK3 17", check_msg="Burn into BLOCK3 is forbidden " "(3/4 coding scheme does not allow this).", ret_code=2, @@ -1774,7 +1775,7 @@ def test_burn_bit_with_34_coding_scheme(self): @pytest.mark.skipif(arg_chip != "esp32", reason="ESP32-only") def test_burn_bit_with_none_recovery_coding_scheme(self): self._set_none_recovery_coding_scheme() - self.espefuse_py("burn_bit BLOCK3 0 1 2 4 8 16 32 64 96 128 160 192 224 255") + self.espefuse_py("burn-bit BLOCK3 0 1 2 4 8 16 32 64 96 128 160 192 224 255") self.espefuse_py( "summary", check_msg="17 01 01 00 01 00 00 00 01 00 00 00 01 00 00 " @@ -1789,11 +1790,11 @@ class TestByteOrderBurnKeyCommand(EfuseTestCase): def test_1_secure_boot_v1(self): if arg_chip == "esp32": self.espefuse_py( - f"burn_key \ + f"burn-key \ flash_encryption {IMAGES_DIR}/256bit \ secure_boot_v1 {IMAGES_DIR}/256bit_1 --no-protect-key" ) - output = self.espefuse_py("summary -d") + output = self.espefuse_py("-d summary") self.check_data_block_in_log( output, f"{IMAGES_DIR}/256bit", reverse_order=True ) @@ -1802,11 +1803,11 @@ def test_1_secure_boot_v1(self): ) self.espefuse_py( - f"burn_key \ + f"burn-key \ flash_encryption {IMAGES_DIR}/256bit \ secure_boot_v1 {IMAGES_DIR}/256bit_1" ) - output = self.espefuse_py("summary -d") + output = self.espefuse_py("-d summary") assert ( "[1 ] read_regs: 00000000 00000000 00000000 00000000 " "00000000 00000000 00000000 00000000" @@ -1823,11 +1824,11 @@ def test_1_secure_boot_v1(self): def test_2_secure_boot_v1(self): if arg_chip == "esp32": self.espefuse_py( - f"burn_key \ + f"burn-key \ flash_encryption {IMAGES_DIR}/256bit \ secure_boot_v2 {IMAGES_DIR}/256bit_1 --no-protect-key" ) - output = self.espefuse_py("summary -d") + output = self.espefuse_py("-d summary") self.check_data_block_in_log( output, f"{IMAGES_DIR}/256bit", reverse_order=True ) @@ -1836,11 +1837,11 @@ def test_2_secure_boot_v1(self): ) self.espefuse_py( - f"burn_key \ + f"burn-key \ flash_encryption {IMAGES_DIR}/256bit \ secure_boot_v2 {IMAGES_DIR}/256bit_1" ) - output = self.espefuse_py("summary -d") + output = self.espefuse_py("-d summary") assert ( "[1 ] read_regs: 00000000 00000000 00000000 00000000 " "00000000 00000000 00000000 00000000" @@ -1850,121 +1851,173 @@ def test_2_secure_boot_v1(self): ) -class TestExecuteScriptsCommands(EfuseTestCase): - @classmethod - def setup_class(self): - # Save the current working directory to be restored later - self.stored_dir = os.getcwd() +class TestPublicAPI(EfuseTestCase): + def _init_commands(self, **kwargs): + from espefuse import init_commands + + args = { + "do_not_confirm": True, + "chip": arg_chip, + "virt": True, + "virt_efuse_file": self.efuse_file.name, + "debug": True, + } + args.update(kwargs) + return init_commands(**args) + + @pytest.mark.skipif(arg_chip != "esp32", reason="This test is only for esp32") + def test_public_api_batch_mode(self): + with self._init_commands(batch_mode=True) as espefuse: + espefuse.burn_efuse( + { + "JTAG_DISABLE": "1", + "DISABLE_SDIO_HOST": "1", + "CONSOLE_DEBUG_DISABLE": "1", + } + ) + assert espefuse.efuses["JTAG_DISABLE"].get() == 0, ( + "Burn should be at the end" + ) - @classmethod - def teardown_class(self): - # Restore the stored working directory - os.chdir(self.stored_dir) + with open(IMAGES_DIR + "/256bit", "rb") as f: + espefuse.burn_key(["flash_encryption"], [f], no_protect_key=True) + assert espefuse.efuses["BLOCK1"].get_meaning() == EMPTY_BLOCK + assert ( + espefuse.efuses["BLOCK1"].is_readable() + and espefuse.efuses["BLOCK1"].is_writeable() + ) - @pytest.mark.skipif( - arg_chip in ["esp32c2", "esp32p4"], - reason="These chips do not have eFuses used in this test", - ) - def test_execute_scripts_with_check_that_only_one_burn(self): - self.espefuse_py("execute_scripts -h") - name = arg_chip if arg_chip in ["esp32", "esp32c2"] else "esp32xx" - os.chdir(os.path.join(TEST_DIR, "efuse_scripts", name)) - self.espefuse_py("execute_scripts execute_efuse_script2.py") + with open(S_IMAGES_DIR + "/rsa_secure_boot_signing_key.pem", "rb") as f: + espefuse.burn_key_digest(f) + assert espefuse.efuses["BLOCK2"].get_meaning() == EMPTY_BLOCK + assert ( + espefuse.efuses["BLOCK2"].is_readable() + and espefuse.efuses["BLOCK2"].is_writeable() + ) + + espefuse.burn_bit("BLOCK3", [64, 66, 69, 72, 78, 82, 83, 90]) + espefuse.burn_custom_mac("aa:cd:ef:11:22:33") + assert espefuse.efuses["BLOCK3"].get_meaning() == EMPTY_BLOCK + + espefuse.burn_all() + espefuse.summary() + + assert espefuse.efuses["JTAG_DISABLE"].get() == 1 + assert espefuse.efuses["DISABLE_SDIO_HOST"].get() == 1 + assert espefuse.efuses["CONSOLE_DEBUG_DISABLE"].get() == 1 - @pytest.mark.skipif( - arg_chip in ["esp32c2", "esp32p4"], - reason="These chips do not have eFuses used in this test", - ) - def test_execute_scripts_with_check(self): - self.espefuse_py("execute_scripts -h") - name = arg_chip if arg_chip in ["esp32", "esp32c2"] else "esp32xx" - os.chdir(os.path.join(TEST_DIR, "efuse_scripts", name)) - self.espefuse_py("execute_scripts execute_efuse_script.py") - - def test_execute_scripts_with_index_and_config(self): - os.chdir(TEST_DIR) - if arg_chip in ["esp32", "esp32c2"]: - cmd = f"execute_scripts {EFUSE_S_DIR}/efuse_burn1.py --index 10 \ - --configfiles {EFUSE_S_DIR}/esp32/config1.json" - else: - cmd = f"execute_scripts {EFUSE_S_DIR}/efuse_burn1.py --index 10 \ - --configfiles {EFUSE_S_DIR}/esp32xx/config1.json" - self.espefuse_py(cmd) - output = self.espefuse_py("summary -d") - if arg_chip in ["esp32", "esp32c2"]: assert ( - "[3 ] read_regs: e00007ff 00000000 00000000 00000000 " - "00000000 00000000 00000000 00000000" - ) in output - else: + espefuse.efuses["BLOCK1"].get_meaning() + == "bf be bd bc bb ba b9 b8 b7 b6 b5 b4 b3 b2 b1 b0 af " + "ae ad ac ab aa a9 a8 a7 a6 a5 a4 a3 a2 a1 a0" + ) assert ( - "[8 ] read_regs: e00007ff 00000000 00000000 00000000 " - "00000000 00000000 00000000 00000000" - ) in output + espefuse.efuses["BLOCK1"].is_readable() + and espefuse.efuses["BLOCK1"].is_writeable() + ) - def test_execute_scripts_nesting(self): - os.chdir(TEST_DIR) - if arg_chip in ["esp32", "esp32c2"]: - cmd = f"execute_scripts {EFUSE_S_DIR}/efuse_burn2.py --index 28 \ - --configfiles {EFUSE_S_DIR}/esp32/config2.json" - else: - cmd = f"execute_scripts {EFUSE_S_DIR}/efuse_burn2.py --index 28 \ - --configfiles {EFUSE_S_DIR}/esp32xx/config2.json" - self.espefuse_py(cmd) - output = self.espefuse_py("summary -d") - if arg_chip in ["esp32", "esp32c2"]: assert ( - "[2 ] read_regs: 10000000 00000000 00000000 00000000 " - "00000000 00000000 00000000 00000000" - ) in output + espefuse.efuses["BLOCK2"].get_meaning() + == "cb 27 91 a3 71 b0 c0 32 2b f7 37 04 78 ba 09 62 22 " + "4c ab 1c f2 28 78 79 e4 29 67 3e 7d a8 44 63" + ) + assert ( - "[3 ] read_regs: ffffffff 00000000 00000000 00000000 " - "00000000 00000000 00000000 00000000" - ) in output - else: + espefuse.efuses["CUSTOM_MAC"].get_meaning() + == "aa:cd:ef:11:22:33 (CRC 0x63 OK)" + ) assert ( - "[7 ] read_regs: 10000000 00000000 00000000 00000000 " - "00000000 00000000 00000000 00000000" - ) in output + espefuse.efuses["BLOCK3"].get_meaning() + == "63 aa cd ef 11 22 33 00 25 41 0c 04 00 00 00 00 " + "00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00" + ) + + def test_public_api_nesting(self): + from espefuse import init_commands + + def burn_custom_mac(esp): + with init_commands( + esp=esp, batch_mode=True, do_not_confirm=True + ) as espefuse: + espefuse.burn_custom_mac(b"\xaa\xcd\xef\x11\x22\x33") + espefuse.burn_all() + + with self._init_commands(batch_mode=True) as espefuse: + espefuse.burn_efuse({"WR_DIS": "2", "RD_DIS": "1"}) + # Burn should be at the end; so the eFuses should be set to 0 + assert espefuse.efuses["WR_DIS"].get() == 0 + assert espefuse.efuses["RD_DIS"].get() == 0 + + burn_custom_mac(espefuse.esp) + espefuse.summary() + + # Make sure that the eFuses are not set; last burn_all is not called yet + assert espefuse.efuses["WR_DIS"].get() == 0 + assert espefuse.efuses["RD_DIS"].get() == 0 assert ( - "[8 ] read_regs: ffffffff 00000000 00000000 00000000 " - "00000000 00000000 00000000 00000000" - ) in output + espefuse.efuses["CUSTOM_MAC"].get_meaning() + == "00:00:00:00:00:00 (CRC 0x00 OK)" + if arg_chip == "esp32" + else "00:00:00:00:00:00 (OK)" + ) + + # Last burn_all should actually set eFuses + espefuse.burn_all() + espefuse.summary() + + assert espefuse.efuses["WR_DIS"].get() == 2 + assert espefuse.efuses["RD_DIS"].get() == 1 + assert ( + espefuse.efuses["CUSTOM_MAC"].get_meaning() + == "aa:cd:ef:11:22:33 (CRC 0x63 OK)" + if arg_chip == "esp32" + else "aa:cd:ef:11:22:33 (OK)" + ) class TestMultipleCommands(EfuseTestCase): def test_multiple_cmds_help(self): if arg_chip == "esp32c2": command1 = ( - f"burn_key_digest {S_IMAGES_DIR}" + f"burn-key-digest {S_IMAGES_DIR}" "/ecdsa256_secure_boot_signing_key_v2.pem" ) command2 = ( - f"burn_key BLOCK_KEY0 {IMAGES_DIR}/128bit_key " + f"burn-key BLOCK_KEY0 {IMAGES_DIR}/128bit_key " "XTS_AES_128_KEY_DERIVED_FROM_128_EFUSE_BITS" ) elif arg_chip == "esp32": - command1 = f"burn_key_digest {S_IMAGES_DIR}/rsa_secure_boot_signing_key.pem" - command2 = f"burn_key flash_encryption {IMAGES_DIR}/256bit" + command1 = f"burn-key-digest {S_IMAGES_DIR}/rsa_secure_boot_signing_key.pem" + command2 = f"burn-key flash-encryption {IMAGES_DIR}/256bit" else: - command1 = f"burn_key_digest BLOCK_KEY0 \ + command1 = f"burn-key-digest BLOCK_KEY0 \ {S_IMAGES_DIR}/rsa_secure_boot_signing_key.pem SECURE_BOOT_DIGEST0" - command2 = f"burn_key BLOCK_KEY0 \ + command2 = f"burn-key BLOCK_KEY0 \ {S_IMAGES_DIR}/rsa_public_key_digest.bin SECURE_BOOT_DIGEST0" self.espefuse_py( f"-h {command1} {command2}", - check_msg="usage: __main__.py [-h]", + check_msg=f"Usage: {ESPEFUSE_MODNAME}", ) self.espefuse_py( f"{command1} -h {command2}", - check_msg="usage: __main__.py burn_key_digest [-h]", + check_msg=f"Usage: {ESPEFUSE_MODNAME} burn-key-digest [OPTIONS] " + + ( + "KEYFILE" + if arg_chip in ["esp32", "esp32c2"] + else "[ ] ..." + ), ) self.espefuse_py( f"{command1} {command2} -h", - check_msg="usage: __main__.py burn_key [-h]", + check_msg=f"Usage: {ESPEFUSE_MODNAME} burn-key [OPTIONS] " + + ( + "[ ] ..." + if arg_chip == "esp32" + else "[ ] ..." + ), ) @pytest.mark.skipif( @@ -1972,12 +2025,12 @@ def test_multiple_cmds_help(self): ) def test_1_esp32c2(self): self.espefuse_py( - f"burn_key_digest {S_IMAGES_DIR}/ecdsa256_secure_boot_signing_key_v2.pem \ - burn_key BLOCK_KEY0 {IMAGES_DIR}/128bit_key \ + f"burn-key-digest {S_IMAGES_DIR}/ecdsa256_secure_boot_signing_key_v2.pem \ + burn-key BLOCK_KEY0 {IMAGES_DIR}/128bit_key \ XTS_AES_128_KEY_DERIVED_FROM_128_EFUSE_BITS --no-read-protect \ summary" ) - output = self.espefuse_py("summary -d") + output = self.espefuse_py("-d summary") assert ( "[3 ] read_regs: 0c0d0e0f 08090a0b 04050607 00010203 " "f66a0fbf 8b6dd38b a9dab353 040af633" @@ -1990,12 +2043,12 @@ def test_1_esp32c2(self): ) def test_2_esp32c2(self): self.espefuse_py( - f"burn_key_digest {S_IMAGES_DIR}/ecdsa256_secure_boot_signing_key_v2.pem \ - burn_key BLOCK_KEY0 \ + f"burn-key-digest {S_IMAGES_DIR}/ecdsa256_secure_boot_signing_key_v2.pem \ + burn-key BLOCK_KEY0 \ {IMAGES_DIR}/128bit_key XTS_AES_128_KEY_DERIVED_FROM_128_EFUSE_BITS \ summary" ) - output = self.espefuse_py("summary -d") + output = self.espefuse_py("-d summary") assert ( "[3 ] read_regs: 00000000 00000000 00000000 00000000 " "f66a0fbf 8b6dd38b a9dab353 040af633" @@ -2007,22 +2060,44 @@ def test_burn_bit(self): if arg_chip == "esp32": self._set_34_coding_scheme() self.espefuse_py( + "burn-bit BLOCK2 0 1 2 3 \ + burn-bit BLOCK2 4 5 6 7 \ + burn-bit BLOCK2 8 9 10 11 \ + burn-bit BLOCK2 12 13 14 15 \ + summary" + ) + output = self.espefuse_py("-d summary") + assert "[2 ] read_regs: 0000ffff 00000000" in output + + @pytest.mark.skipif( + arg_chip != "esp32", reason="We don't need to test this on all chips." + ) + def test_burn_bit_deprecated_commands(self): + """Run deprecated commands and check that the new ones are used instead. + Make sure that this works with command chaining and nargs=-1.""" + if arg_chip == "esp32": + self._set_34_coding_scheme() + output = self.espefuse_py( "burn_bit BLOCK2 0 1 2 3 \ burn_bit BLOCK2 4 5 6 7 \ burn_bit BLOCK2 8 9 10 11 \ burn_bit BLOCK2 12 13 14 15 \ summary" ) - output = self.espefuse_py("summary -d") + assert ( + "Warning: Deprecated: Command 'burn_bit' is deprecated. " + "Use 'burn-bit' instead." in output + ) + output = self.espefuse_py("-d summary") assert "[2 ] read_regs: 0000ffff 00000000" in output def test_not_burn_cmds(self): self.espefuse_py( "summary \ dump \ - get_custom_mac \ - adc_info \ - check_error" + get-custom-mac \ + adc-info \ + check-error" ) @@ -2033,7 +2108,7 @@ def test_not_burn_cmds(self): class TestKeyPurposes(EfuseTestCase): def test_burn_xts_aes_key_purpose(self): self.espefuse_py( - "burn_efuse KEY_PURPOSE_5 XTS_AES_128_KEY", + "burn-efuse KEY_PURPOSE_5 XTS_AES_128_KEY", check_msg="A fatal error occurred: " "KEY_PURPOSE_5 can not have XTS_AES_128_KEY " "key due to a hardware bug (please see TRM for more details)", @@ -2045,7 +2120,7 @@ def test_burn_xts_aes_key_purpose(self): ) def test_burn_ecdsa_key_purpose(self): self.espefuse_py( - "burn_efuse KEY_PURPOSE_5 ECDSA_KEY", + "burn-efuse KEY_PURPOSE_5 ECDSA_KEY", check_msg="A fatal error occurred: " "KEY_PURPOSE_5 can not have ECDSA_KEY " "key due to a hardware bug (please see TRM for more details)", @@ -2054,7 +2129,7 @@ def test_burn_ecdsa_key_purpose(self): def test_burn_xts_aes_key(self): self.espefuse_py( - f"burn_key \ + f"burn-key \ BLOCK_KEY5 {IMAGES_DIR}/256bit XTS_AES_128_KEY", check_msg="A fatal error occurred: " "KEY_PURPOSE_5 can not have XTS_AES_128_KEY " @@ -2067,7 +2142,7 @@ def test_burn_xts_aes_key(self): ) def test_burn_ecdsa_key(self): self.espefuse_py( - f"burn_key \ + f"burn-key \ BLOCK_KEY5 {S_IMAGES_DIR}/ecdsa192_secure_boot_signing_key_v2.pem \ ECDSA_KEY", check_msg="A fatal error occurred: " @@ -2081,24 +2156,24 @@ class TestPostponedEfuses(EfuseTestCase): def test_postpone_efuses(self): if arg_chip == "esp32": cmd = f"--postpone \ - burn_efuse UART_DOWNLOAD_DIS 1 \ - burn_key BLOCK1 {IMAGES_DIR}/256bit \ - burn_efuse ABS_DONE_1 1 FLASH_CRYPT_CNT 1" + burn-efuse UART_DOWNLOAD_DIS 1 \ + burn-key BLOCK1 {IMAGES_DIR}/256bit \ + burn-efuse ABS_DONE_1 1 FLASH_CRYPT_CNT 1" num = 1 else: sb_digest_name = ( "SECURE_BOOT_DIGEST" if arg_chip == "esp32c2" else "SECURE_BOOT_DIGEST0" ) cmd = f"--postpone \ - burn_efuse ENABLE_SECURITY_DOWNLOAD 1 DIS_DOWNLOAD_MODE 1 \ + burn-efuse ENABLE_SECURITY_DOWNLOAD 1 DIS_DOWNLOAD_MODE 1 \ SECURE_VERSION 1 \ - burn_key BLOCK_KEY0 {IMAGES_DIR}/256bit {sb_digest_name} \ - burn_efuse SPI_BOOT_CRYPT_CNT 1 SECURE_BOOT_EN 1" + burn-key BLOCK_KEY0 {IMAGES_DIR}/256bit {sb_digest_name} \ + burn-efuse SPI_BOOT_CRYPT_CNT 1 SECURE_BOOT_EN 1" num = 3 if arg_chip == "esp32c2" else 4 output = self.espefuse_py(cmd) assert f"BURN BLOCK{num} - OK" in output assert "BURN BLOCK0 - OK" in output - assert "Burn postponed efuses from BLOCK0" in output + assert "Burn postponed eFuses from BLOCK0" in output assert "BURN BLOCK0 - OK" in output assert "Successful" in output @@ -2118,7 +2193,7 @@ def test_extend_efuse_table_with_csv_file(self): assert "ID_NUMK_1 (BLOCK3)" in output self.espefuse_py( - f"--extend-efuse-table {csv_file} burn_efuse \ + f"--extend-efuse-table {csv_file} burn-efuse \ MODULE_VERSION 1 \ CUSTOM_SECURE_VERSION 4 \ SETTING_1_ALT_NAME 7 \ diff --git a/tools/esptool_py/test/test_espsecure.py b/tools/esptool_py/test/test_espsecure.py index 6fc2cb3197..d9e224afc5 100755 --- a/tools/esptool_py/test/test_espsecure.py +++ b/tools/esptool_py/test/test_espsecure.py @@ -1,4 +1,4 @@ -# Tests for espsecure.py using the pytest framework +# Tests for espsecure using the pytest framework # # Assumes openssl binary is in the PATH @@ -9,7 +9,6 @@ import subprocess import sys import tempfile -from collections import namedtuple from conftest import need_to_install_package_err @@ -28,10 +27,10 @@ class EspSecureTestCase: def run_espsecure(self, args): """ - Run espsecure.py with the specified arguments + Run espsecure with the specified arguments Returns output as a string if there is any, - raises an exception if espsecure.py fails + raises an exception if espsecure fails """ cmd = [sys.executable, "-m", "espsecure"] + args.split(" ") print("\nExecuting {}...".format(" ".join(cmd))) @@ -64,21 +63,16 @@ def _open(self, image_file): class TestESP32SecureBootloader(EspSecureTestCase): def test_digest_bootloader(self): - DBArgs = namedtuple( - "digest_bootloader_args", ["keyfile", "output", "iv", "image"] - ) - try: output_file = tempfile.NamedTemporaryFile(delete=False) output_file.close() - args = DBArgs( + espsecure.digest_secure_bootloader( self._open("256bit_key.bin"), output_file.name, self._open("256bit_iv.bin"), self._open("bootloader.bin"), ) - espsecure.digest_secure_bootloader(args) with open(output_file.name, "rb") as of: with self._open("bootloader_digested.bin") as ef: @@ -87,16 +81,19 @@ def test_digest_bootloader(self): os.unlink(output_file.name) def test_digest_rsa_public_key(self): - DigestRSAArgs = namedtuple("digest_rsa_public_key_args", ["keyfile", "output"]) - try: output_file = tempfile.NamedTemporaryFile(delete=False) output_file.close() - args = DigestRSAArgs( - self._open("rsa_secure_boot_signing_key.pem"), output_file.name + out = self.run_espsecure( + "digest-rsa-public-key --keyfile " + "secure_images/rsa_secure_boot_signing_key.pem " + f"-o {output_file.name}" + ) + assert ( + "DeprecationWarning: The command 'digest-rsa-public-key' is deprecated." + in out ) - espsecure.digest_rsa_public_key(args) with open(output_file.name, "rb") as of: with self._open("rsa_public_key_digest.bin") as ef: @@ -106,44 +103,19 @@ def test_digest_rsa_public_key(self): class TestSigning(EspSecureTestCase): - VerifyArgs = namedtuple( - "verify_signature_args", ["version", "hsm", "hsm_config", "keyfile", "datafile"] - ) - - SignArgs = namedtuple( - "sign_data_args", - [ - "version", - "keyfile", - "output", - "append_signatures", - "hsm", - "hsm_config", - "pub_key", - "signature", - "datafile", - ], - ) - - ExtractKeyArgs = namedtuple( - "extract_public_key_args", ["version", "keyfile", "public_keyfile"] - ) - - GenerateKeyArgs = namedtuple("generate_key_args", ["version", "scheme", "keyfile"]) - def test_key_generation_v1(self): with tempfile.TemporaryDirectory() as keydir: # keyfile cannot exist before generation -> tempfile.NamedTemporaryFile() # cannot be used for keyfile keyfile_name = os.path.join(keydir, "key.pem") - self.run_espsecure(f"generate_signing_key --version 1 {keyfile_name}") + self.run_espsecure(f"generate-signing-key --version 1 {keyfile_name}") def test_key_generation_v2(self): with tempfile.TemporaryDirectory() as keydir: # keyfile cannot exist before generation -> tempfile.NamedTemporaryFile() # cannot be used for keyfile keyfile_name = os.path.join(keydir, "key.pem") - self.run_espsecure(f"generate_signing_key --version 2 {keyfile_name}") + self.run_espsecure(f"generate-signing-key --version 2 {keyfile_name}") def _test_sign_v1_data(self, key_name): try: @@ -152,7 +124,7 @@ def _test_sign_v1_data(self, key_name): # Note: signing bootloader is not actually needed # for ESP32, it's just a handy file to sign - args = self.SignArgs( + espsecure.sign_data( "1", [self._open(key_name)], output_file.name, @@ -163,7 +135,6 @@ def _test_sign_v1_data(self, key_name): None, self._open("bootloader.bin"), ) - espsecure.sign_data(args) with open(output_file.name, "rb") as of: with self._open("bootloader_signed.bin") as ef: @@ -173,19 +144,19 @@ def _test_sign_v1_data(self, key_name): os.unlink(output_file.name) def test_sign_v1_data(self): - self._test_sign_v1_data("ecdsa_secure_boot_signing_key.pem") + self._test_sign_v1_data("ecdsa256_secure_boot_signing_key.pem") def test_sign_v1_data_pkcs8(self): - self._test_sign_v1_data("ecdsa_secure_boot_signing_key_pkcs8.pem") + self._test_sign_v1_data("ecdsa256_secure_boot_signing_key_pkcs8.pem") def test_sign_v1_with_pre_calculated_signature(self): # Sign using pre-calculated signature + Verify - signing_pubkey = "ecdsa_secure_boot_signing_pubkey.pem" + signing_pubkey = "ecdsa256_secure_boot_signing_pubkey.pem" pre_calculated_signature = "pre_calculated_bootloader_signature.bin" try: output_file = tempfile.NamedTemporaryFile(delete=False) - args = self.SignArgs( + espsecure.sign_data( "1", None, output_file.name, @@ -196,50 +167,41 @@ def test_sign_v1_with_pre_calculated_signature(self): [self._open(pre_calculated_signature)], self._open("bootloader.bin"), ) - espsecure.sign_data(args) - args = self.VerifyArgs( + espsecure.verify_signature( "1", False, None, self._open(signing_pubkey), output_file ) - espsecure.verify_signature(args) finally: output_file.close() os.unlink(output_file.name) - def test_sign_v2_data(self): - signing_keys = [ - "rsa_secure_boot_signing_key.pem", - "ecdsa192_secure_boot_signing_key.pem", - "ecdsa_secure_boot_signing_key.pem", - "ecdsa384_secure_boot_signing_key.pem", - ] - for key in signing_keys: - try: - output_file = tempfile.NamedTemporaryFile(delete=False) - args = self.SignArgs( - "2", - [self._open(key)], - output_file.name, - False, - False, - None, - None, - None, - self._open("bootloader_unsigned_v2.bin"), - ) - espsecure.sign_data(args) + @pytest.mark.parametrize("scheme", ["rsa", "ecdsa192", "ecdsa256", "ecdsa384"]) + def test_sign_v2_data(self, scheme): + key = f"{scheme}_secure_boot_signing_key.pem" + try: + output_file = tempfile.NamedTemporaryFile(delete=False) + espsecure.sign_data( + "2", + [self._open(key)], + output_file.name, + False, + False, + None, + None, + None, + self._open("bootloader_unsigned_v2.bin"), + ) - args = self.VerifyArgs("2", False, None, self._open(key), output_file) - espsecure.verify_signature(args) - finally: - output_file.close() - os.unlink(output_file.name) + espsecure.verify_signature("2", False, None, self._open(key), output_file) + finally: + output_file.close() + os.unlink(output_file.name) def test_sign_v2_multiple_keys(self): # 3 keys + Verify with 3rd key try: output_file = tempfile.NamedTemporaryFile(delete=False) - args = self.SignArgs( + espsecure.sign_data( "2", [ self._open("rsa_secure_boot_signing_key.pem"), @@ -254,46 +216,43 @@ def test_sign_v2_multiple_keys(self): None, self._open("bootloader_unsigned_v2.bin"), ) - espsecure.sign_data(args) - args = self.VerifyArgs( + espsecure.verify_signature( "2", False, None, self._open("rsa_secure_boot_signing_key3.pem"), output_file, ) - espsecure.verify_signature(args) output_file.seek(0) - args = self.VerifyArgs( + espsecure.verify_signature( "2", False, None, self._open("rsa_secure_boot_signing_key2.pem"), output_file, ) - espsecure.verify_signature(args) output_file.seek(0) - args = self.VerifyArgs( + espsecure.verify_signature( "2", False, None, self._open("rsa_secure_boot_signing_key.pem"), output_file, ) - espsecure.verify_signature(args) finally: output_file.close() os.unlink(output_file.name) def test_sign_v2_append_signatures(self): # Append signatures + Verify with an appended key - # (bootloader_signed_v2.bin already signed with rsa_secure_boot_signing_key.pem) + # (bootloader_signed_v2_rsa.bin already signed with + # rsa_secure_boot_signing_key.pem) try: output_file = tempfile.NamedTemporaryFile(delete=False) - args = self.SignArgs( + espsecure.sign_data( "2", [ self._open("rsa_secure_boot_signing_key2.pem"), @@ -305,38 +264,34 @@ def test_sign_v2_append_signatures(self): None, None, None, - self._open("bootloader_signed_v2.bin"), + self._open("bootloader_signed_v2_rsa.bin"), ) - espsecure.sign_data(args) - args = self.VerifyArgs( + espsecure.verify_signature( "2", False, None, self._open("rsa_secure_boot_signing_key.pem"), output_file, ) - espsecure.verify_signature(args) output_file.seek(0) - args = self.VerifyArgs( + espsecure.verify_signature( "2", False, None, self._open("rsa_secure_boot_signing_key2.pem"), output_file, ) - espsecure.verify_signature(args) output_file.seek(0) - args = self.VerifyArgs( + espsecure.verify_signature( "2", False, None, self._open("rsa_secure_boot_signing_key3.pem"), output_file, ) - espsecure.verify_signature(args) finally: output_file.close() os.unlink(output_file.name) @@ -346,7 +301,7 @@ def test_sign_v2_append_signatures_multiple_steps(self): try: output_file1 = tempfile.NamedTemporaryFile(delete=False) output_file2 = tempfile.NamedTemporaryFile(delete=False) - args = self.SignArgs( + espsecure.sign_data( "2", [self._open("rsa_secure_boot_signing_key2.pem")], output_file1.name, @@ -355,11 +310,10 @@ def test_sign_v2_append_signatures_multiple_steps(self): None, None, None, - self._open("bootloader_signed_v2.bin"), + self._open("bootloader_signed_v2_rsa.bin"), ) - espsecure.sign_data(args) - args = self.SignArgs( + espsecure.sign_data( "2", [self._open("rsa_secure_boot_signing_key3.pem")], output_file2.name, @@ -370,79 +324,63 @@ def test_sign_v2_append_signatures_multiple_steps(self): None, output_file1, ) - espsecure.sign_data(args) - args = self.VerifyArgs( + espsecure.verify_signature( "2", False, None, self._open("rsa_secure_boot_signing_key.pem"), output_file2, ) - espsecure.verify_signature(args) output_file2.seek(0) - args = self.VerifyArgs( + espsecure.verify_signature( "2", False, None, self._open("rsa_secure_boot_signing_key2.pem"), output_file2, ) - espsecure.verify_signature(args) output_file2.seek(0) - args = self.VerifyArgs( + espsecure.verify_signature( "2", False, None, self._open("rsa_secure_boot_signing_key3.pem"), output_file2, ) - espsecure.verify_signature(args) finally: output_file1.close() os.unlink(output_file1.name) output_file2.close() os.unlink(output_file2.name) - def test_sign_v2_with_pre_calculated_signature(self): + @pytest.mark.parametrize("scheme", ["rsa", "ecdsa192", "ecdsa256", "ecdsa384"]) + def test_sign_v2_with_pre_calculated_signature(self, scheme): # Sign using pre-calculated signature + Verify - signing_keys = [ - "rsa_secure_boot_signing_pubkey.pem", - "ecdsa192_secure_boot_signing_pubkey.pem", - "ecdsa_secure_boot_signing_pubkey.pem", - "ecdsa384_secure_boot_signing_pubkey.pem", - ] - pre_calculated_signatures = [ - "pre_calculated_bootloader_signature_rsa.bin", - "pre_calculated_bootloader_signature_ecdsa192.bin", - "pre_calculated_bootloader_signature_ecdsa256.bin", - "pre_calculated_bootloader_signature_ecdsa384.bin", - ] - for pub_key, signature in zip(signing_keys, pre_calculated_signatures): - try: - output_file = tempfile.NamedTemporaryFile(delete=False) - args = self.SignArgs( - "2", - None, - output_file.name, - False, - False, - None, - [self._open(pub_key)], - [self._open(signature)], - self._open("bootloader_unsigned_v2.bin"), - ) - espsecure.sign_data(args) + pub_key = f"{scheme}_secure_boot_signing_pubkey.pem" + signature = f"pre_calculated_bootloader_signature_{scheme}.bin" + try: + output_file = tempfile.NamedTemporaryFile(delete=False) + espsecure.sign_data( + "2", + None, + output_file.name, + False, + False, + None, + [self._open(pub_key)], + [self._open(signature)], + self._open("bootloader_unsigned_v2.bin"), + ) - args = self.VerifyArgs( - "2", False, None, self._open(pub_key), output_file - ) - espsecure.verify_signature(args) - finally: - output_file.close() - os.unlink(output_file.name) + espsecure.verify_signature( + "2", False, None, self._open(pub_key), output_file + ) + finally: + output_file.close() + os.unlink(output_file.name) def test_sign_v2_with_multiple_pre_calculated_signatures(self): # Sign using multiple pre-calculated signatures + Verify @@ -458,7 +396,7 @@ def test_sign_v2_with_multiple_pre_calculated_signatures(self): ] try: output_file = tempfile.NamedTemporaryFile(delete=False) - args = self.SignArgs( + espsecure.sign_data( "2", None, output_file.name, @@ -469,349 +407,214 @@ def test_sign_v2_with_multiple_pre_calculated_signatures(self): [self._open(signature) for signature in pre_calculated_signatures], self._open("bootloader_unsigned_v2.bin"), ) - espsecure.sign_data(args) - args = self.VerifyArgs( + espsecure.verify_signature( "2", False, None, self._open(signing_pubkeys[0]), output_file ) - espsecure.verify_signature(args) finally: output_file.close() os.unlink(output_file.name) - def test_verify_signature_signing_key(self): - # correct key v1 - args = self.VerifyArgs( - "1", - False, - None, - self._open("ecdsa_secure_boot_signing_key.pem"), - self._open("bootloader_signed.bin"), - ) - espsecure.verify_signature(args) - - # correct key v2 - args = self.VerifyArgs( - "2", - False, - None, - self._open("rsa_secure_boot_signing_key.pem"), - self._open("bootloader_signed_v2.bin"), - ) - espsecure.verify_signature(args) - - # correct key v2 (ecdsa384) - args = self.VerifyArgs( - "2", - False, - None, - self._open("ecdsa384_secure_boot_signing_key.pem"), - self._open("bootloader_signed_v2_ecdsa384.bin"), - ) - espsecure.verify_signature(args) - - # correct key v2 (ecdsa256) - args = self.VerifyArgs( - "2", - False, - None, - self._open("ecdsa_secure_boot_signing_key.pem"), - self._open("bootloader_signed_v2_ecdsa256.bin"), - ) - espsecure.verify_signature(args) - - # correct key v2 (ecdsa192) - args = self.VerifyArgs( - "2", + @pytest.mark.parametrize( + "version, keyfile, datafile", + [ + ("1", "ecdsa256_secure_boot_signing_key.pem", "bootloader_signed.bin"), + ( + "1", + "ecdsa256_secure_boot_signing_pubkey_raw.bin", + "bootloader_signed.bin", + ), + ("2", "rsa_secure_boot_signing_key.pem", "bootloader_signed_v2_rsa.bin"), + ( + "2", + "ecdsa384_secure_boot_signing_key.pem", + "bootloader_signed_v2_ecdsa384.bin", + ), + ( + "2", + "ecdsa256_secure_boot_signing_key.pem", + "bootloader_signed_v2_ecdsa256.bin", + ), + ( + "2", + "ecdsa192_secure_boot_signing_key.pem", + "bootloader_signed_v2_ecdsa192.bin", + ), + ], + ids=[ + "v1_pem", + "v1_raw", + "v2_rsa", + "v2_ecdsa384", + "v2_ecdsa256", + "v2_ecdsa192", + ], + ) + def test_verify_signature_correct_key(self, version, keyfile, datafile): + espsecure.verify_signature( + version, False, None, - self._open("ecdsa192_secure_boot_signing_key.pem"), - self._open("bootloader_signed_v2_ecdsa192.bin"), + self._open(keyfile), + self._open(datafile), ) - espsecure.verify_signature(args) - # wrong key v1 - args = self.VerifyArgs( - "1", - False, - None, - self._open("ecdsa_secure_boot_signing_key2.pem"), - self._open("bootloader_signed.bin"), - ) + def test_verify_signature_wrong_key_v1(self): with pytest.raises(esptool.FatalError) as cm: - espsecure.verify_signature(args) + espsecure.verify_signature( + "1", + False, + None, + self._open("ecdsa256_secure_boot_signing_key2.pem"), + self._open("bootloader_signed.bin"), + ) assert "Signature is not valid" in str(cm.value) - # wrong key v2 - args = self.VerifyArgs( - "2", - False, - None, - self._open("rsa_secure_boot_signing_key2.pem"), - self._open("bootloader_signed_v2.bin"), - ) + @pytest.mark.parametrize("scheme", ["rsa", "ecdsa192", "ecdsa256", "ecdsa384"]) + def test_verify_signature_wrong_key_v2(self, scheme): with pytest.raises(esptool.FatalError) as cm: - espsecure.verify_signature(args) + espsecure.verify_signature( + "2", + False, + None, + self._open(f"{scheme}_secure_boot_signing_key2.pem"), + self._open(f"bootloader_signed_v2_{scheme}.bin"), + ) assert "Signature could not be verified with the provided key." in str(cm.value) - # right key, wrong scheme (ecdsa256, v2) - args = self.VerifyArgs( - "2", - False, - None, - self._open("ecdsa_secure_boot_signing_key.pem"), - self._open("bootloader_signed.bin"), - ) + def test_verify_signature_wrong_scheme(self): with pytest.raises(esptool.FatalError) as cm: - espsecure.verify_signature(args) + espsecure.verify_signature( + "2", + False, + None, + self._open("ecdsa256_secure_boot_signing_key.pem"), + self._open("bootloader_signed.bin"), + ) assert "Invalid datafile" in str(cm.value) - # wrong key v2 (ecdsa384) - args = self.VerifyArgs( - "2", - False, - None, - self._open("ecdsa384_secure_boot_signing_key2.pem"), - self._open("bootloader_signed_v2_ecdsa384.bin"), - ) + def test_verify_signature_multi_signed_wrong_key(self): with pytest.raises(esptool.FatalError) as cm: - espsecure.verify_signature(args) - assert "Signature could not be verified with the provided key." in str(cm.value) - - # wrong key v2 (ecdsa256) - args = self.VerifyArgs( - "2", - False, - None, - self._open("ecdsa_secure_boot_signing_key2.pem"), - self._open("bootloader_signed_v2_ecdsa256.bin"), - ) - with pytest.raises(esptool.FatalError) as cm: - espsecure.verify_signature(args) + espsecure.verify_signature( + "2", + False, + None, + self._open("rsa_secure_boot_signing_key4.pem"), + self._open("bootloader_multi_signed_v2.bin"), + ) assert "Signature could not be verified with the provided key." in str(cm.value) - # wrong key v2 (ecdsa192) - args = self.VerifyArgs( - "2", + @pytest.mark.parametrize( + "version, keyfile, datafile", + [ + ("1", "ecdsa256_secure_boot_signing_pubkey.pem", "bootloader_signed.bin"), + ("2", "rsa_secure_boot_signing_pubkey.pem", "bootloader_signed_v2_rsa.bin"), + ( + "2", + "ecdsa384_secure_boot_signing_pubkey.pem", + "bootloader_signed_v2_ecdsa384.bin", + ), + ( + "2", + "ecdsa256_secure_boot_signing_pubkey.pem", + "bootloader_signed_v2_ecdsa256.bin", + ), + ( + "2", + "ecdsa192_secure_boot_signing_pubkey.pem", + "bootloader_signed_v2_ecdsa192.bin", + ), + ], + ids=["v1", "v2_rsa", "v2_ecdsa384", "v2_ecdsa256", "v2_ecdsa192"], + ) + def test_verify_signature_correct_pubkey(self, version, keyfile, datafile): + espsecure.verify_signature( + version, False, None, - self._open("ecdsa192_secure_boot_signing_key2.pem"), - self._open("bootloader_signed_v2_ecdsa192.bin"), + self._open(keyfile), + self._open(datafile), ) - with pytest.raises(esptool.FatalError) as cm: - espsecure.verify_signature(args) - assert "Signature could not be verified with the provided key." in str(cm.value) - # multi-signed wrong key v2 - args = self.VerifyArgs( - "2", - False, - None, - self._open("rsa_secure_boot_signing_key4.pem"), - self._open("bootloader_multi_signed_v2.bin"), - ) + def test_verify_signature_wrong_pubkey_v1(self): with pytest.raises(esptool.FatalError) as cm: - espsecure.verify_signature(args) - assert "Signature could not be verified with the provided key." in str(cm.value) - - def test_verify_signature_public_key(self): - # correct key v1 - args = self.VerifyArgs( - "1", - False, - None, - self._open("ecdsa_secure_boot_signing_pubkey.pem"), - self._open("bootloader_signed.bin"), - ) - espsecure.verify_signature(args) - - # correct key v2 - args = self.VerifyArgs( - "2", - False, - None, - self._open("rsa_secure_boot_signing_pubkey.pem"), - self._open("bootloader_signed_v2.bin"), - ) - espsecure.verify_signature(args) - - # correct key v2 (ecdsa384) - args = self.VerifyArgs( - "2", - False, - None, - self._open("ecdsa384_secure_boot_signing_pubkey.pem"), - self._open("bootloader_signed_v2_ecdsa384.bin"), - ) - espsecure.verify_signature(args) - - # correct key v2 (ecdsa256) - args = self.VerifyArgs( - "2", - False, - None, - self._open("ecdsa_secure_boot_signing_pubkey.pem"), - self._open("bootloader_signed_v2_ecdsa256.bin"), - ) - espsecure.verify_signature(args) - - # correct key v2 (ecdsa192) - args = self.VerifyArgs( - "2", - False, - None, - self._open("ecdsa192_secure_boot_signing_pubkey.pem"), - self._open("bootloader_signed_v2_ecdsa192.bin"), - ) - espsecure.verify_signature(args) - - # wrong key v1 - args = self.VerifyArgs( - "1", - False, - None, - self._open("ecdsa_secure_boot_signing_pubkey2.pem"), - self._open("bootloader_signed.bin"), - ) - with pytest.raises(esptool.FatalError) as cm: - espsecure.verify_signature(args) + espsecure.verify_signature( + "1", + False, + None, + self._open("ecdsa256_secure_boot_signing_pubkey2.pem"), + self._open("bootloader_signed.bin"), + ) assert "Signature is not valid" in str(cm.value) - # wrong key v2 - args = self.VerifyArgs( - "2", - False, - None, - self._open("rsa_secure_boot_signing_pubkey2.pem"), - self._open("bootloader_signed_v2.bin"), - ) + @pytest.mark.parametrize("scheme", ["rsa", "ecdsa192", "ecdsa256", "ecdsa384"]) + def test_verify_signature_wrong_pubkey_v2(self, scheme): with pytest.raises(esptool.FatalError) as cm: - espsecure.verify_signature(args) - assert "Signature could not be verified with the provided key." in str(cm.value) - - # wrong key v2 (ecdsa384) - args = self.VerifyArgs( - "2", - False, - None, - self._open("ecdsa384_secure_boot_signing_pubkey2.pem"), - self._open("bootloader_signed_v2_ecdsa384.bin"), - ) - with pytest.raises(esptool.FatalError) as cm: - espsecure.verify_signature(args) - assert "Signature could not be verified with the provided key." in str(cm.value) - - # wrong key v2 (ecdsa256) - args = self.VerifyArgs( - "2", - False, - None, - self._open("ecdsa_secure_boot_signing_pubkey2.pem"), - self._open("bootloader_signed_v2_ecdsa256.bin"), - ) - with pytest.raises(esptool.FatalError) as cm: - espsecure.verify_signature(args) - assert "Signature could not be verified with the provided key." in str(cm.value) - - # wrong key v2 (ecdsa192) - args = self.VerifyArgs( - "2", - False, - None, - self._open("ecdsa192_secure_boot_signing_pubkey2.pem"), - self._open("bootloader_signed_v2_ecdsa192.bin"), - ) - with pytest.raises(esptool.FatalError) as cm: - espsecure.verify_signature(args) + espsecure.verify_signature( + "2", + False, + None, + self._open(f"{scheme}_secure_boot_signing_pubkey2.pem"), + self._open(f"bootloader_signed_v2_{scheme}.bin"), + ) assert "Signature could not be verified with the provided key." in str(cm.value) - # multi-signed wrong key v2 - args = self.VerifyArgs( - "2", - False, - None, - self._open("rsa_secure_boot_signing_pubkey4.pem"), - self._open("bootloader_multi_signed_v2.bin"), - ) + def test_verify_signature_multi_signed_wrong_pubkey(self): with pytest.raises(esptool.FatalError) as cm: - espsecure.verify_signature(args) + espsecure.verify_signature( + "2", + False, + None, + self._open("rsa_secure_boot_signing_pubkey4.pem"), + self._open("bootloader_multi_signed_v2.bin"), + ) assert "Signature could not be verified with the provided key." in str(cm.value) def test_extract_binary_public_key(self): - with tempfile.NamedTemporaryFile() as pub_keyfile, tempfile.NamedTemporaryFile() as pub_keyfile2: # noqa E501 - args = self.ExtractKeyArgs( - "1", self._open("ecdsa_secure_boot_signing_key.pem"), pub_keyfile + with ( + tempfile.NamedTemporaryFile() as pub_keyfile, + tempfile.NamedTemporaryFile() as pub_keyfile2, + ): + espsecure.extract_public_key( + "1", self._open("ecdsa256_secure_boot_signing_key.pem"), pub_keyfile ) - espsecure.extract_public_key(args) - args = self.ExtractKeyArgs( - "1", self._open("ecdsa_secure_boot_signing_key2.pem"), pub_keyfile2 + espsecure.extract_public_key( + "1", self._open("ecdsa256_secure_boot_signing_key2.pem"), pub_keyfile2 ) - espsecure.extract_public_key(args) pub_keyfile.seek(0) pub_keyfile2.seek(0) # use correct extracted public key to verify - args = self.VerifyArgs( + espsecure.verify_signature( "1", False, None, pub_keyfile, self._open("bootloader_signed.bin") ) - espsecure.verify_signature(args) # use wrong extracted public key to try and verify - args = self.VerifyArgs( - "1", False, None, pub_keyfile2, self._open("bootloader_signed.bin") - ) with pytest.raises(esptool.FatalError) as cm: - espsecure.verify_signature(args) + espsecure.verify_signature( + "1", False, None, pub_keyfile2, self._open("bootloader_signed.bin") + ) assert "Signature is not valid" in str(cm.value) - def test_generate_and_extract_key_v2(self): + @pytest.mark.parametrize("scheme", ["rsa3072", "ecdsa192", "ecdsa256", "ecdsa384"]) + def test_generate_and_extract_key_v2(self, scheme): with tempfile.TemporaryDirectory() as keydir: # keyfile cannot exist before generation -> tempfile.NamedTemporaryFile() # cannot be used for keyfile keyfile_name = os.path.join(keydir, "key.pem") - # We need to manually delete the keyfile as we are iterating over - # different schemes with the same keyfile so instead of using addCleanup, - # we remove it using os.remove at the end of each pass - for scheme in ["rsa3072", "ecdsa192", "ecdsa256", "ecdsa384"]: - args = self.GenerateKeyArgs("2", scheme, keyfile_name) - espsecure.generate_signing_key(args) + espsecure.generate_signing_key("2", scheme, keyfile_name) - with tempfile.NamedTemporaryFile() as pub_keyfile, open( - keyfile_name, "rb" - ) as keyfile: - args = self.ExtractKeyArgs("2", keyfile, pub_keyfile) - espsecure.extract_public_key(args) - os.remove(keyfile_name) + with ( + tempfile.NamedTemporaryFile() as pub_keyfile, + open(keyfile_name, "rb") as keyfile, + ): + espsecure.extract_public_key("2", keyfile, pub_keyfile) class TestFlashEncryption(EspSecureTestCase): - EncryptArgs = namedtuple( - "encrypt_flash_data_args", - [ - "keyfile", - "output", - "address", - "flash_crypt_conf", - "aes_xts", - "plaintext_file", - ], - ) - - DecryptArgs = namedtuple( - "decrypt_flash_data_args", - [ - "keyfile", - "output", - "address", - "flash_crypt_conf", - "aes_xts", - "encrypted_file", - ], - ) - def _test_encrypt_decrypt( self, input_plaintext, @@ -825,10 +628,9 @@ def _test_encrypt_decrypt( keyfile = self._open(key_path) ciphertext = io.BytesIO() - args = self.EncryptArgs( + espsecure.encrypt_flash_data( keyfile, ciphertext, offset, flash_crypt_conf, aes_xts, original_plaintext ) - espsecure.encrypt_flash_data(args) original_plaintext.seek(0) assert original_plaintext.read() != ciphertext.getvalue() @@ -838,10 +640,9 @@ def _test_encrypt_decrypt( ciphertext.seek(0) keyfile.seek(0) plaintext = io.BytesIO() - args = self.DecryptArgs( + espsecure.decrypt_flash_data( keyfile, plaintext, offset, flash_crypt_conf, aes_xts, ciphertext ) - espsecure.decrypt_flash_data(args) original_plaintext.seek(0) assert original_plaintext.read() == plaintext.getvalue() @@ -929,12 +730,10 @@ def test_padding(self): keyfile = self._open("256bit_key.bin") address = 0x1000 - encrypt_args_padded = self.EncryptArgs( + espsecure.encrypt_flash_data( keyfile, ciphertext_full_block, address, None, "aes_xts", plaintext_file ) - espsecure.encrypt_flash_data(encrypt_args_padded) - # Test with different number of bytes per encryption call # Final ciphertext should still be the same if padding is done correctly bytes_per_encrypt = [16, 32, 64, 128] @@ -950,7 +749,7 @@ def test_padding(self): # encrypt the whole plaintext a substring of b bytes at a time plaintext_sub = io.BytesIO(plaintext[offset : offset + b]) - encrypt_args = self.EncryptArgs( + espsecure.encrypt_flash_data( keyfile, ciphertext, address + offset, @@ -959,8 +758,6 @@ def test_padding(self): plaintext_sub, ) - espsecure.encrypt_flash_data(encrypt_args) - assert ciphertext_full_block.getvalue() == ciphertext.getvalue() @@ -970,8 +767,8 @@ def test_digest_private_key(self): outfile_name = f.name self.run_espsecure( - "digest_private_key " - "--keyfile secure_images/ecdsa_secure_boot_signing_key.pem " + "digest-private-key " + "--keyfile secure_images/ecdsa256_secure_boot_signing_key.pem " f"{outfile_name}" ) @@ -981,9 +778,9 @@ def test_digest_private_key(self): ) def test_digest_private_key_with_invalid_output(self, capsys): - fname = "secure_images/ecdsa_secure_boot_signing_key.pem" + fname = "secure_images/ecdsa256_secure_boot_signing_key.pem" with pytest.raises(subprocess.CalledProcessError): - self.run_espsecure(f"digest_private_key --keyfile {fname} {fname}") + self.run_espsecure(f"digest-private-key --keyfile {fname} {fname}") output = capsys.readouterr().out assert "should not be the same!" in output diff --git a/tools/esptool_py/test/test_espsecure_hsm.py b/tools/esptool_py/test/test_espsecure_hsm.py index 1f8c52672a..7b80e97151 100644 --- a/tools/esptool_py/test/test_espsecure_hsm.py +++ b/tools/esptool_py/test/test_espsecure_hsm.py @@ -1,4 +1,4 @@ -# Tests for espsecure.py (esp_hsm_sign.py) using the pytest framework +# Tests for espsecure (esp_hsm_sign.py) using the pytest framework # # Assumes openssl binary is in the PATH @@ -7,7 +7,6 @@ import os.path import sys import tempfile -from collections import namedtuple from conftest import need_to_install_package_err @@ -127,123 +126,121 @@ def softhsm_setup_token(self, filename, token_label): class TestSigning(EspSecureHSMTestCase): - VerifyArgs = namedtuple( - "verify_signature_args", ["version", "hsm", "hsm_config", "keyfile", "datafile"] - ) - - SignArgs = namedtuple( - "sign_data_args", - [ - "version", - "keyfile", - "output", - "append_signatures", - "hsm", - "hsm_config", - "pub_key", - "signature", - "datafile", - ], - ) - def test_sign_v2_hsm(self): # Sign using SoftHSMv2 + Verify self.softhsm_setup_token("softhsm_v2.ini", "softhsm-test-token") - with tempfile.NamedTemporaryFile() as output_file: - args = self.SignArgs( + with ( + tempfile.NamedTemporaryFile() as output_file, + open( + os.path.join(TEST_DIR, "secure_images", "softhsm_v2.ini"), "r" + ) as config_file, + ): + espsecure.sign_data( "2", None, output_file.name, False, True, - os.path.join(TEST_DIR, "secure_images", "softhsm_v2.ini"), - None, - None, + config_file, + [], + [], self._open("bootloader_unsigned_v2.bin"), ) - espsecure.sign_data(args) - - args = self.VerifyArgs( + config_file.seek(0) + espsecure.verify_signature( "2", True, - os.path.join(TEST_DIR, "secure_images", "softhsm_v2.ini"), + config_file, None, output_file, ) - espsecure.verify_signature(args) def test_sign_v2_hsm_append_signatures_multiple_steps(self): # Append signatures using HSM + Verify with an appended key self.softhsm_setup_token("softhsm_v2_1.ini", "softhsm-test-token-1") - with tempfile.NamedTemporaryFile() as output_file1: - args = self.SignArgs( + with ( + tempfile.NamedTemporaryFile() as output_file1, + open( + os.path.join(TEST_DIR, "secure_images", "softhsm_v2_1.ini"), "r" + ) as config_file1, + ): + espsecure.sign_data( "2", None, output_file1.name, True, True, - os.path.join(TEST_DIR, "secure_images", "softhsm_v2_1.ini"), - None, - None, + config_file1, + [], + [], self._open("bootloader_unsigned_v2.bin"), ) - espsecure.sign_data(args) self.softhsm_setup_token("softhsm_v2_2.ini", "softhsm-test-token-2") - with tempfile.NamedTemporaryFile() as output_file2: - args = self.SignArgs( + with ( + tempfile.NamedTemporaryFile() as output_file2, + open( + os.path.join(TEST_DIR, "secure_images", "softhsm_v2_2.ini"), "r" + ) as config_file2, + ): + espsecure.sign_data( "2", None, output_file2.name, True, True, - os.path.join(TEST_DIR, "secure_images", "softhsm_v2_2.ini"), - None, - None, + config_file2, + [], + [], self._open(output_file1.name), ) - espsecure.sign_data(args) self.softhsm_setup_token("softhsm_v2_3.ini", "softhsm-test-token-3") - with tempfile.NamedTemporaryFile() as output_file3: - args = self.SignArgs( + with ( + tempfile.NamedTemporaryFile() as output_file3, + open( + os.path.join(TEST_DIR, "secure_images", "softhsm_v2_3.ini"), + "r", + ) as config_file3, + ): + espsecure.sign_data( "2", None, output_file3.name, True, True, - os.path.join(TEST_DIR, "secure_images", "softhsm_v2_3.ini"), - None, - None, + config_file3, + [], + [], self._open(output_file2.name), ) - espsecure.sign_data(args) - args = self.VerifyArgs( + config_file1.seek(0) + config_file2.seek(0) + config_file3.seek(0) + + espsecure.verify_signature( "2", True, - os.path.join(TEST_DIR, "secure_images", "softhsm_v2_1.ini"), + config_file1, None, output_file3, ) - espsecure.verify_signature(args) output_file3.seek(0) - args = self.VerifyArgs( + espsecure.verify_signature( "2", True, - os.path.join(TEST_DIR, "secure_images", "softhsm_v2_2.ini"), + config_file2, None, output_file3, ) - espsecure.verify_signature(args) output_file3.seek(0) - args = self.VerifyArgs( + espsecure.verify_signature( "2", True, - os.path.join(TEST_DIR, "secure_images", "softhsm_v2_3.ini"), + config_file3, None, output_file3, ) - espsecure.verify_signature(args) diff --git a/tools/esptool_py/test/test_esptool.py b/tools/esptool_py/test/test_esptool.py index 9928b6f813..9ab1f70c6c 100755 --- a/tools/esptool_py/test/test_esptool.py +++ b/tools/esptool_py/test/test_esptool.py @@ -1,4 +1,4 @@ -# Unit tests (really integration tests) for esptool.py using the pytest framework +# Unit tests (really integration tests) for esptool using the pytest framework # Uses a device connected to the serial port. # # RUNNING THIS WILL MESS UP THE DEVICE'S SPI FLASH CONTENTS @@ -8,10 +8,17 @@ # Run with a physical connection to a chip: # - `pytest test_esptool.py --chip esp32 --port /dev/ttyUSB0 --baud 115200` # -# where - --port - a serial port for esptool.py operation +# where - --port - a serial port for esptool operation # - --chip - ESP chip name # - --baud - baud rate # - --with-trace - trace all interactions (True or False) +# +# To run the tests in USB-OTG mode, ground the boot mode straping pin +# and set ESPTOOL_TEST_USB_OTG environment variable to any value. +# +# To run the tests in USB-Serial/JTAG mode, set both --port and --preload-port +# options. The --preload-port needs to be connected to a USB-to-UART bridge, +# while --port needs to be connected to the USB-Serial/JTAG peripheral. import os import os.path @@ -21,11 +28,11 @@ import subprocess import sys import tempfile -import time +from io import StringIO from socket import AF_INET, SOCK_STREAM, socket from time import sleep -from typing import List from unittest.mock import MagicMock +from unittest.mock import patch # Link command line options --port, --chip, --baud, --with-trace, and --preload-port from conftest import ( @@ -43,6 +50,21 @@ try: import esptool import espefuse + from esptool.cmds import ( + detect_chip, + erase_flash, + attach_flash, + flash_id, + image_info, + merge_bin, + read_flash_sfdp, + read_flash, + read_mac, + reset_chip, + verify_flash, + version, + write_flash, + ) except ImportError: need_to_install_package_err() @@ -51,10 +73,7 @@ TEST_DIR = os.path.abspath(os.path.dirname(__file__)) -# esptool.py skips strapping mode check in USB-CDC case if this is set -os.environ["ESPTOOL_TESTING"] = "1" - -print("Running esptool.py tests...") +print("Running esptool tests...") class ESPRFC2217Server(object): @@ -64,7 +83,7 @@ def __init__(self, rfc2217_port=None): self.port = rfc2217_port or self.get_free_port() self.cmd = [ sys.executable, - os.path.join(TEST_DIR, "..", "esp_rfc2217_server.py"), + os.path.join(TEST_DIR, "..", "esp_rfc2217_server"), "-p", str(self.port), arg_port, @@ -145,8 +164,8 @@ def run_esptool(self, args, baud=None, chip=None, port=None, preload=True): This is needed in USB-JTAG/Serial mode to disable the RTC watchdog, which causes the port to periodically disappear. - Returns output from esptool.py as a string if there is any. - Raises an exception if esptool.py fails. + Returns output from esptool as a string if there is any. + Raises an exception if esptool fails. """ def run_esptool_process(cmd): @@ -176,8 +195,13 @@ def run_esptool_process(cmd): base_cmd += ["--port", port or arg_port] if baud or arg_baud is not None: base_cmd += ["--baud", str(baud or arg_baud)] - usb_jtag_serial_reset = ["--before", "usb_reset"] if arg_preload_port else [] - full_cmd = base_cmd + usb_jtag_serial_reset + args.split(" ") + usb_jtag_serial_reset = ["--before", "usb-reset"] if arg_preload_port else [] + usb_otg_dont_reset = ( + ["--after", "no-reset-stub"] if "ESPTOOL_TEST_USB_OTG" in os.environ else [] + ) + full_cmd = ( + base_cmd + usb_jtag_serial_reset + usb_otg_dont_reset + args.split(" ") + ) # Preload a dummy binary to disable the RTC watchdog, needed in USB-JTAG/Serial if ( @@ -198,26 +222,30 @@ def run_esptool_process(cmd): base_cmd[port_index] = arg_preload_port # Set the port to the preload one preload_cmd = base_cmd + [ "--no-stub", - "load_ram", + "load-ram", f"{TEST_DIR}/images/ram_helloworld/helloworld-{arg_chip}.bin", ] print("\nPreloading dummy binary to disable RTC watchdog...") run_esptool_process(preload_cmd) print("Dummy binary preloaded successfully.") - time.sleep(0.3) # Wait for the app to run and port to appear + sleep(0.3) # Wait for the app to run and port to appear # Run the command print(f'\nRunning the "{args}" command...') output = run_esptool_process(full_cmd) print(output) # for more complete stdout logs on failure + + if "ESPTOOL_TEST_USB_OTG" in os.environ: + sleep(0.5) # Wait for the port to enumerate between tests + return output def run_esptool_error(self, args, baud=None, chip=None): """ - Run esptool.py similar to run_esptool, but expect an error. + Run esptool similar to run_esptool, but expect an error. Verifies the error is an expected error not an unhandled exception, - and returns the output from esptool.py as a string. + and returns the output from esptool as a string. """ with pytest.raises(subprocess.CalledProcessError) as fail: self.run_esptool(args, baud, chip) @@ -243,7 +271,7 @@ def readback(self, offset, length, spi_connection=None): dump_file = tempfile.NamedTemporaryFile(delete=False) # a file we can read into try: cmd = ( - f"--before default_reset read_flash {offset} {length} {dump_file.name}" + f"--before default-reset read-flash {offset} {length} {dump_file.name}" ) if spi_connection: cmd += f" --spi-connection {spi_connection}" @@ -251,9 +279,10 @@ def readback(self, offset, length, spi_connection=None): 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!" + rb_len = len(rb) + assert length == rb_len, ( + f"read-flash length {length} offset {offset:#x} yielded {rb_len} bytes!" + ) return rb finally: dump_file.close() @@ -261,9 +290,9 @@ def readback(self, offset, length, spi_connection=None): 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}" + assert rb_b == ct_b, ( + f"First difference at offset {offs:#x} Expected {ct_b} got {rb_b}" + ) def verify_readback( self, offset, length, compare_to, is_bootloader=False, spi_connection=None @@ -284,6 +313,20 @@ def verify_readback( ct = ct[8:] self.diff(rb, ct) + def verify_output(self, expected_out: list[bytes]): + """Verify that at least one element of expected_out is in serial output""" + # Setting rtscts to true enables hardware flow control. + # This removes unwanted RTS logic level changes for some machines + # (and, therefore, chip resets) + # when the port is opened by the following function. + # As a result, if an app loaded to RAM, it has a chance to run and send + # "Hello world" data without unwanted chip reset. + with serial.serial_for_url(arg_port, arg_baud, rtscts=True) as p: + p.timeout = 5 + output = p.read(100) + print(f"Output: {output}") + assert any(item in output for item in expected_out) + @pytest.mark.skipif(arg_chip != "esp32", reason="ESP32 only") class TestFlashEncryption(EsptoolTestCase): @@ -291,8 +334,8 @@ def valid_key_present(self): try: esp = esptool.ESP32ROM(arg_port) esp.connect() - efuses, _ = espefuse.get_efuses(esp=esp) - blk1_rd_en = efuses["BLOCK1"].is_readable() + efuse_cls = espefuse.init_commands(esp=esp) + blk1_rd_en = efuse_cls.efuses["BLOCK1"].is_readable() return not blk1_rd_en finally: esp._port.close() @@ -305,12 +348,12 @@ def test_blank_efuse_encrypt_write_abort(self): pytest.skip("Valid encryption key already programmed, aborting the test") self.run_esptool( - "write_flash 0x1000 images/bootloader_esp32.bin " + "write-flash 0x1000 images/bootloader_esp32.bin " "0x8000 images/partitions_singleapp.bin " "0x10000 images/ram_helloworld/helloworld-esp32.bin" ) output = self.run_esptool_error( - "write_flash --encrypt 0x10000 images/ram_helloworld/helloworld-esp32.bin" + "write-flash --encrypt 0x10000 images/ram_helloworld/helloworld-esp32.bin" ) assert "Flash encryption key is not programmed".lower() in output.lower() @@ -326,13 +369,13 @@ def test_blank_efuse_encrypt_write_continue1(self): pytest.skip("Valid encryption key already programmed, aborting the test") self.run_esptool( - "write_flash --encrypt --ignore-flash-encryption-efuse-setting " + "write-flash --encrypt --ignore-flash-enc-efuse " "0x10000 images/ram_helloworld/helloworld-esp32.bin" ) - self.run_esptool("read_flash 0x10000 192 images/read_encrypted_flash.bin") + self.run_esptool("read-flash 0x10000 192 images/read_encrypted_flash.bin") self.run_espsecure( - "encrypt_flash_data --address 0x10000 --keyfile images/aes_key.bin " - "--flash_crypt_conf 0 --output images/local_enc.bin " + "encrypt-flash-data --address 0x10000 --keyfile images/aes_key.bin " + "--flash-crypt-conf 0 --output images/local_enc.bin " "images/ram_helloworld/helloworld-esp32.bin" ) @@ -344,9 +387,9 @@ def test_blank_efuse_encrypt_write_continue1(self): read_file2 = file2.read() for rf1, rf2, i in zip(read_file1, read_file2, range(len(read_file2))): - assert ( - rf1 == rf2 - ), f"Encrypted write failed: file mismatch at byte position {i}" + assert rf1 == rf2, ( + f"Encrypted write failed: file mismatch at byte position {i}" + ) print("Encrypted write success") finally: @@ -365,13 +408,13 @@ def test_blank_efuse_encrypt_write_continue2(self): pytest.skip("Valid encryption key already programmed, aborting the test") self.run_esptool( - "write_flash --encrypt --ignore-flash-encryption-efuse-setting " + "write-flash --encrypt --ignore-flash-enc-efuse " "0x10000 images/ram_helloworld/helloworld-esp32_edit.bin" ) - self.run_esptool("read_flash 0x10000 192 images/read_encrypted_flash.bin") + self.run_esptool("read-flash 0x10000 192 images/read_encrypted_flash.bin") self.run_espsecure( - "encrypt_flash_data --address 0x10000 --keyfile images/aes_key.bin " - "--flash_crypt_conf 0 --output images/local_enc.bin " + "encrypt-flash-data --address 0x10000 --keyfile images/aes_key.bin " + "--flash-crypt-conf 0 --output images/local_enc.bin " "images/ram_helloworld/helloworld-esp32.bin" ) @@ -393,26 +436,45 @@ def test_blank_efuse_encrypt_write_continue2(self): class TestFlashing(EsptoolTestCase): @pytest.mark.quick_test def test_short_flash(self): - self.run_esptool("write_flash 0x0 images/one_kb.bin") + self.run_esptool("write-flash 0x0 images/one_kb.bin") + self.verify_readback(0, 1024, "images/one_kb.bin") + + @pytest.mark.skipif(arg_chip != "esp32", reason="Don't need to test multiple times") + def test_short_flash_deprecated(self): + out = self.run_esptool( + "--before default_reset write_flash 0x0 images/one_kb.bin --flash_size keep" + ) + assert ( + "Deprecated: Choice 'default_reset' for option '--before' is deprecated. " + "Use 'default-reset' instead." in out + ) + assert ( + "Deprecated: Option '--flash_size' is deprecated. " + "Use '--flash-size' instead." in out + ) + assert ( + "Deprecated: Command 'write_flash' is deprecated. " + "Use 'write-flash' instead." in out + ) self.verify_readback(0, 1024, "images/one_kb.bin") @pytest.mark.quick_test def test_highspeed_flash(self): - self.run_esptool("write_flash 0x0 images/fifty_kb.bin", baud=921600) + self.run_esptool("write-flash 0x0 images/fifty_kb.bin", baud=921600) self.verify_readback(0, 50 * 1024, "images/fifty_kb.bin") def test_adjacent_flash(self): - self.run_esptool("write_flash 0x0 images/sector.bin 0x1000 images/fifty_kb.bin") + self.run_esptool("write-flash 0x0 images/sector.bin 0x1000 images/fifty_kb.bin") self.verify_readback(0, 4096, "images/sector.bin") self.verify_readback(4096, 50 * 1024, "images/fifty_kb.bin") def test_short_flash_hex(self): fd, f = tempfile.mkstemp(suffix=".hex") try: - self.run_esptool(f"merge_bin --format hex 0x0 images/one_kb.bin -o {f}") + self.run_esptool(f"merge-bin --format hex 0x0 images/one_kb.bin -o {f}") # make sure file is closed before running next command (mainly for Windows) os.close(fd) - self.run_esptool(f"write_flash 0x0 {f}") + self.run_esptool(f"write-flash 0x0 {f}") self.verify_readback(0, 1024, "images/one_kb.bin") finally: os.unlink(f) @@ -421,14 +483,14 @@ def test_adjacent_flash_hex(self): fd1, f1 = tempfile.mkstemp(suffix=".hex") fd2, f2 = tempfile.mkstemp(suffix=".hex") try: - self.run_esptool(f"merge_bin --format hex 0x0 images/sector.bin -o {f1}") + self.run_esptool(f"merge-bin --format hex 0x0 images/sector.bin -o {f1}") # make sure file is closed before running next command (mainly for Windows) os.close(fd1) self.run_esptool( - f"merge_bin --format hex 0x1000 images/fifty_kb.bin -o {f2}" + f"merge-bin --format hex 0x1000 images/fifty_kb.bin -o {f2}" ) os.close(fd2) - self.run_esptool(f"write_flash 0x0 {f1} 0x1000 {f2}") + self.run_esptool(f"write-flash 0x0 {f1} 0x1000 {f2}") self.verify_readback(0, 4096, "images/sector.bin") self.verify_readback(4096, 50 * 1024, "images/fifty_kb.bin") finally: @@ -439,20 +501,20 @@ def test_adjacent_flash_mixed(self): fd, f = tempfile.mkstemp(suffix=".hex") try: self.run_esptool( - f"merge_bin --format hex 0x1000 images/fifty_kb.bin -o {f}" + f"merge-bin --format hex 0x1000 images/fifty_kb.bin -o {f}" ) # make sure file is closed before running next command (mainly for Windows) os.close(fd) - self.run_esptool(f"write_flash 0x0 images/sector.bin 0x1000 {f}") + self.run_esptool(f"write-flash 0x0 images/sector.bin 0x1000 {f}") self.verify_readback(0, 4096, "images/sector.bin") self.verify_readback(4096, 50 * 1024, "images/fifty_kb.bin") finally: os.unlink(f) def test_adjacent_independent_flash(self): - self.run_esptool("write_flash 0x0 images/sector.bin") + self.run_esptool("write-flash 0x0 images/sector.bin") self.verify_readback(0, 4096, "images/sector.bin") - self.run_esptool("write_flash 0x1000 images/fifty_kb.bin") + self.run_esptool("write-flash 0x1000 images/fifty_kb.bin") self.verify_readback(4096, 50 * 1024, "images/fifty_kb.bin") # writing flash the second time shouldn't have corrupted the first time self.verify_readback(0, 4096, "images/sector.bin") @@ -464,11 +526,11 @@ def test_last_bytes_of_32M_flash(self): flash_size = 32 * 1024 * 1024 image_size = 1024 offset = flash_size - image_size - self.run_esptool("write_flash {} images/one_kb.bin".format(hex(offset))) - # Some of the functions cannot handle 32-bit addresses - i.e. addresses accessing - # the higher 16MB will manipulate with the lower 16MB flash area. + self.run_esptool("write-flash {} images/one_kb.bin".format(hex(offset))) + # Some of the functions cannot handle 32-bit addresses - i.e. addresses + # accessing the higher 16MB will manipulate with the lower 16MB flash area. offset2 = offset & 0xFFFFFF - self.run_esptool("write_flash {} images/one_kb_all_ef.bin".format(hex(offset2))) + self.run_esptool("write-flash {} images/one_kb_all_ef.bin".format(hex(offset2))) self.verify_readback(offset, image_size, "images/one_kb.bin") @pytest.mark.skipif( @@ -476,17 +538,17 @@ def test_last_bytes_of_32M_flash(self): ) def test_write_larger_area_to_32M_flash(self): offset = 18 * 1024 * 1024 - self.run_esptool("write_flash {} images/one_mb.bin".format(hex(offset))) - # Some of the functions cannot handle 32-bit addresses - i.e. addresses accessing - # the higher 16MB will manipulate with the lower 16MB flash area. + self.run_esptool("write-flash {} images/one_mb.bin".format(hex(offset))) + # Some of the functions cannot handle 32-bit addresses - i.e. addresses + # accessing the higher 16MB will manipulate with the lower 16MB flash area. offset2 = offset & 0xFFFFFF - self.run_esptool("write_flash {} images/one_kb_all_ef.bin".format(hex(offset2))) + self.run_esptool("write-flash {} images/one_kb_all_ef.bin".format(hex(offset2))) self.verify_readback(offset, 1 * 1024 * 1024, "images/one_mb.bin") def test_correct_offset(self): """Verify writing at an offset actually writes to that offset.""" - self.run_esptool("write_flash 0x2000 images/sector.bin") - time.sleep(0.1) + self.run_esptool("write-flash 0x2000 images/sector.bin") + sleep(0.1) three_sectors = self.readback(0, 0x3000) last_sector = three_sectors[0x2000:] with open("images/sector.bin", "rb") as f: @@ -496,7 +558,7 @@ def test_correct_offset(self): @pytest.mark.quick_test def test_no_compression_flash(self): self.run_esptool( - "write_flash -u 0x0 images/sector.bin 0x1000 images/fifty_kb.bin" + "write-flash -u 0x0 images/sector.bin 0x1000 images/fifty_kb.bin" ) self.verify_readback(0, 4096, "images/sector.bin") self.verify_readback(4096, 50 * 1024, "images/fifty_kb.bin") @@ -505,7 +567,7 @@ def test_no_compression_flash(self): @pytest.mark.skipif(arg_chip == "esp8266", reason="Added in ESP32") def test_compressed_nostub_flash(self): self.run_esptool( - "--no-stub write_flash -z 0x0 images/sector.bin 0x1000 images/fifty_kb.bin" + "--no-stub write-flash -z 0x0 images/sector.bin 0x1000 images/fifty_kb.bin" ) self.verify_readback(0, 4096, "images/sector.bin") self.verify_readback(4096, 50 * 1024, "images/fifty_kb.bin") @@ -518,13 +580,13 @@ def _test_partition_table_then_bootloader(self, args): self.verify_readback(0x4000, 96, "images/partitions_singleapp.bin") def test_partition_table_then_bootloader(self): - self._test_partition_table_then_bootloader("write_flash --force") + self._test_partition_table_then_bootloader("write-flash --force") def test_partition_table_then_bootloader_no_compression(self): - self._test_partition_table_then_bootloader("write_flash --force -u") + self._test_partition_table_then_bootloader("write-flash --force -u") def test_partition_table_then_bootloader_nostub(self): - self._test_partition_table_then_bootloader("--no-stub write_flash --force") + self._test_partition_table_then_bootloader("--no-stub write-flash --force") # note: there is no "partition table then bootloader" test that # uses --no-stub and -z, as the ESP32 ROM over-erases and can't @@ -532,16 +594,16 @@ def test_partition_table_then_bootloader_nostub(self): # test_compressed_nostub_flash() instead. def test_length_not_aligned_4bytes(self): - self.run_esptool("write_flash 0x0 images/not_4_byte_aligned.bin") + self.run_esptool("write-flash 0x0 images/not_4_byte_aligned.bin") def test_length_not_aligned_4bytes_no_compression(self): - self.run_esptool("write_flash -u 0x0 images/not_4_byte_aligned.bin") + self.run_esptool("write-flash -u 0x0 images/not_4_byte_aligned.bin") @pytest.mark.quick_test @pytest.mark.host_test def test_write_overlap(self): output = self.run_esptool_error( - "write_flash 0x0 images/bootloader_esp32.bin 0x1000 images/one_kb.bin" + "write-flash 0x0 images/bootloader_esp32.bin 0x1000 images/one_kb.bin" ) assert "Detected overlap at address: 0x1000 " in output @@ -549,7 +611,7 @@ def test_write_overlap(self): @pytest.mark.host_test def test_repeated_address(self): output = self.run_esptool_error( - "write_flash 0x0 images/one_kb.bin 0x0 images/one_kb.bin" + "write-flash 0x0 images/one_kb.bin 0x0 images/one_kb.bin" ) assert "Detected overlap at address: 0x0 " in output @@ -559,13 +621,13 @@ def test_write_sector_overlap(self): # These two 1KB files don't overlap, # but they do both touch sector at 0x1000 so should fail output = self.run_esptool_error( - "write_flash 0xd00 images/one_kb.bin 0x1d00 images/one_kb.bin" + "write-flash 0xd00 images/one_kb.bin 0x1d00 images/one_kb.bin" ) assert "Detected overlap at address: 0x1d00" in output def test_write_no_overlap(self): output = self.run_esptool( - "write_flash 0x0 images/one_kb.bin 0x2000 images/one_kb.bin" + "write-flash 0x0 images/one_kb.bin 0x2000 images/one_kb.bin" ) assert "Detected overlap at address" not in output @@ -575,7 +637,7 @@ def test_compressible_file(self): file_size = 1024 * 1024 input_file.write(b"\x00" * file_size) input_file.close() - self.run_esptool(f"write_flash 0x10000 {input_file.name}") + self.run_esptool(f"write-flash 0x10000 {input_file.name}") finally: os.unlink(input_file.name) @@ -589,7 +651,7 @@ def test_compressible_non_trivial_file(self): struct.pack("B", random.randrange(0, 1 << 8)) * same_bytes ) input_file.close() - self.run_esptool(f"write_flash 0x10000 {input_file.name}") + self.run_esptool(f"write-flash 0x10000 {input_file.name}") finally: os.unlink(input_file.name) @@ -597,23 +659,23 @@ def test_compressible_non_trivial_file(self): def test_zero_length(self): # Zero length files are skipped with a warning output = self.run_esptool( - "write_flash 0x10000 images/one_kb.bin 0x11000 images/zerolength.bin" + "write-flash 0x10000 images/one_kb.bin 0x11000 images/zerolength.bin" ) self.verify_readback(0x10000, 1024, "images/one_kb.bin") - assert "zerolength.bin is empty" in output + assert "'images/zerolength.bin' is empty" in output @pytest.mark.quick_test def test_single_byte(self): - self.run_esptool("write_flash 0x0 images/onebyte.bin") + self.run_esptool("write-flash 0x0 images/onebyte.bin") self.verify_readback(0x0, 1, "images/onebyte.bin") def test_erase_range_messages(self): output = self.run_esptool( - "write_flash 0x1000 images/sector.bin 0x0FC00 images/one_kb.bin" + "write-flash 0x1000 images/sector.bin 0x0FC00 images/one_kb.bin" ) assert "Flash will be erased from 0x00001000 to 0x00001fff..." in output assert ( - "WARNING: Flash address 0x0000fc00 is not aligned to a 0x1000 " + "Flash address 0x0000fc00 is not aligned to a 0x1000 " "byte flash sector. 0xc00 bytes before this address will be erased." in output ) @@ -627,12 +689,12 @@ def test_erase_range_messages(self): ) def test_write_image_for_another_target(self): output = self.run_esptool_error( - "write_flash 0x0 images/esp32s3_header.bin 0x1000 images/one_kb.bin" + "write-flash 0x0 images/esp32s3_header.bin 0x1000 images/one_kb.bin" ) - assert "Unexpected chip id in image." in output + assert "Unexpected chip ID in image." in output assert "value was 9. Is this image for a different chip model?" in output - assert "images/esp32s3_header.bin is not an " in output - assert "image. Use --force to flash anyway." in output + assert "'images/esp32s3_header.bin' is not an " in output + assert "image. Use the force argument to flash anyway." in output @pytest.mark.skipif( arg_chip == "esp8266", reason="chip_id field exist in ESP32 and later images" @@ -642,11 +704,11 @@ def test_write_image_for_another_target(self): ) def test_write_image_for_another_revision(self): output = self.run_esptool_error( - "write_flash 0x0 images/one_kb.bin 0x1000 images/esp32s3_header.bin" + "write-flash 0x0 images/one_kb.bin 0x1000 images/esp32s3_header.bin" ) - assert "images/esp32s3_header.bin requires chip revision 10" in output + assert "'images/esp32s3_header.bin' requires chip revision 10" in output assert "or higher (this chip is revision" in output - assert "Use --force to flash anyway." in output + assert "Use the force argument to flash anyway." in output @pytest.mark.skipif( arg_chip != "esp32c3", reason="This check happens only on a valid image" @@ -654,28 +716,29 @@ def test_write_image_for_another_revision(self): def test_flash_with_min_max_rev(self): """Use min/max_rev_full field to specify chip revision""" output = self.run_esptool_error( - "write_flash 0x0 images/one_kb.bin 0x1000 images/esp32c3_header_min_rev.bin" + "write-flash 0x0 images/one_kb.bin 0x1000 images/esp32c3_header_min_rev.bin" ) assert ( - "images/esp32c3_header_min_rev.bin " + "'images/esp32c3_header_min_rev.bin' " "requires chip revision in range [v2.55 - max rev not set]" in output ) - assert "Use --force to flash anyway." in output + assert "Use the force argument to flash anyway." in output @pytest.mark.quick_test def test_erase_before_write(self): - output = self.run_esptool("write_flash --erase-all 0x0 images/one_kb.bin") - assert "Chip erase completed successfully" in output + output = self.run_esptool("write-flash --erase-all 0x0 images/one_kb.bin") + assert "Flash memory erased successfully" in output assert "Hash of data verified" in output @pytest.mark.quick_test def test_flash_not_aligned_nostub(self): - output = self.run_esptool("--no-stub write_flash 0x1 images/one_kb.bin") + output = self.run_esptool("--no-stub write-flash 0x1 images/one_kb.bin") assert ( - "WARNING: Flash address 0x00000001 is not aligned to a 0x1000 byte flash sector. 0x1 bytes before this address will be erased." - in output + "Flash address 0x00000001 is not aligned to a 0x1000 byte flash sector. " + "0x1 bytes before this address will be erased." in output ) - assert "Hard resetting via RTS pin..." in output + if "ESPTOOL_TEST_USB_OTG" not in os.environ: + assert "Hard resetting" in output @pytest.mark.skipif(arg_preload_port is False, reason="USB-JTAG/Serial only") @pytest.mark.skipif(arg_chip != "esp32c3", reason="ESP32-C3 only") @@ -690,13 +753,13 @@ def test_flash_overclocked(self): SYSTEM_SOC_CLK_MAX = 1 output = self.run_esptool( - "--after no_reset_stub write_flash 0x0 images/one_mb.bin", preload=False + "--after no-reset-stub write-flash 0x0 images/one_mb.bin", preload=False ) faster = re.search(r"(\d+(\.\d+)?)\s+seconds", output) assert faster, "Duration summary not found in the output" with esptool.cmds.detect_chip( - port=arg_port, connect_mode="no_reset" + port=arg_port, connect_mode="no-reset" ) as reg_mod: reg_mod.write_reg( SYSTEM_SYSCLK_CONF_REG, @@ -711,13 +774,13 @@ def test_flash_overclocked(self): ) output = self.run_esptool( - "--before no_reset write_flash 0x0 images/one_mb.bin", preload=False + "--before no-reset write-flash 0x0 images/one_mb.bin", preload=False ) slower = re.search(r"(\d+(\.\d+)?)\s+seconds", output) assert slower, "Duration summary not found in the output" - assert ( - float(slower.group(1)) - float(faster.group(1)) > 1 - ), "Overclocking failed" + assert float(slower.group(1)) - float(faster.group(1)) > 1, ( + "Overclocking failed" + ) @pytest.mark.skipif(arg_preload_port is False, reason="USB-JTAG/Serial only") @pytest.mark.skipif(arg_chip != "esp32c3", reason="ESP32-C3 only") @@ -745,14 +808,14 @@ def test_flash_watchdogs(self): reg_mod.run_stub() output = self.run_esptool( - "--before no_reset --after no_reset_stub flash_id", preload=False + "--before no-reset --after no-reset-stub flash-id", preload=False ) - assert "Stub is already running. No upload is necessary." in output + assert "Stub flasher is already running. No upload is necessary." in output - time.sleep(10) # Wait if RTC WDT triggers + sleep(10) # Wait if RTC WDT triggers with esptool.cmds.detect_chip( - port=arg_port, connect_mode="no_reset" + port=arg_port, connect_mode="no-reset" ) as reg_mod: output = reg_mod.read_reg(reg_mod.RTC_CNTL_WDTCONFIG0_REG) assert output == 0, "RTC WDT is not disabled" @@ -764,11 +827,11 @@ def test_flash_watchdogs(self): @pytest.mark.skipif( arg_chip in ["esp8266", "esp32"], - reason="get_security_info command is supported on ESP32S2 and later", + reason="get-security-info command is supported on ESP32S2 and later", ) class TestSecurityInfo(EsptoolTestCase): def test_show_security_info(self): - res = self.run_esptool("get_security_info") + res = self.run_esptool("get-security-info") assert "Flags" in res assert "Crypt Count" in res if arg_chip != "esp32c2": @@ -788,38 +851,45 @@ def test_show_security_info(self): class TestFlashSizes(EsptoolTestCase): def test_high_offset(self): - self.run_esptool("write_flash -fs 4MB 0x300000 images/one_kb.bin") + self.run_esptool("write-flash -fs 4MB 0x300000 images/one_kb.bin") self.verify_readback(0x300000, 1024, "images/one_kb.bin") def test_high_offset_no_compression(self): - self.run_esptool("write_flash -u -fs 4MB 0x300000 images/one_kb.bin") + self.run_esptool("write-flash -u -fs 4MB 0x300000 images/one_kb.bin") self.verify_readback(0x300000, 1024, "images/one_kb.bin") def test_large_image(self): - self.run_esptool("write_flash -fs 4MB 0x280000 images/one_mb.bin") + self.run_esptool("write-flash -fs 4MB 0x280000 images/one_mb.bin") self.verify_readback(0x280000, 0x100000, "images/one_mb.bin") def test_large_no_compression(self): - self.run_esptool("write_flash -u -fs 4MB 0x280000 images/one_mb.bin") + self.run_esptool("write-flash -u -fs 4MB 0x280000 images/one_mb.bin") self.verify_readback(0x280000, 0x100000, "images/one_mb.bin") @pytest.mark.quick_test @pytest.mark.host_test def test_invalid_size_arg(self): - self.run_esptool_error("write_flash -fs 10MB 0x6000 images/one_kb.bin") + self.run_esptool_error("write-flash -fs 10MB 0x6000 images/one_kb.bin") def test_write_past_end_fails(self): output = self.run_esptool_error( - "write_flash -fs 1MB 0x280000 images/one_kb.bin" + "write-flash -fs 1MB 0x280000 images/one_kb.bin" ) - assert "File images/one_kb.bin" in output + assert "File 'images/one_kb.bin'" in output assert "will not fit" in output + @pytest.mark.skipif(arg_chip != "esp32", reason="Don't need to test multiple times") + def test_read_past_end_fails(self): + output = self.run_esptool_error( + "read-flash 0xffffff 1 out.bin" + ) # 0xffffff is well past the end of the flash in most cases (16MB) + assert "Can't access flash regions larger than detected flash size" in output + def test_write_no_compression_past_end_fails(self): output = self.run_esptool_error( - "write_flash -u -fs 1MB 0x280000 images/one_kb.bin" + "write-flash -u -fs 1MB 0x280000 images/one_kb.bin" ) - assert "File images/one_kb.bin" in output + assert "File 'images/one_kb.bin'" in output assert "will not fit" in output @pytest.mark.skipif( @@ -836,7 +906,7 @@ def test_flash_size_keep(self): with open(image, "rb") as f: f.seek(0, 2) image_len = f.tell() - self.run_esptool(f"write_flash -fs keep {offset} {image}") + self.run_esptool(f"write-flash -fs keep {offset} {image}") # header should be the same as in the .bin file self.verify_readback(offset, image_len, image) @@ -846,18 +916,19 @@ def test_flash_size_keep(self): def test_read_nostub_high_offset(self): offset = 0x300000 length = 1024 - self.run_esptool(f"write_flash -fs detect {offset} images/one_kb.bin") + 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}" + f"--no-stub read-flash -fs detect {offset} 1k {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!" + rb_len = len(rb) + assert length == rb_len, ( + f"read-flash length {length} offset {offset:#x} yielded {rb_len} bytes!" + ) finally: dump_file.close() os.unlink(dump_file.name) @@ -871,7 +942,7 @@ class TestFlashDetection(EsptoolTestCase): @pytest.mark.quick_test def test_flash_id(self): """Test manufacturer and device response of flash detection.""" - res = self.run_esptool("flash_id") + res = self.run_esptool("flash-id") assert "Manufacturer:" in res assert "Device:" in res @@ -882,7 +953,7 @@ def test_flash_id_expand_args(self): """ try: arg_file = tempfile.NamedTemporaryFile(delete=False) - arg_file.write(b"flash_id\n") + arg_file.write(b"flash-id\n") arg_file.close() res = self.run_esptool(f"@{arg_file.name}") assert "Manufacturer:" in res @@ -893,17 +964,25 @@ def test_flash_id_expand_args(self): @pytest.mark.quick_test def test_flash_id_trace(self): """Test trace functionality on flash detection, running without stub""" - res = self.run_esptool("--trace flash_id") + res = self.run_esptool("--trace flash-id") # read register command - assert re.search(r"TRACE \+\d.\d{3} command op=0x0a .*", res) is not None + assert ( + re.search(r"TRACE \+\d.\d{3} --- Cmd READ_REG \(0x0a\) .*", res) + is not None + ) # write register command - assert re.search(r"TRACE \+\d.\d{3} command op=0x09 .*", res) is not None - assert re.search(r"TRACE \+\d.\d{3} Read \d* bytes: .*", res) is not None - assert re.search(r"TRACE \+\d.\d{3} Write \d* bytes: .*", res) is not None - assert re.search(r"TRACE \+\d.\d{3} Received full packet: .*", res) is not None + assert ( + re.search(r"TRACE \+\d.\d{3} --- Cmd WRITE_REG \(0x09\) .*", res) + is not None + ) + assert re.search(r"TRACE \+\d.\d{3} Read \d* bytes:", res) is not None + assert re.search(r"TRACE \+\d.\d{3} Write \d+ bytes:", res) is not None + assert ( + re.search(r"TRACE \+\d.\d{3} Received full packet: .*", res) is not None + ) # flasher stub handshake assert ( - re.search(r"TRACE \+\d.\d{3} Received full packet: 4f484149", res) + re.search(r"TRACE \+\d.\d{3} Received full packet: 4f484149", res) is not None ) assert "Manufacturer:" in res @@ -920,7 +999,7 @@ def test_flash_size(self): # but it does not have the same amount of efuse blocks # the methods are overwritten # in case anything changes this test will fail to remind us - res = self.run_esptool("flash_id") + res = self.run_esptool("flash-id") lines = res.splitlines() for line in lines: assert "embedded flash" not in line.lower() @@ -928,10 +1007,10 @@ def test_flash_size(self): @pytest.mark.quick_test def test_flash_sfdp(self): """Test manufacturer and device response of flash detection.""" - res = self.run_esptool("read_flash_sfdp 0 4") - assert "SFDP[0..3]: 53 46 44 50" in res - res = self.run_esptool("read_flash_sfdp 1 3") - assert "SFDP[1..3]: 46 44 50 " in res + res = self.run_esptool("read-flash-sfdp 0 4") + assert "SFDP[0..3]: 0x53 0x46 0x44 0x50" in res + res = self.run_esptool("read-flash-sfdp 1 3") + assert "SFDP[1..3]: 0x46 0x44 0x50" in res @pytest.mark.skipif( @@ -942,9 +1021,9 @@ class TestExternalFlash(EsptoolTestCase): def test_short_flash_to_external_stub(self): # First flash internal flash, then external - self.run_esptool("write_flash 0x0 images/one_kb.bin") + self.run_esptool("write-flash 0x0 images/one_kb.bin") self.run_esptool( - f"write_flash --spi-connection {self.conn} 0x0 images/sector.bin" + f"write-flash --spi-connection {self.conn} 0x0 images/sector.bin" ) self.verify_readback(0, 1024, "images/one_kb.bin") @@ -952,18 +1031,18 @@ def test_short_flash_to_external_stub(self): # First flash external flash, then internal self.run_esptool( - f"write_flash --spi-connection {self.conn} 0x0 images/one_kb.bin" + f"write-flash --spi-connection {self.conn} 0x0 images/one_kb.bin" ) - self.run_esptool("write_flash 0x0 images/sector.bin") + self.run_esptool("write-flash 0x0 images/sector.bin") self.verify_readback(0, 1024, "images/sector.bin") self.verify_readback(0, 1024, "images/one_kb.bin", spi_connection=self.conn) def test_short_flash_to_external_ROM(self): # First flash internal flash, then external - self.run_esptool("--no-stub write_flash 0x0 images/one_kb.bin") + self.run_esptool("--no-stub write-flash 0x0 images/one_kb.bin") self.run_esptool( - f"--no-stub write_flash --spi-connection {self.conn} 0x0 images/sector.bin" + f"--no-stub write-flash --spi-connection {self.conn} 0x0 images/sector.bin" ) self.verify_readback(0, 1024, "images/one_kb.bin") @@ -971,113 +1050,122 @@ def test_short_flash_to_external_ROM(self): # First flash external flash, then internal self.run_esptool( - f"--no-stub write_flash --spi-connection {self.conn} 0x0 images/one_kb.bin" + f"--no-stub write-flash --spi-connection {self.conn} 0x0 images/one_kb.bin" ) - self.run_esptool("--no-stub write_flash 0x0 images/sector.bin") + self.run_esptool("--no-stub write-flash 0x0 images/sector.bin") self.verify_readback(0, 1024, "images/sector.bin") self.verify_readback(0, 1024, "images/one_kb.bin", spi_connection=self.conn) +@pytest.mark.skipif( + "ESPTOOL_TEST_USB_OTG" in os.environ, + reason="USB-OTG tests require --after no-reset for stability.", +) class TestStubReuse(EsptoolTestCase): def test_stub_reuse_with_synchronization(self): """Keep the flasher stub running and reuse it the next time.""" res = self.run_esptool( - "--after no_reset_stub flash_id" + "--after no-reset-stub flash-id" ) # flasher stub keeps running after this assert "Manufacturer:" in res res = self.run_esptool( - "--before no_reset flash_id", + "--before no-reset flash-id", preload=False, ) # do sync before (without reset it talks to the flasher stub) assert "Manufacturer:" in res - @pytest.mark.skipif(arg_chip != "esp8266", reason="ESP8266 only") def test_stub_reuse_without_synchronization(self): """ Keep the flasher stub running and reuse it the next time without synchronization. - - Synchronization is necessary for chips where the ROM bootloader has different - status length in comparison to the flasher stub. - Therefore, this is ESP8266 only test. """ - res = self.run_esptool("--after no_reset_stub flash_id") + res = self.run_esptool("--after no-reset-stub flash-id") assert "Manufacturer:" in res - res = self.run_esptool("--before no_reset_no_sync flash_id") + res = self.run_esptool("--before no-reset-no-sync flash-id", preload=False) assert "Manufacturer:" in res class TestErase(EsptoolTestCase): @pytest.mark.quick_test def test_chip_erase(self): - self.run_esptool("write_flash 0x10000 images/one_kb.bin") + self.run_esptool("write-flash 0x10000 images/one_kb.bin") self.verify_readback(0x10000, 0x400, "images/one_kb.bin") - self.run_esptool("erase_flash") + self.run_esptool("erase-flash") empty = self.readback(0x10000, 0x400) - assert empty == b"\xFF" * 0x400 + assert empty == b"\xff" * 0x400 def test_region_erase(self): - self.run_esptool("write_flash 0x10000 images/one_kb.bin") - self.run_esptool("write_flash 0x11000 images/sector.bin") + self.run_esptool("write-flash 0x10000 images/one_kb.bin") + self.run_esptool("write-flash 0x11000 images/sector.bin") self.verify_readback(0x10000, 0x400, "images/one_kb.bin") self.verify_readback(0x11000, 0x1000, "images/sector.bin") # erase only the flash sector containing one_kb.bin - self.run_esptool("erase_region 0x10000 0x1000") + self.run_esptool("erase-region 0x10000 0x1000") self.verify_readback(0x11000, 0x1000, "images/sector.bin") empty = self.readback(0x10000, 0x1000) - assert empty == b"\xFF" * 0x1000 + assert empty == b"\xff" * 0x1000 def test_region_erase_all(self): - res = self.run_esptool("erase_region 0x0 ALL") + res = self.run_esptool("erase-region 0x0 ALL") assert re.search(r"Detected flash size: \d+[KM]B", res) is not None def test_large_region_erase(self): # verifies that erasing a large region doesn't time out - self.run_esptool("erase_region 0x0 0x100000") + self.run_esptool("erase-region 0x0 0x100000") + + @pytest.mark.skipif(arg_chip == "esp8266", reason="Not supported on ESP8266") + def test_region_erase_no_stub(self): + self.run_esptool("write-flash 0x10000 images/one_kb.bin") + self.run_esptool("write-flash 0x11000 images/sector.bin") + self.verify_readback(0x10000, 0x400, "images/one_kb.bin") + self.verify_readback(0x11000, 0x1000, "images/sector.bin") + # erase only the flash sector containing one_kb.bin + self.run_esptool("--no-stub erase-region 0x10000 0x1000") + self.verify_readback(0x11000, 0x1000, "images/sector.bin") + empty = self.readback(0x10000, 0x1000) + assert empty == b"\xff" * 0x1000 class TestSectorBoundaries(EsptoolTestCase): def test_end_sector(self): - self.run_esptool("write_flash 0x10000 images/sector.bin") - self.run_esptool("write_flash 0x0FC00 images/one_kb.bin") + self.run_esptool("write-flash 0x10000 images/sector.bin") + self.run_esptool("write-flash 0x0FC00 images/one_kb.bin") self.verify_readback(0x0FC00, 0x400, "images/one_kb.bin") self.verify_readback(0x10000, 0x1000, "images/sector.bin") def test_end_sector_uncompressed(self): - self.run_esptool("write_flash -u 0x10000 images/sector.bin") - self.run_esptool("write_flash -u 0x0FC00 images/one_kb.bin") + self.run_esptool("write-flash -u 0x10000 images/sector.bin") + self.run_esptool("write-flash -u 0x0FC00 images/one_kb.bin") self.verify_readback(0x0FC00, 0x400, "images/one_kb.bin") self.verify_readback(0x10000, 0x1000, "images/sector.bin") def test_overlap(self): - self.run_esptool("write_flash 0x20800 images/sector.bin") + self.run_esptool("write-flash 0x20800 images/sector.bin") self.verify_readback(0x20800, 0x1000, "images/sector.bin") class TestVerifyCommand(EsptoolTestCase): @pytest.mark.quick_test def test_verify_success(self): - self.run_esptool("write_flash 0x5000 images/one_kb.bin") - self.run_esptool("verify_flash 0x5000 images/one_kb.bin") + self.run_esptool("write-flash 0x5000 images/one_kb.bin") + self.run_esptool("verify-flash 0x5000 images/one_kb.bin") def test_verify_failure(self): - self.run_esptool("write_flash 0x6000 images/sector.bin") - output = self.run_esptool_error( - "verify_flash --diff=yes 0x6000 images/one_kb.bin" - ) - assert "verify FAILED" in output - assert "first @ 0x00006000" in output + self.run_esptool("write-flash 0x6000 images/sector.bin") + output = self.run_esptool_error("verify-flash --diff 0x6000 images/one_kb.bin") + assert "Verification failed:" in output + assert "first at 0x00006000:" in output def test_verify_unaligned_length(self): - self.run_esptool("write_flash 0x0 images/not_4_byte_aligned.bin") - self.run_esptool("verify_flash 0x0 images/not_4_byte_aligned.bin") + self.run_esptool("write-flash 0x0 images/not_4_byte_aligned.bin") + self.run_esptool("verify-flash 0x0 images/not_4_byte_aligned.bin") class TestReadIdentityValues(EsptoolTestCase): @pytest.mark.quick_test def test_read_mac(self): - output = self.run_esptool("read_mac") + output = self.run_esptool("read-mac") mac = re.search(r"[0-9a-f:]{17}", output) assert mac is not None mac = mac.group(0) @@ -1086,7 +1174,7 @@ def test_read_mac(self): @pytest.mark.skipif(arg_chip != "esp8266", reason="ESP8266 only") def test_read_chip_id(self): - output = self.run_esptool("chip_id") + output = self.run_esptool("chip-id") idstr = re.search("Chip ID: 0x([0-9a-f]+)", output) assert idstr is not None idstr = idstr.group(1) @@ -1097,23 +1185,24 @@ def test_read_chip_id(self): class TestMemoryOperations(EsptoolTestCase): @pytest.mark.quick_test def test_memory_dump(self): - output = self.run_esptool("dump_mem 0x50000000 128 memout.bin") - assert "Read 128 bytes" in output + output = self.run_esptool("dump-mem 0x50000000 128 memout.bin") + assert "Dumped 128 bytes from 0x50000000" in output + assert "to 'memout.bin'" in output os.remove("memout.bin") def test_memory_write(self): - output = self.run_esptool("write_mem 0x400C0000 0xabad1dea 0x0000ffff") - assert "Wrote abad1dea" in output - assert "mask 0000ffff" in output - assert "to 400c0000" in output + output = self.run_esptool("write-mem 0x400C0000 0xabad1dea 0x0000ffff") + assert "Wrote 0xabad1dea" in output + assert "mask 0x0000ffff" in output + assert "to 0x400c0000" in output def test_memory_read(self): - output = self.run_esptool("read_mem 0x400C0000") + output = self.run_esptool("read-mem 0x400C0000") assert "0x400c0000 =" in output class TestKeepImageSettings(EsptoolTestCase): - """Tests for the -fm keep, -ff keep options for write_flash""" + """Tests for the -fm keep, -ff keep options for write-flash""" @classmethod def setup_class(self): @@ -1129,17 +1218,17 @@ def setup_class(self): ) def test_keep_does_not_change_settings(self): # defaults should all be keep - self.run_esptool(f"write_flash -fs keep {self.flash_offset:#x} {self.BL_IMAGE}") + self.run_esptool(f"write-flash -fs keep {self.flash_offset:#x} {self.BL_IMAGE}") self.verify_readback(self.flash_offset, 8, self.BL_IMAGE, False) # can also explicitly set all options self.run_esptool( - f"write_flash -fm keep -ff keep -fs keep " + f"write-flash -fm keep -ff keep -fs keep " f"{self.flash_offset:#x} {self.BL_IMAGE}" ) self.verify_readback(self.flash_offset, 8, self.BL_IMAGE, False) - # verify_flash should also use 'keep' + # verify-flash should also use 'keep' self.run_esptool( - f"verify_flash -fs keep {self.flash_offset:#x} {self.BL_IMAGE}" + f"verify-flash -fs keep {self.flash_offset:#x} {self.BL_IMAGE}" ) @pytest.mark.skipif( @@ -1149,7 +1238,7 @@ def test_keep_does_not_change_settings(self): @pytest.mark.quick_test def test_detect_size_changes_size(self): self.run_esptool( - f"write_flash -fs detect {self.flash_offset:#x} {self.BL_IMAGE}" + f"write-flash -fs detect {self.flash_offset:#x} {self.BL_IMAGE}" ) readback = self.readback(self.flash_offset, 8) assert self.header[:3] == readback[:3] # first 3 bytes unchanged @@ -1162,7 +1251,7 @@ def test_detect_size_changes_size(self): ) def test_explicit_set_size_freq_mode(self): self.run_esptool( - f"write_flash -fs 2MB -fm dout -ff 80m " + f"write-flash -fs 2MB -fm dout -ff 80m " f"{self.flash_offset:#x} {self.BL_IMAGE}" ) @@ -1177,12 +1266,12 @@ def test_explicit_set_size_freq_mode(self): assert self.header[3] != readback[3] # size/freq values have changed assert self.header[4:] == readback[4:] # entrypoint address hasn't changed - # verify_flash should pass if we match params, fail otherwise + # verify-flash should pass if we match params, fail otherwise self.run_esptool( - f"verify_flash -fs 2MB -fm dout -ff 80m " + f"verify-flash -fs 2MB -fm dout -ff 80m " f"{self.flash_offset:#x} {self.BL_IMAGE}" ) - self.run_esptool_error(f"verify_flash {self.flash_offset:#x} {self.BL_IMAGE}") + self.run_esptool_error(f"verify-flash {self.flash_offset:#x} {self.BL_IMAGE}") @pytest.mark.skipif( @@ -1193,7 +1282,7 @@ class TestLoadRAM(EsptoolTestCase): # flashing an application not supporting USB-CDC will make # /dev/ttyACM0 disappear and USB-CDC tests will not work anymore - def verify_output(self, expected_out: List[bytes]): + def verify_output(self, expected_out: list[bytes]): """Verify that at least one element of expected_out is in serial output""" # Setting rtscts to true enables hardware flow control. # This removes unwanted RTS logic level changes for some machines @@ -1209,18 +1298,18 @@ def verify_output(self, expected_out: List[bytes]): @pytest.mark.quick_test def test_load_ram(self): - """Verify load_ram command + """Verify load-ram command The "hello world" binary programs for each chip print "Hello world!\n" to the serial port. """ - self.run_esptool(f"load_ram images/ram_helloworld/helloworld-{arg_chip}.bin") + self.run_esptool(f"load-ram images/ram_helloworld/helloworld-{arg_chip}.bin") self.verify_output( [b"Hello world!", b'\xce?\x13\x05\x04\xd0\x97A\x11"\xc4\x06\xc67\x04'] ) def test_load_ram_hex(self): - """Verify load_ram command with hex file as input + """Verify load-ram command with hex file as input The "hello world" binary programs for each chip print "Hello world!\n" to the serial port. @@ -1228,12 +1317,12 @@ def test_load_ram_hex(self): fd, f = tempfile.mkstemp(suffix=".hex") try: self.run_esptool( - f"merge_bin --format hex -o {f} 0x0 " + f"merge-bin --format hex -o {f} 0x0 " f"images/ram_helloworld/helloworld-{arg_chip}.bin" ) # make sure file is closed before running next command (mainly for Windows) os.close(fd) - self.run_esptool(f"load_ram {f}") + self.run_esptool(f"load-ram {f}") self.verify_output( [b"Hello world!", b'\xce?\x13\x05\x04\xd0\x97A\x11"\xc4\x06\xc67\x04'] ) @@ -1255,11 +1344,11 @@ def test_deep_sleep_flash(self): # not even necessary to wake successfully from sleep, # going into deep sleep is enough # (so GPIO16, etc, config is not important for this test) - self.run_esptool("write_flash 0x0 images/esp8266_deepsleep.bin", baud=230400) + self.run_esptool("write-flash 0x0 images/esp8266_deepsleep.bin", baud=230400) - time.sleep(0.25) # give ESP8266 time to enter deep sleep + sleep(0.25) # give ESP8266 time to enter deep sleep - self.run_esptool("write_flash 0x0 images/fifty_kb.bin", baud=230400) + self.run_esptool("write-flash 0x0 images/fifty_kb.bin", baud=230400) self.verify_readback(0, 50 * 1024, "images/fifty_kb.bin") @@ -1274,13 +1363,13 @@ def test_flash_header_rewrite(self): bl_image = f"images/bootloader_{arg_chip}.bin" output = self.run_esptool( - f"write_flash -fm dout -ff 20m {bl_offset:#x} {bl_image}" + f"write-flash -fm dout -ff 20m {bl_offset:#x} {bl_image}" ) if arg_chip in ["esp8266", "esp32"]: - # ESP8266 doesn't support this; The test image for ESP32 just doesn't have it. - assert "Flash params set to" in output + # ESP8266 lacks this feature; ESP32 test image doesn't include it + assert "Flash parameters set to" in output else: - assert "Flash params set to" in output + assert "Flash parameters set to" in output # Since SHA recalculation is supported for changed bootloader header assert "SHA digest in image updated" in output @@ -1290,7 +1379,7 @@ def test_flash_header_no_magic_no_rewrite(self): bl_offset = esptool.CHIP_DEFS[arg_chip].BOOTLOADER_FLASH_OFFSET for image in ["images/one_kb.bin", "images/one_kb_all_ef.bin"]: output = self.run_esptool( - f"write_flash -fm dout -ff 20m {bl_offset:#x} {image}" + f"write-flash -fm dout -ff 20m {bl_offset:#x} {image}" ) "not changing any flash settings" in output self.verify_readback(bl_offset, 1024, image) @@ -1299,17 +1388,108 @@ def test_flash_header_no_magic_no_rewrite(self): class TestAutoDetect(EsptoolTestCase): def _check_output(self, output): expected_chip_name = esptool.util.expand_chip_name(arg_chip) - if arg_chip not in ["esp8266", "esp32", "esp32s2"]: - assert "Unsupported detection protocol" not in output assert f"Detecting chip type... {expected_chip_name}" in output - assert f"Chip is {expected_chip_name}" in output + assert f"{'Chip type:':<20}{expected_chip_name}" in output @pytest.mark.quick_test def test_auto_detect(self): - output = self.run_esptool("chip_id", chip="auto") + output = self.run_esptool("chip-id", chip="auto") self._check_output(output) +class TestChipDetectionValidation(EsptoolTestCase): + """Test the chip detection validation logic in ESPLoader.connect() method. + + This tests the section that validates if the connected chip matches the + specified chip argument, covering scenarios with: + - Chips that use chip ID detection (ESP32-S3 and later) + - Chips that use magic value detection (ESP8266, ESP32, ESP32-S2) + - ESP32-S2 in Secure Download Mode (SDM) + - Correct chip argument vs wrong chip argument detection + """ + + def _find_different_chip(self, chip_name, detection_method): + """Find a different chip from the specified chip name + based on the detection method, except ESP32-S2. + + Args: + chip_name: The name of the chip to find a different chip for. + detection_method: The detection method to use. + + Returns: + The name of the different chip. + """ + for chip in esptool.CHIP_DEFS: + if chip != chip_name and chip != "esp32s2": + if ( + detection_method == "chip_id" + and not esptool.CHIP_DEFS[chip].USES_MAGIC_VALUE + ): + if ( + esptool.CHIP_DEFS[chip].IMAGE_CHIP_ID + != esptool.CHIP_DEFS[chip_name].IMAGE_CHIP_ID + ): + return chip + elif ( + detection_method == "magic_value" + and esptool.CHIP_DEFS[chip].USES_MAGIC_VALUE + ): + if ( + esptool.CHIP_DEFS[chip].MAGIC_VALUE + != esptool.CHIP_DEFS[chip_name].MAGIC_VALUE + ): + return chip + + @pytest.mark.quick_test + def test_chips_with_chip_id_detection(self): + # First verify the correct chip works + output = self.run_esptool(f"--chip {arg_chip} flash-id") + assert "Stub flasher running." in output + + # Find a different chip with different chip ID to test mismatch detection + different_chip_id = self._find_different_chip(arg_chip, "chip_id") + error_output = self.run_esptool_error(f"--chip {different_chip_id} flash-id") + assert ( + f"This chip is {arg_chip.upper()}, not {different_chip_id.upper()}." + in error_output + or "Wrong chip argument?" in error_output + ) + + # Find a different chip with different magic value to test mismatch detection + different_chip_magic = self._find_different_chip(arg_chip, "magic_value") + error_output = self.run_esptool_error(f"--chip {different_chip_magic} flash-id") + assert ( + f"This chip is {arg_chip.upper()}, not {different_chip_magic.upper()}." + in error_output + or "Wrong chip argument?" in error_output + ) + + if arg_chip != "esp32s2": + # ESP32-S2 is special case that has security info, but not chip ID + error_output = self.run_esptool_error("--chip esp32s2 flash-id") + assert ( + f"This chip is {arg_chip.upper()}, not ESP32-S2." in error_output + or "Wrong chip argument?" in error_output + ) + + +class TestUSBMode(EsptoolTestCase): + @pytest.mark.quick_test + def test_usb_mode(self): + output = self.run_esptool("chip-id") + expected_usb_mode = ( + "USB-OTG" + if os.environ.get("ESPTOOL_TEST_USB_OTG") == "1" + else "USB-Serial/JTAG" + if arg_preload_port + else None + ) + + if expected_usb_mode: + assert "USB mode: " in output + assert expected_usb_mode in output + + @pytest.mark.flaky(reruns=5) @pytest.mark.skipif(arg_preload_port is not False, reason="USB-to-UART bridge only") @pytest.mark.skipif(os.name == "nt", reason="Linux/MacOS only") @@ -1317,7 +1497,7 @@ class TestVirtualPort(TestAutoDetect): def test_auto_detect_virtual_port(self): with ESPRFC2217Server() as server: output = self.run_esptool( - "chip_id", + "chip-id", chip="auto", port=f"rfc2217://localhost:{str(server.port)}?ign_set_control", ) @@ -1327,7 +1507,7 @@ def test_highspeed_flash_virtual_port(self): with ESPRFC2217Server() as server: rfc2217_port = f"rfc2217://localhost:{str(server.port)}?ign_set_control" self.run_esptool( - "write_flash 0x0 images/fifty_kb.bin", + "write-flash 0x0 images/fifty_kb.bin", baud=921600, port=rfc2217_port, ) @@ -1344,7 +1524,7 @@ def pty_port(self): @pytest.mark.host_test def test_pty_port(self, pty_port): - cmd = [sys.executable, "-m", "esptool", "--port", pty_port, "chip_id"] + cmd = [sys.executable, "-m", "esptool", "--port", pty_port, "chip-id"] output = subprocess.run( cmd, cwd=TEST_DIR, @@ -1355,7 +1535,7 @@ def test_pty_port(self, pty_port): assert output.returncode != 0 output = output.stdout.decode("utf-8") print(output) # for logging - assert "WARNING: Chip was NOT reset." in output + assert "Chip was NOT reset." in output @pytest.mark.quick_test @@ -1422,13 +1602,13 @@ def test_read_write_memory_stub(self): ) def test_read_write_flash_status(self): """Read flash status and write back the same status""" - res = self.run_esptool("read_flash_status") - match = re.search(r"Status value: (0x[\d|a-f]*)", res) + res = self.run_esptool("read-flash-status") + match = re.search(r"Flash memory status: (0x[\d|a-f]*)", res) assert match is not None - res = self.run_esptool(f"write_flash_status {match.group(1)}") - assert f"Initial flash status: {match.group(1)}" in res - assert f"Setting flash status: {match.group(1)}" in res - assert f"After flash status: {match.group(1)}" in res + res = self.run_esptool(f"write-flash-status {match.group(1)}") + assert f"Initial flash memory status: {match.group(1)}" in res + assert f"Setting flash memory status: {match.group(1)}" in res + assert f"After flash memory status: {match.group(1)}" in res def test_read_chip_description(self): try: @@ -1459,36 +1639,24 @@ def test_read_get_chip_features(self): @pytest.mark.skipif( - arg_chip != "esp8266", reason="Make image option is supported only on ESP8266" + "ESPTOOL_TEST_USB_OTG" in os.environ or arg_preload_port is not False, + reason="Boot mode strapping pin pulled constantly low, " + "can't reset out of bootloader", ) -class TestMakeImage(EsptoolTestCase): - def verify_image(self, offset, length, image, compare_to): - with open(image, "rb") as f: - f.seek(offset) - rb = f.read(length) - with open(compare_to, "rb") as f: - ct = f.read() - if len(rb) != len(ct): - print( - f"WARNING: Expected length {len(ct)} doesn't match comparison {len(rb)}" - ) - print(f"Readback {len(rb)} bytes") - self.diff(rb, ct) - - def test_make_image(self): - output = self.run_esptool( - "make_image test" - " -a 0x0 -f images/sector.bin -a 0x1000 -f images/fifty_kb.bin" - ) - try: - assert "Successfully created esp8266 image." in output - assert os.path.exists("test0x00000.bin") - self.verify_image(16, 4096, "test0x00000.bin", "images/sector.bin") - self.verify_image( - 4096 + 24, 50 * 1024, "test0x00000.bin", "images/fifty_kb.bin" +class TestReset(EsptoolTestCase): + def test_watchdog_reset(self): + # Erase the bootloader to get "invalid header" output + test watchdog reset + res = self.run_esptool("--after watchdog-reset erase-region 0x0 0x4000") + if arg_chip in ["esp8266", "esp32", "esp32h2", "esp32c6"]: + assert "Watchdog hard reset is not supported" in res + assert "Hard resetting via RTS pin..." in res + else: + assert "Hard resetting with a watchdog..." in res + # If there is no output, the chip did not reset + # Mangled bytes are for C2 26 MHz when the baudrate doesn't match + self.verify_output( + [b"invalid header", b"\x02b\xe2n\x9e\xe0p\x12n\x9c\x0cn"] ) - finally: - os.remove("test0x00000.bin") @pytest.mark.skipif(arg_chip != "esp32", reason="Don't need to test multiple times") @@ -1514,10 +1682,7 @@ def __exit__(self, exc_type, exc_value, exc_tb): assert not os.path.exists(self.file_path) dummy_config = ( - "[esptool]\n" - "connect_attempts = 5\n" - "reset_delay = 1\n" - "serial_write_timeout = 12" + "[esptool]\nconnect_attempts = 5\nreset_delay = 1\nserial_write_timeout = 12" ) @pytest.mark.host_test @@ -1537,7 +1702,7 @@ def test_load_config_file(self): assert f"Loaded custom configuration from {config_file_path}" not in output # Correct header, but options are unparsable - faulty_config = "[esptool]\n" "connect_attempts = 5\n" "connect_attempts = 9\n" + faulty_config = "[esptool]\nconnect_attempts = 5\nconnect_attempts = 9\n" with self.ConfigFile(config_file_path, faulty_config): output = self.run_esptool("version") assert f"Ignoring invalid config file {config_file_path}" in output @@ -1547,9 +1712,7 @@ def test_load_config_file(self): ) # Correct header, unknown option (or a typo) - faulty_config = ( - "[esptool]\n" "connect_attempts = 9\n" "timoout = 2\n" "bits = 2" - ) + faulty_config = "[esptool]\nconnect_attempts = 9\ntimoout = 2\nbits = 2" with self.ConfigFile(config_file_path, faulty_config): output = self.run_esptool("version") assert "Ignoring unknown config file options: bits, timoout" in output @@ -1583,7 +1746,7 @@ def test_load_config_file_with_env_var(self): def test_custom_reset_sequence(self): # This reset sequence will fail to reset the chip to bootloader, - # the flash_id operation should therefore fail. + # the flash-id operation should therefore fail. # Also tests the number of connection attempts. reset_seq_config = ( "[esptool]\n" @@ -1592,7 +1755,7 @@ def test_custom_reset_sequence(self): ) config_file_path = os.path.join(os.getcwd(), "esptool.cfg") with self.ConfigFile(config_file_path, reset_seq_config): - output = self.run_esptool_error("flash_id") + output = self.run_esptool_error("flash-id") assert f"Loaded custom configuration from {config_file_path}" in output assert "A fatal error occurred: Failed to connect to" in output # Connection attempts are represented with dots, @@ -1600,11 +1763,11 @@ def test_custom_reset_sequence(self): assert "Connecting............." not in output # Test invalid custom_reset_sequence format is not accepted - invalid_reset_seq_config = "[esptool]\n" "custom_reset_sequence = F0|R1|C0|A5\n" + invalid_reset_seq_config = "[esptool]\ncustom_reset_sequence = F0|R1|C0|A5\n" with self.ConfigFile(config_file_path, invalid_reset_seq_config): - output = self.run_esptool_error("flash_id") + output = self.run_esptool_error("flash-id") assert f"Loaded custom configuration from {config_file_path}" in output - assert 'Invalid "custom_reset_sequence" option format:' in output + assert "Invalid custom reset sequence option format:" in output def test_open_port_attempts(self): # Test that the open_port_attempts option is loaded correctly @@ -1613,12 +1776,140 @@ def test_open_port_attempts(self): "[esptool]\n" f"open_port_attempts = {connect_attempts}\n" "connect_attempts = 1\n" - "custom_reset_sequence = D0\n" # Invalid reset sequence to make sure connection fails - ) + "custom_reset_sequence = D0\n" + ) # Invalid reset sequence to make sure connection fails config_file_path = os.path.join(os.getcwd(), "esptool.cfg") with self.ConfigFile(config_file_path, config): - output = self.run_esptool_error("flash_id") + output = self.run_esptool_error("flash-id") assert f"Loaded custom configuration from {config_file_path}" in output assert "Retrying failed connection" in output for _ in range(connect_attempts): assert "Connecting........" in output + + +@pytest.mark.skipif( + "ESPTOOL_TEST_USB_OTG" in os.environ, + reason="May cause port disappearing in USB-OTG mode on CI.", +) +class TestESPObjectOperations(EsptoolTestCase): + def capture_stdout(test_function): + """Decorator to capture stdout.""" + + def wrapper(*args, **kwargs): + with patch("sys.stdout", new=StringIO()) as fake_out: + test_function(*args, **kwargs, fake_out=fake_out) + + return wrapper + + @pytest.mark.skipif( + arg_chip in ["esp32s2", "esp32p4"], + reason="ESP32-S2 attaches the flash even without explicit attach", + ) + @pytest.mark.quick_test + @capture_stdout + def test_attach_flash(self, fake_out): + with esptool.CHIP_DEFS[arg_chip](port=arg_port) as esp: + # Try communicating with the flash chip without attaching it + esp.connect() + flash_id(esp) + read_flash_sfdp(esp, 0, 4) + output_pre = fake_out.getvalue() + # Clear the output buffer + fake_out.truncate(0) + fake_out.seek(0) + # Attach the flash chip and try again + attach_flash(esp) + flash_id(esp) + read_flash_sfdp(esp, 0, 4) + reset_chip(esp, "hard-reset") + output_post = fake_out.getvalue() + assert "Detected flash size: Unknown" in output_pre + assert "Device: ffff" in output_pre or "Device: 0000" in output_pre + assert ( + "SFDP[0..3]: 0xff 0xff 0xff 0xff" in output_pre + or "SFDP[0..3]: 0x00 0x00 0x00 0x00" in output_pre + ) + assert "Detected flash size: Unknown" not in output_post + assert "Device: ffff" not in output_post + assert "SFDP[0..3]: 0x53 0x46 0x44 0x50" in output_post + + @pytest.mark.quick_test + @capture_stdout + def test_stub_run(self, fake_out): + with esptool.CHIP_DEFS[arg_chip](port=arg_port) as esp: + esp.connect() + esp = esp.run_stub() + read_mac(esp) + reset_chip(esp, "hard-reset") + output = fake_out.getvalue() + assert "Stub flasher running" in output + assert "MAC:" in output + + @capture_stdout + def test_flash_operations(self, fake_out): + with detect_chip(port=arg_port) as esp: # Test with chip autodetection + esp = esp.run_stub() + try: + attach_flash(esp) + with open("images/one_kb.bin", "rb") as input: + write_flash(esp, [(0x0, input), (0x2000, input)]) + read_flash(esp, 0x0, 0x2400, "output.bin") + verify_flash(esp, [(0x0, input), (0x2000, input)]) + with open("output.bin", "rb") as output: + verify_flash(esp, [(0x0, output)]) + erase_flash(esp) + read_flash(esp, 0x0, 0x10, "output.bin") + finally: + reset_chip(esp, "hard-reset") + os.remove("output.bin") + output = fake_out.getvalue() + assert "Stub flasher running" in output + assert "Hash of data verified" in output + assert "Read 9216 bytes" in output + assert "Verification successful (digest matched)" in output + assert "Flash memory erased successfully" in output + assert "Hard resetting" in output + + @pytest.mark.quick_test + @pytest.mark.host_test + @capture_stdout + def test_non_esp_operations(self, fake_out): + image_info("images/bootloader_esp32.bin") + with open("images/one_kb.bin", "rb") as input: + try: + merge_bin([(0x0, input), (0x2000, input)], arg_chip, "output.bin") + finally: + os.remove("output.bin") + version() + output = fake_out.getvalue() + assert "Detected image type: ESP32" in output + assert "Checksum: 0x83 (valid)" in output + assert "Wrote 0x2400 bytes to file 'output.bin'" in output + assert esptool.__version__ in output + + +@pytest.mark.host_test +class TestOldScripts: + def test_esptool_py(self): + output = subprocess.check_output(["esptool.py", "-h"]) + decoded = output.decode("utf-8") + assert "esptool.py" in decoded + assert "DEPRECATED" in decoded + + def test_espefuse_py(self): + output = subprocess.check_output(["espefuse.py", "-h"]) + decoded = output.decode("utf-8") + assert "espefuse.py" in decoded + assert "DEPRECATED" in decoded + + def test_espsecure_py(self): + output = subprocess.check_output(["espsecure.py", "-h"]) + decoded = output.decode("utf-8") + assert "espsecure.py" in decoded + assert "DEPRECATED" in decoded + + def test_esp_rfc2217_server_py(self): + output = subprocess.check_output(["esp_rfc2217_server.py", "-h"]) + decoded = output.decode("utf-8") + assert "esp_rfc2217_server.py" in decoded + assert "DEPRECATED" in decoded diff --git a/tools/esptool_py/test/test_esptool_sdm.py b/tools/esptool_py/test/test_esptool_sdm.py index eacf107d59..7e1442501d 100644 --- a/tools/esptool_py/test/test_esptool_sdm.py +++ b/tools/esptool_py/test/test_esptool_sdm.py @@ -1,4 +1,4 @@ -# Unit tests (really integration tests) for esptool.py using the pytest framework +# Unit tests (really integration tests) for esptool using the pytest framework # Uses a device in the Secure Download Mode connected to the serial port. # # RUNNING THIS WILL MESS UP THE DEVICE'S SPI FLASH CONTENTS @@ -8,7 +8,7 @@ # Run with a physical connection to a chip: # - `pytest test_esptool_sdm.py --chip esp32 --port /dev/ttyUSB0 --baud 115200` # -# where - --port - a serial port for esptool.py operation +# where - --port - a serial port for esptool operation # - --chip - ESP chip name # - --baud - baud rate # - --with-trace - trace all interactions (True or False) @@ -22,48 +22,49 @@ class TestSecureDownloadMode(EsptoolTestCase): expected_chip_name = esptool.util.expand_chip_name(arg_chip) + @pytest.mark.skipif( + arg_chip in ("esp8266", "esp32"), + reason="No get-security-info on ESP8266 and ESP32", + ) def test_auto_detect(self): - output = self.run_esptool_error("flash_id", chip="auto") + output = self.run_esptool("get-security-info", chip="auto") - if arg_chip in ["esp32", "esp32s2"]: # no autodetection with get_security_info + if arg_chip == "esp32s2": # no autodetection from security info, only magic no. assert "Secure Download Mode is enabled" in output - assert "Unsupported detection protocol" in output + assert "autodetection will not work" in output else: - assert "Unsupported detection protocol" not in output assert f"Detecting chip type... {self.expected_chip_name}" in output - assert "Stub loader is not supported in Secure Download Mode" in output assert ( - f"Chip is {self.expected_chip_name} in Secure Download Mode" in output + f"{'Chip type:':<20}{self.expected_chip_name} " + "in Secure Download Mode" in output ) # Commands not supported in SDM def test_sdm_incompatible_commands(self): - output = self.run_esptool_error("flash_id") # flash_id - assert "This command (0xa) is not supported in Secure Download Mode" in output + output = self.run_esptool_error("flash-id") # flash-id + assert "The 'flash-id' command is not available" in output - output = self.run_esptool_error("read_flash 0 10 out.bin") # read_flash - assert "This command (0xe) is not supported in Secure Download Mode" in output - - output = self.run_esptool_error("erase_flash") # erase_flash - assert ( - f"{self.expected_chip_name} ROM does not support function erase_flash" - in output - ) + output = self.run_esptool_error("read-flash 0 10 out.bin") # read-flash + assert "The 'read-flash' command is not available" in output # Commands supported in SDM def test_sdm_compatible_commands(self): - output = self.run_esptool("write_flash 0x0 images/one_kb.bin") # write_flash + output = self.run_esptool("write-flash 0x0 images/one_kb.bin") # write-flash assert "Security features enabled, so not changing any flash settings" in output assert "Wrote 1024 bytes" in output assert "Hash of data verified." not in output # Verification not supported output = self.run_esptool_error( - "write_flash --flash_size detect 0x0 images/one_kb.bin" + "write-flash --flash-size detect 0x0 images/one_kb.bin" ) assert ( "Detecting flash size is not supported in secure download mode." in output ) - if arg_chip != "esp32": # esp32 does not support get_security_info - output = self.run_esptool("get_security_info") # get_security_info + output = self.run_esptool("erase-region 0 4096") # erase-region + assert "Stub flasher is not supported in Secure Download Mode" in output + assert "Flash memory region erased successfully" in output + + if arg_chip != "esp32": # esp32 does not support get-security-info + output = self.run_esptool("get-security-info") assert "Security Information:" in output diff --git a/tools/esptool_py/test/test_image_info.py b/tools/esptool_py/test/test_image_info.py index f84c624737..c83ce4367f 100755 --- a/tools/esptool_py/test/test_image_info.py +++ b/tools/esptool_py/test/test_image_info.py @@ -25,8 +25,8 @@ def read_image(filename): @pytest.mark.host_test class TestImageInfo: - def run_image_info(self, chip, file, version=None): - """Runs image_info on a binary file. + def run_image_info(self, chip, file): + """Runs image-info on a binary file. Returns the command output. Filenames are relative to the 'test/images' directory. """ @@ -37,49 +37,27 @@ def run_image_info(self, chip, file, version=None): "esptool", "--chip", chip, - "image_info", + "image-info", ] - if version is not None: - cmd += ["--version", str(version)] # if path was passed use the whole path # if file does not exists try to use file from IMAGES_DIR directory cmd += [file] if os.path.isfile(file) else ["".join([IMAGES_DIR, os.sep, file])] print("\nExecuting {}".format(" ".join(cmd))) try: - output = subprocess.check_output(cmd) + output = subprocess.check_output(cmd, stderr=subprocess.STDOUT) output = output.decode("utf-8") print(output) # for more complete stdout logs on failure - assert ( - "warning" not in output.lower() - ), "image_info should not output warnings" + assert "warning" not in output.lower(), ( + "image-info should not output warnings" + ) return output except subprocess.CalledProcessError as e: print(e.output) raise - def test_v1_esp32(self): - out = self.run_image_info("esp32", "bootloader_esp32.bin") - assert "Entry point: 4009816c" in out, "Wrong entry point" - assert "Checksum: 83 (valid)" in out, "Invalid checksum" - assert "4 segments" in out, "Wrong number of segments" - assert ( - "Segment 3: len 0x01068 load 0x40078000 file_offs 0x00000b64 [CACHE_APP]" - in out - ), "Wrong segment info" - - def test_v1_esp8266(self): - out = self.run_image_info("esp8266", ESP8266_BIN) - assert "Image version: 1" in out, "Wrong image version" - assert "Entry point: 40101844" in out, "Wrong entry point" - assert "Checksum: 6b (valid)" in out, "Invalid checksum" - assert "1 segments" in out, "Wrong number of segments" - assert ( - "Segment 1: len 0x00014 load 0x40100000 file_offs 0x00000008 [IRAM]" in out - ), "Wrong segment info" - - def test_v2_esp32c3(self): - out = self.run_image_info("esp32c3", "bootloader_esp32c3.bin", "2") + def test_esp32c3(self): + out = self.run_image_info("esp32c3", "bootloader_esp32c3.bin") # Header assert "Entry point: 0x403c0000" in out, "Wrong entry point" @@ -100,9 +78,9 @@ def test_v2_esp32c3(self): assert "Maximal chip revision: v0.0" in out, "Wrong min revision" # Segments - assert ( - "1 0x01864 0x3fcd6114 0x00000034 DRAM, BYTE_ACCESSIBLE" in out - ), "Wrong segment info" + assert "1 0x01864 0x3fcd6114 0x00000034 DRAM, BYTE_ACCESSIBLE" in out, ( + "Wrong segment info" + ) # Footer assert "Checksum: 0x77 (valid)" in out, "Invalid checksum" @@ -117,8 +95,8 @@ def test_v2_esp32c3(self): if ex_hdr[15] == 1: # Hash appended assert "Validation hash: 4faeab1bd3fd" in out, "Invalid hash" - def test_v2_esp8266(self): - out = self.run_image_info("esp8266", ESP8266_BIN, "2") + def test_esp8266(self): + out = self.run_image_info("esp8266", ESP8266_BIN) assert "Image version: 1" in out, "Wrong image version" assert "Entry point: 0x40101844" in out, "Wrong entry point" assert "Flash size: 512KB" in out, "Wrong flash size" @@ -129,46 +107,41 @@ def test_v2_esp8266(self): assert "0 0x00014 0x40100000 0x00000008 IRAM" in out, "Wrong segment info" def test_image_type_detection(self): - # ESP8266, version 1 and 2 - out = self.run_image_info("auto", ESP8266_BIN, "1") - assert "Detected image type: ESP8266" in out - assert "Segment 1: len 0x00014" in out - out = self.run_image_info("auto", ESP8266_BIN, "2") + # ESP8266 + out = self.run_image_info("auto", ESP8266_BIN) assert "Detected image type: ESP8266" in out assert "Flash freq: 40m" in out - out = self.run_image_info("auto", "esp8266_deepsleep.bin", "2") + out = self.run_image_info("auto", "esp8266_deepsleep.bin") assert "Detected image type: ESP8266" in out # ESP32, with and without detection - out = self.run_image_info("auto", "bootloader_esp32.bin", "2") + out = self.run_image_info("auto", "bootloader_esp32.bin") assert "Detected image type: ESP32" in out - out = self.run_image_info( - "auto", "ram_helloworld/helloworld-esp32_edit.bin", "2" - ) + out = self.run_image_info("auto", "ram_helloworld/helloworld-esp32_edit.bin") assert "Detected image type: ESP32" in out - out = self.run_image_info("esp32", "bootloader_esp32.bin", "2") + out = self.run_image_info("esp32", "bootloader_esp32.bin") assert "Detected image type: ESP32" not in out # ESP32-C3 - out = self.run_image_info("auto", "bootloader_esp32c3.bin", "2") + out = self.run_image_info("auto", "bootloader_esp32c3.bin") assert "Detected image type: ESP32-C3" in out # ESP32-S3 - out = self.run_image_info("auto", "esp32s3_header.bin", "2") + out = self.run_image_info("auto", "esp32s3_header.bin") assert "Detected image type: ESP32-S3" in out def test_invalid_image_type_detection(self, capsys): with pytest.raises(subprocess.CalledProcessError): # Invalid image - self.run_image_info("auto", "one_kb.bin", "2") + self.run_image_info("auto", "one_kb.bin") assert ( "This is not a valid image (invalid magic number: 0xed)" in capsys.readouterr().out ) def test_application_info(self): - out = self.run_image_info("auto", "esp_idf_blink_esp32s2.bin", "2") - assert "Application information" in out + out = self.run_image_info("auto", "esp_idf_blink_esp32s2.bin") + assert "Application Information" in out assert "Project name: blink" in out assert "App version: qa-test-v5.0-20220830-4-g4532e6" in out assert "Secure version: 0" in out @@ -178,25 +151,25 @@ def test_application_info(self): assert "cd0dab311febb0a3ea79eaa223ac2b0" in out assert "ESP-IDF: v5.0-beta1-427-g4532e6e0b2-dirt" in out # No application info in image - out = self.run_image_info("auto", "bootloader_esp32.bin", "2") - assert "Application information" not in out - out = self.run_image_info("auto", ESP8266_BIN, "2") - assert "Application information" not in out + out = self.run_image_info("auto", "bootloader_esp32.bin") + assert "Application Information" not in out + out = self.run_image_info("auto", ESP8266_BIN) + assert "Application Information" not in out def test_bootloader_info(self): # This bootloader binary is built from "hello_world" project # with default settings, IDF version is v5.2. - out = self.run_image_info("esp32", "bootloader_esp32_v5_2.bin", "2") - assert "File size: 26768 (bytes)" in out - assert "Bootloader information" in out + out = self.run_image_info("esp32", "bootloader_esp32_v5_2.bin") + assert "Image size: 26768 bytes" in out + assert "Bootloader Information" in out assert "Bootloader version: 1" in out assert "ESP-IDF: v5.2-dev-254-g1950b15" in out assert "Compile time: Apr 25 2023 00:13:32" in out def test_intel_hex(self): - # This bootloader binary is built from "hello_world" project - # with default settings, IDF version is v5.2. - # File is converted to Intel Hex using merge_bin + # Convert and merge two files to Intel Hex using merge-bin + # Run image-info on the resulting Intel Hex file + # Verify that image info is shown for both files def convert_bin2hex(file): subprocess.check_output( @@ -205,12 +178,14 @@ def convert_bin2hex(file): "-m", "esptool", "--chip", - "esp32", - "merge_bin", + "esp32c3", + "merge-bin", "--format", "hex", "0x0", - "".join([IMAGES_DIR, os.sep, "bootloader_esp32_v5_2.bin"]), + os.path.join(IMAGES_DIR, "bootloader_esp32c3.bin"), + "0x8000", + os.path.join(IMAGES_DIR, "esp32c3_header_min_rev.bin"), "-o", file, ] @@ -219,12 +194,13 @@ def convert_bin2hex(file): fd, file = tempfile.mkstemp(suffix=".hex") try: convert_bin2hex(file) - out = self.run_image_info("esp32", file, "2") - assert "File size: 26768 (bytes)" in out - assert "Bootloader information" in out - assert "Bootloader version: 1" in out - assert "ESP-IDF: v5.2-dev-254-g1950b15" in out - assert "Compile time: Apr 25 2023 00:13:32" in out + out = self.run_image_info("esp32c3", file) + assert ( + "Merged binary image detected. Processing each file individually." + in out + ) + assert "Processing file 1/2, offset: 0x0, size: 17744 bytes" in out + assert "Processing file 2/2, offset: 0x8000, size: 48 bytes" in out finally: try: # make sure that file was closed before removing it diff --git a/tools/esptool_py/test/test_imagegen.py b/tools/esptool_py/test/test_imagegen.py index 5dfbce29c7..ea17e18d8e 100755 --- a/tools/esptool_py/test/test_imagegen.py +++ b/tools/esptool_py/test/test_imagegen.py @@ -5,6 +5,7 @@ import struct import subprocess import sys +import math from conftest import need_to_install_package_err @@ -77,9 +78,9 @@ def assertImageDoesNotContainSection(self, image, elf, section_name): print( f"comparing seg {seg.addr:#x} sec {sh_addr:#x} len {len(data):#x}" ) - assert ( - seg.addr != sh_addr - ), f"{section_name} should not be in the binary image" + assert seg.addr != sh_addr, ( + f"{section_name} should not be in the binary image" + ) def assertImageContainsSection(self, image, elf, section_name): """ @@ -102,9 +103,9 @@ def assertImageContainsSection(self, image, elf, section_name): ) if seg.addr == sh_addr: overlap_len = min(len(seg.data), len(data)) - assert ( - data[:overlap_len] == seg.data[:overlap_len] - ), f"ELF '{section_name}' section has mis-matching bin image data" + assert data[:overlap_len] == seg.data[:overlap_len], ( + f"ELF '{section_name}' section has mis-matching bin image data" + ) sh_addr += overlap_len data = data[overlap_len:] @@ -116,10 +117,10 @@ def assertImageContainsSection(self, image, elf, section_name): def assertImageInfo(self, binpath, chip="esp8266", assert_sha=False): """ - Run esptool.py image_info on a binary file, + Run esptool image-info on a binary file, assert no red flags about contents. """ - cmd = [sys.executable, "-m", "esptool", "--chip", chip, "image_info", binpath] + cmd = [sys.executable, "-m", "esptool", "--chip", chip, "image-info", binpath] try: output = subprocess.check_output(cmd) output = output.decode("utf-8") @@ -127,18 +128,20 @@ def assertImageInfo(self, binpath, chip="esp8266", assert_sha=False): except subprocess.CalledProcessError as e: print(e.output) raise - assert re.search( - r"Checksum: [a-fA-F0-9]{2} \(valid\)", output - ), "Checksum calculation should be valid" + assert re.search(r"Checksum: 0x[a-fA-F0-9]{2} \(valid\)", output), ( + "Checksum calculation should be valid" + ) if assert_sha: - assert re.search( - r"Validation Hash: [a-fA-F0-9]{64} \(valid\)", output - ), "SHA256 should be valid" - assert ( - "warning" not in output.lower() - ), "Should be no warnings in image_info output" - - def run_elf2image(self, chip, elf_path, version=None, extra_args=[]): + assert re.search(r"Validation hash: [a-fA-F0-9]{64} \(valid\)", output), ( + "SHA256 should be valid" + ) + assert "warning" not in output.lower(), ( + "Should be no warnings in image-info output" + ) + + def run_elf2image( + self, chip, elf_path, version=None, extra_args=[], allow_warnings=False + ): """Run elf2image on elf_path""" cmd = [sys.executable, "-m", "esptool", "--chip", chip, "elf2image"] if version is not None: @@ -146,12 +149,13 @@ def run_elf2image(self, chip, elf_path, version=None, extra_args=[]): cmd += [elf_path] + extra_args print("\nExecuting {}".format(" ".join(cmd))) try: - output = subprocess.check_output(cmd) + output = subprocess.check_output(cmd, stderr=subprocess.STDOUT) output = output.decode("utf-8") print(output) - assert ( - "warning" not in output.lower() - ), "elf2image should not output warnings" + if not allow_warnings: + assert "warning" not in output.lower(), ( + "elf2image should not output warnings" + ) except subprocess.CalledProcessError as e: print(e.output) raise @@ -169,17 +173,17 @@ def setup_class(self): @classmethod def teardown_class(self): - super(TestESP8266V1Image, self).teardown_class() try_delete(self.BIN_LOAD) try_delete(self.BIN_IROM) + super(TestESP8266V1Image, self).teardown_class() def test_irom_bin(self): with open(self.ELF, "rb") as f: e = ELFFile(f) irom_section = e.get_section_by_name(".irom0.text") - assert ( - irom_section.header.sh_size == os.stat(self.BIN_IROM).st_size - ), "IROM raw binary file should be same length as .irom0.text section" + assert irom_section.header.sh_size == os.stat(self.BIN_IROM).st_size, ( + "IROM raw binary file should be same length as .irom0.text section" + ) def test_loaded_sections(self): image = esptool.bin_image.LoadFirmwareImage("esp8266", self.BIN_LOAD) @@ -326,11 +330,11 @@ def test_use_segments(self): # this ELF will produce 8 segments in the bin image = self._test_elf2image(ELF, BIN) # Adjacent sections are now merged, len(image.segments) should - # equal 5 (instead of 8). - assert len(image.segments) == 5 + # equal 4 (instead of 8). + assert len(image.segments) == 4 - # --use_segments uses ELF segments(phdrs), produces just 2 segments in the bin - image = self._test_elf2image(ELF, BIN, ["--use_segments"]) + # --use-segments uses ELF segments(phdrs), produces just 2 segments in the bin + image = self._test_elf2image(ELF, BIN, ["--use-segments"]) assert len(image.segments) == 2 def test_ram_only_header(self): @@ -350,7 +354,7 @@ def test_2mb(self): "esp8266", ELF, version=2, - extra_args=["--flash_size", "2MB", "--flash_mode", "dio"], + extra_args=["--flash-size", "2MB", "--flash-mode", "dio"], ) with open(BIN, "rb") as f: header = f.read(4) @@ -371,9 +375,9 @@ def test_16mb(self): "esp32", ELF, extra_args=[ - "--flash_size", + "--flash-size", "16MB", - "--flash_mode", + "--flash-mode", "dio", "--min-rev", "1", @@ -390,15 +394,16 @@ def test_16mb(self): class TestELFSHA256(BaseTestCase): - ELF = "esp32-app-cust-ver-info.elf" + ELF = "esp32c6-appdesc.elf" SHA_OFFS = 0xB0 # absolute offset of the SHA in the .bin file - BIN = "esp32-app-cust-ver-info.bin" + BIN = "esp32c6-appdesc.bin" """ - esp32-app-cust-ver-info.elf was built with the following application version info: + esp32c6-appdesc.elf was built with the following application version info: - const __attribute__((section(".rodata_desc"))) esp_app_desc_t esp_app_desc = { - .magic_word = 0xffffffff, + __attribute__((section(".flash.appdesc"))) + esp_app_desc_t my_app_desc = { + .magic_word = 0xABCD5432, .secure_version = 0xffffffff, .reserv1 = {0xffffffff, 0xffffffff}, .version = "_______________________________", @@ -406,21 +411,28 @@ class TestELFSHA256(BaseTestCase): .time = "xxxxxxxxxxxxxxx", .date = "yyyyyyyyyyyyyyy", .idf_ver = "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz", - .app_elf_sha256 = - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - .reserv2 = {0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff}, + .app_elf_sha256 = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }, + .min_efuse_blk_rev_full = 0xffff, + .max_efuse_blk_rev_full = 0xffff, + .mmu_page_size = 0, + .reserv3 = {0xff, 0xff, 0xff}, + .reserv2 = { + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff + }, }; This leaves zeroes only for the fields of SHA-256 and the test will fail if the placement of zeroes are tested at the wrong place. - 00000000: e907 0020 780f 0840 ee00 0000 0000 0000 ... x..@........ - 00000010: 0000 0000 0000 0001 2000 403f 605a 0000 ........ .@?`Z.. - 00000020: ffff ffff ffff ffff ffff ffff ffff ffff ................ + 00000000: e901 0000 2000 0042 ee00 0000 0d00 0000 .... ..B........ + 00000010: 00ff ff00 0000 0001 2000 0042 0001 0000 ........ ..B.... + 00000020: 3254 cdab ffff ffff ffff ffff ffff ffff 2T.............. 00000030: 5f5f 5f5f 5f5f 5f5f 5f5f 5f5f 5f5f 5f5f ________________ 00000040: 5f5f 5f5f 5f5f 5f5f 5f5f 5f5f 5f5f 5f00 _______________. 00000050: 2d2d 2d2d 2d2d 2d2d 2d2d 2d2d 2d2d 2d2d ---------------- @@ -431,37 +443,46 @@ class TestELFSHA256(BaseTestCase): 000000a0: 7a7a 7a7a 7a7a 7a7a 7a7a 7a7a 7a7a 7a00 zzzzzzzzzzzzzzz. 000000b0: 0000 0000 0000 0000 0000 0000 0000 0000 ................ SHA-256 here 000000c0: 0000 0000 0000 0000 0000 0000 0000 0000 ................ - 000000d0: ffff ffff ffff ffff ffff ffff ffff ffff ................ + 000000d0: ffff ffff 00ff ffff ffff ffff ffff ffff ................ 000000e0: ffff ffff ffff ffff ffff ffff ffff ffff ................ 000000f0: ffff ffff ffff ffff ffff ffff ffff ffff ................ 00000100: ffff ffff ffff ffff ffff ffff ffff ffff ................ 00000110: ffff ffff ffff ffff ffff ffff ffff ffff ................ - 00000120: 6370 755f 7374 6172 7400 0000 1b5b 303b cpu_start....[0; """ - def test_binary_patched(self): + def verify_sha256(self, elf_path, bin_path): + image = esptool.bin_image.LoadFirmwareImage("esp32c6", bin_path) + rodata_segment = image.segments[0] + bin_sha256 = rodata_segment.data[ + self.SHA_OFFS - 0x20 : self.SHA_OFFS - 0x20 + 32 + ] # subtract 0x20 byte header here + + with open(elf_path, "rb") as f: + elf_computed_sha256 = hashlib.sha256(f.read()).digest() + + with open(bin_path, "rb") as f: + f.seek(self.SHA_OFFS) + bin_sha256_raw = f.read(len(elf_computed_sha256)) + + assert elf_computed_sha256 == bin_sha256 + assert elf_computed_sha256 == bin_sha256_raw + + def test_binary_patched_parameter(self): try: self.run_elf2image( - "esp32", + "esp32c6", self.ELF, extra_args=["--elf-sha256-offset", f"{self.SHA_OFFS:#x}"], ) - image = esptool.bin_image.LoadFirmwareImage("esp32", self.BIN) - rodata_segment = image.segments[0] - bin_sha256 = rodata_segment.data[ - self.SHA_OFFS - 0x20 : self.SHA_OFFS - 0x20 + 32 - ] # subtract 0x20 byte header here - - with open(self.ELF, "rb") as f: - elf_computed_sha256 = hashlib.sha256(f.read()).digest() - - with open(self.BIN, "rb") as f: - f.seek(self.SHA_OFFS) - bin_sha256_raw = f.read(len(elf_computed_sha256)) + self.verify_sha256(self.ELF, self.BIN) + finally: + try_delete(self.BIN) - assert elf_computed_sha256 == bin_sha256 - assert elf_computed_sha256 == bin_sha256_raw + def test_binary_patched(self): + try: + self.run_elf2image("esp32c6", self.ELF) + self.verify_sha256(self.ELF, self.BIN) finally: try_delete(self.BIN) @@ -516,3 +537,99 @@ def test_hash_append(self): assert bin_without_hash[self.HASH_APPEND_OFFSET] == 0 assert bytes(expected_bin_without_hash) == bin_without_hash + + +class TestMMUPageSize(BaseTestCase): + def test_appdesc_aligned(self, capsys): + ELF = "esp32c6-appdesc.elf" + BIN = "esp32c6-appdesc.bin" + try: + self.run_elf2image("esp32c6", ELF) + output = capsys.readouterr().out + print(output) + assert "MMU page size not specified, set to 64 KB" in output + finally: + try_delete(BIN) + + @staticmethod + def _modify_section_address(elf_path, section_name, address_offset): + with open(elf_path, "rb+") as f: + elf = ELFFile(f) + section = elf.get_section_by_name(section_name) + + if not section: + raise ValueError(f"Section {section_name} not found") + + # This finds the index of the specified section in the ELF file, + # compute the section header’s position in the file (using section index, + # the section header table’s offset and section header entry size) and then + # modify the section’s address in memory by the specified offset. + index = elf.get_section_index(section_name) + sh_entry_offset = elf.header["e_shoff"] + index * elf.header["e_shentsize"] + section.header.sh_addr += address_offset + + # Write modified header to file + f.seek(sh_entry_offset) + f.write(elf.structs.Elf_Shdr.build(section.header)) + + def test_appdesc_not_aligned(self, capsys): + ELF = "esp32c6-appdesc.elf" + BIN = "esp32c6-appdesc.bin" + ADDRESS_OFFSET = 4 # 4 bytes is minimum allowed + + self._modify_section_address(ELF, ".flash.appdesc", ADDRESS_OFFSET) + try: + self.run_elf2image("esp32c6", ELF, allow_warnings=True) + output = capsys.readouterr().out + print(output) + assert ( + "App description segment is not aligned to MMU page size, probably " + "linker script issue or wrong MMU page size. " + "Try to set MMU page size parameter manually." in output + ) + finally: + # Restore original address to be able to run other tests + self._modify_section_address(ELF, ".flash.appdesc", -ADDRESS_OFFSET) + try_delete(BIN) + + @staticmethod + def _change_appdesc_mmu_page_size(elf_path, mmu_page_size): + """ + Change the MMU page size in the appdesc section of the ELF file. + The following values can be chosen: 0 (empty), 8192, 16384, 32768, 65536. + The numbers are not valid for all chips, so refer to the documentation + of the chip being used. + """ + with open(elf_path, "rb+") as f: + elf = ELFFile(f) + section = elf.get_section_by_name(".flash.appdesc") + + if not section: + raise ValueError("Section .flash.appdesc not found") + + # The mmu_page_size is a power of 2, so we convert it to the corresponding + # value for the appdesc section. It can also be empty (0). + if mmu_page_size == 0: + mmu_page_size_appdesc = 0 + else: + mmu_page_size_appdesc = int(math.log2(mmu_page_size)) + + # Go to the mmu_page_size field in the appdesc section (at offset 0xB4) and + # modify it + f.seek(section.header.sh_offset + 0xB4) + f.write(mmu_page_size_appdesc.to_bytes(4, byteorder="little")) + + def test_appdesc_data(self, capsys): + ELF = "esp32c6-appdesc.elf" + BIN = "esp32c6-appdesc.bin" + MMU_PAGE_SIZE = 65536 + + self._change_appdesc_mmu_page_size(ELF, MMU_PAGE_SIZE) + try: + self.run_elf2image("esp32c6", ELF) + output = capsys.readouterr().out + assert "MMU page size" not in output + print(output) + finally: + self._change_appdesc_mmu_page_size(ELF, 0) + try_delete(BIN) diff --git a/tools/esptool_py/test/test_logger.py b/tools/esptool_py/test/test_logger.py new file mode 100644 index 0000000000..aebe3c7bf1 --- /dev/null +++ b/tools/esptool_py/test/test_logger.py @@ -0,0 +1,154 @@ +import pytest +from io import StringIO +from unittest.mock import patch +from esptool import __version__ +from esptool.logger import EsptoolLogger, log, TemplateLogger +from esptool.cmds import version + + +# Custom logger that implements all methods +class CustomLogger(TemplateLogger): + def print(self, *args, **kwargs): + print("Custom logger:", *args, **kwargs) + + def note(self, message: str): + """ + Logs a Note: message. + """ + pass + + def warning(self, message: str): + """ + Logs a Warning: message. + """ + pass + + def error(self, message: str): + """ + Logs an error message. + """ + pass + + def stage(self, finish=False): + pass + + def progress_bar( + self, + cur_iter: int, + total_iters: int, + prefix: str = "", + suffix: str = "", + bar_length: int = 30, + ): + pass + + def set_verbosity(self, verbosity: str): + pass + + +# Custom logger that doesn't implement all methods +class CustomLoggerIncomplete: + def print(self, *args, **kwargs): + pass + + +@pytest.mark.host_test +class TestLogger: + @pytest.fixture + def logger(self): + log = EsptoolLogger() + log._set_smart_features(True) + return log + + def test_singleton(self, logger): + logger2 = EsptoolLogger() + assert logger is logger2 + assert logger is log + + def test_print(self, logger): + with patch("sys.stdout", new=StringIO()) as fake_out: + logger.print("With newline") + logger.print("Without newline", end="") + assert fake_out.getvalue() == "With newline\nWithout newline" + + def test_note_message(self, logger): + with patch("sys.stdout", new=StringIO()) as fake_out: + logger.note("This is a note") + assert ( + fake_out.getvalue() + == f"{logger.ansi_blue}Note:{logger.ansi_normal} This is a note\n" + ) + + def test_warning_message(self, logger): + with patch("sys.stdout", new=StringIO()) as fake_out: + logger.warning("This is a warning") + assert ( + fake_out.getvalue() + == f"{logger.ansi_yellow}Warning:{logger.ansi_normal} " + "This is a warning\n" + ) + + def test_error_message(self, logger): + with patch("sys.stderr", new=StringIO()) as fake_out: + logger.error("This is an error") + assert ( + fake_out.getvalue() + == f"{logger.ansi_red}This is an error{logger.ansi_normal}\n" + ) + + def test_stage(self, logger): + with patch("sys.stdout", new=StringIO()) as fake_out: + logger.stage() + assert logger._stage_active + logger.print("Line1") + logger.print("Line2") + logger.stage(finish=True) + assert not logger._stage_active + logger.print("Line3") + + output = fake_out.getvalue() + assert f"{logger.ansi_line_up}{logger.ansi_line_clear}" * 2 in output + assert "Line1\nLine2\n" in output + assert "Line1\nLine2\nLine3\n" not in output + + def test_progress_bar(self, logger): + with patch("sys.stdout", new=StringIO()) as fake_out: + logger.progress_bar( + cur_iter=2, + total_iters=4, + prefix="Progress: ", + suffix=" (2/4)", + bar_length=10, + ) + logger.progress_bar( + cur_iter=4, + total_iters=4, + prefix="Progress: ", + suffix=" (4/4)", + bar_length=10, + ) + output = fake_out.getvalue() + assert "Progress: [====> ] 50.0% (2/4)" in output + assert "Progress: [==========] 100.0% (4/4) \n" in output + + def test_set_incomplete_logger(self, logger): + with pytest.raises( + TypeError, + match="'CustomLoggerIncomplete' object layout differs from 'EsptoolLogger'", + ): + logger.set_logger(CustomLoggerIncomplete()) + + def test_set_logger(self, logger): + # Original logger + with patch("sys.stdout", new=StringIO()) as fake_out: + version() # This will log.print the estool version + output = fake_out.getvalue() + assert output == f"{__version__}\n" + + # Replace logger with custom one + with patch("sys.stdout", new=StringIO()) as fake_out: + logger.set_logger(CustomLogger()) + assert isinstance(logger, CustomLogger) + version() # This will use print from CustomLogger + output = fake_out.getvalue() + assert output == f"Custom logger: {__version__}\n" diff --git a/tools/esptool_py/test/test_merge_bin.py b/tools/esptool_py/test/test_merge_bin.py index 75df9bc8b6..d61b902a71 100755 --- a/tools/esptool_py/test/test_merge_bin.py +++ b/tools/esptool_py/test/test_merge_bin.py @@ -32,7 +32,7 @@ def read_image(filename): @pytest.mark.host_test class TestMergeBin: def run_merge_bin(self, chip, offsets_names, options=[], allow_warnings=False): - """Run merge_bin on a list of (offset, filename) tuples + """Run merge-bin on a list of (offset, filename) tuples with output to a named temporary file. Filenames are relative to the 'test/images' directory. @@ -49,7 +49,7 @@ def run_merge_bin(self, chip, offsets_names, options=[], allow_warnings=False): "esptool", "--chip", chip, - "merge_bin", + "merge-bin", "-o", output_file.name, ] + options @@ -63,9 +63,9 @@ def run_merge_bin(self, chip, offsets_names, options=[], allow_warnings=False): output = output.decode("utf-8") print(output) if not allow_warnings: - assert ( - "warning" not in output.lower() - ), "merge_bin should not output warnings" + assert "warning" not in output.lower(), ( + "merge-bin should not output warnings" + ) with open(output_file.name, "rb") as f: return f.read() @@ -78,7 +78,7 @@ def run_merge_bin(self, chip, offsets_names, options=[], allow_warnings=False): def assertAllFF(self, some_bytes): # this may need some improving as the failed assert messages may be # very long and/or useless! - assert b"\xFF" * len(some_bytes) == some_bytes + assert b"\xff" * len(some_bytes) == some_bytes def test_simple_merge(self): merged = self.run_merge_bin( @@ -127,7 +127,7 @@ def test_update_bootloader_params(self): (0x1000, "bootloader_esp32.bin"), (0x10000, "ram_helloworld/helloworld-esp32.bin"), ], - ["--flash_size", "2MB", "--flash_mode", "dout"], + ["--flash-size", "2MB", "--flash-mode", "dout"], ) self.assertAllFF(merged[:0x1000]) @@ -169,9 +169,9 @@ def test_target_offset(self): assert helloworld == merged[0xF000 : 0xF000 + len(helloworld)] self.assertAllFF(merged[0x1000 + len(bootloader) : 0xF000]) - def test_fill_flash_size(self): + def test_pad_to_size(self): merged = self.run_merge_bin( - "esp32c3", [(0x0, "bootloader_esp32c3.bin")], ["--fill-flash-size", "4MB"] + "esp32c3", [(0x0, "bootloader_esp32c3.bin")], ["--pad-to-size", "4MB"] ) bootloader = read_image("bootloader_esp32c3.bin") @@ -179,14 +179,14 @@ def test_fill_flash_size(self): assert bootloader == merged[: len(bootloader)] self.assertAllFF(merged[len(bootloader) :]) - def test_fill_flash_size_w_target_offset(self): + def test_pad_to_size_w_target_offset(self): merged = self.run_merge_bin( "esp32", [ (0x1000, "bootloader_esp32.bin"), (0x10000, "ram_helloworld/helloworld-esp32.bin"), ], - ["--target-offset", "0x1000", "--fill-flash-size", "2MB"], + ["--target-offset", "0x1000", "--pad-to-size", "2MB"], ) # full length is without target-offset arg @@ -215,7 +215,7 @@ def test_merge_mixed(self): merged = self.run_merge_bin( "esp32", [(0x1000, f.name), (0x10000, "ram_helloworld/helloworld-esp32.bin")], - ["--target-offset", "0x1000", "--fill-flash-size", "2MB"], + ["--target-offset", "0x1000", "--pad-to-size", "2MB"], ) finally: os.unlink(f.name) @@ -262,7 +262,7 @@ def test_merge_bin2hex(self): ) source = read_image("bootloader_esp32.bin") # verify that padding was done correctly - assert b"\xFF" * 0x1000 == merged_bin[:0x1000] + assert b"\xff" * 0x1000 == merged_bin[:0x1000] # verify the file itself assert source == merged_bin[0x1000:] @@ -356,7 +356,7 @@ def generate_uf2( "esptool", "--chip", chip_id, - "merge_bin", + "merge-bin", "--format", "uf2", "-o", @@ -372,11 +372,13 @@ def generate_uf2( output = subprocess.check_output(com_args + file_args, stderr=subprocess.STDOUT) output = output.decode("utf-8") print(output) - assert "warning" not in output.lower(), "merge_bin should not output warnings" + assert "warning" not in output.lower(), "merge-bin should not output warnings" - exp_list = [f"Adding {f} at {hex(addr)}" for addr, f in iter_addr_offset_tuples] + exp_list = [ + f"Adding '{f}' at {hex(addr)}" for addr, f in iter_addr_offset_tuples + ] exp_list += [ - f"bytes to file {of_name}, ready to be flashed with any ESP USB Bridge" + f"bytes to file '{of_name}', ready to be flashed with any ESP USB Bridge" ] for e in exp_list: assert e in output diff --git a/tools/esptool_py/test/test_modules.py b/tools/esptool_py/test/test_modules.py index c0bf8de851..547298efea 100755 --- a/tools/esptool_py/test/test_modules.py +++ b/tools/esptool_py/test/test_modules.py @@ -1,5 +1,5 @@ # Tests for regressions in python modules -# used by esptool.py, espefuse.py, and espsecure.py +# used by esptool, espefuse, and espsecure import pytest From 443e3f443936eb8c641070c2893738b1ad09da67 Mon Sep 17 00:00:00 2001 From: Marek Matej Date: Tue, 8 Jul 2025 23:35:36 +0200 Subject: [PATCH 2/3] tools: add flasher_stubs from legacy repository The flasher_stubs folder was removed from the esptool into its own repository as it is deprecated and not recomended for new projects. The new `flasher_stubs` folder is a copy of the repository, https://github.com/espressif/esptool-legacy-flasher-stub Signed-off-by: Marek Matej --- tools/flasher_stub/Makefile | 199 + tools/flasher_stub/README.md | 41 + tools/flasher_stub/compare_stubs.py | 97 + tools/flasher_stub/esptool_test_stub.py | 36 + tools/flasher_stub/include/miniz.h | 1342 +++ tools/flasher_stub/include/rom_functions.h | 382 + tools/flasher_stub/include/slip.h | 40 + tools/flasher_stub/include/soc_support.h | 691 ++ tools/flasher_stub/include/stub_commands.h | 46 + tools/flasher_stub/include/stub_flasher.h | 110 + tools/flasher_stub/include/stub_io.h | 62 + tools/flasher_stub/include/stub_write_flash.h | 34 + tools/flasher_stub/ld/rom_32.ld | 1782 ++++ tools/flasher_stub/ld/rom_32c2.ld | 2960 +++++++ tools/flasher_stub/ld/rom_32c3.ld | 2200 +++++ tools/flasher_stub/ld/rom_32c5.ld | 483 ++ tools/flasher_stub/ld/rom_32c5_beta_3.ld | 429 + tools/flasher_stub/ld/rom_32c6.ld | 487 ++ tools/flasher_stub/ld/rom_32c61.ld | 406 + tools/flasher_stub/ld/rom_32c6_beta.ld | 1951 +++++ tools/flasher_stub/ld/rom_32h2.ld | 428 + tools/flasher_stub/ld/rom_32h2_beta_1.ld | 731 ++ tools/flasher_stub/ld/rom_32h2_beta_2.ld | 1714 ++++ tools/flasher_stub/ld/rom_32p4.ld | 631 ++ tools/flasher_stub/ld/rom_32s2.ld | 1064 +++ tools/flasher_stub/ld/rom_32s3.ld | 2287 +++++ tools/flasher_stub/ld/rom_32s3_beta_2.ld | 2397 ++++++ tools/flasher_stub/ld/rom_8266.ld | 351 + tools/flasher_stub/ld/stub_32.ld | 29 + tools/flasher_stub/ld/stub_32c2.ld | 26 + tools/flasher_stub/ld/stub_32c3.ld | 26 + tools/flasher_stub/ld/stub_32c5.ld | 26 + tools/flasher_stub/ld/stub_32c5_beta_3.ld | 26 + tools/flasher_stub/ld/stub_32c6.ld | 26 + tools/flasher_stub/ld/stub_32c61.ld | 26 + tools/flasher_stub/ld/stub_32c6_beta.ld | 26 + tools/flasher_stub/ld/stub_32h2.ld | 26 + tools/flasher_stub/ld/stub_32h2_beta_1.ld | 26 + tools/flasher_stub/ld/stub_32h2_beta_2.ld | 26 + tools/flasher_stub/ld/stub_32p4.ld | 26 + tools/flasher_stub/ld/stub_32s2.ld | 26 + tools/flasher_stub/ld/stub_32s3.ld | 26 + tools/flasher_stub/ld/stub_32s3_beta_2.ld | 26 + tools/flasher_stub/ld/stub_8266.ld | 32 + tools/flasher_stub/miniz.c | 7657 +++++++++++++++++ tools/flasher_stub/run_tests_with_stub.sh | 10 + tools/flasher_stub/slip.c | 94 + tools/flasher_stub/stub_commands.c | 325 + tools/flasher_stub/stub_flasher.c | 575 ++ tools/flasher_stub/stub_io.c | 318 + tools/flasher_stub/stub_write_flash.c | 640 ++ tools/flasher_stub/wrap_stub.py | 90 + 52 files changed, 33515 insertions(+) create mode 100644 tools/flasher_stub/Makefile create mode 100644 tools/flasher_stub/README.md create mode 100755 tools/flasher_stub/compare_stubs.py create mode 100755 tools/flasher_stub/esptool_test_stub.py create mode 100644 tools/flasher_stub/include/miniz.h create mode 100644 tools/flasher_stub/include/rom_functions.h create mode 100644 tools/flasher_stub/include/slip.h create mode 100644 tools/flasher_stub/include/soc_support.h create mode 100644 tools/flasher_stub/include/stub_commands.h create mode 100644 tools/flasher_stub/include/stub_flasher.h create mode 100644 tools/flasher_stub/include/stub_io.h create mode 100644 tools/flasher_stub/include/stub_write_flash.h create mode 100644 tools/flasher_stub/ld/rom_32.ld create mode 100755 tools/flasher_stub/ld/rom_32c2.ld create mode 100755 tools/flasher_stub/ld/rom_32c3.ld create mode 100755 tools/flasher_stub/ld/rom_32c5.ld create mode 100755 tools/flasher_stub/ld/rom_32c5_beta_3.ld create mode 100755 tools/flasher_stub/ld/rom_32c6.ld create mode 100644 tools/flasher_stub/ld/rom_32c61.ld create mode 100755 tools/flasher_stub/ld/rom_32c6_beta.ld create mode 100755 tools/flasher_stub/ld/rom_32h2.ld create mode 100644 tools/flasher_stub/ld/rom_32h2_beta_1.ld create mode 100644 tools/flasher_stub/ld/rom_32h2_beta_2.ld create mode 100644 tools/flasher_stub/ld/rom_32p4.ld create mode 100755 tools/flasher_stub/ld/rom_32s2.ld create mode 100644 tools/flasher_stub/ld/rom_32s3.ld create mode 100644 tools/flasher_stub/ld/rom_32s3_beta_2.ld create mode 100644 tools/flasher_stub/ld/rom_8266.ld create mode 100644 tools/flasher_stub/ld/stub_32.ld create mode 100644 tools/flasher_stub/ld/stub_32c2.ld create mode 100644 tools/flasher_stub/ld/stub_32c3.ld create mode 100644 tools/flasher_stub/ld/stub_32c5.ld create mode 100644 tools/flasher_stub/ld/stub_32c5_beta_3.ld create mode 100644 tools/flasher_stub/ld/stub_32c6.ld create mode 100644 tools/flasher_stub/ld/stub_32c61.ld create mode 100644 tools/flasher_stub/ld/stub_32c6_beta.ld create mode 100644 tools/flasher_stub/ld/stub_32h2.ld create mode 100644 tools/flasher_stub/ld/stub_32h2_beta_1.ld create mode 100644 tools/flasher_stub/ld/stub_32h2_beta_2.ld create mode 100644 tools/flasher_stub/ld/stub_32p4.ld create mode 100644 tools/flasher_stub/ld/stub_32s2.ld create mode 100644 tools/flasher_stub/ld/stub_32s3.ld create mode 100644 tools/flasher_stub/ld/stub_32s3_beta_2.ld create mode 100644 tools/flasher_stub/ld/stub_8266.ld create mode 100644 tools/flasher_stub/miniz.c create mode 100755 tools/flasher_stub/run_tests_with_stub.sh create mode 100644 tools/flasher_stub/slip.c create mode 100644 tools/flasher_stub/stub_commands.c create mode 100644 tools/flasher_stub/stub_flasher.c create mode 100644 tools/flasher_stub/stub_io.c create mode 100644 tools/flasher_stub/stub_write_flash.c create mode 100755 tools/flasher_stub/wrap_stub.py diff --git a/tools/flasher_stub/Makefile b/tools/flasher_stub/Makefile new file mode 100644 index 0000000000..588d976266 --- /dev/null +++ b/tools/flasher_stub/Makefile @@ -0,0 +1,199 @@ +# Makefile to compile the flasher stub program +# +# Note that YOU DO NOT NEED TO COMPILE THIS IN ORDER TO JUST USE +# esptool.py - a precompiled version is included in esptool.py, +# so if you don't want to modify the stub code then you are good to go. +# +# See the comments in the top of the Makefile for parameters that +# you probably want to override. +# +# Copyright (c) 2016 Cesanta Software Limited & Angus Gratton +# All rights reserved +# +# +# This program is free software; you can redistribute it and/or modify it under +# the terms of the GNU General Public License as published by the Free Software +# Foundation; either version 2 of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along with +# this program; if not, write to the Free Software Foundation, Inc., 51 Franklin +# Street, Fifth Floor, Boston, MA 02110-1301 USA. + +# Adapted from Cesanta's original Makefile at +# https://github.com/cesanta/fnc/tree/master/common/platforms/esp8266/stubs + +# Override these variables on the command line +# or set them in a local.mk +-include local.mk + +# Prefix for each cross compiler (can include a directory path) +# These can be overridden via environment variables or on the make command line +CROSS_8266 ?= xtensa-lx106-elf- +CROSS_32 ?= xtensa-esp32-elf- +CROSS_32S2 ?= xtensa-esp32s2-elf- +CROSS_32S3 ?= xtensa-esp32s3-elf- +CROSS_ESPRISCV32 ?= riscv32-esp-elf- + +# extra CFLAGS to be passed on the compiler, in addition to the stock ones +EXTRA_CFLAGS ?= +EXTRA_CFLAGS_ESPRISCV32 ?= + +# Python command to invoke wrap_stub.py +WRAP_STUB ?= ./wrap_stub.py + +# Pass V=1 to see the commands being executed by make +ifneq ("$(V)","1") +Q = @ +endif + +STUB = esp +SRCS = stub_flasher.c slip.c stub_commands.c stub_write_flash.c stub_io.c +SRCS_8266 = miniz.c + +BUILD_DIR = build +ESPTOOL_STUBS_DIR = .. + +STUB_ELF_8266 = $(BUILD_DIR)/$(STUB)8266.elf +STUB_ELF_32 = $(BUILD_DIR)/$(STUB)32.elf +STUB_ELF_32S2 = $(BUILD_DIR)/$(STUB)32s2.elf +STUB_ELF_32S3_BETA_2 = $(BUILD_DIR)/$(STUB)32s3beta2.elf +STUB_ELF_32S3 = $(BUILD_DIR)/$(STUB)32s3.elf +STUB_ELF_32C3 = $(BUILD_DIR)/$(STUB)32c3.elf +STUB_ELF_32C6BETA = $(BUILD_DIR)/$(STUB)32c6beta.elf +STUB_ELF_32H2_BETA_1 = $(BUILD_DIR)/$(STUB)32h2beta1.elf +STUB_ELF_32H2_BETA_2 = $(BUILD_DIR)/$(STUB)32h2beta2.elf +STUB_ELF_32C2 = $(BUILD_DIR)/$(STUB)32c2.elf +STUB_ELF_32C6 = $(BUILD_DIR)/$(STUB)32c6.elf +STUB_ELF_32C61 = $(BUILD_DIR)/$(STUB)32c61.elf +STUB_ELF_32C5 = $(BUILD_DIR)/$(STUB)32c5.elf +STUB_ELF_32C5_BETA_3 = $(BUILD_DIR)/$(STUB)32c5beta3.elf +STUB_ELF_32H2 = $(BUILD_DIR)/$(STUB)32h2.elf +STUB_ELF_32P4 = $(BUILD_DIR)/$(STUB)32p4.elf + +STUBS_ELF = +ifneq ($(WITHOUT_ESP8266),1) +STUBS_ELF += \ + $(STUB_ELF_8266) +endif + +ifneq ($(WITHOUT_ESP32_XTENSA),1) +STUBS_ELF += \ + $(STUB_ELF_32) \ + $(STUB_ELF_32S2) \ + $(STUB_ELF_32S3_BETA_2) \ + $(STUB_ELF_32S3) +endif + +ifneq ($(WITHOUT_ESP32_RISCV32),1) +STUBS_ELF += \ + $(STUB_ELF_32C3) \ + $(STUB_ELF_32C6BETA) \ + $(STUB_ELF_32H2_BETA_1) \ + $(STUB_ELF_32H2_BETA_2) \ + $(STUB_ELF_32C2) \ + $(STUB_ELF_32C6) \ + $(STUB_ELF_32C61) \ + $(STUB_ELF_32C5) \ + $(STUB_ELF_32C5_BETA_3) \ + $(STUB_ELF_32H2) \ + $(STUB_ELF_32P4) +endif + +.PHONY: all clean install + +all: $(STUBS_ELF:.elf=.json) + +install: $(patsubst $(BUILD_DIR)/%.elf,$(ESPTOOL_STUBS_DIR)/%.json,$(STUBS_ELF)) + +$(BUILD_DIR): + $(Q) mkdir $@ + +$(BUILD_DIR)/%.json: $(BUILD_DIR)/%.elf + @echo " WRAP $^ -> $(BUILD_DIR)" + $(Q) $(WRAP_STUB) $^ + +$(ESPTOOL_STUBS_DIR)/%.json: $(BUILD_DIR)/%.json + @echo " INSTALL $^ -> $@" + $(Q) cp $^ $@ + +CFLAGS = -std=c99 -Wall -Werror -Os \ + -mtext-section-literals -mlongcalls -nostdlib -fno-builtin -flto \ + -Wl,-static -g -ffunction-sections -Wl,--gc-sections -Iinclude -Lld \ + $(EXTRA_CFLAGS) +CFLAGS_ESPRISCV32 = -std=c99 -Wall -Werror -Os \ + -march=rv32imc -mabi=ilp32 -msmall-data-limit=0 \ + -nostdlib -fno-builtin -flto \ + -Wl,-static -g -ffunction-sections -Wl,--gc-sections -Iinclude -Lld \ + $(EXTRA_CFLAGS_ESPRISCV32) +LDLIBS = -lgcc + +$(STUB_ELF_8266): $(SRCS) $(SRCS_8266) $(BUILD_DIR) ld/stub_8266.ld | Makefile + @echo " CC(8266) $^ -> $@" + $(Q) $(CROSS_8266)gcc $(CFLAGS) -DESP8266=1 -Tstub_8266.ld -Wl,-Map=$(@:.elf=.map) -o $@ $(filter %.c, $^) $(LDLIBS) + +$(STUB_ELF_32): $(SRCS) $(BUILD_DIR) ld/stub_32.ld | Makefile + @echo " CC(32) $^ -> $@" + $(Q) $(CROSS_32)gcc $(CFLAGS) -DESP32=1 -Tstub_32.ld -Wl,-Map=$(@:.elf=.map) -o $@ $(filter %.c, $^) $(LDLIBS) + +$(STUB_ELF_32S2): $(SRCS) $(BUILD_DIR) ld/stub_32s2.ld + @echo " CC(32S2) $^ -> $@" + $(Q) $(CROSS_32S2)gcc $(CFLAGS) -DESP32S2=1 -Tstub_32s2.ld -Wl,-Map=$(@:.elf=.map) -o $@ $(filter %.c, $^) $(LDLIBS) + +$(STUB_ELF_32S3_BETA_2): $(SRCS) $(BUILD_DIR) ld/stub_32s3_beta_2.ld + @echo " CC(32S3) $^ -> $@" + $(Q) $(CROSS_32S3)gcc $(CFLAGS) -DESP32S3BETA2=1 -Tstub_32s3_beta_2.ld -Wl,-Map=$(@:.elf=.map) -o $@ $(filter %.c, $^) $(LDLIBS) + +$(STUB_ELF_32S3): $(SRCS) $(BUILD_DIR) ld/stub_32s3.ld + @echo " CC(32S3) $^ -> $@" + $(Q) $(CROSS_32S3)gcc $(CFLAGS) -DESP32S3=1 -Tstub_32s3.ld -Wl,-Map=$(@:.elf=.map) -o $@ $(filter %.c, $^) $(LDLIBS) + +$(STUB_ELF_32C3): $(SRCS) $(BUILD_DIR) ld/stub_32c3.ld + @echo " CC(32C3) $^ -> $@" + $(Q) $(CROSS_ESPRISCV32)gcc $(CFLAGS_ESPRISCV32) -DESP32C3=1 -Tstub_32c3.ld -Wl,-Map=$(@:.elf=.map) -o $@ $(filter %.c, $^) $(LDLIBS) + +$(STUB_ELF_32C6BETA): $(SRCS) $(BUILD_DIR) ld/stub_32c6_beta.ld + @echo " CC(32C6BETA) $^ -> $@" + $(Q) $(CROSS_ESPRISCV32)gcc $(CFLAGS_ESPRISCV32) -DESP32C6BETA=1 -Tstub_32c6_beta.ld -Wl,-Map=$(@:.elf=.map) -o $@ $(filter %.c, $^) $(LDLIBS) + +$(STUB_ELF_32H2_BETA_1): $(SRCS) $(BUILD_DIR) ld/stub_32h2_beta_1.ld + @echo " CC(32H2BETA1) $^ -> $@" + $(Q) $(CROSS_ESPRISCV32)gcc $(CFLAGS_ESPRISCV32) -DESP32H2BETA1=1 -Tstub_32h2_beta_1.ld -Wl,-Map=$(@:.elf=.map) -o $@ $(filter %.c, $^) $(LDLIBS) + +$(STUB_ELF_32H2_BETA_2): $(SRCS) $(BUILD_DIR) ld/stub_32h2_beta_2.ld + @echo " CC(32H2BETA2) $^ -> $@" + $(Q) $(CROSS_ESPRISCV32)gcc $(CFLAGS_ESPRISCV32) -DESP32H2BETA2=1 -Tstub_32h2_beta_2.ld -Wl,-Map=$(@:.elf=.map) -o $@ $(filter %.c, $^) $(LDLIBS) + +$(STUB_ELF_32C2): $(SRCS) $(BUILD_DIR) ld/stub_32c2.ld + @echo " CC(32C2) $^ -> $@" + $(Q) $(CROSS_ESPRISCV32)gcc $(CFLAGS_ESPRISCV32) -DESP32C2=1 -Tstub_32c2.ld -Wl,-Map=$(@:.elf=.map) -o $@ $(filter %.c, $^) $(LDLIBS) + +$(STUB_ELF_32C6): $(SRCS) $(BUILD_DIR) ld/stub_32c6.ld + @echo " CC(32C6) $^ -> $@" + $(Q) $(CROSS_ESPRISCV32)gcc $(CFLAGS_ESPRISCV32) -DESP32C6=1 -Tstub_32c6.ld -Wl,-Map=$(@:.elf=.map) -o $@ $(filter %.c, $^) $(LDLIBS) + +$(STUB_ELF_32C61): $(SRCS) $(BUILD_DIR) ld/stub_32c61.ld + @echo " CC(32C61) $^ -> $@" + $(Q) $(CROSS_ESPRISCV32)gcc $(CFLAGS_ESPRISCV32) -DESP32C61=1 -Tstub_32c61.ld -Wl,-Map=$(@:.elf=.map) -o $@ $(filter %.c, $^) $(LDLIBS) + +$(STUB_ELF_32C5): $(SRCS) $(BUILD_DIR) ld/stub_32c5.ld + @echo " CC(32C5) $^ -> $@" + $(Q) $(CROSS_ESPRISCV32)gcc $(CFLAGS_ESPRISCV32) -DESP32C5=1 -Tstub_32c5.ld -Wl,-Map=$(@:.elf=.map) -o $@ $(filter %.c, $^) $(LDLIBS) + +$(STUB_ELF_32C5_BETA_3): $(SRCS) $(BUILD_DIR) ld/stub_32c5_beta_3.ld + @echo " CC(32C5BETA3) $^ -> $@" + $(Q) $(CROSS_ESPRISCV32)gcc $(CFLAGS_ESPRISCV32) -DESP32C5BETA3=1 -Tstub_32c5_beta_3.ld -Wl,-Map=$(@:.elf=.map) -o $@ $(filter %.c, $^) $(LDLIBS) + +$(STUB_ELF_32H2): $(SRCS) $(BUILD_DIR) ld/stub_32h2.ld + @echo " CC(32H2) $^ -> $@" + $(Q) $(CROSS_ESPRISCV32)gcc $(CFLAGS_ESPRISCV32) -DESP32H2=1 -Tstub_32h2.ld -Wl,-Map=$(@:.elf=.map) -o $@ $(filter %.c, $^) $(LDLIBS) + +$(STUB_ELF_32P4): $(SRCS) $(BUILD_DIR) ld/stub_32p4.ld + @echo " CC(32P4) $^ -> $@" + $(Q) $(CROSS_ESPRISCV32)gcc $(CFLAGS_ESPRISCV32) -DESP32P4=1 -Tstub_32p4.ld -Wl,-Map=$(@:.elf=.map) -o $@ $(filter %.c, $^) $(LDLIBS) + +clean: + $(Q) rm -rf $(BUILD_DIR) diff --git a/tools/flasher_stub/README.md b/tools/flasher_stub/README.md new file mode 100644 index 0000000000..052909c3f5 --- /dev/null +++ b/tools/flasher_stub/README.md @@ -0,0 +1,41 @@ +This is the source of the software flasher stub. + +esptool.py loads the flasher stub into memory and executes it to: + +* Add features that the Espressif chips bootloader ROMs do not have. + +* Add features to the ESP8266 bootloader ROM which are only in the ROM of newer chips. + +* Improve flashing performance over the ROM bootloaders. + +* Work around bugs in the ESP8266 ROM bootloader. + +Thanks to [Cesanta](http://cesanta.com/) who provided the original ESP8266 stub loader upon which this loader is based. + +# To Use + +The stub loader is already automatically integrated into esptool.py. You don't need to do anything special to use it. + +# To Build + +If you want to build the stub to test modifications or updates, here's how: + +* You will need an ESP8266 gcc toolchain (xtensa-lx106-elf-) and toolchains for ESP32 and later chips (xtensa-esp32-elf-, riscv32-esp-elf-) on your PATH. If you are developing the stub flasher and plan to send a pull request, please use the latest toolchains available. + +* Set the environment variables SDK_PATH to the path to an ESP8266 IoT NON-OS SDK directory (last stub was built with SDK v1.5.1). + +* Set the environment variable IDF_PATH to the path to an ESP-IDF directory. + +* Set any other environment variables you'd like to override in the Makefile. + +* To build type `make`. To build only for the ESP32 family, type `make WITHOUT_ESP8266=1` (this negates the need of an ESP8266 toolchain). + +Activating an ESP-IDF environment takes care of most of these steps (only the ESP8266 gcc toolchain has to be manually added to PATH). + +# To Test + +To test the built stub, you can run `make install` (or `make install WITHOUT_ESP8266=1`), which will update the stubs in `esptool.py` to the newly compiled ones. Or there are some convenience wrappers to make testing quicker to iterate on: + +* Running `esptool_test_stub.py` is the same as running `esptool.py`, only it uses the just-compiled stubs from the build directory. + +* Running `run_tests_with_stub.sh` is the same as running `pytest test/test_esptool.py`, only it uses the just-compiled stubs from the build directory. See the [Automated Integration Tests](https://docs.espressif.com/projects/esptool/en/latest/contributing.html#automated-integration-tests) docs for more information. diff --git a/tools/flasher_stub/compare_stubs.py b/tools/flasher_stub/compare_stubs.py new file mode 100755 index 0000000000..74843f0fb4 --- /dev/null +++ b/tools/flasher_stub/compare_stubs.py @@ -0,0 +1,97 @@ +#!/usr/bin/env python +# +# SPDX-FileCopyrightText: 2014-2022 Fredrik Ahlberg, Angus Gratton, +# Espressif Systems (Shanghai) CO LTD, other contributors as noted. +# +# SPDX-License-Identifier: GPL-2.0-or-later + +import os +import sys + +import esptool + +# Compare the esptool stub loaders to freshly built ones in the build directory +# +# (Used by CI to verify the stubs are up to date.) + +THIS_SCRIPT_DIR = os.path.dirname(__file__) +STUB_DIR = "../esptool/targets/stub_flasher/" +BUILD_DIR = "build/" +JSON_NAME = "stub_flasher_{}.json" + + +def diff(path_to_new, path_to_old): + output = "" + new = esptool.loader.StubFlasher(path_to_new) + old = esptool.loader.StubFlasher(path_to_old) + + if new.data_start != old.data_start: + output += " Data start: New {:#x}, old {:#x} \n".format( + new.data_start, old.data_start + ) + if new.text_start != old.text_start: + output += " Text start: New {:#x}, old {:#x} \n".format( + new.text_start, old.text_start + ) + if new.entry != old.entry: + output += " Entrypoint: New {:#x}, old {:#x} \n".format(new.entry, old.entry) + + # data + if new.data != old.data: + if len(new.data) == len(old.data): + for i, (new_b, old_b) in enumerate(zip(new.data, old.data)): + if new_b != old_b: + output += " Data byte {:#x}: new {:#04x} old {:#04x} \n".format( + i, new_b, old_b + ) + else: + output += " Data length: New {} bytes, old {} bytes \n".format( + len(new.data), len(old.data) + ) + + # text + if new.text != old.text: + if len(new.text) == len(old.text): + for i, (new_b, old_b) in enumerate(zip(new.text, old.text)): + if new_b != old_b: + output += " Text byte {:#x}: new {:#04x} old {:#04x} \n".format( + i, new_b, old_b + ) + else: + output += " Text length: New {} bytes, old {} bytes \n".format( + len(new.text), len(old.text) + ) + return output + + +if __name__ == "__main__": + same = True + for chip in esptool.CHIP_LIST: + print("Comparing {} stub: ".format(chip), end="") + # TODO: [ESP32C5] ESPTOOL-825 remove when supported stub flasher + # TODO: [ESP32C61] IDF-9241 remove when supported stub flasher + if chip in ["esp32c5", "esp32c61"]: + print(f"{chip} has not supported stub yet, skipping...") + continue + + chip = chip.replace("esp", "") + old = os.path.join(THIS_SCRIPT_DIR, STUB_DIR, JSON_NAME.format(chip)) + new = os.path.join(THIS_SCRIPT_DIR, BUILD_DIR, JSON_NAME.format(chip)) + + output = diff(new, old) + if output != "": + same = False + print("FAIL") + print( + " Mismatch: {} json file in esptool/targets/stub_flasher/ differs " + "from the just-built stub".format("esp" + chip) + ) + print(output) + else: + print("OK") + + if not same: + sys.exit(1) + else: + print("Stub flasher json files are the same") + sys.exit(0) diff --git a/tools/flasher_stub/esptool_test_stub.py b/tools/flasher_stub/esptool_test_stub.py new file mode 100755 index 0000000000..691495e11b --- /dev/null +++ b/tools/flasher_stub/esptool_test_stub.py @@ -0,0 +1,36 @@ +#!/usr/bin/env python +# +# SPDX-FileCopyrightText: 2014-2022 Fredrik Ahlberg, Angus Gratton, +# Espressif Systems (Shanghai) CO LTD, other contributors as noted. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Trivial wrapper program to run esptool.py using the just-compiled +# flasher stub in the build/ subdirectory +# +# For use when developing new flasher_stubs, not important otherwise. + +import os.path +import sys + +THIS_DIR = os.path.dirname(__file__) +STUBS_BUILD_DIR = os.path.join(THIS_DIR, "build/") + +sys.path.append("..") +import esptool # noqa: E402 + +# Python hackiness: change the path to stub json files in the context of the esptool +# module, so it edits the esptool's global variables +exec( + "loader.STUBS_DIR = '{}'".format(STUBS_BUILD_DIR), + esptool.__dict__, + esptool.__dict__, +) + + +if __name__ == "__main__": + try: + esptool.main() + except esptool.FatalError as e: + print("\nA fatal error occurred: %s" % e) + sys.exit(2) diff --git a/tools/flasher_stub/include/miniz.h b/tools/flasher_stub/include/miniz.h new file mode 100644 index 0000000000..bf1554a06e --- /dev/null +++ b/tools/flasher_stub/include/miniz.h @@ -0,0 +1,1342 @@ +/* miniz.c 2.1.0 - public domain deflate/inflate, zlib-subset, ZIP reading/writing/appending, PNG writing + See "unlicense" statement at the end of this file. + Rich Geldreich , last updated Oct. 13, 2013 + Implements RFC 1950: http://www.ietf.org/rfc/rfc1950.txt and RFC 1951: http://www.ietf.org/rfc/rfc1951.txt + + Most API's defined in miniz.c are optional. For example, to disable the archive related functions just define + MINIZ_NO_ARCHIVE_APIS, or to get rid of all stdio usage define MINIZ_NO_STDIO (see the list below for more macros). + + * Low-level Deflate/Inflate implementation notes: + + Compression: Use the "tdefl" API's. The compressor supports raw, static, and dynamic blocks, lazy or + greedy parsing, match length filtering, RLE-only, and Huffman-only streams. It performs and compresses + approximately as well as zlib. + + Decompression: Use the "tinfl" API's. The entire decompressor is implemented as a single function + coroutine: see tinfl_decompress(). It supports decompression into a 32KB (or larger power of 2) wrapping buffer, or into a memory + block large enough to hold the entire file. + + The low-level tdefl/tinfl API's do not make any use of dynamic memory allocation. + + * zlib-style API notes: + + miniz.c implements a fairly large subset of zlib. There's enough functionality present for it to be a drop-in + zlib replacement in many apps: + The z_stream struct, optional memory allocation callbacks + deflateInit/deflateInit2/deflate/deflateReset/deflateEnd/deflateBound + inflateInit/inflateInit2/inflate/inflateReset/inflateEnd + compress, compress2, compressBound, uncompress + CRC-32, Adler-32 - Using modern, minimal code size, CPU cache friendly routines. + Supports raw deflate streams or standard zlib streams with adler-32 checking. + + Limitations: + The callback API's are not implemented yet. No support for gzip headers or zlib static dictionaries. + I've tried to closely emulate zlib's various flavors of stream flushing and return status codes, but + there are no guarantees that miniz.c pulls this off perfectly. + + * PNG writing: See the tdefl_write_image_to_png_file_in_memory() function, originally written by + Alex Evans. Supports 1-4 bytes/pixel images. + + * ZIP archive API notes: + + The ZIP archive API's where designed with simplicity and efficiency in mind, with just enough abstraction to + get the job done with minimal fuss. There are simple API's to retrieve file information, read files from + existing archives, create new archives, append new files to existing archives, or clone archive data from + one archive to another. It supports archives located in memory or the heap, on disk (using stdio.h), + or you can specify custom file read/write callbacks. + + - Archive reading: Just call this function to read a single file from a disk archive: + + void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename, const char *pArchive_name, + size_t *pSize, mz_uint zip_flags); + + For more complex cases, use the "mz_zip_reader" functions. Upon opening an archive, the entire central + directory is located and read as-is into memory, and subsequent file access only occurs when reading individual files. + + - Archives file scanning: The simple way is to use this function to scan a loaded archive for a specific file: + + int mz_zip_reader_locate_file(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags); + + The locate operation can optionally check file comments too, which (as one example) can be used to identify + multiple versions of the same file in an archive. This function uses a simple linear search through the central + directory, so it's not very fast. + + Alternately, you can iterate through all the files in an archive (using mz_zip_reader_get_num_files()) and + retrieve detailed info on each file by calling mz_zip_reader_file_stat(). + + - Archive creation: Use the "mz_zip_writer" functions. The ZIP writer immediately writes compressed file data + to disk and builds an exact image of the central directory in memory. The central directory image is written + all at once at the end of the archive file when the archive is finalized. + + The archive writer can optionally align each file's local header and file data to any power of 2 alignment, + which can be useful when the archive will be read from optical media. Also, the writer supports placing + arbitrary data blobs at the very beginning of ZIP archives. Archives written using either feature are still + readable by any ZIP tool. + + - Archive appending: The simple way to add a single file to an archive is to call this function: + + mz_bool mz_zip_add_mem_to_archive_file_in_place(const char *pZip_filename, const char *pArchive_name, + const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags); + + The archive will be created if it doesn't already exist, otherwise it'll be appended to. + Note the appending is done in-place and is not an atomic operation, so if something goes wrong + during the operation it's possible the archive could be left without a central directory (although the local + file headers and file data will be fine, so the archive will be recoverable). + + For more complex archive modification scenarios: + 1. The safest way is to use a mz_zip_reader to read the existing archive, cloning only those bits you want to + preserve into a new archive using using the mz_zip_writer_add_from_zip_reader() function (which compiles the + compressed file data as-is). When you're done, delete the old archive and rename the newly written archive, and + you're done. This is safe but requires a bunch of temporary disk space or heap memory. + + 2. Or, you can convert an mz_zip_reader in-place to an mz_zip_writer using mz_zip_writer_init_from_reader(), + append new files as needed, then finalize the archive which will write an updated central directory to the + original archive. (This is basically what mz_zip_add_mem_to_archive_file_in_place() does.) There's a + possibility that the archive's central directory could be lost with this method if anything goes wrong, though. + + - ZIP archive support limitations: + No zip64 or spanning support. Extraction functions can only handle unencrypted, stored or deflated files. + Requires streams capable of seeking. + + * This is a header file library, like stb_image.c. To get only a header file, either cut and paste the + below header, or create miniz.h, #define MINIZ_HEADER_FILE_ONLY, and then include miniz.c from it. + + * Important: For best perf. be sure to customize the below macros for your target platform: + #define MINIZ_USE_UNALIGNED_LOADS_AND_STORES 1 + #define MINIZ_LITTLE_ENDIAN 1 + #define MINIZ_HAS_64BIT_REGISTERS 1 + + * On platforms using glibc, Be sure to "#define _LARGEFILE64_SOURCE 1" before including miniz.c to ensure miniz + uses the 64-bit variants: fopen64(), stat64(), etc. Otherwise you won't be able to process large files + (i.e. 32-bit stat() fails for me on files > 0x7FFFFFFF bytes). +*/ +#pragma once + +/* Hardcoded options for Xtensa - JD */ +#define MINIZ_USE_UNALIGNED_LOADS_AND_STORES 0 +#define MINIZ_LITTLE_ENDIAN 1 + + + + + +/* Defines to completely disable specific portions of miniz.c: + If all macros here are defined the only functionality remaining will be CRC-32, adler-32, tinfl, and tdefl. */ + +/* Define MINIZ_NO_STDIO to disable all usage and any functions which rely on stdio for file I/O. */ +#define MINIZ_NO_STDIO + +/* If MINIZ_NO_TIME is specified then the ZIP archive functions will not be able to get the current time, or */ +/* get/set file times, and the C run-time funcs that get/set times won't be called. */ +/* The current downside is the times written to your archives will be from 1979. */ +#define MINIZ_NO_TIME + +/* Define MINIZ_NO_ARCHIVE_APIS to disable all ZIP archive API's. */ +#define MINIZ_NO_ARCHIVE_APIS + +/* Define MINIZ_NO_ARCHIVE_WRITING_APIS to disable all writing related ZIP archive API's. */ +#define MINIZ_NO_ARCHIVE_WRITING_APIS + +/* Define MINIZ_NO_ZLIB_APIS to remove all ZLIB-style compression/decompression API's. */ +#define MINIZ_NO_ZLIB_APIS + +/* Define MINIZ_NO_ZLIB_COMPATIBLE_NAME to disable zlib names, to prevent conflicts against stock zlib. */ +#define MINIZ_NO_ZLIB_COMPATIBLE_NAMES + +/* Define MINIZ_NO_MALLOC to disable all calls to malloc, free, and realloc. + Note if MINIZ_NO_MALLOC is defined then the user must always provide custom user alloc/free/realloc + callbacks to the zlib and archive API's, and a few stand-alone helper API's which don't provide custom user + functions (such as tdefl_compress_mem_to_heap() and tinfl_decompress_mem_to_heap()) won't work. */ +#define MINIZ_NO_MALLOC + +#if defined(__TINYC__) && (defined(__linux) || defined(__linux__)) +/* TODO: Work around "error: include file 'sys\utime.h' when compiling with tcc on Linux */ +#define MINIZ_NO_TIME +#endif + +#include + +#if !defined(MINIZ_NO_TIME) && !defined(MINIZ_NO_ARCHIVE_APIS) +#include +#endif + +#if defined(_M_IX86) || defined(_M_X64) || defined(__i386__) || defined(__i386) || defined(__i486__) || defined(__i486) || defined(i386) || defined(__ia64__) || defined(__x86_64__) +/* MINIZ_X86_OR_X64_CPU is only used to help set the below macros. */ +#define MINIZ_X86_OR_X64_CPU 1 +#else +#define MINIZ_X86_OR_X64_CPU 0 +#endif + +#if (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) || MINIZ_X86_OR_X64_CPU +/* Set MINIZ_LITTLE_ENDIAN to 1 if the processor is little endian. */ +#define MINIZ_LITTLE_ENDIAN 1 +#else +#define MINIZ_LITTLE_ENDIAN 0 +#endif + +/* Set MINIZ_USE_UNALIGNED_LOADS_AND_STORES only if not set */ +#if !defined(MINIZ_USE_UNALIGNED_LOADS_AND_STORES) +#if MINIZ_X86_OR_X64_CPU +/* Set MINIZ_USE_UNALIGNED_LOADS_AND_STORES to 1 on CPU's that permit efficient integer loads and stores from unaligned addresses. */ +#define MINIZ_USE_UNALIGNED_LOADS_AND_STORES 1 +#define MINIZ_UNALIGNED_USE_MEMCPY +#else +#define MINIZ_USE_UNALIGNED_LOADS_AND_STORES 0 +#endif +#endif + +#if defined(_M_X64) || defined(_WIN64) || defined(__MINGW64__) || defined(_LP64) || defined(__LP64__) || defined(__ia64__) || defined(__x86_64__) +/* Set MINIZ_HAS_64BIT_REGISTERS to 1 if operations on 64-bit integers are reasonably fast (and don't involve compiler generated calls to helper functions). */ +#define MINIZ_HAS_64BIT_REGISTERS 1 +#else +#define MINIZ_HAS_64BIT_REGISTERS 0 +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* ------------------- zlib-style API Definitions. */ + +/* For more compatibility with zlib, miniz.c uses unsigned long for some parameters/struct members. Beware: mz_ulong can be either 32 or 64-bits! */ +typedef unsigned long mz_ulong; + +/* mz_free() internally uses the MZ_FREE() macro (which by default calls free() unless you've modified the MZ_MALLOC macro) to release a block allocated from the heap. */ +void mz_free(void *p); + +#define MZ_ADLER32_INIT (1) +/* mz_adler32() returns the initial adler-32 value to use when called with ptr==NULL. */ +mz_ulong mz_adler32(mz_ulong adler, const unsigned char *ptr, size_t buf_len); + +#define MZ_CRC32_INIT (0) +/* mz_crc32() returns the initial CRC-32 value to use when called with ptr==NULL. */ +mz_ulong mz_crc32(mz_ulong crc, const unsigned char *ptr, size_t buf_len); + +/* Compression strategies. */ +enum +{ + MZ_DEFAULT_STRATEGY = 0, + MZ_FILTERED = 1, + MZ_HUFFMAN_ONLY = 2, + MZ_RLE = 3, + MZ_FIXED = 4 +}; + +/* Method */ +#define MZ_DEFLATED 8 + +/* Heap allocation callbacks. +Note that mz_alloc_func parameter types purpsosely differ from zlib's: items/size is size_t, not unsigned long. */ +typedef void *(*mz_alloc_func)(void *opaque, size_t items, size_t size); +typedef void (*mz_free_func)(void *opaque, void *address); +typedef void *(*mz_realloc_func)(void *opaque, void *address, size_t items, size_t size); + +/* Compression levels: 0-9 are the standard zlib-style levels, 10 is best possible compression (not zlib compatible, and may be very slow), MZ_DEFAULT_COMPRESSION=MZ_DEFAULT_LEVEL. */ +enum +{ + MZ_NO_COMPRESSION = 0, + MZ_BEST_SPEED = 1, + MZ_BEST_COMPRESSION = 9, + MZ_UBER_COMPRESSION = 10, + MZ_DEFAULT_LEVEL = 6, + MZ_DEFAULT_COMPRESSION = -1 +}; + +#define MZ_VERSION "10.1.0" +#define MZ_VERNUM 0xA100 +#define MZ_VER_MAJOR 10 +#define MZ_VER_MINOR 1 +#define MZ_VER_REVISION 0 +#define MZ_VER_SUBREVISION 0 + +#ifndef MINIZ_NO_ZLIB_APIS + +/* Flush values. For typical usage you only need MZ_NO_FLUSH and MZ_FINISH. The other values are for advanced use (refer to the zlib docs). */ +enum +{ + MZ_NO_FLUSH = 0, + MZ_PARTIAL_FLUSH = 1, + MZ_SYNC_FLUSH = 2, + MZ_FULL_FLUSH = 3, + MZ_FINISH = 4, + MZ_BLOCK = 5 +}; + +/* Return status codes. MZ_PARAM_ERROR is non-standard. */ +enum +{ + MZ_OK = 0, + MZ_STREAM_END = 1, + MZ_NEED_DICT = 2, + MZ_ERRNO = -1, + MZ_STREAM_ERROR = -2, + MZ_DATA_ERROR = -3, + MZ_MEM_ERROR = -4, + MZ_BUF_ERROR = -5, + MZ_VERSION_ERROR = -6, + MZ_PARAM_ERROR = -10000 +}; + +/* Window bits */ +#define MZ_DEFAULT_WINDOW_BITS 15 + +struct mz_internal_state; + +/* Compression/decompression stream struct. */ +typedef struct mz_stream_s +{ + const unsigned char *next_in; /* pointer to next byte to read */ + unsigned int avail_in; /* number of bytes available at next_in */ + mz_ulong total_in; /* total number of bytes consumed so far */ + + unsigned char *next_out; /* pointer to next byte to write */ + unsigned int avail_out; /* number of bytes that can be written to next_out */ + mz_ulong total_out; /* total number of bytes produced so far */ + + char *msg; /* error msg (unused) */ + struct mz_internal_state *state; /* internal state, allocated by zalloc/zfree */ + + mz_alloc_func zalloc; /* optional heap allocation function (defaults to malloc) */ + mz_free_func zfree; /* optional heap free function (defaults to free) */ + void *opaque; /* heap alloc function user pointer */ + + int data_type; /* data_type (unused) */ + mz_ulong adler; /* adler32 of the source or uncompressed data */ + mz_ulong reserved; /* not used */ +} mz_stream; + +typedef mz_stream *mz_streamp; + +/* Returns the version string of miniz.c. */ +const char *mz_version(void); + +/* mz_deflateInit() initializes a compressor with default options: */ +/* Parameters: */ +/* pStream must point to an initialized mz_stream struct. */ +/* level must be between [MZ_NO_COMPRESSION, MZ_BEST_COMPRESSION]. */ +/* level 1 enables a specially optimized compression function that's been optimized purely for performance, not ratio. */ +/* (This special func. is currently only enabled when MINIZ_USE_UNALIGNED_LOADS_AND_STORES and MINIZ_LITTLE_ENDIAN are defined.) */ +/* Return values: */ +/* MZ_OK on success. */ +/* MZ_STREAM_ERROR if the stream is bogus. */ +/* MZ_PARAM_ERROR if the input parameters are bogus. */ +/* MZ_MEM_ERROR on out of memory. */ +int mz_deflateInit(mz_streamp pStream, int level); + +/* mz_deflateInit2() is like mz_deflate(), except with more control: */ +/* Additional parameters: */ +/* method must be MZ_DEFLATED */ +/* window_bits must be MZ_DEFAULT_WINDOW_BITS (to wrap the deflate stream with zlib header/adler-32 footer) or -MZ_DEFAULT_WINDOW_BITS (raw deflate/no header or footer) */ +/* mem_level must be between [1, 9] (it's checked but ignored by miniz.c) */ +int mz_deflateInit2(mz_streamp pStream, int level, int method, int window_bits, int mem_level, int strategy); + +/* Quickly resets a compressor without having to reallocate anything. Same as calling mz_deflateEnd() followed by mz_deflateInit()/mz_deflateInit2(). */ +int mz_deflateReset(mz_streamp pStream); + +/* mz_deflate() compresses the input to output, consuming as much of the input and producing as much output as possible. */ +/* Parameters: */ +/* pStream is the stream to read from and write to. You must initialize/update the next_in, avail_in, next_out, and avail_out members. */ +/* flush may be MZ_NO_FLUSH, MZ_PARTIAL_FLUSH/MZ_SYNC_FLUSH, MZ_FULL_FLUSH, or MZ_FINISH. */ +/* Return values: */ +/* MZ_OK on success (when flushing, or if more input is needed but not available, and/or there's more output to be written but the output buffer is full). */ +/* MZ_STREAM_END if all input has been consumed and all output bytes have been written. Don't call mz_deflate() on the stream anymore. */ +/* MZ_STREAM_ERROR if the stream is bogus. */ +/* MZ_PARAM_ERROR if one of the parameters is invalid. */ +/* MZ_BUF_ERROR if no forward progress is possible because the input and/or output buffers are empty. (Fill up the input buffer or free up some output space and try again.) */ +int mz_deflate(mz_streamp pStream, int flush); + +/* mz_deflateEnd() deinitializes a compressor: */ +/* Return values: */ +/* MZ_OK on success. */ +/* MZ_STREAM_ERROR if the stream is bogus. */ +int mz_deflateEnd(mz_streamp pStream); + +/* mz_deflateBound() returns a (very) conservative upper bound on the amount of data that could be generated by deflate(), assuming flush is set to only MZ_NO_FLUSH or MZ_FINISH. */ +mz_ulong mz_deflateBound(mz_streamp pStream, mz_ulong source_len); + +/* Single-call compression functions mz_compress() and mz_compress2(): */ +/* Returns MZ_OK on success, or one of the error codes from mz_deflate() on failure. */ +int mz_compress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len); +int mz_compress2(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len, int level); + +/* mz_compressBound() returns a (very) conservative upper bound on the amount of data that could be generated by calling mz_compress(). */ +mz_ulong mz_compressBound(mz_ulong source_len); + +/* Initializes a decompressor. */ +int mz_inflateInit(mz_streamp pStream); + +/* mz_inflateInit2() is like mz_inflateInit() with an additional option that controls the window size and whether or not the stream has been wrapped with a zlib header/footer: */ +/* window_bits must be MZ_DEFAULT_WINDOW_BITS (to parse zlib header/footer) or -MZ_DEFAULT_WINDOW_BITS (raw deflate). */ +int mz_inflateInit2(mz_streamp pStream, int window_bits); + +/* Quickly resets a compressor without having to reallocate anything. Same as calling mz_inflateEnd() followed by mz_inflateInit()/mz_inflateInit2(). */ +int mz_inflateReset(mz_streamp pStream); + +/* Decompresses the input stream to the output, consuming only as much of the input as needed, and writing as much to the output as possible. */ +/* Parameters: */ +/* pStream is the stream to read from and write to. You must initialize/update the next_in, avail_in, next_out, and avail_out members. */ +/* flush may be MZ_NO_FLUSH, MZ_SYNC_FLUSH, or MZ_FINISH. */ +/* On the first call, if flush is MZ_FINISH it's assumed the input and output buffers are both sized large enough to decompress the entire stream in a single call (this is slightly faster). */ +/* MZ_FINISH implies that there are no more source bytes available beside what's already in the input buffer, and that the output buffer is large enough to hold the rest of the decompressed data. */ +/* Return values: */ +/* MZ_OK on success. Either more input is needed but not available, and/or there's more output to be written but the output buffer is full. */ +/* MZ_STREAM_END if all needed input has been consumed and all output bytes have been written. For zlib streams, the adler-32 of the decompressed data has also been verified. */ +/* MZ_STREAM_ERROR if the stream is bogus. */ +/* MZ_DATA_ERROR if the deflate stream is invalid. */ +/* MZ_PARAM_ERROR if one of the parameters is invalid. */ +/* MZ_BUF_ERROR if no forward progress is possible because the input buffer is empty but the inflater needs more input to continue, or if the output buffer is not large enough. Call mz_inflate() again */ +/* with more input data, or with more room in the output buffer (except when using single call decompression, described above). */ +int mz_inflate(mz_streamp pStream, int flush); + +/* Deinitializes a decompressor. */ +int mz_inflateEnd(mz_streamp pStream); + +/* Single-call decompression. */ +/* Returns MZ_OK on success, or one of the error codes from mz_inflate() on failure. */ +int mz_uncompress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len); + +/* Returns a string description of the specified error code, or NULL if the error code is invalid. */ +const char *mz_error(int err); + +/* Redefine zlib-compatible names to miniz equivalents, so miniz.c can be used as a drop-in replacement for the subset of zlib that miniz.c supports. */ +/* Define MINIZ_NO_ZLIB_COMPATIBLE_NAMES to disable zlib-compatibility if you use zlib in the same project. */ +#ifndef MINIZ_NO_ZLIB_COMPATIBLE_NAMES +typedef unsigned char Byte; +typedef unsigned int uInt; +typedef mz_ulong uLong; +typedef Byte Bytef; +typedef uInt uIntf; +typedef char charf; +typedef int intf; +typedef void *voidpf; +typedef uLong uLongf; +typedef void *voidp; +typedef void *const voidpc; +#define Z_NULL 0 +#define Z_NO_FLUSH MZ_NO_FLUSH +#define Z_PARTIAL_FLUSH MZ_PARTIAL_FLUSH +#define Z_SYNC_FLUSH MZ_SYNC_FLUSH +#define Z_FULL_FLUSH MZ_FULL_FLUSH +#define Z_FINISH MZ_FINISH +#define Z_BLOCK MZ_BLOCK +#define Z_OK MZ_OK +#define Z_STREAM_END MZ_STREAM_END +#define Z_NEED_DICT MZ_NEED_DICT +#define Z_ERRNO MZ_ERRNO +#define Z_STREAM_ERROR MZ_STREAM_ERROR +#define Z_DATA_ERROR MZ_DATA_ERROR +#define Z_MEM_ERROR MZ_MEM_ERROR +#define Z_BUF_ERROR MZ_BUF_ERROR +#define Z_VERSION_ERROR MZ_VERSION_ERROR +#define Z_PARAM_ERROR MZ_PARAM_ERROR +#define Z_NO_COMPRESSION MZ_NO_COMPRESSION +#define Z_BEST_SPEED MZ_BEST_SPEED +#define Z_BEST_COMPRESSION MZ_BEST_COMPRESSION +#define Z_DEFAULT_COMPRESSION MZ_DEFAULT_COMPRESSION +#define Z_DEFAULT_STRATEGY MZ_DEFAULT_STRATEGY +#define Z_FILTERED MZ_FILTERED +#define Z_HUFFMAN_ONLY MZ_HUFFMAN_ONLY +#define Z_RLE MZ_RLE +#define Z_FIXED MZ_FIXED +#define Z_DEFLATED MZ_DEFLATED +#define Z_DEFAULT_WINDOW_BITS MZ_DEFAULT_WINDOW_BITS +#define alloc_func mz_alloc_func +#define free_func mz_free_func +#define internal_state mz_internal_state +#define z_stream mz_stream +#define deflateInit mz_deflateInit +#define deflateInit2 mz_deflateInit2 +#define deflateReset mz_deflateReset +#define deflate mz_deflate +#define deflateEnd mz_deflateEnd +#define deflateBound mz_deflateBound +#define compress mz_compress +#define compress2 mz_compress2 +#define compressBound mz_compressBound +#define inflateInit mz_inflateInit +#define inflateInit2 mz_inflateInit2 +#define inflateReset mz_inflateReset +#define inflate mz_inflate +#define inflateEnd mz_inflateEnd +#define uncompress mz_uncompress +#define crc32 mz_crc32 +#define adler32 mz_adler32 +#define MAX_WBITS 15 +#define MAX_MEM_LEVEL 9 +#define zError mz_error +#define ZLIB_VERSION MZ_VERSION +#define ZLIB_VERNUM MZ_VERNUM +#define ZLIB_VER_MAJOR MZ_VER_MAJOR +#define ZLIB_VER_MINOR MZ_VER_MINOR +#define ZLIB_VER_REVISION MZ_VER_REVISION +#define ZLIB_VER_SUBREVISION MZ_VER_SUBREVISION +#define zlibVersion mz_version +#define zlib_version mz_version() +#endif /* #ifndef MINIZ_NO_ZLIB_COMPATIBLE_NAMES */ + +#endif /* MINIZ_NO_ZLIB_APIS */ + +#ifdef __cplusplus +} +#endif +#pragma once +#include +#include +#include +#include + +/* ------------------- Types and macros */ +typedef unsigned char mz_uint8; +typedef signed short mz_int16; +typedef unsigned short mz_uint16; +typedef unsigned int mz_uint32; +typedef unsigned int mz_uint; +typedef int64_t mz_int64; +typedef uint64_t mz_uint64; +typedef int mz_bool; + +#define MZ_FALSE (0) +#define MZ_TRUE (1) + +/* Works around MSVC's spammy "warning C4127: conditional expression is constant" message. */ +#ifdef _MSC_VER +#define MZ_MACRO_END while (0, 0) +#else +#define MZ_MACRO_END while (0) +#endif + +#ifdef MINIZ_NO_STDIO +#define MZ_FILE void * +#else +#include +#define MZ_FILE FILE +#endif /* #ifdef MINIZ_NO_STDIO */ + +#ifdef MINIZ_NO_TIME +typedef struct mz_dummy_time_t_tag +{ + int m_dummy; +} mz_dummy_time_t; +#define MZ_TIME_T mz_dummy_time_t +#else +#define MZ_TIME_T time_t +#endif + +#define MZ_ASSERT(x) + +#ifdef MINIZ_NO_MALLOC +#define MZ_MALLOC(x) NULL +#define MZ_FREE(x) (void)x, ((void)0) +#define MZ_REALLOC(p, x) NULL +#else +#define MZ_MALLOC(x) malloc(x) +#define MZ_FREE(x) free(x) +#define MZ_REALLOC(p, x) realloc(p, x) +#endif + +#define MZ_MAX(a, b) (((a) > (b)) ? (a) : (b)) +#define MZ_MIN(a, b) (((a) < (b)) ? (a) : (b)) +#define MZ_CLEAR_OBJ(obj) memset(&(obj), 0, sizeof(obj)) + +#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN +#define MZ_READ_LE16(p) *((const mz_uint16 *)(p)) +#define MZ_READ_LE32(p) *((const mz_uint32 *)(p)) +#else +#define MZ_READ_LE16(p) ((mz_uint32)(((const mz_uint8 *)(p))[0]) | ((mz_uint32)(((const mz_uint8 *)(p))[1]) << 8U)) +#define MZ_READ_LE32(p) ((mz_uint32)(((const mz_uint8 *)(p))[0]) | ((mz_uint32)(((const mz_uint8 *)(p))[1]) << 8U) | ((mz_uint32)(((const mz_uint8 *)(p))[2]) << 16U) | ((mz_uint32)(((const mz_uint8 *)(p))[3]) << 24U)) +#endif + +#define MZ_READ_LE64(p) (((mz_uint64)MZ_READ_LE32(p)) | (((mz_uint64)MZ_READ_LE32((const mz_uint8 *)(p) + sizeof(mz_uint32))) << 32U)) + +#ifdef _MSC_VER +#define MZ_FORCEINLINE __forceinline +#elif defined(__GNUC__) +#define MZ_FORCEINLINE __inline__ __attribute__((__always_inline__)) +#else +#define MZ_FORCEINLINE inline +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +extern void *miniz_def_alloc_func(void *opaque, size_t items, size_t size); +extern void miniz_def_free_func(void *opaque, void *address); +extern void *miniz_def_realloc_func(void *opaque, void *address, size_t items, size_t size); + +#define MZ_UINT16_MAX (0xFFFFU) +#define MZ_UINT32_MAX (0xFFFFFFFFU) + +#ifdef __cplusplus +} +#endif +#pragma once + + +#ifdef __cplusplus +extern "C" { +#endif +/* ------------------- Low-level Compression API Definitions */ + +/* Set TDEFL_LESS_MEMORY to 1 to use less memory (compression will be slightly slower, and raw/dynamic blocks will be output more frequently). */ +#define TDEFL_LESS_MEMORY 1 + +/* tdefl_init() compression flags logically OR'd together (low 12 bits contain the max. number of probes per dictionary search): */ +/* TDEFL_DEFAULT_MAX_PROBES: The compressor defaults to 128 dictionary probes per dictionary search. 0=Huffman only, 1=Huffman+LZ (fastest/crap compression), 4095=Huffman+LZ (slowest/best compression). */ +enum +{ + TDEFL_HUFFMAN_ONLY = 0, + TDEFL_DEFAULT_MAX_PROBES = 128, + TDEFL_MAX_PROBES_MASK = 0xFFF +}; + +/* TDEFL_WRITE_ZLIB_HEADER: If set, the compressor outputs a zlib header before the deflate data, and the Adler-32 of the source data at the end. Otherwise, you'll get raw deflate data. */ +/* TDEFL_COMPUTE_ADLER32: Always compute the adler-32 of the input data (even when not writing zlib headers). */ +/* TDEFL_GREEDY_PARSING_FLAG: Set to use faster greedy parsing, instead of more efficient lazy parsing. */ +/* TDEFL_NONDETERMINISTIC_PARSING_FLAG: Enable to decrease the compressor's initialization time to the minimum, but the output may vary from run to run given the same input (depending on the contents of memory). */ +/* TDEFL_RLE_MATCHES: Only look for RLE matches (matches with a distance of 1) */ +/* TDEFL_FILTER_MATCHES: Discards matches <= 5 chars if enabled. */ +/* TDEFL_FORCE_ALL_STATIC_BLOCKS: Disable usage of optimized Huffman tables. */ +/* TDEFL_FORCE_ALL_RAW_BLOCKS: Only use raw (uncompressed) deflate blocks. */ +/* The low 12 bits are reserved to control the max # of hash probes per dictionary lookup (see TDEFL_MAX_PROBES_MASK). */ +enum +{ + TDEFL_WRITE_ZLIB_HEADER = 0x01000, + TDEFL_COMPUTE_ADLER32 = 0x02000, + TDEFL_GREEDY_PARSING_FLAG = 0x04000, + TDEFL_NONDETERMINISTIC_PARSING_FLAG = 0x08000, + TDEFL_RLE_MATCHES = 0x10000, + TDEFL_FILTER_MATCHES = 0x20000, + TDEFL_FORCE_ALL_STATIC_BLOCKS = 0x40000, + TDEFL_FORCE_ALL_RAW_BLOCKS = 0x80000 +}; + +/* High level compression functions: */ +/* tdefl_compress_mem_to_heap() compresses a block in memory to a heap block allocated via malloc(). */ +/* On entry: */ +/* pSrc_buf, src_buf_len: Pointer and size of source block to compress. */ +/* flags: The max match finder probes (default is 128) logically OR'd against the above flags. Higher probes are slower but improve compression. */ +/* On return: */ +/* Function returns a pointer to the compressed data, or NULL on failure. */ +/* *pOut_len will be set to the compressed data's size, which could be larger than src_buf_len on incompressible data. */ +/* The caller must free() the returned block when it's no longer needed. */ +void *tdefl_compress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags); + +/* tdefl_compress_mem_to_mem() compresses a block in memory to another block in memory. */ +/* Returns 0 on failure. */ +size_t tdefl_compress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags); + +/* Compresses an image to a compressed PNG file in memory. */ +/* On entry: */ +/* pImage, w, h, and num_chans describe the image to compress. num_chans may be 1, 2, 3, or 4. */ +/* The image pitch in bytes per scanline will be w*num_chans. The leftmost pixel on the top scanline is stored first in memory. */ +/* level may range from [0,10], use MZ_NO_COMPRESSION, MZ_BEST_SPEED, MZ_BEST_COMPRESSION, etc. or a decent default is MZ_DEFAULT_LEVEL */ +/* If flip is true, the image will be flipped on the Y axis (useful for OpenGL apps). */ +/* On return: */ +/* Function returns a pointer to the compressed data, or NULL on failure. */ +/* *pLen_out will be set to the size of the PNG image file. */ +/* The caller must mz_free() the returned heap block (which will typically be larger than *pLen_out) when it's no longer needed. */ +void *tdefl_write_image_to_png_file_in_memory_ex(const void *pImage, int w, int h, int num_chans, size_t *pLen_out, mz_uint level, mz_bool flip); +void *tdefl_write_image_to_png_file_in_memory(const void *pImage, int w, int h, int num_chans, size_t *pLen_out); + +/* Output stream interface. The compressor uses this interface to write compressed data. It'll typically be called TDEFL_OUT_BUF_SIZE at a time. */ +typedef mz_bool (*tdefl_put_buf_func_ptr)(const void *pBuf, int len, void *pUser); + +/* tdefl_compress_mem_to_output() compresses a block to an output stream. The above helpers use this function internally. */ +mz_bool tdefl_compress_mem_to_output(const void *pBuf, size_t buf_len, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags); + +enum +{ + TDEFL_MAX_HUFF_TABLES = 3, + TDEFL_MAX_HUFF_SYMBOLS_0 = 288, + TDEFL_MAX_HUFF_SYMBOLS_1 = 32, + TDEFL_MAX_HUFF_SYMBOLS_2 = 19, + TDEFL_LZ_DICT_SIZE = (8*1024), + TDEFL_LZ_DICT_SIZE_MASK = TDEFL_LZ_DICT_SIZE - 1, + TDEFL_MIN_MATCH_LEN = 3, + TDEFL_MAX_MATCH_LEN = 258 +}; + +/* TDEFL_OUT_BUF_SIZE MUST be large enough to hold a single entire compressed output block (using static/fixed Huffman codes). */ +#if TDEFL_LESS_MEMORY +enum +{ + TDEFL_LZ_CODE_BUF_SIZE = 8 * 1024, + TDEFL_OUT_BUF_SIZE = (TDEFL_LZ_CODE_BUF_SIZE * 13) / 10, + TDEFL_MAX_HUFF_SYMBOLS = 288, + TDEFL_LZ_HASH_BITS = 12, + TDEFL_LEVEL1_HASH_SIZE_MASK = 4095, + TDEFL_LZ_HASH_SHIFT = (TDEFL_LZ_HASH_BITS + 2) / 3, + TDEFL_LZ_HASH_SIZE = 1 << TDEFL_LZ_HASH_BITS +}; +#else +enum +{ + TDEFL_LZ_CODE_BUF_SIZE = 64 * 1024, + TDEFL_OUT_BUF_SIZE = (TDEFL_LZ_CODE_BUF_SIZE * 13) / 10, + TDEFL_MAX_HUFF_SYMBOLS = 288, + TDEFL_LZ_HASH_BITS = 15, + TDEFL_LEVEL1_HASH_SIZE_MASK = 4095, + TDEFL_LZ_HASH_SHIFT = (TDEFL_LZ_HASH_BITS + 2) / 3, + TDEFL_LZ_HASH_SIZE = 1 << TDEFL_LZ_HASH_BITS +}; +#endif + +/* The low-level tdefl functions below may be used directly if the above helper functions aren't flexible enough. The low-level functions don't make any heap allocations, unlike the above helper functions. */ +typedef enum { + TDEFL_STATUS_BAD_PARAM = -2, + TDEFL_STATUS_PUT_BUF_FAILED = -1, + TDEFL_STATUS_OKAY = 0, + TDEFL_STATUS_DONE = 1 +} tdefl_status; + +/* Must map to MZ_NO_FLUSH, MZ_SYNC_FLUSH, etc. enums */ +typedef enum { + TDEFL_NO_FLUSH = 0, + TDEFL_SYNC_FLUSH = 2, + TDEFL_FULL_FLUSH = 3, + TDEFL_FINISH = 4 +} tdefl_flush; + +/* tdefl's compression state structure. */ +typedef struct +{ + tdefl_put_buf_func_ptr m_pPut_buf_func; + void *m_pPut_buf_user; + mz_uint m_flags, m_max_probes[2]; + int m_greedy_parsing; + mz_uint m_adler32, m_lookahead_pos, m_lookahead_size, m_dict_size; + mz_uint8 *m_pLZ_code_buf, *m_pLZ_flags, *m_pOutput_buf, *m_pOutput_buf_end; + mz_uint m_num_flags_left, m_total_lz_bytes, m_lz_code_buf_dict_pos, m_bits_in, m_bit_buffer; + mz_uint m_saved_match_dist, m_saved_match_len, m_saved_lit, m_output_flush_ofs, m_output_flush_remaining, m_finished, m_block_index, m_wants_to_finish; + tdefl_status m_prev_return_status; + const void *m_pIn_buf; + void *m_pOut_buf; + size_t *m_pIn_buf_size, *m_pOut_buf_size; + tdefl_flush m_flush; + const mz_uint8 *m_pSrc; + size_t m_src_buf_left, m_out_buf_ofs; + mz_uint8 m_dict[TDEFL_LZ_DICT_SIZE + TDEFL_MAX_MATCH_LEN - 1]; + mz_uint16 m_huff_count[TDEFL_MAX_HUFF_TABLES][TDEFL_MAX_HUFF_SYMBOLS]; + mz_uint16 m_huff_codes[TDEFL_MAX_HUFF_TABLES][TDEFL_MAX_HUFF_SYMBOLS]; + mz_uint8 m_huff_code_sizes[TDEFL_MAX_HUFF_TABLES][TDEFL_MAX_HUFF_SYMBOLS]; + mz_uint8 m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE]; + mz_uint16 m_next[TDEFL_LZ_DICT_SIZE]; + mz_uint16 m_hash[TDEFL_LZ_HASH_SIZE]; + mz_uint8 m_output_buf[TDEFL_OUT_BUF_SIZE]; +} tdefl_compressor; + +/* Initializes the compressor. */ +/* There is no corresponding deinit() function because the tdefl API's do not dynamically allocate memory. */ +/* pBut_buf_func: If NULL, output data will be supplied to the specified callback. In this case, the user should call the tdefl_compress_buffer() API for compression. */ +/* If pBut_buf_func is NULL the user should always call the tdefl_compress() API. */ +/* flags: See the above enums (TDEFL_HUFFMAN_ONLY, TDEFL_WRITE_ZLIB_HEADER, etc.) */ +tdefl_status tdefl_init(tdefl_compressor *d, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags); + +/* Compresses a block of data, consuming as much of the specified input buffer as possible, and writing as much compressed data to the specified output buffer as possible. */ +tdefl_status tdefl_compress(tdefl_compressor *d, const void *pIn_buf, size_t *pIn_buf_size, void *pOut_buf, size_t *pOut_buf_size, tdefl_flush flush); + +/* tdefl_compress_buffer() is only usable when the tdefl_init() is called with a non-NULL tdefl_put_buf_func_ptr. */ +/* tdefl_compress_buffer() always consumes the entire input buffer. */ +tdefl_status tdefl_compress_buffer(tdefl_compressor *d, const void *pIn_buf, size_t in_buf_size, tdefl_flush flush); + +tdefl_status tdefl_get_prev_return_status(tdefl_compressor *d); +mz_uint32 tdefl_get_adler32(tdefl_compressor *d); + +/* Create tdefl_compress() flags given zlib-style compression parameters. */ +/* level may range from [0,10] (where 10 is absolute max compression, but may be much slower on some files) */ +/* window_bits may be -15 (raw deflate) or 15 (zlib) */ +/* strategy may be either MZ_DEFAULT_STRATEGY, MZ_FILTERED, MZ_HUFFMAN_ONLY, MZ_RLE, or MZ_FIXED */ +mz_uint tdefl_create_comp_flags_from_zip_params(int level, int window_bits, int strategy); + +#ifndef MINIZ_NO_MALLOC +/* Allocate the tdefl_compressor structure in C so that */ +/* non-C language bindings to tdefl_ API don't need to worry about */ +/* structure size and allocation mechanism. */ +tdefl_compressor *tdefl_compressor_alloc(void); +void tdefl_compressor_free(tdefl_compressor *pComp); +#endif + +#ifdef __cplusplus +} +#endif +#pragma once + +/* ------------------- Low-level Decompression API Definitions */ + +#ifdef __cplusplus +extern "C" { +#endif +/* Decompression flags used by tinfl_decompress(). */ +/* TINFL_FLAG_PARSE_ZLIB_HEADER: If set, the input has a valid zlib header and ends with an adler32 checksum (it's a valid zlib stream). Otherwise, the input is a raw deflate stream. */ +/* TINFL_FLAG_HAS_MORE_INPUT: If set, there are more input bytes available beyond the end of the supplied input buffer. If clear, the input buffer contains all remaining input. */ +/* TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF: If set, the output buffer is large enough to hold the entire decompressed stream. If clear, the output buffer is at least the size of the dictionary (typically 32KB). */ +/* TINFL_FLAG_COMPUTE_ADLER32: Force adler-32 checksum computation of the decompressed bytes. */ +enum +{ + TINFL_FLAG_PARSE_ZLIB_HEADER = 1, + TINFL_FLAG_HAS_MORE_INPUT = 2, + TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF = 4, + TINFL_FLAG_COMPUTE_ADLER32 = 8 +}; + +/* High level decompression functions: */ +/* tinfl_decompress_mem_to_heap() decompresses a block in memory to a heap block allocated via malloc(). */ +/* On entry: */ +/* pSrc_buf, src_buf_len: Pointer and size of the Deflate or zlib source data to decompress. */ +/* On return: */ +/* Function returns a pointer to the decompressed data, or NULL on failure. */ +/* *pOut_len will be set to the decompressed data's size, which could be larger than src_buf_len on incompressible data. */ +/* The caller must call mz_free() on the returned block when it's no longer needed. */ +void *tinfl_decompress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags); + +/* tinfl_decompress_mem_to_mem() decompresses a block in memory to another block in memory. */ +/* Returns TINFL_DECOMPRESS_MEM_TO_MEM_FAILED on failure, or the number of bytes written on success. */ +#define TINFL_DECOMPRESS_MEM_TO_MEM_FAILED ((size_t)(-1)) +size_t tinfl_decompress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags); + +/* tinfl_decompress_mem_to_callback() decompresses a block in memory to an internal 32KB buffer, and a user provided callback function will be called to flush the buffer. */ +/* Returns 1 on success or 0 on failure. */ +typedef int (*tinfl_put_buf_func_ptr)(const void *pBuf, int len, void *pUser); +int tinfl_decompress_mem_to_callback(const void *pIn_buf, size_t *pIn_buf_size, tinfl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags); + +struct tinfl_decompressor_tag; +typedef struct tinfl_decompressor_tag tinfl_decompressor; + +#ifndef MINIZ_NO_MALLOC +/* Allocate the tinfl_decompressor structure in C so that */ +/* non-C language bindings to tinfl_ API don't need to worry about */ +/* structure size and allocation mechanism. */ +tinfl_decompressor *tinfl_decompressor_alloc(void); +void tinfl_decompressor_free(tinfl_decompressor *pDecomp); +#endif + +/* Max size of LZ dictionary. */ +#define TINFL_LZ_DICT_SIZE 32768 + +/* Return status. */ +typedef enum { + /* This flags indicates the inflator needs 1 or more input bytes to make forward progress, but the caller is indicating that no more are available. The compressed data */ + /* is probably corrupted. If you call the inflator again with more bytes it'll try to continue processing the input but this is a BAD sign (either the data is corrupted or you called it incorrectly). */ + /* If you call it again with no input you'll just get TINFL_STATUS_FAILED_CANNOT_MAKE_PROGRESS again. */ + TINFL_STATUS_FAILED_CANNOT_MAKE_PROGRESS = -4, + + /* This flag indicates that one or more of the input parameters was obviously bogus. (You can try calling it again, but if you get this error the calling code is wrong.) */ + TINFL_STATUS_BAD_PARAM = -3, + + /* This flags indicate the inflator is finished but the adler32 check of the uncompressed data didn't match. If you call it again it'll return TINFL_STATUS_DONE. */ + TINFL_STATUS_ADLER32_MISMATCH = -2, + + /* This flags indicate the inflator has somehow failed (bad code, corrupted input, etc.). If you call it again without resetting via tinfl_init() it it'll just keep on returning the same status failure code. */ + TINFL_STATUS_FAILED = -1, + + /* Any status code less than TINFL_STATUS_DONE must indicate a failure. */ + + /* This flag indicates the inflator has returned every byte of uncompressed data that it can, has consumed every byte that it needed, has successfully reached the end of the deflate stream, and */ + /* if zlib headers and adler32 checking enabled that it has successfully checked the uncompressed data's adler32. If you call it again you'll just get TINFL_STATUS_DONE over and over again. */ + TINFL_STATUS_DONE = 0, + + /* This flag indicates the inflator MUST have more input data (even 1 byte) before it can make any more forward progress, or you need to clear the TINFL_FLAG_HAS_MORE_INPUT */ + /* flag on the next call if you don't have any more source data. If the source data was somehow corrupted it's also possible (but unlikely) for the inflator to keep on demanding input to */ + /* proceed, so be sure to properly set the TINFL_FLAG_HAS_MORE_INPUT flag. */ + TINFL_STATUS_NEEDS_MORE_INPUT = 1, + + /* This flag indicates the inflator definitely has 1 or more bytes of uncompressed data available, but it cannot write this data into the output buffer. */ + /* Note if the source compressed data was corrupted it's possible for the inflator to return a lot of uncompressed data to the caller. I've been assuming you know how much uncompressed data to expect */ + /* (either exact or worst case) and will stop calling the inflator and fail after receiving too much. In pure streaming scenarios where you have no idea how many bytes to expect this may not be possible */ + /* so I may need to add some code to address this. */ + TINFL_STATUS_HAS_MORE_OUTPUT = 2 +} tinfl_status; + +/* Initializes the decompressor to its initial state. */ +#define tinfl_init(r) \ + do \ + { \ + (r)->m_state = 0; \ + } \ + MZ_MACRO_END +#define tinfl_get_adler32(r) (r)->m_check_adler32 + +/* Main low-level decompressor coroutine function. This is the only function actually needed for decompression. All the other functions are just high-level helpers for improved usability. */ +/* This is a universal API, i.e. it can be used as a building block to build any desired higher level decompression API. In the limit case, it can be called once per every byte input or output. */ +tinfl_status tinfl_decompress(tinfl_decompressor *r, const mz_uint8 *pIn_buf_next, size_t *pIn_buf_size, mz_uint8 *pOut_buf_start, mz_uint8 *pOut_buf_next, size_t *pOut_buf_size, const mz_uint32 decomp_flags); + +/* Internal/private bits follow. */ +enum +{ + TINFL_MAX_HUFF_TABLES = 3, + TINFL_MAX_HUFF_SYMBOLS_0 = 288, + TINFL_MAX_HUFF_SYMBOLS_1 = 32, + TINFL_MAX_HUFF_SYMBOLS_2 = 19, + TINFL_FAST_LOOKUP_BITS = 10, + TINFL_FAST_LOOKUP_SIZE = 1 << TINFL_FAST_LOOKUP_BITS +}; + +typedef struct +{ + mz_uint8 m_code_size[TINFL_MAX_HUFF_SYMBOLS_0]; + mz_int16 m_look_up[TINFL_FAST_LOOKUP_SIZE], m_tree[TINFL_MAX_HUFF_SYMBOLS_0 * 2]; +} tinfl_huff_table; + +#if MINIZ_HAS_64BIT_REGISTERS +#define TINFL_USE_64BIT_BITBUF 1 +#else +#define TINFL_USE_64BIT_BITBUF 0 +#endif + +#if TINFL_USE_64BIT_BITBUF +typedef mz_uint64 tinfl_bit_buf_t; +#define TINFL_BITBUF_SIZE (64) +#else +typedef mz_uint32 tinfl_bit_buf_t; +#define TINFL_BITBUF_SIZE (32) +#endif + +struct tinfl_decompressor_tag +{ + mz_uint32 m_state, m_num_bits, m_zhdr0, m_zhdr1, m_z_adler32, m_final, m_type, m_check_adler32, m_dist, m_counter, m_num_extra, m_table_sizes[TINFL_MAX_HUFF_TABLES]; + tinfl_bit_buf_t m_bit_buf; + size_t m_dist_from_out_buf_start; + tinfl_huff_table m_tables[TINFL_MAX_HUFF_TABLES]; + mz_uint8 m_raw_header[4], m_len_codes[TINFL_MAX_HUFF_SYMBOLS_0 + TINFL_MAX_HUFF_SYMBOLS_1 + 137]; +}; + +#ifdef __cplusplus +} +#endif + +#pragma once + + +/* ------------------- ZIP archive reading/writing */ + +#ifndef MINIZ_NO_ARCHIVE_APIS + +#ifdef __cplusplus +extern "C" { +#endif + +enum +{ + /* Note: These enums can be reduced as needed to save memory or stack space - they are pretty conservative. */ + MZ_ZIP_MAX_IO_BUF_SIZE = 64 * 1024, + MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE = 512, + MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE = 512 +}; + +typedef struct +{ + /* Central directory file index. */ + mz_uint32 m_file_index; + + /* Byte offset of this entry in the archive's central directory. Note we currently only support up to UINT_MAX or less bytes in the central dir. */ + mz_uint64 m_central_dir_ofs; + + /* These fields are copied directly from the zip's central dir. */ + mz_uint16 m_version_made_by; + mz_uint16 m_version_needed; + mz_uint16 m_bit_flag; + mz_uint16 m_method; + +#ifndef MINIZ_NO_TIME + MZ_TIME_T m_time; +#endif + + /* CRC-32 of uncompressed data. */ + mz_uint32 m_crc32; + + /* File's compressed size. */ + mz_uint64 m_comp_size; + + /* File's uncompressed size. Note, I've seen some old archives where directory entries had 512 bytes for their uncompressed sizes, but when you try to unpack them you actually get 0 bytes. */ + mz_uint64 m_uncomp_size; + + /* Zip internal and external file attributes. */ + mz_uint16 m_internal_attr; + mz_uint32 m_external_attr; + + /* Entry's local header file offset in bytes. */ + mz_uint64 m_local_header_ofs; + + /* Size of comment in bytes. */ + mz_uint32 m_comment_size; + + /* MZ_TRUE if the entry appears to be a directory. */ + mz_bool m_is_directory; + + /* MZ_TRUE if the entry uses encryption/strong encryption (which miniz_zip doesn't support) */ + mz_bool m_is_encrypted; + + /* MZ_TRUE if the file is not encrypted, a patch file, and if it uses a compression method we support. */ + mz_bool m_is_supported; + + /* Filename. If string ends in '/' it's a subdirectory entry. */ + /* Guaranteed to be zero terminated, may be truncated to fit. */ + char m_filename[MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE]; + + /* Comment field. */ + /* Guaranteed to be zero terminated, may be truncated to fit. */ + char m_comment[MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE]; + +} mz_zip_archive_file_stat; + +typedef size_t (*mz_file_read_func)(void *pOpaque, mz_uint64 file_ofs, void *pBuf, size_t n); +typedef size_t (*mz_file_write_func)(void *pOpaque, mz_uint64 file_ofs, const void *pBuf, size_t n); +typedef mz_bool (*mz_file_needs_keepalive)(void *pOpaque); + +struct mz_zip_internal_state_tag; +typedef struct mz_zip_internal_state_tag mz_zip_internal_state; + +typedef enum { + MZ_ZIP_MODE_INVALID = 0, + MZ_ZIP_MODE_READING = 1, + MZ_ZIP_MODE_WRITING = 2, + MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED = 3 +} mz_zip_mode; + +typedef enum { + MZ_ZIP_FLAG_CASE_SENSITIVE = 0x0100, + MZ_ZIP_FLAG_IGNORE_PATH = 0x0200, + MZ_ZIP_FLAG_COMPRESSED_DATA = 0x0400, + MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY = 0x0800, + MZ_ZIP_FLAG_VALIDATE_LOCATE_FILE_FLAG = 0x1000, /* if enabled, mz_zip_reader_locate_file() will be called on each file as its validated to ensure the func finds the file in the central dir (intended for testing) */ + MZ_ZIP_FLAG_VALIDATE_HEADERS_ONLY = 0x2000, /* validate the local headers, but don't decompress the entire file and check the crc32 */ + MZ_ZIP_FLAG_WRITE_ZIP64 = 0x4000, /* always use the zip64 file format, instead of the original zip file format with automatic switch to zip64. Use as flags parameter with mz_zip_writer_init*_v2 */ + MZ_ZIP_FLAG_WRITE_ALLOW_READING = 0x8000, + MZ_ZIP_FLAG_ASCII_FILENAME = 0x10000 +} mz_zip_flags; + +typedef enum { + MZ_ZIP_TYPE_INVALID = 0, + MZ_ZIP_TYPE_USER, + MZ_ZIP_TYPE_MEMORY, + MZ_ZIP_TYPE_HEAP, + MZ_ZIP_TYPE_FILE, + MZ_ZIP_TYPE_CFILE, + MZ_ZIP_TOTAL_TYPES +} mz_zip_type; + +/* miniz error codes. Be sure to update mz_zip_get_error_string() if you add or modify this enum. */ +typedef enum { + MZ_ZIP_NO_ERROR = 0, + MZ_ZIP_UNDEFINED_ERROR, + MZ_ZIP_TOO_MANY_FILES, + MZ_ZIP_FILE_TOO_LARGE, + MZ_ZIP_UNSUPPORTED_METHOD, + MZ_ZIP_UNSUPPORTED_ENCRYPTION, + MZ_ZIP_UNSUPPORTED_FEATURE, + MZ_ZIP_FAILED_FINDING_CENTRAL_DIR, + MZ_ZIP_NOT_AN_ARCHIVE, + MZ_ZIP_INVALID_HEADER_OR_CORRUPTED, + MZ_ZIP_UNSUPPORTED_MULTIDISK, + MZ_ZIP_DECOMPRESSION_FAILED, + MZ_ZIP_COMPRESSION_FAILED, + MZ_ZIP_UNEXPECTED_DECOMPRESSED_SIZE, + MZ_ZIP_CRC_CHECK_FAILED, + MZ_ZIP_UNSUPPORTED_CDIR_SIZE, + MZ_ZIP_ALLOC_FAILED, + MZ_ZIP_FILE_OPEN_FAILED, + MZ_ZIP_FILE_CREATE_FAILED, + MZ_ZIP_FILE_WRITE_FAILED, + MZ_ZIP_FILE_READ_FAILED, + MZ_ZIP_FILE_CLOSE_FAILED, + MZ_ZIP_FILE_SEEK_FAILED, + MZ_ZIP_FILE_STAT_FAILED, + MZ_ZIP_INVALID_PARAMETER, + MZ_ZIP_INVALID_FILENAME, + MZ_ZIP_BUF_TOO_SMALL, + MZ_ZIP_INTERNAL_ERROR, + MZ_ZIP_FILE_NOT_FOUND, + MZ_ZIP_ARCHIVE_TOO_LARGE, + MZ_ZIP_VALIDATION_FAILED, + MZ_ZIP_WRITE_CALLBACK_FAILED, + MZ_ZIP_TOTAL_ERRORS +} mz_zip_error; + +typedef struct +{ + mz_uint64 m_archive_size; + mz_uint64 m_central_directory_file_ofs; + + /* We only support up to UINT32_MAX files in zip64 mode. */ + mz_uint32 m_total_files; + mz_zip_mode m_zip_mode; + mz_zip_type m_zip_type; + mz_zip_error m_last_error; + + mz_uint64 m_file_offset_alignment; + + mz_alloc_func m_pAlloc; + mz_free_func m_pFree; + mz_realloc_func m_pRealloc; + void *m_pAlloc_opaque; + + mz_file_read_func m_pRead; + mz_file_write_func m_pWrite; + mz_file_needs_keepalive m_pNeeds_keepalive; + void *m_pIO_opaque; + + mz_zip_internal_state *m_pState; + +} mz_zip_archive; + +typedef struct +{ + mz_zip_archive *pZip; + mz_uint flags; + + int status; +#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS + mz_uint file_crc32; +#endif + mz_uint64 read_buf_size, read_buf_ofs, read_buf_avail, comp_remaining, out_buf_ofs, cur_file_ofs; + mz_zip_archive_file_stat file_stat; + void *pRead_buf; + void *pWrite_buf; + + size_t out_blk_remain; + + tinfl_decompressor inflator; + +} mz_zip_reader_extract_iter_state; + +/* -------- ZIP reading */ + +/* Inits a ZIP archive reader. */ +/* These functions read and validate the archive's central directory. */ +mz_bool mz_zip_reader_init(mz_zip_archive *pZip, mz_uint64 size, mz_uint flags); + +mz_bool mz_zip_reader_init_mem(mz_zip_archive *pZip, const void *pMem, size_t size, mz_uint flags); + +#ifndef MINIZ_NO_STDIO +/* Read a archive from a disk file. */ +/* file_start_ofs is the file offset where the archive actually begins, or 0. */ +/* actual_archive_size is the true total size of the archive, which may be smaller than the file's actual size on disk. If zero the entire file is treated as the archive. */ +mz_bool mz_zip_reader_init_file(mz_zip_archive *pZip, const char *pFilename, mz_uint32 flags); +mz_bool mz_zip_reader_init_file_v2(mz_zip_archive *pZip, const char *pFilename, mz_uint flags, mz_uint64 file_start_ofs, mz_uint64 archive_size); + +/* Read an archive from an already opened FILE, beginning at the current file position. */ +/* The archive is assumed to be archive_size bytes long. If archive_size is < 0, then the entire rest of the file is assumed to contain the archive. */ +/* The FILE will NOT be closed when mz_zip_reader_end() is called. */ +mz_bool mz_zip_reader_init_cfile(mz_zip_archive *pZip, MZ_FILE *pFile, mz_uint64 archive_size, mz_uint flags); +#endif + +/* Ends archive reading, freeing all allocations, and closing the input archive file if mz_zip_reader_init_file() was used. */ +mz_bool mz_zip_reader_end(mz_zip_archive *pZip); + +/* -------- ZIP reading or writing */ + +/* Clears a mz_zip_archive struct to all zeros. */ +/* Important: This must be done before passing the struct to any mz_zip functions. */ +void mz_zip_zero_struct(mz_zip_archive *pZip); + +mz_zip_mode mz_zip_get_mode(mz_zip_archive *pZip); +mz_zip_type mz_zip_get_type(mz_zip_archive *pZip); + +/* Returns the total number of files in the archive. */ +mz_uint mz_zip_reader_get_num_files(mz_zip_archive *pZip); + +mz_uint64 mz_zip_get_archive_size(mz_zip_archive *pZip); +mz_uint64 mz_zip_get_archive_file_start_offset(mz_zip_archive *pZip); +MZ_FILE *mz_zip_get_cfile(mz_zip_archive *pZip); + +/* Reads n bytes of raw archive data, starting at file offset file_ofs, to pBuf. */ +size_t mz_zip_read_archive_data(mz_zip_archive *pZip, mz_uint64 file_ofs, void *pBuf, size_t n); + +/* All mz_zip funcs set the m_last_error field in the mz_zip_archive struct. These functions retrieve/manipulate this field. */ +/* Note that the m_last_error functionality is not thread safe. */ +mz_zip_error mz_zip_set_last_error(mz_zip_archive *pZip, mz_zip_error err_num); +mz_zip_error mz_zip_peek_last_error(mz_zip_archive *pZip); +mz_zip_error mz_zip_clear_last_error(mz_zip_archive *pZip); +mz_zip_error mz_zip_get_last_error(mz_zip_archive *pZip); +const char *mz_zip_get_error_string(mz_zip_error mz_err); + +/* MZ_TRUE if the archive file entry is a directory entry. */ +mz_bool mz_zip_reader_is_file_a_directory(mz_zip_archive *pZip, mz_uint file_index); + +/* MZ_TRUE if the file is encrypted/strong encrypted. */ +mz_bool mz_zip_reader_is_file_encrypted(mz_zip_archive *pZip, mz_uint file_index); + +/* MZ_TRUE if the compression method is supported, and the file is not encrypted, and the file is not a compressed patch file. */ +mz_bool mz_zip_reader_is_file_supported(mz_zip_archive *pZip, mz_uint file_index); + +/* Retrieves the filename of an archive file entry. */ +/* Returns the number of bytes written to pFilename, or if filename_buf_size is 0 this function returns the number of bytes needed to fully store the filename. */ +mz_uint mz_zip_reader_get_filename(mz_zip_archive *pZip, mz_uint file_index, char *pFilename, mz_uint filename_buf_size); + +/* Attempts to locates a file in the archive's central directory. */ +/* Valid flags: MZ_ZIP_FLAG_CASE_SENSITIVE, MZ_ZIP_FLAG_IGNORE_PATH */ +/* Returns -1 if the file cannot be found. */ +int mz_zip_reader_locate_file(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags); +int mz_zip_reader_locate_file_v2(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags, mz_uint32 *file_index); + +/* Returns detailed information about an archive file entry. */ +mz_bool mz_zip_reader_file_stat(mz_zip_archive *pZip, mz_uint file_index, mz_zip_archive_file_stat *pStat); + +/* MZ_TRUE if the file is in zip64 format. */ +/* A file is considered zip64 if it contained a zip64 end of central directory marker, or if it contained any zip64 extended file information fields in the central directory. */ +mz_bool mz_zip_is_zip64(mz_zip_archive *pZip); + +/* Returns the total central directory size in bytes. */ +/* The current max supported size is <= MZ_UINT32_MAX. */ +size_t mz_zip_get_central_dir_size(mz_zip_archive *pZip); + +/* Extracts a archive file to a memory buffer using no memory allocation. */ +/* There must be at least enough room on the stack to store the inflator's state (~34KB or so). */ +mz_bool mz_zip_reader_extract_to_mem_no_alloc(mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size); +mz_bool mz_zip_reader_extract_file_to_mem_no_alloc(mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size); + +/* Extracts a archive file to a memory buffer. */ +mz_bool mz_zip_reader_extract_to_mem(mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, mz_uint flags); +mz_bool mz_zip_reader_extract_file_to_mem(mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, mz_uint flags); + +/* Extracts a archive file to a dynamically allocated heap buffer. */ +/* The memory will be allocated via the mz_zip_archive's alloc/realloc functions. */ +/* Returns NULL and sets the last error on failure. */ +void *mz_zip_reader_extract_to_heap(mz_zip_archive *pZip, mz_uint file_index, size_t *pSize, mz_uint flags); +void *mz_zip_reader_extract_file_to_heap(mz_zip_archive *pZip, const char *pFilename, size_t *pSize, mz_uint flags); + +/* Extracts a archive file using a callback function to output the file's data. */ +mz_bool mz_zip_reader_extract_to_callback(mz_zip_archive *pZip, mz_uint file_index, mz_file_write_func pCallback, void *pOpaque, mz_uint flags); +mz_bool mz_zip_reader_extract_file_to_callback(mz_zip_archive *pZip, const char *pFilename, mz_file_write_func pCallback, void *pOpaque, mz_uint flags); + +/* Extract a file iteratively */ +mz_zip_reader_extract_iter_state* mz_zip_reader_extract_iter_new(mz_zip_archive *pZip, mz_uint file_index, mz_uint flags); +mz_zip_reader_extract_iter_state* mz_zip_reader_extract_file_iter_new(mz_zip_archive *pZip, const char *pFilename, mz_uint flags); +size_t mz_zip_reader_extract_iter_read(mz_zip_reader_extract_iter_state* pState, void* pvBuf, size_t buf_size); +mz_bool mz_zip_reader_extract_iter_free(mz_zip_reader_extract_iter_state* pState); + +#ifndef MINIZ_NO_STDIO +/* Extracts a archive file to a disk file and sets its last accessed and modified times. */ +/* This function only extracts files, not archive directory records. */ +mz_bool mz_zip_reader_extract_to_file(mz_zip_archive *pZip, mz_uint file_index, const char *pDst_filename, mz_uint flags); +mz_bool mz_zip_reader_extract_file_to_file(mz_zip_archive *pZip, const char *pArchive_filename, const char *pDst_filename, mz_uint flags); + +/* Extracts a archive file starting at the current position in the destination FILE stream. */ +mz_bool mz_zip_reader_extract_to_cfile(mz_zip_archive *pZip, mz_uint file_index, MZ_FILE *File, mz_uint flags); +mz_bool mz_zip_reader_extract_file_to_cfile(mz_zip_archive *pZip, const char *pArchive_filename, MZ_FILE *pFile, mz_uint flags); +#endif + +#if 0 +/* TODO */ + typedef void *mz_zip_streaming_extract_state_ptr; + mz_zip_streaming_extract_state_ptr mz_zip_streaming_extract_begin(mz_zip_archive *pZip, mz_uint file_index, mz_uint flags); + uint64_t mz_zip_streaming_extract_get_size(mz_zip_archive *pZip, mz_zip_streaming_extract_state_ptr pState); + uint64_t mz_zip_streaming_extract_get_cur_ofs(mz_zip_archive *pZip, mz_zip_streaming_extract_state_ptr pState); + mz_bool mz_zip_streaming_extract_seek(mz_zip_archive *pZip, mz_zip_streaming_extract_state_ptr pState, uint64_t new_ofs); + size_t mz_zip_streaming_extract_read(mz_zip_archive *pZip, mz_zip_streaming_extract_state_ptr pState, void *pBuf, size_t buf_size); + mz_bool mz_zip_streaming_extract_end(mz_zip_archive *pZip, mz_zip_streaming_extract_state_ptr pState); +#endif + +/* This function compares the archive's local headers, the optional local zip64 extended information block, and the optional descriptor following the compressed data vs. the data in the central directory. */ +/* It also validates that each file can be successfully uncompressed unless the MZ_ZIP_FLAG_VALIDATE_HEADERS_ONLY is specified. */ +mz_bool mz_zip_validate_file(mz_zip_archive *pZip, mz_uint file_index, mz_uint flags); + +/* Validates an entire archive by calling mz_zip_validate_file() on each file. */ +mz_bool mz_zip_validate_archive(mz_zip_archive *pZip, mz_uint flags); + +/* Misc utils/helpers, valid for ZIP reading or writing */ +mz_bool mz_zip_validate_mem_archive(const void *pMem, size_t size, mz_uint flags, mz_zip_error *pErr); +mz_bool mz_zip_validate_file_archive(const char *pFilename, mz_uint flags, mz_zip_error *pErr); + +/* Universal end function - calls either mz_zip_reader_end() or mz_zip_writer_end(). */ +mz_bool mz_zip_end(mz_zip_archive *pZip); + +/* -------- ZIP writing */ + +#ifndef MINIZ_NO_ARCHIVE_WRITING_APIS + +/* Inits a ZIP archive writer. */ +/*Set pZip->m_pWrite (and pZip->m_pIO_opaque) before calling mz_zip_writer_init or mz_zip_writer_init_v2*/ +/*The output is streamable, i.e. file_ofs in mz_file_write_func always increases only by n*/ +mz_bool mz_zip_writer_init(mz_zip_archive *pZip, mz_uint64 existing_size); +mz_bool mz_zip_writer_init_v2(mz_zip_archive *pZip, mz_uint64 existing_size, mz_uint flags); + +mz_bool mz_zip_writer_init_heap(mz_zip_archive *pZip, size_t size_to_reserve_at_beginning, size_t initial_allocation_size); +mz_bool mz_zip_writer_init_heap_v2(mz_zip_archive *pZip, size_t size_to_reserve_at_beginning, size_t initial_allocation_size, mz_uint flags); + +#ifndef MINIZ_NO_STDIO +mz_bool mz_zip_writer_init_file(mz_zip_archive *pZip, const char *pFilename, mz_uint64 size_to_reserve_at_beginning); +mz_bool mz_zip_writer_init_file_v2(mz_zip_archive *pZip, const char *pFilename, mz_uint64 size_to_reserve_at_beginning, mz_uint flags); +mz_bool mz_zip_writer_init_cfile(mz_zip_archive *pZip, MZ_FILE *pFile, mz_uint flags); +#endif + +/* Converts a ZIP archive reader object into a writer object, to allow efficient in-place file appends to occur on an existing archive. */ +/* For archives opened using mz_zip_reader_init_file, pFilename must be the archive's filename so it can be reopened for writing. If the file can't be reopened, mz_zip_reader_end() will be called. */ +/* For archives opened using mz_zip_reader_init_mem, the memory block must be growable using the realloc callback (which defaults to realloc unless you've overridden it). */ +/* Finally, for archives opened using mz_zip_reader_init, the mz_zip_archive's user provided m_pWrite function cannot be NULL. */ +/* Note: In-place archive modification is not recommended unless you know what you're doing, because if execution stops or something goes wrong before */ +/* the archive is finalized the file's central directory will be hosed. */ +mz_bool mz_zip_writer_init_from_reader(mz_zip_archive *pZip, const char *pFilename); +mz_bool mz_zip_writer_init_from_reader_v2(mz_zip_archive *pZip, const char *pFilename, mz_uint flags); + +/* Adds the contents of a memory buffer to an archive. These functions record the current local time into the archive. */ +/* To add a directory entry, call this method with an archive name ending in a forwardslash with an empty buffer. */ +/* level_and_flags - compression level (0-10, see MZ_BEST_SPEED, MZ_BEST_COMPRESSION, etc.) logically OR'd with zero or more mz_zip_flags, or just set to MZ_DEFAULT_COMPRESSION. */ +mz_bool mz_zip_writer_add_mem(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, mz_uint level_and_flags); + +/* Like mz_zip_writer_add_mem(), except you can specify a file comment field, and optionally supply the function with already compressed data. */ +/* uncomp_size/uncomp_crc32 are only used if the MZ_ZIP_FLAG_COMPRESSED_DATA flag is specified. */ +mz_bool mz_zip_writer_add_mem_ex(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, + mz_uint64 uncomp_size, mz_uint32 uncomp_crc32); + +mz_bool mz_zip_writer_add_mem_ex_v2(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, + mz_uint64 uncomp_size, mz_uint32 uncomp_crc32, MZ_TIME_T *last_modified, const char *user_extra_data_local, mz_uint user_extra_data_local_len, + const char *user_extra_data_central, mz_uint user_extra_data_central_len); + +/* Adds the contents of a file to an archive. This function also records the disk file's modified time into the archive. */ +/* File data is supplied via a read callback function. User mz_zip_writer_add_(c)file to add a file directly.*/ +mz_bool mz_zip_writer_add_read_buf_callback(mz_zip_archive *pZip, const char *pArchive_name, mz_file_read_func read_callback, void* callback_opaque, mz_uint64 size_to_add, + const MZ_TIME_T *pFile_time, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, const char *user_extra_data_local, mz_uint user_extra_data_local_len, + const char *user_extra_data_central, mz_uint user_extra_data_central_len); + +#ifndef MINIZ_NO_STDIO +/* Adds the contents of a disk file to an archive. This function also records the disk file's modified time into the archive. */ +/* level_and_flags - compression level (0-10, see MZ_BEST_SPEED, MZ_BEST_COMPRESSION, etc.) logically OR'd with zero or more mz_zip_flags, or just set to MZ_DEFAULT_COMPRESSION. */ +mz_bool mz_zip_writer_add_file(mz_zip_archive *pZip, const char *pArchive_name, const char *pSrc_filename, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags); + +/* Like mz_zip_writer_add_file(), except the file data is read from the specified FILE stream. */ +mz_bool mz_zip_writer_add_cfile(mz_zip_archive *pZip, const char *pArchive_name, MZ_FILE *pSrc_file, mz_uint64 size_to_add, + const MZ_TIME_T *pFile_time, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, const char *user_extra_data_local, mz_uint user_extra_data_local_len, + const char *user_extra_data_central, mz_uint user_extra_data_central_len); +#endif + +/* Adds a file to an archive by fully cloning the data from another archive. */ +/* This function fully clones the source file's compressed data (no recompression), along with its full filename, extra data (it may add or modify the zip64 local header extra data field), and the optional descriptor following the compressed data. */ +mz_bool mz_zip_writer_add_from_zip_reader(mz_zip_archive *pZip, mz_zip_archive *pSource_zip, mz_uint src_file_index); + +/* Finalizes the archive by writing the central directory records followed by the end of central directory record. */ +/* After an archive is finalized, the only valid call on the mz_zip_archive struct is mz_zip_writer_end(). */ +/* An archive must be manually finalized by calling this function for it to be valid. */ +mz_bool mz_zip_writer_finalize_archive(mz_zip_archive *pZip); + +/* Finalizes a heap archive, returning a pointer to the heap block and its size. */ +/* The heap block will be allocated using the mz_zip_archive's alloc/realloc callbacks. */ +mz_bool mz_zip_writer_finalize_heap_archive(mz_zip_archive *pZip, void **ppBuf, size_t *pSize); + +/* Ends archive writing, freeing all allocations, and closing the output file if mz_zip_writer_init_file() was used. */ +/* Note for the archive to be valid, it *must* have been finalized before ending (this function will not do it for you). */ +mz_bool mz_zip_writer_end(mz_zip_archive *pZip); + +/* -------- Misc. high-level helper functions: */ + +/* mz_zip_add_mem_to_archive_file_in_place() efficiently (but not atomically) appends a memory blob to a ZIP archive. */ +/* Note this is NOT a fully safe operation. If it crashes or dies in some way your archive can be left in a screwed up state (without a central directory). */ +/* level_and_flags - compression level (0-10, see MZ_BEST_SPEED, MZ_BEST_COMPRESSION, etc.) logically OR'd with zero or more mz_zip_flags, or just set to MZ_DEFAULT_COMPRESSION. */ +/* TODO: Perhaps add an option to leave the existing central dir in place in case the add dies? We could then truncate the file (so the old central dir would be at the end) if something goes wrong. */ +mz_bool mz_zip_add_mem_to_archive_file_in_place(const char *pZip_filename, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags); +mz_bool mz_zip_add_mem_to_archive_file_in_place_v2(const char *pZip_filename, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, mz_zip_error *pErr); + +/* Reads a single file from an archive into a heap block. */ +/* If pComment is not NULL, only the file with the specified comment will be extracted. */ +/* Returns NULL on failure. */ +void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename, const char *pArchive_name, size_t *pSize, mz_uint flags); +void *mz_zip_extract_archive_file_to_heap_v2(const char *pZip_filename, const char *pArchive_name, const char *pComment, size_t *pSize, mz_uint flags, mz_zip_error *pErr); + +#endif /* #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS */ + +#ifdef __cplusplus +} +#endif + +#endif /* MINIZ_NO_ARCHIVE_APIS */ diff --git a/tools/flasher_stub/include/rom_functions.h b/tools/flasher_stub/include/rom_functions.h new file mode 100644 index 0000000000..928eebc43a --- /dev/null +++ b/tools/flasher_stub/include/rom_functions.h @@ -0,0 +1,382 @@ +/* + * SPDX-FileCopyrightText: 2016 Cesanta Software Limited + * + * SPDX-License-Identifier: GPL-2.0-or-later + * + * SPDX-FileContributor: 2016-2022 Espressif Systems (Shanghai) CO LTD + */ + +/* ROM function prototypes for functions in ROM which are + called by the flasher stubs. +*/ +#pragma once + +#include +#include "soc_support.h" + +int uart_rx_one_char(uint8_t *ch); +uint8_t uart_rx_one_char_block(); +int uart_tx_one_char(char ch); + +#if ESP32C61 || ESP32C6 || ESP32H2 || ESP32C5 || ESP32C5BETA3 || ESP32P4 +/* uart_tx_one_char doesn't send data to USB device serial, needs to be replaced */ +int uart_tx_one_char2(char ch); +#define uart_tx_one_char(ch) uart_tx_one_char2(ch) +#endif // ESP32C61 ||ESP32C6 || ESP32H2 || ESP32C5 || ESP32C5BETA3 || ESP32P4 + +void uart_div_modify(uint32_t uart_no, uint32_t baud_div); + +void ets_delay_us(uint32_t us); + +typedef enum { SPI_FLASH_RESULT_OK = 0, + SPI_FLASH_RESULT_ERR = 1, + SPI_FLASH_RESULT_TIMEOUT = 2 } SpiFlashOpResult; + +SpiFlashOpResult SPILock(); +SpiFlashOpResult SPIUnlock(); +SpiFlashOpResult SPIRead(uint32_t addr, void *dst, uint32_t size); +SpiFlashOpResult SPIWrite(uint32_t addr, const uint8_t *src, uint32_t size); +SpiFlashOpResult SPIEraseChip(); +SpiFlashOpResult SPIEraseBlock(uint32_t block_num); +SpiFlashOpResult SPIEraseSector(uint32_t sector_num); +uint32_t SPI_read_status(); +uint32_t Wait_SPI_Idle(); +void spi_flash_attach(); + +void SelectSpiFunction(); +uint32_t SPIParamCfg(uint32_t deviceId, uint32_t chip_size, uint32_t block_size, uint32_t sector_size, uint32_t page_size, uint32_t status_mask); + +void ets_isr_mask(uint32_t ints); +void ets_isr_unmask(uint32_t ints); +void ets_set_user_start(void (*user_start_fn)()); + +void software_reset(); +void software_reset_cpu(int cpu_no); + +#ifdef ESP32C2 // ESP32C2 ROM uses mbedtls_md5 +struct MD5Context { // Called mbedtls_md5_context in ROM + uint32_t total[2]; // number of bytes processed + uint32_t state[4]; // intermediate digest state + unsigned char buffer[64]; // data block being processed +}; + +int mbedtls_md5_starts_ret(struct MD5Context *ctx); +int mbedtls_md5_update_ret(struct MD5Context *ctx, const unsigned char *input, size_t ilen); +int mbedtls_md5_finish_ret(struct MD5Context *ctx, unsigned char digest[16]); + +#define MD5Init(ctx) mbedtls_md5_starts_ret(ctx) +#define MD5Update(ctx, buf, n) mbedtls_md5_update_ret(ctx, buf, n) +#define MD5Final(digest, ctx) mbedtls_md5_finish_ret(ctx, digest) +#else // not ESP32C2 +struct MD5Context { + uint32_t buf[4]; + uint32_t bits[2]; + uint8_t in[64]; +}; + +void MD5Init(struct MD5Context *ctx); +void MD5Update(struct MD5Context *ctx, void *buf, uint32_t len); +void MD5Final(uint8_t digest[16], struct MD5Context *ctx); +#endif // not ESP32C2 + +typedef struct { + uint32_t device_id; + uint32_t chip_size; // chip size in bytes + uint32_t block_size; + uint32_t sector_size; + uint32_t page_size; + uint32_t status_mask; +} esp_rom_spiflash_chip_t; + + +typedef void (*int_handler_t)(void *arg); +int_handler_t ets_isr_attach(uint32_t int_num, int_handler_t handler, + void *arg); +/* Some ESP32-onwards ROM functions */ +#if ESP32_OR_LATER +void uart_tx_flush(int uart); +uint32_t ets_efuse_get_spiconfig(void); + +#if ESP32 +SpiFlashOpResult esp_rom_spiflash_write_encrypted(uint32_t addr, const uint8_t *src, uint32_t size); +#else +void SPI_Write_Encrypt_Enable(); +void SPI_Write_Encrypt_Disable(); +SpiFlashOpResult SPI_Encrypt_Write(uint32_t flash_addr, const void* data, uint32_t len); +#endif + +#if ESP32S2_OR_LATER +uint32_t GetSecurityInfoProc(int* pMsg, int* pnErr, uint8_t *buf); // pMsg and pnErr unused in ROM +#if ESP32C3 +extern uint32_t _rom_eco_version; // rom constant to define ECO version +uint32_t GetSecurityInfoProcNewEco(int* pMsg, int* pnErr, uint8_t *buf); // GetSecurityInfo for C3 ECO7+ +#endif // ESP32C3 +SpiFlashOpResult SPI_read_status_high(esp_rom_spiflash_chip_t *spi, uint32_t *status); +#else +/* Note: On ESP32 this was a static function whose first argument was elided by the + compiler. */ +SpiFlashOpResult SPI_read_status_high(uint32_t *status); +#endif + +SpiFlashOpResult SPI_write_status(esp_rom_spiflash_chip_t *spi, uint32_t status_value); + +void intr_matrix_set(int cpu_no, uint32_t module_num, uint32_t intr_num); +#endif /* ESP32_OR_LATER */ + +/* RISC-V-only ROM functions */ +#if IS_RISCV +void esprv_intc_int_set_priority(int intr_num, int priority); +#endif // IS_RISCV + +/* USB-OTG and USB-JTAG-Serial imports */ +#ifdef WITH_USB_OTG +#define ACM_BYTES_PER_TX 64 +#define ACM_STATUS_LINESTATE_CHANGED -1 +#define ACM_STATUS_RX -4 +#define LINE_CTRL_BAUD_RATE (1 << 0) +#define LINE_CTRL_RTS (1 << 1) +#define LINE_CTRL_DTR (1 << 2) +#define LINE_CTRL_DCD (1 << 3) +#define LINE_CTRL_DSR (1 << 4) +#define USBDC_PERSIST_ENA (1<<31) +void usb_dw_isr_handler(void* arg); +typedef void cdc_acm_device; +extern cdc_acm_device *uart_acm_dev; +typedef void(*uart_irq_callback_t)(cdc_acm_device *dev, int status); +void cdc_acm_irq_callback_set(cdc_acm_device *dev, uart_irq_callback_t cb); +void cdc_acm_irq_rx_enable(cdc_acm_device *dev); +void cdc_acm_irq_rx_disable(cdc_acm_device *dev); +int cdc_acm_fifo_read(cdc_acm_device *dev, uint8_t *rx_data, const int size); +int cdc_acm_fifo_fill(cdc_acm_device *dev, const uint8_t *tx_data, int len); +int cdc_acm_line_ctrl_get(cdc_acm_device *dev, uint32_t ctrl, uint32_t *val); +int cdc_acm_rx_fifo_cnt(cdc_acm_device *dev); +void cdc_acm_irq_state_enable(cdc_acm_device *dev); +void usb_dc_check_poll_for_interrupts(void); +void chip_usb_set_persist_flags(uint32_t flags); +int usb_dc_prepare_persist(void); +#endif // WITH_USB_OTG + +#if WITH_USB_JTAG_SERIAL || WITH_USB_OTG +typedef struct { + uint8_t *pRcvMsgBuff; + uint8_t *pWritePos; + uint8_t *pReadPos; + uint8_t TrigLvl; + int BuffState; +} RcvMsgBuff; + +typedef struct { + int baud_rate; + int data_bits; + int exist_parity; + int parity; + int stop_bits; + int flow_ctrl; + uint8_t buff_uart_no; + RcvMsgBuff rcv_buff; + int rcv_state; + int received; +} UartDevice; + +UartDevice * GetUartDevice(); +#endif // WITH_USB_JTAG_SERIAL || WITH_USB_OTG + +#if defined(ESP32S3) || defined(ESP32P4) +#define BIT(nr) (1UL << (nr)) +#define ESP_ROM_OPIFLASH_SEL_CS0 (BIT(0)) + +typedef enum { + SPI_FLASH_QIO_MODE = 0, + SPI_FLASH_QOUT_MODE, + SPI_FLASH_DIO_MODE, + SPI_FLASH_DOUT_MODE, + SPI_FLASH_FASTRD_MODE, + SPI_FLASH_SLOWRD_MODE, + SPI_FLASH_OPI_STR_MODE, + SPI_FLASH_OPI_DTR_MODE, + SPI_FLASH_OOUT_MODE, + SPI_FLASH_OIO_STR_MODE, + SPI_FLASH_OIO_DTR_MODE, + SPI_FLASH_QPI_MODE, +} SpiFlashRdMode; + +typedef enum { + ESP_ROM_SPIFLASH_RESULT_OK, + ESP_ROM_SPIFLASH_RESULT_ERR, + ESP_ROM_SPIFLASH_RESULT_TIMEOUT +} esp_rom_spiflash_result_t; + +#define CMD_RDID 0x9F +#define CMD_RDSR 0x05 +#define CMD_WREN 0x06 +#define CMD_SECTOR_ERASE 0x20 +#define CMD_SECTOR_ERASE_4B 0x21 +#define CMD_FSTRD4B 0x0C +#define CMD_LARGE_BLOCK_ERASE 0xD8 +#define CMD_LARGE_BLOCK_ERASE_4B 0xDC +#define CMD_PROGRAM_PAGE_4B 0x12 + +#define OPIFLASH_DRIVER() { \ + .rdid = { \ + .mode = SPI_FLASH_FASTRD_MODE, \ + .cmd_bit_len = 8, \ + .cmd = CMD_RDID, \ + .addr = 0, \ + .addr_bit_len = 0, \ + .dummy_bit_len = 0, \ + .data_bit_len = 24, \ + .cs_sel = 0x1, \ + .is_pe = 0, \ + }, \ + .rdsr = { \ + .mode = SPI_FLASH_FASTRD_MODE, \ + .cmd_bit_len = 8, \ + .cmd = CMD_RDSR, \ + .addr = 0, \ + .addr_bit_len = 0, \ + .dummy_bit_len = 0, \ + .data_bit_len = 8, \ + .cs_sel = 0x1, \ + .is_pe = 0, \ + }, \ + .wren = { \ + .mode = SPI_FLASH_FASTRD_MODE, \ + .cmd_bit_len = 8, \ + .cmd = CMD_WREN, \ + .addr = 0, \ + .addr_bit_len = 0, \ + .dummy_bit_len = 0, \ + .data_bit_len = 0, \ + .cs_sel = 0x1, \ + .is_pe = 0, \ + }, \ + .se = { \ + .mode = SPI_FLASH_FASTRD_MODE, \ + .cmd_bit_len = 8, \ + .cmd = CMD_SECTOR_ERASE_4B, \ + .addr = 0, \ + .addr_bit_len = 32, \ + .dummy_bit_len = 0, \ + .data_bit_len = 0, \ + .cs_sel = 0x1, \ + .is_pe = 1, \ + }, \ + .be64k = { \ + .mode = SPI_FLASH_FASTRD_MODE, \ + .cmd_bit_len = 8, \ + .cmd = CMD_LARGE_BLOCK_ERASE_4B, \ + .addr = 0, \ + .addr_bit_len = 32, \ + .dummy_bit_len = 0, \ + .data_bit_len = 0, \ + .cs_sel = 0x1, \ + .is_pe = 1, \ + }, \ + .read = { \ + .mode = SPI_FLASH_FASTRD_MODE, \ + .cmd_bit_len = 8, \ + .cmd = CMD_FSTRD4B, \ + .addr = 0, \ + .addr_bit_len = 32, \ + .dummy_bit_len = 0, \ + .data_bit_len = 0, \ + .cs_sel = 0x1, \ + .is_pe = 0, \ + }, \ + .pp = { \ + .mode = SPI_FLASH_FASTRD_MODE, \ + .cmd_bit_len = 8, \ + .cmd = CMD_PROGRAM_PAGE_4B, \ + .addr = 0, \ + .addr_bit_len = 32, \ + .dummy_bit_len = 0, \ + .data_bit_len = 0, \ + .cs_sel = 0x1, \ + .is_pe = 1, \ + }, \ + .cache_rd_cmd = { \ + .addr_bit_len = 32, \ + .dummy_bit_len = 20*2, \ + .cmd = CMD_FSTRD4B, \ + .cmd_bit_len = 16, \ + .var_dummy_en = 1, \ + } \ +} + +#ifndef ESP32S3BETA2 +typedef struct { + uint8_t mode; + uint8_t cmd_bit_len; + uint16_t cmd; + uint32_t addr; + uint8_t addr_bit_len; + uint8_t dummy_bit_len; + uint8_t data_bit_len; + uint8_t cs_sel: 4; + uint8_t is_pe: 4; +} esp_rom_opiflash_cmd_t; + +typedef struct { + uint8_t addr_bit_len; + uint8_t dummy_bit_len; + uint16_t cmd; + uint8_t cmd_bit_len; + uint8_t var_dummy_en; +} esp_rom_opiflash_spi0rd_t; + +typedef struct { + esp_rom_opiflash_cmd_t rdid; + esp_rom_opiflash_cmd_t rdsr; + esp_rom_opiflash_cmd_t wren; + esp_rom_opiflash_cmd_t se; + esp_rom_opiflash_cmd_t be64k; + esp_rom_opiflash_cmd_t read; + esp_rom_opiflash_cmd_t pp; + esp_rom_opiflash_spi0rd_t cache_rd_cmd; +} esp_rom_opiflash_def_t; + +void esp_rom_opiflash_legacy_driver_init(const esp_rom_opiflash_def_t *flash_cmd_def); +bool ets_efuse_flash_octal_mode(void); +#endif //ESP32S3BETA2 + +void esp_rom_opiflash_exec_cmd(int spi_num, SpiFlashRdMode mode, + uint32_t cmd, int cmd_bit_len, + uint32_t addr, int addr_bit_len, + int dummy_bits, + uint8_t* mosi_data, int mosi_bit_len, + uint8_t* miso_data, int miso_bit_len, + uint32_t cs_mask, + bool is_write_erase_operation); + +#if ESP32P4 +extern uint32_t _rom_eco_version; // rom constant to define ECO version +void esp_rom_opiflash_exec_cmd_eco1(int spi_num, SpiFlashRdMode mode, + uint32_t cmd, int cmd_bit_len, + uint32_t addr, int addr_bit_len, + int dummy_bits, + uint8_t* mosi_data, int mosi_bit_len, + uint8_t* miso_data, int miso_bit_len, + uint32_t cs_mask, + bool is_write_erase_operation); + +void esp_rom_opiflash_exec_cmd_eco2(int spi_num, SpiFlashRdMode mode, + uint32_t cmd, int cmd_bit_len, + uint32_t addr, int addr_bit_len, + int dummy_bits, + uint8_t* mosi_data, int mosi_bit_len, + uint8_t* miso_data, int miso_bit_len, + uint32_t cs_mask, + bool is_write_erase_operation); +#endif // ESP32P4 + +esp_rom_spiflash_result_t esp_rom_opiflash_wait_idle(); +esp_rom_spiflash_result_t esp_rom_opiflash_wren(); +esp_rom_spiflash_result_t esp_rom_opiflash_erase_sector(uint32_t sector_num); +esp_rom_spiflash_result_t esp_rom_opiflash_erase_block_64k(uint32_t block_num); +SpiFlashOpResult SPI_write_enable(esp_rom_spiflash_chip_t *spi); + +void esp_rom_spiflash_write_encrypted_enable(); +void esp_rom_spiflash_write_encrypted_disable(); +SpiFlashOpResult esp_rom_spiflash_unlock(); +SpiFlashOpResult esp_rom_spiflash_wait_idle(void); +#endif // ESP32S3 || ESP32P4 diff --git a/tools/flasher_stub/include/slip.h b/tools/flasher_stub/include/slip.h new file mode 100644 index 0000000000..17608e5fb9 --- /dev/null +++ b/tools/flasher_stub/include/slip.h @@ -0,0 +1,40 @@ +/* + * SPDX-FileCopyrightText: 2016 Cesanta Software Limited + * + * SPDX-License-Identifier: GPL-2.0-or-later + * + * SPDX-FileContributor: 2016-2022 Espressif Systems (Shanghai) CO LTD + */ + +#ifndef SLIP_H_ +#define SLIP_H_ + +#include + +/* Send the SLIP frame begin/end delimiter. */ +void SLIP_send_frame_delimiter(void); + +/* Send a single character of SLIP frame data, escaped as per SLIP escaping. */ +void SLIP_send_frame_data(char ch); + +/* Send some SLIP frame data, escaped as per SLIP escaping. */ +void SLIP_send_frame_data_buf(const void *buf, uint32_t size); + +/* Send a full SLIP frame, with specified contents. */ +void SLIP_send(const void *pkt, uint32_t size); + +typedef enum { + SLIP_NO_FRAME, + SLIP_FRAME, + SLIP_FRAME_ESCAPING +} slip_state_t; + +int16_t SLIP_recv_byte(char byte, slip_state_t *state); + +#define SLIP_FINISHED_FRAME -2 +#define SLIP_NO_BYTE -1 + +/* Receive a SLIP frame, with specified contents. */ +uint32_t SLIP_recv(void *pkt, uint32_t max_len); + +#endif /* SLIP_H_ */ diff --git a/tools/flasher_stub/include/soc_support.h b/tools/flasher_stub/include/soc_support.h new file mode 100644 index 0000000000..df28ec1534 --- /dev/null +++ b/tools/flasher_stub/include/soc_support.h @@ -0,0 +1,691 @@ +/* + * SPDX-FileCopyrightText: 2016-2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +/* SoC-level support. + * + * Provide a unified register-level interface. + * + * This is the same information provided in the register headers + * of ESP8266 Non-OS SDK and ESP-IDF soc component, however + * only values that are needed for the flasher stub are included here. + * + */ +#pragma once + +#include +#include +#include + +#define READ_REG(REG) (*((volatile uint32_t *)(REG))) +#define WRITE_REG(REG, VAL) *((volatile uint32_t *)(REG)) = (VAL) +#define REG_SET_MASK(reg, mask) WRITE_REG((reg), (READ_REG(reg)|(mask))) +#define REG_CLR_MASK(reg, mask) WRITE_REG((reg), (READ_REG(reg)&(~(mask)))) +#define REG_SET_FIELD(_r, _f, _v) (WRITE_REG((_r),((READ_REG(_r) & ~((_f) << (_f##_S)))|(((_v) & (_f))<<(_f##_S))))) +#define REG_GET_FIELD(_r, _f) ((READ_REG(_r) >> (_f##_S)) & (_f##_V)) +#define REG_SET_BIT(_r, _b) \ + do \ + { \ + *(volatile uint32_t *)(_r) = (*(volatile uint32_t *)(_r)) | (_b); \ + } while (0) + +#define REG_CLR_BIT(_r, _b) \ + do \ + { \ + *(volatile uint32_t *)(_r) = (*(volatile uint32_t *)(_r)) & (~(_b)); \ + } while (0) + +#define ESP32_OR_LATER !(ESP8266) +#define ESP32S2_OR_LATER !(ESP8266 || ESP32) +#define ESP32S3_OR_LATER !(ESP8266 || ESP32 || ESP32S2) + +/********************************************************** + * Per-SOC capabilities + */ +#ifdef ESP32S2 +#define WITH_USB_OTG 1 +#endif // ESP32S2 + +#ifdef ESP32C3 +#define WITH_USB_JTAG_SERIAL 1 +#define IS_RISCV 1 +#endif // ESP32C3 + +#ifdef ESP32S3 +#define WITH_USB_JTAG_SERIAL 1 +#define WITH_USB_OTG 1 +#endif // ESP32S3 + +#ifdef ESP32C5 +#define WITH_USB_JTAG_SERIAL 1 +#define IS_RISCV 1 +#endif // ESP32C5 + +#ifdef ESP32C5BETA3 +#define WITH_USB_JTAG_SERIAL 0 +#define IS_RISCV 1 +#endif // ESP32C5BETA3 + +#ifdef ESP32C6 +#define WITH_USB_JTAG_SERIAL 1 +#define IS_RISCV 1 +#endif // ESP32C6 + +#ifdef ESP32C61 +#define WITH_USB_JTAG_SERIAL 1 +#define IS_RISCV 1 +#endif // ESP32C61 + +#ifdef ESP32H2 +#define WITH_USB_JTAG_SERIAL 1 +#define IS_RISCV 1 +#endif // ESP32H2 + +#ifdef ESP32P4 +#define WITH_USB_JTAG_SERIAL 1 +#define WITH_USB_OTG 1 +#define IS_RISCV 1 +#endif // ESP32P4 + +// Increase CPU freq to speed up read/write operations over USB +// Disabled on the S3 due to stability issues, would require dbias adjustment. +// https://github.com/espressif/esptool/issues/832, https://github.com/espressif/esptool/issues/808 +// Disabled for P4 because it is already running on high (360MHz) CPU frequency +#define USE_MAX_CPU_FREQ ((WITH_USB_JTAG_SERIAL || WITH_USB_OTG) && !ESP32S3 && !ESP32P4) + +// Later chips don't support ets_efuse_get_spiconfig. +#define SUPPORT_CONFIG_SPI (ESP32 || ESP32S2 || ESP32S3 || ESP32S3BETA2 || ESP32C3 || ESP32H2BETA1 || ESP32H2BETA2 || ESP32C6BETA) + +/********************************************************** + * Per-SOC based peripheral register base addresses + * Sync with reg_base.h in ESP-IDF + */ +#ifdef ESP8266 +#define UART_BASE_REG 0x60000000 /* UART0 */ +#define SPI_BASE_REG 0x60000200 /* SPI peripheral 0 */ +#endif + +#ifdef ESP32 +#define UART_BASE_REG 0x3ff40000 /* UART0 */ +#define SPI_BASE_REG 0x3ff42000 /* SPI peripheral 1, used for SPI flash */ +#define SPI0_BASE_REG 0x3ff43000 /* SPI peripheral 0, inner state machine */ +#define GPIO_BASE_REG 0x3ff44000 /* GPIO */ +#define DR_REG_IO_MUX_BASE 0x3ff49000 +#endif + +#ifdef ESP32S2 +#define UART_BASE_REG 0x60000000 /* UART0 */ +#define SPI_BASE_REG 0x3f402000 /* SPI peripheral 1, used for SPI flash */ +#define SPI0_BASE_REG 0x3f403000 /* SPI peripheral 0, inner state machine */ +#define GPIO_BASE_REG 0x3f404000 +#define USB_BASE_REG 0x60080000 +#define RTCCNTL_BASE_REG 0x3f408000 +#define SYSTEM_BASE_REG 0x3F4C0000 +#define DR_REG_IO_MUX_BASE 0x3f409000 +#endif + +#ifdef ESP32S3 +#define UART_BASE_REG 0x60000000 /* UART0 */ +#define SPI_BASE_REG 0x60002000 /* SPI peripheral 1, used for SPI flash */ +#define SPI0_BASE_REG 0x60003000 /* SPI peripheral 0, inner state machine */ +#define GPIO_BASE_REG 0x60004000 /* GPIO */ +#define USB_BASE_REG 0x60080000 +#define RTCCNTL_BASE_REG 0x60008000 /* RTC Control */ +#define USB_DEVICE_BASE_REG 0x60038000 +#define SYSTEM_BASE_REG 0x600C0000 +#define DR_REG_IO_MUX_BASE 0x60009000 +#define DR_REG_AES_XTS_BASE 0x600CC000 +#endif + +#ifdef ESP32S3BETA2 +#define UART_BASE_REG 0x60000000 /* UART0 */ +#define SPI_BASE_REG 0x60002000 /* SPI peripheral 1, used for SPI flash */ +#define SPI0_BASE_REG 0x60003000 /* SPI peripheral 0, inner state machine */ +#define GPIO_BASE_REG 0x60004000 /* GPIO */ +#define USB_BASE_REG 0x60080000 +#define RTCCNTL_BASE_REG 0x60008000 /* RTC Control */ +#define USB_DEVICE_BASE_REG 0x60038000 +#define SYSTEM_BASE_REG 0x600C0000 +#define DR_REG_IO_MUX_BASE 0x60009000 +#endif + +#ifdef ESP32C3 +#define UART_BASE_REG 0x60000000 /* UART0 */ +#define SPI_BASE_REG 0x60002000 /* SPI peripheral 1, used for SPI flash */ +#define SPI0_BASE_REG 0x60003000 /* SPI peripheral 0, inner state machine */ +#define GPIO_BASE_REG 0x60004000 +#define RTCCNTL_BASE_REG 0x60008000 /* RTC Control */ +#define USB_DEVICE_BASE_REG 0x60043000 +#define SYSTEM_BASE_REG 0x600C0000 +#define DR_REG_IO_MUX_BASE 0x60009000 +#endif + +#ifdef ESP32C6BETA +#define UART_BASE_REG 0x60000000 /* UART0 */ +#define SPI_BASE_REG 0x60002000 /* SPI peripheral 1, used for SPI flash */ +#define SPI0_BASE_REG 0x60003000 /* SPI peripheral 0, inner state machine */ +#define GPIO_BASE_REG 0x60004000 +#define DR_REG_IO_MUX_BASE 0x60009000 +#endif + +#ifdef ESP32H2BETA1 +#define UART_BASE_REG 0x60000000 /* UART0 */ +#define SPI_BASE_REG 0x60002000 /* SPI peripheral 1, used for SPI flash */ +#define SPI0_BASE_REG 0x60003000 /* SPI peripheral 0, inner state machine */ +#define GPIO_BASE_REG 0x60004000 +#define RTCCNTL_BASE_REG 0x60008000 +#define DR_REG_IO_MUX_BASE 0x60009000 +#endif + +#ifdef ESP32H2BETA2 +#define UART_BASE_REG 0x60000000 /* UART0 */ +#define SPI_BASE_REG 0x60002000 /* SPI peripheral 1, used for SPI flash */ +#define SPI0_BASE_REG 0x60003000 /* SPI peripheral 0, inner state machine */ +#define GPIO_BASE_REG 0x60004000 +#define DR_REG_IO_MUX_BASE 0x60009000 +#endif + +#ifdef ESP32C2 +#define UART_BASE_REG 0x60000000 /* UART0 */ +#define SPI_BASE_REG 0x60002000 /* SPI peripheral 1, used for SPI flash */ +#define SPI0_BASE_REG 0x60003000 /* SPI peripheral 0, inner state machine */ +#define GPIO_BASE_REG 0x60004000 +#define DR_REG_IO_MUX_BASE 0x60009000 +#endif + +#if ESP32C61 || ESP32C6 || ESP32C5 || ESP32C5BETA3 +#define UART_BASE_REG 0x60000000 /* UART0 */ +#define SPI_BASE_REG 0x60003000 /* SPI peripheral 1, used for SPI flash */ +#define SPI0_BASE_REG 0x60002000 /* SPI peripheral 0, inner state machine */ +#define GPIO_BASE_REG 0x60091000 +#define USB_DEVICE_BASE_REG 0x6000F000 +#define DR_REG_PCR_BASE 0x60096000 +#define DR_REG_LP_WDT_BASE 0x600B1C00 +#define DR_REG_IO_MUX_BASE 0x60009000 +#endif + +#ifdef ESP32H2 +#define UART_BASE_REG 0x60000000 /* UART0 */ +#define SPI_BASE_REG 0x60003000 /* SPI peripheral 1, used for SPI flash */ +#define SPI0_BASE_REG 0x60002000 /* SPI peripheral 0, inner state machine */ +#define GPIO_BASE_REG 0x60091000 +#define USB_DEVICE_BASE_REG 0x6000F000 +#define DR_REG_PCR_BASE 0x60096000 +#define DR_REG_LP_WDT_BASE 0x600B1C00 +#define DR_REG_IO_MUX_BASE 0x60009000 +#endif + +#ifdef ESP32P4 +#define UART_BASE_REG 0x500CA000 /* UART0 */ +#define SPI_BASE_REG 0x5008D000 /* SPI peripheral 1, used for SPI flash */ +#define SPI0_BASE_REG 0x5008C000 /* SPI peripheral 0, inner state machine */ +#define USB_BASE_REG 0x50000000 +#define GPIO_BASE_REG 0x500E0000 +#define USB_DEVICE_BASE_REG 0x500D2000 +#define DR_REG_LP_SYS_BASE 0x50110000 +#define DR_REG_LP_WDT_BASE 0x50116000 +#define DR_REG_IO_MUX_BASE 0x500E1000 +#define HP_SYS_USBOTG20_CTRL_REG 0x500E515C +#endif + +/********************************************************** + * UART peripheral + * + * The features we use are basically the same on all chips + * + * Only UART0 is used + */ +#define UART_CLKDIV_REG(X) (UART_BASE_REG + 0x14) +#define UART_CLKDIV_M (0x000FFFFF) + +#if ESP32_OR_LATER +#define UART_CLKDIV_FRAG_S 20 +#define UART_CLKDIV_FRAG_V 0xF +#endif + +#define UART_FIFO(X) (UART_BASE_REG + 0x00) +#define UART_INT_ST(X) (UART_BASE_REG + 0x08) +#define UART_INT_ENA(X) (UART_BASE_REG + 0x0C) +#define UART_INT_CLR(X) (UART_BASE_REG + 0x10) +#define UART_STATUS(X) (UART_BASE_REG + 0x1C) + +#if ESP32S2_OR_LATER && !ESP32C61 && !ESP32C6 && !ESP32H2 +#define UART_RXFIFO_CNT_M 0x3FF +#else +#define UART_RXFIFO_CNT_M 0xFF +#endif + +#define UART_RXFIFO_FULL_INT_ENA (1<<0) +#define UART_RXFIFO_TOUT_INT_ENA (1<<8) + +#define ETS_UART0_INUM 5 + + +/********************************************************** + * SPI peripheral + * + * The features we use are mostly the same on all chips + * except for W0 base address & option for 2-byte status command + * + * Only one SPI peripheral is used (0 on ESP8266, 1 on ESP32). + * On ESP32S2 && ESP32S3 this is called SPI_MEM_xxx index 1 + */ +#define SPI_CMD_REG (SPI_BASE_REG + 0x00) +#define SPI_FLASH_WREN (1<<30) +#define SPI_FLASH_RDSR (1<<27) +#define SPI_FLASH_SE (1<<24) +#define SPI_FLASH_BE (1<<23) + +#define SPI_ADDR_REG (SPI_BASE_REG + 0x04) + +#define SPI_CTRL_REG (SPI_BASE_REG + 0x08) +#if ESP32_OR_LATER +#define SPI_WRSR_2B (1<<22) +#endif + +#if ESP32S2_OR_LATER +#define SPI_RD_STATUS_REG (SPI_BASE_REG + 0x2C) +#else +#define SPI_RD_STATUS_REG (SPI_BASE_REG + 0x10) +#endif + +#ifdef ESP8266 +#define SPI_W0_REG (SPI_BASE_REG + 0x40) +#endif +#ifdef ESP32 +#define SPI_W0_REG (SPI_BASE_REG + 0x80) +#endif +#if ESP32S2_OR_LATER +#define SPI_W0_REG (SPI_BASE_REG + 0x58) +#endif + +#if ESP32S2_OR_LATER +#define SPI_EXT2_REG (SPI_BASE_REG + 0x54) /* renamed SPI_MEM_FSM_REG */ +#else +#define SPI_EXT2_REG (SPI_BASE_REG + 0xF8) +#endif + +#define SPI_ST 0x7 /* done state value */ + +#ifdef ESP32 +/* On ESP32 & newer the SPI peripherals are layered + * flash, this lets us check the state of the internal + * state machine under the SPI flash controller + */ +#define SPI0_EXT2_REG (SPI0_BASE_REG + 0xF8) +#endif +#if ESP32S2_OR_LATER +#define SPI0_EXT2_REG (SPI0_BASE_REG + 0x54) +#endif + +/********************************************************** + * GPIO peripheral + * + * We only need to read the strapping register on ESP32 or later + */ +#define GPIO_STRAP_REG (GPIO_BASE_REG + 0x38) + +/********************************************************** + * USB peripheral + */ + +#ifdef ESP32S2 +#define UART_USB_OTG 2 + +#define ETS_USB_INTR_SOURCE 48 +#define ETS_USB_INUM 9 /* arbitrary level 1 level interrupt */ +#endif // ESP32S2 + +#ifdef ESP32C3 +#define UART_USB_JTAG_SERIAL 3 + +#define DR_REG_INTERRUPT_CORE0_BASE 0x600c2000 +#define INTERRUPT_CORE0_USB_INTR_MAP_REG (DR_REG_INTERRUPT_CORE0_BASE + 0x068) /* USB-JTAG-Serial */ + +#define ETS_USB_INUM 17 /* arbitrary level 1 level interrupt */ +#endif // ESP32C3 + +#ifdef ESP32S3 +#define UART_USB_OTG 3 +#define UART_USB_JTAG_SERIAL 4 + +#define DR_REG_INTERRUPT_CORE0_BASE 0x600c2000 +#define INTERRUPT_CORE0_USB_INTR_MAP_REG (DR_REG_INTERRUPT_CORE0_BASE + 0x098) /* DWC-OTG */ +#define INTERRUPT_CORE0_USB_DEVICE_INT_MAP_REG (DR_REG_INTERRUPT_CORE0_BASE + 0x180) /* USB-JTAG-Serial */ + +#define ETS_USB_INUM 17 /* arbitrary level 1 level interrupt */ +#endif // ESP32S3 + +#if ESP32C6 +#define UART_USB_JTAG_SERIAL 3 + +#define DR_REG_INTERRUPT_MATRIX_BASE 0x60010000 +#define INTERRUPT_CORE0_USB_INTR_MAP_REG (DR_REG_INTERRUPT_MATRIX_BASE + 0xC0) /* USB-JTAG-Serial, INTMTX_CORE0_USB_INTR_MAP_REG */ + +#define ETS_USB_INUM 17 /* arbitrary level 1 level interrupt */ +#endif // ESP32C6 + +#if ESP32C61 +#define UART_USB_JTAG_SERIAL 4 + +#define DR_REG_INTERRUPT_MATRIX_BASE 0x60010000 +#define INTERRUPT_CORE0_USB_INTR_MAP_REG (DR_REG_INTERRUPT_MATRIX_BASE + 0xB0) /* USB-JTAG-Serial, INTMTX_CORE0_USB_INTR_MAP_REG */ + +#define CLIC_EXT_INTR_NUM_OFFSET 16 /* For CLIC first 16 interrupts are reserved as internal */ +#define ETS_USB_INUM 17 /* arbitrary level 1 level interrupt */ +#endif // ESP32C61 + +#if ESP32C5 +#define UART_USB_JTAG_SERIAL 3 + +#define DR_REG_INTERRUPT_MATRIX_BASE 0x60010000 +#define INTERRUPT_CORE0_USB_INTR_MAP_REG (DR_REG_INTERRUPT_MATRIX_BASE + 0xD8) /* USB-JTAG-Serial, INTERRUPT_CORE0_USB_SERIAL_JTAG_INTR_MAP_REG */ + +#define CLIC_EXT_INTR_NUM_OFFSET 16 /* For CLIC first 16 interrupts are reserved as internal */ +#define ETS_USB_INUM 17 /* arbitrary level 1 level interrupt */ +#endif // ESP32C5 + +#ifdef ESP32H2 +#define UART_USB_JTAG_SERIAL 3 + +#define DR_REG_INTERRUPT_MATRIX_BASE 0x60010000 +#define INTERRUPT_CORE0_USB_INTR_MAP_REG (DR_REG_INTERRUPT_MATRIX_BASE + 0x94) /* USB-JTAG-Serial, INTMTX_CORE0_USB_INTR_MAP_REG */ + +#define ETS_USB_INUM 17 /* arbitrary level 1 level interrupt */ +#endif // ESP32H2 + +#if ESP32P4 +#define UART_USB_OTG 5 +#define UART_USB_JTAG_SERIAL 6 + +#define DR_REG_INTERRUPT_MATRIX_BASE 0x500D6000 +#define INTERRUPT_CORE0_USB_INTR_MAP_REG (DR_REG_INTERRUPT_MATRIX_BASE + 0x58) /* USB-JTAG-Serial, CORE0_USB_DEVICE_INT_MAP_REG */ +#define INTERRUPT_CORE0_USB_OTG_INT_MAP_REG (DR_REG_INTERRUPT_MATRIX_BASE + 0x174) /* DWC-OTG, CORE0_USB_OTG_INT_MAP_REG */ + +#define CLIC_EXT_INTR_NUM_OFFSET 16 /* For CLIC first 16 interrupts are reserved as internal */ +#define ETS_USB_INUM 17 /* arbitrary level 1 level interrupt */ +#endif + +#ifdef WITH_USB_JTAG_SERIAL +#define USB_DEVICE_INT_ENA_REG (USB_DEVICE_BASE_REG + 0x010) +#define USB_DEVICE_INT_CLR_REG (USB_DEVICE_BASE_REG + 0x014) +#define USB_DEVICE_EP1_CONF_REG (USB_DEVICE_BASE_REG + 0x004) +#define USB_DEVICE_EP1_REG (USB_DEVICE_BASE_REG + 0x000) +#define USB_DEVICE_SERIAL_OUT_RECV_PKT_INT_CLR (1<<2) +#define USB_DEVICE_SERIAL_OUT_EP_DATA_AVAIL (1<<2) +#define USB_DEVICE_SERIAL_OUT_RECV_PKT_INT_ENA (1<<2) +#endif // WITH_USB_JTAG_SERIAL + +#define USB_GAHBCFG_REG (USB_BASE_REG + 0x8) +#define USB_GLBLLNTRMSK (1 << 0) + + +/********************************************************** + * RTC_CNTL peripheral + */ + +#ifdef ESP32S2 +#define RTC_CNTL_OPTION1_REG (RTCCNTL_BASE_REG + 0x0128) +#endif + +#ifdef ESP32S3 +#define RTC_CNTL_OPTION1_REG (RTCCNTL_BASE_REG + 0x012C) +#define RTC_CNTL_WDTCONFIG0_REG (RTCCNTL_BASE_REG + 0x0098) // RTC_CNTL_RTC_WDTCONFIG0_REG +#define RTC_CNTL_WDTWPROTECT_REG (RTCCNTL_BASE_REG + 0x00B0) // RTC_CNTL_RTC_WDTWPROTECT_REG +#define RTC_CNTL_SWD_CONF_REG (RTCCNTL_BASE_REG + 0x00B4) +#define RTC_CNTL_SWD_WPROTECT_REG (RTCCNTL_BASE_REG + 0x00B8) +#define RTC_CNTL_SWD_WKEY 0x8F1D312A +#define RTC_CNTL_SWD_AUTO_FEED_EN (1 << 31) +#endif + +#ifdef ESP32C3 +#define RTC_CNTL_WDTCONFIG0_REG (RTCCNTL_BASE_REG + 0x0090) +#define RTC_CNTL_WDTWPROTECT_REG (RTCCNTL_BASE_REG + 0x00A8) +#define RTC_CNTL_SWD_CONF_REG (RTCCNTL_BASE_REG + 0x00AC) +#define RTC_CNTL_SWD_WPROTECT_REG (RTCCNTL_BASE_REG + 0x00B0) +#define RTC_CNTL_SWD_WKEY 0x8F1D312A +#define RTC_CNTL_SWD_AUTO_FEED_EN (1 << 31) +#endif + +#if ESP32C61 || ESP32C6 || ESP32C5 || ESP32C5BETA3 || ESP32P4 +#define RTC_CNTL_WDTCONFIG0_REG (DR_REG_LP_WDT_BASE + 0x0) // LP_WDT_RWDT_CONFIG0_REG +#define RTC_CNTL_OPTION1_REG (DR_REG_LP_SYS_BASE + 0x08) // LP_SYSTEM_REG_SYS_CTRL_REG +#define RTC_CNTL_WDTWPROTECT_REG (DR_REG_LP_WDT_BASE + 0x0018) // LP_WDT_RWDT_WPROTECT_REG +#define RTC_CNTL_SWD_CONF_REG (DR_REG_LP_WDT_BASE + 0x001C) // LP_WDT_SWD_CONFIG_REG +#define RTC_CNTL_SWD_WPROTECT_REG (DR_REG_LP_WDT_BASE + 0x0020) // LP_WDT_SWD_WPROTECT_REG +#define RTC_CNTL_SWD_WKEY 0x50D83AA1 +#define RTC_CNTL_SWD_AUTO_FEED_EN (1 << 18) +#endif + +#ifdef ESP32H2 +#define RTC_CNTL_WDTCONFIG0_REG (DR_REG_LP_WDT_BASE + 0x0) // LP_WDT_RWDT_CONFIG0_REG +#define RTC_CNTL_WDTWPROTECT_REG (DR_REG_LP_WDT_BASE + 0x001C) // LP_WDT_RWDT_WPROTECT_REG +#define RTC_CNTL_SWD_CONF_REG (DR_REG_LP_WDT_BASE + 0x0020) // LP_WDT_SWD_CONFIG_REG +#define RTC_CNTL_SWD_WPROTECT_REG (DR_REG_LP_WDT_BASE + 0x0024) // LP_WDT_SWD_WPROTECT_REG +#define RTC_CNTL_SWD_WKEY 0x50D83AA1 +#define RTC_CNTL_SWD_AUTO_FEED_EN (1 << 18) +#endif + +#define RTC_CNTL_WDT_WKEY 0x50D83AA1 +#ifdef ESP32P4 + #define RTC_CNTL_FORCE_DOWNLOAD_BOOT (1 << 2) +#else + #define RTC_CNTL_FORCE_DOWNLOAD_BOOT (1 << 0) +#endif // ESP32P4 + +/********************************************************** + * SYSTEM registers + */ + +#ifdef ESP32C3 +#define SYSTEM_CPU_PER_CONF_REG (SYSTEM_BASE_REG + 0x008) +#define SYSTEM_CPUPERIOD_SEL_M ((SYSTEM_CPUPERIOD_SEL_V)<<(SYSTEM_CPUPERIOD_SEL_S)) +#define SYSTEM_CPUPERIOD_SEL_V 0x3 +#define SYSTEM_CPUPERIOD_SEL_S 0 +#define SYSTEM_CPUPERIOD_MAX 1 // CPU_CLK frequency is 160 MHz + +#define SYSTEM_SYSCLK_CONF_REG (SYSTEM_BASE_REG + 0x058) +#define SYSTEM_SOC_CLK_SEL_M ((SYSTEM_SOC_CLK_SEL_V)<<(SYSTEM_SOC_CLK_SEL_S)) +#define SYSTEM_SOC_CLK_SEL_V 0x3 +#define SYSTEM_SOC_CLK_SEL_S 10 +#define SYSTEM_SOC_CLK_MAX 1 +#endif // ESP32C3 + +#ifdef ESP32S2 +#define SYSTEM_CPU_PER_CONF_REG (SYSTEM_BASE_REG + 0x018) +#define SYSTEM_CPUPERIOD_SEL_M ((SYSTEM_CPUPERIOD_SEL_V)<<(SYSTEM_CPUPERIOD_SEL_S)) +#define SYSTEM_CPUPERIOD_SEL_V 0x3 +#define SYSTEM_CPUPERIOD_SEL_S 0 +#define SYSTEM_CPUPERIOD_MAX 2 // CPU_CLK frequency is 240 MHz + +#define SYSTEM_SYSCLK_CONF_REG (SYSTEM_BASE_REG + 0x08C) +#define SYSTEM_SOC_CLK_SEL_M ((SYSTEM_SOC_CLK_SEL_V)<<(SYSTEM_SOC_CLK_SEL_S)) +#define SYSTEM_SOC_CLK_SEL_V 0x3 +#define SYSTEM_SOC_CLK_SEL_S 10 +#define SYSTEM_SOC_CLK_MAX 1 +#endif // ESP32S2 + +#ifdef ESP32C5 +#define PCR_SYSCLK_CONF_REG (DR_REG_PCR_BASE + 0x10c) +#define PCR_SOC_CLK_SEL_M ((PCR_SOC_CLK_SEL_V)<<(PCR_SOC_CLK_SEL_S)) +#define PCR_SOC_CLK_SEL_V 0x3 +#define PCR_SOC_CLK_SEL_S 16 +#define PCR_SOC_CLK_MAX 3 // CPU_CLK frequency is 240 MHz (source is PLL_F240_CLK) +#endif // ESP32C5 + +#ifdef ESP32C5BETA3 +#define PCR_SYSCLK_CONF_REG (DR_REG_PCR_BASE + 0x10c) +#define PCR_SOC_CLK_SEL_M ((PCR_SOC_CLK_SEL_V)<<(PCR_SOC_CLK_SEL_S)) +#define PCR_SOC_CLK_SEL_V 0x3 +#define PCR_SOC_CLK_SEL_S 16 +#define PCR_SOC_CLK_MAX 3 // CPU_CLK frequency is 240 MHz (source is PLL_F240_CLK) +#endif // ESP32C5BETA3 + +#ifdef ESP32C6 +#define PCR_SYSCLK_CONF_REG (DR_REG_PCR_BASE + 0x110) +#define PCR_SOC_CLK_SEL_M ((PCR_SOC_CLK_SEL_V)<<(PCR_SOC_CLK_SEL_S)) +#define PCR_SOC_CLK_SEL_V 0x3 +#define PCR_SOC_CLK_SEL_S 16 +#define PCR_SOC_CLK_MAX 1 // CPU_CLK frequency is 160 MHz (source is PLL_CLK) +#endif // ESP32C6 + +#ifdef ESP32C61 +#define PCR_SYSCLK_CONF_REG (DR_REG_PCR_BASE + 0xe8) +#define PCR_SOC_CLK_SEL_M ((PCR_SOC_CLK_SEL_V)<<(PCR_SOC_CLK_SEL_S)) +#define PCR_SOC_CLK_SEL_V 0x3 +#define PCR_SOC_CLK_SEL_S 16 +#define PCR_SOC_CLK_MAX 1 // CPU_CLK frequency is 160 MHz (source is PLL_CLK) +#endif // ESP32C61 + +#ifdef ESP32H2 +#define PCR_SYSCLK_CONF_REG (DR_REG_PCR_BASE + 0x10c) +#define PCR_SOC_CLK_SEL_M ((PCR_SOC_CLK_SEL_V)<<(PCR_SOC_CLK_SEL_S)) +#define PCR_SOC_CLK_SEL_V 0x3 +#define PCR_SOC_CLK_SEL_S 16 +#define PCR_SOC_CLK_MAX 1 // CPU_CLK frequency is 160 MHz (source is PLL_CLK) +#endif // ESP32H2 + +/********************************************************** + * Per-SOC security info buffer size + */ + +#ifdef ESP32S2 +#define SECURITY_INFO_BYTES 12 /* doesn't include chip_id and api_version */ +#endif // ESP32S2 + +#if ESP32S3_OR_LATER +#define SECURITY_INFO_BYTES 20 +#endif // ESP32S3_OR_LATER + +/********************************************************** + * Per-SOC address of the rom_spiflash_legacy_funcs symbol in ROM + * Can be retrieved with gdb: "info address rom_spiflash_legacy_funcs" + */ + +#if ESP32 || ESP32S2 || ESP32S3 || ESP32S3BETA2 +#define ROM_SPIFLASH_LEGACY 0x3ffae270 +#endif // ESP32 || ESP32S2 || ESP32S3 || ESP32S3BETA2 + +#if ESP32C3 || ESP32C6BETA || ESP32C2 || ESP32C6 || ESP32C61 || ESP32C5BETA3 +#define ROM_SPIFLASH_LEGACY 0x3fcdfff4 +#endif // ESP32C3 || ESP32C6BETA || ESP32C2 || ESP32C6 || ESP32C61 || ESP32C5BETA3 + +#if ESP32H2BETA1 || ESP32H2BETA2 +#define ROM_SPIFLASH_LEGACY 0x3fcdfff0 +#endif // ESP32H2BETA1 || ESP32H2BETA2 + +#if ESP32H2 +#define ROM_SPIFLASH_LEGACY 0x4084fff0 +#endif // ESP32H2 + +#if ESP32C5 +#define ROM_SPIFLASH_LEGACY 0x4085fff0 +#endif // ESP32C5 + +#if ESP32P4 +#define ROM_SPIFLASH_LEGACY 0x4ff3ffec +#endif // ESP32P4 + +/********************************************************** + * IO-MUX peripheral + */ + +#define MCU_SEL 0x7 +#define MCU_SEL_S 12 + +#define PIN_FUNC_SELECT(PIN_NAME, FUNC) REG_SET_FIELD(PIN_NAME, MCU_SEL, FUNC) + +#if ESP32 +// PERIPHS_IO_MUX_SD_... +#define PERIPHS_IO_MUX_SPICLK_U (DR_REG_IO_MUX_BASE + 0x60) +#define PERIPHS_IO_MUX_SPID_U (DR_REG_IO_MUX_BASE + 0x68) +#define PERIPHS_IO_MUX_SPIQ_U (DR_REG_IO_MUX_BASE + 0x64) +#define PERIPHS_IO_MUX_SPICS0_U (DR_REG_IO_MUX_BASE + 0x5c) +#define FUNC_GPIO 2 +#endif // ESP32 + +#if ESP32S2 +#define PERIPHS_IO_MUX_SPICLK_U (DR_REG_IO_MUX_BASE + 0x7c) +#define PERIPHS_IO_MUX_SPIQ_U (DR_REG_IO_MUX_BASE + 0x80) +#define PERIPHS_IO_MUX_SPID_U (DR_REG_IO_MUX_BASE + 0x84) +#define PERIPHS_IO_MUX_SPICS0_U (DR_REG_IO_MUX_BASE + 0x78) +#define FUNC_GPIO 1 +#endif // ESP32S2 + +#if ESP32C3 +#define PERIPHS_IO_MUX_SPICLK_U (DR_REG_IO_MUX_BASE + 0x40) +#define PERIPHS_IO_MUX_SPIQ_U (DR_REG_IO_MUX_BASE + 0x48) +#define PERIPHS_IO_MUX_SPID_U (DR_REG_IO_MUX_BASE + 0x44) +#define PERIPHS_IO_MUX_SPICS0_U (DR_REG_IO_MUX_BASE + 0x3c) +#define FUNC_GPIO 1 +#endif // ESP32C3 + +#if ESP32S3 || ESP32S3BETA2 +#define PERIPHS_IO_MUX_SPICLK_U (DR_REG_IO_MUX_BASE + 0x7c) +#define PERIPHS_IO_MUX_SPIQ_U (DR_REG_IO_MUX_BASE + 0x80) +#define PERIPHS_IO_MUX_SPID_U (DR_REG_IO_MUX_BASE + 0x84) +#define PERIPHS_IO_MUX_SPICS0_U (DR_REG_IO_MUX_BASE + 0x78) +#define FUNC_GPIO 1 +#endif // ESP32S3 || ESP32S3BETA2 + +#if ESP32C2 +#define PERIPHS_IO_MUX_SPICLK_U (DR_REG_IO_MUX_BASE + 0x40) +#define PERIPHS_IO_MUX_SPIQ_U (DR_REG_IO_MUX_BASE + 0x48) +#define PERIPHS_IO_MUX_SPID_U (DR_REG_IO_MUX_BASE + 0x44) +#define PERIPHS_IO_MUX_SPICS0_U (DR_REG_IO_MUX_BASE + 0x3c) +#define FUNC_GPIO 1 +#endif // ESP32C2 + +#if ESP32C61 || ESP32C6 || ESP32C6BETA || ESP32C5 || ESP32C5BETA3 +#define PERIPHS_IO_MUX_SPICLK_U (DR_REG_IO_MUX_BASE + 0x78) +#define PERIPHS_IO_MUX_SPIQ_U (DR_REG_IO_MUX_BASE + 0x68) +#define PERIPHS_IO_MUX_SPID_U (DR_REG_IO_MUX_BASE + 0x7c) +#define PERIPHS_IO_MUX_SPICS0_U (DR_REG_IO_MUX_BASE + 0x64) +#define FUNC_GPIO 1 +#endif // ESP32C61 || ESP32C6 || ESP32C6BETA || ESP32C5 || ESP32C5BETA3 + +#if ESP32H2 || ESP32H2BETA1 || ESP32H2BETA2 +#define PERIPHS_IO_MUX_SPICLK_U (DR_REG_IO_MUX_BASE + 0x50) +#define PERIPHS_IO_MUX_SPIQ_U (DR_REG_IO_MUX_BASE + 0x44) +#define PERIPHS_IO_MUX_SPID_U (DR_REG_IO_MUX_BASE + 0x54) +#define PERIPHS_IO_MUX_SPICS0_U (DR_REG_IO_MUX_BASE + 0x40) +#define FUNC_GPIO 1 +#endif // ESP32H2 || ESP32H2BETA1 || ESP32H2BETA2 + +#if ESP32P4 +#define PERIPHS_IO_MUX_SPICLK_U (DR_REG_IO_MUX_BASE + 0x7c) +#define PERIPHS_IO_MUX_SPIQ_U (DR_REG_IO_MUX_BASE + 0x80) +#define PERIPHS_IO_MUX_SPID_U (DR_REG_IO_MUX_BASE + 0x84) +#define PERIPHS_IO_MUX_SPICS0_U (DR_REG_IO_MUX_BASE + 0x78) +#define FUNC_GPIO 1 +#endif // ESP32P4 + +/********************************************************** + * AES-XTS peripheral + */ + +#define MAX_ENCRYPT_BLOCK 64 + +#if ESP32S3 +#define AES_XTS_PLAIN_BASE (DR_REG_AES_XTS_BASE + 0x00) +#define AES_XTS_SIZE_REG (DR_REG_AES_XTS_BASE + 0x40) +#define AES_XTS_DESTINATION_REG (DR_REG_AES_XTS_BASE + 0x44) +#define AES_XTS_PHYSICAL_ADDR_REG (DR_REG_AES_XTS_BASE + 0x48) +#define AES_XTS_TRIGGER_REG (DR_REG_AES_XTS_BASE + 0x4C) +#define AES_XTS_RELEASE_REG (DR_REG_AES_XTS_BASE + 0x50) +#define AES_XTS_DESTROY_REG (DR_REG_AES_XTS_BASE + 0x54) +#define AES_XTS_STATE_REG (DR_REG_AES_XTS_BASE + 0x58) +#endif // ESP32S3 + +#if ESP32P4 +#define AES_XTS_PLAIN_BASE (SPI0_BASE_REG + 0x300) +#define AES_XTS_SIZE_REG (SPI0_BASE_REG + 0x340) +#define AES_XTS_DESTINATION_REG (SPI0_BASE_REG + 0x344) +#define AES_XTS_PHYSICAL_ADDR_REG (SPI0_BASE_REG + 0x348) +#define AES_XTS_TRIGGER_REG (SPI0_BASE_REG + 0x34C) +#define AES_XTS_RELEASE_REG (SPI0_BASE_REG + 0x350) +#define AES_XTS_DESTROY_REG (SPI0_BASE_REG + 0x354) +#define AES_XTS_STATE_REG (SPI0_BASE_REG + 0x358) +#endif // ESP32P4 diff --git a/tools/flasher_stub/include/stub_commands.h b/tools/flasher_stub/include/stub_commands.h new file mode 100644 index 0000000000..af943ecd72 --- /dev/null +++ b/tools/flasher_stub/include/stub_commands.h @@ -0,0 +1,46 @@ +/* + * SPDX-FileCopyrightText: 2016-2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +/* Flasher command handlers, called from stub_flasher.c + + Commands related to writing flash are in stub_write_flash_xxx. +*/ +#pragma once +#include "stub_flasher.h" +#include "rom_functions.h" +#include + +int handle_flash_erase(uint32_t addr, uint32_t len); + +void handle_flash_read(uint32_t addr, uint32_t len, uint32_t block_size, uint32_t max_in_flight); + +int handle_flash_get_md5sum(uint32_t addr, uint32_t len); + +int handle_flash_read_chip_id(); + +esp_command_error handle_spi_set_params(uint32_t *args, int *status); + +esp_command_error handle_spi_attach(uint32_t hspi_config_arg); + +esp_command_error handle_mem_begin(uint32_t size, uint32_t offset); + +esp_command_error handle_mem_data(void *data, uint32_t length); + +esp_command_error handle_mem_finish(void); + +typedef struct { + uint32_t addr; + uint32_t value; + uint32_t mask; + uint32_t delay_us; +} write_reg_args_t; + +esp_command_error handle_write_reg(const write_reg_args_t *cmd_buf, uint32_t num_commands); + +/* Get security info command only on ESP32S2 and later */ +#if ESP32S2_OR_LATER +esp_command_error handle_get_security_info(void); +#endif // ESP32S2_OR_LATER diff --git a/tools/flasher_stub/include/stub_flasher.h b/tools/flasher_stub/include/stub_flasher.h new file mode 100644 index 0000000000..5f880192eb --- /dev/null +++ b/tools/flasher_stub/include/stub_flasher.h @@ -0,0 +1,110 @@ +/* + * SPDX-FileCopyrightText: 2016 Cesanta Software Limited + * + * SPDX-License-Identifier: GPL-2.0-or-later + * + * SPDX-FileContributor: 2016-2022 Espressif Systems (Shanghai) CO LTD + */ + +#pragma once +#include +#include + +/* Maximum write block size, used for various buffers. */ +#define MAX_WRITE_BLOCK 0x4000 + +/* Flash geometry constants */ +#define FLASH_SECTOR_SIZE 4096 +#define FLASH_BLOCK_SIZE 65536 +#define FLASH_PAGE_SIZE 256 +#define FLASH_STATUS_MASK 0xFFFF +#define SECTORS_PER_BLOCK (FLASH_BLOCK_SIZE / FLASH_SECTOR_SIZE) + +/* 32-bit addressing is supported only by ESP32S3 and ESP32P4 */ +#if (ESP32S3 && !ESP32S3BETA2) || ESP32P4 +#define FLASH_MAX_SIZE 64*1024*1024 +extern bool large_flash_mode; +#else +#define FLASH_MAX_SIZE 16*1024*1024 +#endif + +/* Full set of protocol commands */ +typedef enum { + /* Commands supported by the ESP8266 & ESP32 bootloaders */ + ESP_FLASH_BEGIN = 0x02, + ESP_FLASH_DATA = 0x03, + ESP_FLASH_END = 0x04, + ESP_MEM_BEGIN = 0x05, + ESP_MEM_END = 0x06, + ESP_MEM_DATA = 0x07, + ESP_SYNC = 0x08, + ESP_WRITE_REG = 0x09, + ESP_READ_REG = 0x0a, + + /* Commands supported by the ESP32 bootloader */ + ESP_SPI_SET_PARAMS = 0x0b, + ESP_PIN_READ = 0x0c, /* ??? */ + ESP_SPI_ATTACH = 0x0d, + ESP_SPI_READ = 0x0e, + ESP_SET_BAUD = 0x0f, + ESP_FLASH_DEFLATED_BEGIN = 0x10, + ESP_FLASH_DEFLATED_DATA = 0x11, + ESP_FLASH_DEFLATED_END = 0x12, + ESP_FLASH_VERIFY_MD5 = 0x13, + + /* Commands supported by the ESP32S2 and later bootloaders */ + ESP_GET_SECURITY_INFO = 0x14, + + /* Stub-only commands */ + ESP_ERASE_FLASH = 0xD0, + ESP_ERASE_REGION = 0xD1, + ESP_READ_FLASH = 0xD2, + ESP_RUN_USER_CODE = 0xD3, + + /* Flash encryption debug mode supported command */ + ESP_FLASH_ENCRYPT_DATA = 0xD4, +} esp_command; + +/* Command request header */ +typedef struct __attribute__((packed)) { + uint8_t zero; + uint8_t op; /* maps to esp_command enum */ + uint16_t data_len; + int32_t checksum; + uint8_t data_buf[32]; /* actually variable length, determined by data_len */ +} esp_command_req_t; + +/* Command response header */ +typedef struct __attribute__((packed)) { + uint8_t resp; /* should be '1' */ + uint8_t op_ret; /* Should match 'op' */ + uint16_t len_ret; /* Length of result data (can be ignored as SLIP framing helps) */ + int32_t value; /* 32-bit response used by some commands */ +} esp_command_response_t; + + +/* command response has some (optional) data after it, then 2 (or 4 on ESP32 ROM) + bytes of status. + */ +typedef struct __attribute__((packed)) { + uint8_t error; /* non-zero = failed */ + uint8_t status; /* status of a failure */ +} esp_command_data_status_t; + +/* Error codes */ +typedef enum { + ESP_OK = 0, + + ESP_BAD_DATA_LEN = 0xC0, + ESP_BAD_DATA_CHECKSUM = 0xC1, + ESP_BAD_BLOCKSIZE = 0xC2, + ESP_INVALID_COMMAND = 0xC3, + ESP_FAILED_SPI_OP = 0xC4, + ESP_FAILED_SPI_UNLOCK = 0xC5, + ESP_NOT_IN_FLASH_MODE = 0xC6, + ESP_INFLATE_ERROR = 0xC7, + ESP_NOT_ENOUGH_DATA = 0xC8, + ESP_TOO_MUCH_DATA = 0xC9, + + ESP_CMD_NOT_IMPLEMENTED = 0xFF, +} esp_command_error; diff --git a/tools/flasher_stub/include/stub_io.h b/tools/flasher_stub/include/stub_io.h new file mode 100644 index 0000000000..7c441c31f7 --- /dev/null +++ b/tools/flasher_stub/include/stub_io.h @@ -0,0 +1,62 @@ +/* + * SPDX-FileCopyrightText: 2016 Cesanta Software Limited + * + * SPDX-License-Identifier: GPL-2.0-or-later + * + * SPDX-FileContributor: 2016-2022 Espressif Systems (Shanghai) CO LTD + */ + +#pragma once + +#include +#include + +/* Call to initialize the I/O (either UART or USB CDC at this point). + * The argument is a callback function which will handle received characters, + * when asynchronous (interrupt-driven) RX is used. + * It will be called in an interrupt context. + */ +void stub_io_init(void(*rx_cb_func)(char)); + +/* Enable or disable asynchronous (interrupt-driven) RX, for UART or USB. + * Currently needed only for the read_flash command. + */ +void stub_rx_async_enable(bool enable); + +/* Wrapper for either uart_tx_one_char or the USB CDC output function. + * (uart_tx_one_char in ROM can also handle USB CDC, but it is really + * slow because it flushes the FIFO after every byte). + */ +void stub_tx_one_char(char c); + +/* A blocking (polling) function to receive one character. + * Should only be used when async (interrupt-driven) RX is disabled. + * Currently only needed for the read_flash command. + */ +char stub_rx_one_char(void); + +/* Returns after making sure that all output has been sent to the host */ +void stub_tx_flush(void); + +/* Updates the baud rate divider based on the current baud rate (from host perspective) + * and the requested baud rate. + * No-op for USB CDC. + */ +void stub_io_set_baudrate(uint32_t current_baud, uint32_t new_baud); + +/* To be called periodically while waiting for a command. + * No-op for UART, handles DTR/RTS reset for USB CDC. + */ +void stub_io_idle_hook(void); + +/* Checks if USB-Serial/JTAG is being currently used. + */ +#if WITH_USB_JTAG_SERIAL +bool stub_uses_usb_jtag_serial(void); +#endif + +/* Checks if USB-OTG is being currently used. + */ +#if WITH_USB_OTG +bool stub_uses_usb_otg(void); +#endif diff --git a/tools/flasher_stub/include/stub_write_flash.h b/tools/flasher_stub/include/stub_write_flash.h new file mode 100644 index 0000000000..5ed98e8a04 --- /dev/null +++ b/tools/flasher_stub/include/stub_write_flash.h @@ -0,0 +1,34 @@ +/* + * SPDX-FileCopyrightText: 2016-2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +/* Flasher commands related to writing flash */ +#pragma once +#include "stub_flasher.h" +#include +#include "rom_functions.h" + +bool is_in_flash_mode(void); + +esp_command_error get_flash_error(void); + +esp_command_error handle_flash_begin(uint32_t total_size, uint32_t offset); + +esp_command_error handle_flash_deflated_begin(uint32_t uncompressed_size, uint32_t compressed_size, uint32_t offset); + +void handle_flash_data(void *data_buf, uint32_t length); + +#if !ESP8266 +void handle_flash_encrypt_data(void *data_buf, uint32_t length); +#endif + +void handle_flash_deflated_data(void *data_buf, uint32_t length); + +#if ESP32P4 +void spi_write_enable(void); +#endif + +/* same command used for deflated or non-deflated mode */ +esp_command_error handle_flash_end(void); diff --git a/tools/flasher_stub/ld/rom_32.ld b/tools/flasher_stub/ld/rom_32.ld new file mode 100644 index 0000000000..073eacfb13 --- /dev/null +++ b/tools/flasher_stub/ld/rom_32.ld @@ -0,0 +1,1782 @@ +/* Taken from esp-idf */ +/* +ESP32 ROM address table +Generated for ROM with MD5sum: +ab8282ae908fe9e7a63fb2a4ac2df013 ../../rom_image/prorom.elf +*/ +PROVIDE ( abort = 0x4000bba4 ); +PROVIDE ( abs = 0x40056340 ); +PROVIDE ( __absvdi2 = 0x4006387c ); +PROVIDE ( __absvsi2 = 0x40063868 ); +PROVIDE ( Add2SelfBigHex256 = 0x40015b7c ); +PROVIDE ( AddBigHex256 = 0x40015b28 ); +PROVIDE ( AddBigHexModP256 = 0x40015c98 ); +PROVIDE ( __adddf3 = 0x40002590 ); +PROVIDE ( AddP256 = 0x40015c74 ); +PROVIDE ( AddPdiv2_256 = 0x40015ce0 ); +PROVIDE ( __addsf3 = 0x400020e8 ); +PROVIDE ( __addvdi3 = 0x40002cbc ); +PROVIDE ( __addvsi3 = 0x40002c98 ); +PROVIDE ( aes_128_cbc_decrypt = 0x4005cc7c ); +PROVIDE ( aes_128_cbc_encrypt = 0x4005cc18 ); +PROVIDE ( aes_unwrap = 0x4005ccf0 ); +PROVIDE ( app_gpio_arg = 0x3ffe003c ); +PROVIDE ( app_gpio_handler = 0x3ffe0040 ); +PROVIDE ( __ascii_wctomb = 0x40058ef0 ); +PROVIDE ( asctime = 0x40059588 ); +PROVIDE ( asctime_r = 0x40000ec8 ); +PROVIDE ( __ashldi3 = 0x4000c818 ); +PROVIDE ( __ashrdi3 = 0x4000c830 ); +PROVIDE ( atoi = 0x400566c4 ); +PROVIDE ( _atoi_r = 0x400566d4 ); +PROVIDE ( atol = 0x400566ec ); +PROVIDE ( _atol_r = 0x400566fc ); +PROVIDE ( base64_decode = 0x4005ced8 ); +PROVIDE ( base64_encode = 0x4005cdbc ); +PROVIDE ( BasePoint_x_256 = 0x3ff97488 ); +PROVIDE ( BasePoint_y_256 = 0x3ff97468 ); +PROVIDE ( bigHexInversion256 = 0x400168f0 ); +PROVIDE ( bigHexP256 = 0x3ff973bc ); +PROVIDE ( __bswapdi2 = 0x400649c4 ); +PROVIDE ( __bswapsi2 = 0x4006499c ); +PROVIDE ( btdm_r_ble_bt_handler_tab_p_get = 0x40019b0c ); +PROVIDE ( btdm_r_btdm_option_data_p_get = 0x40010004 ); +PROVIDE ( btdm_r_btdm_rom_version_get = 0x40010078 ); +PROVIDE ( btdm_r_data_init = 0x4001002c ); +PROVIDE ( btdm_r_import_rf_phy_func_p_get = 0x40054298 ); +PROVIDE ( btdm_r_ip_func_p_get = 0x40019af0 ); +PROVIDE ( btdm_r_ip_func_p_set = 0x40019afc ); +PROVIDE ( btdm_r_modules_func_p_get = 0x4005427c ); +PROVIDE ( btdm_r_modules_func_p_set = 0x40054270 ); +PROVIDE ( btdm_r_plf_func_p_set = 0x40054288 ); +PROVIDE ( bt_util_buf_env = 0x3ffb8bd4 ); +PROVIDE ( bzero = 0x4000c1f4 ); +PROVIDE ( cache_flash_mmu_set = 0x400095e0 ); +PROVIDE ( Cache_Flush = 0x40009a14 ); +PROVIDE ( Cache_Read_Disable = 0x40009ab8 ); +PROVIDE ( Cache_Read_Enable = 0x40009a84 ); +PROVIDE ( Cache_Read_Init = 0x40009950 ); +PROVIDE ( cache_sram_mmu_set = 0x400097f4 ); +/* This is static function, but can be used, not generated by script*/ +PROVIDE ( calc_rtc_memory_crc = 0x40008170 ); +PROVIDE ( calloc = 0x4000bee4 ); +PROVIDE ( _calloc_r = 0x4000bbf8 ); +PROVIDE ( check_pos = 0x400068b8 ); +PROVIDE ( _cleanup = 0x40001df8 ); +PROVIDE ( _cleanup_r = 0x40001d48 ); +PROVIDE ( __clear_cache = 0x40063860 ); +PROVIDE ( close = 0x40001778 ); +PROVIDE ( _close_r = 0x4000bd3c ); +PROVIDE ( __clrsbdi2 = 0x40064a38 ); +PROVIDE ( __clrsbsi2 = 0x40064a20 ); +PROVIDE ( __clzdi2 = 0x4000ca50 ); +PROVIDE ( __clzsi2 = 0x4000c7e8 ); +PROVIDE ( __cmpdi2 = 0x40063820 ); +PROVIDE ( co_default_bdaddr = 0x3ffae704 ); +PROVIDE ( co_null_bdaddr = 0x3ffb80e0 ); +PROVIDE ( co_sca2ppm = 0x3ff971e8 ); +PROVIDE ( crc16_be = 0x4005d09c ); +PROVIDE ( crc16_le = 0x4005d05c ); +PROVIDE ( crc32_be = 0x4005d024 ); +PROVIDE ( crc32_le = 0x4005cfec ); +PROVIDE ( crc8_be = 0x4005d114 ); +PROVIDE ( crc8_le = 0x4005d0e0 ); +PROVIDE ( creat = 0x40000e8c ); +PROVIDE ( ctime = 0x400595b0 ); +PROVIDE ( ctime_r = 0x400595c4 ); +PROVIDE ( _ctype_ = 0x3ff96354 ); +PROVIDE ( __ctype_ptr__ = 0x3ff96350 ); +PROVIDE ( __ctzdi2 = 0x4000ca64 ); +PROVIDE ( __ctzsi2 = 0x4000c7f0 ); +PROVIDE ( _data_end = 0x4000d5c8 ); +PROVIDE ( _data_end_btdm_rom = 0x4000d4f8 ); +PROVIDE ( _data_start = 0x4000d4f8 ); +PROVIDE ( _data_start_btdm_rom = 0x4000d4f4 ); +PROVIDE ( _data_start_btdm = 0x3ffae6e0); +PROVIDE ( _data_end_btdm = 0x3ffaff10); +PROVIDE ( _bss_start_btdm = 0x3ffb8000); +PROVIDE ( _bss_end_btdm = 0x3ffbff70); +PROVIDE ( _daylight = 0x3ffae0a4 ); +PROVIDE ( dbg_default_handler = 0x3ff97218 ); +PROVIDE ( dbg_state = 0x3ffb8d5d ); +PROVIDE ( DebugE256PublicKey_x = 0x3ff97428 ); +PROVIDE ( DebugE256PublicKey_y = 0x3ff97408 ); +PROVIDE ( DebugE256SecretKey = 0x3ff973e8 ); +PROVIDE ( _DebugExceptionVector = 0x40000280 ); +PROVIDE ( debug_timer = 0x3ffe042c ); +PROVIDE ( debug_timerfn = 0x3ffe0430 ); +PROVIDE ( dh_group14_generator = 0x3ff9ac60 ); +PROVIDE ( dh_group14_prime = 0x3ff9ab60 ); +PROVIDE ( dh_group15_generator = 0x3ff9ab5f ); +PROVIDE ( dh_group15_prime = 0x3ff9a9df ); +PROVIDE ( dh_group16_generator = 0x3ff9a9de ); +PROVIDE ( dh_group16_prime = 0x3ff9a7de ); +PROVIDE ( dh_group17_generator = 0x3ff9a7dd ); +PROVIDE ( dh_group17_prime = 0x3ff9a4dd ); +PROVIDE ( dh_group18_generator = 0x3ff9a4dc ); +PROVIDE ( dh_group18_prime = 0x3ff9a0dc ); +PROVIDE ( dh_group1_generator = 0x3ff9ae03 ); +PROVIDE ( dh_group1_prime = 0x3ff9ada3 ); +PROVIDE ( dh_group2_generator = 0x3ff9ada2 ); +PROVIDE ( dh_group2_prime = 0x3ff9ad22 ); +PROVIDE ( dh_group5_generator = 0x3ff9ad21 ); +PROVIDE ( dh_group5_prime = 0x3ff9ac61 ); +PROVIDE ( div = 0x40056348 ); +PROVIDE ( __divdc3 = 0x40064460 ); +PROVIDE ( __divdf3 = 0x40002954 ); +PROVIDE ( __divdi3 = 0x4000ca84 ); +PROVIDE ( __divsc3 = 0x40064200 ); +PROVIDE ( __divsf3 = 0x4000234c ); +PROVIDE ( __divsi3 = 0x4000c7b8 ); +PROVIDE ( _DoubleExceptionVector = 0x400003c0 ); +PROVIDE ( dummy_len_plus = 0x3ffae290 ); +PROVIDE ( __dummy_lock = 0x4000c728 ); +PROVIDE ( __dummy_lock_try = 0x4000c730 ); +PROVIDE ( ecc_env = 0x3ffb8d60 ); +PROVIDE ( ecc_Jacobian_InfinityPoint256 = 0x3ff972e8 ); +PROVIDE ( em_buf_env = 0x3ffb8d74 ); +PROVIDE ( environ = 0x3ffae0b4 ); +PROVIDE ( __env_lock = 0x40001fd4 ); +PROVIDE ( __env_unlock = 0x40001fe0 ); +PROVIDE ( __eqdf2 = 0x400636a8 ); +PROVIDE ( __eqsf2 = 0x40063374 ); +PROVIDE ( esp_crc8 = 0x4005d144 ); +PROVIDE ( _etext = 0x4000d66c ); +PROVIDE ( ets_aes_crypt = 0x4005c9b8 ); +PROVIDE ( ets_aes_disable = 0x4005c8f8 ); +PROVIDE ( ets_aes_enable = 0x4005c8cc ); +PROVIDE ( ets_aes_set_endian = 0x4005c928 ); +PROVIDE ( ets_aes_setkey_dec = 0x4005c994 ); +PROVIDE ( ets_aes_setkey_enc = 0x4005c97c ); +PROVIDE ( ets_bigint_disable = 0x4005c4e0 ); +PROVIDE ( ets_bigint_enable = 0x4005c498 ); +PROVIDE ( ets_bigint_mod_mult_getz = 0x4005c818 ); +PROVIDE ( ets_bigint_mod_mult_prepare = 0x4005c7b4 ); +PROVIDE ( ets_bigint_mod_power_getz = 0x4005c614 ); +PROVIDE ( ets_bigint_mod_power_prepare = 0x4005c54c ); +PROVIDE ( ets_bigint_montgomery_mult_getz = 0x4005c7a4 ); +PROVIDE ( ets_bigint_montgomery_mult_prepare = 0x4005c6fc ); +PROVIDE ( ets_bigint_mult_getz = 0x4005c6e8 ); +PROVIDE ( ets_bigint_mult_prepare = 0x4005c630 ); +PROVIDE ( ets_bigint_wait_finish = 0x4005c520 ); +PROVIDE ( ets_delay_us = 0x40008534 ); +PROVIDE ( ets_efuse_get_8M_clock = 0x40008710 ); +PROVIDE ( ets_efuse_get_spiconfig = 0x40008658 ); +PROVIDE ( ets_efuse_program_op = 0x40008628 ); +PROVIDE ( ets_efuse_read_op = 0x40008600 ); +PROVIDE ( ets_get_cpu_frequency = 0x4000855c ); +PROVIDE ( ets_get_detected_xtal_freq = 0x40008588 ); +PROVIDE ( ets_get_xtal_scale = 0x4000856c ); +PROVIDE ( ets_install_putc1 = 0x40007d18 ); +PROVIDE ( ets_install_putc2 = 0x40007d38 ); +PROVIDE ( ets_install_uart_printf = 0x40007d28 ); +PROVIDE ( ets_post = 0x4000673c ); +PROVIDE ( ets_printf = 0x40007d54 ); +PROVIDE ( ets_readySet_ = 0x3ffe01f0 ); +PROVIDE ( ets_run = 0x400066bc ); +PROVIDE ( ets_secure_boot_check = 0x4005cb40 ); +PROVIDE ( ets_secure_boot_check_finish = 0x4005cc04 ); +PROVIDE ( ets_secure_boot_check_start = 0x4005cbcc ); +PROVIDE ( ets_secure_boot_finish = 0x4005ca84 ); +PROVIDE ( ets_secure_boot_hash = 0x4005cad4 ); +PROVIDE ( ets_secure_boot_obtain = 0x4005cb14 ); +PROVIDE ( ets_secure_boot_rd_abstract = 0x4005cba8 ); +PROVIDE ( ets_secure_boot_rd_iv = 0x4005cb84 ); +PROVIDE ( ets_secure_boot_start = 0x4005ca34 ); +PROVIDE ( ets_set_appcpu_boot_addr = 0x4000689c ); +PROVIDE ( ets_set_idle_cb = 0x40006674 ); +PROVIDE ( ets_set_startup_callback = 0x4000688c ); +PROVIDE ( ets_set_user_start = 0x4000687c ); +PROVIDE ( ets_sha_disable = 0x4005c0a8 ); +PROVIDE ( ets_sha_enable = 0x4005c07c ); +PROVIDE ( ets_sha_finish = 0x4005c104 ); +PROVIDE ( ets_sha_init = 0x4005c0d4 ); +PROVIDE ( ets_sha_update = 0x4005c2a0 ); +PROVIDE ( ets_startup_callback = 0x3ffe0404 ); +PROVIDE ( ets_task = 0x40006688 ); +PROVIDE ( ets_timer_arm = 0x40008368 ); +PROVIDE ( ets_timer_arm_us = 0x400083ac ); +PROVIDE ( ets_timer_disarm = 0x400083ec ); +PROVIDE ( ets_timer_done = 0x40008428 ); +PROVIDE ( ets_timer_handler_isr = 0x40008454 ); +PROVIDE ( ets_timer_init = 0x400084e8 ); +PROVIDE ( ets_timer_setfn = 0x40008350 ); +PROVIDE ( ets_unpack_flash_code = 0x40007018 ); +PROVIDE ( ets_unpack_flash_code_legacy = 0x4000694c ); +PROVIDE ( ets_update_cpu_frequency = 0x40008550 ); +PROVIDE ( ets_waiti0 = 0x400067d8 ); +PROVIDE ( exc_cause_table = 0x3ff991d0 ); +PROVIDE ( _exit_r = 0x4000bd28 ); +PROVIDE ( __extendsfdf2 = 0x40002c34 ); +PROVIDE ( fclose = 0x400020ac ); +PROVIDE ( _fclose_r = 0x40001fec ); +PROVIDE ( fflush = 0x40059394 ); +PROVIDE ( _fflush_r = 0x40059320 ); +PROVIDE ( __ffsdi2 = 0x4000ca2c ); +PROVIDE ( __ffssi2 = 0x4000c804 ); +PROVIDE ( FilePacketSendDeflatedReqMsgProc = 0x40008b24 ); +PROVIDE ( FilePacketSendReqMsgProc = 0x40008860 ); +PROVIDE ( _findenv_r = 0x40001f44 ); +PROVIDE ( __fixdfdi = 0x40002ac4 ); +PROVIDE ( __fixdfsi = 0x40002a78 ); +PROVIDE ( __fixsfdi = 0x4000244c ); +PROVIDE ( __fixsfsi = 0x4000240c ); +PROVIDE ( __fixunsdfsi = 0x40002b30 ); +PROVIDE ( __fixunssfdi = 0x40002504 ); +PROVIDE ( __fixunssfsi = 0x400024ac ); +PROVIDE ( FlashDwnLdDeflatedStartMsgProc = 0x40008ad8 ); +PROVIDE ( FlashDwnLdParamCfgMsgProc = 0x4000891c ); +PROVIDE ( FlashDwnLdStartMsgProc = 0x40008820 ); +PROVIDE ( FlashDwnLdStopDeflatedReqMsgProc = 0x40008c18 ); +PROVIDE ( FlashDwnLdStopReqMsgProc = 0x400088ec ); +PROVIDE ( __floatdidf = 0x4000c988 ); +PROVIDE ( __floatdisf = 0x4000c8c0 ); +PROVIDE ( __floatsidf = 0x4000c944 ); +PROVIDE ( __floatsisf = 0x4000c870 ); +PROVIDE ( __floatundidf = 0x4000c978 ); +PROVIDE ( __floatundisf = 0x4000c8b0 ); +PROVIDE ( __floatunsidf = 0x4000c938 ); +PROVIDE ( __floatunsisf = 0x4000c864 ); +PROVIDE ( __fp_lock_all = 0x40001f1c ); +PROVIDE ( __fp_unlock_all = 0x40001f30 ); +PROVIDE ( fputwc = 0x40058ea8 ); +PROVIDE ( __fputwc = 0x40058da0 ); +PROVIDE ( _fputwc_r = 0x40058e4c ); +PROVIDE ( free = 0x4000beb8 ); +PROVIDE ( _free_r = 0x4000bbcc ); +PROVIDE ( _fstat_r = 0x4000bccc ); +PROVIDE ( _fwalk = 0x4000c738 ); +PROVIDE ( _fwalk_reent = 0x4000c770 ); +PROVIDE ( __gcc_bcmp = 0x40064a70 ); +PROVIDE ( __gedf2 = 0x40063768 ); +PROVIDE ( _GeneralException = 0x40000e14 ); +PROVIDE ( __gesf2 = 0x4006340c ); +PROVIDE ( __get_current_time_locale = 0x40001834 ); +PROVIDE ( _getenv_r = 0x40001fbc ); +PROVIDE ( _getpid_r = 0x4000bcfc ); +PROVIDE ( __getreent = 0x4000be8c ); +PROVIDE ( _gettimeofday_r = 0x4000bc58 ); +PROVIDE ( __gettzinfo = 0x40001fcc ); +PROVIDE ( GetUartDevice = 0x40009598 ); +PROVIDE ( GF_Jacobian_Point_Addition256 = 0x400163a4 ); +PROVIDE ( GF_Jacobian_Point_Double256 = 0x40016260 ); +PROVIDE ( GF_Point_Jacobian_To_Affine256 = 0x40016b0c ); +PROVIDE ( _global_impure_ptr = 0x3ffae0b0 ); +PROVIDE ( gmtime = 0x40059848 ); +PROVIDE ( gmtime_r = 0x40059868 ); +PROVIDE ( g_phyFuns_instance = 0x3ffae0c4 ); +PROVIDE ( g_rom_flashchip = 0x3ffae270 ); +PROVIDE ( gpio_init = 0x40009c20 ); +PROVIDE ( gpio_input_get = 0x40009b88 ); +PROVIDE ( gpio_input_get_high = 0x40009b9c ); +PROVIDE ( gpio_intr_ack = 0x40009dd4 ); +PROVIDE ( gpio_intr_ack_high = 0x40009e1c ); +PROVIDE ( gpio_intr_handler_register = 0x40009e6c ); +PROVIDE ( gpio_intr_pending = 0x40009cec ); +PROVIDE ( gpio_intr_pending_high = 0x40009cf8 ); +PROVIDE ( gpio_matrix_in = 0x40009edc ); +PROVIDE ( gpio_matrix_out = 0x40009f0c ); +PROVIDE ( gpio_output_set = 0x40009b24 ); +PROVIDE ( gpio_output_set_high = 0x40009b5c ); +PROVIDE ( gpio_pad_hold = 0x4000a734 ); +PROVIDE ( gpio_pad_pulldown = 0x4000a348 ); +PROVIDE ( gpio_pad_pullup = 0x4000a22c ); +PROVIDE ( gpio_pad_select_gpio = 0x40009fdc ); +PROVIDE ( gpio_pad_set_drv = 0x4000a11c ); +PROVIDE ( gpio_pad_unhold = 0x4000a484 ); +PROVIDE ( gpio_pending_mask = 0x3ffe0038 ); +PROVIDE ( gpio_pending_mask_high = 0x3ffe0044 ); +PROVIDE ( gpio_pin_intr_state_set = 0x40009d04 ); +PROVIDE ( gpio_pin_wakeup_disable = 0x40009eb0 ); +PROVIDE ( gpio_pin_wakeup_enable = 0x40009e7c ); +PROVIDE ( gpio_register_get = 0x40009cbc ); +PROVIDE ( gpio_register_set = 0x40009bbc ); +PROVIDE ( __gtdf2 = 0x400636dc ); +PROVIDE ( __gtsf2 = 0x400633a0 ); +PROVIDE ( gTxMsg = 0x3ffe0050 ); +PROVIDE ( hci_cmd_desc_root_tab = 0x3ff976d4 ); +PROVIDE ( hci_cmd_desc_tab_ctrl_bb = 0x3ff97b70 ); +PROVIDE ( hci_cmd_desc_tab_info_par = 0x3ff97b1c ); +PROVIDE ( hci_cmd_desc_tab_le = 0x3ff97870 ); +PROVIDE ( hci_cmd_desc_tab_lk_ctrl = 0x3ff97fc0 ); +PROVIDE ( hci_cmd_desc_tab_lk_pol = 0x3ff97f3c ); +PROVIDE ( hci_cmd_desc_tab_stat_par = 0x3ff97ac8 ); +PROVIDE ( hci_cmd_desc_tab_testing = 0x3ff97a98 ); +PROVIDE ( hci_cmd_desc_tab_vs = 0x3ff97714 ); +PROVIDE ( hci_command_handler = 0x4004c928 ); +PROVIDE ( hci_env = 0x3ffb9350 ); +PROVIDE ( hci_evt_dbg_desc_tab = 0x3ff9750c ); +PROVIDE ( hci_evt_desc_tab = 0x3ff9751c ); +PROVIDE ( hci_evt_le_desc_tab = 0x3ff974b4 ); +PROVIDE ( hci_fc_env = 0x3ffb9340 ); +PROVIDE ( hmac_md5 = 0x4005d264 ); +PROVIDE ( hmac_md5_vector = 0x4005d17c ); +PROVIDE ( hmac_sha1 = 0x40060acc ); +PROVIDE ( hmac_sha1_vector = 0x400609e4 ); +PROVIDE ( hmac_sha256 = 0x40060d58 ); +PROVIDE ( hmac_sha256_vector = 0x40060c84 ); +PROVIDE ( intr_matrix_set = 0x4000681c ); +PROVIDE ( isalnum = 0x40000f04 ); +PROVIDE ( isalpha = 0x40000f18 ); +PROVIDE ( isascii = 0x4000c20c ); +PROVIDE ( _isatty_r = 0x40000ea0 ); +PROVIDE ( isblank = 0x40000f2c ); +PROVIDE ( iscntrl = 0x40000f50 ); +PROVIDE ( isdigit = 0x40000f64 ); +PROVIDE ( isgraph = 0x40000f94 ); +PROVIDE ( islower = 0x40000f78 ); +PROVIDE ( isprint = 0x40000fa8 ); +PROVIDE ( ispunct = 0x40000fc0 ); +PROVIDE ( isspace = 0x40000fd4 ); +PROVIDE ( isupper = 0x40000fe8 ); +PROVIDE ( itoa = 0x400566b4 ); +PROVIDE ( __itoa = 0x40056678 ); +PROVIDE ( jd_decomp = 0x400613e8 ); +PROVIDE ( jd_prepare = 0x40060fa8 ); +PROVIDE ( ke_env = 0x3ffb93cc ); +PROVIDE ( _KernelExceptionVector = 0x40000300 ); +PROVIDE ( _kill_r = 0x4000bd10 ); +PROVIDE ( labs = 0x40056370 ); +PROVIDE ( lb_default_handler = 0x3ff982b8 ); +PROVIDE ( lb_default_state_tab_p_get = 0x4001c198 ); +PROVIDE ( lb_env = 0x3ffb9424 ); +PROVIDE ( lb_hci_cmd_handler_tab_p_get = 0x4001c18c ); +PROVIDE ( lb_state = 0x3ffb94e8 ); +PROVIDE ( lc_default_handler = 0x3ff98648 ); +PROVIDE ( lc_default_state_tab_p_get = 0x4002f494 ); +PROVIDE ( lc_env = 0x3ffb94ec ); +PROVIDE ( lc_hci_cmd_handler_tab_p_get = 0x4002f488 ); +PROVIDE ( lc_state = 0x3ffb9508 ); +PROVIDE ( ld_acl_br_sizes = 0x3ff98a2a ); +PROVIDE ( ld_acl_br_types = 0x3ff98a36 ); +PROVIDE ( ld_acl_edr_sizes = 0x3ff98a14 ); +PROVIDE ( ld_acl_edr_types = 0x3ff98a22 ); +PROVIDE ( ld_env = 0x3ffb9510 ); +PROVIDE ( ldiv = 0x40056378 ); +PROVIDE ( ld_pcm_settings_dft = 0x3ff98a0c ); +PROVIDE ( ld_sched_params = 0x3ffb96c0 ); +PROVIDE ( ld_sync_train_channels = 0x3ff98a3c ); +PROVIDE ( __ledf2 = 0x40063704 ); +PROVIDE ( __lesf2 = 0x400633c0 ); +PROVIDE ( _Level2FromVector = 0x40000954 ); +PROVIDE ( _Level2Vector = 0x40000180 ); +PROVIDE ( _Level3FromVector = 0x40000a28 ); +PROVIDE ( _Level3Vector = 0x400001c0 ); +PROVIDE ( _Level4FromVector = 0x40000af8 ); +PROVIDE ( _Level4Vector = 0x40000200 ); +PROVIDE ( _Level5FromVector = 0x40000c68 ); +PROVIDE ( _Level5Vector = 0x40000240 ); +PROVIDE ( _LevelOneInterrupt = 0x40000835 ); +PROVIDE ( _link_r = 0x4000bc9c ); +PROVIDE ( llc_default_handler = 0x3ff98b3c ); +PROVIDE ( llc_default_state_tab_p_get = 0x40046058 ); +PROVIDE ( llc_env = 0x3ffb96d0 ); +PROVIDE ( llc_hci_acl_data_tx_handler = 0x40042398 ); +PROVIDE ( llc_hci_cmd_handler_tab_p_get = 0x40042358 ); +PROVIDE ( llc_hci_command_handler = 0x40042360 ); +PROVIDE ( llcp_pdu_handler_tab_p_get = 0x40043f64 ); +PROVIDE ( llc_state = 0x3ffb96f8 ); +PROVIDE ( lldesc_build_chain = 0x4000a850 ); +PROVIDE ( lldesc_num2link = 0x4000a948 ); +PROVIDE ( lldesc_set_owner = 0x4000a974 ); +PROVIDE ( lld_evt_env = 0x3ffb9704 ); +PROVIDE ( lld_pdu_adv_pk_desc_tab = 0x3ff98c70 ); +PROVIDE ( lld_pdu_llcp_pk_desc_tab = 0x3ff98b68 ); +PROVIDE ( LLM_AA_CT1 = 0x3ff98d8a ); +PROVIDE ( LLM_AA_CT2 = 0x3ff98d88 ); +PROVIDE ( llm_default_handler = 0x3ff98d80 ); +PROVIDE ( llm_default_state_tab_p_get = 0x4004e718 ); +PROVIDE ( llm_hci_cmd_handler_tab_p_get = 0x4004c920 ); +PROVIDE ( llm_le_env = 0x3ffb976c ); +PROVIDE ( llm_local_cmds = 0x3ff98d38 ); +PROVIDE ( llm_local_data_len_values = 0x3ff98d1c ); +PROVIDE ( llm_local_le_feats = 0x3ff98d30 ); +PROVIDE ( llm_local_le_states = 0x3ff98d28 ); +PROVIDE ( llm_state = 0x3ffb985c ); +PROVIDE ( lm_default_handler = 0x3ff990e0 ); +PROVIDE ( lm_default_state_tab_p_get = 0x40054268 ); +PROVIDE ( lm_env = 0x3ffb9860 ); +PROVIDE ( lm_hci_cmd_handler_tab_p_get = 0x4005425c ); +PROVIDE ( lm_local_supp_feats = 0x3ff990ee ); +PROVIDE ( lm_n_page_tab = 0x3ff990e8 ); +PROVIDE ( lmp_desc_tab = 0x3ff96e6c ); +PROVIDE ( lmp_ext_desc_tab = 0x3ff96d9c ); +PROVIDE ( lm_state = 0x3ffb9a1c ); +PROVIDE ( __locale_charset = 0x40059540 ); +PROVIDE ( __locale_cjk_lang = 0x40059558 ); +PROVIDE ( localeconv = 0x4005957c ); +PROVIDE ( _localeconv_r = 0x40059560 ); +PROVIDE ( __locale_mb_cur_max = 0x40059548 ); +PROVIDE ( __locale_msgcharset = 0x40059550 ); +PROVIDE ( localtime = 0x400595dc ); +PROVIDE ( localtime_r = 0x400595fc ); +PROVIDE ( _lock_acquire = 0x4000be14 ); +PROVIDE ( _lock_acquire_recursive = 0x4000be28 ); +PROVIDE ( _lock_close = 0x4000bdec ); +PROVIDE ( _lock_close_recursive = 0x4000be00 ); +PROVIDE ( _lock_init = 0x4000bdc4 ); +PROVIDE ( _lock_init_recursive = 0x4000bdd8 ); +PROVIDE ( _lock_release = 0x4000be64 ); +PROVIDE ( _lock_release_recursive = 0x4000be78 ); +PROVIDE ( _lock_try_acquire = 0x4000be3c ); +PROVIDE ( _lock_try_acquire_recursive = 0x4000be50 ); +PROVIDE ( longjmp = 0x400562cc ); +PROVIDE ( _lseek_r = 0x4000bd8c ); +PROVIDE ( __lshrdi3 = 0x4000c84c ); +PROVIDE ( __ltdf2 = 0x40063790 ); +PROVIDE ( __ltsf2 = 0x4006342c ); +PROVIDE ( malloc = 0x4000bea0 ); +PROVIDE ( _malloc_r = 0x4000bbb4 ); +PROVIDE ( maxSecretKey_256 = 0x3ff97448 ); +PROVIDE ( __mb_cur_max = 0x3ff96530 ); +PROVIDE ( MD5Final = 0x4005db1c ); +PROVIDE ( MD5Init = 0x4005da7c ); +PROVIDE ( MD5Update = 0x4005da9c ); +PROVIDE ( md5_vector = 0x4005db80 ); +PROVIDE ( memccpy = 0x4000c220 ); +PROVIDE ( memchr = 0x4000c244 ); +PROVIDE ( memcmp = 0x4000c260 ); +PROVIDE ( memcpy = 0x4000c2c8 ); +PROVIDE ( MemDwnLdStartMsgProc = 0x40008948 ); +PROVIDE ( MemDwnLdStopReqMsgProc = 0x400089dc ); +PROVIDE ( memmove = 0x4000c3c0 ); +PROVIDE ( MemPacketSendReqMsgProc = 0x40008978 ); +PROVIDE ( memrchr = 0x4000c400 ); +PROVIDE ( memset = 0x4000c44c ); +PROVIDE ( mktime = 0x4005a5e8 ); +PROVIDE ( mmu_init = 0x400095a4 ); +PROVIDE ( __moddi3 = 0x4000cd4c ); +PROVIDE ( __modsi3 = 0x4000c7c0 ); +PROVIDE ( __month_lengths = 0x3ff9609c ); +PROVIDE ( __muldc3 = 0x40063bf4 ); +PROVIDE ( __muldf3 = 0x4006358c ); +PROVIDE ( __muldi3 = 0x4000c9fc ); +PROVIDE ( __mulsc3 = 0x40063934 ); +PROVIDE ( __mulsf3 = 0x400632c8 ); +PROVIDE ( __mulsi3 = 0x4000c7b0 ); +PROVIDE ( MultiplyBigHexByUint32_256 = 0x40016214 ); +PROVIDE ( MultiplyBigHexModP256 = 0x400160b8 ); +PROVIDE ( MultiplyByU32ModP256 = 0x40015fdc ); +PROVIDE ( multofup = 0x4000ab8c ); +PROVIDE ( __mulvdi3 = 0x40002d78 ); +PROVIDE ( __mulvsi3 = 0x40002d60 ); +PROVIDE ( mz_adler32 = 0x4005edbc ); +PROVIDE ( mz_crc32 = 0x4005ee88 ); +PROVIDE ( mz_free = 0x4005eed4 ); +PROVIDE ( __nedf2 = 0x400636a8 ); +PROVIDE ( __negdf2 = 0x400634a0 ); +PROVIDE ( __negdi2 = 0x4000ca14 ); +PROVIDE ( __negsf2 = 0x400020c0 ); +PROVIDE ( __negvdi2 = 0x40002e98 ); +PROVIDE ( __negvsi2 = 0x40002e78 ); +PROVIDE ( __nesf2 = 0x40063374 ); +PROVIDE ( _NMIExceptionVector = 0x400002c0 ); +PROVIDE ( notEqual256 = 0x40015b04 ); +PROVIDE ( __nsau_data = 0x3ff96544 ); +PROVIDE ( one_bits = 0x3ff971f8 ); +PROVIDE ( open = 0x4000178c ); +PROVIDE ( _open_r = 0x4000bd54 ); +PROVIDE ( __paritysi2 = 0x40002f3c ); +PROVIDE ( pbkdf2_sha1 = 0x40060ba4 ); +PROVIDE ( phy_get_romfuncs = 0x40004100 ); +PROVIDE ( __popcountdi2 = 0x40002ef8 ); +PROVIDE ( __popcountsi2 = 0x40002ed0 ); +PROVIDE ( __popcount_tab = 0x3ff96544 ); +PROVIDE ( __powidf2 = 0x400638d4 ); +PROVIDE ( __powisf2 = 0x4006389c ); +PROVIDE ( _Pri_4_HandlerAddress = 0x3ffe0648 ); +PROVIDE ( _Pri_5_HandlerAddress = 0x3ffe064c ); +PROVIDE ( qsort = 0x40056424 ); +PROVIDE ( _raise_r = 0x4000bc70 ); +PROVIDE ( rand = 0x40001058 ); +PROVIDE ( rand_r = 0x400010d4 ); +PROVIDE ( r_btdm_option_data = 0x3ffae6e0 ); +PROVIDE ( r_bt_util_buf_acl_rx_alloc = 0x40010218 ); +PROVIDE ( r_bt_util_buf_acl_rx_free = 0x40010234 ); +PROVIDE ( r_bt_util_buf_acl_tx_alloc = 0x40010268 ); +PROVIDE ( r_bt_util_buf_acl_tx_free = 0x40010280 ); +PROVIDE ( r_bt_util_buf_init = 0x400100e4 ); +PROVIDE ( r_bt_util_buf_lmp_tx_alloc = 0x400101d0 ); +PROVIDE ( r_bt_util_buf_lmp_tx_free = 0x400101ec ); +PROVIDE ( r_bt_util_buf_sync_clear = 0x400103c8 ); +PROVIDE ( r_bt_util_buf_sync_init = 0x400102c4 ); +PROVIDE ( r_bt_util_buf_sync_rx_alloc = 0x40010468 ); +PROVIDE ( r_bt_util_buf_sync_rx_free = 0x4001049c ); +PROVIDE ( r_bt_util_buf_sync_tx_alloc = 0x400103ec ); +PROVIDE ( r_bt_util_buf_sync_tx_free = 0x40010428 ); +PROVIDE ( rc4_skip = 0x40060928 ); +PROVIDE ( r_co_bdaddr_compare = 0x40014324 ); +PROVIDE ( r_co_bytes_to_string = 0x400142e4 ); +PROVIDE ( r_co_list_check_size_available = 0x400142c4 ); +PROVIDE ( r_co_list_extract = 0x4001404c ); +PROVIDE ( r_co_list_extract_after = 0x40014118 ); +PROVIDE ( r_co_list_find = 0x4001419c ); +PROVIDE ( r_co_list_init = 0x40013f14 ); +PROVIDE ( r_co_list_insert_after = 0x40014254 ); +PROVIDE ( r_co_list_insert_before = 0x40014200 ); +PROVIDE ( r_co_list_merge = 0x400141bc ); +PROVIDE ( r_co_list_pool_init = 0x40013f30 ); +PROVIDE ( r_co_list_pop_front = 0x40014028 ); +PROVIDE ( r_co_list_push_back = 0x40013fb8 ); +PROVIDE ( r_co_list_push_front = 0x40013ff4 ); +PROVIDE ( r_co_list_size = 0x400142ac ); +PROVIDE ( r_co_nb_good_channels = 0x40014360 ); +PROVIDE ( r_co_slot_to_duration = 0x40014348 ); +PROVIDE ( RcvMsg = 0x4000954c ); +PROVIDE ( r_dbg_init = 0x40014394 ); +PROVIDE ( r_dbg_platform_reset_complete = 0x400143d0 ); +PROVIDE ( r_dbg_swdiag_init = 0x40014470 ); +PROVIDE ( r_dbg_swdiag_read = 0x400144a4 ); +PROVIDE ( r_dbg_swdiag_write = 0x400144d0 ); +PROVIDE ( r_E1 = 0x400108e8 ); +PROVIDE ( r_E21 = 0x40010968 ); +PROVIDE ( r_E22 = 0x400109b4 ); +PROVIDE ( r_E3 = 0x40010a58 ); +PROVIDE ( r_ea_alarm_clear = 0x40015ab4 ); +PROVIDE ( r_ea_alarm_set = 0x40015a10 ); +PROVIDE ( read = 0x400017dc ); +PROVIDE ( _read_r = 0x4000bda8 ); +PROVIDE ( r_ea_elt_cancel = 0x400150d0 ); +PROVIDE ( r_ea_elt_create = 0x40015264 ); +PROVIDE ( r_ea_elt_insert = 0x400152a8 ); +PROVIDE ( r_ea_elt_remove = 0x400154f0 ); +PROVIDE ( r_ea_finetimer_isr = 0x400155d4 ); +PROVIDE ( r_ea_init = 0x40015228 ); +PROVIDE ( r_ea_interval_create = 0x4001555c ); +PROVIDE ( r_ea_interval_delete = 0x400155a8 ); +PROVIDE ( r_ea_interval_duration_req = 0x4001597c ); +PROVIDE ( r_ea_interval_insert = 0x4001557c ); +PROVIDE ( r_ea_interval_remove = 0x40015590 ); +PROVIDE ( realloc = 0x4000becc ); +PROVIDE ( _realloc_r = 0x4000bbe0 ); +PROVIDE ( r_ea_offset_req = 0x40015748 ); +PROVIDE ( r_ea_sleep_check = 0x40015928 ); +PROVIDE ( r_ea_sw_isr = 0x40015724 ); +PROVIDE ( r_ea_time_get_halfslot_rounded = 0x40015894 ); +PROVIDE ( r_ea_time_get_slot_rounded = 0x400158d4 ); +PROVIDE ( r_ecc_abort_key256_generation = 0x40017070 ); +PROVIDE ( r_ecc_generate_key256 = 0x40016e00 ); +PROVIDE ( r_ecc_gen_new_public_key = 0x400170c0 ); +PROVIDE ( r_ecc_gen_new_secret_key = 0x400170e4 ); +PROVIDE ( r_ecc_get_debug_Keys = 0x40017224 ); +PROVIDE ( r_ecc_init = 0x40016dbc ); +PROVIDE ( RecvBuff = 0x3ffe009c ); +PROVIDE ( recv_packet = 0x40009424 ); +PROVIDE ( r_em_buf_init = 0x4001729c ); +PROVIDE ( r_em_buf_rx_buff_addr_get = 0x400173e8 ); +PROVIDE ( r_em_buf_rx_free = 0x400173c4 ); +PROVIDE ( r_em_buf_tx_buff_addr_get = 0x40017404 ); +PROVIDE ( r_em_buf_tx_free = 0x4001741c ); +PROVIDE ( _rename_r = 0x4000bc28 ); +PROVIDE ( _ResetHandler = 0x40000450 ); +PROVIDE ( _ResetVector = 0x40000400 ); +PROVIDE ( r_F1_256 = 0x400133e4 ); +PROVIDE ( r_F2_256 = 0x40013568 ); +PROVIDE ( r_F3_256 = 0x40013664 ); +PROVIDE ( RFPLL_ICP_TABLE = 0x3ffb8b7c ); +PROVIDE ( r_G_256 = 0x40013470 ); +PROVIDE ( r_H3 = 0x40013760 ); +PROVIDE ( r_H4 = 0x40013830 ); +PROVIDE ( r_h4tl_init = 0x40017878 ); +PROVIDE ( r_h4tl_start = 0x40017924 ); +PROVIDE ( r_h4tl_stop = 0x40017934 ); +PROVIDE ( r_h4tl_write = 0x400178d0 ); +PROVIDE ( r_H5 = 0x400138dc ); +PROVIDE ( r_hashConcat = 0x40013a38 ); +PROVIDE ( r_hci_acl_tx_data_alloc = 0x4001951c ); +PROVIDE ( r_hci_acl_tx_data_received = 0x40019654 ); +PROVIDE ( r_hci_bt_acl_bdaddr_register = 0x40018900 ); +PROVIDE ( r_hci_bt_acl_bdaddr_unregister = 0x400189ac ); +PROVIDE ( r_hci_bt_acl_conhdl_register = 0x4001895c ); +PROVIDE ( r_hci_cmd_get_max_param_size = 0x400192d0 ); +PROVIDE ( r_hci_cmd_received = 0x400192f8 ); +PROVIDE ( r_hci_evt_filter_add = 0x40018a64 ); +PROVIDE ( r_hci_evt_mask_set = 0x400189e4 ); +PROVIDE ( r_hci_fc_acl_buf_size_set = 0x40017988 ); +PROVIDE ( r_hci_fc_acl_en = 0x400179d8 ); +PROVIDE ( r_hci_fc_acl_packet_sent = 0x40017a3c ); +PROVIDE ( r_hci_fc_check_host_available_nb_acl_packets = 0x40017aa4 ); +PROVIDE ( r_hci_fc_check_host_available_nb_sync_packets = 0x40017ac8 ); +PROVIDE ( r_hci_fc_host_nb_acl_pkts_complete = 0x40017a6c ); +PROVIDE ( r_hci_fc_host_nb_sync_pkts_complete = 0x40017a88 ); +PROVIDE ( r_hci_fc_init = 0x40017974 ); +PROVIDE ( r_hci_fc_sync_buf_size_set = 0x400179b0 ); +PROVIDE ( r_hci_fc_sync_en = 0x40017a30 ); +PROVIDE ( r_hci_fc_sync_packet_sent = 0x40017a54 ); +PROVIDE ( r_hci_init = 0x40018538 ); +PROVIDE ( r_hci_look_for_cmd_desc = 0x40018454 ); +PROVIDE ( r_hci_look_for_dbg_evt_desc = 0x400184c4 ); +PROVIDE ( r_hci_look_for_evt_desc = 0x400184a0 ); +PROVIDE ( r_hci_look_for_le_evt_desc = 0x400184e0 ); +PROVIDE ( r_hci_reset = 0x4001856c ); +PROVIDE ( r_hci_send_2_host = 0x400185bc ); +PROVIDE ( r_hci_sync_tx_data_alloc = 0x40019754 ); +PROVIDE ( r_hci_sync_tx_data_received = 0x400197c0 ); +PROVIDE ( r_hci_tl_init = 0x40019290 ); +PROVIDE ( r_hci_tl_send = 0x40019228 ); +PROVIDE ( r_hci_util_pack = 0x40019874 ); +PROVIDE ( r_hci_util_unpack = 0x40019998 ); +PROVIDE ( r_hci_voice_settings_get = 0x40018bdc ); +PROVIDE ( r_hci_voice_settings_set = 0x40018be8 ); +PROVIDE ( r_HMAC = 0x40013968 ); +PROVIDE ( r_import_rf_phy_func = 0x3ffb8354 ); +PROVIDE ( r_import_rf_phy_func_p = 0x3ffafd64 ); +PROVIDE ( r_ip_funcs = 0x3ffae710 ); +PROVIDE ( r_ip_funcs_p = 0x3ffae70c ); +PROVIDE ( r_ke_check_malloc = 0x40019de0 ); +PROVIDE ( r_ke_event_callback_set = 0x40019ba8 ); +PROVIDE ( r_ke_event_clear = 0x40019c2c ); +PROVIDE ( r_ke_event_flush = 0x40019ccc ); +PROVIDE ( r_ke_event_get = 0x40019c78 ); +PROVIDE ( r_ke_event_get_all = 0x40019cc0 ); +PROVIDE ( r_ke_event_init = 0x40019b90 ); +PROVIDE ( r_ke_event_schedule = 0x40019cdc ); +PROVIDE ( r_ke_event_set = 0x40019be0 ); +PROVIDE ( r_ke_flush = 0x4001a374 ); +PROVIDE ( r_ke_free = 0x4001a014 ); +PROVIDE ( r_ke_get_max_mem_usage = 0x4001a1c8 ); +PROVIDE ( r_ke_get_mem_usage = 0x4001a1a0 ); +PROVIDE ( r_ke_init = 0x4001a318 ); +PROVIDE ( r_ke_is_free = 0x4001a184 ); +PROVIDE ( r_ke_malloc = 0x40019eb4 ); +PROVIDE ( r_ke_mem_init = 0x40019d3c ); +PROVIDE ( r_ke_mem_is_empty = 0x40019d8c ); +PROVIDE ( r_ke_msg_alloc = 0x4001a1e0 ); +PROVIDE ( r_ke_msg_dest_id_get = 0x4001a2e0 ); +PROVIDE ( r_ke_msg_discard = 0x4001a850 ); +PROVIDE ( r_ke_msg_forward = 0x4001a290 ); +PROVIDE ( r_ke_msg_forward_new_id = 0x4001a2ac ); +PROVIDE ( r_ke_msg_free = 0x4001a2cc ); +PROVIDE ( r_ke_msg_in_queue = 0x4001a2f8 ); +PROVIDE ( r_ke_msg_save = 0x4001a858 ); +PROVIDE ( r_ke_msg_send = 0x4001a234 ); +PROVIDE ( r_ke_msg_send_basic = 0x4001a26c ); +PROVIDE ( r_ke_msg_src_id_get = 0x4001a2ec ); +PROVIDE ( r_ke_queue_extract = 0x40055fd0 ); +PROVIDE ( r_ke_queue_insert = 0x40056020 ); +PROVIDE ( r_ke_sleep_check = 0x4001a3d8 ); +PROVIDE ( r_ke_state_get = 0x4001a7d8 ); +PROVIDE ( r_ke_state_set = 0x4001a6fc ); +PROVIDE ( r_ke_stats_get = 0x4001a3f0 ); +PROVIDE ( r_ke_task_check = 0x4001a8a4 ); +PROVIDE ( r_ke_task_create = 0x4001a674 ); +PROVIDE ( r_ke_task_delete = 0x4001a6c0 ); +PROVIDE ( r_ke_task_init = 0x4001a650 ); +PROVIDE ( r_ke_task_msg_flush = 0x4001a860 ); +PROVIDE ( r_ke_timer_active = 0x4001ac08 ); +PROVIDE ( r_ke_timer_adjust_all = 0x4001ac30 ); +PROVIDE ( r_ke_timer_clear = 0x4001ab90 ); +PROVIDE ( r_ke_timer_init = 0x4001aa9c ); +PROVIDE ( r_ke_timer_set = 0x4001aac0 ); +PROVIDE ( r_ke_timer_sleep_check = 0x4001ac50 ); +PROVIDE ( r_KPrimC = 0x40010ad4 ); +PROVIDE ( r_lb_clk_adj_activate = 0x4001ae70 ); +PROVIDE ( r_lb_clk_adj_id_get = 0x4001af14 ); +PROVIDE ( r_lb_clk_adj_period_update = 0x4001af20 ); +PROVIDE ( r_lb_init = 0x4001acd4 ); +PROVIDE ( r_lb_mst_key = 0x4001afc0 ); +PROVIDE ( r_lb_mst_key_cmp = 0x4001af74 ); +PROVIDE ( r_lb_mst_key_restart_enc = 0x4001b0d4 ); +PROVIDE ( r_lb_mst_start_act_bcst_enc = 0x4001b198 ); +PROVIDE ( r_lb_mst_stop_act_bcst_enc = 0x4001b24c ); +PROVIDE ( r_lb_reset = 0x4001ad38 ); +PROVIDE ( r_lb_send_lmp = 0x4001adbc ); +PROVIDE ( r_lb_send_pdu_clk_adj = 0x4001af3c ); +PROVIDE ( r_lb_util_get_csb_mode = 0x4001ada4 ); +PROVIDE ( r_lb_util_get_nb_broadcast = 0x4001ad80 ); +PROVIDE ( r_lb_util_get_res_lt_addr = 0x4001ad98 ); +PROVIDE ( r_lb_util_set_nb_broadcast = 0x4001ad8c ); +PROVIDE ( r_lc_afh_set = 0x4001cc74 ); +PROVIDE ( r_lc_afh_start = 0x4001d240 ); +PROVIDE ( r_lc_auth_cmp = 0x4001cd54 ); +PROVIDE ( r_lc_calc_link_key = 0x4001ce7c ); +PROVIDE ( r_lc_chg_pkt_type_cmp = 0x4001d038 ); +PROVIDE ( r_lc_chg_pkt_type_cont = 0x4001cfbc ); +PROVIDE ( r_lc_chg_pkt_type_retry = 0x4001d0ac ); +PROVIDE ( r_lc_chk_to = 0x4001d2a8 ); +PROVIDE ( r_lc_cmd_stat_send = 0x4001c914 ); +PROVIDE ( r_lc_comb_key_svr = 0x4001d30c ); +PROVIDE ( r_lc_con_cmp = 0x4001d44c ); +PROVIDE ( r_lc_con_cmp_evt_send = 0x4001d4fc ); +PROVIDE ( r_lc_conn_seq_done = 0x40021334 ); +PROVIDE ( r_lc_detach = 0x4002037c ); +PROVIDE ( r_lc_dhkey = 0x4001d564 ); +PROVIDE ( r_lc_enc_cmp = 0x4001d8bc ); +PROVIDE ( r_lc_enc_key_refresh = 0x4001d720 ); +PROVIDE ( r_lc_end_chk_colli = 0x4001d858 ); +PROVIDE ( r_lc_end_of_sniff_nego = 0x4001d9a4 ); +PROVIDE ( r_lc_enter_sniff_mode = 0x4001ddb8 ); +PROVIDE ( r_lc_epr_change_lk = 0x4001db38 ); +PROVIDE ( r_lc_epr_cmp = 0x4001da88 ); +PROVIDE ( r_lc_epr_resp = 0x4001e0b4 ); +PROVIDE ( r_lc_epr_rsw_cmp = 0x4001dd40 ); +PROVIDE ( r_lc_ext_feat = 0x40020d6c ); +PROVIDE ( r_lc_feat = 0x40020984 ); +PROVIDE ( r_lc_hl_connect = 0x400209e8 ); +PROVIDE ( r_lc_init = 0x4001c948 ); +PROVIDE ( r_lc_init_calc_f3 = 0x4001deb0 ); +PROVIDE ( r_lc_initiator_epr = 0x4001e064 ); +PROVIDE ( r_lc_init_passkey_loop = 0x4001dfc0 ); +PROVIDE ( r_lc_init_start_mutual_auth = 0x4001df60 ); +PROVIDE ( r_lc_key_exch_end = 0x4001e140 ); +PROVIDE ( r_lc_legacy_pair = 0x4001e1c0 ); +PROVIDE ( r_lc_local_switch = 0x4001e22c ); +PROVIDE ( r_lc_local_trans_mode = 0x4001e2e4 ); +PROVIDE ( r_lc_local_untrans_mode = 0x4001e3a0 ); +PROVIDE ( r_lc_loc_auth = 0x40020ecc ); +PROVIDE ( r_lc_locepr_lkref = 0x4001d648 ); +PROVIDE ( r_lc_locepr_rsw = 0x4001d5d0 ); +PROVIDE ( r_lc_loc_sniff = 0x40020a6c ); +PROVIDE ( r_lc_max_slot_mgt = 0x4001e410 ); +PROVIDE ( r_lc_mst_key = 0x4001e7c0 ); +PROVIDE ( r_lc_mst_qos_done = 0x4001ea80 ); +PROVIDE ( r_lc_mst_send_mst_key = 0x4001e8f4 ); +PROVIDE ( r_lc_mutual_auth_end = 0x4001e670 ); +PROVIDE ( r_lc_mutual_auth_end2 = 0x4001e4f4 ); +PROVIDE ( r_lc_packet_type = 0x40021038 ); +PROVIDE ( r_lc_pair = 0x40020ddc ); +PROVIDE ( r_lc_pairing_cont = 0x4001eafc ); +PROVIDE ( r_lc_passkey_comm = 0x4001ed20 ); +PROVIDE ( r_lc_prepare_all_links_for_clk_adj = 0x40021430 ); +PROVIDE ( r_lc_proc_rcv_dhkey = 0x4001edec ); +PROVIDE ( r_lc_ptt = 0x4001ee2c ); +PROVIDE ( r_lc_ptt_cmp = 0x4001eeec ); +PROVIDE ( r_lc_qos_setup = 0x4001ef50 ); +PROVIDE ( r_lc_rd_rem_name = 0x4001efd0 ); +PROVIDE ( r_lc_release = 0x4001f8a8 ); +PROVIDE ( r_lc_rem_enc = 0x4001f124 ); +PROVIDE ( r_lc_rem_name_cont = 0x4001f290 ); +PROVIDE ( r_lc_rem_nego_trans_mode = 0x4001f1b4 ); +PROVIDE ( r_lc_rem_sniff = 0x40020ca4 ); +PROVIDE ( r_lc_rem_sniff_sub_rate = 0x40020b10 ); +PROVIDE ( r_lc_rem_switch = 0x4001f070 ); +PROVIDE ( r_lc_rem_trans_mode = 0x4001f314 ); +PROVIDE ( r_lc_rem_unsniff = 0x400207a0 ); +PROVIDE ( r_lc_rem_untrans_mode = 0x4001f36c ); +PROVIDE ( r_lc_reset = 0x4001c99c ); +PROVIDE ( r_lc_resp_auth = 0x4001f518 ); +PROVIDE ( r_lc_resp_calc_f3 = 0x4001f710 ); +PROVIDE ( r_lc_resp_num_comp = 0x40020074 ); +PROVIDE ( r_lc_resp_oob_nonce = 0x4001f694 ); +PROVIDE ( r_lc_resp_oob_wait_nonce = 0x4001f66c ); +PROVIDE ( r_lc_resp_pair = 0x400208a4 ); +PROVIDE ( r_lc_resp_sec_auth = 0x4001f4a0 ); +PROVIDE ( r_lc_resp_wait_dhkey_cont = 0x4001f86c ); +PROVIDE ( r_lc_restart_enc = 0x4001f8ec ); +PROVIDE ( r_lc_restart_enc_cont = 0x4001f940 ); +PROVIDE ( r_lc_restore_afh_reporting = 0x4001f028 ); +PROVIDE ( r_lc_restore_to = 0x4001f9e0 ); +PROVIDE ( r_lc_ret_sniff_max_slot_chg = 0x4001fa30 ); +PROVIDE ( r_lc_rsw_clean_up = 0x4001dc70 ); +PROVIDE ( r_lc_rsw_done = 0x4001db94 ); +PROVIDE ( r_lc_sco_baseband_ack = 0x40022b00 ); +PROVIDE ( r_lc_sco_detach = 0x40021e40 ); +PROVIDE ( r_lc_sco_host_accept = 0x40022118 ); +PROVIDE ( r_lc_sco_host_reject = 0x400222b8 ); +PROVIDE ( r_lc_sco_host_request = 0x40021f4c ); +PROVIDE ( r_lc_sco_host_request_disc = 0x4002235c ); +PROVIDE ( r_lc_sco_init = 0x40021dc8 ); +PROVIDE ( r_lc_sco_peer_accept = 0x40022780 ); +PROVIDE ( r_lc_sco_peer_accept_disc = 0x40022a08 ); +PROVIDE ( r_lc_sco_peer_reject = 0x40022824 ); +PROVIDE ( r_lc_sco_peer_reject_disc = 0x40022a8c ); +PROVIDE ( r_lc_sco_peer_request = 0x4002240c ); +PROVIDE ( r_lc_sco_peer_request_disc = 0x400228ec ); +PROVIDE ( r_lc_sco_release = 0x40021eec ); +PROVIDE ( r_lc_sco_reset = 0x40021dfc ); +PROVIDE ( r_lc_sco_timeout = 0x40022bd4 ); +PROVIDE ( r_lc_sec_auth_compute_sres = 0x4001f3ec ); +PROVIDE ( r_lc_semi_key_cmp = 0x40020294 ); +PROVIDE ( r_lc_send_enc_chg_evt = 0x4002134c ); +PROVIDE ( r_lc_send_enc_mode = 0x40020220 ); +PROVIDE ( r_lc_send_lmp = 0x4001c1a8 ); +PROVIDE ( r_lc_send_pdu_acc = 0x4001c21c ); +PROVIDE ( r_lc_send_pdu_acc_ext4 = 0x4001c240 ); +PROVIDE ( r_lc_send_pdu_au_rand = 0x4001c308 ); +PROVIDE ( r_lc_send_pdu_auto_rate = 0x4001c5d0 ); +PROVIDE ( r_lc_send_pdu_clk_adj_ack = 0x4001c46c ); +PROVIDE ( r_lc_send_pdu_clk_adj_req = 0x4001c494 ); +PROVIDE ( r_lc_send_pdu_comb_key = 0x4001c368 ); +PROVIDE ( r_lc_send_pdu_dhkey_chk = 0x4001c8e8 ); +PROVIDE ( r_lc_send_pdu_encaps_head = 0x4001c440 ); +PROVIDE ( r_lc_send_pdu_encaps_payl = 0x4001c410 ); +PROVIDE ( r_lc_send_pdu_enc_key_sz_req = 0x4001c670 ); +PROVIDE ( r_lc_send_pdu_esco_lk_rem_req = 0x4001c5a8 ); +PROVIDE ( r_lc_send_pdu_feats_ext_req = 0x4001c6ec ); +PROVIDE ( r_lc_send_pdu_feats_res = 0x4001c694 ); +PROVIDE ( r_lc_send_pdu_in_rand = 0x4001c338 ); +PROVIDE ( r_lc_send_pdu_io_cap_res = 0x4001c72c ); +PROVIDE ( r_lc_send_pdu_lsto = 0x4001c64c ); +PROVIDE ( r_lc_send_pdu_max_slot = 0x4001c3c8 ); +PROVIDE ( r_lc_send_pdu_max_slot_req = 0x4001c3ec ); +PROVIDE ( r_lc_send_pdu_not_acc = 0x4001c26c ); +PROVIDE ( r_lc_send_pdu_not_acc_ext4 = 0x4001c294 ); +PROVIDE ( r_lc_send_pdu_num_comp_fail = 0x4001c770 ); +PROVIDE ( r_lc_send_pdu_pause_enc_aes_req = 0x4001c794 ); +PROVIDE ( r_lc_send_pdu_paus_enc_req = 0x4001c7c0 ); +PROVIDE ( r_lc_send_pdu_ptt_req = 0x4001c4c0 ); +PROVIDE ( r_lc_send_pdu_qos_req = 0x4001c82c ); +PROVIDE ( r_lc_send_pdu_resu_enc_req = 0x4001c7e4 ); +PROVIDE ( r_lc_send_pdu_sco_lk_rem_req = 0x4001c580 ); +PROVIDE ( r_lc_send_pdu_set_afh = 0x4001c2c8 ); +PROVIDE ( r_lc_send_pdu_setup_cmp = 0x4001c808 ); +PROVIDE ( r_lc_send_pdu_slot_off = 0x4001c854 ); +PROVIDE ( r_lc_send_pdu_sniff_req = 0x4001c5f0 ); +PROVIDE ( r_lc_send_pdu_sp_cfm = 0x4001c518 ); +PROVIDE ( r_lc_send_pdu_sp_nb = 0x4001c4e8 ); +PROVIDE ( r_lc_send_pdu_sres = 0x4001c548 ); +PROVIDE ( r_lc_send_pdu_tim_acc = 0x4001c6cc ); +PROVIDE ( r_lc_send_pdu_unit_key = 0x4001c398 ); +PROVIDE ( r_lc_send_pdu_unsniff_req = 0x4001c894 ); +PROVIDE ( r_lc_send_pdu_vers_req = 0x4001c8b4 ); +PROVIDE ( r_lc_skip_hl_oob_req = 0x400201bc ); +PROVIDE ( r_lc_sniff_init = 0x40022cac ); +PROVIDE ( r_lc_sniff_max_slot_chg = 0x40020590 ); +PROVIDE ( r_lc_sniff_reset = 0x40022cc8 ); +PROVIDE ( r_lc_sniff_slot_unchange = 0x40021100 ); +PROVIDE ( r_lc_sniff_sub_mode = 0x400204fc ); +PROVIDE ( r_lc_sp_end = 0x400213a8 ); +PROVIDE ( r_lc_sp_fail = 0x40020470 ); +PROVIDE ( r_lc_sp_oob_tid_fail = 0x400204cc ); +PROVIDE ( r_lc_ssr_nego = 0x4002125c ); +PROVIDE ( r_lc_start = 0x4001ca28 ); +PROVIDE ( r_lc_start_enc = 0x4001fb28 ); +PROVIDE ( r_lc_start_enc_key_size = 0x4001fd9c ); +PROVIDE ( r_lc_start_key_exch = 0x4001fe10 ); +PROVIDE ( r_lc_start_lmp_to = 0x4001fae8 ); +PROVIDE ( r_lc_start_oob = 0x4001fffc ); +PROVIDE ( r_lc_start_passkey = 0x4001feac ); +PROVIDE ( r_lc_start_passkey_loop = 0x4001ff88 ); +PROVIDE ( r_lc_stop_afh_report = 0x40020184 ); +PROVIDE ( r_lc_stop_enc = 0x40020110 ); +PROVIDE ( r_lc_switch_cmp = 0x40020448 ); +PROVIDE ( r_lc_unit_key_svr = 0x400206d8 ); +PROVIDE ( r_lc_unsniff = 0x40020c50 ); +PROVIDE ( r_lc_unsniff_cmp = 0x40020810 ); +PROVIDE ( r_lc_unsniff_cont = 0x40020750 ); +PROVIDE ( r_lc_upd_to = 0x4002065c ); +PROVIDE ( r_lc_util_convert_pref_rate_to_packet_type = 0x4002f9b0 ); +PROVIDE ( r_lc_util_get_max_packet_size = 0x4002f4ac ); +PROVIDE ( r_lc_util_get_offset_clke = 0x4002f538 ); +PROVIDE ( r_lc_util_get_offset_clkn = 0x4002f51c ); +PROVIDE ( r_lc_util_set_loc_trans_coll = 0x4002f500 ); +PROVIDE ( r_lc_version = 0x40020a30 ); +PROVIDE ( r_ld_acl_active_hop_types_get = 0x40036e10 ); +PROVIDE ( r_ld_acl_afh_confirm = 0x40036d40 ); +PROVIDE ( r_ld_acl_afh_prepare = 0x40036c84 ); +PROVIDE ( r_ld_acl_afh_set = 0x40036b60 ); +PROVIDE ( r_ld_acl_allowed_tx_packet_types_set = 0x40036810 ); +PROVIDE ( r_ld_acl_bcst_rx_dec = 0x40036394 ); +PROVIDE ( r_ld_acl_bit_off_get = 0x40036b18 ); +PROVIDE ( r_ld_acl_clk_adj_set = 0x40036a00 ); +PROVIDE ( r_ld_acl_clk_off_get = 0x40036b00 ); +PROVIDE ( r_ld_acl_clk_set = 0x40036950 ); +PROVIDE ( r_ld_acl_clock_offset_get = 0x400364c0 ); +PROVIDE ( r_ld_acl_current_tx_power_get = 0x400368f0 ); +PROVIDE ( r_ld_acl_data_flush = 0x400357bc ); +PROVIDE ( r_ld_acl_data_tx = 0x4003544c ); +PROVIDE ( r_ld_acl_edr_set = 0x4003678c ); +PROVIDE ( r_ld_acl_enc_key_load = 0x40036404 ); +PROVIDE ( r_ld_acl_flow_off = 0x40035400 ); +PROVIDE ( r_ld_acl_flow_on = 0x4003541c ); +PROVIDE ( r_ld_acl_flush_timeout_get = 0x40035f9c ); +PROVIDE ( r_ld_acl_flush_timeout_set = 0x40035fe0 ); +PROVIDE ( r_ld_acl_init = 0x40034d08 ); +PROVIDE ( r_ld_acl_lmp_flush = 0x40035d80 ); +PROVIDE ( r_ld_acl_lmp_tx = 0x40035b34 ); +PROVIDE ( r_ld_acl_lsto_get = 0x400366b4 ); +PROVIDE ( r_ld_acl_lsto_set = 0x400366f8 ); +PROVIDE ( r_ld_acl_reset = 0x40034d24 ); +PROVIDE ( r_ld_acl_role_get = 0x40036b30 ); +PROVIDE ( r_ld_acl_rssi_delta_get = 0x40037028 ); +PROVIDE ( r_ld_acl_rsw_req = 0x40035e74 ); +PROVIDE ( r_ld_acl_rx_enc = 0x40036344 ); +PROVIDE ( r_ld_acl_rx_max_slot_get = 0x40036e58 ); +PROVIDE ( r_ld_acl_rx_max_slot_set = 0x40036ea0 ); +PROVIDE ( r_ld_acl_slot_offset_get = 0x4003653c ); +PROVIDE ( r_ld_acl_slot_offset_set = 0x40036658 ); +PROVIDE ( r_ld_acl_sniff = 0x4003617c ); +PROVIDE ( r_ld_acl_sniff_trans = 0x400360a8 ); +PROVIDE ( r_ld_acl_ssr_set = 0x40036274 ); +PROVIDE ( r_ld_acl_start = 0x40034ddc ); +PROVIDE ( r_ld_acl_stop = 0x4003532c ); +PROVIDE ( r_ld_acl_test_mode_set = 0x40036f24 ); +PROVIDE ( r_ld_acl_timing_accuracy_set = 0x4003673c ); +PROVIDE ( r_ld_acl_t_poll_get = 0x40036024 ); +PROVIDE ( r_ld_acl_t_poll_set = 0x40036068 ); +PROVIDE ( r_ld_acl_tx_enc = 0x400362f8 ); +PROVIDE ( r_ld_acl_unsniff = 0x400361e0 ); +PROVIDE ( r_ld_active_check = 0x4003cac4 ); +PROVIDE ( r_ld_afh_ch_assess_data_get = 0x4003caec ); +PROVIDE ( r_ld_bcst_acl_data_tx = 0x40038d3c ); +PROVIDE ( r_ld_bcst_acl_init = 0x40038bd0 ); +PROVIDE ( r_ld_bcst_acl_reset = 0x40038bdc ); +PROVIDE ( r_ld_bcst_acl_start = 0x4003882c ); +PROVIDE ( r_ld_bcst_afh_update = 0x40038f3c ); +PROVIDE ( r_ld_bcst_enc_key_load = 0x4003906c ); +PROVIDE ( r_ld_bcst_lmp_tx = 0x40038bf8 ); +PROVIDE ( r_ld_bcst_tx_enc = 0x40038ff8 ); +PROVIDE ( r_ld_bd_addr_get = 0x4003ca20 ); +PROVIDE ( r_ld_channel_assess = 0x4003c184 ); +PROVIDE ( r_ld_class_of_dev_get = 0x4003ca34 ); +PROVIDE ( r_ld_class_of_dev_set = 0x4003ca50 ); +PROVIDE ( r_ld_csb_rx_afh_update = 0x40039af4 ); +PROVIDE ( r_ld_csb_rx_init = 0x40039690 ); +PROVIDE ( r_ld_csb_rx_reset = 0x4003969c ); +PROVIDE ( r_ld_csb_rx_start = 0x4003972c ); +PROVIDE ( r_ld_csb_rx_stop = 0x40039bb8 ); +PROVIDE ( r_ld_csb_tx_afh_update = 0x4003a5fc ); +PROVIDE ( r_ld_csb_tx_clr_data = 0x4003a71c ); +PROVIDE ( r_ld_csb_tx_dis = 0x4003a5e8 ); +PROVIDE ( r_ld_csb_tx_en = 0x4003a1c0 ); +PROVIDE ( r_ld_csb_tx_init = 0x4003a0e8 ); +PROVIDE ( r_ld_csb_tx_reset = 0x4003a0f8 ); +PROVIDE ( r_ld_csb_tx_set_data = 0x4003a6c0 ); +PROVIDE ( r_ld_fm_clk_isr = 0x4003a7a8 ); +PROVIDE ( r_ld_fm_frame_isr = 0x4003a82c ); +PROVIDE ( r_ld_fm_init = 0x4003a760 ); +PROVIDE ( r_ld_fm_prog_check = 0x4003ab28 ); +PROVIDE ( r_ld_fm_prog_disable = 0x4003a984 ); +PROVIDE ( r_ld_fm_prog_enable = 0x4003a944 ); +PROVIDE ( r_ld_fm_prog_push = 0x4003a9d4 ); +PROVIDE ( r_ld_fm_reset = 0x4003a794 ); +PROVIDE ( r_ld_fm_rx_isr = 0x4003a7f4 ); +PROVIDE ( r_ld_fm_sket_isr = 0x4003a8a4 ); +PROVIDE ( r_ld_init = 0x4003c294 ); +PROVIDE ( r_ld_inq_init = 0x4003b15c ); +PROVIDE ( r_ld_inq_reset = 0x4003b168 ); +PROVIDE ( r_ld_inq_start = 0x4003b1f0 ); +PROVIDE ( r_ld_inq_stop = 0x4003b4f0 ); +PROVIDE ( r_ld_iscan_eir_get = 0x4003c118 ); +PROVIDE ( r_ld_iscan_eir_set = 0x4003bfa0 ); +PROVIDE ( r_ld_iscan_init = 0x4003b9f0 ); +PROVIDE ( r_ld_iscan_reset = 0x4003ba14 ); +PROVIDE ( r_ld_iscan_restart = 0x4003ba44 ); +PROVIDE ( r_ld_iscan_start = 0x4003bb28 ); +PROVIDE ( r_ld_iscan_stop = 0x4003bf1c ); +PROVIDE ( r_ld_iscan_tx_pwr_get = 0x4003c138 ); +PROVIDE ( r_ld_page_init = 0x4003d808 ); +PROVIDE ( r_ld_page_reset = 0x4003d814 ); +PROVIDE ( r_ld_page_start = 0x4003d848 ); +PROVIDE ( r_ld_page_stop = 0x4003da54 ); +PROVIDE ( r_ld_pca_coarse_clock_adjust = 0x4003e324 ); +PROVIDE ( r_ld_pca_init = 0x4003deb4 ); +PROVIDE ( r_ld_pca_initiate_clock_dragging = 0x4003e4ac ); +PROVIDE ( r_ld_pca_local_config = 0x4003df6c ); +PROVIDE ( r_ld_pca_mws_frame_sync = 0x4003e104 ); +PROVIDE ( r_ld_pca_mws_moment_offset_gt = 0x4003e278 ); +PROVIDE ( r_ld_pca_mws_moment_offset_lt = 0x4003e280 ); +PROVIDE ( r_ld_pca_reporting_enable = 0x4003e018 ); +PROVIDE ( r_ld_pca_reset = 0x4003df0c ); +PROVIDE ( r_ld_pca_update_target_offset = 0x4003e050 ); +PROVIDE ( r_ld_pscan_evt_handler = 0x4003f238 ); +PROVIDE ( r_ld_pscan_init = 0x4003f474 ); +PROVIDE ( r_ld_pscan_reset = 0x4003f498 ); +PROVIDE ( r_ld_pscan_restart = 0x4003f4b8 ); +PROVIDE ( r_ld_pscan_start = 0x4003f514 ); +PROVIDE ( r_ld_pscan_stop = 0x4003f618 ); +PROVIDE ( r_ld_read_clock = 0x4003c9e4 ); +PROVIDE ( r_ld_reset = 0x4003c714 ); +PROVIDE ( r_ld_sched_acl_add = 0x4003f978 ); +PROVIDE ( r_ld_sched_acl_remove = 0x4003f99c ); +PROVIDE ( r_ld_sched_compute = 0x4003f6f8 ); +PROVIDE ( r_ld_sched_init = 0x4003f7ac ); +PROVIDE ( r_ld_sched_inq_add = 0x4003f8a8 ); +PROVIDE ( r_ld_sched_inq_remove = 0x4003f8d0 ); +PROVIDE ( r_ld_sched_iscan_add = 0x4003f7e8 ); +PROVIDE ( r_ld_sched_iscan_remove = 0x4003f808 ); +PROVIDE ( r_ld_sched_page_add = 0x4003f910 ); +PROVIDE ( r_ld_sched_page_remove = 0x4003f938 ); +PROVIDE ( r_ld_sched_pscan_add = 0x4003f828 ); +PROVIDE ( r_ld_sched_pscan_remove = 0x4003f848 ); +PROVIDE ( r_ld_sched_reset = 0x4003f7d4 ); +PROVIDE ( r_ld_sched_sco_add = 0x4003fa4c ); +PROVIDE ( r_ld_sched_sco_remove = 0x4003fa9c ); +PROVIDE ( r_ld_sched_sniff_add = 0x4003f9c4 ); +PROVIDE ( r_ld_sched_sniff_remove = 0x4003fa0c ); +PROVIDE ( r_ld_sched_sscan_add = 0x4003f868 ); +PROVIDE ( r_ld_sched_sscan_remove = 0x4003f888 ); +PROVIDE ( r_ld_sco_audio_isr = 0x40037cc8 ); +PROVIDE ( r_ld_sco_data_tx = 0x40037ee8 ); +PROVIDE ( r_ld_sco_start = 0x40037110 ); +PROVIDE ( r_ld_sco_stop = 0x40037c40 ); +PROVIDE ( r_ld_sco_update = 0x40037a74 ); +PROVIDE ( r_ld_sscan_activated = 0x4004031c ); +PROVIDE ( r_ld_sscan_init = 0x400402f0 ); +PROVIDE ( r_ld_sscan_reset = 0x400402fc ); +PROVIDE ( r_ld_sscan_start = 0x40040384 ); +PROVIDE ( r_ld_strain_init = 0x400409f4 ); +PROVIDE ( r_ld_strain_reset = 0x40040a00 ); +PROVIDE ( r_ld_strain_start = 0x40040a8c ); +PROVIDE ( r_ld_strain_stop = 0x40040df0 ); +PROVIDE ( r_ld_timing_accuracy_get = 0x4003caac ); +PROVIDE ( r_ld_util_active_master_afh_map_get = 0x4004131c ); +PROVIDE ( r_ld_util_active_master_afh_map_set = 0x40041308 ); +PROVIDE ( r_ld_util_bch_create = 0x40040fcc ); +PROVIDE ( r_ld_util_fhs_pk = 0x400411c8 ); +PROVIDE ( r_ld_util_fhs_unpk = 0x40040e54 ); +PROVIDE ( r_ld_util_stp_pk = 0x400413f4 ); +PROVIDE ( r_ld_util_stp_unpk = 0x40041324 ); +PROVIDE ( r_ld_version_get = 0x4003ca6c ); +PROVIDE ( r_ld_wlcoex_set = 0x4003caf8 ); +PROVIDE ( r_llc_ch_assess_get_current_ch_map = 0x40041574 ); +PROVIDE ( r_llc_ch_assess_get_local_ch_map = 0x4004150c ); +PROVIDE ( r_llc_ch_assess_local = 0x40041494 ); +PROVIDE ( r_llc_ch_assess_merge_ch = 0x40041588 ); +PROVIDE ( r_llc_ch_assess_reass_ch = 0x400415c0 ); +PROVIDE ( r_llc_common_cmd_complete_send = 0x40044eac ); +PROVIDE ( r_llc_common_cmd_status_send = 0x40044ee0 ); +PROVIDE ( r_llc_common_enc_change_evt_send = 0x40044f6c ); +PROVIDE ( r_llc_common_enc_key_ref_comp_evt_send = 0x40044f38 ); +PROVIDE ( r_llc_common_flush_occurred_send = 0x40044f0c ); +PROVIDE ( r_llc_common_nb_of_pkt_comp_evt_send = 0x40045000 ); +PROVIDE ( r_llc_con_update_complete_send = 0x40044d68 ); +PROVIDE ( r_llc_con_update_finished = 0x4004518c ); +PROVIDE ( r_llc_con_update_ind = 0x40045038 ); +PROVIDE ( r_llc_discon_event_complete_send = 0x40044a30 ); +PROVIDE ( r_llc_end_evt_defer = 0x40046330 ); +PROVIDE ( r_llc_feats_rd_event_send = 0x40044e0c ); +PROVIDE ( r_llc_init = 0x40044778 ); +PROVIDE ( r_llc_le_con_cmp_evt_send = 0x40044a78 ); +PROVIDE ( r_llc_llcp_ch_map_update_pdu_send = 0x40043f94 ); +PROVIDE ( r_llc_llcp_con_param_req_pdu_send = 0x400442fc ); +PROVIDE ( r_llc_llcp_con_param_rsp_pdu_send = 0x40044358 ); +PROVIDE ( r_llc_llcp_con_update_pdu_send = 0x400442c4 ); +PROVIDE ( r_llc_llcp_enc_req_pdu_send = 0x40044064 ); +PROVIDE ( r_llc_llcp_enc_rsp_pdu_send = 0x40044160 ); +PROVIDE ( r_llc_llcp_feats_req_pdu_send = 0x400443b4 ); +PROVIDE ( r_llc_llcp_feats_rsp_pdu_send = 0x400443f0 ); +PROVIDE ( r_llc_llcp_get_autorize = 0x4004475c ); +PROVIDE ( r_llc_llcp_length_req_pdu_send = 0x40044574 ); +PROVIDE ( r_llc_llcp_length_rsp_pdu_send = 0x400445ac ); +PROVIDE ( r_llc_llcp_pause_enc_req_pdu_send = 0x40043fd8 ); +PROVIDE ( r_llc_llcp_pause_enc_rsp_pdu_send = 0x40044010 ); +PROVIDE ( r_llc_llcp_ping_req_pdu_send = 0x4004454c ); +PROVIDE ( r_llc_llcp_ping_rsp_pdu_send = 0x40044560 ); +PROVIDE ( r_llc_llcp_recv_handler = 0x40044678 ); +PROVIDE ( r_llc_llcp_reject_ind_pdu_send = 0x4004425c ); +PROVIDE ( r_llc_llcp_start_enc_req_pdu_send = 0x4004441c ); +PROVIDE ( r_llc_llcp_start_enc_rsp_pdu_send = 0x400441f8 ); +PROVIDE ( r_llc_llcp_terminate_ind_pdu_send = 0x400444b0 ); +PROVIDE ( r_llc_llcp_tester_send = 0x400445e4 ); +PROVIDE ( r_llc_llcp_unknown_rsp_send_pdu = 0x40044534 ); +PROVIDE ( r_llc_llcp_version_ind_pdu_send = 0x40043f6c ); +PROVIDE ( r_llc_lsto_con_update = 0x40045098 ); +PROVIDE ( r_llc_ltk_req_send = 0x40044dc0 ); +PROVIDE ( r_llc_map_update_finished = 0x40045260 ); +PROVIDE ( r_llc_map_update_ind = 0x400450f0 ); +PROVIDE ( r_llc_pdu_acl_tx_ack_defer = 0x400464dc ); +PROVIDE ( r_llc_pdu_defer = 0x40046528 ); +PROVIDE ( r_llc_pdu_llcp_tx_ack_defer = 0x400463ac ); +PROVIDE ( r_llc_reset = 0x400447b8 ); +PROVIDE ( r_llc_start = 0x400447f4 ); +PROVIDE ( r_llc_stop = 0x400449ac ); +PROVIDE ( r_llc_util_bw_mgt = 0x4004629c ); +PROVIDE ( r_llc_util_clear_operation_ptr = 0x40046234 ); +PROVIDE ( r_llc_util_dicon_procedure = 0x40046130 ); +PROVIDE ( r_llc_util_get_free_conhdl = 0x400460c8 ); +PROVIDE ( r_llc_util_get_nb_active_link = 0x40046100 ); +PROVIDE ( r_llc_util_set_auth_payl_to_margin = 0x400461f4 ); +PROVIDE ( r_llc_util_set_llcp_discard_enable = 0x400461c8 ); +PROVIDE ( r_llc_util_update_channel_map = 0x400461ac ); +PROVIDE ( r_llc_version_rd_event_send = 0x40044e60 ); +PROVIDE ( r_lld_adv_start = 0x40048b38 ); +PROVIDE ( r_lld_adv_stop = 0x40048ea0 ); +PROVIDE ( r_lld_ch_map_ind = 0x4004a2f4 ); +PROVIDE ( r_lld_con_param_req = 0x40049f0c ); +PROVIDE ( r_lld_con_param_rsp = 0x40049e00 ); +PROVIDE ( r_lld_con_start = 0x400491f8 ); +PROVIDE ( r_lld_con_stop = 0x40049fdc ); +PROVIDE ( r_lld_con_update_after_param_req = 0x40049bcc ); +PROVIDE ( r_lld_con_update_ind = 0x4004a30c ); +PROVIDE ( r_lld_con_update_req = 0x40049b60 ); +PROVIDE ( r_lld_core_reset = 0x40048a9c ); +PROVIDE ( r_lld_crypt_isr = 0x4004a324 ); +PROVIDE ( r_lld_evt_adv_create = 0x400481f4 ); +PROVIDE ( r_lld_evt_canceled = 0x400485c8 ); +PROVIDE ( r_lld_evt_channel_next = 0x40046aac ); +PROVIDE ( r_lld_evt_deffered_elt_handler = 0x400482bc ); +PROVIDE ( r_lld_evt_delete_elt_handler = 0x40046974 ); +PROVIDE ( r_lld_evt_delete_elt_push = 0x40046a3c ); +PROVIDE ( r_lld_evt_drift_compute = 0x40047670 ); +PROVIDE ( r_lld_evt_elt_delete = 0x40047538 ); +PROVIDE ( r_lld_evt_elt_insert = 0x400474c8 ); +PROVIDE ( r_lld_evt_end = 0x400483e8 ); +PROVIDE ( r_lld_evt_end_isr = 0x4004862c ); +PROVIDE ( r_lld_evt_init = 0x40046b3c ); +PROVIDE ( r_lld_evt_init_evt = 0x40046cd0 ); +PROVIDE ( r_lld_evt_move_to_master = 0x40047ba0 ); +PROVIDE ( r_lld_evt_move_to_slave = 0x40047e18 ); +PROVIDE ( r_lld_evt_prevent_stop = 0x40047adc ); +PROVIDE ( r_lld_evt_restart = 0x40046d50 ); +PROVIDE ( r_lld_evt_rx = 0x40048578 ); +PROVIDE ( r_lld_evt_rx_isr = 0x40048678 ); +PROVIDE ( r_lld_evt_scan_create = 0x40047ae8 ); +PROVIDE ( r_lld_evt_schedule = 0x40047908 ); +PROVIDE ( r_lld_evt_schedule_next = 0x400477dc ); +PROVIDE ( r_lld_evt_schedule_next_instant = 0x400476a8 ); +PROVIDE ( r_lld_evt_slave_update = 0x40048138 ); +PROVIDE ( r_lld_evt_update_create = 0x40047cd8 ); +PROVIDE ( r_lld_get_mode = 0x40049ff8 ); +PROVIDE ( r_lld_init = 0x4004873c ); +PROVIDE ( r_lld_move_to_master = 0x400499e0 ); +PROVIDE ( r_lld_move_to_slave = 0x4004a024 ); +PROVIDE ( r_lld_pdu_adv_pack = 0x4004b488 ); +PROVIDE ( r_lld_pdu_check = 0x4004ac34 ); +PROVIDE ( r_lld_pdu_data_send = 0x4004b018 ); +PROVIDE ( r_lld_pdu_data_tx_push = 0x4004aecc ); +PROVIDE ( r_lld_pdu_rx_handler = 0x4004b4d4 ); +PROVIDE ( r_lld_pdu_send_packet = 0x4004b774 ); +PROVIDE ( r_lld_pdu_tx_flush = 0x4004b414 ); +PROVIDE ( r_lld_pdu_tx_loop = 0x4004ae40 ); +PROVIDE ( r_lld_pdu_tx_prog = 0x4004b120 ); +PROVIDE ( r_lld_pdu_tx_push = 0x4004b080 ); +PROVIDE ( r_lld_ral_renew_req = 0x4004a73c ); +PROVIDE ( r_lld_scan_start = 0x40048ee0 ); +PROVIDE ( r_lld_scan_stop = 0x40049190 ); +PROVIDE ( r_lld_test_mode_rx = 0x4004a540 ); +PROVIDE ( r_lld_test_mode_tx = 0x4004a350 ); +PROVIDE ( r_lld_test_stop = 0x4004a710 ); +PROVIDE ( r_lld_util_anchor_point_move = 0x4004bacc ); +PROVIDE ( r_lld_util_compute_ce_max = 0x4004bc0c ); +PROVIDE ( r_lld_util_connection_param_set = 0x4004ba40 ); +PROVIDE ( r_lld_util_dle_set_cs_fields = 0x4004ba90 ); +PROVIDE ( r_lld_util_eff_tx_time_set = 0x4004bd88 ); +PROVIDE ( r_lld_util_elt_programmed = 0x4004bce0 ); +PROVIDE ( r_lld_util_flush_list = 0x4004bbd8 ); +PROVIDE ( r_lld_util_freq2chnl = 0x4004b9e4 ); +PROVIDE ( r_lld_util_get_bd_address = 0x4004b8ac ); +PROVIDE ( r_lld_util_get_local_offset = 0x4004ba10 ); +PROVIDE ( r_lld_util_get_peer_offset = 0x4004ba24 ); +PROVIDE ( r_lld_util_get_tx_pkt_cnt = 0x4004bd80 ); +PROVIDE ( r_lld_util_instant_get = 0x4004b890 ); +PROVIDE ( r_lld_util_instant_ongoing = 0x4004bbfc ); +PROVIDE ( r_lld_util_priority_set = 0x4004bd10 ); +PROVIDE ( r_lld_util_priority_update = 0x4004bd78 ); +PROVIDE ( r_lld_util_ral_force_rpa_renew = 0x4004b980 ); +PROVIDE ( r_lld_util_set_bd_address = 0x4004b8f8 ); +PROVIDE ( r_lld_wlcoex_set = 0x4004bd98 ); +PROVIDE ( r_llm_ble_ready = 0x4004cc34 ); +PROVIDE ( r_llm_common_cmd_complete_send = 0x4004d288 ); +PROVIDE ( r_llm_common_cmd_status_send = 0x4004d2b4 ); +PROVIDE ( r_llm_con_req_ind = 0x4004cc54 ); +PROVIDE ( r_llm_con_req_tx_cfm = 0x4004d158 ); +PROVIDE ( r_llm_create_con = 0x4004de78 ); +PROVIDE ( r_llm_encryption_done = 0x4004dff8 ); +PROVIDE ( r_llm_encryption_start = 0x4004e128 ); +PROVIDE ( r_llm_end_evt_defer = 0x4004eb6c ); +PROVIDE ( r_llm_init = 0x4004c9f8 ); +PROVIDE ( r_llm_le_adv_report_ind = 0x4004cdf4 ); +PROVIDE ( r_llm_pdu_defer = 0x4004ec48 ); +PROVIDE ( r_llm_ral_clear = 0x4004e1fc ); +PROVIDE ( r_llm_ral_dev_add = 0x4004e23c ); +PROVIDE ( r_llm_ral_dev_rm = 0x4004e3bc ); +PROVIDE ( r_llm_ral_get_rpa = 0x4004e400 ); +PROVIDE ( r_llm_ral_set_timeout = 0x4004e4a0 ); +PROVIDE ( r_llm_ral_update = 0x4004e4f8 ); +PROVIDE ( r_llm_set_adv_data = 0x4004d960 ); +PROVIDE ( r_llm_set_adv_en = 0x4004d7ec ); +PROVIDE ( r_llm_set_adv_param = 0x4004d5f4 ); +PROVIDE ( r_llm_set_scan_en = 0x4004db64 ); +PROVIDE ( r_llm_set_scan_param = 0x4004dac8 ); +PROVIDE ( r_llm_set_scan_rsp_data = 0x4004da14 ); +PROVIDE ( r_llm_test_mode_start_rx = 0x4004d534 ); +PROVIDE ( r_llm_test_mode_start_tx = 0x4004d2fc ); +PROVIDE ( r_llm_util_adv_data_update = 0x4004e8fc ); +PROVIDE ( r_llm_util_apply_bd_addr = 0x4004e868 ); +PROVIDE ( r_llm_util_bd_addr_in_ral = 0x4004eb08 ); +PROVIDE ( r_llm_util_bd_addr_in_wl = 0x4004e788 ); +PROVIDE ( r_llm_util_bd_addr_wl_position = 0x4004e720 ); +PROVIDE ( r_llm_util_bl_add = 0x4004e9ac ); +PROVIDE ( r_llm_util_bl_check = 0x4004e930 ); +PROVIDE ( r_llm_util_bl_rem = 0x4004ea70 ); +PROVIDE ( r_llm_util_check_address_validity = 0x4004e7e4 ); +PROVIDE ( r_llm_util_check_evt_mask = 0x4004e8b0 ); +PROVIDE ( r_llm_util_check_map_validity = 0x4004e800 ); +PROVIDE ( r_llm_util_get_channel_map = 0x4004e8d4 ); +PROVIDE ( r_llm_util_get_supp_features = 0x4004e8e8 ); +PROVIDE ( r_llm_util_set_public_addr = 0x4004e89c ); +PROVIDE ( r_llm_wl_clr = 0x4004dc54 ); +PROVIDE ( r_llm_wl_dev_add = 0x4004dcc0 ); +PROVIDE ( r_llm_wl_dev_add_hdl = 0x4004dd38 ); +PROVIDE ( r_llm_wl_dev_rem = 0x4004dcfc ); +PROVIDE ( r_llm_wl_dev_rem_hdl = 0x4004dde0 ); +PROVIDE ( r_lm_acl_disc = 0x4004f148 ); +PROVIDE ( r_LM_AddSniff = 0x40022d20 ); +PROVIDE ( r_lm_add_sync = 0x40051358 ); +PROVIDE ( r_lm_afh_activate_timer = 0x4004f444 ); +PROVIDE ( r_lm_afh_ch_ass_en_get = 0x4004f3f8 ); +PROVIDE ( r_lm_afh_host_ch_class_get = 0x4004f410 ); +PROVIDE ( r_lm_afh_master_ch_map_get = 0x4004f43c ); +PROVIDE ( r_lm_afh_peer_ch_class_set = 0x4004f418 ); +PROVIDE ( r_lm_check_active_sync = 0x40051334 ); +PROVIDE ( r_LM_CheckEdrFeatureRequest = 0x4002f90c ); +PROVIDE ( r_LM_CheckSwitchInstant = 0x4002f8c0 ); +PROVIDE ( r_lm_check_sync_hl_rsp = 0x4005169c ); +PROVIDE ( r_lm_clk_adj_ack_pending_clear = 0x4004f514 ); +PROVIDE ( r_lm_clk_adj_instant_pending_set = 0x4004f4d8 ); +PROVIDE ( r_LM_ComputePacketType = 0x4002f554 ); +PROVIDE ( r_LM_ComputeSniffSubRate = 0x400233ac ); +PROVIDE ( r_lm_debug_key_compare_192 = 0x4004f3a8 ); +PROVIDE ( r_lm_debug_key_compare_256 = 0x4004f3d0 ); +PROVIDE ( r_lm_dhkey_calc_init = 0x40013234 ); +PROVIDE ( r_lm_dhkey_compare = 0x400132d8 ); +PROVIDE ( r_lm_dut_mode_en_get = 0x4004f3ec ); +PROVIDE ( r_LM_ExtractMaxEncKeySize = 0x4001aca4 ); +PROVIDE ( r_lm_f1 = 0x40012bb8 ); +PROVIDE ( r_lm_f2 = 0x40012cfc ); +PROVIDE ( r_lm_f3 = 0x40013050 ); +PROVIDE ( r_lm_g = 0x40012f90 ); +PROVIDE ( r_LM_GetAFHSwitchInstant = 0x4002f86c ); +PROVIDE ( r_lm_get_auth_en = 0x4004f1ac ); +PROVIDE ( r_lm_get_common_pkt_types = 0x4002fa1c ); +PROVIDE ( r_LM_GetConnectionAcceptTimeout = 0x4004f1f4 ); +PROVIDE ( r_LM_GetFeature = 0x4002f924 ); +PROVIDE ( r_LM_GetLinkTimeout = 0x400233ec ); +PROVIDE ( r_LM_GetLocalNameSeg = 0x4004f200 ); +PROVIDE ( r_lm_get_loopback_mode = 0x4004f248 ); +PROVIDE ( r_LM_GetMasterEncKeySize = 0x4001b29c ); +PROVIDE ( r_LM_GetMasterEncRand = 0x4001b288 ); +PROVIDE ( r_LM_GetMasterKey = 0x4001b260 ); +PROVIDE ( r_LM_GetMasterKeyRand = 0x4001b274 ); +PROVIDE ( r_lm_get_min_sync_intv = 0x400517a8 ); +PROVIDE ( r_lm_get_nb_acl = 0x4004ef9c ); +PROVIDE ( r_lm_get_nb_sync_link = 0x4005179c ); +PROVIDE ( r_lm_get_nonce = 0x400131c4 ); +PROVIDE ( r_lm_get_oob_local_commit = 0x4004f374 ); +PROVIDE ( r_lm_get_oob_local_data_192 = 0x4004f2d4 ); +PROVIDE ( r_lm_get_oob_local_data_256 = 0x4004f318 ); +PROVIDE ( r_LM_GetPINType = 0x4004f1e8 ); +PROVIDE ( r_lm_get_priv_key_192 = 0x4004f278 ); +PROVIDE ( r_lm_get_priv_key_256 = 0x4004f2b8 ); +PROVIDE ( r_lm_get_pub_key_192 = 0x4004f258 ); +PROVIDE ( r_lm_get_pub_key_256 = 0x4004f298 ); +PROVIDE ( r_LM_GetQoSParam = 0x4002f6e0 ); +PROVIDE ( r_lm_get_sec_con_host_supp = 0x4004f1d4 ); +PROVIDE ( r_LM_GetSniffSubratingParam = 0x4002325c ); +PROVIDE ( r_lm_get_sp_en = 0x4004f1c0 ); +PROVIDE ( r_LM_GetSwitchInstant = 0x4002f7f8 ); +PROVIDE ( r_lm_get_synchdl = 0x4005175c ); +PROVIDE ( r_lm_get_sync_param = 0x400503b4 ); +PROVIDE ( r_lm_init = 0x4004ed34 ); +PROVIDE ( r_lm_init_sync = 0x400512d8 ); +PROVIDE ( r_lm_is_acl_con = 0x4004f47c ); +PROVIDE ( r_lm_is_acl_con_role = 0x4004f49c ); +PROVIDE ( r_lm_is_clk_adj_ack_pending = 0x4004f4e8 ); +PROVIDE ( r_lm_is_clk_adj_instant_pending = 0x4004f4c8 ); +PROVIDE ( r_lm_local_ext_fr_configured = 0x4004f540 ); +PROVIDE ( r_lm_look_for_stored_link_key = 0x4002f948 ); +PROVIDE ( r_lm_look_for_sync = 0x40051774 ); +PROVIDE ( r_lm_lt_addr_alloc = 0x4004ef1c ); +PROVIDE ( r_lm_lt_addr_free = 0x4004ef74 ); +PROVIDE ( r_lm_lt_addr_reserve = 0x4004ef48 ); +PROVIDE ( r_LM_MakeCof = 0x4002f84c ); +PROVIDE ( r_LM_MakeRandVec = 0x400112d8 ); +PROVIDE ( r_lm_master_clk_adj_req_handler = 0x40054180 ); +PROVIDE ( r_LM_MaxSlot = 0x4002f694 ); +PROVIDE ( r_lm_modif_sync = 0x40051578 ); +PROVIDE ( r_lm_n_is_zero = 0x40012170 ); +PROVIDE ( r_lm_num_clk_adj_ack_pending_set = 0x4004f500 ); +PROVIDE ( r_lm_oob_f1 = 0x40012e54 ); +PROVIDE ( r_lm_pca_sscan_link_get = 0x4004f560 ); +PROVIDE ( r_lm_pca_sscan_link_set = 0x4004f550 ); +PROVIDE ( r_lmp_pack = 0x4001135c ); +PROVIDE ( r_lmp_unpack = 0x4001149c ); +PROVIDE ( r_lm_read_features = 0x4004f0d8 ); +PROVIDE ( r_LM_RemoveSniff = 0x40023124 ); +PROVIDE ( r_LM_RemoveSniffSubrating = 0x400233c4 ); +PROVIDE ( r_lm_remove_sync = 0x400517c8 ); +PROVIDE ( r_lm_reset_sync = 0x40051304 ); +PROVIDE ( r_lm_role_switch_finished = 0x4004f028 ); +PROVIDE ( r_lm_role_switch_start = 0x4004efe0 ); +PROVIDE ( r_lm_sco_nego_end = 0x40051828 ); +PROVIDE ( r_LM_SniffSubrateNegoRequired = 0x40023334 ); +PROVIDE ( r_LM_SniffSubratingHlReq = 0x40023154 ); +PROVIDE ( r_LM_SniffSubratingPeerReq = 0x400231dc ); +PROVIDE ( r_lm_sp_debug_mode_get = 0x4004f398 ); +PROVIDE ( r_lm_sp_n192_convert_wnaf = 0x400123c0 ); +PROVIDE ( r_lm_sp_n_one = 0x400123a4 ); +PROVIDE ( r_lm_sp_p192_add = 0x40012828 ); +PROVIDE ( r_lm_sp_p192_dbl = 0x4001268c ); +PROVIDE ( r_lm_sp_p192_invert = 0x40012b6c ); +PROVIDE ( r_lm_sp_p192_point_jacobian_to_affine = 0x40012468 ); +PROVIDE ( r_lm_sp_p192_points_jacobian_to_affine = 0x400124e4 ); +PROVIDE ( r_lm_sp_p192_point_to_inf = 0x40012458 ); +PROVIDE ( r_lm_sp_pre_compute_points = 0x40012640 ); +PROVIDE ( r_lm_sp_sha256_calculate = 0x400121a0 ); +PROVIDE ( r_LM_SuppressAclPacket = 0x4002f658 ); +PROVIDE ( r_lm_sync_flow_ctrl_en_get = 0x4004f404 ); +PROVIDE ( r_LM_UpdateAclEdrPacketType = 0x4002f5d8 ); +PROVIDE ( r_LM_UpdateAclPacketType = 0x4002f584 ); +PROVIDE ( r_modules_funcs = 0x3ffafd6c ); +PROVIDE ( r_modules_funcs_p = 0x3ffafd68 ); +PROVIDE ( r_nvds_del = 0x400544c4 ); +PROVIDE ( r_nvds_get = 0x40054488 ); +PROVIDE ( r_nvds_init = 0x40054410 ); +PROVIDE ( r_nvds_lock = 0x400544fc ); +PROVIDE ( r_nvds_put = 0x40054534 ); +PROVIDE ( rom_abs_temp = 0x400054f0 ); +PROVIDE ( rom_bb_bss_bw_40_en = 0x4000401c ); +PROVIDE ( rom_bb_bss_cbw40_dig = 0x40003bac ); +PROVIDE ( rom_bb_rx_ht20_cen_bcov_en = 0x40003734 ); +PROVIDE ( rom_bb_tx_ht20_cen = 0x40003760 ); +PROVIDE ( rom_bb_wdg_test_en = 0x40003b70 ); +PROVIDE ( rom_cbw2040_cfg = 0x400040b0 ); +PROVIDE ( rom_check_noise_floor = 0x40003c78 ); +PROVIDE ( rom_chip_i2c_readReg = 0x40004110 ); +PROVIDE ( rom_chip_i2c_writeReg = 0x40004168 ); +PROVIDE ( rom_chip_v7_bt_init = 0x40004d8c ); +PROVIDE ( rom_chip_v7_rx_init = 0x40004cec ); +PROVIDE ( rom_chip_v7_rx_rifs_en = 0x40003d90 ); +PROVIDE ( rom_chip_v7_tx_init = 0x40004d18 ); +PROVIDE ( rom_clk_force_on_vit = 0x40003710 ); +PROVIDE ( rom_correct_rf_ana_gain = 0x400062a8 ); +PROVIDE ( rom_dc_iq_est = 0x400055c8 ); +PROVIDE ( rom_disable_agc = 0x40002fa4 ); +PROVIDE ( rom_enable_agc = 0x40002fcc ); +PROVIDE ( rom_en_pwdet = 0x4000506c ); +PROVIDE ( rom_gen_rx_gain_table = 0x40003e3c ); +PROVIDE ( rom_get_data_sat = 0x4000312c ); +PROVIDE ( rom_get_fm_sar_dout = 0x40005204 ); +PROVIDE ( rom_get_power_db = 0x40005fc8 ); +PROVIDE ( rom_get_pwctrl_correct = 0x400065d4 ); +PROVIDE ( rom_get_rfcal_rxiq_data = 0x40005bbc ); +PROVIDE ( rom_get_rf_gain_qdb = 0x40006290 ); +PROVIDE ( rom_get_sar_dout = 0x40006564 ); +PROVIDE ( rom_i2c_readReg = 0x40004148 ); +PROVIDE ( rom_i2c_readReg_Mask = 0x400041c0 ); +PROVIDE ( rom_i2c_writeReg = 0x400041a4 ); +PROVIDE ( rom_i2c_writeReg_Mask = 0x400041fc ); +PROVIDE ( rom_index_to_txbbgain = 0x40004df8 ); +PROVIDE ( rom_iq_est_disable = 0x40005590 ); +PROVIDE ( rom_iq_est_enable = 0x40005514 ); +PROVIDE ( rom_linear_to_db = 0x40005f64 ); +PROVIDE ( rom_loopback_mode_en = 0x400030f8 ); +PROVIDE ( rom_main = 0x400076c4 ); +PROVIDE ( rom_meas_tone_pwr_db = 0x40006004 ); +PROVIDE ( rom_mhz2ieee = 0x4000404c ); +PROVIDE ( rom_noise_floor_auto_set = 0x40003bdc ); +PROVIDE ( rom_pbus_debugmode = 0x40004458 ); +PROVIDE ( rom_pbus_force_mode = 0x40004270 ); +PROVIDE ( rom_pbus_force_test = 0x400043c0 ); +PROVIDE ( rom_pbus_rd = 0x40004414 ); +PROVIDE ( rom_pbus_rd_addr = 0x40004334 ); +PROVIDE ( rom_pbus_rd_shift = 0x40004374 ); +PROVIDE ( rom_pbus_rx_dco_cal = 0x40005620 ); +PROVIDE ( rom_pbus_set_dco = 0x40004638 ); +PROVIDE ( rom_pbus_set_rxgain = 0x40004480 ); +PROVIDE ( rom_pbus_workmode = 0x4000446c ); +PROVIDE ( rom_pbus_xpd_rx_off = 0x40004508 ); +PROVIDE ( rom_pbus_xpd_rx_on = 0x4000453c ); +PROVIDE ( rom_pbus_xpd_tx_off = 0x40004590 ); +PROVIDE ( rom_pbus_xpd_tx_on = 0x400045e0 ); +PROVIDE ( rom_phy_disable_agc = 0x40002f6c ); +PROVIDE ( rom_phy_disable_cca = 0x40003000 ); +PROVIDE ( rom_phy_enable_agc = 0x40002f88 ); +PROVIDE ( rom_phy_enable_cca = 0x4000302c ); +PROVIDE ( rom_phy_freq_correct = 0x40004b44 ); +PROVIDE ( rom_phyFuns = 0x3ffae0c0 ); +PROVIDE ( rom_phy_get_noisefloor = 0x40003c2c ); +PROVIDE ( rom_phy_get_vdd33 = 0x4000642c ); +PROVIDE ( rom_pow_usr = 0x40003044 ); +PROVIDE ( rom_read_sar_dout = 0x400051c0 ); +PROVIDE ( rom_restart_cal = 0x400046e0 ); +PROVIDE ( rom_rfcal_pwrctrl = 0x40006058 ); +PROVIDE ( rom_rfcal_rxiq = 0x40005b4c ); +PROVIDE ( rom_rfcal_txcap = 0x40005dec ); +PROVIDE ( rom_rfpll_reset = 0x40004680 ); +PROVIDE ( rom_rfpll_set_freq = 0x400047f8 ); +PROVIDE ( rom_rtc_mem_backup = 0x40003db4 ); +PROVIDE ( rom_rtc_mem_recovery = 0x40003df4 ); +PROVIDE ( rom_rx_gain_force = 0x4000351c ); +PROVIDE ( rom_rxiq_cover_mg_mp = 0x40005a68 ); +PROVIDE ( rom_rxiq_get_mis = 0x400058e4 ); +PROVIDE ( rom_rxiq_set_reg = 0x40005a00 ); +PROVIDE ( rom_set_cal_rxdc = 0x400030b8 ); +PROVIDE ( rom_set_chan_cal_interp = 0x40005ce0 ); +PROVIDE ( rom_set_channel_freq = 0x40004880 ); +PROVIDE ( rom_set_loopback_gain = 0x40003060 ); +PROVIDE ( rom_set_noise_floor = 0x40003d48 ); +PROVIDE ( rom_set_pbus_mem = 0x400031a4 ); +PROVIDE ( rom_set_rf_freq_offset = 0x40004ca8 ); +PROVIDE ( rom_set_rxclk_en = 0x40003594 ); +PROVIDE ( rom_set_txcap_reg = 0x40005d50 ); +PROVIDE ( rom_set_txclk_en = 0x40003564 ); +PROVIDE ( rom_spur_coef_cfg = 0x40003ac8 ); +PROVIDE ( rom_spur_reg_write_one_tone = 0x400037f0 ); +PROVIDE ( rom_start_tx_tone = 0x400036b4 ); +PROVIDE ( rom_start_tx_tone_step = 0x400035d0 ); +PROVIDE ( rom_stop_tx_tone = 0x40003f98 ); +PROVIDE ( _rom_store = 0x4000d66c ); +PROVIDE ( _rom_store_table = 0x4000d4f8 ); +PROVIDE ( rom_target_power_add_backoff = 0x40006268 ); +PROVIDE ( rom_tx_atten_set_interp = 0x400061cc ); +PROVIDE ( rom_txbbgain_to_index = 0x40004dc0 ); +PROVIDE ( rom_txcal_work_mode = 0x4000510c ); +PROVIDE ( rom_txdc_cal_init = 0x40004e10 ); +PROVIDE ( rom_txdc_cal_v70 = 0x40004ea4 ); +PROVIDE ( rom_txiq_cover = 0x4000538c ); +PROVIDE ( rom_txiq_get_mis_pwr = 0x400052dc ); +PROVIDE ( rom_txiq_set_reg = 0x40005154 ); +PROVIDE ( rom_tx_pwctrl_bg_init = 0x4000662c ); +PROVIDE ( rom_txtone_linear_pwr = 0x40005290 ); +PROVIDE ( rom_wait_rfpll_cal_end = 0x400047a8 ); +PROVIDE ( rom_write_gain_mem = 0x4000348c ); +PROVIDE ( rom_write_rfpll_sdm = 0x40004740 ); +PROVIDE ( roundup2 = 0x4000ab7c ); +PROVIDE ( r_plf_funcs_p = 0x3ffb8360 ); +PROVIDE ( r_rf_rw_bt_init = 0x40054868 ); +PROVIDE ( r_rf_rw_init = 0x40054b0c ); +PROVIDE ( r_rf_rw_le_init = 0x400549d0 ); +PROVIDE ( r_rwble_activity_ongoing_check = 0x40054d8c ); +PROVIDE ( r_rwble_init = 0x40054bf4 ); +PROVIDE ( r_rwble_isr = 0x40054e08 ); +PROVIDE ( r_rwble_reset = 0x40054ce8 ); +PROVIDE ( r_rwble_sleep_check = 0x40054d78 ); +PROVIDE ( r_rwble_version = 0x40054dac ); +PROVIDE ( r_rwbt_init = 0x40055160 ); +PROVIDE ( r_rwbt_isr = 0x40055248 ); +PROVIDE ( r_rwbt_reset = 0x400551bc ); +PROVIDE ( r_rwbt_sleep_check = 0x4005577c ); +PROVIDE ( r_rwbt_sleep_enter = 0x400557a4 ); +PROVIDE ( r_rwbt_sleep_wakeup = 0x400557fc ); +PROVIDE ( r_rwbt_sleep_wakeup_end = 0x400558cc ); +PROVIDE ( r_rwbt_version = 0x4005520c ); +PROVIDE ( r_rwip_assert_err = 0x40055f88 ); +PROVIDE ( r_rwip_check_wakeup_boundary = 0x400558fc ); +PROVIDE ( r_rwip_ext_wakeup_enable = 0x40055f3c ); +PROVIDE ( r_rwip_init = 0x4005595c ); +PROVIDE ( r_rwip_pca_clock_dragging_only = 0x40055f48 ); +PROVIDE ( r_rwip_prevent_sleep_clear = 0x40055ec8 ); +PROVIDE ( r_rwip_prevent_sleep_set = 0x40055e64 ); +PROVIDE ( r_rwip_reset = 0x40055ab8 ); +PROVIDE ( r_rwip_schedule = 0x40055b38 ); +PROVIDE ( r_rwip_sleep = 0x40055b5c ); +PROVIDE ( r_rwip_sleep_enable = 0x40055f30 ); +PROVIDE ( r_rwip_version = 0x40055b20 ); +PROVIDE ( r_rwip_wakeup = 0x40055dc4 ); +PROVIDE ( r_rwip_wakeup_delay_set = 0x40055e4c ); +PROVIDE ( r_rwip_wakeup_end = 0x40055e18 ); +PROVIDE ( r_rwip_wlcoex_set = 0x40055f60 ); +PROVIDE ( r_SHA_256 = 0x40013a90 ); +PROVIDE ( rtc_boot_control = 0x4000821c ); +PROVIDE ( rtc_get_reset_reason = 0x400081d4 ); +PROVIDE ( rtc_get_wakeup_cause = 0x400081f4 ); +PROVIDE ( rtc_select_apb_bridge = 0x40008288 ); +PROVIDE ( rwip_coex_cfg = 0x3ff9914c ); +PROVIDE ( rwip_priority = 0x3ff99159 ); +PROVIDE ( rwip_rf = 0x3ffbdb28 ); +PROVIDE ( rwip_rf_p_get = 0x400558f4 ); +PROVIDE ( r_XorKey = 0x400112c0 ); +PROVIDE ( sbrk = 0x400017f4 ); +PROVIDE ( _sbrk_r = 0x4000bce4 ); +PROVIDE ( __sccl = 0x4000c498 ); +PROVIDE ( __sclose = 0x400011b8 ); +PROVIDE ( SelectSpiFunction = 0x40061f84 ); +PROVIDE ( SelectSpiQIO = 0x40061ddc ); +PROVIDE ( SendMsg = 0x40009384 ); +PROVIDE ( send_packet = 0x40009340 ); +PROVIDE ( __seofread = 0x40001148 ); +PROVIDE ( setjmp = 0x40056268 ); +PROVIDE ( setlocale = 0x40059568 ); +PROVIDE ( _setlocale_r = 0x4005950c ); +PROVIDE ( set_rtc_memory_crc = 0x40008208 ); +PROVIDE ( SetSpiDrvs = 0x40061e78 ); +PROVIDE ( __sf_fake_stderr = 0x3ff96458 ); +PROVIDE ( __sf_fake_stdin = 0x3ff96498 ); +PROVIDE ( __sf_fake_stdout = 0x3ff96478 ); +PROVIDE ( __sflush_r = 0x400591e0 ); +PROVIDE ( __sfmoreglue = 0x40001dc8 ); +PROVIDE ( __sfp = 0x40001e90 ); +PROVIDE ( __sfp_lock_acquire = 0x40001e08 ); +PROVIDE ( __sfp_lock_release = 0x40001e14 ); +PROVIDE ( __sfputs_r = 0x40057790 ); +PROVIDE ( __sfvwrite_r = 0x4005893c ); +PROVIDE ( sha1_prf = 0x40060ae8 ); +PROVIDE ( sha1_vector = 0x40060b64 ); +PROVIDE ( sha256_prf = 0x40060d70 ); +PROVIDE ( sha256_vector = 0x40060e08 ); +PROVIDE ( sha_blk_bits = 0x3ff99290 ); +PROVIDE ( sha_blk_bits_bytes = 0x3ff99288 ); +PROVIDE ( sha_blk_hash_bytes = 0x3ff9928c ); +PROVIDE ( sig_matrix = 0x3ffae293 ); +PROVIDE ( __sinit = 0x40001e38 ); +PROVIDE ( __sinit_lock_acquire = 0x40001e20 ); +PROVIDE ( __sinit_lock_release = 0x40001e2c ); +PROVIDE ( sip_after_tx_complete = 0x4000b358 ); +PROVIDE ( sip_alloc_to_host_evt = 0x4000ab9c ); +PROVIDE ( sip_get_ptr = 0x4000b34c ); +PROVIDE ( sip_get_state = 0x4000ae2c ); +PROVIDE ( sip_init_attach = 0x4000ae58 ); +PROVIDE ( sip_install_rx_ctrl_cb = 0x4000ae10 ); +PROVIDE ( sip_install_rx_data_cb = 0x4000ae20 ); +PROVIDE ( sip_is_active = 0x4000b3c0 ); +PROVIDE ( sip_post_init = 0x4000aed8 ); +PROVIDE ( sip_reclaim_from_host_cmd = 0x4000adbc ); +PROVIDE ( sip_reclaim_tx_data_pkt = 0x4000ad5c ); +PROVIDE ( sip_send = 0x4000af54 ); +PROVIDE ( sip_to_host_chain_append = 0x4000aef8 ); +PROVIDE ( sip_to_host_evt_send_done = 0x4000ac04 ); +PROVIDE ( slc_add_credits = 0x4000baf4 ); +PROVIDE ( slc_enable = 0x4000b64c ); +PROVIDE ( slc_from_host_chain_fetch = 0x4000b7e8 ); +PROVIDE ( slc_from_host_chain_recycle = 0x4000bb10 ); +PROVIDE ( slc_has_pkt_to_host = 0x4000b5fc ); +PROVIDE ( slc_init_attach = 0x4000b918 ); +PROVIDE ( slc_init_credit = 0x4000badc ); +PROVIDE ( slc_reattach = 0x4000b62c ); +PROVIDE ( slc_send_to_host_chain = 0x4000b6a0 ); +PROVIDE ( slc_set_host_io_max_window = 0x4000b89c ); +PROVIDE ( slc_to_host_chain_recycle = 0x4000b758 ); +PROVIDE ( __smakebuf_r = 0x40059108 ); +PROVIDE ( software_reset = 0x4000824c ); +PROVIDE ( software_reset_cpu = 0x40008264 ); +PROVIDE ( specialModP256 = 0x4001600c ); +PROVIDE ( spi_cache_sram_init = 0x400626e4 ); +PROVIDE ( SPIClkConfig = 0x40062bc8 ); +PROVIDE ( SPI_Common_Command = 0x4006246c ); +PROVIDE ( spi_dummy_len_fix = 0x40061d90 ); +PROVIDE ( SPI_Encrypt_Write = 0x40062e78 ); +PROVIDE ( SPIEraseArea = 0x400631ac ); +PROVIDE ( SPIEraseBlock = 0x40062c4c ); +PROVIDE ( SPIEraseChip = 0x40062c14 ); +PROVIDE ( SPIEraseSector = 0x40062ccc ); +PROVIDE ( spi_flash_attach = 0x40062a6c ); +/* NB: SPIUnlock @ 0x400628b0 has been replaced with an updated + version in the "spi_flash" component */ +PROVIDE ( SPILock = 0x400628f0 ); +PROVIDE ( SPIMasterReadModeCnfig = 0x40062b64 ); +PROVIDE ( spi_modes = 0x3ff99270 ); +PROVIDE ( SPIParamCfg = 0x40063238 ); +PROVIDE ( SPI_Prepare_Encrypt_Data = 0x40062e1c ); +PROVIDE ( SPIRead = 0x40062ed8 ); +PROVIDE ( SPIReadModeCnfig = 0x40062944 ); +/* This is static function, but can be used, not generated by script*/ +PROVIDE ( SPI_read_status = 0x4006226c ); +/* This is static function, but can be used, not generated by script*/ +PROVIDE ( SPI_read_status_high = 0x40062448 ); +PROVIDE ( SPI_user_command_read = 0x400621b0 ); +PROVIDE ( SPI_flashchip_data = 0x3ffae270 ); +PROVIDE ( SPIWrite = 0x40062d50 ); +/* This is static function, but can be used, not generated by script*/ +PROVIDE ( SPI_write_enable = 0x40062320 ); +PROVIDE ( SPI_Write_Encrypt_Disable = 0x40062e60 ); +PROVIDE ( SPI_Write_Encrypt_Enable = 0x40062df4 ); +/* This is static function, but can be used, not generated by script*/ +PROVIDE ( SPI_write_status = 0x400622f0 ); +PROVIDE ( srand = 0x40001004 ); +PROVIDE ( __sread = 0x40001118 ); +PROVIDE ( __srefill_r = 0x400593d4 ); +PROVIDE ( __sseek = 0x40001184 ); +PROVIDE ( __ssprint_r = 0x40056ff8 ); +PROVIDE ( __ssputs_r = 0x40056f2c ); +PROVIDE ( __ssrefill_r = 0x40057fec ); +PROVIDE ( __stack = 0x3ffe3f20 ); +PROVIDE ( __stack_app = 0x3ffe7e30 ); +PROVIDE ( _stack_sentry = 0x3ffe1320 ); +PROVIDE ( _stack_sentry_app = 0x3ffe5230 ); +PROVIDE ( _start = 0x40000704 ); +PROVIDE ( start_tb_console = 0x4005a980 ); +PROVIDE ( _stat_r = 0x4000bcb4 ); +PROVIDE ( _stext = 0x40000560 ); +PROVIDE ( strcasecmp = 0x400011cc ); +PROVIDE ( strcasestr = 0x40001210 ); +PROVIDE ( strcat = 0x4000c518 ); +PROVIDE ( strchr = 0x4000c53c ); +PROVIDE ( strcmp = 0x40001274 ); +PROVIDE ( strcoll = 0x40001398 ); +PROVIDE ( strcpy = 0x400013ac ); +PROVIDE ( strcspn = 0x4000c558 ); +PROVIDE ( strdup = 0x4000143c ); +PROVIDE ( _strdup_r = 0x40001450 ); +PROVIDE ( strftime = 0x40059ab4 ); +PROVIDE ( strlcat = 0x40001470 ); +PROVIDE ( strlcpy = 0x4000c584 ); +PROVIDE ( strlen = 0x400014c0 ); +PROVIDE ( strlwr = 0x40001524 ); +PROVIDE ( strncasecmp = 0x40001550 ); +PROVIDE ( strncat = 0x4000c5c4 ); +PROVIDE ( strncmp = 0x4000c5f4 ); +PROVIDE ( strncpy = 0x400015d4 ); +PROVIDE ( strndup = 0x400016b0 ); +PROVIDE ( _strndup_r = 0x400016c4 ); +PROVIDE ( strnlen = 0x4000c628 ); +PROVIDE ( strrchr = 0x40001708 ); +PROVIDE ( strsep = 0x40001734 ); +PROVIDE ( strspn = 0x4000c648 ); +PROVIDE ( strstr = 0x4000c674 ); +PROVIDE ( __strtok_r = 0x4000c6a8 ); +PROVIDE ( strtok_r = 0x4000c70c ); +PROVIDE ( strtol = 0x4005681c ); +PROVIDE ( _strtol_r = 0x40056714 ); +PROVIDE ( strtoul = 0x4005692c ); +PROVIDE ( _strtoul_r = 0x40056834 ); +PROVIDE ( strupr = 0x4000174c ); +PROVIDE ( __subdf3 = 0x400026e4 ); +PROVIDE ( __submore = 0x40058f3c ); +PROVIDE ( __subsf3 = 0x400021d0 ); +PROVIDE ( SubtractBigHex256 = 0x40015bcc ); +PROVIDE ( SubtractBigHexMod256 = 0x40015e8c ); +PROVIDE ( SubtractBigHexUint32_256 = 0x40015f8c ); +PROVIDE ( SubtractFromSelfBigHex256 = 0x40015c20 ); +PROVIDE ( SubtractFromSelfBigHexSign256 = 0x40015dc8 ); +PROVIDE ( __subvdi3 = 0x40002d20 ); +PROVIDE ( __subvsi3 = 0x40002cf8 ); +PROVIDE ( _sungetc_r = 0x40057f6c ); +PROVIDE ( __swbuf = 0x40058cb4 ); +PROVIDE ( __swbuf_r = 0x40058bec ); +PROVIDE ( __swrite = 0x40001150 ); +PROVIDE ( __swsetup_r = 0x40058cc8 ); +PROVIDE ( sw_to_hw = 0x3ffb8d40 ); +PROVIDE ( _SyscallException = 0x400007cf ); +PROVIDE ( syscall_table_ptr_app = 0x3ffae020 ); +PROVIDE ( syscall_table_ptr_pro = 0x3ffae024 ); +PROVIDE ( _system_r = 0x4000bc10 ); +PROVIDE ( tdefl_compress = 0x400600bc ); +PROVIDE ( tdefl_compress_buffer = 0x400607f4 ); +PROVIDE ( tdefl_compress_mem_to_mem = 0x40060900 ); +PROVIDE ( tdefl_compress_mem_to_output = 0x400608e0 ); +PROVIDE ( tdefl_get_adler32 = 0x400608d8 ); +PROVIDE ( tdefl_get_prev_return_status = 0x400608d0 ); +PROVIDE ( tdefl_init = 0x40060810 ); +PROVIDE ( tdefl_write_image_to_png_file_in_memory = 0x4006091c ); +PROVIDE ( tdefl_write_image_to_png_file_in_memory_ex = 0x40060910 ); +PROVIDE ( time = 0x40001844 ); +PROVIDE ( __time_load_locale = 0x4000183c ); +PROVIDE ( times = 0x40001808 ); +PROVIDE ( _times_r = 0x4000bc40 ); +PROVIDE ( _timezone = 0x3ffae0a0 ); +PROVIDE ( tinfl_decompress = 0x4005ef30 ); +PROVIDE ( tinfl_decompress_mem_to_callback = 0x40060090 ); +PROVIDE ( tinfl_decompress_mem_to_mem = 0x40060050 ); +PROVIDE ( toascii = 0x4000c720 ); +PROVIDE ( tolower = 0x40001868 ); +PROVIDE ( toupper = 0x40001884 ); +PROVIDE ( __truncdfsf2 = 0x40002b90 ); +PROVIDE ( __tzcalc_limits = 0x400018a0 ); +PROVIDE ( __tz_lock = 0x40001a04 ); +PROVIDE ( _tzname = 0x3ffae030 ); +PROVIDE ( tzset = 0x40001a1c ); +PROVIDE ( _tzset_r = 0x40001a28 ); +PROVIDE ( __tz_unlock = 0x40001a10 ); +PROVIDE ( uartAttach = 0x40008fd0 ); +PROVIDE ( uart_baudrate_detect = 0x40009034 ); +PROVIDE ( uart_buff_switch = 0x400093c0 ); +PROVIDE ( UartConnCheck = 0x40008738 ); +PROVIDE ( UartConnectProc = 0x40008a04 ); +PROVIDE ( UartDev = 0x3ffe019c ); +PROVIDE ( uart_div_modify = 0x400090cc ); +PROVIDE ( UartDwnLdProc = 0x40008ce8 ); +PROVIDE ( UartGetCmdLn = 0x40009564 ); +PROVIDE ( Uart_Init = 0x40009120 ); +PROVIDE ( UartRegReadProc = 0x40008a58 ); +PROVIDE ( UartRegWriteProc = 0x40008a14 ); +PROVIDE ( uart_rx_intr_handler = 0x40008f4c ); +PROVIDE ( uart_rx_one_char = 0x400092d0 ); +PROVIDE ( uart_rx_one_char_block = 0x400092a4 ); +PROVIDE ( uart_rx_readbuff = 0x40009394 ); +PROVIDE ( UartRxString = 0x400092fc ); +PROVIDE ( UartSetBaudProc = 0x40008aac ); +PROVIDE ( UartSpiAttachProc = 0x40008a6c ); +PROVIDE ( UartSpiReadProc = 0x40008a80 ); +PROVIDE ( uart_tx_flush = 0x40009258 ); +/*PROVIDE ( uart_tx_one_char = 0x40009200 );*/ +/* Note: remapping this to uart_tx_one_char2, to keep consistency */ +PROVIDE ( uart_tx_one_char = 0x4000922c ); +PROVIDE ( uart_tx_one_char2 = 0x4000922c ); +PROVIDE ( uart_tx_switch = 0x40009028 ); +PROVIDE ( uart_tx_wait_idle = 0x40009278 ); +PROVIDE ( __ucmpdi2 = 0x40063840 ); +PROVIDE ( __udivdi3 = 0x4000cff8 ); +PROVIDE ( __udivmoddi4 = 0x40064ab0 ); +PROVIDE ( __udivsi3 = 0x4000c7c8 ); +PROVIDE ( __udiv_w_sdiv = 0x40064aa8 ); +PROVIDE ( __umoddi3 = 0x4000d280 ); +PROVIDE ( __umodsi3 = 0x4000c7d0 ); +PROVIDE ( __umulsidi3 = 0x4000c7d8 ); +PROVIDE ( ungetc = 0x400590f4 ); +PROVIDE ( _ungetc_r = 0x40058fa0 ); +PROVIDE ( _unlink_r = 0x4000bc84 ); +PROVIDE ( __unorddf2 = 0x400637f4 ); +PROVIDE ( __unordsf2 = 0x40063478 ); +PROVIDE ( user_code_start = 0x3ffe0400 ); +PROVIDE ( _UserExceptionVector = 0x40000340 ); +PROVIDE ( utoa = 0x40056258 ); +PROVIDE ( __utoa = 0x400561f0 ); +PROVIDE ( VerifyFlashMd5Proc = 0x40008c44 ); +PROVIDE ( veryBigHexP256 = 0x3ff9736c ); +PROVIDE ( wcrtomb = 0x40058920 ); +PROVIDE ( _wcrtomb_r = 0x400588d8 ); +PROVIDE ( __wctomb = 0x3ff96540 ); +PROVIDE ( _wctomb_r = 0x40058f14 ); +PROVIDE ( _WindowOverflow12 = 0x40000100 ); +PROVIDE ( _WindowOverflow4 = 0x40000000 ); +PROVIDE ( _WindowOverflow8 = 0x40000080 ); +PROVIDE ( _WindowUnderflow12 = 0x40000140 ); +PROVIDE ( _WindowUnderflow4 = 0x40000040 ); +PROVIDE ( _WindowUnderflow8 = 0x400000c0 ); +PROVIDE ( write = 0x4000181c ); +PROVIDE ( _write_r = 0x4000bd70 ); +PROVIDE ( xthal_bcopy = 0x4000c098 ); +PROVIDE ( xthal_copy123 = 0x4000c124 ); +PROVIDE ( xthal_get_ccompare = 0x4000c078 ); +PROVIDE ( xthal_get_ccount = 0x4000c050 ); +PROVIDE ( xthal_get_interrupt = 0x4000c1e4 ); +PROVIDE ( xthal_get_intread = 0x4000c1e4 ); +PROVIDE ( Xthal_intlevel = 0x3ff9c2b4 ); +PROVIDE ( xthal_memcpy = 0x4000c0bc ); +PROVIDE ( xthal_set_ccompare = 0x4000c058 ); +PROVIDE ( xthal_set_intclear = 0x4000c1ec ); +PROVIDE ( _xtos_set_intlevel = 0x4000bfdc ); +PROVIDE ( _xtos_alloca_handler = 0x40000010 ); +PROVIDE ( _xtos_cause3_handler = 0x40000dd8 ); +PROVIDE ( _xtos_c_handler_table = 0x3ffe0548 ); +PROVIDE ( _xtos_c_wrapper_handler = 0x40000de8 ); +PROVIDE ( _xtos_enabled = 0x3ffe0650 ); +PROVIDE ( _xtos_exc_handler_table = 0x3ffe0448 ); +PROVIDE ( _xtos_interrupt_mask_table = 0x3ffe0758 ); +PROVIDE ( _xtos_interrupt_table = 0x3ffe0658 ); +PROVIDE ( _xtos_ints_off = 0x4000bfac ); +PROVIDE ( _xtos_ints_on = 0x4000bf88 ); +PROVIDE ( _xtos_intstruct = 0x3ffe0650 ); +PROVIDE ( _xtos_l1int_handler = 0x40000814 ); +PROVIDE ( _xtos_p_none = 0x4000bfd4 ); +PROVIDE ( _xtos_restore_intlevel = 0x40000928 ); +PROVIDE ( _xtos_return_from_exc = 0x4000c034 ); +PROVIDE ( _xtos_set_exception_handler = 0x4000074c ); +PROVIDE ( _xtos_set_interrupt_handler = 0x4000bf78 ); +PROVIDE ( _xtos_set_interrupt_handler_arg = 0x4000bf34 ); +PROVIDE ( _xtos_set_min_intlevel = 0x4000bff8 ); +PROVIDE ( _xtos_set_vpri = 0x40000934 ); +PROVIDE ( _xtos_syscall_handler = 0x40000790 ); +PROVIDE ( _xtos_unhandled_exception = 0x4000c024 ); +PROVIDE ( _xtos_unhandled_interrupt = 0x4000c01c ); +PROVIDE ( _xtos_vpri_enabled = 0x3ffe0654 ); +PROVIDE ( ets_intr_count = 0x3ffe03fc ); +PROVIDE ( ets_intr_lock = 0x400067b0 ); +PROVIDE ( ets_intr_unlock = 0x400067c4 ); +PROVIDE ( ets_isr_attach = 0x400067ec ); +PROVIDE ( ets_isr_mask = 0x400067fc ); +PROVIDE ( ets_isr_unmask = 0x40006808 ); +/* Following are static data, but can be used, not generated by script <<<<< btdm data */ +PROVIDE ( ld_acl_env = 0x3ffb8258 ); +PROVIDE ( ld_active_ch_map = 0x3ffb8334 ); +PROVIDE ( ld_bcst_acl_env = 0x3ffb8274 ); +PROVIDE ( ld_csb_rx_env = 0x3ffb8278 ); +PROVIDE ( ld_csb_tx_env = 0x3ffb827c ); +PROVIDE ( ld_env = 0x3ffb9510 ); +PROVIDE ( ld_fm_env = 0x3ffb8284 ); +PROVIDE ( ld_inq_env = 0x3ffb82e4 ); +PROVIDE ( ld_iscan_env = 0x3ffb82e8 ); +PROVIDE ( ld_page_env = 0x3ffb82f0 ); +PROVIDE ( ld_pca_env = 0x3ffb82f4 ); +PROVIDE ( ld_pscan_env = 0x3ffb8308 ); +PROVIDE ( ld_sched_env = 0x3ffb830c ); +PROVIDE ( ld_sched_params = 0x3ffb96c0 ); +PROVIDE ( ld_sco_env = 0x3ffb824c ); +PROVIDE ( ld_sscan_env = 0x3ffb832c ); +PROVIDE ( ld_strain_env = 0x3ffb8330 ); + + +PROVIDE ( esp_rom_spiflash_write_encrypted = 0x40062e78 ); +/* Above are static data, but can be used, not generated by script >>>>> btdm data */ diff --git a/tools/flasher_stub/ld/rom_32c2.ld b/tools/flasher_stub/ld/rom_32c2.ld new file mode 100755 index 0000000000..ae11364972 --- /dev/null +++ b/tools/flasher_stub/ld/rom_32c2.ld @@ -0,0 +1,2960 @@ +/* ROM function interface esp32c2.rom.ld for esp32c2 + * + * + * Generated from ./interface-esp8684.yml md5sum 6c4d0f3a9f2d0c93477024a1a8f13746 + * + * Compatible with ROM where ECO version equal or greater to 0. + * + * THIS FILE WAS AUTOMATICALLY GENERATED. DO NOT EDIT. + */ + +/*************************************** + Group common + ***************************************/ + +PROVIDE ( SPIWrite = esp_rom_spiflash_write); +PROVIDE ( SPI_read_status_high = esp_rom_spiflash_read_statushigh); +PROVIDE ( SPI_write_status = esp_rom_spiflash_write_status); +PROVIDE ( SPIRead = esp_rom_spiflash_read); +PROVIDE ( SPIParamCfg = esp_rom_spiflash_config_param); +PROVIDE ( SPIEraseChip = esp_rom_spiflash_erase_chip); +PROVIDE ( SPIEraseSector = esp_rom_spiflash_erase_sector); +PROVIDE ( SPIEraseBlock = esp_rom_spiflash_erase_block); +PROVIDE ( SPI_Write_Encrypt_Enable = esp_rom_spiflash_write_encrypted_enable); +PROVIDE ( SPI_Write_Encrypt_Disable = esp_rom_spiflash_write_encrypted_disable); +PROVIDE ( SPI_Encrypt_Write = esp_rom_spiflash_write_encrypted); + +PROVIDE ( mbedtls_md5_starts_ret = mbedtls_md5_starts_ret ); +PROVIDE ( mbedtls_md5_update_ret = mbedtls_md5_update_ret ); +PROVIDE ( mbedtls_md5_finish_ret = mbedtls_md5_finish_ret ); + +/*************************************** + Group common + ***************************************/ + +/* Functions */ +rtc_get_reset_reason = 0x40000018; +analog_super_wdt_reset_happened = 0x4000001c; +rtc_get_wakeup_cause = 0x40000020; +rtc_select_apb_bridge = 0x40000024; +rtc_unhold_all_pads = 0x40000028; +ets_is_print_boot = 0x4000002c; +ets_vprintf = 0x40000030; +ets_printf = 0x40000034; +ets_install_putc1 = 0x40000038; +ets_install_uart_printf = 0x4000003c; +ets_install_putc2 = 0x40000040; +PROVIDE( ets_delay_us = 0x40000044 ); +ets_get_stack_info = 0x40000048; +ets_install_lock = 0x4000004c; +UartRxString = 0x40000050; +UartGetCmdLn = 0x40000054; +uart_tx_one_char = 0x40000058; +uart_tx_one_char2 = 0x4000005c; +uart_rx_one_char = 0x40000060; +uart_rx_one_char_block = 0x40000064; +uart_rx_readbuff = 0x40000068; +uartAttach = 0x4000006c; +uart_tx_flush = 0x40000070; +uart_tx_wait_idle = 0x40000074; +uart_div_modify = 0x40000078; +ets_write_char_uart = 0x4000007c; +uart_tx_switch = 0x40000080; +multofup = 0x40000084; +software_reset = 0x40000088; +software_reset_cpu = 0x4000008c; +assist_debug_clock_enable = 0x40000090; +assist_debug_record_enable = 0x40000094; +clear_super_wdt_reset_flag = 0x40000098; +disable_default_watchdog = 0x4000009c; +send_packet = 0x400000a0; +recv_packet = 0x400000a4; +GetUartDevice = 0x400000a8; +UartDwnLdProc = 0x400000ac; +GetSecurityInfoProc = 0x400000b0; +Uart_Init = 0x400000b4; +ets_set_user_start = 0x400000b8; +/* Data (.data, .bss, .rodata) */ +ets_rom_layout_p = 0x3ff4fffc; +ets_ops_table_ptr = 0x3fcdfffc; + + +/*************************************** + Group miniz + ***************************************/ + +/* Functions */ +mz_adler32 = 0x400000bc; +mz_free = 0x400000c0; +tdefl_compress = 0x400000c4; +tdefl_compress_buffer = 0x400000c8; +tdefl_compress_mem_to_heap = 0x400000cc; +tdefl_compress_mem_to_mem = 0x400000d0; +tdefl_compress_mem_to_output = 0x400000d4; +tdefl_get_adler32 = 0x400000d8; +tdefl_get_prev_return_status = 0x400000dc; +tdefl_init = 0x400000e0; +tdefl_write_image_to_png_file_in_memory = 0x400000e4; +tdefl_write_image_to_png_file_in_memory_ex = 0x400000e8; +tinfl_decompress = 0x400000ec; +tinfl_decompress_mem_to_callback = 0x400000f0; +tinfl_decompress_mem_to_heap = 0x400000f4; +tinfl_decompress_mem_to_mem = 0x400000f8; + + +/*************************************** + Group spiflash_legacy + ***************************************/ + +/* Functions */ +PROVIDE( esp_rom_spiflash_wait_idle = 0x400000fc ); +PROVIDE( esp_rom_spiflash_write_encrypted = 0x40000100 ); +PROVIDE( esp_rom_spiflash_write_encrypted_dest = 0x40000104 ); +PROVIDE( esp_rom_spiflash_write_encrypted_enable = 0x40000108 ); +PROVIDE( esp_rom_spiflash_write_encrypted_disable = 0x4000010c ); +PROVIDE( esp_rom_spiflash_erase_chip = 0x40000110 ); +PROVIDE( _esp_rom_spiflash_erase_sector = 0x40000114 ); +PROVIDE( _esp_rom_spiflash_erase_block = 0x40000118 ); +PROVIDE( _esp_rom_spiflash_write = 0x4000011c ); +PROVIDE( _esp_rom_spiflash_read = 0x40000120 ); +PROVIDE( _esp_rom_spiflash_unlock = 0x40000124 ); +PROVIDE( _SPIEraseArea = 0x40000128 ); +PROVIDE( _SPI_write_enable = 0x4000012c ); +PROVIDE( esp_rom_spiflash_erase_sector = 0x40000130 ); +PROVIDE( esp_rom_spiflash_erase_block = 0x40000134 ); +PROVIDE( esp_rom_spiflash_write = 0x40000138 ); +PROVIDE( esp_rom_spiflash_read = 0x4000013c ); +PROVIDE( esp_rom_spiflash_unlock = 0x40000140 ); +PROVIDE( SPIEraseArea = 0x40000144 ); +PROVIDE( SPI_write_enable = 0x40000148 ); +PROVIDE( esp_rom_spiflash_config_param = 0x4000014c ); +PROVIDE( esp_rom_spiflash_read_user_cmd = 0x40000150 ); +PROVIDE( esp_rom_spiflash_select_qio_pins = 0x40000154 ); +PROVIDE( esp_rom_spi_flash_auto_sus_res = 0x40000158 ); +PROVIDE( esp_rom_spi_flash_send_resume = 0x4000015c ); +PROVIDE( esp_rom_spi_flash_update_id = 0x40000160 ); +PROVIDE( esp_rom_spiflash_config_clk = 0x40000164 ); +PROVIDE( esp_rom_spiflash_config_readmode = 0x40000168 ); +PROVIDE( esp_rom_spiflash_read_status = 0x4000016c ); +PROVIDE( esp_rom_spiflash_read_statushigh = 0x40000170 ); +PROVIDE( esp_rom_spiflash_write_status = 0x40000174 ); +PROVIDE( spi_flash_attach = 0x40000178 ); +PROVIDE( spi_flash_get_chip_size = 0x4000017c ); +PROVIDE( spi_flash_guard_set = 0x40000180 ); +PROVIDE( spi_flash_guard_get = 0x40000184 ); +PROVIDE( spi_flash_read_encrypted = 0x40000188 ); +PROVIDE( spi_flash_mmap_os_func_set = 0x4000018c ); +PROVIDE( spi_flash_mmap_page_num_init = 0x40000190 ); +PROVIDE( spi_flash_mmap = 0x40000194 ); +PROVIDE( spi_flash_mmap_pages = 0x40000198 ); +PROVIDE( spi_flash_munmap = 0x4000019c ); +PROVIDE( spi_flash_mmap_dump = 0x400001a0 ); +PROVIDE( spi_flash_check_and_flush_cache = 0x400001a4 ); +PROVIDE( spi_flash_mmap_get_free_pages = 0x400001a8 ); +PROVIDE( spi_flash_cache2phys = 0x400001ac ); +PROVIDE( spi_flash_phys2cache = 0x400001b0 ); +PROVIDE( spi_flash_disable_cache = 0x400001b4 ); +PROVIDE( spi_flash_restore_cache = 0x400001b8 ); +PROVIDE( spi_flash_cache_enabled = 0x400001bc ); +PROVIDE( spi_flash_enable_cache = 0x400001c0 ); +PROVIDE( spi_cache_mode_switch = 0x400001c4 ); +PROVIDE( spi_common_set_dummy_output = 0x400001c8 ); +PROVIDE( spi_common_set_flash_cs_timing = 0x400001cc ); +PROVIDE( esp_rom_spi_set_address_bit_len = 0x400001d0 ); +PROVIDE( esp_enable_cache_flash_wrap = 0x400001d4 ); +PROVIDE( SPILock = 0x400001d8 ); +PROVIDE( SPIMasterReadModeCnfig = 0x400001dc ); +PROVIDE( SPI_Common_Command = 0x400001e0 ); +PROVIDE( SPI_WakeUp = 0x400001e4 ); +PROVIDE( SPI_block_erase = 0x400001e8 ); +PROVIDE( SPI_chip_erase = 0x400001ec ); +PROVIDE( SPI_init = 0x400001f0 ); +PROVIDE( SPI_page_program = 0x400001f4 ); +PROVIDE( SPI_read_data = 0x400001f8 ); +PROVIDE( SPI_sector_erase = 0x400001fc ); +PROVIDE( SelectSpiFunction = 0x40000200 ); +PROVIDE( SetSpiDrvs = 0x40000204 ); +PROVIDE( Wait_SPI_Idle = 0x40000208 ); +PROVIDE( spi_dummy_len_fix = 0x4000020c ); +PROVIDE( Disable_QMode = 0x40000210 ); +PROVIDE( Enable_QMode = 0x40000214 ); +/* Data (.data, .bss, .rodata) */ +PROVIDE( rom_spiflash_legacy_funcs = 0x3fcdfff4 ); +PROVIDE( rom_spiflash_legacy_data = 0x3fcdfff0 ); +PROVIDE( g_flash_guard_ops = 0x3fcdfff8 ); + + +/*************************************** + Group hal_soc + ***************************************/ + +/* Functions */ +PROVIDE( spi_flash_hal_poll_cmd_done = 0x40000218 ); +PROVIDE( spi_flash_hal_device_config = 0x4000021c ); +PROVIDE( spi_flash_hal_configure_host_io_mode = 0x40000220 ); +PROVIDE( spi_flash_hal_common_command = 0x40000224 ); +PROVIDE( spi_flash_hal_read = 0x40000228 ); +PROVIDE( spi_flash_hal_erase_chip = 0x4000022c ); +PROVIDE( spi_flash_hal_erase_sector = 0x40000230 ); +PROVIDE( spi_flash_hal_erase_block = 0x40000234 ); +PROVIDE( spi_flash_hal_program_page = 0x40000238 ); +PROVIDE( spi_flash_hal_set_write_protect = 0x4000023c ); +PROVIDE( spi_flash_hal_host_idle = 0x40000240 ); +PROVIDE( spi_flash_hal_check_status = 0x40000244 ); +PROVIDE( spi_flash_hal_setup_read_suspend = 0x40000248 ); +PROVIDE( spi_flash_hal_setup_auto_suspend_mode = 0x4000024c ); +PROVIDE( spi_flash_hal_setup_auto_resume_mode = 0x40000250 ); +PROVIDE( spi_flash_hal_disable_auto_suspend_mode = 0x40000254 ); +PROVIDE( spi_flash_hal_disable_auto_resume_mode = 0x40000258 ); +PROVIDE( spi_flash_hal_resume = 0x4000025c ); +PROVIDE( spi_flash_hal_suspend = 0x40000260 ); +PROVIDE( spi_flash_encryption_hal_enable = 0x40000264 ); +PROVIDE( spi_flash_encryption_hal_disable = 0x40000268 ); +PROVIDE( spi_flash_encryption_hal_prepare = 0x4000026c ); +PROVIDE( spi_flash_encryption_hal_done = 0x40000270 ); +PROVIDE( spi_flash_encryption_hal_destroy = 0x40000274 ); +PROVIDE( spi_flash_encryption_hal_check = 0x40000278 ); +PROVIDE( wdt_hal_init = 0x4000027c ); +PROVIDE( wdt_hal_deinit = 0x40000280 ); +PROVIDE( wdt_hal_config_stage = 0x40000284 ); +PROVIDE( wdt_hal_write_protect_disable = 0x40000288 ); +PROVIDE( wdt_hal_write_protect_enable = 0x4000028c ); +PROVIDE( wdt_hal_enable = 0x40000290 ); +PROVIDE( wdt_hal_disable = 0x40000294 ); +PROVIDE( wdt_hal_handle_intr = 0x40000298 ); +PROVIDE( wdt_hal_feed = 0x4000029c ); +PROVIDE( wdt_hal_set_flashboot_en = 0x400002a0 ); +PROVIDE( wdt_hal_is_enabled = 0x400002a4 ); +PROVIDE( systimer_hal_init = 0x400002a8 ); +PROVIDE( systimer_hal_get_counter_value = 0x400002ac ); +PROVIDE( systimer_hal_get_time = 0x400002b0 ); +PROVIDE( systimer_hal_set_alarm_target = 0x400002b4 ); +PROVIDE( systimer_hal_set_alarm_period = 0x400002b8 ); +PROVIDE( systimer_hal_get_alarm_value = 0x400002bc ); +PROVIDE( systimer_hal_enable_alarm_int = 0x400002c0 ); +PROVIDE( systimer_hal_on_apb_freq_update = 0x400002c4 ); +PROVIDE( systimer_hal_counter_value_advance = 0x400002c8 ); +PROVIDE( systimer_hal_enable_counter = 0x400002cc ); +PROVIDE( systimer_hal_select_alarm_mode = 0x400002d0 ); +PROVIDE( systimer_hal_connect_alarm_counter = 0x400002d4 ); +PROVIDE( systimer_hal_counter_can_stall_by_cpu = 0x400002d8 ); + + +/*************************************** + Group heap + ***************************************/ + +/* Functions */ +PROVIDE( tlsf_create = 0x400002dc ); +PROVIDE( tlsf_create_with_pool = 0x400002e0 ); +PROVIDE( tlsf_get_pool = 0x400002e4 ); +PROVIDE( tlsf_add_pool = 0x400002e8 ); +PROVIDE( tlsf_remove_pool = 0x400002ec ); +PROVIDE( tlsf_malloc = 0x400002f0 ); +PROVIDE( tlsf_memalign = 0x400002f4 ); +PROVIDE( tlsf_memalign_offs = 0x400002f8 ); +PROVIDE( tlsf_realloc = 0x400002fc ); +PROVIDE( tlsf_free = 0x40000300 ); +PROVIDE( tlsf_block_size = 0x40000304 ); +PROVIDE( tlsf_size = 0x40000308 ); +PROVIDE( tlsf_align_size = 0x4000030c ); +PROVIDE( tlsf_block_size_min = 0x40000310 ); +PROVIDE( tlsf_block_size_max = 0x40000314 ); +PROVIDE( tlsf_pool_overhead = 0x40000318 ); +PROVIDE( tlsf_alloc_overhead = 0x4000031c ); +PROVIDE( tlsf_walk_pool = 0x40000320 ); +PROVIDE( tlsf_check = 0x40000324 ); +PROVIDE( tlsf_check_pool = 0x40000328 ); +PROVIDE( tlsf_poison_fill_pfunc_set = 0x4000032c ); +PROVIDE( multi_heap_get_block_address_impl = 0x40000330 ); +PROVIDE( multi_heap_get_allocated_size_impl = 0x40000334 ); +PROVIDE( multi_heap_register_impl = 0x40000338 ); +PROVIDE( multi_heap_set_lock = 0x4000033c ); +PROVIDE( multi_heap_mutex_init = 0x40000340 ); +PROVIDE( multi_heap_internal_lock = 0x40000344 ); +PROVIDE( multi_heap_internal_unlock = 0x40000348 ); +PROVIDE( multi_heap_get_first_block = 0x4000034c ); +PROVIDE( multi_heap_get_next_block = 0x40000350 ); +PROVIDE( multi_heap_is_free = 0x40000354 ); +PROVIDE( multi_heap_malloc_impl = 0x40000358 ); +PROVIDE( multi_heap_free_impl = 0x4000035c ); +PROVIDE( multi_heap_realloc_impl = 0x40000360 ); +PROVIDE( multi_heap_aligned_alloc_impl_offs = 0x40000364 ); +PROVIDE( multi_heap_aligned_alloc_impl = 0x40000368 ); +PROVIDE( multi_heap_check = 0x4000036c ); +PROVIDE( multi_heap_dump = 0x40000370 ); +PROVIDE( multi_heap_free_size_impl = 0x40000374 ); +PROVIDE( multi_heap_minimum_free_size_impl = 0x40000378 ); +PROVIDE( multi_heap_get_info_impl = 0x4000037c ); +/* Data (.data, .bss, .rodata) */ +PROVIDE( heap_tlsf_table_ptr = 0x3fcdffec ); + + +/*************************************** + Group spi_flash_chips + ***************************************/ + +/* Functions */ +PROVIDE( spi_flash_chip_generic_probe = 0x40000380 ); +PROVIDE( spi_flash_chip_generic_detect_size = 0x40000384 ); +PROVIDE( spi_flash_chip_generic_write = 0x40000388 ); +PROVIDE( spi_flash_chip_generic_write_encrypted = 0x4000038c ); +PROVIDE( spi_flash_chip_generic_set_write_protect = 0x40000390 ); +PROVIDE( spi_flash_common_write_status_16b_wrsr = 0x40000394 ); +PROVIDE( spi_flash_chip_generic_reset = 0x40000398 ); +PROVIDE( spi_flash_chip_generic_erase_chip = 0x4000039c ); +PROVIDE( spi_flash_chip_generic_erase_sector = 0x400003a0 ); +PROVIDE( spi_flash_chip_generic_erase_block = 0x400003a4 ); +PROVIDE( spi_flash_chip_generic_page_program = 0x400003a8 ); +PROVIDE( spi_flash_chip_generic_get_write_protect = 0x400003ac ); +PROVIDE( spi_flash_common_read_status_16b_rdsr_rdsr2 = 0x400003b0 ); +PROVIDE( spi_flash_chip_generic_read_reg = 0x400003b4 ); +PROVIDE( spi_flash_chip_generic_yield = 0x400003b8 ); +PROVIDE( spi_flash_generic_wait_host_idle = 0x400003bc ); +PROVIDE( spi_flash_chip_generic_wait_idle = 0x400003c0 ); +PROVIDE( spi_flash_chip_generic_config_host_io_mode = 0x400003c4 ); +PROVIDE( spi_flash_chip_generic_read = 0x400003c8 ); +PROVIDE( spi_flash_common_read_status_8b_rdsr2 = 0x400003cc ); +PROVIDE( spi_flash_chip_generic_get_io_mode = 0x400003d0 ); +PROVIDE( spi_flash_common_read_status_8b_rdsr = 0x400003d4 ); +PROVIDE( spi_flash_common_write_status_8b_wrsr = 0x400003d8 ); +PROVIDE( spi_flash_common_write_status_8b_wrsr2 = 0x400003dc ); +PROVIDE( spi_flash_common_set_io_mode = 0x400003e0 ); +PROVIDE( spi_flash_chip_generic_set_io_mode = 0x400003e4 ); +PROVIDE( spi_flash_chip_generic_read_unique_id = 0x400003e8 ); +PROVIDE( spi_flash_chip_generic_get_caps = 0x400003ec ); +PROVIDE( spi_flash_chip_generic_suspend_cmd_conf = 0x400003f0 ); +PROVIDE( spi_flash_chip_gd_get_io_mode = 0x400003f4 ); +PROVIDE( spi_flash_chip_gd_probe = 0x400003f8 ); +PROVIDE( spi_flash_chip_gd_set_io_mode = 0x400003fc ); +/* Data (.data, .bss, .rodata) */ +PROVIDE( spi_flash_chip_generic_config_data = 0x3fcdffe8 ); +PROVIDE( spi_flash_encryption = 0x3fcdffe4 ); + + +/*************************************** + Group memspi_host + ***************************************/ + +/* Functions */ +PROVIDE( memspi_host_read_id_hs = 0x40000400 ); +PROVIDE( memspi_host_read_status_hs = 0x40000404 ); +PROVIDE( memspi_host_flush_cache = 0x40000408 ); +PROVIDE( memspi_host_erase_chip = 0x4000040c ); +PROVIDE( memspi_host_erase_sector = 0x40000410 ); +PROVIDE( memspi_host_erase_block = 0x40000414 ); +PROVIDE( memspi_host_program_page = 0x40000418 ); +PROVIDE( memspi_host_read = 0x4000041c ); +PROVIDE( memspi_host_set_write_protect = 0x40000420 ); +PROVIDE( memspi_host_set_max_read_len = 0x40000424 ); +PROVIDE( memspi_host_read_data_slicer = 0x40000428 ); +PROVIDE( memspi_host_write_data_slicer = 0x4000042c ); + + +/*************************************** + Group esp_flash + ***************************************/ + +/* Functions */ +PROVIDE( esp_flash_chip_driver_initialized = 0x40000430 ); +PROVIDE( esp_flash_read_id = 0x40000434 ); +PROVIDE( esp_flash_get_size = 0x40000438 ); +PROVIDE( esp_flash_erase_chip = 0x4000043c ); +PROVIDE( esp_flash_erase_region = 0x40000440 ); +PROVIDE( esp_flash_get_chip_write_protect = 0x40000444 ); +PROVIDE( esp_flash_set_chip_write_protect = 0x40000448 ); +PROVIDE( esp_flash_get_protectable_regions = 0x4000044c ); +PROVIDE( esp_flash_get_protected_region = 0x40000450 ); +PROVIDE( esp_flash_set_protected_region = 0x40000454 ); +PROVIDE( esp_flash_read = 0x40000458 ); +PROVIDE( esp_flash_write = 0x4000045c ); +PROVIDE( esp_flash_write_encrypted = 0x40000460 ); +PROVIDE( esp_flash_read_encrypted = 0x40000464 ); +PROVIDE( esp_flash_get_io_mode = 0x40000468 ); +PROVIDE( esp_flash_set_io_mode = 0x4000046c ); +PROVIDE( spi_flash_boot_attach = 0x40000470 ); +PROVIDE( esp_flash_read_chip_id = 0x40000474 ); +PROVIDE( detect_spi_flash_chip = 0x40000478 ); +PROVIDE( esp_rom_spiflash_write_disable = 0x4000047c ); +PROVIDE( esp_flash_suspend_cmd_init = 0x40000480 ); +/* Data (.data, .bss, .rodata) */ +PROVIDE( esp_flash_default_chip = 0x3fcdffe0 ); +PROVIDE( esp_flash_api_funcs = 0x3fcdffdc ); + + +/*************************************** + Group cache + ***************************************/ + +/* Functions */ +PROVIDE( Cache_Get_ICache_Line_Size = 0x400006e0 ); +PROVIDE( Cache_Get_Mode = 0x400006e4 ); +PROVIDE( Cache_Address_Through_IBus = 0x400006e8 ); +PROVIDE( Cache_Address_Through_DBus = 0x400006ec ); +PROVIDE( Cache_Set_Default_Mode = 0x400006f0 ); +PROVIDE( Cache_Enable_Defalut_ICache_Mode = 0x400006f4 ); +PROVIDE( ROM_Boot_Cache_Init = 0x400006f8 ); +PROVIDE( MMU_Set_Page_Mode = 0x400006fc ); +PROVIDE( MMU_Get_Page_Mode = 0x40000700 ); +PROVIDE( Cache_Invalidate_ICache_Items = 0x40000704 ); +PROVIDE( Cache_Op_Addr = 0x40000708 ); +PROVIDE( Cache_Invalidate_Addr = 0x4000070c ); +PROVIDE( Cache_Invalidate_ICache_All = 0x40000710 ); +PROVIDE( Cache_Mask_All = 0x40000714 ); +PROVIDE( Cache_UnMask_Dram0 = 0x40000718 ); +PROVIDE( Cache_Disable_ICache = 0x4000071c ); +PROVIDE( Cache_Enable_ICache = 0x40000720 ); +PROVIDE( Cache_Suspend_ICache = 0x40000724 ); +PROVIDE( Cache_Resume_ICache = 0x40000728 ); +PROVIDE( Cache_Freeze_ICache_Enable = 0x4000072c ); +PROVIDE( Cache_Freeze_ICache_Disable = 0x40000730 ); +PROVIDE( Cache_Set_IDROM_MMU_Size = 0x40000734 ); +PROVIDE( Cache_Get_IROM_MMU_End = 0x40000738 ); +PROVIDE( Cache_Get_DROM_MMU_End = 0x4000073c ); +PROVIDE( Cache_Owner_Init = 0x40000740 ); +PROVIDE( Cache_Occupy_ICache_MEMORY = 0x40000744 ); +PROVIDE( Cache_MMU_Init = 0x40000748 ); +PROVIDE( Cache_Ibus_MMU_Set = 0x4000074c ); +PROVIDE( Cache_Dbus_MMU_Set = 0x40000750 ); +PROVIDE( Cache_Count_Flash_Pages = 0x40000754 ); +PROVIDE( Cache_Travel_Tag_Memory = 0x40000758 ); +PROVIDE( Cache_Get_Virtual_Addr = 0x4000075c ); +PROVIDE( Cache_Get_Memory_BaseAddr = 0x40000760 ); +PROVIDE( Cache_Get_Memory_Addr = 0x40000764 ); +PROVIDE( Cache_Get_Memory_value = 0x40000768 ); +/* Data (.data, .bss, .rodata) */ +PROVIDE( rom_cache_op_cb = 0x3fcdffd0 ); +PROVIDE( rom_cache_internal_table_ptr = 0x3fcdffcc ); + + +/*************************************** + Group clock + ***************************************/ + +/* Functions */ +ets_get_apb_freq = 0x4000076c; +ets_get_cpu_frequency = 0x40000770; +ets_update_cpu_frequency = 0x40000774; +ets_get_printf_channel = 0x40000778; +ets_get_xtal_div = 0x4000077c; +ets_set_xtal_div = 0x40000780; +ets_get_xtal_freq = 0x40000784; + + +/*************************************** + Group gpio + ***************************************/ + +/* Functions */ +gpio_input_get = 0x40000788; +gpio_matrix_in = 0x4000078c; +gpio_matrix_out = 0x40000790; +gpio_output_disable = 0x40000794; +gpio_output_enable = 0x40000798; +gpio_output_set = 0x4000079c; +gpio_pad_hold = 0x400007a0; +gpio_pad_input_disable = 0x400007a4; +gpio_pad_input_enable = 0x400007a8; +gpio_pad_pulldown = 0x400007ac; +gpio_pad_pullup = 0x400007b0; +gpio_pad_select_gpio = 0x400007b4; +gpio_pad_set_drv = 0x400007b8; +gpio_pad_unhold = 0x400007bc; +gpio_pin_wakeup_disable = 0x400007c0; +gpio_pin_wakeup_enable = 0x400007c4; +gpio_bypass_matrix_in = 0x400007c8; + + +/*************************************** + Group interrupts + ***************************************/ + +/* Functions */ +esprv_intc_int_set_priority = 0x400007cc; +esprv_intc_int_set_threshold = 0x400007d0; +esprv_intc_int_enable = 0x400007d4; +esprv_intc_int_disable = 0x400007d8; +esprv_intc_int_set_type = 0x400007dc; +PROVIDE( intr_handler_set = 0x400007e0 ); +intr_matrix_set = 0x400007e4; +ets_intr_lock = 0x400007e8; +ets_intr_unlock = 0x400007ec; +ets_isr_attach = 0x400007f0; +ets_isr_mask = 0x400007f4; +ets_isr_unmask = 0x400007f8; + + +/*************************************** + Group crypto + ***************************************/ + +/* Functions */ +crc32_le = 0x400007fc; +crc16_le = 0x40000800; +crc8_le = 0x40000804; +crc32_be = 0x40000808; +crc16_be = 0x4000080c; +crc8_be = 0x40000810; +esp_crc8 = 0x40000814; +ets_sha_enable = 0x40000818; +ets_sha_disable = 0x4000081c; +ets_sha_get_state = 0x40000820; +ets_sha_init = 0x40000824; +ets_sha_process = 0x40000828; +ets_sha_starts = 0x4000082c; +ets_sha_update = 0x40000830; +ets_sha_finish = 0x40000834; +ets_sha_clone = 0x40000838; +/* Data (.data, .bss, .rodata) */ +crc32_le_table_ptr = 0x3ff4fff8; +crc16_le_table_ptr = 0x3ff4fff4; +crc8_le_table_ptr = 0x3ff4fff0; +crc32_be_table_ptr = 0x3ff4ffec; +crc16_be_table_ptr = 0x3ff4ffe8; +crc8_be_table_ptr = 0x3ff4ffe4; + + +/*************************************** + Group efuse + ***************************************/ + +/* Functions */ +ets_efuse_read = 0x4000083c; +ets_efuse_program = 0x40000840; +ets_efuse_clear_program_registers = 0x40000844; +ets_efuse_write_key = 0x40000848; +ets_efuse_get_read_register_address = 0x4000084c; +ets_efuse_get_key_purpose = 0x40000850; +ets_efuse_key_block_unused = 0x40000854; +ets_efuse_find_unused_key_block = 0x40000858; +ets_efuse_rs_calculate = 0x4000085c; +ets_efuse_count_unused_key_blocks = 0x40000860; +ets_efuse_secure_boot_enabled = 0x40000864; +ets_efuse_secure_boot_aggressive_revoke_enabled = 0x40000868; +ets_efuse_cache_encryption_enabled = 0x4000086c; +ets_efuse_download_modes_disabled = 0x40000870; +ets_efuse_find_purpose = 0x40000874; +ets_efuse_force_send_resume = 0x40000878; +ets_efuse_get_flash_delay_us = 0x4000087c; +ets_efuse_get_mac = 0x40000880; +ets_efuse_get_uart_print_control = 0x40000884; +ets_efuse_direct_boot_mode_disabled = 0x40000888; +ets_efuse_security_download_modes_enabled = 0x4000088c; +ets_efuse_set_timing = 0x40000890; +ets_efuse_jtag_disabled = 0x40000894; + + +/*************************************** + Group secureboot + ***************************************/ + +/* Functions */ +ets_ecdsa_verify = 0x40000898; +ets_secure_boot_verify_bootloader_with_keys = 0x4000089c; +ets_secure_boot_verify_signature = 0x400008a0; +ets_secure_boot_read_key_digests = 0x400008a4; + + +/*************************************** + Group usb_uart + ***************************************/ + +/* Data (.data, .bss, .rodata) */ +g_uart_print = 0x3fcdffc9; +g_usb_print = 0x3fcdffc8; + + +/*************************************** + Group bluetooth + ***************************************/ + +/* Functions */ +ble_controller_rom_data_init = 0x40000aa8; +ble_osi_coex_funcs_register = 0x40000aac; +bt_rf_coex_cfg_get_default = 0x40000ab0; +bt_rf_coex_dft_pti_get_default = 0x40000ab4; +bt_rf_coex_hooks_p_set = 0x40000ab8; +r__os_mbuf_copypkthdr = 0x40000abc; +r__os_msys_find_pool = 0x40000ac0; +r_ble_controller_get_rom_compile_version = 0x40000ac4; +r_ble_hci_ram_hs_acl_tx = 0x40000ac8; +r_ble_hci_ram_hs_cmd_tx = 0x40000acc; +r_ble_hci_ram_ll_acl_tx = 0x40000ad0; +r_ble_hci_ram_ll_evt_tx = 0x40000ad4; +r_ble_hci_ram_reset = 0x40000ad8; +r_ble_hci_ram_set_acl_free_cb = 0x40000adc; +r_ble_hci_trans_acl_buf_alloc = 0x40000ae0; +r_ble_hci_trans_buf_alloc = 0x40000ae4; +r_ble_hci_trans_buf_free = 0x40000ae8; +r_ble_hci_trans_cfg_hs = 0x40000aec; +r_ble_hci_trans_cfg_ll = 0x40000af0; +r_ble_hci_trans_deinit = 0x40000af4; +r_ble_hci_trans_env_init = 0x40000af8; +r_ble_hci_trans_init = 0x40000afc; +r_ble_hci_uart_acl_tx = 0x40000b00; +r_ble_hci_uart_cmdevt_tx = 0x40000b04; +r_ble_hci_uart_config = 0x40000b08; +r_ble_hci_uart_free_pkt = 0x40000b0c; +r_ble_hci_uart_hs_acl_tx = 0x40000b10; +r_ble_hci_uart_hs_cmd_tx = 0x40000b14; +r_ble_hci_uart_ll_acl_tx = 0x40000b18; +r_ble_hci_uart_ll_evt_tx = 0x40000b1c; +r_ble_hci_uart_rx_acl = 0x40000b20; +r_ble_hci_uart_rx_char = 0x40000b24; +r_ble_hci_uart_rx_cmd = 0x40000b28; +r_ble_hci_uart_rx_evt = 0x40000b2c; +r_ble_hci_uart_rx_evt_cb = 0x40000b30; +r_ble_hci_uart_rx_le_evt = 0x40000b34; +r_ble_hci_uart_rx_pkt_type = 0x40000b38; +r_ble_hci_uart_rx_skip_acl = 0x40000b3c; +r_ble_hci_uart_rx_skip_cmd = 0x40000b40; +r_ble_hci_uart_rx_skip_evt = 0x40000b44; +r_ble_hci_uart_rx_sync_loss = 0x40000b48; +r_ble_hci_uart_set_acl_free_cb = 0x40000b4c; +r_ble_hci_uart_sync_lost = 0x40000b50; +r_ble_hci_uart_trans_reset = 0x40000b54; +r_ble_hci_uart_tx_char = 0x40000b58; +r_ble_hci_uart_tx_pkt_type = 0x40000b5c; +r_ble_hw_driver_deinit = 0x40000b60; +r_ble_hw_driver_env_init = 0x40000b64; +r_ble_hw_encrypt_block = 0x40000b68; +r_ble_hw_get_public_addr = 0x40000b6c; +r_ble_hw_get_static_addr = 0x40000b70; +r_ble_hw_periodiclist_add = 0x40000b74; +r_ble_hw_periodiclist_clear = 0x40000b78; +r_ble_hw_periodiclist_rmv = 0x40000b7c; +r_ble_hw_resolv_list_cur_entry = 0x40000b80; +r_ble_hw_resolv_list_get_cur_entry = 0x40000b84; +r_ble_hw_resolv_list_set = 0x40000b88; +r_ble_hw_rng_init = 0x40000b8c; +r_ble_hw_rng_start = 0x40000b90; +r_ble_hw_rng_stop = 0x40000b94; +r_ble_hw_rx_local_is_resolved = 0x40000b98; +r_ble_hw_rx_local_is_rpa = 0x40000b9c; +r_ble_hw_whitelist_add = 0x40000ba0; +r_ble_hw_whitelist_clear = 0x40000ba4; +r_ble_hw_whitelist_dev_num = 0x40000ba8; +r_ble_hw_whitelist_get_base = 0x40000bac; +r_ble_hw_whitelist_rmv = 0x40000bb0; +r_ble_hw_whitelist_search = 0x40000bb4; +r_ble_hw_whitelist_sort = 0x40000bb8; +r_ble_ll_acl_data_in = 0x40000bbc; +r_ble_ll_addr_is_id = 0x40000bc0; +r_ble_ll_addr_subtype = 0x40000bc4; +r_ble_ll_adv_active_chanset_clear = 0x40000bc8; +r_ble_ll_adv_active_chanset_is_pri = 0x40000bcc; +r_ble_ll_adv_active_chanset_is_sec = 0x40000bd0; +r_ble_ll_adv_active_chanset_set_pri = 0x40000bd4; +r_ble_ll_adv_active_chanset_set_sec = 0x40000bd8; +r_ble_ll_adv_aux_calculate = 0x40000bdc; +r_ble_ll_adv_aux_conn_rsp_pdu_make = 0x40000be0; +r_ble_ll_adv_aux_pdu_make = 0x40000be4; +r_ble_ll_adv_aux_scannable_pdu_make = 0x40000be8; +r_ble_ll_adv_aux_txed = 0x40000bec; +r_ble_ll_adv_can_chg_whitelist = 0x40000bf0; +r_ble_ll_adv_chk_rpa_timeout = 0x40000bf4; +r_ble_ll_adv_clear_all = 0x40000bf8; +r_ble_ll_adv_conn_req_rxd = 0x40000bfc; +r_ble_ll_adv_deinit = 0x40000c00; +r_ble_ll_adv_enabled = 0x40000c04; +r_ble_ll_adv_env_init = 0x40000c08; +r_ble_ll_adv_ext_set_adv_data = 0x40000c0c; +r_ble_ll_adv_ext_set_enable = 0x40000c10; +r_ble_ll_adv_ext_set_param = 0x40000c14; +r_ble_ll_adv_ext_set_scan_rsp = 0x40000c18; +r_ble_ll_adv_final_chan = 0x40000c1c; +r_ble_ll_adv_first_chan = 0x40000c20; +r_ble_ll_adv_flags_clear = 0x40000c24; +r_ble_ll_adv_flags_set = 0x40000c28; +r_ble_ll_adv_get_chan_num = 0x40000c2c; +r_ble_ll_adv_get_local_rpa = 0x40000c30; +r_ble_ll_adv_get_peer_rpa = 0x40000c34; +r_ble_ll_adv_hci_set_random_addr = 0x40000c38; +r_ble_ll_adv_init = 0x40000c3c; +r_ble_ll_adv_legacy_pdu_make = 0x40000c40; +r_ble_ll_adv_next_chan = 0x40000c44; +r_ble_ll_adv_pdu_make = 0x40000c48; +r_ble_ll_adv_periodic_check_data_itvl = 0x40000c4c; +r_ble_ll_adv_periodic_enable = 0x40000c50; +r_ble_ll_adv_periodic_estimate_data_itvl = 0x40000c54; +r_ble_ll_adv_periodic_send_sync_ind = 0x40000c58; +r_ble_ll_adv_periodic_set_data = 0x40000c5c; +r_ble_ll_adv_periodic_set_info_transfer = 0x40000c60; +r_ble_ll_adv_periodic_set_param = 0x40000c64; +r_ble_ll_adv_pre_process = 0x40000c68; +r_ble_ll_adv_put_acad_chM_update_ind = 0x40000c6c; +r_ble_ll_adv_put_aux_ptr = 0x40000c70; +r_ble_ll_adv_put_syncinfo = 0x40000c74; +r_ble_ll_adv_rd_max_adv_data_len = 0x40000c78; +r_ble_ll_adv_rd_sup_adv_sets = 0x40000c7c; +r_ble_ll_adv_read_txpwr = 0x40000c80; +r_ble_ll_adv_remove = 0x40000c84; +r_ble_ll_adv_reset = 0x40000c88; +r_ble_ll_adv_rpa_timeout = 0x40000c8c; +r_ble_ll_adv_rpa_update = 0x40000c90; +r_ble_ll_adv_rx_pkt_in = 0x40000c94; +r_ble_ll_adv_scan_req_rxd = 0x40000c98; +r_ble_ll_adv_scan_rsp_legacy_pdu_make = 0x40000c9c; +r_ble_ll_adv_scan_rsp_pdu_make = 0x40000ca0; +r_ble_ll_adv_scheduled = 0x40000ca4; +r_ble_ll_adv_send_conn_comp_ev = 0x40000ca8; +r_ble_ll_adv_set_adv_data = 0x40000cac; +r_ble_ll_adv_set_adv_params = 0x40000cb0; +r_ble_ll_adv_set_enable = 0x40000cb4; +r_ble_ll_adv_set_random_addr = 0x40000cb8; +r_ble_ll_adv_set_scan_rsp_data = 0x40000cbc; +r_ble_ll_adv_set_sched = 0x40000cc0; +r_ble_ll_adv_sm_deinit = 0x40000cc4; +r_ble_ll_adv_sm_event_init = 0x40000cc8; +r_ble_ll_adv_sm_find_configured = 0x40000ccc; +r_ble_ll_adv_sm_get = 0x40000cd0; +r_ble_ll_adv_sm_init = 0x40000cd4; +r_ble_ll_adv_sm_reset = 0x40000cd8; +r_ble_ll_adv_sm_start = 0x40000cdc; +r_ble_ll_adv_sm_start_periodic = 0x40000ce0; +r_ble_ll_adv_sm_stop = 0x40000ce4; +r_ble_ll_adv_sm_stop_limit_reached = 0x40000ce8; +r_ble_ll_adv_sm_stop_periodic = 0x40000cec; +r_ble_ll_adv_sm_stop_timeout = 0x40000cf0; +r_ble_ll_adv_sync_calculate = 0x40000cf4; +r_ble_ll_adv_sync_get_pdu_len = 0x40000cf8; +r_ble_ll_adv_sync_pdu_make = 0x40000cfc; +r_ble_ll_adv_update_adv_scan_rsp_data = 0x40000d00; +r_ble_ll_adv_update_data_mbuf = 0x40000d04; +r_ble_ll_adv_update_did = 0x40000d08; +r_ble_ll_adv_update_periodic_data = 0x40000d0c; +r_ble_ll_arr_pool_init = 0x40000d10; +r_ble_ll_auth_pyld_tmo_event_send = 0x40000d14; +r_ble_ll_calc_offset_ticks_us_for_rampup = 0x40000d18; +r_ble_ll_calc_session_key = 0x40000d1c; +r_ble_ll_calc_ticks_per_slot = 0x40000d20; +r_ble_ll_check_scan_params = 0x40000d24; +r_ble_ll_chk_txrx_octets = 0x40000d28; +r_ble_ll_chk_txrx_time = 0x40000d2c; +r_ble_ll_conn_adjust_pyld_len = 0x40000d30; +r_ble_ll_conn_auth_pyld_timer_cb = 0x40000d34; +r_ble_ll_conn_auth_pyld_timer_start = 0x40000d38; +r_ble_ll_conn_calc_dci = 0x40000d3c; +r_ble_ll_conn_calc_dci_csa1 = 0x40000d40; +r_ble_ll_conn_calc_itvl_ticks = 0x40000d44; +r_ble_ll_conn_chk_csm_flags = 0x40000d48; +r_ble_ll_conn_chk_phy_upd_start = 0x40000d4c; +r_ble_ll_conn_comp_event_send = 0x40000d50; +r_ble_ll_conn_connect_ind_pdu_make = 0x40000d54; +r_ble_ll_conn_create = 0x40000d58; +r_ble_ll_conn_create_cancel = 0x40000d5c; +r_ble_ll_conn_created = 0x40000d60; +r_ble_ll_conn_cth_flow_enable = 0x40000d64; +r_ble_ll_conn_cth_flow_error_fn = 0x40000d68; +r_ble_ll_conn_cth_flow_have_credit = 0x40000d6c; +r_ble_ll_conn_cth_flow_is_enabled = 0x40000d70; +r_ble_ll_conn_cth_flow_process_cmd = 0x40000d74; +r_ble_ll_conn_cth_flow_set_buffers = 0x40000d78; +r_ble_ll_conn_enqueue_pkt = 0x40000d7c; +r_ble_ll_conn_env_init = 0x40000d80; +r_ble_ll_conn_ext_master_init = 0x40000d84; +r_ble_ll_conn_find_active_conn = 0x40000d88; +r_ble_ll_conn_get_active_conn = 0x40000d8c; +r_ble_ll_conn_get_anchor = 0x40000d90; +r_ble_ll_conn_hcc_params_set_fallback = 0x40000d94; +r_ble_ll_conn_hci_cancel_conn_complete_event = 0x40000d98; +r_ble_ll_conn_hci_chk_conn_params = 0x40000d9c; +r_ble_ll_conn_hci_chk_scan_params = 0x40000da0; +r_ble_ll_conn_hci_disconnect_cmd = 0x40000da4; +r_ble_ll_conn_hci_le_ltk_neg_reply = 0x40000da8; +r_ble_ll_conn_hci_le_ltk_reply = 0x40000dac; +r_ble_ll_conn_hci_le_rd_phy = 0x40000db0; +r_ble_ll_conn_hci_le_set_phy = 0x40000db4; +r_ble_ll_conn_hci_le_start_encrypt = 0x40000db8; +r_ble_ll_conn_hci_param_nrr = 0x40000dbc; +r_ble_ll_conn_hci_param_rr = 0x40000dc0; +r_ble_ll_conn_hci_rd_auth_pyld_tmo = 0x40000dc4; +r_ble_ll_conn_hci_rd_chan_map = 0x40000dc8; +r_ble_ll_conn_hci_rd_rem_ver_cmd = 0x40000dcc; +r_ble_ll_conn_hci_rd_rssi = 0x40000dd0; +r_ble_ll_conn_hci_read_rem_features = 0x40000dd4; +r_ble_ll_conn_hci_set_chan_class = 0x40000dd8; +r_ble_ll_conn_hci_set_data_len = 0x40000ddc; +r_ble_ll_conn_hci_update = 0x40000de0; +r_ble_ll_conn_hci_wr_auth_pyld_tmo = 0x40000de4; +r_ble_ll_conn_init_phy = 0x40000de8; +r_ble_ll_conn_is_dev_connected = 0x40000dec; +r_ble_ll_conn_is_empty_pdu = 0x40000df0; +r_ble_ll_conn_is_lru = 0x40000df4; +r_ble_ll_conn_master_init = 0x40000df8; +r_ble_ll_conn_module_deinit = 0x40000dfc; +r_ble_ll_conn_module_init = 0x40000e00; +r_ble_ll_conn_module_reset = 0x40000e04; +r_ble_ll_conn_next_event = 0x40000e08; +r_ble_ll_conn_num_comp_pkts_event_send = 0x40000e0c; +r_ble_ll_conn_prepare_tx_pdu = 0x40000e10; +r_ble_ll_conn_process_conn_params = 0x40000e14; +r_ble_ll_conn_req_peer_sca = 0x40000e18; +r_ble_ll_conn_rx_data_pdu = 0x40000e1c; +r_ble_ll_conn_set_csa = 0x40000e20; +r_ble_ll_conn_set_ext_con_params = 0x40000e24; +r_ble_ll_conn_set_global_chanmap = 0x40000e28; +r_ble_ll_conn_set_phy = 0x40000e2c; +r_ble_ll_conn_set_txpwr_by_handle = 0x40000e30; +r_ble_ll_conn_set_unknown_rx_octets = 0x40000e34; +r_ble_ll_conn_slave_start = 0x40000e38; +r_ble_ll_conn_sm_get = 0x40000e3c; +r_ble_ll_conn_sm_new = 0x40000e40; +r_ble_ll_conn_sm_npl_deinit = 0x40000e44; +r_ble_ll_conn_sm_npl_init = 0x40000e48; +r_ble_ll_conn_tx_pkt_in = 0x40000e4c; +r_ble_ll_conn_update_eff_data_len = 0x40000e50; +r_ble_ll_ctrl_chanmap_req_make = 0x40000e54; +r_ble_ll_ctrl_chk_proc_start = 0x40000e58; +r_ble_ll_ctrl_conn_param_pdu_make = 0x40000e5c; +r_ble_ll_ctrl_conn_param_pdu_proc = 0x40000e60; +r_ble_ll_ctrl_conn_param_reply = 0x40000e64; +r_ble_ll_ctrl_conn_upd_make = 0x40000e68; +r_ble_ll_ctrl_datalen_upd_make = 0x40000e6c; +r_ble_ll_ctrl_enc_allowed_pdu = 0x40000e70; +r_ble_ll_ctrl_enc_allowed_pdu_rx = 0x40000e74; +r_ble_ll_ctrl_enc_allowed_pdu_tx = 0x40000e78; +r_ble_ll_ctrl_enc_req_make = 0x40000e7c; +r_ble_ll_ctrl_find_new_phy = 0x40000e80; +r_ble_ll_ctrl_initiate_dle = 0x40000e84; +r_ble_ll_ctrl_len_proc = 0x40000e88; +r_ble_ll_ctrl_min_used_chan_rsp = 0x40000e8c; +r_ble_ll_ctrl_phy_from_phy_mask = 0x40000e90; +r_ble_ll_ctrl_phy_req_rsp_make = 0x40000e94; +r_ble_ll_ctrl_phy_tx_transition_get = 0x40000e98; +r_ble_ll_ctrl_phy_update_cancel = 0x40000e9c; +r_ble_ll_ctrl_phy_update_ind_make = 0x40000ea0; +r_ble_ll_ctrl_phy_update_proc_complete = 0x40000ea4; +r_ble_ll_ctrl_proc_init = 0x40000ea8; +r_ble_ll_ctrl_proc_rsp_timer_cb = 0x40000eac; +r_ble_ll_ctrl_proc_start = 0x40000eb0; +r_ble_ll_ctrl_proc_stop = 0x40000eb4; +r_ble_ll_ctrl_proc_unk_rsp = 0x40000eb8; +r_ble_ll_ctrl_proc_with_instant_initiated = 0x40000ebc; +r_ble_ll_ctrl_rej_ext_ind_make = 0x40000ec0; +r_ble_ll_ctrl_reject_ind_send = 0x40000ec4; +r_ble_ll_ctrl_rx_chanmap_req = 0x40000ec8; +r_ble_ll_ctrl_rx_conn_param_req = 0x40000ecc; +r_ble_ll_ctrl_rx_conn_param_rsp = 0x40000ed0; +r_ble_ll_ctrl_rx_conn_update = 0x40000ed4; +r_ble_ll_ctrl_rx_enc_req = 0x40000ed8; +r_ble_ll_ctrl_rx_enc_rsp = 0x40000edc; +r_ble_ll_ctrl_rx_feature_req = 0x40000ee0; +r_ble_ll_ctrl_rx_feature_rsp = 0x40000ee4; +r_ble_ll_ctrl_rx_pause_enc_req = 0x40000ee8; +r_ble_ll_ctrl_rx_pause_enc_rsp = 0x40000eec; +r_ble_ll_ctrl_rx_pdu = 0x40000ef0; +r_ble_ll_ctrl_rx_periodic_sync_ind = 0x40000ef4; +r_ble_ll_ctrl_rx_phy_req = 0x40000ef8; +r_ble_ll_ctrl_rx_phy_rsp = 0x40000efc; +r_ble_ll_ctrl_rx_phy_update_ind = 0x40000f00; +r_ble_ll_ctrl_rx_ping_rsp = 0x40000f04; +r_ble_ll_ctrl_rx_reject_ind = 0x40000f08; +r_ble_ll_ctrl_rx_sca_req = 0x40000f0c; +r_ble_ll_ctrl_rx_sca_rsp = 0x40000f10; +r_ble_ll_ctrl_rx_start_enc_req = 0x40000f14; +r_ble_ll_ctrl_rx_start_enc_rsp = 0x40000f18; +r_ble_ll_ctrl_rx_version_ind = 0x40000f1c; +r_ble_ll_ctrl_sca_req_rsp_make = 0x40000f20; +r_ble_ll_ctrl_start_enc_send = 0x40000f24; +r_ble_ll_ctrl_start_rsp_timer = 0x40000f28; +r_ble_ll_ctrl_terminate_start = 0x40000f2c; +r_ble_ll_ctrl_tx_done = 0x40000f30; +r_ble_ll_ctrl_update_features = 0x40000f34; +r_ble_ll_ctrl_version_ind_make = 0x40000f38; +r_ble_ll_data_buffer_overflow = 0x40000f3c; +r_ble_ll_deinit = 0x40000f40; +r_ble_ll_disconn_comp_event_send = 0x40000f44; +r_ble_ll_env_init = 0x40000f48; +r_ble_ll_event_comp_pkts = 0x40000f4c; +r_ble_ll_event_dbuf_overflow = 0x40000f50; +r_ble_ll_event_send = 0x40000f54; +r_ble_ll_event_tx_pkt = 0x40000f58; +r_ble_ll_ext_adv_phy_mode_to_local_phy = 0x40000f5c; +r_ble_ll_ext_conn_create = 0x40000f60; +r_ble_ll_ext_scan_parse_adv_info = 0x40000f64; +r_ble_ll_ext_scan_parse_aux_ptr = 0x40000f68; +r_ble_ll_flush_pkt_queue = 0x40000f6c; +r_ble_ll_generate_dh_key_v1 = 0x40000f70; +r_ble_ll_generate_dh_key_v2 = 0x40000f74; +r_ble_ll_generic_data_init = 0x40000f78; +r_ble_ll_get_addr_type = 0x40000f7c; +r_ble_ll_get_chan_to_scan = 0x40000f80; +r_ble_ll_get_our_devaddr = 0x40000f84; +r_ble_ll_get_tx_pwr_compensation = 0x40000f88; +r_ble_ll_hci_acl_rx = 0x40000f8c; +r_ble_ll_hci_adv_mode_ext = 0x40000f90; +r_ble_ll_hci_adv_set_enable = 0x40000f94; +r_ble_ll_hci_cb_host_buf_size = 0x40000f98; +r_ble_ll_hci_cb_set_ctrlr_to_host_fc = 0x40000f9c; +r_ble_ll_hci_cb_set_event_mask = 0x40000fa0; +r_ble_ll_hci_cb_set_event_mask2 = 0x40000fa4; +r_ble_ll_hci_chk_phy_masks = 0x40000fa8; +r_ble_ll_hci_cmd_proc = 0x40000fac; +r_ble_ll_hci_cmd_rx = 0x40000fb0; +r_ble_ll_hci_ctlr_bb_cmd_proc = 0x40000fb4; +r_ble_ll_hci_deinit = 0x40000fb8; +r_ble_ll_hci_disconnect = 0x40000fbc; +r_ble_ll_hci_env_init = 0x40000fc0; +r_ble_ll_hci_ev_conn_update = 0x40000fc4; +r_ble_ll_hci_ev_databuf_overflow = 0x40000fc8; +r_ble_ll_hci_ev_datalen_chg = 0x40000fcc; +r_ble_ll_hci_ev_encrypt_chg = 0x40000fd0; +r_ble_ll_hci_ev_hw_err = 0x40000fd4; +r_ble_ll_hci_ev_le_csa = 0x40000fd8; +r_ble_ll_hci_ev_ltk_req = 0x40000fdc; +r_ble_ll_hci_ev_phy_update = 0x40000fe0; +r_ble_ll_hci_ev_rd_rem_used_feat = 0x40000fe4; +r_ble_ll_hci_ev_rd_rem_ver = 0x40000fe8; +r_ble_ll_hci_ev_rem_conn_parm_req = 0x40000fec; +r_ble_ll_hci_ev_sca_update = 0x40000ff0; +r_ble_ll_hci_ev_send_adv_set_terminated = 0x40000ff4; +r_ble_ll_hci_ev_send_scan_req_recv = 0x40000ff8; +r_ble_ll_hci_ev_send_scan_timeout = 0x40000ffc; +r_ble_ll_hci_ev_send_vendor_err = 0x40001000; +r_ble_ll_hci_event_send = 0x40001004; +r_ble_ll_hci_ext_scan_set_enable = 0x40001008; +r_ble_ll_hci_get_num_cmd_pkts = 0x4000100c; +r_ble_ll_hci_info_params_cmd_proc = 0x40001010; +r_ble_ll_hci_init = 0x40001014; +r_ble_ll_hci_init_support_cmd_base_on_lmp_ver = 0x40001018; +r_ble_ll_hci_is_event_enabled = 0x4000101c; +r_ble_ll_hci_is_le_event_enabled = 0x40001020; +r_ble_ll_hci_le_cmd_proc = 0x40001024; +r_ble_ll_hci_le_cmd_send_cmd_status = 0x40001028; +r_ble_ll_hci_le_encrypt = 0x4000102c; +r_ble_ll_hci_le_rand = 0x40001030; +r_ble_ll_hci_le_rd_max_data_len = 0x40001034; +r_ble_ll_hci_le_rd_sugg_data_len = 0x40001038; +r_ble_ll_hci_le_read_bufsize = 0x4000103c; +r_ble_ll_hci_le_read_local_features = 0x40001040; +r_ble_ll_hci_le_read_supp_states = 0x40001044; +r_ble_ll_hci_le_set_def_phy = 0x40001048; +r_ble_ll_hci_le_wr_sugg_data_len = 0x4000104c; +r_ble_ll_hci_link_ctrl_cmd_proc = 0x40001050; +r_ble_ll_hci_npl_init = 0x40001054; +r_ble_ll_hci_post_gen_dhkey_cmp_evt = 0x40001058; +r_ble_ll_hci_post_rd_p256_pubkey_cmp_evt = 0x4000105c; +r_ble_ll_hci_rd_bd_addr = 0x40001060; +r_ble_ll_hci_rd_local_supp_cmd = 0x40001064; +r_ble_ll_hci_rd_local_supp_feat = 0x40001068; +r_ble_ll_hci_rd_local_version = 0x4000106c; +r_ble_ll_hci_scan_set_enable = 0x40001070; +r_ble_ll_hci_send_adv_report = 0x40001074; +r_ble_ll_hci_send_dir_adv_report = 0x40001078; +r_ble_ll_hci_send_ext_adv_report = 0x4000107c; +r_ble_ll_hci_send_legacy_ext_adv_report = 0x40001080; +r_ble_ll_hci_send_noop = 0x40001084; +r_ble_ll_hci_set_adv_data = 0x40001088; +r_ble_ll_hci_set_le_event_mask = 0x4000108c; +r_ble_ll_hci_set_scan_rsp_data = 0x40001090; +r_ble_ll_hci_status_params_cmd_proc = 0x40001094; +r_ble_ll_hci_vs_cmd_proc = 0x40001098; +r_ble_ll_hci_vs_rd_static_addr = 0x4000109c; +r_ble_ll_hw_err_timer_cb = 0x400010a0; +r_ble_ll_hw_error = 0x400010a4; +r_ble_ll_init = 0x400010a8; +r_ble_ll_init_alloc_conn_comp_ev = 0x400010ac; +r_ble_ll_init_get_conn_comp_ev = 0x400010b0; +r_ble_ll_init_rx_pkt_in = 0x400010b4; +r_ble_ll_is_addr_empty = 0x400010b8; +r_ble_ll_is_controller_busy = 0x400010bc; +r_ble_ll_is_on_resolv_list = 0x400010c0; +r_ble_ll_is_our_devaddr = 0x400010c4; +r_ble_ll_is_rpa = 0x400010c8; +r_ble_ll_is_valid_adv_mode = 0x400010cc; +r_ble_ll_is_valid_own_addr_type = 0x400010d0; +r_ble_ll_is_valid_public_addr = 0x400010d4; +r_ble_ll_is_valid_random_addr = 0x400010d8; +r_ble_ll_mbuf_init = 0x400010dc; +r_ble_ll_misc_options_set = 0x400010e0; +r_ble_ll_modify_sca = 0x400010e4; +r_ble_ll_modify_sca_action = 0x400010e8; +r_ble_ll_pdu_max_tx_octets_get = 0x400010ec; +r_ble_ll_pdu_tx_time_get = 0x400010f0; +r_ble_ll_phy_to_phy_mode = 0x400010f4; +r_ble_ll_qa_enable = 0x400010f8; +r_ble_ll_rand = 0x400010fc; +r_ble_ll_rand_data_get = 0x40001100; +r_ble_ll_rand_deinit = 0x40001104; +r_ble_ll_rand_env_init = 0x40001108; +r_ble_ll_rand_init = 0x4000110c; +r_ble_ll_rand_prand_get = 0x40001110; +r_ble_ll_rand_sample = 0x40001114; +r_ble_ll_rand_start = 0x40001118; +r_ble_ll_read_local_p256_pub_key = 0x4000111c; +r_ble_ll_read_rf_path_compensation = 0x40001120; +r_ble_ll_read_supp_features = 0x40001124; +r_ble_ll_read_supp_states = 0x40001128; +r_ble_ll_read_tx_power = 0x4000112c; +r_ble_ll_reset = 0x40001130; +r_ble_ll_resolv_clear_all_pl_bit = 0x40001134; +r_ble_ll_resolv_clear_all_wl_bit = 0x40001138; +r_ble_ll_resolv_deinit = 0x4000113c; +r_ble_ll_resolv_enable_cmd = 0x40001140; +r_ble_ll_resolv_enabled = 0x40001144; +r_ble_ll_resolv_env_init = 0x40001148; +r_ble_ll_resolv_gen_priv_addr = 0x4000114c; +r_ble_ll_resolv_gen_rpa = 0x40001150; +r_ble_ll_resolv_get_addr_pointer = 0x40001154; +r_ble_ll_resolv_get_index = 0x40001158; +r_ble_ll_resolv_get_irk_pointer = 0x4000115c; +r_ble_ll_resolv_get_list = 0x40001160; +r_ble_ll_resolv_get_priv_addr = 0x40001164; +r_ble_ll_resolv_get_rpa_tmo = 0x40001168; +r_ble_ll_resolv_init = 0x4000116c; +r_ble_ll_resolv_irk_nonzero = 0x40001170; +r_ble_ll_resolv_list_add = 0x40001174; +r_ble_ll_resolv_list_chg_allowed = 0x40001178; +r_ble_ll_resolv_list_clr = 0x4000117c; +r_ble_ll_resolv_list_find = 0x40001180; +r_ble_ll_resolv_list_read_size = 0x40001184; +r_ble_ll_resolv_list_reset = 0x40001188; +r_ble_ll_resolv_list_rmv = 0x4000118c; +r_ble_ll_resolv_local_addr_rd = 0x40001190; +r_ble_ll_resolv_peer_addr_rd = 0x40001194; +r_ble_ll_resolv_peer_rpa_any = 0x40001198; +r_ble_ll_resolv_reset = 0x4000119c; +r_ble_ll_resolv_rpa = 0x400011a0; +r_ble_ll_resolv_rpa_timer_cb = 0x400011a4; +r_ble_ll_resolv_set_local_rpa = 0x400011a8; +r_ble_ll_resolv_set_peer_rpa = 0x400011ac; +r_ble_ll_resolv_set_rpa_tmo = 0x400011b0; +r_ble_ll_resolve_set_priv_mode = 0x400011b4; +r_ble_ll_rxpdu_alloc = 0x400011b8; +r_ble_ll_scan_add_scan_rsp_adv = 0x400011bc; +r_ble_ll_scan_adv_decode_addr = 0x400011c0; +r_ble_ll_scan_aux_data_ref = 0x400011c4; +r_ble_ll_scan_aux_data_unref = 0x400011c8; +r_ble_ll_scan_can_chg_whitelist = 0x400011cc; +r_ble_ll_scan_check_periodic_sync = 0x400011d0; +r_ble_ll_scan_classify_filter_aux_init = 0x400011d4; +r_ble_ll_scan_classify_filter_init = 0x400011d8; +r_ble_ll_scan_common_init = 0x400011dc; +r_ble_ll_scan_continue_en = 0x400011e0; +r_ble_ll_scan_deinit = 0x400011e4; +r_ble_ll_scan_dup_check_ext = 0x400011e8; +r_ble_ll_scan_dup_check_legacy = 0x400011ec; +r_ble_ll_scan_dup_move_to_head = 0x400011f0; +r_ble_ll_scan_dup_new = 0x400011f4; +r_ble_ll_scan_dup_update_ext = 0x400011f8; +r_ble_ll_scan_dup_update_legacy = 0x400011fc; +r_ble_ll_scan_enabled = 0x40001200; +r_ble_ll_scan_end_adv_evt = 0x40001204; +r_ble_ll_scan_env_init = 0x40001208; +r_ble_ll_scan_ext_initiator_start = 0x4000120c; +r_ble_ll_scan_get_addr_data_from_legacy = 0x40001210; +r_ble_ll_scan_get_addr_from_ext_adv = 0x40001214; +r_ble_ll_scan_get_cur_sm = 0x40001218; +r_ble_ll_scan_get_ext_adv_report = 0x4000121c; +r_ble_ll_scan_get_local_rpa = 0x40001220; +r_ble_ll_scan_get_next_adv_prim_chan = 0x40001224; +r_ble_ll_scan_get_peer_rpa = 0x40001228; +r_ble_ll_scan_have_rxd_scan_rsp = 0x4000122c; +r_ble_ll_scan_init = 0x40001230; +r_ble_ll_scan_initiator_start = 0x40001234; +r_ble_ll_scan_is_inside_window = 0x40001238; +r_ble_ll_scan_move_window_to = 0x4000123c; +r_ble_ll_scan_npl_reset = 0x40001240; +r_ble_ll_scan_parse_auxptr = 0x40001244; +r_ble_ll_scan_parse_ext_hdr = 0x40001248; +r_ble_ll_scan_pre_process = 0x4000124c; +r_ble_ll_scan_record_new_adv = 0x40001250; +r_ble_ll_scan_refresh_nrpa = 0x40001254; +r_ble_ll_scan_reset = 0x40001258; +r_ble_ll_scan_rx_pkt_in = 0x4000125c; +r_ble_ll_scan_rx_pkt_in_on_aux = 0x40001260; +r_ble_ll_scan_rx_pkt_in_on_legacy = 0x40001264; +r_ble_ll_scan_rx_pkt_in_restore_addr_data = 0x40001268; +r_ble_ll_scan_rxed = 0x4000126c; +r_ble_ll_scan_send_adv_report = 0x40001270; +r_ble_ll_scan_send_truncated = 0x40001274; +r_ble_ll_scan_set_enable = 0x40001278; +r_ble_ll_scan_set_peer_rpa = 0x4000127c; +r_ble_ll_scan_set_perfer_addr = 0x40001280; +r_ble_ll_scan_set_scan_params = 0x40001284; +r_ble_ll_scan_sm_start = 0x40001288; +r_ble_ll_scan_sm_stop = 0x4000128c; +r_ble_ll_scan_time_hci_to_ticks = 0x40001290; +r_ble_ll_scan_update_aux_data = 0x40001294; +r_ble_ll_scan_whitelist_enabled = 0x40001298; +r_ble_ll_set_default_privacy_mode = 0x4000129c; +r_ble_ll_set_default_sync_transfer_params = 0x400012a0; +r_ble_ll_set_ext_scan_params = 0x400012a4; +r_ble_ll_set_host_feat = 0x400012a8; +r_ble_ll_set_public_addr = 0x400012ac; +r_ble_ll_set_random_addr = 0x400012b0; +r_ble_ll_set_sync_transfer_params = 0x400012b4; +r_ble_ll_state_get = 0x400012b8; +r_ble_ll_state_set = 0x400012bc; +r_ble_ll_sync_adjust_ext_hdr = 0x400012c0; +r_ble_ll_sync_cancel = 0x400012c4; +r_ble_ll_sync_cancel_complete_event = 0x400012c8; +r_ble_ll_sync_check_acad = 0x400012cc; +r_ble_ll_sync_check_failed = 0x400012d0; +r_ble_ll_sync_create = 0x400012d4; +r_ble_ll_sync_deinit = 0x400012d8; +r_ble_ll_sync_enabled = 0x400012dc; +r_ble_ll_sync_env_init = 0x400012e0; +r_ble_ll_sync_est_event_failed = 0x400012e4; +r_ble_ll_sync_est_event_success = 0x400012e8; +r_ble_ll_sync_established = 0x400012ec; +r_ble_ll_sync_filter_enabled = 0x400012f0; +r_ble_ll_sync_find = 0x400012f4; +r_ble_ll_sync_get_cur_sm = 0x400012f8; +r_ble_ll_sync_get_handle = 0x400012fc; +r_ble_ll_sync_get_sm = 0x40001300; +r_ble_ll_sync_info_event = 0x40001304; +r_ble_ll_sync_init = 0x40001308; +r_ble_ll_sync_list_add = 0x4000130c; +r_ble_ll_sync_list_clear = 0x40001310; +r_ble_ll_sync_list_empty = 0x40001314; +r_ble_ll_sync_list_get_free = 0x40001318; +r_ble_ll_sync_list_remove = 0x4000131c; +r_ble_ll_sync_list_search = 0x40001320; +r_ble_ll_sync_list_size = 0x40001324; +r_ble_ll_sync_lost_event = 0x40001328; +r_ble_ll_sync_next_event = 0x4000132c; +r_ble_ll_sync_on_list = 0x40001330; +r_ble_ll_sync_parse_ext_hdr = 0x40001334; +r_ble_ll_sync_periodic_ind = 0x40001338; +r_ble_ll_sync_phy_mode_to_aux_phy = 0x4000133c; +r_ble_ll_sync_phy_mode_to_hci = 0x40001340; +r_ble_ll_sync_put_syncinfo = 0x40001344; +r_ble_ll_sync_receive_enable = 0x40001348; +r_ble_ll_sync_reserve = 0x4000134c; +r_ble_ll_sync_reset = 0x40001350; +r_ble_ll_sync_reset_sm = 0x40001354; +r_ble_ll_sync_rx_pkt_in = 0x40001358; +r_ble_ll_sync_send_per_adv_rpt = 0x4000135c; +r_ble_ll_sync_send_sync_ind = 0x40001360; +r_ble_ll_sync_send_truncated_per_adv_rpt = 0x40001364; +r_ble_ll_sync_sm_clear = 0x40001368; +r_ble_ll_sync_terminate = 0x4000136c; +r_ble_ll_sync_transfer = 0x40001370; +r_ble_ll_sync_transfer_get = 0x40001374; +r_ble_ll_sync_transfer_received = 0x40001378; +r_ble_ll_task = 0x4000137c; +r_ble_ll_trace_set_func = 0x40001380; +r_ble_ll_trace_u32 = 0x40001384; +r_ble_ll_trace_u32x2 = 0x40001388; +r_ble_ll_trace_u32x3 = 0x4000138c; +r_ble_ll_tx_flat_mbuf_pducb = 0x40001390; +r_ble_ll_tx_mbuf_pducb = 0x40001394; +r_ble_ll_tx_pkt_in = 0x40001398; +r_ble_ll_update_max_tx_octets_phy_mode = 0x4000139c; +r_ble_ll_usecs_to_ticks_round_up = 0x400013a0; +r_ble_ll_utils_calc_access_addr = 0x400013a4; +r_ble_ll_utils_calc_dci_csa2 = 0x400013a8; +r_ble_ll_utils_calc_num_used_chans = 0x400013ac; +r_ble_ll_utils_calc_window_widening = 0x400013b0; +r_ble_ll_utils_csa2_perm = 0x400013b4; +r_ble_ll_utils_csa2_prng = 0x400013b8; +r_ble_ll_utils_remapped_channel = 0x400013bc; +r_ble_ll_whitelist_add = 0x400013c0; +r_ble_ll_whitelist_chg_allowed = 0x400013c4; +r_ble_ll_whitelist_clear = 0x400013c8; +r_ble_ll_whitelist_read_size = 0x400013cc; +r_ble_ll_whitelist_rmv = 0x400013d0; +r_ble_ll_whitelist_search = 0x400013d4; +r_ble_ll_write_rf_path_compensation = 0x400013d8; +r_ble_lll_adv_aux_scannable_pdu_payload_len = 0x400013dc; +r_ble_lll_adv_aux_schedule = 0x400013e0; +r_ble_lll_adv_aux_schedule_first = 0x400013e4; +r_ble_lll_adv_aux_schedule_next = 0x400013e8; +r_ble_lll_adv_aux_scheduled = 0x400013ec; +r_ble_lll_adv_aux_set_start_time = 0x400013f0; +r_ble_lll_adv_coex_dpc_calc_pti_update_itvl = 0x400013f4; +r_ble_lll_adv_coex_dpc_process_pri = 0x400013f8; +r_ble_lll_adv_coex_dpc_process_sec = 0x400013fc; +r_ble_lll_adv_coex_dpc_pti_get = 0x40001400; +r_ble_lll_adv_coex_dpc_update = 0x40001404; +r_ble_lll_adv_coex_dpc_update_on_adv_start = 0x40001408; +r_ble_lll_adv_coex_dpc_update_on_aux_scheduled = 0x4000140c; +r_ble_lll_adv_coex_dpc_update_on_data_updated = 0x40001410; +r_ble_lll_adv_coex_dpc_update_on_event_end = 0x40001414; +r_ble_lll_adv_coex_dpc_update_on_event_scheduled = 0x40001418; +r_ble_lll_adv_done = 0x4000141c; +r_ble_lll_adv_drop_event = 0x40001420; +r_ble_lll_adv_event_done = 0x40001424; +r_ble_lll_adv_event_rmvd_from_sched = 0x40001428; +r_ble_lll_adv_ext_estimate_data_itvl = 0x4000142c; +r_ble_lll_adv_get_sec_pdu_len = 0x40001430; +r_ble_lll_adv_halt = 0x40001434; +r_ble_lll_adv_make_done = 0x40001438; +r_ble_lll_adv_periodic_done = 0x4000143c; +r_ble_lll_adv_periodic_event_done = 0x40001440; +r_ble_lll_adv_periodic_rmvd_from_sched = 0x40001444; +r_ble_lll_adv_periodic_schedule_first = 0x40001448; +r_ble_lll_adv_periodic_schedule_next = 0x4000144c; +r_ble_lll_adv_periodic_start = 0x40001450; +r_ble_lll_adv_periodic_stop = 0x40001454; +r_ble_lll_adv_pri_schedule_tx_pdu = 0x40001458; +r_ble_lll_adv_reschedule_event = 0x4000145c; +r_ble_lll_adv_reschedule_periodic_event = 0x40001460; +r_ble_lll_adv_rx_pkt_isr = 0x40001464; +r_ble_lll_adv_sec_done = 0x40001468; +r_ble_lll_adv_sec_event_done = 0x4000146c; +r_ble_lll_adv_sec_schedule_next_aux = 0x40001470; +r_ble_lll_adv_secondary_tx_start_cb = 0x40001474; +r_ble_lll_adv_sm_deinit = 0x40001478; +r_ble_lll_adv_sm_event_init = 0x4000147c; +r_ble_lll_adv_sm_event_restore = 0x40001480; +r_ble_lll_adv_sm_event_store = 0x40001484; +r_ble_lll_adv_sm_init = 0x40001488; +r_ble_lll_adv_sm_reset = 0x4000148c; +r_ble_lll_adv_start = 0x40001490; +r_ble_lll_adv_stop = 0x40001494; +r_ble_lll_adv_sync_next_scheduled = 0x40001498; +r_ble_lll_adv_sync_schedule = 0x4000149c; +r_ble_lll_adv_sync_tx_done = 0x400014a0; +r_ble_lll_adv_sync_tx_end = 0x400014a4; +r_ble_lll_adv_sync_tx_start_cb = 0x400014a8; +r_ble_lll_adv_tx_done = 0x400014ac; +r_ble_lll_adv_tx_start_cb = 0x400014b0; +r_ble_lll_adv_update_rsp_offset = 0x400014b4; +r_ble_lll_aux_scan_cb = 0x400014b8; +r_ble_lll_aux_scan_drop = 0x400014bc; +r_ble_lll_aux_scan_drop_event_cb = 0x400014c0; +r_ble_lll_calc_us_convert_tick_unit = 0x400014c4; +r_ble_lll_conn_append_tx_buffer = 0x400014c8; +r_ble_lll_conn_can_send_next_pdu = 0x400014cc; +r_ble_lll_conn_check_opcode_matched = 0x400014d0; +r_ble_lll_conn_coex_dpc_process = 0x400014d4; +r_ble_lll_conn_coex_dpc_pti_get = 0x400014d8; +r_ble_lll_conn_coex_dpc_update = 0x400014dc; +r_ble_lll_conn_coex_dpc_update_on_event_end = 0x400014e0; +r_ble_lll_conn_coex_dpc_update_on_event_scheduled = 0x400014e4; +r_ble_lll_conn_coex_dpc_update_on_event_started = 0x400014e8; +r_ble_lll_conn_cth_flow_alloc_credit = 0x400014ec; +r_ble_lll_conn_cth_flow_free_credit = 0x400014f0; +r_ble_lll_conn_current_sm_over = 0x400014f4; +r_ble_lll_conn_end = 0x400014f8; +r_ble_lll_conn_env_deinit = 0x400014fc; +r_ble_lll_conn_env_init = 0x40001500; +r_ble_lll_conn_event_end = 0x40001504; +r_ble_lll_conn_event_end_timer_cb = 0x40001508; +r_ble_lll_conn_event_halt = 0x4000150c; +r_ble_lll_conn_event_is_over = 0x40001510; +r_ble_lll_conn_event_start_cb = 0x40001514; +r_ble_lll_conn_free_rx_mbuf = 0x40001518; +r_ble_lll_conn_get_addr_info_from_rx_buf = 0x4000151c; +r_ble_lll_conn_get_ce_end_time = 0x40001520; +r_ble_lll_conn_get_next_sched_time = 0x40001524; +r_ble_lll_conn_get_rx_mbuf = 0x40001528; +r_ble_lll_conn_halt = 0x4000152c; +r_ble_lll_conn_master_common_init = 0x40001530; +r_ble_lll_conn_master_new = 0x40001534; +r_ble_lll_conn_module_deinit = 0x40001538; +r_ble_lll_conn_module_init = 0x4000153c; +r_ble_lll_conn_module_reset = 0x40001540; +r_ble_lll_conn_no_mem_evt_pre_cb = 0x40001544; +r_ble_lll_conn_pre_process = 0x40001548; +r_ble_lll_conn_process_acked_pdu = 0x4000154c; +r_ble_lll_conn_process_in_isr = 0x40001550; +r_ble_lll_conn_recv_ack = 0x40001554; +r_ble_lll_conn_recv_valid_packet = 0x40001558; +r_ble_lll_conn_reset_pending_sched = 0x4000155c; +r_ble_lll_conn_rx_pkt_isr = 0x40001560; +r_ble_lll_conn_sched_next_anchor = 0x40001564; +r_ble_lll_conn_sched_next_event = 0x40001568; +r_ble_lll_conn_set_slave_flow_control = 0x4000156c; +r_ble_lll_conn_slave_new = 0x40001570; +r_ble_lll_conn_sm_new = 0x40001574; +r_ble_lll_conn_sm_npl_deinit = 0x40001578; +r_ble_lll_conn_sm_npl_init = 0x4000157c; +r_ble_lll_conn_superversion_timer_cb = 0x40001580; +r_ble_lll_conn_timeout = 0x40001584; +r_ble_lll_conn_update_anchor = 0x40001588; +r_ble_lll_conn_update_conn_ind_params = 0x4000158c; +r_ble_lll_conn_update_encryption = 0x40001590; +r_ble_lll_conn_update_tx_buffer = 0x40001594; +r_ble_lll_deinit = 0x40001598; +r_ble_lll_dtm_calculate_itvl = 0x4000159c; +r_ble_lll_dtm_ctx_free = 0x400015a0; +r_ble_lll_dtm_deinit = 0x400015a4; +r_ble_lll_dtm_end_test = 0x400015a8; +r_ble_lll_dtm_ev_rx_restart_cb = 0x400015ac; +r_ble_lll_dtm_ev_tx_resched_cb = 0x400015b0; +r_ble_lll_dtm_init = 0x400015b4; +r_ble_lll_dtm_reset = 0x400015b8; +r_ble_lll_dtm_rx_create_ctx = 0x400015bc; +r_ble_lll_dtm_rx_isr_end = 0x400015c0; +r_ble_lll_dtm_rx_isr_start = 0x400015c4; +r_ble_lll_dtm_rx_pkt_in = 0x400015c8; +r_ble_lll_dtm_rx_sched_cb = 0x400015cc; +r_ble_lll_dtm_rx_start = 0x400015d0; +r_ble_lll_dtm_rx_test = 0x400015d4; +r_ble_lll_dtm_set_next = 0x400015d8; +r_ble_lll_dtm_tx_create_ctx = 0x400015dc; +r_ble_lll_dtm_tx_done = 0x400015e0; +r_ble_lll_dtm_tx_sched_cb = 0x400015e4; +r_ble_lll_dtm_tx_test = 0x400015e8; +r_ble_lll_dtm_wfr_timer_exp = 0x400015ec; +r_ble_lll_event_rx_pkt = 0x400015f0; +r_ble_lll_ext_scan_coex_dpc_process = 0x400015f4; +r_ble_lll_ext_scan_coex_dpc_pti_get = 0x400015f8; +r_ble_lll_ext_scan_coex_dpc_update = 0x400015fc; +r_ble_lll_ext_scan_coex_dpc_update_on_start = 0x40001600; +r_ble_lll_hci_dtm_rx_test = 0x40001604; +r_ble_lll_hci_dtm_rx_test_v2 = 0x40001608; +r_ble_lll_hci_dtm_tx_test = 0x4000160c; +r_ble_lll_hci_dtm_tx_test_ext = 0x40001610; +r_ble_lll_hci_dtm_tx_test_v2 = 0x40001614; +r_ble_lll_hci_dtm_tx_test_v2_ext = 0x40001618; +r_ble_lll_init = 0x4000161c; +r_ble_lll_init_pre_process = 0x40001620; +r_ble_lll_init_rx_pkt_isr = 0x40001624; +r_ble_lll_per_adv_coex_dpc_calc_pti_update_itvl = 0x40001628; +r_ble_lll_per_adv_coex_dpc_process = 0x4000162c; +r_ble_lll_per_adv_coex_dpc_pti_get = 0x40001630; +r_ble_lll_per_adv_coex_dpc_update = 0x40001634; +r_ble_lll_per_adv_coex_dpc_update_on_data_updated = 0x40001638; +r_ble_lll_per_adv_coex_dpc_update_on_scheduled = 0x4000163c; +r_ble_lll_per_adv_coex_dpc_update_on_start = 0x40001640; +r_ble_lll_reset = 0x40001644; +r_ble_lll_rfmgmt_controller_sleep_en = 0x40001648; +r_ble_lll_rfmgmt_deinit = 0x4000164c; +r_ble_lll_rfmgmt_disable = 0x40001650; +r_ble_lll_rfmgmt_enable = 0x40001654; +r_ble_lll_rfmgmt_enable_now = 0x40001658; +r_ble_lll_rfmgmt_init = 0x4000165c; +r_ble_lll_rfmgmt_is_enabled = 0x40001660; +r_ble_lll_rfmgmt_release = 0x40001664; +r_ble_lll_rfmgmt_release_ev = 0x40001668; +r_ble_lll_rfmgmt_reset = 0x4000166c; +r_ble_lll_rfmgmt_scan_changed = 0x40001670; +r_ble_lll_rfmgmt_sched_changed = 0x40001674; +r_ble_lll_rfmgmt_set_sleep_cb = 0x40001678; +r_ble_lll_rfmgmt_ticks_to_enabled = 0x4000167c; +r_ble_lll_rfmgmt_timer_exp = 0x40001680; +r_ble_lll_rfmgmt_timer_reschedule = 0x40001684; +r_ble_lll_rx_pdu_in = 0x40001688; +r_ble_lll_rx_pkt_in = 0x4000168c; +r_ble_lll_rx_pkt_isr = 0x40001690; +r_ble_lll_scan_abort_aux_sched = 0x40001694; +r_ble_lll_scan_aux_data_free = 0x40001698; +r_ble_lll_scan_chk_resume = 0x4000169c; +r_ble_lll_scan_clean_cur_aux_data = 0x400016a0; +r_ble_lll_scan_coex_event_cb = 0x400016a4; +r_ble_lll_scan_common_init = 0x400016a8; +r_ble_lll_scan_deinit = 0x400016ac; +r_ble_lll_scan_duration_period_timers_restart = 0x400016b0; +r_ble_lll_scan_duration_period_timers_stop = 0x400016b4; +r_ble_lll_scan_duration_timer_cb = 0x400016b8; +r_ble_lll_scan_event_proc = 0x400016bc; +r_ble_lll_scan_ext_adv_init = 0x400016c0; +r_ble_lll_scan_halt = 0x400016c4; +r_ble_lll_scan_has_sent_scan_req = 0x400016c8; +r_ble_lll_scan_init = 0x400016cc; +r_ble_lll_scan_npl_init = 0x400016d0; +r_ble_lll_scan_npl_reset = 0x400016d4; +r_ble_lll_scan_npl_restore = 0x400016d8; +r_ble_lll_scan_npl_store = 0x400016dc; +r_ble_lll_scan_period_timer_cb = 0x400016e0; +r_ble_lll_scan_process_adv_in_isr = 0x400016e4; +r_ble_lll_scan_process_rsp_in_isr = 0x400016e8; +r_ble_lll_scan_req_backoff = 0x400016ec; +r_ble_lll_scan_restart = 0x400016f0; +r_ble_lll_scan_rx_isr_on_aux = 0x400016f4; +r_ble_lll_scan_rx_isr_on_legacy = 0x400016f8; +r_ble_lll_scan_rx_pkt_isr = 0x400016fc; +r_ble_lll_scan_sched_next_aux = 0x40001700; +r_ble_lll_scan_sched_remove = 0x40001704; +r_ble_lll_scan_start = 0x40001708; +r_ble_lll_scan_start_rx = 0x4000170c; +r_ble_lll_scan_stop = 0x40001710; +r_ble_lll_scan_targeta_is_matched = 0x40001714; +r_ble_lll_scan_timer_cb = 0x40001718; +r_ble_lll_sched_adv_new = 0x4000171c; +r_ble_lll_sched_adv_resched_pdu = 0x40001720; +r_ble_lll_sched_adv_reschedule = 0x40001724; +r_ble_lll_sched_aux_scan = 0x40001728; +r_ble_lll_sched_conn_overlap = 0x4000172c; +r_ble_lll_sched_conn_reschedule = 0x40001730; +r_ble_lll_sched_deinit = 0x40001734; +r_ble_lll_sched_dtm = 0x40001738; +r_ble_lll_sched_env_init = 0x4000173c; +r_ble_lll_sched_execute_check = 0x40001740; +r_ble_lll_sched_execute_item = 0x40001744; +r_ble_lll_sched_init = 0x40001748; +r_ble_lll_sched_insert_if_empty = 0x4000174c; +r_ble_lll_sched_is_overlap = 0x40001750; +r_ble_lll_sched_master_new = 0x40001754; +r_ble_lll_sched_next_time = 0x40001758; +r_ble_lll_sched_overlaps_current = 0x4000175c; +r_ble_lll_sched_periodic_adv = 0x40001760; +r_ble_lll_sched_rmv_elem = 0x40001764; +r_ble_lll_sched_rmv_elem_type = 0x40001768; +r_ble_lll_sched_run = 0x4000176c; +r_ble_lll_sched_scan_req_over_aux_ptr = 0x40001770; +r_ble_lll_sched_slave_new = 0x40001774; +r_ble_lll_sched_stop = 0x40001778; +r_ble_lll_sched_sync = 0x4000177c; +r_ble_lll_sched_sync_overlaps_current = 0x40001780; +r_ble_lll_sched_sync_reschedule = 0x40001784; +r_ble_lll_sync_chain_start_cb = 0x40001788; +r_ble_lll_sync_coex_dpc_process = 0x4000178c; +r_ble_lll_sync_coex_dpc_pti_get = 0x40001790; +r_ble_lll_sync_coex_dpc_update = 0x40001794; +r_ble_lll_sync_current_sm_over = 0x40001798; +r_ble_lll_sync_deinit = 0x4000179c; +r_ble_lll_sync_event_end = 0x400017a0; +r_ble_lll_sync_event_end_cb = 0x400017a4; +r_ble_lll_sync_event_start_cb = 0x400017a8; +r_ble_lll_sync_get_event_end_time = 0x400017ac; +r_ble_lll_sync_halt = 0x400017b0; +r_ble_lll_sync_init = 0x400017b4; +r_ble_lll_sync_new = 0x400017b8; +r_ble_lll_sync_reset = 0x400017bc; +r_ble_lll_sync_reset_sm = 0x400017c0; +r_ble_lll_sync_rmvd_from_sched = 0x400017c4; +r_ble_lll_sync_rx_pkt_isr = 0x400017c8; +r_ble_lll_sync_schedule_chain = 0x400017cc; +r_ble_lll_sync_stop = 0x400017d0; +r_ble_lll_sync_trnasfer_sched = 0x400017d4; +r_ble_phy_access_addr_get = 0x400017d8; +r_ble_phy_calculate_rxtx_ifs = 0x400017dc; +r_ble_phy_calculate_rxwindow = 0x400017e0; +r_ble_phy_calculate_txrx_ifs = 0x400017e4; +r_ble_phy_check_bb_status = 0x400017e8; +r_ble_phy_complete_rx_info = 0x400017ec; +r_ble_phy_config_access_addr = 0x400017f0; +r_ble_phy_data_make = 0x400017f4; +r_ble_phy_disable = 0x400017f8; +r_ble_phy_disable_irq = 0x400017fc; +r_ble_phy_disable_whitening = 0x40001800; +r_ble_phy_enable_whitening = 0x40001804; +r_ble_phy_encrypt_disable = 0x40001808; +r_ble_phy_env_init = 0x4000180c; +r_ble_phy_get_current_phy = 0x40001810; +r_ble_phy_get_packet_counter = 0x40001814; +r_ble_phy_get_packet_status = 0x40001818; +r_ble_phy_get_pyld_time_offset = 0x4000181c; +r_ble_phy_get_rx_phy_mode = 0x40001820; +r_ble_phy_get_seq_end_st = 0x40001824; +r_ble_phy_init = 0x40001828; +r_ble_phy_isr = 0x4000182c; +r_ble_phy_max_data_pdu_pyld = 0x40001830; +r_ble_phy_mode_config = 0x40001834; +r_ble_phy_mode_convert = 0x40001838; +r_ble_phy_mode_write = 0x4000183c; +r_ble_phy_module_deinit = 0x40001840; +r_ble_phy_module_init = 0x40001844; +r_ble_phy_monitor_bb_sync = 0x40001848; +r_ble_phy_reset_bb_monitor = 0x4000184c; +r_ble_phy_resolv_list_disable = 0x40001850; +r_ble_phy_resolv_list_enable = 0x40001854; +r_ble_phy_restart_sequence = 0x40001858; +r_ble_phy_rx_set_start_time_forcibly = 0x4000185c; +r_ble_phy_rxpdu_copy = 0x40001860; +r_ble_phy_seq_encrypt_enable = 0x40001864; +r_ble_phy_seq_encrypt_set_pkt_cntr = 0x40001868; +r_ble_phy_sequence_end_isr = 0x4000186c; +r_ble_phy_sequence_get_mode = 0x40001870; +r_ble_phy_sequence_is_running = 0x40001874; +r_ble_phy_sequence_is_waiting_rsp = 0x40001878; +r_ble_phy_sequence_single_end = 0x4000187c; +r_ble_phy_sequence_tx_end_invoke = 0x40001880; +r_ble_phy_sequence_update_conn_ind_params = 0x40001884; +r_ble_phy_set_adv_mode = 0x40001888; +r_ble_phy_set_coex_pti = 0x4000188c; +r_ble_phy_set_conn_ind_pdu = 0x40001890; +r_ble_phy_set_conn_mode = 0x40001894; +r_ble_phy_set_dev_address = 0x40001898; +r_ble_phy_set_rx_pwr_compensation = 0x4000189c; +r_ble_phy_set_rxhdr = 0x400018a0; +r_ble_phy_set_scan_mode = 0x400018a4; +r_ble_phy_set_sequence_mode = 0x400018a8; +r_ble_phy_set_single_packet_rx_sequence = 0x400018ac; +r_ble_phy_set_single_packet_tx_sequence = 0x400018b0; +r_ble_phy_set_tx_rx_transition = 0x400018b4; +r_ble_phy_set_txend_cb = 0x400018b8; +r_ble_phy_setchan = 0x400018bc; +r_ble_phy_start_rx_immediately = 0x400018c0; +r_ble_phy_state_get = 0x400018c4; +r_ble_phy_timer_config_start_time = 0x400018c8; +r_ble_phy_timer_start_now = 0x400018cc; +r_ble_phy_timer_stop = 0x400018d0; +r_ble_phy_tx_set_start_time = 0x400018d4; +r_ble_phy_txpower_round = 0x400018d8; +r_ble_phy_txpwr_set = 0x400018dc; +r_ble_phy_update_conn_sequence = 0x400018e0; +r_ble_phy_update_encryption = 0x400018e4; +r_ble_phy_update_ifs = 0x400018e8; +r_ble_phy_xcvr_state_get = 0x400018ec; +r_ble_plf_set_log_level = 0x400018f0; +r_ble_rtc_wake_up_cpu_init = 0x400018f4; +r_ble_rtc_wake_up_state_clr = 0x400018f8; +r_ble_vendor_hci_register = 0x400018fc; +r_bt_rf_coex_cfg_set = 0x40001900; +r_bt_rf_coex_coded_txrx_time_upper_lim = 0x40001904; +r_bt_rf_coex_dft_pti_set = 0x40001908; +r_bt_rf_coex_hook_deinit = 0x4000190c; +r_bt_rf_coex_hook_init = 0x40001910; +r_bt_rf_coex_hook_st_set = 0x40001914; +r_bt_rf_coex_hooks_p_set_default = 0x40001918; +r_btdm_disable_adv_delay = 0x4000191c; +r_btdm_switch_phy_coded = 0x40001920; +r_esp_wait_disabled = 0x40001924; +r_get_be16 = 0x40001928; +r_get_be24 = 0x4000192c; +r_get_be32 = 0x40001930; +r_get_be64 = 0x40001934; +r_get_le16 = 0x40001938; +r_get_le24 = 0x4000193c; +r_get_le32 = 0x40001940; +r_get_le64 = 0x40001944; +r_get_local_irk_offset = 0x40001948; +r_get_local_rpa_offset = 0x4000194c; +r_get_max_skip = 0x40001950; +r_get_peer_id_offset = 0x40001954; +r_get_peer_irk_offset = 0x40001958; +r_get_peer_rpa_offset = 0x4000195c; +r_hal_rtc_intr_init = 0x40001960; +r_hal_rtc_irq_handler = 0x40001964; +r_hal_timer_deinit = 0x40001968; +r_hal_timer_disable_irq = 0x4000196c; +r_hal_timer_env_init = 0x40001970; +r_hal_timer_init = 0x40001974; +r_hal_timer_process = 0x40001978; +r_hal_timer_read = 0x4000197c; +r_hal_timer_read_tick = 0x40001980; +r_hal_timer_set_cb = 0x40001984; +r_hal_timer_set_exp_tick = 0x40001988; +r_hal_timer_start = 0x4000198c; +r_hal_timer_start_at = 0x40001990; +r_hal_timer_stop = 0x40001994; +r_hal_timer_task_start = 0x40001998; +r_ll_assert = 0x4000199c; +r_mem_init_mbuf_pool = 0x400019a0; +r_mem_malloc_mbuf_pool = 0x400019a4; +r_mem_malloc_mbufpkt_pool = 0x400019a8; +r_mem_malloc_mempool = 0x400019ac; +r_mem_malloc_mempool_ext = 0x400019b0; +r_mem_malloc_mempool_gen = 0x400019b4; +r_mem_pullup_obj = 0x400019b8; +r_mem_split_frag = 0x400019bc; +r_os_cputime_get32 = 0x400019c0; +r_os_cputime_ticks_to_usecs = 0x400019c4; +r_os_cputime_timer_init = 0x400019c8; +r_os_cputime_timer_relative = 0x400019cc; +r_os_cputime_timer_start = 0x400019d0; +r_os_cputime_timer_stop = 0x400019d4; +r_os_cputime_usecs_to_ticks = 0x400019d8; +r_os_mbuf_adj = 0x400019dc; +r_os_mbuf_append = 0x400019e0; +r_os_mbuf_appendfrom = 0x400019e4; +r_os_mbuf_cmpf = 0x400019e8; +r_os_mbuf_cmpm = 0x400019ec; +r_os_mbuf_concat = 0x400019f0; +r_os_mbuf_copydata = 0x400019f4; +r_os_mbuf_copyinto = 0x400019f8; +r_os_mbuf_dup = 0x400019fc; +r_os_mbuf_extend = 0x40001a00; +r_os_mbuf_free = 0x40001a04; +r_os_mbuf_free_chain = 0x40001a08; +r_os_mbuf_get = 0x40001a0c; +r_os_mbuf_get_pkthdr = 0x40001a10; +r_os_mbuf_leadingspace = 0x40001a14; +r_os_mbuf_len = 0x40001a18; +r_os_mbuf_off = 0x40001a1c; +r_os_mbuf_pack_chains = 0x40001a20; +r_os_mbuf_pool_init = 0x40001a24; +r_os_mbuf_prepend = 0x40001a28; +r_os_mbuf_prepend_pullup = 0x40001a2c; +r_os_mbuf_pullup = 0x40001a30; +r_os_mbuf_trailingspace = 0x40001a34; +r_os_mbuf_trim_front = 0x40001a38; +r_os_mbuf_widen = 0x40001a3c; +r_os_memblock_from = 0x40001a40; +r_os_memblock_get = 0x40001a44; +r_os_memblock_put = 0x40001a48; +r_os_memblock_put_from_cb = 0x40001a4c; +r_os_mempool_clear = 0x40001a50; +r_os_mempool_ext_clear = 0x40001a54; +r_os_mempool_ext_init = 0x40001a58; +r_os_mempool_info_get_next = 0x40001a5c; +r_os_mempool_init = 0x40001a60; +r_os_mempool_init_internal = 0x40001a64; +r_os_mempool_is_sane = 0x40001a68; +r_os_mempool_module_init = 0x40001a6c; +r_os_mempool_unregister = 0x40001a70; +r_os_mqueue_get = 0x40001a74; +r_os_mqueue_init = 0x40001a78; +r_os_mqueue_put = 0x40001a7c; +r_os_msys_count = 0x40001a80; +r_os_msys_get = 0x40001a84; +r_os_msys_get_pkthdr = 0x40001a88; +r_os_msys_num_free = 0x40001a8c; +r_os_msys_register = 0x40001a90; +r_os_msys_reset = 0x40001a94; +r_pri_phy_valid = 0x40001a98; +r_put_be16 = 0x40001a9c; +r_put_be24 = 0x40001aa0; +r_put_be32 = 0x40001aa4; +r_put_be64 = 0x40001aa8; +r_put_le16 = 0x40001aac; +r_put_le24 = 0x40001ab0; +r_put_le32 = 0x40001ab4; +r_put_le64 = 0x40001ab8; +r_rtc0_timer_handler = 0x40001abc; +r_sdkconfig_get_opts = 0x40001ac0; +r_sdkconfig_set_opts = 0x40001ac4; +r_sec_phy_valid = 0x40001ac8; +r_swap_buf = 0x40001acc; +r_swap_in_place = 0x40001ad0; +/* Data (.data, .bss, .rodata) */ +ble_lll_dtm_module_env_p = 0x3fcdffc4; +g_ble_lll_dtm_prbs15_data = 0x3ff4fee4; +g_ble_lll_dtm_prbs9_data = 0x3ff4fde4; +g_channel_rf_to_index = 0x3ff4fdbc; +g_ble_lll_rfmgmt_data = 0x3fcdff7c; +g_ble_sleep_enter_cb = 0x3fcdff78; +g_ble_sleep_exit_cb = 0x3fcdff74; +ble_lll_sched_env_p = 0x3fcdff70; +ble_ll_env_p = 0x3fcdff6c; +g_ble_ll_pdu_header_tx_time_ro = 0x3ff4fdb4; +ble_ll_adv_env_p = 0x3fcdff68; +ble_ll_conn_env_p = 0x3fcdff64; +ble_ll_conn_required_phy_mask = 0x3ff4fdb0; +ble_ll_valid_conn_phy_mask = 0x3ff4fdaf; +g_ble_ll_ctrl_pkt_lengths_ro = 0x3ff4fd8c; +ble_ll_hci_env_p = 0x3fcdff60; +g_debug_le_private_key = 0x3ff4fd6c; +g_ecc_key = 0x3fcdfefc; +ble_ll_rand_env_p = 0x3fcdfef8; +ble_ll_resolv_env_p = 0x3fcdfef4; +g_ble_ll_resolve_hdr = 0x3fcdfeec; +g_device_mode_default = 0x3fcdfe68; +ble_ll_scan_classify_filter_aux_check_cb = 0x3fcdfee8; +ble_ll_scan_classify_filter_check_cb = 0x3fcdfee4; +ble_ll_scan_env_p = 0x3fcdfee0; +g_ble_ll_supp_cmds_ro = 0x3ff4fd3c; +ble_ll_sync_env_p = 0x3fcdfedc; +g_ble_sca_ppm_tbl_ro = 0x3ff4fd2c; +priv_config_opts = 0x3fcdfe48; +ble_hci_uart_reset_cmd = 0x3ff4fd28; +ble_hci_trans_env_p = 0x3fcdfed8; +ble_hci_trans_mode = 0x3fcdfe44; +ble_hci_trans_funcs_ptr = 0x3fcdfed4; +r_ble_lll_stub_funcs_ptr = 0x3fcdfed0; +r_ble_stub_funcs_ptr = 0x3fcdfecc; +r_ext_funcs_p = 0x3fcdfec8; +r_npl_funcs = 0x3fcdfec4; +ble_hw_env_p = 0x3fcdfec0; +ble_phy_module_env_p = 0x3fcdfebc; +g_ble_phy_chan_freq_ro = 0x3ff4fd00; +g_ble_phy_mode_pkt_start_off_ro = 0x3ff4fcf8; +g_ble_phy_rxtx_ifs_compensation_ro = 0x3ff4fce8; +g_ble_phy_t_rxaddrdelay_ro = 0x3ff4fce4; +g_ble_phy_t_rxenddelay_ro = 0x3ff4fce0; +g_ble_phy_t_txdelay_ro = 0x3ff4fcdc; +g_ble_phy_t_txenddelay_ro = 0x3ff4fcd8; +g_ble_phy_txrx_ifs_compensation_ro = 0x3ff4fcc8; +hal_timer_env_p = 0x3fcdfeb8; +r_osi_coex_funcs_p = 0x3fcdfeb4; +bt_rf_coex_hooks = 0x3fcdfeac; +bt_rf_coex_hooks_p = 0x3fcdfea8; +coex_hook_st_group_tab = 0x3ff4fcbc; +coex_hook_st_group_to_coex_schm_st_tab = 0x3ff4fcb8; +s_ble_act_count_by_group = 0x3fcdfea4; +s_ble_coex_st_map = 0x3fcdfe90; +bt_rf_coex_cfg_cb = 0x3fcdfe74; +bt_rf_coex_cfg_p = 0x3fcdfe70; +bt_rf_coex_cfg_rom = 0x3ff4fc9c; +bt_rf_coex_pti_dft_p = 0x3fcdfe6c; +bt_rf_coex_pti_dft_rom = 0x3fcdfe04; +conn_dynamic_pti_param_rom = 0x3ff4fc84; +conn_phy_coded_max_data_time_param_rom = 0x3ff4fc80; +ext_adv_dynamic_pti_param_rom = 0x3ff4fc4c; +ext_scan_dynamic_param_rom = 0x3ff4fc14; +legacy_adv_dynamic_pti_param_rom = 0x3ff4fbf4; +per_adv_dynamic_pti_param_rom = 0x3ff4fbd8; +sync_dynamic_param_rom = 0x3ff4fbc0; +g_ble_plf_log_level = 0x3fcdfe00; +g_msys_pool_list = 0x3fcdfdf8; +g_os_mempool_list = 0x3fcdfdf0; + + +/*************************************** + Group rom_pp + ***************************************/ + +/* Functions */ +esp_pp_rom_version_get = 0x40001ad4; +RC_GetBlockAckTime = 0x40001ad8; +ebuf_list_remove = 0x40001adc; +esf_buf_alloc = 0x40001ae0; +esf_buf_alloc_dynamic = 0x40001ae4; +esf_buf_recycle = 0x40001ae8; +GetAccess = 0x40001aec; +hal_mac_is_low_rate_enabled = 0x40001af0; +hal_mac_tx_get_blockack = 0x40001af4; +hal_mac_tx_set_ppdu = 0x40001af8; +ic_get_trc = 0x40001afc; +ic_mac_deinit = 0x40001b00; +ic_mac_init = 0x40001b04; +ic_interface_enabled = 0x40001b08; +is_lmac_idle = 0x40001b0c; +lmacAdjustTimestamp = 0x40001b10; +lmacDiscardAgedMSDU = 0x40001b14; +lmacDiscardMSDU = 0x40001b18; +lmacEndFrameExchangeSequence = 0x40001b1c; +lmacIsIdle = 0x40001b20; +lmacIsLongFrame = 0x40001b24; +lmacMSDUAged = 0x40001b28; +lmacPostTxComplete = 0x40001b2c; +lmacProcessAllTxTimeout = 0x40001b30; +lmacProcessCollisions = 0x40001b34; +lmacProcessRxSucData = 0x40001b38; +lmacReachLongLimit = 0x40001b3c; +lmacReachShortLimit = 0x40001b40; +lmacRecycleMPDU = 0x40001b44; +lmacRxDone = 0x40001b48; +lmacSetTxFrame = 0x40001b4c; +lmacTxDone = 0x40001b50; +lmacTxFrame = 0x40001b54; +mac_tx_set_duration = 0x40001b58; +mac_tx_set_htsig = 0x40001b5c; +mac_tx_set_plcp0 = 0x40001b60; +mac_tx_set_plcp1 = 0x40001b64; +mac_tx_set_plcp2 = 0x40001b68; +pm_check_state = 0x40001b6c; +pm_disable_dream_timer = 0x40001b70; +pm_disable_sleep_delay_timer = 0x40001b74; +pm_dream = 0x40001b78; +pm_mac_wakeup = 0x40001b7c; +pm_mac_sleep = 0x40001b80; +pm_enable_active_timer = 0x40001b84; +pm_enable_sleep_delay_timer = 0x40001b88; +pm_local_tsf_process = 0x40001b8c; +pm_set_beacon_filter = 0x40001b90; +pm_is_in_wifi_slice_threshold = 0x40001b94; +pm_is_waked = 0x40001b98; +pm_keep_alive = 0x40001b9c; +pm_on_beacon_rx = 0x40001ba0; +pm_on_data_rx = 0x40001ba4; +pm_on_tbtt = 0x40001ba8; +pm_parse_beacon = 0x40001bac; +pm_process_tim = 0x40001bb0; +pm_rx_beacon_process = 0x40001bb4; +pm_rx_data_process = 0x40001bb8; +pm_sleep = 0x40001bbc; +pm_sleep_for = 0x40001bc0; +pm_tbtt_process = 0x40001bc4; +ppAMPDU2Normal = 0x40001bc8; +ppAssembleAMPDU = 0x40001bcc; +ppCalFrameTimes = 0x40001bd0; +ppCalSubFrameLength = 0x40001bd4; +ppCalTxAMPDULength = 0x40001bd8; +ppCheckTxAMPDUlength = 0x40001bdc; +ppDequeueRxq_Locked = 0x40001be0; +ppDequeueTxQ = 0x40001be4; +ppEmptyDelimiterLength = 0x40001be8; +ppEnqueueRxq = 0x40001bec; +ppEnqueueTxDone = 0x40001bf0; +ppGetTxQFirstAvail_Locked = 0x40001bf4; +ppGetTxframe = 0x40001bf8; +ppMapTxQueue = 0x40001bfc; +ppProcTxSecFrame = 0x40001c00; +ppProcessRxPktHdr = 0x40001c04; +ppProcessTxQ = 0x40001c08; +ppRecordBarRRC = 0x40001c0c; +lmacRequestTxopQueue = 0x40001c10; +lmacReleaseTxopQueue = 0x40001c14; +ppRecycleAmpdu = 0x40001c18; +ppRecycleRxPkt = 0x40001c1c; +ppResortTxAMPDU = 0x40001c20; +ppResumeTxAMPDU = 0x40001c24; +ppRxFragmentProc = 0x40001c28; +ppRxPkt = 0x40001c2c; +ppRxProtoProc = 0x40001c30; +ppSearchTxQueue = 0x40001c34; +ppSearchTxframe = 0x40001c38; +ppSelectNextQueue = 0x40001c3c; +ppSubFromAMPDU = 0x40001c40; +ppTask = 0x40001c44; +ppTxPkt = 0x40001c48; +ppTxProtoProc = 0x40001c4c; +ppTxqUpdateBitmap = 0x40001c50; +pp_coex_tx_request = 0x40001c54; +pp_hdrsize = 0x40001c58; +pp_post = 0x40001c5c; +pp_process_hmac_waiting_txq = 0x40001c60; +rcGetAmpduSched = 0x40001c64; +rcUpdateRxDone = 0x40001c68; +rc_get_trc = 0x40001c6c; +rc_get_trc_by_index = 0x40001c70; +rcAmpduLowerRate = 0x40001c74; +rcampduuprate = 0x40001c78; +rcClearCurAMPDUSched = 0x40001c7c; +rcClearCurSched = 0x40001c80; +rcClearCurStat = 0x40001c84; +rcGetSched = 0x40001c88; +rcLowerSched = 0x40001c8c; +rcSetTxAmpduLimit = 0x40001c90; +rcTxUpdatePer = 0x40001c94; +rcUpdateAckSnr = 0x40001c98; +rcUpdateRate = 0x40001c9c; +rcUpdateTxDone = 0x40001ca0; +rcUpdateTxDoneAmpdu2 = 0x40001ca4; +rcUpSched = 0x40001ca8; +rssi_margin = 0x40001cac; +rx11NRate2AMPDULimit = 0x40001cb0; +TRC_AMPDU_PER_DOWN_THRESHOLD = 0x40001cb4; +TRC_AMPDU_PER_UP_THRESHOLD = 0x40001cb8; +trc_calc_duration = 0x40001cbc; +trc_isTxAmpduOperational = 0x40001cc0; +trc_onAmpduOp = 0x40001cc4; +TRC_PER_IS_GOOD = 0x40001cc8; +trc_SetTxAmpduState = 0x40001ccc; +trc_tid_isTxAmpduOperational = 0x40001cd0; +trcAmpduSetState = 0x40001cd4; +wDevCheckBlockError = 0x40001cd8; +wDev_AppendRxBlocks = 0x40001cdc; +wDev_DiscardFrame = 0x40001ce0; +wDev_GetNoiseFloor = 0x40001ce4; +wDev_IndicateAmpdu = 0x40001ce8; +wDev_IndicateFrame = 0x40001cec; +wdev_mac_reg_load = 0x40001cf0; +wdev_mac_reg_store = 0x40001cf4; +wdev_mac_special_reg_load = 0x40001cf8; +wdev_mac_special_reg_store = 0x40001cfc; +wdev_mac_wakeup = 0x40001d00; +wdev_mac_sleep = 0x40001d04; +wDev_ProcessFiq = 0x40001d08; +wDev_ProcessRxSucData = 0x40001d0c; +wdevProcessRxSucDataAll = 0x40001d10; +wdev_csi_len_align = 0x40001d14; +ppDequeueTxDone_Locked = 0x40001d18; +ppProcTxDone = 0x40001d1c; +pm_tx_data_done_process = 0x40001d20; +config_is_cache_tx_buf_enabled = 0x40001d24; +ppMapWaitTxq = 0x40001d28; +ppProcessWaitingQueue = 0x40001d2c; +ppDisableQueue = 0x40001d30; +pm_allow_tx = 0x40001d34; +wdev_is_data_in_rxlist = 0x40001d38; +ppProcTxCallback = 0x40001d3c; +pm_is_open = 0x40001d40; +pm_wake_up = 0x40001d44; +pm_wake_done = 0x40001d48; +pm_disable_disconnected_sleep_delay_timer = 0x40001d4c; +pm_enable_disconnected_sleep_delay_timer = 0x40001d50; +hal_mac_get_txq_state = 0x40001d54; +hal_mac_clr_txq_state = 0x40001d58; +hal_mac_tx_set_cca = 0x40001d5c; +hal_mac_set_txq_invalid = 0x40001d60; +hal_mac_txq_disable = 0x40001d64; +hal_mac_is_txq_enabled = 0x40001d68; +hal_mac_get_txq_pmd = 0x40001d6c; +lmacDiscardFrameExchangeSequence = 0x40001d70; +lmacDisableTransmit = 0x40001d74; +lmacProcessTxTimeout = 0x40001d78; +lmacProcessTxSuccess = 0x40001d7c; +lmacProcessCollision = 0x40001d80; +lmacProcessTxRtsError = 0x40001d84; +lmacProcessCtsTimeout = 0x40001d88; +lmacProcessTxComplete = 0x40001d8c; +lmacProcessAckTimeout = 0x40001d90; +lmacProcessTxError = 0x40001d94; +lmacProcessTxseckiderr = 0x40001d98; +rcReachRetryLimit = 0x40001d9c; +lmacProcessShortRetryFail = 0x40001da0; +lmacEndRetryAMPDUFail = 0x40001da4; +ppFillAMPDUBar = 0x40001da8; +rcGetRate = 0x40001dac; +ppReSendBar = 0x40001db0; +lmacProcessLongRetryFail = 0x40001db4; +lmacRetryTxFrame = 0x40001db8; +lmacProcessCollisions_task = 0x40001dbc; +lmacProcessTxopQComplete = 0x40001dc0; +lmacInitAc = 0x40001dc4; +lmacInit = 0x40001dc8; +mac_tx_set_txop_q = 0x40001dcc; +hal_init = 0x40001dd0; +hal_mac_rx_set_policy = 0x40001dd4; +hal_mac_set_bssid = 0x40001dd8; +mac_rx_policy_init = 0x40001ddc; +mac_txrx_init = 0x40001de0; +mac_rxbuf_init = 0x40001de4; +mac_last_rxbuf_init = 0x40001de8; +hal_attenna_init = 0x40001dec; +hal_timer_update_by_rtc = 0x40001df0; +hal_coex_pti_init = 0x40001df4; +lmac_stop_hw_txq = 0x40001df8; +ppDirectRecycleAmpdu = 0x40001dfc; +esp_wifi_internal_set_rts = 0x40001e00; +esp_wifi_internal_get_rts = 0x40001e04; +ppTxFragmentProc = 0x40001e08; +esf_buf_setup = 0x40001e0c; +hal_agreement_add_rx_ba = 0x40001e10; +hal_agreement_del_rx_ba = 0x40001e14; +hal_crypto_set_key_entry = 0x40001e18; +hal_crypto_get_key_entry = 0x40001e1c; +hal_crypto_clr_key_entry = 0x40001e20; +config_get_wifi_task_stack_size = 0x40001e24; +pp_create_task = 0x40001e28; +hal_set_sta_tsf_wakeup = 0x40001e2c; +hal_set_rx_beacon_pti = 0x40001e30; +pm_start = 0x40001e34; +pm_stop = 0x40001e38; +hal_disable_sta_tbtt = 0x40001e3c; +ppCalTxopDur = 0x40001e40; +wDev_IndicateCtrlFrame = 0x40001e44; +hal_enable_sta_tbtt = 0x40001e48; +hal_set_sta_tbtt = 0x40001e4c; +pm_update_next_tbtt = 0x40001e50; +pm_set_sleep_type = 0x40001e54; +wDev_Rxbuf_Init = 0x40001e58; +wDev_Rxbuf_Deinit = 0x40001e5c; +ppCalTkipMic = 0x40001e60; +wDev_SnifferRxData = 0x40001e64; +hal_crypto_enable = 0x40001e68; +hal_crypto_disable = 0x40001e6c; +wDev_Insert_KeyEntry = 0x40001e70; +wDev_remove_KeyEntry = 0x40001e74; +rc_enable_trc = 0x40001e78; +rc_set_per_conn_fix_rate = 0x40001e7c; +wdev_csi_rx_process = 0x40001e80; +wDev_SnifferRxAmpdu = 0x40001e84; +hal_mac_tsf_reset = 0x40001e88; +dbg_lmac_statis_dump = 0x40001e8c; +dbg_lmac_rxtx_statis_dump = 0x40001e90; +dbg_lmac_hw_statis_dump = 0x40001e94; +dbg_lmac_diag_statis_dump = 0x40001e98; +dbg_lmac_ps_statis_dump = 0x40001e9c; +pp_timer_do_process = 0x40001ea0; +rcUpdateAMPDUParam = 0x40001ea4; +rcUpdatePhyMode = 0x40001ea8; +rcGetHighestRateIdx = 0x40001eac; +pm_tx_null_data_done_process = 0x40001eb0; +pm_tx_data_process = 0x40001eb4; +pm_attach = 0x40001eb8; +pm_coex_schm_process = 0x40001ebc; +ppInitTxq = 0x40001ec0; +pp_attach = 0x40001ec4; +pp_deattach = 0x40001ec8; +pm_on_probe_resp_rx = 0x40001ecc; +hal_set_sta_tsf = 0x40001ed0; +ic_update_sta_tsf = 0x40001ed4; +ic_tx_pkt = 0x40001ed8; +pm_send_probe_stop = 0x40001edc; +pm_send_probe_start = 0x40001ee0; +pm_on_coex_schm_process_restart = 0x40001ee4; +hal_mac_set_rxq_policy = 0x40001ee8; +hal_sniffer_enable = 0x40001eec; +hal_sniffer_disable = 0x40001ef0; +hal_sniffer_rx_set_promis = 0x40001ef4; +hal_sniffer_rx_clr_statistics = 0x40001ef8; +hal_sniffer_set_promis_misc_pkt = 0x40001efc; +tsf_hal_set_tsf_enable = 0x40001f00; +tsf_hal_set_tsf_disable = 0x40001f04; +tsf_hal_is_tsf_enabled = 0x40001f08; +tsf_hal_set_modem_wakeup_early_time = 0x40001f0c; +tsf_hal_get_counter_value = 0x40001f10; +tsf_hal_set_counter_value = 0x40001f14; +tsf_hal_get_time = 0x40001f18; +tsf_hal_set_time = 0x40001f1c; +tsf_hal_set_tbtt_enable = 0x40001f20; +tsf_hal_set_tbtt_disable = 0x40001f24; +tsf_hal_set_tbtt_intr_enable = 0x40001f28; +tsf_hal_set_tbtt_intr_disable = 0x40001f2c; +tsf_hal_set_tbtt_soc_wakeup_enable = 0x40001f30; +tsf_hal_set_tbtt_soc_wakeup_disable = 0x40001f34; +tsf_hal_set_tbtt_start_time = 0x40001f38; +tsf_hal_set_tbtt_early_time = 0x40001f3c; +tsf_hal_set_tbtt_interval = 0x40001f40; +tsf_hal_get_tbtt_interval = 0x40001f44; +tsf_hal_set_timer_enable = 0x40001f48; +tsf_hal_set_timer_disable = 0x40001f4c; +tsf_hal_set_timer_target = 0x40001f50; +tsf_hal_get_timer_target = 0x40001f54; +tsf_hal_set_timer_intr_enable = 0x40001f58; +tsf_hal_set_timer_intr_disable = 0x40001f5c; +tsf_hal_set_timer_soc_wakeup_enable = 0x40001f60; +tsf_hal_set_timer_soc_wakeup_disable = 0x40001f64; +pm_disconnected_wake = 0x40001f68; +pm_get_connectionless_status = 0x40001f6c; +pm_update_by_connectionless_status = 0x40001f70; +pm_connectionless_wake_interval_timeout_process = 0x40001f74; +pm_connectionless_wake_window_timeout_process = 0x40001f78; +/* Data (.data, .bss, .rodata) */ +our_instances_ptr = 0x3ff4fbbc; +pTxRx = 0x3fcdfdec; +lmacConfMib_ptr = 0x3fcdfde8; +our_wait_eb = 0x3fcdfde4; +our_tx_eb = 0x3fcdfde0; +pp_wdev_funcs = 0x3fcdfddc; +g_osi_funcs_p = 0x3fcdfdd8; +wDevCtrl_ptr = 0x3fcdfdd4; +g_wdev_last_desc_reset_ptr = 0x3ff4fbb8; +wDevMacSleep_ptr = 0x3fcdfdd0; +g_lmac_cnt_ptr = 0x3fcdfdcc; +our_controls_ptr = 0x3ff4fbb4; +pp_sig_cnt_ptr = 0x3fcdfdc8; +g_eb_list_desc_ptr = 0x3fcdfdc4; +s_fragment_ptr = 0x3fcdfdc0; +if_ctrl_ptr = 0x3fcdfdbc; +g_intr_lock_mux = 0x3fcdfdb8; +g_wifi_global_lock = 0x3fcdfdb4; +s_wifi_queue = 0x3fcdfdb0; +pp_task_hdl = 0x3fcdfdac; +s_pp_task_create_sem = 0x3fcdfda8; +s_pp_task_del_sem = 0x3fcdfda4; +g_wifi_menuconfig_ptr = 0x3fcdfda0; +xphyQueue = 0x3fcdfd9c; +ap_no_lr_ptr = 0x3fcdfd98; +rc11BSchedTbl_ptr = 0x3fcdfd94; +rc11NSchedTbl_ptr = 0x3fcdfd90; +rcLoRaSchedTbl_ptr = 0x3fcdfd8c; +BasicOFDMSched_ptr = 0x3fcdfd88; +trc_ctl_ptr = 0x3fcdfd84; +g_pm_cnt_ptr = 0x3fcdfd80; +g_pm_ptr = 0x3fcdfd7c; +g_pm_cfg_ptr = 0x3fcdfd78; +g_esp_mesh_quick_funcs_ptr = 0x3fcdfd74; +g_txop_queue_status_ptr = 0x3fcdfd70; +g_mac_sleep_en_ptr = 0x3fcdfd6c; +g_mesh_is_root_ptr = 0x3fcdfd68; +g_mesh_topology_ptr = 0x3fcdfd64; +g_mesh_init_ps_type_ptr = 0x3fcdfd60; +g_mesh_is_started_ptr = 0x3fcdfd5c; +g_config_func = 0x3fcdfd58; +g_net80211_tx_func = 0x3fcdfd54; +g_timer_func = 0x3fcdfd50; +s_michael_mic_failure_cb = 0x3fcdfd4c; +wifi_sta_rx_probe_req = 0x3fcdfd48; +g_tx_done_cb_func = 0x3fcdfd44; +g_per_conn_trc = 0x3fcdfd28; +s_encap_amsdu_func = 0x3fcdfd24; +bars = 0x3fcdfc84; +eb_txdesc_space = 0x3fcdfbf4; +eb_space = 0x3fcdfb54; +g_pd_mac_in_light_sleep = 0x3fcdfb50; +s_fix_rate_mask = 0x3fcdfb4c; +s_fix_rate = 0x3fcdfb44; +g_wdev_csi_rx = 0x3fcdfb40; +g_wdev_csi_rx_ctx = 0x3fcdfb3c; +BcnSendTick = 0x3fcdfb38; +g_pp_timer_info_ptr = 0x3fcdfb34; +rcP2P11NSchedTbl_ptr = 0x3fcdfb30; +rcP2P11GSchedTbl_ptr = 0x3fcdfb2c; +rc11GSchedTbl_ptr = 0x3fcdfb28; + + +/*************************************** + Group rom_net80211 + ***************************************/ + +/* Functions */ +esp_net80211_rom_version_get = 0x40001f7c; +ampdu_dispatch = 0x40001f80; +ampdu_dispatch_all = 0x40001f84; +ampdu_dispatch_as_many_as_possible = 0x40001f88; +ampdu_dispatch_movement = 0x40001f8c; +ampdu_dispatch_upto = 0x40001f90; +chm_is_at_home_channel = 0x40001f94; +cnx_node_is_existing = 0x40001f98; +cnx_node_search = 0x40001f9c; +ic_ebuf_recycle_rx = 0x40001fa0; +ic_ebuf_recycle_tx = 0x40001fa4; +ic_reset_rx_ba = 0x40001fa8; +ieee80211_align_eb = 0x40001fac; +ieee80211_ampdu_reorder = 0x40001fb0; +ieee80211_ampdu_start_age_timer = 0x40001fb4; +ieee80211_encap_esfbuf = 0x40001fb8; +ieee80211_is_tx_allowed = 0x40001fbc; +ieee80211_output_pending_eb = 0x40001fc0; +ieee80211_output_process = 0x40001fc4; +ieee80211_set_tx_desc = 0x40001fc8; +sta_input = 0x40001fcc; +wifi_get_macaddr = 0x40001fd0; +wifi_rf_phy_disable = 0x40001fd4; +wifi_rf_phy_enable = 0x40001fd8; +ic_ebuf_alloc = 0x40001fdc; +ieee80211_classify = 0x40001fe0; +ieee80211_copy_eb_header = 0x40001fe4; +ieee80211_recycle_cache_eb = 0x40001fe8; +ieee80211_search_node = 0x40001fec; +roundup2 = 0x40001ff0; +ieee80211_crypto_encap = 0x40001ff4; +ieee80211_crypto_decap = 0x40001ff8; +ieee80211_decap = 0x40001ffc; +ieee80211_set_tx_pti = 0x40002000; +wifi_is_started = 0x40002004; +ieee80211_gettid = 0x40002008; +ieee80211_ccmp_decrypt = 0x4000200c; +ieee80211_ccmp_encrypt = 0x40002010; +ccmp_encap = 0x40002014; +ccmp_decap = 0x40002018; +tkip_encap = 0x4000201c; +tkip_decap = 0x40002020; +wep_encap = 0x40002024; +wep_decap = 0x40002028; +dbg_hmac_rxtx_statis_dump = 0x4000202c; +dbg_hmac_statis_dump = 0x40002030; +ieee80211_send_action_vendor_spec = 0x40002034; +ieee80211_send_mgmt = 0x40002038; +ieee80211_auth_construct = 0x4000203c; +ieee80211_deauth_construct = 0x40002040; +ieee80211_disassoc_construct = 0x40002044; +ieee80211_vnd_lora_ie_size = 0x40002048; +ieee80211_vnd_ie_size = 0x4000204c; +ieee80211_add_ssid = 0x40002050; +ieee80211_add_rates = 0x40002054; +ieee80211_add_xrates = 0x40002058; +ieee80211_is_ht_cipher = 0x4000205c; +ieee80211_assoc_req_construct = 0x40002060; +ieee80211_assoc_resp_construct = 0x40002064; +ieee80211_setup_lr_rates = 0x40002068; +ieee80211_ht_node_init = 0x4000206c; +ieee80211_is_support_rate = 0x40002070; +ieee80211_setup_rates = 0x40002074; +ieee80211_is_lr_only = 0x40002078; +ieee80211_setup_phy_mode = 0x4000207c; +ieee80211_sta_is_connected = 0x40002080; +current_task_is_wifi_task = 0x40002084; +wifi_get_init_state = 0x40002088; +ieee80211_timer_process = 0x4000208c; +cnx_coexist_timeout = 0x40002090; +sta_recv_mgmt = 0x40002094; +ieee80211_send_setup = 0x40002098; +ieee80211_send_probereq = 0x4000209c; +sta_auth_open = 0x400020a0; +sta_auth_shared = 0x400020a4; +sta_auth_sae = 0x400020a8; +cnx_coexist_timeout_process = 0x400020ac; +ieee80211_alloc_challenge = 0x400020b0; +cnx_assoc_timeout = 0x400020b4; +ieee80211_vnd_ie_set = 0x400020b8; +ieee80211_vnd_lora_ie_set = 0x400020bc; +ieee80211_add_wme_param = 0x400020c0; +ieee80211_add_dsparams = 0x400020c4; +ieee80211_add_csa = 0x400020c8; +ieee80211_add_extcap = 0x400020cc; +ieee80211_regdomain_get_country = 0x400020d0; +ieee80211_add_countryie = 0x400020d4; +ieee80211_alloc_proberesp = 0x400020d8; +ieee80211_amsdu_adjust_head = 0x400020dc; +ieee80211_amsdu_adjust_last_length = 0x400020e0; +ieee80211_amsdu_send_check = 0x400020e4; +ieee80211_amsdu_encap_check = 0x400020e8; +ieee80211_amsdu_length_check = 0x400020ec; +ieee80211_encap_amsdu = 0x400020f0; +ieee80211_output_raw_process = 0x400020f4; +esp_wifi_80211_tx = 0x400020f8; +ieee80211_raw_frame_sanity_check = 0x400020fc; +ieee80211_crypto_aes_128_cmac_encrypt = 0x40002100; +ieee80211_crypto_aes_128_cmac_decrypt = 0x40002104; +ieee80211_alloc_tx_buf = 0x40002108; +ieee80211_output_do = 0x4000210c; +ieee80211_send_nulldata = 0x40002110; +ieee80211_setup_robust_mgmtframe = 0x40002114; +ieee80211_mgmt_output = 0x40002118; +ieee80211_encap_null_data = 0x4000211c; +ieee80211_send_deauth = 0x40002120; +ieee80211_alloc_deauth = 0x40002124; +ieee80211_send_proberesp = 0x40002128; +ieee80211_tx_mgt_cb = 0x4000212c; +ieee80211_getcapinfo = 0x40002130; +sta_rx_csa = 0x40002134; +sta_send_sa_query_req = 0x40002138; +sta_send_sa_query_resp = 0x4000213c; +sta_recv_sa_query_req = 0x40002140; +sta_recv_sa_query_resp = 0x40002144; +ieee80211_parse_beacon = 0x40002148; +ieee80211_set_max_rate = 0x4000214c; +ic_set_sta = 0x40002150; +ieee80211_match_security = 0x40002154; +ieee80211_parse_wpa = 0x40002158; +ieee80211_parse_rsn = 0x4000215c; +ieee80211_add_assoc_req_ies = 0x40002160; +ieee80211_add_probe_req_ies = 0x40002164; +/* Data (.data, .bss, .rodata) */ +net80211_funcs = 0x3fcdfb24; +g_scan = 0x3fcdfb20; +g_chm = 0x3fcdfb1c; +g_ic_ptr = 0x3fcdfb18; +g_hmac_cnt_ptr = 0x3fcdfaf4; +g_tx_cacheq_ptr = 0x3fcdfb14; +s_netstack_free = 0x3fcdfb10; +mesh_rxcb = 0x3fcdfb0c; +sta_rxcb = 0x3fcdfb08; +ccmp_ptr = 0x3fcdfb04; +s_wifi_nvs_ptr = 0x3fcdfb00; +tkip_ptr = 0x3fcdfafc; +wep_ptr = 0x3fcdfaf8; +g_hmac_cnt_ptr = 0x3fcdfaf4; +g_misc_nvs = 0x3fcdfaf0; +s_wifi_init_state = 0x3fcdfac0; +s_wifi_task_hdl = 0x3fcdfaec; +in_rssi_adjust = 0x3fcdfae8; +rssi_saved = 0x3fcdfae0; +rssi_index = 0x3fcdfadc; +s_sa_query_retries = 0x3fcdfad8; +s_sa_query_success = 0x3fcdfad5; +g_sta_connected_flag = 0x3fcdfad4; +wpa_crypto_funcs_ptr = 0x3fcdfad0; +s_netstack_ref = 0x3fcdfacc; +sta_csa_timer_ptr = 0x3fcdfac8; +s_trans_id = 0x3fcdfac4; + + +/*************************************** + Group rom_coexist + ***************************************/ + +/* Functions */ +esp_coex_rom_version_get = 0x40002168; +coex_bt_release = 0x4000216c; +coex_bt_request = 0x40002170; +coex_core_ble_conn_dyn_prio_get = 0x40002174; +coex_core_event_duration_get = 0x40002178; +coex_core_pti_get = 0x4000217c; +coex_core_release = 0x40002180; +coex_core_request = 0x40002184; +coex_core_status_get = 0x40002188; +coex_core_timer_idx_get = 0x4000218c; +coex_event_duration_get = 0x40002190; +coex_hw_timer_disable = 0x40002194; +coex_hw_timer_enable = 0x40002198; +coex_hw_timer_set = 0x4000219c; +coex_schm_interval_set = 0x400021a0; +coex_schm_lock = 0x400021a4; +coex_schm_unlock = 0x400021a8; +coex_status_get = 0x400021ac; +coex_wifi_release = 0x400021b0; +esp_coex_ble_conn_dynamic_prio_get = 0x400021b4; +coex_hw_timer_tick_get = 0x400021b8; +/* Data (.data, .bss, .rodata) */ +coex_env_ptr = 0x3fcdfabc; +coex_pti_tab_ptr = 0x3fcdfab8; +coex_schm_env_ptr = 0x3fcdfab4; +coexist_funcs = 0x3fcdfab0; +g_coa_funcs_p = 0x3fcdfaac; +g_coex_param_ptr = 0x3fcdfaa8; + + +/*************************************** + Group rom_phy + ***************************************/ + +/* Functions */ +phy_param_addr = 0x400021bc; +phy_get_romfuncs = 0x400021c0; +chip729_phyrom_version = 0x400021c4; +chip729_phyrom_version_num = 0x400021c8; +rom_get_rc_dout = 0x400021cc; +rc_cal = 0x400021d0; +phy_analog_delay_cal = 0x400021d4; +phy_rx_rifs_en = 0x400021d8; +phy_current_level_set = 0x400021dc; +phy_bbpll_en_usb = 0x400021e0; +phy_bt_power_track = 0x400021e4; +phy_xpd_tsens = 0x400021e8; +bb_wdt_rst_enable = 0x400021ec; +bb_wdt_int_enable = 0x400021f0; +bb_wdt_timeout_clear = 0x400021f4; +bb_wdt_get_status = 0x400021f8; +rom_enter_critical_phy = 0x400021fc; +rom_exit_critical_phy = 0x40002200; +rom_bb_bss_cbw40 = 0x40002204; +rom_set_chan_reg = 0x40002208; +abs_temp = 0x4000220c; +set_chan_cal_interp = 0x40002210; +loopback_mode_en = 0x40002214; +get_data_sat = 0x40002218; +phy_byte_to_word = 0x4000221c; +phy_get_rx_freq = 0x40002220; +i2c_master_reset = 0x40002224; +chan14_mic_enable = 0x40002228; +chan14_mic_cfg = 0x4000222c; +set_adc_rand = 0x40002230; +phy_set_most_tpw = 0x40002234; +phy_get_most_tpw = 0x40002238; +esp_tx_state_out = 0x4000223c; +phy_get_adc_rand = 0x40002240; +phy_internal_delay = 0x40002244; +phy_ftm_comp = 0x40002248; +phy_11p_set = 0x4000224c; +phy_freq_mem_backup = 0x40002250; +ant_dft_cfg = 0x40002254; +ant_wifitx_cfg = 0x40002258; +ant_wifirx_cfg = 0x4000225c; +ant_bttx_cfg = 0x40002260; +ant_btrx_cfg = 0x40002264; +phy_chan_dump_cfg = 0x40002268; +phy_enable_low_rate = 0x4000226c; +phy_disable_low_rate = 0x40002270; +phy_dig_reg_backup = 0x40002274; +phy_chan_filt_set = 0x40002278; +phy_rx11blr_cfg = 0x4000227c; +set_cca = 0x40002280; +set_rx_sense = 0x40002284; +rx_gain_force = 0x40002288; +rom_phy_en_hw_set_freq = 0x4000228c; +rom_phy_dis_hw_set_freq = 0x40002290; +wr_rf_freq_mem = 0x40002294; +freq_i2c_write_set = 0x40002298; +write_pll_cap_mem = 0x4000229c; +pll_dac_mem_update = 0x400022a0; +pll_cap_mem_update = 0x400022a4; +get_rf_freq_cap = 0x400022a8; +get_rf_freq_init = 0x400022ac; +freq_get_i2c_data = 0x400022b0; +freq_i2c_data_write = 0x400022b4; +set_chan_freq_hw_init = 0x400022b8; +set_chan_freq_sw_start = 0x400022bc; +rom_get_i2c_read_mask = 0x400022c0; +rom_get_i2c_mst0_mask = 0x400022c4; +rom_get_i2c_hostid = 0x400022c8; +rom_chip_i2c_readReg_org = 0x400022cc; +rom_chip_i2c_readReg = 0x400022d0; +rom_i2c_paral_set_mst0 = 0x400022d4; +rom_i2c_paral_set_read = 0x400022d8; +rom_i2c_paral_read = 0x400022dc; +rom_i2c_paral_write = 0x400022e0; +rom_i2c_paral_write_num = 0x400022e4; +rom_i2c_paral_write_mask = 0x400022e8; +rom_i2c_readReg = 0x400022ec; +rom_chip_i2c_writeReg = 0x400022f0; +rom_i2c_writeReg = 0x400022f4; +rom_i2c_readReg_Mask = 0x400022f8; +rom_i2c_writeReg_Mask = 0x400022fc; +rom_set_txcap_reg = 0x40002300; +i2c_sar2_init_code = 0x40002304; +phy_i2c_init1 = 0x40002308; +phy_i2c_init2 = 0x4000230c; +phy_get_i2c_data = 0x40002310; +bias_reg_set = 0x40002314; +i2c_rc_cal_set = 0x40002318; +i2c_bbpll_set = 0x4000231c; +rom_phy_xpd_rf = 0x40002320; +phy_wakeup_init_rom = 0x40002324; +register_chipv7_phy_init_param = 0x40002328; +phy_reg_init = 0x4000232c; +phy_close_rf_rom = 0x40002330; +rom_pbus_force_mode = 0x40002334; +rom_pbus_rd_addr = 0x40002338; +rom_pbus_rd_shift = 0x4000233c; +rom_pbus_force_test = 0x40002340; +rom_pbus_rd = 0x40002344; +rom_pbus_debugmode = 0x40002348; +rom_pbus_workmode = 0x4000234c; +rom_pbus_set_rxgain = 0x40002350; +rom_pbus_xpd_rx_off = 0x40002354; +rom_pbus_xpd_rx_on = 0x40002358; +rom_pbus_xpd_tx_off = 0x4000235c; +rom_pbus_xpd_tx_on = 0x40002360; +rom_pbus_set_dco = 0x40002364; +rom_set_loopback_gain = 0x40002368; +rom_txcal_debuge_mode = 0x4000236c; +rom_txcal_work_mode = 0x40002370; +set_pbus_mem = 0x40002374; +rom_pwdet_sar2_init = 0x40002378; +rom_en_pwdet = 0x4000237c; +rom_get_sar_sig_ref = 0x40002380; +rom_pwdet_tone_start = 0x40002384; +rom_get_tone_sar_dout = 0x40002388; +rom_get_fm_sar_dout = 0x4000238c; +rom_txtone_linear_pwr = 0x40002390; +rom_get_power_db = 0x40002394; +rom_meas_tone_pwr_db = 0x40002398; +rom_pkdet_vol_start = 0x4000239c; +rom_read_sar_dout = 0x400023a0; +rom_read_sar2_code = 0x400023a4; +rom_get_sar2_vol = 0x400023a8; +rom_get_pll_vol = 0x400023ac; +rom_tx_pwctrl_bg_init = 0x400023b0; +rom_phy_pwdet_always_en = 0x400023b4; +rom_phy_pwdet_onetime_en = 0x400023b8; +linear_to_db = 0x400023bc; +rom_disable_agc = 0x400023c0; +rom_enable_agc = 0x400023c4; +rom_disable_wifi_agc = 0x400023c8; +rom_enable_wifi_agc = 0x400023cc; +rom_write_gain_mem = 0x400023d0; +rom_bb_bss_cbw40_dig = 0x400023d4; +rom_cbw2040_cfg = 0x400023d8; +rom_mac_tx_chan_offset = 0x400023dc; +rom_tx_paon_set = 0x400023e0; +rom_i2cmst_reg_init = 0x400023e4; +rom_bt_gain_offset = 0x400023e8; +rom_fe_reg_init = 0x400023ec; +rom_mac_enable_bb = 0x400023f0; +rom_bb_wdg_cfg = 0x400023f4; +rom_fe_txrx_reset = 0x400023f8; +rom_set_rx_comp = 0x400023fc; +rom_write_chan_freq = 0x40002400; +rom_agc_reg_init = 0x40002404; +rom_bb_reg_init = 0x40002408; +rom_write_txrate_power_offset = 0x4000240c; +rom_open_i2c_xpd = 0x40002410; +rom_txiq_set_reg = 0x40002414; +rom_rxiq_set_reg = 0x40002418; +rom_phy_bbpll_cal = 0x4000241c; +phy_disable_cca = 0x40002420; +phy_enable_cca = 0x40002424; +force_txon = 0x40002428; +set_txclk_en = 0x4000242c; +set_rxclk_en = 0x40002430; +start_tx_tone_step = 0x40002434; +stop_tx_tone = 0x40002438; +bb_wdg_test_en = 0x4000243c; +noise_floor_auto_set = 0x40002440; +read_hw_noisefloor = 0x40002444; +iq_corr_enable = 0x40002448; +bt_tx_dig_gain = 0x4000244c; +wifi_tx_dig_reg = 0x40002450; +wifi_agc_sat_gain = 0x40002454; +phy_ant_init = 0x40002458; +phy_set_bbfreq_init = 0x4000245c; +wifi_fbw_sel = 0x40002460; +phy_rx_sense_set = 0x40002464; +tx_state_set = 0x40002468; +phy_close_pa = 0x4000246c; +bt_filter_reg = 0x40002470; +phy_freq_correct = 0x40002474; +set_pbus_reg = 0x40002478; +wifi_rifs_mode_en = 0x4000247c; +rfagc_disable = 0x40002480; +rom_restart_cal = 0x40002484; +rom_write_rfpll_sdm = 0x40002488; +rom_wait_rfpll_cal_end = 0x4000248c; +rom_rfpll_set_freq = 0x40002490; +rom_rfpll_cap_init_cal = 0x40002494; +rom_set_rfpll_freq = 0x40002498; +rom_write_pll_cap = 0x4000249c; +rom_read_pll_cap = 0x400024a0; +mhz2ieee = 0x400024a4; +chan_to_freq = 0x400024a8; +set_rf_freq_offset = 0x400024ac; +set_channel_rfpll_freq = 0x400024b0; +rfpll_cap_correct = 0x400024b4; +phy_set_freq = 0x400024b8; +correct_rfpll_offset = 0x400024bc; +pll_vol_cal = 0x400024c0; +chip_v7_set_chan_misc = 0x400024c4; +chip_v7_set_chan = 0x400024c8; +chip_v7_set_chan_offset = 0x400024cc; +chip_v7_set_chan_ana = 0x400024d0; +set_chanfreq = 0x400024d4; +rom_rxiq_cover_mg_mp = 0x400024d8; +rom_rfcal_rxiq = 0x400024dc; +rom_get_rfcal_rxiq_data = 0x400024e0; +rom_pbus_rx_dco_cal = 0x400024e4; +rom_rxdc_est_min = 0x400024e8; +rom_pbus_rx_dco_cal_1step = 0x400024ec; +rom_set_lb_txiq = 0x400024f0; +rom_set_rx_gain_cal_iq = 0x400024f4; +rom_set_rx_gain_cal_dc = 0x400024f8; +iq_est_enable = 0x400024fc; +iq_est_disable = 0x40002500; +dc_iq_est = 0x40002504; +set_cal_rxdc = 0x40002508; +rxiq_get_mis = 0x4000250c; +spur_reg_write_one_tone = 0x40002510; +spur_cal = 0x40002514; +spur_coef_cfg = 0x40002518; +gen_rx_gain_table = 0x4000251c; +wr_rx_gain_mem = 0x40002520; +set_rx_gain_param = 0x40002524; +set_rx_gain_table = 0x40002528; +rom_tester_wifi_cali = 0x4000252c; +esp_recover_efuse_data = 0x40002530; +bt_track_pll_cap = 0x40002534; +rfpll_cap_track = 0x40002538; +phy_param_track = 0x4000253c; +txpwr_correct = 0x40002540; +txpwr_cal_track = 0x40002544; +tx_pwctrl_background = 0x40002548; +bt_track_tx_power = 0x4000254c; +wifi_track_tx_power = 0x40002550; +rom_code_to_temp = 0x40002554; +rom_tsens_index_to_dac = 0x40002558; +rom_tsens_index_to_offset = 0x4000255c; +rom_tsens_dac_cal = 0x40002560; +rom_tsens_code_read = 0x40002564; +rom_tsens_temp_read = 0x40002568; +rom_temp_to_power = 0x4000256c; +tsens_read_init = 0x40002570; +get_temp_init = 0x40002574; +rom_txiq_cover = 0x40002578; +rom_rfcal_txiq = 0x4000257c; +rom_get_power_atten = 0x40002580; +rom_tx_pwctrl_init_cal = 0x40002584; +bt_txdc_cal = 0x40002588; +bt_txiq_cal = 0x4000258c; +txiq_cal_init = 0x40002590; +txdc_cal_init = 0x40002594; +txdc_cal_v70 = 0x40002598; +txiq_get_mis_pwr = 0x4000259c; +pwdet_ref_code = 0x400025a0; +pwdet_code_cal = 0x400025a4; +rfcal_txcap = 0x400025a8; +tx_cap_init = 0x400025ac; +rfcal_pwrctrl = 0x400025b0; +tx_pwctrl_init = 0x400025b4; +bt_tx_pwctrl_init = 0x400025b8; +bt_txpwr_freq = 0x400025bc; +rom_txbbgain_to_index = 0x400025c0; +rom_index_to_txbbgain = 0x400025c4; +rom_bt_index_to_bb = 0x400025c8; +rom_bt_bb_to_index = 0x400025cc; +rom_bt_get_tx_gain = 0x400025d0; +rom_get_tx_gain_value = 0x400025d4; +rom_wifi_get_tx_gain = 0x400025d8; +rom_set_tx_gain_mem = 0x400025dc; +rom_get_rate_fcc_index = 0x400025e0; +rom_get_chan_target_power = 0x400025e4; +rom_wifi_tx_dig_gain = 0x400025e8; +rom_wifi_set_tx_gain = 0x400025ec; +rom_bt_set_tx_gain = 0x400025f0; +wifi_11g_rate_chg = 0x400025f4; +bt_chan_pwr_interp = 0x400025f8; +bt_tx_gain_init = 0x400025fc; +/* Data (.data, .bss, .rodata) */ +phy_param_rom = 0x3fcdfaa4; + + +/*************************************** + Group rom_btbb + ***************************************/ + +/* Functions */ +bt_agc_gain_offset = 0x40002600; +bt_agc_gain_max = 0x40002604; +bt_set_rx_comp = 0x40002608; +bt_agc_gain_set = 0x4000260c; +bt_agc_rssi_thresh = 0x40002610; +bt_agc_target_set = 0x40002614; +bt_agc_restart_set = 0x40002618; +bt_agc_recorrect_set = 0x4000261c; +bt_agc_detect_set = 0x40002620; +bt_bb_rx_correlator_set = 0x40002624; +bt_bb_rx_dpo_set = 0x40002628; +bt_bb_rx_filter_sel = 0x4000262c; +bt_bb_rx_set1 = 0x40002630; +bt_bb_v2_rx_set = 0x40002634; +bt_bb_v2_tx_set = 0x40002638; +bt_bb_tx_cca_set = 0x4000263c; +bt_bb_tx_cca_period = 0x40002640; +bt_bb_tx_cca_fifo_reset = 0x40002644; +bt_bb_tx_cca_fifo_empty = 0x40002648; +bt_bb_tx_cca_fifo_full = 0x4000264c; +bt_bb_tx_cca_fifo_count = 0x40002650; +bt_bb_tx_cca_fifo_read = 0x40002654; +coex_pti_v2 = 0x40002658; +bt_bb_set_le_tx_on_delay = 0x4000265c; +bt_bb_set_corr_thresh_le = 0x40002660; + +/* ROM function interface esp8684.rom.mbedtls.ld for esp8684 + * + * + * Generated from ./interface-esp8684.yml md5sum c679b6ed5e9f0a9c3e7b93e5e0f2a1a3 + * + * Compatible with ROM where ECO version equal or greater to 1. + * + * THIS FILE WAS AUTOMATICALLY GENERATED. DO NOT EDIT. + */ + +/*************************************** + Group rom_mbedtls + ***************************************/ + +/* Functions */ +mbedtls_aes_init = 0x40002664; +ssl_write_client_hello = 0x40002668; +ssl_parse_server_hello = 0x4000266c; +ssl_parse_server_key_exchange = 0x40002670; +ssl_parse_certificate_request = 0x40002674; +ssl_parse_server_hello_done = 0x40002678; +ssl_write_client_key_exchange = 0x4000267c; +ssl_write_certificate_verify = 0x40002680; +ssl_parse_new_session_ticket = 0x40002684; +mbedtls_aes_free = 0x40002688; +mbedtls_aes_setkey_enc = 0x4000268c; +mbedtls_aes_setkey_dec = 0x40002690; +mbedtls_aes_crypt_ecb = 0x40002694; +mbedtls_aes_crypt_cbc = 0x40002698; +mbedtls_internal_aes_encrypt = 0x4000269c; +mbedtls_internal_aes_decrypt = 0x400026a0; +mbedtls_asn1_get_len = 0x400026a4; +mbedtls_asn1_get_tag = 0x400026a8; +mbedtls_asn1_get_bool = 0x400026ac; +mbedtls_asn1_get_int = 0x400026b0; +mbedtls_asn1_get_bitstring = 0x400026b4; +mbedtls_asn1_get_bitstring_null = 0x400026b8; +mbedtls_asn1_get_sequence_of = 0x400026bc; +mbedtls_asn1_get_mpi = 0x400026c0; +mbedtls_asn1_get_alg = 0x400026c4; +mbedtls_asn1_get_alg_null = 0x400026c8; +mbedtls_asn1_write_len = 0x400026cc; +mbedtls_asn1_write_tag = 0x400026d0; +mbedtls_asn1_write_mpi = 0x400026d4; +mbedtls_base64_decode = 0x400026d8; +mbedtls_mpi_init = 0x400026dc; +mbedtls_mpi_free = 0x400026e0; +mbedtls_mpi_grow = 0x400026e4; +mbedtls_mpi_shrink = 0x400026e8; +mbedtls_mpi_copy = 0x400026ec; +mbedtls_mpi_safe_cond_assign = 0x400026f0; +mbedtls_mpi_safe_cond_swap = 0x400026f4; +mbedtls_mpi_lset = 0x400026f8; +mbedtls_mpi_get_bit = 0x400026fc; +mbedtls_mpi_set_bit = 0x40002700; +mbedtls_mpi_lsb = 0x40002704; +mbedtls_mpi_bitlen = 0x40002708; +mbedtls_mpi_size = 0x4000270c; +mbedtls_mpi_read_binary = 0x40002710; +mbedtls_mpi_write_binary = 0x40002714; +mbedtls_mpi_shift_l = 0x40002718; +mbedtls_mpi_shift_r = 0x4000271c; +mbedtls_mpi_cmp_abs = 0x40002720; +mbedtls_mpi_cmp_mpi = 0x40002724; +mbedtls_mpi_lt_mpi_ct = 0x40002728; +mbedtls_mpi_cmp_int = 0x4000272c; +mbedtls_mpi_add_abs = 0x40002730; +mbedtls_mpi_sub_abs = 0x40002734; +mbedtls_mpi_add_mpi = 0x40002738; +mbedtls_mpi_sub_mpi = 0x4000273c; +mbedtls_mpi_add_int = 0x40002740; +mbedtls_mpi_sub_int = 0x40002744; +mbedtls_mpi_mul_mpi = 0x40002748; +mbedtls_mpi_mul_int = 0x4000274c; +mbedtls_mpi_div_mpi = 0x40002750; +mbedtls_mpi_div_int = 0x40002754; +mbedtls_mpi_mod_mpi = 0x40002758; +mbedtls_mpi_mod_int = 0x4000275c; +mbedtls_mpi_exp_mod = 0x40002760; +mbedtls_mpi_fill_random = 0x40002764; +mbedtls_mpi_gcd = 0x40002768; +mbedtls_mpi_inv_mod = 0x4000276c; +mbedtls_mpi_is_prime_ext = 0x40002770; +mbedtls_ccm_star_encrypt_and_tag = 0x40002774; +mbedtls_ccm_star_auth_decrypt = 0x40002778; +mbedtls_cipher_init = 0x4000277c; +mbedtls_cipher_set_padding_mode = 0x40002780; +mbedtls_cipher_reset = 0x40002784; +mbedtls_cipher_finish = 0x40002788; +mbedtls_cipher_crypt = 0x4000278c; +mbedtls_cipher_cmac_starts = 0x40002790; +mbedtls_cipher_cmac_update = 0x40002794; +mbedtls_cipher_cmac_finish = 0x40002798; +mbedtls_ctr_drbg_init = 0x4000279c; +mbedtls_ctr_drbg_seed = 0x400027a0; +mbedtls_ctr_drbg_free = 0x400027a4; +mbedtls_ctr_drbg_reseed = 0x400027a8; +mbedtls_ctr_drbg_random_with_add = 0x400027ac; +mbedtls_ctr_drbg_random = 0x400027b0; +mbedtls_dhm_init = 0x400027b4; +mbedtls_dhm_read_params = 0x400027b8; +mbedtls_dhm_make_public = 0x400027bc; +mbedtls_dhm_calc_secret = 0x400027c0; +mbedtls_dhm_free = 0x400027c4; +mbedtls_ecdh_init = 0x400027c8; +mbedtls_ecdh_setup = 0x400027cc; +mbedtls_ecdh_free = 0x400027d0; +mbedtls_ecdh_read_params = 0x400027d4; +mbedtls_ecdh_get_params = 0x400027d8; +mbedtls_ecdh_make_public = 0x400027dc; +mbedtls_ecdh_calc_secret = 0x400027e0; +mbedtls_ecdh_enable_restart = 0x400027e4; +mbedtls_ecdsa_write_signature = 0x400027e8; +mbedtls_ecdsa_write_signature_restartable = 0x400027ec; +mbedtls_ecdsa_read_signature = 0x400027f0; +mbedtls_ecdsa_read_signature_restartable = 0x400027f4; +mbedtls_ecdsa_from_keypair = 0x400027f8; +mbedtls_ecdsa_init = 0x400027fc; +mbedtls_ecdsa_free = 0x40002800; +mbedtls_ecdsa_restart_init = 0x40002804; +mbedtls_ecdsa_restart_free = 0x40002808; +mbedtls_ecjpake_init = 0x4000280c; +mbedtls_ecjpake_check = 0x40002810; +mbedtls_ecjpake_write_round_one = 0x40002814; +mbedtls_ecjpake_read_round_one = 0x40002818; +mbedtls_ecjpake_write_round_two = 0x4000281c; +mbedtls_ecjpake_read_round_two = 0x40002820; +mbedtls_ecjpake_derive_secret = 0x40002824; +mbedtls_ecjpake_free = 0x40002828; +mbedtls_ecp_check_budget = 0x4000282c; +mbedtls_ecp_restart_is_enabled = 0x40002830; +mbedtls_ecp_curve_list = 0x40002834; +mbedtls_ecp_grp_id_list = 0x40002838; +mbedtls_ecp_curve_info_from_grp_id = 0x4000283c; +mbedtls_ecp_curve_info_from_tls_id = 0x40002840; +mbedtls_ecp_point_init = 0x40002844; +mbedtls_ecp_group_init = 0x40002848; +mbedtls_ecp_keypair_init = 0x4000284c; +mbedtls_ecp_point_free = 0x40002850; +mbedtls_ecp_group_free = 0x40002854; +mbedtls_ecp_keypair_free = 0x40002858; +mbedtls_ecp_restart_init = 0x4000285c; +mbedtls_ecp_restart_free = 0x40002860; +mbedtls_ecp_copy = 0x40002864; +mbedtls_ecp_group_copy = 0x40002868; +mbedtls_ecp_set_zero = 0x4000286c; +mbedtls_ecp_is_zero = 0x40002870; +mbedtls_ecp_point_cmp = 0x40002874; +mbedtls_ecp_point_write_binary = 0x40002878; +mbedtls_ecp_point_read_binary = 0x4000287c; +mbedtls_ecp_tls_read_point = 0x40002880; +mbedtls_ecp_tls_write_point = 0x40002884; +mbedtls_ecp_group_load = 0x40002888; +mbedtls_ecp_tls_read_group = 0x4000288c; +mbedtls_ecp_tls_read_group_id = 0x40002890; +mbedtls_ecp_tls_write_group = 0x40002894; +mbedtls_ecp_mul = 0x40002898; +mbedtls_ecp_mul_restartable = 0x4000289c; +mbedtls_ecp_muladd = 0x400028a0; +mbedtls_ecp_muladd_restartable = 0x400028a4; +mbedtls_ecp_check_pubkey = 0x400028a8; +mbedtls_ecp_check_privkey = 0x400028ac; +mbedtls_ecp_gen_privkey = 0x400028b0; +mbedtls_ecp_gen_keypair_base = 0x400028b4; +mbedtls_ecp_check_pub_priv = 0x400028b8; +mbedtls_entropy_add_source = 0x400028bc; +mbedtls_entropy_func = 0x400028c0; +mbedtls_gcm_crypt_and_tag = 0x400028c4; +mbedtls_gcm_starts = 0x400028c8; +mbedtls_gcm_update = 0x400028cc; +mbedtls_gcm_finish = 0x400028d0; +mbedtls_hmac_drbg_init = 0x400028d4; +mbedtls_hmac_drbg_seed_buf = 0x400028d8; +mbedtls_hmac_drbg_update_ret = 0x400028dc; +mbedtls_hmac_drbg_reseed = 0x400028e0; +mbedtls_hmac_drbg_random_with_add = 0x400028e4; +mbedtls_hmac_drbg_random = 0x400028e8; +mbedtls_hmac_drbg_free = 0x400028ec; +mbedtls_md_list = 0x400028f0; +mbedtls_md_init = 0x400028f4; +mbedtls_md_free = 0x400028f8; +mbedtls_md_setup = 0x400028fc; +mbedtls_md_clone = 0x40002900; +mbedtls_md_get_size = 0x40002904; +mbedtls_md_get_type = 0x40002908; +mbedtls_md_starts = 0x4000290c; +mbedtls_md_update = 0x40002910; +mbedtls_md_finish = 0x40002914; +mbedtls_md = 0x40002918; +mbedtls_md_hmac_starts = 0x4000291c; +mbedtls_md_hmac_update = 0x40002920; +mbedtls_md_hmac_finish = 0x40002924; +mbedtls_md_hmac_reset = 0x40002928; +mbedtls_oid_get_x509_ext_type = 0x4000292c; +mbedtls_oid_get_pk_alg = 0x40002930; +mbedtls_oid_get_ec_grp = 0x40002934; +mbedtls_oid_get_sig_alg = 0x40002938; +mbedtls_oid_get_md_alg = 0x4000293c; +mbedtls_oid_get_md_hmac = 0x40002940; +mbedtls_oid_get_oid_by_md = 0x40002944; +mbedtls_oid_get_cipher_alg = 0x40002948; +mbedtls_oid_get_pkcs12_pbe_alg = 0x4000294c; +mbedtls_pem_init = 0x40002950; +mbedtls_pem_free = 0x40002954; +mbedtls_pkcs12_pbe_sha1_rc4_128 = 0x40002958; +mbedtls_pkcs12_pbe = 0x4000295c; +mbedtls_pkcs12_derivation = 0x40002960; +mbedtls_pkcs5_pbes2 = 0x40002964; +mbedtls_pkcs5_pbkdf2_hmac = 0x40002968; +mbedtls_pk_info_from_type = 0x4000296c; +mbedtls_pk_init = 0x40002970; +mbedtls_pk_free = 0x40002974; +mbedtls_pk_restart_init = 0x40002978; +mbedtls_pk_restart_free = 0x4000297c; +mbedtls_pk_setup = 0x40002980; +mbedtls_pk_can_do = 0x40002984; +mbedtls_pk_verify = 0x40002988; +mbedtls_pk_verify_restartable = 0x4000298c; +mbedtls_pk_verify_ext = 0x40002990; +mbedtls_pk_sign_restartable = 0x40002994; +mbedtls_pk_encrypt = 0x40002998; +mbedtls_pk_get_type = 0x4000299c; +mbedtls_pk_parse_subpubkey = 0x400029a0; +mbedtls_rsa_init = 0x400029a4; +mbedtls_rsa_import = 0x400029a8; +mbedtls_rsa_import_raw = 0x400029ac; +mbedtls_rsa_complete = 0x400029b0; +mbedtls_rsa_set_padding = 0x400029b4; +mbedtls_rsa_get_len = 0x400029b8; +mbedtls_rsa_check_pubkey = 0x400029bc; +mbedtls_rsa_check_privkey = 0x400029c0; +mbedtls_rsa_check_pub_priv = 0x400029c4; +mbedtls_rsa_public = 0x400029c8; +mbedtls_rsa_private = 0x400029cc; +mbedtls_rsa_pkcs1_encrypt = 0x400029d0; +mbedtls_rsa_rsaes_pkcs1_v15_encrypt = 0x400029d4; +mbedtls_rsa_rsaes_oaep_encrypt = 0x400029d8; +mbedtls_rsa_pkcs1_decrypt = 0x400029dc; +mbedtls_rsa_rsaes_pkcs1_v15_decrypt = 0x400029e0; +mbedtls_rsa_rsaes_oaep_decrypt = 0x400029e4; +mbedtls_rsa_pkcs1_sign = 0x400029e8; +mbedtls_rsa_rsassa_pkcs1_v15_sign = 0x400029ec; +mbedtls_rsa_rsassa_pss_sign = 0x400029f0; +mbedtls_rsa_pkcs1_verify = 0x400029f4; +mbedtls_rsa_rsassa_pkcs1_v15_verify = 0x400029f8; +mbedtls_rsa_rsassa_pss_verify = 0x400029fc; +mbedtls_rsa_rsassa_pss_verify_ext = 0x40002a00; +mbedtls_rsa_free = 0x40002a04; +mbedtls_rsa_deduce_primes = 0x40002a08; +mbedtls_rsa_deduce_private_exponent = 0x40002a0c; +mbedtls_rsa_deduce_crt = 0x40002a10; +mbedtls_rsa_validate_params = 0x40002a14; +mbedtls_rsa_validate_crt = 0x40002a18; +mbedtls_sha1_init = 0x40002a1c; +mbedtls_sha1_free = 0x40002a20; +mbedtls_sha1_clone = 0x40002a24; +mbedtls_sha1_starts_ret = 0x40002a28; +mbedtls_sha1_finish_ret = 0x40002a2c; +mbedtls_sha256_init = 0x40002a30; +mbedtls_sha256_free = 0x40002a34; +mbedtls_sha256_clone = 0x40002a38; +mbedtls_sha256_starts_ret = 0x40002a3c; +mbedtls_sha256_finish_ret = 0x40002a40; +mbedtls_sha256_ret = 0x40002a44; +mbedtls_sha512_init = 0x40002a48; +mbedtls_sha512_free = 0x40002a4c; +mbedtls_sha512_clone = 0x40002a50; +mbedtls_sha512_starts_ret = 0x40002a54; +mbedtls_sha512_update_ret = 0x40002a58; +mbedtls_sha512_finish_ret = 0x40002a5c; +mbedtls_internal_sha512_process = 0x40002a60; +mbedtls_sha512_ret = 0x40002a64; +mbedtls_ssl_conf_endpoint = 0x40002a68; +mbedtls_ssl_conf_transport = 0x40002a6c; +mbedtls_ssl_set_bio = 0x40002a70; +mbedtls_ssl_conf_dh_param_bin = 0x40002a74; +mbedtls_ssl_get_max_frag_len = 0x40002a78; +mbedtls_ssl_get_max_out_record_payload = 0x40002a7c; +mbedtls_ssl_handshake = 0x40002a80; +mbedtls_ssl_handshake_step = 0x40002a84; +mbedtls_ssl_renegotiate = 0x40002a88; +mbedtls_ssl_send_alert_message = 0x40002a8c; +mbedtls_ssl_config_defaults = 0x40002a90; +mbedtls_ssl_session_init = 0x40002a94; +mbedtls_ssl_session_free = 0x40002a98; +mbedtls_ssl_transform_free = 0x40002a9c; +mbedtls_ssl_handshake_free = 0x40002aa0; +mbedtls_ssl_handshake_client_step = 0x40002aa4; +mbedtls_ssl_handshake_wrapup = 0x40002aa8; +mbedtls_ssl_derive_keys = 0x40002aac; +mbedtls_ssl_handle_message_type = 0x40002ab0; +mbedtls_ssl_prepare_handshake_record = 0x40002ab4; +mbedtls_ssl_update_handshake_status = 0x40002ab8; +mbedtls_ssl_read_record = 0x40002abc; +mbedtls_ssl_fetch_input = 0x40002ac0; +mbedtls_ssl_write_handshake_msg = 0x40002ac4; +mbedtls_ssl_write_record = 0x40002ac8; +mbedtls_ssl_flush_output = 0x40002acc; +mbedtls_ssl_parse_certificate = 0x40002ad0; +mbedtls_ssl_write_certificate = 0x40002ad4; +mbedtls_ssl_parse_change_cipher_spec = 0x40002ad8; +mbedtls_ssl_write_change_cipher_spec = 0x40002adc; +mbedtls_ssl_parse_finished = 0x40002ae0; +mbedtls_ssl_write_finished = 0x40002ae4; +mbedtls_ssl_optimize_checksum = 0x40002ae8; +mbedtls_ssl_psk_derive_premaster = 0x40002aec; +mbedtls_ssl_sig_from_pk = 0x40002af0; +mbedtls_ssl_pk_alg_from_sig = 0x40002af4; +mbedtls_ssl_md_alg_from_hash = 0x40002af8; +mbedtls_ssl_hash_from_md_alg = 0x40002afc; +mbedtls_ssl_check_curve = 0x40002b00; +mbedtls_ssl_check_sig_hash = 0x40002b04; +mbedtls_ssl_write_version = 0x40002b08; +mbedtls_ssl_read_version = 0x40002b0c; +mbedtls_ssl_get_key_exchange_md_ssl_tls = 0x40002b10; +mbedtls_ssl_get_key_exchange_md_tls1_2 = 0x40002b14; +mbedtls_ssl_cf_hmac = 0x40002b18; +mbedtls_ssl_cf_memcpy_offset = 0x40002b1c; +mbedtls_x509_crt_parse_der = 0x40002b20; +mbedtls_x509_crt_verify_restartable = 0x40002b24; +mbedtls_x509_crt_check_key_usage = 0x40002b28; +mbedtls_x509_crt_check_extended_key_usage = 0x40002b2c; +mbedtls_x509_crt_is_revoked = 0x40002b30; +mbedtls_x509_crt_init = 0x40002b34; +mbedtls_x509_crt_free = 0x40002b38; +mbedtls_x509_crt_restart_init = 0x40002b3c; +mbedtls_x509_crt_restart_free = 0x40002b40; +mbedtls_x509_get_name = 0x40002b44; +mbedtls_x509_get_alg_null = 0x40002b48; +mbedtls_x509_get_alg = 0x40002b4c; +mbedtls_x509_get_rsassa_pss_params = 0x40002b50; +mbedtls_x509_get_sig = 0x40002b54; +mbedtls_x509_get_sig_alg = 0x40002b58; +mbedtls_x509_get_time = 0x40002b5c; +mbedtls_x509_get_serial = 0x40002b60; +mbedtls_x509_get_ext = 0x40002b64; +mbedtls_aes_xts_init = 0x40002b68; +mbedtls_aes_xts_free = 0x40002b6c; +mbedtls_aes_xts_setkey_enc = 0x40002b70; +mbedtls_aes_xts_setkey_dec = 0x40002b74; +mbedtls_aes_crypt_xts = 0x40002b78; +mbedtls_aes_crypt_cfb128 = 0x40002b7c; +mbedtls_aes_crypt_ofb = 0x40002b80; +mbedtls_aes_crypt_ctr = 0x40002b84; +mbedtls_arc4_init = 0x40002b88; +mbedtls_arc4_free = 0x40002b8c; +mbedtls_arc4_setup = 0x40002b90; +mbedtls_arc4_crypt = 0x40002b94; +mbedtls_ccm_init = 0x40002b98; +mbedtls_ccm_setkey = 0x40002b9c; +mbedtls_ccm_free = 0x40002ba0; +mbedtls_ccm_encrypt_and_tag = 0x40002ba4; +mbedtls_ccm_auth_decrypt = 0x40002ba8; +mbedtls_dhm_make_params = 0x40002bac; +mbedtls_dhm_set_group = 0x40002bb0; +mbedtls_dhm_read_public = 0x40002bb4; +mbedtls_ecdh_make_params = 0x40002bb8; +mbedtls_ecdh_read_public = 0x40002bbc; +mbedtls_entropy_init = 0x40002bc0; +mbedtls_entropy_free = 0x40002bc4; +mbedtls_gcm_init = 0x40002bc8; +mbedtls_gcm_setkey = 0x40002bcc; +mbedtls_gcm_auth_decrypt = 0x40002bd0; +mbedtls_gcm_free = 0x40002bd4; +mbedtls_md5_init = 0x40002bd8; +mbedtls_md5_free = 0x40002bdc; +mbedtls_md5_clone = 0x40002be0; +mbedtls_md5_starts_ret = 0x40002be4; +mbedtls_md5_update_ret = 0x40002be8; +mbedtls_md5_finish_ret = 0x40002bec; +mbedtls_internal_md5_process = 0x40002bf0; +mbedtls_md5_ret = 0x40002bf4; +mbedtls_pk_get_bitlen = 0x40002bf8; +mbedtls_pk_sign = 0x40002bfc; +mbedtls_pk_decrypt = 0x40002c00; +mbedtls_pk_parse_key = 0x40002c04; +mbedtls_sha1_ret = 0x40002c08; +mbedtls_ssl_init = 0x40002c0c; +mbedtls_ssl_setup = 0x40002c10; +mbedtls_ssl_conf_authmode = 0x40002c14; +mbedtls_ssl_conf_rng = 0x40002c18; +mbedtls_ssl_conf_ca_chain = 0x40002c1c; +mbedtls_ssl_conf_own_cert = 0x40002c20; +mbedtls_ssl_read = 0x40002c24; +mbedtls_ssl_write = 0x40002c28; +mbedtls_ssl_config_init = 0x40002c2c; +mbedtls_ssl_sig_hash_set_find = 0x40002c30; +mbedtls_ssl_sig_hash_set_add = 0x40002c34; +mbedtls_ssl_sig_hash_set_const_hash = 0x40002c38; +mbedtls_ssl_sig_from_pk_alg = 0x40002c3c; +mbedtls_ssl_set_calc_verify_md = 0x40002c40; +mbedtls_x509_crt_parse = 0x40002c44; +/* Data (.data, .bss, .rodata) */ +p_osi_mbedtls_rom_funcs = 0x3fcdfaa0; +mbedtls_x509_crt_profile_default = 0x3ff4fba4; +mbedtls_x509_crt_profile_suiteb = 0x3ff4fb94; +aes_FSb_ptr = 0x3fcdfa9c; +AES_RT0_ptr = 0x3fcdfa98; +AES_RT1_ptr = 0x3fcdfa94; +AES_RT2_ptr = 0x3fcdfa90; +AES_RT3_ptr = 0x3fcdfa8c; +AES_FT0_ptr = 0x3fcdfa88; +AES_FT1_ptr = 0x3fcdfa84; +AES_FT2_ptr = 0x3fcdfa80; +AES_FT3_ptr = 0x3fcdfa7c; +bignum_small_prime_ptr = 0x3fcdfa78; +sha512_K_ptr = 0x3fcdfa74; + diff --git a/tools/flasher_stub/ld/rom_32c3.ld b/tools/flasher_stub/ld/rom_32c3.ld new file mode 100755 index 0000000000..ecaaf49281 --- /dev/null +++ b/tools/flasher_stub/ld/rom_32c3.ld @@ -0,0 +1,2200 @@ +/* ROM function interface esp32c3.rom.ld for esp32c3 + * + * + * Generated from ./interface-esp32c3.yml md5sum 93b28a9e1fe42d212018eb4336849208 + * + * Compatible with ROM where ECO version equal or greater to 0. + * + * THIS FILE WAS AUTOMATICALLY GENERATED. DO NOT EDIT. + */ + + +PROVIDE ( SPIWrite = esp_rom_spiflash_write); +PROVIDE ( SPI_read_status_high = esp_rom_spiflash_read_statushigh); +PROVIDE ( SPI_write_status = esp_rom_spiflash_write_status); +PROVIDE ( SPIRead = esp_rom_spiflash_read); +PROVIDE ( SPIParamCfg = esp_rom_spiflash_config_param); +PROVIDE ( SPIEraseChip = esp_rom_spiflash_erase_chip); +PROVIDE ( SPIEraseSector = esp_rom_spiflash_erase_sector); +PROVIDE ( SPIEraseBlock = esp_rom_spiflash_erase_block); +PROVIDE ( SPI_Write_Encrypt_Enable = esp_rom_spiflash_write_encrypted_enable); +PROVIDE ( SPI_Write_Encrypt_Disable = esp_rom_spiflash_write_encrypted_disable); +PROVIDE ( SPI_Encrypt_Write = esp_rom_spiflash_write_encrypted); + + +/*************************************** + Group common + ***************************************/ + +/* Functions */ +rtc_get_reset_reason = 0x40000018; +analog_super_wdt_reset_happened = 0x4000001c; +jtag_cpu_reset_happened = 0x40000020; +rtc_get_wakeup_cause = 0x40000024; +rtc_boot_control = 0x40000028; +rtc_select_apb_bridge = 0x4000002c; +rtc_unhold_all_pads = 0x40000030; +set_rtc_memory_crc = 0x40000034; +cacl_rtc_memory_crc = 0x40000038; +ets_is_print_boot = 0x4000003c; +ets_printf = 0x40000040; +ets_install_putc1 = 0x40000044; +ets_install_uart_printf = 0x40000048; +ets_install_putc2 = 0x4000004c; +PROVIDE( ets_delay_us = 0x40000050 ); +ets_get_stack_info = 0x40000054; +ets_install_lock = 0x40000058; +ets_backup_dma_copy = 0x4000005c; +ets_apb_backup_init_lock_func = 0x40000060; +UartRxString = 0x40000064; +uart_tx_one_char = 0x40000068; +uart_tx_one_char2 = 0x4000006c; +uart_rx_one_char = 0x40000070; +uart_rx_one_char_block = 0x40000074; +uart_rx_readbuff = 0x40000078; +uartAttach = 0x4000007c; +uart_tx_flush = 0x40000080; +uart_tx_wait_idle = 0x40000084; +uart_div_modify = 0x40000088; +multofup = 0x4000008c; +software_reset = 0x40000090; +software_reset_cpu = 0x40000094; +assist_debug_clock_enable = 0x40000098; +assist_debug_record_enable = 0x4000009c; +clear_super_wdt_reset_flag = 0x400000a0; +disable_default_watchdog = 0x400000a4; +send_packet = 0x400000a8; +recv_packet = 0x400000ac; +GetUartDevice = 0x400000b0; +GetSecurityInfoProc = 0x4004b9da; +GetSecurityInfoProcNewEco = 0x4004d51e; /* manually added from esp32c3eco7-20230720; new address of function for eco7+ */ +UartDwnLdProc = 0x400000b4; +Uart_Init = 0x400000b8; +ets_set_user_start = 0x400000bc; +/* Data (.data, .bss, .rodata) */ +ets_rom_layout_p = 0x3ff1fffc; +ets_ops_table_ptr = 0x3fcdfffc; + + +/*************************************** + Group miniz + ***************************************/ + +/* Functions */ +mz_adler32 = 0x400000c0; +mz_crc32 = 0x400000c4; +mz_free = 0x400000c8; +tdefl_compress = 0x400000cc; +tdefl_compress_buffer = 0x400000d0; +tdefl_compress_mem_to_heap = 0x400000d4; +tdefl_compress_mem_to_mem = 0x400000d8; +tdefl_compress_mem_to_output = 0x400000dc; +tdefl_get_adler32 = 0x400000e0; +tdefl_get_prev_return_status = 0x400000e4; +tdefl_init = 0x400000e8; +tdefl_write_image_to_png_file_in_memory = 0x400000ec; +tdefl_write_image_to_png_file_in_memory_ex = 0x400000f0; +tinfl_decompress = 0x400000f4; +tinfl_decompress_mem_to_callback = 0x400000f8; +tinfl_decompress_mem_to_heap = 0x400000fc; +tinfl_decompress_mem_to_mem = 0x40000100; + + +/*************************************** + Group tjpgd + ***************************************/ + +/* Functions */ +jd_prepare = 0x40000104; +jd_decomp = 0x40000108; + + +/*************************************** + Group spiflash_legacy + ***************************************/ + +/* Functions */ +PROVIDE( esp_rom_spiflash_wait_idle = 0x4000010c ); +PROVIDE( esp_rom_spiflash_write_encrypted = 0x40000110 ); +PROVIDE( esp_rom_spiflash_write_encrypted_dest = 0x40000114 ); +PROVIDE( esp_rom_spiflash_write_encrypted_enable = 0x40000118 ); +PROVIDE( esp_rom_spiflash_write_encrypted_disable = 0x4000011c ); +PROVIDE( esp_rom_spiflash_erase_chip = 0x40000120 ); +PROVIDE( esp_rom_spiflash_erase_block = 0x40000124 ); +PROVIDE( esp_rom_spiflash_erase_sector = 0x40000128 ); +PROVIDE( esp_rom_spiflash_write = 0x4000012c ); +PROVIDE( esp_rom_spiflash_read = 0x40000130 ); +PROVIDE( esp_rom_spiflash_config_param = 0x40000134 ); +PROVIDE( esp_rom_spiflash_read_user_cmd = 0x40000138 ); +PROVIDE( esp_rom_spiflash_select_qio_pins = 0x4000013c ); +PROVIDE( esp_rom_spiflash_unlock = 0x40000140 ); +PROVIDE( esp_rom_spi_flash_auto_sus_res = 0x40000144 ); +PROVIDE( esp_rom_spi_flash_send_resume = 0x40000148 ); +PROVIDE( esp_rom_spi_flash_update_id = 0x4000014c ); +PROVIDE( esp_rom_spiflash_config_clk = 0x40000150 ); +PROVIDE( esp_rom_spiflash_config_readmode = 0x40000154 ); +PROVIDE( esp_rom_spiflash_read_status = 0x40000158 ); +PROVIDE( esp_rom_spiflash_read_statushigh = 0x4000015c ); +PROVIDE( esp_rom_spiflash_write_status = 0x40000160 ); +PROVIDE( spi_flash_attach = 0x40000164 ); +PROVIDE( spi_flash_get_chip_size = 0x40000168 ); +PROVIDE( spi_flash_guard_set = 0x4000016c ); +PROVIDE( spi_flash_guard_get = 0x40000170 ); +PROVIDE( spi_flash_write_config_set = 0x40000174 ); +PROVIDE( spi_flash_write_config_get = 0x40000178 ); +PROVIDE( spi_flash_safe_write_address_func_set = 0x4000017c ); +PROVIDE( spi_flash_unlock = 0x40000180 ); +PROVIDE( spi_flash_erase_range = 0x40000184 ); +PROVIDE( spi_flash_erase_sector = 0x40000188 ); +PROVIDE( spi_flash_write = 0x4000018c ); +PROVIDE( spi_flash_read = 0x40000190 ); +PROVIDE( spi_flash_write_encrypted = 0x40000194 ); +PROVIDE( spi_flash_read_encrypted = 0x40000198 ); +PROVIDE( spi_flash_mmap_os_func_set = 0x4000019c ); +PROVIDE( spi_flash_mmap_page_num_init = 0x400001a0 ); +PROVIDE( spi_flash_mmap = 0x400001a4 ); +PROVIDE( spi_flash_mmap_pages = 0x400001a8 ); +PROVIDE( spi_flash_munmap = 0x400001ac ); +PROVIDE( spi_flash_mmap_dump = 0x400001b0 ); +PROVIDE( spi_flash_check_and_flush_cache = 0x400001b4 ); +PROVIDE( spi_flash_mmap_get_free_pages = 0x400001b8 ); +PROVIDE( spi_flash_cache2phys = 0x400001bc ); +PROVIDE( spi_flash_phys2cache = 0x400001c0 ); +PROVIDE( spi_flash_disable_cache = 0x400001c4 ); +PROVIDE( spi_flash_restore_cache = 0x400001c8 ); +PROVIDE( spi_flash_cache_enabled = 0x400001cc ); +PROVIDE( spi_flash_enable_cache = 0x400001d0 ); +PROVIDE( spi_cache_mode_switch = 0x400001d4 ); +PROVIDE( spi_common_set_dummy_output = 0x400001d8 ); +PROVIDE( spi_common_set_flash_cs_timing = 0x400001dc ); +PROVIDE( esp_enable_cache_flash_wrap = 0x400001e0 ); +PROVIDE( SPIEraseArea = 0x400001e4 ); +PROVIDE( SPILock = 0x400001e8 ); +PROVIDE( SPIMasterReadModeCnfig = 0x400001ec ); +PROVIDE( SPI_Common_Command = 0x400001f0 ); +PROVIDE( SPI_WakeUp = 0x400001f4 ); +PROVIDE( SPI_block_erase = 0x400001f8 ); +PROVIDE( SPI_chip_erase = 0x400001fc ); +PROVIDE( SPI_init = 0x40000200 ); +PROVIDE( SPI_page_program = 0x40000204 ); +PROVIDE( SPI_read_data = 0x40000208 ); +PROVIDE( SPI_sector_erase = 0x4000020c ); +PROVIDE( SPI_write_enable = 0x40000210 ); +PROVIDE( SelectSpiFunction = 0x40000214 ); +PROVIDE( SetSpiDrvs = 0x40000218 ); +PROVIDE( Wait_SPI_Idle = 0x4000021c ); +PROVIDE( spi_dummy_len_fix = 0x40000220 ); +PROVIDE( Disable_QMode = 0x40000224 ); +PROVIDE( Enable_QMode = 0x40000228 ); +/* Data (.data, .bss, .rodata) */ +PROVIDE( rom_spiflash_legacy_funcs = 0x3fcdfff4 ); +PROVIDE( rom_spiflash_legacy_data = 0x3fcdfff0 ); +PROVIDE( g_flash_guard_ops = 0x3fcdfff8 ); + + +/*************************************** + Group spi_flash_hal + ***************************************/ + +/* Functions */ +PROVIDE( spi_flash_hal_poll_cmd_done = 0x4000022c ); +PROVIDE( spi_flash_hal_device_config = 0x40000230 ); +PROVIDE( spi_flash_hal_configure_host_io_mode = 0x40000234 ); +PROVIDE( spi_flash_hal_common_command = 0x40000238 ); +PROVIDE( spi_flash_hal_read = 0x4000023c ); +PROVIDE( spi_flash_hal_erase_chip = 0x40000240 ); +PROVIDE( spi_flash_hal_erase_sector = 0x40000244 ); +PROVIDE( spi_flash_hal_erase_block = 0x40000248 ); +PROVIDE( spi_flash_hal_program_page = 0x4000024c ); +PROVIDE( spi_flash_hal_set_write_protect = 0x40000250 ); +PROVIDE( spi_flash_hal_host_idle = 0x40000254 ); + + +/*************************************** + Group spi_flash_chips + ***************************************/ + +/* Functions */ +PROVIDE( spi_flash_chip_generic_probe = 0x40000258 ); +PROVIDE( spi_flash_chip_generic_detect_size = 0x4000025c ); +PROVIDE( spi_flash_chip_generic_write = 0x40000260 ); +PROVIDE( spi_flash_chip_generic_write_encrypted = 0x40000264 ); +PROVIDE( spi_flash_chip_generic_set_write_protect = 0x40000268 ); +PROVIDE( spi_flash_common_write_status_16b_wrsr = 0x4000026c ); +PROVIDE( spi_flash_chip_generic_reset = 0x40000270 ); +PROVIDE( spi_flash_chip_generic_erase_chip = 0x40000274 ); +PROVIDE( spi_flash_chip_generic_erase_sector = 0x40000278 ); +PROVIDE( spi_flash_chip_generic_erase_block = 0x4000027c ); +PROVIDE( spi_flash_chip_generic_page_program = 0x40000280 ); +PROVIDE( spi_flash_chip_generic_get_write_protect = 0x40000284 ); +PROVIDE( spi_flash_common_read_status_16b_rdsr_rdsr2 = 0x40000288 ); +PROVIDE( spi_flash_chip_generic_read_reg = 0x4000028c ); +PROVIDE( spi_flash_chip_generic_yield = 0x40000290 ); +PROVIDE( spi_flash_generic_wait_host_idle = 0x40000294 ); +PROVIDE( spi_flash_chip_generic_wait_idle = 0x40000298 ); +PROVIDE( spi_flash_chip_generic_config_host_io_mode = 0x4000029c ); +PROVIDE( spi_flash_chip_generic_read = 0x400002a0 ); +PROVIDE( spi_flash_common_read_status_8b_rdsr2 = 0x400002a4 ); +PROVIDE( spi_flash_chip_generic_get_io_mode = 0x400002a8 ); +PROVIDE( spi_flash_common_read_status_8b_rdsr = 0x400002ac ); +PROVIDE( spi_flash_common_write_status_8b_wrsr = 0x400002b0 ); +PROVIDE( spi_flash_common_write_status_8b_wrsr2 = 0x400002b4 ); +PROVIDE( spi_flash_common_set_io_mode = 0x400002b8 ); +PROVIDE( spi_flash_chip_generic_set_io_mode = 0x400002bc ); +PROVIDE( spi_flash_chip_gd_get_io_mode = 0x400002c0 ); +PROVIDE( spi_flash_chip_gd_probe = 0x400002c4 ); +PROVIDE( spi_flash_chip_gd_set_io_mode = 0x400002c8 ); +/* Data (.data, .bss, .rodata) */ +PROVIDE( spi_flash_chip_generic_config_data = 0x3fcdffec ); + + +/*************************************** + Group memspi_host + ***************************************/ + +/* Functions */ +PROVIDE( memspi_host_read_id_hs = 0x400002cc ); +PROVIDE( memspi_host_read_status_hs = 0x400002d0 ); +PROVIDE( memspi_host_flush_cache = 0x400002d4 ); +PROVIDE( memspi_host_erase_chip = 0x400002d8 ); +PROVIDE( memspi_host_erase_sector = 0x400002dc ); +PROVIDE( memspi_host_erase_block = 0x400002e0 ); +PROVIDE( memspi_host_program_page = 0x400002e4 ); +PROVIDE( memspi_host_read = 0x400002e8 ); +PROVIDE( memspi_host_set_write_protect = 0x400002ec ); +PROVIDE( memspi_host_set_max_read_len = 0x400002f0 ); +PROVIDE( memspi_host_read_data_slicer = 0x400002f4 ); +PROVIDE( memspi_host_write_data_slicer = 0x400002f8 ); + + +/*************************************** + Group esp_flash + ***************************************/ + +/* Functions */ +PROVIDE( esp_flash_chip_driver_initialized = 0x400002fc ); +PROVIDE( esp_flash_read_id = 0x40000300 ); +PROVIDE( esp_flash_get_size = 0x40000304 ); +PROVIDE( esp_flash_erase_chip = 0x40000308 ); +PROVIDE( esp_flash_erase_region = 0x4000030c ); +PROVIDE( esp_flash_get_chip_write_protect = 0x40000310 ); +PROVIDE( esp_flash_set_chip_write_protect = 0x40000314 ); +PROVIDE( esp_flash_get_protectable_regions = 0x40000318 ); +PROVIDE( esp_flash_get_protected_region = 0x4000031c ); +PROVIDE( esp_flash_set_protected_region = 0x40000320 ); +PROVIDE( esp_flash_read = 0x40000324 ); +PROVIDE( esp_flash_write = 0x40000328 ); +PROVIDE( esp_flash_write_encrypted = 0x4000032c ); +PROVIDE( esp_flash_read_encrypted = 0x40000330 ); +PROVIDE( esp_flash_get_io_mode = 0x40000334 ); +PROVIDE( esp_flash_set_io_mode = 0x40000338 ); +PROVIDE( spi_flash_boot_attach = 0x4000033c ); +PROVIDE( spi_flash_dump_counters = 0x40000340 ); +PROVIDE( spi_flash_get_counters = 0x40000344 ); +PROVIDE( spi_flash_op_counters_config = 0x40000348 ); +PROVIDE( spi_flash_reset_counters = 0x4000034c ); +/* Data (.data, .bss, .rodata) */ +PROVIDE( esp_flash_default_chip = 0x3fcdffe8 ); +PROVIDE( esp_flash_api_funcs = 0x3fcdffe4 ); + + +/*************************************** + Group cache + ***************************************/ + +/* Functions */ +PROVIDE( Cache_Get_ICache_Line_Size = 0x400004b0 ); +PROVIDE( Cache_Get_Mode = 0x400004b4 ); +PROVIDE( Cache_Address_Through_IBus = 0x400004b8 ); +PROVIDE( Cache_Address_Through_DBus = 0x400004bc ); +PROVIDE( Cache_Set_Default_Mode = 0x400004c0 ); +PROVIDE( Cache_Enable_Defalut_ICache_Mode = 0x400004c4 ); +PROVIDE( ROM_Boot_Cache_Init = 0x400004c8 ); +PROVIDE( Cache_Invalidate_ICache_Items = 0x400004cc ); +PROVIDE( Cache_Op_Addr = 0x400004d0 ); +PROVIDE( Cache_Invalidate_Addr = 0x400004d4 ); +PROVIDE( Cache_Invalidate_ICache_All = 0x400004d8 ); +PROVIDE( Cache_Mask_All = 0x400004dc ); +PROVIDE( Cache_UnMask_Dram0 = 0x400004e0 ); +PROVIDE( Cache_Suspend_ICache_Autoload = 0x400004e4 ); +PROVIDE( Cache_Resume_ICache_Autoload = 0x400004e8 ); +PROVIDE( Cache_Start_ICache_Preload = 0x400004ec ); +PROVIDE( Cache_ICache_Preload_Done = 0x400004f0 ); +PROVIDE( Cache_End_ICache_Preload = 0x400004f4 ); +PROVIDE( Cache_Config_ICache_Autoload = 0x400004f8 ); +PROVIDE( Cache_Enable_ICache_Autoload = 0x400004fc ); +PROVIDE( Cache_Disable_ICache_Autoload = 0x40000500 ); +PROVIDE( Cache_Enable_ICache_PreLock = 0x40000504 ); +PROVIDE( Cache_Disable_ICache_PreLock = 0x40000508 ); +PROVIDE( Cache_Lock_ICache_Items = 0x4000050c ); +PROVIDE( Cache_Unlock_ICache_Items = 0x40000510 ); +PROVIDE( Cache_Lock_Addr = 0x40000514 ); +PROVIDE( Cache_Unlock_Addr = 0x40000518 ); +PROVIDE( Cache_Disable_ICache = 0x4000051c ); +PROVIDE( Cache_Enable_ICache = 0x40000520 ); +PROVIDE( Cache_Suspend_ICache = 0x40000524 ); +PROVIDE( Cache_Resume_ICache = 0x40000528 ); +PROVIDE( Cache_Freeze_ICache_Enable = 0x4000052c ); +PROVIDE( Cache_Freeze_ICache_Disable = 0x40000530 ); +PROVIDE( Cache_Pms_Lock = 0x40000534 ); +PROVIDE( Cache_Ibus_Pms_Set_Addr = 0x40000538 ); +PROVIDE( Cache_Ibus_Pms_Set_Attr = 0x4000053c ); +PROVIDE( Cache_Dbus_Pms_Set_Addr = 0x40000540 ); +PROVIDE( Cache_Dbus_Pms_Set_Attr = 0x40000544 ); +PROVIDE( Cache_Set_IDROM_MMU_Size = 0x40000548 ); +PROVIDE( Cache_Get_IROM_MMU_End = 0x4000054c ); +PROVIDE( Cache_Get_DROM_MMU_End = 0x40000550 ); +PROVIDE( Cache_Owner_Init = 0x40000554 ); +PROVIDE( Cache_Occupy_ICache_MEMORY = 0x40000558 ); +PROVIDE( Cache_MMU_Init = 0x4000055c ); +PROVIDE( Cache_Ibus_MMU_Set = 0x40000560 ); +PROVIDE( Cache_Dbus_MMU_Set = 0x40000564 ); +PROVIDE( Cache_Count_Flash_Pages = 0x40000568 ); +PROVIDE( Cache_Travel_Tag_Memory = 0x4000056c ); +PROVIDE( Cache_Get_Virtual_Addr = 0x40000570 ); +PROVIDE( Cache_Get_Memory_BaseAddr = 0x40000574 ); +PROVIDE( Cache_Get_Memory_Addr = 0x40000578 ); +PROVIDE( Cache_Get_Memory_value = 0x4000057c ); +/* Data (.data, .bss, .rodata) */ +PROVIDE( rom_cache_op_cb = 0x3fcdffd8 ); +PROVIDE( rom_cache_internal_table_ptr = 0x3fcdffd4 ); + + +/*************************************** + Group clock + ***************************************/ + +/* Functions */ +ets_get_apb_freq = 0x40000580; +ets_get_cpu_frequency = 0x40000584; +ets_update_cpu_frequency = 0x40000588; +ets_get_printf_channel = 0x4000058c; +ets_get_xtal_div = 0x40000590; +ets_set_xtal_div = 0x40000594; +ets_get_xtal_freq = 0x40000598; + + +/*************************************** + Group gpio + ***************************************/ + +/* Functions */ +gpio_input_get = 0x4000059c; +gpio_matrix_in = 0x400005a0; +gpio_matrix_out = 0x400005a4; +gpio_output_disable = 0x400005a8; +gpio_output_enable = 0x400005ac; +gpio_output_set = 0x400005b0; +gpio_pad_hold = 0x400005b4; +gpio_pad_input_disable = 0x400005b8; +gpio_pad_input_enable = 0x400005bc; +gpio_pad_pulldown = 0x400005c0; +gpio_pad_pullup = 0x400005c4; +gpio_pad_select_gpio = 0x400005c8; +gpio_pad_set_drv = 0x400005cc; +gpio_pad_unhold = 0x400005d0; +gpio_pin_wakeup_disable = 0x400005d4; +gpio_pin_wakeup_enable = 0x400005d8; +gpio_bypass_matrix_in = 0x400005dc; + + +/*************************************** + Group interrupts + ***************************************/ + +/* Functions */ +esprv_intc_int_set_priority = 0x400005e0; +esprv_intc_int_set_threshold = 0x400005e4; +esprv_intc_int_enable = 0x400005e8; +esprv_intc_int_disable = 0x400005ec; +esprv_intc_int_set_type = 0x400005f0; +intr_matrix_set = 0x400005f4; +ets_intr_lock = 0x400005f8; +ets_intr_unlock = 0x400005fc; +PROVIDE( intr_handler_set = 0x40000600 ); +ets_isr_attach = 0x40000604; +ets_isr_mask = 0x40000608; +ets_isr_unmask = 0x4000060c; + + +/*************************************** + Group crypto + ***************************************/ + +/* Functions */ +md5_vector = 0x40000610; +MD5Init = 0x40000614; +MD5Update = 0x40000618; +MD5Final = 0x4000061c; +hmac_md5_vector = 0x40000620; +hmac_md5 = 0x40000624; +crc32_le = 0x40000628; +crc32_be = 0x4000062c; +crc16_le = 0x40000630; +crc16_be = 0x40000634; +crc8_le = 0x40000638; +crc8_be = 0x4000063c; +esp_crc8 = 0x40000640; +ets_sha_enable = 0x40000644; +ets_sha_disable = 0x40000648; +ets_sha_get_state = 0x4000064c; +ets_sha_init = 0x40000650; +ets_sha_process = 0x40000654; +ets_sha_starts = 0x40000658; +ets_sha_update = 0x4000065c; +ets_sha_finish = 0x40000660; +ets_sha_clone = 0x40000664; +ets_hmac_enable = 0x40000668; +ets_hmac_disable = 0x4000066c; +ets_hmac_calculate_message = 0x40000670; +ets_hmac_calculate_downstream = 0x40000674; +ets_hmac_invalidate_downstream = 0x40000678; +ets_jtag_enable_temporarily = 0x4000067c; +ets_aes_enable = 0x40000680; +ets_aes_disable = 0x40000684; +ets_aes_setkey = 0x40000688; +ets_aes_block = 0x4000068c; +ets_bigint_enable = 0x40000690; +ets_bigint_disable = 0x40000694; +ets_bigint_multiply = 0x40000698; +ets_bigint_modmult = 0x4000069c; +ets_bigint_modexp = 0x400006a0; +ets_bigint_wait_finish = 0x400006a4; +ets_bigint_getz = 0x400006a8; +ets_ds_enable = 0x400006ac; +ets_ds_disable = 0x400006b0; +ets_ds_start_sign = 0x400006b4; +ets_ds_is_busy = 0x400006b8; +ets_ds_finish_sign = 0x400006bc; +ets_ds_encrypt_params = 0x400006c0; +ets_aes_setkey_dec = 0x400006c4; +ets_aes_setkey_enc = 0x400006c8; +ets_mgf1_sha256 = 0x400006cc; + + +/*************************************** + Group efuse + ***************************************/ + +/* Functions */ +ets_efuse_read = 0x400006d0; +ets_efuse_program = 0x400006d4; +ets_efuse_clear_program_registers = 0x400006d8; +ets_efuse_write_key = 0x400006dc; +ets_efuse_get_read_register_address = 0x400006e0; +ets_efuse_get_key_purpose = 0x400006e4; +ets_efuse_key_block_unused = 0x400006e8; +ets_efuse_find_unused_key_block = 0x400006ec; +ets_efuse_rs_calculate = 0x400006f0; +ets_efuse_count_unused_key_blocks = 0x400006f4; +ets_efuse_secure_boot_enabled = 0x400006f8; +ets_efuse_secure_boot_aggressive_revoke_enabled = 0x400006fc; +ets_efuse_cache_encryption_enabled = 0x40000700; +ets_efuse_download_modes_disabled = 0x40000704; +ets_efuse_find_purpose = 0x40000708; +ets_efuse_flash_opi_5pads_power_sel_vddspi = 0x4000070c; +ets_efuse_force_send_resume = 0x40000710; +ets_efuse_get_flash_delay_us = 0x40000714; +ets_efuse_get_mac = 0x40000718; +ets_efuse_get_spiconfig = 0x4000071c; +ets_efuse_usb_print_is_disabled = 0x40000720; +ets_efuse_get_uart_print_channel = 0x40000724; +ets_efuse_get_uart_print_control = 0x40000728; +ets_efuse_get_wp_pad = 0x4000072c; +ets_efuse_legacy_spi_boot_mode_disabled = 0x40000730; +ets_efuse_security_download_modes_enabled = 0x40000734; +ets_efuse_set_timing = 0x40000738; +ets_efuse_jtag_disabled = 0x4000073c; +ets_efuse_usb_download_mode_disabled = 0x40000740; +ets_efuse_usb_module_disabled = 0x40000744; +ets_efuse_usb_device_disabled = 0x40000748; + + +/*************************************** + Group secureboot + ***************************************/ + +/* Functions */ +ets_emsa_pss_verify = 0x4000074c; +ets_rsa_pss_verify = 0x40000750; +ets_secure_boot_verify_bootloader_with_keys = 0x40000754; +ets_secure_boot_verify_signature = 0x40000758; +ets_secure_boot_read_key_digests = 0x4000075c; +ets_secure_boot_revoke_public_key_digest = 0x40000760; + + +/*************************************** + Group usb_uart + ***************************************/ + +/* Functions */ +PROVIDE( usb_uart_rx_one_char = 0x400008cc ); +PROVIDE( usb_uart_rx_one_char_block = 0x400008d0 ); +PROVIDE( usb_uart_tx_flush = 0x400008d4 ); +PROVIDE( usb_uart_tx_one_char = 0x400008d8 ); +/* Data (.data, .bss, .rodata) */ +PROVIDE( g_uart_print = 0x3fcdffd1 ); +PROVIDE( g_usb_print = 0x3fcdffd0 ); + + +/*************************************** + Group bluetooth + ***************************************/ + +/* Functions */ +bt_rf_coex_get_dft_cfg = 0x400008dc; +bt_rf_coex_hooks_p_set = 0x400008e0; +btdm_con_maxevtime_cal_impl = 0x400008e4; +btdm_controller_get_compile_version_impl = 0x400008e8; +btdm_controller_rom_data_init = 0x400008ec; +btdm_dis_privacy_err_report_impl = 0x400008f0; +btdm_disable_adv_delay_impl = 0x400008f4; +btdm_enable_scan_continue_impl = 0x400008f8; +btdm_enable_scan_forever_impl = 0x400008fc; +btdm_get_power_state_impl = 0x40000900; +btdm_get_prevent_sleep_flag_impl = 0x40000904; +btdm_power_state_active_impl = 0x40000908; +btdm_switch_phy_coded_impl = 0x4000090c; +hci_acl_data_handler = 0x40000910; +hci_disconnect_cmd_handler = 0x40000914; +hci_le_con_upd_cmd_handler = 0x40000918; +hci_le_ltk_req_neg_reply_cmd_handler = 0x4000091c; +hci_le_ltk_req_reply_cmd_handler = 0x40000920; +hci_le_rd_chnl_map_cmd_handler = 0x40000924; +hci_le_rd_phy_cmd_handler = 0x40000928; +hci_le_rd_rem_feats_cmd_handler = 0x4000092c; +hci_le_rem_con_param_req_neg_reply_cmd_handler = 0x40000930; +hci_le_rem_con_param_req_reply_cmd_handler = 0x40000934; +hci_le_set_data_len_cmd_handler = 0x40000938; +hci_le_set_phy_cmd_handler = 0x4000093c; +hci_le_start_enc_cmd_handler = 0x40000940; +hci_rd_auth_payl_to_cmd_handler = 0x40000944; +hci_rd_rem_ver_info_cmd_handler = 0x40000948; +hci_rd_rssi_cmd_handler = 0x4000094c; +hci_rd_tx_pwr_lvl_cmd_handler = 0x40000950; +hci_vs_set_pref_slave_evt_dur_cmd_handler = 0x40000954; +hci_vs_set_pref_slave_latency_cmd_handler = 0x40000958; +hci_wr_auth_payl_to_cmd_handler = 0x4000095c; +ll_channel_map_ind_handler = 0x40000960; +ll_connection_param_req_handler = 0x40000964; +ll_connection_param_rsp_handler = 0x40000968; +ll_connection_update_ind_handler = 0x4000096c; +ll_enc_req_handler = 0x40000970; +ll_enc_rsp_handler = 0x40000974; +ll_feature_req_handler = 0x40000978; +ll_feature_rsp_handler = 0x4000097c; +ll_length_req_handler = 0x40000980; +ll_length_rsp_handler = 0x40000984; +ll_min_used_channels_ind_handler = 0x40000988; +ll_pause_enc_req_handler = 0x4000098c; +ll_pause_enc_rsp_handler = 0x40000990; +ll_phy_req_handler = 0x40000994; +ll_phy_rsp_handler = 0x40000998; +ll_phy_update_ind_handler = 0x4000099c; +ll_ping_req_handler = 0x400009a0; +ll_ping_rsp_handler = 0x400009a4; +ll_slave_feature_req_handler = 0x400009a8; +ll_start_enc_req_handler = 0x400009ac; +ll_start_enc_rsp_handler = 0x400009b0; +ll_terminate_ind_handler = 0x400009b4; +ll_version_ind_handler = 0x400009b8; +llc_auth_payl_nearly_to_handler = 0x400009bc; +llc_auth_payl_real_to_handler = 0x400009c0; +llc_encrypt_ind_handler = 0x400009c4; +llc_hci_command_handler_wrapper = 0x400009c8; +llc_ll_connection_param_req_pdu_send = 0x400009cc; +llc_ll_connection_param_rsp_pdu_send = 0x400009d0; +llc_ll_connection_update_ind_pdu_send = 0x400009d4; +llc_ll_enc_req_pdu_send = 0x400009d8; +llc_ll_enc_rsp_pdu_send = 0x400009dc; +llc_ll_feature_req_pdu_send = 0x400009e0; +llc_ll_feature_rsp_pdu_send = 0x400009e4; +llc_ll_length_req_pdu_send = 0x400009e8; +llc_ll_length_rsp_pdu_send = 0x400009ec; +llc_ll_pause_enc_req_pdu_send = 0x400009f0; +llc_ll_pause_enc_rsp_pdu_send = 0x400009f4; +llc_ll_phy_req_pdu_send = 0x400009f8; +llc_ll_phy_rsp_pdu_send = 0x400009fc; +llc_ll_ping_req_pdu_send = 0x40000a00; +llc_ll_ping_rsp_pdu_send = 0x40000a04; +llc_ll_start_enc_req_pdu_send = 0x40000a08; +llc_ll_start_enc_rsp_pdu_send = 0x40000a0c; +llc_ll_terminate_ind_pdu_send = 0x40000a10; +llc_ll_unknown_rsp_pdu_send = 0x40000a14; +llc_llcp_ch_map_update_ind_pdu_send = 0x40000a18; +llc_llcp_phy_upd_ind_pdu_send = 0x40000a1c; +llc_llcp_version_ind_pdu_send = 0x40000a20; +llc_op_ch_map_upd_ind_handler = 0x40000a24; +llc_op_con_upd_ind_handler = 0x40000a28; +llc_op_disconnect_ind_handler = 0x40000a2c; +llc_op_dl_upd_ind_handler = 0x40000a30; +llc_op_encrypt_ind_handler = 0x40000a34; +llc_op_feats_exch_ind_handler = 0x40000a38; +llc_op_le_ping_ind_handler = 0x40000a3c; +llc_op_phy_upd_ind_handler = 0x40000a40; +llc_op_ver_exch_ind_handler = 0x40000a44; +llc_stopped_ind_handler = 0x40000a48; +lld_acl_rx_ind_handler = 0x40000a4c; +lld_acl_tx_cfm_handler = 0x40000a50; +lld_adv_end_ind_handler = 0x40000a54; +lld_adv_rep_ind_handler = 0x40000a58; +lld_ch_map_upd_cfm_handler = 0x40000a5c; +lld_con_estab_ind_handler = 0x40000a60; +lld_con_evt_sd_evt_time_set = 0x40000a64; +lld_con_offset_upd_ind_handler = 0x40000a68; +lld_con_param_upd_cfm_handler = 0x40000a6c; +lld_disc_ind_handler = 0x40000a70; +lld_init_end_ind_handler = 0x40000a74; +lld_llcp_rx_ind_handler_wrapper = 0x40000a78; +lld_llcp_tx_cfm_handler = 0x40000a7c; +lld_per_adv_end_ind_handler = 0x40000a80; +lld_per_adv_rep_ind_handler = 0x40000a84; +lld_per_adv_rx_end_ind_handler = 0x40000a88; +lld_phy_coded_500k_get = 0x40000a8c; +lld_phy_upd_cfm_handler = 0x40000a90; +lld_scan_end_ind_handler = 0x40000a94; +lld_scan_req_ind_handler = 0x40000a98; +lld_sync_start_req_handler = 0x40000a9c; +lld_test_end_ind_handler = 0x40000aa0; +lld_update_rxbuf_handler = 0x40000aa4; +llm_ch_map_update_ind_handler = 0x40000aa8; +llm_hci_command_handler_wrapper = 0x40000aac; +llm_scan_period_to_handler = 0x40000ab0; +r_Add2SelfBigHex256 = 0x40000ab4; +r_AddBigHex256 = 0x40000ab8; +r_AddBigHexModP256 = 0x40000abc; +r_AddP256 = 0x40000ac0; +r_AddPdiv2_256 = 0x40000ac4; +r_GF_Jacobian_Point_Addition256 = 0x40000ac8; +r_GF_Jacobian_Point_Double256 = 0x40000acc; +r_GF_Point_Jacobian_To_Affine256 = 0x40000ad0; +r_MultiplyBigHexByUint32_256 = 0x40000ad4; +r_MultiplyBigHexModP256 = 0x40000ad8; +r_MultiplyByU16ModP256 = 0x40000adc; +r_SubtractBigHex256 = 0x40000ae0; +r_SubtractBigHexMod256 = 0x40000ae4; +r_SubtractBigHexUint32_256 = 0x40000ae8; +r_SubtractFromSelfBigHex256 = 0x40000aec; +r_SubtractFromSelfBigHexSign256 = 0x40000af0; +r_aes_alloc = 0x40000af4; +r_aes_ccm_continue = 0x40000af8; +r_aes_ccm_process_e = 0x40000afc; +r_aes_ccm_xor_128_lsb = 0x40000b00; +r_aes_ccm_xor_128_msb = 0x40000b04; +r_aes_cmac_continue = 0x40000b08; +r_aes_cmac_start = 0x40000b0c; +r_aes_k1_continue = 0x40000b10; +r_aes_k2_continue = 0x40000b14; +r_aes_k3_continue = 0x40000b18; +r_aes_k4_continue = 0x40000b1c; +r_aes_shift_left_128 = 0x40000b20; +r_aes_start = 0x40000b24; +r_aes_xor_128 = 0x40000b28; +r_assert_err = 0x40000b2c; +r_assert_param = 0x40000b30; +r_assert_warn = 0x40000b34; +r_bigHexInversion256 = 0x40000b38; +r_ble_sw_cca_check_isr = 0x40000b3c; +r_ble_util_buf_acl_tx_alloc = 0x40000b40; +r_ble_util_buf_acl_tx_elt_get = 0x40000b44; +r_ble_util_buf_acl_tx_free = 0x40000b48; +r_ble_util_buf_acl_tx_free_in_isr = 0x40000b4c; +r_ble_util_buf_adv_tx_alloc = 0x40000b50; +r_ble_util_buf_adv_tx_free = 0x40000b54; +r_ble_util_buf_adv_tx_free_in_isr = 0x40000b58; +r_ble_util_buf_env_deinit = 0x40000b5c; +r_ble_util_buf_env_init = 0x40000b60; +r_ble_util_buf_get_rx_buf_nb = 0x40000b64; +r_ble_util_buf_get_rx_buf_size = 0x40000b68; +r_ble_util_buf_llcp_tx_alloc = 0x40000b6c; +r_ble_util_buf_llcp_tx_free = 0x40000b70; +r_ble_util_buf_rx_alloc = 0x40000b74; +r_ble_util_buf_rx_alloc_in_isr = 0x40000b78; +r_ble_util_buf_rx_free = 0x40000b7c; +r_ble_util_buf_rx_free_in_isr = 0x40000b80; +r_ble_util_buf_set_rx_buf_nb = 0x40000b84; +r_ble_util_buf_set_rx_buf_size = 0x40000b88; +r_ble_util_data_rx_buf_reset = 0x40000b8c; +r_bt_bb_get_intr_mask = 0x40000b90; +r_bt_bb_intr_clear = 0x40000b94; +r_bt_bb_intr_mask_set = 0x40000b98; +r_bt_bb_isr = 0x40000b9c; +r_bt_rf_coex_cfg_set = 0x40000ba0; +r_bt_rf_coex_conn_dynamic_pti_en_get = 0x40000ba4; +r_bt_rf_coex_conn_phy_coded_data_time_limit_en_get = 0x40000ba8; +r_bt_rf_coex_ext_adv_dynamic_pti_en_get = 0x40000bac; +r_bt_rf_coex_ext_scan_dynamic_pti_en_get = 0x40000bb0; +r_bt_rf_coex_legacy_adv_dynamic_pti_en_get = 0x40000bb4; +r_bt_rf_coex_per_adv_dynamic_pti_en_get = 0x40000bb8; +r_bt_rf_coex_pti_table_get = 0x40000bbc; +r_bt_rf_coex_st_param_get = 0x40000bc0; +r_bt_rf_coex_st_param_set = 0x40000bc4; +r_bt_rf_coex_sync_scan_dynamic_pti_en_get = 0x40000bc8; +r_bt_rma_apply_rule_cs_fmt = 0x40000bcc; +r_bt_rma_apply_rule_cs_idx = 0x40000bd0; +r_bt_rma_configure = 0x40000bd4; +r_bt_rma_deregister_rule_cs_fmt = 0x40000bd8; +r_bt_rma_deregister_rule_cs_idx = 0x40000bdc; +r_bt_rma_get_ant_by_act = 0x40000be0; +r_bt_rma_init = 0x40000be4; +r_bt_rma_register_rule_cs_fmt = 0x40000be8; +r_bt_rma_register_rule_cs_idx = 0x40000bec; +r_bt_rtp_apply_rule_cs_fmt = 0x40000bf0; +r_bt_rtp_apply_rule_cs_idx = 0x40000bf4; +r_bt_rtp_deregister_rule_cs_fmt = 0x40000bf8; +r_bt_rtp_deregister_rule_cs_idx = 0x40000bfc; +r_bt_rtp_get_txpwr_idx_by_act = 0x40000c00; +r_bt_rtp_init = 0x40000c04; +r_bt_rtp_register_rule_cs_fmt = 0x40000c08; +r_bt_rtp_register_rule_cs_idx = 0x40000c0c; +r_btdm_isr = 0x40000c10; +r_btdm_task_post = 0x40000c14; +r_btdm_task_post_from_isr = 0x40000c18; +r_btdm_task_recycle = 0x40000c1c; +r_cali_phase_match_p = 0x40000c20; +r_cmp_abs_time = 0x40000c24; +r_cmp_dest_id = 0x40000c28; +r_cmp_timer_id = 0x40000c2c; +r_co_bdaddr_compare = 0x40000c30; +r_co_ble_pkt_dur_in_us = 0x40000c34; +r_co_list_extract = 0x40000c38; +r_co_list_extract_after = 0x40000c3c; +r_co_list_extract_sublist = 0x40000c40; +r_co_list_find = 0x40000c44; +r_co_list_init = 0x40000c48; +r_co_list_insert_after = 0x40000c4c; +r_co_list_insert_before = 0x40000c50; +r_co_list_merge = 0x40000c54; +r_co_list_pool_init = 0x40000c58; +r_co_list_pop_front = 0x40000c5c; +r_co_list_push_back = 0x40000c60; +r_co_list_push_back_sublist = 0x40000c64; +r_co_list_push_front = 0x40000c68; +r_co_list_size = 0x40000c6c; +r_co_nb_good_le_channels = 0x40000c70; +r_co_util_pack = 0x40000c74; +r_co_util_read_array_size = 0x40000c78; +r_co_util_unpack = 0x40000c7c; +r_dbg_env_deinit = 0x40000c80; +r_dbg_env_init = 0x40000c84; +r_dbg_platform_reset_complete = 0x40000c88; +r_dl_upd_proc_start = 0x40000c8c; +r_dump_data = 0x40000c90; +r_ecc_abort_key256_generation = 0x40000c94; +r_ecc_gen_new_public_key = 0x40000c98; +r_ecc_gen_new_secret_key = 0x40000c9c; +r_ecc_generate_key256 = 0x40000ca0; +r_ecc_get_debug_Keys = 0x40000ca4; +r_ecc_init = 0x40000ca8; +r_ecc_is_valid_point = 0x40000cac; +r_ecc_multiplication_event_handler = 0x40000cb0; +r_ecc_point_multiplication_win_256 = 0x40000cb4; +r_emi_alloc_em_mapping_by_offset = 0x40000cb8; +r_emi_base_reg_lut_show = 0x40000cbc; +r_emi_em_base_reg_show = 0x40000cc0; +r_emi_free_em_mapping_by_offset = 0x40000cc4; +r_emi_get_em_mapping_idx_by_offset = 0x40000cc8; +r_emi_get_mem_addr_by_offset = 0x40000ccc; +r_emi_overwrite_em_mapping_by_offset = 0x40000cd0; +r_esp_vendor_hci_command_handler = 0x40000cd4; +r_get_stack_usage = 0x40000cd8; +r_h4tl_acl_hdr_rx_evt_handler = 0x40000cdc; +r_h4tl_cmd_hdr_rx_evt_handler = 0x40000ce0; +r_h4tl_cmd_pld_rx_evt_handler = 0x40000ce4; +r_h4tl_eif_io_event_post = 0x40000ce8; +r_h4tl_eif_register = 0x40000cec; +r_h4tl_init = 0x40000cf0; +r_h4tl_out_of_sync = 0x40000cf4; +r_h4tl_out_of_sync_check = 0x40000cf8; +r_h4tl_read_hdr = 0x40000cfc; +r_h4tl_read_next_out_of_sync = 0x40000d00; +r_h4tl_read_payl = 0x40000d04; +r_h4tl_read_start = 0x40000d08; +r_h4tl_rx_acl_hdr_extract = 0x40000d0c; +r_h4tl_rx_cmd_hdr_extract = 0x40000d10; +r_h4tl_rx_done = 0x40000d14; +r_h4tl_start = 0x40000d18; +r_h4tl_stop = 0x40000d1c; +r_h4tl_tx_done = 0x40000d20; +r_h4tl_tx_evt_handler = 0x40000d24; +r_h4tl_write = 0x40000d28; +r_hci_acl_tx_data_alloc = 0x40000d2c; +r_hci_acl_tx_data_received = 0x40000d30; +r_hci_basic_cmd_send_2_controller = 0x40000d34; +r_hci_ble_adv_report_filter_check = 0x40000d38; +r_hci_ble_adv_report_tx_check = 0x40000d3c; +r_hci_ble_conhdl_register = 0x40000d40; +r_hci_ble_conhdl_unregister = 0x40000d44; +r_hci_build_acl_data = 0x40000d48; +r_hci_build_cc_evt = 0x40000d4c; +r_hci_build_cs_evt = 0x40000d50; +r_hci_build_evt = 0x40000d54; +r_hci_build_le_evt = 0x40000d58; +r_hci_cmd_get_max_param_size = 0x40000d5c; +r_hci_cmd_received = 0x40000d60; +r_hci_cmd_reject = 0x40000d64; +r_hci_evt_mask_check = 0x40000d68; +r_hci_evt_mask_set = 0x40000d6c; +r_hci_fc_acl_buf_size_set = 0x40000d70; +r_hci_fc_acl_en = 0x40000d74; +r_hci_fc_acl_packet_sent = 0x40000d78; +r_hci_fc_check_host_available_nb_acl_packets = 0x40000d7c; +r_hci_fc_host_nb_acl_pkts_complete = 0x40000d80; +r_hci_fc_init = 0x40000d84; +r_hci_look_for_cmd_desc = 0x40000d88; +r_hci_look_for_evt_desc = 0x40000d8c; +r_hci_look_for_le_evt_desc = 0x40000d90; +r_hci_look_for_le_evt_desc_esp = 0x40000d94; +r_hci_pack_bytes = 0x40000d98; +r_hci_register_vendor_desc_tab = 0x40000d9c; +r_hci_send_2_controller = 0x40000da0; +r_hci_send_2_host = 0x40000da4; +r_hci_tl_c2h_data_flow_on = 0x40000da8; +r_hci_tl_cmd_hdr_rx_evt_handler = 0x40000dac; +r_hci_tl_cmd_pld_rx_evt_handler = 0x40000db0; +r_hci_tl_get_pkt = 0x40000db4; +r_hci_tl_hci_pkt_handler = 0x40000db8; +r_hci_tl_hci_tx_done_evt_handler = 0x40000dbc; +r_hci_tl_inc_nb_h2c_cmd_pkts = 0x40000dc0; +r_hci_tl_save_pkt = 0x40000dc4; +r_hci_tl_send = 0x40000dc8; +r_hci_tx_done = 0x40000dcc; +r_hci_tx_start = 0x40000dd0; +r_hci_tx_trigger = 0x40000dd4; +r_isValidSecretKey_256 = 0x40000dd8; +r_ke_check_malloc = 0x40000ddc; +r_ke_event_callback_set = 0x40000de0; +r_ke_event_clear = 0x40000de4; +r_ke_event_flush = 0x40000de8; +r_ke_event_get = 0x40000dec; +r_ke_event_get_all = 0x40000df0; +r_ke_event_init = 0x40000df4; +r_ke_event_schedule = 0x40000df8; +r_ke_event_set = 0x40000dfc; +r_ke_flush = 0x40000e00; +r_ke_free = 0x40000e04; +r_ke_handler_search = 0x40000e08; +r_ke_init = 0x40000e0c; +r_ke_is_free = 0x40000e10; +r_ke_malloc = 0x40000e14; +r_ke_mem_init = 0x40000e18; +r_ke_mem_is_empty = 0x40000e1c; +r_ke_mem_is_in_heap = 0x40000e20; +r_ke_msg_alloc = 0x40000e24; +r_ke_msg_dest_id_get = 0x40000e28; +r_ke_msg_discard = 0x40000e2c; +r_ke_msg_forward = 0x40000e30; +r_ke_msg_forward_new_id = 0x40000e34; +r_ke_msg_free = 0x40000e38; +r_ke_msg_in_queue = 0x40000e3c; +r_ke_msg_save = 0x40000e40; +r_ke_msg_send = 0x40000e44; +r_ke_msg_send_basic = 0x40000e48; +r_ke_msg_src_id_get = 0x40000e4c; +r_ke_queue_extract = 0x40000e50; +r_ke_queue_insert = 0x40000e54; +r_ke_sleep_check = 0x40000e58; +r_ke_state_get = 0x40000e5c; +r_ke_state_set = 0x40000e60; +r_ke_task_check = 0x40000e64; +r_ke_task_create = 0x40000e68; +r_ke_task_delete = 0x40000e6c; +r_ke_task_handler_get = 0x40000e70; +r_ke_task_init = 0x40000e74; +r_ke_task_msg_flush = 0x40000e78; +r_ke_task_saved_update = 0x40000e7c; +r_ke_task_schedule = 0x40000e80; +r_ke_time = 0x40000e84; +r_ke_time_cmp = 0x40000e88; +r_ke_time_past = 0x40000e8c; +r_ke_timer_active = 0x40000e90; +r_ke_timer_adjust_all = 0x40000e94; +r_ke_timer_clear = 0x40000e98; +r_ke_timer_init = 0x40000e9c; +r_ke_timer_schedule = 0x40000ea0; +r_ke_timer_set = 0x40000ea4; +r_led_init = 0x40000ea8; +r_led_set_all = 0x40000eac; +r_llc_aes_res_cb = 0x40000eb0; +r_llc_ch_map_up_proc_err_cb = 0x40000eb4; +r_llc_cleanup = 0x40000eb8; +r_llc_cmd_cmp_send = 0x40000ebc; +r_llc_cmd_stat_send = 0x40000ec0; +r_llc_con_move_cbk = 0x40000ec4; +r_llc_con_plan_set_update = 0x40000ec8; +r_llc_con_upd_param_in_range = 0x40000ecc; +r_llc_disconnect = 0x40000ed0; +r_llc_disconnect_end = 0x40000ed4; +r_llc_disconnect_proc_continue = 0x40000ed8; +r_llc_disconnect_proc_err_cb = 0x40000edc; +r_llc_dl_chg_check = 0x40000ee0; +r_llc_dle_proc_err_cb = 0x40000ee4; +r_llc_feats_exch_proc_err_cb = 0x40000ee8; +r_llc_hci_cmd_handler_tab_p_get = 0x40000eec; +r_llc_hci_command_handler = 0x40000ef0; +r_llc_hci_con_param_req_evt_send = 0x40000ef4; +r_llc_hci_con_upd_info_send = 0x40000ef8; +r_llc_hci_disconnected_dis = 0x40000efc; +r_llc_hci_dl_upd_info_send = 0x40000f00; +r_llc_hci_enc_evt_send = 0x40000f04; +r_llc_hci_feats_info_send = 0x40000f08; +r_llc_hci_le_phy_upd_cmp_evt_send = 0x40000f0c; +r_llc_hci_ltk_request_evt_send = 0x40000f10; +r_llc_hci_nb_cmp_pkts_evt_send = 0x40000f14; +r_llc_hci_version_info_send = 0x40000f18; +r_llc_init_term_proc = 0x40000f1c; +r_llc_iv_skd_rand_gen = 0x40000f20; +r_llc_le_ping_proc_continue = 0x40000f24; +r_llc_le_ping_proc_err_cb = 0x40000f28; +r_llc_le_ping_restart = 0x40000f2c; +r_llc_le_ping_set = 0x40000f30; +r_llc_ll_pause_enc_rsp_ack_handler = 0x40000f34; +r_llc_ll_reject_ind_ack_handler = 0x40000f38; +r_llc_ll_reject_ind_pdu_send = 0x40000f3c; +r_llc_ll_start_enc_rsp_ack_handler = 0x40000f40; +r_llc_ll_terminate_ind_ack = 0x40000f44; +r_llc_ll_unknown_ind_handler = 0x40000f48; +r_llc_llcp_send = 0x40000f4c; +r_llc_llcp_state_set = 0x40000f50; +r_llc_llcp_trans_timer_set = 0x40000f54; +r_llc_llcp_tx_check = 0x40000f58; +r_llc_loc_ch_map_proc_continue = 0x40000f5c; +r_llc_loc_con_upd_proc_continue = 0x40000f60; +r_llc_loc_con_upd_proc_err_cb = 0x40000f64; +r_llc_loc_dl_upd_proc_continue = 0x40000f68; +r_llc_loc_encrypt_proc_continue = 0x40000f6c; +r_llc_loc_encrypt_proc_err_cb = 0x40000f70; +r_llc_loc_feats_exch_proc_continue = 0x40000f74; +r_llc_loc_phy_upd_proc_continue = 0x40000f78; +r_llc_loc_phy_upd_proc_err_cb = 0x40000f7c; +r_llc_msg_handler_tab_p_get = 0x40000f80; +r_llc_pref_param_compute = 0x40000f84; +r_llc_proc_collision_check = 0x40000f88; +r_llc_proc_err_ind = 0x40000f8c; +r_llc_proc_get = 0x40000f90; +r_llc_proc_id_get = 0x40000f94; +r_llc_proc_reg = 0x40000f98; +r_llc_proc_state_get = 0x40000f9c; +r_llc_proc_state_set = 0x40000fa0; +r_llc_proc_timer_pause_set = 0x40000fa4; +r_llc_proc_timer_set = 0x40000fa8; +r_llc_proc_unreg = 0x40000fac; +r_llc_rem_ch_map_proc_continue = 0x40000fb0; +r_llc_rem_con_upd_proc_continue = 0x40000fb4; +r_llc_rem_con_upd_proc_err_cb = 0x40000fb8; +r_llc_rem_dl_upd_proc = 0x40000fbc; +r_llc_rem_encrypt_proc_continue = 0x40000fc0; +r_llc_rem_encrypt_proc_err_cb = 0x40000fc4; +r_llc_rem_phy_upd_proc_continue = 0x40000fc8; +r_llc_rem_phy_upd_proc_err_cb = 0x40000fcc; +r_llc_role_get = 0x40000fd0; +r_llc_sk_gen = 0x40000fd4; +r_llc_start = 0x40000fd8; +r_llc_stop = 0x40000fdc; +r_llc_ver_exch_loc_proc_continue = 0x40000fe0; +r_llc_ver_proc_err_cb = 0x40000fe4; +r_llcp_pdu_handler_tab_p_get = 0x40000fe8; +r_lld_aa_gen = 0x40000fec; +r_lld_adv_adv_data_set = 0x40000ff0; +r_lld_adv_adv_data_update = 0x40000ff4; +r_lld_adv_aux_ch_idx_set = 0x40000ff8; +r_lld_adv_aux_evt_canceled_cbk = 0x40000ffc; +r_lld_adv_aux_evt_start_cbk = 0x40001000; +r_lld_adv_coex_check_ext_adv_synced = 0x40001004; +r_lld_adv_coex_env_reset = 0x40001008; +r_lld_adv_duration_update = 0x4000100c; +r_lld_adv_dynamic_pti_process = 0x40001010; +r_lld_adv_end = 0x40001014; +r_lld_adv_evt_canceled_cbk = 0x40001018; +r_lld_adv_evt_start_cbk = 0x4000101c; +r_lld_adv_ext_chain_construct = 0x40001020; +r_lld_adv_ext_pkt_prepare = 0x40001024; +r_lld_adv_frm_cbk = 0x40001028; +r_lld_adv_frm_isr = 0x4000102c; +r_lld_adv_frm_skip_isr = 0x40001030; +r_lld_adv_init = 0x40001034; +r_lld_adv_pkt_rx = 0x40001038; +r_lld_adv_pkt_rx_connect_ind = 0x4000103c; +r_lld_adv_pkt_rx_send_scan_req_evt = 0x40001040; +r_lld_adv_rand_addr_update = 0x40001044; +r_lld_adv_restart = 0x40001048; +r_lld_adv_scan_rsp_data_set = 0x4000104c; +r_lld_adv_scan_rsp_data_update = 0x40001050; +r_lld_adv_set_tx_power = 0x40001054; +r_lld_adv_start = 0x40001058; +r_lld_adv_stop = 0x4000105c; +r_lld_adv_sync_info_set = 0x40001060; +r_lld_adv_sync_info_update = 0x40001064; +r_lld_calc_aux_rx = 0x40001068; +r_lld_cca_alloc = 0x4000106c; +r_lld_cca_data_reset = 0x40001070; +r_lld_cca_free = 0x40001074; +r_lld_ch_assess_data_get = 0x40001078; +r_lld_ch_idx_get = 0x4000107c; +r_lld_ch_map_set = 0x40001080; +r_lld_channel_assess = 0x40001084; +r_lld_con_activity_act_offset_compute = 0x40001088; +r_lld_con_activity_offset_compute = 0x4000108c; +r_lld_con_ch_map_update = 0x40001090; +r_lld_con_cleanup = 0x40001094; +r_lld_con_current_tx_power_get = 0x40001098; +r_lld_con_data_flow_set = 0x4000109c; +r_lld_con_data_len_update = 0x400010a0; +r_lld_con_data_tx = 0x400010a4; +r_lld_con_enc_key_load = 0x400010a8; +r_lld_con_event_counter_get = 0x400010ac; +r_lld_con_evt_canceled_cbk = 0x400010b0; +r_lld_con_evt_duration_min_get = 0x400010b4; +r_lld_con_evt_max_eff_time_cal = 0x400010b8; +r_lld_con_evt_sd_evt_time_get = 0x400010bc; +r_lld_con_evt_start_cbk = 0x400010c0; +r_lld_con_evt_time_update = 0x400010c4; +r_lld_con_free_all_tx_buf = 0x400010c8; +r_lld_con_frm_cbk = 0x400010cc; +r_lld_con_frm_isr = 0x400010d0; +r_lld_con_frm_skip_isr = 0x400010d4; +r_lld_con_init = 0x400010d8; +r_lld_con_llcp_tx = 0x400010dc; +r_lld_con_max_lat_calc = 0x400010e0; +r_lld_con_offset_get = 0x400010e4; +r_lld_con_param_update = 0x400010e8; +r_lld_con_phys_update = 0x400010ec; +r_lld_con_pref_slave_evt_dur_set = 0x400010f0; +r_lld_con_pref_slave_latency_set = 0x400010f4; +r_lld_con_rssi_get = 0x400010f8; +r_lld_con_rx = 0x400010fc; +r_lld_con_rx_channel_assess = 0x40001100; +r_lld_con_rx_enc = 0x40001104; +r_lld_con_rx_isr = 0x40001108; +r_lld_con_rx_link_info_check = 0x4000110c; +r_lld_con_rx_llcp_check = 0x40001110; +r_lld_con_rx_sync_time_update = 0x40001114; +r_lld_con_sched = 0x40001118; +r_lld_con_set_tx_power = 0x4000111c; +r_lld_con_start = 0x40001120; +r_lld_con_stop = 0x40001124; +r_lld_con_tx = 0x40001128; +r_lld_con_tx_enc = 0x4000112c; +r_lld_con_tx_isr = 0x40001130; +r_lld_con_tx_len_update = 0x40001134; +r_lld_con_tx_len_update_for_intv = 0x40001138; +r_lld_con_tx_len_update_for_rate = 0x4000113c; +r_lld_con_tx_prog = 0x40001140; +r_lld_conn_dynamic_pti_process = 0x40001144; +r_lld_continue_scan_rx_isr_end_process = 0x40001148; +r_lld_ext_scan_dynamic_pti_process = 0x4000114c; +r_lld_hw_cca_end_isr = 0x40001150; +r_lld_hw_cca_evt_handler = 0x40001154; +r_lld_hw_cca_isr = 0x40001158; +r_lld_init_cal_anchor_point = 0x4000115c; +r_lld_init_compute_winoffset = 0x40001160; +r_lld_init_connect_req_pack = 0x40001164; +r_lld_init_end = 0x40001168; +r_lld_init_evt_canceled_cbk = 0x4000116c; +r_lld_init_evt_start_cbk = 0x40001170; +r_lld_init_frm_cbk = 0x40001174; +r_lld_init_frm_eof_isr = 0x40001178; +r_lld_init_frm_skip_isr = 0x4000117c; +r_lld_init_init = 0x40001180; +r_lld_init_process_pkt_rx = 0x40001184; +r_lld_init_process_pkt_rx_adv_ext_ind = 0x40001188; +r_lld_init_process_pkt_rx_adv_ind_or_direct_ind = 0x4000118c; +r_lld_init_process_pkt_rx_aux_connect_rsp = 0x40001190; +r_lld_init_process_pkt_tx = 0x40001194; +r_lld_init_process_pkt_tx_cal_con_timestamp = 0x40001198; +r_lld_init_sched = 0x4000119c; +r_lld_init_set_tx_power = 0x400011a0; +r_lld_init_start = 0x400011a4; +r_lld_init_stop = 0x400011a8; +r_lld_instant_proc_end = 0x400011ac; +r_lld_llcp_rx_ind_handler = 0x400011b0; +r_lld_per_adv_ch_map_update = 0x400011b4; +r_lld_per_adv_chain_construct = 0x400011b8; +r_lld_per_adv_cleanup = 0x400011bc; +r_lld_per_adv_coex_env_reset = 0x400011c0; +r_lld_per_adv_data_set = 0x400011c4; +r_lld_per_adv_data_update = 0x400011c8; +r_lld_per_adv_dynamic_pti_process = 0x400011cc; +r_lld_per_adv_evt_canceled_cbk = 0x400011d0; +r_lld_per_adv_evt_start_cbk = 0x400011d4; +r_lld_per_adv_ext_pkt_prepare = 0x400011d8; +r_lld_per_adv_frm_cbk = 0x400011dc; +r_lld_per_adv_frm_isr = 0x400011e0; +r_lld_per_adv_frm_skip_isr = 0x400011e4; +r_lld_per_adv_init = 0x400011e8; +r_lld_per_adv_init_info_get = 0x400011ec; +r_lld_per_adv_list_add = 0x400011f0; +r_lld_per_adv_list_rem = 0x400011f4; +r_lld_per_adv_sched = 0x400011f8; +r_lld_per_adv_set_tx_power = 0x400011fc; +r_lld_per_adv_start = 0x40001200; +r_lld_per_adv_stop = 0x40001204; +r_lld_per_adv_sync_info_get = 0x40001208; +r_lld_process_cca_data = 0x4000120c; +r_lld_ral_search = 0x40001210; +r_lld_read_clock = 0x40001214; +r_lld_res_list_add = 0x40001218; +r_lld_res_list_clear = 0x4000121c; +r_lld_res_list_is_empty = 0x40001220; +r_lld_res_list_local_rpa_get = 0x40001224; +r_lld_res_list_peer_rpa_get = 0x40001228; +r_lld_res_list_peer_update = 0x4000122c; +r_lld_res_list_priv_mode_update = 0x40001230; +r_lld_res_list_rem = 0x40001234; +r_lld_reset_reg = 0x40001238; +r_lld_rpa_renew = 0x4000123c; +r_lld_rpa_renew_evt_canceled_cbk = 0x40001240; +r_lld_rpa_renew_evt_start_cbk = 0x40001244; +r_lld_rpa_renew_instant_cbk = 0x40001248; +r_lld_rxdesc_check = 0x4000124c; +r_lld_rxdesc_free = 0x40001250; +r_lld_scan_create_sync = 0x40001254; +r_lld_scan_create_sync_cancel = 0x40001258; +r_lld_scan_end = 0x4000125c; +r_lld_scan_evt_canceled_cbk = 0x40001260; +r_lld_scan_evt_start_cbk = 0x40001264; +r_lld_scan_frm_cbk = 0x40001268; +r_lld_scan_frm_eof_isr = 0x4000126c; +r_lld_scan_frm_rx_isr = 0x40001270; +r_lld_scan_frm_skip_isr = 0x40001274; +r_lld_scan_init = 0x40001278; +r_lld_scan_params_update = 0x4000127c; +r_lld_scan_process_pkt_rx = 0x40001280; +r_lld_scan_process_pkt_rx_adv_rep = 0x40001284; +r_lld_scan_process_pkt_rx_aux_adv_ind = 0x40001288; +r_lld_scan_process_pkt_rx_aux_chain_ind = 0x4000128c; +r_lld_scan_process_pkt_rx_aux_scan_rsp = 0x40001290; +r_lld_scan_process_pkt_rx_ext_adv = 0x40001294; +r_lld_scan_process_pkt_rx_ext_adv_ind = 0x40001298; +r_lld_scan_process_pkt_rx_legacy_adv = 0x4000129c; +r_lld_scan_restart = 0x400012a0; +r_lld_scan_sched = 0x400012a4; +r_lld_scan_set_tx_power = 0x400012a8; +r_lld_scan_start = 0x400012ac; +r_lld_scan_stop = 0x400012b0; +r_lld_scan_sync_accept = 0x400012b4; +r_lld_scan_sync_info_unpack = 0x400012b8; +r_lld_scan_trunc_ind = 0x400012bc; +r_lld_sw_cca_evt_handler = 0x400012c0; +r_lld_sw_cca_isr = 0x400012c4; +r_lld_sync_ch_map_update = 0x400012c8; +r_lld_sync_cleanup = 0x400012cc; +r_lld_sync_evt_canceled_cbk = 0x400012d0; +r_lld_sync_evt_start_cbk = 0x400012d4; +r_lld_sync_frm_cbk = 0x400012d8; +r_lld_sync_frm_eof_isr = 0x400012dc; +r_lld_sync_frm_rx_isr = 0x400012e0; +r_lld_sync_frm_skip_isr = 0x400012e4; +r_lld_sync_init = 0x400012e8; +r_lld_sync_process_pkt_rx = 0x400012ec; +r_lld_sync_process_pkt_rx_aux_sync_ind = 0x400012f0; +r_lld_sync_process_pkt_rx_pkt_check = 0x400012f4; +r_lld_sync_scan_dynamic_pti_process = 0x400012f8; +r_lld_sync_sched = 0x400012fc; +r_lld_sync_start = 0x40001300; +r_lld_sync_stop = 0x40001304; +r_lld_sync_trunc_ind = 0x40001308; +r_lld_test_cleanup = 0x4000130c; +r_lld_test_evt_canceled_cbk = 0x40001310; +r_lld_test_evt_start_cbk = 0x40001314; +r_lld_test_freq2chnl = 0x40001318; +r_lld_test_frm_cbk = 0x4000131c; +r_lld_test_frm_isr = 0x40001320; +r_lld_test_init = 0x40001324; +r_lld_test_rx_isr = 0x40001328; +r_lld_test_set_tx_power = 0x4000132c; +r_lld_test_start = 0x40001330; +r_lld_test_stop = 0x40001334; +r_lld_update_rxbuf = 0x40001338; +r_lld_update_rxbuf_isr = 0x4000133c; +r_lld_white_list_add = 0x40001340; +r_lld_white_list_rem = 0x40001344; +r_llm_activity_free_get = 0x40001348; +r_llm_activity_free_set = 0x4000134c; +r_llm_activity_syncing_get = 0x40001350; +r_llm_adv_con_len_check = 0x40001354; +r_llm_adv_hdl_to_id = 0x40001358; +r_llm_adv_rep_flow_control_check = 0x4000135c; +r_llm_adv_rep_flow_control_update = 0x40001360; +r_llm_adv_reports_list_check = 0x40001364; +r_llm_adv_set_all_release = 0x40001368; +r_llm_adv_set_dft_params = 0x4000136c; +r_llm_adv_set_release = 0x40001370; +r_llm_aes_res_cb = 0x40001374; +r_llm_ble_update_adv_flow_control = 0x40001378; +r_llm_ch_map_update = 0x4000137c; +r_llm_cmd_cmp_send = 0x40001380; +r_llm_cmd_stat_send = 0x40001384; +r_llm_dev_list_empty_entry = 0x40001388; +r_llm_dev_list_search = 0x4000138c; +r_llm_env_adv_dup_filt_deinit = 0x40001390; +r_llm_env_adv_dup_filt_init = 0x40001394; +r_llm_init_ble_adv_report_flow_contol = 0x40001398; +r_llm_is_dev_connected = 0x4000139c; +r_llm_is_dev_synced = 0x400013a0; +r_llm_is_non_con_act_ongoing_check = 0x400013a4; +r_llm_is_wl_accessible = 0x400013a8; +r_llm_le_evt_mask_check = 0x400013ac; +r_llm_le_features_get = 0x400013b0; +r_llm_link_disc = 0x400013b4; +r_llm_master_ch_map_get = 0x400013b8; +r_llm_msg_handler_tab_p_get = 0x400013bc; +r_llm_no_activity = 0x400013c0; +r_llm_per_adv_slot_dur = 0x400013c4; +r_llm_plan_elt_get = 0x400013c8; +r_llm_rx_path_comp_get = 0x400013cc; +r_llm_scan_start = 0x400013d0; +r_llm_scan_sync_acad_attach = 0x400013d4; +r_llm_scan_sync_acad_detach = 0x400013d8; +r_llm_send_adv_lost_event_to_host = 0x400013dc; +r_llm_tx_path_comp_get = 0x400013e0; +r_misc_deinit = 0x400013e4; +r_misc_free_em_buf_in_isr = 0x400013e8; +r_misc_init = 0x400013ec; +r_misc_msg_handler_tab_p_get = 0x400013f0; +r_notEqual256 = 0x400013f4; +r_phy_upd_proc_start = 0x400013f8; +r_platform_reset = 0x400013fc; +r_register_esp_vendor_cmd_handler = 0x40001400; +r_rf_em_init = 0x40001404; +r_rf_force_agc_enable = 0x40001408; +r_rf_reg_rd = 0x4000140c; +r_rf_reg_wr = 0x40001410; +r_rf_reset = 0x40001414; +r_rf_rssi_convert = 0x40001418; +r_rf_rw_v9_le_disable = 0x4000141c; +r_rf_rw_v9_le_enable = 0x40001420; +r_rf_sleep = 0x40001424; +r_rf_txpwr_cs_get = 0x40001428; +r_rf_txpwr_dbm_get = 0x4000142c; +r_rf_util_cs_fmt_convert = 0x40001430; +r_rw_crypto_aes_ccm = 0x40001434; +r_rw_crypto_aes_encrypt = 0x40001438; +r_rw_crypto_aes_init = 0x4000143c; +r_rw_crypto_aes_k1 = 0x40001440; +r_rw_crypto_aes_k2 = 0x40001444; +r_rw_crypto_aes_k3 = 0x40001448; +r_rw_crypto_aes_k4 = 0x4000144c; +r_rw_crypto_aes_rand = 0x40001450; +r_rw_crypto_aes_result_handler = 0x40001454; +r_rw_crypto_aes_s1 = 0x40001458; +r_rw_cryto_aes_cmac = 0x4000145c; +r_rw_v9_init_em_radio_table = 0x40001460; +r_rwble_isr = 0x40001464; +r_rwble_sleep_enter = 0x40001468; +r_rwble_sleep_wakeup_end = 0x4000146c; +r_rwbtdm_isr_wrapper = 0x40001470; +r_rwip_active_check = 0x40001474; +r_rwip_aes_encrypt = 0x40001478; +r_rwip_assert = 0x4000147c; +r_rwip_crypt_evt_handler = 0x40001480; +r_rwip_crypt_isr_handler = 0x40001484; +r_rwip_eif_get = 0x40001488; +r_rwip_half_slot_2_lpcycles = 0x4000148c; +r_rwip_hus_2_lpcycles = 0x40001490; +r_rwip_isr = 0x40001494; +r_rwip_lpcycles_2_hus = 0x40001498; +r_rwip_prevent_sleep_clear = 0x4000149c; +r_rwip_prevent_sleep_set = 0x400014a0; +r_rwip_schedule = 0x400014a4; +r_rwip_sleep = 0x400014a8; +r_rwip_sw_int_handler = 0x400014ac; +r_rwip_sw_int_req = 0x400014b0; +r_rwip_time_get = 0x400014b4; +r_rwip_timer_10ms_handler = 0x400014b8; +r_rwip_timer_10ms_set = 0x400014bc; +r_rwip_timer_hs_handler = 0x400014c0; +r_rwip_timer_hs_set = 0x400014c4; +r_rwip_timer_hus_handler = 0x400014c8; +r_rwip_timer_hus_set = 0x400014cc; +r_rwip_wakeup = 0x400014d0; +r_rwip_wakeup_end = 0x400014d4; +r_rwip_wlcoex_set = 0x400014d8; +r_sch_alarm_clear = 0x400014dc; +r_sch_alarm_init = 0x400014e0; +r_sch_alarm_prog = 0x400014e4; +r_sch_alarm_set = 0x400014e8; +r_sch_alarm_timer_isr = 0x400014ec; +r_sch_arb_conflict_check = 0x400014f0; +r_sch_arb_elt_cancel = 0x400014f4; +r_sch_arb_event_start_isr = 0x400014f8; +r_sch_arb_init = 0x400014fc; +r_sch_arb_insert = 0x40001500; +r_sch_arb_prog_timer = 0x40001504; +r_sch_arb_remove = 0x40001508; +r_sch_arb_sw_isr = 0x4000150c; +r_sch_plan_chk = 0x40001510; +r_sch_plan_clock_wrap_offset_update = 0x40001514; +r_sch_plan_init = 0x40001518; +r_sch_plan_interval_req = 0x4000151c; +r_sch_plan_offset_max_calc = 0x40001520; +r_sch_plan_offset_req = 0x40001524; +r_sch_plan_position_range_compute = 0x40001528; +r_sch_plan_rem = 0x4000152c; +r_sch_plan_req = 0x40001530; +r_sch_plan_set = 0x40001534; +r_sch_prog_end_isr = 0x40001538; +r_sch_prog_init = 0x4000153c; +r_sch_prog_push = 0x40001540; +r_sch_prog_rx_isr = 0x40001544; +r_sch_prog_skip_isr = 0x40001548; +r_sch_prog_tx_isr = 0x4000154c; +r_sch_slice_bg_add = 0x40001550; +r_sch_slice_bg_remove = 0x40001554; +r_sch_slice_compute = 0x40001558; +r_sch_slice_fg_add = 0x4000155c; +r_sch_slice_fg_remove = 0x40001560; +r_sch_slice_init = 0x40001564; +r_sch_slice_per_add = 0x40001568; +r_sch_slice_per_remove = 0x4000156c; +r_sdk_config_get_bt_sleep_enable = 0x40001570; +r_sdk_config_get_hl_derived_opts = 0x40001574; +r_sdk_config_get_opts = 0x40001578; +r_sdk_config_get_priv_opts = 0x4000157c; +r_sdk_config_set_bt_sleep_enable = 0x40001580; +r_sdk_config_set_hl_derived_opts = 0x40001584; +r_sdk_config_set_opts = 0x40001588; +r_specialModP256 = 0x4000158c; +r_unloaded_area_init = 0x40001590; +r_vhci_flow_off = 0x40001594; +r_vhci_flow_on = 0x40001598; +r_vhci_notify_host_send_available = 0x4000159c; +r_vhci_send_to_host = 0x400015a0; +r_vnd_hci_command_handler = 0x400015a4; +r_vshci_init = 0x400015a8; +vnd_hci_command_handler_wrapper = 0x400015ac; +/* Data (.data, .bss, .rodata) */ +bt_rf_coex_cfg_p = 0x3fcdffcc; +bt_rf_coex_hooks_p = 0x3fcdffc8; +btdm_env_p = 0x3fcdffc4; +g_rw_controller_task_handle = 0x3fcdffc0; +g_rw_init_sem = 0x3fcdffbc; +g_rw_schd_queue = 0x3fcdffb8; +lld_init_env = 0x3fcdffb4; +lld_rpa_renew_env = 0x3fcdffb0; +lld_scan_env = 0x3fcdffac; +lld_scan_sync_env = 0x3fcdffa8; +lld_test_env = 0x3fcdffa4; +p_ble_util_buf_env = 0x3fcdffa0; +p_lld_env = 0x3fcdff9c; +p_llm_env = 0x3fcdff98; +r_h4tl_eif_p = 0x3fcdff94; +r_hli_funcs_p = 0x3fcdff90; +r_ip_funcs_p = 0x3fcdff8c; +r_modules_funcs_p = 0x3fcdff88; +r_osi_funcs_p = 0x3fcdff84; +r_plf_funcs_p = 0x3fcdff80; +vhci_env_p = 0x3fcdff7c; +aa_gen = 0x3fcdff78; +aes_env = 0x3fcdff6c; +bt_rf_coex_cfg_cb = 0x3fcdff1c; +btdm_pwr_state = 0x3fcdff18; +btdm_slp_err = 0x3fcdff14; +ecc_env = 0x3fcdff0c; +esp_handler = 0x3fcdff04; +esp_vendor_cmd = 0x3fcdfefc; +g_adv_delay_dis = 0x3fcdfef8; +g_conflict_elt = 0x3fcdfef4; +g_eif_api = 0x3fcdfee4; +g_event_empty = 0x3fcdfed8; +g_llc_state = 0x3fcdfecc; +g_llm_state = 0x3fcdfec8; +g_max_evt_env = 0x3fcdfec4; +g_misc_state = 0x3fcdfec0; +g_rma_rule_db = 0x3fcdfea4; +g_rtp_rule_db = 0x3fcdfe88; +g_scan_forever = 0x3fcdfe85; +g_time_msb = 0x3fcdfe84; +h4tl_env = 0x3fcdfe5c; +hci_env = 0x3fcdfe38; +hci_ext_host = 0x3fcdfe34; +hci_fc_env = 0x3fcdfe2c; +hci_tl_env = 0x3fcdfe00; +ke_env = 0x3fcdfdd0; +ke_event_env = 0x3fcdfd90; +ke_task_env = 0x3fcdfd14; +llc_env = 0x3fcdfcec; +lld_adv_env = 0x3fcdfcc4; +lld_con_env = 0x3fcdfc9c; +lld_exp_sync_pos_tab = 0x3fcdfc94; +lld_per_adv_env = 0x3fcdfc6c; +lld_sync_env = 0x3fcdfc44; +llm_le_adv_flow_env = 0x3fcdfc38; +rw_sleep_enable = 0x3fcdfc34; +rwble_env = 0x3fcdfc2c; +rwip_env = 0x3fcdfc10; +rwip_param = 0x3fcdfc04; +rwip_prog_delay = 0x3fcdfc00; +rwip_rf = 0x3fcdfbc8; +sch_alarm_env = 0x3fcdfbc0; +sch_arb_env = 0x3fcdfbac; +sch_plan_env = 0x3fcdfba4; +sch_prog_env = 0x3fcdfaa0; +sch_slice_env = 0x3fcdfa40; +sch_slice_params = 0x3fcdfa38; +timer_env = 0x3fcdfa30; +unloaded_area = 0x3fcdfa2c; +vshci_state = 0x3fcdfa28; +TASK_DESC_LLC = 0x3fcdfa1c; +TASK_DESC_LLM = 0x3fcdfa10; +TASK_DESC_VSHCI = 0x3fcdfa04; +co_default_bdaddr = 0x3fcdf9fc; +dbg_assert_block = 0x3fcdf9f8; +g_bt_plf_log_level = 0x3fcdf9f4; +hci_cmd_desc_tab_vs_esp = 0x3fcdf9d0; +hci_command_handler_tab_esp = 0x3fcdf9b8; +privacy_en = 0x3fcdf9b4; +sdk_cfg_priv_opts = 0x3fcdf96c; +BasePoint_x_256 = 0x3ff1ffdc; +BasePoint_y_256 = 0x3ff1ffbc; +DebugE256PublicKey_x = 0x3ff1ff9c; +DebugE256PublicKey_y = 0x3ff1ff7c; +DebugE256SecretKey = 0x3ff1ff5c; +ECC_4Win_Look_up_table = 0x3ff1f7a0; +LLM_AA_CT1 = 0x3ff1f79c; +LLM_AA_CT2 = 0x3ff1f798; +RF_TX_PW_CONV_TBL = 0x3ff1f790; +TASK_DESC_MISC = 0x3ff1f784; +adv_evt_prop2type = 0x3ff1f768; +adv_evt_type2prop = 0x3ff1f760; +aes_cmac_zero = 0x3ff1f750; +aes_k2_salt = 0x3ff1f740; +aes_k3_id64 = 0x3ff1f738; +aes_k3_salt = 0x3ff1f728; +aes_k4_id6 = 0x3ff1f724; +aes_k4_salt = 0x3ff1f714; +bigHexP256 = 0x3ff1f6e8; +byte_tx_time = 0x3ff1f6e0; +co_null_bdaddr = 0x3ff1f6d8; +co_phy_mask_to_rate = 0x3ff1f6d0; +co_phy_mask_to_value = 0x3ff1f6c8; +co_phy_to_rate = 0x3ff1f6c4; +co_phy_value_to_mask = 0x3ff1f6c0; +co_rate_to_byte_dur_us = 0x3ff1f6b8; +co_rate_to_phy = 0x3ff1f6b0; +co_rate_to_phy_mask = 0x3ff1f6ac; +co_sca2ppm = 0x3ff1f69c; +coef_B = 0x3ff1f670; +connect_req_dur_tab = 0x3ff1f668; +ecc_Jacobian_InfinityPoint256 = 0x3ff1f5e4; +em_base_reg_lut = 0x3ff1f518; +fixed_tx_time = 0x3ff1f510; +h4tl_msgtype2hdrlen = 0x3ff1f508; +hci_cmd_desc_root_tab = 0x3ff1f4d8; +hci_cmd_desc_tab_ctrl_bb = 0x3ff1f46c; +hci_cmd_desc_tab_info_par = 0x3ff1f43c; +hci_cmd_desc_tab_le = 0x3ff1f0a0; +hci_cmd_desc_tab_lk_ctrl = 0x3ff1f088; +hci_cmd_desc_tab_stat_par = 0x3ff1f07c; +hci_cmd_desc_tab_vs = 0x3ff1f040; +hci_evt_desc_tab = 0x3ff1eff8; +hci_evt_le_desc_tab = 0x3ff1ef58; +hci_evt_le_desc_tab_esp = 0x3ff1ef50; +hci_rsvd_evt_msk = 0x3ff1ef48; +lld_aux_phy_to_rate = 0x3ff1ef44; +lld_init_max_aux_dur_tab = 0x3ff1ef3c; +lld_scan_map_legacy_pdu_to_evt_type = 0x3ff1ef34; +lld_scan_max_aux_dur_tab = 0x3ff1ef2c; +lld_sync_max_aux_dur_tab = 0x3ff1ef24; +llm_local_le_feats = 0x3ff1ef1c; +llm_local_le_states = 0x3ff1ef14; +llm_local_supp_cmds = 0x3ff1eeec; +maxSecretKey_256 = 0x3ff1eecc; +max_data_tx_time = 0x3ff1eec4; +one_bits = 0x3ff1eeb4; +rwip_coex_cfg = 0x3ff1eeac; +rwip_priority = 0x3ff1ee94; +veryBigHexP256 = 0x3ff1ee48; + + +/*************************************** + Group rom_pp + ***************************************/ + +/* Functions */ +esp_pp_rom_version_get = 0x400015b0; +RC_GetBlockAckTime = 0x400015b4; +ebuf_list_remove = 0x400015b8; +esf_buf_alloc = 0x400015bc; +esf_buf_alloc_dynamic = 0x400015c0; +esf_buf_recycle = 0x400015c4; +GetAccess = 0x400015c8; +hal_mac_is_low_rate_enabled = 0x400015cc; +hal_mac_tx_get_blockack = 0x400015d0; +hal_mac_tx_set_ppdu = 0x400015d4; +ic_get_trc = 0x400015d8; +ic_mac_deinit = 0x400015dc; +ic_mac_init = 0x400015e0; +ic_interface_enabled = 0x400015e4; +is_lmac_idle = 0x400015e8; +lmacAdjustTimestamp = 0x400015ec; +lmacDiscardAgedMSDU = 0x400015f0; +lmacDiscardMSDU = 0x400015f4; +lmacEndFrameExchangeSequence = 0x400015f8; +lmacIsIdle = 0x400015fc; +lmacIsLongFrame = 0x40001600; +lmacMSDUAged = 0x40001604; +lmacPostTxComplete = 0x40001608; +lmacProcessAllTxTimeout = 0x4000160c; +lmacProcessCollisions = 0x40001610; +lmacProcessRxSucData = 0x40001614; +lmacReachLongLimit = 0x40001618; +lmacReachShortLimit = 0x4000161c; +lmacRecycleMPDU = 0x40001620; +lmacRxDone = 0x40001624; +lmacSetTxFrame = 0x40001628; +lmacTxDone = 0x4000162c; +lmacTxFrame = 0x40001630; +mac_tx_set_duration = 0x40001634; +mac_tx_set_htsig = 0x40001638; +mac_tx_set_plcp0 = 0x4000163c; +mac_tx_set_plcp1 = 0x40001640; +mac_tx_set_plcp2 = 0x40001644; +pm_check_state = 0x40001648; +pm_disable_dream_timer = 0x4000164c; +pm_disable_sleep_delay_timer = 0x40001650; +pm_dream = 0x40001654; +pm_mac_wakeup = 0x40001658; +pm_mac_sleep = 0x4000165c; +pm_enable_active_timer = 0x40001660; +pm_enable_sleep_delay_timer = 0x40001664; +pm_local_tsf_process = 0x40001668; +pm_set_beacon_filter = 0x4000166c; +pm_is_in_wifi_slice_threshold = 0x40001670; +pm_is_waked = 0x40001674; +pm_keep_alive = 0x40001678; +pm_on_beacon_rx = 0x4000167c; +pm_on_data_rx = 0x40001680; +pm_on_tbtt = 0x40001684; +pm_parse_beacon = 0x40001688; +pm_process_tim = 0x4000168c; +pm_rx_beacon_process = 0x40001690; +pm_rx_data_process = 0x40001694; +pm_sleep = 0x40001698; +pm_sleep_for = 0x4000169c; +pm_tbtt_process = 0x400016a0; +ppAMPDU2Normal = 0x400016a4; +ppAssembleAMPDU = 0x400016a8; +ppCalFrameTimes = 0x400016ac; +ppCalSubFrameLength = 0x400016b0; +ppCalTxAMPDULength = 0x400016b4; +ppCheckTxAMPDUlength = 0x400016b8; +ppDequeueRxq_Locked = 0x400016bc; +ppDequeueTxQ = 0x400016c0; +ppEmptyDelimiterLength = 0x400016c4; +ppEnqueueRxq = 0x400016c8; +ppEnqueueTxDone = 0x400016cc; +ppGetTxQFirstAvail_Locked = 0x400016d0; +ppGetTxframe = 0x400016d4; +ppMapTxQueue = 0x400016d8; +ppProcTxSecFrame = 0x400016dc; +ppProcessRxPktHdr = 0x400016e0; +ppProcessTxQ = 0x400016e4; +ppRecordBarRRC = 0x400016e8; +lmacRequestTxopQueue = 0x400016ec; +lmacReleaseTxopQueue = 0x400016f0; +ppRecycleAmpdu = 0x400016f4; +ppRecycleRxPkt = 0x400016f8; +ppResortTxAMPDU = 0x400016fc; +ppResumeTxAMPDU = 0x40001700; +ppRxFragmentProc = 0x40001704; +ppRxPkt = 0x40001708; +ppRxProtoProc = 0x4000170c; +ppSearchTxQueue = 0x40001710; +ppSearchTxframe = 0x40001714; +ppSelectNextQueue = 0x40001718; +ppSubFromAMPDU = 0x4000171c; +ppTask = 0x40001720; +ppTxPkt = 0x40001724; +ppTxProtoProc = 0x40001728; +ppTxqUpdateBitmap = 0x4000172c; +pp_coex_tx_request = 0x40001730; +pp_hdrsize = 0x40001734; +pp_post = 0x40001738; +pp_process_hmac_waiting_txq = 0x4000173c; +rcGetAmpduSched = 0x40001740; +rcUpdateRxDone = 0x40001744; +rc_get_trc = 0x40001748; +rc_get_trc_by_index = 0x4000174c; +rcAmpduLowerRate = 0x40001750; +rcampduuprate = 0x40001754; +rcClearCurAMPDUSched = 0x40001758; +rcClearCurSched = 0x4000175c; +rcClearCurStat = 0x40001760; +rcGetSched = 0x40001764; +rcLowerSched = 0x40001768; +rcSetTxAmpduLimit = 0x4000176c; +rcTxUpdatePer = 0x40001770; +rcUpdateAckSnr = 0x40001774; +rcUpdateRate = 0x40001778; +rcUpdateTxDone = 0x4000177c; +rcUpdateTxDoneAmpdu2 = 0x40001780; +rcUpSched = 0x40001784; +rssi_margin = 0x40001788; +rx11NRate2AMPDULimit = 0x4000178c; +TRC_AMPDU_PER_DOWN_THRESHOLD = 0x40001790; +TRC_AMPDU_PER_UP_THRESHOLD = 0x40001794; +trc_calc_duration = 0x40001798; +trc_isTxAmpduOperational = 0x4000179c; +trc_onAmpduOp = 0x400017a0; +TRC_PER_IS_GOOD = 0x400017a4; +trc_SetTxAmpduState = 0x400017a8; +trc_tid_isTxAmpduOperational = 0x400017ac; +trcAmpduSetState = 0x400017b0; +wDevCheckBlockError = 0x400017b4; +wDev_AppendRxBlocks = 0x400017b8; +wDev_DiscardFrame = 0x400017bc; +wDev_GetNoiseFloor = 0x400017c0; +wDev_IndicateAmpdu = 0x400017c4; +wDev_IndicateFrame = 0x400017c8; +wdev_bank_store = 0x400017cc; +wdev_bank_load = 0x400017d0; +wdev_mac_reg_load = 0x400017d4; +wdev_mac_reg_store = 0x400017d8; +wdev_mac_special_reg_load = 0x400017dc; +wdev_mac_special_reg_store = 0x400017e0; +wdev_mac_wakeup = 0x400017e4; +wdev_mac_sleep = 0x400017e8; +hal_mac_is_dma_enable = 0x400017ec; +wDev_ProcessFiq = 0x400017f0; +wDev_ProcessRxSucData = 0x400017f4; +wdevProcessRxSucDataAll = 0x400017f8; +wdev_csi_len_align = 0x400017fc; +ppDequeueTxDone_Locked = 0x40001800; +ppProcTxDone = 0x40001804; +pm_tx_data_done_process = 0x40001808; +config_is_cache_tx_buf_enabled = 0x4000180c; +ppMapWaitTxq = 0x40001810; +ppProcessWaitingQueue = 0x40001814; +ppDisableQueue = 0x40001818; +pm_allow_tx = 0x4000181c; +/* Data (.data, .bss, .rodata) */ +our_instances_ptr = 0x3ff1ee44; +pTxRx = 0x3fcdf968; +lmacConfMib_ptr = 0x3fcdf964; +our_wait_eb = 0x3fcdf960; +our_tx_eb = 0x3fcdf95c; +pp_wdev_funcs = 0x3fcdf958; +g_osi_funcs_p = 0x3fcdf954; +wDevCtrl_ptr = 0x3fcdf950; +g_wdev_last_desc_reset_ptr = 0x3ff1ee40; +wDevMacSleep_ptr = 0x3fcdf94c; +g_lmac_cnt_ptr = 0x3fcdf948; +our_controls_ptr = 0x3ff1ee3c; +pp_sig_cnt_ptr = 0x3fcdf944; +g_eb_list_desc_ptr = 0x3fcdf940; +s_fragment_ptr = 0x3fcdf93c; +if_ctrl_ptr = 0x3fcdf938; +g_intr_lock_mux = 0x3fcdf934; +g_wifi_global_lock = 0x3fcdf930; +s_wifi_queue = 0x3fcdf92c; +pp_task_hdl = 0x3fcdf928; +s_pp_task_create_sem = 0x3fcdf924; +s_pp_task_del_sem = 0x3fcdf920; +g_wifi_menuconfig_ptr = 0x3fcdf91c; +xphyQueue = 0x3fcdf918; +ap_no_lr_ptr = 0x3fcdf914; +rc11BSchedTbl_ptr = 0x3fcdf910; +rc11NSchedTbl_ptr = 0x3fcdf90c; +rcLoRaSchedTbl_ptr = 0x3fcdf908; +BasicOFDMSched_ptr = 0x3fcdf904; +trc_ctl_ptr = 0x3fcdf900; +g_pm_cnt_ptr = 0x3fcdf8fc; +g_pm_ptr = 0x3fcdf8f8; +g_pm_cfg_ptr = 0x3fcdf8f4; +g_esp_mesh_quick_funcs_ptr = 0x3fcdf8f0; +g_txop_queue_status_ptr = 0x3fcdf8ec; +g_mac_sleep_en_ptr = 0x3fcdf8e8; +g_mesh_is_root_ptr = 0x3fcdf8e4; +g_mesh_topology_ptr = 0x3fcdf8e0; +g_mesh_init_ps_type_ptr = 0x3fcdf8dc; +g_mesh_is_started_ptr = 0x3fcdf8d8; +g_config_func = 0x3fcdf8d4; +g_net80211_tx_func = 0x3fcdf8d0; +g_timer_func = 0x3fcdf8cc; +s_michael_mic_failure_cb = 0x3fcdf8c8; +wifi_sta_rx_probe_req = 0x3fcdf8c4; +g_tx_done_cb_func = 0x3fcdf8c0; +g_per_conn_trc = 0x3fcdf874; +s_encap_amsdu_func = 0x3fcdf870; + + +/*************************************** + Group rom_net80211 + ***************************************/ + +/* Functions */ +esp_net80211_rom_version_get = 0x40001820; +ampdu_dispatch = 0x40001824; +ampdu_dispatch_all = 0x40001828; +ampdu_dispatch_as_many_as_possible = 0x4000182c; +ampdu_dispatch_movement = 0x40001830; +ampdu_dispatch_upto = 0x40001834; +chm_is_at_home_channel = 0x40001838; +cnx_node_is_existing = 0x4000183c; +cnx_node_search = 0x40001840; +ic_ebuf_recycle_rx = 0x40001844; +ic_ebuf_recycle_tx = 0x40001848; +ic_reset_rx_ba = 0x4000184c; +ieee80211_align_eb = 0x40001850; +ieee80211_ampdu_reorder = 0x40001854; +ieee80211_ampdu_start_age_timer = 0x40001858; +ieee80211_encap_esfbuf = 0x4000185c; +ieee80211_is_tx_allowed = 0x40001860; +ieee80211_output_pending_eb = 0x40001864; +ieee80211_output_process = 0x40001868; +ieee80211_set_tx_desc = 0x4000186c; +sta_input = 0x40001870; +wifi_get_macaddr = 0x40001874; +wifi_rf_phy_disable = 0x40001878; +wifi_rf_phy_enable = 0x4000187c; +ic_ebuf_alloc = 0x40001880; +ieee80211_classify = 0x40001884; +ieee80211_copy_eb_header = 0x40001888; +ieee80211_recycle_cache_eb = 0x4000188c; +ieee80211_search_node = 0x40001890; +roundup2 = 0x40001894; +ieee80211_crypto_encap = 0x40001898; +ieee80211_crypto_decap = 0x4000189c; +ieee80211_decap = 0x400018a0; +ieee80211_set_tx_pti = 0x400018a4; +wifi_is_started = 0x400018a8; +/* Data (.data, .bss, .rodata) */ +net80211_funcs = 0x3fcdf86c; +g_scan = 0x3fcdf868; +g_chm = 0x3fcdf864; +g_ic_ptr = 0x3fcdf860; +g_hmac_cnt_ptr = 0x3fcdf85c; +g_tx_cacheq_ptr = 0x3fcdf858; +s_netstack_free = 0x3fcdf854; +mesh_rxcb = 0x3fcdf850; +sta_rxcb = 0x3fcdf84c; + + +/*************************************** + Group rom_coexist + ***************************************/ + +/* Functions */ +esp_coex_rom_version_get = 0x400018ac; +coex_bt_release = 0x400018b0; +coex_bt_request = 0x400018b4; +coex_core_ble_conn_dyn_prio_get = 0x400018b8; +coex_core_event_duration_get = 0x400018bc; +coex_core_pti_get = 0x400018c0; +coex_core_release = 0x400018c4; +coex_core_request = 0x400018c8; +coex_core_status_get = 0x400018cc; +coex_core_timer_idx_get = 0x400018d0; +coex_event_duration_get = 0x400018d4; +coex_hw_timer_disable = 0x400018d8; +coex_hw_timer_enable = 0x400018dc; +coex_hw_timer_set = 0x400018e0; +coex_schm_interval_set = 0x400018e4; +coex_schm_lock = 0x400018e8; +coex_schm_unlock = 0x400018ec; +coex_status_get = 0x400018f0; +coex_wifi_release = 0x400018f4; +esp_coex_ble_conn_dynamic_prio_get = 0x400018f8; +/* Data (.data, .bss, .rodata) */ +coex_env_ptr = 0x3fcdf848; +coex_pti_tab_ptr = 0x3fcdf844; +coex_schm_env_ptr = 0x3fcdf840; +coexist_funcs = 0x3fcdf83c; +g_coa_funcs_p = 0x3fcdf838; +g_coex_param_ptr = 0x3fcdf834; + + +/*************************************** + Group rom_phy + ***************************************/ + +/* Functions */ +phy_get_romfuncs = 0x400018fc; +rom_abs_temp = 0x40001900; +rom_bb_bss_cbw40_dig = 0x40001904; +rom_bb_wdg_test_en = 0x40001908; +rom_bb_wdt_get_status = 0x4000190c; +rom_bb_wdt_int_enable = 0x40001910; +rom_bb_wdt_rst_enable = 0x40001914; +rom_bb_wdt_timeout_clear = 0x40001918; +rom_cbw2040_cfg = 0x4000191c; +rom_check_noise_floor = 0x40001920; +rom_chip_i2c_readReg = 0x40001924; +rom_chip_i2c_writeReg = 0x40001928; +rom_correct_rf_ana_gain = 0x4000192c; +rom_dc_iq_est = 0x40001930; +rom_disable_agc = 0x40001934; +rom_en_pwdet = 0x40001938; +rom_enable_agc = 0x4000193c; +rom_get_bbgain_db = 0x40001940; +rom_get_data_sat = 0x40001944; +rom_get_i2c_read_mask = 0x40001948; +rom_get_pwctrl_correct = 0x4000194c; +rom_get_rf_gain_qdb = 0x40001950; +rom_i2c_readReg = 0x40001954; +rom_i2c_readReg_Mask = 0x40001958; +rom_i2c_writeReg = 0x4000195c; +rom_i2c_writeReg_Mask = 0x40001960; +rom_index_to_txbbgain = 0x40001964; +rom_iq_est_disable = 0x40001968; +rom_iq_est_enable = 0x4000196c; +rom_linear_to_db = 0x40001970; +rom_loopback_mode_en = 0x40001974; +rom_mhz2ieee = 0x40001978; +rom_noise_floor_auto_set = 0x4000197c; +rom_pbus_debugmode = 0x40001980; +rom_pbus_force_mode = 0x40001984; +rom_pbus_force_test = 0x40001988; +rom_pbus_rd = 0x4000198c; +rom_pbus_rd_addr = 0x40001990; +rom_pbus_rd_shift = 0x40001994; +rom_pbus_set_dco = 0x40001998; +rom_pbus_set_rxgain = 0x4000199c; +rom_pbus_workmode = 0x400019a0; +rom_pbus_xpd_rx_off = 0x400019a4; +rom_pbus_xpd_rx_on = 0x400019a8; +rom_pbus_xpd_tx_off = 0x400019ac; +rom_pbus_xpd_tx_on = 0x400019b0; +rom_phy_byte_to_word = 0x400019b4; +rom_phy_disable_cca = 0x400019b8; +rom_phy_enable_cca = 0x400019bc; +rom_phy_get_noisefloor = 0x400019c0; +rom_phy_get_rx_freq = 0x400019c4; +rom_phy_set_bbfreq_init = 0x400019c8; +rom_pow_usr = 0x400019cc; +rom_pwdet_sar2_init = 0x400019d0; +rom_read_hw_noisefloor = 0x400019d4; +rom_read_sar_dout = 0x400019d8; +rom_set_cal_rxdc = 0x400019dc; +rom_set_chan_cal_interp = 0x400019e0; +rom_set_loopback_gain = 0x400019e4; +rom_set_noise_floor = 0x400019e8; +rom_set_rxclk_en = 0x400019ec; +rom_set_tx_dig_gain = 0x400019f0; +rom_set_txcap_reg = 0x400019f4; +rom_set_txclk_en = 0x400019f8; +rom_spur_cal = 0x400019fc; +rom_spur_reg_write_one_tone = 0x40001a00; +rom_target_power_add_backoff = 0x40001a04; +rom_tx_pwctrl_bg_init = 0x40001a08; +rom_txbbgain_to_index = 0x40001a0c; +rom_wifi_11g_rate_chg = 0x40001a10; +rom_write_gain_mem = 0x40001a14; +chip726_phyrom_version = 0x40001a18; +rom_disable_wifi_agc = 0x40001a1c; +rom_enable_wifi_agc = 0x40001a20; +rom_set_tx_gain_table = 0x40001a24; +rom_bt_index_to_bb = 0x40001a28; +rom_bt_bb_to_index = 0x40001a2c; +rom_wr_bt_tx_atten = 0x40001a30; +rom_wr_bt_tx_gain_mem = 0x40001a34; +rom_spur_coef_cfg = 0x40001a38; +rom_bb_bss_cbw40 = 0x40001a3c; +rom_set_cca = 0x40001a40; +rom_tx_paon_set = 0x40001a44; +rom_i2cmst_reg_init = 0x40001a48; +rom_iq_corr_enable = 0x40001a4c; +rom_fe_reg_init = 0x40001a50; +rom_agc_reg_init = 0x40001a54; +rom_bb_reg_init = 0x40001a58; +rom_mac_enable_bb = 0x40001a5c; +rom_bb_wdg_cfg = 0x40001a60; +rom_force_txon = 0x40001a64; +rom_fe_txrx_reset = 0x40001a68; +rom_set_rx_comp = 0x40001a6c; +rom_set_pbus_reg = 0x40001a70; +rom_write_chan_freq = 0x40001a74; +rom_phy_xpd_rf = 0x40001a78; +rom_set_xpd_sar = 0x40001a7c; +rom_write_dac_gain2 = 0x40001a80; +rom_rtc_sar2_init = 0x40001a84; +rom_get_target_power_offset = 0x40001a88; +rom_write_txrate_power_offset = 0x40001a8c; +rom_get_rate_fcc_index = 0x40001a90; +rom_get_rate_target_power = 0x40001a94; +rom_write_wifi_dig_gain = 0x40001a98; +rom_bt_correct_rf_ana_gain = 0x40001a9c; +rom_pkdet_vol_start = 0x40001aa0; +rom_read_sar2_code = 0x40001aa4; +rom_get_sar2_vol = 0x40001aa8; +rom_get_pll_vol = 0x40001aac; +rom_get_phy_target_power = 0x40001ab0; +rom_temp_to_power = 0x40001ab4; +rom_phy_track_pll_cap = 0x40001ab8; +rom_phy_pwdet_always_en = 0x40001abc; +rom_phy_pwdet_onetime_en = 0x40001ac0; +rom_get_i2c_mst0_mask = 0x40001ac4; +rom_get_i2c_hostid = 0x40001ac8; +rom_enter_critical_phy = 0x40001acc; +rom_exit_critical_phy = 0x40001ad0; +rom_chip_i2c_readReg_org = 0x40001ad4; +rom_i2c_paral_set_mst0 = 0x40001ad8; +rom_i2c_paral_set_read = 0x40001adc; +rom_i2c_paral_read = 0x40001ae0; +rom_i2c_paral_write = 0x40001ae4; +rom_i2c_paral_write_num = 0x40001ae8; +rom_i2c_paral_write_mask = 0x40001aec; +rom_bb_bss_cbw40_ana = 0x40001af0; +rom_chan_to_freq = 0x40001af4; +rom_open_i2c_xpd = 0x40001af8; +rom_dac_rate_set = 0x40001afc; +rom_tsens_read_init = 0x40001b00; +rom_tsens_code_read = 0x40001b04; +rom_tsens_index_to_dac = 0x40001b08; +rom_tsens_index_to_offset = 0x40001b0c; +rom_tsens_dac_cal = 0x40001b10; +rom_code_to_temp = 0x40001b14; +rom_write_pll_cap_mem = 0x40001b18; +rom_pll_correct_dcap = 0x40001b1c; +rom_phy_en_hw_set_freq = 0x40001b20; +rom_phy_dis_hw_set_freq = 0x40001b24; +rom_pll_vol_cal = 0x40001b28; + + + + +/* ROM function interface esp32c3.rom.libgcc.ld for esp32c3 + * + * + * Generated from ./interface-esp32c3.yml md5sum 93b28a9e1fe42d212018eb4336849208 + * + * Compatible with ROM where ECO version equal or greater to 0. + * + * THIS FILE WAS AUTOMATICALLY GENERATED. DO NOT EDIT. + */ + +/*************************************** + Group libgcc + ***************************************/ + +/* Functions */ +__absvdi2 = 0x40000764; +__absvsi2 = 0x40000768; +__adddf3 = 0x4000076c; +__addsf3 = 0x40000770; +__addvdi3 = 0x40000774; +__addvsi3 = 0x40000778; +__ashldi3 = 0x4000077c; +__ashrdi3 = 0x40000780; +__bswapdi2 = 0x40000784; +__bswapsi2 = 0x40000788; +__clear_cache = 0x4000078c; +__clrsbdi2 = 0x40000790; +__clrsbsi2 = 0x40000794; +__clzdi2 = 0x40000798; +__clzsi2 = 0x4000079c; +__cmpdi2 = 0x400007a0; +__ctzdi2 = 0x400007a4; +__ctzsi2 = 0x400007a8; +__divdc3 = 0x400007ac; +__divdf3 = 0x400007b0; +__divdi3 = 0x400007b4; +__divsc3 = 0x400007b8; +__divsf3 = 0x400007bc; +__divsi3 = 0x400007c0; +__eqdf2 = 0x400007c4; +__eqsf2 = 0x400007c8; +__extendsfdf2 = 0x400007cc; +__ffsdi2 = 0x400007d0; +__ffssi2 = 0x400007d4; +__fixdfdi = 0x400007d8; +__fixdfsi = 0x400007dc; +__fixsfdi = 0x400007e0; +__fixsfsi = 0x400007e4; +__fixunsdfsi = 0x400007e8; +__fixunssfdi = 0x400007ec; +__fixunssfsi = 0x400007f0; +__floatdidf = 0x400007f4; +__floatdisf = 0x400007f8; +__floatsidf = 0x400007fc; +__floatsisf = 0x40000800; +__floatundidf = 0x40000804; +__floatundisf = 0x40000808; +__floatunsidf = 0x4000080c; +__floatunsisf = 0x40000810; +__gcc_bcmp = 0x40000814; +__gedf2 = 0x40000818; +__gesf2 = 0x4000081c; +__gtdf2 = 0x40000820; +__gtsf2 = 0x40000824; +__ledf2 = 0x40000828; +__lesf2 = 0x4000082c; +__lshrdi3 = 0x40000830; +__ltdf2 = 0x40000834; +__ltsf2 = 0x40000838; +__moddi3 = 0x4000083c; +__modsi3 = 0x40000840; +__muldc3 = 0x40000844; +__muldf3 = 0x40000848; +__muldi3 = 0x4000084c; +__mulsc3 = 0x40000850; +__mulsf3 = 0x40000854; +__mulsi3 = 0x40000858; +__mulvdi3 = 0x4000085c; +__mulvsi3 = 0x40000860; +__nedf2 = 0x40000864; +__negdf2 = 0x40000868; +__negdi2 = 0x4000086c; +__negsf2 = 0x40000870; +__negvdi2 = 0x40000874; +__negvsi2 = 0x40000878; +__nesf2 = 0x4000087c; +__paritysi2 = 0x40000880; +__popcountdi2 = 0x40000884; +__popcountsi2 = 0x40000888; +__powidf2 = 0x4000088c; +__powisf2 = 0x40000890; +__subdf3 = 0x40000894; +__subsf3 = 0x40000898; +__subvdi3 = 0x4000089c; +__subvsi3 = 0x400008a0; +__truncdfsf2 = 0x400008a4; +__ucmpdi2 = 0x400008a8; +__udivdi3 = 0x400008ac; +__udivmoddi4 = 0x400008b0; +__udivsi3 = 0x400008b4; +__udiv_w_sdiv = 0x400008b8; +__umoddi3 = 0x400008bc; +__umodsi3 = 0x400008c0; +__unorddf2 = 0x400008c4; +__unordsf2 = 0x400008c8; + + + +/* ROM function interface esp32c3.rom.newlib-nano.ld for esp32c3 + * + * + * Generated from ./interface-esp32c3.yml md5sum 93b28a9e1fe42d212018eb4336849208 + * + * Compatible with ROM where ECO version equal or greater to 0. + * + * THIS FILE WAS AUTOMATICALLY GENERATED. DO NOT EDIT. + */ + +/*************************************** + Group newlib_nano_format + ***************************************/ + +/* Functions */ +__sprint_r = 0x40000480; +_fiprintf_r = 0x40000484; +_fprintf_r = 0x40000488; +_printf_common = 0x4000048c; +_printf_i = 0x40000490; +_vfiprintf_r = 0x40000494; +_vfprintf_r = 0x40000498; +fiprintf = 0x4000049c; +fprintf = 0x400004a0; +printf = 0x400004a4; +vfiprintf = 0x400004a8; +vfprintf = 0x400004ac; + + + + +/* ROM function interface esp32c3.rom.newlib.ld for esp32c3 + * + * + * Generated from ./interface-esp32c3.yml md5sum 93b28a9e1fe42d212018eb4336849208 + * + * Compatible with ROM where ECO version equal or greater to 0. + * + * THIS FILE WAS AUTOMATICALLY GENERATED. DO NOT EDIT. + */ + +/*************************************** + Group newlib + ***************************************/ + +/* Functions */ +esp_rom_newlib_init_common_mutexes = 0x40000350; +memset = 0x40000354; +memcpy = 0x40000358; +memmove = 0x4000035c; +memcmp = 0x40000360; +strcpy = 0x40000364; +strncpy = 0x40000368; +strcmp = 0x4000036c; +strncmp = 0x40000370; +strlen = 0x40000374; +strstr = 0x40000378; +bzero = 0x4000037c; +_isatty_r = 0x40000380; +sbrk = 0x40000384; +isalnum = 0x40000388; +isalpha = 0x4000038c; +isascii = 0x40000390; +isblank = 0x40000394; +iscntrl = 0x40000398; +isdigit = 0x4000039c; +islower = 0x400003a0; +isgraph = 0x400003a4; +isprint = 0x400003a8; +ispunct = 0x400003ac; +isspace = 0x400003b0; +isupper = 0x400003b4; +toupper = 0x400003b8; +tolower = 0x400003bc; +toascii = 0x400003c0; +memccpy = 0x400003c4; +memchr = 0x400003c8; +memrchr = 0x400003cc; +strcasecmp = 0x400003d0; +strcasestr = 0x400003d4; +strcat = 0x400003d8; +strdup = 0x400003dc; +strchr = 0x400003e0; +strcspn = 0x400003e4; +strcoll = 0x400003e8; +strlcat = 0x400003ec; +strlcpy = 0x400003f0; +strlwr = 0x400003f4; +strncasecmp = 0x400003f8; +strncat = 0x400003fc; +strndup = 0x40000400; +strnlen = 0x40000404; +strrchr = 0x40000408; +strsep = 0x4000040c; +strspn = 0x40000410; +strtok_r = 0x40000414; +strupr = 0x40000418; +longjmp = 0x4000041c; +setjmp = 0x40000420; +abs = 0x40000424; +div = 0x40000428; +labs = 0x4000042c; +ldiv = 0x40000430; +qsort = 0x40000434; +rand_r = 0x40000438; +rand = 0x4000043c; +srand = 0x40000440; +utoa = 0x40000444; +itoa = 0x40000448; +atoi = 0x4000044c; +atol = 0x40000450; +strtol = 0x40000454; +strtoul = 0x40000458; +PROVIDE( fflush = 0x4000045c ); +PROVIDE( _fflush_r = 0x40000460 ); +PROVIDE( _fwalk = 0x40000464 ); +PROVIDE( _fwalk_reent = 0x40000468 ); +PROVIDE( __smakebuf_r = 0x4000046c ); +PROVIDE( __swhatbuf_r = 0x40000470 ); +PROVIDE( __swbuf_r = 0x40000474 ); +__swbuf = 0x40000478; +PROVIDE( __swsetup_r = 0x4000047c ); +/* Data (.data, .bss, .rodata) */ +syscall_table_ptr = 0x3fcdffe0; +_global_impure_ptr = 0x3fcdffdc; + + + +/* ROM version variables for esp32c3 + * + * These addresses should be compatible with any ROM version for this chip. + * + * THIS FILE WAS AUTOMATICALLY GENERATED. DO NOT EDIT. + */ +_rom_chip_id = 0x40000010; +_rom_eco_version = 0x40000014; diff --git a/tools/flasher_stub/ld/rom_32c5.ld b/tools/flasher_stub/ld/rom_32c5.ld new file mode 100755 index 0000000000..3ef16e1fe3 --- /dev/null +++ b/tools/flasher_stub/ld/rom_32c5.ld @@ -0,0 +1,483 @@ +/* ROM function interface esp32c5.rom.ld for esp32c5 + * + * + * Generated from ./target/esp32c5/interface-esp32c5.yml md5sum f5c146321f24f88ad1f27234da5aed11 + * + * Compatible with ROM where ECO version equal or greater to 0. + * + * THIS FILE WAS AUTOMATICALLY GENERATED. DO NOT EDIT. + */ + +/*************************************** + Group common + ***************************************/ + +PROVIDE ( SPIWrite = esp_rom_spiflash_write); +PROVIDE ( SPI_read_status_high = esp_rom_spiflash_read_statushigh); +PROVIDE ( SPI_write_status = esp_rom_spiflash_write_status); +PROVIDE ( SPIRead = esp_rom_spiflash_read); +PROVIDE ( SPIParamCfg = esp_rom_spiflash_config_param); +PROVIDE ( SPIEraseChip = esp_rom_spiflash_erase_chip); +PROVIDE ( SPIEraseSector = esp_rom_spiflash_erase_sector); +PROVIDE ( SPIEraseBlock = esp_rom_spiflash_erase_block); +PROVIDE ( SPI_Write_Encrypt_Enable = esp_rom_spiflash_write_encrypted_enable); +PROVIDE ( SPI_Write_Encrypt_Disable = esp_rom_spiflash_write_encrypted_disable); +PROVIDE ( SPI_Encrypt_Write = esp_rom_spiflash_write_encrypted); + +/*************************************** + Group common + ***************************************/ + +/* Functions */ +rtc_get_reset_reason = 0x40000018; +rtc_get_wakeup_cause = 0x4000001c; +pmu_enable_unhold_pads = 0x40000020; +ets_printf = 0x40000024; +ets_install_putc1 = 0x40000028; +ets_install_putc2 = 0x4000002c; +ets_install_uart_printf = 0x40000030; +ets_install_usb_printf = 0x40000034; +ets_get_printf_channel = 0x40000038; +ets_delay_us = 0x4000003c; +ets_get_cpu_frequency = 0x40000040; +ets_update_cpu_frequency = 0x40000044; +ets_install_lock = 0x40000048; +UartRxString = 0x4000004c; +UartGetCmdLn = 0x40000050; +uart_tx_one_char = 0x40000054; +uart_tx_one_char2 = 0x40000058; +uart_tx_one_char3 = 0x4000005c; +uart_rx_one_char = 0x40000060; +uart_rx_one_char_block = 0x40000064; +uart_rx_intr_handler = 0x40000068; +uart_rx_readbuff = 0x4000006c; +uartAttach = 0x40000070; +uart_tx_flush = 0x40000074; +uart_tx_wait_idle = 0x40000078; +uart_div_modify = 0x4000007c; +ets_write_char_uart = 0x40000080; +uart_tx_switch = 0x40000084; +uart_buff_switch = 0x40000088; +roundup2 = 0x4000008c; +multofup = 0x40000090; +software_reset = 0x40000094; +software_reset_cpu = 0x40000098; +ets_clk_assist_debug_clock_enable = 0x4000009c; +clear_super_wdt_reset_flag = 0x400000a0; +disable_default_watchdog = 0x400000a4; +esp_rom_set_rtc_wake_addr = 0x400000a8; +esp_rom_get_rtc_wake_addr = 0x400000ac; +send_packet = 0x400000b0; +recv_packet = 0x400000b4; +GetUartDevice = 0x400000b8; +UartDwnLdProc = 0x400000bc; +GetSecurityInfoProc = 0x400000c0; +Uart_Init = 0x400000c4; +ets_set_user_start = 0x400000c8; +/* Data (.data, .bss, .rodata) */ +ets_rom_layout_p = 0x4004fffc; +ets_ops_table_ptr = 0x4085fff8; +g_saved_pc = 0x4085fffc; + + +/*************************************** + Group miniz + ***************************************/ + +/* Functions */ +mz_adler32 = 0x400000cc; +mz_free = 0x400000d0; +tdefl_compress = 0x400000d4; +tdefl_compress_buffer = 0x400000d8; +tdefl_compress_mem_to_heap = 0x400000dc; +tdefl_compress_mem_to_mem = 0x400000e0; +tdefl_compress_mem_to_output = 0x400000e4; +tdefl_get_adler32 = 0x400000e8; +tdefl_get_prev_return_status = 0x400000ec; +tdefl_init = 0x400000f0; +tdefl_write_image_to_png_file_in_memory = 0x400000f4; +tdefl_write_image_to_png_file_in_memory_ex = 0x400000f8; +tinfl_decompress = 0x400000fc; +tinfl_decompress_mem_to_callback = 0x40000100; +tinfl_decompress_mem_to_heap = 0x40000104; +tinfl_decompress_mem_to_mem = 0x40000108; + + +/*************************************** + Group tjpgd + ***************************************/ + +/* Functions */ +jd_prepare = 0x4000010c; +jd_decomp = 0x40000110; + + +/*************************************** + Group spi_extmem_common + ***************************************/ + +/* Functions */ +esp_rom_spi_cmd_config = 0x40000114; +esp_rom_spi_cmd_start = 0x40000118; +esp_rom_spi_set_op_mode = 0x4000011c; + + +/*************************************** + Group spiflash_legacy + ***************************************/ + +/* Functions */ +esp_rom_spiflash_wait_idle = 0x40000120; +esp_rom_spiflash_write_encrypted = 0x40000124; +esp_rom_spiflash_write_encrypted_dest = 0x40000128; +esp_rom_spiflash_write_encrypted_enable = 0x4000012c; +esp_rom_spiflash_write_encrypted_disable = 0x40000130; +esp_rom_spiflash_erase_chip = 0x40000134; +_esp_rom_spiflash_erase_sector = 0x40000138; +_esp_rom_spiflash_erase_block = 0x4000013c; +_esp_rom_spiflash_write = 0x40000140; +_esp_rom_spiflash_read = 0x40000144; +_esp_rom_spiflash_unlock = 0x40000148; +_SPIEraseArea = 0x4000014c; +_SPI_write_enable = 0x40000150; +esp_rom_spiflash_erase_sector = 0x40000154; +esp_rom_spiflash_erase_block = 0x40000158; +esp_rom_spiflash_write = 0x4000015c; +esp_rom_spiflash_read = 0x40000160; +esp_rom_spiflash_unlock = 0x40000164; +SPIEraseArea = 0x40000168; +SPI_write_enable = 0x4000016c; +esp_rom_spiflash_config_param = 0x40000170; +esp_rom_spiflash_read_user_cmd = 0x40000174; +esp_rom_spiflash_select_qio_pins = 0x40000178; +esp_rom_spi_flash_auto_sus_res = 0x4000017c; +esp_rom_spi_flash_send_resume = 0x40000180; +esp_rom_spi_flash_update_id = 0x40000184; +esp_rom_spiflash_config_clk = 0x40000188; +esp_rom_spiflash_config_readmode = 0x4000018c; +esp_rom_spiflash_read_status = 0x40000190; +esp_rom_spiflash_read_statushigh = 0x40000194; +esp_rom_spiflash_write_status = 0x40000198; +esp_rom_spiflash_write_disable = 0x4000019c; +spi_cache_mode_switch = 0x400001a0; +spi_common_set_dummy_output = 0x400001a4; +spi_common_set_flash_cs_timing = 0x400001a8; +esp_rom_spi_set_address_bit_len = 0x400001ac; +SPILock = 0x400001b0; +SPIMasterReadModeCnfig = 0x400001b4; +SPI_Common_Command = 0x400001b8; +SPI_WakeUp = 0x400001bc; +SPI_block_erase = 0x400001c0; +SPI_chip_erase = 0x400001c4; +SPI_init = 0x400001c8; +SPI_page_program = 0x400001cc; +SPI_read_data = 0x400001d0; +SPI_sector_erase = 0x400001d4; +SelectSpiFunction = 0x400001d8; +SetSpiDrvs = 0x400001dc; +Wait_SPI_Idle = 0x400001e0; +spi_dummy_len_fix = 0x400001e4; +Disable_QMode = 0x400001e8; +Enable_QMode = 0x400001ec; +spi_flash_attach = 0x400001f0; +spi_flash_get_chip_size = 0x400001f4; +spi_flash_guard_set = 0x400001f8; +spi_flash_guard_get = 0x400001fc; +spi_flash_read_encrypted = 0x40000200; +/* Data (.data, .bss, .rodata) */ +rom_spiflash_legacy_funcs = 0x4085fff0; +rom_spiflash_legacy_data = 0x4085ffec; +g_flash_guard_ops = 0x4085fff4; + + +/*************************************** + Group hal_wdt + ***************************************/ + +/* Functions */ +wdt_hal_init = 0x400003a4; +wdt_hal_deinit = 0x400003a8; +wdt_hal_config_stage = 0x400003ac; +wdt_hal_write_protect_disable = 0x400003b0; +wdt_hal_write_protect_enable = 0x400003b4; +wdt_hal_enable = 0x400003b8; +wdt_hal_disable = 0x400003bc; +wdt_hal_handle_intr = 0x400003c0; +wdt_hal_feed = 0x400003c4; +wdt_hal_set_flashboot_en = 0x400003c8; +wdt_hal_is_enabled = 0x400003cc; + + +/*************************************** + Group hal_systimer + ***************************************/ + +/* Functions */ +systimer_hal_init = 0x400003d0; +systimer_hal_deinit = 0x400003d4; +systimer_hal_set_tick_rate_ops = 0x400003d8; +systimer_hal_get_counter_value = 0x400003dc; +systimer_hal_get_time = 0x400003e0; +systimer_hal_set_alarm_target = 0x400003e4; +systimer_hal_set_alarm_period = 0x400003e8; +systimer_hal_get_alarm_value = 0x400003ec; +systimer_hal_enable_alarm_int = 0x400003f0; +systimer_hal_on_apb_freq_update = 0x400003f4; +systimer_hal_counter_value_advance = 0x400003f8; +systimer_hal_enable_counter = 0x400003fc; +systimer_hal_select_alarm_mode = 0x40000400; +systimer_hal_connect_alarm_counter = 0x40000404; +systimer_hal_counter_can_stall_by_cpu = 0x40000408; + + +/*************************************** + Group cache + ***************************************/ + +/* Functions */ +Cache_Get_Line_Size = 0x40000638; +Cache_Get_Mode = 0x4000063c; +Cache_Address_Through_Cache = 0x40000640; +ROM_Boot_Cache_Init = 0x40000644; +Cache_Sync_Items = 0x40000648; +Cache_Op_Addr = 0x4000064c; +Cache_Invalidate_Addr = 0x40000650; +Cache_Clean_Addr = 0x40000654; +Cache_WriteBack_Addr = 0x40000658; +Cache_WriteBack_Invalidate_Addr = 0x4000065c; +Cache_Invalidate_All = 0x40000660; +Cache_Clean_All = 0x40000664; +Cache_WriteBack_All = 0x40000668; +Cache_WriteBack_Invalidate_All = 0x4000066c; +Cache_Mask_All = 0x40000670; +Cache_UnMask_Dram0 = 0x40000674; +Cache_Suspend_Autoload = 0x40000678; +Cache_Resume_Autoload = 0x4000067c; +Cache_Start_Preload = 0x40000680; +Cache_Preload_Done = 0x40000684; +Cache_End_Preload = 0x40000688; +Cache_Config_Autoload = 0x4000068c; +Cache_Enable_Autoload = 0x40000690; +Cache_Disable_Autoload = 0x40000694; +Cache_Enable_PreLock = 0x40000698; +Cache_Disable_PreLock = 0x4000069c; +Cache_Lock_Items = 0x400006a0; +Cache_Lock_Addr = 0x400006a4; +Cache_Unlock_Addr = 0x400006a8; +Cache_Disable_Cache = 0x400006ac; +Cache_Enable_Cache = 0x400006b0; +Cache_Suspend_Cache = 0x400006b4; +Cache_Resume_Cache = 0x400006b8; +Cache_Freeze_Enable = 0x400006bc; +Cache_Freeze_Disable = 0x400006c0; +Cache_Set_IDROM_MMU_Size = 0x400006c4; +Cache_Get_IROM_MMU_End = 0x400006c8; +Cache_Get_DROM_MMU_End = 0x400006cc; +Cache_MMU_Init = 0x400006d0; +Cache_MSPI_MMU_Set = 0x400006d4; +Cache_MSPI_MMU_Set_Secure = 0x400006d8; +Cache_Count_Flash_Pages = 0x400006dc; +Cache_Travel_Tag_Memory = 0x400006e0; +Cache_Get_Virtual_Addr = 0x400006e4; +flash2spiram_instruction_offset = 0x400006e8; +flash2spiram_rodata_offset = 0x400006ec; +flash_instr_rodata_start_page = 0x400006f0; +flash_instr_rodata_end_page = 0x400006f4; +Cache_Set_IDROM_MMU_Info = 0x400006f8; +Cache_Flash_To_SPIRAM_Copy = 0x400006fc; +/* Data (.data, .bss, .rodata) */ +rom_cache_op_cb = 0x4085ffcc; +rom_cache_internal_table_ptr = 0x4085ffc8; + + +/*************************************** + Group clock + ***************************************/ + +/* Functions */ +ets_clk_get_xtal_freq = 0x40000700; +ets_clk_get_cpu_freq = 0x40000704; + + +/*************************************** + Group gpio + ***************************************/ + +/* Functions */ +gpio_set_output_level = 0x40000708; +gpio_get_input_level = 0x4000070c; +gpio_matrix_in = 0x40000710; +gpio_matrix_out = 0x40000714; +gpio_bypass_matrix_in = 0x40000718; +gpio_output_disable = 0x4000071c; +gpio_output_enable = 0x40000720; +gpio_pad_input_disable = 0x40000724; +gpio_pad_input_enable = 0x40000728; +gpio_pad_pulldown = 0x4000072c; +gpio_pad_pullup = 0x40000730; +gpio_pad_select_gpio = 0x40000734; +gpio_pad_set_drv = 0x40000738; +gpio_pad_unhold = 0x4000073c; +gpio_pad_hold = 0x40000740; + + +/*************************************** + Group interrupts + ***************************************/ + +/* Functions */ +esprv_intc_int_set_priority = 0x40000744; +esprv_intc_int_set_threshold = 0x40000748; +esprv_intc_int_enable = 0x4000074c; +esprv_intc_int_disable = 0x40000750; +esprv_intc_int_set_type = 0x40000754; +PROVIDE( intr_handler_set = 0x40000758 ); +intr_matrix_set = 0x4000075c; +ets_intr_register_ctx = 0x40000760; +ets_intr_lock = 0x40000764; +ets_intr_unlock = 0x40000768; +ets_isr_attach = 0x4000076c; +ets_isr_mask = 0x40000770; +ets_isr_unmask = 0x40000774; + + +/*************************************** + Group crc + ***************************************/ + +/* Functions */ +crc32_le = 0x40000778; +crc16_le = 0x4000077c; +crc8_le = 0x40000780; +crc32_be = 0x40000784; +crc16_be = 0x40000788; +crc8_be = 0x4000078c; +esp_crc8 = 0x40000790; +/* Data (.data, .bss, .rodata) */ +crc32_le_table_ptr = 0x4004fff8; +crc16_le_table_ptr = 0x4004fff4; +crc8_le_table_ptr = 0x4004fff0; +crc32_be_table_ptr = 0x4004ffec; +crc16_be_table_ptr = 0x4004ffe8; +crc8_be_table_ptr = 0x4004ffe4; + + +/*************************************** + Group md5 + ***************************************/ + +/* Functions */ +md5_vector = 0x40000794; +MD5Init = 0x40000798; +MD5Update = 0x4000079c; +MD5Final = 0x400007a0; + + +/*************************************** + Group hwcrypto + ***************************************/ + +/* Functions */ +ets_sha_enable = 0x400007a4; +ets_sha_disable = 0x400007a8; +ets_sha_get_state = 0x400007ac; +ets_sha_init = 0x400007b0; +ets_sha_process = 0x400007b4; +ets_sha_starts = 0x400007b8; +ets_sha_update = 0x400007bc; +ets_sha_finish = 0x400007c0; +ets_sha_clone = 0x400007c4; +ets_hmac_enable = 0x400007c8; +ets_hmac_disable = 0x400007cc; +ets_hmac_calculate_message = 0x400007d0; +ets_hmac_calculate_downstream = 0x400007d4; +ets_hmac_invalidate_downstream = 0x400007d8; +ets_aes_enable = 0x400007dc; +ets_aes_disable = 0x400007e0; +ets_aes_setkey = 0x400007e4; +ets_aes_block = 0x400007e8; +ets_aes_setkey_dec = 0x400007ec; +ets_aes_setkey_enc = 0x400007f0; +ets_bigint_enable = 0x400007f4; +ets_bigint_disable = 0x400007f8; +ets_bigint_multiply = 0x400007fc; +ets_bigint_modmult = 0x40000800; +ets_bigint_modexp = 0x40000804; +ets_bigint_wait_finish = 0x40000808; +ets_bigint_getz = 0x4000080c; +ets_ds_enable = 0x40000810; +ets_ds_disable = 0x40000814; +ets_ds_start_sign = 0x40000818; +ets_ds_is_busy = 0x4000081c; +ets_ds_finish_sign = 0x40000820; +ets_ds_encrypt_params = 0x40000824; + + +/*************************************** + Group efuse + ***************************************/ + +/* Functions */ +ets_efuse_read = 0x40000828; +ets_efuse_program = 0x4000082c; +ets_efuse_clear_program_registers = 0x40000830; +ets_efuse_write_key = 0x40000834; +ets_efuse_get_read_register_address = 0x40000838; +ets_efuse_get_key_purpose = 0x4000083c; +ets_efuse_key_block_unused = 0x40000840; +ets_efuse_find_unused_key_block = 0x40000844; +ets_efuse_rs_calculate = 0x40000848; +ets_efuse_count_unused_key_blocks = 0x4000084c; +ets_efuse_secure_boot_enabled = 0x40000850; +ets_efuse_secure_boot_aggressive_revoke_enabled = 0x40000854; +ets_efuse_cache_encryption_enabled = 0x40000858; +ets_efuse_download_modes_disabled = 0x4000085c; +ets_efuse_find_purpose = 0x40000860; +ets_efuse_force_send_resume = 0x40000864; +ets_efuse_get_flash_delay_us = 0x40000868; +ets_efuse_get_uart_print_control = 0x4000086c; +ets_efuse_direct_boot_mode_disabled = 0x40000870; +ets_efuse_security_download_modes_enabled = 0x40000874; +ets_efuse_jtag_disabled = 0x40000878; +ets_efuse_usb_print_is_disabled = 0x4000087c; +ets_efuse_usb_download_mode_disabled = 0x40000880; +ets_efuse_usb_device_disabled = 0x40000884; +ets_efuse_secure_boot_fast_wake_enabled = 0x40000888; +ets_jtag_enable_temporarily = 0x4000088c; + + +/*************************************** + Group key_mgr + ***************************************/ + +/* Functions */ +esp_rom_check_recover_key = 0x40000890; +esp_rom_km_huk_conf = 0x40000894; +esp_rom_km_huk_risk = 0x40000898; + + +/*************************************** + Group secureboot + ***************************************/ + +/* Functions */ +ets_emsa_pss_verify = 0x4000089c; +ets_rsa_pss_verify = 0x400008a0; +ets_ecdsa_verify = 0x400008a4; +ets_secure_boot_verify_bootloader_with_keys = 0x400008a8; +ets_secure_boot_verify_signature = 0x400008ac; +ets_secure_boot_read_key_digests = 0x400008b0; +ets_mgf1_sha256 = 0x400008b4; +ets_secure_boot_revoke_public_key_digest = 0x400008b8; + + +/*************************************** + Group usb_device_uart + ***************************************/ + +/* Functions */ +usb_serial_device_rx_one_char = 0x40000ab8; +usb_serial_device_rx_one_char_block = 0x40000abc; +usb_serial_device_tx_flush = 0x40000ac0; +usb_serial_device_tx_one_char = 0x40000ac4; + diff --git a/tools/flasher_stub/ld/rom_32c5_beta_3.ld b/tools/flasher_stub/ld/rom_32c5_beta_3.ld new file mode 100755 index 0000000000..d9c3d3e5e0 --- /dev/null +++ b/tools/flasher_stub/ld/rom_32c5_beta_3.ld @@ -0,0 +1,429 @@ +/* ROM function interface esp32c5.rom.ld for esp32c5 + * + * + * Generated from ./target/esp32c5/interface-esp32c5.yml md5sum 2476337377df636dda217b0b3c1a63db + * + * Compatible with ROM where ECO version equal or greater to 0. + * + * THIS FILE WAS AUTOMATICALLY GENERATED. DO NOT EDIT. + */ + +/*************************************** + Group common + ***************************************/ + +PROVIDE ( SPIWrite = esp_rom_spiflash_write); +PROVIDE ( SPI_read_status_high = esp_rom_spiflash_read_statushigh); +PROVIDE ( SPI_write_status = esp_rom_spiflash_write_status); +PROVIDE ( SPIRead = esp_rom_spiflash_read); +PROVIDE ( SPIParamCfg = esp_rom_spiflash_config_param); +PROVIDE ( SPIEraseChip = esp_rom_spiflash_erase_chip); +PROVIDE ( SPIEraseSector = esp_rom_spiflash_erase_sector); +PROVIDE ( SPIEraseBlock = esp_rom_spiflash_erase_block); +PROVIDE ( SPI_Write_Encrypt_Enable = esp_rom_spiflash_write_encrypted_enable); +PROVIDE ( SPI_Write_Encrypt_Disable = esp_rom_spiflash_write_encrypted_disable); +PROVIDE ( SPI_Encrypt_Write = esp_rom_spiflash_write_encrypted); + +/*************************************** + Group common + ***************************************/ + +/* Functions */ +rtc_get_reset_reason = 0x40000018; +rtc_get_wakeup_cause = 0x4000001c; +pmu_enable_unhold_pads = 0x40000020; +ets_printf = 0x40000024; +ets_install_putc1 = 0x40000028; +ets_install_putc2 = 0x4000002c; +ets_install_uart_printf = 0x40000030; +ets_install_usb_printf = 0x40000034; +ets_get_printf_channel = 0x40000038; +ets_delay_us = 0x4000003c; +ets_get_cpu_frequency = 0x40000040; +ets_update_cpu_frequency = 0x40000044; +ets_install_lock = 0x40000048; +UartRxString = 0x4000004c; +UartGetCmdLn = 0x40000050; +uart_tx_one_char = 0x40000054; +uart_tx_one_char2 = 0x40000058; +uart_tx_one_char3 = 0x4000005c; +uart_rx_one_char = 0x40000060; +uart_rx_one_char_block = 0x40000064; +uart_rx_intr_handler = 0x40000068; +uart_rx_readbuff = 0x4000006c; +uartAttach = 0x40000070; +uart_tx_flush = 0x40000074; +uart_tx_wait_idle = 0x40000078; +uart_div_modify = 0x4000007c; +ets_write_char_uart = 0x40000080; +uart_tx_switch = 0x40000084; +uart_buff_switch = 0x40000088; +roundup2 = 0x4000008c; +multofup = 0x40000090; +software_reset = 0x40000094; +software_reset_cpu = 0x40000098; +ets_clk_assist_debug_clock_enable = 0x4000009c; +clear_super_wdt_reset_flag = 0x400000a0; +disable_default_watchdog = 0x400000a4; +esp_rom_set_rtc_wake_addr = 0x400000a8; +esp_rom_get_rtc_wake_addr = 0x400000ac; +send_packet = 0x400000b0; +recv_packet = 0x400000b4; +GetUartDevice = 0x400000b8; +UartDwnLdProc = 0x400000bc; +GetSecurityInfoProc = 0x400000c0; +Uart_Init = 0x400000c4; +ets_set_user_start = 0x400000c8; +/* Data (.data, .bss, .rodata) */ +ets_rom_layout_p = 0x4004fffc; +ets_ops_table_ptr = 0x4087fff8; +g_saved_pc = 0x4087fffc; + + +/*************************************** + Group miniz + ***************************************/ + +/* Functions */ +mz_adler32 = 0x400000cc; +mz_free = 0x400000d0; +tdefl_compress = 0x400000d4; +tdefl_compress_buffer = 0x400000d8; +tdefl_compress_mem_to_heap = 0x400000dc; +tdefl_compress_mem_to_mem = 0x400000e0; +tdefl_compress_mem_to_output = 0x400000e4; +tdefl_get_adler32 = 0x400000e8; +tdefl_get_prev_return_status = 0x400000ec; +tdefl_init = 0x400000f0; +tdefl_write_image_to_png_file_in_memory = 0x400000f4; +tdefl_write_image_to_png_file_in_memory_ex = 0x400000f8; +tinfl_decompress = 0x400000fc; +tinfl_decompress_mem_to_callback = 0x40000100; +tinfl_decompress_mem_to_heap = 0x40000104; +tinfl_decompress_mem_to_mem = 0x40000108; + + +/*************************************** + Group spiflash_legacy + ***************************************/ + +/* Functions */ +esp_rom_spiflash_wait_idle = 0x4000010c; +esp_rom_spiflash_write_encrypted = 0x40000110; +esp_rom_spiflash_write_encrypted_dest = 0x40000114; +esp_rom_spiflash_write_encrypted_enable = 0x40000118; +esp_rom_spiflash_write_encrypted_disable = 0x4000011c; +esp_rom_spiflash_erase_chip = 0x40000120; +_esp_rom_spiflash_erase_sector = 0x40000124; +_esp_rom_spiflash_erase_block = 0x40000128; +_esp_rom_spiflash_write = 0x4000012c; +_esp_rom_spiflash_read = 0x40000130; +_esp_rom_spiflash_unlock = 0x40000134; +_SPIEraseArea = 0x40000138; +_SPI_write_enable = 0x4000013c; +esp_rom_spiflash_erase_sector = 0x40000140; +esp_rom_spiflash_erase_block = 0x40000144; +esp_rom_spiflash_write = 0x40000148; +esp_rom_spiflash_read = 0x4000014c; +esp_rom_spiflash_unlock = 0x40000150; +SPIEraseArea = 0x40000154; +SPI_write_enable = 0x40000158; +esp_rom_spiflash_config_param = 0x4000015c; +esp_rom_spiflash_read_user_cmd = 0x40000160; +esp_rom_spiflash_select_qio_pins = 0x40000164; +esp_rom_spi_flash_auto_sus_res = 0x40000168; +esp_rom_spi_flash_send_resume = 0x4000016c; +esp_rom_spi_flash_update_id = 0x40000170; +esp_rom_spiflash_config_clk = 0x40000174; +esp_rom_spiflash_config_readmode = 0x40000178; +esp_rom_spiflash_read_status = 0x4000017c; +esp_rom_spiflash_read_statushigh = 0x40000180; +esp_rom_spiflash_write_status = 0x40000184; +esp_rom_spiflash_write_disable = 0x40000188; +spi_cache_mode_switch = 0x4000018c; +spi_common_set_dummy_output = 0x40000190; +spi_common_set_flash_cs_timing = 0x40000194; +esp_rom_spi_set_address_bit_len = 0x40000198; +SPILock = 0x4000019c; +SPIMasterReadModeCnfig = 0x400001a0; +SPI_Common_Command = 0x400001a4; +SPI_WakeUp = 0x400001a8; +SPI_block_erase = 0x400001ac; +SPI_chip_erase = 0x400001b0; +SPI_init = 0x400001b4; +SPI_page_program = 0x400001b8; +SPI_read_data = 0x400001bc; +SPI_sector_erase = 0x400001c0; +SelectSpiFunction = 0x400001c4; +SetSpiDrvs = 0x400001c8; +Wait_SPI_Idle = 0x400001cc; +spi_dummy_len_fix = 0x400001d0; +Disable_QMode = 0x400001d4; +Enable_QMode = 0x400001d8; +spi_flash_attach = 0x400001dc; +spi_flash_get_chip_size = 0x400001e0; +spi_flash_guard_set = 0x400001e4; +spi_flash_guard_get = 0x400001e8; +spi_flash_read_encrypted = 0x400001ec; +/* Data (.data, .bss, .rodata) */ +rom_spiflash_legacy_funcs = 0x4087fff0; +rom_spiflash_legacy_data = 0x4087ffec; +g_flash_guard_ops = 0x4087fff4; + + +/*************************************** + Group hal_wdt + ***************************************/ + +/* Functions */ +wdt_hal_init = 0x40000390; +wdt_hal_deinit = 0x40000394; +wdt_hal_config_stage = 0x40000398; +wdt_hal_write_protect_disable = 0x4000039c; +wdt_hal_write_protect_enable = 0x400003a0; +wdt_hal_enable = 0x400003a4; +wdt_hal_disable = 0x400003a8; +wdt_hal_handle_intr = 0x400003ac; +wdt_hal_feed = 0x400003b0; +wdt_hal_set_flashboot_en = 0x400003b4; +wdt_hal_is_enabled = 0x400003b8; + + +/*************************************** + Group hal_systimer + ***************************************/ + +/* Functions */ +systimer_hal_init = 0x400003bc; +systimer_hal_deinit = 0x400003c0; +systimer_hal_set_tick_rate_ops = 0x400003c4; +systimer_hal_get_counter_value = 0x400003c8; +systimer_hal_get_time = 0x400003cc; +systimer_hal_set_alarm_target = 0x400003d0; +systimer_hal_set_alarm_period = 0x400003d4; +systimer_hal_get_alarm_value = 0x400003d8; +systimer_hal_enable_alarm_int = 0x400003dc; +systimer_hal_on_apb_freq_update = 0x400003e0; +systimer_hal_counter_value_advance = 0x400003e4; +systimer_hal_enable_counter = 0x400003e8; +systimer_hal_select_alarm_mode = 0x400003ec; +systimer_hal_connect_alarm_counter = 0x400003f0; +systimer_hal_counter_can_stall_by_cpu = 0x400003f4; + + +/*************************************** + Group cache + ***************************************/ + +/* Functions */ +Cache_Get_ICache_Line_Size = 0x40000624; +Cache_Get_Mode = 0x40000628; +Cache_Address_Through_Cache = 0x4000062c; +ROM_Boot_Cache_Init = 0x40000630; +MMU_Set_Page_Mode = 0x40000634; +MMU_Get_Page_Mode = 0x40000638; +Cache_Invalidate_ICache_Items = 0x4000063c; +Cache_Op_Addr = 0x40000640; +Cache_Invalidate_Addr = 0x40000644; +Cache_Invalidate_ICache_All = 0x40000648; +Cache_Mask_All = 0x4000064c; +Cache_UnMask_Dram0 = 0x40000650; +Cache_Suspend_ICache_Autoload = 0x40000654; +Cache_Resume_ICache_Autoload = 0x40000658; +Cache_Start_ICache_Preload = 0x4000065c; +Cache_ICache_Preload_Done = 0x40000660; +Cache_End_ICache_Preload = 0x40000664; +Cache_Config_ICache_Autoload = 0x40000668; +Cache_Enable_ICache_Autoload = 0x4000066c; +Cache_Disable_ICache_Autoload = 0x40000670; +Cache_Enable_ICache_PreLock = 0x40000674; +Cache_Disable_ICache_PreLock = 0x40000678; +Cache_Lock_ICache_Items = 0x4000067c; +Cache_Unlock_ICache_Items = 0x40000680; +Cache_Lock_Addr = 0x40000684; +Cache_Unlock_Addr = 0x40000688; +Cache_Disable_ICache = 0x4000068c; +Cache_Enable_ICache = 0x40000690; +Cache_Suspend_ICache = 0x40000694; +Cache_Resume_ICache = 0x40000698; +Cache_Freeze_ICache_Enable = 0x4000069c; +Cache_Freeze_ICache_Disable = 0x400006a0; +Cache_Set_IDROM_MMU_Size = 0x400006a4; +Cache_Get_IROM_MMU_End = 0x400006a8; +Cache_Get_DROM_MMU_End = 0x400006ac; +Cache_MMU_Init = 0x400006b0; +Cache_MSPI_MMU_Set = 0x400006b4; +Cache_MSPI_MMU_Set_Secure = 0x400006b8; +Cache_Travel_Tag_Memory = 0x400006bc; +Cache_Get_Virtual_Addr = 0x400006c0; +/* Data (.data, .bss, .rodata) */ +rom_cache_op_cb = 0x4087ffcc; +rom_cache_internal_table_ptr = 0x4087ffc8; + + +/*************************************** + Group clock + ***************************************/ + +/* Functions */ +ets_clk_get_xtal_freq = 0x400006c4; +ets_clk_get_cpu_freq = 0x400006c8; + + +/*************************************** + Group gpio + ***************************************/ + +/* Functions */ +gpio_set_output_level = 0x400006cc; +gpio_get_input_level = 0x400006d0; +gpio_matrix_in = 0x400006d4; +gpio_matrix_out = 0x400006d8; +gpio_bypass_matrix_in = 0x400006dc; +gpio_output_disable = 0x400006e0; +gpio_output_enable = 0x400006e4; +gpio_pad_input_disable = 0x400006e8; +gpio_pad_input_enable = 0x400006ec; +gpio_pad_pulldown = 0x400006f0; +gpio_pad_pullup = 0x400006f4; +gpio_pad_select_gpio = 0x400006f8; +gpio_pad_set_drv = 0x400006fc; +gpio_pad_unhold = 0x40000700; +gpio_pad_hold = 0x40000704; + + +/*************************************** + Group interrupts + ***************************************/ + +/* Functions */ +esprv_intc_int_set_priority = 0x40000708; +esprv_intc_int_set_threshold = 0x4000070c; +esprv_intc_int_enable = 0x40000710; +esprv_intc_int_disable = 0x40000714; +esprv_intc_int_set_type = 0x40000718; +PROVIDE( intr_handler_set = 0x4000071c ); +intr_matrix_set = 0x40000720; +ets_intr_lock = 0x40000724; +ets_intr_unlock = 0x40000728; +ets_isr_attach = 0x4000072c; +ets_isr_mask = 0x40000730; +ets_isr_unmask = 0x40000734; + + +/*************************************** + Group crypto + ***************************************/ + +/* Functions */ +md5_vector = 0x40000738; +MD5Init = 0x4000073c; +MD5Update = 0x40000740; +MD5Final = 0x40000744; +crc32_le = 0x40000748; +crc16_le = 0x4000074c; +crc8_le = 0x40000750; +crc32_be = 0x40000754; +crc16_be = 0x40000758; +crc8_be = 0x4000075c; +esp_crc8 = 0x40000760; +ets_sha_enable = 0x40000764; +ets_sha_disable = 0x40000768; +ets_sha_get_state = 0x4000076c; +ets_sha_init = 0x40000770; +ets_sha_process = 0x40000774; +ets_sha_starts = 0x40000778; +ets_sha_update = 0x4000077c; +ets_sha_finish = 0x40000780; +ets_sha_clone = 0x40000784; +ets_hmac_enable = 0x40000788; +ets_hmac_disable = 0x4000078c; +ets_hmac_calculate_message = 0x40000790; +ets_hmac_calculate_downstream = 0x40000794; +ets_hmac_invalidate_downstream = 0x40000798; +ets_jtag_enable_temporarily = 0x4000079c; +ets_aes_enable = 0x400007a0; +ets_aes_disable = 0x400007a4; +ets_aes_setkey = 0x400007a8; +ets_aes_block = 0x400007ac; +ets_aes_setkey_dec = 0x400007b0; +ets_aes_setkey_enc = 0x400007b4; +ets_bigint_enable = 0x400007b8; +ets_bigint_disable = 0x400007bc; +ets_bigint_multiply = 0x400007c0; +ets_bigint_modmult = 0x400007c4; +ets_bigint_modexp = 0x400007c8; +ets_bigint_wait_finish = 0x400007cc; +ets_bigint_getz = 0x400007d0; +ets_ds_enable = 0x400007d4; +ets_ds_disable = 0x400007d8; +ets_ds_start_sign = 0x400007dc; +ets_ds_is_busy = 0x400007e0; +ets_ds_finish_sign = 0x400007e4; +ets_ds_encrypt_params = 0x400007e8; +ets_mgf1_sha256 = 0x400007ec; +/* Data (.data, .bss, .rodata) */ +crc32_le_table_ptr = 0x4004fff8; +crc16_le_table_ptr = 0x4004fff4; +crc8_le_table_ptr = 0x4004fff0; +crc32_be_table_ptr = 0x4004ffec; +crc16_be_table_ptr = 0x4004ffe8; +crc8_be_table_ptr = 0x4004ffe4; + + +/*************************************** + Group efuse + ***************************************/ + +/* Functions */ +ets_efuse_read = 0x400007f0; +ets_efuse_program = 0x400007f4; +ets_efuse_clear_program_registers = 0x400007f8; +ets_efuse_write_key = 0x400007fc; +ets_efuse_get_read_register_address = 0x40000800; +ets_efuse_get_key_purpose = 0x40000804; +ets_efuse_key_block_unused = 0x40000808; +ets_efuse_find_unused_key_block = 0x4000080c; +ets_efuse_rs_calculate = 0x40000810; +ets_efuse_count_unused_key_blocks = 0x40000814; +ets_efuse_secure_boot_enabled = 0x40000818; +ets_efuse_secure_boot_aggressive_revoke_enabled = 0x4000081c; +ets_efuse_cache_encryption_enabled = 0x40000820; +ets_efuse_download_modes_disabled = 0x40000824; +ets_efuse_find_purpose = 0x40000828; +ets_efuse_force_send_resume = 0x4000082c; +ets_efuse_get_flash_delay_us = 0x40000830; +ets_efuse_get_uart_print_control = 0x40000834; +ets_efuse_direct_boot_mode_disabled = 0x40000838; +ets_efuse_security_download_modes_enabled = 0x4000083c; +ets_efuse_jtag_disabled = 0x40000840; +ets_efuse_usb_print_is_disabled = 0x40000844; +ets_efuse_usb_download_mode_disabled = 0x40000848; +ets_efuse_usb_device_disabled = 0x4000084c; +ets_efuse_secure_boot_fast_wake_enabled = 0x40000850; + + +/*************************************** + Group secureboot + ***************************************/ + +/* Functions */ +ets_emsa_pss_verify = 0x40000854; +ets_rsa_pss_verify = 0x40000858; +ets_ecdsa_verify = 0x4000085c; +ets_secure_boot_verify_bootloader_with_keys = 0x40000860; +ets_secure_boot_verify_signature = 0x40000864; +ets_secure_boot_read_key_digests = 0x40000868; +ets_secure_boot_revoke_public_key_digest = 0x4000086c; + + +/*************************************** + Group usb_device_uart + ***************************************/ + +/* Functions */ +usb_serial_device_rx_one_char = 0x40000a6c; +usb_serial_device_rx_one_char_block = 0x40000a70; +usb_serial_device_tx_flush = 0x40000a74; +usb_serial_device_tx_one_char = 0x40000a78; + diff --git a/tools/flasher_stub/ld/rom_32c6.ld b/tools/flasher_stub/ld/rom_32c6.ld new file mode 100755 index 0000000000..47466e9770 --- /dev/null +++ b/tools/flasher_stub/ld/rom_32c6.ld @@ -0,0 +1,487 @@ +/* ROM function interface esp32c6.rom.ld for esp32c6 + * + * + * Generated from ./target/esp32c6/interface-esp32c6.yml md5sum 626e7f1bf23e87c38db8c3f22a53407b + * + * Compatible with ROM where ECO version equal or greater to 0. + * + * THIS FILE WAS AUTOMATICALLY GENERATED. DO NOT EDIT. + */ + +/*************************************** + Group common + ***************************************/ + +PROVIDE ( SPIWrite = esp_rom_spiflash_write); +PROVIDE ( SPI_read_status_high = esp_rom_spiflash_read_statushigh); +PROVIDE ( SPI_write_status = esp_rom_spiflash_write_status); +PROVIDE ( SPIRead = esp_rom_spiflash_read); +PROVIDE ( SPIParamCfg = esp_rom_spiflash_config_param); +PROVIDE ( SPIEraseChip = esp_rom_spiflash_erase_chip); +PROVIDE ( SPIEraseSector = esp_rom_spiflash_erase_sector); +PROVIDE ( SPIEraseBlock = esp_rom_spiflash_erase_block); +PROVIDE ( SPI_Write_Encrypt_Enable = esp_rom_spiflash_write_encrypted_enable); +PROVIDE ( SPI_Write_Encrypt_Disable = esp_rom_spiflash_write_encrypted_disable); +PROVIDE ( SPI_Encrypt_Write = esp_rom_spiflash_write_encrypted); + +/*************************************** + Group common + ***************************************/ + +/* Functions */ +rtc_get_reset_reason = 0x40000018; +analog_super_wdt_reset_happened = 0x4000001c; +rtc_get_wakeup_cause = 0x40000020; +rtc_unhold_all_pads = 0x40000024; +ets_printf = 0x40000028; +ets_install_putc1 = 0x4000002c; +ets_install_putc2 = 0x40000030; +ets_install_uart_printf = 0x40000034; +ets_install_usb_printf = 0x40000038; +ets_get_printf_channel = 0x4000003c; +ets_delay_us = 0x40000040; +ets_get_cpu_frequency = 0x40000044; +ets_update_cpu_frequency = 0x40000048; +ets_install_lock = 0x4000004c; +UartRxString = 0x40000050; +UartGetCmdLn = 0x40000054; +uart_tx_one_char = 0x40000058; +uart_tx_one_char2 = 0x4000005c; +uart_rx_one_char = 0x40000060; +uart_rx_one_char_block = 0x40000064; +uart_rx_intr_handler = 0x40000068; +uart_rx_readbuff = 0x4000006c; +uartAttach = 0x40000070; +uart_tx_flush = 0x40000074; +uart_tx_wait_idle = 0x40000078; +uart_div_modify = 0x4000007c; +ets_write_char_uart = 0x40000080; +uart_tx_switch = 0x40000084; +roundup2 = 0x40000088; +multofup = 0x4000008c; +software_reset = 0x40000090; +software_reset_cpu = 0x40000094; +ets_clk_assist_debug_clock_enable = 0x40000098; +clear_super_wdt_reset_flag = 0x4000009c; +disable_default_watchdog = 0x400000a0; +esp_rom_set_rtc_wake_addr = 0x400000a4; +esp_rom_get_rtc_wake_addr = 0x400000a8; +send_packet = 0x400000ac; +recv_packet = 0x400000b0; +GetUartDevice = 0x400000b4; +UartDwnLdProc = 0x400000b8; +GetSecurityInfoProc = 0x400000bc; +Uart_Init = 0x400000c0; +ets_set_user_start = 0x400000c4; +/* Data (.data, .bss, .rodata) */ +ets_rom_layout_p = 0x4004fffc; +ets_ops_table_ptr = 0x4087fff8; +g_saved_pc = 0x4087fffc; + + +/*************************************** + Group miniz + ***************************************/ + +/* Functions */ +mz_adler32 = 0x400000c8; +mz_free = 0x400000cc; +tdefl_compress = 0x400000d0; +tdefl_compress_buffer = 0x400000d4; +tdefl_compress_mem_to_heap = 0x400000d8; +tdefl_compress_mem_to_mem = 0x400000dc; +tdefl_compress_mem_to_output = 0x400000e0; +tdefl_get_adler32 = 0x400000e4; +tdefl_get_prev_return_status = 0x400000e8; +tdefl_init = 0x400000ec; +tdefl_write_image_to_png_file_in_memory = 0x400000f0; +tdefl_write_image_to_png_file_in_memory_ex = 0x400000f4; +tinfl_decompress = 0x400000f8; +tinfl_decompress_mem_to_callback = 0x400000fc; +tinfl_decompress_mem_to_heap = 0x40000100; +tinfl_decompress_mem_to_mem = 0x40000104; + + +/*************************************** + Group tjpgd + ***************************************/ + +/* Functions */ +jd_prepare = 0x40000108; +jd_decomp = 0x4000010c; + + +/*************************************** + Group spiflash_legacy + ***************************************/ + +/* Functions */ +esp_rom_spiflash_wait_idle = 0x40000110; +esp_rom_spiflash_write_encrypted = 0x40000114; +esp_rom_spiflash_write_encrypted_dest = 0x40000118; +esp_rom_spiflash_write_encrypted_enable = 0x4000011c; +esp_rom_spiflash_write_encrypted_disable = 0x40000120; +esp_rom_spiflash_erase_chip = 0x40000124; +_esp_rom_spiflash_erase_sector = 0x40000128; +_esp_rom_spiflash_erase_block = 0x4000012c; +_esp_rom_spiflash_write = 0x40000130; +_esp_rom_spiflash_read = 0x40000134; +_esp_rom_spiflash_unlock = 0x40000138; +_SPIEraseArea = 0x4000013c; +_SPI_write_enable = 0x40000140; +esp_rom_spiflash_erase_sector = 0x40000144; +esp_rom_spiflash_erase_block = 0x40000148; +esp_rom_spiflash_write = 0x4000014c; +esp_rom_spiflash_read = 0x40000150; +esp_rom_spiflash_unlock = 0x40000154; +SPIEraseArea = 0x40000158; +SPI_write_enable = 0x4000015c; +esp_rom_spiflash_config_param = 0x40000160; +esp_rom_spiflash_read_user_cmd = 0x40000164; +esp_rom_spiflash_select_qio_pins = 0x40000168; +esp_rom_spi_flash_auto_sus_res = 0x4000016c; +esp_rom_spi_flash_send_resume = 0x40000170; +esp_rom_spi_flash_update_id = 0x40000174; +esp_rom_spiflash_config_clk = 0x40000178; +esp_rom_spiflash_config_readmode = 0x4000017c; +esp_rom_spiflash_read_status = 0x40000180; +esp_rom_spiflash_read_statushigh = 0x40000184; +esp_rom_spiflash_write_status = 0x40000188; +spi_cache_mode_switch = 0x4000018c; +spi_common_set_dummy_output = 0x40000190; +spi_common_set_flash_cs_timing = 0x40000194; +esp_rom_spi_set_address_bit_len = 0x40000198; +SPILock = 0x4000019c; +SPIMasterReadModeCnfig = 0x400001a0; +SPI_Common_Command = 0x400001a4; +SPI_WakeUp = 0x400001a8; +SPI_block_erase = 0x400001ac; +SPI_chip_erase = 0x400001b0; +SPI_init = 0x400001b4; +SPI_page_program = 0x400001b8; +SPI_read_data = 0x400001bc; +SPI_sector_erase = 0x400001c0; +SelectSpiFunction = 0x400001c4; +SetSpiDrvs = 0x400001c8; +Wait_SPI_Idle = 0x400001cc; +spi_dummy_len_fix = 0x400001d0; +Disable_QMode = 0x400001d4; +Enable_QMode = 0x400001d8; +spi_flash_attach = 0x400001dc; +spi_flash_get_chip_size = 0x400001e0; +spi_flash_guard_set = 0x400001e4; +spi_flash_guard_get = 0x400001e8; +spi_flash_read_encrypted = 0x400001ec; +/* Data (.data, .bss, .rodata) */ +rom_spiflash_legacy_funcs = 0x4087fff0; +rom_spiflash_legacy_data = 0x4087ffec; +g_flash_guard_ops = 0x4087fff4; + + +/*************************************** + Group hal_wdt + ***************************************/ + +/* Functions */ +wdt_hal_init = 0x40000394; +wdt_hal_deinit = 0x40000398; +wdt_hal_config_stage = 0x4000039c; +wdt_hal_write_protect_disable = 0x400003a0; +wdt_hal_write_protect_enable = 0x400003a4; +wdt_hal_enable = 0x400003a8; +wdt_hal_disable = 0x400003ac; +wdt_hal_handle_intr = 0x400003b0; +wdt_hal_feed = 0x400003b4; +wdt_hal_set_flashboot_en = 0x400003b8; +wdt_hal_is_enabled = 0x400003bc; + + +/*************************************** + Group hal_systimer + ***************************************/ + +/* Functions */ +systimer_hal_init = 0x400003c0; +systimer_hal_deinit = 0x400003c4; +systimer_hal_set_tick_rate_ops = 0x400003c8; +systimer_hal_get_counter_value = 0x400003cc; +systimer_hal_get_time = 0x400003d0; +systimer_hal_set_alarm_target = 0x400003d4; +systimer_hal_set_alarm_period = 0x400003d8; +systimer_hal_get_alarm_value = 0x400003dc; +systimer_hal_enable_alarm_int = 0x400003e0; +systimer_hal_on_apb_freq_update = 0x400003e4; +systimer_hal_counter_value_advance = 0x400003e8; +systimer_hal_enable_counter = 0x400003ec; +systimer_hal_select_alarm_mode = 0x400003f0; +systimer_hal_connect_alarm_counter = 0x400003f4; +systimer_hal_counter_can_stall_by_cpu = 0x400003f8; + + +/*************************************** + Group cache + ***************************************/ + +/* Functions */ +Cache_Get_ICache_Line_Size = 0x40000628; +Cache_Get_Mode = 0x4000062c; +Cache_Address_Through_Cache = 0x40000630; +ROM_Boot_Cache_Init = 0x40000634; +MMU_Set_Page_Mode = 0x40000638; +MMU_Get_Page_Mode = 0x4000063c; +Cache_Invalidate_ICache_Items = 0x40000640; +Cache_Op_Addr = 0x40000644; +Cache_Invalidate_Addr = 0x40000648; +Cache_Invalidate_ICache_All = 0x4000064c; +Cache_Mask_All = 0x40000650; +Cache_UnMask_Dram0 = 0x40000654; +Cache_Suspend_ICache_Autoload = 0x40000658; +Cache_Resume_ICache_Autoload = 0x4000065c; +Cache_Start_ICache_Preload = 0x40000660; +Cache_ICache_Preload_Done = 0x40000664; +Cache_End_ICache_Preload = 0x40000668; +Cache_Config_ICache_Autoload = 0x4000066c; +Cache_Enable_ICache_Autoload = 0x40000670; +Cache_Disable_ICache_Autoload = 0x40000674; +Cache_Enable_ICache_PreLock = 0x40000678; +Cache_Disable_ICache_PreLock = 0x4000067c; +Cache_Lock_ICache_Items = 0x40000680; +Cache_Unlock_ICache_Items = 0x40000684; +Cache_Lock_Addr = 0x40000688; +Cache_Unlock_Addr = 0x4000068c; +Cache_Disable_ICache = 0x40000690; +Cache_Enable_ICache = 0x40000694; +Cache_Suspend_ICache = 0x40000698; +Cache_Resume_ICache = 0x4000069c; +Cache_Freeze_ICache_Enable = 0x400006a0; +Cache_Freeze_ICache_Disable = 0x400006a4; +Cache_Set_IDROM_MMU_Size = 0x400006a8; +Cache_Get_IROM_MMU_End = 0x400006ac; +Cache_Get_DROM_MMU_End = 0x400006b0; +Cache_MMU_Init = 0x400006b4; +Cache_MSPI_MMU_Set = 0x400006b8; +Cache_Travel_Tag_Memory = 0x400006bc; +Cache_Get_Virtual_Addr = 0x400006c0; +/* Data (.data, .bss, .rodata) */ +rom_cache_op_cb = 0x4087ffcc; +rom_cache_internal_table_ptr = 0x4087ffc8; + + +/*************************************** + Group clock + ***************************************/ + +/* Functions */ +ets_clk_get_xtal_freq = 0x400006c4; +ets_clk_get_cpu_freq = 0x400006c8; +ets_clk_apb_wait_ready = 0x400006cc; +ets_clk_mspi_apb_wait_ready = 0x400006d0; + + +/*************************************** + Group gpio + ***************************************/ + +/* Functions */ +gpio_input_get = 0x400006d4; +gpio_matrix_in = 0x400006d8; +gpio_matrix_out = 0x400006dc; +gpio_output_disable = 0x400006e0; +gpio_output_enable = 0x400006e4; +gpio_output_set = 0x400006e8; +gpio_pad_hold = 0x400006ec; +gpio_pad_input_disable = 0x400006f0; +gpio_pad_input_enable = 0x400006f4; +gpio_pad_pulldown = 0x400006f8; +gpio_pad_pullup = 0x400006fc; +gpio_pad_select_gpio = 0x40000700; +gpio_pad_set_drv = 0x40000704; +gpio_pad_unhold = 0x40000708; +gpio_pin_wakeup_disable = 0x4000070c; +gpio_pin_wakeup_enable = 0x40000710; +gpio_bypass_matrix_in = 0x40000714; + + +/*************************************** + Group interrupts + ***************************************/ + +/* Functions */ +esprv_intc_int_set_priority = 0x40000718; +esprv_intc_int_set_threshold = 0x4000071c; +esprv_intc_int_enable = 0x40000720; +esprv_intc_int_disable = 0x40000724; +esprv_intc_int_set_type = 0x40000728; +PROVIDE( intr_handler_set = 0x4000072c ); +intr_matrix_set = 0x40000730; +ets_intr_lock = 0x40000734; +ets_intr_unlock = 0x40000738; +ets_isr_attach = 0x4000073c; +ets_isr_mask = 0x40000740; +ets_isr_unmask = 0x40000744; + + +/*************************************** + Group crypto + ***************************************/ + +/* Functions */ +md5_vector = 0x40000748; +MD5Init = 0x4000074c; +MD5Update = 0x40000750; +MD5Final = 0x40000754; +crc32_le = 0x40000758; +crc16_le = 0x4000075c; +crc8_le = 0x40000760; +crc32_be = 0x40000764; +crc16_be = 0x40000768; +crc8_be = 0x4000076c; +esp_crc8 = 0x40000770; +ets_sha_enable = 0x40000774; +ets_sha_disable = 0x40000778; +ets_sha_get_state = 0x4000077c; +ets_sha_init = 0x40000780; +ets_sha_process = 0x40000784; +ets_sha_starts = 0x40000788; +ets_sha_update = 0x4000078c; +ets_sha_finish = 0x40000790; +ets_sha_clone = 0x40000794; +ets_hmac_enable = 0x40000798; +ets_hmac_disable = 0x4000079c; +ets_hmac_calculate_message = 0x400007a0; +ets_hmac_calculate_downstream = 0x400007a4; +ets_hmac_invalidate_downstream = 0x400007a8; +ets_jtag_enable_temporarily = 0x400007ac; +ets_aes_enable = 0x400007b0; +ets_aes_disable = 0x400007b4; +ets_aes_setkey = 0x400007b8; +ets_aes_block = 0x400007bc; +ets_aes_setkey_dec = 0x400007c0; +ets_aes_setkey_enc = 0x400007c4; +ets_bigint_enable = 0x400007c8; +ets_bigint_disable = 0x400007cc; +ets_bigint_multiply = 0x400007d0; +ets_bigint_modmult = 0x400007d4; +ets_bigint_modexp = 0x400007d8; +ets_bigint_wait_finish = 0x400007dc; +ets_bigint_getz = 0x400007e0; +ets_ds_enable = 0x400007e4; +ets_ds_disable = 0x400007e8; +ets_ds_start_sign = 0x400007ec; +ets_ds_is_busy = 0x400007f0; +ets_ds_finish_sign = 0x400007f4; +ets_ds_encrypt_params = 0x400007f8; +ets_mgf1_sha256 = 0x400007fc; +/* Data (.data, .bss, .rodata) */ +crc32_le_table_ptr = 0x4004fff8; +crc16_le_table_ptr = 0x4004fff4; +crc8_le_table_ptr = 0x4004fff0; +crc32_be_table_ptr = 0x4004ffec; +crc16_be_table_ptr = 0x4004ffe8; +crc8_be_table_ptr = 0x4004ffe4; + + +/*************************************** + Group efuse + ***************************************/ + +/* Functions */ +ets_efuse_read = 0x40000800; +ets_efuse_program = 0x40000804; +ets_efuse_clear_program_registers = 0x40000808; +ets_efuse_write_key = 0x4000080c; +ets_efuse_get_read_register_address = 0x40000810; +ets_efuse_get_key_purpose = 0x40000814; +ets_efuse_key_block_unused = 0x40000818; +ets_efuse_find_unused_key_block = 0x4000081c; +ets_efuse_rs_calculate = 0x40000820; +ets_efuse_count_unused_key_blocks = 0x40000824; +ets_efuse_secure_boot_enabled = 0x40000828; +ets_efuse_secure_boot_aggressive_revoke_enabled = 0x4000082c; +ets_efuse_cache_encryption_enabled = 0x40000830; +ets_efuse_download_modes_disabled = 0x40000834; +ets_efuse_find_purpose = 0x40000838; +ets_efuse_force_send_resume = 0x4000083c; +ets_efuse_get_flash_delay_us = 0x40000840; +ets_efuse_get_mac = 0x40000844; +ets_efuse_get_uart_print_control = 0x40000848; +ets_efuse_direct_boot_mode_disabled = 0x4000084c; +ets_efuse_security_download_modes_enabled = 0x40000850; +ets_efuse_set_timing = 0x40000854; +ets_efuse_jtag_disabled = 0x40000858; +ets_efuse_usb_print_is_disabled = 0x4000085c; +ets_efuse_usb_download_mode_disabled = 0x40000860; +ets_efuse_usb_device_disabled = 0x40000864; +ets_efuse_secure_boot_fast_wake_enabled = 0x40000868; + + +/*************************************** + Group secureboot + ***************************************/ + +/* Functions */ +ets_emsa_pss_verify = 0x4000086c; +ets_rsa_pss_verify = 0x40000870; +ets_secure_boot_verify_bootloader_with_keys = 0x40000874; +ets_secure_boot_verify_signature = 0x40000878; +ets_secure_boot_read_key_digests = 0x4000087c; +ets_secure_boot_revoke_public_key_digest = 0x40000880; + + +/*************************************** + Group usb_device_uart + ***************************************/ + +/* Functions */ +usb_serial_device_rx_one_char = 0x40000a80; +usb_serial_device_rx_one_char_block = 0x40000a84; +usb_serial_device_tx_flush = 0x40000a88; +usb_serial_device_tx_one_char = 0x40000a8c; + + +/*************************************** + Group lldesc + ***************************************/ + +/* Functions */ +lldesc_build_chain = 0x40000a90; + + +/*************************************** + Group sip + ***************************************/ + +/* Functions */ +sip_after_tx_complete = 0x40000a94; +sip_alloc_to_host_evt = 0x40000a98; +sip_download_begin = 0x40000a9c; +sip_get_ptr = 0x40000aa0; +sip_get_state = 0x40000aa4; +sip_init_attach = 0x40000aa8; +sip_install_rx_ctrl_cb = 0x40000aac; +sip_install_rx_data_cb = 0x40000ab0; +sip_is_active = 0x40000ab4; +sip_post_init = 0x40000ab8; +sip_reclaim_from_host_cmd = 0x40000abc; +sip_reclaim_tx_data_pkt = 0x40000ac0; +sip_send = 0x40000ac4; +sip_to_host_chain_append = 0x40000ac8; +sip_to_host_evt_send_done = 0x40000acc; + + +/*************************************** + Group slc + ***************************************/ + +/* Functions */ +slc_add_credits = 0x40000ad0; +slc_enable = 0x40000ad4; +slc_from_host_chain_fetch = 0x40000ad8; +slc_from_host_chain_recycle = 0x40000adc; +slc_has_pkt_to_host = 0x40000ae0; +slc_init_attach = 0x40000ae4; +slc_init_credit = 0x40000ae8; +slc_reattach = 0x40000aec; +slc_send_to_host_chain = 0x40000af0; +slc_set_host_io_max_window = 0x40000af4; +slc_to_host_chain_recycle = 0x40000af8; diff --git a/tools/flasher_stub/ld/rom_32c61.ld b/tools/flasher_stub/ld/rom_32c61.ld new file mode 100644 index 0000000000..ac4419af7d --- /dev/null +++ b/tools/flasher_stub/ld/rom_32c61.ld @@ -0,0 +1,406 @@ +/* ROM function interface esp32c61.rom.ld for esp32c61 + * + * + * Generated from ./target/esp32c6lite/interface-esp32c6lite.yml md5sum 27eb0efac0883ee622c22767242c9457 + * + * Compatible with ROM where ECO version equal or greater to 0. + * + * THIS FILE WAS AUTOMATICALLY GENERATED. DO NOT EDIT. + */ + +/*************************************** + Group common + ***************************************/ + +PROVIDE ( SPIWrite = esp_rom_spiflash_write); +PROVIDE ( SPI_read_status_high = esp_rom_spiflash_read_statushigh); +PROVIDE ( SPI_write_status = esp_rom_spiflash_write_status); +PROVIDE ( SPIRead = esp_rom_spiflash_read); +PROVIDE ( SPIParamCfg = esp_rom_spiflash_config_param); +PROVIDE ( SPIEraseChip = esp_rom_spiflash_erase_chip); +PROVIDE ( SPIEraseSector = esp_rom_spiflash_erase_sector); +PROVIDE ( SPIEraseBlock = esp_rom_spiflash_erase_block); +PROVIDE ( SPI_Write_Encrypt_Enable = esp_rom_spiflash_write_encrypted_enable); +PROVIDE ( SPI_Write_Encrypt_Disable = esp_rom_spiflash_write_encrypted_disable); +PROVIDE ( SPI_Encrypt_Write = esp_rom_spiflash_write_encrypted); + +/*************************************** + Group common + ***************************************/ + +/* Functions */ +rtc_get_reset_reason = 0x40000018; +rtc_get_wakeup_cause = 0x4000001c; +pmu_enable_unhold_pads = 0x40000020; +ets_printf = 0x40000024; +ets_install_putc1 = 0x40000028; +ets_install_putc2 = 0x4000002c; +ets_install_uart_printf = 0x40000030; +ets_install_usb_printf = 0x40000034; +ets_get_printf_channel = 0x40000038; +ets_delay_us = 0x4000003c; +ets_get_cpu_frequency = 0x40000040; +ets_update_cpu_frequency = 0x40000044; +ets_install_lock = 0x40000048; +UartRxString = 0x4000004c; +UartGetCmdLn = 0x40000050; +uart_tx_one_char = 0x40000054; +uart_tx_one_char2 = 0x40000058; +uart_tx_one_char3 = 0x4000005c; +uart_rx_one_char = 0x40000060; +uart_rx_one_char_block = 0x40000064; +uart_rx_intr_handler = 0x40000068; +uart_rx_readbuff = 0x4000006c; +uartAttach = 0x40000070; +uart_tx_flush = 0x40000074; +uart_tx_wait_idle = 0x40000078; +uart_div_modify = 0x4000007c; +ets_write_char_uart = 0x40000080; +uart_tx_switch = 0x40000084; +uart_buff_switch = 0x40000088; +roundup2 = 0x4000008c; +multofup = 0x40000090; +software_reset = 0x40000094; +software_reset_cpu = 0x40000098; +ets_clk_assist_debug_clock_enable = 0x4000009c; +clear_super_wdt_reset_flag = 0x400000a0; +disable_default_watchdog = 0x400000a4; +esp_rom_set_rtc_wake_addr = 0x400000a8; +esp_rom_get_rtc_wake_addr = 0x400000ac; +send_packet = 0x400000b0; +recv_packet = 0x400000b4; +GetUartDevice = 0x400000b8; +UartDwnLdProc = 0x400000bc; +GetSecurityInfoProc = 0x400000c0; +Uart_Init = 0x400000c4; +ets_set_user_start = 0x400000c8; +/* Data (.data, .bss, .rodata) */ +ets_rom_layout_p = 0x4003fffc; +ets_ops_table_ptr = 0x4084fff8; +g_saved_pc = 0x4084fffc; + + +/*************************************** + Group miniz + ***************************************/ + +/* Functions */ +mz_adler32 = 0x400000cc; +mz_free = 0x400000d0; +tdefl_compress = 0x400000d4; +tdefl_compress_buffer = 0x400000d8; +tdefl_compress_mem_to_heap = 0x400000dc; +tdefl_compress_mem_to_mem = 0x400000e0; +tdefl_compress_mem_to_output = 0x400000e4; +tdefl_get_adler32 = 0x400000e8; +tdefl_get_prev_return_status = 0x400000ec; +tdefl_init = 0x400000f0; +tdefl_write_image_to_png_file_in_memory = 0x400000f4; +tdefl_write_image_to_png_file_in_memory_ex = 0x400000f8; +tinfl_decompress = 0x400000fc; +tinfl_decompress_mem_to_callback = 0x40000100; +tinfl_decompress_mem_to_heap = 0x40000104; +tinfl_decompress_mem_to_mem = 0x40000108; + + +/*************************************** + Group tjpgd + ***************************************/ + +/* Functions */ +jd_prepare = 0x4000010c; +jd_decomp = 0x40000110; + + +/*************************************** + Group spi_extmem_common + ***************************************/ + +/* Functions */ +esp_rom_spi_cmd_config = 0x40000114; +esp_rom_spi_cmd_start = 0x40000118; +esp_rom_spi_set_op_mode = 0x4000011c; + + +/*************************************** + Group spiflash_legacy + ***************************************/ + +/* Functions */ +esp_rom_spiflash_wait_idle = 0x40000120; +esp_rom_spiflash_write_encrypted = 0x40000124; +esp_rom_spiflash_write_encrypted_dest = 0x40000128; +esp_rom_spiflash_write_encrypted_enable = 0x4000012c; +esp_rom_spiflash_write_encrypted_disable = 0x40000130; +esp_rom_spiflash_erase_chip = 0x40000134; +_esp_rom_spiflash_erase_sector = 0x40000138; +_esp_rom_spiflash_erase_block = 0x4000013c; +_esp_rom_spiflash_write = 0x40000140; +_esp_rom_spiflash_read = 0x40000144; +_esp_rom_spiflash_unlock = 0x40000148; +_SPIEraseArea = 0x4000014c; +_SPI_write_enable = 0x40000150; +esp_rom_spiflash_erase_sector = 0x40000154; +esp_rom_spiflash_erase_block = 0x40000158; +esp_rom_spiflash_write = 0x4000015c; +esp_rom_spiflash_read = 0x40000160; +esp_rom_spiflash_unlock = 0x40000164; +SPIEraseArea = 0x40000168; +SPI_write_enable = 0x4000016c; +esp_rom_spiflash_config_param = 0x40000170; +esp_rom_spiflash_read_user_cmd = 0x40000174; +esp_rom_spiflash_select_qio_pins = 0x40000178; +esp_rom_spi_flash_auto_sus_res = 0x4000017c; +esp_rom_spi_flash_send_resume = 0x40000180; +esp_rom_spi_flash_update_id = 0x40000184; +esp_rom_spiflash_config_clk = 0x40000188; +esp_rom_spiflash_config_readmode = 0x4000018c; +esp_rom_spiflash_read_status = 0x40000190; +esp_rom_spiflash_read_statushigh = 0x40000194; +esp_rom_spiflash_write_status = 0x40000198; +esp_rom_spiflash_write_disable = 0x4000019c; +spi_cache_mode_switch = 0x400001a0; +spi_common_set_dummy_output = 0x400001a4; +spi_common_set_flash_cs_timing = 0x400001a8; +esp_rom_spi_set_address_bit_len = 0x400001ac; +SPILock = 0x400001b0; +SPIMasterReadModeCnfig = 0x400001b4; +SPI_Common_Command = 0x400001b8; +SPI_WakeUp = 0x400001bc; +SPI_block_erase = 0x400001c0; +SPI_chip_erase = 0x400001c4; +SPI_init = 0x400001c8; +SPI_page_program = 0x400001cc; +SPI_read_data = 0x400001d0; +SPI_sector_erase = 0x400001d4; +SelectSpiFunction = 0x400001d8; +SetSpiDrvs = 0x400001dc; +Wait_SPI_Idle = 0x400001e0; +spi_dummy_len_fix = 0x400001e4; +Disable_QMode = 0x400001e8; +Enable_QMode = 0x400001ec; +spi_flash_attach = 0x400001f0; +spi_flash_get_chip_size = 0x400001f4; +spi_flash_guard_set = 0x400001f8; +spi_flash_guard_get = 0x400001fc; +spi_flash_read_encrypted = 0x40000200; +/* Data (.data, .bss, .rodata) */ +rom_spiflash_legacy_funcs = 0x4084fff0; +rom_spiflash_legacy_data = 0x4084ffec; +g_flash_guard_ops = 0x4084fff4; + + +/*************************************** + Group cache + ***************************************/ + +/* Functions */ +Cache_Get_Line_Size = 0x40000614; +Cache_Get_Mode = 0x40000618; +Cache_Address_Through_Cache = 0x4000061c; +ROM_Boot_Cache_Init = 0x40000620; +MMU_Set_Page_Mode = 0x40000624; +MMU_Get_Page_Mode = 0x40000628; +Cache_Sync_Items = 0x4000062c; +Cache_Op_Addr = 0x40000630; +Cache_Invalidate_Addr = 0x40000634; +Cache_Clean_Addr = 0x40000638; +Cache_WriteBack_Addr = 0x4000063c; +Cache_WriteBack_Invalidate_Addr = 0x40000640; +Cache_Invalidate_All = 0x40000644; +Cache_Clean_All = 0x40000648; +Cache_WriteBack_All = 0x4000064c; +Cache_WriteBack_Invalidate_All = 0x40000650; +Cache_Mask_All = 0x40000654; +Cache_UnMask_Dram0 = 0x40000658; +Cache_Suspend_Autoload = 0x4000065c; +Cache_Resume_Autoload = 0x40000660; +Cache_Start_Preload = 0x40000664; +Cache_Preload_Done = 0x40000668; +Cache_End_Preload = 0x4000066c; +Cache_Config_Autoload = 0x40000670; +Cache_Enable_Autoload = 0x40000674; +Cache_Disable_Autoload = 0x40000678; +Cache_Enable_PreLock = 0x4000067c; +Cache_Disable_PreLock = 0x40000680; +Cache_Lock_Items = 0x40000684; +Cache_Lock_Addr = 0x40000688; +Cache_Unlock_Addr = 0x4000068c; +Cache_Disable_Cache = 0x40000690; +Cache_Enable_Cache = 0x40000694; +Cache_Suspend_Cache = 0x40000698; +Cache_Resume_Cache = 0x4000069c; +Cache_Freeze_Enable = 0x400006a0; +Cache_Freeze_Disable = 0x400006a4; +Cache_Set_IDROM_MMU_Size = 0x400006a8; +Cache_Get_IROM_MMU_End = 0x400006ac; +Cache_Get_DROM_MMU_End = 0x400006b0; +Cache_MMU_Init = 0x400006b4; +Cache_MSPI_MMU_Set = 0x400006b8; +Cache_MSPI_MMU_Set_Secure = 0x400006bc; +Cache_Count_Flash_Pages = 0x400006c0; +Cache_Travel_Tag_Memory = 0x400006c4; +Cache_Get_Virtual_Addr = 0x400006c8; +flash2spiram_instruction_offset = 0x400006cc; +flash2spiram_rodata_offset = 0x400006d0; +flash_instr_rodata_start_page = 0x400006d4; +flash_instr_rodata_end_page = 0x400006d8; +Cache_Set_IDROM_MMU_Info = 0x400006dc; +Cache_Flash_To_SPIRAM_Copy = 0x400006e0; +/* Data (.data, .bss, .rodata) */ +rom_cache_op_cb = 0x4084ffcc; +rom_cache_internal_table_ptr = 0x4084ffc8; + + +/*************************************** + Group clock + ***************************************/ + +/* Functions */ +ets_clk_get_xtal_freq = 0x400006e4; +ets_clk_get_cpu_freq = 0x400006e8; + + +/*************************************** + Group gpio + ***************************************/ + +/* Functions */ +gpio_set_output_level = 0x400006ec; +gpio_get_input_level = 0x400006f0; +gpio_matrix_in = 0x400006f4; +gpio_matrix_out = 0x400006f8; +gpio_bypass_matrix_in = 0x400006fc; +gpio_output_disable = 0x40000700; +gpio_output_enable = 0x40000704; +gpio_pad_input_disable = 0x40000708; +gpio_pad_input_enable = 0x4000070c; +gpio_pad_pulldown = 0x40000710; +gpio_pad_pullup = 0x40000714; +gpio_pad_select_gpio = 0x40000718; +gpio_pad_set_drv = 0x4000071c; +gpio_pad_unhold = 0x40000720; +gpio_pad_hold = 0x40000724; + + +/*************************************** + Group interrupts + ***************************************/ + +/* Functions */ +esprv_intc_int_set_priority = 0x40000728; +esprv_intc_int_set_threshold = 0x4000072c; +esprv_intc_int_enable = 0x40000730; +esprv_intc_int_disable = 0x40000734; +esprv_intc_int_set_type = 0x40000738; +PROVIDE( intr_handler_set = 0x4000073c ); +intr_matrix_set = 0x40000740; +ets_intr_register_ctx = 0x40000744; +ets_intr_lock = 0x40000748; +ets_intr_unlock = 0x4000074c; +ets_isr_attach = 0x40000750; +ets_isr_mask = 0x40000754; +ets_isr_unmask = 0x40000758; + + +/*************************************** + Group crc + ***************************************/ + +/* Functions */ +crc32_le = 0x4000075c; +crc16_le = 0x40000760; +crc8_le = 0x40000764; +crc32_be = 0x40000768; +crc16_be = 0x4000076c; +crc8_be = 0x40000770; +esp_crc8 = 0x40000774; +/* Data (.data, .bss, .rodata) */ +crc32_le_table_ptr = 0x4003fff8; +crc16_le_table_ptr = 0x4003fff4; +crc8_le_table_ptr = 0x4003fff0; +crc32_be_table_ptr = 0x4003ffec; +crc16_be_table_ptr = 0x4003ffe8; +crc8_be_table_ptr = 0x4003ffe4; + + +/*************************************** + Group md5 + ***************************************/ + +/* Functions */ +md5_vector = 0x40000778; +MD5Init = 0x4000077c; +MD5Update = 0x40000780; +MD5Final = 0x40000784; + + +/*************************************** + Group hwcrypto + ***************************************/ + +/* Functions */ +ets_sha_enable = 0x40000788; +ets_sha_disable = 0x4000078c; +ets_sha_get_state = 0x40000790; +ets_sha_init = 0x40000794; +ets_sha_process = 0x40000798; +ets_sha_starts = 0x4000079c; +ets_sha_update = 0x400007a0; +ets_sha_finish = 0x400007a4; +ets_sha_clone = 0x400007a8; + + +/*************************************** + Group efuse + ***************************************/ + +/* Functions */ +ets_efuse_read = 0x400007ac; +ets_efuse_program = 0x400007b0; +ets_efuse_clear_program_registers = 0x400007b4; +ets_efuse_write_key = 0x400007b8; +ets_efuse_get_read_register_address = 0x400007bc; +ets_efuse_get_key_purpose = 0x400007c0; +ets_efuse_key_block_unused = 0x400007c4; +ets_efuse_find_unused_key_block = 0x400007c8; +ets_efuse_rs_calculate = 0x400007cc; +ets_efuse_count_unused_key_blocks = 0x400007d0; +ets_efuse_secure_boot_enabled = 0x400007d4; +ets_efuse_secure_boot_aggressive_revoke_enabled = 0x400007d8; +ets_efuse_cache_encryption_enabled = 0x400007dc; +ets_efuse_download_modes_disabled = 0x400007e0; +ets_efuse_find_purpose = 0x400007e4; +ets_efuse_force_send_resume = 0x400007e8; +ets_efuse_get_flash_delay_us = 0x400007ec; +ets_efuse_get_uart_print_control = 0x400007f0; +ets_efuse_direct_boot_mode_disabled = 0x400007f4; +ets_efuse_security_download_modes_enabled = 0x400007f8; +ets_efuse_jtag_disabled = 0x400007fc; +ets_efuse_usb_print_is_disabled = 0x40000800; +ets_efuse_usb_download_mode_disabled = 0x40000804; +ets_efuse_usb_device_disabled = 0x40000808; +ets_efuse_secure_boot_fast_wake_enabled = 0x4000080c; + + +/*************************************** + Group secureboot + ***************************************/ + +/* Functions */ +ets_ecdsa_verify = 0x40000810; +ets_secure_boot_verify_bootloader_with_keys = 0x40000814; +ets_secure_boot_verify_signature = 0x40000818; +ets_secure_boot_read_key_digests = 0x4000081c; +ets_secure_boot_revoke_public_key_digest = 0x40000820; + + +/*************************************** + Group usb_device_uart + ***************************************/ + +/* Functions */ +usb_serial_device_rx_one_char = 0x40000a20; +usb_serial_device_rx_one_char_block = 0x40000a24; +usb_serial_device_tx_flush = 0x40000a28; +usb_serial_device_tx_one_char = 0x40000a2c; diff --git a/tools/flasher_stub/ld/rom_32c6_beta.ld b/tools/flasher_stub/ld/rom_32c6_beta.ld new file mode 100755 index 0000000000..ad801af612 --- /dev/null +++ b/tools/flasher_stub/ld/rom_32c6_beta.ld @@ -0,0 +1,1951 @@ +/* ROM function interface esp32c6.rom.ld for esp32c6 + * + * + * Generated from ./interface-esp32c6.yml md5sum e7196719ebc959e6dd2f61dec2db53e0 + * + * Compatible with ROM where ECO version equal or greater to 0. + * + * THIS FILE WAS AUTOMATICALLY GENERATED. DO NOT EDIT. + */ + + +PROVIDE ( SPIWrite = esp_rom_spiflash_write); +PROVIDE ( SPI_read_status_high = esp_rom_spiflash_read_statushigh); +PROVIDE ( SPI_write_status = esp_rom_spiflash_write_status); +PROVIDE ( SPIRead = esp_rom_spiflash_read); +PROVIDE ( SPIParamCfg = esp_rom_spiflash_config_param); +PROVIDE ( SPIEraseChip = esp_rom_spiflash_erase_chip); +PROVIDE ( SPIEraseSector = esp_rom_spiflash_erase_sector); +PROVIDE ( SPIEraseBlock = esp_rom_spiflash_erase_block); +PROVIDE ( SPI_Write_Encrypt_Enable = esp_rom_spiflash_write_encrypted_enable); +PROVIDE ( SPI_Write_Encrypt_Disable = esp_rom_spiflash_write_encrypted_disable); +PROVIDE ( SPI_Encrypt_Write = esp_rom_spiflash_write_encrypted); + + +/*************************************** + Group common + ***************************************/ + +/* Functions */ +rtc_get_reset_reason = 0x40000018; +analog_super_wdt_reset_happened = 0x4000001c; +jtag_cpu_reset_happened = 0x40000020; +rtc_get_wakeup_cause = 0x40000024; +rtc_select_apb_bridge = 0x40000028; +rtc_unhold_all_pads = 0x4000002c; +ets_is_print_boot = 0x40000030; +ets_printf = 0x40000034; +ets_install_putc1 = 0x40000038; +ets_install_uart_printf = 0x4000003c; +ets_install_putc2 = 0x40000040; +PROVIDE( ets_delay_us = 0x40000044 ); +ets_get_stack_info = 0x40000048; +ets_install_lock = 0x4000004c; +ets_backup_dma_copy = 0x40000050; +ets_apb_backup_init_lock_func = 0x40000054; +UartRxString = 0x40000058; +uart_tx_one_char = 0x4000005c; +uart_tx_one_char2 = 0x40000060; +uart_rx_one_char = 0x40000064; +uart_rx_one_char_block = 0x40000068; +uart_rx_readbuff = 0x4000006c; +uartAttach = 0x40000070; +uart_tx_flush = 0x40000074; +uart_tx_wait_idle = 0x40000078; +uart_div_modify = 0x4000007c; +multofup = 0x40000080; +software_reset = 0x40000084; +software_reset_cpu = 0x40000088; +assist_debug_clock_enable = 0x4000008c; +assist_debug_record_enable = 0x40000090; +clear_super_wdt_reset_flag = 0x40000094; +disable_default_watchdog = 0x40000098; +esp_rom_set_rtc_wake_addr = 0x4000009c; +esp_rom_get_rtc_wake_addr = 0x400000a0; +send_packet = 0x400000a4; +recv_packet = 0x400000a8; +GetUartDevice = 0x400000ac; +GetSecurityInfoProc = 0x4004b172; +UartDwnLdProc = 0x400000b0; +Uart_Init = 0x400000b4; +ets_set_user_start = 0x400000b8; +/* Data (.data, .bss, .rodata) */ +ets_rom_layout_p = 0x3ff1fffc; +ets_ops_table_ptr = 0x3fcdfffc; + + +/*************************************** + Group miniz + ***************************************/ + +/* Functions */ +mz_adler32 = 0x400000bc; +mz_crc32 = 0x400000c0; +mz_free = 0x400000c4; +tdefl_compress = 0x400000c8; +tdefl_compress_buffer = 0x400000cc; +tdefl_compress_mem_to_heap = 0x400000d0; +tdefl_compress_mem_to_mem = 0x400000d4; +tdefl_compress_mem_to_output = 0x400000d8; +tdefl_get_adler32 = 0x400000dc; +tdefl_get_prev_return_status = 0x400000e0; +tdefl_init = 0x400000e4; +tdefl_write_image_to_png_file_in_memory = 0x400000e8; +tdefl_write_image_to_png_file_in_memory_ex = 0x400000ec; +tinfl_decompress = 0x400000f0; +tinfl_decompress_mem_to_callback = 0x400000f4; +tinfl_decompress_mem_to_heap = 0x400000f8; +tinfl_decompress_mem_to_mem = 0x400000fc; + + +/*************************************** + Group tjpgd + ***************************************/ + +/* Functions */ +jd_prepare = 0x40000100; +jd_decomp = 0x40000104; + + +/*************************************** + Group spiflash_legacy + ***************************************/ + +/* Functions */ +PROVIDE( esp_rom_spiflash_wait_idle = 0x40000108 ); +PROVIDE( esp_rom_spiflash_write_encrypted = 0x4000010c ); +PROVIDE( esp_rom_spiflash_write_encrypted_dest = 0x40000110 ); +PROVIDE( esp_rom_spiflash_write_encrypted_enable = 0x40000114 ); +PROVIDE( esp_rom_spiflash_write_encrypted_disable = 0x40000118 ); +PROVIDE( esp_rom_spiflash_erase_chip = 0x4000011c ); +PROVIDE( esp_rom_spiflash_erase_block = 0x40000120 ); +PROVIDE( esp_rom_spiflash_erase_sector = 0x40000124 ); +PROVIDE( esp_rom_spiflash_write = 0x40000128 ); +PROVIDE( esp_rom_spiflash_read = 0x4000012c ); +PROVIDE( esp_rom_spiflash_config_param = 0x40000130 ); +PROVIDE( esp_rom_spiflash_read_user_cmd = 0x40000134 ); +PROVIDE( esp_rom_spiflash_select_qio_pins = 0x40000138 ); +PROVIDE( esp_rom_spiflash_unlock = 0x4000013c ); +PROVIDE( esp_rom_spi_flash_auto_sus_res = 0x40000140 ); +PROVIDE( esp_rom_spi_flash_send_resume = 0x40000144 ); +PROVIDE( esp_rom_spi_flash_update_id = 0x40000148 ); +PROVIDE( esp_rom_spiflash_config_clk = 0x4000014c ); +PROVIDE( esp_rom_spiflash_config_readmode = 0x40000150 ); +PROVIDE( esp_rom_spiflash_read_status = 0x40000154 ); +PROVIDE( esp_rom_spiflash_read_statushigh = 0x40000158 ); +PROVIDE( esp_rom_spiflash_write_status = 0x4000015c ); +PROVIDE( spi_flash_attach = 0x40000160 ); +PROVIDE( spi_flash_get_chip_size = 0x40000164 ); +PROVIDE( spi_flash_guard_set = 0x40000168 ); +PROVIDE( spi_flash_guard_get = 0x4000016c ); +PROVIDE( spi_flash_write_config_set = 0x40000170 ); +PROVIDE( spi_flash_write_config_get = 0x40000174 ); +PROVIDE( spi_flash_safe_write_address_func_set = 0x40000178 ); +PROVIDE( spi_flash_unlock = 0x4000017c ); +PROVIDE( spi_flash_erase_range = 0x40000180 ); +PROVIDE( spi_flash_erase_sector = 0x40000184 ); +PROVIDE( spi_flash_write = 0x40000188 ); +PROVIDE( spi_flash_read = 0x4000018c ); +PROVIDE( spi_flash_write_encrypted = 0x40000190 ); +PROVIDE( spi_flash_read_encrypted = 0x40000194 ); +PROVIDE( spi_flash_mmap_os_func_set = 0x40000198 ); +PROVIDE( spi_flash_mmap_page_num_init = 0x4000019c ); +PROVIDE( spi_flash_mmap = 0x400001a0 ); +PROVIDE( spi_flash_mmap_pages = 0x400001a4 ); +PROVIDE( spi_flash_munmap = 0x400001a8 ); +PROVIDE( spi_flash_mmap_dump = 0x400001ac ); +PROVIDE( spi_flash_check_and_flush_cache = 0x400001b0 ); +PROVIDE( spi_flash_mmap_get_free_pages = 0x400001b4 ); +PROVIDE( spi_flash_cache2phys = 0x400001b8 ); +PROVIDE( spi_flash_phys2cache = 0x400001bc ); +PROVIDE( spi_flash_disable_cache = 0x400001c0 ); +PROVIDE( spi_flash_restore_cache = 0x400001c4 ); +PROVIDE( spi_flash_cache_enabled = 0x400001c8 ); +PROVIDE( spi_flash_enable_cache = 0x400001cc ); +PROVIDE( spi_cache_mode_switch = 0x400001d0 ); +PROVIDE( spi_common_set_dummy_output = 0x400001d4 ); +PROVIDE( spi_common_set_flash_cs_timing = 0x400001d8 ); +PROVIDE( esp_enable_cache_flash_wrap = 0x400001dc ); +PROVIDE( SPIEraseArea = 0x400001e0 ); +PROVIDE( SPILock = 0x400001e4 ); +PROVIDE( SPIMasterReadModeCnfig = 0x400001e8 ); +PROVIDE( SPI_Common_Command = 0x400001ec ); +PROVIDE( SPI_WakeUp = 0x400001f0 ); +PROVIDE( SPI_block_erase = 0x400001f4 ); +PROVIDE( SPI_chip_erase = 0x400001f8 ); +PROVIDE( SPI_init = 0x400001fc ); +PROVIDE( SPI_page_program = 0x40000200 ); +PROVIDE( SPI_read_data = 0x40000204 ); +PROVIDE( SPI_sector_erase = 0x40000208 ); +PROVIDE( SPI_write_enable = 0x4000020c ); +PROVIDE( SelectSpiFunction = 0x40000210 ); +PROVIDE( SetSpiDrvs = 0x40000214 ); +PROVIDE( Wait_SPI_Idle = 0x40000218 ); +PROVIDE( spi_dummy_len_fix = 0x4000021c ); +PROVIDE( Disable_QMode = 0x40000220 ); +PROVIDE( Enable_QMode = 0x40000224 ); +/* Data (.data, .bss, .rodata) */ +PROVIDE( rom_spiflash_legacy_funcs = 0x3fcdfff4 ); +PROVIDE( rom_spiflash_legacy_data = 0x3fcdfff0 ); +PROVIDE( g_flash_guard_ops = 0x3fcdfff8 ); + + +/*************************************** + Group spi_flash_hal + ***************************************/ + +/* Functions */ +PROVIDE( spi_flash_hal_poll_cmd_done = 0x40000228 ); +PROVIDE( spi_flash_hal_device_config = 0x4000022c ); +PROVIDE( spi_flash_hal_configure_host_io_mode = 0x40000230 ); +PROVIDE( spi_flash_hal_common_command = 0x40000234 ); +PROVIDE( spi_flash_hal_read = 0x40000238 ); +PROVIDE( spi_flash_hal_erase_chip = 0x4000023c ); +PROVIDE( spi_flash_hal_erase_sector = 0x40000240 ); +PROVIDE( spi_flash_hal_erase_block = 0x40000244 ); +PROVIDE( spi_flash_hal_program_page = 0x40000248 ); +PROVIDE( spi_flash_hal_set_write_protect = 0x4000024c ); +PROVIDE( spi_flash_hal_host_idle = 0x40000250 ); + + +/*************************************** + Group spi_flash_chips + ***************************************/ + +/* Functions */ +PROVIDE( spi_flash_chip_generic_probe = 0x40000254 ); +PROVIDE( spi_flash_chip_generic_detect_size = 0x40000258 ); +PROVIDE( spi_flash_chip_generic_write = 0x4000025c ); +PROVIDE( spi_flash_chip_generic_write_encrypted = 0x40000260 ); +PROVIDE( spi_flash_chip_generic_set_write_protect = 0x40000264 ); +PROVIDE( spi_flash_common_write_status_16b_wrsr = 0x40000268 ); +PROVIDE( spi_flash_chip_generic_reset = 0x4000026c ); +PROVIDE( spi_flash_chip_generic_erase_chip = 0x40000270 ); +PROVIDE( spi_flash_chip_generic_erase_sector = 0x40000274 ); +PROVIDE( spi_flash_chip_generic_erase_block = 0x40000278 ); +PROVIDE( spi_flash_chip_generic_page_program = 0x4000027c ); +PROVIDE( spi_flash_chip_generic_get_write_protect = 0x40000280 ); +PROVIDE( spi_flash_common_read_status_16b_rdsr_rdsr2 = 0x40000284 ); +PROVIDE( spi_flash_chip_generic_read_reg = 0x40000288 ); +PROVIDE( spi_flash_chip_generic_yield = 0x4000028c ); +PROVIDE( spi_flash_generic_wait_host_idle = 0x40000290 ); +PROVIDE( spi_flash_chip_generic_wait_idle = 0x40000294 ); +PROVIDE( spi_flash_chip_generic_config_host_io_mode = 0x40000298 ); +PROVIDE( spi_flash_chip_generic_read = 0x4000029c ); +PROVIDE( spi_flash_common_read_status_8b_rdsr2 = 0x400002a0 ); +PROVIDE( spi_flash_chip_generic_get_io_mode = 0x400002a4 ); +PROVIDE( spi_flash_common_read_status_8b_rdsr = 0x400002a8 ); +PROVIDE( spi_flash_common_write_status_8b_wrsr = 0x400002ac ); +PROVIDE( spi_flash_common_write_status_8b_wrsr2 = 0x400002b0 ); +PROVIDE( spi_flash_common_set_io_mode = 0x400002b4 ); +PROVIDE( spi_flash_chip_generic_set_io_mode = 0x400002b8 ); +PROVIDE( spi_flash_chip_gd_get_io_mode = 0x400002bc ); +PROVIDE( spi_flash_chip_gd_probe = 0x400002c0 ); +PROVIDE( spi_flash_chip_gd_set_io_mode = 0x400002c4 ); +/* Data (.data, .bss, .rodata) */ +PROVIDE( spi_flash_chip_generic_config_data = 0x3fcdffec ); + + +/*************************************** + Group memspi_host + ***************************************/ + +/* Functions */ +PROVIDE( memspi_host_read_id_hs = 0x400002c8 ); +PROVIDE( memspi_host_read_status_hs = 0x400002cc ); +PROVIDE( memspi_host_flush_cache = 0x400002d0 ); +PROVIDE( memspi_host_erase_chip = 0x400002d4 ); +PROVIDE( memspi_host_erase_sector = 0x400002d8 ); +PROVIDE( memspi_host_erase_block = 0x400002dc ); +PROVIDE( memspi_host_program_page = 0x400002e0 ); +PROVIDE( memspi_host_read = 0x400002e4 ); +PROVIDE( memspi_host_set_write_protect = 0x400002e8 ); +PROVIDE( memspi_host_set_max_read_len = 0x400002ec ); +PROVIDE( memspi_host_read_data_slicer = 0x400002f0 ); +PROVIDE( memspi_host_write_data_slicer = 0x400002f4 ); + + +/*************************************** + Group esp_flash + ***************************************/ + +/* Functions */ +PROVIDE( esp_flash_chip_driver_initialized = 0x400002f8 ); +PROVIDE( esp_flash_read_id = 0x400002fc ); +PROVIDE( esp_flash_get_size = 0x40000300 ); +PROVIDE( esp_flash_erase_chip = 0x40000304 ); +PROVIDE( esp_flash_erase_region = 0x40000308 ); +PROVIDE( esp_flash_get_chip_write_protect = 0x4000030c ); +PROVIDE( esp_flash_set_chip_write_protect = 0x40000310 ); +PROVIDE( esp_flash_get_protectable_regions = 0x40000314 ); +PROVIDE( esp_flash_get_protected_region = 0x40000318 ); +PROVIDE( esp_flash_set_protected_region = 0x4000031c ); +PROVIDE( esp_flash_read = 0x40000320 ); +PROVIDE( esp_flash_write = 0x40000324 ); +PROVIDE( esp_flash_write_encrypted = 0x40000328 ); +PROVIDE( esp_flash_read_encrypted = 0x4000032c ); +PROVIDE( esp_flash_get_io_mode = 0x40000330 ); +PROVIDE( esp_flash_set_io_mode = 0x40000334 ); +PROVIDE( spi_flash_boot_attach = 0x40000338 ); +PROVIDE( spi_flash_dump_counters = 0x4000033c ); +PROVIDE( spi_flash_get_counters = 0x40000340 ); +PROVIDE( spi_flash_op_counters_config = 0x40000344 ); +PROVIDE( spi_flash_reset_counters = 0x40000348 ); +/* Data (.data, .bss, .rodata) */ +PROVIDE( esp_flash_default_chip = 0x3fcdffe8 ); +PROVIDE( esp_flash_api_funcs = 0x3fcdffe4 ); + + +/*************************************** + Group cache + ***************************************/ + +/* Functions */ +PROVIDE( Cache_Get_ICache_Line_Size = 0x400004ac ); +PROVIDE( Cache_Get_Mode = 0x400004b0 ); +PROVIDE( Cache_Address_Through_IBus = 0x400004b4 ); +PROVIDE( Cache_Address_Through_DBus = 0x400004b8 ); +PROVIDE( Cache_Set_Default_Mode = 0x400004bc ); +PROVIDE( Cache_Enable_Defalut_ICache_Mode = 0x400004c0 ); +PROVIDE( ROM_Boot_Cache_Init = 0x400004c4 ); +PROVIDE( Cache_Invalidate_ICache_Items = 0x400004c8 ); +PROVIDE( Cache_Op_Addr = 0x400004cc ); +PROVIDE( Cache_Invalidate_Addr = 0x400004d0 ); +PROVIDE( Cache_Invalidate_ICache_All = 0x400004d4 ); +PROVIDE( Cache_Mask_All = 0x400004d8 ); +PROVIDE( Cache_UnMask_Dram0 = 0x400004dc ); +PROVIDE( Cache_Suspend_ICache_Autoload = 0x400004e0 ); +PROVIDE( Cache_Resume_ICache_Autoload = 0x400004e4 ); +PROVIDE( Cache_Start_ICache_Preload = 0x400004e8 ); +PROVIDE( Cache_ICache_Preload_Done = 0x400004ec ); +PROVIDE( Cache_End_ICache_Preload = 0x400004f0 ); +PROVIDE( Cache_Config_ICache_Autoload = 0x400004f4 ); +PROVIDE( Cache_Enable_ICache_Autoload = 0x400004f8 ); +PROVIDE( Cache_Disable_ICache_Autoload = 0x400004fc ); +PROVIDE( Cache_Enable_ICache_PreLock = 0x40000500 ); +PROVIDE( Cache_Disable_ICache_PreLock = 0x40000504 ); +PROVIDE( Cache_Lock_ICache_Items = 0x40000508 ); +PROVIDE( Cache_Unlock_ICache_Items = 0x4000050c ); +PROVIDE( Cache_Lock_Addr = 0x40000510 ); +PROVIDE( Cache_Unlock_Addr = 0x40000514 ); +PROVIDE( Cache_Disable_ICache = 0x40000518 ); +PROVIDE( Cache_Enable_ICache = 0x4000051c ); +PROVIDE( Cache_Suspend_ICache = 0x40000520 ); +PROVIDE( Cache_Resume_ICache = 0x40000524 ); +PROVIDE( Cache_Freeze_ICache_Enable = 0x40000528 ); +PROVIDE( Cache_Freeze_ICache_Disable = 0x4000052c ); +PROVIDE( Cache_Pms_Lock = 0x40000530 ); +PROVIDE( Cache_Ibus_Pms_Set_Addr = 0x40000534 ); +PROVIDE( Cache_Ibus_Pms_Set_Attr = 0x40000538 ); +PROVIDE( Cache_Dbus_Pms_Set_Addr = 0x4000053c ); +PROVIDE( Cache_Dbus_Pms_Set_Attr = 0x40000540 ); +PROVIDE( Cache_Set_IDROM_MMU_Size = 0x40000544 ); +PROVIDE( Cache_Get_IROM_MMU_End = 0x40000548 ); +PROVIDE( Cache_Get_DROM_MMU_End = 0x4000054c ); +PROVIDE( Cache_Owner_Init = 0x40000550 ); +PROVIDE( Cache_Occupy_ICache_MEMORY = 0x40000554 ); +PROVIDE( Cache_MMU_Init = 0x40000558 ); +PROVIDE( Cache_Ibus_MMU_Set = 0x4000055c ); +PROVIDE( Cache_Dbus_MMU_Set = 0x40000560 ); +PROVIDE( Cache_Count_Flash_Pages = 0x40000564 ); +PROVIDE( Cache_Travel_Tag_Memory = 0x40000568 ); +PROVIDE( Cache_Get_Virtual_Addr = 0x4000056c ); +PROVIDE( Cache_Get_Memory_BaseAddr = 0x40000570 ); +PROVIDE( Cache_Get_Memory_Addr = 0x40000574 ); +PROVIDE( Cache_Get_Memory_value = 0x40000578 ); +/* Data (.data, .bss, .rodata) */ +PROVIDE( rom_cache_op_cb = 0x3fcdffd8 ); +PROVIDE( rom_cache_internal_table_ptr = 0x3fcdffd4 ); + + +/*************************************** + Group clock + ***************************************/ + +/* Functions */ +ets_get_apb_freq = 0x4000057c; +ets_get_cpu_frequency = 0x40000580; +ets_update_cpu_frequency = 0x40000584; +ets_get_printf_channel = 0x40000588; +ets_get_xtal_div = 0x4000058c; +ets_set_xtal_div = 0x40000590; +ets_get_xtal_freq = 0x40000594; + + +/*************************************** + Group gpio + ***************************************/ + +/* Functions */ +gpio_input_get = 0x40000598; +gpio_matrix_in = 0x4000059c; +gpio_matrix_out = 0x400005a0; +gpio_output_disable = 0x400005a4; +gpio_output_enable = 0x400005a8; +gpio_output_set = 0x400005ac; +gpio_pad_hold = 0x400005b0; +gpio_pad_input_disable = 0x400005b4; +gpio_pad_input_enable = 0x400005b8; +gpio_pad_pulldown = 0x400005bc; +gpio_pad_pullup = 0x400005c0; +gpio_pad_select_gpio = 0x400005c4; +gpio_pad_set_drv = 0x400005c8; +gpio_pad_unhold = 0x400005cc; +gpio_pin_wakeup_disable = 0x400005d0; +gpio_pin_wakeup_enable = 0x400005d4; +gpio_bypass_matrix_in = 0x400005d8; + + +/*************************************** + Group interrupts + ***************************************/ + +/* Functions */ +esprv_intc_int_set_priority = 0x400005dc; +esprv_intc_int_set_threshold = 0x400005e0; +esprv_intc_int_enable = 0x400005e4; +esprv_intc_int_disable = 0x400005e8; +esprv_intc_int_set_type = 0x400005ec; +intr_matrix_set = 0x400005f0; +ets_intr_lock = 0x400005f4; +ets_intr_unlock = 0x400005f8; +PROVIDE( intr_handler_set = 0x400005fc ); +ets_isr_attach = 0x40000600; +ets_isr_mask = 0x40000604; +ets_isr_unmask = 0x40000608; + + +/*************************************** + Group crypto + ***************************************/ + +/* Functions */ +md5_vector = 0x4000060c; +MD5Init = 0x40000610; +MD5Update = 0x40000614; +MD5Final = 0x40000618; +hmac_md5_vector = 0x4000061c; +hmac_md5 = 0x40000620; +crc32_le = 0x40000624; +crc32_be = 0x40000628; +crc16_le = 0x4000062c; +crc16_be = 0x40000630; +crc8_le = 0x40000634; +crc8_be = 0x40000638; +esp_crc8 = 0x4000063c; +ets_sha_enable = 0x40000640; +ets_sha_disable = 0x40000644; +ets_sha_get_state = 0x40000648; +ets_sha_init = 0x4000064c; +ets_sha_process = 0x40000650; +ets_sha_starts = 0x40000654; +ets_sha_update = 0x40000658; +ets_sha_finish = 0x4000065c; +ets_sha_clone = 0x40000660; +ets_hmac_enable = 0x40000664; +ets_hmac_disable = 0x40000668; +ets_hmac_calculate_message = 0x4000066c; +ets_hmac_calculate_downstream = 0x40000670; +ets_hmac_invalidate_downstream = 0x40000674; +ets_jtag_enable_temporarily = 0x40000678; +ets_aes_enable = 0x4000067c; +ets_aes_disable = 0x40000680; +ets_aes_setkey = 0x40000684; +ets_aes_block = 0x40000688; +ets_bigint_enable = 0x4000068c; +ets_bigint_disable = 0x40000690; +ets_bigint_multiply = 0x40000694; +ets_bigint_modmult = 0x40000698; +ets_bigint_modexp = 0x4000069c; +ets_bigint_wait_finish = 0x400006a0; +ets_bigint_getz = 0x400006a4; +ets_ds_enable = 0x400006a8; +ets_ds_disable = 0x400006ac; +ets_ds_start_sign = 0x400006b0; +ets_ds_is_busy = 0x400006b4; +ets_ds_finish_sign = 0x400006b8; +ets_ds_encrypt_params = 0x400006bc; +ets_aes_setkey_dec = 0x400006c0; +ets_aes_setkey_enc = 0x400006c4; +ets_mgf1_sha256 = 0x400006c8; + + +/*************************************** + Group efuse + ***************************************/ + +/* Functions */ +ets_efuse_read = 0x400006cc; +ets_efuse_program = 0x400006d0; +ets_efuse_clear_program_registers = 0x400006d4; +ets_efuse_write_key = 0x400006d8; +ets_efuse_get_read_register_address = 0x400006dc; +ets_efuse_get_key_purpose = 0x400006e0; +ets_efuse_key_block_unused = 0x400006e4; +ets_efuse_find_unused_key_block = 0x400006e8; +ets_efuse_rs_calculate = 0x400006ec; +ets_efuse_count_unused_key_blocks = 0x400006f0; +ets_efuse_secure_boot_enabled = 0x400006f4; +ets_efuse_secure_boot_aggressive_revoke_enabled = 0x400006f8; +ets_efuse_cache_encryption_enabled = 0x400006fc; +ets_efuse_download_modes_disabled = 0x40000700; +ets_efuse_find_purpose = 0x40000704; +ets_efuse_flash_opi_5pads_power_sel_vddspi = 0x40000708; +ets_efuse_force_send_resume = 0x4000070c; +ets_efuse_get_flash_delay_us = 0x40000710; +ets_efuse_get_mac = 0x40000714; +ets_efuse_get_spiconfig = 0x40000718; +ets_efuse_usb_print_is_disabled = 0x4000071c; +ets_efuse_get_uart_print_channel = 0x40000720; +ets_efuse_get_uart_print_control = 0x40000724; +ets_efuse_get_wp_pad = 0x40000728; +ets_efuse_legacy_spi_boot_mode_disabled = 0x4000072c; +ets_efuse_security_download_modes_enabled = 0x40000730; +ets_efuse_set_timing = 0x40000734; +ets_efuse_jtag_disabled = 0x40000738; +ets_efuse_usb_download_mode_disabled = 0x4000073c; +ets_efuse_usb_module_disabled = 0x40000740; +ets_efuse_usb_device_disabled = 0x40000744; + + +/*************************************** + Group secureboot + ***************************************/ + +/* Functions */ +ets_emsa_pss_verify = 0x40000748; +ets_rsa_pss_verify = 0x4000074c; +ets_secure_boot_verify_bootloader_with_keys = 0x40000750; +ets_secure_boot_verify_signature = 0x40000754; +ets_secure_boot_read_key_digests = 0x40000758; +ets_secure_boot_revoke_public_key_digest = 0x4000075c; + + +/*************************************** + Group usb_uart + ***************************************/ + +/* Functions */ +PROVIDE( usb_uart_rx_one_char = 0x400008c8 ); +PROVIDE( usb_uart_rx_one_char_block = 0x400008cc ); +PROVIDE( usb_uart_tx_flush = 0x400008d0 ); +PROVIDE( usb_uart_tx_one_char = 0x400008d4 ); +/* Data (.data, .bss, .rodata) */ +PROVIDE( g_uart_print = 0x3fcdffd1 ); +PROVIDE( g_usb_print = 0x3fcdffd0 ); + + +/*************************************** + Group bluetooth + ***************************************/ + +/* Functions */ +bt_rf_coex_get_dft_cfg = 0x400008d8; +bt_rf_coex_hooks_p_set = 0x400008dc; +btdm_con_maxevtime_cal_impl = 0x400008e0; +btdm_controller_get_compile_version_impl = 0x400008e4; +btdm_controller_rom_data_init = 0x400008e8; +btdm_dis_privacy_err_report_impl = 0x400008ec; +btdm_disable_adv_delay_impl = 0x400008f0; +btdm_enable_scan_continue_impl = 0x400008f4; +btdm_enable_scan_forever_impl = 0x400008f8; +btdm_get_power_state_impl = 0x400008fc; +btdm_get_prevent_sleep_flag_impl = 0x40000900; +btdm_power_state_active_impl = 0x40000904; +btdm_switch_phy_coded_impl = 0x40000908; +hci_acl_data_handler = 0x4000090c; +hci_disconnect_cmd_handler = 0x40000910; +hci_le_con_upd_cmd_handler = 0x40000914; +hci_le_ltk_req_neg_reply_cmd_handler = 0x40000918; +hci_le_ltk_req_reply_cmd_handler = 0x4000091c; +hci_le_rd_chnl_map_cmd_handler = 0x40000920; +hci_le_rd_phy_cmd_handler = 0x40000924; +hci_le_rd_rem_feats_cmd_handler = 0x40000928; +hci_le_rem_con_param_req_neg_reply_cmd_handler = 0x4000092c; +hci_le_rem_con_param_req_reply_cmd_handler = 0x40000930; +hci_le_set_data_len_cmd_handler = 0x40000934; +hci_le_set_phy_cmd_handler = 0x40000938; +hci_le_start_enc_cmd_handler = 0x4000093c; +hci_rd_auth_payl_to_cmd_handler = 0x40000940; +hci_rd_rem_ver_info_cmd_handler = 0x40000944; +hci_rd_rssi_cmd_handler = 0x40000948; +hci_rd_tx_pwr_lvl_cmd_handler = 0x4000094c; +hci_vs_set_pref_slave_evt_dur_cmd_handler = 0x40000950; +hci_vs_set_pref_slave_latency_cmd_handler = 0x40000954; +hci_wr_auth_payl_to_cmd_handler = 0x40000958; +ll_channel_map_ind_handler = 0x4000095c; +ll_connection_param_req_handler = 0x40000960; +ll_connection_param_rsp_handler = 0x40000964; +ll_connection_update_ind_handler = 0x40000968; +ll_enc_req_handler = 0x4000096c; +ll_enc_rsp_handler = 0x40000970; +ll_feature_req_handler = 0x40000974; +ll_feature_rsp_handler = 0x40000978; +ll_length_req_handler = 0x4000097c; +ll_length_rsp_handler = 0x40000980; +ll_min_used_channels_ind_handler = 0x40000984; +ll_pause_enc_req_handler = 0x40000988; +ll_pause_enc_rsp_handler = 0x4000098c; +ll_phy_req_handler = 0x40000990; +ll_phy_rsp_handler = 0x40000994; +ll_phy_update_ind_handler = 0x40000998; +ll_ping_req_handler = 0x4000099c; +ll_ping_rsp_handler = 0x400009a0; +ll_slave_feature_req_handler = 0x400009a4; +ll_start_enc_req_handler = 0x400009a8; +ll_start_enc_rsp_handler = 0x400009ac; +ll_terminate_ind_handler = 0x400009b0; +ll_version_ind_handler = 0x400009b4; +llc_auth_payl_nearly_to_handler = 0x400009b8; +llc_auth_payl_real_to_handler = 0x400009bc; +llc_encrypt_ind_handler = 0x400009c0; +llc_hci_command_handler_wrapper = 0x400009c4; +llc_ll_connection_param_req_pdu_send = 0x400009c8; +llc_ll_connection_param_rsp_pdu_send = 0x400009cc; +llc_ll_connection_update_ind_pdu_send = 0x400009d0; +llc_ll_enc_req_pdu_send = 0x400009d4; +llc_ll_enc_rsp_pdu_send = 0x400009d8; +llc_ll_feature_req_pdu_send = 0x400009dc; +llc_ll_feature_rsp_pdu_send = 0x400009e0; +llc_ll_length_req_pdu_send = 0x400009e4; +llc_ll_length_rsp_pdu_send = 0x400009e8; +llc_ll_pause_enc_req_pdu_send = 0x400009ec; +llc_ll_pause_enc_rsp_pdu_send = 0x400009f0; +llc_ll_phy_req_pdu_send = 0x400009f4; +llc_ll_phy_rsp_pdu_send = 0x400009f8; +llc_ll_ping_req_pdu_send = 0x400009fc; +llc_ll_ping_rsp_pdu_send = 0x40000a00; +llc_ll_start_enc_req_pdu_send = 0x40000a04; +llc_ll_start_enc_rsp_pdu_send = 0x40000a08; +llc_ll_terminate_ind_pdu_send = 0x40000a0c; +llc_ll_unknown_rsp_pdu_send = 0x40000a10; +llc_llcp_ch_map_update_ind_pdu_send = 0x40000a14; +llc_llcp_phy_upd_ind_pdu_send = 0x40000a18; +llc_llcp_version_ind_pdu_send = 0x40000a1c; +llc_op_ch_map_upd_ind_handler = 0x40000a20; +llc_op_con_upd_ind_handler = 0x40000a24; +llc_op_disconnect_ind_handler = 0x40000a28; +llc_op_dl_upd_ind_handler = 0x40000a2c; +llc_op_encrypt_ind_handler = 0x40000a30; +llc_op_feats_exch_ind_handler = 0x40000a34; +llc_op_le_ping_ind_handler = 0x40000a38; +llc_op_phy_upd_ind_handler = 0x40000a3c; +llc_op_ver_exch_ind_handler = 0x40000a40; +llc_stopped_ind_handler = 0x40000a44; +lld_acl_rx_ind_handler = 0x40000a48; +lld_acl_tx_cfm_handler = 0x40000a4c; +lld_adv_end_ind_handler = 0x40000a50; +lld_adv_rep_ind_handler = 0x40000a54; +lld_ch_map_upd_cfm_handler = 0x40000a58; +lld_con_estab_ind_handler = 0x40000a5c; +lld_con_evt_sd_evt_time_set = 0x40000a60; +lld_con_offset_upd_ind_handler = 0x40000a64; +lld_con_param_upd_cfm_handler = 0x40000a68; +lld_disc_ind_handler = 0x40000a6c; +lld_init_end_ind_handler = 0x40000a70; +lld_llcp_rx_ind_handler_wrapper = 0x40000a74; +lld_llcp_tx_cfm_handler = 0x40000a78; +lld_per_adv_end_ind_handler = 0x40000a7c; +lld_per_adv_rep_ind_handler = 0x40000a80; +lld_per_adv_rx_end_ind_handler = 0x40000a84; +lld_phy_coded_500k_get = 0x40000a88; +lld_phy_upd_cfm_handler = 0x40000a8c; +lld_scan_end_ind_handler = 0x40000a90; +lld_scan_req_ind_handler = 0x40000a94; +lld_sync_start_req_handler = 0x40000a98; +lld_test_end_ind_handler = 0x40000a9c; +lld_update_rxbuf_handler = 0x40000aa0; +llm_ch_map_update_ind_handler = 0x40000aa4; +llm_hci_command_handler_wrapper = 0x40000aa8; +llm_scan_period_to_handler = 0x40000aac; +r_Add2SelfBigHex256 = 0x40000ab0; +r_AddBigHex256 = 0x40000ab4; +r_AddBigHexModP256 = 0x40000ab8; +r_AddP256 = 0x40000abc; +r_AddPdiv2_256 = 0x40000ac0; +r_GF_Jacobian_Point_Addition256 = 0x40000ac4; +r_GF_Jacobian_Point_Double256 = 0x40000ac8; +r_GF_Point_Jacobian_To_Affine256 = 0x40000acc; +r_MultiplyBigHexByUint32_256 = 0x40000ad0; +r_MultiplyBigHexModP256 = 0x40000ad4; +r_MultiplyByU16ModP256 = 0x40000ad8; +r_SubtractBigHex256 = 0x40000adc; +r_SubtractBigHexMod256 = 0x40000ae0; +r_SubtractBigHexUint32_256 = 0x40000ae4; +r_SubtractFromSelfBigHex256 = 0x40000ae8; +r_SubtractFromSelfBigHexSign256 = 0x40000aec; +r_aes_alloc = 0x40000af0; +r_aes_ccm_continue = 0x40000af4; +r_aes_ccm_process_e = 0x40000af8; +r_aes_ccm_xor_128_lsb = 0x40000afc; +r_aes_ccm_xor_128_msb = 0x40000b00; +r_aes_cmac_continue = 0x40000b04; +r_aes_cmac_start = 0x40000b08; +r_aes_k1_continue = 0x40000b0c; +r_aes_k2_continue = 0x40000b10; +r_aes_k3_continue = 0x40000b14; +r_aes_k4_continue = 0x40000b18; +r_aes_shift_left_128 = 0x40000b1c; +r_aes_start = 0x40000b20; +r_aes_xor_128 = 0x40000b24; +r_assert_err = 0x40000b28; +r_assert_param = 0x40000b2c; +r_assert_warn = 0x40000b30; +r_bigHexInversion256 = 0x40000b34; +r_ble_sw_cca_check_isr = 0x40000b38; +r_ble_util_buf_acl_tx_alloc = 0x40000b3c; +r_ble_util_buf_acl_tx_elt_get = 0x40000b40; +r_ble_util_buf_acl_tx_free = 0x40000b44; +r_ble_util_buf_acl_tx_free_in_isr = 0x40000b48; +r_ble_util_buf_adv_tx_alloc = 0x40000b4c; +r_ble_util_buf_adv_tx_free = 0x40000b50; +r_ble_util_buf_adv_tx_free_in_isr = 0x40000b54; +r_ble_util_buf_env_deinit = 0x40000b58; +r_ble_util_buf_env_init = 0x40000b5c; +r_ble_util_buf_get_rx_buf_nb = 0x40000b60; +r_ble_util_buf_get_rx_buf_size = 0x40000b64; +r_ble_util_buf_llcp_tx_alloc = 0x40000b68; +r_ble_util_buf_llcp_tx_free = 0x40000b6c; +r_ble_util_buf_rx_alloc = 0x40000b70; +r_ble_util_buf_rx_alloc_in_isr = 0x40000b74; +r_ble_util_buf_rx_free = 0x40000b78; +r_ble_util_buf_rx_free_in_isr = 0x40000b7c; +r_ble_util_buf_set_rx_buf_nb = 0x40000b80; +r_ble_util_buf_set_rx_buf_size = 0x40000b84; +r_ble_util_data_rx_buf_reset = 0x40000b88; +r_bt_bb_get_intr_mask = 0x40000b8c; +r_bt_bb_intr_clear = 0x40000b90; +r_bt_bb_intr_mask_set = 0x40000b94; +r_bt_bb_isr = 0x40000b98; +r_bt_rf_coex_cfg_set = 0x40000b9c; +r_bt_rf_coex_conn_dynamic_pti_en_get = 0x40000ba0; +r_bt_rf_coex_conn_phy_coded_data_time_limit_en_get = 0x40000ba4; +r_bt_rf_coex_ext_adv_dynamic_pti_en_get = 0x40000ba8; +r_bt_rf_coex_ext_scan_dynamic_pti_en_get = 0x40000bac; +r_bt_rf_coex_legacy_adv_dynamic_pti_en_get = 0x40000bb0; +r_bt_rf_coex_per_adv_dynamic_pti_en_get = 0x40000bb4; +r_bt_rf_coex_pti_table_get = 0x40000bb8; +r_bt_rf_coex_st_param_get = 0x40000bbc; +r_bt_rf_coex_st_param_set = 0x40000bc0; +r_bt_rf_coex_sync_scan_dynamic_pti_en_get = 0x40000bc4; +r_bt_rma_apply_rule_cs_fmt = 0x40000bc8; +r_bt_rma_apply_rule_cs_idx = 0x40000bcc; +r_bt_rma_configure = 0x40000bd0; +r_bt_rma_deregister_rule_cs_fmt = 0x40000bd4; +r_bt_rma_deregister_rule_cs_idx = 0x40000bd8; +r_bt_rma_get_ant_by_act = 0x40000bdc; +r_bt_rma_init = 0x40000be0; +r_bt_rma_register_rule_cs_fmt = 0x40000be4; +r_bt_rma_register_rule_cs_idx = 0x40000be8; +r_bt_rtp_apply_rule_cs_fmt = 0x40000bec; +r_bt_rtp_apply_rule_cs_idx = 0x40000bf0; +r_bt_rtp_deregister_rule_cs_fmt = 0x40000bf4; +r_bt_rtp_deregister_rule_cs_idx = 0x40000bf8; +r_bt_rtp_get_txpwr_idx_by_act = 0x40000bfc; +r_bt_rtp_init = 0x40000c00; +r_bt_rtp_register_rule_cs_fmt = 0x40000c04; +r_bt_rtp_register_rule_cs_idx = 0x40000c08; +r_btdm_isr = 0x40000c0c; +r_btdm_task_post = 0x40000c10; +r_btdm_task_post_from_isr = 0x40000c14; +r_btdm_task_recycle = 0x40000c18; +r_cali_phase_match_p = 0x40000c1c; +r_cmp_abs_time = 0x40000c20; +r_cmp_dest_id = 0x40000c24; +r_cmp_timer_id = 0x40000c28; +r_co_bdaddr_compare = 0x40000c2c; +r_co_ble_pkt_dur_in_us = 0x40000c30; +r_co_list_extract = 0x40000c34; +r_co_list_extract_after = 0x40000c38; +r_co_list_extract_sublist = 0x40000c3c; +r_co_list_find = 0x40000c40; +r_co_list_init = 0x40000c44; +r_co_list_insert_after = 0x40000c48; +r_co_list_insert_before = 0x40000c4c; +r_co_list_merge = 0x40000c50; +r_co_list_pool_init = 0x40000c54; +r_co_list_pop_front = 0x40000c58; +r_co_list_push_back = 0x40000c5c; +r_co_list_push_back_sublist = 0x40000c60; +r_co_list_push_front = 0x40000c64; +r_co_list_size = 0x40000c68; +r_co_nb_good_le_channels = 0x40000c6c; +r_co_util_pack = 0x40000c70; +r_co_util_read_array_size = 0x40000c74; +r_co_util_unpack = 0x40000c78; +r_dbg_env_deinit = 0x40000c7c; +r_dbg_env_init = 0x40000c80; +r_dbg_platform_reset_complete = 0x40000c84; +r_dl_upd_proc_start = 0x40000c88; +r_dump_data = 0x40000c8c; +r_ecc_abort_key256_generation = 0x40000c90; +r_ecc_gen_new_public_key = 0x40000c94; +r_ecc_gen_new_secret_key = 0x40000c98; +r_ecc_generate_key256 = 0x40000c9c; +r_ecc_get_debug_Keys = 0x40000ca0; +r_ecc_init = 0x40000ca4; +r_ecc_is_valid_point = 0x40000ca8; +r_ecc_multiplication_event_handler = 0x40000cac; +r_ecc_point_multiplication_win_256 = 0x40000cb0; +r_emi_alloc_em_mapping_by_offset = 0x40000cb4; +r_emi_base_reg_lut_show = 0x40000cb8; +r_emi_em_base_reg_show = 0x40000cbc; +r_emi_free_em_mapping_by_offset = 0x40000cc0; +r_emi_get_em_mapping_idx_by_offset = 0x40000cc4; +r_emi_get_mem_addr_by_offset = 0x40000cc8; +r_emi_overwrite_em_mapping_by_offset = 0x40000ccc; +r_esp_vendor_hci_command_handler = 0x40000cd0; +r_get_stack_usage = 0x40000cd4; +r_h4tl_acl_hdr_rx_evt_handler = 0x40000cd8; +r_h4tl_cmd_hdr_rx_evt_handler = 0x40000cdc; +r_h4tl_cmd_pld_rx_evt_handler = 0x40000ce0; +r_h4tl_eif_io_event_post = 0x40000ce4; +r_h4tl_eif_register = 0x40000ce8; +r_h4tl_init = 0x40000cec; +r_h4tl_out_of_sync = 0x40000cf0; +r_h4tl_out_of_sync_check = 0x40000cf4; +r_h4tl_read_hdr = 0x40000cf8; +r_h4tl_read_next_out_of_sync = 0x40000cfc; +r_h4tl_read_payl = 0x40000d00; +r_h4tl_read_start = 0x40000d04; +r_h4tl_rx_acl_hdr_extract = 0x40000d08; +r_h4tl_rx_cmd_hdr_extract = 0x40000d0c; +r_h4tl_rx_done = 0x40000d10; +r_h4tl_start = 0x40000d14; +r_h4tl_stop = 0x40000d18; +r_h4tl_tx_done = 0x40000d1c; +r_h4tl_tx_evt_handler = 0x40000d20; +r_h4tl_write = 0x40000d24; +r_hci_acl_tx_data_alloc = 0x40000d28; +r_hci_acl_tx_data_received = 0x40000d2c; +r_hci_basic_cmd_send_2_controller = 0x40000d30; +r_hci_ble_adv_report_filter_check = 0x40000d34; +r_hci_ble_adv_report_tx_check = 0x40000d38; +r_hci_ble_conhdl_register = 0x40000d3c; +r_hci_ble_conhdl_unregister = 0x40000d40; +r_hci_build_acl_data = 0x40000d44; +r_hci_build_cc_evt = 0x40000d48; +r_hci_build_cs_evt = 0x40000d4c; +r_hci_build_evt = 0x40000d50; +r_hci_build_le_evt = 0x40000d54; +r_hci_cmd_get_max_param_size = 0x40000d58; +r_hci_cmd_received = 0x40000d5c; +r_hci_cmd_reject = 0x40000d60; +r_hci_evt_mask_check = 0x40000d64; +r_hci_evt_mask_set = 0x40000d68; +r_hci_fc_acl_buf_size_set = 0x40000d6c; +r_hci_fc_acl_en = 0x40000d70; +r_hci_fc_acl_packet_sent = 0x40000d74; +r_hci_fc_check_host_available_nb_acl_packets = 0x40000d78; +r_hci_fc_host_nb_acl_pkts_complete = 0x40000d7c; +r_hci_fc_init = 0x40000d80; +r_hci_look_for_cmd_desc = 0x40000d84; +r_hci_look_for_evt_desc = 0x40000d88; +r_hci_look_for_le_evt_desc = 0x40000d8c; +r_hci_look_for_le_evt_desc_esp = 0x40000d90; +r_hci_pack_bytes = 0x40000d94; +r_hci_register_vendor_desc_tab = 0x40000d98; +r_hci_send_2_controller = 0x40000d9c; +r_hci_send_2_host = 0x40000da0; +r_hci_tl_c2h_data_flow_on = 0x40000da4; +r_hci_tl_cmd_hdr_rx_evt_handler = 0x40000da8; +r_hci_tl_cmd_pld_rx_evt_handler = 0x40000dac; +r_hci_tl_get_pkt = 0x40000db0; +r_hci_tl_hci_pkt_handler = 0x40000db4; +r_hci_tl_hci_tx_done_evt_handler = 0x40000db8; +r_hci_tl_inc_nb_h2c_cmd_pkts = 0x40000dbc; +r_hci_tl_save_pkt = 0x40000dc0; +r_hci_tl_send = 0x40000dc4; +r_hci_tx_done = 0x40000dc8; +r_hci_tx_start = 0x40000dcc; +r_hci_tx_trigger = 0x40000dd0; +r_isValidSecretKey_256 = 0x40000dd4; +r_ke_check_malloc = 0x40000dd8; +r_ke_event_callback_set = 0x40000ddc; +r_ke_event_clear = 0x40000de0; +r_ke_event_flush = 0x40000de4; +r_ke_event_get = 0x40000de8; +r_ke_event_get_all = 0x40000dec; +r_ke_event_init = 0x40000df0; +r_ke_event_schedule = 0x40000df4; +r_ke_event_set = 0x40000df8; +r_ke_flush = 0x40000dfc; +r_ke_free = 0x40000e00; +r_ke_handler_search = 0x40000e04; +r_ke_init = 0x40000e08; +r_ke_is_free = 0x40000e0c; +r_ke_malloc = 0x40000e10; +r_ke_mem_init = 0x40000e14; +r_ke_mem_is_empty = 0x40000e18; +r_ke_mem_is_in_heap = 0x40000e1c; +r_ke_msg_alloc = 0x40000e20; +r_ke_msg_dest_id_get = 0x40000e24; +r_ke_msg_discard = 0x40000e28; +r_ke_msg_forward = 0x40000e2c; +r_ke_msg_forward_new_id = 0x40000e30; +r_ke_msg_free = 0x40000e34; +r_ke_msg_in_queue = 0x40000e38; +r_ke_msg_save = 0x40000e3c; +r_ke_msg_send = 0x40000e40; +r_ke_msg_send_basic = 0x40000e44; +r_ke_msg_src_id_get = 0x40000e48; +r_ke_queue_extract = 0x40000e4c; +r_ke_queue_insert = 0x40000e50; +r_ke_sleep_check = 0x40000e54; +r_ke_state_get = 0x40000e58; +r_ke_state_set = 0x40000e5c; +r_ke_task_check = 0x40000e60; +r_ke_task_create = 0x40000e64; +r_ke_task_delete = 0x40000e68; +r_ke_task_handler_get = 0x40000e6c; +r_ke_task_init = 0x40000e70; +r_ke_task_msg_flush = 0x40000e74; +r_ke_task_saved_update = 0x40000e78; +r_ke_task_schedule = 0x40000e7c; +r_ke_time = 0x40000e80; +r_ke_time_cmp = 0x40000e84; +r_ke_time_past = 0x40000e88; +r_ke_timer_active = 0x40000e8c; +r_ke_timer_adjust_all = 0x40000e90; +r_ke_timer_clear = 0x40000e94; +r_ke_timer_init = 0x40000e98; +r_ke_timer_schedule = 0x40000e9c; +r_ke_timer_set = 0x40000ea0; +r_led_init = 0x40000ea4; +r_led_set_all = 0x40000ea8; +r_llc_aes_res_cb = 0x40000eac; +r_llc_ch_map_up_proc_err_cb = 0x40000eb0; +r_llc_cleanup = 0x40000eb4; +r_llc_cmd_cmp_send = 0x40000eb8; +r_llc_cmd_stat_send = 0x40000ebc; +r_llc_con_move_cbk = 0x40000ec0; +r_llc_con_plan_set_update = 0x40000ec4; +r_llc_con_upd_param_in_range = 0x40000ec8; +r_llc_disconnect = 0x40000ecc; +r_llc_disconnect_end = 0x40000ed0; +r_llc_disconnect_proc_continue = 0x40000ed4; +r_llc_disconnect_proc_err_cb = 0x40000ed8; +r_llc_dl_chg_check = 0x40000edc; +r_llc_dle_proc_err_cb = 0x40000ee0; +r_llc_feats_exch_proc_err_cb = 0x40000ee4; +r_llc_hci_cmd_handler_tab_p_get = 0x40000ee8; +r_llc_hci_command_handler = 0x40000eec; +r_llc_hci_con_param_req_evt_send = 0x40000ef0; +r_llc_hci_con_upd_info_send = 0x40000ef4; +r_llc_hci_disconnected_dis = 0x40000ef8; +r_llc_hci_dl_upd_info_send = 0x40000efc; +r_llc_hci_enc_evt_send = 0x40000f00; +r_llc_hci_feats_info_send = 0x40000f04; +r_llc_hci_le_phy_upd_cmp_evt_send = 0x40000f08; +r_llc_hci_ltk_request_evt_send = 0x40000f0c; +r_llc_hci_nb_cmp_pkts_evt_send = 0x40000f10; +r_llc_hci_version_info_send = 0x40000f14; +r_llc_init_term_proc = 0x40000f18; +r_llc_iv_skd_rand_gen = 0x40000f1c; +r_llc_le_ping_proc_continue = 0x40000f20; +r_llc_le_ping_proc_err_cb = 0x40000f24; +r_llc_le_ping_restart = 0x40000f28; +r_llc_le_ping_set = 0x40000f2c; +r_llc_ll_pause_enc_rsp_ack_handler = 0x40000f30; +r_llc_ll_reject_ind_ack_handler = 0x40000f34; +r_llc_ll_reject_ind_pdu_send = 0x40000f38; +r_llc_ll_start_enc_rsp_ack_handler = 0x40000f3c; +r_llc_ll_terminate_ind_ack = 0x40000f40; +r_llc_ll_unknown_ind_handler = 0x40000f44; +r_llc_llcp_send = 0x40000f48; +r_llc_llcp_state_set = 0x40000f4c; +r_llc_llcp_trans_timer_set = 0x40000f50; +r_llc_llcp_tx_check = 0x40000f54; +r_llc_loc_ch_map_proc_continue = 0x40000f58; +r_llc_loc_con_upd_proc_continue = 0x40000f5c; +r_llc_loc_con_upd_proc_err_cb = 0x40000f60; +r_llc_loc_dl_upd_proc_continue = 0x40000f64; +r_llc_loc_encrypt_proc_continue = 0x40000f68; +r_llc_loc_encrypt_proc_err_cb = 0x40000f6c; +r_llc_loc_feats_exch_proc_continue = 0x40000f70; +r_llc_loc_phy_upd_proc_continue = 0x40000f74; +r_llc_loc_phy_upd_proc_err_cb = 0x40000f78; +r_llc_msg_handler_tab_p_get = 0x40000f7c; +r_llc_pref_param_compute = 0x40000f80; +r_llc_proc_collision_check = 0x40000f84; +r_llc_proc_err_ind = 0x40000f88; +r_llc_proc_get = 0x40000f8c; +r_llc_proc_id_get = 0x40000f90; +r_llc_proc_reg = 0x40000f94; +r_llc_proc_state_get = 0x40000f98; +r_llc_proc_state_set = 0x40000f9c; +r_llc_proc_timer_pause_set = 0x40000fa0; +r_llc_proc_timer_set = 0x40000fa4; +r_llc_proc_unreg = 0x40000fa8; +r_llc_rem_ch_map_proc_continue = 0x40000fac; +r_llc_rem_con_upd_proc_continue = 0x40000fb0; +r_llc_rem_con_upd_proc_err_cb = 0x40000fb4; +r_llc_rem_dl_upd_proc = 0x40000fb8; +r_llc_rem_encrypt_proc_continue = 0x40000fbc; +r_llc_rem_encrypt_proc_err_cb = 0x40000fc0; +r_llc_rem_phy_upd_proc_continue = 0x40000fc4; +r_llc_rem_phy_upd_proc_err_cb = 0x40000fc8; +r_llc_role_get = 0x40000fcc; +r_llc_sk_gen = 0x40000fd0; +r_llc_start = 0x40000fd4; +r_llc_stop = 0x40000fd8; +r_llc_ver_exch_loc_proc_continue = 0x40000fdc; +r_llc_ver_proc_err_cb = 0x40000fe0; +r_llcp_pdu_handler_tab_p_get = 0x40000fe4; +r_lld_aa_gen = 0x40000fe8; +r_lld_adv_adv_data_set = 0x40000fec; +r_lld_adv_adv_data_update = 0x40000ff0; +r_lld_adv_aux_ch_idx_set = 0x40000ff4; +r_lld_adv_aux_evt_canceled_cbk = 0x40000ff8; +r_lld_adv_aux_evt_start_cbk = 0x40000ffc; +r_lld_adv_coex_check_ext_adv_synced = 0x40001000; +r_lld_adv_coex_env_reset = 0x40001004; +r_lld_adv_duration_update = 0x40001008; +r_lld_adv_dynamic_pti_process = 0x4000100c; +r_lld_adv_end = 0x40001010; +r_lld_adv_evt_canceled_cbk = 0x40001014; +r_lld_adv_evt_start_cbk = 0x40001018; +r_lld_adv_ext_chain_construct = 0x4000101c; +r_lld_adv_ext_pkt_prepare = 0x40001020; +r_lld_adv_frm_cbk = 0x40001024; +r_lld_adv_frm_isr = 0x40001028; +r_lld_adv_frm_skip_isr = 0x4000102c; +r_lld_adv_init = 0x40001030; +r_lld_adv_pkt_rx = 0x40001034; +r_lld_adv_pkt_rx_connect_ind = 0x40001038; +r_lld_adv_pkt_rx_send_scan_req_evt = 0x4000103c; +r_lld_adv_rand_addr_update = 0x40001040; +r_lld_adv_restart = 0x40001044; +r_lld_adv_scan_rsp_data_set = 0x40001048; +r_lld_adv_scan_rsp_data_update = 0x4000104c; +r_lld_adv_set_tx_power = 0x40001050; +r_lld_adv_start = 0x40001054; +r_lld_adv_stop = 0x40001058; +r_lld_adv_sync_info_set = 0x4000105c; +r_lld_adv_sync_info_update = 0x40001060; +r_lld_calc_aux_rx = 0x40001064; +r_lld_cca_alloc = 0x40001068; +r_lld_cca_data_reset = 0x4000106c; +r_lld_cca_free = 0x40001070; +r_lld_ch_assess_data_get = 0x40001074; +r_lld_ch_idx_get = 0x40001078; +r_lld_ch_map_set = 0x4000107c; +r_lld_channel_assess = 0x40001080; +r_lld_con_activity_act_offset_compute = 0x40001084; +r_lld_con_activity_offset_compute = 0x40001088; +r_lld_con_ch_map_update = 0x4000108c; +r_lld_con_cleanup = 0x40001090; +r_lld_con_current_tx_power_get = 0x40001094; +r_lld_con_data_flow_set = 0x40001098; +r_lld_con_data_len_update = 0x4000109c; +r_lld_con_data_tx = 0x400010a0; +r_lld_con_enc_key_load = 0x400010a4; +r_lld_con_event_counter_get = 0x400010a8; +r_lld_con_evt_canceled_cbk = 0x400010ac; +r_lld_con_evt_duration_min_get = 0x400010b0; +r_lld_con_evt_max_eff_time_cal = 0x400010b4; +r_lld_con_evt_sd_evt_time_get = 0x400010b8; +r_lld_con_evt_start_cbk = 0x400010bc; +r_lld_con_evt_time_update = 0x400010c0; +r_lld_con_free_all_tx_buf = 0x400010c4; +r_lld_con_frm_cbk = 0x400010c8; +r_lld_con_frm_isr = 0x400010cc; +r_lld_con_frm_skip_isr = 0x400010d0; +r_lld_con_init = 0x400010d4; +r_lld_con_llcp_tx = 0x400010d8; +r_lld_con_max_lat_calc = 0x400010dc; +r_lld_con_offset_get = 0x400010e0; +r_lld_con_param_update = 0x400010e4; +r_lld_con_phys_update = 0x400010e8; +r_lld_con_pref_slave_evt_dur_set = 0x400010ec; +r_lld_con_pref_slave_latency_set = 0x400010f0; +r_lld_con_rssi_get = 0x400010f4; +r_lld_con_rx = 0x400010f8; +r_lld_con_rx_channel_assess = 0x400010fc; +r_lld_con_rx_enc = 0x40001100; +r_lld_con_rx_isr = 0x40001104; +r_lld_con_rx_link_info_check = 0x40001108; +r_lld_con_rx_llcp_check = 0x4000110c; +r_lld_con_rx_sync_time_update = 0x40001110; +r_lld_con_sched = 0x40001114; +r_lld_con_set_tx_power = 0x40001118; +r_lld_con_start = 0x4000111c; +r_lld_con_stop = 0x40001120; +r_lld_con_tx = 0x40001124; +r_lld_con_tx_enc = 0x40001128; +r_lld_con_tx_isr = 0x4000112c; +r_lld_con_tx_len_update = 0x40001130; +r_lld_con_tx_len_update_for_intv = 0x40001134; +r_lld_con_tx_len_update_for_rate = 0x40001138; +r_lld_con_tx_prog = 0x4000113c; +r_lld_conn_dynamic_pti_process = 0x40001140; +r_lld_continue_scan_rx_isr_end_process = 0x40001144; +r_lld_ext_scan_dynamic_pti_process = 0x40001148; +r_lld_hw_cca_end_isr = 0x4000114c; +r_lld_hw_cca_evt_handler = 0x40001150; +r_lld_hw_cca_isr = 0x40001154; +r_lld_init_cal_anchor_point = 0x40001158; +r_lld_init_compute_winoffset = 0x4000115c; +r_lld_init_connect_req_pack = 0x40001160; +r_lld_init_end = 0x40001164; +r_lld_init_evt_canceled_cbk = 0x40001168; +r_lld_init_evt_start_cbk = 0x4000116c; +r_lld_init_frm_cbk = 0x40001170; +r_lld_init_frm_eof_isr = 0x40001174; +r_lld_init_frm_skip_isr = 0x40001178; +r_lld_init_init = 0x4000117c; +r_lld_init_process_pkt_rx = 0x40001180; +r_lld_init_process_pkt_rx_adv_ext_ind = 0x40001184; +r_lld_init_process_pkt_rx_adv_ind_or_direct_ind = 0x40001188; +r_lld_init_process_pkt_rx_aux_connect_rsp = 0x4000118c; +r_lld_init_process_pkt_tx = 0x40001190; +r_lld_init_process_pkt_tx_cal_con_timestamp = 0x40001194; +r_lld_init_sched = 0x40001198; +r_lld_init_set_tx_power = 0x4000119c; +r_lld_init_start = 0x400011a0; +r_lld_init_stop = 0x400011a4; +r_lld_instant_proc_end = 0x400011a8; +r_lld_llcp_rx_ind_handler = 0x400011ac; +r_lld_per_adv_ch_map_update = 0x400011b0; +r_lld_per_adv_chain_construct = 0x400011b4; +r_lld_per_adv_cleanup = 0x400011b8; +r_lld_per_adv_coex_env_reset = 0x400011bc; +r_lld_per_adv_data_set = 0x400011c0; +r_lld_per_adv_data_update = 0x400011c4; +r_lld_per_adv_dynamic_pti_process = 0x400011c8; +r_lld_per_adv_evt_canceled_cbk = 0x400011cc; +r_lld_per_adv_evt_start_cbk = 0x400011d0; +r_lld_per_adv_ext_pkt_prepare = 0x400011d4; +r_lld_per_adv_frm_cbk = 0x400011d8; +r_lld_per_adv_frm_isr = 0x400011dc; +r_lld_per_adv_frm_skip_isr = 0x400011e0; +r_lld_per_adv_init = 0x400011e4; +r_lld_per_adv_init_info_get = 0x400011e8; +r_lld_per_adv_list_add = 0x400011ec; +r_lld_per_adv_list_rem = 0x400011f0; +r_lld_per_adv_sched = 0x400011f4; +r_lld_per_adv_set_tx_power = 0x400011f8; +r_lld_per_adv_start = 0x400011fc; +r_lld_per_adv_stop = 0x40001200; +r_lld_per_adv_sync_info_get = 0x40001204; +r_lld_process_cca_data = 0x40001208; +r_lld_ral_search = 0x4000120c; +r_lld_read_clock = 0x40001210; +r_lld_res_list_add = 0x40001214; +r_lld_res_list_clear = 0x40001218; +r_lld_res_list_is_empty = 0x4000121c; +r_lld_res_list_local_rpa_get = 0x40001220; +r_lld_res_list_peer_rpa_get = 0x40001224; +r_lld_res_list_peer_update = 0x40001228; +r_lld_res_list_priv_mode_update = 0x4000122c; +r_lld_res_list_rem = 0x40001230; +r_lld_reset_reg = 0x40001234; +r_lld_rpa_renew = 0x40001238; +r_lld_rpa_renew_evt_canceled_cbk = 0x4000123c; +r_lld_rpa_renew_evt_start_cbk = 0x40001240; +r_lld_rpa_renew_instant_cbk = 0x40001244; +r_lld_rxdesc_check = 0x40001248; +r_lld_rxdesc_free = 0x4000124c; +r_lld_scan_create_sync = 0x40001250; +r_lld_scan_create_sync_cancel = 0x40001254; +r_lld_scan_end = 0x40001258; +r_lld_scan_evt_canceled_cbk = 0x4000125c; +r_lld_scan_evt_start_cbk = 0x40001260; +r_lld_scan_frm_cbk = 0x40001264; +r_lld_scan_frm_eof_isr = 0x40001268; +r_lld_scan_frm_rx_isr = 0x4000126c; +r_lld_scan_frm_skip_isr = 0x40001270; +r_lld_scan_init = 0x40001274; +r_lld_scan_params_update = 0x40001278; +r_lld_scan_process_pkt_rx = 0x4000127c; +r_lld_scan_process_pkt_rx_adv_rep = 0x40001280; +r_lld_scan_process_pkt_rx_aux_adv_ind = 0x40001284; +r_lld_scan_process_pkt_rx_aux_chain_ind = 0x40001288; +r_lld_scan_process_pkt_rx_aux_scan_rsp = 0x4000128c; +r_lld_scan_process_pkt_rx_ext_adv = 0x40001290; +r_lld_scan_process_pkt_rx_ext_adv_ind = 0x40001294; +r_lld_scan_process_pkt_rx_legacy_adv = 0x40001298; +r_lld_scan_restart = 0x4000129c; +r_lld_scan_sched = 0x400012a0; +r_lld_scan_set_tx_power = 0x400012a4; +r_lld_scan_start = 0x400012a8; +r_lld_scan_stop = 0x400012ac; +r_lld_scan_sync_accept = 0x400012b0; +r_lld_scan_sync_info_unpack = 0x400012b4; +r_lld_scan_trunc_ind = 0x400012b8; +r_lld_sw_cca_evt_handler = 0x400012bc; +r_lld_sw_cca_isr = 0x400012c0; +r_lld_sync_ch_map_update = 0x400012c4; +r_lld_sync_cleanup = 0x400012c8; +r_lld_sync_evt_canceled_cbk = 0x400012cc; +r_lld_sync_evt_start_cbk = 0x400012d0; +r_lld_sync_frm_cbk = 0x400012d4; +r_lld_sync_frm_eof_isr = 0x400012d8; +r_lld_sync_frm_rx_isr = 0x400012dc; +r_lld_sync_frm_skip_isr = 0x400012e0; +r_lld_sync_init = 0x400012e4; +r_lld_sync_process_pkt_rx = 0x400012e8; +r_lld_sync_process_pkt_rx_aux_sync_ind = 0x400012ec; +r_lld_sync_process_pkt_rx_pkt_check = 0x400012f0; +r_lld_sync_scan_dynamic_pti_process = 0x400012f4; +r_lld_sync_sched = 0x400012f8; +r_lld_sync_start = 0x400012fc; +r_lld_sync_stop = 0x40001300; +r_lld_sync_trunc_ind = 0x40001304; +r_lld_test_cleanup = 0x40001308; +r_lld_test_evt_canceled_cbk = 0x4000130c; +r_lld_test_evt_start_cbk = 0x40001310; +r_lld_test_freq2chnl = 0x40001314; +r_lld_test_frm_cbk = 0x40001318; +r_lld_test_frm_isr = 0x4000131c; +r_lld_test_init = 0x40001320; +r_lld_test_rx_isr = 0x40001324; +r_lld_test_set_tx_power = 0x40001328; +r_lld_test_start = 0x4000132c; +r_lld_test_stop = 0x40001330; +r_lld_update_rxbuf = 0x40001334; +r_lld_update_rxbuf_isr = 0x40001338; +r_lld_white_list_add = 0x4000133c; +r_lld_white_list_rem = 0x40001340; +r_llm_activity_free_get = 0x40001344; +r_llm_activity_free_set = 0x40001348; +r_llm_activity_syncing_get = 0x4000134c; +r_llm_adv_con_len_check = 0x40001350; +r_llm_adv_hdl_to_id = 0x40001354; +r_llm_adv_rep_flow_control_check = 0x40001358; +r_llm_adv_rep_flow_control_update = 0x4000135c; +r_llm_adv_reports_list_check = 0x40001360; +r_llm_adv_set_all_release = 0x40001364; +r_llm_adv_set_dft_params = 0x40001368; +r_llm_adv_set_release = 0x4000136c; +r_llm_aes_res_cb = 0x40001370; +r_llm_ble_update_adv_flow_control = 0x40001374; +r_llm_ch_map_update = 0x40001378; +r_llm_cmd_cmp_send = 0x4000137c; +r_llm_cmd_stat_send = 0x40001380; +r_llm_dev_list_empty_entry = 0x40001384; +r_llm_dev_list_search = 0x40001388; +r_llm_env_adv_dup_filt_deinit = 0x4000138c; +r_llm_env_adv_dup_filt_init = 0x40001390; +r_llm_init_ble_adv_report_flow_contol = 0x40001394; +r_llm_is_dev_connected = 0x40001398; +r_llm_is_dev_synced = 0x4000139c; +r_llm_is_non_con_act_ongoing_check = 0x400013a0; +r_llm_is_wl_accessible = 0x400013a4; +r_llm_le_evt_mask_check = 0x400013a8; +r_llm_le_features_get = 0x400013ac; +r_llm_link_disc = 0x400013b0; +r_llm_master_ch_map_get = 0x400013b4; +r_llm_msg_handler_tab_p_get = 0x400013b8; +r_llm_no_activity = 0x400013bc; +r_llm_per_adv_slot_dur = 0x400013c0; +r_llm_plan_elt_get = 0x400013c4; +r_llm_rx_path_comp_get = 0x400013c8; +r_llm_scan_start = 0x400013cc; +r_llm_scan_sync_acad_attach = 0x400013d0; +r_llm_scan_sync_acad_detach = 0x400013d4; +r_llm_send_adv_lost_event_to_host = 0x400013d8; +r_llm_tx_path_comp_get = 0x400013dc; +r_misc_deinit = 0x400013e0; +r_misc_free_em_buf_in_isr = 0x400013e4; +r_misc_init = 0x400013e8; +r_misc_msg_handler_tab_p_get = 0x400013ec; +r_notEqual256 = 0x400013f0; +r_phy_upd_proc_start = 0x400013f4; +r_platform_reset = 0x400013f8; +r_register_esp_vendor_cmd_handler = 0x400013fc; +r_rf_em_init = 0x40001400; +r_rf_force_agc_enable = 0x40001404; +r_rf_reg_rd = 0x40001408; +r_rf_reg_wr = 0x4000140c; +r_rf_reset = 0x40001410; +r_rf_rssi_convert = 0x40001414; +r_rf_rw_v9_le_disable = 0x40001418; +r_rf_rw_v9_le_enable = 0x4000141c; +r_rf_sleep = 0x40001420; +r_rf_txpwr_cs_get = 0x40001424; +r_rf_txpwr_dbm_get = 0x40001428; +r_rf_util_cs_fmt_convert = 0x4000142c; +r_rw_crypto_aes_ccm = 0x40001430; +r_rw_crypto_aes_encrypt = 0x40001434; +r_rw_crypto_aes_init = 0x40001438; +r_rw_crypto_aes_k1 = 0x4000143c; +r_rw_crypto_aes_k2 = 0x40001440; +r_rw_crypto_aes_k3 = 0x40001444; +r_rw_crypto_aes_k4 = 0x40001448; +r_rw_crypto_aes_rand = 0x4000144c; +r_rw_crypto_aes_result_handler = 0x40001450; +r_rw_crypto_aes_s1 = 0x40001454; +r_rw_cryto_aes_cmac = 0x40001458; +r_rw_v9_init_em_radio_table = 0x4000145c; +r_rwble_isr = 0x40001460; +r_rwble_sleep_enter = 0x40001464; +r_rwble_sleep_wakeup_end = 0x40001468; +r_rwbtdm_isr_wrapper = 0x4000146c; +r_rwip_active_check = 0x40001470; +r_rwip_aes_encrypt = 0x40001474; +r_rwip_assert = 0x40001478; +r_rwip_crypt_evt_handler = 0x4000147c; +r_rwip_crypt_isr_handler = 0x40001480; +r_rwip_eif_get = 0x40001484; +r_rwip_half_slot_2_lpcycles = 0x40001488; +r_rwip_hus_2_lpcycles = 0x4000148c; +r_rwip_isr = 0x40001490; +r_rwip_lpcycles_2_hus = 0x40001494; +r_rwip_prevent_sleep_clear = 0x40001498; +r_rwip_prevent_sleep_set = 0x4000149c; +r_rwip_schedule = 0x400014a0; +r_rwip_sleep = 0x400014a4; +r_rwip_sw_int_handler = 0x400014a8; +r_rwip_sw_int_req = 0x400014ac; +r_rwip_time_get = 0x400014b0; +r_rwip_timer_10ms_handler = 0x400014b4; +r_rwip_timer_10ms_set = 0x400014b8; +r_rwip_timer_hs_handler = 0x400014bc; +r_rwip_timer_hs_set = 0x400014c0; +r_rwip_timer_hus_handler = 0x400014c4; +r_rwip_timer_hus_set = 0x400014c8; +r_rwip_wakeup = 0x400014cc; +r_rwip_wakeup_end = 0x400014d0; +r_rwip_wlcoex_set = 0x400014d4; +r_sch_alarm_clear = 0x400014d8; +r_sch_alarm_init = 0x400014dc; +r_sch_alarm_prog = 0x400014e0; +r_sch_alarm_set = 0x400014e4; +r_sch_alarm_timer_isr = 0x400014e8; +r_sch_arb_conflict_check = 0x400014ec; +r_sch_arb_elt_cancel = 0x400014f0; +r_sch_arb_event_start_isr = 0x400014f4; +r_sch_arb_init = 0x400014f8; +r_sch_arb_insert = 0x400014fc; +r_sch_arb_prog_timer = 0x40001500; +r_sch_arb_remove = 0x40001504; +r_sch_arb_sw_isr = 0x40001508; +r_sch_plan_chk = 0x4000150c; +r_sch_plan_clock_wrap_offset_update = 0x40001510; +r_sch_plan_init = 0x40001514; +r_sch_plan_interval_req = 0x40001518; +r_sch_plan_offset_max_calc = 0x4000151c; +r_sch_plan_offset_req = 0x40001520; +r_sch_plan_position_range_compute = 0x40001524; +r_sch_plan_rem = 0x40001528; +r_sch_plan_req = 0x4000152c; +r_sch_plan_set = 0x40001530; +r_sch_prog_end_isr = 0x40001534; +r_sch_prog_init = 0x40001538; +r_sch_prog_push = 0x4000153c; +r_sch_prog_rx_isr = 0x40001540; +r_sch_prog_skip_isr = 0x40001544; +r_sch_prog_tx_isr = 0x40001548; +r_sch_slice_bg_add = 0x4000154c; +r_sch_slice_bg_remove = 0x40001550; +r_sch_slice_compute = 0x40001554; +r_sch_slice_fg_add = 0x40001558; +r_sch_slice_fg_remove = 0x4000155c; +r_sch_slice_init = 0x40001560; +r_sch_slice_per_add = 0x40001564; +r_sch_slice_per_remove = 0x40001568; +r_sdk_config_get_bt_sleep_enable = 0x4000156c; +r_sdk_config_get_hl_derived_opts = 0x40001570; +r_sdk_config_get_opts = 0x40001574; +r_sdk_config_get_priv_opts = 0x40001578; +r_sdk_config_set_bt_sleep_enable = 0x4000157c; +r_sdk_config_set_hl_derived_opts = 0x40001580; +r_sdk_config_set_opts = 0x40001584; +r_specialModP256 = 0x40001588; +r_unloaded_area_init = 0x4000158c; +r_vhci_flow_off = 0x40001590; +r_vhci_flow_on = 0x40001594; +r_vhci_notify_host_send_available = 0x40001598; +r_vhci_send_to_host = 0x4000159c; +r_vnd_hci_command_handler = 0x400015a0; +r_vshci_init = 0x400015a4; +vnd_hci_command_handler_wrapper = 0x400015a8; +/* Data (.data, .bss, .rodata) */ +bt_rf_coex_cfg_p = 0x3fcdffcc; +bt_rf_coex_hooks_p = 0x3fcdffc8; +btdm_env_p = 0x3fcdffc4; +g_rw_controller_task_handle = 0x3fcdffc0; +g_rw_init_sem = 0x3fcdffbc; +g_rw_schd_queue = 0x3fcdffb8; +lld_init_env = 0x3fcdffb4; +lld_rpa_renew_env = 0x3fcdffb0; +lld_scan_env = 0x3fcdffac; +lld_scan_sync_env = 0x3fcdffa8; +lld_test_env = 0x3fcdffa4; +p_ble_util_buf_env = 0x3fcdffa0; +p_lld_env = 0x3fcdff9c; +p_llm_env = 0x3fcdff98; +r_h4tl_eif_p = 0x3fcdff94; +r_hli_funcs_p = 0x3fcdff90; +r_ip_funcs_p = 0x3fcdff8c; +r_modules_funcs_p = 0x3fcdff88; +r_osi_funcs_p = 0x3fcdff84; +r_plf_funcs_p = 0x3fcdff80; +vhci_env_p = 0x3fcdff7c; +aa_gen = 0x3fcdff78; +aes_env = 0x3fcdff6c; +bt_rf_coex_cfg_cb = 0x3fcdff1c; +btdm_pwr_state = 0x3fcdff18; +btdm_slp_err = 0x3fcdff14; +ecc_env = 0x3fcdff0c; +esp_handler = 0x3fcdff04; +esp_vendor_cmd = 0x3fcdfefc; +g_adv_delay_dis = 0x3fcdfef8; +g_conflict_elt = 0x3fcdfef4; +g_eif_api = 0x3fcdfee4; +g_event_empty = 0x3fcdfed8; +g_llc_state = 0x3fcdfecc; +g_llm_state = 0x3fcdfec8; +g_max_evt_env = 0x3fcdfec4; +g_misc_state = 0x3fcdfec0; +g_rma_rule_db = 0x3fcdfea4; +g_rtp_rule_db = 0x3fcdfe88; +g_scan_forever = 0x3fcdfe85; +g_time_msb = 0x3fcdfe84; +h4tl_env = 0x3fcdfe5c; +hci_env = 0x3fcdfe38; +hci_ext_host = 0x3fcdfe34; +hci_fc_env = 0x3fcdfe2c; +hci_tl_env = 0x3fcdfe00; +ke_env = 0x3fcdfdd0; +ke_event_env = 0x3fcdfd90; +ke_task_env = 0x3fcdfd14; +llc_env = 0x3fcdfcec; +lld_adv_env = 0x3fcdfcc4; +lld_con_env = 0x3fcdfc9c; +lld_exp_sync_pos_tab = 0x3fcdfc94; +lld_per_adv_env = 0x3fcdfc6c; +lld_sync_env = 0x3fcdfc44; +llm_le_adv_flow_env = 0x3fcdfc38; +rw_sleep_enable = 0x3fcdfc34; +rwble_env = 0x3fcdfc2c; +rwip_env = 0x3fcdfc10; +rwip_param = 0x3fcdfc04; +rwip_prog_delay = 0x3fcdfc00; +rwip_rf = 0x3fcdfbc8; +sch_alarm_env = 0x3fcdfbc0; +sch_arb_env = 0x3fcdfbac; +sch_plan_env = 0x3fcdfba4; +sch_prog_env = 0x3fcdfaa0; +sch_slice_env = 0x3fcdfa40; +sch_slice_params = 0x3fcdfa38; +timer_env = 0x3fcdfa30; +unloaded_area = 0x3fcdfa2c; +vshci_state = 0x3fcdfa28; +TASK_DESC_LLC = 0x3fcdfa1c; +TASK_DESC_LLM = 0x3fcdfa10; +TASK_DESC_VSHCI = 0x3fcdfa04; +co_default_bdaddr = 0x3fcdf9fc; +dbg_assert_block = 0x3fcdf9f8; +g_bt_plf_log_level = 0x3fcdf9f4; +hci_cmd_desc_tab_vs_esp = 0x3fcdf9d0; +hci_command_handler_tab_esp = 0x3fcdf9b8; +privacy_en = 0x3fcdf9b4; +sdk_cfg_priv_opts = 0x3fcdf96c; +BasePoint_x_256 = 0x3ff1ffdc; +BasePoint_y_256 = 0x3ff1ffbc; +DebugE256PublicKey_x = 0x3ff1ff9c; +DebugE256PublicKey_y = 0x3ff1ff7c; +DebugE256SecretKey = 0x3ff1ff5c; +ECC_4Win_Look_up_table = 0x3ff1f7a0; +LLM_AA_CT1 = 0x3ff1f79c; +LLM_AA_CT2 = 0x3ff1f798; +RF_TX_PW_CONV_TBL = 0x3ff1f790; +TASK_DESC_MISC = 0x3ff1f784; +adv_evt_prop2type = 0x3ff1f768; +adv_evt_type2prop = 0x3ff1f760; +aes_cmac_zero = 0x3ff1f750; +aes_k2_salt = 0x3ff1f740; +aes_k3_id64 = 0x3ff1f738; +aes_k3_salt = 0x3ff1f728; +aes_k4_id6 = 0x3ff1f724; +aes_k4_salt = 0x3ff1f714; +bigHexP256 = 0x3ff1f6e8; +byte_tx_time = 0x3ff1f6e0; +co_null_bdaddr = 0x3ff1f6d8; +co_phy_mask_to_rate = 0x3ff1f6d0; +co_phy_mask_to_value = 0x3ff1f6c8; +co_phy_to_rate = 0x3ff1f6c4; +co_phy_value_to_mask = 0x3ff1f6c0; +co_rate_to_byte_dur_us = 0x3ff1f6b8; +co_rate_to_phy = 0x3ff1f6b0; +co_rate_to_phy_mask = 0x3ff1f6ac; +co_sca2ppm = 0x3ff1f69c; +coef_B = 0x3ff1f670; +connect_req_dur_tab = 0x3ff1f668; +ecc_Jacobian_InfinityPoint256 = 0x3ff1f5e4; +em_base_reg_lut = 0x3ff1f518; +fixed_tx_time = 0x3ff1f510; +h4tl_msgtype2hdrlen = 0x3ff1f508; +hci_cmd_desc_root_tab = 0x3ff1f4d8; +hci_cmd_desc_tab_ctrl_bb = 0x3ff1f46c; +hci_cmd_desc_tab_info_par = 0x3ff1f43c; +hci_cmd_desc_tab_le = 0x3ff1f0a0; +hci_cmd_desc_tab_lk_ctrl = 0x3ff1f088; +hci_cmd_desc_tab_stat_par = 0x3ff1f07c; +hci_cmd_desc_tab_vs = 0x3ff1f040; +hci_evt_desc_tab = 0x3ff1eff8; +hci_evt_le_desc_tab = 0x3ff1ef58; +hci_evt_le_desc_tab_esp = 0x3ff1ef50; +hci_rsvd_evt_msk = 0x3ff1ef48; +lld_aux_phy_to_rate = 0x3ff1ef44; +lld_init_max_aux_dur_tab = 0x3ff1ef3c; +lld_scan_map_legacy_pdu_to_evt_type = 0x3ff1ef34; +lld_scan_max_aux_dur_tab = 0x3ff1ef2c; +lld_sync_max_aux_dur_tab = 0x3ff1ef24; +llm_local_le_feats = 0x3ff1ef1c; +llm_local_le_states = 0x3ff1ef14; +llm_local_supp_cmds = 0x3ff1eeec; +maxSecretKey_256 = 0x3ff1eecc; +max_data_tx_time = 0x3ff1eec4; +one_bits = 0x3ff1eeb4; +rwip_coex_cfg = 0x3ff1eeac; +rwip_priority = 0x3ff1ee94; +veryBigHexP256 = 0x3ff1ee48; + + +/*************************************** + Group rom_pp + ***************************************/ + +/* Functions */ +esp_pp_rom_version_get = 0x400015ac; +RC_GetBlockAckTime = 0x400015b0; +ebuf_list_remove = 0x400015b4; +esf_buf_alloc = 0x400015b8; +esf_buf_alloc_dynamic = 0x400015bc; +esf_buf_recycle = 0x400015c0; +GetAccess = 0x400015c4; +hal_mac_is_low_rate_enabled = 0x400015c8; +hal_mac_tx_get_blockack = 0x400015cc; +hal_mac_tx_set_ppdu = 0x400015d0; +ic_get_trc = 0x400015d4; +ic_mac_deinit = 0x400015d8; +ic_mac_init = 0x400015dc; +ic_interface_enabled = 0x400015e0; +is_lmac_idle = 0x400015e4; +lmacAdjustTimestamp = 0x400015e8; +lmacDiscardAgedMSDU = 0x400015ec; +lmacDiscardMSDU = 0x400015f0; +lmacEndFrameExchangeSequence = 0x400015f4; +lmacIsIdle = 0x400015f8; +lmacIsLongFrame = 0x400015fc; +lmacMSDUAged = 0x40001600; +lmacPostTxComplete = 0x40001604; +lmacProcessAllTxTimeout = 0x40001608; +lmacProcessCollisions = 0x4000160c; +lmacProcessRxSucData = 0x40001610; +lmacReachLongLimit = 0x40001614; +lmacReachShortLimit = 0x40001618; +lmacRecycleMPDU = 0x4000161c; +lmacRxDone = 0x40001620; +lmacSetTxFrame = 0x40001624; +lmacTxDone = 0x40001628; +lmacTxFrame = 0x4000162c; +mac_tx_set_duration = 0x40001630; +mac_tx_set_htsig = 0x40001634; +mac_tx_set_plcp0 = 0x40001638; +mac_tx_set_plcp1 = 0x4000163c; +mac_tx_set_plcp2 = 0x40001640; +pm_check_state = 0x40001644; +pm_disable_dream_timer = 0x40001648; +pm_disable_sleep_delay_timer = 0x4000164c; +pm_dream = 0x40001650; +pm_mac_wakeup = 0x40001654; +pm_mac_sleep = 0x40001658; +pm_enable_active_timer = 0x4000165c; +pm_enable_sleep_delay_timer = 0x40001660; +pm_local_tsf_process = 0x40001664; +pm_set_beacon_filter = 0x40001668; +pm_is_in_wifi_slice_threshold = 0x4000166c; +pm_is_waked = 0x40001670; +pm_keep_alive = 0x40001674; +pm_on_beacon_rx = 0x40001678; +pm_on_data_rx = 0x4000167c; +pm_on_tbtt = 0x40001680; +pm_parse_beacon = 0x40001684; +pm_process_tim = 0x40001688; +pm_rx_beacon_process = 0x4000168c; +pm_rx_data_process = 0x40001690; +pm_sleep = 0x40001694; +pm_sleep_for = 0x40001698; +pm_tbtt_process = 0x4000169c; +ppAMPDU2Normal = 0x400016a0; +ppAssembleAMPDU = 0x400016a4; +ppCalFrameTimes = 0x400016a8; +ppCalSubFrameLength = 0x400016ac; +ppCalTxAMPDULength = 0x400016b0; +ppCheckTxAMPDUlength = 0x400016b4; +ppDequeueRxq_Locked = 0x400016b8; +ppDequeueTxQ = 0x400016bc; +ppEmptyDelimiterLength = 0x400016c0; +ppEnqueueRxq = 0x400016c4; +ppEnqueueTxDone = 0x400016c8; +ppGetTxQFirstAvail_Locked = 0x400016cc; +ppGetTxframe = 0x400016d0; +ppMapTxQueue = 0x400016d4; +ppProcTxSecFrame = 0x400016d8; +ppProcessRxPktHdr = 0x400016dc; +ppProcessTxQ = 0x400016e0; +ppRecordBarRRC = 0x400016e4; +lmacRequestTxopQueue = 0x400016e8; +lmacReleaseTxopQueue = 0x400016ec; +ppRecycleAmpdu = 0x400016f0; +ppRecycleRxPkt = 0x400016f4; +ppResortTxAMPDU = 0x400016f8; +ppResumeTxAMPDU = 0x400016fc; +ppRxFragmentProc = 0x40001700; +ppRxPkt = 0x40001704; +ppRxProtoProc = 0x40001708; +ppSearchTxQueue = 0x4000170c; +ppSearchTxframe = 0x40001710; +ppSelectNextQueue = 0x40001714; +ppSubFromAMPDU = 0x40001718; +ppTask = 0x4000171c; +ppTxPkt = 0x40001720; +ppTxProtoProc = 0x40001724; +ppTxqUpdateBitmap = 0x40001728; +pp_coex_tx_request = 0x4000172c; +pp_hdrsize = 0x40001730; +pp_post = 0x40001734; +pp_process_hmac_waiting_txq = 0x40001738; +rcGetAmpduSched = 0x4000173c; +rcUpdateRxDone = 0x40001740; +rc_get_trc = 0x40001744; +rc_get_trc_by_index = 0x40001748; +rcAmpduLowerRate = 0x4000174c; +rcampduuprate = 0x40001750; +rcClearCurAMPDUSched = 0x40001754; +rcClearCurSched = 0x40001758; +rcClearCurStat = 0x4000175c; +rcGetSched = 0x40001760; +rcLowerSched = 0x40001764; +rcSetTxAmpduLimit = 0x40001768; +rcTxUpdatePer = 0x4000176c; +rcUpdateAckSnr = 0x40001770; +rcUpdateRate = 0x40001774; +rcUpdateTxDone = 0x40001778; +rcUpdateTxDoneAmpdu2 = 0x4000177c; +rcUpSched = 0x40001780; +rssi_margin = 0x40001784; +rx11NRate2AMPDULimit = 0x40001788; +TRC_AMPDU_PER_DOWN_THRESHOLD = 0x4000178c; +TRC_AMPDU_PER_UP_THRESHOLD = 0x40001790; +trc_calc_duration = 0x40001794; +trc_isTxAmpduOperational = 0x40001798; +trc_onAmpduOp = 0x4000179c; +TRC_PER_IS_GOOD = 0x400017a0; +trc_SetTxAmpduState = 0x400017a4; +trc_tid_isTxAmpduOperational = 0x400017a8; +trcAmpduSetState = 0x400017ac; +wDevCheckBlockError = 0x400017b0; +wDev_AppendRxBlocks = 0x400017b4; +wDev_DiscardFrame = 0x400017b8; +wDev_GetNoiseFloor = 0x400017bc; +wDev_IndicateAmpdu = 0x400017c0; +wDev_IndicateFrame = 0x400017c4; +wdev_bank_store = 0x400017c8; +wdev_bank_load = 0x400017cc; +wdev_mac_reg_load = 0x400017d0; +wdev_mac_reg_store = 0x400017d4; +wdev_mac_special_reg_load = 0x400017d8; +wdev_mac_special_reg_store = 0x400017dc; +wdev_mac_wakeup = 0x400017e0; +wdev_mac_sleep = 0x400017e4; +hal_mac_is_dma_enable = 0x400017e8; +wDev_ProcessFiq = 0x400017ec; +wDev_ProcessRxSucData = 0x400017f0; +wdevProcessRxSucDataAll = 0x400017f4; +wdev_csi_len_align = 0x400017f8; +ppDequeueTxDone_Locked = 0x400017fc; +ppProcTxDone = 0x40001800; +pm_tx_data_done_process = 0x40001804; +config_is_cache_tx_buf_enabled = 0x40001808; +ppMapWaitTxq = 0x4000180c; +ppProcessWaitingQueue = 0x40001810; +ppDisableQueue = 0x40001814; +pm_allow_tx = 0x40001818; +/* Data (.data, .bss, .rodata) */ +our_instances_ptr = 0x3ff1ee44; +pTxRx = 0x3fcdf968; +lmacConfMib_ptr = 0x3fcdf964; +our_wait_eb = 0x3fcdf960; +our_tx_eb = 0x3fcdf95c; +pp_wdev_funcs = 0x3fcdf958; +g_osi_funcs_p = 0x3fcdf954; +wDevCtrl_ptr = 0x3fcdf950; +g_wdev_last_desc_reset_ptr = 0x3ff1ee40; +wDevMacSleep_ptr = 0x3fcdf94c; +g_lmac_cnt_ptr = 0x3fcdf948; +our_controls_ptr = 0x3ff1ee3c; +pp_sig_cnt_ptr = 0x3fcdf944; +g_eb_list_desc_ptr = 0x3fcdf940; +s_fragment_ptr = 0x3fcdf93c; +if_ctrl_ptr = 0x3fcdf938; +g_intr_lock_mux = 0x3fcdf934; +g_wifi_global_lock = 0x3fcdf930; +s_wifi_queue = 0x3fcdf92c; +pp_task_hdl = 0x3fcdf928; +s_pp_task_create_sem = 0x3fcdf924; +s_pp_task_del_sem = 0x3fcdf920; +g_wifi_menuconfig_ptr = 0x3fcdf91c; +xphyQueue = 0x3fcdf918; +ap_no_lr_ptr = 0x3fcdf914; +rc11BSchedTbl_ptr = 0x3fcdf910; +rc11NSchedTbl_ptr = 0x3fcdf90c; +rcLoRaSchedTbl_ptr = 0x3fcdf908; +BasicOFDMSched_ptr = 0x3fcdf904; +trc_ctl_ptr = 0x3fcdf900; +g_pm_cnt_ptr = 0x3fcdf8fc; +g_pm_ptr = 0x3fcdf8f8; +g_pm_cfg_ptr = 0x3fcdf8f4; +g_esp_mesh_quick_funcs_ptr = 0x3fcdf8f0; +g_txop_queue_status_ptr = 0x3fcdf8ec; +g_mac_sleep_en_ptr = 0x3fcdf8e8; +g_mesh_is_root_ptr = 0x3fcdf8e4; +g_mesh_topology_ptr = 0x3fcdf8e0; +g_mesh_init_ps_type_ptr = 0x3fcdf8dc; +g_mesh_is_started_ptr = 0x3fcdf8d8; +g_config_func = 0x3fcdf8d4; +g_net80211_tx_func = 0x3fcdf8d0; +g_timer_func = 0x3fcdf8cc; +s_michael_mic_failure_cb = 0x3fcdf8c8; +wifi_sta_rx_probe_req = 0x3fcdf8c4; +g_tx_done_cb_func = 0x3fcdf8c0; +g_per_conn_trc = 0x3fcdf874; +s_encap_amsdu_func = 0x3fcdf870; + + +/*************************************** + Group rom_net80211 + ***************************************/ + +/* Functions */ +esp_net80211_rom_version_get = 0x4000181c; +ampdu_dispatch = 0x40001820; +ampdu_dispatch_all = 0x40001824; +ampdu_dispatch_as_many_as_possible = 0x40001828; +ampdu_dispatch_movement = 0x4000182c; +ampdu_dispatch_upto = 0x40001830; +chm_is_at_home_channel = 0x40001834; +cnx_node_is_existing = 0x40001838; +cnx_node_search = 0x4000183c; +ic_ebuf_recycle_rx = 0x40001840; +ic_ebuf_recycle_tx = 0x40001844; +ic_reset_rx_ba = 0x40001848; +ieee80211_align_eb = 0x4000184c; +ieee80211_ampdu_reorder = 0x40001850; +ieee80211_ampdu_start_age_timer = 0x40001854; +ieee80211_encap_esfbuf = 0x40001858; +ieee80211_is_tx_allowed = 0x4000185c; +ieee80211_output_pending_eb = 0x40001860; +ieee80211_output_process = 0x40001864; +ieee80211_set_tx_desc = 0x40001868; +sta_input = 0x4000186c; +wifi_get_macaddr = 0x40001870; +wifi_rf_phy_disable = 0x40001874; +wifi_rf_phy_enable = 0x40001878; +ic_ebuf_alloc = 0x4000187c; +ieee80211_classify = 0x40001880; +ieee80211_copy_eb_header = 0x40001884; +ieee80211_recycle_cache_eb = 0x40001888; +ieee80211_search_node = 0x4000188c; +roundup2 = 0x40001890; +ieee80211_crypto_encap = 0x40001894; +ieee80211_crypto_decap = 0x40001898; +ieee80211_decap = 0x4000189c; +ieee80211_set_tx_pti = 0x400018a0; +wifi_is_started = 0x400018a4; +/* Data (.data, .bss, .rodata) */ +net80211_funcs = 0x3fcdf86c; +g_scan = 0x3fcdf868; +g_chm = 0x3fcdf864; +g_ic_ptr = 0x3fcdf860; +g_hmac_cnt_ptr = 0x3fcdf85c; +g_tx_cacheq_ptr = 0x3fcdf858; +s_netstack_free = 0x3fcdf854; +mesh_rxcb = 0x3fcdf850; +sta_rxcb = 0x3fcdf84c; + + +/*************************************** + Group rom_coexist + ***************************************/ + +/* Functions */ +esp_coex_rom_version_get = 0x400018a8; +coex_bt_release = 0x400018ac; +coex_bt_request = 0x400018b0; +coex_core_ble_conn_dyn_prio_get = 0x400018b4; +coex_core_event_duration_get = 0x400018b8; +coex_core_pti_get = 0x400018bc; +coex_core_release = 0x400018c0; +coex_core_request = 0x400018c4; +coex_core_status_get = 0x400018c8; +coex_core_timer_idx_get = 0x400018cc; +coex_event_duration_get = 0x400018d0; +coex_hw_timer_disable = 0x400018d4; +coex_hw_timer_enable = 0x400018d8; +coex_hw_timer_set = 0x400018dc; +coex_schm_interval_set = 0x400018e0; +coex_schm_lock = 0x400018e4; +coex_schm_unlock = 0x400018e8; +coex_status_get = 0x400018ec; +coex_wifi_release = 0x400018f0; +esp_coex_ble_conn_dynamic_prio_get = 0x400018f4; +/* Data (.data, .bss, .rodata) */ +coex_env_ptr = 0x3fcdf848; +coex_pti_tab_ptr = 0x3fcdf844; +coex_schm_env_ptr = 0x3fcdf840; +coexist_funcs = 0x3fcdf83c; +g_coa_funcs_p = 0x3fcdf838; +g_coex_param_ptr = 0x3fcdf834; + + +/*************************************** + Group rom_phy + ***************************************/ + +/* Functions */ +phy_get_romfuncs = 0x400018f8; +rom_abs_temp = 0x400018fc; +rom_bb_bss_cbw40_dig = 0x40001900; +rom_bb_wdg_test_en = 0x40001904; +rom_bb_wdt_get_status = 0x40001908; +rom_bb_wdt_int_enable = 0x4000190c; +rom_bb_wdt_rst_enable = 0x40001910; +rom_bb_wdt_timeout_clear = 0x40001914; +rom_cbw2040_cfg = 0x40001918; +rom_check_noise_floor = 0x4000191c; +rom_chip_i2c_readReg = 0x40001920; +rom_chip_i2c_writeReg = 0x40001924; +rom_correct_rf_ana_gain = 0x40001928; +rom_dc_iq_est = 0x4000192c; +rom_disable_agc = 0x40001930; +rom_en_pwdet = 0x40001934; +rom_enable_agc = 0x40001938; +rom_get_bbgain_db = 0x4000193c; +rom_get_data_sat = 0x40001940; +rom_get_i2c_read_mask = 0x40001944; +rom_get_pwctrl_correct = 0x40001948; +rom_get_rf_gain_qdb = 0x4000194c; +rom_i2c_readReg = 0x40001950; +rom_i2c_readReg_Mask = 0x40001954; +rom_i2c_writeReg = 0x40001958; +rom_i2c_writeReg_Mask = 0x4000195c; +rom_index_to_txbbgain = 0x40001960; +rom_iq_est_disable = 0x40001964; +rom_iq_est_enable = 0x40001968; +rom_linear_to_db = 0x4000196c; +rom_loopback_mode_en = 0x40001970; +rom_mhz2ieee = 0x40001974; +rom_noise_floor_auto_set = 0x40001978; +rom_pbus_debugmode = 0x4000197c; +rom_pbus_force_mode = 0x40001980; +rom_pbus_force_test = 0x40001984; +rom_pbus_rd = 0x40001988; +rom_pbus_rd_addr = 0x4000198c; +rom_pbus_rd_shift = 0x40001990; +rom_pbus_set_dco = 0x40001994; +rom_pbus_set_rxgain = 0x40001998; +rom_pbus_workmode = 0x4000199c; +rom_pbus_xpd_rx_off = 0x400019a0; +rom_pbus_xpd_rx_on = 0x400019a4; +rom_pbus_xpd_tx_off = 0x400019a8; +rom_pbus_xpd_tx_on = 0x400019ac; +rom_phy_byte_to_word = 0x400019b0; +rom_phy_disable_cca = 0x400019b4; +rom_phy_enable_cca = 0x400019b8; +rom_phy_get_noisefloor = 0x400019bc; +rom_phy_get_rx_freq = 0x400019c0; +rom_phy_set_bbfreq_init = 0x400019c4; +rom_pow_usr = 0x400019c8; +rom_pwdet_sar2_init = 0x400019cc; +rom_read_hw_noisefloor = 0x400019d0; +rom_read_sar_dout = 0x400019d4; +rom_set_cal_rxdc = 0x400019d8; +rom_set_chan_cal_interp = 0x400019dc; +rom_set_loopback_gain = 0x400019e0; +rom_set_noise_floor = 0x400019e4; +rom_set_rxclk_en = 0x400019e8; +rom_set_tx_dig_gain = 0x400019ec; +rom_set_txcap_reg = 0x400019f0; +rom_set_txclk_en = 0x400019f4; +rom_spur_cal = 0x400019f8; +rom_spur_reg_write_one_tone = 0x400019fc; +rom_target_power_add_backoff = 0x40001a00; +rom_tx_pwctrl_bg_init = 0x40001a04; +rom_txbbgain_to_index = 0x40001a08; +rom_wifi_11g_rate_chg = 0x40001a0c; +rom_write_gain_mem = 0x40001a10; +chip726_phyrom_version = 0x40001a14; +rom_disable_wifi_agc = 0x40001a18; +rom_enable_wifi_agc = 0x40001a1c; +rom_set_tx_gain_table = 0x40001a20; +rom_bt_index_to_bb = 0x40001a24; +rom_bt_bb_to_index = 0x40001a28; +rom_wr_bt_tx_atten = 0x40001a2c; +rom_wr_bt_tx_gain_mem = 0x40001a30; +rom_spur_coef_cfg = 0x40001a34; +rom_bb_bss_cbw40 = 0x40001a38; +rom_set_cca = 0x40001a3c; +rom_tx_paon_set = 0x40001a40; +rom_i2cmst_reg_init = 0x40001a44; +rom_iq_corr_enable = 0x40001a48; +rom_fe_reg_init = 0x40001a4c; +rom_agc_reg_init = 0x40001a50; +rom_bb_reg_init = 0x40001a54; +rom_mac_enable_bb = 0x40001a58; +rom_bb_wdg_cfg = 0x40001a5c; +rom_force_txon = 0x40001a60; +rom_fe_txrx_reset = 0x40001a64; +rom_set_rx_comp = 0x40001a68; +rom_set_pbus_reg = 0x40001a6c; +rom_write_chan_freq = 0x40001a70; +rom_phy_xpd_rf = 0x40001a74; +rom_set_xpd_sar = 0x40001a78; +rom_write_dac_gain2 = 0x40001a7c; +rom_rtc_sar2_init = 0x40001a80; +rom_get_target_power_offset = 0x40001a84; +rom_write_txrate_power_offset = 0x40001a88; +rom_get_rate_fcc_index = 0x40001a8c; +rom_get_rate_target_power = 0x40001a90; +rom_write_wifi_dig_gain = 0x40001a94; +rom_bt_correct_rf_ana_gain = 0x40001a98; +rom_pkdet_vol_start = 0x40001a9c; +rom_read_sar2_code = 0x40001aa0; +rom_get_sar2_vol = 0x40001aa4; +rom_get_pll_vol = 0x40001aa8; +rom_get_phy_target_power = 0x40001aac; +rom_temp_to_power = 0x40001ab0; +rom_phy_track_pll_cap = 0x40001ab4; +rom_phy_pwdet_always_en = 0x40001ab8; +rom_phy_pwdet_onetime_en = 0x40001abc; +rom_get_i2c_mst0_mask = 0x40001ac0; +rom_get_i2c_hostid = 0x40001ac4; +rom_enter_critical_phy = 0x40001ac8; +rom_exit_critical_phy = 0x40001acc; +rom_chip_i2c_readReg_org = 0x40001ad0; +rom_i2c_paral_set_mst0 = 0x40001ad4; +rom_i2c_paral_set_read = 0x40001ad8; +rom_i2c_paral_read = 0x40001adc; +rom_i2c_paral_write = 0x40001ae0; +rom_i2c_paral_write_num = 0x40001ae4; +rom_i2c_paral_write_mask = 0x40001ae8; +rom_bb_bss_cbw40_ana = 0x40001aec; +rom_chan_to_freq = 0x40001af0; +rom_open_i2c_xpd = 0x40001af4; +rom_dac_rate_set = 0x40001af8; +rom_tsens_read_init = 0x40001afc; +rom_tsens_code_read = 0x40001b00; +rom_tsens_index_to_dac = 0x40001b04; +rom_tsens_index_to_offset = 0x40001b08; +rom_tsens_dac_cal = 0x40001b0c; +rom_code_to_temp = 0x40001b10; +rom_write_pll_cap_mem = 0x40001b14; +rom_pll_correct_dcap = 0x40001b18; +rom_phy_en_hw_set_freq = 0x40001b1c; +rom_phy_dis_hw_set_freq = 0x40001b20; +rom_pll_vol_cal = 0x40001b24; + diff --git a/tools/flasher_stub/ld/rom_32h2.ld b/tools/flasher_stub/ld/rom_32h2.ld new file mode 100755 index 0000000000..accb0adcf5 --- /dev/null +++ b/tools/flasher_stub/ld/rom_32h2.ld @@ -0,0 +1,428 @@ +/* ROM function interface esp32h2.rom.ld for esp32h2 + * + * + * Generated from ./target/esp32h2/interface-esp32h2.yml md5sum c0ad4e113e5b29bb9d799f10f03edbc1 + * + * Compatible with ROM where ECO version equal or greater to 0. + * + * THIS FILE WAS AUTOMATICALLY GENERATED. DO NOT EDIT. + */ + +/*************************************** + Group common + ***************************************/ + +PROVIDE ( SPIWrite = esp_rom_spiflash_write); +PROVIDE ( SPI_read_status_high = esp_rom_spiflash_read_statushigh); +PROVIDE ( SPI_write_status = esp_rom_spiflash_write_status); +PROVIDE ( SPIRead = esp_rom_spiflash_read); +PROVIDE ( SPIParamCfg = esp_rom_spiflash_config_param); +PROVIDE ( SPIEraseChip = esp_rom_spiflash_erase_chip); +PROVIDE ( SPIEraseSector = esp_rom_spiflash_erase_sector); +PROVIDE ( SPIEraseBlock = esp_rom_spiflash_erase_block); +PROVIDE ( SPI_Write_Encrypt_Enable = esp_rom_spiflash_write_encrypted_enable); +PROVIDE ( SPI_Write_Encrypt_Disable = esp_rom_spiflash_write_encrypted_disable); +PROVIDE ( SPI_Encrypt_Write = esp_rom_spiflash_write_encrypted); + +/*************************************** + Group common + ***************************************/ + +/* Functions */ +rtc_get_reset_reason = 0x40000018; +analog_super_wdt_reset_happened = 0x4000001c; +rtc_get_wakeup_cause = 0x40000020; +rtc_unhold_all_pads = 0x40000024; +ets_printf = 0x40000028; +ets_install_putc1 = 0x4000002c; +ets_install_putc2 = 0x40000030; +ets_install_uart_printf = 0x40000034; +ets_install_usb_printf = 0x40000038; +ets_get_printf_channel = 0x4000003c; +ets_delay_us = 0x40000040; +ets_get_cpu_frequency = 0x40000044; +ets_update_cpu_frequency = 0x40000048; +ets_install_lock = 0x4000004c; +UartRxString = 0x40000050; +UartGetCmdLn = 0x40000054; +uart_tx_one_char = 0x40000058; +uart_tx_one_char2 = 0x4000005c; +uart_rx_one_char = 0x40000060; +uart_rx_one_char_block = 0x40000064; +uart_rx_intr_handler = 0x40000068; +uart_rx_readbuff = 0x4000006c; +uartAttach = 0x40000070; +uart_tx_flush = 0x40000074; +uart_tx_wait_idle = 0x40000078; +uart_div_modify = 0x4000007c; +ets_write_char_uart = 0x40000080; +uart_tx_switch = 0x40000084; +roundup2 = 0x40000088; +multofup = 0x4000008c; +software_reset = 0x40000090; +software_reset_cpu = 0x40000094; +ets_clk_assist_debug_clock_enable = 0x40000098; +clear_super_wdt_reset_flag = 0x4000009c; +disable_default_watchdog = 0x400000a0; +esp_rom_set_rtc_wake_addr = 0x400000a4; +esp_rom_get_rtc_wake_addr = 0x400000a8; +send_packet = 0x400000ac; +recv_packet = 0x400000b0; +GetUartDevice = 0x400000b4; +UartDwnLdProc = 0x400000b8; +GetSecurityInfoProc = 0x400000bc; +Uart_Init = 0x400000c0; +ets_set_user_start = 0x400000c4; +/* Data (.data, .bss, .rodata) */ +ets_rom_layout_p = 0x4001fffc; +ets_ops_table_ptr = 0x4084fff8; +g_saved_pc = 0x4084fffc; + + +/*************************************** + Group miniz + ***************************************/ + +/* Functions */ +mz_adler32 = 0x400000c8; +mz_free = 0x400000cc; +tdefl_compress = 0x400000d0; +tdefl_compress_buffer = 0x400000d4; +tdefl_compress_mem_to_heap = 0x400000d8; +tdefl_compress_mem_to_mem = 0x400000dc; +tdefl_compress_mem_to_output = 0x400000e0; +tdefl_get_adler32 = 0x400000e4; +tdefl_get_prev_return_status = 0x400000e8; +tdefl_init = 0x400000ec; +tdefl_write_image_to_png_file_in_memory = 0x400000f0; +tdefl_write_image_to_png_file_in_memory_ex = 0x400000f4; +tinfl_decompress = 0x400000f8; +tinfl_decompress_mem_to_callback = 0x400000fc; +tinfl_decompress_mem_to_heap = 0x40000100; +tinfl_decompress_mem_to_mem = 0x40000104; + + +/*************************************** + Group spiflash_legacy + ***************************************/ + +/* Functions */ +esp_rom_spiflash_wait_idle = 0x40000108; +esp_rom_spiflash_write_encrypted = 0x4000010c; +esp_rom_spiflash_write_encrypted_dest = 0x40000110; +esp_rom_spiflash_write_encrypted_enable = 0x40000114; +esp_rom_spiflash_write_encrypted_disable = 0x40000118; +esp_rom_spiflash_erase_chip = 0x4000011c; +_esp_rom_spiflash_erase_sector = 0x40000120; +_esp_rom_spiflash_erase_block = 0x40000124; +_esp_rom_spiflash_write = 0x40000128; +_esp_rom_spiflash_read = 0x4000012c; +_esp_rom_spiflash_unlock = 0x40000130; +_SPIEraseArea = 0x40000134; +_SPI_write_enable = 0x40000138; +esp_rom_spiflash_erase_sector = 0x4000013c; +esp_rom_spiflash_erase_block = 0x40000140; +esp_rom_spiflash_write = 0x40000144; +esp_rom_spiflash_read = 0x40000148; +esp_rom_spiflash_unlock = 0x4000014c; +SPIEraseArea = 0x40000150; +SPI_write_enable = 0x40000154; +esp_rom_spiflash_config_param = 0x40000158; +esp_rom_spiflash_read_user_cmd = 0x4000015c; +esp_rom_spiflash_select_qio_pins = 0x40000160; +esp_rom_spi_flash_auto_sus_res = 0x40000164; +esp_rom_spi_flash_send_resume = 0x40000168; +esp_rom_spi_flash_update_id = 0x4000016c; +esp_rom_spiflash_config_clk = 0x40000170; +esp_rom_spiflash_config_readmode = 0x40000174; +esp_rom_spiflash_read_status = 0x40000178; +esp_rom_spiflash_read_statushigh = 0x4000017c; +esp_rom_spiflash_write_status = 0x40000180; +spi_cache_mode_switch = 0x40000184; +spi_common_set_dummy_output = 0x40000188; +spi_common_set_flash_cs_timing = 0x4000018c; +esp_rom_spi_set_address_bit_len = 0x40000190; +SPILock = 0x40000194; +SPIMasterReadModeCnfig = 0x40000198; +SPI_Common_Command = 0x4000019c; +SPI_WakeUp = 0x400001a0; +SPI_block_erase = 0x400001a4; +SPI_chip_erase = 0x400001a8; +SPI_init = 0x400001ac; +SPI_page_program = 0x400001b0; +SPI_read_data = 0x400001b4; +SPI_sector_erase = 0x400001b8; +SelectSpiFunction = 0x400001bc; +SetSpiDrvs = 0x400001c0; +Wait_SPI_Idle = 0x400001c4; +spi_dummy_len_fix = 0x400001c8; +Disable_QMode = 0x400001cc; +Enable_QMode = 0x400001d0; +spi_flash_attach = 0x400001d4; +spi_flash_get_chip_size = 0x400001d8; +spi_flash_guard_set = 0x400001dc; +spi_flash_guard_get = 0x400001e0; +spi_flash_read_encrypted = 0x400001e4; +/* Data (.data, .bss, .rodata) */ +rom_spiflash_legacy_funcs = 0x4084fff0; +rom_spiflash_legacy_data = 0x4084ffec; +g_flash_guard_ops = 0x4084fff4; + + +/*************************************** + Group hal_wdt + ***************************************/ + +/* Functions */ +wdt_hal_init = 0x4000038c; +wdt_hal_deinit = 0x40000390; +wdt_hal_config_stage = 0x40000394; +wdt_hal_write_protect_disable = 0x40000398; +wdt_hal_write_protect_enable = 0x4000039c; +wdt_hal_enable = 0x400003a0; +wdt_hal_disable = 0x400003a4; +wdt_hal_handle_intr = 0x400003a8; +wdt_hal_feed = 0x400003ac; +wdt_hal_set_flashboot_en = 0x400003b0; +wdt_hal_is_enabled = 0x400003b4; + + +/*************************************** + Group hal_systimer + ***************************************/ + +/* Functions */ +systimer_hal_init = 0x400003b8; +systimer_hal_deinit = 0x400003bc; +systimer_hal_set_tick_rate_ops = 0x400003c0; +systimer_hal_get_counter_value = 0x400003c4; +systimer_hal_get_time = 0x400003c8; +systimer_hal_set_alarm_target = 0x400003cc; +systimer_hal_set_alarm_period = 0x400003d0; +systimer_hal_get_alarm_value = 0x400003d4; +systimer_hal_enable_alarm_int = 0x400003d8; +systimer_hal_on_apb_freq_update = 0x400003dc; +systimer_hal_counter_value_advance = 0x400003e0; +systimer_hal_enable_counter = 0x400003e4; +systimer_hal_select_alarm_mode = 0x400003e8; +systimer_hal_connect_alarm_counter = 0x400003ec; +systimer_hal_counter_can_stall_by_cpu = 0x400003f0; + + +/*************************************** + Group cache + ***************************************/ + +/* Functions */ +Cache_Get_ICache_Line_Size = 0x400005fc; +Cache_Get_Mode = 0x40000600; +Cache_Address_Through_Cache = 0x40000604; +ROM_Boot_Cache_Init = 0x40000608; +MMU_Set_Page_Mode = 0x4000060c; +MMU_Get_Page_Mode = 0x40000610; +Cache_Invalidate_ICache_Items = 0x40000614; +Cache_Op_Addr = 0x40000618; +Cache_Invalidate_Addr = 0x4000061c; +Cache_Invalidate_ICache_All = 0x40000620; +Cache_Mask_All = 0x40000624; +Cache_UnMask_Dram0 = 0x40000628; +Cache_Suspend_ICache_Autoload = 0x4000062c; +Cache_Resume_ICache_Autoload = 0x40000630; +Cache_Start_ICache_Preload = 0x40000634; +Cache_ICache_Preload_Done = 0x40000638; +Cache_End_ICache_Preload = 0x4000063c; +Cache_Config_ICache_Autoload = 0x40000640; +Cache_Enable_ICache_Autoload = 0x40000644; +Cache_Disable_ICache_Autoload = 0x40000648; +Cache_Enable_ICache_PreLock = 0x4000064c; +Cache_Disable_ICache_PreLock = 0x40000650; +Cache_Lock_ICache_Items = 0x40000654; +Cache_Unlock_ICache_Items = 0x40000658; +Cache_Lock_Addr = 0x4000065c; +Cache_Unlock_Addr = 0x40000660; +Cache_Disable_ICache = 0x40000664; +Cache_Enable_ICache = 0x40000668; +Cache_Suspend_ICache = 0x4000066c; +Cache_Resume_ICache = 0x40000670; +Cache_Freeze_ICache_Enable = 0x40000674; +Cache_Freeze_ICache_Disable = 0x40000678; +Cache_Set_IDROM_MMU_Size = 0x4000067c; +Cache_Get_IROM_MMU_End = 0x40000680; +Cache_Get_DROM_MMU_End = 0x40000684; +Cache_MMU_Init = 0x40000688; +Cache_MSPI_MMU_Set = 0x4000068c; +Cache_Travel_Tag_Memory = 0x40000690; +Cache_Get_Virtual_Addr = 0x40000694; +/* Data (.data, .bss, .rodata) */ +rom_cache_op_cb = 0x4084ffcc; +rom_cache_internal_table_ptr = 0x4084ffc8; + + +/*************************************** + Group clock + ***************************************/ + +/* Functions */ +ets_clk_get_xtal_freq = 0x40000698; +ets_clk_get_cpu_freq = 0x4000069c; + + +/*************************************** + Group gpio + ***************************************/ + +/* Functions */ +gpio_input_get = 0x400006a0; +gpio_matrix_in = 0x400006a4; +gpio_matrix_out = 0x400006a8; +gpio_output_disable = 0x400006ac; +gpio_output_enable = 0x400006b0; +gpio_output_set = 0x400006b4; +gpio_pad_hold = 0x400006b8; +gpio_pad_input_disable = 0x400006bc; +gpio_pad_input_enable = 0x400006c0; +gpio_pad_pulldown = 0x400006c4; +gpio_pad_pullup = 0x400006c8; +gpio_pad_select_gpio = 0x400006cc; +gpio_pad_set_drv = 0x400006d0; +gpio_pad_unhold = 0x400006d4; +gpio_pin_wakeup_disable = 0x400006d8; +gpio_pin_wakeup_enable = 0x400006dc; +gpio_bypass_matrix_in = 0x400006e0; + + +/*************************************** + Group interrupts + ***************************************/ + +/* Functions */ +esprv_intc_int_set_priority = 0x400006e4; +esprv_intc_int_set_threshold = 0x400006e8; +esprv_intc_int_enable = 0x400006ec; +esprv_intc_int_disable = 0x400006f0; +esprv_intc_int_set_type = 0x400006f4; +PROVIDE( intr_handler_set = 0x400006f8 ); +intr_matrix_set = 0x400006fc; +ets_intr_lock = 0x40000700; +ets_intr_unlock = 0x40000704; +ets_isr_attach = 0x40000708; +ets_isr_mask = 0x4000070c; +ets_isr_unmask = 0x40000710; + + +/*************************************** + Group crypto + ***************************************/ + +/* Functions */ +md5_vector = 0x40000714; +MD5Init = 0x40000718; +MD5Update = 0x4000071c; +MD5Final = 0x40000720; +crc32_le = 0x40000724; +crc16_le = 0x40000728; +crc8_le = 0x4000072c; +crc32_be = 0x40000730; +crc16_be = 0x40000734; +crc8_be = 0x40000738; +esp_crc8 = 0x4000073c; +ets_sha_enable = 0x40000740; +ets_sha_disable = 0x40000744; +ets_sha_get_state = 0x40000748; +ets_sha_init = 0x4000074c; +ets_sha_process = 0x40000750; +ets_sha_starts = 0x40000754; +ets_sha_update = 0x40000758; +ets_sha_finish = 0x4000075c; +ets_sha_clone = 0x40000760; +ets_hmac_enable = 0x40000764; +ets_hmac_disable = 0x40000768; +ets_hmac_calculate_message = 0x4000076c; +ets_hmac_calculate_downstream = 0x40000770; +ets_hmac_invalidate_downstream = 0x40000774; +ets_jtag_enable_temporarily = 0x40000778; +ets_aes_enable = 0x4000077c; +ets_aes_disable = 0x40000780; +ets_aes_setkey = 0x40000784; +ets_aes_block = 0x40000788; +ets_aes_setkey_dec = 0x4000078c; +ets_aes_setkey_enc = 0x40000790; +ets_bigint_enable = 0x40000794; +ets_bigint_disable = 0x40000798; +ets_bigint_multiply = 0x4000079c; +ets_bigint_modmult = 0x400007a0; +ets_bigint_modexp = 0x400007a4; +ets_bigint_wait_finish = 0x400007a8; +ets_bigint_getz = 0x400007ac; +ets_ds_enable = 0x400007b0; +ets_ds_disable = 0x400007b4; +ets_ds_start_sign = 0x400007b8; +ets_ds_is_busy = 0x400007bc; +ets_ds_finish_sign = 0x400007c0; +ets_ds_encrypt_params = 0x400007c4; +ets_mgf1_sha256 = 0x400007c8; +/* Data (.data, .bss, .rodata) */ +crc32_le_table_ptr = 0x4001fff8; +crc16_le_table_ptr = 0x4001fff4; +crc8_le_table_ptr = 0x4001fff0; +crc32_be_table_ptr = 0x4001ffec; +crc16_be_table_ptr = 0x4001ffe8; +crc8_be_table_ptr = 0x4001ffe4; + + +/*************************************** + Group efuse + ***************************************/ + +/* Functions */ +ets_efuse_read = 0x400007cc; +ets_efuse_program = 0x400007d0; +ets_efuse_clear_program_registers = 0x400007d4; +ets_efuse_write_key = 0x400007d8; +ets_efuse_get_read_register_address = 0x400007dc; +ets_efuse_get_key_purpose = 0x400007e0; +ets_efuse_key_block_unused = 0x400007e4; +ets_efuse_find_unused_key_block = 0x400007e8; +ets_efuse_rs_calculate = 0x400007ec; +ets_efuse_count_unused_key_blocks = 0x400007f0; +ets_efuse_secure_boot_enabled = 0x400007f4; +ets_efuse_secure_boot_aggressive_revoke_enabled = 0x400007f8; +ets_efuse_cache_encryption_enabled = 0x400007fc; +ets_efuse_download_modes_disabled = 0x40000800; +ets_efuse_find_purpose = 0x40000804; +ets_efuse_force_send_resume = 0x40000808; +ets_efuse_get_flash_delay_us = 0x4000080c; +ets_efuse_get_mac = 0x40000810; +ets_efuse_get_uart_print_control = 0x40000814; +ets_efuse_direct_boot_mode_disabled = 0x40000818; +ets_efuse_security_download_modes_enabled = 0x4000081c; +ets_efuse_jtag_disabled = 0x40000820; +ets_efuse_usb_print_is_disabled = 0x40000824; +ets_efuse_usb_download_mode_disabled = 0x40000828; +ets_efuse_usb_device_disabled = 0x4000082c; +ets_efuse_secure_boot_fast_wake_enabled = 0x40000830; + + +/*************************************** + Group secureboot + ***************************************/ + +/* Functions */ +ets_emsa_pss_verify = 0x40000834; +ets_rsa_pss_verify = 0x40000838; +ets_ecdsa_verify = 0x4000083c; +ets_secure_boot_verify_bootloader_with_keys = 0x40000840; +ets_secure_boot_verify_signature = 0x40000844; +ets_secure_boot_read_key_digests = 0x40000848; +ets_secure_boot_revoke_public_key_digest = 0x4000084c; + + +/*************************************** + Group usb_device_uart + ***************************************/ + +/* Functions */ +usb_serial_device_rx_one_char = 0x400009c0; +usb_serial_device_rx_one_char_block = 0x400009c4; +usb_serial_device_tx_flush = 0x400009c8; +usb_serial_device_tx_one_char = 0x400009cc; diff --git a/tools/flasher_stub/ld/rom_32h2_beta_1.ld b/tools/flasher_stub/ld/rom_32h2_beta_1.ld new file mode 100644 index 0000000000..f05eed2127 --- /dev/null +++ b/tools/flasher_stub/ld/rom_32h2_beta_1.ld @@ -0,0 +1,731 @@ +/* ROM function interface esp32h2.rom.ld for esp32h2 + * + * + * Generated from ./interface-esp32b1z.yml md5sum a8cce65aa1422e5781ad0d729ef0a0a6 + * + * Compatible with ROM where ECO version equal or greater to 0. + * + * THIS FILE WAS AUTOMATICALLY GENERATED. DO NOT EDIT. + */ + + +PROVIDE ( SPIWrite = esp_rom_spiflash_write); +PROVIDE ( SPI_read_status_high = esp_rom_spiflash_read_statushigh); +PROVIDE ( SPI_write_status = esp_rom_spiflash_write_status); +PROVIDE ( SPIRead = esp_rom_spiflash_read); +PROVIDE ( SPIParamCfg = esp_rom_spiflash_config_param); +PROVIDE ( SPIEraseChip = esp_rom_spiflash_erase_chip); +PROVIDE ( SPIEraseSector = esp_rom_spiflash_erase_sector); +PROVIDE ( SPIEraseBlock = esp_rom_spiflash_erase_block); +PROVIDE ( SPI_Write_Encrypt_Enable = esp_rom_spiflash_write_encrypted_enable); +PROVIDE ( SPI_Write_Encrypt_Disable = esp_rom_spiflash_write_encrypted_disable); +PROVIDE ( SPI_Encrypt_Write = esp_rom_spiflash_write_encrypted); + + +/*************************************** + Group common + ***************************************/ + +/* Functions */ +rtc_get_reset_reason = 0x40000018; +analog_super_wdt_reset_happened = 0x4000001c; +jtag_cpu_reset_happened = 0x40000020; +rtc_get_wakeup_cause = 0x40000024; +rtc_select_apb_bridge = 0x40000028; +rtc_unhold_all_pads = 0x4000002c; +ets_is_print_boot = 0x40000030; +ets_printf = 0x40000034; +ets_install_putc1 = 0x40000038; +ets_install_uart_printf = 0x4000003c; +ets_install_putc2 = 0x40000040; +PROVIDE( ets_delay_us = 0x40000044 ); +ets_get_stack_info = 0x40000048; +ets_install_lock = 0x4000004c; +ets_backup_dma_copy = 0x40000050; +ets_apb_backup_init_lock_func = 0x40000054; +UartRxString = 0x40000058; +uart_tx_one_char = 0x4000005c; +uart_tx_one_char2 = 0x40000060; +uart_rx_one_char = 0x40000064; +uart_rx_one_char_block = 0x40000068; +uart_rx_readbuff = 0x4000006c; +uartAttach = 0x40000070; +uart_tx_flush = 0x40000074; +uart_tx_wait_idle = 0x40000078; +uart_div_modify = 0x4000007c; +multofup = 0x40000080; +software_reset = 0x40000084; +software_reset_cpu = 0x40000088; +assist_debug_clock_enable = 0x4000008c; +assist_debug_record_enable = 0x40000090; +clear_super_wdt_reset_flag = 0x40000094; +disable_default_watchdog = 0x40000098; +esp_rom_set_rtc_wake_addr = 0x4000009c; +esp_rom_get_rtc_wake_addr = 0x400000a0; +send_packet = 0x400000a4; +recv_packet = 0x400000a8; +GetUartDevice = 0x400000ac; +GetSecurityInfoProc = 0x400120b2; +UartDwnLdProc = 0x400000b0; +Uart_Init = 0x400000b4; +ets_set_user_start = 0x400000b8; +/* Data (.data, .bss, .rodata) */ +ets_rom_layout_p = 0x3ff1fffc; +ets_ops_table_ptr = 0x3fcdfffc; + + +/*************************************** + Group miniz + ***************************************/ + +/* Functions */ +mz_adler32 = 0x400000bc; +mz_crc32 = 0x400000c0; +mz_free = 0x400000c4; +tdefl_compress = 0x400000c8; +tdefl_compress_buffer = 0x400000cc; +tdefl_compress_mem_to_heap = 0x400000d0; +tdefl_compress_mem_to_mem = 0x400000d4; +tdefl_compress_mem_to_output = 0x400000d8; +tdefl_get_adler32 = 0x400000dc; +tdefl_get_prev_return_status = 0x400000e0; +tdefl_init = 0x400000e4; +tdefl_write_image_to_png_file_in_memory = 0x400000e8; +tdefl_write_image_to_png_file_in_memory_ex = 0x400000ec; +tinfl_decompress = 0x400000f0; +tinfl_decompress_mem_to_callback = 0x400000f4; +tinfl_decompress_mem_to_heap = 0x400000f8; +tinfl_decompress_mem_to_mem = 0x400000fc; + + +/*************************************** + Group tjpgd + ***************************************/ + +/* Functions */ +jd_prepare = 0x40000100; +jd_decomp = 0x40000104; + + +/*************************************** + Group esp-dsp + ***************************************/ + +/* Data (.data, .bss, .rodata) */ +dsps_fft2r_w_table_fc32_1024 = 0x3fcdfff8; + + +/*************************************** + Group spiflash_legacy + ***************************************/ + +/* Functions */ +PROVIDE( esp_rom_spiflash_wait_idle = 0x40000108 ); +PROVIDE( esp_rom_spiflash_write_encrypted = 0x4000010c ); +PROVIDE( esp_rom_spiflash_write_encrypted_dest = 0x40000110 ); +PROVIDE( esp_rom_spiflash_write_encrypted_enable = 0x40000114 ); +PROVIDE( esp_rom_spiflash_write_encrypted_disable = 0x40000118 ); +PROVIDE( esp_rom_spiflash_erase_chip = 0x4000011c ); +PROVIDE( esp_rom_spiflash_erase_block = 0x40000120 ); +PROVIDE( esp_rom_spiflash_erase_sector = 0x40000124 ); +PROVIDE( esp_rom_spiflash_write = 0x40000128 ); +PROVIDE( esp_rom_spiflash_read = 0x4000012c ); +PROVIDE( esp_rom_spiflash_config_param = 0x40000130 ); +PROVIDE( esp_rom_spiflash_read_user_cmd = 0x40000134 ); +PROVIDE( esp_rom_spiflash_select_qio_pins = 0x40000138 ); +PROVIDE( esp_rom_spiflash_unlock = 0x4000013c ); +PROVIDE( esp_rom_spi_flash_auto_sus_res = 0x40000140 ); +PROVIDE( esp_rom_spi_flash_send_resume = 0x40000144 ); +PROVIDE( esp_rom_spi_flash_update_id = 0x40000148 ); +PROVIDE( esp_rom_spiflash_config_clk = 0x4000014c ); +PROVIDE( esp_rom_spiflash_config_readmode = 0x40000150 ); +PROVIDE( esp_rom_spiflash_read_status = 0x40000154 ); +PROVIDE( esp_rom_spiflash_read_statushigh = 0x40000158 ); +PROVIDE( esp_rom_spiflash_write_status = 0x4000015c ); +PROVIDE( spi_flash_attach = 0x40000160 ); +PROVIDE( spi_flash_get_chip_size = 0x40000164 ); +PROVIDE( spi_flash_guard_set = 0x40000168 ); +PROVIDE( spi_flash_guard_get = 0x4000016c ); +PROVIDE( spi_flash_write_config_set = 0x40000170 ); +PROVIDE( spi_flash_write_config_get = 0x40000174 ); +PROVIDE( spi_flash_safe_write_address_func_set = 0x40000178 ); +PROVIDE( spi_flash_unlock = 0x4000017c ); +PROVIDE( spi_flash_erase_range = 0x40000180 ); +PROVIDE( spi_flash_erase_sector = 0x40000184 ); +PROVIDE( spi_flash_write = 0x40000188 ); +PROVIDE( spi_flash_read = 0x4000018c ); +PROVIDE( spi_flash_write_encrypted = 0x40000190 ); +PROVIDE( spi_flash_read_encrypted = 0x40000194 ); +PROVIDE( spi_flash_mmap_os_func_set = 0x40000198 ); +PROVIDE( spi_flash_mmap_page_num_init = 0x4000019c ); +PROVIDE( spi_flash_mmap = 0x400001a0 ); +PROVIDE( spi_flash_mmap_pages = 0x400001a4 ); +PROVIDE( spi_flash_munmap = 0x400001a8 ); +PROVIDE( spi_flash_mmap_dump = 0x400001ac ); +PROVIDE( spi_flash_check_and_flush_cache = 0x400001b0 ); +PROVIDE( spi_flash_mmap_get_free_pages = 0x400001b4 ); +PROVIDE( spi_flash_cache2phys = 0x400001b8 ); +PROVIDE( spi_flash_phys2cache = 0x400001bc ); +PROVIDE( spi_flash_disable_cache = 0x400001c0 ); +PROVIDE( spi_flash_restore_cache = 0x400001c4 ); +PROVIDE( spi_flash_cache_enabled = 0x400001c8 ); +PROVIDE( spi_flash_enable_cache = 0x400001cc ); +PROVIDE( spi_cache_mode_switch = 0x400001d0 ); +PROVIDE( spi_common_set_dummy_output = 0x400001d4 ); +PROVIDE( spi_common_set_flash_cs_timing = 0x400001d8 ); +PROVIDE( esp_enable_cache_flash_wrap = 0x400001dc ); +PROVIDE( SPIEraseArea = 0x400001e0 ); +PROVIDE( SPILock = 0x400001e4 ); +PROVIDE( SPIMasterReadModeCnfig = 0x400001e8 ); +PROVIDE( SPI_Common_Command = 0x400001ec ); +PROVIDE( SPI_WakeUp = 0x400001f0 ); +PROVIDE( SPI_block_erase = 0x400001f4 ); +PROVIDE( SPI_chip_erase = 0x400001f8 ); +PROVIDE( SPI_init = 0x400001fc ); +PROVIDE( SPI_page_program = 0x40000200 ); +PROVIDE( SPI_read_data = 0x40000204 ); +PROVIDE( SPI_sector_erase = 0x40000208 ); +PROVIDE( SPI_write_enable = 0x4000020c ); +PROVIDE( SelectSpiFunction = 0x40000210 ); +PROVIDE( SetSpiDrvs = 0x40000214 ); +PROVIDE( Wait_SPI_Idle = 0x40000218 ); +PROVIDE( spi_dummy_len_fix = 0x4000021c ); +PROVIDE( Disable_QMode = 0x40000220 ); +PROVIDE( Enable_QMode = 0x40000224 ); +/* Data (.data, .bss, .rodata) */ +PROVIDE( rom_spiflash_legacy_funcs = 0x3fcdfff0 ); +PROVIDE( rom_spiflash_legacy_data = 0x3fcdffec ); +PROVIDE( g_flash_guard_ops = 0x3fcdfff4 ); + + +/*************************************** + Group hal_soc + ***************************************/ + +/* Functions */ +PROVIDE( spi_flash_hal_poll_cmd_done = 0x40000228 ); +PROVIDE( spi_flash_hal_device_config = 0x4000022c ); +PROVIDE( spi_flash_hal_configure_host_io_mode = 0x40000230 ); +PROVIDE( spi_flash_hal_common_command = 0x40000234 ); +PROVIDE( spi_flash_hal_read = 0x40000238 ); +PROVIDE( spi_flash_hal_erase_chip = 0x4000023c ); +PROVIDE( spi_flash_hal_erase_sector = 0x40000240 ); +PROVIDE( spi_flash_hal_erase_block = 0x40000244 ); +PROVIDE( spi_flash_hal_program_page = 0x40000248 ); +PROVIDE( spi_flash_hal_set_write_protect = 0x4000024c ); +PROVIDE( spi_flash_hal_host_idle = 0x40000250 ); + + +/*************************************** + Group spi_flash_chips + ***************************************/ + +/* Functions */ +PROVIDE( spi_flash_chip_generic_probe = 0x40000254 ); +PROVIDE( spi_flash_chip_generic_detect_size = 0x40000258 ); +PROVIDE( spi_flash_chip_generic_write = 0x4000025c ); +PROVIDE( spi_flash_chip_generic_write_encrypted = 0x40000260 ); +PROVIDE( spi_flash_chip_generic_set_write_protect = 0x40000264 ); +PROVIDE( spi_flash_common_write_status_16b_wrsr = 0x40000268 ); +PROVIDE( spi_flash_chip_generic_reset = 0x4000026c ); +PROVIDE( spi_flash_chip_generic_erase_chip = 0x40000270 ); +PROVIDE( spi_flash_chip_generic_erase_sector = 0x40000274 ); +PROVIDE( spi_flash_chip_generic_erase_block = 0x40000278 ); +PROVIDE( spi_flash_chip_generic_page_program = 0x4000027c ); +PROVIDE( spi_flash_chip_generic_get_write_protect = 0x40000280 ); +PROVIDE( spi_flash_common_read_status_16b_rdsr_rdsr2 = 0x40000284 ); +PROVIDE( spi_flash_chip_generic_read_reg = 0x40000288 ); +PROVIDE( spi_flash_chip_generic_yield = 0x4000028c ); +PROVIDE( spi_flash_generic_wait_host_idle = 0x40000290 ); +PROVIDE( spi_flash_chip_generic_wait_idle = 0x40000294 ); +PROVIDE( spi_flash_chip_generic_config_host_io_mode = 0x40000298 ); +PROVIDE( spi_flash_chip_generic_read = 0x4000029c ); +PROVIDE( spi_flash_common_read_status_8b_rdsr2 = 0x400002a0 ); +PROVIDE( spi_flash_chip_generic_get_io_mode = 0x400002a4 ); +PROVIDE( spi_flash_common_read_status_8b_rdsr = 0x400002a8 ); +PROVIDE( spi_flash_common_write_status_8b_wrsr = 0x400002ac ); +PROVIDE( spi_flash_common_write_status_8b_wrsr2 = 0x400002b0 ); +PROVIDE( spi_flash_common_set_io_mode = 0x400002b4 ); +PROVIDE( spi_flash_chip_generic_set_io_mode = 0x400002b8 ); +PROVIDE( spi_flash_chip_gd_get_io_mode = 0x400002bc ); +PROVIDE( spi_flash_chip_gd_probe = 0x400002c0 ); +PROVIDE( spi_flash_chip_gd_set_io_mode = 0x400002c4 ); +/* Data (.data, .bss, .rodata) */ +PROVIDE( spi_flash_chip_generic_config_data = 0x3fcdffe8 ); + + +/*************************************** + Group memspi_host + ***************************************/ + +/* Functions */ +PROVIDE( memspi_host_read_id_hs = 0x400002c8 ); +PROVIDE( memspi_host_read_status_hs = 0x400002cc ); +PROVIDE( memspi_host_flush_cache = 0x400002d0 ); +PROVIDE( memspi_host_erase_chip = 0x400002d4 ); +PROVIDE( memspi_host_erase_sector = 0x400002d8 ); +PROVIDE( memspi_host_erase_block = 0x400002dc ); +PROVIDE( memspi_host_program_page = 0x400002e0 ); +PROVIDE( memspi_host_read = 0x400002e4 ); +PROVIDE( memspi_host_set_write_protect = 0x400002e8 ); +PROVIDE( memspi_host_set_max_read_len = 0x400002ec ); +PROVIDE( memspi_host_read_data_slicer = 0x400002f0 ); +PROVIDE( memspi_host_write_data_slicer = 0x400002f4 ); + + +/*************************************** + Group esp_flash + ***************************************/ + +/* Functions */ +PROVIDE( esp_flash_chip_driver_initialized = 0x400002f8 ); +PROVIDE( esp_flash_read_id = 0x400002fc ); +PROVIDE( esp_flash_get_size = 0x40000300 ); +PROVIDE( esp_flash_erase_chip = 0x40000304 ); +PROVIDE( esp_flash_erase_region = 0x40000308 ); +PROVIDE( esp_flash_get_chip_write_protect = 0x4000030c ); +PROVIDE( esp_flash_set_chip_write_protect = 0x40000310 ); +PROVIDE( esp_flash_get_protectable_regions = 0x40000314 ); +PROVIDE( esp_flash_get_protected_region = 0x40000318 ); +PROVIDE( esp_flash_set_protected_region = 0x4000031c ); +PROVIDE( esp_flash_read = 0x40000320 ); +PROVIDE( esp_flash_write = 0x40000324 ); +PROVIDE( esp_flash_write_encrypted = 0x40000328 ); +PROVIDE( esp_flash_read_encrypted = 0x4000032c ); +PROVIDE( esp_flash_get_io_mode = 0x40000330 ); +PROVIDE( esp_flash_set_io_mode = 0x40000334 ); +PROVIDE( spi_flash_boot_attach = 0x40000338 ); +PROVIDE( spi_flash_dump_counters = 0x4000033c ); +PROVIDE( spi_flash_get_counters = 0x40000340 ); +PROVIDE( spi_flash_op_counters_config = 0x40000344 ); +PROVIDE( spi_flash_reset_counters = 0x40000348 ); +PROVIDE( esp_flash_read_chip_id = 0x4000034c ); +PROVIDE( detect_spi_flash_chip = 0x40000350 ); +PROVIDE( esp_rom_spiflash_write_disable = 0x40000354 ); +/* Data (.data, .bss, .rodata) */ +PROVIDE( esp_flash_default_chip = 0x3fcdffe4 ); +PROVIDE( esp_flash_api_funcs = 0x3fcdffe0 ); + + +/*************************************** + Group cache + ***************************************/ + +/* Functions */ +PROVIDE( Cache_Get_ICache_Line_Size = 0x400004b8 ); +PROVIDE( Cache_Get_Mode = 0x400004bc ); +PROVIDE( Cache_Address_Through_IBus = 0x400004c0 ); +PROVIDE( Cache_Address_Through_DBus = 0x400004c4 ); +PROVIDE( Cache_Set_Default_Mode = 0x400004c8 ); +PROVIDE( Cache_Enable_Defalut_ICache_Mode = 0x400004cc ); +PROVIDE( ROM_Boot_Cache_Init = 0x400004d0 ); +PROVIDE( Cache_Invalidate_ICache_Items = 0x400004d4 ); +PROVIDE( Cache_Op_Addr = 0x400004d8 ); +PROVIDE( Cache_Invalidate_Addr = 0x400004dc ); +PROVIDE( Cache_Invalidate_ICache_All = 0x400004e0 ); +PROVIDE( Cache_Mask_All = 0x400004e4 ); +PROVIDE( Cache_UnMask_Dram0 = 0x400004e8 ); +PROVIDE( Cache_Suspend_ICache_Autoload = 0x400004ec ); +PROVIDE( Cache_Resume_ICache_Autoload = 0x400004f0 ); +PROVIDE( Cache_Start_ICache_Preload = 0x400004f4 ); +PROVIDE( Cache_ICache_Preload_Done = 0x400004f8 ); +PROVIDE( Cache_End_ICache_Preload = 0x400004fc ); +PROVIDE( Cache_Config_ICache_Autoload = 0x40000500 ); +PROVIDE( Cache_Enable_ICache_Autoload = 0x40000504 ); +PROVIDE( Cache_Disable_ICache_Autoload = 0x40000508 ); +PROVIDE( Cache_Enable_ICache_PreLock = 0x4000050c ); +PROVIDE( Cache_Disable_ICache_PreLock = 0x40000510 ); +PROVIDE( Cache_Lock_ICache_Items = 0x40000514 ); +PROVIDE( Cache_Unlock_ICache_Items = 0x40000518 ); +PROVIDE( Cache_Lock_Addr = 0x4000051c ); +PROVIDE( Cache_Unlock_Addr = 0x40000520 ); +PROVIDE( Cache_Disable_ICache = 0x40000524 ); +PROVIDE( Cache_Enable_ICache = 0x40000528 ); +PROVIDE( Cache_Suspend_ICache = 0x4000052c ); +PROVIDE( Cache_Resume_ICache = 0x40000530 ); +PROVIDE( Cache_Freeze_ICache_Enable = 0x40000534 ); +PROVIDE( Cache_Freeze_ICache_Disable = 0x40000538 ); +PROVIDE( Cache_Pms_Lock = 0x4000053c ); +PROVIDE( Cache_Ibus_Pms_Set_Addr = 0x40000540 ); +PROVIDE( Cache_Ibus_Pms_Set_Attr = 0x40000544 ); +PROVIDE( Cache_Dbus_Pms_Set_Addr = 0x40000548 ); +PROVIDE( Cache_Dbus_Pms_Set_Attr = 0x4000054c ); +PROVIDE( Cache_Set_IDROM_MMU_Size = 0x40000550 ); +PROVIDE( Cache_Get_IROM_MMU_End = 0x40000554 ); +PROVIDE( Cache_Get_DROM_MMU_End = 0x40000558 ); +PROVIDE( Cache_Owner_Init = 0x4000055c ); +PROVIDE( Cache_Occupy_ICache_MEMORY = 0x40000560 ); +PROVIDE( Cache_MMU_Init = 0x40000564 ); +PROVIDE( Cache_Ibus_MMU_Set = 0x40000568 ); +PROVIDE( Cache_Dbus_MMU_Set = 0x4000056c ); +PROVIDE( Cache_Count_Flash_Pages = 0x40000570 ); +PROVIDE( Cache_Travel_Tag_Memory = 0x40000574 ); +PROVIDE( Cache_Get_Virtual_Addr = 0x40000578 ); +PROVIDE( Cache_Get_Memory_BaseAddr = 0x4000057c ); +PROVIDE( Cache_Get_Memory_Addr = 0x40000580 ); +PROVIDE( Cache_Get_Memory_value = 0x40000584 ); +/* Data (.data, .bss, .rodata) */ +PROVIDE( rom_cache_op_cb = 0x3fcdffd4 ); +PROVIDE( rom_cache_internal_table_ptr = 0x3fcdffd0 ); + + +/*************************************** + Group clock + ***************************************/ + +/* Functions */ +ets_get_apb_freq = 0x40000588; +ets_get_cpu_frequency = 0x4000058c; +ets_update_cpu_frequency = 0x40000590; +ets_get_printf_channel = 0x40000594; +ets_get_xtal_div = 0x40000598; +ets_set_xtal_div = 0x4000059c; +ets_get_xtal_freq = 0x400005a0; + + +/*************************************** + Group gpio + ***************************************/ + +/* Functions */ +gpio_input_get = 0x400005a4; +gpio_matrix_in = 0x400005a8; +gpio_matrix_out = 0x400005ac; +gpio_output_disable = 0x400005b0; +gpio_output_enable = 0x400005b4; +gpio_output_set = 0x400005b8; +gpio_pad_hold = 0x400005bc; +gpio_pad_input_disable = 0x400005c0; +gpio_pad_input_enable = 0x400005c4; +gpio_pad_pulldown = 0x400005c8; +gpio_pad_pullup = 0x400005cc; +gpio_pad_select_gpio = 0x400005d0; +gpio_pad_set_drv = 0x400005d4; +gpio_pad_unhold = 0x400005d8; +gpio_pin_wakeup_disable = 0x400005dc; +gpio_pin_wakeup_enable = 0x400005e0; +gpio_bypass_matrix_in = 0x400005e4; + + +/*************************************** + Group interrupts + ***************************************/ + +/* Functions */ +esprv_intc_int_set_priority = 0x400005e8; +esprv_intc_int_set_threshold = 0x400005ec; +esprv_intc_int_enable = 0x400005f0; +esprv_intc_int_disable = 0x400005f4; +esprv_intc_int_set_type = 0x400005f8; +intr_matrix_set = 0x400005fc; +ets_intr_lock = 0x40000600; +ets_intr_unlock = 0x40000604; +PROVIDE( intr_handler_set = 0x40000608 ); +ets_isr_attach = 0x4000060c; +ets_isr_mask = 0x40000610; +ets_isr_unmask = 0x40000614; + + +/*************************************** + Group crypto + ***************************************/ + +/* Functions */ +md5_vector = 0x40000618; +MD5Init = 0x4000061c; +MD5Update = 0x40000620; +MD5Final = 0x40000624; +hmac_md5_vector = 0x40000628; +hmac_md5 = 0x4000062c; +crc32_le = 0x40000630; +crc32_be = 0x40000634; +crc16_le = 0x40000638; +crc16_be = 0x4000063c; +crc8_le = 0x40000640; +crc8_be = 0x40000644; +esp_crc8 = 0x40000648; +ets_sha_enable = 0x4000064c; +ets_sha_disable = 0x40000650; +ets_sha_get_state = 0x40000654; +ets_sha_init = 0x40000658; +ets_sha_process = 0x4000065c; +ets_sha_starts = 0x40000660; +ets_sha_update = 0x40000664; +ets_sha_finish = 0x40000668; +ets_sha_clone = 0x4000066c; +ets_hmac_enable = 0x40000670; +ets_hmac_disable = 0x40000674; +ets_hmac_calculate_message = 0x40000678; +ets_hmac_calculate_downstream = 0x4000067c; +ets_hmac_invalidate_downstream = 0x40000680; +ets_jtag_enable_temporarily = 0x40000684; +ets_aes_enable = 0x40000688; +ets_aes_disable = 0x4000068c; +ets_aes_setkey = 0x40000690; +ets_aes_block = 0x40000694; +ets_bigint_enable = 0x40000698; +ets_bigint_disable = 0x4000069c; +ets_bigint_multiply = 0x400006a0; +ets_bigint_modmult = 0x400006a4; +ets_bigint_modexp = 0x400006a8; +ets_bigint_wait_finish = 0x400006ac; +ets_bigint_getz = 0x400006b0; +ets_ds_enable = 0x400006b4; +ets_ds_disable = 0x400006b8; +ets_ds_start_sign = 0x400006bc; +ets_ds_is_busy = 0x400006c0; +ets_ds_finish_sign = 0x400006c4; +ets_ds_encrypt_params = 0x400006c8; +ets_aes_setkey_dec = 0x400006cc; +ets_aes_setkey_enc = 0x400006d0; +ets_mgf1_sha256 = 0x400006d4; + + +/*************************************** + Group efuse + ***************************************/ + +/* Functions */ +ets_efuse_read = 0x400006d8; +ets_efuse_program = 0x400006dc; +ets_efuse_clear_program_registers = 0x400006e0; +ets_efuse_write_key = 0x400006e4; +ets_efuse_get_read_register_address = 0x400006e8; +ets_efuse_get_key_purpose = 0x400006ec; +ets_efuse_key_block_unused = 0x400006f0; +ets_efuse_find_unused_key_block = 0x400006f4; +ets_efuse_rs_calculate = 0x400006f8; +ets_efuse_count_unused_key_blocks = 0x400006fc; +ets_efuse_secure_boot_enabled = 0x40000700; +ets_efuse_secure_boot_aggressive_revoke_enabled = 0x40000704; +ets_efuse_cache_encryption_enabled = 0x40000708; +ets_efuse_download_modes_disabled = 0x4000070c; +ets_efuse_find_purpose = 0x40000710; +ets_efuse_flash_opi_5pads_power_sel_vddspi = 0x40000714; +ets_efuse_force_send_resume = 0x40000718; +ets_efuse_get_flash_delay_us = 0x4000071c; +ets_efuse_get_mac = 0x40000720; +ets_efuse_get_spiconfig = 0x40000724; +ets_efuse_usb_print_is_disabled = 0x40000728; +ets_efuse_get_uart_print_channel = 0x4000072c; +ets_efuse_get_uart_print_control = 0x40000730; +ets_efuse_get_wp_pad = 0x40000734; +ets_efuse_direct_boot_mode_disabled = 0x40000738; +ets_efuse_security_download_modes_enabled = 0x4000073c; +ets_efuse_set_timing = 0x40000740; +ets_efuse_jtag_disabled = 0x40000744; +ets_efuse_usb_download_mode_disabled = 0x40000748; +ets_efuse_usb_module_disabled = 0x4000074c; +ets_efuse_usb_device_disabled = 0x40000750; +ets_efuse_secure_boot_fast_wake_enabled = 0x40000754; + + +/*************************************** + Group secureboot + ***************************************/ + +/* Functions */ +ets_emsa_pss_verify = 0x40000758; +ets_rsa_pss_verify = 0x4000075c; +ets_secure_boot_verify_bootloader_with_keys = 0x40000760; +ets_secure_boot_verify_signature = 0x40000764; +ets_secure_boot_read_key_digests = 0x40000768; +ets_secure_boot_revoke_public_key_digest = 0x4000076c; + + +/*************************************** + Group usb_uart + ***************************************/ + +/* Functions */ +PROVIDE( usb_uart_device_rx_one_char = 0x400008d8 ); +PROVIDE( usb_uart_device_rx_one_char_block = 0x400008dc ); +PROVIDE( usb_uart_device_tx_flush = 0x400008e0 ); +PROVIDE( usb_uart_device_tx_one_char = 0x400008e4 ); +/* Data (.data, .bss, .rodata) */ +PROVIDE( g_uart_print = 0x3fcdffcd ); +PROVIDE( g_usb_print = 0x3fcdffcc ); + + +/*************************************** + Group rom_phy + ***************************************/ + +/* Functions */ +phy_get_romfuncs = 0x400008e8; +rom_abs_temp = 0x400008ec; +rom_bb_bss_cbw40_dig = 0x400008f0; +rom_bb_wdg_test_en = 0x400008f4; +rom_bb_wdt_get_status = 0x400008f8; +rom_bb_wdt_int_enable = 0x400008fc; +rom_bb_wdt_rst_enable = 0x40000900; +rom_bb_wdt_timeout_clear = 0x40000904; +rom_cbw2040_cfg = 0x40000908; +rom_check_noise_floor = 0x4000090c; +rom_chip_i2c_readReg = 0x40000910; +rom_chip_i2c_writeReg = 0x40000914; +rom_correct_rf_ana_gain = 0x40000918; +rom_dc_iq_est = 0x4000091c; +rom_disable_agc = 0x40000920; +rom_en_pwdet = 0x40000924; +rom_enable_agc = 0x40000928; +rom_get_bbgain_db = 0x4000092c; +rom_get_data_sat = 0x40000930; +rom_get_i2c_read_mask = 0x40000934; +rom_get_pwctrl_correct = 0x40000938; +rom_get_rf_gain_qdb = 0x4000093c; +rom_i2c_readReg = 0x40000940; +rom_i2c_readReg_Mask = 0x40000944; +rom_i2c_writeReg = 0x40000948; +rom_i2c_writeReg_Mask = 0x4000094c; +rom_index_to_txbbgain = 0x40000950; +rom_iq_est_disable = 0x40000954; +rom_iq_est_enable = 0x40000958; +rom_linear_to_db = 0x4000095c; +rom_loopback_mode_en = 0x40000960; +rom_mhz2ieee = 0x40000964; +rom_noise_floor_auto_set = 0x40000968; +rom_pbus_debugmode = 0x4000096c; +rom_pbus_force_mode = 0x40000970; +rom_pbus_force_test = 0x40000974; +rom_pbus_rd = 0x40000978; +rom_pbus_rd_addr = 0x4000097c; +rom_pbus_rd_shift = 0x40000980; +rom_pbus_set_dco = 0x40000984; +rom_pbus_set_rxgain = 0x40000988; +rom_pbus_workmode = 0x4000098c; +rom_pbus_xpd_rx_off = 0x40000990; +rom_pbus_xpd_rx_on = 0x40000994; +rom_pbus_xpd_tx_off = 0x40000998; +rom_pbus_xpd_tx_on = 0x4000099c; +rom_phy_byte_to_word = 0x400009a0; +rom_phy_disable_cca = 0x400009a4; +rom_phy_enable_cca = 0x400009a8; +rom_phy_get_noisefloor = 0x400009ac; +rom_phy_get_rx_freq = 0x400009b0; +rom_phy_set_bbfreq_init = 0x400009b4; +rom_pow_usr = 0x400009b8; +rom_pwdet_sar2_init = 0x400009bc; +rom_read_hw_noisefloor = 0x400009c0; +rom_read_sar_dout = 0x400009c4; +rom_set_cal_rxdc = 0x400009c8; +rom_set_chan_cal_interp = 0x400009cc; +rom_set_loopback_gain = 0x400009d0; +rom_set_noise_floor = 0x400009d4; +rom_set_rxclk_en = 0x400009d8; +rom_set_tx_dig_gain = 0x400009dc; +rom_set_txcap_reg = 0x400009e0; +rom_set_txclk_en = 0x400009e4; +rom_spur_cal = 0x400009e8; +rom_spur_reg_write_one_tone = 0x400009ec; +rom_target_power_add_backoff = 0x400009f0; +rom_tx_pwctrl_bg_init = 0x400009f4; +rom_txbbgain_to_index = 0x400009f8; +rom_wifi_11g_rate_chg = 0x400009fc; +rom_write_gain_mem = 0x40000a00; +chip726_phyrom_version = 0x40000a04; +rom_disable_wifi_agc = 0x40000a08; +rom_enable_wifi_agc = 0x40000a0c; +rom_set_tx_gain_table = 0x40000a10; +rom_bt_index_to_bb = 0x40000a14; +rom_bt_bb_to_index = 0x40000a18; +rom_wr_bt_tx_atten = 0x40000a1c; +rom_wr_bt_tx_gain_mem = 0x40000a20; +rom_spur_coef_cfg = 0x40000a24; +rom_bb_bss_cbw40 = 0x40000a28; +rom_set_cca = 0x40000a2c; +rom_tx_paon_set = 0x40000a30; +rom_i2cmst_reg_init = 0x40000a34; +rom_iq_corr_enable = 0x40000a38; +rom_fe_reg_init = 0x40000a3c; +rom_agc_reg_init = 0x40000a40; +rom_bb_reg_init = 0x40000a44; +rom_mac_enable_bb = 0x40000a48; +rom_bb_wdg_cfg = 0x40000a4c; +rom_force_txon = 0x40000a50; +rom_fe_txrx_reset = 0x40000a54; +rom_set_rx_comp = 0x40000a58; +rom_set_pbus_reg = 0x40000a5c; +rom_write_chan_freq = 0x40000a60; +rom_phy_xpd_rf = 0x40000a64; +rom_set_xpd_sar = 0x40000a68; +rom_write_dac_gain2 = 0x40000a6c; +rom_rtc_sar2_init = 0x40000a70; +rom_get_target_power_offset = 0x40000a74; +rom_write_txrate_power_offset = 0x40000a78; +rom_get_rate_fcc_index = 0x40000a7c; +rom_get_rate_target_power = 0x40000a80; +rom_write_wifi_dig_gain = 0x40000a84; +rom_bt_correct_rf_ana_gain = 0x40000a88; +rom_pkdet_vol_start = 0x40000a8c; +rom_read_sar2_code = 0x40000a90; +rom_get_sar2_vol = 0x40000a94; +rom_get_pll_vol = 0x40000a98; +rom_get_phy_target_power = 0x40000a9c; +rom_temp_to_power = 0x40000aa0; +rom_phy_track_pll_cap = 0x40000aa4; +rom_phy_pwdet_always_en = 0x40000aa8; +rom_phy_pwdet_onetime_en = 0x40000aac; +rom_get_i2c_mst0_mask = 0x40000ab0; +rom_get_i2c_hostid = 0x40000ab4; +rom_enter_critical_phy = 0x40000ab8; +rom_exit_critical_phy = 0x40000abc; +rom_chip_i2c_readReg_org = 0x40000ac0; +rom_i2c_paral_set_mst0 = 0x40000ac4; +rom_i2c_paral_set_read = 0x40000ac8; +rom_i2c_paral_read = 0x40000acc; +rom_i2c_paral_write = 0x40000ad0; +rom_i2c_paral_write_num = 0x40000ad4; +rom_i2c_paral_write_mask = 0x40000ad8; +rom_bb_bss_cbw40_ana = 0x40000adc; +rom_chan_to_freq = 0x40000ae0; +rom_open_i2c_xpd = 0x40000ae4; +rom_dac_rate_set = 0x40000ae8; +rom_tsens_read_init = 0x40000aec; +rom_tsens_code_read = 0x40000af0; +rom_tsens_index_to_dac = 0x40000af4; +rom_tsens_index_to_offset = 0x40000af8; +rom_tsens_dac_cal = 0x40000afc; +rom_code_to_temp = 0x40000b00; +rom_write_pll_cap_mem = 0x40000b04; +rom_pll_correct_dcap = 0x40000b08; +rom_phy_en_hw_set_freq = 0x40000b0c; +rom_phy_dis_hw_set_freq = 0x40000b10; +rom_pll_vol_cal = 0x40000b14; +rom_wrtie_pll_cap = 0x40000b18; +rom_set_tx_gain_mem = 0x40000b1c; +rom_bt_tx_dig_gain = 0x40000b20; +rom_bt_get_tx_gain = 0x40000b24; +rom_get_chan_target_power = 0x40000b28; +rom_get_tx_gain_value = 0x40000b2c; +rom_wifi_tx_dig_gain = 0x40000b30; +rom_wifi_get_tx_gain = 0x40000b34; +rom_fe_i2c_reg_renew = 0x40000b38; +rom_wifi_agc_sat_gain = 0x40000b3c; +rom_i2c_master_reset = 0x40000b40; +rom_bt_filter_reg = 0x40000b44; +rom_phy_bbpll_cal = 0x40000b48; +rom_i2c_sar2_init_code = 0x40000b4c; +rom_phy_param_addr = 0x40000b50; +rom_phy_reg_init = 0x40000b54; +rom_set_chan_reg = 0x40000b58; +rom_phy_wakeup_init = 0x40000b5c; +rom_phy_i2c_init1 = 0x40000b60; +rom_tsens_temp_read = 0x40000b64; +rom_bt_track_pll_cap = 0x40000b68; +rom_wifi_track_pll_cap = 0x40000b6c; +rom_wifi_set_tx_gain = 0x40000b70; +rom_txpwr_cal_track = 0x40000b74; +rom_tx_pwctrl_background = 0x40000b78; +rom_bt_set_tx_gain = 0x40000b7c; +rom_noise_check_loop = 0x40000b80; +rom_phy_close_rf = 0x40000b84; +rom_phy_xpd_tsens = 0x40000b88; +rom_phy_freq_mem_backup = 0x40000b8c; +rom_phy_ant_init = 0x40000b90; +rom_bt_track_tx_power = 0x40000b94; +rom_wifi_track_tx_power = 0x40000b98; +rom_phy_dig_reg_backup = 0x40000b9c; +chip726_phyrom_version_num = 0x40000ba0; +/* Data (.data, .bss, .rodata) */ +phy_param_rom = 0x3fcdffc8; diff --git a/tools/flasher_stub/ld/rom_32h2_beta_2.ld b/tools/flasher_stub/ld/rom_32h2_beta_2.ld new file mode 100644 index 0000000000..81d8df7a12 --- /dev/null +++ b/tools/flasher_stub/ld/rom_32h2_beta_2.ld @@ -0,0 +1,1714 @@ +/* ROM function interface esp32h2.rom.ld for esp32h2 + * + * + * Generated from ./target/esp32h2/interface-esp32h2.yml md5sum da4c474a48c097d4ac9acad67f70fda6 + * + * Compatible with ROM where ECO version equal or greater to 0. + * + * THIS FILE WAS AUTOMATICALLY GENERATED. DO NOT EDIT. + */ + + +PROVIDE ( SPIWrite = esp_rom_spiflash_write); +PROVIDE ( SPI_read_status_high = esp_rom_spiflash_read_statushigh); +PROVIDE ( SPI_write_status = esp_rom_spiflash_write_status); +PROVIDE ( SPIRead = esp_rom_spiflash_read); +PROVIDE ( SPIParamCfg = esp_rom_spiflash_config_param); +PROVIDE ( SPIEraseChip = esp_rom_spiflash_erase_chip); +PROVIDE ( SPIEraseSector = esp_rom_spiflash_erase_sector); +PROVIDE ( SPIEraseBlock = esp_rom_spiflash_erase_block); +PROVIDE ( SPI_Write_Encrypt_Enable = esp_rom_spiflash_write_encrypted_enable); +PROVIDE ( SPI_Write_Encrypt_Disable = esp_rom_spiflash_write_encrypted_disable); +PROVIDE ( SPI_Encrypt_Write = esp_rom_spiflash_write_encrypted); + + + +/*************************************** + Group common + ***************************************/ + +/* Functions */ +rtc_get_reset_reason = 0x40000018; +analog_super_wdt_reset_happened = 0x4000001c; +rtc_get_wakeup_cause = 0x40000020; +rtc_select_apb_bridge = 0x40000024; +rtc_unhold_all_pads = 0x40000028; +ets_is_print_boot = 0x4000002c; +ets_printf = 0x40000030; +ets_install_putc1 = 0x40000034; +ets_install_uart_printf = 0x40000038; +ets_install_putc2 = 0x4000003c; +PROVIDE( ets_delay_us = 0x40000040 ); +ets_install_lock = 0x40000044; +ets_backup_dma_copy = 0x40000048; +ets_apb_backup_init_lock_func = 0x4000004c; +UartRxString = 0x40000050; +UartGetCmdLn = 0x40000054; +uart_tx_one_char = 0x40000058; +uart_tx_one_char2 = 0x4000005c; +uart_rx_one_char = 0x40000060; +uart_rx_one_char_block = 0x40000064; +uart_rx_readbuff = 0x40000068; +uartAttach = 0x4000006c; +uart_tx_flush = 0x40000070; +uart_tx_wait_idle = 0x40000074; +uart_div_modify = 0x40000078; +ets_write_char_uart = 0x4000007c; +uart_tx_switch = 0x40000080; +multofup = 0x40000084; +software_reset = 0x40000088; +software_reset_cpu = 0x4000008c; +assist_debug_clock_enable = 0x40000090; +assist_debug_record_enable = 0x40000094; +clear_super_wdt_reset_flag = 0x40000098; +disable_default_watchdog = 0x4000009c; +esp_rom_set_rtc_wake_addr = 0x400000a0; +esp_rom_get_rtc_wake_addr = 0x400000a4; +send_packet = 0x400000a8; +recv_packet = 0x400000ac; +GetUartDevice = 0x400000b0; +UartDwnLdProc = 0x400000b4; +GetSecurityInfoProc = 0x400000b8; +Uart_Init = 0x400000bc; +ets_set_user_start = 0x400000c0; +/* Data (.data, .bss, .rodata) */ +ets_rom_layout_p = 0x3ff1fffc; +ets_ops_table_ptr = 0x3fcdfff8; +g_uart_print = 0x3fcdfffd; +g_usb_print = 0x3fcdfffc; + + +/*************************************** + Group miniz + ***************************************/ + +/* Functions */ +mz_adler32 = 0x400000c4; +mz_free = 0x400000c8; +tdefl_compress = 0x400000cc; +tdefl_compress_buffer = 0x400000d0; +tdefl_compress_mem_to_heap = 0x400000d4; +tdefl_compress_mem_to_mem = 0x400000d8; +tdefl_compress_mem_to_output = 0x400000dc; +tdefl_get_adler32 = 0x400000e0; +tdefl_get_prev_return_status = 0x400000e4; +tdefl_init = 0x400000e8; +tdefl_write_image_to_png_file_in_memory = 0x400000ec; +tdefl_write_image_to_png_file_in_memory_ex = 0x400000f0; +tinfl_decompress = 0x400000f4; +tinfl_decompress_mem_to_callback = 0x400000f8; +tinfl_decompress_mem_to_heap = 0x400000fc; +tinfl_decompress_mem_to_mem = 0x40000100; + + +/*************************************** + Group tjpgd + ***************************************/ + +/* Functions */ +jd_prepare = 0x40000104; +jd_decomp = 0x40000108; + + +/*************************************** + Group spiflash_legacy + ***************************************/ + +/* Functions */ +PROVIDE( esp_rom_spiflash_wait_idle = 0x4000010c ); +PROVIDE( esp_rom_spiflash_write_encrypted = 0x40000110 ); +PROVIDE( esp_rom_spiflash_write_encrypted_dest = 0x40000114 ); +PROVIDE( esp_rom_spiflash_write_encrypted_enable = 0x40000118 ); +PROVIDE( esp_rom_spiflash_write_encrypted_disable = 0x4000011c ); +PROVIDE( esp_rom_spiflash_erase_chip = 0x40000120 ); +PROVIDE( _esp_rom_spiflash_erase_sector = 0x40000124 ); +PROVIDE( _esp_rom_spiflash_erase_block = 0x40000128 ); +PROVIDE( _esp_rom_spiflash_write = 0x4000012c ); +PROVIDE( _esp_rom_spiflash_read = 0x40000130 ); +PROVIDE( _esp_rom_spiflash_unlock = 0x40000134 ); +PROVIDE( _SPIEraseArea = 0x40000138 ); +PROVIDE( _SPI_write_enable = 0x4000013c ); +PROVIDE( esp_rom_spiflash_erase_sector = 0x40000140 ); +PROVIDE( esp_rom_spiflash_erase_block = 0x40000144 ); +PROVIDE( esp_rom_spiflash_write = 0x40000148 ); +PROVIDE( esp_rom_spiflash_read = 0x4000014c ); +PROVIDE( esp_rom_spiflash_unlock = 0x40000150 ); +PROVIDE( SPIEraseArea = 0x40000154 ); +PROVIDE( SPI_write_enable = 0x40000158 ); +PROVIDE( esp_rom_spiflash_config_param = 0x4000015c ); +PROVIDE( esp_rom_spiflash_read_user_cmd = 0x40000160 ); +PROVIDE( esp_rom_spiflash_select_qio_pins = 0x40000164 ); +PROVIDE( esp_rom_spi_flash_auto_sus_res = 0x40000168 ); +PROVIDE( esp_rom_spi_flash_send_resume = 0x4000016c ); +PROVIDE( esp_rom_spi_flash_update_id = 0x40000170 ); +PROVIDE( esp_rom_spiflash_config_clk = 0x40000174 ); +PROVIDE( esp_rom_spiflash_config_readmode = 0x40000178 ); +PROVIDE( esp_rom_spiflash_read_status = 0x4000017c ); +PROVIDE( esp_rom_spiflash_read_statushigh = 0x40000180 ); +PROVIDE( esp_rom_spiflash_write_status = 0x40000184 ); +PROVIDE( spi_flash_attach = 0x40000188 ); +PROVIDE( spi_flash_get_chip_size = 0x4000018c ); +PROVIDE( spi_flash_guard_set = 0x40000190 ); +PROVIDE( spi_flash_guard_get = 0x40000194 ); +PROVIDE( spi_flash_read_encrypted = 0x40000198 ); +PROVIDE( spi_flash_mmap_os_func_set = 0x4000019c ); +PROVIDE( spi_flash_mmap_page_num_init = 0x400001a0 ); +PROVIDE( spi_flash_mmap = 0x400001a4 ); +PROVIDE( spi_flash_mmap_pages = 0x400001a8 ); +PROVIDE( spi_flash_munmap = 0x400001ac ); +PROVIDE( spi_flash_mmap_dump = 0x400001b0 ); +PROVIDE( spi_flash_check_and_flush_cache = 0x400001b4 ); +PROVIDE( spi_flash_mmap_get_free_pages = 0x400001b8 ); +PROVIDE( spi_flash_cache2phys = 0x400001bc ); +PROVIDE( spi_flash_phys2cache = 0x400001c0 ); +PROVIDE( spi_flash_disable_cache = 0x400001c4 ); +PROVIDE( spi_flash_restore_cache = 0x400001c8 ); +PROVIDE( spi_flash_cache_enabled = 0x400001cc ); +PROVIDE( spi_flash_enable_cache = 0x400001d0 ); +PROVIDE( spi_cache_mode_switch = 0x400001d4 ); +PROVIDE( spi_common_set_dummy_output = 0x400001d8 ); +PROVIDE( spi_common_set_flash_cs_timing = 0x400001dc ); +PROVIDE( esp_rom_spi_set_address_bit_len = 0x400001e0 ); +PROVIDE( esp_enable_cache_flash_wrap = 0x400001e4 ); +PROVIDE( SPILock = 0x400001e8 ); +PROVIDE( SPIMasterReadModeCnfig = 0x400001ec ); +PROVIDE( SPI_Common_Command = 0x400001f0 ); +PROVIDE( SPI_WakeUp = 0x400001f4 ); +PROVIDE( SPI_block_erase = 0x400001f8 ); +PROVIDE( SPI_chip_erase = 0x400001fc ); +PROVIDE( SPI_init = 0x40000200 ); +PROVIDE( SPI_page_program = 0x40000204 ); +PROVIDE( SPI_read_data = 0x40000208 ); +PROVIDE( SPI_sector_erase = 0x4000020c ); +PROVIDE( SelectSpiFunction = 0x40000210 ); +PROVIDE( SetSpiDrvs = 0x40000214 ); +PROVIDE( Wait_SPI_Idle = 0x40000218 ); +PROVIDE( spi_dummy_len_fix = 0x4000021c ); +PROVIDE( Disable_QMode = 0x40000220 ); +PROVIDE( Enable_QMode = 0x40000224 ); +/* Data (.data, .bss, .rodata) */ +PROVIDE( rom_spiflash_legacy_funcs = 0x3fcdfff0 ); +PROVIDE( rom_spiflash_legacy_data = 0x3fcdffec ); +PROVIDE( g_flash_guard_ops = 0x3fcdfff4 ); + + +/*************************************** + Group hal_soc + ***************************************/ + +/* Functions */ +PROVIDE( spi_flash_hal_poll_cmd_done = 0x40000228 ); +PROVIDE( spi_flash_hal_device_config = 0x4000022c ); +PROVIDE( spi_flash_hal_configure_host_io_mode = 0x40000230 ); +PROVIDE( spi_flash_hal_common_command = 0x40000234 ); +PROVIDE( spi_flash_hal_read = 0x40000238 ); +PROVIDE( spi_flash_hal_erase_chip = 0x4000023c ); +PROVIDE( spi_flash_hal_erase_sector = 0x40000240 ); +PROVIDE( spi_flash_hal_erase_block = 0x40000244 ); +PROVIDE( spi_flash_hal_program_page = 0x40000248 ); +PROVIDE( spi_flash_hal_set_write_protect = 0x4000024c ); +PROVIDE( spi_flash_hal_host_idle = 0x40000250 ); +PROVIDE( spi_flash_hal_check_status = 0x40000254 ); +PROVIDE( spi_flash_hal_setup_read_suspend = 0x40000258 ); +PROVIDE( spi_flash_hal_setup_auto_suspend_mode = 0x4000025c ); +PROVIDE( spi_flash_hal_setup_auto_resume_mode = 0x40000260 ); +PROVIDE( spi_flash_hal_disable_auto_suspend_mode = 0x40000264 ); +PROVIDE( spi_flash_hal_disable_auto_resume_mode = 0x40000268 ); +PROVIDE( spi_flash_hal_resume = 0x4000026c ); +PROVIDE( spi_flash_hal_suspend = 0x40000270 ); +PROVIDE( spi_flash_encryption_hal_enable = 0x40000274 ); +PROVIDE( spi_flash_encryption_hal_disable = 0x40000278 ); +PROVIDE( spi_flash_encryption_hal_prepare = 0x4000027c ); +PROVIDE( spi_flash_encryption_hal_done = 0x40000280 ); +PROVIDE( spi_flash_encryption_hal_destroy = 0x40000284 ); +PROVIDE( spi_flash_encryption_hal_check = 0x40000288 ); +PROVIDE( wdt_hal_init = 0x4000028c ); +PROVIDE( wdt_hal_deinit = 0x40000290 ); +PROVIDE( wdt_hal_config_stage = 0x40000294 ); +PROVIDE( wdt_hal_write_protect_disable = 0x40000298 ); +PROVIDE( wdt_hal_write_protect_enable = 0x4000029c ); +PROVIDE( wdt_hal_enable = 0x400002a0 ); +PROVIDE( wdt_hal_disable = 0x400002a4 ); +PROVIDE( wdt_hal_handle_intr = 0x400002a8 ); +PROVIDE( wdt_hal_feed = 0x400002ac ); +PROVIDE( wdt_hal_set_flashboot_en = 0x400002b0 ); +PROVIDE( wdt_hal_is_enabled = 0x400002b4 ); +PROVIDE( systimer_hal_init = 0x400002b8 ); +PROVIDE( systimer_hal_get_counter_value = 0x400002bc ); +PROVIDE( systimer_hal_get_time = 0x400002c0 ); +PROVIDE( systimer_hal_set_alarm_target = 0x400002c4 ); +PROVIDE( systimer_hal_set_alarm_period = 0x400002c8 ); +PROVIDE( systimer_hal_get_alarm_value = 0x400002cc ); +PROVIDE( systimer_hal_enable_alarm_int = 0x400002d0 ); +PROVIDE( systimer_hal_on_apb_freq_update = 0x400002d4 ); +PROVIDE( systimer_hal_counter_value_advance = 0x400002d8 ); +PROVIDE( systimer_hal_enable_counter = 0x400002dc ); +PROVIDE( systimer_hal_select_alarm_mode = 0x400002e0 ); +PROVIDE( systimer_hal_connect_alarm_counter = 0x400002e4 ); +PROVIDE( systimer_hal_counter_can_stall_by_cpu = 0x400002e8 ); + + +/*************************************** + Group heap + ***************************************/ + +/* Functions */ +PROVIDE( tlsf_create = 0x400002ec ); +PROVIDE( tlsf_create_with_pool = 0x400002f0 ); +PROVIDE( tlsf_get_pool = 0x400002f4 ); +PROVIDE( tlsf_add_pool = 0x400002f8 ); +PROVIDE( tlsf_remove_pool = 0x400002fc ); +PROVIDE( tlsf_malloc = 0x40000300 ); +PROVIDE( tlsf_memalign = 0x40000304 ); +PROVIDE( tlsf_memalign_offs = 0x40000308 ); +PROVIDE( tlsf_realloc = 0x4000030c ); +PROVIDE( tlsf_free = 0x40000310 ); +PROVIDE( tlsf_block_size = 0x40000314 ); +PROVIDE( tlsf_size = 0x40000318 ); +PROVIDE( tlsf_align_size = 0x4000031c ); +PROVIDE( tlsf_block_size_min = 0x40000320 ); +PROVIDE( tlsf_block_size_max = 0x40000324 ); +PROVIDE( tlsf_pool_overhead = 0x40000328 ); +PROVIDE( tlsf_alloc_overhead = 0x4000032c ); +PROVIDE( tlsf_walk_pool = 0x40000330 ); +PROVIDE( tlsf_check = 0x40000334 ); +PROVIDE( tlsf_check_pool = 0x40000338 ); +PROVIDE( tlsf_poison_fill_pfunc_set = 0x4000033c ); +PROVIDE( multi_heap_get_block_address_impl = 0x40000340 ); +PROVIDE( multi_heap_get_allocated_size_impl = 0x40000344 ); +PROVIDE( multi_heap_register_impl = 0x40000348 ); +PROVIDE( multi_heap_set_lock = 0x4000034c ); +PROVIDE( multi_heap_mutex_init = 0x40000350 ); +PROVIDE( multi_heap_internal_lock = 0x40000354 ); +PROVIDE( multi_heap_internal_unlock = 0x40000358 ); +PROVIDE( multi_heap_get_first_block = 0x4000035c ); +PROVIDE( multi_heap_get_next_block = 0x40000360 ); +PROVIDE( multi_heap_is_free = 0x40000364 ); +PROVIDE( multi_heap_malloc_impl = 0x40000368 ); +PROVIDE( multi_heap_free_impl = 0x4000036c ); +PROVIDE( multi_heap_realloc_impl = 0x40000370 ); +PROVIDE( multi_heap_aligned_alloc_impl_offs = 0x40000374 ); +PROVIDE( multi_heap_aligned_alloc_impl = 0x40000378 ); +PROVIDE( multi_heap_check = 0x4000037c ); +PROVIDE( multi_heap_dump = 0x40000380 ); +PROVIDE( multi_heap_free_size_impl = 0x40000384 ); +PROVIDE( multi_heap_minimum_free_size_impl = 0x40000388 ); +PROVIDE( multi_heap_get_info_impl = 0x4000038c ); +/* Data (.data, .bss, .rodata) */ +PROVIDE( heap_tlsf_table_ptr = 0x3fcdffe8 ); + + +/*************************************** + Group spi_flash_chips + ***************************************/ + +/* Functions */ +PROVIDE( spi_flash_chip_generic_probe = 0x40000390 ); +PROVIDE( spi_flash_chip_generic_detect_size = 0x40000394 ); +PROVIDE( spi_flash_chip_generic_write = 0x40000398 ); +PROVIDE( spi_flash_chip_generic_write_encrypted = 0x4000039c ); +PROVIDE( spi_flash_chip_generic_set_write_protect = 0x400003a0 ); +PROVIDE( spi_flash_common_write_status_16b_wrsr = 0x400003a4 ); +PROVIDE( spi_flash_chip_generic_reset = 0x400003a8 ); +PROVIDE( spi_flash_chip_generic_erase_chip = 0x400003ac ); +PROVIDE( spi_flash_chip_generic_erase_sector = 0x400003b0 ); +PROVIDE( spi_flash_chip_generic_erase_block = 0x400003b4 ); +PROVIDE( spi_flash_chip_generic_page_program = 0x400003b8 ); +PROVIDE( spi_flash_chip_generic_get_write_protect = 0x400003bc ); +PROVIDE( spi_flash_common_read_status_16b_rdsr_rdsr2 = 0x400003c0 ); +PROVIDE( spi_flash_chip_generic_read_reg = 0x400003c4 ); +PROVIDE( spi_flash_chip_generic_yield = 0x400003c8 ); +PROVIDE( spi_flash_generic_wait_host_idle = 0x400003cc ); +PROVIDE( spi_flash_chip_generic_wait_idle = 0x400003d0 ); +PROVIDE( spi_flash_chip_generic_config_host_io_mode = 0x400003d4 ); +PROVIDE( spi_flash_chip_generic_read = 0x400003d8 ); +PROVIDE( spi_flash_common_read_status_8b_rdsr2 = 0x400003dc ); +PROVIDE( spi_flash_chip_generic_get_io_mode = 0x400003e0 ); +PROVIDE( spi_flash_common_read_status_8b_rdsr = 0x400003e4 ); +PROVIDE( spi_flash_common_write_status_8b_wrsr = 0x400003e8 ); +PROVIDE( spi_flash_common_write_status_8b_wrsr2 = 0x400003ec ); +PROVIDE( spi_flash_common_set_io_mode = 0x400003f0 ); +PROVIDE( spi_flash_chip_generic_set_io_mode = 0x400003f4 ); +PROVIDE( spi_flash_chip_generic_read_unique_id = 0x400003f8 ); +PROVIDE( spi_flash_chip_generic_get_caps = 0x400003fc ); +PROVIDE( spi_flash_chip_generic_suspend_cmd_conf = 0x40000400 ); +PROVIDE( spi_flash_chip_gd_get_io_mode = 0x40000404 ); +PROVIDE( spi_flash_chip_gd_probe = 0x40000408 ); +PROVIDE( spi_flash_chip_gd_set_io_mode = 0x4000040c ); +/* Data (.data, .bss, .rodata) */ +PROVIDE( spi_flash_chip_generic_config_data = 0x3fcdffe4 ); +PROVIDE( spi_flash_encryption = 0x3fcdffe0 ); + + +/*************************************** + Group memspi_host + ***************************************/ + +/* Functions */ +PROVIDE( memspi_host_read_id_hs = 0x40000410 ); +PROVIDE( memspi_host_read_status_hs = 0x40000414 ); +PROVIDE( memspi_host_flush_cache = 0x40000418 ); +PROVIDE( memspi_host_erase_chip = 0x4000041c ); +PROVIDE( memspi_host_erase_sector = 0x40000420 ); +PROVIDE( memspi_host_erase_block = 0x40000424 ); +PROVIDE( memspi_host_program_page = 0x40000428 ); +PROVIDE( memspi_host_read = 0x4000042c ); +PROVIDE( memspi_host_set_write_protect = 0x40000430 ); +PROVIDE( memspi_host_set_max_read_len = 0x40000434 ); +PROVIDE( memspi_host_read_data_slicer = 0x40000438 ); +PROVIDE( memspi_host_write_data_slicer = 0x4000043c ); + + +/*************************************** + Group esp_flash + ***************************************/ + +/* Functions */ +PROVIDE( esp_flash_chip_driver_initialized = 0x40000440 ); +PROVIDE( esp_flash_read_id = 0x40000444 ); +PROVIDE( esp_flash_get_size = 0x40000448 ); +PROVIDE( esp_flash_erase_chip = 0x4000044c ); +PROVIDE( esp_flash_erase_region = 0x40000450 ); +PROVIDE( esp_flash_get_chip_write_protect = 0x40000454 ); +PROVIDE( esp_flash_set_chip_write_protect = 0x40000458 ); +PROVIDE( esp_flash_get_protectable_regions = 0x4000045c ); +PROVIDE( esp_flash_get_protected_region = 0x40000460 ); +PROVIDE( esp_flash_set_protected_region = 0x40000464 ); +PROVIDE( esp_flash_read = 0x40000468 ); +PROVIDE( esp_flash_write = 0x4000046c ); +PROVIDE( esp_flash_write_encrypted = 0x40000470 ); +PROVIDE( esp_flash_read_encrypted = 0x40000474 ); +PROVIDE( esp_flash_get_io_mode = 0x40000478 ); +PROVIDE( esp_flash_set_io_mode = 0x4000047c ); +PROVIDE( spi_flash_boot_attach = 0x40000480 ); +PROVIDE( esp_flash_read_chip_id = 0x40000484 ); +PROVIDE( detect_spi_flash_chip = 0x40000488 ); +PROVIDE( esp_rom_spiflash_write_disable = 0x4000048c ); +PROVIDE( esp_flash_suspend_cmd_init = 0x40000490 ); +/* Data (.data, .bss, .rodata) */ +PROVIDE( esp_flash_default_chip = 0x3fcdffdc ); +PROVIDE( esp_flash_api_funcs = 0x3fcdffd8 ); + + +/*************************************** + Group cache + ***************************************/ + +/* Functions */ +PROVIDE( Cache_Get_ICache_Line_Size = 0x400006f0 ); +PROVIDE( Cache_Get_Mode = 0x400006f4 ); +PROVIDE( Cache_Address_Through_IBus = 0x400006f8 ); +PROVIDE( Cache_Address_Through_DBus = 0x400006fc ); +PROVIDE( Cache_Set_Default_Mode = 0x40000700 ); +PROVIDE( Cache_Enable_Defalut_ICache_Mode = 0x40000704 ); +PROVIDE( ROM_Boot_Cache_Init = 0x40000708 ); +PROVIDE( Cache_Invalidate_ICache_Items = 0x4000070c ); +PROVIDE( Cache_Op_Addr = 0x40000710 ); +PROVIDE( Cache_Invalidate_Addr = 0x40000714 ); +PROVIDE( Cache_Invalidate_ICache_All = 0x40000718 ); +PROVIDE( Cache_Mask_All = 0x4000071c ); +PROVIDE( Cache_UnMask_Dram0 = 0x40000720 ); +PROVIDE( Cache_Suspend_ICache_Autoload = 0x40000724 ); +PROVIDE( Cache_Resume_ICache_Autoload = 0x40000728 ); +PROVIDE( Cache_Start_ICache_Preload = 0x4000072c ); +PROVIDE( Cache_ICache_Preload_Done = 0x40000730 ); +PROVIDE( Cache_End_ICache_Preload = 0x40000734 ); +PROVIDE( Cache_Config_ICache_Autoload = 0x40000738 ); +PROVIDE( Cache_Enable_ICache_Autoload = 0x4000073c ); +PROVIDE( Cache_Disable_ICache_Autoload = 0x40000740 ); +PROVIDE( Cache_Enable_ICache_PreLock = 0x40000744 ); +PROVIDE( Cache_Disable_ICache_PreLock = 0x40000748 ); +PROVIDE( Cache_Lock_ICache_Items = 0x4000074c ); +PROVIDE( Cache_Unlock_ICache_Items = 0x40000750 ); +PROVIDE( Cache_Lock_Addr = 0x40000754 ); +PROVIDE( Cache_Unlock_Addr = 0x40000758 ); +PROVIDE( Cache_Disable_ICache = 0x4000075c ); +PROVIDE( Cache_Enable_ICache = 0x40000760 ); +PROVIDE( Cache_Suspend_ICache = 0x40000764 ); +PROVIDE( Cache_Resume_ICache = 0x40000768 ); +PROVIDE( Cache_Freeze_ICache_Enable = 0x4000076c ); +PROVIDE( Cache_Freeze_ICache_Disable = 0x40000770 ); +PROVIDE( Cache_Pms_Lock = 0x40000774 ); +PROVIDE( Cache_Ibus_Pms_Set_Addr = 0x40000778 ); +PROVIDE( Cache_Ibus_Pms_Set_Attr = 0x4000077c ); +PROVIDE( Cache_Dbus_Pms_Set_Addr = 0x40000780 ); +PROVIDE( Cache_Dbus_Pms_Set_Attr = 0x40000784 ); +PROVIDE( Cache_Set_IDROM_MMU_Size = 0x40000788 ); +PROVIDE( Cache_Get_IROM_MMU_End = 0x4000078c ); +PROVIDE( Cache_Get_DROM_MMU_End = 0x40000790 ); +PROVIDE( Cache_Owner_Init = 0x40000794 ); +PROVIDE( Cache_Occupy_ICache_MEMORY = 0x40000798 ); +PROVIDE( Cache_MMU_Init = 0x4000079c ); +PROVIDE( Cache_Ibus_MMU_Set = 0x400007a0 ); +PROVIDE( Cache_Dbus_MMU_Set = 0x400007a4 ); +PROVIDE( Cache_Count_Flash_Pages = 0x400007a8 ); +PROVIDE( Cache_Travel_Tag_Memory = 0x400007ac ); +PROVIDE( Cache_Get_Virtual_Addr = 0x400007b0 ); +PROVIDE( Cache_Get_Memory_BaseAddr = 0x400007b4 ); +PROVIDE( Cache_Get_Memory_Addr = 0x400007b8 ); +PROVIDE( Cache_Get_Memory_value = 0x400007bc ); +/* Data (.data, .bss, .rodata) */ +PROVIDE( rom_cache_op_cb = 0x3fcdffcc ); +PROVIDE( rom_cache_internal_table_ptr = 0x3fcdffc8 ); + + +/*************************************** + Group clock + ***************************************/ + +/* Functions */ +ets_get_apb_freq = 0x400007c0; +ets_get_cpu_frequency = 0x400007c4; +ets_update_cpu_frequency = 0x400007c8; +ets_get_printf_channel = 0x400007cc; +ets_get_xtal_div = 0x400007d0; +ets_set_xtal_div = 0x400007d4; +ets_get_xtal_freq = 0x400007d8; + + +/*************************************** + Group gpio + ***************************************/ + +/* Functions */ +gpio_input_get = 0x400007dc; +gpio_matrix_in = 0x400007e0; +gpio_matrix_out = 0x400007e4; +gpio_output_disable = 0x400007e8; +gpio_output_enable = 0x400007ec; +gpio_output_set = 0x400007f0; +gpio_pad_hold = 0x400007f4; +gpio_pad_input_disable = 0x400007f8; +gpio_pad_input_enable = 0x400007fc; +gpio_pad_pulldown = 0x40000800; +gpio_pad_pullup = 0x40000804; +gpio_pad_select_gpio = 0x40000808; +gpio_pad_set_drv = 0x4000080c; +gpio_pad_unhold = 0x40000810; +gpio_pin_wakeup_disable = 0x40000814; +gpio_pin_wakeup_enable = 0x40000818; +gpio_bypass_matrix_in = 0x4000081c; + + +/*************************************** + Group interrupts + ***************************************/ + +/* Functions */ +esprv_intc_int_set_priority = 0x40000820; +esprv_intc_int_set_threshold = 0x40000824; +esprv_intc_int_enable = 0x40000828; +esprv_intc_int_disable = 0x4000082c; +esprv_intc_int_set_type = 0x40000830; +PROVIDE( intr_handler_set = 0x40000834 ); +intr_matrix_set = 0x40000838; +ets_intr_lock = 0x4000083c; +ets_intr_unlock = 0x40000840; +ets_isr_attach = 0x40000844; +ets_isr_mask = 0x40000848; +ets_isr_unmask = 0x4000084c; + + +/*************************************** + Group crypto + ***************************************/ + +/* Functions */ +md5_vector = 0x40000850; +MD5Init = 0x40000854; +MD5Update = 0x40000858; +MD5Final = 0x4000085c; +crc32_le = 0x40000860; +crc16_le = 0x40000864; +crc8_le = 0x40000868; +crc32_be = 0x4000086c; +crc16_be = 0x40000870; +crc8_be = 0x40000874; +esp_crc8 = 0x40000878; +ets_sha_enable = 0x4000087c; +ets_sha_disable = 0x40000880; +ets_sha_get_state = 0x40000884; +ets_sha_init = 0x40000888; +ets_sha_process = 0x4000088c; +ets_sha_starts = 0x40000890; +ets_sha_update = 0x40000894; +ets_sha_finish = 0x40000898; +ets_sha_clone = 0x4000089c; +ets_hmac_enable = 0x400008a0; +ets_hmac_disable = 0x400008a4; +ets_hmac_calculate_message = 0x400008a8; +ets_hmac_calculate_downstream = 0x400008ac; +ets_hmac_invalidate_downstream = 0x400008b0; +ets_jtag_enable_temporarily = 0x400008b4; +ets_aes_enable = 0x400008b8; +ets_aes_disable = 0x400008bc; +ets_aes_setkey = 0x400008c0; +ets_aes_block = 0x400008c4; +ets_aes_setkey_dec = 0x400008c8; +ets_aes_setkey_enc = 0x400008cc; +ets_bigint_enable = 0x400008d0; +ets_bigint_disable = 0x400008d4; +ets_bigint_multiply = 0x400008d8; +ets_bigint_modmult = 0x400008dc; +ets_bigint_modexp = 0x400008e0; +ets_bigint_wait_finish = 0x400008e4; +ets_bigint_getz = 0x400008e8; +ets_ds_enable = 0x400008ec; +ets_ds_disable = 0x400008f0; +ets_ds_start_sign = 0x400008f4; +ets_ds_is_busy = 0x400008f8; +ets_ds_finish_sign = 0x400008fc; +ets_ds_encrypt_params = 0x40000900; +ets_mgf1_sha256 = 0x40000904; +/* Data (.data, .bss, .rodata) */ +crc32_le_table_ptr = 0x3ff1fff8; +crc16_le_table_ptr = 0x3ff1fff4; +crc8_le_table_ptr = 0x3ff1fff0; +crc32_be_table_ptr = 0x3ff1ffec; +crc16_be_table_ptr = 0x3ff1ffe8; +crc8_be_table_ptr = 0x3ff1ffe4; + + +/*************************************** + Group efuse + ***************************************/ + +/* Functions */ +ets_efuse_read = 0x40000908; +ets_efuse_program = 0x4000090c; +ets_efuse_clear_program_registers = 0x40000910; +ets_efuse_write_key = 0x40000914; +ets_efuse_get_read_register_address = 0x40000918; +ets_efuse_get_key_purpose = 0x4000091c; +ets_efuse_key_block_unused = 0x40000920; +ets_efuse_find_unused_key_block = 0x40000924; +ets_efuse_rs_calculate = 0x40000928; +ets_efuse_count_unused_key_blocks = 0x4000092c; +ets_efuse_secure_boot_enabled = 0x40000930; +ets_efuse_secure_boot_aggressive_revoke_enabled = 0x40000934; +ets_efuse_cache_encryption_enabled = 0x40000938; +ets_efuse_download_modes_disabled = 0x4000093c; +ets_efuse_find_purpose = 0x40000940; +ets_efuse_force_send_resume = 0x40000944; +ets_efuse_get_flash_delay_us = 0x40000948; +ets_efuse_get_mac = 0x4000094c; +ets_efuse_get_uart_print_control = 0x40000950; +ets_efuse_direct_boot_mode_disabled = 0x40000954; +ets_efuse_security_download_modes_enabled = 0x40000958; +ets_efuse_set_timing = 0x4000095c; +ets_efuse_jtag_disabled = 0x40000960; +ets_efuse_get_spiconfig = 0x40000964; +ets_efuse_get_wp_pad = 0x40000968; +ets_efuse_usb_print_is_disabled = 0x4000096c; +ets_efuse_usb_download_mode_disabled = 0x40000970; +ets_efuse_usb_module_disabled = 0x40000974; +ets_efuse_usb_device_disabled = 0x40000978; +ets_efuse_secure_boot_fast_wake_enabled = 0x4000097c; + + +/*************************************** + Group secureboot + ***************************************/ + +/* Functions */ +ets_emsa_pss_verify = 0x40000980; +ets_rsa_pss_verify = 0x40000984; +ets_secure_boot_verify_bootloader_with_keys = 0x40000988; +ets_secure_boot_verify_signature = 0x4000098c; +ets_secure_boot_read_key_digests = 0x40000990; +ets_secure_boot_revoke_public_key_digest = 0x40000994; + + +/*************************************** + Group btdm + ***************************************/ + +/* Functions */ +ble_controller_rom_data_init = 0x40000b08; +ble_osi_coex_funcs_register = 0x40000b0c; +bt_rf_coex_cfg_get_default = 0x40000b10; +bt_rf_coex_dft_pti_get_default = 0x40000b14; +bt_rf_coex_hooks_p_set = 0x40000b18; +r__os_mbuf_copypkthdr = 0x40000b1c; +r__os_msys_find_pool = 0x40000b20; +r_ble_controller_get_rom_compile_version = 0x40000b24; +r_ble_hci_ram_hs_acl_tx = 0x40000b28; +r_ble_hci_ram_hs_cmd_tx = 0x40000b2c; +r_ble_hci_ram_ll_acl_tx = 0x40000b30; +r_ble_hci_ram_ll_evt_tx = 0x40000b34; +r_ble_hci_ram_reset = 0x40000b38; +r_ble_hci_ram_set_acl_free_cb = 0x40000b3c; +r_ble_hci_trans_acl_buf_alloc = 0x40000b40; +r_ble_hci_trans_buf_alloc = 0x40000b44; +r_ble_hci_trans_buf_free = 0x40000b48; +r_ble_hci_trans_cfg_hs = 0x40000b4c; +r_ble_hci_trans_cfg_ll = 0x40000b50; +r_ble_hci_trans_deinit = 0x40000b54; +r_ble_hci_trans_env_init = 0x40000b58; +r_ble_hci_trans_init = 0x40000b5c; +r_ble_hci_uart_acl_tx = 0x40000b60; +r_ble_hci_uart_cmdevt_tx = 0x40000b64; +r_ble_hci_uart_config = 0x40000b68; +r_ble_hci_uart_free_pkt = 0x40000b6c; +r_ble_hci_uart_hs_acl_tx = 0x40000b70; +r_ble_hci_uart_hs_cmd_tx = 0x40000b74; +r_ble_hci_uart_ll_acl_tx = 0x40000b78; +r_ble_hci_uart_ll_evt_tx = 0x40000b7c; +r_ble_hci_uart_rx_acl = 0x40000b80; +r_ble_hci_uart_rx_char = 0x40000b84; +r_ble_hci_uart_rx_cmd = 0x40000b88; +r_ble_hci_uart_rx_evt = 0x40000b8c; +r_ble_hci_uart_rx_evt_cb = 0x40000b90; +r_ble_hci_uart_rx_le_evt = 0x40000b94; +r_ble_hci_uart_rx_pkt_type = 0x40000b98; +r_ble_hci_uart_rx_skip_acl = 0x40000b9c; +r_ble_hci_uart_rx_skip_cmd = 0x40000ba0; +r_ble_hci_uart_rx_skip_evt = 0x40000ba4; +r_ble_hci_uart_rx_sync_loss = 0x40000ba8; +r_ble_hci_uart_set_acl_free_cb = 0x40000bac; +r_ble_hci_uart_sync_lost = 0x40000bb0; +r_ble_hci_uart_trans_reset = 0x40000bb4; +r_ble_hci_uart_tx_char = 0x40000bb8; +r_ble_hci_uart_tx_pkt_type = 0x40000bbc; +r_ble_hw_driver_deinit = 0x40000bc0; +r_ble_hw_driver_env_init = 0x40000bc4; +r_ble_hw_encrypt_block = 0x40000bc8; +r_ble_hw_get_public_addr = 0x40000bcc; +r_ble_hw_get_static_addr = 0x40000bd0; +r_ble_hw_periodiclist_add = 0x40000bd4; +r_ble_hw_periodiclist_clear = 0x40000bd8; +r_ble_hw_periodiclist_rmv = 0x40000bdc; +r_ble_hw_resolv_list_cur_entry = 0x40000be0; +r_ble_hw_resolv_list_match = 0x40000be4; +r_ble_hw_resolv_list_set = 0x40000be8; +r_ble_hw_rng_init = 0x40000bec; +r_ble_hw_rng_start = 0x40000bf0; +r_ble_hw_rng_stop = 0x40000bf4; +r_ble_hw_rx_local_is_rpa = 0x40000bf8; +r_ble_hw_whitelist_add = 0x40000bfc; +r_ble_hw_whitelist_clear = 0x40000c00; +r_ble_hw_whitelist_dev_num = 0x40000c04; +r_ble_hw_whitelist_get_base = 0x40000c08; +r_ble_hw_whitelist_rmv = 0x40000c0c; +r_ble_hw_whitelist_search = 0x40000c10; +r_ble_hw_whitelist_sort = 0x40000c14; +r_ble_ll_acl_data_in = 0x40000c18; +r_ble_ll_addr_is_id = 0x40000c1c; +r_ble_ll_addr_subtype = 0x40000c20; +r_ble_ll_adv_active_chanset_clear = 0x40000c24; +r_ble_ll_adv_active_chanset_is_pri = 0x40000c28; +r_ble_ll_adv_active_chanset_is_sec = 0x40000c2c; +r_ble_ll_adv_active_chanset_set_pri = 0x40000c30; +r_ble_ll_adv_active_chanset_set_sec = 0x40000c34; +r_ble_ll_adv_aux_calculate = 0x40000c38; +r_ble_ll_adv_aux_conn_rsp_pdu_make = 0x40000c3c; +r_ble_ll_adv_aux_pdu_make = 0x40000c40; +r_ble_ll_adv_aux_scannable_pdu_make = 0x40000c44; +r_ble_ll_adv_aux_scannable_pdu_payload_len = 0x40000c48; +r_ble_ll_adv_aux_schedule = 0x40000c4c; +r_ble_ll_adv_aux_schedule_first = 0x40000c50; +r_ble_ll_adv_aux_schedule_next = 0x40000c54; +r_ble_ll_adv_aux_scheduled = 0x40000c58; +r_ble_ll_adv_aux_set_start_time = 0x40000c5c; +r_ble_ll_adv_aux_txed = 0x40000c60; +r_ble_ll_adv_can_chg_whitelist = 0x40000c64; +r_ble_ll_adv_chk_rpa_timeout = 0x40000c68; +r_ble_ll_adv_clear_all = 0x40000c6c; +r_ble_ll_adv_coex_dpc_calc_pti_update_itvl = 0x40000c70; +r_ble_ll_adv_coex_dpc_process_pri = 0x40000c74; +r_ble_ll_adv_coex_dpc_process_sec = 0x40000c78; +r_ble_ll_adv_coex_dpc_pti_get = 0x40000c7c; +r_ble_ll_adv_coex_dpc_update = 0x40000c80; +r_ble_ll_adv_coex_dpc_update_on_adv_start = 0x40000c84; +r_ble_ll_adv_coex_dpc_update_on_aux_scheduled = 0x40000c88; +r_ble_ll_adv_coex_dpc_update_on_data_updated = 0x40000c8c; +r_ble_ll_adv_coex_dpc_update_on_event_end = 0x40000c90; +r_ble_ll_adv_coex_dpc_update_on_event_scheduled = 0x40000c94; +r_ble_ll_adv_conn_req_rxd = 0x40000c98; +r_ble_ll_adv_deinit = 0x40000c9c; +r_ble_ll_adv_done = 0x40000ca0; +r_ble_ll_adv_drop_event = 0x40000ca4; +r_ble_ll_adv_enabled = 0x40000ca8; +r_ble_ll_adv_env_init = 0x40000cac; +r_ble_ll_adv_event_done = 0x40000cb0; +r_ble_ll_adv_event_rmvd_from_sched = 0x40000cb4; +r_ble_ll_adv_ext_estimate_data_itvl = 0x40000cb8; +r_ble_ll_adv_ext_set_adv_data = 0x40000cbc; +r_ble_ll_adv_ext_set_enable = 0x40000cc0; +r_ble_ll_adv_ext_set_param = 0x40000cc4; +r_ble_ll_adv_ext_set_scan_rsp = 0x40000cc8; +r_ble_ll_adv_final_chan = 0x40000ccc; +r_ble_ll_adv_first_chan = 0x40000cd0; +r_ble_ll_adv_flags_clear = 0x40000cd4; +r_ble_ll_adv_flags_set = 0x40000cd8; +r_ble_ll_adv_get_local_rpa = 0x40000cdc; +r_ble_ll_adv_get_peer_rpa = 0x40000ce0; +r_ble_ll_adv_get_sec_pdu_len = 0x40000ce4; +r_ble_ll_adv_halt = 0x40000ce8; +r_ble_ll_adv_hci_set_random_addr = 0x40000cec; +r_ble_ll_adv_init = 0x40000cf0; +r_ble_ll_adv_legacy_pdu_make = 0x40000cf4; +r_ble_ll_adv_make_done = 0x40000cf8; +r_ble_ll_adv_pdu_make = 0x40000cfc; +r_ble_ll_adv_periodic_check_data_itvl = 0x40000d00; +r_ble_ll_adv_periodic_done = 0x40000d04; +r_ble_ll_adv_periodic_enable = 0x40000d08; +r_ble_ll_adv_periodic_estimate_data_itvl = 0x40000d0c; +r_ble_ll_adv_periodic_event_done = 0x40000d10; +r_ble_ll_adv_periodic_rmvd_from_sched = 0x40000d14; +r_ble_ll_adv_periodic_schedule_first = 0x40000d18; +r_ble_ll_adv_periodic_schedule_next = 0x40000d1c; +r_ble_ll_adv_periodic_send_sync_ind = 0x40000d20; +r_ble_ll_adv_periodic_set_data = 0x40000d24; +r_ble_ll_adv_periodic_set_info_transfer = 0x40000d28; +r_ble_ll_adv_periodic_set_param = 0x40000d2c; +r_ble_ll_adv_put_aux_ptr = 0x40000d30; +r_ble_ll_adv_put_syncinfo = 0x40000d34; +r_ble_ll_adv_rd_max_adv_data_len = 0x40000d38; +r_ble_ll_adv_rd_sup_adv_sets = 0x40000d3c; +r_ble_ll_adv_read_txpwr = 0x40000d40; +r_ble_ll_adv_remove = 0x40000d44; +r_ble_ll_adv_reschedule_event = 0x40000d48; +r_ble_ll_adv_reschedule_periodic_event = 0x40000d4c; +r_ble_ll_adv_reset = 0x40000d50; +r_ble_ll_adv_rpa_timeout = 0x40000d54; +r_ble_ll_adv_rpa_update = 0x40000d58; +r_ble_ll_adv_rx_isr_end = 0x40000d5c; +r_ble_ll_adv_rx_isr_start = 0x40000d60; +r_ble_ll_adv_rx_pkt_in = 0x40000d64; +r_ble_ll_adv_rx_req = 0x40000d68; +r_ble_ll_adv_scan_rsp_legacy_pdu_make = 0x40000d6c; +r_ble_ll_adv_scan_rsp_pdu_make = 0x40000d70; +r_ble_ll_adv_scheduled = 0x40000d74; +r_ble_ll_adv_sec_done = 0x40000d78; +r_ble_ll_adv_sec_event_done = 0x40000d7c; +r_ble_ll_adv_secondary_tx_start_cb = 0x40000d80; +r_ble_ll_adv_send_conn_comp_ev = 0x40000d84; +r_ble_ll_adv_set_adv_data = 0x40000d88; +r_ble_ll_adv_set_adv_params = 0x40000d8c; +r_ble_ll_adv_set_enable = 0x40000d90; +r_ble_ll_adv_set_random_addr = 0x40000d94; +r_ble_ll_adv_set_scan_rsp_data = 0x40000d98; +r_ble_ll_adv_set_sched = 0x40000d9c; +r_ble_ll_adv_sm_deinit = 0x40000da0; +r_ble_ll_adv_sm_event_init = 0x40000da4; +r_ble_ll_adv_sm_event_restore = 0x40000da8; +r_ble_ll_adv_sm_event_store = 0x40000dac; +r_ble_ll_adv_sm_find_configured = 0x40000db0; +r_ble_ll_adv_sm_get = 0x40000db4; +r_ble_ll_adv_sm_init = 0x40000db8; +r_ble_ll_adv_sm_reset = 0x40000dbc; +r_ble_ll_adv_sm_start = 0x40000dc0; +r_ble_ll_adv_sm_start_periodic = 0x40000dc4; +r_ble_ll_adv_sm_stop = 0x40000dc8; +r_ble_ll_adv_sm_stop_limit_reached = 0x40000dcc; +r_ble_ll_adv_sm_stop_periodic = 0x40000dd0; +r_ble_ll_adv_sm_stop_timeout = 0x40000dd4; +r_ble_ll_adv_sync_calculate = 0x40000dd8; +r_ble_ll_adv_sync_get_pdu_len = 0x40000ddc; +r_ble_ll_adv_sync_next_scheduled = 0x40000de0; +r_ble_ll_adv_sync_pdu_make = 0x40000de4; +r_ble_ll_adv_sync_schedule = 0x40000de8; +r_ble_ll_adv_sync_tx_done = 0x40000dec; +r_ble_ll_adv_sync_tx_end = 0x40000df0; +r_ble_ll_adv_sync_tx_start_cb = 0x40000df4; +r_ble_ll_adv_tx_done = 0x40000df8; +r_ble_ll_adv_tx_start_cb = 0x40000dfc; +r_ble_ll_adv_update_adv_scan_rsp_data = 0x40000e00; +r_ble_ll_adv_update_data_mbuf = 0x40000e04; +r_ble_ll_adv_update_did = 0x40000e08; +r_ble_ll_adv_update_periodic_data = 0x40000e0c; +r_ble_ll_adv_update_rsp_offset = 0x40000e10; +r_ble_ll_adv_wfr_timer_exp = 0x40000e14; +r_ble_ll_arr_pool_init = 0x40000e18; +r_ble_ll_auth_pyld_tmo_event_send = 0x40000e1c; +r_ble_ll_aux_scan_cb = 0x40000e20; +r_ble_ll_aux_scan_drop = 0x40000e24; +r_ble_ll_aux_scan_drop_event_cb = 0x40000e28; +r_ble_ll_calc_offset_ticks_us_for_rampup = 0x40000e2c; +r_ble_ll_calc_session_key = 0x40000e30; +r_ble_ll_calc_ticks_per_slot = 0x40000e34; +r_ble_ll_calc_us_convert_tick_unit = 0x40000e38; +r_ble_ll_check_scan_params = 0x40000e3c; +r_ble_ll_chk_txrx_octets = 0x40000e40; +r_ble_ll_chk_txrx_time = 0x40000e44; +r_ble_ll_conn_adjust_pyld_len = 0x40000e48; +r_ble_ll_conn_auth_pyld_timer_cb = 0x40000e4c; +r_ble_ll_conn_auth_pyld_timer_start = 0x40000e50; +r_ble_ll_conn_calc_dci = 0x40000e54; +r_ble_ll_conn_calc_dci_csa1 = 0x40000e58; +r_ble_ll_conn_calc_itvl_ticks = 0x40000e5c; +r_ble_ll_conn_can_send_next_pdu = 0x40000e60; +r_ble_ll_conn_chk_csm_flags = 0x40000e64; +r_ble_ll_conn_chk_phy_upd_start = 0x40000e68; +r_ble_ll_conn_coex_dpc_process = 0x40000e6c; +r_ble_ll_conn_coex_dpc_pti_get = 0x40000e70; +r_ble_ll_conn_coex_dpc_update = 0x40000e74; +r_ble_ll_conn_coex_dpc_update_on_event_scheduled = 0x40000e78; +r_ble_ll_conn_comp_event_send = 0x40000e7c; +r_ble_ll_conn_connect_ind_pdu_make = 0x40000e80; +r_ble_ll_conn_create = 0x40000e84; +r_ble_ll_conn_create_cancel = 0x40000e88; +r_ble_ll_conn_created = 0x40000e8c; +r_ble_ll_conn_cth_flow_alloc_credit = 0x40000e90; +r_ble_ll_conn_cth_flow_enable = 0x40000e94; +r_ble_ll_conn_cth_flow_error_fn = 0x40000e98; +r_ble_ll_conn_cth_flow_free_credit = 0x40000e9c; +r_ble_ll_conn_cth_flow_have_credit = 0x40000ea0; +r_ble_ll_conn_cth_flow_is_enabled = 0x40000ea4; +r_ble_ll_conn_cth_flow_process_cmd = 0x40000ea8; +r_ble_ll_conn_cth_flow_set_buffers = 0x40000eac; +r_ble_ll_conn_cur_pducb = 0x40000eb0; +r_ble_ll_conn_current_sm_over = 0x40000eb4; +r_ble_ll_conn_end = 0x40000eb8; +r_ble_ll_conn_enqueue_pkt = 0x40000ebc; +r_ble_ll_conn_env_init = 0x40000ec0; +r_ble_ll_conn_event_end = 0x40000ec4; +r_ble_ll_conn_event_end_timer_cb = 0x40000ec8; +r_ble_ll_conn_event_halt = 0x40000ecc; +r_ble_ll_conn_event_is_over = 0x40000ed0; +r_ble_ll_conn_event_start_cb = 0x40000ed4; +r_ble_ll_conn_ext_master_init = 0x40000ed8; +r_ble_ll_conn_ext_set_params = 0x40000edc; +r_ble_ll_conn_find_active_conn = 0x40000ee0; +r_ble_ll_conn_get_anchor = 0x40000ee4; +r_ble_ll_conn_get_ce_end_time = 0x40000ee8; +r_ble_ll_conn_get_new_pdu = 0x40000eec; +r_ble_ll_conn_get_next_sched_time = 0x40000ef0; +r_ble_ll_conn_halt = 0x40000ef4; +r_ble_ll_conn_hcc_params_set_fallback = 0x40000ef8; +r_ble_ll_conn_hci_cancel_conn_complete_event = 0x40000efc; +r_ble_ll_conn_hci_chk_conn_params = 0x40000f00; +r_ble_ll_conn_hci_chk_scan_params = 0x40000f04; +r_ble_ll_conn_hci_disconnect_cmd = 0x40000f08; +r_ble_ll_conn_hci_le_ltk_neg_reply = 0x40000f0c; +r_ble_ll_conn_hci_le_ltk_reply = 0x40000f10; +r_ble_ll_conn_hci_le_rd_phy = 0x40000f14; +r_ble_ll_conn_hci_le_set_phy = 0x40000f18; +r_ble_ll_conn_hci_le_start_encrypt = 0x40000f1c; +r_ble_ll_conn_hci_param_nrr = 0x40000f20; +r_ble_ll_conn_hci_param_rr = 0x40000f24; +r_ble_ll_conn_hci_rd_auth_pyld_tmo = 0x40000f28; +r_ble_ll_conn_hci_rd_chan_map = 0x40000f2c; +r_ble_ll_conn_hci_rd_rem_ver_cmd = 0x40000f30; +r_ble_ll_conn_hci_rd_rssi = 0x40000f34; +r_ble_ll_conn_hci_read_rem_features = 0x40000f38; +r_ble_ll_conn_hci_set_chan_class = 0x40000f3c; +r_ble_ll_conn_hci_set_data_len = 0x40000f40; +r_ble_ll_conn_hci_update = 0x40000f44; +r_ble_ll_conn_hci_wr_auth_pyld_tmo = 0x40000f48; +r_ble_ll_conn_init_pending_aux_conn_rsp = 0x40000f4c; +r_ble_ll_conn_init_phy = 0x40000f50; +r_ble_ll_conn_init_wfr_timer_exp = 0x40000f54; +r_ble_ll_conn_is_empty_pdu = 0x40000f58; +r_ble_ll_conn_is_lru = 0x40000f5c; +r_ble_ll_conn_master_common_init = 0x40000f60; +r_ble_ll_conn_master_init = 0x40000f64; +r_ble_ll_conn_module_deinit = 0x40000f68; +r_ble_ll_conn_module_init = 0x40000f6c; +r_ble_ll_conn_module_reset = 0x40000f70; +r_ble_ll_conn_new_pducb = 0x40000f74; +r_ble_ll_conn_next_event = 0x40000f78; +r_ble_ll_conn_num_comp_pkts_event_send = 0x40000f7c; +r_ble_ll_conn_process_conn_params = 0x40000f80; +r_ble_ll_conn_recv_ack = 0x40000f84; +r_ble_ll_conn_reset_pending_aux_conn_rsp = 0x40000f88; +r_ble_ll_conn_rx_data_pdu = 0x40000f8c; +r_ble_ll_conn_rx_isr_end = 0x40000f90; +r_ble_ll_conn_rx_isr_start = 0x40000f94; +r_ble_ll_conn_rxend_unencrypt = 0x40000f98; +r_ble_ll_conn_set_csa = 0x40000f9c; +r_ble_ll_conn_set_global_chanmap = 0x40000fa0; +r_ble_ll_conn_set_md_flag = 0x40000fa4; +r_ble_ll_conn_set_phy = 0x40000fa8; +r_ble_ll_conn_set_slave_flow_control = 0x40000fac; +r_ble_ll_conn_set_txpwr_by_handle = 0x40000fb0; +r_ble_ll_conn_set_unknown_rx_octets = 0x40000fb4; +r_ble_ll_conn_slave_start = 0x40000fb8; +r_ble_ll_conn_sm_get = 0x40000fbc; +r_ble_ll_conn_sm_new = 0x40000fc0; +r_ble_ll_conn_sm_npl_deinit = 0x40000fc4; +r_ble_ll_conn_sm_npl_init = 0x40000fc8; +r_ble_ll_conn_start_rx_encrypt = 0x40000fcc; +r_ble_ll_conn_start_rx_unencrypt = 0x40000fd0; +r_ble_ll_conn_timeout = 0x40000fd4; +r_ble_ll_conn_tx_pdu = 0x40000fd8; +r_ble_ll_conn_tx_pkt_in = 0x40000fdc; +r_ble_ll_conn_txend_encrypt = 0x40000fe0; +r_ble_ll_conn_update_conn_params = 0x40000fe4; +r_ble_ll_conn_update_eff_data_len = 0x40000fe8; +r_ble_ll_conn_update_new_pdu_len = 0x40000fec; +r_ble_ll_conn_wait_txend = 0x40000ff0; +r_ble_ll_conn_wfr_timer_exp = 0x40000ff4; +r_ble_ll_copy_data = 0x40000ff8; +r_ble_ll_ctrl_chanmap_req_make = 0x40000ffc; +r_ble_ll_ctrl_chk_proc_start = 0x40001000; +r_ble_ll_ctrl_conn_param_pdu_make = 0x40001004; +r_ble_ll_ctrl_conn_param_pdu_proc = 0x40001008; +r_ble_ll_ctrl_conn_param_reply = 0x4000100c; +r_ble_ll_ctrl_conn_upd_make = 0x40001010; +r_ble_ll_ctrl_datalen_upd_make = 0x40001014; +r_ble_ll_ctrl_enc_allowed_pdu = 0x40001018; +r_ble_ll_ctrl_enc_allowed_pdu_rx = 0x4000101c; +r_ble_ll_ctrl_enc_allowed_pdu_tx = 0x40001020; +r_ble_ll_ctrl_enc_req_make = 0x40001024; +r_ble_ll_ctrl_find_new_phy = 0x40001028; +r_ble_ll_ctrl_initiate_dle = 0x4000102c; +r_ble_ll_ctrl_is_start_enc_rsp = 0x40001030; +r_ble_ll_ctrl_is_terminate_ind = 0x40001034; +r_ble_ll_ctrl_len_proc = 0x40001038; +r_ble_ll_ctrl_phy_from_phy_mask = 0x4000103c; +r_ble_ll_ctrl_phy_req_rsp_make = 0x40001040; +r_ble_ll_ctrl_phy_tx_transition_get = 0x40001044; +r_ble_ll_ctrl_phy_update_cancel = 0x40001048; +r_ble_ll_ctrl_phy_update_ind_make = 0x4000104c; +r_ble_ll_ctrl_phy_update_proc_complete = 0x40001050; +r_ble_ll_ctrl_proc_init = 0x40001054; +r_ble_ll_ctrl_proc_rsp_timer_cb = 0x40001058; +r_ble_ll_ctrl_proc_start = 0x4000105c; +r_ble_ll_ctrl_proc_stop = 0x40001060; +r_ble_ll_ctrl_proc_unk_rsp = 0x40001064; +r_ble_ll_ctrl_proc_with_instant_initiated = 0x40001068; +r_ble_ll_ctrl_rej_ext_ind_make = 0x4000106c; +r_ble_ll_ctrl_reject_ind_send = 0x40001070; +r_ble_ll_ctrl_rx_chanmap_req = 0x40001074; +r_ble_ll_ctrl_rx_conn_param_req = 0x40001078; +r_ble_ll_ctrl_rx_conn_param_rsp = 0x4000107c; +r_ble_ll_ctrl_rx_conn_update = 0x40001080; +r_ble_ll_ctrl_rx_enc_req = 0x40001084; +r_ble_ll_ctrl_rx_enc_rsp = 0x40001088; +r_ble_ll_ctrl_rx_feature_req = 0x4000108c; +r_ble_ll_ctrl_rx_feature_rsp = 0x40001090; +r_ble_ll_ctrl_rx_pause_enc_req = 0x40001094; +r_ble_ll_ctrl_rx_pause_enc_rsp = 0x40001098; +r_ble_ll_ctrl_rx_pdu = 0x4000109c; +r_ble_ll_ctrl_rx_periodic_sync_ind = 0x400010a0; +r_ble_ll_ctrl_rx_phy_req = 0x400010a4; +r_ble_ll_ctrl_rx_phy_rsp = 0x400010a8; +r_ble_ll_ctrl_rx_phy_update_ind = 0x400010ac; +r_ble_ll_ctrl_rx_ping_rsp = 0x400010b0; +r_ble_ll_ctrl_rx_reject_ind = 0x400010b4; +r_ble_ll_ctrl_rx_start_enc_req = 0x400010b8; +r_ble_ll_ctrl_rx_start_enc_rsp = 0x400010bc; +r_ble_ll_ctrl_rx_version_ind = 0x400010c0; +r_ble_ll_ctrl_start_enc_send = 0x400010c4; +r_ble_ll_ctrl_start_rsp_timer = 0x400010c8; +r_ble_ll_ctrl_terminate_start = 0x400010cc; +r_ble_ll_ctrl_tx_done = 0x400010d0; +r_ble_ll_ctrl_update_features = 0x400010d4; +r_ble_ll_ctrl_version_ind_make = 0x400010d8; +r_ble_ll_data_buffer_overflow = 0x400010dc; +r_ble_ll_deinit = 0x400010e0; +r_ble_ll_disconn_comp_event_send = 0x400010e4; +r_ble_ll_dtm_calculate_itvl = 0x400010e8; +r_ble_ll_dtm_ctx_free = 0x400010ec; +r_ble_ll_dtm_deinit = 0x400010f0; +r_ble_ll_dtm_end_test = 0x400010f4; +r_ble_ll_dtm_ev_rx_restart_cb = 0x400010f8; +r_ble_ll_dtm_ev_tx_resched_cb = 0x400010fc; +r_ble_ll_dtm_init = 0x40001100; +r_ble_ll_dtm_reset = 0x40001104; +r_ble_ll_dtm_rx_create_ctx = 0x40001108; +r_ble_ll_dtm_rx_isr_end = 0x4000110c; +r_ble_ll_dtm_rx_isr_start = 0x40001110; +r_ble_ll_dtm_rx_pkt_in = 0x40001114; +r_ble_ll_dtm_rx_sched_cb = 0x40001118; +r_ble_ll_dtm_rx_start = 0x4000111c; +r_ble_ll_dtm_rx_test = 0x40001120; +r_ble_ll_dtm_set_next = 0x40001124; +r_ble_ll_dtm_tx_create_ctx = 0x40001128; +r_ble_ll_dtm_tx_done = 0x4000112c; +r_ble_ll_dtm_tx_sched_cb = 0x40001130; +r_ble_ll_dtm_tx_test = 0x40001134; +r_ble_ll_dtm_wfr_timer_exp = 0x40001138; +r_ble_ll_env_init = 0x4000113c; +r_ble_ll_event_comp_pkts = 0x40001140; +r_ble_ll_event_dbuf_overflow = 0x40001144; +r_ble_ll_event_rx_pkt = 0x40001148; +r_ble_ll_event_send = 0x4000114c; +r_ble_ll_event_tx_pkt = 0x40001150; +r_ble_ll_ext_adv_phy_mode_to_local_phy = 0x40001154; +r_ble_ll_ext_conn_create = 0x40001158; +r_ble_ll_ext_scan_coex_dpc_process = 0x4000115c; +r_ble_ll_ext_scan_coex_dpc_pti_get = 0x40001160; +r_ble_ll_ext_scan_coex_dpc_update = 0x40001164; +r_ble_ll_ext_scan_coex_dpc_update_on_start = 0x40001168; +r_ble_ll_ext_scan_parse_adv_info = 0x4000116c; +r_ble_ll_ext_scan_parse_aux_ptr = 0x40001170; +r_ble_ll_flush_pkt_queue = 0x40001174; +r_ble_ll_generic_data_init = 0x40001178; +r_ble_ll_get_addr_type = 0x4000117c; +r_ble_ll_get_chan_to_scan = 0x40001180; +r_ble_ll_get_our_devaddr = 0x40001184; +r_ble_ll_get_tx_pwr_compensation = 0x40001188; +r_ble_ll_hci_acl_rx = 0x4000118c; +r_ble_ll_hci_adv_mode_ext = 0x40001190; +r_ble_ll_hci_adv_set_enable = 0x40001194; +r_ble_ll_hci_cb_host_buf_size = 0x40001198; +r_ble_ll_hci_cb_set_ctrlr_to_host_fc = 0x4000119c; +r_ble_ll_hci_cb_set_event_mask = 0x400011a0; +r_ble_ll_hci_cb_set_event_mask2 = 0x400011a4; +r_ble_ll_hci_chk_phy_masks = 0x400011a8; +r_ble_ll_hci_cmd_proc = 0x400011ac; +r_ble_ll_hci_cmd_rx = 0x400011b0; +r_ble_ll_hci_ctlr_bb_cmd_proc = 0x400011b4; +r_ble_ll_hci_deinit = 0x400011b8; +r_ble_ll_hci_disconnect = 0x400011bc; +r_ble_ll_hci_dtm_rx_test = 0x400011c0; +r_ble_ll_hci_dtm_rx_test_v2 = 0x400011c4; +r_ble_ll_hci_dtm_tx_test = 0x400011c8; +r_ble_ll_hci_dtm_tx_test_ext = 0x400011cc; +r_ble_ll_hci_dtm_tx_test_v2 = 0x400011d0; +r_ble_ll_hci_dtm_tx_test_v2_ext = 0x400011d4; +r_ble_ll_hci_env_init = 0x400011d8; +r_ble_ll_hci_ev_conn_update = 0x400011dc; +r_ble_ll_hci_ev_databuf_overflow = 0x400011e0; +r_ble_ll_hci_ev_datalen_chg = 0x400011e4; +r_ble_ll_hci_ev_encrypt_chg = 0x400011e8; +r_ble_ll_hci_ev_hw_err = 0x400011ec; +r_ble_ll_hci_ev_le_csa = 0x400011f0; +r_ble_ll_hci_ev_ltk_req = 0x400011f4; +r_ble_ll_hci_ev_phy_update = 0x400011f8; +r_ble_ll_hci_ev_rd_rem_used_feat = 0x400011fc; +r_ble_ll_hci_ev_rd_rem_ver = 0x40001200; +r_ble_ll_hci_ev_rem_conn_parm_req = 0x40001204; +r_ble_ll_hci_ev_send_adv_set_terminated = 0x40001208; +r_ble_ll_hci_ev_send_scan_req_recv = 0x4000120c; +r_ble_ll_hci_ev_send_scan_timeout = 0x40001210; +r_ble_ll_hci_ev_send_vendor_err = 0x40001214; +r_ble_ll_hci_event_send = 0x40001218; +r_ble_ll_hci_ext_scan_set_enable = 0x4000121c; +r_ble_ll_hci_get_num_cmd_pkts = 0x40001220; +r_ble_ll_hci_info_params_cmd_proc = 0x40001224; +r_ble_ll_hci_init = 0x40001228; +r_ble_ll_hci_is_event_enabled = 0x4000122c; +r_ble_ll_hci_is_le_event_enabled = 0x40001230; +r_ble_ll_hci_le_cmd_proc = 0x40001234; +r_ble_ll_hci_le_cmd_send_cmd_status = 0x40001238; +r_ble_ll_hci_le_encrypt = 0x4000123c; +r_ble_ll_hci_le_rand = 0x40001240; +r_ble_ll_hci_le_rd_max_data_len = 0x40001244; +r_ble_ll_hci_le_rd_sugg_data_len = 0x40001248; +r_ble_ll_hci_le_read_bufsize = 0x4000124c; +r_ble_ll_hci_le_read_local_features = 0x40001250; +r_ble_ll_hci_le_read_supp_states = 0x40001254; +r_ble_ll_hci_le_set_def_phy = 0x40001258; +r_ble_ll_hci_le_wr_sugg_data_len = 0x4000125c; +r_ble_ll_hci_link_ctrl_cmd_proc = 0x40001260; +r_ble_ll_hci_npl_init = 0x40001264; +r_ble_ll_hci_rd_bd_addr = 0x40001268; +r_ble_ll_hci_rd_local_supp_cmd = 0x4000126c; +r_ble_ll_hci_rd_local_supp_feat = 0x40001270; +r_ble_ll_hci_rd_local_version = 0x40001274; +r_ble_ll_hci_scan_set_enable = 0x40001278; +r_ble_ll_hci_send_adv_report = 0x4000127c; +r_ble_ll_hci_send_dir_adv_report = 0x40001280; +r_ble_ll_hci_send_ext_adv_report = 0x40001284; +r_ble_ll_hci_send_legacy_ext_adv_report = 0x40001288; +r_ble_ll_hci_send_noop = 0x4000128c; +r_ble_ll_hci_set_adv_data = 0x40001290; +r_ble_ll_hci_set_le_event_mask = 0x40001294; +r_ble_ll_hci_set_scan_rsp_data = 0x40001298; +r_ble_ll_hci_status_params_cmd_proc = 0x4000129c; +r_ble_ll_hci_vs_cmd_proc = 0x400012a0; +r_ble_ll_hci_vs_rd_static_addr = 0x400012a4; +r_ble_ll_hw_err_timer_cb = 0x400012a8; +r_ble_ll_hw_error = 0x400012ac; +r_ble_ll_init = 0x400012b0; +r_ble_ll_init_alloc_conn_comp_ev = 0x400012b4; +r_ble_ll_init_get_conn_comp_ev = 0x400012b8; +r_ble_ll_init_rx_isr_end = 0x400012bc; +r_ble_ll_init_rx_isr_start = 0x400012c0; +r_ble_ll_init_rx_pkt_in = 0x400012c4; +r_ble_ll_is_addr_empty = 0x400012c8; +r_ble_ll_is_controller_busy = 0x400012cc; +r_ble_ll_is_on_resolv_list = 0x400012d0; +r_ble_ll_is_our_devaddr = 0x400012d4; +r_ble_ll_is_rpa = 0x400012d8; +r_ble_ll_is_valid_adv_mode = 0x400012dc; +r_ble_ll_is_valid_own_addr_type = 0x400012e0; +r_ble_ll_is_valid_public_addr = 0x400012e4; +r_ble_ll_is_valid_random_addr = 0x400012e8; +r_ble_ll_mbuf_init = 0x400012ec; +r_ble_ll_misc_options_set = 0x400012f0; +r_ble_ll_pdu_max_tx_octets_get = 0x400012f4; +r_ble_ll_pdu_tx_time_get = 0x400012f8; +r_ble_ll_per_adv_coex_dpc_calc_pti_update_itvl = 0x400012fc; +r_ble_ll_per_adv_coex_dpc_process = 0x40001300; +r_ble_ll_per_adv_coex_dpc_pti_get = 0x40001304; +r_ble_ll_per_adv_coex_dpc_update = 0x40001308; +r_ble_ll_per_adv_coex_dpc_update_on_data_updated = 0x4000130c; +r_ble_ll_per_adv_coex_dpc_update_on_scheduled = 0x40001310; +r_ble_ll_per_adv_coex_dpc_update_on_start = 0x40001314; +r_ble_ll_phy_to_phy_mode = 0x40001318; +r_ble_ll_process_rx_data = 0x4000131c; +r_ble_ll_qa_enable = 0x40001320; +r_ble_ll_rand = 0x40001324; +r_ble_ll_rand_data_get = 0x40001328; +r_ble_ll_rand_deinit = 0x4000132c; +r_ble_ll_rand_env_init = 0x40001330; +r_ble_ll_rand_init = 0x40001334; +r_ble_ll_rand_prand_get = 0x40001338; +r_ble_ll_rand_sample = 0x4000133c; +r_ble_ll_rand_start = 0x40001340; +r_ble_ll_read_rf_path_compensation = 0x40001344; +r_ble_ll_read_supp_features = 0x40001348; +r_ble_ll_read_supp_states = 0x4000134c; +r_ble_ll_read_tx_power = 0x40001350; +r_ble_ll_reset = 0x40001354; +r_ble_ll_resolv_clear_all_pl_bit = 0x40001358; +r_ble_ll_resolv_clear_all_wl_bit = 0x4000135c; +r_ble_ll_resolv_deinit = 0x40001360; +r_ble_ll_resolv_enable_cmd = 0x40001364; +r_ble_ll_resolv_enabled = 0x40001368; +r_ble_ll_resolv_env_init = 0x4000136c; +r_ble_ll_resolv_gen_priv_addr = 0x40001370; +r_ble_ll_resolv_gen_rpa = 0x40001374; +r_ble_ll_resolv_get_addr_pointer = 0x40001378; +r_ble_ll_resolv_get_entry = 0x4000137c; +r_ble_ll_resolv_get_index = 0x40001380; +r_ble_ll_resolv_get_irk_pointer = 0x40001384; +r_ble_ll_resolv_get_list = 0x40001388; +r_ble_ll_resolv_get_priv_addr = 0x4000138c; +r_ble_ll_resolv_get_rpa_tmo = 0x40001390; +r_ble_ll_resolv_init = 0x40001394; +r_ble_ll_resolv_irk_nonzero = 0x40001398; +r_ble_ll_resolv_list_add = 0x4000139c; +r_ble_ll_resolv_list_chg_allowed = 0x400013a0; +r_ble_ll_resolv_list_clr = 0x400013a4; +r_ble_ll_resolv_list_find = 0x400013a8; +r_ble_ll_resolv_list_read_size = 0x400013ac; +r_ble_ll_resolv_list_reset = 0x400013b0; +r_ble_ll_resolv_list_rmv = 0x400013b4; +r_ble_ll_resolv_local_addr_rd = 0x400013b8; +r_ble_ll_resolv_peer_addr_rd = 0x400013bc; +r_ble_ll_resolv_peer_rpa_any = 0x400013c0; +r_ble_ll_resolv_reset = 0x400013c4; +r_ble_ll_resolv_rpa = 0x400013c8; +r_ble_ll_resolv_rpa_timer_cb = 0x400013cc; +r_ble_ll_resolv_set_local_rpa = 0x400013d0; +r_ble_ll_resolv_set_peer_rpa = 0x400013d4; +r_ble_ll_resolv_set_rpa_tmo = 0x400013d8; +r_ble_ll_resolve_set_priv_mode = 0x400013dc; +r_ble_ll_rfmgmt_controller_sleep_en = 0x400013e0; +r_ble_ll_rfmgmt_deinit = 0x400013e4; +r_ble_ll_rfmgmt_disable = 0x400013e8; +r_ble_ll_rfmgmt_enable = 0x400013ec; +r_ble_ll_rfmgmt_enable_now = 0x400013f0; +r_ble_ll_rfmgmt_init = 0x400013f4; +r_ble_ll_rfmgmt_is_enabled = 0x400013f8; +r_ble_ll_rfmgmt_release = 0x400013fc; +r_ble_ll_rfmgmt_release_ev = 0x40001400; +r_ble_ll_rfmgmt_reset = 0x40001404; +r_ble_ll_rfmgmt_scan_changed = 0x40001408; +r_ble_ll_rfmgmt_sched_changed = 0x4000140c; +r_ble_ll_rfmgmt_set_sleep_cb = 0x40001410; +r_ble_ll_rfmgmt_ticks_to_enabled = 0x40001414; +r_ble_ll_rfmgmt_timer_exp = 0x40001418; +r_ble_ll_rfmgmt_timer_reschedule = 0x4000141c; +r_ble_ll_rx_end = 0x40001420; +r_ble_ll_rx_pdu_in = 0x40001424; +r_ble_ll_rx_pkt_in = 0x40001428; +r_ble_ll_rx_start = 0x4000142c; +r_ble_ll_rxpdu_alloc = 0x40001430; +r_ble_ll_scan_add_scan_rsp_adv = 0x40001434; +r_ble_ll_scan_adv_decode_addr = 0x40001438; +r_ble_ll_scan_aux_data_free = 0x4000143c; +r_ble_ll_scan_aux_data_ref = 0x40001440; +r_ble_ll_scan_aux_data_unref = 0x40001444; +r_ble_ll_scan_can_chg_whitelist = 0x40001448; +r_ble_ll_scan_check_periodic_sync = 0x4000144c; +r_ble_ll_scan_chk_resume = 0x40001450; +r_ble_ll_scan_clean_cur_aux_data = 0x40001454; +r_ble_ll_scan_common_init = 0x40001458; +r_ble_ll_scan_continue_en = 0x4000145c; +r_ble_ll_scan_deinit = 0x40001460; +r_ble_ll_scan_dup_check_ext = 0x40001464; +r_ble_ll_scan_dup_check_legacy = 0x40001468; +r_ble_ll_scan_dup_move_to_head = 0x4000146c; +r_ble_ll_scan_dup_new = 0x40001470; +r_ble_ll_scan_dup_update_ext = 0x40001474; +r_ble_ll_scan_dup_update_legacy = 0x40001478; +r_ble_ll_scan_duration_period_timers_restart = 0x4000147c; +r_ble_ll_scan_duration_timer_cb = 0x40001480; +r_ble_ll_scan_enabled = 0x40001484; +r_ble_ll_scan_end_adv_evt = 0x40001488; +r_ble_ll_scan_env_init = 0x4000148c; +r_ble_ll_scan_event_proc = 0x40001490; +r_ble_ll_scan_ext_adv_init = 0x40001494; +r_ble_ll_scan_ext_initiator_start = 0x40001498; +r_ble_ll_scan_get_addr_data_from_legacy = 0x4000149c; +r_ble_ll_scan_get_addr_from_ext_adv = 0x400014a0; +r_ble_ll_scan_get_cur_sm = 0x400014a4; +r_ble_ll_scan_get_ext_adv_report = 0x400014a8; +r_ble_ll_scan_get_local_rpa = 0x400014ac; +r_ble_ll_scan_get_next_adv_prim_chan = 0x400014b0; +r_ble_ll_scan_get_pdu_data = 0x400014b4; +r_ble_ll_scan_get_peer_rpa = 0x400014b8; +r_ble_ll_scan_halt = 0x400014bc; +r_ble_ll_scan_has_sent_scan_req = 0x400014c0; +r_ble_ll_scan_have_rxd_scan_rsp = 0x400014c4; +r_ble_ll_scan_init = 0x400014c8; +r_ble_ll_scan_initiator_start = 0x400014cc; +r_ble_ll_scan_interrupted = 0x400014d0; +r_ble_ll_scan_interrupted_event_cb = 0x400014d4; +r_ble_ll_scan_is_inside_window = 0x400014d8; +r_ble_ll_scan_move_window_to = 0x400014dc; +r_ble_ll_scan_npl_init = 0x400014e0; +r_ble_ll_scan_npl_reset = 0x400014e4; +r_ble_ll_scan_npl_restore = 0x400014e8; +r_ble_ll_scan_npl_store = 0x400014ec; +r_ble_ll_scan_parse_ext_hdr = 0x400014f0; +r_ble_ll_scan_period_timer_cb = 0x400014f4; +r_ble_ll_scan_record_new_adv = 0x400014f8; +r_ble_ll_scan_refresh_nrpa = 0x400014fc; +r_ble_ll_scan_req_backoff = 0x40001500; +r_ble_ll_scan_reset = 0x40001504; +r_ble_ll_scan_rx_filter = 0x40001508; +r_ble_ll_scan_rx_isr_end = 0x4000150c; +r_ble_ll_scan_rx_isr_on_aux = 0x40001510; +r_ble_ll_scan_rx_isr_on_legacy = 0x40001514; +r_ble_ll_scan_rx_isr_start = 0x40001518; +r_ble_ll_scan_rx_pkt_in = 0x4000151c; +r_ble_ll_scan_rx_pkt_in_on_aux = 0x40001520; +r_ble_ll_scan_rx_pkt_in_on_legacy = 0x40001524; +r_ble_ll_scan_rx_pkt_in_restore_addr_data = 0x40001528; +r_ble_ll_scan_rxed = 0x4000152c; +r_ble_ll_scan_sched_remove = 0x40001530; +r_ble_ll_scan_send_adv_report = 0x40001534; +r_ble_ll_scan_send_truncated = 0x40001538; +r_ble_ll_scan_set_enable = 0x4000153c; +r_ble_ll_scan_set_peer_rpa = 0x40001540; +r_ble_ll_scan_set_scan_params = 0x40001544; +r_ble_ll_scan_sm_start = 0x40001548; +r_ble_ll_scan_sm_stop = 0x4000154c; +r_ble_ll_scan_start = 0x40001550; +r_ble_ll_scan_time_hci_to_ticks = 0x40001554; +r_ble_ll_scan_timer_cb = 0x40001558; +r_ble_ll_scan_update_aux_data = 0x4000155c; +r_ble_ll_scan_wfr_timer_exp = 0x40001560; +r_ble_ll_scan_whitelist_enabled = 0x40001564; +r_ble_ll_sched_adv_new = 0x40001568; +r_ble_ll_sched_adv_resched_pdu = 0x4000156c; +r_ble_ll_sched_adv_reschedule = 0x40001570; +r_ble_ll_sched_aux_scan = 0x40001574; +r_ble_ll_sched_conn_overlap = 0x40001578; +r_ble_ll_sched_conn_reschedule = 0x4000157c; +r_ble_ll_sched_deinit = 0x40001580; +r_ble_ll_sched_dtm = 0x40001584; +r_ble_ll_sched_env_init = 0x40001588; +r_ble_ll_sched_execute_item = 0x4000158c; +r_ble_ll_sched_init = 0x40001590; +r_ble_ll_sched_insert_if_empty = 0x40001594; +r_ble_ll_sched_is_overlap = 0x40001598; +r_ble_ll_sched_master_new = 0x4000159c; +r_ble_ll_sched_next_time = 0x400015a0; +r_ble_ll_sched_overlaps_current = 0x400015a4; +r_ble_ll_sched_periodic_adv = 0x400015a8; +r_ble_ll_sched_rmv_elem = 0x400015ac; +r_ble_ll_sched_rmv_elem_type = 0x400015b0; +r_ble_ll_sched_run = 0x400015b4; +r_ble_ll_sched_scan_req_over_aux_ptr = 0x400015b8; +r_ble_ll_sched_slave_new = 0x400015bc; +r_ble_ll_sched_stop = 0x400015c0; +r_ble_ll_sched_sync = 0x400015c4; +r_ble_ll_sched_sync_overlaps_current = 0x400015c8; +r_ble_ll_sched_sync_reschedule = 0x400015cc; +r_ble_ll_set_default_privacy_mode = 0x400015d0; +r_ble_ll_set_default_sync_transfer_params = 0x400015d4; +r_ble_ll_set_ext_scan_params = 0x400015d8; +r_ble_ll_set_host_feat = 0x400015dc; +r_ble_ll_set_public_addr = 0x400015e0; +r_ble_ll_set_random_addr = 0x400015e4; +r_ble_ll_set_sync_transfer_params = 0x400015e8; +r_ble_ll_slave_rx_isr_end = 0x400015ec; +r_ble_ll_state_get = 0x400015f0; +r_ble_ll_state_set = 0x400015f4; +r_ble_ll_sync_adjust_ext_hdr = 0x400015f8; +r_ble_ll_sync_cancel = 0x400015fc; +r_ble_ll_sync_cancel_complete_event = 0x40001600; +r_ble_ll_sync_chain_start_cb = 0x40001604; +r_ble_ll_sync_check_acad = 0x40001608; +r_ble_ll_sync_check_failed = 0x4000160c; +r_ble_ll_sync_coex_dpc_process = 0x40001610; +r_ble_ll_sync_coex_dpc_pti_get = 0x40001614; +r_ble_ll_sync_coex_dpc_update = 0x40001618; +r_ble_ll_sync_create = 0x4000161c; +r_ble_ll_sync_current_sm_over = 0x40001620; +r_ble_ll_sync_deinit = 0x40001624; +r_ble_ll_sync_enabled = 0x40001628; +r_ble_ll_sync_env_init = 0x4000162c; +r_ble_ll_sync_est_event_failed = 0x40001630; +r_ble_ll_sync_est_event_success = 0x40001634; +r_ble_ll_sync_established = 0x40001638; +r_ble_ll_sync_event_end = 0x4000163c; +r_ble_ll_sync_event_start_cb = 0x40001640; +r_ble_ll_sync_filter_enabled = 0x40001644; +r_ble_ll_sync_find = 0x40001648; +r_ble_ll_sync_get_cur_sm = 0x4000164c; +r_ble_ll_sync_get_event_end_time = 0x40001650; +r_ble_ll_sync_get_handle = 0x40001654; +r_ble_ll_sync_halt = 0x40001658; +r_ble_ll_sync_has_been_reported = 0x4000165c; +r_ble_ll_sync_info_event = 0x40001660; +r_ble_ll_sync_init = 0x40001664; +r_ble_ll_sync_list_add = 0x40001668; +r_ble_ll_sync_list_clear = 0x4000166c; +r_ble_ll_sync_list_empty = 0x40001670; +r_ble_ll_sync_list_get_free = 0x40001674; +r_ble_ll_sync_list_remove = 0x40001678; +r_ble_ll_sync_list_search = 0x4000167c; +r_ble_ll_sync_list_size = 0x40001680; +r_ble_ll_sync_lost_event = 0x40001684; +r_ble_ll_sync_next_event = 0x40001688; +r_ble_ll_sync_on_list = 0x4000168c; +r_ble_ll_sync_parse_aux_ptr = 0x40001690; +r_ble_ll_sync_parse_ext_hdr = 0x40001694; +r_ble_ll_sync_periodic_ind = 0x40001698; +r_ble_ll_sync_phy_mode_to_aux_phy = 0x4000169c; +r_ble_ll_sync_phy_mode_to_hci = 0x400016a0; +r_ble_ll_sync_put_syncinfo = 0x400016a4; +r_ble_ll_sync_reserve = 0x400016a8; +r_ble_ll_sync_reset = 0x400016ac; +r_ble_ll_sync_reset_sm = 0x400016b0; +r_ble_ll_sync_rmvd_from_sched = 0x400016b4; +r_ble_ll_sync_rx_isr_end = 0x400016b8; +r_ble_ll_sync_rx_isr_start = 0x400016bc; +r_ble_ll_sync_rx_pkt_in = 0x400016c0; +r_ble_ll_sync_schedule_chain = 0x400016c4; +r_ble_ll_sync_send_per_adv_rpt = 0x400016c8; +r_ble_ll_sync_send_sync_ind = 0x400016cc; +r_ble_ll_sync_send_truncated_per_adv_rpt = 0x400016d0; +r_ble_ll_sync_sm_clear = 0x400016d4; +r_ble_ll_sync_terminate = 0x400016d8; +r_ble_ll_sync_transfer = 0x400016dc; +r_ble_ll_sync_transfer_get = 0x400016e0; +r_ble_ll_sync_transfer_received = 0x400016e4; +r_ble_ll_sync_wfr_timer_exp = 0x400016e8; +r_ble_ll_task = 0x400016ec; +r_ble_ll_trace_set_func = 0x400016f0; +r_ble_ll_trace_u32 = 0x400016f4; +r_ble_ll_trace_u32x2 = 0x400016f8; +r_ble_ll_trace_u32x3 = 0x400016fc; +r_ble_ll_tx_flat_mbuf_pducb = 0x40001700; +r_ble_ll_tx_mbuf_pducb = 0x40001704; +r_ble_ll_tx_pkt_in = 0x40001708; +r_ble_ll_update_max_tx_octets_phy_mode = 0x4000170c; +r_ble_ll_usecs_to_ticks_round_up = 0x40001710; +r_ble_ll_utils_calc_access_addr = 0x40001714; +r_ble_ll_utils_calc_dci_csa2 = 0x40001718; +r_ble_ll_utils_calc_num_used_chans = 0x4000171c; +r_ble_ll_utils_calc_window_widening = 0x40001720; +r_ble_ll_utils_csa2_perm = 0x40001724; +r_ble_ll_utils_csa2_prng = 0x40001728; +r_ble_ll_utils_remapped_channel = 0x4000172c; +r_ble_ll_wfr_timer_exp = 0x40001730; +r_ble_ll_whitelist_add = 0x40001734; +r_ble_ll_whitelist_chg_allowed = 0x40001738; +r_ble_ll_whitelist_clear = 0x4000173c; +r_ble_ll_whitelist_read_size = 0x40001740; +r_ble_ll_whitelist_rmv = 0x40001744; +r_ble_ll_whitelist_search = 0x40001748; +r_ble_ll_write_rf_path_compensation = 0x4000174c; +r_ble_phy_access_addr_get = 0x40001750; +r_ble_phy_bb_bug_is_triggered = 0x40001754; +r_ble_phy_calculate_rxtx_ifs = 0x40001758; +r_ble_phy_calculate_rxwindow = 0x4000175c; +r_ble_phy_calculate_txrx_ifs = 0x40001760; +r_ble_phy_config_access_addr = 0x40001764; +r_ble_phy_data_make = 0x40001768; +r_ble_phy_disable = 0x4000176c; +r_ble_phy_disable_irq = 0x40001770; +r_ble_phy_disable_whitening = 0x40001774; +r_ble_phy_enable_scan_seq_immediately = 0x40001778; +r_ble_phy_enable_whitening = 0x4000177c; +r_ble_phy_encrypt_disable = 0x40001780; +r_ble_phy_env_init = 0x40001784; +r_ble_phy_get_current_phy = 0x40001788; +r_ble_phy_get_packet_counter = 0x4000178c; +r_ble_phy_get_packet_status = 0x40001790; +r_ble_phy_get_pyld_time_offset = 0x40001794; +r_ble_phy_get_rx_phy_mode = 0x40001798; +r_ble_phy_init = 0x4000179c; +r_ble_phy_isr = 0x400017a0; +r_ble_phy_max_data_pdu_pyld = 0x400017a4; +r_ble_phy_mode_config = 0x400017a8; +r_ble_phy_mode_convert = 0x400017ac; +r_ble_phy_mode_write = 0x400017b0; +r_ble_phy_module_deinit = 0x400017b4; +r_ble_phy_module_init = 0x400017b8; +r_ble_phy_monitor_bb_sync = 0x400017bc; +r_ble_phy_need_to_report = 0x400017c0; +r_ble_phy_pkt_received = 0x400017c4; +r_ble_phy_reset_bb_monitor = 0x400017c8; +r_ble_phy_resolv_list_disable = 0x400017cc; +r_ble_phy_resolv_list_enable = 0x400017d0; +r_ble_phy_restart_sequence = 0x400017d4; +r_ble_phy_rfclk_disable = 0x400017d8; +r_ble_phy_rfclk_enable = 0x400017dc; +r_ble_phy_rx_is_expected = 0x400017e0; +r_ble_phy_rxpdu_copy = 0x400017e4; +r_ble_phy_scan_set_start_time = 0x400017e8; +r_ble_phy_seq_encrypt_enable = 0x400017ec; +r_ble_phy_seq_encrypt_set_pkt_cntr = 0x400017f0; +r_ble_phy_sequence_adv_end = 0x400017f4; +r_ble_phy_sequence_copy_rx_flags = 0x400017f8; +r_ble_phy_sequence_end_isr = 0x400017fc; +r_ble_phy_sequence_get_mode = 0x40001800; +r_ble_phy_sequence_get_state = 0x40001804; +r_ble_phy_sequence_init_end = 0x40001808; +r_ble_phy_sequence_is_running = 0x4000180c; +r_ble_phy_sequence_is_waiting_rsp = 0x40001810; +r_ble_phy_sequence_isr_copy_data = 0x40001814; +r_ble_phy_sequence_master_end = 0x40001818; +r_ble_phy_sequence_rx_end_isr = 0x4000181c; +r_ble_phy_sequence_scan_end = 0x40001820; +r_ble_phy_sequence_single_end = 0x40001824; +r_ble_phy_sequence_slave_end = 0x40001828; +r_ble_phy_sequence_tx_end_invoke = 0x4000182c; +r_ble_phy_sequence_update_conn_params = 0x40001830; +r_ble_phy_set_adv_sequence = 0x40001834; +r_ble_phy_set_coex_pti = 0x40001838; +r_ble_phy_set_dev_address = 0x4000183c; +r_ble_phy_set_master_sequence = 0x40001840; +r_ble_phy_set_rx_pwr_compensation = 0x40001844; +r_ble_phy_set_rxhdr_flags = 0x40001848; +r_ble_phy_set_rxhdr_info = 0x4000184c; +r_ble_phy_set_scan_sequence = 0x40001850; +r_ble_phy_set_single_packet_rx_sequence = 0x40001854; +r_ble_phy_set_single_packet_tx_sequence = 0x40001858; +r_ble_phy_set_slave_sequence = 0x4000185c; +r_ble_phy_set_txend_cb = 0x40001860; +r_ble_phy_setchan = 0x40001864; +r_ble_phy_slave_set_start_time = 0x40001868; +r_ble_phy_state_get = 0x4000186c; +r_ble_phy_timer_config_start_time = 0x40001870; +r_ble_phy_timer_start_now = 0x40001874; +r_ble_phy_timer_stop = 0x40001878; +r_ble_phy_tx_set_start_time = 0x4000187c; +r_ble_phy_txpower_round = 0x40001880; +r_ble_phy_txpwr_set = 0x40001884; +r_ble_phy_wfr_enable = 0x40001888; +r_ble_phy_xcvr_state_get = 0x4000188c; +r_ble_plf_set_log_level = 0x40001890; +r_ble_vendor_hci_register = 0x40001894; +r_bleonly_os_tick_init = 0x40001898; +r_bt_rf_coex_cfg_set = 0x4000189c; +r_bt_rf_coex_coded_txrx_time_upper_lim = 0x400018a0; +r_bt_rf_coex_dft_pti_set = 0x400018a4; +r_bt_rf_coex_hook_deinit = 0x400018a8; +r_bt_rf_coex_hook_init = 0x400018ac; +r_bt_rf_coex_hook_st_set = 0x400018b0; +r_bt_rf_coex_hooks_p_set_default = 0x400018b4; +r_btdm_disable_adv_delay = 0x400018b8; +r_btdm_switch_phy_coded = 0x400018bc; +r_esp_wait_disabled = 0x400018c0; +r_get_be16 = 0x400018c4; +r_get_be24 = 0x400018c8; +r_get_be32 = 0x400018cc; +r_get_be64 = 0x400018d0; +r_get_le16 = 0x400018d4; +r_get_le24 = 0x400018d8; +r_get_le32 = 0x400018dc; +r_get_le64 = 0x400018e0; +r_get_local_irk_offset = 0x400018e4; +r_get_local_rpa_offset = 0x400018e8; +r_get_max_skip = 0x400018ec; +r_get_peer_id_offset = 0x400018f0; +r_get_peer_irk_offset = 0x400018f4; +r_get_peer_rpa_offset = 0x400018f8; +r_hal_os_tick_read_tick = 0x400018fc; +r_hal_os_tick_set_exp_tick = 0x40001900; +r_hal_rtc_intr_init = 0x40001904; +r_hal_rtc_irq_handler = 0x40001908; +r_hal_timer_deinit = 0x4000190c; +r_hal_timer_disable_irq = 0x40001910; +r_hal_timer_env_init = 0x40001914; +r_hal_timer_init = 0x40001918; +r_hal_timer_process = 0x4000191c; +r_hal_timer_read = 0x40001920; +r_hal_timer_read_tick = 0x40001924; +r_hal_timer_set_cb = 0x40001928; +r_hal_timer_set_exp_tick = 0x4000192c; +r_hal_timer_start = 0x40001930; +r_hal_timer_start_at = 0x40001934; +r_hal_timer_stop = 0x40001938; +r_hal_timer_task_start = 0x4000193c; +r_ll_assert = 0x40001940; +r_mem_init_mbuf_pool = 0x40001944; +r_mem_malloc_mbuf_pool = 0x40001948; +r_mem_malloc_mbufpkt_pool = 0x4000194c; +r_mem_malloc_mempool = 0x40001950; +r_mem_malloc_mempool_ext = 0x40001954; +r_mem_malloc_mempool_gen = 0x40001958; +r_mem_pullup_obj = 0x4000195c; +r_mem_split_frag = 0x40001960; +r_os_cputime_delay_ticks = 0x40001964; +r_os_cputime_delay_usecs = 0x40001968; +r_os_cputime_get32 = 0x4000196c; +r_os_cputime_ticks_to_usecs = 0x40001970; +r_os_cputime_timer_init = 0x40001974; +r_os_cputime_timer_relative = 0x40001978; +r_os_cputime_timer_start = 0x4000197c; +r_os_cputime_timer_stop = 0x40001980; +r_os_cputime_usecs_to_ticks = 0x40001984; +r_os_mbuf_adj = 0x40001988; +r_os_mbuf_append = 0x4000198c; +r_os_mbuf_appendfrom = 0x40001990; +r_os_mbuf_cmpf = 0x40001994; +r_os_mbuf_cmpm = 0x40001998; +r_os_mbuf_concat = 0x4000199c; +r_os_mbuf_copydata = 0x400019a0; +r_os_mbuf_copyinto = 0x400019a4; +r_os_mbuf_dup = 0x400019a8; +r_os_mbuf_extend = 0x400019ac; +r_os_mbuf_free = 0x400019b0; +r_os_mbuf_free_chain = 0x400019b4; +r_os_mbuf_get = 0x400019b8; +r_os_mbuf_get_pkthdr = 0x400019bc; +r_os_mbuf_len = 0x400019c0; +r_os_mbuf_off = 0x400019c4; +r_os_mbuf_pack_chains = 0x400019c8; +r_os_mbuf_pool_init = 0x400019cc; +r_os_mbuf_prepend = 0x400019d0; +r_os_mbuf_prepend_pullup = 0x400019d4; +r_os_mbuf_pullup = 0x400019d8; +r_os_mbuf_trim_front = 0x400019dc; +r_os_mbuf_widen = 0x400019e0; +r_os_memblock_from = 0x400019e4; +r_os_memblock_get = 0x400019e8; +r_os_memblock_put = 0x400019ec; +r_os_memblock_put_from_cb = 0x400019f0; +r_os_mempool_clear = 0x400019f4; +r_os_mempool_ext_clear = 0x400019f8; +r_os_mempool_ext_init = 0x400019fc; +r_os_mempool_info_get_next = 0x40001a00; +r_os_mempool_init = 0x40001a04; +r_os_mempool_init_internal = 0x40001a08; +r_os_mempool_is_sane = 0x40001a0c; +r_os_mempool_module_init = 0x40001a10; +r_os_mempool_unregister = 0x40001a14; +r_os_mqueue_get = 0x40001a18; +r_os_mqueue_init = 0x40001a1c; +r_os_mqueue_put = 0x40001a20; +r_os_msys_count = 0x40001a24; +r_os_msys_get = 0x40001a28; +r_os_msys_get_pkthdr = 0x40001a2c; +r_os_msys_num_free = 0x40001a30; +r_os_msys_register = 0x40001a34; +r_os_msys_reset = 0x40001a38; +r_os_tick_idle = 0x40001a3c; +r_pri_phy_valid = 0x40001a40; +r_put_be16 = 0x40001a44; +r_put_be24 = 0x40001a48; +r_put_be32 = 0x40001a4c; +r_put_be64 = 0x40001a50; +r_put_le16 = 0x40001a54; +r_put_le24 = 0x40001a58; +r_put_le32 = 0x40001a5c; +r_put_le64 = 0x40001a60; +r_rtc0_timer_handler = 0x40001a64; +r_rtc1_timer_handler = 0x40001a68; +r_sdkconfig_get_opts = 0x40001a6c; +r_sdkconfig_set_opts = 0x40001a70; +r_sec_phy_valid = 0x40001a74; +r_sub24 = 0x40001a78; +r_swap_buf = 0x40001a7c; +r_swap_in_place = 0x40001a80; +/* Data (.data, .bss, .rodata) */ +ble_hci_uart_reset_cmd = 0x3ff1ffe0; +ble_hci_trans_env_p = 0x3fcdffc4; +ble_hci_trans_mode = 0x3fcdfebc; +ble_ll_adv_env_p = 0x3fcdffc0; +ble_ll_conn_env_p = 0x3fcdffbc; +g_ble_ll_conn_cth_flow = 0x3fcdffb4; +g_ble_ll_conn_cth_flow_error_ev = 0x3fcdffb0; +g_ble_ll_ctrl_pkt_lengths_ro = 0x3ff1ffbc; +ble_ll_dtm_module_env_p = 0x3fcdffac; +channel_rf_to_index = 0x3ff1ff94; +g_ble_ll_dtm_prbs15_data = 0x3ff1fe94; +g_ble_ll_dtm_prbs9_data = 0x3ff1fd94; +ble_ll_hci_env_p = 0x3fcdffa8; +ble_ll_rand_env_p = 0x3fcdffa4; +ble_ll_resolv_env_p = 0x3fcdffa0; +g_ble_ll_resolve_hdr = 0x3fcdff98; +g_device_mode_default = 0x3fcdfeba; +g_ble_ll_rfmgmt_data = 0x3fcdff50; +g_ble_sleep_enter_cb = 0x3fcdff4c; +g_ble_sleep_exit_cb = 0x3fcdff48; +g_rfclk_enabled = 0x3fcdff44; +ble_ll_scan_env_p = 0x3fcdff40; +ble_ll_sched_env_p = 0x3fcdff3c; +g_ble_ll_supp_cmds_ro = 0x3ff1fd64; +ble_ll_sync_env_p = 0x3fcdff38; +g_ble_sca_ppm_tbl_ro = 0x3ff1fd54; +ble_ll_env_p = 0x3fcdff34; +g_ble_ll_pdu_header_tx_time_ro = 0x3ff1fd4c; +priv_config_opts = 0x3fcdfea4; +ble_hci_trans_funcs_ptr = 0x3fcdff30; +r_ble_stub_funcs_ptr = 0x3fcdff2c; +r_ext_funcs_p = 0x3fcdff28; +r_npl_funcs = 0x3fcdff24; +ble_hw_env_p = 0x3fcdff20; +ble_phy_module_env_p = 0x3fcdff1c; +g_ble_phy_chan_freq_ro = 0x3ff1fd24; +g_ble_phy_mode_pkt_start_off_ro = 0x3ff1fd1c; +g_ble_phy_rxtx_ifs_compensation_ro = 0x3ff1fd0c; +g_ble_phy_t_rxaddrdelay_ro = 0x3ff1fd08; +g_ble_phy_t_rxenddelay_ro = 0x3ff1fd04; +g_ble_phy_t_txdelay_ro = 0x3ff1fd00; +g_ble_phy_t_txenddelay_ro = 0x3ff1fcfc; +g_ble_phy_txrx_ifs_compensation_ro = 0x3ff1fcec; +hal_timer_env_p = 0x3fcdff18; +g_hal_os_tick = 0x3fcdff0c; +r_osi_coex_funcs_p = 0x3fcdff08; +bt_rf_coex_hooks = 0x3fcdff00; +bt_rf_coex_hooks_p = 0x3fcdfefc; +coex_hook_st_group_tab = 0x3ff1fce0; +coex_hook_st_group_to_coex_schm_st_tab = 0x3ff1fcdc; +s_ble_act_count_by_group = 0x3fcdfef8; +s_ble_coex_st_map = 0x3fcdfee4; +bt_rf_coex_cfg_cb = 0x3fcdfec8; +bt_rf_coex_cfg_p = 0x3fcdfec4; +bt_rf_coex_cfg_rom = 0x3ff1fcc0; +bt_rf_coex_pti_dft_p = 0x3fcdfec0; +bt_rf_coex_pti_dft_rom = 0x3fcdfe64; +conn_dynamic_pti_param_rom = 0x3ff1fca8; +conn_phy_coded_max_data_time_param_rom = 0x3ff1fca4; +ext_adv_dynamic_pti_param_rom = 0x3ff1fc70; +ext_scan_dynamic_param_rom = 0x3ff1fc38; +legacy_adv_dynamic_pti_param_rom = 0x3ff1fc18; +per_adv_dynamic_pti_param_rom = 0x3ff1fbfc; +sync_dynamic_param_rom = 0x3ff1fbe4; +g_ble_plf_log_level = 0x3fcdfe60; +g_msys_pool_list = 0x3fcdfe58; +g_os_mempool_list = 0x3fcdfe50; + + +/*************************************** + Group rom_phy + ***************************************/ + +/* Functions */ +phy_param_addr = 0x40001a84; +phy_get_romfuncs = 0x40001a88; +chip729_phyrom_version = 0x40001a8c; +chip729_phyrom_version_num = 0x40001a90; +rom_get_i2c_read_mask = 0x40001c6c; +rom_get_i2c_mst0_mask = 0x40001c70; +rom_get_i2c_hostid = 0x40001c74; +rom_chip_i2c_readReg_org = 0x40001c78; +rom_chip_i2c_readReg = 0x40001c7c; +rom_i2c_paral_set_mst0 = 0x40001c80; +rom_i2c_paral_set_read = 0x40001c84; +rom_i2c_paral_read = 0x40001c88; +rom_i2c_paral_write = 0x40001c8c; +rom_i2c_paral_write_num = 0x40001c90; +rom_i2c_paral_write_mask = 0x40001c94; +rom_i2c_readReg = 0x40001c98; +rom_chip_i2c_writeReg = 0x40001c9c; +rom_i2c_writeReg = 0x40001ca0; +rom_i2c_readReg_Mask = 0x40001ca4; +rom_i2c_writeReg_Mask = 0x40001ca8; +/* Data (.data, .bss, .rodata) */ +phy_param_rom = 0x3fcdfe4c; diff --git a/tools/flasher_stub/ld/rom_32p4.ld b/tools/flasher_stub/ld/rom_32p4.ld new file mode 100644 index 0000000000..89bd00f3be --- /dev/null +++ b/tools/flasher_stub/ld/rom_32p4.ld @@ -0,0 +1,631 @@ +/* ROM function interface esp32p4.rom.ld for esp32p4 + * + * + * Generated from ./target/esp32p4/interface-esp32p4.yml md5sum f6516bd9708d890f63db87f8aed53ca7 + * + * Compatible with ROM where ECO version equal or greater to 0. + * + * THIS FILE WAS AUTOMATICALLY GENERATED. DO NOT EDIT. + */ + +/*************************************** + Group common + ***************************************/ + +PROVIDE ( SPIWrite = esp_rom_spiflash_write); +PROVIDE ( SPI_read_status_high = esp_rom_spiflash_read_statushigh); +PROVIDE ( SPI_write_status = esp_rom_spiflash_write_status); +PROVIDE ( SPIRead = esp_rom_spiflash_read); +PROVIDE ( SPIParamCfg = esp_rom_spiflash_config_param); +PROVIDE ( SPIEraseChip = esp_rom_spiflash_erase_chip); +PROVIDE ( SPIEraseSector = esp_rom_spiflash_erase_sector); +PROVIDE ( SPIEraseBlock = esp_rom_spiflash_erase_block); +PROVIDE ( SPI_Write_Encrypt_Enable = esp_rom_spiflash_write_encrypted_enable); +PROVIDE ( SPI_Write_Encrypt_Disable = esp_rom_spiflash_write_encrypted_disable); +PROVIDE ( SPI_Encrypt_Write = esp_rom_spiflash_write_encrypted); + +/*************************************** + Group common + ***************************************/ + +/* Functions */ +rtc_get_reset_reason = 0x4fc00018; +rtc_get_wakeup_cause = 0x4fc0001c; +pmu_enable_unhold_pads = 0x4fc00020; +ets_printf = 0x4fc00024; +ets_install_putc1 = 0x4fc00028; +ets_install_putc2 = 0x4fc0002c; +ets_install_uart_printf = 0x4fc00030; +ets_install_usb_printf = 0x4fc00034; +ets_get_printf_channel = 0x4fc00038; +ets_delay_us = 0x4fc0003c; +ets_get_cpu_frequency = 0x4fc00040; +ets_update_cpu_frequency = 0x4fc00044; +ets_install_lock = 0x4fc00048; +UartRxString = 0x4fc0004c; +UartGetCmdLn = 0x4fc00050; +uart_tx_one_char = 0x4fc00054; +uart_tx_one_char2 = 0x4fc00058; +uart_tx_one_char3 = 0x4fc0005c; +uart_rx_one_char = 0x4fc00060; +uart_rx_one_char_block = 0x4fc00064; +uart_rx_intr_handler = 0x4fc00068; +uart_rx_readbuff = 0x4fc0006c; +uartAttach = 0x4fc00070; +uart_tx_flush = 0x4fc00074; +uart_tx_wait_idle = 0x4fc00078; +uart_div_modify = 0x4fc0007c; +ets_write_char_uart = 0x4fc00080; +uart_tx_switch = 0x4fc00084; +uart_buff_switch = 0x4fc00088; +roundup2 = 0x4fc0008c; +multofup = 0x4fc00090; +software_reset = 0x4fc00094; +software_reset_cpu = 0x4fc00098; +ets_clk_assist_debug_clock_enable = 0x4fc0009c; +clear_super_wdt_reset_flag = 0x4fc000a0; +disable_default_watchdog = 0x4fc000a4; +ets_set_appcpu_boot_addr = 0x4fc000a8; +send_packet = 0x4fc000ac; +recv_packet = 0x4fc000b0; +GetUartDevice = 0x4fc000b4; +UartDwnLdProc = 0x4fc000b8; +GetSecurityInfoProc = 0x4fc000bc; +Uart_Init = 0x4fc000c0; +ets_set_user_start = 0x4fc000c4; +/* Data (.data, .bss, .rodata) */ +ets_rom_layout_p = 0x4fc1fffc; +ets_ops_table_ptr = 0x4ff3fff4; +g_saved_pc = 0x4ff3fff8; +memcpy = 0x4fc0026c; +esp_rom_opiflash_exec_cmd_eco1 = 0x4fc0fe76; +esp_rom_opiflash_exec_cmd_eco2 = 0x4fc10320; + + +/*************************************** + Group miniz + ***************************************/ + +/* Functions */ +mz_adler32 = 0x4fc000c8; +mz_free = 0x4fc000cc; +tdefl_compress = 0x4fc000d0; +tdefl_compress_buffer = 0x4fc000d4; +tdefl_compress_mem_to_heap = 0x4fc000d8; +tdefl_compress_mem_to_mem = 0x4fc000dc; +tdefl_compress_mem_to_output = 0x4fc000e0; +tdefl_get_adler32 = 0x4fc000e4; +tdefl_get_prev_return_status = 0x4fc000e8; +tdefl_init = 0x4fc000ec; +tdefl_write_image_to_png_file_in_memory = 0x4fc000f0; +tdefl_write_image_to_png_file_in_memory_ex = 0x4fc000f4; +tinfl_decompress = 0x4fc000f8; +tinfl_decompress_mem_to_callback = 0x4fc000fc; +tinfl_decompress_mem_to_heap = 0x4fc00100; +tinfl_decompress_mem_to_mem = 0x4fc00104; + + +/*************************************** + Group spi_extmem_common + ***************************************/ + +/* Functions */ +esp_rom_spi_cmd_config = 0x4fc00108; +esp_rom_spi_cmd_start = 0x4fc0010c; +esp_rom_spi_set_op_mode = 0x4fc00110; +esp_rom_spi_set_dtr_swap_mode = 0x4fc00114; + + +/*************************************** + Group spiflash_legacy + ***************************************/ + +/* Functions */ +esp_rom_spiflash_wait_idle = 0x4fc00118; +esp_rom_spiflash_write_encrypted = 0x4fc0011c; +esp_rom_spiflash_write_encrypted_dest = 0x4fc00120; +esp_rom_spiflash_write_encrypted_enable = 0x4fc00124; +esp_rom_spiflash_write_encrypted_disable = 0x4fc00128; +esp_rom_spiflash_erase_chip = 0x4fc0012c; +_esp_rom_spiflash_erase_sector = 0x4fc00130; +_esp_rom_spiflash_erase_block = 0x4fc00134; +_esp_rom_spiflash_write = 0x4fc00138; +_esp_rom_spiflash_read = 0x4fc0013c; +_esp_rom_spiflash_unlock = 0x4fc00140; +_SPIEraseArea = 0x4fc00144; +_SPI_write_enable = 0x4fc00148; +esp_rom_spiflash_erase_sector = 0x4fc0014c; +esp_rom_spiflash_erase_block = 0x4fc00150; +esp_rom_spiflash_write = 0x4fc00154; +esp_rom_spiflash_read = 0x4fc00158; +esp_rom_spiflash_unlock = 0x4fc0015c; +SPIEraseArea = 0x4fc00160; +SPI_write_enable = 0x4fc00164; +esp_rom_spiflash_config_param = 0x4fc00168; +esp_rom_spiflash_read_user_cmd = 0x4fc0016c; +esp_rom_spiflash_select_qio_pins = 0x4fc00170; +esp_rom_spi_flash_auto_sus_res = 0x4fc00174; +esp_rom_spi_flash_send_resume = 0x4fc00178; +esp_rom_spi_flash_update_id = 0x4fc0017c; +esp_rom_spiflash_config_clk = 0x4fc00180; +esp_rom_spiflash_config_readmode = 0x4fc00184; +esp_rom_spiflash_read_status = 0x4fc00188; +esp_rom_spiflash_read_statushigh = 0x4fc0018c; +esp_rom_spiflash_write_status = 0x4fc00190; +esp_rom_spiflash_write_disable = 0x4fc00194; +spi_cache_mode_switch = 0x4fc00198; +spi_common_set_dummy_output = 0x4fc0019c; +spi_common_set_flash_cs_timing = 0x4fc001a0; +esp_rom_spi_set_address_bit_len = 0x4fc001a4; +SPILock = 0x4fc001a8; +SPIMasterReadModeCnfig = 0x4fc001ac; +SPI_Common_Command = 0x4fc001b0; +SPI_WakeUp = 0x4fc001b4; +SPI_block_erase = 0x4fc001b8; +SPI_chip_erase = 0x4fc001bc; +SPI_init = 0x4fc001c0; +SPI_page_program = 0x4fc001c4; +SPI_read_data = 0x4fc001c8; +SPI_sector_erase = 0x4fc001cc; +SelectSpiFunction = 0x4fc001d0; +SetSpiDrvs = 0x4fc001d4; +Wait_SPI_Idle = 0x4fc001d8; +spi_dummy_len_fix = 0x4fc001dc; +Disable_QMode = 0x4fc001e0; +Enable_QMode = 0x4fc001e4; +spi_flash_attach = 0x4fc001e8; +spi_flash_get_chip_size = 0x4fc001ec; +spi_flash_guard_set = 0x4fc001f0; +spi_flash_guard_get = 0x4fc001f4; +spi_flash_read_encrypted = 0x4fc001f8; +/* Data (.data, .bss, .rodata) */ +rom_spiflash_legacy_funcs = 0x4ff3ffec; +rom_spiflash_legacy_data = 0x4ff3ffe8; +g_flash_guard_ops = 0x4ff3fff0; + + +/*************************************** + Group hal_systimer + ***************************************/ + +/* Functions */ +systimer_hal_init = 0x4fc00228; +systimer_hal_deinit = 0x4fc0022c; +systimer_hal_set_tick_rate_ops = 0x4fc00230; +systimer_hal_get_counter_value = 0x4fc00234; +systimer_hal_get_time = 0x4fc00238; +systimer_hal_set_alarm_target = 0x4fc0023c; +systimer_hal_set_alarm_period = 0x4fc00240; +systimer_hal_get_alarm_value = 0x4fc00244; +systimer_hal_enable_alarm_int = 0x4fc00248; +systimer_hal_on_apb_freq_update = 0x4fc0024c; +systimer_hal_counter_value_advance = 0x4fc00250; +systimer_hal_enable_counter = 0x4fc00254; +systimer_hal_select_alarm_mode = 0x4fc00258; +systimer_hal_connect_alarm_counter = 0x4fc0025c; +systimer_hal_counter_can_stall_by_cpu = 0x4fc00260; + + +/*************************************** + Group cache + ***************************************/ + +/* Functions */ +Cache_Get_L1_ICache_Line_Size = 0x4fc003c4; +Cache_Get_L1_DCache_Line_Size = 0x4fc003c8; +Cache_Get_L2_Cache_Line_Size = 0x4fc003cc; +Cache_Get_Mode = 0x4fc003d0; +Cache_Set_L2_Cache_Mode = 0x4fc003d4; +Cache_Address_Through_Cache = 0x4fc003d8; +ROM_Boot_Cache_Init = 0x4fc003dc; +Cache_Sync_Addr = 0x4fc003e0; +Cache_Invalidate_Addr = 0x4fc003e4; +Cache_Invalidate_Addr_Gid = 0x4fc003e8; +Cache_Clean_Addr = 0x4fc003ec; +Cache_Clean_Addr_Gid = 0x4fc003f0; +Cache_WriteBack_Addr = 0x4fc003f4; +Cache_WriteBack_Addr_Gid = 0x4fc003f8; +Cache_WriteBack_Invalidate_Addr = 0x4fc003fc; +Cache_WriteBack_Invalidate_Addr_Gid = 0x4fc00400; +Cache_Invalidate_All = 0x4fc00404; +Cache_Invalidate_All_Gid = 0x4fc00408; +Cache_Clean_All = 0x4fc0040c; +Cache_Clean_All_Gid = 0x4fc00410; +Cache_WriteBack_All = 0x4fc00414; +Cache_WriteBack_All_Gid = 0x4fc00418; +Cache_WriteBack_Invalidate_All = 0x4fc0041c; +Cache_WriteBack_Invalidate_All_Gid = 0x4fc00420; +Cache_Mask_All = 0x4fc00424; +Cache_Suspend_L1_CORE0_ICache_Autoload = 0x4fc00428; +Cache_Resume_L1_CORE0_ICache_Autoload = 0x4fc0042c; +Cache_Suspend_L1_CORE1_ICache_Autoload = 0x4fc00430; +Cache_Resume_L1_CORE1_ICache_Autoload = 0x4fc00434; +Cache_Suspend_L1_DCache_Autoload = 0x4fc00438; +Cache_Resume_L1_DCache_Autoload = 0x4fc0043c; +Cache_Suspend_L2_Cache_Autoload = 0x4fc00440; +Cache_Resume_L2_Cache_Autoload = 0x4fc00444; +Cache_Start_L1_CORE0_ICache_Preload = 0x4fc00448; +Cache_L1_CORE0_ICache_Preload_Done = 0x4fc0044c; +Cache_End_L1_CORE0_ICache_Preload = 0x4fc00450; +Cache_Start_L1_CORE1_ICache_Preload = 0x4fc00454; +Cache_L1_CORE1_ICache_Preload_Done = 0x4fc00458; +Cache_End_L1_CORE1_ICache_Preload = 0x4fc0045c; +Cache_Start_L1_DCache_Preload = 0x4fc00460; +Cache_L1_DCache_Preload_Done = 0x4fc00464; +Cache_End_L1_DCache_Preload = 0x4fc00468; +Cache_Start_L2_Cache_Preload = 0x4fc0046c; +Cache_L2_Cache_Preload_Done = 0x4fc00470; +Cache_End_L2_Cache_Preload = 0x4fc00474; +Cache_Config_L1_CORE0_ICache_Autoload = 0x4fc00478; +Cache_Enable_L1_CORE0_ICache_Autoload = 0x4fc0047c; +Cache_Disable_L1_CORE0_ICache_Autoload = 0x4fc00480; +Cache_Config_L1_CORE1_ICache_Autoload = 0x4fc00484; +Cache_Enable_L1_CORE1_ICache_Autoload = 0x4fc00488; +Cache_Disable_L1_CORE1_ICache_Autoload = 0x4fc0048c; +Cache_Config_L1_DCache_Autoload = 0x4fc00490; +Cache_Enable_L1_DCache_Autoload = 0x4fc00494; +Cache_Disable_L1_DCache_Autoload = 0x4fc00498; +Cache_Config_L2_Cache_Autoload = 0x4fc0049c; +Cache_Enable_L2_Cache_Autoload = 0x4fc004a0; +Cache_Disable_L2_Cache_Autoload = 0x4fc004a4; +Cache_Enable_L1_CORE0_ICache_PreLock = 0x4fc004a8; +Cache_Disable_L1_CORE0_ICache_PreLock = 0x4fc004ac; +Cache_Enable_L1_CORE1_ICache_PreLock = 0x4fc004b0; +Cache_Disable_L1_CORE1_ICache_PreLock = 0x4fc004b4; +Cache_Enable_L1_DCache_PreLock = 0x4fc004b8; +Cache_Disable_L1_DCache_PreLock = 0x4fc004bc; +Cache_Enable_L2_Cache_PreLock = 0x4fc004c0; +Cache_Disable_L2_Cache_PreLock = 0x4fc004c4; +Cache_Lock_Addr = 0x4fc004c8; +Cache_Unlock_Addr = 0x4fc004cc; +Cache_Disable_L1_CORE0_ICache = 0x4fc004d0; +Cache_Enable_L1_CORE0_ICache = 0x4fc004d4; +Cache_Suspend_L1_CORE0_ICache = 0x4fc004d8; +Cache_Resume_L1_CORE0_ICache = 0x4fc004dc; +Cache_Disable_L1_CORE1_ICache = 0x4fc004e0; +Cache_Enable_L1_CORE1_ICache = 0x4fc004e4; +Cache_Suspend_L1_CORE1_ICache = 0x4fc004e8; +Cache_Resume_L1_CORE1_ICache = 0x4fc004ec; +Cache_Disable_L1_DCache = 0x4fc004f0; +Cache_Enable_L1_DCache = 0x4fc004f4; +Cache_Suspend_L1_DCache = 0x4fc004f8; +Cache_Resume_L1_DCache = 0x4fc004fc; +Cache_Disable_L2_Cache = 0x4fc00500; +Cache_Enable_L2_Cache = 0x4fc00504; +Cache_Suspend_L2_Cache = 0x4fc00508; +Cache_Resume_L2_Cache = 0x4fc0050c; +Cache_FLASH_MMU_Init = 0x4fc00510; +Cache_PSRAM_MMU_Init = 0x4fc00514; +Cache_FLASH_MMU_Set = 0x4fc00518; +Cache_FLASH_MMU_Set_Secure = 0x4fc0051c; +Cache_PSRAM_MMU_Set = 0x4fc00520; +Cache_PSRAM_MMU_Set_Secure = 0x4fc00524; +Cache_Count_Flash_Pages = 0x4fc00528; +Cache_Flash_To_SPIRAM_Copy = 0x4fc0052c; +Cache_Travel_Tag_Memory = 0x4fc00530; +Cache_Travel_Tag_Memory2 = 0x4fc00534; +Cache_Get_Virtual_Addr = 0x4fc00538; +Cache_Set_IDROM_MMU_Size = 0x4fc0053c; +flash2spiram_instruction_offset = 0x4fc00540; +flash2spiram_rodata_offset = 0x4fc00544; +flash_instr_rodata_start_page = 0x4fc00548; +flash_instr_rodata_end_page = 0x4fc0054c; +Cache_Set_IDROM_MMU_Info = 0x4fc00550; +Cache_Get_IROM_MMU_End = 0x4fc00554; +Cache_Get_DROM_MMU_End = 0x4fc00558; +/* Data (.data, .bss, .rodata) */ +rom_cache_op_cb = 0x4ff3ffdc; +rom_cache_internal_table_ptr = 0x4ff3ffd8; + + +/*************************************** + Group clock + ***************************************/ + +/* Functions */ +ets_clk_get_xtal_freq = 0x4fc0055c; +ets_clk_get_cpu_freq = 0x4fc00560; + + +/*************************************** + Group gpio + ***************************************/ + +/* Functions */ +gpio_set_output_level = 0x4fc00564; +gpio_get_input_level = 0x4fc00568; +gpio_matrix_in = 0x4fc0056c; +gpio_matrix_out = 0x4fc00570; +gpio_bypass_matrix_in = 0x4fc00574; +gpio_output_disable = 0x4fc00578; +gpio_output_enable = 0x4fc0057c; +gpio_pad_input_disable = 0x4fc00580; +gpio_pad_input_enable = 0x4fc00584; +gpio_pad_pulldown = 0x4fc00588; +gpio_pad_pullup = 0x4fc0058c; +gpio_pad_select_gpio = 0x4fc00590; +gpio_pad_set_drv = 0x4fc00594; +gpio_pad_unhold = 0x4fc00598; +gpio_pad_hold = 0x4fc0059c; +gpio_lppad_select_mux = 0x4fc005a0; +gpio_ded_pad_set_drv = 0x4fc005a4; +gpio_ded_pad_pullup = 0x4fc005a8; +gpio_ded_pad_pulldown = 0x4fc005ac; +gpio_ded_pad_hold = 0x4fc005b0; +gpio_ded_pad_unhold = 0x4fc005b4; + + +/*************************************** + Group interrupts + ***************************************/ + +/* Functions */ +esprv_intc_int_set_priority = 0x4fc005b8; +esprv_intc_int_set_threshold = 0x4fc005bc; +esprv_intc_int_enable = 0x4fc005c0; +esprv_intc_int_disable = 0x4fc005c4; +esprv_intc_int_set_type = 0x4fc005c8; +PROVIDE( intr_handler_set = 0x4fc005cc ); +intr_matrix_set = 0x4fc005d0; +ets_intr_lock = 0x4fc005d4; +ets_intr_unlock = 0x4fc005d8; +ets_isr_attach = 0x4fc005dc; +ets_isr_mask = 0x4fc005e0; +ets_isr_unmask = 0x4fc005e4; + + +/*************************************** + Group crypto + ***************************************/ + +/* Functions */ +md5_vector = 0x4fc005e8; +MD5Init = 0x4fc005ec; +MD5Update = 0x4fc005f0; +MD5Final = 0x4fc005f4; +crc32_le = 0x4fc005f8; +crc16_le = 0x4fc005fc; +crc8_le = 0x4fc00600; +crc32_be = 0x4fc00604; +crc16_be = 0x4fc00608; +crc8_be = 0x4fc0060c; +esp_crc8 = 0x4fc00610; +ets_sha_enable = 0x4fc00614; +ets_sha_disable = 0x4fc00618; +ets_sha_get_state = 0x4fc0061c; +ets_sha_init = 0x4fc00620; +ets_sha_process = 0x4fc00624; +ets_sha_starts = 0x4fc00628; +ets_sha_update = 0x4fc0062c; +ets_sha_finish = 0x4fc00630; +ets_sha_clone = 0x4fc00634; +ets_hmac_enable = 0x4fc00638; +ets_hmac_disable = 0x4fc0063c; +ets_hmac_calculate_message = 0x4fc00640; +ets_hmac_calculate_downstream = 0x4fc00644; +ets_hmac_invalidate_downstream = 0x4fc00648; +ets_jtag_enable_temporarily = 0x4fc0064c; +ets_aes_enable = 0x4fc00650; +ets_aes_disable = 0x4fc00654; +ets_aes_setkey = 0x4fc00658; +ets_aes_block = 0x4fc0065c; +ets_aes_setkey_dec = 0x4fc00660; +ets_aes_setkey_enc = 0x4fc00664; +ets_bigint_enable = 0x4fc00668; +ets_bigint_disable = 0x4fc0066c; +ets_bigint_multiply = 0x4fc00670; +ets_bigint_modmult = 0x4fc00674; +ets_bigint_modexp = 0x4fc00678; +ets_bigint_wait_finish = 0x4fc0067c; +ets_bigint_getz = 0x4fc00680; +ets_ds_enable = 0x4fc00684; +ets_ds_disable = 0x4fc00688; +ets_ds_start_sign = 0x4fc0068c; +ets_ds_is_busy = 0x4fc00690; +ets_ds_finish_sign = 0x4fc00694; +ets_ds_encrypt_params = 0x4fc00698; +ets_mgf1_sha256 = 0x4fc0069c; +/* Data (.data, .bss, .rodata) */ +crc32_le_table_ptr = 0x4fc1fff8; +crc16_le_table_ptr = 0x4fc1fff4; +crc8_le_table_ptr = 0x4fc1fff0; +crc32_be_table_ptr = 0x4fc1ffec; +crc16_be_table_ptr = 0x4fc1ffe8; +crc8_be_table_ptr = 0x4fc1ffe4; + + +/*************************************** + Group efuse + ***************************************/ + +/* Functions */ +ets_efuse_read = 0x4fc006a0; +ets_efuse_program = 0x4fc006a4; +ets_efuse_clear_program_registers = 0x4fc006a8; +ets_efuse_write_key = 0x4fc006ac; +ets_efuse_get_read_register_address = 0x4fc006b0; +ets_efuse_get_key_purpose = 0x4fc006b4; +ets_efuse_key_block_unused = 0x4fc006b8; +ets_efuse_find_unused_key_block = 0x4fc006bc; +ets_efuse_rs_calculate = 0x4fc006c0; +ets_efuse_count_unused_key_blocks = 0x4fc006c4; +ets_efuse_secure_boot_enabled = 0x4fc006c8; +ets_efuse_secure_boot_aggressive_revoke_enabled = 0x4fc006cc; +ets_efuse_cache_encryption_enabled = 0x4fc006d0; +ets_efuse_download_modes_disabled = 0x4fc006d4; +ets_efuse_find_purpose = 0x4fc006d8; +ets_efuse_force_send_resume = 0x4fc006dc; +ets_efuse_get_flash_delay_us = 0x4fc006e0; +ets_efuse_get_uart_print_control = 0x4fc006e4; +ets_efuse_direct_boot_mode_disabled = 0x4fc006e8; +ets_efuse_security_download_modes_enabled = 0x4fc006ec; +ets_efuse_jtag_disabled = 0x4fc006f0; +ets_efuse_usb_print_is_disabled = 0x4fc006f4; +ets_efuse_usb_download_mode_disabled = 0x4fc006f8; +ets_efuse_usb_device_disabled = 0x4fc006fc; +ets_efuse_get_km_huk_gen_state = 0x4fc00700; +ets_efuse_get_km_deploy_only_once = 0x4fc00704; +ets_efuse_get_force_use_km_key = 0x4fc00708; +ets_efuse_xts_key_length_256 = 0x4fc0070c; +ets_efuse_get_km_key_lock = 0x4fc00710; + + +/*************************************** + Group key_mgr + ***************************************/ + +/* Functions */ +esp_rom_check_recover_key = 0x4fc00714; +esp_rom_km_huk_conf = 0x4fc00718; +esp_rom_km_huk_risk = 0x4fc0071c; + + +/*************************************** + Group secureboot + ***************************************/ + +/* Functions */ +ets_emsa_pss_verify = 0x4fc00720; +ets_rsa_pss_verify = 0x4fc00724; +ets_ecdsa_verify = 0x4fc00728; +ets_secure_boot_verify_bootloader_with_keys = 0x4fc0072c; +ets_secure_boot_verify_signature = 0x4fc00730; +ets_secure_boot_read_key_digests = 0x4fc00734; +ets_secure_boot_revoke_public_key_digest = 0x4fc00738; + + +/*************************************** + Group usb_device_uart + ***************************************/ + +/* Functions */ +usb_serial_device_rx_one_char = 0x4fc008b0; +usb_serial_device_rx_one_char_block = 0x4fc008b4; +usb_serial_device_tx_flush = 0x4fc008b8; +usb_serial_device_tx_one_char = 0x4fc008bc; + + +/*************************************** + Group usb_dwcotg_uart + ***************************************/ + +/* Functions */ +Uart_Init_USB = 0x4fc008c0; +usb_serial_otg_rx_one_char = 0x4fc008c4; +usb_serial_otg_rx_one_char_block = 0x4fc008c8; +usb_serial_otg_tx_flush = 0x4fc008cc; +usb_serial_otg_tx_one_char = 0x4fc008d0; +/* Data (.data, .bss, .rodata) */ +uart_acm_dev = 0x4ff3ffd4; + + +/*************************************** + Group usb_dwcotg_module + ***************************************/ + +/* Functions */ +cdc_acm_class_handle_req = 0x4fc008d4; +cdc_acm_init = 0x4fc008d8; +cdc_acm_fifo_fill = 0x4fc008dc; +cdc_acm_rx_fifo_cnt = 0x4fc008e0; +cdc_acm_fifo_read = 0x4fc008e4; +cdc_acm_irq_tx_enable = 0x4fc008e8; +cdc_acm_irq_tx_disable = 0x4fc008ec; +cdc_acm_irq_state_enable = 0x4fc008f0; +cdc_acm_irq_state_disable = 0x4fc008f4; +cdc_acm_irq_tx_ready = 0x4fc008f8; +cdc_acm_irq_rx_enable = 0x4fc008fc; +cdc_acm_irq_rx_disable = 0x4fc00900; +cdc_acm_irq_rx_ready = 0x4fc00904; +cdc_acm_irq_is_pending = 0x4fc00908; +cdc_acm_irq_callback_set = 0x4fc0090c; +cdc_acm_line_ctrl_set = 0x4fc00910; +cdc_acm_line_ctrl_get = 0x4fc00914; +cdc_acm_poll_out = 0x4fc00918; +chip_usb_dw_did_persist = 0x4fc0091c; +chip_usb_dw_init = 0x4fc00920; +chip_usb_detach = 0x4fc00924; +chip_usb_dw_prepare_persist = 0x4fc00928; +chip_usb_get_persist_flags = 0x4fc0092c; +chip_usb_set_persist_flags = 0x4fc00930; +cpio_start = 0x4fc00934; +cpio_feed = 0x4fc00938; +cpio_done = 0x4fc0093c; +cpio_destroy = 0x4fc00940; +dfu_flash_init = 0x4fc00944; +dfu_flash_erase = 0x4fc00948; +dfu_flash_program = 0x4fc0094c; +dfu_flash_read = 0x4fc00950; +dfu_flash_attach = 0x4fc00954; +dfu_cpio_callback = 0x4fc00958; +dfu_updater_get_err = 0x4fc0095c; +dfu_updater_clear_err = 0x4fc00960; +dfu_updater_enable = 0x4fc00964; +dfu_updater_begin = 0x4fc00968; +dfu_updater_feed = 0x4fc0096c; +dfu_updater_end = 0x4fc00970; +dfu_updater_set_raw_addr = 0x4fc00974; +dfu_updater_flash_read = 0x4fc00978; +usb_dc_prepare_persist = 0x4fc0097c; +usb_dw_isr_handler = 0x4fc00980; +usb_dc_attach = 0x4fc00984; +usb_dc_detach = 0x4fc00988; +usb_dc_reset = 0x4fc0098c; +usb_dc_set_address = 0x4fc00990; +usb_dc_ep_check_cap = 0x4fc00994; +usb_dc_ep_configure = 0x4fc00998; +usb_dc_ep_set_stall = 0x4fc0099c; +usb_dc_ep_clear_stall = 0x4fc009a0; +usb_dc_ep_halt = 0x4fc009a4; +usb_dc_ep_is_stalled = 0x4fc009a8; +usb_dc_ep_enable = 0x4fc009ac; +usb_dc_ep_disable = 0x4fc009b0; +usb_dc_ep_flush = 0x4fc009b4; +usb_dc_ep_write_would_block = 0x4fc009b8; +usb_dc_ep_write = 0x4fc009bc; +usb_dc_ep_read_wait = 0x4fc009c0; +usb_dc_ep_read_continue = 0x4fc009c4; +usb_dc_ep_read = 0x4fc009c8; +usb_dc_ep_set_callback = 0x4fc009cc; +usb_dc_set_status_callback = 0x4fc009d0; +usb_dc_ep_mps = 0x4fc009d4; +usb_dc_check_poll_for_interrupts = 0x4fc009d8; +mac_addr_to_serial_str_desc = 0x4fc009dc; +usb_set_current_descriptor = 0x4fc009e0; +usb_get_descriptor = 0x4fc009e4; +usb_dev_resume = 0x4fc009e8; +usb_dev_get_configuration = 0x4fc009ec; +usb_set_config = 0x4fc009f0; +usb_deconfig = 0x4fc009f4; +usb_enable = 0x4fc009f8; +usb_disable = 0x4fc009fc; +usb_write_would_block = 0x4fc00a00; +usb_write = 0x4fc00a04; +usb_read = 0x4fc00a08; +usb_ep_set_stall = 0x4fc00a0c; +usb_ep_clear_stall = 0x4fc00a10; +usb_ep_read_wait = 0x4fc00a14; +usb_ep_read_continue = 0x4fc00a18; +usb_transfer_ep_callback = 0x4fc00a1c; +usb_transfer = 0x4fc00a20; +usb_cancel_transfer = 0x4fc00a24; +usb_transfer_sync = 0x4fc00a28; +usb_dfu_set_detach_cb = 0x4fc00a2c; +dfu_class_handle_req = 0x4fc00a30; +dfu_status_cb = 0x4fc00a34; +dfu_custom_handle_req = 0x4fc00a38; +usb_dfu_init = 0x4fc00a3c; +usb_dfu_force_detach = 0x4fc00a40; +usb_dev_deinit = 0x4fc00a44; +usb_dw_ctrl_deinit = 0x4fc00a48; +/* Data (.data, .bss, .rodata) */ +s_usb_osglue = 0x4ff3ffc8; + + +/*************************************** + ROM version variables for esp32p4 + These addresses should be compatible with any ROM version for this chip. + ***************************************/ + +_rom_chip_id = 0x4fc00010; +_rom_eco_version = 0x4fc00014; diff --git a/tools/flasher_stub/ld/rom_32s2.ld b/tools/flasher_stub/ld/rom_32s2.ld new file mode 100755 index 0000000000..399aa0f671 --- /dev/null +++ b/tools/flasher_stub/ld/rom_32s2.ld @@ -0,0 +1,1064 @@ +/* +ESP32S2 ROM address table +Generated for ROM with MD5sum: +0a2c7ec5109c17884606d23b47045796 /home/jack/esp-rom/rom//.output/eagle/release/image/eagle.pro.rom.out +*/ +PROVIDE ( abort = 0x40019fb4 ); +PROVIDE ( abs = 0x40000618 ); +PROVIDE ( __absvdi2 = 0x40005ad8 ); +PROVIDE ( __absvsi2 = 0x40005ac4 ); +PROVIDE ( acm_config_descr = 0x3ffaef0f ); +PROVIDE ( acm_usb_descriptors = 0x3ffaee68 ); +PROVIDE ( __adddf3 = 0x40008660 ); +PROVIDE ( __addsf3 = 0x400081b8 ); +PROVIDE ( __addvdi3 = 0x40008d90 ); +PROVIDE ( __addvsi3 = 0x40008d6c ); +PROVIDE ( __ascii_mbtowc = 0x40007a04 ); +PROVIDE ( __ascii_wctomb = 0x400018d0 ); +PROVIDE ( __ashldi3 = 0x4001b000 ); +PROVIDE ( __ashrdi3 = 0x4001b018 ); +PROVIDE ( __assert = 0x4001a430 ); +PROVIDE ( __assert_func = 0x4001a408 ); +PROVIDE ( boot_prepare = 0x4000f348 ); +PROVIDE ( __bswapdi2 = 0x40006d34 ); +PROVIDE ( __bswapsi2 = 0x40006d0c ); +PROVIDE ( bzero = 0x400078c8 ); +PROVIDE ( Cache_Address_Through_DCache = 0x400180f0 ); +PROVIDE ( Cache_Address_Through_ICache = 0x400180bc ); +PROVIDE ( Cache_Allocate_SRAM = 0x40018d6c ); +PROVIDE ( Cache_Clean_Addr = 0x40018370 ); +PROVIDE ( Cache_Clean_All = 0x40018438 ); +PROVIDE ( Cache_Clean_Items = 0x40018250 ); +PROVIDE ( Cache_Config_DCache_Autoload = 0x40018794 ); +PROVIDE ( Cache_Config_ICache_Autoload = 0x40018664 ); +PROVIDE ( Cache_Count_Flash_Pages = 0x40018f70 ); +PROVIDE ( Cache_Dbus_MMU_Set = 0x40018eb0 ); +PROVIDE ( Cache_DCache_Preload_Done = 0x40018630 ); +PROVIDE ( Cache_Disable_DCache = 0x40018c68 ); +PROVIDE ( Cache_Disable_DCache_Autoload = 0x4001888c ); +PROVIDE ( Cache_Disable_DCache_PreLock = 0x40018a5c ); +PROVIDE ( Cache_Disable_ICache = 0x40018c2c ); +PROVIDE ( Cache_Disable_ICache_Autoload = 0x4001875c ); +PROVIDE ( Cache_Disable_ICache_PreLock = 0x4001892c ); +PROVIDE ( Cache_Enable_DCache = 0x40018d58 ); +PROVIDE ( Cache_Enable_DCache_Autoload = 0x40018874 ); +PROVIDE ( Cache_Enable_DCache_PreLock = 0x400189f0 ); +PROVIDE ( Cache_Enable_Defalut_DCache_Mode = 0x40018170 ); +PROVIDE ( Cache_Enable_ICache = 0x40018cf8 ); +PROVIDE ( Cache_Enable_ICache_Autoload = 0x40018744 ); +PROVIDE ( Cache_Enable_ICache_PreLock = 0x400188c0 ); +PROVIDE ( Cache_End_DCache_Preload = 0x40018644 ); +PROVIDE ( Cache_End_ICache_Preload = 0x400185b0 ); +PROVIDE ( Cache_Flash_To_SPIRAM_Copy = 0x40018fc4 ); +PROVIDE ( Cache_Get_DCache_Line_Size = 0x40017fd8 ); +PROVIDE ( Cache_Get_ICache_Line_Size = 0x40017fbc ); +PROVIDE ( Cache_Get_Memory_Addr = 0x4001929c ); +PROVIDE ( Cache_Get_Memory_BaseAddr = 0x40019244 ); +PROVIDE ( Cache_Get_Memory_value = 0x400192d8 ); +PROVIDE ( Cache_Get_Mode = 0x40017ff0 ); +PROVIDE ( Cache_Get_Virtual_Addr = 0x40019210 ); +PROVIDE ( Cache_Ibus_MMU_Set = 0x40018df4 ); +PROVIDE ( Cache_ICache_Preload_Done = 0x4001859c ); +PROVIDE ( Cache_Invalidate_Addr = 0x400182e4 ); +PROVIDE ( Cache_Invalidate_DCache_All = 0x4001842c ); +PROVIDE ( Cache_Invalidate_DCache_Items = 0x40018208 ); +PROVIDE ( Cache_Invalidate_ICache_All = 0x40018420 ); +PROVIDE ( Cache_Invalidate_ICache_Items = 0x400181b8 ); +PROVIDE ( Cache_Lock_Addr = 0x40018b10 ); +PROVIDE ( Cache_Lock_DCache_Items = 0x40018a80 ); +PROVIDE ( Cache_Lock_ICache_Items = 0x40018950 ); +PROVIDE ( Cache_Mask_All = 0x40018458 ); +PROVIDE ( cache_memory_baseaddrs = 0x3ffaf020 ); +PROVIDE ( Cache_MMU_Init = 0x40018dd8 ); +PROVIDE ( Cache_Resume_DCache = 0x40018d3c ); +PROVIDE ( Cache_Resume_DCache_Autoload = 0x4001850c ); +PROVIDE ( Cache_Resume_ICache = 0x40018cdc ); +PROVIDE ( Cache_Resume_ICache_Autoload = 0x400184c4 ); +PROVIDE ( Cache_Set_DCache_Mode = 0x40018074 ); +PROVIDE ( Cache_Set_Default_Mode = 0x4001810c ); +PROVIDE ( Cache_Set_ICache_Mode = 0x4001803c ); +PROVIDE ( Cache_Start_DCache_Preload = 0x400185c4 ); +PROVIDE ( Cache_Start_ICache_Preload = 0x40018530 ); +PROVIDE ( Cache_Suspend_DCache = 0x40018d04 ); +PROVIDE ( Cache_Suspend_DCache_Autoload = 0x400184e0 ); +PROVIDE ( Cache_Suspend_ICache = 0x40018ca4 ); +PROVIDE ( Cache_Suspend_ICache_Autoload = 0x40018498 ); +PROVIDE ( Cache_Travel_Tag_Memory = 0x4001908c ); +PROVIDE ( Cache_Unlock_Addr = 0x40018b9c ); +PROVIDE ( Cache_Unlock_DCache_Items = 0x40018ac8 ); +PROVIDE ( Cache_Unlock_ICache_Items = 0x40018998 ); +PROVIDE ( Cache_UnMask_Drom0 = 0x40018480 ); +PROVIDE ( Cache_WriteBack_Addr = 0x400183c8 ); +PROVIDE ( Cache_WriteBack_All = 0x40018444 ); +PROVIDE ( Cache_WriteBack_Items = 0x40018298 ); +PROVIDE ( cacl_rtc_memory_crc = 0x4000ffa0 ); +PROVIDE ( calloc = 0x4001a2f4 ); +PROVIDE ( _calloc_r = 0x4001a008 ); +PROVIDE ( cdc_acm_class_handle_req = 0x40013050 ); +PROVIDE ( cdc_acm_config = 0x3ffffa10 ); +PROVIDE ( cdc_acm_dev = 0x3ffffce8 ); +PROVIDE ( cdc_acm_fifo_fill = 0x4001318c ); +PROVIDE ( cdc_acm_fifo_read = 0x40013200 ); +PROVIDE ( cdc_acm_init = 0x40013144 ); +PROVIDE ( cdc_acm_irq_callback_set = 0x400132d4 ); +PROVIDE ( cdc_acm_irq_is_pending = 0x400132b0 ); +PROVIDE ( cdc_acm_irq_rx_disable = 0x40013290 ); +PROVIDE ( cdc_acm_irq_rx_enable = 0x40013284 ); +PROVIDE ( cdc_acm_irq_rx_ready = 0x4001329c ); +PROVIDE ( cdc_acm_irq_state_disable = 0x40013264 ); +PROVIDE ( cdc_acm_irq_state_enable = 0x40013258 ); +PROVIDE ( cdc_acm_irq_tx_disable = 0x4001324c ); +PROVIDE ( cdc_acm_irq_tx_enable = 0x40013240 ); +PROVIDE ( cdc_acm_irq_tx_ready = 0x40013270 ); +PROVIDE ( cdc_acm_line_ctrl_get = 0x40013330 ); +PROVIDE ( cdc_acm_line_ctrl_set = 0x400132dc ); +PROVIDE ( cdc_acm_poll_out = 0x40013360 ); +PROVIDE ( cdc_acm_rx_fifo_cnt = 0x400131ec ); +PROVIDE ( chip723_phyrom_version = 0x4000a8a8 ); +PROVIDE ( chip_usb_detach = 0x40013508 ); +PROVIDE ( chip_usb_dw_did_persist = 0x4001337c ); +PROVIDE ( chip_usb_dw_init = 0x400133bc ); +PROVIDE ( chip_usb_dw_prepare_persist = 0x40013588 ); +PROVIDE ( chip_usb_get_persist_flags = 0x400135d8 ); +PROVIDE ( chip_usb_set_persist_flags = 0x400135e8 ); +PROVIDE ( _cleanup = 0x4001a4f8 ); +PROVIDE ( _cleanup_r = 0x4001a480 ); +PROVIDE ( __clear_cache = 0x40005abc ); +PROVIDE ( close = 0x400080b0 ); +PROVIDE ( _close_r = 0x4001a14c ); +PROVIDE ( __clrsbdi2 = 0x40006da8 ); +PROVIDE ( __clrsbsi2 = 0x40006d90 ); +PROVIDE ( __clzdi2 = 0x4001b238 ); +PROVIDE ( __clzsi2 = 0x4001afd0 ); +PROVIDE ( __cmpdi2 = 0x40005a7c ); +PROVIDE ( context = 0x3fffeb34 ); +PROVIDE ( cpio_destroy = 0x4001599c ); +PROVIDE ( cpio_done = 0x40015968 ); +PROVIDE ( cpio_feed = 0x40015668 ); +PROVIDE ( cpio_start = 0x4001561c ); +PROVIDE ( crc16_le = 0x40011a10 ); +PROVIDE ( crc32_le = 0x400119dc ); +PROVIDE ( crc8_le = 0x40011a4c ); +PROVIDE ( creat = 0x4000788c ); +PROVIDE ( _ctype_ = 0x3ffac76c ); +PROVIDE ( __ctzdi2 = 0x4001b24c ); +PROVIDE ( __ctzsi2 = 0x4001afd8 ); +PROVIDE ( _cvt = 0x4000f9b8 ); +PROVIDE ( _data_end_all_pro = 0x3fffff98 ); +PROVIDE ( _data_end_c = 0x3ffffd80 ); +PROVIDE ( _data_end_ets = 0x3fffe710 ); +PROVIDE ( _data_end_ets_delay = 0x3ffffd74 ); +PROVIDE ( _data_end_ets_printf = 0x3ffffd5c ); +PROVIDE ( _data_end_newlib = 0x3ffffd74 ); +PROVIDE ( _data_end_phyrom = 0x3fffff98 ); +PROVIDE ( _data_end_sip = 0x3fffeb70 ); +PROVIDE ( _data_end_slc = 0x3fffeb70 ); +PROVIDE ( _data_end_spi_flash = 0x3ffffd54 ); +PROVIDE ( _data_end_spi_slave = 0x3fffeb30 ); +PROVIDE ( _data_end_uart = 0x3ffffcf4 ); +PROVIDE ( _data_end_usbdev = 0x3ffffa6c ); +PROVIDE ( _data_end_xtos = 0x3fffef88 ); +PROVIDE ( _data_start_all_pro = 0x3fffff98 ); +PROVIDE ( _data_start_c = 0x3ffffd7c ); +PROVIDE ( _data_start_ets = 0x3fffe710 ); +PROVIDE ( _data_start_ets_delay = 0x3ffffd70 ); +PROVIDE ( _data_start_ets_printf = 0x3ffffd5c ); +PROVIDE ( _data_start_newlib = 0x3ffffd74 ); +PROVIDE ( _data_start_phyrom = 0x3ffffd90 ); +PROVIDE ( _data_start_sip = 0x3fffeb70 ); +PROVIDE ( _data_start_slc = 0x3fffeb70 ); +PROVIDE ( _data_start_spi_flash = 0x3ffffd38 ); +PROVIDE ( _data_start_spi_slave = 0x3fffeb30 ); +PROVIDE ( _data_start_uart = 0x3ffffcf4 ); +PROVIDE ( _data_start_usbdev = 0x3ffffa10 ); +PROVIDE ( _data_start_xtos = 0x3fffeb70 ); +PROVIDE ( dbus_baseaddrs = 0x3ffaf030 ); +PROVIDE ( _DebugExceptionVector = 0x40000280 ); +PROVIDE ( _DebugExceptionVector_text_end = 0x4000028b ); +PROVIDE ( _DebugExceptionVector_text_start = 0x40000280 ); +PROVIDE ( __default_global_locale = 0x3ffac600 ); +PROVIDE ( dfu_class_handle_req = 0x400152f0 ); +PROVIDE ( dfu_config_descr = 0x3ffaeeb2 ); +PROVIDE ( dfu_cpio_callback = 0x4001360c ); +PROVIDE ( dfu_custom_handle_req = 0x40015568 ); +PROVIDE ( dfu_flash_attach = 0x40015a34 ); +PROVIDE ( dfu_flash_deinit = 0x400159b4 ); +PROVIDE ( dfu_flash_erase = 0x400159bc ); +PROVIDE ( dfu_flash_init = 0x400159a4 ); +PROVIDE ( dfu_flash_program = 0x400159d0 ); +PROVIDE ( dfu_flash_read = 0x40015a24 ); +PROVIDE ( dfu_status_cb = 0x40015514 ); +PROVIDE ( dfu_updater_begin = 0x40013858 ); +PROVIDE ( dfu_updater_clear_err = 0x40013810 ); +PROVIDE ( dfu_updater_enable = 0x40013828 ); +PROVIDE ( dfu_updater_end = 0x40013900 ); +PROVIDE ( dfu_updater_feed = 0x400138b4 ); +PROVIDE ( dfu_updater_flash_read = 0x400139e8 ); +PROVIDE ( dfu_updater_get_err = 0x400137fc ); +PROVIDE ( dfu_updater_set_raw_addr = 0x400139d4 ); +PROVIDE ( dfu_usb_descriptors = 0x3ffaee4c ); +PROVIDE ( dh_group14_generator = 0x3ffadfec ); +PROVIDE ( dh_group14_prime = 0x3ffadeec ); +PROVIDE ( dh_group15_generator = 0x3ffadeeb ); +PROVIDE ( dh_group15_prime = 0x3ffadd6b ); +PROVIDE ( dh_group16_generator = 0x3ffadd6a ); +PROVIDE ( dh_group16_prime = 0x3ffadb6a ); +PROVIDE ( dh_group17_generator = 0x3ffadb69 ); +PROVIDE ( dh_group17_prime = 0x3ffad869 ); +PROVIDE ( dh_group18_generator = 0x3ffad868 ); +PROVIDE ( dh_group18_prime = 0x3ffad468 ); +PROVIDE ( dh_group1_generator = 0x3ffae18f ); +PROVIDE ( dh_group1_prime = 0x3ffae12f ); +PROVIDE ( dh_group2_generator = 0x3ffae12e ); +PROVIDE ( dh_group2_prime = 0x3ffae0ae ); +PROVIDE ( dh_group5_generator = 0x3ffae0ad ); +PROVIDE ( dh_group5_prime = 0x3ffadfed ); +PROVIDE ( disable_default_watchdog = 0x4000f270 ); +PROVIDE ( Disable_QMode = 0x400166e0 ); +PROVIDE ( div = 0x40000620 ); +PROVIDE ( __divdc3 = 0x40006854 ); +PROVIDE ( __divdf3 = 0x40008a24 ); +PROVIDE ( __divdi3 = 0x4001b26c ); +PROVIDE ( __divsc3 = 0x40006544 ); +PROVIDE ( __divsf3 = 0x4000841c ); +PROVIDE ( __divsi3 = 0x4001afa0 ); +PROVIDE ( dmadesc_rx = 0x3fffeb4c ); +PROVIDE ( dmadesc_tx = 0x3fffeb40 ); +PROVIDE ( _DoubleExceptionVector = 0x400003c0 ); +PROVIDE ( _DoubleExceptionVector_text_end = 0x400003c6 ); +PROVIDE ( _DoubleExceptionVector_text_start = 0x400003c0 ); +PROVIDE ( _dram0_0_start = 0x3ffeab00 ); +PROVIDE ( _dram0_rtos_reserved_start = 0x3ffffa10 ); +PROVIDE ( dummy_len_plus = 0x3ffffd54 ); +PROVIDE ( Enable_QMode = 0x40016690 ); +PROVIDE ( __eqdf2 = 0x40005904 ); +PROVIDE ( __eqsf2 = 0x400055d0 ); +PROVIDE ( esp_crc8 = 0x40011a78 ); +PROVIDE ( esp_rom_config_pad_power_select = 0x40016e58 ); +PROVIDE ( esp_rom_opiflash_cache_mode_config = 0x40016754 ); +PROVIDE ( esp_rom_opiflash_exec_cmd = 0x40017e30 ); +PROVIDE ( esp_rom_opiflash_exit_continuous_read_mode = 0x40017ee8 ); +PROVIDE ( esp_rom_opiflash_mode_reset = 0x40017f90 ); +PROVIDE ( esp_rom_opiflash_pin_config = 0x400177f8 ); +PROVIDE ( esp_rom_opiflash_soft_reset = 0x40017f24 ); +PROVIDE ( esp_rom_spi_cmd_config = 0x40017c58 ); +PROVIDE ( esp_rom_spi_cmd_start = 0x40017ba8 ); +PROVIDE ( esp_rom_spi_flash_auto_sus_res = 0x400175e0 ); +PROVIDE ( esp_rom_spi_flash_auto_wait_idle = 0x4001751c ); +PROVIDE ( esp_rom_spi_flash_send_resume = 0x40017570 ); +PROVIDE ( esp_rom_spi_flash_update_id = 0x40016e44 ); +PROVIDE ( esp_rom_spi_reset_rw_mode = 0x40017984 ); +PROVIDE ( esp_rom_spi_set_dtr_swap_mode = 0x40017b60 ); +PROVIDE ( esp_rom_spi_set_op_mode = 0x400179e8 ); +PROVIDE ( _etext = 0x4001bed0 ); +PROVIDE ( ets_aes_block = 0x4000d610 ); +PROVIDE ( ets_aes_disable = 0x4000d4f8 ); +PROVIDE ( ets_aes_enable = 0x4000d4cc ); +PROVIDE ( ets_aes_set_endian = 0x4000d528 ); +PROVIDE ( ets_aes_setkey = 0x4000d594 ); +PROVIDE ( ets_aes_setkey_dec = 0x4000d5f0 ); +PROVIDE ( ets_aes_setkey_enc = 0x4000d5e0 ); +PROVIDE ( ets_bigint_disable = 0x4000d750 ); +PROVIDE ( ets_bigint_enable = 0x4000d708 ); +PROVIDE ( ets_bigint_getz = 0x4000d858 ); +PROVIDE ( ets_bigint_modexp = 0x4000d818 ); +PROVIDE ( ets_bigint_modmult = 0x4000d7f4 ); +PROVIDE ( ets_bigint_multiply = 0x4000d790 ); +PROVIDE ( ets_bigint_wait_finish = 0x4000d840 ); +PROVIDE ( ets_config_flash_by_image_hdr = 0x40010e40 ); +PROVIDE ( ets_delay_us = 0x4000d888 ); +PROVIDE ( ets_ds_disable = 0x4000d910 ); +PROVIDE ( ets_ds_enable = 0x4000d8e4 ); +PROVIDE ( ets_ds_encrypt_params = 0x4000da90 ); +PROVIDE ( ets_ds_finish_sign = 0x4000d9f8 ); +PROVIDE ( ets_ds_is_busy = 0x4000d93c ); +PROVIDE ( ets_ds_start_sign = 0x4000d96c ); +PROVIDE ( ets_efuse_cache_encryption_enabled = 0x4000e690 ); +PROVIDE ( ets_efuse_clear_program_registers = 0x4000e100 ); +PROVIDE ( ets_efuse_count_unused_key_blocks = 0x4000e2c4 ); +PROVIDE ( ets_efuse_download_modes_disabled = 0x4000e594 ); +PROVIDE ( ets_efuse_find_purpose = 0x4000e224 ); +PROVIDE ( ets_efuse_find_unused_key_block = 0x4000e2ac ); +PROVIDE ( ets_efuse_flash_opi_5pads_power_sel_vddspi = 0x4000e640 ); +PROVIDE ( ets_efuse_flash_opi_mode = 0x4000e650 ); +PROVIDE ( ets_efuse_force_send_resume = 0x4000e660 ); +PROVIDE ( ets_efuse_get_flash_delay_us = 0x4000e6d4 ); +PROVIDE ( ets_efuse_get_key_purpose = 0x4000e1b0 ); +PROVIDE ( ets_efuse_get_opiconfig = 0x4000e4fc ); +PROVIDE ( ets_efuse_get_read_register_address = 0x4000e18c ); +PROVIDE ( ets_efuse_get_spiconfig = 0x4000e4a0 ); +PROVIDE ( ets_efuse_get_uart_print_channel = 0x4000e5b4 ); +PROVIDE ( ets_efuse_get_uart_print_control = 0x4000e5a4 ); +PROVIDE ( ets_efuse_get_wp_pad = 0x4000e444 ); +PROVIDE ( ets_efuse_key_block_unused = 0x4000e250 ); +PROVIDE ( ets_efuse_legacy_spi_boot_mode_disabled = 0x4000e6b0 ); +PROVIDE ( ets_efuse_program = 0x4000e134 ); +PROVIDE ( ets_efuse_read = 0x4000e0c0 ); +PROVIDE ( ets_efuse_rs_calculate = 0x4000e6f8 ); +PROVIDE ( ets_efuse_secure_boot_aggressive_revoke_enabled = 0x4000e680 ); +PROVIDE ( ets_efuse_secure_boot_enabled = 0x4000e670 ); +PROVIDE ( ets_efuse_security_download_modes_enabled = 0x4000e5d4 ); +PROVIDE ( ets_efuse_set_timing = 0x4000df3c ); +PROVIDE ( ets_efuse_start = 0x4000e084 ); +PROVIDE ( ets_efuse_usb_download_mode_disabled = 0x4000e5f4 ); +PROVIDE ( ets_efuse_usb_force_nopersist = 0x4000e630 ); +PROVIDE ( ets_efuse_usb_module_disabled = 0x4000e5c4 ); +PROVIDE ( ets_efuse_usb_use_ext_phy = 0x4000e620 ); +PROVIDE ( ets_efuse_write_key = 0x4000e2f4 ); +PROVIDE ( ets_emsa_pss_verify = 0x40011818 ); +PROVIDE ( ets_get_apb_freq = 0x40010c58 ); +PROVIDE ( ets_get_cpu_frequency = 0x4000d8b0 ); +PROVIDE ( ets_get_printf_channel = 0x4000ff48 ); +PROVIDE ( ets_get_xtal_div = 0x40010bfc ); +PROVIDE ( ets_get_xtal_freq = 0x40010c38 ); +PROVIDE ( ets_hmac_calculate_downstream = 0x4000f120 ); +PROVIDE ( ets_hmac_calculate_message = 0x4000f020 ); +PROVIDE ( ets_hmac_disable = 0x4000eff4 ); +PROVIDE ( ets_hmac_enable = 0x4000efd8 ); +PROVIDE ( ets_hmac_invalidate_downstream = 0x4000f140 ); +PROVIDE ( ets_install_lock = 0x4000fea0 ); +PROVIDE ( ets_install_putc1 = 0x4000feb0 ); +PROVIDE ( ets_install_putc2 = 0x4000fed0 ); +PROVIDE ( ets_install_uart_printf = 0x4000fec0 ); +PROVIDE ( ets_intr_count = 0x3fffe710 ); +PROVIDE ( ets_intr_lock = 0x4000f168 ); +PROVIDE ( ets_intr_unlock = 0x4000f17c ); +PROVIDE ( ets_is_print_boot = 0x4000f2a0 ); +PROVIDE ( ets_isr_attach = 0x4000f1a4 ); +PROVIDE ( ets_isr_mask = 0x4000f1b4 ); +PROVIDE ( ets_isr_unmask = 0x4000f1c0 ); +PROVIDE ( ets_jtag_enable_temporarily = 0x4000e548 ); +PROVIDE ( ets_loader_map_range = 0x40010d4c ); +PROVIDE ( ets_mgf1_sha256 = 0x400117b0 ); +PROVIDE ( ets_printf = 0x4000fee0 ); +PROVIDE ( ets_printf_lock = 0x3ffffd64 ); +PROVIDE ( ets_printf_uart = 0x3ffffd5c ); +PROVIDE ( ets_printf_unlock = 0x3ffffd60 ); +PROVIDE ( ets_rsa_pss_verify = 0x4001191c ); +PROVIDE ( ets_run_flash_bootloader = 0x40010f58 ); +PROVIDE ( ets_secure_boot_read_key_digests = 0x400101ac ); +PROVIDE ( ets_secure_boot_revoke_public_key_digest = 0x4001025c ); +PROVIDE ( ets_secure_boot_verify_bootloader_with_keys = 0x40010444 ); +PROVIDE ( ets_secure_boot_verify_signature = 0x400102cc ); +PROVIDE ( ets_secure_boot_verify_stage_bootloader = 0x40010720 ); +PROVIDE ( ets_set_printf_channel = 0x4000ff3c ); +PROVIDE ( ets_set_user_start = 0x4000f25c ); +PROVIDE ( ets_set_xtal_div = 0x40010c18 ); +PROVIDE ( ets_sha_clone = 0x4001095c ); +PROVIDE ( ets_sha_disable = 0x400107b4 ); +PROVIDE ( ets_sha_enable = 0x40010788 ); +PROVIDE ( ets_sha_finish = 0x40010ab8 ); +PROVIDE ( ets_sha_get_state = 0x40010934 ); +PROVIDE ( ets_sha_init = 0x400107e0 ); +PROVIDE ( ets_sha_process = 0x40010988 ); +PROVIDE ( ets_sha_starts = 0x40010828 ); +PROVIDE ( ets_sha_update = 0x400109f8 ); +PROVIDE ( ets_startup_callback = 0x3fffe718 ); +PROVIDE ( ets_unpack_flash_code_legacy = 0x40011430 ); +PROVIDE ( ets_update_cpu_frequency = 0x4000d8a4 ); +PROVIDE ( ets_vprintf = 0x4000fa3c ); +PROVIDE ( ets_waiti0 = 0x4000f190 ); +PROVIDE ( ets_wdt_reset_cpu = 0x4001a82c ); +PROVIDE ( ets_write_char = 0x4000f974 ); +PROVIDE ( ets_write_char_uart = 0x4000f998 ); +PROVIDE ( exc_cause_table = 0x3ffacbe8 ); +PROVIDE ( _exit_r = 0x4001a138 ); +PROVIDE ( __extendsfdf2 = 0x40008d08 ); +PROVIDE ( fclose = 0x4001a804 ); +PROVIDE ( _fclose_r = 0x4001a714 ); +PROVIDE ( fflush = 0x40001bb8 ); +PROVIDE ( _fflush_r = 0x40001b30 ); +PROVIDE ( __ffsdi2 = 0x4001b214 ); +PROVIDE ( __ffssi2 = 0x4001afec ); +PROVIDE ( FilePacketSendDeflatedReqMsgProc = 0x40011ed8 ); +PROVIDE ( FilePacketSendReqMsgProc = 0x40011bd8 ); +PROVIDE ( fiprintf = 0x40000a3c ); +PROVIDE ( _fiprintf_r = 0x40000a18 ); +PROVIDE ( __fixdfdi = 0x40008b98 ); +PROVIDE ( __fixdfsi = 0x40008b4c ); +PROVIDE ( __fixsfdi = 0x4000851c ); +PROVIDE ( __fixsfsi = 0x400084dc ); +PROVIDE ( __fixunsdfsi = 0x40008c04 ); +PROVIDE ( __fixunssfdi = 0x400085d4 ); +PROVIDE ( __fixunssfsi = 0x4000857c ); +PROVIDE ( flashchip = 0x3ffffd38 ); +PROVIDE ( FlashDwnLdDeflatedStartMsgProc = 0x40011e80 ); +PROVIDE ( FlashDwnLdParamCfgMsgProc = 0x40011cc0 ); +PROVIDE ( FlashDwnLdStartMsgProc = 0x40011b74 ); +PROVIDE ( FlashDwnLdStopDeflatedReqMsgProc = 0x40011fd8 ); +PROVIDE ( FlashDwnLdStopReqMsgProc = 0x40011c90 ); +PROVIDE ( __floatdidf = 0x4001b170 ); +PROVIDE ( __floatdisf = 0x4001b0a8 ); +PROVIDE ( __floatsidf = 0x4001b12c ); +PROVIDE ( __floatsisf = 0x4001b058 ); +PROVIDE ( __floatundidf = 0x4001b160 ); +PROVIDE ( __floatundisf = 0x4001b098 ); +PROVIDE ( __floatunsidf = 0x4001b120 ); +PROVIDE ( __floatunsisf = 0x4001b04c ); +PROVIDE ( __fp_lock_all = 0x4001a638 ); +PROVIDE ( fprintf = 0x40000a3c ); +PROVIDE ( _fprintf_r = 0x40000a18 ); +PROVIDE ( __fp_unlock_all = 0x4001a64c ); +PROVIDE ( fputwc = 0x40001864 ); +PROVIDE ( __fputwc = 0x40001770 ); +PROVIDE ( _fputwc_r = 0x400017f8 ); +PROVIDE ( free = 0x4001a2c8 ); +PROVIDE ( _free_r = 0x40019fdc ); +PROVIDE ( _fstat_r = 0x4001a0dc ); +PROVIDE ( _fwalk = 0x4001bcec ); +PROVIDE ( _fwalk_reent = 0x4001bd24 ); +PROVIDE ( __gcc_bcmp = 0x40006de0 ); +PROVIDE ( __gedf2 = 0x400059c4 ); +PROVIDE ( general_device_descr = 0x3ffffa58 ); +PROVIDE ( _GeneralException = 0x400073cf ); +PROVIDE ( __gesf2 = 0x40005668 ); +PROVIDE ( get_id = 0x4001610c ); +PROVIDE ( _getpid_r = 0x4001a10c ); +PROVIDE ( __getreent = 0x4001a29c ); +PROVIDE ( GetSecurityInfoProc = 0x40012098 ); +PROVIDE ( _gettimeofday_r = 0x4001a068 ); +PROVIDE ( GetUartDevice = 0x40012f60 ); +PROVIDE ( _global_impure_ptr = 0x3ffffd8c ); +PROVIDE ( __global_locale_ptr = 0x3ffffd7c ); +PROVIDE ( g_phyFuns = 0x3ffffd90 ); +PROVIDE ( g_phyFuns_instance = 0x3ffffd94 ); +PROVIDE ( gpio_input_get = 0x400193a0 ); +PROVIDE ( gpio_input_get_high = 0x400193b4 ); +PROVIDE ( gpio_matrix_in = 0x40019430 ); +PROVIDE ( gpio_matrix_out = 0x40019460 ); +PROVIDE ( gpio_output_disable = 0x400194dc ); +PROVIDE ( gpio_output_enable = 0x400194b0 ); +PROVIDE ( gpio_output_set = 0x4001933c ); +PROVIDE ( gpio_output_set_high = 0x40019374 ); +PROVIDE ( gpio_pad_hold = 0x40019654 ); +PROVIDE ( gpio_pad_input_disable = 0x400195f0 ); +PROVIDE ( gpio_pad_input_enable = 0x400195cc ); +PROVIDE ( gpio_pad_pulldown = 0x40019598 ); +PROVIDE ( gpio_pad_pullup = 0x40019564 ); +PROVIDE ( gpio_pad_select_gpio = 0x40019510 ); +PROVIDE ( gpio_pad_set_drv = 0x40019538 ); +PROVIDE ( gpio_pad_unhold = 0x4001961c ); +PROVIDE ( gpio_pin_wakeup_disable = 0x40019404 ); +PROVIDE ( gpio_pin_wakeup_enable = 0x400193c8 ); +PROVIDE ( g_shared_buffers = 0x3ffeab04 ); +PROVIDE ( __gtdf2 = 0x40005938 ); +PROVIDE ( g_ticks_per_us = 0x3ffffd70 ); +PROVIDE ( __gtsf2 = 0x400055fc ); +PROVIDE ( hmac_md5 = 0x40005490 ); +PROVIDE ( hmac_md5_vector = 0x400053a0 ); +PROVIDE ( ibus_baseaddrs = 0x3ffaf03c ); +PROVIDE ( intr_matrix_set = 0x4000f1d0 ); +PROVIDE ( _iram0_text_end = 0x40000540 ); +PROVIDE ( _iram0_text_start = 0x40000540 ); +PROVIDE ( _iram1_text_end = 0x60021100 ); +PROVIDE ( _iram1_text_start = 0x60021100 ); +PROVIDE ( isalnum = 0x400078d8 ); +PROVIDE ( isalpha = 0x400078e8 ); +PROVIDE ( isascii = 0x4001aaec ); +PROVIDE ( _isatty_r = 0x400078a0 ); +PROVIDE ( isblank = 0x400078f8 ); +PROVIDE ( iscntrl = 0x40007918 ); +PROVIDE ( isdigit = 0x40007930 ); +PROVIDE ( isgraph = 0x40007968 ); +PROVIDE ( islower = 0x40007948 ); +PROVIDE ( isprint = 0x40007980 ); +PROVIDE ( ispunct = 0x40007994 ); +PROVIDE ( isspace = 0x400079ac ); +PROVIDE ( isupper = 0x400079c4 ); +PROVIDE ( _KernelExceptionVector = 0x40000300 ); +PROVIDE ( _KernelExceptionVector_text_end = 0x40000306 ); +PROVIDE ( _KernelExceptionVector_text_start = 0x40000300 ); +PROVIDE ( _kill_r = 0x4001a120 ); +PROVIDE ( labs = 0x40000648 ); +PROVIDE ( ldiv = 0x40000650 ); +PROVIDE ( __ledf2 = 0x40005960 ); +PROVIDE ( __lesf2 = 0x4000561c ); +PROVIDE ( _Level2FromVector = 0x400074f8 ); +PROVIDE ( _Level2HandlerLabel = 0x00000000 ); +PROVIDE ( _Level2InterruptVector_text_end = 0x40000186 ); +PROVIDE ( _Level2InterruptVector_text_start = 0x40000180 ); +PROVIDE ( _Level2Vector = 0x40000180 ); +PROVIDE ( _Level3FromVector = 0x40007594 ); +PROVIDE ( _Level3HandlerLabel = 0x00000000 ); +PROVIDE ( _Level3InterruptVector_text_end = 0x400001c6 ); +PROVIDE ( _Level3InterruptVector_text_start = 0x400001c0 ); +PROVIDE ( _Level3Vector = 0x400001c0 ); +PROVIDE ( _Level4FromVector = 0x4000762c ); +PROVIDE ( _Level4HandlerLabel = 0x00000000 ); +PROVIDE ( _Level4InterruptVector_text_end = 0x40000206 ); +PROVIDE ( _Level4InterruptVector_text_start = 0x40000200 ); +PROVIDE ( _Level4Vector = 0x40000200 ); +PROVIDE ( _Level5FromVector = 0x4000775c ); +PROVIDE ( _Level5HandlerLabel = 0x00000000 ); +PROVIDE ( _Level5InterruptVector_text_end = 0x40000246 ); +PROVIDE ( _Level5InterruptVector_text_start = 0x40000240 ); +PROVIDE ( _Level5Vector = 0x40000240 ); +PROVIDE ( _LevelOneInterrupt = 0x4000740a ); +PROVIDE ( _link_r = 0x4001a0ac ); +PROVIDE ( _lit4_end = 0x40000540 ); +PROVIDE ( _lit4_start = 0x40000540 ); +PROVIDE ( lldesc_build_chain = 0x4000907c ); +PROVIDE ( lldesc_num2link = 0x4000916c ); +PROVIDE ( lldesc_set_owner = 0x40009198 ); +PROVIDE ( lldesc_setup = 0x40019ed8 ); +PROVIDE ( __locale_ctype_ptr = 0x40001c2c ); +PROVIDE ( __locale_ctype_ptr_l = 0x40001c24 ); +PROVIDE ( __locale_mb_cur_max = 0x40001c0c ); +PROVIDE ( _lock_acquire = 0x4001a224 ); +PROVIDE ( _lock_acquire_recursive = 0x4001a238 ); +PROVIDE ( _lock_close = 0x4001a1fc ); +PROVIDE ( _lock_close_recursive = 0x4001a210 ); +PROVIDE ( _lock_init = 0x4001a1d4 ); +PROVIDE ( _lock_init_recursive = 0x4001a1e8 ); +PROVIDE ( _lock_release = 0x4001a274 ); +PROVIDE ( _lock_release_recursive = 0x4001a288 ); +PROVIDE ( _lock_try_acquire = 0x4001a24c ); +PROVIDE ( _lock_try_acquire_recursive = 0x4001a260 ); +PROVIDE ( longjmp = 0x400005a4 ); +PROVIDE ( _lseek_r = 0x4001a19c ); +PROVIDE ( __lshrdi3 = 0x4001b034 ); +PROVIDE ( __ltdf2 = 0x400059ec ); +PROVIDE ( __ltsf2 = 0x40005688 ); +PROVIDE ( main = 0x4000f6c4 ); +PROVIDE ( malloc = 0x4001a2b0 ); +PROVIDE ( _malloc_r = 0x40019fc4 ); +PROVIDE ( _mbtowc_r = 0x400079e0 ); +PROVIDE ( MD5Final = 0x4000530c ); +PROVIDE ( MD5Init = 0x4000526c ); +PROVIDE ( MD5Update = 0x4000528c ); +PROVIDE ( md5_vector = 0x40005374 ); +PROVIDE ( memccpy = 0x4001ab00 ); +PROVIDE ( memchr = 0x4001ab24 ); +PROVIDE ( memcmp = 0x4001ab40 ); +PROVIDE ( memcpy = 0x4001aba8 ); +PROVIDE ( MemDwnLdStartMsgProc = 0x40011cec ); +PROVIDE ( MemDwnLdStopReqMsgProc = 0x40011d80 ); +PROVIDE ( _memmap_cacheattr_bp_allvalid = 0x22222222 ); +PROVIDE ( _memmap_cacheattr_bp_base = 0x00000220 ); +PROVIDE ( _memmap_cacheattr_bp_strict = 0xfffff22f ); +PROVIDE ( _memmap_cacheattr_bp_trapnull = 0x2222222f ); +PROVIDE ( _memmap_cacheattr_reset = 0x2222211f ); +PROVIDE ( _memmap_cacheattr_unused_mask = 0xfffff00f ); +PROVIDE ( _memmap_cacheattr_wb_allvalid = 0x22222112 ); +PROVIDE ( _memmap_cacheattr_wba_trapnull = 0x2222211f ); +PROVIDE ( _memmap_cacheattr_wb_base = 0x00000110 ); +PROVIDE ( _memmap_cacheattr_wbna_trapnull = 0x2222211f ); +PROVIDE ( _memmap_cacheattr_wb_strict = 0xfffff11f ); +PROVIDE ( _memmap_cacheattr_wb_trapnull = 0x2222211f ); +PROVIDE ( _memmap_cacheattr_wt_allvalid = 0x22222112 ); +PROVIDE ( _memmap_cacheattr_wt_base = 0x00000110 ); +PROVIDE ( _memmap_cacheattr_wt_strict = 0xfffff11f ); +PROVIDE ( _memmap_cacheattr_wt_trapnull = 0x2222211f ); +PROVIDE ( _memmap_vecbase_reset = 0x40000000 ); +PROVIDE ( memmove = 0x4001acb0 ); +PROVIDE ( MemPacketSendReqMsgProc = 0x40011d1c ); +PROVIDE ( memrchr = 0x4001acec ); +PROVIDE ( memset = 0x4001ad3c ); +PROVIDE ( __moddi3 = 0x4001b534 ); +PROVIDE ( __modsi3 = 0x4001afa8 ); +PROVIDE ( __muldc3 = 0x40005f0c ); +PROVIDE ( __muldf3 = 0x400057e8 ); +PROVIDE ( __muldi3 = 0x4001b1e4 ); +PROVIDE ( __mulsc3 = 0x40005ba4 ); +PROVIDE ( __mulsf3 = 0x40005524 ); +PROVIDE ( __mulsi3 = 0x4001af98 ); +PROVIDE ( multofup = 0x4001bce0 ); +PROVIDE ( __mulvdi3 = 0x40008e50 ); +PROVIDE ( __mulvsi3 = 0x40008e38 ); +PROVIDE ( must_reset = 0x3ffffcf4 ); +PROVIDE ( mz_adler32 = 0x40002e90 ); +PROVIDE ( mz_crc32 = 0x40002f58 ); +PROVIDE ( mz_free = 0x40002fa4 ); +PROVIDE ( __nedf2 = 0x40005904 ); +PROVIDE ( __negdf2 = 0x400056fc ); +PROVIDE ( __negdi2 = 0x4001b1fc ); +PROVIDE ( __negsf2 = 0x40008190 ); +PROVIDE ( __negvdi2 = 0x40008f6c ); +PROVIDE ( __negvsi2 = 0x40008f4c ); +PROVIDE ( __nesf2 = 0x400055d0 ); +PROVIDE ( _NMIExceptionVector = 0x400002c0 ); +PROVIDE ( _NMIExceptionVector_text_end = 0x400002c3 ); +PROVIDE ( _NMIExceptionVector_text_start = 0x400002c0 ); +PROVIDE ( __nsau_data = 0x3ffac870 ); +PROVIDE ( open = 0x400080c4 ); +PROVIDE ( _open_r = 0x4001a164 ); +PROVIDE ( __packed = 0x3ffffcec ); +PROVIDE ( __paritysi2 = 0x40009038 ); +PROVIDE ( _PathLocale = 0x3ffffd80 ); +PROVIDE ( phy_get_romfuncs = 0x4000a88c ); +PROVIDE ( __popcountdi2 = 0x40008fe0 ); +PROVIDE ( __popcountsi2 = 0x40008fa8 ); +PROVIDE ( __popcount_tab = 0x3ffac870 ); +PROVIDE ( __powidf2 = 0x40005b40 ); +PROVIDE ( __powisf2 = 0x40005af8 ); +PROVIDE ( _Pri_4_HandlerAddress = 0x3fffed78 ); +PROVIDE ( _Pri_5_HandlerAddress = 0x3fffed7c ); +PROVIDE ( _printf_common = 0x40000e60 ); +PROVIDE ( _printf_float = 0x4001a30c ); +PROVIDE ( _printf_i = 0x40000f2c ); +PROVIDE ( pthread_setcancelstate = 0x40019fa8 ); +PROVIDE ( _putc1 = 0x3ffffd6c ); +PROVIDE ( _putc2 = 0x3ffffd68 ); +PROVIDE ( qsort = 0x400006f4 ); +PROVIDE ( _raise_r = 0x4001a080 ); +PROVIDE ( rand = 0x40007a78 ); +PROVIDE ( rand_r = 0x40007af4 ); +PROVIDE ( RcvMsg = 0x40012f10 ); +PROVIDE ( read = 0x40008114 ); +PROVIDE ( _read_r = 0x4001a1b8 ); +PROVIDE ( realloc = 0x4001a2dc ); +PROVIDE ( _realloc_r = 0x40019ff0 ); +PROVIDE ( recv_packet = 0x40012de8 ); +PROVIDE ( _rename_r = 0x4001a038 ); +PROVIDE ( _ResetHandler = 0x4000044c ); +PROVIDE ( _ResetVector = 0x40000400 ); +PROVIDE ( _ResetVector_literal_end = 0x40000540 ); +PROVIDE ( _ResetVector_literal_start = 0x40000540 ); +PROVIDE ( _ResetVector_text_end = 0x4000053d ); +PROVIDE ( _ResetVector_text_start = 0x40000400 ); +PROVIDE ( _rodata_end = 0x3ffaff2c ); +PROVIDE ( _rodata_start = 0x3ffac600 ); +PROVIDE ( rom_abs_temp = 0x4000c330 ); +PROVIDE ( rom_ant_btrx_cfg = 0x4000a0fc ); +PROVIDE ( rom_ant_bttx_cfg = 0x4000a0c0 ); +PROVIDE ( rom_ant_dft_cfg = 0x40009fc8 ); +PROVIDE ( rom_ant_wifirx_cfg = 0x4000a03c ); +PROVIDE ( rom_ant_wifitx_cfg = 0x40009ff8 ); +PROVIDE ( rom_bb_bss_cbw40_dig = 0x40009a84 ); +PROVIDE ( rom_bb_wdg_cfg = 0x40009eb8 ); +PROVIDE ( rom_bb_wdg_test_en = 0x40009a48 ); +PROVIDE ( rom_bb_wdt_get_status = 0x40009d18 ); +PROVIDE ( rom_bb_wdt_int_enable = 0x40009cd4 ); +PROVIDE ( rom_bb_wdt_rst_enable = 0x40009cb4 ); +PROVIDE ( rom_bb_wdt_timeout_clear = 0x40009cfc ); +PROVIDE ( rom_cbw2040_cfg = 0x4000a550 ); +PROVIDE ( rom_check_noise_floor = 0x40009b4c ); +PROVIDE ( rom_chip_i2c_readReg = 0x4000a8e4 ); +PROVIDE ( rom_chip_i2c_writeReg = 0x4000a960 ); +PROVIDE ( rom_correct_rf_ana_gain = 0x4000d2b4 ); +PROVIDE ( rom_dc_iq_est = 0x4000c414 ); +PROVIDE ( rom_disable_agc = 0x400091cc ); +PROVIDE ( rom_enable_agc = 0x400091e4 ); +PROVIDE ( rom_freq_get_i2c_data = 0x4000bb84 ); +PROVIDE ( rom_freq_i2c_set_wifi_data = 0x4000b948 ); +PROVIDE ( rom_freq_i2c_write_set = 0x4000b3bc ); +PROVIDE ( rom_gen_rx_gain_table = 0x4000a300 ); +PROVIDE ( rom_get_bbgain_db = 0x400094ec ); +PROVIDE ( rom_get_data_sat = 0x40009338 ); +PROVIDE ( rom_get_fm_sar_dout = 0x4000c024 ); +PROVIDE ( rom_get_i2c_read_mask = 0x4000a8c0 ); +PROVIDE ( rom_get_power_db = 0x4000ce28 ); +PROVIDE ( rom_get_pwctrl_correct = 0x4000d470 ); +PROVIDE ( rom_get_rfcal_rxiq_data = 0x4000cab0 ); +PROVIDE ( rom_get_rf_gain_qdb = 0x4000d29c ); +PROVIDE ( rom_get_sar_dout = 0x4000d400 ); +PROVIDE ( rom_i2c_clk_sel = 0x4000a788 ); +PROVIDE ( rom_i2c_readReg = 0x4000a940 ); +PROVIDE ( rom_i2c_readReg_Mask = 0x4000a9c4 ); +PROVIDE ( rom_i2c_writeReg = 0x4000a9a8 ); +PROVIDE ( rom_i2c_writeReg_Mask = 0x4000aa00 ); +PROVIDE ( rom_index_to_txbbgain = 0x4000bd10 ); +PROVIDE ( rom_iq_est_disable = 0x4000c3d8 ); +PROVIDE ( rom_iq_est_enable = 0x4000c358 ); +PROVIDE ( rom_linear_to_db = 0x4000cdbc ); +PROVIDE ( rom_loopback_mode_en = 0x40009304 ); +PROVIDE ( rom_mac_enable_bb = 0x40009e48 ); +PROVIDE ( rom_meas_tone_pwr_db = 0x4000ce64 ); +PROVIDE ( rom_mhz2ieee = 0x4000a4e8 ); +PROVIDE ( rom_noise_floor_auto_set = 0x40009ab4 ); +PROVIDE ( rom_pbus_debugmode = 0x4000ac70 ); +PROVIDE ( rom_pbus_force_mode = 0x4000aa6c ); +PROVIDE ( rom_pbus_force_test = 0x4000abd0 ); +PROVIDE ( rom_pbus_rd = 0x4000ac2c ); +PROVIDE ( rom_pbus_rd_addr = 0x4000ab34 ); +PROVIDE ( rom_pbus_rd_shift = 0x4000ab80 ); +PROVIDE ( rom_pbus_rx_dco_cal = 0x4000c49c ); +PROVIDE ( rom_pbus_set_dco = 0x4000ae2c ); +PROVIDE ( rom_pbus_set_rxgain = 0x4000ac98 ); +PROVIDE ( rom_pbus_workmode = 0x4000ac84 ); +PROVIDE ( rom_pbus_xpd_rx_off = 0x4000acfc ); +PROVIDE ( rom_pbus_xpd_rx_on = 0x4000ad30 ); +PROVIDE ( rom_pbus_xpd_tx_off = 0x4000ad84 ); +PROVIDE ( rom_pbus_xpd_tx_on = 0x4000add4 ); +PROVIDE ( rom_phy_ant_init = 0x40009f48 ); +PROVIDE ( rom_phy_byte_to_word = 0x40009d60 ); +PROVIDE ( rom_phy_chan_dump_cfg = 0x4000a180 ); +PROVIDE ( rom_phy_chan_filt_set = 0x4000a614 ); +PROVIDE ( rom_phy_close_pa = 0x4000a810 ); +PROVIDE ( rom_phy_disable_cca = 0x40009208 ); +PROVIDE ( rom_phy_disable_low_rate = 0x4000a2b8 ); +PROVIDE ( rom_phy_enable_cca = 0x40009234 ); +PROVIDE ( rom_phy_enable_low_rate = 0x4000a280 ); +PROVIDE ( rom_phy_freq_correct = 0x4000b0b4 ); +PROVIDE ( rom_phy_get_noisefloor = 0x40009b04 ); +PROVIDE ( rom_phy_get_rx_freq = 0x4000a6ac ); +PROVIDE ( rom_phy_get_tx_rate = 0x40009d50 ); +PROVIDE ( rom_phy_rx11blr_cfg = 0x40009c5c ); +PROVIDE ( rom_phy_rx_sense_set = 0x4000a704 ); +PROVIDE ( rom_phy_set_bbfreq_init = 0x4000d3d0 ); +PROVIDE ( rom_pll_correct_dcap = 0x4000bad4 ); +PROVIDE ( rom_pow_usr = 0x4000924c ); +PROVIDE ( rom_read_hw_noisefloor = 0x40009c38 ); +PROVIDE ( rom_read_sar_dout = 0x4000bfd4 ); +PROVIDE ( rom_restart_cal = 0x4000ae74 ); +PROVIDE ( rom_rfcal_pwrctrl = 0x4000d098 ); +PROVIDE ( rom_rfcal_rxiq = 0x4000ca3c ); +PROVIDE ( rom_rfcal_txcap = 0x4000ccac ); +PROVIDE ( rom_rfpll_set_freq = 0x4000afa4 ); +PROVIDE ( rom_rftx_init = 0x4000b24c ); +PROVIDE ( rom_rx_gain_force = 0x40009558 ); +PROVIDE ( rom_rxiq_cover_mg_mp = 0x4000c954 ); +PROVIDE ( rom_rxiq_get_mis = 0x4000c7d8 ); +PROVIDE ( rom_rxiq_set_reg = 0x4000c8ec ); +PROVIDE ( rom_set_cal_rxdc = 0x400092c4 ); +PROVIDE ( rom_set_cca = 0x4000a59c ); +PROVIDE ( rom_set_chan_cal_interp = 0x4000cba4 ); +PROVIDE ( rom_set_channel_freq = 0x4000b00c ); +PROVIDE ( rom_set_loopback_gain = 0x40009268 ); +PROVIDE ( rom_set_noise_floor = 0x40009bf4 ); +PROVIDE ( rom_set_pbus_mem = 0x40009380 ); +PROVIDE ( rom_set_rf_freq_offset = 0x4000b214 ); +PROVIDE ( rom_set_rxclk_en = 0x400095cc ); +PROVIDE ( rom_set_txcap_reg = 0x4000cc34 ); +PROVIDE ( rom_set_txclk_en = 0x4000959c ); +PROVIDE ( rom_set_tx_dig_gain = 0x40009514 ); +PROVIDE ( rom_set_xpd_sar = 0x40009f08 ); +PROVIDE ( rom_spur_cal = 0x4000a47c ); +PROVIDE ( rom_spur_reg_write_one_tone = 0x400097c4 ); +PROVIDE ( rom_start_tx_tone = 0x400096f0 ); +PROVIDE ( rom_start_tx_tone_step = 0x40009608 ); +PROVIDE ( rom_stop_tx_tone = 0x4000a428 ); +PROVIDE ( _rom_store = 0x4001bed0 ); +PROVIDE ( _rom_store_table = 0x4001bd64 ); +PROVIDE ( rom_target_power_add_backoff = 0x4000d278 ); +PROVIDE ( rom_txbbgain_to_index = 0x4000bce0 ); +PROVIDE ( rom_txcal_work_mode = 0x4000bf30 ); +PROVIDE ( rom_txdc_cal_init = 0x4000bd2c ); +PROVIDE ( rom_txdc_cal_v70 = 0x4000bdc0 ); +PROVIDE ( rom_txiq_cover = 0x4000c1ac ); +PROVIDE ( rom_txiq_get_mis_pwr = 0x4000c0f8 ); +PROVIDE ( rom_txiq_set_reg = 0x4000bf64 ); +PROVIDE ( rom_tx_paon_set = 0x40009db8 ); +PROVIDE ( rom_tx_pwr_backoff = 0x4000ceb8 ); +PROVIDE ( rom_txtone_linear_pwr = 0x4000c0b0 ); +PROVIDE ( rom_wait_rfpll_cal_end = 0x4000af3c ); +PROVIDE ( rom_wifi_11g_rate_chg = 0x4000d260 ); +PROVIDE ( rom_wifi_rifs_mode_en = 0x40009d2c ); +PROVIDE ( rom_write_dac_gain2 = 0x4000a210 ); +PROVIDE ( rom_write_gain_mem = 0x400094bc ); +PROVIDE ( rom_write_pll_cap_mem = 0x4000ba58 ); +PROVIDE ( rom_write_rfpll_sdm = 0x4000aed4 ); +PROVIDE ( rom_wr_rf_freq_mem = 0x4000b2f0 ); +PROVIDE ( roundup2 = 0x4001bcd0 ); +PROVIDE ( rtc_boot_control = 0x4001002c ); +PROVIDE ( rtc_get_reset_reason = 0x4000ff58 ); +PROVIDE ( rtc_get_wakeup_cause = 0x4000ff7c ); +PROVIDE ( rtc_select_apb_bridge = 0x400100a0 ); +PROVIDE ( sbrk = 0x4000812c ); +PROVIDE ( _sbrk_r = 0x4001a0f4 ); +PROVIDE ( _scanf_float = 0x4001a328 ); +PROVIDE ( s_cdcacm_old_rts = 0x3ffffd34 ); +PROVIDE ( __sclose = 0x4001a700 ); +PROVIDE ( SelectSpiFunction = 0x40015d08 ); +PROVIDE ( SelectSpiQIO = 0x40015b88 ); +PROVIDE ( SendMsg = 0x40012d0c ); +PROVIDE ( send_packet = 0x40012cc8 ); +PROVIDE ( __seofread = 0x4001a690 ); +PROVIDE ( setjmp = 0x40000540 ); +PROVIDE ( setlocale = 0x40001c44 ); +PROVIDE ( _setlocale_r = 0x40001bdc ); +PROVIDE ( set_rtc_memory_crc = 0x40010010 ); +PROVIDE ( SetSpiDrvs = 0x40015c18 ); +PROVIDE ( __sf_fake_stderr = 0x3ffaf08c ); +PROVIDE ( __sf_fake_stdin = 0x3ffaf0cc ); +PROVIDE ( __sf_fake_stdout = 0x3ffaf0ac ); +PROVIDE ( __sflush_r = 0x400019dc ); +PROVIDE ( __sfmoreglue = 0x4001a4c8 ); +PROVIDE ( __sfp = 0x4001a590 ); +PROVIDE ( __sfp_lock_acquire = 0x4001a508 ); +PROVIDE ( __sfp_lock_release = 0x4001a514 ); +PROVIDE ( __sfputs_r = 0x40000aa0 ); +PROVIDE ( __sfvwrite_r = 0x40001310 ); +PROVIDE ( sig_matrix = 0x3ffffd57 ); +PROVIDE ( __sinit = 0x4001a538 ); +PROVIDE ( __sinit_lock_acquire = 0x4001a520 ); +PROVIDE ( __sinit_lock_release = 0x4001a52c ); +PROVIDE ( __smakebuf_r = 0x40001954 ); +PROVIDE ( software_reset = 0x40010068 ); +PROVIDE ( software_reset_cpu = 0x40010080 ); +PROVIDE ( SPI_block_erase = 0x4001623c ); +PROVIDE ( spi_cache_mode_switch = 0x40016a00 ); +PROVIDE ( SPI_chip_erase = 0x400161b8 ); +PROVIDE ( SPIClkConfig = 0x400170a0 ); +PROVIDE ( SPI_Common_Command = 0x400162e8 ); +PROVIDE ( spi_common_set_flash_cs_timing = 0x40016c0c ); +PROVIDE ( spi_dummy_len_fix = 0x40015b50 ); +PROVIDE ( SPI_Encrypt_Write = 0x400177e0 ); +PROVIDE ( SPI_Encrypt_Write_Dest = 0x400176cc ); +PROVIDE ( SPIEraseArea = 0x40017470 ); +PROVIDE ( SPIEraseBlock = 0x4001710c ); +PROVIDE ( SPIEraseChip = 0x400170ec ); +PROVIDE ( SPIEraseSector = 0x4001716c ); +PROVIDE ( spi_flash_attach = 0x40017004 ); +PROVIDE ( spi_flash_boot_attach = 0x40016fc0 ); +PROVIDE ( spi_flash_check_suspend_cb = 0x3ffffd58 ); +PROVIDE ( SPI_flashchip_data = 0x3ffffd3c ); +PROVIDE ( spi_flash_set_check_suspend_cb = 0x40015b3c ); +PROVIDE ( SPI_init = 0x40016ce8 ); +PROVIDE ( SPILock = 0x40016ed4 ); +PROVIDE ( SPIMasterReadModeCnfig = 0x40017014 ); +PROVIDE ( SPI_page_program = 0x400165a8 ); +PROVIDE ( SPIParamCfg = 0x40017500 ); +PROVIDE ( SPIRead = 0x4001728c ); +PROVIDE ( SPI_read_data = 0x40015ed8 ); +PROVIDE ( SPIReadModeCnfig = 0x40016f1c ); +PROVIDE ( SPI_read_status = 0x40016084 ); +PROVIDE ( SPI_read_status_high = 0x40016284 ); +PROVIDE ( SPI_sector_erase = 0x400161ec ); +PROVIDE ( spi_slave_download = 0x4001998c ); +PROVIDE ( spi_slave_rom_check_conn = 0x40019724 ); +PROVIDE ( spi_slave_rom_init = 0x40019774 ); +PROVIDE ( spi_slave_rom_init_hw = 0x40019b5c ); +PROVIDE ( spi_slave_rom_intr_enable = 0x40019b3c ); +PROVIDE ( spi_slave_rom_rxdma_load = 0x40019da8 ); +PROVIDE ( spi_slave_rom_txdma_load = 0x40019e3c ); +PROVIDE ( SPIUnlock = 0x40016e88 ); +PROVIDE ( SPI_user_command_read = 0x40015fc8 ); +PROVIDE ( SPI_Wait_Idle = 0x40016680 ); +PROVIDE ( SPI_WakeUp = 0x400160f4 ); +PROVIDE ( SPIWrite = 0x400171cc ); +PROVIDE ( SPI_write_enable = 0x4001655c ); +PROVIDE ( SPI_Write_Encrypt_Disable = 0x40017694 ); +PROVIDE ( SPI_Write_Encrypt_Enable = 0x40017678 ); +PROVIDE ( SPI_write_status = 0x400162a4 ); +PROVIDE ( __sprint_r = 0x40000aec ); +PROVIDE ( srand = 0x40007a24 ); +PROVIDE ( __sread = 0x4001a660 ); +PROVIDE ( __sseek = 0x4001a6cc ); +PROVIDE ( __stack = 0x3fffe710 ); +PROVIDE ( _stack_sentry = 0x3fffc410 ); +PROVIDE ( _start = 0x4000726c ); +PROVIDE ( _stat_r = 0x4001a0c4 ); +PROVIDE ( _stext = 0x40007118 ); +PROVIDE ( strcasecmp = 0x40007b38 ); +PROVIDE ( strcasestr = 0x40007b7c ); +PROVIDE ( strcat = 0x4001ad90 ); +PROVIDE ( strchr = 0x4001adb0 ); +PROVIDE ( strcmp = 0x40007be4 ); +PROVIDE ( strcoll = 0x40007ce8 ); +PROVIDE ( strcpy = 0x40007cfc ); +PROVIDE ( strcspn = 0x4001adcc ); +PROVIDE ( strdup = 0x40007d84 ); +PROVIDE ( _strdup_r = 0x40007d98 ); +PROVIDE ( string0_descr = 0x3ffaeeae ); +PROVIDE ( strlcat = 0x40007db8 ); +PROVIDE ( strlcpy = 0x4001adf8 ); +PROVIDE ( strlen = 0x40007e08 ); +PROVIDE ( strlwr = 0x40007e68 ); +PROVIDE ( str_manu_descr = 0x3ffaee9a ); +PROVIDE ( strncasecmp = 0x40007e94 ); +PROVIDE ( strncat = 0x4001ae34 ); +PROVIDE ( strncmp = 0x4001ae64 ); +PROVIDE ( strncpy = 0x40007f20 ); +PROVIDE ( strndup = 0x40007fe8 ); +PROVIDE ( _strndup_r = 0x40007ffc ); +PROVIDE ( strnlen = 0x4001ae9c ); +PROVIDE ( str_prod_descr = 0x3ffaee88 ); +PROVIDE ( strrchr = 0x40008040 ); +PROVIDE ( strsep = 0x4000806c ); +PROVIDE ( str_serial_descr = 0x3ffaee84 ); +PROVIDE ( strspn = 0x4001aebc ); +PROVIDE ( strstr = 0x4001aee8 ); +PROVIDE ( __strtok_r = 0x4001af18 ); +PROVIDE ( strtok_r = 0x4001af7c ); +PROVIDE ( strupr = 0x40008084 ); +PROVIDE ( __subdf3 = 0x400087b4 ); +PROVIDE ( __subsf3 = 0x400082a0 ); +PROVIDE ( __subvdi3 = 0x40008df4 ); +PROVIDE ( __subvsi3 = 0x40008dd0 ); +PROVIDE ( s_usb_osglue = 0x3ffffcdc ); +PROVIDE ( __swbuf = 0x4000167c ); +PROVIDE ( __swbuf_r = 0x400015bc ); +PROVIDE ( __swhatbuf_r = 0x400018f8 ); +PROVIDE ( __swrite = 0x4001a698 ); +PROVIDE ( __swsetup_r = 0x40001690 ); +PROVIDE ( _SyscallException = 0x4000732a ); +PROVIDE ( syscall_table_ptr_app = 0x3ffffd74 ); +PROVIDE ( syscall_table_ptr_pro = 0x3ffffd78 ); +PROVIDE ( _system_r = 0x4001a020 ); +PROVIDE ( tdefl_compress = 0x400041dc ); +PROVIDE ( tdefl_compress_buffer = 0x40004938 ); +PROVIDE ( tdefl_compress_mem_to_mem = 0x40004a50 ); +PROVIDE ( tdefl_compress_mem_to_output = 0x40004a30 ); +PROVIDE ( tdefl_get_adler32 = 0x40004a28 ); +PROVIDE ( tdefl_get_prev_return_status = 0x40004a20 ); +PROVIDE ( tdefl_init = 0x40004954 ); +PROVIDE ( tdefl_write_image_to_png_file_in_memory = 0x40004a64 ); +PROVIDE ( tdefl_write_image_to_png_file_in_memory_ex = 0x40004a58 ); +PROVIDE ( _text_end = 0x4001bed0 ); +PROVIDE ( _text_start = 0x40007118 ); +PROVIDE ( _times_r = 0x4001a050 ); +PROVIDE ( tinfl_decompress = 0x40003000 ); +PROVIDE ( tinfl_decompress_mem_to_callback = 0x400041a8 ); +PROVIDE ( tinfl_decompress_mem_to_mem = 0x40004168 ); +PROVIDE ( toascii = 0x4001af90 ); +PROVIDE ( tolower = 0x40008158 ); +PROVIDE ( toupper = 0x40008174 ); +PROVIDE ( __truncdfsf2 = 0x40008c64 ); +PROVIDE ( uart_acm_dev = 0x3ffffcf8 ); +PROVIDE ( uartAttach = 0x40012890 ); +PROVIDE ( uart_baudrate_detect = 0x400128f0 ); +PROVIDE ( uart_buff_switch = 0x40012d64 ); +PROVIDE ( UartConnCheck = 0x40011ab4 ); +PROVIDE ( UartConnectProc = 0x40011da8 ); +PROVIDE ( UartDev = 0x3ffffcfc ); +PROVIDE ( UartDev_buff_uart_no = 0x3ffffd14 ); +PROVIDE ( uart_div_modify = 0x40012984 ); +PROVIDE ( uart_div_reinit = 0x400129d0 ); +PROVIDE ( UartDwnLdProc = 0x400121ac ); +PROVIDE ( UartGetCmdLn = 0x40012f28 ); +PROVIDE ( Uart_Init = 0x40012a04 ); +PROVIDE ( Uart_Init_USB = 0x40012818 ); +PROVIDE ( UartRegReadProc = 0x40011df8 ); +PROVIDE ( UartRegWriteProc = 0x40011db8 ); +PROVIDE ( uart_rx_intr_handler = 0x40012690 ); +PROVIDE ( uart_rx_one_char = 0x40012bf0 ); +PROVIDE ( uart_rx_one_char_block = 0x40012b9c ); +PROVIDE ( uart_rx_readbuff = 0x40012d1c ); +PROVIDE ( UartRxString = 0x40012c84 ); +PROVIDE ( UartSecureDwnLdProc = 0x40012464 ); +PROVIDE ( UartSetBaudProc = 0x40011e54 ); +PROVIDE ( UartSpiAttachProc = 0x40011e0c ); +PROVIDE ( UartSpiReadProc = 0x40011e28 ); +PROVIDE ( uart_tx_flush = 0x40012b40 ); +/* PROVIDE ( uart_tx_one_char = 0x40012b10 ); */ +/* Note: remapping this to uart_tx_one_char2, to keep consistency */ +PROVIDE ( uart_tx_one_char = 0x40012b28 ); +PROVIDE ( uart_tx_one_char2 = 0x40012b28 ); +PROVIDE ( uart_tx_switch = 0x400128e4 ); +PROVIDE ( uart_tx_wait_idle = 0x40012b6c ); +PROVIDE ( uart_usb_enable_reset_on_rts = 0x40012858 ); +PROVIDE ( Uart_USB_Send_Testament = 0x400127d8 ); +PROVIDE ( __ucmpdi2 = 0x40005a9c ); +PROVIDE ( __udivdi3 = 0x4001b7dc ); +PROVIDE ( __udivmoddi4 = 0x40006e20 ); +PROVIDE ( __udivsi3 = 0x4001afb0 ); +PROVIDE ( __udiv_w_sdiv = 0x40006e18 ); +PROVIDE ( __umoddi3 = 0x4001ba60 ); +PROVIDE ( __umodsi3 = 0x4001afb8 ); +PROVIDE ( __umulsidi3 = 0x4001afc0 ); +PROVIDE ( _unlink_r = 0x4001a094 ); +PROVIDE ( __unorddf2 = 0x40005a50 ); +PROVIDE ( __unordsf2 = 0x400056d4 ); +PROVIDE ( usb_cancel_transfer = 0x40015200 ); +PROVIDE ( usb_data_stuff = 0x3ffacc88 ); +PROVIDE ( usb_dc_attach = 0x40013ecc ); +PROVIDE ( usb_dc_check_poll_for_interrupts = 0x40014980 ); +PROVIDE ( usb_dc_detach = 0x40014010 ); +PROVIDE ( usb_dc_ep_check_cap = 0x40014094 ); +PROVIDE ( usb_dc_ep_clear_stall = 0x400142f0 ); +PROVIDE ( usb_dc_ep_configure = 0x400140d8 ); +PROVIDE ( usb_dc_ep_disable = 0x400144ec ); +PROVIDE ( usb_dc_ep_enable = 0x4001442c ); +PROVIDE ( usb_dc_ep_flush = 0x400145b8 ); +PROVIDE ( usb_dc_ep_halt = 0x4001435c ); +PROVIDE ( usb_dc_ep_is_stalled = 0x400143bc ); +PROVIDE ( usb_dc_ep_mps = 0x40014958 ); +PROVIDE ( usb_dc_ep_read = 0x400148d8 ); +PROVIDE ( usb_dc_ep_read_continue = 0x40014898 ); +PROVIDE ( usb_dc_ep_read_wait = 0x400147bc ); +PROVIDE ( usb_dc_ep_set_callback = 0x40014910 ); +PROVIDE ( usb_dc_ep_set_stall = 0x40014290 ); +PROVIDE ( usb_dc_ep_write = 0x40014684 ); +PROVIDE ( usb_dc_ep_write_would_block = 0x40014624 ); +PROVIDE ( usb_dc_prepare_persist = 0x40013bec ); +PROVIDE ( usb_dc_reset = 0x40014044 ); +PROVIDE ( usb_dc_set_address = 0x4001405c ); +PROVIDE ( usb_dc_set_status_callback = 0x4001494c ); +PROVIDE ( usb_deconfig = 0x40014fa8 ); +PROVIDE ( usb_dev_get_configuration = 0x40014f4c ); +PROVIDE ( usb_dev_resume = 0x40014f38 ); +PROVIDE ( usb_dfu_force_detach = 0x400155b0 ); +PROVIDE ( usb_dfu_init = 0x40015598 ); +PROVIDE ( usb_dfu_set_detach_cb = 0x400152dc ); +PROVIDE ( usb_disable = 0x40015058 ); +PROVIDE ( usb_dw_isr_handler = 0x40013c48 ); +PROVIDE ( usb_enable = 0x40014fc8 ); +PROVIDE ( usb_ep_clear_stall = 0x400150c8 ); +PROVIDE ( usb_ep_read_continue = 0x400150f0 ); +PROVIDE ( usb_ep_read_wait = 0x400150d8 ); +PROVIDE ( usb_ep_set_stall = 0x400150b8 ); +PROVIDE ( usb_get_descriptor = 0x400149c0 ); +PROVIDE ( usb_read = 0x400150a0 ); +PROVIDE ( usb_set_config = 0x40014f64 ); +PROVIDE ( usb_set_current_descriptor = 0x400149a8 ); +PROVIDE ( usb_transfer = 0x40015150 ); +PROVIDE ( usb_transfer_ep_callback = 0x40015100 ); +PROVIDE ( usb_transfer_sync = 0x40015250 ); +PROVIDE ( usb_write = 0x40015088 ); +PROVIDE ( usb_write_would_block = 0x40015078 ); +PROVIDE ( user_code_start = 0x3fffe714 ); +PROVIDE ( _UserExceptionVector = 0x40000340 ); +PROVIDE ( _UserExceptionVector_text_end = 0x40000357 ); +PROVIDE ( _UserExceptionVector_text_start = 0x40000340 ); +PROVIDE ( VerifyFlashMd5Proc = 0x40012004 ); +PROVIDE ( vfiprintf = 0x40000e40 ); +PROVIDE ( _vfiprintf_r = 0x40000b58 ); +PROVIDE ( vfprintf = 0x40000e40 ); +PROVIDE ( _vfprintf_r = 0x40000b58 ); +PROVIDE ( Wait_SPI_Idle = 0x40016188 ); +PROVIDE ( wcrtomb = 0x400012f4 ); +PROVIDE ( _wcrtomb_r = 0x400012a0 ); +PROVIDE ( _wctomb_r = 0x400018ac ); +PROVIDE ( _WindowOverflow12 = 0x40000100 ); +PROVIDE ( _WindowOverflow4 = 0x40000000 ); +PROVIDE ( _WindowOverflow8 = 0x40000080 ); +PROVIDE ( _WindowUnderflow12 = 0x40000140 ); +PROVIDE ( _WindowUnderflow4 = 0x40000040 ); +PROVIDE ( _WindowUnderflow8 = 0x400000c0 ); +PROVIDE ( _WindowVectors_text_end = 0x40000170 ); +PROVIDE ( _WindowVectors_text_start = 0x40000000 ); +PROVIDE ( write = 0x40008140 ); +PROVIDE ( _write_r = 0x4001a180 ); +PROVIDE ( __XT_EXCEPTION_DESCS__ = 0x3ffaff2c ); +PROVIDE ( __XT_EXCEPTION_DESCS_END__ = 0x3ffaff2c ); +PROVIDE ( __XT_EXCEPTION_TABLE__ = 0x3ffafe3a ); +PROVIDE ( xthal_bcopy = 0x4001a918 ); +PROVIDE ( xthal_copy123 = 0x4001a9ac ); +PROVIDE ( xthal_get_ccompare = 0x4001aabc ); +PROVIDE ( xthal_get_ccount = 0x4001aa90 ); +PROVIDE ( xthal_get_interrupt = 0x4001aadc ); +PROVIDE ( Xthal_intlevel = 0x3ffaf06c ); +PROVIDE ( xthal_memcpy = 0x4001a93c ); +PROVIDE ( xthal_set_ccompare = 0x4001aa98 ); +PROVIDE ( xthal_set_intclear = 0x4001aae4 ); +PROVIDE ( xthals_hw_configid0 = 0xc2ecfafe ); +PROVIDE ( xthals_hw_configid1 = 0x224787b1 ); +PROVIDE ( xthals_release_major = 0x00002ee0 ); +PROVIDE ( xthals_release_minor = 0x00000009 ); +PROVIDE ( _xtos_alloca_handler = 0x40000010 ); +PROVIDE ( xtos_cause3_handler = 0x40007370 ); +PROVIDE ( xtos_c_handler_table = 0x3fffec78 ); +PROVIDE ( xtos_c_wrapper_handler = 0x40007380 ); +PROVIDE ( _xtos_enabled = 0x3fffed80 ); +PROVIDE ( xtos_exc_handler_table = 0x3fffeb78 ); +PROVIDE ( xtos_interrupt_mask_table = 0x3fffee88 ); +PROVIDE ( xtos_interrupt_table = 0x3fffed88 ); +PROVIDE ( _xtos_ints_off = 0x4001a3e0 ); +PROVIDE ( _xtos_ints_on = 0x4001a3bc ); +PROVIDE ( _xtos_intstruct = 0x3fffed80 ); +PROVIDE ( _xtos_l1int_handler = 0x400073ec ); +PROVIDE ( xtos_p_none = 0x4001a8a0 ); +PROVIDE ( _xtos_restore_intlevel = 0x400074cc ); +PROVIDE ( _xtos_return_from_exc = 0x4001a8a8 ); +PROVIDE ( _xtos_set_exception_handler = 0x400072b4 ); +PROVIDE ( _xtos_set_interrupt_handler = 0x4001a380 ); +PROVIDE ( _xtos_set_interrupt_handler_arg = 0x4001a344 ); +PROVIDE ( _xtos_set_intlevel = 0x4001a8c0 ); +PROVIDE ( _xtos_set_min_intlevel = 0x4001a8dc ); +PROVIDE ( _xtos_set_vpri = 0x400074d8 ); +PROVIDE ( _xtos_syscall_handler = 0x400072fc ); +PROVIDE ( xtos_unhandled_exception = 0x4001a900 ); +PROVIDE ( xtos_unhandled_interrupt = 0x4001a910 ); +PROVIDE ( _xtos_vectors_ref_ = 0x00000000 ); +PROVIDE ( _xtos_vpri_enabled = 0x3fffed84 ); diff --git a/tools/flasher_stub/ld/rom_32s3.ld b/tools/flasher_stub/ld/rom_32s3.ld new file mode 100644 index 0000000000..17d4127b08 --- /dev/null +++ b/tools/flasher_stub/ld/rom_32s3.ld @@ -0,0 +1,2287 @@ +/* ROM function interface esp32s3.rom.ld for esp32s3 + * + * + * Generated from ./interface-esp32s3.yml md5sum 39c4ce259b11323b9404c192b01b712b + * + * Compatible with ROM where ECO version equal or greater to 0. + * + * THIS FILE WAS AUTOMATICALLY GENERATED. DO NOT EDIT. + */ + +PROVIDE ( SPIWrite = esp_rom_spiflash_write); +PROVIDE ( SPI_read_status_high = esp_rom_spiflash_read_statushigh); +PROVIDE ( SPI_write_status = esp_rom_spiflash_write_status); +PROVIDE ( SPIRead = esp_rom_spiflash_read); +PROVIDE ( SPIParamCfg = esp_rom_spiflash_config_param); +PROVIDE ( SPIEraseChip = esp_rom_spiflash_erase_chip); +PROVIDE ( SPIEraseSector = esp_rom_spiflash_erase_sector); +PROVIDE ( SPIEraseBlock = esp_rom_spiflash_erase_block); +PROVIDE ( SPI_Write_Encrypt_Enable = esp_rom_spiflash_write_encrypted_enable); +PROVIDE ( SPI_Write_Encrypt_Disable = esp_rom_spiflash_write_encrypted_disable); +PROVIDE ( SPI_Encrypt_Write = esp_rom_spiflash_write_encrypted); +PROVIDE ( opi_flash_wren = esp_rom_opiflash_wren); + + +/*************************************** + Group common + ***************************************/ + +/* Functions */ +rtc_get_reset_reason = 0x4000057c; +analog_super_wdt_reset_happened = 0x40000588; +jtag_cpu_reset_happened = 0x40000594; +rtc_get_wakeup_cause = 0x400005a0; +rtc_select_apb_bridge = 0x400005ac; +rtc_unhold_all_pads = 0x400005b8; +ets_is_print_boot = 0x400005c4; +ets_printf = 0x400005d0; +ets_install_putc1 = 0x400005dc; +ets_install_uart_printf = 0x400005e8; +ets_install_putc2 = 0x400005f4; +PROVIDE( ets_delay_us = 0x40000600 ); +ets_get_stack_info = 0x4000060c; +ets_install_lock = 0x40000618; +ets_backup_dma_copy = 0x40000624; +ets_apb_backup_init_lock_func = 0x40000630; +UartRxString = 0x4000063c; +uart_tx_one_char = 0x40000648; +uart_tx_one_char2 = 0x40000654; +uart_rx_one_char = 0x40000660; +uart_rx_one_char_block = 0x4000066c; +uart_rx_readbuff = 0x40000678; +uartAttach = 0x40000684; +uart_tx_flush = 0x40000690; +uart_tx_wait_idle = 0x4000069c; +uart_div_modify = 0x400006a8; +ets_write_char_uart = 0x400006b4; +uart_tx_switch = 0x400006c0; +multofup = 0x400006cc; +software_reset = 0x400006d8; +software_reset_cpu = 0x400006e4; +assist_debug_clock_enable = 0x400006f0; +assist_debug_record_enable = 0x400006fc; +clear_super_wdt_reset_flag = 0x40000708; +disable_default_watchdog = 0x40000714; +ets_set_appcpu_boot_addr = 0x40000720; +esp_rom_set_rtc_wake_addr = 0x4000072c; +esp_rom_get_rtc_wake_addr = 0x40000738; +send_packet = 0x40000744; +recv_packet = 0x40000750; +GetUartDevice = 0x4000075c; +GetSecurityInfoProc = 0x40048174; +UartDwnLdProc = 0x40000768; +Uart_Init = 0x40000774; +ets_set_user_start = 0x40000780; +/* Data (.data, .bss, .rodata) */ +ets_rom_layout_p = 0x3ff1fffc; +ets_ops_table_ptr = 0x3fcefffc; + + +/*************************************** + Group miniz + ***************************************/ + +/* Functions */ +mz_adler32 = 0x4000078c; +mz_crc32 = 0x40000798; +mz_free = 0x400007a4; +tdefl_compress = 0x400007b0; +tdefl_compress_buffer = 0x400007bc; +tdefl_compress_mem_to_heap = 0x400007c8; +tdefl_compress_mem_to_mem = 0x400007d4; +tdefl_compress_mem_to_output = 0x400007e0; +tdefl_get_adler32 = 0x400007ec; +tdefl_get_prev_return_status = 0x400007f8; +tdefl_init = 0x40000804; +tdefl_write_image_to_png_file_in_memory = 0x40000810; +tdefl_write_image_to_png_file_in_memory_ex = 0x4000081c; +tinfl_decompress = 0x40000828; +tinfl_decompress_mem_to_callback = 0x40000834; +tinfl_decompress_mem_to_heap = 0x40000840; +tinfl_decompress_mem_to_mem = 0x4000084c; + + +/*************************************** + Group tjpgd + ***************************************/ + +/* Functions */ +jd_prepare = 0x40000858; +jd_decomp = 0x40000864; + + +/*************************************** + Group esp-dsp + ***************************************/ + +/* Data (.data, .bss, .rodata) */ +dsps_fft2r_w_table_fc32_1024 = 0x3fcefff8; + + +/*************************************** + Group opi_flash + ***************************************/ + +/* Functions */ +PROVIDE( opi_flash_set_lock_func = 0x40000870 ); +PROVIDE( esp_rom_spi_cmd_config = 0x4000087c ); +PROVIDE( esp_rom_spi_cmd_start = 0x40000888 ); +PROVIDE( esp_rom_opiflash_pin_config = 0x40000894 ); +PROVIDE( esp_rom_spi_set_op_mode = 0x400008a0 ); +PROVIDE( esp_rom_opiflash_mode_reset = 0x400008ac ); +PROVIDE( esp_rom_opiflash_exec_cmd = 0x400008b8 ); +PROVIDE( esp_rom_opiflash_soft_reset = 0x400008c4 ); +PROVIDE( esp_rom_opiflash_read_id = 0x400008d0 ); +PROVIDE( esp_rom_opiflash_rdsr = 0x400008dc ); +PROVIDE( esp_rom_opiflash_wait_idle = 0x400008e8 ); +PROVIDE( esp_rom_opiflash_wren = 0x400008f4 ); +PROVIDE( esp_rom_opiflash_erase_sector = 0x40000900 ); +PROVIDE( esp_rom_opiflash_erase_block_64k = 0x4000090c ); +PROVIDE( esp_rom_opiflash_erase_area = 0x40000918 ); +PROVIDE( esp_rom_opiflash_read = 0x40000924 ); +PROVIDE( esp_rom_opiflash_write = 0x40000930 ); +PROVIDE( esp_rom_spi_set_dtr_swap_mode = 0x4000093c ); +PROVIDE( esp_rom_opiflash_exit_continuous_read_mode = 0x40000948 ); +PROVIDE( esp_rom_opiflash_legacy_driver_init = 0x40000954 ); +/* Data (.data, .bss, .rodata) */ +PROVIDE( rom_opiflash_cmd_def = 0x3fcefff4 ); +PROVIDE( rom_spi_usr_cmd_legacy_funcs = 0x3fcefff0 ); + + +/*************************************** + Group spiflash_legacy + ***************************************/ + +/* Functions */ +PROVIDE( esp_rom_spiflash_wait_idle = 0x40000960 ); +PROVIDE( esp_rom_spiflash_write_encrypted = 0x4000096c ); +PROVIDE( esp_rom_spiflash_write_encrypted_dest = 0x40000978 ); +PROVIDE( esp_rom_spiflash_write_encrypted_enable = 0x40000984 ); +PROVIDE( esp_rom_spiflash_write_encrypted_disable = 0x40000990 ); +PROVIDE( esp_rom_spiflash_erase_chip = 0x4000099c ); +PROVIDE( _esp_rom_spiflash_erase_sector = 0x400009a8 ); +PROVIDE( _esp_rom_spiflash_erase_block = 0x400009b4 ); +PROVIDE( _esp_rom_spiflash_write = 0x400009c0 ); +PROVIDE( _esp_rom_spiflash_read = 0x400009cc ); +PROVIDE( _esp_rom_spiflash_unlock = 0x400009d8 ); +PROVIDE( _SPIEraseArea = 0x400009e4 ); +PROVIDE( _SPI_write_enable = 0x400009f0 ); +PROVIDE( esp_rom_spiflash_erase_sector = 0x400009fc ); +PROVIDE( esp_rom_spiflash_erase_block = 0x40000a08 ); +PROVIDE( esp_rom_spiflash_write = 0x40000a14 ); +PROVIDE( esp_rom_spiflash_read = 0x40000a20 ); +PROVIDE( esp_rom_spiflash_unlock = 0x40000a2c ); +PROVIDE( SPIEraseArea = 0x40000a38 ); +PROVIDE( SPI_write_enable = 0x40000a44 ); +PROVIDE( esp_rom_spiflash_config_param = 0x40000a50 ); +PROVIDE( esp_rom_spiflash_read_user_cmd = 0x40000a5c ); +PROVIDE( esp_rom_spiflash_select_qio_pins = 0x40000a68 ); +PROVIDE( esp_rom_spi_flash_auto_sus_res = 0x40000a74 ); +PROVIDE( esp_rom_spi_flash_send_resume = 0x40000a80 ); +PROVIDE( esp_rom_spi_flash_update_id = 0x40000a8c ); +PROVIDE( esp_rom_spiflash_config_clk = 0x40000a98 ); +PROVIDE( esp_rom_spiflash_config_readmode = 0x40000aa4 ); +PROVIDE( esp_rom_spiflash_read_status = 0x40000ab0 ); +PROVIDE( esp_rom_spiflash_read_statushigh = 0x40000abc ); +PROVIDE( esp_rom_spiflash_write_status = 0x40000ac8 ); +PROVIDE( esp_rom_opiflash_cache_mode_config = 0x40000ad4 ); +PROVIDE( esp_rom_spiflash_auto_wait_idle = 0x40000ae0 ); +PROVIDE( spi_flash_attach = 0x40000aec ); +PROVIDE( spi_flash_get_chip_size = 0x40000af8 ); +PROVIDE( spi_flash_guard_set = 0x40000b04 ); +PROVIDE( spi_flash_guard_get = 0x40000b10 ); +PROVIDE( spi_flash_write_config_set = 0x40000b1c ); +PROVIDE( spi_flash_write_config_get = 0x40000b28 ); +PROVIDE( spi_flash_safe_write_address_func_set = 0x40000b34 ); +PROVIDE( spi_flash_unlock = 0x40000b40 ); +PROVIDE( spi_flash_erase_range = 0x40000b4c ); +PROVIDE( spi_flash_erase_sector = 0x40000b58 ); +PROVIDE( spi_flash_write = 0x40000b64 ); +PROVIDE( spi_flash_read = 0x40000b70 ); +PROVIDE( spi_flash_write_encrypted = 0x40000b7c ); +PROVIDE( spi_flash_read_encrypted = 0x40000b88 ); +PROVIDE( spi_flash_mmap_os_func_set = 0x40000b94 ); +PROVIDE( spi_flash_mmap_page_num_init = 0x40000ba0 ); +PROVIDE( spi_flash_mmap = 0x40000bac ); +PROVIDE( spi_flash_mmap_pages = 0x40000bb8 ); +PROVIDE( spi_flash_munmap = 0x40000bc4 ); +PROVIDE( spi_flash_mmap_dump = 0x40000bd0 ); +PROVIDE( spi_flash_check_and_flush_cache = 0x40000bdc ); +PROVIDE( spi_flash_mmap_get_free_pages = 0x40000be8 ); +PROVIDE( spi_flash_cache2phys = 0x40000bf4 ); +PROVIDE( spi_flash_phys2cache = 0x40000c00 ); +PROVIDE( spi_flash_disable_cache = 0x40000c0c ); +PROVIDE( spi_flash_restore_cache = 0x40000c18 ); +PROVIDE( spi_flash_cache_enabled = 0x40000c24 ); +PROVIDE( spi_flash_enable_cache = 0x40000c30 ); +PROVIDE( spi_cache_mode_switch = 0x40000c3c ); +PROVIDE( spi_common_set_dummy_output = 0x40000c48 ); +PROVIDE( spi_common_set_flash_cs_timing = 0x40000c54 ); +PROVIDE( esp_rom_spi_set_address_bit_len = 0x40000c60 ); +PROVIDE( esp_enable_cache_flash_wrap = 0x40000c6c ); +PROVIDE( SPILock = 0x40000c78 ); +PROVIDE( SPIMasterReadModeCnfig = 0x40000c84 ); +PROVIDE( SPI_Common_Command = 0x40000c90 ); +PROVIDE( SPI_WakeUp = 0x40000c9c ); +PROVIDE( SPI_block_erase = 0x40000ca8 ); +PROVIDE( SPI_chip_erase = 0x40000cb4 ); +PROVIDE( SPI_init = 0x40000cc0 ); +PROVIDE( SPI_page_program = 0x40000ccc ); +PROVIDE( SPI_read_data = 0x40000cd8 ); +PROVIDE( SPI_sector_erase = 0x40000ce4 ); +PROVIDE( SelectSpiFunction = 0x40000cf0 ); +PROVIDE( SetSpiDrvs = 0x40000cfc ); +PROVIDE( Wait_SPI_Idle = 0x40000d08 ); +PROVIDE( spi_dummy_len_fix = 0x40000d14 ); +PROVIDE( Disable_QMode = 0x40000d20 ); +PROVIDE( Enable_QMode = 0x40000d2c ); +/* Data (.data, .bss, .rodata) */ +PROVIDE( rom_spiflash_legacy_funcs = 0x3fceffe8 ); +PROVIDE( rom_spiflash_legacy_data = 0x3fceffe4 ); +PROVIDE( g_flash_guard_ops = 0x3fceffec ); + + +/*************************************** + Group hal_soc + ***************************************/ + +/* Functions */ +PROVIDE( spi_flash_hal_poll_cmd_done = 0x40000d38 ); +PROVIDE( spi_flash_hal_device_config = 0x40000d44 ); +PROVIDE( spi_flash_hal_configure_host_io_mode = 0x40000d50 ); +PROVIDE( spi_flash_hal_common_command = 0x40000d5c ); +PROVIDE( spi_flash_hal_read = 0x40000d68 ); +PROVIDE( spi_flash_hal_erase_chip = 0x40000d74 ); +PROVIDE( spi_flash_hal_erase_sector = 0x40000d80 ); +PROVIDE( spi_flash_hal_erase_block = 0x40000d8c ); +PROVIDE( spi_flash_hal_program_page = 0x40000d98 ); +PROVIDE( spi_flash_hal_set_write_protect = 0x40000da4 ); +PROVIDE( spi_flash_hal_host_idle = 0x40000db0 ); +PROVIDE( wdt_hal_init = 0x40000dbc ); +PROVIDE( wdt_hal_deinit = 0x40000dc8 ); +PROVIDE( wdt_hal_config_stage = 0x40000dd4 ); +PROVIDE( wdt_hal_write_protect_disable = 0x40000de0 ); +PROVIDE( wdt_hal_write_protect_enable = 0x40000dec ); +PROVIDE( wdt_hal_enable = 0x40000df8 ); +PROVIDE( wdt_hal_disable = 0x40000e04 ); +PROVIDE( wdt_hal_handle_intr = 0x40000e10 ); +PROVIDE( wdt_hal_feed = 0x40000e1c ); +PROVIDE( wdt_hal_set_flashboot_en = 0x40000e28 ); +PROVIDE( wdt_hal_is_enabled = 0x40000e34 ); +PROVIDE( systimer_hal_get_counter_value = 0x40000e40 ); +PROVIDE( systimer_hal_get_time = 0x40000e4c ); +PROVIDE( systimer_hal_set_alarm_target = 0x40000e58 ); +PROVIDE( systimer_hal_set_alarm_period = 0x40000e64 ); +PROVIDE( systimer_hal_get_alarm_value = 0x40000e70 ); +PROVIDE( systimer_hal_enable_alarm_int = 0x40000e7c ); +PROVIDE( systimer_hal_on_apb_freq_update = 0x40000e88 ); +PROVIDE( systimer_hal_counter_value_advance = 0x40000e94 ); +PROVIDE( systimer_hal_enable_counter = 0x40000ea0 ); +PROVIDE( systimer_hal_init = 0x40000eac ); +PROVIDE( systimer_hal_select_alarm_mode = 0x40000eb8 ); +PROVIDE( systimer_hal_connect_alarm_counter = 0x40000ec4 ); + + +/*************************************** + Group spi_flash_chips + ***************************************/ + +/* Functions */ +PROVIDE( spi_flash_chip_generic_probe = 0x40000ed0 ); +PROVIDE( spi_flash_chip_generic_detect_size = 0x40000edc ); +PROVIDE( spi_flash_chip_generic_write = 0x40000ee8 ); +PROVIDE( spi_flash_chip_generic_write_encrypted = 0x40000ef4 ); +PROVIDE( spi_flash_chip_generic_set_write_protect = 0x40000f00 ); +PROVIDE( spi_flash_common_write_status_16b_wrsr = 0x40000f0c ); +PROVIDE( spi_flash_chip_generic_reset = 0x40000f18 ); +PROVIDE( spi_flash_chip_generic_erase_chip = 0x40000f24 ); +PROVIDE( spi_flash_chip_generic_erase_sector = 0x40000f30 ); +PROVIDE( spi_flash_chip_generic_erase_block = 0x40000f3c ); +PROVIDE( spi_flash_chip_generic_page_program = 0x40000f48 ); +PROVIDE( spi_flash_chip_generic_get_write_protect = 0x40000f54 ); +PROVIDE( spi_flash_common_read_status_16b_rdsr_rdsr2 = 0x40000f60 ); +PROVIDE( spi_flash_chip_generic_read_reg = 0x40000f6c ); +PROVIDE( spi_flash_chip_generic_yield = 0x40000f78 ); +PROVIDE( spi_flash_generic_wait_host_idle = 0x40000f84 ); +PROVIDE( spi_flash_chip_generic_wait_idle = 0x40000f90 ); +PROVIDE( spi_flash_chip_generic_config_host_io_mode = 0x40000f9c ); +PROVIDE( spi_flash_chip_generic_read = 0x40000fa8 ); +PROVIDE( spi_flash_common_read_status_8b_rdsr2 = 0x40000fb4 ); +PROVIDE( spi_flash_chip_generic_get_io_mode = 0x40000fc0 ); +PROVIDE( spi_flash_common_read_status_8b_rdsr = 0x40000fcc ); +PROVIDE( spi_flash_common_write_status_8b_wrsr = 0x40000fd8 ); +PROVIDE( spi_flash_common_write_status_8b_wrsr2 = 0x40000fe4 ); +PROVIDE( spi_flash_common_set_io_mode = 0x40000ff0 ); +PROVIDE( spi_flash_chip_generic_set_io_mode = 0x40000ffc ); +PROVIDE( spi_flash_chip_gd_get_io_mode = 0x40001008 ); +PROVIDE( spi_flash_chip_gd_probe = 0x40001014 ); +PROVIDE( spi_flash_chip_gd_set_io_mode = 0x40001020 ); +/* Data (.data, .bss, .rodata) */ +PROVIDE( spi_flash_chip_generic_config_data = 0x3fceffe0 ); + + +/*************************************** + Group memspi_host + ***************************************/ + +/* Functions */ +PROVIDE( memspi_host_read_id_hs = 0x4000102c ); +PROVIDE( memspi_host_read_status_hs = 0x40001038 ); +PROVIDE( memspi_host_flush_cache = 0x40001044 ); +PROVIDE( memspi_host_erase_chip = 0x40001050 ); +PROVIDE( memspi_host_erase_sector = 0x4000105c ); +PROVIDE( memspi_host_erase_block = 0x40001068 ); +PROVIDE( memspi_host_program_page = 0x40001074 ); +PROVIDE( memspi_host_read = 0x40001080 ); +PROVIDE( memspi_host_set_write_protect = 0x4000108c ); +PROVIDE( memspi_host_set_max_read_len = 0x40001098 ); +PROVIDE( memspi_host_read_data_slicer = 0x400010a4 ); +PROVIDE( memspi_host_write_data_slicer = 0x400010b0 ); + + +/*************************************** + Group esp_flash + ***************************************/ + +/* Functions */ +PROVIDE( esp_flash_chip_driver_initialized = 0x400010bc ); +PROVIDE( esp_flash_read_id = 0x400010c8 ); +PROVIDE( esp_flash_get_size = 0x400010d4 ); +PROVIDE( esp_flash_erase_chip = 0x400010e0 ); +PROVIDE( esp_flash_erase_region = 0x400010ec ); +PROVIDE( esp_flash_get_chip_write_protect = 0x400010f8 ); +PROVIDE( esp_flash_set_chip_write_protect = 0x40001104 ); +PROVIDE( esp_flash_get_protectable_regions = 0x40001110 ); +PROVIDE( esp_flash_get_protected_region = 0x4000111c ); +PROVIDE( esp_flash_set_protected_region = 0x40001128 ); +PROVIDE( esp_flash_read = 0x40001134 ); +PROVIDE( esp_flash_write = 0x40001140 ); +PROVIDE( esp_flash_write_encrypted = 0x4000114c ); +PROVIDE( esp_flash_read_encrypted = 0x40001158 ); +PROVIDE( esp_flash_get_io_mode = 0x40001164 ); +PROVIDE( esp_flash_set_io_mode = 0x40001170 ); +PROVIDE( spi_flash_boot_attach = 0x4000117c ); +PROVIDE( spi_flash_dump_counters = 0x40001188 ); +PROVIDE( spi_flash_get_counters = 0x40001194 ); +PROVIDE( spi_flash_op_counters_config = 0x400011a0 ); +PROVIDE( spi_flash_reset_counters = 0x400011ac ); +PROVIDE( esp_flash_read_chip_id = 0x400011b8 ); +PROVIDE( detect_spi_flash_chip = 0x400011c4 ); +PROVIDE( esp_rom_spiflash_write_disable = 0x400011d0 ); +/* Data (.data, .bss, .rodata) */ +PROVIDE( esp_flash_default_chip = 0x3fceffdc ); +PROVIDE( esp_flash_api_funcs = 0x3fceffd8 ); + + +/*************************************** + Group cache + ***************************************/ + +/* Functions */ +PROVIDE( Cache_Get_ICache_Line_Size = 0x400015fc ); +PROVIDE( Cache_Get_DCache_Line_Size = 0x40001608 ); +PROVIDE( Cache_Get_Mode = 0x40001614 ); +PROVIDE( Cache_Set_ICache_Mode = 0x40001620 ); +PROVIDE( Cache_Set_DCache_Mode = 0x4000162c ); +PROVIDE( Cache_Address_Through_ICache = 0x40001638 ); +PROVIDE( Cache_Address_Through_DCache = 0x40001644 ); +PROVIDE( Cache_Set_Default_Mode = 0x40001650 ); +PROVIDE( Cache_Enable_Defalut_ICache_Mode = 0x4000165c ); +PROVIDE( ROM_Boot_Cache_Init = 0x40001668 ); +PROVIDE( Cache_Invalidate_ICache_Items = 0x40001674 ); +PROVIDE( Cache_Invalidate_DCache_Items = 0x40001680 ); +PROVIDE( Cache_Clean_Items = 0x4000168c ); +PROVIDE( Cache_WriteBack_Items = 0x40001698 ); +PROVIDE( Cache_Op_Addr = 0x400016a4 ); +PROVIDE( Cache_Invalidate_Addr = 0x400016b0 ); +PROVIDE( Cache_Clean_Addr = 0x400016bc ); +PROVIDE( Cache_WriteBack_Addr = 0x400016c8 ); +PROVIDE( Cache_Invalidate_ICache_All = 0x400016d4 ); +PROVIDE( Cache_Invalidate_DCache_All = 0x400016e0 ); +PROVIDE( Cache_Clean_All = 0x400016ec ); +PROVIDE( Cache_WriteBack_All = 0x400016f8 ); +PROVIDE( Cache_Mask_All = 0x40001704 ); +PROVIDE( Cache_UnMask_Dram0 = 0x40001710 ); +PROVIDE( Cache_Suspend_ICache_Autoload = 0x4000171c ); +PROVIDE( Cache_Resume_ICache_Autoload = 0x40001728 ); +PROVIDE( Cache_Suspend_DCache_Autoload = 0x40001734 ); +PROVIDE( Cache_Resume_DCache_Autoload = 0x40001740 ); +PROVIDE( Cache_Start_ICache_Preload = 0x4000174c ); +PROVIDE( Cache_ICache_Preload_Done = 0x40001758 ); +PROVIDE( Cache_End_ICache_Preload = 0x40001764 ); +PROVIDE( Cache_Start_DCache_Preload = 0x40001770 ); +PROVIDE( Cache_DCache_Preload_Done = 0x4000177c ); +PROVIDE( Cache_End_DCache_Preload = 0x40001788 ); +PROVIDE( Cache_Config_ICache_Autoload = 0x40001794 ); +PROVIDE( Cache_Config_ICache_Region_Autoload = 0x400017a0 ); +PROVIDE( Cache_Enable_ICache_Autoload = 0x400017ac ); +PROVIDE( Cache_Disable_ICache_Autoload = 0x400017b8 ); +PROVIDE( Cache_Config_DCache_Autoload = 0x400017c4 ); +PROVIDE( Cache_Config_DCache_Region_Autoload = 0x400017d0 ); +PROVIDE( Cache_Enable_DCache_Autoload = 0x400017dc ); +PROVIDE( Cache_Disable_DCache_Autoload = 0x400017e8 ); +PROVIDE( Cache_Enable_ICache_PreLock = 0x400017f4 ); +PROVIDE( Cache_Disable_ICache_PreLock = 0x40001800 ); +PROVIDE( Cache_Lock_ICache_Items = 0x4000180c ); +PROVIDE( Cache_Unlock_ICache_Items = 0x40001818 ); +PROVIDE( Cache_Enable_DCache_PreLock = 0x40001824 ); +PROVIDE( Cache_Disable_DCache_PreLock = 0x40001830 ); +PROVIDE( Cache_Lock_DCache_Items = 0x4000183c ); +PROVIDE( Cache_Unlock_DCache_Items = 0x40001848 ); +PROVIDE( Cache_Lock_Addr = 0x40001854 ); +PROVIDE( Cache_Unlock_Addr = 0x40001860 ); +PROVIDE( Cache_Disable_ICache = 0x4000186c ); +PROVIDE( Cache_Enable_ICache = 0x40001878 ); +PROVIDE( Cache_Disable_DCache = 0x40001884 ); +PROVIDE( Cache_Enable_DCache = 0x40001890 ); +PROVIDE( Cache_Suspend_ICache = 0x4000189c ); +PROVIDE( Cache_Resume_ICache = 0x400018a8 ); +PROVIDE( Cache_Suspend_DCache = 0x400018b4 ); +PROVIDE( Cache_Resume_DCache = 0x400018c0 ); +PROVIDE( Cache_Occupy_Items = 0x400018cc ); +PROVIDE( Cache_Occupy_Addr = 0x400018d8 ); +PROVIDE( Cache_Freeze_ICache_Enable = 0x400018e4 ); +PROVIDE( Cache_Freeze_ICache_Disable = 0x400018f0 ); +PROVIDE( Cache_Freeze_DCache_Enable = 0x400018fc ); +PROVIDE( Cache_Freeze_DCache_Disable = 0x40001908 ); +PROVIDE( Cache_Set_IDROM_MMU_Size = 0x40001914 ); +PROVIDE( flash2spiram_instruction_offset = 0x40001920 ); +PROVIDE( flash2spiram_rodata_offset = 0x4000192c ); +PROVIDE( flash_instr_rodata_start_page = 0x40001938 ); +PROVIDE( flash_instr_rodata_end_page = 0x40001944 ); +PROVIDE( Cache_Set_IDROM_MMU_Info = 0x40001950 ); +PROVIDE( Cache_Get_IROM_MMU_End = 0x4000195c ); +PROVIDE( Cache_Get_DROM_MMU_End = 0x40001968 ); +PROVIDE( Cache_Owner_Init = 0x40001974 ); +PROVIDE( Cache_Occupy_ICache_MEMORY = 0x40001980 ); +PROVIDE( Cache_Occupy_DCache_MEMORY = 0x4000198c ); +PROVIDE( Cache_MMU_Init = 0x40001998 ); +PROVIDE( Cache_Ibus_MMU_Set = 0x400019a4 ); +PROVIDE( Cache_Dbus_MMU_Set = 0x400019b0 ); +PROVIDE( Cache_Count_Flash_Pages = 0x400019bc ); +PROVIDE( Cache_Flash_To_SPIRAM_Copy = 0x400019c8 ); +PROVIDE( Cache_Travel_Tag_Memory = 0x400019d4 ); +PROVIDE( Cache_Travel_Tag_Memory2 = 0x400019e0 ); +PROVIDE( Cache_Get_Virtual_Addr = 0x400019ec ); +PROVIDE( Cache_Get_Memory_BaseAddr = 0x400019f8 ); +PROVIDE( Cache_Get_Memory_Addr = 0x40001a04 ); +PROVIDE( Cache_Get_Memory_value = 0x40001a10 ); +PROVIDE( rom_config_instruction_cache_mode = 0x40001a1c ); +PROVIDE( rom_config_data_cache_mode = 0x40001a28 ); +/* Data (.data, .bss, .rodata) */ +PROVIDE( rom_cache_op_cb = 0x3fceffc8 ); +PROVIDE( rom_cache_internal_table_ptr = 0x3fceffc4 ); + + +/*************************************** + Group clock + ***************************************/ + +/* Functions */ +ets_get_apb_freq = 0x40001a34; +ets_get_cpu_frequency = 0x40001a40; +ets_update_cpu_frequency = 0x40001a4c; +ets_get_printf_channel = 0x40001a58; +ets_get_xtal_div = 0x40001a64; +ets_set_xtal_div = 0x40001a70; +ets_get_xtal_freq = 0x40001a7c; + + +/*************************************** + Group gpio + ***************************************/ + +/* Functions */ +gpio_input_get = 0x40001a88; +gpio_matrix_in = 0x40001a94; +gpio_matrix_out = 0x40001aa0; +gpio_output_disable = 0x40001aac; +gpio_output_enable = 0x40001ab8; +gpio_output_set = 0x40001ac4; +gpio_pad_hold = 0x40001ad0; +gpio_pad_input_disable = 0x40001adc; +gpio_pad_input_enable = 0x40001ae8; +gpio_pad_pulldown = 0x40001af4; +gpio_pad_pullup = 0x40001b00; +gpio_pad_select_gpio = 0x40001b0c; +gpio_pad_set_drv = 0x40001b18; +gpio_pad_unhold = 0x40001b24; +gpio_pin_wakeup_disable = 0x40001b30; +gpio_pin_wakeup_enable = 0x40001b3c; +gpio_bypass_matrix_in = 0x40001b48; + + +/*************************************** + Group interrupts + ***************************************/ + +/* Functions */ +intr_matrix_set = 0x40001b54; +ets_intr_lock = 0x40001b60; +ets_intr_unlock = 0x40001b6c; +ets_isr_attach = 0x40001b78; +ets_isr_mask = 0x40001b84; +ets_isr_unmask = 0x40001b90; + + +/*************************************** + Group xtos + ***************************************/ + +/* Functions */ + +memcpy = 0x400011f4; +xthal_bcopy = 0x40001b9c; +xthal_memcpy = 0x40001ba8; +xthal_get_ccompare = 0x40001bb4; +xthal_set_ccompare = 0x40001bc0; +xthal_get_ccount = 0x40001bcc; +xthal_get_interrupt = 0x40001bd8; +xthal_set_intclear = 0x40001be4; +_xtos_ints_off = 0x40001bf0; +_xtos_ints_on = 0x40001bfc; +_xtos_restore_intlevel = 0x40001c08; +_xtos_set_exception_handler = 0x40001c14; +_xtos_set_interrupt_handler = 0x40001c20; +_xtos_set_interrupt_handler_arg = 0x40001c2c; +_xtos_set_intlevel = 0x40001c38; +_xtos_set_vpri = 0x40001c44; + + +/*************************************** + Group crypto + ***************************************/ + +/* Functions */ +md5_vector = 0x40001c50; +MD5Init = 0x40001c5c; +MD5Update = 0x40001c68; +MD5Final = 0x40001c74; +hmac_md5_vector = 0x40001c80; +hmac_md5 = 0x40001c8c; +crc32_le = 0x40001c98; +crc32_be = 0x40001ca4; +crc16_le = 0x40001cb0; +crc16_be = 0x40001cbc; +crc8_le = 0x40001cc8; +crc8_be = 0x40001cd4; +esp_crc8 = 0x40001ce0; +ets_sha_enable = 0x40001cec; +ets_sha_disable = 0x40001cf8; +ets_sha_get_state = 0x40001d04; +ets_sha_init = 0x40001d10; +ets_sha_process = 0x40001d1c; +ets_sha_starts = 0x40001d28; +ets_sha_update = 0x40001d34; +ets_sha_finish = 0x40001d40; +ets_sha_clone = 0x40001d4c; +ets_hmac_enable = 0x40001d58; +ets_hmac_disable = 0x40001d64; +ets_hmac_calculate_message = 0x40001d70; +ets_hmac_calculate_downstream = 0x40001d7c; +ets_hmac_invalidate_downstream = 0x40001d88; +ets_jtag_enable_temporarily = 0x40001d94; +ets_aes_enable = 0x40001da0; +ets_aes_disable = 0x40001dac; +ets_aes_setkey = 0x40001db8; +ets_aes_block = 0x40001dc4; +ets_bigint_enable = 0x40001dd0; +ets_bigint_disable = 0x40001ddc; +ets_bigint_multiply = 0x40001de8; +ets_bigint_modmult = 0x40001df4; +ets_bigint_modexp = 0x40001e00; +ets_bigint_wait_finish = 0x40001e0c; +ets_bigint_getz = 0x40001e18; +ets_ds_enable = 0x40001e24; +ets_ds_disable = 0x40001e30; +ets_ds_start_sign = 0x40001e3c; +ets_ds_is_busy = 0x40001e48; +ets_ds_finish_sign = 0x40001e54; +ets_ds_encrypt_params = 0x40001e60; +ets_aes_setkey_dec = 0x40001e6c; +ets_aes_setkey_enc = 0x40001e78; +ets_mgf1_sha256 = 0x40001e84; + + +/*************************************** + Group efuse + ***************************************/ + +/* Functions */ +ets_efuse_read = 0x40001e90; +ets_efuse_program = 0x40001e9c; +ets_efuse_clear_program_registers = 0x40001ea8; +ets_efuse_write_key = 0x40001eb4; +ets_efuse_get_read_register_address = 0x40001ec0; +ets_efuse_get_key_purpose = 0x40001ecc; +ets_efuse_key_block_unused = 0x40001ed8; +ets_efuse_find_unused_key_block = 0x40001ee4; +ets_efuse_rs_calculate = 0x40001ef0; +ets_efuse_count_unused_key_blocks = 0x40001efc; +ets_efuse_secure_boot_enabled = 0x40001f08; +ets_efuse_secure_boot_aggressive_revoke_enabled = 0x40001f14; +ets_efuse_cache_encryption_enabled = 0x40001f20; +ets_efuse_download_modes_disabled = 0x40001f2c; +ets_efuse_find_purpose = 0x40001f38; +ets_efuse_flash_opi_5pads_power_sel_vddspi = 0x40001f44; +ets_efuse_force_send_resume = 0x40001f50; +ets_efuse_get_flash_delay_us = 0x40001f5c; +ets_efuse_get_mac = 0x40001f68; +ets_efuse_get_spiconfig = 0x40001f74; +ets_efuse_usb_print_is_disabled = 0x40001f80; +ets_efuse_get_uart_print_channel = 0x40001f8c; +ets_efuse_get_uart_print_control = 0x40001f98; +ets_efuse_get_wp_pad = 0x40001fa4; +ets_efuse_legacy_spi_boot_mode_disabled = 0x40001fb0; +ets_efuse_security_download_modes_enabled = 0x40001fbc; +ets_efuse_set_timing = 0x40001fc8; +ets_efuse_jtag_disabled = 0x40001fd4; +ets_efuse_usb_download_mode_disabled = 0x40001fe0; +ets_efuse_usb_module_disabled = 0x40001fec; +ets_efuse_usb_device_disabled = 0x40001ff8; +ets_efuse_flash_octal_mode = 0x40002004; +ets_efuse_ecc_en = 0x40002010; +ets_efuse_ecc_flash_page_size = 0x4000201c; +ets_efuse_ecc_16to17_mode = 0x40002028; + + +/*************************************** + Group ecc + ***************************************/ + +/* Functions */ +ets_ecc_flash_enable = 0x40002034; +ets_ecc_flash_enable_all = 0x40002040; +ets_ecc_flash_disable = 0x4000204c; +ets_ecc_flash_disable_all = 0x40002058; +ets_ecc_get_flash_page_size = 0x40002064; +ets_ecc_set_flash_page_size = 0x40002070; +ets_ecc_set_flash_byte_mode = 0x4000207c; +ets_ecc_get_flash_byte_mode = 0x40002088; +ets_ecc_set_flash_range = 0x40002094; +ets_ecc_get_flash_range = 0x400020a0; +ets_ecc_sram_enable = 0x400020ac; +ets_ecc_sram_disable = 0x400020b8; +ets_ecc_sram_enable_all = 0x400020c4; +ets_ecc_sram_disable_all = 0x400020d0; +ets_ecc_get_sram_page_size = 0x400020dc; +ets_ecc_set_sram_page_size = 0x400020e8; +ets_ecc_get_sram_byte_mode = 0x400020f4; +ets_ecc_set_sram_byte_mode = 0x40002100; +ets_ecc_set_sram_range = 0x4000210c; +ets_ecc_get_sram_range = 0x40002118; +/* Data (.data, .bss, .rodata) */ +ets_ecc_table_ptr = 0x3fceffc0; + + +/*************************************** + Group secureboot + ***************************************/ + +/* Functions */ +ets_emsa_pss_verify = 0x40002124; +ets_rsa_pss_verify = 0x40002130; +ets_secure_boot_verify_bootloader_with_keys = 0x4000213c; +ets_secure_boot_verify_signature = 0x40002148; +ets_secure_boot_read_key_digests = 0x40002154; +ets_secure_boot_revoke_public_key_digest = 0x40002160; + + +/*************************************** + Group usb_uart + ***************************************/ + +/* Functions */ +PROVIDE( usb_uart_otg_rx_one_char = 0x400025a4 ); +PROVIDE( usb_uart_otg_rx_one_char_block = 0x400025b0 ); +PROVIDE( usb_uart_otg_tx_flush = 0x400025bc ); +PROVIDE( usb_uart_otg_tx_one_char = 0x400025c8 ); +PROVIDE( usb_uart_device_rx_one_char = 0x400025d4 ); +PROVIDE( usb_uart_device_rx_one_char_block = 0x400025e0 ); +PROVIDE( usb_uart_device_tx_flush = 0x400025ec ); +PROVIDE( usb_uart_device_tx_one_char = 0x400025f8 ); +PROVIDE( Uart_Init_USB = 0x40002604 ); +/* Data (.data, .bss, .rodata) */ +PROVIDE( uart_acm_dev = 0x3fceffbc ); +PROVIDE( g_uart_print = 0x3fceffb9 ); +PROVIDE( g_usb_print = 0x3fceffb8 ); + + +/*************************************** + Group usb_module + ***************************************/ + +/* Functions */ +cdc_acm_class_handle_req = 0x40002610; +cdc_acm_init = 0x4000261c; +cdc_acm_fifo_fill = 0x40002628; +cdc_acm_rx_fifo_cnt = 0x40002634; +cdc_acm_fifo_read = 0x40002640; +cdc_acm_irq_tx_enable = 0x4000264c; +cdc_acm_irq_tx_disable = 0x40002658; +cdc_acm_irq_state_enable = 0x40002664; +cdc_acm_irq_state_disable = 0x40002670; +cdc_acm_irq_tx_ready = 0x4000267c; +cdc_acm_irq_rx_enable = 0x40002688; +cdc_acm_irq_rx_disable = 0x40002694; +cdc_acm_irq_rx_ready = 0x400026a0; +cdc_acm_irq_is_pending = 0x400026ac; +cdc_acm_irq_callback_set = 0x400026b8; +cdc_acm_line_ctrl_set = 0x400026c4; +cdc_acm_line_ctrl_get = 0x400026d0; +cdc_acm_poll_out = 0x400026dc; +chip_usb_dw_did_persist = 0x400026e8; +chip_usb_dw_init = 0x400026f4; +chip_usb_detach = 0x40002700; +chip_usb_dw_prepare_persist = 0x4000270c; +chip_usb_get_persist_flags = 0x40002718; +chip_usb_set_persist_flags = 0x40002724; +cpio_start = 0x40002730; +cpio_feed = 0x4000273c; +cpio_done = 0x40002748; +cpio_destroy = 0x40002754; +dfu_flash_init = 0x40002760; +dfu_flash_erase = 0x4000276c; +dfu_flash_program = 0x40002778; +dfu_flash_read = 0x40002784; +dfu_flash_attach = 0x40002790; +dfu_cpio_callback = 0x4000279c; +dfu_updater_get_err = 0x400027a8; +dfu_updater_clear_err = 0x400027b4; +dfu_updater_enable = 0x400027c0; +dfu_updater_begin = 0x400027cc; +dfu_updater_feed = 0x400027d8; +dfu_updater_end = 0x400027e4; +dfu_updater_set_raw_addr = 0x400027f0; +dfu_updater_flash_read = 0x400027fc; +usb_dc_prepare_persist = 0x40002808; +usb_dw_isr_handler = 0x40002814; +usb_dc_attach = 0x40002820; +usb_dc_detach = 0x4000282c; +usb_dc_reset = 0x40002838; +usb_dc_set_address = 0x40002844; +usb_dc_ep_check_cap = 0x40002850; +usb_dc_ep_configure = 0x4000285c; +usb_dc_ep_set_stall = 0x40002868; +usb_dc_ep_clear_stall = 0x40002874; +usb_dc_ep_halt = 0x40002880; +usb_dc_ep_is_stalled = 0x4000288c; +usb_dc_ep_enable = 0x40002898; +usb_dc_ep_disable = 0x400028a4; +usb_dc_ep_flush = 0x400028b0; +usb_dc_ep_write_would_block = 0x400028bc; +usb_dc_ep_write = 0x400028c8; +usb_dc_ep_read_wait = 0x400028d4; +usb_dc_ep_read_continue = 0x400028e0; +usb_dc_ep_read = 0x400028ec; +usb_dc_ep_set_callback = 0x400028f8; +usb_dc_set_status_callback = 0x40002904; +usb_dc_ep_mps = 0x40002910; +usb_dc_check_poll_for_interrupts = 0x4000291c; +mac_addr_to_serial_str_desc = 0x40002928; +usb_set_current_descriptor = 0x40002934; +usb_get_descriptor = 0x40002940; +usb_dev_resume = 0x4000294c; +usb_dev_get_configuration = 0x40002958; +usb_set_config = 0x40002964; +usb_deconfig = 0x40002970; +usb_enable = 0x4000297c; +usb_disable = 0x40002988; +usb_write_would_block = 0x40002994; +usb_write = 0x400029a0; +usb_read = 0x400029ac; +usb_ep_set_stall = 0x400029b8; +usb_ep_clear_stall = 0x400029c4; +usb_ep_read_wait = 0x400029d0; +usb_ep_read_continue = 0x400029dc; +usb_transfer_ep_callback = 0x400029e8; +usb_transfer = 0x400029f4; +usb_cancel_transfer = 0x40002a00; +usb_transfer_sync = 0x40002a0c; +usb_dfu_set_detach_cb = 0x40002a18; +dfu_class_handle_req = 0x40002a24; +dfu_status_cb = 0x40002a30; +dfu_custom_handle_req = 0x40002a3c; +usb_dfu_init = 0x40002a48; +usb_dfu_force_detach = 0x40002a54; +usb_dev_deinit = 0x40002a60; +usb_dw_ctrl_deinit = 0x40002a6c; +/* Data (.data, .bss, .rodata) */ +s_usb_osglue = 0x3fceffac; + + +/*************************************** + Group bluetooth + ***************************************/ + +/* Functions */ +bt_rf_coex_get_dft_cfg = 0x40002a78; +bt_rf_coex_hooks_p_set = 0x40002a84; +btdm_con_maxevtime_cal_impl = 0x40002a90; +btdm_controller_get_compile_version_impl = 0x40002a9c; +btdm_controller_rom_data_init = 0x40002aa8; +btdm_dis_privacy_err_report_impl = 0x40002ab4; +btdm_disable_adv_delay_impl = 0x40002ac0; +btdm_enable_scan_continue_impl = 0x40002acc; +btdm_enable_scan_forever_impl = 0x40002ad8; +btdm_get_power_state_impl = 0x40002ae4; +btdm_get_prevent_sleep_flag_impl = 0x40002af0; +btdm_power_state_active_impl = 0x40002afc; +btdm_switch_phy_coded_impl = 0x40002b08; +hci_acl_data_handler = 0x40002b14; +hci_disconnect_cmd_handler = 0x40002b20; +hci_le_con_upd_cmd_handler = 0x40002b2c; +hci_le_ltk_req_neg_reply_cmd_handler = 0x40002b38; +hci_le_ltk_req_reply_cmd_handler = 0x40002b44; +hci_le_rd_chnl_map_cmd_handler = 0x40002b50; +hci_le_rd_phy_cmd_handler = 0x40002b5c; +hci_le_rd_rem_feats_cmd_handler = 0x40002b68; +hci_le_rem_con_param_req_neg_reply_cmd_handler = 0x40002b74; +hci_le_rem_con_param_req_reply_cmd_handler = 0x40002b80; +hci_le_set_data_len_cmd_handler = 0x40002b8c; +hci_le_set_phy_cmd_handler = 0x40002b98; +hci_le_start_enc_cmd_handler = 0x40002ba4; +hci_rd_auth_payl_to_cmd_handler = 0x40002bb0; +hci_rd_rem_ver_info_cmd_handler = 0x40002bbc; +hci_rd_rssi_cmd_handler = 0x40002bc8; +hci_rd_tx_pwr_lvl_cmd_handler = 0x40002bd4; +hci_vs_set_pref_slave_evt_dur_cmd_handler = 0x40002be0; +hci_vs_set_pref_slave_latency_cmd_handler = 0x40002bec; +hci_wr_auth_payl_to_cmd_handler = 0x40002bf8; +ll_channel_map_ind_handler = 0x40002c04; +ll_connection_param_req_handler = 0x40002c10; +ll_connection_param_rsp_handler = 0x40002c1c; +ll_connection_update_ind_handler = 0x40002c28; +ll_enc_req_handler = 0x40002c34; +ll_enc_rsp_handler = 0x40002c40; +ll_feature_req_handler = 0x40002c4c; +ll_feature_rsp_handler = 0x40002c58; +ll_length_req_handler = 0x40002c64; +ll_length_rsp_handler = 0x40002c70; +ll_min_used_channels_ind_handler = 0x40002c7c; +ll_pause_enc_req_handler = 0x40002c88; +ll_pause_enc_rsp_handler = 0x40002c94; +ll_phy_req_handler = 0x40002ca0; +ll_phy_rsp_handler = 0x40002cac; +ll_phy_update_ind_handler = 0x40002cb8; +ll_ping_req_handler = 0x40002cc4; +ll_ping_rsp_handler = 0x40002cd0; +ll_slave_feature_req_handler = 0x40002cdc; +ll_start_enc_req_handler = 0x40002ce8; +ll_start_enc_rsp_handler = 0x40002cf4; +ll_terminate_ind_handler = 0x40002d00; +ll_version_ind_handler = 0x40002d0c; +llc_auth_payl_nearly_to_handler = 0x40002d18; +llc_auth_payl_real_to_handler = 0x40002d24; +llc_encrypt_ind_handler = 0x40002d30; +llc_hci_command_handler_wrapper = 0x40002d3c; +llc_ll_connection_param_req_pdu_send = 0x40002d48; +llc_ll_connection_param_rsp_pdu_send = 0x40002d54; +llc_ll_connection_update_ind_pdu_send = 0x40002d60; +llc_ll_enc_req_pdu_send = 0x40002d6c; +llc_ll_enc_rsp_pdu_send = 0x40002d78; +llc_ll_feature_req_pdu_send = 0x40002d84; +llc_ll_feature_rsp_pdu_send = 0x40002d90; +llc_ll_length_req_pdu_send = 0x40002d9c; +llc_ll_length_rsp_pdu_send = 0x40002da8; +llc_ll_pause_enc_req_pdu_send = 0x40002db4; +llc_ll_pause_enc_rsp_pdu_send = 0x40002dc0; +llc_ll_phy_req_pdu_send = 0x40002dcc; +llc_ll_phy_rsp_pdu_send = 0x40002dd8; +llc_ll_ping_req_pdu_send = 0x40002de4; +llc_ll_ping_rsp_pdu_send = 0x40002df0; +llc_ll_start_enc_req_pdu_send = 0x40002dfc; +llc_ll_start_enc_rsp_pdu_send = 0x40002e08; +llc_ll_terminate_ind_pdu_send = 0x40002e14; +llc_ll_unknown_rsp_pdu_send = 0x40002e20; +llc_llcp_ch_map_update_ind_pdu_send = 0x40002e2c; +llc_llcp_phy_upd_ind_pdu_send = 0x40002e38; +llc_llcp_version_ind_pdu_send = 0x40002e44; +llc_op_ch_map_upd_ind_handler = 0x40002e50; +llc_op_con_upd_ind_handler = 0x40002e5c; +llc_op_disconnect_ind_handler = 0x40002e68; +llc_op_dl_upd_ind_handler = 0x40002e74; +llc_op_encrypt_ind_handler = 0x40002e80; +llc_op_feats_exch_ind_handler = 0x40002e8c; +llc_op_le_ping_ind_handler = 0x40002e98; +llc_op_phy_upd_ind_handler = 0x40002ea4; +llc_op_ver_exch_ind_handler = 0x40002eb0; +llc_stopped_ind_handler = 0x40002ebc; +lld_acl_rx_ind_handler = 0x40002ec8; +lld_acl_tx_cfm_handler = 0x40002ed4; +lld_adv_end_ind_handler = 0x40002ee0; +lld_adv_rep_ind_handler = 0x40002eec; +lld_ch_map_upd_cfm_handler = 0x40002ef8; +lld_con_estab_ind_handler = 0x40002f04; +lld_con_evt_sd_evt_time_set = 0x40002f10; +lld_con_offset_upd_ind_handler = 0x40002f1c; +lld_con_param_upd_cfm_handler = 0x40002f28; +lld_disc_ind_handler = 0x40002f34; +lld_init_end_ind_handler = 0x40002f40; +lld_llcp_rx_ind_handler_wrapper = 0x40002f4c; +lld_llcp_tx_cfm_handler = 0x40002f58; +lld_per_adv_end_ind_handler = 0x40002f64; +lld_per_adv_rep_ind_handler = 0x40002f70; +lld_per_adv_rx_end_ind_handler = 0x40002f7c; +lld_phy_coded_500k_get = 0x40002f88; +lld_phy_upd_cfm_handler = 0x40002f94; +lld_scan_end_ind_handler = 0x40002fa0; +lld_scan_req_ind_handler = 0x40002fac; +lld_sync_start_req_handler = 0x40002fb8; +lld_test_end_ind_handler = 0x40002fc4; +lld_update_rxbuf_handler = 0x40002fd0; +llm_ch_map_update_ind_handler = 0x40002fdc; +llm_hci_command_handler_wrapper = 0x40002fe8; +llm_scan_period_to_handler = 0x40002ff4; +r_Add2SelfBigHex256 = 0x40003000; +r_AddBigHex256 = 0x4000300c; +r_AddBigHexModP256 = 0x40003018; +r_AddP256 = 0x40003024; +r_AddPdiv2_256 = 0x40003030; +r_GF_Jacobian_Point_Addition256 = 0x4000303c; +r_GF_Jacobian_Point_Double256 = 0x40003048; +r_GF_Point_Jacobian_To_Affine256 = 0x40003054; +r_MultiplyBigHexByUint32_256 = 0x40003060; +r_MultiplyBigHexModP256 = 0x4000306c; +r_MultiplyByU16ModP256 = 0x40003078; +r_SubtractBigHex256 = 0x40003084; +r_SubtractBigHexMod256 = 0x40003090; +r_SubtractBigHexUint32_256 = 0x4000309c; +r_SubtractFromSelfBigHex256 = 0x400030a8; +r_SubtractFromSelfBigHexSign256 = 0x400030b4; +r_aes_alloc = 0x400030c0; +r_aes_ccm_continue = 0x400030cc; +r_aes_ccm_process_e = 0x400030d8; +r_aes_ccm_xor_128_lsb = 0x400030e4; +r_aes_ccm_xor_128_msb = 0x400030f0; +r_aes_cmac_continue = 0x400030fc; +r_aes_cmac_start = 0x40003108; +r_aes_k1_continue = 0x40003114; +r_aes_k2_continue = 0x40003120; +r_aes_k3_continue = 0x4000312c; +r_aes_k4_continue = 0x40003138; +r_aes_shift_left_128 = 0x40003144; +r_aes_start = 0x40003150; +r_aes_xor_128 = 0x4000315c; +r_assert_err = 0x40003168; +r_assert_param = 0x40003174; +r_assert_warn = 0x40003180; +r_bigHexInversion256 = 0x4000318c; +r_ble_sw_cca_check_isr = 0x40003198; +r_ble_util_buf_acl_tx_alloc = 0x400031a4; +r_ble_util_buf_acl_tx_elt_get = 0x400031b0; +r_ble_util_buf_acl_tx_free = 0x400031bc; +r_ble_util_buf_acl_tx_free_in_isr = 0x400031c8; +r_ble_util_buf_adv_tx_alloc = 0x400031d4; +r_ble_util_buf_adv_tx_free = 0x400031e0; +r_ble_util_buf_adv_tx_free_in_isr = 0x400031ec; +r_ble_util_buf_env_deinit = 0x400031f8; +r_ble_util_buf_env_init = 0x40003204; +r_ble_util_buf_get_rx_buf_nb = 0x40003210; +r_ble_util_buf_get_rx_buf_size = 0x4000321c; +r_ble_util_buf_llcp_tx_alloc = 0x40003228; +r_ble_util_buf_llcp_tx_free = 0x40003234; +r_ble_util_buf_rx_alloc = 0x40003240; +r_ble_util_buf_rx_alloc_in_isr = 0x4000324c; +r_ble_util_buf_rx_free = 0x40003258; +r_ble_util_buf_rx_free_in_isr = 0x40003264; +r_ble_util_buf_set_rx_buf_nb = 0x40003270; +r_ble_util_buf_set_rx_buf_size = 0x4000327c; +r_ble_util_data_rx_buf_reset = 0x40003288; +r_bt_bb_get_intr_mask = 0x40003294; +r_bt_bb_intr_clear = 0x400032a0; +r_bt_bb_intr_mask_set = 0x400032ac; +r_bt_bb_isr = 0x400032b8; +r_bt_rf_coex_cfg_set = 0x400032c4; +r_bt_rf_coex_conn_dynamic_pti_en_get = 0x400032d0; +r_bt_rf_coex_conn_phy_coded_data_time_limit_en_get = 0x400032dc; +r_bt_rf_coex_ext_adv_dynamic_pti_en_get = 0x400032e8; +r_bt_rf_coex_ext_scan_dynamic_pti_en_get = 0x400032f4; +r_bt_rf_coex_legacy_adv_dynamic_pti_en_get = 0x40003300; +r_bt_rf_coex_per_adv_dynamic_pti_en_get = 0x4000330c; +r_bt_rf_coex_pti_table_get = 0x40003318; +r_bt_rf_coex_st_param_get = 0x40003324; +r_bt_rf_coex_st_param_set = 0x40003330; +r_bt_rf_coex_sync_scan_dynamic_pti_en_get = 0x4000333c; +r_bt_rma_apply_rule_cs_fmt = 0x40003348; +r_bt_rma_apply_rule_cs_idx = 0x40003354; +r_bt_rma_configure = 0x40003360; +r_bt_rma_deregister_rule_cs_fmt = 0x4000336c; +r_bt_rma_deregister_rule_cs_idx = 0x40003378; +r_bt_rma_get_ant_by_act = 0x40003384; +r_bt_rma_init = 0x40003390; +r_bt_rma_register_rule_cs_fmt = 0x4000339c; +r_bt_rma_register_rule_cs_idx = 0x400033a8; +r_bt_rtp_apply_rule_cs_fmt = 0x400033b4; +r_bt_rtp_apply_rule_cs_idx = 0x400033c0; +r_bt_rtp_deregister_rule_cs_fmt = 0x400033cc; +r_bt_rtp_deregister_rule_cs_idx = 0x400033d8; +r_bt_rtp_get_txpwr_idx_by_act = 0x400033e4; +r_bt_rtp_init = 0x400033f0; +r_bt_rtp_register_rule_cs_fmt = 0x400033fc; +r_bt_rtp_register_rule_cs_idx = 0x40003408; +r_btdm_isr = 0x40003414; +r_btdm_task_post = 0x40003420; +r_btdm_task_post_from_isr = 0x4000342c; +r_btdm_task_recycle = 0x40003438; +r_cali_phase_match_p = 0x40003444; +r_cmp_abs_time = 0x40003450; +r_cmp_dest_id = 0x4000345c; +r_cmp_timer_id = 0x40003468; +r_co_bdaddr_compare = 0x40003474; +r_co_ble_pkt_dur_in_us = 0x40003480; +r_co_list_extract = 0x4000348c; +r_co_list_extract_after = 0x40003498; +r_co_list_extract_sublist = 0x400034a4; +r_co_list_find = 0x400034b0; +r_co_list_init = 0x400034bc; +r_co_list_insert_after = 0x400034c8; +r_co_list_insert_before = 0x400034d4; +r_co_list_merge = 0x400034e0; +r_co_list_pool_init = 0x400034ec; +r_co_list_pop_front = 0x400034f8; +r_co_list_push_back = 0x40003504; +r_co_list_push_back_sublist = 0x40003510; +r_co_list_push_front = 0x4000351c; +r_co_list_size = 0x40003528; +r_co_nb_good_le_channels = 0x40003534; +r_co_util_pack = 0x40003540; +r_co_util_read_array_size = 0x4000354c; +r_co_util_unpack = 0x40003558; +r_dbg_env_deinit = 0x40003564; +r_dbg_env_init = 0x40003570; +r_dbg_platform_reset_complete = 0x4000357c; +r_dl_upd_proc_start = 0x40003588; +r_dump_data = 0x40003594; +r_ecc_abort_key256_generation = 0x400035a0; +r_ecc_gen_new_public_key = 0x400035ac; +r_ecc_gen_new_secret_key = 0x400035b8; +r_ecc_generate_key256 = 0x400035c4; +r_ecc_get_debug_Keys = 0x400035d0; +r_ecc_init = 0x400035dc; +r_ecc_is_valid_point = 0x400035e8; +r_ecc_multiplication_event_handler = 0x400035f4; +r_ecc_point_multiplication_win_256 = 0x40003600; +r_emi_alloc_em_mapping_by_offset = 0x4000360c; +r_emi_base_reg_lut_show = 0x40003618; +r_emi_em_base_reg_show = 0x40003624; +r_emi_free_em_mapping_by_offset = 0x40003630; +r_emi_get_em_mapping_idx_by_offset = 0x4000363c; +r_emi_get_mem_addr_by_offset = 0x40003648; +r_emi_overwrite_em_mapping_by_offset = 0x40003654; +r_esp_vendor_hci_command_handler = 0x40003660; +r_get_stack_usage = 0x4000366c; +r_h4tl_acl_hdr_rx_evt_handler = 0x40003678; +r_h4tl_cmd_hdr_rx_evt_handler = 0x40003684; +r_h4tl_cmd_pld_rx_evt_handler = 0x40003690; +r_h4tl_eif_io_event_post = 0x4000369c; +r_h4tl_eif_register = 0x400036a8; +r_h4tl_init = 0x400036b4; +r_h4tl_out_of_sync = 0x400036c0; +r_h4tl_out_of_sync_check = 0x400036cc; +r_h4tl_read_hdr = 0x400036d8; +r_h4tl_read_next_out_of_sync = 0x400036e4; +r_h4tl_read_payl = 0x400036f0; +r_h4tl_read_start = 0x400036fc; +r_h4tl_rx_acl_hdr_extract = 0x40003708; +r_h4tl_rx_cmd_hdr_extract = 0x40003714; +r_h4tl_rx_done = 0x40003720; +r_h4tl_start = 0x4000372c; +r_h4tl_stop = 0x40003738; +r_h4tl_tx_done = 0x40003744; +r_h4tl_tx_evt_handler = 0x40003750; +r_h4tl_write = 0x4000375c; +r_hci_acl_tx_data_alloc = 0x40003768; +r_hci_acl_tx_data_received = 0x40003774; +r_hci_basic_cmd_send_2_controller = 0x40003780; +r_hci_ble_adv_report_filter_check = 0x4000378c; +r_hci_ble_adv_report_tx_check = 0x40003798; +r_hci_ble_conhdl_register = 0x400037a4; +r_hci_ble_conhdl_unregister = 0x400037b0; +r_hci_build_acl_data = 0x400037bc; +r_hci_build_cc_evt = 0x400037c8; +r_hci_build_cs_evt = 0x400037d4; +r_hci_build_evt = 0x400037e0; +r_hci_build_le_evt = 0x400037ec; +r_hci_cmd_get_max_param_size = 0x400037f8; +r_hci_cmd_received = 0x40003804; +r_hci_cmd_reject = 0x40003810; +r_hci_evt_mask_check = 0x4000381c; +r_hci_evt_mask_set = 0x40003828; +r_hci_fc_acl_buf_size_set = 0x40003834; +r_hci_fc_acl_en = 0x40003840; +r_hci_fc_acl_packet_sent = 0x4000384c; +r_hci_fc_check_host_available_nb_acl_packets = 0x40003858; +r_hci_fc_host_nb_acl_pkts_complete = 0x40003864; +r_hci_fc_init = 0x40003870; +r_hci_look_for_cmd_desc = 0x4000387c; +r_hci_look_for_evt_desc = 0x40003888; +r_hci_look_for_le_evt_desc = 0x40003894; +r_hci_look_for_le_evt_desc_esp = 0x400038a0; +r_hci_pack_bytes = 0x400038ac; +r_hci_register_vendor_desc_tab = 0x400038b8; +r_hci_send_2_controller = 0x400038c4; +r_hci_send_2_host = 0x400038d0; +r_hci_tl_c2h_data_flow_on = 0x400038dc; +r_hci_tl_cmd_hdr_rx_evt_handler = 0x400038e8; +r_hci_tl_cmd_pld_rx_evt_handler = 0x400038f4; +r_hci_tl_get_pkt = 0x40003900; +r_hci_tl_hci_pkt_handler = 0x4000390c; +r_hci_tl_hci_tx_done_evt_handler = 0x40003918; +r_hci_tl_inc_nb_h2c_cmd_pkts = 0x40003924; +r_hci_tl_save_pkt = 0x40003930; +r_hci_tl_send = 0x4000393c; +r_hci_tx_done = 0x40003948; +r_hci_tx_start = 0x40003954; +r_hci_tx_trigger = 0x40003960; +r_isValidSecretKey_256 = 0x4000396c; +r_ke_check_malloc = 0x40003978; +r_ke_event_callback_set = 0x40003984; +r_ke_event_clear = 0x40003990; +r_ke_event_flush = 0x4000399c; +r_ke_event_get = 0x400039a8; +r_ke_event_get_all = 0x400039b4; +r_ke_event_init = 0x400039c0; +r_ke_event_schedule = 0x400039cc; +r_ke_event_set = 0x400039d8; +r_ke_flush = 0x400039e4; +r_ke_free = 0x400039f0; +r_ke_handler_search = 0x400039fc; +r_ke_init = 0x40003a08; +r_ke_is_free = 0x40003a14; +r_ke_malloc = 0x40003a20; +r_ke_mem_init = 0x40003a2c; +r_ke_mem_is_empty = 0x40003a38; +r_ke_mem_is_in_heap = 0x40003a44; +r_ke_msg_alloc = 0x40003a50; +r_ke_msg_dest_id_get = 0x40003a5c; +r_ke_msg_discard = 0x40003a68; +r_ke_msg_forward = 0x40003a74; +r_ke_msg_forward_new_id = 0x40003a80; +r_ke_msg_free = 0x40003a8c; +r_ke_msg_in_queue = 0x40003a98; +r_ke_msg_save = 0x40003aa4; +r_ke_msg_send = 0x40003ab0; +r_ke_msg_send_basic = 0x40003abc; +r_ke_msg_src_id_get = 0x40003ac8; +r_ke_queue_extract = 0x40003ad4; +r_ke_queue_insert = 0x40003ae0; +r_ke_sleep_check = 0x40003aec; +r_ke_state_get = 0x40003af8; +r_ke_state_set = 0x40003b04; +r_ke_task_check = 0x40003b10; +r_ke_task_create = 0x40003b1c; +r_ke_task_delete = 0x40003b28; +r_ke_task_handler_get = 0x40003b34; +r_ke_task_init = 0x40003b40; +r_ke_task_msg_flush = 0x40003b4c; +r_ke_task_saved_update = 0x40003b58; +r_ke_task_schedule = 0x40003b64; +r_ke_time = 0x40003b70; +r_ke_time_cmp = 0x40003b7c; +r_ke_time_past = 0x40003b88; +r_ke_timer_active = 0x40003b94; +r_ke_timer_adjust_all = 0x40003ba0; +r_ke_timer_clear = 0x40003bac; +r_ke_timer_init = 0x40003bb8; +r_ke_timer_schedule = 0x40003bc4; +r_ke_timer_set = 0x40003bd0; +r_led_init = 0x40003bdc; +r_led_set_all = 0x40003be8; +r_llc_aes_res_cb = 0x40003bf4; +r_llc_ch_map_up_proc_err_cb = 0x40003c00; +r_llc_cleanup = 0x40003c0c; +r_llc_cmd_cmp_send = 0x40003c18; +r_llc_cmd_stat_send = 0x40003c24; +r_llc_con_move_cbk = 0x40003c30; +r_llc_con_plan_set_update = 0x40003c3c; +r_llc_con_upd_param_in_range = 0x40003c48; +r_llc_disconnect = 0x40003c54; +r_llc_disconnect_end = 0x40003c60; +r_llc_disconnect_proc_continue = 0x40003c6c; +r_llc_disconnect_proc_err_cb = 0x40003c78; +r_llc_dl_chg_check = 0x40003c84; +r_llc_dle_proc_err_cb = 0x40003c90; +r_llc_feats_exch_proc_err_cb = 0x40003c9c; +r_llc_hci_cmd_handler_tab_p_get = 0x40003ca8; +r_llc_hci_command_handler = 0x40003cb4; +r_llc_hci_con_param_req_evt_send = 0x40003cc0; +r_llc_hci_con_upd_info_send = 0x40003ccc; +r_llc_hci_disconnected_dis = 0x40003cd8; +r_llc_hci_dl_upd_info_send = 0x40003ce4; +r_llc_hci_enc_evt_send = 0x40003cf0; +r_llc_hci_feats_info_send = 0x40003cfc; +r_llc_hci_le_phy_upd_cmp_evt_send = 0x40003d08; +r_llc_hci_ltk_request_evt_send = 0x40003d14; +r_llc_hci_nb_cmp_pkts_evt_send = 0x40003d20; +r_llc_hci_version_info_send = 0x40003d2c; +r_llc_init_term_proc = 0x40003d38; +r_llc_iv_skd_rand_gen = 0x40003d44; +r_llc_le_ping_proc_continue = 0x40003d50; +r_llc_le_ping_proc_err_cb = 0x40003d5c; +r_llc_le_ping_restart = 0x40003d68; +r_llc_le_ping_set = 0x40003d74; +r_llc_ll_pause_enc_rsp_ack_handler = 0x40003d80; +r_llc_ll_reject_ind_ack_handler = 0x40003d8c; +r_llc_ll_reject_ind_pdu_send = 0x40003d98; +r_llc_ll_start_enc_rsp_ack_handler = 0x40003da4; +r_llc_ll_terminate_ind_ack = 0x40003db0; +r_llc_ll_unknown_ind_handler = 0x40003dbc; +r_llc_llcp_send = 0x40003dc8; +r_llc_llcp_state_set = 0x40003dd4; +r_llc_llcp_trans_timer_set = 0x40003de0; +r_llc_llcp_tx_check = 0x40003dec; +r_llc_loc_ch_map_proc_continue = 0x40003df8; +r_llc_loc_con_upd_proc_continue = 0x40003e04; +r_llc_loc_con_upd_proc_err_cb = 0x40003e10; +r_llc_loc_dl_upd_proc_continue = 0x40003e1c; +r_llc_loc_encrypt_proc_continue = 0x40003e28; +r_llc_loc_encrypt_proc_err_cb = 0x40003e34; +r_llc_loc_feats_exch_proc_continue = 0x40003e40; +r_llc_loc_phy_upd_proc_continue = 0x40003e4c; +r_llc_loc_phy_upd_proc_err_cb = 0x40003e58; +r_llc_msg_handler_tab_p_get = 0x40003e64; +r_llc_pref_param_compute = 0x40003e70; +r_llc_proc_collision_check = 0x40003e7c; +r_llc_proc_err_ind = 0x40003e88; +r_llc_proc_get = 0x40003e94; +r_llc_proc_id_get = 0x40003ea0; +r_llc_proc_reg = 0x40003eac; +r_llc_proc_state_get = 0x40003eb8; +r_llc_proc_state_set = 0x40003ec4; +r_llc_proc_timer_pause_set = 0x40003ed0; +r_llc_proc_timer_set = 0x40003edc; +r_llc_proc_unreg = 0x40003ee8; +r_llc_rem_ch_map_proc_continue = 0x40003ef4; +r_llc_rem_con_upd_proc_continue = 0x40003f00; +r_llc_rem_con_upd_proc_err_cb = 0x40003f0c; +r_llc_rem_dl_upd_proc = 0x40003f18; +r_llc_rem_encrypt_proc_continue = 0x40003f24; +r_llc_rem_encrypt_proc_err_cb = 0x40003f30; +r_llc_rem_phy_upd_proc_continue = 0x40003f3c; +r_llc_rem_phy_upd_proc_err_cb = 0x40003f48; +r_llc_role_get = 0x40003f54; +r_llc_sk_gen = 0x40003f60; +r_llc_start = 0x40003f6c; +r_llc_stop = 0x40003f78; +r_llc_ver_exch_loc_proc_continue = 0x40003f84; +r_llc_ver_proc_err_cb = 0x40003f90; +r_llcp_pdu_handler_tab_p_get = 0x40003f9c; +r_lld_aa_gen = 0x40003fa8; +r_lld_adv_adv_data_set = 0x40003fb4; +r_lld_adv_adv_data_update = 0x40003fc0; +r_lld_adv_aux_ch_idx_set = 0x40003fcc; +r_lld_adv_aux_evt_canceled_cbk = 0x40003fd8; +r_lld_adv_aux_evt_start_cbk = 0x40003fe4; +r_lld_adv_coex_check_ext_adv_synced = 0x40003ff0; +r_lld_adv_coex_env_reset = 0x40003ffc; +r_lld_adv_duration_update = 0x40004008; +r_lld_adv_dynamic_pti_process = 0x40004014; +r_lld_adv_end = 0x40004020; +r_lld_adv_evt_canceled_cbk = 0x4000402c; +r_lld_adv_evt_start_cbk = 0x40004038; +r_lld_adv_ext_chain_construct = 0x40004044; +r_lld_adv_ext_pkt_prepare = 0x40004050; +r_lld_adv_frm_cbk = 0x4000405c; +r_lld_adv_frm_isr = 0x40004068; +r_lld_adv_frm_skip_isr = 0x40004074; +r_lld_adv_init = 0x40004080; +r_lld_adv_pkt_rx = 0x4000408c; +r_lld_adv_pkt_rx_connect_ind = 0x40004098; +r_lld_adv_pkt_rx_send_scan_req_evt = 0x400040a4; +r_lld_adv_rand_addr_update = 0x400040b0; +r_lld_adv_restart = 0x400040bc; +r_lld_adv_scan_rsp_data_set = 0x400040c8; +r_lld_adv_scan_rsp_data_update = 0x400040d4; +r_lld_adv_set_tx_power = 0x400040e0; +r_lld_adv_start = 0x400040ec; +r_lld_adv_stop = 0x400040f8; +r_lld_adv_sync_info_set = 0x40004104; +r_lld_adv_sync_info_update = 0x40004110; +r_lld_calc_aux_rx = 0x4000411c; +r_lld_cca_alloc = 0x40004128; +r_lld_cca_data_reset = 0x40004134; +r_lld_cca_free = 0x40004140; +r_lld_ch_assess_data_get = 0x4000414c; +r_lld_ch_idx_get = 0x40004158; +r_lld_ch_map_set = 0x40004164; +r_lld_channel_assess = 0x40004170; +r_lld_con_activity_act_offset_compute = 0x4000417c; +r_lld_con_activity_offset_compute = 0x40004188; +r_lld_con_ch_map_update = 0x40004194; +r_lld_con_cleanup = 0x400041a0; +r_lld_con_current_tx_power_get = 0x400041ac; +r_lld_con_data_flow_set = 0x400041b8; +r_lld_con_data_len_update = 0x400041c4; +r_lld_con_data_tx = 0x400041d0; +r_lld_con_enc_key_load = 0x400041dc; +r_lld_con_event_counter_get = 0x400041e8; +r_lld_con_evt_canceled_cbk = 0x400041f4; +r_lld_con_evt_duration_min_get = 0x40004200; +r_lld_con_evt_max_eff_time_cal = 0x4000420c; +r_lld_con_evt_sd_evt_time_get = 0x40004218; +r_lld_con_evt_start_cbk = 0x40004224; +r_lld_con_evt_time_update = 0x40004230; +r_lld_con_free_all_tx_buf = 0x4000423c; +r_lld_con_frm_cbk = 0x40004248; +r_lld_con_frm_isr = 0x40004254; +r_lld_con_frm_skip_isr = 0x40004260; +r_lld_con_init = 0x4000426c; +r_lld_con_llcp_tx = 0x40004278; +r_lld_con_max_lat_calc = 0x40004284; +r_lld_con_offset_get = 0x40004290; +r_lld_con_param_update = 0x4000429c; +r_lld_con_phys_update = 0x400042a8; +r_lld_con_pref_slave_evt_dur_set = 0x400042b4; +r_lld_con_pref_slave_latency_set = 0x400042c0; +r_lld_con_rssi_get = 0x400042cc; +r_lld_con_rx = 0x400042d8; +r_lld_con_rx_channel_assess = 0x400042e4; +r_lld_con_rx_enc = 0x400042f0; +r_lld_con_rx_isr = 0x400042fc; +r_lld_con_rx_link_info_check = 0x40004308; +r_lld_con_rx_llcp_check = 0x40004314; +r_lld_con_rx_sync_time_update = 0x40004320; +r_lld_con_sched = 0x4000432c; +r_lld_con_set_tx_power = 0x40004338; +r_lld_con_start = 0x40004344; +r_lld_con_stop = 0x40004350; +r_lld_con_tx = 0x4000435c; +r_lld_con_tx_enc = 0x40004368; +r_lld_con_tx_isr = 0x40004374; +r_lld_con_tx_len_update = 0x40004380; +r_lld_con_tx_len_update_for_intv = 0x4000438c; +r_lld_con_tx_len_update_for_rate = 0x40004398; +r_lld_con_tx_prog = 0x400043a4; +r_lld_conn_dynamic_pti_process = 0x400043b0; +r_lld_continue_scan_rx_isr_end_process = 0x400043bc; +r_lld_ext_scan_dynamic_pti_process = 0x400043c8; +r_lld_hw_cca_end_isr = 0x400043d4; +r_lld_hw_cca_evt_handler = 0x400043e0; +r_lld_hw_cca_isr = 0x400043ec; +r_lld_init_cal_anchor_point = 0x400043f8; +r_lld_init_compute_winoffset = 0x40004404; +r_lld_init_connect_req_pack = 0x40004410; +r_lld_init_end = 0x4000441c; +r_lld_init_evt_canceled_cbk = 0x40004428; +r_lld_init_evt_start_cbk = 0x40004434; +r_lld_init_frm_cbk = 0x40004440; +r_lld_init_frm_eof_isr = 0x4000444c; +r_lld_init_frm_skip_isr = 0x40004458; +r_lld_init_init = 0x40004464; +r_lld_init_process_pkt_rx = 0x40004470; +r_lld_init_process_pkt_rx_adv_ext_ind = 0x4000447c; +r_lld_init_process_pkt_rx_adv_ind_or_direct_ind = 0x40004488; +r_lld_init_process_pkt_rx_aux_connect_rsp = 0x40004494; +r_lld_init_process_pkt_tx = 0x400044a0; +r_lld_init_process_pkt_tx_cal_con_timestamp = 0x400044ac; +r_lld_init_sched = 0x400044b8; +r_lld_init_set_tx_power = 0x400044c4; +r_lld_init_start = 0x400044d0; +r_lld_init_stop = 0x400044dc; +r_lld_instant_proc_end = 0x400044e8; +r_lld_llcp_rx_ind_handler = 0x400044f4; +r_lld_per_adv_ch_map_update = 0x40004500; +r_lld_per_adv_chain_construct = 0x4000450c; +r_lld_per_adv_cleanup = 0x40004518; +r_lld_per_adv_coex_env_reset = 0x40004524; +r_lld_per_adv_data_set = 0x40004530; +r_lld_per_adv_data_update = 0x4000453c; +r_lld_per_adv_dynamic_pti_process = 0x40004548; +r_lld_per_adv_evt_canceled_cbk = 0x40004554; +r_lld_per_adv_evt_start_cbk = 0x40004560; +r_lld_per_adv_ext_pkt_prepare = 0x4000456c; +r_lld_per_adv_frm_cbk = 0x40004578; +r_lld_per_adv_frm_isr = 0x40004584; +r_lld_per_adv_frm_skip_isr = 0x40004590; +r_lld_per_adv_init = 0x4000459c; +r_lld_per_adv_init_info_get = 0x400045a8; +r_lld_per_adv_list_add = 0x400045b4; +r_lld_per_adv_list_rem = 0x400045c0; +r_lld_per_adv_sched = 0x400045cc; +r_lld_per_adv_set_tx_power = 0x400045d8; +r_lld_per_adv_start = 0x400045e4; +r_lld_per_adv_stop = 0x400045f0; +r_lld_per_adv_sync_info_get = 0x400045fc; +r_lld_process_cca_data = 0x40004608; +r_lld_ral_search = 0x40004614; +r_lld_read_clock = 0x40004620; +r_lld_res_list_add = 0x4000462c; +r_lld_res_list_clear = 0x40004638; +r_lld_res_list_is_empty = 0x40004644; +r_lld_res_list_local_rpa_get = 0x40004650; +r_lld_res_list_peer_rpa_get = 0x4000465c; +r_lld_res_list_peer_update = 0x40004668; +r_lld_res_list_priv_mode_update = 0x40004674; +r_lld_res_list_rem = 0x40004680; +r_lld_reset_reg = 0x4000468c; +r_lld_rpa_renew = 0x40004698; +r_lld_rpa_renew_evt_canceled_cbk = 0x400046a4; +r_lld_rpa_renew_evt_start_cbk = 0x400046b0; +r_lld_rpa_renew_instant_cbk = 0x400046bc; +r_lld_rxdesc_check = 0x400046c8; +r_lld_rxdesc_free = 0x400046d4; +r_lld_scan_create_sync = 0x400046e0; +r_lld_scan_create_sync_cancel = 0x400046ec; +r_lld_scan_end = 0x400046f8; +r_lld_scan_evt_canceled_cbk = 0x40004704; +r_lld_scan_evt_start_cbk = 0x40004710; +r_lld_scan_frm_cbk = 0x4000471c; +r_lld_scan_frm_eof_isr = 0x40004728; +r_lld_scan_frm_rx_isr = 0x40004734; +r_lld_scan_frm_skip_isr = 0x40004740; +r_lld_scan_init = 0x4000474c; +r_lld_scan_params_update = 0x40004758; +r_lld_scan_process_pkt_rx = 0x40004764; +r_lld_scan_process_pkt_rx_adv_rep = 0x40004770; +r_lld_scan_process_pkt_rx_aux_adv_ind = 0x4000477c; +r_lld_scan_process_pkt_rx_aux_chain_ind = 0x40004788; +r_lld_scan_process_pkt_rx_aux_scan_rsp = 0x40004794; +r_lld_scan_process_pkt_rx_ext_adv = 0x400047a0; +r_lld_scan_process_pkt_rx_ext_adv_ind = 0x400047ac; +r_lld_scan_process_pkt_rx_legacy_adv = 0x400047b8; +r_lld_scan_restart = 0x400047c4; +r_lld_scan_sched = 0x400047d0; +r_lld_scan_set_tx_power = 0x400047dc; +r_lld_scan_start = 0x400047e8; +r_lld_scan_stop = 0x400047f4; +r_lld_scan_sync_accept = 0x40004800; +r_lld_scan_sync_info_unpack = 0x4000480c; +r_lld_scan_trunc_ind = 0x40004818; +r_lld_sw_cca_evt_handler = 0x40004824; +r_lld_sw_cca_isr = 0x40004830; +r_lld_sync_ch_map_update = 0x4000483c; +r_lld_sync_cleanup = 0x40004848; +r_lld_sync_evt_canceled_cbk = 0x40004854; +r_lld_sync_evt_start_cbk = 0x40004860; +r_lld_sync_frm_cbk = 0x4000486c; +r_lld_sync_frm_eof_isr = 0x40004878; +r_lld_sync_frm_rx_isr = 0x40004884; +r_lld_sync_frm_skip_isr = 0x40004890; +r_lld_sync_init = 0x4000489c; +r_lld_sync_process_pkt_rx = 0x400048a8; +r_lld_sync_process_pkt_rx_aux_sync_ind = 0x400048b4; +r_lld_sync_process_pkt_rx_pkt_check = 0x400048c0; +r_lld_sync_scan_dynamic_pti_process = 0x400048cc; +r_lld_sync_sched = 0x400048d8; +r_lld_sync_start = 0x400048e4; +r_lld_sync_stop = 0x400048f0; +r_lld_sync_trunc_ind = 0x400048fc; +r_lld_test_cleanup = 0x40004908; +r_lld_test_evt_canceled_cbk = 0x40004914; +r_lld_test_evt_start_cbk = 0x40004920; +r_lld_test_freq2chnl = 0x4000492c; +r_lld_test_frm_cbk = 0x40004938; +r_lld_test_frm_isr = 0x40004944; +r_lld_test_init = 0x40004950; +r_lld_test_rx_isr = 0x4000495c; +r_lld_test_set_tx_power = 0x40004968; +r_lld_test_start = 0x40004974; +r_lld_test_stop = 0x40004980; +r_lld_update_rxbuf = 0x4000498c; +r_lld_update_rxbuf_isr = 0x40004998; +r_lld_white_list_add = 0x400049a4; +r_lld_white_list_rem = 0x400049b0; +r_llm_activity_free_get = 0x400049bc; +r_llm_activity_free_set = 0x400049c8; +r_llm_activity_syncing_get = 0x400049d4; +r_llm_adv_con_len_check = 0x400049e0; +r_llm_adv_hdl_to_id = 0x400049ec; +r_llm_adv_rep_flow_control_check = 0x400049f8; +r_llm_adv_rep_flow_control_update = 0x40004a04; +r_llm_adv_reports_list_check = 0x40004a10; +r_llm_adv_set_all_release = 0x40004a1c; +r_llm_adv_set_dft_params = 0x40004a28; +r_llm_adv_set_release = 0x40004a34; +r_llm_aes_res_cb = 0x40004a40; +r_llm_ble_update_adv_flow_control = 0x40004a4c; +r_llm_ch_map_update = 0x40004a58; +r_llm_cmd_cmp_send = 0x40004a64; +r_llm_cmd_stat_send = 0x40004a70; +r_llm_dev_list_empty_entry = 0x40004a7c; +r_llm_dev_list_search = 0x40004a88; +r_llm_env_adv_dup_filt_deinit = 0x40004a94; +r_llm_env_adv_dup_filt_init = 0x40004aa0; +r_llm_init_ble_adv_report_flow_contol = 0x40004aac; +r_llm_is_dev_connected = 0x40004ab8; +r_llm_is_dev_synced = 0x40004ac4; +r_llm_is_non_con_act_ongoing_check = 0x40004ad0; +r_llm_is_wl_accessible = 0x40004adc; +r_llm_le_evt_mask_check = 0x40004ae8; +r_llm_le_features_get = 0x40004af4; +r_llm_link_disc = 0x40004b00; +r_llm_master_ch_map_get = 0x40004b0c; +r_llm_msg_handler_tab_p_get = 0x40004b18; +r_llm_no_activity = 0x40004b24; +r_llm_per_adv_slot_dur = 0x40004b30; +r_llm_plan_elt_get = 0x40004b3c; +r_llm_rx_path_comp_get = 0x40004b48; +r_llm_scan_start = 0x40004b54; +r_llm_scan_sync_acad_attach = 0x40004b60; +r_llm_scan_sync_acad_detach = 0x40004b6c; +r_llm_send_adv_lost_event_to_host = 0x40004b78; +r_llm_tx_path_comp_get = 0x40004b84; +r_misc_deinit = 0x40004b90; +r_misc_free_em_buf_in_isr = 0x40004b9c; +r_misc_init = 0x40004ba8; +r_misc_msg_handler_tab_p_get = 0x40004bb4; +r_notEqual256 = 0x40004bc0; +r_phy_upd_proc_start = 0x40004bcc; +r_platform_reset = 0x40004bd8; +r_register_esp_vendor_cmd_handler = 0x40004be4; +r_rf_em_init = 0x40004bf0; +r_rf_force_agc_enable = 0x40004bfc; +r_rf_reg_rd = 0x40004c08; +r_rf_reg_wr = 0x40004c14; +r_rf_reset = 0x40004c20; +r_rf_rssi_convert = 0x40004c2c; +r_rf_rw_v9_le_disable = 0x40004c38; +r_rf_rw_v9_le_enable = 0x40004c44; +r_rf_sleep = 0x40004c50; +r_rf_txpwr_cs_get = 0x40004c5c; +r_rf_txpwr_dbm_get = 0x40004c68; +r_rf_util_cs_fmt_convert = 0x40004c74; +r_rw_crypto_aes_ccm = 0x40004c80; +r_rw_crypto_aes_encrypt = 0x40004c8c; +r_rw_crypto_aes_init = 0x40004c98; +r_rw_crypto_aes_k1 = 0x40004ca4; +r_rw_crypto_aes_k2 = 0x40004cb0; +r_rw_crypto_aes_k3 = 0x40004cbc; +r_rw_crypto_aes_k4 = 0x40004cc8; +r_rw_crypto_aes_rand = 0x40004cd4; +r_rw_crypto_aes_result_handler = 0x40004ce0; +r_rw_crypto_aes_s1 = 0x40004cec; +r_rw_cryto_aes_cmac = 0x40004cf8; +r_rw_v9_init_em_radio_table = 0x40004d04; +r_rwble_isr = 0x40004d10; +r_rwble_sleep_enter = 0x40004d1c; +r_rwble_sleep_wakeup_end = 0x40004d28; +r_rwbtdm_isr_wrapper = 0x40004d34; +r_rwip_active_check = 0x40004d40; +r_rwip_aes_encrypt = 0x40004d4c; +r_rwip_assert = 0x40004d58; +r_rwip_crypt_evt_handler = 0x40004d64; +r_rwip_crypt_isr_handler = 0x40004d70; +r_rwip_eif_get = 0x40004d7c; +r_rwip_half_slot_2_lpcycles = 0x40004d88; +r_rwip_hus_2_lpcycles = 0x40004d94; +r_rwip_isr = 0x40004da0; +r_rwip_lpcycles_2_hus = 0x40004dac; +r_rwip_prevent_sleep_clear = 0x40004db8; +r_rwip_prevent_sleep_set = 0x40004dc4; +r_rwip_schedule = 0x40004dd0; +r_rwip_sleep = 0x40004ddc; +r_rwip_sw_int_handler = 0x40004de8; +r_rwip_sw_int_req = 0x40004df4; +r_rwip_time_get = 0x40004e00; +r_rwip_timer_10ms_handler = 0x40004e0c; +r_rwip_timer_10ms_set = 0x40004e18; +r_rwip_timer_hs_handler = 0x40004e24; +r_rwip_timer_hs_set = 0x40004e30; +r_rwip_timer_hus_handler = 0x40004e3c; +r_rwip_timer_hus_set = 0x40004e48; +r_rwip_wakeup = 0x40004e54; +r_rwip_wakeup_end = 0x40004e60; +r_rwip_wlcoex_set = 0x40004e6c; +r_sch_alarm_clear = 0x40004e78; +r_sch_alarm_init = 0x40004e84; +r_sch_alarm_prog = 0x40004e90; +r_sch_alarm_set = 0x40004e9c; +r_sch_alarm_timer_isr = 0x40004ea8; +r_sch_arb_conflict_check = 0x40004eb4; +r_sch_arb_elt_cancel = 0x40004ec0; +r_sch_arb_event_start_isr = 0x40004ecc; +r_sch_arb_init = 0x40004ed8; +r_sch_arb_insert = 0x40004ee4; +r_sch_arb_prog_timer = 0x40004ef0; +r_sch_arb_remove = 0x40004efc; +r_sch_arb_sw_isr = 0x40004f08; +r_sch_plan_chk = 0x40004f14; +r_sch_plan_clock_wrap_offset_update = 0x40004f20; +r_sch_plan_init = 0x40004f2c; +r_sch_plan_interval_req = 0x40004f38; +r_sch_plan_offset_max_calc = 0x40004f44; +r_sch_plan_offset_req = 0x40004f50; +r_sch_plan_position_range_compute = 0x40004f5c; +r_sch_plan_rem = 0x40004f68; +r_sch_plan_req = 0x40004f74; +r_sch_plan_set = 0x40004f80; +r_sch_prog_end_isr = 0x40004f8c; +r_sch_prog_init = 0x40004f98; +r_sch_prog_push = 0x40004fa4; +r_sch_prog_rx_isr = 0x40004fb0; +r_sch_prog_skip_isr = 0x40004fbc; +r_sch_prog_tx_isr = 0x40004fc8; +r_sch_slice_bg_add = 0x40004fd4; +r_sch_slice_bg_remove = 0x40004fe0; +r_sch_slice_compute = 0x40004fec; +r_sch_slice_fg_add = 0x40004ff8; +r_sch_slice_fg_remove = 0x40005004; +r_sch_slice_init = 0x40005010; +r_sch_slice_per_add = 0x4000501c; +r_sch_slice_per_remove = 0x40005028; +r_sdk_config_get_bt_sleep_enable = 0x40005034; +r_sdk_config_get_hl_derived_opts = 0x40005040; +r_sdk_config_get_opts = 0x4000504c; +r_sdk_config_get_priv_opts = 0x40005058; +r_sdk_config_set_bt_sleep_enable = 0x40005064; +r_sdk_config_set_hl_derived_opts = 0x40005070; +r_sdk_config_set_opts = 0x4000507c; +r_specialModP256 = 0x40005088; +r_unloaded_area_init = 0x40005094; +r_vhci_flow_off = 0x400050a0; +r_vhci_flow_on = 0x400050ac; +r_vhci_notify_host_send_available = 0x400050b8; +r_vhci_send_to_host = 0x400050c4; +r_vnd_hci_command_handler = 0x400050d0; +r_vshci_init = 0x400050dc; +vnd_hci_command_handler_wrapper = 0x400050e8; +r_lld_legacy_adv_dynamic_pti_get = 0x400050f4; +r_lld_legacy_adv_dynamic_pti_process = 0x40005100; +r_lld_ext_adv_dynamic_pti_get = 0x4000510c; +r_lld_ext_adv_dynamic_aux_pti_process = 0x40005118; +r_lld_ext_adv_dynamic_pti_process = 0x40005124; +r_lld_adv_ext_pkt_prepare_set = 0x40005130; +r_lld_adv_ext_chain_none_construct = 0x4000513c; +r_lld_adv_ext_chain_connectable_construct = 0x40005148; +r_lld_adv_ext_chain_scannable_construct = 0x40005154; +r_lld_adv_pkt_rx_connect_post = 0x40005160; +r_lld_adv_start_init_evt_param = 0x4000516c; +r_lld_adv_start_set_cs = 0x40005178; +r_lld_adv_start_update_filter_policy = 0x40005184; +r_lld_adv_start_schedule_asap = 0x40005190; +r_lld_con_tx_prog_new_packet_coex = 0x4000519c; +r_lld_con_tx_prog_new_packet = 0x400051a8; +r_lld_per_adv_dynamic_pti_get = 0x400051b4; +r_lld_per_adv_evt_start_chm_upd = 0x400051c0; +r_lld_ext_scan_dynamic_pti_get = 0x400051cc; +r_lld_scan_try_sched = 0x400051d8; +r_lld_sync_insert = 0x400051e4; +r_sch_prog_ble_push = 0x400051f0; +r_sch_prog_bt_push = 0x400051fc; +r_lld_init_evt_end_type_set = 0x40005208; +r_lld_init_evt_end_type_get = 0x40005214; +r_lld_adv_direct_adv_use_rpa_addr_state_set = 0x40005220; +r_lld_adv_direct_adv_use_rpa_addr_state_get = 0x4000522c; +r_lld_init_evt_end_type_check_state_set = 0x40005238; +r_lld_init_evt_end_type_check_state_get = 0x40005244; +/* Data (.data, .bss, .rodata) */ +bt_rf_coex_cfg_p = 0x3fceffa8; +bt_rf_coex_hooks_p = 0x3fceffa4; +btdm_env_p = 0x3fceffa0; +g_rw_controller_task_handle = 0x3fceff9c; +g_rw_init_sem = 0x3fceff98; +g_rw_schd_queue = 0x3fceff94; +lld_init_env = 0x3fceff90; +lld_rpa_renew_env = 0x3fceff8c; +lld_scan_env = 0x3fceff88; +lld_scan_sync_env = 0x3fceff84; +lld_test_env = 0x3fceff80; +p_ble_util_buf_env = 0x3fceff7c; +p_lld_env = 0x3fceff78; +p_llm_env = 0x3fceff74; +r_h4tl_eif_p = 0x3fceff70; +r_hli_funcs_p = 0x3fceff6c; +r_ip_funcs_p = 0x3fceff68; +r_modules_funcs_p = 0x3fceff64; +r_osi_funcs_p = 0x3fceff60; +r_plf_funcs_p = 0x3fceff5c; +vhci_env_p = 0x3fceff58; +aa_gen = 0x3fceff54; +aes_env = 0x3fceff48; +bt_rf_coex_cfg_cb = 0x3fcefef8; +btdm_pwr_state = 0x3fcefef4; +btdm_slp_err = 0x3fcefef0; +ecc_env = 0x3fcefee8; +esp_handler = 0x3fcefee0; +esp_vendor_cmd = 0x3fcefed8; +g_adv_delay_dis = 0x3fcefed4; +g_conflict_elt = 0x3fcefed0; +g_eif_api = 0x3fcefec0; +g_event_empty = 0x3fcefeb4; +g_llc_state = 0x3fcefeaa; +g_llm_state = 0x3fcefea9; +g_max_evt_env = 0x3fcefea7; +g_misc_state = 0x3fcefea6; +g_rma_rule_db = 0x3fcefe8a; +g_rtp_rule_db = 0x3fcefe6e; +g_scan_forever = 0x3fcefe6d; +g_time_msb = 0x3fcefe6c; +h4tl_env = 0x3fcefe44; +hci_env = 0x3fcefe21; +hci_ext_host = 0x3fcefe20; +hci_fc_env = 0x3fcefe18; +hci_tl_env = 0x3fcefdec; +ke_env = 0x3fcefdbc; +ke_event_env = 0x3fcefd7c; +ke_task_env = 0x3fcefd00; +llc_env = 0x3fcefcd8; +lld_adv_env = 0x3fcefcb0; +lld_con_env = 0x3fcefc88; +lld_exp_sync_pos_tab = 0x3fcefc80; +lld_per_adv_env = 0x3fcefc58; +lld_sync_env = 0x3fcefc30; +llm_le_adv_flow_env = 0x3fcefc24; +rw_sleep_enable = 0x3fcefc20; +rwble_env = 0x3fcefc18; +rwip_env = 0x3fcefbfc; +rwip_param = 0x3fcefbf0; +rwip_prog_delay = 0x3fcefbec; +rwip_rf = 0x3fcefbb4; +sch_alarm_env = 0x3fcefbac; +sch_arb_env = 0x3fcefb98; +sch_plan_env = 0x3fcefb90; +sch_prog_env = 0x3fcefa8c; +sch_slice_env = 0x3fcefa2c; +sch_slice_params = 0x3fcefa24; +timer_env = 0x3fcefa1c; +unloaded_area = 0x3fcefa18; +vshci_state = 0x3fcefa14; +TASK_DESC_LLC = 0x3fcefa08; +TASK_DESC_LLM = 0x3fcef9fc; +TASK_DESC_VSHCI = 0x3fcef9f0; +co_default_bdaddr = 0x3fcef9e8; +dbg_assert_block = 0x3fcef9e4; +g_bt_plf_log_level = 0x3fcef9e0; +hci_cmd_desc_tab_vs_esp = 0x3fcef9bc; +hci_command_handler_tab_esp = 0x3fcef9a4; +privacy_en = 0x3fcef9a0; +sdk_cfg_priv_opts = 0x3fcef958; +BasePoint_x_256 = 0x3ff1ffdc; +BasePoint_y_256 = 0x3ff1ffbc; +DebugE256PublicKey_x = 0x3ff1ff9c; +DebugE256PublicKey_y = 0x3ff1ff7c; +DebugE256SecretKey = 0x3ff1ff5c; +ECC_4Win_Look_up_table = 0x3ff1f7a0; +LLM_AA_CT1 = 0x3ff1f79a; +LLM_AA_CT2 = 0x3ff1f798; +RF_TX_PW_CONV_TBL = 0x3ff1f790; +TASK_DESC_MISC = 0x3ff1f784; +adv_evt_prop2type = 0x3ff1f766; +adv_evt_type2prop = 0x3ff1f761; +aes_cmac_zero = 0x3ff1f751; +aes_k2_salt = 0x3ff1f741; +aes_k3_id64 = 0x3ff1f73c; +aes_k3_salt = 0x3ff1f72c; +aes_k4_id6 = 0x3ff1f728; +aes_k4_salt = 0x3ff1f718; +bigHexP256 = 0x3ff1f6ec; +byte_tx_time = 0x3ff1f6e2; +co_null_bdaddr = 0x3ff1f6dc; +co_phy_mask_to_rate = 0x3ff1f6d7; +co_phy_mask_to_value = 0x3ff1f6d2; +co_phy_to_rate = 0x3ff1f6ce; +co_phy_value_to_mask = 0x3ff1f6ca; +co_rate_to_byte_dur_us = 0x3ff1f6c5; +co_rate_to_phy = 0x3ff1f6c0; +co_rate_to_phy_mask = 0x3ff1f6bc; +co_sca2ppm = 0x3ff1f6ac; +coef_B = 0x3ff1f680; +connect_req_dur_tab = 0x3ff1f678; +ecc_Jacobian_InfinityPoint256 = 0x3ff1f5f4; +em_base_reg_lut = 0x3ff1f526; +fixed_tx_time = 0x3ff1f51e; +h4tl_msgtype2hdrlen = 0x3ff1f518; +hci_cmd_desc_root_tab = 0x3ff1f4e8; +hci_cmd_desc_tab_ctrl_bb = 0x3ff1f47c; +hci_cmd_desc_tab_info_par = 0x3ff1f44c; +hci_cmd_desc_tab_le = 0x3ff1f0b0; +hci_cmd_desc_tab_lk_ctrl = 0x3ff1f098; +hci_cmd_desc_tab_stat_par = 0x3ff1f08c; +hci_cmd_desc_tab_vs = 0x3ff1f050; +hci_evt_desc_tab = 0x3ff1f008; +hci_evt_le_desc_tab = 0x3ff1ef68; +hci_evt_le_desc_tab_esp = 0x3ff1ef60; +hci_rsvd_evt_msk = 0x3ff1ef57; +lld_aux_phy_to_rate = 0x3ff1ef54; +lld_init_max_aux_dur_tab = 0x3ff1ef4c; +lld_scan_map_legacy_pdu_to_evt_type = 0x3ff1ef44; +lld_scan_max_aux_dur_tab = 0x3ff1ef3c; +lld_sync_max_aux_dur_tab = 0x3ff1ef34; +llm_local_le_feats = 0x3ff1ef2c; +llm_local_le_states = 0x3ff1ef24; +llm_local_supp_cmds = 0x3ff1eefc; +maxSecretKey_256 = 0x3ff1eedc; +max_data_tx_time = 0x3ff1eed4; +one_bits = 0x3ff1eec3; +rwip_coex_cfg = 0x3ff1eebe; +rwip_priority = 0x3ff1eea8; +veryBigHexP256 = 0x3ff1ee5c; + + +/*************************************** + Group rom_pp + ***************************************/ + +/* Functions */ +esp_pp_rom_version_get = 0x40005250; +RC_GetBlockAckTime = 0x4000525c; +ebuf_list_remove = 0x40005268; +esf_buf_alloc = 0x40005274; +esf_buf_alloc_dynamic = 0x40005280; +esf_buf_recycle = 0x4000528c; +GetAccess = 0x40005298; +hal_mac_is_low_rate_enabled = 0x400052a4; +hal_mac_tx_get_blockack = 0x400052b0; +hal_mac_tx_set_ppdu = 0x400052bc; +ic_get_trc = 0x400052c8; +ic_mac_deinit = 0x400052d4; +ic_mac_init = 0x400052e0; +ic_interface_enabled = 0x400052ec; +is_lmac_idle = 0x400052f8; +lmacAdjustTimestamp = 0x40005304; +lmacDiscardAgedMSDU = 0x40005310; +lmacDiscardMSDU = 0x4000531c; +lmacEndFrameExchangeSequence = 0x40005328; +lmacIsIdle = 0x40005334; +lmacIsLongFrame = 0x40005340; +lmacMSDUAged = 0x4000534c; +lmacPostTxComplete = 0x40005358; +lmacProcessAllTxTimeout = 0x40005364; +lmacProcessCollisions = 0x40005370; +lmacProcessRxSucData = 0x4000537c; +lmacReachLongLimit = 0x40005388; +lmacReachShortLimit = 0x40005394; +lmacRecycleMPDU = 0x400053a0; +lmacRxDone = 0x400053ac; +lmacSetTxFrame = 0x400053b8; +lmacTxDone = 0x400053c4; +lmacTxFrame = 0x400053d0; +mac_tx_set_duration = 0x400053dc; +mac_tx_set_htsig = 0x400053e8; +mac_tx_set_plcp0 = 0x400053f4; +mac_tx_set_plcp1 = 0x40005400; +mac_tx_set_plcp2 = 0x4000540c; +pm_check_state = 0x40005418; +pm_disable_dream_timer = 0x40005424; +pm_disable_sleep_delay_timer = 0x40005430; +pm_dream = 0x4000543c; +pm_mac_wakeup = 0x40005448; +pm_mac_sleep = 0x40005454; +pm_enable_active_timer = 0x40005460; +pm_enable_sleep_delay_timer = 0x4000546c; +pm_local_tsf_process = 0x40005478; +pm_set_beacon_filter = 0x40005484; +pm_is_in_wifi_slice_threshold = 0x40005490; +pm_is_waked = 0x4000549c; +pm_keep_alive = 0x400054a8; +pm_on_beacon_rx = 0x400054b4; +pm_on_data_rx = 0x400054c0; +pm_on_tbtt = 0x400054cc; +pm_parse_beacon = 0x400054d8; +pm_process_tim = 0x400054e4; +pm_rx_beacon_process = 0x400054f0; +pm_rx_data_process = 0x400054fc; +pm_sleep = 0x40005508; +pm_sleep_for = 0x40005514; +pm_tbtt_process = 0x40005520; +ppAMPDU2Normal = 0x4000552c; +ppAssembleAMPDU = 0x40005538; +ppCalFrameTimes = 0x40005544; +ppCalSubFrameLength = 0x40005550; +ppCalTxAMPDULength = 0x4000555c; +ppCheckTxAMPDUlength = 0x40005568; +ppDequeueRxq_Locked = 0x40005574; +ppDequeueTxQ = 0x40005580; +ppEmptyDelimiterLength = 0x4000558c; +ppEnqueueRxq = 0x40005598; +ppEnqueueTxDone = 0x400055a4; +ppGetTxQFirstAvail_Locked = 0x400055b0; +ppGetTxframe = 0x400055bc; +ppMapTxQueue = 0x400055c8; +ppProcTxSecFrame = 0x400055d4; +ppProcessRxPktHdr = 0x400055e0; +ppProcessTxQ = 0x400055ec; +ppRecordBarRRC = 0x400055f8; +lmacRequestTxopQueue = 0x40005604; +lmacReleaseTxopQueue = 0x40005610; +ppRecycleAmpdu = 0x4000561c; +ppRecycleRxPkt = 0x40005628; +ppResortTxAMPDU = 0x40005634; +ppResumeTxAMPDU = 0x40005640; +ppRxFragmentProc = 0x4000564c; +ppRxPkt = 0x40005658; +ppRxProtoProc = 0x40005664; +ppSearchTxQueue = 0x40005670; +ppSearchTxframe = 0x4000567c; +ppSelectNextQueue = 0x40005688; +ppSubFromAMPDU = 0x40005694; +ppTask = 0x400056a0; +ppTxPkt = 0x400056ac; +ppTxProtoProc = 0x400056b8; +ppTxqUpdateBitmap = 0x400056c4; +pp_coex_tx_request = 0x400056d0; +pp_hdrsize = 0x400056dc; +pp_post = 0x400056e8; +pp_process_hmac_waiting_txq = 0x400056f4; +rcGetAmpduSched = 0x40005700; +rcUpdateRxDone = 0x4000570c; +rc_get_trc = 0x40005718; +rc_get_trc_by_index = 0x40005724; +rcAmpduLowerRate = 0x40005730; +rcampduuprate = 0x4000573c; +rcClearCurAMPDUSched = 0x40005748; +rcClearCurSched = 0x40005754; +rcClearCurStat = 0x40005760; +rcGetSched = 0x4000576c; +rcLowerSched = 0x40005778; +rcSetTxAmpduLimit = 0x40005784; +rcTxUpdatePer = 0x40005790; +rcUpdateAckSnr = 0x4000579c; +rcUpdateRate = 0x400057a8; +rcUpdateTxDone = 0x400057b4; +rcUpdateTxDoneAmpdu2 = 0x400057c0; +rcUpSched = 0x400057cc; +rssi_margin = 0x400057d8; +rx11NRate2AMPDULimit = 0x400057e4; +TRC_AMPDU_PER_DOWN_THRESHOLD = 0x400057f0; +TRC_AMPDU_PER_UP_THRESHOLD = 0x400057fc; +trc_calc_duration = 0x40005808; +trc_isTxAmpduOperational = 0x40005814; +trc_onAmpduOp = 0x40005820; +TRC_PER_IS_GOOD = 0x4000582c; +trc_SetTxAmpduState = 0x40005838; +trc_tid_isTxAmpduOperational = 0x40005844; +trcAmpduSetState = 0x40005850; +wDevCheckBlockError = 0x4000585c; +wDev_AppendRxBlocks = 0x40005868; +wDev_DiscardFrame = 0x40005874; +wDev_GetNoiseFloor = 0x40005880; +wDev_IndicateAmpdu = 0x4000588c; +wDev_IndicateFrame = 0x40005898; +wdev_bank_store = 0x400058a4; +wdev_bank_load = 0x400058b0; +wdev_mac_reg_load = 0x400058bc; +wdev_mac_reg_store = 0x400058c8; +wdev_mac_special_reg_load = 0x400058d4; +wdev_mac_special_reg_store = 0x400058e0; +wdev_mac_wakeup = 0x400058ec; +wdev_mac_sleep = 0x400058f8; +hal_mac_is_dma_enable = 0x40005904; +wDev_ProcessFiq = 0x40005910; +wDev_ProcessRxSucData = 0x4000591c; +wdevProcessRxSucDataAll = 0x40005928; +wdev_csi_len_align = 0x40005934; +ppDequeueTxDone_Locked = 0x40005940; +ppProcTxDone = 0x4000594c; +pm_tx_data_done_process = 0x40005958; +config_is_cache_tx_buf_enabled = 0x40005964; +ppMapWaitTxq = 0x40005970; +ppProcessWaitingQueue = 0x4000597c; +ppDisableQueue = 0x40005988; +pm_allow_tx = 0x40005994; +wdev_is_data_in_rxlist = 0x400059a0; +ppProcTxCallback = 0x400059ac; +/* Data (.data, .bss, .rodata) */ +our_instances_ptr = 0x3ff1ee58; +pTxRx = 0x3fcef954; +lmacConfMib_ptr = 0x3fcef950; +our_wait_eb = 0x3fcef94c; +our_tx_eb = 0x3fcef948; +pp_wdev_funcs = 0x3fcef944; +g_osi_funcs_p = 0x3fcef940; +wDevCtrl_ptr = 0x3fcef93c; +g_wdev_last_desc_reset_ptr = 0x3ff1ee54; +wDevMacSleep_ptr = 0x3fcef938; +g_lmac_cnt_ptr = 0x3fcef934; +our_controls_ptr = 0x3ff1ee50; +pp_sig_cnt_ptr = 0x3fcef930; +g_eb_list_desc_ptr = 0x3fcef92c; +s_fragment_ptr = 0x3fcef928; +if_ctrl_ptr = 0x3fcef924; +g_intr_lock_mux = 0x3fcef920; +g_wifi_global_lock = 0x3fcef91c; +s_wifi_queue = 0x3fcef918; +pp_task_hdl = 0x3fcef914; +s_pp_task_create_sem = 0x3fcef910; +s_pp_task_del_sem = 0x3fcef90c; +g_wifi_menuconfig_ptr = 0x3fcef908; +xphyQueue = 0x3fcef904; +ap_no_lr_ptr = 0x3fcef900; +rc11BSchedTbl_ptr = 0x3fcef8fc; +rc11NSchedTbl_ptr = 0x3fcef8f8; +rcLoRaSchedTbl_ptr = 0x3fcef8f4; +BasicOFDMSched_ptr = 0x3fcef8f0; +trc_ctl_ptr = 0x3fcef8ec; +g_pm_cnt_ptr = 0x3fcef8e8; +g_pm_ptr = 0x3fcef8e4; +g_pm_cfg_ptr = 0x3fcef8e0; +g_esp_mesh_quick_funcs_ptr = 0x3fcef8dc; +g_txop_queue_status_ptr = 0x3fcef8d8; +g_mac_sleep_en_ptr = 0x3fcef8d4; +g_mesh_is_root_ptr = 0x3fcef8d0; +g_mesh_topology_ptr = 0x3fcef8cc; +g_mesh_init_ps_type_ptr = 0x3fcef8c8; +g_mesh_is_started_ptr = 0x3fcef8c4; +g_config_func = 0x3fcef8c0; +g_net80211_tx_func = 0x3fcef8bc; +g_timer_func = 0x3fcef8b8; +s_michael_mic_failure_cb = 0x3fcef8b4; +wifi_sta_rx_probe_req = 0x3fcef8b0; +g_tx_done_cb_func = 0x3fcef8ac; +g_per_conn_trc = 0x3fcef860; +s_encap_amsdu_func = 0x3fcef85c; + + +/*************************************** + Group rom_net80211 + ***************************************/ + +/* Functions */ +esp_net80211_rom_version_get = 0x400059b8; +ampdu_dispatch = 0x400059c4; +ampdu_dispatch_all = 0x400059d0; +ampdu_dispatch_as_many_as_possible = 0x400059dc; +ampdu_dispatch_movement = 0x400059e8; +ampdu_dispatch_upto = 0x400059f4; +chm_is_at_home_channel = 0x40005a00; +cnx_node_is_existing = 0x40005a0c; +cnx_node_search = 0x40005a18; +ic_ebuf_recycle_rx = 0x40005a24; +ic_ebuf_recycle_tx = 0x40005a30; +ic_reset_rx_ba = 0x40005a3c; +ieee80211_align_eb = 0x40005a48; +ieee80211_ampdu_reorder = 0x40005a54; +ieee80211_ampdu_start_age_timer = 0x40005a60; +ieee80211_encap_esfbuf = 0x40005a6c; +ieee80211_is_tx_allowed = 0x40005a78; +ieee80211_output_pending_eb = 0x40005a84; +ieee80211_output_process = 0x40005a90; +ieee80211_set_tx_desc = 0x40005a9c; +sta_input = 0x40005aa8; +wifi_get_macaddr = 0x40005ab4; +wifi_rf_phy_disable = 0x40005ac0; +wifi_rf_phy_enable = 0x40005acc; +ic_ebuf_alloc = 0x40005ad8; +ieee80211_classify = 0x40005ae4; +ieee80211_copy_eb_header = 0x40005af0; +ieee80211_recycle_cache_eb = 0x40005afc; +ieee80211_search_node = 0x40005b08; +roundup2 = 0x40005b14; +ieee80211_crypto_encap = 0x40005b20; +ieee80211_crypto_decap = 0x40005b2c; +ieee80211_decap = 0x40005b38; +ieee80211_set_tx_pti = 0x40005b44; +wifi_is_started = 0x40005b50; +ieee80211_gettid = 0x40005b5c; +/* Data (.data, .bss, .rodata) */ +net80211_funcs = 0x3fcef858; +g_scan = 0x3fcef854; +g_chm = 0x3fcef850; +g_ic_ptr = 0x3fcef84c; +g_hmac_cnt_ptr = 0x3fcef848; +g_tx_cacheq_ptr = 0x3fcef844; +s_netstack_free = 0x3fcef840; +mesh_rxcb = 0x3fcef83c; +sta_rxcb = 0x3fcef838; + + +/*************************************** + Group rom_coexist + ***************************************/ + +/* Functions */ +esp_coex_rom_version_get = 0x40005b68; +coex_bt_release = 0x40005b74; +coex_bt_request = 0x40005b80; +coex_core_ble_conn_dyn_prio_get = 0x40005b8c; +coex_core_event_duration_get = 0x40005b98; +coex_core_pti_get = 0x40005ba4; +coex_core_release = 0x40005bb0; +coex_core_request = 0x40005bbc; +coex_core_status_get = 0x40005bc8; +coex_core_timer_idx_get = 0x40005bd4; +coex_event_duration_get = 0x40005be0; +coex_hw_timer_disable = 0x40005bec; +coex_hw_timer_enable = 0x40005bf8; +coex_hw_timer_set = 0x40005c04; +coex_schm_interval_set = 0x40005c10; +coex_schm_lock = 0x40005c1c; +coex_schm_unlock = 0x40005c28; +coex_status_get = 0x40005c34; +coex_wifi_release = 0x40005c40; +esp_coex_ble_conn_dynamic_prio_get = 0x40005c4c; +/* Data (.data, .bss, .rodata) */ +coex_env_ptr = 0x3fcef834; +coex_pti_tab_ptr = 0x3fcef830; +coex_schm_env_ptr = 0x3fcef82c; +coexist_funcs = 0x3fcef828; +g_coa_funcs_p = 0x3fcef824; +g_coex_param_ptr = 0x3fcef820; + + +/*************************************** + Group rom_phy + ***************************************/ + +/* Functions */ +phy_get_romfuncs = 0x40005c58; +rom_abs_temp = 0x40005c64; +rom_bb_bss_cbw40_dig = 0x40005c70; +rom_bb_wdg_test_en = 0x40005c7c; +rom_bb_wdt_get_status = 0x40005c88; +rom_bb_wdt_int_enable = 0x40005c94; +rom_bb_wdt_rst_enable = 0x40005ca0; +rom_bb_wdt_timeout_clear = 0x40005cac; +rom_cbw2040_cfg = 0x40005cb8; +rom_check_noise_floor = 0x40005cc4; +rom_chip_i2c_readReg = 0x40005cd0; +rom_chip_i2c_writeReg = 0x40005cdc; +rom_dc_iq_est = 0x40005ce8; +rom_disable_agc = 0x40005cf4; +rom_en_pwdet = 0x40005d00; +rom_enable_agc = 0x40005d0c; +rom_get_bbgain_db = 0x40005d18; +rom_get_data_sat = 0x40005d24; +rom_get_i2c_read_mask = 0x40005d30; +rom_get_pwctrl_correct = 0x40005d3c; +rom_i2c_readReg = 0x40005d48; +rom_i2c_readReg_Mask = 0x40005d54; +rom_i2c_writeReg = 0x40005d60; +rom_i2c_writeReg_Mask = 0x40005d6c; +rom_index_to_txbbgain = 0x40005d78; +rom_iq_est_disable = 0x40005d84; +rom_iq_est_enable = 0x40005d90; +rom_linear_to_db = 0x40005d9c; +rom_loopback_mode_en = 0x40005da8; +rom_mhz2ieee = 0x40005db4; +rom_noise_floor_auto_set = 0x40005dc0; +rom_pbus_debugmode = 0x40005dcc; +rom_pbus_force_mode = 0x40005dd8; +rom_pbus_force_test = 0x40005de4; +rom_pbus_rd = 0x40005df0; +rom_pbus_rd_addr = 0x40005dfc; +rom_pbus_rd_shift = 0x40005e08; +rom_pbus_set_dco = 0x40005e14; +rom_pbus_set_rxgain = 0x40005e20; +rom_pbus_workmode = 0x40005e2c; +rom_pbus_xpd_rx_off = 0x40005e38; +rom_pbus_xpd_rx_on = 0x40005e44; +rom_pbus_xpd_tx_off = 0x40005e50; +rom_pbus_xpd_tx_on = 0x40005e5c; +rom_phy_byte_to_word = 0x40005e68; +rom_phy_disable_cca = 0x40005e74; +rom_phy_enable_cca = 0x40005e80; +rom_phy_get_noisefloor = 0x40005e8c; +rom_phy_get_rx_freq = 0x40005e98; +rom_phy_set_bbfreq_init = 0x40005ea4; +rom_pow_usr = 0x40005eb0; +rom_pwdet_sar2_init = 0x40005ebc; +rom_read_hw_noisefloor = 0x40005ec8; +rom_read_sar_dout = 0x40005ed4; +rom_set_cal_rxdc = 0x40005ee0; +rom_set_chan_cal_interp = 0x40005eec; +rom_set_loopback_gain = 0x40005ef8; +rom_set_noise_floor = 0x40005f04; +rom_set_rxclk_en = 0x40005f10; +rom_set_tx_dig_gain = 0x40005f1c; +rom_set_txcap_reg = 0x40005f28; +rom_set_txclk_en = 0x40005f34; +rom_spur_cal = 0x40005f40; +rom_spur_reg_write_one_tone = 0x40005f4c; +rom_target_power_add_backoff = 0x40005f58; +rom_tx_pwctrl_bg_init = 0x40005f64; +rom_txbbgain_to_index = 0x40005f70; +rom_wifi_11g_rate_chg = 0x40005f7c; +rom_write_gain_mem = 0x40005f88; +chip728_phyrom_version = 0x40005f94; +rom_disable_wifi_agc = 0x40005fa0; +rom_enable_wifi_agc = 0x40005fac; +rom_bt_index_to_bb = 0x40005fb8; +rom_bt_bb_to_index = 0x40005fc4; +rom_spur_coef_cfg = 0x40005fd0; +rom_bb_bss_cbw40 = 0x40005fdc; +rom_set_cca = 0x40005fe8; +rom_tx_paon_set = 0x40005ff4; +rom_i2cmst_reg_init = 0x40006000; +rom_iq_corr_enable = 0x4000600c; +rom_fe_reg_init = 0x40006018; +rom_agc_reg_init = 0x40006024; +rom_bb_reg_init = 0x40006030; +rom_mac_enable_bb = 0x4000603c; +rom_bb_wdg_cfg = 0x40006048; +rom_force_txon = 0x40006054; +rom_fe_txrx_reset = 0x40006060; +rom_set_rx_comp = 0x4000606c; +rom_set_pbus_reg = 0x40006078; +rom_write_chan_freq = 0x40006084; +rom_phy_xpd_rf = 0x40006090; +rom_set_xpd_sar = 0x4000609c; +rom_get_target_power_offset = 0x400060a8; +rom_write_txrate_power_offset = 0x400060b4; +rom_get_rate_fcc_index = 0x400060c0; +rom_get_rate_target_power = 0x400060cc; +rom_pkdet_vol_start = 0x400060d8; +rom_read_sar2_code = 0x400060e4; +rom_get_sar2_vol = 0x400060f0; +rom_get_pll_vol = 0x400060fc; +rom_get_phy_target_power = 0x40006108; +rom_temp_to_power = 0x40006114; +rom_phy_track_pll_cap = 0x40006120; +rom_phy_pwdet_always_en = 0x4000612c; +rom_phy_pwdet_onetime_en = 0x40006138; +rom_get_i2c_mst0_mask = 0x40006144; +rom_get_i2c_hostid = 0x40006150; +rom_enter_critical_phy = 0x4000615c; +rom_exit_critical_phy = 0x40006168; +rom_chip_i2c_readReg_org = 0x40006174; +rom_i2c_paral_set_mst0 = 0x40006180; +rom_i2c_paral_set_read = 0x4000618c; +rom_i2c_paral_read = 0x40006198; +rom_i2c_paral_write = 0x400061a4; +rom_i2c_paral_write_num = 0x400061b0; +rom_i2c_paral_write_mask = 0x400061bc; +rom_bb_bss_cbw40_ana = 0x400061c8; +rom_chan_to_freq = 0x400061d4; +rom_open_i2c_xpd = 0x400061e0; +rom_dac_rate_set = 0x400061ec; +rom_tsens_read_init = 0x400061f8; +rom_tsens_code_read = 0x40006204; +rom_tsens_index_to_dac = 0x40006210; +rom_tsens_index_to_offset = 0x4000621c; +rom_tsens_dac_cal = 0x40006228; +rom_code_to_temp = 0x40006234; +rom_write_pll_cap_mem = 0x40006240; +rom_pll_correct_dcap = 0x4000624c; +rom_phy_en_hw_set_freq = 0x40006258; +rom_phy_dis_hw_set_freq = 0x40006264; +rom_pll_vol_cal = 0x40006270; +rom_wrtie_pll_cap = 0x4000627c; +rom_set_tx_gain_mem = 0x40006288; +rom_bt_tx_dig_gain = 0x40006294; +rom_bt_get_tx_gain = 0x400062a0; +rom_get_chan_target_power = 0x400062ac; +rom_get_tx_gain_value = 0x400062b8; +rom_wifi_tx_dig_gain = 0x400062c4; +rom_wifi_get_tx_gain = 0x400062d0; +rom_fe_i2c_reg_renew = 0x400062dc; +rom_wifi_agc_sat_gain = 0x400062e8; +rom_i2c_master_reset = 0x400062f4; +rom_bt_filter_reg = 0x40006300; +rom_phy_bbpll_cal = 0x4000630c; +rom_i2c_sar2_init_code = 0x40006318; +rom_phy_param_addr = 0x40006324; +rom_phy_reg_init = 0x40006330; +rom_set_chan_reg = 0x4000633c; +rom_phy_wakeup_init = 0x40006348; +rom_phy_i2c_init1 = 0x40006354; +rom_tsens_temp_read = 0x40006360; +rom_bt_track_pll_cap = 0x4000636c; +rom_wifi_track_pll_cap = 0x40006378; +rom_wifi_set_tx_gain = 0x40006384; +rom_txpwr_cal_track = 0x40006390; +rom_tx_pwctrl_background = 0x4000639c; +rom_bt_set_tx_gain = 0x400063a8; +rom_noise_check_loop = 0x400063b4; +rom_phy_close_rf = 0x400063c0; +rom_phy_xpd_tsens = 0x400063cc; +rom_phy_freq_mem_backup = 0x400063d8; +rom_phy_ant_init = 0x400063e4; +rom_bt_track_tx_power = 0x400063f0; +rom_wifi_track_tx_power = 0x400063fc; +rom_phy_dig_reg_backup = 0x40006408; +chip728_phyrom_version_num = 0x40006414; +rom_mac_tx_chan_offset = 0x40006420; +rom_rx_gain_force = 0x4000642c; +/* Data (.data, .bss, .rodata) */ +phy_param_rom = 0x3fcef81c; diff --git a/tools/flasher_stub/ld/rom_32s3_beta_2.ld b/tools/flasher_stub/ld/rom_32s3_beta_2.ld new file mode 100644 index 0000000000..eb2ce03153 --- /dev/null +++ b/tools/flasher_stub/ld/rom_32s3_beta_2.ld @@ -0,0 +1,2397 @@ +/* +ESP32-S3 ROM address table +Generated for ROM with MD5sum: +d20fb231463ce337432b1fa9cba0b3c9 eagle.pro.rom.out +*/ +PROVIDE ( aa_gen = 0x3fcefa9c ); +PROVIDE ( abort = 0x400544a4 ); +PROVIDE ( abs = 0x40032344 ); +PROVIDE ( __absvdi2 = 0x40037f14 ); +PROVIDE ( __absvsi2 = 0x40037f00 ); +PROVIDE ( acm_config_descr = 0x3ff0c257 ); +PROVIDE ( acm_usb_descriptors = 0x3ff0c1b4 ); +PROVIDE ( __adddf3 = 0x4003bd5c ); +PROVIDE ( __addsf3 = 0x4003b9f0 ); +PROVIDE ( __addvdi3 = 0x4003c488 ); +PROVIDE ( __addvsi3 = 0x4003c464 ); +PROVIDE ( aes_cmac_zero = 0x3ff07782 ); +PROVIDE ( aes_env = 0x3fcef8c4 ); +PROVIDE ( aes_k2_salt = 0x3ff07792 ); +PROVIDE ( aes_k3_id64 = 0x3ff077a2 ); +PROVIDE ( aes_k3_salt = 0x3ff077a7 ); +PROVIDE ( aes_k4_id6 = 0x3ff077b7 ); +PROVIDE ( aes_k4_salt = 0x3ff077bb ); +PROVIDE ( analog_super_wdt_reset = 0x3fcefcc6 ); +PROVIDE ( analog_super_wdt_reset_happened = 0x40045a3c ); +PROVIDE ( __ascii_mbtowc = 0x40039ec4 ); +PROVIDE ( __ascii_wctomb = 0x40033cb0 ); +PROVIDE ( __ashldi3 = 0x40055928 ); +PROVIDE ( __ashrdi3 = 0x40055940 ); +PROVIDE ( __assert = 0x40054a5c ); +PROVIDE ( __assert_func = 0x40054a30 ); +PROVIDE ( atoi = 0x40032984 ); +PROVIDE ( _atoi_r = 0x40032994 ); +PROVIDE ( atol = 0x400329ac ); +PROVIDE ( _atol_r = 0x400329bc ); +PROVIDE ( BasePoint_x_256 = 0x3ff08238 ); +PROVIDE ( BasePoint_y_256 = 0x3ff08218 ); +PROVIDE ( bigHexP256 = 0x3ff08140 ); +PROVIDE ( boot_prepare = 0x40044ef4 ); +PROVIDE ( __bswapdi2 = 0x40039054 ); +PROVIDE ( __bswapsi2 = 0x4003902c ); +PROVIDE ( btdm_con_maxevtime_cal_impl = 0x40017018 ); +PROVIDE ( btdm_controller_get_compile_version_impl = 0x40001234 ); +PROVIDE ( btdm_disable_adv_delay_impl = 0x40014788 ); +PROVIDE ( btdm_dis_privacy_err_report_impl = 0x4001ddb0 ); +PROVIDE ( btdm_enable_scan_continue_impl = 0x4001d7f8 ); +PROVIDE ( btdm_enable_scan_forever_impl = 0x4002344c ); +PROVIDE ( btdm_env_p = 0x3fcef464 ); +PROVIDE ( btdm_get_power_state_impl = 0x4002ffbc ); +PROVIDE ( btdm_get_prevent_sleep_flag_impl = 0x4002ffc8 ); +PROVIDE ( btdm_power_state_active_impl = 0x4002ffa8 ); +PROVIDE ( btdm_pwr_state = 0x3fcefb90 ); +PROVIDE ( btdm_slp_err = 0x3fcefb48 ); +PROVIDE ( btdm_switch_phy_coded_impl = 0x4001d77c ); +PROVIDE ( bt_rf_coex_cfg_cb = 0x3fcefad0 ); +PROVIDE ( bt_rf_coex_cfg_p = 0x3fcefacc ); +PROVIDE ( bt_rf_coex_get_dft_cfg = 0x4002e518 ); +PROVIDE ( bt_rf_coex_hooks_p = 0x3fcef694 ); +PROVIDE ( bt_rf_coex_hooks_p_set = 0x4002e4e4 ); +PROVIDE ( byte_tx_time = 0x3ff08d44 ); +PROVIDE ( bzero = 0x40039d84 ); +PROVIDE ( Cache_Address_Through_DCache = 0x40051ebc ); +PROVIDE ( Cache_Address_Through_ICache = 0x40051ea4 ); +PROVIDE ( Cache_Clean_Addr = 0x40052458 ); +PROVIDE ( Cache_Clean_All = 0x40052518 ); +PROVIDE ( Cache_Clean_Items = 0x40051fe8 ); +PROVIDE ( Cache_Config_DCache_Autoload = 0x40052828 ); +PROVIDE ( Cache_Config_ICache_Autoload = 0x400526dc ); +PROVIDE ( Cache_Count_Flash_Pages = 0x40053088 ); +PROVIDE ( Cache_Dbus_MMU_Set = 0x40053004 ); +PROVIDE ( Cache_DCache_Preload_Done = 0x400526a0 ); +PROVIDE ( Cache_Disable_DCache = 0x40052be4 ); +PROVIDE ( Cache_Disable_DCache_Autoload = 0x40052924 ); +PROVIDE ( Cache_Disable_DCache_PreLock = 0x40052a74 ); +PROVIDE ( Cache_Disable_ICache = 0x40052b70 ); +PROVIDE ( Cache_Disable_ICache_Autoload = 0x400527d8 ); +PROVIDE ( Cache_Disable_ICache_PreLock = 0x400529dc ); +PROVIDE ( Cache_Enable_DCache = 0x40052c34 ); +PROVIDE ( Cache_Enable_DCache_Autoload = 0x4005290c ); +PROVIDE ( Cache_Enable_DCache_PreLock = 0x40052a0c ); +PROVIDE ( Cache_Enable_Defalut_ICache_Mode = 0x40051f1c ); +PROVIDE ( Cache_Enable_ICache = 0x40052bc0 ); +PROVIDE ( Cache_Enable_ICache_Autoload = 0x400527c0 ); +PROVIDE ( Cache_Enable_ICache_PreLock = 0x40052974 ); +PROVIDE ( Cache_End_DCache_Preload = 0x400526b4 ); +PROVIDE ( Cache_End_ICache_Preload = 0x40052614 ); +PROVIDE ( Cache_Flash_To_SPIRAM_Copy = 0x400530e4 ); +PROVIDE ( Cache_Freeze_DCache_Disable = 0x40052390 ); +PROVIDE ( Cache_Freeze_DCache_Enable = 0x40052354 ); +PROVIDE ( Cache_Freeze_ICache_Disable = 0x4005232c ); +PROVIDE ( Cache_Freeze_ICache_Enable = 0x400522f0 ); +PROVIDE ( Cache_Get_DCache_Line_Size = 0x40051d90 ); +PROVIDE ( Cache_Get_DROM_MMU_End = 0x40052e9c ); +PROVIDE ( Cache_Get_ICache_Line_Size = 0x40051d78 ); +PROVIDE ( Cache_Get_IROM_MMU_End = 0x40052e90 ); +PROVIDE ( Cache_Get_Memory_Addr = 0x4005352c ); +PROVIDE ( Cache_Get_Memory_BaseAddr = 0x400534b8 ); +PROVIDE ( Cache_Get_Memory_value = 0x40053574 ); +PROVIDE ( Cache_Get_Mode = 0x40051dac ); +PROVIDE ( Cache_Get_Virtual_Addr = 0x40053480 ); +PROVIDE ( Cache_Ibus_MMU_Set = 0x40052f80 ); +PROVIDE ( Cache_ICache_Preload_Done = 0x40052600 ); +PROVIDE ( cache_internal_table_ptr = 0x3fcefc70 ); +PROVIDE ( Cache_Invalidate_Addr = 0x400523ec ); +PROVIDE ( Cache_Invalidate_DCache_All = 0x40052504 ); +PROVIDE ( Cache_Invalidate_DCache_Items = 0x40051fa0 ); +PROVIDE ( Cache_Invalidate_ICache_All = 0x400524f0 ); +PROVIDE ( Cache_Invalidate_ICache_Items = 0x40051f4c ); +PROVIDE ( Cache_Lock_Addr = 0x40052a94 ); +PROVIDE ( Cache_Lock_DCache_Items = 0x40052214 ); +PROVIDE ( Cache_Lock_ICache_Items = 0x40052180 ); +PROVIDE ( Cache_Mask_All = 0x40052548 ); +PROVIDE ( cache_memory_baseaddrs = 0x3ff0c4c4 ); +PROVIDE ( Cache_MMU_Init = 0x40052f64 ); +PROVIDE ( Cache_Occupy_Addr = 0x40052d70 ); +PROVIDE ( Cache_Occupy_DCache_MEMORY = 0x40052f18 ); +PROVIDE ( Cache_Occupy_ICache_MEMORY = 0x40052ed4 ); +PROVIDE ( Cache_Occupy_Items = 0x400522a8 ); +PROVIDE ( Cache_Op_Addr = 0x4005207c ); +PROVIDE ( cache_op_cb = 0x3fcefc7c ); +PROVIDE ( Cache_Owner_Init = 0x40052eb4 ); +PROVIDE ( Cache_Resume_DCache = 0x40052d38 ); +PROVIDE ( Cache_Resume_DCache_Autoload = 0x400523d0 ); +PROVIDE ( Cache_Resume_ICache = 0x40052cac ); +PROVIDE ( Cache_Resume_ICache_Autoload = 0x400523b4 ); +PROVIDE ( Cache_Set_DCache_Mode = 0x40051e68 ); +PROVIDE ( Cache_Set_Default_Mode = 0x40051ed4 ); +PROVIDE ( Cache_Set_ICache_Mode = 0x40051e14 ); +PROVIDE ( Cache_Set_IDROM_MMU_Info = 0x40052e6c ); +PROVIDE ( Cache_Set_IDROM_MMU_Size = 0x40052dd0 ); +PROVIDE ( Cache_Start_DCache_Preload = 0x40052634 ); +PROVIDE ( Cache_Start_ICache_Preload = 0x40052594 ); +PROVIDE ( Cache_Suspend_DCache = 0x40052ce4 ); +PROVIDE ( Cache_Suspend_DCache_Autoload = 0x40052140 ); +PROVIDE ( Cache_Suspend_ICache = 0x40052c58 ); +PROVIDE ( Cache_Suspend_ICache_Autoload = 0x40052108 ); +PROVIDE ( Cache_Travel_Tag_Memory = 0x400531c0 ); +PROVIDE ( Cache_Unlock_Addr = 0x40052b00 ); +PROVIDE ( Cache_Unlock_DCache_Items = 0x40052258 ); +PROVIDE ( Cache_Unlock_ICache_Items = 0x400521c4 ); +PROVIDE ( Cache_UnMask_Dram0 = 0x40052570 ); +PROVIDE ( Cache_WriteBack_Addr = 0x400524a4 ); +PROVIDE ( Cache_WriteBack_All = 0x4005252c ); +PROVIDE ( Cache_WriteBack_Items = 0x40052030 ); +PROVIDE ( cacl_rtc_memory_crc = 0x40045b04 ); +PROVIDE ( calloc = 0x400547e4 ); +PROVIDE ( _calloc_r = 0x400544f8 ); +PROVIDE ( cdc_acm_class_handle_req = 0x40049da4 ); +PROVIDE ( cdc_acm_config = 0x3fcef044 ); +PROVIDE ( cdc_acm_dev = 0x3fcef340 ); +PROVIDE ( cdc_acm_fifo_fill = 0x40049ee0 ); +PROVIDE ( cdc_acm_fifo_read = 0x40049f54 ); +PROVIDE ( cdc_acm_init = 0x40049e98 ); +PROVIDE ( cdc_acm_irq_callback_set = 0x4004a028 ); +PROVIDE ( cdc_acm_irq_is_pending = 0x4004a004 ); +PROVIDE ( cdc_acm_irq_rx_disable = 0x40049fe4 ); +PROVIDE ( cdc_acm_irq_rx_enable = 0x40049fd8 ); +PROVIDE ( cdc_acm_irq_rx_ready = 0x40049ff0 ); +PROVIDE ( cdc_acm_irq_state_disable = 0x40049fb8 ); +PROVIDE ( cdc_acm_irq_state_enable = 0x40049fac ); +PROVIDE ( cdc_acm_irq_tx_disable = 0x40049fa0 ); +PROVIDE ( cdc_acm_irq_tx_enable = 0x40049f94 ); +PROVIDE ( cdc_acm_irq_tx_ready = 0x40049fc4 ); +PROVIDE ( cdc_acm_line_ctrl_get = 0x4004a084 ); +PROVIDE ( cdc_acm_line_ctrl_set = 0x4004a030 ); +PROVIDE ( cdc_acm_poll_out = 0x4004a0b4 ); +PROVIDE ( cdc_acm_rx_fifo_cnt = 0x40049f40 ); +PROVIDE ( chip725_phyrom_version = 0x4003edec ); +PROVIDE ( chip_usb_detach = 0x4004a250 ); +PROVIDE ( chip_usb_dw_did_persist = 0x4004a0d0 ); +PROVIDE ( chip_usb_dw_init = 0x4004a104 ); +PROVIDE ( chip_usb_dw_prepare_persist = 0x4004a2cc ); +PROVIDE ( chip_usb_get_persist_flags = 0x4004a31c ); +PROVIDE ( chip_usb_set_persist_flags = 0x4004a32c ); +PROVIDE ( _cleanup = 0x40054ae4 ); +PROVIDE ( _cleanup_r = 0x40054a6c ); +PROVIDE ( __clear_cache = 0x40037ef8 ); +PROVIDE ( clear_super_wdt_reset_flag = 0x40045bc8 ); +PROVIDE ( close = 0x4003b8ec ); +PROVIDE ( _close_r = 0x4005463c ); +PROVIDE ( __clrsbdi2 = 0x400390c8 ); +PROVIDE ( __clrsbsi2 = 0x400390b0 ); +PROVIDE ( __clzdi2 = 0x40055bbc ); +PROVIDE ( __clzsi2 = 0x400558f8 ); +PROVIDE ( __cmpdi2 = 0x40037eb8 ); +PROVIDE ( co_default_bdaddr = 0x3fcef398 ); +PROVIDE ( coef_B = 0x3ff0816c ); +PROVIDE ( connect_req_dur_tab = 0x3ff08d4c ); +PROVIDE ( context = 0x3fcee134 ); +PROVIDE ( co_null_bdaddr = 0x3ff077ec ); +PROVIDE ( co_phy_mask_to_rate = 0x3ff077d1 ); +PROVIDE ( co_phy_mask_to_value = 0x3ff077de ); +PROVIDE ( co_phy_to_rate = 0x3ff077e3 ); +PROVIDE ( co_phy_value_to_mask = 0x3ff077da ); +PROVIDE ( co_rate_to_byte_dur_us = 0x3ff077cc ); +PROVIDE ( co_rate_to_phy = 0x3ff077e7 ); +PROVIDE ( co_rate_to_phy_mask = 0x3ff077d6 ); +PROVIDE ( co_sca2ppm = 0x3ff077f2 ); +PROVIDE ( cpio_destroy = 0x4004c76c ); +PROVIDE ( cpio_done = 0x4004c738 ); +PROVIDE ( cpio_feed = 0x4004c438 ); +PROVIDE ( cpio_start = 0x4004c3ec ); +PROVIDE ( crc16_be = 0x400477b8 ); +PROVIDE ( crc16_le = 0x4004777c ); +PROVIDE ( crc32_be = 0x40047748 ); +PROVIDE ( crc32_le = 0x40047714 ); +PROVIDE ( crc8_be = 0x40047828 ); +PROVIDE ( crc8_le = 0x400477f8 ); +PROVIDE ( creat = 0x40039d48 ); +PROVIDE ( _ctype_ = 0x3ff0732c ); +PROVIDE ( __ctzdi2 = 0x40055bd0 ); +PROVIDE ( __ctzsi2 = 0x40055900 ); +PROVIDE ( _cvt = 0x40045498 ); +PROVIDE ( _data_end_all_app = 0x3fcefff0 ); +PROVIDE ( _data_end_all_pro = 0x3fcefff0 ); +PROVIDE ( _data_end_btdm = 0x3fcef454 ); +PROVIDE ( _data_end_btdm_rom = 0x40056700 ); +PROVIDE ( _data_end_c = 0x3fcefcd0 ); +PROVIDE ( _data_end_cache = 0x3fcefc7c ); +PROVIDE ( _data_end_ets = 0x3fced910 ); +PROVIDE ( _data_end_ets_delay = 0x3fcefcc4 ); +PROVIDE ( _data_end_ets_printf = 0x3fcefcac ); +PROVIDE ( _data_end_ets_rtc = 0x3fcefcc4 ); +PROVIDE ( _data_end_newlib = 0x3fcefcc8 ); +PROVIDE ( _data_end_opi_flash = 0x3fcefca4 ); +PROVIDE ( _data_end_phyrom = 0x3fcefff0 ); +PROVIDE ( _data_end_sip = 0x3fcee174 ); +PROVIDE ( _data_end_slc = 0x3fcee174 ); +PROVIDE ( _data_end_spi_flash = 0x3fcefc10 ); +PROVIDE ( _data_end_spi_slave = 0x3fcee130 ); +PROVIDE ( _data_end_uart = 0x3fcef34c ); +PROVIDE ( _data_end_usbdev = 0x3fcef0c4 ); +PROVIDE ( _data_end_xtos = 0x3fcee590 ); +PROVIDE ( _data_start_all_app = 0x3fcefff0 ); +PROVIDE ( _data_start_all_pro = 0x3fcefff0 ); +PROVIDE ( _data_start_btdm = 0x3fcef390 ); +PROVIDE ( _data_start_btdm_rom = 0x400566fc ); +PROVIDE ( _data_start_c = 0x3fcefccc ); +PROVIDE ( _data_start_cache = 0x3fcefc70 ); +PROVIDE ( _data_start_ets = 0x3fced910 ); +PROVIDE ( _data_start_ets_delay = 0x3fcefcc0 ); +PROVIDE ( _data_start_ets_printf = 0x3fcefcac ); +PROVIDE ( _data_start_ets_rtc = 0x3fcefcc4 ); +PROVIDE ( _data_start_newlib = 0x3fcefcc8 ); +PROVIDE ( _data_start_opi_flash = 0x3fcefca4 ); +PROVIDE ( _data_start_phyrom = 0x3fcefce0 ); +PROVIDE ( _data_start_sip = 0x3fcee174 ); +PROVIDE ( _data_start_slc = 0x3fcee174 ); +PROVIDE ( _data_start_spi_flash = 0x3fcefba8 ); +PROVIDE ( _data_start_spi_slave = 0x3fcee130 ); +PROVIDE ( _data_start_uart = 0x3fcef34c ); +PROVIDE ( _data_start_usbdev = 0x3fcef044 ); +PROVIDE ( _data_start_xtos = 0x3fcee174 ); +PROVIDE ( dbg_sch_plan_act = 0x3fcef914 ); +PROVIDE ( dbg_sch_plan_move_id = 0x3fcef968 ); +PROVIDE ( dbg_state = 0x3fcef96a ); +PROVIDE ( dbg_trc_env = 0x3fcef970 ); +PROVIDE ( dbg_trc_tl_env = 0x3fcef978 ); +PROVIDE ( dbus_baseaddrs = 0x3ff0c4d4 ); +PROVIDE ( DebugE256PublicKey_x = 0x3ff081d8 ); +PROVIDE ( DebugE256PublicKey_y = 0x3ff081b8 ); +PROVIDE ( DebugE256SecretKey = 0x3ff08198 ); +PROVIDE ( _DebugExceptionVector = 0x40000280 ); +PROVIDE ( _DebugExceptionVector_text_end = 0x4000028b ); +PROVIDE ( _DebugExceptionVector_text_start = 0x40000280 ); +PROVIDE ( __default_global_locale = 0x3ff071c0 ); +PROVIDE ( dfu_class_handle_req = 0x4004c0c0 ); +PROVIDE ( dfu_config_descr = 0x3ff0c1fa ); +PROVIDE ( dfu_cpio_callback = 0x4004a34c ); +PROVIDE ( dfu_custom_handle_req = 0x4004c338 ); +PROVIDE ( dfu_flash_attach = 0x4004c804 ); +PROVIDE ( dfu_flash_deinit = 0x4004c784 ); +PROVIDE ( dfu_flash_erase = 0x4004c78c ); +PROVIDE ( dfu_flash_init = 0x4004c774 ); +PROVIDE ( dfu_flash_program = 0x4004c7a0 ); +PROVIDE ( dfu_flash_read = 0x4004c7f4 ); +PROVIDE ( dfu_status_cb = 0x4004c2e4 ); +PROVIDE ( dfu_updater_begin = 0x4004a594 ); +PROVIDE ( dfu_updater_clear_err = 0x4004a550 ); +PROVIDE ( dfu_updater_enable = 0x4004a568 ); +PROVIDE ( dfu_updater_end = 0x4004a640 ); +PROVIDE ( dfu_updater_feed = 0x4004a5f4 ); +PROVIDE ( dfu_updater_flash_read = 0x4004a728 ); +PROVIDE ( dfu_updater_get_err = 0x4004a53c ); +PROVIDE ( dfu_updater_set_raw_addr = 0x4004a714 ); +PROVIDE ( dfu_usb_descriptors = 0x3ff0c198 ); +PROVIDE ( dh_group14_generator = 0x3ff0adf0 ); +PROVIDE ( dh_group14_prime = 0x3ff0acf0 ); +PROVIDE ( dh_group15_generator = 0x3ff0acef ); +PROVIDE ( dh_group15_prime = 0x3ff0ab6f ); +PROVIDE ( dh_group16_generator = 0x3ff0ab6e ); +PROVIDE ( dh_group16_prime = 0x3ff0a96e ); +PROVIDE ( dh_group17_generator = 0x3ff0a96d ); +PROVIDE ( dh_group17_prime = 0x3ff0a66d ); +PROVIDE ( dh_group18_generator = 0x3ff0a66c ); +PROVIDE ( dh_group18_prime = 0x3ff0a26c ); +PROVIDE ( dh_group1_generator = 0x3ff0af93 ); +PROVIDE ( dh_group1_prime = 0x3ff0af33 ); +PROVIDE ( dh_group2_generator = 0x3ff0af32 ); +PROVIDE ( dh_group2_prime = 0x3ff0aeb2 ); +PROVIDE ( dh_group5_generator = 0x3ff0aeb1 ); +PROVIDE ( dh_group5_prime = 0x3ff0adf1 ); +PROVIDE ( disable_default_watchdog = 0x40044e20 ); +PROVIDE ( Disable_QMode = 0x4004d6d0 ); +PROVIDE ( div = 0x4003234c ); +PROVIDE ( __divdc3 = 0x40038b74 ); +PROVIDE ( __divdf3 = 0x4003c120 ); +PROVIDE ( __divdi3 = 0x40055bf0 ); +PROVIDE ( __divsc3 = 0x400388d4 ); +PROVIDE ( __divsf3 = 0x40055974 ); +PROVIDE ( __divsi3 = 0x400558c8 ); +PROVIDE ( dmadesc_rx = 0x3fcee150 ); +PROVIDE ( dmadesc_tx = 0x3fcee144 ); +PROVIDE ( _DoubleExceptionVector = 0x400003c0 ); +PROVIDE ( _DoubleExceptionVector_text_end = 0x400003c6 ); +PROVIDE ( _DoubleExceptionVector_text_start = 0x400003c0 ); +PROVIDE ( _dram0_0_start = 0x3fcd8000 ); +PROVIDE ( _dram0_rtos_reserved_start = 0x3fcef044 ); +PROVIDE ( dummy_len_plus = 0x3fcefc10 ); +PROVIDE ( ECC_4Win_Look_up_table = 0x3ff078b4 ); +PROVIDE ( ecc_env = 0x3fcef984 ); +PROVIDE ( ecc_Jacobian_InfinityPoint256 = 0x3ff08070 ); +PROVIDE ( em_base_reg_lut = 0x3ff08258 ); +PROVIDE ( Enable_QMode = 0x4004d680 ); +PROVIDE ( __eqdf2 = 0x40037d40 ); +PROVIDE ( __eqsf2 = 0x40037a0c ); +PROVIDE ( esp_crc8 = 0x40047854 ); +PROVIDE ( esp_flash_chip_driver_initialized = 0x4004e88c ); +PROVIDE ( esp_flash_erase_chip = 0x4004e998 ); +PROVIDE ( esp_flash_erase_region = 0x4004ea00 ); +PROVIDE ( esp_flash_get_chip_write_protect = 0x4004eb70 ); +PROVIDE ( esp_flash_get_io_mode = 0x4004efa4 ); +PROVIDE ( esp_flash_get_protectable_regions = 0x4004ec00 ); +PROVIDE ( esp_flash_get_protected_region = 0x4004ec4c ); +PROVIDE ( esp_flash_get_size = 0x4004e938 ); +PROVIDE ( esp_flash_read = 0x4004ed7c ); +PROVIDE ( esp_flash_read_chip_id = 0x4004e8a0 ); +PROVIDE ( esp_flash_read_encrypted = 0x4004ef80 ); +PROVIDE ( esp_flash_read_id = 0x4004e8e8 ); +PROVIDE ( esp_flash_set_chip_write_protect = 0x4004ebb8 ); +PROVIDE ( esp_flash_set_io_mode = 0x4004effc ); +PROVIDE ( esp_flash_set_protected_region = 0x4004ecd4 ); +PROVIDE ( esp_flash_write = 0x4004ee74 ); +PROVIDE ( esp_flash_write_encrypted = 0x4004ef48 ); +PROVIDE ( esp_handler = 0x3fcef46c ); +PROVIDE ( esp_rom_config_pad_power_select = 0x4004de78 ); +PROVIDE ( esp_rom_flash_ecc_init = 0x4004deac ); +PROVIDE ( esp_rom_opiflash_cache_mode_config = 0x4004d744 ); +PROVIDE ( esp_rom_opiflash_erase_area = 0x40051acc ); +PROVIDE ( esp_rom_opiflash_erase_block_64k = 0x40051a9c ); +PROVIDE ( esp_rom_opiflash_erase_sector = 0x40051a68 ); +PROVIDE ( esp_rom_opiflash_exec_cmd = 0x400515e0 ); +PROVIDE ( esp_rom_opiflash_exit_continuous_read_mode = 0x4005168c ); +PROVIDE ( esp_rom_opiflash_lock_acquire_cb = 0x3fcefca8 ); +PROVIDE ( esp_rom_opiflash_lock_release_cb = 0x3fcefca4 ); +PROVIDE ( esp_rom_opiflash_mode_reset = 0x40051734 ); +PROVIDE ( esp_rom_opiflash_pin_config = 0x40050f58 ); +PROVIDE ( esp_rom_opiflash_rdcr2 = 0x40051898 ); +PROVIDE ( esp_rom_opiflash_rdsr = 0x400517d8 ); +PROVIDE ( esp_rom_opiflash_read = 0x40051bd4 ); +PROVIDE ( esp_rom_opiflash_read_id = 0x40051760 ); +PROVIDE ( esp_rom_opiflash_set_mode = 0x40051d58 ); +PROVIDE ( esp_rom_opiflash_soft_reset = 0x400516c8 ); +PROVIDE ( esp_rom_opiflash_wait_idle = 0x4005182c ); +PROVIDE ( esp_rom_opiflash_wrcr2 = 0x40051904 ); +PROVIDE ( esp_rom_opiflash_write = 0x40051d0c ); +PROVIDE ( esp_rom_spi_cmd_config = 0x40051390 ); +PROVIDE ( esp_rom_spi_cmd_start = 0x400512bc ); +PROVIDE ( esp_rom_spi_flash_auto_sus_res = 0x4004e75c ); +PROVIDE ( esp_rom_spi_flash_auto_wait_idle = 0x4004e68c ); +PROVIDE ( esp_rom_spi_flash_send_resume = 0x4004e6e0 ); +PROVIDE ( esp_rom_spi_flash_update_id = 0x4004de64 ); +PROVIDE ( esp_rom_spi_reset_rw_mode = 0x40051084 ); +PROVIDE ( esp_rom_spi_set_dtr_swap_mode = 0x40051274 ); +PROVIDE ( esp_rom_spi_set_op_mode = 0x400510e8 ); +PROVIDE ( esp_vendor_cmd = 0x3fcef4c0 ); +PROVIDE ( _etext = 0x400568d0 ); +PROVIDE ( ets_aes_block = 0x40042ed0 ); +PROVIDE ( ets_aes_disable = 0x40042e30 ); +PROVIDE ( ets_aes_enable = 0x40042e04 ); +PROVIDE ( ets_aes_setkey = 0x40042e64 ); +PROVIDE ( ets_aes_setkey_dec = 0x40042eb0 ); +PROVIDE ( ets_aes_setkey_enc = 0x40042ea0 ); +PROVIDE ( ets_bigint_disable = 0x40043010 ); +PROVIDE ( ets_bigint_enable = 0x40042fc8 ); +PROVIDE ( ets_bigint_getz = 0x40043118 ); +PROVIDE ( ets_bigint_modexp = 0x400430d8 ); +PROVIDE ( ets_bigint_modmult = 0x400430b4 ); +PROVIDE ( ets_bigint_multiply = 0x40043050 ); +PROVIDE ( ets_bigint_wait_finish = 0x40043100 ); +PROVIDE ( ets_config_flash_by_image_hdr = 0x40046b10 ); +PROVIDE ( ets_delay_us = 0x40043148 ); +PROVIDE ( ets_ds_disable = 0x400431d0 ); +PROVIDE ( ets_ds_enable = 0x400431a4 ); +PROVIDE ( ets_ds_encrypt_params = 0x40043320 ); +PROVIDE ( ets_ds_finish_sign = 0x400432b8 ); +PROVIDE ( ets_ds_is_busy = 0x400431fc ); +PROVIDE ( ets_ds_start_sign = 0x4004322c ); +PROVIDE ( ets_ecc_flash_disable = 0x40054ef0 ); +PROVIDE ( ets_ecc_flash_disable_all = 0x40054f10 ); +PROVIDE ( ets_ecc_flash_enable = 0x40054eb4 ); +PROVIDE ( ets_ecc_flash_enable_all = 0x40054ed4 ); +PROVIDE ( ets_ecc_get_flash_byte_mode = 0x40054fc4 ); +PROVIDE ( ets_ecc_get_flash_page_size = 0x40054f30 ); +PROVIDE ( ets_ecc_get_flash_range = 0x40055008 ); +PROVIDE ( ets_ecc_get_sram_byte_mode = 0x4005514c ); +PROVIDE ( ets_ecc_get_sram_page_size = 0x400550a4 ); +PROVIDE ( ets_ecc_get_sram_range = 0x40055160 ); +PROVIDE ( ets_ecc_set_flash_byte_mode = 0x40054f90 ); +PROVIDE ( ets_ecc_set_flash_page_size = 0x40054f50 ); +PROVIDE ( ets_ecc_set_flash_range = 0x40054fd8 ); +PROVIDE ( ets_ecc_set_sram_byte_mode = 0x40055118 ); +PROVIDE ( ets_ecc_set_sram_page_size = 0x400550c0 ); +PROVIDE ( ets_ecc_set_sram_range = 0x40055180 ); +PROVIDE ( ets_ecc_sram_disable = 0x4005504c ); +PROVIDE ( ets_ecc_sram_disable_all = 0x40055088 ); +PROVIDE ( ets_ecc_sram_enable = 0x4005502c ); +PROVIDE ( ets_ecc_sram_enable_all = 0x4005506c ); +PROVIDE ( ets_efuse_cache_encryption_enabled = 0x40043cb8 ); +PROVIDE ( ets_efuse_clear_program_registers = 0x400436c0 ); +PROVIDE ( ets_efuse_count_unused_key_blocks = 0x40043884 ); +PROVIDE ( ets_efuse_download_modes_disabled = 0x40043b94 ); +PROVIDE ( ets_efuse_ecc_16to17_mode = 0x40043c68 ); +PROVIDE ( ets_efuse_ecc_en = 0x40043c78 ); +PROVIDE ( ets_efuse_ecc_flash_page_size = 0x40043c88 ); +PROVIDE ( ets_efuse_find_purpose = 0x400437e4 ); +PROVIDE ( ets_efuse_find_unused_key_block = 0x4004386c ); +PROVIDE ( ets_efuse_flash_octal_mode = 0x40043c48 ); +PROVIDE ( ets_efuse_flash_opi_5pads_power_sel_vddspi = 0x40043c38 ); +PROVIDE ( ets_efuse_force_send_resume = 0x40043c58 ); +PROVIDE ( ets_efuse_get_flash_delay_us = 0x40043cfc ); +PROVIDE ( ets_efuse_get_key_purpose = 0x40043770 ); +PROVIDE ( ets_efuse_get_mac = 0x40043d24 ); +PROVIDE ( ets_efuse_get_opiconfig = 0x40043ac8 ); +PROVIDE ( ets_efuse_get_read_register_address = 0x4004374c ); +PROVIDE ( ets_efuse_get_spiconfig = 0x40043a6c ); +PROVIDE ( ets_efuse_get_uart_print_channel = 0x40043bb4 ); +PROVIDE ( ets_efuse_get_uart_print_control = 0x40043ba4 ); +PROVIDE ( ets_efuse_get_wp_pad = 0x40043a10 ); +PROVIDE ( ets_efuse_jtag_disabled = 0x40043b5c ); +PROVIDE ( ets_efuse_key_block_unused = 0x40043810 ); +PROVIDE ( ets_efuse_legacy_spi_boot_mode_disabled = 0x40043cd8 ); +PROVIDE ( ets_efuse_program = 0x400436f4 ); +PROVIDE ( ets_efuse_read = 0x40043678 ); +PROVIDE ( ets_efuse_rs_calculate = 0x40043d58 ); +PROVIDE ( ets_efuse_secure_boot_aggressive_revoke_enabled = 0x40043ca8 ); +PROVIDE ( ets_efuse_secure_boot_enabled = 0x40043c98 ); +PROVIDE ( ets_efuse_security_download_modes_enabled = 0x40043bd4 ); +PROVIDE ( ets_efuse_set_timing = 0x40043648 ); +PROVIDE ( ets_efuse_usb_download_mode_disabled = 0x40043bf4 ); +PROVIDE ( ets_efuse_usb_force_nopersist = 0x40043c30 ); +PROVIDE ( ets_efuse_usb_module_disabled = 0x40043bc4 ); +PROVIDE ( ets_efuse_usb_use_ext_phy = 0x40043c20 ); +PROVIDE ( ets_efuse_write_key = 0x400438bc ); +PROVIDE ( ets_emsa_pss_verify = 0x40047554 ); +PROVIDE ( ets_get_apb_freq = 0x40046918 ); +PROVIDE ( ets_get_cpu_frequency = 0x40043170 ); +PROVIDE ( ets_get_printf_channel = 0x40045a28 ); +PROVIDE ( ets_get_stack_info = 0x40045118 ); +PROVIDE ( ets_get_xtal_div = 0x400468b8 ); +PROVIDE ( ets_get_xtal_freq = 0x400468f4 ); +PROVIDE ( ets_hmac_calculate_downstream = 0x400447b4 ); +PROVIDE ( ets_hmac_calculate_message = 0x400446b4 ); +PROVIDE ( ets_hmac_disable = 0x40044688 ); +PROVIDE ( ets_hmac_enable = 0x4004466c ); +PROVIDE ( ets_hmac_invalidate_downstream = 0x400447d4 ); +PROVIDE ( ets_install_lock = 0x40045980 ); +PROVIDE ( ets_install_putc1 = 0x40045990 ); +PROVIDE ( ets_install_putc2 = 0x400459b0 ); +PROVIDE ( ets_install_uart_printf = 0x400459a0 ); +PROVIDE ( ets_intr_count = 0x3fced910 ); +PROVIDE ( ets_intr_lock = 0x400447fc ); +PROVIDE ( ets_intr_unlock = 0x40044810 ); +PROVIDE ( ets_is_print_boot = 0x40044e50 ); +PROVIDE ( ets_isr_attach = 0x40044838 ); +PROVIDE ( ets_isr_mask = 0x40044848 ); +PROVIDE ( ets_isr_unmask = 0x40044854 ); +PROVIDE ( ets_jtag_enable_temporarily = 0x40043b14 ); +PROVIDE ( ets_loader_map_range = 0x40046a24 ); +PROVIDE ( ets_mgf1_sha256 = 0x400474ec ); +PROVIDE ( ets_printf = 0x400459c0 ); +PROVIDE ( ets_printf_lock = 0x3fcefcb4 ); +PROVIDE ( ets_printf_uart = 0x3fcefcac ); +PROVIDE ( ets_printf_unlock = 0x3fcefcb0 ); +PROVIDE ( ets_rsa_pss_verify = 0x40047660 ); +PROVIDE ( ets_run_flash_bootloader = 0x40046c38 ); +PROVIDE ( ets_secure_boot_read_key_digests = 0x40045da4 ); +PROVIDE ( ets_secure_boot_revoke_public_key_digest = 0x40045e54 ); +PROVIDE ( ets_secure_boot_verify_bootloader_with_keys = 0x400460a0 ); +PROVIDE ( ets_secure_boot_verify_signature = 0x40046024 ); +PROVIDE ( ets_secure_boot_verify_stage_bootloader = 0x4004637c ); +PROVIDE ( ets_set_appcpu_boot_addr = 0x40044e08 ); +PROVIDE ( ets_set_printf_channel = 0x40045a1c ); +PROVIDE ( ets_set_user_start = 0x40044df8 ); +PROVIDE ( ets_set_xtal_div = 0x400468d4 ); +PROVIDE ( ets_sha_clone = 0x40046618 ); +PROVIDE ( ets_sha_disable = 0x40046470 ); +PROVIDE ( ets_sha_enable = 0x40046444 ); +PROVIDE ( ets_sha_finish = 0x40046774 ); +PROVIDE ( ets_sha_get_state = 0x400465f0 ); +PROVIDE ( ets_sha_init = 0x4004649c ); +PROVIDE ( ets_sha_process = 0x40046644 ); +PROVIDE ( ets_sha_starts = 0x400464e4 ); +PROVIDE ( ets_sha_update = 0x400466b4 ); +PROVIDE ( ets_startup_callback = 0x3fced918 ); +PROVIDE ( ets_unpack_flash_code_legacy = 0x4004716c ); +PROVIDE ( ets_update_cpu_frequency = 0x40043164 ); +PROVIDE ( ets_vprintf = 0x4004551c ); +PROVIDE ( ets_waiti0 = 0x40044824 ); +PROVIDE ( ets_wdt_reset_cpu = 0x400551c0 ); +PROVIDE ( ets_write_char = 0x40045454 ); +PROVIDE ( ets_write_char_uart = 0x40045478 ); +PROVIDE ( event_empty = 0x3fcef5cc ); +PROVIDE ( _exit_r = 0x40054628 ); +PROVIDE ( __extendsfdf2 = 0x4003c400 ); +PROVIDE ( fclose = 0x40054e9c ); +PROVIDE ( _fclose_r = 0x40054da4 ); +PROVIDE ( fflush = 0x40033fd8 ); +PROVIDE ( _fflush_r = 0x40033f50 ); +PROVIDE ( __ffsdi2 = 0x40055b98 ); +PROVIDE ( __ffssi2 = 0x40055914 ); +PROVIDE ( FilePacketSendDeflatedReqMsgProc = 0x40048a2c ); +PROVIDE ( FilePacketSendReqMsgProc = 0x40048708 ); +PROVIDE ( fiprintf = 0x40032cdc ); +PROVIDE ( _fiprintf_r = 0x40032cac ); +PROVIDE ( __fixdfdi = 0x4003c290 ); +PROVIDE ( __fixdfsi = 0x4003c244 ); +PROVIDE ( fixed_tx_time = 0x3ff08d3c ); +PROVIDE ( __fixsfdi = 0x4003bc18 ); +PROVIDE ( __fixsfsi = 0x4003bbd8 ); +PROVIDE ( __fixunsdfsi = 0x4003c2fc ); +PROVIDE ( __fixunssfdi = 0x4003bcd0 ); +PROVIDE ( __fixunssfsi = 0x4003bc78 ); +PROVIDE ( flash2spiram_instruction_offset = 0x40052e14 ); +PROVIDE ( flash2spiram_rodata_offset = 0x40052e24 ); +PROVIDE ( flashchip = 0x3fcefbac ); +PROVIDE ( FlashDwnLdDeflatedStartMsgProc = 0x400489d4 ); +PROVIDE ( FlashDwnLdParamCfgMsgProc = 0x400487f0 ); +PROVIDE ( FlashDwnLdStartMsgProc = 0x400486a4 ); +PROVIDE ( FlashDwnLdStopDeflatedReqMsgProc = 0x40048b28 ); +PROVIDE ( FlashDwnLdStopReqMsgProc = 0x400487c0 ); +PROVIDE ( flash_instr_rodata_end_page = 0x40052e4c ); +PROVIDE ( flash_instr_rodata_start_page = 0x40052e30 ); +PROVIDE ( __floatdidf = 0x40055af4 ); +PROVIDE ( __floatdisf = 0x40055a2c ); +PROVIDE ( __floatsidf = 0x40055ab0 ); +PROVIDE ( __floatsisf = 0x400559dc ); +PROVIDE ( __floatundidf = 0x40055ae4 ); +PROVIDE ( __floatundisf = 0x40055a1c ); +PROVIDE ( __floatunsidf = 0x40055aa4 ); +PROVIDE ( __floatunsisf = 0x400559d0 ); +PROVIDE ( __fp_lock_all = 0x40054cbc ); +PROVIDE ( fprintf = 0x40032cdc ); +PROVIDE ( _fprintf_r = 0x40032cac ); +PROVIDE ( __fp_unlock_all = 0x40054cd4 ); +PROVIDE ( fputwc = 0x40033c40 ); +PROVIDE ( __fputwc = 0x40033b2c ); +PROVIDE ( _fputwc_r = 0x40033bc0 ); +PROVIDE ( free = 0x400547b8 ); +PROVIDE ( _free_r = 0x400544cc ); +PROVIDE ( _fstat_r = 0x400545cc ); +PROVIDE ( _fwalk = 0x40056670 ); +PROVIDE ( _fwalk_reent = 0x400566b0 ); +PROVIDE ( g_bt_plf_log_level = 0x3fcef394 ); +PROVIDE ( __gcc_bcmp = 0x40039100 ); +PROVIDE ( __gedf2 = 0x40037e00 ); +PROVIDE ( general_device_descr = 0x3fcef0b2 ); +PROVIDE ( _GeneralException = 0x40039758 ); +PROVIDE ( __gesf2 = 0x40037aa4 ); +PROVIDE ( get_id = 0x4004d0dc ); +PROVIDE ( _getpid_r = 0x400545fc ); +PROVIDE ( __getreent = 0x4005478c ); +PROVIDE ( GetSecurityInfoProc = 0x40048bf4 ); +PROVIDE ( _gettimeofday_r = 0x40054558 ); +PROVIDE ( GetUartDevice = 0x40049cb4 ); +PROVIDE ( g_flash_guard_ops = 0x3fcefc34 ); +PROVIDE ( _global_impure_ptr = 0x3fcefcdc ); +PROVIDE ( __global_locale_ptr = 0x3fcefccc ); +PROVIDE ( g_phyFuns = 0x3fcefce0 ); +PROVIDE ( g_phyFuns_instance = 0x3fcefce4 ); +PROVIDE ( gpio_bypass_matrix_in = 0x4005370c ); +PROVIDE ( gpio_input_get = 0x40053680 ); +PROVIDE ( gpio_input_get_high = 0x40053694 ); +PROVIDE ( gpio_matrix_in = 0x4005372c ); +PROVIDE ( gpio_matrix_out = 0x4005375c ); +PROVIDE ( gpio_output_disable = 0x400537dc ); +PROVIDE ( gpio_output_enable = 0x400537b0 ); +PROVIDE ( gpio_output_set = 0x4005361c ); +PROVIDE ( gpio_output_set_high = 0x40053654 ); +PROVIDE ( gpio_pad_hold = 0x40053950 ); +PROVIDE ( gpio_pad_input_disable = 0x400538ec ); +PROVIDE ( gpio_pad_input_enable = 0x400538c8 ); +PROVIDE ( gpio_pad_pulldown = 0x40053894 ); +PROVIDE ( gpio_pad_pullup = 0x40053860 ); +PROVIDE ( gpio_pad_select_gpio = 0x4005380c ); +PROVIDE ( gpio_pad_set_drv = 0x40053834 ); +PROVIDE ( gpio_pad_unhold = 0x40053918 ); +PROVIDE ( gpio_pin_wakeup_disable = 0x400536e0 ); +PROVIDE ( gpio_pin_wakeup_enable = 0x400536a8 ); +PROVIDE ( g_rw_controller_task_handle = 0x3fcef8b8 ); +PROVIDE ( g_rw_init_sem = 0x3fcef8c0 ); +PROVIDE ( g_rw_schd_queue = 0x3fcef8bc ); +PROVIDE ( g_shared_buffers = 0x3fcd8004 ); +PROVIDE ( __gtdf2 = 0x40037d74 ); +PROVIDE ( g_ticks_per_us = 0x3fcefcc0 ); +PROVIDE ( __gtsf2 = 0x40037a38 ); +PROVIDE ( hci_acl_data_handler = 0x4000ed70 ); +PROVIDE ( hci_cmd_desc_root_tab = 0x3ff08434 ); +PROVIDE ( hci_cmd_desc_tab_ctrl_bb = 0x3ff08974 ); +PROVIDE ( hci_cmd_desc_tab_info_par = 0x3ff08944 ); +PROVIDE ( hci_cmd_desc_tab_le = 0x3ff0859c ); +PROVIDE ( hci_cmd_desc_tab_lk_ctrl = 0x3ff089e0 ); +PROVIDE ( hci_cmd_desc_tab_stat_par = 0x3ff08938 ); +PROVIDE ( hci_cmd_desc_tab_vs = 0x3ff08464 ); +PROVIDE ( hci_cmd_desc_tab_vs_esp = 0x3fcef3c4 ); +PROVIDE ( hci_dbg_llcp_discard_cmd_handler = 0x4000c3a0 ); +PROVIDE ( hci_dbg_send_llcp_cmd_handler = 0x4000f934 ); +PROVIDE ( hci_disconnect_cmd_handler = 0x4000c824 ); +PROVIDE ( hci_env = 0x3fcef99d ); +PROVIDE ( hci_evt_dbg_desc_tab = 0x3ff083e4 ); +PROVIDE ( hci_evt_desc_tab = 0x3ff083ec ); +PROVIDE ( hci_evt_le_desc_tab = 0x3ff08344 ); +PROVIDE ( hci_evt_le_desc_tab_esp = 0x3ff0833c ); +PROVIDE ( hci_ext_host = 0x3fcef99c ); +PROVIDE ( hci_le_add_dev_to_per_adv_list_cmd_handler = 0x4002ca68 ); +PROVIDE ( hci_le_clear_adv_sets_cmd_handler = 0x40028e6c ); +PROVIDE ( hci_le_clear_per_adv_list_cmd_handler = 0x4002cc74 ); +PROVIDE ( hci_le_con_upd_cmd_handler = 0x4000bbb8 ); +PROVIDE ( hci_le_create_con_cancel_cmd_handler = 0x4002b060 ); +PROVIDE ( hci_le_create_con_cmd_handler = 0x4002a914 ); +PROVIDE ( hci_le_ext_create_con_cmd_handler = 0x4002ac78 ); +PROVIDE ( hci_le_ltk_req_neg_reply_cmd_handler = 0x4000e278 ); +PROVIDE ( hci_le_ltk_req_reply_cmd_handler = 0x4000e1d8 ); +PROVIDE ( hci_le_per_adv_create_sync_cancel_cmd_handler = 0x4002c87c ); +PROVIDE ( hci_le_per_adv_create_sync_cmd_handler = 0x4002c710 ); +PROVIDE ( hci_le_per_adv_term_sync_cmd_handler = 0x4002c9dc ); +PROVIDE ( hci_le_rd_adv_ch_tx_pw_cmd_handler = 0x40026f30 ); +PROVIDE ( hci_le_rd_chnl_map_cmd_handler = 0x4000aaa4 ); +PROVIDE ( hci_le_rd_max_adv_data_len_cmd_handler = 0x40028d04 ); +PROVIDE ( hci_le_rd_nb_supp_adv_sets_cmd_handler = 0x40028d4c ); +PROVIDE ( hci_le_rd_per_adv_list_size_cmd_handler = 0x4002cd08 ); +PROVIDE ( hci_le_rd_phy_cmd_handler = 0x40010eb0 ); +PROVIDE ( hci_le_rd_rem_feats_cmd_handler = 0x4000e8f8 ); +PROVIDE ( hci_le_rem_con_param_req_neg_reply_cmd_handler = 0x4000bdd0 ); +PROVIDE ( hci_le_rem_con_param_req_reply_cmd_handler = 0x4000bd20 ); +PROVIDE ( hci_le_rmv_adv_set_cmd_handler = 0x40028dd0 ); +PROVIDE ( hci_le_rmv_dev_from_per_adv_list_cmd_handler = 0x4002cb7c ); +PROVIDE ( hci_le_set_adv_data_cmd_handler = 0x400271c0 ); +PROVIDE ( hci_le_set_adv_en_cmd_handler = 0x400273c8 ); +PROVIDE ( hci_le_set_adv_param_cmd_handler = 0x40026f94 ); +PROVIDE ( hci_le_set_adv_set_rand_addr_cmd_handler = 0x40027970 ); +PROVIDE ( hci_le_set_data_len_cmd_handler = 0x4000cf90 ); +PROVIDE ( hci_le_set_ext_adv_data_cmd_handler = 0x40027a2c ); +PROVIDE ( hci_le_set_ext_adv_en_cmd_handler = 0x40028038 ); +PROVIDE ( hci_le_set_ext_adv_param_cmd_handler = 0x4002768c ); +PROVIDE ( hci_le_set_ext_scan_en_cmd_handler = 0x4002c368 ); +PROVIDE ( hci_le_set_ext_scan_param_cmd_handler = 0x4002c1f0 ); +PROVIDE ( hci_le_set_ext_scan_rsp_data_cmd_handler = 0x40027d44 ); +PROVIDE ( hci_le_set_per_adv_data_cmd_handler = 0x40028844 ); +PROVIDE ( hci_le_set_per_adv_en_cmd_handler = 0x40028a88 ); +PROVIDE ( hci_le_set_per_adv_param_cmd_handler = 0x400286bc ); +PROVIDE ( hci_le_set_phy_cmd_handler = 0x40010f1c ); +PROVIDE ( hci_le_set_scan_en_cmd_handler = 0x4002bf34 ); +PROVIDE ( hci_le_set_scan_param_cmd_handler = 0x4002bda0 ); +PROVIDE ( hci_le_set_scan_rsp_data_cmd_handler = 0x400272c4 ); +PROVIDE ( hci_le_start_enc_cmd_handler = 0x4000e0dc ); +PROVIDE ( hci_rd_auth_payl_to_cmd_handler = 0x4000f0ec ); +PROVIDE ( hci_rd_rem_ver_info_cmd_handler = 0x4001157c ); +PROVIDE ( hci_rd_rssi_cmd_handler = 0x4000eb18 ); +PROVIDE ( hci_rd_tx_pwr_lvl_cmd_handler = 0x4000ea74 ); +PROVIDE ( hci_tl_env = 0x3fcef9c0 ); +PROVIDE ( hci_vs_set_pref_slave_evt_dur_cmd_handler = 0x4000ec04 ); +PROVIDE ( hci_vs_set_pref_slave_latency_cmd_handler = 0x4000ebb0 ); +PROVIDE ( hci_wr_auth_payl_to_cmd_handler = 0x4000f158 ); +PROVIDE ( hmac_md5 = 0x400378cc ); +PROVIDE ( hmac_md5_vector = 0x400377d4 ); +PROVIDE ( ibus_baseaddrs = 0x3ff0c4d8 ); +PROVIDE ( intr_matrix_set = 0x40044868 ); +PROVIDE ( _iram0_text_end = 0x4000056c ); +PROVIDE ( _iram0_text_start = 0x4000056c ); +PROVIDE ( _iram1_text_end = 0x60021100 ); +PROVIDE ( _iram1_text_start = 0x60021100 ); +PROVIDE ( isalnum = 0x40039d94 ); +PROVIDE ( isalpha = 0x40039da4 ); +PROVIDE ( isascii = 0x4005546c ); +PROVIDE ( _isatty_r = 0x40039d5c ); +PROVIDE ( isblank = 0x40039db4 ); +PROVIDE ( iscntrl = 0x40039dd4 ); +PROVIDE ( isdigit = 0x40039dec ); +PROVIDE ( isgraph = 0x40039e24 ); +PROVIDE ( islower = 0x40039e04 ); +PROVIDE ( isprint = 0x40039e3c ); +PROVIDE ( ispunct = 0x40039e50 ); +PROVIDE ( isspace = 0x40039e68 ); +PROVIDE ( isupper = 0x40039e80 ); +PROVIDE ( itoa = 0x40032974 ); +PROVIDE ( __itoa = 0x40032938 ); +PROVIDE ( jd_decomp = 0x40047e30 ); +PROVIDE ( jd_prepare = 0x400479e0 ); +PROVIDE ( jtag_appcpu_reset = 0x3fcefcc4 ); +PROVIDE ( jtag_cpu_reset_happened = 0x40045a78 ); +PROVIDE ( jtag_procpu_reset = 0x3fcefcc5 ); +PROVIDE ( ke_env = 0x3fcefa04 ); +PROVIDE ( _KernelExceptionVector = 0x40000300 ); +PROVIDE ( _KernelExceptionVector_text_end = 0x40000306 ); +PROVIDE ( _KernelExceptionVector_text_start = 0x40000300 ); +PROVIDE ( _kill_r = 0x40054610 ); +PROVIDE ( labs = 0x40032370 ); +PROVIDE ( ldiv = 0x40032378 ); +PROVIDE ( __ledf2 = 0x40037d9c ); +PROVIDE ( __lesf2 = 0x40037a58 ); +PROVIDE ( _Level2FromVector = 0x400398cc ); +PROVIDE ( _Level2HandlerLabel = 0x00000000 ); +PROVIDE ( _Level2InterruptVector_text_end = 0x40000186 ); +PROVIDE ( _Level2InterruptVector_text_start = 0x40000180 ); +PROVIDE ( _Level2Vector = 0x40000180 ); +PROVIDE ( _Level3FromVector = 0x4003999c ); +PROVIDE ( _Level3HandlerLabel = 0x00000000 ); +PROVIDE ( _Level3InterruptVector_text_end = 0x400001c6 ); +PROVIDE ( _Level3InterruptVector_text_start = 0x400001c0 ); +PROVIDE ( _Level3Vector = 0x400001c0 ); +PROVIDE ( _Level4FromVector = 0x40039a68 ); +PROVIDE ( _Level4HandlerLabel = 0x00000000 ); +PROVIDE ( _Level4InterruptVector_text_end = 0x40000206 ); +PROVIDE ( _Level4InterruptVector_text_start = 0x40000200 ); +PROVIDE ( _Level4Vector = 0x40000200 ); +PROVIDE ( _Level5FromVector = 0x40039bd8 ); +PROVIDE ( _Level5HandlerLabel = 0x00000000 ); +PROVIDE ( _Level5InterruptVector_text_end = 0x40000246 ); +PROVIDE ( _Level5InterruptVector_text_start = 0x40000240 ); +PROVIDE ( _Level5Vector = 0x40000240 ); +PROVIDE ( _LevelOneInterrupt = 0x400397ae ); +PROVIDE ( _link_r = 0x4005459c ); +PROVIDE ( _lit4_end = 0x4000056c ); +PROVIDE ( _lit4_start = 0x4000056c ); +PROVIDE ( llc_auth_payl_nearly_to_handler = 0x4000f234 ); +PROVIDE ( llc_auth_payl_real_to_handler = 0x4000f2b0 ); +PROVIDE ( llc_encrypt_ind_handler = 0x4000e344 ); +PROVIDE ( llc_env = 0x3fcefa64 ); +PROVIDE ( ll_channel_map_ind_handler = 0x4000a934 ); +PROVIDE ( llc_hci_command_handler_wrapper = 0x4000ed44 ); +PROVIDE ( llc_ll_connection_param_req_pdu_send = 0x4000ae9c ); +PROVIDE ( llc_ll_connection_param_rsp_pdu_send = 0x4000b220 ); +PROVIDE ( llc_ll_connection_update_ind_pdu_send = 0x4000ae58 ); +PROVIDE ( llc_llcp_ch_map_update_ind_pdu_send = 0x4000a718 ); +PROVIDE ( llc_llcp_phy_upd_ind_pdu_send = 0x40010584 ); +PROVIDE ( llc_llcp_version_ind_pdu_send = 0x400112cc ); +PROVIDE ( llc_ll_enc_req_pdu_send = 0x4000d2b0 ); +PROVIDE ( llc_ll_enc_rsp_pdu_send = 0x4000d304 ); +PROVIDE ( llc_ll_feature_req_pdu_send = 0x4000e574 ); +PROVIDE ( llc_ll_feature_rsp_pdu_send = 0x4000e5cc ); +PROVIDE ( llc_ll_length_req_pdu_send = 0x4000c99c ); +PROVIDE ( llc_ll_length_rsp_pdu_send = 0x4000c9c8 ); +PROVIDE ( llc_ll_pause_enc_req_pdu_send = 0x4000d270 ); +PROVIDE ( llc_ll_pause_enc_rsp_pdu_send = 0x4000d290 ); +PROVIDE ( llc_ll_phy_req_pdu_send = 0x40010268 ); +PROVIDE ( llc_ll_phy_rsp_pdu_send = 0x40010290 ); +PROVIDE ( llc_ll_ping_req_pdu_send = 0x4000efc4 ); +PROVIDE ( llc_ll_ping_rsp_pdu_send = 0x4000f088 ); +PROVIDE ( llc_ll_start_enc_req_pdu_send = 0x4000d348 ); +PROVIDE ( llc_ll_start_enc_rsp_pdu_send = 0x4000d368 ); +PROVIDE ( llc_ll_terminate_ind_pdu_send = 0x4000c444 ); +PROVIDE ( llc_ll_unknown_rsp_pdu_send = 0x4000f460 ); +PROVIDE ( ll_connection_param_req_handler = 0x4000b9ec ); +PROVIDE ( ll_connection_param_rsp_handler = 0x4000bb0c ); +PROVIDE ( ll_connection_update_ind_handler = 0x4000b850 ); +PROVIDE ( llc_op_ch_map_upd_ind_handler = 0x4000ab10 ); +PROVIDE ( llc_op_con_upd_ind_handler = 0x4000be4c ); +PROVIDE ( llc_op_disconnect_ind_handler = 0x4000c744 ); +PROVIDE ( llc_op_dl_upd_ind_handler = 0x4000d0c8 ); +PROVIDE ( llc_op_encrypt_ind_handler = 0x4000e4e8 ); +PROVIDE ( llc_op_feats_exch_ind_handler = 0x4000e9dc ); +PROVIDE ( llc_op_le_ping_ind_handler = 0x4000f1c4 ); +PROVIDE ( llc_op_phy_upd_ind_handler = 0x400110d4 ); +PROVIDE ( llc_op_ver_exch_ind_handler = 0x4001147c ); +PROVIDE ( llc_stopped_ind_handler = 0x4000c6e8 ); +PROVIDE ( lld_acl_rx_ind_handler = 0x4000ee78 ); +PROVIDE ( lld_acl_tx_cfm_handler = 0x4000ef4c ); +PROVIDE ( lld_adv_end_ind_handler = 0x40028fd4 ); +PROVIDE ( lld_adv_rep_ind_handler = 0x4002cfb0 ); +PROVIDE ( lld_ch_map_upd_cfm_handler = 0x4000ac18 ); +PROVIDE ( lld_con_estab_ind_handler = 0x4000c048 ); +PROVIDE ( lld_con_evt_sd_evt_time_set = 0x4001aa08 ); +PROVIDE ( lld_con_offset_upd_ind_handler = 0x4000c100 ); +PROVIDE ( lld_con_param_upd_cfm_handler = 0x4000bf50 ); +PROVIDE ( lld_disc_ind_handler = 0x4000c608 ); +PROVIDE ( lldesc_build_chain = 0x4003c774 ); +PROVIDE ( lldesc_num2link = 0x4003c864 ); +PROVIDE ( lldesc_set_owner = 0x4003c890 ); +PROVIDE ( lldesc_setup = 0x400543c8 ); +PROVIDE ( lld_exp_sync_pos_tab = 0x3fcefa90 ); +PROVIDE ( lld_init_end_ind_handler = 0x4002b140 ); +PROVIDE ( lld_init_max_aux_dur_tab = 0x3ff08d54 ); +PROVIDE ( lld_llcp_rx_ind_handler_wrapper = 0x4000f88c ); +PROVIDE ( lld_llcp_tx_cfm_handler = 0x4000f8ac ); +PROVIDE ( lld_per_adv_end_ind_handler = 0x40029710 ); +PROVIDE ( lld_per_adv_rep_ind_handler = 0x4002d5e4 ); +PROVIDE ( lld_per_adv_rx_end_ind_handler = 0x4002d9c0 ); +PROVIDE ( lld_phy_coded_500k_get = 0x4001d76c ); +PROVIDE ( lld_phy_upd_cfm_handler = 0x400111cc ); +PROVIDE ( lld_rpa_renew_env = 0x3fcefa8c ); +PROVIDE ( lld_scan_end_ind_handler = 0x4002dbc4 ); +PROVIDE ( lld_scan_map_legacy_pdu_to_evt_type = 0x3ff08d64 ); +PROVIDE ( lld_scan_max_aux_dur_tab = 0x3ff08d6c ); +PROVIDE ( lld_scan_req_ind_handler = 0x40028f2c ); +PROVIDE ( lld_sync_env = 0x3fcefaa0 ); +PROVIDE ( lld_sync_max_aux_dur_tab = 0x3ff08d74 ); +PROVIDE ( lld_sync_start_req_handler = 0x4002d4d0 ); +PROVIDE ( lld_test_end_ind_handler = 0x4002ddb8 ); +PROVIDE ( lld_update_rxbuf_handler = 0x4001e69c ); +PROVIDE ( ll_enc_req_handler = 0x4000de54 ); +PROVIDE ( ll_enc_rsp_handler = 0x4000df64 ); +PROVIDE ( ll_feature_req_handler = 0x4000e7d4 ); +PROVIDE ( ll_feature_rsp_handler = 0x4000e884 ); +PROVIDE ( ll_length_req_handler = 0x4000ce78 ); +PROVIDE ( ll_length_rsp_handler = 0x4000cefc ); +PROVIDE ( LLM_AA_CT1 = 0x3ff08d61 ); +PROVIDE ( LLM_AA_CT2 = 0x3ff08d5f ); +PROVIDE ( llm_ch_map_update_ind_handler = 0x4000ab84 ); +PROVIDE ( llm_hci_command_handler_wrapper = 0x4002a8e8 ); +PROVIDE ( ll_min_used_channels_ind_handler = 0x4000aa08 ); +PROVIDE ( llm_scan_period_to_handler = 0x4002cedc ); +PROVIDE ( ll_pause_enc_req_handler = 0x4000dd50 ); +PROVIDE ( ll_pause_enc_rsp_handler = 0x4000dddc ); +PROVIDE ( ll_phy_req_handler = 0x40010c70 ); +PROVIDE ( ll_phy_rsp_handler = 0x40010d50 ); +PROVIDE ( ll_phy_update_ind_handler = 0x40010de8 ); +PROVIDE ( ll_ping_req_handler = 0x4000f0a8 ); +PROVIDE ( ll_ping_rsp_handler = 0x4000f0b8 ); +PROVIDE ( ll_slave_feature_req_handler = 0x4000e82c ); +PROVIDE ( ll_start_enc_req_handler = 0x4000e004 ); +PROVIDE ( ll_start_enc_rsp_handler = 0x4000e070 ); +PROVIDE ( ll_terminate_ind_handler = 0x4000c5b4 ); +PROVIDE ( ll_version_ind_handler = 0x4001150c ); +PROVIDE ( __locale_ctype_ptr = 0x40034050 ); +PROVIDE ( __locale_ctype_ptr_l = 0x40034048 ); +PROVIDE ( __locale_mb_cur_max = 0x40034030 ); +PROVIDE ( _lock_acquire = 0x40054714 ); +PROVIDE ( _lock_acquire_recursive = 0x40054728 ); +PROVIDE ( _lock_close = 0x400546ec ); +PROVIDE ( _lock_close_recursive = 0x40054700 ); +PROVIDE ( _lock_init = 0x400546c4 ); +PROVIDE ( _lock_init_recursive = 0x400546d8 ); +PROVIDE ( _lock_release = 0x40054764 ); +PROVIDE ( _lock_release_recursive = 0x40054778 ); +PROVIDE ( _lock_try_acquire = 0x4005473c ); +PROVIDE ( _lock_try_acquire_recursive = 0x40054750 ); +PROVIDE ( longjmp = 0x400322d0 ); +PROVIDE ( _lseek_r = 0x4005468c ); +PROVIDE ( __lshrdi3 = 0x4005595c ); +PROVIDE ( __ltdf2 = 0x40037e28 ); +PROVIDE ( __ltsf2 = 0x40037ac4 ); +PROVIDE ( mac_addr_to_serial_str_desc = 0x4004b6f8 ); +PROVIDE ( main = 0x40045170 ); +PROVIDE ( malloc = 0x400547a0 ); +PROVIDE ( _malloc_r = 0x400544b4 ); +PROVIDE ( max_data_tx_time = 0x3ff08d34 ); +PROVIDE ( maxSecretKey_256 = 0x3ff081f8 ); +PROVIDE ( _mbtowc_r = 0x40039e9c ); +PROVIDE ( MD5Final = 0x40037740 ); +PROVIDE ( MD5Init = 0x400376a0 ); +PROVIDE ( MD5Update = 0x400376c0 ); +PROVIDE ( md5_vector = 0x400377a8 ); +PROVIDE ( memccpy = 0x40039ee8 ); +PROVIDE ( memchr = 0x40039f5c ); +PROVIDE ( memcmp = 0x40055480 ); +PROVIDE ( memcpy = 0x40055528 ); +PROVIDE ( MemDwnLdStartMsgProc = 0x4004881c ); +PROVIDE ( MemDwnLdStopReqMsgProc = 0x400488b0 ); +PROVIDE ( _memmap_cacheattr_bp_allvalid = 0x22222222 ); +PROVIDE ( _memmap_cacheattr_bp_base = 0x00000220 ); +PROVIDE ( _memmap_cacheattr_bp_strict = 0xfffff22f ); +PROVIDE ( _memmap_cacheattr_bp_trapnull = 0x2222222f ); +PROVIDE ( _memmap_cacheattr_reset = 0x2222211f ); +PROVIDE ( _memmap_cacheattr_unused_mask = 0xfffff00f ); +PROVIDE ( _memmap_cacheattr_wb_allvalid = 0x22222112 ); +PROVIDE ( _memmap_cacheattr_wba_trapnull = 0x2222211f ); +PROVIDE ( _memmap_cacheattr_wb_base = 0x00000110 ); +PROVIDE ( _memmap_cacheattr_wbna_trapnull = 0x2222211f ); +PROVIDE ( _memmap_cacheattr_wb_strict = 0xfffff11f ); +PROVIDE ( _memmap_cacheattr_wb_trapnull = 0x2222211f ); +PROVIDE ( _memmap_cacheattr_wt_allvalid = 0x22222112 ); +PROVIDE ( _memmap_cacheattr_wt_base = 0x00000110 ); +PROVIDE ( _memmap_cacheattr_wt_strict = 0xfffff11f ); +PROVIDE ( _memmap_cacheattr_wt_trapnull = 0x2222211f ); +PROVIDE ( _memmap_vecbase_reset = 0x40000000 ); +PROVIDE ( memmove = 0x40055620 ); +PROVIDE ( MemPacketSendReqMsgProc = 0x4004884c ); +PROVIDE ( memrchr = 0x40039ff8 ); +PROVIDE ( memset = 0x40055710 ); +PROVIDE ( memspi_host_erase_block = 0x4004ca10 ); +PROVIDE ( memspi_host_erase_chip = 0x4004c9c8 ); +PROVIDE ( memspi_host_erase_sector = 0x4004c9e8 ); +PROVIDE ( memspi_host_flush_cache = 0x4004c9ac ); +PROVIDE ( memspi_host_program_page = 0x4004ca38 ); +PROVIDE ( memspi_host_read = 0x4004ca64 ); +PROVIDE ( memspi_host_read_data_slicer = 0x4004cae8 ); +PROVIDE ( memspi_host_read_id_hs = 0x4004c90c ); +PROVIDE ( memspi_host_read_status_hs = 0x4004c974 ); +PROVIDE ( memspi_host_set_write_protect = 0x4004ca90 ); +PROVIDE ( memspi_host_write_data_slicer = 0x4004cab8 ); +PROVIDE ( __moddi3 = 0x40055eb8 ); +PROVIDE ( __modsi3 = 0x400558d0 ); +PROVIDE ( __muldc3 = 0x4003829c ); +PROVIDE ( __muldf3 = 0x40037c24 ); +PROVIDE ( __muldi3 = 0x40055b68 ); +PROVIDE ( __mulsc3 = 0x40037fd8 ); +PROVIDE ( __mulsf3 = 0x40037960 ); +PROVIDE ( __mulsi3 = 0x400558c0 ); +PROVIDE ( multofup = 0x40056664 ); +PROVIDE ( __mulvdi3 = 0x4003c548 ); +PROVIDE ( __mulvsi3 = 0x4003c530 ); +PROVIDE ( must_reset = 0x3fcef34c ); +PROVIDE ( mz_adler32 = 0x400352c4 ); +PROVIDE ( mz_crc32 = 0x4003538c ); +PROVIDE ( mz_free = 0x400353d8 ); +PROVIDE ( __nedf2 = 0x40037d40 ); +PROVIDE ( __negdf2 = 0x40037b38 ); +PROVIDE ( __negdi2 = 0x40055b80 ); +PROVIDE ( __negsf2 = 0x4003b9c8 ); +PROVIDE ( __negvdi2 = 0x4003c664 ); +PROVIDE ( __negvsi2 = 0x4003c644 ); +PROVIDE ( __nesf2 = 0x40037a0c ); +PROVIDE ( _NMIExceptionVector = 0x400002c0 ); +PROVIDE ( _NMIExceptionVector_text_end = 0x400002c3 ); +PROVIDE ( _NMIExceptionVector_text_start = 0x400002c0 ); +PROVIDE ( __nsau_data = 0x3ff07430 ); +PROVIDE ( one_bits = 0x3ff07802 ); +PROVIDE ( open = 0x4003b900 ); +PROVIDE ( _open_r = 0x40054654 ); +PROVIDE ( opi_flash_conf_cmd = 0x400515a0 ); +PROVIDE ( opi_flash_cpu_read = 0x40051b4c ); +PROVIDE ( opi_flash_erase_internal = 0x40051a04 ); +PROVIDE ( opi_flash_page_program_internal = 0x40051c18 ); +PROVIDE ( opi_flash_set_lock_func = 0x40051590 ); +PROVIDE ( _opi_flash_wren = 0x40051844 ); +PROVIDE ( opi_flash_wren = 0x40051874 ); +PROVIDE ( _opi_flash_write = 0x40051c98 ); +PROVIDE ( __packed = 0x3fcef344 ); +PROVIDE ( __paritysi2 = 0x4003c730 ); +PROVIDE ( _PathLocale = 0x3fcefcd0 ); +PROVIDE ( p_ble_util_buf_env = 0x3fcef8e0 ); +PROVIDE ( p_dbg_trc_mem_env = 0x3fcef96c ); +PROVIDE ( phy_get_romfuncs = 0x4003edd0 ); +PROVIDE ( p_lld_env = 0x3fcefa98 ); +PROVIDE ( p_llm_env = 0x3fcefac8 ); +PROVIDE ( __popcountdi2 = 0x4003c6d8 ); +PROVIDE ( __popcountsi2 = 0x4003c6a0 ); +PROVIDE ( __popcount_tab = 0x3ff07430 ); +PROVIDE ( __powidf2 = 0x40037f74 ); +PROVIDE ( __powisf2 = 0x40037f34 ); +PROVIDE ( _Pri_4_HandlerAddress = 0x3fcee37c ); +PROVIDE ( _Pri_5_HandlerAddress = 0x3fcee380 ); +PROVIDE ( _printf_common = 0x40033114 ); +PROVIDE ( _printf_float = 0x400547fc ); +PROVIDE ( _printf_i = 0x40033214 ); +PROVIDE ( print_other_reset_reason = 0x400450e4 ); +PROVIDE ( privacy_en = 0x3fcef3f4 ); +PROVIDE ( pthread_setcancelstate = 0x40054498 ); +PROVIDE ( _putc1 = 0x3fcefcbc ); +PROVIDE ( _putc2 = 0x3fcefcb8 ); +PROVIDE ( qsort = 0x4003239c ); +PROVIDE ( r_Add2SelfBigHex256 = 0x400041e0 ); +PROVIDE ( r_AddBigHex256 = 0x40004128 ); +PROVIDE ( r_AddBigHexModP256 = 0x4000417c ); +PROVIDE ( r_AddP256 = 0x400042c4 ); +PROVIDE ( r_AddPdiv2_256 = 0x400042f4 ); +PROVIDE ( r_aes_alloc = 0x40000e78 ); +PROVIDE ( r_aes_ccm_continue = 0x400005e0 ); +PROVIDE ( r_aes_ccm_process_e = 0x400006f8 ); +PROVIDE ( r_aes_ccm_xor_128_lsb = 0x4000056c ); +PROVIDE ( r_aes_ccm_xor_128_msb = 0x400005a4 ); +PROVIDE ( r_aes_cmac_continue = 0x400009b8 ); +PROVIDE ( r_aes_cmac_start = 0x4000097c ); +PROVIDE ( r_aes_k1_continue = 0x40000b20 ); +PROVIDE ( r_aes_k2_continue = 0x40000ba8 ); +PROVIDE ( r_aes_k3_continue = 0x40000d1c ); +PROVIDE ( r_aes_k4_continue = 0x40000da0 ); +PROVIDE ( r_aes_shift_left_128 = 0x40001000 ); +PROVIDE ( r_aes_start = 0x40000e98 ); +PROVIDE ( r_aes_xor_128 = 0x40000fd8 ); +PROVIDE ( _raise_r = 0x40054570 ); +PROVIDE ( rand = 0x4003a0e4 ); +PROVIDE ( rand_r = 0x4003a170 ); +PROVIDE ( r_assert_err = 0x4000106c ); +PROVIDE ( r_assert_param = 0x400010b8 ); +PROVIDE ( r_assert_warn = 0x40001104 ); +PROVIDE ( r_bigHexInversion256 = 0x40005248 ); +PROVIDE ( r_ble_sw_cca_check_isr = 0x4002ebb8 ); +PROVIDE ( r_ble_util_buf_acl_tx_alloc = 0x400015c4 ); +PROVIDE ( r_ble_util_buf_acl_tx_elt_get = 0x40001668 ); +PROVIDE ( r_ble_util_buf_acl_tx_free = 0x400016a4 ); +PROVIDE ( r_ble_util_buf_acl_tx_free_in_isr = 0x40001734 ); +PROVIDE ( r_ble_util_buf_adv_tx_alloc = 0x400017b4 ); +PROVIDE ( r_ble_util_buf_adv_tx_free = 0x40001828 ); +PROVIDE ( r_ble_util_buf_adv_tx_free_in_isr = 0x40001894 ); +PROVIDE ( r_ble_util_buf_env_deinit = 0x40001260 ); +PROVIDE ( r_ble_util_buf_env_init = 0x40001240 ); +PROVIDE ( r_ble_util_buf_get_rx_buf_nb = 0x40001280 ); +PROVIDE ( r_ble_util_buf_get_rx_buf_size = 0x40001290 ); +PROVIDE ( r_ble_util_buf_llcp_tx_alloc = 0x40001308 ); +PROVIDE ( r_ble_util_buf_llcp_tx_free = 0x40001334 ); +PROVIDE ( r_ble_util_buf_rx_alloc = 0x40001420 ); +PROVIDE ( r_ble_util_buf_rx_alloc_in_isr = 0x40001508 ); +PROVIDE ( r_ble_util_buf_rx_free = 0x40001480 ); +PROVIDE ( r_ble_util_buf_rx_free_in_isr = 0x40001564 ); +PROVIDE ( r_ble_util_buf_set_rx_buf_nb = 0x400012a8 ); +PROVIDE ( r_ble_util_buf_set_rx_buf_size = 0x400012dc ); +PROVIDE ( r_ble_util_data_rx_buf_reset = 0x400013a0 ); +PROVIDE ( r_bt_bb_get_intr_mask = 0x400093e8 ); +PROVIDE ( r_bt_bb_intr_clear = 0x400093d8 ); +PROVIDE ( r_bt_bb_intr_mask_set = 0x400093c4 ); +PROVIDE ( r_bt_bb_isr = 0x4000940c ); +PROVIDE ( r_btdm_isr = 0x4000948c ); +PROVIDE ( r_btdm_task_post = 0x40031f44 ); +PROVIDE ( r_btdm_task_post_from_isr = 0x40031f00 ); +PROVIDE ( r_btdm_task_recycle = 0x40031fc0 ); +PROVIDE ( r_bt_rf_coex_cfg_set = 0x4002e4f4 ); +PROVIDE ( r_bt_rf_coex_conn_dynamic_pti_en_get = 0x4002e57c ); +PROVIDE ( r_bt_rf_coex_conn_phy_coded_data_time_limit_en_get = 0x4002e60c ); +PROVIDE ( r_bt_rf_coex_ext_adv_dynamic_pti_en_get = 0x4002e5d4 ); +PROVIDE ( r_bt_rf_coex_ext_scan_dynamic_pti_en_get = 0x4002e598 ); +PROVIDE ( r_bt_rf_coex_legacy_adv_dynamic_pti_en_get = 0x4002e560 ); +PROVIDE ( r_bt_rf_coex_per_adv_dynamic_pti_en_get = 0x4002e5f0 ); +PROVIDE ( r_bt_rf_coex_pti_table_get = 0x4002e62c ); +PROVIDE ( r_bt_rf_coex_st_param_get = 0x4002e544 ); +PROVIDE ( r_bt_rf_coex_st_param_set = 0x4002e520 ); +PROVIDE ( r_bt_rf_coex_sync_scan_dynamic_pti_en_get = 0x4002e5b4 ); +PROVIDE ( r_bt_rma_apply_rule_cs_fmt = 0x4002e840 ); +PROVIDE ( r_bt_rma_apply_rule_cs_idx = 0x4002e910 ); +PROVIDE ( r_bt_rma_configure = 0x4002e764 ); +PROVIDE ( r_bt_rma_deregister_rule_cs_fmt = 0x4002e7f8 ); +PROVIDE ( r_bt_rma_deregister_rule_cs_idx = 0x4002e8d4 ); +PROVIDE ( r_bt_rma_get_ant_by_act = 0x4002e948 ); +PROVIDE ( r_bt_rma_init = 0x4002e74c ); +PROVIDE ( r_bt_rma_register_rule_cs_fmt = 0x4002e798 ); +PROVIDE ( r_bt_rma_register_rule_cs_idx = 0x4002e884 ); +PROVIDE ( r_bt_rtp_apply_rule_cs_fmt = 0x4002ea50 ); +PROVIDE ( r_bt_rtp_apply_rule_cs_idx = 0x4002eb10 ); +PROVIDE ( r_bt_rtp_deregister_rule_cs_fmt = 0x4002ea08 ); +PROVIDE ( r_bt_rtp_deregister_rule_cs_idx = 0x4002ead4 ); +PROVIDE ( r_bt_rtp_get_txpwr_idx_by_act = 0x4002eb40 ); +PROVIDE ( r_bt_rtp_init = 0x4002e9a0 ); +PROVIDE ( r_bt_rtp_register_rule_cs_fmt = 0x4002e9b4 ); +PROVIDE ( r_bt_rtp_register_rule_cs_idx = 0x4002ea8c ); +PROVIDE ( r_cali_phase_match_p = 0x40001af8 ); +PROVIDE ( r_cmp_abs_time = 0x4000a31c ); +PROVIDE ( r_cmp_dest_id = 0x40009de0 ); +PROVIDE ( r_cmp_timer_id = 0x4000a340 ); +PROVIDE ( r_co_bdaddr_compare = 0x400020ac ); +PROVIDE ( r_co_ble_pkt_dur_in_us = 0x400025e8 ); +PROVIDE ( r_co_bytes_to_string = 0x40002074 ); +PROVIDE ( r_co_list_extract = 0x40001d88 ); +PROVIDE ( r_co_list_extract_after = 0x40001e28 ); +PROVIDE ( r_co_list_extract_sublist = 0x40001eac ); +PROVIDE ( r_co_list_find = 0x40001ef0 ); +PROVIDE ( r_co_list_init = 0x40001c4c ); +PROVIDE ( r_co_list_insert_after = 0x40001fa8 ); +PROVIDE ( r_co_list_insert_before = 0x40001f50 ); +PROVIDE ( r_co_list_merge = 0x40001f0c ); +PROVIDE ( r_co_list_pool_init = 0x40001c60 ); +PROVIDE ( r_co_list_pop_front = 0x40001d64 ); +PROVIDE ( r_co_list_push_back = 0x40001c94 ); +PROVIDE ( r_co_list_push_back_sublist = 0x40001cd8 ); +PROVIDE ( r_co_list_push_front = 0x40001d30 ); +PROVIDE ( r_co_list_size = 0x40002000 ); +PROVIDE ( r_co_nb_good_le_channels = 0x400020d0 ); +PROVIDE ( r_co_util_pack = 0x4000210c ); +PROVIDE ( r_co_util_read_array_size = 0x40002020 ); +PROVIDE ( r_co_util_unpack = 0x4000236c ); +PROVIDE ( RcvMsg = 0x40049c64 ); +PROVIDE ( r_dbg_env_deinit = 0x40002650 ); +PROVIDE ( r_dbg_env_init = 0x4000263c ); +PROVIDE ( r_dbg_esp_vendor_hci_command_handler = 0x40002fcc ); +PROVIDE ( r_dbg_hci_cmd_handler_tab_p_get = 0x40002fa8 ); +PROVIDE ( r_dbg_hci_command_handler = 0x40003010 ); +PROVIDE ( r_dbg_init = 0x40002664 ); +PROVIDE ( r_dbg_msg_handler_tab_p_get = 0x40003088 ); +PROVIDE ( r_dbg_platform_reset_complete = 0x400026a8 ); +PROVIDE ( r_dbg_register_esp_vendor_cmd_handler = 0x40002fb8 ); +PROVIDE ( r_dbg_sch_plan_move = 0x40002f98 ); +PROVIDE ( r_dbg_swdiag_init = 0x4000276c ); +PROVIDE ( r_dbg_swdiag_read = 0x400027a4 ); +PROVIDE ( r_dbg_swdiag_update = 0x400026f8 ); +PROVIDE ( r_dbg_swdiag_write = 0x400027cc ); +PROVIDE ( r_dbg_trc_cfg_received = 0x4000405c ); +PROVIDE ( r_dbg_trc_ke_evt_cbk = 0x40003248 ); +PROVIDE ( r_dbg_trc_mem_alloc = 0x400030e4 ); +PROVIDE ( r_dbg_trc_mem_dealloc = 0x400031dc ); +PROVIDE ( r_dbg_trc_mem_read = 0x4000318c ); +PROVIDE ( r_dbg_trc_mem_writing_allowed = 0x40003094 ); +PROVIDE ( r_dbg_trc_pay_buff_get = 0x400040d0 ); +PROVIDE ( r_dbg_trc_req_acl_rx_pdu = 0x40003dac ); +PROVIDE ( r_dbg_trc_req_acl_tx_pdu = 0x40003e08 ); +PROVIDE ( r_dbg_trc_req_adv_rx_pdu = 0x40003974 ); +PROVIDE ( r_dbg_trc_req_adv_tx_pdu = 0x400039fc ); +PROVIDE ( r_dbg_trc_req_cs_ble = 0x400035c4 ); +PROVIDE ( r_dbg_trc_req_custom = 0x40003ed0 ); +PROVIDE ( r_dbg_trc_req_deep_sleep = 0x400033f8 ); +PROVIDE ( r_dbg_trc_req_et_prog = 0x400034b0 ); +PROVIDE ( r_dbg_trc_req_evt_cnt = 0x40003524 ); +PROVIDE ( r_dbg_trc_req_frm_cmp = 0x40003568 ); +PROVIDE ( r_dbg_trc_req_hci_cmd = 0x400038c8 ); +PROVIDE ( r_dbg_trc_req_hci_evt = 0x4000391c ); +PROVIDE ( r_dbg_trc_req_init_rx_pdu = 0x40003ae0 ); +PROVIDE ( r_dbg_trc_req_init_tx_pdu = 0x40003b74 ); +PROVIDE ( r_dbg_trc_req_ke_evt = 0x40003360 ); +PROVIDE ( r_dbg_trc_req_ke_msg_handled = 0x400032ac ); +PROVIDE ( r_dbg_trc_req_ke_msg_send = 0x40003268 ); +PROVIDE ( r_dbg_trc_req_ke_tmr = 0x40003304 ); +PROVIDE ( r_dbg_trc_req_l2cap = 0x400036b0 ); +PROVIDE ( r_dbg_trc_req_l2cap_ack = 0x40003710 ); +PROVIDE ( r_dbg_trc_req_llcp = 0x40003664 ); +PROVIDE ( r_dbg_trc_req_llc_state_trans = 0x40003878 ); +PROVIDE ( r_dbg_trc_req_mem = 0x4000339c ); +PROVIDE ( r_dbg_trc_req_rx_desc = 0x40003610 ); +PROVIDE ( r_dbg_trc_req_scan_rx_pdu = 0x40003c0c ); +PROVIDE ( r_dbg_trc_req_scan_tx_pdu = 0x40003cc8 ); +PROVIDE ( r_dbg_trc_req_sch_arb = 0x400037bc ); +PROVIDE ( r_dbg_trc_req_sch_arb_insert = 0x40003754 ); +PROVIDE ( r_dbg_trc_req_sch_arb_shift = 0x40003800 ); +PROVIDE ( r_dbg_trc_req_sw_ass = 0x40003428 ); +PROVIDE ( r_dbg_trc_tx_done = 0x40004014 ); +PROVIDE ( r_dbg_trc_tx_start = 0x40003fb8 ); +PROVIDE ( r_dbg_trc_tx_trigger = 0x40004040 ); +PROVIDE ( r_dl_upd_proc_start = 0x4000d160 ); +PROVIDE ( r_dump_data = 0x40001144 ); +PROVIDE ( read = 0x4003b94c ); +PROVIDE ( _read_r = 0x400546a8 ); +PROVIDE ( realloc = 0x400547cc ); +PROVIDE ( _realloc_r = 0x400544e0 ); +PROVIDE ( r_ecc_abort_key256_generation = 0x40005fec ); +PROVIDE ( r_ecc_generate_key256 = 0x40005d18 ); +PROVIDE ( r_ecc_gen_new_public_key = 0x4000604c ); +PROVIDE ( r_ecc_gen_new_secret_key = 0x40006070 ); +PROVIDE ( r_ecc_get_debug_Keys = 0x4000618c ); +PROVIDE ( r_ecc_init = 0x40005ca4 ); +PROVIDE ( r_ecc_is_valid_point = 0x40005930 ); +PROVIDE ( r_ecc_multiplication_event_handler = 0x40005a64 ); +PROVIDE ( r_ecc_point_multiplication_win_256 = 0x400054dc ); +PROVIDE ( recv_packet = 0x40049b3c ); +PROVIDE ( r_emi_alloc_em_mapping_by_offset = 0x40006534 ); +PROVIDE ( r_emi_base_reg_lut_show = 0x400062b8 ); +PROVIDE ( r_emi_em_base_reg_show = 0x40006258 ); +PROVIDE ( r_emi_free_em_mapping_by_offset = 0x400066f0 ); +PROVIDE ( r_emi_get_em_mapping_idx_by_offset = 0x400063d8 ); +PROVIDE ( r_emi_get_mem_addr_by_offset = 0x40006300 ); +PROVIDE ( r_emi_overwrite_em_mapping_by_offset = 0x40006424 ); +PROVIDE ( _rename_r = 0x40054528 ); +PROVIDE ( _ResetHandler = 0x40000454 ); +PROVIDE ( _ResetVector = 0x40000400 ); +PROVIDE ( _ResetVector_literal_end = 0x4000056c ); +PROVIDE ( _ResetVector_literal_start = 0x4000056c ); +PROVIDE ( _ResetVector_text_end = 0x40000569 ); +PROVIDE ( _ResetVector_text_start = 0x40000400 ); +PROVIDE ( r_flash_env_deinit = 0x4000696c ); +PROVIDE ( r_flash_env_init = 0x4000693c ); +PROVIDE ( r_flash_erase = 0x40006a34 ); +PROVIDE ( r_flash_identify = 0x400069d4 ); +PROVIDE ( r_flash_init = 0x40006990 ); +PROVIDE ( r_flash_read = 0x40006a9c ); +PROVIDE ( r_flash_unlock = 0x40006928 ); +PROVIDE ( r_flash_unlocksector = 0x40006920 ); +PROVIDE ( r_flash_write = 0x40006a68 ); +PROVIDE ( r_flash_writebyte = 0x40006904 ); +PROVIDE ( r_get_stack_usage = 0x4000118c ); +PROVIDE ( r_GF_Jacobian_Point_Addition256 = 0x400049d0 ); +PROVIDE ( r_GF_Jacobian_Point_Double256 = 0x40004f54 ); +PROVIDE ( r_GF_Point_Jacobian_To_Affine256 = 0x400051b0 ); +PROVIDE ( r_h4tl_acl_hdr_rx_evt_handler = 0x40007074 ); +PROVIDE ( r_h4tl_cmd_hdr_rx_evt_handler = 0x40006fb0 ); +PROVIDE ( r_h4tl_cmd_pld_rx_evt_handler = 0x4000702c ); +PROVIDE ( r_h4tl_eif_io_event_post = 0x40006234 ); +PROVIDE ( r_h4tl_eif_p = 0x3fcef474 ); +PROVIDE ( r_h4tl_eif_register = 0x400061dc ); +PROVIDE ( r_h4tl_init = 0x400070f8 ); +PROVIDE ( r_h4tl_out_of_sync = 0x40006bac ); +PROVIDE ( r_h4tl_out_of_sync_check = 0x40006c04 ); +PROVIDE ( r_h4tl_read_hdr = 0x40006b3c ); +PROVIDE ( r_h4tl_read_next_out_of_sync = 0x40006b88 ); +PROVIDE ( r_h4tl_read_payl = 0x40006b68 ); +PROVIDE ( r_h4tl_read_start = 0x40006b10 ); +PROVIDE ( r_h4tl_rx_acl_hdr_extract = 0x40006aec ); +PROVIDE ( r_h4tl_rx_cmd_hdr_extract = 0x40006ad0 ); +PROVIDE ( r_h4tl_rx_done = 0x40006d84 ); +PROVIDE ( r_h4tl_start = 0x40007200 ); +PROVIDE ( r_h4tl_stop = 0x40007210 ); +PROVIDE ( r_h4tl_tx_done = 0x40006cb0 ); +PROVIDE ( r_h4tl_tx_evt_handler = 0x40006cec ); +PROVIDE ( r_h4tl_write = 0x40007170 ); +PROVIDE ( r_hci_acl_tx_data_alloc = 0x400092a8 ); +PROVIDE ( r_hci_acl_tx_data_received = 0x40009344 ); +PROVIDE ( r_hci_basic_cmd_send_2_controller = 0x400082b0 ); +PROVIDE ( r_hci_ble_adv_report_filter_check = 0x40008420 ); +PROVIDE ( r_hci_ble_adv_report_tx_check = 0x4000866c ); +PROVIDE ( r_hci_ble_conhdl_register = 0x400082dc ); +PROVIDE ( r_hci_ble_conhdl_unregister = 0x40008334 ); +PROVIDE ( r_hci_build_acl_data = 0x40008b60 ); +PROVIDE ( r_hci_build_cc_evt = 0x40008854 ); +PROVIDE ( r_hci_build_cs_evt = 0x40008820 ); +PROVIDE ( r_hci_build_dbg_evt = 0x400089f4 ); +PROVIDE ( r_hci_build_evt = 0x40008918 ); +PROVIDE ( r_hci_build_le_evt = 0x40008aa4 ); +PROVIDE ( r_hci_cmd_get_max_param_size = 0x40009030 ); +PROVIDE ( r_hci_cmd_received = 0x40009054 ); +PROVIDE ( r_hci_cmd_reject = 0x400086f8 ); +PROVIDE ( r_hci_evt_mask_check = 0x40007f28 ); +PROVIDE ( r_hci_evt_mask_set = 0x40008394 ); +PROVIDE ( r_hci_fc_acl_buf_size_set = 0x40007260 ); +PROVIDE ( r_hci_fc_acl_en = 0x40007280 ); +PROVIDE ( r_hci_fc_acl_packet_sent = 0x400072c0 ); +PROVIDE ( r_hci_fc_check_host_available_nb_acl_packets = 0x400072fc ); +PROVIDE ( r_hci_fc_host_nb_acl_pkts_complete = 0x400072d8 ); +PROVIDE ( r_hci_fc_init = 0x4000724c ); +PROVIDE ( r_hci_look_for_cmd_desc = 0x40007e1c ); +PROVIDE ( r_hci_look_for_dbg_evt_desc = 0x40007ec8 ); +PROVIDE ( r_hci_look_for_evt_desc = 0x40007e9c ); +PROVIDE ( r_hci_look_for_le_evt_desc = 0x40007ee0 ); +PROVIDE ( r_hci_look_for_le_evt_desc_esp = 0x40007f0c ); +PROVIDE ( r_hci_pack_bytes = 0x40007de4 ); +PROVIDE ( r_hci_register_vendor_desc_tab = 0x40007dd0 ); +PROVIDE ( r_hci_send_2_controller = 0x400081d0 ); +PROVIDE ( r_hci_send_2_host = 0x40007fe4 ); +PROVIDE ( r_hci_tl_c2h_data_flow_on = 0x40008dfc ); +PROVIDE ( r_hci_tl_cmd_hdr_rx_evt_handler = 0x40008ec8 ); +PROVIDE ( r_hci_tl_cmd_pld_rx_evt_handler = 0x40008f1c ); +PROVIDE ( r_hci_tl_get_pkt = 0x40008ebc ); +PROVIDE ( r_hci_tl_hci_pkt_handler = 0x40008f74 ); +PROVIDE ( r_hci_tl_hci_tx_done_evt_handler = 0x40009010 ); +PROVIDE ( r_hci_tl_inc_nb_h2c_cmd_pkts = 0x40008e6c ); +PROVIDE ( r_hci_tl_save_pkt = 0x40008e88 ); +PROVIDE ( r_hci_tl_send = 0x40008e14 ); +PROVIDE ( r_hci_tx_done = 0x40008d1c ); +PROVIDE ( r_hci_tx_start = 0x40008b90 ); +PROVIDE ( r_hci_tx_trigger = 0x40008de0 ); +PROVIDE ( r_hli_funcs_p = 0x3fcef4c8 ); +PROVIDE ( r_ip_funcs_p = 0x3fcef4cc ); +PROVIDE ( r_isValidSecretKey_256 = 0x400040dc ); +PROVIDE ( r_ke_check_malloc = 0x40009740 ); +PROVIDE ( r_ke_event_callback_set = 0x400094d4 ); +PROVIDE ( r_ke_event_clear = 0x40009568 ); +PROVIDE ( r_ke_event_flush = 0x4000960c ); +PROVIDE ( r_ke_event_get = 0x400095b4 ); +PROVIDE ( r_ke_event_get_all = 0x40009600 ); +PROVIDE ( r_ke_event_init = 0x400094bc ); +PROVIDE ( r_ke_event_schedule = 0x4000961c ); +PROVIDE ( r_ke_event_set = 0x4000950c ); +PROVIDE ( r_ke_flush = 0x40009d4c ); +PROVIDE ( r_ke_free = 0x400099b4 ); +PROVIDE ( r_ke_get_max_mem_usage = 0x40009b9c ); +PROVIDE ( r_ke_get_mem_usage = 0x40009b74 ); +PROVIDE ( r_ke_handler_search = 0x40009e54 ); +PROVIDE ( r_ke_init = 0x40009cf4 ); +PROVIDE ( r_ke_is_free = 0x40009b58 ); +PROVIDE ( r_ke_malloc = 0x40009808 ); +PROVIDE ( r_ke_mem_init = 0x400096b8 ); +PROVIDE ( r_ke_mem_is_empty = 0x400096f0 ); +PROVIDE ( r_ke_msg_alloc = 0x40009bb4 ); +PROVIDE ( r_ke_msg_dest_id_get = 0x40009cbc ); +PROVIDE ( r_ke_msg_discard = 0x4000a258 ); +PROVIDE ( r_ke_msg_forward = 0x40009c6c ); +PROVIDE ( r_ke_msg_forward_new_id = 0x40009c88 ); +PROVIDE ( r_ke_msg_free = 0x40009ca8 ); +PROVIDE ( r_ke_msg_in_queue = 0x40009cd4 ); +PROVIDE ( r_ke_msg_save = 0x4000a260 ); +PROVIDE ( r_ke_msg_send = 0x40009c08 ); +PROVIDE ( r_ke_msg_send_basic = 0x40009c48 ); +PROVIDE ( r_ke_msg_src_id_get = 0x40009cc8 ); +PROVIDE ( r_ke_queue_extract = 0x400320d8 ); +PROVIDE ( r_ke_queue_insert = 0x40032128 ); +PROVIDE ( r_ke_sleep_check = 0x40009da8 ); +PROVIDE ( r_ke_state_get = 0x4000a1d8 ); +PROVIDE ( r_ke_state_set = 0x4000a134 ); +PROVIDE ( r_ke_stats_get = 0x40009dc0 ); +PROVIDE ( r_ke_task_check = 0x4000a2ac ); +PROVIDE ( r_ke_task_create = 0x4000a0b4 ); +PROVIDE ( r_ke_task_delete = 0x4000a100 ); +PROVIDE ( r_ke_task_handler_get = 0x40009ec0 ); +PROVIDE ( r_ke_task_init = 0x4000a090 ); +PROVIDE ( r_ke_task_msg_flush = 0x4000a268 ); +PROVIDE ( r_ke_task_saved_update = 0x40009df4 ); +PROVIDE ( r_ke_task_schedule = 0x40009f34 ); +PROVIDE ( r_ke_time = 0x4000a458 ); +PROVIDE ( r_ke_time_cmp = 0x4000a2e0 ); +PROVIDE ( r_ke_time_past = 0x4000a300 ); +PROVIDE ( r_ke_timer_active = 0x4000a600 ); +PROVIDE ( r_ke_timer_adjust_all = 0x4000a628 ); +PROVIDE ( r_ke_timer_clear = 0x4000a574 ); +PROVIDE ( r_ke_timer_init = 0x4000a440 ); +PROVIDE ( r_ke_timer_schedule = 0x4000a360 ); +PROVIDE ( r_ke_timer_set = 0x4000a490 ); +PROVIDE ( r_led_init = 0x40032160 ); +PROVIDE ( r_led_set_all = 0x40032168 ); +PROVIDE ( r_llc_aes_res_cb = 0x4000d1e8 ); +PROVIDE ( r_llc_ch_map_up_proc_err_cb = 0x4000a8c0 ); +PROVIDE ( r_llc_cleanup = 0x4000fa20 ); +PROVIDE ( r_llc_cmd_cmp_send = 0x4000ec9c ); +PROVIDE ( r_llc_cmd_stat_send = 0x4000ecd0 ); +PROVIDE ( r_llc_con_move_cbk = 0x4000c1e8 ); +PROVIDE ( r_llc_con_plan_set_update = 0x4000b534 ); +PROVIDE ( r_llc_con_upd_param_in_range = 0x4000ac70 ); +PROVIDE ( r_llc_disconnect = 0x4000c8fc ); +PROVIDE ( r_llc_disconnect_end = 0x4000c40c ); +PROVIDE ( r_llc_disconnect_proc_continue = 0x4000c46c ); +PROVIDE ( r_llc_disconnect_proc_err_cb = 0x4000c57c ); +PROVIDE ( r_llc_dl_chg_check = 0x40010b7c ); +PROVIDE ( r_llc_dle_proc_err_cb = 0x4000cdec ); +PROVIDE ( r_llc_feats_exch_proc_err_cb = 0x4000e758 ); +PROVIDE ( r_llc_hci_cmd_handler_tab_p_get = 0x4000ed00 ); +PROVIDE ( r_llc_hci_command_handler = 0x4000ed08 ); +PROVIDE ( r_llc_hci_con_param_req_evt_send = 0x4000b4e4 ); +PROVIDE ( r_llc_hci_con_upd_info_send = 0x4000b674 ); +PROVIDE ( r_llc_hci_disconnected_dis = 0x4000c808 ); +PROVIDE ( r_llc_hci_dl_upd_info_send = 0x4000c9f4 ); +PROVIDE ( r_llc_hci_enc_evt_send = 0x4000dc08 ); +PROVIDE ( r_llc_hci_feats_info_send = 0x4000e624 ); +PROVIDE ( r_llc_hci_le_phy_upd_cmp_evt_send = 0x40010a3c ); +PROVIDE ( r_llc_hci_ltk_request_evt_send = 0x4000dbc4 ); +PROVIDE ( r_llc_hci_nb_cmp_pkts_evt_send = 0x4000ec64 ); +PROVIDE ( r_llc_hci_version_info_send = 0x40011300 ); +PROVIDE ( r_llc_init_term_proc = 0x4000c940 ); +PROVIDE ( r_llc_iv_skd_rand_gen = 0x4000d228 ); +PROVIDE ( r_llc_le_ping_proc_continue = 0x4000efe4 ); +PROVIDE ( r_llc_le_ping_proc_err_cb = 0x4000ef6c ); +PROVIDE ( r_llc_le_ping_restart = 0x4000f314 ); +PROVIDE ( r_llc_le_ping_set = 0x4000f358 ); +PROVIDE ( r_llc_llcp_send = 0x4000f4f8 ); +PROVIDE ( r_llc_llcp_state_set = 0x4000fd84 ); +PROVIDE ( r_llc_llcp_trans_timer_set = 0x4000f9a8 ); +PROVIDE ( r_llc_llcp_tx_check = 0x4000f5bc ); +PROVIDE ( r_llc_ll_pause_enc_rsp_ack_handler = 0x4000db34 ); +PROVIDE ( r_llc_ll_reject_ind_ack_handler = 0x4000db94 ); +PROVIDE ( r_llc_ll_reject_ind_pdu_send = 0x4000f494 ); +PROVIDE ( r_llc_ll_start_enc_rsp_ack_handler = 0x4000db64 ); +PROVIDE ( r_llc_ll_terminate_ind_ack = 0x4000c564 ); +PROVIDE ( r_llc_ll_unknown_ind_handler = 0x4000f484 ); +PROVIDE ( r_llc_loc_ch_map_proc_continue = 0x4000a748 ); +PROVIDE ( r_llc_loc_con_upd_proc_continue = 0x4000af0c ); +PROVIDE ( r_llc_loc_con_upd_proc_err_cb = 0x4000b770 ); +PROVIDE ( r_llc_loc_dl_upd_proc_continue = 0x4000ca4c ); +PROVIDE ( r_llc_loc_encrypt_proc_continue = 0x4000d38c ); +PROVIDE ( r_llc_loc_encrypt_proc_err_cb = 0x4000dc58 ); +PROVIDE ( r_llc_loc_feats_exch_proc_continue = 0x4000e66c ); +PROVIDE ( r_llc_loc_phy_upd_proc_continue = 0x400105b0 ); +PROVIDE ( r_llc_loc_phy_upd_proc_err_cb = 0x40010ab8 ); +PROVIDE ( r_llc_msg_handler_tab_p_get = 0x400112c4 ); +PROVIDE ( r_llcp_pdu_handler_tab_p_get = 0x4000f458 ); +PROVIDE ( r_llc_pref_param_compute = 0x4000acf4 ); +PROVIDE ( r_llc_proc_collision_check = 0x4001022c ); +PROVIDE ( r_llc_proc_err_ind = 0x40010080 ); +PROVIDE ( r_llc_proc_get = 0x4001004c ); +PROVIDE ( r_llc_proc_id_get = 0x4000ffe8 ); +PROVIDE ( r_llc_proc_reg = 0x4000fea4 ); +PROVIDE ( r_llc_proc_state_get = 0x40010020 ); +PROVIDE ( r_llc_proc_state_set = 0x40010028 ); +PROVIDE ( r_llc_proc_timer_pause_set = 0x4001017c ); +PROVIDE ( r_llc_proc_timer_set = 0x400100c4 ); +PROVIDE ( r_llc_proc_unreg = 0x4000ff44 ); +PROVIDE ( r_llc_rem_ch_map_proc_continue = 0x4000a64c ); +PROVIDE ( r_llc_rem_con_upd_proc_continue = 0x4000b288 ); +PROVIDE ( r_llc_rem_con_upd_proc_err_cb = 0x4000b810 ); +PROVIDE ( r_llc_rem_dl_upd_proc = 0x4000cc74 ); +PROVIDE ( r_llc_rem_encrypt_proc_continue = 0x4000d734 ); +PROVIDE ( r_llc_rem_encrypt_proc_err_cb = 0x4000dcf4 ); +PROVIDE ( r_llc_rem_phy_upd_proc_continue = 0x400102c4 ); +PROVIDE ( r_llc_rem_phy_upd_proc_err_cb = 0x40010b44 ); +PROVIDE ( r_llc_role_get = 0x4000fd48 ); +PROVIDE ( r_llc_sk_gen = 0x4000d248 ); +PROVIDE ( r_llc_start = 0x4000fb10 ); +PROVIDE ( r_llc_stop = 0x4000fab4 ); +PROVIDE ( r_llc_ver_exch_loc_proc_continue = 0x4001134c ); +PROVIDE ( r_llc_ver_proc_err_cb = 0x40011444 ); +PROVIDE ( r_lld_aa_gen = 0x4001e1c4 ); +PROVIDE ( r_lld_adv_adv_data_set = 0x4001349c ); +PROVIDE ( r_lld_adv_adv_data_update = 0x40016978 ); +PROVIDE ( r_lld_adv_aux_ch_idx_set = 0x400124dc ); +PROVIDE ( r_lld_adv_aux_evt_canceled_cbk = 0x400148f8 ); +PROVIDE ( r_lld_adv_aux_evt_start_cbk = 0x400144ac ); +PROVIDE ( r_lld_adv_coex_check_ext_adv_synced = 0x40016c7c ); +PROVIDE ( r_lld_adv_coex_env_reset = 0x4001163c ); +PROVIDE ( r_lld_adv_duration_update = 0x40016a80 ); +PROVIDE ( r_lld_adv_dynamic_pti_process = 0x400116bc ); +PROVIDE ( r_lld_adv_end = 0x400121e0 ); +PROVIDE ( r_lld_adv_evt_canceled_cbk = 0x4001479c ); +PROVIDE ( r_lld_adv_evt_start_cbk = 0x4001411c ); +PROVIDE ( r_lld_adv_ext_chain_construct = 0x40012c7c ); +PROVIDE ( r_lld_adv_ext_pkt_prepare = 0x40012688 ); +PROVIDE ( r_lld_adv_frm_cbk = 0x40015060 ); +PROVIDE ( r_lld_adv_frm_isr = 0x40014aac ); +PROVIDE ( r_lld_adv_frm_skip_isr = 0x40014ea8 ); +PROVIDE ( r_lld_adv_init = 0x400150b0 ); +PROVIDE ( r_lld_adv_pkt_rx = 0x40014040 ); +PROVIDE ( r_lld_adv_pkt_rx_connect_ind = 0x400139ac ); +PROVIDE ( r_lld_adv_pkt_rx_send_scan_req_evt = 0x40013ee8 ); +PROVIDE ( r_lld_adv_rand_addr_update = 0x40016af0 ); +PROVIDE ( r_lld_adv_restart = 0x40016bb4 ); +PROVIDE ( r_lld_adv_scan_rsp_data_set = 0x40013730 ); +PROVIDE ( r_lld_adv_scan_rsp_data_update = 0x400169fc ); +PROVIDE ( r_lld_adv_set_tx_power = 0x4001217c ); +PROVIDE ( r_lld_adv_start = 0x4001519c ); +PROVIDE ( r_lld_adv_stop = 0x40016890 ); +PROVIDE ( r_lld_adv_sync_info_set = 0x400122a4 ); +PROVIDE ( r_lld_adv_sync_info_update = 0x40016c2c ); +PROVIDE ( r_lld_calc_aux_rx = 0x4001e27c ); +PROVIDE ( r_lld_cca_alloc = 0x4001e944 ); +PROVIDE ( r_lld_cca_data_reset = 0x4001ea04 ); +PROVIDE ( r_lld_cca_free = 0x4001e9a0 ); +PROVIDE ( r_lld_channel_assess = 0x4001d704 ); +PROVIDE ( r_lld_ch_assess_data_get = 0x4001d830 ); +PROVIDE ( r_lld_ch_idx_get = 0x4001e454 ); +PROVIDE ( r_lld_ch_map_set = 0x4001e408 ); +PROVIDE ( r_lld_con_activity_act_offset_compute = 0x4001a3c0 ); +PROVIDE ( r_lld_con_activity_offset_compute = 0x4001a4b0 ); +PROVIDE ( r_lld_con_ch_map_update = 0x4001a18c ); +PROVIDE ( r_lld_con_cleanup = 0x40017368 ); +PROVIDE ( r_lld_con_current_tx_power_get = 0x4001a77c ); +PROVIDE ( r_lld_con_data_flow_set = 0x40019fe4 ); +PROVIDE ( r_lld_con_data_len_update = 0x4001a1e8 ); +PROVIDE ( r_lld_con_data_tx = 0x40019e34 ); +PROVIDE ( r_lld_con_enc_key_load = 0x4001a654 ); +PROVIDE ( r_lld_con_event_counter_get = 0x4001a38c ); +PROVIDE ( r_lld_con_evt_canceled_cbk = 0x40018c5c ); +PROVIDE ( r_lld_con_evt_duration_min_get = 0x40017330 ); +PROVIDE ( r_lld_con_evt_max_eff_time_cal = 0x4001702c ); +PROVIDE ( r_lld_con_evt_sd_evt_time_get = 0x4001aa70 ); +PROVIDE ( r_lld_con_evt_start_cbk = 0x400187d0 ); +PROVIDE ( r_lld_con_evt_time_update = 0x40017060 ); +PROVIDE ( r_lld_con_free_all_tx_buf = 0x4001a9ac ); +PROVIDE ( r_lld_con_frm_cbk = 0x40019160 ); +PROVIDE ( r_lld_con_frm_isr = 0x40018d40 ); +PROVIDE ( r_lld_con_frm_skip_isr = 0x40019050 ); +PROVIDE ( r_lld_con_init = 0x4001a95c ); +PROVIDE ( r_lld_con_llcp_tx = 0x40019c74 ); +PROVIDE ( r_lld_con_max_lat_calc = 0x40016f04 ); +PROVIDE ( r_lld_conn_dynamic_pti_process = 0x40016cb0 ); +PROVIDE ( r_lld_con_offset_get = 0x4001a830 ); +PROVIDE ( r_lld_con_param_update = 0x4001a0dc ); +PROVIDE ( r_lld_con_phys_update = 0x4001a24c ); +PROVIDE ( r_lld_con_pref_slave_evt_dur_set = 0x4001a8f4 ); +PROVIDE ( r_lld_con_pref_slave_latency_set = 0x4001a8a4 ); +PROVIDE ( r_lld_con_rssi_get = 0x4001a7ec ); +PROVIDE ( r_lld_con_rx = 0x40017de4 ); +PROVIDE ( r_lld_con_rx_channel_assess = 0x4001798c ); +PROVIDE ( r_lld_con_rx_enc = 0x4001a5e8 ); +PROVIDE ( r_lld_con_rx_isr = 0x40018f14 ); +PROVIDE ( r_lld_con_rx_link_info_check = 0x40017bcc ); +PROVIDE ( r_lld_con_rx_llcp_check = 0x40017a0c ); +PROVIDE ( r_lld_con_rx_sync_time_update = 0x40017c94 ); +PROVIDE ( r_lld_con_sched = 0x400175c8 ); +PROVIDE ( r_lld_con_set_tx_power = 0x40016e94 ); +PROVIDE ( r_lld_con_start = 0x400191f8 ); +PROVIDE ( r_lld_con_stop = 0x40019be8 ); +PROVIDE ( r_lld_continue_scan_rx_isr_end_process = 0x40021060 ); +PROVIDE ( r_lld_con_tx = 0x40017f50 ); +PROVIDE ( r_lld_con_tx_enc = 0x4001a578 ); +PROVIDE ( r_lld_con_tx_isr = 0x40018fa4 ); +PROVIDE ( r_lld_con_tx_len_update = 0x40016f98 ); +PROVIDE ( r_lld_con_tx_len_update_for_intv = 0x4001a2d4 ); +PROVIDE ( r_lld_con_tx_len_update_for_rate = 0x4001a31c ); +PROVIDE ( r_lld_con_tx_prog = 0x400182d0 ); +PROVIDE ( r_lld_ext_scan_dynamic_pti_process = 0x40020bb4 ); +PROVIDE ( r_lld_hw_cca_end_isr = 0x4001eb90 ); +PROVIDE ( r_lld_hw_cca_evt_handler = 0x4001eb44 ); +PROVIDE ( r_lld_hw_cca_isr = 0x4001eb64 ); +PROVIDE ( r_lld_init_cal_anchor_point = 0x4001b6d4 ); +PROVIDE ( r_lld_init_compute_winoffset = 0x4001ac0c ); +PROVIDE ( r_lld_init_connect_req_pack = 0x4001c134 ); +PROVIDE ( r_lld_init_end = 0x4001aafc ); +PROVIDE ( r_lld_init_evt_canceled_cbk = 0x4001c010 ); +PROVIDE ( r_lld_init_evt_start_cbk = 0x4001bda4 ); +PROVIDE ( r_lld_init_frm_cbk = 0x4001bcc4 ); +PROVIDE ( r_lld_init_frm_eof_isr = 0x4001ba0c ); +PROVIDE ( r_lld_init_frm_skip_isr = 0x4001bb84 ); +PROVIDE ( r_lld_init_init = 0x4001c1c0 ); +PROVIDE ( r_lld_init_process_pkt_rx = 0x4001b51c ); +PROVIDE ( r_lld_init_process_pkt_rx_adv_ext_ind = 0x4001b1b4 ); +PROVIDE ( r_lld_init_process_pkt_rx_adv_ind_or_direct_ind = 0x4001aff4 ); +PROVIDE ( r_lld_init_process_pkt_rx_aux_connect_rsp = 0x4001b33c ); +PROVIDE ( r_lld_init_process_pkt_tx = 0x4001b7b0 ); +PROVIDE ( r_lld_init_process_pkt_tx_cal_con_timestamp = 0x4001b6e4 ); +PROVIDE ( r_lld_init_sched = 0x4001ac68 ); +PROVIDE ( r_lld_init_set_tx_power = 0x4001aab4 ); +PROVIDE ( r_lld_init_start = 0x4001c270 ); +PROVIDE ( r_lld_init_stop = 0x4001d0d0 ); +PROVIDE ( r_lld_instant_proc_end = 0x400174f8 ); +PROVIDE ( r_lld_llcp_rx_ind_handler = 0x4000f6d0 ); +PROVIDE ( r_lld_per_adv_chain_construct = 0x4001f50c ); +PROVIDE ( r_lld_per_adv_ch_map_update = 0x40020b48 ); +PROVIDE ( r_lld_per_adv_cleanup = 0x4001ef68 ); +PROVIDE ( r_lld_per_adv_coex_env_reset = 0x4001eb9c ); +PROVIDE ( r_lld_per_adv_data_set = 0x4001f730 ); +PROVIDE ( r_lld_per_adv_data_update = 0x40020a2c ); +PROVIDE ( r_lld_per_adv_dynamic_pti_process = 0x4001ebd4 ); +PROVIDE ( r_lld_per_adv_evt_canceled_cbk = 0x4001fbf4 ); +PROVIDE ( r_lld_per_adv_evt_start_cbk = 0x4001f7b4 ); +PROVIDE ( r_lld_per_adv_ext_pkt_prepare = 0x4001f0a0 ); +PROVIDE ( r_lld_per_adv_frm_cbk = 0x40020094 ); +PROVIDE ( r_lld_per_adv_frm_isr = 0x4001fca0 ); +PROVIDE ( r_lld_per_adv_frm_skip_isr = 0x4001ff88 ); +PROVIDE ( r_lld_per_adv_init = 0x400200e4 ); +PROVIDE ( r_lld_per_adv_init_info_get = 0x40020ae8 ); +PROVIDE ( r_lld_per_adv_list_add = 0x4001db28 ); +PROVIDE ( r_lld_per_adv_list_rem = 0x4001dc8c ); +PROVIDE ( r_lld_per_adv_sched = 0x4001eff0 ); +PROVIDE ( r_lld_per_adv_set_tx_power = 0x4001ef8c ); +PROVIDE ( r_lld_per_adv_start = 0x40020164 ); +PROVIDE ( r_lld_per_adv_stop = 0x4002096c ); +PROVIDE ( r_lld_per_adv_sync_info_get = 0x40020a94 ); +PROVIDE ( r_lld_process_cca_data = 0x4001ea5c ); +PROVIDE ( r_lld_ral_search = 0x4001d160 ); +PROVIDE ( r_lld_read_clock = 0x4001d81c ); +PROVIDE ( r_lld_reg_rd = 0x4001e188 ); +PROVIDE ( r_lld_reg_wr = 0x4001e1a0 ); +PROVIDE ( r_lld_reset_reg = 0x4001d7b0 ); +PROVIDE ( r_lld_res_list_add = 0x4001ddc8 ); +PROVIDE ( r_lld_res_list_clear = 0x4001dd70 ); +PROVIDE ( r_lld_res_list_is_empty = 0x4001e154 ); +PROVIDE ( r_lld_res_list_local_rpa_get = 0x4001e0ec ); +PROVIDE ( r_lld_res_list_peer_rpa_get = 0x4001e084 ); +PROVIDE ( r_lld_res_list_peer_update = 0x4001e014 ); +PROVIDE ( r_lld_res_list_priv_mode_update = 0x4001df9c ); +PROVIDE ( r_lld_res_list_rem = 0x4001df40 ); +PROVIDE ( r_lld_rpa_renew = 0x4001d844 ); +PROVIDE ( r_lld_rpa_renew_evt_canceled_cbk = 0x4001d370 ); +PROVIDE ( r_lld_rpa_renew_evt_start_cbk = 0x4001d2ec ); +PROVIDE ( r_lld_rpa_renew_instant_cbk = 0x4001d1e4 ); +PROVIDE ( r_lld_rxdesc_check = 0x4001d5ac ); +PROVIDE ( r_lld_rxdesc_free = 0x4001d3c4 ); +PROVIDE ( r_lld_scan_create_sync = 0x40024240 ); +PROVIDE ( r_lld_scan_create_sync_cancel = 0x400242ac ); +PROVIDE ( r_lld_scan_end = 0x40020f40 ); +PROVIDE ( r_lld_scan_evt_canceled_cbk = 0x400231d8 ); +PROVIDE ( r_lld_scan_evt_start_cbk = 0x40022fa0 ); +PROVIDE ( r_lld_scan_frm_cbk = 0x40022f20 ); +PROVIDE ( r_lld_scan_frm_eof_isr = 0x40022b80 ); +PROVIDE ( r_lld_scan_frm_rx_isr = 0x40022d24 ); +PROVIDE ( r_lld_scan_frm_skip_isr = 0x40022dc4 ); +PROVIDE ( r_lld_scan_init = 0x40023314 ); +PROVIDE ( r_lld_scan_params_update = 0x400241ec ); +PROVIDE ( r_lld_scan_process_pkt_rx = 0x40021fec ); +PROVIDE ( r_lld_scan_process_pkt_rx_adv_rep = 0x400211e8 ); +PROVIDE ( r_lld_scan_process_pkt_rx_aux_adv_ind = 0x40021684 ); +PROVIDE ( r_lld_scan_process_pkt_rx_aux_chain_ind = 0x40021cf8 ); +PROVIDE ( r_lld_scan_process_pkt_rx_aux_scan_rsp = 0x40021b64 ); +PROVIDE ( r_lld_scan_process_pkt_rx_ext_adv = 0x40021eac ); +PROVIDE ( r_lld_scan_process_pkt_rx_ext_adv_ind = 0x40021414 ); +PROVIDE ( r_lld_scan_process_pkt_rx_legacy_adv = 0x400210b4 ); +PROVIDE ( r_lld_scan_restart = 0x4002337c ); +PROVIDE ( r_lld_scan_sched = 0x40022544 ); +PROVIDE ( r_lld_scan_set_tx_power = 0x40020edc ); +PROVIDE ( r_lld_scan_start = 0x4002349c ); +PROVIDE ( r_lld_scan_stop = 0x40024160 ); +PROVIDE ( r_lld_scan_sync_accept = 0x4002232c ); +PROVIDE ( r_lld_scan_sync_info_unpack = 0x40022230 ); +PROVIDE ( r_lld_scan_trunc_ind = 0x400221dc ); +PROVIDE ( r_lld_sw_cca_evt_handler = 0x4001eaf8 ); +PROVIDE ( r_lld_sw_cca_isr = 0x4001eb18 ); +PROVIDE ( r_lld_sync_ch_map_update = 0x40025e84 ); +PROVIDE ( r_lld_sync_cleanup = 0x40024520 ); +PROVIDE ( r_lld_sync_evt_canceled_cbk = 0x4002568c ); +PROVIDE ( r_lld_sync_evt_start_cbk = 0x400254e0 ); +PROVIDE ( r_lld_sync_frm_cbk = 0x4002545c ); +PROVIDE ( r_lld_sync_frm_eof_isr = 0x400251a8 ); +PROVIDE ( r_lld_sync_frm_rx_isr = 0x400252fc ); +PROVIDE ( r_lld_sync_frm_skip_isr = 0x4002538c ); +PROVIDE ( r_lld_sync_init = 0x40025754 ); +PROVIDE ( r_lld_sync_process_pkt_rx = 0x40024ad0 ); +PROVIDE ( r_lld_sync_process_pkt_rx_aux_sync_ind = 0x400245d4 ); +PROVIDE ( r_lld_sync_process_pkt_rx_pkt_check = 0x40024720 ); +PROVIDE ( r_lld_sync_scan_dynamic_pti_process = 0x40024304 ); +PROVIDE ( r_lld_sync_sched = 0x40024bd8 ); +PROVIDE ( r_lld_sync_start = 0x400257bc ); +PROVIDE ( r_lld_sync_stop = 0x40025ec4 ); +PROVIDE ( r_lld_sync_trunc_ind = 0x40024574 ); +PROVIDE ( r_lld_test_cleanup = 0x40025fdc ); +PROVIDE ( r_lld_test_evt_canceled_cbk = 0x400261a8 ); +PROVIDE ( r_lld_test_evt_start_cbk = 0x40026060 ); +PROVIDE ( r_lld_test_freq2chnl = 0x4002601c ); +PROVIDE ( r_lld_test_frm_cbk = 0x40026344 ); +PROVIDE ( r_lld_test_frm_isr = 0x40026268 ); +PROVIDE ( r_lld_test_init = 0x40026aec ); +PROVIDE ( r_lld_test_rx_isr = 0x40026228 ); +PROVIDE ( r_lld_test_set_tx_power = 0x40025f78 ); +PROVIDE ( r_lld_test_start = 0x400263b4 ); +PROVIDE ( r_lld_test_stop = 0x40026a1c ); +PROVIDE ( r_lld_update_rxbuf = 0x4001e4ac ); +PROVIDE ( r_lld_update_rxbuf_isr = 0x4001e638 ); +PROVIDE ( r_lld_white_list_add = 0x4001d8e0 ); +PROVIDE ( r_lld_white_list_rem = 0x4001da40 ); +PROVIDE ( r_llm_activity_free_get = 0x4002bb5c ); +PROVIDE ( r_llm_activity_free_set = 0x4002bc20 ); +PROVIDE ( r_llm_activity_syncing_get = 0x4002bc60 ); +PROVIDE ( r_llm_adv_con_len_check = 0x40026cd8 ); +PROVIDE ( r_llm_adv_hdl_to_id = 0x40026ebc ); +PROVIDE ( r_llm_adv_rep_flow_control_check = 0x4002cf3c ); +PROVIDE ( r_llm_adv_rep_flow_control_update = 0x4002cf78 ); +PROVIDE ( r_llm_adv_reports_list_check = 0x4002cdf0 ); +PROVIDE ( r_llm_adv_set_all_release = 0x4002975c ); +PROVIDE ( r_llm_adv_set_dft_params = 0x40026dc8 ); +PROVIDE ( r_llm_adv_set_release = 0x40026b18 ); +PROVIDE ( r_llm_aes_res_cb = 0x4002a870 ); +PROVIDE ( r_llm_ble_update_adv_flow_control = 0x4002cdd8 ); +PROVIDE ( r_llm_ch_map_update = 0x4002b9c4 ); +PROVIDE ( r_llm_cmd_cmp_send = 0x4002b674 ); +PROVIDE ( r_llm_cmd_stat_send = 0x4002b6bc ); +PROVIDE ( r_llm_dev_list_empty_entry = 0x4002b7f8 ); +PROVIDE ( r_llm_dev_list_search = 0x4002b81c ); +PROVIDE ( r_llm_env_adv_dup_filt_deinit = 0x4002dd90 ); +PROVIDE ( r_llm_env_adv_dup_filt_init = 0x4002dd38 ); +PROVIDE ( r_llm_hci_cmd_handler_tab_p_get = 0x4002a8a8 ); +PROVIDE ( r_llm_hci_command_handler = 0x4002a8b0 ); +PROVIDE ( r_llm_init_ble_adv_report_flow_contol = 0x4002cda4 ); +PROVIDE ( r_llm_is_dev_connected = 0x4002b6e8 ); +PROVIDE ( r_llm_is_dev_synced = 0x4002b76c ); +PROVIDE ( r_llm_is_non_con_act_ongoing_check = 0x4002a7d4 ); +PROVIDE ( r_llm_is_wl_accessible = 0x4002a76c ); +PROVIDE ( r_llm_le_evt_mask_check = 0x4002b958 ); +PROVIDE ( r_llm_le_features_get = 0x4002b980 ); +PROVIDE ( r_llm_link_disc = 0x4002b868 ); +PROVIDE ( r_llm_master_ch_map_get = 0x4002b948 ); +PROVIDE ( r_llm_msg_handler_tab_p_get = 0x4002df30 ); +PROVIDE ( r_llm_no_activity = 0x4002a820 ); +PROVIDE ( r_llm_per_adv_slot_dur = 0x40026d3c ); +PROVIDE ( r_llm_plan_elt_get = 0x4002b9a8 ); +PROVIDE ( r_llm_rx_path_comp_get = 0x4002b998 ); +PROVIDE ( r_llm_scan_start = 0x4002bca0 ); +PROVIDE ( r_llm_scan_sync_acad_attach = 0x4002dcb0 ); +PROVIDE ( r_llm_scan_sync_acad_detach = 0x4002dcf8 ); +PROVIDE ( r_llm_send_adv_lost_event_to_host = 0x4002cd54 ); +PROVIDE ( r_llm_tx_path_comp_get = 0x4002b988 ); +PROVIDE ( r_misc_deinit = 0x4002df94 ); +PROVIDE ( r_misc_free_em_buf_in_isr = 0x4002dfa8 ); +PROVIDE ( r_misc_init = 0x4002df78 ); +PROVIDE ( r_misc_msg_handler_tab_p_get = 0x4002df6c ); +PROVIDE ( r_modules_funcs_p = 0x3fcef66c ); +PROVIDE ( r_MultiplyBigHexByUint32_256 = 0x400047fc ); +PROVIDE ( r_MultiplyBigHexModP256 = 0x40004698 ); +PROVIDE ( r_MultiplyByU16ModP256 = 0x40004948 ); +PROVIDE ( r_notEqual256 = 0x400049a4 ); +PROVIDE ( r_nvds_browse_tag = 0x4002e088 ); +PROVIDE ( r_nvds_del = 0x4002e314 ); +PROVIDE ( r_nvds_erase = 0x4002e164 ); +PROVIDE ( r_nvds_get = 0x4002e2c4 ); +PROVIDE ( r_nvds_init = 0x4002e240 ); +PROVIDE ( r_nvds_init_memory = 0x4002e184 ); +PROVIDE ( r_nvds_is_magic_number_ok = 0x4002e010 ); +PROVIDE ( r_nvds_lock = 0x4002e35c ); +PROVIDE ( r_nvds_null_init = 0x4002e0cc ); +PROVIDE ( r_nvds_purge = 0x4002e1a8 ); +PROVIDE ( r_nvds_put = 0x4002e3a4 ); +PROVIDE ( r_nvds_read = 0x4002e0f4 ); +PROVIDE ( r_nvds_walk_tag = 0x4002e040 ); +PROVIDE ( r_nvds_write = 0x4002e12c ); +PROVIDE ( _rodata_end = 0x3ff0fff0 ); +PROVIDE ( rodata_reserved_end = 0x3fcefca0 ); +PROVIDE ( rodata_reserved_start = 0x3fcefc9c ); +PROVIDE ( _rodata_start = 0x3ff071c0 ); +PROVIDE ( rom_abs_temp = 0x40041394 ); +PROVIDE ( rom_agc_reg_init = 0x4003de00 ); +PROVIDE ( rom_ant_btrx_cfg = 0x4003e44c ); +PROVIDE ( rom_ant_bttx_cfg = 0x4003e410 ); +PROVIDE ( rom_ant_dft_cfg = 0x4003e320 ); +PROVIDE ( rom_ant_wifirx_cfg = 0x4003e388 ); +PROVIDE ( rom_ant_wifitx_cfg = 0x4003e348 ); +PROVIDE ( rom_bb_bss_cbw40 = 0x4003ea3c ); +PROVIDE ( rom_bb_bss_cbw40_ana = 0x4003f91c ); +PROVIDE ( rom_bb_bss_cbw40_dig = 0x4003d564 ); +PROVIDE ( rom_bb_reg_init = 0x4003e07c ); +PROVIDE ( rom_bb_wdg_cfg = 0x4003e174 ); +PROVIDE ( rom_bb_wdg_test_en = 0x4003d528 ); +PROVIDE ( rom_bb_wdt_get_status = 0x4003d9d8 ); +PROVIDE ( rom_bb_wdt_int_enable = 0x4003d994 ); +PROVIDE ( rom_bb_wdt_rst_enable = 0x4003d974 ); +PROVIDE ( rom_bb_wdt_timeout_clear = 0x4003d9bc ); +PROVIDE ( rom_bt_bb_to_index = 0x4003ce5c ); +PROVIDE ( rom_bt_correct_rf_ana_gain = 0x40042874 ); +PROVIDE ( rom_bt_index_to_bb = 0x4003ce40 ); +PROVIDE ( rom_cbw2040_cfg = 0x4003e9d4 ); +PROVIDE ( rom_chan_to_freq = 0x4003f9d4 ); +PROVIDE ( rom_check_noise_floor = 0x4003d62c ); +PROVIDE ( rom_chip_i2c_readReg = 0x4003ee28 ); +PROVIDE ( rom_chip_i2c_writeReg = 0x4003eea0 ); +PROVIDE ( rom_chip_wait_idle_interval = 0x3fcefc04 ); +PROVIDE ( rom_code_to_temp = 0x40040648 ); +PROVIDE ( rom_config_data_cache_mode = 0x4004f188 ); +PROVIDE ( rom_config_instruction_cache_mode = 0x4004f138 ); +PROVIDE ( rom_correct_rf_ana_gain = 0x40042758 ); +PROVIDE ( rom_correct_rfpll_offset = 0x4003fd3c ); +PROVIDE ( rom_dac_rate_set = 0x4003fc44 ); +PROVIDE ( rom_dc_iq_est = 0x40041470 ); +PROVIDE ( rom_disable_agc = 0x4003c8c4 ); +PROVIDE ( rom_disable_wifi_agc = 0x4003c944 ); +PROVIDE ( rom_enable_agc = 0x4003c8ec ); +PROVIDE ( rom_enable_cache_flash_wrap = 0x4004f0c0 ); +PROVIDE ( rom_enable_cache_spiram_wrap = 0x4004f0fc ); +PROVIDE ( rom_enable_wifi_agc = 0x4003c98c ); +PROVIDE ( rom_en_pwdet = 0x40040eac ); +PROVIDE ( rom_esp_flash_default_chip = 0x3fcefc14 ); +PROVIDE ( rom_fe_reg_init = 0x4003dc84 ); +PROVIDE ( rom_fe_txrx_reset = 0x4003e1a8 ); +PROVIDE ( rom_flash_chip_dummy = 0x3fcefc0c ); +PROVIDE ( rom_force_txon = 0x4003ebbc ); +PROVIDE ( rom_freq_get_i2c_data = 0x40040778 ); +PROVIDE ( rom_freq_i2c_write_set = 0x4003fe9c ); +PROVIDE ( rom_gen_rx_gain_table = 0x4003e7a8 ); +PROVIDE ( rom_get_bbgain_db = 0x4003ce78 ); +PROVIDE ( rom_get_bias_ref_code = 0x4004297c ); +PROVIDE ( rom_get_data_sat = 0x4003cb08 ); +PROVIDE ( rom_get_fm_sar_dout = 0x400410fc ); +PROVIDE ( rom_get_i2c_read_mask = 0x4003ee04 ); +PROVIDE ( rom_get_phy_target_power = 0x40042c20 ); +PROVIDE ( rom_get_pll_ref_code = 0x40040914 ); +PROVIDE ( rom_get_pll_vol = 0x40042adc ); +PROVIDE ( rom_get_power_atten = 0x40041f0c ); +PROVIDE ( rom_get_power_db = 0x40042044 ); +PROVIDE ( rom_get_pwctrl_correct = 0x40042ba8 ); +PROVIDE ( rom_get_rate_fcc_index = 0x400425fc ); +PROVIDE ( rom_get_rate_target_power = 0x4004267c ); +PROVIDE ( rom_get_rc_dout = 0x40041c50 ); +PROVIDE ( rom_get_rfcal_rxiq_data = 0x40041b64 ); +PROVIDE ( rom_get_rf_gain_qdb = 0x40042740 ); +PROVIDE ( rom_get_sar2_vol = 0x40042a08 ); +PROVIDE ( rom_get_sar_sig_ref = 0x40040fc4 ); +PROVIDE ( rom_get_target_power_offset = 0x40042498 ); +PROVIDE ( rom_get_tone_sar_dout = 0x40041088 ); +PROVIDE ( rom_host_delay_interval = 0x3fcefc08 ); +PROVIDE ( rom_i2c_bbtop_init = 0x4003f774 ); +PROVIDE ( rom_i2c_clk_sel = 0x4003ecd4 ); +PROVIDE ( rom_i2cmst_reg_init = 0x4003daf8 ); +PROVIDE ( rom_i2c_readReg = 0x4003ee84 ); +PROVIDE ( rom_i2c_readReg_Mask = 0x4003ef04 ); +PROVIDE ( rom_i2c_sar2_init_code = 0x4003fbe8 ); +PROVIDE ( rom_i2c_writeReg = 0x4003eee8 ); +PROVIDE ( rom_i2c_writeReg_Mask = 0x4003ef40 ); +PROVIDE ( rom_index_to_txbbgain = 0x40040b10 ); +PROVIDE ( rom_iq_corr_enable = 0x4003dc10 ); +PROVIDE ( rom_iq_est_disable = 0x40041434 ); +PROVIDE ( rom_iq_est_enable = 0x400413b4 ); +PROVIDE ( rom_linear_to_db = 0x40041fd8 ); +PROVIDE ( rom_loopback_mode_en = 0x4003cad4 ); +PROVIDE ( rom_mac_enable_bb = 0x4003e134 ); +PROVIDE ( rom_mac_tx_chan_offset = 0x4003e9fc ); +PROVIDE ( rom_meas_tone_pwr_db = 0x40042080 ); +PROVIDE ( rom_mhz2ieee = 0x4003e990 ); +PROVIDE ( rom_noise_floor_auto_set = 0x4003d594 ); +PROVIDE ( rom_open_i2c_xpd = 0x4003fc1c ); +PROVIDE ( rom_pbus_debugmode = 0x4003f1b4 ); +PROVIDE ( rom_pbus_force_mode = 0x4003efb0 ); +PROVIDE ( rom_pbus_force_test = 0x4003f114 ); +PROVIDE ( rom_pbus_rd = 0x4003f170 ); +PROVIDE ( rom_pbus_rd_addr = 0x4003f078 ); +PROVIDE ( rom_pbus_rd_shift = 0x4003f0c4 ); +PROVIDE ( rom_pbus_rx_dco_cal = 0x400414f8 ); +PROVIDE ( rom_pbus_set_dco = 0x4003f370 ); +PROVIDE ( rom_pbus_set_rxgain = 0x4003f1dc ); +PROVIDE ( rom_pbus_workmode = 0x4003f1c8 ); +PROVIDE ( rom_pbus_xpd_rx_off = 0x4003f240 ); +PROVIDE ( rom_pbus_xpd_rx_on = 0x4003f274 ); +PROVIDE ( rom_pbus_xpd_tx_off = 0x4003f2c8 ); +PROVIDE ( rom_pbus_xpd_tx_on = 0x4003f318 ); +PROVIDE ( rom_phy_ant_init = 0x4003e2d4 ); +PROVIDE ( rom_phy_byte_to_word = 0x4003da20 ); +PROVIDE ( rom_phy_chan_dump_cfg = 0x4003e548 ); +PROVIDE ( rom_phy_chan_filt_set = 0x4003eb28 ); +PROVIDE ( rom_phy_close_pa = 0x4003ed54 ); +PROVIDE ( rom_phy_disable_cca = 0x4003c9dc ); +PROVIDE ( rom_phy_disable_low_rate = 0x4003e760 ); +PROVIDE ( rom_phy_dis_hw_set_freq = 0x400408d8 ); +PROVIDE ( rom_phy_enable_cca = 0x4003ca08 ); +PROVIDE ( rom_phy_enable_low_rate = 0x4003e728 ); +PROVIDE ( rom_phy_freq_correct = 0x4003f5dc ); +PROVIDE ( rom_phy_get_fetx_delay = 0x4003fa08 ); +PROVIDE ( rom_phy_get_noisefloor = 0x4003d5e4 ); +PROVIDE ( rom_phy_get_rx_freq = 0x4003ec10 ); +PROVIDE ( rom_phy_get_tx_rate = 0x4003da10 ); +PROVIDE ( rom_phy_get_vdd33 = 0x400428f4 ); +PROVIDE ( rom_phy_i2c_init = 0x4003fac8 ); +PROVIDE ( rom_phy_pwdet_always_en = 0x40042c90 ); +PROVIDE ( rom_phy_pwdet_onetime_en = 0x40042ccc ); +PROVIDE ( rom_phy_rx11blr_cfg = 0x4003d91c ); +PROVIDE ( rom_phy_rx_sense_set = 0x4003ec58 ); +PROVIDE ( rom_phy_set_bbfreq_init = 0x40042b30 ); +PROVIDE ( rom_pll_correct_dcap = 0x400406ec ); +PROVIDE ( rom_pll_vol_cal = 0x40040948 ); +PROVIDE ( rom_pocket_sar_power = 0x40042b60 ); +PROVIDE ( rom_pow_usr = 0x4003ca20 ); +PROVIDE ( rom_pwdet_force_start = 0x40040ff0 ); +PROVIDE ( rom_pwdet_sar2_init = 0x40040e08 ); +PROVIDE ( rom_read_hw_noisefloor = 0x4003d6d0 ); +PROVIDE ( rom_read_sar2_code = 0x400429e8 ); +PROVIDE ( rom_read_sar_dout = 0x40040fb4 ); +PROVIDE ( rom_restart_cal = 0x4003f3c0 ); +PROVIDE ( rom_rfcal_pwrctrl = 0x400422b4 ); +PROVIDE ( rom_rfcal_rxiq = 0x40041af0 ); +PROVIDE ( rom_rfcal_txcap = 0x40041dfc ); +PROVIDE ( rom_rfpll_init = 0x4003f3b8 ); +PROVIDE ( rom_rfpll_set_freq = 0x4003f4cc ); +PROVIDE ( rom_rftx_init = 0x4003fa28 ); +PROVIDE ( rom_rtc_sar2_init = 0x40040d48 ); +PROVIDE ( rom_rxdc_est_min = 0x40041820 ); +PROVIDE ( rom_rx_gain_force = 0x4003d038 ); +PROVIDE ( rom_rxiq_cover_mg_mp = 0x40041a0c ); +PROVIDE ( rom_rxiq_get_mis = 0x40041874 ); +PROVIDE ( rom_rxiq_set_reg = 0x40041988 ); +PROVIDE ( rom_set_adc_rand = 0x4003e5dc ); +PROVIDE ( rom_set_cal_rxdc = 0x4003ca94 ); +PROVIDE ( rom_set_cca = 0x4003eac4 ); +PROVIDE ( rom_set_chan_cal_interp = 0x40041d20 ); +PROVIDE ( rom_set_channel_freq = 0x4003f534 ); +PROVIDE ( rom_set_loopback_gain = 0x4003ca38 ); +PROVIDE ( rom_set_noise_floor = 0x4003d6e8 ); +PROVIDE ( rom_set_pbus_mem = 0x4003cb78 ); +PROVIDE ( rom_set_pbus_reg = 0x4003e25c ); +PROVIDE ( rom_set_rf_freq_offset = 0x4003f73c ); +PROVIDE ( rom_set_rfpll_freq = 0x4003fce8 ); +PROVIDE ( rom_set_rxclk_en = 0x4003d0ac ); +PROVIDE ( rom_set_rx_comp = 0x4003e1d4 ); +PROVIDE ( rom_set_rx_sense = 0x4003d75c ); +PROVIDE ( rom_set_txcap_reg = 0x40041d74 ); +PROVIDE ( rom_set_txclk_en = 0x4003d07c ); +PROVIDE ( rom_set_tx_dig_gain = 0x4003cff4 ); +PROVIDE ( rom_set_tx_gain_table = 0x4003cd94 ); +PROVIDE ( rom_set_xpd_sar = 0x4003e290 ); +PROVIDE ( rom_spiflash_api_funcs = 0x3fcefbf4 ); +PROVIDE ( rom_spi_flash_cache2phys = 0x400505cc ); +PROVIDE ( rom_spi_flash_cache_enabled = 0x4004f08c ); +PROVIDE ( rom_spi_flash_check_and_flush_cache = 0x4005070c ); +PROVIDE ( rom_spi_flash_disable_cache = 0x4004f054 ); +PROVIDE ( rom_spi_flash_dump_counters = 0x40050850 ); +PROVIDE ( rom_spi_flash_enable_cache = 0x4004f0ac ); +PROVIDE ( rom_spi_flash_erase_range = 0x40050974 ); +PROVIDE ( rom_spi_flash_erase_sector = 0x40050a7c ); +PROVIDE ( rom_spi_flash_get_chip_size = 0x4005087c ); +PROVIDE ( rom_spi_flash_get_counters = 0x40050820 ); +PROVIDE ( rom_spi_flash_guard_get = 0x400508bc ); +PROVIDE ( rom_spi_flash_guard_set = 0x400508b0 ); +PROVIDE ( rom_spi_flash_hal_max_read_len = 0x3fcefba8 ); +PROVIDE ( rom_spi_flash_mmap = 0x400503b0 ); +PROVIDE ( rom_spi_flash_mmap_dump = 0x400504f4 ); +PROVIDE ( rom_spi_flash_mmap_get_free_pages = 0x40050550 ); +PROVIDE ( rom_spi_flash_mmap_os_func_set = 0x4005016c ); +PROVIDE ( rom_spi_flash_mmap_page_num_init = 0x4005017c ); +PROVIDE ( rom_spi_flash_mmap_pages = 0x400501cc ); +PROVIDE ( rom_spi_flash_munmap = 0x40050444 ); +PROVIDE ( rom_spi_flash_op_counters_config = 0x40050810 ); +PROVIDE ( rom_spi_flash_phys2cache = 0x40050660 ); +PROVIDE ( rom_spi_flash_read = 0x40050c4c ); +PROVIDE ( rom_spi_flash_read_encrypted = 0x40050f00 ); +PROVIDE ( rom_spi_flash_reset_counters = 0x40050828 ); +PROVIDE ( rom_spi_flash_restore_cache = 0x4004f070 ); +PROVIDE ( rom_spi_flash_safe_write_address_func_set = 0x400508c8 ); +PROVIDE ( rom_spi_flash_unlock = 0x400508d8 ); +PROVIDE ( rom_spi_flash_write = 0x40050a90 ); +PROVIDE ( rom_spi_flash_write_config_get = 0x400508a8 ); +PROVIDE ( rom_spi_flash_write_config_set = 0x4005088c ); +PROVIDE ( rom_spi_flash_write_encrypted = 0x40050e7c ); +PROVIDE ( rom_spur_cal = 0x4003e924 ); +PROVIDE ( rom_spur_reg_write_one_tone = 0x4003d2a4 ); +PROVIDE ( rom_start_tx_tone = 0x4003d1d0 ); +PROVIDE ( rom_start_tx_tone_step = 0x4003d0e8 ); +PROVIDE ( rom_stop_tx_tone = 0x4003e8d0 ); +PROVIDE ( _rom_store = 0x400568d0 ); +PROVIDE ( _rom_store_table = 0x40056700 ); +PROVIDE ( rom_target_power_add_backoff = 0x4004271c ); +PROVIDE ( rom_temp_to_power = 0x40042c5c ); +PROVIDE ( rom_test_rx_gain_cal = 0x40042d14 ); +PROVIDE ( rom_tsens_code_read = 0x40040554 ); +PROVIDE ( rom_tsens_dac_cal = 0x400405cc ); +PROVIDE ( rom_tsens_index_to_dac = 0x40040590 ); +PROVIDE ( rom_tsens_index_to_offset = 0x400405ac ); +PROVIDE ( rom_tsens_read_init = 0x40040434 ); +PROVIDE ( rom_txbbgain_to_index = 0x40040ae0 ); +PROVIDE ( rom_txcal_work_mode = 0x40040f14 ); +PROVIDE ( rom_txdc_cal_init = 0x40040b2c ); +PROVIDE ( rom_txdc_cal_v70 = 0x40040bc0 ); +PROVIDE ( rom_txiq_cover = 0x40041218 ); +PROVIDE ( rom_txiq_get_mis_pwr = 0x4004116c ); +PROVIDE ( rom_txiq_set_reg = 0x40040f44 ); +PROVIDE ( rom_tx_paon_set = 0x4003da6c ); +PROVIDE ( rom_tx_pwctrl_bg_init = 0x40042bfc ); +PROVIDE ( rom_tx_pwr_backoff = 0x400420d4 ); +PROVIDE ( rom_tx_state_set = 0x4003e4dc ); +PROVIDE ( rom_txtone_linear_pwr = 0x4004111c ); +PROVIDE ( rom_wait_rfpll_cal_end = 0x4003f488 ); +PROVIDE ( rom_wifi_11g_rate_chg = 0x4004247c ); +PROVIDE ( rom_wifi_rifs_mode_en = 0x4003d9ec ); +PROVIDE ( rom_wr_bt_tx_atten = 0x4003ceb0 ); +PROVIDE ( rom_wr_bt_tx_gain_mem = 0x4003cf48 ); +PROVIDE ( rom_write_dac_gain2 = 0x4003e6b8 ); +PROVIDE ( rom_write_gain_mem = 0x4003cd60 ); +PROVIDE ( rom_write_pll_cap_mem = 0x40040688 ); +PROVIDE ( rom_write_rfpll_sdm = 0x4003f420 ); +PROVIDE ( rom_write_txrate_power_offset = 0x40042510 ); +PROVIDE ( rom_write_wifi_dig_gain = 0x400426b8 ); +PROVIDE ( rom_wr_rf_freq_mem = 0x4003fdd0 ); +PROVIDE ( r_osi_funcs_p = 0x3fcef68c ); +PROVIDE ( roundup2 = 0x40056654 ); +PROVIDE ( r_phy_upd_proc_start = 0x40011220 ); +PROVIDE ( r_platform_reset = 0x400011a4 ); +PROVIDE ( r_plf_funcs_p = 0x3fcef690 ); +PROVIDE ( r_readbyte = 0x400068f4 ); +PROVIDE ( r_rf_em_init = 0x4002e65c ); +PROVIDE ( r_rf_force_agc_enable = 0x4002e714 ); +PROVIDE ( r_rf_reg_rd = 0x4002e648 ); +PROVIDE ( r_rf_reg_wr = 0x4002e650 ); +PROVIDE ( r_rf_reset = 0x4002e70c ); +PROVIDE ( r_rf_rssi_convert = 0x4002e69c ); +PROVIDE ( r_rf_rw_v9_le_disable = 0x40001ac8 ); +PROVIDE ( r_rf_rw_v9_le_enable = 0x40001ab0 ); +PROVIDE ( r_rf_sleep = 0x4002e730 ); +PROVIDE ( r_rf_txpwr_cs_get = 0x4002e6a8 ); +PROVIDE ( r_rf_txpwr_dbm_get = 0x4002e71c ); +PROVIDE ( r_rf_util_cs_fmt_convert = 0x4002eb88 ); +PROVIDE ( r_rwble_isr = 0x4002ec44 ); +PROVIDE ( r_rwble_sleep_enter = 0x4002f014 ); +PROVIDE ( r_rwble_sleep_wakeup_end = 0x4002f058 ); +PROVIDE ( r_rwbtdm_isr_wrapper = 0x4000949c ); +PROVIDE ( r_rw_crypto_aes_ccm = 0x400008c8 ); +PROVIDE ( r_rw_crypto_aes_encrypt = 0x40000ecc ); +PROVIDE ( r_rw_crypto_aes_init = 0x40000e34 ); +PROVIDE ( r_rw_crypto_aes_k1 = 0x40000b68 ); +PROVIDE ( r_rw_crypto_aes_k2 = 0x40000cc0 ); +PROVIDE ( r_rw_crypto_aes_k3 = 0x40000d68 ); +PROVIDE ( r_rw_crypto_aes_k4 = 0x40000dfc ); +PROVIDE ( r_rw_crypto_aes_rand = 0x40000f3c ); +PROVIDE ( r_rw_crypto_aes_result_handler = 0x40000f70 ); +PROVIDE ( r_rw_crypto_aes_s1 = 0x40001030 ); +PROVIDE ( r_rw_cryto_aes_cmac = 0x40000948 ); +PROVIDE ( r_rwip_active_check = 0x4002f90c ); +PROVIDE ( r_rwip_aes_encrypt = 0x4002faf8 ); +PROVIDE ( r_rwip_assert = 0x40030080 ); +PROVIDE ( r_rwip_crypt_evt_handler = 0x4002f1d8 ); +PROVIDE ( r_rwip_crypt_isr_handler = 0x4002f214 ); +PROVIDE ( r_rwip_eif_get = 0x400011f4 ); +PROVIDE ( r_rwip_half_slot_2_lpcycles = 0x4002f114 ); +PROVIDE ( r_rwip_hus_2_lpcycles = 0x4002f0dc ); +PROVIDE ( r_rwip_isr = 0x4002fc4c ); +PROVIDE ( r_rwip_lpcycles_2_hus = 0x4002f084 ); +PROVIDE ( r_rwip_prevent_sleep_clear = 0x4002f8e0 ); +PROVIDE ( r_rwip_prevent_sleep_set = 0x4002f8b8 ); +PROVIDE ( r_rwip_schedule = 0x4002ffd4 ); +PROVIDE ( r_rwip_sleep = 0x4002f520 ); +PROVIDE ( r_rwip_sw_int_handler = 0x4002f244 ); +PROVIDE ( r_rwip_sw_int_req = 0x4002fc08 ); +PROVIDE ( r_rwip_time_get = 0x4002f4c0 ); +PROVIDE ( r_rwip_timer_10ms_handler = 0x4002f1ac ); +PROVIDE ( r_rwip_timer_10ms_set = 0x4002f924 ); +PROVIDE ( r_rwip_timer_hs_handler = 0x4002f150 ); +PROVIDE ( r_rwip_timer_hs_set = 0x4002f9b0 ); +PROVIDE ( r_rwip_timer_hus_handler = 0x4002f17c ); +PROVIDE ( r_rwip_timer_hus_set = 0x4002fa30 ); +PROVIDE ( r_rwip_wakeup = 0x4002f288 ); +PROVIDE ( r_rwip_wakeup_end = 0x4002f3a0 ); +PROVIDE ( r_rwip_wlcoex_set = 0x4002fffc ); +PROVIDE ( r_rw_v9_init_em_radio_table = 0x40001900 ); +PROVIDE ( r_sch_alarm_clear = 0x40030234 ); +PROVIDE ( r_sch_alarm_init = 0x40030100 ); +PROVIDE ( r_sch_alarm_prog = 0x400300a4 ); +PROVIDE ( r_sch_alarm_set = 0x40030190 ); +PROVIDE ( r_sch_alarm_timer_isr = 0x40030124 ); +PROVIDE ( r_sch_arb_conflict_check = 0x4003028c ); +PROVIDE ( r_sch_arb_elt_cancel = 0x4003039c ); +PROVIDE ( r_sch_arb_event_start_isr = 0x40030a50 ); +PROVIDE ( r_sch_arb_init = 0x40030604 ); +PROVIDE ( r_sch_arb_insert = 0x40030640 ); +PROVIDE ( r_sch_arb_prog_timer = 0x4003052c ); +PROVIDE ( r_sch_arb_remove = 0x40030970 ); +PROVIDE ( r_sch_arb_sw_isr = 0x40030bd0 ); +PROVIDE ( r_sch_plan_chk = 0x400310c8 ); +PROVIDE ( r_sch_plan_clock_wrap_offset_update = 0x40030c98 ); +PROVIDE ( r_sch_plan_init = 0x40030fbc ); +PROVIDE ( r_sch_plan_interval_req = 0x40030f40 ); +PROVIDE ( r_sch_plan_offset_max_calc = 0x40030ccc ); +PROVIDE ( r_sch_plan_offset_req = 0x40030d68 ); +PROVIDE ( r_sch_plan_position_range_compute = 0x400310e8 ); +PROVIDE ( r_sch_plan_rem = 0x4003106c ); +PROVIDE ( r_sch_plan_req = 0x40031080 ); +PROVIDE ( r_sch_plan_set = 0x40030fe4 ); +PROVIDE ( r_sch_prog_end_isr = 0x4003159c ); +PROVIDE ( r_sch_prog_init = 0x400311f4 ); +PROVIDE ( r_sch_prog_push = 0x40031770 ); +PROVIDE ( r_sch_prog_rx_isr = 0x40031288 ); +PROVIDE ( r_sch_prog_skip_isr = 0x40031434 ); +PROVIDE ( r_sch_prog_tx_isr = 0x4003135c ); +PROVIDE ( r_sch_slice_bg_add = 0x40031cf4 ); +PROVIDE ( r_sch_slice_bg_remove = 0x40031d1c ); +PROVIDE ( r_sch_slice_compute = 0x40031bec ); +PROVIDE ( r_sch_slice_fg_add = 0x40031d48 ); +PROVIDE ( r_sch_slice_fg_remove = 0x40031d90 ); +PROVIDE ( r_sch_slice_init = 0x40031ca8 ); +PROVIDE ( r_sch_slice_per_add = 0x40031df0 ); +PROVIDE ( r_sch_slice_per_remove = 0x40031e44 ); +PROVIDE ( r_sdk_config_get_bt_sleep_enable = 0x40031ef0 ); +PROVIDE ( r_sdk_config_get_hl_derived_opts = 0x40031e9c ); +PROVIDE ( r_sdk_config_get_opts = 0x40031ebc ); +PROVIDE ( r_sdk_config_get_priv_opts = 0x40031ed8 ); +PROVIDE ( r_sdk_config_set_bt_sleep_enable = 0x40031ee4 ); +PROVIDE ( r_sdk_config_set_hl_derived_opts = 0x40031ea4 ); +PROVIDE ( r_sdk_config_set_opts = 0x40031ec4 ); +PROVIDE ( r_specialModP256 = 0x40004854 ); +PROVIDE ( r_SubtractBigHex256 = 0x40004224 ); +PROVIDE ( r_SubtractBigHexMod256 = 0x400044c4 ); +PROVIDE ( r_SubtractBigHexUint32_256 = 0x40004630 ); +PROVIDE ( r_SubtractFromSelfBigHex256 = 0x40004278 ); +PROVIDE ( r_SubtractFromSelfBigHexSign256 = 0x400043d4 ); +PROVIDE ( rtc_boot_control = 0x40045b90 ); +PROVIDE ( rtc_get_reset_reason = 0x40045abc ); +PROVIDE ( rtc_get_wakeup_cause = 0x40045ae0 ); +PROVIDE ( rtc_select_apb_bridge = 0x40045c24 ); +PROVIDE ( r_unloaded_area_init = 0x40001060 ); +PROVIDE ( r_vhci_flow_off = 0x4003200c ); +PROVIDE ( r_vhci_flow_on = 0x40032034 ); +PROVIDE ( r_vhci_notify_host_send_available = 0x40031fdc ); +PROVIDE ( r_vhci_send_to_host = 0x40032084 ); +PROVIDE ( r_vnd_hci_command_handler = 0x4000304c ); +PROVIDE ( rwble_env = 0x3fcefb20 ); +PROVIDE ( rwip_coex_cfg = 0x3ff091bb ); +PROVIDE ( rwip_env = 0x3fcefb28 ); +PROVIDE ( rwip_param = 0x3fcefb84 ); +PROVIDE ( rwip_priority = 0x3ff091c0 ); +PROVIDE ( rwip_prog_delay = 0x3fcefb44 ); +PROVIDE ( rwip_rf = 0x3fcefb4c ); +PROVIDE ( r_writebyte = 0x400068e4 ); +PROVIDE ( sbrk = 0x4003b964 ); +PROVIDE ( _sbrk_r = 0x400545e4 ); +PROVIDE ( _scanf_float = 0x40054818 ); +PROVIDE ( s_cdcacm_old_rts = 0x3fcef38c ); +PROVIDE ( sch_slice_params = 0x3fcefb94 ); +PROVIDE ( __sclose = 0x40054d90 ); +PROVIDE ( sdk_cfg_priv_opts = 0x3fcef40c ); +PROVIDE ( SelectSpiFunction = 0x4004cd2c ); +PROVIDE ( SelectSpiQIO = 0x4004cbb4 ); +PROVIDE ( SendMsg = 0x40049a44 ); +PROVIDE ( send_packet = 0x40049a00 ); +PROVIDE ( __seofread = 0x40054d1c ); +PROVIDE ( setjmp = 0x4003226c ); +PROVIDE ( setlocale = 0x40034068 ); +PROVIDE ( _setlocale_r = 0x40033ffc ); +PROVIDE ( set_rtc_memory_crc = 0x40045b74 ); +PROVIDE ( SetSpiDrvs = 0x4004cc48 ); +PROVIDE ( __sf_fake_stderr = 0x3ff0c524 ); +PROVIDE ( __sf_fake_stdin = 0x3ff0c564 ); +PROVIDE ( __sf_fake_stdout = 0x3ff0c544 ); +PROVIDE ( __sflush_r = 0x40033dc8 ); +PROVIDE ( __sfmoreglue = 0x40054ab4 ); +PROVIDE ( __sfp = 0x40054bdc ); +PROVIDE ( __sfp_lock_acquire = 0x40054c8c ); +PROVIDE ( __sfp_lock_release = 0x40054c98 ); +PROVIDE ( __sfputs_r = 0x40032d44 ); +PROVIDE ( __sfvwrite_r = 0x40033674 ); +PROVIDE ( sig_matrix = 0x3fcefc13 ); +PROVIDE ( __sinit = 0x40054af4 ); +PROVIDE ( __sinit_lock_acquire = 0x40054ca4 ); +PROVIDE ( __sinit_lock_release = 0x40054cb0 ); +PROVIDE ( __smakebuf_r = 0x40033d28 ); +PROVIDE ( software_reset = 0x40045bec ); +PROVIDE ( software_reset_cpu = 0x40045c04 ); +PROVIDE ( SPI_block_erase = 0x4004d214 ); +PROVIDE ( spi_cache_mode_switch = 0x4004d9f0 ); +PROVIDE ( SPI_chip_erase = 0x4004d188 ); +PROVIDE ( SPIClkConfig = 0x4004e198 ); +PROVIDE ( SPI_Common_Command = 0x4004d2bc ); +PROVIDE ( spi_common_set_dummy_output = 0x4004dcac ); +PROVIDE ( spi_common_set_flash_cs_timing = 0x4004dbf8 ); +PROVIDE ( spi_dummy_len_fix = 0x4004cb30 ); +PROVIDE ( SPI_Encrypt_Write = 0x4004fa5c ); +PROVIDE ( SPI_Encrypt_Write_Dest = 0x4004f908 ); +PROVIDE ( SPIEraseArea = 0x4004e5cc ); +PROVIDE ( SPIEraseBlock = 0x4004e204 ); +PROVIDE ( SPIEraseChip = 0x4004e1e4 ); +PROVIDE ( SPIEraseSector = 0x4004e278 ); +PROVIDE ( spi_flash_attach = 0x4004e100 ); +PROVIDE ( spi_flash_boot_attach = 0x4004e0a0 ); +PROVIDE ( SPI_flashchip_data = 0x3fcefbdc ); +PROVIDE ( spi_flash_chip_gd_get_io_mode = 0x4004f248 ); +PROVIDE ( spi_flash_chip_gd_probe = 0x4004f1d8 ); +PROVIDE ( spi_flash_chip_gd_set_io_mode = 0x4004f20c ); +PROVIDE ( spi_flash_chip_generic_config_host_io_mode = 0x4004f6e0 ); +PROVIDE ( spi_flash_chip_generic_detect_size = 0x4004f368 ); +PROVIDE ( spi_flash_chip_generic_erase_block = 0x4004f454 ); +PROVIDE ( spi_flash_chip_generic_erase_chip = 0x4004f39c ); +PROVIDE ( spi_flash_chip_generic_erase_sector = 0x4004f3f8 ); +PROVIDE ( spi_flash_chip_generic_get_io_mode = 0x4004f7d4 ); +PROVIDE ( spi_flash_chip_generic_get_write_protect = 0x4004f5e0 ); +PROVIDE ( spi_flash_chip_generic_page_program = 0x4004f4b0 ); +PROVIDE ( spi_flash_chip_generic_probe = 0x4004f30c ); +PROVIDE ( spi_flash_chip_generic_read = 0x4004f740 ); +PROVIDE ( spi_flash_chip_generic_reset = 0x4004f314 ); +PROVIDE ( spi_flash_chip_generic_set_io_mode = 0x4004f898 ); +PROVIDE ( spi_flash_chip_generic_set_write_protect = 0x4004f594 ); +PROVIDE ( spi_flash_chip_generic_wait_idle = 0x4004f660 ); +PROVIDE ( spi_flash_chip_generic_write = 0x4004f4e4 ); +PROVIDE ( spi_flash_chip_generic_write_encrypted = 0x4004f58c ); +PROVIDE ( spi_flash_common_read_status_16b_rdsr_rdsr2 = 0x4004f2dc ); +PROVIDE ( spi_flash_common_read_status_8b_rdsr = 0x4004f7f0 ); +PROVIDE ( spi_flash_common_read_status_8b_rdsr2 = 0x4004f7c4 ); +PROVIDE ( spi_flash_common_set_io_mode = 0x4004f828 ); +PROVIDE ( spi_flash_common_write_status_16b_wrsr = 0x4004f294 ); +PROVIDE ( spi_flash_common_write_status_8b_wrsr = 0x4004f800 ); +PROVIDE ( spi_flash_common_write_status_8b_wrsr2 = 0x4004f814 ); +PROVIDE ( SPI_flash_func = 0x3fcefbb0 ); +PROVIDE ( spi_flash_generic_wait_host_idle = 0x4004f61c ); +PROVIDE ( spi_flash_hal_common_command = 0x4004fd8c ); +PROVIDE ( spi_flash_hal_configure_host_io_mode = 0x4004fbac ); +PROVIDE ( spi_flash_hal_device_config = 0x4004fb44 ); +PROVIDE ( spi_flash_hal_erase_block = 0x4004ff94 ); +PROVIDE ( spi_flash_hal_erase_chip = 0x4004ff1c ); +PROVIDE ( spi_flash_hal_erase_sector = 0x4004ff40 ); +PROVIDE ( spi_flash_hal_host_idle = 0x40050088 ); +PROVIDE ( spi_flash_hal_poll_cmd_done = 0x4004fb1c ); +PROVIDE ( spi_flash_hal_program_page = 0x4004ffe0 ); +PROVIDE ( spi_flash_hal_read = 0x4004fe8c ); +PROVIDE ( spi_flash_hal_set_write_protect = 0x40050054 ); +PROVIDE ( spi_flash_set_check_suspend_cb = 0x4004cb1c ); +PROVIDE ( SPI_init = 0x4004dcf0 ); +PROVIDE ( SPILock = 0x4004dfb0 ); +PROVIDE ( SPIMasterReadModeCnfig = 0x4004e110 ); +PROVIDE ( SPIMEM0 = 0x60003000 ); +PROVIDE ( SPIMEM1 = 0x60002000 ); +PROVIDE ( SPI_page_program = 0x4004d584 ); +PROVIDE ( SPIParamCfg = 0x4004e670 ); +PROVIDE ( SPIRead = 0x4004e3cc ); +PROVIDE ( SPI_read_data = 0x4004cea8 ); +PROVIDE ( SPIReadModeCnfig = 0x4004dff8 ); +PROVIDE ( SPI_read_status = 0x4004d054 ); +PROVIDE ( SPI_read_status_high = 0x4004d258 ); +PROVIDE ( SPI_sector_erase = 0x4004d1c0 ); +PROVIDE ( spi_set_dummy_output = 0x4004cb64 ); +PROVIDE ( spi_slave_download = 0x40053df0 ); +PROVIDE ( spi_slave_rom_check_conn = 0x40053a60 ); +PROVIDE ( spi_slave_rom_init = 0x40053ab0 ); +PROVIDE ( spi_slave_rom_init_hw = 0x40053fd8 ); +PROVIDE ( spi_slave_rom_intr_enable = 0x40053fa0 ); +PROVIDE ( spi_slave_rom_rxdma_load = 0x400542a4 ); +PROVIDE ( spi_slave_rom_txdma_load = 0x4005433c ); +PROVIDE ( SPIUnlock = 0x4004df54 ); +PROVIDE ( SPI_user_command_read = 0x4004cf98 ); +PROVIDE ( SPI_Wait_Idle = 0x4004d664 ); +PROVIDE ( SPI_WakeUp = 0x4004d0c4 ); +PROVIDE ( SPIWrite = 0x4004e2ec ); +PROVIDE ( SPI_write_enable = 0x4004d530 ); +PROVIDE ( SPI_Write_Encrypt_Disable = 0x4004f8d0 ); +PROVIDE ( SPI_Write_Encrypt_Enable = 0x4004f8b4 ); +PROVIDE ( SPI_write_status = 0x4004d278 ); +PROVIDE ( __sprint_r = 0x40032d90 ); +PROVIDE ( srand = 0x4003a094 ); +PROVIDE ( __sread = 0x40054cec ); +PROVIDE ( __sseek = 0x40054d5c ); +PROVIDE ( __stack = 0x3fceb910 ); +PROVIDE ( __stack_app = 0x3fced910 ); +PROVIDE ( _stack_sentry = 0x3fce9910 ); +PROVIDE ( _stack_sentry_app = 0x3fceb910 ); +PROVIDE ( _start = 0x4003959c ); +PROVIDE ( _stat_r = 0x400545b4 ); +PROVIDE ( _stext = 0x40039438 ); +PROVIDE ( strcasecmp = 0x4003a1bc ); +PROVIDE ( strcasestr = 0x4003a850 ); +PROVIDE ( strcat = 0x4003aba8 ); +PROVIDE ( strchr = 0x4003abec ); +PROVIDE ( strcmp = 0x4003acd8 ); +PROVIDE ( strcoll = 0x4003adfc ); +PROVIDE ( strcpy = 0x4003ae10 ); +PROVIDE ( strcspn = 0x4005575c ); +PROVIDE ( strdup = 0x4003aea0 ); +PROVIDE ( _strdup_r = 0x4003aeb4 ); +PROVIDE ( string0_descr = 0x3ff0c1f6 ); +PROVIDE ( strlcat = 0x4003aed4 ); +PROVIDE ( strlcpy = 0x40055798 ); +PROVIDE ( strlen = 0x4003af3c ); +PROVIDE ( strlwr = 0x4003afa0 ); +PROVIDE ( str_manu_descr = 0x3ff0c1e2 ); +PROVIDE ( strncasecmp = 0x4003afd0 ); +PROVIDE ( strncat = 0x4003b028 ); +PROVIDE ( strncmp = 0x4003b088 ); +PROVIDE ( strncpy = 0x4003b178 ); +PROVIDE ( strndup = 0x4003b254 ); +PROVIDE ( _strndup_r = 0x4003b268 ); +PROVIDE ( strnlen = 0x400557d8 ); +PROVIDE ( str_prod_descr = 0x3ff0c1d0 ); +PROVIDE ( strrchr = 0x4003b2b8 ); +PROVIDE ( strsep = 0x4003b2e4 ); +PROVIDE ( str_serial_descr = 0x3fcef08c ); +PROVIDE ( strspn = 0x4005580c ); +PROVIDE ( strstr = 0x4003b674 ); +PROVIDE ( __strtok_r = 0x40055848 ); +PROVIDE ( strtok_r = 0x400558a4 ); +PROVIDE ( strtol = 0x40032b14 ); +PROVIDE ( strtol_l = 0x40032afc ); +PROVIDE ( _strtol_r = 0x40032ad8 ); +PROVIDE ( strtoul = 0x40032c84 ); +PROVIDE ( strtoul_l = 0x40032c6c ); +PROVIDE ( _strtoul_r = 0x40032c48 ); +PROVIDE ( strupr = 0x4003b8bc ); +PROVIDE ( __subdf3 = 0x4003beb0 ); +PROVIDE ( __subsf3 = 0x4003bad8 ); +PROVIDE ( __subvdi3 = 0x4003c4ec ); +PROVIDE ( __subvsi3 = 0x4003c4c8 ); +PROVIDE ( s_usb_osglue = 0x3fcef334 ); +PROVIDE ( __swbuf = 0x40033a34 ); +PROVIDE ( __swbuf_r = 0x4003396c ); +PROVIDE ( __swhatbuf_r = 0x40033cd4 ); +PROVIDE ( __swrite = 0x40054d24 ); +PROVIDE ( __swsetup_r = 0x40033a48 ); +PROVIDE ( sw_to_hw = 0x3fcef8e4 ); +PROVIDE ( _SyscallException = 0x40039677 ); +PROVIDE ( syscall_table_ptr = 0x3fcefcc8 ); +PROVIDE ( _system_r = 0x40054510 ); +PROVIDE ( TASK_DESC_DBG = 0x3fcef3a0 ); +PROVIDE ( TASK_DESC_LLC = 0x3fcef3e8 ); +PROVIDE ( TASK_DESC_LLM = 0x3fcef3f8 ); +PROVIDE ( TASK_DESC_MISC = 0x3ff090d8 ); +PROVIDE ( tdefl_compress = 0x40036610 ); +PROVIDE ( tdefl_compress_buffer = 0x40036d6c ); +PROVIDE ( tdefl_compress_mem_to_mem = 0x40036e84 ); +PROVIDE ( tdefl_compress_mem_to_output = 0x40036e64 ); +PROVIDE ( tdefl_get_adler32 = 0x40036e5c ); +PROVIDE ( tdefl_get_prev_return_status = 0x40036e54 ); +PROVIDE ( tdefl_init = 0x40036d88 ); +PROVIDE ( tdefl_write_image_to_png_file_in_memory = 0x40036e98 ); +PROVIDE ( tdefl_write_image_to_png_file_in_memory_ex = 0x40036e8c ); +PROVIDE ( _text_end = 0x400568d0 ); +PROVIDE ( _text_end_btdm_rom = 0x40032170 ); +PROVIDE ( _text_start = 0x40039438 ); +PROVIDE ( _text_start_btdm_rom = 0x4000056c ); +PROVIDE ( timer_env = 0x3fcefb9c ); +PROVIDE ( _times_r = 0x40054540 ); +PROVIDE ( tinfl_decompress = 0x4003542c ); +PROVIDE ( tinfl_decompress_mem_to_callback = 0x400365e4 ); +PROVIDE ( tinfl_decompress_mem_to_mem = 0x400365a4 ); +PROVIDE ( toascii = 0x400558b8 ); +PROVIDE ( tolower = 0x4003b990 ); +PROVIDE ( toupper = 0x4003b9ac ); +PROVIDE ( __truncdfsf2 = 0x4003c35c ); +PROVIDE ( uart_acm_dev = 0x3fcef350 ); +PROVIDE ( uartAttach = 0x40049414 ); +PROVIDE ( uart_baudrate_detect = 0x40049474 ); +PROVIDE ( uart_buff_switch = 0x40049a9c ); +PROVIDE ( UartConnCheck = 0x400485d8 ); +PROVIDE ( UartConnectProc = 0x400488d8 ); +PROVIDE ( UartDev = 0x3fcef354 ); +PROVIDE ( uart_div_modify = 0x40049568 ); +PROVIDE ( uart_div_reinit = 0x400495e0 ); +PROVIDE ( UartDwnLdProc = 0x40048d10 ); +PROVIDE ( UartGetCmdLn = 0x40049c7c ); +PROVIDE ( Uart_Init = 0x40049624 ); +PROVIDE ( Uart_Init_USB = 0x4004939c ); +PROVIDE ( UartRegReadProc = 0x4004893c ); +PROVIDE ( UartRegWriteProc = 0x400488e8 ); +PROVIDE ( uart_rx_intr_handler = 0x400491ec ); +PROVIDE ( uart_rx_one_char = 0x40049918 ); +PROVIDE ( uart_rx_one_char_block = 0x400498bc ); +PROVIDE ( uart_rx_readbuff = 0x40049a54 ); +PROVIDE ( UartRxString = 0x400499bc ); +PROVIDE ( UartSecureDwnLdProc = 0x40048fd8 ); +PROVIDE ( UartSetBaudProc = 0x400489b0 ); +PROVIDE ( UartSpiAttachProc = 0x40048964 ); +PROVIDE ( UartSpiReadProc = 0x40048980 ); +PROVIDE ( uart_tx_flush = 0x40049850 ); +PROVIDE ( uart_tx_one_char = 0x40049820 ); +PROVIDE ( uart_tx_one_char2 = 0x40049838 ); +PROVIDE ( uart_tx_switch = 0x40049468 ); +PROVIDE ( uart_tx_wait_idle = 0x40049884 ); +PROVIDE ( uart_usb_enable_reset_on_rts = 0x400493dc ); +PROVIDE ( Uart_USB_Send_Testament = 0x4004935c ); +PROVIDE ( __ucmpdi2 = 0x40037ed8 ); +PROVIDE ( __udivdi3 = 0x40056160 ); +PROVIDE ( __udivmoddi4 = 0x40039140 ); +PROVIDE ( __udivsi3 = 0x400558d8 ); +PROVIDE ( __udiv_w_sdiv = 0x40039138 ); +PROVIDE ( __umoddi3 = 0x400563e4 ); +PROVIDE ( __umodsi3 = 0x400558e0 ); +PROVIDE ( __umulsidi3 = 0x400558e8 ); +PROVIDE ( _unlink_r = 0x40054584 ); +PROVIDE ( unloaded_area = 0x3fcef8dc ); +PROVIDE ( __unorddf2 = 0x40037e8c ); +PROVIDE ( __unordsf2 = 0x40037b10 ); +PROVIDE ( usb_cancel_transfer = 0x4004bfd0 ); +PROVIDE ( usb_data_stuff = 0x3ff0938c ); +PROVIDE ( usb_dc_attach = 0x4004ac1c ); +PROVIDE ( usb_dc_check_poll_for_interrupts = 0x4004b6d0 ); +PROVIDE ( usb_dc_detach = 0x4004ad60 ); +PROVIDE ( usb_dc_ep_check_cap = 0x4004ade4 ); +PROVIDE ( usb_dc_ep_clear_stall = 0x4004b040 ); +PROVIDE ( usb_dc_ep_configure = 0x4004ae28 ); +PROVIDE ( usb_dc_ep_disable = 0x4004b23c ); +PROVIDE ( usb_dc_ep_enable = 0x4004b17c ); +PROVIDE ( usb_dc_ep_flush = 0x4004b308 ); +PROVIDE ( usb_dc_ep_halt = 0x4004b0ac ); +PROVIDE ( usb_dc_ep_is_stalled = 0x4004b10c ); +PROVIDE ( usb_dc_ep_mps = 0x4004b6a8 ); +PROVIDE ( usb_dc_ep_read = 0x4004b628 ); +PROVIDE ( usb_dc_ep_read_continue = 0x4004b5e8 ); +PROVIDE ( usb_dc_ep_read_wait = 0x4004b50c ); +PROVIDE ( usb_dc_ep_set_callback = 0x4004b660 ); +PROVIDE ( usb_dc_ep_set_stall = 0x4004afe0 ); +PROVIDE ( usb_dc_ep_write = 0x4004b3d4 ); +PROVIDE ( usb_dc_ep_write_would_block = 0x4004b374 ); +PROVIDE ( usb_dc_prepare_persist = 0x4004a92c ); +PROVIDE ( usb_dc_reset = 0x4004ad94 ); +PROVIDE ( usb_dc_set_address = 0x4004adac ); +PROVIDE ( usb_dc_set_status_callback = 0x4004b69c ); +PROVIDE ( usb_deconfig = 0x4004bd70 ); +PROVIDE ( usb_dev_get_configuration = 0x4004bd14 ); +PROVIDE ( usb_dev_resume = 0x4004bd00 ); +PROVIDE ( usb_dfu_force_detach = 0x4004c380 ); +PROVIDE ( usb_dfu_init = 0x4004c368 ); +PROVIDE ( usb_dfu_set_detach_cb = 0x4004c0ac ); +PROVIDE ( usb_disable = 0x4004be20 ); +PROVIDE ( usb_dw_isr_handler = 0x4004a98c ); +PROVIDE ( usb_enable = 0x4004bd90 ); +PROVIDE ( usb_ep_clear_stall = 0x4004be90 ); +PROVIDE ( usb_ep_read_continue = 0x4004beb8 ); +PROVIDE ( usb_ep_read_wait = 0x4004bea0 ); +PROVIDE ( usb_ep_set_stall = 0x4004be80 ); +PROVIDE ( usb_get_descriptor = 0x4004b77c ); +PROVIDE ( usb_read = 0x4004be68 ); +PROVIDE ( usb_set_config = 0x4004bd2c ); +PROVIDE ( usb_set_current_descriptor = 0x4004b764 ); +PROVIDE ( usb_transfer = 0x4004bf1c ); +PROVIDE ( usb_transfer_ep_callback = 0x4004bec8 ); +PROVIDE ( usb_transfer_sync = 0x4004c020 ); +PROVIDE ( usb_write = 0x4004be50 ); +PROVIDE ( usb_write_would_block = 0x4004be40 ); +PROVIDE ( user_code_start = 0x3fced914 ); +PROVIDE ( _UserExceptionVector = 0x40000340 ); +PROVIDE ( _UserExceptionVector_text_end = 0x40000365 ); +PROVIDE ( _UserExceptionVector_text_start = 0x40000340 ); +PROVIDE ( utoa = 0x4003225c ); +PROVIDE ( __utoa = 0x400321f4 ); +PROVIDE ( VerifyFlashMd5Proc = 0x40048b58 ); +PROVIDE ( veryBigHexP256 = 0x3ff080f4 ); +PROVIDE ( vfiprintf = 0x400330f4 ); +PROVIDE ( _vfiprintf_r = 0x40032df8 ); +PROVIDE ( vflash_mem = 0x3fcef998 ); +PROVIDE ( vfprintf = 0x400330f4 ); +PROVIDE ( _vfprintf_r = 0x40032df8 ); +PROVIDE ( vhci_env_p = 0x3fcefba4 ); +PROVIDE ( vnd_hci_command_handler_wrapper = 0x40002f20 ); +PROVIDE ( Wait_SPI_Idle = 0x4004d158 ); +PROVIDE ( wcrtomb = 0x40033618 ); +PROVIDE ( _wcrtomb_r = 0x400335c0 ); +PROVIDE ( _wctomb_r = 0x40033c88 ); +PROVIDE ( _WindowOverflow12 = 0x40000100 ); +PROVIDE ( _WindowOverflow4 = 0x40000000 ); +PROVIDE ( _WindowOverflow8 = 0x40000080 ); +PROVIDE ( _WindowUnderflow12 = 0x40000140 ); +PROVIDE ( _WindowUnderflow4 = 0x40000040 ); +PROVIDE ( _WindowUnderflow8 = 0x400000c0 ); +PROVIDE ( _WindowVectors_text_end = 0x40000170 ); +PROVIDE ( _WindowVectors_text_start = 0x40000000 ); +PROVIDE ( write = 0x4003b978 ); +PROVIDE ( _write_r = 0x40054670 ); +PROVIDE ( __XT_EXCEPTION_DESCS__ = 0x3ff0fff0 ); +PROVIDE ( __XT_EXCEPTION_DESCS_END__ = 0x3ff0fff0 ); +PROVIDE ( __XT_EXCEPTION_TABLE__ = 0x3ff0ff00 ); +PROVIDE ( xthal_bcopy = 0x400552ac ); +PROVIDE ( xthal_copy123 = 0x40055338 ); +PROVIDE ( xthal_get_ccompare = 0x4005543c ); +PROVIDE ( xthal_get_ccount = 0x40055410 ); +PROVIDE ( xthal_get_interrupt = 0x4005545c ); +PROVIDE ( Xthal_intlevel = 0x3ff0c504 ); +PROVIDE ( xthal_memcpy = 0x400552d0 ); +PROVIDE ( xthal_set_ccompare = 0x40055418 ); +PROVIDE ( xthal_set_intclear = 0x40055464 ); +PROVIDE ( xthals_hw_configid0 = 0xc2f0fffe ); +PROVIDE ( xthals_hw_configid1 = 0x23086d67 ); +PROVIDE ( xthal_spill_registers_into_stack_nw = 0x400548f8 ); +PROVIDE ( xthals_release_major = 0x00002ee0 ); +PROVIDE ( xthals_release_minor = 0x0000000c ); +PROVIDE ( xthal_window_spill = 0x40054a0c ); +PROVIDE ( xthal_window_spill_nw = 0x400548f8 ); +PROVIDE ( _xtos_alloca_handler = 0x40000010 ); +PROVIDE ( xtos_cause3_handler = 0x400396bc ); +PROVIDE ( xtos_c_handler_table = 0x3fcee27c ); +PROVIDE ( xtos_c_wrapper_handler = 0x400396cc ); +PROVIDE ( _xtos_enabled = 0x3fcee388 ); +PROVIDE ( xtos_exc_handler_table = 0x3fcee17c ); +PROVIDE ( xtos_interrupt_mask_table = 0x3fcee490 ); +PROVIDE ( xtos_interrupt_table = 0x3fcee390 ); +PROVIDE ( _xtos_ints_off = 0x400548d0 ); +PROVIDE ( _xtos_ints_on = 0x400548ac ); +PROVIDE ( _xtos_intstruct = 0x3fcee388 ); +PROVIDE ( _xtos_l1int_handler = 0x40039790 ); +PROVIDE ( xtos_p_none = 0x40055234 ); +PROVIDE ( _xtos_restore_intlevel = 0x400398a0 ); +PROVIDE ( _xtos_return_from_exc = 0x4005523c ); +PROVIDE ( _xtos_set_exception_handler = 0x400395f0 ); +PROVIDE ( _xtos_set_interrupt_handler = 0x40054870 ); +PROVIDE ( _xtos_set_interrupt_handler_arg = 0x40054834 ); +PROVIDE ( _xtos_set_intlevel = 0x40055254 ); +PROVIDE ( _xtos_set_min_intlevel = 0x40055270 ); +PROVIDE ( _xtos_set_vpri = 0x400398ac ); +PROVIDE ( _xtos_syscall_handler = 0x40039638 ); +PROVIDE ( xtos_unhandled_exception = 0x40055294 ); +PROVIDE ( xtos_unhandled_interrupt = 0x400552a4 ); +PROVIDE ( _xtos_vectors_ref_ = 0x00000000 ); +PROVIDE ( _xtos_vpri_enabled = 0x3fcee38c ); diff --git a/tools/flasher_stub/ld/rom_8266.ld b/tools/flasher_stub/ld/rom_8266.ld new file mode 100644 index 0000000000..9269fa2de5 --- /dev/null +++ b/tools/flasher_stub/ld/rom_8266.ld @@ -0,0 +1,351 @@ +PROVIDE ( Cache_Read_Disable = 0x400047f0 ); +PROVIDE ( Cache_Read_Enable = 0x40004678 ); +PROVIDE ( FilePacketSendReqMsgProc = 0x400035a0 ); +PROVIDE ( FlashDwnLdParamCfgMsgProc = 0x4000368c ); +PROVIDE ( FlashDwnLdStartMsgProc = 0x40003538 ); +PROVIDE ( FlashDwnLdStopReqMsgProc = 0x40003658 ); +PROVIDE ( GetUartDevice = 0x40003f4c ); +PROVIDE ( MD5Final = 0x40009900 ); +PROVIDE ( MD5Init = 0x40009818 ); +PROVIDE ( MD5Update = 0x40009834 ); +PROVIDE ( MemDwnLdStartMsgProc = 0x400036c4 ); +PROVIDE ( MemDwnLdStopReqMsgProc = 0x4000377c ); +PROVIDE ( MemPacketSendReqMsgProc = 0x400036f0 ); +PROVIDE ( RcvMsg = 0x40003eac ); +PROVIDE ( SHA1Final = 0x4000b648 ); +PROVIDE ( SHA1Init = 0x4000b584 ); +PROVIDE ( SHA1Transform = 0x4000a364 ); +PROVIDE ( SHA1Update = 0x4000b5a8 ); +PROVIDE ( SPI_read_status = 0x400043c8 ); +PROVIDE ( SPI_write_status = 0x40004400 ); +PROVIDE ( SPI_write_enable = 0x4000443c ); +PROVIDE ( Wait_SPI_Idle = 0x4000448c ); +PROVIDE ( Enable_QMode = 0x400044c0 ); +PROVIDE ( SPIEraseArea = 0x40004b44 ); +PROVIDE ( SPIEraseBlock = 0x400049b4 ); +PROVIDE ( SPIEraseChip = 0x40004984 ); +PROVIDE ( SPIEraseSector = 0x40004a00 ); +PROVIDE ( SPILock = 0x400048a8 ); +PROVIDE ( SPIParamCfg = 0x40004c2c ); +PROVIDE ( SPIRead = 0x40004b1c ); +PROVIDE ( SPIReadModeCnfig = 0x400048ec ); +PROVIDE ( SPIUnlock = 0x40004878 ); +PROVIDE ( SPIWrite = 0x40004a4c ); +PROVIDE ( SelectSpiFunction = 0x40003f58 ); +PROVIDE ( SendMsg = 0x40003cf4 ); +PROVIDE ( UartConnCheck = 0x40003230 ); +PROVIDE ( UartConnectProc = 0x400037a0 ); +PROVIDE ( UartDwnLdProc = 0x40003368 ); +PROVIDE ( UartGetCmdLn = 0x40003ef4 ); +PROVIDE ( UartRegReadProc = 0x4000381c ); +PROVIDE ( UartRegWriteProc = 0x400037ac ); +PROVIDE ( UartRxString = 0x40003c30 ); +PROVIDE ( Uart_Init = 0x40003a14 ); +PROVIDE ( _DebugExceptionVector = 0x40000010 ); +PROVIDE ( _DoubleExceptionVector = 0x40000070 ); +PROVIDE ( _KernelExceptionVector = 0x40000030 ); +PROVIDE ( _NMIExceptionVector = 0x40000020 ); +PROVIDE ( _ResetHandler = 0x400000a4 ); +PROVIDE ( _ResetVector = 0x40000080 ); +PROVIDE ( _UserExceptionVector = 0x40000050 ); +PROVIDE ( __adddf3 = 0x4000c538 ); +PROVIDE ( __addsf3 = 0x4000c180 ); +PROVIDE ( __divdf3 = 0x4000cb94 ); +PROVIDE ( __divdi3 = 0x4000ce60 ); +PROVIDE ( __divsi3 = 0x4000dc88 ); +PROVIDE ( __extendsfdf2 = 0x4000cdfc ); +PROVIDE ( __fixdfsi = 0x4000ccb8 ); +PROVIDE ( __fixunsdfsi = 0x4000cd00 ); +PROVIDE ( __fixunssfsi = 0x4000c4c4 ); +PROVIDE ( __floatsidf = 0x4000e2f0 ); +PROVIDE ( __floatsisf = 0x4000e2ac ); +PROVIDE ( __floatunsidf = 0x4000e2e8 ); +PROVIDE ( __floatunsisf = 0x4000e2a4 ); +PROVIDE ( __muldf3 = 0x4000c8f0 ); +PROVIDE ( __muldi3 = 0x40000650 ); +PROVIDE ( __mulsf3 = 0x4000c3dc ); +PROVIDE ( __subdf3 = 0x4000c688 ); +PROVIDE ( __subsf3 = 0x4000c268 ); +PROVIDE ( __truncdfsf2 = 0x4000cd5c ); +PROVIDE ( __udivdi3 = 0x4000d310 ); +PROVIDE ( __udivsi3 = 0x4000e21c ); +PROVIDE ( __umoddi3 = 0x4000d770 ); +PROVIDE ( __umodsi3 = 0x4000e268 ); +PROVIDE ( __umulsidi3 = 0x4000dcf0 ); +PROVIDE ( _rom_store = 0x4000e388 ); +PROVIDE ( _rom_store_table = 0x4000e328 ); +PROVIDE ( _start = 0x4000042c ); +PROVIDE ( _xtos_alloca_handler = 0x4000dbe0 ); +PROVIDE ( _xtos_c_wrapper_handler = 0x40000598 ); +PROVIDE ( _xtos_cause3_handler = 0x40000590 ); +PROVIDE ( _xtos_ints_off = 0x4000bda4 ); +PROVIDE ( _xtos_ints_on = 0x4000bd84 ); +PROVIDE ( _xtos_l1int_handler = 0x4000048c ); +PROVIDE ( _xtos_p_none = 0x4000dbf8 ); +PROVIDE ( _xtos_restore_intlevel = 0x4000056c ); +PROVIDE ( _xtos_return_from_exc = 0x4000dc54 ); +PROVIDE ( _xtos_set_exception_handler = 0x40000454 ); +PROVIDE ( _xtos_set_interrupt_handler = 0x4000bd70 ); +PROVIDE ( _xtos_set_interrupt_handler_arg = 0x4000bd28 ); +PROVIDE ( _xtos_set_intlevel = 0x4000dbfc ); +PROVIDE ( _xtos_set_min_intlevel = 0x4000dc18 ); +PROVIDE ( _xtos_set_vpri = 0x40000574 ); +PROVIDE ( _xtos_syscall_handler = 0x4000dbe4 ); +PROVIDE ( _xtos_unhandled_exception = 0x4000dc44 ); +PROVIDE ( _xtos_unhandled_interrupt = 0x4000dc3c ); +PROVIDE ( aes_decrypt = 0x400092d4 ); +PROVIDE ( aes_decrypt_deinit = 0x400092e4 ); +PROVIDE ( aes_decrypt_init = 0x40008ea4 ); +PROVIDE ( aes_unwrap = 0x40009410 ); +PROVIDE ( base64_decode = 0x40009648 ); +PROVIDE ( base64_encode = 0x400094fc ); +PROVIDE ( bzero = 0x4000de84 ); +PROVIDE ( cmd_parse = 0x40000814 ); +PROVIDE ( conv_str_decimal = 0x40000b24 ); +PROVIDE ( conv_str_hex = 0x40000cb8 ); +PROVIDE ( convert_para_str = 0x40000a60 ); +PROVIDE ( dtm_get_intr_mask = 0x400026d0 ); +PROVIDE ( dtm_params_init = 0x4000269c ); +PROVIDE ( dtm_set_intr_mask = 0x400026c8 ); +PROVIDE ( dtm_set_params = 0x400026dc ); +PROVIDE ( eprintf = 0x40001d14 ); +PROVIDE ( eprintf_init_buf = 0x40001cb8 ); +PROVIDE ( eprintf_to_host = 0x40001d48 ); +PROVIDE ( est_get_printf_buf_remain_len = 0x40002494 ); +PROVIDE ( est_reset_printf_buf_len = 0x4000249c ); +PROVIDE ( ets_bzero = 0x40002ae8 ); +PROVIDE ( ets_char2xdigit = 0x40002b74 ); +PROVIDE ( ets_delay_us = 0x40002ecc ); +PROVIDE ( ets_enter_sleep = 0x400027b8 ); +PROVIDE ( ets_external_printf = 0x40002578 ); +PROVIDE ( ets_get_cpu_frequency = 0x40002f0c ); +PROVIDE ( ets_getc = 0x40002bcc ); +PROVIDE ( ets_install_external_printf = 0x40002450 ); +PROVIDE ( ets_install_putc1 = 0x4000242c ); +PROVIDE ( ets_install_putc2 = 0x4000248c ); +PROVIDE ( ets_install_uart_printf = 0x40002438 ); +PROVIDE ( ets_intr_lock = 0x40000f74 ); +PROVIDE ( ets_intr_unlock = 0x40000f80 ); +PROVIDE ( ets_isr_attach = 0x40000f88 ); +PROVIDE ( ets_isr_mask = 0x40000f98 ); +PROVIDE ( ets_isr_unmask = 0x40000fa8 ); +PROVIDE ( ets_memcmp = 0x400018d4 ); +PROVIDE ( ets_memcpy = 0x400018b4 ); +PROVIDE ( ets_memmove = 0x400018c4 ); +PROVIDE ( ets_memset = 0x400018a4 ); +PROVIDE ( ets_post = 0x40000e24 ); +PROVIDE ( ets_printf = 0x400024cc ); +PROVIDE ( ets_putc = 0x40002be8 ); +PROVIDE ( ets_rtc_int_register = 0x40002a40 ); +PROVIDE ( ets_run = 0x40000e04 ); +PROVIDE ( ets_set_idle_cb = 0x40000dc0 ); +PROVIDE ( ets_set_user_start = 0x40000fbc ); +PROVIDE ( ets_str2macaddr = 0x40002af8 ); +PROVIDE ( ets_strcmp = 0x40002aa8 ); +PROVIDE ( ets_strcpy = 0x40002a88 ); +PROVIDE ( ets_strlen = 0x40002ac8 ); +PROVIDE ( ets_strncmp = 0x40002ab8 ); +PROVIDE ( ets_strncpy = 0x40002a98 ); +PROVIDE ( ets_strstr = 0x40002ad8 ); +PROVIDE ( ets_task = 0x40000dd0 ); +PROVIDE ( ets_timer_arm = 0x40002cc4 ); +PROVIDE ( ets_timer_disarm = 0x40002d40 ); +PROVIDE ( ets_timer_done = 0x40002d80 ); +PROVIDE ( ets_timer_handler_isr = 0x40002da8 ); +PROVIDE ( ets_timer_init = 0x40002e68 ); +PROVIDE ( ets_timer_setfn = 0x40002c48 ); +PROVIDE ( ets_uart_printf = 0x40002544 ); +PROVIDE ( ets_update_cpu_frequency = 0x40002f04 ); +PROVIDE ( ets_vprintf = 0x40001f00 ); +PROVIDE ( ets_wdt_disable = 0x400030f0 ); +PROVIDE ( ets_wdt_enable = 0x40002fa0 ); +PROVIDE ( ets_wdt_get_mode = 0x40002f34 ); +PROVIDE ( ets_wdt_init = 0x40003170 ); +PROVIDE ( ets_wdt_restore = 0x40003158 ); +PROVIDE ( ets_write_char = 0x40001da0 ); +PROVIDE ( get_first_seg = 0x4000091c ); +PROVIDE ( gpio_init = 0x40004c50 ); +PROVIDE ( gpio_input_get = 0x40004cf0 ); +PROVIDE ( gpio_intr_ack = 0x40004dcc ); +PROVIDE ( gpio_intr_handler_register = 0x40004e28 ); +PROVIDE ( gpio_intr_pending = 0x40004d88 ); +PROVIDE ( gpio_intr_test = 0x40004efc ); +PROVIDE ( gpio_output_set = 0x40004cd0 ); +PROVIDE ( gpio_pin_intr_state_set = 0x40004d90 ); +PROVIDE ( gpio_pin_wakeup_disable = 0x40004ed4 ); +PROVIDE ( gpio_pin_wakeup_enable = 0x40004e90 ); +PROVIDE ( gpio_register_get = 0x40004d5c ); +PROVIDE ( gpio_register_set = 0x40004d04 ); +PROVIDE ( hmac_md5 = 0x4000a2cc ); +PROVIDE ( hmac_md5_vector = 0x4000a160 ); +PROVIDE ( hmac_sha1 = 0x4000ba28 ); +PROVIDE ( hmac_sha1_vector = 0x4000b8b4 ); +PROVIDE ( lldesc_build_chain = 0x40004f40 ); +PROVIDE ( lldesc_num2link = 0x40005050 ); +PROVIDE ( lldesc_set_owner = 0x4000507c ); +PROVIDE ( main = 0x40000fec ); +PROVIDE ( md5_vector = 0x400097ac ); +PROVIDE ( mem_calloc = 0x40001c2c ); +PROVIDE ( mem_free = 0x400019e0 ); +PROVIDE ( mem_init = 0x40001998 ); +PROVIDE ( mem_malloc = 0x40001b40 ); +PROVIDE ( mem_realloc = 0x40001c6c ); +PROVIDE ( mem_trim = 0x40001a14 ); +PROVIDE ( mem_zalloc = 0x40001c58 ); +PROVIDE ( memcmp = 0x4000dea8 ); +PROVIDE ( memcpy = 0x4000df48 ); +PROVIDE ( memmove = 0x4000e04c ); +PROVIDE ( memset = 0x4000e190 ); +PROVIDE ( multofup = 0x400031c0 ); +PROVIDE ( pbkdf2_sha1 = 0x4000b840 ); +PROVIDE ( phy_get_romfuncs = 0x40006b08 ); +PROVIDE ( rand = 0x40000600 ); +PROVIDE ( rc4_skip = 0x4000dd68 ); +PROVIDE ( recv_packet = 0x40003d08 ); +PROVIDE ( remove_head_space = 0x40000a04 ); +PROVIDE ( rijndaelKeySetupDec = 0x40008dd0 ); +PROVIDE ( rijndaelKeySetupEnc = 0x40009300 ); +PROVIDE ( rom_abs_temp = 0x400060c0 ); +PROVIDE ( rom_ana_inf_gating_en = 0x40006b10 ); +PROVIDE ( rom_cal_tos_v50 = 0x40007a28 ); +PROVIDE ( rom_chip_50_set_channel = 0x40006f84 ); +PROVIDE ( rom_chip_v5_disable_cca = 0x400060d0 ); +PROVIDE ( rom_chip_v5_enable_cca = 0x400060ec ); +PROVIDE ( rom_chip_v5_rx_init = 0x4000711c ); +PROVIDE ( rom_chip_v5_sense_backoff = 0x4000610c ); +PROVIDE ( rom_chip_v5_tx_init = 0x4000718c ); +PROVIDE ( rom_dc_iq_est = 0x4000615c ); +PROVIDE ( rom_en_pwdet = 0x400061b8 ); +PROVIDE ( rom_get_bb_atten = 0x40006238 ); +PROVIDE ( rom_get_corr_power = 0x40006260 ); +PROVIDE ( rom_get_fm_sar_dout = 0x400062dc ); +PROVIDE ( rom_get_noisefloor = 0x40006394 ); +PROVIDE ( rom_get_power_db = 0x400063b0 ); +PROVIDE ( rom_i2c_readReg = 0x40007268 ); +PROVIDE ( rom_i2c_readReg_Mask = 0x4000729c ); +PROVIDE ( rom_i2c_writeReg = 0x400072d8 ); +PROVIDE ( rom_i2c_writeReg_Mask = 0x4000730c ); +PROVIDE ( rom_iq_est_disable = 0x40006400 ); +PROVIDE ( rom_iq_est_enable = 0x40006430 ); +PROVIDE ( rom_linear_to_db = 0x40006484 ); +PROVIDE ( rom_mhz2ieee = 0x400065a4 ); +PROVIDE ( rom_pbus_dco___SA2 = 0x40007bf0 ); +PROVIDE ( rom_pbus_debugmode = 0x4000737c ); +PROVIDE ( rom_pbus_enter_debugmode = 0x40007410 ); +PROVIDE ( rom_pbus_exit_debugmode = 0x40007448 ); +PROVIDE ( rom_pbus_force_test = 0x4000747c ); +PROVIDE ( rom_pbus_rd = 0x400074d8 ); +PROVIDE ( rom_pbus_set_rxgain = 0x4000754c ); +PROVIDE ( rom_pbus_set_txgain = 0x40007610 ); +PROVIDE ( rom_pbus_workmode = 0x40007648 ); +PROVIDE ( rom_pbus_xpd_rx_off = 0x40007688 ); +PROVIDE ( rom_pbus_xpd_rx_on = 0x400076cc ); +PROVIDE ( rom_pbus_xpd_tx_off = 0x400076fc ); +PROVIDE ( rom_pbus_xpd_tx_on = 0x40007740 ); +PROVIDE ( rom_pbus_xpd_tx_on__low_gain = 0x400077a0 ); +PROVIDE ( rom_phy_reset_req = 0x40007804 ); +PROVIDE ( rom_restart_cal = 0x4000781c ); +PROVIDE ( rom_rfcal_pwrctrl = 0x40007eb4 ); +PROVIDE ( rom_rfcal_rxiq = 0x4000804c ); +PROVIDE ( rom_rfcal_rxiq_set_reg = 0x40008264 ); +PROVIDE ( rom_rfcal_txcap = 0x40008388 ); +PROVIDE ( rom_rfcal_txiq = 0x40008610 ); +PROVIDE ( rom_rfcal_txiq_cover = 0x400088b8 ); +PROVIDE ( rom_rfcal_txiq_set_reg = 0x40008a70 ); +PROVIDE ( rom_rfpll_reset = 0x40007868 ); +PROVIDE ( rom_rfpll_set_freq = 0x40007968 ); +PROVIDE ( rom_rxiq_cover_mg_mp = 0x40008b6c ); +PROVIDE ( rom_rxiq_get_mis = 0x40006628 ); +PROVIDE ( rom_sar_init = 0x40006738 ); +PROVIDE ( rom_set_ana_inf_tx_scale = 0x4000678c ); +PROVIDE ( rom_set_channel_freq = 0x40006c50 ); +PROVIDE ( rom_set_loopback_gain = 0x400067c8 ); +PROVIDE ( rom_set_noise_floor = 0x40006830 ); +PROVIDE ( rom_set_rxclk_en = 0x40006550 ); +PROVIDE ( rom_set_txbb_atten = 0x40008c6c ); +PROVIDE ( rom_set_txclk_en = 0x4000650c ); +PROVIDE ( rom_set_txiq_cal = 0x40008d34 ); +PROVIDE ( rom_start_noisefloor = 0x40006874 ); +PROVIDE ( rom_start_tx_tone = 0x400068b4 ); +PROVIDE ( rom_stop_tx_tone = 0x4000698c ); +PROVIDE ( rom_tx_mac_disable = 0x40006a98 ); +PROVIDE ( rom_tx_mac_enable = 0x40006ad4 ); +PROVIDE ( rom_txtone_linear_pwr = 0x40006a1c ); +PROVIDE ( rom_write_rfpll_sdm = 0x400078dc ); +PROVIDE ( roundup2 = 0x400031b4 ); +PROVIDE ( rtc_enter_sleep = 0x40002870 ); +PROVIDE ( rtc_get_reset_reason = 0x400025e0 ); +PROVIDE ( rtc_intr_handler = 0x400029ec ); +PROVIDE ( rtc_set_sleep_mode = 0x40002668 ); +PROVIDE ( save_rxbcn_mactime = 0x400027a4 ); +PROVIDE ( save_tsf_us = 0x400027ac ); +PROVIDE ( send_packet = 0x40003c80 ); +PROVIDE ( sha1_prf = 0x4000ba48 ); +PROVIDE ( sha1_vector = 0x4000a2ec ); +PROVIDE ( sip_alloc_to_host_evt = 0x40005180 ); +PROVIDE ( sip_get_ptr = 0x400058a8 ); +PROVIDE ( sip_get_state = 0x40005668 ); +PROVIDE ( sip_init_attach = 0x4000567c ); +PROVIDE ( sip_install_rx_ctrl_cb = 0x4000544c ); +PROVIDE ( sip_install_rx_data_cb = 0x4000545c ); +PROVIDE ( sip_post = 0x400050fc ); +PROVIDE ( sip_post_init = 0x400056c4 ); +PROVIDE ( sip_reclaim_from_host_cmd = 0x4000534c ); +PROVIDE ( sip_reclaim_tx_data_pkt = 0x400052c0 ); +PROVIDE ( sip_send = 0x40005808 ); +PROVIDE ( sip_to_host_chain_append = 0x40005864 ); +PROVIDE ( sip_to_host_evt_send_done = 0x40005234 ); +PROVIDE ( slc_add_credits = 0x400060ac ); +PROVIDE ( slc_enable = 0x40005d90 ); +PROVIDE ( slc_from_host_chain_fetch = 0x40005f24 ); +PROVIDE ( slc_from_host_chain_recycle = 0x40005e94 ); +PROVIDE ( slc_init_attach = 0x40005c50 ); +PROVIDE ( slc_init_credit = 0x4000608c ); +PROVIDE ( slc_pause_from_host = 0x40006014 ); +PROVIDE ( slc_reattach = 0x40005c1c ); +PROVIDE ( slc_resume_from_host = 0x4000603c ); +PROVIDE ( slc_select_tohost_gpio = 0x40005dc0 ); +PROVIDE ( slc_select_tohost_gpio_mode = 0x40005db8 ); +PROVIDE ( slc_send_to_host_chain = 0x40005de4 ); +PROVIDE ( slc_set_host_io_max_window = 0x40006068 ); +PROVIDE ( slc_to_host_chain_recycle = 0x40005f10 ); +PROVIDE ( software_reset = 0x4000264c ); +PROVIDE ( spi_flash_attach = 0x40004644 ); +PROVIDE ( srand = 0x400005f0 ); +PROVIDE ( strcmp = 0x4000bdc8 ); +PROVIDE ( strcpy = 0x4000bec8 ); +PROVIDE ( strlen = 0x4000bf4c ); +PROVIDE ( strncmp = 0x4000bfa8 ); +PROVIDE ( strncpy = 0x4000c0a0 ); +PROVIDE ( strstr = 0x4000e1e0 ); +PROVIDE ( timer_insert = 0x40002c64 ); +PROVIDE ( uartAttach = 0x4000383c ); +PROVIDE ( uart_baudrate_detect = 0x40003924 ); +PROVIDE ( uart_buff_switch = 0x400038a4 ); +PROVIDE ( uart_div_modify = 0x400039d8 ); +PROVIDE ( uart_rx_intr_handler = 0x40003bbc ); +PROVIDE ( uart_rx_one_char = 0x40003b8c ); +PROVIDE ( uart_rx_one_char_block = 0x40003b64 ); +PROVIDE ( uart_rx_readbuff = 0x40003ec8 ); +PROVIDE ( uart_tx_one_char = 0x40003b30 ); +PROVIDE ( wepkey_128 = 0x4000bc40 ); +PROVIDE ( wepkey_64 = 0x4000bb3c ); +PROVIDE ( xthal_bcopy = 0x40000688 ); +PROVIDE ( xthal_copy123 = 0x4000074c ); +PROVIDE ( xthal_get_ccompare = 0x4000dd4c ); +PROVIDE ( xthal_get_ccount = 0x4000dd38 ); +PROVIDE ( xthal_get_interrupt = 0x4000dd58 ); +PROVIDE ( xthal_get_intread = 0x4000dd58 ); +PROVIDE ( xthal_memcpy = 0x400006c4 ); +PROVIDE ( xthal_set_ccompare = 0x4000dd40 ); +PROVIDE ( xthal_set_intclear = 0x4000dd60 ); +PROVIDE ( xthal_spill_registers_into_stack_nw = 0x4000e320 ); +PROVIDE ( xthal_window_spill = 0x4000e324 ); +PROVIDE ( xthal_window_spill_nw = 0x4000e320 ); + +PROVIDE ( Te0 = 0x3fffccf0 ); +PROVIDE ( Td0 = 0x3fffd100 ); +PROVIDE ( Td4s = 0x3fffd500); +PROVIDE ( rcons = 0x3fffd0f0); +PROVIDE ( UartDev = 0x3fffde10 ); +PROVIDE ( flashchip = 0x3fffc714); diff --git a/tools/flasher_stub/ld/stub_32.ld b/tools/flasher_stub/ld/stub_32.ld new file mode 100644 index 0000000000..9ab8255858 --- /dev/null +++ b/tools/flasher_stub/ld/stub_32.ld @@ -0,0 +1,29 @@ +/* Note: stub is deliberately loaded close to the very top + of available RAM, to reduce change of colliding with anything + else... */ +MEMORY { + iram : org = 0x400BE000, len = 0x1000 + dram : org = 0x3ffcc000, len = 0x14000 +} + +ENTRY(stub_main) + +SECTIONS { + .text : ALIGN(4) { + *(.literal) + *(.text .text.*) + } > iram + + .bss : ALIGN(4) { + _bss_start = ABSOLUTE(.); + *(.bss) + _bss_end = ABSOLUTE(.); + } > dram + + .data : ALIGN(4) { + *(.data) + *(.rodata .rodata.*) + } > dram +} + +INCLUDE "rom_32.ld" diff --git a/tools/flasher_stub/ld/stub_32c2.ld b/tools/flasher_stub/ld/stub_32c2.ld new file mode 100644 index 0000000000..e0c0ec4edf --- /dev/null +++ b/tools/flasher_stub/ld/stub_32c2.ld @@ -0,0 +1,26 @@ +MEMORY { + iram : org = 0x40380000, len = 0x4000 + dram : org = 0x3FCA4000, len = 0x18000 +} + +ENTRY(stub_main) + +SECTIONS { + .text : ALIGN(4) { + *(.literal) + *(.text .text.*) + } > iram + + .bss : ALIGN(4) { + _bss_start = ABSOLUTE(.); + *(.bss) + _bss_end = ABSOLUTE(.); + } > dram + + .data : ALIGN(4) { + *(.data) + *(.rodata .rodata.*) + } > dram +} + +INCLUDE "rom_32c2.ld" diff --git a/tools/flasher_stub/ld/stub_32c3.ld b/tools/flasher_stub/ld/stub_32c3.ld new file mode 100644 index 0000000000..dc9d4201e3 --- /dev/null +++ b/tools/flasher_stub/ld/stub_32c3.ld @@ -0,0 +1,26 @@ +MEMORY { + iram : org = 0x40380000, len = 0x4000 + dram : org = 0x3FC84000, len = 0x18000 +} + +ENTRY(stub_main) + +SECTIONS { + .text : ALIGN(4) { + *(.literal) + *(.text .text.*) + } > iram + + .bss : ALIGN(4) { + _bss_start = ABSOLUTE(.); + *(.bss) + _bss_end = ABSOLUTE(.); + } > dram + + .data : ALIGN(4) { + *(.data) + *(.rodata .rodata.*) + } > dram +} + +INCLUDE "rom_32c3.ld" diff --git a/tools/flasher_stub/ld/stub_32c5.ld b/tools/flasher_stub/ld/stub_32c5.ld new file mode 100644 index 0000000000..0ddc7cf961 --- /dev/null +++ b/tools/flasher_stub/ld/stub_32c5.ld @@ -0,0 +1,26 @@ +MEMORY { + iram : org = 0x40800000, len = 0x4000 + dram : org = 0x40840000, len = 0x18000 +} + +ENTRY(stub_main) + +SECTIONS { + .text : ALIGN(4) { + *(.literal) + *(.text .text.*) + } > iram + + .bss : ALIGN(4) { + _bss_start = ABSOLUTE(.); + *(.bss) + _bss_end = ABSOLUTE(.); + } > dram + + .data : ALIGN(4) { + *(.data) + *(.rodata .rodata.*) + } > dram +} + +INCLUDE "rom_32c5.ld" diff --git a/tools/flasher_stub/ld/stub_32c5_beta_3.ld b/tools/flasher_stub/ld/stub_32c5_beta_3.ld new file mode 100644 index 0000000000..e1133674e9 --- /dev/null +++ b/tools/flasher_stub/ld/stub_32c5_beta_3.ld @@ -0,0 +1,26 @@ +MEMORY { + iram : org = 0x40800000, len = 0x4000 + dram : org = 0x40840000, len = 0x18000 +} + +ENTRY(stub_main) + +SECTIONS { + .text : ALIGN(4) { + *(.literal) + *(.text .text.*) + } > iram + + .bss : ALIGN(4) { + _bss_start = ABSOLUTE(.); + *(.bss) + _bss_end = ABSOLUTE(.); + } > dram + + .data : ALIGN(4) { + *(.data) + *(.rodata .rodata.*) + } > dram +} + +INCLUDE "rom_32c5_beta_3.ld" diff --git a/tools/flasher_stub/ld/stub_32c6.ld b/tools/flasher_stub/ld/stub_32c6.ld new file mode 100644 index 0000000000..91b8d3137a --- /dev/null +++ b/tools/flasher_stub/ld/stub_32c6.ld @@ -0,0 +1,26 @@ +MEMORY { + iram : org = 0x40800000, len = 0x4000 + dram : org = 0x40840000, len = 0x18000 +} + +ENTRY(stub_main) + +SECTIONS { + .text : ALIGN(4) { + *(.literal) + *(.text .text.*) + } > iram + + .bss : ALIGN(4) { + _bss_start = ABSOLUTE(.); + *(.bss) + _bss_end = ABSOLUTE(.); + } > dram + + .data : ALIGN(4) { + *(.data) + *(.rodata .rodata.*) + } > dram +} + +INCLUDE "rom_32c6.ld" diff --git a/tools/flasher_stub/ld/stub_32c61.ld b/tools/flasher_stub/ld/stub_32c61.ld new file mode 100644 index 0000000000..8cda581f34 --- /dev/null +++ b/tools/flasher_stub/ld/stub_32c61.ld @@ -0,0 +1,26 @@ +MEMORY { + iram : org = 0x40800000, len = 0x4000 + dram : org = 0x40804000, len = 0x18000 +} + +ENTRY(stub_main) + +SECTIONS { + .text : ALIGN(4) { + *(.literal) + *(.text .text.*) + } > iram + + .bss : ALIGN(4) { + _bss_start = ABSOLUTE(.); + *(.bss) + _bss_end = ABSOLUTE(.); + } > dram + + .data : ALIGN(4) { + *(.data) + *(.rodata .rodata.*) + } > dram +} + +INCLUDE "rom_32c61.ld" diff --git a/tools/flasher_stub/ld/stub_32c6_beta.ld b/tools/flasher_stub/ld/stub_32c6_beta.ld new file mode 100644 index 0000000000..5acb1029b3 --- /dev/null +++ b/tools/flasher_stub/ld/stub_32c6_beta.ld @@ -0,0 +1,26 @@ +MEMORY { + iram : org = 0x40380000, len = 0x4000 + dram : org = 0x3FC84000, len = 0x18000 +} + +ENTRY(stub_main) + +SECTIONS { + .text : ALIGN(4) { + *(.literal) + *(.text .text.*) + } > iram + + .bss : ALIGN(4) { + _bss_start = ABSOLUTE(.); + *(.bss) + _bss_end = ABSOLUTE(.); + } > dram + + .data : ALIGN(4) { + *(.data) + *(.rodata .rodata.*) + } > dram +} + +INCLUDE "rom_32c6_beta.ld" diff --git a/tools/flasher_stub/ld/stub_32h2.ld b/tools/flasher_stub/ld/stub_32h2.ld new file mode 100644 index 0000000000..c94f5939e8 --- /dev/null +++ b/tools/flasher_stub/ld/stub_32h2.ld @@ -0,0 +1,26 @@ +MEMORY { + iram : org = 0x40800000, len = 0x4000 + dram : org = 0x40830000, len = 0x18000 +} + +ENTRY(stub_main) + +SECTIONS { + .text : ALIGN(4) { + *(.literal) + *(.text .text.*) + } > iram + + .bss : ALIGN(4) { + _bss_start = ABSOLUTE(.); + *(.bss) + _bss_end = ABSOLUTE(.); + } > dram + + .data : ALIGN(4) { + *(.data) + *(.rodata .rodata.*) + } > dram +} + +INCLUDE "rom_32h2.ld" diff --git a/tools/flasher_stub/ld/stub_32h2_beta_1.ld b/tools/flasher_stub/ld/stub_32h2_beta_1.ld new file mode 100644 index 0000000000..62b16372c6 --- /dev/null +++ b/tools/flasher_stub/ld/stub_32h2_beta_1.ld @@ -0,0 +1,26 @@ +MEMORY { + iram : org = 0x40380000, len = 0x4000 + dram : org = 0x3FC84000, len = 0x18000 +} + +ENTRY(stub_main) + +SECTIONS { + .text : ALIGN(4) { + *(.literal) + *(.text .text.*) + } > iram + + .bss : ALIGN(4) { + _bss_start = ABSOLUTE(.); + *(.bss) + _bss_end = ABSOLUTE(.); + } > dram + + .data : ALIGN(4) { + *(.data) + *(.rodata .rodata.*) + } > dram +} + +INCLUDE "rom_32h2_beta_1.ld" diff --git a/tools/flasher_stub/ld/stub_32h2_beta_2.ld b/tools/flasher_stub/ld/stub_32h2_beta_2.ld new file mode 100644 index 0000000000..903b497eec --- /dev/null +++ b/tools/flasher_stub/ld/stub_32h2_beta_2.ld @@ -0,0 +1,26 @@ +MEMORY { + iram : org = 0x40380000, len = 0x4000 + dram : org = 0x3FC84000, len = 0x18000 +} + +ENTRY(stub_main) + +SECTIONS { + .text : ALIGN(4) { + *(.literal) + *(.text .text.*) + } > iram + + .bss : ALIGN(4) { + _bss_start = ABSOLUTE(.); + *(.bss) + _bss_end = ABSOLUTE(.); + } > dram + + .data : ALIGN(4) { + *(.data) + *(.rodata .rodata.*) + } > dram +} + +INCLUDE "rom_32h2_beta_2.ld" diff --git a/tools/flasher_stub/ld/stub_32p4.ld b/tools/flasher_stub/ld/stub_32p4.ld new file mode 100644 index 0000000000..bf7e46a4e1 --- /dev/null +++ b/tools/flasher_stub/ld/stub_32p4.ld @@ -0,0 +1,26 @@ +MEMORY { + iram : org = 0x4FF10000, len = 0x4000 + dram : org = 0x4FF50000, len = 0x18000 +} + +ENTRY(stub_main) + +SECTIONS { + .text : ALIGN(4) { + *(.literal) + *(.text .text.*) + } > iram + + .bss : ALIGN(4) { + _bss_start = ABSOLUTE(.); + *(.bss) + _bss_end = ABSOLUTE(.); + } > dram + + .data : ALIGN(4) { + *(.data) + *(.rodata .rodata.*) + } > dram +} + +INCLUDE "rom_32p4.ld" diff --git a/tools/flasher_stub/ld/stub_32s2.ld b/tools/flasher_stub/ld/stub_32s2.ld new file mode 100644 index 0000000000..ccec2b79c7 --- /dev/null +++ b/tools/flasher_stub/ld/stub_32s2.ld @@ -0,0 +1,26 @@ +MEMORY { + iram : org = 0x40028000, len = 0x18000 + dram : org = 0x3FFD0000, len = 0x28000 +} + +ENTRY(stub_main) + +SECTIONS { + .text : ALIGN(4) { + *(.literal) + *(.text .text.*) + } > iram + + .bss : ALIGN(4) { + _bss_start = ABSOLUTE(.); + *(.bss) + _bss_end = ABSOLUTE(.); + } > dram + + .data : ALIGN(4) { + *(.data) + *(.rodata .rodata.*) + } > dram +} + +INCLUDE "rom_32s2.ld" diff --git a/tools/flasher_stub/ld/stub_32s3.ld b/tools/flasher_stub/ld/stub_32s3.ld new file mode 100644 index 0000000000..98cce22848 --- /dev/null +++ b/tools/flasher_stub/ld/stub_32s3.ld @@ -0,0 +1,26 @@ +MEMORY { + iram : org = 0x40378000, len = 0x18000 + dram : org = 0x3FCA0000, len = 0x28000 +} + +ENTRY(stub_main) + +SECTIONS { + .text : ALIGN(4) { + *(.literal) + *(.text .text.*) + } > iram + + .bss : ALIGN(4) { + _bss_start = ABSOLUTE(.); + *(.bss) + _bss_end = ABSOLUTE(.); + } > dram + + .data : ALIGN(4) { + *(.data) + *(.rodata .rodata.*) + } > dram +} + +INCLUDE "rom_32s3.ld" diff --git a/tools/flasher_stub/ld/stub_32s3_beta_2.ld b/tools/flasher_stub/ld/stub_32s3_beta_2.ld new file mode 100644 index 0000000000..5105e30d91 --- /dev/null +++ b/tools/flasher_stub/ld/stub_32s3_beta_2.ld @@ -0,0 +1,26 @@ +MEMORY { + iram : org = 0x40378000, len = 0x18000 + dram : org = 0x3FCA0000, len = 0x28000 +} + +ENTRY(stub_main) + +SECTIONS { + .text : ALIGN(4) { + *(.literal) + *(.text .text.*) + } > iram + + .bss : ALIGN(4) { + _bss_start = ABSOLUTE(.); + *(.bss) + _bss_end = ABSOLUTE(.); + } > dram + + .data : ALIGN(4) { + *(.data) + *(.rodata .rodata.*) + } > dram +} + +INCLUDE "rom_32s3_beta_2.ld" diff --git a/tools/flasher_stub/ld/stub_8266.ld b/tools/flasher_stub/ld/stub_8266.ld new file mode 100644 index 0000000000..a42b9b25e2 --- /dev/null +++ b/tools/flasher_stub/ld/stub_8266.ld @@ -0,0 +1,32 @@ +/* Note: stub is deliberately loaded close to the very top + of available RAM, to reduce change of colliding with anything + else... */ +MEMORY { + iram : org = 0x4010D000, len = 0x2100 + dram : org = 0x3FFE8100, len = 0x13f00 +} + +ENTRY(stub_main_8266) + +SECTIONS { + .text : ALIGN(4) { + *(.literal) + *(.text .text.*) + } > iram + + .bss : ALIGN(4) { + _bss_start = ABSOLUTE(.); + *(.bss) + _bss_end = ABSOLUTE(.); + } > dram + + .data : ALIGN(4) { + *(.data) + *(.rodata .rodata.*) + } > dram +} + +INCLUDE "rom_8266.ld" + +PROVIDE(SPIFlashModeConfig = 0x40004568); +PROVIDE(SPIParamCfg = 0x40004c2c); diff --git a/tools/flasher_stub/miniz.c b/tools/flasher_stub/miniz.c new file mode 100644 index 0000000000..9ded4c75ab --- /dev/null +++ b/tools/flasher_stub/miniz.c @@ -0,0 +1,7657 @@ +/************************************************************************** + * + * Copyright 2013-2014 RAD Game Tools and Valve Software + * Copyright 2010-2014 Rich Geldreich and Tenacious Software LLC + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + **************************************************************************/ + +#include "miniz.h" + +typedef unsigned char mz_validate_uint16[sizeof(mz_uint16) == 2 ? 1 : -1]; +typedef unsigned char mz_validate_uint32[sizeof(mz_uint32) == 4 ? 1 : -1]; +typedef unsigned char mz_validate_uint64[sizeof(mz_uint64) == 8 ? 1 : -1]; + +#ifdef __cplusplus +extern "C" { +#endif + +/* ------------------- zlib-style API's */ + +mz_ulong mz_adler32(mz_ulong adler, const unsigned char *ptr, size_t buf_len) +{ + mz_uint32 i, s1 = (mz_uint32)(adler & 0xffff), s2 = (mz_uint32)(adler >> 16); + size_t block_len = buf_len % 5552; + if (!ptr) + return MZ_ADLER32_INIT; + while (buf_len) + { + for (i = 0; i + 7 < block_len; i += 8, ptr += 8) + { + s1 += ptr[0], s2 += s1; + s1 += ptr[1], s2 += s1; + s1 += ptr[2], s2 += s1; + s1 += ptr[3], s2 += s1; + s1 += ptr[4], s2 += s1; + s1 += ptr[5], s2 += s1; + s1 += ptr[6], s2 += s1; + s1 += ptr[7], s2 += s1; + } + for (; i < block_len; ++i) + s1 += *ptr++, s2 += s1; + s1 %= 65521U, s2 %= 65521U; + buf_len -= block_len; + block_len = 5552; + } + return (s2 << 16) + s1; +} + +/* Karl Malbrain's compact CRC-32. See "A compact CCITT crc16 and crc32 C implementation that balances processor cache usage against speed": http://www.geocities.com/malbrain/ */ +#if 0 + mz_ulong mz_crc32(mz_ulong crc, const mz_uint8 *ptr, size_t buf_len) + { + static const mz_uint32 s_crc32[16] = { 0, 0x1db71064, 0x3b6e20c8, 0x26d930ac, 0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c, + 0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c, 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c }; + mz_uint32 crcu32 = (mz_uint32)crc; + if (!ptr) + return MZ_CRC32_INIT; + crcu32 = ~crcu32; + while (buf_len--) + { + mz_uint8 b = *ptr++; + crcu32 = (crcu32 >> 4) ^ s_crc32[(crcu32 & 0xF) ^ (b & 0xF)]; + crcu32 = (crcu32 >> 4) ^ s_crc32[(crcu32 & 0xF) ^ (b >> 4)]; + } + return ~crcu32; + } +#else +/* Faster, but larger CPU cache footprint. + */ +mz_ulong mz_crc32(mz_ulong crc, const mz_uint8 *ptr, size_t buf_len) +{ + static const mz_uint32 s_crc_table[256] = + { + 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, + 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, + 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, + 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, + 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4, + 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C, + 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, 0x26D930AC, + 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, + 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, + 0xB6662D3D, 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, + 0x9FBFE4A5, 0xE8B8D433, 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, + 0x086D3D2D, 0x91646C97, 0xE6635C01, 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, + 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, + 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, 0x4DB26158, 0x3AB551CE, + 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, + 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, + 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, + 0xCE61E49F, 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, + 0xB7BD5C3B, 0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, + 0x9DD277AF, 0x04DB2615, 0x73DC1683, 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, + 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, 0xF00F9344, 0x8708A3D2, 0x1E01F268, + 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, + 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, + 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, + 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, + 0x4669BE79, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, + 0x220216B9, 0x5505262F, 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, + 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, + 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, + 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242, + 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, 0x88085AE6, + 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, + 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, + 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, + 0x47B2CF7F, 0x30B5FFE9, 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, + 0xCDD70693, 0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, + 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D + }; + + mz_uint32 crc32 = (mz_uint32)crc ^ 0xFFFFFFFF; + const mz_uint8 *pByte_buf = (const mz_uint8 *)ptr; + + while (buf_len >= 4) + { + crc32 = (crc32 >> 8) ^ s_crc_table[(crc32 ^ pByte_buf[0]) & 0xFF]; + crc32 = (crc32 >> 8) ^ s_crc_table[(crc32 ^ pByte_buf[1]) & 0xFF]; + crc32 = (crc32 >> 8) ^ s_crc_table[(crc32 ^ pByte_buf[2]) & 0xFF]; + crc32 = (crc32 >> 8) ^ s_crc_table[(crc32 ^ pByte_buf[3]) & 0xFF]; + pByte_buf += 4; + buf_len -= 4; + } + + while (buf_len) + { + crc32 = (crc32 >> 8) ^ s_crc_table[(crc32 ^ pByte_buf[0]) & 0xFF]; + ++pByte_buf; + --buf_len; + } + + return ~crc32; +} +#endif + +void mz_free(void *p) +{ + MZ_FREE(p); +} + +void *miniz_def_alloc_func(void *opaque, size_t items, size_t size) +{ + (void)opaque, (void)items, (void)size; + return MZ_MALLOC(items * size); +} +void miniz_def_free_func(void *opaque, void *address) +{ + (void)opaque, (void)address; + MZ_FREE(address); +} +void *miniz_def_realloc_func(void *opaque, void *address, size_t items, size_t size) +{ + (void)opaque, (void)address, (void)items, (void)size; + return MZ_REALLOC(address, items * size); +} + +const char *mz_version(void) +{ + return MZ_VERSION; +} + +#ifndef MINIZ_NO_ZLIB_APIS + +int mz_deflateInit(mz_streamp pStream, int level) +{ + return mz_deflateInit2(pStream, level, MZ_DEFLATED, MZ_DEFAULT_WINDOW_BITS, 9, MZ_DEFAULT_STRATEGY); +} + +int mz_deflateInit2(mz_streamp pStream, int level, int method, int window_bits, int mem_level, int strategy) +{ + tdefl_compressor *pComp; + mz_uint comp_flags = TDEFL_COMPUTE_ADLER32 | tdefl_create_comp_flags_from_zip_params(level, window_bits, strategy); + + if (!pStream) + return MZ_STREAM_ERROR; + if ((method != MZ_DEFLATED) || ((mem_level < 1) || (mem_level > 9)) || ((window_bits != MZ_DEFAULT_WINDOW_BITS) && (-window_bits != MZ_DEFAULT_WINDOW_BITS))) + return MZ_PARAM_ERROR; + + pStream->data_type = 0; + pStream->adler = MZ_ADLER32_INIT; + pStream->msg = NULL; + pStream->reserved = 0; + pStream->total_in = 0; + pStream->total_out = 0; + if (!pStream->zalloc) + pStream->zalloc = miniz_def_alloc_func; + if (!pStream->zfree) + pStream->zfree = miniz_def_free_func; + + pComp = (tdefl_compressor *)pStream->zalloc(pStream->opaque, 1, sizeof(tdefl_compressor)); + if (!pComp) + return MZ_MEM_ERROR; + + pStream->state = (struct mz_internal_state *)pComp; + + if (tdefl_init(pComp, NULL, NULL, comp_flags) != TDEFL_STATUS_OKAY) + { + mz_deflateEnd(pStream); + return MZ_PARAM_ERROR; + } + + return MZ_OK; +} + +int mz_deflateReset(mz_streamp pStream) +{ + if ((!pStream) || (!pStream->state) || (!pStream->zalloc) || (!pStream->zfree)) + return MZ_STREAM_ERROR; + pStream->total_in = pStream->total_out = 0; + tdefl_init((tdefl_compressor *)pStream->state, NULL, NULL, ((tdefl_compressor *)pStream->state)->m_flags); + return MZ_OK; +} + +int mz_deflate(mz_streamp pStream, int flush) +{ + size_t in_bytes, out_bytes; + mz_ulong orig_total_in, orig_total_out; + int mz_status = MZ_OK; + + if ((!pStream) || (!pStream->state) || (flush < 0) || (flush > MZ_FINISH) || (!pStream->next_out)) + return MZ_STREAM_ERROR; + if (!pStream->avail_out) + return MZ_BUF_ERROR; + + if (flush == MZ_PARTIAL_FLUSH) + flush = MZ_SYNC_FLUSH; + + if (((tdefl_compressor *)pStream->state)->m_prev_return_status == TDEFL_STATUS_DONE) + return (flush == MZ_FINISH) ? MZ_STREAM_END : MZ_BUF_ERROR; + + orig_total_in = pStream->total_in; + orig_total_out = pStream->total_out; + for (;;) + { + tdefl_status defl_status; + in_bytes = pStream->avail_in; + out_bytes = pStream->avail_out; + + defl_status = tdefl_compress((tdefl_compressor *)pStream->state, pStream->next_in, &in_bytes, pStream->next_out, &out_bytes, (tdefl_flush)flush); + pStream->next_in += (mz_uint)in_bytes; + pStream->avail_in -= (mz_uint)in_bytes; + pStream->total_in += (mz_uint)in_bytes; + pStream->adler = tdefl_get_adler32((tdefl_compressor *)pStream->state); + + pStream->next_out += (mz_uint)out_bytes; + pStream->avail_out -= (mz_uint)out_bytes; + pStream->total_out += (mz_uint)out_bytes; + + if (defl_status < 0) + { + mz_status = MZ_STREAM_ERROR; + break; + } + else if (defl_status == TDEFL_STATUS_DONE) + { + mz_status = MZ_STREAM_END; + break; + } + else if (!pStream->avail_out) + break; + else if ((!pStream->avail_in) && (flush != MZ_FINISH)) + { + if ((flush) || (pStream->total_in != orig_total_in) || (pStream->total_out != orig_total_out)) + break; + return MZ_BUF_ERROR; /* Can't make forward progress without some input. + */ + } + } + return mz_status; +} + +int mz_deflateEnd(mz_streamp pStream) +{ + if (!pStream) + return MZ_STREAM_ERROR; + if (pStream->state) + { + pStream->zfree(pStream->opaque, pStream->state); + pStream->state = NULL; + } + return MZ_OK; +} + +mz_ulong mz_deflateBound(mz_streamp pStream, mz_ulong source_len) +{ + (void)pStream; + /* This is really over conservative. (And lame, but it's actually pretty tricky to compute a true upper bound given the way tdefl's blocking works.) */ + return MZ_MAX(128 + (source_len * 110) / 100, 128 + source_len + ((source_len / (31 * 1024)) + 1) * 5); +} + +int mz_compress2(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len, int level) +{ + int status; + mz_stream stream; + memset(&stream, 0, sizeof(stream)); + + /* In case mz_ulong is 64-bits (argh I hate longs). */ + if ((source_len | *pDest_len) > 0xFFFFFFFFU) + return MZ_PARAM_ERROR; + + stream.next_in = pSource; + stream.avail_in = (mz_uint32)source_len; + stream.next_out = pDest; + stream.avail_out = (mz_uint32)*pDest_len; + + status = mz_deflateInit(&stream, level); + if (status != MZ_OK) + return status; + + status = mz_deflate(&stream, MZ_FINISH); + if (status != MZ_STREAM_END) + { + mz_deflateEnd(&stream); + return (status == MZ_OK) ? MZ_BUF_ERROR : status; + } + + *pDest_len = stream.total_out; + return mz_deflateEnd(&stream); +} + +int mz_compress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len) +{ + return mz_compress2(pDest, pDest_len, pSource, source_len, MZ_DEFAULT_COMPRESSION); +} + +mz_ulong mz_compressBound(mz_ulong source_len) +{ + return mz_deflateBound(NULL, source_len); +} + +typedef struct +{ + tinfl_decompressor m_decomp; + mz_uint m_dict_ofs, m_dict_avail, m_first_call, m_has_flushed; + int m_window_bits; + mz_uint8 m_dict[TINFL_LZ_DICT_SIZE]; + tinfl_status m_last_status; +} inflate_state; + +int mz_inflateInit2(mz_streamp pStream, int window_bits) +{ + inflate_state *pDecomp; + if (!pStream) + return MZ_STREAM_ERROR; + if ((window_bits != MZ_DEFAULT_WINDOW_BITS) && (-window_bits != MZ_DEFAULT_WINDOW_BITS)) + return MZ_PARAM_ERROR; + + pStream->data_type = 0; + pStream->adler = 0; + pStream->msg = NULL; + pStream->total_in = 0; + pStream->total_out = 0; + pStream->reserved = 0; + if (!pStream->zalloc) + pStream->zalloc = miniz_def_alloc_func; + if (!pStream->zfree) + pStream->zfree = miniz_def_free_func; + + pDecomp = (inflate_state *)pStream->zalloc(pStream->opaque, 1, sizeof(inflate_state)); + if (!pDecomp) + return MZ_MEM_ERROR; + + pStream->state = (struct mz_internal_state *)pDecomp; + + tinfl_init(&pDecomp->m_decomp); + pDecomp->m_dict_ofs = 0; + pDecomp->m_dict_avail = 0; + pDecomp->m_last_status = TINFL_STATUS_NEEDS_MORE_INPUT; + pDecomp->m_first_call = 1; + pDecomp->m_has_flushed = 0; + pDecomp->m_window_bits = window_bits; + + return MZ_OK; +} + +int mz_inflateInit(mz_streamp pStream) +{ + return mz_inflateInit2(pStream, MZ_DEFAULT_WINDOW_BITS); +} + +int mz_inflateReset(mz_streamp pStream) +{ + inflate_state *pDecomp; + if (!pStream) + return MZ_STREAM_ERROR; + + pStream->data_type = 0; + pStream->adler = 0; + pStream->msg = NULL; + pStream->total_in = 0; + pStream->total_out = 0; + pStream->reserved = 0; + + pDecomp = (inflate_state *)pStream->state; + + tinfl_init(&pDecomp->m_decomp); + pDecomp->m_dict_ofs = 0; + pDecomp->m_dict_avail = 0; + pDecomp->m_last_status = TINFL_STATUS_NEEDS_MORE_INPUT; + pDecomp->m_first_call = 1; + pDecomp->m_has_flushed = 0; + /* pDecomp->m_window_bits = window_bits */; + + return MZ_OK; +} + +int mz_inflate(mz_streamp pStream, int flush) +{ + inflate_state *pState; + mz_uint n, first_call, decomp_flags = TINFL_FLAG_COMPUTE_ADLER32; + size_t in_bytes, out_bytes, orig_avail_in; + tinfl_status status; + + if ((!pStream) || (!pStream->state)) + return MZ_STREAM_ERROR; + if (flush == MZ_PARTIAL_FLUSH) + flush = MZ_SYNC_FLUSH; + if ((flush) && (flush != MZ_SYNC_FLUSH) && (flush != MZ_FINISH)) + return MZ_STREAM_ERROR; + + pState = (inflate_state *)pStream->state; + if (pState->m_window_bits > 0) + decomp_flags |= TINFL_FLAG_PARSE_ZLIB_HEADER; + orig_avail_in = pStream->avail_in; + + first_call = pState->m_first_call; + pState->m_first_call = 0; + if (pState->m_last_status < 0) + return MZ_DATA_ERROR; + + if (pState->m_has_flushed && (flush != MZ_FINISH)) + return MZ_STREAM_ERROR; + pState->m_has_flushed |= (flush == MZ_FINISH); + + if ((flush == MZ_FINISH) && (first_call)) + { + /* MZ_FINISH on the first call implies that the input and output buffers are large enough to hold the entire compressed/decompressed file. */ + decomp_flags |= TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF; + in_bytes = pStream->avail_in; + out_bytes = pStream->avail_out; + status = tinfl_decompress(&pState->m_decomp, pStream->next_in, &in_bytes, pStream->next_out, pStream->next_out, &out_bytes, decomp_flags); + pState->m_last_status = status; + pStream->next_in += (mz_uint)in_bytes; + pStream->avail_in -= (mz_uint)in_bytes; + pStream->total_in += (mz_uint)in_bytes; + pStream->adler = tinfl_get_adler32(&pState->m_decomp); + pStream->next_out += (mz_uint)out_bytes; + pStream->avail_out -= (mz_uint)out_bytes; + pStream->total_out += (mz_uint)out_bytes; + + if (status < 0) + return MZ_DATA_ERROR; + else if (status != TINFL_STATUS_DONE) + { + pState->m_last_status = TINFL_STATUS_FAILED; + return MZ_BUF_ERROR; + } + return MZ_STREAM_END; + } + /* flush != MZ_FINISH then we must assume there's more input. */ + if (flush != MZ_FINISH) + decomp_flags |= TINFL_FLAG_HAS_MORE_INPUT; + + if (pState->m_dict_avail) + { + n = MZ_MIN(pState->m_dict_avail, pStream->avail_out); + memcpy(pStream->next_out, pState->m_dict + pState->m_dict_ofs, n); + pStream->next_out += n; + pStream->avail_out -= n; + pStream->total_out += n; + pState->m_dict_avail -= n; + pState->m_dict_ofs = (pState->m_dict_ofs + n) & (TINFL_LZ_DICT_SIZE - 1); + return ((pState->m_last_status == TINFL_STATUS_DONE) && (!pState->m_dict_avail)) ? MZ_STREAM_END : MZ_OK; + } + + for (;;) + { + in_bytes = pStream->avail_in; + out_bytes = TINFL_LZ_DICT_SIZE - pState->m_dict_ofs; + + status = tinfl_decompress(&pState->m_decomp, pStream->next_in, &in_bytes, pState->m_dict, pState->m_dict + pState->m_dict_ofs, &out_bytes, decomp_flags); + pState->m_last_status = status; + + pStream->next_in += (mz_uint)in_bytes; + pStream->avail_in -= (mz_uint)in_bytes; + pStream->total_in += (mz_uint)in_bytes; + pStream->adler = tinfl_get_adler32(&pState->m_decomp); + + pState->m_dict_avail = (mz_uint)out_bytes; + + n = MZ_MIN(pState->m_dict_avail, pStream->avail_out); + memcpy(pStream->next_out, pState->m_dict + pState->m_dict_ofs, n); + pStream->next_out += n; + pStream->avail_out -= n; + pStream->total_out += n; + pState->m_dict_avail -= n; + pState->m_dict_ofs = (pState->m_dict_ofs + n) & (TINFL_LZ_DICT_SIZE - 1); + + if (status < 0) + return MZ_DATA_ERROR; /* Stream is corrupted (there could be some uncompressed data left in the output dictionary - oh well). */ + else if ((status == TINFL_STATUS_NEEDS_MORE_INPUT) && (!orig_avail_in)) + return MZ_BUF_ERROR; /* Signal caller that we can't make forward progress without supplying more input or by setting flush to MZ_FINISH. */ + else if (flush == MZ_FINISH) + { + /* The output buffer MUST be large to hold the remaining uncompressed data when flush==MZ_FINISH. */ + if (status == TINFL_STATUS_DONE) + return pState->m_dict_avail ? MZ_BUF_ERROR : MZ_STREAM_END; + /* status here must be TINFL_STATUS_HAS_MORE_OUTPUT, which means there's at least 1 more byte on the way. If there's no more room left in the output buffer then something is wrong. */ + else if (!pStream->avail_out) + return MZ_BUF_ERROR; + } + else if ((status == TINFL_STATUS_DONE) || (!pStream->avail_in) || (!pStream->avail_out) || (pState->m_dict_avail)) + break; + } + + return ((status == TINFL_STATUS_DONE) && (!pState->m_dict_avail)) ? MZ_STREAM_END : MZ_OK; +} + +int mz_inflateEnd(mz_streamp pStream) +{ + if (!pStream) + return MZ_STREAM_ERROR; + if (pStream->state) + { + pStream->zfree(pStream->opaque, pStream->state); + pStream->state = NULL; + } + return MZ_OK; +} + +int mz_uncompress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len) +{ + mz_stream stream; + int status; + memset(&stream, 0, sizeof(stream)); + + /* In case mz_ulong is 64-bits (argh I hate longs). */ + if ((source_len | *pDest_len) > 0xFFFFFFFFU) + return MZ_PARAM_ERROR; + + stream.next_in = pSource; + stream.avail_in = (mz_uint32)source_len; + stream.next_out = pDest; + stream.avail_out = (mz_uint32)*pDest_len; + + status = mz_inflateInit(&stream); + if (status != MZ_OK) + return status; + + status = mz_inflate(&stream, MZ_FINISH); + if (status != MZ_STREAM_END) + { + mz_inflateEnd(&stream); + return ((status == MZ_BUF_ERROR) && (!stream.avail_in)) ? MZ_DATA_ERROR : status; + } + *pDest_len = stream.total_out; + + return mz_inflateEnd(&stream); +} + +const char *mz_error(int err) +{ + static struct + { + int m_err; + const char *m_pDesc; + } s_error_descs[] = + { + { MZ_OK, "" }, { MZ_STREAM_END, "stream end" }, { MZ_NEED_DICT, "need dictionary" }, { MZ_ERRNO, "file error" }, { MZ_STREAM_ERROR, "stream error" }, { MZ_DATA_ERROR, "data error" }, { MZ_MEM_ERROR, "out of memory" }, { MZ_BUF_ERROR, "buf error" }, { MZ_VERSION_ERROR, "version error" }, { MZ_PARAM_ERROR, "parameter error" } + }; + mz_uint i; + for (i = 0; i < sizeof(s_error_descs) / sizeof(s_error_descs[0]); ++i) + if (s_error_descs[i].m_err == err) + return s_error_descs[i].m_pDesc; + return NULL; +} + +#endif /*MINIZ_NO_ZLIB_APIS */ + +#ifdef __cplusplus +} +#endif + +/* + This is free and unencumbered software released into the public domain. + + Anyone is free to copy, modify, publish, use, compile, sell, or + distribute this software, either in source code form or as a compiled + binary, for any purpose, commercial or non-commercial, and by any + means. + + In jurisdictions that recognize copyright laws, the author or authors + of this software dedicate any and all copyright interest in the + software to the public domain. We make this dedication for the benefit + of the public at large and to the detriment of our heirs and + successors. We intend this dedication to be an overt act of + relinquishment in perpetuity of all present and future rights to this + software under copyright law. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR + OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. + + For more information, please refer to +*/ +/************************************************************************** + * + * Copyright 2013-2014 RAD Game Tools and Valve Software + * Copyright 2010-2014 Rich Geldreich and Tenacious Software LLC + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + **************************************************************************/ + + + + +#ifdef __cplusplus +extern "C" { +#endif + +/* ------------------- Low-level Compression (independent from all decompression API's) */ + +/* Purposely making these tables static for faster init and thread safety. */ +static const mz_uint16 s_tdefl_len_sym[256] = + { + 257, 258, 259, 260, 261, 262, 263, 264, 265, 265, 266, 266, 267, 267, 268, 268, 269, 269, 269, 269, 270, 270, 270, 270, 271, 271, 271, 271, 272, 272, 272, 272, + 273, 273, 273, 273, 273, 273, 273, 273, 274, 274, 274, 274, 274, 274, 274, 274, 275, 275, 275, 275, 275, 275, 275, 275, 276, 276, 276, 276, 276, 276, 276, 276, + 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, + 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, + 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, + 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, + 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, + 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 285 + }; + +static const mz_uint8 s_tdefl_len_extra[256] = + { + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0 + }; + +static const mz_uint8 s_tdefl_small_dist_sym[512] = + { + 0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17 + }; + +static const mz_uint8 s_tdefl_small_dist_extra[512] = + { + 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7 + }; + +static const mz_uint8 s_tdefl_large_dist_sym[128] = + { + 0, 0, 18, 19, 20, 20, 21, 21, 22, 22, 22, 22, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, + 28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29 + }; + +static const mz_uint8 s_tdefl_large_dist_extra[128] = + { + 0, 0, 8, 8, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13 + }; + +/* Radix sorts tdefl_sym_freq[] array by 16-bit key m_key. Returns ptr to sorted values. */ +typedef struct +{ + mz_uint16 m_key, m_sym_index; +} tdefl_sym_freq; +static tdefl_sym_freq *tdefl_radix_sort_syms(mz_uint num_syms, tdefl_sym_freq *pSyms0, tdefl_sym_freq *pSyms1) +{ + mz_uint32 total_passes = 2, pass_shift, pass, i, hist[256 * 2]; + tdefl_sym_freq *pCur_syms = pSyms0, *pNew_syms = pSyms1; + MZ_CLEAR_OBJ(hist); + for (i = 0; i < num_syms; i++) + { + mz_uint freq = pSyms0[i].m_key; + hist[freq & 0xFF]++; + hist[256 + ((freq >> 8) & 0xFF)]++; + } + while ((total_passes > 1) && (num_syms == hist[(total_passes - 1) * 256])) + total_passes--; + for (pass_shift = 0, pass = 0; pass < total_passes; pass++, pass_shift += 8) + { + const mz_uint32 *pHist = &hist[pass << 8]; + mz_uint offsets[256], cur_ofs = 0; + for (i = 0; i < 256; i++) + { + offsets[i] = cur_ofs; + cur_ofs += pHist[i]; + } + for (i = 0; i < num_syms; i++) + pNew_syms[offsets[(pCur_syms[i].m_key >> pass_shift) & 0xFF]++] = pCur_syms[i]; + { + tdefl_sym_freq *t = pCur_syms; + pCur_syms = pNew_syms; + pNew_syms = t; + } + } + return pCur_syms; +} + +/* tdefl_calculate_minimum_redundancy() originally written by: Alistair Moffat, alistair@cs.mu.oz.au, Jyrki Katajainen, jyrki@diku.dk, November 1996. */ +static void tdefl_calculate_minimum_redundancy(tdefl_sym_freq *A, int n) +{ + int root, leaf, next, avbl, used, dpth; + if (n == 0) + return; + else if (n == 1) + { + A[0].m_key = 1; + return; + } + A[0].m_key += A[1].m_key; + root = 0; + leaf = 2; + for (next = 1; next < n - 1; next++) + { + if (leaf >= n || A[root].m_key < A[leaf].m_key) + { + A[next].m_key = A[root].m_key; + A[root++].m_key = (mz_uint16)next; + } + else + A[next].m_key = A[leaf++].m_key; + if (leaf >= n || (root < next && A[root].m_key < A[leaf].m_key)) + { + A[next].m_key = (mz_uint16)(A[next].m_key + A[root].m_key); + A[root++].m_key = (mz_uint16)next; + } + else + A[next].m_key = (mz_uint16)(A[next].m_key + A[leaf++].m_key); + } + A[n - 2].m_key = 0; + for (next = n - 3; next >= 0; next--) + A[next].m_key = A[A[next].m_key].m_key + 1; + avbl = 1; + used = dpth = 0; + root = n - 2; + next = n - 1; + while (avbl > 0) + { + while (root >= 0 && (int)A[root].m_key == dpth) + { + used++; + root--; + } + while (avbl > used) + { + A[next--].m_key = (mz_uint16)(dpth); + avbl--; + } + avbl = 2 * used; + dpth++; + used = 0; + } +} + +/* Limits canonical Huffman code table's max code size. */ +enum +{ + TDEFL_MAX_SUPPORTED_HUFF_CODESIZE = 32 +}; +static void tdefl_huffman_enforce_max_code_size(int *pNum_codes, int code_list_len, int max_code_size) +{ + int i; + mz_uint32 total = 0; + if (code_list_len <= 1) + return; + for (i = max_code_size + 1; i <= TDEFL_MAX_SUPPORTED_HUFF_CODESIZE; i++) + pNum_codes[max_code_size] += pNum_codes[i]; + for (i = max_code_size; i > 0; i--) + total += (((mz_uint32)pNum_codes[i]) << (max_code_size - i)); + while (total != (1UL << max_code_size)) + { + pNum_codes[max_code_size]--; + for (i = max_code_size - 1; i > 0; i--) + if (pNum_codes[i]) + { + pNum_codes[i]--; + pNum_codes[i + 1] += 2; + break; + } + total--; + } +} + +static void tdefl_optimize_huffman_table(tdefl_compressor *d, int table_num, int table_len, int code_size_limit, int static_table) +{ + int i, j, l, num_codes[1 + TDEFL_MAX_SUPPORTED_HUFF_CODESIZE]; + mz_uint next_code[TDEFL_MAX_SUPPORTED_HUFF_CODESIZE + 1]; + MZ_CLEAR_OBJ(num_codes); + if (static_table) + { + for (i = 0; i < table_len; i++) + num_codes[d->m_huff_code_sizes[table_num][i]]++; + } + else + { + tdefl_sym_freq syms0[TDEFL_MAX_HUFF_SYMBOLS], syms1[TDEFL_MAX_HUFF_SYMBOLS], *pSyms; + int num_used_syms = 0; + const mz_uint16 *pSym_count = &d->m_huff_count[table_num][0]; + for (i = 0; i < table_len; i++) + if (pSym_count[i]) + { + syms0[num_used_syms].m_key = (mz_uint16)pSym_count[i]; + syms0[num_used_syms++].m_sym_index = (mz_uint16)i; + } + + pSyms = tdefl_radix_sort_syms(num_used_syms, syms0, syms1); + tdefl_calculate_minimum_redundancy(pSyms, num_used_syms); + + for (i = 0; i < num_used_syms; i++) + num_codes[pSyms[i].m_key]++; + + tdefl_huffman_enforce_max_code_size(num_codes, num_used_syms, code_size_limit); + + MZ_CLEAR_OBJ(d->m_huff_code_sizes[table_num]); + MZ_CLEAR_OBJ(d->m_huff_codes[table_num]); + for (i = 1, j = num_used_syms; i <= code_size_limit; i++) + for (l = num_codes[i]; l > 0; l--) + d->m_huff_code_sizes[table_num][pSyms[--j].m_sym_index] = (mz_uint8)(i); + } + + next_code[1] = 0; + for (j = 0, i = 2; i <= code_size_limit; i++) + next_code[i] = j = ((j + num_codes[i - 1]) << 1); + + for (i = 0; i < table_len; i++) + { + mz_uint rev_code = 0, code, code_size; + if ((code_size = d->m_huff_code_sizes[table_num][i]) == 0) + continue; + code = next_code[code_size]++; + for (l = code_size; l > 0; l--, code >>= 1) + rev_code = (rev_code << 1) | (code & 1); + d->m_huff_codes[table_num][i] = (mz_uint16)rev_code; + } +} + +#define TDEFL_PUT_BITS(b, l) \ + do \ + { \ + mz_uint bits = b; \ + mz_uint len = l; \ + MZ_ASSERT(bits <= ((1U << len) - 1U)); \ + d->m_bit_buffer |= (bits << d->m_bits_in); \ + d->m_bits_in += len; \ + while (d->m_bits_in >= 8) \ + { \ + if (d->m_pOutput_buf < d->m_pOutput_buf_end) \ + *d->m_pOutput_buf++ = (mz_uint8)(d->m_bit_buffer); \ + d->m_bit_buffer >>= 8; \ + d->m_bits_in -= 8; \ + } \ + } \ + MZ_MACRO_END + +#define TDEFL_RLE_PREV_CODE_SIZE() \ + { \ + if (rle_repeat_count) \ + { \ + if (rle_repeat_count < 3) \ + { \ + d->m_huff_count[2][prev_code_size] = (mz_uint16)(d->m_huff_count[2][prev_code_size] + rle_repeat_count); \ + while (rle_repeat_count--) \ + packed_code_sizes[num_packed_code_sizes++] = prev_code_size; \ + } \ + else \ + { \ + d->m_huff_count[2][16] = (mz_uint16)(d->m_huff_count[2][16] + 1); \ + packed_code_sizes[num_packed_code_sizes++] = 16; \ + packed_code_sizes[num_packed_code_sizes++] = (mz_uint8)(rle_repeat_count - 3); \ + } \ + rle_repeat_count = 0; \ + } \ + } + +#define TDEFL_RLE_ZERO_CODE_SIZE() \ + { \ + if (rle_z_count) \ + { \ + if (rle_z_count < 3) \ + { \ + d->m_huff_count[2][0] = (mz_uint16)(d->m_huff_count[2][0] + rle_z_count); \ + while (rle_z_count--) \ + packed_code_sizes[num_packed_code_sizes++] = 0; \ + } \ + else if (rle_z_count <= 10) \ + { \ + d->m_huff_count[2][17] = (mz_uint16)(d->m_huff_count[2][17] + 1); \ + packed_code_sizes[num_packed_code_sizes++] = 17; \ + packed_code_sizes[num_packed_code_sizes++] = (mz_uint8)(rle_z_count - 3); \ + } \ + else \ + { \ + d->m_huff_count[2][18] = (mz_uint16)(d->m_huff_count[2][18] + 1); \ + packed_code_sizes[num_packed_code_sizes++] = 18; \ + packed_code_sizes[num_packed_code_sizes++] = (mz_uint8)(rle_z_count - 11); \ + } \ + rle_z_count = 0; \ + } \ + } + +static mz_uint8 s_tdefl_packed_code_size_syms_swizzle[] = { 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 }; + +static void tdefl_start_dynamic_block(tdefl_compressor *d) +{ + int num_lit_codes, num_dist_codes, num_bit_lengths; + mz_uint i, total_code_sizes_to_pack, num_packed_code_sizes, rle_z_count, rle_repeat_count, packed_code_sizes_index; + mz_uint8 code_sizes_to_pack[TDEFL_MAX_HUFF_SYMBOLS_0 + TDEFL_MAX_HUFF_SYMBOLS_1], packed_code_sizes[TDEFL_MAX_HUFF_SYMBOLS_0 + TDEFL_MAX_HUFF_SYMBOLS_1], prev_code_size = 0xFF; + + d->m_huff_count[0][256] = 1; + + tdefl_optimize_huffman_table(d, 0, TDEFL_MAX_HUFF_SYMBOLS_0, 15, MZ_FALSE); + tdefl_optimize_huffman_table(d, 1, TDEFL_MAX_HUFF_SYMBOLS_1, 15, MZ_FALSE); + + for (num_lit_codes = 286; num_lit_codes > 257; num_lit_codes--) + if (d->m_huff_code_sizes[0][num_lit_codes - 1]) + break; + for (num_dist_codes = 30; num_dist_codes > 1; num_dist_codes--) + if (d->m_huff_code_sizes[1][num_dist_codes - 1]) + break; + + memcpy(code_sizes_to_pack, &d->m_huff_code_sizes[0][0], num_lit_codes); + memcpy(code_sizes_to_pack + num_lit_codes, &d->m_huff_code_sizes[1][0], num_dist_codes); + total_code_sizes_to_pack = num_lit_codes + num_dist_codes; + num_packed_code_sizes = 0; + rle_z_count = 0; + rle_repeat_count = 0; + + memset(&d->m_huff_count[2][0], 0, sizeof(d->m_huff_count[2][0]) * TDEFL_MAX_HUFF_SYMBOLS_2); + for (i = 0; i < total_code_sizes_to_pack; i++) + { + mz_uint8 code_size = code_sizes_to_pack[i]; + if (!code_size) + { + TDEFL_RLE_PREV_CODE_SIZE(); + if (++rle_z_count == 138) + { + TDEFL_RLE_ZERO_CODE_SIZE(); + } + } + else + { + TDEFL_RLE_ZERO_CODE_SIZE(); + if (code_size != prev_code_size) + { + TDEFL_RLE_PREV_CODE_SIZE(); + d->m_huff_count[2][code_size] = (mz_uint16)(d->m_huff_count[2][code_size] + 1); + packed_code_sizes[num_packed_code_sizes++] = code_size; + } + else if (++rle_repeat_count == 6) + { + TDEFL_RLE_PREV_CODE_SIZE(); + } + } + prev_code_size = code_size; + } + if (rle_repeat_count) + { + TDEFL_RLE_PREV_CODE_SIZE(); + } + else + { + TDEFL_RLE_ZERO_CODE_SIZE(); + } + + tdefl_optimize_huffman_table(d, 2, TDEFL_MAX_HUFF_SYMBOLS_2, 7, MZ_FALSE); + + TDEFL_PUT_BITS(2, 2); + + TDEFL_PUT_BITS(num_lit_codes - 257, 5); + TDEFL_PUT_BITS(num_dist_codes - 1, 5); + + for (num_bit_lengths = 18; num_bit_lengths >= 0; num_bit_lengths--) + if (d->m_huff_code_sizes[2][s_tdefl_packed_code_size_syms_swizzle[num_bit_lengths]]) + break; + num_bit_lengths = MZ_MAX(4, (num_bit_lengths + 1)); + TDEFL_PUT_BITS(num_bit_lengths - 4, 4); + for (i = 0; (int)i < num_bit_lengths; i++) + TDEFL_PUT_BITS(d->m_huff_code_sizes[2][s_tdefl_packed_code_size_syms_swizzle[i]], 3); + + for (packed_code_sizes_index = 0; packed_code_sizes_index < num_packed_code_sizes;) + { + mz_uint code = packed_code_sizes[packed_code_sizes_index++]; + MZ_ASSERT(code < TDEFL_MAX_HUFF_SYMBOLS_2); + TDEFL_PUT_BITS(d->m_huff_codes[2][code], d->m_huff_code_sizes[2][code]); + if (code >= 16) + TDEFL_PUT_BITS(packed_code_sizes[packed_code_sizes_index++], "\02\03\07"[code - 16]); + } +} + +static void tdefl_start_static_block(tdefl_compressor *d) +{ + mz_uint i; + mz_uint8 *p = &d->m_huff_code_sizes[0][0]; + + for (i = 0; i <= 143; ++i) + *p++ = 8; + for (; i <= 255; ++i) + *p++ = 9; + for (; i <= 279; ++i) + *p++ = 7; + for (; i <= 287; ++i) + *p++ = 8; + + memset(d->m_huff_code_sizes[1], 5, 32); + + tdefl_optimize_huffman_table(d, 0, 288, 15, MZ_TRUE); + tdefl_optimize_huffman_table(d, 1, 32, 15, MZ_TRUE); + + TDEFL_PUT_BITS(1, 2); +} + +static const mz_uint mz_bitmasks[17] = { 0x0000, 0x0001, 0x0003, 0x0007, 0x000F, 0x001F, 0x003F, 0x007F, 0x00FF, 0x01FF, 0x03FF, 0x07FF, 0x0FFF, 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF }; + +#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN && MINIZ_HAS_64BIT_REGISTERS +static mz_bool tdefl_compress_lz_codes(tdefl_compressor *d) +{ + mz_uint flags; + mz_uint8 *pLZ_codes; + mz_uint8 *pOutput_buf = d->m_pOutput_buf; + mz_uint8 *pLZ_code_buf_end = d->m_pLZ_code_buf; + mz_uint64 bit_buffer = d->m_bit_buffer; + mz_uint bits_in = d->m_bits_in; + +#define TDEFL_PUT_BITS_FAST(b, l) \ + { \ + bit_buffer |= (((mz_uint64)(b)) << bits_in); \ + bits_in += (l); \ + } + + flags = 1; + for (pLZ_codes = d->m_lz_code_buf; pLZ_codes < pLZ_code_buf_end; flags >>= 1) + { + if (flags == 1) + flags = *pLZ_codes++ | 0x100; + + if (flags & 1) + { + mz_uint s0, s1, n0, n1, sym, num_extra_bits; + mz_uint match_len = pLZ_codes[0], match_dist = *(const mz_uint16 *)(pLZ_codes + 1); + pLZ_codes += 3; + + MZ_ASSERT(d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]); + TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][s_tdefl_len_sym[match_len]], d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]); + TDEFL_PUT_BITS_FAST(match_len & mz_bitmasks[s_tdefl_len_extra[match_len]], s_tdefl_len_extra[match_len]); + + /* This sequence coaxes MSVC into using cmov's vs. jmp's. */ + s0 = s_tdefl_small_dist_sym[match_dist & 511]; + n0 = s_tdefl_small_dist_extra[match_dist & 511]; + s1 = s_tdefl_large_dist_sym[match_dist >> 8]; + n1 = s_tdefl_large_dist_extra[match_dist >> 8]; + sym = (match_dist < 512) ? s0 : s1; + num_extra_bits = (match_dist < 512) ? n0 : n1; + + MZ_ASSERT(d->m_huff_code_sizes[1][sym]); + TDEFL_PUT_BITS_FAST(d->m_huff_codes[1][sym], d->m_huff_code_sizes[1][sym]); + TDEFL_PUT_BITS_FAST(match_dist & mz_bitmasks[num_extra_bits], num_extra_bits); + } + else + { + mz_uint lit = *pLZ_codes++; + MZ_ASSERT(d->m_huff_code_sizes[0][lit]); + TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][lit], d->m_huff_code_sizes[0][lit]); + + if (((flags & 2) == 0) && (pLZ_codes < pLZ_code_buf_end)) + { + flags >>= 1; + lit = *pLZ_codes++; + MZ_ASSERT(d->m_huff_code_sizes[0][lit]); + TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][lit], d->m_huff_code_sizes[0][lit]); + + if (((flags & 2) == 0) && (pLZ_codes < pLZ_code_buf_end)) + { + flags >>= 1; + lit = *pLZ_codes++; + MZ_ASSERT(d->m_huff_code_sizes[0][lit]); + TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][lit], d->m_huff_code_sizes[0][lit]); + } + } + } + + if (pOutput_buf >= d->m_pOutput_buf_end) + return MZ_FALSE; + + *(mz_uint64 *)pOutput_buf = bit_buffer; + pOutput_buf += (bits_in >> 3); + bit_buffer >>= (bits_in & ~7); + bits_in &= 7; + } + +#undef TDEFL_PUT_BITS_FAST + + d->m_pOutput_buf = pOutput_buf; + d->m_bits_in = 0; + d->m_bit_buffer = 0; + + while (bits_in) + { + mz_uint32 n = MZ_MIN(bits_in, 16); + TDEFL_PUT_BITS((mz_uint)bit_buffer & mz_bitmasks[n], n); + bit_buffer >>= n; + bits_in -= n; + } + + TDEFL_PUT_BITS(d->m_huff_codes[0][256], d->m_huff_code_sizes[0][256]); + + return (d->m_pOutput_buf < d->m_pOutput_buf_end); +} +#else +static mz_bool tdefl_compress_lz_codes(tdefl_compressor *d) +{ + mz_uint flags; + mz_uint8 *pLZ_codes; + + flags = 1; + for (pLZ_codes = d->m_lz_code_buf; pLZ_codes < d->m_pLZ_code_buf; flags >>= 1) + { + if (flags == 1) + flags = *pLZ_codes++ | 0x100; + if (flags & 1) + { + mz_uint sym, num_extra_bits; + mz_uint match_len = pLZ_codes[0], match_dist = (pLZ_codes[1] | (pLZ_codes[2] << 8)); + pLZ_codes += 3; + + MZ_ASSERT(d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]); + TDEFL_PUT_BITS(d->m_huff_codes[0][s_tdefl_len_sym[match_len]], d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]); + TDEFL_PUT_BITS(match_len & mz_bitmasks[s_tdefl_len_extra[match_len]], s_tdefl_len_extra[match_len]); + + if (match_dist < 512) + { + sym = s_tdefl_small_dist_sym[match_dist]; + num_extra_bits = s_tdefl_small_dist_extra[match_dist]; + } + else + { + sym = s_tdefl_large_dist_sym[match_dist >> 8]; + num_extra_bits = s_tdefl_large_dist_extra[match_dist >> 8]; + } + MZ_ASSERT(d->m_huff_code_sizes[1][sym]); + TDEFL_PUT_BITS(d->m_huff_codes[1][sym], d->m_huff_code_sizes[1][sym]); + TDEFL_PUT_BITS(match_dist & mz_bitmasks[num_extra_bits], num_extra_bits); + } + else + { + mz_uint lit = *pLZ_codes++; + MZ_ASSERT(d->m_huff_code_sizes[0][lit]); + TDEFL_PUT_BITS(d->m_huff_codes[0][lit], d->m_huff_code_sizes[0][lit]); + } + } + + TDEFL_PUT_BITS(d->m_huff_codes[0][256], d->m_huff_code_sizes[0][256]); + + return (d->m_pOutput_buf < d->m_pOutput_buf_end); +} +#endif /* MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN && MINIZ_HAS_64BIT_REGISTERS */ + +static mz_bool tdefl_compress_block(tdefl_compressor *d, mz_bool static_block) +{ + if (static_block) + tdefl_start_static_block(d); + else + tdefl_start_dynamic_block(d); + return tdefl_compress_lz_codes(d); +} + +static int tdefl_flush_block(tdefl_compressor *d, int flush) +{ + mz_uint saved_bit_buf, saved_bits_in; + mz_uint8 *pSaved_output_buf; + mz_bool comp_block_succeeded = MZ_FALSE; + int n, use_raw_block = ((d->m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS) != 0) && (d->m_lookahead_pos - d->m_lz_code_buf_dict_pos) <= d->m_dict_size; + mz_uint8 *pOutput_buf_start = ((d->m_pPut_buf_func == NULL) && ((*d->m_pOut_buf_size - d->m_out_buf_ofs) >= TDEFL_OUT_BUF_SIZE)) ? ((mz_uint8 *)d->m_pOut_buf + d->m_out_buf_ofs) : d->m_output_buf; + + d->m_pOutput_buf = pOutput_buf_start; + d->m_pOutput_buf_end = d->m_pOutput_buf + TDEFL_OUT_BUF_SIZE - 16; + + MZ_ASSERT(!d->m_output_flush_remaining); + d->m_output_flush_ofs = 0; + d->m_output_flush_remaining = 0; + + *d->m_pLZ_flags = (mz_uint8)(*d->m_pLZ_flags >> d->m_num_flags_left); + d->m_pLZ_code_buf -= (d->m_num_flags_left == 8); + + if ((d->m_flags & TDEFL_WRITE_ZLIB_HEADER) && (!d->m_block_index)) + { + TDEFL_PUT_BITS(0x78, 8); + TDEFL_PUT_BITS(0x01, 8); + } + + TDEFL_PUT_BITS(flush == TDEFL_FINISH, 1); + + pSaved_output_buf = d->m_pOutput_buf; + saved_bit_buf = d->m_bit_buffer; + saved_bits_in = d->m_bits_in; + + if (!use_raw_block) + comp_block_succeeded = tdefl_compress_block(d, (d->m_flags & TDEFL_FORCE_ALL_STATIC_BLOCKS) || (d->m_total_lz_bytes < 48)); + + /* If the block gets expanded, forget the current contents of the output buffer and send a raw block instead. */ + if (((use_raw_block) || ((d->m_total_lz_bytes) && ((d->m_pOutput_buf - pSaved_output_buf + 1U) >= d->m_total_lz_bytes))) && + ((d->m_lookahead_pos - d->m_lz_code_buf_dict_pos) <= d->m_dict_size)) + { + mz_uint i; + d->m_pOutput_buf = pSaved_output_buf; + d->m_bit_buffer = saved_bit_buf, d->m_bits_in = saved_bits_in; + TDEFL_PUT_BITS(0, 2); + if (d->m_bits_in) + { + TDEFL_PUT_BITS(0, 8 - d->m_bits_in); + } + for (i = 2; i; --i, d->m_total_lz_bytes ^= 0xFFFF) + { + TDEFL_PUT_BITS(d->m_total_lz_bytes & 0xFFFF, 16); + } + for (i = 0; i < d->m_total_lz_bytes; ++i) + { + TDEFL_PUT_BITS(d->m_dict[(d->m_lz_code_buf_dict_pos + i) & TDEFL_LZ_DICT_SIZE_MASK], 8); + } + } + /* Check for the extremely unlikely (if not impossible) case of the compressed block not fitting into the output buffer when using dynamic codes. */ + else if (!comp_block_succeeded) + { + d->m_pOutput_buf = pSaved_output_buf; + d->m_bit_buffer = saved_bit_buf, d->m_bits_in = saved_bits_in; + tdefl_compress_block(d, MZ_TRUE); + } + + if (flush) + { + if (flush == TDEFL_FINISH) + { + if (d->m_bits_in) + { + TDEFL_PUT_BITS(0, 8 - d->m_bits_in); + } + if (d->m_flags & TDEFL_WRITE_ZLIB_HEADER) + { + mz_uint i, a = d->m_adler32; + for (i = 0; i < 4; i++) + { + TDEFL_PUT_BITS((a >> 24) & 0xFF, 8); + a <<= 8; + } + } + } + else + { + mz_uint i, z = 0; + TDEFL_PUT_BITS(0, 3); + if (d->m_bits_in) + { + TDEFL_PUT_BITS(0, 8 - d->m_bits_in); + } + for (i = 2; i; --i, z ^= 0xFFFF) + { + TDEFL_PUT_BITS(z & 0xFFFF, 16); + } + } + } + + MZ_ASSERT(d->m_pOutput_buf < d->m_pOutput_buf_end); + + memset(&d->m_huff_count[0][0], 0, sizeof(d->m_huff_count[0][0]) * TDEFL_MAX_HUFF_SYMBOLS_0); + memset(&d->m_huff_count[1][0], 0, sizeof(d->m_huff_count[1][0]) * TDEFL_MAX_HUFF_SYMBOLS_1); + + d->m_pLZ_code_buf = d->m_lz_code_buf + 1; + d->m_pLZ_flags = d->m_lz_code_buf; + d->m_num_flags_left = 8; + d->m_lz_code_buf_dict_pos += d->m_total_lz_bytes; + d->m_total_lz_bytes = 0; + d->m_block_index++; + + if ((n = (int)(d->m_pOutput_buf - pOutput_buf_start)) != 0) + { + if (d->m_pPut_buf_func) + { + *d->m_pIn_buf_size = d->m_pSrc - (const mz_uint8 *)d->m_pIn_buf; + if (!(*d->m_pPut_buf_func)(d->m_output_buf, n, d->m_pPut_buf_user)) + return (d->m_prev_return_status = TDEFL_STATUS_PUT_BUF_FAILED); + } + else if (pOutput_buf_start == d->m_output_buf) + { + int bytes_to_copy = (int)MZ_MIN((size_t)n, (size_t)(*d->m_pOut_buf_size - d->m_out_buf_ofs)); + memcpy((mz_uint8 *)d->m_pOut_buf + d->m_out_buf_ofs, d->m_output_buf, bytes_to_copy); + d->m_out_buf_ofs += bytes_to_copy; + if ((n -= bytes_to_copy) != 0) + { + d->m_output_flush_ofs = bytes_to_copy; + d->m_output_flush_remaining = n; + } + } + else + { + d->m_out_buf_ofs += n; + } + } + + return d->m_output_flush_remaining; +} + +#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES +#ifdef MINIZ_UNALIGNED_USE_MEMCPY +static mz_uint16 TDEFL_READ_UNALIGNED_WORD(const mz_uint8* p) +{ + mz_uint16 ret; + memcpy(&ret, p, sizeof(mz_uint16)); + return ret; +} +static mz_uint16 TDEFL_READ_UNALIGNED_WORD2(const mz_uint16* p) +{ + mz_uint16 ret; + memcpy(&ret, p, sizeof(mz_uint16)); + return ret; +} +#else +#define TDEFL_READ_UNALIGNED_WORD(p) *(const mz_uint16 *)(p) +#define TDEFL_READ_UNALIGNED_WORD2(p) *(const mz_uint16 *)(p) +#endif +static MZ_FORCEINLINE void tdefl_find_match(tdefl_compressor *d, mz_uint lookahead_pos, mz_uint max_dist, mz_uint max_match_len, mz_uint *pMatch_dist, mz_uint *pMatch_len) +{ + mz_uint dist, pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK, match_len = *pMatch_len, probe_pos = pos, next_probe_pos, probe_len; + mz_uint num_probes_left = d->m_max_probes[match_len >= 32]; + const mz_uint16 *s = (const mz_uint16 *)(d->m_dict + pos), *p, *q; + mz_uint16 c01 = TDEFL_READ_UNALIGNED_WORD(&d->m_dict[pos + match_len - 1]), s01 = TDEFL_READ_UNALIGNED_WORD2(s); + MZ_ASSERT(max_match_len <= TDEFL_MAX_MATCH_LEN); + if (max_match_len <= match_len) + return; + for (;;) + { + for (;;) + { + if (--num_probes_left == 0) + return; +#define TDEFL_PROBE \ + next_probe_pos = d->m_next[probe_pos]; \ + if ((!next_probe_pos) || ((dist = (mz_uint16)(lookahead_pos - next_probe_pos)) > max_dist)) \ + return; \ + probe_pos = next_probe_pos & TDEFL_LZ_DICT_SIZE_MASK; \ + if (TDEFL_READ_UNALIGNED_WORD(&d->m_dict[probe_pos + match_len - 1]) == c01) \ + break; + TDEFL_PROBE; + TDEFL_PROBE; + TDEFL_PROBE; + } + if (!dist) + break; + q = (const mz_uint16 *)(d->m_dict + probe_pos); + if (TDEFL_READ_UNALIGNED_WORD2(q) != s01) + continue; + p = s; + probe_len = 32; + do + { + } while ((TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) && (TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) && + (TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) && (TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) && (--probe_len > 0)); + if (!probe_len) + { + *pMatch_dist = dist; + *pMatch_len = MZ_MIN(max_match_len, (mz_uint)TDEFL_MAX_MATCH_LEN); + break; + } + else if ((probe_len = ((mz_uint)(p - s) * 2) + (mz_uint)(*(const mz_uint8 *)p == *(const mz_uint8 *)q)) > match_len) + { + *pMatch_dist = dist; + if ((*pMatch_len = match_len = MZ_MIN(max_match_len, probe_len)) == max_match_len) + break; + c01 = TDEFL_READ_UNALIGNED_WORD(&d->m_dict[pos + match_len - 1]); + } + } +} +#else +static MZ_FORCEINLINE void tdefl_find_match(tdefl_compressor *d, mz_uint lookahead_pos, mz_uint max_dist, mz_uint max_match_len, mz_uint *pMatch_dist, mz_uint *pMatch_len) +{ + mz_uint dist, pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK, match_len = *pMatch_len, probe_pos = pos, next_probe_pos, probe_len; + mz_uint num_probes_left = d->m_max_probes[match_len >= 32]; + const mz_uint8 *s = d->m_dict + pos, *p, *q; + mz_uint8 c0 = d->m_dict[pos + match_len], c1 = d->m_dict[pos + match_len - 1]; + MZ_ASSERT(max_match_len <= TDEFL_MAX_MATCH_LEN); + if (max_match_len <= match_len) + return; + for (;;) + { + for (;;) + { + if (--num_probes_left == 0) + return; +#define TDEFL_PROBE \ + next_probe_pos = d->m_next[probe_pos]; \ + if ((!next_probe_pos) || ((dist = (mz_uint16)(lookahead_pos - next_probe_pos)) > max_dist)) \ + return; \ + probe_pos = next_probe_pos & TDEFL_LZ_DICT_SIZE_MASK; \ + if ((d->m_dict[probe_pos + match_len] == c0) && (d->m_dict[probe_pos + match_len - 1] == c1)) \ + break; + TDEFL_PROBE; + TDEFL_PROBE; + TDEFL_PROBE; + } + if (!dist) + break; + p = s; + q = d->m_dict + probe_pos; + for (probe_len = 0; probe_len < max_match_len; probe_len++) + if (*p++ != *q++) + break; + if (probe_len > match_len) + { + *pMatch_dist = dist; + if ((*pMatch_len = match_len = probe_len) == max_match_len) + return; + c0 = d->m_dict[pos + match_len]; + c1 = d->m_dict[pos + match_len - 1]; + } + } +} +#endif /* #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES */ + +#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN +#ifdef MINIZ_UNALIGNED_USE_MEMCPY +static mz_uint32 TDEFL_READ_UNALIGNED_WORD32(const mz_uint8* p) +{ + mz_uint32 ret; + memcpy(&ret, p, sizeof(mz_uint32)); + return ret; +} +#else +#define TDEFL_READ_UNALIGNED_WORD32(p) *(const mz_uint32 *)(p) +#endif +static mz_bool tdefl_compress_fast(tdefl_compressor *d) +{ + /* Faster, minimally featured LZRW1-style match+parse loop with better register utilization. Intended for applications where raw throughput is valued more highly than ratio. */ + mz_uint lookahead_pos = d->m_lookahead_pos, lookahead_size = d->m_lookahead_size, dict_size = d->m_dict_size, total_lz_bytes = d->m_total_lz_bytes, num_flags_left = d->m_num_flags_left; + mz_uint8 *pLZ_code_buf = d->m_pLZ_code_buf, *pLZ_flags = d->m_pLZ_flags; + mz_uint cur_pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK; + + while ((d->m_src_buf_left) || ((d->m_flush) && (lookahead_size))) + { + const mz_uint TDEFL_COMP_FAST_LOOKAHEAD_SIZE = 4096; + mz_uint dst_pos = (lookahead_pos + lookahead_size) & TDEFL_LZ_DICT_SIZE_MASK; + mz_uint num_bytes_to_process = (mz_uint)MZ_MIN(d->m_src_buf_left, TDEFL_COMP_FAST_LOOKAHEAD_SIZE - lookahead_size); + d->m_src_buf_left -= num_bytes_to_process; + lookahead_size += num_bytes_to_process; + + while (num_bytes_to_process) + { + mz_uint32 n = MZ_MIN(TDEFL_LZ_DICT_SIZE - dst_pos, num_bytes_to_process); + memcpy(d->m_dict + dst_pos, d->m_pSrc, n); + if (dst_pos < (TDEFL_MAX_MATCH_LEN - 1)) + memcpy(d->m_dict + TDEFL_LZ_DICT_SIZE + dst_pos, d->m_pSrc, MZ_MIN(n, (TDEFL_MAX_MATCH_LEN - 1) - dst_pos)); + d->m_pSrc += n; + dst_pos = (dst_pos + n) & TDEFL_LZ_DICT_SIZE_MASK; + num_bytes_to_process -= n; + } + + dict_size = MZ_MIN(TDEFL_LZ_DICT_SIZE - lookahead_size, dict_size); + if ((!d->m_flush) && (lookahead_size < TDEFL_COMP_FAST_LOOKAHEAD_SIZE)) + break; + + while (lookahead_size >= 4) + { + mz_uint cur_match_dist, cur_match_len = 1; + mz_uint8 *pCur_dict = d->m_dict + cur_pos; + mz_uint first_trigram = TDEFL_READ_UNALIGNED_WORD32(pCur_dict) & 0xFFFFFF; + mz_uint hash = (first_trigram ^ (first_trigram >> (24 - (TDEFL_LZ_HASH_BITS - 8)))) & TDEFL_LEVEL1_HASH_SIZE_MASK; + mz_uint probe_pos = d->m_hash[hash]; + d->m_hash[hash] = (mz_uint16)lookahead_pos; + + if (((cur_match_dist = (mz_uint16)(lookahead_pos - probe_pos)) <= dict_size) && ((TDEFL_READ_UNALIGNED_WORD32(d->m_dict + (probe_pos &= TDEFL_LZ_DICT_SIZE_MASK)) & 0xFFFFFF) == first_trigram)) + { + const mz_uint16 *p = (const mz_uint16 *)pCur_dict; + const mz_uint16 *q = (const mz_uint16 *)(d->m_dict + probe_pos); + mz_uint32 probe_len = 32; + do + { + } while ((TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) && (TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) && + (TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) && (TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) && (--probe_len > 0)); + cur_match_len = ((mz_uint)(p - (const mz_uint16 *)pCur_dict) * 2) + (mz_uint)(*(const mz_uint8 *)p == *(const mz_uint8 *)q); + if (!probe_len) + cur_match_len = cur_match_dist ? TDEFL_MAX_MATCH_LEN : 0; + + if ((cur_match_len < TDEFL_MIN_MATCH_LEN) || ((cur_match_len == TDEFL_MIN_MATCH_LEN) && (cur_match_dist >= 8U * 1024U))) + { + cur_match_len = 1; + *pLZ_code_buf++ = (mz_uint8)first_trigram; + *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1); + d->m_huff_count[0][(mz_uint8)first_trigram]++; + } + else + { + mz_uint32 s0, s1; + cur_match_len = MZ_MIN(cur_match_len, lookahead_size); + + MZ_ASSERT((cur_match_len >= TDEFL_MIN_MATCH_LEN) && (cur_match_dist >= 1) && (cur_match_dist <= TDEFL_LZ_DICT_SIZE)); + + cur_match_dist--; + + pLZ_code_buf[0] = (mz_uint8)(cur_match_len - TDEFL_MIN_MATCH_LEN); +#ifdef MINIZ_UNALIGNED_USE_MEMCPY + memcpy(&pLZ_code_buf[1], &cur_match_dist, sizeof(cur_match_dist)); +#else + *(mz_uint16 *)(&pLZ_code_buf[1]) = (mz_uint16)cur_match_dist; +#endif + pLZ_code_buf += 3; + *pLZ_flags = (mz_uint8)((*pLZ_flags >> 1) | 0x80); + + s0 = s_tdefl_small_dist_sym[cur_match_dist & 511]; + s1 = s_tdefl_large_dist_sym[cur_match_dist >> 8]; + d->m_huff_count[1][(cur_match_dist < 512) ? s0 : s1]++; + + d->m_huff_count[0][s_tdefl_len_sym[cur_match_len - TDEFL_MIN_MATCH_LEN]]++; + } + } + else + { + *pLZ_code_buf++ = (mz_uint8)first_trigram; + *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1); + d->m_huff_count[0][(mz_uint8)first_trigram]++; + } + + if (--num_flags_left == 0) + { + num_flags_left = 8; + pLZ_flags = pLZ_code_buf++; + } + + total_lz_bytes += cur_match_len; + lookahead_pos += cur_match_len; + dict_size = MZ_MIN(dict_size + cur_match_len, (mz_uint)TDEFL_LZ_DICT_SIZE); + cur_pos = (cur_pos + cur_match_len) & TDEFL_LZ_DICT_SIZE_MASK; + MZ_ASSERT(lookahead_size >= cur_match_len); + lookahead_size -= cur_match_len; + + if (pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8]) + { + int n; + d->m_lookahead_pos = lookahead_pos; + d->m_lookahead_size = lookahead_size; + d->m_dict_size = dict_size; + d->m_total_lz_bytes = total_lz_bytes; + d->m_pLZ_code_buf = pLZ_code_buf; + d->m_pLZ_flags = pLZ_flags; + d->m_num_flags_left = num_flags_left; + if ((n = tdefl_flush_block(d, 0)) != 0) + return (n < 0) ? MZ_FALSE : MZ_TRUE; + total_lz_bytes = d->m_total_lz_bytes; + pLZ_code_buf = d->m_pLZ_code_buf; + pLZ_flags = d->m_pLZ_flags; + num_flags_left = d->m_num_flags_left; + } + } + + while (lookahead_size) + { + mz_uint8 lit = d->m_dict[cur_pos]; + + total_lz_bytes++; + *pLZ_code_buf++ = lit; + *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1); + if (--num_flags_left == 0) + { + num_flags_left = 8; + pLZ_flags = pLZ_code_buf++; + } + + d->m_huff_count[0][lit]++; + + lookahead_pos++; + dict_size = MZ_MIN(dict_size + 1, (mz_uint)TDEFL_LZ_DICT_SIZE); + cur_pos = (cur_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK; + lookahead_size--; + + if (pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8]) + { + int n; + d->m_lookahead_pos = lookahead_pos; + d->m_lookahead_size = lookahead_size; + d->m_dict_size = dict_size; + d->m_total_lz_bytes = total_lz_bytes; + d->m_pLZ_code_buf = pLZ_code_buf; + d->m_pLZ_flags = pLZ_flags; + d->m_num_flags_left = num_flags_left; + if ((n = tdefl_flush_block(d, 0)) != 0) + return (n < 0) ? MZ_FALSE : MZ_TRUE; + total_lz_bytes = d->m_total_lz_bytes; + pLZ_code_buf = d->m_pLZ_code_buf; + pLZ_flags = d->m_pLZ_flags; + num_flags_left = d->m_num_flags_left; + } + } + } + + d->m_lookahead_pos = lookahead_pos; + d->m_lookahead_size = lookahead_size; + d->m_dict_size = dict_size; + d->m_total_lz_bytes = total_lz_bytes; + d->m_pLZ_code_buf = pLZ_code_buf; + d->m_pLZ_flags = pLZ_flags; + d->m_num_flags_left = num_flags_left; + return MZ_TRUE; +} +#endif /* MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN */ + +static MZ_FORCEINLINE void tdefl_record_literal(tdefl_compressor *d, mz_uint8 lit) +{ + d->m_total_lz_bytes++; + *d->m_pLZ_code_buf++ = lit; + *d->m_pLZ_flags = (mz_uint8)(*d->m_pLZ_flags >> 1); + if (--d->m_num_flags_left == 0) + { + d->m_num_flags_left = 8; + d->m_pLZ_flags = d->m_pLZ_code_buf++; + } + d->m_huff_count[0][lit]++; +} + +static MZ_FORCEINLINE void tdefl_record_match(tdefl_compressor *d, mz_uint match_len, mz_uint match_dist) +{ + mz_uint32 s0, s1; + + MZ_ASSERT((match_len >= TDEFL_MIN_MATCH_LEN) && (match_dist >= 1) && (match_dist <= TDEFL_LZ_DICT_SIZE)); + + d->m_total_lz_bytes += match_len; + + d->m_pLZ_code_buf[0] = (mz_uint8)(match_len - TDEFL_MIN_MATCH_LEN); + + match_dist -= 1; + d->m_pLZ_code_buf[1] = (mz_uint8)(match_dist & 0xFF); + d->m_pLZ_code_buf[2] = (mz_uint8)(match_dist >> 8); + d->m_pLZ_code_buf += 3; + + *d->m_pLZ_flags = (mz_uint8)((*d->m_pLZ_flags >> 1) | 0x80); + if (--d->m_num_flags_left == 0) + { + d->m_num_flags_left = 8; + d->m_pLZ_flags = d->m_pLZ_code_buf++; + } + + s0 = s_tdefl_small_dist_sym[match_dist & 511]; + s1 = s_tdefl_large_dist_sym[(match_dist >> 8) & 127]; + d->m_huff_count[1][(match_dist < 512) ? s0 : s1]++; + + if (match_len >= TDEFL_MIN_MATCH_LEN) + d->m_huff_count[0][s_tdefl_len_sym[match_len - TDEFL_MIN_MATCH_LEN]]++; +} + +static mz_bool tdefl_compress_normal(tdefl_compressor *d) +{ + const mz_uint8 *pSrc = d->m_pSrc; + size_t src_buf_left = d->m_src_buf_left; + tdefl_flush flush = d->m_flush; + + while ((src_buf_left) || ((flush) && (d->m_lookahead_size))) + { + mz_uint len_to_move, cur_match_dist, cur_match_len, cur_pos; + /* Update dictionary and hash chains. Keeps the lookahead size equal to TDEFL_MAX_MATCH_LEN. */ + if ((d->m_lookahead_size + d->m_dict_size) >= (TDEFL_MIN_MATCH_LEN - 1)) + { + mz_uint dst_pos = (d->m_lookahead_pos + d->m_lookahead_size) & TDEFL_LZ_DICT_SIZE_MASK, ins_pos = d->m_lookahead_pos + d->m_lookahead_size - 2; + mz_uint hash = (d->m_dict[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] << TDEFL_LZ_HASH_SHIFT) ^ d->m_dict[(ins_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK]; + mz_uint num_bytes_to_process = (mz_uint)MZ_MIN(src_buf_left, TDEFL_MAX_MATCH_LEN - d->m_lookahead_size); + const mz_uint8 *pSrc_end = pSrc + num_bytes_to_process; + src_buf_left -= num_bytes_to_process; + d->m_lookahead_size += num_bytes_to_process; + while (pSrc != pSrc_end) + { + mz_uint8 c = *pSrc++; + d->m_dict[dst_pos] = c; + if (dst_pos < (TDEFL_MAX_MATCH_LEN - 1)) + d->m_dict[TDEFL_LZ_DICT_SIZE + dst_pos] = c; + hash = ((hash << TDEFL_LZ_HASH_SHIFT) ^ c) & (TDEFL_LZ_HASH_SIZE - 1); + d->m_next[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] = d->m_hash[hash]; + d->m_hash[hash] = (mz_uint16)(ins_pos); + dst_pos = (dst_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK; + ins_pos++; + } + } + else + { + while ((src_buf_left) && (d->m_lookahead_size < TDEFL_MAX_MATCH_LEN)) + { + mz_uint8 c = *pSrc++; + mz_uint dst_pos = (d->m_lookahead_pos + d->m_lookahead_size) & TDEFL_LZ_DICT_SIZE_MASK; + src_buf_left--; + d->m_dict[dst_pos] = c; + if (dst_pos < (TDEFL_MAX_MATCH_LEN - 1)) + d->m_dict[TDEFL_LZ_DICT_SIZE + dst_pos] = c; + if ((++d->m_lookahead_size + d->m_dict_size) >= TDEFL_MIN_MATCH_LEN) + { + mz_uint ins_pos = d->m_lookahead_pos + (d->m_lookahead_size - 1) - 2; + mz_uint hash = ((d->m_dict[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] << (TDEFL_LZ_HASH_SHIFT * 2)) ^ (d->m_dict[(ins_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK] << TDEFL_LZ_HASH_SHIFT) ^ c) & (TDEFL_LZ_HASH_SIZE - 1); + d->m_next[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] = d->m_hash[hash]; + d->m_hash[hash] = (mz_uint16)(ins_pos); + } + } + } + d->m_dict_size = MZ_MIN(TDEFL_LZ_DICT_SIZE - d->m_lookahead_size, d->m_dict_size); + if ((!flush) && (d->m_lookahead_size < TDEFL_MAX_MATCH_LEN)) + break; + + /* Simple lazy/greedy parsing state machine. */ + len_to_move = 1; + cur_match_dist = 0; + cur_match_len = d->m_saved_match_len ? d->m_saved_match_len : (TDEFL_MIN_MATCH_LEN - 1); + cur_pos = d->m_lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK; + if (d->m_flags & (TDEFL_RLE_MATCHES | TDEFL_FORCE_ALL_RAW_BLOCKS)) + { + if ((d->m_dict_size) && (!(d->m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS))) + { + mz_uint8 c = d->m_dict[(cur_pos - 1) & TDEFL_LZ_DICT_SIZE_MASK]; + cur_match_len = 0; + while (cur_match_len < d->m_lookahead_size) + { + if (d->m_dict[cur_pos + cur_match_len] != c) + break; + cur_match_len++; + } + if (cur_match_len < TDEFL_MIN_MATCH_LEN) + cur_match_len = 0; + else + cur_match_dist = 1; + } + } + else + { + tdefl_find_match(d, d->m_lookahead_pos, d->m_dict_size, d->m_lookahead_size, &cur_match_dist, &cur_match_len); + } + if (((cur_match_len == TDEFL_MIN_MATCH_LEN) && (cur_match_dist >= 8U * 1024U)) || (cur_pos == cur_match_dist) || ((d->m_flags & TDEFL_FILTER_MATCHES) && (cur_match_len <= 5))) + { + cur_match_dist = cur_match_len = 0; + } + if (d->m_saved_match_len) + { + if (cur_match_len > d->m_saved_match_len) + { + tdefl_record_literal(d, (mz_uint8)d->m_saved_lit); + if (cur_match_len >= 128) + { + tdefl_record_match(d, cur_match_len, cur_match_dist); + d->m_saved_match_len = 0; + len_to_move = cur_match_len; + } + else + { + d->m_saved_lit = d->m_dict[cur_pos]; + d->m_saved_match_dist = cur_match_dist; + d->m_saved_match_len = cur_match_len; + } + } + else + { + tdefl_record_match(d, d->m_saved_match_len, d->m_saved_match_dist); + len_to_move = d->m_saved_match_len - 1; + d->m_saved_match_len = 0; + } + } + else if (!cur_match_dist) + tdefl_record_literal(d, d->m_dict[MZ_MIN(cur_pos, sizeof(d->m_dict) - 1)]); + else if ((d->m_greedy_parsing) || (d->m_flags & TDEFL_RLE_MATCHES) || (cur_match_len >= 128)) + { + tdefl_record_match(d, cur_match_len, cur_match_dist); + len_to_move = cur_match_len; + } + else + { + d->m_saved_lit = d->m_dict[MZ_MIN(cur_pos, sizeof(d->m_dict) - 1)]; + d->m_saved_match_dist = cur_match_dist; + d->m_saved_match_len = cur_match_len; + } + /* Move the lookahead forward by len_to_move bytes. */ + d->m_lookahead_pos += len_to_move; + MZ_ASSERT(d->m_lookahead_size >= len_to_move); + d->m_lookahead_size -= len_to_move; + d->m_dict_size = MZ_MIN(d->m_dict_size + len_to_move, (mz_uint)TDEFL_LZ_DICT_SIZE); + /* Check if it's time to flush the current LZ codes to the internal output buffer. */ + if ((d->m_pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8]) || + ((d->m_total_lz_bytes > 31 * 1024) && (((((mz_uint)(d->m_pLZ_code_buf - d->m_lz_code_buf) * 115) >> 7) >= d->m_total_lz_bytes) || (d->m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS)))) + { + int n; + d->m_pSrc = pSrc; + d->m_src_buf_left = src_buf_left; + if ((n = tdefl_flush_block(d, 0)) != 0) + return (n < 0) ? MZ_FALSE : MZ_TRUE; + } + } + + d->m_pSrc = pSrc; + d->m_src_buf_left = src_buf_left; + return MZ_TRUE; +} + +static tdefl_status tdefl_flush_output_buffer(tdefl_compressor *d) +{ + if (d->m_pIn_buf_size) + { + *d->m_pIn_buf_size = d->m_pSrc - (const mz_uint8 *)d->m_pIn_buf; + } + + if (d->m_pOut_buf_size) + { + size_t n = MZ_MIN(*d->m_pOut_buf_size - d->m_out_buf_ofs, d->m_output_flush_remaining); + memcpy((mz_uint8 *)d->m_pOut_buf + d->m_out_buf_ofs, d->m_output_buf + d->m_output_flush_ofs, n); + d->m_output_flush_ofs += (mz_uint)n; + d->m_output_flush_remaining -= (mz_uint)n; + d->m_out_buf_ofs += n; + + *d->m_pOut_buf_size = d->m_out_buf_ofs; + } + + return (d->m_finished && !d->m_output_flush_remaining) ? TDEFL_STATUS_DONE : TDEFL_STATUS_OKAY; +} + +tdefl_status tdefl_compress(tdefl_compressor *d, const void *pIn_buf, size_t *pIn_buf_size, void *pOut_buf, size_t *pOut_buf_size, tdefl_flush flush) +{ + if (!d) + { + if (pIn_buf_size) + *pIn_buf_size = 0; + if (pOut_buf_size) + *pOut_buf_size = 0; + return TDEFL_STATUS_BAD_PARAM; + } + + d->m_pIn_buf = pIn_buf; + d->m_pIn_buf_size = pIn_buf_size; + d->m_pOut_buf = pOut_buf; + d->m_pOut_buf_size = pOut_buf_size; + d->m_pSrc = (const mz_uint8 *)(pIn_buf); + d->m_src_buf_left = pIn_buf_size ? *pIn_buf_size : 0; + d->m_out_buf_ofs = 0; + d->m_flush = flush; + + if (((d->m_pPut_buf_func != NULL) == ((pOut_buf != NULL) || (pOut_buf_size != NULL))) || (d->m_prev_return_status != TDEFL_STATUS_OKAY) || + (d->m_wants_to_finish && (flush != TDEFL_FINISH)) || (pIn_buf_size && *pIn_buf_size && !pIn_buf) || (pOut_buf_size && *pOut_buf_size && !pOut_buf)) + { + if (pIn_buf_size) + *pIn_buf_size = 0; + if (pOut_buf_size) + *pOut_buf_size = 0; + return (d->m_prev_return_status = TDEFL_STATUS_BAD_PARAM); + } + d->m_wants_to_finish |= (flush == TDEFL_FINISH); + + if ((d->m_output_flush_remaining) || (d->m_finished)) + return (d->m_prev_return_status = tdefl_flush_output_buffer(d)); + +#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN + if (((d->m_flags & TDEFL_MAX_PROBES_MASK) == 1) && + ((d->m_flags & TDEFL_GREEDY_PARSING_FLAG) != 0) && + ((d->m_flags & (TDEFL_FILTER_MATCHES | TDEFL_FORCE_ALL_RAW_BLOCKS | TDEFL_RLE_MATCHES)) == 0)) + { + if (!tdefl_compress_fast(d)) + return d->m_prev_return_status; + } + else +#endif /* #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN */ + { + if (!tdefl_compress_normal(d)) + return d->m_prev_return_status; + } + + if ((d->m_flags & (TDEFL_WRITE_ZLIB_HEADER | TDEFL_COMPUTE_ADLER32)) && (pIn_buf)) + d->m_adler32 = (mz_uint32)mz_adler32(d->m_adler32, (const mz_uint8 *)pIn_buf, d->m_pSrc - (const mz_uint8 *)pIn_buf); + + if ((flush) && (!d->m_lookahead_size) && (!d->m_src_buf_left) && (!d->m_output_flush_remaining)) + { + if (tdefl_flush_block(d, flush) < 0) + return d->m_prev_return_status; + d->m_finished = (flush == TDEFL_FINISH); + if (flush == TDEFL_FULL_FLUSH) + { + MZ_CLEAR_OBJ(d->m_hash); + MZ_CLEAR_OBJ(d->m_next); + d->m_dict_size = 0; + } + } + + return (d->m_prev_return_status = tdefl_flush_output_buffer(d)); +} + +tdefl_status tdefl_compress_buffer(tdefl_compressor *d, const void *pIn_buf, size_t in_buf_size, tdefl_flush flush) +{ + MZ_ASSERT(d->m_pPut_buf_func); + return tdefl_compress(d, pIn_buf, &in_buf_size, NULL, NULL, flush); +} + +tdefl_status tdefl_init(tdefl_compressor *d, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags) +{ + d->m_pPut_buf_func = pPut_buf_func; + d->m_pPut_buf_user = pPut_buf_user; + d->m_flags = (mz_uint)(flags); + d->m_max_probes[0] = 1 + ((flags & 0xFFF) + 2) / 3; + d->m_greedy_parsing = (flags & TDEFL_GREEDY_PARSING_FLAG) != 0; + d->m_max_probes[1] = 1 + (((flags & 0xFFF) >> 2) + 2) / 3; + if (!(flags & TDEFL_NONDETERMINISTIC_PARSING_FLAG)) + MZ_CLEAR_OBJ(d->m_hash); + d->m_lookahead_pos = d->m_lookahead_size = d->m_dict_size = d->m_total_lz_bytes = d->m_lz_code_buf_dict_pos = d->m_bits_in = 0; + d->m_output_flush_ofs = d->m_output_flush_remaining = d->m_finished = d->m_block_index = d->m_bit_buffer = d->m_wants_to_finish = 0; + d->m_pLZ_code_buf = d->m_lz_code_buf + 1; + d->m_pLZ_flags = d->m_lz_code_buf; + d->m_num_flags_left = 8; + d->m_pOutput_buf = d->m_output_buf; + d->m_pOutput_buf_end = d->m_output_buf; + d->m_prev_return_status = TDEFL_STATUS_OKAY; + d->m_saved_match_dist = d->m_saved_match_len = d->m_saved_lit = 0; + d->m_adler32 = 1; + d->m_pIn_buf = NULL; + d->m_pOut_buf = NULL; + d->m_pIn_buf_size = NULL; + d->m_pOut_buf_size = NULL; + d->m_flush = TDEFL_NO_FLUSH; + d->m_pSrc = NULL; + d->m_src_buf_left = 0; + d->m_out_buf_ofs = 0; + if (!(flags & TDEFL_NONDETERMINISTIC_PARSING_FLAG)) + MZ_CLEAR_OBJ(d->m_dict); + memset(&d->m_huff_count[0][0], 0, sizeof(d->m_huff_count[0][0]) * TDEFL_MAX_HUFF_SYMBOLS_0); + memset(&d->m_huff_count[1][0], 0, sizeof(d->m_huff_count[1][0]) * TDEFL_MAX_HUFF_SYMBOLS_1); + return TDEFL_STATUS_OKAY; +} + +tdefl_status tdefl_get_prev_return_status(tdefl_compressor *d) +{ + return d->m_prev_return_status; +} + +mz_uint32 tdefl_get_adler32(tdefl_compressor *d) +{ + return d->m_adler32; +} + +mz_bool tdefl_compress_mem_to_output(const void *pBuf, size_t buf_len, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags) +{ + tdefl_compressor *pComp; + mz_bool succeeded; + if (((buf_len) && (!pBuf)) || (!pPut_buf_func)) + return MZ_FALSE; + pComp = (tdefl_compressor *)MZ_MALLOC(sizeof(tdefl_compressor)); + if (!pComp) + return MZ_FALSE; + succeeded = (tdefl_init(pComp, pPut_buf_func, pPut_buf_user, flags) == TDEFL_STATUS_OKAY); + succeeded = succeeded && (tdefl_compress_buffer(pComp, pBuf, buf_len, TDEFL_FINISH) == TDEFL_STATUS_DONE); + MZ_FREE(pComp); + return succeeded; +} + +typedef struct +{ + size_t m_size, m_capacity; + mz_uint8 *m_pBuf; + mz_bool m_expandable; +} tdefl_output_buffer; + +static mz_bool tdefl_output_buffer_putter(const void *pBuf, int len, void *pUser) +{ + tdefl_output_buffer *p = (tdefl_output_buffer *)pUser; + size_t new_size = p->m_size + len; + if (new_size > p->m_capacity) + { + size_t new_capacity = p->m_capacity; + mz_uint8 *pNew_buf; + if (!p->m_expandable) + return MZ_FALSE; + do + { + new_capacity = MZ_MAX(128U, new_capacity << 1U); + } while (new_size > new_capacity); + pNew_buf = (mz_uint8 *)MZ_REALLOC(p->m_pBuf, new_capacity); + if (!pNew_buf) + return MZ_FALSE; + p->m_pBuf = pNew_buf; + p->m_capacity = new_capacity; + } + memcpy((mz_uint8 *)p->m_pBuf + p->m_size, pBuf, len); + p->m_size = new_size; + return MZ_TRUE; +} + +void *tdefl_compress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags) +{ + tdefl_output_buffer out_buf; + MZ_CLEAR_OBJ(out_buf); + if (!pOut_len) + return MZ_FALSE; + else + *pOut_len = 0; + out_buf.m_expandable = MZ_TRUE; + if (!tdefl_compress_mem_to_output(pSrc_buf, src_buf_len, tdefl_output_buffer_putter, &out_buf, flags)) + return NULL; + *pOut_len = out_buf.m_size; + return out_buf.m_pBuf; +} + +size_t tdefl_compress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags) +{ + tdefl_output_buffer out_buf; + MZ_CLEAR_OBJ(out_buf); + if (!pOut_buf) + return 0; + out_buf.m_pBuf = (mz_uint8 *)pOut_buf; + out_buf.m_capacity = out_buf_len; + if (!tdefl_compress_mem_to_output(pSrc_buf, src_buf_len, tdefl_output_buffer_putter, &out_buf, flags)) + return 0; + return out_buf.m_size; +} + +static const mz_uint s_tdefl_num_probes[11] = { 0, 1, 6, 32, 16, 32, 128, 256, 512, 768, 1500 }; + +/* level may actually range from [0,10] (10 is a "hidden" max level, where we want a bit more compression and it's fine if throughput to fall off a cliff on some files). */ +mz_uint tdefl_create_comp_flags_from_zip_params(int level, int window_bits, int strategy) +{ + mz_uint comp_flags = s_tdefl_num_probes[(level >= 0) ? MZ_MIN(10, level) : MZ_DEFAULT_LEVEL] | ((level <= 3) ? TDEFL_GREEDY_PARSING_FLAG : 0); + if (window_bits > 0) + comp_flags |= TDEFL_WRITE_ZLIB_HEADER; + + if (!level) + comp_flags |= TDEFL_FORCE_ALL_RAW_BLOCKS; + else if (strategy == MZ_FILTERED) + comp_flags |= TDEFL_FILTER_MATCHES; + else if (strategy == MZ_HUFFMAN_ONLY) + comp_flags &= ~TDEFL_MAX_PROBES_MASK; + else if (strategy == MZ_FIXED) + comp_flags |= TDEFL_FORCE_ALL_STATIC_BLOCKS; + else if (strategy == MZ_RLE) + comp_flags |= TDEFL_RLE_MATCHES; + + return comp_flags; +} + +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable : 4204) /* nonstandard extension used : non-constant aggregate initializer (also supported by GNU C and C99, so no big deal) */ +#endif + +/* Simple PNG writer function by Alex Evans, 2011. Released into the public domain: https://gist.github.com/908299, more context at + http://altdevblogaday.org/2011/04/06/a-smaller-jpg-encoder/. + This is actually a modification of Alex's original code so PNG files generated by this function pass pngcheck. */ +void *tdefl_write_image_to_png_file_in_memory_ex(const void *pImage, int w, int h, int num_chans, size_t *pLen_out, mz_uint level, mz_bool flip) +{ + /* Using a local copy of this array here in case MINIZ_NO_ZLIB_APIS was defined. */ + static const mz_uint s_tdefl_png_num_probes[11] = { 0, 1, 6, 32, 16, 32, 128, 256, 512, 768, 1500 }; + tdefl_compressor *pComp = (tdefl_compressor *)MZ_MALLOC(sizeof(tdefl_compressor)); + tdefl_output_buffer out_buf; + int i, bpl = w * num_chans, y, z; + mz_uint32 c; + *pLen_out = 0; + if (!pComp) + return NULL; + MZ_CLEAR_OBJ(out_buf); + out_buf.m_expandable = MZ_TRUE; + out_buf.m_capacity = 57 + MZ_MAX(64, (1 + bpl) * h); + if (NULL == (out_buf.m_pBuf = (mz_uint8 *)MZ_MALLOC(out_buf.m_capacity))) + { + MZ_FREE(pComp); + return NULL; + } + /* write dummy header */ + for (z = 41; z; --z) + tdefl_output_buffer_putter(&z, 1, &out_buf); + /* compress image data */ + tdefl_init(pComp, tdefl_output_buffer_putter, &out_buf, s_tdefl_png_num_probes[MZ_MIN(10, level)] | TDEFL_WRITE_ZLIB_HEADER); + for (y = 0; y < h; ++y) + { + tdefl_compress_buffer(pComp, &z, 1, TDEFL_NO_FLUSH); + tdefl_compress_buffer(pComp, (mz_uint8 *)pImage + (flip ? (h - 1 - y) : y) * bpl, bpl, TDEFL_NO_FLUSH); + } + if (tdefl_compress_buffer(pComp, NULL, 0, TDEFL_FINISH) != TDEFL_STATUS_DONE) + { + MZ_FREE(pComp); + MZ_FREE(out_buf.m_pBuf); + return NULL; + } + /* write real header */ + *pLen_out = out_buf.m_size - 41; + { + static const mz_uint8 chans[] = { 0x00, 0x00, 0x04, 0x02, 0x06 }; + mz_uint8 pnghdr[41] = { 0x89, 0x50, 0x4e, 0x47, 0x0d, + 0x0a, 0x1a, 0x0a, 0x00, 0x00, + 0x00, 0x0d, 0x49, 0x48, 0x44, + 0x52, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x08, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x49, 0x44, 0x41, + 0x54 }; + pnghdr[18] = (mz_uint8)(w >> 8); + pnghdr[19] = (mz_uint8)w; + pnghdr[22] = (mz_uint8)(h >> 8); + pnghdr[23] = (mz_uint8)h; + pnghdr[25] = chans[num_chans]; + pnghdr[33] = (mz_uint8)(*pLen_out >> 24); + pnghdr[34] = (mz_uint8)(*pLen_out >> 16); + pnghdr[35] = (mz_uint8)(*pLen_out >> 8); + pnghdr[36] = (mz_uint8)*pLen_out; + c = (mz_uint32)mz_crc32(MZ_CRC32_INIT, pnghdr + 12, 17); + for (i = 0; i < 4; ++i, c <<= 8) + ((mz_uint8 *)(pnghdr + 29))[i] = (mz_uint8)(c >> 24); + memcpy(out_buf.m_pBuf, pnghdr, 41); + } + /* write footer (IDAT CRC-32, followed by IEND chunk) */ + if (!tdefl_output_buffer_putter("\0\0\0\0\0\0\0\0\x49\x45\x4e\x44\xae\x42\x60\x82", 16, &out_buf)) + { + *pLen_out = 0; + MZ_FREE(pComp); + MZ_FREE(out_buf.m_pBuf); + return NULL; + } + c = (mz_uint32)mz_crc32(MZ_CRC32_INIT, out_buf.m_pBuf + 41 - 4, *pLen_out + 4); + for (i = 0; i < 4; ++i, c <<= 8) + (out_buf.m_pBuf + out_buf.m_size - 16)[i] = (mz_uint8)(c >> 24); + /* compute final size of file, grab compressed data buffer and return */ + *pLen_out += 57; + MZ_FREE(pComp); + return out_buf.m_pBuf; +} +void *tdefl_write_image_to_png_file_in_memory(const void *pImage, int w, int h, int num_chans, size_t *pLen_out) +{ + /* Level 6 corresponds to TDEFL_DEFAULT_MAX_PROBES or MZ_DEFAULT_LEVEL (but we can't depend on MZ_DEFAULT_LEVEL being available in case the zlib API's where #defined out) */ + return tdefl_write_image_to_png_file_in_memory_ex(pImage, w, h, num_chans, pLen_out, 6, MZ_FALSE); +} + +#ifndef MINIZ_NO_MALLOC +/* Allocate the tdefl_compressor and tinfl_decompressor structures in C so that */ +/* non-C language bindings to tdefL_ and tinfl_ API don't need to worry about */ +/* structure size and allocation mechanism. */ +tdefl_compressor *tdefl_compressor_alloc() +{ + return (tdefl_compressor *)MZ_MALLOC(sizeof(tdefl_compressor)); +} + +void tdefl_compressor_free(tdefl_compressor *pComp) +{ + MZ_FREE(pComp); +} +#endif + +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +#ifdef __cplusplus +} +#endif +/************************************************************************** + * + * Copyright 2013-2014 RAD Game Tools and Valve Software + * Copyright 2010-2014 Rich Geldreich and Tenacious Software LLC + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + **************************************************************************/ + + + +#ifdef __cplusplus +extern "C" { +#endif + +/* ------------------- Low-level Decompression (completely independent from all compression API's) */ + +#define TINFL_MEMCPY(d, s, l) memcpy(d, s, l) +#define TINFL_MEMSET(p, c, l) memset(p, c, l) + +#define TINFL_CR_BEGIN \ + switch (r->m_state) \ + { \ + case 0: +#define TINFL_CR_RETURN(state_index, result) \ + do \ + { \ + status = result; \ + r->m_state = state_index; \ + goto common_exit; \ + case state_index:; \ + } \ + MZ_MACRO_END +#define TINFL_CR_RETURN_FOREVER(state_index, result) \ + do \ + { \ + for (;;) \ + { \ + TINFL_CR_RETURN(state_index, result); \ + } \ + } \ + MZ_MACRO_END +#define TINFL_CR_FINISH } + +#define TINFL_GET_BYTE(state_index, c) \ + do \ + { \ + while (pIn_buf_cur >= pIn_buf_end) \ + { \ + TINFL_CR_RETURN(state_index, (decomp_flags & TINFL_FLAG_HAS_MORE_INPUT) ? TINFL_STATUS_NEEDS_MORE_INPUT : TINFL_STATUS_FAILED_CANNOT_MAKE_PROGRESS); \ + } \ + c = *pIn_buf_cur++; \ + } \ + MZ_MACRO_END + +#define TINFL_NEED_BITS(state_index, n) \ + do \ + { \ + mz_uint c; \ + TINFL_GET_BYTE(state_index, c); \ + bit_buf |= (((tinfl_bit_buf_t)c) << num_bits); \ + num_bits += 8; \ + } while (num_bits < (mz_uint)(n)) +#define TINFL_SKIP_BITS(state_index, n) \ + do \ + { \ + if (num_bits < (mz_uint)(n)) \ + { \ + TINFL_NEED_BITS(state_index, n); \ + } \ + bit_buf >>= (n); \ + num_bits -= (n); \ + } \ + MZ_MACRO_END +#define TINFL_GET_BITS(state_index, b, n) \ + do \ + { \ + if (num_bits < (mz_uint)(n)) \ + { \ + TINFL_NEED_BITS(state_index, n); \ + } \ + b = bit_buf & ((1 << (n)) - 1); \ + bit_buf >>= (n); \ + num_bits -= (n); \ + } \ + MZ_MACRO_END + +/* TINFL_HUFF_BITBUF_FILL() is only used rarely, when the number of bytes remaining in the input buffer falls below 2. */ +/* It reads just enough bytes from the input stream that are needed to decode the next Huffman code (and absolutely no more). It works by trying to fully decode a */ +/* Huffman code by using whatever bits are currently present in the bit buffer. If this fails, it reads another byte, and tries again until it succeeds or until the */ +/* bit buffer contains >=15 bits (deflate's max. Huffman code size). */ +#define TINFL_HUFF_BITBUF_FILL(state_index, pHuff) \ + do \ + { \ + temp = (pHuff)->m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]; \ + if (temp >= 0) \ + { \ + code_len = temp >> 9; \ + if ((code_len) && (num_bits >= code_len)) \ + break; \ + } \ + else if (num_bits > TINFL_FAST_LOOKUP_BITS) \ + { \ + code_len = TINFL_FAST_LOOKUP_BITS; \ + do \ + { \ + temp = (pHuff)->m_tree[~temp + ((bit_buf >> code_len++) & 1)]; \ + } while ((temp < 0) && (num_bits >= (code_len + 1))); \ + if (temp >= 0) \ + break; \ + } \ + TINFL_GET_BYTE(state_index, c); \ + bit_buf |= (((tinfl_bit_buf_t)c) << num_bits); \ + num_bits += 8; \ + } while (num_bits < 15); + +/* TINFL_HUFF_DECODE() decodes the next Huffman coded symbol. It's more complex than you would initially expect because the zlib API expects the decompressor to never read */ +/* beyond the final byte of the deflate stream. (In other words, when this macro wants to read another byte from the input, it REALLY needs another byte in order to fully */ +/* decode the next Huffman code.) Handling this properly is particularly important on raw deflate (non-zlib) streams, which aren't followed by a byte aligned adler-32. */ +/* The slow path is only executed at the very end of the input buffer. */ +/* v1.16: The original macro handled the case at the very end of the passed-in input buffer, but we also need to handle the case where the user passes in 1+zillion bytes */ +/* following the deflate data and our non-conservative read-ahead path won't kick in here on this code. This is much trickier. */ +#define TINFL_HUFF_DECODE(state_index, sym, pHuff) \ + do \ + { \ + int temp; \ + mz_uint code_len, c; \ + if (num_bits < 15) \ + { \ + if ((pIn_buf_end - pIn_buf_cur) < 2) \ + { \ + TINFL_HUFF_BITBUF_FILL(state_index, pHuff); \ + } \ + else \ + { \ + bit_buf |= (((tinfl_bit_buf_t)pIn_buf_cur[0]) << num_bits) | (((tinfl_bit_buf_t)pIn_buf_cur[1]) << (num_bits + 8)); \ + pIn_buf_cur += 2; \ + num_bits += 16; \ + } \ + } \ + if ((temp = (pHuff)->m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0) \ + code_len = temp >> 9, temp &= 511; \ + else \ + { \ + code_len = TINFL_FAST_LOOKUP_BITS; \ + do \ + { \ + temp = (pHuff)->m_tree[~temp + ((bit_buf >> code_len++) & 1)]; \ + } while (temp < 0); \ + } \ + sym = temp; \ + bit_buf >>= code_len; \ + num_bits -= code_len; \ + } \ + MZ_MACRO_END + +tinfl_status tinfl_decompress(tinfl_decompressor *r, const mz_uint8 *pIn_buf_next, size_t *pIn_buf_size, mz_uint8 *pOut_buf_start, mz_uint8 *pOut_buf_next, size_t *pOut_buf_size, const mz_uint32 decomp_flags) +{ + static const int s_length_base[31] = { 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0 }; + static const int s_length_extra[31] = { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 0, 0 }; + static const int s_dist_base[32] = { 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577, 0, 0 }; + static const int s_dist_extra[32] = { 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13 }; + static const mz_uint8 s_length_dezigzag[19] = { 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 }; + static const int s_min_table_sizes[3] = { 257, 1, 4 }; + + tinfl_status status = TINFL_STATUS_FAILED; + mz_uint32 num_bits, dist, counter, num_extra; + tinfl_bit_buf_t bit_buf; + const mz_uint8 *pIn_buf_cur = pIn_buf_next, *const pIn_buf_end = pIn_buf_next + *pIn_buf_size; + mz_uint8 *pOut_buf_cur = pOut_buf_next, *const pOut_buf_end = pOut_buf_next + *pOut_buf_size; + size_t out_buf_size_mask = (decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF) ? (size_t)-1 : ((pOut_buf_next - pOut_buf_start) + *pOut_buf_size) - 1, dist_from_out_buf_start; + + /* Ensure the output buffer's size is a power of 2, unless the output buffer is large enough to hold the entire output file (in which case it doesn't matter). */ + if (((out_buf_size_mask + 1) & out_buf_size_mask) || (pOut_buf_next < pOut_buf_start)) + { + *pIn_buf_size = *pOut_buf_size = 0; + return TINFL_STATUS_BAD_PARAM; + } + + num_bits = r->m_num_bits; + bit_buf = r->m_bit_buf; + dist = r->m_dist; + counter = r->m_counter; + num_extra = r->m_num_extra; + dist_from_out_buf_start = r->m_dist_from_out_buf_start; + TINFL_CR_BEGIN + + bit_buf = num_bits = dist = counter = num_extra = r->m_zhdr0 = r->m_zhdr1 = 0; + r->m_z_adler32 = r->m_check_adler32 = 1; + if (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER) + { + TINFL_GET_BYTE(1, r->m_zhdr0); + TINFL_GET_BYTE(2, r->m_zhdr1); + counter = (((r->m_zhdr0 * 256 + r->m_zhdr1) % 31 != 0) || (r->m_zhdr1 & 32) || ((r->m_zhdr0 & 15) != 8)); + if (!(decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF)) + counter |= (((1U << (8U + (r->m_zhdr0 >> 4))) > 32768U) || ((out_buf_size_mask + 1) < (size_t)(1U << (8U + (r->m_zhdr0 >> 4))))); + if (counter) + { + TINFL_CR_RETURN_FOREVER(36, TINFL_STATUS_FAILED); + } + } + + do + { + TINFL_GET_BITS(3, r->m_final, 3); + r->m_type = r->m_final >> 1; + if (r->m_type == 0) + { + TINFL_SKIP_BITS(5, num_bits & 7); + for (counter = 0; counter < 4; ++counter) + { + if (num_bits) + TINFL_GET_BITS(6, r->m_raw_header[counter], 8); + else + TINFL_GET_BYTE(7, r->m_raw_header[counter]); + } + if ((counter = (r->m_raw_header[0] | (r->m_raw_header[1] << 8))) != (mz_uint)(0xFFFF ^ (r->m_raw_header[2] | (r->m_raw_header[3] << 8)))) + { + TINFL_CR_RETURN_FOREVER(39, TINFL_STATUS_FAILED); + } + while ((counter) && (num_bits)) + { + TINFL_GET_BITS(51, dist, 8); + while (pOut_buf_cur >= pOut_buf_end) + { + TINFL_CR_RETURN(52, TINFL_STATUS_HAS_MORE_OUTPUT); + } + *pOut_buf_cur++ = (mz_uint8)dist; + counter--; + } + while (counter) + { + size_t n; + while (pOut_buf_cur >= pOut_buf_end) + { + TINFL_CR_RETURN(9, TINFL_STATUS_HAS_MORE_OUTPUT); + } + while (pIn_buf_cur >= pIn_buf_end) + { + TINFL_CR_RETURN(38, (decomp_flags & TINFL_FLAG_HAS_MORE_INPUT) ? TINFL_STATUS_NEEDS_MORE_INPUT : TINFL_STATUS_FAILED_CANNOT_MAKE_PROGRESS); + } + n = MZ_MIN(MZ_MIN((size_t)(pOut_buf_end - pOut_buf_cur), (size_t)(pIn_buf_end - pIn_buf_cur)), counter); + TINFL_MEMCPY(pOut_buf_cur, pIn_buf_cur, n); + pIn_buf_cur += n; + pOut_buf_cur += n; + counter -= (mz_uint)n; + } + } + else if (r->m_type == 3) + { + TINFL_CR_RETURN_FOREVER(10, TINFL_STATUS_FAILED); + } + else + { + if (r->m_type == 1) + { + mz_uint8 *p = r->m_tables[0].m_code_size; + mz_uint i; + r->m_table_sizes[0] = 288; + r->m_table_sizes[1] = 32; + TINFL_MEMSET(r->m_tables[1].m_code_size, 5, 32); + for (i = 0; i <= 143; ++i) + *p++ = 8; + for (; i <= 255; ++i) + *p++ = 9; + for (; i <= 279; ++i) + *p++ = 7; + for (; i <= 287; ++i) + *p++ = 8; + } + else + { + for (counter = 0; counter < 3; counter++) + { + TINFL_GET_BITS(11, r->m_table_sizes[counter], "\05\05\04"[counter]); + r->m_table_sizes[counter] += s_min_table_sizes[counter]; + } + MZ_CLEAR_OBJ(r->m_tables[2].m_code_size); + for (counter = 0; counter < r->m_table_sizes[2]; counter++) + { + mz_uint s; + TINFL_GET_BITS(14, s, 3); + r->m_tables[2].m_code_size[s_length_dezigzag[counter]] = (mz_uint8)s; + } + r->m_table_sizes[2] = 19; + } + for (; (int)r->m_type >= 0; r->m_type--) + { + int tree_next, tree_cur; + tinfl_huff_table *pTable; + mz_uint i, j, used_syms, total, sym_index, next_code[17], total_syms[16]; + pTable = &r->m_tables[r->m_type]; + MZ_CLEAR_OBJ(total_syms); + MZ_CLEAR_OBJ(pTable->m_look_up); + MZ_CLEAR_OBJ(pTable->m_tree); + for (i = 0; i < r->m_table_sizes[r->m_type]; ++i) + total_syms[pTable->m_code_size[i]]++; + used_syms = 0, total = 0; + next_code[0] = next_code[1] = 0; + for (i = 1; i <= 15; ++i) + { + used_syms += total_syms[i]; + next_code[i + 1] = (total = ((total + total_syms[i]) << 1)); + } + if ((65536 != total) && (used_syms > 1)) + { + TINFL_CR_RETURN_FOREVER(35, TINFL_STATUS_FAILED); + } + for (tree_next = -1, sym_index = 0; sym_index < r->m_table_sizes[r->m_type]; ++sym_index) + { + mz_uint rev_code = 0, l, cur_code, code_size = pTable->m_code_size[sym_index]; + if (!code_size) + continue; + cur_code = next_code[code_size]++; + for (l = code_size; l > 0; l--, cur_code >>= 1) + rev_code = (rev_code << 1) | (cur_code & 1); + if (code_size <= TINFL_FAST_LOOKUP_BITS) + { + mz_int16 k = (mz_int16)((code_size << 9) | sym_index); + while (rev_code < TINFL_FAST_LOOKUP_SIZE) + { + pTable->m_look_up[rev_code] = k; + rev_code += (1 << code_size); + } + continue; + } + if (0 == (tree_cur = pTable->m_look_up[rev_code & (TINFL_FAST_LOOKUP_SIZE - 1)])) + { + pTable->m_look_up[rev_code & (TINFL_FAST_LOOKUP_SIZE - 1)] = (mz_int16)tree_next; + tree_cur = tree_next; + tree_next -= 2; + } + rev_code >>= (TINFL_FAST_LOOKUP_BITS - 1); + for (j = code_size; j > (TINFL_FAST_LOOKUP_BITS + 1); j--) + { + tree_cur -= ((rev_code >>= 1) & 1); + if (!pTable->m_tree[-tree_cur - 1]) + { + pTable->m_tree[-tree_cur - 1] = (mz_int16)tree_next; + tree_cur = tree_next; + tree_next -= 2; + } + else + tree_cur = pTable->m_tree[-tree_cur - 1]; + } + tree_cur -= ((rev_code >>= 1) & 1); + pTable->m_tree[-tree_cur - 1] = (mz_int16)sym_index; + } + if (r->m_type == 2) + { + for (counter = 0; counter < (r->m_table_sizes[0] + r->m_table_sizes[1]);) + { + mz_uint s; + TINFL_HUFF_DECODE(16, dist, &r->m_tables[2]); + if (dist < 16) + { + r->m_len_codes[counter++] = (mz_uint8)dist; + continue; + } + if ((dist == 16) && (!counter)) + { + TINFL_CR_RETURN_FOREVER(17, TINFL_STATUS_FAILED); + } + num_extra = "\02\03\07"[dist - 16]; + TINFL_GET_BITS(18, s, num_extra); + s += "\03\03\013"[dist - 16]; + TINFL_MEMSET(r->m_len_codes + counter, (dist == 16) ? r->m_len_codes[counter - 1] : 0, s); + counter += s; + } + if ((r->m_table_sizes[0] + r->m_table_sizes[1]) != counter) + { + TINFL_CR_RETURN_FOREVER(21, TINFL_STATUS_FAILED); + } + TINFL_MEMCPY(r->m_tables[0].m_code_size, r->m_len_codes, r->m_table_sizes[0]); + TINFL_MEMCPY(r->m_tables[1].m_code_size, r->m_len_codes + r->m_table_sizes[0], r->m_table_sizes[1]); + } + } + for (;;) + { + mz_uint8 *pSrc; + for (;;) + { + if (((pIn_buf_end - pIn_buf_cur) < 4) || ((pOut_buf_end - pOut_buf_cur) < 2)) + { + TINFL_HUFF_DECODE(23, counter, &r->m_tables[0]); + if (counter >= 256) + break; + while (pOut_buf_cur >= pOut_buf_end) + { + TINFL_CR_RETURN(24, TINFL_STATUS_HAS_MORE_OUTPUT); + } + *pOut_buf_cur++ = (mz_uint8)counter; + } + else + { + int sym2; + mz_uint code_len; +#if TINFL_USE_64BIT_BITBUF + if (num_bits < 30) + { + bit_buf |= (((tinfl_bit_buf_t)MZ_READ_LE32(pIn_buf_cur)) << num_bits); + pIn_buf_cur += 4; + num_bits += 32; + } +#else + if (num_bits < 15) + { + bit_buf |= (((tinfl_bit_buf_t)MZ_READ_LE16(pIn_buf_cur)) << num_bits); + pIn_buf_cur += 2; + num_bits += 16; + } +#endif + if ((sym2 = r->m_tables[0].m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0) + code_len = sym2 >> 9; + else + { + code_len = TINFL_FAST_LOOKUP_BITS; + do + { + sym2 = r->m_tables[0].m_tree[~sym2 + ((bit_buf >> code_len++) & 1)]; + } while (sym2 < 0); + } + counter = sym2; + bit_buf >>= code_len; + num_bits -= code_len; + if (counter & 256) + break; + +#if !TINFL_USE_64BIT_BITBUF + if (num_bits < 15) + { + bit_buf |= (((tinfl_bit_buf_t)MZ_READ_LE16(pIn_buf_cur)) << num_bits); + pIn_buf_cur += 2; + num_bits += 16; + } +#endif + if ((sym2 = r->m_tables[0].m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0) + code_len = sym2 >> 9; + else + { + code_len = TINFL_FAST_LOOKUP_BITS; + do + { + sym2 = r->m_tables[0].m_tree[~sym2 + ((bit_buf >> code_len++) & 1)]; + } while (sym2 < 0); + } + bit_buf >>= code_len; + num_bits -= code_len; + + pOut_buf_cur[0] = (mz_uint8)counter; + if (sym2 & 256) + { + pOut_buf_cur++; + counter = sym2; + break; + } + pOut_buf_cur[1] = (mz_uint8)sym2; + pOut_buf_cur += 2; + } + } + if ((counter &= 511) == 256) + break; + + num_extra = s_length_extra[counter - 257]; + counter = s_length_base[counter - 257]; + if (num_extra) + { + mz_uint extra_bits; + TINFL_GET_BITS(25, extra_bits, num_extra); + counter += extra_bits; + } + + TINFL_HUFF_DECODE(26, dist, &r->m_tables[1]); + num_extra = s_dist_extra[dist]; + dist = s_dist_base[dist]; + if (num_extra) + { + mz_uint extra_bits; + TINFL_GET_BITS(27, extra_bits, num_extra); + dist += extra_bits; + } + + dist_from_out_buf_start = pOut_buf_cur - pOut_buf_start; + if ((dist > dist_from_out_buf_start) && (decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF)) + { + TINFL_CR_RETURN_FOREVER(37, TINFL_STATUS_FAILED); + } + + pSrc = pOut_buf_start + ((dist_from_out_buf_start - dist) & out_buf_size_mask); + + if ((MZ_MAX(pOut_buf_cur, pSrc) + counter) > pOut_buf_end) + { + while (counter--) + { + while (pOut_buf_cur >= pOut_buf_end) + { + TINFL_CR_RETURN(53, TINFL_STATUS_HAS_MORE_OUTPUT); + } + *pOut_buf_cur++ = pOut_buf_start[(dist_from_out_buf_start++ - dist) & out_buf_size_mask]; + } + continue; + } +#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES + else if ((counter >= 9) && (counter <= dist)) + { + const mz_uint8 *pSrc_end = pSrc + (counter & ~7); + do + { +#ifdef MINIZ_UNALIGNED_USE_MEMCPY + memcpy(pOut_buf_cur, pSrc, sizeof(mz_uint32)*2); +#else + ((mz_uint32 *)pOut_buf_cur)[0] = ((const mz_uint32 *)pSrc)[0]; + ((mz_uint32 *)pOut_buf_cur)[1] = ((const mz_uint32 *)pSrc)[1]; +#endif + pOut_buf_cur += 8; + } while ((pSrc += 8) < pSrc_end); + if ((counter &= 7) < 3) + { + if (counter) + { + pOut_buf_cur[0] = pSrc[0]; + if (counter > 1) + pOut_buf_cur[1] = pSrc[1]; + pOut_buf_cur += counter; + } + continue; + } + } +#endif + while(counter>2) + { + pOut_buf_cur[0] = pSrc[0]; + pOut_buf_cur[1] = pSrc[1]; + pOut_buf_cur[2] = pSrc[2]; + pOut_buf_cur += 3; + pSrc += 3; + counter -= 3; + } + if (counter > 0) + { + pOut_buf_cur[0] = pSrc[0]; + if (counter > 1) + pOut_buf_cur[1] = pSrc[1]; + pOut_buf_cur += counter; + } + } + } + } while (!(r->m_final & 1)); + + /* Ensure byte alignment and put back any bytes from the bitbuf if we've looked ahead too far on gzip, or other Deflate streams followed by arbitrary data. */ + /* I'm being super conservative here. A number of simplifications can be made to the byte alignment part, and the Adler32 check shouldn't ever need to worry about reading from the bitbuf now. */ + TINFL_SKIP_BITS(32, num_bits & 7); + while ((pIn_buf_cur > pIn_buf_next) && (num_bits >= 8)) + { + --pIn_buf_cur; + num_bits -= 8; + } + bit_buf &= (tinfl_bit_buf_t)((((mz_uint64)1) << num_bits) - (mz_uint64)1); + MZ_ASSERT(!num_bits); /* if this assert fires then we've read beyond the end of non-deflate/zlib streams with following data (such as gzip streams). */ + + if (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER) + { + for (counter = 0; counter < 4; ++counter) + { + mz_uint s; + if (num_bits) + TINFL_GET_BITS(41, s, 8); + else + TINFL_GET_BYTE(42, s); + r->m_z_adler32 = (r->m_z_adler32 << 8) | s; + } + } + TINFL_CR_RETURN_FOREVER(34, TINFL_STATUS_DONE); + + TINFL_CR_FINISH + +common_exit: + /* As long as we aren't telling the caller that we NEED more input to make forward progress: */ + /* Put back any bytes from the bitbuf in case we've looked ahead too far on gzip, or other Deflate streams followed by arbitrary data. */ + /* We need to be very careful here to NOT push back any bytes we definitely know we need to make forward progress, though, or we'll lock the caller up into an inf loop. */ + if ((status != TINFL_STATUS_NEEDS_MORE_INPUT) && (status != TINFL_STATUS_FAILED_CANNOT_MAKE_PROGRESS)) + { + while ((pIn_buf_cur > pIn_buf_next) && (num_bits >= 8)) + { + --pIn_buf_cur; + num_bits -= 8; + } + } + r->m_num_bits = num_bits; + r->m_bit_buf = bit_buf & (tinfl_bit_buf_t)((((mz_uint64)1) << num_bits) - (mz_uint64)1); + r->m_dist = dist; + r->m_counter = counter; + r->m_num_extra = num_extra; + r->m_dist_from_out_buf_start = dist_from_out_buf_start; + *pIn_buf_size = pIn_buf_cur - pIn_buf_next; + *pOut_buf_size = pOut_buf_cur - pOut_buf_next; + if ((decomp_flags & (TINFL_FLAG_PARSE_ZLIB_HEADER | TINFL_FLAG_COMPUTE_ADLER32)) && (status >= 0)) + { + const mz_uint8 *ptr = pOut_buf_next; + size_t buf_len = *pOut_buf_size; + mz_uint32 i, s1 = r->m_check_adler32 & 0xffff, s2 = r->m_check_adler32 >> 16; + size_t block_len = buf_len % 5552; + while (buf_len) + { + for (i = 0; i + 7 < block_len; i += 8, ptr += 8) + { + s1 += ptr[0], s2 += s1; + s1 += ptr[1], s2 += s1; + s1 += ptr[2], s2 += s1; + s1 += ptr[3], s2 += s1; + s1 += ptr[4], s2 += s1; + s1 += ptr[5], s2 += s1; + s1 += ptr[6], s2 += s1; + s1 += ptr[7], s2 += s1; + } + for (; i < block_len; ++i) + s1 += *ptr++, s2 += s1; + s1 %= 65521U, s2 %= 65521U; + buf_len -= block_len; + block_len = 5552; + } + r->m_check_adler32 = (s2 << 16) + s1; + if ((status == TINFL_STATUS_DONE) && (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER) && (r->m_check_adler32 != r->m_z_adler32)) + status = TINFL_STATUS_ADLER32_MISMATCH; + } + return status; +} + +/* Higher level helper functions. */ +void *tinfl_decompress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags) +{ + tinfl_decompressor decomp; + void *pBuf = NULL, *pNew_buf; + size_t src_buf_ofs = 0, out_buf_capacity = 0; + *pOut_len = 0; + tinfl_init(&decomp); + for (;;) + { + size_t src_buf_size = src_buf_len - src_buf_ofs, dst_buf_size = out_buf_capacity - *pOut_len, new_out_buf_capacity; + tinfl_status status = tinfl_decompress(&decomp, (const mz_uint8 *)pSrc_buf + src_buf_ofs, &src_buf_size, (mz_uint8 *)pBuf, pBuf ? (mz_uint8 *)pBuf + *pOut_len : NULL, &dst_buf_size, + (flags & ~TINFL_FLAG_HAS_MORE_INPUT) | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF); + if ((status < 0) || (status == TINFL_STATUS_NEEDS_MORE_INPUT)) + { + MZ_FREE(pBuf); + *pOut_len = 0; + return NULL; + } + src_buf_ofs += src_buf_size; + *pOut_len += dst_buf_size; + if (status == TINFL_STATUS_DONE) + break; + new_out_buf_capacity = out_buf_capacity * 2; + if (new_out_buf_capacity < 128) + new_out_buf_capacity = 128; + pNew_buf = MZ_REALLOC(pBuf, new_out_buf_capacity); + if (!pNew_buf) + { + MZ_FREE(pBuf); + *pOut_len = 0; + return NULL; + } + pBuf = pNew_buf; + out_buf_capacity = new_out_buf_capacity; + } + return pBuf; +} + +size_t tinfl_decompress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags) +{ + tinfl_decompressor decomp; + tinfl_status status; + tinfl_init(&decomp); + status = tinfl_decompress(&decomp, (const mz_uint8 *)pSrc_buf, &src_buf_len, (mz_uint8 *)pOut_buf, (mz_uint8 *)pOut_buf, &out_buf_len, (flags & ~TINFL_FLAG_HAS_MORE_INPUT) | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF); + return (status != TINFL_STATUS_DONE) ? TINFL_DECOMPRESS_MEM_TO_MEM_FAILED : out_buf_len; +} + +int tinfl_decompress_mem_to_callback(const void *pIn_buf, size_t *pIn_buf_size, tinfl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags) +{ + int result = 0; + tinfl_decompressor decomp; + mz_uint8 *pDict = (mz_uint8 *)MZ_MALLOC(TINFL_LZ_DICT_SIZE); + size_t in_buf_ofs = 0, dict_ofs = 0; + if (!pDict) + return TINFL_STATUS_FAILED; + tinfl_init(&decomp); + for (;;) + { + size_t in_buf_size = *pIn_buf_size - in_buf_ofs, dst_buf_size = TINFL_LZ_DICT_SIZE - dict_ofs; + tinfl_status status = tinfl_decompress(&decomp, (const mz_uint8 *)pIn_buf + in_buf_ofs, &in_buf_size, pDict, pDict + dict_ofs, &dst_buf_size, + (flags & ~(TINFL_FLAG_HAS_MORE_INPUT | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF))); + in_buf_ofs += in_buf_size; + if ((dst_buf_size) && (!(*pPut_buf_func)(pDict + dict_ofs, (int)dst_buf_size, pPut_buf_user))) + break; + if (status != TINFL_STATUS_HAS_MORE_OUTPUT) + { + result = (status == TINFL_STATUS_DONE); + break; + } + dict_ofs = (dict_ofs + dst_buf_size) & (TINFL_LZ_DICT_SIZE - 1); + } + MZ_FREE(pDict); + *pIn_buf_size = in_buf_ofs; + return result; +} + +#ifndef MINIZ_NO_MALLOC +tinfl_decompressor *tinfl_decompressor_alloc() +{ + tinfl_decompressor *pDecomp = (tinfl_decompressor *)MZ_MALLOC(sizeof(tinfl_decompressor)); + if (pDecomp) + tinfl_init(pDecomp); + return pDecomp; +} + +void tinfl_decompressor_free(tinfl_decompressor *pDecomp) +{ + MZ_FREE(pDecomp); +} +#endif + +#ifdef __cplusplus +} +#endif +/************************************************************************** + * + * Copyright 2013-2014 RAD Game Tools and Valve Software + * Copyright 2010-2014 Rich Geldreich and Tenacious Software LLC + * Copyright 2016 Martin Raiber + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + **************************************************************************/ + + +#ifndef MINIZ_NO_ARCHIVE_APIS + +#ifdef __cplusplus +extern "C" { +#endif + +/* ------------------- .ZIP archive reading */ + +#ifdef MINIZ_NO_STDIO +#define MZ_FILE void * +#else +#include + +#if defined(_MSC_VER) || defined(__MINGW64__) +static FILE *mz_fopen(const char *pFilename, const char *pMode) +{ + FILE *pFile = NULL; + fopen_s(&pFile, pFilename, pMode); + return pFile; +} +static FILE *mz_freopen(const char *pPath, const char *pMode, FILE *pStream) +{ + FILE *pFile = NULL; + if (freopen_s(&pFile, pPath, pMode, pStream)) + return NULL; + return pFile; +} +#ifndef MINIZ_NO_TIME +#include +#endif +#define MZ_FOPEN mz_fopen +#define MZ_FCLOSE fclose +#define MZ_FREAD fread +#define MZ_FWRITE fwrite +#define MZ_FTELL64 _ftelli64 +#define MZ_FSEEK64 _fseeki64 +#define MZ_FILE_STAT_STRUCT _stat64 +#define MZ_FILE_STAT _stat64 +#define MZ_FFLUSH fflush +#define MZ_FREOPEN mz_freopen +#define MZ_DELETE_FILE remove +#elif defined(__MINGW32__) +#ifndef MINIZ_NO_TIME +#include +#endif +#define MZ_FOPEN(f, m) fopen(f, m) +#define MZ_FCLOSE fclose +#define MZ_FREAD fread +#define MZ_FWRITE fwrite +#define MZ_FTELL64 ftello64 +#define MZ_FSEEK64 fseeko64 +#define MZ_FILE_STAT_STRUCT _stat +#define MZ_FILE_STAT _stat +#define MZ_FFLUSH fflush +#define MZ_FREOPEN(f, m, s) freopen(f, m, s) +#define MZ_DELETE_FILE remove +#elif defined(__TINYC__) +#ifndef MINIZ_NO_TIME +#include +#endif +#define MZ_FOPEN(f, m) fopen(f, m) +#define MZ_FCLOSE fclose +#define MZ_FREAD fread +#define MZ_FWRITE fwrite +#define MZ_FTELL64 ftell +#define MZ_FSEEK64 fseek +#define MZ_FILE_STAT_STRUCT stat +#define MZ_FILE_STAT stat +#define MZ_FFLUSH fflush +#define MZ_FREOPEN(f, m, s) freopen(f, m, s) +#define MZ_DELETE_FILE remove +#elif defined(__GNUC__) && defined(_LARGEFILE64_SOURCE) +#ifndef MINIZ_NO_TIME +#include +#endif +#define MZ_FOPEN(f, m) fopen64(f, m) +#define MZ_FCLOSE fclose +#define MZ_FREAD fread +#define MZ_FWRITE fwrite +#define MZ_FTELL64 ftello64 +#define MZ_FSEEK64 fseeko64 +#define MZ_FILE_STAT_STRUCT stat64 +#define MZ_FILE_STAT stat64 +#define MZ_FFLUSH fflush +#define MZ_FREOPEN(p, m, s) freopen64(p, m, s) +#define MZ_DELETE_FILE remove +#elif defined(__APPLE__) +#ifndef MINIZ_NO_TIME +#include +#endif +#define MZ_FOPEN(f, m) fopen(f, m) +#define MZ_FCLOSE fclose +#define MZ_FREAD fread +#define MZ_FWRITE fwrite +#define MZ_FTELL64 ftello +#define MZ_FSEEK64 fseeko +#define MZ_FILE_STAT_STRUCT stat +#define MZ_FILE_STAT stat +#define MZ_FFLUSH fflush +#define MZ_FREOPEN(p, m, s) freopen(p, m, s) +#define MZ_DELETE_FILE remove + +#else +#pragma message("Using fopen, ftello, fseeko, stat() etc. path for file I/O - this path may not support large files.") +#ifndef MINIZ_NO_TIME +#include +#endif +#define MZ_FOPEN(f, m) fopen(f, m) +#define MZ_FCLOSE fclose +#define MZ_FREAD fread +#define MZ_FWRITE fwrite +#ifdef __STRICT_ANSI__ +#define MZ_FTELL64 ftell +#define MZ_FSEEK64 fseek +#else +#define MZ_FTELL64 ftello +#define MZ_FSEEK64 fseeko +#endif +#define MZ_FILE_STAT_STRUCT stat +#define MZ_FILE_STAT stat +#define MZ_FFLUSH fflush +#define MZ_FREOPEN(f, m, s) freopen(f, m, s) +#define MZ_DELETE_FILE remove +#endif /* #ifdef _MSC_VER */ +#endif /* #ifdef MINIZ_NO_STDIO */ + +#define MZ_TOLOWER(c) ((((c) >= 'A') && ((c) <= 'Z')) ? ((c) - 'A' + 'a') : (c)) + +/* Various ZIP archive enums. To completely avoid cross platform compiler alignment and platform endian issues, miniz.c doesn't use structs for any of this stuff. */ +enum +{ + /* ZIP archive identifiers and record sizes */ + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG = 0x06054b50, + MZ_ZIP_CENTRAL_DIR_HEADER_SIG = 0x02014b50, + MZ_ZIP_LOCAL_DIR_HEADER_SIG = 0x04034b50, + MZ_ZIP_LOCAL_DIR_HEADER_SIZE = 30, + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE = 46, + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE = 22, + + /* ZIP64 archive identifier and record sizes */ + MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIG = 0x06064b50, + MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIG = 0x07064b50, + MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE = 56, + MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE = 20, + MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID = 0x0001, + MZ_ZIP_DATA_DESCRIPTOR_ID = 0x08074b50, + MZ_ZIP_DATA_DESCRIPTER_SIZE64 = 24, + MZ_ZIP_DATA_DESCRIPTER_SIZE32 = 16, + + /* Central directory header record offsets */ + MZ_ZIP_CDH_SIG_OFS = 0, + MZ_ZIP_CDH_VERSION_MADE_BY_OFS = 4, + MZ_ZIP_CDH_VERSION_NEEDED_OFS = 6, + MZ_ZIP_CDH_BIT_FLAG_OFS = 8, + MZ_ZIP_CDH_METHOD_OFS = 10, + MZ_ZIP_CDH_FILE_TIME_OFS = 12, + MZ_ZIP_CDH_FILE_DATE_OFS = 14, + MZ_ZIP_CDH_CRC32_OFS = 16, + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS = 20, + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS = 24, + MZ_ZIP_CDH_FILENAME_LEN_OFS = 28, + MZ_ZIP_CDH_EXTRA_LEN_OFS = 30, + MZ_ZIP_CDH_COMMENT_LEN_OFS = 32, + MZ_ZIP_CDH_DISK_START_OFS = 34, + MZ_ZIP_CDH_INTERNAL_ATTR_OFS = 36, + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS = 38, + MZ_ZIP_CDH_LOCAL_HEADER_OFS = 42, + + /* Local directory header offsets */ + MZ_ZIP_LDH_SIG_OFS = 0, + MZ_ZIP_LDH_VERSION_NEEDED_OFS = 4, + MZ_ZIP_LDH_BIT_FLAG_OFS = 6, + MZ_ZIP_LDH_METHOD_OFS = 8, + MZ_ZIP_LDH_FILE_TIME_OFS = 10, + MZ_ZIP_LDH_FILE_DATE_OFS = 12, + MZ_ZIP_LDH_CRC32_OFS = 14, + MZ_ZIP_LDH_COMPRESSED_SIZE_OFS = 18, + MZ_ZIP_LDH_DECOMPRESSED_SIZE_OFS = 22, + MZ_ZIP_LDH_FILENAME_LEN_OFS = 26, + MZ_ZIP_LDH_EXTRA_LEN_OFS = 28, + MZ_ZIP_LDH_BIT_FLAG_HAS_LOCATOR = 1 << 3, + + /* End of central directory offsets */ + MZ_ZIP_ECDH_SIG_OFS = 0, + MZ_ZIP_ECDH_NUM_THIS_DISK_OFS = 4, + MZ_ZIP_ECDH_NUM_DISK_CDIR_OFS = 6, + MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS = 8, + MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS = 10, + MZ_ZIP_ECDH_CDIR_SIZE_OFS = 12, + MZ_ZIP_ECDH_CDIR_OFS_OFS = 16, + MZ_ZIP_ECDH_COMMENT_SIZE_OFS = 20, + + /* ZIP64 End of central directory locator offsets */ + MZ_ZIP64_ECDL_SIG_OFS = 0, /* 4 bytes */ + MZ_ZIP64_ECDL_NUM_DISK_CDIR_OFS = 4, /* 4 bytes */ + MZ_ZIP64_ECDL_REL_OFS_TO_ZIP64_ECDR_OFS = 8, /* 8 bytes */ + MZ_ZIP64_ECDL_TOTAL_NUMBER_OF_DISKS_OFS = 16, /* 4 bytes */ + + /* ZIP64 End of central directory header offsets */ + MZ_ZIP64_ECDH_SIG_OFS = 0, /* 4 bytes */ + MZ_ZIP64_ECDH_SIZE_OF_RECORD_OFS = 4, /* 8 bytes */ + MZ_ZIP64_ECDH_VERSION_MADE_BY_OFS = 12, /* 2 bytes */ + MZ_ZIP64_ECDH_VERSION_NEEDED_OFS = 14, /* 2 bytes */ + MZ_ZIP64_ECDH_NUM_THIS_DISK_OFS = 16, /* 4 bytes */ + MZ_ZIP64_ECDH_NUM_DISK_CDIR_OFS = 20, /* 4 bytes */ + MZ_ZIP64_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS = 24, /* 8 bytes */ + MZ_ZIP64_ECDH_CDIR_TOTAL_ENTRIES_OFS = 32, /* 8 bytes */ + MZ_ZIP64_ECDH_CDIR_SIZE_OFS = 40, /* 8 bytes */ + MZ_ZIP64_ECDH_CDIR_OFS_OFS = 48, /* 8 bytes */ + MZ_ZIP_VERSION_MADE_BY_DOS_FILESYSTEM_ID = 0, + MZ_ZIP_DOS_DIR_ATTRIBUTE_BITFLAG = 0x10, + MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED = 1, + MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_COMPRESSED_PATCH_FLAG = 32, + MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION = 64, + MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_LOCAL_DIR_IS_MASKED = 8192, + MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_UTF8 = 1 << 11 +}; + +typedef struct +{ + void *m_p; + size_t m_size, m_capacity; + mz_uint m_element_size; +} mz_zip_array; + +struct mz_zip_internal_state_tag +{ + mz_zip_array m_central_dir; + mz_zip_array m_central_dir_offsets; + mz_zip_array m_sorted_central_dir_offsets; + + /* The flags passed in when the archive is initially opened. */ + uint32_t m_init_flags; + + /* MZ_TRUE if the archive has a zip64 end of central directory headers, etc. */ + mz_bool m_zip64; + + /* MZ_TRUE if we found zip64 extended info in the central directory (m_zip64 will also be slammed to true too, even if we didn't find a zip64 end of central dir header, etc.) */ + mz_bool m_zip64_has_extended_info_fields; + + /* These fields are used by the file, FILE, memory, and memory/heap read/write helpers. */ + MZ_FILE *m_pFile; + mz_uint64 m_file_archive_start_ofs; + + void *m_pMem; + size_t m_mem_size; + size_t m_mem_capacity; +}; + +#define MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(array_ptr, element_size) (array_ptr)->m_element_size = element_size + +#if defined(DEBUG) || defined(_DEBUG) || defined(NDEBUG) +static MZ_FORCEINLINE mz_uint mz_zip_array_range_check(const mz_zip_array *pArray, mz_uint index) +{ + MZ_ASSERT(index < pArray->m_size); + return index; +} +#define MZ_ZIP_ARRAY_ELEMENT(array_ptr, element_type, index) ((element_type *)((array_ptr)->m_p))[mz_zip_array_range_check(array_ptr, index)] +#else +#define MZ_ZIP_ARRAY_ELEMENT(array_ptr, element_type, index) ((element_type *)((array_ptr)->m_p))[index] +#endif + +static MZ_FORCEINLINE void mz_zip_array_init(mz_zip_array *pArray, mz_uint32 element_size) +{ + memset(pArray, 0, sizeof(mz_zip_array)); + pArray->m_element_size = element_size; +} + +static MZ_FORCEINLINE void mz_zip_array_clear(mz_zip_archive *pZip, mz_zip_array *pArray) +{ + pZip->m_pFree(pZip->m_pAlloc_opaque, pArray->m_p); + memset(pArray, 0, sizeof(mz_zip_array)); +} + +static mz_bool mz_zip_array_ensure_capacity(mz_zip_archive *pZip, mz_zip_array *pArray, size_t min_new_capacity, mz_uint growing) +{ + void *pNew_p; + size_t new_capacity = min_new_capacity; + MZ_ASSERT(pArray->m_element_size); + if (pArray->m_capacity >= min_new_capacity) + return MZ_TRUE; + if (growing) + { + new_capacity = MZ_MAX(1, pArray->m_capacity); + while (new_capacity < min_new_capacity) + new_capacity *= 2; + } + if (NULL == (pNew_p = pZip->m_pRealloc(pZip->m_pAlloc_opaque, pArray->m_p, pArray->m_element_size, new_capacity))) + return MZ_FALSE; + pArray->m_p = pNew_p; + pArray->m_capacity = new_capacity; + return MZ_TRUE; +} + +static MZ_FORCEINLINE mz_bool mz_zip_array_reserve(mz_zip_archive *pZip, mz_zip_array *pArray, size_t new_capacity, mz_uint growing) +{ + if (new_capacity > pArray->m_capacity) + { + if (!mz_zip_array_ensure_capacity(pZip, pArray, new_capacity, growing)) + return MZ_FALSE; + } + return MZ_TRUE; +} + +static MZ_FORCEINLINE mz_bool mz_zip_array_resize(mz_zip_archive *pZip, mz_zip_array *pArray, size_t new_size, mz_uint growing) +{ + if (new_size > pArray->m_capacity) + { + if (!mz_zip_array_ensure_capacity(pZip, pArray, new_size, growing)) + return MZ_FALSE; + } + pArray->m_size = new_size; + return MZ_TRUE; +} + +static MZ_FORCEINLINE mz_bool mz_zip_array_ensure_room(mz_zip_archive *pZip, mz_zip_array *pArray, size_t n) +{ + return mz_zip_array_reserve(pZip, pArray, pArray->m_size + n, MZ_TRUE); +} + +static MZ_FORCEINLINE mz_bool mz_zip_array_push_back(mz_zip_archive *pZip, mz_zip_array *pArray, const void *pElements, size_t n) +{ + size_t orig_size = pArray->m_size; + if (!mz_zip_array_resize(pZip, pArray, orig_size + n, MZ_TRUE)) + return MZ_FALSE; + if (n > 0) + memcpy((mz_uint8 *)pArray->m_p + orig_size * pArray->m_element_size, pElements, n * pArray->m_element_size); + return MZ_TRUE; +} + +#ifndef MINIZ_NO_TIME +static MZ_TIME_T mz_zip_dos_to_time_t(int dos_time, int dos_date) +{ + struct tm tm; + memset(&tm, 0, sizeof(tm)); + tm.tm_isdst = -1; + tm.tm_year = ((dos_date >> 9) & 127) + 1980 - 1900; + tm.tm_mon = ((dos_date >> 5) & 15) - 1; + tm.tm_mday = dos_date & 31; + tm.tm_hour = (dos_time >> 11) & 31; + tm.tm_min = (dos_time >> 5) & 63; + tm.tm_sec = (dos_time << 1) & 62; + return mktime(&tm); +} + +#ifndef MINIZ_NO_ARCHIVE_WRITING_APIS +static void mz_zip_time_t_to_dos_time(MZ_TIME_T time, mz_uint16 *pDOS_time, mz_uint16 *pDOS_date) +{ +#ifdef _MSC_VER + struct tm tm_struct; + struct tm *tm = &tm_struct; + errno_t err = localtime_s(tm, &time); + if (err) + { + *pDOS_date = 0; + *pDOS_time = 0; + return; + } +#else + struct tm *tm = localtime(&time); +#endif /* #ifdef _MSC_VER */ + + *pDOS_time = (mz_uint16)(((tm->tm_hour) << 11) + ((tm->tm_min) << 5) + ((tm->tm_sec) >> 1)); + *pDOS_date = (mz_uint16)(((tm->tm_year + 1900 - 1980) << 9) + ((tm->tm_mon + 1) << 5) + tm->tm_mday); +} +#endif /* MINIZ_NO_ARCHIVE_WRITING_APIS */ + +#ifndef MINIZ_NO_STDIO +#ifndef MINIZ_NO_ARCHIVE_WRITING_APIS +static mz_bool mz_zip_get_file_modified_time(const char *pFilename, MZ_TIME_T *pTime) +{ + struct MZ_FILE_STAT_STRUCT file_stat; + + /* On Linux with x86 glibc, this call will fail on large files (I think >= 0x80000000 bytes) unless you compiled with _LARGEFILE64_SOURCE. Argh. */ + if (MZ_FILE_STAT(pFilename, &file_stat) != 0) + return MZ_FALSE; + + *pTime = file_stat.st_mtime; + + return MZ_TRUE; +} +#endif /* #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS*/ + +static mz_bool mz_zip_set_file_times(const char *pFilename, MZ_TIME_T access_time, MZ_TIME_T modified_time) +{ + struct utimbuf t; + + memset(&t, 0, sizeof(t)); + t.actime = access_time; + t.modtime = modified_time; + + return !utime(pFilename, &t); +} +#endif /* #ifndef MINIZ_NO_STDIO */ +#endif /* #ifndef MINIZ_NO_TIME */ + +static MZ_FORCEINLINE mz_bool mz_zip_set_error(mz_zip_archive *pZip, mz_zip_error err_num) +{ + if (pZip) + pZip->m_last_error = err_num; + return MZ_FALSE; +} + +static mz_bool mz_zip_reader_init_internal(mz_zip_archive *pZip, mz_uint flags) +{ + (void)flags; + if ((!pZip) || (pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_INVALID)) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + + if (!pZip->m_pAlloc) + pZip->m_pAlloc = miniz_def_alloc_func; + if (!pZip->m_pFree) + pZip->m_pFree = miniz_def_free_func; + if (!pZip->m_pRealloc) + pZip->m_pRealloc = miniz_def_realloc_func; + + pZip->m_archive_size = 0; + pZip->m_central_directory_file_ofs = 0; + pZip->m_total_files = 0; + pZip->m_last_error = MZ_ZIP_NO_ERROR; + + if (NULL == (pZip->m_pState = (mz_zip_internal_state *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(mz_zip_internal_state)))) + return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + + memset(pZip->m_pState, 0, sizeof(mz_zip_internal_state)); + MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir, sizeof(mz_uint8)); + MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir_offsets, sizeof(mz_uint32)); + MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_sorted_central_dir_offsets, sizeof(mz_uint32)); + pZip->m_pState->m_init_flags = flags; + pZip->m_pState->m_zip64 = MZ_FALSE; + pZip->m_pState->m_zip64_has_extended_info_fields = MZ_FALSE; + + pZip->m_zip_mode = MZ_ZIP_MODE_READING; + + return MZ_TRUE; +} + +static MZ_FORCEINLINE mz_bool mz_zip_reader_filename_less(const mz_zip_array *pCentral_dir_array, const mz_zip_array *pCentral_dir_offsets, mz_uint l_index, mz_uint r_index) +{ + const mz_uint8 *pL = &MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_array, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32, l_index)), *pE; + const mz_uint8 *pR = &MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_array, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32, r_index)); + mz_uint l_len = MZ_READ_LE16(pL + MZ_ZIP_CDH_FILENAME_LEN_OFS), r_len = MZ_READ_LE16(pR + MZ_ZIP_CDH_FILENAME_LEN_OFS); + mz_uint8 l = 0, r = 0; + pL += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; + pR += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; + pE = pL + MZ_MIN(l_len, r_len); + while (pL < pE) + { + if ((l = MZ_TOLOWER(*pL)) != (r = MZ_TOLOWER(*pR))) + break; + pL++; + pR++; + } + return (pL == pE) ? (l_len < r_len) : (l < r); +} + +#define MZ_SWAP_UINT32(a, b) \ + do \ + { \ + mz_uint32 t = a; \ + a = b; \ + b = t; \ + } \ + MZ_MACRO_END + +/* Heap sort of lowercased filenames, used to help accelerate plain central directory searches by mz_zip_reader_locate_file(). (Could also use qsort(), but it could allocate memory.) */ +static void mz_zip_reader_sort_central_dir_offsets_by_filename(mz_zip_archive *pZip) +{ + mz_zip_internal_state *pState = pZip->m_pState; + const mz_zip_array *pCentral_dir_offsets = &pState->m_central_dir_offsets; + const mz_zip_array *pCentral_dir = &pState->m_central_dir; + mz_uint32 *pIndices; + mz_uint32 start, end; + const mz_uint32 size = pZip->m_total_files; + + if (size <= 1U) + return; + + pIndices = &MZ_ZIP_ARRAY_ELEMENT(&pState->m_sorted_central_dir_offsets, mz_uint32, 0); + + start = (size - 2U) >> 1U; + for (;;) + { + mz_uint64 child, root = start; + for (;;) + { + if ((child = (root << 1U) + 1U) >= size) + break; + child += (((child + 1U) < size) && (mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[child], pIndices[child + 1U]))); + if (!mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[root], pIndices[child])) + break; + MZ_SWAP_UINT32(pIndices[root], pIndices[child]); + root = child; + } + if (!start) + break; + start--; + } + + end = size - 1; + while (end > 0) + { + mz_uint64 child, root = 0; + MZ_SWAP_UINT32(pIndices[end], pIndices[0]); + for (;;) + { + if ((child = (root << 1U) + 1U) >= end) + break; + child += (((child + 1U) < end) && mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[child], pIndices[child + 1U])); + if (!mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[root], pIndices[child])) + break; + MZ_SWAP_UINT32(pIndices[root], pIndices[child]); + root = child; + } + end--; + } +} + +static mz_bool mz_zip_reader_locate_header_sig(mz_zip_archive *pZip, mz_uint32 record_sig, mz_uint32 record_size, mz_int64 *pOfs) +{ + mz_int64 cur_file_ofs; + mz_uint32 buf_u32[4096 / sizeof(mz_uint32)]; + mz_uint8 *pBuf = (mz_uint8 *)buf_u32; + + /* Basic sanity checks - reject files which are too small */ + if (pZip->m_archive_size < record_size) + return MZ_FALSE; + + /* Find the record by scanning the file from the end towards the beginning. */ + cur_file_ofs = MZ_MAX((mz_int64)pZip->m_archive_size - (mz_int64)sizeof(buf_u32), 0); + for (;;) + { + int i, n = (int)MZ_MIN(sizeof(buf_u32), pZip->m_archive_size - cur_file_ofs); + + if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, n) != (mz_uint)n) + return MZ_FALSE; + + for (i = n - 4; i >= 0; --i) + { + mz_uint s = MZ_READ_LE32(pBuf + i); + if (s == record_sig) + { + if ((pZip->m_archive_size - (cur_file_ofs + i)) >= record_size) + break; + } + } + + if (i >= 0) + { + cur_file_ofs += i; + break; + } + + /* Give up if we've searched the entire file, or we've gone back "too far" (~64kb) */ + if ((!cur_file_ofs) || ((pZip->m_archive_size - cur_file_ofs) >= (MZ_UINT16_MAX + record_size))) + return MZ_FALSE; + + cur_file_ofs = MZ_MAX(cur_file_ofs - (sizeof(buf_u32) - 3), 0); + } + + *pOfs = cur_file_ofs; + return MZ_TRUE; +} + +static mz_bool mz_zip_reader_read_central_dir(mz_zip_archive *pZip, mz_uint flags) +{ + mz_uint cdir_size = 0, cdir_entries_on_this_disk = 0, num_this_disk = 0, cdir_disk_index = 0; + mz_uint64 cdir_ofs = 0; + mz_int64 cur_file_ofs = 0; + const mz_uint8 *p; + + mz_uint32 buf_u32[4096 / sizeof(mz_uint32)]; + mz_uint8 *pBuf = (mz_uint8 *)buf_u32; + mz_bool sort_central_dir = ((flags & MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY) == 0); + mz_uint32 zip64_end_of_central_dir_locator_u32[(MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; + mz_uint8 *pZip64_locator = (mz_uint8 *)zip64_end_of_central_dir_locator_u32; + + mz_uint32 zip64_end_of_central_dir_header_u32[(MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; + mz_uint8 *pZip64_end_of_central_dir = (mz_uint8 *)zip64_end_of_central_dir_header_u32; + + mz_uint64 zip64_end_of_central_dir_ofs = 0; + + /* Basic sanity checks - reject files which are too small, and check the first 4 bytes of the file to make sure a local header is there. */ + if (pZip->m_archive_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) + return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE); + + if (!mz_zip_reader_locate_header_sig(pZip, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE, &cur_file_ofs)) + return mz_zip_set_error(pZip, MZ_ZIP_FAILED_FINDING_CENTRAL_DIR); + + /* Read and verify the end of central directory record. */ + if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) != MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) + return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); + + if (MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_SIG_OFS) != MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG) + return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE); + + if (cur_file_ofs >= (MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE + MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE)) + { + if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs - MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE, pZip64_locator, MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE) == MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE) + { + if (MZ_READ_LE32(pZip64_locator + MZ_ZIP64_ECDL_SIG_OFS) == MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIG) + { + zip64_end_of_central_dir_ofs = MZ_READ_LE64(pZip64_locator + MZ_ZIP64_ECDL_REL_OFS_TO_ZIP64_ECDR_OFS); + if (zip64_end_of_central_dir_ofs > (pZip->m_archive_size - MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE)) + return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE); + + if (pZip->m_pRead(pZip->m_pIO_opaque, zip64_end_of_central_dir_ofs, pZip64_end_of_central_dir, MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE) == MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE) + { + if (MZ_READ_LE32(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_SIG_OFS) == MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIG) + { + pZip->m_pState->m_zip64 = MZ_TRUE; + } + } + } + } + } + + pZip->m_total_files = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS); + cdir_entries_on_this_disk = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS); + num_this_disk = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_NUM_THIS_DISK_OFS); + cdir_disk_index = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_NUM_DISK_CDIR_OFS); + cdir_size = MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_CDIR_SIZE_OFS); + cdir_ofs = MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_CDIR_OFS_OFS); + + if (pZip->m_pState->m_zip64) + { + mz_uint32 zip64_total_num_of_disks = MZ_READ_LE32(pZip64_locator + MZ_ZIP64_ECDL_TOTAL_NUMBER_OF_DISKS_OFS); + mz_uint64 zip64_cdir_total_entries = MZ_READ_LE64(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_CDIR_TOTAL_ENTRIES_OFS); + mz_uint64 zip64_cdir_total_entries_on_this_disk = MZ_READ_LE64(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS); + mz_uint64 zip64_size_of_end_of_central_dir_record = MZ_READ_LE64(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_SIZE_OF_RECORD_OFS); + mz_uint64 zip64_size_of_central_directory = MZ_READ_LE64(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_CDIR_SIZE_OFS); + + if (zip64_size_of_end_of_central_dir_record < (MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE - 12)) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + + if (zip64_total_num_of_disks != 1U) + return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_MULTIDISK); + + /* Check for miniz's practical limits */ + if (zip64_cdir_total_entries > MZ_UINT32_MAX) + return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); + + pZip->m_total_files = (mz_uint32)zip64_cdir_total_entries; + + if (zip64_cdir_total_entries_on_this_disk > MZ_UINT32_MAX) + return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); + + cdir_entries_on_this_disk = (mz_uint32)zip64_cdir_total_entries_on_this_disk; + + /* Check for miniz's current practical limits (sorry, this should be enough for millions of files) */ + if (zip64_size_of_central_directory > MZ_UINT32_MAX) + return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE); + + cdir_size = (mz_uint32)zip64_size_of_central_directory; + + num_this_disk = MZ_READ_LE32(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_NUM_THIS_DISK_OFS); + + cdir_disk_index = MZ_READ_LE32(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_NUM_DISK_CDIR_OFS); + + cdir_ofs = MZ_READ_LE64(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_CDIR_OFS_OFS); + } + + if (pZip->m_total_files != cdir_entries_on_this_disk) + return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_MULTIDISK); + + if (((num_this_disk | cdir_disk_index) != 0) && ((num_this_disk != 1) || (cdir_disk_index != 1))) + return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_MULTIDISK); + + if (cdir_size < pZip->m_total_files * MZ_ZIP_CENTRAL_DIR_HEADER_SIZE) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + + if ((cdir_ofs + (mz_uint64)cdir_size) > pZip->m_archive_size) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + + pZip->m_central_directory_file_ofs = cdir_ofs; + + if (pZip->m_total_files) + { + mz_uint i, n; + /* Read the entire central directory into a heap block, and allocate another heap block to hold the unsorted central dir file record offsets, and possibly another to hold the sorted indices. */ + if ((!mz_zip_array_resize(pZip, &pZip->m_pState->m_central_dir, cdir_size, MZ_FALSE)) || + (!mz_zip_array_resize(pZip, &pZip->m_pState->m_central_dir_offsets, pZip->m_total_files, MZ_FALSE))) + return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + + if (sort_central_dir) + { + if (!mz_zip_array_resize(pZip, &pZip->m_pState->m_sorted_central_dir_offsets, pZip->m_total_files, MZ_FALSE)) + return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + } + + if (pZip->m_pRead(pZip->m_pIO_opaque, cdir_ofs, pZip->m_pState->m_central_dir.m_p, cdir_size) != cdir_size) + return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); + + /* Now create an index into the central directory file records, do some basic sanity checking on each record */ + p = (const mz_uint8 *)pZip->m_pState->m_central_dir.m_p; + for (n = cdir_size, i = 0; i < pZip->m_total_files; ++i) + { + mz_uint total_header_size, disk_index, bit_flags, filename_size, ext_data_size; + mz_uint64 comp_size, decomp_size, local_header_ofs; + + if ((n < MZ_ZIP_CENTRAL_DIR_HEADER_SIZE) || (MZ_READ_LE32(p) != MZ_ZIP_CENTRAL_DIR_HEADER_SIG)) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + + MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, i) = (mz_uint32)(p - (const mz_uint8 *)pZip->m_pState->m_central_dir.m_p); + + if (sort_central_dir) + MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_sorted_central_dir_offsets, mz_uint32, i) = i; + + comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS); + decomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS); + local_header_ofs = MZ_READ_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS); + filename_size = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS); + ext_data_size = MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS); + + if ((!pZip->m_pState->m_zip64_has_extended_info_fields) && + (ext_data_size) && + (MZ_MAX(MZ_MAX(comp_size, decomp_size), local_header_ofs) == MZ_UINT32_MAX)) + { + /* Attempt to find zip64 extended information field in the entry's extra data */ + mz_uint32 extra_size_remaining = ext_data_size; + + if (extra_size_remaining) + { + const mz_uint8 *pExtra_data; + void* buf = NULL; + + if (MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_size + ext_data_size > n) + { + buf = MZ_MALLOC(ext_data_size); + if(buf==NULL) + return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + + if (pZip->m_pRead(pZip->m_pIO_opaque, cdir_ofs + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_size, buf, ext_data_size) != ext_data_size) + { + MZ_FREE(buf); + return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); + } + + pExtra_data = (mz_uint8*)buf; + } + else + { + pExtra_data = p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_size; + } + + do + { + mz_uint32 field_id; + mz_uint32 field_data_size; + + if (extra_size_remaining < (sizeof(mz_uint16) * 2)) + { + MZ_FREE(buf); + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + } + + field_id = MZ_READ_LE16(pExtra_data); + field_data_size = MZ_READ_LE16(pExtra_data + sizeof(mz_uint16)); + + if ((field_data_size + sizeof(mz_uint16) * 2) > extra_size_remaining) + { + MZ_FREE(buf); + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + } + + if (field_id == MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID) + { + /* Ok, the archive didn't have any zip64 headers but it uses a zip64 extended information field so mark it as zip64 anyway (this can occur with infozip's zip util when it reads compresses files from stdin). */ + pZip->m_pState->m_zip64 = MZ_TRUE; + pZip->m_pState->m_zip64_has_extended_info_fields = MZ_TRUE; + break; + } + + pExtra_data += sizeof(mz_uint16) * 2 + field_data_size; + extra_size_remaining = extra_size_remaining - sizeof(mz_uint16) * 2 - field_data_size; + } while (extra_size_remaining); + + MZ_FREE(buf); + } + } + + /* I've seen archives that aren't marked as zip64 that uses zip64 ext data, argh */ + if ((comp_size != MZ_UINT32_MAX) && (decomp_size != MZ_UINT32_MAX)) + { + if (((!MZ_READ_LE32(p + MZ_ZIP_CDH_METHOD_OFS)) && (decomp_size != comp_size)) || (decomp_size && !comp_size)) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + } + + disk_index = MZ_READ_LE16(p + MZ_ZIP_CDH_DISK_START_OFS); + if ((disk_index == MZ_UINT16_MAX) || ((disk_index != num_this_disk) && (disk_index != 1))) + return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_MULTIDISK); + + if (comp_size != MZ_UINT32_MAX) + { + if (((mz_uint64)MZ_READ_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS) + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + comp_size) > pZip->m_archive_size) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + } + + bit_flags = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS); + if (bit_flags & MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_LOCAL_DIR_IS_MASKED) + return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION); + + if ((total_header_size = MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS) + MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS) + MZ_READ_LE16(p + MZ_ZIP_CDH_COMMENT_LEN_OFS)) > n) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + + n -= total_header_size; + p += total_header_size; + } + } + + if (sort_central_dir) + mz_zip_reader_sort_central_dir_offsets_by_filename(pZip); + + return MZ_TRUE; +} + +void mz_zip_zero_struct(mz_zip_archive *pZip) +{ + if (pZip) + MZ_CLEAR_OBJ(*pZip); +} + +static mz_bool mz_zip_reader_end_internal(mz_zip_archive *pZip, mz_bool set_last_error) +{ + mz_bool status = MZ_TRUE; + + if (!pZip) + return MZ_FALSE; + + if ((!pZip->m_pState) || (!pZip->m_pAlloc) || (!pZip->m_pFree) || (pZip->m_zip_mode != MZ_ZIP_MODE_READING)) + { + if (set_last_error) + pZip->m_last_error = MZ_ZIP_INVALID_PARAMETER; + + return MZ_FALSE; + } + + if (pZip->m_pState) + { + mz_zip_internal_state *pState = pZip->m_pState; + pZip->m_pState = NULL; + + mz_zip_array_clear(pZip, &pState->m_central_dir); + mz_zip_array_clear(pZip, &pState->m_central_dir_offsets); + mz_zip_array_clear(pZip, &pState->m_sorted_central_dir_offsets); + +#ifndef MINIZ_NO_STDIO + if (pState->m_pFile) + { + if (pZip->m_zip_type == MZ_ZIP_TYPE_FILE) + { + if (MZ_FCLOSE(pState->m_pFile) == EOF) + { + if (set_last_error) + pZip->m_last_error = MZ_ZIP_FILE_CLOSE_FAILED; + status = MZ_FALSE; + } + } + pState->m_pFile = NULL; + } +#endif /* #ifndef MINIZ_NO_STDIO */ + + pZip->m_pFree(pZip->m_pAlloc_opaque, pState); + } + pZip->m_zip_mode = MZ_ZIP_MODE_INVALID; + + return status; +} + +mz_bool mz_zip_reader_end(mz_zip_archive *pZip) +{ + return mz_zip_reader_end_internal(pZip, MZ_TRUE); +} +mz_bool mz_zip_reader_init(mz_zip_archive *pZip, mz_uint64 size, mz_uint flags) +{ + if ((!pZip) || (!pZip->m_pRead)) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + + if (!mz_zip_reader_init_internal(pZip, flags)) + return MZ_FALSE; + + pZip->m_zip_type = MZ_ZIP_TYPE_USER; + pZip->m_archive_size = size; + + if (!mz_zip_reader_read_central_dir(pZip, flags)) + { + mz_zip_reader_end_internal(pZip, MZ_FALSE); + return MZ_FALSE; + } + + return MZ_TRUE; +} + +static size_t mz_zip_mem_read_func(void *pOpaque, mz_uint64 file_ofs, void *pBuf, size_t n) +{ + mz_zip_archive *pZip = (mz_zip_archive *)pOpaque; + size_t s = (file_ofs >= pZip->m_archive_size) ? 0 : (size_t)MZ_MIN(pZip->m_archive_size - file_ofs, n); + memcpy(pBuf, (const mz_uint8 *)pZip->m_pState->m_pMem + file_ofs, s); + return s; +} + +mz_bool mz_zip_reader_init_mem(mz_zip_archive *pZip, const void *pMem, size_t size, mz_uint flags) +{ + if (!pMem) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + + if (size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) + return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE); + + if (!mz_zip_reader_init_internal(pZip, flags)) + return MZ_FALSE; + + pZip->m_zip_type = MZ_ZIP_TYPE_MEMORY; + pZip->m_archive_size = size; + pZip->m_pRead = mz_zip_mem_read_func; + pZip->m_pIO_opaque = pZip; + pZip->m_pNeeds_keepalive = NULL; + +#ifdef __cplusplus + pZip->m_pState->m_pMem = const_cast(pMem); +#else + pZip->m_pState->m_pMem = (void *)pMem; +#endif + + pZip->m_pState->m_mem_size = size; + + if (!mz_zip_reader_read_central_dir(pZip, flags)) + { + mz_zip_reader_end_internal(pZip, MZ_FALSE); + return MZ_FALSE; + } + + return MZ_TRUE; +} + +#ifndef MINIZ_NO_STDIO +static size_t mz_zip_file_read_func(void *pOpaque, mz_uint64 file_ofs, void *pBuf, size_t n) +{ + mz_zip_archive *pZip = (mz_zip_archive *)pOpaque; + mz_int64 cur_ofs = MZ_FTELL64(pZip->m_pState->m_pFile); + + file_ofs += pZip->m_pState->m_file_archive_start_ofs; + + if (((mz_int64)file_ofs < 0) || (((cur_ofs != (mz_int64)file_ofs)) && (MZ_FSEEK64(pZip->m_pState->m_pFile, (mz_int64)file_ofs, SEEK_SET)))) + return 0; + + return MZ_FREAD(pBuf, 1, n, pZip->m_pState->m_pFile); +} + +mz_bool mz_zip_reader_init_file(mz_zip_archive *pZip, const char *pFilename, mz_uint32 flags) +{ + return mz_zip_reader_init_file_v2(pZip, pFilename, flags, 0, 0); +} + +mz_bool mz_zip_reader_init_file_v2(mz_zip_archive *pZip, const char *pFilename, mz_uint flags, mz_uint64 file_start_ofs, mz_uint64 archive_size) +{ + mz_uint64 file_size; + MZ_FILE *pFile; + + if ((!pZip) || (!pFilename) || ((archive_size) && (archive_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE))) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + + pFile = MZ_FOPEN(pFilename, "rb"); + if (!pFile) + return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED); + + file_size = archive_size; + if (!file_size) + { + if (MZ_FSEEK64(pFile, 0, SEEK_END)) + { + MZ_FCLOSE(pFile); + return mz_zip_set_error(pZip, MZ_ZIP_FILE_SEEK_FAILED); + } + + file_size = MZ_FTELL64(pFile); + } + + /* TODO: Better sanity check archive_size and the # of actual remaining bytes */ + + if (file_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) + { + MZ_FCLOSE(pFile); + return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE); + } + + if (!mz_zip_reader_init_internal(pZip, flags)) + { + MZ_FCLOSE(pFile); + return MZ_FALSE; + } + + pZip->m_zip_type = MZ_ZIP_TYPE_FILE; + pZip->m_pRead = mz_zip_file_read_func; + pZip->m_pIO_opaque = pZip; + pZip->m_pState->m_pFile = pFile; + pZip->m_archive_size = file_size; + pZip->m_pState->m_file_archive_start_ofs = file_start_ofs; + + if (!mz_zip_reader_read_central_dir(pZip, flags)) + { + mz_zip_reader_end_internal(pZip, MZ_FALSE); + return MZ_FALSE; + } + + return MZ_TRUE; +} + +mz_bool mz_zip_reader_init_cfile(mz_zip_archive *pZip, MZ_FILE *pFile, mz_uint64 archive_size, mz_uint flags) +{ + mz_uint64 cur_file_ofs; + + if ((!pZip) || (!pFile)) + return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED); + + cur_file_ofs = MZ_FTELL64(pFile); + + if (!archive_size) + { + if (MZ_FSEEK64(pFile, 0, SEEK_END)) + return mz_zip_set_error(pZip, MZ_ZIP_FILE_SEEK_FAILED); + + archive_size = MZ_FTELL64(pFile) - cur_file_ofs; + + if (archive_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) + return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE); + } + + if (!mz_zip_reader_init_internal(pZip, flags)) + return MZ_FALSE; + + pZip->m_zip_type = MZ_ZIP_TYPE_CFILE; + pZip->m_pRead = mz_zip_file_read_func; + + pZip->m_pIO_opaque = pZip; + pZip->m_pState->m_pFile = pFile; + pZip->m_archive_size = archive_size; + pZip->m_pState->m_file_archive_start_ofs = cur_file_ofs; + + if (!mz_zip_reader_read_central_dir(pZip, flags)) + { + mz_zip_reader_end_internal(pZip, MZ_FALSE); + return MZ_FALSE; + } + + return MZ_TRUE; +} + +#endif /* #ifndef MINIZ_NO_STDIO */ + +static MZ_FORCEINLINE const mz_uint8 *mz_zip_get_cdh(mz_zip_archive *pZip, mz_uint file_index) +{ + if ((!pZip) || (!pZip->m_pState) || (file_index >= pZip->m_total_files)) + return NULL; + return &MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, file_index)); +} + +mz_bool mz_zip_reader_is_file_encrypted(mz_zip_archive *pZip, mz_uint file_index) +{ + mz_uint m_bit_flag; + const mz_uint8 *p = mz_zip_get_cdh(pZip, file_index); + if (!p) + { + mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + return MZ_FALSE; + } + + m_bit_flag = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS); + return (m_bit_flag & (MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION)) != 0; +} + +mz_bool mz_zip_reader_is_file_supported(mz_zip_archive *pZip, mz_uint file_index) +{ + mz_uint bit_flag; + mz_uint method; + + const mz_uint8 *p = mz_zip_get_cdh(pZip, file_index); + if (!p) + { + mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + return MZ_FALSE; + } + + method = MZ_READ_LE16(p + MZ_ZIP_CDH_METHOD_OFS); + bit_flag = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS); + + if ((method != 0) && (method != MZ_DEFLATED)) + { + mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_METHOD); + return MZ_FALSE; + } + + if (bit_flag & (MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION)) + { + mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION); + return MZ_FALSE; + } + + if (bit_flag & MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_COMPRESSED_PATCH_FLAG) + { + mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_FEATURE); + return MZ_FALSE; + } + + return MZ_TRUE; +} + +mz_bool mz_zip_reader_is_file_a_directory(mz_zip_archive *pZip, mz_uint file_index) +{ + mz_uint filename_len, attribute_mapping_id, external_attr; + const mz_uint8 *p = mz_zip_get_cdh(pZip, file_index); + if (!p) + { + mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + return MZ_FALSE; + } + + filename_len = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS); + if (filename_len) + { + if (*(p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_len - 1) == '/') + return MZ_TRUE; + } + + /* Bugfix: This code was also checking if the internal attribute was non-zero, which wasn't correct. */ + /* Most/all zip writers (hopefully) set DOS file/directory attributes in the low 16-bits, so check for the DOS directory flag and ignore the source OS ID in the created by field. */ + /* FIXME: Remove this check? Is it necessary - we already check the filename. */ + attribute_mapping_id = MZ_READ_LE16(p + MZ_ZIP_CDH_VERSION_MADE_BY_OFS) >> 8; + (void)attribute_mapping_id; + + external_attr = MZ_READ_LE32(p + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS); + if ((external_attr & MZ_ZIP_DOS_DIR_ATTRIBUTE_BITFLAG) != 0) + { + return MZ_TRUE; + } + + return MZ_FALSE; +} + +static mz_bool mz_zip_file_stat_internal(mz_zip_archive *pZip, mz_uint file_index, const mz_uint8 *pCentral_dir_header, mz_zip_archive_file_stat *pStat, mz_bool *pFound_zip64_extra_data) +{ + mz_uint n; + const mz_uint8 *p = pCentral_dir_header; + + if (pFound_zip64_extra_data) + *pFound_zip64_extra_data = MZ_FALSE; + + if ((!p) || (!pStat)) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + + /* Extract fields from the central directory record. */ + pStat->m_file_index = file_index; + pStat->m_central_dir_ofs = MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, file_index); + pStat->m_version_made_by = MZ_READ_LE16(p + MZ_ZIP_CDH_VERSION_MADE_BY_OFS); + pStat->m_version_needed = MZ_READ_LE16(p + MZ_ZIP_CDH_VERSION_NEEDED_OFS); + pStat->m_bit_flag = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS); + pStat->m_method = MZ_READ_LE16(p + MZ_ZIP_CDH_METHOD_OFS); +#ifndef MINIZ_NO_TIME + pStat->m_time = mz_zip_dos_to_time_t(MZ_READ_LE16(p + MZ_ZIP_CDH_FILE_TIME_OFS), MZ_READ_LE16(p + MZ_ZIP_CDH_FILE_DATE_OFS)); +#endif + pStat->m_crc32 = MZ_READ_LE32(p + MZ_ZIP_CDH_CRC32_OFS); + pStat->m_comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS); + pStat->m_uncomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS); + pStat->m_internal_attr = MZ_READ_LE16(p + MZ_ZIP_CDH_INTERNAL_ATTR_OFS); + pStat->m_external_attr = MZ_READ_LE32(p + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS); + pStat->m_local_header_ofs = MZ_READ_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS); + + /* Copy as much of the filename and comment as possible. */ + n = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS); + n = MZ_MIN(n, MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE - 1); + memcpy(pStat->m_filename, p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, n); + pStat->m_filename[n] = '\0'; + + n = MZ_READ_LE16(p + MZ_ZIP_CDH_COMMENT_LEN_OFS); + n = MZ_MIN(n, MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE - 1); + pStat->m_comment_size = n; + memcpy(pStat->m_comment, p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS) + MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS), n); + pStat->m_comment[n] = '\0'; + + /* Set some flags for convienance */ + pStat->m_is_directory = mz_zip_reader_is_file_a_directory(pZip, file_index); + pStat->m_is_encrypted = mz_zip_reader_is_file_encrypted(pZip, file_index); + pStat->m_is_supported = mz_zip_reader_is_file_supported(pZip, file_index); + + /* See if we need to read any zip64 extended information fields. */ + /* Confusingly, these zip64 fields can be present even on non-zip64 archives (Debian zip on a huge files from stdin piped to stdout creates them). */ + if (MZ_MAX(MZ_MAX(pStat->m_comp_size, pStat->m_uncomp_size), pStat->m_local_header_ofs) == MZ_UINT32_MAX) + { + /* Attempt to find zip64 extended information field in the entry's extra data */ + mz_uint32 extra_size_remaining = MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS); + + if (extra_size_remaining) + { + const mz_uint8 *pExtra_data = p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS); + + do + { + mz_uint32 field_id; + mz_uint32 field_data_size; + + if (extra_size_remaining < (sizeof(mz_uint16) * 2)) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + + field_id = MZ_READ_LE16(pExtra_data); + field_data_size = MZ_READ_LE16(pExtra_data + sizeof(mz_uint16)); + + if ((field_data_size + sizeof(mz_uint16) * 2) > extra_size_remaining) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + + if (field_id == MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID) + { + const mz_uint8 *pField_data = pExtra_data + sizeof(mz_uint16) * 2; + mz_uint32 field_data_remaining = field_data_size; + + if (pFound_zip64_extra_data) + *pFound_zip64_extra_data = MZ_TRUE; + + if (pStat->m_uncomp_size == MZ_UINT32_MAX) + { + if (field_data_remaining < sizeof(mz_uint64)) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + + pStat->m_uncomp_size = MZ_READ_LE64(pField_data); + pField_data += sizeof(mz_uint64); + field_data_remaining -= sizeof(mz_uint64); + } + + if (pStat->m_comp_size == MZ_UINT32_MAX) + { + if (field_data_remaining < sizeof(mz_uint64)) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + + pStat->m_comp_size = MZ_READ_LE64(pField_data); + pField_data += sizeof(mz_uint64); + field_data_remaining -= sizeof(mz_uint64); + } + + if (pStat->m_local_header_ofs == MZ_UINT32_MAX) + { + if (field_data_remaining < sizeof(mz_uint64)) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + + pStat->m_local_header_ofs = MZ_READ_LE64(pField_data); + pField_data += sizeof(mz_uint64); + field_data_remaining -= sizeof(mz_uint64); + } + + break; + } + + pExtra_data += sizeof(mz_uint16) * 2 + field_data_size; + extra_size_remaining = extra_size_remaining - sizeof(mz_uint16) * 2 - field_data_size; + } while (extra_size_remaining); + } + } + + return MZ_TRUE; +} + +static MZ_FORCEINLINE mz_bool mz_zip_string_equal(const char *pA, const char *pB, mz_uint len, mz_uint flags) +{ + mz_uint i; + if (flags & MZ_ZIP_FLAG_CASE_SENSITIVE) + return 0 == memcmp(pA, pB, len); + for (i = 0; i < len; ++i) + if (MZ_TOLOWER(pA[i]) != MZ_TOLOWER(pB[i])) + return MZ_FALSE; + return MZ_TRUE; +} + +static MZ_FORCEINLINE int mz_zip_filename_compare(const mz_zip_array *pCentral_dir_array, const mz_zip_array *pCentral_dir_offsets, mz_uint l_index, const char *pR, mz_uint r_len) +{ + const mz_uint8 *pL = &MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_array, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32, l_index)), *pE; + mz_uint l_len = MZ_READ_LE16(pL + MZ_ZIP_CDH_FILENAME_LEN_OFS); + mz_uint8 l = 0, r = 0; + pL += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; + pE = pL + MZ_MIN(l_len, r_len); + while (pL < pE) + { + if ((l = MZ_TOLOWER(*pL)) != (r = MZ_TOLOWER(*pR))) + break; + pL++; + pR++; + } + return (pL == pE) ? (int)(l_len - r_len) : (l - r); +} + +static mz_bool mz_zip_locate_file_binary_search(mz_zip_archive *pZip, const char *pFilename, mz_uint32 *pIndex) +{ + mz_zip_internal_state *pState = pZip->m_pState; + const mz_zip_array *pCentral_dir_offsets = &pState->m_central_dir_offsets; + const mz_zip_array *pCentral_dir = &pState->m_central_dir; + mz_uint32 *pIndices = &MZ_ZIP_ARRAY_ELEMENT(&pState->m_sorted_central_dir_offsets, mz_uint32, 0); + const uint32_t size = pZip->m_total_files; + const mz_uint filename_len = (mz_uint)strlen(pFilename); + + if (pIndex) + *pIndex = 0; + + if (size) + { + /* yes I could use uint32_t's, but then we would have to add some special case checks in the loop, argh, and */ + /* honestly the major expense here on 32-bit CPU's will still be the filename compare */ + mz_int64 l = 0, h = (mz_int64)size - 1; + + while (l <= h) + { + mz_int64 m = l + ((h - l) >> 1); + uint32_t file_index = pIndices[(uint32_t)m]; + + int comp = mz_zip_filename_compare(pCentral_dir, pCentral_dir_offsets, file_index, pFilename, filename_len); + if (!comp) + { + if (pIndex) + *pIndex = file_index; + return MZ_TRUE; + } + else if (comp < 0) + l = m + 1; + else + h = m - 1; + } + } + + return mz_zip_set_error(pZip, MZ_ZIP_FILE_NOT_FOUND); +} + +int mz_zip_reader_locate_file(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags) +{ + mz_uint32 index; + if (!mz_zip_reader_locate_file_v2(pZip, pName, pComment, flags, &index)) + return -1; + else + return (int)index; +} + +mz_bool mz_zip_reader_locate_file_v2(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags, mz_uint32 *pIndex) +{ + mz_uint file_index; + size_t name_len, comment_len; + + if (pIndex) + *pIndex = 0; + + if ((!pZip) || (!pZip->m_pState) || (!pName)) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + + /* See if we can use a binary search */ + if (((pZip->m_pState->m_init_flags & MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY) == 0) && + (pZip->m_zip_mode == MZ_ZIP_MODE_READING) && + ((flags & (MZ_ZIP_FLAG_IGNORE_PATH | MZ_ZIP_FLAG_CASE_SENSITIVE)) == 0) && (!pComment) && (pZip->m_pState->m_sorted_central_dir_offsets.m_size)) + { + return mz_zip_locate_file_binary_search(pZip, pName, pIndex); + } + + /* Locate the entry by scanning the entire central directory */ + name_len = strlen(pName); + if (name_len > MZ_UINT16_MAX) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + + comment_len = pComment ? strlen(pComment) : 0; + if (comment_len > MZ_UINT16_MAX) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + + for (file_index = 0; file_index < pZip->m_total_files; file_index++) + { + const mz_uint8 *pHeader = &MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, file_index)); + mz_uint filename_len = MZ_READ_LE16(pHeader + MZ_ZIP_CDH_FILENAME_LEN_OFS); + const char *pFilename = (const char *)pHeader + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; + if (filename_len < name_len) + continue; + if (comment_len) + { + mz_uint file_extra_len = MZ_READ_LE16(pHeader + MZ_ZIP_CDH_EXTRA_LEN_OFS), file_comment_len = MZ_READ_LE16(pHeader + MZ_ZIP_CDH_COMMENT_LEN_OFS); + const char *pFile_comment = pFilename + filename_len + file_extra_len; + if ((file_comment_len != comment_len) || (!mz_zip_string_equal(pComment, pFile_comment, file_comment_len, flags))) + continue; + } + if ((flags & MZ_ZIP_FLAG_IGNORE_PATH) && (filename_len)) + { + int ofs = filename_len - 1; + do + { + if ((pFilename[ofs] == '/') || (pFilename[ofs] == '\\') || (pFilename[ofs] == ':')) + break; + } while (--ofs >= 0); + ofs++; + pFilename += ofs; + filename_len -= ofs; + } + if ((filename_len == name_len) && (mz_zip_string_equal(pName, pFilename, filename_len, flags))) + { + if (pIndex) + *pIndex = file_index; + return MZ_TRUE; + } + } + + return mz_zip_set_error(pZip, MZ_ZIP_FILE_NOT_FOUND); +} + +mz_bool mz_zip_reader_extract_to_mem_no_alloc(mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size) +{ + int status = TINFL_STATUS_DONE; + mz_uint64 needed_size, cur_file_ofs, comp_remaining, out_buf_ofs = 0, read_buf_size, read_buf_ofs = 0, read_buf_avail; + mz_zip_archive_file_stat file_stat; + void *pRead_buf; + mz_uint32 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; + mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32; + tinfl_decompressor inflator; + + if ((!pZip) || (!pZip->m_pState) || ((buf_size) && (!pBuf)) || ((user_read_buf_size) && (!pUser_read_buf)) || (!pZip->m_pRead)) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + + if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat)) + return MZ_FALSE; + + /* A directory or zero length file */ + if ((file_stat.m_is_directory) || (!file_stat.m_comp_size)) + return MZ_TRUE; + + /* Encryption and patch files are not supported. */ + if (file_stat.m_bit_flag & (MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_COMPRESSED_PATCH_FLAG)) + return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION); + + /* This function only supports decompressing stored and deflate. */ + if ((!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (file_stat.m_method != 0) && (file_stat.m_method != MZ_DEFLATED)) + return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_METHOD); + + /* Ensure supplied output buffer is large enough. */ + needed_size = (flags & MZ_ZIP_FLAG_COMPRESSED_DATA) ? file_stat.m_comp_size : file_stat.m_uncomp_size; + if (buf_size < needed_size) + return mz_zip_set_error(pZip, MZ_ZIP_BUF_TOO_SMALL); + + /* Read and parse the local directory entry. */ + cur_file_ofs = file_stat.m_local_header_ofs; + if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE) + return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); + + if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + + cur_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS); + if ((cur_file_ofs + file_stat.m_comp_size) > pZip->m_archive_size) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + + if ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!file_stat.m_method)) + { + /* The file is stored or the caller has requested the compressed data. */ + if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, (size_t)needed_size) != needed_size) + return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); + +#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS + if ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) == 0) + { + if (mz_crc32(MZ_CRC32_INIT, (const mz_uint8 *)pBuf, (size_t)file_stat.m_uncomp_size) != file_stat.m_crc32) + return mz_zip_set_error(pZip, MZ_ZIP_CRC_CHECK_FAILED); + } +#endif + + return MZ_TRUE; + } + + /* Decompress the file either directly from memory or from a file input buffer. */ + tinfl_init(&inflator); + + if (pZip->m_pState->m_pMem) + { + /* Read directly from the archive in memory. */ + pRead_buf = (mz_uint8 *)pZip->m_pState->m_pMem + cur_file_ofs; + read_buf_size = read_buf_avail = file_stat.m_comp_size; + comp_remaining = 0; + } + else if (pUser_read_buf) + { + /* Use a user provided read buffer. */ + if (!user_read_buf_size) + return MZ_FALSE; + pRead_buf = (mz_uint8 *)pUser_read_buf; + read_buf_size = user_read_buf_size; + read_buf_avail = 0; + comp_remaining = file_stat.m_comp_size; + } + else + { + /* Temporarily allocate a read buffer. */ + read_buf_size = MZ_MIN(file_stat.m_comp_size, (mz_uint64)MZ_ZIP_MAX_IO_BUF_SIZE); + if (((sizeof(size_t) == sizeof(mz_uint32))) && (read_buf_size > 0x7FFFFFFF)) + return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); + + if (NULL == (pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)read_buf_size))) + return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + + read_buf_avail = 0; + comp_remaining = file_stat.m_comp_size; + } + + do + { + /* The size_t cast here should be OK because we've verified that the output buffer is >= file_stat.m_uncomp_size above */ + size_t in_buf_size, out_buf_size = (size_t)(file_stat.m_uncomp_size - out_buf_ofs); + if ((!read_buf_avail) && (!pZip->m_pState->m_pMem)) + { + read_buf_avail = MZ_MIN(read_buf_size, comp_remaining); + if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail) + { + status = TINFL_STATUS_FAILED; + mz_zip_set_error(pZip, MZ_ZIP_DECOMPRESSION_FAILED); + break; + } + cur_file_ofs += read_buf_avail; + comp_remaining -= read_buf_avail; + read_buf_ofs = 0; + } + in_buf_size = (size_t)read_buf_avail; + status = tinfl_decompress(&inflator, (mz_uint8 *)pRead_buf + read_buf_ofs, &in_buf_size, (mz_uint8 *)pBuf, (mz_uint8 *)pBuf + out_buf_ofs, &out_buf_size, TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF | (comp_remaining ? TINFL_FLAG_HAS_MORE_INPUT : 0)); + read_buf_avail -= in_buf_size; + read_buf_ofs += in_buf_size; + out_buf_ofs += out_buf_size; + } while (status == TINFL_STATUS_NEEDS_MORE_INPUT); + + if (status == TINFL_STATUS_DONE) + { + /* Make sure the entire file was decompressed, and check its CRC. */ + if (out_buf_ofs != file_stat.m_uncomp_size) + { + mz_zip_set_error(pZip, MZ_ZIP_UNEXPECTED_DECOMPRESSED_SIZE); + status = TINFL_STATUS_FAILED; + } +#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS + else if (mz_crc32(MZ_CRC32_INIT, (const mz_uint8 *)pBuf, (size_t)file_stat.m_uncomp_size) != file_stat.m_crc32) + { + mz_zip_set_error(pZip, MZ_ZIP_CRC_CHECK_FAILED); + status = TINFL_STATUS_FAILED; + } +#endif + } + + if ((!pZip->m_pState->m_pMem) && (!pUser_read_buf)) + pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); + + return status == TINFL_STATUS_DONE; +} + +mz_bool mz_zip_reader_extract_file_to_mem_no_alloc(mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size) +{ + mz_uint32 file_index; + if (!mz_zip_reader_locate_file_v2(pZip, pFilename, NULL, flags, &file_index)) + return MZ_FALSE; + return mz_zip_reader_extract_to_mem_no_alloc(pZip, file_index, pBuf, buf_size, flags, pUser_read_buf, user_read_buf_size); +} + +mz_bool mz_zip_reader_extract_to_mem(mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, mz_uint flags) +{ + return mz_zip_reader_extract_to_mem_no_alloc(pZip, file_index, pBuf, buf_size, flags, NULL, 0); +} + +mz_bool mz_zip_reader_extract_file_to_mem(mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, mz_uint flags) +{ + return mz_zip_reader_extract_file_to_mem_no_alloc(pZip, pFilename, pBuf, buf_size, flags, NULL, 0); +} + +void *mz_zip_reader_extract_to_heap(mz_zip_archive *pZip, mz_uint file_index, size_t *pSize, mz_uint flags) +{ + mz_uint64 comp_size, uncomp_size, alloc_size; + const mz_uint8 *p = mz_zip_get_cdh(pZip, file_index); + void *pBuf; + + if (pSize) + *pSize = 0; + + if (!p) + { + mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + return NULL; + } + + comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS); + uncomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS); + + alloc_size = (flags & MZ_ZIP_FLAG_COMPRESSED_DATA) ? comp_size : uncomp_size; + if (((sizeof(size_t) == sizeof(mz_uint32))) && (alloc_size > 0x7FFFFFFF)) + { + mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); + return NULL; + } + + if (NULL == (pBuf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)alloc_size))) + { + mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + return NULL; + } + + if (!mz_zip_reader_extract_to_mem(pZip, file_index, pBuf, (size_t)alloc_size, flags)) + { + pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); + return NULL; + } + + if (pSize) + *pSize = (size_t)alloc_size; + return pBuf; +} + +void *mz_zip_reader_extract_file_to_heap(mz_zip_archive *pZip, const char *pFilename, size_t *pSize, mz_uint flags) +{ + mz_uint32 file_index; + if (!mz_zip_reader_locate_file_v2(pZip, pFilename, NULL, flags, &file_index)) + { + if (pSize) + *pSize = 0; + return MZ_FALSE; + } + return mz_zip_reader_extract_to_heap(pZip, file_index, pSize, flags); +} + +mz_bool mz_zip_reader_extract_to_callback(mz_zip_archive *pZip, mz_uint file_index, mz_file_write_func pCallback, void *pOpaque, mz_uint flags) +{ + int status = TINFL_STATUS_DONE; + mz_uint file_crc32 = MZ_CRC32_INIT; + mz_uint64 read_buf_size, read_buf_ofs = 0, read_buf_avail, comp_remaining, out_buf_ofs = 0, cur_file_ofs; + mz_zip_archive_file_stat file_stat; + void *pRead_buf = NULL; + void *pWrite_buf = NULL; + mz_uint32 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; + mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32; + + if ((!pZip) || (!pZip->m_pState) || (!pCallback) || (!pZip->m_pRead)) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + + if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat)) + return MZ_FALSE; + + /* A directory or zero length file */ + if ((file_stat.m_is_directory) || (!file_stat.m_comp_size)) + return MZ_TRUE; + + /* Encryption and patch files are not supported. */ + if (file_stat.m_bit_flag & (MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_COMPRESSED_PATCH_FLAG)) + return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION); + + /* This function only supports decompressing stored and deflate. */ + if ((!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (file_stat.m_method != 0) && (file_stat.m_method != MZ_DEFLATED)) + return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_METHOD); + + /* Read and do some minimal validation of the local directory entry (this doesn't crack the zip64 stuff, which we already have from the central dir) */ + cur_file_ofs = file_stat.m_local_header_ofs; + if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE) + return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); + + if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + + cur_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS); + if ((cur_file_ofs + file_stat.m_comp_size) > pZip->m_archive_size) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + + /* Decompress the file either directly from memory or from a file input buffer. */ + if (pZip->m_pState->m_pMem) + { + pRead_buf = (mz_uint8 *)pZip->m_pState->m_pMem + cur_file_ofs; + read_buf_size = read_buf_avail = file_stat.m_comp_size; + comp_remaining = 0; + } + else + { + read_buf_size = MZ_MIN(file_stat.m_comp_size, (mz_uint64)MZ_ZIP_MAX_IO_BUF_SIZE); + if (NULL == (pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)read_buf_size))) + return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + + read_buf_avail = 0; + comp_remaining = file_stat.m_comp_size; + } + + if ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!file_stat.m_method)) + { + /* The file is stored or the caller has requested the compressed data. */ + if (pZip->m_pState->m_pMem) + { + if (((sizeof(size_t) == sizeof(mz_uint32))) && (file_stat.m_comp_size > MZ_UINT32_MAX)) + return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); + + if (pCallback(pOpaque, out_buf_ofs, pRead_buf, (size_t)file_stat.m_comp_size) != file_stat.m_comp_size) + { + mz_zip_set_error(pZip, MZ_ZIP_WRITE_CALLBACK_FAILED); + status = TINFL_STATUS_FAILED; + } + else if (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) + { +#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS + file_crc32 = (mz_uint32)mz_crc32(file_crc32, (const mz_uint8 *)pRead_buf, (size_t)file_stat.m_comp_size); +#endif + } + + cur_file_ofs += file_stat.m_comp_size; + out_buf_ofs += file_stat.m_comp_size; + comp_remaining = 0; + } + else + { + while (comp_remaining) + { + read_buf_avail = MZ_MIN(read_buf_size, comp_remaining); + if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail) + { + mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); + status = TINFL_STATUS_FAILED; + break; + } + +#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS + if (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) + { + file_crc32 = (mz_uint32)mz_crc32(file_crc32, (const mz_uint8 *)pRead_buf, (size_t)read_buf_avail); + } +#endif + + if (pCallback(pOpaque, out_buf_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail) + { + mz_zip_set_error(pZip, MZ_ZIP_WRITE_CALLBACK_FAILED); + status = TINFL_STATUS_FAILED; + break; + } + + cur_file_ofs += read_buf_avail; + out_buf_ofs += read_buf_avail; + comp_remaining -= read_buf_avail; + } + } + } + else + { + tinfl_decompressor inflator; + tinfl_init(&inflator); + + if (NULL == (pWrite_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, TINFL_LZ_DICT_SIZE))) + { + mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + status = TINFL_STATUS_FAILED; + } + else + { + do + { + mz_uint8 *pWrite_buf_cur = (mz_uint8 *)pWrite_buf + (out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1)); + size_t in_buf_size, out_buf_size = TINFL_LZ_DICT_SIZE - (out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1)); + if ((!read_buf_avail) && (!pZip->m_pState->m_pMem)) + { + read_buf_avail = MZ_MIN(read_buf_size, comp_remaining); + if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail) + { + mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); + status = TINFL_STATUS_FAILED; + break; + } + cur_file_ofs += read_buf_avail; + comp_remaining -= read_buf_avail; + read_buf_ofs = 0; + } + + in_buf_size = (size_t)read_buf_avail; + status = tinfl_decompress(&inflator, (const mz_uint8 *)pRead_buf + read_buf_ofs, &in_buf_size, (mz_uint8 *)pWrite_buf, pWrite_buf_cur, &out_buf_size, comp_remaining ? TINFL_FLAG_HAS_MORE_INPUT : 0); + read_buf_avail -= in_buf_size; + read_buf_ofs += in_buf_size; + + if (out_buf_size) + { + if (pCallback(pOpaque, out_buf_ofs, pWrite_buf_cur, out_buf_size) != out_buf_size) + { + mz_zip_set_error(pZip, MZ_ZIP_WRITE_CALLBACK_FAILED); + status = TINFL_STATUS_FAILED; + break; + } + +#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS + file_crc32 = (mz_uint32)mz_crc32(file_crc32, pWrite_buf_cur, out_buf_size); +#endif + if ((out_buf_ofs += out_buf_size) > file_stat.m_uncomp_size) + { + mz_zip_set_error(pZip, MZ_ZIP_DECOMPRESSION_FAILED); + status = TINFL_STATUS_FAILED; + break; + } + } + } while ((status == TINFL_STATUS_NEEDS_MORE_INPUT) || (status == TINFL_STATUS_HAS_MORE_OUTPUT)); + } + } + + if ((status == TINFL_STATUS_DONE) && (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA))) + { + /* Make sure the entire file was decompressed, and check its CRC. */ + if (out_buf_ofs != file_stat.m_uncomp_size) + { + mz_zip_set_error(pZip, MZ_ZIP_UNEXPECTED_DECOMPRESSED_SIZE); + status = TINFL_STATUS_FAILED; + } +#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS + else if (file_crc32 != file_stat.m_crc32) + { + mz_zip_set_error(pZip, MZ_ZIP_DECOMPRESSION_FAILED); + status = TINFL_STATUS_FAILED; + } +#endif + } + + if (!pZip->m_pState->m_pMem) + pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); + + if (pWrite_buf) + pZip->m_pFree(pZip->m_pAlloc_opaque, pWrite_buf); + + return status == TINFL_STATUS_DONE; +} + +mz_bool mz_zip_reader_extract_file_to_callback(mz_zip_archive *pZip, const char *pFilename, mz_file_write_func pCallback, void *pOpaque, mz_uint flags) +{ + mz_uint32 file_index; + if (!mz_zip_reader_locate_file_v2(pZip, pFilename, NULL, flags, &file_index)) + return MZ_FALSE; + + return mz_zip_reader_extract_to_callback(pZip, file_index, pCallback, pOpaque, flags); +} + +mz_zip_reader_extract_iter_state* mz_zip_reader_extract_iter_new(mz_zip_archive *pZip, mz_uint file_index, mz_uint flags) +{ + mz_zip_reader_extract_iter_state *pState; + mz_uint32 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; + mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32; + + /* Argument sanity check */ + if ((!pZip) || (!pZip->m_pState)) + return NULL; + + /* Allocate an iterator status structure */ + pState = (mz_zip_reader_extract_iter_state*)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(mz_zip_reader_extract_iter_state)); + if (!pState) + { + mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + return NULL; + } + + /* Fetch file details */ + if (!mz_zip_reader_file_stat(pZip, file_index, &pState->file_stat)) + { + pZip->m_pFree(pZip->m_pAlloc_opaque, pState); + return NULL; + } + + /* Encryption and patch files are not supported. */ + if (pState->file_stat.m_bit_flag & (MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_COMPRESSED_PATCH_FLAG)) + { + mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION); + pZip->m_pFree(pZip->m_pAlloc_opaque, pState); + return NULL; + } + + /* This function only supports decompressing stored and deflate. */ + if ((!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (pState->file_stat.m_method != 0) && (pState->file_stat.m_method != MZ_DEFLATED)) + { + mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_METHOD); + pZip->m_pFree(pZip->m_pAlloc_opaque, pState); + return NULL; + } + + /* Init state - save args */ + pState->pZip = pZip; + pState->flags = flags; + + /* Init state - reset variables to defaults */ + pState->status = TINFL_STATUS_DONE; +#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS + pState->file_crc32 = MZ_CRC32_INIT; +#endif + pState->read_buf_ofs = 0; + pState->out_buf_ofs = 0; + pState->pRead_buf = NULL; + pState->pWrite_buf = NULL; + pState->out_blk_remain = 0; + + /* Read and parse the local directory entry. */ + pState->cur_file_ofs = pState->file_stat.m_local_header_ofs; + if (pZip->m_pRead(pZip->m_pIO_opaque, pState->cur_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE) + { + mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); + pZip->m_pFree(pZip->m_pAlloc_opaque, pState); + return NULL; + } + + if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG) + { + mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + pZip->m_pFree(pZip->m_pAlloc_opaque, pState); + return NULL; + } + + pState->cur_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS); + if ((pState->cur_file_ofs + pState->file_stat.m_comp_size) > pZip->m_archive_size) + { + mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + pZip->m_pFree(pZip->m_pAlloc_opaque, pState); + return NULL; + } + + /* Decompress the file either directly from memory or from a file input buffer. */ + if (pZip->m_pState->m_pMem) + { + pState->pRead_buf = (mz_uint8 *)pZip->m_pState->m_pMem + pState->cur_file_ofs; + pState->read_buf_size = pState->read_buf_avail = pState->file_stat.m_comp_size; + pState->comp_remaining = pState->file_stat.m_comp_size; + } + else + { + if (!((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!pState->file_stat.m_method))) + { + /* Decompression required, therefore intermediate read buffer required */ + pState->read_buf_size = MZ_MIN(pState->file_stat.m_comp_size, MZ_ZIP_MAX_IO_BUF_SIZE); + if (NULL == (pState->pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)pState->read_buf_size))) + { + mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + pZip->m_pFree(pZip->m_pAlloc_opaque, pState); + return NULL; + } + } + else + { + /* Decompression not required - we will be reading directly into user buffer, no temp buf required */ + pState->read_buf_size = 0; + } + pState->read_buf_avail = 0; + pState->comp_remaining = pState->file_stat.m_comp_size; + } + + if (!((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!pState->file_stat.m_method))) + { + /* Decompression required, init decompressor */ + tinfl_init( &pState->inflator ); + + /* Allocate write buffer */ + if (NULL == (pState->pWrite_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, TINFL_LZ_DICT_SIZE))) + { + mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + if (pState->pRead_buf) + pZip->m_pFree(pZip->m_pAlloc_opaque, pState->pRead_buf); + pZip->m_pFree(pZip->m_pAlloc_opaque, pState); + return NULL; + } + } + + return pState; +} + +mz_zip_reader_extract_iter_state* mz_zip_reader_extract_file_iter_new(mz_zip_archive *pZip, const char *pFilename, mz_uint flags) +{ + mz_uint32 file_index; + + /* Locate file index by name */ + if (!mz_zip_reader_locate_file_v2(pZip, pFilename, NULL, flags, &file_index)) + return NULL; + + /* Construct iterator */ + return mz_zip_reader_extract_iter_new(pZip, file_index, flags); +} + +size_t mz_zip_reader_extract_iter_read(mz_zip_reader_extract_iter_state* pState, void* pvBuf, size_t buf_size) +{ + size_t copied_to_caller = 0; + + /* Argument sanity check */ + if ((!pState) || (!pState->pZip) || (!pState->pZip->m_pState) || (!pvBuf)) + return 0; + + if ((pState->flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!pState->file_stat.m_method)) + { + /* The file is stored or the caller has requested the compressed data, calc amount to return. */ + copied_to_caller = (size_t)MZ_MIN( buf_size, pState->comp_remaining ); + + /* Zip is in memory....or requires reading from a file? */ + if (pState->pZip->m_pState->m_pMem) + { + /* Copy data to caller's buffer */ + memcpy( pvBuf, pState->pRead_buf, copied_to_caller ); + pState->pRead_buf = ((mz_uint8*)pState->pRead_buf) + copied_to_caller; + } + else + { + /* Read directly into caller's buffer */ + if (pState->pZip->m_pRead(pState->pZip->m_pIO_opaque, pState->cur_file_ofs, pvBuf, copied_to_caller) != copied_to_caller) + { + /* Failed to read all that was asked for, flag failure and alert user */ + mz_zip_set_error(pState->pZip, MZ_ZIP_FILE_READ_FAILED); + pState->status = TINFL_STATUS_FAILED; + copied_to_caller = 0; + } + } + +#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS + /* Compute CRC if not returning compressed data only */ + if (!(pState->flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) + pState->file_crc32 = (mz_uint32)mz_crc32(pState->file_crc32, (const mz_uint8 *)pvBuf, copied_to_caller); +#endif + + /* Advance offsets, dec counters */ + pState->cur_file_ofs += copied_to_caller; + pState->out_buf_ofs += copied_to_caller; + pState->comp_remaining -= copied_to_caller; + } + else + { + do + { + /* Calc ptr to write buffer - given current output pos and block size */ + mz_uint8 *pWrite_buf_cur = (mz_uint8 *)pState->pWrite_buf + (pState->out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1)); + + /* Calc max output size - given current output pos and block size */ + size_t in_buf_size, out_buf_size = TINFL_LZ_DICT_SIZE - (pState->out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1)); + + if (!pState->out_blk_remain) + { + /* Read more data from file if none available (and reading from file) */ + if ((!pState->read_buf_avail) && (!pState->pZip->m_pState->m_pMem)) + { + /* Calc read size */ + pState->read_buf_avail = MZ_MIN(pState->read_buf_size, pState->comp_remaining); + if (pState->pZip->m_pRead(pState->pZip->m_pIO_opaque, pState->cur_file_ofs, pState->pRead_buf, (size_t)pState->read_buf_avail) != pState->read_buf_avail) + { + mz_zip_set_error(pState->pZip, MZ_ZIP_FILE_READ_FAILED); + pState->status = TINFL_STATUS_FAILED; + break; + } + + /* Advance offsets, dec counters */ + pState->cur_file_ofs += pState->read_buf_avail; + pState->comp_remaining -= pState->read_buf_avail; + pState->read_buf_ofs = 0; + } + + /* Perform decompression */ + in_buf_size = (size_t)pState->read_buf_avail; + pState->status = tinfl_decompress(&pState->inflator, (const mz_uint8 *)pState->pRead_buf + pState->read_buf_ofs, &in_buf_size, (mz_uint8 *)pState->pWrite_buf, pWrite_buf_cur, &out_buf_size, pState->comp_remaining ? TINFL_FLAG_HAS_MORE_INPUT : 0); + pState->read_buf_avail -= in_buf_size; + pState->read_buf_ofs += in_buf_size; + + /* Update current output block size remaining */ + pState->out_blk_remain = out_buf_size; + } + + if (pState->out_blk_remain) + { + /* Calc amount to return. */ + size_t to_copy = MZ_MIN( (buf_size - copied_to_caller), pState->out_blk_remain ); + + /* Copy data to caller's buffer */ + memcpy( (uint8_t*)pvBuf + copied_to_caller, pWrite_buf_cur, to_copy ); + +#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS + /* Perform CRC */ + pState->file_crc32 = (mz_uint32)mz_crc32(pState->file_crc32, pWrite_buf_cur, to_copy); +#endif + + /* Decrement data consumed from block */ + pState->out_blk_remain -= to_copy; + + /* Inc output offset, while performing sanity check */ + if ((pState->out_buf_ofs += to_copy) > pState->file_stat.m_uncomp_size) + { + mz_zip_set_error(pState->pZip, MZ_ZIP_DECOMPRESSION_FAILED); + pState->status = TINFL_STATUS_FAILED; + break; + } + + /* Increment counter of data copied to caller */ + copied_to_caller += to_copy; + } + } while ( (copied_to_caller < buf_size) && ((pState->status == TINFL_STATUS_NEEDS_MORE_INPUT) || (pState->status == TINFL_STATUS_HAS_MORE_OUTPUT)) ); + } + + /* Return how many bytes were copied into user buffer */ + return copied_to_caller; +} + +mz_bool mz_zip_reader_extract_iter_free(mz_zip_reader_extract_iter_state* pState) +{ + int status; + + /* Argument sanity check */ + if ((!pState) || (!pState->pZip) || (!pState->pZip->m_pState)) + return MZ_FALSE; + + /* Was decompression completed and requested? */ + if ((pState->status == TINFL_STATUS_DONE) && (!(pState->flags & MZ_ZIP_FLAG_COMPRESSED_DATA))) + { + /* Make sure the entire file was decompressed, and check its CRC. */ + if (pState->out_buf_ofs != pState->file_stat.m_uncomp_size) + { + mz_zip_set_error(pState->pZip, MZ_ZIP_UNEXPECTED_DECOMPRESSED_SIZE); + pState->status = TINFL_STATUS_FAILED; + } +#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS + else if (pState->file_crc32 != pState->file_stat.m_crc32) + { + mz_zip_set_error(pState->pZip, MZ_ZIP_DECOMPRESSION_FAILED); + pState->status = TINFL_STATUS_FAILED; + } +#endif + } + + /* Free buffers */ + if (!pState->pZip->m_pState->m_pMem) + pState->pZip->m_pFree(pState->pZip->m_pAlloc_opaque, pState->pRead_buf); + if (pState->pWrite_buf) + pState->pZip->m_pFree(pState->pZip->m_pAlloc_opaque, pState->pWrite_buf); + + /* Save status */ + status = pState->status; + + /* Free context */ + pState->pZip->m_pFree(pState->pZip->m_pAlloc_opaque, pState); + + return status == TINFL_STATUS_DONE; +} + +#ifndef MINIZ_NO_STDIO +static size_t mz_zip_file_write_callback(void *pOpaque, mz_uint64 ofs, const void *pBuf, size_t n) +{ + (void)ofs; + + return MZ_FWRITE(pBuf, 1, n, (MZ_FILE *)pOpaque); +} + +mz_bool mz_zip_reader_extract_to_file(mz_zip_archive *pZip, mz_uint file_index, const char *pDst_filename, mz_uint flags) +{ + mz_bool status; + mz_zip_archive_file_stat file_stat; + MZ_FILE *pFile; + + if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat)) + return MZ_FALSE; + + if ((file_stat.m_is_directory) || (!file_stat.m_is_supported)) + return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_FEATURE); + + pFile = MZ_FOPEN(pDst_filename, "wb"); + if (!pFile) + return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED); + + status = mz_zip_reader_extract_to_callback(pZip, file_index, mz_zip_file_write_callback, pFile, flags); + + if (MZ_FCLOSE(pFile) == EOF) + { + if (status) + mz_zip_set_error(pZip, MZ_ZIP_FILE_CLOSE_FAILED); + + status = MZ_FALSE; + } + +#if !defined(MINIZ_NO_TIME) && !defined(MINIZ_NO_STDIO) + if (status) + mz_zip_set_file_times(pDst_filename, file_stat.m_time, file_stat.m_time); +#endif + + return status; +} + +mz_bool mz_zip_reader_extract_file_to_file(mz_zip_archive *pZip, const char *pArchive_filename, const char *pDst_filename, mz_uint flags) +{ + mz_uint32 file_index; + if (!mz_zip_reader_locate_file_v2(pZip, pArchive_filename, NULL, flags, &file_index)) + return MZ_FALSE; + + return mz_zip_reader_extract_to_file(pZip, file_index, pDst_filename, flags); +} + +mz_bool mz_zip_reader_extract_to_cfile(mz_zip_archive *pZip, mz_uint file_index, MZ_FILE *pFile, mz_uint flags) +{ + mz_zip_archive_file_stat file_stat; + + if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat)) + return MZ_FALSE; + + if ((file_stat.m_is_directory) || (!file_stat.m_is_supported)) + return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_FEATURE); + + return mz_zip_reader_extract_to_callback(pZip, file_index, mz_zip_file_write_callback, pFile, flags); +} + +mz_bool mz_zip_reader_extract_file_to_cfile(mz_zip_archive *pZip, const char *pArchive_filename, MZ_FILE *pFile, mz_uint flags) +{ + mz_uint32 file_index; + if (!mz_zip_reader_locate_file_v2(pZip, pArchive_filename, NULL, flags, &file_index)) + return MZ_FALSE; + + return mz_zip_reader_extract_to_cfile(pZip, file_index, pFile, flags); +} +#endif /* #ifndef MINIZ_NO_STDIO */ + +static size_t mz_zip_compute_crc32_callback(void *pOpaque, mz_uint64 file_ofs, const void *pBuf, size_t n) +{ + mz_uint32 *p = (mz_uint32 *)pOpaque; + (void)file_ofs; + *p = (mz_uint32)mz_crc32(*p, (const mz_uint8 *)pBuf, n); + return n; +} + +mz_bool mz_zip_validate_file(mz_zip_archive *pZip, mz_uint file_index, mz_uint flags) +{ + mz_zip_archive_file_stat file_stat; + mz_zip_internal_state *pState; + const mz_uint8 *pCentral_dir_header; + mz_bool found_zip64_ext_data_in_cdir = MZ_FALSE; + mz_bool found_zip64_ext_data_in_ldir = MZ_FALSE; + mz_uint32 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; + mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32; + mz_uint64 local_header_ofs = 0; + mz_uint32 local_header_filename_len, local_header_extra_len, local_header_crc32; + mz_uint64 local_header_comp_size, local_header_uncomp_size; + mz_uint32 uncomp_crc32 = MZ_CRC32_INIT; + mz_bool has_data_descriptor; + mz_uint32 local_header_bit_flags; + + mz_zip_array file_data_array; + mz_zip_array_init(&file_data_array, 1); + + if ((!pZip) || (!pZip->m_pState) || (!pZip->m_pAlloc) || (!pZip->m_pFree) || (!pZip->m_pRead)) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + + if (file_index > pZip->m_total_files) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + + pState = pZip->m_pState; + + pCentral_dir_header = mz_zip_get_cdh(pZip, file_index); + + if (!mz_zip_file_stat_internal(pZip, file_index, pCentral_dir_header, &file_stat, &found_zip64_ext_data_in_cdir)) + return MZ_FALSE; + + /* A directory or zero length file */ + if ((file_stat.m_is_directory) || (!file_stat.m_uncomp_size)) + return MZ_TRUE; + + /* Encryption and patch files are not supported. */ + if (file_stat.m_is_encrypted) + return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION); + + /* This function only supports stored and deflate. */ + if ((file_stat.m_method != 0) && (file_stat.m_method != MZ_DEFLATED)) + return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_METHOD); + + if (!file_stat.m_is_supported) + return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_FEATURE); + + /* Read and parse the local directory entry. */ + local_header_ofs = file_stat.m_local_header_ofs; + if (pZip->m_pRead(pZip->m_pIO_opaque, local_header_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE) + return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); + + if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + + local_header_filename_len = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS); + local_header_extra_len = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS); + local_header_comp_size = MZ_READ_LE32(pLocal_header + MZ_ZIP_LDH_COMPRESSED_SIZE_OFS); + local_header_uncomp_size = MZ_READ_LE32(pLocal_header + MZ_ZIP_LDH_DECOMPRESSED_SIZE_OFS); + local_header_crc32 = MZ_READ_LE32(pLocal_header + MZ_ZIP_LDH_CRC32_OFS); + local_header_bit_flags = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_BIT_FLAG_OFS); + has_data_descriptor = (local_header_bit_flags & 8) != 0; + + if (local_header_filename_len != strlen(file_stat.m_filename)) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + + if ((local_header_ofs + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + local_header_filename_len + local_header_extra_len + file_stat.m_comp_size) > pZip->m_archive_size) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + + if (!mz_zip_array_resize(pZip, &file_data_array, MZ_MAX(local_header_filename_len, local_header_extra_len), MZ_FALSE)) + return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + + if (local_header_filename_len) + { + if (pZip->m_pRead(pZip->m_pIO_opaque, local_header_ofs + MZ_ZIP_LOCAL_DIR_HEADER_SIZE, file_data_array.m_p, local_header_filename_len) != local_header_filename_len) + { + mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); + goto handle_failure; + } + + /* I've seen 1 archive that had the same pathname, but used backslashes in the local dir and forward slashes in the central dir. Do we care about this? For now, this case will fail validation. */ + if (memcmp(file_stat.m_filename, file_data_array.m_p, local_header_filename_len) != 0) + { + mz_zip_set_error(pZip, MZ_ZIP_VALIDATION_FAILED); + goto handle_failure; + } + } + + if ((local_header_extra_len) && ((local_header_comp_size == MZ_UINT32_MAX) || (local_header_uncomp_size == MZ_UINT32_MAX))) + { + mz_uint32 extra_size_remaining = local_header_extra_len; + const mz_uint8 *pExtra_data = (const mz_uint8 *)file_data_array.m_p; + + if (pZip->m_pRead(pZip->m_pIO_opaque, local_header_ofs + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + local_header_filename_len, file_data_array.m_p, local_header_extra_len) != local_header_extra_len) + { + mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); + goto handle_failure; + } + + do + { + mz_uint32 field_id, field_data_size, field_total_size; + + if (extra_size_remaining < (sizeof(mz_uint16) * 2)) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + + field_id = MZ_READ_LE16(pExtra_data); + field_data_size = MZ_READ_LE16(pExtra_data + sizeof(mz_uint16)); + field_total_size = field_data_size + sizeof(mz_uint16) * 2; + + if (field_total_size > extra_size_remaining) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + + if (field_id == MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID) + { + const mz_uint8 *pSrc_field_data = pExtra_data + sizeof(mz_uint32); + + if (field_data_size < sizeof(mz_uint64) * 2) + { + mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + goto handle_failure; + } + + local_header_uncomp_size = MZ_READ_LE64(pSrc_field_data); + local_header_comp_size = MZ_READ_LE64(pSrc_field_data + sizeof(mz_uint64)); + + found_zip64_ext_data_in_ldir = MZ_TRUE; + break; + } + + pExtra_data += field_total_size; + extra_size_remaining -= field_total_size; + } while (extra_size_remaining); + } + + /* TODO: parse local header extra data when local_header_comp_size is 0xFFFFFFFF! (big_descriptor.zip) */ + /* I've seen zips in the wild with the data descriptor bit set, but proper local header values and bogus data descriptors */ + if ((has_data_descriptor) && (!local_header_comp_size) && (!local_header_crc32)) + { + mz_uint8 descriptor_buf[32]; + mz_bool has_id; + const mz_uint8 *pSrc; + mz_uint32 file_crc32; + mz_uint64 comp_size = 0, uncomp_size = 0; + + mz_uint32 num_descriptor_uint32s = ((pState->m_zip64) || (found_zip64_ext_data_in_ldir)) ? 6 : 4; + + if (pZip->m_pRead(pZip->m_pIO_opaque, local_header_ofs + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + local_header_filename_len + local_header_extra_len + file_stat.m_comp_size, descriptor_buf, sizeof(mz_uint32) * num_descriptor_uint32s) != (sizeof(mz_uint32) * num_descriptor_uint32s)) + { + mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); + goto handle_failure; + } + + has_id = (MZ_READ_LE32(descriptor_buf) == MZ_ZIP_DATA_DESCRIPTOR_ID); + pSrc = has_id ? (descriptor_buf + sizeof(mz_uint32)) : descriptor_buf; + + file_crc32 = MZ_READ_LE32(pSrc); + + if ((pState->m_zip64) || (found_zip64_ext_data_in_ldir)) + { + comp_size = MZ_READ_LE64(pSrc + sizeof(mz_uint32)); + uncomp_size = MZ_READ_LE64(pSrc + sizeof(mz_uint32) + sizeof(mz_uint64)); + } + else + { + comp_size = MZ_READ_LE32(pSrc + sizeof(mz_uint32)); + uncomp_size = MZ_READ_LE32(pSrc + sizeof(mz_uint32) + sizeof(mz_uint32)); + } + + if ((file_crc32 != file_stat.m_crc32) || (comp_size != file_stat.m_comp_size) || (uncomp_size != file_stat.m_uncomp_size)) + { + mz_zip_set_error(pZip, MZ_ZIP_VALIDATION_FAILED); + goto handle_failure; + } + } + else + { + if ((local_header_crc32 != file_stat.m_crc32) || (local_header_comp_size != file_stat.m_comp_size) || (local_header_uncomp_size != file_stat.m_uncomp_size)) + { + mz_zip_set_error(pZip, MZ_ZIP_VALIDATION_FAILED); + goto handle_failure; + } + } + + mz_zip_array_clear(pZip, &file_data_array); + + if ((flags & MZ_ZIP_FLAG_VALIDATE_HEADERS_ONLY) == 0) + { + if (!mz_zip_reader_extract_to_callback(pZip, file_index, mz_zip_compute_crc32_callback, &uncomp_crc32, 0)) + return MZ_FALSE; + + /* 1 more check to be sure, although the extract checks too. */ + if (uncomp_crc32 != file_stat.m_crc32) + { + mz_zip_set_error(pZip, MZ_ZIP_VALIDATION_FAILED); + return MZ_FALSE; + } + } + + return MZ_TRUE; + +handle_failure: + mz_zip_array_clear(pZip, &file_data_array); + return MZ_FALSE; +} + +mz_bool mz_zip_validate_archive(mz_zip_archive *pZip, mz_uint flags) +{ + mz_zip_internal_state *pState; + uint32_t i; + + if ((!pZip) || (!pZip->m_pState) || (!pZip->m_pAlloc) || (!pZip->m_pFree) || (!pZip->m_pRead)) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + + pState = pZip->m_pState; + + /* Basic sanity checks */ + if (!pState->m_zip64) + { + if (pZip->m_total_files > MZ_UINT16_MAX) + return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); + + if (pZip->m_archive_size > MZ_UINT32_MAX) + return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); + } + else + { + if (pZip->m_total_files >= MZ_UINT32_MAX) + return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); + + if (pState->m_central_dir.m_size >= MZ_UINT32_MAX) + return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); + } + + for (i = 0; i < pZip->m_total_files; i++) + { + if (MZ_ZIP_FLAG_VALIDATE_LOCATE_FILE_FLAG & flags) + { + mz_uint32 found_index; + mz_zip_archive_file_stat stat; + + if (!mz_zip_reader_file_stat(pZip, i, &stat)) + return MZ_FALSE; + + if (!mz_zip_reader_locate_file_v2(pZip, stat.m_filename, NULL, 0, &found_index)) + return MZ_FALSE; + + /* This check can fail if there are duplicate filenames in the archive (which we don't check for when writing - that's up to the user) */ + if (found_index != i) + return mz_zip_set_error(pZip, MZ_ZIP_VALIDATION_FAILED); + } + + if (!mz_zip_validate_file(pZip, i, flags)) + return MZ_FALSE; + } + + return MZ_TRUE; +} + +mz_bool mz_zip_validate_mem_archive(const void *pMem, size_t size, mz_uint flags, mz_zip_error *pErr) +{ + mz_bool success = MZ_TRUE; + mz_zip_archive zip; + mz_zip_error actual_err = MZ_ZIP_NO_ERROR; + + if ((!pMem) || (!size)) + { + if (pErr) + *pErr = MZ_ZIP_INVALID_PARAMETER; + return MZ_FALSE; + } + + mz_zip_zero_struct(&zip); + + if (!mz_zip_reader_init_mem(&zip, pMem, size, flags)) + { + if (pErr) + *pErr = zip.m_last_error; + return MZ_FALSE; + } + + if (!mz_zip_validate_archive(&zip, flags)) + { + actual_err = zip.m_last_error; + success = MZ_FALSE; + } + + if (!mz_zip_reader_end_internal(&zip, success)) + { + if (!actual_err) + actual_err = zip.m_last_error; + success = MZ_FALSE; + } + + if (pErr) + *pErr = actual_err; + + return success; +} + +#ifndef MINIZ_NO_STDIO +mz_bool mz_zip_validate_file_archive(const char *pFilename, mz_uint flags, mz_zip_error *pErr) +{ + mz_bool success = MZ_TRUE; + mz_zip_archive zip; + mz_zip_error actual_err = MZ_ZIP_NO_ERROR; + + if (!pFilename) + { + if (pErr) + *pErr = MZ_ZIP_INVALID_PARAMETER; + return MZ_FALSE; + } + + mz_zip_zero_struct(&zip); + + if (!mz_zip_reader_init_file_v2(&zip, pFilename, flags, 0, 0)) + { + if (pErr) + *pErr = zip.m_last_error; + return MZ_FALSE; + } + + if (!mz_zip_validate_archive(&zip, flags)) + { + actual_err = zip.m_last_error; + success = MZ_FALSE; + } + + if (!mz_zip_reader_end_internal(&zip, success)) + { + if (!actual_err) + actual_err = zip.m_last_error; + success = MZ_FALSE; + } + + if (pErr) + *pErr = actual_err; + + return success; +} +#endif /* #ifndef MINIZ_NO_STDIO */ + +/* ------------------- .ZIP archive writing */ + +#ifndef MINIZ_NO_ARCHIVE_WRITING_APIS + +static MZ_FORCEINLINE void mz_write_le16(mz_uint8 *p, mz_uint16 v) +{ + p[0] = (mz_uint8)v; + p[1] = (mz_uint8)(v >> 8); +} +static MZ_FORCEINLINE void mz_write_le32(mz_uint8 *p, mz_uint32 v) +{ + p[0] = (mz_uint8)v; + p[1] = (mz_uint8)(v >> 8); + p[2] = (mz_uint8)(v >> 16); + p[3] = (mz_uint8)(v >> 24); +} +static MZ_FORCEINLINE void mz_write_le64(mz_uint8 *p, mz_uint64 v) +{ + mz_write_le32(p, (mz_uint32)v); + mz_write_le32(p + sizeof(mz_uint32), (mz_uint32)(v >> 32)); +} + +#define MZ_WRITE_LE16(p, v) mz_write_le16((mz_uint8 *)(p), (mz_uint16)(v)) +#define MZ_WRITE_LE32(p, v) mz_write_le32((mz_uint8 *)(p), (mz_uint32)(v)) +#define MZ_WRITE_LE64(p, v) mz_write_le64((mz_uint8 *)(p), (mz_uint64)(v)) + +static size_t mz_zip_heap_write_func(void *pOpaque, mz_uint64 file_ofs, const void *pBuf, size_t n) +{ + mz_zip_archive *pZip = (mz_zip_archive *)pOpaque; + mz_zip_internal_state *pState = pZip->m_pState; + mz_uint64 new_size = MZ_MAX(file_ofs + n, pState->m_mem_size); + + if (!n) + return 0; + + /* An allocation this big is likely to just fail on 32-bit systems, so don't even go there. */ + if ((sizeof(size_t) == sizeof(mz_uint32)) && (new_size > 0x7FFFFFFF)) + { + mz_zip_set_error(pZip, MZ_ZIP_FILE_TOO_LARGE); + return 0; + } + + if (new_size > pState->m_mem_capacity) + { + void *pNew_block; + size_t new_capacity = MZ_MAX(64, pState->m_mem_capacity); + + while (new_capacity < new_size) + new_capacity *= 2; + + if (NULL == (pNew_block = pZip->m_pRealloc(pZip->m_pAlloc_opaque, pState->m_pMem, 1, new_capacity))) + { + mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + return 0; + } + + pState->m_pMem = pNew_block; + pState->m_mem_capacity = new_capacity; + } + memcpy((mz_uint8 *)pState->m_pMem + file_ofs, pBuf, n); + pState->m_mem_size = (size_t)new_size; + return n; +} + +static mz_bool mz_zip_writer_end_internal(mz_zip_archive *pZip, mz_bool set_last_error) +{ + mz_zip_internal_state *pState; + mz_bool status = MZ_TRUE; + + if ((!pZip) || (!pZip->m_pState) || (!pZip->m_pAlloc) || (!pZip->m_pFree) || ((pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) && (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED))) + { + if (set_last_error) + mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + return MZ_FALSE; + } + + pState = pZip->m_pState; + pZip->m_pState = NULL; + mz_zip_array_clear(pZip, &pState->m_central_dir); + mz_zip_array_clear(pZip, &pState->m_central_dir_offsets); + mz_zip_array_clear(pZip, &pState->m_sorted_central_dir_offsets); + +#ifndef MINIZ_NO_STDIO + if (pState->m_pFile) + { + if (pZip->m_zip_type == MZ_ZIP_TYPE_FILE) + { + if (MZ_FCLOSE(pState->m_pFile) == EOF) + { + if (set_last_error) + mz_zip_set_error(pZip, MZ_ZIP_FILE_CLOSE_FAILED); + status = MZ_FALSE; + } + } + + pState->m_pFile = NULL; + } +#endif /* #ifndef MINIZ_NO_STDIO */ + + if ((pZip->m_pWrite == mz_zip_heap_write_func) && (pState->m_pMem)) + { + pZip->m_pFree(pZip->m_pAlloc_opaque, pState->m_pMem); + pState->m_pMem = NULL; + } + + pZip->m_pFree(pZip->m_pAlloc_opaque, pState); + pZip->m_zip_mode = MZ_ZIP_MODE_INVALID; + return status; +} + +mz_bool mz_zip_writer_init_v2(mz_zip_archive *pZip, mz_uint64 existing_size, mz_uint flags) +{ + mz_bool zip64 = (flags & MZ_ZIP_FLAG_WRITE_ZIP64) != 0; + + if ((!pZip) || (pZip->m_pState) || (!pZip->m_pWrite) || (pZip->m_zip_mode != MZ_ZIP_MODE_INVALID)) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + + if (flags & MZ_ZIP_FLAG_WRITE_ALLOW_READING) + { + if (!pZip->m_pRead) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + } + + if (pZip->m_file_offset_alignment) + { + /* Ensure user specified file offset alignment is a power of 2. */ + if (pZip->m_file_offset_alignment & (pZip->m_file_offset_alignment - 1)) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + } + + if (!pZip->m_pAlloc) + pZip->m_pAlloc = miniz_def_alloc_func; + if (!pZip->m_pFree) + pZip->m_pFree = miniz_def_free_func; + if (!pZip->m_pRealloc) + pZip->m_pRealloc = miniz_def_realloc_func; + + pZip->m_archive_size = existing_size; + pZip->m_central_directory_file_ofs = 0; + pZip->m_total_files = 0; + + if (NULL == (pZip->m_pState = (mz_zip_internal_state *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(mz_zip_internal_state)))) + return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + + memset(pZip->m_pState, 0, sizeof(mz_zip_internal_state)); + + MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir, sizeof(mz_uint8)); + MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir_offsets, sizeof(mz_uint32)); + MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_sorted_central_dir_offsets, sizeof(mz_uint32)); + + pZip->m_pState->m_zip64 = zip64; + pZip->m_pState->m_zip64_has_extended_info_fields = zip64; + + pZip->m_zip_type = MZ_ZIP_TYPE_USER; + pZip->m_zip_mode = MZ_ZIP_MODE_WRITING; + + return MZ_TRUE; +} + +mz_bool mz_zip_writer_init(mz_zip_archive *pZip, mz_uint64 existing_size) +{ + return mz_zip_writer_init_v2(pZip, existing_size, 0); +} + +mz_bool mz_zip_writer_init_heap_v2(mz_zip_archive *pZip, size_t size_to_reserve_at_beginning, size_t initial_allocation_size, mz_uint flags) +{ + pZip->m_pWrite = mz_zip_heap_write_func; + pZip->m_pNeeds_keepalive = NULL; + + if (flags & MZ_ZIP_FLAG_WRITE_ALLOW_READING) + pZip->m_pRead = mz_zip_mem_read_func; + + pZip->m_pIO_opaque = pZip; + + if (!mz_zip_writer_init_v2(pZip, size_to_reserve_at_beginning, flags)) + return MZ_FALSE; + + pZip->m_zip_type = MZ_ZIP_TYPE_HEAP; + + if (0 != (initial_allocation_size = MZ_MAX(initial_allocation_size, size_to_reserve_at_beginning))) + { + if (NULL == (pZip->m_pState->m_pMem = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, initial_allocation_size))) + { + mz_zip_writer_end_internal(pZip, MZ_FALSE); + return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + } + pZip->m_pState->m_mem_capacity = initial_allocation_size; + } + + return MZ_TRUE; +} + +mz_bool mz_zip_writer_init_heap(mz_zip_archive *pZip, size_t size_to_reserve_at_beginning, size_t initial_allocation_size) +{ + return mz_zip_writer_init_heap_v2(pZip, size_to_reserve_at_beginning, initial_allocation_size, 0); +} + +#ifndef MINIZ_NO_STDIO +static size_t mz_zip_file_write_func(void *pOpaque, mz_uint64 file_ofs, const void *pBuf, size_t n) +{ + mz_zip_archive *pZip = (mz_zip_archive *)pOpaque; + mz_int64 cur_ofs = MZ_FTELL64(pZip->m_pState->m_pFile); + + file_ofs += pZip->m_pState->m_file_archive_start_ofs; + + if (((mz_int64)file_ofs < 0) || (((cur_ofs != (mz_int64)file_ofs)) && (MZ_FSEEK64(pZip->m_pState->m_pFile, (mz_int64)file_ofs, SEEK_SET)))) + { + mz_zip_set_error(pZip, MZ_ZIP_FILE_SEEK_FAILED); + return 0; + } + + return MZ_FWRITE(pBuf, 1, n, pZip->m_pState->m_pFile); +} + +mz_bool mz_zip_writer_init_file(mz_zip_archive *pZip, const char *pFilename, mz_uint64 size_to_reserve_at_beginning) +{ + return mz_zip_writer_init_file_v2(pZip, pFilename, size_to_reserve_at_beginning, 0); +} + +mz_bool mz_zip_writer_init_file_v2(mz_zip_archive *pZip, const char *pFilename, mz_uint64 size_to_reserve_at_beginning, mz_uint flags) +{ + MZ_FILE *pFile; + + pZip->m_pWrite = mz_zip_file_write_func; + pZip->m_pNeeds_keepalive = NULL; + + if (flags & MZ_ZIP_FLAG_WRITE_ALLOW_READING) + pZip->m_pRead = mz_zip_file_read_func; + + pZip->m_pIO_opaque = pZip; + + if (!mz_zip_writer_init_v2(pZip, size_to_reserve_at_beginning, flags)) + return MZ_FALSE; + + if (NULL == (pFile = MZ_FOPEN(pFilename, (flags & MZ_ZIP_FLAG_WRITE_ALLOW_READING) ? "w+b" : "wb"))) + { + mz_zip_writer_end(pZip); + return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED); + } + + pZip->m_pState->m_pFile = pFile; + pZip->m_zip_type = MZ_ZIP_TYPE_FILE; + + if (size_to_reserve_at_beginning) + { + mz_uint64 cur_ofs = 0; + char buf[4096]; + + MZ_CLEAR_OBJ(buf); + + do + { + size_t n = (size_t)MZ_MIN(sizeof(buf), size_to_reserve_at_beginning); + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_ofs, buf, n) != n) + { + mz_zip_writer_end(pZip); + return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + } + cur_ofs += n; + size_to_reserve_at_beginning -= n; + } while (size_to_reserve_at_beginning); + } + + return MZ_TRUE; +} + +mz_bool mz_zip_writer_init_cfile(mz_zip_archive *pZip, MZ_FILE *pFile, mz_uint flags) +{ + pZip->m_pWrite = mz_zip_file_write_func; + pZip->m_pNeeds_keepalive = NULL; + + if (flags & MZ_ZIP_FLAG_WRITE_ALLOW_READING) + pZip->m_pRead = mz_zip_file_read_func; + + pZip->m_pIO_opaque = pZip; + + if (!mz_zip_writer_init_v2(pZip, 0, flags)) + return MZ_FALSE; + + pZip->m_pState->m_pFile = pFile; + pZip->m_pState->m_file_archive_start_ofs = MZ_FTELL64(pZip->m_pState->m_pFile); + pZip->m_zip_type = MZ_ZIP_TYPE_CFILE; + + return MZ_TRUE; +} +#endif /* #ifndef MINIZ_NO_STDIO */ + +mz_bool mz_zip_writer_init_from_reader_v2(mz_zip_archive *pZip, const char *pFilename, mz_uint flags) +{ + mz_zip_internal_state *pState; + + if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_READING)) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + + if (flags & MZ_ZIP_FLAG_WRITE_ZIP64) + { + /* We don't support converting a non-zip64 file to zip64 - this seems like more trouble than it's worth. (What about the existing 32-bit data descriptors that could follow the compressed data?) */ + if (!pZip->m_pState->m_zip64) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + } + + /* No sense in trying to write to an archive that's already at the support max size */ + if (pZip->m_pState->m_zip64) + { + if (pZip->m_total_files == MZ_UINT32_MAX) + return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); + } + else + { + if (pZip->m_total_files == MZ_UINT16_MAX) + return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); + + if ((pZip->m_archive_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + MZ_ZIP_LOCAL_DIR_HEADER_SIZE) > MZ_UINT32_MAX) + return mz_zip_set_error(pZip, MZ_ZIP_FILE_TOO_LARGE); + } + + pState = pZip->m_pState; + + if (pState->m_pFile) + { +#ifdef MINIZ_NO_STDIO + (void)pFilename; + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); +#else + if (pZip->m_pIO_opaque != pZip) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + + if (pZip->m_zip_type == MZ_ZIP_TYPE_FILE) + { + if (!pFilename) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + + /* Archive is being read from stdio and was originally opened only for reading. Try to reopen as writable. */ + if (NULL == (pState->m_pFile = MZ_FREOPEN(pFilename, "r+b", pState->m_pFile))) + { + /* The mz_zip_archive is now in a bogus state because pState->m_pFile is NULL, so just close it. */ + mz_zip_reader_end_internal(pZip, MZ_FALSE); + return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED); + } + } + + pZip->m_pWrite = mz_zip_file_write_func; + pZip->m_pNeeds_keepalive = NULL; +#endif /* #ifdef MINIZ_NO_STDIO */ + } + else if (pState->m_pMem) + { + /* Archive lives in a memory block. Assume it's from the heap that we can resize using the realloc callback. */ + if (pZip->m_pIO_opaque != pZip) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + + pState->m_mem_capacity = pState->m_mem_size; + pZip->m_pWrite = mz_zip_heap_write_func; + pZip->m_pNeeds_keepalive = NULL; + } + /* Archive is being read via a user provided read function - make sure the user has specified a write function too. */ + else if (!pZip->m_pWrite) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + + /* Start writing new files at the archive's current central directory location. */ + /* TODO: We could add a flag that lets the user start writing immediately AFTER the existing central dir - this would be safer. */ + pZip->m_archive_size = pZip->m_central_directory_file_ofs; + pZip->m_central_directory_file_ofs = 0; + + /* Clear the sorted central dir offsets, they aren't useful or maintained now. */ + /* Even though we're now in write mode, files can still be extracted and verified, but file locates will be slow. */ + /* TODO: We could easily maintain the sorted central directory offsets. */ + mz_zip_array_clear(pZip, &pZip->m_pState->m_sorted_central_dir_offsets); + + pZip->m_zip_mode = MZ_ZIP_MODE_WRITING; + + return MZ_TRUE; +} + +mz_bool mz_zip_writer_init_from_reader(mz_zip_archive *pZip, const char *pFilename) +{ + return mz_zip_writer_init_from_reader_v2(pZip, pFilename, 0); +} + +/* TODO: pArchive_name is a terrible name here! */ +mz_bool mz_zip_writer_add_mem(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, mz_uint level_and_flags) +{ + return mz_zip_writer_add_mem_ex(pZip, pArchive_name, pBuf, buf_size, NULL, 0, level_and_flags, 0, 0); +} + +typedef struct +{ + mz_zip_archive *m_pZip; + mz_uint64 m_cur_archive_file_ofs; + mz_uint64 m_comp_size; +} mz_zip_writer_add_state; + +static mz_bool mz_zip_writer_add_put_buf_callback(const void *pBuf, int len, void *pUser) +{ + mz_zip_writer_add_state *pState = (mz_zip_writer_add_state *)pUser; + if ((int)pState->m_pZip->m_pWrite(pState->m_pZip->m_pIO_opaque, pState->m_cur_archive_file_ofs, pBuf, len) != len) + return MZ_FALSE; + + pState->m_cur_archive_file_ofs += len; + pState->m_comp_size += len; + return MZ_TRUE; +} + +#define MZ_ZIP64_MAX_LOCAL_EXTRA_FIELD_SIZE (sizeof(mz_uint16) * 2 + sizeof(mz_uint64) * 2) +#define MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE (sizeof(mz_uint16) * 2 + sizeof(mz_uint64) * 3) +static mz_uint32 mz_zip_writer_create_zip64_extra_data(mz_uint8 *pBuf, mz_uint64 *pUncomp_size, mz_uint64 *pComp_size, mz_uint64 *pLocal_header_ofs) +{ + mz_uint8 *pDst = pBuf; + mz_uint32 field_size = 0; + + MZ_WRITE_LE16(pDst + 0, MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID); + MZ_WRITE_LE16(pDst + 2, 0); + pDst += sizeof(mz_uint16) * 2; + + if (pUncomp_size) + { + MZ_WRITE_LE64(pDst, *pUncomp_size); + pDst += sizeof(mz_uint64); + field_size += sizeof(mz_uint64); + } + + if (pComp_size) + { + MZ_WRITE_LE64(pDst, *pComp_size); + pDst += sizeof(mz_uint64); + field_size += sizeof(mz_uint64); + } + + if (pLocal_header_ofs) + { + MZ_WRITE_LE64(pDst, *pLocal_header_ofs); + pDst += sizeof(mz_uint64); + field_size += sizeof(mz_uint64); + } + + MZ_WRITE_LE16(pBuf + 2, field_size); + + return (mz_uint32)(pDst - pBuf); +} + +static mz_bool mz_zip_writer_create_local_dir_header(mz_zip_archive *pZip, mz_uint8 *pDst, mz_uint16 filename_size, mz_uint16 extra_size, mz_uint64 uncomp_size, mz_uint64 comp_size, mz_uint32 uncomp_crc32, mz_uint16 method, mz_uint16 bit_flags, mz_uint16 dos_time, mz_uint16 dos_date) +{ + (void)pZip; + memset(pDst, 0, MZ_ZIP_LOCAL_DIR_HEADER_SIZE); + MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_SIG_OFS, MZ_ZIP_LOCAL_DIR_HEADER_SIG); + MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_VERSION_NEEDED_OFS, method ? 20 : 0); + MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_BIT_FLAG_OFS, bit_flags); + MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_METHOD_OFS, method); + MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILE_TIME_OFS, dos_time); + MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILE_DATE_OFS, dos_date); + MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_CRC32_OFS, uncomp_crc32); + MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_COMPRESSED_SIZE_OFS, MZ_MIN(comp_size, MZ_UINT32_MAX)); + MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_DECOMPRESSED_SIZE_OFS, MZ_MIN(uncomp_size, MZ_UINT32_MAX)); + MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILENAME_LEN_OFS, filename_size); + MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_EXTRA_LEN_OFS, extra_size); + return MZ_TRUE; +} + +static mz_bool mz_zip_writer_create_central_dir_header(mz_zip_archive *pZip, mz_uint8 *pDst, + mz_uint16 filename_size, mz_uint16 extra_size, mz_uint16 comment_size, + mz_uint64 uncomp_size, mz_uint64 comp_size, mz_uint32 uncomp_crc32, + mz_uint16 method, mz_uint16 bit_flags, mz_uint16 dos_time, mz_uint16 dos_date, + mz_uint64 local_header_ofs, mz_uint32 ext_attributes) +{ + (void)pZip; + memset(pDst, 0, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE); + MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_SIG_OFS, MZ_ZIP_CENTRAL_DIR_HEADER_SIG); + MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_VERSION_NEEDED_OFS, method ? 20 : 0); + MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_BIT_FLAG_OFS, bit_flags); + MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_METHOD_OFS, method); + MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_FILE_TIME_OFS, dos_time); + MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_FILE_DATE_OFS, dos_date); + MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_CRC32_OFS, uncomp_crc32); + MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS, MZ_MIN(comp_size, MZ_UINT32_MAX)); + MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS, MZ_MIN(uncomp_size, MZ_UINT32_MAX)); + MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_FILENAME_LEN_OFS, filename_size); + MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_EXTRA_LEN_OFS, extra_size); + MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_COMMENT_LEN_OFS, comment_size); + MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS, ext_attributes); + MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_LOCAL_HEADER_OFS, MZ_MIN(local_header_ofs, MZ_UINT32_MAX)); + return MZ_TRUE; +} + +static mz_bool mz_zip_writer_add_to_central_dir(mz_zip_archive *pZip, const char *pFilename, mz_uint16 filename_size, + const void *pExtra, mz_uint16 extra_size, const void *pComment, mz_uint16 comment_size, + mz_uint64 uncomp_size, mz_uint64 comp_size, mz_uint32 uncomp_crc32, + mz_uint16 method, mz_uint16 bit_flags, mz_uint16 dos_time, mz_uint16 dos_date, + mz_uint64 local_header_ofs, mz_uint32 ext_attributes, + const char *user_extra_data, mz_uint user_extra_data_len) +{ + mz_zip_internal_state *pState = pZip->m_pState; + mz_uint32 central_dir_ofs = (mz_uint32)pState->m_central_dir.m_size; + size_t orig_central_dir_size = pState->m_central_dir.m_size; + mz_uint8 central_dir_header[MZ_ZIP_CENTRAL_DIR_HEADER_SIZE]; + + if (!pZip->m_pState->m_zip64) + { + if (local_header_ofs > 0xFFFFFFFF) + return mz_zip_set_error(pZip, MZ_ZIP_FILE_TOO_LARGE); + } + + /* miniz doesn't support central dirs >= MZ_UINT32_MAX bytes yet */ + if (((mz_uint64)pState->m_central_dir.m_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_size + extra_size + user_extra_data_len + comment_size) >= MZ_UINT32_MAX) + return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE); + + if (!mz_zip_writer_create_central_dir_header(pZip, central_dir_header, filename_size, (mz_uint16)(extra_size + user_extra_data_len), comment_size, uncomp_size, comp_size, uncomp_crc32, method, bit_flags, dos_time, dos_date, local_header_ofs, ext_attributes)) + return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); + + if ((!mz_zip_array_push_back(pZip, &pState->m_central_dir, central_dir_header, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE)) || + (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pFilename, filename_size)) || + (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pExtra, extra_size)) || + (!mz_zip_array_push_back(pZip, &pState->m_central_dir, user_extra_data, user_extra_data_len)) || + (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pComment, comment_size)) || + (!mz_zip_array_push_back(pZip, &pState->m_central_dir_offsets, ¢ral_dir_ofs, 1))) + { + /* Try to resize the central directory array back into its original state. */ + mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE); + return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + } + + return MZ_TRUE; +} + +static mz_bool mz_zip_writer_validate_archive_name(const char *pArchive_name) +{ + /* Basic ZIP archive filename validity checks: Valid filenames cannot start with a forward slash, cannot contain a drive letter, and cannot use DOS-style backward slashes. */ + if (*pArchive_name == '/') + return MZ_FALSE; + + /* Making sure the name does not contain drive letters or DOS style backward slashes is the responsibility of the program using miniz*/ + + return MZ_TRUE; +} + +static mz_uint mz_zip_writer_compute_padding_needed_for_file_alignment(mz_zip_archive *pZip) +{ + mz_uint32 n; + if (!pZip->m_file_offset_alignment) + return 0; + n = (mz_uint32)(pZip->m_archive_size & (pZip->m_file_offset_alignment - 1)); + return (mz_uint)((pZip->m_file_offset_alignment - n) & (pZip->m_file_offset_alignment - 1)); +} + +static mz_bool mz_zip_writer_write_zeros(mz_zip_archive *pZip, mz_uint64 cur_file_ofs, mz_uint32 n) +{ + char buf[4096]; + memset(buf, 0, MZ_MIN(sizeof(buf), n)); + while (n) + { + mz_uint32 s = MZ_MIN(sizeof(buf), n); + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_file_ofs, buf, s) != s) + return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + + cur_file_ofs += s; + n -= s; + } + return MZ_TRUE; +} + +mz_bool mz_zip_writer_add_mem_ex(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, + mz_uint64 uncomp_size, mz_uint32 uncomp_crc32) +{ + return mz_zip_writer_add_mem_ex_v2(pZip, pArchive_name, pBuf, buf_size, pComment, comment_size, level_and_flags, uncomp_size, uncomp_crc32, NULL, NULL, 0, NULL, 0); +} + +mz_bool mz_zip_writer_add_mem_ex_v2(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, + mz_uint level_and_flags, mz_uint64 uncomp_size, mz_uint32 uncomp_crc32, MZ_TIME_T *last_modified, + const char *user_extra_data, mz_uint user_extra_data_len, const char *user_extra_data_central, mz_uint user_extra_data_central_len) +{ + mz_uint16 method = 0, dos_time = 0, dos_date = 0; + mz_uint level, ext_attributes = 0, num_alignment_padding_bytes; + mz_uint64 local_dir_header_ofs = pZip->m_archive_size, cur_archive_file_ofs = pZip->m_archive_size, comp_size = 0; + size_t archive_name_size; + mz_uint8 local_dir_header[MZ_ZIP_LOCAL_DIR_HEADER_SIZE]; + tdefl_compressor *pComp = NULL; + mz_bool store_data_uncompressed; + mz_zip_internal_state *pState; + mz_uint8 *pExtra_data = NULL; + mz_uint32 extra_size = 0; + mz_uint8 extra_data[MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE]; + mz_uint16 bit_flags = 0; + + if ((int)level_and_flags < 0) + level_and_flags = MZ_DEFAULT_LEVEL; + + if (uncomp_size || (buf_size && !(level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA))) + bit_flags |= MZ_ZIP_LDH_BIT_FLAG_HAS_LOCATOR; + + if (!(level_and_flags & MZ_ZIP_FLAG_ASCII_FILENAME)) + bit_flags |= MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_UTF8; + + level = level_and_flags & 0xF; + store_data_uncompressed = ((!level) || (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)); + + if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) || ((buf_size) && (!pBuf)) || (!pArchive_name) || ((comment_size) && (!pComment)) || (level > MZ_UBER_COMPRESSION)) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + + pState = pZip->m_pState; + + if (pState->m_zip64) + { + if (pZip->m_total_files == MZ_UINT32_MAX) + return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); + } + else + { + if (pZip->m_total_files == MZ_UINT16_MAX) + { + pState->m_zip64 = MZ_TRUE; + /*return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); */ + } + if ((buf_size > 0xFFFFFFFF) || (uncomp_size > 0xFFFFFFFF)) + { + pState->m_zip64 = MZ_TRUE; + /*return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); */ + } + } + + if ((!(level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (uncomp_size)) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + + if (!mz_zip_writer_validate_archive_name(pArchive_name)) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_FILENAME); + +#ifndef MINIZ_NO_TIME + if (last_modified != NULL) + { + mz_zip_time_t_to_dos_time(*last_modified, &dos_time, &dos_date); + } + else + { + MZ_TIME_T cur_time; + time(&cur_time); + mz_zip_time_t_to_dos_time(cur_time, &dos_time, &dos_date); + } +#endif /* #ifndef MINIZ_NO_TIME */ + + if (!(level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) + { + uncomp_crc32 = (mz_uint32)mz_crc32(MZ_CRC32_INIT, (const mz_uint8 *)pBuf, buf_size); + uncomp_size = buf_size; + if (uncomp_size <= 3) + { + level = 0; + store_data_uncompressed = MZ_TRUE; + } + } + + archive_name_size = strlen(pArchive_name); + if (archive_name_size > MZ_UINT16_MAX) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_FILENAME); + + num_alignment_padding_bytes = mz_zip_writer_compute_padding_needed_for_file_alignment(pZip); + + /* miniz doesn't support central dirs >= MZ_UINT32_MAX bytes yet */ + if (((mz_uint64)pState->m_central_dir.m_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + archive_name_size + MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE + comment_size) >= MZ_UINT32_MAX) + return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE); + + if (!pState->m_zip64) + { + /* Bail early if the archive would obviously become too large */ + if ((pZip->m_archive_size + num_alignment_padding_bytes + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + archive_name_size + + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + archive_name_size + comment_size + user_extra_data_len + + pState->m_central_dir.m_size + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE + user_extra_data_central_len + + MZ_ZIP_DATA_DESCRIPTER_SIZE32) > 0xFFFFFFFF) + { + pState->m_zip64 = MZ_TRUE; + /*return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); */ + } + } + + if ((archive_name_size) && (pArchive_name[archive_name_size - 1] == '/')) + { + /* Set DOS Subdirectory attribute bit. */ + ext_attributes |= MZ_ZIP_DOS_DIR_ATTRIBUTE_BITFLAG; + + /* Subdirectories cannot contain data. */ + if ((buf_size) || (uncomp_size)) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + } + + /* Try to do any allocations before writing to the archive, so if an allocation fails the file remains unmodified. (A good idea if we're doing an in-place modification.) */ + if ((!mz_zip_array_ensure_room(pZip, &pState->m_central_dir, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + archive_name_size + comment_size + (pState->m_zip64 ? MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE : 0))) || (!mz_zip_array_ensure_room(pZip, &pState->m_central_dir_offsets, 1))) + return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + + if ((!store_data_uncompressed) && (buf_size)) + { + if (NULL == (pComp = (tdefl_compressor *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(tdefl_compressor)))) + return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + } + + if (!mz_zip_writer_write_zeros(pZip, cur_archive_file_ofs, num_alignment_padding_bytes)) + { + pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); + return MZ_FALSE; + } + + local_dir_header_ofs += num_alignment_padding_bytes; + if (pZip->m_file_offset_alignment) + { + MZ_ASSERT((local_dir_header_ofs & (pZip->m_file_offset_alignment - 1)) == 0); + } + cur_archive_file_ofs += num_alignment_padding_bytes; + + MZ_CLEAR_OBJ(local_dir_header); + + if (!store_data_uncompressed || (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) + { + method = MZ_DEFLATED; + } + + if (pState->m_zip64) + { + if (uncomp_size >= MZ_UINT32_MAX || local_dir_header_ofs >= MZ_UINT32_MAX) + { + pExtra_data = extra_data; + extra_size = mz_zip_writer_create_zip64_extra_data(extra_data, (uncomp_size >= MZ_UINT32_MAX) ? &uncomp_size : NULL, + (uncomp_size >= MZ_UINT32_MAX) ? &comp_size : NULL, (local_dir_header_ofs >= MZ_UINT32_MAX) ? &local_dir_header_ofs : NULL); + } + + if (!mz_zip_writer_create_local_dir_header(pZip, local_dir_header, (mz_uint16)archive_name_size, (mz_uint16)(extra_size + user_extra_data_len), 0, 0, 0, method, bit_flags, dos_time, dos_date)) + return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); + + if (pZip->m_pWrite(pZip->m_pIO_opaque, local_dir_header_ofs, local_dir_header, sizeof(local_dir_header)) != sizeof(local_dir_header)) + return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + + cur_archive_file_ofs += sizeof(local_dir_header); + + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name, archive_name_size) != archive_name_size) + { + pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); + return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + } + cur_archive_file_ofs += archive_name_size; + + if (pExtra_data != NULL) + { + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, extra_data, extra_size) != extra_size) + return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + + cur_archive_file_ofs += extra_size; + } + } + else + { + if ((comp_size > MZ_UINT32_MAX) || (cur_archive_file_ofs > MZ_UINT32_MAX)) + return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); + if (!mz_zip_writer_create_local_dir_header(pZip, local_dir_header, (mz_uint16)archive_name_size, (mz_uint16)user_extra_data_len, 0, 0, 0, method, bit_flags, dos_time, dos_date)) + return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); + + if (pZip->m_pWrite(pZip->m_pIO_opaque, local_dir_header_ofs, local_dir_header, sizeof(local_dir_header)) != sizeof(local_dir_header)) + return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + + cur_archive_file_ofs += sizeof(local_dir_header); + + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name, archive_name_size) != archive_name_size) + { + pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); + return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + } + cur_archive_file_ofs += archive_name_size; + } + + if (user_extra_data_len > 0) + { + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, user_extra_data, user_extra_data_len) != user_extra_data_len) + return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + + cur_archive_file_ofs += user_extra_data_len; + } + + if (store_data_uncompressed) + { + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pBuf, buf_size) != buf_size) + { + pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); + return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + } + + cur_archive_file_ofs += buf_size; + comp_size = buf_size; + } + else if (buf_size) + { + mz_zip_writer_add_state state; + + state.m_pZip = pZip; + state.m_cur_archive_file_ofs = cur_archive_file_ofs; + state.m_comp_size = 0; + + if ((tdefl_init(pComp, mz_zip_writer_add_put_buf_callback, &state, tdefl_create_comp_flags_from_zip_params(level, -15, MZ_DEFAULT_STRATEGY)) != TDEFL_STATUS_OKAY) || + (tdefl_compress_buffer(pComp, pBuf, buf_size, TDEFL_FINISH) != TDEFL_STATUS_DONE)) + { + pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); + return mz_zip_set_error(pZip, MZ_ZIP_COMPRESSION_FAILED); + } + + comp_size = state.m_comp_size; + cur_archive_file_ofs = state.m_cur_archive_file_ofs; + } + + pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); + pComp = NULL; + + if (uncomp_size) + { + mz_uint8 local_dir_footer[MZ_ZIP_DATA_DESCRIPTER_SIZE64]; + mz_uint32 local_dir_footer_size = MZ_ZIP_DATA_DESCRIPTER_SIZE32; + + MZ_ASSERT(bit_flags & MZ_ZIP_LDH_BIT_FLAG_HAS_LOCATOR); + + MZ_WRITE_LE32(local_dir_footer + 0, MZ_ZIP_DATA_DESCRIPTOR_ID); + MZ_WRITE_LE32(local_dir_footer + 4, uncomp_crc32); + if (pExtra_data == NULL) + { + if (comp_size > MZ_UINT32_MAX) + return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); + + MZ_WRITE_LE32(local_dir_footer + 8, comp_size); + MZ_WRITE_LE32(local_dir_footer + 12, uncomp_size); + } + else + { + MZ_WRITE_LE64(local_dir_footer + 8, comp_size); + MZ_WRITE_LE64(local_dir_footer + 16, uncomp_size); + local_dir_footer_size = MZ_ZIP_DATA_DESCRIPTER_SIZE64; + } + + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, local_dir_footer, local_dir_footer_size) != local_dir_footer_size) + return MZ_FALSE; + + cur_archive_file_ofs += local_dir_footer_size; + } + + if (pExtra_data != NULL) + { + extra_size = mz_zip_writer_create_zip64_extra_data(extra_data, (uncomp_size >= MZ_UINT32_MAX) ? &uncomp_size : NULL, + (uncomp_size >= MZ_UINT32_MAX) ? &comp_size : NULL, (local_dir_header_ofs >= MZ_UINT32_MAX) ? &local_dir_header_ofs : NULL); + } + + if (!mz_zip_writer_add_to_central_dir(pZip, pArchive_name, (mz_uint16)archive_name_size, pExtra_data, (mz_uint16)extra_size, pComment, + comment_size, uncomp_size, comp_size, uncomp_crc32, method, bit_flags, dos_time, dos_date, local_dir_header_ofs, ext_attributes, + user_extra_data_central, user_extra_data_central_len)) + return MZ_FALSE; + + pZip->m_total_files++; + pZip->m_archive_size = cur_archive_file_ofs; + + return MZ_TRUE; +} + +mz_bool mz_zip_writer_add_read_buf_callback(mz_zip_archive *pZip, const char *pArchive_name, mz_file_read_func read_callback, void* callback_opaque, mz_uint64 size_to_add, const MZ_TIME_T *pFile_time, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, + const char *user_extra_data, mz_uint user_extra_data_len, const char *user_extra_data_central, mz_uint user_extra_data_central_len) +{ + mz_uint16 gen_flags = MZ_ZIP_LDH_BIT_FLAG_HAS_LOCATOR; + mz_uint uncomp_crc32 = MZ_CRC32_INIT, level, num_alignment_padding_bytes; + mz_uint16 method = 0, dos_time = 0, dos_date = 0, ext_attributes = 0; + mz_uint64 local_dir_header_ofs, cur_archive_file_ofs = pZip->m_archive_size, uncomp_size = size_to_add, comp_size = 0; + size_t archive_name_size; + mz_uint8 local_dir_header[MZ_ZIP_LOCAL_DIR_HEADER_SIZE]; + mz_uint8 *pExtra_data = NULL; + mz_uint32 extra_size = 0; + mz_uint8 extra_data[MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE]; + mz_zip_internal_state *pState; + mz_uint64 file_ofs = 0; + + if (!(level_and_flags & MZ_ZIP_FLAG_ASCII_FILENAME)) + gen_flags |= MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_UTF8; + + if ((int)level_and_flags < 0) + level_and_flags = MZ_DEFAULT_LEVEL; + level = level_and_flags & 0xF; + + /* Sanity checks */ + if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) || (!pArchive_name) || ((comment_size) && (!pComment)) || (level > MZ_UBER_COMPRESSION)) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + + pState = pZip->m_pState; + + if ((!pState->m_zip64) && (uncomp_size > MZ_UINT32_MAX)) + { + /* Source file is too large for non-zip64 */ + /*return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); */ + pState->m_zip64 = MZ_TRUE; + } + + /* We could support this, but why? */ + if (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + + if (!mz_zip_writer_validate_archive_name(pArchive_name)) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_FILENAME); + + if (pState->m_zip64) + { + if (pZip->m_total_files == MZ_UINT32_MAX) + return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); + } + else + { + if (pZip->m_total_files == MZ_UINT16_MAX) + { + pState->m_zip64 = MZ_TRUE; + /*return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); */ + } + } + + archive_name_size = strlen(pArchive_name); + if (archive_name_size > MZ_UINT16_MAX) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_FILENAME); + + num_alignment_padding_bytes = mz_zip_writer_compute_padding_needed_for_file_alignment(pZip); + + /* miniz doesn't support central dirs >= MZ_UINT32_MAX bytes yet */ + if (((mz_uint64)pState->m_central_dir.m_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + archive_name_size + MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE + comment_size) >= MZ_UINT32_MAX) + return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE); + + if (!pState->m_zip64) + { + /* Bail early if the archive would obviously become too large */ + if ((pZip->m_archive_size + num_alignment_padding_bytes + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + archive_name_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + + archive_name_size + comment_size + user_extra_data_len + pState->m_central_dir.m_size + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE + 1024 + + MZ_ZIP_DATA_DESCRIPTER_SIZE32 + user_extra_data_central_len) > 0xFFFFFFFF) + { + pState->m_zip64 = MZ_TRUE; + /*return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); */ + } + } + +#ifndef MINIZ_NO_TIME + if (pFile_time) + { + mz_zip_time_t_to_dos_time(*pFile_time, &dos_time, &dos_date); + } +#endif + + if (uncomp_size <= 3) + level = 0; + + if (!mz_zip_writer_write_zeros(pZip, cur_archive_file_ofs, num_alignment_padding_bytes)) + { + return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + } + + cur_archive_file_ofs += num_alignment_padding_bytes; + local_dir_header_ofs = cur_archive_file_ofs; + + if (pZip->m_file_offset_alignment) + { + MZ_ASSERT((cur_archive_file_ofs & (pZip->m_file_offset_alignment - 1)) == 0); + } + + if (uncomp_size && level) + { + method = MZ_DEFLATED; + } + + MZ_CLEAR_OBJ(local_dir_header); + if (pState->m_zip64) + { + if (uncomp_size >= MZ_UINT32_MAX || local_dir_header_ofs >= MZ_UINT32_MAX) + { + pExtra_data = extra_data; + extra_size = mz_zip_writer_create_zip64_extra_data(extra_data, (uncomp_size >= MZ_UINT32_MAX) ? &uncomp_size : NULL, + (uncomp_size >= MZ_UINT32_MAX) ? &comp_size : NULL, (local_dir_header_ofs >= MZ_UINT32_MAX) ? &local_dir_header_ofs : NULL); + } + + if (!mz_zip_writer_create_local_dir_header(pZip, local_dir_header, (mz_uint16)archive_name_size, (mz_uint16)(extra_size + user_extra_data_len), 0, 0, 0, method, gen_flags, dos_time, dos_date)) + return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); + + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, local_dir_header, sizeof(local_dir_header)) != sizeof(local_dir_header)) + return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + + cur_archive_file_ofs += sizeof(local_dir_header); + + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name, archive_name_size) != archive_name_size) + { + return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + } + + cur_archive_file_ofs += archive_name_size; + + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, extra_data, extra_size) != extra_size) + return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + + cur_archive_file_ofs += extra_size; + } + else + { + if ((comp_size > MZ_UINT32_MAX) || (cur_archive_file_ofs > MZ_UINT32_MAX)) + return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); + if (!mz_zip_writer_create_local_dir_header(pZip, local_dir_header, (mz_uint16)archive_name_size, (mz_uint16)user_extra_data_len, 0, 0, 0, method, gen_flags, dos_time, dos_date)) + return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); + + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, local_dir_header, sizeof(local_dir_header)) != sizeof(local_dir_header)) + return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + + cur_archive_file_ofs += sizeof(local_dir_header); + + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name, archive_name_size) != archive_name_size) + { + return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + } + + cur_archive_file_ofs += archive_name_size; + } + + if (user_extra_data_len > 0) + { + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, user_extra_data, user_extra_data_len) != user_extra_data_len) + return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + + cur_archive_file_ofs += user_extra_data_len; + } + + if (uncomp_size) + { + mz_uint64 uncomp_remaining = uncomp_size; + void *pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, MZ_ZIP_MAX_IO_BUF_SIZE); + if (!pRead_buf) + { + return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + } + + if (!level) + { + while (uncomp_remaining) + { + mz_uint n = (mz_uint)MZ_MIN((mz_uint64)MZ_ZIP_MAX_IO_BUF_SIZE, uncomp_remaining); + if ((read_callback(callback_opaque, file_ofs, pRead_buf, n) != n) || (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pRead_buf, n) != n)) + { + pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); + return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); + } + file_ofs += n; + uncomp_crc32 = (mz_uint32)mz_crc32(uncomp_crc32, (const mz_uint8 *)pRead_buf, n); + uncomp_remaining -= n; + cur_archive_file_ofs += n; + } + comp_size = uncomp_size; + } + else + { + mz_bool result = MZ_FALSE; + mz_zip_writer_add_state state; + tdefl_compressor *pComp = (tdefl_compressor *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(tdefl_compressor)); + if (!pComp) + { + pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); + return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + } + + state.m_pZip = pZip; + state.m_cur_archive_file_ofs = cur_archive_file_ofs; + state.m_comp_size = 0; + + if (tdefl_init(pComp, mz_zip_writer_add_put_buf_callback, &state, tdefl_create_comp_flags_from_zip_params(level, -15, MZ_DEFAULT_STRATEGY)) != TDEFL_STATUS_OKAY) + { + pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); + pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); + return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); + } + + for (;;) + { + size_t in_buf_size = (mz_uint32)MZ_MIN(uncomp_remaining, (mz_uint64)MZ_ZIP_MAX_IO_BUF_SIZE); + tdefl_status status; + tdefl_flush flush = TDEFL_NO_FLUSH; + + if (read_callback(callback_opaque, file_ofs, pRead_buf, in_buf_size)!= in_buf_size) + { + mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); + break; + } + + file_ofs += in_buf_size; + uncomp_crc32 = (mz_uint32)mz_crc32(uncomp_crc32, (const mz_uint8 *)pRead_buf, in_buf_size); + uncomp_remaining -= in_buf_size; + + if (pZip->m_pNeeds_keepalive != NULL && pZip->m_pNeeds_keepalive(pZip->m_pIO_opaque)) + flush = TDEFL_FULL_FLUSH; + + status = tdefl_compress_buffer(pComp, pRead_buf, in_buf_size, uncomp_remaining ? flush : TDEFL_FINISH); + if (status == TDEFL_STATUS_DONE) + { + result = MZ_TRUE; + break; + } + else if (status != TDEFL_STATUS_OKAY) + { + mz_zip_set_error(pZip, MZ_ZIP_COMPRESSION_FAILED); + break; + } + } + + pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); + + if (!result) + { + pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); + return MZ_FALSE; + } + + comp_size = state.m_comp_size; + cur_archive_file_ofs = state.m_cur_archive_file_ofs; + } + + pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); + } + + { + mz_uint8 local_dir_footer[MZ_ZIP_DATA_DESCRIPTER_SIZE64]; + mz_uint32 local_dir_footer_size = MZ_ZIP_DATA_DESCRIPTER_SIZE32; + + MZ_WRITE_LE32(local_dir_footer + 0, MZ_ZIP_DATA_DESCRIPTOR_ID); + MZ_WRITE_LE32(local_dir_footer + 4, uncomp_crc32); + if (pExtra_data == NULL) + { + if (comp_size > MZ_UINT32_MAX) + return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); + + MZ_WRITE_LE32(local_dir_footer + 8, comp_size); + MZ_WRITE_LE32(local_dir_footer + 12, uncomp_size); + } + else + { + MZ_WRITE_LE64(local_dir_footer + 8, comp_size); + MZ_WRITE_LE64(local_dir_footer + 16, uncomp_size); + local_dir_footer_size = MZ_ZIP_DATA_DESCRIPTER_SIZE64; + } + + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, local_dir_footer, local_dir_footer_size) != local_dir_footer_size) + return MZ_FALSE; + + cur_archive_file_ofs += local_dir_footer_size; + } + + if (pExtra_data != NULL) + { + extra_size = mz_zip_writer_create_zip64_extra_data(extra_data, (uncomp_size >= MZ_UINT32_MAX) ? &uncomp_size : NULL, + (uncomp_size >= MZ_UINT32_MAX) ? &comp_size : NULL, (local_dir_header_ofs >= MZ_UINT32_MAX) ? &local_dir_header_ofs : NULL); + } + + if (!mz_zip_writer_add_to_central_dir(pZip, pArchive_name, (mz_uint16)archive_name_size, pExtra_data, (mz_uint16)extra_size, pComment, comment_size, + uncomp_size, comp_size, uncomp_crc32, method, gen_flags, dos_time, dos_date, local_dir_header_ofs, ext_attributes, + user_extra_data_central, user_extra_data_central_len)) + return MZ_FALSE; + + pZip->m_total_files++; + pZip->m_archive_size = cur_archive_file_ofs; + + return MZ_TRUE; +} + +#ifndef MINIZ_NO_STDIO + +static size_t mz_file_read_func_stdio(void *pOpaque, mz_uint64 file_ofs, void *pBuf, size_t n) +{ + MZ_FILE *pSrc_file = (MZ_FILE *)pOpaque; + mz_int64 cur_ofs = MZ_FTELL64(pSrc_file); + + if (((mz_int64)file_ofs < 0) || (((cur_ofs != (mz_int64)file_ofs)) && (MZ_FSEEK64(pSrc_file, (mz_int64)file_ofs, SEEK_SET)))) + return 0; + + return MZ_FREAD(pBuf, 1, n, pSrc_file); +} + +mz_bool mz_zip_writer_add_cfile(mz_zip_archive *pZip, const char *pArchive_name, MZ_FILE *pSrc_file, mz_uint64 size_to_add, const MZ_TIME_T *pFile_time, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, + const char *user_extra_data, mz_uint user_extra_data_len, const char *user_extra_data_central, mz_uint user_extra_data_central_len) +{ + return mz_zip_writer_add_read_buf_callback(pZip, pArchive_name, mz_file_read_func_stdio, pSrc_file, size_to_add, pFile_time, pComment, comment_size, level_and_flags, + user_extra_data, user_extra_data_len, user_extra_data_central, user_extra_data_central_len); +} + +mz_bool mz_zip_writer_add_file(mz_zip_archive *pZip, const char *pArchive_name, const char *pSrc_filename, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags) +{ + MZ_FILE *pSrc_file = NULL; + mz_uint64 uncomp_size = 0; + MZ_TIME_T file_modified_time; + MZ_TIME_T *pFile_time = NULL; + mz_bool status; + + memset(&file_modified_time, 0, sizeof(file_modified_time)); + +#if !defined(MINIZ_NO_TIME) && !defined(MINIZ_NO_STDIO) + pFile_time = &file_modified_time; + if (!mz_zip_get_file_modified_time(pSrc_filename, &file_modified_time)) + return mz_zip_set_error(pZip, MZ_ZIP_FILE_STAT_FAILED); +#endif + + pSrc_file = MZ_FOPEN(pSrc_filename, "rb"); + if (!pSrc_file) + return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED); + + MZ_FSEEK64(pSrc_file, 0, SEEK_END); + uncomp_size = MZ_FTELL64(pSrc_file); + MZ_FSEEK64(pSrc_file, 0, SEEK_SET); + + status = mz_zip_writer_add_cfile(pZip, pArchive_name, pSrc_file, uncomp_size, pFile_time, pComment, comment_size, level_and_flags, NULL, 0, NULL, 0); + + MZ_FCLOSE(pSrc_file); + + return status; +} +#endif /* #ifndef MINIZ_NO_STDIO */ + +static mz_bool mz_zip_writer_update_zip64_extension_block(mz_zip_array *pNew_ext, mz_zip_archive *pZip, const mz_uint8 *pExt, uint32_t ext_len, mz_uint64 *pComp_size, mz_uint64 *pUncomp_size, mz_uint64 *pLocal_header_ofs, mz_uint32 *pDisk_start) +{ + /* + 64 should be enough for any new zip64 data */ + if (!mz_zip_array_reserve(pZip, pNew_ext, ext_len + 64, MZ_FALSE)) + return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + + mz_zip_array_resize(pZip, pNew_ext, 0, MZ_FALSE); + + if ((pUncomp_size) || (pComp_size) || (pLocal_header_ofs) || (pDisk_start)) + { + mz_uint8 new_ext_block[64]; + mz_uint8 *pDst = new_ext_block; + mz_write_le16(pDst, MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID); + mz_write_le16(pDst + sizeof(mz_uint16), 0); + pDst += sizeof(mz_uint16) * 2; + + if (pUncomp_size) + { + mz_write_le64(pDst, *pUncomp_size); + pDst += sizeof(mz_uint64); + } + + if (pComp_size) + { + mz_write_le64(pDst, *pComp_size); + pDst += sizeof(mz_uint64); + } + + if (pLocal_header_ofs) + { + mz_write_le64(pDst, *pLocal_header_ofs); + pDst += sizeof(mz_uint64); + } + + if (pDisk_start) + { + mz_write_le32(pDst, *pDisk_start); + pDst += sizeof(mz_uint32); + } + + mz_write_le16(new_ext_block + sizeof(mz_uint16), (mz_uint16)((pDst - new_ext_block) - sizeof(mz_uint16) * 2)); + + if (!mz_zip_array_push_back(pZip, pNew_ext, new_ext_block, pDst - new_ext_block)) + return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + } + + if ((pExt) && (ext_len)) + { + mz_uint32 extra_size_remaining = ext_len; + const mz_uint8 *pExtra_data = pExt; + + do + { + mz_uint32 field_id, field_data_size, field_total_size; + + if (extra_size_remaining < (sizeof(mz_uint16) * 2)) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + + field_id = MZ_READ_LE16(pExtra_data); + field_data_size = MZ_READ_LE16(pExtra_data + sizeof(mz_uint16)); + field_total_size = field_data_size + sizeof(mz_uint16) * 2; + + if (field_total_size > extra_size_remaining) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + + if (field_id != MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID) + { + if (!mz_zip_array_push_back(pZip, pNew_ext, pExtra_data, field_total_size)) + return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + } + + pExtra_data += field_total_size; + extra_size_remaining -= field_total_size; + } while (extra_size_remaining); + } + + return MZ_TRUE; +} + +/* TODO: This func is now pretty freakin complex due to zip64, split it up? */ +mz_bool mz_zip_writer_add_from_zip_reader(mz_zip_archive *pZip, mz_zip_archive *pSource_zip, mz_uint src_file_index) +{ + mz_uint n, bit_flags, num_alignment_padding_bytes, src_central_dir_following_data_size; + mz_uint64 src_archive_bytes_remaining, local_dir_header_ofs; + mz_uint64 cur_src_file_ofs, cur_dst_file_ofs; + mz_uint32 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; + mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32; + mz_uint8 new_central_header[MZ_ZIP_CENTRAL_DIR_HEADER_SIZE]; + size_t orig_central_dir_size; + mz_zip_internal_state *pState; + void *pBuf; + const mz_uint8 *pSrc_central_header; + mz_zip_archive_file_stat src_file_stat; + mz_uint32 src_filename_len, src_comment_len, src_ext_len; + mz_uint32 local_header_filename_size, local_header_extra_len; + mz_uint64 local_header_comp_size, local_header_uncomp_size; + mz_bool found_zip64_ext_data_in_ldir = MZ_FALSE; + + /* Sanity checks */ + if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) || (!pSource_zip->m_pRead)) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + + pState = pZip->m_pState; + + /* Don't support copying files from zip64 archives to non-zip64, even though in some cases this is possible */ + if ((pSource_zip->m_pState->m_zip64) && (!pZip->m_pState->m_zip64)) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + + /* Get pointer to the source central dir header and crack it */ + if (NULL == (pSrc_central_header = mz_zip_get_cdh(pSource_zip, src_file_index))) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + + if (MZ_READ_LE32(pSrc_central_header + MZ_ZIP_CDH_SIG_OFS) != MZ_ZIP_CENTRAL_DIR_HEADER_SIG) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + + src_filename_len = MZ_READ_LE16(pSrc_central_header + MZ_ZIP_CDH_FILENAME_LEN_OFS); + src_comment_len = MZ_READ_LE16(pSrc_central_header + MZ_ZIP_CDH_COMMENT_LEN_OFS); + src_ext_len = MZ_READ_LE16(pSrc_central_header + MZ_ZIP_CDH_EXTRA_LEN_OFS); + src_central_dir_following_data_size = src_filename_len + src_ext_len + src_comment_len; + + /* TODO: We don't support central dir's >= MZ_UINT32_MAX bytes right now (+32 fudge factor in case we need to add more extra data) */ + if ((pState->m_central_dir.m_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + src_central_dir_following_data_size + 32) >= MZ_UINT32_MAX) + return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE); + + num_alignment_padding_bytes = mz_zip_writer_compute_padding_needed_for_file_alignment(pZip); + + if (!pState->m_zip64) + { + if (pZip->m_total_files == MZ_UINT16_MAX) + return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); + } + else + { + /* TODO: Our zip64 support still has some 32-bit limits that may not be worth fixing. */ + if (pZip->m_total_files == MZ_UINT32_MAX) + return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); + } + + if (!mz_zip_file_stat_internal(pSource_zip, src_file_index, pSrc_central_header, &src_file_stat, NULL)) + return MZ_FALSE; + + cur_src_file_ofs = src_file_stat.m_local_header_ofs; + cur_dst_file_ofs = pZip->m_archive_size; + + /* Read the source archive's local dir header */ + if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, cur_src_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE) + return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); + + if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + + cur_src_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE; + + /* Compute the total size we need to copy (filename+extra data+compressed data) */ + local_header_filename_size = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS); + local_header_extra_len = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS); + local_header_comp_size = MZ_READ_LE32(pLocal_header + MZ_ZIP_LDH_COMPRESSED_SIZE_OFS); + local_header_uncomp_size = MZ_READ_LE32(pLocal_header + MZ_ZIP_LDH_DECOMPRESSED_SIZE_OFS); + src_archive_bytes_remaining = local_header_filename_size + local_header_extra_len + src_file_stat.m_comp_size; + + /* Try to find a zip64 extended information field */ + if ((local_header_extra_len) && ((local_header_comp_size == MZ_UINT32_MAX) || (local_header_uncomp_size == MZ_UINT32_MAX))) + { + mz_zip_array file_data_array; + const mz_uint8 *pExtra_data; + mz_uint32 extra_size_remaining = local_header_extra_len; + + mz_zip_array_init(&file_data_array, 1); + if (!mz_zip_array_resize(pZip, &file_data_array, local_header_extra_len, MZ_FALSE)) + { + return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + } + + if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, src_file_stat.m_local_header_ofs + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + local_header_filename_size, file_data_array.m_p, local_header_extra_len) != local_header_extra_len) + { + mz_zip_array_clear(pZip, &file_data_array); + return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); + } + + pExtra_data = (const mz_uint8 *)file_data_array.m_p; + + do + { + mz_uint32 field_id, field_data_size, field_total_size; + + if (extra_size_remaining < (sizeof(mz_uint16) * 2)) + { + mz_zip_array_clear(pZip, &file_data_array); + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + } + + field_id = MZ_READ_LE16(pExtra_data); + field_data_size = MZ_READ_LE16(pExtra_data + sizeof(mz_uint16)); + field_total_size = field_data_size + sizeof(mz_uint16) * 2; + + if (field_total_size > extra_size_remaining) + { + mz_zip_array_clear(pZip, &file_data_array); + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + } + + if (field_id == MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID) + { + const mz_uint8 *pSrc_field_data = pExtra_data + sizeof(mz_uint32); + + if (field_data_size < sizeof(mz_uint64) * 2) + { + mz_zip_array_clear(pZip, &file_data_array); + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + } + + local_header_uncomp_size = MZ_READ_LE64(pSrc_field_data); + local_header_comp_size = MZ_READ_LE64(pSrc_field_data + sizeof(mz_uint64)); /* may be 0 if there's a descriptor */ + + found_zip64_ext_data_in_ldir = MZ_TRUE; + break; + } + + pExtra_data += field_total_size; + extra_size_remaining -= field_total_size; + } while (extra_size_remaining); + + mz_zip_array_clear(pZip, &file_data_array); + } + + if (!pState->m_zip64) + { + /* Try to detect if the new archive will most likely wind up too big and bail early (+(sizeof(mz_uint32) * 4) is for the optional descriptor which could be present, +64 is a fudge factor). */ + /* We also check when the archive is finalized so this doesn't need to be perfect. */ + mz_uint64 approx_new_archive_size = cur_dst_file_ofs + num_alignment_padding_bytes + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + src_archive_bytes_remaining + (sizeof(mz_uint32) * 4) + + pState->m_central_dir.m_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + src_central_dir_following_data_size + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE + 64; + + if (approx_new_archive_size >= MZ_UINT32_MAX) + return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); + } + + /* Write dest archive padding */ + if (!mz_zip_writer_write_zeros(pZip, cur_dst_file_ofs, num_alignment_padding_bytes)) + return MZ_FALSE; + + cur_dst_file_ofs += num_alignment_padding_bytes; + + local_dir_header_ofs = cur_dst_file_ofs; + if (pZip->m_file_offset_alignment) + { + MZ_ASSERT((local_dir_header_ofs & (pZip->m_file_offset_alignment - 1)) == 0); + } + + /* The original zip's local header+ext block doesn't change, even with zip64, so we can just copy it over to the dest zip */ + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_dst_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE) + return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + + cur_dst_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE; + + /* Copy over the source archive bytes to the dest archive, also ensure we have enough buf space to handle optional data descriptor */ + if (NULL == (pBuf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)MZ_MAX(32U, MZ_MIN((mz_uint64)MZ_ZIP_MAX_IO_BUF_SIZE, src_archive_bytes_remaining))))) + return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + + while (src_archive_bytes_remaining) + { + n = (mz_uint)MZ_MIN((mz_uint64)MZ_ZIP_MAX_IO_BUF_SIZE, src_archive_bytes_remaining); + if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, cur_src_file_ofs, pBuf, n) != n) + { + pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); + return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); + } + cur_src_file_ofs += n; + + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_dst_file_ofs, pBuf, n) != n) + { + pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); + return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + } + cur_dst_file_ofs += n; + + src_archive_bytes_remaining -= n; + } + + /* Now deal with the optional data descriptor */ + bit_flags = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_BIT_FLAG_OFS); + if (bit_flags & 8) + { + /* Copy data descriptor */ + if ((pSource_zip->m_pState->m_zip64) || (found_zip64_ext_data_in_ldir)) + { + /* src is zip64, dest must be zip64 */ + + /* name uint32_t's */ + /* id 1 (optional in zip64?) */ + /* crc 1 */ + /* comp_size 2 */ + /* uncomp_size 2 */ + if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, cur_src_file_ofs, pBuf, (sizeof(mz_uint32) * 6)) != (sizeof(mz_uint32) * 6)) + { + pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); + return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); + } + + n = sizeof(mz_uint32) * ((MZ_READ_LE32(pBuf) == MZ_ZIP_DATA_DESCRIPTOR_ID) ? 6 : 5); + } + else + { + /* src is NOT zip64 */ + mz_bool has_id; + + if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, cur_src_file_ofs, pBuf, sizeof(mz_uint32) * 4) != sizeof(mz_uint32) * 4) + { + pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); + return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); + } + + has_id = (MZ_READ_LE32(pBuf) == MZ_ZIP_DATA_DESCRIPTOR_ID); + + if (pZip->m_pState->m_zip64) + { + /* dest is zip64, so upgrade the data descriptor */ + const mz_uint32 *pSrc_descriptor = (const mz_uint32 *)((const mz_uint8 *)pBuf + (has_id ? sizeof(mz_uint32) : 0)); + const mz_uint32 src_crc32 = pSrc_descriptor[0]; + const mz_uint64 src_comp_size = pSrc_descriptor[1]; + const mz_uint64 src_uncomp_size = pSrc_descriptor[2]; + + mz_write_le32((mz_uint8 *)pBuf, MZ_ZIP_DATA_DESCRIPTOR_ID); + mz_write_le32((mz_uint8 *)pBuf + sizeof(mz_uint32) * 1, src_crc32); + mz_write_le64((mz_uint8 *)pBuf + sizeof(mz_uint32) * 2, src_comp_size); + mz_write_le64((mz_uint8 *)pBuf + sizeof(mz_uint32) * 4, src_uncomp_size); + + n = sizeof(mz_uint32) * 6; + } + else + { + /* dest is NOT zip64, just copy it as-is */ + n = sizeof(mz_uint32) * (has_id ? 4 : 3); + } + } + + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_dst_file_ofs, pBuf, n) != n) + { + pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); + return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + } + + cur_src_file_ofs += n; + cur_dst_file_ofs += n; + } + pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); + + /* Finally, add the new central dir header */ + orig_central_dir_size = pState->m_central_dir.m_size; + + memcpy(new_central_header, pSrc_central_header, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE); + + if (pState->m_zip64) + { + /* This is the painful part: We need to write a new central dir header + ext block with updated zip64 fields, and ensure the old fields (if any) are not included. */ + const mz_uint8 *pSrc_ext = pSrc_central_header + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + src_filename_len; + mz_zip_array new_ext_block; + + mz_zip_array_init(&new_ext_block, sizeof(mz_uint8)); + + MZ_WRITE_LE32(new_central_header + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS, MZ_UINT32_MAX); + MZ_WRITE_LE32(new_central_header + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS, MZ_UINT32_MAX); + MZ_WRITE_LE32(new_central_header + MZ_ZIP_CDH_LOCAL_HEADER_OFS, MZ_UINT32_MAX); + + if (!mz_zip_writer_update_zip64_extension_block(&new_ext_block, pZip, pSrc_ext, src_ext_len, &src_file_stat.m_comp_size, &src_file_stat.m_uncomp_size, &local_dir_header_ofs, NULL)) + { + mz_zip_array_clear(pZip, &new_ext_block); + return MZ_FALSE; + } + + MZ_WRITE_LE16(new_central_header + MZ_ZIP_CDH_EXTRA_LEN_OFS, new_ext_block.m_size); + + if (!mz_zip_array_push_back(pZip, &pState->m_central_dir, new_central_header, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE)) + { + mz_zip_array_clear(pZip, &new_ext_block); + return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + } + + if (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pSrc_central_header + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, src_filename_len)) + { + mz_zip_array_clear(pZip, &new_ext_block); + mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE); + return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + } + + if (!mz_zip_array_push_back(pZip, &pState->m_central_dir, new_ext_block.m_p, new_ext_block.m_size)) + { + mz_zip_array_clear(pZip, &new_ext_block); + mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE); + return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + } + + if (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pSrc_central_header + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + src_filename_len + src_ext_len, src_comment_len)) + { + mz_zip_array_clear(pZip, &new_ext_block); + mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE); + return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + } + + mz_zip_array_clear(pZip, &new_ext_block); + } + else + { + /* sanity checks */ + if (cur_dst_file_ofs > MZ_UINT32_MAX) + return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); + + if (local_dir_header_ofs >= MZ_UINT32_MAX) + return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); + + MZ_WRITE_LE32(new_central_header + MZ_ZIP_CDH_LOCAL_HEADER_OFS, local_dir_header_ofs); + + if (!mz_zip_array_push_back(pZip, &pState->m_central_dir, new_central_header, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE)) + return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + + if (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pSrc_central_header + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, src_central_dir_following_data_size)) + { + mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE); + return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + } + } + + /* This shouldn't trigger unless we screwed up during the initial sanity checks */ + if (pState->m_central_dir.m_size >= MZ_UINT32_MAX) + { + /* TODO: Support central dirs >= 32-bits in size */ + mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE); + return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE); + } + + n = (mz_uint32)orig_central_dir_size; + if (!mz_zip_array_push_back(pZip, &pState->m_central_dir_offsets, &n, 1)) + { + mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE); + return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + } + + pZip->m_total_files++; + pZip->m_archive_size = cur_dst_file_ofs; + + return MZ_TRUE; +} + +mz_bool mz_zip_writer_finalize_archive(mz_zip_archive *pZip) +{ + mz_zip_internal_state *pState; + mz_uint64 central_dir_ofs, central_dir_size; + mz_uint8 hdr[256]; + + if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING)) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + + pState = pZip->m_pState; + + if (pState->m_zip64) + { + if ((pZip->m_total_files > MZ_UINT32_MAX) || (pState->m_central_dir.m_size >= MZ_UINT32_MAX)) + return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); + } + else + { + if ((pZip->m_total_files > MZ_UINT16_MAX) || ((pZip->m_archive_size + pState->m_central_dir.m_size + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) > MZ_UINT32_MAX)) + return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); + } + + central_dir_ofs = 0; + central_dir_size = 0; + if (pZip->m_total_files) + { + /* Write central directory */ + central_dir_ofs = pZip->m_archive_size; + central_dir_size = pState->m_central_dir.m_size; + pZip->m_central_directory_file_ofs = central_dir_ofs; + if (pZip->m_pWrite(pZip->m_pIO_opaque, central_dir_ofs, pState->m_central_dir.m_p, (size_t)central_dir_size) != central_dir_size) + return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + + pZip->m_archive_size += central_dir_size; + } + + if (pState->m_zip64) + { + /* Write zip64 end of central directory header */ + mz_uint64 rel_ofs_to_zip64_ecdr = pZip->m_archive_size; + + MZ_CLEAR_OBJ(hdr); + MZ_WRITE_LE32(hdr + MZ_ZIP64_ECDH_SIG_OFS, MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIG); + MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDH_SIZE_OF_RECORD_OFS, MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE - sizeof(mz_uint32) - sizeof(mz_uint64)); + MZ_WRITE_LE16(hdr + MZ_ZIP64_ECDH_VERSION_MADE_BY_OFS, 0x031E); /* TODO: always Unix */ + MZ_WRITE_LE16(hdr + MZ_ZIP64_ECDH_VERSION_NEEDED_OFS, 0x002D); + MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS, pZip->m_total_files); + MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDH_CDIR_TOTAL_ENTRIES_OFS, pZip->m_total_files); + MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDH_CDIR_SIZE_OFS, central_dir_size); + MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDH_CDIR_OFS_OFS, central_dir_ofs); + if (pZip->m_pWrite(pZip->m_pIO_opaque, pZip->m_archive_size, hdr, MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE) != MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE) + return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + + pZip->m_archive_size += MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE; + + /* Write zip64 end of central directory locator */ + MZ_CLEAR_OBJ(hdr); + MZ_WRITE_LE32(hdr + MZ_ZIP64_ECDL_SIG_OFS, MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIG); + MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDL_REL_OFS_TO_ZIP64_ECDR_OFS, rel_ofs_to_zip64_ecdr); + MZ_WRITE_LE32(hdr + MZ_ZIP64_ECDL_TOTAL_NUMBER_OF_DISKS_OFS, 1); + if (pZip->m_pWrite(pZip->m_pIO_opaque, pZip->m_archive_size, hdr, MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE) != MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE) + return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + + pZip->m_archive_size += MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE; + } + + /* Write end of central directory record */ + MZ_CLEAR_OBJ(hdr); + MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_SIG_OFS, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG); + MZ_WRITE_LE16(hdr + MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS, MZ_MIN(MZ_UINT16_MAX, pZip->m_total_files)); + MZ_WRITE_LE16(hdr + MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS, MZ_MIN(MZ_UINT16_MAX, pZip->m_total_files)); + MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_CDIR_SIZE_OFS, MZ_MIN(MZ_UINT32_MAX, central_dir_size)); + MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_CDIR_OFS_OFS, MZ_MIN(MZ_UINT32_MAX, central_dir_ofs)); + + if (pZip->m_pWrite(pZip->m_pIO_opaque, pZip->m_archive_size, hdr, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) != MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) + return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + +#ifndef MINIZ_NO_STDIO + if ((pState->m_pFile) && (MZ_FFLUSH(pState->m_pFile) == EOF)) + return mz_zip_set_error(pZip, MZ_ZIP_FILE_CLOSE_FAILED); +#endif /* #ifndef MINIZ_NO_STDIO */ + + pZip->m_archive_size += MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE; + + pZip->m_zip_mode = MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED; + return MZ_TRUE; +} + +mz_bool mz_zip_writer_finalize_heap_archive(mz_zip_archive *pZip, void **ppBuf, size_t *pSize) +{ + if ((!ppBuf) || (!pSize)) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + + *ppBuf = NULL; + *pSize = 0; + + if ((!pZip) || (!pZip->m_pState)) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + + if (pZip->m_pWrite != mz_zip_heap_write_func) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + + if (!mz_zip_writer_finalize_archive(pZip)) + return MZ_FALSE; + + *ppBuf = pZip->m_pState->m_pMem; + *pSize = pZip->m_pState->m_mem_size; + pZip->m_pState->m_pMem = NULL; + pZip->m_pState->m_mem_size = pZip->m_pState->m_mem_capacity = 0; + + return MZ_TRUE; +} + +mz_bool mz_zip_writer_end(mz_zip_archive *pZip) +{ + return mz_zip_writer_end_internal(pZip, MZ_TRUE); +} + +#ifndef MINIZ_NO_STDIO +mz_bool mz_zip_add_mem_to_archive_file_in_place(const char *pZip_filename, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags) +{ + return mz_zip_add_mem_to_archive_file_in_place_v2(pZip_filename, pArchive_name, pBuf, buf_size, pComment, comment_size, level_and_flags, NULL); +} + +mz_bool mz_zip_add_mem_to_archive_file_in_place_v2(const char *pZip_filename, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, mz_zip_error *pErr) +{ + mz_bool status, created_new_archive = MZ_FALSE; + mz_zip_archive zip_archive; + struct MZ_FILE_STAT_STRUCT file_stat; + mz_zip_error actual_err = MZ_ZIP_NO_ERROR; + + mz_zip_zero_struct(&zip_archive); + if ((int)level_and_flags < 0) + level_and_flags = MZ_DEFAULT_LEVEL; + + if ((!pZip_filename) || (!pArchive_name) || ((buf_size) && (!pBuf)) || ((comment_size) && (!pComment)) || ((level_and_flags & 0xF) > MZ_UBER_COMPRESSION)) + { + if (pErr) + *pErr = MZ_ZIP_INVALID_PARAMETER; + return MZ_FALSE; + } + + if (!mz_zip_writer_validate_archive_name(pArchive_name)) + { + if (pErr) + *pErr = MZ_ZIP_INVALID_FILENAME; + return MZ_FALSE; + } + + /* Important: The regular non-64 bit version of stat() can fail here if the file is very large, which could cause the archive to be overwritten. */ + /* So be sure to compile with _LARGEFILE64_SOURCE 1 */ + if (MZ_FILE_STAT(pZip_filename, &file_stat) != 0) + { + /* Create a new archive. */ + if (!mz_zip_writer_init_file_v2(&zip_archive, pZip_filename, 0, level_and_flags)) + { + if (pErr) + *pErr = zip_archive.m_last_error; + return MZ_FALSE; + } + + created_new_archive = MZ_TRUE; + } + else + { + /* Append to an existing archive. */ + if (!mz_zip_reader_init_file_v2(&zip_archive, pZip_filename, level_and_flags | MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY, 0, 0)) + { + if (pErr) + *pErr = zip_archive.m_last_error; + return MZ_FALSE; + } + + if (!mz_zip_writer_init_from_reader_v2(&zip_archive, pZip_filename, level_and_flags)) + { + if (pErr) + *pErr = zip_archive.m_last_error; + + mz_zip_reader_end_internal(&zip_archive, MZ_FALSE); + + return MZ_FALSE; + } + } + + status = mz_zip_writer_add_mem_ex(&zip_archive, pArchive_name, pBuf, buf_size, pComment, comment_size, level_and_flags, 0, 0); + actual_err = zip_archive.m_last_error; + + /* Always finalize, even if adding failed for some reason, so we have a valid central directory. (This may not always succeed, but we can try.) */ + if (!mz_zip_writer_finalize_archive(&zip_archive)) + { + if (!actual_err) + actual_err = zip_archive.m_last_error; + + status = MZ_FALSE; + } + + if (!mz_zip_writer_end_internal(&zip_archive, status)) + { + if (!actual_err) + actual_err = zip_archive.m_last_error; + + status = MZ_FALSE; + } + + if ((!status) && (created_new_archive)) + { + /* It's a new archive and something went wrong, so just delete it. */ + int ignoredStatus = MZ_DELETE_FILE(pZip_filename); + (void)ignoredStatus; + } + + if (pErr) + *pErr = actual_err; + + return status; +} + +void *mz_zip_extract_archive_file_to_heap_v2(const char *pZip_filename, const char *pArchive_name, const char *pComment, size_t *pSize, mz_uint flags, mz_zip_error *pErr) +{ + mz_uint32 file_index; + mz_zip_archive zip_archive; + void *p = NULL; + + if (pSize) + *pSize = 0; + + if ((!pZip_filename) || (!pArchive_name)) + { + if (pErr) + *pErr = MZ_ZIP_INVALID_PARAMETER; + + return NULL; + } + + mz_zip_zero_struct(&zip_archive); + if (!mz_zip_reader_init_file_v2(&zip_archive, pZip_filename, flags | MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY, 0, 0)) + { + if (pErr) + *pErr = zip_archive.m_last_error; + + return NULL; + } + + if (mz_zip_reader_locate_file_v2(&zip_archive, pArchive_name, pComment, flags, &file_index)) + { + p = mz_zip_reader_extract_to_heap(&zip_archive, file_index, pSize, flags); + } + + mz_zip_reader_end_internal(&zip_archive, p != NULL); + + if (pErr) + *pErr = zip_archive.m_last_error; + + return p; +} + +void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename, const char *pArchive_name, size_t *pSize, mz_uint flags) +{ + return mz_zip_extract_archive_file_to_heap_v2(pZip_filename, pArchive_name, NULL, pSize, flags, NULL); +} + +#endif /* #ifndef MINIZ_NO_STDIO */ + +#endif /* #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS */ + +/* ------------------- Misc utils */ + +mz_zip_mode mz_zip_get_mode(mz_zip_archive *pZip) +{ + return pZip ? pZip->m_zip_mode : MZ_ZIP_MODE_INVALID; +} + +mz_zip_type mz_zip_get_type(mz_zip_archive *pZip) +{ + return pZip ? pZip->m_zip_type : MZ_ZIP_TYPE_INVALID; +} + +mz_zip_error mz_zip_set_last_error(mz_zip_archive *pZip, mz_zip_error err_num) +{ + mz_zip_error prev_err; + + if (!pZip) + return MZ_ZIP_INVALID_PARAMETER; + + prev_err = pZip->m_last_error; + + pZip->m_last_error = err_num; + return prev_err; +} + +mz_zip_error mz_zip_peek_last_error(mz_zip_archive *pZip) +{ + if (!pZip) + return MZ_ZIP_INVALID_PARAMETER; + + return pZip->m_last_error; +} + +mz_zip_error mz_zip_clear_last_error(mz_zip_archive *pZip) +{ + return mz_zip_set_last_error(pZip, MZ_ZIP_NO_ERROR); +} + +mz_zip_error mz_zip_get_last_error(mz_zip_archive *pZip) +{ + mz_zip_error prev_err; + + if (!pZip) + return MZ_ZIP_INVALID_PARAMETER; + + prev_err = pZip->m_last_error; + + pZip->m_last_error = MZ_ZIP_NO_ERROR; + return prev_err; +} + +const char *mz_zip_get_error_string(mz_zip_error mz_err) +{ + switch (mz_err) + { + case MZ_ZIP_NO_ERROR: + return "no error"; + case MZ_ZIP_UNDEFINED_ERROR: + return "undefined error"; + case MZ_ZIP_TOO_MANY_FILES: + return "too many files"; + case MZ_ZIP_FILE_TOO_LARGE: + return "file too large"; + case MZ_ZIP_UNSUPPORTED_METHOD: + return "unsupported method"; + case MZ_ZIP_UNSUPPORTED_ENCRYPTION: + return "unsupported encryption"; + case MZ_ZIP_UNSUPPORTED_FEATURE: + return "unsupported feature"; + case MZ_ZIP_FAILED_FINDING_CENTRAL_DIR: + return "failed finding central directory"; + case MZ_ZIP_NOT_AN_ARCHIVE: + return "not a ZIP archive"; + case MZ_ZIP_INVALID_HEADER_OR_CORRUPTED: + return "invalid header or archive is corrupted"; + case MZ_ZIP_UNSUPPORTED_MULTIDISK: + return "unsupported multidisk archive"; + case MZ_ZIP_DECOMPRESSION_FAILED: + return "decompression failed or archive is corrupted"; + case MZ_ZIP_COMPRESSION_FAILED: + return "compression failed"; + case MZ_ZIP_UNEXPECTED_DECOMPRESSED_SIZE: + return "unexpected decompressed size"; + case MZ_ZIP_CRC_CHECK_FAILED: + return "CRC-32 check failed"; + case MZ_ZIP_UNSUPPORTED_CDIR_SIZE: + return "unsupported central directory size"; + case MZ_ZIP_ALLOC_FAILED: + return "allocation failed"; + case MZ_ZIP_FILE_OPEN_FAILED: + return "file open failed"; + case MZ_ZIP_FILE_CREATE_FAILED: + return "file create failed"; + case MZ_ZIP_FILE_WRITE_FAILED: + return "file write failed"; + case MZ_ZIP_FILE_READ_FAILED: + return "file read failed"; + case MZ_ZIP_FILE_CLOSE_FAILED: + return "file close failed"; + case MZ_ZIP_FILE_SEEK_FAILED: + return "file seek failed"; + case MZ_ZIP_FILE_STAT_FAILED: + return "file stat failed"; + case MZ_ZIP_INVALID_PARAMETER: + return "invalid parameter"; + case MZ_ZIP_INVALID_FILENAME: + return "invalid filename"; + case MZ_ZIP_BUF_TOO_SMALL: + return "buffer too small"; + case MZ_ZIP_INTERNAL_ERROR: + return "internal error"; + case MZ_ZIP_FILE_NOT_FOUND: + return "file not found"; + case MZ_ZIP_ARCHIVE_TOO_LARGE: + return "archive is too large"; + case MZ_ZIP_VALIDATION_FAILED: + return "validation failed"; + case MZ_ZIP_WRITE_CALLBACK_FAILED: + return "write calledback failed"; + default: + break; + } + + return "unknown error"; +} + +/* Note: Just because the archive is not zip64 doesn't necessarily mean it doesn't have Zip64 extended information extra field, argh. */ +mz_bool mz_zip_is_zip64(mz_zip_archive *pZip) +{ + if ((!pZip) || (!pZip->m_pState)) + return MZ_FALSE; + + return pZip->m_pState->m_zip64; +} + +size_t mz_zip_get_central_dir_size(mz_zip_archive *pZip) +{ + if ((!pZip) || (!pZip->m_pState)) + return 0; + + return pZip->m_pState->m_central_dir.m_size; +} + +mz_uint mz_zip_reader_get_num_files(mz_zip_archive *pZip) +{ + return pZip ? pZip->m_total_files : 0; +} + +mz_uint64 mz_zip_get_archive_size(mz_zip_archive *pZip) +{ + if (!pZip) + return 0; + return pZip->m_archive_size; +} + +mz_uint64 mz_zip_get_archive_file_start_offset(mz_zip_archive *pZip) +{ + if ((!pZip) || (!pZip->m_pState)) + return 0; + return pZip->m_pState->m_file_archive_start_ofs; +} + +MZ_FILE *mz_zip_get_cfile(mz_zip_archive *pZip) +{ + if ((!pZip) || (!pZip->m_pState)) + return 0; + return pZip->m_pState->m_pFile; +} + +size_t mz_zip_read_archive_data(mz_zip_archive *pZip, mz_uint64 file_ofs, void *pBuf, size_t n) +{ + if ((!pZip) || (!pZip->m_pState) || (!pBuf) || (!pZip->m_pRead)) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + + return pZip->m_pRead(pZip->m_pIO_opaque, file_ofs, pBuf, n); +} + +mz_uint mz_zip_reader_get_filename(mz_zip_archive *pZip, mz_uint file_index, char *pFilename, mz_uint filename_buf_size) +{ + mz_uint n; + const mz_uint8 *p = mz_zip_get_cdh(pZip, file_index); + if (!p) + { + if (filename_buf_size) + pFilename[0] = '\0'; + mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + return 0; + } + n = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS); + if (filename_buf_size) + { + n = MZ_MIN(n, filename_buf_size - 1); + memcpy(pFilename, p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, n); + pFilename[n] = '\0'; + } + return n + 1; +} + +mz_bool mz_zip_reader_file_stat(mz_zip_archive *pZip, mz_uint file_index, mz_zip_archive_file_stat *pStat) +{ + return mz_zip_file_stat_internal(pZip, file_index, mz_zip_get_cdh(pZip, file_index), pStat, NULL); +} + +mz_bool mz_zip_end(mz_zip_archive *pZip) +{ + if (!pZip) + return MZ_FALSE; + + if (pZip->m_zip_mode == MZ_ZIP_MODE_READING) + return mz_zip_reader_end(pZip); +#ifndef MINIZ_NO_ARCHIVE_WRITING_APIS + else if ((pZip->m_zip_mode == MZ_ZIP_MODE_WRITING) || (pZip->m_zip_mode == MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED)) + return mz_zip_writer_end(pZip); +#endif + + return MZ_FALSE; +} + +#ifdef __cplusplus +} +#endif + +#endif /*#ifndef MINIZ_NO_ARCHIVE_APIS*/ diff --git a/tools/flasher_stub/run_tests_with_stub.sh b/tools/flasher_stub/run_tests_with_stub.sh new file mode 100755 index 0000000000..bb1b07a492 --- /dev/null +++ b/tools/flasher_stub/run_tests_with_stub.sh @@ -0,0 +1,10 @@ +#!/bin/sh +# +# Run "pytest test/test_esptool.py" using the newly compiled stub, for quick tests +# +# Usage same as "pytest test/test_esptool.py --port --chip --baud " + +THISDIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) + +export ESPTOOL_PY="${THISDIR}/esptool_test_stub.py" +pytest ${THISDIR}/../test/test_esptool.py $@ diff --git a/tools/flasher_stub/slip.c b/tools/flasher_stub/slip.c new file mode 100644 index 0000000000..ddd8f265ee --- /dev/null +++ b/tools/flasher_stub/slip.c @@ -0,0 +1,94 @@ +/* + * SPDX-FileCopyrightText: 2016 Cesanta Software Limited + * + * SPDX-License-Identifier: GPL-2.0-or-later + * + * SPDX-FileContributor: 2016-2022 Espressif Systems (Shanghai) CO LTD + */ + +#include +#include "slip.h" +#include "stub_io.h" + +void SLIP_send_frame_delimiter(void) { + stub_tx_one_char('\xc0'); +} + +void SLIP_send_frame_data(char ch) { + if(ch == '\xc0') { + stub_tx_one_char('\xdb'); + stub_tx_one_char('\xdc'); + } else if (ch == '\xdb') { + stub_tx_one_char('\xdb'); + stub_tx_one_char('\xdd'); + } else { + stub_tx_one_char(ch); + } +} + +void SLIP_send_frame_data_buf(const void *buf, uint32_t size) { + const uint8_t *buf_c = (const uint8_t *)buf; + for(int i = 0; i < size; i++) { + SLIP_send_frame_data(buf_c[i]); + } +} + +void SLIP_send(const void *pkt, uint32_t size) { + SLIP_send_frame_delimiter(); + SLIP_send_frame_data_buf(pkt, size); + SLIP_send_frame_delimiter(); +} + +int16_t SLIP_recv_byte(char byte, slip_state_t *state) +{ + if (byte == '\xc0') { + if (*state == SLIP_NO_FRAME) { + *state = SLIP_FRAME; + return SLIP_NO_BYTE; + } else { + *state = SLIP_NO_FRAME; + return SLIP_FINISHED_FRAME; + } + } + + switch(*state) { + case SLIP_NO_FRAME: + return SLIP_NO_BYTE; + case SLIP_FRAME: + if (byte == '\xdb') { + *state = SLIP_FRAME_ESCAPING; + return SLIP_NO_BYTE; + } + return byte; + case SLIP_FRAME_ESCAPING: + if (byte == '\xdc') { + *state = SLIP_FRAME; + return '\xc0'; + } + if (byte == '\xdd') { + *state = SLIP_FRAME; + return '\xdb'; + } + return SLIP_NO_BYTE; /* actually a framing error */ + } + return SLIP_NO_BYTE; /* actually a framing error */ +} + +/* This function is needed for the synchornous I/O case, + * which is only flash_read command at the moment. + */ +uint32_t SLIP_recv(void *pkt, uint32_t max_len) { + uint32_t len = 0; + slip_state_t state = SLIP_NO_FRAME; + uint8_t *p = (uint8_t *) pkt; + + int16_t r; + do { + r = SLIP_recv_byte(stub_rx_one_char(), &state); + if(r >= 0 && len < max_len) { + p[len++] = (uint8_t)r; + } + } while(r != SLIP_FINISHED_FRAME); + + return len; +} diff --git a/tools/flasher_stub/stub_commands.c b/tools/flasher_stub/stub_commands.c new file mode 100644 index 0000000000..de71639b94 --- /dev/null +++ b/tools/flasher_stub/stub_commands.c @@ -0,0 +1,325 @@ +/* + * SPDX-FileCopyrightText: 2019-2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include +#include "stub_commands.h" +#include "stub_write_flash.h" +#include "stub_flasher.h" +#include "rom_functions.h" +#include "slip.h" +#include "soc_support.h" +#include "stub_io.h" + +#if (ESP32S3 && !ESP32S3BETA2) || ESP32P4 +static esp_rom_spiflash_result_t SPIRead4B(int spi_num, uint32_t flash_addr, uint8_t* buf, int len) +{ + uint8_t cmd_len = 8; + + esp_rom_spiflash_wait_idle(); + while (len > 0) { + int rd_length; + if (len > 16 ) { //16 = read_sub_len + rd_length = 16; + } else { + rd_length = len; + } + esp_rom_opiflash_exec_cmd(spi_num, SPI_FLASH_FASTRD_MODE, + CMD_FSTRD4B, cmd_len, + flash_addr, 32, + 8, + NULL, 0, + buf, 8 * rd_length, + ESP_ROM_OPIFLASH_SEL_CS0, + false); + + len -= rd_length; + buf += rd_length; + flash_addr += rd_length; + } + return ESP_ROM_SPIFLASH_RESULT_OK; +} +#endif // ESP32S3 + +int handle_flash_erase(uint32_t addr, uint32_t len) { + if (addr % FLASH_SECTOR_SIZE != 0) return 0x32; + if (len % FLASH_SECTOR_SIZE != 0) return 0x33; + if (SPIUnlock() != 0) return 0x34; + + while (len > 0 && (addr % FLASH_BLOCK_SIZE != 0)) { + #if defined(ESP32S3) && !defined(ESP32S3BETA2) + if (large_flash_mode) { + if (esp_rom_opiflash_erase_sector(addr / FLASH_SECTOR_SIZE) != 0) return 0x35; + } else { + if (SPIEraseSector(addr / FLASH_SECTOR_SIZE) != 0) return 0x35; + } + #elif ESP32P4 + if (large_flash_mode) { + spi_write_enable(); + esp_rom_spiflash_wait_idle(); + esp_rom_opiflash_exec_cmd(1, SPI_FLASH_SLOWRD_MODE, + CMD_SECTOR_ERASE_4B, 8, + addr, 32, + 0, + NULL, 0, + NULL, 0, + 1, + true); + } else { + if (SPIEraseSector(addr / FLASH_SECTOR_SIZE) != 0) return 0x35; + } + #else + if (SPIEraseSector(addr / FLASH_SECTOR_SIZE) != 0) return 0x35; + #endif // ESP32S3 + len -= FLASH_SECTOR_SIZE; + addr += FLASH_SECTOR_SIZE; + } + + while (len > FLASH_BLOCK_SIZE) { + #if defined(ESP32S3) && !defined(ESP32S3BETA2) + if (large_flash_mode) { + if (esp_rom_opiflash_erase_block_64k(addr / FLASH_BLOCK_SIZE) != 0) return 0x36; + } else { + if (SPIEraseBlock(addr / FLASH_BLOCK_SIZE) != 0) return 0x36; + } + #elif ESP32P4 + if (large_flash_mode) { + spi_write_enable(); + esp_rom_spiflash_wait_idle(); + esp_rom_opiflash_exec_cmd(1, SPI_FLASH_SLOWRD_MODE, + CMD_LARGE_BLOCK_ERASE_4B, 8, + addr, 32, + 0, + NULL, 0, + NULL, 0, + 1, + true); + } else { + if (SPIEraseBlock(addr / FLASH_BLOCK_SIZE) != 0) return 0x36; + } + #else + if (SPIEraseBlock(addr / FLASH_BLOCK_SIZE) != 0) return 0x36; + #endif // ESP32S3 + len -= FLASH_BLOCK_SIZE; + addr += FLASH_BLOCK_SIZE; + } + + while (len > 0) { + #if defined(ESP32S3) && !defined(ESP32S3BETA2) + if (large_flash_mode) { + if (esp_rom_opiflash_erase_sector(addr / FLASH_SECTOR_SIZE) != 0) return 0x37; + } else { + if (SPIEraseSector(addr / FLASH_SECTOR_SIZE) != 0) return 0x37; + } + #elif ESP32P4 + if (large_flash_mode) { + spi_write_enable(); + esp_rom_spiflash_wait_idle(); + esp_rom_opiflash_exec_cmd(1, SPI_FLASH_SLOWRD_MODE, + CMD_SECTOR_ERASE_4B, 8, + addr, 32, + 0, + NULL, 0, + NULL, 0, + 1, + true); + } else { + if (SPIEraseSector(addr / FLASH_SECTOR_SIZE) != 0) return 0x35; + } + #else + if (SPIEraseSector(addr / FLASH_SECTOR_SIZE) != 0) return 0x37; + #endif // ESP32S3 + len -= FLASH_SECTOR_SIZE; + addr += FLASH_SECTOR_SIZE; + } + + return 0; +} + +void handle_flash_read(uint32_t addr, uint32_t len, uint32_t block_size, + uint32_t max_in_flight) { + uint8_t buf[FLASH_SECTOR_SIZE]; + uint8_t digest[16]; + struct MD5Context ctx; + uint32_t num_sent = 0, num_acked = 0; + uint8_t res = 0; + + /* This is one routine where we still do synchronous I/O */ + stub_rx_async_enable(false); + + if (block_size > sizeof(buf)) { + return; + } + MD5Init(&ctx); + while (num_acked < len && num_acked <= num_sent) { + while (num_sent < len && num_sent - num_acked < max_in_flight) { + uint32_t n = len - num_sent; + if (n > block_size) n = block_size; + #if (ESP32S3 && !ESP32S3BETA2) || ESP32P4 + if (large_flash_mode) { + res = SPIRead4B(1, addr, buf, n); + } else { + res = SPIRead(addr, (uint32_t *)buf, n); + } + #else + res = SPIRead(addr, (uint32_t *)buf, n); + #endif // ESP32S3 + if (res != 0) { + break; + } + SLIP_send(buf, n); + MD5Update(&ctx, buf, n); + addr += n; + num_sent += n; + } + int r = SLIP_recv(&num_acked, sizeof(num_acked)); + if (r != 4) { + break; + } + } + MD5Final(digest, &ctx); + SLIP_send(digest, sizeof(digest)); + + /* Go back to async RX */ + stub_rx_async_enable(true); +} + +int handle_flash_get_md5sum(uint32_t addr, uint32_t len) { + uint8_t buf[FLASH_SECTOR_SIZE]; + uint8_t digest[16]; + uint8_t res = 0; + struct MD5Context ctx; + MD5Init(&ctx); + while (len > 0) { + uint32_t n = len; + if (n > FLASH_SECTOR_SIZE) { + n = FLASH_SECTOR_SIZE; + } + #if (ESP32S3 && !ESP32S3BETA2) || ESP32P4 + if (large_flash_mode) { + res = SPIRead4B(1, addr, buf, n); + } else { + res = SPIRead(addr, (uint32_t *)buf, n); + } + #else + res = SPIRead(addr, (uint32_t *)buf, n); + #endif // ESP32S3 + if (res != 0) { + return 0x63; + } + MD5Update(&ctx, buf, n); + addr += n; + len -= n; + } + MD5Final(digest, &ctx); + /* ESP32 ROM sends as hex, but we just send raw bytes - esptool.py can handle either. */ + SLIP_send_frame_data_buf(digest, sizeof(digest)); + return 0; +} + +esp_command_error handle_spi_set_params(uint32_t *args, int *status) +{ + *status = SPIParamCfg(args[0], args[1], args[2], args[3], args[4], args[5]); + return *status ? ESP_FAILED_SPI_OP : ESP_OK; +} + +esp_command_error handle_spi_attach(uint32_t hspi_config_arg) +{ +#ifdef ESP8266 + /* ESP8266 doesn't yet support SPI flash on HSPI, but could: + see https://github.com/themadinventor/esptool/issues/98 */ + SelectSpiFunction(); +#else + /* Stub calls spi_flash_attach automatically when it boots, + therefore, we need to "unattach" the flash before attaching again + with different configuration to avoid issues. */ + + // Configure the SPI flash pins back as classic GPIOs + PIN_FUNC_SELECT(PERIPHS_IO_MUX_SPICLK_U, FUNC_GPIO); + PIN_FUNC_SELECT(PERIPHS_IO_MUX_SPIQ_U, FUNC_GPIO); + PIN_FUNC_SELECT(PERIPHS_IO_MUX_SPID_U, FUNC_GPIO); + PIN_FUNC_SELECT(PERIPHS_IO_MUX_SPICS0_U, FUNC_GPIO); + + /* spi_flash_attach calls SelectSpiFunction() and another + function to initialise SPI flash interface. + + Second argument 'legacy' mode is not currently supported. + */ + spi_flash_attach(hspi_config_arg, 0); +#endif + return ESP_OK; /* neither function/attach command takes an arg */ +} + +static uint32_t *mem_offset; +static uint32_t mem_remaining; + +esp_command_error handle_mem_begin(uint32_t size, uint32_t offset) +{ + mem_offset = (uint32_t *)offset; + mem_remaining = size; + return ESP_OK; +} + +esp_command_error handle_mem_data(void *data, uint32_t length) +{ + uint32_t *data_words = (uint32_t *)data; + if (mem_offset == NULL && length > 0) { + return ESP_NOT_IN_FLASH_MODE; + } + if (length > mem_remaining) { + return ESP_TOO_MUCH_DATA; + } + if (length % 4 != 0) { + return ESP_BAD_DATA_LEN; + } + + for(int i = 0; i < length; i+= 4) { + *mem_offset++ = *data_words++; + mem_remaining -= 4; + } + return ESP_OK; +} + +esp_command_error handle_mem_finish() +{ + esp_command_error res = mem_remaining > 0 ? ESP_NOT_ENOUGH_DATA : ESP_OK; + mem_remaining = 0; + mem_offset = NULL; + return res; +} + +esp_command_error handle_write_reg(const write_reg_args_t *cmds, uint32_t num_commands) +{ + for (uint32_t i = 0; i < num_commands; i++) { + const write_reg_args_t *cmd = &cmds[i]; + ets_delay_us(cmd->delay_us); + uint32_t v = cmd->value & cmd->mask; + if (cmd->mask != UINT32_MAX) { + v |= READ_REG(cmd->addr) & ~cmd->mask; + } + WRITE_REG(cmd->addr, v); + } + return ESP_OK; +} + +#if ESP32S2_OR_LATER +esp_command_error handle_get_security_info() +{ + uint8_t buf[SECURITY_INFO_BYTES]; + esp_command_error ret; + + #ifdef ESP32C3 + if (_rom_eco_version >= 7) + ret = GetSecurityInfoProcNewEco(NULL, NULL, buf); + else + ret = GetSecurityInfoProc(NULL, NULL, buf); + #else + ret = GetSecurityInfoProc(NULL, NULL, buf); + #endif // ESP32C3 + if (ret == ESP_OK) + SLIP_send_frame_data_buf(buf, sizeof(buf)); + return ret; +} +#endif // ESP32S2_OR_LATER diff --git a/tools/flasher_stub/stub_flasher.c b/tools/flasher_stub/stub_flasher.c new file mode 100644 index 0000000000..97434850ff --- /dev/null +++ b/tools/flasher_stub/stub_flasher.c @@ -0,0 +1,575 @@ +/* + * SPDX-FileCopyrightText: 2016 Cesanta Software Limited + * + * SPDX-License-Identifier: GPL-2.0-or-later + * + * SPDX-FileContributor: 2016-2022 Espressif Systems (Shanghai) CO LTD + */ + +/* + * Main flasher stub logic + * + * This stub uses the same SLIP framing and basic command/response structure + * as the in-ROM flasher program, but with some enhanced + * functions and also standardizes the flasher features between different chips. + * + * Actual command handlers are implemented in stub_commands.c + */ +#include +#include "stub_flasher.h" +#include "rom_functions.h" +#include "slip.h" +#include "stub_commands.h" +#include "stub_write_flash.h" +#include "stub_io.h" +#include "soc_support.h" + +/* Buffers for reading from UART. Data is read double-buffered, so + we can read into one buffer while handling data from the other one + (used for flashing throughput.) */ +typedef struct { + uint8_t buf_a[MAX_WRITE_BLOCK+64]; + uint8_t buf_b[MAX_WRITE_BLOCK+64]; + volatile uint8_t *reading_buf; /* Pointer to buf_a, or buf_b - which are we reading_buf? */ + uint16_t read; /* how many bytes have we read in the frame */ + slip_state_t state; + esp_command_req_t *command; /* Pointer to buf_a or buf_b as latest command received */ +} uart_buf_t; +static volatile uart_buf_t ub; + +/* esptool protocol "checksum" is XOR of 0xef and each byte of + data payload. */ +static uint8_t calculate_checksum(uint8_t *buf, int length) +{ + uint8_t res = 0xef; + for(int i = 0; i < length; i++) { + res ^= buf[i]; + } + return res; +} + +#if ESP32P4 +void esp_rom_opiflash_exec_cmd(int spi_num, SpiFlashRdMode mode, + uint32_t cmd, int cmd_bit_len, + uint32_t addr, int addr_bit_len, + int dummy_bits, + uint8_t* mosi_data, int mosi_bit_len, + uint8_t* miso_data, int miso_bit_len, + uint32_t cs_mask, + bool is_write_erase_operation) +{ + + if (_rom_eco_version == 2) { + esp_rom_opiflash_exec_cmd_eco2(spi_num, mode, + cmd, cmd_bit_len, + addr, addr_bit_len, + dummy_bits, + mosi_data, mosi_bit_len, + miso_data, miso_bit_len, + cs_mask, + is_write_erase_operation); + } else { + esp_rom_opiflash_exec_cmd_eco1(spi_num, mode, + cmd, cmd_bit_len, + addr, addr_bit_len, + dummy_bits, + mosi_data, mosi_bit_len, + miso_data, miso_bit_len, + cs_mask, + is_write_erase_operation); + } +} +#endif // ESP32P4 + +#if USE_MAX_CPU_FREQ +static bool can_use_max_cpu_freq() +{ + /* Check if any of available USB modes are being used. */ + #if WITH_USB_OTG && !WITH_USB_JTAG_SERIAL + return stub_uses_usb_otg(); + #elif !WITH_USB_OTG && WITH_USB_JTAG_SERIAL + return stub_uses_usb_jtag_serial(); + #elif WITH_USB_OTG && WITH_USB_JTAG_SERIAL + return stub_uses_usb_otg() || stub_uses_usb_jtag_serial(); + #else + return false; + #endif +} + +#if ESP32C61 || ESP32C6 || ESP32H2 || ESP32C5 || ESP32C5BETA3 +static uint32_t pcr_sysclk_conf_reg = 0; +#else +static uint32_t cpu_per_conf_reg = 0; +static uint32_t sysclk_conf_reg = 0; +#endif + +static void set_max_cpu_freq() +{ + if (can_use_max_cpu_freq()) + { + /* Set CPU frequency to max. This also increases SPI speed. */ + #if ESP32C61 || ESP32C6 || ESP32H2 || ESP32C5 || ESP32C5BETA3 + pcr_sysclk_conf_reg = READ_REG(PCR_SYSCLK_CONF_REG); + WRITE_REG(PCR_SYSCLK_CONF_REG, (pcr_sysclk_conf_reg & ~PCR_SOC_CLK_SEL_M) | (PCR_SOC_CLK_MAX << PCR_SOC_CLK_SEL_S)); + #else + cpu_per_conf_reg = READ_REG(SYSTEM_CPU_PER_CONF_REG); + sysclk_conf_reg = READ_REG(SYSTEM_SYSCLK_CONF_REG); + WRITE_REG(SYSTEM_SYSCLK_CONF_REG, (sysclk_conf_reg & ~SYSTEM_SOC_CLK_SEL_M) | (SYSTEM_SOC_CLK_MAX << SYSTEM_SOC_CLK_SEL_S)); + ets_delay_us(100); /* Leave some time for the change to settle, needed for ESP32-S3 */ + WRITE_REG(SYSTEM_CPU_PER_CONF_REG, (cpu_per_conf_reg & ~SYSTEM_CPUPERIOD_SEL_M) | (SYSTEM_CPUPERIOD_MAX << SYSTEM_CPUPERIOD_SEL_S)); + #endif + } +} + +static void reset_cpu_freq() +{ + /* Restore saved sysclk_conf and cpu_per_conf registers. + Use only if set_max_cpu_freq() has been called. */ + #if ESP32C61 || ESP32C6 || ESP32H2 || ESP32C5 || ESP32C5BETA3 + if (can_use_max_cpu_freq() && pcr_sysclk_conf_reg != 0) + { + WRITE_REG(PCR_SYSCLK_CONF_REG, (READ_REG(PCR_SYSCLK_CONF_REG) & ~PCR_SOC_CLK_SEL_M) | (pcr_sysclk_conf_reg & PCR_SOC_CLK_SEL_M)); + } + #else + if (can_use_max_cpu_freq() && sysclk_conf_reg != 0 && cpu_per_conf_reg != 0) + { + WRITE_REG(SYSTEM_CPU_PER_CONF_REG, (READ_REG(SYSTEM_CPU_PER_CONF_REG) & ~SYSTEM_CPUPERIOD_SEL_M) | (cpu_per_conf_reg & SYSTEM_CPUPERIOD_SEL_M)); + WRITE_REG(SYSTEM_SYSCLK_CONF_REG, (READ_REG(SYSTEM_SYSCLK_CONF_REG) & ~SYSTEM_SOC_CLK_SEL_M) | (sysclk_conf_reg & SYSTEM_SOC_CLK_SEL_M)); + } + #endif +} +#endif // USE_MAX_CPU_FREQ + +#if WITH_USB_JTAG_SERIAL +static void disable_watchdogs() +{ + if (stub_uses_usb_jtag_serial()) + { + WRITE_REG(RTC_CNTL_WDTWPROTECT_REG, RTC_CNTL_WDT_WKEY); // Disable write protection + WRITE_REG(RTC_CNTL_WDTCONFIG0_REG, 0x0); // Disable RTC watchdog + WRITE_REG(RTC_CNTL_WDTWPROTECT_REG, 0x0); // Re-enable write protection + + WRITE_REG(RTC_CNTL_SWD_WPROTECT_REG, RTC_CNTL_SWD_WKEY); // Disable write protection + REG_SET_MASK(RTC_CNTL_SWD_CONF_REG, RTC_CNTL_SWD_AUTO_FEED_EN); // Autofeed super watchdog + WRITE_REG(RTC_CNTL_SWD_WPROTECT_REG, 0x0); // Re-enable write protection + } +} +#endif // WITH_USB_JTAG_SERIAL + +#if (ESP32S3 && !ESP32S3BETA2) || ESP32P4 +bool large_flash_mode = false; + +bool flash_larger_than_16mb() +{ + uint32_t flash_id; + esp_rom_opiflash_exec_cmd(1, SPI_FLASH_FASTRD_MODE, + CMD_RDID, 8, + 0, 0, + 0, + NULL, 0, + (uint8_t *)&flash_id, 24, + ESP_ROM_OPIFLASH_SEL_CS0, + false); + + uint8_t flid_lowbyte = (flash_id >> 16) & 0xFF; + return ((flid_lowbyte >= 0x19 && flid_lowbyte < 0x30) || (flid_lowbyte >= 0x39)); // See DETECTED_FLASH_SIZES in esptool +} +#endif // (ESP32S3 && !ESP32S3BETA2) || ESP32P4 + +static void stub_handle_rx_byte(char byte) +{ + int16_t r = SLIP_recv_byte(byte, (slip_state_t *)&ub.state); + if (r >= 0) { + ub.reading_buf[ub.read++] = (uint8_t) r; + if (ub.read == MAX_WRITE_BLOCK+64) { + /* shouldn't happen unless there are data errors */ + r = SLIP_FINISHED_FRAME; + } + } + if (r == SLIP_FINISHED_FRAME) { + /* end of frame, set 'command' + to be processed by main thread */ + if(ub.reading_buf == ub.buf_a) { + ub.command = (esp_command_req_t *)ub.buf_a; + ub.reading_buf = ub.buf_b; + } else { + ub.command = (esp_command_req_t *)ub.buf_b; + ub.reading_buf = ub.buf_a; + } + ub.read = 0; + } +} + +static esp_command_error verify_data_len(esp_command_req_t *command, uint8_t len) +{ + return (command->data_len == len) ? ESP_OK : ESP_BAD_DATA_LEN; +} + +void cmd_loop() { + while(1) { + /* Wait for a command */ + while(ub.command == NULL) { + stub_io_idle_hook(); + } + esp_command_req_t *command = ub.command; + ub.command = NULL; + /* provide easy access for 32-bit data words */ + uint32_t *data_words = (uint32_t *)command->data_buf; + + /* Send command response header */ + esp_command_response_t resp = { + .resp = 1, + .op_ret = command->op, + .len_ret = 2, /* esptool.py checks this length */ + .value = 0, + }; + + /* Some commands need to set resp.len_ret or resp.value before it is sent back */ + switch(command->op) { + case ESP_READ_REG: + if (command->data_len == 4) { + resp.value = READ_REG(data_words[0]); + } + break; + case ESP_FLASH_VERIFY_MD5: + resp.len_ret = 16 + 2; /* Will sent 16 bytes of data with MD5 value */ + break; + #if ESP32S2_OR_LATER + case ESP_GET_SECURITY_INFO: + resp.len_ret = SECURITY_INFO_BYTES; /* Buffer size varies */ + break; + #endif // ESP32S2_OR_LATER + default: + break; + } + + /* Send the command response */ + SLIP_send_frame_delimiter(); + SLIP_send_frame_data_buf(&resp, sizeof(esp_command_response_t)); + + if(command->data_len > MAX_WRITE_BLOCK+16) { + SLIP_send_frame_data(ESP_BAD_DATA_LEN); + SLIP_send_frame_data(0xEE); + SLIP_send_frame_delimiter(); + continue; + } + + /* ... ESP_FLASH_VERIFY_MD5 and ESP_GET_SECURITY_INFO will insert + * in-frame response data between here and when we send the + * status bytes at the end of the frame */ + + esp_command_error error = ESP_CMD_NOT_IMPLEMENTED; + int status = 0; + + /* First stage of command processing - before sending error/status */ + switch (command->op) { + case ESP_SYNC: + /* Bootloader responds to the SYNC request with eight identical SYNC responses. Stub flasher should react + * the same way so SYNC could be possible with the flasher stub as well. This helps in cases when the chip + * cannot be reset and the flasher stub keeps running. */ + error = verify_data_len(command, 36); + + if (error == ESP_OK) { + /* resp.value remains 0 which esptool.py can use to detect the flasher stub */ + resp.value = 0; + for (int i = 0; i < 7; ++i) { + SLIP_send_frame_data(error); + SLIP_send_frame_data(status); + SLIP_send_frame_delimiter(); /* end the previous frame */ + + SLIP_send_frame_delimiter(); /* start new frame */ + SLIP_send_frame_data_buf(&resp, sizeof(esp_command_response_t)); + } + /* The last frame is ended outside of the "switch case" at the same place regular one-response frames are + * ended. */ + } + break; + #if ESP32S2_OR_LATER + case ESP_GET_SECURITY_INFO: + error = verify_data_len(command, 0) || handle_get_security_info(); + break; + #endif // ESP32S2_OR_LATER + case ESP_ERASE_FLASH: + error = verify_data_len(command, 0) || SPIEraseChip(); + break; + case ESP_ERASE_REGION: + /* Params for ERASE_REGION are addr, len */ + error = verify_data_len(command, 8) || handle_flash_erase(data_words[0], data_words[1]); + break; + case ESP_SET_BAUD: + /* ESP_SET_BAUD sends two args, new and old baud rates */ + error = verify_data_len(command, 8); + /* actual baud setting happens after we send the reply */ + break; + case ESP_READ_FLASH: + error = verify_data_len(command, 16); + /* actual data is sent after we send the reply */ + break; + case ESP_FLASH_VERIFY_MD5: + /* unsure why the MD5 command has 4 params but we only pass 2 of them, + but this is in ESP32 ROM so we can't mess with it. + */ + error = verify_data_len(command, 16) || handle_flash_get_md5sum(data_words[0], data_words[1]); + break; + case ESP_FLASH_BEGIN: + /* parameters (interpreted differently to ROM flasher): + 0 - erase_size (used as total size to write) + 1 - num_blocks (ignored) + 2 - block_size (should be MAX_WRITE_BLOCK, relies on num_blocks * block_size >= erase_size) + 3 - offset (used as-is) + */ + if (command->data_len == 16 && data_words[2] > MAX_WRITE_BLOCK) { + error = ESP_BAD_BLOCKSIZE; + } else { + error = verify_data_len(command, 16) || handle_flash_begin(data_words[0], data_words[3]); + } + break; + case ESP_FLASH_DEFLATED_BEGIN: + /* parameters: + 0 - uncompressed size + 1 - num_blocks (based on compressed size) + 2 - block_size (should be MAX_WRITE_BLOCK, total bytes over serial = num_blocks * block_size) + 3 - offset (used as-is) + */ + if (command->data_len == 16 && data_words[2] > MAX_WRITE_BLOCK) { + error = ESP_BAD_BLOCKSIZE; + } else { + error = verify_data_len(command, 16) || handle_flash_deflated_begin(data_words[0], data_words[1] * data_words[2], data_words[3]); + } + break; + case ESP_FLASH_DATA: + case ESP_FLASH_DEFLATED_DATA: +#if !ESP8266 + case ESP_FLASH_ENCRYPT_DATA: +#endif + + /* ACK DATA commands immediately, then process them a few lines down, + allowing next command to buffer */ + if(is_in_flash_mode()) { + error = get_flash_error(); + int payload_len = command->data_len - 16; + if (data_words[0] != payload_len) { + /* First byte of data payload header is length (repeated) as a word */ + error = ESP_BAD_DATA_LEN; + } + uint8_t data_checksum = calculate_checksum(command->data_buf + 16, payload_len); + if (data_checksum != command->checksum) { + error = ESP_BAD_DATA_CHECKSUM; + } + } + else { + error = ESP_NOT_IN_FLASH_MODE; + } + break; + case ESP_FLASH_END: + case ESP_FLASH_DEFLATED_END: + error = handle_flash_end(); + break; + case ESP_SPI_SET_PARAMS: + /* data params: fl_id, total_size, block_size, sector_Size, page_size, status_mask */ + error = verify_data_len(command, 24) || handle_spi_set_params(data_words, &status); + break; + case ESP_SPI_ATTACH: + /* parameter is 'hspi mode' (0, 1 or a pin mask for ESP32. Ignored on ESP8266.) */ + error = verify_data_len(command, 4) || handle_spi_attach(data_words[0]); + break; + case ESP_WRITE_REG: + /* The write_reg command can pass multiple write operations in a sequence */ + if (command->data_len % sizeof(write_reg_args_t) != 0) { + error = ESP_BAD_DATA_LEN; + } else { + error = handle_write_reg((const write_reg_args_t *)data_words, command->data_len/sizeof(write_reg_args_t)); + } + break; + case ESP_READ_REG: + /* actual READ_REG operation happens higher up */ + error = verify_data_len(command, 4); + break; + case ESP_MEM_BEGIN: + error = verify_data_len(command, 16) || handle_mem_begin(data_words[0], data_words[3]); + break; + case ESP_MEM_DATA: + error = handle_mem_data(command->data_buf + 16, command->data_len - 16); + break; + case ESP_MEM_END: + error = verify_data_len(command, 8) || handle_mem_finish(); + break; + case ESP_RUN_USER_CODE: + /* Returning from here will run user code, ie standard boot process + + This command does not send a response. + */ + return; + } + + SLIP_send_frame_data(error); + SLIP_send_frame_data(status); + SLIP_send_frame_delimiter(); + + /* Some commands need to do things after after sending this response */ + if (error == ESP_OK) { + switch(command->op) { + case ESP_SET_BAUD: + stub_io_set_baudrate(data_words[1], data_words[0]); + break; + case ESP_READ_FLASH: + /* args are: offset, length, block_size, max_in_flight */ + handle_flash_read(data_words[0], data_words[1], data_words[2], + data_words[3]); + break; + case ESP_FLASH_DATA: + /* drop into flashing mode, discard 16 byte payload header */ + handle_flash_data(command->data_buf + 16, command->data_len - 16); + break; +#if !ESP8266 + case ESP_FLASH_ENCRYPT_DATA: + /* write encrypted data */ + handle_flash_encrypt_data(command->data_buf + 16, command->data_len -16); + break; +#endif + case ESP_FLASH_DEFLATED_DATA: + handle_flash_deflated_data(command->data_buf + 16, command->data_len - 16); + break; + case ESP_FLASH_DEFLATED_END: + case ESP_FLASH_END: + /* passing 0 as parameter for ESP_FLASH_END means reboot now */ + if (data_words[0] == 0) { + /* Flush the FLASH_END response before rebooting */ + stub_tx_flush(); + ets_delay_us(10000); + #if USE_MAX_CPU_FREQ + reset_cpu_freq(); + #endif // USE_MAX_CPU_FREQ + software_reset(); + } + break; + case ESP_MEM_END: + if (data_words[1] != 0) { + void (*entrypoint_fn)(void) = (void (*))data_words[1]; + /* Make sure the command response has been flushed out + of the UART before we run the new code */ + stub_tx_flush(); + ets_delay_us(1000); + /* this is a little different from the ROM loader, + which exits the loader routine and _then_ calls this + function. But for our purposes so far, having a bit of + extra stuff on the stack doesn't really matter. + */ + #if USE_MAX_CPU_FREQ + reset_cpu_freq(); + #endif // USE_MAX_CPU_FREQ + entrypoint_fn(); + } + break; + } + } + } +} + + +extern uint32_t _bss_start; +extern uint32_t _bss_end; + +void __attribute__((used)) stub_main(); + + +#ifdef ESP8266 +__asm__ ( + ".global stub_main_8266\n" + ".literal_position\n" + ".align 4\n" + "stub_main_8266:\n" +/* ESP8266 wrapper for "stub_main()" manipulates the return address in + * a0, so 'return' from here runs user code. + * + * After setting a0, we jump directly to stub_main_inner() which is a + * normal C function + * + * Adapted from similar approach used by Cesanta Software for ESP8266 + * flasher stub. + * + */ + "movi a0, 0x400010a8;" + "j stub_main;"); +#endif + +/* This function is called from stub_main, with return address + reset to point to user code. */ +void stub_main() +{ + const uint32_t greeting = 0x4941484f; /* OHAI */ + + /* This points to stub_main now, clear for next boot. */ + ets_set_user_start(0); + + /* Increase CPU frequency and flashing speed if supported. */ + #if USE_MAX_CPU_FREQ + set_max_cpu_freq(); + #endif // USE_MAX_CPU_FREQ + + /* Disable all watchdogs to prevent the chip from resetting during longer operations. */ + #if WITH_USB_JTAG_SERIAL + disable_watchdogs(); + #endif // WITH_USB_JTAG_SERIAL + + /* Zero the bss region. */ + for(uint32_t *p = &_bss_start; p < &_bss_end; p++) { + *p = 0; + } + + /* Send the OHAI greeting, stub will be reported as running. */ + SLIP_send(&greeting, 4); + + /* Configure the interrupts for receiving data from esptool on the host. */ + ub.reading_buf = ub.buf_a; + stub_io_init(&stub_handle_rx_byte); + + /* Configure default SPI flash functionality. + Can be overridden later by esptool.py. */ + #ifdef ESP8266 + SelectSpiFunction(); + spi_flash_attach(); + #else + #if SUPPORT_CONFIG_SPI + uint32_t spiconfig = ets_efuse_get_spiconfig(); + #else + uint32_t spiconfig = 0; + #endif // SUPPORT_CONFIG_SPI + uint32_t strapping = READ_REG(GPIO_STRAP_REG); + /* If GPIO1 (U0TXD) is pulled low and no other boot mode is + set in efuse, assume HSPI flash mode (same as normal boot) + */ + if (spiconfig == 0 && (strapping & 0x1c) == 0x08) { + spiconfig = 1; /* HSPI flash mode */ + } + spi_flash_attach(spiconfig, 0); + #endif // ESP8266 + + /* Initialize the OPI flash driver if supported. */ + #if ESP32S3 && !ESP32S3BETA2 + large_flash_mode = ets_efuse_flash_octal_mode() || flash_larger_than_16mb(); + + // Initialize OPI flash driver only when flash is detected octal or quad larger than 16MB. + // Otherwise, we don't need to initialize such a driver + if (large_flash_mode) { + static const esp_rom_opiflash_def_t flash_driver = OPIFLASH_DRIVER(); + esp_rom_opiflash_legacy_driver_init(&flash_driver); + esp_rom_opiflash_wait_idle(); + } + #elif ESP32P4 + large_flash_mode = flash_larger_than_16mb(); + #endif //ESP32S3 && !ESP32S3BETA2 + SPIParamCfg(0, FLASH_MAX_SIZE, FLASH_BLOCK_SIZE, FLASH_SECTOR_SIZE, + FLASH_PAGE_SIZE, FLASH_STATUS_MASK); + + /* Configurations are done, now run the loop to receive and handle commands. */ + cmd_loop(); + + /* If cmd_loop returns, it's due to ESP_RUN_USER_CODE command. */ + /* Decrease CPU frequency back to the saved value before the stub flasher returns. */ + #if USE_MAX_CPU_FREQ + reset_cpu_freq(); + #endif // USE_MAX_CPU_FREQ + + return; +} diff --git a/tools/flasher_stub/stub_io.c b/tools/flasher_stub/stub_io.c new file mode 100644 index 0000000000..c0e559b1fe --- /dev/null +++ b/tools/flasher_stub/stub_io.c @@ -0,0 +1,318 @@ +/* + * SPDX-FileCopyrightText: 2016 Cesanta Software Limited + * + * SPDX-License-Identifier: GPL-2.0-or-later + * + * SPDX-FileContributor: 2016-2022 Espressif Systems (Shanghai) CO LTD + */ + +#include +#include "stub_io.h" +#include "rom_functions.h" +#include "soc_support.h" + + +#define UART_RX_INTS (UART_RXFIFO_FULL_INT_ENA | UART_RXFIFO_TOUT_INT_ENA) + + +static void(*s_rx_cb_func)(char); +#ifdef WITH_USB_OTG +static uint32_t s_cdcacm_old_rts; +static volatile bool s_cdcacm_reset_requested; +static char s_cdcacm_txbuf[ACM_BYTES_PER_TX]; +static size_t s_cdcacm_txpos; +#endif // WITH_USB_OTG + + +void uart_isr(void *arg) { + uint32_t int_st = READ_REG(UART_INT_ST(0)); + while (1) { + uint32_t fifo_len = READ_REG(UART_STATUS(0)) & UART_RXFIFO_CNT_M; + if (fifo_len == 0) { + break; + } + while (fifo_len-- > 0) { + uint8_t byte = READ_REG(UART_FIFO(0)) & 0xff; + (*s_rx_cb_func)(byte); + } + } + WRITE_REG(UART_INT_CLR(0), int_st); +} + +#if WITH_USB_JTAG_SERIAL +bool stub_uses_usb_jtag_serial(void) +{ + UartDevice *uart = GetUartDevice(); + + /* buff_uart_no indicates which UART is used for SLIP communication) */ + return uart->buff_uart_no == UART_USB_JTAG_SERIAL; +} + +void jtag_serial_isr(void *arg) +{ + WRITE_REG(USB_DEVICE_INT_CLR_REG, USB_DEVICE_SERIAL_OUT_RECV_PKT_INT_CLR); //ack interrupt + while (READ_REG(USB_DEVICE_EP1_CONF_REG) & USB_DEVICE_SERIAL_OUT_EP_DATA_AVAIL) + { + uint8_t byte = READ_REG(USB_DEVICE_EP1_REG); + (*s_rx_cb_func)(byte); + } +} +#endif // WITH_USB_JTAG_SERIAL + +static void stub_configure_rx_uart(void) +{ + /* All UART reads come via uart_isr or jtag_serial_isr */ +#if WITH_USB_JTAG_SERIAL + if (stub_uses_usb_jtag_serial()) { + #if IS_RISCV + #if ESP32P4 || ESP32C5 || ESP32C61 + WRITE_REG(INTERRUPT_CORE0_USB_INTR_MAP_REG, ETS_USB_INUM + CLIC_EXT_INTR_NUM_OFFSET); + #else + WRITE_REG(INTERRUPT_CORE0_USB_INTR_MAP_REG, ETS_USB_INUM); // Route USB interrupt to CPU + #endif + esprv_intc_int_set_priority(ETS_USB_INUM, 1); + #else + WRITE_REG(INTERRUPT_CORE0_USB_DEVICE_INT_MAP_REG, ETS_USB_INUM); + #endif // IS_RISCV + ets_isr_attach(ETS_USB_INUM, jtag_serial_isr, NULL); + WRITE_REG(USB_DEVICE_INT_ENA_REG, USB_DEVICE_SERIAL_OUT_RECV_PKT_INT_ENA); + ets_isr_unmask(1 << ETS_USB_INUM); + return; + } +#endif // WITH_USB_JTAG_SERIAL + ets_isr_attach(ETS_UART0_INUM, uart_isr, NULL); + REG_SET_MASK(UART_INT_ENA(0), UART_RX_INTS); + ets_isr_unmask(1 << ETS_UART0_INUM); +} + +#ifdef WITH_USB_OTG + +void stub_cdcacm_cb(cdc_acm_device *dev, int status) +{ + if (status == ACM_STATUS_RX) { + while (cdc_acm_rx_fifo_cnt(uart_acm_dev) > 0) { + uint8_t c; + cdc_acm_fifo_read(uart_acm_dev, &c, 1); + (*s_rx_cb_func)((char) c); + } + } else if (status == ACM_STATUS_LINESTATE_CHANGED) { + uint32_t rts = 0; + cdc_acm_line_ctrl_get(dev, LINE_CTRL_RTS, &rts); + if (rts == 0 && s_cdcacm_old_rts == 1) { + s_cdcacm_reset_requested = true; + } + s_cdcacm_old_rts = rts; + } +} + +static void stub_cdcacm_flush(void) +{ + cdc_acm_fifo_fill(uart_acm_dev, (const uint8_t *) s_cdcacm_txbuf, s_cdcacm_txpos); + /* return value ignored — if bootloader fails to log something, proceed anyway */ + s_cdcacm_txpos = 0; +} + +static void stub_cdcacm_write_char(char ch) +{ + s_cdcacm_txbuf[s_cdcacm_txpos++] = ch; + if (ch == '\xc0' || s_cdcacm_txpos == sizeof(s_cdcacm_txbuf)) { + stub_cdcacm_flush(); + } +} + +bool stub_uses_usb_otg(void) +{ + UartDevice *uart = GetUartDevice(); + + /* buff_uart_no indicates which UART is used for SLIP communication) */ + return uart->buff_uart_no == UART_USB_OTG; +} + +#ifdef ESP32S3 +static void usb_dw_isr_handler_wrapper(void *arg) +{ + /* ISR handler wrapper added as a workaround for the failure of compressed flashing using USB OTG. + * + * LoadStoreException happens inside the first call of tinfl_decompress() where the a13 register gets corrupted by + * the address of usb_dw_isr_handler(). The corruption probably still happens with this workaround but because of + * the nested call another register window is used. + * + * Other possible workarounds: + * - wait at least 25 ms before the tinfl_decompress() so usb_dw_isr_handler() would finish and not corrupt the + * pointer inside of tinfl_decompress(), or + * - disable the USB interrupt during tinfl_decompress(). + */ + usb_dw_isr_handler(arg); +} +#else +#define usb_dw_isr_handler_wrapper usb_dw_isr_handler +#endif //ESP32S3 + +static void stub_configure_rx_usb(void) +{ + cdc_acm_line_ctrl_get(uart_acm_dev, LINE_CTRL_RTS, &s_cdcacm_old_rts); + #if ESP32S2 + intr_matrix_set(0, ETS_USB_INTR_SOURCE, ETS_USB_INUM); + #elif ESP32S3 + WRITE_REG(INTERRUPT_CORE0_USB_INTR_MAP_REG, ETS_USB_INUM); + #elif ESP32P4 + // Additional setting to solve missing DCONN event on ESP32P4 (IDF-9953). + REG_SET_MASK(HP_SYS_USBOTG20_CTRL_REG, 1 << 21); /* set HP_SYS_OTG_SUSPENDM */ + WRITE_REG(INTERRUPT_CORE0_USB_OTG_INT_MAP_REG, ETS_USB_INUM + CLIC_EXT_INTR_NUM_OFFSET); + esprv_intc_int_set_priority(ETS_USB_INUM, 1); + #endif + ets_isr_attach(ETS_USB_INUM, usb_dw_isr_handler_wrapper, NULL); + ets_isr_unmask(1 << ETS_USB_INUM); + cdc_acm_irq_callback_set(uart_acm_dev, &stub_cdcacm_cb); + cdc_acm_irq_rx_enable(uart_acm_dev); + cdc_acm_irq_state_enable(uart_acm_dev); + REG_SET_MASK(USB_GAHBCFG_REG, USB_GLBLLNTRMSK); +} +#endif // WITH_USB_OTG + +void stub_tx_one_char(char c) +{ +#if WITH_USB_OTG + if (stub_uses_usb_otg()) { + stub_cdcacm_write_char(c); + return; + } +#endif // WITH_USB_OTG + uart_tx_one_char(c); +#if WITH_USB_JTAG_SERIAL + static unsigned short transferred_without_flush = 0; + if (stub_uses_usb_jtag_serial()){ + // Defer flushing until we have a (full - 1) packet or a end of packet (0xc0) byte to increase throughput. + // Note that deferring flushing until we have a full packet can cause hang-ups on some platforms. + ++transferred_without_flush; + if (c == '\xc0' || transferred_without_flush >= 63) { + stub_tx_flush(); + transferred_without_flush = 0; + } + } +#endif // WITH_USB_JTAG_SERIAL +} + +void stub_tx_flush(void) +{ +#if WITH_USB_OTG + if (stub_uses_usb_otg()) { + if (s_cdcacm_txpos > 0) { + stub_cdcacm_flush(); + } + } +#endif // WITH_USB_OTG +#if WITH_USB_JTAG_SERIAL + if (stub_uses_usb_jtag_serial()){ + uart_tx_flush(UART_USB_JTAG_SERIAL); + return; + } +#endif // WITH_USB_JTAG_SERIAL +#if ESP32_OR_LATER + uart_tx_flush(0); +#endif +} + +char stub_rx_one_char(void) +{ + char c = 0; + /* Using uart_rx_one_char here instead of uart_rx_one_char_block, + * because the latter simply returns (char) 0 if no bytes + * are available, when used with USB CDC. + */ + while (uart_rx_one_char((uint8_t*) &c) != 0) { } + return c; +} + +void stub_rx_async_enable(bool enable) +{ + uint32_t mask; +#if WITH_USB_OTG + if (stub_uses_usb_otg()) { + mask = 1 << ETS_USB_INUM; + if (enable) { + cdc_acm_irq_rx_enable(uart_acm_dev); + ets_isr_unmask(mask); + } else { + ets_isr_mask(mask); + cdc_acm_irq_rx_disable(uart_acm_dev); + } + return; + } +#endif // WITH_USB_OTG +#if WITH_USB_JTAG_SERIAL + mask = stub_uses_usb_jtag_serial() ? 1 << ETS_USB_INUM : 1 << ETS_UART0_INUM; +#else + mask = 1 << ETS_UART0_INUM; +#endif + if (enable) { + ets_isr_unmask(mask); + } else { + ets_isr_mask(mask); + } +} + +void stub_io_idle_hook(void) +{ +#if WITH_USB_OTG + if (s_cdcacm_reset_requested) + { + s_cdcacm_reset_requested = false; + ets_isr_mask(1 << ETS_USB_INUM); + ets_delay_us(10000); + /* Handle the last few interrupts as they come in before the USB peripheral is idle */ + usb_dc_check_poll_for_interrupts(); + REG_CLR_MASK(RTC_CNTL_OPTION1_REG, RTC_CNTL_FORCE_DOWNLOAD_BOOT); + chip_usb_set_persist_flags(USBDC_PERSIST_ENA); + usb_dc_prepare_persist(); + software_reset_cpu(0); + } +#endif // WITH_USB_OTG +} + +void stub_io_init(void(*rx_cb_func)(char)) +{ + s_rx_cb_func = rx_cb_func; +#if WITH_USB_OTG + if (stub_uses_usb_otg()) { + stub_configure_rx_usb(); + return; + } +#endif // WITH_USB_OTG + stub_configure_rx_uart(); +} + +static uint32_t get_new_uart_divider(uint32_t current_baud, uint32_t new_baud) +{ + uint32_t master_freq; + /* ESP32 has ROM code to detect the crystal freq but ESP8266 does not have this... + So instead we use the previously auto-synced 115200 baud rate (which we know + is correct wrt the relative crystal accuracy of the ESP & the USB/serial adapter). + From this we can estimate crystal freq, and update for a new baud rate relative to that. + */ + uint32_t uart_reg = READ_REG(UART_CLKDIV_REG(0)); + uint32_t uart_div = uart_reg & UART_CLKDIV_M; +#if ESP32_OR_LATER + // account for fractional part of divider (bottom 4 bits) + uint32_t fraction = (uart_reg >> UART_CLKDIV_FRAG_S) & UART_CLKDIV_FRAG_V; + uart_div = (uart_div << 4) + fraction; +#endif + master_freq = uart_div * current_baud; + return master_freq / new_baud; +} + +void stub_io_set_baudrate(uint32_t current_baud, uint32_t new_baud) +{ +#if WITH_USB_OTG + /* Technically no harm in increasing UART baud rate when communicating over USB, + * however for debugging the USB part it is occasionally useful to ets_printf + * something to UART. Not changing the baud rate helps in such case. + */ + if (stub_uses_usb_otg()) { + return; + } +#endif // WITH_USB_OTG + ets_delay_us(10000); + uart_div_modify(0, get_new_uart_divider(current_baud, new_baud)); + ets_delay_us(1000); +} diff --git a/tools/flasher_stub/stub_write_flash.c b/tools/flasher_stub/stub_write_flash.c new file mode 100644 index 0000000000..55900f6eb9 --- /dev/null +++ b/tools/flasher_stub/stub_write_flash.c @@ -0,0 +1,640 @@ +/* + * SPDX-FileCopyrightText: 2016 Cesanta Software Limited + * + * SPDX-License-Identifier: GPL-2.0-or-later + * + * SPDX-FileContributor: 2016-2022 Espressif Systems (Shanghai) CO LTD + */ + +#include "soc_support.h" +#include "stub_write_flash.h" +#include "stub_flasher.h" +#include "rom_functions.h" +#include "miniz.h" + +/* local flashing state + + This is wrapped in a structure because gcc 4.8 + generates significantly more code for ESP32 + if they are static variables (literal pool, I think!) +*/ +static struct { + /* set by flash_begin, cleared by flash_end */ + bool in_flash_mode; + /* offset of next SPI write */ + uint32_t next_write; + /* sector number for next erase */ + int next_erase_sector; + /* number of output bytes remaining to write */ + uint32_t remaining; + /* number of sectors remaining to erase */ + int remaining_erase_sector; + /* last error generated by a data packet */ + esp_command_error last_error; + + /* inflator state for deflate write */ + tinfl_decompressor inflator; + /* number of compressed bytes remaining to read */ + uint32_t remaining_compressed; +} fs; + +/* SPI status bits */ +static const uint32_t STATUS_WIP_BIT = (1 << 0); +#if ESP32_OR_LATER +static const uint32_t STATUS_QIE_BIT = (1 << 9); /* Quad Enable */ +#endif + +bool is_in_flash_mode(void) +{ + return fs.in_flash_mode; +} + +esp_command_error get_flash_error(void) +{ + return fs.last_error; +} + +/* Wait for the SPI state machine to be ready, + ie no command in progress in the internal host. +*/ +inline static void spi_wait_ready(void) +{ + /* Wait for SPI state machine ready */ + while((READ_REG(SPI_EXT2_REG) & SPI_ST)) + { } +#if ESP32_OR_LATER + while(READ_REG(SPI0_EXT2_REG) & SPI_ST) + { } +#endif +} + +/* Returns true if the spiflash is ready for its next write + operation. + + Doesn't block, except for the SPI state machine to finish + any previous SPI host operation. +*/ +static bool spiflash_is_ready(void) +{ + spi_wait_ready(); + WRITE_REG(SPI_RD_STATUS_REG, 0); + /* Issue read status command */ + WRITE_REG(SPI_CMD_REG, SPI_FLASH_RDSR); + while(READ_REG(SPI_CMD_REG) != 0) + { } + uint32_t status_value = READ_REG(SPI_RD_STATUS_REG); + return (status_value & STATUS_WIP_BIT) == 0; +} + +void spi_write_enable(void) +{ + while(!spiflash_is_ready()) + { } + WRITE_REG(SPI_CMD_REG, SPI_FLASH_WREN); + while(READ_REG(SPI_CMD_REG) != 0) + { } +} + +#if ESP32_OR_LATER +static esp_rom_spiflash_chip_t *flashchip = (esp_rom_spiflash_chip_t *)ROM_SPIFLASH_LEGACY; + +/* Stub version of SPIUnlock() that replaces version in ROM. + + This works around a bug where SPIUnlock sometimes reads the wrong + high status byte (RDSR2 result) and then copies it back to the + flash status, causing lock bit CMP or Status Register Protect ` to + become set. + */ +SpiFlashOpResult SPIUnlock(void) +{ + uint32_t status; + + spi_wait_ready(); /* ROM SPI_read_status_high() doesn't wait for this */ +#if ESP32S2_OR_LATER + if (SPI_read_status_high(flashchip, &status) != SPI_FLASH_RESULT_OK) { + return SPI_FLASH_RESULT_ERR; + } +#else + if (SPI_read_status_high(&status) != SPI_FLASH_RESULT_OK) { + return SPI_FLASH_RESULT_ERR; + } +#endif // ESP32S2_OR_LATER + + /* Clear all bits except QIE, if it is set. + (This is different from ROM SPIUnlock, which keeps all bits as-is.) + */ + status &= STATUS_QIE_BIT; + + spi_write_enable(); + + REG_SET_MASK(SPI_CTRL_REG, SPI_WRSR_2B); + if (SPI_write_status(flashchip, status) != SPI_FLASH_RESULT_OK) { + return SPI_FLASH_RESULT_ERR; + } + + return SPI_FLASH_RESULT_OK; +} +#endif // ESP32_OR_LATER + +#if (ESP32S3 && !ESP32S3BETA2) || ESP32P4 +static esp_rom_spiflash_result_t page_program_internal(int spi_num, uint32_t spi_addr, uint8_t* addr_source, uint32_t byte_length) +{ + uint32_t temp_addr; + int32_t temp_bl; + esp_rom_spiflash_wait_idle(); + temp_addr = spi_addr; + temp_bl = byte_length; + uint32_t temp_len = 0; + + const uint16_t cmd = CMD_PROGRAM_PAGE_4B; + uint8_t cmd_len = 8; + int dummy = 0; + + while (temp_bl > 0 ) { + spi_write_enable(); + temp_len = (temp_bl >= 32) ? 32 : temp_bl; //32 = write_sub_len + esp_rom_opiflash_exec_cmd(spi_num, SPI_FLASH_FASTRD_MODE, + cmd, cmd_len, + temp_addr, 32, + dummy, + addr_source, 8 * temp_len, + NULL, 0, + ESP_ROM_OPIFLASH_SEL_CS0, + true); + esp_rom_spiflash_wait_idle(); + addr_source += temp_len; + temp_addr += temp_len; + temp_bl -= temp_len; + } + return ESP_ROM_SPIFLASH_RESULT_OK; +} + +static esp_rom_spiflash_result_t SPIWrite4B(int spi_num, uint32_t target, uint8_t *src_addr, int32_t len) +{ + uint32_t page_size = 256; + uint32_t pgm_len, pgm_num; + uint8_t i; + + esp_rom_spiflash_wait_idle(); + pgm_len = page_size - (target % page_size); + if (len < pgm_len) { + page_program_internal(spi_num, target, src_addr, len); + } else { + page_program_internal(spi_num, target, src_addr, pgm_len); + //whole page program + pgm_num = (len - pgm_len) / page_size; + for (i = 0; i < pgm_num; i++) { + page_program_internal(spi_num, target + pgm_len, (src_addr + pgm_len), page_size); + pgm_len += page_size; + } + //remain parts to program + page_program_internal(spi_num, target + pgm_len, (src_addr + pgm_len), len - pgm_len); + } + esp_rom_spiflash_wait_idle(); + return ESP_ROM_SPIFLASH_RESULT_OK; +} + +SpiFlashOpResult SPI_Encrypt_Write_4B(uint32_t flash_addr, const void* data, uint32_t len) { + const uint8_t *data_bytes = (const uint8_t *)data; + SpiFlashOpResult result = SPI_FLASH_RESULT_OK; + + if (flash_addr % 16 != 0 || len % 16 != 0) + { + // Minimum 128-bit size & alignment + return SPI_FLASH_RESULT_ERR; + } + + esp_rom_spiflash_write_encrypted_enable(); + + WRITE_REG(AES_XTS_DESTINATION_REG, 0); + + result = esp_rom_spiflash_unlock(); + if (result != SPI_FLASH_RESULT_OK) + { + goto done_encrypt_write_4B; + } + + while (len > 0) + { + int next_block; + int timeout = 0; + const int TIMEOUT_LIMIT = 100000; + int page_size = 256; + + // Write the largest block possible + if (flash_addr % 64 == 0 && len >= 64 && (page_size - flash_addr % page_size >= 64)) { + next_block = 64; + } + else if (flash_addr % 32 == 0 && len >= 32 && (page_size - flash_addr % page_size >= 32)) { + next_block = 32; + } + else { + next_block = 16; + } + + WRITE_REG(AES_XTS_SIZE_REG, next_block >> 5); // 0, 1, 2 + + uint32_t plaintext_offs = (flash_addr % MAX_ENCRYPT_BLOCK); + memcpy((void *)(AES_XTS_PLAIN_BASE + plaintext_offs), data_bytes, next_block); + + WRITE_REG(AES_XTS_PHYSICAL_ADDR_REG, flash_addr); + + // Perform the encryption + WRITE_REG(AES_XTS_TRIGGER_REG, 1); + + // Prepare the flash chip (same time as AES operation, for performance) + spi_write_enable(); + + // Wait for the encryption to finish + while (READ_REG(AES_XTS_STATE_REG) != 0x2 && timeout < TIMEOUT_LIMIT) { + timeout++; + } + if (timeout == TIMEOUT_LIMIT) { + result = SPI_FLASH_RESULT_TIMEOUT; + goto done_encrypt_write_4B; + } + + esp_rom_spiflash_wait_idle(); + + // Make the result visible to the SPI controller + WRITE_REG(AES_XTS_RELEASE_REG, 1); + + while (READ_REG(AES_XTS_STATE_REG) != 0x3 && timeout < TIMEOUT_LIMIT) { + timeout++; + } + if (timeout == TIMEOUT_LIMIT) { + result = SPI_FLASH_RESULT_TIMEOUT; + goto done_encrypt_write_4B; + } + + result = esp_rom_spiflash_wait_idle(); + if (result != SPI_FLASH_RESULT_OK) { + goto done_encrypt_write_4B; + } + + // Write the encrypted page to flash + esp_rom_opiflash_exec_cmd(1, SPI_FLASH_FASTRD_MODE, + CMD_PROGRAM_PAGE_4B, 8, + flash_addr, 32, // address is set in AES_XTS_PHYSICAL_ADDR_REG, only the length is actually needed + 0, + NULL, (8 * next_block - 1), // data is exposed by AES-XTS, just set the length + NULL, 0, + ESP_ROM_OPIFLASH_SEL_CS0, + true); + + WRITE_REG(AES_XTS_DESTROY_REG, 1); + + len -= next_block; + data_bytes += next_block; + flash_addr += next_block; + } + + result = esp_rom_spiflash_wait_idle(); + +done_encrypt_write_4B: + esp_rom_spiflash_write_encrypted_disable(); + return result; +} +#endif // (ESP32S3 && !ESP32S3BETA2) || ESP32P4 + +esp_command_error handle_flash_begin(uint32_t total_size, uint32_t offset) { + fs.in_flash_mode = true; + fs.next_write = offset; + fs.next_erase_sector = offset / FLASH_SECTOR_SIZE; + fs.remaining = total_size; + fs.remaining_erase_sector = ((offset % FLASH_SECTOR_SIZE) + total_size + FLASH_SECTOR_SIZE - 1) / FLASH_SECTOR_SIZE; + fs.last_error = ESP_OK; + +#if defined(ESP32S3) && !defined(ESP32S3BETA2) + if (large_flash_mode) { + esp_rom_opiflash_wait_idle(); + } else { + if (SPIUnlock() != 0) { + return ESP_FAILED_SPI_UNLOCK; + } + } +#else + if (SPIUnlock() != 0) { + return ESP_FAILED_SPI_UNLOCK; + } +#endif //defined(ESP32S3) and !defined(ESP32S3BETA2) + + return ESP_OK; +} + +esp_command_error handle_flash_deflated_begin(uint32_t uncompressed_size, uint32_t compressed_size, uint32_t offset) { + esp_command_error err = handle_flash_begin(uncompressed_size, offset); + tinfl_init(&fs.inflator); + fs.remaining_compressed = compressed_size; + return err; +} + +/* Erase the next sector or block (depending if we're at a block boundary). + + Updates fs.next_erase_sector & fs.remaining_erase_sector on success. + + If nothing left to erase, returns immediately. + + Returns immediately if SPI flash not yet ready for a write operation. + + Does not wait for the erase to complete - the next SPI operation + should check if a write operation is currently in progress. + */ +static void start_next_erase(void) +{ + bool block_erase = false; + + if(fs.remaining_erase_sector == 0) + return; /* nothing left to erase */ + if(!spiflash_is_ready()) + return; /* don't wait for flash to be ready, caller will call again if needed */ + + if(fs.remaining_erase_sector >= SECTORS_PER_BLOCK + && fs.next_erase_sector % SECTORS_PER_BLOCK == 0) { + /* perform a 64KB block erase if we have space for it */ + block_erase = true; + } + + spi_write_enable(); + spi_wait_ready(); + #if defined(ESP32S3) && !defined(ESP32S3BETA2) + if (large_flash_mode) { + if (block_erase) { + if (fs.next_erase_sector * FLASH_SECTOR_SIZE < (1 << 24)) { + esp_rom_opiflash_wait_idle(); + esp_rom_opiflash_wren(); + + esp_rom_opiflash_exec_cmd(1, SPI_FLASH_SLOWRD_MODE, + CMD_LARGE_BLOCK_ERASE, 8, + fs.next_erase_sector * FLASH_SECTOR_SIZE, 24, + 0, + NULL, 0, + NULL, 0, + 1, + true); + esp_rom_opiflash_wait_idle(); + } else { + esp_rom_opiflash_erase_block_64k(fs.next_erase_sector / SECTORS_PER_BLOCK); + } + } + else { + if (fs.next_erase_sector * FLASH_SECTOR_SIZE < (1 << 24)) { + esp_rom_opiflash_wait_idle(); + esp_rom_opiflash_wren(); + + esp_rom_opiflash_exec_cmd(1, SPI_FLASH_SLOWRD_MODE, + CMD_SECTOR_ERASE, 8, + fs.next_erase_sector * FLASH_SECTOR_SIZE, 24, + 0, + NULL, 0, + NULL, 0, + 1, + true); + esp_rom_opiflash_wait_idle(); + } else { + esp_rom_opiflash_erase_sector(fs.next_erase_sector); + } + } + } else { + uint32_t addr = fs.next_erase_sector * FLASH_SECTOR_SIZE; + uint32_t command = block_erase ? SPI_FLASH_BE : SPI_FLASH_SE; /* block erase, 64KB : sector erase, 4KB */ + WRITE_REG(SPI_ADDR_REG, addr & 0xffffff); + WRITE_REG(SPI_CMD_REG, command); + while(READ_REG(SPI_CMD_REG) != 0) { } + } + #elif ESP32P4 + if (large_flash_mode) { + esp_rom_spiflash_wait_idle(); + spi_write_enable(); + if (block_erase) { + if (fs.next_erase_sector * FLASH_SECTOR_SIZE < (1 << 24)) { + esp_rom_opiflash_exec_cmd(1, SPI_FLASH_SLOWRD_MODE, + CMD_LARGE_BLOCK_ERASE, 8, + fs.next_erase_sector * FLASH_SECTOR_SIZE, 24, + 0, + NULL, 0, + NULL, 0, + 1, + true); + } else { + esp_rom_opiflash_exec_cmd(1, SPI_FLASH_SLOWRD_MODE, + CMD_LARGE_BLOCK_ERASE_4B, 8, + fs.next_erase_sector * FLASH_SECTOR_SIZE, 32, + 0, + NULL, 0, + NULL, 0, + 1, + true); + } + } + else { + if (fs.next_erase_sector * FLASH_SECTOR_SIZE < (1 << 24)) { + esp_rom_opiflash_exec_cmd(1, SPI_FLASH_SLOWRD_MODE, + CMD_SECTOR_ERASE, 8, + fs.next_erase_sector * FLASH_SECTOR_SIZE, 24, + 0, + NULL, 0, + NULL, 0, + 1, + true); + } else { + esp_rom_opiflash_exec_cmd(1, SPI_FLASH_SLOWRD_MODE, + CMD_SECTOR_ERASE_4B, 8, + fs.next_erase_sector * FLASH_SECTOR_SIZE, 32, + 0, + NULL, 0, + NULL, 0, + 1, + true); + } + } + esp_rom_spiflash_wait_idle(); + } else { + uint32_t addr = fs.next_erase_sector * FLASH_SECTOR_SIZE; + uint32_t command = block_erase ? SPI_FLASH_BE : SPI_FLASH_SE; /* block erase, 64KB : sector erase, 4KB */ + WRITE_REG(SPI_ADDR_REG, addr & 0xffffff); + WRITE_REG(SPI_CMD_REG, command); + while(READ_REG(SPI_CMD_REG) != 0) { } + } + #else + uint32_t addr = fs.next_erase_sector * FLASH_SECTOR_SIZE; + uint32_t command = block_erase ? SPI_FLASH_BE : SPI_FLASH_SE; /* block erase, 64KB : sector erase, 4KB */ + WRITE_REG(SPI_ADDR_REG, addr & 0xffffff); + WRITE_REG(SPI_CMD_REG, command); + while(READ_REG(SPI_CMD_REG) != 0) { } + #endif // defined(ESP32S3) && !defined(ESP32S3BETA2) + + uint32_t sectors_to_erase = block_erase ? SECTORS_PER_BLOCK : 1; + fs.remaining_erase_sector -= sectors_to_erase; + fs.next_erase_sector += sectors_to_erase; +} + +/* Write data to flash (either direct for non-compressed upload, or + freshly decompressed.) Erases as it goes. + + Updates fs.remaining_erase_sector, fs.next_write, and fs.remaining +*/ +void handle_flash_data(void *data_buf, uint32_t length) { + int last_sector; + uint8_t res = 0; + + if (length > fs.remaining) { + /* Trim the final block, as it may have padding beyond + the length we are writing */ + length = fs.remaining; + } + + if (length == 0) { + return; + } + + /* what sector is this write going to end in? + make sure we've erased at least that far. + */ + last_sector = (fs.next_write + length) / FLASH_SECTOR_SIZE; + while(fs.remaining_erase_sector > 0 && fs.next_erase_sector <= last_sector) { + start_next_erase(); + } + while(!spiflash_is_ready()) + {} + + /* do the actual write */ + #if (ESP32S3 && !ESP32S3BETA2) || ESP32P4 + if (large_flash_mode){ + res = SPIWrite4B(1, fs.next_write, data_buf, length); + } else { + res = SPIWrite(fs.next_write, data_buf, length); + } + #else + res = SPIWrite(fs.next_write, data_buf, length); + #endif // defined(ESP32S3) && !defined(ESP32S3BETA2) + if (res != 0) + fs.last_error = ESP_FAILED_SPI_OP; + fs.next_write += length; + fs.remaining -= length; +} + +#if !ESP8266 +/* Write encrypted data to flash (either direct for non-compressed upload, or + freshly decompressed.) Erases as it goes. + + Updates fs.remaining_erase_sector, fs.next_write, and fs.remaining +*/ +void handle_flash_encrypt_data(void *data_buf, uint32_t length) { + int last_sector; + int res; + +#if ESP32S2_OR_LATER + SPI_Write_Encrypt_Enable(); +#endif + + if (length > fs.remaining) { + /* Trim the final block, as it may have padding beyond + the length we are writing */ + length = fs.remaining; + } + + if (length == 0) { + return; + } + + /* what sector is this write going to end in? + make sure we've erased at least that far. + */ + last_sector = (fs.next_write + length) / FLASH_SECTOR_SIZE; + while(fs.remaining_erase_sector > 0 && fs.next_erase_sector <= last_sector) { + start_next_erase(); + } + while(!spiflash_is_ready()) + {} + + /* do the actual write */ +#if ESP32 + res = esp_rom_spiflash_write_encrypted(fs.next_write, data_buf, length); +#elif (ESP32S3 && !ESP32S3BETA2) || ESP32P4 + if (large_flash_mode){ + res = SPI_Encrypt_Write_4B(fs.next_write, data_buf, length); + } else { + res = SPI_Encrypt_Write(fs.next_write, data_buf, length); + } +#else + res = SPI_Encrypt_Write(fs.next_write, data_buf, length); +#endif + + if (res) { + fs.last_error = ESP_FAILED_SPI_OP; + } + fs.next_write += length; + fs.remaining -= length; + +#if ESP32S2_OR_LATER + SPI_Write_Encrypt_Disable(); +#endif +} + +#endif // !ESP8266 + +void handle_flash_deflated_data(void *data_buf, uint32_t length) { + /* if all data has been uploaded and another block comes, + accept it only if it is part of a 4-byte Adler-32 checksum */ + if (fs.remaining == 0 && length > 4) { + fs.last_error = ESP_TOO_MUCH_DATA; + return; + } + + static uint8_t out_buf[32768]; + static uint8_t *next_out = out_buf; + int status = TINFL_STATUS_NEEDS_MORE_INPUT; + + while(length > 0 && fs.remaining > 0 && status > TINFL_STATUS_DONE) { + size_t in_bytes = length; /* input remaining */ + size_t out_bytes = out_buf + sizeof(out_buf) - next_out; /* output space remaining */ + int flags = TINFL_FLAG_PARSE_ZLIB_HEADER; + if(fs.remaining_compressed > length) { + flags |= TINFL_FLAG_HAS_MORE_INPUT; + } + + /* start an opportunistic erase: decompressing takes time, so might as + well be running a SPI erase in the background. */ + start_next_erase(); + + status = tinfl_decompress(&fs.inflator, data_buf, &in_bytes, + out_buf, next_out, &out_bytes, + flags); + + fs.remaining_compressed -= in_bytes; + length -= in_bytes; + data_buf += in_bytes; + + next_out += out_bytes; + size_t bytes_in_out_buf = next_out - out_buf; + if (status == TINFL_STATUS_DONE || bytes_in_out_buf == sizeof(out_buf)) { + // Output buffer full, or done + handle_flash_data(out_buf, bytes_in_out_buf); + next_out = out_buf; + } + } // while + + if (status < TINFL_STATUS_DONE) { + /* error won't get sent back to esptool.py until next block is sent */ + fs.last_error = ESP_INFLATE_ERROR; + } + + if (status == TINFL_STATUS_DONE && fs.remaining > 0) { + fs.last_error = ESP_NOT_ENOUGH_DATA; + } +} + +esp_command_error handle_flash_end(void) +{ + if (!fs.in_flash_mode) { + return ESP_NOT_IN_FLASH_MODE; + } + + if (fs.remaining > 0) { + return ESP_NOT_ENOUGH_DATA; + } + + fs.in_flash_mode = false; + return fs.last_error; +} diff --git a/tools/flasher_stub/wrap_stub.py b/tools/flasher_stub/wrap_stub.py new file mode 100755 index 0000000000..f63db4f25a --- /dev/null +++ b/tools/flasher_stub/wrap_stub.py @@ -0,0 +1,90 @@ +#!/usr/bin/env python +# +# SPDX-FileCopyrightText: 2016 Cesanta Software Limited +# +# SPDX-License-Identifier: GPL-2.0-or-later +# +# SPDX-FileContributor: 2016-2022 Espressif Systems (Shanghai) CO LTD + +import argparse +import base64 +import json +import os +import os.path +import sys + +sys.path.append("..") +import esptool # noqa: E402 + +THIS_DIR = os.path.dirname(__file__) +BUILD_DIR = os.path.join(THIS_DIR, "build") + + +def wrap_stub(elf_file): + """Wrap an ELF file into a stub JSON dict""" + print("Wrapping ELF file %s..." % elf_file) + + e = esptool.bin_image.ELFFile(elf_file) + + text_section = e.get_section(".text") + stub = { + "entry": e.entrypoint, + "text": text_section.data, + "text_start": text_section.addr, + } + try: + data_section = e.get_section(".data") + stub["data"] = data_section.data + stub["data_start"] = data_section.addr + except ValueError: + pass + + for s in e.nobits_sections: + if s.name == ".bss": + stub["bss_start"] = s.addr + + # Pad text with NOPs to mod 4. + if len(stub["text"]) % 4 != 0: + stub["text"] += (4 - (len(stub["text"]) % 4)) * "\0" + + print( + "Stub text: %d @ 0x%08x, data: %d @ 0x%08x, entry @ 0x%x" + % ( + len(stub["text"]), + stub["text_start"], + len(stub.get("data", "")), + stub.get("data_start", 0), + stub["entry"], + ), + file=sys.stderr, + ) + + return stub + + +def write_json_files(stubs_dict): + class BytesEncoder(json.JSONEncoder): + def default(self, obj): + if isinstance(obj, bytes): + return base64.b64encode(obj).decode("ascii") + return json.JSONEncoder.default(self, obj) + + for filename, stub_data in stubs_dict.items(): + with open(os.path.join(BUILD_DIR, filename), "w") as outfile: + json.dump(stub_data, outfile, cls=BytesEncoder, indent=4) + + +def stub_name(filename): + """Return a dictionary key for the stub with filename 'filename'""" + return os.path.splitext(os.path.basename(filename))[0] + ".json" + + +if __name__ == "__main__": + parser = argparse.ArgumentParser() + parser.add_argument("elf_files", nargs="+", help="Stub ELF files to convert") + args = parser.parse_args() + + stubs = dict( + (stub_name(elf_file), wrap_stub(elf_file)) for elf_file in args.elf_files + ) + write_json_files(stubs) From a9080411b1cce5fdfb777215b7e48aaaf2c1aa36 Mon Sep 17 00:00:00 2001 From: Marek Matej Date: Tue, 8 Jul 2025 23:45:42 +0200 Subject: [PATCH 3/3] zephyr: esp32c6: fix include path Update the path where flash stubs were moved after the esptool update. Signed-off-by: Marek Matej --- zephyr/esp32c6/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zephyr/esp32c6/CMakeLists.txt b/zephyr/esp32c6/CMakeLists.txt index ebc0d12de8..29f7331a2f 100644 --- a/zephyr/esp32c6/CMakeLists.txt +++ b/zephyr/esp32c6/CMakeLists.txt @@ -127,7 +127,7 @@ if(CONFIG_SOC_SERIES_ESP32C6) -T${CMAKE_CURRENT_SOURCE_DIR}/../../components/esp_rom/${CONFIG_SOC_SERIES}/ld/${CONFIG_SOC_SERIES}.rom.version.ld -T${CMAKE_CURRENT_SOURCE_DIR}/../../components/esp_rom/${CONFIG_SOC_SERIES}/ld/${CONFIG_SOC_SERIES}.rom.wdt.ld -T${CMAKE_CURRENT_SOURCE_DIR}/../../components/soc/${CONFIG_SOC_SERIES}/ld/${CONFIG_SOC_SERIES}.peripherals.ld - -T${CMAKE_CURRENT_SOURCE_DIR}/../../tools/esptool_py/flasher_stub/ld/rom_32c6.ld + -T${CMAKE_CURRENT_SOURCE_DIR}/../../tools/flasher_stub/ld/rom_32c6.ld ) zephyr_compile_definitions(ESP_PLATFORM)

    j+TY@LSk%>^H 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 diff --git a/tools/esptool_py/test/elf2image/esp32c6-appdesc.elf b/tools/esptool_py/test/elf2image/esp32c6-appdesc.elf new file mode 100755 index 0000000000000000000000000000000000000000..40fb1ae98e471183db5c67882664c96be3d5b96a GIT binary patch literal 4984 zcmeHL!A`y%{#Ts`8q<3MJmQvtC*rIb`V-Gb zHIiXC8#g11er5w0;)vszt}%P}f7QoG drom_seg +} \ No newline at end of file diff --git a/tools/esptool_py/test/elf2image/esp32c6-appdesc/main.c b/tools/esptool_py/test/elf2image/esp32c6-appdesc/main.c new file mode 100644 index 0000000000..59c2638cfa --- /dev/null +++ b/tools/esptool_py/test/elf2image/esp32c6-appdesc/main.c @@ -0,0 +1,45 @@ +#include + +// This is the structure of the application description section in the binary image (taken from ESP-IDF). +typedef struct { + uint32_t magic_word; + uint32_t secure_version; + uint32_t reserv1[2]; + char version[32]; + char project_name[32]; + char time[16]; + char date[16]; + char idf_ver[32]; + uint8_t app_elf_sha256[32]; + uint16_t min_efuse_blk_rev_full; + uint16_t max_efuse_blk_rev_full; + uint8_t mmu_page_size; + uint8_t reserv3[3]; + uint32_t reserv2[18]; +} esp_app_desc_t; + +__attribute__((section(".flash.appdesc"))) +esp_app_desc_t my_app_desc = { + .magic_word = 0xABCD5432, + .secure_version = 0xffffffff, + .reserv1 = {0xffffffff, 0xffffffff}, + .version = "_______________________________", + .project_name = "-------------------------------", + .time = "xxxxxxxxxxxxxxx", + .date = "yyyyyyyyyyyyyyy", + .idf_ver = "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz", + .app_elf_sha256 = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }, + .min_efuse_blk_rev_full = 0xffff, + .max_efuse_blk_rev_full = 0xffff, + .mmu_page_size = 0, + .reserv3 = {0xff, 0xff, 0xff}, + .reserv2 = { + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff + }, +}; \ No newline at end of file diff --git a/tools/esptool_py/test/elf2image/esp8266-nonossdkv20-at-v2.elf-0x00000.bin b/tools/esptool_py/test/elf2image/esp8266-nonossdkv20-at-v2.elf-0x00000.bin new file mode 100644 index 0000000000000000000000000000000000000000..ef49875b406ae40b92bc55799834aa9e2927c6d8 GIT binary patch literal 42096 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