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