4.13.SDEI: Software Delegated Exception Interface

This document provides an overview of the SDEI dispatcher implementation inTrusted Firmware-A (TF-A).

4.13.1.Introduction

Software Delegated Exception Interface (SDEI) is an Arm specification forNon-secure world to register handlers with firmware to receive notificationsabout system events. Firmware will first receive the system events by way ofasynchronous exceptions and, in response, arranges for the registered handler toexecute in the Non-secure EL.

Normal world software that interacts with the SDEI dispatcher (makes SDEIrequests and receives notifications) is referred to as theSDEI Client. Aclient receives the event notification at the registered handler even when itwas executing with exceptions masked. The list of SDEI events available to theclient are specific to the platform[1]. See alsoDetermining clientEL.

The following figure depicts a general sequence involving SDEI client executingat EL2 and an event dispatch resulting from the triggering of a bound interrupt.A commentary is provided below:

/' ' Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. ' ' SPDX-License-Identifier: BSD-3-Clause '/@startumlautonumber "<b>[#]</b>"participant "SDEI client" as EL2participant EL3participant "SDEI interrupt source" as SDEIactivate EL2EL2->EL3: **SDEI_INTERRUPT_BIND**(irq)EL3->EL2: event number: evEL2->EL3: **SDEI_EVENT_REGISTER**(ev, handler, ...)EL3->EL2: successEL2->EL3: **SDEI_EVENT_ENABLE**(ev)EL3->EL2: successEL2->EL3: **SDEI_PE_UNMASK**()EL3->EL2: 1... <<Business as usual>> ...SDEI-->EL3: SDEI interruptactivate SDEI #salmonactivate EL3 #rednote over EL3: Prepare SDEI dispatchEL3->EL2: dispatchactivate EL2 #salmonnote over EL2: SDEI handlerEL2->EL3: **SDEI_EVENT_COMPLETE()**deactivate EL2note over EL3: Complete SDEI dispatchEL3-->SDEI: EOIdeactivate SDEIEL3->EL2: resumes preempted executiondeactivate EL3... <<Normal execution resumes>> ...@enduml

As part of initialisation, the SDEI client binds a Non-secure interrupt [1], andthe SDEI dispatcher returns a platform dynamic event number [2]. The client thenregisters a handler for that event [3], enables the event [5], and unmasks allevents on the current PE [7]. This sequence is typical of an SDEI client, but itmay involve additional SDEI calls.

At a later point in time, when the bound interrupt triggers [9], it’s trapped toEL3. The interrupt is handed over to the SDEI dispatcher, which then arranges toexecute the registered handler [10]. The client terminates its execution withSDEI_EVENT_COMPLETE [11], following which the dispatcher resumes theoriginal EL2 execution [13]. Note that the SDEI interrupt remains active untilthe client handler completes, at which point EL3 does EOI [12].

Other than events bound to interrupts, as depicted in the sequence above, SDEIevents can be explicitly dispatched in response to other exceptions, forexample, upon receiving anSError orSynchronous External Abort. SeeExplicit dispatch of events.

The remainder of this document only discusses the design and implementation ofSDEI dispatcher in TF-A, and assumes that the reader is familiar with the SDEIspecification, the interfaces, and their requirements.

4.13.2.Defining events

A platform choosing to include the SDEI dispatcher must also define the eventsavailable on the platform, along with their attributes.

The platform is expected to provide two arrays of event descriptors: one forprivate events, and another for shared events. The SDEI dispatcher providesSDEI_PRIVATE_EVENT() andSDEI_SHARED_EVENT() macros to populate theevent descriptors. Both macros take 3 arguments:

  • The event number: this must be a positive 32-bit integer.

  • For an event that has a backing interrupt, the interrupt number the event isbound to:

    • If it’s not applicable to an event, this shall be left as0.

    • If the event is dynamic, this should be specified asSDEI_DYN_IRQ.

  • A bit map ofEvent flags.

To define event 0, the macroSDEI_DEFINE_EVENT_0() should be used. Thismacro takes only one parameter: an SGI number to signal other PEs.

To define an event that’s meant to be explicitly dispatched (i.e., not as aresult of receiving an SDEI interrupt), the macroSDEI_EXPLICIT_EVENT()should be used. It accepts two parameters:

  • The event number (as above);

  • Event priority:SDEI_MAPF_CRITICAL orSDEI_MAPF_NORMAL, as describedbelow.

Once the event descriptor arrays are defined, they should be exported to theSDEI dispatcher using theREGISTER_SDEI_MAP() macro, passing it the pointersto the private and shared event descriptor arrays, respectively. Note that theREGISTER_SDEI_MAP() macro must be used in the same file where the arrays aredefined.

Regarding event descriptors:

  • For Event 0:

    • There must be exactly one descriptor in the private array, and none in theshared array.

    • The event should be defined usingSDEI_DEFINE_EVENT_0().

    • Must be bound to a Secure SGI on the platform.

  • Explicit events should only be used in the private array.

  • Statically bound shared and private interrupts must be bound to shared andprivate interrupts on the platform, respectively. See the section onConfiguration within Exception Handling Framework.

  • Both arrays should be one-dimensional. TheREGISTER_SDEI_MAP() macrotakes care of replicating private events for each PE on the platform.

  • Both arrays must be sorted in the increasing order of event number.

The SDEI specification doesn’t have provisions for discovery of available eventson the platform. The list of events made available to the client, along withtheir semantics, have to be communicated out of band; for example, throughDevice Trees or firmware configuration tables.

See alsoEvent definition example.

4.13.2.1.Event flags

Event flags describe the properties of the event. They are bit maps that can beORed to form parameters to macros that define events (seeDefining events).

  • SDEI_MAPF_DYNAMIC: Marks the event as dynamic. Dynamic events can bebound to (or released from) any Non-secure interrupt at runtime via theSDEI_INTERRUPT_BIND andSDEI_INTERRUPT_RELEASE calls.

  • SDEI_MAPF_BOUND: Marks the event as statically bound to an interrupt.These events cannot be re-bound at runtime.

  • SDEI_MAPF_NORMAL: Marks the event as havingNormal priority. This isthe default priority.

  • SDEI_MAPF_CRITICAL: Marks the event as havingCritical priority.

4.13.3.Event definition example

staticsdei_ev_map_tplat_private_sdei[]={/* Event 0 definition */SDEI_DEFINE_EVENT_0(8),/* PPI */SDEI_PRIVATE_EVENT(8,23,SDEI_MAPF_BOUND),/* Dynamic private events */SDEI_PRIVATE_EVENT(100,SDEI_DYN_IRQ,SDEI_MAPF_DYNAMIC),SDEI_PRIVATE_EVENT(101,SDEI_DYN_IRQ,SDEI_MAPF_DYNAMIC)/* Events for explicit dispatch */SDEI_EXPLICIT_EVENT(2000,SDEI_MAPF_NORMAL);SDEI_EXPLICIT_EVENT(2000,SDEI_MAPF_CRITICAL);};/* Shared event mappings */staticsdei_ev_map_tplat_shared_sdei[]={SDEI_SHARED_EVENT(804,0,SDEI_MAPF_DYNAMIC),/* Dynamic shared events */SDEI_SHARED_EVENT(3000,SDEI_DYN_IRQ,SDEI_MAPF_DYNAMIC),SDEI_SHARED_EVENT(3001,SDEI_DYN_IRQ,SDEI_MAPF_DYNAMIC)};/* Export SDEI events */REGISTER_SDEI_MAP(plat_private_sdei,plat_shared_sdei);

4.13.4.Configuration within Exception Handling Framework

The SDEI dispatcher functions alongside the Exception Handling Framework. Thismeans that the platform must assign priorities to both Normal and Critical SDEIinterrupts for the platform:

  • Install priority descriptors for Normal and Critical SDEI interrupts.

  • For those interrupts that are statically bound (i.e. events defined as havingtheSDEI_MAPF_BOUND property), enumerate their properties for the GICdriver to configure interrupts accordingly.

    The interrupts must be configured to target EL3. This means that they shouldbe configured asGroup 0. Additionally, on GICv2 systems, the build optionGICV2_G0_FOR_EL3 must be set to1.

See alsoSDEI porting requirements.

4.13.5.Determining client EL

The SDEI specification requires that thephysical SDEI client executes in thehighest Non-secure EL implemented on the system. This means that the dispatcherwill only allow SDEI calls to be made from:

  • EL2, if EL2 is implemented. The Hypervisor is expected to implement avirtual SDEI dispatcher to support SDEI clients in Guest Operating Systemsexecuting in Non-secure EL1.

  • Non-secure EL1, if EL2 is not implemented or disabled.

See the functionsdei_client_el() insdei_private.h.

4.13.6.Explicit dispatch of events

Typically, an SDEI event dispatch is caused by the PE receiving interrupts thatare bound to an SDEI event. However, there are cases where the Secure worldrequires dispatch of an SDEI event as a direct or indirect result of a pastactivity, such as receiving a Secure interrupt or an exception.

The SDEI dispatcher implementation providessdei_dispatch_event() API forthis purpose. The API has the following signature:

intsdei_dispatch_event(intev_num);

The parameterev_num is the event number to dispatch. The API returns0on success, or-1 on failure.

The following figure depicts a scenario involving explicit dispatch of SDEIevent. A commentary is provided below:

/' ' Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. ' ' SPDX-License-Identifier: BSD-3-Clause '/@startumlautonumber "<b>[#]</b>"participant "SDEI client" as EL2participant EL3participant SDEIparticipant "RAS Driver" as RASactivate EL2EL2->EL3: **SDEI_EVENT_REGISTER**(ev, handler, ...)EL3->EL2: successEL2->EL3: **SDEI_EVENT_ENABLE**(ev)EL3->EL2: successEL2->EL3: **SDEI_PE_UNMASK**()EL3->EL2: 1... <<Business as usual>> ...EL3<--]: **CRITICAL EVENT**activate EL3 #rednote over EL3: Critical event triageEL3->RAS: dispatch to handledeactivate EL3activate RAS #salmonnote over RAS: Critical event handlingRAS-->SDEI: sdei_dispatch_event(ev)deactivate RASactivate SDEI #salmonnote over SDEI: Prepare SDEI dispatchSDEI->EL2: dispatchactivate EL2 #salmonnote over EL2: SDEI handlerEL2->SDEI: **SDEI_EVENT_COMPLETE()**deactivate EL2note over SDEI: Complete SDEI dispatchSDEI-->RAS: returndeactivate SDEIactivate RAS #salmonRAS->EL3: error handling donedeactivate RASEL3->EL2: resumes preempted execution... <<Normal execution resumes>> ...@enduml

As part of initialisation, the SDEI client registers a handler for a platformevent [1], enables the event [3], and unmasks the current PE [5]. Note that,unlike ingeneral SDEI dispatch, this doesn’t involve interrupt binding, asbound or dynamic events can’t be explicitly dispatched (see the section below).

At a later point in time, a critical event[2] is trapped intoEL3 [7]. EL3 performs a first-level triage of the event, and a RAS componentassumes further handling [8]. The dispatch completes, but intends to involveNon-secure world in further handling, and therefore decides to explicitlydispatch an event [10] (which the client had already registered for [1]). Therest of the sequence is similar to that in thegeneral SDEI dispatch: therequested event is dispatched to the client (assuming all the conditions aremet), and when the handler completes, the preempted execution resumes.

4.13.6.1.Conditions for event dispatch

All of the following requirements must be met for the API to return0 andevent to be dispatched:

  • SDEI events must be unmasked on the PE. I.e. the client must have calledPE_UNMASK beforehand.

  • Event 0 can’t be dispatched.

  • The event must be declared using theSDEI_EXPLICIT_EVENT() macrodescribed above.

  • The event must be private to the PE.

  • The event must have been registered for and enabled.

  • A dispatch for the same event must not be outstanding. I.e. it hasn’t alreadybeen dispatched and is yet to be completed.

  • The priority of the event (either Critical or Normal, as configured by theplatform at build-time) shouldn’t cause priority inversion. This means:

    • If it’s of Normal priority, neither Normal nor Critical priority dispatchmust be outstanding on the PE.

    • If it’s of a Critical priority, no Critical priority dispatch must beoutstanding on the PE.

Further, the caller should be aware of the following assumptions made by thedispatcher:

  • The caller of the API is a component running in EL3; for example, a RASdriver.

  • The requested dispatch will be permitted by the Exception Handling Framework.I.e. the caller must make sure that the requested dispatch has sufficientpriority so as not to cause priority level inversion within ExceptionHandling Framework.

  • The caller must be prepared for the SDEI dispatcher to restore the Non-securecontext, and mark that the active context.

  • The call will block until the SDEI client completes the event (i.e. when theclient calls eitherSDEI_EVENT_COMPLETE orSDEI_COMPLETE_AND_RESUME).

  • The caller must be prepared for this API to return failure and handleaccordingly.

4.13.7.Porting requirements

The porting requirements of the SDEI dispatcher are outlined in thePorting Guide.

4.13.8.Note on writing SDEI event handlers

This section pertains to SDEI event handlers in general, not just when usingthe TF-A SDEI dispatcher.

The SDEI specification requires that event handlers preserve the contents of allregisters exceptx0 tox17. This has significance if event handler iswritten in C: compilers typically adjust the stack frame at the beginning andend of C functions. For example, AArch64 GCC typically produces the followingfunction prologue and epilogue:

c_event_handler:stpx29,x30,[sp,#-32]!movx29,sp...bl......ldpx29,x30,[sp],#32ret

The registerx29 is used as frame pointer in the prologue. Because neither avalidSDEI_EVENT_COMPLETE norSDEI_EVENT_COMPLETE_AND_RESUME callsreturn to the handler, the epilogue never gets executed, and registersx29andx30 (in the case above) are inadvertently corrupted. This violates theSDEI specification, and the normal execution thereafter will result inunexpected behaviour.

To work this around, it’s advised that the top-level event handlers areimplemented in assembly, following a similar pattern as below:

asm_event_handler:/*Savelinkregisterwhilstmaintainingstackalignment*/stpxzr,x30,[sp,#-16]!blc_event_handler/*Restorelinkregister*/ldpxzr,x30,[sp],#16/*Completecall*/ldrx0,=SDEI_EVENT_COMPLETEsmc#0b.

4.13.9.Security Considerations

SDEI introduces concept of providing software based non-maskable interrupts toHypervisor/OS. In doing so, it modifies the priority scheme defined by Interruptcontrollers and relies on Non-Secure clients, Hypervisor or OS, to create/managehigh priority events.

Considering a Non-secure client is involved in SDEI state management, there existssome security considerations which needs to be taken care of in both client and EL3when using SDEI. Few of them are mentioned below.

4.13.9.1.Bound events

A bound event is an SDEI event that corresponds to a client interrupt.The binding of event is done usingSDEI_INTERRUPT_BIND SMC call to associatean SDEI event with a client interrupt. There is a possibility that a rogueclient can request an invalid interrupt to be bound. This may potentiallycause out-of-bound memory read.

Even though TF-A implementation has checks to ensure that interrupt ID passedby client is architecturally valid, Non-secure client should also ensure thevalidity of interrupts.

4.13.9.2.Recurring events

For a given event source, if the events are generated continuously, then NS clientmay be unusable. To mitigate against this, the Non-secure client must havemechanism in place to remove such interrupt source from the system.

One of the examples is a memory region which continuously generates RAS errors.This may result in unusable Non-secure client.

4.13.9.3.Dispatched events

For a dispatched event, it is the client’s responsibility to ensure that thehandling finishes in finite time and notify the dispatcher throughSDEI_EVENT_COMPLETE orSDEI_EVENT_COMPLETE_AND_RESUME. If the clientfails to complete the event handling, it might result inUNPREDICTABLE behaviorin the client and potentially end up in unusable PE.

Copyright (c) 2017-2024, Arm Limited and Contributors. All rights reserved.

Footnotes

[1]

Except event 0, which is defined by the SDEI specification as astandard event.

[2]

Examples of critical events areSError,SynchronousExternal Abort,Fault Handling interrupt orErrorRecovery interrupt from one of RAS nodes in the system.