1cmake_minimum_required(VERSION 3.16) 2 3if(NOT SDKCONFIG) 4 message(FATAL_ERROR "Bootloader subproject expects the SDKCONFIG variable to be passed " 5 "in by the parent build process.") 6endif() 7 8if(NOT IDF_PATH) 9 message(FATAL_ERROR "Bootloader subproject expects the IDF_PATH variable to be passed " 10 "in by the parent build process.") 11endif() 12 13if(NOT IDF_TARGET) 14 message(FATAL_ERROR "Bootloader subproject expects the IDF_TARGET variable to be passed " 15 "in by the parent build process.") 16endif() 17 18# A number of these components are implemented as config-only when built in the bootloader 19set(COMPONENTS 20 bootloader 21 esptool_py 22 esp_hw_support 23 esp_system 24 freertos 25 hal 26 partition_table 27 soc 28 bootloader_support 29 log 30 spi_flash 31 micro-ecc 32 main 33 efuse 34 esp_system 35 newlib) 36 37# Make EXTRA_COMPONENT_DIRS variable to point to the bootloader_components directory 38# of the project being compiled 39set(PROJECT_EXTRA_COMPONENTS "${PROJECT_SOURCE_DIR}/bootloader_components") 40if(EXISTS ${PROJECT_EXTRA_COMPONENTS}) 41 list(APPEND EXTRA_COMPONENT_DIRS "${PROJECT_EXTRA_COMPONENTS}") 42endif() 43 44# Consider each directory in project's bootloader_components as a component to be compiled 45file(GLOB proj_components RELATIVE ${PROJECT_EXTRA_COMPONENTS} ${PROJECT_EXTRA_COMPONENTS}/*) 46foreach(component ${proj_components}) 47 # Only directories are considered as components 48 if(IS_DIRECTORY ${curdir}/${child}) 49 list(APPEND COMPONENTS ${component}) 50 endif() 51endforeach() 52 53set(BOOTLOADER_BUILD 1) 54include("${IDF_PATH}/tools/cmake/project.cmake") 55set(common_req log esp_rom esp_common esp_hw_support newlib) 56idf_build_set_property(__COMPONENT_REQUIRES_COMMON "${common_req}") 57idf_build_set_property(__OUTPUT_SDKCONFIG 0) 58project(bootloader) 59 60idf_build_set_property(COMPILE_DEFINITIONS "BOOTLOADER_BUILD=1" APPEND) 61idf_build_set_property(COMPILE_OPTIONS "-fno-stack-protector" APPEND) 62 63idf_component_get_property(main_args esptool_py FLASH_ARGS) 64idf_component_get_property(sub_args esptool_py FLASH_SUB_ARGS) 65 66# String for printing flash command 67string(REPLACE ";" " " esptoolpy_write_flash 68 "${ESPTOOLPY} --port=(PORT) --baud=(BAUD) ${main_args} " 69 "write_flash ${sub_args}") 70 71string(REPLACE ";" " " espsecurepy "${ESPSECUREPY}") 72string(REPLACE ";" " " espefusepy "${ESPEFUSEPY}") 73 74# Suppress warning: "Manually-specified variables were not used by the project: SECURE_BOOT_SIGNING_KEY" 75set(ignore_signing_key "${SECURE_BOOT_SIGNING_KEY}") 76 77if(CONFIG_SECURE_BOOTLOADER_REFLASHABLE) 78 if(CONFIG_SECURE_BOOTLOADER_KEY_ENCODING_192BIT) 79 set(key_digest_len 192) 80 else() 81 set(key_digest_len 256) 82 endif() 83 84 get_filename_component(bootloader_digest_bin 85 "bootloader-reflash-digest.bin" 86 ABSOLUTE BASE_DIR "${CMAKE_BINARY_DIR}") 87 88 get_filename_component(secure_bootloader_key 89 "secure-bootloader-key-${key_digest_len}.bin" 90 ABSOLUTE BASE_DIR "${CMAKE_BINARY_DIR}") 91 92 add_custom_command(OUTPUT "${secure_bootloader_key}" 93 COMMAND ${ESPSECUREPY} digest_private_key 94 --keylen "${key_digest_len}" 95 --keyfile "${SECURE_BOOT_SIGNING_KEY}" 96 "${secure_bootloader_key}" 97 VERBATIM) 98 99 if(CONFIG_SECURE_BOOT_BUILD_SIGNED_BINARIES) 100 add_custom_target(gen_secure_bootloader_key ALL DEPENDS "${secure_bootloader_key}") 101 else() 102 if(NOT EXISTS "${secure_bootloader_key}") 103 message(FATAL_ERROR 104 "No pre-generated key for a reflashable secure bootloader is available, " 105 "due to signing configuration." 106 "\nTo generate one, you can use this command:" 107 "\n\t${espsecurepy} generate_flash_encryption_key ${secure_bootloader_key}" 108 "\nIf a signing key is present, then instead use:" 109 "\n\t${espsecurepy} digest_private_key " 110 "--keylen (192/256) --keyfile KEYFILE " 111 "${secure_bootloader_key}") 112 endif() 113 add_custom_target(gen_secure_bootloader_key) 114 endif() 115 116 add_custom_command(OUTPUT "${bootloader_digest_bin}" 117 COMMAND ${CMAKE_COMMAND} -E echo "DIGEST ${bootloader_digest_bin}" 118 COMMAND ${ESPSECUREPY} digest_secure_bootloader --keyfile "${secure_bootloader_key}" 119 -o "${bootloader_digest_bin}" "${CMAKE_BINARY_DIR}/bootloader.bin" 120 MAIN_DEPENDENCY "${CMAKE_BINARY_DIR}/.bin_timestamp" 121 DEPENDS gen_secure_bootloader_key gen_project_binary 122 VERBATIM) 123 124 add_custom_target(gen_bootloader_digest_bin ALL DEPENDS "${bootloader_digest_bin}") 125endif() 126 127if(CONFIG_SECURE_BOOT_V2_ENABLED) 128 if(CONFIG_SECURE_BOOT_BUILD_SIGNED_BINARIES) 129 get_filename_component(secure_boot_signing_key 130 "${SECURE_BOOT_SIGNING_KEY}" ABSOLUTE BASE_DIR "${project_dir}") 131 132 if(NOT EXISTS "${secure_boot_signing_key}") 133 message(FATAL_ERROR 134 "Secure Boot Signing Key Not found." 135 "\nGenerate the Secure Boot V2 RSA-PSS 3072 Key." 136 "\nTo generate one, you can use this command:" 137 "\n\t${espsecurepy} generate_signing_key --version 2 ${SECURE_BOOT_SIGNING_KEY}") 138 endif() 139 140 set(bootloader_unsigned_bin "bootloader-unsigned.bin") 141 add_custom_command(OUTPUT ".signed_bin_timestamp" 142 COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_BINARY_DIR}/${PROJECT_BIN}" 143 "${CMAKE_BINARY_DIR}/${bootloader_unsigned_bin}" 144 COMMAND ${ESPSECUREPY} sign_data --version 2 --keyfile "${secure_boot_signing_key}" 145 -o "${CMAKE_BINARY_DIR}/${PROJECT_BIN}" "${CMAKE_BINARY_DIR}/${bootloader_unsigned_bin}" 146 COMMAND ${CMAKE_COMMAND} -E echo "Generated signed binary image ${build_dir}/${PROJECT_BIN}" 147 "from ${CMAKE_BINARY_DIR}/${bootloader_unsigned_bin}" 148 COMMAND ${CMAKE_COMMAND} -E md5sum "${CMAKE_BINARY_DIR}/${PROJECT_BIN}" 149 > "${CMAKE_BINARY_DIR}/.signed_bin_timestamp" 150 DEPENDS "${build_dir}/.bin_timestamp" 151 VERBATIM 152 COMMENT "Generated the signed Bootloader") 153 else() 154 add_custom_command(OUTPUT ".signed_bin_timestamp" 155 VERBATIM 156 COMMENT "Bootloader generated but not signed") 157 endif() 158 159 add_custom_target(gen_signed_bootloader ALL DEPENDS "${build_dir}/.signed_bin_timestamp") 160endif() 161 162if(CONFIG_SECURE_BOOTLOADER_ONE_TIME_FLASH) 163 add_custom_command(TARGET bootloader.elf POST_BUILD 164 COMMAND ${CMAKE_COMMAND} -E echo 165 "==============================================================================" 166 COMMAND ${CMAKE_COMMAND} -E echo 167 "Bootloader built. Secure boot enabled, so bootloader not flashed automatically." 168 COMMAND ${CMAKE_COMMAND} -E echo 169 "One-time flash command is:" 170 COMMAND ${CMAKE_COMMAND} -E echo 171 "\t${esptoolpy_write_flash} ${BOOTLOADER_OFFSET} ${CMAKE_BINARY_DIR}/bootloader.bin" 172 COMMAND ${CMAKE_COMMAND} -E echo 173 "* IMPORTANT: After first boot, BOOTLOADER CANNOT BE RE-FLASHED on same device" 174 VERBATIM) 175elseif(CONFIG_SECURE_BOOTLOADER_REFLASHABLE) 176 add_custom_command(TARGET bootloader.elf POST_BUILD 177 COMMAND ${CMAKE_COMMAND} -E echo 178 "==============================================================================" 179 COMMAND ${CMAKE_COMMAND} -E echo 180 "Bootloader built and secure digest generated." 181 COMMAND ${CMAKE_COMMAND} -E echo 182 "Secure boot enabled, so bootloader not flashed automatically." 183 COMMAND ${CMAKE_COMMAND} -E echo 184 "Burn secure boot key to efuse using:" 185 COMMAND ${CMAKE_COMMAND} -E echo 186 "\t${espefusepy} burn_key secure_boot_v1 ${secure_bootloader_key}" 187 COMMAND ${CMAKE_COMMAND} -E echo 188 "First time flash command is:" 189 COMMAND ${CMAKE_COMMAND} -E echo 190 "\t${esptoolpy_write_flash} ${BOOTLOADER_OFFSET} ${CMAKE_BINARY_DIR}/bootloader.bin" 191 COMMAND ${CMAKE_COMMAND} -E echo 192 "==============================================================================" 193 COMMAND ${CMAKE_COMMAND} -E echo 194 "To reflash the bootloader after initial flash:" 195 COMMAND ${CMAKE_COMMAND} -E echo 196 "\t${esptoolpy_write_flash} 0x0 ${bootloader_digest_bin}" 197 COMMAND ${CMAKE_COMMAND} -E echo 198 "==============================================================================" 199 COMMAND ${CMAKE_COMMAND} -E echo 200 "* After first boot, only re-flashes of this kind (with same key) will be accepted." 201 COMMAND ${CMAKE_COMMAND} -E echo 202 "* Not recommended to re-use the same secure boot keyfile on multiple production devices." 203 DEPENDS gen_secure_bootloader_key gen_bootloader_digest_bin 204 VERBATIM) 205elseif(CONFIG_SECURE_BOOT_V2_ENABLED AND (CONFIG_IDF_TARGET_ESP32S2 OR CONFIG_IDF_TARGET_ESP32C3)) 206 add_custom_command(TARGET bootloader.elf POST_BUILD 207 COMMAND ${CMAKE_COMMAND} -E echo 208 "==============================================================================" 209 COMMAND ${CMAKE_COMMAND} -E echo 210 "Bootloader built. Secure boot enabled, so bootloader not flashed automatically." 211 COMMAND ${CMAKE_COMMAND} -E echo 212 "To sign the bootloader with additional private keys." 213 COMMAND ${CMAKE_COMMAND} -E echo 214 "\t${espsecurepy} sign_data -k secure_boot_signing_key2.pem -v 2 \ 215--append_signatures -o signed_bootloader.bin build/bootloader/bootloader.bin" 216 COMMAND ${CMAKE_COMMAND} -E echo 217 "Secure boot enabled, so bootloader not flashed automatically." 218 COMMAND ${CMAKE_COMMAND} -E echo 219 "\t${esptoolpy_write_flash} ${BOOTLOADER_OFFSET} ${CMAKE_BINARY_DIR}/bootloader.bin" 220 COMMAND ${CMAKE_COMMAND} -E echo 221 "==============================================================================" 222 DEPENDS gen_signed_bootloader 223 VERBATIM) 224elseif(CONFIG_SECURE_BOOT_V2_ENABLED) 225 add_custom_command(TARGET bootloader.elf POST_BUILD 226 COMMAND ${CMAKE_COMMAND} -E echo 227 "==============================================================================" 228 COMMAND ${CMAKE_COMMAND} -E echo 229 "Bootloader built. Secure boot enabled, so bootloader not flashed automatically." 230 COMMAND ${CMAKE_COMMAND} -E echo 231 "Secure boot enabled, so bootloader not flashed automatically." 232 COMMAND ${CMAKE_COMMAND} -E echo 233 "\t${esptoolpy_write_flash} ${BOOTLOADER_OFFSET} ${CMAKE_BINARY_DIR}/bootloader.bin" 234 COMMAND ${CMAKE_COMMAND} -E echo 235 "==============================================================================" 236 DEPENDS gen_signed_bootloader 237 VERBATIM) 238endif() 239