Lab 2 syscall
System call tracing
该题要实现一个系统调用跟踪功能,创建一个新的系统调用trace来控制跟踪。
在用户层面的系统调用trace已经写好,在user/trace.c中。
首先按照提示增加相应的系统调用原型、存根、系统调用编号等内容。通过在kernel/sysproc.c中添加一个sys_trace()函数来实现系统调用。
uint64sys_trace(void){int mask;if(argint(0, &mask) < 0)return -1;myproc()->mask = mask;return 0;}
对于mask,根据提示中可以知道,将参数保存到proc结构体中来实现新的系统调用,所以,在proc结构体中将其补上。接着需要修改fork()将跟踪mask从父进程复制到子进程,这里很简单,只要直接赋值就好。
对于系统调用的实现,需要改写syscall()函数,打印跟踪的输出,添加一个系统调用名称数组以建立索引,实现打印系统调用名称的功能。
static char *syscallname[] = {
[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] "sgetpid",
[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",
[SYS_trace] "trace",
};
void
syscall(void)
{
int num;
struct proc *p = myproc();
num = p->trapframe->a7;
if(num > 0 && num < NELEM(syscalls) && syscalls[num]) {
p->trapframe->a0 = syscalls[num]();
if((p->mask) & (1 << num))
{
printf("%d: syscall %s -> %d\n", p->pid, syscallname[num], p->trapframe->a0);
}
} else {
printf("%d %s: unknown sys call %d\n",
p->pid, p->name, num);
p->trapframe->a0 = -1;
}
}
Sysinfo
首先,按照“System call tracing”中的步骤添加相应的内容,以及hints中的对struct sysinfo的声明,使得编译成功。
根据hints,我们知道sysinfo需要将一个struct sysinfo复制回用户空间,且提示告诉我们要参考sys_fstat()以及在filestat()中如何使用copyout()。于是我们可以照葫芦画瓢,使用argadd()检索地址确保程序正常运行。同理,观察copyout(),创建一个进程以便于传入参数,按照解释我们可以知道,我们需要复制sysinfo,所以可以确定对应的参数,如果复制失败,则返回-1。
接下来是获取空闲的内存量,观察kernel/kalloc.c中的内容,可以知道这里建立了结构体以存储内存,类似于一个页表,且对于每一页,有4096个字节(PGSIZE)。所以可以采用确定页数,然后求出內存的方法。
uint64
free_mem(void)
{
struct run *p = kmem.freelist;
int n = 0;
while(p)
{
n++;
p = p->next;
}
return n * PGSIZE;
}
然后是获取进程数,对于每一个进程,只要状态state不是UNUSED的,就应该被计算入其中,于是可以很容易得到代码。
uint64
proc_size(void)
{
int n = 0;
for(int i = 0; i < NPROC; i++)
{
if(proc[i].state != UNUSED) n++;
}
return n;
}
最后是sys_info的代码,将上述内容结合起来。
uint64
sys_info(void)
{
struct sysinfo info;
uint64 addr;
struct proc *p = myproc();
info.freemem = free_mem();
info.nproc = proc_size();
if(argaddr(0, &addr) < 0)
return -1;
if(copyout(p->pagetable, addr, (char *)&info, sizeof(info)) < 0)
return -1;
return 0;
}
