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 <[email protected]>
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 <[email protected]>
---
 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.

Reply via email to