diff --git a/docs/Doxyfile b/docs/Doxyfile index 13241bf66..c6d918e8c 100644 --- a/docs/Doxyfile +++ b/docs/Doxyfile @@ -31,7 +31,7 @@ PROJECT_NAME = ChibiOS/RT # This could be handy for archiving the generated documentation or # if some version control system is used. -PROJECT_NUMBER = 2.2.2 +PROJECT_NUMBER = 2.2.3 # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) # base path where the generated documentation will be put. diff --git a/os/kernel/include/ch.h b/os/kernel/include/ch.h index 42f623f69..3c43776d2 100644 --- a/os/kernel/include/ch.h +++ b/os/kernel/include/ch.h @@ -46,7 +46,7 @@ /** * @brief Kernel version string. */ -#define CH_KERNEL_VERSION "2.2.2" +#define CH_KERNEL_VERSION "2.2.3" /** * @brief Kernel version major number. @@ -61,7 +61,7 @@ /** * @brief Kernel version patch number. */ -#define CH_KERNEL_PATCH 2 +#define CH_KERNEL_PATCH 3 /* * Common values. diff --git a/os/ports/GCC/ARMCMx/chcore_v6m.c b/os/ports/GCC/ARMCMx/chcore_v6m.c index 66aa8621f..162348385 100644 --- a/os/ports/GCC/ARMCMx/chcore_v6m.c +++ b/os/ports/GCC/ARMCMx/chcore_v6m.c @@ -34,11 +34,6 @@ #include "ch.h" -/** - * @brief PC register temporary storage. - */ -regarm_t _port_saved_pc; - /** * @brief System Timer vector. * @details This interrupt is used as system tick. @@ -55,40 +50,39 @@ CH_IRQ_HANDLER(SysTickVector) { CH_IRQ_EPILOGUE(); } +/** + * @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; + + /* Discarding the current exception context and positioning the stack to + point to the real one.*/ + asm volatile ("mrs %0, PSP" : "=r" (ctxp) : : "memory"); + ctxp++; + asm volatile ("msr PSP, %0" : : "r" (ctxp) : "memory"); + port_unlock_from_isr(); +} + /** * @brief Post-IRQ switch code. - * @details On entry the stack and the registers are restored by the exception - * return, the PC value is stored in @p _port_saved_pc, the interrupts - * are disabled. + * @details The switch is performed in thread context then an NMI exception + * is enforced in order to return to the exact point before the + * preemption. */ #if !defined(__DOXYGEN__) __attribute__((naked)) #endif void _port_switch_from_isr(void) { - /* Note, saves r4 to make space for the PC.*/ - asm volatile ("push {r0, r1, r2, r3, r4} \n\t" - "mrs r0, APSR \n\t" - "mov r1, r12 \n\t" - "push {r0, r1, lr} \n\t" - "ldr r0, =_port_saved_pc \n\t" - "ldr r0, [r0] \n\t" - "add r0, r0, #1 \n\t" - "str r0, [sp, #28]" : : : "memory"); chSchDoRescheduleI(); - - /* Note, the last register is restored alone after re-enabling the - interrupts in order to minimize the (very remote and unlikely) - possibility that the stack is filled by continuous and saturating - interrupts that would not allow that last words to be pulled out of - the stack.*/ - asm volatile ("pop {r0, r1, r2} \n\t" - "mov r12, r1 \n\t" - "msr APSR, r0 \n\t" - "mov lr, r2 \n\t" - "pop {r0, r1, r2, r3} \n\t" - "cpsie i \n\t" - "pop {pc}" : : : "memory"); + SCB_ICSR = ICSR_NMIPENDSET; + /* The following loop should never be executed, the NMI will kick in + immediately.*/ + while (TRUE) + ; } #define PUSH_CONTEXT(sp) { \ @@ -140,6 +134,33 @@ void port_switch(Thread *ntp, Thread *otp) { POP_CONTEXT(r13); } +/** + * @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) { + port_lock_from_isr(); + if (chSchIsRescRequiredExI()) { + register struct extctx *ctxp; + + /* Adding an artificial exception return context, there is no need to + populate it fully.*/ + asm volatile ("mrs %0, PSP" : "=r" (ctxp) : : "memory"); + ctxp--; + asm volatile ("msr PSP, %0" : : "r" (ctxp) : "memory"); + ctxp->pc = _port_switch_from_isr; + ctxp->xpsr = (regarm_t)0x01000000; + /* Note, returning without unlocking is intentional, this is done in + order to keep the rest of the context switching atomic.*/ + return; + } + port_unlock_from_isr(); + } +} + /** * @brief Start a thread by invoking its work function. * @details If the work function returns @p chThdExit() is automatically diff --git a/os/ports/GCC/ARMCMx/chcore_v6m.h b/os/ports/GCC/ARMCMx/chcore_v6m.h index 8199602ad..d495e1f5c 100644 --- a/os/ports/GCC/ARMCMx/chcore_v6m.h +++ b/os/ports/GCC/ARMCMx/chcore_v6m.h @@ -39,10 +39,8 @@ /* Port implementation part. */ /*===========================================================================*/ -/** - * @brief Cortex-Mx exception context. - */ -struct cmxctx { +#if !defined(__DOXYGEN__) +struct extctx { regarm_t r0; regarm_t r1; regarm_t r2; @@ -53,18 +51,6 @@ struct cmxctx { regarm_t xpsr; }; -#if !defined(__DOXYGEN__) -struct extctx { - regarm_t xpsr; - regarm_t r12; - regarm_t lr; - regarm_t r0; - regarm_t r1; - regarm_t r2; - regarm_t r3; - regarm_t pc; -}; - struct intctx { regarm_t r8; regarm_t r9; @@ -134,20 +120,7 @@ struct intctx { * @details This macro must be inserted at the end of all IRQ handlers * enabled to invoke system APIs. */ -#define PORT_IRQ_EPILOGUE() { \ - if (_saved_lr != (regarm_t)0xFFFFFFF1) { \ - port_lock_from_isr(); \ - if (chSchIsRescRequiredExI()) { \ - register struct cmxctx *ctxp; \ - \ - asm volatile ("mrs %0, PSP" : "=r" (ctxp) : ); \ - _port_saved_pc = ctxp->pc; \ - ctxp->pc = _port_switch_from_isr; \ - return; \ - } \ - port_unlock_from_isr(); \ - } \ -} +#define PORT_IRQ_EPILOGUE() _port_irq_epilogue(_saved_lr) /** * @brief IRQ handler function declaration. @@ -233,15 +206,12 @@ struct intctx { #define port_wait_for_interrupt() #endif -#if !defined(__DOXYGEN__) -extern regarm_t _port_saved_pc; -#endif - #ifdef __cplusplus 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_thread_start(void); #ifdef __cplusplus diff --git a/readme.txt b/readme.txt index fb2f1cb5a..92c2a5f3d 100644 --- a/readme.txt +++ b/readme.txt @@ -68,6 +68,13 @@ *** Releases *** ***************************************************************************** +*** 2.2.3 *** +- NEW: Improved preemption implementation for the Cortex-M0, now it uses + the NMI vector in order to restore the original context. The change makes + IRQ handling faster and also saves some RAM/ROM space. The GCC port code + now does not inline the epilogue code in each ISR saving significant ROM + space for each interrupt handler in the system. + *** 2.2.2 *** - FIX: Fixed race condition in CM0 ports, the fix also improves the ISR latency (bug 3193062).