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