在ARM架构的嵌入式系统中,软件委托异常接口(Software Delegated Exception Interface,简称SDEI)提供了一种高效的事件处理机制。这种机制允许将特定事件(如硬件错误、看门狗定时器触发等)从固件层委托给操作系统或应用程序处理,实现了异常处理的灵活分层。
SDEI的核心设计理念是通过状态机来精确管理事件处理流程。这种状态机模型定义了三种基础状态和若干衍生状态,配合handler-running属性,构成了完整的事件生命周期管理体系。与传统的硬件中断处理相比,SDEI具有以下显著优势:
提示:SDEI事件处理通常运行在EL1或EL2异常级别,具体取决于系统配置和虚拟化需求。在设计事件处理程序时,需要特别注意异常级别的上下文切换开销。
SDEI状态机定义了三种基础状态,每种状态都有明确的语义和转换规则:
未注册状态(handler-unregistered)
已注册状态(handler-registered)
已启用状态(handler-enabled)
状态转换通过特定的接口调用触发,以下是主要的状态转换路径:
注册转换:
code复制handler-unregistered → SDEI_EVENT_REGISTER → handler-registered
启用转换:
code复制handler-registered → SDEI_EVENT_ENABLE → handler-enabled
禁用转换:
code复制handler-enabled → SDEI_EVENT_DISABLE → handler-registered
注销转换:
code复制handler-registered → SDEI_EVENT_UNREGISTER → handler-unregistered
handler-enabled → SDEI_EVENT_UNREGISTER → handler-unregistered
下表总结了主要状态转换关系:
| 当前状态 | 接口调用 | 下一状态 |
|---|---|---|
| handler-unregistered | SDEI_EVENT_REGISTER | handler-registered |
| handler-registered | SDEI_EVENT_ENABLE | handler-enabled |
| handler-registered | SDEI_EVENT_UNREGISTER | handler-unregistered |
| handler-enabled | SDEI_EVENT_DISABLE | handler-registered |
| handler-enabled | SDEI_EVENT_UNREGISTER | handler-unregistered |
handler-running是SDEI状态机的一个重要属性,表示事件处理程序正在某个处理单元(PE)上执行。当handler-running为TRUE时,会衍生出三种特殊状态:
未注册待处理状态(handler-unregister-pending)
已注册且运行状态(handler-registered and handler-running)
已启用且运行状态(handler-enabled and handler-running)
handler-running属性会在以下情况下发生变化:
不同状态下可用的接口调用存在严格限制,这是SDEI设计的重要约束条件。以下是各状态下可用的主要接口调用:
| 事件状态 | 可用接口调用 |
|---|---|
| handler-unregistered | SDEI_EVENT_REGISTER, SDEI_INTERRUPT_RELEASE |
| handler-unregister-pending | SDEI_EVENT_CONTEXT, SDEI_EVENT_COMPLETE, SDEI_EVENT_COMPLETE_AND_RESUME |
| handler-registered | SDEI_EVENT_STATUS, SDEI_EVENT_ENABLE, SDEI_EVENT_DISABLE, SDEI_EVENT_GET_INFO, SDEI_EVENT_ROUTING_SET |
| handler-registered and handler-running | SDEI_EVENT_CONTEXT, SDEI_EVENT_COMPLETE, SDEI_EVENT_COMPLETE_AND_RESUME |
| handler-enabled | SDEI_EVENT_STATUS, SDEI_EVENT_ENABLE, SDEI_EVENT_DISABLE, SDEI_EVENT_GET_INFO, SDEI_EVENT_UNREGISTER |
| handler-enabled and handler-running | SDEI_EVENT_CONTEXT, SDEI_EVENT_COMPLETE, SDEI_EVENT_COMPLETE_AND_RESUME |
部分接口调用不受状态限制,可在任何状态下使用:
注意:SDEI_EVENT_GET_INFO的可用性取决于参数设置,在某些参数组合下可能不可用。
SDEI事件分发器仅在满足以下所有条件时才会分发事件:
如果上述任一条件不满足,事件将保持pending状态,直到所有条件满足为止。对于同一优先级类别的多个pending事件,分发顺序由具体实现定义。
SDEI事件分为私有事件和共享事件,两者的分发逻辑有所不同:
c复制Dispatcher(Client C) {
For each P in PE {
For each E in PrivateEvents {
if (IsSignaled(E, P) &&
IsEnabled(E, P) &&
IsUnmasked(P) &&
((IsCriticalEvent(E) && !CriticalEventRunning(P, C)) ||
(!IsCriticalEvent(E) && !EventRunning(P, C)))) {
// 分发事件到处理程序
}
}
}
}
c复制Dispatcher(Client C) {
For each P in PE {
For each E in SharedEvents {
if (IsSignaled(E) &&
IsEnabled(E) &&
IsEventTarget(E, P) &&
IsUnmasked(P) &&
((IsCriticalEvent(E) && !CriticalEventRunning(P, C)) ||
(!IsCriticalEvent(E) && !EventRunning(P, C)))) {
// 分发事件到处理程序
}
}
}
}
对于重复触发的事件,SDEI有以下处理规则:
SDEI与PSCI的协同工作确保了在各种电源状态下事件处理的可靠性:
上电序列(Power-on):
关机序列(CPU_OFF):
挂起到内存(CPU_SUSPEND with powerdown):
挂起到待机(CPU_SUSPEND with standby):
SDEI处理程序中允许调用部分PSCI功能,最小支持集合包括:
在SDEI处理程序中调用SYSTEM_RESET、SYSTEM_OFF、CPU_OFF和CPU_FREEZE会隐式完成所有SDEI处理程序,然后执行电源操作。
这种模式适用于看门狗定时器、性能分析器等场景,典型流程如下:
这种模式下,事件的启用/禁用操作会直接启用/禁用物理中断,适合分发器提供服务的情况。
这种模式适用于错误处理等复杂场景,典型流程如下:
在这种模式下,事件的启用/禁用操作仅影响对客户端的事件生成,即使客户端禁用事件,分发器仍可处理事件。
在虚拟化环境中,运行在hypervisor下的客户OS可以注册虚拟SDEI事件。存在两级委托:
hypervisor处理物理事件时有三种选择:
虚拟事件的共享行为由具体hypervisor实现决定,某些实现可能允许共享物理事件分发给多个客户OS。
在GICv2系统中实现SDEI需要考虑以下要点:
GICv3提供了更灵活的中断分组机制:
在Secure EL1处理Secure Group 1中断时,可以通过以下方式确保SDEI事件处理:
SDEI ACPI表(表签名'SDEI')通告平台固件或hypervisor实现的SDEI接口存在,主要字段包括:
在解析APEI HEST表的GHES条目时,操作系统应使用SDEI调用注册使用SDEI作为通知方法的事件(通知类型11)。事件号存储在vector字段中。
在实际开发中,使用SDEI时需要注意以下关键点:
事件处理程序设计:
状态管理最佳实践:
电源管理集成:
错误处理:
性能考量:
在调试SDEI相关问题时,可以重点关注以下方面: