Skip to content

Commit 2c603d9

Browse files
Split the prefetch-exception handler into two.
One for T32 and one for A32. We have to do this because the exception is non-recoverable (we return to the faulting instruction, which faults again).
1 parent af3fce8 commit 2c603d9

7 files changed

+217
-62
lines changed
Lines changed: 11 additions & 0 deletions
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
Lines changed: 11 additions & 0 deletions
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
Lines changed: 11 additions & 0 deletions
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
Lines changed: 11 additions & 0 deletions
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
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
//! Example triggering a prefetch exception.
2+
3+
#![no_std]
4+
#![no_main]
5+
6+
use core::sync::atomic::{AtomicU32, Ordering};
7+
use cortex_ar::register::{Ifar, Ifsr};
8+
use semihosting::println;
9+
10+
// pull in our start-up code
11+
use versatileab as _;
12+
13+
static COUNTER: AtomicU32 = AtomicU32::new(0);
14+
15+
/// The entry-point to the Rust application.
16+
///
17+
/// It is called by the start-up.
18+
#[no_mangle]
19+
pub extern "C" fn kmain() -> ! {
20+
println!("Hello, this is a prefetch exception example");
21+
22+
// A BKPT instruction triggers a Prefetch Abort except when Halting debug-mode is enabled.
23+
// See p. 2038 of ARMv7-M Architecture Reference Manual
24+
unsafe {
25+
// trigger an prefetch exception, from A32 (Arm) mode
26+
bkpt_from_a32();
27+
}
28+
29+
// this should be impossible because returning from the fault handler will
30+
// immediately trigger the fault again.
31+
32+
unreachable!("should never be here!");
33+
}
34+
35+
// These functions are written in assembly
36+
extern "C" {
37+
fn bkpt_from_a32();
38+
}
39+
40+
core::arch::global_asm!(
41+
r#"
42+
// fn bkpt_from_a32();
43+
.arm
44+
.global bkpt_from_a32
45+
.type bkpt_from_a32, %function
46+
bkpt_from_a32:
47+
bkpt #0
48+
bx lr
49+
.size bkpt_from_a32, . - bkpt_from_a32
50+
"#
51+
);
52+
53+
#[unsafe(no_mangle)]
54+
unsafe extern "C" fn _undefined_handler(_addr: usize) {
55+
panic!("unexpected undefined exception");
56+
}
57+
58+
#[unsafe(no_mangle)]
59+
unsafe extern "C" fn _prefetch_handler(addr: usize) {
60+
println!("prefetch abort occurred");
61+
let ifsr = Ifsr::read();
62+
println!("IFSR (Fault Status Register): {:?}", ifsr);
63+
println!("IFSR Status: {:?}", ifsr.status());
64+
let ifar = Ifar::read();
65+
println!("IFAR (Faulting Address Register): {:?}", ifar);
66+
67+
if addr == bkpt_from_a32 as usize {
68+
println!("caught bkpt_from_a32");
69+
} else {
70+
println!(
71+
"Bad fault address {:08x} is not {:08x}",
72+
addr, bkpt_from_a32 as usize
73+
);
74+
}
75+
76+
if COUNTER.fetch_add(1, Ordering::Relaxed) == 1 {
77+
// we've faulted twice - time to quit
78+
semihosting::process::exit(0);
79+
}
80+
}
81+
82+
#[unsafe(no_mangle)]
83+
unsafe extern "C" fn _abort_handler(_addr: usize) {
84+
panic!("unexpected abort exception");
85+
}
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
//! Example triggering a prefetch exception.
2+
3+
#![no_std]
4+
#![no_main]
5+
6+
use core::sync::atomic::{AtomicU32, Ordering};
7+
use cortex_ar::register::{Ifar, Ifsr};
8+
use semihosting::println;
9+
10+
// pull in our start-up code
11+
use versatileab as _;
12+
13+
static COUNTER: AtomicU32 = AtomicU32::new(0);
14+
15+
/// The entry-point to the Rust application.
16+
///
17+
/// It is called by the start-up.
18+
#[no_mangle]
19+
pub extern "C" fn kmain() -> ! {
20+
println!("Hello, this is a prefetch exception example");
21+
22+
// A BKPT instruction triggers a Prefetch Abort except when Halting debug-mode is enabled.
23+
// See p. 2038 of ARMv7-M Architecture Reference Manual
24+
unsafe {
25+
// trigger an prefetch exception, from T32 (Thumb) mode
26+
bkpt_from_t32();
27+
}
28+
29+
// this should be impossible because returning from the fault handler will
30+
// immediately trigger the fault again.
31+
32+
unreachable!("should never be here!");
33+
}
34+
35+
// These functions are written in assembly
36+
extern "C" {
37+
fn bkpt_from_t32();
38+
}
39+
40+
core::arch::global_asm!(
41+
r#"
42+
// fn bkpt_from_t32();
43+
.thumb
44+
.global bkpt_from_t32
45+
.type bkpt_from_t32, %function
46+
bkpt_from_t32:
47+
bkpt #0
48+
bx lr
49+
.size bkpt_from_t32, . - bkpt_from_t32
50+
"#
51+
);
52+
53+
#[unsafe(no_mangle)]
54+
unsafe extern "C" fn _undefined_handler(_addr: usize) {
55+
panic!("unexpected undefined exception");
56+
}
57+
58+
#[unsafe(no_mangle)]
59+
unsafe extern "C" fn _prefetch_handler(addr: usize) {
60+
println!("prefetch abort occurred");
61+
let ifsr = Ifsr::read();
62+
println!("IFSR (Fault Status Register): {:?}", ifsr);
63+
println!("IFSR Status: {:?}", ifsr.status());
64+
let ifar = Ifar::read();
65+
println!("IFAR (Faulting Address Register): {:?}", ifar);
66+
67+
if (addr + 1) == bkpt_from_t32 as usize {
68+
// note that thumb functions have their LSB set, despite always being a
69+
// multiple of two - that's how the CPU knows they are written in T32
70+
// machine code.
71+
println!("caught bkpt_from_t32");
72+
} else {
73+
println!(
74+
"Bad fault address {:08x} is not {:08x}",
75+
addr, bkpt_from_t32 as usize
76+
);
77+
}
78+
79+
if COUNTER.fetch_add(1, Ordering::Relaxed) == 1 {
80+
// we've faulted twice - time to quit
81+
semihosting::process::exit(0);
82+
}
83+
}
84+
85+
#[unsafe(no_mangle)]
86+
unsafe extern "C" fn _abort_handler(_addr: usize) {
87+
panic!("unexpected abort exception");
88+
}

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

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

0 commit comments

Comments
 (0)