Skip to content

Commit c6fb5fa

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 c6fb5fa

File tree

8 files changed

+98
-89
lines changed

8 files changed

+98
-89
lines changed

cortex-a-rt/src/lib.rs

Lines changed: 21 additions & 25 deletions
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,31 +426,27 @@ 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}
449435
"#,
450436
save_context!(),
451437
r#"
438+
// First adjust LR for two purposes: Passing the faulting instruction to the C handler,
439+
// and to return to the failing instruction after the C handler returns.
440+
// Load processor status for the calling code
441+
mrs r4, spsr
442+
// Was the code that triggered the exception in Thumb state?
443+
tst r4, {t_bit}
444+
// Subtract 2 in Thumb Mode, 4 in Arm Mode - see p.1206 of the ARMv7-A architecture manual.
445+
ite eq
446+
subeq lr, lr, #4
447+
subne lr, lr, #2
452448
// Pass the faulting instruction address to the handler.
453-
mov r0, lr
449+
mov r0, lr
454450
// call C handler
455451
bl _undefined_handler
456452
"#,
@@ -461,9 +457,9 @@ done:
461457
.size _asm_default_undefined_handler, . - _asm_default_undefined_handler
462458
463459
464-
// Called from the vector table when we have an undefined exception.
460+
// Called from the vector table when we have a prefetch exception.
465461
// Saves state and calls a C-compatible handler like
466-
// `extern "C" fn _prefetch_handler();`
462+
// `extern "C" fn _prefetch_handler(addr: usize);`
467463
.global _asm_default_prefetch_handler
468464
.type _asm_default_prefetch_handler, %function
469465
_asm_default_prefetch_handler:
@@ -488,7 +484,7 @@ done:
488484
489485
// Called from the vector table when we have an undefined exception.
490486
// Saves state and calls a C-compatible handler like
491-
// `extern "C" fn _abort_handler();`
487+
// `extern "C" fn _abort_handler(addr: usize);`
492488
.global _asm_default_abort_handler
493489
.type _asm_default_abort_handler, %function
494490
_asm_default_abort_handler:
@@ -500,7 +496,7 @@ done:
500496
save_context!(),
501497
r#"
502498
// Pass the faulting instruction address to the handler.
503-
mov r0, lr
499+
mov r0, lr
504500
// call C handler
505501
bl _abort_handler
506502
"#,

cortex-r-rt/src/lib.rs

Lines changed: 23 additions & 26 deletions
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,29 +358,25 @@ 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}
380367
"#,
381368
save_context!(),
382369
r#"
370+
// First adjust LR for two purposes: Passing the faulting instruction to the C handler,
371+
// and to return to the failing instruction after the C handler returns.
372+
// Load processor status for the calling code
373+
mrs r4, spsr
374+
// Was the code that triggered the exception in Thumb state?
375+
tst r4, {t_bit}
376+
// Subtract 2 in Thumb Mode, 4 in Arm Mode - see p.1206 of the ARMv7-A architecture manual.
377+
ite eq
378+
subeq lr, lr, #4
379+
subne lr, lr, #2
383380
// Pass the faulting instruction address to the handler.
384381
mov r0, lr
385382
// call C handler
@@ -392,21 +389,21 @@ done:
392389
.size _asm_default_undefined_handler, . - _asm_default_undefined_handler
393390
394391
395-
// Called from the vector table when we have an undefined exception.
392+
// Called from the vector table when we have a prefetch exception.
396393
// Saves state and calls a C-compatible handler like
397-
// `extern "C" fn _prefetch_handler();`
394+
// `extern "C" fn _prefetch_handler(addr: usize);`
398395
.global _asm_default_prefetch_handler
399396
.type _asm_default_prefetch_handler, %function
400397
_asm_default_prefetch_handler:
401398
// Subtract 4 from the stored LR, see p.1212 of the ARMv7-A architecture manual.
402-
subs lr, lr, #4
399+
subs lr, lr, #4
403400
// state save from compiled code
404401
srsfd sp!, {abt_mode}
405402
"#,
406403
save_context!(),
407404
r#"
408405
// Pass the faulting instruction address to the handler.
409-
mov r0, lr
406+
mov r0, lr
410407
// call C handler
411408
bl _prefetch_handler
412409
"#,
@@ -419,12 +416,12 @@ done:
419416
420417
// Called from the vector table when we have an undefined exception.
421418
// Saves state and calls a C-compatible handler like
422-
// `extern "C" fn _abort_handler();`
419+
// `extern "C" fn _abort_handler(addr: usize);`
423420
.global _asm_default_abort_handler
424421
.type _asm_default_abort_handler, %function
425422
_asm_default_abort_handler:
426423
// Subtract 8 from the stored LR, see p.1214 of the ARMv7-A architecture manual.
427-
subs lr, lr, #8
424+
subs lr, lr, #8
428425
// state save from compiled code
429426
srsfd sp!, {abt_mode}
430427
"#,

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

Lines changed: 0 additions & 9 deletions
This file was deleted.

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

Lines changed: 0 additions & 9 deletions
This file was deleted.
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
Hello, this is an undefined exception example
2-
undefined exception occurred
3-
undefined exception occurred
2+
caught undef_from_t32
3+
caught undef_from_a32
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
Hello, this is an undefined exception example
2-
undefined exception occurred
3-
undefined exception occurred
2+
caught undef_from_t32
3+
caught undef_from_a32

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

Lines changed: 3 additions & 3 deletions
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);

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

Lines changed: 47 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,17 @@
33
#![no_std]
44
#![no_main]
55

6-
use core::sync::atomic::AtomicU32;
7-
86
// pull in our start-up code
97
use versatileab as _;
108

119
use semihosting::println;
1210

11+
// These functions are written in assembly
12+
extern "C" {
13+
fn undef_from_a32();
14+
fn undef_from_t32();
15+
}
16+
1317
/// The entry-point to the Rust application.
1418
///
1519
/// It is called by the start-up.
@@ -18,25 +22,55 @@ pub extern "C" fn kmain() -> ! {
1822
main();
1923
}
2024

21-
static COUNTER: AtomicU32 = AtomicU32::new(0);
22-
2325
/// The main function of our Rust application.
2426
#[export_name = "main"]
2527
fn main() -> ! {
2628
println!("Hello, this is an undefined exception example");
2729
unsafe {
28-
core::arch::asm!("udf #0");
30+
// trigger an undefined exception, from T32 (Thumb) mode
31+
undef_from_t32();
32+
// trigger an undefined exception, from A32 (Arm) mode
33+
undef_from_a32();
2934
}
30-
unreachable!("should never be here!");
35+
36+
semihosting::process::exit(0);
3137
}
3238

39+
core::arch::global_asm!(
40+
r#"
41+
// fn undef_from_a32();
42+
.arm
43+
.global undef_from_a32
44+
.type undef_from_a32, %function
45+
undef_from_a32:
46+
udf #0
47+
bx lr
48+
.size undef_from_a32, . - undef_from_a32
49+
50+
// fn undef_from_t32();
51+
.thumb
52+
.global undef_from_t32
53+
.type undef_from_t32, %function
54+
undef_from_t32:
55+
udf #0
56+
bx lr
57+
.size undef_from_t32, . - undef_from_t32
58+
"#
59+
);
60+
3361
#[no_mangle]
34-
unsafe extern "C" fn _undefined_handler(_faulting_instruction: u32) {
35-
println!("undefined exception occurred");
36-
// For the first iteration, we do a regular exception return, which should
37-
// trigger the exception again.
38-
let counter_val = COUNTER.fetch_add(1, core::sync::atomic::Ordering::Relaxed) + 1;
39-
if counter_val == 2 {
40-
semihosting::process::exit(0);
62+
unsafe extern "C" fn _undefined_handler(addr: usize) {
63+
if addr == undef_from_a32 as usize {
64+
println!("caught undef_from_a32");
65+
} else if (addr + 1) == undef_from_t32 as usize {
66+
// note that thumb functions have their LSB set, despite always being a
67+
// multiple of two - that's how the CPU knows they are written in T32
68+
// machine code.
69+
println!("caught undef_from_t32");
70+
} else {
71+
println!(
72+
"Bad fault address {:08x} is not {:08x} or {:08x}",
73+
addr, undef_from_a32 as usize, undef_from_t32 as usize
74+
);
4175
}
4276
}

0 commit comments

Comments
 (0)