cmake_minimum_required(VERSION 3.22)
project(bootloader)

set(SRC_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/)
set(COMMON ${SRC_ROOT}/common)
set(CRYPTO ${SRC_ROOT}/cyclone_crypto)
set(BOOT ${SRC_ROOT}/cyclone_boot)
set(THIRD_PARTY ${CMAKE_SOURCE_DIR}/../../../../../third_party)
set(SCRIPTS ${CMAKE_SOURCE_DIR}/../../../../../scripts)

# Version published by the (immutable) first stage through the mailbox, read by the 2nd stage
# and the applications for display; the first stage has no image header of its own.
set(FSB_VERSION "1.0.0" CACHE STRING "1st-stage bootloader version")
string(REPLACE "." ";" FSB_VERSION_PARTS ${FSB_VERSION})
list(GET FSB_VERSION_PARTS 0 FSB_MAJOR_VERSION)
list(GET FSB_VERSION_PARTS 1 FSB_MINOR_VERSION)
list(GET FSB_VERSION_PARTS 2 FSB_REV_NUMBER)

# Setup compiler settings
set(CMAKE_C_STANDARD 11)
set(CMAKE_C_STANDARD_REQUIRED ON)
set(CMAKE_C_EXTENSIONS ON)

# Define the build type
if(NOT CMAKE_BUILD_TYPE)
    set(CMAKE_BUILD_TYPE "Debug")
endif()

# Enable compile command to ease indexing with e.g. clangd
set(CMAKE_EXPORT_COMPILE_COMMANDS TRUE)
message("Build type: " ${CMAKE_BUILD_TYPE})

add_executable(bootloader)

target_sources(bootloader PRIVATE
        ${COMMON}/cpu_endian.c
        ${COMMON}/os_port_none.c
        ${COMMON}/date_time.c
        ${COMMON}/str.c

        ${BOOT}/core/crc32.c
        ${BOOT}/core/mailbox.c
        ${BOOT}/modules/image/image.c
        ${BOOT}/modules/image/image_utils.c
        ${BOOT}/drivers/mcu_core/stm32h5xx_mcu_driver.c
        ${BOOT}/drivers/flash/internal/stm32h5xx_flash_driver.c
        ${BOOT}/bootloader/first_stage/boot.c
        ${BOOT}/bootloader/first_stage/boot_common.c

        # Runtime RSA/ECDSA signature check (install-time + verify-before-execute)
        ${BOOT}/bootloader/first_stage/boot_verify.c
        ${BOOT}/modules/security/verify_runtime.c
        ${BOOT}/modules/security/verify_integrity.c
        ${BOOT}/modules/security/verify_sign.c
        ${CRYPTO}/hash/sha256.c
        ${CRYPTO}/encoding/oid.c
        ${CRYPTO}/encoding/asn1.c
        ${CRYPTO}/encoding/base64.c
        ${CRYPTO}/mpi/mpi.c
        ${CRYPTO}/mpi/mpi_misc.c
        ${CRYPTO}/pkc/rsa.c
        ${CRYPTO}/pkc/rsa_misc.c
        ${CRYPTO}/ecc/ec.c
        ${CRYPTO}/ecc/ec_curves.c
        ${CRYPTO}/ecc/ec_misc.c
        ${CRYPTO}/ecc/ecdsa.c
        ${CRYPTO}/pkix/pem_common.c
        ${CRYPTO}/pkix/pem_key_import.c
        ${CRYPTO}/pkix/x509_common.c
        ${CRYPTO}/pkix/x509_key_parse.c

        ${THIRD_PARTY}/st/drivers/stm32h5xx_hal_driver/src/stm32h5xx_hal.c
        ${THIRD_PARTY}/st/drivers/stm32h5xx_hal_driver/src/stm32h5xx_hal_cortex.c
        ${THIRD_PARTY}/st/drivers/stm32h5xx_hal_driver/src/stm32h5xx_hal_rcc.c
        ${THIRD_PARTY}/st/drivers/stm32h5xx_hal_driver/src/stm32h5xx_hal_rcc_ex.c
        ${THIRD_PARTY}/st/drivers/stm32h5xx_hal_driver/src/stm32h5xx_hal_pwr.c
        ${THIRD_PARTY}/st/drivers/stm32h5xx_hal_driver/src/stm32h5xx_hal_pwr_ex.c
        ${THIRD_PARTY}/st/drivers/stm32h5xx_hal_driver/src/stm32h5xx_hal_gpio.c
        ${THIRD_PARTY}/st/drivers/stm32h5xx_hal_driver/src/stm32h5xx_hal_icache.c
        ${THIRD_PARTY}/st/drivers/stm32h5xx_hal_driver/src/stm32h5xx_hal_flash.c
        ${THIRD_PARTY}/st/drivers/stm32h5xx_hal_driver/src/stm32h5xx_hal_flash_ex.c
        ${THIRD_PARTY}/st/drivers/stm32h5xx_hal_driver/src/stm32h5xx_hal_uart.c
        ${THIRD_PARTY}/st/drivers/stm32h5xx_hal_driver/src/stm32h5xx_hal_uart_ex.c

        ${THIRD_PARTY}/st/boards2/stm32h573i_discovery/stm32h573i_discovery.c

        ${CMAKE_SOURCE_DIR}/cmake/startup_stm32h573xx.S
        ${CMAKE_SOURCE_DIR}/cmake/syscalls.c
        ${CMAKE_SOURCE_DIR}/src/system_stm32h5xx.c
        ${CMAKE_SOURCE_DIR}/src/stm32h5xx_it.c
        ${CMAKE_SOURCE_DIR}/src/main.c
        ${CMAKE_SOURCE_DIR}/src/board.c
        ${CMAKE_SOURCE_DIR}/src/debug.c
)

target_include_directories(bootloader PRIVATE
        ${CMAKE_SOURCE_DIR}/src
        ${COMMON}
        ${BOOT}
        ${CRYPTO}
        ${BOOT}/bootloader
        ${BOOT}/modules
        ${THIRD_PARTY}/cmsis/include
        ${THIRD_PARTY}/st/devices/stm32h5xx
        ${THIRD_PARTY}/st/drivers/stm32h5xx_hal_driver/inc
        ${THIRD_PARTY}/st/boards2/stm32h573i_discovery
        ${THIRD_PARTY}/st/boards2/components/common
)

target_compile_definitions(bootloader PRIVATE
    STM32H573xx
    USE_HAL_DRIVER
    USE_STM32H573I_DK
    __USE_C99_MATH
    FSB_VERSION_STRING="${FSB_VERSION}"
    FSB_MAJOR_VERSION=${FSB_MAJOR_VERSION}
    FSB_MINOR_VERSION=${FSB_MINOR_VERSION}
    FSB_REV_NUMBER=${FSB_REV_NUMBER}

    $<$<CONFIG:Debug>:DEBUG>
)

# Add the map file to the list of files to be removed with 'clean' target
set_target_properties(bootloader PROPERTIES ADDITIONAL_CLEAN_FILES ${CMAKE_PROJECT_NAME}.map)

# Convert .elf to .bin
add_custom_command(TARGET bootloader POST_BUILD
        COMMAND ${CMAKE_OBJCOPY} -O binary
        ${CMAKE_CURRENT_BINARY_DIR}/bootloader.elf
        ${CMAKE_CURRENT_BINARY_DIR}/1st_stage_bootloader.bin
        COMMENT "Generating binary file from ELF"
)

# Copy the generated .bin file to ../
add_custom_command(TARGET bootloader POST_BUILD
    COMMAND ${CMAKE_COMMAND} -E copy
            ${CMAKE_CURRENT_BINARY_DIR}/1st_stage_bootloader.bin
            ${CMAKE_CURRENT_SOURCE_DIR}/../
    COMMENT "Copying 1st_stage_bootloader.bin to parent directory"
)

# Refresh the footprint report on a Release build. A Debug build leaves the committed
# numbers alone, so a report always describes the configuration customers ship.
if (CMAKE_BUILD_TYPE STREQUAL "Release")
	add_custom_command(TARGET bootloader POST_BUILD
		COMMAND python3 ${CMAKE_SOURCE_DIR}/footprint.py
		--map "${CMAKE_CURRENT_BINARY_DIR}/bootloader.map"
		--ld "${CMAKE_SOURCE_DIR}/cmake/stm32h573_flash.ld"
		--elf "${CMAKE_CURRENT_BINARY_DIR}/bootloader.elf"
		--output-summary "${CMAKE_SOURCE_DIR}/reports/footprint_summary.json"
		--build-type Release
		--folders ${SRC_ROOT}/cyclone_boot ${SRC_ROOT}/cyclone_crypto ${SRC_ROOT}/cyclone_tcp ${SRC_ROOT}/common
	)
endif ()
