6.S081 lab2 syscall
#System call tracing
-
跟着hints做就可以了,给系统调用
trace添加一个系统调用号,并且将函数原型添加到kernel/syscall.h中。 -
在
kernel/proc.h中为proc结构体添加一个int mask成员,mask的32位分别标识是否追踪该位所代表的系统调用。比如write的系统调用号为16,那么当mask的第16位为1时,则表示需要追踪write系统调用。 -
关键是实现
sys_trace函数,在kernel/sysproc.c中实现该函数,该函数用argint获得了trace的参数,即mask掩码,将此mask掩码拷贝至当前用户进程中。代码如下:uint64 sys_trace(void) { int mask; if (argint(0, &mask) < 0) return -1; myproc()->mask = mask; return 0; }上述函数中,
argint(int num, int *p)函数是从p->trapframe中获得编号为num寄存器的值,对于系统调用,发生中断时,p->trapframe->a0存储了系统调用第一个参数的值,p->trapframe->a1存储了第二个参数的值,依此类推。 -
在
kernel/syscall.c中,syscall函数为系统调用函数,在该函数中添加代码实现跟踪系统调用的效果,我的实现方法如下:const char *syscallNames[] = { 0, "fork", "exit", "wait", "pipe", "read", "kill", "exec", "fstat", "chdir", "dup", "getpid", "sbrk", "sleep", "uptime", "open", "write", "mknod", "unlink", "link", "mkdir", "close", "trace", "sysinfo" }; 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 >> num & 1){ printf("%d: syscall %s -> %d\n",p->pid, syscallNames[num], p->trapframe->a0); } } else { printf("%d %s: unknown sys call %d\n", p->pid, p->name, num); p->trapframe->a0 = -1; } }当发生系统调用时,
p->trapframe->a7存储了系统调用号,主要到syscalls,syscalls为全局的函数指针,通过系统调用号,调用对应的函数。当每次发生系统调用时,查看当前进程的mask掩码,并根据mask的值判断是否追踪这次系统调用。注意到p->trapframe->a0存储了系统调用的返回值。为了打印系统调用的名称,可以添加一个字符串数组syscallNames。 -
注意在
fork系统调用时,子进程拷贝父进程的空间时,也应该拷贝父进程的掩码mask。
#Sysinfo
-
同
trace,加入sysinfo的系统调用号以及相关函数声明。 -
在
kernel/kalloc.c中,xv6实现了管理物理内存的方法。kmem是一个全局结构体对象,xv6把空闲物理页组织为链表,kmem->freelist为物理空闲页的头指针。在kernel/riscv.h中,第323行#define PGSIZE 4096 // bytes per page定义了物理页的大小。那么遍历链表就可以获得空闲内存的大小了,具体代码如下:// Get the size of free memory uint64 freemem(void) { struct run *p = kmem.freelist; uint64 sum = 0; while (p){ sum += PGSIZE; p = p->next; } return sum; } -
在
kernel/proc.c中,xv6实现了管理内存的方法。可以在kernel/proc.h中查看struct proc的成员,其中的state是一个枚举类型的成员,指明了进程的状态(第83行),在xv6中,每个进程共有五种状态。xv6最多可以有64个进程,这些进程被组织为一个数组proc(kernel/proc.h11行)。为了获取进程数,直接遍历
proc数组即可,计算状态不为UNUSED的进程数。代码如下:// Get the number of proc uint64 getproc(void) { uint64 cnt = 0; struct proc* p; for (p = proc; p < &proc[NPROC]; p++){ if (p->state != UNUSED) cnt++; } return cnt; } -
最后就是实现
sys_sysinfo了,在执行系统调用时,xv6还处于内核态,需要调用copyout函数把struct sysinfo复制到进程的用户空间中,代码如下:uint64 sys_sysinfo(void) { uint64 p; struct sysinfo s; s.freemem = freemem(); s.nproc = getproc(); if (argaddr(0, &p) < 0) return -1; if (copyout(myproc()->pagetable, p, (char*)&s, sizeof(s)) < 0) return -1; return 0; }
通关截图


浙公网安备 33010602011771号