XV6学习(2)Lab syscall

实验的代码放在了Github上。

第二个实验是Lab: system calls。
这个实验主要就是自己实现几个简单的系统调用并添加到XV6中。

XV6系统调用

添加系统调用主要有以下几步:

在user/user.h中添加系统调用函数的定义。

在user/usys.pl中添加入口,这个文件将会在make后生成user/usys.S文件,在该汇编文件中,每个函数就只有三行,将系统调用号通过li(load imm)存入a7寄存器,之后使用ecall进入内核态,最后返回。

fork: li a7, SYS_fork ecall ret

在kernel/syscall.h中定义系统调用号。

在kernel/syscall.c的syscalls函数指针数组中添加对应的函数。在syscall函数中,先读取trapframe->a7获取系统调用号,之后根据该系统调用号查找syscalls数组中的对应的处理函数并调用。

System call tracing (moderate)

先在proc结构体中添加一个trace_mask字段,之后在fork函数中复制该字段到新进程。

在系统调用sys_trace中就只要通过argint函数读取参数,然后设置给trace_mask字段就行了。

最后修改syscall,当系统调用号和trace_mask匹配时就打印相关信息。

// proc.h struct proc { ... // this is for sys_trace() uint trace_mask; }; // proc.c int fork(void) fork(void) { ... // copy trace mask np->trace_mask = p->trace_mask; ... } // sysproc.c uint64 sys_trace(void) { uint mask; if(argint(0, (int*)&mask) < 0) return -1; struct proc *p = myproc(); p->trace_mask |= mask; return 0; } // syscall.c void syscall(void) { int num; struct proc *p = myproc(); num = p->trapframe->a7; if(num > 0 && num < NELEM(syscalls) && syscalls[num]) { uint64 ret = syscalls[num](); p->trapframe->a0 = ret; if((1 << num) & p->trace_mask) { printf("%d: syscall %s -> %d\n", p->pid, syscall_name[num], ret); } } else { printf("%d %s: unknown sys call %d\n", p->pid, p->name, num); p->trapframe->a0 = -1; } } Sysinfo (moderate)

这一个系统调用主要就是要实现freemem和nproc两个函数来统计内存和进程。

// sysproc.c uint64 sys_sysinfo(void) { uint64 info; // user pointer struct sysinfo kinfo; struct proc *p = myproc(); if(argaddr(0, &info) < 0){ return -1; } kinfo.freemem = freemem(); kinfo.nproc = nproc(); if(copyout(p->pagetable, info, (char*)&kinfo, sizeof(kinfo)) < 0){ return -1; } return 0; }

阅读kalloc和kfree两个函数就可以知道,kmem.freelist是一个保存了当前空闲内存块的链表,因此只需要统计这个链表的长度再乘以PGSIZE就可以得到空闲内存。

// kalloc.c uint64 freemem(void) { uint64 counter = 0; struct run *r; acquire(&kmem.lock); r = kmem.freelist; while(r){ r = r->next; ++counter; } release(&kmem.lock); return counter * PGSIZE; }

阅读procdump和相关代码就可以知道,XV6的进程结构体保存在proc[NPROC]数组当中。而proc->state字段保存了PCB的当前状态,有UNUSED、SLEEPING、RUNNABLE、RUNNING、ZOMBIE五种状态。因此只需要遍历这个数组,然后统计state不是UNUSED状态的就行了。

// proc.c uint64 nproc(void) { uint64 counter = 0; struct proc *p; for(p = proc; p < &proc[NPROC]; p++) { acquire(&p->lock); if(p->state != UNUSED) { ++counter; } release(&p->lock); } return counter; }

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpxgzj.html