diff --git a/os/ports/RVCT/ARMCMx/chcore_v6m.c b/os/ports/RVCT/ARMCMx/chcore_v6m.c index c0b2922d9..d9765d837 100644 --- a/os/ports/RVCT/ARMCMx/chcore_v6m.c +++ b/os/ports/RVCT/ARMCMx/chcore_v6m.c @@ -28,6 +28,10 @@ #include "ch.h" +/*===========================================================================*/ +/* Port interrupt handlers. */ +/*===========================================================================*/ + /** * @brief System Timer vector. * @details This interrupt is used as system tick. @@ -44,4 +48,81 @@ CH_IRQ_HANDLER(SysTickVector) { CH_IRQ_EPILOGUE(); } +#if !CORTEX_ALTERNATE_SWITCH || defined(__DOXYGEN__) +/** + * @brief NMI vector. + * @details The NMI vector is used for exception mode re-entering after a + * context switch. + */ +void NMIVector(void) { + register struct extctx *ctxp; + register uint32_t psp __asm("psp"); + + /* Discarding the current exception context and positioning the stack to + point to the real one.*/ + ctxp = (struct extctx *)psp; + ctxp++; + psp = (uint32_t)ctxp; + port_unlock_from_isr(); +} +#endif /* !CORTEX_ALTERNATE_SWITCH */ + +#if CORTEX_ALTERNATE_SWITCH || defined(__DOXYGEN__) +/** + * @brief PendSV vector. + * @details The PendSV vector is used for exception mode re-entering after a + * context switch. + */ +void PendSVVector(void) { + register struct extctx *ctxp; + register uint32_t psp __asm("psp"); + + /* Discarding the current exception context and positioning the stack to + point to the real one.*/ + ctxp = (struct extctx *)psp; + ctxp++; + psp = (uint32_t)ctxp; +} +#endif /* CORTEX_ALTERNATE_SWITCH */ + +/*===========================================================================*/ +/* Port exported functions. */ +/*===========================================================================*/ + +/** + * @brief IRQ epilogue code. + * + * @param[in] lr value of the @p LR register on ISR entry + */ +void _port_irq_epilogue(regarm_t lr) { + + if (lr != (regarm_t)0xFFFFFFF1) { + register struct extctx *ctxp; + register uint32_t psp __asm("psp"); + + port_lock_from_isr(); + /* Adding an artificial exception return context, there is no need to + populate it fully.*/ + ctxp = (struct extctx *)psp; + ctxp--; + psp = (uint32_t)ctxp; + ctxp->xpsr = (regarm_t)0x01000000; + + /* The exit sequence is different depending on if a preemption is + required or not.*/ + if (chSchIsPreemptionRequired()) { + /* Preemption is required we need to enforce a context switch.*/ + ctxp->pc = (regarm_t)_port_switch_from_isr; + } + else { + /* Preemption not required, we just need to exit the exception + atomically.*/ + ctxp->pc = (regarm_t)_port_exit_from_isr; + } + + /* Note, returning without unlocking is intentional, this is done in + order to keep the rest of the context switching atomic.*/ + } +} + /** @} */ diff --git a/os/ports/RVCT/ARMCMx/chcore_v6m.h b/os/ports/RVCT/ARMCMx/chcore_v6m.h index be8b7267b..a1477269f 100644 --- a/os/ports/RVCT/ARMCMx/chcore_v6m.h +++ b/os/ports/RVCT/ARMCMx/chcore_v6m.h @@ -41,10 +41,61 @@ */ #define CORTEX_PRIORITY_PENDSV 0 +/*===========================================================================*/ +/* Port macros. */ +/*===========================================================================*/ + /*===========================================================================*/ /* Port configurable parameters. */ /*===========================================================================*/ +/** + * @brief Stack size for the system idle thread. + * @details This size depends on the idle thread implementation, usually + * the idle thread should take no more space than those reserved + * by @p PORT_INT_REQUIRED_STACK. + * @note In this port it is set to 16 because the idle thread does have + * a stack frame when compiling without optimizations. You may + * reduce this value to zero when compiling with optimizations. + */ +#if !defined(PORT_IDLE_THREAD_STACK_SIZE) +#define PORT_IDLE_THREAD_STACK_SIZE 16 +#endif + +/** + * @brief Per-thread stack overhead for interrupts servicing. + * @details This constant is used in the calculation of the correct working + * area size. + * This value can be zero on those architecture where there is a + * separate interrupt stack and the stack space between @p intctx and + * @p extctx is known to be zero. + * @note In this port it is conservatively set to 16 because the function + * @p chSchDoReschedule() can have a stack frame, expecially with + * compiler optimizations disabled. + */ +#if !defined(PORT_INT_REQUIRED_STACK) +#define PORT_INT_REQUIRED_STACK 16 +#endif + +/** + * @brief Enables the use of the WFI instruction in the idle thread loop. + */ +#if !defined(CORTEX_ENABLE_WFI_IDLE) +#define CORTEX_ENABLE_WFI_IDLE FALSE +#endif + +/** + * @brief SYSTICK handler priority. + * @note The default SYSTICK handler priority is calculated as the priority + * level in the middle of the numeric priorities range. + */ +#if !defined(CORTEX_PRIORITY_SYSTICK) +#define CORTEX_PRIORITY_SYSTICK (CORTEX_PRIORITY_LEVELS >> 1) +#elif !CORTEX_IS_VALID_PRIORITY(CORTEX_PRIORITY_SYSTICK) +/* If it is externally redefined then better perform a validity check on it.*/ +#error "invalid priority level specified for CORTEX_PRIORITY_SYSTICK" +#endif + /** * @brief Alternate preemption method. * @details Activating this option will make the Kernel use the PendSV @@ -101,7 +152,18 @@ */ typedef void *regarm_t; +/** + * @brief Stack and memory alignment enforcement. + * @note In this architecture the stack alignment is enforced to 64 bits, + * 32 bits alignment is supported by hardware but deprecated by ARM, + * the implementation choice is to not offer the option. + */ +typedef uint64_t stkalign_t; + + /* The documentation of the following declarations is in chconf.h in order + to not have duplicated structure names into the documentation.*/ #if !defined(__DOXYGEN__) + struct extctx { regarm_t r0; regarm_t r1; @@ -124,7 +186,51 @@ struct intctx { regarm_t r7; regarm_t lr; }; -#endif + +#endif /* !defined(__DOXYGEN__) */ + +/** + * @brief Platform dependent part of the @p Thread structure. + * @details In this port the structure just holds a pointer to the @p intctx + * structure representing the stack pointer at context switch time. + */ +struct context { + struct intctx *r13; +}; + +/** + * @brief Platform dependent part of the @p chThdCreateI() API. + * @details This code usually setup the context switching frame represented + * by an @p intctx structure. + */ +#define SETUP_CONTEXT(workspace, wsize, pf, arg) { \ + tp->p_ctx.r13 = (struct intctx *)((uint8_t *)workspace + \ + wsize - \ + sizeof(struct intctx)); \ + tp->p_ctx.r13->r4 = (regarm_t)pf; \ + tp->p_ctx.r13->r5 = (regarm_t)arg; \ + tp->p_ctx.r13->lr = (regarm_t)_port_thread_start; \ +} + +/** + * @brief Enforces a correct alignment for a stack area size value. + */ +#define STACK_ALIGN(n) ((((n) - 1) | (sizeof(stkalign_t) - 1)) + 1) + +/** + * @brief Computes the thread working area global size. + */ +#define THD_WA_SIZE(n) STACK_ALIGN(sizeof(Thread) + \ + sizeof(struct intctx) + \ + sizeof(struct extctx) + \ + (n) + (PORT_INT_REQUIRED_STACK)) + +/** + * @brief Static working area allocation. + * @details This macro is used to allocate a static thread working area + * aligned as both position and size. + */ +#define WORKING_AREA(s, n) stkalign_t s[THD_WA_SIZE(n) / sizeof(stkalign_t)] /** * @brief IRQ prologue code. @@ -251,9 +357,10 @@ struct intctx { extern "C" { #endif void port_halt(void); - void _port_switch(Thread *ntp, Thread *otp); void _port_irq_epilogue(regarm_t lr); void _port_switch_from_isr(void); + void _port_exit_from_isr(void); + void _port_switch(Thread *ntp, Thread *otp); void _port_thread_start(void); #ifdef __cplusplus } diff --git a/os/ports/RVCT/ARMCMx/chcoreasm_v6m.s b/os/ports/RVCT/ARMCMx/chcoreasm_v6m.s index 83878805e..4bf0570c8 100644 --- a/os/ports/RVCT/ARMCMx/chcoreasm_v6m.s +++ b/os/ports/RVCT/ARMCMx/chcoreasm_v6m.s @@ -25,7 +25,6 @@ #include "chconf.h" #include "chcore.h" -EXTCTX_SIZE EQU 32 CONTEXT_OFFSET EQU 12 SCB_ICSR EQU 0xE000ED04 @@ -34,7 +33,6 @@ SCB_ICSR EQU 0xE000ED04 AREA |.text|, CODE, READONLY IMPORT chThdExit - IMPORT chSchIsPreemptionRequired IMPORT chSchDoReschedule #if CH_DBG_SYSTEM_STATE_CHECK IMPORT dbg_check_unlock @@ -79,51 +77,18 @@ _port_thread_start PROC bl chThdExit ENDP -/* - * NMI vector. - * The NMI vector is used for exception mode re-entering after a context - * switch. - */ -#if !CORTEX_ALTERNATE_SWITCH - EXPORT NMIVector -NMIVector PROC - mrs r3, PSP - adds r3, r3, #32 - msr PSP, r3 - cpsie i - bx lr - ENDP -#endif - -/* - * PendSV vector. - * The PendSV vector is used for exception mode re-entering after a context - * switch. - */ -#if CORTEX_ALTERNATE_SWITCH - EXPORT PendSVVector -PendSVVector PROC - mrs r3, PSP - adds r3, r3, #32 - msr PSP, r3 - bx lr - ENDP -#endif - /* * Post-IRQ switch code. * Exception handlers return here for context switching. */ EXPORT _port_switch_from_isr + EXPORT _port_exit_from_isr _port_switch_from_isr PROC #if CH_DBG_SYSTEM_STATE_CHECK bl dbg_check_lock #endif - bl chSchIsPreemptionRequired - cmp r0, #0 - beq noreschedule bl chSchDoReschedule -noreschedule +_port_exit_from_isr #if CH_DBG_SYSTEM_STATE_CHECK bl dbg_check_unlock #endif @@ -140,25 +105,4 @@ noreschedule waithere b waithere ENDP -/* - * Reschedule verification and setup after an IRQ. - */ - EXPORT _port_irq_epilogue -_port_irq_epilogue PROC - push {lr} - adds r0, r0, #15 - beq skipexit - cpsid i - mrs r3, PSP - subs r3, r3, #32 - msr PSP, r3 - ldr r2, =_port_switch_from_isr - str r2, [r3, #24] - movs r2, #128 - lsls r2, r2, #17 - str r2, [r3, #28] -skipexit - pop {pc} - ENDP - END