summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGregory Nutt <gnutt@nuttx.org>2014-09-12 08:04:27 -0600
committerGregory Nutt <gnutt@nuttx.org>2014-09-12 08:04:27 -0600
commitde19ad5f0c7bfba50bde0136c4dd8037b72859f1 (patch)
treeb0c0c317682c3a1474a484340b6eb2ad433ed4be
parent30dc5ca366058b3004dd42900e6b11c3f8c84634 (diff)
downloadnuttx-de19ad5f0c7bfba50bde0136c4dd8037b72859f1.tar.gz
nuttx-de19ad5f0c7bfba50bde0136c4dd8037b72859f1.tar.bz2
nuttx-de19ad5f0c7bfba50bde0136c4dd8037b72859f1.zip
ARMv7-A: Modify up_fullcontextrestore() for CONFIG_BUILD_KERNEL. It changed CPSR while in kernel. That will crash is the new CPSR is user mode while executing in kernel space. Fixed by adding a SYS_context_restore system call. There is an alternative, simpler modification to up_fullcontextrestore() that could have been done: It might have been possible to use the SPSR instead of the CPRSR and then do an exception return from up_fullcontextrestore(). That would be more efficient, but I never tried it.
-rw-r--r--nuttx/arch/arm/src/armv7-a/arm_fullcontextrestore.S27
-rw-r--r--nuttx/arch/arm/src/armv7-a/arm_syscall.c40
-rw-r--r--nuttx/arch/arm/src/armv7-a/crt0.c2
-rw-r--r--nuttx/arch/arm/src/armv7-a/svcall.h27
-rw-r--r--nuttx/configs/sama5d4-ek/knsh/defconfig2
-rw-r--r--nuttx/configs/sama5d4-ek/knsh/defconfig.ROMFS2
6 files changed, 79 insertions, 21 deletions
diff --git a/nuttx/arch/arm/src/armv7-a/arm_fullcontextrestore.S b/nuttx/arch/arm/src/armv7-a/arm_fullcontextrestore.S
index b1885a778..f6de34b98 100644
--- a/nuttx/arch/arm/src/armv7-a/arm_fullcontextrestore.S
+++ b/nuttx/arch/arm/src/armv7-a/arm_fullcontextrestore.S
@@ -37,8 +37,10 @@
* Included Files
****************************************************************************/
+#include <nuttx/config.h>
#include <nuttx/irq.h>
#include "up_internal.h"
+#include "svcall.h"
.file "arm_fullcontextrestore.S"
@@ -112,6 +114,28 @@ up_fullcontextrestore:
vmsr fpscr, r2 /* Restore the FPCSR */
#endif
+#ifdef CONFIG_BUILD_KERNEL
+ /* For the kernel build, we need to be able to transition gracefully
+ * between kernel- and user-mode tasks. We have to do that with a system
+ * call; the system call will execute in kernel mode and but can return
+ * to either user or kernel mode.
+ */
+
+ /* Perform the System call with R0=SYS_context_restore, R1=restoreregs */
+
+ mov r1, r0 /* R1: restoreregs */
+ mov r0, #SYS_context_restore /* R0: SYS_context_restore syscall */
+ svc #0x900001 /* Perform the system call */
+
+ /* This call should not return */
+
+ bx lr /* Unnecessary ... will not return */
+
+#else
+ /* For a flat build, we can do all of this here... Just think of this as
+ * a longjmp() all on steriods.
+ */
+
/* Recover all registers except for r0, r1, R15, and CPSR */
add r1, r0, #(4*REG_R2) /* Offset to REG_R2 storage */
@@ -148,4 +172,7 @@ up_fullcontextrestore:
*/
ldr pc, [sp], #4
+
+#endif
+
.size up_fullcontextrestore, . - up_fullcontextrestore
diff --git a/nuttx/arch/arm/src/armv7-a/arm_syscall.c b/nuttx/arch/arm/src/armv7-a/arm_syscall.c
index eeb8c1fdd..b5f803402 100644
--- a/nuttx/arch/arm/src/armv7-a/arm_syscall.c
+++ b/nuttx/arch/arm/src/armv7-a/arm_syscall.c
@@ -58,16 +58,16 @@
****************************************************************************/
/* Debug ********************************************************************/
-/* Output debug info if stack dump is selected -- even if
- * debug is not selected.
- */
-
-#if defined(CONFIG_DEBUG_SYSCALL) || defined(CONFIG_DEBUG_SVCALL)
+#if defined(CONFIG_DEBUG_SYSCALL)
# define svcdbg(format, ...) lldbg(format, ##__VA_ARGS__)
#else
# define svcdbg(x...)
#endif
+/* Output debug info if stack dump is selected -- even if debug is not
+ * selected.
+ */
+
#ifdef CONFIG_ARCH_STACKDUMP
# undef lldbg
# define lldbg lowsyslog
@@ -229,6 +229,30 @@ uint32_t *arm_syscall(uint32_t *regs)
}
break;
+ /* R0=SYS_context_restore: Restore task context
+ *
+ * void up_fullcontextrestore(uint32_t *restoreregs) noreturn_function;
+ *
+ * At this point, the following values are saved in context:
+ *
+ * R0 = SYS_context_restore
+ * R1 = restoreregs
+ */
+
+#ifdef CONFIG_BUILD_KERNEL
+ case SYS_context_restore:
+ {
+ /* Replace 'regs' with the pointer to the register set in
+ * regs[REG_R1]. On return from the system call, that register
+ * set will determine the restored context.
+ */
+
+ regs = (uint32_t *)regs[REG_R1];
+ DEBUGASSERT(regs);
+ }
+ break;
+#endif
+
/* R0=SYS_task_start: This a user task start
*
* void up_task_start(main_t taskentry, int argc, FAR char *argv[]) noreturn_function;
@@ -427,9 +451,9 @@ uint32_t *arm_syscall(uint32_t *regs)
svcdbg("CPSR: %08x\n", regs[REG_CPSR]);
#endif
- /* Return the last value of curent_regs. This supports context switchs
- * on return from the exception. That capability is not used here,
- * however.
+ /* Return the last value of curent_regs. This supports context switches
+ * on return from the exception. That capability is only used with the
+ * SYS_context_switch system call.
*/
return regs;
diff --git a/nuttx/arch/arm/src/armv7-a/crt0.c b/nuttx/arch/arm/src/armv7-a/crt0.c
index 2127ab2ed..cfa00e7b1 100644
--- a/nuttx/arch/arm/src/armv7-a/crt0.c
+++ b/nuttx/arch/arm/src/armv7-a/crt0.c
@@ -101,7 +101,7 @@ static void sig_trampoline(void)
" blx ip\n" /* Call the signal handler */
" pop {r2}\n" /* Recover LR in R2 */
" mov lr, r2\n" /* Restore LR */
- " mov r0, #4\n" /* SYS_signal_handler_return */
+ " mov r0, #5\n" /* SYS_signal_handler_return */
" svc #0x900001\n" /* Return from the signal handler */
);
}
diff --git a/nuttx/arch/arm/src/armv7-a/svcall.h b/nuttx/arch/arm/src/armv7-a/svcall.h
index 5253e27b9..513299c17 100644
--- a/nuttx/arch/arm/src/armv7-a/svcall.h
+++ b/nuttx/arch/arm/src/armv7-a/svcall.h
@@ -60,9 +60,9 @@
#ifdef CONFIG_BUILD_KERNEL
# ifndef CONFIG_SYS_RESERVED
-# error "CONFIG_SYS_RESERVED must be defined to have the value 5"
-# elif CONFIG_SYS_RESERVED != 5
-# error "CONFIG_SYS_RESERVED must have the value 5"
+# error "CONFIG_SYS_RESERVED must be defined to have the value 6"
+# elif CONFIG_SYS_RESERVED != 6
+# error "CONFIG_SYS_RESERVED must have the value 6"
# endif
#else
# ifndef CONFIG_SYS_RESERVED
@@ -84,34 +84,41 @@
#ifdef CONFIG_BUILD_KERNEL
/* SYS call 1:
*
+ * void up_fullcontextrestore(uint32_t *restoreregs) noreturn_function;
+ */
+
+#define SYS_context_restore (1)
+
+/* SYS call 2:
+ *
* void up_task_start(main_t taskentry, int argc, FAR char *argv[])
* noreturn_function;
*/
-#define SYS_task_start (1)
+#define SYS_task_start (2)
-/* SYS call 2:
+/* SYS call 3:
*
* void up_pthread_start(pthread_startroutine_t entrypt, pthread_addr_t arg)
* noreturn_function
*/
-#define SYS_pthread_start (2)
+#define SYS_pthread_start (3)
-/* SYS call 3:
+/* SYS call 4:
*
* void signal_handler(_sa_sigaction_t sighand, int signo, FAR siginfo_t *info,
* FAR void *ucontext);
*/
-#define SYS_signal_handler (3)
+#define SYS_signal_handler (4)
-/* SYS call 4:
+/* SYS call 5:
*
* void signal_handler_return(void);
*/
-#define SYS_signal_handler_return (4)
+#define SYS_signal_handler_return (5)
#endif /* CONFIG_BUILD_KERNEL */
diff --git a/nuttx/configs/sama5d4-ek/knsh/defconfig b/nuttx/configs/sama5d4-ek/knsh/defconfig
index 37daf0d0c..6c933b367 100644
--- a/nuttx/configs/sama5d4-ek/knsh/defconfig
+++ b/nuttx/configs/sama5d4-ek/knsh/defconfig
@@ -455,7 +455,7 @@ CONFIG_USERMAIN_STACKSIZE=2048
CONFIG_PTHREAD_STACK_MIN=256
CONFIG_PTHREAD_STACK_DEFAULT=2048
CONFIG_LIB_SYSCALL=y
-CONFIG_SYS_RESERVED=5
+CONFIG_SYS_RESERVED=6
CONFIG_SYS_NNEST=2
#
diff --git a/nuttx/configs/sama5d4-ek/knsh/defconfig.ROMFS b/nuttx/configs/sama5d4-ek/knsh/defconfig.ROMFS
index d52473f33..0252ea21c 100644
--- a/nuttx/configs/sama5d4-ek/knsh/defconfig.ROMFS
+++ b/nuttx/configs/sama5d4-ek/knsh/defconfig.ROMFS
@@ -438,7 +438,7 @@ CONFIG_USERMAIN_STACKSIZE=2048
CONFIG_PTHREAD_STACK_MIN=256
CONFIG_PTHREAD_STACK_DEFAULT=2048
CONFIG_LIB_SYSCALL=y
-CONFIG_SYS_RESERVED=5
+CONFIG_SYS_RESERVED=6
CONFIG_SYS_NNEST=2
#