引流关键词: 中断,irq,fiq,中断嵌套,中断抢占, optee、ATF、TF-A、Trustzone、optee3.14、MMU、VMSA、cache、TLB、arm、armv8、armv9、TEE、安全、内存管理、页表…
快速链接:
.
👉👉👉 个人博客笔记导读目录(全部) 👈👈👈
说明:
在默认情况下,本文讲述的都是ARMV8-aarch64架构,gicv3, linux kernel 5.14
思考:你是否想过这样的一个场景:当一个中断正在处理事务时,又来了一个高优先级中断把它抢占了? 也就是所谓着中断嵌套。很多人可能都会说“这种场景当然存在了”,但现实中真的存在吗? 不要被网上的博客或书上的一些章节所误导,今天我们抛开事务看本质,从以下方面着手进行讨论:
- ARM CORE支持中断嵌套吗
- GIC中断控制器支持中断嵌套吗?
- Linux Kernel操作系统有没有使用中断嵌套?
在介绍之前,我们先记下几个共识(也就是常识,本文不做重复介绍的):
- FIQ和IRQ具有同样的优先级,FIQ只是一种中断类型,并非所谓着快速中断。
1、ARM CORE支持中断嵌套吗?
首先来看ARM CORE支持中断嵌套吗?答案 支持! 但是是有一个前提,在进入中断处理时,PSTATE的I、F、A等比特位是MASK的,软件中需要主动unmask后,那么就可以中断嵌套了。如下图所示,正是ARM Core支持中断嵌套的一个示例(或者叫模型):
2、GIC中断控制器支持中断嵌套吗?
继续看GIC中断控制器支持中断嵌套吗?答案 支持中断抢占,支持中断嵌套!。
2.1、先介绍以下优先级和抢占的概念
-
每个 INTID(中断号) 都有一个优先级(用寄存器
GICD_IPRIORITYn
或GICR_IPRIORITYn
表示),它是一个 8 位无符号值。 0x00 是可能的最高优先级,0xFF 是可能的最低优先级 -
每个 PE 在其 CPU interface中都有一个优先级掩码寄存器 (
ICC_PMR_EL1
)。 该寄存器设置将中断转发到该 PE 所需的最低优先级。 只有优先级高于寄存器值的中断才会发送给 PE -
GICv3 架构具有 运行优先级的概念。 当 PE 响应中断时,它的运行优先级变为该中断的优先级。 当 PE 写入 EOI 寄存器之一时,运行优先级将返回其先前值。 如果 PE 尚未处理中断,则运行优先级为空闲优先级 (0xFF)。 只有优先级高于运行优先级的中断才能抢占当前中断
2.2、Without preemption : 即关闭抢占,disable running priority
在Without preemption的情况下,高优先级的中断无法抢占正在active的中断,只能等active的中断执行完了、返回了,高优先级的中断才能发生"抢占"(这里还说抢占,合适吗? 此种情况应属于抢占pendding中断)。 如下图所示,便是一个示例:
- 高优先级的中断 无法抢占active的中断
- 等待active的中断执行完毕返回了,高优先级的中断才能发生抢占(也就是抢占pendding中断)
虽然你关闭了抢占,但优先级仍然存在,仍然会发生作用
抢占正在pendding中断的示例, 这种情况下,一个高优先级的中断可以抢占一个低优先级的pendding中断,并非抢占正在执行的中断,抢占后高优先级的中断变成pendding。而我们大多数人所说的中断嵌套是指,一个中断正在执行时,被另外一个中断给抢占了。
当 CPU interface上的一个低优先级中断处于pendding状态时,更高优先级的中断也可能会变为pendding状态。 Redistributor 可以为新的更高优先级中断发送 Set 命令。 此 Set 命令将取代之前的 Set 命令,导致 CPU interface为较低优先级的中断发出 Release。 下图显示了此类场景的示例。 该示例假设 INTID Y 的优先级高于 INTID X。
2.3、With preemption
接下来就看 抢占正在active中断的示例,描述的其实就是:一个中断正在执行,然后另一个更高优先级的中断打断了它, 这也就是正是我们所说的中断嵌套。
在考虑抢占时,运行优先级的概念很重要。 当一个高优先级中断被发送给一个已经在处理一个低优先级中断的 PE 时,就会发生抢占。 抢占为软件带来了一些额外的复杂性,但它可以防止低优先级中断阻塞更高优先级中断的处理。
2.4、那么对于一个gicv3的IP,优先级肯定是有的,它到底是Without preemption 还是With preemption呢? 如何配置的呢?
请查略ICC_BPRn_EL1
寄存器,该寄存器定义优先级值字段分成两部分的点,即组优先级字段和子优先级字段。 组优先级字段确定组 1 中断抢占。 换句白话来解释就是,中断优先级被分成了两部分,如下图所示,ICC_BPRn_EL1
寄存器的BIT[2:0]定义了下图中的N的值
对于抢占,仅考虑Group优先级位。 Subpriority优先级位被忽略. 然后举一个例子:
- INTID A has priority 0x10
- INTID B has priority 0x20
- INTID C has priority 0x21
如上有三个中断,A可以抢占B,但B不可以抢占C,因为B和C的Group priority是一样的
3、 Linux Kernel操作系统有没有使用中断嵌套?
继续看Linux Kernel操作系统有没有使用中断嵌套?答案 没有使用!
首先查看ICC_BPRn_EL1
寄存器的配置:
写入的是0,也就是意味着,N=0, 即下图的第一行,也就是说抢占是开启的。
继续看,针对每一个 INTID(中断号) 的priority的配置,如下所示,在gic初始化阶段,给每一个 INTID(中断号) 都配置成了一样的优先级,值位0XA5。 也就是所有中断的优先级都是一样的。
事实上,在gicv3代码中,提供了一个接口,可以单独针对某一中断设置优先级。
查略该函数用途,仅仅是为NMI中断设置的(注:Linux Kernel中armv8体系目前还没有该中断,ARMV9新增了一类NMI中断),其值为0Xa5 & 0x7f = 0x25,该值小于0XA0,所有该优先级大于其它中断的优先级。