1mod context;
15
16use crate::config::{TRAMPOLINE, TRAP_CONTEXT};
17use crate::syscall::syscall;
18use crate::task::{
19 current_trap_cx, current_user_token, exit_current_and_run_next, suspend_current_and_run_next,
20};
21use crate::timer::set_next_trigger;
22use core::arch::{asm, global_asm};
23use riscv::register::{
24 mtvec::TrapMode,
25 scause::{self, Exception, Interrupt, Trap},
26 sie, stval, stvec,
27};
28
29global_asm!(include_str!("trap.S"));
30pub fn init() {
32 set_kernel_trap_entry();
33}
34
35fn set_kernel_trap_entry() {
36 unsafe {
37 stvec::write(trap_from_kernel as usize, TrapMode::Direct);
38 }
39}
40
41fn set_user_trap_entry() {
42 unsafe {
43 stvec::write(TRAMPOLINE as usize, TrapMode::Direct);
44 }
45}
46pub fn enable_timer_interrupt() {
48 unsafe {
49 sie::set_stimer();
50 }
51}
52
53#[unsafe(no_mangle)]
54pub fn trap_handler() -> ! {
56 set_kernel_trap_entry();
57 let scause = scause::read();
58 let stval = stval::read();
59 match scause.cause() {
60 Trap::Exception(Exception::UserEnvCall) => {
61 let mut cx = current_trap_cx();
63 cx.sepc += 4;
64 let result = syscall(cx.x[17], [cx.x[10], cx.x[11], cx.x[12]]);
66 cx = current_trap_cx();
68 cx.x[10] = result as usize;
69 }
70 Trap::Exception(Exception::StoreFault)
71 | Trap::Exception(Exception::StorePageFault)
72 | Trap::Exception(Exception::InstructionFault)
73 | Trap::Exception(Exception::InstructionPageFault)
74 | Trap::Exception(Exception::LoadFault)
75 | Trap::Exception(Exception::LoadPageFault) => {
76 println!(
77 "[kernel] {:?} in application, bad addr = {:#x}, bad instruction = {:#x}, kernel killed it.",
78 scause.cause(),
79 stval,
80 current_trap_cx().sepc,
81 );
82 exit_current_and_run_next(-2);
84 }
85 Trap::Exception(Exception::IllegalInstruction) => {
86 println!("[kernel] IllegalInstruction in application, kernel killed it.");
87 exit_current_and_run_next(-3);
89 }
90 Trap::Interrupt(Interrupt::SupervisorTimer) => {
91 set_next_trigger();
92 suspend_current_and_run_next();
93 }
94 _ => {
95 panic!(
96 "Unsupported trap {:?}, stval = {:#x}!",
97 scause.cause(),
98 stval
99 );
100 }
101 }
102 trap_return();
103}
104
105#[unsafe(no_mangle)]
106pub fn trap_return() -> ! {
110 set_user_trap_entry();
111 let trap_cx_ptr = TRAP_CONTEXT;
112 let user_satp = current_user_token();
113 unsafe extern "C" {
114 unsafe fn __alltraps();
115 unsafe fn __restore();
116 }
117 let restore_va = __restore as usize - __alltraps as usize + TRAMPOLINE;
118 unsafe {
119 asm!(
120 "fence.i",
121 "jr {restore_va}",
122 restore_va = in(reg) restore_va,
123 in("a0") trap_cx_ptr,
124 in("a1") user_satp,
125 options(noreturn)
126 );
127 }
128}
129
130#[unsafe(no_mangle)]
131pub fn trap_from_kernel() -> ! {
134 panic!("a trap {:?} from kernel!", scause::read().cause());
135}
136
137pub use context::TrapContext;