Lab

  1. lab2 中, 我们是什么时候第一次进入U态的?

    __init_sepc 中调用 sret 时. 因为程序一开始执行 main 函数, 到 call_first_process 时选择第一个进程, 进行一次 __switch_to. 在退出时会进入 __init_sepc 中, 此时的 SPP = 0, 调用 sret 会将特权级设成 U 态, 所以此时第一次进入 U 态.

    特别地, 执行 sret 进入 U 态跳转到 0x80200000, 即 head.S_start 的位置. 此时执行 call main 后, main() 的第一句 puts() 需要 S 态权限, U 态执行时会触发 trap_s, 而 sepc 被设置为 ecall 指令的位置, 此时执行 trap_shandler_s, 由于不是时钟中断, 会跳到 else 分支, 如果里面加输出会看到程序输出; 之后回到 trap_s, sret 又回到 ecall, 但是进入 trap_s 前是 U 态, 所以会一直在 ecall 指令重复进入 trap_s, 达到死循环的目的; 前面的输出也会循环输出

  2. lab2 中样例进入死循环的问题. 经过 GDB 调试, 发现倒数第二条样例最后一个完成的是第二个进程, 而在完成上一个样例时调用的是 task_init() + init_test_case() + schedule(), 由于 schedule() 没有初始化 current, 所以 current 仍然指向 pid = 2, 此时 __switch_topid = 2 进程保存在栈上的 ra 更新成现在的 ra, 即 __switch_to 的下一行. 当调度算法运行到需要切换到 pid = 2 时, 从栈上恢复的 ra__switch_to 的下一行, 即 return. 所以出现了再一次执行 return 的情况, 导致程序出错. 解决方法: 将 schedule() 改成 call_first_process(), 初始化 current 即可.