RISCV 切换特权级原理

我们首先介绍一下 RISCV 中切换特权级的原理。关于具体细节,我们会在后面的内容中介绍。你不需要对整个过程中所有的寄存器都有深入的了解。

典型的特权级切换过程

最通常的同步特权级切换就是系统调用。在一次系统调用中,用户态程序会使用 ecall 指令进入内核为其设置好的处理代码段。这段代码通常会先保存所有的上下文(这阶段不需要保存用户态的 pc,因为已经有寄存器保存了,这个寄存器叫 sepc),然后根据内核的设计,可能会切换页表,然后跳转到内核的 trap 处理代码。完成后,如果内核要返回该应用的用户态,那么会通过 CSR 寄存器设置好应用的环境(包括 ecall 的处理代码),并恢复上下文,然后执行 sret 指令返回用户态。

最通常的异步特权级切换是时间片的中断。时间片中断会进入 M mode,所以为了进入到 S mode,我们需要再进行一次特权级的切换。这个切换可以通过同步或异步的方式完成。

注意在 ecalleret 的过程中,除 pc 以外的通用寄存器都不会被修改。

高特权级到低特权级的同步方式

前面已经举了一个例子,在高特权级到低特权级的过程中,我们通常会设置好应用的环境,然后保存所有的通用寄存器,切换页表(如果需要),最后执行 *ret 指令回到用户态。

低特权级到高特权级的同步方式

低特权级到高特权级是通过 ecall 来实现的,此时 CPU 会跳转到内核设置的处理代码。

异步方式

异步方式是通过中断来实现的。中断会进入到特定状态(取决于是何种特权级的中断)的特定处理代码。