islet_rmm/exception/
trap.rs1mod frame;
2pub mod syndrome;
3
4use self::frame::TrapFrame;
5use self::syndrome::Fault;
6use self::syndrome::Syndrome;
7use super::lower::synchronous;
8use crate::cpu;
9use crate::event::realmexit::{ExitSyncType, RecExitReason};
10use crate::rec::simd;
11use crate::rec::Rec;
12
13use aarch64_cpu::registers::*;
14
15#[repr(u16)]
16#[derive(Debug, Copy, Clone)]
17pub enum Source {
18 CurrentSPEL0,
19 CurrentSPELx,
20 LowerAArch64,
21 LowerAArch32,
22}
23
24#[repr(u16)]
25#[derive(Debug, Copy, Clone)]
26pub enum Kind {
27 Synchronous,
28 Irq,
29 Fiq,
30 SError,
31}
32
33#[repr(C)]
34#[derive(Debug, Copy, Clone)]
35pub struct Info {
36 source: Source,
37 kind: Kind,
38}
39
40#[no_mangle]
47#[allow(unused_variables)]
48pub extern "C" fn handle_exception(info: Info, esr: u32, tf: &mut TrapFrame) {
49 match info.kind {
50 Kind::Synchronous => match Syndrome::from(esr) {
51 Syndrome::Brk(b) => {
52 debug!("brk #{}", b);
53 debug!("{:?}\nESR: {:X}\n{:#X?}", info, esr, tf);
54 tf.elr += 4; }
56 Syndrome::PCAlignmentFault => {
57 debug!("PCAlignmentFault");
58 }
59 Syndrome::DataAbort(fault) => {
60 let far = FAR_EL2.get();
61 debug!("Data Abort (higher), far:{:X}", far);
62 match fault {
63 Fault::AddressSize { level } => {
64 debug!("address size, level:{}", level);
65 }
66 Fault::Translation { level } => {
67 debug!("translation, level:{}, esr:{:X}", level, esr);
68 }
69 Fault::AccessFlag { level } => {
70 debug!("access flag, level:{}", level);
71 }
72 Fault::Permission { level } => {
73 debug!("permission, level:{}", level);
74 }
75 Fault::Alignment => {
76 debug!("alignment");
77 }
78 Fault::TLBConflict => {
79 debug!("tlb conflict");
80 }
81 Fault::Other(_x) => {
82 debug!("other");
83 }
84 }
85 }
86 Syndrome::InstructionAbort(v) => {
87 debug!("Instruction Abort (higher)");
88 }
89 Syndrome::HVC => {
90 debug!("HVC");
91 }
92 Syndrome::SMC => {
93 debug!("SMC");
94 }
95 Syndrome::SysRegInst => {
96 debug!("SysRegInst");
97 }
98 Syndrome::WFX => {
99 debug!("WFX");
100 }
101 Syndrome::FPU | Syndrome::SVE | Syndrome::SME => {
102 debug!("ELR_EL2:{:x}", ELR_EL2.get());
104 panic!("RMM is using SIMD instruction");
105 }
106 Syndrome::Other(v) => {
107 debug!("Other");
108 }
109 undefined => {
110 panic!(
111 "{:?} and esr {:x}, TrapFrame: {:?} on cpu::id {:?}",
112 info,
113 esr,
114 tf,
115 cpu::id()
116 );
117 }
118 },
119 _ => {
120 panic!(
121 "Unknown exception! Info={:?}, ESR={:x} on CPU {:?}",
122 info,
123 esr,
124 cpu::id()
125 );
126 }
127 }
128}
129
130pub const RET_TO_REC: u64 = 0;
131pub const RET_TO_RMM: u64 = 1;
132#[no_mangle]
143#[allow(unused_variables)]
144pub extern "C" fn handle_lower_exception(
145 info: Info,
146 esr: u32,
147 rec: &mut Rec<'_>,
148 tf: &mut TrapFrame,
149) -> u64 {
150 match info.kind {
151 Kind::Synchronous => match Syndrome::from(esr) {
153 Syndrome::HVC => {
154 debug!("Synchronous: HVC: {:#X}", rec.context.gp_regs[0]);
155
156 SPSR_EL1.set(rec.context.spsr_el2);
158 ELR_EL1.set(rec.context.elr_el2);
159 ESR_EL1.write(ESR_EL1::EC::Unknown + ESR_EL1::IL::SET);
160
161 let vbar = rec.context.sys_regs.vbar;
163 const SPSR_EL2_MODE_EL1H_OFFSET: u64 = 0x200;
164 rec.context.elr_el2 = vbar + SPSR_EL2_MODE_EL1H_OFFSET;
165
166 tf.regs[0] = RecExitReason::Sync(ExitSyncType::Undefined).into();
167 tf.regs[1] = esr as u64;
168 tf.regs[2] = 0;
169 tf.regs[3] = FAR_EL2.get();
170 RET_TO_REC
171 }
172 Syndrome::SMC => {
173 tf.regs[0] = RecExitReason::Sync(ExitSyncType::RSI).into();
174 tf.regs[1] = rec.context.gp_regs[0]; advance_pc(rec);
176 RET_TO_RMM
177 }
178 Syndrome::InstructionAbort(_) | Syndrome::DataAbort(_) => {
179 debug!("Synchronous: InstructionAbort | DataAbort");
180 if let Syndrome::InstructionAbort(_) = Syndrome::from(esr) {
181 tf.regs[0] = RecExitReason::Sync(ExitSyncType::InstAbort).into()
182 } else {
183 tf.regs[0] = RecExitReason::Sync(ExitSyncType::DataAbort).into();
184 }
185 tf.regs[1] = esr as u64;
186 tf.regs[2] = HPFAR_EL2.get();
187 tf.regs[3] = FAR_EL2.get();
188 let fipa = HPFAR_EL2.read(HPFAR_EL2::FIPA) << 8;
189 debug!("fipa: {:X}", fipa);
190 debug!("esr_el2: {:X}", esr);
191 RET_TO_RMM
192 }
193 Syndrome::SysRegInst => {
194 debug!("Synchronous: MRS, MSR System Register Instruction");
195 let ret = synchronous::sys_reg::handle(rec, esr as u64);
196 advance_pc(rec);
197 if ret == RET_TO_RMM {
198 tf.regs[0] = RecExitReason::Sync(ExitSyncType::Undefined).into();
199 tf.regs[1] = esr as u64;
200 tf.regs[2] = 0;
201 }
202 ret
203 }
204 Syndrome::WFX => {
205 debug!("Synchronous: WFx");
206 tf.regs[0] = RecExitReason::Sync(ExitSyncType::WFx).into();
207 tf.regs[1] = esr as u64;
208 advance_pc(rec);
209 RET_TO_RMM
210 }
211 Syndrome::FPU | Syndrome::SVE | Syndrome::SME => {
212 debug!("Synchronous: SIMD");
213 let abort: bool = match Syndrome::from(esr) {
214 Syndrome::SVE => !rec.context.simd.cfg.sve_en,
215 Syndrome::SME => !rec.context.simd.cfg.sve_en,
219 _ => false,
220 };
221 if abort {
222 SPSR_EL1.set(rec.context.spsr_el2);
224 ELR_EL1.set(rec.context.elr_el2);
225 ESR_EL1.write(ESR_EL1::EC::Unknown + ESR_EL1::IL::SET);
226
227 let vbar = rec.context.sys_regs.vbar;
229 const SPSR_EL2_MODE_EL1H_OFFSET: u64 = 0x200;
230 rec.context.elr_el2 = vbar + SPSR_EL2_MODE_EL1H_OFFSET;
231
232 tf.regs[0] = RecExitReason::Sync(ExitSyncType::Undefined).into();
233 tf.regs[1] = esr as u64;
234 tf.regs[2] = 0;
235 tf.regs[3] = FAR_EL2.get();
236 debug!("Unsupported feature access. Inject abort");
237 return RET_TO_REC;
238 }
239 simd::restore_state_lazy(rec);
242 rec.context.simd.is_used = true;
243 RET_TO_REC
244 }
245 undefined => {
246 debug!("Synchronous: Other");
247 tf.regs[0] = RecExitReason::Sync(ExitSyncType::Undefined).into();
248 tf.regs[1] = esr as u64;
249 RET_TO_RMM
250 }
251 },
252 Kind::Irq => {
253 debug!("IRQ");
254 tf.regs[0] = RecExitReason::IRQ.into();
255 tf.regs[1] = 0;
257 RET_TO_RMM
258 }
259 Kind::SError => {
260 debug!("SError");
261 tf.regs[0] = RecExitReason::SError.into();
262 tf.regs[1] = esr as u64;
263 RET_TO_RMM
264 }
265 _ => {
266 error!(
267 "Unknown exception! Info={:?}, ESR={:x} on CPU {:?}",
268 info,
269 esr,
270 cpu::id()
271 );
272 RET_TO_REC
273 }
274 }
275}
276
277#[inline(always)]
278fn advance_pc(rec: &mut Rec<'_>) {
279 rec.context.elr_el2 += 4;
280}