LV04-07-中断与异常-03-中断与GIC
本文主要是中断与异常——中断与中断控制器GIC的相关笔记,若笔记中有错误或者不合适的地方,欢迎批评指正😃。
点击查看使用工具及版本
Windows版本 | windows11 |
Ubuntu版本 | Ubuntu16.04的64位版本 |
VMware® Workstation 16 Pro | 16.2.3 build-19376536 |
终端软件 | MobaXterm(Professional Edition v23.0 Build 5042 (license)) |
Linux开发板 | 正点原子 i.MX6ULL Linux 阿尔法开发板 |
uboot | NXP官方提供的uboot,NXP提供的版本为uboot-imx-rel_imx_4.1.15_2.1.0_ga(使用的uboot版本为U-Boot 2016.03) |
linux内核 | linux-4.15(NXP官方提供) |
Win32DiskImager | Win32DiskImager v1.0 |
点击查看本文参考资料
分类 | 网址 | 说明 |
官方网站 | https://www.arm.com/ | ARM官方网站,在这里我们可以找到Cotex-Mx以及ARMVx的一些文档 |
https://www.nxp.com.cn/ | NXP官方网站 | |
https://www.nxpic.org.cn/ | NXP 官方社区 | |
https://u-boot.readthedocs.io/en/latest/ | u-boot官网 | |
https://www.kernel.org/ | linux内核官网 |
点击查看相关文件下载
分类 | 网址 | 说明 |
NXP | https://github.com/nxp-imx | NXP imx开发资源GitHub组织,里边会有u-boot和linux内核的仓库 |
https://elixir.bootlin.com/linux/latest/source | 在线阅读linux kernel源码 | |
nxp-imx/linux-imx/releases/tag/rel_imx_4.1.15_2.1.0_ga | NXP linux内核仓库tags中的rel_imx_4.1.15_2.1.0_ga | |
nxp-imx/uboot-imx/releases/tag/rel_imx_4.1.15_2.1.0_ga | NXP u-boot仓库tags中的rel_imx_4.1.15_2.1.0_ga | |
I.MX6ULL | i.MX 6ULL Applications Processors for Industrial Products | I.MX6ULL 芯片手册(datasheet,可以在线查看) |
i.MX 6ULL Applications ProcessorReference Manual | I.MX6ULL 参考手册(下载后才能查看,需要登录NXP官网) | |
ARM | Cortex-A7 MPCore Technical Reference Manual | Cortex-A7 MPCore技术参考手册 |
ARM Architecture Reference Manual ARMv7-A and ARMv7-R edition | ARM架构参考手册ARMv7-A和ARMv7-R版 | |
Arm Generic Interrupt Controller Architecture Specification- version 3 and version 4 | Arm通用中断控制器架构规范-版本3和版本4 | |
ARM Generic Interrupt Controller Architecture Specification - Version 2.0 | Arm通用中断控制器架构规范-版本2.0 | |
ARM Cortex-A Series Programmer's Guide for ARMv7-A | Cortex-A系列ARMv7-A编程指南 |
一、中断处理
对于 S3C2440 等较旧的 ARM 体系结构版本,芯片厂家在设计外部中断控制器时具有很大的自由度,在中断的数量、类型、与中断控制器模块接口等时方面
都可以自由发挥。
通用中断控制器 v2( GIC)架构提供了更为严格的规范,不同厂商的中断控制器之间具有更高的一致性。这使中断处理程序代码更易于移植。
1. 外部中断请求
ARM 核有两个外部中断请求 FIQ 和 IRQ,如下图所示:
各个不同的芯片实现,里面都有中断控制器。中断控制器接受来自各种外部源的中断请求并将它们映射为 FIQ 或 IRQ,从而导致 ARM 核发生异常。
通常,只有当相应的 CPSR 禁止位(分别为 F 和 I 位)清零并且相应的输入为有效时,才可以产生中断异常。
CPS 指令提供了一种简单的机制来启用或禁用由 CPSR A, I 和 F 位(分别为异步中止, IRQ 和 FIQ)控制的异常。
CPS IE 或 CPS ID 将分别启用或禁用异常。使用字母 A, I 和 F 中的一个或多个指定要启用或禁用的异常。省略了相应字母的异常将不会被修改。
在 Cortex-A 系列处理器中,可以配置 CPU 核,以使 FIQ 不能被软件屏蔽。这被称为不可屏蔽 FIQ,并由 CPU 核复位时采样的硬件配置的输入信号控制。发
生 FIQ 异常后,它们仍将自动被屏蔽。
2. 分配中断
中断控制器接受来自各种源的中断, 并决定谁能优先被处理(仲裁)。控制器通常包含多个寄存器,通过这些寄存器,我们能够屏蔽或使能各个中断源,为
各个中断源分配优先级;当发生中断时,可以确定中断源。
中断控制器可以由芯片厂家自己设计(比如比较老的芯片 S3C2440),也可以使用 ARM 通用中断控制器( GIC)架构。
3. 简单的中断处理
上图代表了最简单的中断处理程序。发生中断时,将禁用其他同类中断,直到稍后显式启用。我们只能在第一个中断请求完成时才能处理其他中断,并且在
此期间没有更高优先级或更紧急的中断需要处理。在这种情况下是不可重入的中断处理程序。处理中断所采取的步骤如下:
- (1)外部硬件引发 IRQ 异常
ARM 核自动执行几个步骤:
① 当前模式下 PC 的内容存储在 LR_IRQ 中;
② CPSR 寄存器被复制到 SPSR_IRQ;
③ CPSR 内容被更新,设置模式位为 IRQ 模式,并且将 I 位设置为屏蔽其他IRQ;
④ PC 被设置为向量表中的 IRQ 入口。
(2)执行向量表中 IRQ 入口处(中断异常的分支)的指令;
(3)中断处理程序保存被中断程序的上下文:它将被该中断处理程序损坏的所有寄存器压入堆栈。
(4)中断处理程序确定中断源,然后调用响应的处理程序。
(5)恢复现场。
通过将 SPSR_IRQ 复制到 CPSR,并还原先前保存的上下文,准备将 CPU 核切换到先前的执行状态,最后从 LR_IRQ 恢复 PC。相同的顺序也适用于 FIQ 中断。
4. 嵌套中断处理
嵌套中断处理是软件可以在完成对当前中断的处理之前,接受另一个中断。这可以将中断进行优先级分级,降低高优先级事件的响应延迟,代价是增加了软
件的复杂性。值得注意的是,嵌套中断处理是由软件来实现。
支持中断嵌套的处理函数,被称为“可重入中断处理程序”。在 Linux 系统中,不支持中断嵌套。对于裸机程序,我们也不需要花费精力在这上面。在实时性要求很高的 RTOS 中,也许对中断嵌套有所要求。但是可以通过其他办法习实现,比如把某个中断单独设置在 FIQ。
二、通用中断控制器(GIC)
ARM 体系结构定义了通用中断控制器(GIC, Generic InterruptController),该控制器包括一组用于管理单核或多核系统中的中断的硬件资源。 GIC 提供了内存映射寄存器,可用于管理中断源和行为,以及(在多核系统中)用于将中断路由到各个 CPU 核。它使软件能够屏蔽,启用和禁用来自各个中断源的中断,以(在硬件中)对各个中断源进行优先级排序和生成软件触发中断。它还提供对 TrustZone 安全性扩展的支持。GIC 接受系统级别中断的产生,并可以发信号通知给它所连接的每个内核,从而有可能导致 IRQ 或 FIQ 异常发生。
GIC 是 ARM 公司给 Cortex-A/R 内核提供的一个中断控制器,类似 Cortex-M 内核中的NVIC。目前 GIC 有 4 个版本:V1~V4, V1 是最老的版本,已经被废弃了。 V2~V4 目前正在大量的使用。 GIC V2 是给 ARMv7-A 架构使用的,比如 Cortex-A7、 Cortex-A9、 Cortex-A15 等,V3 和 V4 是给 ARMv8-A/R 架构使用的,也就是 64 位芯片使用的。
1. 基本结构
从软件角度来看, GIC 具有两个主要功能模块,
- 分发器(Distributor)
系统中的所有中断源都连接到该单元。可以通过仲裁单元的寄存器来控制各个中断源的属性,例如优先级、状态、安全性、路由信息和使能状态。分发器把中断输出到“ CPU 接口单元”,后者决定将哪个中断转发给 CPU 核。
- CPU 接口单元(CPU Interface)
CPU 核通过控制器的 CPU 接口单元接收中断。 CPU 接口单元寄存器用于屏蔽,识别和控制转发到 CPU 核的中断的状态。系统中的每个 CPU 核心都有一个单独的 CPU 接口。中断在软件中由一个称为中断 ID 的数字标识。中断 ID 唯一对应于一个中断源。软件可以使用中断 ID 来识别中断源并调用相应的处理程序来处理中断。呈现给软件的中断 ID 由系统设计确定,一般在 SOC 的数据手册有记录。
2. 中断的类型与状态
2.1 中断可以有多种不同的类型
- (1)软件触发中断(SGI, Software Generated Interrupt)
这是由软件通过写入专用仲裁单元的寄存器即软件触发中断寄存器( ICDSGIR)显式生成的。它最常用于 CPU 核间通信。 SGI 既可以发给所有的核,也可以发送给系统中选定的一组核心。中断号 0-15 保留用于 SGI 的中断号。用于通信的确切中断号由软件决定。
- (2)私有外设中断(PPI, Private Peripheral Interrupt)
这是由单个 CPU 核私有的外设生成的。 PPI 的中断号为 16-31。它们标识CPU 核私有的中断源,并且独立于另一个内核上的相同中断源,比如,每个核的计时器。
- (3)共享外设中断(SPI, Shared Peripheral Interrupt)
这是由外设生成的,中断控制器可以将其路由到多个核。中断号为 32-1020。SPI 用于从整个系统可访问的各种外围设备发出中断信号。中断可以是边沿触发的(在中断控制器检测到相关输入的上升沿时认为中断触发,并且一直保持到清除为止)或电平触发(仅在中断控制器的相关输入为高时触发)。
2.2 中断可以处于多种不同状态
(1)非活动状态(Inactive): 这意味着该中断未触发。
(2)挂起(Pending): 这意味着中断源已被触发,但正在等待 CPU 核处理。待处理的中断要通过转发到 CPU 接口单元,然后再由 CPU 接口单元转发到内核。
(3)活动(Active): 描述了一个已被内核接收并正在处理的中断。
(4)活动和挂起(Active and pending):描述了一种情况,其中 CPU 核正在为中断服务,而 GIC 又收到来自同一源的中断。
3. GIC的逻辑结构
GIC 控制器的逻辑结构 如下图(《ARM® Generic Interrupt Controller Architecture version 2.0》的2.1 About GIC partitioning)所示:
中断的优先级和可接收中断的核都在分发器(distributor)中配置。外设发给分发器的中断将标记为 pending 状态(或 Active and Pending 状态,如触发时果状态是 active)。 distributor 确定可以传递给 CPU 核的优先级最高的 pending 中断,并将其转发给内核的 CPU interface。通过 CPU interface,该中断又向 CPU 核发出信号,此时 CPU 核将触发 FIQ 或 IRQ 异常。
作为响应, CPU 核执行异常处理程序。异常处理程序必须从 CPU interface寄存器查询中断 ID,并开始为中断源提供服务。完成后,处理程序必须写入 CPU interface 寄 存 器 以 报 告 处 理 结 束 。 然 后 CPU interface 准备转发distributor 发给它的下一个中断。
在处理中断时,中断的状态开始为 pending, active,结束时变成 inactive。中断状态保存在 distributor 寄存器中。
4. GIC的配置
GIC 作为内存映射的外围设备,被软件访问。所有内核都可以访问公共的distributor 单元,但是 CPU interface 是备份的,也就是说,每个 CPU 核都使用相同的地址来访问其专用 CPU 接口。一个 CPU 核不可能访问另一个 CPU 核的 CPU 接口。Distributor 拥有许多寄存器,可以通过它们配置各个中断的属性。这些可配置属性是:
- 中断优先级: Distributor 使用它来确定接下来将哪个中断转发到 CPU 接口。
- 中断配置:这确定中断是对电平触发还是边沿触发。
- 中断目标:这确定了可以将中断发给哪些 CPU 核。
- 中断启用或禁用状态:只有 Distributor 中启用的那些中断变为挂起状态时,才有资格转发。
- 中断安全性:确定将中断分配给 Secure 还是 Normal world 软件。
- 中断状态。
Distributor 还提供优先级屏蔽,可防止低于某个优先级的中断发送给 CPU核。每个 CPU 核上的 CPU interface,专注于控制和处理发送给该 CPU 核的中断。
5. 初始化GIC
Distributor 和 CPU interface 在复位时均被禁用。复位后,必须初始化GIC,才能将中断传递给 CPU 核。在 Distributor 中,软件必须配置优先级、目标核、安全性并启用单个中断;随后必须通过其控制寄存器使能。
对于每个 CPU interface,软件必须对优先级和抢占设置进行编程。每个CPU 接口模块本身必须通过其控制寄存器使能。
在 CPU 核可以处理中断之前,软件会通过在向量表中设置有效的中断向量并清除 CPSR 中的中断屏蔽位来让 CPU 核可以接收中断。
可以通过禁用 Distributor 单元来禁用系统中的整个中断机制;可以通过禁用单个 CPU 的 CPU 接口模块或者在 CPSR 中设置屏蔽位来禁止向单个 CPU 核的中断传递。也可以在 Distributor 中禁用(或启用)单个中断。
为了使某个中断可以触发 CPU 核,必须将各个中断, Distributor 和 CPUinterface 全部使能,并将 CPSR 中断屏蔽位清零,如下图:
6. GIC 中断处理
当 CPU 核接收到中断时,它会跳转到中断向量表执行。顶层中断处理程序读取CPU接口模块的 Interrupt Acknowledge Register,以获取中断 ID。除了返回中断 ID 之外,读取操作还会使该中断在Distributor 中标记为 active 状态。一旦知道了中断 ID(标识中断源),顶层处理程序现在就可以分派特定于设备的处理程序来处理中断。
当特定于设备的处理程序完成执行时,顶级处理程序将相同的中断 ID 写入 CPU interface 模块中的 End of Interrupt register 中断结束寄存器, 指示中断处理结束。除了把当前中断移除 active 状态之外,这将使最终中断状态变为 inactive 或 pending(如果状态为 inactive and pending),这将使CPU interface 能够将更多待处理 pending 的中断转发给 CPU 核。这样就结束了单个中断的处理。
同一 CPU 核上可能有多个中断等待服务,但是 CPU interface 一次只能发出一个中断信号。顶层中断处理程序重复上述顺序,直到读取特殊的中断 ID 值1023,表明该内核不再有任何待处理的中断。这个特殊的中断 ID 被称为伪中断ID( spurious interrupt ID)。
伪中断 ID 是保留值,不能分配给系统中的任何设备。
7. 中断控制器寄存器
GIC 分为两部分: Distributor 和 CPU interface,它们的寄存器都有相应的前缀:“GICD_”、“ GICC_”。这些寄存器都是映射为内存接口(memery map),CPU 可以直接读写。
这里就不详细介绍了,需要的时候可以查看《ARM® Generic Interrupt Controller Architecture version 2.0》的Chapter 4 Programmers’ Model一节。