-
-
[原创] xv6 陷入机制浅析
-
发表于: 2025-8-30 21:42 553
-
笔者最近在写 xv6 的 lab,阅读 xv6 book 后仍对 xv6 的陷入机制感到迷惑。在统整 xv6 book 中的内容与询问 GPT 的答案后,便产出此篇文章。
因为笔者仍是新手,错误之处请各位师傅指正,谢谢!
xv6 的进程空间:

硬件线程(hardware thread, hart):处理器核心中的一个执行单元。
per-CPU:每个核的资料。
控制与状态寄存器 (Control and Status Register, CSR):存放一些能改变 CPU 行为的控制,并反映处理器目前的状态。
trampoline:其中存放 uservec 与 userret 的汇编代码,帮助从用户模式切换为内核模式或从内核模式返回到用户模式。内核与每个进程都将 trampoline 映射到同一虚拟地址上,使得页表从一个模式切换到另一个模式后,对 trampoline 虚拟地址的访问不会造成 page fault。参考:trampoline.S。
trapframe:存放使用者寄存器,还有与进程相关的内核栈、hartid、usertrap地址、内核页表地址等资讯,其地址由 TRAMPOLINE 定义。参考proc.h。
以下为陷入机制使用的 CSR 寄存器:
当执行陷阱(除去计时器中断)时,RISC-V 执行以下操作:
当硬件执行完以下操作,交由软件(xv6)处理剩余操作。
xv6 从用户模式陷入内核模式与返回的过程(uservec -> usertrap -> prepare_return -> userret):
以下用对 exec 的调用说明。
用户代码会将参数存在 a0, a1 中,然后将系统调用号存放在 a7。syscall 将返回值存放在 a0。系统调用号的定义存放在:syscall.h。
参考:syscall.c。
stvec:内核在此放置陷阱处理程序的地址。sepc:发生陷阱时,旧的 pc 值会保存在此,sret会将sepc复制到 pc 从而从陷阱返回。scause:存放引起陷阱的原因。sscratch:保存 per-CPU 的struct cpu*指针。sstatus:其中SIE位控制设备中断是否启用,SPP位保存陷阱是来自用户还是管理模式,并控制sret的返回模式。
- 若陷阱是设备中断,且 SIE 被清空,则不执行以下操作。
- 清除 SIE 禁止中断,防止处理程序被打断。
- 将 pc 复制到
sepc。 - 将当前模式(用户或管理)保存在状态的 SPP 位中。
- 设置
scause反映原因。 - 将模式设置为管理模式。
- 将
stvec复制到 pc。 - 跳转到 pc 运行。
- 当执行用户代码时,
stvec指向uservec(即 trampoline.S 中协助从用户模式陷入内核的汇编码),所以一旦需要陷入内核就会跳转到uservec中。 uservec在trampoline中保存用户寄存器,以免进入内核时修改这些值。uservec将trampoline保存在sscratch中。- 从
p->trapframe->kernel_satp中取得内核页表,将satp切换为内核页表并调用usertrap(p->trapframe->kernel_trap)。usertrap参考:trap.c usertrap会确认陷阱的原因,处理并返回。usertrap会修改stvec指向kernelvec,因为此时系统处于内核模式,所以所有中断与异常都由都由kerneltrap处理。- 当以上处理结束,会调用
prepare_return。由trap.c返回到trampoline.c中的userret。 userret会读出保存的用户寄存器,并切换页表回用户模式。