1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
|
//! Exceptions
use {Handler, Reserved, StackFrame};
/// Kind of exception
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum Exception {
/// i.e. currently not servicing an exception
ThreadMode,
/// Non-maskable interrupt.
Nmi,
/// All class of fault.
HardFault,
/// Memory management.
MemoryManagementFault,
/// Pre-fetch fault, memory access fault.
BusFault,
/// Undefined instruction or illegal state.
UsageFault,
/// System service call via SWI instruction
SVCall,
/// Pendable request for system service
PendSV,
/// System tick timer
Systick,
/// An interrupt
Interrupt(u8),
// Unreachable variant
#[doc(hidden)]
Reserved,
}
impl Exception {
/// Returns the kind of exception that's currently being serviced
pub fn current() -> Exception {
match ::peripheral::scb().icsr.read() as u8 {
0 => Exception::ThreadMode,
2 => Exception::Nmi,
3 => Exception::HardFault,
4 => Exception::MemoryManagementFault,
5 => Exception::BusFault,
6 => Exception::UsageFault,
11 => Exception::SVCall,
14 => Exception::PendSV,
15 => Exception::Systick,
n if n >= 16 => Exception::Interrupt(n - 16),
_ => Exception::Reserved,
}
}
}
/// Exception handlers
#[repr(C)]
pub struct Handlers {
/// Non-maskable interrupt
pub nmi: Handler,
/// All class of fault
pub hard_fault: Handler,
/// Memory management
pub mem_manage: Handler,
/// Pre-fetch fault, memory access fault
pub bus_fault: Handler,
/// Undefined instruction or illegal state
pub usage_fault: Handler,
/// Reserved spots in the vector table
pub _reserved0: [Reserved; 4],
/// System service call via SWI instruction
pub svcall: Handler,
/// Reserved spots in the vector table
pub _reserved1: [Reserved; 2],
/// Pendable request for system service
pub pendsv: Handler,
/// System tick timer
pub sys_tick: Handler,
}
/// Default exception handlers
pub const DEFAULT_HANDLERS: Handlers = Handlers {
_reserved0: [Reserved::Vector; 4],
_reserved1: [Reserved::Vector; 2],
bus_fault: default_handler,
hard_fault: default_handler,
mem_manage: default_handler,
nmi: default_handler,
pendsv: default_handler,
svcall: default_handler,
sys_tick: default_handler,
usage_fault: default_handler,
};
/// The default exception handler
///
/// This handler triggers a breakpoint (`bkpt`) and gives you access, within a
/// GDB session, to the stack frame (`_sf`) where the exception occurred.
// This needs asm!, #[naked] and unreachable() to avoid modifying the stack
// pointer (MSP), that way it points to the previous stack frame
#[naked]
pub unsafe extern "C" fn default_handler() {
// This is the actual exception handler. `_sf` is a pointer to the previous
// stack frame
extern "C" fn handler(_sf: &StackFrame) -> ! {
#[cfg(feature = "semihosting")]
hprintln!("EXCEPTION {:?} @ PC=0x{:08x}", Exception::current(), _sf.pc);
unsafe {
bkpt!();
}
loop {}
}
// "trampoline" to get to the real exception handler.
asm!("mrs r0, MSP
ldr r1, [r0, #20]
b $0"
:
: "i"(handler as extern "C" fn(&StackFrame) -> !) :: "volatile");
::core::intrinsics::unreachable()
}
|