RISC-V 特权指令结构
机器模式
机器模式(缩写为 M 模式,M-mode)是 RISC-V 中 hart(hardware thread,硬件线 程)可以执行的最高权限模式。在 M 模式下运行的 hart 对内存,I/O 和一些对于启动和配 置系统来说必要的底层功能有着完全的使用权。因此它是唯一所有标准 RISC-V 处理器都 必须实现的权限模式。实际上简单的 RISC-V 微控制器仅支持 M 模式。
hart 是 硬 件 线 程 (hardware thread)的缩略 形式。 我们用该术语将 它们与大多数程序员熟 悉的软件线程区分开 来。软件线程在 harts 上 进行分时复用。 大多数 处理器核都只有一个 hart。
CSR:控制状态寄存器
机器模式最重要的特性是拦截和处理异常
(不寻常的运行时事件)的能力。
RISC-V 将 异常分为两类。
- 同步异常:这类异常在指令执行期间产生
- 如访问了无效的存储器地址
- 执行了具有无效操作码的指令
- 中断:它是与指令流异步的外部事件,比如键盘输入。
为了方便表述与区分,本文接下来的表述按照如下规则
- 异常:异常分两类,其中的同步异常
- 中断:异常分两类,其中的中断
RISC-V 异常和中断的原因
中断时mcause
的最高有效位被设置成1
,异常时置为0
,剩下的位标识了中断或者异常的具体原因。
中断类型(来源)
- 软件中断:软件中断通过向内存映射寄存器中存数来触发,并通常用于由一个 hart 中断另一个 hart(在其他架构中称为处理器间中断机制)。
- 时钟中断:当 hart 的时间比较器(一个名为
mtimecmp
的内存映射寄存器)大于实时计数器mtime
时,会触发时钟中断。 - 外部中断: 有平台级中断控制器(大多数外部设备连接到这个中断控制器)引发。
机器模式下的异常、中断处理
八个控制状态寄存器(CSR)是机器模式下异常、中断处理的必要部分
mtvec
(Machine Trap Vector)它保存发生异常/中断时处理器需要跳转到的地址。- RISC-V 还支持
向量中断
,其中处理器跳转到各类异常/中断各自对应的地址,而不是一个统一的入口点。这种寻址消除 了读取和解码mcause
的需要,加快了中断处理速度。 将mtval [0]
设 置为1
可启用此功能; 然后根据异常/中断原因x
将PC
设置为(mtval-1 + 4x ),
而 不 是 通 常 的mtvec
。
- RISC-V 还支持
mepc
(Machine Exception PC)它指向发生异常/中断的指令。mcause
(Machine Exception Cause)它指示发生异常/中断的原因(类型)。mie
(Machine Interrupt Enable)它指出处理器当前屏蔽了哪些中断。mip
(Machine Interrupt Pending)它列出目前正准备处理的中断(已经到来的中断)。mtval
(Machine Trap Value)它保存了陷入(trap)的附加信息:page fault
中出错的地址、发生非法指令例外的指令本身,对于其他异常,它的值为 0。mscratch
(Machine Scratch)它暂时存放一个字大小的数据。mstatus
(Machine Status)它保存全局中断使能,以及许多其他的状态
mstatus
mstatus.MIE
置 1 时才会产生中断。
mstatus.PMIE
它在异常/中断发生后保存 MIE
的旧值
mie
每个中断在控制状态寄存器 mie 中都有自己的使能位。这些位在 mie 中的位置对应于图[[RISC-V 异常和中断的原因.png]]。例如,mie[7]=1
对应于 M 模式中的时钟中断打开。
注意:中断可以被屏蔽,但是异常不能被屏蔽
mip
与 mie
有着相同的布局,并且指示当前待处理的中断。
三者相互配合
mstatus.MIE
=1 打开接收中断的总开关 = 1mie[7]
= 1 接收时钟中断mip[7]
= 1 当前待处理的中断刚好有时钟中断
则可以处理机器的时钟中断。mstatus[MIE] & mie[7] & mip[7] ≠ 0
当一个hart 发生异常、中断时
硬件会自动经历如下的状态转换:
- 异常指令的
PC
被保存在mepc
中,PC
被设置为mtvec
。- 对于同步异常:
pepc
指向导致异常的指令。 - 对于中断:它指向中断处理后应该恢复执行的位置。(这个由软件设置)
- 对于同步异常:
- 根据异常/中断源来设置
mcause
寄存器。 - 将
mtval
设置为出错的地址或者其他适用于特定异常的信息。 - 将
mstatus
中的MIE
位置置零以禁用中断,并把先前的MIE
值保留到MPIE
中。 - 发生异常之前的权限模式保留在
mstatus
的MPP
域中,再把权限模式更改为M
。(如果处理器仅实现 M 模式,则有效地跳过这个步骤)。
处理中
为避免覆盖整数寄存器中的内容,异常/中断处理程序先在最开始用 mscratch
和整数寄存器(例如 a0
)中的值交换。通常,软件会让 mscratch
包含指向附加临时内存空间的指针,处理程序用该指针来保存其主体中将会用到的整数寄存器。在主体执行之 后,中断程序会恢复它保存到内存中的寄存器,然后再次使用 mscratch
和 a0
交换, 将两个寄存器恢复到它们在发生异常之前的值。
返回
- 使用
mret
指令返回,mret
将PC
设置为mepc
- 将
mstatus
的MPIE
域复制到MIE
来恢复之前的中断使能设置 - 并将权限模式设置为
mstatus
的MPP
域中的值
委托
默认情况下,发生所有异常(不论在什么权限模式下)的时候,控制权都会被移交到 M
模式的异常处理程序。但是 Unix 系统中的大多数例外都应该进行 S
模式下的系统调 用。M
模式的异常处理程序可以将异常重新导向 S
模式,但这些额外的操作会减慢大多数 异常的处理速度。因此,RISC-V 提供了一种异常委托机制
。通过该机制可以选择性地将中断和同步异常交给 S 模式处理,而完全绕过 M 模式。
委托中断
mideleg(Machine Interrupt Delegation,机器中断委托)CSR控制将哪些中断委托给 S模式
与 mip
和 mie
一样,mideleg
中的每个位对应于”异常/中断原因图“相同的中断。例如, mideleg[5]
对应于 S 模式的时钟中断,如果把它置位,S 模式的时钟中断将会移交 S 模式 的异常处理程序,而不是 M 模式的异常处理程序。
屏蔽委托的中断
委托给 S 模式的任何中断都可以被 S 模式的sie
CSR屏蔽。
sie
(Supervisor Interrupt Enable,监管者中断使能)和 sip
(Supervisor Interrupt Pending,监管者中断待处理)CSR 是 S
模式的控制状态寄存器,他们是 mie
和 mip
的子集。它们有着和 M
模式下相同的布局,但在 sie
和 sip
中只有与由 mideleg 委托的中断对应的位才能读写。那些没有被委派 的中断对应的位始终为零。
委托异常
M 模式还可以通过 medeleg CSR 将同步异常委托给 S 模式
medeleg[15]
便会把 store page fault
(store 过程中出现的缺页)委托给 S 模式。
基于页面的虚拟内存
S 模式提供了一种传统的虚拟内存系统,它将内存划分为固定大小的页来进行地址转 换和对内存内容的保护。启用分页的时候,大多数地址(包括 load 和 store 的有效地址和 PC 中的地址)都是虚拟地址。要访问物理内存,它们必须被转换为真正的物理地址,这通 过遍历一种称为页表的多叉树实现。 RISC-V 的分页方案以 SvX 的模式命名,其中 X 是以位为单位的虚拟地址的长度。RV64 支持多种分页方案,但我们只介绍最受欢迎的一种,Sv39。
标志位 | 说明 |
---|---|
V | 决定了该页表项的其余部分是否有效(V = 1 时有效) 。若 V = 0,则任何遍历到此页表项的虚址转换操作都会导致页错误。 |
R、W 和 X | 位分别表示此页是否可以读取、写入和执行。如果这三个位都是 0,V=1 那么这个页表项是指向下一级页表的指针,否则它是页表树的一个叶节点。 |
U | 位表示该页是否是用户页面。若 U = 0,则 U 模式不能访问此页面,但 S 模式 可以。若 U = 1,则 U 模式下能访问这个页面 。 |
G | 表示这个映射是否对所有虚址空间有效,硬件可以用这个信息来提高地址转换的性能。这一位通常只用于属于操作系统的页面 |
A | 位表示自从上次 A 位被清除以来,该页面是否被访问过。 |
D | 位表示自从上次清除 D 位以来页面是否被弄脏(例如被写入)。 |
RSW | 域留给操作系统使用,它会被硬件忽略。 |
PNN | PPN 域包含物理页号,这是物理地址的一部分。若这个页表项是一个叶节点,那 么 PPN 是转换后物理地址的一部分。否则 PPN 给出下一节页表的地址。 |
操作系统依赖于 A 位和 D 位来决定将哪些页面 交换到辅存。定期清除 A 位有助于 OS 判断哪 些页面是最近最少使用 的。 置上 D 位表示换 出该页面的成本更高, 因为它必须写回辅存。
一个叫 satp(Supervisor Address Translation and Protection,监管者地址转换和保护) 的 S 模式控制状态寄存器控制了分页系统。satp 有三个域。Mode域可以开启分页并选择页表级数。ASID(Address Space Identifier, 地址空间标识符)域是可选的,它可以用来降低上下文切换的开销。最后,PPN 字段保存 了根页表的物理地址,它以 4 KiB 的页面大小为单位。通常 M 模式的程序在第一次进入 S 模式之前会把零写入 satp 以禁用分页,然后 S 模式的程序在初始化页表以后会再次进行 satp 寄存器的写操
清除TLB缓存
所有现代的处理器都用地 址转换缓存(通常称为 TLB,全称为 Translation Lookaside Buffer)来减少这种开销。为了 降低这个缓存本身的开销,大多数处理器不会让它时刻与页表保持一致。这意味着如果操 作系统修改了页表,那么这个缓存会变得陈旧而不可用。S 模式添加了另一条指令来解决 这个问题。这条sfence.vma
会通知处理器,软件可能已经修改了页表,于是处理器可以 相应地刷新转换缓存。它需要两个可选的参数,这样可以缩小缓存刷新的范围。一个位于 rs1,它指示了页表哪个虚址对应的转换被修改了;另一个位于 rs2,它给出了被修改页表 的进程的地址空间标识符(ASID)。如果两者都是 x0,便会刷新整个转换缓存。
特权指令:
mret
: machine-mode trap returnsret
: supervisor-mode trap returnsfence.vma
: supervisor-mode fence.virtual memory addreeewfi
: wait for interruptcsrr
,读取一个 CSR 的值到通用寄存器。如:csrr t0, mstatus
,读取mstatus
的值到t0
中。csrw
,把一个通用寄存器中的值写入 CSR 中。如:csrw mstatus, t0
,将t0
的值写入mstatus
。csrs
,把 CSR 中指定的 bit 置 1。如:csrsi mstatus, (1 << 2)
,将mstatus
的右起第 3 位置 1。csrc
,把 CSR 中指定的 bit 置 0。如:csrci mstatus, (1 << 2)
,将mstatus
的右起第 3 位置 0。csrrw
,读取一个 CSR 的值到通用寄存器,然后把另一个值写入该 CSR。如:csrrw t0, mstatus, t0
,将mstatus
的值与t0
的值交换。csrrs
,读取一个 CSR 的值到通用寄存器,然后把该 CSR 中指定的 bit 置 1。csrrc
,读取一个 CSR 的值到通用寄存器,然后把该 CSR 中指定的 bit 置 0。