阅读材料
- Xv6代码:usys.pl、syscall.h、syscall.c
- 教材4.3节
系统调用流程
用户程序调用系统调用--->usys.S中对应的汇编函数--->uservec汇编函数--->usertrap()函数--->syscall()函数--->usertrapret()函数--->userret汇编函数--->usys.S中对应的汇编函数--->继续执行用户程序
系统调用接口:usys.S
usys.S本身不存在,通过执行make qemu命令,usys.pl脚本会自动生成usys.S文件。内容如下:
- 声明一个全局符号
- 将对应的系统调用号保存在a7寄存器中
- 执行ecall指令
- 执行ret伪指令返回用户进程
.global fork
fork:
li a7, SYS_fork
ecall
ret
系统调用表
系统调用表中将系统调用号作为索引,元素则是指向相应系统调用的函数指针
static uint64 (*syscalls[])(void) =
{
[SYS_fork] sys_fork,
[SYS_exit] sys_exit,
[SYS_wait] sys_wait,
[SYS_pipe] sys_pipe,
[SYS_read] sys_read,
[SYS_kill] sys_kill,
[SYS_exec] sys_exec,
[SYS_fstat] sys_fstat,
[SYS_chdir] sys_chdir,
[SYS_dup] sys_dup,
[SYS_getpid] sys_getpid,
[SYS_sbrk] sys_sbrk,
[SYS_sleep] sys_sleep,
[SYS_uptime] sys_uptime,
[SYS_open] sys_open,
[SYS_write] sys_write,
[SYS_mknod] sys_mknod,
[SYS_unlink] sys_unlink,
[SYS_link] sys_link,
[SYS_mkdir] sys_mkdir,
[SYS_close] sys_close,
};
syscall函数
该函数根据a7寄存器中的系统调用号,调用对应的系统调用,并将返回值保存在a0寄存器当中
void syscall(void)
{
int num;
struct proc *p = myproc();
num = p->trapframe->a7;
if (num > 0 && num < NELEM(syscalls) && syscalls[num])
{
// Use num to lookup the system call function for num, call it,
// and store its return value in p->trapframe->a0
p->trapframe->a0 = syscalls[num]();
}
else
{
printf("%d %s: unknown sys call %d\n",
p->pid, p->name, num);
p->trapframe->a0 = -1;
}
}