xv6 traps
Traps and System calls
什么是trap
在xv6操作系统中,"trap"是指cpu暂时跳出正常执行流程,从用户态切换到内核态的一种机制。这种切换,在xv6系统中,在这3个情况下发生:系统调用、异常、外部设备触发了中断。
系统调用就是使用了ecall指令,之前lab中增加过trace的syscall
异常的情况,包括page fault, 除0等等
外部设备触发中断,一般是磁盘完成了读写等
trap一般流程
- 一个trap发生时,把控制权转移到kernel
- 在kernel中保存寄存器,和其他一些状态,以便可以在处理完trap后恢复到正常的执行流程中去。
- 在kernel中执行handler代码
- kernel恢复保存的状态,从trap中返回,回到原本的执行代码中去。
用来处理trap的kernel代码(C或asm)通常称为handler,handler中的指令通常是用asm写的,称为vector.
我理解,handler就是trampoline.S
riscv trap机制
每个riscv cpu都有一组reg,kernel将cpu如何处理trap的信息写到这些reg中。在一个多核的芯片上,因为每个cpu有自己的一组reg,所以可以独立的处理trap
-
- stvec
- trap handler的地址写在这里
-
- sepc
- pc寄存器的值保存在这里,因为后续pc的值要被stvec中的值覆盖,sret指令会把sepc的值拷贝回pc寄存器,用来当trap结束后的返回地址。
- scause: 一个数字,用来描述trap的原因。
- sscratch: 一个值,方便handler的起始阶段使用
- sstatus: 这个寄存器中的SIE bit控制设备中断是否启用。SSP bit表示一个trap来自user mode还是supervisor mode,控制sret返回的mode
code: 调用 系统调用
看一下用户是如何进行exec
系统调用的
initcode.S将exec的参数放在reg a0, a1中,系统调用码放在a7中. 这个系统调用码和syscalls指针数组中,exec的函数指针在数组中的索引是相同的. ecall指令立即通过trap机制进行kernel中,通过uservec
-> usertrap
-> syscall
来进行执行
当sys_exec这个系统调用函数结束后,syscall记录了这个返回值,放在trapframe->a0,user也会得到这个返回值.
NOTE相关
- 6.3节中
对于这里page table,有一件事情需要注意:它并没有包含任何内核部分的地址映射,这里既没有对于kernel data的映射,也没有对于kernel指令的映射。除了最后两条PTE,这个page table几乎是完全为用户代码执行而创建,所以它对于在内核执行代码并没有直接特殊的作用。
这段内容中,kernel data是什么?
- 6.4节
这里的控制是通过STVEC寄存器完成的,这是一个只能在supervisor mode下读写的特权寄存器。在从内核空间进入到用户空间之前,内核会设置好STVEC寄存器指向内核希望trap代码运行的位置。
内核何时设置了STVEC寄存器?代码对应到哪里?
- 6.5节
注意看学生提问
STVEC是内核在进入到用户空间之前设置好的众多数据之一,内核会将其设置成trampoline page的起始位置。
所以是在当前user mode之前的kernel mode会进行设置的操作
kernel stack和user stack区别
根据trapframe结构体的定义,起始地址偏移8字节的地址,就是kernel stack的地址。所以现在是把kernel stack的地址加载到当前进程的stack pointer,以开始执行kernel代码。
本文来自博客园,作者:ijpq,转载请注明原文链接:https://www.cnblogs.com/ijpq/p/17771897.html