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
/// Generate entry points for [`::cortex_m_rt`]. **Requires [`EntryPoint`]
/// and [`KernelTraits`] to be implemented.**
///
/// [`EntryPoint`]: crate::EntryPoint
/// [`KernelTraits`]: r3_kernel::KernelTraits
///
/// This macro registers the following items:
///
///  - The entry function (`#[cortex_m_rt::entry]`).
///  - The SysTick handler (`SysTick` global symbol).
///  - The PendSV handler (`PendSV` global symbol).
///  - Interrupt handlers and the vector table (`__INTERRUPTS` global symbol).
///
#[macro_export]
macro_rules! use_rt {
    (unsafe $Traits:ty) => {
        const _: () = {
            use $crate::{
                r3_kernel::KernelCfg2, rt::imp::ExceptionTrampoline, EntryPoint, INTERRUPT_SYSTICK,
            };
            #[link_section = ".vector_table.interrupts"]
            #[no_mangle]
            static __INTERRUPTS: $crate::rt::imp::InterruptHandlerTable =
                $crate::rt::imp::make_interrupt_handler_table::<$Traits>();
            #[$crate::cortex_m_rt::entry]
            fn main() -> ! {
                // Register `HANDLE_PEND_SV` as the PendSV handler under `cortex_m_rt`'s regime.
                //
                // `PEND_SV_TRAMPOLINE` contains the trampoline code. However, since it's not
                // recognized the linker as a Thumb function, its address does not have its least
                // significant bit set to mark a Thumb function. So we set the bit here.
                unsafe {
                    ::core::arch::asm!(
                        "
                            .global PendSV
                            PendSV = {} + 1
                        ",
                        sym PEND_SV_TRAMPOLINE
                    );
                }
                // `<$Traits as EntryPoint>::HANDLE_PEND_SV` contains the address of the PendSV
                // handler. Ideally we would like to simply assign the symbol address like the
                // following:
                //
                //     asm!(".global PendSV\n PendSV = {}", const HANDLE_PEND_SV);
                //
                // However, this does not work because `const` inputs do not currently accept
                // function pointers. So we assemble a trampoline function using a carefully
                // laid out `struct`.  The outcome is something like this:
                //
                //     .global PEND_SV_TRAMPOLINE
                //     PEND_SV_TRAMPOLINE:
                //         ldr pc, =(value of HANDLE_PEND_SV)
                //
                #[link_section = ".text"]
                static PEND_SV_TRAMPOLINE: ExceptionTrampoline =
                    ExceptionTrampoline::new(<$Traits as EntryPoint>::HANDLE_PEND_SV);
                unsafe { <$Traits as EntryPoint>::start() };
            }
            #[$crate::cortex_m_rt::exception]
            fn SysTick() {
                if let Some(x) = <$Traits as KernelCfg2>::INTERRUPT_HANDLERS.get(INTERRUPT_SYSTICK)
                {
                    // Safety: It's a first-level interrupt handler here. CPU Lock inactive
                    unsafe { x() };
                }
            }
        };
    };
}