问题1:内核如何处理来自用户空间的陷阱?
进入内核空间的路径:先uservec
,后usertrap
;
返回用户空间的路径:先usertrapret
,后userret
;
问题2:函数uservec
都做了哪些事?
- 保存除了
pc
之外的所有寄存器的值; - 切换内核页表;
- 切换内核栈;
- 调用
usertrap
;
问题3:函数usertrap
都做了哪些事?
- 判断陷阱的原因;
- 处理陷阱;
- 从内核中返回,即调用
usertrapret
;
问题4:函数usertrapret
都做了哪些事?
为下一次来自用户空间的陷阱做好准备,包括:
- 修改
stvec
指向uservec
; - 准备好
trapframe
字段; - 设置
sepc
为之前保存的用户pc
; - 调用
userret
;
问题5:函数userret
都做了哪些事?
- 切换用户页表;
- 恢复用户寄存器的值;
- 在
sscratch
中保存用户trapframe
的地址; - 使用
sret
指令返回到用户空间;
问题6:进程的trapframe
有哪些性质?
- 什么时候创建?
创建进程时,分配一个页用于进程的trapframe
,并映射到用户的虚拟地址TRAPFRAME
。 - 相关的指针有哪些?
p->trapframe
;
问题7:在处理来自用户空间的陷阱时,是如何使用trapframe
的?
- 进入内核空间时,在
trapframe
上保存属于用户空间的寄存器的值; - 返回用户空间时,保存
trapframe
为下次陷阱做好准备;
比如,当前进程的内核栈指针、usertrap
的地址、内核页表的地址等;
问题8:uservec
函数和trampoline
页的联系?
-
uservec
函数在trampline
页上。 - 基于事实:
trampoline
页被映射到内核页表和用户页表的虚拟地址是相同的,所以在修改satp
后,uservec
可继续执行。
问题9:陷阱帧trapframe
上有哪些数据?
- 当前进程内核栈的指针;
- 当前CPU的hartid;
-
usertrap
的地址; - 内核页表的地址;
问题10:在处理来自用户空间的陷阱过程中,a0
和sscratch
进行了几次交换?
两次,分别是
- 在进入内核的过程中,
uservec
在一开始就使用csrrw
指令交换a0
和sscratch
交换后,原用户空间的a0
值被保存到sscratch
中,即sscratch
此时的值是陷阱发生时用户空间的a0
,a0
的值是内核先前在sscratch
中放入的值。 - 在返回用户空间的过程中,userret交换
a0
和sscratch
交换前,sscratch
中记录的是陷阱发生时保存的用户空间的a0
值,交换后,a0
的值就是先前保存的用户空间的值;
交换前,在usertrapret
调用userret
时,给a0
传递了指向TRAPFRAME
的指针,交换后,sscratch
中记录的就是指向TRAPFRAME
的指针;
网友评论