1#-------------------------------------------------------------------------------
2# Copyright (c) 2020-2022, Arm Limited. All rights reserved.
3#
4# SPDX-License-Identifier: BSD-3-Clause
5#
6#-------------------------------------------------------------------------------
7
8cmake_minimum_required(VERSION 3.15)
9find_package(Python3)
10
11############################### Manifest lists declaration #####################
12list(APPEND MANIFEST_LISTS ${TFM_MANIFEST_LIST})
13
14if (TFM_NS_REG_TEST OR TFM_S_REG_TEST)
15    list(APPEND MANIFEST_LISTS ${TFM_TEST_PATH}/secure_fw/tfm_test_manifest_list.yaml)
16endif()
17
18if ("${TEST_PSA_API}" STREQUAL "IPC")
19    # The manifest tool does not recognize CMake varibles. Do configure_file() first.
20    configure_file(${CMAKE_CURRENT_SOURCE_DIR}/tfm_psa_ff_test_manifest_list.yaml
21                   ${CMAKE_CURRENT_BINARY_DIR}/tfm_psa_ff_test_manifest_list.yaml)
22    list(APPEND MANIFEST_LISTS ${CMAKE_CURRENT_BINARY_DIR}/tfm_psa_ff_test_manifest_list.yaml)
23endif()
24
25if (TFM_EXTRA_MANIFEST_LIST_FILES)
26    list(APPEND MANIFEST_LISTS ${TFM_EXTRA_MANIFEST_LIST_FILES})
27endif()
28
29if (TFM_EXTRAS_REPO_EXTRA_MANIFEST_LIST)
30    set(TMP_MANIFEST_LISTS ${TFM_EXTRAS_REPO_EXTRA_MANIFEST_LIST})
31    list(TRANSFORM TMP_MANIFEST_LISTS PREPEND ${TFM_EXTRAS_REPO_PATH}/)
32    list(APPEND MANIFEST_LISTS ${TMP_MANIFEST_LISTS})
33endif()
34
35# Remove any duplicate entries to prevent same path appended twice in case of mulitiple runs
36list(REMOVE_DUPLICATES MANIFEST_LISTS)
37
38############################### File list declaration ##########################
39set(GENERATED_FILE_LISTS ${CMAKE_CURRENT_SOURCE_DIR}/tfm_generated_file_list.yaml)
40set(GENERATED_FILE_LISTS ${GENERATED_FILE_LISTS} ${TFM_EXTRA_GENERATED_FILE_LIST_PATH})
41
42############################### Functions declaration ##########################
43# Parses the given YAML "files" to find out all the items of the given "field"
44# and put them to the "output_variable" as a list.
45function(parse_field_from_yaml files field output_variable)
46    set(local_variable "")
47    foreach(yaml_file ${files})
48        # Load the lines that refer to the key we selected
49        file(STRINGS ${yaml_file} temp_variable REGEX " *\"${field}\":")
50        # Take only the value of the key
51        list(TRANSFORM temp_variable REPLACE " *\"${field}\": *" ";")
52        # Remove all commas
53        list(TRANSFORM temp_variable REPLACE "," "")
54        # Remove all quote marks
55        list(TRANSFORM temp_variable REPLACE "\"" "")
56        list(APPEND local_variable ${temp_variable})
57    endforeach()
58    set(${output_variable} ${local_variable} PARENT_SCOPE)
59endfunction()
60
61############################### Dependency generation ##########################
62# Get all the manifest files from manifest lists
63foreach(MANIFEST_LIST ${MANIFEST_LISTS})
64    if (NOT EXISTS ${MANIFEST_LIST})
65        message(FATAL_ERROR "Manifest list ${MANIFEST_LIST} doesn't exist")
66    endif()
67
68    # Get the path of the manifest list
69    get_filename_component(MANIFEST_LIST_PATH ${MANIFEST_LIST} DIRECTORY)
70
71    # Get all the "manifest"
72    parse_field_from_yaml(${MANIFEST_LIST} manifest MANIFESTS)
73
74    foreach(MANIFEST ${MANIFESTS})
75        # Convert to absolute paths
76        if (NOT IS_ABSOLUTE ${MANIFEST})
77            get_filename_component(MANIFEST "${MANIFEST_LIST_PATH}/${MANIFEST}" ABSOLUTE)
78        endif()
79        list(APPEND MANIFEST_FILES ${MANIFEST})
80    endforeach()
81endforeach()
82
83parse_field_from_yaml("${GENERATED_FILE_LISTS}" template TEMPLATE_FILES)
84# Replace relative paths with absolute paths
85# Paths used in GENERATED_FILE_LISTS are all relative to TF-M root (${CMAKE_SOURCE_DIR})
86list(TRANSFORM TEMPLATE_FILES REPLACE "^([^/\\][^:].*)" "${CMAKE_SOURCE_DIR}/\\1")
87
88parse_field_from_yaml("${GENERATED_FILE_LISTS}" output OUTPUT_FILES)
89# Replace relative paths with absolute paths
90# Paths used in GENERATED_FILE_LISTS are all relative to TF-M root (${CMAKE_SOURCE_DIR})
91list(TRANSFORM OUTPUT_FILES REPLACE "^([^/\\][^:].*)" "${CMAKE_BINARY_DIR}/generated/\\1")
92
93############################### Generate Manifest config header ################
94
95# The function appends the given `config` to the `out_var` variable.
96# Supported `type` are [BOOL, STRING].
97# The format of contents appended is
98#   #cmakedefine01 config      for BOOL types
99#   #cmakedefine config @config@    for STRING types
100function(append_manifest_config out_var config type)
101    # Operate on a local var and write back to the out_var later
102    set(local_var ${${out_var}})
103
104    # Avoid duplications of configs
105    string(FIND "${local_var}" ${config} config_exists)
106    if(${config_exists} EQUAL -1)   # Not found
107        if (${type} STREQUAL "BOOL")
108            string(APPEND local_var "#cmakedefine01 ${config}\r\n")
109        elseif(${type} STREQUAL "STRING")
110            string(APPEND local_var "#cmakedefine ${config} @${config}@\r\n")
111        else()
112            message(FATAL_ERROR "Unsupported config type: ${type}")
113        endif()
114    endif()
115
116    set(${out_var} ${local_var} PARENT_SCOPE)
117endfunction()
118
119# The following build configurations are required to pass to manifest tool via the config header
120#   - The isolation level
121#   - The SPM backend
122#   - "conditional" attributes for every Secure Partition in manifest lists
123#   - "stack_size" in manifests
124#   - "heap_size" in manifests
125append_manifest_config(MANIFEST_CONFIG_H_CONTENT TFM_ISOLATION_LEVEL STRING)
126append_manifest_config(MANIFEST_CONFIG_H_CONTENT CONFIG_TFM_SPM_BACKEND STRING)
127
128parse_field_from_yaml("${MANIFEST_LISTS}" conditional CONDITIONS)
129foreach(CON ${CONDITIONS})
130    append_manifest_config(MANIFEST_CONFIG_H_CONTENT ${CON} BOOL)
131endforeach()
132
133parse_field_from_yaml("${MANIFEST_FILES}" stack_size STACK_SIZES)
134foreach(STK_SIZE ${STACK_SIZES})
135    if (NOT STK_SIZE GREATER 0)
136        # The "stack_size" might not be a valid number. Treat it as a configuration
137        append_manifest_config(MANIFEST_CONFIG_H_CONTENT ${STK_SIZE} STRING)
138    endif()
139endforeach()
140
141parse_field_from_yaml("${MANIFEST_FILES}" heap_size HEAP_SIZES)
142foreach(HEAP_SIZE ${HEAP_SIZES})
143    if (NOT HEAP_SIZE GREATER 0)
144        # The "heap_size" might not be a valid number. Treat it as a configuration
145        append_manifest_config(MANIFEST_CONFIG_H_CONTENT ${HEAP_SIZE} STRING)
146    endif()
147endforeach()
148
149# Generate the config header
150file(WRITE
151     ${CMAKE_CURRENT_BINARY_DIR}/manifest_config.h.in
152     ${MANIFEST_CONFIG_H_CONTENT})
153
154configure_file(${CMAKE_CURRENT_BINARY_DIR}/manifest_config.h.in
155               ${CMAKE_CURRENT_BINARY_DIR}/manifest_config.h)
156
157############################### Command declaration ############################
158
159# Workaround for heap support
160if ("${TEST_PSA_API}" STREQUAL "IPC")
161    execute_process(
162        WORKING_DIRECTORY ${PSA_ARCH_TESTS_PATH}/api-tests
163        COMMAND ${Python3_EXECUTABLE} tools/scripts/manifest_update.py
164    )
165endif()
166
167if (CONFIG_TFM_PARSE_MANIFEST_QUIET)
168    set(PARSE_MANIFEST_QUIET_FLAG "-q")
169else()
170    set(PARSE_MANIFEST_QUIET_FLAG "")
171endif()
172
173set(MANIFEST_COMMAND
174    ${Python3_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/tfm_parse_manifest_list.py
175    -m ${MANIFEST_LISTS}
176    -f ${GENERATED_FILE_LISTS}
177    -c ${CMAKE_CURRENT_BINARY_DIR}/manifest_config.h
178    -o ${CMAKE_BINARY_DIR}/generated
179    ${PARSE_MANIFEST_QUIET_FLAG})
180
181# The files need to be generated before cmake will allow them to be used as
182# sources. Due to issue with custom_command scoping the easiest way to do this
183# is to run the script at cmake-time.
184execute_process(
185    COMMAND ${MANIFEST_COMMAND}
186    RESULT_VARIABLE RET
187)
188
189if(RET EQUAL 0)
190    include(${CMAKE_BINARY_DIR}/generated/tools/config_impl.cmake)
191else()
192    message(FATAL_ERROR "Manifest tool failed to generate files!")
193endif()
194