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, sscratch, sstatus, 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 extern "C" {
23 unsafe fn __alltraps();
24 unsafe fn __alltraps_k();
25 }
26 let __alltraps_k_va =
27 linker_symbol_addr!(__alltraps_k) - linker_symbol_addr!(__alltraps) + TRAMPOLINE;
28 unsafe {
29 stvec::write(stvec::Stvec::new(__alltraps_k_va, TrapMode::Direct));
30 sscratch::write(linker_symbol_addr!(trap_from_kernel));
31 }
32}
33
34fn set_user_trap_entry() {
35 unsafe {
36 stvec::write(stvec::Stvec::new(TRAMPOLINE as usize, TrapMode::Direct));
37 }
38}
39
40pub fn enable_timer_interrupt() {
41 unsafe {
42 sie::set_stimer();
43 }
44}
45
46fn enable_supervisor_interrupt() {
47 unsafe {
48 sstatus::set_sie();
49 }
50}
51
52fn disable_supervisor_interrupt() {
53 unsafe {
54 sstatus::clear_sie();
55 }
56}
57
58#[unsafe(no_mangle)]
59pub fn trap_handler() -> ! {
60 set_kernel_trap_entry();
61 let scause = scause::read();
62 let stval = stval::read();
63 let trap: Trap<Interrupt, Exception> = match scause.cause().try_into() {
64 Ok(trap) => trap,
65 Err(_) => panic!(
66 "Unsupported trap {:?}, stval = {:#x}!",
67 scause.cause(),
68 stval
69 ),
70 };
71 match trap {
72 Trap::Exception(Exception::UserEnvCall) => {
73 let mut cx = current_trap_cx();
75 cx.sepc += 4;
76
77 enable_supervisor_interrupt();
78
79 let result = syscall(cx.x[17], [cx.x[10], cx.x[11], cx.x[12]]);
81 cx = current_trap_cx();
83 cx.x[10] = result as usize;
84 }
85 Trap::Exception(Exception::StoreFault)
86 | Trap::Exception(Exception::StorePageFault)
87 | Trap::Exception(Exception::InstructionFault)
88 | Trap::Exception(Exception::InstructionPageFault)
89 | Trap::Exception(Exception::LoadFault)
90 | Trap::Exception(Exception::LoadPageFault) => {
91 current_add_signal(SignalFlags::SIGSEGV);
100 }
101 Trap::Exception(Exception::IllegalInstruction) => {
102 current_add_signal(SignalFlags::SIGILL);
103 }
104 Trap::Interrupt(Interrupt::SupervisorTimer) => {
105 set_next_trigger();
106 check_timer();
107 suspend_current_and_run_next();
108 }
109 Trap::Interrupt(Interrupt::SupervisorExternal) => {
110 crate::board::irq_handler();
111 }
112 _ => {
113 panic!(
114 "Unsupported trap {:?}, stval = {:#x}!",
115 scause.cause(),
116 stval
117 );
118 }
119 }
120 if let Some((errno, msg)) = check_signals_of_current() {
122 println!("[kernel] {}", msg);
123 exit_current_and_run_next(errno);
124 }
125 trap_return();
126}
127
128#[unsafe(no_mangle)]
129pub fn trap_return() -> ! {
133 disable_supervisor_interrupt();
134 set_user_trap_entry();
135 let trap_cx_user_va = current_trap_cx_user_va();
136 let user_satp = current_user_token();
137 unsafe extern "C" {
138 unsafe fn __alltraps();
139 unsafe fn __restore();
140 }
141 let restore_va = linker_symbol_addr!(__restore) - linker_symbol_addr!(__alltraps) + TRAMPOLINE;
142 unsafe {
144 asm!(
145 "fence.i",
146 "jr {restore_va}",
147 restore_va = in(reg) restore_va,
148 in("a0") trap_cx_user_va,
149 in("a1") user_satp,
150 options(noreturn)
151 );
152 }
153}
154
155#[unsafe(no_mangle)]
156pub fn trap_from_kernel(_trap_cx: &TrapContext) {
157 let scause = scause::read();
158 let stval = stval::read();
159 let trap: Trap<Interrupt, Exception> = match scause.cause().try_into() {
160 Ok(trap) => trap,
161 Err(_) => panic!(
162 "Unsupported trap from kernel: {:?}, stval = {:#x}!",
163 scause.cause(),
164 stval
165 ),
166 };
167 match trap {
168 Trap::Interrupt(Interrupt::SupervisorExternal) => {
169 crate::board::irq_handler();
170 }
171 Trap::Interrupt(Interrupt::SupervisorTimer) => {
172 set_next_trigger();
173 check_timer();
174 }
176 _ => {
177 panic!(
178 "Unsupported trap from kernel: {:?}, stval = {:#x}!",
179 scause.cause(),
180 stval
181 );
182 }
183 }
184}
185
186pub use context::TrapContext;