diff --git a/components/bootloader/project_include.cmake b/components/bootloader/project_include.cmake index d59689820..54799088c 100644 --- a/components/bootloader/project_include.cmake +++ b/components/bootloader/project_include.cmake @@ -1,3 +1,24 @@ +# This is for tracking the top level project path +if(BOOTLOADER_BUILD) + set(main_project_path "${CMAKE_BINARY_DIR}/../..") +else() + set(main_project_path "${PROJECT_PATH}") +endif() + +get_filename_component(secure_boot_signing_key + "${CONFIG_SECURE_BOOT_SIGNING_KEY}" + ABSOLUTE BASE_DIR "${main_project_path}") +if(NOT EXISTS ${secure_boot_signing_key}) + # If the signing key is not found, create a phony gen_secure_boot_signing_key target that + # fails the build. fail_at_build_time also touches CMakeCache.txt to cause a cmake run next time + # (to pick up a new signing key if one exists, etc.) + fail_at_build_time(gen_secure_boot_signing_key + "Secure Boot Signing Key ${CONFIG_SECURE_BOOT_SIGNING_KEY} does not exist. Generate using:" + "\tespsecure.py generate_signing_key ${CONFIG_SECURE_BOOT_SIGNING_KEY}") +else() + add_custom_target(gen_secure_boot_signing_key) +endif() + if(BOOTLOADER_BUILD) return() # don't keep recursing! endif() @@ -13,16 +34,34 @@ set(bootloader_binary_files "${bootloader_build_dir}/bootloader.map" ) -externalproject_add(bootloader - # TODO: support overriding the bootloader in COMPONENT_PATHS - SOURCE_DIR "${IDF_PATH}/components/bootloader/subproject" - BINARY_DIR "${bootloader_build_dir}" - CMAKE_ARGS -DSDKCONFIG=${SDKCONFIG} -DIDF_PATH=${IDF_PATH} -DEXTRA_COMPONENT_DIRS=${COMPONENT_DIRS} - -DTESTS_ALL=0 -DTEST_COMPONENTS="" - INSTALL_COMMAND "" - BUILD_ALWAYS 1 # no easy way around this... - BUILD_BYPRODUCTS ${bootloader_binary_files} - ) +# These additional files may get generated +if(CONFIG_SECURE_BOOTLOADER_REFLASHABLE) + set(bootloader_binary_files + ${bootloader_binary_files} + "${bootloader_build_dir}/bootloader-reflash-digest.bin" + "${bootloader_build_dir}/secure-bootloader-key-192.bin" + "${bootloader_build_dir}/secure-bootloader-key-256.bin" + ) +endif() + +if((NOT CONFIG_SECURE_BOOT_ENABLED) OR + CONFIG_SECURE_BOOTLOADER_REFLASHABLE OR + CONFIG_SECURE_BOOTLOADER_ONE_TIME_FLASH) + externalproject_add(bootloader + # TODO: support overriding the bootloader in COMPONENT_PATHS + SOURCE_DIR "${IDF_PATH}/components/bootloader/subproject" + BINARY_DIR "${bootloader_build_dir}" + CMAKE_ARGS -DSDKCONFIG=${SDKCONFIG} -DIDF_PATH=${IDF_PATH} -DEXTRA_COMPONENT_DIRS=${COMPONENT_DIRS} + -DTESTS_ALL=0 -DTEST_COMPONENTS="" + -DSECURE_BOOT_SIGNING_KEY=${secure_boot_signing_key} + INSTALL_COMMAND "" + BUILD_ALWAYS 1 # no easy way around this... + BUILD_BYPRODUCTS ${bootloader_binary_files} + DEPENDS gen_secure_boot_signing_key + ) +else() + fail_at_build_time(bootloader "Invalid bootloader target: bad sdkconfig?") +endif() # this is a hack due to an (annoying) shortcoming in cmake, it can't # extend the 'clean' target to the external project diff --git a/components/bootloader/subproject/CMakeLists.txt b/components/bootloader/subproject/CMakeLists.txt index 6d3c44c44..2d75c0a4d 100644 --- a/components/bootloader/subproject/CMakeLists.txt +++ b/components/bootloader/subproject/CMakeLists.txt @@ -26,3 +26,104 @@ target_linker_script(bootloader.elf target_linker_script(bootloader.elf ${ESP32_BOOTLOADER_LINKER_SCRIPTS}) target_link_libraries(bootloader.elf gcc) + +set(secure_boot_signing_key ${SECURE_BOOT_SIGNING_KEY}) + +string(REPLACE ";" " " espsecurepy "${ESPSECUREPY}") +string(REPLACE ";" " " espefusepy "${ESPEFUSEPY}") +set(esptoolpy_write_flash "${ESPTOOLPY_WRITE_FLASH_STR}") + +if(CONFIG_SECURE_BOOTLOADER_REFLASHABLE) + if(CONFIG_SECURE_BOOTLOADER_KEY_ENCODING_192BIT) + set(key_digest_len 192) + else() + set(key_digest_len 256) + endif() + + get_filename_component(bootloader_digest_bin + "bootloader-reflash-digest.bin" + ABSOLUTE BASE_DIR "${CMAKE_BINARY_DIR}") + + get_filename_component(secure_bootloader_key + "secure-bootloader-key-${key_digest_len}.bin" + ABSOLUTE BASE_DIR "${CMAKE_BINARY_DIR}") + + add_custom_command(OUTPUT "${secure_bootloader_key}" + COMMAND ${ESPSECUREPY} digest_private_key + --keylen "${key_digest_len}" + --keyfile "${secure_boot_signing_key}" + "${secure_bootloader_key}" + VERBATIM) + + if(CONFIG_SECURE_BOOT_BUILD_SIGNED_BINARIES) + add_custom_target(gen_secure_bootloader_key ALL DEPENDS "${secure_bootloader_key}") + else() + if(NOT EXISTS "${secure_bootloader_key}") + message(FATAL_ERROR + "No pre-generated key for a reflashable secure bootloader is available, " + "due to signing configuration." + "\nTo generate one, you can use this command:" + "\n\t${espsecurepy} generate_flash_encryption_key ${secure_bootloader_key}" + "\nIf a signing key is present, then instead use:" + "\n\t${ESPSECUREPY} digest_private_key " + "--keylen (192/256) --keyfile KEYFILE " + "${secure_bootloader_key}") + endif() + add_custom_target(gen_secure_bootloader_key) + endif() + + add_custom_command(OUTPUT "${bootloader_digest_bin}" + COMMAND ${CMAKE_COMMAND} -E echo "DIGEST ${bootloader_digest_bin}" + COMMAND ${ESPSECUREPY} digest_secure_bootloader --keyfile "${secure_bootloader_key}" + -o "${bootloader_digest_bin}" "${CMAKE_BINARY_DIR}/bootloader.bin" + DEPENDS gen_secure_bootloader_key "${CMAKE_BINARY_DIR}/bootloader.bin" + VERBATIM) + + add_custom_target (gen_bootloader_digest_bin ALL DEPENDS "${bootloader_digest_bin}") +endif() + +if(CONFIG_SECURE_BOOTLOADER_ONE_TIME_FLASH) + add_custom_command(TARGET bootloader POST_BUILD + COMMAND ${CMAKE_COMMAND} -E echo + "==============================================================================" + COMMAND ${CMAKE_COMMAND} -E echo + "Bootloader built. Secure boot enabled, so bootloader not flashed automatically." + COMMAND ${CMAKE_COMMAND} -E echo + "One-time flash command is:" + COMMAND ${CMAKE_COMMAND} -E echo + "\t${esptoolpy_write_flash} ${BOOTLOADER_OFFSET} ${CMAKE_BINARY_DIR}/bootloader.bin" + COMMAND ${CMAKE_COMMAND} -E echo + "* IMPORTANT: After first boot, BOOTLOADER CANNOT BE RE-FLASHED on same device" + VERBATIM) + +elseif(CONFIG_SECURE_BOOTLOADER_REFLASHABLE) + add_custom_command(TARGET bootloader POST_BUILD + COMMAND ${CMAKE_COMMAND} -E echo + "==============================================================================" + COMMAND ${CMAKE_COMMAND} -E echo + "Bootloader built and secure digest generated." + COMMAND ${CMAKE_COMMAND} -E echo + "Secure boot enabled, so bootloader not flashed automatically." + COMMAND ${CMAKE_COMMAND} -E echo + "Burn secure boot key to efuse using:" + COMMAND ${CMAKE_COMMAND} -E echo + "\t${espefusepy} burn_key secure_boot ${secure_bootloader_key}" + COMMAND ${CMAKE_COMMAND} -E echo + "First time flash command is:" + COMMAND ${CMAKE_COMMAND} -E echo + "\t${esptoolpy_write_flash} ${BOOTLOADER_OFFSET} ${CMAKE_BINARY_DIR}/bootloader.bin" + COMMAND ${CMAKE_COMMAND} -E echo + "==============================================================================" + COMMAND ${CMAKE_COMMAND} -E echo + "To reflash the bootloader after initial flash:" + COMMAND ${CMAKE_COMMAND} -E echo + "\t${esptoolpy_write_flash} 0x0 ${bootloader_digest_bin}" + COMMAND ${CMAKE_COMMAND} -E echo + "==============================================================================" + COMMAND ${CMAKE_COMMAND} -E echo + "* After first boot, only re-flashes of this kind (with same key) will be accepted." + COMMAND ${CMAKE_COMMAND} -E echo + "* Not recommended to re-use the same secure boot keyfile on multiple production devices." + DEPENDS gen_secure_bootloader_key gen_bootloader_digest_bin + VERBATIM) +endif() diff --git a/components/bootloader_support/CMakeLists.txt b/components/bootloader_support/CMakeLists.txt index cdb086abf..088040f16 100644 --- a/components/bootloader_support/CMakeLists.txt +++ b/components/bootloader_support/CMakeLists.txt @@ -17,6 +17,40 @@ if(${BOOTLOADER_BUILD}) set(COMPONENT_REQUIRES) set(COMPONENT_PRIV_REQUIRES spi_flash micro-ecc) list(APPEND COMPONENT_SRCS "src/bootloader_init.c") + + if(CONFIG_SECURE_SIGNED_APPS) + get_filename_component(secure_boot_verification_key + "signature_verification_key.bin" + ABSOLUTE BASE_DIR "${CMAKE_BINARY_DIR}") + if(CONFIG_SECURE_BOOT_BUILD_SIGNED_BINARIES) + add_custom_command(OUTPUT "${secure_boot_verification_key}" + COMMAND ${ESPSECUREPY} + extract_public_key --keyfile "${secure_boot_signing_key}" + "${secure_boot_verification_key}" + DEPENDS gen_secure_boot_signing_key + VERBATIM) + else() + get_filename_component(orig_secure_boot_verification_key + "${CONFIG_SECURE_BOOT_VERIFICATION_KEY}" + ABSOLUTE BASE_DIR "${main_project_path}") + if(NOT EXISTS ${orig_secure_boot_verification_key}) + message(FATAL_ERROR + "Secure Boot Verification Public Key ${CONFIG_SECURE_BOOT_VERIFICATION_KEY} does not exist." + "\nThis can be extracted from the private signing key." + "\nSee docs/security/secure-boot.rst for details.") + endif() + + add_custom_command(OUTPUT "${secure_boot_verification_key}" + COMMAND ${CMAKE_COMMAND} -E copy "${orig_secure_boot_verification_key}" + "${secure_boot_verification_key}" + DEPENDS "${orig_secure_boot_verification_key}" + VERBATIM) + endif() + set(COMPONENT_EMBED_FILES "${secure_boot_verification_key}") + set_property(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" + APPEND PROPERTY ADDITIONAL_MAKE_CLEAN_FILES + "${secure_boot_verification_key}") + endif() else() set(COMPONENT_ADD_INCLUDEDIRS "include") set(COMPONENT_PRIV_INCLUDEDIRS "include_bootloader") diff --git a/components/esptool_py/CMakeLists.txt b/components/esptool_py/CMakeLists.txt index 690763934..05293be37 100644 --- a/components/esptool_py/CMakeLists.txt +++ b/components/esptool_py/CMakeLists.txt @@ -1,5 +1,14 @@ register_config_only_component() +string(REPLACE ";" " " ESPTOOLPY_FLASH_PROJECT_OPTIONS "${ESPTOOLPY_ELF2IMAGE_FLASH_OPTIONS}") +set(ESPTOOLPY_FLASH_PROJECT_OPTIONS + "${ESPTOOLPY_FLASH_PROJECT_OPTIONS} ${BOOTLOADER_OFFSET} bootloader/bootloader.bin" + ) + +if(CONFIG_SECURE_BOOT_ENABLED) + set(ESPTOOLPY_FLASH_PROJECT_OPTIONS "") +endif() + # Generate pre-canned flasher args files suitable for passing to esptool.py foreach(part project app bootloader partition_table) configure_file( diff --git a/components/esptool_py/flash_bootloader_args.in b/components/esptool_py/flash_bootloader_args.in index ac19a6d81..cd7b7766d 100644 --- a/components/esptool_py/flash_bootloader_args.in +++ b/components/esptool_py/flash_bootloader_args.in @@ -1,4 +1,4 @@ --flash_mode ${ESPFLASHMODE} --flash_size ${ESPFLASHSIZE} --flash_freq ${ESPFLASHFREQ} -0x1000 bootloader/bootloader.bin +${BOOTLOADER_OFFSET} bootloader/bootloader.bin diff --git a/components/esptool_py/flash_project_args.in b/components/esptool_py/flash_project_args.in index c09bc08fb..18ee9ab2c 100644 --- a/components/esptool_py/flash_project_args.in +++ b/components/esptool_py/flash_project_args.in @@ -1,7 +1,4 @@ ---flash_mode ${ESPFLASHMODE} ---flash_size ${ESPFLASHSIZE} ---flash_freq ${ESPFLASHFREQ} -0x1000 bootloader/bootloader.bin +${ESPTOOLPY_FLASH_PROJECT_OPTIONS} ${PARTITION_TABLE_OFFSET} partition_table/partition-table.bin ${PHY_PARTITION_OFFSET} ${PHY_PARTITION_BIN_FILE} ${OTADATA_PARTITION_OFFSET} ${BLANK_OTADATA_FILE} diff --git a/components/esptool_py/flasher_args.json.in b/components/esptool_py/flasher_args.json.in index 6a4128f13..bc0e5e340 100644 --- a/components/esptool_py/flasher_args.json.in +++ b/components/esptool_py/flasher_args.json.in @@ -3,18 +3,22 @@ "--flash_size", "${ESPFLASHSIZE}", "--flash_freq", "${ESPFLASHFREQ}" ], "flash_files" : { - "0x1000" : "bootloader/bootloader.bin", + "${BOOTLOADER_OFFSET}" : "bootloader/bootloader.bin", "${PARTITION_TABLE_OFFSET}" : "partition_table/partition-table.bin", "${PHY_PARTITION_OFFSET}" : "${PHY_PARTITION_BIN_FILE}", "${OTADATA_PARTITION_OFFSET}" : "${BLANK_OTADATA_FILE}", "${APP_PARTITION_OFFSET}" : "${PROJECT_NAME}.bin" }, - "bootloader" : { "offset" : "0x1000", + "bootloader" : { "offset" : "${BOOTLOADER_OFFSET}", "file" : "bootloader/bootloader.bin" }, "partition_table" : { "offset" : "${PARTITION_TABLE_OFFSET}", "file" : "partition_table/partition-table.bin" }, "otadata" : { "offset" : "${OTADATA_PARTITION_OFFSET}", "file" : "${BLANK_OTADATA_FILE}" }, "app" : { "offset" : "${APP_PARTITION_OFFSET}", - "file" : "${PROJECT_NAME}.bin" } + "file" : "${PROJECT_NAME}.bin" }, + "extra_esptool_args" : { + "after" : "${ESPTOOLPY_AFTER}", + "before" : "${ESPTOOLPY_BEFORE}" + } } diff --git a/components/esptool_py/project_include.cmake b/components/esptool_py/project_include.cmake index e39b09485..7ab07f5b8 100644 --- a/components/esptool_py/project_include.cmake +++ b/components/esptool_py/project_include.cmake @@ -1,14 +1,34 @@ # Set some global esptool.py variables # # Many of these are read when generating flash_app_args & flash_project_args -set(ESPTOOLPY "${PYTHON}" "${CMAKE_CURRENT_LIST_DIR}/esptool/esptool.py" --chip esp32) -set(ESPSECUREPY "${PYTHON}" "${CMAKE_CURRENT_LIST_DIR}/esptool/espsecure.py") +set(ESPTOOLPY "${CMAKE_CURRENT_LIST_DIR}/esptool/esptool.py" --chip esp32) +set(ESPSECUREPY "${CMAKE_CURRENT_LIST_DIR}/esptool/espsecure.py") +set(ESPEFUSEPY "${CMAKE_CURRENT_LIST_DIR}/esptool/espefuse.py") set(ESPFLASHMODE ${CONFIG_ESPTOOLPY_FLASHMODE}) set(ESPFLASHFREQ ${CONFIG_ESPTOOLPY_FLASHFREQ}) set(ESPFLASHSIZE ${CONFIG_ESPTOOLPY_FLASHSIZE}) -set(ESPTOOLPY_SERIAL "${ESPTOOLPY}" --port "${ESPPORT}" --baud ${ESPBAUD}) +set(ESPTOOLPY_BEFORE "${CONFIG_ESPTOOLPY_BEFORE}") +set(ESPTOOLPY_AFTER "${CONFIG_ESPTOOLPY_AFTER}") + +if(CONFIG_SECURE_BOOT_ENABLED OR CONFIG_FLASH_ENCRYPTION_ENABLED) + # If security enabled then override post flash option + set(ESPTOOLPY_AFTER "no_reset") +endif() + +set(ESPTOOLPY_SERIAL "${ESPTOOLPY}" + --port "${ESPPORT}" + --baud ${ESPBAUD} + --before "${ESPTOOLPY_BEFORE}" + --after "${ESPTOOLPY_AFTER}" + ) + +if(CONFIG_ESPTOOLPY_COMPRESSED) + set(ESPTOOLPY_COMPRESSED_OPT -z) +else() + set(ESPTOOLPY_COMPRESSED_OPT -u) +endif() set(ESPTOOLPY_ELF2IMAGE_FLASH_OPTIONS --flash_mode ${ESPFLASHMODE} @@ -16,6 +36,18 @@ set(ESPTOOLPY_ELF2IMAGE_FLASH_OPTIONS --flash_size ${ESPFLASHSIZE} ) +# String for printing flash command +string(REPLACE ";" " " ESPTOOLPY_WRITE_FLASH_STR + "${ESPTOOLPY} --port (PORT) --baud (BAUD) --before ${ESPTOOLPY_BEFORE} --after ${ESPTOOLPY_AFTER} " + "write_flash ${ESPTOOLPY_ELF2IMAGE_FLASH_OPTIONS} ${ESPTOOLPY_EXTRA_FLASH_OPTIONS} ${ESPTOOLPY_COMPRESSED_OPT}") + +if(CONFIG_SECURE_BOOT_ENABLED AND + NOT CONFIG_SECURE_BOOT_ALLOW_SHORT_APP_PARTITION AND + NOT BOOTLOADER_BUILD) + set(ESPTOOLPY_ELF2IMAGE_FLASH_OPTIONS + ${ESPTOOLPY_ELF2IMAGE_FLASH_OPTIONS} --secure-pad) +endif() + if(CONFIG_ESPTOOLPY_FLASHSIZE_DETECT) # Set ESPFLASHSIZE to 'detect' *after* elf2image options are generated, # as elf2image can't have 'detect' as an option... @@ -28,15 +60,50 @@ if(CONFIG_ESP32_PHY_INIT_DATA_IN_PARTITION) set(PHY_PARTITION_BIN_FILE "esp32/phy_init_data.bin") endif() +if(CONFIG_SECURE_BOOT_BUILD_SIGNED_BINARIES AND NOT BOOTLOADER_BUILD) + set(unsigned_project_binary "${PROJECT_NAME}-unsigned.bin") +else() + set(unsigned_project_binary "${PROJECT_NAME}.bin") +endif() + # # Add 'app.bin' target - generates with elf2image # -add_custom_command(OUTPUT "${PROJECT_NAME}.bin" - COMMAND ${ESPTOOLPY} elf2image ${ESPTOOLPY_ELF2IMAGE_FLASH_OPTIONS} -o "${PROJECT_NAME}.bin" "${PROJECT_NAME}.elf" +add_custom_command(OUTPUT "${unsigned_project_binary}" + COMMAND ${ESPTOOLPY} elf2image ${ESPTOOLPY_ELF2IMAGE_FLASH_OPTIONS} + -o "${unsigned_project_binary}" "${PROJECT_NAME}.elf" DEPENDS ${PROJECT_NAME}.elf VERBATIM ) -add_custom_target(app ALL DEPENDS "${PROJECT_NAME}.bin") + +if(NOT BOOTLOADER_BUILD AND + CONFIG_SECURE_BOOT_BUILD_SIGNED_BINARIES) + # for locally signed secure boot image, add a signing step to get from unsigned app to signed app + add_custom_target(gen_unsigned_project_binary ALL DEPENDS "${unsigned_project_binary}") + add_custom_command(OUTPUT "${PROJECT_NAME}.bin" + COMMAND ${ESPSECUREPY} sign_data --keyfile ${secure_boot_signing_key} + -o "${PROJECT_NAME}.bin" "${unsigned_project_binary}" + DEPENDS gen_unsigned_project_binary + VERBATIM + ) +endif() + +if(NOT BOOTLOADER_BUILD) + add_custom_target(app ALL DEPENDS "${PROJECT_NAME}.bin") +else() + add_custom_target(bootloader ALL DEPENDS "${PROJECT_NAME}.bin") +endif() + +if(NOT BOOTLOADER_BUILD AND + CONFIG_SECURE_BOOT_ENABLED AND + NOT CONFIG_SECURE_BOOT_BUILD_SIGNED_BINARIES) + add_custom_command(TARGET app POST_BUILD + COMMAND ${CMAKE_COMMAND} -E echo + "App built but not signed. Sign app before flashing" + COMMAND ${CMAKE_COMMAND} -E echo + "\t${ESPSECUREPY} sign_data --keyfile KEYFILE ${CMAKE_BINARY_DIR}/${PROJECT_NAME}.bin" + VERBATIM) +endif() # # Add 'flash' target - not all build systems can run this directly diff --git a/components/partition_table/CMakeLists.txt b/components/partition_table/CMakeLists.txt index 443a5ad6e..fc2ecf7ad 100644 --- a/components/partition_table/CMakeLists.txt +++ b/components/partition_table/CMakeLists.txt @@ -22,40 +22,48 @@ if(CONFIG_ESPTOOLPY_FLASHSIZE) set(flashsize_opt --flash-size ${CONFIG_ESPTOOLPY_FLASHSIZE}) endif() +if(CONFIG_SECURE_BOOT_ENABLED AND NOT CONFIG_SECURE_BOOT_ALLOW_SHORT_APP_PARTITION) + set(partition_secure_opt --secure) +else() + set(partition_secure_opt "") +endif() + add_custom_command(OUTPUT "${unsigned_partition_bin}" - COMMAND "${PYTHON}" "${CMAKE_CURRENT_SOURCE_DIR}/gen_esp32part.py" -q --offset ${PARTITION_TABLE_OFFSET} ${md5_opt} ${flashsize_opt} - ${partition_csv} ${unsigned_partition_bin} + COMMAND "${PYTHON}" "${CMAKE_CURRENT_SOURCE_DIR}/gen_esp32part.py" + -q --offset ${PARTITION_TABLE_OFFSET} ${md5_opt} ${flashsize_opt} + ${partition_secure_opt} ${partition_csv} ${unsigned_partition_bin} DEPENDS ${partition_csv} "${CMAKE_CURRENT_SOURCE_DIR}/gen_esp32part.py" VERBATIM) # Add signing steps if(CONFIG_SECURE_BOOT_BUILD_SIGNED_BINARIES) - get_filename_component(secure_boot_signing_key - "${CONFIG_SECURE_BOOT_SIGNING_KEY}" - ABSOLUTE BASE_DIR "${PROJECT_PATH}") - + add_custom_target(gen_unsigned_partition_bin ALL DEPENDS "${unsigned_partition_bin}") add_custom_command(OUTPUT "${final_partition_bin}" - COMMAND "${PYTHON}" "${ESPSECUREPY}" sign_data --keyfile "${secure_boot_signing_key}" - -o "${final_partition_bin}" "${unsigned_partition_bin}" - DEPENDS "${unsigned_partition_bin}" + COMMAND ${ESPSECUREPY} sign_data --keyfile "${secure_boot_signing_key}" + -o "${final_partition_bin}" "${unsigned_partition_bin}" + DEPENDS gen_unsigned_partition_bin gen_secure_boot_signing_key VERBATIM) - endif() if(EXISTS ${partition_csv}) add_custom_target(partition_table ALL DEPENDS "${final_partition_bin}") else() - # This is a bit of a hack: If the partition input CSV is not found, create a phony partition_table target that - # fails the build. Have it also touch CMakeCache.txt to cause a cmake run next time + # If the partition input CSV is not found, create a phony partition_table target that + # fails the build. fail_at_build_time also touches CMakeCache.txt to cause a cmake run next time # (to pick up a new CSV if one exists, etc.) - # - # This is because partition CSV is required at CMake runtime (to generate metadata files with flashing data, etc) but we can't - # fail the build if it is not found, because the "menuconfig" target may be required to fix the problem. CMAKE_CONFIGURE_DEPENDS - # only works for files which exist at CMake runtime. - add_custom_target(partition_table ALL - COMMAND ${CMAKE_COMMAND} -E echo "Partition table CSV ${partition_csv} does not exist. Either change partition table in menuconfig or create this input file." - COMMAND ${CMAKE_COMMAND} -E touch "${CMAKE_BINARY_DIR}/CMakeCache.txt" - COMMAND ${CMAKE_COMMAND} -P ${IDF_PATH}/tools/cmake/scripts/fail.cmake) + fail_at_build_time(partition_table + "Partition table CSV ${partition_csv} does not exist." + "Either change partition table in menuconfig or create this input file.") +endif() + +if(CONFIG_SECURE_BOOT_ENABLED AND + NOT CONFIG_SECURE_BOOT_BUILD_SIGNED_BINARIES) + add_custom_command(TARGET partition_table POST_BUILD + COMMAND ${CMAKE_COMMAND} -E echo + "Partition table built but not signed. Sign partition data before flashing:" + COMMAND ${CMAKE_COMMAND} -E echo + "\t${ESPSECUREPY} sign_data --keyfile KEYFILE ${CMAKE_CURRENT_BINARY_DIR}/${final_partition_bin}" + VERBATIM) endif() add_dependencies(bootloader partition_table) diff --git a/components/partition_table/project_include.cmake b/components/partition_table/project_include.cmake index 014426472..0d168c7bd 100644 --- a/components/partition_table/project_include.cmake +++ b/components/partition_table/project_include.cmake @@ -56,3 +56,5 @@ get_partition_info(OTADATA_PARTITION_OFFSET "--type data --subtype ota --offset" get_partition_info(OTADATA_PARTITION_SIZE "--type data --subtype ota --size") endif() + +set(BOOTLOADER_OFFSET 0x1000) diff --git a/tools/cmake/utilities.cmake b/tools/cmake/utilities.cmake index bfe10c090..8abeef89a 100644 --- a/tools/cmake/utilities.cmake +++ b/tools/cmake/utilities.cmake @@ -114,8 +114,9 @@ function(target_add_binary_data target embed_file embed_type) -D "FILE_TYPE=${embed_type}" -P "${IDF_PATH}/tools/cmake/scripts/data_file_embed_asm.cmake" MAIN_DEPENDENCY "${embed_file}" - DEPENDENCIES "${IDF_PATH}/tools/cmake/scripts/data_file_embed_asm.cmake" - WORKING_DIRECTORY "${CMAKE_BINARY_DIR}") + DEPENDS "${IDF_PATH}/tools/cmake/scripts/data_file_embed_asm.cmake" + WORKING_DIRECTORY "${CMAKE_BINARY_DIR}" + VERBATIM) set_property(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" APPEND PROPERTY ADDITIONAL_MAKE_CLEAN_FILES "${embed_srcfile}") @@ -188,4 +189,25 @@ function(add_prefix var prefix) list(APPEND newlist "${prefix}${elm}") endforeach() set(${var} "${newlist}" PARENT_SCOPE) -endfunction() \ No newline at end of file +endfunction() + +# fail_at_build_time +# +# Creates a phony target which fails the build and touches CMakeCache.txt to cause a cmake run next time. +# +# This is used when a missing file is required at CMake runtime, but we can't fail the build if it is not found, +# because the "menuconfig" target may be required to fix the problem. +# +# We cannot use CMAKE_CONFIGURE_DEPENDS instead because it only works for files which exist at CMake runtime. +# +function(fail_at_build_time target_name message_line0) + set(message_lines COMMAND ${CMAKE_COMMAND} -E echo "${message_line0}") + foreach(message_line ${ARGN}) + set(message_lines ${message_lines} COMMAND ${CMAKE_COMMAND} -E echo "${message_line}") + endforeach() + add_custom_target(${target_name} ALL + ${message_lines} + COMMAND ${CMAKE_COMMAND} -E touch "${CMAKE_BINARY_DIR}/CMakeCache.txt" + COMMAND ${CMAKE_COMMAND} -P ${IDF_PATH}/tools/cmake/scripts/fail.cmake + VERBATIM) +endfunction() diff --git a/tools/idf.py b/tools/idf.py index 716bbf50b..830ff9713 100755 --- a/tools/idf.py +++ b/tools/idf.py @@ -244,6 +244,12 @@ def _get_esptool_args(args): result = [ PYTHON, esptool_path ] result += [ "-p", args.port ] result += [ "-b", str(args.baud) ] + + with open(os.path.join(args.build_dir, "flasher_args.json")) as f: + flasher_args = json.load(f) + + extra_esptool_args = flasher_args["extra_esptool_args"] + result += [ "--after", extra_esptool_args["after"] ] return result def flash(action, args): @@ -360,10 +366,11 @@ def print_closing_message(args): for o,f in flash_items: cmd += o + " " + flasher_path(f) + " " - print("%s -p %s -b %s write_flash %s" % ( + print("%s -p %s -b %s --after %s write_flash %s" % ( os.path.relpath("%s/components/esptool_py/esptool/esptool.py" % os.environ["IDF_PATH"]), args.port or "(PORT)", args.baud, + flasher_args["extra_esptool_args"]["after"], cmd.strip())) print("or run 'idf.py -p %s %s'" % (args.port or "(PORT)", key + "-flash" if key != "project" else "flash",))