cmake_minimum_required(VERSION 3.22)
project(bootloader C CXX ASM)

set(SRC_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/)
set(COMMON ${SRC_ROOT}/common)
set(CRYPTO ${SRC_ROOT}/cyclone_crypto)
set(UPDATE ${SRC_ROOT}/cyclone_boot)
set(TCP ${SRC_ROOT}/cyclone_tcp)
set(THIRD_PARTY ${CMAKE_SOURCE_DIR}/../../../../../third_party)
set(BSP ${THIRD_PARTY}/st/boards2/stm32n6xx_nucleo)
set(FREERTOS ${THIRD_PARTY}/freertos_10_5)
set(HTTP ${CMAKE_SOURCE_DIR}/../../../../common/update_protocols/http)
set(RESOURCE_COMPILER ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../tools/ResourceCompiler)
set(SIGNING_TOOL /opt/st/stm32cubeprogrammer/bin/STM32_SigningTool_CLI CACHE FILEPATH "ST signing tool adding the boot ROM header")

# Bootloader version shown in the trace
set(BOOT_VERSION "1.0.0" CACHE STRING "Standalone bootloader firmware version")

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(STATUS "Build type: ${CMAKE_BUILD_TYPE}")

# The whole HAL; the linker drops what the bootloader does not use
file(GLOB HAL_SOURCES ${THIRD_PARTY}/st/drivers/stm32n6xx_hal_driver/src/*.c)
list(FILTER HAL_SOURCES EXCLUDE REGEX "_template\\.c$")

add_executable(bootloader
        ${COMMON}/cpu_endian.c
        ${COMMON}/os_port_freertos.c
        ${COMMON}/date_time.c
        ${COMMON}/str.c
        ${COMMON}/path.c
        ${COMMON}/resource_manager.c
        ${UPDATE}/drivers/mcu_core/stm32n6xx_mcu_driver.c
        ${UPDATE}/drivers/flash/external/mx25um51245g_flash_driver.c
        ${UPDATE}/core/crc32.c
        ${UPDATE}/core/mailbox.c
        ${UPDATE}/modules/image/image.c
        ${UPDATE}/modules/image/image_process.c
        ${UPDATE}/modules/image/image_utils.c
        ${UPDATE}/modules/memory/memory.c
        ${UPDATE}/modules/memory/memory_ex.c
        ${UPDATE}/core/verify.c
        ${UPDATE}/modules/security/verify_auth.c
        ${UPDATE}/modules/security/verify_sign.c
        ${UPDATE}/modules/security/verify_runtime.c
        ${UPDATE}/modules/security/verify_integrity.c
        ${UPDATE}/modules/security/cipher.c
        ${UPDATE}/update/update.c
        ${UPDATE}/update/update_misc.c
        ${UPDATE}/bootloader/standalone/boot.c
        ${UPDATE}/bootloader/standalone/boot_trigger.c
        ${UPDATE}/bootloader/standalone/boot_recovery.c
        ${CRYPTO}/hash/md5.c
        ${CRYPTO}/hash/sha1.c
        ${CRYPTO}/hash/sha224.c
        ${CRYPTO}/hash/sha256.c
        ${CRYPTO}/hash/sha384.c
        ${CRYPTO}/hash/sha512.c
        ${CRYPTO}/mac/hmac.c
        ${CRYPTO}/cipher/rc4.c
        ${CRYPTO}/cipher/idea.c
        ${CRYPTO}/cipher/des.c
        ${CRYPTO}/cipher/des3.c
        ${CRYPTO}/cipher/aes.c
        ${CRYPTO}/cipher/camellia.c
        ${CRYPTO}/cipher/seed.c
        ${CRYPTO}/cipher/aria.c
        ${CRYPTO}/cipher_modes/cbc.c
        ${CRYPTO}/aead/ccm.c
        ${CRYPTO}/aead/gcm.c
        ${CRYPTO}/cipher/chacha.c
        ${CRYPTO}/mac/poly1305.c
        ${CRYPTO}/aead/chacha20_poly1305.c
        ${CRYPTO}/pkc/dh.c
        ${CRYPTO}/pkc/rsa.c
        ${CRYPTO}/pkc/dsa.c
        ${CRYPTO}/ecc/ec.c
        ${CRYPTO}/ecc/ec_curves.c
        ${CRYPTO}/ecc/ecdh.c
        ${CRYPTO}/ecc/ecdsa.c
        ${CRYPTO}/ecc/eddsa.c
        ${CRYPTO}/ecc/curve25519.c
        ${CRYPTO}/ecc/curve448.c
        ${CRYPTO}/ecc/x25519.c
        ${CRYPTO}/ecc/x448.c
        ${CRYPTO}/ecc/ed25519.c
        ${CRYPTO}/ecc/ed448.c
        ${CRYPTO}/mpi/mpi.c
        ${CRYPTO}/mpi/mpi_misc.c
        ${CRYPTO}/encoding/base64.c
        ${CRYPTO}/encoding/asn1.c
        ${CRYPTO}/encoding/oid.c
        ${CRYPTO}/pkix/pem_import.c
        ${CRYPTO}/pkix/pem_key_import.c
        ${CRYPTO}/pkix/pem_decrypt.c
        ${CRYPTO}/pkix/pem_common.c
        ${CRYPTO}/pkix/pkcs5_decrypt.c
        ${CRYPTO}/pkix/pkcs5_common.c
        ${CRYPTO}/pkix/pkcs8_key_parse.c
        ${CRYPTO}/pkix/x509_key_parse.c
        ${CRYPTO}/pkix/x509_cert_parse.c
        ${CRYPTO}/pkix/x509_cert_validate.c
        ${CRYPTO}/pkix/x509_cert_ext_parse.c
        ${CRYPTO}/pkix/x509_common.c
        ${CRYPTO}/pkix/x509_sign_parse.c
        ${CRYPTO}/pkix/x509_sign_verify.c
        ${CRYPTO}/kdf/hkdf.c
        ${CRYPTO}/ecc/ec_misc.c
        ${CRYPTO}/pkc/rsa_misc.c
        ${TCP}/core/net.c
        ${TCP}/core/net_mem.c
        ${TCP}/core/net_misc.c
        ${TCP}/core/nic.c
        ${TCP}/core/ethernet.c
        ${TCP}/core/ethernet_misc.c
        ${TCP}/ipv4/arp.c
        ${TCP}/ipv4/arp_cache.c
        ${TCP}/ipv4/ipv4.c
        ${TCP}/ipv4/ipv4_frag.c
        ${TCP}/ipv4/ipv4_multicast.c
        ${TCP}/ipv4/ipv4_misc.c
        ${TCP}/ipv4/icmp.c
        ${TCP}/core/ip.c
        ${TCP}/core/tcp.c
        ${TCP}/core/tcp_fsm.c
        ${TCP}/core/tcp_misc.c
        ${TCP}/core/tcp_timer.c
        ${TCP}/core/udp.c
        ${TCP}/core/socket.c
        ${TCP}/core/socket_misc.c
        ${TCP}/http/http_server.c
        ${TCP}/http/http_server_misc.c
        ${TCP}/http/http_server_auth.c
        ${TCP}/http/http_common.c
        ${TCP}/http/mime.c
        ${TCP}/drivers/mac/stm32n6xx_eth_driver.c
        ${TCP}/drivers/phy/lan8742_driver.c
        ${HTTP}/http_receiver.c
        ${HTTP}/http_transport.c
        ${FREERTOS}/croutine.c
        ${FREERTOS}/list.c
        ${FREERTOS}/queue.c
        ${FREERTOS}/tasks.c
        ${FREERTOS}/timers.c
        ${FREERTOS}/portable/gcc/arm_cm55_ntz/non_secure/port.c
        ${FREERTOS}/portable/gcc/arm_cm55_ntz/non_secure/portasm.c
        ${FREERTOS}/portable/memmang/heap_3.c
        ${BSP}/stm32n6xx_nucleo.c
        ${BSP}/stm32n6xx_nucleo_xspi.c
        ${THIRD_PARTY}/st/boards2/components/mx25um51245g/mx25um51245g.c
        ${HAL_SOURCES}
        ${CMAKE_SOURCE_DIR}/cmake/startup_stm32n657xx_fsbl.s
        ${CMAKE_SOURCE_DIR}/cmake/syscalls.c
        ${CMAKE_SOURCE_DIR}/src/system_stm32n6xx_fsbl.c
        ${CMAKE_SOURCE_DIR}/src/stm32n6xx_it.c
        ${CMAKE_SOURCE_DIR}/src/stm32n6xx_hal_timebase_tim.c
        ${CMAKE_SOURCE_DIR}/src/board.c
        ${CMAKE_SOURCE_DIR}/src/debug.c
        ${CMAKE_SOURCE_DIR}/src/main.c
        ${CMAKE_SOURCE_DIR}/src/res.c
)

target_include_directories(bootloader PUBLIC
        ${CMAKE_SOURCE_DIR}/src
        ${COMMON}
        ${HTTP}
        ${CRYPTO}
        ${TCP}
        ${UPDATE}
        ${UPDATE}/bootloader
        ${UPDATE}/modules
        ${FREERTOS}/include
        ${FREERTOS}/portable/gcc/arm_cm55_ntz/non_secure
        ${THIRD_PARTY}/cmsis/core/include
        ${THIRD_PARTY}/st/devices/stm32n6xx
        ${THIRD_PARTY}/st/drivers/stm32n6xx_hal_driver/inc
        ${BSP}
        ${THIRD_PARTY}/st/boards2/components/mx25um51245g
)

target_compile_definitions(bootloader PUBLIC
        STM32N657xx
        USE_HAL_DRIVER
        USE_STM32N6xx_NUCLEO
        _WINSOCK_H
        BOOT_VERSION_STRING="${BOOT_VERSION}"
        $<$<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, then add the header the boot ROM expects (no key: development boot)
add_custom_command(TARGET bootloader POST_BUILD
        COMMAND ${CMAKE_OBJCOPY} -O binary
        ${CMAKE_CURRENT_BINARY_DIR}/bootloader.elf
        ${CMAKE_CURRENT_BINARY_DIR}/bootloader.bin
)

if(EXISTS ${SIGNING_TOOL})
    add_custom_command(TARGET bootloader POST_BUILD
            COMMAND ${SIGNING_TOOL} -s -nk -of 0x80000000 -t fsbl -hv 2.3 -align
            -bin ${CMAKE_CURRENT_BINARY_DIR}/bootloader.bin
            -o ${CMAKE_CURRENT_SOURCE_DIR}/../bootloader_trusted.bin
            COMMENT "Generating bootloader_trusted.bin for the boot ROM"
    )
else()
    message(WARNING "${SIGNING_TOOL} not found, bootloader_trusted.bin will not be generated")
endif()

# Pre-build step: generate res.c (the upload page) using ResourceCompiler
if(WIN32)
    set(RC_TOOL ${RESOURCE_COMPILER}/bin/rc.exe)
else()
    set(RC_TOOL ${RESOURCE_COMPILER}/bin/rc)
endif()

add_custom_command(
        OUTPUT ${CMAKE_SOURCE_DIR}/src/res.c
        COMMAND ${RC_TOOL} ${CMAKE_SOURCE_DIR}/resources/ ${CMAKE_SOURCE_DIR}/src/res.c
        DEPENDS ${CMAKE_SOURCE_DIR}/resources/www/index.html
        COMMENT "Running Resource Compiler to generate res.c"
)

# 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}/http_server_bl.map"
		--ld "${CMAKE_SOURCE_DIR}/cmake/stm32n657_fsbl.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 ()
