diff options
author | Gregory Nutt <gnutt@nuttx.org> | 2014-02-23 08:25:49 -0600 |
---|---|---|
committer | Gregory Nutt <gnutt@nuttx.org> | 2014-02-23 08:25:49 -0600 |
commit | 875b32e8389ac6e06bfb328e992c1865445d96c1 (patch) | |
tree | 5d730f8771b65cb86d9559a37d0cdf358f19c0c5 /nuttx/arch/arm/src/armv6-m/up_schedulesigaction.c | |
parent | d75e62056261d8f75ec5b1b4fb9fd61d4768c163 (diff) | |
download | nuttx-875b32e8389ac6e06bfb328e992c1865445d96c1.tar.gz nuttx-875b32e8389ac6e06bfb328e992c1865445d96c1.tar.bz2 nuttx-875b32e8389ac6e06bfb328e992c1865445d96c1.zip |
ARMv6-M/ARMv7-M: Correct a register handling error in signal delivery (Kernel build mode only). Noted by Mike Smith.
Diffstat (limited to 'nuttx/arch/arm/src/armv6-m/up_schedulesigaction.c')
-rw-r--r-- | nuttx/arch/arm/src/armv6-m/up_schedulesigaction.c | 64 |
1 files changed, 32 insertions, 32 deletions
diff --git a/nuttx/arch/arm/src/armv6-m/up_schedulesigaction.c b/nuttx/arch/arm/src/armv6-m/up_schedulesigaction.c index e41a1a33a..308f395b8 100644 --- a/nuttx/arch/arm/src/armv6-m/up_schedulesigaction.c +++ b/nuttx/arch/arm/src/armv6-m/up_schedulesigaction.c @@ -1,7 +1,7 @@ /**************************************************************************** * arch/arm/src/armv6-m/up_schedulesigaction.c * - * Copyright (C) 2013 Gregory Nutt. All rights reserved. + * Copyright (C) 2013-2014 Gregory Nutt. All rights reserved. * Author: Gregory Nutt <gnutt@nuttx.org> * * Redistribution and use in source and binary forms, with or without @@ -116,16 +116,16 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver) flags = irqsave(); - /* First, handle some special cases when the signal is - * being delivered to the currently executing task. + /* 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 == (struct tcb_s*)g_readytorun.head) { - /* CASE 1: We are not in an interrupt handler and - * a task is signalling itself for some reason. + /* CASE 1: We are not in an interrupt handler and a task is + * signalling itself for some reason. */ if (!current_regs) @@ -135,30 +135,26 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver) 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! + /* 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. */ 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. + /* Save the return PC, CPSR, and PRIMASK registers (and + * perhaps the LR). These will be restored by the signal + * trampoline after the signal has been delivered. */ tcb->xcp.sigdeliver = sigdeliver; tcb->xcp.saved_pc = current_regs[REG_PC]; tcb->xcp.saved_primask = current_regs[REG_PRIMASK]; tcb->xcp.saved_xpsr = current_regs[REG_XPSR]; - +#ifdef CONFIG_NUTTX_KERNEL + tcb->xcp.saved_lr = current_regs[REG_LR]; +#endif /* Then set up to vector to the trampoline with interrupts * disabled. The kernel-space trampoline must run in * privileged thread mode. @@ -168,43 +164,47 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver) current_regs[REG_PRIMASK] = 1; current_regs[REG_XPSR] = ARMV6M_XPSR_T; #ifdef CONFIG_NUTTX_KERNEL - current_regs[REG_XPSR] = EXC_RETURN_PRIVTHR; + current_regs[REG_LR] = EXC_RETURN_PRIVTHR; #endif - - /* And make sure that the saved context in the TCB - * is the same as the interrupt return context. + /* 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. + /* Otherwise, we are (1) signalling 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. + /* Save the return PS, CPSR and PRIMASK register (a perhaps also + * the LR). These will be restored by the signal trampoline after + * the signal has been delivered. */ tcb->xcp.sigdeliver = sigdeliver; tcb->xcp.saved_pc = tcb->xcp.regs[REG_PC]; tcb->xcp.saved_primask = tcb->xcp.regs[REG_PRIMASK]; tcb->xcp.saved_xpsr = tcb->xcp.regs[REG_XPSR]; +#ifdef CONFIG_NUTTX_KERNEL + tcb->xcp.saved_lr = tcb->xcp.regs[REG_LR]; +#endif /* Then set up to vector to the trampoline with interrupts - * disabled. We must already be in privileged thread mode - * to be here. + * disabled. We must already be in privileged thread mode to be + * here. */ tcb->xcp.regs[REG_PC] = (uint32_t)up_sigdeliver; tcb->xcp.regs[REG_PRIMASK] = 1; tcb->xcp.regs[REG_XPSR] = ARMV6M_XPSR_T; +#ifdef CONFIG_NUTTX_KERNEL + tcb->xcp.regs[REG_LR] = EXC_RETURN_PRIVTHR; +#endif } irqrestore(flags); |