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::register::{
13 mtvec::TrapMode,
14 scause::{self, Exception, Interrupt, Trap},
15 sie, stval, stvec,
16};
17
18global_asm!(include_str!("trap.S"));
19
20pub fn init() {
21 set_kernel_trap_entry();
22}
23
24fn set_kernel_trap_entry() {
25 unsafe {
26 stvec::write(trap_from_kernel as usize, TrapMode::Direct);
27 }
28}
29
30fn set_user_trap_entry() {
31 unsafe {
32 stvec::write(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)]
43pub fn trap_handler() -> ! {
45 set_kernel_trap_entry();
46 let scause = scause::read();
47 let stval = stval::read();
48 match scause.cause() {
49 Trap::Exception(Exception::UserEnvCall) => {
50 let mut cx = current_trap_cx();
52 cx.sepc += 4;
53 let result = syscall(cx.x[17], [cx.x[10], cx.x[11], cx.x[12]]);
55 cx = current_trap_cx();
57 cx.x[10] = result as usize;
58 }
59 Trap::Exception(Exception::StoreFault)
60 | Trap::Exception(Exception::StorePageFault)
61 | Trap::Exception(Exception::InstructionFault)
62 | Trap::Exception(Exception::InstructionPageFault)
63 | Trap::Exception(Exception::LoadFault)
64 | Trap::Exception(Exception::LoadPageFault) => {
65 current_add_signal(SignalFlags::SIGSEGV);
74 }
75 Trap::Exception(Exception::IllegalInstruction) => {
76 current_add_signal(SignalFlags::SIGILL);
77 }
78 Trap::Interrupt(Interrupt::SupervisorTimer) => {
79 set_next_trigger();
80 check_timer();
81 suspend_current_and_run_next();
82 }
83 _ => {
84 panic!(
85 "Unsupported trap {:?}, stval = {:#x}!",
86 scause.cause(),
87 stval
88 );
89 }
90 }
91 if let Some((errno, msg)) = check_signals_of_current() {
93 println!("[kernel] {}", msg);
94 exit_current_and_run_next(errno);
95 }
96 trap_return();
97}
98
99#[unsafe(no_mangle)]
100pub fn trap_return() -> ! {
104 set_user_trap_entry();
105 let trap_cx_user_va = current_trap_cx_user_va();
106 let user_satp = current_user_token();
107 unsafe extern "C" {
108 unsafe fn __alltraps();
109 unsafe fn __restore();
110 }
111 let restore_va = __restore as usize - __alltraps as usize + TRAMPOLINE;
112 unsafe {
113 asm!(
114 "fence.i",
115 "jr {restore_va}",
116 restore_va = in(reg) restore_va,
117 in("a0") trap_cx_user_va,
118 in("a1") user_satp,
119 options(noreturn)
120 );
121 }
122}
123
124#[unsafe(no_mangle)]
125pub fn trap_from_kernel() -> ! {
128 use riscv::register::sepc;
129 println!("stval = {:#x}, sepc = {:#x}", stval::read(), sepc::read());
130 panic!("a trap {:?} from kernel!", scause::read().cause());
131}
132
133pub use context::TrapContext;