aarch32-rt 0.4.0

Run-time support for Arm AArch32
Documentation
//! IRQ handler for for Armv7 and higher

#[cfg(target_arch = "arm")]
core::arch::global_asm!(
    r#"
    // Work around https://github.com/rust-lang/rust/issues/127269
    .fpu vfp3

    // Called from the vector table when we have an interrupt. Saves state and
    // calls a C-compatible handler like `extern "C" fn _irq_handler();` in
    // system mode (or SVC mode if the `svc-stack-interrupt` feature is
    // enabled).
    //
    // We call the C-compatible handler in a different mode because when when an
    // IRQ occurs, the PC is copied to LR_irq immediately. If the C code was
    // running in IRQ mode, then it will be using LR_irq for normal LR things
    // (because that's the LR register when you are in IRQ mode). Instantly
    // trashing the LR register of running code is bad. So, by switching to SYS
    // mode (or SVC mode) we ensure that LR_irq is always unused at the point an
    // IRQ occurs.
    //
    // Because this is ARMv7, we can save state (SPSR_irq and LR_irq) straight
    // to another mode's stack, meaning that we never actually push anything to
    // the IRQ stack. You can therefore run with an IRQ stack size of zero.
    //
    // See [ARM Cortex-R Series (Armv7-R) Programmer's Guide] for more details.
    //
    // [ARM Cortex-R Series (Armv7-R) Programmer's Guide]:
    //     https://developer.arm.com/documentation/den0042/0100/Exceptions-and-Interrupts/External-interrupt-requests/Nested-interrupt-handling
    .pushsection .text._asm_default_irq_handler
    .arm
    .global _asm_default_irq_handler
    .type _asm_default_irq_handler, %function
    _asm_default_irq_handler:
        sub     lr, lr, 4                 // Make sure we jump back to the right place
        srsfd   sp!, #{handler_mode}      // Store return state to the handler stack (1)
        cps     #{handler_mode}           // Switch to handler mode (2)
        push    {{ lr }}                  // Push adjusted LR to handler mode stack (3)
        and     lr, sp, 7                 // Align SP down to eight byte boundary using LR
        sub     sp, lr                    // SP now aligned - only push 64-bit values from here (4)
        push    {{ r0-r3, r12, lr }}      // Push alignment amount (in LR) and preserved registers (5)
     "#,
    crate::fpu_context!("save"),
    r#"
        bl      _irq_handler              // Call C handler (they may choose to re-enable interrupts)
    "#,
    crate::fpu_context!("restore"),
    r#"
        pop     {{ r0-r3, r12, lr }}      // Pop alignment amount (in LR) and preserved registers to undo (5)
        add     sp, lr                    // Restore SP alignment using LR to undo (4)
        pop     {{ lr }}                  // Pop adjusted LR to undo (3)
        rfefd   sp!                       // Return from exception to undo (2) and (1) together
    .size _asm_default_irq_handler, . - _asm_default_irq_handler
    .popsection
    "#,
    handler_mode = const HANDLER_MODE,
);

#[cfg(feature = "svc-stack-interrupt")]
const HANDLER_MODE: u8 = crate::ProcessorMode::Svc as u8;

#[cfg(not(feature = "svc-stack-interrupt"))]
const HANDLER_MODE: u8 = crate::ProcessorMode::Sys as u8;