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