Homework: xv6 system calls
参考boot homework中的内容,为xv6操作系统添加一个系统调用。
链接:https://pdos.csail.mit.edu/6.828/2018/homework/xv6-syscall.html
Part One: System call tracing
修改xv6内核,为每个系统调用打印一行,打印系统调用的名称和返回值。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| static char syscall_name[][10] = { [SYS_fork] "fork", [SYS_exit] "exit", [SYS_wait] "wait", [SYS_pipe] "pipe", [SYS_read] "read", [SYS_kill] "kill", [SYS_exec] "exec", [SYS_fstat] "fstat", [SYS_chdir] "chdir", [SYS_dup] "dup", [SYS_getpid] "getpid", [SYS_sbrk] "sbrk", [SYS_sleep] "sleep", [SYS_uptime] "uptime", [SYS_open] "open", [SYS_write] "write", [SYS_mknod] "mknod", [SYS_unlink] "unlink", [SYS_link] "link", [SYS_mkdir] "mkdir", [SYS_close] "close" };
|
首先类似于指针函数那样,准备一个名称数组,便于快速打印;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| void syscall(void) { int num; struct proc *curproc = myproc();
num = curproc->tf->eax; if(num > 0 && num < NELEM(syscalls) && syscalls[num]) { curproc->tf->eax = syscalls[num](); cprintf("%s -> %d\n", syscall_name[num], curproc->tf->eax); } else { cprintf("%d %s: unknown sys call %d\n", curproc->pid, curproc->name, num); curproc->tf->eax = -1; } }
|
然后添加打印具体的系统调用名称即可,根据x86的函数调用堆栈关系,返回值保存在eax寄存器之中,因此需要将进程页帧中的eax寄存器的值进行打印。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| void syscall(void) { int num; struct proc *curproc = myproc();
num = curproc->tf->eax; if(num > 0 && num < NELEM(syscalls) && syscalls[num]) { curproc->tf->eax = syscalls[num](); cprintf("%s -> %d\n", syscall_name[num], curproc->tf->eax); int *fd; switch(num){ case SYS_fork: cprintf("sys_fork no args\n"); break; case SYS_exit: cprintf("sys_exit no args\n"); break; case SYS_wait: cprintf("sys_wait no args\n"); break; case SYS_pipe: if(argptr(0, (void*)&fd, 2*sizeof(fd[0]))<0){ cprintf("error: sys_pipe cannot get the args\n"); } cprintf("sys_pipe args: %p %p",&fd[0],&fd[1]); break; default: break; } } else { cprintf("%d %s: unknown sys call %d\n", curproc->pid, curproc->name, num); curproc->tf->eax = -1; } }
|
同样打印系统调用时的参数,仍然根据x86的堆栈关系,进行打印,具体的用法,在syscall.c的前边儿给出了几个辅助函数,进程的context内保存了%esp,通过从堆栈内部查找指定字节长度的值,来进行获取参数,同时参考具体的系统调用的程序来进行参数的获取于打印。
Part Two: Date system call
写一个用户态的应用,进行系统调用,给出具体的UTC时间。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| #include "types.h" #include "user.h" #include "date.h"
int main(int argc, char *argv[]) { struct rtcdate r;
if (date(&r)) { printf(2, "date failed\n"); exit(); }
printf(1, "UTC date: %d-%d-%d %d:%d:%d\n", r.year, r.month, r.day, r.hour, r.minute, r.second); exit(); }
|
首先添加一个用户程序,进行系统调用,并且将具体的日期输出到标准输出端口。同时在Makefile里边儿添加用户调用的编译选项。

参照uptime的系统调用组成部分,对每个文件内的内容进行添加,分别是:
1
| int date(struct rtcdate*);
|
1 2 3
| extern int sys_date(void);
[SYS_date] sys_date,
|
1 2 3 4 5 6 7 8
| int sys_date(void) { struct rtcdate*; if (argptr(0, (char**)&r, sizeof(*r)) < 0) { return -1; } cmostime(r); return 0; }
|
按照上述运行结果:
