From b3890db5ce9ba89fd984441284e1b2428c9a9130 Mon Sep 17 00:00:00 2001 From: patacongo Date: Sun, 17 Mar 2013 00:40:49 +0000 Subject: [PATCH] Add support for calling to and returning from signal handlers in in user-mode threads git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@5750 42af7a65-404d-4744-a932-0658087f49c3 --- arch/arm/include/armv6-m/irq.h | 8 ++ arch/arm/include/armv6-m/syscall.h | 26 ++++++ arch/arm/include/armv7-m/irq.h | 8 ++ arch/arm/include/armv7-m/syscall.h | 26 ++++++ arch/arm/src/armv6-m/svcall.h | 39 ++++++--- arch/arm/src/armv6-m/up_sigdeliver.c | 2 +- arch/arm/src/armv6-m/up_svcall.c | 74 +++++++++++++++- arch/arm/src/armv7-m/svcall.h | 39 ++++++--- arch/arm/src/armv7-m/up_sigdeliver.c | 2 +- arch/arm/src/armv7-m/up_svcall.c | 74 +++++++++++++++- arch/arm/src/common/up_signal_handler.c | 100 +++++++++++++++++++++ arch/arm/src/common/up_task_start.c | 3 +- arch/arm/src/lpc17xx/Make.defs | 3 + arch/arm/src/sam3u/Make.defs | 3 + configs/open1788/kernel/up_userspace.c | 9 +- configs/open1788/knsh/defconfig | 2 +- configs/sam3u-ek/kernel/up_userspace.c | 8 +- configs/sam3u-ek/knsh/defconfig | 2 +- include/nuttx/arch.h | 64 +++++++++++++- include/nuttx/sched.h | 40 --------- include/nuttx/userspace.h | 77 ++++++++++++++++- include/signal.h | 19 ++-- libc/pthread/pthread_startup.c | 2 +- libc/sched/task_startup.c | 2 +- libc/signal/Make.defs | 4 + libc/signal/signal_handler.c | 110 ++++++++++++++++++++++++ sched/sig_deliver.c | 21 ++++- 27 files changed, 679 insertions(+), 88 deletions(-) create mode 100644 arch/arm/src/common/up_signal_handler.c create mode 100644 libc/signal/signal_handler.c diff --git a/arch/arm/include/armv6-m/irq.h b/arch/arm/include/armv6-m/irq.h index db5c829138..75aed8ff18 100644 --- a/arch/arm/include/armv6-m/irq.h +++ b/arch/arm/include/armv6-m/irq.h @@ -161,6 +161,14 @@ struct xcptcontext uint32_t saved_pc; uint32_t saved_basepri; uint32_t saved_xpsr; + +# 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 diff --git a/arch/arm/include/armv6-m/syscall.h b/arch/arm/include/armv6-m/syscall.h index f92dea7e83..9548ae4942 100644 --- a/arch/arm/include/armv6-m/syscall.h +++ b/arch/arm/include/armv6-m/syscall.h @@ -54,8 +54,22 @@ * Pro-processor Definitions ****************************************************************************/ +/* This is the value used as the argument to the SVC instruction. It is not + * used. + */ + #define SYS_syscall 0x00 +/* The SYS_signal_handler_return is executed here... its value is not always + * available in this context and so is assumed to be 7. + */ + +#ifndef SYS_signal_handler_return +# define SYS_signal_handler_return (7) +#elif SYS_signal_handler_return != 7 +# error "SYS_signal_handler_return was assumed to be 7" +#endif + /**************************************************************************** * Public Types ****************************************************************************/ @@ -218,6 +232,18 @@ static inline uintptr_t sys_call6(unsigned int nbr, uintptr_t parm1, return reg0; } +/* This inline function is used by user-space code in order to return from + * a signal handler. + */ + +#if defined(CONFIG_NUTTX_KERNEL) && !defined(__KERNEL__) +static inline void signal_handler_return(void) noreturn_function; +static inline void signal_handler_return(void) +{ + sys_call0(SYS_signal_handler_return); +} +#endif + /**************************************************************************** * Public Variables ****************************************************************************/ diff --git a/arch/arm/include/armv7-m/irq.h b/arch/arm/include/armv7-m/irq.h index 7556d07473..afeebdb4fe 100644 --- a/arch/arm/include/armv7-m/irq.h +++ b/arch/arm/include/armv7-m/irq.h @@ -124,6 +124,14 @@ struct xcptcontext uint32_t saved_primask; #endif uint32_t saved_xpsr; + +# 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 diff --git a/arch/arm/include/armv7-m/syscall.h b/arch/arm/include/armv7-m/syscall.h index 4278c3a36b..91220f3591 100644 --- a/arch/arm/include/armv7-m/syscall.h +++ b/arch/arm/include/armv7-m/syscall.h @@ -54,8 +54,22 @@ * Pro-processor Definitions ****************************************************************************/ +/* This is the value used as the argument to the SVC instruction. It is not + * used. + */ + #define SYS_syscall 0x00 +/* The SYS_signal_handler_return is executed here... its value is not always + * available in this context and so is assumed to be 7. + */ + +#ifndef SYS_signal_handler_return +# define SYS_signal_handler_return (7) +#elif SYS_signal_handler_return != 7 +# error "SYS_signal_handler_return was assumed to be 7" +#endif + /**************************************************************************** * Public Types ****************************************************************************/ @@ -218,6 +232,18 @@ static inline uintptr_t sys_call6(unsigned int nbr, uintptr_t parm1, return reg0; } +/* This inline function is used by user-space code in order to return from + * a signal handler. + */ + +#if defined(CONFIG_NUTTX_KERNEL) && !defined(__KERNEL__) +static inline void signal_handler_return(void) noreturn_function; +static inline void signal_handler_return(void) +{ + sys_call0(SYS_signal_handler_return); +} +#endif + /**************************************************************************** * Public Variables ****************************************************************************/ diff --git a/arch/arm/src/armv6-m/svcall.h b/arch/arm/src/armv6-m/svcall.h index c7f2013fce..daa70a0c0e 100644 --- a/arch/arm/src/armv6-m/svcall.h +++ b/arch/arm/src/armv6-m/svcall.h @@ -57,9 +57,9 @@ #ifdef CONFIG_NUTTX_KERNEL # ifndef CONFIG_SYS_RESERVED -# error "CONFIG_SYS_RESERVED must be defined to the value 6" -# elif CONFIG_SYS_RESERVED != 6 -# error "CONFIG_SYS_RESERVED must have the value 6" +# error "CONFIG_SYS_RESERVED must be defined to have the value 8" +# elif CONFIG_SYS_RESERVED != 8 +# error "CONFIG_SYS_RESERVED must have the value 8" # endif #endif @@ -70,21 +70,21 @@ * int up_saveusercontext(uint32_t *saveregs); */ -#define SYS_save_context (0) +#define SYS_save_context (0) /* SYS call 1: * * void up_fullcontextrestore(uint32_t *restoreregs) noreturn_function; */ -#define SYS_restore_context (1) +#define SYS_restore_context (1) /* SYS call 2: * * void up_switchcontext(uint32_t *saveregs, uint32_t *restoreregs); */ -#define SYS_switch_context (2) +#define SYS_switch_context (2) #ifdef CONFIG_NUTTX_KERNEL /* SYS call 3: @@ -92,21 +92,38 @@ * void up_syscall_return(void); */ -#define SYS_syscall_return (3) +#define SYS_syscall_return (3) /* SYS call 4: * - * 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; */ -#define SYS_task_start (4) +#define SYS_task_start (4) /* SYS call 5: * - * void up_pthread_start(pthread_startroutine_t entrypt, pthread_addr_t arg) noreturn_function + * void up_pthread_start(pthread_startroutine_t entrypt, pthread_addr_t arg) + * noreturn_function */ -#define SYS_pthread_start (5) +#define SYS_pthread_start (5) + +/* SYS call 6: + * + * void signal_handler(_sa_sigaction_t sighand, int signo, FAR siginfo_t *info, + * FAR void *ucontext); + */ + +#define SYS_signal_handler (6) + +/* SYS call 7: + * + * void signal_handler_return(void); + */ + +#define SYS_signal_handler_return (7) #endif /************************************************************************************ diff --git a/arch/arm/src/armv6-m/up_sigdeliver.c b/arch/arm/src/armv6-m/up_sigdeliver.c index ca60b68c57..83a064e126 100644 --- a/arch/arm/src/armv6-m/up_sigdeliver.c +++ b/arch/arm/src/armv6-m/up_sigdeliver.c @@ -122,7 +122,7 @@ void up_sigdeliver(void) irqrestore((uint8_t)regs[REG_BASEPRI]); - /* Deliver the signals */ + /* Deliver the signal */ sigdeliver(rtcb); diff --git a/arch/arm/src/armv6-m/up_svcall.c b/arch/arm/src/armv6-m/up_svcall.c index ac99cabe03..7458005328 100644 --- a/arch/arm/src/armv6-m/up_svcall.c +++ b/arch/arm/src/armv6-m/up_svcall.c @@ -344,6 +344,78 @@ int up_svcall(int irq, FAR void *context) break; #endif + /* R0=SYS_signal_handler: This a user signal handler callback + * + * void signal_handler(_sa_sigaction_t sighand, int signo, + * FAR siginfo_t *info, FAR void *ucontext); + * + * At this point, the following values are saved in context: + * + * R0 = SYS_signal_handler + * R1 = sighand + * R2 = signo + * R3 = info + * ucontext (on the stack) + */ + +#if defined(CONFIG_NUTTX_KERNEL) && !defined(CONFIG_DISABLE_SIGNALS) + case SYS_signal_handler: + { + struct tcb_s *rtcb = sched_self(); + + /* Remember the caller's return address */ + + DEBUGASSERT(rtcb->xcp.sigreturn == 0); + rtcb->xcp.sigreturn = regs[REG_PC]; + + /* Set up to return to the user-space pthread start-up function in + * unprivileged mode. + */ + + regs[REG_PC] = (uint32_t)USERSPACE->signal_handler; + regs[REG_EXC_RETURN] = EXC_RETURN_UNPRIVTHR; + + /* Change the parameter ordering to match the expectation of struct + * userpace_s signal_handler. + */ + + regs[REG_R0] = regs[REG_R1]; /* sighand */ + regs[REG_R1] = regs[REG_R2]; /* signal */ + regs[REG_R2] = regs[REG_R3]; /* info */ + + /* The last parameter, arg, is trickier. The arg parameter will + * reside at an offset of 4 from the stack pointer. + */ + + regs[REG_R3] = *(uint32_t*)(regs[REG_SP+4]); + } + break; +#endif + + /* R0=SYS_signal_handler_return: This a user signal handler callback + * + * void signal_handler_return(void); + * + * At this point, the following values are saved in context: + * + * R0 = SYS_signal_handler_return + */ + +#if defined(CONFIG_NUTTX_KERNEL) && !defined(CONFIG_DISABLE_SIGNALS) + case SYS_signal_handler_return: + { + struct tcb_s *rtcb = sched_self(); + + /* Set up to return to the kernel-mode signal dispatching logic. */ + + DEBUGASSERT(rtcb->xcp.sigreturn != 0); + + regs[REG_PC] = rtcb->xcp.sigreturn; + regs[REG_EXC_RETURN] = EXC_RETURN_PRIVTHR; + } + break; +#endif + /* This is not an architecture-specific system call. If NuttX is built * as a standalone kernel with a system call interface, then all of the * additional system calls must be handled as in the default case. @@ -356,7 +428,7 @@ int up_svcall(int irq, FAR void *context) /* Verify that the SYS call number is within range */ - DEBUGASSERT(cmd < SYS_maxsyscall); + DEBUGASSERT(cmd >= CONFIG_SYS_RESERVED && cmd < SYS_maxsyscall); /* Make sure that there is a no saved syscall return address. We * cannot yet handle nested system calls. diff --git a/arch/arm/src/armv7-m/svcall.h b/arch/arm/src/armv7-m/svcall.h index 333dfb6d0e..2c47353350 100644 --- a/arch/arm/src/armv7-m/svcall.h +++ b/arch/arm/src/armv7-m/svcall.h @@ -57,9 +57,9 @@ #ifdef CONFIG_NUTTX_KERNEL # ifndef CONFIG_SYS_RESERVED -# error "CONFIG_SYS_RESERVED must be defined to the value 6" -# elif CONFIG_SYS_RESERVED != 6 -# error "CONFIG_SYS_RESERVED must have the value 6" +# error "CONFIG_SYS_RESERVED must be defined to have the value 8" +# elif CONFIG_SYS_RESERVED != 8 +# error "CONFIG_SYS_RESERVED must have the value 8" # endif #endif @@ -70,21 +70,21 @@ * int up_saveusercontext(uint32_t *saveregs); */ -#define SYS_save_context (0) +#define SYS_save_context (0) /* SYS call 1: * * void up_fullcontextrestore(uint32_t *restoreregs) noreturn_function; */ -#define SYS_restore_context (1) +#define SYS_restore_context (1) /* SYS call 2: * * void up_switchcontext(uint32_t *saveregs, uint32_t *restoreregs); */ -#define SYS_switch_context (2) +#define SYS_switch_context (2) #ifdef CONFIG_NUTTX_KERNEL /* SYS call 3: @@ -92,21 +92,38 @@ * void up_syscall_return(void); */ -#define SYS_syscall_return (3) +#define SYS_syscall_return (3) /* SYS call 4: * - * 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; */ -#define SYS_task_start (4) +#define SYS_task_start (4) /* SYS call 5: * - * void up_pthread_start(pthread_startroutine_t entrypt, pthread_addr_t arg) noreturn_function + * void up_pthread_start(pthread_startroutine_t entrypt, pthread_addr_t arg) + * noreturn_function */ -#define SYS_pthread_start (5) +#define SYS_pthread_start (5) + +/* SYS call 6: + * + * void signal_handler(_sa_sigaction_t sighand, int signo, FAR siginfo_t *info, + * FAR void *ucontext); + */ + +#define SYS_signal_handler (6) + +/* SYS call 7: + * + * void signal_handler_return(void); + */ + +#define SYS_signal_handler_return (7) #endif /************************************************************************************ diff --git a/arch/arm/src/armv7-m/up_sigdeliver.c b/arch/arm/src/armv7-m/up_sigdeliver.c index 2e75d254a1..e9c7a95235 100644 --- a/arch/arm/src/armv7-m/up_sigdeliver.c +++ b/arch/arm/src/armv7-m/up_sigdeliver.c @@ -125,7 +125,7 @@ void up_sigdeliver(void) irqrestore((uint16_t)regs[REG_PRIMASK]); #endif - /* Deliver the signals */ + /* Deliver the signal */ sigdeliver(rtcb); diff --git a/arch/arm/src/armv7-m/up_svcall.c b/arch/arm/src/armv7-m/up_svcall.c index 1a153dead8..ab313671c6 100644 --- a/arch/arm/src/armv7-m/up_svcall.c +++ b/arch/arm/src/armv7-m/up_svcall.c @@ -348,6 +348,78 @@ int up_svcall(int irq, FAR void *context) break; #endif + /* R0=SYS_signal_handler: This a user signal handler callback + * + * void signal_handler(_sa_sigaction_t sighand, int signo, + * FAR siginfo_t *info, FAR void *ucontext); + * + * At this point, the following values are saved in context: + * + * R0 = SYS_signal_handler + * R1 = sighand + * R2 = signo + * R3 = info + * ucontext (on the stack) + */ + +#if defined(CONFIG_NUTTX_KERNEL) && !defined(CONFIG_DISABLE_SIGNALS) + case SYS_signal_handler: + { + struct tcb_s *rtcb = sched_self(); + + /* Remember the caller's return address */ + + DEBUGASSERT(rtcb->xcp.sigreturn == 0); + rtcb->xcp.sigreturn = regs[REG_PC]; + + /* Set up to return to the user-space pthread start-up function in + * unprivileged mode. + */ + + regs[REG_PC] = (uint32_t)USERSPACE->signal_handler; + regs[REG_EXC_RETURN] = EXC_RETURN_UNPRIVTHR; + + /* Change the parameter ordering to match the expectation of struct + * userpace_s signal_handler. + */ + + regs[REG_R0] = regs[REG_R1]; /* sighand */ + regs[REG_R1] = regs[REG_R2]; /* signal */ + regs[REG_R2] = regs[REG_R3]; /* info */ + + /* The last parameter, arg, is trickier. The arg parameter will + * reside at an offset of 4 from the stack pointer. + */ + + regs[REG_R3] = *(uint32_t*)(regs[REG_SP+4]); + } + break; +#endif + + /* R0=SYS_signal_handler_return: This a user signal handler callback + * + * void signal_handler_return(void); + * + * At this point, the following values are saved in context: + * + * R0 = SYS_signal_handler_return + */ + +#if defined(CONFIG_NUTTX_KERNEL) && !defined(CONFIG_DISABLE_SIGNALS) + case SYS_signal_handler_return: + { + struct tcb_s *rtcb = sched_self(); + + /* Set up to return to the kernel-mode signal dispatching logic. */ + + DEBUGASSERT(rtcb->xcp.sigreturn != 0); + + regs[REG_PC] = rtcb->xcp.sigreturn; + regs[REG_EXC_RETURN] = EXC_RETURN_PRIVTHR; + } + break; +#endif + /* This is not an architecture-specific system call. If NuttX is built * as a standalone kernel with a system call interface, then all of the * additional system calls must be handled as in the default case. @@ -360,7 +432,7 @@ int up_svcall(int irq, FAR void *context) /* Verify that the SYS call number is within range */ - DEBUGASSERT(cmd < SYS_maxsyscall); + DEBUGASSERT(cmd >= CONFIG_SYS_RESERVED && cmd < SYS_maxsyscall); /* Make sure that there is a no saved syscall return address. We * cannot yet handle nested system calls. diff --git a/arch/arm/src/common/up_signal_handler.c b/arch/arm/src/common/up_signal_handler.c new file mode 100644 index 0000000000..34407885eb --- /dev/null +++ b/arch/arm/src/common/up_signal_handler.c @@ -0,0 +1,100 @@ +/**************************************************************************** + * arch/arm/src/common/up_task_start.c + * + * Copyright (C) 2013 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include + +#include "svcall.h" +#include "up_internal.h" + +#if defined(CONFIG_NUTTX_KERNEL) && defined(__KERNEL__) && !defined(CONFIG_DISABLE_SIGNALS) + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: up_signal_handler + * + * Description: + * In this kernel mode build, this function will be called to execute a + * a signal handler in user-space. When the signal is delivered, a + * kernel-mode stub will first run to perform some housekeeping functions. + * This kernel-mode stub will then be called transfer control to the user + * mode signal handler by calling this function. + * + * Normally the a user-mode signalling handling stub will also execute + * before the ultimate signal handler is called. See + * libc/signal/signal_handler.c This function is the user-space, signal + * handler trampoline function. It is called from up_signal_handler() in + * user-mode. + * + * Inputs: + * sighand - The address user-space signal handling function + * signo, info, and ucontext - Standard arguments to be passed to the + * signal handling function. + * + * Return: + * None. This function does not return in the normal sense. It returns + * via signal_handler_return (below) + * + ****************************************************************************/ + +void up_signal_handler(_sa_sigaction_t sighand, int signo, + FAR siginfo_t *info, FAR void *ucontext) +{ + /* Let sys_call4() do all of the work */ + + sys_call4(SYS_signal_handler, (uintptr_t)sighand, (uintptr_t)signo, + (uintptr_t)info, (uintptr_t)ucontext); +} + +#endif /* CONFIG_NUTTX_KERNEL && __KERNEL__ && !CONFIG_DISABLE_SIGNALS */ diff --git a/arch/arm/src/common/up_task_start.c b/arch/arm/src/common/up_task_start.c index c006f95957..0a3f3c4a48 100644 --- a/arch/arm/src/common/up_task_start.c +++ b/arch/arm/src/common/up_task_start.c @@ -90,7 +90,8 @@ void up_task_start(main_t taskentry, int argc, FAR char *argv[]) { /* Let sys_call3() do all of the work */ - sys_call3(SYS_task_start, (uintptr_t)taskentry, (uintptr_t)argc, (uintptr_t)argv); + sys_call3(SYS_task_start, (uintptr_t)taskentry, (uintptr_t)argc, + (uintptr_t)argv); } #endif /* CONFIG_NUTTX_KERNEL */ diff --git a/arch/arm/src/lpc17xx/Make.defs b/arch/arm/src/lpc17xx/Make.defs index e6d007902c..2bedbf5b33 100644 --- a/arch/arm/src/lpc17xx/Make.defs +++ b/arch/arm/src/lpc17xx/Make.defs @@ -65,6 +65,9 @@ endif ifeq ($(CONFIG_NUTTX_KERNEL),y) CMN_CSRCS += up_mpu.c up_task_start.c up_pthread_start.c +ifneq ($(CONFIG_DISABLE_SIGNALS),y) +CMN_CSRCS += up_signal_handler.c +endif endif ifeq ($(CONFIG_NET),y) diff --git a/arch/arm/src/sam3u/Make.defs b/arch/arm/src/sam3u/Make.defs index a2047a78a9..14cc68d493 100644 --- a/arch/arm/src/sam3u/Make.defs +++ b/arch/arm/src/sam3u/Make.defs @@ -57,6 +57,9 @@ endif ifeq ($(CONFIG_NUTTX_KERNEL),y) CMN_CSRCS += up_mpu.c up_task_start.c up_pthread_start.c +ifneq ($(CONFIG_DISABLE_SIGNALS),y) +CMN_CSRCS += up_signal_handler.c +endif endif ifeq ($(CONFIG_ELF),y) diff --git a/configs/open1788/kernel/up_userspace.c b/configs/open1788/kernel/up_userspace.c index 3947af1cda..2263bc3f5e 100644 --- a/configs/open1788/kernel/up_userspace.c +++ b/configs/open1788/kernel/up_userspace.c @@ -44,7 +44,6 @@ #include #include #include -#include #if defined(CONFIG_NUTTX_KERNEL) && !defined(__KERNEL__) @@ -102,13 +101,19 @@ const struct userspace_s userspace __attribute__ ((section (".userspace"))) = .us_bssstart = (uintptr_t)&_sbss, .us_bssend = (uintptr_t)&_ebss, - /* Task/thread startup stubs */ + /* Task/thread startup routines */ .task_startup = task_startup, #ifndef CONFIG_DISABLE_PTHREAD .pthread_startup = pthread_startup, #endif + /* Signal handler trampoline */ + +#ifndef CONFIG_DISABLE_SIGNALS + .signal_handler = signal_handler, +#endif + /* Memory manager entry points (declared in include/nuttx/mm.h) */ .mm_initialize = umm_initialize, diff --git a/configs/open1788/knsh/defconfig b/configs/open1788/knsh/defconfig index b8d36e6fd2..addfd82ada 100755 --- a/configs/open1788/knsh/defconfig +++ b/configs/open1788/knsh/defconfig @@ -344,7 +344,7 @@ CONFIG_IDLETHREAD_STACKSIZE=1024 CONFIG_USERMAIN_STACKSIZE=2048 CONFIG_PTHREAD_STACK_MIN=256 CONFIG_PTHREAD_STACK_DEFAULT=2048 -CONFIG_SYS_RESERVED=6 +CONFIG_SYS_RESERVED=8 # # Device Drivers diff --git a/configs/sam3u-ek/kernel/up_userspace.c b/configs/sam3u-ek/kernel/up_userspace.c index ee61d1b692..484cdc2d02 100644 --- a/configs/sam3u-ek/kernel/up_userspace.c +++ b/configs/sam3u-ek/kernel/up_userspace.c @@ -101,13 +101,19 @@ const struct userspace_s userspace __attribute__ ((section (".userspace"))) = .us_bssstart = (uintptr_t)&_sbss, .us_bssend = (uintptr_t)&_ebss, - /* Task/thread startup stubs */ + /* Task/thread startup routines */ .task_startup = task_startup, #ifndef CONFIG_DISABLE_PTHREAD .pthread_startup = pthread_startup, #endif + /* Signal handler trampoline */ + +#ifndef CONFIG_DISABLE_SIGNALS + .signal_handler = signal_handler, +#endif + /* Memory manager entry points (declared in include/nuttx/mm.h) */ .mm_initialize = umm_initialize, diff --git a/configs/sam3u-ek/knsh/defconfig b/configs/sam3u-ek/knsh/defconfig index 9bdb33004a..71c646083b 100755 --- a/configs/sam3u-ek/knsh/defconfig +++ b/configs/sam3u-ek/knsh/defconfig @@ -249,7 +249,7 @@ CONFIG_IDLETHREAD_STACKSIZE=1024 CONFIG_USERMAIN_STACKSIZE=2048 CONFIG_PTHREAD_STACK_MIN=256 CONFIG_PTHREAD_STACK_DEFAULT=2048 -CONFIG_SYS_RESERVED=6 +CONFIG_SYS_RESERVED=8 # # Device Drivers diff --git a/include/nuttx/arch.h b/include/nuttx/arch.h index ed461b50dc..afd385ea64 100644 --- a/include/nuttx/arch.h +++ b/include/nuttx/arch.h @@ -373,7 +373,7 @@ void up_schedule_sigaction(FAR struct tcb_s *tcb, sig_deliver_t sigdeliver); * task in user-space. When the task is first started, a kernel-mode * stub will first run to perform some housekeeping functions. This * kernel-mode stub will then be called transfer control to the user-mode - * task. + * task by calling this function. * * Normally the a user-mode start-up stub will also execute before the * task actually starts. See libc/sched/task_startup.c @@ -391,7 +391,8 @@ void up_schedule_sigaction(FAR struct tcb_s *tcb, sig_deliver_t sigdeliver); ****************************************************************************/ #if defined(CONFIG_NUTTX_KERNEL) && defined(__KERNEL__) -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; #endif /**************************************************************************** @@ -402,7 +403,7 @@ void up_task_start(main_t taskentry, int argc, FAR char *argv[]) noreturn_functi * pthread in user-space. When the pthread is first started, a kernel-mode * stub will first run to perform some housekeeping functions. This * kernel-mode stub will then be called transfer control to the user-mode - * pthread. + * pthread by calling this function. * * Normally the a user-mode start-up stub will also execute before the * pthread actually starts. See libc/pthread/pthread_startup.c @@ -419,9 +420,64 @@ void up_task_start(main_t taskentry, int argc, FAR char *argv[]) noreturn_functi ****************************************************************************/ #if defined(CONFIG_NUTTX_KERNEL) && defined(__KERNEL__) && !defined(CONFIG_DISABLE_PTHREAD) -void up_pthread_start(pthread_startroutine_t entrypt, pthread_addr_t arg) noreturn_function; +void up_pthread_start(pthread_startroutine_t entrypt, pthread_addr_t arg) + noreturn_function; #endif +/**************************************************************************** + * Name: up_signal_handler + * + * Description: + * In this kernel mode build, this function will be called to execute a + * a signal handler in user-space. When the signal is delivered, a + * kernel-mode stub will first run to perform some housekeeping functions. + * This kernel-mode stub will then be called transfer control to the user + * mode signal handler by calling this function. + * + * Normally the a user-mode signalling handling stub will also execute + * before the ultimate signal handler is called. See + * libc/signal/signal_handler.c This function is the user-space, signal + * handler trampoline function. It is called from up_signal_handler() in + * user-mode. + * + * Inputs: + * sighand - The address user-space signal handling function + * signo, info, and ucontext - Standard arguments to be passed to the + * signal handling function. + * + * Return: + * None. This function does not return in the normal sense. It returns + * via signal_handler_return (below) + * + ****************************************************************************/ + +#if defined(CONFIG_NUTTX_KERNEL) && defined(__KERNEL__) && !defined(CONFIG_DISABLE_SIGNALS) +void up_signal_handler(_sa_sigaction_t sighand, int signo, + FAR siginfo_t *info, FAR void *ucontext); +#endif + +/**************************************************************************** + * Name: signal_handler_return + * + * Description: + * This function is the user-space, signal handler return function. It + * is called from the signal_handler() in user-mode. This function has the + * general prototype: + * + * void signal_handler_return(void); + * + * However, it it not prototyped here because it should be implemented as + * an inline function or macro that can be obtain by including the file + * include/arch/syscall.h. + * + * Inputs: + * None. + * + * Return: + * None. This function does not return. + * + ****************************************************************************/ + /**************************************************************************** * Name: up_allocate_heap * diff --git a/include/nuttx/sched.h b/include/nuttx/sched.h index 9101a28763..2641dd9d10 100644 --- a/include/nuttx/sched.h +++ b/include/nuttx/sched.h @@ -682,46 +682,6 @@ FAR struct task_tcb_s *task_vforksetup(start_t retaddr); pid_t task_vforkstart(FAR struct task_tcb_s *child); void task_vforkabort(FAR struct task_tcb_s *child, int errcode); -/**************************************************************************** - * Name: task_startup - * - * Description: - * This function is the user-space, task startup function. It is called - * from up_task_start() in user-mode. - * - * Inputs: - * entrypt - The user-space address of the task entry point - * argc and argv - Standard arguments for the task entry point - * - * Return: - * None. This function does not return. - * - ****************************************************************************/ - -#if defined(CONFIG_NUTTX_KERNEL) && !defined(__KERNEL__) -void task_startup(main_t entrypt, int argc, FAR char *argv[]); -#endif - -/**************************************************************************** - * Name: pthread_startup - * - * Description: - * This function is the user-space, pthread startup function. It is called - * from up_pthread_start() in user-mode. - * - * Inputs: - * entrypt - The user-space address of the pthread entry point - * arg - Standard argument for the pthread entry point - * - * Return: - * None. This function does not return. - * - ****************************************************************************/ - -#if defined(CONFIG_NUTTX_KERNEL) && !defined(__KERNEL__) && !defined(CONFIG_DISABLE_PTHREAD) -void pthread_startup(pthread_startroutine_t entrypt, pthread_addr_t arg); -#endif - #undef EXTERN #if defined(__cplusplus) } diff --git a/include/nuttx/userspace.h b/include/nuttx/userspace.h index 842870664e..38e123bc22 100644 --- a/include/nuttx/userspace.h +++ b/include/nuttx/userspace.h @@ -44,6 +44,7 @@ #include #include +#include #include #ifdef CONFIG_NUTTX_KERNEL @@ -114,9 +115,18 @@ struct userspace_s /* Task/thread startup routines */ - void (*task_startup)(main_t entrypt, int argc, FAR char *argv[]) noreturn_function; + void (*task_startup)(main_t entrypt, int argc, FAR char *argv[]) + noreturn_function; #ifndef CONFIG_DISABLE_PTHREAD - void (*pthread_startup)(pthread_startroutine_t entrypt, pthread_addr_t arg); + void (*pthread_startup)(pthread_startroutine_t entrypt, + pthread_addr_t arg); +#endif + + /* Signal handler trampoline */ + +#ifndef CONFIG_DISABLE_SIGNALS + void (*signal_handler)(_sa_sigaction_t sighand, int signo, + FAR siginfo_t *info, FAR void *ucontext); #endif /* Memory manager entry points */ @@ -154,6 +164,69 @@ extern "C" * Public Function Prototypes ****************************************************************************/ +/**************************************************************************** + * Name: task_startup + * + * Description: + * This function is the user-space, task startup function. It is called + * from up_task_start() in user-mode. + * + * Inputs: + * entrypt - The user-space address of the task entry point + * argc and argv - Standard arguments for the task entry point + * + * Return: + * None. This function does not return. + * + ****************************************************************************/ + +#if defined(CONFIG_NUTTX_KERNEL) && !defined(__KERNEL__) +void task_startup(main_t entrypt, int argc, FAR char *argv[]); +#endif + +/**************************************************************************** + * Name: pthread_startup + * + * Description: + * This function is the user-space, pthread startup function. It is called + * from up_pthread_start() in user-mode. + * + * Inputs: + * entrypt - The user-space address of the pthread entry point + * arg - Standard argument for the pthread entry point + * + * Return: + * None. This function does not return. + * + ****************************************************************************/ + +#if defined(CONFIG_NUTTX_KERNEL) && !defined(__KERNEL__) && !defined(CONFIG_DISABLE_PTHREAD) +void pthread_startup(pthread_startroutine_t entrypt, pthread_addr_t arg); +#endif + +/**************************************************************************** + * Name: signal_handler + * + * Description: + * This function is the user-space, signal handler trampoline function. It + * is called from up_signal_handler() in user-mode. + * + * Inputs: + * sighand - The address user-space signal handling function + * signo, info, and ucontext - Standard arguments to be passed to the + * signal handling function. + * + * Return: + * None. This function does not return in the normal sense. It returns + * via signal_handler_return (see include/nuttx/arch.h) + * + ****************************************************************************/ + +#if defined(CONFIG_NUTTX_KERNEL) && !defined(__KERNEL__) && !defined(CONFIG_DISABLE_SIGNALS) +void signal_handler(_sa_sigaction_t sighand, int signo, FAR siginfo_t *info, + FAR void *ucontext); +#endif + #undef EXTERN #ifdef __cplusplus } diff --git a/include/signal.h b/include/signal.h index a021702426..a31e62ff2b 100644 --- a/include/signal.h +++ b/include/signal.h @@ -1,7 +1,7 @@ /******************************************************************************** * include/signal.h * - * Copyright (C) 2007-2009, 2011 Gregory Nutt. All rights reserved. + * Copyright (C) 2007-2009, 2011, 2013 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -206,19 +206,28 @@ struct siginfo typedef struct siginfo siginfo_t; +/* Non-standard convenience definition of signal handling function types. + * These should be used only internally within the NuttX signal logic. + */ + +typedef CODE void (*_sa_handler_t)(int); +typedef CODE void (*_sa_sigaction_t)(int, FAR siginfo_t *, FAR void *); + /* The following structure defines the action to take for given signal */ struct sigaction { union { - CODE void (*_sa_handler)(int); - CODE void (*_sa_sigaction)(int, FAR siginfo_t *, FAR void *); + _sa_handler_t _sa_handler; + _sa_sigaction_t _sa_sigaction; } sa_u; - sigset_t sa_mask; - int sa_flags; + sigset_t sa_mask; + int sa_flags; }; +/* Definitions that adjust the non-standard naming */ + #define sa_handler sa_u._sa_handler #define sa_sigaction sa_u._sa_sigaction diff --git a/libc/pthread/pthread_startup.c b/libc/pthread/pthread_startup.c index dee9826fc6..50aa263e4e 100644 --- a/libc/pthread/pthread_startup.c +++ b/libc/pthread/pthread_startup.c @@ -42,7 +42,7 @@ #include #include -#include +#include #if defined(CONFIG_NUTTX_KERNEL) && !defined(__KERNEL__) diff --git a/libc/sched/task_startup.c b/libc/sched/task_startup.c index 8795faa7a3..72cffbaaa3 100644 --- a/libc/sched/task_startup.c +++ b/libc/sched/task_startup.c @@ -42,7 +42,7 @@ #include #include -#include +#include #if defined(CONFIG_NUTTX_KERNEL) && !defined(__KERNEL__) diff --git a/libc/signal/Make.defs b/libc/signal/Make.defs index fe7eb180e7..0264cce258 100644 --- a/libc/signal/Make.defs +++ b/libc/signal/Make.defs @@ -39,6 +39,10 @@ ifneq ($(CONFIG_DISABLE_SIGNALS),y) CSRCS += sig_emptyset.c sig_fillset.c sig_addset.c sig_delset.c sig_ismember.c +ifeq ($(CONFIG_NUTTX_KERNEL),y) +CSRCS += signal_handler.c +endif + # Add the signal directory to the build DEPPATH += --dep-path signal diff --git a/libc/signal/signal_handler.c b/libc/signal/signal_handler.c new file mode 100644 index 0000000000..0a0996baeb --- /dev/null +++ b/libc/signal/signal_handler.c @@ -0,0 +1,110 @@ +/**************************************************************************** + * libc/signal/signal_handler.c + * + * Copyright (C) 2013 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include + +#include +#include + +#if defined(CONFIG_NUTTX_KERNEL) && !defined(__KERNEL__) + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Type Declarations + ****************************************************************************/ + +/**************************************************************************** + * Global Variables + ****************************************************************************/ + +/**************************************************************************** + * Private Variables + ****************************************************************************/ + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: signal_handler + * + * Description: + * This function is the user-space, signal handler trampoline function. It + * is called from up_signal_handler() in user-mode. + * + * Inputs: + * sighand - The address user-space signal handling function + * signo, info, and ucontext - Standard arguments to be passed to the + * signal handling function. + * + * Return: + * None. This function does not return in the normal sense. It returns + * via signal_handler_return (see include/nuttx/arch.h) + * + ****************************************************************************/ + +void signal_handler(_sa_sigaction_t sighand, int signo, FAR siginfo_t *info, + FAR void *ucontext) +{ + DEBUGASSERT(sighand); + + /* Execute the signal handler. */ + + sighand(signo, info, ucontext); + + /* And return from the signal handler */ + + signal_handler_return(); +} + +#endif /* CONFIG_NUTTX_KERNEL && !__KERNEL__ */ diff --git a/sched/sig_deliver.c b/sched/sig_deliver.c index 3f0adc6d54..bb6ca71a45 100644 --- a/sched/sig_deliver.c +++ b/sched/sig_deliver.c @@ -1,7 +1,7 @@ /**************************************************************************** * sched/sig_deliver.c * - * Copyright (C) 2007, 2008, 2012 Gregory Nutt. All rights reserved. + * Copyright (C) 2007, 2008, 2012-2013 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -127,9 +127,24 @@ void sig_deliver(FAR struct tcb_s *stcb) savesigprocmask = stcb->sigprocmask; stcb->sigprocmask = savesigprocmask | sigq->mask | SIGNO2SET(sigq->info.si_signo); - /* Deliver the signal */ + /* Deliver the signal. In the kernel build this has to be handled + * differently if we are dispatching to a signal handler in a user- + * space task or thread; we have to switch to user-mode before + * calling the task. + */ - (*sigq->action.sighandler)(sigq->info.si_signo, &sigq->info, NULL); +#ifdef CONFIG_NUTTX_KERNEL + if ((stcb->flags & TCB_FLAG_TTYPE_MASK) != TCB_FLAG_TTYPE_KERNEL) + { + up_signal_handler(sigq->action.sighandler, sigq->info.si_signo, + &sigq->info, NULL); + } + else +#endif + { + (*sigq->action.sighandler)(sigq->info.si_signo, &sigq->info, + NULL); + } /* Restore the original sigprocmask */