diff options
Diffstat (limited to 'src/exception.rs')
-rw-r--r-- | src/exception.rs | 165 |
1 files changed, 163 insertions, 2 deletions
diff --git a/src/exception.rs b/src/exception.rs index 7046080..f5c8c28 100644 --- a/src/exception.rs +++ b/src/exception.rs @@ -1,4 +1,9 @@ -/// Kind of exception +//! Exceptions + +use ctxt::Context; +use Reserved; + +/// Enumeration of all exceptions #[derive(Clone, Copy, Debug, Eq, PartialEq)] pub enum Exception { /// i.e. currently not servicing an exception @@ -29,7 +34,7 @@ pub enum Exception { impl Exception { /// Returns the kind of exception that's currently being serviced pub fn current() -> Exception { - match ::peripheral::scb().icsr.read() as u8 { + match unsafe { (*::peripheral::SCB.get()).icsr.read() } as u8 { 0 => Exception::ThreadMode, 2 => Exception::Nmi, 3 => Exception::HardFault, @@ -41,7 +46,163 @@ impl Exception { 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: extern "C" fn(Nmi), + /// All class of fault + pub hard_fault: extern "C" fn(HardFault), + /// Memory management + pub mem_manage: extern "C" fn(MemManage), + /// Pre-fetch fault, memory access fault + pub bus_fault: extern "C" fn(BusFault), + /// Undefined instruction or illegal state + pub usage_fault: extern "C" fn(UsageFault), + /// Reserved spots in the vector table + pub _reserved0: [Reserved; 4], + /// System service call via SWI instruction + pub svcall: extern "C" fn(Svcall), + /// Reserved spots in the vector table + pub _reserved1: [Reserved; 2], + /// Pendable request for system service + pub pendsv: extern "C" fn(Pendsv), + /// System tick timer + pub sys_tick: extern "C" fn(SysTick), +} + +/// Non-maskable interrupt +pub struct Nmi { + _0: (), +} + +/// All class of fault +pub struct HardFault { + _0: (), +} + +/// Memory management +pub struct MemManage { + _0: (), +} + +/// Pre-fetch fault, memory access fault +pub struct BusFault { + _0: (), +} + +/// Undefined instruction or illegal state +pub struct UsageFault { + _0: (), +} + +/// System service call via SWI instruction +pub struct Svcall { + _0: (), +} + +/// Pendable request for system service +pub struct Pendsv { + _0: (), +} + +/// System tick timer +pub struct SysTick { + _0: (), +} + +unsafe impl Context for Nmi {} + +unsafe impl Context for HardFault {} + +unsafe impl Context for MemManage {} + +unsafe impl Context for BusFault {} + +unsafe impl Context for UsageFault {} + +unsafe impl Context for Svcall {} + +unsafe impl Context for Pendsv {} + +unsafe impl Context for SysTick {} + +/// 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 stacked registers +#[naked] +pub extern "C" fn default_handler<T>(_token: T) +where + T: Context, +{ + // This is the actual exception handler. `_sf` is a pointer to the previous + // stack frame + #[cfg(target_arch = "arm")] + extern "C" fn handler(_sr: &StackedRegisters) -> ! { + ::asm::bkpt(); + + loop {} + } + + match () { + #[cfg(target_arch = "arm")] + () => { + unsafe { + // "trampoline" to get to the real exception handler. + asm!("mrs r0, MSP + ldr r1, [r0, #20] + b $0" + : + : "i"(handler as extern "C" fn(&StackedRegisters) -> !) + : + : "volatile"); + + ::core::intrinsics::unreachable() + } } + #[cfg(not(target_arch = "arm"))] + () => {} } } + +/// Registers stacked during an exception +#[repr(C)] +pub struct StackedRegisters { + /// (General purpose) Register 0 + pub r0: u32, + /// (General purpose) Register 1 + pub r1: u32, + /// (General purpose) Register 2 + pub r2: u32, + /// (General purpose) Register 3 + pub r3: u32, + /// (General purpose) Register 12 + pub r12: u32, + /// Linker Register + pub lr: u32, + /// Program Counter + pub pc: u32, + /// Program Status Register + pub xpsr: u32, +} |