Add support for nested system calls

git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@5752 42af7a65-404d-4744-a932-0658087f49c3
This commit is contained in:
patacongo 2013-03-17 16:13:28 +00:00
parent 4ebca78ada
commit 56ce985e7f
8 changed files with 140 additions and 38 deletions

View File

@ -4356,4 +4356,9 @@
system call (2013-03-16).
* arch/arm/src/armv[6|7]-m/up_schedulesigaction.c: Need make sure we are
in kernel mode before switching to kernel-mode signal handler
trampoline.
trampoline (2013-03-16).
* arch/arm/include/armv[6|7]-m/irq.h, and arch/arm/src/armv[6|7]-m/up_svcall.c:
Add support for nested system calls. In the current design, this can
happen only under one condition: When the kernel system function calls
back into user space in order to allocate user space memory. So it is
expected that the maximum nesting level will be only 2.

View File

@ -57,8 +57,14 @@
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/* Configuration ************************************************************/
/* If this is a kernel build, how many nested system calls should we support? */
/* IRQ Stack Frame Format:
#ifndef CONFIG_SYS_NNEST
# define CONFIG_SYS_NNEST 2
#endif
/* IRQ Stack Frame Format ***************************************************
*
* The following additional registers are stored by the interrupt handling
* logic.
@ -140,11 +146,22 @@
* Public Types
****************************************************************************/
#ifndef __ASSEMBLY__
/* This structure represents the return state from a system call */
#ifdef CONFIG_NUTTX_KERNEL
struct xcpt_syscall_s
{
uint32_t excreturn; /* The EXC_RETURN value */
uint32_t sysreturn; /* The return PC */
};
#endif
/* The following structure is included in the TCB and defines the complete
* state of the thread.
*/
#ifndef __ASSEMBLY__
struct xcptcontext
{
#ifndef CONFIG_DISABLE_SIGNALS
@ -168,16 +185,17 @@ struct xcptcontext
*/
uint32_t sigreturn;
# endif
#endif
#ifdef CONFIG_NUTTX_KERNEL
/* The following holds the return address and the exc_return value needed
* to return from a system call.
/* The following array holds the return address and the exc_return value
* needed to return from each nested system call.
*/
uint32_t excreturn;
uint32_t sysreturn;
uint8_t nsyscalls;
struct xcpt_syscall_s syscall[CONFIG_SYS_NNEST];
#endif
/* Register save area */

View File

@ -67,8 +67,14 @@
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/* Configuration ************************************************************/
/* If this is a kernel build, how many nested system calls should we support? */
/* Alternate register names */
#ifndef CONFIG_SYS_NNEST
# define CONFIG_SYS_NNEST 2
#endif
/* Alternate register names *************************************************/
#define REG_A1 REG_R0
#define REG_A2 REG_R1
@ -98,12 +104,22 @@
/****************************************************************************
* Public Types
****************************************************************************/
#ifndef __ASSEMBLY__
/* This structure represents the return state from a system call */
#ifdef CONFIG_NUTTX_KERNEL
struct xcpt_syscall_s
{
uint32_t excreturn; /* The EXC_RETURN value */
uint32_t sysreturn; /* The return PC */
};
#endif
/* The following structure is included in the TCB and defines the complete
* state of the thread.
*/
#ifndef __ASSEMBLY__
struct xcptcontext
{
#ifndef CONFIG_DISABLE_SIGNALS
@ -131,16 +147,18 @@ struct xcptcontext
*/
uint32_t sigreturn;
# endif
#endif
#ifdef CONFIG_NUTTX_KERNEL
/* The following holds the return address and the exc_return value needed
* to return from a system call.
/* The following array holds the return address and the exc_return value
* needed to return from each nested system call.
*/
uint32_t excreturn;
uint32_t sysreturn;
uint8_t nsyscalls;
struct xcpt_syscall_s syscall[CONFIG_SYS_NNEST];
#endif
/* Register save area */

View File

@ -258,18 +258,19 @@ int up_svcall(int irq, FAR void *context)
case SYS_syscall_return:
{
struct tcb_s *rtcb = sched_self();
int index = (int)rtcb->xcp.nsyscalls - 1;
/* Make sure that there is a saved syscall return address. */
DEBUGASSERT(rtcb->xcp.sysreturn != 0);
DEBUGASSERT(index >= 0);
/* Setup to return to the saved syscall return address in
* the original mode.
*/
regs[REG_PC] = rtcb->xcp.sysreturn;
regs[REG_EXC_RETURN] = rtcb->xcp.excreturn;
rtcb->xcp.sysreturn = 0;
regs[REG_PC] = rtcb->xcp.syscall[index].sysreturn;
regs[REG_EXC_RETURN] = rtcb->xcp.syscall[index].excreturn;
rtcb->xcp.nsyscalls = index;
/* The return value must be in R0-R1. dispatch_syscall() temporarily
* moved the value for R0 into R2.
@ -425,6 +426,7 @@ int up_svcall(int irq, FAR void *context)
{
#ifdef CONFIG_NUTTX_KERNEL
FAR struct tcb_s *rtcb = sched_self();
int index = rtcb->xcp.nsyscalls;
/* Verify that the SYS call number is within range */
@ -434,19 +436,20 @@ int up_svcall(int irq, FAR void *context)
* cannot yet handle nested system calls.
*/
DEBUGASSERT(rtcb->xcp.sysreturn == 0);
DEBUGASSERT(index < CONFIG_SYS_NNEST);
/* Setup to return to dispatch_syscall in privileged mode. */
rtcb->xcp.sysreturn = regs[REG_PC];
rtcb->xcp.excreturn = regs[REG_EXC_RETURN];
rtcb->xcp.syscall[index].sysreturn = regs[REG_PC];
rtcb->xcp.syscall[index].excreturn = regs[REG_EXC_RETURN];
rtcb->xcp.nsyscalls = index + 1;
regs[REG_PC] = (uint32_t)dispatch_syscall;
regs[REG_EXC_RETURN] = EXC_RETURN_PRIVTHR;
/* Offset R0 to account for the reserved values */
regs[REG_R0] -= CONFIG_SYS_RESERVED;
regs[REG_R0] -= CONFIG_SYS_RESERVED;
#else
slldbg("ERROR: Bad SYS call: %d\n", regs[REG_R0]);
#endif

View File

@ -262,18 +262,19 @@ int up_svcall(int irq, FAR void *context)
case SYS_syscall_return:
{
struct tcb_s *rtcb = sched_self();
int index = (int)rtcb->xcp.nsyscalls - 1;
/* Make sure that there is a saved syscall return address. */
DEBUGASSERT(rtcb->xcp.sysreturn != 0);
DEBUGASSERT(index >= 0);
/* Setup to return to the saved syscall return address in
* the original mode.
*/
regs[REG_PC] = rtcb->xcp.sysreturn;
regs[REG_EXC_RETURN] = rtcb->xcp.excreturn;
rtcb->xcp.sysreturn = 0;
regs[REG_PC] = rtcb->xcp.syscall[index].sysreturn;
regs[REG_EXC_RETURN] = rtcb->xcp.syscall[index].excreturn;
rtcb->xcp.nsyscalls = index;
/* The return value must be in R0-R1. dispatch_syscall() temporarily
* moved the value for R0 into R2.
@ -429,6 +430,7 @@ int up_svcall(int irq, FAR void *context)
{
#ifdef CONFIG_NUTTX_KERNEL
FAR struct tcb_s *rtcb = sched_self();
int index = rtcb->xcp.nsyscalls;
/* Verify that the SYS call number is within range */
@ -438,19 +440,20 @@ int up_svcall(int irq, FAR void *context)
* cannot yet handle nested system calls.
*/
DEBUGASSERT(rtcb->xcp.sysreturn == 0);
DEBUGASSERT(index < CONFIG_SYS_NNEST);
/* Setup to return to dispatch_syscall in privileged mode. */
rtcb->xcp.sysreturn = regs[REG_PC];
rtcb->xcp.excreturn = regs[REG_EXC_RETURN];
rtcb->xcp.syscall[index].sysreturn = regs[REG_PC];
rtcb->xcp.syscall[index].excreturn = regs[REG_EXC_RETURN];
rtcb->xcp.nsyscalls = index + 1;
regs[REG_PC] = (uint32_t)dispatch_syscall;
regs[REG_EXC_RETURN] = EXC_RETURN_PRIVTHR;
/* Offset R0 to account for the reserved values */
regs[REG_R0] -= CONFIG_SYS_RESERVED;
regs[REG_R0] -= CONFIG_SYS_RESERVED;
#else
slldbg("ERROR: Bad SYS call: %d\n", regs[REG_R0]);
#endif

View File

@ -61,6 +61,12 @@
# define MIPS32_SAVE_GP 1
#endif
/* If this is a kernel build, how many nested system calls should we support? */
#ifndef CONFIG_SYS_NNEST
# define CONFIG_SYS_NNEST 2
#endif
/* Register save state structure ********************************************/
/* Co processor registers */
@ -308,6 +314,19 @@
#ifndef __ASSEMBLY__
/* This structure represents the return state from a system call */
#ifdef CONFIG_NUTTX_KERNEL
struct xcpt_syscall_s
{
uint32_t sysreturn; /* The return PC */
};
#endif
/* The following structure is included in the TCB and defines the complete
* state of the thread.
*/
struct xcptcontext
{
#ifndef CONFIG_DISABLE_SIGNALS
@ -323,12 +342,25 @@ struct xcptcontext
uint32_t saved_epc; /* Trampoline PC */
uint32_t saved_status; /* Status with interrupts disabled. */
# ifdef CONFIG_NUTTX_KERNEL
/* This is the saved address to use when returning from a user-space
* signal handler.
*/
uint32_t sigreturn;
# endif
#endif
#ifdef CONFIG_NUTTX_KERNEL
/* The following holds the return address from a system call */
/* The following array holds information needed to return from each nested
* system call.
*/
uint8_t nsyscalls;
struct xcpt_syscall_s syscall[CONFIG_SYS_NNEST];
uint32_t sysreturn;
#endif
/* Register save area */

View File

@ -238,18 +238,19 @@ int up_swint0(int irq, FAR void *context)
case SYS_syscall_return:
{
struct tcb_s *rtcb = sched_self();
int index = (int)rtcb->xcp.nsyscalls - 1;
/* Make sure that there is a saved syscall return address. */
DEBUGASSERT(rtcb->xcp.sysreturn != 0);
DEBUGASSERT(index >= 0);
/* Setup to return to the saved syscall return address in
* the original mode.
*/
current_regs[REG_EPC] = rtcb->xcp.sysreturn;
current_regs[REG_EPC] = rtcb->xcp.syscall[index].sysreturn;
#error "Missing logic -- need to restore the original mode"
rtcb->sysreturn = 0;
rtcb->xcp.nsyscalls = index;
}
break;
#endif
@ -263,6 +264,7 @@ int up_swint0(int irq, FAR void *context)
{
#ifdef CONFIG_NUTTX_KERNEL
FAR struct tcb_s *rtcb = sched_self();
int index = rtcb->xcp.nsyscalls;
/* Verify that the SYS call number is within range */
@ -272,17 +274,20 @@ int up_swint0(int irq, FAR void *context)
* return address. We cannot yet handle nested system calls.
*/
DEBUGASSERT(rtcb->xcp.sysreturn == 0);
DEBUGASSERT(index < CONFIG_SYS_NNEST);
/* Setup to return to dispatch_syscall in privileged mode. */
rtcb->sysreturn = regs[REG_EPC];
regs[REG_EPC] = (uint32_t)dispatch_syscall;
rtcb->xcpsyscall[index].sysreturn = regs[REG_EPC];
#error "Missing logic -- Need to save mode"
rtcb->xcp.nsyscalls = index + 1;
regs[REG_EPC] = (uint32_t)dispatch_syscall;
#error "Missing logic -- Need to set privileged mode"
/* Offset R0 to account for the reserved values */
current_regs[REG_R0] -= CONFIG_SYS_RESERVED;
current_regs[REG_R0] -= CONFIG_SYS_RESERVED;
#else
slldbg("ERROR: Bad SYS call: %d\n", regs[REG_A0]);
#endif

View File

@ -5,6 +5,8 @@
if NUTTX_KERNEL
comment "System call configuration"
config SYS_RESERVED
int "Number of reserved system calls"
default 0
@ -16,4 +18,20 @@ config SYS_RESERVED
architecture; number of the kernel system calls will begin with this
number.
config SYS_NNEST
int "Number of nested system calls"
default 2
---help---
This is architecture dependent. Most architectures allocate
resources to manage a fixed, maximum number of nested system calls.
A nested system call occurs in the following scenario: (1) A non-
privileged user thread executes a system call, (2) part of the
system call processing cause a call back into the user space code,
and (3) the user space code performs another system call.
In the current design, this can happen only under one condition:
When the kernel calls back into user space in order to allocate user
space memory. So it is expected that the maximum nesting level will
be only 2.
endif