diff --git a/arch/arm/include/armv6-m/irq.h b/arch/arm/include/armv6-m/irq.h index 75aed8ff180..f4b026c4181 100644 --- a/arch/arm/include/armv6-m/irq.h +++ b/arch/arm/include/armv6-m/irq.h @@ -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 */ diff --git a/arch/arm/include/armv7-m/irq.h b/arch/arm/include/armv7-m/irq.h index afeebdb4fed..663a703e3b5 100644 --- a/arch/arm/include/armv7-m/irq.h +++ b/arch/arm/include/armv7-m/irq.h @@ -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 */ diff --git a/arch/arm/src/armv6-m/up_svcall.c b/arch/arm/src/armv6-m/up_svcall.c index 74580053287..cf9396414f8 100644 --- a/arch/arm/src/armv6-m/up_svcall.c +++ b/arch/arm/src/armv6-m/up_svcall.c @@ -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 diff --git a/arch/arm/src/armv7-m/up_svcall.c b/arch/arm/src/armv7-m/up_svcall.c index ab313671c6a..e41b8c4c58c 100644 --- a/arch/arm/src/armv7-m/up_svcall.c +++ b/arch/arm/src/armv7-m/up_svcall.c @@ -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 diff --git a/arch/mips/include/mips32/irq.h b/arch/mips/include/mips32/irq.h index 22fa6c75e0e..8a3a713521c 100644 --- a/arch/mips/include/mips32/irq.h +++ b/arch/mips/include/mips32/irq.h @@ -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 */ diff --git a/arch/mips/src/mips32/up_swint0.c b/arch/mips/src/mips32/up_swint0.c index 7be82a9e77e..34a8a1dded9 100644 --- a/arch/mips/src/mips32/up_swint0.c +++ b/arch/mips/src/mips32/up_swint0.c @@ -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