aarch32-rt 0.3.0

Run-time support for Arm AArch32
Documentation
//! IRQ handler for for Armv4 to Armv6

use crate::{Cpsr, ProcessorMode};

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

    // Called from the vector table when we have an interrupt.
    // Saves state and calls a C-compatible handler like
    // `extern "C" fn _irq_handler();`
    //
    // See https://developer.arm.com/documentation/dui0203/j/handling-processor-exceptions/armv6-and-earlier--armv7-a-and-armv7-r-profiles/interrupt-handlers
    // for details on how we need to save LR_irq, SPSR_irq and LR_sys.
    .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
        push    {{ lr }}                  // save adjusted LR to IRQ stack
        mrs     lr, spsr                  // The hardware has copied the interrupted task's CPSR to SPSR_irq - grab it and
        push    {{ lr }}                  //   save it to IRQ stack using LR
        msr     cpsr_c, {sys_mode}        // switch to system mode (because if we interrupt in IRQ mode we trash IRQ mode's LR)
        push    {{ lr }}                  // Save LR of system mode before using it for stack alignment
        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
        push    {{ r0-r3, r12, lr }}      // push alignment amount (in LR) and preserved registers
     "#,
    crate::save_fpu_context!(),
    r#"
        bl      _irq_handler              // call C handler (they may choose to re-enable interrupts)
    "#,
    crate::restore_fpu_context!(),
    r#"
        pop     {{ r0-r3, r12, lr }}      // restore alignment amount (in LR) and preserved registers
        add     sp, lr                    // restore SP alignment using LR
        pop     {{ lr }}                  // Restore the actual link register of system mode.
        msr     cpsr_c, {irq_mode}        // switch back to IRQ mode (with IRQ masked)
        pop     {{ lr }}                  // load and restore SPSR using LR
        msr     spsr, lr                  //
        ldmfd   sp!, {{ pc }}^            // return from exception (^ => restore SPSR to CPSR)
    .size _asm_default_irq_handler, . - _asm_default_irq_handler
    .popsection
    "#,
    // sys mode with IRQ masked
    sys_mode = const {
        Cpsr::new_with_raw_value(0)
            .with_mode(ProcessorMode::Sys)
            .with_i(true)
            .raw_value()
    },
    irq_mode = const {
        Cpsr::new_with_raw_value(0)
            .with_mode(ProcessorMode::Irq)
            .with_i(true)
            .raw_value()
    }
);