diff options
author | Gregory Nutt <gnutt@nuttx.org> | 2014-09-15 11:38:48 -0600 |
---|---|---|
committer | Gregory Nutt <gnutt@nuttx.org> | 2014-09-15 11:38:48 -0600 |
commit | 8fc8a50b327626fb6bf3e034e5ad9494f6d3f418 (patch) | |
tree | fcf74e3dbb41493ce9e1fecdbb1051955b131e5e | |
parent | 0f95d236d32cb70cdb1114ef67fc682c42406e3d (diff) | |
download | nuttx-8fc8a50b327626fb6bf3e034e5ad9494f6d3f418.tar.gz nuttx-8fc8a50b327626fb6bf3e034e5ad9494f6d3f418.tar.bz2 nuttx-8fc8a50b327626fb6bf3e034e5ad9494f6d3f418.zip |
If we are configured to use a kernel stack while in SYSCALL handling, then we need to switch back to the user stack to deliver a signal
-rwxr-xr-x | nuttx/arch/arm/include/armv7-a/irq.h | 3 | ||||
-rw-r--r-- | nuttx/arch/arm/src/armv7-a/arm_syscall.c | 42 |
2 files changed, 45 insertions, 0 deletions
diff --git a/nuttx/arch/arm/include/armv7-a/irq.h b/nuttx/arch/arm/include/armv7-a/irq.h index 3813e919a..5688593ff 100755 --- a/nuttx/arch/arm/include/armv7-a/irq.h +++ b/nuttx/arch/arm/include/armv7-a/irq.h @@ -296,6 +296,9 @@ struct xcptcontext FAR uint32_t *ustkptr; /* Saved user stack pointer */ FAR uint32_t *kstack; /* Allocate base of the (aligned) kernel stack */ +#ifndef CONFIG_DISABLE_SIGNALS + FAR uint32_t *kstkptr; /* Saved kernel stack pointer */ +#endif #endif #endif }; diff --git a/nuttx/arch/arm/src/armv7-a/arm_syscall.c b/nuttx/arch/arm/src/armv7-a/arm_syscall.c index 7be976ae0..fdd05badb 100644 --- a/nuttx/arch/arm/src/armv7-a/arm_syscall.c +++ b/nuttx/arch/arm/src/armv7-a/arm_syscall.c @@ -352,6 +352,9 @@ uint32_t *arm_syscall(uint32_t *regs) case SYS_signal_handler: { FAR struct tcb_s *rtcb = sched_self(); +#ifdef CONFIG_ARCH_KERNEL_STACK + int depth; +#endif /* Remember the caller's return address */ @@ -379,6 +382,24 @@ uint32_t *arm_syscall(uint32_t *regs) */ regs[REG_R3] = *(uint32_t*)(regs[REG_SP]+4); + +#ifdef CONFIG_ARCH_KERNEL_STACK + /* If this is a nested SYSCALL and if there is an allocated kernel + * stack, then we must be operating on the kernal stack now. We + * need to switch back to the user stack before dispatching the + * signal handler to the user code. + */ + + depth = rtcb->xcp.nsyscalls; + if (depth > 0 && rtcb->xcp.kstack != NULL) + { + DEBUGASSERT(rtcb->xcp.kstkptr == NULL && + rtcb->xcp.ustkptr[depth - 1] != 0); + + rtcb->xcp.kstkptr = (FAR uint32_t *)regs[REG_SP]; + regs[REG_SP] = (uint32_t)rtcb->xcp.ustkptr[depth - 1]; + } +#endif } break; #endif @@ -396,6 +417,9 @@ uint32_t *arm_syscall(uint32_t *regs) case SYS_signal_handler_return: { FAR struct tcb_s *rtcb = sched_self(); +#ifdef CONFIG_ARCH_KERNEL_STACK + int depth; +#endif /* Set up to return to the kernel-mode signal dispatching logic. */ @@ -405,6 +429,24 @@ uint32_t *arm_syscall(uint32_t *regs) cpsr = regs[REG_CPSR] & ~PSR_MODE_MASK; regs[REG_CPSR] = cpsr | PSR_MODE_SVC; rtcb->xcp.sigreturn = 0; + +#ifdef CONFIG_ARCH_KERNEL_STACK + /* If this is a nested SYSCALL and if there is an allocated kernel + * stack, we must be using the user stack to dispatch to the signal + * handler. We need to switch to back to the kernel user stack + * before returning to the kernel mode signal trampoline. + */ + + depth = rtcb->xcp.nsyscalls; + if (depth > 0 && rtcb->xcp.kstack != NULL) + { + DEBUGASSERT(rtcb->xcp.kstkptr != NULL && + (uint32_t)rtcb->xcp.ustkptr[depth - 1] == regs[REG_SP]); + + regs[REG_SP] = (uint32_t)rtcb->xcp.kstkptr; + rtcb->xcp.kstkptr = NULL; + } +#endif } break; #endif |