cortex-m 0.2.4

Low level access to Cortex-M processors
Documentation
//! 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
    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 unsafe { (*::peripheral::SCB.get()).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: 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. `_sr` is a pointer to the previous
    // stack frame
    #[cfg(target_arch = "arm")]
    extern "C" fn handler(_sr: &StackedRegisters) -> ! {
        // What exception is currently being serviced
        let _e = Exception::current();

        ::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,
}