zhuzilin's Blog

about

6.828 Homework xv6 system call

date: 2019-02-19
tags: OS  6.828  

Part One: System call tracing

第一个任务是让每次调用system call的时候,都会输出其名字和返回值。需要修改的代码是syscall.c

我就直接用了暴力方法,如下:

static char* syscalls_name[] = {
[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",
};

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", syscalls_name[num], curproc->tf->eax);
  } else {
    cprintf("%d %s: unknown sys call %d\n",
            curproc->pid, curproc->name, num);
    curproc->tf->eax = -1;
  }
}

至于如何输出system call arguments,应该是要用curproc->tf里面的值吧,具体具体没想好。

这样之后,直接运行kernel的结果是:

...
fork -> 2
exec -> 0
open -> 3
close -> 0
$write -> 1
 write -> 1

Part Two: Date system call

注意在做这一问的时候,最好把part 1的print给注释掉,不然太乱了。

如题目所说,仿照uptime,有:

$ grep -n uptime *.[chS]
syscall.c:105:extern int sys_uptime(void);
syscall.c:122:[SYS_uptime]  sys_uptime,
syscall.c:147:[SYS_uptime]  "uptime",
syscall.h:15:#define SYS_uptime 14
sysproc.c:83:sys_uptime(void)
user.h:25:int uptime(void);
usys.S:31:SYSCALL(uptime)

所以在syscall.h中加入SYS_dateextern int sys_date(struct rtcdate*);。之后,在sysproc.c中加入:

int sys_date(void)
{
  struct rtcdate *r;
  if(argptr(0, &p, sizeof(struct rtcdate)) < 0)
    return -1;
  return cmostime(r);
}

user.h中加入int sys_date(struct rtcdate*);。在usys.S中加入SYSCALL(date)

之后按照要求加入加入date.c文件,进行修改:

int
main(int argc, char *argv[])
{
  struct rtcdate r;

  if (date(&r)) {
    printf(2, "date failed\n");
    exit();
  }

  // your code to print the time in any format you like...
    printf(1, "UTC %d-%d-%d %d:%d:%d\n", r.year, r.month, r.day, \
                                       r.hour, r.minute, r.second);
  exit();
}

最后,在MakefileUPPROGS中加入_date。就大功告成了。

$ date
UTC 2019-2-19 19:6:33

注意,xv6的printf没有实现%02d这样的操作,所以也没办法了。

这个作业的目的就是为了总结一下,大致应该是在sh中调用date会调用date.c,而date.c中调用的date函数被定义在了user.h头文件中,user.h的函数中的system call都是由usys.S实现的,实现的方式就是调用了一个叫SYSCALL(name)的宏,其操作为:

#define SYSCALL(name) \
  .globl name; \
  name: \
    movl $SYS_ ## name, %eax; \
    int $T_SYSCALL; \
    ret

也就是会调用INT指令的。make了之后,我们可以看到,sh.asm果然出现了

00000db2 <date>:
     db2:	b8 16 00 00 00       	mov    $0x16,%eax
     db7:	cd 40                	int    $0x40
     db9:	c3                   	ret    
     dba:	66 90                	xchg   %ax,%ax
     dbc:	66 90                	xchg   %ax,%ax
     dbe:	66 90                	xchg   %ax,%ax

使用INT指令开始,就和note4中记录的调用write一样了。在Makefile中加入date.c应该只是为了编译出date的二进制文件用的吧,这个我还不清楚...