    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68

    //! Trap handling functionality
    //!
    //! For rCore, we have a single trap entry point, namely `__alltraps`. At
    //! initialization in [`init()`], we set the `stvec` CSR to point to it.
    //!
    //! All traps go through `__alltraps`, which is defined in `trap.S`. The
    //! assembly language code does just enough work restore the kernel space
    //! context, ensuring that Rust code safely runs, and transfers control to
    //! [`trap_handler()`].
    //!
    //! It then calls different functionality based on what exactly the exception
    //! was. For example, timer interrupts trigger task preemption, and syscalls go
    //! to [`syscall()`].

    mod context;

    use crate::syscall::syscall;
    use core::arch::global_asm;
    use riscv::register::{
        mtvec::TrapMode,
        scause::{self, Exception, Trap},
        stval, stvec,
    };

    global_asm!(include_str!("trap.S"));

    /// initialize CSR `stvec` as the entry of `__alltraps`
    pub fn init() {
        extern "C" {
            fn __alltraps();
        }
        unsafe {
            stvec::write(__alltraps as usize, TrapMode::Direct);
        }
    }

    #[no_mangle]
    /// handle an interrupt, exception, or system call from user space
    pub fn trap_handler(cx: &mut TrapContext) -> &mut TrapContext {
        let scause = scause::read(); // get trap cause
        let stval = stval::read(); // get extra value
        match scause.cause() {
            Trap::Exception(Exception::UserEnvCall) => {
                cx.sepc += 4;
                cx.x[10] = syscall(cx.x[17], [cx.x[10], cx.x[11], cx.x[12]]) as usize;
            }
            Trap::Exception(Exception::StoreFault) | Trap::Exception(Exception::StorePageFault) => {
                println!("[kernel] PageFault in application, bad addr = {:#x}, bad instruction = {:#x}, kernel killed it.", stval, cx.sepc);
                panic!("[kernel] Cannot continue!");
                //run_next_app();
            }
            Trap::Exception(Exception::IllegalInstruction) => {
                println!("[kernel] IllegalInstruction in application, kernel killed it.");
                panic!("[kernel] Cannot continue!");
                //run_next_app();
            }
            _ => {
                panic!(
                    "Unsupported trap {:?}, stval = {:#x}!",
                    scause.cause(),
                    stval
                );
            }
        }
        cx
    }

    pub use context::TrapContext;