1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021 |
- Interrupt Management Framework
- ==============================
- This framework is responsible for managing interrupts routed to EL3. It also
- allows EL3 software to configure the interrupt routing behavior. Its main
- objective is to implement the following two requirements.
- #. It should be possible to route interrupts meant to be handled by secure
- software (Secure interrupts) to EL3, when execution is in non-secure state
- (normal world). The framework should then take care of handing control of
- the interrupt to either software in EL3 or Secure-EL1 depending upon the
- software configuration and the GIC implementation. This requirement ensures
- that secure interrupts are under the control of the secure software with
- respect to their delivery and handling without the possibility of
- intervention from non-secure software.
- #. It should be possible to route interrupts meant to be handled by
- non-secure software (Non-secure interrupts) to the last executed exception
- level in the normal world when the execution is in secure world at
- exception levels lower than EL3. This could be done with or without the
- knowledge of software executing in Secure-EL1/Secure-EL0. The choice of
- approach should be governed by the secure software. This requirement
- ensures that non-secure software is able to execute in tandem with the
- secure software without overriding it.
- Concepts
- --------
- Interrupt types
- ~~~~~~~~~~~~~~~
- The framework categorises an interrupt to be one of the following depending upon
- the exception level(s) it is handled in.
- #. Secure EL1 interrupt. This type of interrupt can be routed to EL3 or
- Secure-EL1 depending upon the security state of the current execution
- context. It is always handled in Secure-EL1.
- #. Non-secure interrupt. This type of interrupt can be routed to EL3,
- Secure-EL1, Non-secure EL1 or EL2 depending upon the security state of the
- current execution context. It is always handled in either Non-secure EL1
- or EL2.
- #. EL3 interrupt. This type of interrupt can be routed to EL3 or Secure-EL1
- depending upon the security state of the current execution context. It is
- always handled in EL3.
- The following constants define the various interrupt types in the framework
- implementation.
- .. code:: c
- #define INTR_TYPE_S_EL1 0
- #define INTR_TYPE_EL3 1
- #define INTR_TYPE_NS 2
- Routing model
- ~~~~~~~~~~~~~
- A type of interrupt can be either generated as an FIQ or an IRQ. The target
- exception level of an interrupt type is configured through the FIQ and IRQ bits
- in the Secure Configuration Register at EL3 (``SCR_EL3.FIQ`` and ``SCR_EL3.IRQ``
- bits). When ``SCR_EL3.FIQ``\ =1, FIQs are routed to EL3. Otherwise they are routed
- to the First Exception Level (FEL) capable of handling interrupts. When
- ``SCR_EL3.IRQ``\ =1, IRQs are routed to EL3. Otherwise they are routed to the
- FEL. This register is configured independently by EL3 software for each security
- state prior to entry into a lower exception level in that security state.
- A routing model for a type of interrupt (generated as FIQ or IRQ) is defined as
- its target exception level for each security state. It is represented by a
- single bit for each security state. A value of ``0`` means that the interrupt
- should be routed to the FEL. A value of ``1`` means that the interrupt should be
- routed to EL3. A routing model is applicable only when execution is not in EL3.
- The default routing model for an interrupt type is to route it to the FEL in
- either security state.
- Valid routing models
- ~~~~~~~~~~~~~~~~~~~~
- The framework considers certain routing models for each type of interrupt to be
- incorrect as they conflict with the requirements mentioned in Section 1. The
- following sub-sections describe all the possible routing models and specify
- which ones are valid or invalid. EL3 interrupts are currently supported only
- for GIC version 3.0 (Arm GICv3) and only the Secure-EL1 and Non-secure interrupt
- types are supported for GIC version 2.0 (Arm GICv2) (see `Assumptions in
- Interrupt Management Framework`_). The terminology used in the following
- sub-sections is explained below.
- #. **CSS**. Current Security State. ``0`` when secure and ``1`` when non-secure
- #. **TEL3**. Target Exception Level 3. ``0`` when targeted to the FEL. ``1`` when
- targeted to EL3.
- Secure-EL1 interrupts
- ^^^^^^^^^^^^^^^^^^^^^
- #. **CSS=0, TEL3=0**. Interrupt is routed to the FEL when execution is in
- secure state. This is a valid routing model as secure software is in
- control of handling secure interrupts.
- #. **CSS=0, TEL3=1**. Interrupt is routed to EL3 when execution is in secure
- state. This is a valid routing model as secure software in EL3 can
- handover the interrupt to Secure-EL1 for handling.
- #. **CSS=1, TEL3=0**. Interrupt is routed to the FEL when execution is in
- non-secure state. This is an invalid routing model as a secure interrupt
- is not visible to the secure software which violates the motivation behind
- the Arm Security Extensions.
- #. **CSS=1, TEL3=1**. Interrupt is routed to EL3 when execution is in
- non-secure state. This is a valid routing model as secure software in EL3
- can handover the interrupt to Secure-EL1 for handling.
- Non-secure interrupts
- ^^^^^^^^^^^^^^^^^^^^^
- #. **CSS=0, TEL3=0**. Interrupt is routed to the FEL when execution is in
- secure state. This allows the secure software to trap non-secure
- interrupts, perform its book-keeping and hand the interrupt to the
- non-secure software through EL3. This is a valid routing model as secure
- software is in control of how its execution is preempted by non-secure
- interrupts.
- #. **CSS=0, TEL3=1**. Interrupt is routed to EL3 when execution is in secure
- state. This is a valid routing model as secure software in EL3 can save
- the state of software in Secure-EL1/Secure-EL0 before handing the
- interrupt to non-secure software. This model requires additional
- coordination between Secure-EL1 and EL3 software to ensure that the
- former's state is correctly saved by the latter.
- #. **CSS=1, TEL3=0**. Interrupt is routed to FEL when execution is in
- non-secure state. This is a valid routing model as a non-secure interrupt
- is handled by non-secure software.
- #. **CSS=1, TEL3=1**. Interrupt is routed to EL3 when execution is in
- non-secure state. This is an invalid routing model as there is no valid
- reason to route the interrupt to EL3 software and then hand it back to
- non-secure software for handling.
- .. _EL3 interrupts:
- EL3 interrupts
- ^^^^^^^^^^^^^^
- #. **CSS=0, TEL3=0**. Interrupt is routed to the FEL when execution is in
- Secure-EL1/Secure-EL0. This is a valid routing model as secure software
- in Secure-EL1/Secure-EL0 is in control of how its execution is preempted
- by EL3 interrupt and can handover the interrupt to EL3 for handling.
- However, when ``EL3_EXCEPTION_HANDLING`` is ``1``, this routing model is
- invalid as EL3 interrupts are unconditionally routed to EL3, and EL3
- interrupts will always preempt Secure EL1/EL0 execution. See :ref:`exception
- handling<interrupt-handling>` documentation.
- #. **CSS=0, TEL3=1**. Interrupt is routed to EL3 when execution is in
- Secure-EL1/Secure-EL0. This is a valid routing model as secure software
- in EL3 can handle the interrupt.
- #. **CSS=1, TEL3=0**. Interrupt is routed to the FEL when execution is in
- non-secure state. This is an invalid routing model as a secure interrupt
- is not visible to the secure software which violates the motivation behind
- the Arm Security Extensions.
- #. **CSS=1, TEL3=1**. Interrupt is routed to EL3 when execution is in
- non-secure state. This is a valid routing model as secure software in EL3
- can handle the interrupt.
- Mapping of interrupt type to signal
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- The framework is meant to work with any interrupt controller implemented by a
- platform. A interrupt controller could generate a type of interrupt as either an
- FIQ or IRQ signal to the CPU depending upon the current security state. The
- mapping between the type and signal is known only to the platform. The framework
- uses this information to determine whether the IRQ or the FIQ bit should be
- programmed in ``SCR_EL3`` while applying the routing model for a type of
- interrupt. The platform provides this information through the
- ``plat_interrupt_type_to_line()`` API (described in the
- :ref:`Porting Guide`). For example, on the FVP port when the platform uses an
- Arm GICv2 interrupt controller, Secure-EL1 interrupts are signaled through the
- FIQ signal while Non-secure interrupts are signaled through the IRQ signal.
- This applies when execution is in either security state.
- Effect of mapping of several interrupt types to one signal
- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- It should be noted that if more than one interrupt type maps to a single
- interrupt signal, and if any one of the interrupt type sets **TEL3=1** for a
- particular security state, then interrupt signal will be routed to EL3 when in
- that security state. This means that all the other interrupt types using the
- same interrupt signal will be forced to the same routing model. This should be
- borne in mind when choosing the routing model for an interrupt type.
- For example, in Arm GICv3, when the execution context is Secure-EL1/
- Secure-EL0, both the EL3 and the non secure interrupt types map to the FIQ
- signal. So if either one of the interrupt type sets the routing model so
- that **TEL3=1** when **CSS=0**, the FIQ bit in ``SCR_EL3`` will be programmed to
- route the FIQ signal to EL3 when executing in Secure-EL1/Secure-EL0, thereby
- effectively routing the other interrupt type also to EL3.
- Assumptions in Interrupt Management Framework
- ---------------------------------------------
- The framework makes the following assumptions to simplify its implementation.
- #. Although the framework has support for 2 types of secure interrupts (EL3
- and Secure-EL1 interrupt), only interrupt controller architectures
- like Arm GICv3 has architectural support for EL3 interrupts in the form of
- Group 0 interrupts. In Arm GICv2, all secure interrupts are assumed to be
- handled in Secure-EL1. They can be delivered to Secure-EL1 via EL3 but they
- cannot be handled in EL3.
- #. Interrupt exceptions (``PSTATE.I`` and ``F`` bits) are masked during execution
- in EL3.
- #. Interrupt management: the following sections describe how interrupts are
- managed by the interrupt handling framework. This entails:
- #. Providing an interface to allow registration of a handler and
- specification of the routing model for a type of interrupt.
- #. Implementing support to hand control of an interrupt type to its
- registered handler when the interrupt is generated.
- Both aspects of interrupt management involve various components in the secure
- software stack spanning from EL3 to Secure-EL1. These components are described
- in the section `Software components`_. The framework stores information
- associated with each type of interrupt in the following data structure.
- .. code:: c
- typedef struct intr_type_desc {
- interrupt_type_handler_t handler;
- uint32_t flags;
- uint32_t scr_el3[2];
- } intr_type_desc_t;
- The ``flags`` field stores the routing model for the interrupt type in
- bits[1:0]. Bit[0] stores the routing model when execution is in the secure
- state. Bit[1] stores the routing model when execution is in the non-secure
- state. As mentioned in Section `Routing model`_, a value of ``0`` implies that
- the interrupt should be targeted to the FEL. A value of ``1`` implies that it
- should be targeted to EL3. The remaining bits are reserved and SBZ. The helper
- macro ``set_interrupt_rm_flag()`` should be used to set the bits in the
- ``flags`` parameter.
- The ``scr_el3[2]`` field also stores the routing model but as a mapping of the
- model in the ``flags`` field to the corresponding bit in the ``SCR_EL3`` for each
- security state.
- The framework also depends upon the platform port to configure the interrupt
- controller to distinguish between secure and non-secure interrupts. The platform
- is expected to be aware of the secure devices present in the system and their
- associated interrupt numbers. It should configure the interrupt controller to
- enable the secure interrupts, ensure that their priority is always higher than
- the non-secure interrupts and target them to the primary CPU. It should also
- export the interface described in the :ref:`Porting Guide` to enable
- handling of interrupts.
- In the remainder of this document, for the sake of simplicity a Arm GICv2 system
- is considered and it is assumed that the FIQ signal is used to generate Secure-EL1
- interrupts and the IRQ signal is used to generate non-secure interrupts in either
- security state. EL3 interrupts are not considered.
- Software components
- -------------------
- Roles and responsibilities for interrupt management are sub-divided between the
- following components of software running in EL3 and Secure-EL1. Each component is
- briefly described below.
- #. EL3 Runtime Firmware. This component is common to all ports of TF-A.
- #. Secure Payload Dispatcher (SPD) service. This service interfaces with the
- Secure Payload (SP) software which runs in Secure-EL1/Secure-EL0 and is
- responsible for switching execution between secure and non-secure states.
- A switch is triggered by a Secure Monitor Call and it uses the APIs
- exported by the Context management library to implement this functionality.
- Switching execution between the two security states is a requirement for
- interrupt management as well. This results in a significant dependency on
- the SPD service. TF-A implements an example Test Secure Payload Dispatcher
- (TSPD) service.
- An SPD service plugs into the EL3 runtime firmware and could be common to
- some ports of TF-A.
- #. Secure Payload (SP). On a production system, the Secure Payload corresponds
- to a Secure OS which runs in Secure-EL1/Secure-EL0. It interfaces with the
- SPD service to manage communication with non-secure software. TF-A
- implements an example secure payload called Test Secure Payload (TSP)
- which runs only in Secure-EL1.
- A Secure payload implementation could be common to some ports of TF-A,
- just like the SPD service.
- Interrupt registration
- ----------------------
- This section describes in detail the role of each software component (see
- `Software components`_) during the registration of a handler for an interrupt
- type.
- .. _el3-runtime-firmware:
- EL3 runtime firmware
- ~~~~~~~~~~~~~~~~~~~~
- This component declares the following prototype for a handler of an interrupt type.
- .. code:: c
- typedef uint64_t (*interrupt_type_handler_t)(uint32_t id,
- uint32_t flags,
- void *handle,
- void *cookie);
- The ``id`` is parameter is reserved and could be used in the future for passing
- the interrupt id of the highest pending interrupt only if there is a foolproof
- way of determining the id. Currently it contains ``INTR_ID_UNAVAILABLE``.
- The ``flags`` parameter contains miscellaneous information as follows.
- #. Security state, bit[0]. This bit indicates the security state of the lower
- exception level when the interrupt was generated. A value of ``1`` means
- that it was in the non-secure state. A value of ``0`` indicates that it was
- in the secure state. This bit can be used by the handler to ensure that
- interrupt was generated and routed as per the routing model specified
- during registration.
- #. Reserved, bits[31:1]. The remaining bits are reserved for future use.
- The ``handle`` parameter points to the ``cpu_context`` structure of the current CPU
- for the security state specified in the ``flags`` parameter.
- Once the handler routine completes, execution will return to either the secure
- or non-secure state. The handler routine must return a pointer to
- ``cpu_context`` structure of the current CPU for the target security state. On
- AArch64, this return value is currently ignored by the caller as the
- appropriate ``cpu_context`` to be used is expected to be set by the handler
- via the context management library APIs.
- A portable interrupt handler implementation must set the target context both in
- the structure pointed to by the returned pointer and via the context management
- library APIs. The handler should treat all error conditions as critical errors
- and take appropriate action within its implementation e.g. use assertion
- failures.
- The runtime firmware provides the following API for registering a handler for a
- particular type of interrupt. A Secure Payload Dispatcher service should use
- this API to register a handler for Secure-EL1 and optionally for non-secure
- interrupts. This API also requires the caller to specify the routing model for
- the type of interrupt.
- .. code:: c
- int32_t register_interrupt_type_handler(uint32_t type,
- interrupt_type_handler handler,
- uint64_t flags);
- The ``type`` parameter can be one of the three interrupt types listed above i.e.
- ``INTR_TYPE_S_EL1``, ``INTR_TYPE_NS`` & ``INTR_TYPE_EL3``. The ``flags`` parameter
- is as described in Section 2.
- The function will return ``0`` upon a successful registration. It will return
- ``-EALREADY`` in case a handler for the interrupt type has already been
- registered. If the ``type`` is unrecognised or the ``flags`` or the ``handler`` are
- invalid it will return ``-EINVAL``.
- Interrupt routing is governed by the configuration of the ``SCR_EL3.FIQ/IRQ`` bits
- prior to entry into a lower exception level in either security state. The
- context management library maintains a copy of the ``SCR_EL3`` system register for
- each security state in the ``cpu_context`` structure of each CPU. It exports the
- following APIs to let EL3 Runtime Firmware program and retrieve the routing
- model for each security state for the current CPU. The value of ``SCR_EL3`` stored
- in the ``cpu_context`` is used by the ``el3_exit()`` function to program the
- ``SCR_EL3`` register prior to returning from the EL3 exception level.
- .. code:: c
- uint32_t cm_get_scr_el3(uint32_t security_state);
- void cm_write_scr_el3_bit(uint32_t security_state,
- uint32_t bit_pos,
- uint32_t value);
- ``cm_get_scr_el3()`` returns the value of the ``SCR_EL3`` register for the specified
- security state of the current CPU. ``cm_write_scr_el3_bit()`` writes a ``0`` or ``1``
- to the bit specified by ``bit_pos``. ``register_interrupt_type_handler()`` invokes
- ``set_routing_model()`` API which programs the ``SCR_EL3`` according to the routing
- model using the ``cm_get_scr_el3()`` and ``cm_write_scr_el3_bit()`` APIs.
- It is worth noting that in the current implementation of the framework, the EL3
- runtime firmware is responsible for programming the routing model. The SPD is
- responsible for ensuring that the routing model has been adhered to upon
- receiving an interrupt.
- .. _spd-int-registration:
- Secure payload dispatcher
- ~~~~~~~~~~~~~~~~~~~~~~~~~
- A SPD service is responsible for determining and maintaining the interrupt
- routing model supported by itself and the Secure Payload. It is also responsible
- for ferrying interrupts between secure and non-secure software depending upon
- the routing model. It could determine the routing model at build time or at
- runtime. It must use this information to register a handler for each interrupt
- type using the ``register_interrupt_type_handler()`` API in EL3 runtime firmware.
- If the routing model is not known to the SPD service at build time, then it must
- be provided by the SP as the result of its initialisation. The SPD should
- program the routing model only after SP initialisation has completed e.g. in the
- SPD initialisation function pointed to by the ``bl32_init`` variable.
- The SPD should determine the mechanism to pass control to the Secure Payload
- after receiving an interrupt from the EL3 runtime firmware. This information
- could either be provided to the SPD service at build time or by the SP at
- runtime.
- Test secure payload dispatcher behavior
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- .. note::
- Where this document discusses ``TSP_NS_INTR_ASYNC_PREEMPT`` as being
- ``1``, the same results also apply when ``EL3_EXCEPTION_HANDLING`` is ``1``.
- The TSPD only handles Secure-EL1 interrupts and is provided with the following
- routing model at build time.
- - Secure-EL1 interrupts are routed to EL3 when execution is in non-secure
- state and are routed to the FEL when execution is in the secure state
- i.e **CSS=0, TEL3=0** & **CSS=1, TEL3=1** for Secure-EL1 interrupts
- - When the build flag ``TSP_NS_INTR_ASYNC_PREEMPT`` is zero, the default routing
- model is used for non-secure interrupts. They are routed to the FEL in
- either security state i.e **CSS=0, TEL3=0** & **CSS=1, TEL3=0** for
- Non-secure interrupts.
- - When the build flag ``TSP_NS_INTR_ASYNC_PREEMPT`` is defined to 1, then the
- non secure interrupts are routed to EL3 when execution is in secure state
- i.e **CSS=0, TEL3=1** for non-secure interrupts. This effectively preempts
- Secure-EL1. The default routing model is used for non secure interrupts in
- non-secure state. i.e **CSS=1, TEL3=0**.
- It performs the following actions in the ``tspd_init()`` function to fulfill the
- requirements mentioned earlier.
- #. It passes control to the Test Secure Payload to perform its
- initialisation. The TSP provides the address of the vector table
- ``tsp_vectors`` in the SP which also includes the handler for Secure-EL1
- interrupts in the ``sel1_intr_entry`` field. The TSPD passes control to the TSP at
- this address when it receives a Secure-EL1 interrupt.
- The handover agreement between the TSP and the TSPD requires that the TSPD
- masks all interrupts (``PSTATE.DAIF`` bits) when it calls
- ``tsp_sel1_intr_entry()``. The TSP has to preserve the callee saved general
- purpose, SP_EL1/Secure-EL0, LR, VFP and system registers. It can use
- ``x0-x18`` to enable its C runtime.
- #. The TSPD implements a handler function for Secure-EL1 interrupts. This
- function is registered with the EL3 runtime firmware using the
- ``register_interrupt_type_handler()`` API as follows
- .. code:: c
- /* Forward declaration */
- interrupt_type_handler tspd_secure_el1_interrupt_handler;
- int32_t rc, flags = 0;
- set_interrupt_rm_flag(flags, NON_SECURE);
- rc = register_interrupt_type_handler(INTR_TYPE_S_EL1,
- tspd_secure_el1_interrupt_handler,
- flags);
- if (rc)
- panic();
- #. When the build flag ``TSP_NS_INTR_ASYNC_PREEMPT`` is defined to 1, the TSPD
- implements a handler function for non-secure interrupts. This function is
- registered with the EL3 runtime firmware using the
- ``register_interrupt_type_handler()`` API as follows
- .. code:: c
- /* Forward declaration */
- interrupt_type_handler tspd_ns_interrupt_handler;
- int32_t rc, flags = 0;
- set_interrupt_rm_flag(flags, SECURE);
- rc = register_interrupt_type_handler(INTR_TYPE_NS,
- tspd_ns_interrupt_handler,
- flags);
- if (rc)
- panic();
- .. _sp-int-registration:
- Secure payload
- ~~~~~~~~~~~~~~
- A Secure Payload must implement an interrupt handling framework at Secure-EL1
- (Secure-EL1 IHF) to support its chosen interrupt routing model. Secure payload
- execution will alternate between the below cases.
- #. In the code where IRQ, FIQ or both interrupts are enabled, if an interrupt
- type is targeted to the FEL, then it will be routed to the Secure-EL1
- exception vector table. This is defined as the **asynchronous mode** of
- handling interrupts. This mode applies to both Secure-EL1 and non-secure
- interrupts.
- #. In the code where both interrupts are disabled, if an interrupt type is
- targeted to the FEL, then execution will eventually migrate to the
- non-secure state. Any non-secure interrupts will be handled as described
- in the routing model where **CSS=1 and TEL3=0**. Secure-EL1 interrupts
- will be routed to EL3 (as per the routing model where **CSS=1 and
- TEL3=1**) where the SPD service will hand them to the SP. This is defined
- as the **synchronous mode** of handling interrupts.
- The interrupt handling framework implemented by the SP should support one or
- both these interrupt handling models depending upon the chosen routing model.
- The following list briefly describes how the choice of a valid routing model
- (see `Valid routing models`_) effects the implementation of the Secure-EL1
- IHF. If the choice of the interrupt routing model is not known to the SPD
- service at compile time, then the SP should pass this information to the SPD
- service at runtime during its initialisation phase.
- As mentioned earlier, an Arm GICv2 system is considered and it is assumed that
- the FIQ signal is used to generate Secure-EL1 interrupts and the IRQ signal
- is used to generate non-secure interrupts in either security state.
- Secure payload IHF design w.r.t secure-EL1 interrupts
- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- #. **CSS=0, TEL3=0**. If ``PSTATE.F=0``, Secure-EL1 interrupts will be
- triggered at one of the Secure-EL1 FIQ exception vectors. The Secure-EL1
- IHF should implement support for handling FIQ interrupts asynchronously.
- If ``PSTATE.F=1`` then Secure-EL1 interrupts will be handled as per the
- synchronous interrupt handling model. The SP could implement this scenario
- by exporting a separate entrypoint for Secure-EL1 interrupts to the SPD
- service during the registration phase. The SPD service would also need to
- know the state of the system, general purpose and the ``PSTATE`` registers
- in which it should arrange to return execution to the SP. The SP should
- provide this information in an implementation defined way during the
- registration phase if it is not known to the SPD service at build time.
- #. **CSS=1, TEL3=1**. Interrupts are routed to EL3 when execution is in
- non-secure state. They should be handled through the synchronous interrupt
- handling model as described in 1. above.
- #. **CSS=0, TEL3=1**. Secure-EL1 interrupts are routed to EL3 when execution
- is in secure state. They will not be visible to the SP. The ``PSTATE.F`` bit
- in Secure-EL1/Secure-EL0 will not mask FIQs. The EL3 runtime firmware will
- call the handler registered by the SPD service for Secure-EL1 interrupts.
- Secure-EL1 IHF should then handle all Secure-EL1 interrupt through the
- synchronous interrupt handling model described in 1. above.
- Secure payload IHF design w.r.t non-secure interrupts
- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- #. **CSS=0, TEL3=0**. If ``PSTATE.I=0``, non-secure interrupts will be
- triggered at one of the Secure-EL1 IRQ exception vectors . The Secure-EL1
- IHF should co-ordinate with the SPD service to transfer execution to the
- non-secure state where the interrupt should be handled e.g the SP could
- allocate a function identifier to issue a SMC64 or SMC32 to the SPD
- service which indicates that the SP execution has been preempted by a
- non-secure interrupt. If this function identifier is not known to the SPD
- service at compile time then the SP could provide it during the
- registration phase.
- If ``PSTATE.I=1`` then the non-secure interrupt will pend until execution
- resumes in the non-secure state.
- #. **CSS=0, TEL3=1**. Non-secure interrupts are routed to EL3. They will not
- be visible to the SP. The ``PSTATE.I`` bit in Secure-EL1/Secure-EL0 will
- have not effect. The SPD service should register a non-secure interrupt
- handler which should save the SP state correctly and resume execution in
- the non-secure state where the interrupt will be handled. The Secure-EL1
- IHF does not need to take any action.
- #. **CSS=1, TEL3=0**. Non-secure interrupts are handled in the FEL in
- non-secure state (EL1/EL2) and are not visible to the SP. This routing
- model does not affect the SP behavior.
- A Secure Payload must also ensure that all Secure-EL1 interrupts are correctly
- configured at the interrupt controller by the platform port of the EL3 runtime
- firmware. It should configure any additional Secure-EL1 interrupts which the EL3
- runtime firmware is not aware of through its platform port.
- Test secure payload behavior
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- The routing model for Secure-EL1 and non-secure interrupts chosen by the TSP is
- described in Section `Secure Payload Dispatcher`__. It is known to the TSPD
- service at build time.
- .. __: #spd-int-registration
- The TSP implements an entrypoint (``tsp_sel1_intr_entry()``) for handling Secure-EL1
- interrupts taken in non-secure state and routed through the TSPD service
- (synchronous handling model). It passes the reference to this entrypoint via
- ``tsp_vectors`` to the TSPD service.
- The TSP also replaces the default exception vector table referenced through the
- ``early_exceptions`` variable, with a vector table capable of handling FIQ and IRQ
- exceptions taken at the same (Secure-EL1) exception level. This table is
- referenced through the ``tsp_exceptions`` variable and programmed into the
- VBAR_EL1. It caters for the asynchronous handling model.
- The TSP also programs the Secure Physical Timer in the Arm Generic Timer block
- to raise a periodic interrupt (every half a second) for the purpose of testing
- interrupt management across all the software components listed in `Software
- components`_.
- Interrupt handling
- ------------------
- This section describes in detail the role of each software component (see
- Section `Software components`_) in handling an interrupt of a particular type.
- EL3 runtime firmware
- ~~~~~~~~~~~~~~~~~~~~
- The EL3 runtime firmware populates the IRQ and FIQ exception vectors referenced
- by the ``runtime_exceptions`` variable as follows.
- #. IRQ and FIQ exceptions taken from the current exception level with
- ``SP_EL0`` or ``SP_EL3`` are reported as irrecoverable error conditions. As
- mentioned earlier, EL3 runtime firmware always executes with the
- ``PSTATE.I`` and ``PSTATE.F`` bits set.
- #. The following text describes how the IRQ and FIQ exceptions taken from a
- lower exception level using AArch64 or AArch32 are handled.
- When an interrupt is generated, the vector for each interrupt type is
- responsible for:
- #. Saving the entire general purpose register context (x0-x30) immediately
- upon exception entry. The registers are saved in the per-cpu ``cpu_context``
- data structure referenced by the ``SP_EL3``\ register.
- #. Saving the ``ELR_EL3``, ``SP_EL0`` and ``SPSR_EL3`` system registers in the
- per-cpu ``cpu_context`` data structure referenced by the ``SP_EL3`` register.
- #. Switching to the C runtime stack by restoring the ``CTX_RUNTIME_SP`` value
- from the per-cpu ``cpu_context`` data structure in ``SP_EL0`` and
- executing the ``msr spsel, #0`` instruction.
- #. Determining the type of interrupt. Secure-EL1 interrupts will be signaled
- at the FIQ vector. Non-secure interrupts will be signaled at the IRQ
- vector. The platform should implement the following API to determine the
- type of the pending interrupt.
- .. code:: c
- uint32_t plat_ic_get_interrupt_type(void);
- It should return either ``INTR_TYPE_S_EL1`` or ``INTR_TYPE_NS``.
- #. Determining the handler for the type of interrupt that has been generated.
- The following API has been added for this purpose.
- .. code:: c
- interrupt_type_handler get_interrupt_type_handler(uint32_t interrupt_type);
- It returns the reference to the registered handler for this interrupt
- type. The ``handler`` is retrieved from the ``intr_type_desc_t`` structure as
- described in Section 2. ``NULL`` is returned if no handler has been
- registered for this type of interrupt. This scenario is reported as an
- irrecoverable error condition.
- #. Calling the registered handler function for the interrupt type generated.
- The ``id`` parameter is set to ``INTR_ID_UNAVAILABLE`` currently. The id along
- with the current security state and a reference to the ``cpu_context_t``
- structure for the current security state are passed to the handler function
- as its arguments.
- The handler function returns a reference to the per-cpu ``cpu_context_t``
- structure for the target security state.
- #. Calling ``el3_exit()`` to return from EL3 into a lower exception level in
- the security state determined by the handler routine. The ``el3_exit()``
- function is responsible for restoring the register context from the
- ``cpu_context_t`` data structure for the target security state.
- Secure payload dispatcher
- ~~~~~~~~~~~~~~~~~~~~~~~~~
- Interrupt entry
- ^^^^^^^^^^^^^^^
- The SPD service begins handling an interrupt when the EL3 runtime firmware calls
- the handler function for that type of interrupt. The SPD service is responsible
- for the following:
- #. Validating the interrupt. This involves ensuring that the interrupt was
- generated according to the interrupt routing model specified by the SPD
- service during registration. It should use the security state of the
- exception level (passed in the ``flags`` parameter of the handler) where
- the interrupt was taken from to determine this. If the interrupt is not
- recognised then the handler should treat it as an irrecoverable error
- condition.
- An SPD service can register a handler for Secure-EL1 and/or Non-secure
- interrupts. A non-secure interrupt should never be routed to EL3 from
- from non-secure state. Also if a routing model is chosen where Secure-EL1
- interrupts are routed to S-EL1 when execution is in Secure state, then a
- S-EL1 interrupt should never be routed to EL3 from secure state. The handler
- could use the security state flag to check this.
- #. Determining whether a context switch is required. This depends upon the
- routing model and interrupt type. For non secure and S-EL1 interrupt,
- if the security state of the execution context where the interrupt was
- generated is not the same as the security state required for handling
- the interrupt, a context switch is required. The following 2 cases
- require a context switch from secure to non-secure or vice-versa:
- #. A Secure-EL1 interrupt taken from the non-secure state should be
- routed to the Secure Payload.
- #. A non-secure interrupt taken from the secure state should be routed
- to the last known non-secure exception level.
- The SPD service must save the system register context of the current
- security state. It must then restore the system register context of the
- target security state. It should use the ``cm_set_next_eret_context()`` API
- to ensure that the next ``cpu_context`` to be restored is of the target
- security state.
- If the target state is secure then execution should be handed to the SP as
- per the synchronous interrupt handling model it implements. A Secure-EL1
- interrupt can be routed to EL3 while execution is in the SP. This implies
- that SP execution can be preempted while handling an interrupt by a
- another higher priority Secure-EL1 interrupt or a EL3 interrupt. The SPD
- service should be able to handle this preemption or manage secure interrupt
- priorities before handing control to the SP.
- #. Setting the return value of the handler to the per-cpu ``cpu_context`` if
- the interrupt has been successfully validated and ready to be handled at a
- lower exception level.
- The routing model allows non-secure interrupts to interrupt Secure-EL1 when in
- secure state if it has been configured to do so. The SPD service and the SP
- should implement a mechanism for routing these interrupts to the last known
- exception level in the non-secure state. The former should save the SP context,
- restore the non-secure context and arrange for entry into the non-secure state
- so that the interrupt can be handled.
- Interrupt exit
- ^^^^^^^^^^^^^^
- When the Secure Payload has finished handling a Secure-EL1 interrupt, it could
- return control back to the SPD service through a SMC32 or SMC64. The SPD service
- should handle this secure monitor call so that execution resumes in the
- exception level and the security state from where the Secure-EL1 interrupt was
- originally taken.
- Test secure payload dispatcher Secure-EL1 interrupt handling
- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- The example TSPD service registers a handler for Secure-EL1 interrupts taken
- from the non-secure state. During execution in S-EL1, the TSPD expects that the
- Secure-EL1 interrupts are handled in S-EL1 by TSP. Its handler
- ``tspd_secure_el1_interrupt_handler()`` expects only to be invoked for Secure-EL1
- originating from the non-secure state. It takes the following actions upon being
- invoked.
- #. It uses the security state provided in the ``flags`` parameter to ensure
- that the secure interrupt originated from the non-secure state. It asserts
- if this is not the case.
- #. It saves the system register context for the non-secure state by calling
- ``cm_el1_sysregs_context_save(NON_SECURE);``.
- #. It sets the ``ELR_EL3`` system register to ``tsp_sel1_intr_entry`` and sets the
- ``SPSR_EL3.DAIF`` bits in the secure CPU context. It sets ``x0`` to
- ``TSP_HANDLE_SEL1_INTR_AND_RETURN``. If the TSP was preempted earlier by a non
- secure interrupt during ``yielding`` SMC processing, save the registers that
- will be trashed, which is the ``ELR_EL3`` and ``SPSR_EL3``, in order to be able
- to re-enter TSP for Secure-EL1 interrupt processing. It does not need to
- save any other secure context since the TSP is expected to preserve it
- (see section `Test secure payload dispatcher behavior`_).
- #. It restores the system register context for the secure state by calling
- ``cm_el1_sysregs_context_restore(SECURE);``.
- #. It ensures that the secure CPU context is used to program the next
- exception return from EL3 by calling ``cm_set_next_eret_context(SECURE);``.
- #. It returns the per-cpu ``cpu_context`` to indicate that the interrupt can
- now be handled by the SP. ``x1`` is written with the value of ``elr_el3``
- register for the non-secure state. This information is used by the SP for
- debugging purposes.
- The figure below describes how the interrupt handling is implemented by the TSPD
- when a Secure-EL1 interrupt is generated when execution is in the non-secure
- state.
- |Image 1|
- The TSP issues an SMC with ``TSP_HANDLED_S_EL1_INTR`` as the function identifier to
- signal completion of interrupt handling.
- The TSPD service takes the following actions in ``tspd_smc_handler()`` function
- upon receiving an SMC with ``TSP_HANDLED_S_EL1_INTR`` as the function identifier:
- #. It ensures that the call originated from the secure state otherwise
- execution returns to the non-secure state with ``SMC_UNK`` in ``x0``.
- #. It restores the saved ``ELR_EL3`` and ``SPSR_EL3`` system registers back to
- the secure CPU context (see step 3 above) in case the TSP had been preempted
- by a non secure interrupt earlier.
- #. It restores the system register context for the non-secure state by
- calling ``cm_el1_sysregs_context_restore(NON_SECURE)``.
- #. It ensures that the non-secure CPU context is used to program the next
- exception return from EL3 by calling ``cm_set_next_eret_context(NON_SECURE)``.
- #. ``tspd_smc_handler()`` returns a reference to the non-secure ``cpu_context``
- as the return value.
- Test secure payload dispatcher non-secure interrupt handling
- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- The TSP in Secure-EL1 can be preempted by a non-secure interrupt during
- ``yielding`` SMC processing or by a higher priority EL3 interrupt during
- Secure-EL1 interrupt processing. When ``EL3_EXCEPTION_HANDLING`` is ``0``, only
- non-secure interrupts can cause preemption of TSP since there are no EL3
- interrupts in the system. With ``EL3_EXCEPTION_HANDLING=1`` however, any EL3
- interrupt may preempt Secure execution.
- It should be noted that while TSP is preempted, the TSPD only allows entry into
- the TSP either for Secure-EL1 interrupt handling or for resuming the preempted
- ``yielding`` SMC in response to the ``TSP_FID_RESUME`` SMC from the normal world.
- (See Section `Implication of preempted SMC on Non-Secure Software`_).
- The non-secure interrupt triggered in Secure-EL1 during ``yielding`` SMC
- processing can be routed to either EL3 or Secure-EL1 and is controlled by build
- option ``TSP_NS_INTR_ASYNC_PREEMPT`` (see Section `Test secure payload
- dispatcher behavior`_). If the build option is set, the TSPD will set the
- routing model for the non-secure interrupt to be routed to EL3 from secure state
- i.e. **TEL3=1, CSS=0** and registers ``tspd_ns_interrupt_handler()`` as the
- non-secure interrupt handler. The ``tspd_ns_interrupt_handler()`` on being
- invoked ensures that the interrupt originated from the secure state and disables
- routing of non-secure interrupts from secure state to EL3. This is to prevent
- further preemption (by a non-secure interrupt) when TSP is reentered for
- handling Secure-EL1 interrupts that triggered while execution was in the normal
- world. The ``tspd_ns_interrupt_handler()`` then invokes
- ``tspd_handle_sp_preemption()`` for further handling.
- If the ``TSP_NS_INTR_ASYNC_PREEMPT`` build option is zero (default), the default
- routing model for non-secure interrupt in secure state is in effect
- i.e. **TEL3=0, CSS=0**. During ``yielding`` SMC processing, the IRQ
- exceptions are unmasked i.e. ``PSTATE.I=0``, and a non-secure interrupt will
- trigger at Secure-EL1 IRQ exception vector. The TSP saves the general purpose
- register context and issues an SMC with ``TSP_PREEMPTED`` as the function
- identifier to signal preemption of TSP. The TSPD SMC handler,
- ``tspd_smc_handler()``, ensures that the SMC call originated from the
- secure state otherwise execution returns to the non-secure state with
- ``SMC_UNK`` in ``x0``. It then invokes ``tspd_handle_sp_preemption()`` for
- further handling.
- The ``tspd_handle_sp_preemption()`` takes the following actions upon being
- invoked:
- #. It saves the system register context for the secure state by calling
- ``cm_el1_sysregs_context_save(SECURE)``.
- #. It restores the system register context for the non-secure state by
- calling ``cm_el1_sysregs_context_restore(NON_SECURE)``.
- #. It ensures that the non-secure CPU context is used to program the next
- exception return from EL3 by calling ``cm_set_next_eret_context(NON_SECURE)``.
- #. ``SMC_PREEMPTED`` is set in x0 and return to non secure state after
- restoring non secure context.
- The Normal World is expected to resume the TSP after the ``yielding`` SMC
- preemption by issuing an SMC with ``TSP_FID_RESUME`` as the function identifier
- (see section `Implication of preempted SMC on Non-Secure Software`_). The TSPD
- service takes the following actions in ``tspd_smc_handler()`` function upon
- receiving this SMC:
- #. It ensures that the call originated from the non secure state. An
- assertion is raised otherwise.
- #. Checks whether the TSP needs a resume i.e check if it was preempted. It
- then saves the system register context for the non-secure state by calling
- ``cm_el1_sysregs_context_save(NON_SECURE)``.
- #. Restores the secure context by calling
- ``cm_el1_sysregs_context_restore(SECURE)``
- #. It ensures that the secure CPU context is used to program the next
- exception return from EL3 by calling ``cm_set_next_eret_context(SECURE)``.
- #. ``tspd_smc_handler()`` returns a reference to the secure ``cpu_context`` as the
- return value.
- The figure below describes how the TSP/TSPD handle a non-secure interrupt when
- it is generated during execution in the TSP with ``PSTATE.I`` = 0 when the
- ``TSP_NS_INTR_ASYNC_PREEMPT`` build flag is 0.
- |Image 2|
- .. _sp-synchronous-int:
- Secure payload interrupt handling
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- The SP should implement one or both of the synchronous and asynchronous
- interrupt handling models depending upon the interrupt routing model it has
- chosen (as described in section :ref:`Secure Payload <sp-int-registration>`).
- In the synchronous model, it should begin handling a Secure-EL1 interrupt after
- receiving control from the SPD service at an entrypoint agreed upon during build
- time or during the registration phase. Before handling the interrupt, the SP
- should save any Secure-EL1 system register context which is needed for resuming
- normal execution in the SP later e.g. ``SPSR_EL1``, ``ELR_EL1``. After handling
- the interrupt, the SP could return control back to the exception level and
- security state where the interrupt was originally taken from. The SP should use
- an SMC32 or SMC64 to ask the SPD service to do this.
- In the asynchronous model, the Secure Payload is responsible for handling
- non-secure and Secure-EL1 interrupts at the IRQ and FIQ vectors in its exception
- vector table when ``PSTATE.I`` and ``PSTATE.F`` bits are 0. As described earlier,
- when a non-secure interrupt is generated, the SP should coordinate with the SPD
- service to pass control back to the non-secure state in the last known exception
- level. This will allow the non-secure interrupt to be handled in the non-secure
- state.
- Test secure payload behavior
- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- The TSPD hands control of a Secure-EL1 interrupt to the TSP at the
- ``tsp_sel1_intr_entry()``. The TSP handles the interrupt while ensuring that the
- handover agreement described in Section `Test secure payload dispatcher
- behavior`_ is maintained. It updates some statistics by calling
- ``tsp_update_sync_sel1_intr_stats()``. It then calls
- ``tsp_common_int_handler()`` which.
- #. Checks whether the interrupt is the secure physical timer interrupt. It
- uses the platform API ``plat_ic_get_pending_interrupt_id()`` to get the
- interrupt number. If it is not the secure physical timer interrupt, then
- that means that a higher priority interrupt has preempted it. Invoke
- ``tsp_handle_preemption()`` to handover control back to EL3 by issuing
- an SMC with ``TSP_PREEMPTED`` as the function identifier.
- #. Handles the secure timer interrupt interrupt by acknowledging it using the
- ``plat_ic_acknowledge_interrupt()`` platform API, calling
- ``tsp_generic_timer_handler()`` to reprogram the secure physical generic
- timer and calling the ``plat_ic_end_of_interrupt()`` platform API to signal
- end of interrupt processing.
- The TSP passes control back to the TSPD by issuing an SMC64 with
- ``TSP_HANDLED_S_EL1_INTR`` as the function identifier.
- The TSP handles interrupts under the asynchronous model as follows.
- #. Secure-EL1 interrupts are handled by calling the ``tsp_common_int_handler()``
- function. The function has been described above.
- #. Non-secure interrupts are handled by calling the ``tsp_common_int_handler()``
- function which ends up invoking ``tsp_handle_preemption()`` and issuing an
- SMC64 with ``TSP_PREEMPTED`` as the function identifier. Execution resumes at
- the instruction that follows this SMC instruction when the TSPD hands control
- to the TSP in response to an SMC with ``TSP_FID_RESUME`` as the function
- identifier from the non-secure state (see section `Test secure payload
- dispatcher non-secure interrupt handling`_).
- Other considerations
- --------------------
- Implication of preempted SMC on Non-Secure Software
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- A ``yielding`` SMC call to Secure payload can be preempted by a non-secure
- interrupt and the execution can return to the non-secure world for handling
- the interrupt (For details on ``yielding`` SMC refer `SMC calling convention`_).
- In this case, the SMC call has not completed its execution and the execution
- must return back to the secure payload to resume the preempted SMC call.
- This can be achieved by issuing an SMC call which instructs to resume the
- preempted SMC.
- A ``fast`` SMC cannot be preempted and hence this case will not happen for
- a fast SMC call.
- In the Test Secure Payload implementation, ``TSP_FID_RESUME`` is designated
- as the resume SMC FID. It is important to note that ``TSP_FID_RESUME`` is a
- ``yielding`` SMC which means it too can be be preempted. The typical non
- secure software sequence for issuing a ``yielding`` SMC would look like this,
- assuming ``P.STATE.I=0`` in the non secure state :
- .. code:: c
- int rc;
- rc = smc(TSP_YIELD_SMC_FID, ...); /* Issue a Yielding SMC call */
- /* The pending non-secure interrupt is handled by the interrupt handler
- and returns back here. */
- while (rc == SMC_PREEMPTED) { /* Check if the SMC call is preempted */
- rc = smc(TSP_FID_RESUME); /* Issue resume SMC call */
- }
- The ``TSP_YIELD_SMC_FID`` is any ``yielding`` SMC function identifier and the smc()
- function invokes a SMC call with the required arguments. The pending non-secure
- interrupt causes an IRQ exception and the IRQ handler registered at the
- exception vector handles the non-secure interrupt and returns. The return value
- from the SMC call is tested for ``SMC_PREEMPTED`` to check whether it is
- preempted. If it is, then the resume SMC call ``TSP_FID_RESUME`` is issued. The
- return value of the SMC call is tested again to check if it is preempted.
- This is done in a loop till the SMC call succeeds or fails. If a ``yielding``
- SMC is preempted, until it is resumed using ``TSP_FID_RESUME`` SMC and
- completed, the current TSPD prevents any other SMC call from re-entering
- TSP by returning ``SMC_UNK`` error.
- --------------
- *Copyright (c) 2014-2020, Arm Limited and Contributors. All rights reserved.*
- .. _SMC calling convention: https://developer.arm.com/docs/den0028/latest
- .. |Image 1| image:: ../resources/diagrams/sec-int-handling.png
- .. |Image 2| image:: ../resources/diagrams/non-sec-int-handling.png
|