Your first task is to modify the xv6 kernel to print out a line for each system call invocation. It is enough to print the name of the system call and the return value; you don’t need to print the system call arguments.
When you’re done, you should see output like this when booting xv6:
...
fork -> 2
exec -> 0
open -> 3
close -> 0
$write -> 1
write -> 1
That’s init forking and execing sh, sh making sure only two file descriptors are open, and sh writing the $ prompt. (Note: the output of the shell and the system call trace are intermixed, because the shell uses the write syscall to print its output.)
Hint: modify the syscall() function in syscall.c.
Optional challenge: print the system call arguments.
Your second task is to add a new system call to xv6. The main point of the exercise is for you to see some of the different pieces of the system call machinery. Your new system call will get the current UTC time and return it to the user program. You may want to use the helper function, cmostime() (defined in lapic.c), to read the real time clock. date.h contains the definition of the struct rtcdate struct, which you will provide as an argument to cmostime() as a pointer.
You should create a user-level program that calls your new date system call; here’s some source you should put in date.c:
#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();
}
// your code to print the time in any format you like...
exit();
}
In order to make your new date
program available to run from the xv6 shell, add _date to the UPROGS definition in Makefile.
Your strategy for making a date system call should be to clone all of the pieces of code that are specific to some existing system call, for example the “uptime” system call. You should grep for uptime in all the source files, using *grep -n uptime .[chS].
When you’re done, typing date to an xv6 shell prompt should print the current UTC time.
Write down a few words of explanation for each of the files you had to modify in the process of creating your date system call.
Optional challenge: add a dup2() system call and modify the shell to use it.
*syscall.h:
要实现系统调调用时打印系统调用的名称和参数,我们需要修改syscall.c 和syscalll.h文件
然后我们先看一下syscall.c
的代码
// 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
不难看出,这段代码是对xv6 21个常见系统调用的宏定义,我们要想实现打印调用名称和参数,可以在syscall.c
设置和系统调用的相同的编号和名称相对应的数组
#include "x86.h"
#include "syscall.h"
// 以下为添加的内容
static char SYS_call_names[][6] = {
[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"
};
// 以上为添加的内容
然后除此之外还需要修改syscall()
函数,使其实现当系统调用时打印对应的名称和编号
$make qemu (或make qemu-nox)
//make qemu-nox是将qemu固定在linux下,在串口终端中启动Qemu
运行结果如下图
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-C5kxiRPK-1571208580659)(partone.png)]
void syscall(void)
····
curproc ->tf->eax = syscall[numm]();
// 以下为添加的内容
cprintf("\tSYS_call: %s\tid: %d\n", SYS_call_names[num], num);
// 以上为添加的内容
}
else
···
到这里第一个小部分就完成了,这部分其实很简单就是在syscall
调用函数是加入了一句打印代码使其实现功能
在这没学过c语言的可能会疑惑是printf的基本语法,我在下面简单介绍一下:
首先在这里的**cprintf()我认为和printf()**的基本用法是一样的。
printf()函数调用格式:printf(“格式化字符串”,输出表列)。格式化字符串包含三种对象,为:
(1)字符串常量
(2)格式化控制字符串
(3)转义字符
字符串常量原样输出,在显示中起提示作用。输出表列中给出了各个输出项,要求格式控制字符串和各输出项在数量和类型上应该一一对应。其中格式控制字符串是以%
开头的字符串,在%
后面跟有各种格式控制符,以说明输出数据的类型、宽度、精度等。
格式化控制字符串:
%[标志][最小宽度][.精度][类型长度]类型
示例:
printf("%5d\n",1000); //默认右对齐,左边补空格
output:
` `1000
常用转义字符:
\n :回车符
\t :横向制表符
\v:纵向制表符
在各种文件里添加第22个系统调用sys_date
1.syscall.h
:
#define SYS_date 22
2.syscall.c
:
[SYS_date] " date"
};
···
extern int sys_date(void);
···
[SYS_date] sys_date
3.user.h
文件添加用户态函数
int sleep(int);
int uptime(void);
// 以下为添加内容
int date(struct rtcdate*);
// 以上为添加内容
4.usys.S
添加用户态函数的实现
SYSCALL(date)
5.sysproc.c
添加系统调用函数
int
sys_date(struct rtcdate *r)
{
if (argptr(0, (void *)&r, sizeof(*r)) < 0)
return -1;
cmostime(r); //从cmos中获取时间
return 0;
}
至此,就完成了添加系统调用函数 date()
最后,我们需要添加使用这个系统调用函数的方法
新建文件 date.c
,并添加一下内容
#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();
}
// your code to print the time in any format you like...
printf(1, "%d-%d %d %d:%d:%d\n", r.month, r.day, r.year, r.hour, r.minute, r.second);
//输出格式可以随意定义
exit();
}
6.最后不要忘了在MakeFile
添加UPROGS
对应的命令:
_big\
# 以下为添加内容
_date\
# 以上为添加内容
make qemu
//然后输入date
$date