Interuption and Exception
Exception arises within the CPU when executeinstruction
Interruption is from an external I/O controller.
- 一般情况下,我们必须立即处理 exception
- 比如说 stack overflow 就是段错误,直接 core dump 了
- 又比如说 illegal instruction,也是无法继续执行下去,就终止了
- 也比如 page fault,需要立即去硬盘里取对应的 page,然后复制到物理内存的某个部分,做好虚存的映射,然后再重新跳转回原来的指令处,开始执行
- 还比如 trap
- 但是可以不立即执行 interruption。
- 比如 IO 信号就是 interruption
Type of event | From where? | RISC-V terminology |
---|---|---|
System reset | External | Exception |
I/O device request | External | Interrupt |
Invoke the OS from user program | Internal | Exception |
Using an undefined instruction | Internal | Exception |
Hardware manifunctions | Either | Either |
对于 MIPS 等大多数 ISA 而言,interruption 和 exception 是分开的。
但是,RISC-V 不区分两者,都是在执行某一条 inst 之前,检查是否有 exception/interruption,然后就跳转至对应的入口。跳转过去之后,再检查具体是 interruption 还是 exception,具体是哪种 interruption/exception,然后执行对应的动作。
Why we need Interruption?
- 如果由 CPU 专门来轮询等待的话,就会非常浪费资源。
- 如果只是在执行每一条指令之前,检查一下 interruption bit 是否置位,则可以干别的事(比如等待 I/O 的时候,就上下文切换,去执行别的进程,而把当前的进程挂起)。
后者就是所谓 interruption driven I/O。
设计哲学:我们将所有耗时的外部行为,都交给外部元件去做。然后外部原件做完了之后,通过 interruption 来通知 CPU。
比如,对于硬盘(而非输入输出设备)这种 I/O,我们往往是通过 DMA (Direct Memory Access) 来管理。
具体地:将硬盘数据位置、大小以及希望存储到的内存位置发给 DMA,然后等待 DMA 执行即可。
How to Handle Exceptions?
- Save PC
- In RISC-V: Supervisor Exception Program Counter (SEPC)
- Save indication of the problem
- In RISC-V: Supervisor Exception Cause Register (SCAUSE)
- Jump to handler
- In RISC-V: Entry address is in a special register: supervisor trap vector (STVEC), which can be loaded by OS
Privileged Levels
特权可以保证不同的软件栈(不被非法访问)。
- 为方便起见,我们此处只使用一个 M
Control and Status Registers (CSR)
如果要找一个 CSR,需要用到 12 位。因此一共有 4096 个 CSR。
Instruction Overview
具体而言,我们可以通过以下指令来改变 CSR:
其中:
- csr rw rd,csr,rs1:rs1------>csr,csr------>rd,写入新的数据
- csr rc rd,csr,rs1:~rs1&csr------>csr,csr------->rd,关闭某几位
- csr rs rd,csr,rs1:rs1|csr----->csr,csr------>rd,打开某几位
- csr rwi rd,csr,imm:imm------>csr,csr------>rd,写入新的数据
- csr rci rd,csr,imm:~imm&csr------>csr,csr------->rd,关闭某几位
- csr rsi rd,csr,imm:imm|csr----->csr,csr------>rd,打开某几位
Address Mapping Conventions
Privileged Call Instructions
Obs:
- ecall 本质上和 jal 是类似的
- MEPC 就是用来存返回地址的
Some Important Registers
mstatus
: 全局状态
这是一个全局寄存器,负责记录全局的情况。
如图
- MIE, SIE, UIE 分别记录了在这些模式下是否允许 interrupt
- 意义:我在执行系统代码的时候,可能根本不希望任何来自外部的 interrupt 来打断我的执行
- xPIE 记录了在 trap 之前的的 MIE, SIE, UIE
- xPP 记录了 trap 之前的 mode
- 由于只会从 low privilege trap 到 high privilege,因此
- MPP 可能有 3 种情况(MPP, SPP, UPP),因此需要两位
- SPP 只有两种情况(SPP, UPP),因此只需要一位
- UPP 只有一种情况(UPP),因此在这里被省略了
- 由于只会从 low privilege trap 到 high privilege,因此
mie
/mip
: 更细粒度的状态
这两类寄存器,相比 mstatus
,粒度更细。也就是说,如果 mstatus
的 xIE 为 1,那么mie
/mip
就会对允许的 interrupt 进行更加细致的划分;如果是 0,那么所有 interrupt 均被禁止,mie
/mip
也失去作用。
如上图
- xEIE 决定是否 enable 外部中断
- xSIE 决定是否 enable 软件中断
- xTIE 决定是否 enable 计时器中断(也就是是否允许 context switch)
- xyIP 决定是否 enable 某种中断 pending
- 也就是说:不处理这个中断,但是通知你这个中断出现了
mtvec
: 入口地址
如图
- 当 mode 的值为 0 的时候,不论是异常还是中断,都直接跳到 base,然后再做处理
- 当 mode 的值为 1 的时候,如果是中断,那么就跳到 base+4×cause
- 比如说,external exception 的 cause 是 11,从而机器就跳到 base + 44
mepc
: 返回地址
mcause
: 异常/中断原因(与 mtvec
相配合)
注意: 不难发现,如果用的是向量模式,那么两个相邻的异常之间,就是一条指令。一条指令能够执行什么中断功能?能够执行 jal zero, xxx
,继续跳至目标程序地址。
Priority
不同的中断/异常可能是同时发生的,因此总要有一个先后顺序:
中断处理过程
Privileged Architecture
如图,
- 如果直接面向硬件,那么应用程序就需要自行发起 trap
- 如果下面有操作系统,那么可以进行 system-call,让操作系统代替自己发起 trap
- 有时候,一台裸机上有多个操作系统在运行,运行在 hypervisor 之上,那么就是图三的 hierarchy