Jeenu Viswambharan | cafad7b | 2017-10-18 14:35:20 +0100 | [diff] [blame] | 1 | Software Delegated Exception Interface |
| 2 | ====================================== |
| 3 | |
| 4 | |
| 5 | .. section-numbering:: |
| 6 | :suffix: . |
| 7 | |
| 8 | .. contents:: |
| 9 | :depth: 2 |
| 10 | |
Dan Handley | 4def07d | 2018-03-01 18:44:00 +0000 | [diff] [blame] | 11 | This document provides an overview of the SDEI dispatcher implementation in |
| 12 | Trusted Firmware-A (TF-A). |
Jeenu Viswambharan | cafad7b | 2017-10-18 14:35:20 +0100 | [diff] [blame] | 13 | |
| 14 | Introduction |
| 15 | ------------ |
| 16 | |
Dan Handley | 4def07d | 2018-03-01 18:44:00 +0000 | [diff] [blame] | 17 | `Software Delegated Exception Interface`_ (SDEI) is an Arm specification for |
Jeenu Viswambharan | cafad7b | 2017-10-18 14:35:20 +0100 | [diff] [blame] | 18 | Non-secure world to register handlers with firmware to receive notifications |
| 19 | about system events. Firmware will first receive the system events by way of |
| 20 | asynchronous exceptions and, in response, arranges for the registered handler to |
| 21 | execute in the Non-secure EL. |
| 22 | |
| 23 | Normal world software that interacts with the SDEI dispatcher (makes SDEI |
| 24 | requests and receives notifications) is referred to as the *SDEI Client*. A |
| 25 | client receives the event notification at the registered handler even when it |
| 26 | was executing with exceptions masked. The list of SDEI events available to the |
| 27 | client are specific to the platform [#std-event]_. See also `Determining client |
| 28 | EL`_. |
| 29 | |
| 30 | .. _general SDEI dispatch: |
| 31 | |
| 32 | The following figure depicts a general sequence involving SDEI client executing |
| 33 | at EL2 and an event dispatch resulting from the triggering of a bound interrupt. |
| 34 | A commentary is provided below: |
| 35 | |
| 36 | .. image:: plantuml/sdei_general.svg |
| 37 | |
| 38 | As part of initialisation, the SDEI client binds a Non-secure interrupt [1], and |
| 39 | the SDEI dispatcher returns a platform dynamic event number [2]. The client then |
| 40 | registers a handler for that event [3], enables the event [5], and unmasks all |
| 41 | events on the current PE [7]. This sequence is typical of an SDEI client, but it |
| 42 | may involve additional SDEI calls. |
| 43 | |
| 44 | At a later point in time, when the bound interrupt triggers [9], it's trapped to |
| 45 | EL3. The interrupt is handed over to the SDEI dispatcher, which then arranges to |
| 46 | execute the registered handler [10]. The client terminates its execution with |
| 47 | ``SDEI_EVENT_COMPLETE`` [11], following which the dispatcher resumes the |
| 48 | original EL2 execution [13]. Note that the SDEI interrupt remains active until |
| 49 | the client handler completes, at which point EL3 does EOI [12]. |
| 50 | |
Jeenu Viswambharan | af2c9ec | 2018-01-17 12:30:11 +0000 | [diff] [blame] | 51 | Other than events bound to interrupts (as depicted in the sequence above, SDEI |
| 52 | events can be explicitly dispatched in response to other exceptions, for |
| 53 | example, upon receiving an *SError* or *Synchronous External Abort*. See |
| 54 | `Explicit dispatch of events`_. |
Jeenu Viswambharan | cafad7b | 2017-10-18 14:35:20 +0100 | [diff] [blame] | 55 | |
| 56 | The remainder of this document only discusses the design and implementation of |
Dan Handley | 4def07d | 2018-03-01 18:44:00 +0000 | [diff] [blame] | 57 | SDEI dispatcher in TF-A, and assumes that the reader is familiar with the SDEI |
| 58 | specification, the interfaces, and their requirements. |
Jeenu Viswambharan | cafad7b | 2017-10-18 14:35:20 +0100 | [diff] [blame] | 59 | |
| 60 | .. [#std-event] Except event 0, which is defined by the SDEI specification as a |
| 61 | standard event. |
| 62 | |
| 63 | Defining events |
| 64 | --------------- |
| 65 | |
| 66 | A platform choosing to include the SDEI dispatcher must also define the events |
| 67 | available on the platform, along with their attributes. |
| 68 | |
| 69 | The platform is expected to provide two arrays of event descriptors: one for |
| 70 | private events, and another for shared events. The SDEI dispatcher provides |
| 71 | ``SDEI_PRIVATE_EVENT()`` and ``SDEI_SHARED_EVENT()`` macros to populate the |
| 72 | event descriptors. Both macros take 3 arguments: |
| 73 | |
| 74 | - The event number: this must be a positive 32-bit integer. |
| 75 | |
Jeenu Viswambharan | af2c9ec | 2018-01-17 12:30:11 +0000 | [diff] [blame] | 76 | - For an event that has a backing interrupt, the interrupt number the event is |
| 77 | bound to: |
Jeenu Viswambharan | cafad7b | 2017-10-18 14:35:20 +0100 | [diff] [blame] | 78 | |
| 79 | - If it's not applicable to an event, this shall be left as ``0``. |
| 80 | |
| 81 | - If the event is dynamic, this should be specified as ``SDEI_DYN_IRQ``. |
| 82 | |
| 83 | - A bit map of `Event flags`_. |
| 84 | |
| 85 | To define event 0, the macro ``SDEI_DEFINE_EVENT_0()`` should be used. This |
| 86 | macro takes only one parameter: an SGI number to signal other PEs. |
| 87 | |
Jeenu Viswambharan | af2c9ec | 2018-01-17 12:30:11 +0000 | [diff] [blame] | 88 | To define an event that's meant to be `explicitly dispatched`__ (i.e., not as a |
| 89 | result of receiving an SDEI interrupt), the macro ``SDEI_EXPLICIT_EVENT()`` |
| 90 | should be used. It accepts two parameters: |
| 91 | |
| 92 | .. __: `Explicit dispatch of events`_ |
| 93 | |
| 94 | - The event number (as above); |
| 95 | |
| 96 | - Event priority: ``SDEI_MAPF_CRITICAL`` or ``SDEI_MAPF_NORMAL``, as described |
| 97 | below. |
| 98 | |
Jeenu Viswambharan | cafad7b | 2017-10-18 14:35:20 +0100 | [diff] [blame] | 99 | Once the event descriptor arrays are defined, they should be exported to the |
| 100 | SDEI dispatcher using the ``REGISTER_SDEI_MAP()`` macro, passing it the pointers |
| 101 | to the private and shared event descriptor arrays, respectively. Note that the |
| 102 | ``REGISTER_SDEI_MAP()`` macro must be used in the same file where the arrays are |
| 103 | defined. |
| 104 | |
| 105 | Regarding event descriptors: |
| 106 | |
| 107 | - For Event 0: |
| 108 | |
| 109 | - There must be exactly one descriptor in the private array, and none in the |
| 110 | shared array. |
| 111 | |
| 112 | - The event should be defined using ``SDEI_DEFINE_EVENT_0()``. |
| 113 | |
| 114 | - Must be bound to a Secure SGI on the platform. |
| 115 | |
Jeenu Viswambharan | af2c9ec | 2018-01-17 12:30:11 +0000 | [diff] [blame] | 116 | - Explicit events should only be used in the private array. |
| 117 | |
Jeenu Viswambharan | cafad7b | 2017-10-18 14:35:20 +0100 | [diff] [blame] | 118 | - Statically bound shared and private interrupts must be bound to shared and |
| 119 | private interrupts on the platform, respectively. See the section on |
| 120 | `interrupt configuration`__. |
| 121 | |
| 122 | .. __: `Configuration within Exception Handling Framework`_ |
| 123 | |
| 124 | - Both arrays should be one-dimensional. The ``REGISTER_SDEI_MAP()`` macro |
| 125 | takes care of replicating private events for each PE on the platform. |
| 126 | |
| 127 | - Both arrays must be sorted in the increasing order of event number. |
| 128 | |
| 129 | The SDEI specification doesn't have provisions for discovery of available events |
| 130 | on the platform. The list of events made available to the client, along with |
| 131 | their semantics, have to be communicated out of band; for example, through |
| 132 | Device Trees or firmware configuration tables. |
| 133 | |
| 134 | See also `Event definition example`_. |
| 135 | |
| 136 | Event flags |
| 137 | ~~~~~~~~~~~ |
| 138 | |
| 139 | Event flags describe the properties of the event. They are bit maps that can be |
| 140 | ``OR``\ ed to form parameters to macros that `define events`__. |
| 141 | |
| 142 | .. __: `Defining events`_ |
| 143 | |
| 144 | - ``SDEI_MAPF_DYNAMIC``: Marks the event as dynamic. Dynamic events can be |
Antonio Nino Diaz | 7330861 | 2019-02-28 13:35:21 +0000 | [diff] [blame] | 145 | bound to (or released from) any Non-secure interrupt at runtime via the |
Jeenu Viswambharan | cafad7b | 2017-10-18 14:35:20 +0100 | [diff] [blame] | 146 | ``SDEI_INTERRUPT_BIND`` and ``SDEI_INTERRUPT_RELEASE`` calls. |
| 147 | |
| 148 | - ``SDEI_MAPF_BOUND``: Marks the event as statically bound to an interrupt. |
| 149 | These events cannot be re-bound at runtime. |
| 150 | |
Jeenu Viswambharan | af2c9ec | 2018-01-17 12:30:11 +0000 | [diff] [blame] | 151 | - ``SDEI_MAPF_NORMAL``: Marks the event as having *Normal* priority. This is |
| 152 | the default priority. |
| 153 | |
Jeenu Viswambharan | cafad7b | 2017-10-18 14:35:20 +0100 | [diff] [blame] | 154 | - ``SDEI_MAPF_CRITICAL``: Marks the event as having *Critical* priority. |
Jeenu Viswambharan | cafad7b | 2017-10-18 14:35:20 +0100 | [diff] [blame] | 155 | |
| 156 | Event definition example |
| 157 | ------------------------ |
| 158 | |
| 159 | .. code:: c |
| 160 | |
| 161 | static sdei_ev_map_t plat_private_sdei[] = { |
| 162 | /* Event 0 definition */ |
| 163 | SDEI_DEFINE_EVENT_0(8), |
| 164 | |
| 165 | /* PPI */ |
| 166 | SDEI_PRIVATE_EVENT(8, 23, SDEI_MAPF_BOUND), |
| 167 | |
| 168 | /* Dynamic private events */ |
| 169 | SDEI_PRIVATE_EVENT(100, SDEI_DYN_IRQ, SDEI_MAPF_DYNAMIC), |
| 170 | SDEI_PRIVATE_EVENT(101, SDEI_DYN_IRQ, SDEI_MAPF_DYNAMIC) |
Jeenu Viswambharan | af2c9ec | 2018-01-17 12:30:11 +0000 | [diff] [blame] | 171 | |
| 172 | /* Events for explicit dispatch */ |
| 173 | SDEI_EXPLICIT_EVENT(2000, SDEI_MAPF_NORMAL); |
| 174 | SDEI_EXPLICIT_EVENT(2000, SDEI_MAPF_CRITICAL); |
Jeenu Viswambharan | cafad7b | 2017-10-18 14:35:20 +0100 | [diff] [blame] | 175 | }; |
| 176 | |
| 177 | /* Shared event mappings */ |
| 178 | static sdei_ev_map_t plat_shared_sdei[] = { |
| 179 | SDEI_SHARED_EVENT(804, 0, SDEI_MAPF_DYNAMIC), |
| 180 | |
| 181 | /* Dynamic shared events */ |
| 182 | SDEI_SHARED_EVENT(3000, SDEI_DYN_IRQ, SDEI_MAPF_DYNAMIC), |
| 183 | SDEI_SHARED_EVENT(3001, SDEI_DYN_IRQ, SDEI_MAPF_DYNAMIC) |
| 184 | }; |
| 185 | |
| 186 | /* Export SDEI events */ |
| 187 | REGISTER_SDEI_MAP(plat_private_sdei, plat_shared_sdei); |
| 188 | |
| 189 | Configuration within Exception Handling Framework |
| 190 | ------------------------------------------------- |
| 191 | |
| 192 | The SDEI dispatcher functions alongside the Exception Handling Framework. This |
| 193 | means that the platform must assign priorities to both Normal and Critical SDEI |
| 194 | interrupts for the platform: |
| 195 | |
| 196 | - Install priority descriptors for Normal and Critical SDEI interrupts. |
| 197 | |
| 198 | - For those interrupts that are statically bound (i.e. events defined as having |
| 199 | the ``SDEI_MAPF_BOUND`` property), enumerate their properties for the GIC |
| 200 | driver to configure interrupts accordingly. |
| 201 | |
| 202 | The interrupts must be configured to target EL3. This means that they should |
| 203 | be configured as *Group 0*. Additionally, on GICv2 systems, the build option |
| 204 | ``GICV2_G0_FOR_EL3`` must be set to ``1``. |
| 205 | |
| 206 | See also `SDEI porting requirements`_. |
| 207 | |
| 208 | Determining client EL |
| 209 | --------------------- |
| 210 | |
| 211 | The SDEI specification requires that the *physical* SDEI client executes in the |
| 212 | highest Non-secure EL implemented on the system. This means that the dispatcher |
| 213 | will only allow SDEI calls to be made from: |
| 214 | |
| 215 | - EL2, if EL2 is implemented. The Hypervisor is expected to implement a |
| 216 | *virtual* SDEI dispatcher to support SDEI clients in Guest Operating Systems |
| 217 | executing in Non-secure EL1. |
| 218 | |
| 219 | - Non-secure EL1, if EL2 is not implemented or disabled. |
| 220 | |
| 221 | See the function ``sdei_client_el()`` in ``sdei_private.h``. |
| 222 | |
| 223 | Explicit dispatch of events |
| 224 | --------------------------- |
| 225 | |
| 226 | Typically, an SDEI event dispatch is caused by the PE receiving interrupts that |
| 227 | are bound to an SDEI event. However, there are cases where the Secure world |
| 228 | requires dispatch of an SDEI event as a direct or indirect result of a past |
Antonio Nino Diaz | 7330861 | 2019-02-28 13:35:21 +0000 | [diff] [blame] | 229 | activity, such as receiving a Secure interrupt or an exception. |
Jeenu Viswambharan | cafad7b | 2017-10-18 14:35:20 +0100 | [diff] [blame] | 230 | |
| 231 | The SDEI dispatcher implementation provides ``sdei_dispatch_event()`` API for |
| 232 | this purpose. The API has the following signature: |
| 233 | |
| 234 | :: |
| 235 | |
Jeenu Viswambharan | cdb6ac9 | 2018-02-16 12:07:48 +0000 | [diff] [blame] | 236 | int sdei_dispatch_event(int ev_num); |
Jeenu Viswambharan | cafad7b | 2017-10-18 14:35:20 +0100 | [diff] [blame] | 237 | |
Jeenu Viswambharan | cdb6ac9 | 2018-02-16 12:07:48 +0000 | [diff] [blame] | 238 | The parameter ``ev_num`` is the event number to dispatch. The API returns ``0`` |
| 239 | on success, or ``-1`` on failure. |
Jeenu Viswambharan | cafad7b | 2017-10-18 14:35:20 +0100 | [diff] [blame] | 240 | |
| 241 | The following figure depicts a scenario involving explicit dispatch of SDEI |
| 242 | event. A commentary is provided below: |
| 243 | |
| 244 | .. image:: plantuml/sdei_explicit_dispatch.svg |
| 245 | |
| 246 | As part of initialisation, the SDEI client registers a handler for a platform |
| 247 | event [1], enables the event [3], and unmasks the current PE [5]. Note that, |
| 248 | unlike in `general SDEI dispatch`_, this doesn't involve interrupt binding, as |
| 249 | bound or dynamic events can't be explicitly dispatched (see the section below). |
| 250 | |
| 251 | At a later point in time, a critical event [#critical-event]_ is trapped into |
Jeenu Viswambharan | cdb6ac9 | 2018-02-16 12:07:48 +0000 | [diff] [blame] | 252 | EL3 [7]. EL3 performs a first-level triage of the event, and a RAS component |
| 253 | assumes further handling [8]. The dispatch completes, but intends to involve |
| 254 | Non-secure world in further handling, and therefore decides to explicitly |
| 255 | dispatch an event [10] (which the client had already registered for [1]). The |
| 256 | rest of the sequence is similar to that in the `general SDEI dispatch`_: the |
| 257 | requested event is dispatched to the client (assuming all the conditions are |
| 258 | met), and when the handler completes, the preempted execution resumes. |
Jeenu Viswambharan | 1a0f8f3 | 2017-11-16 12:34:15 +0000 | [diff] [blame] | 259 | |
| 260 | .. [#critical-event] Examples of critical event are *SError*, *Synchronous |
| 261 | External Abort*, *Fault Handling interrupt*, or *Error |
| 262 | Recovery interrupt* from one of RAS nodes in the system. |
| 263 | |
Jeenu Viswambharan | cafad7b | 2017-10-18 14:35:20 +0100 | [diff] [blame] | 264 | Conditions for event dispatch |
| 265 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| 266 | |
| 267 | All of the following requirements must be met for the API to return ``0`` and |
| 268 | event to be dispatched: |
| 269 | |
| 270 | - SDEI events must be unmasked on the PE. I.e. the client must have called |
| 271 | ``PE_UNMASK`` beforehand. |
| 272 | |
| 273 | - Event 0 can't be dispatched. |
| 274 | |
Jeenu Viswambharan | af2c9ec | 2018-01-17 12:30:11 +0000 | [diff] [blame] | 275 | - The event must be declared using the ``SDEI_EXPLICIT_EVENT()`` macro |
| 276 | described above. |
Jeenu Viswambharan | cafad7b | 2017-10-18 14:35:20 +0100 | [diff] [blame] | 277 | |
| 278 | - The event must be private to the PE. |
| 279 | |
| 280 | - The event must have been registered for and enabled. |
| 281 | |
| 282 | - A dispatch for the same event must not be outstanding. I.e. it hasn't already |
| 283 | been dispatched and is yet to be completed. |
| 284 | |
| 285 | - The priority of the event (either Critical or Normal, as configured by the |
| 286 | platform at build-time) shouldn't cause priority inversion. This means: |
| 287 | |
| 288 | - If it's of Normal priority, neither Normal nor Critical priority dispatch |
| 289 | must be outstanding on the PE. |
| 290 | |
| 291 | - If it's of a Critical priority, no Critical priority dispatch must be |
| 292 | outstanding on the PE. |
| 293 | |
| 294 | Further, the caller should be aware of the following assumptions made by the |
| 295 | dispatcher: |
| 296 | |
Jeenu Viswambharan | cdb6ac9 | 2018-02-16 12:07:48 +0000 | [diff] [blame] | 297 | - The caller of the API is a component running in EL3; for example, a RAS |
| 298 | driver. |
Jeenu Viswambharan | cafad7b | 2017-10-18 14:35:20 +0100 | [diff] [blame] | 299 | |
| 300 | - The requested dispatch will be permitted by the Exception Handling Framework. |
| 301 | I.e. the caller must make sure that the requested dispatch has sufficient |
| 302 | priority so as not to cause priority level inversion within Exception |
| 303 | Handling Framework. |
| 304 | |
Jeenu Viswambharan | cdb6ac9 | 2018-02-16 12:07:48 +0000 | [diff] [blame] | 305 | - The caller must be prepared for the SDEI dispatcher to restore the Non-secure |
| 306 | context, and mark that the active context. |
Jeenu Viswambharan | cafad7b | 2017-10-18 14:35:20 +0100 | [diff] [blame] | 307 | |
Jeenu Viswambharan | cdb6ac9 | 2018-02-16 12:07:48 +0000 | [diff] [blame] | 308 | - The call will block until the SDEI client completes the event (i.e. when the |
| 309 | client calls either ``SDEI_EVENT_COMPLETE`` or ``SDEI_COMPLETE_AND_RESUME``). |
Jeenu Viswambharan | cafad7b | 2017-10-18 14:35:20 +0100 | [diff] [blame] | 310 | |
Jeenu Viswambharan | cdb6ac9 | 2018-02-16 12:07:48 +0000 | [diff] [blame] | 311 | - The caller must be prepared for this API to return failure and handle |
| 312 | accordingly. |
Jeenu Viswambharan | cafad7b | 2017-10-18 14:35:20 +0100 | [diff] [blame] | 313 | |
Jeenu Viswambharan | cafad7b | 2017-10-18 14:35:20 +0100 | [diff] [blame] | 314 | Porting requirements |
| 315 | -------------------- |
| 316 | |
| 317 | The porting requirements of the SDEI dispatcher are outlined in the `porting |
| 318 | guide`__. |
| 319 | |
| 320 | .. __: `SDEI porting requirements`_ |
| 321 | |
| 322 | Note on writing SDEI event handlers |
| 323 | ----------------------------------- |
| 324 | |
| 325 | *This section pertains to SDEI event handlers in general, not just when using |
Dan Handley | 4def07d | 2018-03-01 18:44:00 +0000 | [diff] [blame] | 326 | the TF-A SDEI dispatcher.* |
Jeenu Viswambharan | cafad7b | 2017-10-18 14:35:20 +0100 | [diff] [blame] | 327 | |
| 328 | The SDEI specification requires that event handlers preserve the contents of all |
| 329 | registers except ``x0`` to ``x17``. This has significance if event handler is |
| 330 | written in C: compilers typically adjust the stack frame at the beginning and |
| 331 | end of C functions. For example, AArch64 GCC typically produces the following |
| 332 | function prologue and epilogue: |
| 333 | |
| 334 | :: |
| 335 | |
| 336 | c_event_handler: |
| 337 | stp x29, x30, [sp,#-32]! |
| 338 | mov x29, sp |
| 339 | |
| 340 | ... |
| 341 | |
| 342 | bl ... |
| 343 | |
| 344 | ... |
| 345 | |
| 346 | ldp x29, x30, [sp],#32 |
| 347 | ret |
| 348 | |
| 349 | The register ``x29`` is used as frame pointer in the prologue. Because neither a |
| 350 | valid ``SDEI_EVENT_COMPLETE`` nor ``SDEI_EVENT_COMPLETE_AND_RESUME`` calls |
| 351 | return to the handler, the epilogue never gets executed, and registers ``x29`` |
| 352 | and ``x30`` (in the case above) are inadvertently corrupted. This violates the |
| 353 | SDEI specification, and the normal execution thereafter will result in |
| 354 | unexpected behaviour. |
| 355 | |
| 356 | To work this around, it's advised that the top-level event handlers are |
| 357 | implemented in assembly, following a similar pattern as below: |
| 358 | |
| 359 | :: |
| 360 | |
| 361 | asm_event_handler: |
| 362 | /* Save link register whilst maintaining stack alignment */ |
| 363 | stp xzr, x30, [sp, #-16]! |
| 364 | bl c_event_handler |
| 365 | |
| 366 | /* Restore link register */ |
| 367 | ldp xzr, x30, [sp], #16 |
| 368 | |
| 369 | /* Complete call */ |
| 370 | ldr x0, =SDEI_EVENT_COMPLETE |
| 371 | smc #0 |
| 372 | b . |
| 373 | |
| 374 | ---- |
| 375 | |
Dan Handley | 4def07d | 2018-03-01 18:44:00 +0000 | [diff] [blame] | 376 | *Copyright (c) 2017-2018, Arm Limited and Contributors. All rights reserved.* |
Jeenu Viswambharan | cafad7b | 2017-10-18 14:35:20 +0100 | [diff] [blame] | 377 | |
| 378 | .. _SDEI specification: http://infocenter.arm.com/help/topic/com.arm.doc.den0054a/ARM_DEN0054A_Software_Delegated_Exception_Interface.pdf |
| 379 | .. _SDEI porting requirements: porting-guide.rst#sdei-porting-requirements |