You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by ra...@apache.org on 2024/10/10 13:31:59 UTC
(nuttx) 04/05: xtensa: g_current_regs is only used to determine if we are in irq, with other functionalities removed.
This is an automated email from the ASF dual-hosted git repository.
raiden00 pushed a commit to branch releases/12.7
in repository https://gitbox.apache.org/repos/asf/nuttx.git
commit 542e46319caa3f989d1e9e3c7d969ee4ad86480d
Author: hujun5 <hu...@xiaomi.com>
AuthorDate: Fri Sep 27 11:42:44 2024 +0800
xtensa: 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
text data bss dec hex filename
178368 876 130604 309848 4ba58 nuttx
after
text data bss dec hex filename
178120 876 130212 309208 4b7d8 nuttx
szie change -248
Signed-off-by: hujun5 <hu...@xiaomi.com>
---
arch/xtensa/src/common/xtensa.h | 7 -
arch/xtensa/src/common/xtensa_cpupause.c | 12 +-
arch/xtensa/src/common/xtensa_irqdispatch.c | 22 +-
arch/xtensa/src/common/xtensa_schedsigaction.c | 327 ++-----------------------
arch/xtensa/src/common/xtensa_swint.c | 19 +-
arch/xtensa/src/common/xtensa_switchcontext.c | 19 +-
6 files changed, 52 insertions(+), 354 deletions(-)
diff --git a/arch/xtensa/src/common/xtensa.h b/arch/xtensa/src/common/xtensa.h
index 0d49184bdb..bae9bd1f81 100644
--- a/arch/xtensa/src/common/xtensa.h
+++ b/arch/xtensa/src/common/xtensa.h
@@ -103,13 +103,6 @@
#define IDLETHREAD_STACKSIZE ((CONFIG_IDLETHREAD_STACKSIZE + 15) & ~15)
#define IDLETHREAD_STACKWORDS (IDLETHREAD_STACKSIZE >> 2)
-/* In the Xtensa model, the state is saved in stack,
- * only a reference stored in TCB.
- */
-
-#define xtensa_savestate(regs) ((regs) = up_current_regs())
-#define xtensa_restorestate(regs) up_set_current_regs(regs)
-
/* Context switching via system calls ***************************************/
#define xtensa_context_restore(regs)\
diff --git a/arch/xtensa/src/common/xtensa_cpupause.c b/arch/xtensa/src/common/xtensa_cpupause.c
index 3709e45da8..1eeb13c584 100644
--- a/arch/xtensa/src/common/xtensa_cpupause.c
+++ b/arch/xtensa/src/common/xtensa_cpupause.c
@@ -102,11 +102,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.
- */
-
- xtensa_savestate(tcb->xcp.regs);
+ UNUSED(tcb);
return OK;
}
@@ -186,11 +182,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.
- */
-
- xtensa_restorestate(tcb->xcp.regs);
+ UNUSED(tcb);
return OK;
}
diff --git a/arch/xtensa/src/common/xtensa_irqdispatch.c b/arch/xtensa/src/common/xtensa_irqdispatch.c
index daca91ba3e..c3023994c8 100644
--- a/arch/xtensa/src/common/xtensa_irqdispatch.c
+++ b/arch/xtensa/src/common/xtensa_irqdispatch.c
@@ -44,6 +44,8 @@
uint32_t *xtensa_irq_dispatch(int irq, uint32_t *regs)
{
+ struct tcb_s *tcb = this_task();
+
#ifdef CONFIG_SUPPRESS_INTERRUPTS
board_autoled_on(LED_INIRQ);
PANIC();
@@ -62,15 +64,23 @@ uint32_t *xtensa_irq_dispatch(int irq, uint32_t *regs)
up_set_current_regs(regs);
+ if (irq != XTENSA_IRQ_SWINT)
+ {
+ /* we are not trigger by syscall */
+
+ tcb->xcp.regs = 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 (regs != up_current_regs())
+ if (regs != tcb->xcp.regs)
{
#ifdef CONFIG_ARCH_ADDRENV
/* Make sure that the address environment for the previously
@@ -92,14 +102,8 @@ uint32_t *xtensa_irq_dispatch(int irq, uint32_t *regs)
* crashes.
*/
- g_running_tasks[this_cpu()] = this_task();
- }
-
- /* Restore the cpu lock */
-
- if (regs != up_current_regs())
- {
- 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
diff --git a/arch/xtensa/src/common/xtensa_schedsigaction.c b/arch/xtensa/src/common/xtensa_schedsigaction.c
index c69fe20d8f..2d3a381583 100644
--- a/arch/xtensa/src/common/xtensa_schedsigaction.c
+++ b/arch/xtensa/src/common/xtensa_schedsigaction.c
@@ -78,11 +78,9 @@
*
****************************************************************************/
-#ifndef CONFIG_SMP
void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver)
{
sinfo("tcb=%p sigdeliver=%p\n", tcb, sigdeliver);
- DEBUGASSERT(tcb != NULL && sigdeliver != NULL);
/* Refuse to handle nested signal actions */
@@ -90,321 +88,33 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver)
{
tcb->xcp.sigdeliver = sigdeliver;
- sinfo("rtcb=%p current_regs=%p\n", this_task(), up_current_regs());
-
/* First, handle some special cases when the signal is being delivered
- * to the currently executing task.
+ * to task that is currently executing on any CPU.
*/
- 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.
- */
-
- 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()!
+ /* In this case just deliver the signal now.
+ * REVISIT: Signal handler will run in a critical section!
*/
- else
- {
- /* Save the context registers. These will be restored by the
- * signal trampoline after the signals have been delivered.
- *
- * NOTE: that hi-priority interrupts are not disabled.
- */
-
- xtensa_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);
-
- /* Then set up to vector to the trampoline with interrupts
- * disabled
- */
-
- up_current_regs()[REG_PC] = (uint32_t)xtensa_sig_deliver;
-#ifdef __XTENSA_CALL0_ABI__
- up_current_regs()[REG_PS] = (uint32_t)
- (PS_INTLEVEL(XCHAL_EXCM_LEVEL) | PS_UM);
-#else
- up_current_regs()[REG_PS] = (uint32_t)
- (PS_INTLEVEL(XCHAL_EXCM_LEVEL) | PS_UM |
- PS_WOE | PS_CALLINC(1));
-#endif
-#ifndef CONFIG_BUILD_FLAT
- xtensa_raiseprivilege(up_current_regs());
-#endif
-
- up_current_regs()[REG_A1] = (uint32_t)(up_current_regs() +
- XCPTCONTEXT_REGS);
- }
+ 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 context registers. These will be restored by the
- * signal trampoline after the signals have been delivered.
- *
- * NOTE: that hi-priority interrupts are not disabled.
- */
-
- 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_A1] = (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)xtensa_sig_deliver;
-#ifdef __XTENSA_CALL0_ABI__
- tcb->xcp.regs[REG_PS] = (uint32_t)
- (PS_INTLEVEL(XCHAL_EXCM_LEVEL) | PS_UM);
-#else
- tcb->xcp.regs[REG_PS] = (uint32_t)
- (PS_INTLEVEL(XCHAL_EXCM_LEVEL) | PS_UM |
- PS_WOE | PS_CALLINC(1));
-#endif
-#ifndef CONFIG_BUILD_FLAT
- xtensa_raiseprivilege(tcb->xcp.regs);
-#endif
- }
- }
-}
-#endif /* !CONFIG_SMP */
-
#ifdef CONFIG_SMP
-void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver)
-{
- int cpu;
- int me;
+ int cpu = tcb->cpu;
+ int me = this_cpu();
- 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())
+ if (cpu != me)
{
- /* In this case just deliver the signal now.
- * REVISIT: Signal handler will run in a critical section!
- */
+ /* Pause the CPU */
- sigdeliver(tcb);
- tcb->xcp.sigdeliver = NULL;
+ up_cpu_pause(cpu);
}
-
- /* 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_regs. These will be
- * restored by the signal trampoline after the signal has
- * been delivered.
- *
- * NOTE: that hi-priority interrupts are not disabled.
- */
-
- tcb->xcp.saved_regs = tcb->xcp.regs;
-
- /* The Inter-Processor Interrupt that pauses the other CPU
- * generates a level-1 interrupt which sets the PS.EXCM.
- * This level-1 interrupt is treated as an Exception and
- * the bit PS.EXCM bit is automatically reset on return
- * from Exception. However, this is not the case here
- * because we are changing the execution to the signal
- * trampoline. Restoring the PS register with PS.EXCM bit
- * set would cause any other exception to deviate execution
- * to the DEC (double exception vector), avoiding it to be
- * treated correctly. According to xtensa ISA: "The process
- * of taking an interrupt does not clear the interrupt
- * request. The process does set PS.EXCM to 1, which
- * disables level-1 interrupts in the interrupt handler.
- * Typically, PS.EXCM is reset to 0 by the handler, after
- * it has set up the stack frame and masked the interrupt."
- * Clean the saved PS.EXCM to 1) avoid an exception from
- * being properly treated and 2) avoid interrupts to be
- * masked while delivering the signal.
- */
-
- if ((tcb->xcp.saved_regs[REG_PS] & PS_EXCM_MASK) != 0)
- {
- tcb->xcp.saved_regs[REG_PS] &= ~PS_EXCM_MASK;
- }
-
- /* 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_A1] = (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)xtensa_sig_deliver;
-#ifdef __XTENSA_CALL0_ABI__
- tcb->xcp.regs[REG_PS] = (uint32_t)
- (PS_INTLEVEL(XCHAL_EXCM_LEVEL) | PS_UM);
-#else
- tcb->xcp.regs[REG_PS] = (uint32_t)
- (PS_INTLEVEL(XCHAL_EXCM_LEVEL) | PS_UM |
- PS_WOE | PS_CALLINC(1));
-#endif
-#ifndef CONFIG_BUILD_FLAT
- xtensa_raiseprivilege(tcb->xcp.regs);
#endif
- }
- else
- {
- /* tcb is running on the same CPU */
-
- /* Copy tcb->xcp.regs to tcp.xcp.saved_regs. These will be
- * restored by the signal trampoline after the signal has
- * been delivered.
- *
- * NOTE: that hi-priority interrupts are not disabled.
- */
-
- xtensa_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_A1] = (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)xtensa_sig_deliver;
-#ifdef __XTENSA_CALL0_ABI__
- up_current_regs()[REG_PS] = (uint32_t)
- (PS_INTLEVEL(XCHAL_EXCM_LEVEL) | PS_UM);
-#else
- up_current_regs()[REG_PS] = (uint32_t)
- (PS_INTLEVEL(XCHAL_EXCM_LEVEL) | PS_UM |
- PS_WOE | PS_CALLINC(1));
-#endif
-#ifndef CONFIG_BUILD_FLAT
- xtensa_raiseprivilege(up_current_regs());
-#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);
- }
- }
- }
-
- /* 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 context registers. These will be restored by the
* signal trampoline after the signals have been delivered.
*
@@ -413,6 +123,11 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver)
tcb->xcp.saved_regs = tcb->xcp.regs;
+ if ((tcb->xcp.saved_regs[REG_PS] & PS_EXCM_MASK) != 0)
+ {
+ tcb->xcp.saved_regs[REG_PS] &= ~PS_EXCM_MASK;
+ }
+
/* Duplicate the register context. These will be
* restored by the signal trampoline after the signal has been
* delivered.
@@ -442,7 +157,15 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver)
#ifndef CONFIG_BUILD_FLAT
xtensa_raiseprivilege(tcb->xcp.regs);
#endif
+
+#ifdef CONFIG_SMP
+ /* RESUME the other CPU if it was PAUSED */
+
+ if (cpu != me)
+ {
+ up_cpu_resume(cpu);
+ }
+#endif
}
}
}
-#endif /* CONFIG_SMP */
diff --git a/arch/xtensa/src/common/xtensa_swint.c b/arch/xtensa/src/common/xtensa_swint.c
index d62a93ded1..943a772430 100644
--- a/arch/xtensa/src/common/xtensa_swint.c
+++ b/arch/xtensa/src/common/xtensa_swint.c
@@ -35,6 +35,7 @@
#include "sched/sched.h"
#include "chip.h"
#include "signal/signal.h"
+#include "sched/sched.h"
#include "xtensa.h"
/****************************************************************************
@@ -57,11 +58,13 @@
int xtensa_swint(int irq, void *context, void *arg)
{
uint32_t *regs = (uint32_t *)context;
+ struct tcb_s *tcb = this_task();
uint32_t cmd;
- DEBUGASSERT(regs != NULL && regs == up_current_regs());
+ DEBUGASSERT(regs != NULL);
cmd = regs[REG_A2];
+ tcb->xcp.regs = regs;
/* The syscall software interrupt is called with A2 = system call command
* and A3..A9 = variable number of arguments depending on the system call.
@@ -116,7 +119,7 @@ int xtensa_swint(int irq, void *context, void *arg)
case SYS_restore_context:
{
DEBUGASSERT(regs[REG_A3] != 0);
- up_set_current_regs((uint32_t *)regs[REG_A3]);
+ tcb->xcp.regs = (uint32_t *)regs[REG_A3];
}
break;
@@ -141,7 +144,7 @@ int xtensa_swint(int irq, void *context, void *arg)
{
DEBUGASSERT(regs[REG_A3] != 0 && regs[REG_A4] != 0);
*(uint32_t **)regs[REG_A3] = regs;
- up_set_current_regs((uint32_t *)regs[REG_A4]);
+ tcb->xcp.regs = (uint32_t *)regs[REG_A4];
}
break;
@@ -419,9 +422,9 @@ int xtensa_swint(int irq, void *context, void *arg)
break;
}
- if ((up_current_regs()[REG_PS] & PS_EXCM_MASK) != 0)
+ if ((tcb->xcp.regs[REG_PS] & PS_EXCM_MASK) != 0)
{
- up_current_regs()[REG_PS] &= ~PS_EXCM_MASK;
+ tcb->xcp.regs[REG_PS] &= ~PS_EXCM_MASK;
}
/* Report what happened. That might difficult in the case of a context
@@ -429,10 +432,10 @@ int xtensa_swint(int irq, void *context, void *arg)
*/
#ifdef CONFIG_DEBUG_SYSCALL_INFO
- if (regs != up_current_regs())
+ if (regs != tcb->xcp.regs)
{
svcinfo("SYSCALL Return: Context switch!\n");
- up_dump_register(up_current_regs());
+ up_dump_register(tcb->xcp.regs);
}
else
{
@@ -440,7 +443,7 @@ int xtensa_swint(int irq, void *context, void *arg)
}
#endif
- if (regs != up_current_regs())
+ if (regs != tcb->xcp.regs)
{
restore_critical_section(this_task(), this_cpu());
}
diff --git a/arch/xtensa/src/common/xtensa_switchcontext.c b/arch/xtensa/src/common/xtensa_switchcontext.c
index ad84e86ef0..a98e3e1069 100644
--- a/arch/xtensa/src/common/xtensa_switchcontext.c
+++ b/arch/xtensa/src/common/xtensa_switchcontext.c
@@ -59,24 +59,7 @@ void up_switch_context(struct tcb_s *tcb, struct tcb_s *rtcb)
{
/* Are we in an interrupt handler? */
- if (up_current_regs())
- {
- /* Yes, then we have to do things differently.
- * Just copy the current_regs into the OLD rtcb.
- */
-
- xtensa_savestate(rtcb->xcp.regs);
-
- /* Then switch contexts. Any necessary address environment
- * changes will be made when the interrupt returns.
- */
-
- xtensa_restorestate(tcb->xcp.regs);
- }
-
- /* No, then we will need to perform the user context switch */
-
- else
+ if (!up_current_regs())
{
/* Switch context to the context of the task at the head of the
* ready to run list.