1#-------------------------------------------------------------------------------
2# Copyright (c) 2020-2024, Arm Limited. All rights reserved.
3#
4# SPDX-License-Identifier: BSD-3-Clause
5#
6#-------------------------------------------------------------------------------
7
8set(CMAKE_SYSTEM_NAME Generic)
9
10find_program(CMAKE_C_COMPILER ${CROSS_COMPILE}-gcc)
11find_program(CMAKE_CXX_COMPILER ${CROSS_COMPILE}-g++)
12
13if(CMAKE_C_COMPILER STREQUAL "CMAKE_C_COMPILER-NOTFOUND")
14    message(FATAL_ERROR "Could not find compiler: '${CROSS_COMPILE}-gcc'")
15endif()
16
17if(CMAKE_CXX_COMPILER STREQUAL "CMAKE_CXX_COMPILER-NOTFOUND")
18    message(FATAL_ERROR "Could not find compiler: '${CROSS_COMPILE}-g++'")
19endif()
20
21set(CMAKE_ASM_COMPILER ${CMAKE_C_COMPILER})
22
23set(LINKER_VENEER_OUTPUT_FLAG -Wl,--cmse-implib,--out-implib=)
24set(COMPILER_CMSE_FLAG -mcmse)
25
26# This variable name is a bit of a misnomer. The file it is set to is included
27# at a particular step in the compiler initialisation. It is used here to
28# configure the extensions for object files. Despite the name, it also works
29# with the Ninja generator.
30set(CMAKE_USER_MAKE_RULES_OVERRIDE ${CMAKE_CURRENT_LIST_DIR}/cmake/set_extensions.cmake)
31
32# CMAKE_C_COMPILER_VERSION is not guaranteed to be defined.
33EXECUTE_PROCESS( COMMAND ${CMAKE_C_COMPILER} -dumpversion OUTPUT_VARIABLE GCC_VERSION )
34
35# ===================== SEt toolchain CPU and Arch =============================
36
37if (DEFINED TFM_SYSTEM_PROCESSOR)
38    if(TFM_SYSTEM_PROCESSOR MATCHES "cortex-m85" AND GCC_VERSION VERSION_LESS "13.0.0")
39        # GNUARM until version 13 does not support the -mcpu=cortex-m85 flag
40        message(WARNING "Cortex-m85 is only supported from GCC13. "
41                        "Falling back to -march usage for earlier versions.")
42    else()
43        set(CMAKE_SYSTEM_PROCESSOR ${TFM_SYSTEM_PROCESSOR})
44
45        if (DEFINED TFM_SYSTEM_DSP)
46            if (NOT TFM_SYSTEM_DSP)
47                string(APPEND CMAKE_SYSTEM_PROCESSOR "+nodsp")
48            endif()
49        endif()
50        # GCC specifies that '+nofp' is available on following M-profile cpus: 'cortex-m4',
51        # 'cortex-m7', 'cortex-m33', 'cortex-m35p' and 'cortex-m55'.
52        # Build fails if other M-profile cpu, such as 'cortex-m23', is added with '+nofp'.
53        # Explicitly list those cpu to align with GCC description.
54        if(GCC_VERSION VERSION_GREATER_EQUAL "8.0.0")
55            if(NOT CONFIG_TFM_ENABLE_FP AND
56                (TFM_SYSTEM_PROCESSOR STREQUAL "cortex-m4"
57                OR TFM_SYSTEM_PROCESSOR STREQUAL "cortex-m7"
58                OR TFM_SYSTEM_PROCESSOR STREQUAL "cortex-m33"
59                OR TFM_SYSTEM_PROCESSOR STREQUAL "cortex-m35p"
60                OR TFM_SYSTEM_PROCESSOR STREQUAL "cortex-m55"))
61                    string(APPEND CMAKE_SYSTEM_PROCESSOR "+nofp")
62            endif()
63        endif()
64
65        if(TFM_SYSTEM_ARCHITECTURE STREQUAL "armv8.1-m.main")
66            if(NOT CONFIG_TFM_ENABLE_MVE)
67                string(APPEND CMAKE_SYSTEM_PROCESSOR "+nomve")
68            endif()
69            if(NOT CONFIG_TFM_ENABLE_MVE_FP)
70                string(APPEND CMAKE_SYSTEM_PROCESSOR "+nomve.fp")
71            endif()
72        endif()
73    endif()
74
75endif()
76
77# CMAKE_SYSTEM_ARCH variable is not a built-in CMAKE variable. It is used to
78# set the compile and link flags when TFM_SYSTEM_PROCESSOR is not specified.
79# The variable name is choosen to align with the ARMCLANG toolchain file.
80set(CMAKE_SYSTEM_ARCH         ${TFM_SYSTEM_ARCHITECTURE})
81
82if(TFM_SYSTEM_ARCHITECTURE STREQUAL "armv8.1-m.main")
83    if(CONFIG_TFM_ENABLE_MVE)
84        string(APPEND CMAKE_SYSTEM_ARCH "+mve")
85    endif()
86    if(CONFIG_TFM_ENABLE_MVE_FP)
87        string(APPEND CMAKE_SYSTEM_ARCH "+mve.fp")
88    endif()
89endif()
90
91if (DEFINED TFM_SYSTEM_DSP)
92    # +nodsp modifier is only supported from GCC version 8.
93    if(GCC_VERSION VERSION_GREATER_EQUAL "8.0.0")
94        # armv8.1-m.main arch does not have +nodsp option
95        if ((NOT TFM_SYSTEM_ARCHITECTURE STREQUAL "armv8.1-m.main") AND
96            NOT TFM_SYSTEM_DSP)
97            string(APPEND CMAKE_SYSTEM_ARCH "+nodsp")
98        endif()
99    endif()
100endif()
101
102if(GCC_VERSION VERSION_GREATER_EQUAL "8.0.0")
103    if(CONFIG_TFM_ENABLE_FP)
104        string(APPEND CMAKE_SYSTEM_ARCH "+fp")
105    endif()
106endif()
107
108add_compile_options(
109    -specs=nano.specs
110    -specs=nosys.specs
111    -Wall
112    -Wno-format
113    -Wno-return-type
114    -Wno-unused-but-set-variable
115    -c
116    -fdata-sections
117    -ffunction-sections
118    -fno-builtin
119    -fshort-enums
120    -funsigned-char
121    -mthumb
122    $<$<COMPILE_LANGUAGE:C>:-std=c99>
123    $<$<COMPILE_LANGUAGE:CXX>:-std=c++11>
124    # Force DWARF version 4 for zephyr as pyelftools does not support version 5 at present
125    -gdwarf-4
126    $<$<OR:$<BOOL:${TFM_DEBUG_SYMBOLS}>,$<BOOL:${TFM_CODE_COVERAGE}>>:-g>
127)
128
129add_link_options(
130    --entry=Reset_Handler
131    -specs=nano.specs
132    -specs=nosys.specs
133    LINKER:-check-sections
134    LINKER:-fatal-warnings
135    LINKER:--gc-sections
136    LINKER:--no-wchar-size-warning
137)
138
139if(NOT CONFIG_TFM_MEMORY_USAGE_QUIET)
140    add_link_options(LINKER:--print-memory-usage)
141endif()
142
143if (GCC_VERSION VERSION_LESS 7.3.1)
144    message(FATAL_ERROR "Please use newer GNU Arm compiler version starting from 7.3.1.")
145endif()
146
147if (GCC_VERSION VERSION_EQUAL 10.2.1)
148    message(FATAL_ERROR "GNU Arm compiler version 10-2020-q4-major has an issue in CMSE support."
149                        " Select other GNU Arm compiler versions instead."
150                        " See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=99157 for the issue detail.")
151endif()
152
153# GNU Arm compiler version greater equal than *11.3.Rel1*
154# has a linker issue that required system calls are missing,
155# such as _read and _write. Add stub functions of required
156# system calls to solve this issue.
157#
158# READONLY linker script attribute is not supported in older
159# GNU Arm compilers. For these version the preprocessor will
160# remove the READONLY string from the linker scripts.
161if (GCC_VERSION VERSION_GREATER_EQUAL 11.3.1)
162    set(CONFIG_GNU_SYSCALL_STUB_ENABLED TRUE)
163    set(CONFIG_GNU_LINKER_READONLY_ATTRIBUTE TRUE)
164endif()
165
166if (CMAKE_SYSTEM_PROCESSOR)
167    set(CMAKE_C_FLAGS_INIT "-mcpu=${CMAKE_SYSTEM_PROCESSOR}")
168    set(CMAKE_CXX_FLAGS_INIT "-mcpu=${CMAKE_SYSTEM_PROCESSOR}")
169    set(CMAKE_ASM_FLAGS_INIT "-mcpu=${CMAKE_SYSTEM_PROCESSOR}")
170    set(CMAKE_C_LINK_FLAGS "-mcpu=${CMAKE_SYSTEM_PROCESSOR}")
171    set(CMAKE_ASM_LINK_FLAGS "-mcpu=${CMAKE_SYSTEM_PROCESSOR}")
172else()
173    set(CMAKE_C_FLAGS_INIT "-march=${CMAKE_SYSTEM_ARCH}")
174    set(CMAKE_CXX_FLAGS_INIT "-march=${CMAKE_SYSTEM_ARCH}")
175    set(CMAKE_ASM_FLAGS_INIT "-march=${CMAKE_SYSTEM_ARCH}")
176    set(CMAKE_C_LINK_FLAGS "-march=${CMAKE_SYSTEM_ARCH}")
177    set(CMAKE_ASM_LINK_FLAGS "-march=${CMAKE_SYSTEM_ARCH}")
178endif()
179
180set(CMAKE_C_FLAGS ${CMAKE_C_FLAGS_INIT})
181set(CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS_INIT})
182set(CMAKE_ASM_FLAGS ${CMAKE_ASM_FLAGS_INIT})
183
184set(BL2_COMPILER_CP_FLAG -mfloat-abi=soft)
185set(BL2_LINKER_CP_OPTION -mfloat-abi=soft)
186
187set(BL1_COMPILER_CP_FLAG -mfloat-abi=soft)
188set(BL1_LINKER_CP_OPTION -mfloat-abi=soft)
189
190if (CONFIG_TFM_FLOAT_ABI STREQUAL "hard")
191    set(COMPILER_CP_FLAG -mfloat-abi=hard)
192    set(LINKER_CP_OPTION -mfloat-abi=hard)
193    if (CONFIG_TFM_ENABLE_FP OR CONFIG_TFM_ENABLE_MVE_FP)
194        set(COMPILER_CP_FLAG -mfloat-abi=hard -mfpu=${CONFIG_TFM_FP_ARCH})
195        set(LINKER_CP_OPTION -mfloat-abi=hard -mfpu=${CONFIG_TFM_FP_ARCH})
196    endif()
197else()
198    set(COMPILER_CP_FLAG -mfloat-abi=soft)
199    set(LINKER_CP_OPTION -mfloat-abi=soft)
200endif()
201
202# For GNU Arm Embedded Toolchain doesn't emit __ARM_ARCH_8_1M_MAIN__, adding this macro manually.
203add_compile_definitions($<$<STREQUAL:${TFM_SYSTEM_ARCHITECTURE},armv8.1-m.main>:__ARM_ARCH_8_1M_MAIN__=1>)
204
205macro(target_add_scatter_file target)
206    target_link_options(${target}
207        PRIVATE
208        -T $<TARGET_OBJECTS:${target}_scatter>
209    )
210
211    add_library(${target}_scatter OBJECT)
212    foreach(scatter_file ${ARGN})
213        target_sources(${target}_scatter
214            PRIVATE
215                ${scatter_file}
216        )
217        # Cmake cannot use generator expressions in the
218        # set_source_file_properties command, so instead we just parse the regex
219        # for the filename and set the property on all files, regardless of if
220        # the generator expression would evaluate to true or not.
221        string(REGEX REPLACE ".*>:(.*)>$" "\\1" SCATTER_FILE_PATH "${scatter_file}")
222        set_source_files_properties(${SCATTER_FILE_PATH}
223            PROPERTIES
224            LANGUAGE C
225            KEEP_EXTENSION True # Don't use .o extension for the preprocessed file
226        )
227    endforeach()
228
229    add_dependencies(${target}
230        ${target}_scatter
231    )
232
233    set_target_properties(${target} PROPERTIES LINK_DEPENDS $<TARGET_OBJECTS:${target}_scatter>)
234
235    target_link_libraries(${target}_scatter
236        platform_region_defs
237        psa_interface
238        tfm_config
239    )
240
241    target_compile_options(${target}_scatter
242        PRIVATE
243            -E
244            -P
245            -xc
246    )
247
248    target_compile_definitions(${target}_scatter
249        PRIVATE
250            $<$<NOT:$<BOOL:${CONFIG_GNU_LINKER_READONLY_ATTRIBUTE}>>:READONLY=>
251    )
252endmacro()
253
254macro(add_convert_to_bin_target target)
255    get_target_property(bin_dir ${target} RUNTIME_OUTPUT_DIRECTORY)
256
257    add_custom_target(${target}_bin
258        SOURCES ${bin_dir}/${target}.bin
259    )
260    add_custom_command(OUTPUT ${bin_dir}/${target}.bin
261        DEPENDS ${target}
262        COMMAND ${CMAKE_OBJCOPY}
263            -O binary $<TARGET_FILE:${target}>
264            ${bin_dir}/${target}.bin
265    )
266
267    add_custom_target(${target}_elf
268        SOURCES ${bin_dir}/${target}.elf
269    )
270    add_custom_command(OUTPUT ${bin_dir}/${target}.elf
271        DEPENDS ${target}
272        COMMAND ${CMAKE_OBJCOPY}
273            -O elf32-littlearm $<TARGET_FILE:${target}>
274            ${bin_dir}/${target}.elf
275    )
276
277    add_custom_target(${target}_hex
278        SOURCES ${bin_dir}/${target}.hex
279    )
280    add_custom_command(OUTPUT ${bin_dir}/${target}.hex
281        DEPENDS ${target}
282        COMMAND ${CMAKE_OBJCOPY}
283            -O ihex $<TARGET_FILE:${target}>
284            ${bin_dir}/${target}.hex
285    )
286
287    add_custom_target(${target}_binaries
288        ALL
289        DEPENDS ${target}_bin
290        DEPENDS ${target}_elf
291        DEPENDS ${target}_hex
292    )
293endmacro()
294
295macro(target_share_symbols target)
296    get_target_property(TARGET_TYPE ${target} TYPE)
297    if (NOT TARGET_TYPE STREQUAL "EXECUTABLE")
298        message(FATAL_ERROR "${target} is not an executable. Symbols cannot be shared from libraries.")
299    endif()
300
301    foreach(symbol_file ${ARGN})
302        FILE(STRINGS ${symbol_file} SYMBOLS
303            LENGTH_MINIMUM 1
304        )
305        list(APPEND KEEP_SYMBOL_LIST ${SYMBOLS})
306    endforeach()
307
308    set(STRIP_SYMBOL_KEEP_LIST ${KEEP_SYMBOL_LIST})
309
310    # Force the target to not remove the symbols if they're unused.
311    list(TRANSFORM KEEP_SYMBOL_LIST PREPEND "-Wl,--undefined=")
312    target_link_options(${target}
313        PRIVATE
314            ${KEEP_SYMBOL_LIST}
315    )
316
317    list(TRANSFORM STRIP_SYMBOL_KEEP_LIST PREPEND  --keep-symbol=)
318    # strip all the symbols except those proveded as arguments
319    add_custom_command(
320        TARGET ${target}
321        POST_BUILD
322        COMMAND ${CMAKE_OBJCOPY}
323        ARGS $<TARGET_FILE:${target}> --wildcard ${STRIP_SYMBOL_KEEP_LIST} --strip-all $<TARGET_FILE_DIR:${target}>/${target}${CODE_SHARING_OUTPUT_FILE_SUFFIX}
324    )
325endmacro()
326
327macro(target_link_shared_code target)
328    foreach(symbol_provider ${ARGN})
329        if (TARGET ${symbol_provider})
330            get_target_property(SYMBOL_PROVIDER_TYPE ${symbol_provider} TYPE)
331            if (NOT SYMBOL_PROVIDER_TYPE STREQUAL "EXECUTABLE")
332                message(FATAL_ERROR "${symbol_provider} is not an executable. Symbols cannot be shared from libraries.")
333            endif()
334        endif()
335
336        add_dependencies(${target} ${symbol_provider})
337        target_link_options(${target} PRIVATE LINKER:-R$<TARGET_FILE_DIR:${symbol_provider}>/${symbol_provider}${CODE_SHARING_INPUT_FILE_SUFFIX})
338    endforeach()
339endmacro()
340
341macro(target_strip_symbols target)
342    set(SYMBOL_LIST "${ARGN}")
343    list(TRANSFORM SYMBOL_LIST PREPEND  --strip-symbol=)
344
345    add_custom_command(
346        TARGET ${target}
347        POST_BUILD
348        COMMAND ${CMAKE_OBJCOPY}
349        ARGS $<TARGET_FILE:${target}> --wildcard ${SYMBOL_LIST} $<TARGET_FILE:${target}>
350    )
351endmacro()
352
353macro(target_strip_symbols_from_dependency target dependency)
354    set(SYMBOL_LIST "${ARGN}")
355    list(TRANSFORM SYMBOL_LIST PREPEND  --strip-symbol=)
356
357    add_custom_command(
358        TARGET ${target}
359        PRE_LINK
360        COMMAND ${CMAKE_OBJCOPY}
361        ARGS $<TARGET_FILE:${dependency}> --wildcard ${SYMBOL_LIST} $<TARGET_FILE:${dependency}>
362    )
363endmacro()
364
365macro(target_weaken_symbols target)
366    set(SYMBOL_LIST "${ARGN}")
367    list(TRANSFORM SYMBOL_LIST PREPEND  --weaken-symbol=)
368
369    add_custom_command(
370        TARGET ${target}
371        POST_BUILD
372        COMMAND ${CMAKE_OBJCOPY}
373        ARGS $<TARGET_FILE:${target}> --wildcard ${SYMBOL_LIST} $<TARGET_FILE:${target}>
374    )
375endmacro()
376
377macro(target_weaken_symbols_from_dependency target dependency)
378    set(SYMBOL_LIST "${ARGN}")
379    list(TRANSFORM SYMBOL_LIST PREPEND  --weaken-symbol=)
380
381    add_custom_command(
382        TARGET ${target}
383        PRE_LINK
384        COMMAND ${CMAKE_OBJCOPY}
385        ARGS $<TARGET_FILE:${dependency}> --wildcard ${SYMBOL_LIST} $<TARGET_FILE:${dependency}>
386    )
387endmacro()
388
389# A dummy macro to align with Armclang workaround
390macro(tfm_toolchain_reload_compiler)
391endmacro()
392