RISCV 切换特权级原理
我们首先介绍一下 RISCV 中切换特权级的原理。关于具体细节,我们会在后面的内容中介绍。你不需要对整个过程中所有的寄存器都有深入的了解。
典型的特权级切换过程
最通常的同步特权级切换就是系统调用。在一次系统调用中,用户态程序会使用 ecall
指令进入内核为其设置好的处理代码段。这段代码通常会先保存所有的上下文(这阶段不需要保存用户态的 pc
,因为已经有寄存器保存了,这个寄存器叫 sepc
),然后根据内核的设计,可能会切换页表,然后跳转到内核的 trap 处理代码。完成后,如果内核要返回该应用的用户态,那么会通过 CSR 寄存器设置好应用的环境(包括 ecall
的处理代码),并恢复上下文,然后执行 sret
指令返回用户态。
最通常的异步特权级切换是时间片的中断。时间片中断会进入 M mode,所以为了进入到 S mode,我们需要再进行一次特权级的切换。这个切换可以通过同步或异步的方式完成。
注意在 ecall
和 eret
的过程中,除 pc
以外的通用寄存器都不会被修改。
高特权级到低特权级的同步方式
前面已经举了一个例子,在高特权级到低特权级的过程中,我们通常会设置好应用的环境,然后保存所有的通用寄存器,切换页表(如果需要),最后执行 *ret
指令回到用户态。
低特权级到高特权级的同步方式
低特权级到高特权级是通过 ecall
来实现的,此时 CPU 会跳转到内核设置的处理代码。
异步方式
异步方式是通过中断来实现的。中断会进入到特定状态(取决于是何种特权级的中断)的特定处理代码。