Tags: MIT 6.828
遇到的困难包括:
实验结束后的全部代码在:https://github.com/monkey2000/xv6-riscv/tree/syscall/
测试结果: 1
2
3
4
5
6
7
8
9
10
11
12
13
14answers-syscall.txt: OK
uthread:
$ make qemu-gdb
OK (2.3s)
running alarmtest:
$ make qemu-gdb
(3.7s)
alarmtest: test0: OK
alarmtest: test1: OK
usertests:
$ make qemu-gdb
OK (91.4s)
time: OK
Score: 100/100
上来直接:
1 |
|
这块要回答几个问题,打开 user/call.c
和 user/call.asm
,有如下代码片段:
1 |
|
1 |
|
下面来回答问题:
doc/riscv-calling.pdf
) , a0-a7 和 fa0-fa7 共计 16 个寄存器会用于传递参数13
f(8)+1 = 12
,又发现 main 中并为调用 f 函数,说明 f 在编译期被直接优化成一个常量 12
塞到 a1 寄存器里了。auipc ra,0x0
和 jalr 1440(ra)
,前者取当前指令的 pc 加上 0x0 存入 ra,后者跳转到 ra + 1440。计算知 0x0000000000000030 + 1440 = 0x00000000000005d0
。经验证是 printf 的入口地址。jalr
指令完成后,ra
寄存器会存储返回点位置(也即 pc + 4 )这题并不难,我给想复杂了。
首先我们把 Hint 里面的问题解决:thread_switch needs to save/restore only the callee-save registers. Why? 这个是因为协程切换的过程本质是一个函数调用,因此 caller-save registers
是被调用者(如 thread_a()
)保存好的。
然后我们研究以下代码该怎么写(抄):
kernel/swtch.S
,查阅 riscv calling convention ,验证这段代码可以完成寄存器的切换。注意 ra 表示返回地址,sp 表示当前栈顶。直接复制到 user/uthread_switch.S
即可。kernel/proc.h
中,找到上述代码配套的 context
结构体声明,复制到 user/uthread.c
中。uthread_switch(old_ctx, new_ctx)
,完成寄存器状态的切换;当新建协程时,将 ra 设为协程入口点地址,sp 设为 thread.stack
的最高地址(栈底)。第三部相对有思维量的代码如下,可以证明是正确的: 1
2t->ctx.ra = (uint64) func;
t->ctx.sp = (uint64) (&t->stack) + STACK_SIZE;
这块是以 alarm 为例实现一个 signal 系统,即 signal 触发的时候调用进程注册的 signal handler,运行结束后返回原来进程的位置,恢复状态。
首先,按照实验指导,添加 sigalarm 和 sigreturn 两个系统调用:
1 |
|
这里我给 proc 结构体新增了一些字段,来存储 alarm 相关的信息: 1
2
3
4
5
6
7
8
9// Per-process state
struct proc {
//... omitted
int alarm_interval; // Alarm's interval (0 for disabled)
uint64 alarm_handler; // Virtual address of the alarm handler (can be 0 due to xv6-rv's userspace memory layout)
uint64 alarm_last_tick; // Ticks of the last call
struct trapframe alarm_tf; // trapframe for storing original tf
uint alarm_state; // 1 if the handler hasn't return
};
前三个变量很好理解,这里解释一下 alarm_tf
和 alarm_state
的意义:
alarm_tf
用于在调用 alarm handler 的过程当中,存储原有的 trapframe(用户态的寄存器状态),这样在 sigreturn()
中可以恢复这个状态,实现恢复执行。alarm_state
用于防止因为上一个 alarm 信号还没处理完导致的重入