操作系统 Lab 1


Lab 1

功能实现

  1. 为每个 TaskControlBlock 维护一个 TaskInfo 对象, 并为 TaskInfo 实现了 init() 默认方法用于初始化.
  2. TASK_MANAGER 实现 get_task_info(&self, ti: *mut TaskInfo)set_syscall_times(&self, syscall_id: usize) 方法分别用于获取当前任务的信息以及计数系统调用, 并对外暴露调用接口.
  3. 进入 syscall 分发函数后先调用 set_syscall_times, 计数当前系统调用.
  4. run_first_task(&self) 中使用 get_time_ms() 初始化任务调度时刻.
  5. TASK_MANAGER::run_next_task(&self) 中依据当前任务调度时刻是否为 0 判断该任务是否被首次调度, 并使用 get_time_ms() 进行初始化.

问答题

  1. 正确进入 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 导致的.

  1. 深入理解 trap.S 中两个函数 __alltraps__restore 的作用, 并回答如下问题:

    1. 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 态的状态转换.

文章作者: Chengsx
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Chengsx !
  目录