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.
This commit is contained in:
parent
5a96bc37e4
commit
f8170550e1
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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 */
|
||||
);
|
||||
}
|
||||
|
@ -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
|
||||
@ -83,35 +83,42 @@
|
||||
|
||||
#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 */
|
||||
|
||||
|
@ -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
|
||||
|
||||
#
|
||||
|
@ -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
|
||||
|
||||
#
|
||||
|
Loading…
Reference in New Issue
Block a user