1use super::ExceptionLevel;
4use crate::system_register_access;
5use core::arch::asm;
6use tartan_bitfield::bitfield;
7use tartan_c_enum::c_enum;
8
9#[doc(hidden)]
11pub use paste::paste;
12
13
14#[macro_export]
44macro_rules! aarch64_exception_vector_table {
45 [$table:ident, $handler:path] => {
46 extern "C" {
47 #[no_mangle]
48 static $table: $crate::aarch64::interrupt::VectorTable;
49 }
50
51 core::arch::global_asm!(concat!(
52 "
53 //
54 // Exceptions from current level using SP_EL0 (thread mode)
55
56 .balign 0x800
57 ", stringify!($table), ":
58 // Synchronous exception
59 stp lr, fp, [sp, #-16]!
60 bl ", stringify!($table), "_save
61 bl ", stringify!($table), "_sync_exception_from_thread
62 bl ", stringify!($table), "_restore
63 ldp lr, fp, [sp], #16
64 eret
65
66 .balign 0x80
67 // Interrupt
68 stp lr, fp, [sp, #-16]!
69 bl ", stringify!($table), "_save
70 bl ", stringify!($table), "_interrupt_from_thread
71 bl ", stringify!($table), "_restore
72 ldp lr, fp, [sp], #16
73 eret
74
75 .balign 0x80
76 // Fast interrupt
77 stp lr, fp, [sp, #-16]!
78 bl ", stringify!($table), "_save
79 bl ", stringify!($table), "_fast_interrupt_from_thread
80 bl ", stringify!($table), "_restore
81 ldp lr, fp, [sp], #16
82 eret
83
84 .balign 0x80
85 // System error
86 stp lr, fp, [sp, #-16]!
87 bl ", stringify!($table), "_save
88 bl ", stringify!($table), "_system_error_from_thread
89 bl ", stringify!($table), "_restore
90 ldp lr, fp, [sp], #16
91 eret
92
93 //
94 // Exceptions from current level using current-level SP (handler mode)
95
96 .balign 0x80
97 // Synchronous exception
98 stp lr, fp, [sp, #-16]!
99 bl ", stringify!($table), "_save
100 bl ", stringify!($table), "_sync_exception_from_handler
101 bl ", stringify!($table), "_restore
102 ldp lr, fp, [sp], #16
103 eret
104
105 .balign 0x80
106 // Interrupt
107 stp lr, fp, [sp, #-16]!
108 bl ", stringify!($table), "_save
109 bl ", stringify!($table), "_interrupt_from_handler
110 bl ", stringify!($table), "_restore
111 ldp lr, fp, [sp], #16
112 eret
113
114 .balign 0x80
115 // Fast interrupt
116 stp lr, fp, [sp, #-16]!
117 bl ", stringify!($table), "_save
118 bl ", stringify!($table), "_fast_interrupt_from_handler
119 bl ", stringify!($table), "_restore
120 ldp lr, fp, [sp], #16
121 eret
122
123 .balign 0x80
124 // System error
125 stp lr, fp, [sp, #-16]!
126 bl ", stringify!($table), "_save
127 bl ", stringify!($table), "_system_error_from_handler
128 bl ", stringify!($table), "_restore
129 ldp lr, fp, [sp], #16
130 eret
131
132 //
133 // Exceptions from lower level in 64-bit mode
134
135 .balign 0x80
136 // Synchronous exception
137 stp lr, fp, [sp, #-16]!
138 bl ", stringify!($table), "_save
139 bl ", stringify!($table), "_sync_exception_from_lower
140 bl ", stringify!($table), "_restore
141 ldp lr, fp, [sp], #16
142 eret
143
144 .balign 0x80
145 // Interrupt
146 stp lr, fp, [sp, #-16]!
147 bl ", stringify!($table), "_save
148 bl ", stringify!($table), "_interrupt_from_lower
149 bl ", stringify!($table), "_restore
150 ldp lr, fp, [sp], #16
151 eret
152
153 .balign 0x80
154 // Fast interrupt
155 stp lr, fp, [sp, #-16]!
156 bl ", stringify!($table), "_save
157 bl ", stringify!($table), "_fast_interrupt_from_lower
158 bl ", stringify!($table), "_restore
159 ldp lr, fp, [sp], #16
160 eret
161
162 .balign 0x80
163 // System error
164 stp lr, fp, [sp, #-16]!
165 bl ", stringify!($table), "_save
166 bl ", stringify!($table), "_system_error_from_lower
167 bl ", stringify!($table), "_restore
168 ldp lr, fp, [sp], #16
169 eret
170
171 //
172 // Exceptions from lower level in 32-bit mode
173
174 .balign 0x80
175 // Synchronous exception
176 stp lr, fp, [sp, #-16]!
177 bl ", stringify!($table), "_save
178 bl ", stringify!($table), "_sync_exception_from_lower_32bit
179 bl ", stringify!($table), "_restore
180 ldp lr, fp, [sp], #16
181 eret
182
183 .balign 0x80
184 // Interrupt
185 stp lr, fp, [sp, #-16]!
186 bl ", stringify!($table), "_save
187 bl ", stringify!($table), "_interrupt_from_lower_32bit
188 bl ", stringify!($table), "_restore
189 ldp lr, fp, [sp], #16
190 eret
191
192 .balign 0x80
193 // Fast interrupt
194 stp lr, fp, [sp, #-16]!
195 bl ", stringify!($table), "_save
196 bl ", stringify!($table), "_fast_interrupt_from_lower_32bit
197 bl ", stringify!($table), "_restore
198 ldp lr, fp, [sp], #16
199 eret
200
201 .balign 0x80
202 // System error
203 stp lr, fp, [sp, #-16]!
204 bl ", stringify!($table), "_save
205 bl ", stringify!($table), "_system_error_from_lower_32bit
206 bl ", stringify!($table), "_restore
207 ldp lr, fp, [sp], #16
208 eret
209
210
211 ", stringify!($table), "_save:
212 stp x0, x1, [sp, #-16]!
213 stp x2, x3, [sp, #-16]!
214 stp x4, x5, [sp, #-16]!
215 stp x6, x7, [sp, #-16]!
216 stp x8, x9, [sp, #-16]!
217 stp x10, x11, [sp, #-16]!
218 stp x12, x13, [sp, #-16]!
219 stp x14, x15, [sp, #-16]!
220
221 ", stringify!($table), "_restore:
222 ldp x14, x15, [sp], #16
223 ldp x12, x13, [sp], #16
224 ldp x10, x11, [sp], #16
225 ldp x8, x9, [sp], #16
226 ldp x6, x7, [sp], #16
227 ldp x4, x5, [sp], #16
228 ldp x2, x3, [sp], #16
229 ldp x0, x1, [sp], #16
230 "
231 ));
232
233 $crate::aarch64::interrupt::paste! {
234 #[no_mangle]
235 fn [< $table _sync_exception_from_thread >]() {
236 $handler(
237 $crate::aarch64::interrupt::Kind::Synchronous,
238 $crate::aarch64::interrupt::Source::CurrentLevelThread,
239 )
240 }
241
242 #[no_mangle]
243 fn [< $table _interrupt_from_thread >]() {
244 $handler(
245 $crate::aarch64::interrupt::Kind::Interrupt,
246 $crate::aarch64::interrupt::Source::CurrentLevelThread,
247 )
248 }
249
250 #[no_mangle]
251 fn [< $table _fast_interrupt_from_thread >]() {
252 $handler(
253 $crate::aarch64::interrupt::Kind::FastInterrupt,
254 $crate::aarch64::interrupt::Source::CurrentLevelThread,
255 )
256 }
257
258 #[no_mangle]
259 fn [< $table _system_error_from_thread >]() {
260 $handler(
261 $crate::aarch64::interrupt::Kind::SystemError,
262 $crate::aarch64::interrupt::Source::CurrentLevelThread,
263 )
264 }
265
266 #[no_mangle]
267 fn [< $table _sync_exception_from_handler >]() {
268 $handler(
269 $crate::aarch64::interrupt::Kind::Synchronous,
270 $crate::aarch64::interrupt::Source::CurrentLevelHandler,
271 )
272 }
273
274 #[no_mangle]
275 fn [< $table _interrupt_from_handler >]() {
276 $handler(
277 $crate::aarch64::interrupt::Kind::Interrupt,
278 $crate::aarch64::interrupt::Source::CurrentLevelHandler,
279 )
280 }
281
282 #[no_mangle]
283 fn [< $table _fast_interrupt_from_handler >]() {
284 $handler(
285 $crate::aarch64::interrupt::Kind::FastInterrupt,
286 $crate::aarch64::interrupt::Source::CurrentLevelHandler,
287 )
288 }
289
290 #[no_mangle]
291 fn [< $table _system_error_from_handler >]() {
292 $handler(
293 $crate::aarch64::interrupt::Kind::SystemError,
294 $crate::aarch64::interrupt::Source::CurrentLevelHandler,
295 )
296 }
297
298 #[no_mangle]
299 fn [< $table _sync_exception_from_lower >]() {
300 $handler(
301 $crate::aarch64::interrupt::Kind::Synchronous,
302 $crate::aarch64::interrupt::Source::LowerLevel,
303 )
304 }
305
306 #[no_mangle]
307 fn [< $table _interrupt_from_lower >]() {
308 $handler(
309 $crate::aarch64::interrupt::Kind::Interrupt,
310 $crate::aarch64::interrupt::Source::LowerLevel,
311 )
312 }
313
314 #[no_mangle]
315 fn [< $table _fast_interrupt_from_lower >]() {
316 $handler(
317 $crate::aarch64::interrupt::Kind::FastInterrupt,
318 $crate::aarch64::interrupt::Source::LowerLevel,
319 )
320 }
321
322 #[no_mangle]
323 fn [< $table _system_error_from_lower >]() {
324 $handler(
325 $crate::aarch64::interrupt::Kind::SystemError,
326 $crate::aarch64::interrupt::Source::LowerLevel,
327 )
328 }
329
330 #[no_mangle]
331 fn [< $table _sync_exception_from_lower_32bit >]() {
332 $handler(
333 $crate::aarch64::interrupt::Kind::Synchronous,
334 $crate::aarch64::interrupt::Source::LowerLevel32Bit,
335 )
336 }
337
338 #[no_mangle]
339 fn [< $table _interrupt_from_lower_32bit >]() {
340 $handler(
341 $crate::aarch64::interrupt::Kind::Interrupt,
342 $crate::aarch64::interrupt::Source::LowerLevel32Bit,
343 )
344 }
345
346 #[no_mangle]
347 fn [< $table _fast_interrupt_from_lower_32bit >]() {
348 $handler(
349 $crate::aarch64::interrupt::Kind::FastInterrupt,
350 $crate::aarch64::interrupt::Source::LowerLevel32Bit,
351 )
352 }
353
354 #[no_mangle]
355 fn [< $table _system_error_from_lower_32bit >]() {
356 $handler(
357 $crate::aarch64::interrupt::Kind::SystemError,
358 $crate::aarch64::interrupt::Source::LowerLevel32Bit,
359 )
360 }
361 }
362 };
363}
364
365#[repr(u8)]
367#[derive(Debug, Clone, Copy, PartialEq, Eq)]
368pub enum Kind {
369 Synchronous,
371 Interrupt,
373 FastInterrupt,
375 SystemError,
377}
378
379#[repr(u8)]
381#[derive(Debug, Clone, Copy, PartialEq, Eq)]
382pub enum Source {
383 CurrentLevelThread,
385 CurrentLevelHandler,
387 LowerLevel,
389 LowerLevel32Bit,
391}
392
393
394#[repr(align(0x80))]
401#[allow(dead_code)]
402pub struct VectorEntry([u8; 0x80]);
403
404
405#[repr(align(0x800))]
408#[allow(dead_code)]
409pub struct VectorTable([VectorEntry; 16]);
410
411
412pub enum VectorBaseAddressRegister {}
415
416impl VectorBaseAddressRegister {
417 pub fn get(level: ExceptionLevel) -> *const VectorTable {
422 let mut value: *const VectorTable;
423 unsafe {
424 match level {
425 ExceptionLevel::Zero => panic!("This register does not exist for EL0"),
426 ExceptionLevel::One => asm!("mrs {}, vbar_el1", out(reg) value),
427 ExceptionLevel::Two => asm!("mrs {}, vbar_el2", out(reg) value),
428 ExceptionLevel::Three => asm!("mrs {}, vbar_el3", out(reg) value),
429 }
430 }
431 value
432 }
433
434 pub fn set(level: ExceptionLevel, value: *const VectorTable) {
438 unsafe {
439 match level {
440 ExceptionLevel::Zero => panic!("This register does not exist for EL0"),
441 ExceptionLevel::One => asm!("msr vbar_el1, {}", in(reg) value),
442 ExceptionLevel::Two => asm!("msr vbar_el2, {}", in(reg) value),
443 ExceptionLevel::Three => asm!("msr vbar_el3, {}", in(reg) value),
444 }
445 }
446 }
447}
448
449
450bitfield! {
451 pub struct MaskRegister(u64) {
453 [6] pub fast_interrupts_masked,
455 [7] pub interrupts_masked,
457 [8] pub system_error_masked,
459 [9] pub debug_masked,
462 }
463}
464
465system_register_access!(MaskRegister, "DAIF");
466
467
468bitfield! {
469 pub struct SyndromeRegister(u64) {
472 [26..32] pub class: u8 as Class,
474 [25] pub length_32bit,
478 [ 0..25] pub class_data: u32,
481 }
482}
483
484impl SyndromeRegister {
485 pub fn get(level: ExceptionLevel) -> Self {
490 let mut value = Self(0);
491 unsafe {
492 match level {
493 ExceptionLevel::Zero => panic!("This register does not exist for EL0"),
494 ExceptionLevel::One => asm!("mrs {}, esr_el1", out(reg) value.0),
495 ExceptionLevel::Two => asm!("mrs {}, esr_el2", out(reg) value.0),
496 ExceptionLevel::Three => asm!("mrs {}, esr_el3", out(reg) value.0),
497 }
498 }
499 value
500 }
501
502 pub fn set(level: ExceptionLevel, value: Self) {
504 unsafe {
505 match level {
506 ExceptionLevel::Zero => panic!("This register does not exist for EL0"),
507 ExceptionLevel::One => asm!("msr esr_el1, {}", in(reg) value.0),
508 ExceptionLevel::Two => asm!("msr esr_el2, {}", in(reg) value.0),
509 ExceptionLevel::Three => asm!("msr esr_el3, {}", in(reg) value.0),
510 }
511 }
512 }
513}
514
515
516c_enum! {
517 pub enum Class(u8) {
523 Unknown = 0b00_0000,
526 Wait = 0b00_0001,
528 FPUAccess = 0b00_0111,
530 IllegalState = 0b00_1110,
532 SupervisorCall = 0b01_0101,
534 SystemInstruction = 0b01_1000,
536 VectorAccess = 0b01_1001,
538 PointerAuthFailure = 0b01_1100,
540 InstructionAbortFromLower = 0b10_0000,
542 InstructionAbortFromCurrent = 0b10_0001,
544 PCAlignment = 0b10_0010,
546 DataAbortFromLower = 0b10_0100,
548 DataAbortFromCurrent = 0b10_0101,
550 SPAlignment = 0b10_0110,
552 FloatException = 0b10_1100,
554 SystemError = 0b10_1111,
556 BreakpointFromLower = 0b11_0000,
558 BreakpointFromCurrent = 0b11_0001,
560 StepFromLower = 0b11_0010,
562 StepFromCurrent = 0b11_0011,
564 WatchpointFromLower = 0b11_0100,
566 WatchpointFromCurrent = 0b11_0101,
568 BreakpointInstruction = 0b11_1100,
570 }
571}