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