进入中断处理流程

接下来,我们将要手动触发一个 Trap(ebreak),并且进入中断处理流程。

开启中断

为了让硬件能够找到我们编写的 __interrupt 入口,在操作系统初始化时,需要将其写入 stvec 寄存器中:

os/src/interrupt/handler.rs

use super::context::Context;
use riscv::register::stvec;

global_asm!(include_str!("./interrupt.asm"));

/// 初始化中断处理
///
/// 把中断入口 `__interrupt` 写入 `stvec` 中,并且开启中断使能
pub fn init() {
    unsafe {
        extern "C" {
            /// `interrupt.asm` 中的中断入口
            fn __interrupt();
        }
        // 使用 Direct 模式,将中断入口设置为 `__interrupt`
        stvec::write(__interrupt as usize, stvec::TrapMode::Direct);
    }
}

处理中断

然后,我们再补上 __interrupt 后跳转的中断处理流程 handle_interrupt()

os/src/interrupt/handler.rs

/// 中断的处理入口
/// 
/// `interrupt.asm` 首先保存寄存器至 Context,其作为参数和 scause 以及 stval 一并传入此函数
/// 具体的中断类型需要根据 scause 来推断,然后分别处理
#[no_mangle]
pub fn handle_interrupt(context: &mut Context, scause: Scause, stval: usize) {
    panic!("Interrupted: {:?}", scause.cause());
}

触发中断

最后,我们把刚刚写的函数封装一下:

os/src/interrupt/mod.rs

//! 中断模块
//! 
//! 

mod handler;
mod context;

/// 初始化中断相关的子模块
/// 
/// - [`handler::init`]
/// - [`timer::init`]
pub fn init() {
    handler::init();
    println!("mod interrupt initialized");
}

同时,我们在 main 函数中主动使用 ebreak 来触发一个中断。

os/src/main.rs

...
mod interrupt;
...

/// Rust 的入口函数
///
/// 在 `_start` 为我们进行了一系列准备之后,这是第一个被调用的 Rust 函数
pub extern "C" fn rust_main() -> ! {
    // 初始化各种模块
    interrupt::init();

    unsafe {
        llvm_asm!("ebreak"::::"volatile");
    };

    unreachable!();
}

运行一下,可以看到 ebreak 导致程序进入了中断处理并退出,而没有执行到后面的 unreachable!()

运行输出

Hello rCore-Tutorial!
mod interrupt initialized
panic: 'Interrupted: Exception(Breakpoint)'

results matching ""

    No results matching ""

    results matching ""

      No results matching ""