diff --git a/ch2/os/src/trap/context.rs b/ch2/os/src/trap/context.rs new file mode 100644 index 0000000..7ed956d --- /dev/null +++ b/ch2/os/src/trap/context.rs @@ -0,0 +1,40 @@ +use riscv::register::sstatus::{self, Sstatus, SPP}; + +/// Trap Context +#[repr(C)] +pub struct TrapContext { + /// 保存了 [0..31] 号寄存器, 其中0/2/4 号寄存器我们不保存, 2有特殊用途 + /// > 其中 [17] 号寄存器保存的是系统调用号 + /// + /// > [10]/[11]/[12] 寄存器保存了系统调用时的3个参数 + /// + /// > [2] 号寄存器因为我们有特殊用途所以也跳过保存, (保存了用户栈)保存了用户 USER_STACK 的 栈顶 + /// + /// > [0] 被硬编码为了0, 不会有变化, 不需要做任何处理 + /// + /// > [4] 除非特殊用途使用它, 一般我们也用不到, 不需要做任何处理 + pub x: [usize; 32], + /// CSR sstatus 保存的是在trap发生之前, cpu处在哪一个特权级 + pub sstatus: Sstatus, + /// CSR sepc 保存的是用户态ecall时 所在的那一行的代码 + pub sepc: usize, +} + +impl TrapContext { + /// 把用户栈的栈顶 保存到 [2] + pub fn set_sp(&mut self, sp: usize) { + self.x[2] = sp; + } + /// init app context + pub fn app_init_context(entry: usize, sp: usize) -> Self { + let mut sstatus = sstatus::read(); // 读取CSR sstatus + sstatus.set_spp(SPP::User); // 设置特权级为用户模式 + let mut cx = Self { + x: [0; 32], + sstatus, + sepc: entry, // 设置代码执行的开头, 将来条入到这里执行 + }; + cx.set_sp(sp); // 设置用户栈的栈顶 + cx // 返回, 外面会恢复完 x[0; 32] 之后最后 sret 根据entry和sstatus 返回 + } +}