4.1 KiB
System Call
System Call即系统调用(以下简称syscall),用于在用户程序中执行一些特权模式下才能完成的操作(如I/O操作)。
对于处理器而言,syscall是一种同步发生的事件,在基于RISC-V的操作系统中由ecall
指令(Environment Call)产生。
当系统调用事件结束后,处理器将返回到ecall指令的下一条指令继续执行。
原版xv6的文档将“system call”、“exception”和“interrupt”统称为“trap”。这可能与我们平常使用的术语有一定出入,需要注意。 在RISC-V指令集手册的1.6节中,对“exception”、“interrupt”和“trap”的定义是这样的:
We use the term exception to refer to an unusual condition occurring at run time associated with an instruction in the current RISC-V hart. We use the term interrupt to refer to an external asynchronous event that may cause a RISC-V hart to experience an unexpected transfer of control. We use the term trap to refer to the transfer of control to a trap handler caused by either an exception or an interrupt.
从这个角度来看,trap在RISC-V的语境下指的是控制权的转换,也就是特权级的转换。
在RISC-V中请求系统调用
在RISC-V的用户程序中,使用ecall
指令请求syscall。操作系统提供不同功能的syscall,对应不同的请求调用号。
因此请求前,需要向a7
寄存器中写入所请求的syscall的调用号。以下为一个请求8号调用的例子:
li a7, 8
ecall
系统调用的处理过程
Syscall涉及到特权态的转换,需要经过trap过程。对于用户程序而言,一般是从用户模式(U模式)陷入到监管模式(S模式)。 我们知道,操作系统中有中断向量表,保存着各类异常与中断的处理例程的入口,syscall的处理例程自然也在其中。 而对于不同类型的调用请求,syscall的处理例程也有相应的系统调用表,保存不同类型的系统调用功能函数的入口。 根据用户事先写入寄存器的系统调用号,syscall的处理例程调用相应的功能函数,完成系统调用,随后返回至原先的特权态。
那么,执行ecall
指令后,系统中发生了什么呢?其实不仅是系统调用,异常与各类中断发生后,首先都会经过这一过程——特权态的转换。
在RISC-V中,各个特权级都有一组状态与控制寄存器(CSRs),当在U模式下中断发生时(除了时钟中断),RISC-V硬件系统会自动完成下列操作:
- 如果发生的是设备中断,且
sstatus
寄存器的SIE
位为0(即中断关闭),则不继续下列的操作,也就是暂时忽略这个中断; - 关闭外部设备中断,即将
sstatus
寄存器的SIE
位设为0; - 拷贝
pc
寄存器的值至sepc
寄存器; - 保存当前的特权态信息至
sstatus
寄存器的SPP
字段; - 设置
scause
寄存器,其值表示trap产生的原因; - 将特权态设置为S模式;
- 将
stvec
寄存器的值存入pc
寄存器(stvec
寄存器存放S模式的中断处理函数的入口地址); - 从新的
pc
值指向的指令继续执行。
执行上述步骤后,处理机就进入了S模式。此时,操作系统可能还需要进行一些额外操作,以应对S模式下再次发生trap事件。
之后,根据scause
寄存器,判断发生的是异常、中断或是系统调用,并进行相应的处理。处理完毕后,就执行sret
指令,返回U模式。
sret
指令会执行若干相反的操作,例如将sepc
的值写回pc
、更新sstatus
寄存器的SIE
字段等,使处理机恢复到原本U模式的执行状态。