3. System call

  • user.h

syscalls

  • syscall.h
System callSystem call number
fork1
exit2
wait3
pipe4
read5
kill6
exec7
fstat8
chdir9
dup10
getpid11
sbrk12
sleep13
uptime14
open15
write16
mknod17
unlink18
link19
mkdir20
close21
  • syscall.c
// Prototypes for the functions that handle system calls.
extern uint64 sys_func(void);
...

static uint64 (*syscalls[])(void) = {
  [SYS_fork] sys_fork,
  ...
};

void syscall(void) {
  int num;
  struct proc *p = myproc();
  num = p->trapframe->a7;
  ...
}

4. Kernel (Supervisor) mode

  • usertrapret (trap.c): Sets up the RISC-V control registers to prepare for a future trap from user space. (ecall 的逆操作)
    • 关中断 intr_off();
    • 更新 stvec 指向用户空间的 trap 处理代码, 设置了 stvec 指向 trampoline, 在那里执行 sret 返回到 user address space
    • 填入 trapframe 内容 (恢复现场)
      • 存储 kernel page table pointer (kernel_satp)
      • 存储当前用户进程的 kernel stack (kernel_sp, stack pointer)
      • 存储 usertrap 函数指针, 使得 trampoline 代码能够跳转到 (kernel_trap = usertrap)
      • tp 中读取当前的CPU核编号 (kernel_hartid), 存储在 trapframe 中, 使得 trampoline 代码能够恢复这个数字, 因为用户代码可能会修改它
  • userret (trampoline.S): Switches satp to the process’s user page table. kernel 中最后一条指令
    • 程序切换回 user mode
    • $sepc 的数值会被 copy 到 pc
    • sret 重新打开中断