This is an automated email from the ASF dual-hosted git repository.
xiaoxiang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git
The following commit(s) were added to refs/heads/master by this push:
new c5ecc49c10 riscv: g_current_regs is only used to determine if we are
in irq, with other functionalities removed.
c5ecc49c10 is described below
commit c5ecc49c10586125fa97148ee8aac555dc0a5009
Author: hujun5 <[email protected]>
AuthorDate: Fri Sep 20 20:50:51 2024 +0800
riscv: 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
138805 337 24256 163398 27e46 nuttx
after
text data bss dec hex filename
138499 337 24240 163076 27d04 nuttx
szie change -322
Signed-off-by: hujun5 <[email protected]>
---
arch/risc-v/src/common/riscv_doirq.c | 13 +-
arch/risc-v/src/common/riscv_internal.h | 11 -
arch/risc-v/src/common/riscv_schedulesigaction.c | 293 ++-------------------
arch/risc-v/src/common/riscv_swint.c | 22 +-
.../src/common/supervisor/riscv_perform_syscall.c | 10 +-
5 files changed, 45 insertions(+), 304 deletions(-)
diff --git a/arch/risc-v/src/common/riscv_doirq.c
b/arch/risc-v/src/common/riscv_doirq.c
index 44da81d418..895bd910de 100644
--- a/arch/risc-v/src/common/riscv_doirq.c
+++ b/arch/risc-v/src/common/riscv_doirq.c
@@ -58,6 +58,8 @@
uintreg_t *riscv_doirq(int irq, uintreg_t *regs)
{
+ struct tcb_s *tcb = this_task();
+
board_autoled_on(LED_INIRQ);
#ifdef CONFIG_SUPPRESS_INTERRUPTS
PANIC();
@@ -69,6 +71,10 @@ uintreg_t *riscv_doirq(int irq, uintreg_t *regs)
{
regs[REG_EPC] += 4;
}
+ else
+ {
+ 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.
@@ -82,6 +88,7 @@ uintreg_t *riscv_doirq(int irq, uintreg_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
@@ -90,7 +97,7 @@ uintreg_t *riscv_doirq(int irq, uintreg_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
@@ -107,7 +114,7 @@ uintreg_t *riscv_doirq(int irq, uintreg_t *regs)
* crashes.
*/
- g_running_tasks[this_cpu()] = this_task();
+ g_running_tasks[this_cpu()] = tcb;
/* If a context switch occurred while processing the interrupt then
* current_regs may have change value. If we return any value
@@ -115,7 +122,7 @@ uintreg_t *riscv_doirq(int irq, uintreg_t *regs)
* that a context switch occurred during interrupt processing.
*/
- regs = up_current_regs();
+ regs = tcb->xcp.regs;
}
/* Set current_regs to NULL to indicate that we are no longer in an
diff --git a/arch/risc-v/src/common/riscv_internal.h
b/arch/risc-v/src/common/riscv_internal.h
index 13a887615a..d9165356a9 100644
--- a/arch/risc-v/src/common/riscv_internal.h
+++ b/arch/risc-v/src/common/riscv_internal.h
@@ -85,13 +85,6 @@
/* Interrupt Stack macros */
#define INT_STACK_SIZE (STACK_ALIGN_DOWN(CONFIG_ARCH_INTERRUPTSTACK))
-/* In the RISC-V model, the state is saved in stack,
- * only a reference stored in TCB.
- */
-
-#define riscv_savestate(regs) (regs = up_current_regs())
-#define riscv_restorestate(regs) up_set_current_regs(regs)
-
/* Determine which (if any) console driver to use. If a console is enabled
* and no other console device is specified, then a serial console is
* assumed.
@@ -322,8 +315,6 @@ static inline uintptr_t *riscv_vpuregs(struct tcb_s *tcb)
static inline void riscv_savecontext(struct tcb_s *tcb)
{
- tcb->xcp.regs = (uintreg_t *)up_current_regs();
-
#ifdef CONFIG_ARCH_FPU
/* Save current process FPU state to TCB */
@@ -339,8 +330,6 @@ static inline void riscv_savecontext(struct tcb_s *tcb)
static inline void riscv_restorecontext(struct tcb_s *tcb)
{
- up_set_current_regs(tcb->xcp.regs);
-
#ifdef CONFIG_ARCH_FPU
/* Restore FPU state for next process */
diff --git a/arch/risc-v/src/common/riscv_schedulesigaction.c
b/arch/risc-v/src/common/riscv_schedulesigaction.c
index ecc5260cde..d886443d9e 100644
--- a/arch/risc-v/src/common/riscv_schedulesigaction.c
+++ b/arch/risc-v/src/common/riscv_schedulesigaction.c
@@ -76,7 +76,6 @@
*
****************************************************************************/
-#ifndef CONFIG_SMP
void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver)
{
uintptr_t int_ctx;
@@ -89,289 +88,33 @@ void up_schedule_sigaction(struct tcb_s *tcb,
sig_deliver_t sigdeliver)
{
tcb->xcp.sigdeliver = sigdeliver;
- /* First, handle some special cases when the signal is
- * being delivered to the currently executing task.
+ /* First, handle some special cases when the signal is being delivered
+ * to task that is currently executing on any CPU.
*/
- sinfo("rtcb=%p current_regs=%p\n", this_task(), up_current_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.
- */
-
- 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()!
+ /* 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.
- */
-
- riscv_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. The kernel-space trampoline must run in
- * privileged thread mode.
- */
-
- up_current_regs()[REG_EPC] = (uintptr_t)riscv_sigdeliver;
-
- int_ctx = up_current_regs()[REG_INT_CTX];
- int_ctx &= ~STATUS_PIE;
-#ifndef CONFIG_BUILD_FLAT
- int_ctx |= STATUS_PPP;
-#endif
- up_current_regs()[REG_INT_CTX] = int_ctx;
-
- up_current_regs()[REG_SP] = (uintptr_t)(up_current_regs() +
- XCPTCONTEXT_REGS);
-
- sinfo("PC/STATUS Saved: %" PRIxREG "/%" PRIxREG
- " New: %" PRIxREG "/%" PRIxREG "\n",
- tcb->xcp.saved_regs[REG_EPC],
- tcb->xcp.saved_regs[REG_INT_CTX],
- up_current_regs()[REG_EPC],
- up_current_regs()[REG_INT_CTX]);
- }
+ 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 signalling
- * some non-running task.
- */
-
else
{
- /* Save the return EPC and STATUS registers. 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 = (uintreg_t *)((uintptr_t)tcb->xcp.regs -
- XCPTCONTEXT_SIZE);
-
- memcpy(tcb->xcp.regs, tcb->xcp.saved_regs, XCPTCONTEXT_SIZE);
-
- tcb->xcp.regs[REG_SP] = (uintptr_t)tcb->xcp.regs +
- XCPTCONTEXT_SIZE;
-
- tcb->xcp.regs[REG_EPC] = (uintptr_t)riscv_sigdeliver;
- int_ctx = tcb->xcp.regs[REG_INT_CTX];
- int_ctx &= ~STATUS_PIE;
-
- tcb->xcp.regs[REG_INT_CTX] = int_ctx;
-
- sinfo("PC/STATUS Saved: %" PRIxREG "/%" PRIxREG
- " New: %" PRIxREG "/%" PRIxREG "\n",
- tcb->xcp.saved_regs[REG_EPC],
- tcb->xcp.saved_regs[REG_INT_CTX],
- tcb->xcp.regs[REG_EPC], tcb->xcp.regs[REG_INT_CTX]);
- }
- }
-}
-#endif /* !CONFIG_SMP */
-
#ifdef CONFIG_SMP
-void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver)
-{
- uintptr_t int_ctx;
- int cpu;
- int me;
-
- sinfo("tcb=%p sigdeliver=%p\n", tcb, sigdeliver);
+ int cpu = tcb->cpu;
+ int me = this_cpu();
- /* 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. These will be
- * restored by the signal trampoline after the signal has
- * been delivered.
- */
-
- /* Then set up vector to the trampoline with interrupts
- * disabled. We must already be in privileged thread mode
- * to be here.
- */
-
- /* 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 = (uintreg_t *)((uintptr_t)tcb->xcp.regs -
- XCPTCONTEXT_SIZE);
-
- memcpy(tcb->xcp.regs, tcb->xcp.saved_regs,
- XCPTCONTEXT_SIZE);
-
- tcb->xcp.regs[REG_SP] = (uintptr_t)tcb->xcp.regs +
- XCPTCONTEXT_SIZE;
-
- tcb->xcp.regs[REG_EPC] = (uintptr_t)riscv_sigdeliver;
- int_ctx = tcb->xcp.regs[REG_INT_CTX];
- int_ctx &= ~STATUS_PIE;
-#ifndef CONFIG_BUILD_FLAT
- int_ctx |= STATUS_PPP;
#endif
- tcb->xcp.regs[REG_INT_CTX] = int_ctx;
- }
- else
- {
- /* tcb is running on the same CPU */
- /* Save the context registers. These will be
- * restored by the signal trampoline after the signal has
- * been delivered.
- */
-
- tcb->xcp.saved_regs = up_current_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] = (uintptr_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_EPC] = (uintptr_t)riscv_sigdeliver;
-
- int_ctx = up_current_regs()[REG_INT_CTX];
- int_ctx &= ~STATUS_PIE;
-#ifndef CONFIG_BUILD_FLAT
- int_ctx |= STATUS_PPP;
-#endif
- up_current_regs()[REG_INT_CTX] = int_ctx;
- }
-
- /* 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 return EPC and STATUS registers. These will be
* by the signal trampoline after the signal has been delivered.
*/
@@ -403,9 +146,19 @@ void up_schedule_sigaction(struct tcb_s *tcb,
sig_deliver_t sigdeliver)
int_ctx = tcb->xcp.regs[REG_INT_CTX];
int_ctx &= ~STATUS_PIE;
+#ifndef CONFIG_BUILD_FLAT
+ int_ctx |= STATUS_PPP;
+#endif
tcb->xcp.regs[REG_INT_CTX] = int_ctx;
+#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/risc-v/src/common/riscv_swint.c
b/arch/risc-v/src/common/riscv_swint.c
index f0ed4825d8..510161db6f 100644
--- a/arch/risc-v/src/common/riscv_swint.c
+++ b/arch/risc-v/src/common/riscv_swint.c
@@ -199,8 +199,7 @@ uintptr_t dispatch_syscall(unsigned int nbr, uintptr_t
parm1,
int riscv_swint(int irq, void *context, void *arg)
{
uintreg_t *regs = (uintreg_t *)context;
-
- DEBUGASSERT(regs && regs == up_current_regs());
+ uintreg_t *new_regs = regs;
/* Software interrupt 0 is invoked with REG_A0 (REG_X10) = system call
* command and REG_A1-6 = variable number of
@@ -225,11 +224,6 @@ int riscv_swint(int irq, void *context, void *arg)
*
* A0 = SYS_restore_context
* A1 = next
- *
- * In this case, we simply need to set current_regs to restore register
- * area referenced in the saved A1. context == current_regs is the
- * normal exception return. By setting current_regs = context[A1], we
- * force the return to the saved context referenced in $a1.
*/
case SYS_restore_context:
@@ -237,6 +231,7 @@ int riscv_swint(int irq, void *context, void *arg)
struct tcb_s *next = (struct tcb_s *)(uintptr_t)regs[REG_A1];
DEBUGASSERT(regs[REG_A1] != 0);
+ new_regs = next->xcp.regs;
riscv_restorecontext(next);
}
break;
@@ -253,9 +248,7 @@ int riscv_swint(int irq, void *context, void *arg)
* A2 = next
*
* In this case, we save the context registers to the save register
- * area referenced by the saved contents of R5 and then set
- * current_regs to the save register area referenced by the saved
- * contents of R6.
+ * area referenced by the saved contents of R5.
*/
case SYS_switch_context:
@@ -264,7 +257,9 @@ int riscv_swint(int irq, void *context, void *arg)
struct tcb_s *next = (struct tcb_s *)(uintptr_t)regs[REG_A2];
DEBUGASSERT(regs[REG_A1] != 0 && regs[REG_A2] != 0);
+ prev->xcp.regs = regs;
riscv_savecontext(prev);
+ new_regs = next->xcp.regs;
riscv_restorecontext(next);
}
break;
@@ -478,7 +473,6 @@ int riscv_swint(int irq, void *context, void *arg)
#endif
default:
-
DEBUGPANIC();
break;
}
@@ -488,10 +482,10 @@ int riscv_swint(int irq, void *context, void *arg)
*/
#ifdef CONFIG_DEBUG_SYSCALL_INFO
- if (regs != up_current_regs())
+ if (regs != new_regs)
{
svcinfo("SWInt Return: Context switch!\n");
- up_dump_register(up_current_regs());
+ up_dump_register(new_regs);
}
else
{
@@ -499,7 +493,7 @@ int riscv_swint(int irq, void *context, void *arg)
}
#endif
- if (regs != up_current_regs())
+ if (regs != new_regs)
{
restore_critical_section(this_task(), this_cpu());
}
diff --git a/arch/risc-v/src/common/supervisor/riscv_perform_syscall.c
b/arch/risc-v/src/common/supervisor/riscv_perform_syscall.c
index 8b9d287c8d..8e26221e40 100644
--- a/arch/risc-v/src/common/supervisor/riscv_perform_syscall.c
+++ b/arch/risc-v/src/common/supervisor/riscv_perform_syscall.c
@@ -47,10 +47,11 @@ void *riscv_perform_syscall(uintreg_t *regs)
/* Run the system call handler (swint) */
riscv_swint(0, regs, NULL);
+ tcb = this_task();
-#ifdef CONFIG_ARCH_ADDRENV
- 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
@@ -58,11 +59,8 @@ void *riscv_perform_syscall(uintreg_t *regs)
*/
addrenv_switch(NULL);
- }
#endif
- if (regs != up_current_regs())
- {
/* Record the new "running" task. g_running_tasks[] is only used by
* assertion logic for reporting crashes.
*/
@@ -81,7 +79,7 @@ void *riscv_perform_syscall(uintreg_t *regs)
* that a context switch occurred during interrupt processing.
*/
- regs = up_current_regs();
+ regs = tcb->xcp.regs;
}
up_set_current_regs(NULL);