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