TF-RMM Release v0.1.0
This is the first external release of TF-RMM and provides a reference
implementation of Realm Management Monitor (RMM) as specified by the
RMM Beta0 specification[1].
The `docs/readme.rst` has more details about the project and
`docs/getting_started/getting-started.rst` has details on how to get
started with TF-RMM.
[1] https://developer.arm.com/documentation/den0137/1-0bet0/?lang=en
Signed-off-by: Soby Mathew <soby.mathew@arm.com>
Change-Id: I205ef14c015e4a37ae9ae1a64e4cd22eb8da746e
diff --git a/cmake/Modules/ArmConfigOption.cmake b/cmake/Modules/ArmConfigOption.cmake
new file mode 100644
index 0000000..07b80c7
--- /dev/null
+++ b/cmake/Modules/ArmConfigOption.cmake
@@ -0,0 +1,449 @@
+#
+# SPDX-License-Identifier: BSD-3-Clause
+# SPDX-FileCopyrightText: Copyright TF-RMM Contributors.
+#
+
+#[=======================================================================[.rst:
+ArmConfigOption
+---------------
+
+.. default-domain:: cmake
+
+.. command:: arm_config_option
+
+Create a configuration option with more flexibility than offered by
+:module:`cmake_dependent_option() <module:CMakeDependentOption>`.
+
+.. code:: cmake
+
+ arm_config_option(NAME <name> HELP <help> [TYPE <type>] [DEFAULT <default>]
+ [[STRINGS <strings>...] [FREEFORM]] [ADVANCED]
+ [[DEPENDS <depends>] [ELSE <else>]] [FORCE <force>])
+
+This helper function is intended to simplify some of the complex mechanics
+involved in creating a robust, scalable configuration system for medium to
+large projects. It incorporates basic dependency resolution, overridable default
+values, and stronger typing in order to provide a smoother experience for both
+build system developers and users.
+
+Basics
+^^^^^^
+
+Every configuration option has one of the following types:
+
+- ``BOOL`` for booleans (shows as a toggle option)
+- ``STRING`` for strings (shows as a text box)
+- ``PATH`` for directory paths (shows as a directory chooser)
+- ``FILEPATH`` for file paths (shows as a file chooser)
+
+These are the types supported by the :prop_cache:`TYPE <prop_cache:TYPE>` cache
+entry property. It's important to choose the right type for the option in order
+to provide a consistent user experience.
+
+By default, any configuration option that does not specify a type (by providing
+a value to the ``TYPE`` argument) is ``BOOL``, unless the ``STRINGS`` argument
+has been provided. For example:
+
+.. code:: cmake
+
+ arm_config_option(NAME XYZ ... TYPE BOOL) # BOOL
+ arm_config_option(NAME XYZ ... TYPE STRING) # STRING
+ arm_config_option(NAME XYZ ... TYPE PATH) # PATH
+ arm_config_option(NAME XYZ ... TYPE FILEPATH) # FILEPATH
+
+ arm_config_option(NAME XYZ ...) # BOOL
+ arm_config_option(NAME XYZ ... STRINGS ...) # STRING
+
+Likewise, every configuration option has a (default) default value, dependent on
+its type:
+
+.. code:: cmake
+
+ arm_config_option(NAME XYZ ... TYPE BOOL) # FALSE
+ arm_config_option(NAME XYZ ... TYPE STRING) # ""
+ arm_config_option(NAME XYZ ... TYPE PATH) # ""
+ arm_config_option(NAME XYZ ... TYPE FILEPATH) # ""
+
+ arm_config_option(NAME XYZ ...) # FALSE
+ arm_config_option(NAME XYZ ... STRINGS X Y Z) # "X"
+
+Note that the default value of configuration options with a ``STRINGS`` list
+will use the first element of the list as the default.
+
+The default value can be overridden by providing a value to the ``DEFAULT``
+argument:
+
+.. code:: cmake
+
+ arm_config_option(NAME XYZ ... TYPE BOOL DEFAULT TRUE) # TRUE
+ arm_config_option(NAME XYZ ... TYPE STRING DEFAULT "x") # "x"
+ arm_config_option(NAME XYZ ... TYPE PATH DEFAULT "./x") # "./x"
+ arm_config_option(NAME XYZ ... TYPE FILEPATH DEFAULT "./x.txt") # "./x.txt"
+
+For options with a ``STRINGS`` list, the value provided to the ``DEFAULT``
+argument must exist within the list unless the ``FREEFORM`` argument has been
+provided. Freeform string list options permit values outside of the list:
+
+.. code:: cmake
+
+ arm_config_option(NAME XYZ ... STRINGS X Y Z) # "X"
+ arm_config_option(NAME XYZ ... STRINGS X Y Z DEFAULT Z) # "Z"
+ arm_config_option(NAME XYZ ... STRINGS X Y Z DEFAULT A FREEFORM) # "A"
+ arm_config_option(NAME XYZ ... STRINGS X Y Z DEFAULT A) # ERROR
+
+Configuration options can be marked as "advanced" by using the ``ADVANCED``
+flag. In CMake's user interfaces, this hides the configuration option behind the
+"advanced" toggle:
+
+ arm_config_option(NAME XYZ ...) # Always visible
+ arm_config_option(NAME XYZ ... ADVANCED) # Visible only when requested
+
+Some basic usage examples follow:
+
+.. code:: cmake
+
+ arm_config_option(
+ NAME MYPROJECT_ENABLE_FOO
+ HELP "Enable the foo feature.")
+
+ arm_config_option(
+ NAME MYPROJECT_ENABLE_BAR
+ HELP "Enable the bar feature."
+ ADVANCED)
+
+ arm_config_option(
+ NAME MYPROJECT_BAZ_NAME
+ HELP "Name of the baz."
+ TYPE STRING
+ DEFAULT "Baz")
+
+ arm_config_option(
+ NAME MYPROJECT_BAZ_TYPE
+ HELP "Type of the baz."
+ STRINGS "Surly" "Bewildered" "Aloof")
+
+ if(MYPROJECT_ENABLE_FOO)
+ message(STATUS "The foo feature is enabled!")
+ endif()
+
+ if(MYPROJECT_ENABLE_BAR)
+ message(STATUS "The bar feature is enabled!")
+ endif()
+
+ message(STATUS "The name of the baz is: ${MYPROJECT_BAZ_NAME}!")
+ message(STATUS "The type of the baz is: ${MYPROJECT_BAZ_TYPE}!")
+
+Dependencies
+^^^^^^^^^^^^
+
+Dependencies between options can be modelled using the ``DEPENDS`` argument.
+This argument takes an expression in :ref:`Condition Syntax`, which determines
+whether the option will be shown.
+
+For example, if you have a feature flag ``foo``, and you have a feature flag
+``bar`` that only makes sense if ``foo`` is enabled, you might use:
+
+.. code:: cmake
+
+ arm_config_option(
+ NAME MYPROJECT_ENABLE_FOO
+ HELP "Enable the foo feature.")
+
+ arm_config_option(
+ NAME MYPROJECT_ENABLE_BAR
+ HELP "Enable the bar feature."
+ DEPENDS MYPROJECT_ENABLE_FOO)
+
+Configuration options whose dependencies have not been met are hidden from the
+GUI (that is, the cache variable is given the ``INTERNAL`` type), and the
+default value is restored.
+
+If you need a value *other* than the default to be set if the dependency is not
+met, then use the ``ELSE`` argument:
+
+.. code:: cmake
+
+ arm_config_option(
+ NAME STACK_SIZE
+ HELP "Stack size (in bytes)."
+ TYPE STRING
+ DEFAULT 512)
+
+ arm_config_option(
+ NAME HEAP_SIZE
+ HELP "Heap size (in bytes)."
+ DEFAULT 65536)
+
+ arm_config_option(
+ NAME STACKHEAP_SIZE
+ HELP "Stackheap size."
+ DEFAULT 65536
+ DEPENDS ((STACK_SIZE EQUAL 0) AND (HEAP_SIZE EQUAL 0))
+ ELSE 0)
+
+In some cases you may need to forcibly overwrite the value of a configuration
+option under certain conditions. You can do this using the ``FORCE`` argument
+which, like ``DEPENDS``, accepts :ref:`Condition Syntax`. This is typically only
+useful for augmenting existing cache variables.
+
+In the following example, ``FORCE`` is used to forcibly override the default
+value of :variable:`CMAKE_BUILD_TYPE <variable:CMAKE_BUILD_TYPE>` (``""``) with
+a new default defined by the build system configuration:
+
+.. code:: cmake
+
+ arm_config_option(
+ NAME CMAKE_BUILD_TYPE
+ HELP "Build type."
+ STRINGS "Debug" "RelWithDebInfo" "MinSizeRel" "Release"
+ DEFAULT "MinSizeRel"
+ FORCE NOT CMAKE_BUILD_TYPE)
+
+Detecting Changes
+^^^^^^^^^^^^^^^^^
+
+In some cases it's useful to know whether a configuration option has been
+modified. Any configuration option created with this function has an associated
+``${NAME}_CHANGED`` cache variable, which can be used to detect whether the
+value of ``${NAME}`` has changed between the last configuration run and the
+current one.
+
+For example:
+
+.. code:: cmake
+
+ arm_config_option(
+ NAME ENABLE_FEATURE
+ HELP "Enable the feature.")
+
+ if(ENABLE_FEATURE_CHANGED)
+ message(STATUS "The feature's been toggled!")
+ endif()
+
+Fine-Grained Control
+^^^^^^^^^^^^^^^^^^^^
+
+Additional facilities for fine-grained control over defaults and forced values
+are provided by the :command:`arm_config_option_override`.
+#]=======================================================================]
+
+include_guard()
+
+function(arm_config_option)
+ set(_options "FREEFORM;ADVANCED")
+ set(_single_args "NAME;HELP;TYPE")
+ set(_multi_args "DEFAULT;STRINGS;DEPENDS;ELSE;FORCE")
+
+ cmake_parse_arguments(
+ arg "${_options}" "${_single_args}" "${_multi_args}" ${ARGN})
+
+ if("DEFAULT" IN_LIST arg_KEYWORDS_MISSING_VALUES)
+ set(arg_DEFAULT "")
+ endif()
+
+ #
+ # Attempt to derive the type from the other arguments given. Passing STRINGS
+ # implies a type of STRING, otherwise the type is BOOL.
+ #
+
+ if(NOT DEFINED arg_TYPE)
+ if(DEFINED arg_STRINGS)
+ set(arg_TYPE "STRING")
+ else()
+ set(arg_TYPE "BOOL")
+ endif()
+ endif()
+
+ #
+ # Identify a reasonable default if one has not been provided. For BOOL this
+ # is FALSE. If STRINGS has been provided then we take the first entry in the
+ # list. For any other type we use an empty string.
+ #
+
+ if(NOT DEFINED arg_DEFAULT)
+ if(arg_TYPE MATCHES "BOOL")
+ set(arg_DEFAULT "FALSE")
+ elseif(DEFINED arg_STRINGS)
+ list(GET arg_STRINGS 0 arg_DEFAULT)
+ else()
+ set(arg_DEFAULT "")
+ endif()
+ endif()
+
+ #
+ # If no dependency condition is provided, it is implicitly TRUE.
+ #
+
+ if(NOT DEFINED arg_DEPENDS)
+ set(arg_DEPENDS "TRUE")
+ endif()
+
+ if(${arg_DEPENDS})
+ #
+ # If an internal cache variable exists by this name but the dependency
+ # condition holds, it's because it previously didn't. We need to
+ # forcibly update the variable to make it visible again.
+ #
+
+ if(DEFINED "${arg_NAME}")
+ get_property(type CACHE "${arg_NAME}" PROPERTY TYPE)
+
+ if(type STREQUAL "INTERNAL")
+ set(arg_FORCE TRUE)
+ endif()
+ endif()
+
+ #
+ # If a force variable exists, take on its value and hide the cache
+ # variable. Otherwise, if a default variable exists, just take on its
+ # value.
+ #
+
+ if(DEFINED "${arg_NAME}_FORCE")
+ set(arg_TYPE "INTERNAL")
+ set(arg_DEFAULT "${${arg_NAME}_FORCE}")
+ elseif(DEFINED "${arg_NAME}_INIT")
+ set(arg_DEFAULT "${${arg_NAME}_INIT}")
+ endif()
+ else()
+ #
+ # If the dependency condition doesn't hold, hide the cache variable from
+ # the user.
+ #
+
+ set(arg_TYPE "INTERNAL")
+
+ #
+ # If an else value has been given, now is the time to adopt it.
+ #
+
+ if(DEFINED arg_ELSE)
+ set(arg_DEFAULT "${arg_ELSE}")
+ endif()
+ endif()
+
+ #
+ # Try to detect whether the user has overridden an already
+ # forcibly-overriden variable. We throw an error in this situation to avoid
+ # a split-brain configuration, where the variable expands to two values
+ # depending on which side of this function call you are on.
+ #
+ # This usually happens if the user has defined the value on the command
+ # line, as these options are replaced every time reconfiguration
+ # happens.
+ #
+
+ if((DEFINED "${arg_NAME}") AND
+ (DEFINED "${arg_NAME}_FORCE") AND
+ (NOT "${${arg_NAME}_FORCE}" STREQUAL "${${arg_NAME}}"))
+ set(value "${${arg_NAME}}")
+ unset("${arg_NAME}" CACHE)
+
+ if(${arg_DEPENDS})
+ message(FATAL_ERROR
+ "Overridden configuration option detected!\n"
+
+ "The configuration option `${arg_NAME}` cannot be given "
+ "the value `${value}` because it has been forcibly set to "
+ "`${arg_DEFAULT}`.")
+ else()
+ string(REPLACE ";" " " dependency "${arg_DEPENDS}")
+
+ message(FATAL_ERROR
+ "Impossible configuration detected!\n"
+
+ "The configuration option `${arg_NAME}` cannot be given "
+ "the value `${value}` because it has been forcibly set to "
+ "`${arg_DEFAULT}` due to an unmet dependency:\n"
+
+ "${dependency}")
+ endif()
+ endif()
+
+ #
+ # The official documentation says that `INTERNAL` implies `FORCE`, but this
+ # does not seem to be the case in some situations, so let's be safe.
+ #
+
+ if(arg_TYPE STREQUAL "INTERNAL")
+ set(arg_FORCE TRUE)
+ endif()
+
+ #
+ # If we're being asked to forcibly update the cache variable, append FORCE
+ # to the set() call.
+ #
+
+ if((DEFINED arg_FORCE) AND (${arg_FORCE}))
+ set(force "FORCE")
+ else()
+ unset(force)
+
+ #
+ # Clear the forced-value variable so that we don't accidentally flag
+ # this
+ #
+
+ unset("${arg_NAME}_FORCE" CACHE)
+ endif()
+
+ #
+ # Update the change-tracking variable.
+ #
+
+ set(old "${${arg_NAME}_NEW}")
+ set(new "${${arg_NAME}}")
+
+ if(NOT old STREQUAL new)
+ set(changed TRUE)
+ else()
+ set(changed FALSE)
+ endif()
+
+ set("${arg_NAME}_OLD" "${old}"
+ CACHE INTERNAL "Previous value of ${arg_NAME}." FORCE)
+
+ set("${arg_NAME}_NEW" "${new}"
+ CACHE INTERNAL "Latest value of ${arg_NAME}." FORCE)
+
+ set("${arg_NAME}_CHANGED" ${changed}
+ CACHE INTERNAL "Has ${arg_NAME} just changed?" FORCE)
+
+ #
+ # Create the cache variable.
+ #
+
+ set("${arg_NAME}" "${arg_DEFAULT}"
+ CACHE "${arg_TYPE}" "${arg_HELP}" ${force})
+
+ if(arg_ADVANCED)
+ mark_as_advanced("${arg_NAME}")
+ endif()
+
+ #
+ # If we've been given a list of valid values, update the STRINGS property of
+ # the cache variable with that list.
+ #
+
+ if(DEFINED arg_STRINGS)
+ set_property(CACHE "${arg_NAME}" PROPERTY STRINGS ${arg_STRINGS})
+
+ #
+ # If we haven't been asked to offer a freeform text box, let the user
+ # know if they've provided something out of bounds.
+ #
+
+ if((NOT arg_FREEFORM) AND (NOT "${${arg_NAME}}" IN_LIST arg_STRINGS))
+ set(strings "")
+
+ foreach(string IN LISTS arg_STRINGS)
+ string(APPEND strings "\"${string}\" ")
+ endforeach()
+
+ message(FATAL_ERROR
+ "Invalid value for `${arg_NAME}`!\n"
+
+ "This configuration supports the following values: ${strings}")
+ endif()
+ endif()
+endfunction()
diff --git a/cmake/Modules/ArmConfigOptionOverride.cmake b/cmake/Modules/ArmConfigOptionOverride.cmake
new file mode 100644
index 0000000..8e5b270
--- /dev/null
+++ b/cmake/Modules/ArmConfigOptionOverride.cmake
@@ -0,0 +1,94 @@
+#
+# SPDX-License-Identifier: BSD-3-Clause
+# SPDX-FileCopyrightText: Copyright TF-RMM Contributors.
+#
+
+#[=======================================================================[.rst:
+ArmConfigOptionOverride
+-----------------------
+
+.. default-domain:: cmake
+
+.. command:: arm_config_option_override
+
+Override the default or final value of a configuration option defined by
+:command:`arm_config_option`.
+
+.. note::
+
+ Configuration options can only be overridden if their dependencies are met.
+ This ensures the configuration space is always in a valid state.
+
+Override Default Value
+^^^^^^^^^^^^^^^^^^^^^^
+
+.. code:: cmake
+
+ arm_config_option_override(NAME <name> DEFAULT <default>)
+
+Overrides the default value of the configuration option ``<name>`` with the
+value ``<default>``.
+
+For example:
+
+.. code:: cmake
+
+ arm_config_option_override(
+ NAME MYPROJECT_USE_FOO
+ DEFAULT TRUE)
+
+ arm_config_option(
+ NAME MYPROJECT_USE_FOO
+ HELP "Use foo.")
+
+In this situation, the configuration option ``USE_FOO`` is created with a
+default value of ``FALSE``, but will use the overridden default value of
+``TRUE``. This is most often useful in larger projects where certain default
+values make more sense under certain conditions.
+
+Forcibly Override Value
+=======================
+
+.. code:: cmake
+
+ arm_config_option_override(NAME <name> FORCE <force>)
+
+Forcibly overrides the value of the configuration option ``<name>`` with
+``<force>``.
+
+For example:
+
+.. code:: cmake
+
+ arm_config_option_override(
+ NAME MYPROJECT_USE_FOO
+ FORCE TRUE)
+
+ arm_config_option(
+ NAME MYPROJECT_USE_FOO
+ HELP "Use foo.")
+
+In this situation, ``USE_FOO`` will be forcibly set to ``TRUE``, and it will be
+hidden from the GUI. Users may also no longer configure this value themselves.
+Attempting to change the value of the configuration option will cause a
+configuration failure, and the previous value will be restored.
+#]=======================================================================]
+
+include_guard()
+
+function(arm_config_option_override)
+ set(_options "")
+ set(_single_args "NAME;DEFAULT;FORCE")
+ set(_multi_args "")
+
+ cmake_parse_arguments(arg "${_options}" "${_single_args}" "${_multi_args}"
+ ${ARGN})
+
+ if(DEFINED arg_FORCE)
+ set("${arg_NAME}_FORCE" "${arg_FORCE}" CACHE INTERNAL
+ "Forced value for `${arg_NAME}`." FORCE)
+ elseif(DEFINED arg_DEFAULT)
+ set("${arg_NAME}_INIT" "${arg_DEFAULT}" CACHE INTERNAL
+ "Default value for `${arg_NAME}`." FORCE)
+ endif()
+endfunction()
diff --git a/cmake/Modules/ArmPreprocessSource.cmake b/cmake/Modules/ArmPreprocessSource.cmake
new file mode 100644
index 0000000..a3f511b
--- /dev/null
+++ b/cmake/Modules/ArmPreprocessSource.cmake
@@ -0,0 +1,168 @@
+#
+# SPDX-License-Identifier: BSD-3-Clause
+# SPDX-FileCopyrightText: Copyright TF-RMM Contributors.
+#
+
+#[=======================================================================[.rst:
+ArmPreprocessSource
+-------------------
+
+.. default-domain:: cmake
+
+.. command:: arm_preprocess_source
+
+Preprocess a file with the C preprocessor.
+
+.. code:: cmake
+
+ arm_preprocess_source(<target> <source>)
+
+Creates a target ``<target>`` which preprocesses an input file ``<source>``. The
+target created by this macro can then be used as a dependency for a higher-level
+target. The output file can be retrieved from the :prop_tgt:`LOCATION_<CONFIG>
+<prop_tgt:LOCATION_<CONFIG>>` target property.
+
+The following target properties are passed to the preprocessor:
+
+- :prop_tgt:`COMPILE_OPTIONS <prop_tgt:COMPILE_OPTIONS>`
+- :prop_tgt:`COMPILE_DEFINITIONS <prop_tgt:COMPILE_DEFINITIONS>`
+- :prop_tgt:`INCLUDE_DIRECTORIES <prop_tgt:INCLUDE_DIRECTORIES>`
+
+.. note::
+
+ The created target automatically inherits :variable:`CMAKE_C_FLAGS
+ <variable:CMAKE_<LANG>_FLAGS>` and :variable:`CMAKE_C_FLAGS_<CONFIG>
+ <variable:CMAKE_<LANG>_FLAGS_<CONFIG>>`.
+
+For example, if you wish to preprocess a file while providing the preprocessor
+definition ``-DFOO=BAR``, you would use:
+
+.. code:: cmake
+
+ arm_preprocess_source(foo "bar.ld.S")
+
+ set_target_properties(foo PROPERTIES
+ COMPILE_DEFINITIONS "FOO=BAR")
+
+ get_target_property(location foo LOCATION_${CMAKE_BUILD_TYPE})
+
+ message(STATUS "My preprocessed file is here: ${location}")
+
+For processing linker scripts specifically, see the
+:command:`arm_target_linker_script` command instead.
+#]=======================================================================]
+
+include_guard()
+
+macro(arm_preprocess_source target source)
+ #
+ # We start by trying to get the source file relative to the current source
+ # directory, which means that we can mirror where it goes in the binary
+ # directory. This just replicates what CMake does with source files it's
+ # aware of.
+ #
+
+ get_filename_component(preprocessed_source "${source}.i" ABSOLUTE)
+ file(RELATIVE_PATH preprocessed_source "${CMAKE_CURRENT_SOURCE_DIR}"
+ "${preprocessed_source}")
+
+ #
+ # If we're using a multi-config generator, we need to place the output file
+ # into the correct configuration directory.
+ #
+
+ get_property(multi_config GLOBAL
+ PROPERTY "GENERATOR_IS_MULTI_CONFIG")
+
+ if(multi_config)
+ string(PREPEND preprocessed_source "$<CONFIG>/")
+ endif()
+
+ #
+ # Make the source path absolute so that we don't need to care which
+ # working directory the preprocessor uses.
+ #
+
+ string(PREPEND preprocessed_source "${CMAKE_CURRENT_BINARY_DIR}/")
+
+ #
+ # Create a single target for all configurations. It's differentiated based
+ # on the generator expression in the dependency.
+ #
+
+ add_custom_target(${target}
+ DEPENDS "${preprocessed_source}")
+
+ #
+ # Now that we've got that out of the way, we need to generate the
+ # preprocessing command for each of the enabled configurations. Multi-config
+ # generators will use `CMAKE_CONFIGURATION_TYPES`, whereas single-config
+ # generators will use `CMAKE_BUILD_TYPE`. Only one is ever non-empty.
+ #
+
+ foreach(config IN LISTS CMAKE_CONFIGURATION_TYPES CMAKE_BUILD_TYPE)
+ #
+ # CMake provides the `CMAKE_C_CREATE_PREPROCESSED_SOURCE` variable,
+ # which describes the command line required to preprocess a C source
+ # file. This variable is in a format similar to this:
+ #
+ # <CMAKE_C_COMPILER> <DEFINES> <INCLUDES> <FLAGS> -E <SOURCE> >
+ # <PREPROCESSED_SOURCE>
+ #
+ # We do some processing on this variable to convert these
+ # bracket-surrounded names to variables we set. For example, `<DEFINES>`
+ # is replaced with `${DEFINES}`. We then need to do some string
+ # replacement magic to expand that string out to the value of the actual
+ # variable.
+ #
+ # The values for some of these, namely include directories, definitions
+ # and other compiler options, come from properties set on the target by
+ # the caller. These are typically taken from the target that this
+ # preprocessed source file belongs to.
+ #
+
+ set(command ${CMAKE_C_CREATE_PREPROCESSED_SOURCE})
+ string(REPLACE " " ";" command ${command})
+
+ get_filename_component(SOURCE "${source}" ABSOLUTE)
+ string(REPLACE "$<CONFIG>" "${config}" PREPROCESSED_SOURCE
+ "${preprocessed_source}")
+
+ separate_arguments(FLAGS UNIX_COMMAND
+ "${CMAKE_C_FLAGS} ${CMAKE_C_FLAGS_${config}} -P -x c")
+
+ if(CMAKE_C_COMPILER_TARGET)
+ if(CMAKE_C_COMPILER_ID MATCHES "Clang")
+ list(APPEND FLAGS "-target" "${CMAKE_C_COMPILER_TARGET}")
+ endif()
+ endif()
+
+ unset(DEFINES)
+ unset(INCLUDES)
+
+ list(APPEND FLAGS "$<TARGET_PROPERTY:${target},COMPILE_OPTIONS>")
+ list(APPEND DEFINES "$<TARGET_PROPERTY:${target},COMPILE_DEFINITIONS>")
+ list(APPEND INCLUDES "$<TARGET_PROPERTY:${target},INCLUDE_DIRECTORIES>")
+
+ set(DEFINES "$<$<BOOL:${DEFINES}>:-D$<JOIN:${DEFINES},$<SEMICOLON>-D>>")
+ set(INCLUDES "$<$<BOOL:${INCLUDES}>:-I$<JOIN:${INCLUDES},$<SEMICOLON>-I>>")
+
+ string(REGEX REPLACE "<([[A-Z_]+)>" "\${\\1}" command "${command}")
+ string(REGEX MATCH "\\\${[^}]*}" match "${command}")
+
+ while(match)
+ string(REGEX REPLACE "\\\${(.*)}" "\\1" variable "${match}")
+ string(REPLACE "\${${variable}}" "${${variable}}" command "${command}")
+ string(REGEX MATCH "\\\${[^}]*}" match "${command}")
+ endwhile()
+
+ add_custom_command(
+ OUTPUT "${PREPROCESSED_SOURCE}"
+ MAIN_DEPENDENCY ${source}
+ COMMAND "${command}"
+ VERBATIM COMMAND_EXPAND_LISTS)
+
+ set_target_properties(${target} PROPERTIES
+ LOCATION_${config} "${PREPROCESSED_SOURCE}")
+ endforeach()
+endmacro()
diff --git a/cmake/Modules/ArmTargetLinkerScript.cmake b/cmake/Modules/ArmTargetLinkerScript.cmake
new file mode 100644
index 0000000..087fe8e
--- /dev/null
+++ b/cmake/Modules/ArmTargetLinkerScript.cmake
@@ -0,0 +1,89 @@
+#
+# SPDX-License-Identifier: BSD-3-Clause
+# SPDX-FileCopyrightText: Copyright TF-RMM Contributors.
+#
+
+#[=======================================================================[.rst:
+ArmTargetLinkerScript
+---------------------
+
+.. default-domain:: cmake
+
+.. command:: arm_target_linker_script
+
+Set the linker script for a target.
+
+.. code:: cmake
+
+ arm_target_linker_script(<target> <script>)
+
+Sets the linker script of the target ``<target>`` to the script ``<script>``,
+which is first preprocessed with the C preprocessor.
+
+Properties for the linker script target may be set on `<target>-lds`.
+
+Example usage:
+
+.. code:: cmake
+
+ add_executable(my-executable "main.c")
+
+ arm_target_linker_script(my-executable "linker.lds")
+
+ set_target_properties(my-executable-lds
+ PROPERTIES COMPILE_DEFINITIONS "__LINKER__")
+
+.. note::
+
+ When preprocessing, the linker script given to this macro automatically
+ inherits :variable:`CMAKE_C_FLAGS <variable:CMAKE_<LANG>_FLAGS>` and
+ :variable:`CMAKE_C_FLAGS_<CONFIG> <variable:CMAKE_<LANG>_FLAGS_<CONFIG>>`.
+
+ It also inherits the following properties from the target ``<target>``:
+
+ - :prop_tgt:`COMPILE_OPTIONS <prop_tgt:COMPILE_OPTIONS>`
+ - :prop_tgt:`COMPILE_DEFINITIONS <prop_tgt:COMPILE_DEFINITIONS>`
+ - :prop_tgt:`INCLUDE_DIRECTORIES <prop_tgt:INCLUDE_DIRECTORIES>`
+#]=======================================================================]
+
+include_guard()
+
+include(ArmPreprocessSource)
+
+macro(arm_target_linker_script target script)
+ set(subtarget "${target}-lds")
+
+ #
+ # Preprocess the linker script before doing anything else.
+ #
+
+ arm_preprocess_source(${subtarget} "${script}")
+
+ set_target_properties(${subtarget}
+ PROPERTIES
+ COMPILE_OPTIONS
+ "$<TARGET_PROPERTY:${target},COMPILE_OPTIONS>"
+ COMPILE_DEFINITIONS
+ "$<TARGET_PROPERTY:${target},COMPILE_DEFINITIONS>"
+ INCLUDE_DIRECTORIES
+ "$<TARGET_PROPERTY:${target},INCLUDE_DIRECTORIES>")
+
+ #
+ # Add the linker script to the dependencies of the target.
+ #
+
+ add_dependencies(${target} ${subtarget})
+
+ set(location "$<TARGET_PROPERTY:${subtarget},LOCATION_$<CONFIG>>")
+
+ set_target_properties(${target}
+ PROPERTIES INTERFACE_LINK_DEPENDS "${location}")
+
+ if(CMAKE_C_COMPILER_ID STREQUAL "ARMClang")
+ target_link_options(${target}
+ PUBLIC "LINKER:--scatter" "LINKER:${location}")
+ else()
+ target_link_options(${target}
+ PUBLIC "LINKER:-T" "LINKER:${location}")
+ endif()
+endmacro()
diff --git a/cmake/Modules/FindMbedTLS.cmake b/cmake/Modules/FindMbedTLS.cmake
new file mode 100644
index 0000000..89fb237
--- /dev/null
+++ b/cmake/Modules/FindMbedTLS.cmake
@@ -0,0 +1,60 @@
+#
+# SPDX-License-Identifier: BSD-3-Clause
+# SPDX-FileCopyrightText: Copyright TF-RMM Contributors.
+#
+
+#[=======================================================================[.rst:
+FindMbedTLS
+===========
+
+TODO: documentation.
+#]=======================================================================]
+
+include(FindPackageHandleStandardArgs)
+
+find_path(MbedTLS_INCLUDE_DIR
+ NAMES "mbedtls/build_info.h")
+
+if(MbedTLS_INCLUDE_DIR)
+ mark_as_advanced(MbedTLS_INCLUDE_DIR)
+
+ set(MbedTLS_FOUND TRUE)
+endif()
+
+find_library(MbedTLS_Crypto_LIBRARY "mbedcrypto" PATHS "library" "lib")
+find_library(MbedTLS_TLS_LIBRARY "mbedtls" PATHS "library" "lib")
+find_library(MbedTLS_X509_LIBRARY "mbedx509" PATHS "library" "lib")
+
+foreach(component IN ITEMS Crypto TLS X509)
+ if(MbedTLS_${component}_LIBRARY)
+ mark_as_advanced(MbedTLS_${component}_LIBRARY)
+
+ set(MbedTLS_${component}_FOUND TRUE)
+ endif()
+endforeach()
+
+find_package_handle_standard_args(MbedTLS HANDLE_COMPONENTS
+ REQUIRED_VARS MbedTLS_FOUND MbedTLS_INCLUDE_DIR)
+
+if(MbedTLS_FOUND)
+ add_library(MbedTLS INTERFACE)
+
+ target_include_directories(MbedTLS
+ INTERFACE "${MbedTLS_INCLUDE_DIR}"
+ "${RMM_SOURCE_DIR}/configs/mbedtls")
+
+ target_compile_definitions(MbedTLS
+ INTERFACE "MBEDTLS_CONFIG_FILE=<mbedtls_config.h>")
+
+ foreach(component IN ITEMS Crypto TLS X509)
+ if(MbedTLS_${component}_LIBRARY)
+ add_library(MbedTLS::${component} UNKNOWN IMPORTED)
+
+ set_target_properties(MbedTLS::${component}
+ PROPERTIES IMPORTED_LOCATION "${MbedTLS_${component}_LIBRARY}")
+
+ target_link_libraries(MbedTLS::${component}
+ INTERFACE MbedTLS)
+ endif()
+ endforeach()
+endif()
diff --git a/cmake/Modules/FindPlantUML.cmake b/cmake/Modules/FindPlantUML.cmake
new file mode 100644
index 0000000..331c221c76
--- /dev/null
+++ b/cmake/Modules/FindPlantUML.cmake
@@ -0,0 +1,60 @@
+#-------------------------------------------------------------------------------
+# SPDX-License-Identifier: BSD-3-Clause
+# SPDX-FileCopyrightText: Copyright TF-RMM Contributors.
+#-------------------------------------------------------------------------------
+
+#FindPlantuml
+#-----------
+#PlantUML is a diagram generation tool. It can generate various UML and non-UML
+#diagrams. See: http://plantuml.com/
+#
+#This module checks PlantUML availability and checks if the Java runtime is
+#available.
+#For Windows PlantUML is distributed as a jar archive and thus there is no
+#standard install location where it could be searched for.
+#Most Linux distributions come with a proper PlantUML package which installs
+#a shell script to easy starting PlantUML, but the location of the .jar file
+#is hidden.
+#Thus there is no standard location to search for the .jar file and this module
+#depends on user input.
+#
+#This module has the following parameters:
+# PLANTUML_JAR_PATH = variable specifying where the PlantUML java archive
+# (plantuml.jar) can be found. If it is not defined,
+# the environment variable with the same name is used.
+# If both is missing, that is an error.
+#
+#This module defines the following variables:
+# PLANTUML_VERSION = The version reported by "plantuml.jar -version"
+# PLANTUML_FOUND = Was the .jar file found and sucesfuly executed.
+#
+
+#include(Common/Utils)
+
+find_package(Java 1.8 COMPONENTS Runtime)
+if(Java_Runtime_FOUND)
+ #Check if the jar file is at the user defined location.
+ #Prefer the cmake variable to the environment setting.
+ if (NOT DEFINED PLANTUML_JAR_PATH)
+ if (DEFINED ENV{PLANTUML_JAR_PATH})
+ set(PLANTUML_JAR_PATH "$ENV{PLANTUML_JAR_PATH}" CACHE STRING "PLANTUML location." )
+ endif()
+ endif()
+
+ if (NOT DEFINED PLANTUML_JAR_PATH)
+ message(STATUS "PLANTUML_JAR_PATH variable is missing, PlantUML jar location is unknown.")
+ else()
+ #Get plantuml version
+ execute_process(COMMAND "${Java_JAVA_EXECUTABLE}" "-jar" "${PLANTUML_JAR_PATH}" "-version" OUTPUT_VARIABLE _PLANTUML_VERSION OUTPUT_STRIP_TRAILING_WHITESPACE ERROR_QUIET)
+ #Parse plantuml output
+ if(_PLANTUML_VERSION)
+ if(_PLANTUML_VERSION MATCHES ".*PlantUML version ([0-9.]+).*")
+ string(REGEX REPLACE ".*PlantUML version ([0-9.]+).*" "\\1" PLANTUML_VERSION "${_PLANTUML_VERSION}")
+ endif()
+ endif()
+ endif()
+endif()
+
+#Set "standard" find module return values
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(PlantUML REQUIRED_VARS PLANTUML_JAR_PATH PLANTUML_VERSION VERSION_VAR PLANTUML_VERSION)
diff --git a/cmake/Modules/FindPythonModules.cmake b/cmake/Modules/FindPythonModules.cmake
new file mode 100644
index 0000000..625bfec
--- /dev/null
+++ b/cmake/Modules/FindPythonModules.cmake
@@ -0,0 +1,61 @@
+#-------------------------------------------------------------------------------
+# SPDX-License-Identifier: BSD-3-Clause
+# SPDX-FileCopyrightText: Copyright TF-RMM Contributors.
+#-------------------------------------------------------------------------------
+
+#FindPythonModules
+#-----------
+#This module checks availability of Python modules.
+#
+#This module has the following parameters:
+# PYTHON_EXECUTABLE - Location of python interpreter.
+# COMPONENTS - List of python modules to look for.
+#
+#This module defines the following variables:
+# PY_XXX - Cached string variable with the location of the module.
+# PY_XXX_FOUND - Set if the module is available.
+#
+# Where XXX is the upper case name of the module.
+#
+#Examples
+# To look for m2r and report error if not found
+# find_module(PythonModules COMPONENTS m2r)
+# if (PY_M2R_FOUND)
+# do something
+# endif()
+#
+# To look for m2r and do not report error if not found
+# find_module(PythonModules OPTIONAL_COMPONENTS m2r)
+# if (PY_M2R_FOUND)
+# do something
+# endif()
+
+if(NOT DEFINED PYTHON_EXECUTABLE)
+ message(FATAL_ERROR "FindPythonModules: mandatory parameter PYTHON_EXECUTABLE is missing.")
+endif()
+
+foreach(_mod ${PythonModules_FIND_COMPONENTS})
+ string(TOUPPER ${_mod} _mod_upper)
+ string(REPLACE "-" "_" _modname "${_mod}")
+ if (NOT PY_${_mod_upper})
+ #Execute python and try to include the module.
+ execute_process(
+ COMMAND ${PYTHON_EXECUTABLE} -c "import ${_modname}; print(${_modname}.__file__);"
+ RESULT_VARIABLE ${_mod}_status
+ OUTPUT_VARIABLE ${_mod}_path
+ ERROR_QUIET
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+ #If suceeded
+ if(NOT ${_mod}_status)
+ #Avoid trouble with directory separator on windows.
+ set("PY_${_mod_upper}" "${${_mod}_path}" CACHE STRING
+ "Location of Python module ${_mod}")
+ endif()
+ endif()
+ #Set "standard" find module return values
+ include(FindPackageHandleStandardArgs)
+ find_package_handle_standard_args(PY_${_mod_upper}
+ REQUIRED_VARS PY_${_mod_upper}
+ NAME_MISMATCHED
+ FAIL_MESSAGE "Can not find Python module ${_mod}")
+endforeach()
diff --git a/cmake/Modules/FindSphinx.cmake b/cmake/Modules/FindSphinx.cmake
new file mode 100644
index 0000000..7acab08
--- /dev/null
+++ b/cmake/Modules/FindSphinx.cmake
@@ -0,0 +1,90 @@
+#-------------------------------------------------------------------------------
+# SPDX-License-Identifier: BSD-3-Clause
+# SPDX-FileCopyrightText: Copyright TF-RMM Contributors.
+#-------------------------------------------------------------------------------
+
+#FindSphinx
+#-----------
+#Sphinx is a document generation tool written in Python.
+#See http://www.sphinx-doc.org/en/master/
+#
+#This module checks availability of the Sphinx document generator
+#(sphinx-build) and it's dependences (Python).
+#Sphinx is distributed as pip package or on Linux as a distribution specific
+#package (i.e. python-sphinx for Ubuntu). Independent of the distribution
+#method this module expects sphix-build to be either available on the PATH,
+#or to be located in a host OS specific standard location.
+#
+#This modules has the following parameters:
+# SPHINX_PATH = variable specifying where sphinx-build can be found.
+# If it is not defined the environment variable with
+# the same name is used. If that is also undefined,
+# then OS specific standard locations will be
+# searched.
+#
+# This modules defines the following variables:
+# SPHINX_VERSION = The version reported by "sphinx-build --version"
+# SPHINX_FOUND = True is sphinx-build was found and executed fine
+#
+
+Include(CMakeParseArguments)
+
+#Sphinx needs Python.
+find_package(PythonInterp 3)
+if (NOT PYTHONINTERP_FOUND)
+ message(STATUS "Can not find Python3.x interpreter. Pyhton3 must be installed and available on the PATH.")
+ message(STATUS "Sphinx documentation targets will not be created.")
+ return()
+endif()
+
+if (NOT DEFINED SPHINX_PATH)
+ if (DEFINED $ENV{SPHINX_PATH})
+ set(SPHINX_PATH $ENV{SPHINX_PATH})
+ endif()
+endif()
+
+
+if (DEFINED SPHINX_PATH)
+ #Find the Sphinx executable. Search only at SPHINX_PATH.
+ find_program(SPHINX_EXECUTABLE
+ NAMES sphinx-build
+ DOC "Sphinx Documentation Builder (sphinx-doc.org)"
+ PATH ${SPHINX_PATH}
+ NO_DEFAULT_PATH
+ NO_CMAKE_ENVIRONMENT_PATH
+ NO_CMAKE_PATH
+ NO_SYSTEM_ENVIRONMENT_PATH
+ NO_CMAKE_SYSTEM_PATH
+ NO_CMAKE_FIND_ROOT_PATH
+ )
+ if (SPHINX_EXECUTABLE-NOTFOUND)
+ message(STATUS "Failed to find sphinx-build at ${SPHINX_PATH}.")
+ message(STATUS "Sphinx documentation targets will not be created.")
+ return()
+ endif()
+else()
+ #Find the Sphinx executable. Search OS specific default locations.
+ find_program(SPHINX_EXECUTABLE
+ NAMES sphinx-build
+ DOC "Sphinx Documentation Builder (sphinx-doc.org)"
+ )
+
+ if (SPHINX_EXECUTABLE-NOTFOUND)
+ message(STATUS "Failed to find sphinx-build at OS specific default locations.")
+ message(STATUS "Sphinx documentation targets will not be created.")
+ return()
+ endif()
+endif()
+
+#Get Sphinx version
+execute_process(COMMAND "${SPHINX_EXECUTABLE}" "--version" OUTPUT_VARIABLE _SPHINX_VERSION OUTPUT_STRIP_TRAILING_WHITESPACE ERROR_QUIET)
+#Parse output
+if(_SPHINX_VERSION)
+ if(_SPHINX_VERSION MATCHES ".*sphinx-build[^0-9.]*([0-9.]+).*")
+ string(REGEX REPLACE ".*sphinx-build ([0-9.]+).*" "\\1" SPHINX_VERSION "${_SPHINX_VERSION}")
+ endif()
+endif()
+
+#Set "standard" find module return values
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(Sphinx REQUIRED_VARS SPHINX_EXECUTABLE SPHINX_VERSION VERSION_VAR SPHINX_VERSION)