mirror of
https://github.com/apache/nuttx.git
synced 2026-06-01 16:59:28 +08:00
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:
@@ -37,8 +37,10 @@
|
|||||||
* Included Files
|
* Included Files
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
|
#include <nuttx/config.h>
|
||||||
#include <nuttx/irq.h>
|
#include <nuttx/irq.h>
|
||||||
#include "up_internal.h"
|
#include "up_internal.h"
|
||||||
|
#include "svcall.h"
|
||||||
|
|
||||||
.file "arm_fullcontextrestore.S"
|
.file "arm_fullcontextrestore.S"
|
||||||
|
|
||||||
@@ -112,6 +114,28 @@ up_fullcontextrestore:
|
|||||||
vmsr fpscr, r2 /* Restore the FPCSR */
|
vmsr fpscr, r2 /* Restore the FPCSR */
|
||||||
#endif
|
#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 */
|
/* Recover all registers except for r0, r1, R15, and CPSR */
|
||||||
|
|
||||||
add r1, r0, #(4*REG_R2) /* Offset to REG_R2 storage */
|
add r1, r0, #(4*REG_R2) /* Offset to REG_R2 storage */
|
||||||
@@ -148,4 +172,7 @@ up_fullcontextrestore:
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
ldr pc, [sp], #4
|
ldr pc, [sp], #4
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
.size up_fullcontextrestore, . - up_fullcontextrestore
|
.size up_fullcontextrestore, . - up_fullcontextrestore
|
||||||
|
|||||||
@@ -58,16 +58,16 @@
|
|||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
/* Debug ********************************************************************/
|
/* Debug ********************************************************************/
|
||||||
|
|
||||||
/* Output debug info if stack dump is selected -- even if
|
#if defined(CONFIG_DEBUG_SYSCALL)
|
||||||
* debug is not selected.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#if defined(CONFIG_DEBUG_SYSCALL) || defined(CONFIG_DEBUG_SVCALL)
|
|
||||||
# define svcdbg(format, ...) lldbg(format, ##__VA_ARGS__)
|
# define svcdbg(format, ...) lldbg(format, ##__VA_ARGS__)
|
||||||
#else
|
#else
|
||||||
# define svcdbg(x...)
|
# define svcdbg(x...)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* Output debug info if stack dump is selected -- even if debug is not
|
||||||
|
* selected.
|
||||||
|
*/
|
||||||
|
|
||||||
#ifdef CONFIG_ARCH_STACKDUMP
|
#ifdef CONFIG_ARCH_STACKDUMP
|
||||||
# undef lldbg
|
# undef lldbg
|
||||||
# define lldbg lowsyslog
|
# define lldbg lowsyslog
|
||||||
@@ -229,6 +229,30 @@ uint32_t *arm_syscall(uint32_t *regs)
|
|||||||
}
|
}
|
||||||
break;
|
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
|
/* R0=SYS_task_start: This a user task start
|
||||||
*
|
*
|
||||||
* void up_task_start(main_t taskentry, int argc, FAR char *argv[]) noreturn_function;
|
* 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]);
|
svcdbg("CPSR: %08x\n", regs[REG_CPSR]);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Return the last value of curent_regs. This supports context switchs
|
/* Return the last value of curent_regs. This supports context switches
|
||||||
* on return from the exception. That capability is not used here,
|
* on return from the exception. That capability is only used with the
|
||||||
* however.
|
* SYS_context_switch system call.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
return regs;
|
return regs;
|
||||||
|
|||||||
@@ -101,7 +101,7 @@ static void sig_trampoline(void)
|
|||||||
" blx ip\n" /* Call the signal handler */
|
" blx ip\n" /* Call the signal handler */
|
||||||
" pop {r2}\n" /* Recover LR in R2 */
|
" pop {r2}\n" /* Recover LR in R2 */
|
||||||
" mov lr, r2\n" /* Restore LR */
|
" 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 */
|
" svc #0x900001\n" /* Return from the signal handler */
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -60,9 +60,9 @@
|
|||||||
|
|
||||||
#ifdef CONFIG_BUILD_KERNEL
|
#ifdef CONFIG_BUILD_KERNEL
|
||||||
# ifndef CONFIG_SYS_RESERVED
|
# ifndef CONFIG_SYS_RESERVED
|
||||||
# error "CONFIG_SYS_RESERVED must be defined to have the value 5"
|
# error "CONFIG_SYS_RESERVED must be defined to have the value 6"
|
||||||
# elif CONFIG_SYS_RESERVED != 5
|
# elif CONFIG_SYS_RESERVED != 6
|
||||||
# error "CONFIG_SYS_RESERVED must have the value 5"
|
# error "CONFIG_SYS_RESERVED must have the value 6"
|
||||||
# endif
|
# endif
|
||||||
#else
|
#else
|
||||||
# ifndef CONFIG_SYS_RESERVED
|
# ifndef CONFIG_SYS_RESERVED
|
||||||
@@ -83,35 +83,42 @@
|
|||||||
|
|
||||||
#ifdef CONFIG_BUILD_KERNEL
|
#ifdef CONFIG_BUILD_KERNEL
|
||||||
/* SYS call 1:
|
/* 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[])
|
* void up_task_start(main_t taskentry, int argc, FAR char *argv[])
|
||||||
* noreturn_function;
|
* 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)
|
* void up_pthread_start(pthread_startroutine_t entrypt, pthread_addr_t arg)
|
||||||
* noreturn_function
|
* 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,
|
* void signal_handler(_sa_sigaction_t sighand, int signo, FAR siginfo_t *info,
|
||||||
* FAR void *ucontext);
|
* FAR void *ucontext);
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define SYS_signal_handler (3)
|
#define SYS_signal_handler (4)
|
||||||
|
|
||||||
/* SYS call 4:
|
/* SYS call 5:
|
||||||
*
|
*
|
||||||
* void signal_handler_return(void);
|
* void signal_handler_return(void);
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define SYS_signal_handler_return (4)
|
#define SYS_signal_handler_return (5)
|
||||||
|
|
||||||
#endif /* CONFIG_BUILD_KERNEL */
|
#endif /* CONFIG_BUILD_KERNEL */
|
||||||
|
|
||||||
|
|||||||
@@ -455,7 +455,7 @@ CONFIG_USERMAIN_STACKSIZE=2048
|
|||||||
CONFIG_PTHREAD_STACK_MIN=256
|
CONFIG_PTHREAD_STACK_MIN=256
|
||||||
CONFIG_PTHREAD_STACK_DEFAULT=2048
|
CONFIG_PTHREAD_STACK_DEFAULT=2048
|
||||||
CONFIG_LIB_SYSCALL=y
|
CONFIG_LIB_SYSCALL=y
|
||||||
CONFIG_SYS_RESERVED=5
|
CONFIG_SYS_RESERVED=6
|
||||||
CONFIG_SYS_NNEST=2
|
CONFIG_SYS_NNEST=2
|
||||||
|
|
||||||
#
|
#
|
||||||
|
|||||||
@@ -438,7 +438,7 @@ CONFIG_USERMAIN_STACKSIZE=2048
|
|||||||
CONFIG_PTHREAD_STACK_MIN=256
|
CONFIG_PTHREAD_STACK_MIN=256
|
||||||
CONFIG_PTHREAD_STACK_DEFAULT=2048
|
CONFIG_PTHREAD_STACK_DEFAULT=2048
|
||||||
CONFIG_LIB_SYSCALL=y
|
CONFIG_LIB_SYSCALL=y
|
||||||
CONFIG_SYS_RESERVED=5
|
CONFIG_SYS_RESERVED=6
|
||||||
CONFIG_SYS_NNEST=2
|
CONFIG_SYS_NNEST=2
|
||||||
|
|
||||||
#
|
#
|
||||||
|
|||||||
Reference in New Issue
Block a user