diff options
author | Paul Beesley <paul.beesley@arm.com> | 2019-02-11 17:54:45 +0000 |
---|---|---|
committer | Paul Beesley <paul.beesley@arm.com> | 2019-05-21 15:05:56 +0100 |
commit | 40d553cfde38d4f68449c62967cd1ce0d6478750 (patch) | |
tree | 1fafd4701066cdf0e5fb15aee2d842279a67b611 /docs/components | |
parent | 12b67439e93a78a4b756e987e1bd1b6e22cc4bf8 (diff) |
doc: Move documents into subdirectories
This change creates the following directories under docs/
in order to provide a grouping for the content:
- components
- design
- getting_started
- perf
- process
In each of these directories an index.rst file is created
and this serves as an index / landing page for each of the
groups when the pages are compiled. Proper layout of the
top-level table of contents relies on this directory/index
structure.
Without this patch it is possible to build the documents
correctly with Sphinx but the output looks messy because
there is no overall hierarchy.
Change-Id: I3c9f4443ec98571a56a6edf775f2c8d74d7f429f
Signed-off-by: Paul Beesley <paul.beesley@arm.com>
Diffstat (limited to 'docs/components')
-rw-r--r-- | docs/components/arm-sip-service.rst | 96 | ||||
-rw-r--r-- | docs/components/exception-handling.rst | 635 | ||||
-rw-r--r-- | docs/components/firmware-update.rst | 411 | ||||
-rw-r--r-- | docs/components/index.rst | 18 | ||||
-rw-r--r-- | docs/components/platform-interrupt-controller-API.rst | 312 | ||||
-rw-r--r-- | docs/components/ras.rst | 257 | ||||
-rw-r--r-- | docs/components/romlib-design.rst | 133 | ||||
-rw-r--r-- | docs/components/sdei.rst | 375 | ||||
-rw-r--r-- | docs/components/secure-partition-manager-design.rst | 823 | ||||
-rw-r--r-- | docs/components/spd/index.rst | 11 | ||||
-rw-r--r-- | docs/components/spd/optee-dispatcher.rst | 14 | ||||
-rw-r--r-- | docs/components/spd/tlk-dispatcher.rst | 76 | ||||
-rw-r--r-- | docs/components/spd/trusty-dispatcher.rst | 32 | ||||
-rw-r--r-- | docs/components/xlat-tables-lib-v2-design.rst | 427 |
14 files changed, 3620 insertions, 0 deletions
diff --git a/docs/components/arm-sip-service.rst b/docs/components/arm-sip-service.rst new file mode 100644 index 00000000..6cdac835 --- /dev/null +++ b/docs/components/arm-sip-service.rst @@ -0,0 +1,96 @@ +Arm SiP Service +=============== + +This document enumerates and describes the Arm SiP (Silicon Provider) services. + +SiP services are non-standard, platform-specific services offered by the silicon +implementer or platform provider. They are accessed via ``SMC`` ("SMC calls") +instruction executed from Exception Levels below EL3. SMC calls for SiP +services: + +- Follow `SMC Calling Convention`_; +- Use SMC function IDs that fall in the SiP range, which are ``0xc2000000`` - + ``0xc200ffff`` for 64-bit calls, and ``0x82000000`` - ``0x8200ffff`` for 32-bit + calls. + +The Arm SiP implementation offers the following services: + +- Performance Measurement Framework (PMF) +- Execution State Switching service + +Source definitions for Arm SiP service are located in the ``arm_sip_svc.h`` header +file. + +Performance Measurement Framework (PMF) +--------------------------------------- + +The `Performance Measurement Framework`_ +allows callers to retrieve timestamps captured at various paths in TF-A +execution. It's described in detail in `Firmware Design document`_. + +Execution State Switching service +--------------------------------- + +Execution State Switching service provides a mechanism for a non-secure lower +Exception Level (either EL2, or NS EL1 if EL2 isn't implemented) to request to +switch its execution state (a.k.a. Register Width), either from AArch64 to +AArch32, or from AArch32 to AArch64, for the calling CPU. This service is only +available when Trusted Firmware-A (TF-A) is built for AArch64 (i.e. when build +option ``ARCH`` is set to ``aarch64``). + +``ARM_SIP_SVC_EXE_STATE_SWITCH`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +:: + + Arguments: + uint32_t Function ID + uint32_t PC hi + uint32_t PC lo + uint32_t Cookie hi + uint32_t Cookie lo + + Return: + uint32_t + +The function ID parameter must be ``0x82000020``. It uniquely identifies the +Execution State Switching service being requested. + +The parameters *PC hi* and *PC lo* defines upper and lower words, respectively, +of the entry point (physical address) at which execution should start, after +Execution State has been switched. When calling from AArch64, *PC hi* must be 0. + +When execution starts at the supplied entry point after Execution State has been +switched, the parameters *Cookie hi* and *Cookie lo* are passed in CPU registers +0 and 1, respectively. When calling from AArch64, *Cookie hi* must be 0. + +This call can only be made on the primary CPU, before any secondaries were +brought up with ``CPU_ON`` PSCI call. Otherwise, the call will always fail. + +The effect of switching execution state is as if the Exception Level were +entered for the first time, following power on. This means CPU registers that +have a defined reset value by the Architecture will assume that value. Other +registers should not be expected to hold their values before the call was made. +CPU endianness, however, is preserved from the previous execution state. Note +that this switches the execution state of the calling CPU only. This is not a +substitute for PSCI ``SYSTEM_RESET``. + +The service may return the following error codes: + +- ``STATE_SW_E_PARAM``: If any of the parameters were deemed invalid for + a specific request. +- ``STATE_SW_E_DENIED``: If the call is not successful, or when TF-A is + built for AArch32. + +If the call is successful, the caller wouldn't observe the SMC returning. +Instead, execution starts at the supplied entry point, with the CPU registers 0 +and 1 populated with the supplied *Cookie hi* and *Cookie lo* values, +respectively. + +-------------- + +*Copyright (c) 2017-2018, Arm Limited and Contributors. All rights reserved.* + +.. _SMC Calling Convention: http://infocenter.arm.com/help/topic/com.arm.doc.den0028a/index.html +.. _Performance Measurement Framework: ./firmware-design.rst#user-content-performance-measurement-framework +.. _Firmware Design document: ./firmware-design.rst diff --git a/docs/components/exception-handling.rst b/docs/components/exception-handling.rst new file mode 100644 index 00000000..e3684f13 --- /dev/null +++ b/docs/components/exception-handling.rst @@ -0,0 +1,635 @@ +Exception Handling Framework in Trusted Firmware-A +================================================== + + + + +.. contents:: + :depth: 2 + +.. |EHF| replace:: Exception Handling Framework +.. |TF-A| replace:: Trusted Firmware-A + +This document describes various aspects of handling exceptions by Runtime +Firmware (BL31) that are targeted at EL3, other than SMCs. The |EHF| takes care +of the following exceptions when targeted at EL3: + +- Interrupts +- Synchronous External Aborts +- Asynchronous External Aborts + +|TF-A|'s handling of synchronous ``SMC`` exceptions raised from lower ELs is +described in the `Firmware Design document`__. However, the |EHF| changes the +semantics of `interrupt handling`__ and `synchronous exceptions`__ other than +SMCs. + +.. __: firmware-design.rst#handling-an-smc +.. __: `Interrupt handling`_ +.. __: `Effect on SMC calls`_ + +The |EHF| is selected by setting the build option ``EL3_EXCEPTION_HANDLING`` to +``1``, and is only available for AArch64 systems. + +Introduction +------------ + +Through various control bits in the ``SCR_EL3`` register, the Arm architecture +allows for asynchronous exceptions to be routed to EL3. As described in the +`Interrupt Framework Design`_ document, depending on the chosen interrupt +routing model, TF-A appropriately sets the ``FIQ`` and ``IRQ`` bits of +``SCR_EL3`` register to effect this routing. For most use cases, other than for +the purpose of facilitating context switch between Normal and Secure worlds, +FIQs and IRQs routed to EL3 are not required to be handled in EL3. + +However, the evolving system and standards landscape demands that various +exceptions are targeted at and handled in EL3. For instance: + +- Starting with ARMv8.2 architecture extension, many RAS features have been + introduced to the Arm architecture. With RAS features implemented, various + components of the system may use one of the asynchronous exceptions to signal + error conditions to PEs. These error conditions are of critical nature, and + it's imperative that corrective or remedial actions are taken at the earliest + opportunity. Therefore, a *Firmware-first Handling* approach is generally + followed in response to RAS events in the system. + +- The Arm `SDEI specification`_ defines interfaces through which Normal world + interacts with the Runtime Firmware in order to request notification of + system events. The SDEI specification requires that these events are notified + even when the Normal world executes with the exceptions masked. This too + implies that firmware-first handling is required, where the events are first + received by the EL3 firmware, and then dispatched to Normal world through + purely software mechanism. + +For |TF-A|, firmware-first handling means that asynchronous exceptions are +suitably routed to EL3, and the Runtime Firmware (BL31) is extended to include +software components that are capable of handling those exceptions that target +EL3. These components—referred to as *dispatchers* [#spd]_ in general—may +choose to: + +.. _delegation-use-cases: + +- Receive and handle exceptions entirely in EL3, meaning the exceptions + handling terminates in EL3. + +- Receive exceptions, but handle part of the exception in EL3, and delegate the + rest of the handling to a dedicated software stack running at lower Secure + ELs. In this scheme, the handling spans various secure ELs. + +- Receive exceptions, but handle part of the exception in EL3, and delegate + processing of the error to dedicated software stack running at lower secure + ELs (as above); additionally, the Normal world may also be required to + participate in the handling, or be notified of such events (for example, as + an SDEI event). In this scheme, exception handling potentially and maximally + spans all ELs in both Secure and Normal worlds. + +On any given system, all of the above handling models may be employed +independently depending on platform choice and the nature of the exception +received. + +.. [#spd] Not to be confused with `Secure Payload Dispatcher`__, which is an + EL3 component that operates in EL3 on behalf of Secure OS. + +.. __: firmware-design.rst#secure-el1-payloads-and-dispatchers + +The role of Exception Handling Framework +---------------------------------------- + +Corollary to the use cases cited above, the primary role of the |EHF| is to +facilitate firmware-first handling of exceptions on Arm systems. The |EHF| thus +enables multiple exception dispatchers in runtime firmware to co-exist, register +for, and handle exceptions targeted at EL3. This section outlines the basics, +and the rest of this document expands the various aspects of the |EHF|. + +In order to arbitrate exception handling among dispatchers, the |EHF| operation +is based on a priority scheme. This priority scheme is closely tied to how the +Arm GIC architecture defines it, although it's applied to non-interrupt +exceptions too (SErrors, for example). + +The platform is required to `partition`__ the Secure priority space into +priority levels as applicable for the Secure software stack. It then assigns the +dispatchers to one or more priority levels. The dispatchers then register +handlers for the priority levels at runtime. A dispatcher can register handlers +for more than one priority level. + +.. __: `Partitioning priority levels`_ + + +.. _ehf-figure: + +.. image:: ../draw.io/ehf.svg + +A priority level is *active* when a handler at that priority level is currently +executing in EL3, or has delegated the execution to a lower EL. For interrupts, +this is implicit when an interrupt is targeted and acknowledged at EL3, and the +priority of the acknowledged interrupt is used to match its registered handler. +The priority level is likewise implicitly deactivated when the interrupt +handling concludes by EOIing the interrupt. + +Non-interrupt exceptions (SErrors, for example) don't have a notion of priority. +In order for the priority arbitration to work, the |EHF| provides APIs in order +for these non-interrupt exceptions to assume a priority, and to interwork with +interrupts. Dispatchers handling such exceptions must therefore explicitly +activate and deactivate the respective priority level as and when they're +handled or delegated. + +Because priority activation and deactivation for interrupt handling is implicit +and involves GIC priority masking, it's impossible for a lower priority +interrupt to preempt a higher priority one. By extension, this means that a +lower priority dispatcher cannot preempt a higher-priority one. Priority +activation and deactivation for non-interrupt exceptions, however, has to be +explicit. The |EHF| therefore disallows for lower priority level to be activated +whilst a higher priority level is active, and would result in a panic. +Likewise, a panic would result if it's attempted to deactivate a lower priority +level when a higher priority level is active. + +In essence, priority level activation and deactivation conceptually works like a +stack—priority levels stack up in strictly increasing fashion, and need to be +unstacked in strictly the reverse order. For interrupts, the GIC ensures this is +the case; for non-interrupts, the |EHF| monitors and asserts this. See +`Transition of priority levels`_. + +Interrupt handling +------------------ + +The |EHF| is a client of *Interrupt Management Framework*, and registers the +top-level handler for interrupts that target EL3, as described in the `Interrupt +Framework Design`_ document. This has the following implications. + +- On GICv3 systems, when executing in S-EL1, pending Non-secure interrupts of + sufficient priority are signalled as FIQs, and therefore will be routed to + EL3. As a result, S-EL1 software cannot expect to handle Non-secure + interrupts at S-EL1. Essentially, this deprecates the routing mode described + as `CSS=0, TEL3=0`__. + + .. __: interrupt-framework-design.rst#el3-interrupts + + In order for S-EL1 software to handle Non-secure interrupts while having + |EHF| enabled, the dispatcher must adopt a model where Non-secure interrupts + are received at EL3, but are then `synchronously`__ handled over to S-EL1. + + .. __: interrupt-framework-design.rst#secure-payload + +- On GICv2 systems, it's required that the build option ``GICV2_G0_FOR_EL3`` is + set to ``1`` so that *Group 0* interrupts target EL3. + +- While executing in Secure world, |EHF| sets GIC Priority Mask Register to the + lowest Secure priority. This means that no Non-secure interrupts can preempt + Secure execution. See `Effect on SMC calls`_ for more details. + +As mentioned above, with |EHF|, the platform is required to partition *Group 0* +interrupts into distinct priority levels. A dispatcher that chooses to receive +interrupts can then *own* one or more priority levels, and register interrupt +handlers for them. A given priority level can be assigned to only one handler. A +dispatcher may register more than one priority level. + +Dispatchers are assigned interrupt priority levels in two steps: + +Partitioning priority levels +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Interrupts are associated to dispatchers by way of grouping and assigning +interrupts to a priority level. In other words, all interrupts that are to +target a particular dispatcher should fall in a particular priority level. For +priority assignment: + +- Of the 8 bits of priority that Arm GIC architecture permits, bit 7 must be 0 + (secure space). + +- Depending on the number of dispatchers to support, the platform must choose + to use the top *n* of the 7 remaining bits to identify and assign interrupts + to individual dispatchers. Choosing *n* bits supports up to 2\ :sup:`n` + distinct dispatchers. For example, by choosing 2 additional bits (i.e., bits + 6 and 5), the platform can partition into 4 secure priority ranges: ``0x0``, + ``0x20``, ``0x40``, and ``0x60``. See `Interrupt handling example`_. + +Note: + + The Arm GIC architecture requires that a GIC implementation that supports two + security states must implement at least 32 priority levels; i.e., at least 5 + upper bits of the 8 bits are writeable. In the scheme described above, when + choosing *n* bits for priority range assignment, the platform must ensure + that at least ``n+1`` top bits of GIC priority are writeable. + +The priority thus assigned to an interrupt is also used to determine the +priority of delegated execution in lower ELs. Delegated execution in lower EL is +associated with a priority level chosen with ``ehf_activate_priority()`` API +(described `later`__). The chosen priority level also determines the interrupts +masked while executing in a lower EL, therefore controls preemption of delegated +execution. + +.. __: `ehf-apis`_ + +The platform expresses the chosen priority levels by declaring an array of +priority level descriptors. Each entry in the array is of type +``ehf_pri_desc_t``, and declares a priority level, and shall be populated by the +``EHF_PRI_DESC()`` macro. + +Note: + + The macro ``EHF_PRI_DESC()`` installs the descriptors in the array at a + computed index, and not necessarily where the macro is placed in the array. + The size of the array might therefore be larger than what it appears to be. + The ``ARRAY_SIZE()`` macro therefore should be used to determine the size of + array. + +Finally, this array of descriptors is exposed to |EHF| via the +``EHF_REGISTER_PRIORITIES()`` macro. + +Refer to the `Interrupt handling example`_ for usage. See also: `Interrupt +Prioritisation Considerations`_. + +Programming priority +~~~~~~~~~~~~~~~~~~~~ + +The text in `Partitioning priority levels`_ only describes how the platform +expresses the required levels of priority. It however doesn't choose interrupts +nor program the required priority in GIC. + +The `Firmware Design guide`__ explains methods for configuring secure +interrupts. |EHF| requires the platform to enumerate interrupt properties (as +opposed to just numbers) of Secure interrupts. The priority of secure interrupts +must match that as determined in the `Partitioning priority levels`_ section above. + +.. __: firmware-design.rst#configuring-secure-interrupts + +See `Limitations`_, and also refer to `Interrupt handling example`_ for +illustration. + +Registering handler +------------------- + +Dispatchers register handlers for their priority levels through the following +API: + +.. code:: c + + int ehf_register_priority_handler(int pri, ehf_handler_t handler) + +The API takes two arguments: + +- The priority level for which the handler is being registered; + +- The handler to be registered. The handler must be aligned to 4 bytes. + +If a dispatcher owns more than one priority levels, it has to call the API for +each of them. + +The API will succeed, and return ``0``, only if: + +- There exists a descriptor with the priority level requested. + +- There are no handlers already registered by a previous call to the API. + +Otherwise, the API returns ``-1``. + +The interrupt handler should have the following signature: + +.. code:: c + + typedef int (*ehf_handler_t)(uint32_t intr_raw, uint32_t flags, void *handle, + void *cookie); + +The parameters are as obtained from the top-level `EL3 interrupt handler`__. + +.. __: interrupt-framework-design.rst#el3-runtime-firmware + +The `SDEI dispatcher`__, for example, expects the platform to allocate two +different priority levels—``PLAT_SDEI_CRITICAL_PRI``, and +``PLAT_SDEI_NORMAL_PRI``—and registers the same handler to handle both levels. + +.. __: sdei.rst + +Interrupt handling example +-------------------------- + +The following annotated snippet demonstrates how a platform might choose to +assign interrupts to fictitious dispatchers: + +.. code:: c + + #include <common/interrupt_props.h> + #include <drivers/arm/gic_common.h> + #include <exception_mgmt.h> + + ... + + /* + * This platform uses 2 bits for interrupt association. In total, 3 upper + * bits are in use. + * + * 7 6 5 3 0 + * .-.-.-.----------. + * |0|b|b| ..0.. | + * '-'-'-'----------' + */ + #define PLAT_PRI_BITS 2 + + /* Priorities for individual dispatchers */ + #define DISP0_PRIO 0x00 /* Not used */ + #define DISP1_PRIO 0x20 + #define DISP2_PRIO 0x40 + #define DISP3_PRIO 0x60 + + /* Install priority level descriptors for each dispatcher */ + ehf_pri_desc_t plat_exceptions[] = { + EHF_PRI_DESC(PLAT_PRI_BITS, DISP1_PRIO), + EHF_PRI_DESC(PLAT_PRI_BITS, DISP2_PRIO), + EHF_PRI_DESC(PLAT_PRI_BITS, DISP3_PRIO), + }; + + /* Expose priority descriptors to Exception Handling Framework */ + EHF_REGISTER_PRIORITIES(plat_exceptions, ARRAY_SIZE(plat_exceptions), + PLAT_PRI_BITS); + + ... + + /* List interrupt properties for GIC driver. All interrupts target EL3 */ + const interrupt_prop_t plat_interrupts[] = { + /* Dispatcher 1 owns interrupts d1_0 and d1_1, so assigns priority DISP1_PRIO */ + INTR_PROP_DESC(d1_0, DISP1_PRIO, INTR_TYPE_EL3, GIC_INTR_CFG_LEVEL), + INTR_PROP_DESC(d1_1, DISP1_PRIO, INTR_TYPE_EL3, GIC_INTR_CFG_LEVEL), + + /* Dispatcher 2 owns interrupts d2_0 and d2_1, so assigns priority DISP2_PRIO */ + INTR_PROP_DESC(d2_0, DISP2_PRIO, INTR_TYPE_EL3, GIC_INTR_CFG_LEVEL), + INTR_PROP_DESC(d2_1, DISP2_PRIO, INTR_TYPE_EL3, GIC_INTR_CFG_LEVEL), + + /* Dispatcher 3 owns interrupts d3_0 and d3_1, so assigns priority DISP3_PRIO */ + INTR_PROP_DESC(d3_0, DISP3_PRIO, INTR_TYPE_EL3, GIC_INTR_CFG_LEVEL), + INTR_PROP_DESC(d3_1, DISP3_PRIO, INTR_TYPE_EL3, GIC_INTR_CFG_LEVEL), + }; + + ... + + /* Dispatcher 1 registers its handler */ + ehf_register_priority_handler(DISP1_PRIO, disp1_handler); + + /* Dispatcher 2 registers its handler */ + ehf_register_priority_handler(DISP2_PRIO, disp2_handler); + + /* Dispatcher 3 registers its handler */ + ehf_register_priority_handler(DISP3_PRIO, disp3_handler); + + ... + +See also the `Build-time flow`_ and the `Run-time flow`_. + +Activating and Deactivating priorities +-------------------------------------- + +A priority level is said to be *active* when an exception of that priority is +being handled: for interrupts, this is implied when the interrupt is +acknowledged; for non-interrupt exceptions, such as SErrors or `SDEI explicit +dispatches`__, this has to be done via calling ``ehf_activate_priority()``. See +`Run-time flow`_. + +.. __: sdei.rst#explicit-dispatch-of-events + +Conversely, when the dispatcher has reached a logical resolution for the cause +of the exception, the corresponding priority level ought to be deactivated. As +above, for interrupts, this is implied when the interrupt is EOId in the GIC; +for other exceptions, this has to be done via calling +``ehf_deactivate_priority()``. + +Thanks to `different provisions`__ for exception delegation, there are +potentially more than one work flow for deactivation: + +.. __: `delegation-use-cases`_ + +.. _deactivation workflows: + +- The dispatcher has addressed the cause of the exception, and decided to take + no further action. In this case, the dispatcher's handler deactivates the + priority level before returning to the |EHF|. Runtime firmware, upon exit + through an ``ERET``, resumes execution before the interrupt occurred. + +- The dispatcher has to delegate the execution to lower ELs, and the cause of + the exception can be considered resolved only when the lower EL returns + signals complete (via an ``SMC``) at a future point in time. The following + sequence ensues: + + #. The dispatcher calls ``setjmp()`` to setup a jump point, and arranges to + enter a lower EL upon the next ``ERET``. + + #. Through the ensuing ``ERET`` from runtime firmware, execution is delegated + to a lower EL. + + #. The lower EL completes its execution, and signals completion via an + ``SMC``. + + #. The ``SMC`` is handled by the same dispatcher that handled the exception + previously. Noticing the conclusion of exception handling, the dispatcher + does ``longjmp()`` to resume beyond the previous jump point. + +As mentioned above, the |EHF| provides the following APIs for activating and +deactivating interrupt: + +.. _ehf-apis: + +- ``ehf_activate_priority()`` activates the supplied priority level, but only + if the current active priority is higher than the given one; otherwise + panics. Also, to prevent interruption by physical interrupts of lower + priority, the |EHF| programs the *Priority Mask Register* corresponding to + the PE to the priority being activated. Dispatchers typically only need to + call this when handling exceptions other than interrupts, and it needs to + delegate execution to a lower EL at a desired priority level. + +- ``ehf_deactivate_priority()`` deactivates a given priority, but only if the + current active priority is equal to the given one; otherwise panics. |EHF| + also restores the *Priority Mask Register* corresponding to the PE to the + priority before the call to ``ehf_activate_priority()``. Dispatchers + typically only need to call this after handling exceptions other than + interrupts. + +The calling of APIs are subject to allowed `transitions`__. See also the +`Run-time flow`_. + +.. __: `Transition of priority levels`_ + +Transition of priority levels +----------------------------- + +The |EHF| APIs ``ehf_activate_priority()`` and ``ehf_deactivate_priority()`` can +be called to transition the current priority level on a PE. A given sequence of +calls to these APIs are subject to the following conditions: + +- For activation, the |EHF| only allows for the priority to increase (i.e. + numeric value decreases); + +- For deactivation, the |EHF| only allows for the priority to decrease (i.e. + numeric value increases). Additionally, the priority being deactivated is + required to be the current priority. + +If these are violated, a panic will result. + +Effect on SMC calls +------------------- + +In general, Secure execution is regarded as more important than Non-secure +execution. As discussed elsewhere in this document, EL3 execution, and any +delegated execution thereafter, has the effect of raising GIC's priority +mask—either implicitly by acknowledging Secure interrupts, or when dispatchers +call ``ehf_activate_priority()``. As a result, Non-secure interrupts cannot +preempt any Secure execution. + +SMCs from Non-secure world are synchronous exceptions, and are mechanisms for +Non-secure world to request Secure services. They're broadly classified as +*Fast* or *Yielding* (see `SMCCC`__). + +.. __: `http://infocenter.arm.com/help/topic/com.arm.doc.den0028a/index.html` + +- *Fast* SMCs are atomic from the caller's point of view. I.e., they return + to the caller only when the Secure world has finished serving the request. + Any Non-secure interrupts that become pending meanwhile cannot preempt Secure + execution. + +- *Yielding* SMCs carry the semantics of a preemptible, lower-priority request. + A pending Non-secure interrupt can preempt Secure execution handling a + Yielding SMC. I.e., the caller might observe a Yielding SMC returning when + either: + + #. Secure world completes the request, and the caller would find ``SMC_OK`` + as the return code. + + #. A Non-secure interrupt preempts Secure execution. Non-secure interrupt is + handled, and Non-secure execution resumes after ``SMC`` instruction. + + The dispatcher handling a Yielding SMC must provide a different return code + to the Non-secure caller to distinguish the latter case. This return code, + however, is not standardised (unlike ``SMC_UNKNOWN`` or ``SMC_OK``, for + example), so will vary across dispatchers that handle the request. + +For the latter case above, dispatchers before |EHF| expect Non-secure interrupts +to be taken to S-EL1 [#irq]_, so would get a chance to populate the designated +preempted error code before yielding to Non-secure world. + +The introduction of |EHF| changes the behaviour as described in `Interrupt +handling`_. + +When |EHF| is enabled, in order to allow Non-secure interrupts to preempt +Yielding SMC handling, the dispatcher must call ``ehf_allow_ns_preemption()`` +API. The API takes one argument, the error code to be returned to the Non-secure +world upon getting preempted. + +.. [#irq] In case of GICv2, Non-secure interrupts while in S-EL1 were signalled + as IRQs, and in case of GICv3, FIQs. + +Build-time flow +--------------- + +Please refer to the `figure`__ above. + +.. __: `ehf-figure`_ + +The build-time flow involves the following steps: + +#. Platform assigns priorities by installing priority level descriptors for + individual dispatchers, as described in `Partitioning priority levels`_. + +#. Platform provides interrupt properties to GIC driver, as described in + `Programming priority`_. + +#. Dispatcher calling ``ehf_register_priority_handler()`` to register an + interrupt handler. + +Also refer to the `Interrupt handling example`_. + +Run-time flow +------------- + +.. _interrupt-flow: + +The following is an example flow for interrupts: + +#. The GIC driver, during initialization, iterates through the platform-supplied + interrupt properties (see `Programming priority`_), and configures the + interrupts. This programs the appropriate priority and group (Group 0) on + interrupts belonging to different dispatchers. + +#. The |EHF|, during its initialisation, registers a top-level interrupt handler + with the `Interrupt Management Framework`__ for EL3 interrupts. This also + results in setting the routing bits in ``SCR_EL3``. + + .. __: interrupt-framework-design.rst#el3-runtime-firmware + +#. When an interrupt belonging to a dispatcher fires, GIC raises an EL3/Group 0 + interrupt, and is taken to EL3. + +#. The top-level EL3 interrupt handler executes. The handler acknowledges the + interrupt, reads its *Running Priority*, and from that, determines the + dispatcher handler. + +#. The |EHF| programs the *Priority Mask Register* of the PE to the priority of + the interrupt received. + +#. The |EHF| marks that priority level *active*, and jumps to the dispatcher + handler. + +#. Once the dispatcher handler finishes its job, it has to immediately + *deactivate* the priority level before returning to the |EHF|. See + `deactivation workflows`_. + +.. _non-interrupt-flow: + +The following is an example flow for exceptions that targets EL3 other than +interrupt: + +#. The platform provides handlers for the specific kind of exception. + +#. The exception arrives, and the corresponding handler is executed. + +#. The handler calls ``ehf_activate_priority()`` to activate the required + priority level. This also has the effect of raising GIC priority mask, thus + preventing interrupts of lower priority from preempting the handling. The + handler may choose to do the handling entirely in EL3 or delegate to a lower + EL. + +#. Once exception handling concludes, the handler calls + ``ehf_deactivate_priority()`` to deactivate the priority level activated + earlier. This also has the effect of lowering GIC priority mask to what it + was before. + +Interrupt Prioritisation Considerations +--------------------------------------- + +The GIC priority scheme, by design, prioritises Secure interrupts over Normal +world ones. The platform further assigns relative priorities amongst Secure +dispatchers through |EHF|. + +As mentioned in `Partitioning priority levels`_, interrupts targeting distinct +dispatchers fall in distinct priority levels. Because they're routed via the +GIC, interrupt delivery to the PE is subject to GIC prioritisation rules. In +particular, when an interrupt is being handled by the PE (i.e., the interrupt is +in *Active* state), only interrupts of higher priority are signalled to the PE, +even if interrupts of same or lower priority are pending. This has the side +effect of one dispatcher being starved of interrupts by virtue of another +dispatcher handling its (higher priority) interrupts. + +The |EHF| doesn't enforce a particular prioritisation policy, but the platform +should carefully consider the assignment of priorities to dispatchers integrated +into runtime firmware. The platform should sensibly delineate priority to +various dispatchers according to their nature. In particular, dispatchers of +critical nature (RAS, for example) should be assigned higher priority than +others (SDEI, for example); and within SDEI, Critical priority SDEI should be +assigned higher priority than Normal ones. + +Limitations +----------- + +The |EHF| has the following limitations: + +- Although there could be up to 128 Secure dispatchers supported by the GIC + priority scheme, the size of descriptor array exposed with + ``EHF_REGISTER_PRIORITIES()`` macro is currently limited to 32. This serves most + expected use cases. This may be expanded in the future, should use cases + demand so. + +- The platform must ensure that the priority assigned to the dispatcher in the + exception descriptor and the programmed priority of interrupts handled by the + dispatcher match. The |EHF| cannot verify that this has been followed. + +---- + +*Copyright (c) 2018, Arm Limited and Contributors. All rights reserved.* + +.. _Interrupt Framework Design: interrupt-framework-design.rst +.. _SDEI specification: http://infocenter.arm.com/help/topic/com.arm.doc.den0054a/ARM_DEN0054A_Software_Delegated_Exception_Interface.pdf diff --git a/docs/components/firmware-update.rst b/docs/components/firmware-update.rst new file mode 100644 index 00000000..f3ad6af1 --- /dev/null +++ b/docs/components/firmware-update.rst @@ -0,0 +1,411 @@ +Trusted Firmware-A - Firmware Update design guide +================================================= + + + + +.. contents:: + +-------------- + +Introduction +------------ + +This document describes the design of the Firmware Update (FWU) feature, which +enables authenticated firmware to update firmware images from external +interfaces such as USB, UART, SD-eMMC, NAND, NOR or Ethernet to SoC Non-Volatile +memories such as NAND Flash, LPPDR2-NVM or any memory determined by the +platform. This feature functions even when the current firmware in the system +is corrupt or missing; it therefore may be used as a recovery mode. It may also +be complemented by other, higher level firmware update software. + +FWU implements a specific part of the Trusted Board Boot Requirements (TBBR) +specification, Arm DEN0006C-1. It should be used in conjunction with the +`Trusted Board Boot`_ design document, which describes the image authentication +parts of the Trusted Firmware-A (TF-A) TBBR implementation. + +Scope +~~~~~ + +This document describes the secure world FWU design. It is beyond its scope to +describe how normal world FWU images should operate. To implement normal world +FWU images, please refer to the "Non-Trusted Firmware Updater" requirements in +the TBBR. + +FWU Overview +------------ + +The FWU boot flow is primarily mediated by BL1. Since BL1 executes in ROM, and +it is usually desirable to minimize the amount of ROM code, the design allows +some parts of FWU to be implemented in other secure and normal world images. +Platform code may choose which parts are implemented in which images but the +general expectation is: + +- BL1 handles: + + - Detection and initiation of the FWU boot flow. + - Copying images from non-secure to secure memory + - FWU image authentication + - Context switching between the normal and secure world during the FWU + process. + +- Other secure world FWU images handle platform initialization required by + the FWU process. +- Normal world FWU images handle loading of firmware images from external + interfaces to non-secure memory. + +The primary requirements of the FWU feature are: + +#. Export a BL1 SMC interface to interoperate with other FWU images executing + at other Exception Levels. +#. Export a platform interface to provide FWU common code with the information + it needs, and to enable platform specific FWU functionality. See the + `Porting Guide`_ for details of this interface. + +TF-A uses abbreviated image terminology for FWU images like for other TF-A +images. An overview of this terminology can be found `here`_. + +The following diagram shows the FWU boot flow for Arm development platforms. +Arm CSS platforms like Juno have a System Control Processor (SCP), and these +use all defined FWU images. Other platforms may use a subset of these. + +|Flow Diagram| + +Image Identification +-------------------- + +Each FWU image and certificate is identified by a unique ID, defined by the +platform, which BL1 uses to fetch an image descriptor (``image_desc_t``) via a +call to ``bl1_plat_get_image_desc()``. The same ID is also used to prepare the +Chain of Trust (Refer to the `Authentication Framework Design`_ +for more information). + +The image descriptor includes the following information: + +- Executable or non-executable image. This indicates whether the normal world + is permitted to request execution of a secure world FWU image (after + authentication). Secure world certificates and non-AP images are examples + of non-executable images. +- Secure or non-secure image. This indicates whether the image is + authenticated/executed in secure or non-secure memory. +- Image base address and size. +- Image entry point configuration (an ``entry_point_info_t``). +- FWU image state. + +BL1 uses the FWU image descriptors to: + +- Validate the arguments of FWU SMCs +- Manage the state of the FWU process +- Initialize the execution state of the next FWU image. + +FWU State Machine +----------------- + +BL1 maintains state for each FWU image during FWU execution. FWU images at lower +Exception Levels raise SMCs to invoke FWU functionality in BL1, which causes +BL1 to update its FWU image state. The BL1 image states and valid state +transitions are shown in the diagram below. Note that secure images have a more +complex state machine than non-secure images. + +|FWU state machine| + +The following is a brief description of the supported states: + +- RESET: This is the initial state of every image at the start of FWU. + Authentication failure also leads to this state. A secure + image may yield to this state if it has completed execution. + It can also be reached by using ``FWU_SMC_IMAGE_RESET``. + +- COPYING: This is the state of a secure image while BL1 is copying it + in blocks from non-secure to secure memory. + +- COPIED: This is the state of a secure image when BL1 has completed + copying it to secure memory. + +- AUTHENTICATED: This is the state of an image when BL1 has successfully + authenticated it. + +- EXECUTED: This is the state of a secure, executable image when BL1 has + passed execution control to it. + +- INTERRUPTED: This is the state of a secure, executable image after it has + requested BL1 to resume normal world execution. + +BL1 SMC Interface +----------------- + +BL1_SMC_CALL_COUNT +~~~~~~~~~~~~~~~~~~ + +:: + + Arguments: + uint32_t function ID : 0x0 + + Return: + uint32_t + +This SMC returns the number of SMCs supported by BL1. + +BL1_SMC_UID +~~~~~~~~~~~ + +:: + + Arguments: + uint32_t function ID : 0x1 + + Return: + UUID : 32 bits in each of w0-w3 (or r0-r3 for AArch32 callers) + +This SMC returns the 128-bit `Universally Unique Identifier`_ for the +BL1 SMC service. + +BL1_SMC_VERSION +~~~~~~~~~~~~~~~ + +:: + + Argument: + uint32_t function ID : 0x3 + + Return: + uint32_t : Bits [31:16] Major Version + Bits [15:0] Minor Version + +This SMC returns the current version of the BL1 SMC service. + +BL1_SMC_RUN_IMAGE +~~~~~~~~~~~~~~~~~ + +:: + + Arguments: + uint32_t function ID : 0x4 + entry_point_info_t *ep_info + + Return: + void + + Pre-conditions: + if (normal world caller) synchronous exception + if (ep_info not EL3) synchronous exception + +This SMC passes execution control to an EL3 image described by the provided +``entry_point_info_t`` structure. In the normal TF-A boot flow, BL2 invokes +this SMC for BL1 to pass execution control to BL31. + +FWU_SMC_IMAGE_COPY +~~~~~~~~~~~~~~~~~~ + +:: + + Arguments: + uint32_t function ID : 0x10 + unsigned int image_id + uintptr_t image_addr + unsigned int block_size + unsigned int image_size + + Return: + int : 0 (Success) + : -ENOMEM + : -EPERM + + Pre-conditions: + if (image_id is invalid) return -EPERM + if (image_id is non-secure image) return -EPERM + if (image_id state is not (RESET or COPYING)) return -EPERM + if (secure world caller) return -EPERM + if (image_addr + block_size overflows) return -ENOMEM + if (image destination address + image_size overflows) return -ENOMEM + if (source block is in secure memory) return -ENOMEM + if (source block is not mapped into BL1) return -ENOMEM + if (image_size > free secure memory) return -ENOMEM + if (image overlaps another image) return -EPERM + +This SMC copies the secure image indicated by ``image_id`` from non-secure memory +to secure memory for later authentication. The image may be copied in a single +block or multiple blocks. In either case, the total size of the image must be +provided in ``image_size`` when invoking this SMC for the first time for each +image; it is ignored in subsequent calls (if any) for the same image. + +The ``image_addr`` and ``block_size`` specify the source memory block to copy from. +The destination address is provided by the platform code. + +If ``block_size`` is greater than the amount of remaining bytes to copy for this +image then the former is truncated to the latter. The copy operation is then +considered as complete and the FWU state machine transitions to the "COPIED" +state. If there is still more to copy, the FWU state machine stays in or +transitions to the COPYING state (depending on the previous state). + +When using multiple blocks, the source blocks do not necessarily need to be in +contiguous memory. + +Once the SMC is handled, BL1 returns from exception to the normal world caller. + +FWU_SMC_IMAGE_AUTH +~~~~~~~~~~~~~~~~~~ + +:: + + Arguments: + uint32_t function ID : 0x11 + unsigned int image_id + uintptr_t image_addr + unsigned int image_size + + Return: + int : 0 (Success) + : -ENOMEM + : -EPERM + : -EAUTH + + Pre-conditions: + if (image_id is invalid) return -EPERM + if (secure world caller) + if (image_id state is not RESET) return -EPERM + if (image_addr/image_size is not mapped into BL1) return -ENOMEM + else // normal world caller + if (image_id is secure image) + if (image_id state is not COPIED) return -EPERM + else // image_id is non-secure image + if (image_id state is not RESET) return -EPERM + if (image_addr/image_size is in secure memory) return -ENOMEM + if (image_addr/image_size not mapped into BL1) return -ENOMEM + +This SMC authenticates the image specified by ``image_id``. If the image is in the +RESET state, BL1 authenticates the image in place using the provided +``image_addr`` and ``image_size``. If the image is a secure image in the COPIED +state, BL1 authenticates the image from the secure memory that BL1 previously +copied the image into. + +BL1 returns from exception to the caller. If authentication succeeds then BL1 +sets the image state to AUTHENTICATED. If authentication fails then BL1 returns +the -EAUTH error and sets the image state back to RESET. + +FWU_SMC_IMAGE_EXECUTE +~~~~~~~~~~~~~~~~~~~~~ + +:: + + Arguments: + uint32_t function ID : 0x12 + unsigned int image_id + + Return: + int : 0 (Success) + : -EPERM + + Pre-conditions: + if (image_id is invalid) return -EPERM + if (secure world caller) return -EPERM + if (image_id is non-secure image) return -EPERM + if (image_id is non-executable image) return -EPERM + if (image_id state is not AUTHENTICATED) return -EPERM + +This SMC initiates execution of a previously authenticated image specified by +``image_id``, in the other security world to the caller. The current +implementation only supports normal world callers initiating execution of a +secure world image. + +BL1 saves the normal world caller's context, sets the secure image state to +EXECUTED, and returns from exception to the secure image. + +FWU_SMC_IMAGE_RESUME +~~~~~~~~~~~~~~~~~~~~ + +:: + + Arguments: + uint32_t function ID : 0x13 + register_t image_param + + Return: + register_t : image_param (Success) + : -EPERM + + Pre-conditions: + if (normal world caller and no INTERRUPTED secure image) return -EPERM + +This SMC resumes execution in the other security world while there is a secure +image in the EXECUTED/INTERRUPTED state. + +For normal world callers, BL1 sets the previously interrupted secure image state +to EXECUTED. For secure world callers, BL1 sets the previously executing secure +image state to INTERRUPTED. In either case, BL1 saves the calling world's +context, restores the resuming world's context and returns from exception into +the resuming world. If the call is successful then the caller provided +``image_param`` is returned to the resumed world, otherwise an error code is +returned to the caller. + +FWU_SMC_SEC_IMAGE_DONE +~~~~~~~~~~~~~~~~~~~~~~ + +:: + + Arguments: + uint32_t function ID : 0x14 + + Return: + int : 0 (Success) + : -EPERM + + Pre-conditions: + if (normal world caller) return -EPERM + +This SMC indicates completion of a previously executing secure image. + +BL1 sets the previously executing secure image state to the RESET state, +restores the normal world context and returns from exception into the normal +world. + +FWU_SMC_UPDATE_DONE +~~~~~~~~~~~~~~~~~~~ + +:: + + Arguments: + uint32_t function ID : 0x15 + register_t client_cookie + + Return: + N/A + +This SMC completes the firmware update process. BL1 calls the platform specific +function ``bl1_plat_fwu_done``, passing the optional argument ``client_cookie`` as +a ``void *``. The SMC does not return. + +FWU_SMC_IMAGE_RESET +~~~~~~~~~~~~~~~~~~~ + +:: + + Arguments: + uint32_t function ID : 0x16 + unsigned int image_id + + Return: + int : 0 (Success) + : -EPERM + + Pre-conditions: + if (secure world caller) return -EPERM + if (image in EXECUTED) return -EPERM + +This SMC sets the state of an image to RESET and zeroes the memory used by it. + +This is only allowed if the image is not being executed. + +-------------- + +*Copyright (c) 2015-2018, Arm Limited and Contributors. All rights reserved.* + +.. _Trusted Board Boot: ./trusted-board-boot.rst +.. _Porting Guide: ../getting_started/porting-guide.rst +.. _here: https://github.com/ARM-software/arm-trusted-firmware/wiki/ARM-Trusted-Firmware-Image-Terminology +.. _Authentication Framework Design: ./auth-framework.rst +.. _Universally Unique Identifier: https://tools.ietf.org/rfc/rfc4122.txt + +.. |Flow Diagram| image:: diagrams/fwu_flow.png?raw=true +.. |FWU state machine| image:: diagrams/fwu_states.png?raw=true diff --git a/docs/components/index.rst b/docs/components/index.rst new file mode 100644 index 00000000..f1904c00 --- /dev/null +++ b/docs/components/index.rst @@ -0,0 +1,18 @@ +Components +========== + +.. toctree:: + :maxdepth: 1 + :caption: Contents + :numbered: + + spd/index + arm-sip-service + exception-handling + firmware-update + platform-interrupt-controller-API + ras + romlib-design + sdei + secure-partition-manager-design + xlat-tables-lib-v2-design diff --git a/docs/components/platform-interrupt-controller-API.rst b/docs/components/platform-interrupt-controller-API.rst new file mode 100644 index 00000000..42d92be2 --- /dev/null +++ b/docs/components/platform-interrupt-controller-API.rst @@ -0,0 +1,312 @@ +Platform Interrupt Controller API documentation +=============================================== + + + +.. contents:: + +This document lists the optional platform interrupt controller API that +abstracts the runtime configuration and control of interrupt controller from the +generic code. The mandatory APIs are described in the `porting guide`__. + +.. __: ../getting_started/porting-guide.rst#interrupt-management-framework-in-bl31 + +Function: unsigned int plat_ic_get_running_priority(void); [optional] +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +:: + + Argument : void + Return : unsigned int + +This API should return the priority of the interrupt the PE is currently +servicing. This must be be called only after an interrupt has already been +acknowledged via ``plat_ic_acknowledge_interrupt``. + +In the case of Arm standard platforms using GIC, the *Running Priority Register* +is read to determine the priority of the interrupt. + +Function: int plat_ic_is_spi(unsigned int id); [optional] +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +:: + + Argument : unsigned int + Return : int + +The API should return whether the interrupt ID (first parameter) is categorized +as a Shared Peripheral Interrupt. Shared Peripheral Interrupts are typically +associated to system-wide peripherals, and these interrupts can target any PE in +the system. + +Function: int plat_ic_is_ppi(unsigned int id); [optional] +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +:: + + Argument : unsigned int + Return : int + +The API should return whether the interrupt ID (first parameter) is categorized +as a Private Peripheral Interrupt. Private Peripheral Interrupts are typically +associated with peripherals that are private to each PE. Interrupts from private +peripherals target to that PE only. + +Function: int plat_ic_is_sgi(unsigned int id); [optional] +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +:: + + Argument : unsigned int + Return : int + +The API should return whether the interrupt ID (first parameter) is categorized +as a Software Generated Interrupt. Software Generated Interrupts are raised by +explicit programming by software, and are typically used in inter-PE +communication. Secure SGIs are reserved for use by Secure world software. + +Function: unsigned int plat_ic_get_interrupt_active(unsigned int id); [optional] +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +:: + + Argument : unsigned int + Return : int + +This API should return the *active* status of the interrupt ID specified by the +first parameter, ``id``. + +In case of Arm standard platforms using GIC, the implementation of the API reads +the GIC *Set Active Register* to read and return the active status of the +interrupt. + +Function: void plat_ic_enable_interrupt(unsigned int id); [optional] +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +:: + + Argument : unsigned int + Return : void + +This API should enable the interrupt ID specified by the first parameter, +``id``. PEs in the system are expected to receive only enabled interrupts. + +In case of Arm standard platforms using GIC, the implementation of the API +inserts barrier to make memory updates visible before enabling interrupt, and +then writes to GIC *Set Enable Register* to enable the interrupt. + +Function: void plat_ic_disable_interrupt(unsigned int id); [optional] +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +:: + + Argument : unsigned int + Return : void + +This API should disable the interrupt ID specified by the first parameter, +``id``. PEs in the system are not expected to receive disabled interrupts. + +In case of Arm standard platforms using GIC, the implementation of the API +writes to GIC *Clear Enable Register* to disable the interrupt, and inserts +barrier to make memory updates visible afterwards. + +Function: void plat_ic_set_interrupt_priority(unsigned int id, unsigned int priority); [optional] +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +:: + + Argument : unsigned int + Argument : unsigned int + Return : void + +This API should set the priority of the interrupt specified by first parameter +``id`` to the value set by the second parameter ``priority``. + +In case of Arm standard platforms using GIC, the implementation of the API +writes to GIC *Priority Register* set interrupt priority. + +Function: int plat_ic_has_interrupt_type(unsigned int type); [optional] +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +:: + + Argument : unsigned int + Return : int + +This API should return whether the platform supports a given interrupt type. The +parameter ``type`` shall be one of ``INTR_TYPE_EL3``, ``INTR_TYPE_S_EL1``, or +``INTR_TYPE_NS``. + +In case of Arm standard platforms using GICv3, the implementation of the API +returns ``1`` for all interrupt types. + +In case of Arm standard platforms using GICv2, the API always return ``1`` for +``INTR_TYPE_NS``. Return value for other types depends on the value of build +option ``GICV2_G0_FOR_EL3``: + +- For interrupt type ``INTR_TYPE_EL3``: + + - When ``GICV2_G0_FOR_EL3`` is ``0``, it returns ``0``, indicating no support + for EL3 interrupts. + + - When ``GICV2_G0_FOR_EL3`` is ``1``, it returns ``1``, indicating support for + EL3 interrupts. + +- For interrupt type ``INTR_TYPE_S_EL1``: + + - When ``GICV2_G0_FOR_EL3`` is ``0``, it returns ``1``, indicating support for + Secure EL1 interrupts. + + - When ``GICV2_G0_FOR_EL3`` is ``1``, it returns ``0``, indicating no support + for Secure EL1 interrupts. + +Function: void plat_ic_set_interrupt_type(unsigned int id, unsigned int type); [optional] +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +:: + + Argument : unsigned int + Argument : unsigned int + Return : void + +This API should set the interrupt specified by first parameter ``id`` to the +type specified by second parameter ``type``. The ``type`` parameter can be +one of: + +- ``INTR_TYPE_NS``: interrupt is meant to be consumed by the Non-secure world. + +- ``INTR_TYPE_S_EL1``: interrupt is meant to be consumed by Secure EL1. + +- ``INTR_TYPE_EL3``: interrupt is meant to be consumed by EL3. + +In case of Arm standard platforms using GIC, the implementation of the API +writes to the GIC *Group Register* and *Group Modifier Register* (only GICv3) to +assign the interrupt to the right group. + +For GICv3: + +- ``INTR_TYPE_NS`` maps to Group 1 interrupt. + +- ``INTR_TYPE_S_EL1`` maps to Secure Group 1 interrupt. + +- ``INTR_TYPE_EL3`` maps to Secure Group 0 interrupt. + +For GICv2: + +- ``INTR_TYPE_NS`` maps to Group 1 interrupt. + +- When the build option ``GICV2_G0_FOR_EL3`` is set to ``0`` (the default), + ``INTR_TYPE_S_EL1`` maps to Group 0. Otherwise, ``INTR_TYPE_EL3`` maps to + Group 0 interrupt. + +Function: void plat_ic_raise_el3_sgi(int sgi_num, u_register_t target); [optional] +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +:: + + Argument : int + Argument : u_register_t + Return : void + +This API should raise an EL3 SGI. The first parameter, ``sgi_num``, specifies +the ID of the SGI. The second parameter, ``target``, must be the MPIDR of the +target PE. + +In case of Arm standard platforms using GIC, the implementation of the API +inserts barrier to make memory updates visible before raising SGI, then writes +to appropriate *SGI Register* in order to raise the EL3 SGI. + +Function: void plat_ic_set_spi_routing(unsigned int id, unsigned int routing_mode, u_register_t mpidr); [optional] +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +:: + + Argument : unsigned int + Argument : unsigned int + Argument : u_register_t + Return : void + +This API should set the routing mode of Share Peripheral Interrupt (SPI) +specified by first parameter ``id`` to that specified by the second parameter +``routing_mode``. + +The ``routing_mode`` parameter can be one of: + +- ``INTR_ROUTING_MODE_ANY`` means the interrupt can be routed to any PE in the + system. The ``mpidr`` parameter is ignored in this case. + +- ``INTR_ROUTING_MODE_PE`` means the interrupt is routed to the PE whose MPIDR + value is specified by the parameter ``mpidr``. + +In case of Arm standard platforms using GIC, the implementation of the API +writes to the GIC *Target Register* (GICv2) or *Route Register* (GICv3) to set +the routing. + +Function: void plat_ic_set_interrupt_pending(unsigned int id); [optional] +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +:: + + Argument : unsigned int + Return : void + +This API should set the interrupt specified by first parameter ``id`` to +*Pending*. + +In case of Arm standard platforms using GIC, the implementation of the API +inserts barrier to make memory updates visible before setting interrupt pending, +and writes to the GIC *Set Pending Register* to set the interrupt pending +status. + +Function: void plat_ic_clear_interrupt_pending(unsigned int id); [optional] +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +:: + + Argument : unsigned int + Return : void + +This API should clear the *Pending* status of the interrupt specified by first +parameter ``id``. + +In case of Arm standard platforms using GIC, the implementation of the API +writes to the GIC *Clear Pending Register* to clear the interrupt pending +status, and inserts barrier to make memory updates visible afterwards. + +Function: unsigned int plat_ic_set_priority_mask(unsigned int id); [optional] +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +:: + + Argument : unsigned int + Return : int + +This API should set the priority mask (first parameter) in the interrupt +controller such that only interrupts of higher priority than the supplied one +may be signalled to the PE. The API should return the current priority value +that it's overwriting. + +In case of Arm standard platforms using GIC, the implementation of the API +inserts to order memory updates before updating mask, then writes to the GIC +*Priority Mask Register*, and make sure memory updates are visible before +potential trigger due to mask update. + +Function: unsigned int plat_ic_get_interrupt_id(unsigned int raw); [optional] +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +:: + + Argument : unsigned int + Return : unsigned int + +This API should extract and return the interrupt number from the raw value +obtained by the acknowledging the interrupt (read using +``plat_ic_acknowledge_interrupt()``). If the interrupt ID is invalid, this API +should return ``INTR_ID_UNAVAILABLE``. + +In case of Arm standard platforms using GIC, the implementation of the API +masks out the interrupt ID field from the acknowledged value from GIC. + +---- + +*Copyright (c) 2017-2018, Arm Limited and Contributors. All rights reserved.* diff --git a/docs/components/ras.rst b/docs/components/ras.rst new file mode 100644 index 00000000..f329fb0b --- /dev/null +++ b/docs/components/ras.rst @@ -0,0 +1,257 @@ +RAS support in Trusted Firmware-A +================================= + + + +.. contents:: + :depth: 2 + +.. |EHF| replace:: Exception Handling Framework +.. |TF-A| replace:: Trusted Firmware-A + +This document describes |TF-A| support for Arm Reliability, Availability, and +Serviceability (RAS) extensions. RAS is a mandatory extension for Armv8.2 and +later CPUs, and also an optional extension to the base Armv8.0 architecture. + +In conjunction with the |EHF|, support for RAS extension enables firmware-first +paradigm for handling platform errors: exceptions resulting from errors are +routed to and handled in EL3. Said errors are Synchronous External Abort (SEA), +Asynchronous External Abort (signalled as SErrors), Fault Handling and Error +Recovery interrupts. The |EHF| document mentions various `error handling +use-cases`__. + +.. __: exception-handling.rst#delegation-use-cases + +For the description of Arm RAS extensions, Standard Error Records, and the +precise definition of RAS terminology, please refer to the Arm Architecture +Reference Manual. The rest of this document assumes familiarity with +architecture and terminology. + +Overview +-------- + +As mentioned above, the RAS support in |TF-A| enables routing to and handling of +exceptions resulting from platform errors in EL3. It allows the platform to +define an External Abort handler, and to register RAS nodes and interrupts. RAS +framework also provides `helpers`__ for accessing Standard Error Records as +introduced by the RAS extensions. + +.. __: `Standard Error Record helpers`_ + +The build option ``RAS_EXTENSION`` when set to ``1`` includes the RAS in run +time firmware; ``EL3_EXCEPTION_HANDLING`` and ``HANDLE_EA_EL3_FIRST`` must also +be set ``1``. + +.. _ras-figure: + +.. image:: ../draw.io/ras.svg + +See more on `Engaging the RAS framework`_. + +Platform APIs +------------- + +The RAS framework allows the platform to define handlers for External Abort, +Uncontainable Errors, Double Fault, and errors rising from EL3 execution. Please +refer to the porting guide for the `RAS platform API descriptions`__. + +.. __: ../getting_started/porting-guide.rst#external-abort-handling-and-ras-support + +Registering RAS error records +----------------------------- + +RAS nodes are components in the system capable of signalling errors to PEs +through one one of the notification mechanisms—SEAs, SErrors, or interrupts. RAS +nodes contain one or more error records, which are registers through which the +nodes advertise various properties of the signalled error. Arm recommends that +error records are implemented in the Standard Error Record format. The RAS +architecture allows for error records to be accessible via system or +memory-mapped registers. + +The platform should enumerate the error records providing for each of them: + +- A handler to probe error records for errors; +- When the probing identifies an error, a handler to handle it; +- For memory-mapped error record, its base address and size in KB; for a system + register-accessed record, the start index of the record and number of + continuous records from that index; +- Any node-specific auxiliary data. + +With this information supplied, when the run time firmware receives one of the +notification mechanisms, the RAS framework can iterate through and probe error +records for error, and invoke the appropriate handler to handle it. + +The RAS framework provides the macros to populate error record information. The +macros are versioned, and the latest version as of this writing is 1. These +macros create a structure of type ``struct err_record_info`` from its arguments, +which are later passed to probe and error handlers. + +For memory-mapped error records: + +.. code:: c + + ERR_RECORD_MEMMAP_V1(base_addr, size_num_k, probe, handler, aux) + +And, for system register ones: + +.. code:: c + + ERR_RECORD_SYSREG_V1(idx_start, num_idx, probe, handler, aux) + +The probe handler must have the following prototype: + +.. code:: c + + typedef int (*err_record_probe_t)(const struct err_record_info *info, + int *probe_data); + +The probe handler must return a non-zero value if an error was detected, or 0 +otherwise. The ``probe_data`` output parameter can be used to pass any useful +information resulting from probe to the error handler (see `below`__). For +example, it could return the index of the record. + +.. __: `Standard Error Record helpers`_ + +The error handler must have the following prototype: + +.. code:: c + + typedef int (*err_record_handler_t)(const struct err_record_info *info, + int probe_data, const struct err_handler_data *const data); + +The ``data`` constant parameter describes the various properties of the error, +including the reason for the error, exception syndrome, and also ``flags``, +``cookie``, and ``handle`` parameters from the `top-level exception handler`__. + +.. __: interrupt-framework-design.rst#el3-interrupts + +The platform is expected populate an array using the macros above, and register +the it with the RAS framework using the macro ``REGISTER_ERR_RECORD_INFO()``, +passing it the name of the array describing the records. Note that the macro +must be used in the same file where the array is defined. + +Standard Error Record helpers +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The |TF-A| RAS framework provides probe handlers for Standard Error Records, for +both memory-mapped and System Register accesses: + +.. code:: c + + int ras_err_ser_probe_memmap(const struct err_record_info *info, + int *probe_data); + + int ras_err_ser_probe_sysreg(const struct err_record_info *info, + int *probe_data); + +When the platform enumerates error records, for those records in the Standard +Error Record format, these helpers maybe used instead of rolling out their own. +Both helpers above: + +- Return non-zero value when an error is detected in a Standard Error Record; +- Set ``probe_data`` to the index of the error record upon detecting an error. + +Registering RAS interrupts +-------------------------- + +RAS nodes can signal errors to the PE by raising Fault Handling and/or Error +Recovery interrupts. For the firmware-first handling paradigm for interrupts to +work, the platform must setup and register with |EHF|. See `Interaction with +Exception Handling Framework`_. + +For each RAS interrupt, the platform has to provide structure of type ``struct +ras_interrupt``: + +- Interrupt number; +- The associated error record information (pointer to the corresponding + ``struct err_record_info``); +- Optionally, a cookie. + +The platform is expected to define an array of ``struct ras_interrupt``, and +register it with the RAS framework using the macro +``REGISTER_RAS_INTERRUPTS()``, passing it the name of the array. Note that the +macro must be used in the same file where the array is defined. + +The array of ``struct ras_interrupt`` must be sorted in the increasing order of +interrupt number. This allows for fast look of handlers in order to service RAS +interrupts. + +Double-fault handling +--------------------- + +A Double Fault condition arises when an error is signalled to the PE while +handling of a previously signalled error is still underway. When a Double Fault +condition arises, the Arm RAS extensions only require for handler to perform +orderly shutdown of the system, as recovery may be impossible. + +The RAS extensions part of Armv8.4 introduced new architectural features to deal +with Double Fault conditions, specifically, the introduction of ``NMEA`` and +``EASE`` bits to ``SCR_EL3`` register. These were introduced to assist EL3 +software which runs part of its entry/exit routines with exceptions momentarily +masked—meaning, in such systems, External Aborts/SErrors are not immediately +handled when they occur, but only after the exceptions are unmasked again. + +|TF-A|, for legacy reasons, executes entire EL3 with all exceptions unmasked. +This means that all exceptions routed to EL3 are handled immediately. |TF-A| +thus is able to detect a Double Fault conditions in software, without needing +the intended advantages of Armv8.4 Double Fault architecture extensions. + +Double faults are fatal, and terminate at the platform double fault handler, and +doesn't return. + +Engaging the RAS framework +-------------------------- + +Enabling RAS support is a platform choice constructed from three distinct, but +related, build options: + +- ``RAS_EXTENSION=1`` includes the RAS framework in the run time firmware; + +- ``EL3_EXCEPTION_HANDLING=1`` enables handling of exceptions at EL3. See + `Interaction with Exception Handling Framework`_; + +- ``HANDLE_EA_EL3_FIRST=1`` enables routing of External Aborts and SErrors to + EL3. + +The RAS support in |TF-A| introduces a default implementation of +``plat_ea_handler``, the External Abort handler in EL3. When ``RAS_EXTENSION`` +is set to ``1``, it'll first call ``ras_ea_handler()`` function, which is the +top-level RAS exception handler. ``ras_ea_handler`` is responsible for iterating +to through platform-supplied error records, probe them, and when an error is +identified, look up and invoke the corresponding error handler. + +Note that, if the platform chooses to override the ``plat_ea_handler`` function +and intend to use the RAS framework, it must explicitly call +``ras_ea_handler()`` from within. + +Similarly, for RAS interrupts, the framework defines +``ras_interrupt_handler()``. The RAS framework arranges for it to be invoked +when a RAS interrupt taken at EL3. The function bisects the platform-supplied +sorted array of interrupts to look up the error record information associated +with the interrupt number. That error handler for that record is then invoked to +handle the error. + +Interaction with Exception Handling Framework +--------------------------------------------- + +As mentioned in earlier sections, RAS framework interacts with the |EHF| to +arbitrate handling of RAS exceptions with others that are routed to EL3. This +means that the platform must partition a `priority level`__ for handling RAS +exceptions. The platform must then define the macro ``PLAT_RAS_PRI`` to the +priority level used for RAS exceptions. Platforms would typically want to +allocate the highest secure priority for RAS handling. + +.. __: exception-handling.rst#partitioning-priority-levels + +Handling of both `interrupt`__ and `non-interrupt`__ exceptions follow the +sequences outlined in the |EHF| documentation. I.e., for interrupts, the +priority management is implicit; but for non-interrupt exceptions, they're +explicit using `EHF APIs`__. + +.. __: exception-handling.rst#interrupt-flow +.. __: exception-handling.rst#non-interrupt-flow +.. __: exception-handling.rst#activating-and-deactivating-priorities + +---- + +*Copyright (c) 2018, Arm Limited and Contributors. All rights reserved.* diff --git a/docs/components/romlib-design.rst b/docs/components/romlib-design.rst new file mode 100644 index 00000000..41957214 --- /dev/null +++ b/docs/components/romlib-design.rst @@ -0,0 +1,133 @@ +Library at ROM +============== + +.. section-numbering:: + :suffix: . + +.. contents:: + +This document provides an overview of the "library at ROM" implementation in +Trusted Firmware-A (TF-A). + +Introduction +~~~~~~~~~~~~ + +The "library at ROM" feature allows platforms to build a library of functions to +be placed in ROM. This reduces SRAM usage by utilising the available space in +ROM. The "library at ROM" contains a jump table with the list of functions that +are placed in ROM. The capabilities of the "library at ROM" are: + +1. Functions can be from one or several libraries. + +2. Functions can be patched after they have been programmed into ROM. + +3. Platform-specific libraries can be placed in ROM. + +4. Functions can be accessed by one or more BL images. + +Index file +~~~~~~~~~~ + +.. image:: diagrams/romlib_design.png + :width: 600 + +Library at ROM is described by an index file with the list of functions to be +placed in ROM. The index file is platform specific and its format is: + +:: + + lib function [patch] + + lib -- Name of the library the function belongs to + function -- Name of the function to be placed in library at ROM + [patch] -- Option to patch the function + +It is also possible to insert reserved spaces in the list by using the keyword +"reserved" rather than the "lib" and "function" names as shown below: + +:: + + reserved reserved + +The reserved spaces can be used to add more functions in the future without +affecting the order and location of functions already existing in the jump +table. Also, for additional flexibility and modularity, the index file can +include other index files. + +For an index file example, refer to ``lib/romlib/jmptbl.i``. + +Wrapper functions +~~~~~~~~~~~~~~~~~ + +.. image:: diagrams/romlib_wrapper.png + :width: 600 + +When invoking a function of the "library at ROM", the calling sequence is as +follows: + +BL image --> wrapper function --> jump table entry --> library at ROM + +The index file is used to create a jump table which is placed in ROM. Then, the +wrappers refer to the jump table to call the "library at ROM" functions. The +wrappers essentially contain a branch instruction to the jump table entry +corresponding to the original function. Finally, the original function in the BL +image(s) is replaced with the wrapper function. + +The "library at ROM" contains a necessary init function that initialises the +global variables defined by the functions inside "library at ROM". + +Scripts +~~~~~~~ + +There are several scripts that generate the necessary files for the "library at +ROM" to work: + +1. ``gentbl.sh`` - Generates the jump table by parsing the index file. + +2. ``genvar.sh`` - Generates the jump table global variable (**not** the jump + table itself) with the absolute address in ROM. This global variable is, + basically, a pointer to the jump table. + +3. ``genwrappers.sh`` - Generates a wrapper function for each entry in the index + file except for the ones that contain the keyword ``patch``. The generated + wrapper file is called ``<lib>_<fn_name>.S``. + +Patching of functions in library at ROM +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The ``genwrappers.sh`` script does not generate wrappers for the entries in the +index file that contain the keyword ``patch``. Thus, it allows calling the +function from the actual library by breaking the link to the "library at ROM" +version of this function. + +The calling sequence for a patched function is as follows: + +BL image --> function + +Build library at ROM +~~~~~~~~~~~~~~~~~~~~~ + +The environment variable ``CROSS_COMPILE`` must be set as per the user guide. +In the below example the usage of ROMLIB together with mbed TLS is demonstrated +to showcase the benefits of library at ROM - it's not mandatory. + +:: + + make PLAT=fvp \ + MBEDTLS_DIR=</path/to/mbedtls/> \ + TRUSTED_BOARD_BOOT=1 GENERATE_COT=1 \ + ARM_ROTPK_LOCATION=devel_rsa \ + ROT_KEY=plat/arm/board/common/rotpk/arm_rotprivk_rsa.pem \ + BL33=</path/to/bl33.bin> \ + USE_ROMLIB=1 \ + all fip + +Known issue +----------- +When building library at ROM, a clean build is always required. This is +necessary when changes are made to the index files, e.g. adding new functions, +patching existing ones etc. + +-------------- + +*Copyright (c) 2019, Arm Limited. All rights reserved.* diff --git a/docs/components/sdei.rst b/docs/components/sdei.rst new file mode 100644 index 00000000..aca1ccb0 --- /dev/null +++ b/docs/components/sdei.rst @@ -0,0 +1,375 @@ +SDEI: Software Delegated Exception Interface +============================================ + +.. contents:: + :depth: 2 + +This document provides an overview of the SDEI dispatcher implementation in +Trusted Firmware-A (TF-A). + +Introduction +------------ + +`Software Delegated Exception Interface`_ (SDEI) is an Arm specification for +Non-secure world to register handlers with firmware to receive notifications +about system events. Firmware will first receive the system events by way of +asynchronous exceptions and, in response, arranges for the registered handler to +execute in the Non-secure EL. + +Normal world software that interacts with the SDEI dispatcher (makes SDEI +requests and receives notifications) is referred to as the *SDEI Client*. A +client receives the event notification at the registered handler even when it +was executing with exceptions masked. The list of SDEI events available to the +client are specific to the platform [#std-event]_. See also `Determining client +EL`_. + +.. _general SDEI dispatch: + +The following figure depicts a general sequence involving SDEI client executing +at EL2 and an event dispatch resulting from the triggering of a bound interrupt. +A commentary is provided below: + +.. image:: ../plantuml/sdei_general.svg + +As part of initialisation, the SDEI client binds a Non-secure interrupt [1], and +the SDEI dispatcher returns a platform dynamic event number [2]. The client then +registers a handler for that event [3], enables the event [5], and unmasks all +events on the current PE [7]. This sequence is typical of an SDEI client, but it +may involve additional SDEI calls. + +At a later point in time, when the bound interrupt triggers [9], it's trapped to +EL3. The interrupt is handed over to the SDEI dispatcher, which then arranges to +execute the registered handler [10]. The client terminates its execution with +``SDEI_EVENT_COMPLETE`` [11], following which the dispatcher resumes the +original EL2 execution [13]. Note that the SDEI interrupt remains active until +the client handler completes, at which point EL3 does EOI [12]. + +Other than events bound to interrupts (as depicted in the sequence above, SDEI +events can be explicitly dispatched in response to other exceptions, for +example, upon receiving an *SError* or *Synchronous External Abort*. See +`Explicit dispatch of events`_. + +The remainder of this document only discusses the design and implementation of +SDEI dispatcher in TF-A, and assumes that the reader is familiar with the SDEI +specification, the interfaces, and their requirements. + +.. [#std-event] Except event 0, which is defined by the SDEI specification as a + standard event. + +Defining events +--------------- + +A platform choosing to include the SDEI dispatcher must also define the events +available on the platform, along with their attributes. + +The platform is expected to provide two arrays of event descriptors: one for +private events, and another for shared events. The SDEI dispatcher provides +``SDEI_PRIVATE_EVENT()`` and ``SDEI_SHARED_EVENT()`` macros to populate the +event descriptors. Both macros take 3 arguments: + +- The event number: this must be a positive 32-bit integer. + +- For an event that has a backing interrupt, the interrupt number the event is + bound to: + + - If it's not applicable to an event, this shall be left as ``0``. + + - If the event is dynamic, this should be specified as ``SDEI_DYN_IRQ``. + +- A bit map of `Event flags`_. + +To define event 0, the macro ``SDEI_DEFINE_EVENT_0()`` should be used. This +macro takes only one parameter: an SGI number to signal other PEs. + +To define an event that's meant to be `explicitly dispatched`__ (i.e., not as a +result of receiving an SDEI interrupt), the macro ``SDEI_EXPLICIT_EVENT()`` +should be used. It accepts two parameters: + +.. __: `Explicit dispatch of events`_ + +- The event number (as above); + +- Event priority: ``SDEI_MAPF_CRITICAL`` or ``SDEI_MAPF_NORMAL``, as described + below. + +Once the event descriptor arrays are defined, they should be exported to the +SDEI dispatcher using the ``REGISTER_SDEI_MAP()`` macro, passing it the pointers +to the private and shared event descriptor arrays, respectively. Note that the +``REGISTER_SDEI_MAP()`` macro must be used in the same file where the arrays are +defined. + +Regarding event descriptors: + +- For Event 0: + + - There must be exactly one descriptor in the private array, and none in the + shared array. + + - The event should be defined using ``SDEI_DEFINE_EVENT_0()``. + + - Must be bound to a Secure SGI on the platform. + +- Explicit events should only be used in the private array. + +- Statically bound shared and private interrupts must be bound to shared and + private interrupts on the platform, respectively. See the section on + `interrupt configuration`__. + + .. __: `Configuration within Exception Handling Framework`_ + +- Both arrays should be one-dimensional. The ``REGISTER_SDEI_MAP()`` macro + takes care of replicating private events for each PE on the platform. + +- Both arrays must be sorted in the increasing order of event number. + +The SDEI specification doesn't have provisions for discovery of available events +on the platform. The list of events made available to the client, along with +their semantics, have to be communicated out of band; for example, through +Device Trees or firmware configuration tables. + +See also `Event definition example`_. + +Event flags +~~~~~~~~~~~ + +Event flags describe the properties of the event. They are bit maps that can be +``OR``\ ed to form parameters to macros that `define events`__. + +.. __: `Defining events`_ + +- ``SDEI_MAPF_DYNAMIC``: Marks the event as dynamic. Dynamic events can be + bound to (or released from) any Non-secure interrupt at runtime via the + ``SDEI_INTERRUPT_BIND`` and ``SDEI_INTERRUPT_RELEASE`` calls. + +- ``SDEI_MAPF_BOUND``: Marks the event as statically bound to an interrupt. + These events cannot be re-bound at runtime. + +- ``SDEI_MAPF_NORMAL``: Marks the event as having *Normal* priority. This is + the default priority. + +- ``SDEI_MAPF_CRITICAL``: Marks the event as having *Critical* priority. + +Event definition example +------------------------ + +.. code:: c + + static sdei_ev_map_t plat_private_sdei[] = { + /* Event 0 definition */ + SDEI_DEFINE_EVENT_0(8), + + /* PPI */ + SDEI_PRIVATE_EVENT(8, 23, SDEI_MAPF_BOUND), + + /* Dynamic private events */ + SDEI_PRIVATE_EVENT(100, SDEI_DYN_IRQ, SDEI_MAPF_DYNAMIC), + SDEI_PRIVATE_EVENT(101, SDEI_DYN_IRQ, SDEI_MAPF_DYNAMIC) + + /* Events for explicit dispatch */ + SDEI_EXPLICIT_EVENT(2000, SDEI_MAPF_NORMAL); + SDEI_EXPLICIT_EVENT(2000, SDEI_MAPF_CRITICAL); + }; + + /* Shared event mappings */ + static sdei_ev_map_t plat_shared_sdei[] = { + SDEI_SHARED_EVENT(804, 0, SDEI_MAPF_DYNAMIC), + + /* Dynamic shared events */ + SDEI_SHARED_EVENT(3000, SDEI_DYN_IRQ, SDEI_MAPF_DYNAMIC), + SDEI_SHARED_EVENT(3001, SDEI_DYN_IRQ, SDEI_MAPF_DYNAMIC) + }; + + /* Export SDEI events */ + REGISTER_SDEI_MAP(plat_private_sdei, plat_shared_sdei); + +Configuration within Exception Handling Framework +------------------------------------------------- + +The SDEI dispatcher functions alongside the Exception Handling Framework. This +means that the platform must assign priorities to both Normal and Critical SDEI +interrupts for the platform: + +- Install priority descriptors for Normal and Critical SDEI interrupts. + +- For those interrupts that are statically bound (i.e. events defined as having + the ``SDEI_MAPF_BOUND`` property), enumerate their properties for the GIC + driver to configure interrupts accordingly. + + The interrupts must be configured to target EL3. This means that they should + be configured as *Group 0*. Additionally, on GICv2 systems, the build option + ``GICV2_G0_FOR_EL3`` must be set to ``1``. + +See also `SDEI porting requirements`_. + +Determining client EL +--------------------- + +The SDEI specification requires that the *physical* SDEI client executes in the +highest Non-secure EL implemented on the system. This means that the dispatcher +will only allow SDEI calls to be made from: + +- EL2, if EL2 is implemented. The Hypervisor is expected to implement a + *virtual* SDEI dispatcher to support SDEI clients in Guest Operating Systems + executing in Non-secure EL1. + +- Non-secure EL1, if EL2 is not implemented or disabled. + +See the function ``sdei_client_el()`` in ``sdei_private.h``. + +Explicit dispatch of events +--------------------------- + +Typically, an SDEI event dispatch is caused by the PE receiving interrupts that +are bound to an SDEI event. However, there are cases where the Secure world +requires dispatch of an SDEI event as a direct or indirect result of a past +activity, such as receiving a Secure interrupt or an exception. + +The SDEI dispatcher implementation provides ``sdei_dispatch_event()`` API for +this purpose. The API has the following signature: + +:: + + int sdei_dispatch_event(int ev_num); + +The parameter ``ev_num`` is the event number to dispatch. The API returns ``0`` +on success, or ``-1`` on failure. + +The following figure depicts a scenario involving explicit dispatch of SDEI +event. A commentary is provided below: + +.. image:: ../plantuml/sdei_explicit_dispatch.svg + +As part of initialisation, the SDEI client registers a handler for a platform +event [1], enables the event [3], and unmasks the current PE [5]. Note that, +unlike in `general SDEI dispatch`_, this doesn't involve interrupt binding, as +bound or dynamic events can't be explicitly dispatched (see the section below). + +At a later point in time, a critical event [#critical-event]_ is trapped into +EL3 [7]. EL3 performs a first-level triage of the event, and a RAS component +assumes further handling [8]. The dispatch completes, but intends to involve +Non-secure world in further handling, and therefore decides to explicitly +dispatch an event [10] (which the client had already registered for [1]). The +rest of the sequence is similar to that in the `general SDEI dispatch`_: the +requested event is dispatched to the client (assuming all the conditions are +met), and when the handler completes, the preempted execution resumes. + +.. [#critical-event] Examples of critical event are *SError*, *Synchronous + External Abort*, *Fault Handling interrupt*, or *Error + Recovery interrupt* from one of RAS nodes in the system. + +Conditions for event dispatch +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +All of the following requirements must be met for the API to return ``0`` and +event to be dispatched: + +- SDEI events must be unmasked on the PE. I.e. the client must have called + ``PE_UNMASK`` beforehand. + +- Event 0 can't be dispatched. + +- The event must be declared using the ``SDEI_EXPLICIT_EVENT()`` macro + described above. + +- The event must be private to the PE. + +- The event must have been registered for and enabled. + +- A dispatch for the same event must not be outstanding. I.e. it hasn't already + been dispatched and is yet to be completed. + +- The priority of the event (either Critical or Normal, as configured by the + platform at build-time) shouldn't cause priority inversion. This means: + + - If it's of Normal priority, neither Normal nor Critical priority dispatch + must be outstanding on the PE. + + - If it's of a Critical priority, no Critical priority dispatch must be + outstanding on the PE. + +Further, the caller should be aware of the following assumptions made by the +dispatcher: + +- The caller of the API is a component running in EL3; for example, a RAS + driver. + +- The requested dispatch will be permitted by the Exception Handling Framework. + I.e. the caller must make sure that the requested dispatch has sufficient + priority so as not to cause priority level inversion within Exception + Handling Framework. + +- The caller must be prepared for the SDEI dispatcher to restore the Non-secure + context, and mark that the active context. + +- The call will block until the SDEI client completes the event (i.e. when the + client calls either ``SDEI_EVENT_COMPLETE`` or ``SDEI_COMPLETE_AND_RESUME``). + +- The caller must be prepared for this API to return failure and handle + accordingly. + +Porting requirements +-------------------- + +The porting requirements of the SDEI dispatcher are outlined in the `porting +guide`__. + +.. __: `SDEI porting requirements`_ + +Note on writing SDEI event handlers +----------------------------------- + +*This section pertains to SDEI event handlers in general, not just when using +the TF-A SDEI dispatcher.* + +The SDEI specification requires that event handlers preserve the contents of all +registers except ``x0`` to ``x17``. This has significance if event handler is +written in C: compilers typically adjust the stack frame at the beginning and +end of C functions. For example, AArch64 GCC typically produces the following +function prologue and epilogue: + +:: + + c_event_handler: + stp x29, x30, [sp,#-32]! + mov x29, sp + + ... + + bl ... + + ... + + ldp x29, x30, [sp],#32 + ret + +The register ``x29`` is used as frame pointer in the prologue. Because neither a +valid ``SDEI_EVENT_COMPLETE`` nor ``SDEI_EVENT_COMPLETE_AND_RESUME`` calls +return to the handler, the epilogue never gets executed, and registers ``x29`` +and ``x30`` (in the case above) are inadvertently corrupted. This violates the +SDEI specification, and the normal execution thereafter will result in +unexpected behaviour. + +To work this around, it's advised that the top-level event handlers are +implemented in assembly, following a similar pattern as below: + +:: + + asm_event_handler: + /* Save link register whilst maintaining stack alignment */ + stp xzr, x30, [sp, #-16]! + bl c_event_handler + + /* Restore link register */ + ldp xzr, x30, [sp], #16 + + /* Complete call */ + ldr x0, =SDEI_EVENT_COMPLETE + smc #0 + b . + +---- + +*Copyright (c) 2017-2018, Arm Limited and Contributors. All rights reserved.* + +.. _SDEI specification: http://infocenter.arm.com/help/topic/com.arm.doc.den0054a/ARM_DEN0054A_Software_Delegated_Exception_Interface.pdf +.. _SDEI porting requirements: ../getting_started/porting-guide.rst#sdei-porting-requirements diff --git a/docs/components/secure-partition-manager-design.rst b/docs/components/secure-partition-manager-design.rst new file mode 100644 index 00000000..2c32eba1 --- /dev/null +++ b/docs/components/secure-partition-manager-design.rst @@ -0,0 +1,823 @@ +******************************* +Secure Partition Manager Design +******************************* + + + +.. contents:: + +Background +========== + +In some market segments that primarily deal with client-side devices like mobile +phones, tablets, STBs and embedded devices, a Trusted OS instantiates trusted +applications to provide security services like DRM, secure payment and +authentication. The Global Platform TEE Client API specification defines the API +used by Non-secure world applications to access these services. A Trusted OS +fulfils the requirements of a security service as described above. + +Management services are typically implemented at the highest level of privilege +in the system, i.e. EL3 in Trusted Firmware-A (TF-A). The service requirements are +fulfilled by the execution environment provided by TF-A. + +The following diagram illustrates the corresponding software stack: + +|Image 1| + +In other market segments that primarily deal with server-side devices (e.g. data +centres and enterprise servers) the secure software stack typically does not +include a Global Platform Trusted OS. Security functions are accessed through +other interfaces (e.g. ACPI TCG TPM interface, UEFI runtime variable service). + +Placement of management and security functions with diverse requirements in a +privileged Exception Level (i.e. EL3 or S-EL1) makes security auditing of +firmware more difficult and does not allow isolation of unrelated services from +each other either. + +Introduction +============ + +A **Secure Partition** is a software execution environment instantiated in +S-EL0 that can be used to implement simple management and security services. +Since S-EL0 is an unprivileged Exception Level, a Secure Partition relies on +privileged firmware (i.e. TF-A) to be granted access to system and processor +resources. Essentially, it is a software sandbox in the Secure world that runs +under the control of privileged software, provides one or more services and +accesses the following system resources: + +- Memory and device regions in the system address map. + +- PE system registers. + +- A range of synchronous exceptions (e.g. SMC function identifiers). + +Note that currently TF-A only supports handling one Secure Partition. + +A Secure Partition enables TF-A to implement only the essential secure +services in EL3 and instantiate the rest in a partition in S-EL0. +Furthermore, multiple Secure Partitions can be used to isolate unrelated +services from each other. + +The following diagram illustrates the place of a Secure Partition in a typical +Armv8-A software stack. A single or multiple Secure Partitions provide secure +services to software components in the Non-secure world and other Secure +Partitions. + +|Image 2| + +The TF-A build system is responsible for including the Secure Partition image +in the FIP. During boot, BL2 includes support to authenticate and load the +Secure Partition image. A BL31 component called **Secure Partition Manager +(SPM)** is responsible for managing the partition. This is semantically +similar to a hypervisor managing a virtual machine. + +The SPM is responsible for the following actions during boot: + +- Allocate resources requested by the Secure Partition. + +- Perform architectural and system setup required by the Secure Partition to + fulfil a service request. + +- Implement a standard interface that is used for initialising a Secure + Partition. + +The SPM is responsible for the following actions during runtime: + +- Implement a standard interface that is used by a Secure Partition to fulfil + service requests. + +- Implement a standard interface that is used by the Non-secure world for + accessing the services exported by a Secure Partition. A service can be + invoked through a SMC. + +Alternatively, a partition can be viewed as a thread of execution running under +the control of the SPM. Hence common programming concepts described below are +applicable to a partition. + +Description +=========== + +The previous section introduced some general aspects of the software +architecture of a Secure Partition. This section describes the specific choices +made in the current implementation of this software architecture. Subsequent +revisions of the implementation will include a richer set of features that +enable a more flexible architecture. + +Building TF-A with Secure Partition support +------------------------------------------- + +SPM is supported on the Arm FVP exclusively at the moment. The current +implementation supports inclusion of only a single Secure Partition in which a +service always runs to completion (e.g. the requested services cannot be +preempted to give control back to the Normal world). + +It is not currently possible for BL31 to integrate SPM support and a Secure +Payload Dispatcher (SPD) at the same time; they are mutually exclusive. In the +SPM bootflow, a Secure Partition image executing at S-EL0 replaces the Secure +Payload image executing at S-EL1 (e.g. a Trusted OS). Both are referred to as +BL32. + +A working prototype of a SP has been implemented by re-purposing the EDK2 code +and tools, leveraging the concept of the *Standalone Management Mode (MM)* in +the UEFI specification (see the PI v1.6 Volume 4: Management Mode Core +Interface). This will be referred to as the *Standalone MM Secure Partition* in +the rest of this document. + +To enable SPM support in TF-A, the source code must be compiled with the build +flag ``ENABLE_SPM=1``, along with ``EL3_EXCEPTION_HANDLING=1``. On Arm +platforms the build option ``ARM_BL31_IN_DRAM`` must be set to 1. Also, the +location of the binary that contains the BL32 image +(``BL32=path/to/image.bin``) must be specified. + +First, build the Standalone MM Secure Partition. To build it, refer to the +`instructions in the EDK2 repository`_. + +Then build TF-A with SPM support and include the Standalone MM Secure Partition +image in the FIP: + +:: + + BL32=path/to/standalone/mm/sp BL33=path/to/bl33.bin \ + make PLAT=fvp ENABLE_SPM=1 ARM_BL31_IN_DRAM=1 fip all + +Describing Secure Partition resources +------------------------------------- + +TF-A exports a porting interface that enables a platform to specify the system +resources required by the Secure Partition. Some instructions are given below. +However, this interface is under development and it may change as new features +are implemented. + +- A Secure Partition is considered a BL32 image, so the same defines that apply + to BL32 images apply to a Secure Partition: ``BL32_BASE`` and ``BL32_LIMIT``. + +- The following defines are needed to allocate space for the translation tables + used by the Secure Partition: ``PLAT_SP_IMAGE_MMAP_REGIONS`` and + ``PLAT_SP_IMAGE_MAX_XLAT_TABLES``. + +- The functions ``plat_get_secure_partition_mmap()`` and + ``plat_get_secure_partition_boot_info()`` have to be implemented. The file + ``plat/arm/board/fvp/fvp_common.c`` can be used as an example. It uses the + defines in ``include/plat/arm/common/arm_spm_def.h``. + + - ``plat_get_secure_partition_mmap()`` returns an array of mmap regions that + describe the memory regions that the SPM needs to allocate for a Secure + Partition. + + - ``plat_get_secure_partition_boot_info()`` returns a + ``secure_partition_boot_info_t`` struct that is populated by the platform + with information about the memory map of the Secure Partition. + +For an example of all the changes in context, you may refer to commit +``e29efeb1b4``, in which the port for FVP was introduced. + +Accessing Secure Partition services +----------------------------------- + +The `SMC Calling Convention`_ (*Arm DEN 0028B*) describes SMCs as a conduit for +accessing services implemented in the Secure world. The ``MM_COMMUNICATE`` +interface defined in the `Management Mode Interface Specification`_ (*Arm DEN +0060A*) is used to invoke a Secure Partition service as a Fast Call. + +The mechanism used to identify a service within the partition depends on the +service implementation. It is assumed that the caller of the service will be +able to discover this mechanism through standard platform discovery mechanisms +like ACPI and Device Trees. For example, *Volume 4: Platform Initialisation +Specification v1.6. Management Mode Core Interface* specifies that a GUID is +used to identify a management mode service. A client populates the GUID in the +``EFI_MM_COMMUNICATE_HEADER``. The header is populated in the communication +buffer shared with the Secure Partition. + +A Fast Call appears to be atomic from the perspective of the caller and returns +when the requested operation has completed. A service invoked through the +``MM_COMMUNICATE`` SMC will run to completion in the partition on a given CPU. +The SPM is responsible for guaranteeing this behaviour. This means that there +can only be a single outstanding Fast Call in a partition on a given CPU. + +Exchanging data with the Secure Partition +----------------------------------------- + +The exchange of data between the Non-secure world and the partition takes place +through a shared memory region. The location of data in the shared memory area +is passed as a parameter to the ``MM_COMMUNICATE`` SMC. The shared memory area +is statically allocated by the SPM and is expected to be either implicitly known +to the Non-secure world or discovered through a platform discovery mechanism +e.g. ACPI table or device tree. It is possible for the Non-secure world to +exchange data with a partition only if it has been populated in this shared +memory area. The shared memory area is implemented as per the guidelines +specified in Section 3.2.3 of the `Management Mode Interface Specification`_ +(*Arm DEN 0060A*). + +The format of data structures used to encapsulate data in the shared memory is +agreed between the Non-secure world and the Secure Partition. For example, in +the `Management Mode Interface specification`_ (*Arm DEN 0060A*), Section 4 +describes that the communication buffer shared between the Non-secure world and +the Management Mode (MM) in the Secure world must be of the type +``EFI_MM_COMMUNICATE_HEADER``. This data structure is defined in *Volume 4: +Platform Initialisation Specification v1.6. Management Mode Core Interface*. +Any caller of a MM service will have to use the ``EFI_MM_COMMUNICATE_HEADER`` +data structure. + +Runtime model of the Secure Partition +===================================== + +This section describes how the Secure Partition interfaces with the SPM. + +Interface with SPM +------------------ + +In order to instantiate one or more secure services in the Secure Partition in +S-EL0, the SPM should define the following types of interfaces: + +- Interfaces that enable access to privileged operations from S-EL0. These + operations typically require access to system resources that are either shared + amongst multiple software components in the Secure world or cannot be directly + accessed from an unprivileged Exception Level. + +- Interfaces that establish the control path between the SPM and the Secure + Partition. + +This section describes the APIs currently exported by the SPM that enable a +Secure Partition to initialise itself and export its services in S-EL0. These +interfaces are not accessible from the Non-secure world. + +Conduit +^^^^^^^ + +The `SMC Calling Convention`_ (*Arm DEN 0028B*) specification describes the SMC +and HVC conduits for accessing firmware services and their availability +depending on the implemented Exception levels. In S-EL0, the Supervisor Call +exception (SVC) is the only architectural mechanism available for unprivileged +software to make a request for an operation implemented in privileged software. +Hence, the SVC conduit must be used by the Secure Partition to access interfaces +implemented by the SPM. + +A SVC causes an exception to be taken to S-EL1. TF-A assumes ownership of S-EL1 +and installs a simple exception vector table in S-EL1 that relays a SVC request +from a Secure Partition as a SMC request to the SPM in EL3. Upon servicing the +SMC request, Arm Trusted Firmware returns control directly to S-EL0 through an +ERET instruction. + +Calling conventions +^^^^^^^^^^^^^^^^^^^ + +The `SMC Calling Convention`_ (*Arm DEN 0028B*) specification describes the +32-bit and 64-bit calling conventions for the SMC and HVC conduits. The SVC +conduit introduces the concept of SVC32 and SVC64 calling conventions. The SVC32 +and SVC64 calling conventions are equivalent to the 32-bit (SMC32) and the +64-bit (SMC64) calling conventions respectively. + +Communication initiated by SPM +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +A service request is initiated from the SPM through an exception return +instruction (ERET) to S-EL0. Later, the Secure Partition issues an SVC +instruction to signal completion of the request. Some example use cases are +given below: + +- A request to initialise the Secure Partition during system boot. + +- A request to handle a runtime service request. + +Communication initiated by Secure Partition +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +A request is initiated from the Secure Partition by executing a SVC instruction. +An ERET instruction is used by TF-A to return to S-EL0 with the result of the +request. + +For instance, a request to perform privileged operations on behalf of a +partition (e.g. management of memory attributes in the translation tables for +the Secure EL1&0 translation regime). + +Interfaces +^^^^^^^^^^ + +The current implementation reserves function IDs for Fast Calls in the Standard +Secure Service calls range (see `SMC Calling Convention`_ (*Arm DEN 0028B*) +specification) for each API exported by the SPM. This section defines the +function prototypes for each function ID. The function IDs specify whether one +or both of the SVC32 and SVC64 calling conventions can be used to invoke the +corresponding interface. + +Secure Partition Event Management +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The Secure Partition provides an Event Management interface that is used by the +SPM to delegate service requests to the Secure Partition. The interface also +allows the Secure Partition to: + +- Register with the SPM a service that it provides. +- Indicate completion of a service request delegated by the SPM + +Miscellaneous interfaces +------------------------ + +``SPM_VERSION_AARCH32`` +^^^^^^^^^^^^^^^^^^^^^^^ + +- Description + + Returns the version of the interface exported by SPM. + +- Parameters + + - **uint32** - Function ID + + - SVC32 Version: **0x84000060** + +- Return parameters + + - **int32** - Status + + On success, the format of the value is as follows: + + - Bit [31]: Must be 0 + - Bits [30:16]: Major Version. Must be 0 for this revision of the SPM + interface. + - Bits [15:0]: Minor Version. Must be 1 for this revision of the SPM + interface. + + On error, the format of the value is as follows: + + - ``NOT_SUPPORTED``: SPM interface is not supported or not available for the + client. + +- Usage + + This function returns the version of the Secure Partition Manager + implementation. The major version is 0 and the minor version is 1. The version + number is a 31-bit unsigned integer, with the upper 15 bits denoting the major + revision, and the lower 16 bits denoting the minor revision. The following + rules apply to the version numbering: + + - Different major revision values indicate possibly incompatible functions. + + - For two revisions, A and B, for which the major revision values are + identical, if the minor revision value of revision B is greater than the + minor revision value of revision A, then every function in revision A must + work in a compatible way with revision B. However, it is possible for + revision B to have a higher function count than revision A. + +- Implementation responsibilities + + If this function returns a valid version number, all the functions that are + described subsequently must be implemented, unless it is explicitly stated + that a function is optional. + +See `Error Codes`_ for integer values that are associated with each return +code. + +Secure Partition Initialisation +------------------------------- + +The SPM is responsible for initialising the architectural execution context to +enable initialisation of a service in S-EL0. The responsibilities of the SPM are +listed below. At the end of initialisation, the partition issues a +``SP_EVENT_COMPLETE_AARCH64`` call (described later) to signal readiness for +handling requests for services implemented by the Secure Partition. The +initialisation event is executed as a Fast Call. + +Entry point invocation +^^^^^^^^^^^^^^^^^^^^^^ + +The entry point for service requests that should be handled as Fast Calls is +used as the target of the ERET instruction to start initialisation of the Secure +Partition. + +Architectural Setup +^^^^^^^^^^^^^^^^^^^ + +At cold boot, system registers accessible from S-EL0 will be in their reset +state unless otherwise specified. The SPM will perform the following +architectural setup to enable execution in S-EL0 + +MMU setup +^^^^^^^^^ + +The platform port of a Secure Partition specifies to the SPM a list of regions +that it needs access to and their attributes. The SPM validates this resource +description and initialises the Secure EL1&0 translation regime as follows. + +1. Device regions are mapped with nGnRE attributes and Execute Never + instruction access permissions. + +2. Code memory regions are mapped with RO data and Executable instruction access + permissions. + +3. Read Only data memory regions are mapped with RO data and Execute Never + instruction access permissions. + +4. Read Write data memory regions are mapped with RW data and Execute Never + instruction access permissions. + +5. If the resource description does not explicitly describe the type of memory + regions then all memory regions will be marked with Code memory region + attributes. + +6. The ``UXN`` and ``PXN`` bits are set for regions that are not executable by + S-EL0 or S-EL1. + +System Register Setup +^^^^^^^^^^^^^^^^^^^^^ + +System registers that influence software execution in S-EL0 are setup by the SPM +as follows: + +1. ``SCTLR_EL1`` + + - ``UCI=1`` + - ``EOE=0`` + - ``WXN=1`` + - ``nTWE=1`` + - ``nTWI=1`` + - ``UCT=1`` + - ``DZE=1`` + - ``I=1`` + - ``UMA=0`` + - ``SA0=1`` + - ``C=1`` + - ``A=1`` + - ``M=1`` + +2. ``CPACR_EL1`` + + - ``FPEN=b'11`` + +3. ``PSTATE`` + + - ``D,A,I,F=1`` + - ``CurrentEL=0`` (EL0) + - ``SpSel=0`` (Thread mode) + - ``NRW=0`` (AArch64) + +General Purpose Register Setup +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +SPM will invoke the entry point of a service by executing an ERET instruction. +This transition into S-EL0 is special since it is not in response to a previous +request through a SVC instruction. This is the first entry into S-EL0. The +general purpose register usage at the time of entry will be as specified in the +"Return State" column of Table 3-1 in Section 3.1 "Register use in AArch64 SMC +calls" of the `SMC Calling Convention`_ (*Arm DEN 0028B*) specification. In +addition, certain other restrictions will be applied as described below. + +1. ``SP_EL0`` + + A non-zero value will indicate that the SPM has initialised the stack pointer + for the current CPU. + + The value will be 0 otherwise. + +2. ``X4-X30`` + + The values of these registers will be 0. + +3. ``X0-X3`` + + Parameters passed by the SPM. + + - ``X0``: Virtual address of a buffer shared between EL3 and S-EL0. The + buffer will be mapped in the Secure EL1&0 translation regime with read-only + memory attributes described earlier. + + - ``X1``: Size of the buffer in bytes. + + - ``X2``: Cookie value (*IMPLEMENTATION DEFINED*). + + - ``X3``: Cookie value (*IMPLEMENTATION DEFINED*). + +Runtime Event Delegation +------------------------ + +The SPM receives requests for Secure Partition services through a synchronous +invocation (i.e. a SMC from the Non-secure world). These requests are delegated +to the partition by programming a return from the last +``SP_EVENT_COMPLETE_AARCH64`` call received from the partition. The last call +was made to signal either completion of Secure Partition initialisation or +completion of a partition service request. + +``SP_EVENT_COMPLETE_AARCH64`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +- Description + + Signal completion of the last SP service request. + +- Parameters + + - **uint32** - Function ID + + - SVC64 Version: **0xC4000061** + + - **int32** - Event Status Code + + Zero or a positive value indicates that the event was handled successfully. + The values depend upon the original event that was delegated to the Secure + partition. They are described as follows. + + - ``SUCCESS`` : Used to indicate that the Secure Partition was initialised + or a runtime request was handled successfully. + + - Any other value greater than 0 is used to pass a specific Event Status + code in response to a runtime event. + + A negative value indicates an error. The values of Event Status code depend + on the original event. + +- Return parameters + + - **int32** - Event ID/Return Code + + Zero or a positive value specifies the unique ID of the event being + delegated to the partition by the SPM. + + In the current implementation, this parameter contains the function ID of + the ``MM_COMMUNICATE`` SMC. This value indicates to the partition that an + event has been delegated to it in response to an ``MM_COMMUNICATE`` request + from the Non-secure world. + + A negative value indicates an error. The format of the value is as follows: + + - ``NOT_SUPPORTED``: Function was called from the Non-secure world. + + See `Error Codes`_ for integer values that are associated with each return + code. + + - **uint32** - Event Context Address + + Address of a buffer shared between the SPM and Secure Partition to pass + event specific information. The format of the data populated in the buffer + is implementation defined. + + The buffer is mapped in the Secure EL1&0 translation regime with read-only + memory attributes described earlier. + + For the SVC64 version, this parameter is a 64-bit Virtual Address (VA). + + For the SVC32 version, this parameter is a 32-bit Virtual Address (VA). + + - **uint32** - Event context size + + Size of the memory starting at Event Address. + + - **uint32/uint64** - Event Cookie + + This is an optional parameter. If unused its value is SBZ. + +- Usage + + This function signals to the SPM that the handling of the last event delegated + to a partition has completed. The partition is ready to handle its next event. + A return from this function is in response to the next event that will be + delegated to the partition. The return parameters describe the next event. + +- Caller responsibilities + + A Secure Partition must only call ``SP_EVENT_COMPLETE_AARCH64`` to signal + completion of a request that was delegated to it by the SPM. + +- Callee responsibilities + + When the SPM receives this call from a Secure Partition, the corresponding + syndrome information can be used to return control through an ERET + instruction, to the instruction immediately after the call in the Secure + Partition context. This syndrome information comprises of general purpose and + system register values when the call was made. + + The SPM must save this syndrome information and use it to delegate the next + event to the Secure Partition. The return parameters of this interface must + specify the properties of the event and be populated in ``X0-X3/W0-W3`` + registers. + +Secure Partition Memory Management +---------------------------------- + +A Secure Partition executes at S-EL0, which is an unprivileged Exception Level. +The SPM is responsible for enabling access to regions of memory in the system +address map from a Secure Partition. This is done by mapping these regions in +the Secure EL1&0 Translation regime with appropriate memory attributes. +Attributes refer to memory type, permission, cacheability and shareability +attributes used in the Translation tables. The definitions of these attributes +and their usage can be found in the `Armv8-A ARM`_ (*Arm DDI 0487*). + +All memory required by the Secure Partition is allocated upfront in the SPM, +even before handing over to the Secure Partition for the first time. The initial +access permissions of the memory regions are statically provided by the platform +port and should allow the Secure Partition to run its initialisation code. + +However, they might not suit the final needs of the Secure Partition because its +final memory layout might not be known until the Secure Partition initialises +itself. As the Secure Partition initialises its runtime environment it might, +for example, load dynamically some modules. For instance, a Secure Partition +could implement a loader for a standard executable file format (e.g. an PE-COFF +loader for loading executable files at runtime). These executable files will be +a part of the Secure Partition image. The location of various sections in an +executable file and their permission attributes (e.g. read-write data, read-only +data and code) will be known only when the file is loaded into memory. + +In this case, the Secure Partition needs a way to change the access permissions +of its memory regions. The SPM provides this feature through the +``SP_MEMORY_ATTRIBUTES_SET_AARCH64`` SVC interface. This interface is available +to the Secure Partition during a specific time window: from the first entry into +the Secure Partition up to the first ``SP_EVENT_COMPLETE`` call that signals the +Secure Partition has finished its initialisation. Once the initialisation is +complete, the SPM does not allow changes to the memory attributes. + +This section describes the standard SVC interface that is implemented by the SPM +to determine and change permission attributes of memory regions that belong to a +Secure Partition. + +``SP_MEMORY_ATTRIBUTES_GET_AARCH64`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +- Description + + Request the permission attributes of a memory region from S-EL0. + +- Parameters + + - **uint32** Function ID + + - SVC64 Version: **0xC4000064** + + - **uint64** Base Address + + This parameter is a 64-bit Virtual Address (VA). + + There are no alignment restrictions on the Base Address. The permission + attributes of the translation granule it lies in are returned. + +- Return parameters + + - **int32** - Memory Attributes/Return Code + + On success the format of the Return Code is as follows: + + - Bits[1:0] : Data access permission + + - b'00 : No access + - b'01 : Read-Write access + - b'10 : Reserved + - b'11 : Read-only access + + - Bit[2]: Instruction access permission + + - b'0 : Executable + - b'1 : Non-executable + + - Bit[30:3] : Reserved. SBZ. + + - Bit[31] : Must be 0 + + On failure the following error codes are returned: + + - ``INVALID_PARAMETERS``: The Secure Partition is not allowed to access the + memory region the Base Address lies in. + + - ``NOT_SUPPORTED`` : The SPM does not support retrieval of attributes of + any memory page that is accessible by the Secure Partition, or the + function was called from the Non-secure world. Also returned if it is + used after ``SP_EVENT_COMPLETE_AARCH64``. + + See `Error Codes`_ for integer values that are associated with each return + code. + +- Usage + + This function is used to request the permission attributes for S-EL0 on a + memory region accessible from a Secure Partition. The size of the memory + region is equal to the Translation Granule size used in the Secure EL1&0 + translation regime. Requests to retrieve other memory region attributes are + not currently supported. + +- Caller responsibilities + + The caller must obtain the Translation Granule Size of the Secure EL1&0 + translation regime from the SPM through an implementation defined method. + +- Callee responsibilities + + The SPM must not return the memory access controls for a page of memory that + is not accessible from a Secure Partition. + +``SP_MEMORY_ATTRIBUTES_SET_AARCH64`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +- Description + + Set the permission attributes of a memory region from S-EL0. + +- Parameters + + - **uint32** - Function ID + + - SVC64 Version: **0xC4000065** + + - **uint64** - Base Address + + This parameter is a 64-bit Virtual Address (VA). + + The alignment of the Base Address must be greater than or equal to the size + of the Translation Granule Size used in the Secure EL1&0 translation + regime. + + - **uint32** - Page count + + Number of pages starting from the Base Address whose memory attributes + should be changed. The page size is equal to the Translation Granule Size. + + - **uint32** - Memory Access Controls + + - Bits[1:0] : Data access permission + + - b'00 : No access + - b'01 : Read-Write access + - b'10 : Reserved + - b'11 : Read-only access + + - Bit[2] : Instruction access permission + + - b'0 : Executable + - b'1 : Non-executable + + - Bits[31:3] : Reserved. SBZ. + + A combination of attributes that mark the region with RW and Executable + permissions is prohibited. A request to mark a device memory region with + Executable permissions is prohibited. + +- Return parameters + + - **int32** - Return Code + + - ``SUCCESS``: The Memory Access Controls were changed successfully. + + - ``DENIED``: The SPM is servicing a request to change the attributes of a + memory region that overlaps with the region specified in this request. + + - ``INVALID_PARAMETER``: An invalid combination of Memory Access Controls + has been specified. The Base Address is not correctly aligned. The Secure + Partition is not allowed to access part or all of the memory region + specified in the call. + + - ``NO_MEMORY``: The SPM does not have memory resources to change the + attributes of the memory region in the translation tables. + + - ``NOT_SUPPORTED``: The SPM does not permit change of attributes of any + memory region that is accessible by the Secure Partition. Function was + called from the Non-secure world. Also returned if it is used after + ``SP_EVENT_COMPLETE_AARCH64``. + + See `Error Codes`_ for integer values that are associated with each return + code. + +- Usage + + This function is used to change the permission attributes for S-EL0 on a + memory region accessible from a Secure Partition. The size of the memory + region is equal to the Translation Granule size used in the Secure EL1&0 + translation regime. Requests to change other memory region attributes are not + currently supported. + + This function is only available at boot time. This interface is revoked after + the Secure Partition sends the first ``SP_EVENT_COMPLETE_AARCH64`` to signal + that it is initialised and ready to receive run-time requests. + +- Caller responsibilities + + The caller must obtain the Translation Granule Size of the Secure EL1&0 + translation regime from the SPM through an implementation defined method. + +- Callee responsibilities + + The SPM must preserve the original memory access controls of the region of + memory in case of an unsuccessful call. The SPM must preserve the consistency + of the S-EL1 translation regime if this function is called on different PEs + concurrently and the memory regions specified overlap. + +Error Codes +----------- + +.. csv-table:: + :header: "Name", "Value" + + ``SUCCESS``,0 + ``NOT_SUPPORTED``,-1 + ``INVALID_PARAMETER``,-2 + ``DENIED``,-3 + ``NO_MEMORY``,-5 + ``NOT_PRESENT``,-7 + +-------------- + +*Copyright (c) 2017-2018, Arm Limited and Contributors. All rights reserved.* + +.. _Armv8-A ARM: https://developer.arm.com/docs/ddi0487/latest/arm-architecture-reference-manual-armv8-for-armv8-a-architecture-profile +.. _instructions in the EDK2 repository: https://github.com/tianocore/edk2-staging/blob/AArch64StandaloneMm/HowtoBuild.MD +.. _Management Mode Interface Specification: http://infocenter.arm.com/help/topic/com.arm.doc.den0060a/DEN0060A_ARM_MM_Interface_Specification.pdf +.. _SDEI Specification: http://infocenter.arm.com/help/topic/com.arm.doc.den0054a/ARM_DEN0054A_Software_Delegated_Exception_Interface.pdf +.. _SMC Calling Convention: http://infocenter.arm.com/help/topic/com.arm.doc.den0028b/ARM_DEN0028B_SMC_Calling_Convention.pdf + +.. |Image 1| image:: ../diagrams/secure_sw_stack_tos.png +.. |Image 2| image:: ../diagrams/secure_sw_stack_sp.png diff --git a/docs/components/spd/index.rst b/docs/components/spd/index.rst new file mode 100644 index 00000000..e03bfe33 --- /dev/null +++ b/docs/components/spd/index.rst @@ -0,0 +1,11 @@ +Secure Payload Dispatcher (SPD) +=============================== + +.. toctree:: + :maxdepth: 1 + :caption: Contents + :numbered: + + optee-dispatcher + tlk-dispatcher + trusty-dispatcher diff --git a/docs/components/spd/optee-dispatcher.rst b/docs/components/spd/optee-dispatcher.rst new file mode 100644 index 00000000..63baccc5 --- /dev/null +++ b/docs/components/spd/optee-dispatcher.rst @@ -0,0 +1,14 @@ +OP-TEE Dispatcher +================= + +`OP-TEE OS`_ is a Trusted OS running as Secure EL1. + +To build and execute OP-TEE follow the instructions at +`OP-TEE build.git`_ + +-------------- + +*Copyright (c) 2014-2018, Arm Limited and Contributors. All rights reserved.* + +.. _OP-TEE OS: https://github.com/OP-TEE/build +.. _OP-TEE build.git: https://github.com/OP-TEE/build diff --git a/docs/components/spd/tlk-dispatcher.rst b/docs/components/spd/tlk-dispatcher.rst new file mode 100644 index 00000000..90af5faf --- /dev/null +++ b/docs/components/spd/tlk-dispatcher.rst @@ -0,0 +1,76 @@ +Trusted Little Kernel (TLK) Dispatcher +====================================== + +TLK dispatcher (TLK-D) adds support for NVIDIA's Trusted Little Kernel (TLK) +to work with Trusted Firmware-A (TF-A). TLK-D can be compiled by including it +in the platform's makefile. TLK is primarily meant to work with Tegra SoCs, +so while TF-A only supports TLK on Tegra, the dispatcher code can only be +compiled for other platforms. + +In order to compile TLK-D, we need a BL32 image to be present. Since, TLKD +just needs to compile, any BL32 image would do. To use TLK as the BL32, please +refer to the "Build TLK" section. + +Once a BL32 is ready, TLKD can be included in the image by adding "SPD=tlkd" +to the build command. + +Trusted Little Kernel (TLK) +=========================== + +TLK is a Trusted OS running as Secure EL1. It is a Free Open Source Software +(FOSS) release of the NVIDIA® Trusted Little Kernel (TLK) technology, which +extends technology made available with the development of the Little Kernel (LK). +You can download the LK modular embedded preemptive kernel for use on Arm, +x86, and AVR32 systems from https://github.com/travisg/lk + +NVIDIA implemented its Trusted Little Kernel (TLK) technology, designed as a +free and open-source trusted execution environment (OTE). + +TLK features include: + +• Small, pre-emptive kernel +• Supports multi-threading, IPCs, and thread scheduling +• Added TrustZone features +• Added Secure Storage +• Under MIT/FreeBSD license + +NVIDIA extensions to Little Kernel (LK) include: + +• User mode +• Address-space separation for TAs +• TLK Client Application (CA) library +• TLK TA library +• Crypto library (encrypt/decrypt, key handling) via OpenSSL +• Linux kernel driver +• Cortex A9/A15 support +• Power Management +• TrustZone memory carve-out (reconfigurable) +• Page table management +• Debugging support over UART (USB planned) + +TLK is hosted by NVIDIA on http://nv-tegra.nvidia.com under the +3rdparty/ote\_partner/tlk.git repository. Detailed information about +TLK and OTE can be found in the Tegra\_BSP\_for\_Android\_TLK\_FOSS\_Reference.pdf +manual located under the "documentation" directory\_. + +Build TLK +========= + +To build and execute TLK, follow the instructions from "Building a TLK Device" +section from Tegra\_BSP\_for\_Android\_TLK\_FOSS\_Reference.pdf manual. + +Input parameters to TLK +======================= + +TLK expects the TZDRAM size and a structure containing the boot arguments. BL2 +passes this information to the EL3 software as members of the bl32\_ep\_info +struct, where bl32\_ep\_info is part of bl31\_params\_t (passed by BL2 in X0) + +Example: +-------- + +:: + + bl32_ep_info->args.arg0 = TZDRAM size available for BL32 + bl32_ep_info->args.arg1 = unused (used only on Armv7-A) + bl32_ep_info->args.arg2 = pointer to boot args diff --git a/docs/components/spd/trusty-dispatcher.rst b/docs/components/spd/trusty-dispatcher.rst new file mode 100644 index 00000000..be085705 --- /dev/null +++ b/docs/components/spd/trusty-dispatcher.rst @@ -0,0 +1,32 @@ +Trusty Dispatcher +================= + +Trusty is a a set of software components, supporting a Trusted Execution +Environment (TEE) on mobile devices, published and maintained by Google. + +Detailed information and build instructions can be found on the Android +Open Source Project (AOSP) webpage for Trusty hosted at +https://source.android.com/security/trusty + +Boot parameters +=============== + +Custom boot parameters can be passed to Trusty by providing a platform +specific function: + +.. code:: c + + void plat_trusty_set_boot_args(aapcs64_params_t *args) + +If this function is provided ``args->arg0`` must be set to the memory +size allocated to trusty. If the platform does not provide this +function, but defines ``TSP_SEC_MEM_SIZE``, a default implementation +will pass the memory size from ``TSP_SEC_MEM_SIZE``. ``args->arg1`` +can be set to a platform specific parameter block, and ``args->arg2`` +should then be set to the size of that block. + +Supported platforms +=================== + +Out of all the platforms supported by Trusted Firmware-A, Trusty is only +verified and supported by NVIDIA's Tegra SoCs. diff --git a/docs/components/xlat-tables-lib-v2-design.rst b/docs/components/xlat-tables-lib-v2-design.rst new file mode 100644 index 00000000..d55f010a --- /dev/null +++ b/docs/components/xlat-tables-lib-v2-design.rst @@ -0,0 +1,427 @@ +Translation Tables Library Design +================================= + + + + +.. contents:: + + +This document describes the design of the translation tables library (version 2) +used by Trusted Firmware-A (TF-A). This library provides APIs to create page +tables based on a description of the memory layout, as well as setting up system +registers related to the Memory Management Unit (MMU) and performing the +required Translation Lookaside Buffer (TLB) maintenance operations. + +More specifically, some use cases that this library aims to support are: + +#. Statically allocate translation tables and populate them (at run-time) based + on a description of the memory layout. The memory layout is typically + provided by the platform port as a list of memory regions; + +#. Support for generating translation tables pertaining to a different + translation regime than the exception level the library code is executing at; + +#. Support for dynamic mapping and unmapping of regions, even while the MMU is + on. This can be used to temporarily map some memory regions and unmap them + later on when no longer needed; + +#. Support for non-identity virtual to physical mappings to compress the virtual + address space; + +#. Support for changing memory attributes of memory regions at run-time. + + +About version 1 and version 2 +----------------------------- + +This document focuses on version 2 of the library, whose sources are available +in the `lib/xlat_tables_v2`_ directory. Version 1 of the library can still be +found in `lib/xlat_tables`_ directory but it is less flexible and doesn't +support dynamic mapping. Although potential bug fixes will be applied to both +versions, future features enhancements will focus on version 2 and might not be +back-ported to version 1. Therefore, it is recommended to use version 2, +especially for new platform ports. + +However, please note that version 2 is still in active development and is not +considered stable yet. Hence, compatibility breaks might be introduced. + +From this point onwards, this document will implicitly refer to version 2 of the +library. + + +Design concepts and interfaces +------------------------------ + +This section presents some of the key concepts and data structures used in the +translation tables library. + +`mmap` regions +~~~~~~~~~~~~~~ + +An ``mmap_region`` is an abstract, concise way to represent a memory region to +map. It is one of the key interfaces to the library. It is identified by: + +- its physical base address; +- its virtual base address; +- its size; +- its attributes; +- its mapping granularity (optional). + +See the ``struct mmap_region`` type in `xlat_tables_v2.h`_. + +The user usually provides a list of such mmap regions to map and lets the +library transpose that in a set of translation tables. As a result, the library +might create new translation tables, update or split existing ones. + +The region attributes specify the type of memory (for example device or cached +normal memory) as well as the memory access permissions (read-only or +read-write, executable or not, secure or non-secure, and so on). In the case of +the EL1&0 translation regime, the attributes also specify whether the region is +a User region (EL0) or Privileged region (EL1). See the ``MT_xxx`` definitions +in `xlat_tables_v2.h`_. Note that for the EL1&0 translation regime the Execute +Never attribute is set simultaneously for both EL1 and EL0. + +The granularity controls the translation table level to go down to when mapping +the region. For example, assuming the MMU has been configured to use a 4KB +granule size, the library might map a 2MB memory region using either of the two +following options: + +- using a single level-2 translation table entry; +- using a level-2 intermediate entry to a level-3 translation table (which + contains 512 entries, each mapping 4KB). + +The first solution potentially requires less translation tables, hence +potentially less memory. However, if part of this 2MB region is later remapped +with different memory attributes, the library might need to split the existing +page tables to refine the mappings. If a single level-2 entry has been used +here, a level-3 table will need to be allocated on the fly and the level-2 +modified to point to this new level-3 table. This has a performance cost at +run-time. + +If the user knows upfront that such a remapping operation is likely to happen +then they might enforce a 4KB mapping granularity for this 2MB region from the +beginning; remapping some of these 4KB pages on the fly then becomes a +lightweight operation. + +The region's granularity is an optional field; if it is not specified the +library will choose the mapping granularity for this region as it sees fit (more +details can be found in `The memory mapping algorithm`_ section below). + +Translation Context +~~~~~~~~~~~~~~~~~~~ + +The library can create or modify translation tables pertaining to a different +translation regime than the exception level the library code is executing at. +For example, the library might be used by EL3 software (for instance BL31) to +create translation tables pertaining to the S-EL1&0 translation regime. + +This flexibility comes from the use of *translation contexts*. A *translation +context* constitutes the superset of information used by the library to track +the status of a set of translation tables for a given translation regime. + +The library internally allocates a default translation context, which pertains +to the translation regime of the current exception level. Additional contexts +may be explicitly allocated and initialized using the +``REGISTER_XLAT_CONTEXT()`` macro. Separate APIs are provided to act either on +the default translation context or on an alternative one. + +To register a translation context, the user must provide the library with the +following information: + +* A name. + + The resulting translation context variable will be called after this name, to + which ``_xlat_ctx`` is appended. For example, if the macro name parameter is + ``foo``, the context variable name will be ``foo_xlat_ctx``. + +* The maximum number of `mmap` regions to map. + + Should account for both static and dynamic regions, if applicable. + +* The number of sub-translation tables to allocate. + + Number of translation tables to statically allocate for this context, + excluding the initial lookup level translation table, which is always + allocated. For example, if the initial lookup level is 1, this parameter would + specify the number of level-2 and level-3 translation tables to pre-allocate + for this context. + +* The size of the virtual address space. + + Size in bytes of the virtual address space to map using this context. This + will incidentally determine the number of entries in the initial lookup level + translation table : the library will allocate as many entries as is required + to map the entire virtual address space. + +* The size of the physical address space. + + Size in bytes of the physical address space to map using this context. + +The default translation context is internally initialized using information +coming (for the most part) from platform-specific defines: + +- name: hard-coded to ``tf`` ; hence the name of the default context variable is + ``tf_xlat_ctx``; +- number of `mmap` regions: ``MAX_MMAP_REGIONS``; +- number of sub-translation tables: ``MAX_XLAT_TABLES``; +- size of the virtual address space: ``PLAT_VIRT_ADDR_SPACE_SIZE``; +- size of the physical address space: ``PLAT_PHY_ADDR_SPACE_SIZE``. + +Please refer to the `Porting Guide`_ for more details about these macros. + + +Static and dynamic memory regions +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The library optionally supports dynamic memory mapping. This feature may be +enabled using the ``PLAT_XLAT_TABLES_DYNAMIC`` platform build flag. + +When dynamic memory mapping is enabled, the library categorises mmap regions as +*static* or *dynamic*. + +- *Static regions* are fixed for the lifetime of the system. They can only be + added early on, before the translation tables are created and populated. They + cannot be removed afterwards. + +- *Dynamic regions* can be added or removed any time. + +When the dynamic memory mapping feature is disabled, only static regions exist. + +The dynamic memory mapping feature may be used to map and unmap transient memory +areas. This is useful when the user needs to access some memory for a fixed +period of time, after which the memory may be discarded and reclaimed. For +example, a memory region that is only required at boot time while the system is +initializing, or to temporarily share a memory buffer between the normal world +and trusted world. Note that it is up to the caller to ensure that these regions +are not accessed concurrently while the regions are being added or removed. + +Although this feature provides some level of dynamic memory allocation, this +does not allow dynamically allocating an arbitrary amount of memory at an +arbitrary memory location. The user is still required to declare at compile-time +the limits of these allocations ; the library will deny any mapping request that +does not fit within this pre-allocated pool of memory. + + +Library APIs +------------ + +The external APIs exposed by this library are declared and documented in the +`xlat_tables_v2.h`_ header file. This should be the reference point for +getting information about the usage of the different APIs this library +provides. This section just provides some extra details and clarifications. + +Although the ``mmap_region`` structure is a publicly visible type, it is not +recommended to populate these structures by hand. Instead, wherever APIs expect +function arguments of type ``mmap_region_t``, these should be constructed using +the ``MAP_REGION*()`` family of helper macros. This is to limit the risk of +compatibility breaks, should the ``mmap_region`` structure type evolve in the +future. + +The ``MAP_REGION()`` and ``MAP_REGION_FLAT()`` macros do not allow specifying a +mapping granularity, which leaves the library implementation free to choose +it. However, in cases where a specific granularity is required, the +``MAP_REGION2()`` macro might be used instead. + +As explained earlier in this document, when the dynamic mapping feature is +disabled, there is no notion of dynamic regions. Conceptually, there are only +static regions. For this reason (and to retain backward compatibility with the +version 1 of the library), the APIs that map static regions do not embed the +word *static* in their functions names (for example ``mmap_add_region()``), in +contrast with the dynamic regions APIs (for example +``mmap_add_dynamic_region()``). + +Although the definition of static and dynamic regions is not based on the state +of the MMU, the two are still related in some way. Static regions can only be +added before ``init_xlat_tables()`` is called and ``init_xlat_tables()`` must be +called while the MMU is still off. As a result, static regions cannot be added +once the MMU has been enabled. Dynamic regions can be added with the MMU on or +off. In practice, the usual call flow would look like this: + +#. The MMU is initially off. + +#. Add some static regions, add some dynamic regions. + +#. Initialize translation tables based on the list of mmap regions (using one of + the ``init_xlat_tables*()`` APIs). + +#. At this point, it is no longer possible to add static regions. Dynamic + regions can still be added or removed. + +#. Enable the MMU. + +#. Dynamic regions can continue to be added or removed. + +Because static regions are added early on at boot time and are all in the +control of the platform initialization code, the ``mmap_add*()`` family of APIs +are not expected to fail. They do not return any error code. + +Nonetheless, these APIs will check upfront whether the region can be +successfully added before updating the translation context structure. If the +library detects that there is insufficient memory to meet the request, or that +the new region will overlap another one in an invalid way, or if any other +unexpected error is encountered, they will print an error message on the UART. +Additionally, when asserts are enabled (typically in debug builds), an assertion +will be triggered. Otherwise, the function call will just return straight away, +without adding the offending memory region. + + +Library limitations +------------------- + +Dynamic regions are not allowed to overlap each other. Static regions are +allowed to overlap as long as one of them is fully contained inside the other +one. This is allowed for backwards compatibility with the previous behaviour in +the version 1 of the library. + + +Implementation details +---------------------- + +Code structure +~~~~~~~~~~~~~~ + +The library is divided into 4 modules: + +- **Core module** + + Provides the main functionality of the library, such as the initialization of + translation tables contexts and mapping/unmapping memory regions. This module + provides functions such as ``mmap_add_region_ctx`` that let the caller specify + the translation tables context affected by them. + + See `xlat_tables_core.c`_. + +- **Active context module** + + Instantiates the context that is used by the current BL image and provides + helpers to manipulate it, abstracting it from the rest of the code. + This module provides functions such as ``mmap_add_region``, that directly + affect the BL image using them. + + See `xlat_tables_context.c`_. + +- **Utilities module** + + Provides additional functionality like debug print of the current state of the + translation tables and helpers to query memory attributes and to modify them. + + See `xlat_tables_utils.c`_. + +- **Architectural module** + + Provides functions that are dependent on the current execution state + (AArch32/AArch64), such as the functions used for TLB invalidation, setup the + MMU, or calculate the Physical Address Space size. They do not need a + translation context to work on. + + See `aarch32/xlat_tables_arch.c`_ and `aarch64/xlat_tables_arch.c`_. + +From mmap regions to translation tables +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +A translation context contains a list of ``mmap_region_t``, which holds the +information of all the regions that are mapped at any given time. Whenever there +is a request to map (resp. unmap) a memory region, it is added to (resp. removed +from) the ``mmap_region_t`` list. + +The mmap regions list is a conceptual way to represent the memory layout. At +some point, the library has to convert this information into actual translation +tables to program into the MMU. + +Before the ``init_xlat_tables()`` API is called, the library only acts on the +mmap regions list. Adding a static or dynamic region at this point through one +of the ``mmap_add*()`` APIs does not affect the translation tables in any way, +they only get registered in the internal mmap region list. It is only when the +user calls the ``init_xlat_tables()`` that the translation tables are populated +in memory based on the list of mmap regions registered so far. This is an +optimization that allows creation of the initial set of translation tables in +one go, rather than having to edit them every time while the MMU is disabled. + +After the ``init_xlat_tables()`` API has been called, only dynamic regions can +be added. Changes to the translation tables (as well as the mmap regions list) +will take effect immediately. + +The memory mapping algorithm +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The mapping function is implemented as a recursive algorithm. It is however +bound by the level of depth of the translation tables (the Armv8-A architecture +allows up to 4 lookup levels). + +By default [#granularity-ref]_, the algorithm will attempt to minimize the +number of translation tables created to satisfy the user's request. It will +favour mapping a region using the biggest possible blocks, only creating a +sub-table if it is strictly necessary. This is to reduce the memory footprint of +the firmware. + +The most common reason for needing a sub-table is when a specific mapping +requires a finer granularity. Misaligned regions also require a finer +granularity than what the user may had originally expected, using a lot more +memory than expected. The reason is that all levels of translation are +restricted to address translations of the same granularity as the size of the +blocks of that level. For example, for a 4 KiB page size, a level 2 block entry +can only translate up to a granularity of 2 MiB. If the Physical Address is not +aligned to 2 MiB then additional level 3 tables are also needed. + +Note that not every translation level allows any type of descriptor. Depending +on the page size, levels 0 and 1 of translation may only allow table +descriptors. If a block entry could be able to describe a translation, but that +level does not allow block descriptors, a table descriptor will have to be used +instead, as well as additional tables at the next level. + +|Alignment Example| + +The mmap regions are sorted in a way that simplifies the code that maps +them. Even though this ordering is only strictly needed for overlapping static +regions, it must also be applied for dynamic regions to maintain a consistent +order of all regions at all times. As each new region is mapped, existing +entries in the translation tables are checked to ensure consistency. Please +refer to the comments in the source code of the core module for more details +about the sorting algorithm in use. + +.. [#granularity-ref] That is, when mmap regions do not enforce their mapping + granularity. + +TLB maintenance operations +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The library takes care of performing TLB maintenance operations when required. +For example, when the user requests removing a dynamic region, the library +invalidates all TLB entries associated to that region to ensure that these +changes are visible to subsequent execution, including speculative execution, +that uses the changed translation table entries. + +A counter-example is the initialization of translation tables. In this case, +explicit TLB maintenance is not required. The Armv8-A architecture guarantees +that all TLBs are disabled from reset and their contents have no effect on +address translation at reset [#tlb-reset-ref]_. Therefore, the TLBs invalidation +is deferred to the ``enable_mmu*()`` family of functions, just before the MMU is +turned on. + +TLB invalidation is not required when adding dynamic regions either. Dynamic +regions are not allowed to overlap existing memory region. Therefore, if the +dynamic mapping request is deemed legitimate, it automatically concerns memory +that was not mapped in this translation regime and the library will have +initialized its corresponding translation table entry to an invalid +descriptor. Given that the TLBs are not architecturally permitted to hold any +invalid translation table entry [#tlb-no-invalid-entry]_, this means that this +mapping cannot be cached in the TLBs. + +.. [#tlb-reset-ref] See section D4.9 `Translation Lookaside Buffers (TLBs)`, subsection `TLB behavior at reset` in Armv8-A, rev C.a. +.. [#tlb-no-invalid-entry] See section D4.10.1 `General TLB maintenance requirements` in Armv8-A, rev C.a. + +-------------- + +*Copyright (c) 2017-2018, Arm Limited and Contributors. All rights reserved.* + +.. _lib/xlat_tables_v2: ../../lib/xlat_tables_v2 +.. _lib/xlat_tables: ../../lib/xlat_tables +.. _xlat_tables_v2.h: ../../include/lib/xlat_tables/xlat_tables_v2.h +.. _xlat_tables_context.c: ../../lib/xlat_tables_v2/xlat_tables_context.c +.. _xlat_tables_core.c: ../../lib/xlat_tables_v2/xlat_tables_core.c +.. _xlat_tables_utils.c: ../../lib/xlat_tables_v2/xlat_tables_utils.c +.. _aarch32/xlat_tables_arch.c: ../../lib/xlat_tables_v2/aarch32/xlat_tables_arch.c +.. _aarch64/xlat_tables_arch.c: ../../lib/xlat_tables_v2/aarch64/xlat_tables_arch.c +.. _Porting Guide: ../getting_started/porting-guide.rst +.. |Alignment Example| image:: ../diagrams/xlat_align.png?raw=true |