为xv6添加一个系统调用

1. Overview

要为xv6添加一个系统调用,需要修改以下5个文件:

  • syscall.h
  • syscall.c
  • sysproc.c
  • usys.S
  • user.h

由于Unix v6发行于1975年,下面我们以添加一个返回整数1975的系统调用作为示范来说明如何为xv6添加一个系统调用。

2. syscall.h

打开syscall.h,在相应位置添加下面这一行:

#define SYS_getyear 22

添加后整个文件的内容如下:

// System call numbers
#define SYS_fork    1
#define SYS_exit    2
#define SYS_wait    3
#define SYS_pipe    4
#define SYS_read    5
#define SYS_kill    6
#define SYS_exec    7
#define SYS_fstat   8
#define SYS_chdir   9
#define SYS_dup    10
#define SYS_getpid 11
#define SYS_sbrk   12
#define SYS_sleep  13
#define SYS_uptime 14
#define SYS_open   15
#define SYS_write  16
#define SYS_mknod  17
#define SYS_unlink 18
#define SYS_link   19
#define SYS_mkdir  20
#define SYS_close  21
#define SYS_getyear 22

由此可见,我们添加的getyear是第22号系统调用。

3. syscall.c

syscall.c中添加一个指向该系统调用的函数指针:

[SYS_getyear] sys_getyear

添加后上行后,系统调用的函数指针数组为:

static int (*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,
[SYS_getyear] sys_getyear // SYS_getyear == 22
};

可见当用户程序调用22号系统调用时,会调用sys_getyear这个指针所指向的函数。

因此我们需要自己实现这个函数,在此之前先在syscall.c中添加该函数的原型:

extern int sys_getyear(void);

4. sysproc.c

sysproc.c中添加该调用的实现:

int
sys_getyear(void)
{
	return 1975;
}

可见,该系统调用返回了Unix v6的发布日期1975。

5. usys.S

usys.S中添加下面这一行:

SYSCALL(getyear)

添加后的内容:

#include "syscall.h"
#include "traps.h"

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

SYSCALL(fork)
SYSCALL(exit)
SYSCALL(wait)
SYSCALL(pipe)
SYSCALL(read)
SYSCALL(write)
SYSCALL(close)
SYSCALL(kill)
SYSCALL(exec)
SYSCALL(open)
SYSCALL(mknod)
SYSCALL(unlink)
SYSCALL(fstat)
SYSCALL(link)
SYSCALL(mkdir)
SYSCALL(chdir)
SYSCALL(dup)
SYSCALL(getpid)
SYSCALL(sbrk)
SYSCALL(sleep)
SYSCALL(uptime)
SYSCALL(getyear)

6. user.h

为了能够让用户程序访问到getyear系统调用,我们需要在user.h中声明该调用:

int getyear(void);

添加后的系统调用声明:

// system calls
int fork(void);
int exit(void) __attribute__((noreturn));
int wait(void);
int pipe(int*);
int write(int, const void*, int);
int read(int, void*, int);
int close(int);
int kill(int);
int exec(char*, char**);
int open(const char*, int);
int mknod(const char*, short, short);
int unlink(const char*);
int fstat(int fd, struct stat*);
int link(const char*, const char*);
int mkdir(const char*);
int chdir(const char*);
int dup(int);
int getpid(void);
char* sbrk(int);
int sleep(int);
int uptime(void);
int getyear(void); 

7. 测试getyear

完成上述步骤,一个系统调用就已经创建好了,现在来编写一个用户程序来测试以下该系统调用。

创建一个用户程序:getyear.c

#include "types.h"
#include "stat.h"
#include "user.h"

int
main(void)
{
        printf(1, "Note: Unix v6 was released in year %d\n", getyear());
        exit();
}

Makefile中的UPROGS中添加_getyear:

UPROGS=\
        _cat\
        _echo\
        _forktest\
        _getyear\
        _grep\
        _hello\
        _init\
        _kill\
        _ln\
        _ls\
        _mkdir\
        _rm\
        _sh\
        _stressfs\
        _usertests\
        _wc\
        _zombie\

现在启动xv6,运行getyear程序:

Booting from Hard Disk..xv6...
cpu1: starting 1
cpu0: starting 0
sb: size 1000 nblocks 941 ninodes 200 nlog 30 logstart 2 inodestart 32 bmap start 58
init: starting sh
$ getyear
Note: Unix v6 was released in year 1975

命令行里顺利地显示出了预期的Unix v6的发布日期。

posted @ 2022-01-26 17:34  刷书狂魔  阅读(991)  评论(0编辑  收藏  举报
总访问: counter for blog 次