Skip to content

Commit af3fce8

Browse files
Fix the undef handler.
It was looking at CPSR's Thumb bit, which tells you if the *handler* is in thumb mode, not the code that threw the fault. Change the test to validate the address of the failing function, to verify that we've got this right. Also fixes the issue of _asm_default_undefined_handler damaging r4. You have to save all the state first, then you can touch registers.
1 parent d20623c commit af3fce8

18 files changed

+289
-109
lines changed

cortex-a-rt/src/lib.rs

+33-25
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@
9191
//!
9292
//! ```rust
9393
//! #[unsafe(no_mangle)]
94-
//! extern "C" fn _undefined_handler(faulting_instruction: u32);
94+
//! extern "C" fn _undefined_handler(addr: usize);
9595
//! ```
9696
//!
9797
//! * `_abort_handler` - an `extern "C"` function to call when a Data Abort Exception
@@ -103,7 +103,7 @@
103103
//!
104104
//! ```rust
105105
//! #[unsafe(no_mangle)]
106-
//! extern "C" fn _abort_handler(faulting_instruction: u32);
106+
//! extern "C" fn _abort_handler(addr: usize);
107107
//! ```
108108
//!
109109
//! * `_prefetch_handler` - an `extern "C"` function to call when a Prefetch Abort Exception
@@ -115,7 +115,7 @@
115115
//!
116116
//! ```rust
117117
//! #[unsafe(no_mangle)]
118-
//! extern "C" fn _prefetch_handler(faulting_instruction: u32);
118+
//! extern "C" fn _prefetch_handler(addr: usize);
119119
//! ```
120120
//!
121121
//! ### ASM functions
@@ -130,7 +130,7 @@
130130
//! * `_asm_undefined_handler` - a naked function to call when an Undefined
131131
//! Exception occurs. Our linker script PROVIDEs a default function at
132132
//! `_asm_default_undefined_handler` but you can override it.
133-
//! * `_asm_prefetch_handler` - a naked function to call when an Prefetch
133+
//! * `_asm_prefetch_handler` - a naked function to call when a Prefetch
134134
//! Exception occurs. Our linker script PROVIDEs a default function at
135135
//! `_asm_default_prefetch_handler` but you can override it. The provided default
136136
//! handler will perform an exception return to the faulting address.
@@ -381,7 +381,7 @@ core::arch::global_asm!(
381381
382382
// Called from the vector table when we have an software interrupt.
383383
// Saves state and calls a C-compatible handler like
384-
// `extern "C" fn svc_handler(svc: u32, context: *const u32);`
384+
// `extern "C" fn svc_handler(svc: u32);`
385385
.global _asm_svc_handler
386386
.type _asm_svc_handler, %function
387387
_asm_svc_handler:
@@ -426,44 +426,52 @@ core::arch::global_asm!(
426426
427427
// Called from the vector table when we have an undefined exception.
428428
// Saves state and calls a C-compatible handler like
429-
// `extern "C" fn _undefined_handler();`
429+
// `extern "C" fn _undefined_handler(addr: usize);`
430430
.global _asm_default_undefined_handler
431431
.type _asm_default_undefined_handler, %function
432432
_asm_default_undefined_handler:
433-
// First adjust LR for two purposes: Passing the faulting instruction to the C handler,
434-
// and to return to the failing instruction after the C handler returns.
435-
// Load processor status
436-
mrs r4, cpsr
437-
// Occurred in Thumb state?
438-
tst r4, {t_bit}
439-
// If not in Thumb mode, branch to not_thumb
440-
beq not_thumb
441-
subs lr, lr, #2
442-
b done
443-
not_thumb:
444-
// Subtract 4 from LR (ARM mode)
445-
subs lr, lr, #4
446-
done:
447433
// state save from compiled code
448434
srsfd sp!, {und_mode}
435+
// to work out what mode we're in, we need R0
436+
push {{r0}}
437+
// First adjust LR for two purposes: Passing the faulting instruction to the C handler,
438+
// and to return to the failing instruction after the C handler returns.
439+
// Load processor status for the calling code
440+
mrs r0, spsr
441+
// Was the code that triggered the exception in Thumb state?
442+
tst r0, {t_bit}
443+
// Subtract 2 in Thumb Mode, 4 in Arm Mode - see p.1206 of the ARMv7-A architecture manual.
444+
ite eq
445+
subeq lr, lr, #4
446+
subne lr, lr, #2
447+
// save the newly computed LR
448+
push {{lr}}
449+
// now do our standard exception save
449450
"#,
450451
save_context!(),
451452
r#"
452453
// Pass the faulting instruction address to the handler.
453-
mov r0, lr
454+
mov r0, lr
454455
// call C handler
455456
bl _undefined_handler
457+
// do our standard restore
456458
"#,
457459
restore_context!(),
458460
r#"
461+
// get our saved LR
462+
pop {{lr}}
463+
// get our real saved R0
464+
pop {{r0}}
465+
// overwrite the saved LR with the adjusted one
466+
str lr, [sp]
459467
// Return to the failing instruction which is the recommended approach by ARM.
460468
rfefd sp!
461469
.size _asm_default_undefined_handler, . - _asm_default_undefined_handler
462470
463471
464-
// Called from the vector table when we have an undefined exception.
472+
// Called from the vector table when we have a prefetch exception.
465473
// Saves state and calls a C-compatible handler like
466-
// `extern "C" fn _prefetch_handler();`
474+
// `extern "C" fn _prefetch_handler(addr: usize);`
467475
.global _asm_default_prefetch_handler
468476
.type _asm_default_prefetch_handler, %function
469477
_asm_default_prefetch_handler:
@@ -488,7 +496,7 @@ done:
488496
489497
// Called from the vector table when we have an undefined exception.
490498
// Saves state and calls a C-compatible handler like
491-
// `extern "C" fn _abort_handler();`
499+
// `extern "C" fn _abort_handler(addr: usize);`
492500
.global _asm_default_abort_handler
493501
.type _asm_default_abort_handler, %function
494502
_asm_default_abort_handler:
@@ -500,7 +508,7 @@ done:
500508
save_context!(),
501509
r#"
502510
// Pass the faulting instruction address to the handler.
503-
mov r0, lr
511+
mov r0, lr
504512
// call C handler
505513
bl _abort_handler
506514
"#,

cortex-r-rt/src/lib.rs

+35-26
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@
7474
//!
7575
//! ```rust
7676
//! #[unsafe(no_mangle)]
77-
//! extern "C" fn _undefined_handler(faulting_instruction: u32);
77+
//! extern "C" fn _undefined_handler(addr: usize);
7878
//! ```
7979
//!
8080
//! * `_abort_handler` - an `extern "C"` function to call when a Data Abort Exception
@@ -86,7 +86,7 @@
8686
//!
8787
//! ```rust
8888
//! #[unsafe(no_mangle)]
89-
//! extern "C" fn _abort_handler(faulting_instruction: u32);
89+
//! extern "C" fn _abort_handler(addr: usize);
9090
//! ```
9191
//!
9292
//! * `_prefetch_handler` - an `extern "C"` function to call when a Prefetch Abort Exception
@@ -98,7 +98,7 @@
9898
//!
9999
//! ```rust
100100
//! #[unsafe(no_mangle)]
101-
//! extern "C" fn _prefetch_handler(faulting_instruction: u32);
101+
//! extern "C" fn _prefetch_handler(addr: usize);
102102
//! ```
103103
//!
104104
//! ### ASM functions
@@ -113,7 +113,7 @@
113113
//! * `_asm_undefined_handler` - a naked function to call when an Undefined
114114
//! Exception occurs. Our linker script PROVIDEs a default function at
115115
//! `_asm_default_undefined_handler` but you can override it.
116-
//! * `_asm_prefetch_handler` - a naked function to call when an Prefetch
116+
//! * `_asm_prefetch_handler` - a naked function to call when a Prefetch
117117
//! Exception occurs. Our linker script PROVIDEs a default function at
118118
//! `_asm_default_prefetch_handler` but you can override it. The provided default
119119
//! handler will perform an exception return to the faulting address.
@@ -313,7 +313,7 @@ core::arch::global_asm!(
313313
314314
// Called from the vector table when we have an software interrupt.
315315
// Saves state and calls a C-compatible handler like
316-
// `extern "C" fn svc_handler(svc: u32, context: *const u32);`
316+
// `extern "C" fn svc_handler(svc: u32);`
317317
.global _asm_svc_handler
318318
.type _asm_svc_handler, %function
319319
_asm_svc_handler:
@@ -335,6 +335,7 @@ core::arch::global_asm!(
335335
rfefd sp!
336336
.size _asm_svc_handler, . - _asm_svc_handler
337337
338+
338339
// Called from the vector table when we have an interrupt.
339340
// Saves state and calls a C-compatible handler like
340341
// `extern "C" fn irq_handler();`
@@ -357,56 +358,64 @@ core::arch::global_asm!(
357358
358359
// Called from the vector table when we have an undefined exception.
359360
// Saves state and calls a C-compatible handler like
360-
// `extern "C" fn _undefined_handler();`
361+
// `extern "C" fn _undefined_handler(addr: usize);`
361362
.global _asm_default_undefined_handler
362363
.type _asm_default_undefined_handler, %function
363364
_asm_default_undefined_handler:
364-
// First adjust LR for two purposes: Passing the faulting instruction to the C handler,
365-
// and to return to the failing instruction after the C handler returns.
366-
// Load processor status
367-
mrs r4, cpsr
368-
// Occurred in Thumb state?
369-
tst r4, {t_bit}
370-
// If not in Thumb mode, branch to not_thumb
371-
beq not_thumb
372-
subs lr, lr, #2
373-
b done
374-
not_thumb:
375-
// Subtract 4 from LR (ARM mode)
376-
subs lr, lr, #4
377-
done:
378365
// state save from compiled code
379366
srsfd sp!, {und_mode}
367+
// to work out what mode we're in, we need R0
368+
push {{r0}}
369+
// First adjust LR for two purposes: Passing the faulting instruction to the C handler,
370+
// and to return to the failing instruction after the C handler returns.
371+
// Load processor status for the calling code
372+
mrs r0, spsr
373+
// Was the code that triggered the exception in Thumb state?
374+
tst r0, {t_bit}
375+
// Subtract 2 in Thumb Mode, 4 in Arm Mode - see p.1206 of the ARMv7-A architecture manual.
376+
ite eq
377+
subeq lr, lr, #4
378+
subne lr, lr, #2
379+
// save the newly computed LR
380+
push {{lr}}
381+
// now do our standard exception save
380382
"#,
381383
save_context!(),
382384
r#"
383385
// Pass the faulting instruction address to the handler.
384386
mov r0, lr
385387
// call C handler
386388
bl _undefined_handler
389+
// do our standard restore
387390
"#,
388391
restore_context!(),
389392
r#"
393+
// get our saved LR
394+
pop {{lr}}
395+
// get our real saved R0
396+
pop {{r0}}
397+
// overwrite the saved LR with the adjusted one
398+
str lr, [sp]
390399
// Return to the failing instruction which is the recommended approach by ARM.
391400
rfefd sp!
392401
.size _asm_default_undefined_handler, . - _asm_default_undefined_handler
393402
394403
395-
// Called from the vector table when we have an undefined exception.
404+
// Called from the vector table when we have a prefetch exception.
396405
// Saves state and calls a C-compatible handler like
397-
// `extern "C" fn _prefetch_handler();`
406+
// `extern "C" fn _prefetch_handler(addr: usize);`
398407
.global _asm_default_prefetch_handler
399408
.type _asm_default_prefetch_handler, %function
400409
_asm_default_prefetch_handler:
401410
// Subtract 4 from the stored LR, see p.1212 of the ARMv7-A architecture manual.
402-
subs lr, lr, #4
411+
subs lr, lr, #4
403412
// state save from compiled code
404413
srsfd sp!, {abt_mode}
405414
"#,
406415
save_context!(),
407416
r#"
408417
// Pass the faulting instruction address to the handler.
409-
mov r0, lr
418+
mov r0, lr
410419
// call C handler
411420
bl _prefetch_handler
412421
"#,
@@ -419,12 +428,12 @@ done:
419428
420429
// Called from the vector table when we have an undefined exception.
421430
// Saves state and calls a C-compatible handler like
422-
// `extern "C" fn _abort_handler();`
431+
// `extern "C" fn _abort_handler(addr: usize);`
423432
.global _asm_default_abort_handler
424433
.type _asm_default_abort_handler, %function
425434
_asm_default_abort_handler:
426435
// Subtract 8 from the stored LR, see p.1214 of the ARMv7-A architecture manual.
427-
subs lr, lr, #8
436+
subs lr, lr, #8
428437
// state save from compiled code
429438
srsfd sp!, {abt_mode}
430439
"#,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
Hello, this is an data abort exception example
2+
data abort occurred
3+
DFSR (Fault Status Register): DFSR { ext=false wnr=false Domain=0b0000 Status=0b00001 }
4+
DFSR Status: Ok(AlignmentFault)
5+
DFAR (Faulting Address Register): Dfar(4097)
6+
data abort occurred
7+
DFSR (Fault Status Register): DFSR { ext=false wnr=false Domain=0b0000 Status=0b00001 }
8+
DFSR Status: Ok(AlignmentFault)
9+
DFAR (Faulting Address Register): Dfar(4097)
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
1-
Hello, this is an prefetch exception example
1+
Hello, this is a prefetch exception example
22
prefetch abort occurred
33
IFSR (Fault Status Register): IFSR { ext=false Domain=0b0000 Status=0b00010 }
44
IFSR Status: Ok(DebugEvent)
55
IFAR (Faulting Address Register): Ifar(0)
6+
caught bkpt_from_a32
67
prefetch abort occurred
78
IFSR (Fault Status Register): IFSR { ext=false Domain=0b0000 Status=0b00010 }
89
IFSR Status: Ok(DebugEvent)
910
IFAR (Faulting Address Register): Ifar(0)
11+
caught bkpt_from_a32
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
1-
Hello, this is an prefetch exception example
1+
Hello, this is a prefetch exception example
22
prefetch abort occurred
33
IFSR (Fault Status Register): IFSR { ext=false Domain=0b0000 Status=0b00010 }
44
IFSR Status: Ok(DebugEvent)
55
IFAR (Faulting Address Register): Ifar(0)
6+
caught bkpt_from_t32
67
prefetch abort occurred
78
IFSR (Fault Status Register): IFSR { ext=false Domain=0b0000 Status=0b00010 }
89
IFSR Status: Ok(DebugEvent)
910
IFAR (Faulting Address Register): Ifar(0)
11+
caught bkpt_from_t32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
Hello, this is a undef exception example
2+
undefined abort occurred
3+
caught udf_from_a32
4+
undefined abort occurred
5+
caught udf_from_a32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
Hello, this is a undef exception example
2+
undefined abort occurred
3+
caught udf_from_a32
4+
undefined abort occurred
5+
caught udf_from_a32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
Hello, this is a undef exception example
2+
undefined abort occurred
3+
caught udf_from_a32
4+
undefined abort occurred
5+
caught udf_from_a32

examples/versatileab/reference/undef-exception-armv7a-none-eabi.out

-3
This file was deleted.

examples/versatileab/reference/undef-exception-armv7r-none-eabihf.out

-3
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
Hello, this is a undef exception example
2+
undefined abort occurred
3+
caught udf_from_t32
4+
undefined abort occurred
5+
caught udf_from_t32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
Hello, this is a undef exception example
2+
undefined abort occurred
3+
caught udf_from_t32
4+
undefined abort occurred
5+
caught udf_from_t32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
Hello, this is a undef exception example
2+
undefined abort occurred
3+
caught udf_from_t32
4+
undefined abort occurred
5+
caught udf_from_t32

examples/versatileab/src/bin/abt-exception.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -56,17 +56,17 @@ fn disable_alignment_check() {
5656
}
5757

5858
#[unsafe(no_mangle)]
59-
unsafe extern "C" fn _undefined_handler(_faulting_instruction: u32) {
59+
unsafe extern "C" fn _undefined_handler(_addr: u32) {
6060
panic!("unexpected undefined exception");
6161
}
6262

6363
#[unsafe(no_mangle)]
64-
unsafe extern "C" fn _prefetch_handler(_faulting_instruction: u32) {
64+
unsafe extern "C" fn _prefetch_handler(_addr: u32) {
6565
panic!("unexpected prefetch exception");
6666
}
6767

6868
#[unsafe(no_mangle)]
69-
unsafe extern "C" fn _abort_handler(_faulting_instruction: u32) {
69+
unsafe extern "C" fn _abort_handler(_addr: u32) {
7070
println!("data abort occurred");
7171
let dfsr = Dfsr::read();
7272
println!("DFSR (Fault Status Register): {:?}", dfsr);

0 commit comments

Comments
 (0)