Jianliang Shen | 7e48bef | 2022-10-31 16:15:36 +0800 | [diff] [blame] | 1 | #------------------------------------------------------------------------------- |
Kevin Peng | a2b6802 | 2023-01-13 13:54:05 +0800 | [diff] [blame] | 2 | # Copyright (c) 2022-2023, Arm Limited. All rights reserved. |
Jianliang Shen | 7e48bef | 2022-10-31 16:15:36 +0800 | [diff] [blame] | 3 | # |
| 4 | # SPDX-License-Identifier: BSD-3-Clause |
| 5 | # |
| 6 | #------------------------------------------------------------------------------- |
| 7 | |
Kevin Peng | 97ac698 | 2022-11-24 17:10:00 +0800 | [diff] [blame] | 8 | # Load multiple config files and merge into one, generates CMake config file and config header file. |
| 9 | # The first loaded configs would be overridden by later ones. That's how the "merge" works. |
| 10 | # Check CONFIG_FILE_LIST for the loading order. |
| 11 | # Configurations not set by any of the config files would be set to the default values in Kconfig |
| 12 | # files with dependencies respected. |
| 13 | # If a ".config" already exists in the output folder, then the CONFIG_FILE_LIST is ignored. |
| 14 | # For more details, check the kconfig_system.rst. |
| 15 | |
| 16 | set(KCONFIG_OUTPUT_DIR ${CMAKE_BINARY_DIR}/kconfig) |
| 17 | |
| 18 | set(DOTCONFIG_FILE ${KCONFIG_OUTPUT_DIR}/.config) |
| 19 | set(ROOT_KCONFIG ${CMAKE_SOURCE_DIR}/Kconfig) |
| 20 | set(PLATFORM_KCONFIG ${TARGET_PLATFORM_PATH}/Kconfig) |
Jianliang Shen | 7e48bef | 2022-10-31 16:15:36 +0800 | [diff] [blame] | 21 | |
Kevin Peng | b9c99f0 | 2022-12-07 11:23:17 +0800 | [diff] [blame] | 22 | if(TFM_PROFILE) |
| 23 | # Selecting TF-M profiles is not supported yet. |
| 24 | message(FATAL_ERROR "Selecting TF-M profiles is not supported yet in Kconfig system!") |
Jianliang Shen | 7e48bef | 2022-10-31 16:15:36 +0800 | [diff] [blame] | 25 | endif() |
| 26 | |
Kevin Peng | 026b811 | 2023-01-13 11:24:38 +0800 | [diff] [blame] | 27 | # This function parses the input ${cmake_file} to get normal CMake variables and their values in the |
| 28 | # format of "set(_VAR_ _VALUE_)". The format could be split into multiple lines. |
| 29 | # Note that CMake does not allow the "(" to be in a different line as "set" and no white spaces are |
| 30 | # recommanded between "set" and "(". So the function only covers format of "set(". |
| 31 | function(convert_normal_cmake_config_to_kconfig cmake_file out_var) |
| 32 | # Operate on a local var and write back to the "out_var" later. |
| 33 | set(local_var "") |
| 34 | |
| 35 | # Read out the strings of the file. Binary data in the file are ignored |
| 36 | file(STRINGS ${cmake_file} CONTENTS) |
| 37 | |
| 38 | # Exclude lines of comments (started with "#") |
| 39 | set(CONTENTS_WITHOUT_COMMENTS "") |
| 40 | |
| 41 | foreach(LINE ${CONTENTS}) |
| 42 | string(REGEX MATCH "^#.*" OUT_STRING ${LINE}) |
| 43 | if(NOT OUT_STRING) |
| 44 | string(APPEND CONTENTS_WITHOUT_COMMENTS "${LINE}\n") |
| 45 | endif() |
Kevin Peng | 13f0c25 | 2023-03-23 17:26:38 +0800 | [diff] [blame^] | 46 | |
| 47 | string(REGEX MATCH "^include\\((.*)\\)$" OUT_STRING ${LINE}) |
| 48 | if(OUT_STRING AND CMAKE_MATCH_COUNT EQUAL 1) |
| 49 | message(FATAL_ERROR "Including another file in config file is not supported yet: ${LINE}") |
| 50 | endif() |
Kevin Peng | 026b811 | 2023-01-13 11:24:38 +0800 | [diff] [blame] | 51 | endforeach() |
| 52 | |
| 53 | # Search for strings match set(_VAR_ _VALUE_) with support of multi-line format |
| 54 | string(REGEX MATCHALL |
| 55 | "set\\([ \t\r\n]*([A-Za-z0-9_]*)[ \t\r\n]*([^ \t\r\n]*)[ \t\r\n]*\\)" |
| 56 | OUT_STRINGS ${CONTENTS_WITHOUT_COMMENTS}) |
| 57 | |
| 58 | foreach(MATCHED_ITEM ${OUT_STRINGS}) |
| 59 | # Try to convert CMake format to Kconfig one |
| 60 | # If the format does not match, the content will not be changed and fall down to the next |
| 61 | |
| 62 | # Bool types |
| 63 | string(REGEX REPLACE |
| 64 | "set\\([ \t\r\n]*([A-Za-z0-9_]*)[ \t\r\n]*(TRUE|ON)[ \t\r\n]*\\)" |
| 65 | "config \\1\n default y\n" |
| 66 | MATCHED_ITEM ${MATCHED_ITEM}) |
| 67 | string(REGEX REPLACE |
| 68 | "set\\([ \t\r\n]*([A-Za-z0-9_]*)[ \t\r\n]*(FALSE|OFF)[ \t\r\n]*\\)" |
| 69 | "config \\1\n default n\n" |
| 70 | MATCHED_ITEM ${MATCHED_ITEM}) |
| 71 | # Hex int |
| 72 | string(REGEX REPLACE |
| 73 | "set\\([ \t\r\n]*([A-Za-z0-9_]*)[ \t\r\n]*(0x[0-9a-fA-F]+[ \t\r\n]*)\\)" |
| 74 | "config \\1\n default \\2\n" |
| 75 | MATCHED_ITEM ${MATCHED_ITEM}) |
| 76 | # Decimal int |
| 77 | string(REGEX REPLACE |
| 78 | "set\\([ \t\r\n]*([A-Za-z0-9_]*)[ \t\r\n]*([0-9]+)[ \t\r\n]*\\)" |
| 79 | "config \\1\n default \\2\n" |
| 80 | MATCHED_ITEM ${MATCHED_ITEM}) |
| 81 | # Quoted string |
| 82 | string(REGEX REPLACE |
| 83 | "set\\([ \t\r\n]*([A-Za-z0-9_]*)[ \t\r\n]*(\".*\")[ \t\r\n]*\\)" |
| 84 | "config \\1\n default \\2\n" |
| 85 | MATCHED_ITEM ${MATCHED_ITEM}) |
| 86 | # If none of the above matches, must be a non-quoted string |
| 87 | string(REGEX REPLACE |
| 88 | "set\\([ \t\r\n]*([A-Za-z0-9_]*)[ \t\r\n]*(.*)[ \t\r\n]*\\)" |
| 89 | "config \\1\n default \"\\2\"\n" |
| 90 | MATCHED_ITEM ${MATCHED_ITEM}) |
| 91 | |
| 92 | string(APPEND local_var ${MATCHED_ITEM}) |
| 93 | endforeach() |
| 94 | |
| 95 | set(${out_var} ${local_var} PARENT_SCOPE) |
| 96 | endfunction() |
| 97 | |
Kevin Peng | e72f29e | 2023-01-29 17:05:35 +0800 | [diff] [blame] | 98 | # This function goes through the CMake cache variables and convert them to .config format. |
| 99 | # The function distinguishes command-line variables and other ones and it can only handle one of |
| 100 | # them in the same time. |
| 101 | function(convert_cache_config_to_dotconfig convert_cl_var out_var) |
| 102 | # Operate on a local var and write back to the out_var later |
| 103 | set(local_var "") |
Kevin Peng | b9c99f0 | 2022-12-07 11:23:17 +0800 | [diff] [blame] | 104 | |
Kevin Peng | e72f29e | 2023-01-29 17:05:35 +0800 | [diff] [blame] | 105 | get_cmake_property(CACHE_VARS CACHE_VARIABLES) |
| 106 | foreach(CACHE_VAR ${CACHE_VARS}) |
| 107 | get_property(HELP_STRING CACHE ${CACHE_VAR} PROPERTY HELPSTRING) |
| 108 | |
| 109 | if("${HELP_STRING}" MATCHES "variable specified on the command line") |
| 110 | # Command-line variables have the help string above by default |
| 111 | set(IS_CL_VAR TRUE) |
| 112 | else() |
| 113 | set(IS_CL_VAR FALSE) |
| 114 | endif() |
| 115 | |
| 116 | if((IS_CL_VAR AND NOT ${convert_cl_var}) OR (NOT IS_CL_VAR AND ${convert_cl_var})) |
| 117 | continue() |
| 118 | endif() |
| 119 | |
| 120 | set(CACHE_VAR_VAL ${${CACHE_VAR}}) |
| 121 | STRING(TOUPPER "${CACHE_VAR_VAL}" CACHE_VAR_VAL_UPPER) |
| 122 | |
| 123 | set(CACHE_VAR "CONFIG_${CACHE_VAR}") |
| 124 | |
| 125 | set(KCONFIG_OPTION_ITEM "") |
| 126 | |
| 127 | # False CMAKE values |
| 128 | if(CACHE_VAR_VAL_UPPER STREQUAL "OFF" OR CACHE_VAR_VAL_UPPER STREQUAL "FALSE") |
| 129 | set(KCONFIG_OPTION_ITEM "${CACHE_VAR}=n\r\n") |
| 130 | # True CMAKE Values |
| 131 | elseif(CACHE_VAR_VAL_UPPER STREQUAL "ON" OR CACHE_VAR_VAL_UPPER STREQUAL "TRUE") |
| 132 | set(KCONFIG_OPTION_ITEM "${CACHE_VAR}=y\r\n") |
| 133 | # Non-quoted values (hex and decimal numbers) |
| 134 | elseif(CACHE_VAR_VAL MATCHES "^0x[a-fA-F0-9]+$" OR CACHE_VAR_VAL MATCHES "^[0-9]+$" ) |
| 135 | set(KCONFIG_OPTION_ITEM "${CACHE_VAR}=${CACHE_VAR_VAL}\r\n") |
| 136 | # Everything else is a quoted string |
| 137 | else() |
| 138 | if(${CACHE_VAR} STREQUAL "CONFIG_TEST_PSA_API") |
| 139 | # Turn on the corresponding "choice" option for psa-arch-test |
| 140 | list(APPEND _LEGAL_PSA_API_TEST_LIST "IPC" "CRYPTO" "INITIAL_ATTESTATION" "INTERNAL_TRUSTED_STORAGE" "PROTECTED_STORAGE" "STORAGE") |
| 141 | list(FIND _LEGAL_PSA_API_TEST_LIST ${CACHE_VAR_VAL_UPPER} _RET_VAL) |
| 142 | if(NOT ${_RET_VAL} EQUAL -1) |
| 143 | set(KCONFIG_OPTION_ITEM "CONFIG_PSA_API_TEST_${CACHE_VAR_VAL_UPPER}=y\r\n") |
| 144 | |
| 145 | if(${CACHE_VAR_VAL_UPPER} STREQUAL "IPC") |
| 146 | # PSA API IPC test requires IPC model to be enabled while |
| 147 | # the CONFIG_TFM_SPM_BACKEND_IPC cannot be selected or implied because it is a choice. |
| 148 | # It can be only enabled in a Kconfig config file. So append it here. |
| 149 | string(APPEND KCONFIG_OPTION_ITEM "CONFIG_CONFIG_TFM_SPM_BACKEND_IPC=y\r\n") |
| 150 | endif() |
| 151 | endif() |
| 152 | elseif(${CACHE_VAR} STREQUAL "CONFIG_CONFIG_TFM_SPM_BACKEND") |
| 153 | # Turn on the corresponding "choice" option for SPM backend |
| 154 | set(KCONFIG_OPTION_ITEM "CONFIG_CONFIG_TFM_SPM_BACKEND_${CACHE_VAR_VAL_UPPER}=y\r\n") |
| 155 | else() |
| 156 | set(KCONFIG_OPTION_ITEM "${CACHE_VAR}=\"${CACHE_VAR_VAL}\"\r\n") |
| 157 | endif() |
| 158 | endif() |
| 159 | |
| 160 | string(APPEND local_var ${KCONFIG_OPTION_ITEM}) |
| 161 | endforeach() |
| 162 | |
| 163 | set(${out_var} ${local_var} PARENT_SCOPE) |
| 164 | endfunction() |
| 165 | |
| 166 | # Initialize the .cl_config |
| 167 | set(COMMAND_LINE_CONFIG_TO_FILE ${KCONFIG_OUTPUT_DIR}/.cl_config) |
| 168 | file(REMOVE ${COMMAND_LINE_CONFIG_TO_FILE}) |
| 169 | |
| 170 | # Initialize the .cache_var_config |
| 171 | set(CACHE_VAR_CONFIG_FILE ${KCONFIG_OUTPUT_DIR}/.cache_var_config) |
| 172 | file(REMOVE ${CACHE_VAR_CONFIG_FILE}) |
| 173 | |
| 174 | if(NOT EXISTS ${PLATFORM_KCONFIG}) |
Kevin Peng | 026b811 | 2023-01-13 11:24:38 +0800 | [diff] [blame] | 175 | # Parse platform's preload.cmake and config.cmake to get config options. |
| 176 | set(PLATFORM_KCONFIG_OPTIONS "") |
| 177 | set(PLATFORM_KCONFIG ${KCONFIG_OUTPUT_DIR}/platform/Kconfig) |
| 178 | |
| 179 | convert_normal_cmake_config_to_kconfig(${TARGET_PLATFORM_PATH}/preload.cmake PLATFORM_KCONFIG_OPTIONS) |
| 180 | file(WRITE ${PLATFORM_KCONFIG} ${PLATFORM_KCONFIG_OPTIONS}) |
| 181 | |
Kevin Peng | b9c99f0 | 2022-12-07 11:23:17 +0800 | [diff] [blame] | 182 | if(EXISTS ${TARGET_PLATFORM_PATH}/config.cmake) |
| 183 | include(${TARGET_PLATFORM_PATH}/config.cmake) |
Kevin Peng | 026b811 | 2023-01-13 11:24:38 +0800 | [diff] [blame] | 184 | convert_normal_cmake_config_to_kconfig(${TARGET_PLATFORM_PATH}/config.cmake PLATFORM_KCONFIG_OPTIONS) |
| 185 | file(APPEND ${PLATFORM_KCONFIG} ${PLATFORM_KCONFIG_OPTIONS}) |
Kevin Peng | e72f29e | 2023-01-29 17:05:35 +0800 | [diff] [blame] | 186 | |
| 187 | set(PLATFORM_CMAKE_CONFIGS "") |
| 188 | set(CONVERT_CL_VAR FALSE) |
| 189 | convert_cache_config_to_dotconfig(CONVERT_CL_VAR PLATFORM_CMAKE_CONFIGS) |
| 190 | file(APPEND ${CACHE_VAR_CONFIG_FILE} ${PLATFORM_CMAKE_CONFIGS}) |
Kevin Peng | b9c99f0 | 2022-12-07 11:23:17 +0800 | [diff] [blame] | 191 | endif() |
| 192 | endif() |
Kevin Peng | 026b811 | 2023-01-13 11:24:38 +0800 | [diff] [blame] | 193 | get_filename_component(PLATFORM_KCONFIG_PATH ${PLATFORM_KCONFIG} DIRECTORY) |
Jianliang Shen | 7e48bef | 2022-10-31 16:15:36 +0800 | [diff] [blame] | 194 | |
Kevin Peng | e72f29e | 2023-01-29 17:05:35 +0800 | [diff] [blame] | 195 | # Parse command-line variables |
| 196 | set(CL_CONFIGS "") |
| 197 | set(CONVERT_CL_VAR TRUE) |
| 198 | convert_cache_config_to_dotconfig(CONVERT_CL_VAR CL_CONFIGS) |
| 199 | file(APPEND ${COMMAND_LINE_CONFIG_TO_FILE} ${CL_CONFIGS}) |
| 200 | |
| 201 | if(NOT EXISTS ${CACHE_VAR_CONFIG_FILE}) |
| 202 | set(CACHE_VAR_CONFIG_FILE "") |
| 203 | endif() |
| 204 | |
Kevin Peng | 97ac698 | 2022-11-24 17:10:00 +0800 | [diff] [blame] | 205 | # User customized config file |
| 206 | if(DEFINED KCONFIG_CONFIG_FILE AND NOT EXISTS ${KCONFIG_CONFIG_FILE}) |
| 207 | message(FATAL_ERROR "No such file: ${KCONFIG_CONFIG_FILE}") |
| 208 | endif() |
| 209 | |
| 210 | # Note the order of CONFIG_FILE_LIST, as the first loaded configs would be |
| 211 | # overridden by later ones. |
| 212 | list(APPEND CONFIG_FILE_LIST |
Kevin Peng | e72f29e | 2023-01-29 17:05:35 +0800 | [diff] [blame] | 213 | ${CACHE_VAR_CONFIG_FILE} |
| 214 | ${KCONFIG_CONFIG_FILE} |
| 215 | ${COMMAND_LINE_CONFIG_TO_FILE}) |
Kevin Peng | 97ac698 | 2022-11-24 17:10:00 +0800 | [diff] [blame] | 216 | |
| 217 | # Set up ENV variables for the tfm_kconfig.py which are then consumed by Kconfig files. |
Jianliang Shen | c4e719b | 2023-03-02 14:37:54 +0800 | [diff] [blame] | 218 | set(KCONFIG_ENV_VARS "TFM_SOURCE_DIR=${CMAKE_SOURCE_DIR} \ |
Kevin Peng | 97ac698 | 2022-11-24 17:10:00 +0800 | [diff] [blame] | 219 | TFM_VERSION=${TFM_VERSION} \ |
Kevin Peng | 026b811 | 2023-01-13 11:24:38 +0800 | [diff] [blame] | 220 | PLATFORM_PATH=${PLATFORM_KCONFIG_PATH} \ |
Kevin Peng | 97ac698 | 2022-11-24 17:10:00 +0800 | [diff] [blame] | 221 | CMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}") |
| 222 | |
| 223 | if(MENUCONFIG) |
| 224 | # Note: Currently, only GUI menuconfig can be supported with CMake integration |
| 225 | set(MENUCONFIG_ARG "-u=gui") |
| 226 | else() |
| 227 | set(MENUCONFIG_ARG "") |
| 228 | endif() |
| 229 | |
Jianliang Shen | 7c67ab1 | 2023-03-14 14:41:34 +0800 | [diff] [blame] | 230 | if(DEFINED PROJECT_CONFIG_HEADER_FILE) |
| 231 | get_property(HELP_STRING CACHE PROJECT_CONFIG_HEADER_FILE PROPERTY HELPSTRING) |
| 232 | |
| 233 | # It is not supported to set PROJECT_CONFIG_HEADER_FILE while using Kconfig, either from |
| 234 | # command line or CMake files. It should be set to the file generated the Kconfig system. |
| 235 | # As this file set it itself, if the user re-run the CMake config command, the |
| 236 | # PROJECT_CONFIG_HEADER_FILE will be already defined set. |
| 237 | # So the existence of the ${DOTCONFIG_FILE} is used to indicate if it is a re-configuration. |
| 238 | if("${HELP_STRING}" MATCHES "variable specified on the command line" OR NOT EXISTS ${DOTCONFIG_FILE}) |
| 239 | message(FATAL_ERROR "It is NOT supported to manually set PROJECT_CONFIG_HEADER_FILE while using Kconfig.") |
| 240 | endif() |
| 241 | endif() |
| 242 | |
Jianliang Shen | 7e48bef | 2022-10-31 16:15:36 +0800 | [diff] [blame] | 243 | find_package(Python3) |
| 244 | |
Jianliang Shen | 7e48bef | 2022-10-31 16:15:36 +0800 | [diff] [blame] | 245 | execute_process( |
| 246 | COMMAND |
| 247 | ${Python3_EXECUTABLE} ${CMAKE_SOURCE_DIR}/tools/kconfig/tfm_kconfig.py |
Kevin Peng | 97ac698 | 2022-11-24 17:10:00 +0800 | [diff] [blame] | 248 | -k ${ROOT_KCONFIG} -o ${KCONFIG_OUTPUT_DIR} |
| 249 | --envs ${KCONFIG_ENV_VARS} |
| 250 | --config-files ${CONFIG_FILE_LIST} |
| 251 | ${MENUCONFIG_ARG} |
Jianliang Shen | 7e48bef | 2022-10-31 16:15:36 +0800 | [diff] [blame] | 252 | WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} |
| 253 | RESULT_VARIABLE ret |
| 254 | ) |
| 255 | |
| 256 | if(NOT ret EQUAL 0) |
| 257 | message(FATAL_ERROR "Kconfig tool failed!") |
| 258 | endif() |
| 259 | |
Kevin Peng | 97ac698 | 2022-11-24 17:10:00 +0800 | [diff] [blame] | 260 | # Component configs generated by tfm_kconfig.py |
| 261 | set(PROJECT_CONFIG_HEADER_FILE ${KCONFIG_OUTPUT_DIR}/project_config.h CACHE FILEPATH "User defined header file for TF-M config") |
| 262 | |
Jianliang Shen | 7e48bef | 2022-10-31 16:15:36 +0800 | [diff] [blame] | 263 | # Load project cmake configs generated by tfm_kconfig.py |
Kevin Peng | 97ac698 | 2022-11-24 17:10:00 +0800 | [diff] [blame] | 264 | include(${KCONFIG_OUTPUT_DIR}/project_config.cmake) |
Kevin Peng | b9c99f0 | 2022-12-07 11:23:17 +0800 | [diff] [blame] | 265 | |
| 266 | #################################################################################################### |
| 267 | |
| 268 | # The Kconfig system does not cover all the config options for the time being. |
| 269 | # So part of them still use the CMake config system. |
| 270 | |
| 271 | # Load regression configs overrided by platform |
| 272 | if(EXISTS ${TARGET_PLATFORM_PATH}/reg_config_override.cmake) |
| 273 | include(${TARGET_PLATFORM_PATH}/reg_config_override.cmake) |
| 274 | endif() |
| 275 | |
| 276 | # Load build type config, setting options not already set |
| 277 | if(EXISTS ${CMAKE_SOURCE_DIR}/config/build_type/${CMAKE_BUILD_TYPE_LOWERCASE}.cmake) |
| 278 | include(${CMAKE_SOURCE_DIR}/config/build_type/${CMAKE_BUILD_TYPE_LOWERCASE}.cmake) |
| 279 | endif() |
| 280 | |
| 281 | # Load TF-M model specific default config |
| 282 | # Load IPC backend config if isolation level is explicitly specified to 2/3 or IPC backend is |
| 283 | # selected via build command line. Otherwise, load SFN backend config by default. |
| 284 | # If a pair of invalid settings are passed via command line, it will be captured later via config |
| 285 | # check. |
| 286 | # Also select IPC model by default for multi-core platform unless it has already selected SFN model |
| 287 | if((DEFINED TFM_ISOLATION_LEVEL AND TFM_ISOLATION_LEVEL GREATER 1) OR |
| 288 | CONFIG_TFM_SPM_BACKEND STREQUAL "IPC" OR |
| 289 | TFM_MULTI_CORE_TOPOLOGY) |
| 290 | include(config/tfm_ipc_config_default.cmake) |
| 291 | else() |
| 292 | #The default backend is SFN |
| 293 | include(config/tfm_sfn_config_default.cmake) |
| 294 | endif() |
| 295 | |
| 296 | # Load bl1 config |
| 297 | if(BL1 AND PLATFORM_DEFAULT_BL1) |
| 298 | include(${CMAKE_SOURCE_DIR}/bl1/config/bl1_config_default.cmake) |
| 299 | endif() |
| 300 | |
| 301 | # Load MCUboot specific default.cmake |
| 302 | if(NOT DEFINED BL2 OR BL2) |
| 303 | include(${CMAKE_SOURCE_DIR}/bl2/ext/mcuboot/mcuboot_default_config.cmake) |
| 304 | endif() |
| 305 | |
| 306 | # Include FWU partition configs. |
| 307 | include(config/tfm_fwu_config.cmake) |
| 308 | |
| 309 | # Include coprocessor configs |
| 310 | include(config/cp_config_default.cmake) |
| 311 | |
| 312 | # Load defaults, setting options not already set |
| 313 | include(config/config_base.cmake) |
| 314 | |
| 315 | # Set secure log configs |
| 316 | # It also depends on regression test config. |
| 317 | include(config/tfm_secure_log.cmake) |