kernel/arch/riscv64/trap/
exception.rs1use core::arch::asm;
2use core::panic;
3
4use crate::abi::syscall_dispatcher;
5use crate::arch::trap::print_traplog;
6use crate::arch::{Trapframe, get_cpu};
7use crate::println;
8use crate::sched::scheduler::get_scheduler;
9use crate::task::mytask;
10
11fn log_fatal_page_fault_context(
12 trapframe: &Trapframe,
13 cause: usize,
14 vaddr: usize,
15 task_id: usize,
16 task_name: &str,
17 asid: u16,
18) {
19 use crate::arch::vm::{get_root_pagetable_ptr, is_asid_used};
20
21 let cpu_id = get_cpu().get_cpuid();
22 let epc = trapframe.epc as usize;
23 let ra = trapframe.regs.reg[1] as usize;
25 let sp = trapframe.regs.reg[2] as usize;
26 let fp = trapframe.regs.reg[8] as usize;
27
28 let asid_used = is_asid_used(asid);
29 let root_pt = get_root_pagetable_ptr(asid).unwrap_or(core::ptr::null_mut());
30
31 println!(
32 "[Trap] fatal page fault map failed: cpu={} cause={} task_id={} name={} asid={} asid_used={} root_pt={:p}",
33 cpu_id, cause, task_id, task_name, asid, asid_used, root_pt
34 );
35 println!(
36 "[Trap] epc={:#x} vaddr={:#x} ra={:#x} sp={:#x} fp={:#x}",
37 epc, vaddr, ra, sp, fp
38 );
39}
40
41pub fn arch_exception_handler(trapframe: &mut Trapframe, cause: usize) {
42 match cause {
43 2 => {
45 let task = get_scheduler()
46 .get_current_task(get_cpu().get_cpuid())
47 .unwrap();
48
49 let user_fpu_allowed = crate::arch::user_fpu_enabled();
50 let user_vec_allowed = crate::arch::user_vector_enabled();
51
52 let mut inst: usize;
54 let sstatus: usize;
55 unsafe {
56 asm!(
57 "csrr {0}, stval",
58 "csrr {1}, sstatus",
59 out(reg) inst,
60 out(reg) sstatus,
61 );
62 }
63
64 if inst == 0 {
67 if let Some(paddr) = task.vm_manager.translate_vaddr(trapframe.epc as usize) {
68 inst = crate::arch::instruction::Instruction::fetch(paddr).raw as usize;
69 }
70 }
71
72 let fs_off = (sstatus & 0x6000) == 0;
74 let vs_off = (sstatus & 0x600) == 0;
75
76 let raw32 = inst as u32;
77 let is_32bit = (raw32 & 0b11) == 0b11;
78
79 let is_vector_insn = if is_32bit {
81 let opcode = raw32 & 0x7f;
82 if opcode == 0x57 {
83 true
84 } else if opcode == 0x73 {
85 let csr = (raw32 >> 20) & 0xfff;
87 (csr >= 0x008 && csr <= 0x00a) || (csr >= 0xc20 && csr <= 0xc22)
89 } else {
90 false
91 }
92 } else {
93 false
94 };
95
96 let is_fpu_insn = if is_32bit {
97 let opcode = raw32 & 0x7f;
98 let funct3 = (raw32 >> 12) & 0x7;
99 match opcode {
100 0x53 | 0x43 | 0x47 | 0x4b | 0x4f => true,
102 0x07 | 0x27 => matches!(funct3, 0b010 | 0b011 | 0b100),
104 _ => false,
105 }
106 } else {
107 let raw16 = (raw32 & 0xffff) as u16;
109 let quadrant = raw16 & 0b11;
110 let funct3 = (raw16 >> 13) & 0x7;
111
112 (quadrant == 0b00 || quadrant == 0b10) && matches!(funct3, 0b001 | 0b101)
114 };
115
116 #[cfg(feature = "user-vector")]
119 if user_vec_allowed && vs_off && is_vector_insn {
120 task.vcpu.lock().vector_used = true;
121 crate::arch::riscv64::fpu::enable_vector();
122 if task.vcpu.lock().vector.is_none() {
123 task.vcpu.lock().vector = Some(alloc::boxed::Box::new(
124 crate::arch::riscv64::fpu::VectorContext::new(),
125 ));
126 }
127 unsafe { task.vcpu.lock().vector.as_ref().unwrap().restore() };
128 crate::arch::riscv64::fpu::mark_vector_clean();
129 return;
130 }
131
132 #[cfg(feature = "user-fpu")]
133 if user_fpu_allowed && fs_off && is_fpu_insn {
134 task.vcpu.lock().fpu_used = true;
135 crate::arch::riscv64::fpu::enable_fpu();
136 unsafe { task.vcpu.lock().fpu.restore() };
137 crate::arch::riscv64::fpu::mark_fpu_clean();
138 return;
139 }
140
141 #[cfg(feature = "user-fpu")]
144 if user_fpu_allowed && fs_off {
145 task.vcpu.lock().fpu_used = true;
146 crate::arch::riscv64::fpu::enable_fpu();
147 unsafe { task.vcpu.lock().fpu.restore() };
148 crate::arch::riscv64::fpu::mark_fpu_clean();
149 return;
150 }
151
152 #[cfg(feature = "user-vector")]
153 if user_vec_allowed && vs_off {
154 task.vcpu.lock().vector_used = true;
155 crate::arch::riscv64::fpu::enable_vector();
156 if task.vcpu.lock().vector.is_none() {
157 task.vcpu.lock().vector = Some(alloc::boxed::Box::new(
158 crate::arch::riscv64::fpu::VectorContext::new(),
159 ));
160 }
161 unsafe { task.vcpu.lock().vector.as_ref().unwrap().restore() };
162 crate::arch::riscv64::fpu::mark_vector_clean();
163 return;
164 }
165
166 print_traplog(trapframe);
167 panic!(
168 "Unhandled illegal instruction: inst={:#x} epc={:#x}",
169 raw32, trapframe.epc
170 );
171 }
172 8 => {
174 match syscall_dispatcher(trapframe) {
176 Ok(ret) => {
177 trapframe.set_return_value(ret);
178 }
179 Err(msg) => {
180 println!("Syscall error: {}", msg);
182 trapframe.set_return_value(usize::MAX); trapframe.increment_pc_next(mytask().unwrap());
184 }
185 }
186 }
187 12 => {
189 let mut vaddr = trapframe.epc as usize;
190 let task = get_scheduler()
191 .get_current_task(get_cpu().get_cpuid())
192 .unwrap();
193 use crate::object::capability::memory_mapping::{AccessKind, AccessOp};
194 loop {
195 let access = AccessKind {
196 op: AccessOp::Instruction,
197 vaddr,
198 size: None,
199 };
200 match task.vm_manager.lazy_map_page_with(access) {
201 Ok(_) => (),
202 Err(_) => {
203 print_traplog(trapframe);
204 log_fatal_page_fault_context(
205 trapframe,
206 cause,
207 vaddr,
208 task.get_id(),
209 &task.name.read(),
210 task.vm_manager.get_asid(),
211 );
212 panic!(
213 "Failed to map page for instruction page fault at vaddr: {:#x}",
214 vaddr
215 );
216 }
217 }
218
219 if vaddr & 0b11 == 0 {
220 break;
222 }
223 vaddr = (vaddr + 4) & !0b11; }
225 }
226 13 | 15 => {
228 let mut vaddr;
229 unsafe {
230 asm!("csrr {}, stval", out(reg) vaddr);
231 }
232 let task = get_scheduler()
233 .get_current_task(get_cpu().get_cpuid())
234 .unwrap();
235 use crate::object::capability::memory_mapping::{AccessKind, AccessOp};
236 loop {
237 let op = if cause == 13 {
238 AccessOp::Load
239 } else {
240 AccessOp::Store
241 };
242 let access = AccessKind {
243 op,
244 vaddr,
245 size: None,
246 };
247 match task.vm_manager.lazy_map_page_with(access) {
248 Ok(_) => (),
249 Err(_) => {
250 print_traplog(trapframe);
251 log_fatal_page_fault_context(
252 trapframe,
253 cause,
254 vaddr,
255 task.get_id(),
256 &task.name.read(),
257 task.vm_manager.get_asid(),
258 );
259 panic!(
260 "Failed to map page for load/store page fault at vaddr: {:#x}",
261 vaddr
262 );
263 }
264 }
265
266 if vaddr & 0b11 == 0 {
267 break;
269 }
270 vaddr = (vaddr + 4) & !0b11; }
272 }
273 _ => {
274 print_traplog(trapframe);
275 panic!("Unhandled exception: {}", cause);
276 }
277 }
278}