diff options
author | Gregory Nutt <gnutt@nuttx.org> | 2014-09-12 08:04:27 -0600 |
---|---|---|
committer | Gregory Nutt <gnutt@nuttx.org> | 2014-09-12 08:04:27 -0600 |
commit | de19ad5f0c7bfba50bde0136c4dd8037b72859f1 (patch) | |
tree | b0c0c317682c3a1474a484340b6eb2ad433ed4be | |
parent | 30dc5ca366058b3004dd42900e6b11c3f8c84634 (diff) | |
download | nuttx-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.S | 27 | ||||
-rw-r--r-- | nuttx/arch/arm/src/armv7-a/arm_syscall.c | 40 | ||||
-rw-r--r-- | nuttx/arch/arm/src/armv7-a/crt0.c | 2 | ||||
-rw-r--r-- | nuttx/arch/arm/src/armv7-a/svcall.h | 27 | ||||
-rw-r--r-- | nuttx/configs/sama5d4-ek/knsh/defconfig | 2 | ||||
-rw-r--r-- | nuttx/configs/sama5d4-ek/knsh/defconfig.ROMFS | 2 |
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 # |