首页 > 代码库 > 《Cortex?-A系列编程者指南(V3.0)》第13章<中断处理>笔记
《Cortex?-A系列编程者指南(V3.0)》第13章<中断处理>笔记
在本章,我们会看看ARM处理器处理中断的一系列方法,简单地看看通用中断控制器(Generic Interrupt Controller,GIC)架构。
旧版本的ARM架构允许实现者在他们的外部中断控制器设计中相当大的自由,没有关于中断类型或数量,或者是被用于中断控制模块接口的软件模型的协议。GIC架构提供一个更为严格的控制规范,使得来自不同制造商之间的中断控制器之间有更高程度的一致性。这使得中断处理代码变得更加可移植。
13.1 外部中断请求
如我们在第12章的异常类型中讨论的,所有的ARM处理器有两种外部中断请求,FIQ和IRQ。它们都是电平敏感低电平有效的输入。个别实现具有中断控制器,接受来自多种外部源的中断请求,并把映射到FIQ或IRQ上,引起处理器获取一个异常。
总的来说,中断异常仅在合适的CPSR位(分别是F和I位)清除时才能被获取。
CPS汇编语言指令提供一种简单的机制来使能或禁止由CPSR A,I和F位(分别是异步中止,IRQ和FIQ)控制的异常。另外,CPS可以被用于修改模式,如下所示。
CPS #<mode> CPSIE <if> CPSID <if><mode>是要修改的模式号码。如果这个选项被忽略,不会发生模式切换。这些模式的值在表4-1中所列。
IE或ID会分别使能或禁止异常。使用一个或多个字母A,I和F指定异常的使能或禁止。相应字母被忽略的异常不会被修改。
在Cortex-A系列处理器中,配置处理器从而使FIQ不会被软件屏蔽是可能的。这被称为不可屏蔽FIQ,由硬件配置输入信号控制,在处理器复位时被采样。它们在获取到FIQ异常时仍然会自动被屏蔽。
13.1.1 分配中断
一个系统总是会有一个中断控制器,它接收来自多个外部硬件的中断请求。这通常包含一些寄存器来使能运行在ARM处理器上的软件来屏蔽个别中断源,应答来自外部设备的中断和确定当前激活的中断源。
中断控制器可以是特定于系统的,或它也可以是ARM通用中断控制器(GIC)架构的实现,这会在接下来的13.2节的通用中断控制器中讲述。
13.1.2 最简单的中断处理
这表示最简单的那种中断处理。一个中断产生并且在处理那个中断时,后续中算被禁止。我们只能在第一个中断请求完成时处理后续中断,在此期间没有一个更高优先级或更加紧急的中断需要被处理。这通常对于嵌入式系统来说是不合适的,但在继续一个更为真实的例子之前是非常有用的。
处理一个中断的步骤如下:
a. 外部硬件引发了一个IRQ异常。处理器自动执行几个步骤。当前模式PC的内容被存放在LR_IRQ。CPSR寄存器被拷贝到SPSR_IRQ。CPSR的底部字节被更新以切换到IRQ模式,并且禁止IRQ,阻止后续异常发生。PC设置到向量表中的IRQ入口。
b. 向量表中IRQ入口的指令(跳转到中断处理的分支)被执行。
c. 中断处理程序保存被中断程序的上下文(就是,它压入会被中断处理函数损坏的任何寄存器到堆栈)。
d. 中断处理程序决定需要处理的中断源,调用合适的设备驱动。
e. 最后,SPSR_IRQ被拷回CPSR,切换系统回先前执行的模式。同时,PC从LR_IRQ恢复。
13.1.3 嵌套的中断处理
在嵌套的中断处理中,我们在中断处理被完全服务完之前重行使能中断。这允许我们优先化中断,以增加额外的复杂性为代价极大缩短高优先级事件的延迟。
一个可重入中断处理程序在中断使能,跳转到嵌套子程序或C函数之前,必须保存IRQ状态,切换处理器模式,为新的处理器模式保存状态。这是因为新的中断可能在任何事件发生,这会引起处理器存储新中断的返回地址到LR_IRQ,覆盖原来的中断。当原来的中断试图返回主程序,它会引起系统失败。嵌套的中断处理程序必须在重新使能中断之前改变到另外一个内核模式,以防止此类情况发生。
<注意>
一个程序是可重入的,如果它可以在它执行中被中断,然后在先前版本完成之前被再次调用。
因此,一个可重入中断处理程序必须在一个IRQ异常被引发并且控制被传递到按照先前描述的中断处理程序之后,采取下列步骤。
a. 中断处理程序保存被中断程序的上下文(那就是,它压入任何会被处理函数毁坏的寄存器到替代内核模式的堆栈,包括返回地址和SPSR_IRQ)。
b. 它确定需要被处理的中断源,清除外部硬件中的中断源(防止它立即触发另一个中断)。
c. 中断处理函数修改处理器SVC模式,CPSR I位被设置(中断仍然被禁止)。
d. 中断处理程序保存异常返回地址到堆栈(为新模式的堆栈,位于内核存储区),并且重新使能中断。
e. 调用合适的设备驱动。
f. 在完成时,中断处理程序禁止IRQ,从堆栈获取异常返回地址。
g. 从替代内核模式的堆栈恢复被中断程序的上下文。这包括恢复PC,CPSR切换到先前执行的模式。如果SPSR的I位没有置位,重新使能中断。
13.2 通用中断控制器
GIC架构定义了一个通用中断控制器(Generic Interrupt Controller, GIC),它由单核或多核系统中为管理中断的硬件资源集组成。GIC提供内存映射寄存器,它可用于管理中断源和行为,并且(在多核系统中)路由中断到单独的处理器。它使得软件能够屏蔽、使能和禁止来自独立源的中断,优先化(硬件上)单个源的中断,生成软件中断。它也为信任区安全扩展提供支持,如第26章安全中所描述。GIC接受系统级声明的中断,并且可以将它们传递到它所连接到每个处理器,潜在地导致一个IRQ或FIQ异常被引发。
从软件角度,一个GIC有两个主要的功能模块:
<分配器>
在多核系统中的所有处理器之间被分享。被用于配置例如优先级、路由等事情,也用于提供全局使能或禁止单个中断。
<CPU接口>
每个处理器处理中断的私有通道。这是你发现已被触发的中断,通知当你已完成处理一个中断。
每个中断可以被认为处于四个状态之一:
> 未激活
> 挂起 --- 这意味着中断源已经声明,但是等待被处理器处理
> 激活 --- 这描述一个已被处理器承认的中断,并且当前正在服务
> 激活并挂起--- 这描述的情形为,处理器正在处理终端,GIC从相同的源有一个挂起的中断
中断可以是很多不同的类型:
软件生成的中断(Software Generated Interrupt, SGI)
这通过写一个专用寄存器生成,软件生成中断寄存器(Software Generated Interrupt Register, ICDSGIR)。这通常被用于内部处理器之间的通信。
私有外设中断(Private Peripheral Interrupt, PPI)
由对一个单独的处理器私有的外设生成
共享外设中断(Shared Peripheral Interrupt, SPI)
由一个可以被中断控制器路由到超过一个处理器的外设生成。
中断可以是边缘触发的(当在相关输入上中断控制器检测到一个上升沿时考虑确认,并且保持确认直到被清除)或者是电平敏感的(仅在相关到中断控制器的输入是高电平时被确认)。
独立的中断源可以使用一个ID号来呗确认。GIC赋值一个指定范围的ID值到不同类型的中断。
处理器硬件与处理器当前中断优先级比较。如果中断有足够的优先级,一个中断异常请求信号被发出。
我们在第22章会回到GIC的主题,那里讲述了ARM多核处理器中的实现。关于GIC更为详细的信息可以在单独处理器的TRM(Technical Reference Manual)和《ARM通用中断处理器架构规范》(ARM Generic Interrupt Controller Architecture specification)中找到。
13.2.1 配置
访问通用中断处理寄存器是内存映射的。在一个使用GIC的多核处理器中,这通过使用对每个处理器私有的接口来完成(进一步细节看22章第6节的SMP系统中的处理中断)。
分配器包含一个配置寄存器集,数目取决于实现了多少个外部中断:
> 中断配置寄存器配置独立中断源为边沿或电平敏感的。
> 中断优先级寄存器为每个独立中断设置优先级值。较低的值表示较高的优先级。
CPU接口为中断处理提供寄存器的每核实例,相对于配置:
> 优先级屏蔽寄存器阻止低于某个优先级的中断被传递到处理器。最低优先级的中断绝不会被传递。
> 二进制点寄存器(The Binary Point Register)为了优先级的目的使得可配数量的优先级值的最低有效位被忽略。这使得中断被如此配置,相似优先级的中断组不会相互抢占,但是如果同时发生仍然会以优先级的顺序被处理。
初始化序列
a. 使用分配器控制寄存器(Distributor Control Register)使能分配器;
b. 使用使能设置和优先级寄存器使能和设置SPI(Shared Peripheral Interrupt, 共享外设中断)的优先级。中断的复位后优先级对它们来说可能太低,以至于不能递交。
c. 使用CPU接口控制寄存器(CPU Interface Control Register)使能CPU接口。
d. 设置优先级屏蔽寄存器(Priority Mask Register)。(复位值阻止所有中断被递交)
e. 使用使能设置和优先级寄存器(Enable Set and Priority Level registers)使能和设置私有外设中断(Private Peripheral Interrupts)和软件生成中断(Software Generated
Interrupts)。这些操作是在分配器优先级寄存器(Distributor Priority Level registers)中被执行。这些寄存器是分组的,为每个处理器提供一份独立的拷贝。
f. 确保中断在向量表中的有效入口存在。
g. 清除CPSR中的I位。
13.2.2 中断处理
当一个处理器获取到一个中断异常,它读取中断应答寄存器(Interrupt Acknowledge Register, ICCIAR),来应答中断。这个读取返回一个中断ID,它被用于选择正确的中断处理程序。当GIC看到这个读取,它恰当地将终端的状态从挂起切换到激活或激活并挂起。如果当前没有中断挂起,一个为假中断的预定义ID被返回。
如果一个中断被激活,中断控制器就将IRQ输入报告给处理器。这意味着中断复位例程现在可以重新使能中断。这使得较高优先级中断的到来可以抢占当前中断的处理。
当中断服务例程已完成处理中断,它通过写GIC中的中断结束寄存器(End of Interrupt Register,ICCEOIR)来发消息。直到这一过程被完成,那个中断(并且任何较低优先级的中断)的新信号不会被检测到。
> 中断号码ID1020-ID1023为特殊用途保留,包括发布假中断的信号。
> 中断ID值在ID32-ID1019之间的被用于SPI(共享外设中断)。
> 中断号码ID0-ID31之间的被用于私有于一个处理器接口的中断。在多核系统(或者是在一个多核GIC实现)中,这些号码在每个核的基础上被分组。ID0-ID15被用于SGI(软件生成中断),ID16-ID31被用于PPI(私有外设中断)。