RISC-V 的特权级与陷入架构

特权级

现代应用处理器通常采用多特权级的设计,限制低特权级的程序访问一些特殊寄存器、内存区域或执行特权指令, 以提高系统的安全性与隔离性。如 x86 架构有 Ring0 到 Ring3 ,Arm-A z划分了 EL0 到 EL3 , 而 RISC-V 指令集规范将 CPU 的运行状态划分为 Machine, Supervisor, User 这三个特权级。 M 态为最高的特权级,也是所有 RISC-V 平台必须实现的特权级,M 态下的指令对 CPU 有完全的控制权; S 态为通常的操作系统运行的特权级,U 态则为用户程序运行的特权级。

在实现了地址空间隔离的平台上,M 态程序不受地址空间限制,始终使用物理地址访问内存,除非将 mstatus.MPRV 置位; S 态程序可以通过 satp 寄存器控制分页模式和页表基址,通常在初始化完成后运行在虚拟地址上; U 态程序则完全运行在虚拟地址空间中,受页表权限控制位的限制,且无权访问和修改 satp 寄存器的内容。

在引入了虚拟化、可信执行等机制的处理器上,特权级设计会变得更复杂,如 x86 架构进一步划分了 Root 和 Non-Root 模式, RISC-V 则加入了 HS, VS, VU 特权级,本文不会重点讨论这些内容。

陷入

RISC-V 将陷入(trap)分为同步的异常(exception)和异步的中断(interrupt),异常由指令执行产生, 而中断通常来源于指令之外的因素,如时钟、外设等。中断分为外部中断、时钟中断、软件中断, 分别记为 xEI, xTI, xSI (x 为特权级,下同) ;这三者在每个特权级下有不同的中断编号, 因而 M 态的时钟中断和 S 态的时钟中断不是同一个中断。与之相对的是,异常在不同特权级下编号相同, 因为异常源于指令执行,而执行某条指令时系统的特权级是确定的,无需通过编号区分。

中断的使能和屏蔽由 xstatus.xIE 位和 xie 寄存器控制,前者为当前特权级下的全局中断使能, 后者可以独立控制每种中断的使能情况。待处理中断在 xip 寄存器中相应的位为 1 。低特权级的 status, ie, ip 寄存器均为相应高特权级寄存器的子集,即高特权级可以查看和修改低特权级的中断控制信息, 但反过来不行,如 S 态和 M 态的程序均可以通过清除 sie.STIE 来屏蔽 S 态的时钟中断, 但 S 态程序不能通过访问或修改 mie.MTIE 位来影响 M 态时钟中断的行为。这也是特权级架构提供的隔离性的体现。

默认情况下所有的陷入都由最高特权级(即 M 态)的程序来处理,高特权级的程序可以再将其转交给低特权级处理, 如将 xtval, xepc, xcause 写入相应的低特权级寄存器,清除 xip 寄存器中的相应位,再将低特权级的 中断处理函数入口地址(即 ytvec 寄存器的值)移入 xepc 中,执行 xret 指令,即可进入到低特权级的中断处理程序。

为了提高中断处理效率,RISC-V 提供了陷入委托机制,允许陷入在较低特权级处理,相应的控制寄存器为 xidelegxedeleg 。高特权级的陷入不能委托给低特权级。对于已经委托的低特权级陷入, 在高特权级下将被忽略,直至返回低特权级时才进行处理。如 midelegMTI, MEI, MSI 的相应位恒为 0, 不能委托,而将 mideleg.STI 置为 1 则将 S 态的时钟中断委托给 S 态处理,此时即使 mip.STIP==1 , M 态也不会进入中断处理程序。

RISC-V 的 N 扩展草案

在 RISC-V 特权级指令规范 v1.11 版本中存在一章 N 扩展(即用户态中断扩展)的草案。 该扩展设计的主要目标是为嵌入式系统提供更好的安全支持,此类系统可以仅实现 M 和 U 两个特权级, 将“不可信”的用户程序代码置于 U 态执行,同时通过中断委托机制,允许其直接处理中断。 在类 Unix 系统上,该扩展主要希望为整数溢出、浮点异常、垃圾回收等发生在用户态的事件提供支持。

然而有另一些观点认为,在嵌入式系统上,使用 M 和 S 两个特权级可以实现同样的目标,只需将 satp 寄存器由硬件置为 0 ;而对于 Unix 环境下,N 扩展的应用场景尚不明朗, 长期以来也几乎无人推动 N 扩展的完善和实现。最终在 RISC-V 规范 v1.12 版本中,N 扩展被移除, 其他部分关于用户态中断的表述也相应降级。

RISC-V 其他与中断相关的扩展与规范

中断控制器不属于严格意义上的 RISC-V 指令集规范。目前仅 PLIC(Platform-Level Interrupt Controller) 有一个兼容性标准。一种常见的设计是 CLINT(Core-Local Interruptor) 搭配 PLIC,前者提供时钟中断和跨核软件中断支持,后者管理外设产生的中断。

除 CLINT 和 PLIC 之外,RISC-V 还有 CLIC(Core Local Interrupt Controller)、ACLINT(Advanced CLINT)、AIA(Advanced Interrupt Archetecture) 等扩展草案。其中 CLIC 提供低延迟、向量化、可抢占的中断系统,在草案中明确可以与 N 扩展兼容;ACLINT 为 CLINT 扩展,目前可以提供 S 态的跨核中断;AIA 主要提供对 PCIe 标准中的消息信号中断 (Message-Signaled Interrupt) 机制支持。后两者没有明确与用户态中断的兼容性。