Skip to content

Commit 4c451f6

Browse files
committed
Don't trash the LR returned from _undefined_handler.
Also modifies the undef-exception test to make sure we can actually recover from an undef exception. And updates the abt-exception test to also check returning, and dealing with both A32 and T32 modes.
1 parent 6f287c1 commit 4c451f6

38 files changed

+731
-120
lines changed

cortex-a-rt/src/lib.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -459,8 +459,6 @@ core::arch::global_asm!(
459459
ite eq
460460
subeq lr, lr, #4
461461
subne lr, lr, #2
462-
// save the newly computed LR
463-
push {{lr}}
464462
// now do our standard exception save
465463
"#,
466464
save_context!(),
@@ -475,8 +473,6 @@ core::arch::global_asm!(
475473
"#,
476474
restore_context!(),
477475
r#"
478-
// get our saved LR
479-
pop {{lr}}
480476
// get our real saved R0
481477
pop {{r0}}
482478
// overwrite the saved LR with the adjusted one
@@ -537,6 +533,8 @@ core::arch::global_asm!(
537533
"#,
538534
restore_context!(),
539535
r#"
536+
// overwrite the saved LR with the adjusted one
537+
str lr, [sp]
540538
// Return to the failing instruction which is the recommended approach by ARM.
541539
rfefd sp!
542540
.size _asm_default_abort_handler, . - _asm_default_abort_handler
@@ -566,6 +564,8 @@ core::arch::global_asm!(
566564
"#,
567565
restore_context!(),
568566
r#"
567+
// overwrite the saved LR with the adjusted one
568+
str lr, [sp]
569569
// Return to the failing instruction which is the recommended approach by ARM.
570570
rfefd sp!
571571
.size _asm_default_prefetch_handler, . - _asm_default_prefetch_handler

cortex-r-rt/src/lib.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -409,8 +409,6 @@ core::arch::global_asm!(
409409
ite eq
410410
subeq lr, lr, #4
411411
subne lr, lr, #2
412-
// save the newly computed LR
413-
push {{lr}}
414412
// now do our standard exception save
415413
"#,
416414
save_context!(),
@@ -425,8 +423,6 @@ core::arch::global_asm!(
425423
"#,
426424
restore_context!(),
427425
r#"
428-
// get our saved LR
429-
pop {{lr}}
430426
// get our real saved R0
431427
pop {{r0}}
432428
// overwrite the saved LR with the adjusted one
@@ -487,6 +483,8 @@ core::arch::global_asm!(
487483
"#,
488484
restore_context!(),
489485
r#"
486+
// overwrite the saved LR with the adjusted one
487+
str lr, [sp]
490488
// Return to the failing instruction which is the recommended approach by ARM.
491489
rfefd sp!
492490
.size _asm_default_abort_handler, . - _asm_default_abort_handler
@@ -516,6 +514,8 @@ core::arch::global_asm!(
516514
"#,
517515
restore_context!(),
518516
r#"
517+
// overwrite the saved LR with the adjusted one
518+
str lr, [sp]
519519
// Return to the failing instruction which is the recommended approach by ARM.
520520
rfefd sp!
521521
.size _asm_default_prefetch_handler, . - _asm_default_prefetch_handler

examples/mps3-an536/reference/abt-exception-armv8r-none-eabihf.out renamed to examples/mps3-an536/reference/abt-exception-a32-armv8r-none-eabihf.out

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,15 @@ Hello, this is an data abort exception example
22
data abort occurred
33
DFSR (Fault Status Register): DFSR { ext=false wnr=false Domain=0b0010 Status=0b00001 }
44
DFSR Status: Ok(AlignmentFault)
5-
DFAR (Faulting Address Register): Dfar(4097)
5+
DFAR (Faulting Address Register): Dfar(536870913)
6+
caught unaligned_from_a32
7+
caught fault on COUNTER
8+
Doing it again
69
data abort occurred
710
DFSR (Fault Status Register): DFSR { ext=false wnr=false Domain=0b0010 Status=0b00001 }
811
DFSR Status: Ok(AlignmentFault)
9-
DFAR (Faulting Address Register): Dfar(4097)
12+
DFAR (Faulting Address Register): Dfar(536870913)
13+
caught unaligned_from_a32
14+
caught fault on COUNTER
15+
Skipping instruction
16+
Recovered from fault OK!
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
Hello, this is an data abort exception example
2+
data abort occurred
3+
DFSR (Fault Status Register): DFSR { ext=false wnr=false Domain=0b0010 Status=0b00001 }
4+
DFSR Status: Ok(AlignmentFault)
5+
DFAR (Faulting Address Register): Dfar(536870913)
6+
caught unaligned_from_t32
7+
caught fault on COUNTER
8+
Doing it again
9+
data abort occurred
10+
DFSR (Fault Status Register): DFSR { ext=false wnr=false Domain=0b0010 Status=0b00001 }
11+
DFSR Status: Ok(AlignmentFault)
12+
DFAR (Faulting Address Register): Dfar(536870913)
13+
caught unaligned_from_t32
14+
caught fault on COUNTER
15+
Skipping instruction
16+
Recovered from fault OK!

examples/mps3-an536/reference/prefetch-exception-a32-armv8r-none-eabihf.out

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,11 @@ IFSR (Fault Status Register): IFSR { ext=false Domain=0b0010 Status=0b00010 }
44
IFSR Status: Ok(DebugEvent)
55
IFAR (Faulting Address Register): Ifar(0)
66
caught bkpt_from_a32
7+
Doing it again
78
prefetch abort occurred
89
IFSR (Fault Status Register): IFSR { ext=false Domain=0b0010 Status=0b00010 }
910
IFSR Status: Ok(DebugEvent)
1011
IFAR (Faulting Address Register): Ifar(0)
1112
caught bkpt_from_a32
13+
Skipping instruction
14+
Recovered from fault OK!

examples/mps3-an536/reference/prefetch-exception-t32-armv8r-none-eabihf.out

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,11 @@ IFSR (Fault Status Register): IFSR { ext=false Domain=0b0010 Status=0b00010 }
44
IFSR Status: Ok(DebugEvent)
55
IFAR (Faulting Address Register): Ifar(0)
66
caught bkpt_from_t32
7+
Doing it again
78
prefetch abort occurred
89
IFSR (Fault Status Register): IFSR { ext=false Domain=0b0010 Status=0b00010 }
910
IFSR Status: Ok(DebugEvent)
1011
IFAR (Faulting Address Register): Ifar(0)
1112
caught bkpt_from_t32
13+
Skipping instruction
14+
Recovered from fault OK!
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
Hello, this is a undef exception example
22
undefined abort occurred
33
caught udf_from_a32
4+
Doing it again
45
undefined abort occurred
56
caught udf_from_a32
7+
Skipping instruction
8+
Recovered from fault OK!
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
Hello, this is a undef exception example
22
undefined abort occurred
33
caught udf_from_t32
4+
Doing it again
45
undefined abort occurred
56
caught udf_from_t32
7+
Skipping instruction
8+
Recovered from fault OK!

examples/mps3-an536/src/bin/abt-exception.rs renamed to examples/mps3-an536/src/bin/abt-exception-a32.rs

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

6-
use core::sync::atomic::AtomicU32;
6+
use core::sync::atomic::{AtomicU32, Ordering};
77

88
use cortex_ar::register::{Dfar, Dfsr, Sctlr};
99
// pull in our start-up code
1010
use mps3_an536 as _;
1111

1212
use semihosting::println;
1313

14+
#[no_mangle]
1415
static COUNTER: AtomicU32 = AtomicU32::new(0);
1516

1617
/// The entry-point to the Rust application.
@@ -30,19 +31,36 @@ fn main() -> ! {
3031
enable_alignment_check();
3132

3233
println!("Hello, this is an data abort exception example");
33-
// Unaligned read
3434
unsafe {
35-
let addr: *const u32 = 0x1001 as *const u32; // Unaligned address (not 4-byte aligned)
36-
core::arch::asm!(
37-
"ldr r0, [{addr}]", // Attempt unaligned load (should trigger Data Abort)
38-
addr = in(reg) addr, // Pass unaligned pointer
39-
options(nostack, preserves_flags) // No stack usage, preserves flags
40-
);
35+
// Unaligned read
36+
unaligned_from_a32();
4137
}
4238

43-
unreachable!("should never be here!");
39+
println!("Recovered from fault OK!");
40+
41+
semihosting::process::exit(0);
4442
}
4543

44+
// These functions are written in assembly
45+
extern "C" {
46+
fn unaligned_from_a32();
47+
}
48+
49+
core::arch::global_asm!(
50+
r#"
51+
// fn unaligned_from_a32();
52+
.arm
53+
.global unaligned_from_a32
54+
.type unaligned_from_a32, %function
55+
unaligned_from_a32:
56+
ldr r0, =COUNTER
57+
add r0, r0, 1
58+
ldr r0, [r0]
59+
bx lr
60+
.size unaligned_from_a32, . - unaligned_from_a32
61+
"#
62+
);
63+
4664
fn enable_alignment_check() {
4765
let mut sctrl = Sctlr::read();
4866
sctrl.set_a(true);
@@ -77,11 +95,47 @@ unsafe extern "C" fn _abort_handler(addr: usize) -> usize {
7795
let dfar = Dfar::read();
7896
println!("DFAR (Faulting Address Register): {:?}", dfar);
7997
enable_alignment_check();
80-
// For the first iteration, we do a regular exception return, which should
81-
// trigger the exception again. The second time around we quit.
82-
if COUNTER.fetch_add(1, core::sync::atomic::Ordering::Relaxed) == 1 {
83-
semihosting::process::exit(0);
98+
99+
// note the fault isn't at the start of the function
100+
let expect_fault_at = unaligned_from_a32 as usize + 8;
101+
102+
if addr == expect_fault_at {
103+
println!("caught unaligned_from_a32");
104+
} else {
105+
println!(
106+
"Bad fault address {:08x} is not {:08x}",
107+
addr, expect_fault_at
108+
);
84109
}
85110

86-
addr
111+
let expect_fault_from = core::ptr::addr_of!(COUNTER) as usize + 1;
112+
113+
if dfar.0 as usize == expect_fault_from {
114+
println!("caught fault on COUNTER");
115+
} else {
116+
println!(
117+
"Bad DFAR address {:08x} is not {:08x}",
118+
dfar.0, expect_fault_from
119+
);
120+
}
121+
122+
match COUNTER.fetch_add(1, Ordering::Relaxed) {
123+
0 => {
124+
// first time, huh?
125+
// go back and do it again
126+
println!("Doing it again");
127+
addr
128+
}
129+
1 => {
130+
// second time, huh?
131+
// go back but skip the instruction
132+
println!("Skipping instruction");
133+
addr + 4
134+
}
135+
_ => {
136+
// we've faulted thrice - time to quit
137+
println!("We triple faulted");
138+
semihosting::process::abort();
139+
}
140+
}
87141
}

0 commit comments

Comments
 (0)