# SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD # # SPDX-License-Identifier: Apache-2.0 cmake_minimum_required(VERSION 3.13) cmake_policy(SET CMP0109 NEW) include(${CMAKE_CURRENT_LIST_DIR}/tools/utils.cmake) message(STATUS "Building MCUboot -- ESPRESSIF PORT") if(NOT DEFINED MCUBOOT_TARGET) message(FATAL_ERROR "MCUBOOT_TARGET not defined. Please pass -DMCUBOOT_TARGET flag.") endif() set(MCUBOOT_ROOT_DIR ${CMAKE_CURRENT_LIST_DIR}/../..) set(ESPRESSIF_PORT_DIR ${MCUBOOT_ROOT_DIR}/boot/espressif) set(APP_NAME mcuboot_${MCUBOOT_TARGET}) set(APP_EXECUTABLE ${APP_NAME}.elf) set(EXPECTED_IDF_HAL_VERSION "6.0.0") project(mcuboot_${MCUBOOT_TARGET}) add_executable( ${APP_EXECUTABLE} ${ESPRESSIF_PORT_DIR}/main.c ) add_definitions(-DMCUBOOT_TARGET=${MCUBOOT_TARGET}) add_definitions(-D__ESPRESSIF__=1) # Set chip arch if("${MCUBOOT_TARGET}" STREQUAL "esp32" OR "${MCUBOOT_TARGET}" STREQUAL "esp32s2" OR "${MCUBOOT_TARGET}" STREQUAL "esp32s3") set(MCUBOOT_ARCH "xtensa") elseif("${MCUBOOT_TARGET}" STREQUAL "esp32c2" OR "${MCUBOOT_TARGET}" STREQUAL "esp32c3" OR "${MCUBOOT_TARGET}" STREQUAL "esp32c5" OR "${MCUBOOT_TARGET}" STREQUAL "esp32c6" OR "${MCUBOOT_TARGET}" STREQUAL "esp32c61" OR "${MCUBOOT_TARGET}" STREQUAL "esp32p4" OR "${MCUBOOT_TARGET}" STREQUAL "esp32h2") set(MCUBOOT_ARCH "riscv") endif() if("${MCUBOOT_ARCH}" STREQUAL "riscv") add_definitions(-D__riscv) endif() # Set MCUboot Espressif Port configuration file if(NOT DEFINED MCUBOOT_CONFIG_FILE) set(MCUBOOT_CONFIG_FILE "${ESPRESSIF_PORT_DIR}/port/${MCUBOOT_TARGET}/bootloader.conf") message(STATUS "MCUBOOT_CONFIG_FILE: ${MCUBOOT_CONFIG_FILE}") endif() string(REPLACE " " ";" MCUBOOT_CONFIG_FILE_LIST "${MCUBOOT_CONFIG_FILE}") foreach(CONFIG_FILE ${MCUBOOT_CONFIG_FILE_LIST}) if(NOT EXISTS "${CONFIG_FILE}") message(FATAL_ERROR "MCUboot configuration file does not exist at ${CONFIG_FILE}") endif() parse_and_set_config_file(${CONFIG_FILE}) endforeach() # Fetch and set toolchain if(NOT DEFINED CMAKE_TOOLCHAIN_FILE) if(DEFINED TOOLCHAIN_BIN_DIR) message(STATUS "CMAKE_TOOLCHAIN_FILE not defined, searching for toolchain compiler in TOOLCHAIN_BIN_DIR: ${TOOLCHAIN_BIN_DIR}") set(CMAKE_SYSTEM_NAME Generic) file(GLOB C_COMPILER_BIN "${TOOLCHAIN_BIN_DIR}/*${MCUBOOT_ARCH}*elf-gcc") if(NOT C_COMPILER_BIN) message(FATAL_ERROR "No C compiler found. Please ensure that TOOLCHAIN_BIN_DIR directory contains a set of C compiling tools compatible with the target") endif() set(CMAKE_C_COMPILER ${C_COMPILER_BIN}) set(CMAKE_ASM_COMPILER ${C_COMPILER_BIN}) message(STATUS "C compiler found: ${CMAKE_C_COMPILER}") file(GLOB CXX_COMPILER_BIN "${TOOLCHAIN_BIN_DIR}/*${MCUBOOT_ARCH}*elf-g++") if(NOT CXX_COMPILER_BIN) message(FATAL_ERROR "No C++ compiler found. Please ensure that TOOLCHAIN_BIN_DIR directory contains a set of C++ compiling tools compatible with the target") endif() set(CMAKE_CXX_COMPILER ${CXX_COMPILER_BIN}) message(STATUS "CXX compiler found: ${CMAKE_CXX_COMPILER}") else() # Set toolchain file that expect the same toolchain as IDF sets on PATH set(CMAKE_TOOLCHAIN_FILE ${ESPRESSIF_PORT_DIR}/tools/toolchain-${MCUBOOT_TARGET}.cmake) message(STATUS "No user-defined toolchain, setting default toolchain file: ${CMAKE_TOOLCHAIN_FILE}") endif() # This flag is needed when redefining a different compiler toolchain at this point # on CMakeLists, the reason is that CMake does a compiler testing prior to building # that may fail due to cross-compilation set(CMAKE_TRY_COMPILE_TARGET_TYPE "STATIC_LIBRARY") else() message(STATUS "CMAKE_TOOLCHAIN_FILE: ${CMAKE_TOOLCHAIN_FILE}") endif() # Set the minimum revision for each supported chip if("${MCUBOOT_TARGET}" STREQUAL "esp32") set(ESP_MIN_REVISION 3) elseif("${MCUBOOT_TARGET}" STREQUAL "esp32s2") set(ESP_MIN_REVISION 0) elseif("${MCUBOOT_TARGET}" STREQUAL "esp32s3") set(ESP_MIN_REVISION 0) elseif("${MCUBOOT_TARGET}" STREQUAL "esp32c2") set(ESP_MIN_REVISION 0) elseif("${MCUBOOT_TARGET}" STREQUAL "esp32c3") set(ESP_MIN_REVISION 3) elseif("${MCUBOOT_TARGET}" STREQUAL "esp32c5") set(ESP_MIN_REVISION 0) elseif("${MCUBOOT_TARGET}" STREQUAL "esp32c6") set(ESP_MIN_REVISION 0) elseif("${MCUBOOT_TARGET}" STREQUAL "esp32c61") set(ESP_MIN_REVISION 0) elseif("${MCUBOOT_TARGET}" STREQUAL "esp32p4") set(ESP_MIN_REVISION 3) elseif("${MCUBOOT_TARGET}" STREQUAL "esp32h2") set(ESP_MIN_REVISION 0) else() message(FATAL_ERROR "Unsupported target ${MCUBOOT_TARGET}") endif() # Get MCUboot revision to be added into bootloader image version execute_process( COMMAND git describe --tags WORKING_DIRECTORY ${ESPRESSIF_PORT_DIR} OUTPUT_VARIABLE MCUBOOT_VER OUTPUT_STRIP_TRAILING_WHITESPACE ) add_definitions(-DMCUBOOT_VER=\"${MCUBOOT_VER}\") # Set Espressif HAL to use if(NOT DEFINED ESP_HAL_PATH) if(DEFINED ENV{ESP_HAL_PATH}) set(ESP_HAL_PATH $ENV{ESP_HAL_PATH}) else() message(WARNING "ESP_HAL_PATH not defined, checking if IDF_PATH exists.") if(DEFINED ENV{IDF_PATH}) set(ESP_HAL_PATH $ENV{IDF_PATH}) message("IDF installation found in the system, using IDF_PATH as ESP_HAL_PATH.") else () message(FATAL_ERROR "Please set -DESP_HAL_PATH parameter or define ESP_HAL_PATH environment variable.") endif() endif() endif() message(STATUS "Defined ESP_HAL_PATH: ${ESP_HAL_PATH}") # Verify from which IDF version the HAL is based on set(IDF_VER_HEADER_FILE "${ESP_HAL_PATH}/components/esp_common/include/esp_idf_version.h") get_version_from_header("ESP_IDF_VERSION_MAJOR" ${IDF_VER_HEADER_FILE} IDF_VERSION_MAJOR) get_version_from_header("ESP_IDF_VERSION_MINOR" ${IDF_VER_HEADER_FILE} IDF_VERSION_MINOR) get_version_from_header("ESP_IDF_VERSION_PATCH" ${IDF_VER_HEADER_FILE} IDF_VERSION_PATCH) set(IDF_VERSION "${IDF_VERSION_MAJOR}.${IDF_VERSION_MINOR}.${IDF_VERSION_PATCH}") if(NOT IDF_VERSION VERSION_EQUAL ${EXPECTED_IDF_HAL_VERSION}) message( FATAL_ERROR " Unsupported HAL version ${IDF_VERSION}, expected ${EXPECTED_IDF_HAL_VERSION}. \ Verify if the RTOS repository, where you are trying to build from, is up to date, \ or check the installation pointed on ESP_HAL_PATH." ) else () message(STATUS "HAL based on ESP-IDF version: ${IDF_VERSION}") endif() # Find imgtool. # Go with an explicitly installed imgtool first, falling # back to mcuboot/scripts/imgtool.py. find_program(IMGTOOL_COMMAND NAMES imgtool imgtool.py ) if("${IMGTOOL_COMMAND}" MATCHES "IMGTOOL_COMMAND-NOTFOUND") set(imgtool_path "${MCUBOOT_ROOT_DIR}/scripts/imgtool.py") else() set(imgtool_path "${IMGTOOL_COMMAND}") endif() # Set MCUboot core source directories set(BOOTUTIL_DIR ${MCUBOOT_ROOT_DIR}/boot/bootutil) set(BOOT_SERIAL_DIR ${MCUBOOT_ROOT_DIR}/boot/boot_serial) set(ZCBOR_DIR ${MCUBOOT_ROOT_DIR}/boot/zcbor) list(APPEND inc_directories ${BOOTUTIL_DIR}/include ${BOOTUTIL_DIR}/src ${ESPRESSIF_PORT_DIR}/include ) set(port_srcs ${ESPRESSIF_PORT_DIR}/port/esp_mcuboot.c ${ESPRESSIF_PORT_DIR}/port/esp_loader.c ${ESPRESSIF_PORT_DIR}/os.c ) set(bootutil_srcs ${BOOTUTIL_DIR}/src/boot_record.c ${BOOTUTIL_DIR}/src/bootutil_find_key.c ${BOOTUTIL_DIR}/src/bootutil_img_hash.c ${BOOTUTIL_DIR}/src/bootutil_img_security_cnt.c ${BOOTUTIL_DIR}/src/bootutil_misc.c ${BOOTUTIL_DIR}/src/bootutil_area.c ${BOOTUTIL_DIR}/src/bootutil_loader.c ${BOOTUTIL_DIR}/src/bootutil_public.c ${BOOTUTIL_DIR}/src/caps.c ${BOOTUTIL_DIR}/src/encrypted.c ${BOOTUTIL_DIR}/src/fault_injection_hardening.c ${BOOTUTIL_DIR}/src/fault_injection_hardening_delay_rng_mbedtls.c ${BOOTUTIL_DIR}/src/image_ecdsa.c ${BOOTUTIL_DIR}/src/image_ed25519.c ${BOOTUTIL_DIR}/src/image_rsa.c ${BOOTUTIL_DIR}/src/image_validate.c ${BOOTUTIL_DIR}/src/loader.c ${BOOTUTIL_DIR}/src/swap_misc.c ${BOOTUTIL_DIR}/src/swap_move.c ${BOOTUTIL_DIR}/src/swap_scratch.c ${BOOTUTIL_DIR}/src/tlv.c ) if(CONFIG_BOOT_RAM_LOAD) list(APPEND bootutil_srcs ${BOOTUTIL_DIR}/src/ram_load.c) endif() if(DEFINED CONFIG_ESP_SIGN_RSA) include(${ESPRESSIF_PORT_DIR}/include/crypto_config/rsa.cmake) elseif(DEFINED CONFIG_ESP_SIGN_EC256) include(${ESPRESSIF_PORT_DIR}/include/crypto_config/ec256.cmake) elseif(DEFINED CONFIG_ESP_SIGN_ED25519) include(${ESPRESSIF_PORT_DIR}/include/crypto_config/ed25519.cmake) else() # No signature verification set(TINYCRYPT_DIR ${MCUBOOT_ROOT_DIR}/ext/tinycrypt/lib) set(CRYPTO_INC ${TINYCRYPT_DIR}/include ) set(crypto_srcs ${TINYCRYPT_DIR}/source/sha256.c ${TINYCRYPT_DIR}/source/utils.c ) endif() if(DEFINED CONFIG_ESP_SIGN_KEY_FILE) if(IS_ABSOLUTE ${CONFIG_ESP_SIGN_KEY_FILE}) set(KEY_FILE ${CONFIG_ESP_SIGN_KEY_FILE}) else() set(KEY_FILE ${MCUBOOT_ROOT_DIR}/${CONFIG_ESP_SIGN_KEY_FILE}) endif() message("MCUBoot bootloader key file: ${KEY_FILE}") set(GENERATED_PUBKEY ${CMAKE_CURRENT_BINARY_DIR}/autogen-pubkey.c) add_custom_command( OUTPUT ${GENERATED_PUBKEY} COMMAND ${imgtool_path} getpub -k ${KEY_FILE} > ${GENERATED_PUBKEY} DEPENDS ${KEY_FILE} ) list(APPEND crypto_srcs ${GENERATED_PUBKEY}) endif() if(CONFIG_ESP_MCUBOOT_SERIAL) set(MBEDTLS_DIR "${MCUBOOT_ROOT_DIR}/ext/mbedtls-3.6.0") list(APPEND bootutil_srcs ${BOOT_SERIAL_DIR}/src/boot_serial.c ${BOOT_SERIAL_DIR}/src/zcbor_bulk.c ${ZCBOR_DIR}/src/zcbor_decode.c ${ZCBOR_DIR}/src/zcbor_encode.c ${ZCBOR_DIR}/src/zcbor_common.c ) list(APPEND inc_directories ${BOOT_SERIAL_DIR}/include ${ZCBOR_DIR}/include ) list(APPEND port_srcs ${ESPRESSIF_PORT_DIR}/port/serial_adapter.c ${MBEDTLS_DIR}/library/base64.c ${MBEDTLS_DIR}/library/constant_time.c ) list(APPEND CRYPTO_INC ${MBEDTLS_DIR}/include ) endif() list(APPEND inc_directories ${CRYPTO_INC} ) set(CFLAGS "-specs=picolibc.specs" "-nostdlib" "-Wno-frame-address" "-Wall" "-Wextra" "-W" "-Wdeclaration-after-statement" "-Wwrite-strings" "-Wlogical-op" "-Wshadow" "-ffunction-sections" "-fdata-sections" "-fstrict-volatile-bitfields" "-fdump-rtl-expand" "-Werror=all" "-Wno-error=unused-function" "-Wno-error=unused-but-set-variable" "-Wno-error=unused-variable" "-Wno-error=deprecated-declarations" "-Wno-unused-parameter" "-Wno-sign-compare" "-ggdb" "-Os" "-std=gnu23" "-Wno-old-style-declaration" "-Wno-implicit-int" "-Wno-declaration-after-statement" ) set(LDFLAGS "-specs=picolibc.specs" "-nostdlib" "-Wno-frame-address" "-Wl,--cref" "-Wl,--print-memory-usage" "-fno-rtti" "-fno-lto" "-Wl,--gc-sections" "-Wl,--undefined=uxTopUsedPriority" "-Wl,--Map=${APP_NAME}.map" "-lm" "-lgcc" "-lgcov" ) if("${MCUBOOT_ARCH}" STREQUAL "xtensa") list(APPEND CFLAGS "-mlongcalls" "-fno-builtin-memcpy" "-fno-builtin-memset" "-fno-builtin-bzero" ) list(APPEND LDFLAGS "-mlongcalls" "-fno-builtin-memcpy" "-fno-builtin-memset" "-fno-builtin-bzero" ) endif() set_source_files_properties( ${ESPRESSIF_PORT_DIR}/port/serial_adapter.c PROPERTIES COMPILE_FLAGS "-Wno-logical-op" ) set(LINKER_SCRIPT_INCLUDES ${ESPRESSIF_PORT_DIR}/port/include/${MCUBOOT_TARGET}) # Set linker script set(ld_input ${ESPRESSIF_PORT_DIR}/port/${MCUBOOT_TARGET}/ld/bootloader.ld) set(ld_output ${CMAKE_CURRENT_BINARY_DIR}/ld/bootloader.ld) file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/ld") get_directory_property(configs COMPILE_DEFINITIONS) foreach(c ${configs}) list(APPEND conf_defines "-D${c}") endforeach() # Preprocess linker script add_custom_command( TARGET ${APP_EXECUTABLE} PRE_LINK COMMAND ${CMAKE_C_COMPILER} -x c -E -P -o ${ld_output} -I${LINKER_SCRIPT_INCLUDES} ${conf_defines} ${ld_input} MAIN_DEPENDENCY ${ld_input} COMMENT "Preprocessing bootloader.ld linker script..." ) target_compile_options( ${APP_EXECUTABLE} PUBLIC ${CFLAGS} ) target_sources( ${APP_EXECUTABLE} PUBLIC ${bootutil_srcs} ${crypto_srcs} ${port_srcs} ) target_include_directories( ${APP_EXECUTABLE} PUBLIC ${inc_directories} ) target_link_libraries( ${APP_EXECUTABLE} PUBLIC -T${ld_output} ${LDFLAGS} ) add_subdirectory(hal) target_link_libraries( ${APP_EXECUTABLE} PUBLIC hal ) # Find installed esptool, if not found falls to IDF's find_program(ESPTOOL_COMMAND NAMES esptool esptool.py ) if("${ESPTOOL_COMMAND}" MATCHES "ESPTOOL_COMMAND-NOTFOUND") if(DEFINED ENV{IDF_PATH}) set(esptool_path "${IDF_PATH}/components/esptool_py/esptool/esptool.py") else() message(FATAL_ERROR "esptool.py not found. Please install it using \'pip install esptool\'.") endif() else() set(esptool_path "${ESPTOOL_COMMAND}") endif() # Flash frequency parameter for esptool.py, for more information, check `esptool.py -h` if(NOT DEFINED ESP_FLASH_FREQ) if("${MCUBOOT_TARGET}" STREQUAL "esp32" OR "${MCUBOOT_TARGET}" STREQUAL "esp32s2" OR "${MCUBOOT_TARGET}" STREQUAL "esp32s3" OR "${MCUBOOT_TARGET}" STREQUAL "esp32c3" OR "${MCUBOOT_TARGET}" STREQUAL "esp32c5" OR "${MCUBOOT_TARGET}" STREQUAL "esp32c6" OR "${MCUBOOT_TARGET}" STREQUAL "esp32c61") set(ESP_FLASH_FREQ "40m") elseif("${MCUBOOT_TARGET}" STREQUAL "esp32p4") set(ESP_FLASH_FREQ "80m") elseif("${MCUBOOT_TARGET}" STREQUAL "esp32c2") set(ESP_FLASH_FREQ "60m") elseif("${MCUBOOT_TARGET}" STREQUAL "esp32h2") set(ESP_FLASH_FREQ "24m") endif() endif() # Flash mode parameter for esptool.py, for more information, check `esptool.py -h` if(NOT DEFINED ESP_FLASH_MODE) set(ESP_FLASH_MODE "dio") endif() # Serial baud rate parameter for esptool.py flash use, for more information, check `esptool.py -h` if(NOT DEFINED ESP_BAUD_RATE) set(ESP_BAUD_RATE 115200) endif() # This step uses esptool.py for generating the final bootloader binary in # Espressif compatible format. # Note: Both binary generation and flash steps still have some default arguments add_custom_command( TARGET ${APP_EXECUTABLE} POST_BUILD COMMAND ${esptool_path} --chip ${MCUBOOT_TARGET} elf2image --min-rev ${ESP_MIN_REVISION} --flash-mode ${ESP_FLASH_MODE} --flash-freq ${ESP_FLASH_FREQ} --flash-size ${CONFIG_ESP_FLASH_SIZE} -o ${APP_NAME}.bin ${APP_NAME}.elf ) if(DEFINED MCUBOOT_FLASH_PORT) set(FLASH_PORT ${MCUBOOT_FLASH_PORT}) else() # Defaults to the first USB serial port set(FLASH_PORT "/dev/ttyUSB0") endif() if(NOT EXISTS "${FLASH_PORT}") message(WARNING "Could not open ${FLASH_PORT}, serial port does not exist") endif() set(FLASH_COMMAND ${esptool_path} -p ${FLASH_PORT} -b ${ESP_BAUD_RATE} --before default-reset --after no-reset --chip ${MCUBOOT_TARGET} write-flash --flash-mode ${ESP_FLASH_MODE} --flash-size ${CONFIG_ESP_FLASH_SIZE} --flash-freq ${ESP_FLASH_FREQ} ${CONFIG_ESP_BOOTLOADER_OFFSET} ${CMAKE_CURRENT_BINARY_DIR}/${APP_NAME}.bin) # Target for flashing the bootloader using esptool.py add_custom_target(flash DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${APP_NAME}.bin) add_custom_command( TARGET flash USES_TERMINAL COMMAND ${FLASH_COMMAND} COMMENT "Flashing bootloader using command: ${FLASH_COMMAND}" )