- machine mode: 运行最可信的代码;
- supervisor mode:为 Linux,FreeBSD 和 Windows 等操作系统提供支持;
- user mode:权限最低,应用程序的代码在此模式下运行;
这两种新模式都比user mode有着更高的权限,有更多权限的模式通常可以使用权限较低的模式的所用功能,并且它们还有一些低权限模式下不可用的额外功能,例如处理中断和执行 I/O 的功能。
处理器通常大部分时间都运行在权限最低的模式下,处理中断和异常时会将控制权移交到更高权限的模式。
machine mode
- RISC-V 中 hart(hardware thread,硬件线 程)可以执行的最高权限模式;
- 在 M 模式下运行的 hart 对内存,I/O 和一些对于启动和配 置系统来说必要的底层功能有着完全的使用权;
- 它是唯一所有标准 RISC-V 处理器都 必须实现的权限模式。
- 简单的 RISC-V 微控制器仅支持 M 模式;
- 机器模式最重要的特性是拦截和处理异常(不寻常的运行时事件)的能力。包括exception和interrupt;
- M mode下,可能发生的exception有:
- access fault exception,当物理内存的地址不支持访问类型时发生(例如尝试写入 ROM)。
- Breadkpoint exception, 在执行 ebreak 指令,或者地址或数据matches debug trigger;
- Environment call exception, 在执行 ecall 指令时发生。
- Illegal instruction exception, 在译码阶段发现无效操作码时发生。
- Misaligned addr exception,在有效地址不能被访问大小整除时发生,例如地址为 0x12 的 amoadd.w
三种标准的中断源:软件、时钟和外部来源。
- 软件中断通过向内存映射寄存器中存数来触发,并通常用于由一个 hart 中断另一个 hart(在其他架构中称为处理器间中断机 制)
- 当 hart 的时间比较器(一个名为 mtimecmp 的内存映射寄存器)大于实时计数器 mtime 时,会触发时钟中断。
- 外部中断由平台级中断控制器(大多数外部设备连接到这个 中断控制器)引发。
机器模式下的异常处理
八个控制状态寄存器(CSR)是机器模式下异常处理的必要部分。
- mtvec(Machine Trap Vector)它保存发生异常时处理器需要跳转到的地址。
- mepc(Machine Exception PC)它指向发生异常的指令。
- mcause(Machine Exception Cause)它指示发生异常的种类。
- mie(Machine Interrupt Enable)它指出处理器目前能处理和必须忽略的中断。
- mip(Machine Interrupt Pending)它列出目前正准备处理的中断。
- mtval(Machine Trap Value)它保存了陷入(trap)的附加信息:addr exception中出错的地址、发生非法指令例外的指令本身,对于其他异常,它的值为 0。
- mscratch(Machine Scratch)它暂时存放一个字大小的数据。
- mstatus(Machine Status)它保存全局中断使能,以及许多其他的状态,如图 10.4 所示。
处理器在 M 模式下运行时,只有在全局中断使能位 mstatus.MIE 置 1 时才会产生中 断.此外,每个中断在控制状态寄存器 mie 中都有自己的使能位;这些位在 mie 中的位置对应于图 10.3 中的中断代码。例如,mie[7]对应于 M 模式中的时钟中断。
控制状态寄存器 mip具有相同的布局,并且它指示当前待处理的中断。将所有三个控制状态寄存器合在一起考 虑,如果 mstatus.MIE = 1,mie[7] = 1,且 mip[7] = 1,则可以处理机器的时钟中断。
当一个 hart 发生异常时,硬件自动经历如下的状态转换
- 异常指令的 PC 被保存在 mepc 中,PC 被设置为 mtvec。
- 对于同步异常,mepc 指向导致异常的指令;对于中断,它指向中断处理后应该恢复执行的位置
- 根据异常来源设置 mcause(如图 10.3 所示),并将 mtval 设置为出错的地址或 者其它适用于特定异常的信息字。
- 把控制状态寄存器 mstatus 中的 MIE 位置零以禁用中断,并把先前的 MIE 值保 留到 MPIE 中
- 发生异常之前的权限模式保留在 mstatus 的 MPP 域中,再把权限模式更改为 M。图 10.5 显示了 MPP 域的编码(如果处理器仅实现 M 模式,则有效地跳过这 个步骤)。
为避免覆盖整数寄存器中的内容,中断处理程序先在最开始用 mscratch 和整数 寄存器(例如 a0)中的值交换。通常,软件会让 mscratch 包含指向附加临时内存空 间的指针,处理程序用该指针来保存其主体中将会用到的整数寄存器。在主体执行之 后,中断程序会恢复它保存到内存中的寄存器,然后再次使用 mscratch 和 a0 交换, 将两个寄存器恢复到它们在发生异常之前的值。最后,处理程序用 mret 指令(M 模 式特有的指令)返回。mret 将 PC 设置为 mepc,通过将 mstatus 的 MPIE 域复制到 MIE 来恢复之前的中断使能设置,并将权限模式设置为 mstatus 的 MPP 域中的值。 这基本是前一段中描述的逆操作。
有时需要在处理异常的过程中转到处理更高优先级的中断。唉,mepc, mcause,mtval 和 mstatus 这些控制寄存器只有一个副本,处理第二个中断的时候 如果软件不进行一些帮助的话,这些寄存器中的旧值会被破坏,导致数据丢失。可抢 占的中断处理程序可以在启用中断之前把这些寄存器保存到内存中的栈,然后在退出 之前,禁用中断并从栈中恢复寄存器。
除了上面介绍的 mret 指令之外,M 模式还提供了另外一条指令:wfi(Wait For Interrupt)。wfi 通知处理器目前没有任何有用的工作,所有它应该进入低功耗模式, 直到任何使能有效的中断等待处理,即mie&mip ≠ 0。RISC-V 处理器以多种方式实现 该指令,包括到中断待处理之前都停止时钟。有的时候只把这条指令当作 nop 来执 行。因此,wfi 通常在循环内使用。