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:
parent
4ebca78ada
commit
56ce985e7f
|
@ -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.
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue