(11)ATF中断管理框架

发布时间:2024年01月20日

欢迎关注“安全有理”微信公众号。

安全有理

中断管理框架

中断管理框架负责管理路由到 EL3 的中断,还允许 EL3 软件配置中断的路由行为。其主要实现两个要求:

  1. 当软件在非安全状态(normal world)执行时,该框架需要将由安全软件处理的中断(Secure interrupts)路由到 EL3。然后框改架应根据软件配置和 GIC 实现,将中断控制权交给 EL3 或 Secure-EL1。这确保安全中断在处理过程中处于安全软件的控制之下,而不能受到非安全软件的干预。
  2. 当软件在低于 EL3 异常等级的安全世界中执行时,框架应该可以将打算由非安全软件(Non-secure interrupts)处理的中断路由到非安全世界中最后运行的异常等级。无论软件在 Secure-EL1 还是 Secure-EL0 中执行,应该都能完成此操作,如何选择应由安全软件控制。此要求确保非安全软件能够与安全软件一起执行,而不会将其覆盖。

概念

中断类型

根据处理中断的异常等级,中断管理框架将中断分为几类:

  1. Secure EL1 中断。根据当前执行上下文的安全状态,该中断可以路由到 EL3 或 Secure-EL1,但它始终在 Secure-EL1 中处理。
  2. Non-secure 中断。根据当前执行上下文的安全状态,该中断可以路由到 EL3、Secure-EL1、Non-secure-EL1 或 EL2,但它始终在 Non-secure EL1 或 EL2 中处理。
  3. EL3 中断。根据当前执行上下文的安全状态,该中断可以路由到 EL3 或 Secure-EL1,但它总是在 EL3 中处理。

下面定义了框架实现的各种中断类型。

#define INTR_TYPE_S_EL1      0
#define INTR_TYPE_EL3        1
#define INTR_TYPE_NS         2

路由模型

中断可以作为 FIQ 或 IRQ 生成。中断的目标异常等级是 EL3 Secure Configuration Register(安全配置寄存器SCR)中的 FIQ 和 IRQ 位(SCR_EL3.FIQSCR_EL3.IRQ 位)进行配置的。当SCR_EL3.FIQ=1时,FIQ被路由到EL3,否则路由到能够处理中断的 First Exception Level (FEL)。当 SCR_EL3.IRQ=1 时,IRQ 将路由到 EL3,否则路由至 FEL。在进入较低异常等级之前, EL3 软件已经配置了每个安全状态的SCR。

中断( FIQ 或 IRQ)的路由模型定义为每个安全状态的目标异常等级。对于每个安全状态,它由一个位表示,0表示中断应路由至 FEL,而1表示中断应路由至 EL3。仅当不在 EL3 执行时,路由模型才适用。

中断的默认路由模型是将其路由到任一安全状态下的 FEL。

有效的路由模型

中断管理框架认为中断的某些路由模型是不正确的,因为它们与上面提到的要求相冲突。下面介绍了哪些路由模型是有效的,哪些是无效的。目前只有 GIC 版本 3.0 (Arm GICv3) 支持 EL3 中断,GIC 版本 2.0 (Arm GICv2) 仅支持 Secure-EL1 和 Non-secure 中断。下面是定义的一些术语:

  • CSS:Current Security State(当前安全状态),0表示安全,1表示非安全
  • TEL3:目标异常等级3(Target Exception Level 3),0表示目标异常等级为 FEL,1表示目标异常等级为 EL3

注意:异常等级和安全状态要区分开,不能混淆,Armv8-A包括两种安全状态和四个异常等级。

Secure-EL1中断

  • CSS=0,TEL3=0。当在安全状态执行时,中断将路由至 FEL。这是一个有效的路由模型,因为安全软件控制着安全中断的处理。

  • CSS=0,TEL3=1。当在安全状态执行时,中断被路由到 EL3。这是一个有效的路由模型,因为 EL3 中的安全软件可以将中断移交给 Secure-EL1 进行处理。

  • CSS=1,TEL3=0。当在非安全状态执行时,中断将路由至 FEL。这是一个无效的路由模型,因为这个安全中断对于安全侧软件来说是不可见的,这违反了 Arm Security Extensions 的设计思想。

  • CSS=1,TEL3=1。当在非安全状态执行时,中断被路由到 EL3。这是一个有效的路由模型,因为 EL3 中的安全软件可以将中断移交给 Secure-EL1 进行处理。

Non-secure中断

  • CSS=0,TEL3=0。当在安全状态执行时,中断将路由至 FEL。这允许安全软件捕获非安全中断、执行book-keeping,并通过 EL3 将中断交给非安全软件。这是一种有效的路由模型,因为安全软件决定如何被非安全中断抢占。
  • CSS=0,TEL3=1。当在安全状态执行时,中断被路由到 EL3。这是一种有效的路由模型,因为 EL3 软件在将中断交给非安全软件之前,其可以保存 Secure-EL1/Secure-EL0 中的软件状态。该模型需要 Secure-EL1 和 EL3 软件进行协调,以确保保存了正确的状态。
  • CSS=1,TEL3=0。当在非安全状态执行时,中断将路由至 FEL。这是一种有效的路由模型,因为非安全中断由非安全软件处理。
  • CSS=1,TEL3=1。当在非安全状态执行时,中断被路由到 EL3。这是无效的路由模型,因为没有正当理由将中断路由到 EL3 软件,然后将其交还给非安全软件进行处理。

EL3中断

  • CSS=0,TEL3=0。当在 Secure-EL1/Secure-EL0 中执行时,中断将路由至 FEL。这是一个有效的路由模型,因为 Secure-EL1/Secure-EL0 中运行的软件决定其如何被 EL3 中断抢占,并且可以将中断移交给 EL3 进行处理。但是,当EL3_EXCEPTION_HANDLING为 时1,此路由模型无效,因为 EL3 中断将无条件路由到 EL3,并且 EL3 中断将始终抢占Secure EL1/EL0 执行。请参阅异常处理文档。
  • CSS=0,TEL3=1。当在 Secure-EL1/Secure-EL0 中执行时,中断将路由至 EL3。这是一个有效的路由模型,因为 EL3 中的安全软件可以处理中断。
  • CSS=1,TEL3=0。当执行处于非安全状态时,中断将路由至 FEL。这是一个无效的路由模型,因为这个安全中断对于安全侧软件来说是不可见的,这违反了 Arm Security Extensions 的设计思想。
  • CSS=1,TEL3=1。当执行处于非安全状态时,中断被路由到 EL3。这是一个有效的路由模型,因为 EL3 中的安全软件可以处理中断。

中断信号映射

中断管理框架是在实现的中断控制器下使用。中断控制器可以根据当前的安全状态生成一种中断类型,向 CPU 发送 FIQ 或 IRQ 信号。中断类型和信号之间的映射关系由平台实现确定,这些信息用于是否配置SCR_EL3中的IRQ 或 FIQ 位。平台通过 plat_interrupt_type_to_line()API 提供此信息(在 移植指南中进行了描述)。例如,在 FVP 平台上,当使用 Arm GICv2 中断控制器时,Secure-EL1 中断发出 FIQ 信号,而 Non-secure 中断发出 IRQ 信号,这些运用在任意安全状态。

将多种中断类型映射到同一信号

应当注意,如果将多种中断类型映射到一个中断信号,并且其中任一中断设置TEL3=1,则该中断信号将路由到EL3。这意味着使用相同中断信号的其他类型中断将强制使用相同的路由模型,在选择路由模型时应牢记这一点。

例如,在 Arm GICv3 中,当执行上下文为 Secure-EL1/Secure-EL0 时,EL3 和非安全中断类型都会映射成 FIQ 信号。因此,如果其中任一中断采用此路由模型,即配置CSS=0TEL3=1 ,则在 Secure-EL1/Secure-EL0 中执行时,FIQ 位将被配置,使 FIQ 信号路由到EL3,这会导致其他中断也会路由到 EL3。

中断管理框架中的假设

该框架做出以下假设以简化其实现。

  1. 尽管该框架支持两种类型的安全中断(EL3 和 Secure-EL1 中断),但只有像 Arm GICv3 这样的中断控制器架构才支持 EL3 中断(Group 0中断)。在 Arm GICv2 中,假定所有安全中断都在 Secure-EL1 中处理,它们可以通过 EL3 传给 Secure-EL1,但不能在 EL3 中处理。
  2. 中断异常(PSTATE.IF位)在 EL3 执行期间被屏蔽。
  3. 中断管理:下面描述了中断处理框架如何管理中断,这需要:
    • 提供接口用于注册中断处理程序并指定路由模型
    • 当产生中断时,支持将中断的控制权交给其注册的处理程序

中断管理涉及从 EL3 到 Secure-EL1 安全软件栈中的各个组件,这些在软件组件章节中进行了描述。该框架使用以下结构存储中断的相关信息:

typedef struct intr_type_desc {
        interrupt_type_handler_t handler;
        uint32_t flags;
        uint32_t scr_el3[2];
} intr_type_desc_t;

flags字段的低两位存储中断的路由模型。Bit[0] 存储处于安全状态时的路由模型,Bit[1] 存储处于非安全状态时的路由模型。正如路由模型一节中提到的, 值0意味着中断路由到 FEL ,值1意味着中断路由到 EL3,其余位保留为 SBZ。set_interrupt_rm_flag()宏用于配置flags字段。

scr_el3[2]字段也存储路由模型,但作为flags字段(两种安全状态)到SCR_EL3位(FIQ或者IRQ位)的映射,即如从NS和Secure路由到EL3,NS路由到EL1/EL2,Secure路由到S-EL1等等。

该框架还依赖于平台来配置中断控制器,用以区分安全和非安全中断。平台必须知道系统中的安全设备及其关联的中断号。平台应该配置中断控制器以启用安全中断,确保安全中断优先级始终高于非安全中断,并将其路由到主 CPU。平台还应该导出移植指南中关于中断处理的接口。

在本文档的其余部分中,为了简单起见,只考虑了 Arm GICv2 系统,并假设 FIQ 信号用于生成 Secure-EL1 中断,IRQ 信号用于生成非安全中断,不考虑 EL3 中断。

软件组件

中断管理组件在 EL3 和 Secure-EL1 中功能不同:

  • EL3 Runtime Firmware。该组件对于所有平台移植 TF-A 是通用的。

  • Secure Payload Dispatcher (SPD) 服务。该服务与在 Secure-EL1/Secure-EL0 中运行的 Secure Payload (SP) 软件进行通信,负责安全与非安全状态的切换。切换通过 Secure Monitor Call 触发,其通过上下文管理库导出的 API 来实现。在两种安全状态之间切换执行也是中断管理的要求,这导致严重依赖 SPD 服务。TF-A 实现了一个示例 Test Secure Payload Dispatcher (TSPD) 服务。

    一个SPD 服务是集成到 EL3 runtime firmware 中,并且可以与某些平台移植 TF-A 是通用的。

  • Secure Payload (SP)。Secure Payload 对应于在 Secure-EL1/Secure-EL0 中运行的 Secure OS。它与 SPD 服务交互,管理与非安全软件间的通信。TF-A 实现了一个 Test Secure Payload 示例,其仅在Secure-EL1 中运行。

    Secure payload 对于某些平台移植 TF-A 是通用的,就像 SPD 服务一样。

中断注册

本节详细描述了中断软件组件的作用。

EL3 runtime firmware

该组件为中断处理的原型声明。

typedef uint64_t (*interrupt_type_handler_t)(uint32_t id,
                                             uint32_t flags,
                                             void *handle,
                                             void *cookie);

其中id参数是保留的,未来用于传递最高挂起中断 id,目前值为INTR_ID_UNAVAILABLE

flags参数含义如下:

  • Security,bits[0]:该位表示中断生成时较低异常等级的安全状态。1表示处于非安全状态,0表示它处于安全状态。中断处理程序使用此位进行中断路由。
  • Reserved,bits[31:1]:其余位保留。

handle参数指向当前安全状态的cpu_context上下文。

一旦中断处理程序执行完成,将返回到安全或非安全状态。中断处理程序必须返回指向目标安全状态的cpu_context指针。在 AArch64 上,调用者目前会忽略此返回值,因为处理程序应当通过上下文管理库 API 设置相应的值,移植中断处理程序必须设置目标上下文结构。中断处理程序应将所有错误条件视为严重错误,并采取适当的操作,例如使用断言失败。

Runtime firmware 提供以下 API,用于注册中断的处理程序。Secure Payload Dispatcher 服务应使用此 API 来注册 Secure-EL1 的处理程序,并可选择用于非安全中断,该API还要求调用者指定中断的路由模型。

int32_t register_interrupt_type_handler(uint32_t type,
                                        interrupt_type_handler handler,
                                        uint64_t flags);

type参数可以是上面列出的三种中断类型,即INTR_TYPE_S_EL1INTR_TYPE_NSINTR_TYPE_EL3

注册成功后该函数将返回0,如果中断处理程序已经注册,它将返回-EALREADY。如果type无法识别或flagshandler无效,则会返回-EINVAL

在任一安全状态下,SCR_EL3.FIQ/IRQ位控制中断路由,即路由到当前异常等级还是EL3。上下文管理库为每个CPU的安全状态维护了一个SCR_EL3系统寄存器副本。 EL3 运行时固件可以使用下面API,检索当前 CPU 每个安全状态的路由模型。在从 EL3 执行异常返回时,el3_exit()函数利用cpu_context保存的SCR_EL3值来配置 SCR_EL3寄存器 。

uint32_t cm_get_scr_el3(uint32_t security_state);
void cm_write_scr_el3_bit(uint32_t security_state,
                          uint32_t bit_pos,
                          uint32_t value);

cm_get_scr_el3()返回当前 CPU 安全状态的SCR_EL3寄存器值。cm_write_scr_el3_bit()0or1 写入位bit_pos,即SCR_EL3寄存器中的相应位。函数register_interrupt_type_handler()调用 set_routing_model()API,配置SCR_EL3寄存器,完成路由模型的设置。

值得注意的是,在当前框架的实现中,EL3 Runtime Firmware 负责配置路由模型,SPD 负责确保在收到中断时遵守此路由模型。

Secure payload dispatcher

SPD服务负责确定和维护其自身和Secure Payload支持的中断路由模型,它还根据路由模型在安全和非安全软件之间传送中断,可以在构建时或运行时确定路由模型。它必须使用这些信息来注册中断处理程序,使用register_interrupt_type_handler()API。

如果 SPD 服务在构建时不知道路由模型,则 SP 初始化完成后必须提供。SPD应该在SP初始化完成之后对路由模型进行配置,例如在初始化函数bl32_init中。

SPD 应在收到来自 EL3 runtime firmware 的中断后将控制权传递给 Secure Payload,该信息可以在编译时提供给 SPD 服务,也可以由 SP 在运行时提供。

Test secure payload dispatcher行为

TSPD 仅处理 Secure-EL1 中断,并在编译时提供以下路由模型。

  • 当执行处于非安全状态时,Secure-EL1 中断将路由到 EL3;当执行处于安全状态时,Secure-EL1 中断将路由到 FEL。即对于Secure-EL1 中断, CSS=0、TEL3=0CSS=1、TEL3=1
  • 当编译标志TSP_NS_INTR_ASYNC_PREEMPT为0时,Non-secure 中断使用默认路由模型。对于 Non-secure 中断,在任一安全状态下都路由到 FEL,即CSS=0、TEL3=0CSS=1、TEL3=0。(这种情况下:Non-secure中断将在Secure-EL1 IRQ 异常向量处触发)
  • 当编译标志TSP_NS_INTR_ASYNC_PREEMPT被定义为1时,当执行处于安全状态时,Non-secure 中断强制被路由到EL3,即对于 Non-secure 中断CSS=0,TEL3=1,这事实上抢占了 Secure-EL1。此时默认路由模型只用于非安全状态下的非安全中断,即CSS=1,TEL3=0

通过执行函数tspd_init()来满足前面提到的要求。

  1. 它将控制权传递给 Test Secure Payload 以执行初始化。TSP 提供了 SP 中向量表的地址tsp_vectors ,其还包括 Secure-EL1 的中断处理程序sel1_intr_entry。当 TSPD 接收到 Secure-EL1 中断时,它会将控制权传递给该地址处的 TSP。

    当调用tsp_sel1_intr_entry()时,要求TSPD屏蔽所有中断(PSTATE.DAIF位)。TSP 必须保存被调用者的通用寄存器、SP_EL1/Secure-EL0、LR、VFP 和系统寄存器,可以用 x0-x18启用 C runtime。

  2. TSPD 实现 Secure-EL1 中断的处理函数,该函数使用 register_interrupt_type_handler() API 注册到 EL3 runtime firmware,如下所示:

    /* Forward declaration */
    interrupt_type_handler tspd_secure_el1_interrupt_handler;
    int32_t rc, flags = 0;
    set_interrupt_rm_flag(flags, NON_SECURE); // 这里NON_SECURE表示生成中断时PE在非安全状态执行
    rc = register_interrupt_type_handler(INTR_TYPE_S_EL1,
                                     tspd_secure_el1_interrupt_handler,
                                     flags);
    if (rc)
        panic();
    
  3. 当编译标志TSP_NS_INTR_ASYNC_PREEMPT定义为 1 时,TSPD 实现非安全中断的处理函数。同样,如下所示:

    /* Forward declaration */
    interrupt_type_handler tspd_ns_interrupt_handler;
    int32_t rc, flags = 0;
    set_interrupt_rm_flag(flags, SECURE); // 这里SECURE表示生成中断时PE在安全状态执行
    rc = register_interrupt_type_handler(INTR_TYPE_NS,
                                    tspd_ns_interrupt_handler,
                                    flags);
    if (rc)
        panic();
    

Secure payload

Secure payload 必须在 Secure-EL1 (Secure-EL1 IHF) 上实现中断处理框架,以支持其选择的中断路由模型。Secure payload 将在以下情况之间交替执行。

  1. 在启用 IRQ、FIQ 中断的代码中,如果中断路由到 FEL,则它将使用 Secure-EL1 异常向量表。这被定义为处理中断的异步模式,该模式适用于 Secure-EL1 和 non-secure 中断。
  2. 在禁用IRQ、FIQ 中断的代码中,如果中断路由到 FEL,则执行最终将切换到非安全状态。任何非安全中断都将按照路由模型中所述进行处理,其中CSS=1 且 TEL3=0。Secure-EL1 中断将被路由到 EL3(根据CSS=1 和 TEL3=1 的路由模型),其中 SPD 服务会将它们交给 SP。这被定义为处理中断的同步模式

SP 实现的中断处理框架应该支持这些中断处理模型中的一种或两种,具体取决于所选的路由模型。

以下列表简要描述了有效路由模型的选择(请参阅有效路由模型)如何影响 Secure-EL1 IHF 的实现。如果 SPD 服务在编译时不知道中断路由模型的选择,则 SP 应在运行时的初始化阶段将此信息传递给 SPD 服务。

如前所述,考虑了 Arm GICv2 系统,并假设 FIQ 信号用于生成 Secure-EL1 中断,IRQ 信号用于在任一安全状态下生成非安全中断。

针对secure- EL1 中断的 Secure payload IHF 设计

  1. CSS=0,TLE3=0。如果PSTATE.F=0,Secure-EL1 中断将进入 Secure-EL1 FIQ 异常向量。Secure-EL1 IHF 应实现支持处理异步 FIQ 中断。

    如果PSTATE.F=1,此时 Secure-EL1 中断将按照同步中断处理模型进行处理。在注册阶段,SP 可以将 Secure-EL1 中断入口点导出给到 SPD 服务。SPD 服务还需要了解系统的状态,通用目的以及PSTATE状态。如果 SPD 服务在构建时不知道该信息,则 SP 应在注册阶段以实现定义的方式提供此信息。

  2. CSS=1,TEL3=1。当执行处于非安全状态时,中断将路由至 EL3。它们应该通过上面 1 中描述的同步中断处理模型来处理。

  3. CSS=0,TEL3=1。当执行处于安全状态时,Secure-EL1 中断将路由至 EL3,这对 SP 不可见。Secure-EL1/Secure-EL0 中的PSTATE.F位不会屏蔽 FIQ。EL3 运行时固件将调用 SPD 服务为 Secure-EL1 中断注册处理程序。然后,Secure-EL1 IHF 应通过上面 1 中描述的同步中断处理模型来处理所有 Secure-EL1 中断。

针对non-secure 中断的 Secure payload IHF 设计

  1. CSS=0,TEL3=0。如果是PSTATE.I=0,非安全中断将进入 Secure-EL1 IRQ 异常向量。Secure-EL1 IHF 应与 SPD 服务协调,转移到非安全状态处理中断,例如 SP 可以分配一个ID以向 SPD 服务发出 SMC64 或 SMC32,以指示 SP 执行已被非安全中断抢占。如果 SPD 服务在编译时不知道此ID,则 SP 可以在注册阶段提供。

    如果PSTATE.I=1那么非安全中断将挂起,直到在非安全状态下恢复执行。

  2. CSS=0,TEL3=1。非安全中断被路由到 EL3,这对 SP 不可见。Secure-EL1/Secure-EL0 中的位PSTATE.I将不起作用。SPD 服务应注册一个非安全中断处理程序,该处理程序应正确保存 SP 状态,并在非安全状态下恢复执行处理中断。Secure-EL1 IHF 不需要采取任何操作。

  3. CSS=1,TEL3=0。非安全中断在非安全状态 (EL1/EL2) 的 FEL 中处理,并且对 SP 不可见。此路由模型不影响 SP 行为。

Secure Payload 还必须确保所有 Secure-EL1 中断在中断控制器上进行正确配置,它还应该配置 EL3 runtime firmware 无法识别的其他 Secure-EL1 中断。

Test secure payload行为

TSP 选择的 Secure-EL1 和 non-secure 中断的路由模型在Secure Payload Dispatcher部分中进行了描述,TSPD 服务在编译时就知道。

TSP 实现了一个中断处理入口 ( tsp_sel1_intr_entry()),用于处理在非安全状态下发生并通过 TSPD 服务(同步处理模型)路由的 Secure-EL1 中断。它通过 tsp_vectors将对此入口点传递给 TSPD 服务。

通过变量early_exceptions,TSP 还会替换默认的异常向量表,替换成 Secure-EL1 异常等级发生的 FIQ 和 IRQ 异常向量表。该表通过变量tsp_exceptions引用并配置到 VBAR_EL1 中,它适合异步处理模型。

TSP 还在 Arm 通用定时器模块中对 Secure Physical Timer 进行配置,以引发周期性中断(每半秒),以测试软件组件中的中断管理。

中断处理

本节详细描述了每个软件组件(请参阅软件组件一节)在中断处理时的作用。

EL3 runtime firmware

EL3 runtime firmware使用runtime_exceptions配置IRQ 和 FIQ 异常向量,如下所示。

  1. SP_EL0SP_EL3类型的 IRQ 和 FIQ 异常上报为错误,不进行处理。如前所述,EL3 runtime firmware执行时,PSTATE.IPSTATE.F位均置位。
  2. 下面描述了在较低异常等级下触发IRQ和FIQ异常时,如何使用 AArch64 或 AArch32 进行处理。

当产生中断时,每个中断向量负责:

  1. 在异常进入时立即保存整个通用寄存器上下文 (x0-x30),这些寄存器保存在cpu_context上下文结构体中。

  2. ELR_EL3SP_EL0和系统寄存器保存在cpu_context上下文结构体中。

  3. cpu_context数据结构中恢复CTX_RUNTIME_SP,切换 C 运行时堆栈,执行msr spsel, #0指令。

  4. 确定中断类型。Secure-EL1 中断以 FIQ 发出信号,Non-secure 中断以 IRQ 发出信号。平台应实现以下 API 来确定待处理中断的类型。

    uint32_t plat_ic_get_interrupt_type(void);
    

    它应该返回INTR_TYPE_S_EL1INTR_TYPE_NS

  5. 确定已生成中断的处理程序,为此添加了以下 API。

    interrupt_type_handler get_interrupt_type_handler(uint32_t interrupt_type);
    

    它返回此中断的注册处理程序。中断处理程序handler从上面提到的intr_type_desc_t中获取。如果没有为此类的中断注册处理程序,则返回NULL,这种情况被报告为不可恢复的错误。

  6. 为生成的中断调用注册的处理函数。该id参数当前设置为INTR_ID_UNAVAILABLE。当前安全状态的 id 和cpu_context_t 均通过参数传递给处理函数。

    中断处理程序函数返回目标安全状态的cpu_context_t

  7. 调用el3_exit()从 EL3 执行异常返回,该el3_exit() 函数负责从 cpu_context_t目标安全状态的数据结构中恢复寄存器上下文。

Secure payload dispatcher

中断进入

当 EL3 runtime firmware 调用中断的处理函数时,SPD 服务开始处理该中断。SPD 服务负责以下工作:

  1. 验证中断。确保中断是按照 SPD 服务在注册期间指定的中断路由模型生成的,其通过中断发生时异常等级的安全状态(flags参数)来判断。如果中断无法识别,处理程序应将其视为不可恢复的错误情形。

    SPD 服务可以注册 Secure-EL1 或 Non-secure 中断的处理程序。Non-secure 中断不应该从非安全状态路由到 EL3。此外,如果在 Secure 状态下执行时,将 Secure-EL1 中断路由到 S-EL1,S-EL1 中断也不应从 Secure 状态路由到 EL3。中断处理程序可以使用安全状态标志来检查这一点。

  2. 确定是否需要上下文切换。这取决于路由模型和中断类型,对于非安全中断和 S-EL1 中断,如果产生中断的执行上下文的安全状态与处理中断所需的安全状态不同,则需要进行上下文切换。以下两种情况需要执行从安全到非安全的上下文切换,反之亦然:

    • 从非安全状态获取的 Secure-EL1 中断应路由到 Secure Payload.。
    • 从安全状态获取的非安全中断应路由到最后已知的非安全异常等级。

    SPD服务必须保存当前安全状态的系统寄存器上下文,然后恢复目标安全状态的系统寄存器上下文,使用cm_set_next_eret_context()API来保证要恢复的目标安全状态。

    如果目标状态是安全的,则同步中断的处理模型将执行交给 SP。当在 SP 中执行时,Secure-EL1 中断可以路由到 EL3。这意味着在处理中断时,SP 执行可以被另一个更高优先级的 Secure-EL1 中断或 EL3 中断抢占。SPD 服务需要在将控制权交给 SP 之前处理此抢占或管理安全中断优先级。

  3. 如果中断通过验证并准备进入低异常等级处理,处理程序需要设置异常返回的上下文cpu_context

路由模型允许非安全中断抢占 Secure-EL1 执行(如果已配置)。SPD 服务和 SP 应该实现一种机制,用于将这些中断路由到非安全状态下最后的已知异常等级。SPD 服务应该保存 SP上下文,恢复非安全上下文并准备进入非安全状态,以便处理中断。

中断退出

当 Secure Payload 处理 完成 Secure-EL1 中断时,它可以通过 SMC32 或 SMC64 将控制权返回给 SPD 服务。SPD 服务应处理此 secure monitor 调用,恢复以前的异常等级和安全状态,继续执行。

TSPD对于 Secure-EL1 的中断处理

TSPD 示例服务注册了一个 Secure-EL1 中断处理程序(中断触发来自 non-secure 状态)。在 S-EL1 中执行期间,TSPD 期望 Secure-EL1 中断由 TSP 在 S-EL1 中处理。中断处理程序 tspd_secure_el1_interrupt_handler()仅期望被来自非安全状态的 Secure-EL1 中断调用,当调用时会执行以下操作。

  1. 使用flags参数中提供的安全状态来确保安全中断来自非安全状态。如果情况并非如此,它会断言。
  2. 调用cm_el1_sysregs_context_save(NON_SECURE); 保存非安全状态的系统寄存器上下文。
  3. tsp_sel1_intr_entry配置到ELR_EL3系统寄存器,并设置安全 CPU 上下文中 SPSR_EL3.DAIF位。设置x0TSP_HANDLE_SEL1_INTR_AND_RETURN。 如果在 yielding类型的 SMC 处理期间 TSP 被非安全中断抢占,为了能够重新进入 TSP 进行 Secure-EL1 中断处理,请保存将被丢弃的寄存器,即ELR_EL3SRSR_EL3。它不需要保存任何其他安全上下文,因为 TSP 应该保留它。
  4. 调用 cm_el1_sysregs_context_restore(SECURE);恢复安全状态系统寄存器上下文。
  5. 调用cm_set_next_eret_context(SECURE);设置从EL3异常返回的 CPU 上下文为Secure。
  6. 返回待进入的CPU上下文cpu_context,指示 SP 现在可以处理该中断。x1elr_el3 非安全状态寄存器的值,SP 使用此信息进行调试。

下图描述了在非安全状态下执行,生成 Secure-EL1 中断时, TSPD 如何实现中断处理。

SPD对于Secure-EL1中断的处理

TSP 发出ID为TSP_HANDLED_S_EL1_INTR的SMC来表示中断处理已完成。

TSPD 服务在接收到TSP_HANDLED_S_EL1_INTR的SMC后,在函数tspd_smc_handler()里执行以下操作:

  1. 确保调用来自安全状态,否则执行将返回到非安全状态,x0值为SMC_UNK
  2. 恢复保存的ELR_EL3SPSR_EL3系统寄存器,回到安全 CPU 上下文,以防 TSP 之前被非安全中断抢占。
  3. 调用cm_el1_sysregs_context_restore(NON_SECURE)恢复非安全状态的系统寄存器上下文。
  4. 调用cm_set_next_eret_context(NON_SECURE)设置下一异常等级的非安全 CPU 上下文。
  5. tspd_smc_handler()返回对非安全的上下文指针cpu_context

TSPD对于 non-secure 的中断处理

Secure-EL1 中的 TSP 可以在yielding类型 SMC 调度处理期间被非安全中断抢占,或者在 Secure-EL1 中断处理期间被更高优先级的 EL3 中断抢占。当EL3_EXCEPTION_HANDLINGis 时0,只有非安全中断才能导致 TSP 抢占,因为系统中没有 EL3 中断。然而EL3_EXCEPTION_HANDLING=1,任何 EL3 中断都可能抢占Secure执行。

应该注意的是,当 TSP 被抢占时,TSPD 仅允许进入 TSP 以进行 Secure-EL1 中断处理,或者恢复被抢占的yielding类型 SMC,以响应来自非安全世界的 SMC(TSP_FID_RESUME)。

在调用yielding类型 SMC 处理期间,在 Secure-EL1 中触发的非安全中断可以路由到 EL3 或 Secure-EL1,并由编译控制TSP_NS_INTR_ASYNC_PREEMPT。如果设置了该编译选项,TSPD 将设置路由模型:非安全中断从安全状态路由到 EL3,即TEL3=1、CSS=0,并注册非安全中断处理程序tspd_ns_interrupt_handler()tspd_ns_interrupt_handler()确保中断源来自安全状态,并禁止将非安全中断从安全状态路由到 EL3。当TSP重新进入处理Secure-EL1中断(在非安全世界触发生成的)时,这样做可以防止被非安全中断进一步抢占,然后tspd_ns_interrupt_handler()调用 tspd_handle_sp_preemption()进一步处理。

如果TSP_NS_INTR_ASYNC_PREEMPT编译选项为零(默认),则安全状态下非安全中断的默认路由模型生效,即TEL3=0, CSS=0。在yielding类型 SMC 处理期间,IRQ 异常不会被屏蔽PSTATE.I=0,即非安全中断将在 Secure-EL1 IRQ 异常向量处触发。TSP 保存通用寄存器上下文,并发出TSP_PREEMPTED的 SMC 作为抢占 TSP 的信号。TSPD SMC 处理程序 tspd_smc_handler()保证 SMC 调用来自安全状态,否则执行将返回到非安全状态。然后它调用tspd_handle_sp_preemption()进一步处理。

tspd_handle_sp_preemption()调用后会执行以下操作:

  1. 调用cm_el1_sysregs_context_save(SECURE)来保存安全状态的系统寄存器上下文。
  2. 调用cm_el1_sysregs_context_restore(NON_SECURE)恢复非安全状态的系统寄存器上下文。
  3. 调用cm_set_next_eret_context(NON_SECURE)设置下一异常等级的非安全 CPU 上下文。
  4. 在恢复非安全上下文后,设置x0SMC_PREEMPTED,返回到非安全状态。

yielding类型 SMC 被抢占后,通过发出TSP_FID_RESUME的SMC,非安全世界期望恢复TSP。TSPD 服务在收到此 SMC 后将采取以下操作:

  1. 确保调用来自非安全状态,否则会断言。
  2. 检查 TSP 是否需要恢复,即检查它是否被抢占。然后调用cm_el1_sysregs_context_save(NON_SECURE)保存非安全状态的系统寄存器上下文。
  3. 调用 cm_el1_sysregs_context_restore(SECURE)恢复安全上下文。
  4. 调用cm_set_next_eret_context(SECURE)设置下一异常等级的安全 CPU 上下文。
  5. tspd_smc_handler()返回安全的上下文指针cpu_context

下图描述了当编译标志TSP_NS_INTR_ASYNC_PREEMPT为 0 时,TSP/TSPD 如何处理在 TSP 执行期间生成且PSTATE.I= 0 的非安全中断。

SPD对于non-secure中断的处理

SP中断处理

SP 应实现同步或者异步中断处理模型。

在同步模型中,在 SPD 服务跳转到入口点后,开始处理 Secure-EL1 中断。在处理中断之前,SP 应保存 Secure-EL1 系统寄存器上下文,例如SPSR_EL1ELR_EL1,这些上下文在稍后 SP 恢复正常执行时需要。在完成处理中断后,SP 可以返回到中断发生的异常等级和安全状态,SP 应使用 SMC32 或 SMC64 来要求 SPD 服务来实现这一点。

在异步模型中,当PSTATE.IPSTATE.F位为0时,Secure Payload 负责处理非安全和 Secure-EL1 中断。如前所述,当生成非安全中断时, SP 应与 SPD 服务协调,将控制权传递回最后已知异常等级中的非安全状态,这将允许在非安全状态下处理非安全中断。

TSP行为

TSPD 将 Secure-EL1 中断的控制权交给TSP的 tsp_sel1_intr_entry()。TSP 处理中断,同时确保维护Test secure payload dispatcher behavior部分中描述的切换协议。它调用 tsp_update_sync_sel1_intr_stats()更新一些统计数据,然后调用 tsp_common_int_handler()

  1. 检查中断是否为安全物理定时器中断。它使用plat_ic_get_pending_interrupt_id()API来获取中断号。如果不是安全物理定时器中断,则意味着更高优先级的中断已抢占它。通过发出TSP_PREEMPTED的SMC,调用tsp_handle_preemption()将控制权移交回 EL3。
  2. 使用 plat_ic_acknowledge_interrupt() API 确认安全定时器中断,调用 tsp_generic_timer_handler()对安全物理通用定时器重新配置,以及调用plat_ic_end_of_interrupt() API 发出中断处理结束信号。

发出TSP_HANDLED_S_EL1_INTR的SMC,TSP 将控制权传递回 TSPD 。

在异步模型下 TSP 处理中断如下:

  1. Secure-EL1 中断通过调用该tsp_common_int_handler() 函数来处理,上面已经描述了该功能。
  2. 非安全中断通过调用tsp_common_int_handler(),最终调用tsp_handle_preemption()并发出TSP_PREEMPTED的SMC64。当 TSPD 响应来自非安全状态的SMC, 并将控制权移交给 TSP 时,执行将在该 SMC 指令之后恢复。

其他考虑

抢占 SMC 对非安全软件的影响

对Secure payload的yieldingSMC调用可以被非安全中断抢占,并且执行可以返回到非安全世界来处理中断。在这种情况下,SMC 调用尚未完成,并且执行必须返回到secure payload以恢复抢占的 SMC 调用。这可以通过请求 SMC 调用,恢复被强占的 SMC 实现。

fast类型的SMC无法被抢占,因此对于快速 SMC 调用不会发生这种情况。

在 Test Secure Payload 实现中,TSP_FID_RESUME设计为恢复 SMC FID。值得注意的是,TSP_FID_RESUME是一个 yieldingSMC,这意味着它也可以被抢占。假设处于非安全状态P.STATE.I=0,请求yielding SMC 的典型非安全软件流程如下:

int rc;
rc = smc(TSP_YIELD_SMC_FID, ...);     /* Issue a Yielding SMC call */
/* The pending non-secure interrupt is handled by the interrupt handler
   and returns back here. */
while (rc == SMC_PREEMPTED) {       /* Check if the SMC call is preempted */
    rc = smc(TSP_FID_RESUME);       /* Issue resume SMC call */
}

TSP_YIELD_SMC_FIDyieldingSMC ID,smc() 函数使用所需参数进行 SMC 调用。挂起的非安全中断会导致 IRQ 异常,进行非安全中断处理,并返回。检查 SMC 调用的返回值SMC_PREEMPTED判断它是否被抢占。如果是,则发出恢复 SMC 调用TSP_FID_RESUME,然后再次检查SMC调用的返回值,检查是否被抢占。这是递归完成的,直到 SMC 调用成功或失败。如果yielding SMC 被抢占,则在使用TSP_FID_RESUMESMC 恢复并完成之前,当前 TSPD 会阻止任何重新进入TSP的其他 SMC 调用,并返回SMC_UNK错误。

文章来源:https://blog.csdn.net/qq_16106195/article/details/135719482
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。