aboutsummaryrefslogtreecommitdiffstats
path: root/os/ports/GCC
diff options
context:
space:
mode:
authorgdisirio <gdisirio@35acf78f-673a-0410-8e92-d51de3d6d3f4>2011-03-06 08:02:26 +0000
committergdisirio <gdisirio@35acf78f-673a-0410-8e92-d51de3d6d3f4>2011-03-06 08:02:26 +0000
commit3cc5ac6d9a6555ba70ea83c9eb9cae1bb1f44fd9 (patch)
treecd540ec3b5dc1b737388870ddd2c45efdde9067e /os/ports/GCC
parent645fce5f28b5d62b682657ec8d6c3fcf775b9f08 (diff)
downloadChibiOS-3cc5ac6d9a6555ba70ea83c9eb9cae1bb1f44fd9.tar.gz
ChibiOS-3cc5ac6d9a6555ba70ea83c9eb9cae1bb1f44fd9.tar.bz2
ChibiOS-3cc5ac6d9a6555ba70ea83c9eb9cae1bb1f44fd9.zip
Improved preemption for Cortex-M0 port.
git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@2797 35acf78f-673a-0410-8e92-d51de3d6d3f4
Diffstat (limited to 'os/ports/GCC')
-rw-r--r--os/ports/GCC/ARMCMx/chcore_v6m.c54
-rw-r--r--os/ports/GCC/ARMCMx/chcore_v6m.h30
2 files changed, 35 insertions, 49 deletions
diff --git a/os/ports/GCC/ARMCMx/chcore_v6m.c b/os/ports/GCC/ARMCMx/chcore_v6m.c
index 4e49e6256..5004b2256 100644
--- a/os/ports/GCC/ARMCMx/chcore_v6m.c
+++ b/os/ports/GCC/ARMCMx/chcore_v6m.c
@@ -28,11 +28,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.
* @note The timer must be initialized in the startup code.
@@ -49,39 +44,38 @@ CH_IRQ_HANDLER(SysTickVector) {
}
/**
+ * @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) { \
diff --git a/os/ports/GCC/ARMCMx/chcore_v6m.h b/os/ports/GCC/ARMCMx/chcore_v6m.h
index bb20cb4be..89fbdbec6 100644
--- a/os/ports/GCC/ARMCMx/chcore_v6m.h
+++ b/os/ports/GCC/ARMCMx/chcore_v6m.h
@@ -32,10 +32,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;
@@ -46,18 +44,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;
@@ -131,11 +117,17 @@ struct intctx {
if (_saved_lr != (regarm_t)0xFFFFFFF1) { \
port_lock_from_isr(); \
if (chSchIsRescRequiredExI()) { \
- register struct cmxctx *ctxp; \
+ register struct extctx *ctxp; \
\
- asm volatile ("mrs %0, PSP" : "=r" (ctxp) : ); \
- _port_saved_pc = ctxp->pc; \
+ /* 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(); \