MIT6.s081-2020 Lab2 System Calls
准备
git checkout syscall
make clean
System call trace
引言
在本任务中,您将添加一个系统调用跟踪功能,该功能可能会在以后调试实验时帮助您。您将创建一个新的trace
将控制跟踪的系统调用。它应该采用一个参数,一个整数“掩码”,其位指定要跟踪的系统调用。例如,要跟踪 fork 系统调用,程序调用trace(1 << SYS_fork)
, 在哪里SYS_fork
是来自的系统调用号kernel/syscall.h
. 如果掩码中设置了系统调用的编号,则必须修改 xv6 内核以在每个系统调用即将返回时打印出一行。该行应包含进程id、系统调用的名称和返回值;您不需要打印系统调用参数。这trace
系统调用应该启用对调用它的进程以及它随后派生的任何子进程的跟踪,但不应影响其他进程。
实现
这一部分是要求我们实现一个系统调用的跟踪,按照HINT一步步做下去即可。
HINT1:在Makefile的UPROGS中添加$U/_trace
打开目录可以发现已经提供了一个user/trace.c
文件,先在Makefile里添加一下即可。
user/trace.c
if (trace(atoi(argv[1])) < 0) {
fprintf(2, "%s: trace failed\n", argv[0]);
exit(1);
}
可以看到trace.c里面调用了trace()
方法(来自user.h),trace接收一个int参数,返回int,并且如果执行失败返回负值。
然后这个trace()
函数的作用是,输入参数是掩码,因为int是32位最多能表示31个系统调用,被置为1的那个系统调用位就会被跟踪并打印信息。
HINT2:在user/user.h
中添加系统调用的原型,在user/usys.pl
中添加一个占位,并在kernel/syscall.h
中添加一个系统调用号。
Makefile调用perl脚本user/usys.pl
来生成user/usys.S
,usys.S
也就是实际的系统调用代码(stub),它使用RISC-V的ecall指令来进入内核态。修复了编译问题后运行trace 32 grep hello README
依然执行失败因为你还没有在内核中实现这个系统调用。
usys.pl
的内容
sub entry {
my $name = shift;
print ".global $name\n";
print "${name}:\n";
print " li a7, SYS_${name}\n";
print " ecall\n";
print " ret\n";
}
ecall
: xv6是基于RISC-V指令集的,在RISV-V指令集中ecall
代表系统调用。
li
: 是一个加载立即数到寄存器的指令,格式是li rd, immediate
,表示x[rd] = immediate
,将常量加载到 x[rd]
中。
SYS_${name}
的含义是在kernel/syscall.h中#define SYS_${name} xxx
的系统调用号,这样就可以告诉ecall要调用几号系统调用。
在user/user.h
中添加函数原型。
int trace(int);
在user/usys.pl
中添加trace的占位。
entry("trace");
在syscall.h
里添加系统调用号。
#define SYS_close 21
#define SYS_trace 22 // NEW
HINT3:在kernel/syspro.c
中添加sys_trace()
函数,sys_trace()
通过在proc struct的新变量中存储参数来实现这个新的系统调用。从用户空间检索系统调用参数的函数位于kernel/syscall.c
中,可以在kernel/sysproc.c
中看到这些函数的使用示例。
查看kernel/syscall.c
中函数可以发现:
syscall.c
中的argint()
函数的实现如下,trapframe
是的用户进程陷入(trap)内核之前的寄存器等上下文信息。
// Fetch the nth 32-bit system call argument.
int argint(int n, int *ip) {
*ip = argraw(n);
return 0;
}
static uint64 argraw(int n) {
struct proc *p = myproc();
switch (n) {
case 0:
return p->trapframe->a0;
case 1:
return p->trapframe->a1;
case 2:
return p->trapframe->a2;
case 3:
return p->trapframe->a3;
case 4:
return p->trapframe