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::interrupt::{Exception, Interrupt, Trap};
24use riscv::register::{mtvec::TrapMode, scause, sie, stval, stvec};
25
26global_asm!(include_str!("trap.S"));
27pub fn init() {
29 set_kernel_trap_entry();
30}
31
32fn set_kernel_trap_entry() {
33 unsafe {
34 stvec::write(stvec::Stvec::new(
35 linker_symbol_addr!(trap_from_kernel),
36 TrapMode::Direct,
37 ));
38 }
39}
40
41fn set_user_trap_entry() {
42 unsafe {
43 stvec::write(stvec::Stvec::new(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 let trap: Trap<Interrupt, Exception> = match scause.cause().try_into() {
60 Ok(trap) => trap,
61 Err(_) => panic!(
62 "Unsupported trap {:?}, stval = {:#x}!",
63 scause.cause(),
64 stval
65 ),
66 };
67 match trap {
68 Trap::Exception(Exception::UserEnvCall) => {
69 let mut cx = current_trap_cx();
71 cx.sepc += 4;
72 let result = syscall(cx.x[17], [cx.x[10], cx.x[11], cx.x[12]]);
74 cx = current_trap_cx();
76 cx.x[10] = result as usize;
77 }
78 Trap::Exception(Exception::StoreFault)
79 | Trap::Exception(Exception::StorePageFault)
80 | Trap::Exception(Exception::InstructionFault)
81 | Trap::Exception(Exception::InstructionPageFault)
82 | Trap::Exception(Exception::LoadFault)
83 | Trap::Exception(Exception::LoadPageFault) => {
84 println!(
85 "[kernel] {:?} in application, bad addr = {:#x}, bad instruction = {:#x}, kernel killed it.",
86 scause.cause(),
87 stval,
88 current_trap_cx().sepc,
89 );
90 exit_current_and_run_next(-2);
92 }
93 Trap::Exception(Exception::IllegalInstruction) => {
94 println!("[kernel] IllegalInstruction in application, kernel killed it.");
95 exit_current_and_run_next(-3);
97 }
98 Trap::Interrupt(Interrupt::SupervisorTimer) => {
99 set_next_trigger();
100 suspend_current_and_run_next();
101 }
102 _ => {
103 panic!(
104 "Unsupported trap {:?}, stval = {:#x}!",
105 scause.cause(),
106 stval
107 );
108 }
109 }
110 trap_return();
112}
113
114#[unsafe(no_mangle)]
115pub fn trap_return() -> ! {
119 set_user_trap_entry();
120 let trap_cx_ptr = TRAP_CONTEXT;
121 let user_satp = current_user_token();
122 unsafe extern "C" {
123 unsafe fn __alltraps();
124 unsafe fn __restore();
125 }
126 let restore_va = linker_symbol_addr!(__restore) - linker_symbol_addr!(__alltraps) + TRAMPOLINE;
127 unsafe {
128 asm!(
129 "fence.i",
130 "jr {restore_va}",
131 restore_va = in(reg) restore_va,
132 in("a0") trap_cx_ptr,
133 in("a1") user_satp,
134 options(noreturn)
135 );
136 }
137}
138
139#[unsafe(no_mangle)]
140pub fn trap_from_kernel() -> ! {
143 use riscv::register::sepc;
144 let scause = scause::read();
145 let stval = stval::read();
146 let trap: Trap<Interrupt, Exception> = match scause.cause().try_into() {
147 Ok(trap) => trap,
148 Err(_) => panic!(
149 "Unsupported trap from kernel: {:?}, stval = {:#x}, sepc = {:#x}!",
150 scause.cause(),
151 stval,
152 sepc::read()
153 ),
154 };
155 println!("stval = {:#x}, sepc = {:#x}", stval, sepc::read());
156 panic!("a trap {:?} from kernel!", trap);
157}
158
159pub use context::TrapContext;