diff --git a/arch/x86/include/i486/irq.h b/arch/x86/include/i486/irq.h index 7f6d849ba6..0ff572df47 100755 --- a/arch/x86/include/i486/irq.h +++ b/arch/x86/include/i486/irq.h @@ -57,23 +57,25 @@ /* Storage order: %ebx, $esi, %edi, %ebp, sp, and return PC */ #ifdef __ASSEMBLY__ -# define REG_EBX (0*4) -# define REG_ESI (1*4) -# define REG_EDI (2*4) -# define REG_EBP (3*4) -# define REG_SP (4*4) -# define REG_PC (5*4) +# define REG_EBX (0*4) +# define REG_ESI (1*4) +# define REG_EDI (2*4) +# define REG_EBP (3*4) +# define REG_SP (4*4) +# define REG_PC (5*4) +# define REG_FLAGS (6*4) #else -# define REG_EBX (0) -# define REG_ESI (1) -# define REG_EDI (2) -# define REG_EBP (3) -# define REG_SP (4) -# define REG_PC (5) +# define REG_EBX (0) +# define REG_ESI (1) +# define REG_EDI (2) +# define REG_EBP (3) +# define REG_SP (4) +# define REG_PC (5) +# define REG_FLAGS (6) #endif /* __ASSEMBLY__ */ -#define XCPTCONTEXT_REGS (6) -#define XCPTCONTEXT_SIZE (6 * XCPTCONTEXT_REGS) +#define XCPTCONTEXT_REGS (7) +#define XCPTCONTEXT_SIZE (4 * XCPTCONTEXT_REGS) /**************************************************************************** * Public Types @@ -84,9 +86,20 @@ #ifndef __ASSEMBLY__ struct xcptcontext { - void *sigdeliver; /* Actual type is sig_deliver_t */ + /* The following function pointer is non-zero if there are pending signals + * to be processed. + */ - /* Storage order: %ebx, $esi, %edi, %ebp, sp, and return PC */ +#ifndef CONFIG_DISABLE_SIGNALS + void *sigdeliver; /* Actual type is sig_deliver_t */ + + /* These are saved copies of LR and CPSR used during signal processing. */ + + uint32_t saved_pc; + uint32_t saved_flags; +#endif + + /* Register save area */ uint32_t regs[XCPTCONTEXT_REGS]; }; @@ -117,7 +130,7 @@ static inline irqstate_t irqflags() static inline bool irqdisabled(irqstate_t flags) { - return ((flags & X86_FLAGS_IF) == 0); + return ((flags & X86_FLAGS_IF) != 0); } /* Disable interrupts unconditionally */ diff --git a/arch/x86/src/i486/up_initialstate.c b/arch/x86/src/i486/up_initialstate.c new file mode 100644 index 0000000000..e458d35b81 --- /dev/null +++ b/arch/x86/src/i486/up_initialstate.c @@ -0,0 +1,104 @@ +/**************************************************************************** + * arch/x86/src/i486/up_initialstate.c + * + * Copyright (C) 2010 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 + +#include "up_internal.h" +#include "up_arch.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: up_initial_state + * + * Description: + * A new thread is being started and a new TCB has been created. This + * function is called to initialize the processor specific portions of the + * new TCB. + * + * This function must setup the intial architecture registers and/or stack + * so that execution will begin at tcb->start on the next context switch. + * + ****************************************************************************/ + +void up_initial_state(_TCB *tcb) +{ + struct xcptcontext *xcp = &tcb->xcp; + + /* Initialize the initial exception register context structure */ + + memset(xcp, 0, sizeof(struct xcptcontext)); + + /* Save the initial stack pointer */ + + xcp->regs[REG_SP] = (uint32_t)tcb->adj_stack_ptr; + + /* Save the task entry point */ + + xcp->regs[REG_PC] = (uint32_t)tcb->start; + + /* Enable or disable interrupts, based on user configuration. If the IF + * bit is set, maskable interrupts will be enabled. + */ + +#ifndef CONFIG_SUPPRESS_INTERRUPTS + xcp->regs[REG_FLAGS] = X86_FLAGS_IF; +#endif +} + diff --git a/arch/x86/src/i486/up_schedulesigaction.c b/arch/x86/src/i486/up_schedulesigaction.c new file mode 100644 index 0000000000..6bcc3c656a --- /dev/null +++ b/arch/x86/src/i486/up_schedulesigaction.c @@ -0,0 +1,198 @@ +/**************************************************************************** + * arch/x86/src/i486/up_schedulesigaction.c + * + * Copyright (C) 2011 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 + +#include "os_internal.h" +#include "up_internal.h" +#include "up_arch.h" + +#ifndef CONFIG_DISABLE_SIGNALS + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: up_schedule_sigaction + * + * Description: + * This function is called by the OS when one or more signal handling + * actions have been queued for execution. The architecture specific code + * must configure things so that the 'sigdeliver' callback is executed on + * the thread specified by 'tcb' as soon as possible. + * + * This function may be called from interrupt handling logic. + * + * This operation should not cause the task to be unblocked nor should it + * cause any immediate execution of sigdeliver. Typically, a few cases need + * to be considered: + * + * (1) This function may be called from an interrupt handler. During + * interrupt processing, all xcptcontext structures should be valid for + * all tasks. That structure should be modified to invoke sigdeliver() + * either on return from (this) interrupt or on some subsequent context + * switch to the recipient task. + * (2) If not in an interrupt handler and the tcb is NOT the currently + * executing task, then again just modify the saved xcptcontext + * structure for the recipient task so it will invoke sigdeliver when + * that task is later resumed. + * (3) If not in an interrupt handler and the tcb IS the currently + * executing task -- just call the signal handler now. + * + ****************************************************************************/ + +void up_schedule_sigaction(_TCB *tcb, sig_deliver_t sigdeliver) +{ + /* Refuse to handle nested signal actions */ + + sdbg("tcb=0x%p sigdeliver=0x%p\n", tcb, sigdeliver); + + if (!tcb->xcp.sigdeliver) + { + irqstate_t flags; + + /* Make sure that interrupts are disabled */ + + flags = irqsave(); + + /* First, handle some special cases when the signal is being delivered + * to the currently executing task. + */ + + sdbg("rtcb=0x%p current_regs=0x%p\n", g_readytorun.head, current_regs); + + if (tcb == (_TCB*)g_readytorun.head) + { + /* CASE 1: We are not in an interrupt handler and a task is + * signalling itself for some reason. + */ + + if (!current_regs) + { + /* In this case just deliver the signal now. */ + + sigdeliver(tcb); + } + + /* CASE 2: We are in an interrupt handler AND the interrupted task + * is the same as the one that must receive the signal, then we will + * have to modify the return state as well as the state in the TCB. + * + * Hmmm... there looks like a latent bug here: The following logic + * would fail in the strange case where we are in an interrupt + * handler, the thread is signalling itself, but a context switch to + * another task has occurred so that current_regs does not refer to + * the thread at g_readytorun.head! + */ + + else + { + /* Save the return lr and cpsr and one scratch register. These + * will be restored by the signal trampoline after the signals + * have been delivered. + */ + + tcb->xcp.sigdeliver = sigdeliver; + tcb->xcp.saved_pc = current_regs[REG_PC]; + tcb->xcp.saved_flags = current_regs[REG_FLAGS]; + + /* Then set up to vector to the trampoline with interrupts + * disabled + */ + + current_regs[REG_PC] = (uint32_t)up_sigdeliver; + current_regs[REG_FLAGS] = 0; + + /* And make sure that the saved context in the TCB + * is the same as the interrupt return context. + */ + + up_savestate(tcb->xcp.regs); + } + } + + /* Otherwise, we are (1) signaling a task is not running + * from an interrupt handler or (2) we are not in an + * interrupt handler and the running task is signalling + * some non-running task. + */ + + else + { + /* Save the return lr and cpsr and one scratch register + * These will be restored by the signal trampoline after + * the signals have been delivered. + */ + + tcb->xcp.sigdeliver = sigdeliver; + tcb->xcp.saved_pc = tcb->xcp.regs[REG_PC]; + tcb->xcp.saved_flags = tcb->xcp.regs[REG_FLAGS]; + + /* Then set up to vector to the trampoline with interrupts + * disabled + */ + + tcb->xcp.regs[REG_PC] = (uint32_t)up_sigdeliver; + tcb->xcp.regs[REG_FLAGS] = 0; + } + + irqrestore(flags); + } +} + +#endif /* !CONFIG_DISABLE_SIGNALS */ diff --git a/arch/x86/src/i486/up_sigdeliver.c b/arch/x86/src/i486/up_sigdeliver.c new file mode 100644 index 0000000000..839943bcc3 --- /dev/null +++ b/arch/x86/src/i486/up_sigdeliver.c @@ -0,0 +1,139 @@ +/**************************************************************************** + * arch/x86/src/i486/up_sigdeliver.c + * + * Copyright (C) 2010 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 +#include +#include + +#include "os_internal.h" +#include "up_internal.h" +#include "up_arch.h" + +#ifndef CONFIG_DISABLE_SIGNALS + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: up_sigdeliver + * + * Description: + * This is the a signal handling trampoline. When a signal action was + * posted. The task context was mucked with and forced to branch to this + * location with interrupts disabled. + * + ****************************************************************************/ + +void up_sigdeliver(void) +{ + _TCB *rtcb = (_TCB*)g_readytorun.head; + uint32_t regs[XCPTCONTEXT_REGS]; + sig_deliver_t sigdeliver; + + /* Save the errno. This must be preserved throughout the signal handling + * so that the user code final gets the correct errno value (probably + * EINTR). + */ + + int saved_errno = rtcb->pterrno; + + up_ledon(LED_SIGNAL); + + sdbg("rtcb=%p sigdeliver=%p sigpendactionq.head=%p\n", + rtcb, rtcb->xcp.sigdeliver, rtcb->sigpendactionq.head); + ASSERT(rtcb->xcp.sigdeliver != NULL); + + /* Save the real return state on the stack. */ + + up_copystate(regs, rtcb->xcp.regs); + regs[REG_PC] = rtcb->xcp.saved_pc; + regs[REG_FLAGS] = rtcb->xcp.saved_flags; + + /* Get a local copy of the sigdeliver function pointer. we do this so that + * we can nullify the sigdeliver function pointer in the TCB and accept + * more signal deliveries while processing the current pending signals. + */ + + sigdeliver = rtcb->xcp.sigdeliver; + rtcb->xcp.sigdeliver = NULL; + + /* Then restore the task interrupt state */ + + irqrestore(regs[REG_FLAGS]); + + /* Deliver the signals */ + + sigdeliver(rtcb); + + /* Output any debug messages BEFORE restoring errno (because they may + * alter errno), then disable interrupts again and restore the original + * errno that is needed by the user logic (it is probably EINTR). + */ + + sdbg("Resuming\n"); + (void)irqsave(); + rtcb->pterrno = saved_errno; + + /* Then restore the correct state for this thread of execution. */ + + up_ledoff(LED_SIGNAL); + up_fullcontextrestore(regs); +} + +#endif /* !CONFIG_DISABLE_SIGNALS */ + diff --git a/arch/x86/src/qemu/Make.defs b/arch/x86/src/qemu/Make.defs index c7a65ea10a..5793ecd09d 100755 --- a/arch/x86/src/qemu/Make.defs +++ b/arch/x86/src/qemu/Make.defs @@ -42,9 +42,10 @@ HEAD_ASRC = qemu_head.S CMN_ASRCS = CMN_CSRCS = up_allocateheap.c up_assert.c up_blocktask.c up_copystate.c \ up_createstack.c up_mdelay.c up_udelay.c up_exit.c \ - up_initialize.c up_interruptcontext.c up_modifyreg8.c \ - up_modifyreg16.c up_modifyreg32.c up_releasepending.c \ - up_releasestack.c up_reprioritizertr.c up_unblocktask.c \ + up_initialize.c up_initialstate.c up_interruptcontext.c \ + up_modifyreg8.c up_modifyreg16.c up_modifyreg32.c \ + up_releasepending.c up_releasestack.c up_reprioritizertr.c \ + up_sigdeliver.c up_schedulesigaction.c up_unblocktask.c \ up_usestack.c # Required QEMU files diff --git a/arch/x86/src/qemu/qemu_fullcontextrestore.S b/arch/x86/src/qemu/qemu_fullcontextrestore.S index 49f1e5ee65..07023e5a05 100644 --- a/arch/x86/src/qemu/qemu_fullcontextrestore.S +++ b/arch/x86/src/qemu/qemu_fullcontextrestore.S @@ -1,7 +1,7 @@ /************************************************************************** * arch/x86/src/qemu/qemu_fullcontextrestore.S * - * Copyright (C) 2010 Gregory Nutt. All rights reserved. + * Copyright (C) 2011 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -96,24 +96,35 @@ .type SYMBOL(up_fullcontextrestore), @function #endif SYMBOL(up_fullcontextrestore): - movl 4(%esp), %ecx /* U_pthread_jmpbuf in %ecx. */ - movl 8(%esp), %eax /* Second argument is return value. */ + movl 4(%esp), %ecx /* Register save area in %ecx. */ - /* Save the return address now. */ + /* Disable interrupts now (the will be conditionally re-enabled below) */ - movl (REG_PC)(%ecx), %edx + cli + + /* Save the return address. */ + + movl (REG_PC)(%ecx), %edx /* Restore registers. */ - movl (REG_EBX)(%ecx), %ebx - movl (REG_ESI)(%ecx), %esi - movl (REG_EDI)(%ecx), %edi - movl (REG_EBP)(%ecx), %ebp - movl (REG_SP)(%ecx), %esp + movl (REG_EBX)(%ecx), %ebx + movl (REG_ESI)(%ecx), %esi + movl (REG_EDI)(%ecx), %edi + movl (REG_EBP)(%ecx), %ebp + movl (REG_SP)(%ecx), %esp - /* Jump to saved PC. */ + /* Conditionally restore interrupts */ - jmp *%edx + testl $512, (REG_FLAGS)(%ecx) + je .Ldisabled + sti +.Ldisabled: + + /* Jump to saved PC with non-zero return value in %eax. */ + + movl $1, %eax + jmp *%edx #ifndef __CYGWIN__ .size SYMBOL(up_fullcontextrestore), . - SYMBOL(up_fullcontextrestore) #endif diff --git a/arch/x86/src/qemu/qemu_saveusercontext.S b/arch/x86/src/qemu/qemu_saveusercontext.S index 1d72bd6437..cc46418359 100644 --- a/arch/x86/src/qemu/qemu_saveusercontext.S +++ b/arch/x86/src/qemu/qemu_saveusercontext.S @@ -117,8 +117,14 @@ SYMBOL(up_saveusercontext): /* Save the framepointer */ - movl %ebp, (REG_EBP)(%eax) + movl %ebp, (REG_EBP)(%eax) + /* Save the interrupt state */ + + pushf + pop %ecx + movl %ecx, (REG_FLAGS)(%eax) + /* And return 0 */ xorl %eax, %eax