中断处理
由于用户进程比起内核进程多了一个"用户栈",也就是每个用户进程会有两个栈,一个内核栈一个用户栈,所以中断处理的代码trapentry.S
要有一些小变化。关注用户态产生中断时,内核栈和用户栈两个栈顶指针的移动。
# kern/trap/trapentry.S
#include <riscv.h>
# 若在中断之前处于 U mode(用户态)
# 则 sscratch 保存的是内核栈地址
# 否则中断之前处于 S mode(内核态),sscratch 保存的是 0
.altmacro
.align 2
.macro SAVE_ALL
LOCAL _restore_kernel_sp
LOCAL _save_context
# If coming from userspace, preserve the user stack pointer and load
# the kernel stack pointer. If we came from the kernel, sscratch
# will contain 0, and we should continue on the current stack.
csrrw sp, sscratch, sp #这里交换了sp和sccratch寄存器
#sp为0,说明之前是内核态,我们刚才把内核栈指针换到了sscratch, 需要再拿回来
#sp不为0 时,说明之前是用户态,sp里现在存的就是内核栈指针,sscratch里现在是用户栈指针
#sp不为0,就跳到_save_context, 跳过_restore_kernel_sp的代码
bnez sp, _save_context
_restore_kernel_sp:
csrr sp, sscratch #刚才把内核栈指针换到了sscratch, 需要再拿回来
_save_context:
#分配栈帧
addi sp, sp, -36 * REGBYTES
# save x registers
STORE x0, 0*REGBYTES(sp)
STORE x1, 1*REGBYTES(sp)
STORE x3, 3*REGBYTES(sp)
STORE x4, 4*REGBYTES(sp)
STORE x5, 5*REGBYTES(sp)
STORE x6, 6*REGBYTES(sp)
STORE x7, 7*REGBYTES(sp)
STORE x8, 8*REGBYTES(sp)
STORE x9, 9*REGBYTES(sp)
STORE x10, 10*REGBYTES(sp)
STORE x11, 11*REGBYTES(sp)
STORE x12, 12*REGBYTES(sp)
STORE x13, 13*REGBYTES(sp)
STORE x14, 14*REGBYTES(sp)
STORE x15, 15*REGBYTES(sp)
STORE x16, 16*REGBYTES(sp)
STORE x17, 17*REGBYTES(sp)
STORE x18, 18*REGBYTES(sp)
STORE x19, 19*REGBYTES(sp)
STORE x20, 20*REGBYTES(sp)
STORE x21, 21*REGBYTES(sp)
STORE x22, 22*REGBYTES(sp)
STORE x23, 23*REGBYTES(sp)
STORE x24, 24*REGBYTES(sp)
STORE x25, 25*REGBYTES(sp)
STORE x26, 26*REGBYTES(sp)
STORE x27, 27*REGBYTES(sp)
STORE x28, 28*REGBYTES(sp)
STORE x29, 29*REGBYTES(sp)
STORE x30, 30*REGBYTES(sp)
STORE x31, 31*REGBYTES(sp)
# get sr, epc, tval, cause
# Set sscratch register to 0, so that if a recursive exception
# occurs, the exception vector knows it came from the kernel
#如果之前是用户态产生的中断,用户栈指针从sscratch里挪到了s0寄存器, sscratch清零
csrrw s0, sscratch, x0
csrr s1, sstatus
csrr s2, sepc
csrr s3, 0x143 #stval
csrr s4, scause
STORE s0, 2*REGBYTES(sp) #如果之前是用户态发生中断,此时用户栈指针存到了内存里
STORE s1, 32*REGBYTES(sp)
STORE s2, 33*REGBYTES(sp)
STORE s3, 34*REGBYTES(sp)
STORE s4, 35*REGBYTES(sp)
.endm
.macro RESTORE_ALL
LOCAL _save_kernel_sp
LOCAL _restore_context
LOAD s1, 32*REGBYTES(sp)
LOAD s2, 33*REGBYTES(sp)
andi s0, s1, SSTATUS_SPP #可以通过SSTATUS_SPP的值判断之前是用户态还是内核态
bnez s0, _restore_context
_save_kernel_sp:
# Save unwound kernel stack pointer in sscratch
addi s0, sp, 36 * REGBYTES
csrw sscratch, s0
_restore_context:
csrw sstatus, s1
csrw sepc, s2
# restore x registers
LOAD x1, 1*REGBYTES(sp)
LOAD x3, 3*REGBYTES(sp)
LOAD x4, 4*REGBYTES(sp)
LOAD x5, 5*REGBYTES(sp)
LOAD x6, 6*REGBYTES(sp)
LOAD x7, 7*REGBYTES(sp)
LOAD x8, 8*REGBYTES(sp)
LOAD x9, 9*REGBYTES(sp)
LOAD x10, 10*REGBYTES(sp)
LOAD x11, 11*REGBYTES(sp)
LOAD x12, 12*REGBYTES(sp)
LOAD x13, 13*REGBYTES(sp)
LOAD x14, 14*REGBYTES(sp)
LOAD x15, 15*REGBYTES(sp)
LOAD x16, 16*REGBYTES(sp)
LOAD x17, 17*REGBYTES(sp)
LOAD x18, 18*REGBYTES(sp)
LOAD x19, 19*REGBYTES(sp)
LOAD x20, 20*REGBYTES(sp)
LOAD x21, 21*REGBYTES(sp)
LOAD x22, 22*REGBYTES(sp)
LOAD x23, 23*REGBYTES(sp)
LOAD x24, 24*REGBYTES(sp)
LOAD x25, 25*REGBYTES(sp)
LOAD x26, 26*REGBYTES(sp)
LOAD x27, 27*REGBYTES(sp)
LOAD x28, 28*REGBYTES(sp)
LOAD x29, 29*REGBYTES(sp)
LOAD x30, 30*REGBYTES(sp)
LOAD x31, 31*REGBYTES(sp)
# restore sp last
LOAD x2, 2*REGBYTES(sp) #如果是用户态产生的中断,此时sp恢复为用户栈指针
.endm
.globl __alltraps
__alltraps:
SAVE_ALL
move a0, sp
jal trap
# sp should be the same as before "jal trap"
.globl __trapret
__trapret:
RESTORE_ALL
# return from supervisor call
sret
.globl forkrets
forkrets:
# set stack to this new process's trapframe
move sp, a0
j __trapret
目前为止的代码可以在这里找到。
最后更新于