mirror of
https://github.com/apache/nuttx.git
synced 2026-05-30 21:36:28 +08:00
arm: g_current_regs is only used to determine if we are in irq,
with other functionalities removed. reason: by doing this we can reduce context switch time, When we exit from an interrupt handler, we directly use tcb->xcp.regs before size nuttx text data bss dec hex filename 225920 409 30925 257254 3ece6 nuttx after text data bss dec hex filename 225604 409 30925 256938 3ebaa nuttx szie change -316 Signed-off-by: hujun5 <hujun5@xiaomi.com>
This commit is contained in:
@@ -58,6 +58,8 @@
|
||||
|
||||
uint32_t *arm_doirq(int irq, uint32_t *regs)
|
||||
{
|
||||
struct tcb_s *tcb = this_task();
|
||||
|
||||
board_autoled_on(LED_INIRQ);
|
||||
#ifdef CONFIG_SUPPRESS_INTERRUPTS
|
||||
PANIC();
|
||||
@@ -71,6 +73,7 @@ uint32_t *arm_doirq(int irq, uint32_t *regs)
|
||||
*/
|
||||
|
||||
up_set_current_regs(regs);
|
||||
tcb->xcp.regs = regs;
|
||||
|
||||
/* Acknowledge the interrupt */
|
||||
|
||||
@@ -79,6 +82,7 @@ uint32_t *arm_doirq(int irq, uint32_t *regs)
|
||||
/* Deliver the IRQ */
|
||||
|
||||
irq_dispatch(irq, regs);
|
||||
tcb = this_task();
|
||||
|
||||
/* Check for a context switch. If a context switch occurred, then
|
||||
* current_regs will have a different value than it did on entry. If an
|
||||
@@ -87,7 +91,7 @@ uint32_t *arm_doirq(int irq, uint32_t *regs)
|
||||
* returning from the interrupt.
|
||||
*/
|
||||
|
||||
if (regs != up_current_regs())
|
||||
if (regs != tcb->xcp.regs)
|
||||
{
|
||||
#ifdef CONFIG_ARCH_ADDRENV
|
||||
/* Make sure that the address environment for the previously
|
||||
@@ -104,9 +108,9 @@ uint32_t *arm_doirq(int irq, uint32_t *regs)
|
||||
* crashes.
|
||||
*/
|
||||
|
||||
g_running_tasks[this_cpu()] = this_task();
|
||||
g_running_tasks[this_cpu()] = tcb;
|
||||
|
||||
regs = up_current_regs();
|
||||
regs = tcb->xcp.regs;
|
||||
}
|
||||
|
||||
/* Set current_regs to NULL to indicate that we are no longer in an
|
||||
|
||||
@@ -89,70 +89,15 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver)
|
||||
* being delivered to the currently executing task.
|
||||
*/
|
||||
|
||||
sinfo("rtcb=%p current_regs=%p\n", this_task(), up_current_regs());
|
||||
sinfo("rtcb=%p current_regs=%p\n", this_task(),
|
||||
this_task()->xcp.regs);
|
||||
|
||||
if (tcb == this_task())
|
||||
if (tcb == this_task() && !up_interrupt_context())
|
||||
{
|
||||
/* CASE 1: We are not in an interrupt handler and
|
||||
* a task is signalling itself for some reason.
|
||||
*/
|
||||
/* In this case just deliver the signal now. */
|
||||
|
||||
if (!up_current_regs())
|
||||
{
|
||||
/* In this case just deliver the signal now. */
|
||||
|
||||
sigdeliver(tcb);
|
||||
tcb->xcp.sigdeliver = NULL;
|
||||
}
|
||||
|
||||
/* 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 of this_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.
|
||||
*/
|
||||
|
||||
/* And make sure that the saved context in the TCB
|
||||
* is the same as the interrupt return context.
|
||||
*/
|
||||
|
||||
arm_savestate(tcb->xcp.saved_regs);
|
||||
|
||||
/* Duplicate the register context. These will be
|
||||
* restored by the signal trampoline after the signal has been
|
||||
* delivered.
|
||||
*/
|
||||
|
||||
up_set_current_regs(up_current_regs() - XCPTCONTEXT_REGS);
|
||||
memcpy(up_current_regs(), tcb->xcp.saved_regs,
|
||||
XCPTCONTEXT_SIZE);
|
||||
|
||||
up_current_regs()[REG_SP] = (uint32_t)(up_current_regs() +
|
||||
XCPTCONTEXT_REGS);
|
||||
|
||||
/* Then set up to vector to the trampoline with interrupts
|
||||
* disabled
|
||||
*/
|
||||
|
||||
up_current_regs()[REG_PC] = (uint32_t)arm_sigdeliver;
|
||||
up_current_regs()[REG_CPSR] = PSR_MODE_SYS | PSR_I_BIT |
|
||||
PSR_F_BIT;
|
||||
#ifdef CONFIG_ARM_THUMB
|
||||
up_current_regs()[REG_CPSR] |= PSR_T_BIT;
|
||||
#endif
|
||||
}
|
||||
sigdeliver(tcb);
|
||||
tcb->xcp.sigdeliver = NULL;
|
||||
}
|
||||
|
||||
/* Otherwise, we are (1) signaling a task is not running
|
||||
|
||||
@@ -54,7 +54,7 @@
|
||||
|
||||
uint32_t *arm_syscall(uint32_t *regs)
|
||||
{
|
||||
struct tcb_s *tcb;
|
||||
struct tcb_s *tcb = this_task();
|
||||
uint32_t cmd;
|
||||
int cpu;
|
||||
|
||||
@@ -66,6 +66,7 @@ uint32_t *arm_syscall(uint32_t *regs)
|
||||
* current_regs is also used to manage interrupt level context switches.
|
||||
*/
|
||||
|
||||
tcb->xcp.regs = regs;
|
||||
up_set_current_regs(regs);
|
||||
|
||||
/* The SYSCALL command is in R0 on entry. Parameters follow in R1..R7 */
|
||||
@@ -94,7 +95,7 @@ uint32_t *arm_syscall(uint32_t *regs)
|
||||
* set will determine the restored context.
|
||||
*/
|
||||
|
||||
up_set_current_regs((uint32_t *)regs[REG_R1]);
|
||||
tcb->xcp.regs = (uint32_t *)regs[REG_R1];
|
||||
DEBUGASSERT(up_current_regs());
|
||||
}
|
||||
break;
|
||||
@@ -133,15 +134,9 @@ uint32_t *arm_syscall(uint32_t *regs)
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_ARCH_ADDRENV
|
||||
/* Check for a context switch. If a context switch occurred, then
|
||||
* current_regs will have a different value than it did on entry. If an
|
||||
* interrupt level context switch has occurred, then establish the correct
|
||||
* address environment before returning from the interrupt.
|
||||
*/
|
||||
|
||||
if (regs != up_current_regs())
|
||||
if (regs != tcb->xcp.regs)
|
||||
{
|
||||
#ifdef CONFIG_ARCH_ADDRENV
|
||||
/* Make sure that the address environment for the previously
|
||||
* running task is closed down gracefully (data caches dump,
|
||||
* MMU flushed) and set up the address environment for the new
|
||||
@@ -149,13 +144,8 @@ uint32_t *arm_syscall(uint32_t *regs)
|
||||
*/
|
||||
|
||||
addrenv_switch(NULL);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Restore the cpu lock */
|
||||
|
||||
if (regs != up_current_regs())
|
||||
{
|
||||
/* Record the new "running" task. g_running_tasks[] is only used by
|
||||
* assertion logic for reporting crashes.
|
||||
*/
|
||||
@@ -181,5 +171,5 @@ uint32_t *arm_syscall(uint32_t *regs)
|
||||
* SYS_context_switch system call.
|
||||
*/
|
||||
|
||||
return regs;
|
||||
return tcb->xcp.regs;
|
||||
}
|
||||
|
||||
@@ -42,6 +42,8 @@
|
||||
|
||||
uint32_t *arm_doirq(int irq, uint32_t *regs)
|
||||
{
|
||||
struct tcb_s *tcb = this_task();
|
||||
|
||||
board_autoled_on(LED_INIRQ);
|
||||
#ifdef CONFIG_SUPPRESS_INTERRUPTS
|
||||
PANIC();
|
||||
@@ -49,6 +51,7 @@ uint32_t *arm_doirq(int irq, uint32_t *regs)
|
||||
|
||||
if (regs[REG_EXC_RETURN] & EXC_RETURN_THREAD_MODE)
|
||||
{
|
||||
tcb->xcp.regs = regs;
|
||||
up_set_current_regs(regs);
|
||||
}
|
||||
|
||||
@@ -68,17 +71,17 @@ uint32_t *arm_doirq(int irq, uint32_t *regs)
|
||||
|
||||
if (regs[REG_EXC_RETURN] & EXC_RETURN_THREAD_MODE)
|
||||
{
|
||||
/* Restore the cpu lock */
|
||||
tcb = this_task();
|
||||
|
||||
if (regs != up_current_regs())
|
||||
if (regs != tcb->xcp.regs)
|
||||
{
|
||||
/* Record the new "running" task when context switch occurred.
|
||||
* g_running_tasks[] is only used by assertion logic for reporting
|
||||
* crashes.
|
||||
*/
|
||||
|
||||
g_running_tasks[this_cpu()] = this_task();
|
||||
regs = up_current_regs();
|
||||
g_running_tasks[this_cpu()] = tcb;
|
||||
regs = tcb->xcp.regs;
|
||||
}
|
||||
|
||||
/* Update the current_regs to NULL. */
|
||||
|
||||
@@ -78,7 +78,6 @@
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef CONFIG_SMP
|
||||
void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver)
|
||||
{
|
||||
sinfo("tcb=%p sigdeliver=%p\n", tcb, sigdeliver);
|
||||
@@ -94,158 +93,20 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver)
|
||||
* to the currently executing task.
|
||||
*/
|
||||
|
||||
sinfo("rtcb=%p current_regs=%p\n", this_task(), up_current_regs());
|
||||
sinfo("rtcb=%p current_regs=%p\n", this_task(),
|
||||
this_task()->xcp.regs);
|
||||
|
||||
if (tcb == this_task())
|
||||
if (tcb == this_task() && !up_interrupt_context())
|
||||
{
|
||||
/* CASE 1: We are not in an interrupt handler and a task is
|
||||
* signaling itself for some reason.
|
||||
/* In this case just deliver the signal now.
|
||||
* REVISIT: Signal handle will run in a critical section!
|
||||
*/
|
||||
|
||||
if (!up_current_regs())
|
||||
{
|
||||
/* In this case just deliver the signal now.
|
||||
* REVISIT: Signal handle will run in a critical section!
|
||||
*/
|
||||
|
||||
sigdeliver(tcb);
|
||||
tcb->xcp.sigdeliver = NULL;
|
||||
}
|
||||
|
||||
/* 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 PC, CPSR and PRIMASK
|
||||
* registers (and perhaps also the LR). These will be
|
||||
* restored by the signal trampoline after the signal has been
|
||||
* delivered.
|
||||
*/
|
||||
|
||||
/* And make sure that the saved context in the TCB is the same
|
||||
* as the interrupt return context.
|
||||
*/
|
||||
|
||||
arm_savestate(tcb->xcp.saved_regs);
|
||||
|
||||
/* Duplicate the register context. These will be
|
||||
* restored by the signal trampoline after the signal has been
|
||||
* delivered.
|
||||
*/
|
||||
|
||||
up_set_current_regs(up_current_regs() - XCPTCONTEXT_REGS);
|
||||
memcpy(up_current_regs(), tcb->xcp.saved_regs,
|
||||
XCPTCONTEXT_SIZE);
|
||||
|
||||
up_current_regs()[REG_SP] = (uint32_t)(up_current_regs() +
|
||||
XCPTCONTEXT_REGS);
|
||||
|
||||
/* Then set up to vector to the trampoline with interrupts
|
||||
* disabled. The kernel-space trampoline must run in
|
||||
* privileged thread mode.
|
||||
*/
|
||||
|
||||
up_current_regs()[REG_PC] = (uint32_t)arm_sigdeliver;
|
||||
up_current_regs()[REG_PRIMASK] = 1;
|
||||
up_current_regs()[REG_XPSR] = ARMV6M_XPSR_T;
|
||||
#ifdef CONFIG_BUILD_PROTECTED
|
||||
up_current_regs()[REG_LR] = EXC_RETURN_THREAD;
|
||||
up_current_regs()[REG_EXC_RETURN] = EXC_RETURN_THREAD;
|
||||
up_current_regs()[REG_CONTROL] = getcontrol() &
|
||||
~CONTROL_NPRIV;
|
||||
#endif
|
||||
}
|
||||
sigdeliver(tcb);
|
||||
tcb->xcp.sigdeliver = NULL;
|
||||
}
|
||||
|
||||
/* 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 signaling* some non-running task.
|
||||
*/
|
||||
|
||||
else
|
||||
{
|
||||
/* Save the return PC, CPSR and PRIMASK
|
||||
* registers (and perhaps also the LR). These will be restored
|
||||
* by the signal trampoline after the signal has been delivered.
|
||||
*/
|
||||
|
||||
/* Save the current register context location */
|
||||
|
||||
tcb->xcp.saved_regs = tcb->xcp.regs;
|
||||
|
||||
/* Duplicate the register context. These will be
|
||||
* restored by the signal trampoline after the signal has been
|
||||
* delivered.
|
||||
*/
|
||||
|
||||
tcb->xcp.regs = (void *)
|
||||
((uint32_t)tcb->xcp.regs -
|
||||
XCPTCONTEXT_SIZE);
|
||||
memcpy(tcb->xcp.regs, tcb->xcp.saved_regs, XCPTCONTEXT_SIZE);
|
||||
|
||||
tcb->xcp.regs[REG_SP] = (uint32_t)tcb->xcp.regs +
|
||||
XCPTCONTEXT_SIZE;
|
||||
|
||||
/* Then set up to vector to the trampoline with interrupts
|
||||
* disabled. We must already be in privileged thread mode to be
|
||||
* here.
|
||||
*/
|
||||
|
||||
tcb->xcp.regs[REG_PC] = (uint32_t)arm_sigdeliver;
|
||||
tcb->xcp.regs[REG_PRIMASK] = 1;
|
||||
tcb->xcp.regs[REG_XPSR] = ARMV6M_XPSR_T;
|
||||
#ifdef CONFIG_BUILD_PROTECTED
|
||||
tcb->xcp.regs[REG_LR] = EXC_RETURN_THREAD;
|
||||
tcb->xcp.regs[REG_CONTROL] = getcontrol() & ~CONTROL_NPRIV;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* !CONFIG_SMP */
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver)
|
||||
{
|
||||
int cpu;
|
||||
int me;
|
||||
|
||||
sinfo("tcb=%p sigdeliver=%p\n", tcb, sigdeliver);
|
||||
|
||||
/* Refuse to handle nested signal actions */
|
||||
|
||||
if (!tcb->xcp.sigdeliver)
|
||||
{
|
||||
tcb->xcp.sigdeliver = sigdeliver;
|
||||
|
||||
/* First, handle some special cases when the signal is being delivered
|
||||
* to task that is currently executing on any CPU.
|
||||
*/
|
||||
|
||||
sinfo("rtcb=%p current_regs=%p\n", this_task(), up_current_regs());
|
||||
|
||||
if (tcb->task_state == TSTATE_TASK_RUNNING)
|
||||
{
|
||||
me = this_cpu();
|
||||
cpu = tcb->cpu;
|
||||
|
||||
/* CASE 1: We are not in an interrupt handler and a task is
|
||||
* signaling itself for some reason.
|
||||
*/
|
||||
|
||||
if (cpu == me && !up_current_regs())
|
||||
{
|
||||
/* In this case just deliver the signal now.
|
||||
* REVISIT: Signal handler will run in a critical section!
|
||||
*/
|
||||
|
||||
sigdeliver(tcb);
|
||||
tcb->xcp.sigdeliver = NULL;
|
||||
}
|
||||
|
||||
/* CASE 2: The task that needs to receive the signal is running.
|
||||
* This could happen if the task is running on another CPU OR if
|
||||
* we are in an interrupt handler and the task is running on this
|
||||
@@ -254,122 +115,22 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver)
|
||||
* state as well as the state in the TCB.
|
||||
*/
|
||||
|
||||
else
|
||||
/* If we signaling a task running on the other CPU, we have
|
||||
* to PAUSE the other CPU.
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
int cpu = tcb->cpu;
|
||||
int me = this_cpu();
|
||||
|
||||
if (cpu != me)
|
||||
{
|
||||
/* If we signaling a task running on the other CPU, we have
|
||||
* to PAUSE the other CPU.
|
||||
*/
|
||||
/* Pause the CPU */
|
||||
|
||||
if (cpu != me)
|
||||
{
|
||||
/* Pause the CPU */
|
||||
|
||||
up_cpu_pause(cpu);
|
||||
|
||||
/* Now tcb on the other CPU can be accessed safely */
|
||||
|
||||
/* Copy tcb->xcp.regs to tcp.xcp.saved. These will be
|
||||
* restored by the signal trampoline after the signal has
|
||||
* been delivered.
|
||||
*/
|
||||
|
||||
/* Save the current register context location */
|
||||
|
||||
tcb->xcp.saved_regs = tcb->xcp.regs;
|
||||
|
||||
/* Duplicate the register context. These will be
|
||||
* restored by the signal trampoline after the signal has
|
||||
* been delivered.
|
||||
*/
|
||||
|
||||
tcb->xcp.regs = (void *)
|
||||
((uint32_t)tcb->xcp.regs -
|
||||
XCPTCONTEXT_SIZE);
|
||||
memcpy(tcb->xcp.regs, tcb->xcp.saved_regs,
|
||||
XCPTCONTEXT_SIZE);
|
||||
|
||||
tcb->xcp.regs[REG_SP] = (uint32_t)tcb->xcp.regs +
|
||||
XCPTCONTEXT_SIZE;
|
||||
|
||||
/* Then set up vector to the trampoline with interrupts
|
||||
* disabled. We must already be in privileged thread mode
|
||||
* to be here.
|
||||
*/
|
||||
|
||||
tcb->xcp.regs[REG_PC] = (uint32_t)arm_sigdeliver;
|
||||
tcb->xcp.regs[REG_PRIMASK] = 1;
|
||||
tcb->xcp.regs[REG_XPSR] = ARMV6M_XPSR_T;
|
||||
#ifdef CONFIG_BUILD_PROTECTED
|
||||
tcb->xcp.regs[REG_LR] = EXC_RETURN_THREAD;
|
||||
tcb->xcp.regs[REG_CONTROL] = getcontrol() & ~CONTROL_NPRIV;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
/* tcb is running on the same CPU */
|
||||
|
||||
/* Save the return PC, CPSR and either the BASEPRI or
|
||||
* PRIMASK registers (and perhaps also the LR). These
|
||||
* will be restored by the signal trampoline after the
|
||||
* signal has been delivered.
|
||||
*/
|
||||
|
||||
/* And make sure that the saved context in the TCB is the
|
||||
* same as the interrupt return context.
|
||||
*/
|
||||
|
||||
arm_savestate(tcb->xcp.saved_regs);
|
||||
|
||||
/* Duplicate the register context. These will be
|
||||
* restored by the signal trampoline after the signal has
|
||||
* been delivered.
|
||||
*/
|
||||
|
||||
up_set_current_regs(up_current_regs() - XCPTCONTEXT_REGS);
|
||||
memcpy(up_current_regs(), tcb->xcp.saved_regs,
|
||||
XCPTCONTEXT_SIZE);
|
||||
|
||||
up_current_regs()[REG_SP] = (uint32_t)(up_current_regs()
|
||||
+ XCPTCONTEXT_REGS);
|
||||
|
||||
/* Then set up vector to the trampoline with interrupts
|
||||
* disabled. The kernel-space trampoline must run in
|
||||
* privileged thread mode.
|
||||
*/
|
||||
|
||||
up_current_regs()[REG_PC] = (uint32_t)arm_sigdeliver;
|
||||
up_current_regs()[REG_PRIMASK] = 1;
|
||||
up_current_regs()[REG_XPSR] = ARMV6M_XPSR_T;
|
||||
#ifdef CONFIG_BUILD_PROTECTED
|
||||
up_current_regs()[REG_LR] = EXC_RETURN_THREAD;
|
||||
up_current_regs()[REG_CONTROL] = getcontrol() &
|
||||
~CONTROL_NPRIV;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* NOTE: If the task runs on another CPU(cpu), adjusting
|
||||
* global IRQ controls will be done in the pause handler
|
||||
* on the CPU(cpu) by taking a critical section.
|
||||
* If the task is scheduled on this CPU(me), do nothing
|
||||
* because this CPU already took a critical section
|
||||
*/
|
||||
|
||||
/* RESUME the other CPU if it was PAUSED */
|
||||
|
||||
if (cpu != me)
|
||||
{
|
||||
up_cpu_resume(cpu);
|
||||
}
|
||||
up_cpu_pause(cpu);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* 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 signaling some other non-running task.
|
||||
*/
|
||||
|
||||
else
|
||||
{
|
||||
/* Save the return PC, CPSR and either the BASEPRI or PRIMASK
|
||||
* registers (and perhaps also the LR). These will be restored
|
||||
* by the signal trampoline after the signal has been delivered.
|
||||
@@ -377,34 +138,43 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver)
|
||||
|
||||
/* Save the current register context location */
|
||||
|
||||
tcb->xcp.saved_regs = tcb->xcp.regs;
|
||||
tcb->xcp.saved_regs = tcb->xcp.regs;
|
||||
|
||||
/* Duplicate the register context. These will be
|
||||
* restored by the signal trampoline after the signal has been
|
||||
* delivered.
|
||||
*/
|
||||
|
||||
tcb->xcp.regs = (void *)
|
||||
((uint32_t)tcb->xcp.regs -
|
||||
XCPTCONTEXT_SIZE);
|
||||
tcb->xcp.regs = (void *)
|
||||
((uint32_t)tcb->xcp.regs -
|
||||
XCPTCONTEXT_SIZE);
|
||||
memcpy(tcb->xcp.regs, tcb->xcp.saved_regs, XCPTCONTEXT_SIZE);
|
||||
|
||||
tcb->xcp.regs[REG_SP] = (uint32_t)tcb->xcp.regs +
|
||||
XCPTCONTEXT_SIZE;
|
||||
tcb->xcp.regs[REG_SP] = (uint32_t)tcb->xcp.regs +
|
||||
XCPTCONTEXT_SIZE;
|
||||
|
||||
/* Then set up to vector to the trampoline with interrupts
|
||||
* disabled. We must already be in privileged thread mode to be
|
||||
* here.
|
||||
*/
|
||||
|
||||
tcb->xcp.regs[REG_PC] = (uint32_t)arm_sigdeliver;
|
||||
tcb->xcp.regs[REG_PRIMASK] = 1;
|
||||
tcb->xcp.regs[REG_XPSR] = ARMV6M_XPSR_T;
|
||||
tcb->xcp.regs[REG_PC] = (uint32_t)arm_sigdeliver;
|
||||
tcb->xcp.regs[REG_PRIMASK] = 1;
|
||||
tcb->xcp.regs[REG_XPSR] = ARMV6M_XPSR_T;
|
||||
#ifdef CONFIG_BUILD_PROTECTED
|
||||
tcb->xcp.regs[REG_LR] = EXC_RETURN_THREAD;
|
||||
tcb->xcp.regs[REG_CONTROL] = getcontrol() & ~CONTROL_NPRIV;
|
||||
tcb->xcp.regs[REG_LR] = EXC_RETURN_THREAD;
|
||||
tcb->xcp.regs[REG_EXC_RETURN] = EXC_RETURN_THREAD;
|
||||
tcb->xcp.regs[REG_CONTROL] = getcontrol() & ~CONTROL_NPRIV;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
/* RESUME the other CPU if it was PAUSED */
|
||||
|
||||
if (cpu != me)
|
||||
{
|
||||
up_cpu_resume(cpu);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_SMP */
|
||||
|
||||
@@ -117,6 +117,7 @@ static void dispatch_syscall(void)
|
||||
|
||||
int arm_svcall(int irq, void *context, void *arg)
|
||||
{
|
||||
struct tcb_s *tcb = this_task();
|
||||
uint32_t *regs = (uint32_t *)context;
|
||||
uint32_t cmd;
|
||||
|
||||
@@ -167,7 +168,7 @@ int arm_svcall(int irq, void *context, void *arg)
|
||||
case SYS_restore_context:
|
||||
{
|
||||
DEBUGASSERT(regs[REG_R1] != 0);
|
||||
up_set_current_regs((uint32_t *)regs[REG_R1]);
|
||||
tcb->xcp.regs = (uint32_t *)regs[REG_R1];
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -192,7 +193,7 @@ int arm_svcall(int irq, void *context, void *arg)
|
||||
{
|
||||
DEBUGASSERT(regs[REG_R1] != 0 && regs[REG_R2] != 0);
|
||||
*(uint32_t **)regs[REG_R1] = regs;
|
||||
up_set_current_regs((uint32_t *)regs[REG_R2]);
|
||||
tcb->xcp.regs = (uint32_t *)regs[REG_R2];
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -450,23 +451,20 @@ int arm_svcall(int irq, void *context, void *arg)
|
||||
# ifndef CONFIG_DEBUG_SVCALL
|
||||
if (cmd > SYS_switch_context)
|
||||
# else
|
||||
if (regs != up_current_regs())
|
||||
if (regs != tcb->xcp.regs)
|
||||
# endif
|
||||
{
|
||||
regs = (uint32_t *)tcb->xcp.regs;
|
||||
|
||||
svcinfo("SVCall Return:\n");
|
||||
svcinfo(" R0: %08x %08x %08x %08x %08x %08x %08x %08x\n",
|
||||
up_current_regs()[REG_R0], up_current_regs()[REG_R1],
|
||||
up_current_regs()[REG_R2], up_current_regs()[REG_R3],
|
||||
up_current_regs()[REG_R4], up_current_regs()[REG_R5],
|
||||
up_current_regs()[REG_R6], up_current_regs()[REG_R7]);
|
||||
regs[REG_R0], regs[REG_R1], regs[REG_R2], regs[REG_R3],
|
||||
regs[REG_R4], regs[REG_R5], regs[REG_R6], regs[REG_R7]);
|
||||
svcinfo(" R8: %08x %08x %08x %08x %08x %08x %08x %08x\n",
|
||||
up_current_regs()[REG_R8], up_current_regs()[REG_R9],
|
||||
up_current_regs()[REG_R10], up_current_regs()[REG_R11],
|
||||
up_current_regs()[REG_R12], up_current_regs()[REG_R13],
|
||||
up_current_regs()[REG_R14], up_current_regs()[REG_R15]);
|
||||
svcinfo(" PSR: %08x PRIMASK: %08x EXC_RETURN: %08x\n",
|
||||
up_current_regs()[REG_XPSR], up_current_regs()[REG_PRIMASK],
|
||||
up_current_regs()[REG_EXC_RETURN]);
|
||||
regs[REG_R8], regs[REG_R9], regs[REG_R10], regs[REG_R11],
|
||||
regs[REG_R12], regs[REG_R13], regs[REG_R14], regs[REG_R15]);
|
||||
svcinfo(" PSR: %08x EXC_RETURN: %08x CONTROL: %08x\n",
|
||||
regs[REG_XPSR], regs[REG_EXC_RETURN], regs[REG_CONTROL]);
|
||||
}
|
||||
# ifdef CONFIG_DEBUG_SVCALL
|
||||
else
|
||||
|
||||
@@ -117,11 +117,7 @@ int up_cpu_paused_save(void)
|
||||
sched_note_cpu_paused(tcb);
|
||||
#endif
|
||||
|
||||
/* Save the current context at current_regs into the TCB at the head
|
||||
* of the assigned task list for this CPU.
|
||||
*/
|
||||
|
||||
arm_savestate(tcb->xcp.regs);
|
||||
UNUSED(tcb);
|
||||
|
||||
return OK;
|
||||
}
|
||||
@@ -207,11 +203,7 @@ int up_cpu_paused_restore(void)
|
||||
|
||||
nxsched_resume_scheduler(tcb);
|
||||
|
||||
/* Then switch contexts. Any necessary address environment changes
|
||||
* will be made when the interrupt returns.
|
||||
*/
|
||||
|
||||
arm_restorestate(tcb->xcp.regs);
|
||||
UNUSED(tcb);
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
@@ -79,18 +79,8 @@ int arm_start_handler(int irq, void *context, void *arg)
|
||||
|
||||
nxsched_resume_scheduler(tcb);
|
||||
|
||||
/* Dump registers so that we can see what is going to happen on return */
|
||||
UNUSED(tcb);
|
||||
|
||||
#if 0
|
||||
up_dump_register(tcb->xcp.regs);
|
||||
#endif
|
||||
|
||||
/* Then switch contexts. This instantiates the exception context of the
|
||||
* tcb at the head of the assigned task list. In this case, this should
|
||||
* be the CPUs NULL task.
|
||||
*/
|
||||
|
||||
arm_restorestate(tcb->xcp.regs);
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
||||
@@ -53,6 +53,8 @@
|
||||
|
||||
uint32_t *arm_doirq(int irq, uint32_t *regs)
|
||||
{
|
||||
struct tcb_s *tcb = this_task();
|
||||
|
||||
board_autoled_on(LED_INIRQ);
|
||||
#ifdef CONFIG_SUPPRESS_INTERRUPTS
|
||||
PANIC();
|
||||
@@ -61,6 +63,18 @@ uint32_t *arm_doirq(int irq, uint32_t *regs)
|
||||
|
||||
DEBUGASSERT(up_current_regs() == NULL);
|
||||
|
||||
/* if irq == GIC_SMP_CPUSTART
|
||||
* We are initiating the multi-core jumping state to up_idle,
|
||||
* and we will use this_task(). Therefore, it cannot be overridden.
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
if (irq != GIC_SMP_CPUSTART)
|
||||
#endif
|
||||
{
|
||||
tcb->xcp.regs = regs;
|
||||
}
|
||||
|
||||
/* Current regs non-zero indicates that we are processing an interrupt;
|
||||
* current_regs is also used to manage interrupt level context switches.
|
||||
*/
|
||||
@@ -70,10 +84,9 @@ uint32_t *arm_doirq(int irq, uint32_t *regs)
|
||||
/* Deliver the IRQ */
|
||||
|
||||
irq_dispatch(irq, regs);
|
||||
tcb = this_task();
|
||||
|
||||
/* Restore the cpu lock */
|
||||
|
||||
if (regs != up_current_regs())
|
||||
if (regs != tcb->xcp.regs)
|
||||
{
|
||||
#ifdef CONFIG_ARCH_ADDRENV
|
||||
/* Make sure that the address environment for the previously
|
||||
@@ -90,8 +103,8 @@ uint32_t *arm_doirq(int irq, uint32_t *regs)
|
||||
* crashes.
|
||||
*/
|
||||
|
||||
g_running_tasks[this_cpu()] = this_task();
|
||||
regs = up_current_regs();
|
||||
g_running_tasks[this_cpu()] = tcb;
|
||||
regs = tcb->xcp.regs;
|
||||
}
|
||||
|
||||
/* Set current_regs to NULL to indicate that we are no longer in an
|
||||
|
||||
@@ -77,7 +77,6 @@
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef CONFIG_SMP
|
||||
void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver)
|
||||
{
|
||||
sinfo("tcb=%p sigdeliver=%p\n", tcb, sigdeliver);
|
||||
@@ -92,157 +91,20 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver)
|
||||
* to task that is currently executing on this CPU.
|
||||
*/
|
||||
|
||||
sinfo("rtcb=%p current_regs=%p\n", this_task(), up_current_regs());
|
||||
sinfo("rtcb=%p current_regs=%p\n", this_task(),
|
||||
this_task()->xcp.regs);
|
||||
|
||||
if (tcb == this_task())
|
||||
if (tcb == this_task() && !up_interrupt_context())
|
||||
{
|
||||
/* CASE 1: We are not in an interrupt handler and a task is
|
||||
* signaling itself for some reason.
|
||||
/* In this case just deliver the signal now.
|
||||
* REVISIT: Signal handler will run in a critical section!
|
||||
*/
|
||||
|
||||
if (!up_current_regs())
|
||||
{
|
||||
/* In this case just deliver the signal now.
|
||||
* REVISIT: Signal handler will run in a critical section!
|
||||
*/
|
||||
|
||||
sigdeliver(tcb);
|
||||
tcb->xcp.sigdeliver = NULL;
|
||||
}
|
||||
|
||||
/* 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 signaling itself, but a context switch
|
||||
* to another task has occurred so that current_regs does not
|
||||
* refer to the thread of this_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.
|
||||
*/
|
||||
|
||||
/* And make sure that the saved context in the TCB is the same
|
||||
* as the interrupt return context.
|
||||
*/
|
||||
|
||||
arm_savestate(tcb->xcp.saved_regs);
|
||||
|
||||
/* Duplicate the register context. These will be
|
||||
* restored by the signal trampoline after the signal has been
|
||||
* delivered.
|
||||
*/
|
||||
|
||||
up_set_current_regs(up_current_regs() - XCPTCONTEXT_REGS);
|
||||
|
||||
memcpy(up_current_regs(), tcb->xcp.saved_regs,
|
||||
XCPTCONTEXT_SIZE);
|
||||
|
||||
up_current_regs()[REG_SP] = (uint32_t)(up_current_regs() +
|
||||
XCPTCONTEXT_REGS);
|
||||
|
||||
/* Then set up to vector to the trampoline with interrupts
|
||||
* disabled
|
||||
*/
|
||||
|
||||
up_current_regs()[REG_PC] = (uint32_t)arm_sigdeliver;
|
||||
up_current_regs()[REG_CPSR] = (PSR_MODE_SYS | PSR_I_BIT |
|
||||
PSR_F_BIT);
|
||||
#ifdef CONFIG_ARM_THUMB
|
||||
up_current_regs()[REG_CPSR] |= PSR_T_BIT;
|
||||
#endif
|
||||
}
|
||||
sigdeliver(tcb);
|
||||
tcb->xcp.sigdeliver = NULL;
|
||||
}
|
||||
|
||||
/* 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 signaling some other 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 current register context location */
|
||||
|
||||
tcb->xcp.saved_regs = tcb->xcp.regs;
|
||||
|
||||
/* Duplicate the register context. These will be
|
||||
* restored by the signal trampoline after the signal has been
|
||||
* delivered.
|
||||
*/
|
||||
|
||||
tcb->xcp.regs = (void *)
|
||||
((uint32_t)tcb->xcp.regs -
|
||||
XCPTCONTEXT_SIZE);
|
||||
memcpy(tcb->xcp.regs, tcb->xcp.saved_regs, XCPTCONTEXT_SIZE);
|
||||
|
||||
tcb->xcp.regs[REG_SP] = (uint32_t)tcb->xcp.regs +
|
||||
XCPTCONTEXT_SIZE;
|
||||
|
||||
/* Then set up to vector to the trampoline with interrupts
|
||||
* disabled
|
||||
*/
|
||||
|
||||
tcb->xcp.regs[REG_PC] = (uint32_t)arm_sigdeliver;
|
||||
tcb->xcp.regs[REG_CPSR] = (PSR_MODE_SYS | PSR_I_BIT | PSR_F_BIT);
|
||||
#ifdef CONFIG_ARM_THUMB
|
||||
tcb->xcp.regs[REG_CPSR] |= PSR_T_BIT;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* !CONFIG_SMP */
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver)
|
||||
{
|
||||
int cpu;
|
||||
int me;
|
||||
|
||||
sinfo("tcb=%p sigdeliver=%p\n", tcb, sigdeliver);
|
||||
|
||||
/* Refuse to handle nested signal actions */
|
||||
|
||||
if (!tcb->xcp.sigdeliver)
|
||||
{
|
||||
tcb->xcp.sigdeliver = sigdeliver;
|
||||
|
||||
/* First, handle some special cases when the signal is being delivered
|
||||
* to task that is currently executing on any CPU.
|
||||
*/
|
||||
|
||||
sinfo("rtcb=%p current_regs=%p\n", this_task(), up_current_regs());
|
||||
|
||||
if (tcb->task_state == TSTATE_TASK_RUNNING)
|
||||
{
|
||||
me = this_cpu();
|
||||
cpu = tcb->cpu;
|
||||
|
||||
/* CASE 1: We are not in an interrupt handler and a task is
|
||||
* signaling itself for some reason.
|
||||
*/
|
||||
|
||||
if (cpu == me && !up_current_regs())
|
||||
{
|
||||
/* In this case just deliver the signal now.
|
||||
* REVISIT: Signal handler will run in a critical section!
|
||||
*/
|
||||
|
||||
sigdeliver(tcb);
|
||||
tcb->xcp.sigdeliver = NULL;
|
||||
}
|
||||
|
||||
/* CASE 2: The task that needs to receive the signal is running.
|
||||
* This could happen if the task is running on another CPU OR if
|
||||
* we are in an interrupt handler and the task is running on this
|
||||
@@ -251,118 +113,22 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver)
|
||||
* state as well as the state in the TCB.
|
||||
*/
|
||||
|
||||
else
|
||||
/* If we signaling a task running on the other CPU, we have
|
||||
* to PAUSE the other CPU.
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
int cpu = tcb->cpu;
|
||||
int me = this_cpu();
|
||||
|
||||
if (cpu != me)
|
||||
{
|
||||
/* If we signaling a task running on the other CPU, we have
|
||||
* to PAUSE the other CPU.
|
||||
*/
|
||||
/* Pause the CPU */
|
||||
|
||||
if (cpu != me)
|
||||
{
|
||||
/* Pause the CPU */
|
||||
|
||||
up_cpu_pause(cpu);
|
||||
|
||||
/* Now tcb on the other CPU can be accessed safely */
|
||||
|
||||
/* Copy tcb->xcp.regs to tcp.xcp.saved. These will be
|
||||
* restored by the signal trampoline after the signal has
|
||||
* been delivered.
|
||||
*/
|
||||
|
||||
/* Save the current register context location */
|
||||
|
||||
tcb->xcp.saved_regs = tcb->xcp.regs;
|
||||
|
||||
/* Duplicate the register context. These will be
|
||||
* restored by the signal trampoline after the signal has
|
||||
* been delivered.
|
||||
*/
|
||||
|
||||
tcb->xcp.regs = (void *)
|
||||
((uint32_t)tcb->xcp.regs -
|
||||
XCPTCONTEXT_SIZE);
|
||||
memcpy(tcb->xcp.regs, tcb->xcp.saved_regs,
|
||||
XCPTCONTEXT_SIZE);
|
||||
|
||||
tcb->xcp.regs[REG_SP] = (uint32_t)tcb->xcp.regs +
|
||||
XCPTCONTEXT_SIZE;
|
||||
|
||||
/* Then set up to vector to the trampoline with interrupts
|
||||
* disabled
|
||||
*/
|
||||
|
||||
tcb->xcp.regs[REG_PC] = (uint32_t)arm_sigdeliver;
|
||||
tcb->xcp.regs[REG_CPSR] = (PSR_MODE_SYS | PSR_I_BIT |
|
||||
PSR_F_BIT);
|
||||
#ifdef CONFIG_ARM_THUMB
|
||||
tcb->xcp.regs[REG_CPSR] |= PSR_T_BIT;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
/* tcb is running on the same CPU */
|
||||
|
||||
/* Save the return PC, CPSR and either the BASEPRI or
|
||||
* PRIMASK registers (and perhaps also the LR). These will
|
||||
* be restored by the signal trampoline after the signal
|
||||
* has been delivered.
|
||||
*/
|
||||
|
||||
/* And make sure that the saved context in the TCB is the
|
||||
* same as the interrupt return context.
|
||||
*/
|
||||
|
||||
arm_savestate(tcb->xcp.saved_regs);
|
||||
|
||||
/* Duplicate the register context. These will be
|
||||
* restored by the signal trampoline after the signal has
|
||||
* been delivered.
|
||||
*/
|
||||
|
||||
up_set_current_regs(up_current_regs() - XCPTCONTEXT_REGS);
|
||||
memcpy(up_current_regs(), tcb->xcp.saved_regs,
|
||||
XCPTCONTEXT_SIZE);
|
||||
|
||||
up_current_regs()[REG_SP] = (uint32_t)(up_current_regs()
|
||||
+ XCPTCONTEXT_REGS);
|
||||
|
||||
/* Then set up vector to the trampoline with interrupts
|
||||
* disabled. The kernel-space trampoline must run in
|
||||
* privileged thread mode.
|
||||
*/
|
||||
|
||||
up_current_regs()[REG_PC] = (uint32_t)arm_sigdeliver;
|
||||
up_current_regs()[REG_CPSR] = (PSR_MODE_SYS | PSR_I_BIT |
|
||||
PSR_F_BIT);
|
||||
#ifdef CONFIG_ARM_THUMB
|
||||
up_current_regs()[REG_CPSR] |= PSR_T_BIT;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* NOTE: If the task runs on another CPU(cpu), adjusting
|
||||
* global IRQ controls will be done in the pause handler
|
||||
* on the CPU(cpu) by taking a critical section.
|
||||
* If the task is scheduled on this CPU(me), do nothing
|
||||
* because this CPU already took a critical section
|
||||
*/
|
||||
|
||||
/* RESUME the other CPU if it was PAUSED */
|
||||
|
||||
if (cpu != me)
|
||||
{
|
||||
up_cpu_resume(cpu);
|
||||
}
|
||||
up_cpu_pause(cpu);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* 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 signaling some other 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.
|
||||
@@ -394,7 +160,15 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver)
|
||||
#ifdef CONFIG_ARM_THUMB
|
||||
tcb->xcp.regs[REG_CPSR] |= PSR_T_BIT;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
/* RESUME the other CPU if it was PAUSED */
|
||||
|
||||
if (cpu != me)
|
||||
{
|
||||
up_cpu_resume(cpu);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_SMP */
|
||||
|
||||
@@ -160,7 +160,7 @@ static void dispatch_syscall(void)
|
||||
|
||||
uint32_t *arm_syscall(uint32_t *regs)
|
||||
{
|
||||
struct tcb_s *tcb;
|
||||
struct tcb_s *tcb = this_task();
|
||||
uint32_t cmd;
|
||||
int cpu;
|
||||
#ifdef CONFIG_BUILD_KERNEL
|
||||
@@ -171,6 +171,8 @@ uint32_t *arm_syscall(uint32_t *regs)
|
||||
|
||||
DEBUGASSERT(up_current_regs() == NULL);
|
||||
|
||||
tcb->xcp.regs = regs;
|
||||
|
||||
/* Current regs non-zero indicates that we are processing an interrupt;
|
||||
* current_regs is also used to manage interrupt level context switches.
|
||||
*/
|
||||
@@ -272,7 +274,7 @@ uint32_t *arm_syscall(uint32_t *regs)
|
||||
* set will determine the restored context.
|
||||
*/
|
||||
|
||||
up_set_current_regs((uint32_t *)regs[REG_R1]);
|
||||
tcb->xcp.regs = (uint32_t *)regs[REG_R1];
|
||||
DEBUGASSERT(up_current_regs());
|
||||
}
|
||||
break;
|
||||
@@ -298,7 +300,7 @@ uint32_t *arm_syscall(uint32_t *regs)
|
||||
{
|
||||
DEBUGASSERT(regs[REG_R1] != 0 && regs[REG_R2] != 0);
|
||||
*(uint32_t **)regs[REG_R1] = regs;
|
||||
up_set_current_regs((uint32_t *)regs[REG_R2]);
|
||||
tcb->xcp.regs = (uint32_t *)regs[REG_R2];
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -565,15 +567,9 @@ uint32_t *arm_syscall(uint32_t *regs)
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_ARCH_ADDRENV
|
||||
/* Check for a context switch. If a context switch occurred, then
|
||||
* current_regs will have a different value than it did on entry. If an
|
||||
* interrupt level context switch has occurred, then establish the correct
|
||||
* address environment before returning from the interrupt.
|
||||
*/
|
||||
|
||||
if (regs != up_current_regs())
|
||||
if (regs != tcb->xcp.regs)
|
||||
{
|
||||
#ifdef CONFIG_ARCH_ADDRENV
|
||||
/* Make sure that the address environment for the previously
|
||||
* running task is closed down gracefully (data caches dump,
|
||||
* MMU flushed) and set up the address environment for the new
|
||||
@@ -581,13 +577,8 @@ uint32_t *arm_syscall(uint32_t *regs)
|
||||
*/
|
||||
|
||||
addrenv_switch(NULL);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Restore the cpu lock */
|
||||
|
||||
if (regs != up_current_regs())
|
||||
{
|
||||
/* Record the new "running" task. g_running_tasks[] is only used by
|
||||
* assertion logic for reporting crashes.
|
||||
*/
|
||||
@@ -599,7 +590,7 @@ uint32_t *arm_syscall(uint32_t *regs)
|
||||
/* Restore the cpu lock */
|
||||
|
||||
restore_critical_section(tcb, cpu);
|
||||
regs = up_current_regs();
|
||||
regs = tcb->xcp.regs;
|
||||
}
|
||||
|
||||
/* Report what happened */
|
||||
|
||||
@@ -42,6 +42,8 @@
|
||||
|
||||
uint32_t *arm_doirq(int irq, uint32_t *regs)
|
||||
{
|
||||
struct tcb_s *tcb = this_task();
|
||||
|
||||
board_autoled_on(LED_INIRQ);
|
||||
#ifdef CONFIG_SUPPRESS_INTERRUPTS
|
||||
PANIC();
|
||||
@@ -49,6 +51,7 @@ uint32_t *arm_doirq(int irq, uint32_t *regs)
|
||||
|
||||
if (regs[REG_EXC_RETURN] & EXC_RETURN_THREAD_MODE)
|
||||
{
|
||||
tcb->xcp.regs = regs;
|
||||
up_set_current_regs(regs);
|
||||
}
|
||||
|
||||
@@ -68,17 +71,17 @@ uint32_t *arm_doirq(int irq, uint32_t *regs)
|
||||
|
||||
if (regs[REG_EXC_RETURN] & EXC_RETURN_THREAD_MODE)
|
||||
{
|
||||
/* Restore the cpu lock */
|
||||
tcb = this_task();
|
||||
|
||||
if (regs != up_current_regs())
|
||||
if (regs != tcb->xcp.regs)
|
||||
{
|
||||
/* Record the new "running" task when context switch occurred.
|
||||
* g_running_tasks[] is only used by assertion logic for reporting
|
||||
* crashes.
|
||||
*/
|
||||
|
||||
g_running_tasks[this_cpu()] = this_task();
|
||||
regs = up_current_regs();
|
||||
g_running_tasks[this_cpu()] = tcb;
|
||||
regs = tcb->xcp.regs;
|
||||
}
|
||||
|
||||
/* Update the current_regs to NULL. */
|
||||
|
||||
@@ -79,7 +79,6 @@
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef CONFIG_SMP
|
||||
void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver)
|
||||
{
|
||||
sinfo("tcb=%p sigdeliver=%p\n", tcb, sigdeliver);
|
||||
@@ -95,167 +94,20 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver)
|
||||
* to the currently executing task.
|
||||
*/
|
||||
|
||||
sinfo("rtcb=%p current_regs=%p\n", this_task(), up_current_regs());
|
||||
sinfo("rtcb=%p current_regs=%p\n", this_task(),
|
||||
this_task()->xcp.regs);
|
||||
|
||||
if (tcb == this_task())
|
||||
if (tcb == this_task() && !up_interrupt_context())
|
||||
{
|
||||
/* CASE 1: We are not in an interrupt handler and a task is
|
||||
* signaling itself for some reason.
|
||||
/* In this case just deliver the signal now.
|
||||
* REVISIT: Signal handle will run in a critical section!
|
||||
*/
|
||||
|
||||
if (!up_current_regs())
|
||||
{
|
||||
/* In this case just deliver the signal now.
|
||||
* REVISIT: Signal handle will run in a critical section!
|
||||
*/
|
||||
|
||||
sigdeliver(tcb);
|
||||
tcb->xcp.sigdeliver = NULL;
|
||||
}
|
||||
|
||||
/* 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 PC, CPSR and either the BASEPRI or PRIMASK
|
||||
* registers (and perhaps also the LR). These will be
|
||||
* restored by the signal trampoline after the signal has been
|
||||
* delivered.
|
||||
*/
|
||||
|
||||
/* And make sure that the saved context in the TCB is the same
|
||||
* as the interrupt return context.
|
||||
*/
|
||||
|
||||
arm_savestate(tcb->xcp.saved_regs);
|
||||
|
||||
/* Duplicate the register context. These will be
|
||||
* restored by the signal trampoline after the signal has been
|
||||
* delivered.
|
||||
*/
|
||||
|
||||
up_set_current_regs(up_current_regs() - XCPTCONTEXT_REGS);
|
||||
memcpy(up_current_regs(), tcb->xcp.saved_regs,
|
||||
XCPTCONTEXT_SIZE);
|
||||
|
||||
up_current_regs()[REG_SP] = (uint32_t)(up_current_regs() +
|
||||
XCPTCONTEXT_REGS);
|
||||
|
||||
/* Then set up to vector to the trampoline with interrupts
|
||||
* disabled. The kernel-space trampoline must run in
|
||||
* privileged thread mode.
|
||||
*/
|
||||
|
||||
up_current_regs()[REG_PC] = (uint32_t)arm_sigdeliver;
|
||||
#ifdef CONFIG_ARMV7M_USEBASEPRI
|
||||
up_current_regs()[REG_BASEPRI] =
|
||||
NVIC_SYSH_DISABLE_PRIORITY;
|
||||
#else
|
||||
up_current_regs()[REG_PRIMASK] = 1;
|
||||
#endif
|
||||
up_current_regs()[REG_XPSR] = ARMV7M_XPSR_T;
|
||||
#ifdef CONFIG_BUILD_PROTECTED
|
||||
up_current_regs()[REG_LR] = EXC_RETURN_THREAD;
|
||||
up_current_regs()[REG_EXC_RETURN] = EXC_RETURN_THREAD;
|
||||
up_current_regs()[REG_CONTROL] = getcontrol() &
|
||||
~CONTROL_NPRIV;
|
||||
#endif
|
||||
}
|
||||
sigdeliver(tcb);
|
||||
tcb->xcp.sigdeliver = NULL;
|
||||
}
|
||||
|
||||
/* 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 signaling* some non-running task.
|
||||
*/
|
||||
|
||||
else
|
||||
{
|
||||
/* Save the return PC, CPSR and either the BASEPRI or PRIMASK
|
||||
* registers (and perhaps also the LR). These will be restored
|
||||
* by the signal trampoline after the signal has been delivered.
|
||||
*/
|
||||
|
||||
/* Save the current register context location */
|
||||
|
||||
tcb->xcp.saved_regs = tcb->xcp.regs;
|
||||
|
||||
/* Duplicate the register context. These will be
|
||||
* restored by the signal trampoline after the signal has been
|
||||
* delivered.
|
||||
*/
|
||||
|
||||
tcb->xcp.regs = (void *)
|
||||
((uint32_t)tcb->xcp.regs -
|
||||
XCPTCONTEXT_SIZE);
|
||||
memcpy(tcb->xcp.regs, tcb->xcp.saved_regs, XCPTCONTEXT_SIZE);
|
||||
|
||||
tcb->xcp.regs[REG_SP] = (uint32_t)tcb->xcp.regs +
|
||||
XCPTCONTEXT_SIZE;
|
||||
|
||||
/* Then set up to vector to the trampoline with interrupts
|
||||
* disabled. We must already be in privileged thread mode to be
|
||||
* here.
|
||||
*/
|
||||
|
||||
tcb->xcp.regs[REG_PC] = (uint32_t)arm_sigdeliver;
|
||||
#ifdef CONFIG_ARMV7M_USEBASEPRI
|
||||
tcb->xcp.regs[REG_BASEPRI] = NVIC_SYSH_DISABLE_PRIORITY;
|
||||
#else
|
||||
tcb->xcp.regs[REG_PRIMASK] = 1;
|
||||
#endif
|
||||
tcb->xcp.regs[REG_XPSR] = ARMV7M_XPSR_T;
|
||||
#ifdef CONFIG_BUILD_PROTECTED
|
||||
tcb->xcp.regs[REG_LR] = EXC_RETURN_THREAD;
|
||||
tcb->xcp.regs[REG_CONTROL] = getcontrol() & ~CONTROL_NPRIV;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* !CONFIG_SMP */
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver)
|
||||
{
|
||||
int cpu;
|
||||
int me;
|
||||
|
||||
sinfo("tcb=%p sigdeliver=%p\n", tcb, sigdeliver);
|
||||
|
||||
/* Refuse to handle nested signal actions */
|
||||
|
||||
if (!tcb->xcp.sigdeliver)
|
||||
{
|
||||
tcb->xcp.sigdeliver = sigdeliver;
|
||||
|
||||
/* First, handle some special cases when the signal is being delivered
|
||||
* to task that is currently executing on any CPU.
|
||||
*/
|
||||
|
||||
sinfo("rtcb=%p current_regs=%p\n", this_task(), up_current_regs());
|
||||
|
||||
if (tcb->task_state == TSTATE_TASK_RUNNING)
|
||||
{
|
||||
me = this_cpu();
|
||||
cpu = tcb->cpu;
|
||||
|
||||
/* CASE 1: We are not in an interrupt handler and a task is
|
||||
* signaling itself for some reason.
|
||||
*/
|
||||
|
||||
if (cpu == me && !up_current_regs())
|
||||
{
|
||||
/* In this case just deliver the signal now.
|
||||
* REVISIT: Signal handler will run in a critical section!
|
||||
*/
|
||||
|
||||
sigdeliver(tcb);
|
||||
tcb->xcp.sigdeliver = NULL;
|
||||
}
|
||||
|
||||
/* CASE 2: The task that needs to receive the signal is running.
|
||||
* This could happen if the task is running on another CPU OR if
|
||||
* we are in an interrupt handler and the task is running on this
|
||||
@@ -264,131 +116,22 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver)
|
||||
* state as well as the state in the TCB.
|
||||
*/
|
||||
|
||||
else
|
||||
/* If we signaling a task running on the other CPU, we have
|
||||
* to PAUSE the other CPU.
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
int cpu = tcb->cpu;
|
||||
int me = this_cpu();
|
||||
|
||||
if (cpu != me)
|
||||
{
|
||||
/* If we signaling a task running on the other CPU, we have
|
||||
* to PAUSE the other CPU.
|
||||
*/
|
||||
/* Pause the CPU */
|
||||
|
||||
if (cpu != me)
|
||||
{
|
||||
/* Pause the CPU */
|
||||
|
||||
up_cpu_pause(cpu);
|
||||
|
||||
/* Now tcb on the other CPU can be accessed safely */
|
||||
|
||||
/* Copy tcb->xcp.regs to tcp.xcp.saved. These will be
|
||||
* restored by the signal trampoline after the signal has
|
||||
* been delivered.
|
||||
*/
|
||||
|
||||
/* Save the current register context location */
|
||||
|
||||
tcb->xcp.saved_regs = tcb->xcp.regs;
|
||||
|
||||
/* Duplicate the register context. These will be
|
||||
* restored by the signal trampoline after the signal has
|
||||
* been delivered.
|
||||
*/
|
||||
|
||||
tcb->xcp.regs = (void *)
|
||||
((uint32_t)tcb->xcp.regs -
|
||||
XCPTCONTEXT_SIZE);
|
||||
memcpy(tcb->xcp.regs, tcb->xcp.saved_regs,
|
||||
XCPTCONTEXT_SIZE);
|
||||
|
||||
tcb->xcp.regs[REG_SP] = (uint32_t)tcb->xcp.regs +
|
||||
XCPTCONTEXT_SIZE;
|
||||
|
||||
/* Then set up vector to the trampoline with interrupts
|
||||
* disabled. We must already be in privileged thread mode
|
||||
* to be here.
|
||||
*/
|
||||
|
||||
tcb->xcp.regs[REG_PC] = (uint32_t)arm_sigdeliver;
|
||||
#ifdef CONFIG_ARMV7M_USEBASEPRI
|
||||
tcb->xcp.regs[REG_BASEPRI] = NVIC_SYSH_DISABLE_PRIORITY;
|
||||
#else
|
||||
tcb->xcp.regs[REG_PRIMASK] = 1;
|
||||
#endif
|
||||
tcb->xcp.regs[REG_XPSR] = ARMV7M_XPSR_T;
|
||||
#ifdef CONFIG_BUILD_PROTECTED
|
||||
tcb->xcp.regs[REG_LR] = EXC_RETURN_THREAD;
|
||||
tcb->xcp.regs[REG_CONTROL] = getcontrol() & ~CONTROL_NPRIV;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
/* tcb is running on the same CPU */
|
||||
|
||||
/* Save the return PC, CPSR and either the BASEPRI or
|
||||
* PRIMASK registers (and perhaps also the LR). These
|
||||
* will be restored by the signal trampoline after the
|
||||
* signal has been delivered.
|
||||
*/
|
||||
|
||||
/* And make sure that the saved context in the TCB is the
|
||||
* same as the interrupt return context.
|
||||
*/
|
||||
|
||||
arm_savestate(tcb->xcp.saved_regs);
|
||||
|
||||
/* Duplicate the register context. These will be
|
||||
* restored by the signal trampoline after the signal has
|
||||
* been delivered.
|
||||
*/
|
||||
|
||||
up_set_current_regs(up_current_regs() - XCPTCONTEXT_REGS);
|
||||
memcpy(up_current_regs(), tcb->xcp.saved_regs,
|
||||
XCPTCONTEXT_SIZE);
|
||||
|
||||
up_current_regs()[REG_SP] = (uint32_t)(up_current_regs()
|
||||
+ XCPTCONTEXT_REGS);
|
||||
|
||||
/* Then set up vector to the trampoline with interrupts
|
||||
* disabled. The kernel-space trampoline must run in
|
||||
* privileged thread mode.
|
||||
*/
|
||||
|
||||
up_current_regs()[REG_PC] = (uint32_t)arm_sigdeliver;
|
||||
#ifdef CONFIG_ARMV7M_USEBASEPRI
|
||||
up_current_regs()[REG_BASEPRI] =
|
||||
NVIC_SYSH_DISABLE_PRIORITY;
|
||||
#else
|
||||
up_current_regs()[REG_PRIMASK] = 1;
|
||||
#endif
|
||||
up_current_regs()[REG_XPSR] = ARMV7M_XPSR_T;
|
||||
#ifdef CONFIG_BUILD_PROTECTED
|
||||
up_current_regs()[REG_LR] = EXC_RETURN_THREAD;
|
||||
up_current_regs()[REG_CONTROL] = getcontrol() &
|
||||
~CONTROL_NPRIV;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* NOTE: If the task runs on another CPU(cpu), adjusting
|
||||
* global IRQ controls will be done in the pause handler
|
||||
* on the CPU(cpu) by taking a critical section.
|
||||
* If the task is scheduled on this CPU(me), do nothing
|
||||
* because this CPU already took a critical section
|
||||
*/
|
||||
|
||||
/* RESUME the other CPU if it was PAUSED */
|
||||
|
||||
if (cpu != me)
|
||||
{
|
||||
up_cpu_resume(cpu);
|
||||
}
|
||||
up_cpu_pause(cpu);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* 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 signaling some other non-running task.
|
||||
*/
|
||||
|
||||
else
|
||||
{
|
||||
/* Save the return PC, CPSR and either the BASEPRI or PRIMASK
|
||||
* registers (and perhaps also the LR). These will be restored
|
||||
* by the signal trampoline after the signal has been delivered.
|
||||
@@ -396,38 +139,47 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver)
|
||||
|
||||
/* Save the current register context location */
|
||||
|
||||
tcb->xcp.saved_regs = tcb->xcp.regs;
|
||||
tcb->xcp.saved_regs = tcb->xcp.regs;
|
||||
|
||||
/* Duplicate the register context. These will be
|
||||
* restored by the signal trampoline after the signal has been
|
||||
* delivered.
|
||||
*/
|
||||
|
||||
tcb->xcp.regs = (void *)
|
||||
((uint32_t)tcb->xcp.regs -
|
||||
XCPTCONTEXT_SIZE);
|
||||
tcb->xcp.regs = (void *)
|
||||
((uint32_t)tcb->xcp.regs -
|
||||
XCPTCONTEXT_SIZE);
|
||||
memcpy(tcb->xcp.regs, tcb->xcp.saved_regs, XCPTCONTEXT_SIZE);
|
||||
|
||||
tcb->xcp.regs[REG_SP] = (uint32_t)tcb->xcp.regs +
|
||||
XCPTCONTEXT_SIZE;
|
||||
tcb->xcp.regs[REG_SP] = (uint32_t)tcb->xcp.regs +
|
||||
XCPTCONTEXT_SIZE;
|
||||
|
||||
/* Then set up to vector to the trampoline with interrupts
|
||||
* disabled. We must already be in privileged thread mode to be
|
||||
* here.
|
||||
*/
|
||||
|
||||
tcb->xcp.regs[REG_PC] = (uint32_t)arm_sigdeliver;
|
||||
tcb->xcp.regs[REG_PC] = (uint32_t)arm_sigdeliver;
|
||||
#ifdef CONFIG_ARMV7M_USEBASEPRI
|
||||
tcb->xcp.regs[REG_BASEPRI] = NVIC_SYSH_DISABLE_PRIORITY;
|
||||
tcb->xcp.regs[REG_BASEPRI] = NVIC_SYSH_DISABLE_PRIORITY;
|
||||
#else
|
||||
tcb->xcp.regs[REG_PRIMASK] = 1;
|
||||
tcb->xcp.regs[REG_PRIMASK] = 1;
|
||||
#endif
|
||||
tcb->xcp.regs[REG_XPSR] = ARMV7M_XPSR_T;
|
||||
tcb->xcp.regs[REG_XPSR] = ARMV7M_XPSR_T;
|
||||
#ifdef CONFIG_BUILD_PROTECTED
|
||||
tcb->xcp.regs[REG_LR] = EXC_RETURN_THREAD;
|
||||
tcb->xcp.regs[REG_CONTROL] = getcontrol() & ~CONTROL_NPRIV;
|
||||
tcb->xcp.regs[REG_LR] = EXC_RETURN_THREAD;
|
||||
tcb->xcp.regs[REG_EXC_RETURN] = EXC_RETURN_THREAD;
|
||||
tcb->xcp.regs[REG_CONTROL] = getcontrol() & ~CONTROL_NPRIV;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
/* RESUME the other CPU if it was PAUSED */
|
||||
|
||||
if (cpu != me)
|
||||
{
|
||||
up_cpu_resume(cpu);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_SMP */
|
||||
|
||||
@@ -125,6 +125,7 @@ static void dispatch_syscall(void)
|
||||
|
||||
int arm_svcall(int irq, void *context, void *arg)
|
||||
{
|
||||
struct tcb_s *tcb = this_task();
|
||||
uint32_t *regs = (uint32_t *)context;
|
||||
uint32_t cmd;
|
||||
|
||||
@@ -176,7 +177,7 @@ int arm_svcall(int irq, void *context, void *arg)
|
||||
case SYS_restore_context:
|
||||
{
|
||||
DEBUGASSERT(regs[REG_R1] != 0);
|
||||
up_set_current_regs((uint32_t *)regs[REG_R1]);
|
||||
tcb->xcp.regs = (uint32_t *)regs[REG_R1];
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -201,7 +202,7 @@ int arm_svcall(int irq, void *context, void *arg)
|
||||
{
|
||||
DEBUGASSERT(regs[REG_R1] != 0 && regs[REG_R2] != 0);
|
||||
*(uint32_t **)regs[REG_R1] = regs;
|
||||
up_set_current_regs((uint32_t *)regs[REG_R2]);
|
||||
tcb->xcp.regs = (uint32_t *)regs[REG_R2];
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -459,24 +460,20 @@ int arm_svcall(int irq, void *context, void *arg)
|
||||
# ifndef CONFIG_DEBUG_SVCALL
|
||||
if (cmd > SYS_switch_context)
|
||||
# else
|
||||
if (regs != up_current_regs())
|
||||
if (regs != tcb->xcp.regs)
|
||||
# endif
|
||||
{
|
||||
regs = (uint32_t *)tcb->xcp.regs;
|
||||
|
||||
svcinfo("SVCall Return:\n");
|
||||
svcinfo(" R0: %08x %08x %08x %08x %08x %08x %08x %08x\n",
|
||||
up_current_regs()[REG_R0], up_current_regs()[REG_R1],
|
||||
up_current_regs()[REG_R2], up_current_regs()[REG_R3],
|
||||
up_current_regs()[REG_R4], up_current_regs()[REG_R5],
|
||||
up_current_regs()[REG_R6], up_current_regs()[REG_R7]);
|
||||
regs[REG_R0], regs[REG_R1], regs[REG_R2], regs[REG_R3],
|
||||
regs[REG_R4], regs[REG_R5], regs[REG_R6], regs[REG_R7]);
|
||||
svcinfo(" R8: %08x %08x %08x %08x %08x %08x %08x %08x\n",
|
||||
up_current_regs()[REG_R8], up_current_regs()[REG_R9],
|
||||
up_current_regs()[REG_R10], up_current_regs()[REG_R11],
|
||||
up_current_regs()[REG_R12], up_current_regs()[REG_R13],
|
||||
up_current_regs()[REG_R14], up_current_regs()[REG_R15]);
|
||||
svcinfo(" PSR: %08x EXC_RETURN: %08x, CONTROL: %08x\n",
|
||||
up_current_regs()[REG_XPSR],
|
||||
up_current_regs()[REG_EXC_RETURN],
|
||||
up_current_regs()[REG_CONTROL]);
|
||||
regs[REG_R8], regs[REG_R9], regs[REG_R10], regs[REG_R11],
|
||||
regs[REG_R12], regs[REG_R13], regs[REG_R14], regs[REG_R15]);
|
||||
svcinfo(" PSR: %08x EXC_RETURN: %08x CONTROL: %08x\n",
|
||||
regs[REG_XPSR], regs[REG_EXC_RETURN], regs[REG_CONTROL]);
|
||||
}
|
||||
# ifdef CONFIG_DEBUG_SVCALL
|
||||
else
|
||||
|
||||
@@ -117,11 +117,7 @@ int up_cpu_paused_save(void)
|
||||
sched_note_cpu_paused(tcb);
|
||||
#endif
|
||||
|
||||
/* Save the current context at current_regs into the TCB at the head
|
||||
* of the assigned task list for this CPU.
|
||||
*/
|
||||
|
||||
arm_savestate(tcb->xcp.regs);
|
||||
UNUSED(tcb);
|
||||
|
||||
return OK;
|
||||
}
|
||||
@@ -207,11 +203,7 @@ int up_cpu_paused_restore(void)
|
||||
|
||||
nxsched_resume_scheduler(tcb);
|
||||
|
||||
/* Then switch contexts. Any necessary address environment changes
|
||||
* will be made when the interrupt returns.
|
||||
*/
|
||||
|
||||
arm_restorestate(tcb->xcp.regs);
|
||||
UNUSED(tcb);
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
@@ -79,12 +79,8 @@ int arm_start_handler(int irq, void *context, void *arg)
|
||||
|
||||
nxsched_resume_scheduler(tcb);
|
||||
|
||||
/* Then switch contexts. This instantiates the exception context of the
|
||||
* tcb at the head of the assigned task list. In this case, this should
|
||||
* be the CPUs NULL task.
|
||||
*/
|
||||
UNUSED(tcb);
|
||||
|
||||
arm_restorestate(tcb->xcp.regs);
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
||||
@@ -41,6 +41,8 @@
|
||||
|
||||
uint32_t *arm_doirq(int irq, uint32_t *regs)
|
||||
{
|
||||
struct tcb_s *tcb = this_task();
|
||||
|
||||
board_autoled_on(LED_INIRQ);
|
||||
|
||||
#ifdef CONFIG_SUPPRESS_INTERRUPTS
|
||||
@@ -50,6 +52,18 @@ uint32_t *arm_doirq(int irq, uint32_t *regs)
|
||||
|
||||
DEBUGASSERT(up_current_regs() == NULL);
|
||||
|
||||
/* if irq == GIC_SMP_CPUSTART
|
||||
* We are initiating the multi-core jumping state to up_idle,
|
||||
* and we will use this_task(). Therefore, it cannot be overridden.
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
if (irq != GIC_SMP_CPUSTART)
|
||||
#endif
|
||||
{
|
||||
tcb->xcp.regs = regs;
|
||||
}
|
||||
|
||||
/* Current regs non-zero indicates that we are processing an interrupt;
|
||||
* current_regs is also used to manage interrupt level context switches.
|
||||
*/
|
||||
@@ -59,18 +73,17 @@ uint32_t *arm_doirq(int irq, uint32_t *regs)
|
||||
/* Deliver the IRQ */
|
||||
|
||||
irq_dispatch(irq, regs);
|
||||
tcb = this_task();
|
||||
|
||||
/* Restore the cpu lock */
|
||||
|
||||
if (regs != up_current_regs())
|
||||
if (regs != tcb->xcp.regs)
|
||||
{
|
||||
/* Record the new "running" task when context switch occurred.
|
||||
* g_running_tasks[] is only used by assertion logic for reporting
|
||||
* crashes.
|
||||
*/
|
||||
|
||||
g_running_tasks[this_cpu()] = this_task();
|
||||
regs = up_current_regs();
|
||||
g_running_tasks[this_cpu()] = tcb;
|
||||
regs = tcb->xcp.regs;
|
||||
}
|
||||
|
||||
/* Set current_regs to NULL to indicate that we are no longer in an
|
||||
|
||||
@@ -75,147 +75,12 @@
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef CONFIG_SMP
|
||||
void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver)
|
||||
{
|
||||
sinfo("tcb=%p sigdeliver=%p\n", tcb, sigdeliver);
|
||||
|
||||
/* Refuse to handle nested signal actions */
|
||||
|
||||
if (!tcb->xcp.sigdeliver)
|
||||
{
|
||||
tcb->xcp.sigdeliver = sigdeliver;
|
||||
|
||||
/* First, handle some special cases when the signal is being delivered
|
||||
* to the currently executing task.
|
||||
*/
|
||||
|
||||
sinfo("rtcb=%p current_regs=%p\n", this_task(), up_current_regs());
|
||||
|
||||
if (tcb == this_task())
|
||||
{
|
||||
/* CASE 1: We are not in an interrupt handler and a task is
|
||||
* signalling itself for some reason.
|
||||
*/
|
||||
|
||||
if (!up_current_regs())
|
||||
{
|
||||
/* In this case just deliver the signal now. */
|
||||
|
||||
sigdeliver(tcb);
|
||||
tcb->xcp.sigdeliver = NULL;
|
||||
}
|
||||
|
||||
/* 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 of this_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.
|
||||
*/
|
||||
|
||||
/* And make sure that the saved context in the TCB is the same
|
||||
* as the interrupt return context.
|
||||
*/
|
||||
|
||||
arm_savestate(tcb->xcp.saved_regs);
|
||||
|
||||
/* Duplicate the register context. These will be
|
||||
* restored by the signal trampoline after the signal has been
|
||||
* delivered.
|
||||
*/
|
||||
|
||||
up_set_current_regs(up_current_regs() - XCPTCONTEXT_REGS);
|
||||
memcpy(up_current_regs(), tcb->xcp.saved_regs,
|
||||
XCPTCONTEXT_SIZE);
|
||||
|
||||
up_current_regs()[REG_SP] = (uint32_t)(up_current_regs() +
|
||||
XCPTCONTEXT_REGS);
|
||||
|
||||
/* Then set up to vector to the trampoline with interrupts
|
||||
* disabled
|
||||
*/
|
||||
|
||||
up_current_regs()[REG_PC] = (uint32_t)arm_sigdeliver;
|
||||
up_current_regs()[REG_CPSR] = (PSR_MODE_SYS | PSR_I_BIT |
|
||||
PSR_F_BIT);
|
||||
#ifdef CONFIG_ARM_THUMB
|
||||
up_current_regs()[REG_CPSR] |= PSR_T_BIT;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ENDIAN_BIG
|
||||
up_current_regs()[REG_CPSR] |= PSR_E_BIT;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/* 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.
|
||||
*/
|
||||
|
||||
/* Save the current register context location */
|
||||
|
||||
tcb->xcp.saved_regs = tcb->xcp.regs;
|
||||
|
||||
/* Duplicate the register context. These will be
|
||||
* restored by the signal trampoline after the signal has been
|
||||
* delivered.
|
||||
*/
|
||||
|
||||
tcb->xcp.regs = (void *)
|
||||
((uint32_t)tcb->xcp.regs -
|
||||
XCPTCONTEXT_SIZE);
|
||||
memcpy(tcb->xcp.regs, tcb->xcp.saved_regs, XCPTCONTEXT_SIZE);
|
||||
|
||||
tcb->xcp.regs[REG_SP] = (uint32_t)tcb->xcp.regs +
|
||||
XCPTCONTEXT_SIZE;
|
||||
|
||||
/* Then set up to vector to the trampoline with interrupts
|
||||
* disabled
|
||||
*/
|
||||
|
||||
tcb->xcp.regs[REG_PC] = (uint32_t)arm_sigdeliver;
|
||||
tcb->xcp.regs[REG_CPSR] = (PSR_MODE_SYS | PSR_I_BIT |
|
||||
PSR_F_BIT);
|
||||
#ifdef CONFIG_ARM_THUMB
|
||||
tcb->xcp.regs[REG_CPSR] |= PSR_T_BIT;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ENDIAN_BIG
|
||||
tcb->xcp.regs[REG_CPSR] |= PSR_E_BIT;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver)
|
||||
{
|
||||
int cpu;
|
||||
int me;
|
||||
|
||||
sinfo("tcb=%p sigdeliver=%p\n", tcb, sigdeliver);
|
||||
|
||||
/* Refuse to handle nested signal actions */
|
||||
|
||||
if (!tcb->xcp.sigdeliver)
|
||||
{
|
||||
tcb->xcp.sigdeliver = sigdeliver;
|
||||
@@ -224,147 +89,36 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver)
|
||||
* to task that is currently executing on any CPU.
|
||||
*/
|
||||
|
||||
sinfo("rtcb=%p current_regs=%p\n", this_task(), up_current_regs());
|
||||
sinfo("rtcb=%p current_regs=%p\n", this_task(),
|
||||
this_task()->xcp.regs);
|
||||
|
||||
if (tcb->task_state == TSTATE_TASK_RUNNING)
|
||||
if (tcb == this_task() && !up_interrupt_context())
|
||||
{
|
||||
me = this_cpu();
|
||||
cpu = tcb->cpu;
|
||||
|
||||
/* CASE 1: We are not in an interrupt handler and a task is
|
||||
* signaling itself for some reason.
|
||||
/* In this case just deliver the signal now.
|
||||
* REVISIT: Signal handler will run in a critical section!
|
||||
*/
|
||||
|
||||
if (cpu == me && !up_current_regs())
|
||||
{
|
||||
/* In this case just deliver the signal now.
|
||||
* REVISIT: Signal handler will run in a critical section!
|
||||
*/
|
||||
|
||||
sigdeliver(tcb);
|
||||
tcb->xcp.sigdeliver = NULL;
|
||||
}
|
||||
|
||||
/* CASE 2: The task that needs to receive the signal is running.
|
||||
* This could happen if the task is running on another CPU OR if
|
||||
* we are in an interrupt handler and the task is running on this
|
||||
* CPU. In the former case, we will have to PAUSE the other CPU
|
||||
* first. But in either case, we will have to modify the return
|
||||
* state as well as the state in the TCB.
|
||||
*/
|
||||
|
||||
else
|
||||
{
|
||||
/* If we signaling a task running on the other CPU, we have
|
||||
* to PAUSE the other CPU.
|
||||
*/
|
||||
|
||||
if (cpu != me)
|
||||
{
|
||||
/* Pause the CPU */
|
||||
|
||||
up_cpu_pause(cpu);
|
||||
|
||||
/* Now tcb on the other CPU can be accessed safely */
|
||||
|
||||
/* Copy tcb->xcp.regs to tcp.xcp.saved. These will be
|
||||
* restored by the signal trampoline after the signal has
|
||||
* been delivered.
|
||||
*/
|
||||
|
||||
/* Save the current register context location */
|
||||
|
||||
tcb->xcp.saved_regs = tcb->xcp.regs;
|
||||
|
||||
/* Duplicate the register context. These will be
|
||||
* restored by the signal trampoline after the signal has
|
||||
* been delivered.
|
||||
*/
|
||||
|
||||
tcb->xcp.regs = (void *)
|
||||
((uint32_t)tcb->xcp.regs -
|
||||
XCPTCONTEXT_SIZE);
|
||||
memcpy(tcb->xcp.regs, tcb->xcp.saved_regs,
|
||||
XCPTCONTEXT_SIZE);
|
||||
|
||||
tcb->xcp.regs[REG_SP] = (uint32_t)tcb->xcp.regs +
|
||||
XCPTCONTEXT_SIZE;
|
||||
|
||||
/* Then set up to vector to the trampoline with interrupts
|
||||
* disabled
|
||||
*/
|
||||
|
||||
tcb->xcp.regs[REG_PC] = (uint32_t)arm_sigdeliver;
|
||||
tcb->xcp.regs[REG_CPSR] = (PSR_MODE_SYS | PSR_I_BIT |
|
||||
PSR_F_BIT);
|
||||
#ifdef CONFIG_ARM_THUMB
|
||||
tcb->xcp.regs[REG_CPSR] |= PSR_T_BIT;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
/* tcb is running on the same CPU */
|
||||
|
||||
/* Save the return PC, CPSR and either the BASEPRI or
|
||||
* PRIMASK registers (and perhaps also the LR). These will
|
||||
* be restored by the signal trampoline after the signal
|
||||
* has been delivered.
|
||||
*/
|
||||
|
||||
/* And make sure that the saved context in the TCB is the
|
||||
* same as the interrupt return context.
|
||||
*/
|
||||
|
||||
arm_savestate(tcb->xcp.saved_regs);
|
||||
|
||||
/* Duplicate the register context. These will be
|
||||
* restored by the signal trampoline after the signal has
|
||||
* been delivered.
|
||||
*/
|
||||
|
||||
up_set_current_regs(up_current_regs() - XCPTCONTEXT_REGS);
|
||||
memcpy(up_current_regs(), tcb->xcp.saved_regs,
|
||||
XCPTCONTEXT_SIZE);
|
||||
|
||||
up_current_regs()[REG_SP] = (uint32_t)(up_current_regs()
|
||||
+ XCPTCONTEXT_REGS);
|
||||
|
||||
/* Then set up vector to the trampoline with interrupts
|
||||
* disabled. The kernel-space trampoline must run in
|
||||
* privileged thread mode.
|
||||
*/
|
||||
|
||||
up_current_regs()[REG_PC] = (uint32_t)arm_sigdeliver;
|
||||
up_current_regs()[REG_CPSR] = (PSR_MODE_SYS | PSR_I_BIT |
|
||||
PSR_F_BIT);
|
||||
#ifdef CONFIG_ARM_THUMB
|
||||
up_current_regs()[REG_CPSR] |= PSR_T_BIT;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* NOTE: If the task runs on another CPU(cpu), adjusting
|
||||
* global IRQ controls will be done in the pause handler
|
||||
* on the CPU(cpu) by taking a critical section.
|
||||
* If the task is scheduled on this CPU(me), do nothing
|
||||
* because this CPU already took a critical section
|
||||
*/
|
||||
|
||||
/* RESUME the other CPU if it was PAUSED */
|
||||
|
||||
if (cpu != me)
|
||||
{
|
||||
up_cpu_resume(cpu);
|
||||
}
|
||||
}
|
||||
sigdeliver(tcb);
|
||||
tcb->xcp.sigdeliver = NULL;
|
||||
}
|
||||
|
||||
/* 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 signaling some other non-running task.
|
||||
*/
|
||||
|
||||
else
|
||||
{
|
||||
/* If we signaling a task running on the other CPU, we have
|
||||
* to PAUSE the other CPU.
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
int cpu = tcb->cpu;
|
||||
int me = this_cpu();
|
||||
|
||||
if (cpu != me)
|
||||
{
|
||||
/* Pause the CPU */
|
||||
|
||||
up_cpu_pause(cpu);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Save the return lr and cpsr and one scratch register. These
|
||||
* will be restored by the signal trampoline after the signals
|
||||
* have been delivered.
|
||||
@@ -396,7 +150,15 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver)
|
||||
#ifdef CONFIG_ARM_THUMB
|
||||
tcb->xcp.regs[REG_CPSR] |= PSR_T_BIT;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
/* RESUME the other CPU if it was PAUSED */
|
||||
|
||||
if (cpu != me)
|
||||
{
|
||||
up_cpu_resume(cpu);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -156,7 +156,8 @@ static void dispatch_syscall(void)
|
||||
|
||||
uint32_t *arm_syscall(uint32_t *regs)
|
||||
{
|
||||
struct tcb_s *tcb;
|
||||
struct tcb_s *tcb = this_task();
|
||||
|
||||
uint32_t cmd;
|
||||
int cpu;
|
||||
#ifdef CONFIG_BUILD_PROTECTED
|
||||
@@ -167,6 +168,8 @@ uint32_t *arm_syscall(uint32_t *regs)
|
||||
|
||||
DEBUGASSERT(up_current_regs() == NULL);
|
||||
|
||||
tcb->xcp.regs = regs;
|
||||
|
||||
/* Current regs non-zero indicates that we are processing an interrupt;
|
||||
* current_regs is also used to manage interrupt level context switches.
|
||||
*/
|
||||
@@ -268,7 +271,7 @@ uint32_t *arm_syscall(uint32_t *regs)
|
||||
* set will determine the restored context.
|
||||
*/
|
||||
|
||||
up_set_current_regs((uint32_t *)regs[REG_R1]);
|
||||
tcb->xcp.regs = (uint32_t *)regs[REG_R1];
|
||||
DEBUGASSERT(up_current_regs());
|
||||
}
|
||||
break;
|
||||
@@ -294,7 +297,7 @@ uint32_t *arm_syscall(uint32_t *regs)
|
||||
{
|
||||
DEBUGASSERT(regs[REG_R1] != 0 && regs[REG_R2] != 0);
|
||||
*(uint32_t **)regs[REG_R1] = regs;
|
||||
up_set_current_regs((uint32_t *)regs[REG_R2]);
|
||||
tcb->xcp.regs = (uint32_t *)regs[REG_R2];
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -561,22 +564,19 @@ uint32_t *arm_syscall(uint32_t *regs)
|
||||
break;
|
||||
}
|
||||
|
||||
/* Restore the cpu lock */
|
||||
|
||||
if (regs != up_current_regs())
|
||||
if (regs != tcb->xcp.regs)
|
||||
{
|
||||
/* Record the new "running" task. g_running_tasks[] is only used by
|
||||
* assertion logic for reporting crashes.
|
||||
*/
|
||||
|
||||
cpu = this_cpu();
|
||||
tcb = current_task(cpu);
|
||||
g_running_tasks[cpu] = tcb;
|
||||
|
||||
/* Restore the cpu lock */
|
||||
|
||||
restore_critical_section(tcb, cpu);
|
||||
regs = up_current_regs();
|
||||
regs = tcb->xcp.regs;
|
||||
}
|
||||
|
||||
/* Report what happened */
|
||||
|
||||
@@ -91,6 +91,8 @@ static inline bool arm_from_thread(uint32_t excret)
|
||||
|
||||
uint32_t *arm_doirq(int irq, uint32_t *regs)
|
||||
{
|
||||
struct tcb_s *tcb = this_task();
|
||||
|
||||
board_autoled_on(LED_INIRQ);
|
||||
#ifdef CONFIG_SUPPRESS_INTERRUPTS
|
||||
PANIC();
|
||||
@@ -98,6 +100,7 @@ uint32_t *arm_doirq(int irq, uint32_t *regs)
|
||||
|
||||
if (arm_from_thread(regs[REG_EXC_RETURN]))
|
||||
{
|
||||
tcb->xcp.regs = regs;
|
||||
up_set_current_regs(regs);
|
||||
}
|
||||
|
||||
@@ -117,17 +120,17 @@ uint32_t *arm_doirq(int irq, uint32_t *regs)
|
||||
|
||||
if (arm_from_thread(regs[REG_EXC_RETURN]))
|
||||
{
|
||||
/* Restore the cpu lock */
|
||||
tcb = this_task();
|
||||
|
||||
if (regs != up_current_regs())
|
||||
if (regs != tcb->xcp.regs)
|
||||
{
|
||||
/* Record the new "running" task when context switch occurred.
|
||||
* g_running_tasks[] is only used by assertion logic for reporting
|
||||
* crashes.
|
||||
*/
|
||||
|
||||
g_running_tasks[this_cpu()] = this_task();
|
||||
regs = up_current_regs();
|
||||
g_running_tasks[this_cpu()] = tcb;
|
||||
regs = tcb->xcp.regs;
|
||||
}
|
||||
|
||||
/* Update the current_regs to NULL. */
|
||||
|
||||
@@ -79,7 +79,6 @@
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef CONFIG_SMP
|
||||
void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver)
|
||||
{
|
||||
sinfo("tcb=%p sigdeliver=%p\n", tcb, sigdeliver);
|
||||
@@ -95,167 +94,20 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver)
|
||||
* to the currently executing task.
|
||||
*/
|
||||
|
||||
sinfo("rtcb=%p current_regs=%p\n", this_task(), up_current_regs());
|
||||
sinfo("rtcb=%p current_regs=%p\n", this_task(),
|
||||
this_task()->xcp.regs);
|
||||
|
||||
if (tcb == this_task())
|
||||
if (tcb == this_task() && !up_interrupt_context())
|
||||
{
|
||||
/* CASE 1: We are not in an interrupt handler and a task is
|
||||
* signaling itself for some reason.
|
||||
/* In this case just deliver the signal now.
|
||||
* REVISIT: Signal handle will run in a critical section!
|
||||
*/
|
||||
|
||||
if (!up_current_regs())
|
||||
{
|
||||
/* In this case just deliver the signal now.
|
||||
* REVISIT: Signal handle will run in a critical section!
|
||||
*/
|
||||
|
||||
sigdeliver(tcb);
|
||||
tcb->xcp.sigdeliver = NULL;
|
||||
}
|
||||
|
||||
/* 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 PC, CPSR and either the BASEPRI or PRIMASK
|
||||
* registers (and perhaps also the LR). These will be
|
||||
* restored by the signal trampoline after the signal has been
|
||||
* delivered.
|
||||
*/
|
||||
|
||||
/* And make sure that the saved context in the TCB is the same
|
||||
* as the interrupt return context.
|
||||
*/
|
||||
|
||||
arm_savestate(tcb->xcp.saved_regs);
|
||||
|
||||
/* Duplicate the register context. These will be
|
||||
* restored by the signal trampoline after the signal has been
|
||||
* delivered.
|
||||
*/
|
||||
|
||||
up_set_current_regs(up_current_regs() - XCPTCONTEXT_REGS);
|
||||
memcpy(up_current_regs(), tcb->xcp.saved_regs,
|
||||
XCPTCONTEXT_SIZE);
|
||||
|
||||
up_current_regs()[REG_SP] = (uint32_t)(up_current_regs() +
|
||||
XCPTCONTEXT_REGS);
|
||||
|
||||
/* Then set up to vector to the trampoline with interrupts
|
||||
* disabled. The kernel-space trampoline must run in
|
||||
* privileged thread mode.
|
||||
*/
|
||||
|
||||
up_current_regs()[REG_PC] = (uint32_t)arm_sigdeliver;
|
||||
#ifdef CONFIG_ARMV8M_USEBASEPRI
|
||||
up_current_regs()[REG_BASEPRI] =
|
||||
NVIC_SYSH_DISABLE_PRIORITY;
|
||||
#else
|
||||
up_current_regs()[REG_PRIMASK] = 1;
|
||||
#endif
|
||||
up_current_regs()[REG_XPSR] = ARMV8M_XPSR_T;
|
||||
#ifdef CONFIG_BUILD_PROTECTED
|
||||
up_current_regs()[REG_LR] = EXC_RETURN_THREAD;
|
||||
up_current_regs()[REG_EXC_RETURN] = EXC_RETURN_THREAD;
|
||||
up_current_regs()[REG_CONTROL] = getcontrol() &
|
||||
~CONTROL_NPRIV;
|
||||
#endif
|
||||
}
|
||||
sigdeliver(tcb);
|
||||
tcb->xcp.sigdeliver = NULL;
|
||||
}
|
||||
|
||||
/* 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 signaling* some non-running task.
|
||||
*/
|
||||
|
||||
else
|
||||
{
|
||||
/* Save the return PC, CPSR and either the BASEPRI or PRIMASK
|
||||
* registers (and perhaps also the LR). These will be restored
|
||||
* by the signal trampoline after the signal has been delivered.
|
||||
*/
|
||||
|
||||
/* Save the current register context location */
|
||||
|
||||
tcb->xcp.saved_regs = tcb->xcp.regs;
|
||||
|
||||
/* Duplicate the register context. These will be
|
||||
* restored by the signal trampoline after the signal has been
|
||||
* delivered.
|
||||
*/
|
||||
|
||||
tcb->xcp.regs = (void *)
|
||||
((uint32_t)tcb->xcp.regs -
|
||||
XCPTCONTEXT_SIZE);
|
||||
memcpy(tcb->xcp.regs, tcb->xcp.saved_regs, XCPTCONTEXT_SIZE);
|
||||
|
||||
tcb->xcp.regs[REG_SP] = (uint32_t)tcb->xcp.regs +
|
||||
XCPTCONTEXT_SIZE;
|
||||
|
||||
/* Then set up to vector to the trampoline with interrupts
|
||||
* disabled. We must already be in privileged thread mode to be
|
||||
* here.
|
||||
*/
|
||||
|
||||
tcb->xcp.regs[REG_PC] = (uint32_t)arm_sigdeliver;
|
||||
#ifdef CONFIG_ARMV8M_USEBASEPRI
|
||||
tcb->xcp.regs[REG_BASEPRI] = NVIC_SYSH_DISABLE_PRIORITY;
|
||||
#else
|
||||
tcb->xcp.regs[REG_PRIMASK] = 1;
|
||||
#endif
|
||||
tcb->xcp.regs[REG_XPSR] = ARMV8M_XPSR_T;
|
||||
#ifdef CONFIG_BUILD_PROTECTED
|
||||
tcb->xcp.regs[REG_LR] = EXC_RETURN_THREAD;
|
||||
tcb->xcp.regs[REG_CONTROL] = getcontrol() & ~CONTROL_NPRIV;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* !CONFIG_SMP */
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver)
|
||||
{
|
||||
int cpu;
|
||||
int me;
|
||||
|
||||
sinfo("tcb=%p sigdeliver=%p\n", tcb, sigdeliver);
|
||||
|
||||
/* Refuse to handle nested signal actions */
|
||||
|
||||
if (!tcb->xcp.sigdeliver)
|
||||
{
|
||||
tcb->xcp.sigdeliver = sigdeliver;
|
||||
|
||||
/* First, handle some special cases when the signal is being delivered
|
||||
* to task that is currently executing on any CPU.
|
||||
*/
|
||||
|
||||
sinfo("rtcb=%p current_regs=%p\n", this_task(), up_current_regs());
|
||||
|
||||
if (tcb->task_state == TSTATE_TASK_RUNNING)
|
||||
{
|
||||
me = this_cpu();
|
||||
cpu = tcb->cpu;
|
||||
|
||||
/* CASE 1: We are not in an interrupt handler and a task is
|
||||
* signaling itself for some reason.
|
||||
*/
|
||||
|
||||
if (cpu == me && !up_current_regs())
|
||||
{
|
||||
/* In this case just deliver the signal now.
|
||||
* REVISIT: Signal handler will run in a critical section!
|
||||
*/
|
||||
|
||||
sigdeliver(tcb);
|
||||
tcb->xcp.sigdeliver = NULL;
|
||||
}
|
||||
|
||||
/* CASE 2: The task that needs to receive the signal is running.
|
||||
* This could happen if the task is running on another CPU OR if
|
||||
* we are in an interrupt handler and the task is running on this
|
||||
@@ -264,124 +116,22 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver)
|
||||
* state as well as the state in the TCB.
|
||||
*/
|
||||
|
||||
else
|
||||
/* If we signaling a task running on the other CPU, we have
|
||||
* to PAUSE the other CPU.
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
int cpu = tcb->cpu;
|
||||
int me = this_cpu();
|
||||
|
||||
if (cpu != me)
|
||||
{
|
||||
/* If we signaling a task running on the other CPU, we have
|
||||
* to PAUSE the other CPU.
|
||||
*/
|
||||
/* Pause the CPU */
|
||||
|
||||
if (cpu != me)
|
||||
{
|
||||
/* Pause the CPU */
|
||||
|
||||
up_cpu_pause(cpu);
|
||||
|
||||
/* Now tcb on the other CPU can be accessed safely */
|
||||
|
||||
/* Copy tcb->xcp.regs to tcp.xcp.saved. These will be
|
||||
* restored by the signal trampoline after the signal has
|
||||
* been delivered.
|
||||
*/
|
||||
|
||||
/* Save the current register context location */
|
||||
|
||||
tcb->xcp.saved_regs = tcb->xcp.regs;
|
||||
|
||||
/* Duplicate the register context. These will be
|
||||
* restored by the signal trampoline after the signal has
|
||||
* been delivered.
|
||||
*/
|
||||
|
||||
tcb->xcp.regs = (void *)
|
||||
((uint32_t)tcb->xcp.regs -
|
||||
XCPTCONTEXT_SIZE);
|
||||
memcpy(tcb->xcp.regs, tcb->xcp.saved_regs,
|
||||
XCPTCONTEXT_SIZE);
|
||||
|
||||
tcb->xcp.regs[REG_SP] = (uint32_t)tcb->xcp.regs +
|
||||
XCPTCONTEXT_SIZE;
|
||||
|
||||
/* Then set up vector to the trampoline with interrupts
|
||||
* disabled. We must already be in privileged thread mode
|
||||
* to be here.
|
||||
*/
|
||||
|
||||
tcb->xcp.regs[REG_PC] = (uint32_t)arm_sigdeliver;
|
||||
#ifdef CONFIG_ARMV8M_USEBASEPRI
|
||||
tcb->xcp.regs[REG_BASEPRI] = NVIC_SYSH_DISABLE_PRIORITY;
|
||||
#else
|
||||
tcb->xcp.regs[REG_PRIMASK] = 1;
|
||||
#endif
|
||||
tcb->xcp.regs[REG_XPSR] = ARMV8M_XPSR_T;
|
||||
#ifdef CONFIG_BUILD_PROTECTED
|
||||
tcb->xcp.regs[REG_LR] = EXC_RETURN_THREAD;
|
||||
tcb->xcp.regs[REG_CONTROL] = getcontrol() & ~CONTROL_NPRIV;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
/* tcb is running on the same CPU */
|
||||
|
||||
/* Save the return PC, CPSR and either the BASEPRI or
|
||||
* PRIMASK registers (and perhaps also the LR). These
|
||||
* will be restored by the signal trampoline after the
|
||||
* signal has been delivered.
|
||||
*/
|
||||
|
||||
/* And make sure that the saved context in the TCB is the
|
||||
* same as the interrupt return context.
|
||||
*/
|
||||
|
||||
arm_savestate(tcb->xcp.saved_regs);
|
||||
|
||||
/* Duplicate the register context. These will be
|
||||
* restored by the signal trampoline after the signal has
|
||||
* been delivered.
|
||||
*/
|
||||
|
||||
up_set_current_regs(up_current_regs() - XCPTCONTEXT_REGS);
|
||||
memcpy(up_current_regs(), tcb->xcp.saved_regs,
|
||||
XCPTCONTEXT_SIZE);
|
||||
|
||||
up_current_regs()[REG_SP] = (uint32_t)(up_current_regs()
|
||||
+ XCPTCONTEXT_REGS);
|
||||
|
||||
/* Then set up vector to the trampoline with interrupts
|
||||
* disabled. The kernel-space trampoline must run in
|
||||
* privileged thread mode.
|
||||
*/
|
||||
|
||||
up_current_regs()[REG_PC] = (uint32_t)arm_sigdeliver;
|
||||
#ifdef CONFIG_ARMV8M_USEBASEPRI
|
||||
up_current_regs()[REG_BASEPRI] =
|
||||
NVIC_SYSH_DISABLE_PRIORITY;
|
||||
#else
|
||||
up_current_regs()[REG_PRIMASK] = 1;
|
||||
#endif
|
||||
up_current_regs()[REG_XPSR] = ARMV8M_XPSR_T;
|
||||
#ifdef CONFIG_BUILD_PROTECTED
|
||||
up_current_regs()[REG_LR] = EXC_RETURN_THREAD;
|
||||
up_current_regs()[REG_CONTROL] = getcontrol() &
|
||||
~CONTROL_NPRIV;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* RESUME the other CPU if it was PAUSED */
|
||||
|
||||
if (cpu != me)
|
||||
{
|
||||
up_cpu_resume(cpu);
|
||||
}
|
||||
up_cpu_pause(cpu);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* 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 signaling some other non-running task.
|
||||
*/
|
||||
|
||||
else
|
||||
{
|
||||
/* Save the return PC, CPSR and either the BASEPRI or PRIMASK
|
||||
* registers (and perhaps also the LR). These will be restored
|
||||
* by the signal trampoline after the signal has been delivered.
|
||||
@@ -389,38 +139,47 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver)
|
||||
|
||||
/* Save the current register context location */
|
||||
|
||||
tcb->xcp.saved_regs = tcb->xcp.regs;
|
||||
tcb->xcp.saved_regs = tcb->xcp.regs;
|
||||
|
||||
/* Duplicate the register context. These will be
|
||||
* restored by the signal trampoline after the signal has been
|
||||
* delivered.
|
||||
*/
|
||||
|
||||
tcb->xcp.regs = (void *)
|
||||
((uint32_t)tcb->xcp.regs -
|
||||
XCPTCONTEXT_SIZE);
|
||||
tcb->xcp.regs = (void *)
|
||||
((uint32_t)tcb->xcp.regs -
|
||||
XCPTCONTEXT_SIZE);
|
||||
memcpy(tcb->xcp.regs, tcb->xcp.saved_regs, XCPTCONTEXT_SIZE);
|
||||
|
||||
tcb->xcp.regs[REG_SP] = (uint32_t)tcb->xcp.regs +
|
||||
XCPTCONTEXT_SIZE;
|
||||
tcb->xcp.regs[REG_SP] = (uint32_t)tcb->xcp.regs +
|
||||
XCPTCONTEXT_SIZE;
|
||||
|
||||
/* Then set up to vector to the trampoline with interrupts
|
||||
* disabled. We must already be in privileged thread mode to be
|
||||
* here.
|
||||
*/
|
||||
|
||||
tcb->xcp.regs[REG_PC] = (uint32_t)arm_sigdeliver;
|
||||
tcb->xcp.regs[REG_PC] = (uint32_t)arm_sigdeliver;
|
||||
#ifdef CONFIG_ARMV8M_USEBASEPRI
|
||||
tcb->xcp.regs[REG_BASEPRI] = NVIC_SYSH_DISABLE_PRIORITY;
|
||||
tcb->xcp.regs[REG_BASEPRI] = NVIC_SYSH_DISABLE_PRIORITY;
|
||||
#else
|
||||
tcb->xcp.regs[REG_PRIMASK] = 1;
|
||||
tcb->xcp.regs[REG_PRIMASK] = 1;
|
||||
#endif
|
||||
tcb->xcp.regs[REG_XPSR] = ARMV8M_XPSR_T;
|
||||
tcb->xcp.regs[REG_XPSR] = ARMV8M_XPSR_T;
|
||||
#ifdef CONFIG_BUILD_PROTECTED
|
||||
tcb->xcp.regs[REG_LR] = EXC_RETURN_THREAD;
|
||||
tcb->xcp.regs[REG_CONTROL] = getcontrol() & ~CONTROL_NPRIV;
|
||||
tcb->xcp.regs[REG_LR] = EXC_RETURN_THREAD;
|
||||
tcb->xcp.regs[REG_EXC_RETURN] = EXC_RETURN_THREAD;
|
||||
tcb->xcp.regs[REG_CONTROL] = getcontrol() & ~CONTROL_NPRIV;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
/* RESUME the other CPU if it was PAUSED */
|
||||
|
||||
if (cpu != me)
|
||||
{
|
||||
up_cpu_resume(cpu);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_SMP */
|
||||
|
||||
@@ -124,6 +124,7 @@ static void dispatch_syscall(void)
|
||||
|
||||
int arm_svcall(int irq, void *context, void *arg)
|
||||
{
|
||||
struct tcb_s *tcb = this_task();
|
||||
uint32_t *regs = (uint32_t *)context;
|
||||
uint32_t cmd;
|
||||
|
||||
@@ -175,7 +176,7 @@ int arm_svcall(int irq, void *context, void *arg)
|
||||
case SYS_restore_context:
|
||||
{
|
||||
DEBUGASSERT(regs[REG_R1] != 0);
|
||||
up_set_current_regs((uint32_t *)regs[REG_R1]);
|
||||
tcb->xcp.regs = (uint32_t *)regs[REG_R1];
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -200,7 +201,7 @@ int arm_svcall(int irq, void *context, void *arg)
|
||||
{
|
||||
DEBUGASSERT(regs[REG_R1] != 0 && regs[REG_R2] != 0);
|
||||
*(uint32_t **)regs[REG_R1] = regs;
|
||||
up_set_current_regs((uint32_t *)regs[REG_R2]);
|
||||
tcb->xcp.regs = (uint32_t *)regs[REG_R2];
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -460,24 +461,20 @@ int arm_svcall(int irq, void *context, void *arg)
|
||||
# ifndef CONFIG_DEBUG_SVCALL
|
||||
if (cmd > SYS_switch_context)
|
||||
# else
|
||||
if (regs != up_current_regs())
|
||||
if (regs != tcb->xcp.regs)
|
||||
# endif
|
||||
{
|
||||
regs = (uint32_t *)tcb->xcp.regs;
|
||||
|
||||
svcinfo("SVCall Return:\n");
|
||||
svcinfo(" R0: %08x %08x %08x %08x %08x %08x %08x %08x\n",
|
||||
up_current_regs()[REG_R0], up_current_regs()[REG_R1],
|
||||
up_current_regs()[REG_R2], up_current_regs()[REG_R3],
|
||||
up_current_regs()[REG_R4], up_current_regs()[REG_R5],
|
||||
up_current_regs()[REG_R6], up_current_regs()[REG_R7]);
|
||||
regs[REG_R0], regs[REG_R1], regs[REG_R2], regs[REG_R3],
|
||||
regs[REG_R4], regs[REG_R5], regs[REG_R6], regs[REG_R7]);
|
||||
svcinfo(" R8: %08x %08x %08x %08x %08x %08x %08x %08x\n",
|
||||
up_current_regs()[REG_R8], up_current_regs()[REG_R9],
|
||||
up_current_regs()[REG_R10], up_current_regs()[REG_R11],
|
||||
up_current_regs()[REG_R12], up_current_regs()[REG_R13],
|
||||
up_current_regs()[REG_R14], up_current_regs()[REG_R15]);
|
||||
regs[REG_R8], regs[REG_R9], regs[REG_R10], regs[REG_R11],
|
||||
regs[REG_R12], regs[REG_R13], regs[REG_R14], regs[REG_R15]);
|
||||
svcinfo(" PSR: %08x EXC_RETURN: %08x CONTROL: %08x\n",
|
||||
up_current_regs()[REG_XPSR],
|
||||
up_current_regs()[REG_EXC_RETURN],
|
||||
up_current_regs()[REG_CONTROL]);
|
||||
regs[REG_XPSR], regs[REG_EXC_RETURN], regs[REG_CONTROL]);
|
||||
}
|
||||
# ifdef CONFIG_DEBUG_SVCALL
|
||||
else
|
||||
|
||||
@@ -42,6 +42,8 @@
|
||||
|
||||
uint32_t *arm_doirq(int irq, uint32_t *regs)
|
||||
{
|
||||
struct tcb_s *tcb = this_task();
|
||||
|
||||
board_autoled_on(LED_INIRQ);
|
||||
|
||||
#ifdef CONFIG_SUPPRESS_INTERRUPTS
|
||||
@@ -51,6 +53,16 @@ uint32_t *arm_doirq(int irq, uint32_t *regs)
|
||||
|
||||
DEBUGASSERT(up_current_regs() == NULL);
|
||||
|
||||
/* if irq == GIC_SMP_CPUSTART
|
||||
* We are initiating the multi-core jumping state to up_idle,
|
||||
* and we will use this_task(). Therefore, it cannot be overridden.
|
||||
*/
|
||||
|
||||
if (irq != GIC_SMP_CPUSTART)
|
||||
{
|
||||
tcb->xcp.regs = regs;
|
||||
}
|
||||
|
||||
/* Current regs non-zero indicates that we are processing an interrupt;
|
||||
* current_regs is also used to manage interrupt level context switches.
|
||||
*/
|
||||
@@ -60,10 +72,9 @@ uint32_t *arm_doirq(int irq, uint32_t *regs)
|
||||
/* Deliver the IRQ */
|
||||
|
||||
irq_dispatch(irq, regs);
|
||||
tcb = this_task();
|
||||
|
||||
/* Restore the cpu lock */
|
||||
|
||||
if (regs != up_current_regs())
|
||||
if (regs != tcb->xcp.regs)
|
||||
{
|
||||
/* Record the new "running" task when context switch occurred.
|
||||
* g_running_tasks[] is only used by assertion logic for reporting
|
||||
@@ -71,7 +82,7 @@ uint32_t *arm_doirq(int irq, uint32_t *regs)
|
||||
*/
|
||||
|
||||
g_running_tasks[this_cpu()] = this_task();
|
||||
regs = up_current_regs();
|
||||
regs = tcb->xcp.regs;
|
||||
}
|
||||
|
||||
/* Set current_regs to NULL to indicate that we are no longer in an
|
||||
|
||||
@@ -75,147 +75,12 @@
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef CONFIG_SMP
|
||||
void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver)
|
||||
{
|
||||
sinfo("tcb=%p sigdeliver=%p\n", tcb, sigdeliver);
|
||||
|
||||
/* Refuse to handle nested signal actions */
|
||||
|
||||
if (!tcb->xcp.sigdeliver)
|
||||
{
|
||||
tcb->xcp.sigdeliver = sigdeliver;
|
||||
|
||||
/* First, handle some special cases when the signal is being delivered
|
||||
* to the currently executing task.
|
||||
*/
|
||||
|
||||
sinfo("rtcb=%p current_regs=%p\n", this_task(), up_current_regs());
|
||||
|
||||
if (tcb == this_task())
|
||||
{
|
||||
/* CASE 1: We are not in an interrupt handler and a task is
|
||||
* signalling itself for some reason.
|
||||
*/
|
||||
|
||||
if (!up_current_regs())
|
||||
{
|
||||
/* In this case just deliver the signal now. */
|
||||
|
||||
sigdeliver(tcb);
|
||||
tcb->xcp.sigdeliver = NULL;
|
||||
}
|
||||
|
||||
/* 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 of this_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.
|
||||
*/
|
||||
|
||||
/* And make sure that the saved context in the TCB is the same
|
||||
* as the interrupt return context.
|
||||
*/
|
||||
|
||||
arm_savestate(tcb->xcp.saved_regs);
|
||||
|
||||
/* Duplicate the register context. These will be
|
||||
* restored by the signal trampoline after the signal has been
|
||||
* delivered.
|
||||
*/
|
||||
|
||||
up_set_current_regs(up_current_regs() - XCPTCONTEXT_REGS);
|
||||
memcpy(up_current_regs(), tcb->xcp.saved_regs,
|
||||
XCPTCONTEXT_SIZE);
|
||||
|
||||
up_current_regs()[REG_SP] = (uint32_t)(up_current_regs() +
|
||||
XCPTCONTEXT_REGS);
|
||||
|
||||
/* Then set up to vector to the trampoline with interrupts
|
||||
* disabled
|
||||
*/
|
||||
|
||||
up_current_regs()[REG_PC] = (uint32_t)arm_sigdeliver;
|
||||
up_current_regs()[REG_CPSR] = (PSR_MODE_SYS | PSR_I_BIT |
|
||||
PSR_F_BIT);
|
||||
#ifdef CONFIG_ARM_THUMB
|
||||
up_current_regs()[REG_CPSR] |= PSR_T_BIT;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ENDIAN_BIG
|
||||
up_current_regs()[REG_CPSR] |= PSR_E_BIT;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/* 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.
|
||||
*/
|
||||
|
||||
/* Save the current register context location */
|
||||
|
||||
tcb->xcp.saved_regs = tcb->xcp.regs;
|
||||
|
||||
/* Duplicate the register context. These will be
|
||||
* restored by the signal trampoline after the signal has been
|
||||
* delivered.
|
||||
*/
|
||||
|
||||
tcb->xcp.regs = (void *)
|
||||
((uint32_t)tcb->xcp.regs -
|
||||
XCPTCONTEXT_SIZE);
|
||||
memcpy(tcb->xcp.regs, tcb->xcp.saved_regs, XCPTCONTEXT_SIZE);
|
||||
|
||||
tcb->xcp.regs[REG_SP] = (uint32_t)tcb->xcp.regs +
|
||||
XCPTCONTEXT_SIZE;
|
||||
|
||||
/* Then set up to vector to the trampoline with interrupts
|
||||
* disabled
|
||||
*/
|
||||
|
||||
tcb->xcp.regs[REG_PC] = (uint32_t)arm_sigdeliver;
|
||||
tcb->xcp.regs[REG_CPSR] = (PSR_MODE_SYS | PSR_I_BIT |
|
||||
PSR_F_BIT);
|
||||
#ifdef CONFIG_ARM_THUMB
|
||||
tcb->xcp.regs[REG_CPSR] |= PSR_T_BIT;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ENDIAN_BIG
|
||||
tcb->xcp.regs[REG_CPSR] |= PSR_E_BIT;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver)
|
||||
{
|
||||
int cpu;
|
||||
int me;
|
||||
|
||||
sinfo("tcb=%p sigdeliver=%p\n", tcb, sigdeliver);
|
||||
|
||||
/* Refuse to handle nested signal actions */
|
||||
|
||||
if (!tcb->xcp.sigdeliver)
|
||||
{
|
||||
tcb->xcp.sigdeliver = sigdeliver;
|
||||
@@ -224,154 +89,36 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver)
|
||||
* to task that is currently executing on any CPU.
|
||||
*/
|
||||
|
||||
sinfo("rtcb=%p current_regs=%p\n", this_task(), up_current_regs());
|
||||
sinfo("rtcb=%p current_regs=%p\n", this_task(),
|
||||
this_task()->xcp.regs);
|
||||
|
||||
if (tcb->task_state == TSTATE_TASK_RUNNING)
|
||||
if (tcb == this_task() && !up_interrupt_context())
|
||||
{
|
||||
me = this_cpu();
|
||||
cpu = tcb->cpu;
|
||||
|
||||
/* CASE 1: We are not in an interrupt handler and a task is
|
||||
* signaling itself for some reason.
|
||||
/* In this case just deliver the signal now.
|
||||
* REVISIT: Signal handler will run in a critical section!
|
||||
*/
|
||||
|
||||
if (cpu == me && !up_current_regs())
|
||||
{
|
||||
/* In this case just deliver the signal now.
|
||||
* REVISIT: Signal handler will run in a critical section!
|
||||
*/
|
||||
|
||||
sigdeliver(tcb);
|
||||
tcb->xcp.sigdeliver = NULL;
|
||||
}
|
||||
|
||||
/* CASE 2: The task that needs to receive the signal is running.
|
||||
* This could happen if the task is running on another CPU OR if
|
||||
* we are in an interrupt handler and the task is running on this
|
||||
* CPU. In the former case, we will have to PAUSE the other CPU
|
||||
* first. But in either case, we will have to modify the return
|
||||
* state as well as the state in the TCB.
|
||||
*/
|
||||
|
||||
else
|
||||
{
|
||||
/* If we signaling a task running on the other CPU, we have
|
||||
* to PAUSE the other CPU.
|
||||
*/
|
||||
|
||||
if (cpu != me)
|
||||
{
|
||||
/* Pause the CPU */
|
||||
|
||||
up_cpu_pause(cpu);
|
||||
|
||||
/* Now tcb on the other CPU can be accessed safely */
|
||||
|
||||
/* Copy tcb->xcp.regs to tcp.xcp.saved. These will be
|
||||
* restored by the signal trampoline after the signal has
|
||||
* been delivered.
|
||||
*/
|
||||
|
||||
/* Save the current register context location */
|
||||
|
||||
tcb->xcp.saved_regs = tcb->xcp.regs;
|
||||
|
||||
/* Duplicate the register context. These will be
|
||||
* restored by the signal trampoline after the signal has
|
||||
* been delivered.
|
||||
*/
|
||||
|
||||
tcb->xcp.regs = (void *)
|
||||
((uint32_t)tcb->xcp.regs -
|
||||
XCPTCONTEXT_SIZE);
|
||||
memcpy(tcb->xcp.regs, tcb->xcp.saved_regs,
|
||||
XCPTCONTEXT_SIZE);
|
||||
|
||||
tcb->xcp.regs[REG_SP] = (uint32_t)tcb->xcp.regs +
|
||||
XCPTCONTEXT_SIZE;
|
||||
|
||||
/* Then set up to vector to the trampoline with interrupts
|
||||
* disabled
|
||||
*/
|
||||
|
||||
tcb->xcp.regs[REG_PC] = (uint32_t)arm_sigdeliver;
|
||||
tcb->xcp.regs[REG_CPSR] = (PSR_MODE_SYS | PSR_I_BIT |
|
||||
PSR_F_BIT);
|
||||
#ifdef CONFIG_ARM_THUMB
|
||||
tcb->xcp.regs[REG_CPSR] |= PSR_T_BIT;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
/* tcb is running on the same CPU */
|
||||
|
||||
/* Save the return PC, CPSR and either the BASEPRI or
|
||||
* PRIMASK registers (and perhaps also the LR). These will
|
||||
* be restored by the signal trampoline after the signal
|
||||
* has been delivered.
|
||||
*/
|
||||
|
||||
/* And make sure that the saved context in the TCB is the
|
||||
* same as the interrupt return context.
|
||||
*/
|
||||
|
||||
arm_savestate(tcb->xcp.saved_regs);
|
||||
|
||||
/* Duplicate the register context. These will be
|
||||
* restored by the signal trampoline after the signal has
|
||||
* been delivered.
|
||||
*/
|
||||
|
||||
up_set_current_regs(up_current_regs() - XCPTCONTEXT_REGS);
|
||||
memcpy(up_current_regs(), tcb->xcp.saved_regs,
|
||||
XCPTCONTEXT_SIZE);
|
||||
|
||||
up_current_regs()[REG_SP] = (uint32_t)(up_current_regs()
|
||||
+ XCPTCONTEXT_REGS);
|
||||
|
||||
/* Then set up vector to the trampoline with interrupts
|
||||
* disabled. The kernel-space trampoline must run in
|
||||
* privileged thread mode.
|
||||
*/
|
||||
|
||||
up_current_regs()[REG_PC] = (uint32_t)arm_sigdeliver;
|
||||
up_current_regs()[REG_CPSR] = (PSR_MODE_SYS | PSR_I_BIT |
|
||||
PSR_F_BIT);
|
||||
#ifdef CONFIG_ARM_THUMB
|
||||
up_current_regs()[REG_CPSR] |= PSR_T_BIT;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Increment the IRQ lock count so that when the task is
|
||||
* restarted, it will hold the IRQ spinlock.
|
||||
*/
|
||||
|
||||
DEBUGASSERT(tcb->irqcount < INT16_MAX);
|
||||
tcb->irqcount++;
|
||||
|
||||
/* NOTE: If the task runs on another CPU(cpu), adjusting
|
||||
* global IRQ controls will be done in the pause handler
|
||||
* on the CPU(cpu) by taking a critical section.
|
||||
* If the task is scheduled on this CPU(me), do nothing
|
||||
* because this CPU already took a critical section
|
||||
*/
|
||||
|
||||
/* RESUME the other CPU if it was PAUSED */
|
||||
|
||||
if (cpu != me)
|
||||
{
|
||||
up_cpu_resume(cpu);
|
||||
}
|
||||
}
|
||||
sigdeliver(tcb);
|
||||
tcb->xcp.sigdeliver = NULL;
|
||||
}
|
||||
|
||||
/* 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 signaling some other non-running task.
|
||||
*/
|
||||
|
||||
else
|
||||
{
|
||||
/* If we signaling a task running on the other CPU, we have
|
||||
* to PAUSE the other CPU.
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
int cpu = tcb->cpu;
|
||||
int me = this_cpu();
|
||||
|
||||
if (cpu != me)
|
||||
{
|
||||
/* Pause the CPU */
|
||||
|
||||
up_cpu_pause(cpu);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Save the return lr and cpsr and one scratch register. These
|
||||
* will be restored by the signal trampoline after the signals
|
||||
* have been delivered.
|
||||
@@ -394,13 +141,6 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver)
|
||||
tcb->xcp.regs[REG_SP] = (uint32_t)tcb->xcp.regs +
|
||||
XCPTCONTEXT_SIZE;
|
||||
|
||||
/* Increment the IRQ lock count so that when the task is restarted,
|
||||
* it will hold the IRQ spinlock.
|
||||
*/
|
||||
|
||||
DEBUGASSERT(tcb->irqcount < INT16_MAX);
|
||||
tcb->irqcount++;
|
||||
|
||||
/* Then set up to vector to the trampoline with interrupts
|
||||
* disabled
|
||||
*/
|
||||
@@ -410,7 +150,15 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver)
|
||||
#ifdef CONFIG_ARM_THUMB
|
||||
tcb->xcp.regs[REG_CPSR] |= PSR_T_BIT;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
/* RESUME the other CPU if it was PAUSED */
|
||||
|
||||
if (cpu != me)
|
||||
{
|
||||
up_cpu_resume(cpu);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -156,7 +156,7 @@ static void dispatch_syscall(void)
|
||||
|
||||
uint32_t *arm_syscall(uint32_t *regs)
|
||||
{
|
||||
struct tcb_s *tcb;
|
||||
struct tcb_s *tcb = this_task();
|
||||
uint32_t cmd;
|
||||
int cpu;
|
||||
#ifdef CONFIG_BUILD_PROTECTED
|
||||
@@ -167,6 +167,8 @@ uint32_t *arm_syscall(uint32_t *regs)
|
||||
|
||||
DEBUGASSERT(up_current_regs() == NULL);
|
||||
|
||||
tcb->xcp.regs = regs;
|
||||
|
||||
/* Current regs non-zero indicates that we are processing an interrupt;
|
||||
* current_regs is also used to manage interrupt level context switches.
|
||||
*/
|
||||
@@ -268,7 +270,7 @@ uint32_t *arm_syscall(uint32_t *regs)
|
||||
* set will determine the restored context.
|
||||
*/
|
||||
|
||||
up_set_current_regs((uint32_t *)regs[REG_R1]);
|
||||
tcb->xcp.regs = (uint32_t *)regs[REG_R1];
|
||||
DEBUGASSERT(up_current_regs());
|
||||
}
|
||||
break;
|
||||
@@ -294,7 +296,7 @@ uint32_t *arm_syscall(uint32_t *regs)
|
||||
{
|
||||
DEBUGASSERT(regs[REG_R1] != 0 && regs[REG_R2] != 0);
|
||||
*(uint32_t **)regs[REG_R1] = regs;
|
||||
up_set_current_regs((uint32_t *)regs[REG_R2]);
|
||||
tcb->xcp.regs = (uint32_t *)regs[REG_R2];
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -561,22 +563,19 @@ uint32_t *arm_syscall(uint32_t *regs)
|
||||
break;
|
||||
}
|
||||
|
||||
/* Restore the cpu lock */
|
||||
|
||||
if (regs != up_current_regs())
|
||||
if (regs != tcb->xcp.regs)
|
||||
{
|
||||
/* Record the new "running" task. g_running_tasks[] is only used by
|
||||
* assertion logic for reporting crashes.
|
||||
*/
|
||||
|
||||
cpu = this_cpu();
|
||||
tcb = current_task(cpu);
|
||||
g_running_tasks[cpu] = tcb;
|
||||
|
||||
/* Restore the cpu lock */
|
||||
|
||||
restore_critical_section(tcb, cpu);
|
||||
regs = up_current_regs();
|
||||
regs = tcb->xcp.regs;
|
||||
}
|
||||
|
||||
/* Report what happened */
|
||||
|
||||
@@ -96,11 +96,6 @@
|
||||
|
||||
#define INTSTACK_SIZE (CONFIG_ARCH_INTERRUPTSTACK & ~STACK_ALIGN_MASK)
|
||||
|
||||
/* Macros to handle saving and restoring interrupt state. */
|
||||
|
||||
#define arm_savestate(regs) (regs = up_current_regs())
|
||||
#define arm_restorestate(regs) up_set_current_regs(regs)
|
||||
|
||||
/* Toolchain dependent, linker defined section addresses */
|
||||
|
||||
#if defined(__ICCARM__)
|
||||
|
||||
@@ -63,21 +63,9 @@ void up_switch_context(struct tcb_s *tcb, struct tcb_s *rtcb)
|
||||
|
||||
if (up_current_regs())
|
||||
{
|
||||
/* Yes, then we have to do things differently.
|
||||
* Just copy the current_regs into the OLD rtcb.
|
||||
*/
|
||||
|
||||
arm_savestate(rtcb->xcp.regs);
|
||||
|
||||
/* Update scheduler parameters */
|
||||
|
||||
nxsched_resume_scheduler(tcb);
|
||||
|
||||
/* Then switch contexts. Any necessary address environment
|
||||
* changes will be made when the interrupt returns.
|
||||
*/
|
||||
|
||||
arm_restorestate(tcb->xcp.regs);
|
||||
}
|
||||
|
||||
/* No, then we will need to perform the user context switch */
|
||||
|
||||
@@ -199,11 +199,7 @@ int up_cpu_paused_save(void)
|
||||
sched_note_cpu_paused(tcb);
|
||||
#endif
|
||||
|
||||
/* Save the current context at current_regs into the TCB at the head
|
||||
* of the assigned task list for this CPU.
|
||||
*/
|
||||
|
||||
arm_savestate(tcb->xcp.regs);
|
||||
UNUSED(tcb);
|
||||
|
||||
return OK;
|
||||
}
|
||||
@@ -290,11 +286,7 @@ int up_cpu_paused_restore(void)
|
||||
|
||||
nxsched_resume_scheduler(tcb);
|
||||
|
||||
/* Then switch contexts. Any necessary address environment changes
|
||||
* will be made when the interrupt returns.
|
||||
*/
|
||||
|
||||
arm_restorestate(tcb->xcp.regs);
|
||||
UNUSED(tcb);
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
|
||||
#include "chip.h"
|
||||
#include "arm_internal.h"
|
||||
#include "sched/sched.h"
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
@@ -41,6 +42,8 @@
|
||||
|
||||
uint32_t *arm_decodeirq(uint32_t *regs)
|
||||
{
|
||||
struct tcb_s *tcb = this_task();
|
||||
|
||||
#ifdef CONFIG_SUPPRESS_INTERRUPTS
|
||||
up_set_current_regs(regs);
|
||||
err("ERROR: Unexpected IRQ\n");
|
||||
@@ -78,11 +81,13 @@ uint32_t *arm_decodeirq(uint32_t *regs)
|
||||
*/
|
||||
|
||||
DEBUGASSERT(up_current_regs() == NULL);
|
||||
tcb->xcp.regs = regs;
|
||||
up_set_current_regs(regs);
|
||||
|
||||
/* Deliver the IRQ */
|
||||
|
||||
irq_dispatch(irq, regs);
|
||||
tcb = this_task();
|
||||
|
||||
#ifdef CONFIG_ARCH_ADDRENV
|
||||
/* Check for a context switch. If a context switch occurred, then
|
||||
@@ -92,7 +97,7 @@ uint32_t *arm_decodeirq(uint32_t *regs)
|
||||
* from the interrupt.
|
||||
*/
|
||||
|
||||
if (regs != up_current_regs())
|
||||
if (regs != tcb->xcp.regs)
|
||||
{
|
||||
/* Make sure that the address environment for the previously
|
||||
* running task is closed down gracefully (data caches dump,
|
||||
|
||||
@@ -57,6 +57,8 @@
|
||||
|
||||
uint32_t *arm_decodeirq(uint32_t *regs)
|
||||
{
|
||||
struct tcb_s *tcb = this_task();
|
||||
|
||||
#ifdef CONFIG_SUPPRESS_INTERRUPTS
|
||||
up_set_current_regs(regs);
|
||||
err("ERROR: Unexpected IRQ\n");
|
||||
@@ -74,6 +76,7 @@ uint32_t *arm_decodeirq(uint32_t *regs)
|
||||
|
||||
DEBUGASSERT(up_current_regs() == NULL);
|
||||
up_set_current_regs(regs);
|
||||
tcb->xcp.regs = regs;
|
||||
|
||||
/* Loop while there are pending interrupts to be processed */
|
||||
|
||||
@@ -99,6 +102,7 @@ uint32_t *arm_decodeirq(uint32_t *regs)
|
||||
/* Deliver the IRQ */
|
||||
|
||||
irq_dispatch(irq, regs);
|
||||
tcb = this_task();
|
||||
|
||||
#ifdef CONFIG_ARCH_ADDRENV
|
||||
/* Check for a context switch. If a context switch occurred, then
|
||||
@@ -108,7 +112,7 @@ uint32_t *arm_decodeirq(uint32_t *regs)
|
||||
* from the interrupt.
|
||||
*/
|
||||
|
||||
if (regs != up_current_regs())
|
||||
if (regs != tcb->xcp.regs)
|
||||
{
|
||||
/* Make sure that the address environment for the previously
|
||||
* running task is closed down gracefully (data caches dump,
|
||||
|
||||
@@ -127,11 +127,7 @@ int up_cpu_paused_save(void)
|
||||
sched_note_cpu_paused(tcb);
|
||||
#endif
|
||||
|
||||
/* Save the current context at current_regs into the TCB at the head
|
||||
* of the assigned task list for this CPU.
|
||||
*/
|
||||
|
||||
arm_savestate(tcb->xcp.regs);
|
||||
UNUSED(tcb);
|
||||
|
||||
return OK;
|
||||
}
|
||||
@@ -211,11 +207,7 @@ int up_cpu_paused_restore(void)
|
||||
|
||||
nxsched_resume_scheduler(tcb);
|
||||
|
||||
/* Then switch contexts. Any necessary address environment changes
|
||||
* will be made when the interrupt returns.
|
||||
*/
|
||||
|
||||
arm_restorestate(tcb->xcp.regs);
|
||||
UNUSED(tcb);
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
#include "chip.h"
|
||||
#include "arm_internal.h"
|
||||
#include "lpc214x_vic.h"
|
||||
#include "sched/sched.h"
|
||||
|
||||
/****************************************************************************
|
||||
* Private Data
|
||||
@@ -81,6 +82,8 @@ uint32_t *arm_decodeirq(uint32_t *regs)
|
||||
static uint32_t *lpc214x_decodeirq(uint32_t *regs)
|
||||
#endif
|
||||
{
|
||||
struct tcb_s *tcb = this_task();
|
||||
|
||||
#ifdef CONFIG_SUPPRESS_INTERRUPTS
|
||||
up_set_current_regs(regs);
|
||||
err("ERROR: Unexpected IRQ\n");
|
||||
@@ -125,6 +128,7 @@ static uint32_t *lpc214x_decodeirq(uint32_t *regs)
|
||||
|
||||
savestate = up_current_regs();
|
||||
up_set_current_regs(regs);
|
||||
tcb->xcp.regs = regs;
|
||||
|
||||
/* Deliver the IRQ */
|
||||
|
||||
|
||||
@@ -56,6 +56,7 @@
|
||||
#include "arm_internal.h"
|
||||
#include "lpc2378.h"
|
||||
#include "lpc23xx_vic.h"
|
||||
#include "sched/sched.h"
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
@@ -91,6 +92,8 @@ uint32_t *arm_decodeirq(uint32_t *regs)
|
||||
static uint32_t *lpc23xx_decodeirq(uint32_t *regs)
|
||||
#endif
|
||||
{
|
||||
struct tcb_s *tcb = this_task();
|
||||
|
||||
#ifdef CONFIG_SUPPRESS_INTERRUPTS
|
||||
err("ERROR: Unexpected IRQ\n");
|
||||
up_set_current_regs(regs);
|
||||
@@ -124,6 +127,7 @@ static uint32_t *lpc23xx_decodeirq(uint32_t *regs)
|
||||
|
||||
savestate = up_current_regs();
|
||||
up_set_current_regs(regs);
|
||||
tcb->xcp.regs = regs;
|
||||
|
||||
/* Acknowledge the interrupt */
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
|
||||
#include "chip.h"
|
||||
#include "arm_internal.h"
|
||||
|
||||
#include "sched/sched.h"
|
||||
#include "lpc31_intc.h"
|
||||
|
||||
/****************************************************************************
|
||||
@@ -43,6 +43,8 @@
|
||||
|
||||
uint32_t *arm_decodeirq(uint32_t *regs)
|
||||
{
|
||||
struct tcb_s *tcb = this_task();
|
||||
|
||||
#ifdef CONFIG_SUPPRESS_INTERRUPTS
|
||||
up_set_current_regs(regs);
|
||||
err("ERROR: Unexpected IRQ\n");
|
||||
@@ -84,10 +86,12 @@ uint32_t *arm_decodeirq(uint32_t *regs)
|
||||
|
||||
DEBUGASSERT(up_current_regs() == NULL);
|
||||
up_set_current_regs(regs);
|
||||
tcb->xcp.regs = regs;
|
||||
|
||||
/* Deliver the IRQ */
|
||||
|
||||
irq_dispatch(irq, regs);
|
||||
tcb = this_task();
|
||||
|
||||
#ifdef CONFIG_ARCH_ADDRENV
|
||||
/* Check for a context switch. If a context switch occurred, then
|
||||
@@ -97,7 +101,7 @@ uint32_t *arm_decodeirq(uint32_t *regs)
|
||||
* from the interrupt.
|
||||
*/
|
||||
|
||||
if (regs != up_current_regs())
|
||||
if (regs != tcb->xcp.regs)
|
||||
{
|
||||
/* Make sure that the address environment for the previously
|
||||
* running task is closed down gracefully (data caches dump,
|
||||
|
||||
@@ -260,6 +260,7 @@ void arm_ack_irq(int irq)
|
||||
|
||||
uint32_t *arm_decodeirq(uint32_t *regs)
|
||||
{
|
||||
struct tcb_s *tcb = this_task();
|
||||
uint32_t num;
|
||||
uint32_t status;
|
||||
|
||||
@@ -278,6 +279,7 @@ uint32_t *arm_decodeirq(uint32_t *regs)
|
||||
|
||||
DEBUGASSERT(up_current_regs() == NULL);
|
||||
up_set_current_regs(regs);
|
||||
tcb->xcp.regs = regs;
|
||||
|
||||
irq_dispatch(num, regs);
|
||||
up_set_current_regs(NULL);
|
||||
|
||||
@@ -167,11 +167,7 @@ int up_cpu_paused_save(void)
|
||||
sched_note_cpu_paused(tcb);
|
||||
#endif
|
||||
|
||||
/* Save the current context at current_regs into the TCB at the head
|
||||
* of the assigned task list for this CPU.
|
||||
*/
|
||||
|
||||
arm_savestate(tcb->xcp.regs);
|
||||
UNUSED(tcb);
|
||||
|
||||
return OK;
|
||||
}
|
||||
@@ -251,11 +247,7 @@ int up_cpu_paused_restore(void)
|
||||
|
||||
nxsched_resume_scheduler(tcb);
|
||||
|
||||
/* Then switch contexts. Any necessary address environment changes
|
||||
* will be made when the interrupt returns.
|
||||
*/
|
||||
|
||||
arm_restorestate(tcb->xcp.regs);
|
||||
UNUSED(tcb);
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
@@ -129,11 +129,7 @@ int up_cpu_paused_save(void)
|
||||
sched_note_cpu_paused(tcb);
|
||||
#endif
|
||||
|
||||
/* Save the current context at current_regs into the TCB at the head
|
||||
* of the assigned task list for this CPU.
|
||||
*/
|
||||
|
||||
arm_savestate(tcb->xcp.regs);
|
||||
UNUSED(tcb);
|
||||
|
||||
return OK;
|
||||
}
|
||||
@@ -213,11 +209,7 @@ int up_cpu_paused_restore(void)
|
||||
|
||||
nxsched_resume_scheduler(tcb);
|
||||
|
||||
/* Then switch contexts. Any necessary address environment changes
|
||||
* will be made when the interrupt returns.
|
||||
*/
|
||||
|
||||
arm_restorestate(tcb->xcp.regs);
|
||||
UNUSED(tcb);
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
|
||||
#include "chip.h"
|
||||
#include "arm_internal.h"
|
||||
#include "sched/sched.h"
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
@@ -53,6 +54,8 @@
|
||||
|
||||
uint32_t *arm_decodeirq(uint32_t *regs)
|
||||
{
|
||||
struct tcb_s *tcb = this_task();
|
||||
|
||||
#ifdef CONFIG_SUPPRESS_INTERRUPTS
|
||||
board_autoled_on(LED_INIRQ);
|
||||
up_set_current_regs(regs);
|
||||
@@ -82,6 +85,7 @@ uint32_t *arm_decodeirq(uint32_t *regs)
|
||||
|
||||
savestate = up_current_regs();
|
||||
up_set_current_regs(regs);
|
||||
tcb->xcp.regs = regs;
|
||||
|
||||
/* Acknowledge the interrupt */
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
#include <arch/board/board.h>
|
||||
|
||||
#include "arm_internal.h"
|
||||
|
||||
#include "sched/sched.h"
|
||||
#include "hardware/tlsr82_irq.h"
|
||||
|
||||
/****************************************************************************
|
||||
@@ -57,6 +57,8 @@
|
||||
|
||||
uint32_t *arm_doirq(int irq, uint32_t *regs)
|
||||
{
|
||||
struct tcb_s *tcb = this_task();
|
||||
|
||||
board_autoled_on(LED_INIRQ);
|
||||
#ifdef CONFIG_SUPPRESS_INTERRUPTS
|
||||
PANIC();
|
||||
@@ -78,6 +80,8 @@ uint32_t *arm_doirq(int irq, uint32_t *regs)
|
||||
regs = NULL;
|
||||
}
|
||||
|
||||
tcb->xcp.regs = regs;
|
||||
|
||||
/* Acknowledge the interrupt */
|
||||
|
||||
arm_ack_irq(irq);
|
||||
@@ -85,6 +89,7 @@ uint32_t *arm_doirq(int irq, uint32_t *regs)
|
||||
/* Deliver the IRQ */
|
||||
|
||||
irq_dispatch(irq, up_current_regs());
|
||||
tcb = this_task();
|
||||
|
||||
/* If a context switch occurred while processing the interrupt then
|
||||
* current_regs may have change value. If we return any value different
|
||||
@@ -94,11 +99,9 @@ uint32_t *arm_doirq(int irq, uint32_t *regs)
|
||||
|
||||
if (regs == NULL)
|
||||
{
|
||||
/* Restore the cpu lock */
|
||||
|
||||
if (regs != up_current_regs())
|
||||
if (regs != tcb->xcp.regs)
|
||||
{
|
||||
regs = up_current_regs();
|
||||
regs = tcb->xcp.regs;
|
||||
}
|
||||
|
||||
/* Update the current_regs to NULL. */
|
||||
|
||||
@@ -89,67 +89,15 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver)
|
||||
* being delivered to the currently executing task.
|
||||
*/
|
||||
|
||||
sinfo("rtcb=%p current_regs=%p\n", this_task(), up_current_regs());
|
||||
sinfo("rtcb=%p current_regs=%p\n", this_task(),
|
||||
this_task()->xcp.regs);
|
||||
|
||||
if (tcb == this_task())
|
||||
if (tcb == this_task() && !up_interrupt_context())
|
||||
{
|
||||
/* CASE 1: We are not in an interrupt handler and
|
||||
* a task is signalling itself for some reason.
|
||||
*/
|
||||
/* In this case just deliver the signal now. */
|
||||
|
||||
if (!up_current_regs())
|
||||
{
|
||||
/* In this case just deliver the signal now. */
|
||||
|
||||
sigdeliver(tcb);
|
||||
tcb->xcp.sigdeliver = NULL;
|
||||
}
|
||||
|
||||
/* 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 of this_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.
|
||||
*/
|
||||
|
||||
/* And make sure that the saved context in the TCB
|
||||
* is the same as the interrupt return context.
|
||||
*/
|
||||
|
||||
arm_savestate(tcb->xcp.saved_regs);
|
||||
|
||||
/* Duplicate the register context. These will be
|
||||
* restored by the signal trampoline after the signal has been
|
||||
* delivered.
|
||||
*/
|
||||
|
||||
up_set_current_regs(up_current_regs() - XCPTCONTEXT_REGS);
|
||||
memcpy(up_current_regs(), tcb->xcp.saved_regs,
|
||||
XCPTCONTEXT_SIZE);
|
||||
|
||||
up_current_regs()[REG_SP] = (uint32_t)(up_current_regs() +
|
||||
XCPTCONTEXT_REGS);
|
||||
|
||||
/* Then set up to vector to the trampoline with interrupts
|
||||
* disabled
|
||||
*/
|
||||
|
||||
up_current_regs()[REG_LR] = (uint32_t)arm_sigdeliver;
|
||||
up_current_regs()[REG_CPSR] = PSR_MODE_SVC | PSR_I_BIT;
|
||||
up_current_regs()[REG_IRQ_EN] = 0;
|
||||
}
|
||||
sigdeliver(tcb);
|
||||
tcb->xcp.sigdeliver = NULL;
|
||||
}
|
||||
|
||||
/* Otherwise, we are (1) signaling a task is not running
|
||||
|
||||
Reference in New Issue
Block a user