batch
这章开始,计算机能处理一个接一个的任务。任务可能失败,异常,崩溃,此时 os 应该能及时处理,并开始下一个任务
栈切换
一共有 3 个栈
- 操作系统执行之前的栈
 - 内核栈
 - 用户栈
 
sp指向boot_stack_top执行rust_main执行到run_next_app,__restore时将sp指向内核栈sret,sp指向用户栈
内核栈从一开始就是空的
trap
trap 用于从用户态跳转到内核态,处理异常与中断,并在结束后返回用户态
下面考察 trap 前后的用户栈和内核栈
(栈总是要假装自己回来之后什么也没有发生)
首先,批处理系统中,不考虑外部硬件中断。因此,内核态的 CPU 不会被打断抢占
然后,不考虑分时,任务总是执行完了再执行其他任务。因此,CPU 在内核态总是把手上的事情按部就班做完,然后再慢慢回到用户态
所以当 CPU 在用户态执行程序时,内核栈只需要保存用户栈的地址,以方便在中断完成之后回到用户态
分两种情况讨论
- 中断
 
    -> 正在用户态执行任务
    -> 发生系统调用 ecall,CPU 切换到内核态
    -> 交换 sp(x2) <-> sscratch,sp 现在指向内核栈地址
-> 将寄存器信息保存到内核栈
-> 内核态处理系统调用 call trap_handler,然后回来
-> 执行 __restore
-> 指向内核栈,恢复寄存器
-> 交换 sp(x2) <-> sscratch,sp 现在指向用户栈地址
    -> sret,CPU 切换到用户态
    -> 继续执行任务
- 初始化
 
-> 在内核态,把下一个程序加载到内存
-> 伪造一份用户态寄存器上下文,
    假装自己刚刚结束了一个空的程序的系统调用,
    现在准备回用户态
-> 调用 __restore, sret 回到用户态,此时 sp 指向全新的用户栈
    -> 执行程序
sepc
Supervisor Exception Program Counter
或者 S模式异常PC寄存器
当 trap 发生,陷入 S 态时,sepc 被写入当前 pc 寄存器的值(通常是虚拟地址)
trap 应当保存这个值,以便 trap 结束后返回程序执行位置