123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568 |
- Context Management Library
- **************************
- This document provides an overview of the Context Management library implementation
- in Trusted Firmware-A (TF-A). It enumerates and describes the APIs implemented
- and their accessibility from other components at EL3.
- Overview
- ========
- Arm TrustZone architecture facilitates hardware-enforced isolation between
- software running in various security states (Secure/Non-Secure/Realm).
- The general-purpose registers, most of the system registers and vector registers
- are not banked per world. When moving between the security states it is the
- responsibility of the secure monitor software (BL31(AArch64) / BL32(Aarch32))
- in TF-A, not the hardware, to save and restore register state.
- Refer to `Trustzone for AArch64`_ for more details.
- EL3 Runtime Firmware, also termed as secure monitor firmware, is integrated
- with a context management library to handle the context of the CPU, managing the
- saving and restoring of register states across the worlds.
- TF-A Context
- ============
- In TF-A, the context is represented as a data structure used by the EL3 firmware
- to preserve the state of the CPU at the next lower exception level (EL) in a given
- security state and save enough EL3 metadata to be able to return to that exception
- level and security state. The memory for the context data structures are allocated
- in BSS section of EL3 firmware.
- In a trusted system at any instance, a given CPU could be executing in one of the
- security states (Non-Secure, Secure, Realm). Each world must have its
- configuration of system registers independent of other security states to access
- and execute any of the architectural features.
- If the CPU switches across security states (for example: from Non-secure to Secure
- or vice versa), the register contents, especially the ones that are not banked
- (EL2/EL1, vector, general-purpose registers), will be overwritten, as the software
- running in either state has the privileges to access them. Additionally, some of
- the architectural features enabled in the former security state will be unconditionally
- accessible in the latter security state as well. This can be a major concern when
- dealing with security-specific bits, as they need to be explicitly enabled or
- disabled in each state to prevent data leakage across the worlds.
- In general, an ideal trusted system should have Secure world-specific configurations
- that are not influenced by Normal World operations. Therefore, for each CPU, we
- need to maintain world-specific context to ensure that register entries from one
- world do not leak or impact the execution of the CPU in other worlds.
- This will help ensure the integrity and security of the system, preventing any
- unauthorized access or data corruption between the different security states.
- Design
- ======
- The Context Management library in TF-A is designed to cover all the requirements
- for maintaining world-specific context essential for a trusted system.
- This includes implementing CPU context initialization and management routines,
- as well as other helper APIs that are required by dispatcher components in EL3
- firmware, which are collectively referred to as CPU Context Management.
- The APIs and their usecases are listed in detail under the :ref:`Library APIs`
- section.
- Originally, the Context Management library in TF-A was designed to cater for a
- two-world system, comprising of Non-Secure and Secure Worlds. In this case, the
- EL3 Firmware is assumed to be running in Secure World.
- With introduction of Realm Management Extension (RME), from Armv9.2 a system
- can have four distinct worlds (Non-Secure, Secure, Realm, Root).
- RME isolates EL3 from all other Security states and moves it into its own security
- state called root. EL3 firmware now runs at Root World and thereby is
- trusted from software in Non-secure, Secure, and Realm states.
- Refer to `Security States with RME`_ for more details.
- Key principles followed in designing the context management library :
- 1. **EL3 should only initialize immediate used lower EL**
- Context Management library running at EL3 should only initialize and monitor the
- immediate used lower EL. This implies that, when S-EL2 is present in the system,
- EL3 should initialise and monitor S-EL2 registers only. S-EL1 registers should
- not be the concern of EL3 while S-EL2 is in place. In systems where S-EL2 is
- absent, S-EL1 registers should be initialised from EL3.
- 2. **Decentralized model for context management**
- Each world (Non-Secure, Secure, and Realm) should have their separate component
- in EL3 responsible for their respective world context management.
- Both the Secure and Realm world have associated dispatcher components in EL3
- firmware to allow management of the respective worlds. For the Non-Secure world,
- PSCI Library (BL31)/context management library provides routines to help
- initialize the Non-Secure world context.
- 3. **Flexibility for Dispatchers to select desired feature set to save and restore**
- Each feature is supported with a helper function ``is_feature_supported(void)``,
- to detect its presence at runtime. This helps dispatchers to select the desired
- feature set, and thereby save and restore the configuration associated with them.
- 4. **Dynamic discovery of Feature enablement by EL3**
- TF-A supports four states for feature enablement at EL3, to make them available
- for lower exception levels.
- .. code:: c
- #define FEAT_STATE_DISABLED 0
- #define FEAT_STATE_ENABLED 1
- #define FEAT_STATE_CHECK 2
- #define FEAT_STATE_CHECK_ASYMMETRIC 3
- A pattern is established for feature enablement behavior.
- Each feature must support the 3 possible values with rigid semantics.
- - **FEAT_STATE_DISABLED** - all code relating to this feature is always skipped.
- Firmware is unaware of this feature.
- - **FEAT_STATE_ALWAYS** - all code relating to this feature is always executed.
- Firmware expects this feature to be present in hardware.
- - **FEAT_STATE_CHECK** - same as ``FEAT_STATE_ALWAYS`` except that the feature's
- existence will be checked at runtime. Default on dynamic platforms (example: FVP).
- - **FEAT_STATE_CHECK_ASYMMETRIC** - same as ``FEAT_STATE_CHECK`` except that the feature's
- existence is asymmetric across cores, which requires the feature existence is checked
- during warmboot path also. Note that only limited number of features can be asymmetric.
- .. note::
- Only limited number of features can be ``FEAT_STATE_CHECK_ASYMMETRIC`` this is due to
- the fact that Operating systems are designed for SMP systems.
- There are no clear guidelines what kind of mismatch is allowed but following pointers
- can help making a decision
- - All mandatory features must be symmetric.
- - Any feature that impacts the generation of page tables must be symmetric.
- - Any feature access which does not trap to EL3 should be symmetric.
- - Features related with profiling, debug and trace could be asymmetric
- - Migration of vCPU/tasks between CPUs should not cause an error
- Whenever there is asymmetric feature support is added for a feature TF-A need to add
- feature specific code in context management code.
- .. note::
- ``FEAT_RAS`` is an exception here, as it impacts the execution of EL3 and
- it is essential to know its presence at compile time. Refer to ``ENABLE_FEAT``
- macro under :ref:`Build Options` section for more details.
- Code Structure
- ==============
- `lib/el3_runtime/(aarch32/aarch64)`_ - Context library code directory.
- Source Files
- ~~~~~~~~~~~~
- #. ``context_mgmt.c`` : consists of core functions that setup, save and restore
- context for different security states alongside high level feature enablement
- APIs for individual worlds.
- #. ``cpu_data_array.c`` : contains per_cpu_data structure instantiation.
- #. ``context.S`` : consists of functions that save and restore some of the context
- structure members in assembly code.
- #. ``cpu_data.S`` : consists of helper functions to initialise per_cpu_data pointers.
- #. ``el3_common_macros.S`` : consists of macros to facilitate actions to be performed
- during cold and warmboot and el3 registers initialisation in assembly code.
- Header Files
- ~~~~~~~~~~~~
- #. ``context_mgmt.h`` : contains the public interface to Context Management Library.
- #. ``context.h`` : contains the helper macros and definitions for context entries.
- #. ``cpu_data.h`` : contains the public interface to Per CPU data structure.
- #. ``context_debug.h`` : contains public interface to report context memory
- utilisation across the security states.
- #. ``context_el2.h`` : internal header consisting of helper macros to access EL2
- context entries. Used by ``context.h``.
- Apart from these files, we have some context related source files under ``BL1``
- and ``BL31`` directory. ``bl1_context_mgmt.c`` ``bl31_context_mgmt.c``
- Bootloader Images utilizing Context Management Library
- ======================================================
- +-------------------------------------------+-----------------------------+
- | Bootloader | Context Management Library |
- +-------------------------------------------+-----------------------------+
- | BL1 | Yes |
- +-------------------------------------------+-----------------------------+
- | BL2 | No |
- +-------------------------------------------+-----------------------------+
- | BL31 (Aarch64- EL3runtime firmware) | Yes |
- +-------------------------------------------+-----------------------------+
- | BL32 (Aarch32- EL3runtime firmware) | Yes |
- +-------------------------------------------+-----------------------------+
- CPU Data Structure
- ==================
- For a given system, depending on the CPU count, the platform statically
- allocates memory for the CPU data structure.
- .. code:: c
- /* The per_cpu_ptr_cache_t space allocation */
- cpu_data_t percpu_data[PLATFORM_CORE_COUNT];
- This CPU data structure has a member element with an array of pointers to hold
- the Non-Secure, Realm and Secure security state context structures as listed below.
- .. code:: c
- typedef struct cpu_data {
- #ifdef __aarch64__
- void *cpu_context[CPU_DATA_CONTEXT_NUM];
- #endif
- ....
- ....
- }cpu_data_t;
- |CPU Data Structure|
- At runtime, ``cpu_context[CPU_DATA_CONTEXT_NUM]`` array will be intitialised with
- the Secure, Non-Secure and Realm context structure addresses to ensure proper
- handling of the register state.
- See :ref:`Library APIs` section for more details.
- CPU Context and Memory allocation
- =================================
- CPU Context
- ~~~~~~~~~~~
- The members of the context structure used by the EL3 firmware to preserve the
- state of CPU across exception levels for a given security state are listed below.
- .. code:: c
- typedef struct cpu_context {
- gp_regs_t gpregs_ctx;
- el3_state_t el3state_ctx;
- cve_2018_3639_t cve_2018_3639_ctx;
- #if ERRATA_SPECULATIVE_AT
- errata_speculative_at_t errata_speculative_at_ctx;
- #endif
- #if CTX_INCLUDE_PAUTH_REGS
- pauth_t pauth_ctx;
- #endif
- #if (CTX_INCLUDE_EL2_REGS && IMAGE_BL31)
- el2_sysregs_t el2_sysregs_ctx;
- #else
- el1_sysregs_t el1_sysregs_ctx;
- #endif
- } cpu_context_t;
- Context Memory Allocation
- ~~~~~~~~~~~~~~~~~~~~~~~~~
- CPUs maintain their context per world. The individual context memory allocation
- for each CPU per world is allocated by the world-specific dispatcher components
- at compile time as shown below.
- |Context memory allocation|
- NS-Context Memory
- ~~~~~~~~~~~~~~~~~
- It's important to note that the Normal world doesn't possess the dispatcher
- component found in the Secure and Realm worlds. Instead, the PSCI library at EL3
- handles memory allocation for ``Non-Secure`` world context for all CPUs.
- .. code:: c
- static cpu_context_t psci_ns_context[PLATFORM_CORE_COUNT];
- Secure-Context Memory
- ~~~~~~~~~~~~~~~~~~~~~
- Secure World dispatcher (such as SPMD) at EL3 allocates the memory for ``Secure``
- world context of all CPUs.
- .. code:: c
- static spmd_spm_core_context_t spm_core_context[PLATFORM_CORE_COUNT];
- Realm-Context Memory
- ~~~~~~~~~~~~~~~~~~~~
- Realm World dispatcher (RMMD) at EL3 allocates the memory for ``Realm`` world
- context of all CPUs.
- .. code:: c
- rmmd_rmm_context_t rmm_context[PLATFORM_CORE_COUNT];
- To summarize, the world-specific context structures are synchronized with
- per-CPU data structures, which means that each CPU will have an array of pointers
- to individual worlds. The figure below illustrates the same.
- |CPU Context Memory Configuration|
- Context Setup/Initialization
- ============================
- The CPU has been assigned context structures for every security state, which include
- Non-Secure, Secure and Realm. It is crucial to initialize each of these structures
- during the bootup of every CPU before they enter any security state for the
- first time. This section explains the specifics of how the initialization of
- every CPU context takes place during both cold and warm boot paths.
- Context Setup during Cold boot
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- The cold boot path is mainly executed by the primary CPU, other than essential
- CPU initialization executed by all CPUs. After executing BL1 and BL2, the Primary
- CPU jumps to the BL31 image for runtime services initialization.
- During this process, the per_cpu_data structure gets initialized with statically
- allocated world-specific context memory.
- Later in the cold boot sequence, the BL31 image at EL3 checks for the presence
- of a Secure world image at S-EL2. If detected, it invokes the secure context
- initialization sequence under SPMD. Additionally, based on RME enablement,
- the Realm context gets initialized from the RMMD at EL3. Finally, before exiting
- to the normal world, the Non-Secure context gets initialized via the context
- management library. At this stage, all Primary CPU contexts are initialized
- and the CPU exits EL3 to enter the Normal world.
- |Context Init ColdBoot|
- .. note::
- The figure above illustrates a scenario on FVP for one of the build
- configurations with TFTF component at NS-EL2.
- Context Setup during Warmboot
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- During a warm boot sequence, the primary CPU is responsible for powering on the
- secondary CPUs. Refer to :ref:`CPU Reset` and :ref:`Firmware Design` sections for
- more details on the warm boot.
- |Context Init WarmBoot|
- The primary CPU initializes the Non-Secure context for the secondary CPU while
- restoring re-entry information for the Non-Secure world.
- It initialises via ``cm_init_context_by_index(target_idx, ep )``.
- ``psci_warmboot_entrypoint()`` is the warm boot entrypoint procedure.
- During the warm bootup process, secondary CPUs have their secure context
- initialized through SPMD at EL3. Upon successful SP initialization, the SPD
- power management operations become shared with the PSCI library. During this
- process, the SPMD duly registers its handlers with the PSCI library.
- .. code:: c
- file: psci_common.c
- const spd_pm_ops_t *psci_spd_pm;
- file: spmd_pm.c
- const spd_pm_ops_t spmd_pm = {
- .svc_on_finish = spmd_cpu_on_finish_handler,
- .svc_off = spmd_cpu_off_handler
- }
- Secondary CPUs during their bootup in the ``psci_cpu_on_finish()`` routine get
- their secure context initialised via the registered SPMD handler
- ``spmd_cpu_on_finish_handler()`` at EL3.
- The figure above illustrates the same with reference of Primary CPU running at
- NS-EL2.
- .. _Library APIs:
- Library APIs
- ============
- The public APIs and types can be found in ``include/lib/el3_runtime/context_management.h``
- and this section is intended to provide additional details and clarifications.
- Context Initialization for Individual Worlds
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- The library implements high level APIs for the CPUs in setting up their individual
- context for each world (Non-Secure, Secure and Realm).
- .. c:function:: static void setup_context_common(cpu_context_t *ctx, const entry_point_info_t *ep);
- This function is responsible for the general context initialization that applies
- to all worlds. It will be invoked first, before calling the individual
- world-specific context setup APIs.
- .. c:function:: static void setup_ns_context(cpu_context_t *ctx, const struct entry_point_info *ep);
- .. c:function:: static void setup_realm_context(cpu_context_t *ctx, const struct entry_point_info *ep);
- .. c:function:: static void setup_secure_context(cpu_context_t *ctx, const struct entry_point_info *ep);
- Depending on the security state that the CPU needs to enter, the respective
- world-specific context setup handlers listed above will be invoked once per-CPU
- to set up the context for their execution.
- .. c:function:: void cm_manage_extensions_el3(void)
- This function initializes all EL3 registers whose values do not change during the
- lifetime of EL3 runtime firmware. It is invoked from each CPU via the cold boot
- path ``bl31_main()`` and in the WarmBoot entry path ``void psci_warmboot_entrypoint()``.
- Runtime Save and Restore of Registers
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- EL1 Registers
- -------------
- .. c:function:: void cm_el1_sysregs_context_save(uint32_t security_state);
- .. c:function:: void cm_el1_sysregs_context_restore(uint32_t security_state);
- These functions are utilized by the world-specific dispatcher components running
- at EL3 to facilitate the saving and restoration of the EL1 system registers
- during a world switch.
- EL2 Registers
- -------------
- .. c:function:: void cm_el2_sysregs_context_save(uint32_t security_state);
- .. c:function:: void cm_el2_sysregs_context_restore(uint32_t security_state);
- These functions are utilized by the world-specific dispatcher components running
- at EL3 to facilitate the saving and restoration of the EL2 system registers
- during a world switch.
- Pauth Registers
- ---------------
- Pointer Authentication feature is enabled by default for Non-Secure world and
- disabled for Secure and Realm worlds. In this case, we don't need to explicitly
- save and restore the Pauth registers during world switch.
- However, ``CTX_INCLUDE_PAUTH_REGS`` flag is explicitly used to enable Pauth for
- lower exception levels of Secure and Realm worlds. In this scenario, we save the
- general purpose and Pauth registers while we enter EL3 from lower ELs via
- ``prepare_el3_entry`` and restore them back while we exit EL3 to lower ELs
- via ``el3_exit``.
- .. code:: c
- .macro save_gp_pmcr_pauth_regs
- func restore_gp_pmcr_pauth_regs
- Feature Enablement for Individual Worlds
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- .. c:function:: static void manage_extensions_nonsecure(cpu_context_t *ctx);
- .. c:function:: static void manage_extensions_secure(cpu_context_t *ctx);
- .. c:function:: static void manage_extensions_realm(cpu_context_t *ctx)
- Functions that allow the enabling and disabling of architectural features for
- each security state. These functions are invoked from the top-level setup APIs
- during context initialization.
- Further, a pattern is established for feature enablement code (AArch64).
- Each feature implements following APIs as applicable:
- Note: (``xxx`` is the name of the feature in the APIs)
- - ``is_feat_xxx_supported()`` and ``is_feat_xxx_present()`` - mandatory for all features.
- - ``xxx_enable(cpu_context * )`` and ``xxx_disable(cpu_context * )`` - optional
- functions to enable the feature for the passed context only. To be called in
- the respective world's setup_context to select behaviour.
- - ``xxx_init_el3()`` - optional function to enable the feature in-place in any EL3
- registers that are never context switched. The values they write must never
- change, otherwise the functions mentioned in previous point should be used.
- Invoked from ``cm_manage_extensions_el3()``.
- - ``xxx_init_el2_unused()`` - optional function to enable the feature in-place
- in any EL2 registers that are necessary for execution in EL1 with no EL2 present.
- The above mentioned rules, followed for ``FEAT_SME`` is shown below:
- .. code:: c
- void sme_enable(cpu_context_t *context);
- void sme_init_el3(void);
- void sme_init_el2_unused(void);
- void sme_disable(cpu_context_t *context);
- Per-world Context
- =================
- Apart from the CPU context structure, we have another structure to manage some
- of the EL3 system registers whose values are identical across all the CPUs
- referred to as ``per_world_context_t``.
- The Per-world context structure is intended for managing EL3 system registers with
- identical values across all CPUs, requiring only a singular context entry for each
- individual world. This structure operates independently of the CPU context
- structure and is intended to manage specific EL3 registers.
- .. code-block:: c
- typedef struct per_world_context {
- uint64_t ctx_cptr_el3;
- uint64_t ctx_zcr_el3;
- uint64_t ctx_mpam3_el3;
- } per_world_context_t;
- These functions facilitate the activation of architectural extensions that possess
- identical values across all cores for the individual Non-secure, Secure, and
- Realm worlds.
- Root-Context (EL3-Execution-Context)
- ====================================
- EL3/Root Context is the execution environment while the CPU is running at EL3.
- Previously, while the CPU is in execution at EL3, the system registers persist
- with the values of the incoming world. This implies that if the CPU is entering
- EL3 from NS world, the EL1 and EL2 system registers which might be modified in
- lower exception levels NS(EL2/EL1) will carry forward those values to EL3.
- Further the EL3 registers also hold on to the values configured for Non-secure
- world, written during the previous ERET from EL3 to NS(EL2/EL1).
- Same policy is followed with respect to other worlds (Secure/Realm) depending on
- the system configuration.
- The firmware at EL3 has traditionally operated within the context of the incoming
- world (Secure/Non-Secure/Realm). This becomes problematic in scenarios where the
- EL3/Root world must explicitly use architectural features that depend on system
- registers configured for lower exception levels.
- A good example of this is the PAuth regs. The Root world would need to program
- its own PAuth Keys while executing in EL3 and this needs to be restored in entry
- to EL3 from any world.
- Therefore, Root world should maintain its own distinct settings to access
- features for its own execution at EL3.
- Register values which are currently known to be of importance during EL3 execution,
- is referred to as the EL3/Root context.
- This includes ( MDCR_EL3.SDD, SCR_EL3.{EA, SIF}, PMCR_EL0.DP, PSTATE.DIT)
- EL3 Context ensures, CPU executes under fixed EL3 system register settings
- which is not affected by settings of other worlds.
- Root Context needs to be setup as early as possible before we try and access/modify
- architectural features at EL3. Its a simple restore operation ``setup_el3_execution_context``
- that overwrites the selected bits listed above. EL3 never changes its mind about
- what those values should be, sets it as required for EL3. Henceforth, a Root
- context save operation is not required.
- The figure below illustrates the same with NS-world as a reference while entering
- EL3.
- |Root Context Sequence|
- .. code:: c
- # EL3/Root_Context routine
- .macro setup_el3_execution_context
- EL3 execution context needs to setup at both boot time (cold and warm boot)
- entrypaths and at all the possible exception handlers routing to EL3 at runtime.
- *Copyright (c) 2024, Arm Limited and Contributors. All rights reserved.*
- .. |Context Memory Allocation| image:: ../resources/diagrams/context_memory_allocation.png
- .. |CPU Context Memory Configuration| image:: ../resources/diagrams/cpu_data_config_context_memory.png
- .. |CPU Data Structure| image:: ../resources/diagrams/percpu-data-struct.png
- .. |Context Init ColdBoot| image:: ../resources/diagrams/context_init_coldboot.png
- .. |Context Init WarmBoot| image:: ../resources/diagrams/context_init_warmboot.png
- .. |Root Context Sequence| image:: ../resources/diagrams/root_context_sequence.png
- .. _Trustzone for AArch64: https://developer.arm.com/documentation/102418/0101/TrustZone-in-the-processor/Switching-between-Security-states
- .. _Security States with RME: https://developer.arm.com/documentation/den0126/0100/Security-states
- .. _lib/el3_runtime/(aarch32/aarch64): https://git.trustedfirmware.org/TF-A/trusted-firmware-a.git/tree/lib/el3_runtime
|