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, 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 {
23 stvec::write(stvec::Stvec::new(
24 linker_symbol_addr!(trap_from_kernel),
25 TrapMode::Direct,
26 ));
27 }
28}
29
30fn set_user_trap_entry() {
31 unsafe {
32 stvec::write(stvec::Stvec::new(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 let trap: Trap<Interrupt, Exception> = match scause.cause().try_into() {
49 Ok(trap) => trap,
50 Err(_) => panic!(
51 "Unsupported trap {:?}, stval = {:#x}!",
52 scause.cause(),
53 stval
54 ),
55 };
56 match trap {
57 Trap::Exception(Exception::UserEnvCall) => {
58 let mut cx = current_trap_cx();
60 cx.sepc += 4;
61 let result = syscall(cx.x[17], [cx.x[10], cx.x[11], cx.x[12]]);
63 cx = current_trap_cx();
65 cx.x[10] = result as usize;
66 }
67 Trap::Exception(Exception::StoreFault)
68 | Trap::Exception(Exception::StorePageFault)
69 | Trap::Exception(Exception::InstructionFault)
70 | Trap::Exception(Exception::InstructionPageFault)
71 | Trap::Exception(Exception::LoadFault)
72 | Trap::Exception(Exception::LoadPageFault) => {
73 current_add_signal(SignalFlags::SIGSEGV);
82 }
83 Trap::Exception(Exception::IllegalInstruction) => {
84 current_add_signal(SignalFlags::SIGILL);
85 }
86 Trap::Interrupt(Interrupt::SupervisorTimer) => {
87 set_next_trigger();
88 check_timer();
89 suspend_current_and_run_next();
90 }
91 _ => {
92 panic!(
93 "Unsupported trap {:?}, stval = {:#x}!",
94 scause.cause(),
95 stval
96 );
97 }
98 }
99 if let Some((errno, msg)) = check_signals_of_current() {
101 println!("[kernel] {}", msg);
102 exit_current_and_run_next(errno);
103 }
104 trap_return();
105}
106
107#[unsafe(no_mangle)]
108pub fn trap_return() -> ! {
112 set_user_trap_entry();
113 let trap_cx_user_va = current_trap_cx_user_va();
114 let user_satp = current_user_token();
115 unsafe extern "C" {
116 unsafe fn __alltraps();
117 unsafe fn __restore();
118 }
119 let restore_va = linker_symbol_addr!(__restore) - linker_symbol_addr!(__alltraps) + TRAMPOLINE;
120 unsafe {
121 asm!(
122 "fence.i",
123 "jr {restore_va}",
124 restore_va = in(reg) restore_va,
125 in("a0") trap_cx_user_va,
126 in("a1") user_satp,
127 options(noreturn)
128 );
129 }
130}
131
132#[unsafe(no_mangle)]
133pub fn trap_from_kernel() -> ! {
136 use riscv::register::sepc;
137 let scause = scause::read();
138 let stval = stval::read();
139 let trap: Trap<Interrupt, Exception> = match scause.cause().try_into() {
140 Ok(trap) => trap,
141 Err(_) => panic!(
142 "Unsupported trap from kernel: {:?}, stval = {:#x}, sepc = {:#x}!",
143 scause.cause(),
144 stval,
145 sepc::read()
146 ),
147 };
148 println!("stval = {:#x}, sepc = {:#x}", stval, sepc::read());
149 panic!("a trap {:?} from kernel!", trap);
150}
151
152pub use context::TrapContext;