做这个实验之前需要把 xvb book 第二章和第四章的 4.3 4.4看了, 有助于理解。
System call tracing 实验大意 实现trace指令, trace接受mask以及调用的程序和它的参数。mask代表要追踪哪些系统调用,这些都可以在kernel/syscall.h中看到
过程 大致思路是通过trace函数将进程中新添加的trace_mask设置好,当syscall调用时,通过trace_mask和被调用的系统调用的mask进行相与,如果大于零,就打印该系统调用的信息。
这个lab已经提供了user/trace.c这个函数,所以不需要自己写,但是需要在user/user.h,user/usys.pl,以及kernel/syscall.h添加声明,还需要在kernel/syscall.c中的函数指针数组中,添加后面需要我们自己在 kernel/sysproc.c添加的sys_trace。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 static uint64 (*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_trace] sys_trace, }
然后向kernel/proc.h 中的 struct proc 添加 int trace_mask
1 2 3 4 struct proc { ...... int trace_mask; };
user调用trace时,实际上调用的是sys_trace,所以我们需要添加在 kernei/sysproc.c的sys_trace函数。。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 uint64 sys_trace (void ) { int trace_mask = 0 ; if (argint(0 , &trace_mask) < 0 ) return -1 ; return trace(trace_mask); } int trace (int mask) { struct proc *p = myproc(); p->trace_mask = mask; return 0 ; } ....... int trace (int ) ;
我们还需要在调用fork生成子进程的时候,将父进程的trace_mask复制给子进程
1 np->trace_mask = p->trace_mask;
最后需要在syscall中,判断是否被调用的函数包含在mask中,如果包含在mask中,则输出信息,因为输出信息需要输出系统调用的函数名,所以还需要添加一个字符串数组。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 kernel/syscall.h char * fun_name[35 ]={ "null" , "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; int mask_value = 1 << num; if (num > 0 && num < NELEM(syscalls) && syscalls[num]) { p->trapframe->a0 = syscalls[num](); if ((mask_value & (p->trace_mask)) != 0 ) printf ("%d: syscall %s -> %d\n" , p->pid, fun_name[num], p->trapframe->a0); } else { printf ("%d %s: unknown sys call %d\n" , p->pid, p->name, num); p->trapframe->a0 = -1 ; }
这样我们就完成了lab2的第一个实验。
Sysinfo 实验大意 实现sysinfo,获取系统中有多少非UNUSED的进程和空闲内存字节数。
过程 和上一个system call 实验一样,需要将sysinfo声明在各个文件中,实验介绍中已经给出来了。 然后就是获取当前不是UNUSED的进程,比较简单。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 int count_proc (void ) { int count = 0 ; struct proc *p ; for (p = proc; p < &proc[NPROC]; p++) { acquire(&p->lock); if (p->state != UNUSED) count ++; release(&p->lock); } return count; }
然后就是获取空闲内存字节数, xv6是通过freelist管理的内存,每个页大小为PAGESIZE,相关代码可以参考 kernel/kalloc.c中的kalloc
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 void *kalloc (void ) { struct run *r ; acquire(&kmem.lock); r = kmem.freelist; if (r) kmem.freelist = r->next; release(&kmem.lock); if (r) memset ((char *)r, 5 , PGSIZE); return (void *)r; }
通过阅读这个代码,就可以知道想计算空闲内存的大小,只需要计算freelist中有多少个页就行了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 uint64 get_freemem_num (void ) { struct run *r ; uint64 num = 0 ; acquire(&kmem.lock); r = kmem.freelist; while (r) { num ++; r = r->next; } release(&kmem.lock); return num * PGSIZE; }
至此,我们需要的两个函数就写完了,剩下的就是完成kernel/sysproc.c 中的sysinfo函数了,需要注意的是,当程序调用系统函数的时候,进入的是 kernel mode 无法通过 user mode 中的虚拟地址直接将数据存入虚拟地址所指向的物理地址,因为目前xv6是有一个全局的kernel page table,其中没有每个进程的user table 的映射,所以需要使用copyout来获取指定page table中的物理地址,并将数据存入进去。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 uint64 sys_sysinfo (void ) { uint64 st; struct proc *p = myproc(); struct sysinfo info ; if (argaddr(0 , &st) < 0 ) { printf ("sys_sysinfo: get addr error\n" ); return -1 ; } info.freemem = get_freemem_num(); info.nproc = count_proc(); if (copyout(p->pagetable, st, (char *)&info, sizeof info) < 0 ) { printf ("sys_sysinfo: copyout error\n" ); return -1 ; } return 0 ; }
在添加函数的时候,不要忘记取 defs.h中添加对应的声明。
我们lab2整个就完成了^_^