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的发布日期。