Lab 1
功能实现
- 为每个
TaskControlBlock
维护一个TaskInfo
对象, 并为TaskInfo
实现了init()
默认方法用于初始化. - 为
TASK_MANAGER
实现get_task_info(&self, ti: *mut TaskInfo)
与set_syscall_times(&self, syscall_id: usize)
方法分别用于获取当前任务的信息以及计数系统调用, 并对外暴露调用接口. - 进入
syscall
分发函数后先调用set_syscall_times
, 计数当前系统调用. - 在
run_first_task(&self)
中使用get_time_ms()
初始化任务调度时刻. - 在
TASK_MANAGER::run_next_task(&self)
中依据当前任务调度时刻是否为 0 判断该任务是否被首次调度, 并使用get_time_ms()
进行初始化.
问答题
正确进入 U 态后, 程序的特征还应有: 使用 S 态特权指令, 访问 S 态寄存器后会报错. 可以自行测试这些内容 (运行三个 bad 测例 (
ch2b_bad_*.rs
), 注意在编译时至少需要指定LOG=ERROR
才能观察到内核的报错信息), 描述程序出错行为, 同时注意注明你使用的 sbi 及其版本.答: 我使用的 sbi 版本为
RustSBI 0.3.0-alpha.2
.分别报错
[kernel] PageFault in application, bad addr = 0x0, bad instruction = 0x804003ac, kernel killed it
,[kernel] Illegal Instruction in application, kernel killed it
,[kernel] Illegal Instruction in application, kernel killed it
.分别是因为写入非法地址
0x0
, 使用 S 态特权指令sret
, 以及使用 S 态指令访问 S 态寄存器sstatus
导致的.
深入理解
trap.S
中两个函数__alltraps
和__restore
的作用, 并回答如下问题:L40: 刚进入
__restore
时,a0
代表了什么值. 请指出__restore
的两种使用情景.答:
a0
是指向__switch
后被切换任务的TaskContext
的指针;__restore
封装在goto_restore
中, 用于任务切换或 Trap 处理这两种使用情景后从 S 态返回 U 态.
2. **L43-L48: 这几行汇编代码特殊处理了哪些寄存器? 这些寄存器的的值对于进入用户态有何意义? 请分别解释.**
ld t0, 32*8(sp)
ld t1, 33*8(sp)
ld t2, 2*8(sp)
csrw sstatus, t0
csrw sepc, t1
csrw sscratch, t2
答: 特殊处理了 `sstatus`, `sepc`, `sscratch` 这三个特权寄存器, 在 `__alltraps` 进入 S 态前将这些特权寄存器的信息存储在了内核栈上.
+ `sstatus` 保存了 Trap 发生前 CPU 的特权级等信息, 在 Trap 处理完成后正确恢复特权级.
+ `sepc` 保存了 Trap 发生前最后一条指令的地址, 在 Trap 处理完成后恢复到正确的执行位置.
+ `sscratch` 保存了 Trap 发生前的栈指针 `sp`, 在 Trap 处理完成后正确恢复到用户栈, 确保用户态程序正确执行.
3. **L50-L56: 为何跳过了 `x2` 和 `x4`?**
ld x1, 1*8(sp)
ld x3, 3*8(sp)
.set n, 5
.rept 27
LOAD_GP %n
.set n, n+1
.endr
答: `x2` 是栈指针寄存器 `sp`: 用户栈指针已经通过 `csrw sscratch, t2` 读到了特权寄存器 `sscratch` 中, `sp` 指向当前内核栈, 用于恢复其它通用寄存器, 不可直接覆盖为用户栈指针.
`x4` 是线程指针寄存器 `tp`: 在当前情境中不会用到.
4. **L60: 该指令之后, `sp` 和 `sscratch` 中的值分别有什么意义?**
csrrw sp, sscratch, sp
答: `csrrw` 交换了 `sp` 与 `sscratch` 的值, 交换后 `sp` 指向用户栈栈顶, `sscratch` 指向内核栈栈顶, 并使用 `sret` 进行状态切换.
5. **`__restore` 中发生状态切换在哪一条指令? 为何该指令执行之后会进入用户态?**
答: `sret`. 为了执行这条指令, 硬件会将特权级按 `sstatus` 的 `SPP` 字段设置为 U, 并跳转到 `sepc` 指向的指令恢复程序执行.
6. **L13: 该指令之后, `sp` 和 `sscratch` 中的值分别有什么意义?**
csrrw sp, sscratch, sp
答: `csrrw` 交换了 `sp` 与 `sscratch` 的值, 交换后 `sp` 指向内核栈栈顶, `sscratch` 指向用户栈栈顶.
7. **从 U 态进入 S 态是哪一条指令发生的?**
答: 通过 `ecall` 指令执行系统调用发生从 U 态到 S 态的状态转换.