Skip to content

Commit 93d17c1

Browse files
Fix the undef handler again
1 parent f1ad209 commit 93d17c1

17 files changed

+271
-97
lines changed

Diff for: cortex-a-rt/src/lib.rs

+17-5
Original file line numberDiff line numberDiff line change
@@ -432,26 +432,38 @@ core::arch::global_asm!(
432432
_asm_default_undefined_handler:
433433
// state save from compiled code
434434
srsfd sp!, {und_mode}
435-
"#,
436-
save_context!(),
437-
r#"
435+
// to work out what mode we're in, we need R0
436+
push {{r0}}
438437
// First adjust LR for two purposes: Passing the faulting instruction to the C handler,
439438
// and to return to the failing instruction after the C handler returns.
440439
// Load processor status for the calling code
441-
mrs r4, spsr
440+
mrs r0, spsr
442441
// Was the code that triggered the exception in Thumb state?
443-
tst r4, {t_bit}
442+
tst r0, {t_bit}
444443
// Subtract 2 in Thumb Mode, 4 in Arm Mode - see p.1206 of the ARMv7-A architecture manual.
445444
ite eq
446445
subeq lr, lr, #4
447446
subne lr, lr, #2
447+
// save the newly computed LR
448+
push {{lr}}
449+
// now do our standard exception save
450+
"#,
451+
save_context!(),
452+
r#"
448453
// Pass the faulting instruction address to the handler.
449454
mov r0, lr
450455
// call C handler
451456
bl _undefined_handler
457+
// do our standard restore
452458
"#,
453459
restore_context!(),
454460
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]
455467
// Return to the failing instruction which is the recommended approach by ARM.
456468
rfefd sp!
457469
.size _asm_default_undefined_handler, . - _asm_default_undefined_handler

Diff for: cortex-r-rt/src/lib.rs

+17-5
Original file line numberDiff line numberDiff line change
@@ -364,26 +364,38 @@ core::arch::global_asm!(
364364
_asm_default_undefined_handler:
365365
// state save from compiled code
366366
srsfd sp!, {und_mode}
367-
"#,
368-
save_context!(),
369-
r#"
367+
// to work out what mode we're in, we need R0
368+
push {{r0}}
370369
// First adjust LR for two purposes: Passing the faulting instruction to the C handler,
371370
// and to return to the failing instruction after the C handler returns.
372371
// Load processor status for the calling code
373-
mrs r4, spsr
372+
mrs r0, spsr
374373
// Was the code that triggered the exception in Thumb state?
375-
tst r4, {t_bit}
374+
tst r0, {t_bit}
376375
// Subtract 2 in Thumb Mode, 4 in Arm Mode - see p.1206 of the ARMv7-A architecture manual.
377376
ite eq
378377
subeq lr, lr, #4
379378
subne lr, lr, #2
379+
// save the newly computed LR
380+
push {{lr}}
381+
// now do our standard exception save
382+
"#,
383+
save_context!(),
384+
r#"
380385
// Pass the faulting instruction address to the handler.
381386
mov r0, lr
382387
// call C handler
383388
bl _undefined_handler
389+
// do our standard restore
384390
"#,
385391
restore_context!(),
386392
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]
387399
// Return to the failing instruction which is the recommended approach by ARM.
388400
rfefd sp!
389401
.size _asm_default_undefined_handler, . - _asm_default_undefined_handler
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
@@ -0,0 +1,11 @@
1+
Hello, this is a prefetch exception example
2+
prefetch abort occurred
3+
IFSR (Fault Status Register): IFSR { ext=false Domain=0b0000 Status=0b00010 }
4+
IFSR Status: Ok(DebugEvent)
5+
IFAR (Faulting Address Register): Ifar(0)
6+
caught bkpt_from_a32
7+
prefetch abort occurred
8+
IFSR (Fault Status Register): IFSR { ext=false Domain=0b0000 Status=0b00010 }
9+
IFSR Status: Ok(DebugEvent)
10+
IFAR (Faulting Address Register): Ifar(0)
11+
caught bkpt_from_a32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
Hello, this is a prefetch exception example
2+
prefetch abort occurred
3+
IFSR (Fault Status Register): IFSR { ext=false Domain=0b0000 Status=0b00010 }
4+
IFSR Status: Ok(DebugEvent)
5+
IFAR (Faulting Address Register): Ifar(0)
6+
caught bkpt_from_t32
7+
prefetch abort occurred
8+
IFSR (Fault Status Register): IFSR { ext=false Domain=0b0000 Status=0b00010 }
9+
IFSR Status: Ok(DebugEvent)
10+
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

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

-3
This file was deleted.

Diff for: 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

Diff for: examples/versatileab/src/bin/undef-exception-a32.rs

+80
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
//! Example triggering a undef exception.
2+
3+
#![no_std]
4+
#![no_main]
5+
6+
use core::sync::atomic::{AtomicU32, Ordering};
7+
use semihosting::println;
8+
9+
// pull in our start-up code
10+
use versatileab as _;
11+
12+
static COUNTER: AtomicU32 = AtomicU32::new(0);
13+
14+
/// The entry-point to the Rust application.
15+
///
16+
/// It is called by the start-up.
17+
#[no_mangle]
18+
pub extern "C" fn kmain() -> ! {
19+
println!("Hello, this is a undef exception example");
20+
21+
unsafe {
22+
// trigger an Undefined exception, from A32 (Thumb) mode
23+
udf_from_a32();
24+
}
25+
26+
// this should be impossible because returning from the fault handler will
27+
// immediately trigger the fault again.
28+
29+
unreachable!("should never be here!");
30+
}
31+
32+
// These functions are written in assembly
33+
extern "C" {
34+
fn udf_from_a32();
35+
}
36+
37+
core::arch::global_asm!(
38+
r#"
39+
// fn udf_from_a32();
40+
.arm
41+
.global udf_from_a32
42+
.type udf_from_a32, %function
43+
udf_from_a32:
44+
udf #0
45+
bx lr
46+
.size udf_from_a32, . - udf_from_a32
47+
"#
48+
);
49+
50+
#[unsafe(no_mangle)]
51+
unsafe extern "C" fn _prefetch_handler(_addr: usize) {
52+
panic!("unexpected undefined exception");
53+
}
54+
55+
#[unsafe(no_mangle)]
56+
unsafe extern "C" fn _undefined_handler(addr: usize) {
57+
println!("undefined abort occurred");
58+
59+
if addr == udf_from_a32 as usize {
60+
// note that thumb functions have their LSB set, despite always being a
61+
// multiple of two - that's how the CPU knows they are written in a32
62+
// machine code.
63+
println!("caught udf_from_a32");
64+
} else {
65+
println!(
66+
"Bad fault address {:08x} is not {:08x}",
67+
addr, udf_from_a32 as usize
68+
);
69+
}
70+
71+
if COUNTER.fetch_add(1, Ordering::Relaxed) == 1 {
72+
// we've faulted twice - time to quit
73+
semihosting::process::exit(0);
74+
}
75+
}
76+
77+
#[unsafe(no_mangle)]
78+
unsafe extern "C" fn _abort_handler(_addr: usize) {
79+
panic!("unexpected abort exception");
80+
}

Diff for: examples/versatileab/src/bin/undef-exception-t32.rs

+80
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
//! Example triggering a undef exception.
2+
3+
#![no_std]
4+
#![no_main]
5+
6+
use core::sync::atomic::{AtomicU32, Ordering};
7+
use semihosting::println;
8+
9+
// pull in our start-up code
10+
use versatileab as _;
11+
12+
static COUNTER: AtomicU32 = AtomicU32::new(0);
13+
14+
/// The entry-point to the Rust application.
15+
///
16+
/// It is called by the start-up.
17+
#[no_mangle]
18+
pub extern "C" fn kmain() -> ! {
19+
println!("Hello, this is a undef exception example");
20+
21+
unsafe {
22+
// trigger an Undefined exception, from T32 (Thumb) mode
23+
udf_from_t32();
24+
}
25+
26+
// this should be impossible because returning from the fault handler will
27+
// immediately trigger the fault again.
28+
29+
unreachable!("should never be here!");
30+
}
31+
32+
// These functions are written in assembly
33+
extern "C" {
34+
fn udf_from_t32();
35+
}
36+
37+
core::arch::global_asm!(
38+
r#"
39+
// fn udf_from_t32();
40+
.thumb
41+
.global udf_from_t32
42+
.type udf_from_t32, %function
43+
udf_from_t32:
44+
udf #0
45+
bx lr
46+
.size udf_from_t32, . - udf_from_t32
47+
"#
48+
);
49+
50+
#[unsafe(no_mangle)]
51+
unsafe extern "C" fn _prefetch_handler(_addr: usize) {
52+
panic!("unexpected undefined exception");
53+
}
54+
55+
#[unsafe(no_mangle)]
56+
unsafe extern "C" fn _undefined_handler(addr: usize) {
57+
println!("undefined abort occurred");
58+
59+
if (addr + 1) == udf_from_t32 as usize {
60+
// note that thumb functions have their LSB set, despite always being a
61+
// multiple of two - that's how the CPU knows they are written in T32
62+
// machine code.
63+
println!("caught udf_from_t32");
64+
} else {
65+
println!(
66+
"Bad fault address {:08x} is not {:08x}",
67+
addr, udf_from_t32 as usize
68+
);
69+
}
70+
71+
if COUNTER.fetch_add(1, Ordering::Relaxed) == 1 {
72+
// we've faulted twice - time to quit
73+
semihosting::process::exit(0);
74+
}
75+
}
76+
77+
#[unsafe(no_mangle)]
78+
unsafe extern "C" fn _abort_handler(_addr: usize) {
79+
panic!("unexpected abort exception");
80+
}

0 commit comments

Comments
 (0)