更多精彩,请点击上方
蓝字关注我
前言:
RISC-V(发音为“risk-five”)是一种新的指令集架构(ISA),最初的设计目的是支持计算机架构的研究和教育,但随着近些年的发展,它已经成为工业实现中的一个标准化、免费且开放的架构。
RISC-V 指令集的一大优势是其可扩展性,用户可根据具体应用需求,选择合适的扩展指令集,本文介绍Smrnmi扩展。(所有spec下载:我整理了RISC-V所有spec(附下载链接))
0. 背景
基础机器级架构仅支持不可恢复不可屏蔽中断(UNMI)。此时 NMI 会跳转到机器模式下的处理程序,并覆盖当前 mepc 和 mcause 寄存器的值。
若硬件线程(hart)正在陷阱处理程序中执行机器模式代码,mepc 和 mcause 中的原有值将无法恢复,因此执行过程通常不具备可恢复性。
Smrnmi 扩展为 RISC-V 架构新增了可恢复不可屏蔽中断(RNMI)支持,通过新增四个控制状态寄存器(CSR)(mnepc、mncause、mnstatus 和 mnscratch)存储中断状态,并添加一条新指令 MNRET 用于从 RNMI 处理程序恢复执行。
1. RNMI 中断信号
RNMI 中断信号是硬件线程(hart)的输入信号,其优先级高于 hart 上的所有其他中断和异常,且无法被软件禁用 —— 即使清除 mstatus.MIE 寄存器也无法屏蔽该类中断。
2. RNMI 处理程序地址
RNMI 中断陷阱处理程序地址为设计实现定义(implementation-defined)。
RNMI 还关联一个异常陷阱处理程序地址,该地址同样为实现定义。
例如,部分实现可能将 mtvec 寄存器指定的地址用作 RNMI 异常陷阱处理程序。
3. RNMI 控制状态寄存器(CSR)
本扩展新增了以下机器模式(M-mode)CSR,以支持可恢复不可屏蔽中断:
3.1 可恢复 NMI 暂存寄存器(mnscratch)
mnscratch 是一个 MXLEN 位的读写寄存器,供 RNMI 陷阱处理程序保存和恢复被中断的上下文。
3.2 可恢复 NMI 程序计数器(mnepc)
mnepc 是一个 MXLEN 位的读写寄存器,进入 RNMI 陷阱处理程序时,其值将被设置为触发中断的指令地址(PC)。
-
mnepc 的最低位(mnepc [0])恒为 0; -
仅支持 IALIGN=32(指令对齐方式为 32 位)的实现中,最低两位(mnepc [1:0])恒为 0; -
若实现允许 IALIGN 在 16 位和 32 位之间切换(例如通过修改 misa 寄存器),则当 IALIGN=32 时,读取 mnepc [1] 会被掩码为 0(包括 MRET 指令的隐式读取),但该位仍可写入; -
mnepc 为 WARL(写任意值读合法值)寄存器,需支持存储所有有效虚拟地址,无需支持存储所有无效地址;写入前,实现可将无效地址转换为其支持的其他无效地址。
3.3 可恢复 NMI 原因寄存器(mncause)
mncause 用于存储 RNMI 的触发原因,编码规则如下:
-
若为中断触发:最高位(MXLEN-1)设为 1,最低位字段存储 RNMI 具体原因编码; -
若为中断触发但不支持 RNMI 原因编码:最高位(MXLEN-1)设为 1,最低位字段设为 0; -
若为机器模式下的异常(符合 Smdbltrp 扩展定义的双重陷阱场景):最高位(MXLEN-1)设为 0,最低位字段存储触发双重陷阱的异常原因码。
3.4 可恢复 NMI 状态寄存器(mnstatus)
mnstatus 包含以下字段:
- MNPP(2 位字段):进入 RNMI 陷阱处理程序时,存储被中断上下文的特权模式,编码方式与 mstatus.MPP 一致;
- MNPV(1 位字段):进入 RNMI 陷阱处理程序时,存储被中断上下文的虚拟化模式,编码方式与 mstatus.MPV 一致;
- MNPELP(可选字段):若实现 Zicfilp 扩展,该字段存储被中断上下文的前序 ELP(扩展特权级别)状态;触发 RNMI 陷阱时,MNPELP 将被设为当前 ELP 值,同时 ELP 清零;
- NMIE(1 位字段):中断使能控制位
-
NMIE=1:允许不可屏蔽中断; -
NMIE=0:禁用所有中断(此时 hart 行为等同于 mstatus.MPRV 被清零,无论其实际配置); -
复位后 NMIE 初始值为 0(RNMI 默认被屏蔽,以便软件初始化 RNMI 处理所需的数据结构和设备); -
软件可将 NMIE 设为 1,但尝试清零 NMIE 无效(通常仅复位序列会显式设置 NMIE 位)。
注:NMIE 的可设置性并不支持 RNMI 嵌套 —— 直接支持嵌套需允许软件清零 NMIE,这与不可屏蔽中断的设计理念冲突。若需最小化下一次 RNMI 的响应延迟,软件可采用 “上半部分 / 下半部分”(top-half/bottom-half)模型:RNMI 处理程序仅将任务加入队列后立即返回,中断服务的主体逻辑在 RNMI 使能状态下异步执行。
-
对于 WFI(等待中断)指令:NMIE 属于全局中断使能位,其状态不影响 WFI 指令的运行; -
mnstatus 的其他位为保留位,软件应写入 0,硬件读取时应返回 0。
4. MNRET 指令
MNRET 是仅机器模式(M-mode)支持的指令,功能如下:
-
从 mnepc 恢复程序计数器(PC); -
从 mnstatus 恢复特权模式和虚拟化模式; -
设置 mnstatus.NMIE(重新使能中断); -
若恢复后的特权模式低于 M-mode,将 mstatus.MPRV 清零; -
若实现 Zicfilp 扩展,且新特权模式为 y,则将 ELP 设为 yLPE与 mnstatus.MNPELP 的按位与结果。
5. RNMI 工作流程
当检测到 RNMI 中断时,硬件执行以下操作:
-
将被中断的 PC 值写入 mnepc 寄存器; -
将 RNMI 类型写入 mncause 寄存器; -
将被中断上下文的特权模式写入 mnstatus 寄存器; -
清零 mnstatus.NMIE 位(屏蔽所有中断); -
进入机器模式(M-mode),并跳转到 RNMI 陷阱处理程序地址。
RNMI 处理程序可通过 MNRET 指令恢复原执行流程:
-
从 mnepc 恢复 PC; -
从 mnstatus 恢复特权模式; -
设置 mnstatus.NMIE(重新使能中断)。
若 hart 在 mnstatus.NMIE=0(中断屏蔽状态)下执行机器模式代码时触发异常,处理逻辑与 NMIE=1 时一致,仅程序计数器(PC)会被设置为 RNMI 异常陷阱处理程序地址。
Smrnmi 扩展不改变 MRET 和 SRET 指令的原有行为:
-
MRET/SRET 不受 mnstatus.NMIE 位影响; -
执行 MRET/SRET 不会修改 mnstatus.NMIE 位。

