You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
42 lines
1.6 KiB
Rust
42 lines
1.6 KiB
Rust
2 years ago
|
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;
|
||
|
}
|
||
|
|
||
|
// 根据entry和sp构造一个 trap_context
|
||
|
pub fn from(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 返回
|
||
|
}
|
||
|
}
|