Paul Beesley | fc9ee36 | 2019-03-07 15:47:15 +0000 | [diff] [blame] | 1 | Exception Handling Framework |
| 2 | ============================ |
Jeenu Viswambharan | cbb40d5 | 2017-10-18 14:30:53 +0100 | [diff] [blame] | 3 | |
Jeenu Viswambharan | cbb40d5 | 2017-10-18 14:30:53 +0100 | [diff] [blame] | 4 | This document describes various aspects of handling exceptions by Runtime |
| 5 | Firmware (BL31) that are targeted at EL3, other than SMCs. The |EHF| takes care |
| 6 | of the following exceptions when targeted at EL3: |
| 7 | |
| 8 | - Interrupts |
| 9 | - Synchronous External Aborts |
| 10 | - Asynchronous External Aborts |
| 11 | |
| 12 | |TF-A|'s handling of synchronous ``SMC`` exceptions raised from lower ELs is |
Madhukar Pappireddy | 86350ae | 2020-07-29 09:37:25 -0500 | [diff] [blame] | 13 | described in the :ref:`Firmware Design document <handling-an-smc>`. However, the |
| 14 | |EHF| changes the semantics of `Interrupt handling`_ and :ref:`synchronous |
| 15 | exceptions <Effect on SMC calls>` other than SMCs. |
Jeenu Viswambharan | cbb40d5 | 2017-10-18 14:30:53 +0100 | [diff] [blame] | 16 | |
| 17 | The |EHF| is selected by setting the build option ``EL3_EXCEPTION_HANDLING`` to |
| 18 | ``1``, and is only available for AArch64 systems. |
| 19 | |
| 20 | Introduction |
| 21 | ------------ |
| 22 | |
| 23 | Through various control bits in the ``SCR_EL3`` register, the Arm architecture |
| 24 | allows for asynchronous exceptions to be routed to EL3. As described in the |
Paul Beesley | f864067 | 2019-04-12 14:19:42 +0100 | [diff] [blame] | 25 | :ref:`Interrupt Management Framework` document, depending on the chosen |
| 26 | interrupt routing model, TF-A appropriately sets the ``FIQ`` and ``IRQ`` bits of |
Jeenu Viswambharan | cbb40d5 | 2017-10-18 14:30:53 +0100 | [diff] [blame] | 27 | ``SCR_EL3`` register to effect this routing. For most use cases, other than for |
| 28 | the purpose of facilitating context switch between Normal and Secure worlds, |
| 29 | FIQs and IRQs routed to EL3 are not required to be handled in EL3. |
| 30 | |
| 31 | However, the evolving system and standards landscape demands that various |
| 32 | exceptions are targeted at and handled in EL3. For instance: |
| 33 | |
| 34 | - Starting with ARMv8.2 architecture extension, many RAS features have been |
| 35 | introduced to the Arm architecture. With RAS features implemented, various |
| 36 | components of the system may use one of the asynchronous exceptions to signal |
| 37 | error conditions to PEs. These error conditions are of critical nature, and |
| 38 | it's imperative that corrective or remedial actions are taken at the earliest |
| 39 | opportunity. Therefore, a *Firmware-first Handling* approach is generally |
| 40 | followed in response to RAS events in the system. |
| 41 | |
| 42 | - The Arm `SDEI specification`_ defines interfaces through which Normal world |
| 43 | interacts with the Runtime Firmware in order to request notification of |
Paul Beesley | 606d807 | 2019-03-13 13:58:02 +0000 | [diff] [blame] | 44 | system events. The |SDEI| specification requires that these events are |
| 45 | notified even when the Normal world executes with the exceptions masked. This |
| 46 | too implies that firmware-first handling is required, where the events are |
| 47 | first received by the EL3 firmware, and then dispatched to Normal world |
| 48 | through purely software mechanism. |
Jeenu Viswambharan | cbb40d5 | 2017-10-18 14:30:53 +0100 | [diff] [blame] | 49 | |
| 50 | For |TF-A|, firmware-first handling means that asynchronous exceptions are |
| 51 | suitably routed to EL3, and the Runtime Firmware (BL31) is extended to include |
| 52 | software components that are capable of handling those exceptions that target |
| 53 | EL3. These components—referred to as *dispatchers* [#spd]_ in general—may |
| 54 | choose to: |
| 55 | |
| 56 | .. _delegation-use-cases: |
| 57 | |
| 58 | - Receive and handle exceptions entirely in EL3, meaning the exceptions |
| 59 | handling terminates in EL3. |
| 60 | |
| 61 | - Receive exceptions, but handle part of the exception in EL3, and delegate the |
| 62 | rest of the handling to a dedicated software stack running at lower Secure |
| 63 | ELs. In this scheme, the handling spans various secure ELs. |
| 64 | |
| 65 | - Receive exceptions, but handle part of the exception in EL3, and delegate |
| 66 | processing of the error to dedicated software stack running at lower secure |
| 67 | ELs (as above); additionally, the Normal world may also be required to |
| 68 | participate in the handling, or be notified of such events (for example, as |
Paul Beesley | 606d807 | 2019-03-13 13:58:02 +0000 | [diff] [blame] | 69 | an |SDEI| event). In this scheme, exception handling potentially and |
| 70 | maximally spans all ELs in both Secure and Normal worlds. |
Jeenu Viswambharan | cbb40d5 | 2017-10-18 14:30:53 +0100 | [diff] [blame] | 71 | |
| 72 | On any given system, all of the above handling models may be employed |
| 73 | independently depending on platform choice and the nature of the exception |
| 74 | received. |
| 75 | |
Madhukar Pappireddy | 86350ae | 2020-07-29 09:37:25 -0500 | [diff] [blame] | 76 | .. [#spd] Not to be confused with :ref:`Secure Payload Dispatcher |
| 77 | <firmware_design_sel1_spd>`, which is an EL3 component that operates in EL3 |
| 78 | on behalf of Secure OS. |
Jeenu Viswambharan | cbb40d5 | 2017-10-18 14:30:53 +0100 | [diff] [blame] | 79 | |
| 80 | The role of Exception Handling Framework |
| 81 | ---------------------------------------- |
| 82 | |
| 83 | Corollary to the use cases cited above, the primary role of the |EHF| is to |
| 84 | facilitate firmware-first handling of exceptions on Arm systems. The |EHF| thus |
| 85 | enables multiple exception dispatchers in runtime firmware to co-exist, register |
| 86 | for, and handle exceptions targeted at EL3. This section outlines the basics, |
| 87 | and the rest of this document expands the various aspects of the |EHF|. |
| 88 | |
| 89 | In order to arbitrate exception handling among dispatchers, the |EHF| operation |
| 90 | is based on a priority scheme. This priority scheme is closely tied to how the |
| 91 | Arm GIC architecture defines it, although it's applied to non-interrupt |
| 92 | exceptions too (SErrors, for example). |
| 93 | |
| 94 | The platform is required to `partition`__ the Secure priority space into |
| 95 | priority levels as applicable for the Secure software stack. It then assigns the |
| 96 | dispatchers to one or more priority levels. The dispatchers then register |
| 97 | handlers for the priority levels at runtime. A dispatcher can register handlers |
| 98 | for more than one priority level. |
| 99 | |
| 100 | .. __: `Partitioning priority levels`_ |
| 101 | |
| 102 | |
| 103 | .. _ehf-figure: |
| 104 | |
Paul Beesley | 814f8c0 | 2019-03-13 15:49:27 +0000 | [diff] [blame] | 105 | .. image:: ../resources/diagrams/draw.io/ehf.svg |
Jeenu Viswambharan | cbb40d5 | 2017-10-18 14:30:53 +0100 | [diff] [blame] | 106 | |
| 107 | A priority level is *active* when a handler at that priority level is currently |
| 108 | executing in EL3, or has delegated the execution to a lower EL. For interrupts, |
| 109 | this is implicit when an interrupt is targeted and acknowledged at EL3, and the |
| 110 | priority of the acknowledged interrupt is used to match its registered handler. |
| 111 | The priority level is likewise implicitly deactivated when the interrupt |
| 112 | handling concludes by EOIing the interrupt. |
| 113 | |
| 114 | Non-interrupt exceptions (SErrors, for example) don't have a notion of priority. |
| 115 | In order for the priority arbitration to work, the |EHF| provides APIs in order |
| 116 | for these non-interrupt exceptions to assume a priority, and to interwork with |
| 117 | interrupts. Dispatchers handling such exceptions must therefore explicitly |
| 118 | activate and deactivate the respective priority level as and when they're |
| 119 | handled or delegated. |
| 120 | |
| 121 | Because priority activation and deactivation for interrupt handling is implicit |
| 122 | and involves GIC priority masking, it's impossible for a lower priority |
| 123 | interrupt to preempt a higher priority one. By extension, this means that a |
| 124 | lower priority dispatcher cannot preempt a higher-priority one. Priority |
| 125 | activation and deactivation for non-interrupt exceptions, however, has to be |
| 126 | explicit. The |EHF| therefore disallows for lower priority level to be activated |
| 127 | whilst a higher priority level is active, and would result in a panic. |
| 128 | Likewise, a panic would result if it's attempted to deactivate a lower priority |
| 129 | level when a higher priority level is active. |
| 130 | |
| 131 | In essence, priority level activation and deactivation conceptually works like a |
| 132 | stack—priority levels stack up in strictly increasing fashion, and need to be |
| 133 | unstacked in strictly the reverse order. For interrupts, the GIC ensures this is |
| 134 | the case; for non-interrupts, the |EHF| monitors and asserts this. See |
| 135 | `Transition of priority levels`_. |
| 136 | |
Madhukar Pappireddy | 86350ae | 2020-07-29 09:37:25 -0500 | [diff] [blame] | 137 | .. _interrupt-handling: |
| 138 | |
Jeenu Viswambharan | cbb40d5 | 2017-10-18 14:30:53 +0100 | [diff] [blame] | 139 | Interrupt handling |
| 140 | ------------------ |
| 141 | |
| 142 | The |EHF| is a client of *Interrupt Management Framework*, and registers the |
Paul Beesley | f864067 | 2019-04-12 14:19:42 +0100 | [diff] [blame] | 143 | top-level handler for interrupts that target EL3, as described in the |
| 144 | :ref:`Interrupt Management Framework` document. This has the following |
| 145 | implications: |
Jeenu Viswambharan | cbb40d5 | 2017-10-18 14:30:53 +0100 | [diff] [blame] | 146 | |
| 147 | - On GICv3 systems, when executing in S-EL1, pending Non-secure interrupts of |
| 148 | sufficient priority are signalled as FIQs, and therefore will be routed to |
| 149 | EL3. As a result, S-EL1 software cannot expect to handle Non-secure |
| 150 | interrupts at S-EL1. Essentially, this deprecates the routing mode described |
Madhukar Pappireddy | 86350ae | 2020-07-29 09:37:25 -0500 | [diff] [blame] | 151 | as :ref:`CSS=0, TEL3=0 <EL3 interrupts>`. |
Jeenu Viswambharan | cbb40d5 | 2017-10-18 14:30:53 +0100 | [diff] [blame] | 152 | |
| 153 | In order for S-EL1 software to handle Non-secure interrupts while having |
| 154 | |EHF| enabled, the dispatcher must adopt a model where Non-secure interrupts |
Madhukar Pappireddy | 86350ae | 2020-07-29 09:37:25 -0500 | [diff] [blame] | 155 | are received at EL3, but are then :ref:`synchronously <sp-synchronous-int>` |
| 156 | handled over to S-EL1. |
Jeenu Viswambharan | cbb40d5 | 2017-10-18 14:30:53 +0100 | [diff] [blame] | 157 | |
| 158 | - On GICv2 systems, it's required that the build option ``GICV2_G0_FOR_EL3`` is |
| 159 | set to ``1`` so that *Group 0* interrupts target EL3. |
| 160 | |
| 161 | - While executing in Secure world, |EHF| sets GIC Priority Mask Register to the |
| 162 | lowest Secure priority. This means that no Non-secure interrupts can preempt |
| 163 | Secure execution. See `Effect on SMC calls`_ for more details. |
| 164 | |
| 165 | As mentioned above, with |EHF|, the platform is required to partition *Group 0* |
| 166 | interrupts into distinct priority levels. A dispatcher that chooses to receive |
| 167 | interrupts can then *own* one or more priority levels, and register interrupt |
| 168 | handlers for them. A given priority level can be assigned to only one handler. A |
| 169 | dispatcher may register more than one priority level. |
| 170 | |
| 171 | Dispatchers are assigned interrupt priority levels in two steps: |
| 172 | |
Manish Pandey | 9c9f38a | 2020-06-30 00:46:08 +0100 | [diff] [blame] | 173 | .. _Partitioning priority levels: |
| 174 | |
Jeenu Viswambharan | cbb40d5 | 2017-10-18 14:30:53 +0100 | [diff] [blame] | 175 | Partitioning priority levels |
| 176 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| 177 | |
| 178 | Interrupts are associated to dispatchers by way of grouping and assigning |
| 179 | interrupts to a priority level. In other words, all interrupts that are to |
| 180 | target a particular dispatcher should fall in a particular priority level. For |
| 181 | priority assignment: |
| 182 | |
| 183 | - Of the 8 bits of priority that Arm GIC architecture permits, bit 7 must be 0 |
| 184 | (secure space). |
| 185 | |
| 186 | - Depending on the number of dispatchers to support, the platform must choose |
| 187 | to use the top *n* of the 7 remaining bits to identify and assign interrupts |
| 188 | to individual dispatchers. Choosing *n* bits supports up to 2\ :sup:`n` |
| 189 | distinct dispatchers. For example, by choosing 2 additional bits (i.e., bits |
| 190 | 6 and 5), the platform can partition into 4 secure priority ranges: ``0x0``, |
| 191 | ``0x20``, ``0x40``, and ``0x60``. See `Interrupt handling example`_. |
| 192 | |
Paul Beesley | ba3ed40 | 2019-03-13 16:20:44 +0000 | [diff] [blame] | 193 | .. note:: |
Jeenu Viswambharan | cbb40d5 | 2017-10-18 14:30:53 +0100 | [diff] [blame] | 194 | |
| 195 | The Arm GIC architecture requires that a GIC implementation that supports two |
| 196 | security states must implement at least 32 priority levels; i.e., at least 5 |
| 197 | upper bits of the 8 bits are writeable. In the scheme described above, when |
| 198 | choosing *n* bits for priority range assignment, the platform must ensure |
| 199 | that at least ``n+1`` top bits of GIC priority are writeable. |
| 200 | |
| 201 | The priority thus assigned to an interrupt is also used to determine the |
| 202 | priority of delegated execution in lower ELs. Delegated execution in lower EL is |
| 203 | associated with a priority level chosen with ``ehf_activate_priority()`` API |
| 204 | (described `later`__). The chosen priority level also determines the interrupts |
| 205 | masked while executing in a lower EL, therefore controls preemption of delegated |
| 206 | execution. |
| 207 | |
| 208 | .. __: `ehf-apis`_ |
| 209 | |
| 210 | The platform expresses the chosen priority levels by declaring an array of |
| 211 | priority level descriptors. Each entry in the array is of type |
| 212 | ``ehf_pri_desc_t``, and declares a priority level, and shall be populated by the |
| 213 | ``EHF_PRI_DESC()`` macro. |
| 214 | |
Paul Beesley | ba3ed40 | 2019-03-13 16:20:44 +0000 | [diff] [blame] | 215 | .. warning:: |
Jeenu Viswambharan | cbb40d5 | 2017-10-18 14:30:53 +0100 | [diff] [blame] | 216 | |
| 217 | The macro ``EHF_PRI_DESC()`` installs the descriptors in the array at a |
| 218 | computed index, and not necessarily where the macro is placed in the array. |
| 219 | The size of the array might therefore be larger than what it appears to be. |
| 220 | The ``ARRAY_SIZE()`` macro therefore should be used to determine the size of |
| 221 | array. |
| 222 | |
Antonio Nino Diaz | 56b68ad | 2019-02-28 13:35:21 +0000 | [diff] [blame] | 223 | Finally, this array of descriptors is exposed to |EHF| via the |
Jeenu Viswambharan | cbb40d5 | 2017-10-18 14:30:53 +0100 | [diff] [blame] | 224 | ``EHF_REGISTER_PRIORITIES()`` macro. |
| 225 | |
| 226 | Refer to the `Interrupt handling example`_ for usage. See also: `Interrupt |
| 227 | Prioritisation Considerations`_. |
| 228 | |
| 229 | Programming priority |
| 230 | ~~~~~~~~~~~~~~~~~~~~ |
| 231 | |
| 232 | The text in `Partitioning priority levels`_ only describes how the platform |
| 233 | expresses the required levels of priority. It however doesn't choose interrupts |
| 234 | nor program the required priority in GIC. |
| 235 | |
Madhukar Pappireddy | 423d18c | 2020-08-06 12:36:17 -0500 | [diff] [blame] | 236 | The :ref:`Firmware Design guide<configuring-secure-interrupts>` explains methods |
| 237 | for configuring secure interrupts. |EHF| requires the platform to enumerate |
| 238 | interrupt properties (as opposed to just numbers) of Secure interrupts. The |
| 239 | priority of secure interrupts must match that as determined in the |
| 240 | `Partitioning priority levels`_ section above. |
Jeenu Viswambharan | cbb40d5 | 2017-10-18 14:30:53 +0100 | [diff] [blame] | 241 | |
| 242 | See `Limitations`_, and also refer to `Interrupt handling example`_ for |
| 243 | illustration. |
| 244 | |
| 245 | Registering handler |
| 246 | ------------------- |
| 247 | |
| 248 | Dispatchers register handlers for their priority levels through the following |
| 249 | API: |
| 250 | |
| 251 | .. code:: c |
| 252 | |
| 253 | int ehf_register_priority_handler(int pri, ehf_handler_t handler) |
| 254 | |
| 255 | The API takes two arguments: |
| 256 | |
| 257 | - The priority level for which the handler is being registered; |
| 258 | |
| 259 | - The handler to be registered. The handler must be aligned to 4 bytes. |
| 260 | |
| 261 | If a dispatcher owns more than one priority levels, it has to call the API for |
| 262 | each of them. |
| 263 | |
| 264 | The API will succeed, and return ``0``, only if: |
| 265 | |
| 266 | - There exists a descriptor with the priority level requested. |
| 267 | |
| 268 | - There are no handlers already registered by a previous call to the API. |
| 269 | |
| 270 | Otherwise, the API returns ``-1``. |
| 271 | |
| 272 | The interrupt handler should have the following signature: |
| 273 | |
| 274 | .. code:: c |
| 275 | |
| 276 | typedef int (*ehf_handler_t)(uint32_t intr_raw, uint32_t flags, void *handle, |
| 277 | void *cookie); |
| 278 | |
Madhukar Pappireddy | 86350ae | 2020-07-29 09:37:25 -0500 | [diff] [blame] | 279 | The parameters are as obtained from the top-level :ref:`EL3 interrupt handler |
| 280 | <el3-runtime-firmware>`. |
Jeenu Viswambharan | cbb40d5 | 2017-10-18 14:30:53 +0100 | [diff] [blame] | 281 | |
Madhukar Pappireddy | 86350ae | 2020-07-29 09:37:25 -0500 | [diff] [blame] | 282 | The :ref:`SDEI dispatcher<SDEI: Software Delegated Exception Interface>`, for |
| 283 | example, expects the platform to allocate two different priority levels— |
| 284 | ``PLAT_SDEI_CRITICAL_PRI``, and ``PLAT_SDEI_NORMAL_PRI`` —and registers the |
| 285 | same handler to handle both levels. |
Jeenu Viswambharan | cbb40d5 | 2017-10-18 14:30:53 +0100 | [diff] [blame] | 286 | |
| 287 | Interrupt handling example |
| 288 | -------------------------- |
| 289 | |
| 290 | The following annotated snippet demonstrates how a platform might choose to |
| 291 | assign interrupts to fictitious dispatchers: |
| 292 | |
| 293 | .. code:: c |
| 294 | |
Antonio Nino Diaz | e0f9063 | 2018-12-14 00:18:21 +0000 | [diff] [blame] | 295 | #include <common/interrupt_props.h> |
| 296 | #include <drivers/arm/gic_common.h> |
Jeenu Viswambharan | cbb40d5 | 2017-10-18 14:30:53 +0100 | [diff] [blame] | 297 | #include <exception_mgmt.h> |
Jeenu Viswambharan | cbb40d5 | 2017-10-18 14:30:53 +0100 | [diff] [blame] | 298 | |
| 299 | ... |
| 300 | |
| 301 | /* |
| 302 | * This platform uses 2 bits for interrupt association. In total, 3 upper |
| 303 | * bits are in use. |
| 304 | * |
| 305 | * 7 6 5 3 0 |
| 306 | * .-.-.-.----------. |
| 307 | * |0|b|b| ..0.. | |
| 308 | * '-'-'-'----------' |
| 309 | */ |
| 310 | #define PLAT_PRI_BITS 2 |
| 311 | |
| 312 | /* Priorities for individual dispatchers */ |
| 313 | #define DISP0_PRIO 0x00 /* Not used */ |
| 314 | #define DISP1_PRIO 0x20 |
| 315 | #define DISP2_PRIO 0x40 |
| 316 | #define DISP3_PRIO 0x60 |
| 317 | |
| 318 | /* Install priority level descriptors for each dispatcher */ |
| 319 | ehf_pri_desc_t plat_exceptions[] = { |
| 320 | EHF_PRI_DESC(PLAT_PRI_BITS, DISP1_PRIO), |
| 321 | EHF_PRI_DESC(PLAT_PRI_BITS, DISP2_PRIO), |
| 322 | EHF_PRI_DESC(PLAT_PRI_BITS, DISP3_PRIO), |
| 323 | }; |
| 324 | |
| 325 | /* Expose priority descriptors to Exception Handling Framework */ |
| 326 | EHF_REGISTER_PRIORITIES(plat_exceptions, ARRAY_SIZE(plat_exceptions), |
| 327 | PLAT_PRI_BITS); |
| 328 | |
| 329 | ... |
| 330 | |
| 331 | /* List interrupt properties for GIC driver. All interrupts target EL3 */ |
| 332 | const interrupt_prop_t plat_interrupts[] = { |
| 333 | /* Dispatcher 1 owns interrupts d1_0 and d1_1, so assigns priority DISP1_PRIO */ |
| 334 | INTR_PROP_DESC(d1_0, DISP1_PRIO, INTR_TYPE_EL3, GIC_INTR_CFG_LEVEL), |
| 335 | INTR_PROP_DESC(d1_1, DISP1_PRIO, INTR_TYPE_EL3, GIC_INTR_CFG_LEVEL), |
| 336 | |
| 337 | /* Dispatcher 2 owns interrupts d2_0 and d2_1, so assigns priority DISP2_PRIO */ |
| 338 | INTR_PROP_DESC(d2_0, DISP2_PRIO, INTR_TYPE_EL3, GIC_INTR_CFG_LEVEL), |
| 339 | INTR_PROP_DESC(d2_1, DISP2_PRIO, INTR_TYPE_EL3, GIC_INTR_CFG_LEVEL), |
| 340 | |
| 341 | /* Dispatcher 3 owns interrupts d3_0 and d3_1, so assigns priority DISP3_PRIO */ |
| 342 | INTR_PROP_DESC(d3_0, DISP3_PRIO, INTR_TYPE_EL3, GIC_INTR_CFG_LEVEL), |
| 343 | INTR_PROP_DESC(d3_1, DISP3_PRIO, INTR_TYPE_EL3, GIC_INTR_CFG_LEVEL), |
| 344 | }; |
| 345 | |
| 346 | ... |
| 347 | |
| 348 | /* Dispatcher 1 registers its handler */ |
| 349 | ehf_register_priority_handler(DISP1_PRIO, disp1_handler); |
| 350 | |
| 351 | /* Dispatcher 2 registers its handler */ |
| 352 | ehf_register_priority_handler(DISP2_PRIO, disp2_handler); |
| 353 | |
| 354 | /* Dispatcher 3 registers its handler */ |
| 355 | ehf_register_priority_handler(DISP3_PRIO, disp3_handler); |
| 356 | |
| 357 | ... |
| 358 | |
| 359 | See also the `Build-time flow`_ and the `Run-time flow`_. |
| 360 | |
Manish Pandey | 9c9f38a | 2020-06-30 00:46:08 +0100 | [diff] [blame] | 361 | .. _Activating and Deactivating priorities: |
| 362 | |
Jeenu Viswambharan | cbb40d5 | 2017-10-18 14:30:53 +0100 | [diff] [blame] | 363 | Activating and Deactivating priorities |
| 364 | -------------------------------------- |
| 365 | |
| 366 | A priority level is said to be *active* when an exception of that priority is |
| 367 | being handled: for interrupts, this is implied when the interrupt is |
Madhukar Pappireddy | 86350ae | 2020-07-29 09:37:25 -0500 | [diff] [blame] | 368 | acknowledged; for non-interrupt exceptions, such as SErrors or :ref:`SDEI |
| 369 | explicit dispatches <explicit-dispatch-of-events>`, this has to be done via |
| 370 | calling ``ehf_activate_priority()``. See `Run-time flow`_. |
Jeenu Viswambharan | cbb40d5 | 2017-10-18 14:30:53 +0100 | [diff] [blame] | 371 | |
| 372 | Conversely, when the dispatcher has reached a logical resolution for the cause |
| 373 | of the exception, the corresponding priority level ought to be deactivated. As |
| 374 | above, for interrupts, this is implied when the interrupt is EOId in the GIC; |
Antonio Nino Diaz | 56b68ad | 2019-02-28 13:35:21 +0000 | [diff] [blame] | 375 | for other exceptions, this has to be done via calling |
Jeenu Viswambharan | cbb40d5 | 2017-10-18 14:30:53 +0100 | [diff] [blame] | 376 | ``ehf_deactivate_priority()``. |
| 377 | |
| 378 | Thanks to `different provisions`__ for exception delegation, there are |
| 379 | potentially more than one work flow for deactivation: |
| 380 | |
| 381 | .. __: `delegation-use-cases`_ |
| 382 | |
| 383 | .. _deactivation workflows: |
| 384 | |
| 385 | - The dispatcher has addressed the cause of the exception, and decided to take |
| 386 | no further action. In this case, the dispatcher's handler deactivates the |
| 387 | priority level before returning to the |EHF|. Runtime firmware, upon exit |
| 388 | through an ``ERET``, resumes execution before the interrupt occurred. |
| 389 | |
| 390 | - The dispatcher has to delegate the execution to lower ELs, and the cause of |
| 391 | the exception can be considered resolved only when the lower EL returns |
Antonio Nino Diaz | 56b68ad | 2019-02-28 13:35:21 +0000 | [diff] [blame] | 392 | signals complete (via an ``SMC``) at a future point in time. The following |
Jeenu Viswambharan | cbb40d5 | 2017-10-18 14:30:53 +0100 | [diff] [blame] | 393 | sequence ensues: |
| 394 | |
| 395 | #. The dispatcher calls ``setjmp()`` to setup a jump point, and arranges to |
| 396 | enter a lower EL upon the next ``ERET``. |
| 397 | |
| 398 | #. Through the ensuing ``ERET`` from runtime firmware, execution is delegated |
| 399 | to a lower EL. |
| 400 | |
Antonio Nino Diaz | 56b68ad | 2019-02-28 13:35:21 +0000 | [diff] [blame] | 401 | #. The lower EL completes its execution, and signals completion via an |
Jeenu Viswambharan | cbb40d5 | 2017-10-18 14:30:53 +0100 | [diff] [blame] | 402 | ``SMC``. |
| 403 | |
| 404 | #. The ``SMC`` is handled by the same dispatcher that handled the exception |
| 405 | previously. Noticing the conclusion of exception handling, the dispatcher |
| 406 | does ``longjmp()`` to resume beyond the previous jump point. |
| 407 | |
| 408 | As mentioned above, the |EHF| provides the following APIs for activating and |
| 409 | deactivating interrupt: |
| 410 | |
| 411 | .. _ehf-apis: |
| 412 | |
| 413 | - ``ehf_activate_priority()`` activates the supplied priority level, but only |
| 414 | if the current active priority is higher than the given one; otherwise |
| 415 | panics. Also, to prevent interruption by physical interrupts of lower |
| 416 | priority, the |EHF| programs the *Priority Mask Register* corresponding to |
| 417 | the PE to the priority being activated. Dispatchers typically only need to |
| 418 | call this when handling exceptions other than interrupts, and it needs to |
| 419 | delegate execution to a lower EL at a desired priority level. |
| 420 | |
| 421 | - ``ehf_deactivate_priority()`` deactivates a given priority, but only if the |
| 422 | current active priority is equal to the given one; otherwise panics. |EHF| |
| 423 | also restores the *Priority Mask Register* corresponding to the PE to the |
| 424 | priority before the call to ``ehf_activate_priority()``. Dispatchers |
| 425 | typically only need to call this after handling exceptions other than |
| 426 | interrupts. |
| 427 | |
| 428 | The calling of APIs are subject to allowed `transitions`__. See also the |
| 429 | `Run-time flow`_. |
| 430 | |
| 431 | .. __: `Transition of priority levels`_ |
| 432 | |
| 433 | Transition of priority levels |
| 434 | ----------------------------- |
| 435 | |
| 436 | The |EHF| APIs ``ehf_activate_priority()`` and ``ehf_deactivate_priority()`` can |
| 437 | be called to transition the current priority level on a PE. A given sequence of |
| 438 | calls to these APIs are subject to the following conditions: |
| 439 | |
| 440 | - For activation, the |EHF| only allows for the priority to increase (i.e. |
| 441 | numeric value decreases); |
| 442 | |
| 443 | - For deactivation, the |EHF| only allows for the priority to decrease (i.e. |
| 444 | numeric value increases). Additionally, the priority being deactivated is |
| 445 | required to be the current priority. |
| 446 | |
| 447 | If these are violated, a panic will result. |
| 448 | |
Madhukar Pappireddy | 86350ae | 2020-07-29 09:37:25 -0500 | [diff] [blame] | 449 | .. _Effect on SMC calls: |
| 450 | |
Jeenu Viswambharan | cbb40d5 | 2017-10-18 14:30:53 +0100 | [diff] [blame] | 451 | Effect on SMC calls |
| 452 | ------------------- |
| 453 | |
| 454 | In general, Secure execution is regarded as more important than Non-secure |
| 455 | execution. As discussed elsewhere in this document, EL3 execution, and any |
| 456 | delegated execution thereafter, has the effect of raising GIC's priority |
| 457 | mask—either implicitly by acknowledging Secure interrupts, or when dispatchers |
| 458 | call ``ehf_activate_priority()``. As a result, Non-secure interrupts cannot |
| 459 | preempt any Secure execution. |
| 460 | |
| 461 | SMCs from Non-secure world are synchronous exceptions, and are mechanisms for |
| 462 | Non-secure world to request Secure services. They're broadly classified as |
| 463 | *Fast* or *Yielding* (see `SMCCC`__). |
| 464 | |
laurenw-arm | 03e7e61 | 2020-04-16 10:02:17 -0500 | [diff] [blame] | 465 | .. __: https://developer.arm.com/docs/den0028/latest |
Jeenu Viswambharan | cbb40d5 | 2017-10-18 14:30:53 +0100 | [diff] [blame] | 466 | |
| 467 | - *Fast* SMCs are atomic from the caller's point of view. I.e., they return |
| 468 | to the caller only when the Secure world has finished serving the request. |
| 469 | Any Non-secure interrupts that become pending meanwhile cannot preempt Secure |
| 470 | execution. |
| 471 | |
| 472 | - *Yielding* SMCs carry the semantics of a preemptible, lower-priority request. |
| 473 | A pending Non-secure interrupt can preempt Secure execution handling a |
| 474 | Yielding SMC. I.e., the caller might observe a Yielding SMC returning when |
| 475 | either: |
| 476 | |
| 477 | #. Secure world completes the request, and the caller would find ``SMC_OK`` |
| 478 | as the return code. |
| 479 | |
| 480 | #. A Non-secure interrupt preempts Secure execution. Non-secure interrupt is |
| 481 | handled, and Non-secure execution resumes after ``SMC`` instruction. |
| 482 | |
| 483 | The dispatcher handling a Yielding SMC must provide a different return code |
| 484 | to the Non-secure caller to distinguish the latter case. This return code, |
| 485 | however, is not standardised (unlike ``SMC_UNKNOWN`` or ``SMC_OK``, for |
| 486 | example), so will vary across dispatchers that handle the request. |
| 487 | |
| 488 | For the latter case above, dispatchers before |EHF| expect Non-secure interrupts |
| 489 | to be taken to S-EL1 [#irq]_, so would get a chance to populate the designated |
| 490 | preempted error code before yielding to Non-secure world. |
| 491 | |
| 492 | The introduction of |EHF| changes the behaviour as described in `Interrupt |
| 493 | handling`_. |
| 494 | |
| 495 | When |EHF| is enabled, in order to allow Non-secure interrupts to preempt |
| 496 | Yielding SMC handling, the dispatcher must call ``ehf_allow_ns_preemption()`` |
| 497 | API. The API takes one argument, the error code to be returned to the Non-secure |
| 498 | world upon getting preempted. |
| 499 | |
| 500 | .. [#irq] In case of GICv2, Non-secure interrupts while in S-EL1 were signalled |
| 501 | as IRQs, and in case of GICv3, FIQs. |
| 502 | |
| 503 | Build-time flow |
| 504 | --------------- |
| 505 | |
| 506 | Please refer to the `figure`__ above. |
| 507 | |
| 508 | .. __: `ehf-figure`_ |
| 509 | |
| 510 | The build-time flow involves the following steps: |
| 511 | |
| 512 | #. Platform assigns priorities by installing priority level descriptors for |
| 513 | individual dispatchers, as described in `Partitioning priority levels`_. |
| 514 | |
| 515 | #. Platform provides interrupt properties to GIC driver, as described in |
| 516 | `Programming priority`_. |
| 517 | |
| 518 | #. Dispatcher calling ``ehf_register_priority_handler()`` to register an |
| 519 | interrupt handler. |
| 520 | |
| 521 | Also refer to the `Interrupt handling example`_. |
| 522 | |
| 523 | Run-time flow |
| 524 | ------------- |
| 525 | |
| 526 | .. _interrupt-flow: |
| 527 | |
| 528 | The following is an example flow for interrupts: |
| 529 | |
| 530 | #. The GIC driver, during initialization, iterates through the platform-supplied |
| 531 | interrupt properties (see `Programming priority`_), and configures the |
| 532 | interrupts. This programs the appropriate priority and group (Group 0) on |
| 533 | interrupts belonging to different dispatchers. |
| 534 | |
| 535 | #. The |EHF|, during its initialisation, registers a top-level interrupt handler |
Madhukar Pappireddy | 86350ae | 2020-07-29 09:37:25 -0500 | [diff] [blame] | 536 | with the :ref:`Interrupt Management Framework<el3-runtime-firmware>` for EL3 |
| 537 | interrupts. This also results in setting the routing bits in ``SCR_EL3``. |
Jeenu Viswambharan | cbb40d5 | 2017-10-18 14:30:53 +0100 | [diff] [blame] | 538 | |
| 539 | #. When an interrupt belonging to a dispatcher fires, GIC raises an EL3/Group 0 |
| 540 | interrupt, and is taken to EL3. |
| 541 | |
| 542 | #. The top-level EL3 interrupt handler executes. The handler acknowledges the |
| 543 | interrupt, reads its *Running Priority*, and from that, determines the |
| 544 | dispatcher handler. |
| 545 | |
| 546 | #. The |EHF| programs the *Priority Mask Register* of the PE to the priority of |
| 547 | the interrupt received. |
| 548 | |
| 549 | #. The |EHF| marks that priority level *active*, and jumps to the dispatcher |
| 550 | handler. |
| 551 | |
| 552 | #. Once the dispatcher handler finishes its job, it has to immediately |
| 553 | *deactivate* the priority level before returning to the |EHF|. See |
| 554 | `deactivation workflows`_. |
| 555 | |
| 556 | .. _non-interrupt-flow: |
| 557 | |
| 558 | The following is an example flow for exceptions that targets EL3 other than |
| 559 | interrupt: |
| 560 | |
| 561 | #. The platform provides handlers for the specific kind of exception. |
| 562 | |
| 563 | #. The exception arrives, and the corresponding handler is executed. |
| 564 | |
| 565 | #. The handler calls ``ehf_activate_priority()`` to activate the required |
| 566 | priority level. This also has the effect of raising GIC priority mask, thus |
| 567 | preventing interrupts of lower priority from preempting the handling. The |
| 568 | handler may choose to do the handling entirely in EL3 or delegate to a lower |
| 569 | EL. |
| 570 | |
| 571 | #. Once exception handling concludes, the handler calls |
| 572 | ``ehf_deactivate_priority()`` to deactivate the priority level activated |
| 573 | earlier. This also has the effect of lowering GIC priority mask to what it |
| 574 | was before. |
| 575 | |
| 576 | Interrupt Prioritisation Considerations |
| 577 | --------------------------------------- |
| 578 | |
| 579 | The GIC priority scheme, by design, prioritises Secure interrupts over Normal |
| 580 | world ones. The platform further assigns relative priorities amongst Secure |
| 581 | dispatchers through |EHF|. |
| 582 | |
| 583 | As mentioned in `Partitioning priority levels`_, interrupts targeting distinct |
Antonio Nino Diaz | 56b68ad | 2019-02-28 13:35:21 +0000 | [diff] [blame] | 584 | dispatchers fall in distinct priority levels. Because they're routed via the |
Jeenu Viswambharan | cbb40d5 | 2017-10-18 14:30:53 +0100 | [diff] [blame] | 585 | GIC, interrupt delivery to the PE is subject to GIC prioritisation rules. In |
| 586 | particular, when an interrupt is being handled by the PE (i.e., the interrupt is |
| 587 | in *Active* state), only interrupts of higher priority are signalled to the PE, |
| 588 | even if interrupts of same or lower priority are pending. This has the side |
| 589 | effect of one dispatcher being starved of interrupts by virtue of another |
| 590 | dispatcher handling its (higher priority) interrupts. |
| 591 | |
| 592 | The |EHF| doesn't enforce a particular prioritisation policy, but the platform |
| 593 | should carefully consider the assignment of priorities to dispatchers integrated |
| 594 | into runtime firmware. The platform should sensibly delineate priority to |
| 595 | various dispatchers according to their nature. In particular, dispatchers of |
| 596 | critical nature (RAS, for example) should be assigned higher priority than |
Paul Beesley | 606d807 | 2019-03-13 13:58:02 +0000 | [diff] [blame] | 597 | others (|SDEI|, for example); and within |SDEI|, Critical priority |
| 598 | |SDEI| should be assigned higher priority than Normal ones. |
Jeenu Viswambharan | cbb40d5 | 2017-10-18 14:30:53 +0100 | [diff] [blame] | 599 | |
| 600 | Limitations |
| 601 | ----------- |
| 602 | |
| 603 | The |EHF| has the following limitations: |
| 604 | |
| 605 | - Although there could be up to 128 Secure dispatchers supported by the GIC |
| 606 | priority scheme, the size of descriptor array exposed with |
| 607 | ``EHF_REGISTER_PRIORITIES()`` macro is currently limited to 32. This serves most |
| 608 | expected use cases. This may be expanded in the future, should use cases |
| 609 | demand so. |
| 610 | |
| 611 | - The platform must ensure that the priority assigned to the dispatcher in the |
| 612 | exception descriptor and the programmed priority of interrupts handled by the |
| 613 | dispatcher match. The |EHF| cannot verify that this has been followed. |
| 614 | |
Paul Beesley | f864067 | 2019-04-12 14:19:42 +0100 | [diff] [blame] | 615 | -------------- |
Jeenu Viswambharan | cbb40d5 | 2017-10-18 14:30:53 +0100 | [diff] [blame] | 616 | |
Imre Kis | c83f720 | 2020-02-03 14:48:21 +0100 | [diff] [blame] | 617 | *Copyright (c) 2018-2020, Arm Limited and Contributors. All rights reserved.* |
Jeenu Viswambharan | cbb40d5 | 2017-10-18 14:30:53 +0100 | [diff] [blame] | 618 | |
Jeenu Viswambharan | cbb40d5 | 2017-10-18 14:30:53 +0100 | [diff] [blame] | 619 | .. _SDEI specification: http://infocenter.arm.com/help/topic/com.arm.doc.den0054a/ARM_DEN0054A_Software_Delegated_Exception_Interface.pdf |