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