笔记思维导图
trap流程图
注意
ecall
不会更换页表,所以这意味着,陷阱处理代码必须存在于每一个用户页表中。而蹦床页面(trampoline page),是由内核小心的映射到每一个用户页表中,以使得当我们仍然在使用用户页表时,内核在一个地方能够执行trap机制的最开始的一些指令。这个地址是由stvec
指明的,每次从内核空间转为用户空间前,都会设置好stvec
- 即使蹦床页面是在用户地址空间的页表完成的映射,但用户代码不能写它,因为这些页面对应的PTE并没有设置PTE_U标志位。这也是为什么trap机制是安全的。
SSCRATCH
如何保存TRAPFRAME
,即陷阱帧的地址?
操作系统开始时先运行在管理模式,即内核中,而后才会转到用户模式
在从内核返回到用户空间的最后一个C函数usertrapret
(kernel/trap.c)中最后一行代码((void (*)(uint64, uint64))fn)(TRAPFRAME, satp)
调用fn
函数,第一个参数将传入a0
中保存,因此a0
保存了TRAPFRAME
,而在trampoline.S中userret
函数执行了csrrw a0, sscratch, a0
指令交换了sscratch
和a0
的值,因此SSCRATCH
保存TRAPFRAME
了。