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"));
27
28pub fn init() {
30 set_kernel_trap_entry();
31}
32
33fn set_kernel_trap_entry() {
34 unsafe {
35 stvec::write(stvec::Stvec::new(
36 linker_symbol_addr!(trap_from_kernel),
37 TrapMode::Direct,
38 ));
39 }
40}
41
42fn set_user_trap_entry() {
43 unsafe {
44 stvec::write(stvec::Stvec::new(TRAMPOLINE, TrapMode::Direct));
45 }
46}
47
48pub fn enable_timer_interrupt() {
50 unsafe {
51 sie::set_stimer();
52 }
53}
54
55#[unsafe(no_mangle)]
56pub fn trap_handler() -> ! {
58 set_kernel_trap_entry();
59 let cx = current_trap_cx();
60 let scause = scause::read();
61 let stval = stval::read();
62 let trap: Trap<Interrupt, Exception> = match scause.cause().try_into() {
63 Ok(trap) => trap,
64 Err(_) => panic!(
65 "Unsupported trap {:?}, stval = {:#x}!",
66 scause.cause(),
67 stval
68 ),
69 };
70 match trap {
71 Trap::Exception(Exception::UserEnvCall) => {
72 cx.sepc += 4;
73 cx.x[10] = syscall(cx.x[17], [cx.x[10], cx.x[11], cx.x[12]]) as usize;
74 }
75 Trap::Exception(Exception::StoreFault)
76 | Trap::Exception(Exception::StorePageFault)
77 | Trap::Exception(Exception::LoadFault)
78 | Trap::Exception(Exception::LoadPageFault) => {
79 println!(
80 "[kernel] PageFault in application, bad addr = {:#x}, bad instruction = {:#x}, kernel killed it.",
81 stval, cx.sepc
82 );
83 exit_current_and_run_next();
84 }
85 Trap::Exception(Exception::IllegalInstruction) => {
86 println!("[kernel] IllegalInstruction in application, kernel killed it.");
87 exit_current_and_run_next();
88 }
89 Trap::Interrupt(Interrupt::SupervisorTimer) => {
90 set_next_trigger();
91 suspend_current_and_run_next();
92 }
93 _ => {
94 panic!("Unsupported trap {:?}, stval = {:#x}!", trap, stval);
95 }
96 }
97 trap_return();
98}
99
100#[unsafe(no_mangle)]
101pub fn trap_return() -> ! {
105 set_user_trap_entry();
106 let trap_cx_ptr = TRAP_CONTEXT;
107 let user_satp = current_user_token();
108 unsafe extern "C" {
109 unsafe fn __alltraps();
110 unsafe fn __restore();
111 }
112 let restore_va = linker_symbol_addr!(__restore) - linker_symbol_addr!(__alltraps) + TRAMPOLINE;
113 unsafe {
114 asm!(
115 "fence.i",
116 "jr {restore_va}", restore_va = in(reg) restore_va,
118 in("a0") trap_cx_ptr, in("a1") user_satp, options(noreturn)
121 );
122 }
123}
124
125#[unsafe(no_mangle)]
126pub fn trap_from_kernel() -> ! {
129 panic!("a trap from kernel!");
130}
131
132pub use context::TrapContext;