summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--nuttx/TODO2
-rw-r--r--nuttx/arch/arm/src/armv7-a/arm_vectors.S394
2 files changed, 363 insertions, 33 deletions
diff --git a/nuttx/TODO b/nuttx/TODO
index a4253845b..3469b8e3c 100644
--- a/nuttx/TODO
+++ b/nuttx/TODO
@@ -1439,7 +1439,7 @@ o ARM (arch/arm/)
Priority: Low
Title: CORTEX-M3 STACK OVERFLOW
- Description: There is bit bit logic inf up_fullcontextrestore() that executes on
+ Description: There is bit bit logic in up_fullcontextrestore() that executes on
return from interrupts (and other context switches) that looks like:
ldr r1, [r0, #(4*REG_CPSR)] /* Fetch the stored CPSR value */
diff --git a/nuttx/arch/arm/src/armv7-a/arm_vectors.S b/nuttx/arch/arm/src/armv7-a/arm_vectors.S
index a5340acb0..bb1cd63f8 100644
--- a/nuttx/arch/arm/src/armv7-a/arm_vectors.S
+++ b/nuttx/arch/arm/src/armv7-a/arm_vectors.S
@@ -57,6 +57,11 @@
g_irqtmp:
.word 0 /* Saved lr */
.word 0 /* Saved spsr */
+#ifdef CONFIG_BUILD_KERNEL
+g_svctmp:
+ .word 0 /* User R13 */
+ .word 0 /* User R14 */
+#endif
g_undeftmp:
.word 0 /* Saved lr */
.word 0 /* Saved spsr */
@@ -123,15 +128,46 @@ arm_vectorirq:
sub sp, sp, #XCPTCONTEXT_SIZE
stmia sp, {r0-r12} /* Save the SVC mode regs */
- /* Get the correct values of r13(sp) and r14(lr) in r1 and r2 */
+ /* Get the values for r15(pc) and CPSR in r3 and r4 */
+
+ ldr r0, .Lirqtmp /* Points to temp storage */
+ ldmia r0, {r3, r4} /* Recover r3=lr_IRQ, r4=spsr_IRQ */
+
+#ifdef CONFIG_BUILD_KERNEL
+ /* Did we enter from user mode? If so then we need get the values of
+ * USER mode r13(sp) and r14(lr) in r1 and r2.
+ */
+
+ and r1, r4, #PSR_MODE_MASK /* Interrupted mode */
+ cmp r1, #PSR_MODE_USR /* User mode? */
+ bne .Lirqentersvc /* Branch if not user mode */
+
+ /* ldmia with ^ will return the user mode registers (provided that r15
+ * is not in the register list).
+ */
+
+ stmia r0, {r13, r14}^ /* Get user mode R13/R14 into scratch area */
+ ldmia r0, {r1, r2} /* Then reload into R1 and R2 */
+ b .Lirqcontinue
+
+.Lirqentersvc:
+ /* Otherwise, get the correct values of SVC r13(sp) and r14(lr) in r1
+ * and r2.
+ */
add r1, sp, #XCPTCONTEXT_SIZE
mov r2, r14
- /* Get the values for r15(pc) and CPSR in r3 and r4 */
+.Lirqcontinue:
- ldr r0, .Lirqtmp /* Points to temp storage */
- ldmia r0, {r3, r4} /* Recover r1=lr_IRQ, r2=spsr_IRQ */
+#else
+ /* Get the correct values of SVC r13(sp) and r14(lr) in r1 and r2 */
+
+ add r1, sp, #XCPTCONTEXT_SIZE
+ mov r2, r14
+#endif
+
+ /* Save r13(sp), r14(lr), r15(pc), and the CPSR */
add r0, sp, #(4*REG_SP) /* Offset to pc, cpsr storage */
stmia r0, {r1-r4}
@@ -163,8 +199,30 @@ arm_vectorirq:
/* Restore the CPSR, SVC mode registers and return */
- ldr r1, [r0, #(4*REG_CPSR)] /* Setup the SVC mode SPSR */
- msr spsr, r1
+ ldr r1, [r0, #(4*REG_CPSR)] /* Setup the return SPSR */
+ msr spsr, r1 /* Establish the return mode SPSR */
+
+#ifdef CONFIG_BUILD_KERNEL
+ /* Did we enter from user mode? If so then we need get the values of
+ * USER mode r13(sp) and r14(lr) in r1 and r2.
+ */
+
+ and r2, r1, #PSR_MODE_MASK /* Interrupted mode */
+ cmp r2, #PSR_MODE_USR /* User mode? */
+ bne .Lirqleavesvc /* Branch if not user mode */
+
+ /* ldmia with ^ will return the user mode registers (provided that r15
+ * is not in the register list).
+ */
+
+ add r1, r0, #(4*REG_R13) /* R1=address of R13/R14 storage */
+ ldmia r1, {r13, r14}^ /* Restore to user mode USER R13/R14 */
+ ldmia r0, {r0-R12,r15}^ /* Return */
+
+.Lirqleavesvc:
+#endif
+ /* Life is simple when everything is SVC mode */
+
ldmia r0, {r0-r15}^ /* Return */
.Lirqtmp:
@@ -197,15 +255,48 @@ arm_vectorsvc:
sub sp, sp, #XCPTCONTEXT_SIZE
stmia sp, {r0-r12} /* Save the SVC mode regs */
- /* Get the correct values of r13(sp), r14(lr), r15(pc)
- * and CPSR in r1-r4.
- */
+ /* Get the values for r15(pc) and CPSR in r3 and r4 */
- add r1, sp, #XCPTCONTEXT_SIZE
- mov r2, r14 /* R14 is altered on return from SVC */
mov r3, r14 /* Save r14 as the PC as well */
mrs r4, spsr /* Get the saved CPSR */
+#ifdef CONFIG_BUILD_KERNEL
+ /* Did we enter from user mode? If so then we need get the values of
+ * USER mode r13(sp) and r14(lr) in r1 and r2.
+ */
+
+ and r1, r4, #PSR_MODE_MASK /* Interrupted mode */
+ cmp r1, #PSR_MODE_USR /* User mode? */
+ bne .Lsvcentersvc /* Branch if not user mode */
+
+ /* ldmia with ^ will return the user mode registers (provided that r15
+ * is not in the register list).
+ */
+
+ ldr r0, .Lsvctmp /* Points to temp storage */
+ stmia r0, {r13, r14}^ /* Get user mode R13/R14 into temp storage */
+ ldmia r0, {r1, r2} /* Then reload into R1 and R2 */
+ b .Lsvccontinue
+
+.Lsvcentersvc:
+ /* Otherwise, get the correct values of SVC r13(sp) and r14(lr) in r1
+ * and r2.
+ */
+
+ add r1, sp, #XCPTCONTEXT_SIZE
+ mov r2, r14
+
+.Lsvccontinue:
+
+#else
+ /* Get the correct values of SVC r13(sp) and r14(lr) in r1 and r2 */
+
+ add r1, sp, #XCPTCONTEXT_SIZE
+ mov r2, r14
+#endif
+
+ /* Save r13(sp), r14(lr), r15(pc), and the CPSR */
+
add r0, sp, #(4*REG_SP) /* Offset to pc, cpsr storage */
stmia r0, {r1-r4}
@@ -229,8 +320,35 @@ arm_vectorsvc:
/* Restore the CPSR, SVC mode registers and return */
ldr r1, [r0, #(4*REG_CPSR)] /* Setup the SVC mode SPSR */
- msr spsr, r1
+ msr spsr, r1 /* Establish the return mode SPSR */
+
+#ifdef CONFIG_BUILD_KERNEL
+ /* Did we enter from user mode? If so then we need get the values of
+ * USER mode r13(sp) and r14(lr) in r1 and r2.
+ */
+
+ and r2, r1, #PSR_MODE_MASK /* Interrupted mode */
+ cmp r2, #PSR_MODE_USR /* User mode? */
+ bne .Lleavesvcsvc /* Branch if not user mode */
+
+ /* ldmia with ^ will return the user mode registers (provided that r15
+ * is not in the register list).
+ */
+
+ add r1, r0, #(4*REG_R13) /* R1=address of R13/R14 storage */
+ ldmia r1, {r13, r14}^ /* Restore to user mode USER R13/R14 */
+ ldmia r0, {r0-R12,r15}^ /* Return */
+
+.Lleavesvcsvc:
+#endif
+ /* Life is simple when everything is SVC mode */
+
ldmia r0, {r0-r15}^ /* Return */
+
+#ifdef CONFIG_BUILD_KERNEL
+.Lsvctmp:
+ .word g_svctmp
+#endif
.size arm_vectorsvc, . - arm_vectorsvc
.align 5
@@ -274,15 +392,46 @@ arm_vectordata:
sub sp, sp, #XCPTCONTEXT_SIZE
stmia sp, {r0-r12} /* Save the SVC mode regs */
- /* Get the correct values of r13(sp) and r14(lr) in r1 and r2 */
+ /* Get the values for r15(pc) and CPSR in r3 and r4 */
+
+ ldr r0, .Ldaborttmp /* Points to temp storage */
+ ldmia r0, {r3, r4} /* Recover r3=lr_ABT, r4=spsr_ABT */
+
+#ifdef CONFIG_BUILD_KERNEL
+ /* Did we enter from user mode? If so then we need get the values of
+ * USER mode r13(sp) and r14(lr) in r1 and r2.
+ */
+
+ and r1, r4, #PSR_MODE_MASK /* Interrupted mode */
+ cmp r1, #PSR_MODE_USR /* User mode? */
+ bne .Ldabtentersvc /* Branch if not user mode */
+
+ /* ldmia with ^ will return the user mode registers (provided that r15
+ * is not in the register list).
+ */
+
+ stmia r0, {r13, r14}^ /* Get user mode R13/R14 into scratch area */
+ ldmia r0, {r1, r2} /* Then reload into R1 and R2 */
+ b .Ldabtcontinue
+
+.Ldabtentersvc:
+ /* Otherwise, get the correct values of SVC r13(sp) and r14(lr) in r1
+ * and r2.
+ */
add r1, sp, #XCPTCONTEXT_SIZE
mov r2, r14
- /* Get the values for r15(pc) and CPSR in r3 and r4 */
+.Ldabtcontinue:
- ldr r0, .Ldaborttmp /* Points to temp storage */
- ldmia r0, {r3, r4} /* Recover r1=lr_IRQ, r2=spsr_IRQ */
+#else
+ /* Get the correct values of SVC r13(sp) and r14(lr) in r1 and r2 */
+
+ add r1, sp, #XCPTCONTEXT_SIZE
+ mov r2, r14
+#endif
+
+ /* Save r13(sp), r14(lr), r15(pc), and the CPSR */
add r0, sp, #(4*REG_SP) /* Offset to pc, cpsr storage */
stmia r0, {r1-r4}
@@ -309,7 +458,29 @@ arm_vectordata:
/* Restore the CPSR, SVC mode registers and return */
ldr r1, [r0, #(4*REG_CPSR)] /* Setup the SVC mode SPSR */
- msr spsr_cxsf, r1
+ msr spsr_cxsf, r1 /* Establish the return mode SPSR */
+
+#ifdef CONFIG_BUILD_KERNEL
+ /* Did we enter from user mode? If so then we need get the values of
+ * USER mode r13(sp) and r14(lr) in r1 and r2.
+ */
+
+ and r2, r1, #PSR_MODE_MASK /* Interrupted mode */
+ cmp r2, #PSR_MODE_USR /* User mode? */
+ bne .Ldabtleavesvc /* Branch if not user mode */
+
+ /* ldmia with ^ will return the user mode registers (provided that r15
+ * is not in the register list).
+ */
+
+ add r1, r0, #(4*REG_R13) /* R1=address of R13/R14 storage */
+ ldmia r1, {r13, r14}^ /* Restore to user mode USER R13/R14 */
+ ldmia r0, {r0-R12,r15}^ /* Return */
+
+.Ldabtleavesvc:
+#endif
+ /* Life is simple when everything is SVC mode */
+
ldmia r0, {r1-r15}^ /* Return */
.Ldaborttmp:
@@ -357,15 +528,46 @@ arm_vectorprefetch:
sub sp, sp, #XCPTCONTEXT_SIZE
stmia sp, {r0-r12} /* Save the SVC mode regs */
- /* Get the correct values of r13(sp) and r14(lr) in r1 and r2 */
+ /* Get the values for r15(pc) and CPSR in r3 and r4 */
+
+ ldr r0, .Lpaborttmp /* Points to temp storage */
+ ldmia r0, {r3, r4} /* Recover r3=lr_ABT, r4=spsr_ABT */
+
+#ifdef CONFIG_BUILD_KERNEL
+ /* Did we enter from user mode? If so then we need get the values of
+ * USER mode r13(sp) and r14(lr) in r1 and r2.
+ */
+
+ and r1, r4, #PSR_MODE_MASK /* Interrupted mode */
+ cmp r1, #PSR_MODE_USR /* User mode? */
+ bne .Lpabtentersvc /* Branch if not user mode */
+
+ /* ldmia with ^ will return the user mode registers (provided that r15
+ * is not in the register list).
+ */
+
+ stmia r0, {r13, r14}^ /* Get user mode R13/R14 into scratch area */
+ ldmia r0, {r1, r2} /* Then reload into R1 and R2 */
+ b .Lpabtcontinue
+
+.Lpabtentersvc:
+ /* Otherwise, get the correct values of SVC r13(sp) and r14(lr) in r1
+ * and r2.
+ */
add r1, sp, #XCPTCONTEXT_SIZE
mov r2, r14
- /* Get the values for r15(pc) and CPSR in r3 and r4 */
+.Lpabtcontinue:
- ldr r0, .Lpaborttmp /* Points to temp storage */
- ldmia r0, {r3, r4} /* Recover r1=lr_IRQ, r2=spsr_IRQ */
+#else
+ /* Get the correct values of SVC r13(sp) and r14(lr) in r1 and r2 */
+
+ add r1, sp, #XCPTCONTEXT_SIZE
+ mov r2, r14
+#endif
+
+ /* Save r13(sp), r14(lr), r15(pc), and the CPSR */
add r0, sp, #(4*REG_SP) /* Offset to pc, cpsr storage */
stmia r0, {r1-r4}
@@ -392,7 +594,29 @@ arm_vectorprefetch:
/* Restore the CPSR, SVC mode registers and return */
ldr r1, [r0, #(4*REG_CPSR)] /* Setup the SVC mode SPSR */
- msr spsr_cxsf, r1
+ msr spsr_cxsf, r1 /* Establish the return mode SPSR */
+
+#ifdef CONFIG_BUILD_KERNEL
+ /* Did we enter from user mode? If so then we need get the values of
+ * USER mode r13(sp) and r14(lr) in r1 and r2.
+ */
+
+ and r2, r1, #PSR_MODE_MASK /* Interrupted mode */
+ cmp r2, #PSR_MODE_USR /* User mode? */
+ bne .Lpabtleavesvc /* Branch if not user mode */
+
+ /* ldmia with ^ will return the user mode registers (provided that r15
+ * is not in the register list).
+ */
+
+ add r1, r0, #(4*REG_R13) /* R1=address of R13/R14 storage */
+ ldmia r1, {r13, r14}^ /* Restore to user mode USER R13/R14 */
+ ldmia r0, {r0-R12,r15}^ /* Return */
+
+.Lpabtleavesvc:
+#endif
+ /* Life is simple when everything is SVC mode */
+
ldmia r0, {r0-r15}^ /* Return */
.Lpaborttmp:
@@ -437,15 +661,46 @@ arm_vectorundefinsn:
sub sp, sp, #XCPTCONTEXT_SIZE
stmia sp, {r0-r12} /* Save the SVC mode regs */
- /* Get the correct values of r13(sp) and r14(lr) in r1 and r2 */
+ /* Get the values for r15(pc) and CPSR in r3 and r4 */
+
+ ldr r0, .Lundeftmp /* Points to temp storage */
+ ldmia r0, {r3, r4} /* Recover r3=lr_UND, r4=spsr_UND */
+
+#ifdef CONFIG_BUILD_KERNEL
+ /* Did we enter from user mode? If so then we need get the values of
+ * USER mode r13(sp) and r14(lr) in r1 and r2.
+ */
+
+ and r1, r4, #PSR_MODE_MASK /* Interrupted mode */
+ cmp r1, #PSR_MODE_USR /* User mode? */
+ bne .Lundefentersvc /* Branch if not user mode */
+
+ /* ldmia with ^ will return the user mode registers (provided that r15
+ * is not in the register list).
+ */
+
+ stmia r0, {r13, r14}^ /* Get user mode R13/R14 into scratch area */
+ ldmia r0, {r1, r2} /* Then reload into R1 and R2 */
+ b .Lundefcontinue
+
+.Lundefentersvc:
+ /* Otherwise, get the correct values of SVC r13(sp) and r14(lr) in r1
+ * and r2.
+ */
add r1, sp, #XCPTCONTEXT_SIZE
mov r2, r14
- /* Get the values for r15(pc) and CPSR in r3 and r4 */
+.Lundefcontinue:
- ldr r0, .Lundeftmp /* Points to temp storage */
- ldmia r0, {r3, r4} /* Recover r1=lr_IRQ, r2=spsr_IRQ */
+#else
+ /* Get the correct values of SVC r13(sp) and r14(lr) in r1 and r2 */
+
+ add r1, sp, #XCPTCONTEXT_SIZE
+ mov r2, r14
+#endif
+
+ /* Save r13(sp), r14(lr), r15(pc), and the CPSR */
add r0, sp, #(4*REG_SP) /* Offset to pc, cpsr storage */
stmia r0, {r1-r4}
@@ -470,7 +725,29 @@ arm_vectorundefinsn:
/* Restore the CPSR, SVC mode registers and return */
ldr r1, [r0, #(4*REG_CPSR)] /* Setup the SVC mode SPSR */
- msr spsr_cxsf, r1
+ msr spsr_cxsf, r1 /* Establish the return mode SPSR */
+
+#ifdef CONFIG_BUILD_KERNEL
+ /* Did we enter from user mode? If so then we need get the values of
+ * USER mode r13(sp) and r14(lr) in r1 and r2.
+ */
+
+ and r2, r1, #PSR_MODE_MASK /* Interrupted mode */
+ cmp r2, #PSR_MODE_USR /* User mode? */
+ bne .Lundefleavesvc /* Branch if not user mode */
+
+ /* ldmia with ^ will return the user mode registers (provided that r15
+ * is not in the register list).
+ */
+
+ add r1, r0, #(4*REG_R13) /* R1=address of R13/R14 storage */
+ ldmia r1, {r13, r14}^ /* Restore to user mode USER R13/R14 */
+ ldmia r0, {r0-R12,r15}^ /* Return */
+
+.Lundefleavesvc:
+#endif
+ /* Life is simple when everything is SVC mode */
+
ldmia r0, {r0-r15}^ /* Return */
.Lundeftmp:
@@ -517,15 +794,46 @@ arm_vectorfiq:
sub sp, sp, #XCPTCONTEXT_SIZE
stmia sp, {r0-r12} /* Save the SVC mode regs */
- /* Get the correct values of r13(sp) and r14(lr) in r1 and r2 */
+ /* Get the values for r15(pc) and CPSR in r3 and r4 */
+
+ ldr r0, .Lfiqtmp /* Points to temp storage */
+ ldmia r0, {r3, r4} /* Recover r3=lr_SVC, r4=spsr_SVC */
+
+#ifdef CONFIG_BUILD_KERNEL
+ /* Did we enter from user mode? If so then we need get the values of
+ * USER mode r13(sp) and r14(lr) in r1 and r2.
+ */
+
+ and r1, r4, #PSR_MODE_MASK /* Interrupted mode */
+ cmp r1, #PSR_MODE_USR /* User mode? */
+ bne .Lfiqentersvc /* Branch if not user mode */
+
+ /* ldmia with ^ will return the user mode registers (provided that r15
+ * is not in the register list).
+ */
+
+ stmia r0, {r13, r14}^ /* Get user mode R13/R14 into scratch area */
+ ldmia r0, {r1, r2} /* Then reload into R1 and R2 */
+ b .Lfiqcontinue
+
+.Lfiqentersvc:
+ /* Otherwise, get the correct values of SVC r13(sp) and r14(lr) in r1
+ * and r2.
+ */
add r1, sp, #XCPTCONTEXT_SIZE
mov r2, r14
- /* Get the values for r15(pc) and CPSR in r3 and r4 */
+.Lfiqcontinue:
- ldr r0, .Lfiqtmp /* Points to temp storage */
- ldmia r0, {r3, r4} /* Recover r1=lr_IRQ, r2=spsr_IRQ */
+#else
+ /* Get the correct values of SVC r13(sp) and r14(lr) in r1 and r2 */
+
+ add r1, sp, #XCPTCONTEXT_SIZE
+ mov r2, r14
+#endif
+
+ /* Save r13(sp), r14(lr), r15(pc), and the CPSR */
add r0, sp, #(4*REG_SP) /* Offset to pc, cpsr storage */
stmia r0, {r1-r4}
@@ -558,7 +866,29 @@ arm_vectorfiq:
/* Restore the CPSR, SVC mode registers and return */
ldr r1, [r0, #(4*REG_CPSR)] /* Setup the SVC mode SPSR */
- msr spsr, r1
+ msr spsr, r1 /* Establish the return mode SPSR */
+
+#ifdef CONFIG_BUILD_KERNEL
+ /* Did we enter from user mode? If so then we need get the values of
+ * USER mode r13(sp) and r14(lr) in r1 and r2.
+ */
+
+ and r2, r1, #PSR_MODE_MASK /* Interrupted mode */
+ cmp r2, #PSR_MODE_USR /* User mode? */
+ bne .Lfiqleavesvc /* Branch if not user mode */
+
+ /* ldmia with ^ will return the user mode registers (provided that r15
+ * is not in the register list).
+ */
+
+ add r1, r0, #(4*REG_R13) /* R1=address of R13/R14 storage */
+ ldmia r1, {r13, r14}^ /* Restore to user mode USER R13/R14 */
+ ldmia r0, {r0-R12,r15}^ /* Return */
+
+.Lfiqleavesvc:
+#endif
+ /* Life is simple when everything is SVC mode */
+
ldmia r0, {r0-r15}^ /* Return */
.Lfiqtmp: