手动触发断点中断

我们引入一个对寄存器进行操作的库,这样就可以不用自己写了。

// Cargo.toml

[dependencies]
riscv = { git = "https://github.com/rcore-os/riscv", features = ["inline-asm"] }

为了方便起见,我们先将 stvec 设置为 Direct 模式跳转到一个统一的处理程序。

// src/lib.rs

mod interrupt;

// src/interrupt.rs

use riscv::register::{
    scause,
    sepc,
    stvec,
    sscratch
};

pub fn init() {
    unsafe {
        sscratch::write(0);
        stvec::write(trap_handler as usize, stvec::TrapMode::Direct);
    }
    println!("++++ setup interrupt! ++++");
}

fn trap_handler() -> ! {
    let cause = scause::read().cause();
    let epc = sepc::read();
    println!("trap: cause: {:?}, epc: 0x{:#x}", cause, epc);
    panic!("trap handled!");
}

这里我们通过设置 stvec 使得所有中断都跳转到 trap_handler 并将其作为中断处理程序。而这个中断处理程序仅仅输出了一下中断原因以及中断发生的地址,就匆匆 panic 了事。

我们在主函数中通过汇编指令手动触发断点中断:

// src/init.rs

#[no_mangle]
pub extern "C" fn rust_main() -> ! {
    crate::interrupt::init();
    unsafe {
        asm!("ebreak"::::"volatile");
    }
    panic!("end of rust_main");
}

使用 make run构建并运行,结果如下:

[success] trap handled

++++ setup interrupt! ++++
trap: cause: Exception(Breakpoint), epc: 0x0x80200022
panicked at 'trap handled!', src/interrupt.rs:20:5

可见在进入中断处理程序之前,硬件为我们正确的设置好了 scause,sepc 寄存器;随后我们正确的进入了设定的中断处理程序。

如果输出与预期不一致的话,可以在这里找到目前的代码进行参考。

results matching ""

    No results matching ""