diff --git a/components/app_update/CMakeLists.txt b/components/app_update/CMakeLists.txt index 96806d30f8..6c910d71cf 100644 --- a/components/app_update/CMakeLists.txt +++ b/components/app_update/CMakeLists.txt @@ -29,7 +29,9 @@ if(NOT BOOTLOADER_BUILD) add_custom_target(blank_ota_data ALL DEPENDS ${blank_otadata_file}) add_dependencies(flash blank_ota_data) - add_dependencies(encrypted-flash blank_ota_data) + if(CONFIG_SECURE_FLASH_ENCRYPTION_MODE_DEVELOPMENT) + add_dependencies(encrypted-flash blank_ota_data) + endif() set(otatool_py "${python}" "${COMPONENT_DIR}/otatool.py") diff --git a/components/esp_tee/CMakeLists.txt b/components/esp_tee/CMakeLists.txt index a0c6a6f248..e3df1b47ce 100644 --- a/components/esp_tee/CMakeLists.txt +++ b/components/esp_tee/CMakeLists.txt @@ -50,7 +50,9 @@ else() add_custom_target(blank_tee_ota_data ALL DEPENDS ${blank_tee_otadata_file}) add_dependencies(flash blank_tee_ota_data) - add_dependencies(encrypted-flash blank_tee_ota_data) + if(CONFIG_SECURE_FLASH_ENCRYPTION_MODE_DEVELOPMENT) + add_dependencies(encrypted-flash blank_tee_ota_data) + endif() partition_table_get_partition_info(tee_otadata_part "--partition-type data --partition-subtype tee_ota" "name") diff --git a/components/esptool_py/CMakeLists.txt b/components/esptool_py/CMakeLists.txt index 955c63a0fa..925cb59550 100644 --- a/components/esptool_py/CMakeLists.txt +++ b/components/esptool_py/CMakeLists.txt @@ -15,13 +15,7 @@ idf_component_register(REQUIRES bootloader PRIV_REQUIRES partition_table) if(NOT BOOTLOADER_BUILD) idf_build_get_property(build_dir BUILD_DIR) - if(CONFIG_APP_BUILD_GENERATE_BINARIES) - partition_table_get_partition_info(app_partition_offset "--partition-boot-default" "offset") - esptool_py_custom_target(app-flash app "app") - esptool_py_flash_target_image(app-flash app "${app_partition_offset}" "${build_dir}/${PROJECT_BIN}") - esptool_py_flash_target_image(flash app "${app_partition_offset}" "${build_dir}/${PROJECT_BIN}") - endif() # If anti-rollback option is set then factory partition should not be in Partition Table. # In this case, should be used the partition table with two ota app without the factory. diff --git a/components/esptool_py/project_include.cmake b/components/esptool_py/project_include.cmake index 24db465076..e3997f139d 100644 --- a/components/esptool_py/project_include.cmake +++ b/components/esptool_py/project_include.cmake @@ -274,6 +274,16 @@ idf_component_set_property(esptool_py FLASH_ARGS "${esptool_flash_main_args}") idf_component_set_property(esptool_py FLASH_SUB_ARGS "--flash_mode ${ESPFLASHMODE} --flash_freq ${ESPFLASHFREQ} \ --flash_size ${ESPFLASHSIZE}") +# esptool_py_partition_needs_encryption +# +# @brief Determine if a partition needs to be encrypted when flash encryption is enabled. +# +# When flash encryption is enabled in development mode, this function checks +# the type and subtype of a partition to determine if its contents should be +# encrypted before flashing. +# +# @param[out] retencrypted Variable to store the result (TRUE if encryption needed, FALSE otherwise) +# @param[in] partition_name Name of the partition to check function(esptool_py_partition_needs_encryption retencrypted partition_name) # Check if encryption is enabled if(CONFIG_SECURE_FLASH_ENCRYPTION_MODE_DEVELOPMENT) @@ -311,6 +321,17 @@ function(esptool_py_partition_needs_encryption retencrypted partition_name) endfunction() +# esptool_py_flash_to_partition +# +# @brief Add a binary image to be flashed to a specific partition. +# +# This function is a convenience wrapper that automatically determines the partition +# offset and encryption requirements, then calls esptool_py_flash_target_image() with +# the appropriate parameters. It simplifies flashing to named partitions. +# +# @param[in] target_name Name of the flash target to add the image to +# @param[in] partition_name Name of the partition where the image should be flashed +# @param[in] binary_path Path to the binary file to flash function(esptool_py_flash_to_partition target_name partition_name binary_path) # Retrieve the offset for the partition to flash the image on partition_table_get_partition_info(offset "--partition-name ${partition_name}" "offset") @@ -333,12 +354,21 @@ function(esptool_py_flash_to_partition target_name partition_name binary_path) ${binary_path} ${option}) endfunction() -# This function takes a fifth optional named parameter: "ALWAYS_PLAINTEXT". As -# its name states, it marks whether the image should be flashed as plain text or -# not. If build macro CONFIG_SECURE_FLASH_ENCRYPTION_MODE_DEVELOPMENT is set and -# this parameter is provided, then the image will be flashed as plain text -# (not encrypted) on the target. This parameter will be ignored if build macro -# CONFIG_SECURE_FLASH_ENCRYPTION_MODE_DEVELOPMENT is not set. +# esptool_py_flash_target_image +# +# @brief Add a binary image to a flash target at a specific offset. +# +# This function adds a binary image to the specified flash target, which will be +# included when the target is executed. It handles both plain and encrypted flash +# scenarios, automatically setting up the appropriate target properties. +# +# @param[in] target_name Name of the flash target to add the image to +# @param[in] image_name Logical name for the image (used in flasher_args.json) +# @param[in] offset Flash offset where the image should be written (in hex format like 0x1000) +# @param[in] image Path to the binary file to flash +# @param[in, optional] ALWAYS_PLAINTEXT (option) Force the image to be flashed as plain text +# even when flash encryption is enabled. Ignored if flash encryption +# is not configured. function(esptool_py_flash_target_image target_name image_name offset image) set(options ALWAYS_PLAINTEXT) idf_build_get_property(build_dir BUILD_DIR) @@ -391,21 +421,56 @@ function(esptool_py_flash_target_image target_name image_name offset image) endfunction() +# esptool_py_flash_target +# +# @brief Create a flash target that can flash multiple images using esptool.py. +# +# This function is the core of the flashing mechanism. It creates a custom target +# and attaches the actual esptool.py command to it as a POST_BUILD step. This +# ensures that the flash command only runs after all of the target's dependencies +# (like binary generation) have been successfully built. +# +# It works by generating an argument file (`_args`) that contains all the +# necessary parameters for esptool.py. This file's content is constructed using +# CMake generator expressions, which are resolved at build time. This allows the +# final list of binaries to be flashed to be collected from properties on the +# target. +# +# If flash encryption is enabled, it also creates a corresponding `encrypted-` +# target, which handles the logic for encrypting all or a subset of the binaries. +# +# @param[in] target_name Name of the flash target to create +# @param[in] main_args Main esptool.py arguments (before write_flash command) +# @param[in] sub_args Sub-arguments for write_flash command (flash mode, frequency, size) +# @param[in, optional] FILENAME_PREFIX (single value) Prefix for generated argument files. +# If not specified, uses target_name as prefix. +# @param[in, optional] ALWAYS_PLAINTEXT (option) Force all images to be flashed as plain text. function(esptool_py_flash_target target_name main_args sub_args) - set(single_value OFFSET IMAGE) # template file to use to be able to - # flash the image individually using esptool + set(single_value OFFSET IMAGE FILENAME_PREFIX) # template file to use to be able to + # flash the image individually using esptool set(options ALWAYS_PLAINTEXT) cmake_parse_arguments(_ "${options}" "${single_value}" "" "${ARGN}") + if(__FILENAME_PREFIX) + set(filename_prefix ${__FILENAME_PREFIX}) + else() + set(filename_prefix ${target_name}) + endif() + idf_build_get_property(idf_path IDF_PATH) idf_build_get_property(build_dir BUILD_DIR) idf_component_get_property(esptool_py_dir esptool_py COMPONENT_DIR) + idf_component_get_property(esptool_py_cmd esptool_py ESPTOOLPY_CMD) - add_custom_target(${target_name} + if(NOT TARGET ${target_name}) + add_custom_target(${target_name}) + endif() + + add_custom_command(TARGET ${target_name} POST_BUILD COMMAND ${CMAKE_COMMAND} -D "IDF_PATH=${idf_path}" - -D "SERIAL_TOOL=${ESPTOOLPY}" - -D "SERIAL_TOOL_ARGS=${main_args};write_flash;@${target_name}_args" + -D "SERIAL_TOOL=${esptool_py_cmd}" + -D "SERIAL_TOOL_ARGS=${main_args};write_flash;@${filename_prefix}_args" -D "WORKING_DIRECTORY=${build_dir}" -P ${esptool_py_dir}/run_serial_tool.cmake WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR} @@ -421,13 +486,13 @@ function(esptool_py_flash_target target_name main_args sub_args) $,\n>") # Write the previous expression to the target_name_args.in file - file(GENERATE OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/${target_name}_args.in" + file(GENERATE OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/${filename_prefix}_args.in" CONTENT "${flash_args_content}") # Generate the actual expression value from the content of the file # we just wrote - file(GENERATE OUTPUT "${build_dir}/${target_name}_args" - INPUT "${CMAKE_CURRENT_BINARY_DIR}/${target_name}_args.in") + file(GENERATE OUTPUT "${build_dir}/${filename_prefix}_args" + INPUT "${CMAKE_CURRENT_BINARY_DIR}/${filename_prefix}_args.in") # Check if the target has to be plain text or not, depending on the macro # CONFIG_SECURE_FLASH_ENCRYPTION_MODE_DEVELOPMENT and the parameter @@ -443,11 +508,15 @@ $,\n>") # For example, if 'target_name' is app-flash and 'encrypted' is TRUE, # 'build' directory will contain a file name 'encrypted_app-flash_args' if(${encrypted}) - add_custom_target(encrypted-${target_name} + if(NOT TARGET encrypted-${target_name}) + add_custom_target(encrypted-${target_name}) + endif() + + add_custom_command(TARGET encrypted-${target_name} POST_BUILD COMMAND ${CMAKE_COMMAND} -D "IDF_PATH=${idf_path}" - -D "SERIAL_TOOL=${ESPTOOLPY}" - -D "SERIAL_TOOL_ARGS=${main_args};write_flash;@encrypted_${target_name}_args" + -D "SERIAL_TOOL=${esptool_py_cmd}" + -D "SERIAL_TOOL_ARGS=${main_args};write_flash;@encrypted_${filename_prefix}_args" -D "WORKING_DIRECTORY=${build_dir}" -P ${esptool_py_dir}/run_serial_tool.cmake WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR} @@ -493,12 +562,12 @@ ${encrypted_files}") # The expression is ready to be generated, write it to the file which # extension is .in - file_generate("${CMAKE_CURRENT_BINARY_DIR}/encrypted_${target_name}_args.in" + file_generate("${CMAKE_CURRENT_BINARY_DIR}/encrypted_${filename_prefix}_args.in" CONTENT "${flash_args_content}") # Generate the actual string from the content of the file we just wrote - file_generate("${build_dir}/encrypted_${target_name}_args" - INPUT "${CMAKE_CURRENT_BINARY_DIR}/encrypted_${target_name}_args.in") + file_generate("${build_dir}/encrypted_${filename_prefix}_args" + INPUT "${CMAKE_CURRENT_BINARY_DIR}/encrypted_${filename_prefix}_args.in") else() fail_target(encrypted-${target_name} "Error: The target encrypted-${target_name} requires" "CONFIG_SECURE_FLASH_ENCRYPTION_MODE_DEVELOPMENT to be enabled.") @@ -507,46 +576,250 @@ ${encrypted_files}") endfunction() +# esptool_py_custom_target +# +# @brief Create a custom flash target with dependencies. +# +# This function creates a flash target that depends on other build targets. +# +# @param[in] target_name Name of the flash target to create +# @param[in] flasher_filename Base name for generated flasher argument files +# @param[in] dependencies List of CMake targets that this flash target depends on +# @param[in, optional] FILENAME_PREFIX (single value) Custom prefix for argument files. +# If not specified, uses target_name as prefix. function(esptool_py_custom_target target_name flasher_filename dependencies) + __ensure_esptool_py_setup() + idf_component_get_property(main_args esptool_py FLASH_ARGS) idf_component_get_property(sub_args esptool_py FLASH_SUB_ARGS) idf_build_get_property(build_dir BUILD_DIR) - esptool_py_flash_target(${target_name} "${main_args}" "${sub_args}") + # Parse optional arguments like FILENAME_PREFIX. + set(one_value_args FILENAME_PREFIX) + cmake_parse_arguments(arg "" "${one_value_args}" "" ${ARGN}) + + # Call the underlying flash target function, explicitly passing the prefix if it exists. + if(arg_FILENAME_PREFIX) + esptool_py_flash_target(${target_name} "${main_args}" "${sub_args}" FILENAME_PREFIX "${arg_FILENAME_PREFIX}") + set(filename_prefix ${arg_FILENAME_PREFIX}) + else() + esptool_py_flash_target(${target_name} "${main_args}" "${sub_args}") + set(filename_prefix ${target_name}) + endif() # Copy the file to flash_xxx_args for compatibility for select target file_generate("${build_dir}/flash_${flasher_filename}_args" - INPUT "${build_dir}/${target_name}_args") + INPUT "${build_dir}/${filename_prefix}_args") add_dependencies(${target_name} ${dependencies}) if(CONFIG_SECURE_FLASH_ENCRYPTION_MODE_DEVELOPMENT) file_generate("${build_dir}/flash_encrypted_${flasher_filename}_args" - INPUT "${build_dir}/encrypted_${target_name}_args") + INPUT "${build_dir}/encrypted_${filename_prefix}_args") add_dependencies(encrypted-${target_name} ${dependencies}) endif() endfunction() -if(NOT non_os_build) - set(flash_deps "") +# __esptool_py_setup_tools +# +# @brief Sets up esptool.py, espsecure.py, and espefuse.py tool commands. +# +# This function retrieves the necessary paths and Python interpreter, then +# constructs the full command-line strings for `esptool.py`, `espsecure.py`, +# and `espefuse.py`. It stores these commands as properties of the `esptool_py` +# component for later use by other functions or components. +function(__esptool_py_setup_tools) + idf_build_get_property(target IDF_TARGET) + idf_build_get_property(python PYTHON) + idf_component_get_property(esptool_py_dir esptool_py COMPONENT_DIR) - if(CONFIG_APP_BUILD_TYPE_APP_2NDBOOT) - list(APPEND flash_deps "partition_table_bin") + set(esptool_py_cmd ${python} "$ENV{ESPTOOL_WRAPPER}" "${esptool_py_dir}/esptool/esptool.py" --chip ${target}) + idf_component_set_property(esptool_py ESPTOOLPY_CMD "${esptool_py_cmd}") + + set(espsecure_py_cmd ${python} "${esptool_py_dir}/esptool/espsecure.py") + idf_component_set_property(esptool_py ESPSECUREPY_CMD "${espsecure_py_cmd}") + + set(espefuse_py_cmd ${python} "${esptool_py_dir}/esptool/espefuse.py") + idf_component_set_property(esptool_py ESPEFUSEPY_CMD "${espefuse_py_cmd}") +endfunction() + +# __esptool_py_setup_esptool_py_args +# +# @brief Sets up esptool.py arguments for elf2image and flash targets. +# +# This function determines the appropriate flash mode, frequency, and size based +# on the project configuration (Kconfig values). It assembles argument lists +# for both the `elf2image` operation (converting ELF to BIN), for general +# flashing commands and for creating the flasher_args.json file. +# These argument lists are then stored as properties of the `esptool_py` +# component for consistent use across the build system. +function(__esptool_py_setup_esptool_py_args) + if(NOT CONFIG_APP_BUILD_TYPE_RAM AND CONFIG_APP_BUILD_GENERATE_BINARIES) + if(CONFIG_BOOTLOADER_FLASH_DC_AWARE) + # When set flash frequency to 120M, must keep 1st bootloader work under ``DOUT`` mode + # because on some flash chips, 120M will modify the status register, + # which will make ROM won't work. + # This change intends to be for esptool only and the bootloader should keep use + # ``DOUT`` mode. + set(ESPFLASHMODE "dout") + message("Note: HPM is enabled for the flash, force the ROM bootloader into DOUT mode for stable boot on") + else() + set(ESPFLASHMODE ${CONFIG_ESPTOOLPY_FLASHMODE}) + endif() + set(ESPFLASHFREQ ${CONFIG_ESPTOOLPY_FLASHFREQ}) + set(ESPFLASHSIZE ${CONFIG_ESPTOOLPY_FLASHSIZE}) + + set(esptool_elf2image_args + --flash_mode ${ESPFLASHMODE} + --flash_freq ${ESPFLASHFREQ} + --flash_size ${ESPFLASHSIZE} + ) + + if(BOOTLOADER_BUILD AND CONFIG_SECURE_BOOT_V2_ENABLED) + # The bootloader binary needs to be 4KB aligned in order to append a secure boot V2 signature block. + # If CONFIG_SECURE_BOOT_BUILD_SIGNED_BINARIES is NOT set, the bootloader + # image generated is not 4KB aligned for external HSM to sign it readily. + # Following esptool option --pad-to-size 4KB generates a 4K aligned bootloader image. + # In case of signing during build, espsecure.py "sign_data" operation handles the 4K alignment of the image. + if(NOT CONFIG_SECURE_BOOT_BUILD_SIGNED_BINARIES) + list(APPEND esptool_elf2image_args --pad-to-size 4KB) + endif() + endif() + + set(MMU_PAGE_SIZE ${CONFIG_MMU_PAGE_MODE}) + + if(NOT BOOTLOADER_BUILD) + list(APPEND esptool_elf2image_args --elf-sha256-offset 0xb0) + # For chips that support configurable MMU page size feature + # If page size is configured to values other than the default "64KB" in menuconfig, + # then we need to pass the actual size to flash-mmu-page-size arg + if(NOT MMU_PAGE_SIZE STREQUAL "64KB") + list(APPEND esptool_elf2image_args --flash-mmu-page-size ${MMU_PAGE_SIZE}) + endif() + endif() + + if(NOT CONFIG_SECURE_BOOT_ALLOW_SHORT_APP_PARTITION AND NOT BOOTLOADER_BUILD) + if(CONFIG_SECURE_SIGNED_APPS_ECDSA_SCHEME) + list(APPEND esptool_elf2image_args --secure-pad) + elseif(CONFIG_SECURE_SIGNED_APPS_RSA_SCHEME OR CONFIG_SECURE_SIGNED_APPS_ECDSA_V2_SCHEME) + list(APPEND esptool_elf2image_args --secure-pad-v2) + endif() + endif() endif() - if(CONFIG_APP_BUILD_GENERATE_BINARIES) - list(APPEND flash_deps "app") + if(CONFIG_ESPTOOLPY_HEADER_FLASHSIZE_UPDATE) + # Set ESPFLASHSIZE to 'detect' *after* esptool_elf2image_args are generated, + # as elf2image can't have 'detect' as an option... + set(ESPFLASHSIZE detect) endif() - if(CONFIG_APP_BUILD_BOOTLOADER) - list(APPEND flash_deps "bootloader") + if(CONFIG_SECURE_SIGNED_APPS_RSA_SCHEME) + set(ESPFLASHSIZE keep) endif() - esptool_py_custom_target(flash project "${flash_deps}") -endif() + # We still set "--min-rev" to keep the app compatible with older bootloaders where this field is controlled. + if(CONFIG_IDF_TARGET_ESP32) + # for this chip min_rev is major revision + math(EXPR min_rev "${CONFIG_ESP_REV_MIN_FULL} / 100") + endif() + if(CONFIG_IDF_TARGET_ESP32C3) + # for this chip min_rev is minor revision + math(EXPR min_rev "${CONFIG_ESP_REV_MIN_FULL} % 100") + endif() + + if(min_rev) + list(APPEND esptool_elf2image_args --min-rev ${min_rev}) + endif() + + list(APPEND esptool_elf2image_args --min-rev-full ${CONFIG_ESP_REV_MIN_FULL}) + list(APPEND esptool_elf2image_args --max-rev-full ${CONFIG_ESP_REV_MAX_FULL}) + + # Save esptool_elf2image_args to component property + idf_component_set_property(esptool_py ESPTOOL_PY_ELF2IMAGE_ARGS "${esptool_elf2image_args}") + + set(esptool_flash_main_args "--before=${CONFIG_ESPTOOLPY_BEFORE}") + + if(CONFIG_SECURE_BOOT OR CONFIG_SECURE_FLASH_ENC_ENABLED) + # If security enabled then override post flash option + list(APPEND esptool_flash_main_args "--after=no_reset") + else() + list(APPEND esptool_flash_main_args "--after=${CONFIG_ESPTOOLPY_AFTER}") + endif() + + if(CONFIG_ESPTOOLPY_NO_STUB) + list(APPEND esptool_flash_main_args "--no-stub") + endif() + + # Save flash arguments to component property + idf_component_set_property(esptool_py FLASH_ARGS "${esptool_flash_main_args}") + idf_component_set_property(esptool_py FLASH_SUB_ARGS + "--flash_mode ${ESPFLASHMODE} --flash_freq ${ESPFLASHFREQ} --flash_size ${ESPFLASHSIZE}") + + # Save arguments for flasher_args.json + idf_component_set_property(esptool_py ESPFLASHMODE "${ESPFLASHMODE}") + idf_component_set_property(esptool_py ESPFLASHFREQ "${ESPFLASHFREQ}") + idf_component_set_property(esptool_py ESPFLASHSIZE "${ESPFLASHSIZE}") +endfunction() + +# __ensure_esptool_py_setup +# +# @brief Ensures that the esptool.py setup functions have been called once. +# +# This function acts as an initializer. It checks if the esptool_py +# setup has already been performed by checking a component property. If not, it +# calls __esptool_py_setup_tools() and __esptool_py_setup_esptool_py_args() +# to configure the component. +function(__ensure_esptool_py_setup) + idf_component_get_property(esptool_py_setup_done esptool_py _ESPTOOL_PY_SETUP_DONE) + if(NOT esptool_py_setup_done) + __esptool_py_setup_tools() + __esptool_py_setup_esptool_py_args() + idf_component_set_property(esptool_py _ESPTOOL_PY_SETUP_DONE TRUE) + endif() +endfunction() + + +# __esptool_py_setup_main_flash_target +# +# @brief Sets up the main `flash` target and its dependencies. +# +# This function creates the main `flash` target, which is used to flash multiple +# images to the target device. It determines the dependencies for a full +# project flash (bootloader, partition table, the main app) and then calls +# +function(__esptool_py_setup_main_flash_target) + __ensure_esptool_py_setup() + + idf_build_get_property(non_os_build NON_OS_BUILD) + + if(NOT non_os_build) + set(flash_deps "") + + if(CONFIG_APP_BUILD_TYPE_APP_2NDBOOT) + list(APPEND flash_deps "partition_table_bin") + endif() + + if(CONFIG_APP_BUILD_GENERATE_BINARIES) + list(APPEND flash_deps "app") + endif() + + if(CONFIG_APP_BUILD_BOOTLOADER) + list(APPEND flash_deps "bootloader") + endif() + + # Create the flash target. If encryption is enabled, it will also create + # an encrypted-flash target. + esptool_py_custom_target(flash project "${flash_deps}" FILENAME_PREFIX "flash") + endif() +endfunction() # Adds espefuse functions for global use idf_component_get_property(esptool_py_dir esptool_py COMPONENT_DIR) include(${esptool_py_dir}/espefuse.cmake) + +# Initialize the esptool_py component. +# This ensures that all its properties are set before any other components that +# depend on it try to access them. +__ensure_esptool_py_setup() diff --git a/components/nvs_flash/project_include.cmake b/components/nvs_flash/project_include.cmake index b465024a2b..5503753c54 100644 --- a/components/nvs_flash/project_include.cmake +++ b/components/nvs_flash/project_include.cmake @@ -53,7 +53,9 @@ function(nvs_create_partition_image partition csv) if(arg_FLASH_IN_PROJECT) esptool_py_flash_to_partition(flash "${partition}" "${image_file}") add_dependencies(flash nvs_${partition}_bin) - add_dependencies(encrypted-flash nvs_${partition}_bin) + if(CONFIG_SECURE_FLASH_ENCRYPTION_MODE_DEVELOPMENT) + add_dependencies(encrypted-flash nvs_${partition}_bin) + endif() endif() else() set(message diff --git a/tools/cmake/build.cmake b/tools/cmake/build.cmake index 6f77a72278..76dfdde8c8 100644 --- a/tools/cmake/build.cmake +++ b/tools/cmake/build.cmake @@ -469,6 +469,22 @@ macro(__build_process_project_includes) endforeach() endmacro() +# +# Add placeholder flash targets to the build. +# This is used by components to declare dependencies on the flash target. +# +macro(__build_create_flash_targets) + if(NOT TARGET flash) + add_custom_target(flash) + endif() + + # When flash encryption is enabled, a corresponding 'encrypted-flash' target will be created. + idf_build_get_config(encrypted_flash_enabled CONFIG_SECURE_FLASH_ENCRYPTION_MODE_DEVELOPMENT) + if(encrypted_flash_enabled AND NOT TARGET encrypted-flash) + add_custom_target(encrypted-flash) + endif() +endmacro() + # # Utility macro for setting default property value if argument is not specified # for idf_build_process(). @@ -713,6 +729,13 @@ macro(idf_build_process target) set(ESP_PLATFORM 1) idf_build_set_property(COMPILE_DEFINITIONS "ESP_PLATFORM" APPEND) + # Create flash targets early so components can attach images to them. + # These targets will be appended with actual esptool.py command later + # in the build process when __idf_build_setup_flash_targets() is called. + if(NOT BOOTLOADER_BUILD AND NOT ESP_TEE_BUILD AND NOT "${target}" STREQUAL "linux") + __build_create_flash_targets() + endif() + # Perform component processing (inclusion of project_include.cmake, adding component # subdirectories, creating library targets, linking libraries, etc.) __build_process_project_includes() @@ -752,6 +775,39 @@ function(idf_build_executable elf) # Add dependency of the build target to the executable add_dependencies(${elf} __idf_build_target) + + # Set up esptool_py flash targets + # This must be done after the executable properties are set but before the function exits + # so that all components have had a chance to add their images to the phony flash targets + idf_build_get_property(bootloader_build BOOTLOADER_BUILD) + idf_build_get_property(esp_tee_build ESP_TEE_BUILD) + idf_build_get_property(target IDF_TARGET) + + if(NOT bootloader_build AND NOT esp_tee_build AND NOT "${target}" STREQUAL "linux") + # Check if esptool_py component is available before calling its functions + if(TARGET idf::esptool_py) + # The following block is placed here to ensure that the application binary is added to the 'flash' + # target's properties *before* __esptool_py_setup_main_flash_target is called. + # This is because __esptool_py_setup_main_flash_target copies properties from the 'flash' + # target to an internal '_flash_impl' target, from which the final 'flash_args' file is generated. + # If the app target is not added to the 'flash' target *before* the properties are copied, + # the app binary will be missing from the final 'flash_args' file. + # + # Set up app-flash and flash targets. The app-flash target is specifically for flashing + # just the application, while the flash target is for flashing the entire system. + if(CONFIG_APP_BUILD_GENERATE_BINARIES) + idf_build_get_property(build_dir BUILD_DIR) + idf_build_get_property(project_bin PROJECT_BIN) + partition_table_get_partition_info(app_partition_offset "--partition-boot-default" "offset") + esptool_py_custom_target(app-flash app "app") + + esptool_py_flash_target_image(app-flash app "${app_partition_offset}" "${build_dir}/${project_bin}") + esptool_py_flash_target_image(flash app "${app_partition_offset}" "${build_dir}/${project_bin}") + endif() + + __esptool_py_setup_main_flash_target() + endif() + endif() endfunction() # idf_build_get_config