summaryrefslogtreecommitdiff
path: root/nuttx/arch/arm/src/lpc17xx/lpc17_vectors.S
diff options
context:
space:
mode:
Diffstat (limited to 'nuttx/arch/arm/src/lpc17xx/lpc17_vectors.S')
-rwxr-xr-xnuttx/arch/arm/src/lpc17xx/lpc17_vectors.S93
1 files changed, 68 insertions, 25 deletions
diff --git a/nuttx/arch/arm/src/lpc17xx/lpc17_vectors.S b/nuttx/arch/arm/src/lpc17xx/lpc17_vectors.S
index 7a25c5610..4cfa9a3ce 100755
--- a/nuttx/arch/arm/src/lpc17xx/lpc17_vectors.S
+++ b/nuttx/arch/arm/src/lpc17xx/lpc17_vectors.S
@@ -220,7 +220,8 @@ handlers:
HANDLER lpc17_usbact, LPC17_IRQ_USBACT /* Vector 16+33: USB Activity Interrupt */
HANDLER lpc17_canact, LPC17_IRQ_CANACT /* Vector 16+34: CAN Activity Interrupt */
-/* Common IRQ handling logic. On entry here, the stack is like the following:
+/* Common IRQ handling logic. On entry here, the return stack is on either
+ * the PSP or the MSP and looks like the following:
*
* REG_XPSR
* REG_R15
@@ -231,18 +232,38 @@ handlers:
* REG_R1
* MSP->REG_R0
*
- * and R0 contains the IRQ number
+ * And
+ * R0 contains the IRQ number
+ * R14 Contains the EXC_RETURN value
+ * We are in handler mode and the current SP is the MSP
*/
lpc17_common:
/* Complete the context save */
+#ifdef CONFIG_NUTTX_KERNEL
+ /* The EXC_RETURN value will be 0xfffffff9 (privileged thread) or 0xfffffff1
+ * (handler mode) if the state is on the MSP. It can only be on the PSP if
+ * EXC_RETURN is 0xfffffffd (unprivileged thread)
+ */
+
+ adds r2, r14, #3 /* If R14=0xfffffffd, then r2 == 0 */
+ ite ne /* Next two instructions are condition */
+ mrsne r1, msp /* R1=The main stack pointer */
+ mrseq r1, psp /* R1=The process stack pointer */
+#else
mrs r1, msp /* R1=The main stack pointer */
- mov r2, r1 /* R2=Copy of the main stack pointer */
- add r2, #HW_XCPT_SIZE /* R2=MSP before the interrupt was taken */
+#endif
+
+ mov r2, r1 /* R2=Copy of the main/process stack pointer */
+ add r2, #HW_XCPT_SIZE /* R2=MSP/PSP before the interrupt was taken */
mrs r3, primask /* R3=Current PRIMASK setting */
+#ifdef CONFIG_NUTTX_KERNEL
+ stmdb r1!, {r2-r11,r14} /* Save the remaining registers plus the SP value */
+#else
stmdb r1!, {r2-r11} /* Save the remaining registers plus the SP value */
+#endif
/* Disable interrupts, select the stack to use for interrupt handling
* and call up_doirq to handle the interrupt
@@ -257,13 +278,13 @@ lpc17_common:
#if CONFIG_ARCH_INTERRUPTSTACK > 3
ldr sp, =g_intstackbase
- str r1, [sp, #-4]! /* Save the MSP on the interrupt stack */
- bl up_doirq /* R0=IRQ, R1=register save (msp) */
- ldr r1, [sp, #+4]! /* Recover R1=main stack pointer */
+ str r1, [sp, #-4]! /* Save the MSP on the interrupt stack */
+ bl up_doirq /* R0=IRQ, R1=register save (msp) */
+ ldr r1, [sp, #+4]! /* Recover R1=main stack pointer */
#else
- mov sp, r1 /* We are using the main stack pointer */
- bl up_doirq /* R0=IRQ, R1=register save (msp) */
- mov r1, sp /* Recover R1=main stack pointer */
+ mov sp, r1 /* We are using the main stack pointer */
+ bl up_doirq /* R0=IRQ, R1=register save (msp) */
+ mov r1, sp /* Recover R1=main stack pointer */
#endif
/* On return from up_doirq, R0 will hold a pointer to register context
@@ -271,8 +292,8 @@ lpc17_common:
* as current stack pointer, then things are relatively easy.
*/
- cmp r0, r1 /* Context switch? */
- beq 1f /* Branch if no context switch */
+ cmp r0, r1 /* Context switch? */
+ beq 1f /* Branch if no context switch */
/* We are returning with a pending context switch. This case is different
* because in this case, the register save structure does not lie on the
@@ -280,34 +301,56 @@ lpc17_common:
* values to the stack.
*/
- add r1, r0, #SW_XCPT_SIZE /* R1=Address of HW save area in reg array */
- ldmia r1, {r4-r11} /* Fetch eight registers in HW save area */
+ add r1, r0, #SW_XCPT_SIZE /* R1=Address of HW save area in reg array */
+ ldmia r1, {r4-r11} /* Fetch eight registers in HW save area */
ldr r1, [r0, #(4*REG_SP)] /* R1=Value of SP before interrupt */
- stmdb r1!, {r4-r11} /* Store eight registers in HW save area */
- ldmia r0, {r2-r11} /* Recover R4-R11 + 2 temp values */
- b 2f /* Re-join common logic */
+ stmdb r1!, {r4-r11} /* Store eight registers in HW save area */
+#ifdef CONFIG_NUTTX_KERNEL
+ ldmia r0, {r2-r11,r14} /* Recover R4-R11, r14 + 2 temp values */
+#else
+ ldmia r0, {r2-r11} /* Recover R4-R11 + 2 temp values */
+#endif
+ b 2f /* Re-join common logic */
/* We are returning with no context switch. We simply need to "unwind"
* the same stack frame that we created
*/
1:
- ldmia r1!, {r2-r11} /* Recover R4-R11 + 2 temp values */
+#ifdef CONFIG_NUTTX_KERNEL
+ ldmia r0, {r2-r11,r14} /* Recover R4-R11, r14 + 2 temp values */
+#else
+ ldmia r0, {r2-r11} /* Recover R4-R11 + 2 temp values */
+#endif
2:
- msr msp, r1 /* Recover the return MSP value */
+#ifdef CONFIG_NUTTX_KERNEL
+ /* The EXC_RETURN value will be 0xfffffff9 (privileged thread) or 0xfffffff1
+ * (handler mode) if the state is on the MSP. It can only be on the PSP if
+ * EXC_RETURN is 0xfffffffd (unprivileged thread)
+ */
+
+ adds r0, r14, #3 /* If R14=0xfffffffd, then r0 == 0 */
+ ite ne /* Next two instructions are condition */
+ msrne msp, r1 /* R1=The main stack pointer */
+ msreq psp, r1 /* R1=The process stack pointer */
+#else
+ msr msp, r1 /* Recover the return MSP value */
- /* Restore the interrupt state. Preload r14 with the special return
- * value first (so that the return actually occurs with interrupts
- * still disabled).
+ /* Preload r14 with the special return value first (so that the return
+ * actually occurs with interrupts still disabled).
*/
- ldr r14, =EXC_RETURN /* Load the special value */
- msr primask, r3 /* Restore interrupts */
+ ldr r14, =EXC_RETURN /* Load the special value */
+#endif
+
+ /* Restore the interrupt state */
+
+ msr primask, r3 /* Restore interrupts */
/* Always return with R14 containing the special value that will: (1)
* return to thread mode, and (2) continue to use the MSP
*/
- bx r14 /* And return */
+ bx r14 /* And return */
.size handlers, .-handlers
/************************************************************************************************