4.1.2 中断跳转

本文章是对 Trap 的补充,如果没有看过的话最好先去看看。不看对后续影响不大,可以作为独立的文章阅读。

__alltrap

当操作系统产生中断时, cpu 会跳转到 stvec 控制寄存器中保存的地址。在 interrupt::init 中,我们设置这个地址为 __alltrap

.section .text
.globl __alltraps
__alltraps:
    SAVE_ALL
    mv a0, sp
    jal rust_trap
.globl __trapret
__trapret:
    RESTORE_ALL
    # return from supervisor call
    sret

.globl 表示该符号是一个全局符号,可以被外部访问到。 .section .text__alltraps__trapret 放到程序的同一个代码段中,使得 __alltrap 执行完后会立刻执行 __trapret 。在使用 SAVE_ALL 保存了所有寄存器状态后,将 栈帧地址(sp) 赋值给 a0a0 是参数寄存器, jal 调用的函数(rusttrap)将把 a0 中的内容作为参数。在处理完中断后,由 **\_trapret** 将寄存器恢复到中断前的状态,继续执行中断前的指令。

SAVE_ALL

保存寄存器的工作只能在 内核态 进行。如果当前处于 用户态 ,则需要先返回内核态,再保存寄存器:

这里我们通过 sscratch 寄存器来判断操作系统所处状态。在执行完 csrrw sp, sscratch, sp 后,如果 sp 的值为 0 ,则当前状态为内核态,直接跳转开始保存寄存器。否则需要先执行 csrr sp, sscratch ,跳转至内核态,再保存寄存器,并修改 sscratch ,表示已经处于内核态。

RESTORE_ALL

在恢复寄存器则与保存的过程相反。首先通过 sstatus 判断中断前操作系统所处状态。若为用户态,则需要恢复 sscratch 的值:

代码总览

将上述所有代码整理好后,我们的 trap.asm 应该长成这样:

Last updated

Was this helpful?