ARMv8 中断系统的架构
GIC 的输入为许多的中断线,但输出到 CPU 的只有 IRQ 和 FIQ 两种, 所以就要由 GIC 做中断的分发和过滤工作。
总体来说,整个中断系统架构从底向上可分为三部分:
- 硬件接口;外设的引脚
- 中断控制器;桥梁,向下提供引脚连接外设,向上连接 CPU 在合适的时间 触发中断信号,充当中断系统的主管
- 中断处理函数;GIC 将中断信号传递到 CPU 后,CPU 执行中断处理函数
+-----------+ +-----------+
| Process | | Process |
+---------+-+ ++----------+
| |
+-+--------+----+
| |
| GIC |
| |
+-------+-------+
|
+-------------+----------+
| Peripheral Device |
+------------------------+
中断控制器 GICv3
GIC 的有许多版本,本文皆以 GIC version3 为例介绍, 简称为 GICv3
如上所述,GIC 在中断系统中充当“管家”的作用。如果将 CPU 比作老板, 到来的中断比作约见老板的员工,那么 GIC 就是秘书,统筹安排何人何时 与老板谈话。
GICv3 的组成大概可分为 3 部分:
- Distributor
- Redistributor
- CPU Interface
如果将上面架构图中的 GIC 拆开,大概的结构如下图所示。能够注意到除了 GIC 被细分外,外设中断源也划分为两部分,在下面中断分类中会详细 介绍。
+----------------+ +----------------+
| Process | | Process |
+--+----------+--+ +--+----------+--+
| CPU | | CPU |
| Interface| | Interface|
+----+-----+ +----+-----+
| |
+------+-------+ +------+-------+
| Reditributor | | Reditributor +-----+
+----------+---+ +--+-----------+ |
| | |
+---+-------------+-----+ |
| | |
| Distributor | |
| | |
+-----------+-----------+ |
| |
+---------+--------+ +-------+---------+
|Peripheral Device | |Peripheral Device|
| (SPI) | | (PPI) |
+------------------+ +-----------------+
Distributor
负责全局中断的分发
Redistributor
Redistributor 是 GICv3 相较于 v2 新引入的部件,在我看来,引入 Redistributor 的 主要原因是: 提高中断相应的效率。 在以前,无论是全局中断还是私有中断都是通过一个 Distributor 分发,如果中断到来的比较频繁,则可能产生延迟。
Redistributor 就主要负责私有中断的分发,减轻了 Distributor 的负担。
CPU Interface
物理结构上依附与 CPU,而不是 GIC。主要负责控制中断被 CPU 接收的过程, 即中断状态 pengding , active, inactive 的切换。
同时, CPU Interface 还负责优先级的过滤,只有符合优先级条件的中断才会被 CPU 响应。
相关的寄存器有ICC_PMR_EL1
,ICC_RPR_EL1
等
中断抢占的配置也是由其完成,详见ICC_BPRx_EL1
寄存器。
GICv3 Affinity Rounting
GICv3 以前都是用 target-list, 来设置中断到达的目的 CPU,这种方式类似于位图, 以前只有 8bit 来做这个,所以采用 GICv2 的系统最多支持 8 个 CPU。
而 GICv3 引入了 Affinity value 来支持更多的 CPU,类似于 IP 地址的方法,用 4 个 8bit 来标识。可以写作a.b.c.d
- c: 一般是指某个 cluster
- d: 转发时会填入 target-list,指定多个 CPU,最多 8 个(下图的形式还没有将d转为targetlist)
所以用 Affinity value 虽然能指定大于 8 个 CPU,但是一次只能发往一个 cluster 内的最多 8CPU。
GICv3 中断的分类与标识
在使用 GICv3 的系统上,中断被划分为 4 种类型:
- spi: 全局的中断,可以被路由到任意的一个或多个 CPU。一般对应所有 CPU 共用 的外设,例如串口中断。
- ppi: 每个 CPU 私有的中断,只能被路由到该 CPU。对应与 CPU 私有的外设中断, 例如 CPU 内部定时器中断。
- sgi: CPU 触发的中断,可以被路由到任意 CPU。一般用于核间通信使用。
- lpi: message-based interrupts 这里不做介绍.
中断标识: INTID
CPU 如何区分当前来的中断是来自哪个外设的中断信号? 答案是通过 INTID,它是 GIC
定义的中断标识符,CPU 通过读取寄存器ICC_IAR1_EL1
就能得知当前处理中断的 INTID。
INTID 按照中断类型分类的, 对照表如下:
INTID | 中断类型 | Note |
---|---|---|
0-15 | SGI | 本地的, 不同 CPU 可使用同一中断号代表不同中断 |
16-31 | PPI | 本地的 |
32-1019 | SPI | 全局的 |
1020-1023 | 特殊中断 | |
1056-1119 | 扩展的 PPI | 本地的 |
4096 – 5119 | 扩展的 SPI | 全局的 |
扩展中断号的最大值是实现定义的, 可以在
GICD_TYPER.IDbits
中读取。
特殊中断号
特殊中断不需要 end of interrupt or deactivation 过程.
1020:
1021:
1022:
1023: 读
ICC_IAR1_EL1
返回该值表明当前的 CPU 上没有待处理的中断, 编程时可当做while
退出的标志
小结
这节主要总结 ARMv8 中断系统的总体架构和 GICv3 的组成结构,下一节将介绍 一个中断的生命周期,即中断的状态转换,以及在此过程中各个组件的作用。