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() };
                }
            }
        };
    };
}