Skip to content

Commit d3f5f15

Browse files
Merge pull request #30 from thejpster/fix-exception-return
2 parents 59b0af5 + 104fe1d commit d3f5f15

40 files changed

+871
-280
lines changed

cortex-a-rt/src/lib.rs

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -447,7 +447,7 @@ core::arch::global_asm!(
447447
_asm_default_undefined_handler:
448448
// state save from compiled code
449449
srsfd sp!, {und_mode}
450-
// to work out what mode we're in, we need R0
450+
// to work out what mode we're in, we need R0, so save it
451451
push {{r0}}
452452
// First adjust LR for two purposes: Passing the faulting instruction to the C handler,
453453
// and to return to the failing instruction after the C handler returns.
@@ -459,9 +459,7 @@ 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}}
464-
// now do our standard exception save
462+
// now do our standard exception save (which saves the 'wrong' R0)
465463
"#,
466464
save_context!(),
467465
r#"
@@ -471,17 +469,15 @@ core::arch::global_asm!(
471469
bl _undefined_handler
472470
// if we get back here, assume they returned a new LR in r0
473471
mov lr, r0
474-
// do our standard restore
472+
// do our standard restore (with the 'wrong' R0)
475473
"#,
476474
restore_context!(),
477475
r#"
478-
// get our saved LR
479-
pop {{lr}}
480-
// get our real saved R0
476+
// get the R0 we saved early
481477
pop {{r0}}
482-
// overwrite the saved LR with the adjusted one
478+
// overwrite the saved LR with the one from the C handler
483479
str lr, [sp]
484-
// Return to the failing instruction which is the recommended approach by ARM.
480+
// Return from the asm handler
485481
rfefd sp!
486482
.size _asm_default_undefined_handler, . - _asm_default_undefined_handler
487483
@@ -537,7 +533,9 @@ core::arch::global_asm!(
537533
"#,
538534
restore_context!(),
539535
r#"
540-
// Return to the failing instruction which is the recommended approach by ARM.
536+
// overwrite the saved LR with the one from the C handler
537+
str lr, [sp]
538+
// Return from the asm handler
541539
rfefd sp!
542540
.size _asm_default_abort_handler, . - _asm_default_abort_handler
543541
@@ -566,7 +564,9 @@ core::arch::global_asm!(
566564
"#,
567565
restore_context!(),
568566
r#"
569-
// Return to the failing instruction which is the recommended approach by ARM.
567+
// overwrite the saved LR with the one from the C handler
568+
str lr, [sp]
569+
// Return from the asm handler
570570
rfefd sp!
571571
.size _asm_default_prefetch_handler, . - _asm_default_prefetch_handler
572572

cortex-r-rt/src/lib.rs

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -409,9 +409,7 @@ 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}}
414-
// now do our standard exception save
412+
// now do our standard exception save (which saves the 'wrong' R0)
415413
"#,
416414
save_context!(),
417415
r#"
@@ -421,17 +419,15 @@ core::arch::global_asm!(
421419
bl _undefined_handler
422420
// if we get back here, assume they returned a new LR in r0
423421
mov lr, r0
424-
// do our standard restore
422+
// do our standard restore (with the 'wrong' R0)
425423
"#,
426424
restore_context!(),
427425
r#"
428-
// get our saved LR
429-
pop {{lr}}
430-
// get our real saved R0
426+
// get the R0 we saved early
431427
pop {{r0}}
432-
// overwrite the saved LR with the adjusted one
428+
// overwrite the saved LR with the one from the C handler
433429
str lr, [sp]
434-
// Return to the failing instruction which is the recommended approach by ARM.
430+
// Return from the asm handler
435431
rfefd sp!
436432
.size _asm_default_undefined_handler, . - _asm_default_undefined_handler
437433
@@ -487,7 +483,9 @@ core::arch::global_asm!(
487483
"#,
488484
restore_context!(),
489485
r#"
490-
// Return to the failing instruction which is the recommended approach by ARM.
486+
// overwrite the saved LR with the one from the C handler
487+
str lr, [sp]
488+
// Return from the asm handler
491489
rfefd sp!
492490
.size _asm_default_abort_handler, . - _asm_default_abort_handler
493491
@@ -516,7 +514,9 @@ core::arch::global_asm!(
516514
"#,
517515
restore_context!(),
518516
r#"
519-
// Return to the failing instruction which is the recommended approach by ARM.
517+
// overwrite the saved LR with the one from the C handler
518+
str lr, [sp]
519+
// Return from the asm handler
520520
rfefd sp!
521521
.size _asm_default_prefetch_handler, . - _asm_default_prefetch_handler
522522
@@ -558,8 +558,8 @@ core::arch::global_asm!(
558558
abt_mode = const ProcessorMode::Abt as u8,
559559
t_bit = const {
560560
Cpsr::new_with_raw_value(0)
561-
.with_t(true)
562-
.raw_value()
561+
.with_t(true)
562+
.raw_value()
563563
},
564564
);
565565

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: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,13 @@ 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+
caught unaligned_from_a32
6+
caught fault on COUNTER
7+
Doing it again
68
data abort occurred
79
DFSR (Fault Status Register): DFSR { ext=false wnr=false Domain=0b0010 Status=0b00001 }
810
DFSR Status: Ok(AlignmentFault)
9-
DFAR (Faulting Address Register): Dfar(4097)
11+
caught unaligned_from_a32
12+
caught fault on COUNTER
13+
Skipping instruction
14+
Recovered from fault OK!
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
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+
caught unaligned_from_t32
6+
caught fault on COUNTER
7+
Doing it again
8+
data abort occurred
9+
DFSR (Fault Status Register): DFSR { ext=false wnr=false Domain=0b0010 Status=0b00001 }
10+
DFSR Status: Ok(AlignmentFault)
11+
caught unaligned_from_t32
12+
caught fault on COUNTER
13+
Skipping instruction
14+
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!
Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
//! Example triggering an data abort exception.
2+
3+
#![no_std]
4+
#![no_main]
5+
6+
use core::sync::atomic::{AtomicU32, Ordering};
7+
8+
use cortex_ar::register::{Dfar, Dfsr, Sctlr};
9+
// pull in our start-up code
10+
use mps3_an536 as _;
11+
12+
use semihosting::println;
13+
14+
#[no_mangle]
15+
static COUNTER: AtomicU32 = AtomicU32::new(0);
16+
17+
/// The entry-point to the Rust application.
18+
///
19+
/// It is called by the start-up.
20+
#[no_mangle]
21+
pub extern "C" fn kmain() -> ! {
22+
main();
23+
}
24+
25+
/// The main function of our Rust application.
26+
#[export_name = "main"]
27+
#[allow(unreachable_code)]
28+
fn main() -> ! {
29+
// Enable alignment check for Armv7-R. Was not required
30+
// on Cortex-A for some reason, even though the bit was not set.
31+
enable_alignment_check();
32+
33+
println!("Hello, this is an data abort exception example");
34+
unsafe {
35+
// Unaligned read
36+
unaligned_from_a32();
37+
}
38+
39+
println!("Recovered from fault OK!");
40+
41+
semihosting::process::exit(0);
42+
}
43+
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+
64+
fn enable_alignment_check() {
65+
let mut sctrl = Sctlr::read();
66+
sctrl.set_a(true);
67+
Sctlr::write(sctrl);
68+
}
69+
70+
fn disable_alignment_check() {
71+
let mut sctrl = Sctlr::read();
72+
sctrl.set_a(false);
73+
Sctlr::write(sctrl);
74+
}
75+
76+
#[unsafe(no_mangle)]
77+
unsafe extern "C" fn _undefined_handler(_addr: u32) -> ! {
78+
panic!("unexpected undefined exception");
79+
}
80+
81+
#[unsafe(no_mangle)]
82+
unsafe extern "C" fn _prefetch_handler(_addr: u32) -> ! {
83+
panic!("unexpected prefetch exception");
84+
}
85+
86+
#[unsafe(no_mangle)]
87+
unsafe extern "C" fn _abort_handler(addr: usize) -> usize {
88+
println!("data abort occurred");
89+
// If this is not disabled, reading DFAR will trigger an alignment fault on Armv8-R, leading
90+
// to a loop.
91+
disable_alignment_check();
92+
let dfsr = Dfsr::read();
93+
println!("DFSR (Fault Status Register): {:?}", dfsr);
94+
println!("DFSR Status: {:?}", dfsr.status());
95+
let dfar = Dfar::read();
96+
enable_alignment_check();
97+
98+
// note the fault isn't at the start of the function
99+
let expect_fault_at = unaligned_from_a32 as usize + 8;
100+
101+
if addr == expect_fault_at {
102+
println!("caught unaligned_from_a32");
103+
} else {
104+
println!(
105+
"Bad fault address {:08x} is not {:08x}",
106+
addr, expect_fault_at
107+
);
108+
}
109+
110+
let expect_fault_from = core::ptr::addr_of!(COUNTER) as usize + 1;
111+
112+
if dfar.0 as usize == expect_fault_from {
113+
println!("caught fault on COUNTER");
114+
} else {
115+
println!(
116+
"Bad DFAR address {:08x} is not {:08x}",
117+
dfar.0, expect_fault_from
118+
);
119+
}
120+
121+
match COUNTER.fetch_add(1, Ordering::Relaxed) {
122+
0 => {
123+
// first time, huh?
124+
// go back and do it again
125+
println!("Doing it again");
126+
addr
127+
}
128+
1 => {
129+
// second time, huh?
130+
// go back but skip the instruction
131+
println!("Skipping instruction");
132+
addr + 4
133+
}
134+
_ => {
135+
// we've faulted thrice - time to quit
136+
println!("We triple faulted");
137+
semihosting::process::abort();
138+
}
139+
}
140+
}

0 commit comments

Comments
 (0)