本文主要是介绍mit6.s081 lab2 System calls,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
添加mit仓库
- 添加remote
git remote add mit git://g.csail.mit.edu/xv6-labs-2020
- 从mit拉取分支
git fetch mit
git checkout syscall
chapter 2
System call tracing
写一个程序追踪另一个程序所调用的system call,打印追踪的syscall的syscall num, syscall num, 以及调用syscall的返回值,需要注意的是如果mask中标识需要追踪trace,那么第一次调用trace时也需要打印trace syscall的追踪信息
$ trace 32 grep hello README
3: syscall read -> 1023
3: syscall read -> 966
3: syscall read -> 70
3: syscall read -> 0$ trace 2147483647 grep hello README
4: syscall trace -> 0
4: syscall exec -> 3
4: syscall open -> 3
4: syscall read -> 1023
4: syscall read -> 966
4: syscall read -> 70
4: syscall read -> 0
4: syscall close -> 0
主要进行以下修改:
1.在Makefile中添加trace程序
2.user/trace.c中已经完成了trace程序,但是syscall trace还没有完成,所以这个exercise的主要工作为完成syscall trace
3.在kernel/proc.h中process的结构体中增加mask成员,用于记录需要追踪哪些syscall
3.在kernel/sysproc.c中完成sys_trace(),sys_trace就是trace syscall实际执行的函数,sys_trace函数的主要工作是修改process中的mask,从user space中获取trace syscall的参数的方式为使用argint函数(如argint(0, &mask)),argint实际上是从process的trapframe中获取对应位置的寄存器内容
4.修改fork()(kernel/proc.c),创建新的process继承父process的mask值
5.修改syscall()(kernel/syscall.c),这部分要做的工作是声明一个syscall name string数组,用于根据syscall num获取对应的syscall名。另外一个工作是获取当前process的mask值,判断当前调用的syscall是否是需要追踪的,如果需要追踪则将对应的信息打印出来
- kernel/sysproc.c
uint64 sys_trace(void) {int mask = 0;if (argint(0, &mask) < 0)return -1;myproc()->mask = mask;return 0;
}
- kernel/syscall.c
添加sys_systrace的函数声明
extern uint64 sys_trace(void);
在函数指针数组syscalls中添加sys_trace函数指针
[SYS_trace] sys_trace,
修改函数syscall
char* system_call_name[] = {"","fork","exit","wait","pipe","read","kill","exec","fstat","chdir","dup","getpid","sbrk","sleep","uptime","open","write","mknod","unlink","link","mkdir","close","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]();int mask = p->mask;if ((mask >> num) & 0x1) {printf("%d: syscall %s -> %d\n", p->pid, system_call_name[num], p->trapframe->a0);}} else {printf("%d %s: unknown sys call %d\n",p->pid, p->name, num);p->trapframe->a0 = -1;}
}
- 在kernel/syscall.h中增加
#define SYS_trace 22
- 在user/user.h中增加
int trace(int);
- 在usys.pl中增加
entry("trace");
usys.pl中生成user mode下的system call的内容,具体为设置对应syscall num到寄存器a7中,然后调用ecall
Sysinfo
这部分的内容是实现sysinfo syscall,sysinfo用于收集系统中的信息,包括系统中空闲内存的大小(byte),以及系统中的进程数量,这两项信息在struct sysinfo(kernel/sysinfo.h)中记录
- sysinfo的用户态调用函数的原型为int sysinfo(struct sysinfo *),在此syscall中的工作为传入sysinfo结构,并将结果填充到该sysinfo结构中
- 首先要添加syscall的声明,步骤与trace相同
- 然后是在kernel/kalloc.c中添加获取空闲内存容量的函数,根据kmalloc.c中的其他函数可知在系统中维护了一条空闲链表,每个链表节点为一个PGSIZE的页,所以获取空闲内存容量就是遍历空闲链表,获取空闲链表节点数量,空闲内容容量为空闲链表节点数量 * PGSIZE,在遍历空闲链表的过程中需要对空闲链表进行上锁
// 获取空闲内存容量
uint64 get_free_memory_info() {struct run *r;int freelist_size = 0;acquire(&kmem.lock);r = kmem.freelist;while (r) {freelist_size++;r = r->next;}uint64 res = freelist_size * PGSIZE;release(&kmem.lock);return res;
}
- 在kernel/proc.c中添加获取系统中的process数量的函数,在proc.c中维护了一个数组struct proc proc[NPROC],遍历此数组,如果proc的state不为UNUSED那么说明这是一个有效的proc,统计有效的proc数量并返回
uint64 get_proc_num() {struct proc *p;uint64 proc_num = 0;for (p = proc; p < &proc[NPROC]; p++) {if (p->state != UNUSED)proc_num++;}return proc_num;
}
- 在kernel/defs.h中对以上两个函数进行声明
- 在kernel/sysproc.c中实现sys_sysinfo函数,在该函数中获取用户传入的sysinfo结构体的指针(user_info)可以使用argaddr实现,首先在函数声明一个sysinfo kernel_info,通过上述的两个函数获取系统中空闲内存容量以及进程数量,填充kernel_info,然后需要将kernel_info的内容拷贝到user_info中,这里涉及到kernel space到user space的内存拷贝操作,可以参考sys_fstat() (kernel/sysfile.c)和filestat() (kernel/file.c) 中的做法,使用copyout进行拷贝,copyout的参数依次为当前process的pagetable,user space的目标内存起始地址,kernel space的拷贝内存气势地址,需要拷贝的长度
uint64 sys_sysinfo(void) {uint64 user_info;if (argaddr(0, &user_info) < 0)return -1;struct sysinfo kernel_info;kernel_info.freemem = get_free_memory_info();kernel_info.nproc = get_proc_num();struct proc *p = myproc();if (copyout(p->pagetable, user_info, (char*)&kernel_info, sizeof(kernel_info)) < 0)return -1;return 0;
}
这篇关于mit6.s081 lab2 System calls的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!