分为中断与异常,这里主要记录RISC-V指令集的中断。
一、CPU框图
二、RISC-V中断的分类
- 本地中断 (Local interrupt)
- software interrupt
- timer interrupt
- 全局中断 (Global interrupt)
- externel interrupt
三、与中断有关的寄存器(mie/mip)
mstatus寄存器的MIE标志位是全局中断开关位,相当于一级中断标志。
mie (Machine interrupt Enable)
用于设置M/S/U模式下对应的External/Timer/Software中断。(M/S/U下方特权模式说到)
在RISCV下,将中断(interrupt)又细分为三种类型:定时中断(timer)、核间中断(soft)、中断控制器中断(external)。定时中断可以用于产生系统的tick,核间中断用于不同cpu核之间通信,中断控制器则负责所有外设中断。这个设计和arm下有点不一样,在arm多核下,架构中的定时器中断、核间中断和外设中断都是统一由中断控制器管理的,而在RISCV中定时器和核间中断是分离出来的,这两个中断被称为CLINT(Core Local Interrupt),而管理其他外设中断的中断控制器则被称为PLIC(Platform-Level Interrupt Controller)。
mip (Machine Interrupt Pending): 获取当前M/S/U模式下对应的External/Timer/Software中断是否发生。
四、特权模式
RISCV架构下有三种特权级别,分别是Machine、Supervisor和User,简称M模式、S模式和U模式。M模式权限最高,在这个级别下的程序可以访问一切硬件和执行所有特权指令;S模式一般用于运行操作系统,可以设置MMU使用虚拟地址;U模式一般是普通应用程序使用,权限最低。
M模式使用物理地址进行访问,不经过MMU,但是有类似arm下cortex-m中的MPU功能;S模式可以通过设置MMU来使用虚拟地址访问内存,所以像Linux这类操作系统都运行在S模式下。那么有人要问了,为啥RISCV架构特权模式设计成这样,直接把M模式和S模式合二为一不行吗?这个得从RISCV架构诞生背景来看了,RISCV架构诞生于2010年左右,这时不管是x86还是arm架构都发展得算是比较成熟了,所以RISCV架构设计时就定位了从微控制器到大型超级计算机都可以使用这个架构。在微控制器上使用的RISCV架构一般只有M模式,或者使用M和U两种模式,类似于cortex-m架构的定位;而在带MMU的芯片上,RISCV架构一般都使用M、S和U三种模式,这样通过“拼积木”的方式就可以让RISCV架构适用于各种场景了。
五、PLIC (Platform-Level Interrupt Controller)
RISC-V里面的中断控制器,相当于ARM中的GIC,主要根据优先级处理外部中断
中断源->中断号->中断向量->中断服务程序(ISR)->中断返回 中断源ID范围:1 ~ 53(0x35),0保留
PLIC编程接口 - 寄存器
- RISC-V规范规定,PLIC的寄存器编制采用内存映射(memory map)方式。每个寄存器的宽度为32 - bit。
- 具体寄存器编址采用 base + offset 的格式,且base由各个特定platform自己定义。
Priority寄存器
可编程寄存器 | 功能描述 | 内存映射地址 |
---|
Priority | 设置某一路中断源的优先级 | BASE + (interrupt-id) * 4 |
- 每个PLIC中断源都有一个内存映射地址,此地址指向的寄存器用于配置该中断源的优先级。
- 如果两个中断源优先级相同,则根据中断源的ID值进一步区分优先级,ID值越小的优先级越高
Pending寄存器
可编程寄存器 | 功能描述 | 内存映射地址 |
---|
Pending | 用于指示某一路中断源是否发生 | BASE + 0x1000 + ((interrupt-id/32)) |
- 每个PLIC中断控制器包含2个32位的Pending寄存器(因为52个中断源用1个32bit无法表示完全),每一个bit对应一个中断源,为1表示该中断源上发生了中断(进入Pending状态),有待hart处理,否则表示该中断源上当前无中断发生。
- Pending寄存器中断的Pending状态可以通过claim方式清除。
- 第一个Pending寄存器的第0位对应不存在的0号中断源,其值永远为0。
Enable寄存器
可编程寄存器 | 功能描述 | 内存映射地址 |
---|
Enable | 针对某个hart开启或关闭某一路中断源 | BASE + 0x2000 + (hart) * 0x80 |
- 每个Hart有2个Enable寄存器 (Enable1 和 Enable2)用于针对该Hart启动或关闭某路中断源。
- 每个中断源对应Enable寄存器的一个bit,其中Enable1负责控制131号中断源;Enable2负责控制3253号中断源。将对应的bit位设置为1表示使能该中断源,否则表示关闭该中断源。
Threshold寄存器
可编程寄存器 | 功能描述 | 内存映射地址 |
---|
Threshold | 针对某个hart设置中断源优先级的阈值 | BASE + 0x200000 + (hart) * 0x1000 |
- 每个Hart有1个Threshold寄存器用于设置中断优先级的阈值。
- 所有小于或者等于(<=)该阈值的中断源即使发生了也会被PLIC丢弃。特别地,当阈值为0时允许所有中断源上发生的中断;当阈值为7时丢弃所有中断源上发生的中断。
Claim/Complete寄存器
可编程寄存器 | 功能描述 | 内存映射地址 |
---|
Claim/Complete | 针获取当前发生的最高优先级的中断源ID/通知PLIC对中断的处理已经结束 | BASE + 0x200004 + (hart) * 0x1000 |
- Claim和Complete是同一个寄存器,每个Hart一个。
- 对该寄存器执行读操作时称为Claim,即获取当前发生的最高优先级的中断源ID。Claim成功后会清除对应的Pending位。
- 对该寄存器执行写操作称之为Complete。所谓Complete指的是通知PLIC对该路中断的处理已经结束。
六、中断处理流程
即使中断同时发生,也会按照中断优先级的筛选进行响应。
详情可跳转 FreeRTOS的中断机制可跳转
|