lab1 report
实现功能
修改 TaskControlBlock ,加入成员变量 TaskInfo 。
初始化时,TaskInfo.status 为 TaskStatus::Running 。由于查询的是当前任务的状态,因此 TaskStatus 一定是 Running ;TaskInfo.syscall_times 为 全 0 ;TaskStatus.time 用 get_time_us() 赋值。
每次调用 syscall 的时候,都先更新 TaskControlBlock.TaskInfo ,然后真正去调用 syscall 。
返回的 task_info.status 和 task_info.syscall_times 都是直接从 TaskControlBlock 复制;task_info.time 为 (get_time_us() - TaskControlBlock.TaskInfo.time) / 1000 ,从而体现出时间差以及时间单位换算。
简答作业
1
[rustsbi] RustSBI version 0.2.2, adapting to RISC-V SBI v1.0.0
- ch2b_bad_address.rs
- [ERROR] [kernel] PageFault in application, core dumped.
- 访问错误地址
- ch2b_bad_instructions.rs
- [ERROR] [kernel] IllegalInstruction in application, core dumped.
- 执行非法指令
- ch2b_bad_register.rs
- [ERROR] [kernel] IllegalInstruction in application, core dumped.
- 执行非法指令
2
1
__restore 是在 switch 的时候,通过设置 ra 寄存器调用的。在 switch 期间没有写过 a0 寄存器,因此 a0 在 __restore 时仍然是 switch 的第一个参数,unuse 或者 current_task_cx_ptr 。
在启用第一个进程和切换进程这两个场景下,都会需要通过 restore 来设置寄存器。
2
特殊处理了 sstatus、sepc、sscratch 寄存器。
- sscratch:进入用户态时,保存内核栈地址。用户态返回内核态时,将 sp 设置为内核栈地址。
- sepc:当 Trap 是一个异常的时候,记录 Trap 发生之前执行的最后一条指令的地址
- sstatus:SPP 等字段给出 Trap 发生之前 CPU 处在哪个特权级(S/U)等信息
3
x2 是 sp ,会在后面保存到 sscratch 。
x4 用户程序用不到,所以不用保存。
4
sscratch 是内核栈地址,sp 是用户栈地址。
5
sret 指令。
sret 的时候,CPU 会将当前的特权级按照 sstatus 的 SPP 字段设置为 U 或者 S ;CPU 会跳转到 sepc 寄存器指向的那条指令,然后继续执行。
6
sp 是内核栈,sscratch 是用户栈。
7
ecall
其它
作业题和 trap.S 的行有一些不一致。
lab2
(刚知道不用写报告,气死我了)
实现功能
fix sys_get_time && sys_task_info
通过用户态页表将用户态地址转换为物理地址。
将传入的 *TimeVal 地址转换为内核态可用的指针,然后填充结构体。
sys_task_info 同理。
sys_mmap
首先对输入参数做检查,非法参数返回 -1 。
然后检查将要 mmap 的地址对应的 vpn 是否已经 map ,如果已经 map 了,返回 -1 ,否则将这一页 mmap 到一个匿名 frame 。
传入的 port 需要转换成 MapPermission ,然后设置 U 位。
sys_munmap
检查将要 unmap 的地址是否都是已经被 map ,如果 unmap 一段没有被 map 的地址会返回 -1 。
检查 vpn 是否 map 的方式,是通过 page table 获取 pte ,如果 ptr 存在且有效,就认为已经 map。所以 unmap 也是调用 page table 的 unmap 。
尝试操作 data_frames ,但是似乎有 bug ,无法正常调用 remove 函数,所以就没用。
问答题
1
上图为 SV39 分页模式下的页表项,其中 [53:10] 这 44 位是物理页号,最低的 8 位 [7:0] 则是标志位,它们的含义如下:
仅当 V(Valid) 位为 1 时,页表项才是合法的;
R/W/X 分别控制索引到这个页表项的对应虚拟页面是否允许读/写/取指;
U 控制索引到这个页表项的对应虚拟页面是否在 CPU 处于 U 特权级的情况下是否被允许访问;
G 是 Global;
A(Accessed) 记录自从页表项上的这一位被清零之后,页表项的对应虚拟页面是否被访问过;
D(Dirty) 则记录自从页表项上的这一位被清零之后,页表项的对应虚拟页表是否被修改过。
2
其它
小语法错误。
1 | - 一定要注意 mmap 是的页表项,注意 riscv 页表项的格式与 port 的区别。 |
lab3
spawn 就是抄了一下 fork 和 exec 没啥难度。stride 调度算法的测例不是很好,最后用玄学办法才勉强过了测例,很烦。建议测例改成在调度过程中 print ,然后用 python 检查 print 内容的比例。stride 是我最讨厌的 lab 。
lab4
好难,感觉的是最难的 lab 了。学习了如何在磁盘中进行读写,如何与底层磁盘交互。
lab5
这个感觉没啥难度,就是按照文档写完就好了,总共好像也不到五十行。