【ARM中文手册】第十二章 Interrupt Handling

文摘   2024-11-20 07:25   上海  

12.Interrupt Handling


旧版本的ARM架构允许实现者在设计外部中断控制器时有相当大的自由度,未对中断的数量或类型以及用于与中断控制器块接口的软件模型达成一致。通用中断控制器版本2(GIC)架构提供了更为严格的规范,不同制造商之间的中断控制器具有更高的一致性。这使得中断处理程序代码更加可移植。

12.1 External interrupt requests

所有ARM核心具有两种外部中断请求,分别为FIQ和IRQ。这两者都是敏感电平的主动低输入。各个实现有中断控制器,接受来自各种外部源的中断请求,并将其映射到FIQ或IRQ,从而使核心触发异常。

一般来说,只有当相应的CPSR禁用位(F和I位)清零并且对应输入被激活时,才能触发中断异常。CPS指令提供了一种简单的机制来启用或禁用由CPSR的A、I和F位控制的异常(异步中止、IRQ和FIQ)。

CPS IE或CPS ID将分别启用或禁用异常。要启用或禁用的异常使用一个或多个字母A、I和F来指定。省略相应字母的异常将不会被修改。

在Cortex-A系列处理器中,可以配置核心,使得FIQ无法被软件屏蔽。这称为不可屏蔽FIQ,由在核心复位时采样的硬件配置输入信号控制。触发FIQ异常时,它们仍会自动被屏蔽。

12.1.1 Assigning interrupts

系统始终会有一个中断控制器,接受并仲裁来自多个源的中断。这个控制器通常包含多个寄存器,使得在核心上运行的软件能够屏蔽单个中断源、确认来自外部设备的中断、为单个中断源分配优先级,以及确定当前哪些中断源请求关注或需要服务。

这个中断控制器可以是特定于系统的设计,也可以是ARM通用中断控制器(GIC)架构的实现。

12.1.2 Simplistic interrupt handling

这代表了最简单的中断处理程序。在接收到中断时,禁用相同类型的额外中断,直到稍后显式启用。我们只能在处理第一个中断请求完成后才能处理额外的中断,此时没有机会处理更高优先级或更紧急的中断。这通常不适合复杂的嵌入式系统,但在转向更现实的示例之前,检查这个示例是有用的,这里是一个不可重入的中断处理程序。

处理中断的步骤如下:

  1. 外部硬件引发一个IRQ异常。核心自动执行多个步骤。当前执行模式下的PC内容被存储在LR_IRQ中。CPSR寄存器的内容被复制到SPSR_IRQ。CPSR的内容被更新,以使模式位反映IRQ模式,并将I位设置为屏蔽额外的IRQ。PC被设置为向量表中的IRQ入口。

  2. 向量表中IRQ入口处的指令(跳转到中断处理程序)被执行。

  3. 中断处理程序保存被中断程序的上下文,也就是说,将会被处理程序破坏的寄存器压入栈中。这些寄存器将在处理程序执行完毕后从栈中弹出。

  4. 中断处理程序确定必须处理的中断源,并调用相应的设备驱动程序。

  5. 通过将SPSR_IRQ复制到CPSR,准备核心切换回之前的执行状态,并恢复之前保存的上下文,最后从LR_IRQ恢复PC。

    相同的步骤也适用于FIQ中断。
    下面的示例展示了一个非常简单的中断处理程序。

12.1.3 Nested interrupt handling

嵌套中断处理是指软件在处理当前中断之前,已经准备好接受另一个中断。这使得您可以对中断进行优先级排序,并在增加复杂性的情况下显著提高高优先级事件的延迟。值得注意的是,嵌套中断处理是软件做出的选择,依赖于中断优先级配置和中断控制,而不是由硬件强加的。

可重入的中断处理程序必须保存IRQ状态,然后切换核心模式,并保存新核心模式的状态,才能在启用中断的情况下跳转到嵌套的子例程或C函数。这是因为新的中断可以在任何时候发生,这将导致核心存储新中断的返回地址并覆盖原始中断。当原始中断尝试返回到主程序时,会导致系统失败。为了防止这种情况,嵌套处理程序必须在重新启用中断之前切换到另一种内核模式。

注 :
如果一个计算机程序能够在执行过程中被中断,并在先前版本完成之前再次调用,则该程序是可重入的。

在上图中,SPSR的值在重新启用中断之前必须保存。如果没有保存,任何新的中断都将覆盖SPSR_irq的值。解决方法是使用以下指令在重新启用中断之前将SPSR压栈:

SRSFD sp!, #0x12

此外,在中断处理程序代码中使用BL指令会导致LR_IRQ损坏。解决方法是在使用BL指令之前切换到Supervisor模式。

因此,可重入的中断处理程序在IRQ异常被触发并且控制权按照先前描述的方式转移到中断处理程序后,必须执行以下步骤:

  1. 中断处理程序保存被中断程序的上下文(也就是说,它将任何可能被处理程序破坏的寄存器,包括返回地址和SPSR_IRQ,压入替代内核模式栈中)。

  2. 它确定需要处理的中断源,并在外部硬件中清除该源(防止其立即触发另一个中断)。

  3. 中断处理程序切换到核心SVC模式,同时保持CPSR I位置位(中断仍然被禁用)。

  4. 中断处理程序将异常返回地址保存到栈中(新的内核模式的栈,位于内核内存中)并重新启用中断。

  5. 它调用适当的处理程序代码。

  6. 完成后,中断处理程序禁用IRQ并将异常返回地址从栈中弹出。

  7. 它直接从替代内核模式栈中恢复被中断程序的上下文。这包括恢复PC和CPSR,从而切换回之前的执行模式。如果SPSR没有设置I位,那么该操作还会重新启用中断。
    嵌套中断处理程序(针对非向量中断)的示例代码见下面的示例。

12.2 The Generic Interrupt Controller

GIC(通用中断控制器)架构定义了一套硬件资源,用于管理单核或多核系统中的中断。GIC提供了内存映射的寄存器,用于管理中断源和行为,并且(在多核系统中)用于将中断路由到各个核心。它使得软件可以屏蔽、启用和禁用来自单个源的中断,硬件上对单个源进行优先级排序,并生成软件中断。GIC还支持第21章安全中描述的TrustZone安全扩展。GIC接受在系统级别断言的中断,并可以将它们传送到连接的每个核心,可能导致触发IRQ或FIQ异常。

从软件的角度来看,GIC有两个主要功能模块:

  • 分配器(Distributor)
    系统中的所有中断源都与分配器连接。分配器有寄存器来控制单个中断的属性,如优先级、状态、安全性、路由信息和启用状态。分配器决定将哪个中断通过连接的CPU接口转发到核心。

  • CPU接口(CPU Interface)
    核心通过此接口接收中断。CPU接口有寄存器来屏蔽、识别和控制转发到该核心的中断状态。系统中的每个核心都有一个独立的CPU接口。

在软件中,中断通过一个编号标识,称为中断ID。中断ID唯一对应一个中断源。软件可以使用中断ID识别中断源,并调用相应的处理程序来服务该中断。向软件提供的具体中断ID由系统设计决定。

中断可以分为几种不同的类型:

  • 软件生成中断(SGI)
    这是由软件通过写入专用分配器寄存器(软件生成中断寄存器,ICDSGIR)明确生成的。它最常用于核心间通信。SGI可以面向系统中的所有核心或特定核心组。中断编号0-15为此保留。用于通信的具体中断编号由软件决定。

  • 私有外设中断(PPI)
    这是由专用于某个核心的外设生成的。中断编号16-31为此保留。这些编号用于标识该核心私有的中断源,与另一个核心上的相同源无关,例如每核心定时器。

  • 共享外设中断(SPI)
    这是由中断控制器可以路由到多个核心的外设生成的。中断编号32-1020用于此类中断。SPI用于向系统中所有核心可访问的外设信号中断。

中断可以是边沿触发(当中断控制器检测到相关输入上的上升沿时被认为是触发的,直到清除为止)或电平敏感(仅当中断控制器的相关输入为高电平时被认为是触发的)。

一个中断可以处于以下几种状态:

  • 非活动状态(Inactive):表示中断尚未触发。

  • 挂起状态(Pending):表示中断源已触发,但正在等待由核心处理。挂起的中断是可以转发到CPU接口并随后传递给核心的候选者。

  • 活动状态(Active):表示中断已被核心确认,当前正在被处理。

  • 活动和挂起状态(Active and pending):表示核心正在处理中断,但GIC仍然有来自同一来源的挂起中断。

中断的优先级以及可以传递到的核心列表都在分配器中配置。当外设向分配器触发中断时,该中断会被标记为挂起状态(如果之前已经是活动状态,则标记为活动和挂起状态)。分配器会确定可以传递给核心的最高优先级的挂起中断,并将其转发到该核心的CPU接口。在CPU接口,中断被传递给核心,此时核心会触发FIQ或IRQ异常。

核心在响应中断时执行异常处理程序。处理程序必须从CPU接口寄存器查询中断ID,并开始处理中断源。处理完成后,处理程序必须写入CPU接口寄存器,报告处理结束。之后,CPU接口准备信号传递给分配器转发的下一个中断。

在处理中断期间,分配器依次经历挂起、活动等状态,最终在处理完成后变为非活动状态。因此,中断的状态会在分配器寄存器中反映出来。

关于GIC行为的更多详细信息可以在各个处理器类型的技术参考手册(TRM)以及ARM通用中断控制器架构规范中找到。

12.2.1 Configuration

GIC作为内存映射外设进行访问。所有核心都可以访问公共的分配器块,但CPU接口是分离的,也就是说,每个核心使用相同的地址访问其私有的CPU接口。一个核心无法访问其他核心的CPU接口。

分配器包含一些寄存器,可用于配置各个中断的属性。这些可配置的属性包括:

  • 中断优先级:分配器根据优先级确定下一个转发到CPU接口的中断。

  • 中断配置:确定中断是电平敏感的还是边沿敏感的。

  • 中断目标:确定中断可以转发到的核心列表。

  • 中断启用或禁用状态:只有那些在分配器中启用的中断,在变为挂起时才有资格被转发。

  • 中断安全性:确定中断是分配给安全世界还是普通世界的软件。

  • 中断状态

分配器还提供优先级屏蔽,通过它可以防止低于某一优先级的中断到达核心。分配器在确定是否将挂起的中断转发到特定核心时使用此功能。每个核心的CPU接口有助于微调该核心上的中断控制和处理。

12.2.2 Initialization

分配器和CPU接口在复位时都是禁用的。GIC必须在复位后进行初始化,才能将中断传递给核心。

在分配器中,软件必须配置中断的优先级、目标、安全性,并启用各个中断。然后,必须通过分配器的控制寄存器启用分配器块。对于每个CPU接口,软件必须设置优先级屏蔽和抢占设置。每个CPU接口块本身也必须通过其控制寄存器启用。这为GIC准备好将中断传递给核心。

在核心预期接收中断之前,软件需要在向量表中设置有效的中断向量,并清除CPSR中的中断屏蔽位。

整个系统中的中断机制可以通过禁用分配器块来禁用。传递给单个核心的中断可以通过禁用其CPU接口块,或设置该核心CPSR中的屏蔽位来禁用。单个中断也可以在分配器中被禁用(或启用)。

要使中断到达核心,必须启用该单个中断、分配器和CPU接口,并清除CPSR中的中断屏蔽位。

12.2.3 Interrupt handling

当核心接收到中断时,它会跳转到从向量表获取的顶级中断向量并开始执行。

顶级中断处理程序从CPU接口块读取中断确认寄存器以获取中断ID。读取该寄存器不仅返回中断ID,还会使该中断在分配器中被标记为活动状态。一旦获取到中断ID(即识别出中断源),顶级处理程序就可以调度设备特定的处理程序来处理中断。

当设备特定的处理程序执行完毕后,顶级处理程序会将相同的中断ID写入CPU接口块中的中断结束寄存器,以表明中断处理结束。

除了移除活动状态(这将使中断的最终状态变为非活动或挂起,如果之前的状态是“活动和挂起”),这还会使CPU接口能够将更多的挂起中断转发给核心。至此,单个中断的处理结束。

可能在同一核心上有多个中断等待处理,但CPU接口一次只能发出一个中断信号。顶级中断处理程序重复上述步骤,直到它读取到特殊的中断ID值1023,表示该核心上没有更多挂起的中断。这一特殊中断ID称为伪中断ID。伪中断ID是保留值,不能分配给系统中的任何设备。当顶级处理程序读取到伪中断ID后,它可以完成执行,并准备核心恢复处理中断之前的任务。



(广告时间)

Arm架构类课程:


安全热销大课程:


安全类经典课程:


其它课程:


铂金VIP课程介绍


之最介绍

  • 招牌课程:Truszone标准版、Trustzone高配版

  • 销量前三课程:ARM三期、Secureboot、Android15安全架构

  • 持续更新的课程:ARM三期、铂金VIP

  • 非常好非常好但又被忽视的课程:CA/TA开发

  • 近期更新/力推的课程/重点课程:optee系统架构从入门到精通


说点心里话:

  • 1、不要再说课贵了,你看看咱这是啥课?别家的能比不?请不要拿通用的linux、android、python、C语言和咱这专业课比。

  • 2、咱们的VIP是数十门课程的集合。不要拿别人一门课程的价格对标咱这20门课程价格。

  • 3、这些知识很多人都会,但拿出来讲的有多少人? 愿意拿出来讲的有多少人?讲的又有多少人?

  • 4、价格都是认真计算的,并非随意定价。都是根据内容质量、核心知识点、时长和节数计算而来。从来不无缘无故涨价(涨价是需要理由的,如课程内容增加了....)。咱靠的是内容质量长期服务,而不是运营和营销(无脑涨价)。 

  • 5、如果你刷到此处,可能是老粉/铁粉,记得点赞、评论哦。感谢您的支持。


Arm精选
ARMv8/ARMv9架构、SOC架构、Trustzone/TEE安全、终端安全、SOC安全、ARM安全、ATF、OPTEE等
 最新文章