Lab syscall System calls

Lab 2 System Call

​ lab2 总算是跌跌撞撞做完了,其实思路不难,但就是会发生一些意想不到的错误,就包括了 PPT 中提到的指针问题,把我卡了一天f**k;然后内存那个地方误打误撞还做出来了,思路找wyy提示了一下,总而言之还是对页表部分理解不够深刻吧可能

​ 学习网站:https://pdos.csail.mit.edu/6.S081/2020/labs/syscall.html

System call tracing

​ 要求实现一个调用跟踪的 trace,其中有一个地方我一开始没理解到 mask 是干嘛的(原文: You have to modify the xv6 kernel to print out a line when each system call is about to return, if the system call’s number is set in the mask. ),卡了2天(英语不够,google来凑);

1、修改 Makefile

​ add $U/_trace\

2、添加 syscall

​ add a prototype for the system call to user/user.h, a stub to user/usys.pl, and a syscall number to kernel/syscall.h. The Makefile invokes the perl script user/usys.pl, which produces user/usys.S, the actual system call stubs, which use the RISC-V ecall instruction to transition to the kernel.

3、添加 sys_trace()函数 kernel/sysproc.c
1
2
3
4
5
6
7
8
9
10
// lab2 trace
uint64
sys_trace(void){
int n;
struct proc *p = myproc();
if (argint(0,&n)<0)
return -1;
p->mask = n;
return 0;
}
4、修改 fork 函数 kernel/proc.c

​ 以防万一,修改的时候mask还是上锁了,mask 其实是每个 process 的 private 信息应该,但是上锁无伤大雅感觉,就放到了release前边儿

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
46
47
48
49
// Create a new process, copying the parent.
// Sets up child kernel stack to return as if from fork() system call.
int
fork(void)
{
int i, pid;
struct proc *np;
struct proc *p = myproc();

// Allocate process.
if((np = allocproc()) == 0){
return -1;
}

// Copy user memory from parent to child.
if(uvmcopy(p->pagetable, np->pagetable, p->sz) < 0){
freeproc(np);
release(&np->lock);
return -1;
}
np->sz = p->sz;

np->parent = p;

// copy saved user registers.
*(np->trapframe) = *(p->trapframe);

// Cause fork to return 0 in the child.
np->trapframe->a0 = 0;

// increment reference counts on open file descriptors.
for(i = 0; i < NOFILE; i++)
if(p->ofile[i])
np->ofile[i] = filedup(p->ofile[i]);
np->cwd = idup(p->cwd);

safestrcpy(np->name, p->name, sizeof(p->name));

pid = np->pid;

np->state = RUNNABLE;

// lab2 get the trace mask from parent
np->mask = p->mask;

release(&np->lock);

return pid;
}
5、添加trace输出

​ 提前准备好映射的名字,因为输出的时候需要(You will need to add an array of syscall names to index into.),然后积极犯错,忘记如何定义二维数组的信息了

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
static const char *syscall_names[] = {
[SYS_fork] "fork",
[SYS_exit] "exit",
[SYS_wait] "wait",
[SYS_pipe] "pipe",
[SYS_read] "read",
[SYS_kill] "kill",
[SYS_exec] "exec",
[SYS_fstat] "fstat",
[SYS_chdir] "chdir",
[SYS_dup] "dup",
[SYS_getpid] "getpid",
[SYS_sbrk] "sbrk",
[SYS_sleep] "sleep",
[SYS_uptime] "uptime",
[SYS_open] "open",
[SYS_write] "write",
[SYS_mknod] "mknod",
[SYS_unlink] "unlink",
[SYS_link] "link",
[SYS_mkdir] "mkdir",
[SYS_close] "close",
[SYS_trace] "trace",
[SYS_sysinfo] "sysinfo",
};

void
syscall(void) {
int num;
struct proc *p = myproc();

// num syscall numbers store in the register a7
num = p->trapframe->a7;
if (num > 0 && num < NELEM(syscalls) && syscalls[num]) {
p->trapframe->a0 = syscalls[num]();
} else {
printf("%d %s: unknown sys call %d\n",
p->pid, p->name, num);
p->trapframe->a0 = -1;
}

// trace the syscall
if (((1 << num) & p->mask) > 0)
printf("%d: syscall %s -> %d\n", p->pid, syscall_names[num], p->trapframe->a0);
}

​ 到这里 trace 就完成了,解决之前的疑惑,mask 和 num 两个的关系,在开头的英语中说的是,如果返回的 mask 和调用 num 在mask 中,也就是那个mask = 1 << num ,ok搞定

Sysinfo

​ 这个实验着实让人伤脑筋一开始,主要是没认真 xv6 这书,书上说了 defs.h 中定义了各个模块的接口,然而一开始没看见,所以老是不知道怎么把要加的两个函数加入到新函数中,老是出现未定义的错误提示

1、添加基本的调用信息

​ 和 trace 中的步骤一样,每个地方都要填

2、kernel/kalloc.c

​ 遍历 freelist ,把所有的 page 求和就好了,这里我一开始很meng不知道怎么办,后来问了问wyy逻辑关系,一下子就明朗了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// lab2
uint64
collect_free_memory(void) {
uint64 res = 0;
struct run* r;
acquire(&kmem.lock);
r = kmem.freelist;
while (r) {
res += PGSIZE;
r = r->next;
}
release(&kmem.lock);
return res;
}
3、kernel/proc.c

​ 这里的 p->state 在 proc.h 中有要求上锁,所以要小心

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//lab2
uint64
collect_process_number(void){
uint64 n = 0;
struct proc *p;
for (p = proc;p < &proc[NPROC];p++) {
acquire(&p->lock);
if (p->state != UNUSED){
n += 1;
}
release(&p->lock);
}
return n;
}
4、kernel/sysproc.c

​ 这里一开始我犯的错误,是开了一个 sysinfo 的指针,然后将 info->freemem = collect_free_memory(),然后返回的地址是一个未知的地址,指针指向的是一个 uint64 的地址,根本不是值,f**k一天过去了原来如此,太菜了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// lab2 sys_info
uint64
sys_sysinfo(void){

uint64 addr;
// wrong answer
// struct sysinfo* info;
struct sysinfo info;
if (argaddr(0,&addr)<0){
return -1;
}

struct proc* p = myproc();
info.freemem= collect_free_memory();
info.nproc = collect_process_number();

if (copyout(p->pagetable,addr,(char*)&info,sizeof(info))<0){
return -1;
}
return 0;
}

​ 到此就两个实验结束了,赶紧学习下一个鸭得,不然得失业了要,下一个实验很有意思,是关于页表的。


Lab syscall System calls
https://www.bencorn.com/2021/03/30/Lab-syscall-System-calls/
作者
Bencorn
发布于
2021年3月30日
许可协议