Docs: Structure the Design documents
- gather documents in folders:
"booting" for secure boot related designs
"services" for Secure services and SPM
"software" for general TF-M framework design and rules
- add short document names in indexes
Signed-off-by: Anton Komlev <anton.komlev@arm.com>
Change-Id: I4efd309c186e431cf24c3259a35bfef53e2eb24c
diff --git a/docs/design_docs/software/code_sharing.rst b/docs/design_docs/software/code_sharing.rst
new file mode 100644
index 0000000..5f11bb5
--- /dev/null
+++ b/docs/design_docs/software/code_sharing.rst
@@ -0,0 +1,367 @@
+######################################################
+Code sharing between independently linked XIP binaries
+######################################################
+
+:Author: Tamas Ban
+:Organization: Arm Limited
+:Contact: tamas.ban@arm.com
+
+**********
+Motivation
+**********
+Cortex-M devices are usually constrained in terms of flash and RAM. Therefore,
+it is often challenging to fit bigger projects in the available memory. The PSA
+specifications require a device to both have a secure boot process in place at
+device boot-up time, and to have a partition in the SPE which provides
+cryptographic services at runtime. These two entities have some overlapping
+functionality. Some cryptographic primitives (e.g. hash calculation and digital
+signature verification) are required both in the bootloader and the runtime
+environment. In the current TF-M code base, both firmware components use the
+mbed-crypto library to implement these requirements. During the build process,
+the mbed-crpyto library is built twice, with different configurations (the
+bootloader requires less functionality) and then linked to the corresponding
+firmware component. As a result of this workflow, the same code is placed in the
+flash twice. For example, the code for the SHA-256 algorithm is included in
+MCUboot, but the exact same code is duplicated in the SPE cryptography
+partition. In most cases, there is no memory isolation between the bootloader
+and the SPE, because both are part of the PRoT code and run in the secure
+domain. So, in theory, the code of the common cryptographic algorithms could be
+reused among these firmware components. This could result in a big reduction in
+code footprint, because the cryptographic algorithms are usually flash hungry.
+Code size reduction can be a good opportunity for very constrained devices,
+which might need to use TF-M Profile Small anyway.
+
+*******************
+Technical challenge
+*******************
+Code sharing in a regular OS environment is easily achievable with dynamically
+linked libraries. However, this is not the case in Cortex-M systems where
+applications might run bare-metal, or on top of an RTOS, which usually lacks
+dynamic loading functionality. One major challenge to be solved in the Cortex-M
+space is how to share code between independently linked XIP applications that
+are tied to a certain memory address range to be executable and have absolute
+function and global data memory addresses. In this case, the code is not
+relocatable, and in most cases, there is no loader functionality in the system
+that can perform code relocation. Also, the lack of an MMU makes the address
+space flat, constant and not reconfigurable at runtime by privileged code.
+
+One other difficulty is that the bootloader and the runtime use the same RAM
+area during execution. The runtime firmware is executed strictly after the
+bootloader, so normally, it can reuse the whole secure RAM area, as it would be
+the exclusive user. No attention needs to be paid as to where global data is
+placed by the linker. The bootloader does not need to retain its state. The low
+level startup of the runtime firmware can freely overwrite the RAM with its data
+without corrupting bootloader functionality. However, with code sharing between
+bootloader and runtime firmware, these statements are no longer true. Global
+variables used by the shared code must either retain their value or must be
+reinitialised during low level startup of the runtime firmware. The startup code
+is not allowed to overwrite the shared global variables with arbitrary data. The
+following design proposal provides a solution to these challenges.
+
+**************
+Design concept
+**************
+The bootloader is sometimes implemented as ROM code (BL1) or stored in a region
+of the flash which is lockable, to prevent tampering. In a secure system, the
+bootloader is immutable code and thus implements a part of the Root of Trust
+anchor in the device, which is trusted implicitly. The shared code is primarily
+part of the bootloader, and is reused by the runtime SPE firmware at a later
+stage. Not all of the bootloader code is reused by the runtime SPE, only some
+cryptographic functions.
+
+Simplified steps of building with code sharing enabled:
+
+ - Complete the bootloader build process to have a final image that contains
+ the absolute addresses of the shared functions, and the global variables
+ used by these functions.
+ - Extract the addresses of the functions and related global variables that are
+ intended to be shared from the bootloader executable.
+ - When building runtime firmware, provide the absolute addresses of the shared
+ symbols to the linker, so that it can pick them up, instead of instantiating
+ them again.
+
+The execution flow looks like this:
+
+.. code-block:: bash
+
+ SPE MCUboot func1() MCUboot func2() MCUboot func3()
+ |
+ | Hash()
+ |------------->|
+ |----------------->|
+ |
+ Return |
+ Return |<-----------------|
+ |<-------------|
+ |
+ |
+ |----------------------------------------------------->|
+ |
+ Function pointer in shared global data() |
+ |<-----------------------------------------------------|
+ |
+ | Return
+ |----------------------------------------------------->|
+ |
+ Return |
+ |<-----------------------------------------------------|
+ |
+ |
+
+The execution flow usually returns from a shared function back to the SPE with
+an ordinary function return. So usually, once a shared function is called in the
+call path, all further functions in the call chain will be shared as well.
+However, this is not always the case, as it is possible for a shared function to
+call a non-shared function in SPE code through a global function pointer.
+
+For shared global variables, a dedicated data section must be allocated in the
+linker configuration file. This area must have the same memory address in both
+MCUboot's and the SPE's linker files, to ensure the integrity of the variables.
+For simplicity's sake, this section is placed at the very beginning of the RAM
+area. Also, the RAM wiping functionality at the end of the secure boot flow
+(that is intended to remove any possible secrets from the RAM) must not clear
+this area. Furthermore, it must be ensured that the linker places shared globals
+into this data section. There are two way to achieve this:
+
+ - Put a filter pattern in the section body that matches the shared global
+ variables.
+ - Mark the global variables in the source code with special attribute
+ `__attribute__((section(<NAME_OF_SHARED_SYMBOL_SECTION>)))`
+
+RAM memory layout in MCUboot with code sharing enabled:
+
+.. code-block:: bash
+
+ +------------------+
+ | Shared symbols |
+ +------------------+
+ | Shared boot data |
+ +------------------+
+ | Data |
+ +------------------+
+ | Stack (MSP) |
+ +------------------+
+ | Heap |
+ +------------------+
+
+RAM memory layout in SPE with code sharing enabled:
+
+.. code-block:: bash
+
+ +-------------------+
+ | Shared symbols |
+ +-------------------+
+ | Shared boot data |
+ +-------------------+
+ | Stack (MSP) |
+ +-------------------+
+ | Stack (PSP) |
+ +-------------------+
+ | Partition X Data |
+ +-------------------+
+ | Partition X Stack |
+ +-------------------+
+ .
+ .
+ .
+ +-------------------+
+ | Partition Z Data |
+ +-------------------+
+ | Partition Z Stack |
+ +-------------------+
+ | PRoT Data |
+ +-------------------+
+ | Heap |
+ +-------------------+
+
+Patching mbedTLS
+================
+In order to share some global function pointers from mbed-crypto that are
+related to dynamic memory allocation, their scope must be extended from private
+to global. This is needed because some compiler toolchain only extract the
+addresses of public functions and global variables, and extraction of addresses
+is a requirement to share them among binaries. Therefore, a short patch was
+created for the mbed-crypto library, which "globalises" these function pointers:
+
+`lib/ext/mbedcrypto/0002-Enable-crypto-code-sharing-between-independent-binar.patch`
+
+The patch need to manually applied in the mbedtls repo, if code sharing is
+enabled. The patch has no effect on the functional behaviour of the
+cryptographic library, it only extends the scope of some variables.
+
+*************
+Tools support
+*************
+All the currently supported compilers provide a way to achieve the above
+objectives. However, there is no standard way, which means that the code sharing
+functionality must be implemented on a per compiler basis. The following steps
+are needed:
+
+ - Extraction of the addresses of all global symbols.
+ - The filtering out of the addresses of symbols that aren't shared. The goal is
+ to not need to list all the shared symbols by name. Only a simple pattern
+ has to be provided, which matches the beginning of the symbol's name.
+ Matching symbols will be shared. Examples are in :
+ `bl2/shared_symbol_template.txt`
+ - Provision of the addresses of shared symbols to the linker during the SPE
+ build process.
+ - The resolution of symbol collisions during SPE linking. Because mbed-crypto
+ is linked to both firmware components as a static library, the external
+ shared symbols will conflict with the same symbols found within it. In order
+ to prioritize the external symbol, the symbol with the same name in
+ mbed-crypto must be marked as weak in the symbol table.
+
+The above functionalities are implemented in the toolchain specific CMake files:
+
+ - `toolchain_ARMCLANG.cmake`
+ - `toolchain_GNUARM.cmake`
+
+By the following two functions:
+
+ - `target_share_symbols()`: Extract and filter shared symbol addresses
+ from MCUboot.
+ - `target_link_shared_code()`: Link shared code to the SPE and resolve symbol
+ conflict issues.
+
+ARMCLANG
+========
+The toolchain specific steps are:
+
+ - Extract all symbols from MCUboot: add `-symdefs` to the compiler command line
+ - Filter shared symbols: call CMake script `FilterSharedSymbols.cmake`
+ - Weaken duplicated (shared) symbols in the mbed-crypto static library that are
+ linked to the SPE: `arm-none-eabi-objcopy`
+ - Link shared code to SPE: Add the filtered output of `-symdefs` to the SPE
+ source file list.
+
+GNUARM
+======
+The toolchain specific steps are:
+
+ - Extract all symbols from MCUboot: `arm-none-eabi-nm`
+ - Filter shared symbols: call CMake script: `FilterSharedSymbols.cmake`
+ - Strip unshared code from MCUboot: `arm-none-eabi-strip`
+ - Weaken duplicated (shared) symbols in the mbed-crypto static library that are
+ linked to the SPE: `arm-none-eabi-objcopy`
+ - Link shared code to SPE: Add `-Wl -R <SHARED_STRIPPED_CODE.axf>` to the
+ compiler command line
+
+IAR
+===
+Functionality currently not implemented, but the toolchain supports doing it.
+
+**************************
+Memory footprint reduction
+**************************
+Build type: MinSizeRel
+Platform: mps2/an521
+Version: TF-Mv1.2.0 + code sharing patches
+MCUboot image encryption support is disabled.
+
++------------------+-------------------+-------------------+-------------------+
+| | ConfigDefault | ConfigProfile-M | ConfigProfile-S |
++------------------+----------+--------+----------+--------+----------+--------+
+| | ARMCLANG | GNUARM | ARMCLANG | GNUARM | ARMCLANG | GNUARM |
++------------------+----------+--------+----------+--------+----------+--------+
+| CODE_SHARING=OFF | 122268 | 124572 | 75936 | 75996 | 50336 | 50224 |
++------------------+----------+--------+----------+--------+----------+--------+
+| CODE_SHARING=ON | 113264 | 115500 | 70400 | 70336 | 48840 | 48988 |
++------------------+----------+--------+----------+--------+----------+--------+
+| Difference | 9004 | 9072 | 5536 | 5660 | 1496 | 1236 |
++------------------+----------+--------+----------+--------+----------+--------+
+
+If MCUboot image encryption support is enabled then saving could be up to
+~13-15KB.
+
+.. Note::
+
+ Code sharing on Musca-B1 was tested only with SW only crypto, so crypto
+ hardware acceleration must be turned off: -DCRYPTO_HW_ACCELERATOR=OFF
+
+
+*************************
+Useability considerations
+*************************
+Functions that only use local variables can be shared easily. However, functions
+that rely on global variables are a bit tricky. They can still be shared, but
+all global variables must be placed in the shared symbol section, to prevent
+overwriting and to enable the retention of their values.
+
+Some global variables might need to be reinitialised to their original values by
+runtime firmware, if they have been used by the bootloader, but need to have
+their original value when runtime firmware starts to use them. If so, the
+reinitialising functionality must be implemented explicitly, because the low
+level startup code in the SPE does not initialise the shared variables, which
+means they retain their value after MCUboot stops running.
+
+If a bug is discovered in the shared code, it cannot be fixed with a firmware
+upgrade, if the bootloader code is immutable. If this is the case, disabling
+code sharing might be a solution, as the new runtime firmware could contain the
+fixed code instead of relying on the unfixed shared code. However, this would
+increase code footprint.
+
+API backward compatibility also can be an issue. If the API has changed in newer
+version of the shared code. Then new code cannot rely on the shared version.
+The changed code and all the other shared code where it is referenced from must
+be ignored and the updated version of the functions must be compiled in the
+SPE binary. The mbedTLS library is API compatible with its current version
+(``v2.24.0``) since the ``mbedtls-2.7.0 release`` (2018-02-03).
+
+To minimise the risk of incompatibility, use the same compiler flags to build
+both firmware components.
+
+The artifacts of the shared code extraction steps must be preserved so as to
+remain available if new SPE firmware (that relies on shared code) is built and
+released. Those files are necessary to know the address of shared symbols when
+linking the SPE.
+
+************************
+How to use code sharing?
+************************
+Considering the above, code sharing is an optional feature, which is disabled
+by default. It can be enabled from the command line with a compile time switch:
+
+ - `TFM_CODE_SHARING`: Set to `ON` to enable code sharing.
+
+With the default settings, only the common part of the mbed-crypto library is
+shared, between MCUboot and the SPE. However, there might be other device
+specific code (e.g. device drivers) that could be shared. The shared
+cryptography code consists mainly of the SHA-256 algorithm, the `bignum` library
+and some RSA related functions. If image encryption support is enabled in
+MCUboot, then AES algorithms can be shared as well.
+
+Sharing code between the SPE and an external project is possible, even if
+MCUboot isn't used as the bootloader. For example, a custom bootloader can also
+be built in such a way as to create the necessary artifacts to share some of its
+code with the SPE. The same artifacts must be created like the case of MCUboot:
+
+ - `shared_symbols_name.txt`: Contains the name of the shared symbols. Used by
+ the script that prevents symbol collision.
+ - `shared_symbols_address.txt`: Contains the type, address and name of shared
+ symbols. Used by the linker when linking runtime SPE.
+ - `shared_code.axf`: GNUARM specific. The stripped version of the firmware
+ component, only contains the shared code. It is used by the linker when
+ linking the SPE.
+
+.. Note::
+
+ The artifacts of the shared code extraction steps must be preserved to be
+ able to link them to any future SPE version.
+
+When an external project is sharing code with the SPE, the `SHARED_CODE_PATH`
+compile time switch must be set to the path of the artifacts mentioned above.
+
+********************
+Further improvements
+********************
+This design focuses only on sharing the cryptography code. However, other code
+could be shared as well. Some possibilities:
+
+- Flash driver
+- Serial driver
+- Image metadata parsing code
+- etc.
+
+--------------
+
+*Copyright (c) 2020-2022, Arm Limited. All rights reserved.*
\ No newline at end of file
diff --git a/docs/design_docs/software/enum_implicit_casting.rst b/docs/design_docs/software/enum_implicit_casting.rst
new file mode 100644
index 0000000..3c1e453
--- /dev/null
+++ b/docs/design_docs/software/enum_implicit_casting.rst
@@ -0,0 +1,189 @@
+################################################
+Fixing implicit casting for C enumeration values
+################################################
+
+:Author: Hugues de Valon
+:Organization: Arm Limited
+:Contact: hugues.devalon@arm.com
+
+********
+Abstract
+********
+
+C enumerations provide a nice way to increase readability by creating new
+enumerated types but the developer should take extra care when mixing
+enumeration and integer values.
+This document investigates C enumerations safety and proposes strategies on how
+to fix the implicit casting of the enumeration values of TF-M with other types.
+
+**************************
+C99 Standard point of view
+**************************
+
+In TF-M many implicit casts are done between integer types (``uint32_t``,
+``int32_t``, ``size_t``, etc), enumerated types (``enum foobar``) and
+enumeration constants (``FOOBAR_ENUM_1``).
+
+According to the C99 standard [1]_:
+
+ **§6.2.5, 16**:
+ An enumeration comprises a set of named integer constant values. Each
+ distinct enumeration constitutes a different numerated type.
+
+ **§6.7.2.2, 2**:
+ The expression that defines the value of an enumeration constant shall be an
+ integer constant expression that has a value representable as an int.
+
+ **§6.7.2.2, 3**:
+ The identifiers in an enumerator list are declared as constants that have
+ type int and may appear wherever such are permitted.
+
+ **§6.7.2.2, 4**:
+ Each enumerated type shall be compatible with char, a signed integer type,
+ or an unsigned integer type. The choice of type is implementation-defined,
+ but shall be capable of representing the values of all the members of the
+ enumeration.
+
+From these four quotes from the C99 standard [1]_, the following conclusions can
+be made:
+
+* an enumeration defines a new type and should be treated as such
+* the enumeration constants must only contains value representable as an ``int``
+* the enumeration constants have type ``int``
+* the actual type of the enumeration can be between ``char``, signed and
+ unsigned ``int``. The compiler chooses the type it wants among those that can
+ represent all declared constants of the enumeration.
+
+Example::
+
+ enum french_cities {
+ MARSEILLE,
+ PARIS,
+ LILLE,
+ LYON
+ };
+
+In that example, ``MARSEILLE``, ``PARIS``, ``LILLE`` and ``LYON`` are
+enumeration constants of type ``int`` and ``enum french_cities`` is a enumerated
+type which can be of actual type ``char``, ``unsigned int`` or ``int``
+(the compiler chooses!).
+
+For these reasons, doing an implicit cast between an enumeration and another
+type is the same as doing an implicit cast between two different types. From a
+defensive programming point of view, it should be checked that the destination
+type can represent the values from the origin type. In this specific case it
+means four things for enumerations:
+
+* it is always safe to assign an enumeration constant to an int, but might be
+ better to cast to show intent.
+* when casting an enumeration constant to another type, it should be checked
+ that the constant can fit into the destination type.
+* when casting from an integer type (``uint32_t``, ``int32_t``, etc) to an
+ enumeration type, it should be checked that the integer's value is one of the
+ enumeration constants. The comparison needs to be done on the biggest type of
+ the two so that no information is lost. C integer promotion should
+ automatically do that for the programmer (check §6.3.1.8, 1 for the rules).
+* when casting from an enumeration type to an integer type, it should be checked
+ that the enumeration type value fits into the integer type. The value of a
+ variable which has the type of an enumeration type is not limited to the
+ enumeration constants of the type. An enumeration constant will always fit
+ into an ``int``.
+
+*****************
+Strategies to fix
+*****************
+
+0. Replace the enumerated type with an integer type and replace the enumeration
+ constant with preprocessor constants.
+1. Whenever possible, try to use matching types to avoid implicit casting.
+ It happens, for example, for arithmetic operations, function calls and
+ function returns. This strategy always have the lowest performance impact.
+2. When using an enumeration constant in an arithmetic operation with another
+ type, verify that the constant can fit in the other type and cast it.
+3. When converting an integer to an enumeration type, use a conversion function
+ to check if the integer matches an enumeration constant. To not impact
+ performance too much, this function should be an inline function. If it does
+ not match, use (or add) the error constant or return an error value.
+4. When converting an enumeration type to an integer, use a conversion function
+ to check that the integer type can contain the enumeration value.
+
+************************
+Design proposal for TF-M
+************************
+
+In TF-M, an action will be taken for all enumerated types and enumeration
+constants that are used for implicit casting. The goal of this proposal is to
+remove all implicit casting of enumeration values in TF-M.
+
+The following enumerated types will be removed and replaced with preprocessor
+constants (strategy 0). These enumerated types are not used in TF-M
+but only the constants they declare.
+
+* ``enum spm_part_state_t``
+* ``enum spm_part_flag_mask_t``
+* ``enum tfm_partition_priority``
+
+The following enumerated types will be kept because they are used in the
+prototypes of functions and are useful for debugging. Whenever possible,
+strategy 1 will be applied to remove implicit casting related with those
+enumerations but dynamic conversions will be used if the first option would
+create too much change in the code base.
+
+* ``enum tfm_status_e``: the return type of the following functions will be
+ changed to return the ``enum tfm_status_e`` type. These functions are already
+ returning the enumeration constants, but implicitly casted to an integer type
+ like ``int32_t``.
+
+ * ``int32_t check_address_range``
+ * ``int32_t has_access_to_region``
+ * ``int32_t tfm_core_check_sfn_parameters``
+ * ``int32_t tfm_start_partition``
+ * ``int32_t tfm_return_from_partition``
+ * ``int32_t tfm_check_sfn_req_integrity``
+ * ``int32_t tfm_core_check_sfn_req_rules``
+ * ``int32_t tfm_spm_sfn_request_handler``
+ * ``int32_t tfm_spm_sfn_request_thread_mode``
+* ``enum tfm_buffer_share_region_e``: the following function prototypes will be
+ changed:
+
+ * ``tfm_spm_partition_set_share(uint32_t partition_idx, uint32_t share)`` -> ``tfm_spm_partition_set_share(uint32_t partition_idx, enum tfm_buffer_share_region_e share)``
+* ``enum tfm_memory_access_e``
+* ``enum attest_memory_access_t``
+* ``enum engine_cipher_mode_t``
+* ``mbedtls_cipher_type_t``
+
+The following enumerated types are used for error code values of Secure service
+calls. They should be kept as they are part of the interface and might be used
+by external parties in Non-Secure code. For the Initial Attestation service,
+the enumeration is defined in the PSA Attestation API specifications.
+
+* ``enum psa_attest_err_t``
+* ``enum psa_audit_err``
+* ``enum tfm_platform_err_t``
+
+Implicit casting related with these enumerations is happening in two locations
+of TF-M and need conversion functions in those locations, because the types can
+not be changed:
+
+* In the Non-Secure Client library, all of the Secure Service functions
+ implicitly cast the ``uint32_t`` returned by ``tfm_ns_lock_dispatch`` to
+ these enumerated types. Strategy 3 is needed here.
+* In all of the veneer functions, there is an implicit cast from the ``int32_t``
+ value returned by the SVC request function (``tfm_core_*_request``) to these
+ enumerated types. Strategy 3 is needed here as well. The implicit cast will
+ eventually be removed if all of the services are using the Uniform Signatures
+ Prototypes so that the veneer functions all return ``psa_status_t`` which is
+ an ``int32_t``.
+
+If the interface of those services can be changed, these enumerations could be
+removed and replaced with the ``psa_status_t`` type to remove the implicit
+casting.
+
+.. [1] C99 standard: http://www.open-std.org/jtc1/sc22/WG14/www/docs/n1256.pdf
+
+
+--------------
+
+
+*Copyright (c) 2019-2020, Arm Limited. All rights reserved.*
+
diff --git a/docs/design_docs/software/hardware_abstraction_layer.rst b/docs/design_docs/software/hardware_abstraction_layer.rst
new file mode 100644
index 0000000..bf70d6c
--- /dev/null
+++ b/docs/design_docs/software/hardware_abstraction_layer.rst
@@ -0,0 +1,921 @@
+##########################
+Hardware Abstraction Layer
+##########################
+
+:Organization: Arm Limited
+:Contact: tf-m@lists.trustedfirmware.org
+
+:API Version: 0.9
+
+************
+Introduction
+************
+:term:`TF-M` :term:`HAL` abstracts the hardware-oriented and platform specific
+operations on the :term:`SPE` side and provides a set of APIs to the upper
+layers such as :term:`SPM`, :term:`RoT Service`.
+The :term:`HAL` aims to cover the platform different aspects whereas common
+architecturally defined aspects are done generically within the common
+:term:`SPE`.
+In some cases, although the operations are defined architecturally,
+it may not be possible to generalize implementations because lots of information
+is only known to platforms.
+It is more efficient to define a :term:`HAL` API for those architectural
+operations as well.
+
+.. note::
+ :term:`TBSA-M` provides the hardware requirements for security purposes.
+ :term:`TF-M` :term:`HAL` tries to reference :term:`TBSA-M` recommendations in
+ the interfaces from the software perspective only. Please reference
+ :term:`TBSA-M` for your security hardware design.
+
+Design Goals
+============
+:term:`TF-M` :term:`HAL` is designed to simplify the integration efforts on
+different platforms.
+
+:term:`TF-M` :term:`HAL` is designed to make it easy to use the hardware and
+develop the :term:`SPM` and :term:`RoT Service` which need to access the
+devices.
+
+:term:`TF-M` :term:`HAL` is designed to make the structure clearer and let the
+:term:`TF-M` mainly focus on :term:`PSA` implementation.
+
+********
+Overview
+********
+This section provides an overview of the abstraction layer structure.
+
+.. figure:: /design_docs/media/hal_structure.png
+
+Here lists a minimal set of necessary functionalities:
+
+ - **Isolation API**: Provides the necessary isolation functionalities required
+ by the :term:`PSA-FF-M` and :term:`TBSA-M`, and provides APIs to :term:`SPM`
+ to check the permissions of memory access.
+ - **Platform API**: Provides the platform initialization, platform-specific
+ memory information, system reset, etc.
+ - **Log dev API**: Provides the log system functions.
+ - **Interrupt API**: Provides the interrupt functions.
+
+.. note::
+ - There is a non-secure :term:`HAL` that focuses on the mailbox operation API
+ for Dual-core topology. For more information about it, please refer to
+ :doc:`Mailbox Design in TF-M on Dual-core System
+ </design_docs/dual-cpu/mailbox_design_on_dual_core_system>`.
+ - The minimal set of :term:`TF-M` :term:`HAL` is sufficient for Secure
+ Partitions by using customized peripheral interfaces. To provide easier
+ portability for the Secure Partitions, a Secure Partition :term:`HAL` is
+ provided in this design too.
+ - The debug mechanisms give the external entity the corresponding right to
+ access the system assets. :term:`TF-M` ensures that the external entity is
+ permitted access to those assets. Currently, :term:`TF-M` only needs the
+ debug authentication. The whole debug mechanism and related :term:`HAL` will
+ be enhanced in the future. Please refer to the :doc:`Debug authentication
+ settings section </integration_guide/source_structure/platform_folder>`
+ for more details.
+
+*****************
+Design Principles
+*****************
+As :term:`TF-M` runs on resource-constrained devices, the :term:`HAL` tries to
+avoid multiple level abstractions which cost more resources.
+
+Part of the :term:`HAL` interfaces does not focus on exact hardware operations
+such as power on/off or PIN manipulation.
+Instead, the :term:`HAL` abstracts higher-level interfaces to reserve the
+implementation flexibility for the platform vendors.
+
+The :term:`TF-M` :term:`HAL` should be easy to deprecate APIs and provide
+compatibilities.
+Any API incompatibility should be detected during building.
+
+:term:`TF-M` relies on the :term:`HAL` APIs to be implemented correctly and
+trusts the :term:`HAL` APIs.
+:term:`TFM` can provide assertions to detect common programming errors but
+essentially no further extensive checks will be provided.
+
+************
+Source Files
+************
+This section describes the source file of the :term:`TF-M` :term:`HAL`,
+including the header and c files.
+
+tfm_hal_defs.h
+==============
+This header file contains the definitions of common macros and types used by all
+:term:`HAL` APIs. Please refer to `Status Codes`_ for detailed definitions.
+
+tfm_hal_[module].[h/c]
+======================
+All other headers and c files are classified by the modules, such as isolation,
+platform, interrupt, devices, etc.
+
+.. note::
+ There are common files in the platform folder include the implemented
+ :term:`HAL` APIs. The platform vendors can use them directly but need to
+ implement all the sub APIs.
+
+************
+Status Codes
+************
+These are common status and error codes for all :term:`HAL` APIs.
+
+Types
+=====
+tfm_hal_status_t
+----------------
+This is a status code to be used as the return type of :term:`HAL` APIs.
+
+.. code-block:: c
+
+ enum tfm_hal_status_t {
+ TFM_HAL_ERROR_MEM_FAULT = SCHAR_MIN,
+ TFM_HAL_ERROR_MAX_VALUE,
+ TFM_HAL_ERROR_BAD_STATE,
+ TFM_HAL_ERROR_NOT_SUPPORTED,
+ TFM_HAL_ERROR_INVALID_INPUT,
+ TFM_HAL_ERROR_NOT_INIT,
+ TFM_HAL_ERROR_GENERIC,
+ TFM_HAL_SUCCESS = 0
+ };
+
+Error Codes
+===========
+Negative values indicate an error. Zero and positive values indicate success.
+
+Here is the general list. The detailed usages for each error code are described
+in the API introduction sections.
+
+TFM_HAL_SUCCESS
+---------------
+Status code to indicate general success.
+
+TFM_HAL_ERROR_GENERIC
+---------------------
+Status code to indicate an error that does not correspond to any defined failure
+cause.
+
+TFM_HAL_ERROR_NOT_INIT
+----------------------
+Status code to indicate that the module is not initialed.
+
+TFM_HAL_ERROR_INVALID_INPUT
+---------------------------
+Status code to indicate that the input is invalid.
+
+TFM_HAL_ERROR_NOT_SUPPORTED
+---------------------------
+Status code to indicate that the requested operation or a parameter is not
+supported.
+
+TFM_HAL_ERROR_BAD_STATE
+-----------------------
+Status code to indicate that the requested action cannot be performed in the
+current state.
+
+TFM_HAL_ERROR_MAX_VALUE
+-----------------------
+Status code to indicate that the current number has got the max value.
+
+TFM_HAL_ERROR_MEM_FAULT
+-----------------------
+Status code to indicate that the memory check failed.
+
+***************************
+API Definition for TF-M SPM
+***************************
+This section describes the APIs defined for :term:`TF-M` :term:`SPM`.
+
+Platform API
+============
+The platform API is a higher-level abstraction layer of the platform, other than
+a dedicated API set for the special hardware devices.
+
+APIs
+----
+tfm_hal_platform_init()
+^^^^^^^^^^^^^^^^^^^^^^^
+**Prototype**
+
+.. code-block:: c
+
+ enum tfm_hal_status_t tfm_hal_platform_init(void)
+
+**Description**
+
+This API performs the platform initializations **before** the :term:`SPM`
+initialization.
+
+The initializations could include but not limited to:
+- Fault handlers
+- Reset configurations
+- Debug init
+- NVIC init
+
+**Parameter**
+
+- ``void`` - None.
+
+**Return Values**
+
+- ``TFM_HAL_SUCCESS`` - Init success.
+- ``TFM_HAL_ERROR_GENERIC`` - Generic errors.
+
+tfm_hal_system_reset()
+^^^^^^^^^^^^^^^^^^^^^^
+**Prototype**
+
+.. code-block:: c
+
+ void tfm_hal_system_reset(void)
+
+**Description**
+
+This API performs a system reset.
+
+The platform can uninitialize some resources before reset.
+
+When ``CONFIG_TFM_HALT_ON_CORE_PANIC`` is disabled this function is called to reset
+the system when a fatal error occurs.
+
+**Parameter**
+
+- ``void`` - None
+
+**Return Values**
+
+- ``void`` - None
+
+**Note**
+
+This API should not return.
+
+tfm_hal_system_halt()
+^^^^^^^^^^^^^^^^^^^^^
+**Prototype**
+
+.. code-block:: c
+
+ void tfm_hal_system_halt(void)
+
+**Description**
+
+This API enters the CPU into an infinite loop.
+
+The platform can uninitialize some resources before looping forever.
+
+When ``CONFIG_TFM_HALT_ON_CORE_PANIC`` is enabled this function is called to halt the
+system when a fatal error occurs.
+
+**Parameter**
+
+- ``void`` - None
+
+**Return Values**
+
+- ``void`` - None
+
+**Note**
+
+This API should not return.
+
+Isolation API
+=============
+The :term:`PSA-FF-M` defines three isolation levels and a memory access rule to
+provide diverse levels of securitiy. The isolation API provides the functions to
+implement these requirements.
+
+The Isolation API operates on boundaries. A boundary represents a set of
+protection settings that isolates components and domains. Below are the
+boundary examples in the current implementation:
+
+ - Boundaries between SPM and Secure Partitions.
+ - Boundaries between ARoT domain and PRoT domain.
+
+There are two types of boundaries:
+
+ - Static boundaries: Set up when the system is initializing and
+ persistent after the initialization. This type of boundary needs the
+ set-up operations only.
+ - Partition boundaries: Keeps switching from one to another when the system
+ is running. This type of boundary needs both set-up and switching
+ operations.
+
+The boundary operations are abstracted as HAL interfaces because isolation
+hardwares can be different for platforms:
+
+ - The set-up HAL interface creates a partition boundary based on given
+ partition information. This created boundary is bound with the partition
+ for subsequent usage. The binding is done by storing the boundary into
+ partition runtime data.
+ - The activation HAL interface activates the partition boundary to secure
+ the execution for the partition to be switched. The target partition's
+ information and boundary are given to the activation HAL to accomplish
+ the operation.
+
+The data representing the partition boundary in runtime is defined with the
+opaque type ``uintptr_t``:
+
+ - It is required that one value represents one boundary. The different values
+ represent different boundaries.
+ - The value is created by HAL implementation with its own-defined encoding
+ scheme.
+
+The HAL implementation defined encoding scheme can be designed for
+implementation convenience. For example:
+
+ - The implementation scheme can encode attribute flags into integer bits.
+ This could help the activation HAL to extract the protection settings
+ quickly from this encoded value, or even write to hardware registers
+ directly in the most ideal case. The initial TF-M Isolation HAL reference
+ implementation applies this scheme.
+ - The implementation scheme can reference the addresses of isolation
+ hardware description data. This could help the activation HAL to reference
+ the protection settings directly by pointers.
+
+Multiple Secure Partitions can bind with the same boundary value. This
+flexibility is useful for specific configurations. Take Isolation Level 2 as
+an example, assigning PRoT and ARoT domain boundaries to respective partitions
+can make execution more efficient, because switching two partitions in the
+same domain does not need to change the activated boundary.
+
+The boundary contains the partition's memory accessibility information, hence
+memory access check shall be performed based on boundary.
+
+Memory Access Attributes
+------------------------
+The memory access attributes are encoded as bit fields, you can logic OR them to
+have a combination of the atrributes, for example
+``TFM_HAL_ACCESS_UNPRIVILEGED | TFM_HAL_ACCESS_READABLE`` is unprivileged
+readable. The data type is `uint32_t`.
+
+TFM_HAL_ACCESS_EXECUTABLE
+^^^^^^^^^^^^^^^^^^^^^^^^^
+The memory is executable.
+
+.. code-block:: c
+
+ #define TFM_HAL_ACCESS_EXECUTABLE (1UL << 0)
+
+TFM_HAL_ACCESS_READABLE
+^^^^^^^^^^^^^^^^^^^^^^^
+The memory is readable.
+
+.. code-block:: c
+
+ #define TFM_HAL_ACCESS_READABLE (1UL << 1)
+
+TFM_HAL_ACCESS_WRITABLE
+^^^^^^^^^^^^^^^^^^^^^^^
+The memory is writable.
+
+.. code-block:: c
+
+ #define TFM_HAL_ACCESS_WRITABLE (1UL << 2)
+
+TFM_HAL_ACCESS_UNPRIVILEGED
+^^^^^^^^^^^^^^^^^^^^^^^^^^^
+The memory is unprivileged mode accessible.
+
+.. code-block:: c
+
+ #define TFM_HAL_ACCESS_UNPRIVILEGED (1UL << 3)
+
+TFM_HAL_ACCESS_DEVICE
+^^^^^^^^^^^^^^^^^^^^^
+The memory is a MMIO device.
+
+.. code-block:: c
+
+ #define TFM_HAL_ACCESS_DEVICE (1UL << 4)
+
+TFM_HAL_ACCESS_NS
+^^^^^^^^^^^^^^^^^
+The memory is accessible from :term:`NSPE`
+
+.. code-block:: c
+
+ #define TFM_HAL_ACCESS_NS (1UL << 5)
+
+APIs
+----
+
+tfm_hal_set_up_static_boundaries()
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+**Prototype**
+
+.. code-block:: c
+
+ enum tfm_hal_status_t tfm_hal_set_up_static_boundaries(void)
+
+**Description**
+
+This API sets up the static isolation boundaries which are constant throughout
+the system runtime.
+
+These boundaries include:
+
+- The boundary between the :term:`SPE` and the :term:`NSPE`
+- The boundary to protect the SPM execution. For example, the PSA RoT
+ isolation boundary between the PSA Root of Trust and the Application Root of
+ Trust which is for isolation level 2 and 3 only.
+
+Refer to the :term:`PSA-FF-M` for the definitions of the isolation boundaries.
+
+**Return Values**
+
+- ``TFM_HAL_SUCCESS`` - Isolation boundaries have been set up.
+- ``TFM_HAL_ERROR_GENERIC`` - Failed to set up the static boundaries.
+
+tfm_hal_bind_boundary()
+^^^^^^^^^^^^^^^^^^^^^^^^^
+**Prototype**
+
+.. code-block:: c
+
+ enum tfm_hal_status_t tfm_hal_bind_boundary(
+ const struct partition_load_info_t *p_ldinf,
+ uintptr_t *p_boundary);
+
+**Description**
+
+This API binds partition with a platform-generated boundary. The boundary is
+bound by writing the generated value into ``p_boundary``. And this bound
+boundary is used in subsequent calls to `tfm_hal_activate_boundary()`_ when
+boundary's owner partition get scheduled for running.
+
+**Parameter**
+
+- ``p_ldinf`` - Load information of the partition that is under loading.
+- ``p_boundary`` - Pointer for holding a partition's boundary.
+
+**Return Values**
+
+- ``TFM_HAL_SUCCESS`` - The boundary has been bound successfully.
+- ``TFM_HAL_ERROR_GENERIC`` - Failed to bind the handle.
+
+tfm_hal_activate_boundary()
+^^^^^^^^^^^^^^^^^^^^^^^^^^^
+**Prototype**
+
+.. code-block:: c
+
+ enum tfm_hal_status_t tfm_hal_activate_boundary(
+ const struct partition_load_info_t *p_ldinf,
+ uintptr_t boundary);
+
+**Description**
+
+This API requires the platform to activate the boundary to ensure the given
+Secure Partition can run successfully.
+
+The access permissions outside the boundary is platform-dependent.
+
+**Parameter**
+
+- ``p_ldinf`` - The load information of the partition that is going to be run.
+- ``boundary`` - The boundary for the owner partition of ``p_ldinf``. This
+ value is bound in function ``tfm_hal_bind_boundary``.
+
+**Return Values**
+
+- ``TFM_HAL_SUCCESS`` - the isolation boundary has been set up.
+- ``TFM_HAL_ERROR_GENERIC`` - failed to set upthe isolation boundary.
+
+tfm_hal_memory_check()
+^^^^^^^^^^^^^^^^^^^^^^
+**Prototype**
+
+.. code-block:: c
+
+ tfm_hal_status_t tfm_hal_memory_check(uintptr_t boundary,
+ uintptr_t base,
+ size_t size,
+ uint32_t access_type)
+
+**Description**
+
+This API checks if a given range of memory can be accessed with specified
+access types in boundary. The boundary belongs to a partition which
+contains asset info.
+
+**Parameter**
+
+- ``boundary`` - Boundary of a Secure Partition.
+ Check `tfm_hal_bind_boundary` for details.
+- ``base`` - The base address of the region.
+- ``size`` - The size of the region.
+- ``access_type`` - The memory access types to be checked between given memory
+ and boundaries. The `Memory Access Attributes`_.
+
+**Return Values**
+
+- ``TFM_HAL_SUCCESS`` - The memory region has the access permissions.
+- ``TFM_HAL_ERROR_MEM_FAULT`` - The memory region does not have the access
+ permissions.
+- ``TFM_HAL_ERROR_INVALID_INPUT`` - Invalid inputs.
+- ``TFM_HAL_ERROR_GENERIC`` - An error occurred.
+
+**Note**
+
+If the implementation chooses to encode a pointer as the boundary,
+a platform-specific pointer validation needs to be considered before
+referencing the content in this pointer.
+
+Log API
+=======
+The log API is used by the :term:`TF-M` :doc:`log system </design_docs/tfm_log_system_design_document>`.
+The log device could be uart, memory, usb, etc.
+
+APIs
+----
+tfm_hal_output_partition_log()
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+**Prototype**
+
+.. code-block:: c
+
+ int32_t tfm_hal_output_partition_log(const unsigned char *str, uint32_t len)
+
+**Description**
+
+This API is called by Secure Partition to output logs.
+
+**Parameter**
+
+- ``str`` - The string to output.
+- ``len`` - Length of the string in bytes.
+
+**Return Values**
+
+- Positive values - Number of bytes output.
+- ``TFM_HAL_ERROR_NOT_INIT`` - The log device has not been initialized.
+- ``TFM_HAL_ERROR_INVALID_INPUT`` - Invalid inputs when ``str`` is ``NULL`` or
+ ``len`` is zero.
+
+**Note**
+
+None.
+
+tfm_hal_output_spm_log()
+^^^^^^^^^^^^^^^^^^^^^^^^
+**Prototype**
+
+.. code-block:: c
+
+ int32_t tfm_hal_output_spm_log(const unsigned char *str, uint32_t len)
+
+**Description**
+
+This API is called by :term:`SPM` to output logs.
+
+**Parameter**
+
+- ``str`` - The string to output.
+- ``len`` - Length of the string in bytes.
+
+**Return Values**
+
+- Positive numbers - Number of bytes output.
+- ``TFM_HAL_ERROR_NOT_INIT`` - The log device has not been initialized.
+- ``TFM_HAL_ERROR_INVALID_INPUT`` - Invalid inputs when ``str`` is ``NULL``
+ or ``len`` is zero.
+
+**Note**
+
+Please check :doc:`TF-M log system </design_docs/tfm_log_system_design_document>`
+for more information.
+
+Interrupt APIs
+==============
+
+The SPM HAL interrupt APIs are intended for operations on Interrupt Controllers
+of platforms.
+
+APIs for control registers of interrupt sources are not in the scope of this set
+of APIs.
+Secure Partitions should define the APIs for managing interrupts with those MMIO
+registers.
+
+APIs
+----
+
+tfm_hal_irq_enable()
+^^^^^^^^^^^^^^^^^^^^
+
+**Prototype**
+
+.. code-block:: c
+
+ enum tfm_hal_status_t tfm_hal_irq_enable(uint32_t irq_num)
+
+**Description**
+
+This API enables an interrupt from the Interrupt Controller of the platform.
+
+**Parameter**
+
+- ``irq_num`` - the interrupt to be enabled with a number
+
+**Return Values**
+
+- ``TFM_HAL_ERROR_INVALID_INPUT`` - the ``irq_num`` exceeds The maximum
+ supported number of external interrupts.
+- ``TFM_HAL_ERROR_GENERIC`` - failed to enable the interrupt.
+- ``TFM_HAL_SUCCESS`` - the interrupt is successfully enabled.
+
+tfm_hal_irq_disable()
+^^^^^^^^^^^^^^^^^^^^^
+
+**Prototype**
+
+.. code-block:: c
+
+ enum tfm_hal_status_t tfm_hal_irq_disable(uint32_t irq_num)
+
+**Description**
+
+This API disables an interrupt from the Interrupt Controller of the platform.
+
+**Parameter**
+
+- ``irq_num`` - the interrupt to be disabled with a number
+
+**Return Values**
+
+- ``TFM_HAL_ERROR_INVALID_INPUT`` - the ``irq_num`` exceeds The maximum
+ supported number of external interrupts.
+- ``TFM_HAL_ERROR_GENERIC`` - failed to disable the interrupt.
+- ``TFM_HAL_SUCCESS`` - the interrupt is successfully disabled.
+
+tfm_hal_irq_clear_pending()
+^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+**Prototype**
+
+.. code-block:: c
+
+ enum tfm_hal_status_t tfm_hal_irq_clear_pending(uint32_t irq_num)
+
+**Description**
+
+This API clears an active and pending interrupt.
+
+**Parameter**
+
+- ``irq_num`` - the interrupt to be disabled with a number
+
+**Return Values**
+
+- ``TFM_HAL_ERROR_INVALID_INPUT`` - the ``irq_num`` exceeds The maximum
+ supported number of external interrupts.
+- ``TFM_HAL_ERROR_GENERIC`` - failed to clear the pending interrupt.
+- ``TFM_HAL_SUCCESS`` - the pending interrupt has been cleared.
+
+Initializations
+^^^^^^^^^^^^^^^
+
+**Prototype**
+
+.. code-block:: c
+
+ enum tfm_hal_status_t {source_symbol}_init(void *p_pt,
+ const struct irq_load_info_t *p_ildi)
+
+The ``{source_symbol}`` is:
+
+- ``irq_{source}``, if the ``source`` attribute of the IRQ in Partition manifest
+ is a number
+- Lowercase of ``source`` attribute, if ``source`` is a symbolic name
+
+**Description**
+
+Each interrupt has an initialization function individually.
+The :term:`SPM` calls the functions while loading the Partitions.
+
+The following initializations are required for each interrupt:
+
+- Setting the priority. The value must between 0 to 0x80 exclusively.
+- Ensuring that the interrupt targets the Secure State.
+- Saving the input parameters for future use.
+
+Platforms can have extra initializations as well.
+
+**Parameter**
+
+- ``p_pt`` - pointer to Partition runtime struct of the owner Partition
+- ``p_ildi`` - pointer to ``irq_load_info_t`` struct of the interrupt
+
+**Note**
+
+Please refer to the
+:doc: `IRQ intergration guide<tfm_secure_irq_integration_guide>`
+for more information.
+
+************************************
+API Definition for Secure Partitions
+************************************
+The Secure Partition (SP) :term:`HAL` mainly focuses on two parts:
+
+ - Peripheral devices. The peripherals accessed by the :term:`TF-M` default
+ Secure Partitions.
+ - Secure Partition abstraction support. The Secure Partition data that must be
+ provided by the platform.
+
+The Secure Partition abstraction support will be introduced in the peripheral
+API definition.
+
+ITS and PS flash API
+====================
+There are two kinds of flash:
+
+ - Internal flash. Accessed by the PSA Internal Trusted Storage (ITS) service.
+ - External flash. Accessed by the PSA Protected Storage (PS) service.
+
+The ITS HAL for the internal flash device is defined in the ``tfm_hal_its.h``
+header and the PS HAL in the ``tfm_hal_ps.h`` header.
+
+Macros
+------
+Internal Trusted Storage
+^^^^^^^^^^^^^^^^^^^^^^^^
+TFM_HAL_ITS_FLASH_DRIVER
+~~~~~~~~~~~~~~~~~~~~~~~~
+Defines the identifier of the CMSIS Flash ARM_DRIVER_FLASH object to use for
+ITS. It must have been allocated by the platform and will be declared extern in
+the HAL header.
+
+TFM_HAL_ITS_PROGRAM_UNIT
+~~~~~~~~~~~~~~~~~~~~~~~~
+Defines the size of the ITS flash device's physical program unit (the smallest
+unit of data that can be individually programmed to flash). It must be equal to
+TFM_HAL_ITS_FLASH_DRIVER.GetInfo()->program_unit, but made available at compile
+time so that filesystem structures can be statically sized.
+
+TFM_HAL_ITS_FLASH_AREA_ADDR
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Defines the base address of the dedicated flash area for ITS.
+
+TFM_HAL_ITS_FLASH_AREA_SIZE
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Defines the size of the dedicated flash area for ITS in bytes.
+
+TFM_HAL_ITS_SECTORS_PER_BLOCK
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Defines the number of contiguous physical flash erase sectors that form a
+logical filesystem erase block.
+
+Protected Storage
+^^^^^^^^^^^^^^^^^
+TFM_HAL_PS_FLASH_DRIVER
+~~~~~~~~~~~~~~~~~~~~~~~
+Defines the identifier of the CMSIS Flash ARM_DRIVER_FLASH object to use for
+PS. It must have been allocated by the platform and will be declared extern in
+the HAL header.
+
+TFM_HAL_PS_PROGRAM_UNIT
+~~~~~~~~~~~~~~~~~~~~~~~~
+Defines the size of the PS flash device's physical program unit (the smallest
+unit of data that can be individually programmed to flash). It must be equal to
+TFM_HAL_PS_FLASH_DRIVER.GetInfo()->program_unit, but made available at compile
+time so that filesystem structures can be statically sized.
+
+TFM_HAL_PS_FLASH_AREA_ADDR
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Defines the base address of the dedicated flash area for PS.
+
+TFM_HAL_PS_FLASH_AREA_SIZE
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Defines the size of the dedicated flash area for PS in bytes.
+
+TFM_HAL_PS_SECTORS_PER_BLOCK
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Defines the number of contiguous physical flash erase sectors that form a
+logical filesystem erase block.
+
+Optional definitions
+--------------------
+The ``TFM_HAL_ITS_FLASH_AREA_ADDR``, ``TFM_HAL_ITS_FLASH_AREA_SIZE`` and
+``TFM_HAL_ITS_SECTORS_PER_BLOCK`` definitions are optional. If not defined, the
+platform must implement ``tfm_hal_its_fs_info()`` instead.
+
+Equivalently, ``tfm_hal_its_ps_info()`` must be implemented by the platform if
+``TFM_HAL_ITS_FLASH_AREA_ADDR``, ``TFM_HAL_ITS_FLASH_AREA_SIZE`` or
+``TFM_HAL_ITS_SECTORS_PER_BLOCK`` is not defined.
+
+Objects
+-------
+ARM_DRIVER_FLASH
+^^^^^^^^^^^^^^^^
+The ITS and PS HAL headers each expose a CMSIS Flash Driver instance.
+
+.. code-block:: c
+
+ extern ARM_DRIVER_FLASH TFM_HAL_ITS_FLASH_DRIVER
+
+ extern ARM_DRIVER_FLASH TFM_HAL_PS_FLASH_DRIVER
+
+The CMSIS Flash Driver provides the flash primitives ReadData(), ProgramData()
+and EraseSector() as well as GetInfo() to access flash device properties such
+as the sector size.
+
+Types
+-----
+tfm_hal_its_fs_info_t
+^^^^^^^^^^^^^^^^^^^^^
+Struct containing information required from the platform at runtime to configure
+the ITS filesystem.
+
+.. code-block:: c
+
+ struct tfm_hal_its_fs_info_t {
+ uint32_t flash_area_addr;
+ size_t flash_area_size;
+ uint8_t sectors_per_block;
+ };
+
+Each attribute is described below:
+
+ - ``flash_area_addr`` - Location of the block of flash to use for ITS
+ - ``flash_area_size`` - Number of bytes of flash to use for ITS
+ - ``sectors_per_block`` - Number of erase sectors per logical FS block
+
+tfm_hal_ps_fs_info_t
+^^^^^^^^^^^^^^^^^^^^^
+Struct containing information required from the platform at runtime to configure
+the PS filesystem.
+
+.. code-block:: c
+
+ struct tfm_hal_ps_fs_info_t {
+ uint32_t flash_area_addr;
+ size_t flash_area_size;
+ uint8_t sectors_per_block;
+ };
+
+Each attribute is described below:
+
+ - ``flash_area_addr`` - Location of the block of flash to use for PS
+ - ``flash_area_size`` - Number of bytes of flash to use for PS
+ - ``sectors_per_block`` - Number of erase sectors per logical FS block
+
+Functions
+---------
+tfm_hal_its_fs_info()
+^^^^^^^^^^^^^^^^^^^^^
+**Prototype**
+
+.. code-block:: c
+
+ enum tfm_hal_status_t tfm_hal_its_fs_info(struct tfm_hal_its_fs_info_t *fs_info);
+
+**Description**
+
+Retrieves the filesystem configuration parameters for ITS.
+
+**Parameter**
+
+- ``fs_info`` - Filesystem config information
+
+**Return values**
+
+- ``TFM_HAL_SUCCESS`` - The operation completed successfully
+- ``TFM_HAL_ERROR_INVALID_INPUT`` - Invalid parameter
+
+**Note**
+
+This function should ensure that the values returned do not result in a security
+compromise. The block of flash supplied must meet the security requirements of
+Internal Trusted Storage.
+
+tfm_hal_ps_fs_info()
+^^^^^^^^^^^^^^^^^^^^
+**Prototype**
+
+.. code-block:: c
+
+ enum tfm_hal_status_t tfm_hal_ps_fs_info(struct tfm_hal_ps_fs_info_t *fs_info);
+
+**Description**
+
+Retrieves the filesystem configuration parameters for PS.
+
+**Parameter**
+
+- ``fs_info`` - Filesystem config information
+
+**Return values**
+
+- ``TFM_HAL_SUCCESS`` - The operation completed successfully
+- ``TFM_HAL_ERROR_INVALID_INPUT`` - Invalid parameter
+
+**Note**
+
+This function should ensure that the values returned do not result in a security
+compromise.
+
+--------------
+
+*Copyright (c) 2020-2022, Arm Limited. All rights reserved.*
+*Copyright (c) 2022 Cypress Semiconductor Corporation (an Infineon company)
+or an affiliate of Cypress Semiconductor Corporation. All rights reserved.*
diff --git a/docs/design_docs/software/index.rst b/docs/design_docs/software/index.rst
new file mode 100644
index 0000000..45240ed
--- /dev/null
+++ b/docs/design_docs/software/index.rst
@@ -0,0 +1,16 @@
+#####################
+Software Design Notes
+#####################
+
+.. toctree::
+ :maxdepth: 1
+
+ Code Sharing <code_sharing.rst>
+ Hardware Abstraction Layer <hardware_abstraction_layer.rst>
+ Cooperative Scheduling <tfm_cooperative_scheduling_rules.rst>
+ Code Templates <tfm_code_generation_with_jinja2.rst>
+ Implicit Typecasintg <enum_implicit_casting.rst>
+
+--------------
+
+*Copyright (c) 2023, Arm Limited. All rights reserved.*
diff --git a/docs/design_docs/software/tfm_code_generation_with_jinja2.rst b/docs/design_docs/software/tfm_code_generation_with_jinja2.rst
new file mode 100644
index 0000000..fbdfbbc
--- /dev/null
+++ b/docs/design_docs/software/tfm_code_generation_with_jinja2.rst
@@ -0,0 +1,78 @@
+###########################
+Code Generation With Jinja2
+###########################
+
+:Author: Mate Toth-Pal
+:Organization: Arm Limited
+:Contact: Mate Toth-Pal <mate.toth-pal@arm.com>
+
+***************************************
+Generating files from templates in TF-M
+***************************************
+
+Some of the files in TF-M are generated from template files. The files to be
+generated are listed in ``tools/tfm_generated_file_list.yaml``. For each
+generated file ``<path_to_file>/<filename>`` the template file is
+``<path_to_file>/<filename>.template``. The templates are populated with
+partition information from the partition manifests. The manifests to be used for
+the generation are listed in ``tools/tfm_manifest_list.yaml``.
+
+****************************************
+Custom generator script - Current method
+****************************************
+
+``tools/tfm_parse_manifest_list.py`` Python script is used to generate files
+from the templates. This script calls the ``tools/generate_from_template.py`` to
+parse the template files, and uses ``tools/keyword_substitution.py`` to
+substitute the keychains with actual values from the manifest files.
+
+*************************************
+Use Jinja2 template engine - proposal
+*************************************
+
+The proposal is to eliminate the template parser and substituter scripts, and
+call the Jinja2 template engine library from
+``tools/tfm_parse_manifest_list.py`` to do the substitution.
+
+More information on jinja2: http://jinja.pocoo.org/
+
+Changes needed:
+===============
+
+- ``tools/tfm_parse_manifest_list.py`` have to be modified to call the Jinja2
+ library instead of the custom scripts. The data structure required by the
+ library is very similar to the one required by the current scripts.
+- template files needs to be rewritten to the Jinja syntax: The control
+ characters to be replaced (like ``@!`` -> ``{%``) and ``for`` statements to be
+ added to iterate over the substitutions.
+
+Improvements over the current solution
+======================================
+
+- Compatible with Python 2.7 and Python 3, while current solution only supports
+ Python 2.7
+- More advanced functionality: direct control over the list of items for a
+ keychain, meta information on that list (like length)
+- Well documented (see website)
+- Jinja2 is free and open-source software, BSD licensed, just like TF-M. It is a
+ well established software in contrast with the current proprietary solution.
+
+*******
+Example
+*******
+
+Below code snippet enumerates services in Secure Partitions:
+
+.. code-block:: jinja
+
+ {% for partition in partitions %}
+ {% if partition.manifest.services %}
+ {% for service in partition.manifest.services %}
+ {do something for the service}
+ {% endfor %}
+ {% endif %}
+ {% endfor %}
+
+--------------
+
+*Copyright (c) 2019-2021, Arm Limited. All rights reserved.*
diff --git a/docs/design_docs/software/tfm_cooperative_scheduling_rules.rst b/docs/design_docs/software/tfm_cooperative_scheduling_rules.rst
new file mode 100644
index 0000000..37270da
--- /dev/null
+++ b/docs/design_docs/software/tfm_cooperative_scheduling_rules.rst
@@ -0,0 +1,210 @@
+############################
+Cooperative Scheduling Rules
+############################
+
+:Author: Ashutosh Singh
+:Organization: Arm Limited
+:Contact: Ashutosh Singh <ashutosh.singh@arm.com>
+
+TF-M Scheduler - Rules
+======================
+
+On ArmV8-M CPUs, NSPE and SPE share the same physical processing element(PE). A
+TF-M enabled system need to be able to handle asynchronous events (interrupts)
+regardless of current security state of the PE, and that may lead to scheduling
+decisions. This introduces significant complexity into TF-M. To keep the
+integrity of (NSPE and SPE) schedulers and call paths between NSPE and SPE,
+following set of rules are imposed on the TF-M scheduler design.
+
+Objectives and Requirements
+===========================
+
+1. Decoupling of scheduling decisions between NSPE and SPE
+2. Efficient interrupt handling by SPE as well as NSPE
+3. Reduce critical sections on the secure side to not block interrupts
+ unnecessarily
+4. Scalability to allow simplification/reduction of overheads to scale down the
+ design for constrained devices
+5. Reduce impact on NSPE software design
+
+ a. NSPE interrupt handling implementation should be independent
+ b. Impact on the NSPE scheduler should be minimal
+ c. No assumptions should be made about NSPE's scheduling capabilities
+
+Scheduler Rules for context switching between SPE and NSPE
+==========================================================
+
+To allow coherent cooperative scheduling, following set of rules are imposed on
+security state changes.
+The switching between SPE and NSPE can be triggered in multiple ways.
+
+`Involuntary security state switch`; when the software has no control over the
+switch:
+
+- A NSPE interrupt take control into NSPE from SPE
+- A SPE interrupt takes control into SPE from NSPE
+
+`Voluntary security state switch`; when software programmatically makes the
+switch:
+
+- A NSPE exception handler returns from NSPE to pre-empted SPE context
+- A SPE exception handler returns from SPE to pre-empted NSPE context
+- NSPE makes a function call into SPE
+- SPE returns a call from NSPE
+- SPE makes a function call into NSPE (not covered in current design)
+- NSPE returns a call from SPE (not covered in current design)
+
+In order to maintain the call stack integrity across NSPE and SPE, following
+rules are imposed on all security state switches.
+
+Rules for NSPE Exception handling
+---------------------------------
+
+1. **The NSPE exception handler is allowed to trigger a NSPE context switch**
+ **(regardless of security state of the preempted context.**
+
+This is expected behaviour of any (RT)OS.
+
+2. **The NSPE scheduler must eventually 'restore' the preempted (by**
+ **exception) context.**
+
+This is expected behaviour of any (RT)OS.
+
+3. **If NSPE exception results in a NSPE context switch, SPM must be informed**
+ **of the scheduling decision; this must be done BEFORE the execution of**
+ **newly scheduled-in context.**
+
+This is to ensures integrity of the call stack when SPE is ready to return a
+previous function call from NSPE.
+
+Rules for SPE Exception handling
+--------------------------------
+
+1. **All of the SPE interrupts must have higher priority than NSPE interrupts**
+
+This is rule is primarily for simplifying the SPM design.
+
+2. **The SPE interrupt handler is allowed to trigger a SPE context switch**
+ **(regardless of security state of the pre-empted context)**
+
+If the SPE context targeted by the interrupt is not same as current SPE context,
+the SPM may choose to switch the current running SPE context based on priority.
+
+3. **SPE scheduler must treat pre-empted context as one of the SPE contexts**
+
+ a. If the pre-empted SPE context is SP1, the TCB for SP1 should be used for
+ saving the context. i.e. the context of SP1 should be saved before
+ scheduling anything other secure partition.
+ b. If SP1 was pre-empted by a NSPE interrupt, and subsequent NSPE execution is
+ pre-empted by SPE exception (before NSPE scheduling decision is communicated
+ back to SPM) -- SP1 TCB must be used for saving the context
+ In this case SPM is not yet aware of the NSPE context switch, from SPM's
+ standpoint SP1 is still executing, so SPM assumes that the preempted context
+ is SP1.
+ c. If SP1 was pre-empted by a NSPE interrupt, and subsequent NSPE execution is
+ pre-empted by SPE exception `after` NSPE scheduling decision is
+ communicated back to SPM) - a TCB dedicated to NSPE should be used for
+ saving the context.
+
+ When NSPE scheduler communicates the scheduling decision to SPM, SPM must save
+ the SP1 context, if a SPE interrupt preempts the currently running NSPE context,
+ SPM should save the context to a dedicated NSPE TCB.
+
+ d. The SPE scheduler must eventually 'restore' the pre-empted context.
+ This is an expected behaviour of any scheduler.
+
+4. **All of the interrupts belonging to a partition must have same priority.**
+
+This serializes ISR execution targeted for same partition.
+
+5. **In case of nested interrupts, all of the ISRs must run to finish before**
+ **any service code is allowed to run**
+
+This is an expected behaviour of any scheduler.
+
+6. **If the previously preempted context was a NSPE ISR context, SPE ISR**
+ **handler must return to preempted NSPE context.**
+
+This is an expected behaviour of any scheduler to return to preempted context.
+
+Rules for NSPE to SPM function call (and NSPE scheduler)
+--------------------------------------------------------
+
+1. Current NSPE context must have been communicated to SPM, otherwise SPM cannot
+ guarantee NSPE function calling stack integrity.
+
+Rules for Function Return from SPE to NSPE with result
+------------------------------------------------------
+
+1. **The result available on SPE side are for currently active NSPE context.**
+
+To maintain call stack integrity, if SPE is ready to return to NSPE, it can do
+function return only if the SPE return path corresponds to currently active NSPE
+context.
+
+2. **Last entry into secure world happened programmatically (Voluntary**
+ **security state switch into SPE)**
+
+i.e. control is voluntarily given back by NSPE, either through a function call,
+or a context restore via 'return to SPE from NSPE'. As opposed to a SPE
+interrupt bringing back the execution into SPE.
+
+3. **The current NSPE call stack has not already been returned with SPM_IDLE.**
+
+This rule applies if following optional feature is enabled.
+
+Rules for Return from SPE to NSPE with SPM_IDLE
+-----------------------------------------------
+
+This is optional part of the design as it introduces significant complexity on
+both sides of the security boundary.
+It allows yielding of the CPU to NSPE when SPE has not CPU execution to do but
+it has not yet finished the previous request(s) from NSPE; i.e. SPE is waiting
+on arrival of a SPE interrupt.
+
+1. **Last entry into secure world happens programmatically (Voluntary**
+ **security context switch into SPE)**
+
+i.e. control is voluntarily given back by NSPE, either through a function call,
+or a context restore via 'return to SPE from NSPE'. As opposed to a SPE
+interrupt bringing back the execution into SPE.
+
+2. **The result for the currently active NSPE entity is not yet available,**
+ **the called service is waiting (on interrupt/event).**
+
+SPE request corresponding to currently active NSPE caller is not yet completed
+and is waiting on an ISR.
+
+3. **The current NSPE call stack has not already been returned with SPM_IDLE.**
+
+Rules for NSPE pend irq based return from SPE to NSPE
+-----------------------------------------------------
+
+This is optional part of the design as it introduces significant complexity on
+both sides. This works in conjunction with [Rules for Return from SPE to NSPE
+with SPM_IDLE](#rules-for-return-from-spe-to-nspe-with-spm_idle).
+In this scenario, when SPE is ready with result for a previous call from NSPE,
+it raises a pended IRQ to NSPE instead of returning the function call path.
+
+1. **The SPE has finished a NSPE request.**
+
+2. **The corresponding NSPE context has already been returned with SPM_IDLE.**
+
+Rules for ISR pre-emption
+-------------------------
+
+1. **A higher priority NSPE interrupt is allowed to preempt a lower priority**
+ **NSPE ISR**
+
+2. **A higher priority SPE interrupt is allowed to preempt a lower priority**
+ **SPE ISR**
+
+3. **A SPE interrupt is allowed to preempt NSPE ISR**
+
+4. **A NSPE interrupt is not allowed to preempt SPE ISR**
+
+5. **All interrupts belonging to a service must have same priority**
+
+--------------
+
+*Copyright (c) 2019, Arm Limited. All rights reserved.*