1mod context;
2
3use crate::config::{TRAMPOLINE, TRAP_CONTEXT};
4use crate::syscall::syscall;
5use crate::task::{
6 SignalFlags, check_signals_error_of_current, current_add_signal, current_trap_cx,
7 current_user_token, exit_current_and_run_next, handle_signals, suspend_current_and_run_next,
8};
9use crate::timer::set_next_trigger;
10use core::arch::{asm, global_asm};
11use riscv::interrupt::{Exception, Interrupt, Trap};
12use riscv::register::{mtvec::TrapMode, scause, sie, stval, stvec};
13
14global_asm!(include_str!("trap.S"));
15
16pub fn init() {
17 set_kernel_trap_entry();
18}
19
20fn set_kernel_trap_entry() {
21 unsafe {
22 stvec::write(stvec::Stvec::new(
23 linker_symbol_addr!(trap_from_kernel),
24 TrapMode::Direct,
25 ));
26 }
27}
28
29fn set_user_trap_entry() {
30 unsafe {
31 stvec::write(stvec::Stvec::new(TRAMPOLINE as usize, TrapMode::Direct));
32 }
33}
34
35pub fn enable_timer_interrupt() {
36 unsafe {
37 sie::set_stimer();
38 }
39}
40
41#[unsafe(no_mangle)]
42pub fn trap_handler() -> ! {
44 set_kernel_trap_entry();
45 let scause = scause::read();
46 let stval = stval::read();
47 let trap: Trap<Interrupt, Exception> = match scause.cause().try_into() {
48 Ok(trap) => trap,
49 Err(_) => panic!(
50 "Unsupported trap {:?}, stval = {:#x}!",
51 scause.cause(),
52 stval
53 ),
54 };
55 match trap {
56 Trap::Exception(Exception::UserEnvCall) => {
57 let mut cx = current_trap_cx();
59 cx.sepc += 4;
60 let result = syscall(cx.x[17], [cx.x[10], cx.x[11], cx.x[12]]);
62 cx = current_trap_cx();
64 cx.x[10] = result as usize;
65 }
66 Trap::Exception(Exception::StoreFault)
67 | Trap::Exception(Exception::StorePageFault)
68 | Trap::Exception(Exception::InstructionFault)
69 | Trap::Exception(Exception::InstructionPageFault)
70 | Trap::Exception(Exception::LoadFault)
71 | Trap::Exception(Exception::LoadPageFault) => {
72 current_add_signal(SignalFlags::SIGSEGV);
81 }
82 Trap::Exception(Exception::IllegalInstruction) => {
83 current_add_signal(SignalFlags::SIGILL);
84 }
85 Trap::Interrupt(Interrupt::SupervisorTimer) => {
86 set_next_trigger();
87 suspend_current_and_run_next();
88 }
89 _ => {
90 panic!(
91 "Unsupported trap {:?}, stval = {:#x}!",
92 scause.cause(),
93 stval
94 );
95 }
96 }
97 handle_signals();
100
101 if let Some((errno, msg)) = check_signals_error_of_current() {
103 println!("[kernel] {}", msg);
104 exit_current_and_run_next(errno);
105 }
106 trap_return();
107}
108
109#[unsafe(no_mangle)]
110pub fn trap_return() -> ! {
114 set_user_trap_entry();
115 let trap_cx_ptr = TRAP_CONTEXT;
116 let user_satp = current_user_token();
117 unsafe extern "C" {
118 unsafe fn __alltraps();
119 unsafe fn __restore();
120 }
121 let restore_va = linker_symbol_addr!(__restore) - linker_symbol_addr!(__alltraps) + TRAMPOLINE;
122 unsafe {
123 asm!(
124 "fence.i",
125 "jr {restore_va}",
126 restore_va = in(reg) restore_va,
127 in("a0") trap_cx_ptr,
128 in("a1") user_satp,
129 options(noreturn)
130 );
131 }
132}
133
134#[unsafe(no_mangle)]
135pub fn trap_from_kernel() -> ! {
138 use riscv::register::sepc;
139 let scause = scause::read();
140 let stval = stval::read();
141 let trap: Trap<Interrupt, Exception> = match scause.cause().try_into() {
142 Ok(trap) => trap,
143 Err(_) => panic!(
144 "Unsupported trap from kernel: {:?}, stval = {:#x}, sepc = {:#x}!",
145 scause.cause(),
146 stval,
147 sepc::read()
148 ),
149 };
150 println!("stval = {:#x}, sepc = {:#x}", stval, sepc::read());
151 panic!("a trap {:?} from kernel!", trap);
152}
153
154pub use context::TrapContext;