Xv6 lab2 增加系统调用
在本lab实验中,需要实现两个系统调用,分别为trace
和sysinfo
。
系统调用trace
主要用于debug其他程序所执行的系统调用。打开trace,并通过mask设置需要观察的系统调用内容。在后续命令执行的时候,即可打印相关系统调用和其返回值。
系统调用sysinfo
则用于统计空闲内存个数,以及执行的进程个数。
添加一个系统调用的基本步骤
- 系统调用需要提供用户态下的调用接口,需要在
user/user.h
文件下添加用户态函数原型。 - 在
user/usys.pl
文件中添加系统调用的入口。在Makefile文件中,该脚本用于生成汇编代码,将对应的系统调用号读入a7寄存器。 - 在内核部分,设置系统调用号,以及从系统调用号到索引的关系。在
kernel/syscall.h
添加新的系统调用号,并在kernel/syscall.c
中建立系统调用号和函数的索引关系。 - 最后在
kernel/sysproc
文件中实现对应的系统调用(sys_trace,sys_sysinfo)等,完成具体的功能。
系统调用trace
- user/trace.c
- user/user.h
- user/usys.pl
- kernel/syscall.c
- kernel/sysproc.c
用户态到内核态时,由于页表不通用,寄存器也不通用。
- 参数需要使用argaddr、argint、argstr等系列函数,从用户进程的trapframe中读取用户进程寄存器中的参数。
- 由于页表不同,指针也不能直接互通访问,而是需要copyin、copyout方法结合进程的页表,才能顺利找到用户态指针对应的物理内存地址。完成数据的传输。
需要在proc结构中保存需要记录的系统调用,使用mask实现。
打印系统调用的实现,需要修改system call执行跳转的部分,若匹配mask,则打印该系统调用。
系统调用sysinfo
在这一部分,不仅需要添加sysinfo的调用逻辑,还需要实现系统调用的具体实现:
- 从用户态读取保存信息的地址信息
- 统计系统信息:空闲内存和运行程序数
- 将信息通过copyout方法保存到用户态的空间中。
// sysinfo系统调用
uint64
sys_sysinfo(void)
{
// 获取user sys info地址
uint64 user_sys_info;
if(argaddr(0, &user_sys_info) < 0)
return -1;
struct sysinfo kernel_sys_info;
kernel_sys_info.freemem = k_count_free_memory();
kernel_sys_info.nproc = count_proc();
// 将kernel_sys_info拷贝回user空间
if(copyout(myproc()->pagetable, user_sys_info, (char*)&kernel_sys_info, sizeof(struct sysinfo)) < 0)
return -1;
return 0;
}
其中k_count_free_memory()
和count_proc()
需要分别在kernel/kalloc.c
和kernel/proc.c
文件中实现。
// count free memory pages
uint64
k_count_free_memory(void)
{
uint64 res = 0;
acquire(&kmem.lock);
struct run *r = kmem.freelist;
while(r){
res += PGSIZE;
r = r->next;
}
release(&kmem.lock);
return res;
}
// count the number of processes.
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;
}
skr