Skip to main content

os/trap/
mod.rs

1mod context;
2
3use crate::config::TRAMPOLINE;
4use crate::syscall::syscall;
5use crate::task::{
6    SignalFlags, check_signals_of_current, current_add_signal, current_trap_cx,
7    current_trap_cx_user_va, current_user_token, exit_current_and_run_next,
8    suspend_current_and_run_next,
9};
10use crate::timer::{check_timer, set_next_trigger};
11use core::arch::{asm, global_asm};
12use riscv::interrupt::{Exception, Interrupt, Trap};
13use riscv::register::{mtvec::TrapMode, scause, sie, stval, stvec};
14
15global_asm!(include_str!("trap.S"));
16
17pub fn init() {
18    set_kernel_trap_entry();
19}
20
21fn set_kernel_trap_entry() {
22    unsafe {
23        stvec::write(stvec::Stvec::new(
24            linker_symbol_addr!(trap_from_kernel),
25            TrapMode::Direct,
26        ));
27    }
28}
29
30fn set_user_trap_entry() {
31    unsafe {
32        stvec::write(stvec::Stvec::new(TRAMPOLINE as usize, TrapMode::Direct));
33    }
34}
35
36pub fn enable_timer_interrupt() {
37    unsafe {
38        sie::set_stimer();
39    }
40}
41
42#[unsafe(no_mangle)]
43/// handle an interrupt, exception, or system call from user space
44pub fn trap_handler() -> ! {
45    set_kernel_trap_entry();
46    let scause = scause::read();
47    let stval = stval::read();
48    let trap: Trap<Interrupt, Exception> = match scause.cause().try_into() {
49        Ok(trap) => trap,
50        Err(_) => panic!(
51            "Unsupported trap {:?}, stval = {:#x}!",
52            scause.cause(),
53            stval
54        ),
55    };
56    match trap {
57        Trap::Exception(Exception::UserEnvCall) => {
58            // jump to next instruction anyway
59            let mut cx = current_trap_cx();
60            cx.sepc += 4;
61            // get system call return value
62            let result = syscall(cx.x[17], [cx.x[10], cx.x[11], cx.x[12]]);
63            // cx is changed during sys_exec, so we have to call it again
64            cx = current_trap_cx();
65            cx.x[10] = result as usize;
66        }
67        Trap::Exception(Exception::StoreFault)
68        | Trap::Exception(Exception::StorePageFault)
69        | Trap::Exception(Exception::InstructionFault)
70        | Trap::Exception(Exception::InstructionPageFault)
71        | Trap::Exception(Exception::LoadFault)
72        | Trap::Exception(Exception::LoadPageFault) => {
73            /*
74            println!(
75                "[kernel] {:?} in application, bad addr = {:#x}, bad instruction = {:#x}, kernel killed it.",
76                scause.cause(),
77                stval,
78                current_trap_cx().sepc,
79            );
80            */
81            current_add_signal(SignalFlags::SIGSEGV);
82        }
83        Trap::Exception(Exception::IllegalInstruction) => {
84            current_add_signal(SignalFlags::SIGILL);
85        }
86        Trap::Interrupt(Interrupt::SupervisorTimer) => {
87            set_next_trigger();
88            check_timer();
89            suspend_current_and_run_next();
90        }
91        _ => {
92            panic!(
93                "Unsupported trap {:?}, stval = {:#x}!",
94                scause.cause(),
95                stval
96            );
97        }
98    }
99    // check signals
100    if let Some((errno, msg)) = check_signals_of_current() {
101        println!("[kernel] {}", msg);
102        exit_current_and_run_next(errno);
103    }
104    trap_return();
105}
106
107#[unsafe(no_mangle)]
108/// set the new addr of __restore asm function in TRAMPOLINE page,
109/// set the reg a0 = trap_cx_ptr, reg a1 = phy addr of usr page table,
110/// finally, jump to new addr of __restore asm function
111pub fn trap_return() -> ! {
112    set_user_trap_entry();
113    let trap_cx_user_va = current_trap_cx_user_va();
114    let user_satp = current_user_token();
115    unsafe extern "C" {
116        unsafe fn __alltraps();
117        unsafe fn __restore();
118    }
119    let restore_va = linker_symbol_addr!(__restore) - linker_symbol_addr!(__alltraps) + TRAMPOLINE;
120    unsafe {
121        asm!(
122            "fence.i",
123            "jr {restore_va}",
124            restore_va = in(reg) restore_va,
125            in("a0") trap_cx_user_va,
126            in("a1") user_satp,
127            options(noreturn)
128        );
129    }
130}
131
132#[unsafe(no_mangle)]
133/// Unimplement: traps/interrupts/exceptions from kernel mode
134/// Todo: Chapter 9: I/O device
135pub fn trap_from_kernel() -> ! {
136    use riscv::register::sepc;
137    let scause = scause::read();
138    let stval = stval::read();
139    let trap: Trap<Interrupt, Exception> = match scause.cause().try_into() {
140        Ok(trap) => trap,
141        Err(_) => panic!(
142            "Unsupported trap from kernel: {:?}, stval = {:#x}, sepc = {:#x}!",
143            scause.cause(),
144            stval,
145            sepc::read()
146        ),
147    };
148    println!("stval = {:#x}, sepc = {:#x}", stval, sepc::read());
149    panic!("a trap {:?} from kernel!", trap);
150}
151
152pub use context::TrapContext;