From 7b5ca0ec41a6b4328b3ec996f3cf71361f941873 Mon Sep 17 00:00:00 2001 From: hujun5 Date: Tue, 24 Sep 2024 09:39:37 +0800 Subject: [PATCH] riscv: use g_running_task store current regs This commit fixes the regression from https://github.com/apache/nuttx/pull/13561 In order to determine whether a context switch has occurred, we can use g_running_task to store the current regs. This allows us to compare the current register state with the previously stored state to identify if a context switch has taken place. Signed-off-by: hujun5 --- arch/risc-v/src/common/riscv_doirq.c | 21 +++++++--------- arch/risc-v/src/common/riscv_internal.h | 4 ---- arch/risc-v/src/common/riscv_swint.c | 12 ++++------ .../common/supervisor/riscv_perform_syscall.c | 24 +++++++------------ 4 files changed, 22 insertions(+), 39 deletions(-) diff --git a/arch/risc-v/src/common/riscv_doirq.c b/arch/risc-v/src/common/riscv_doirq.c index 895bd910ded1f..75ac42954dd93 100644 --- a/arch/risc-v/src/common/riscv_doirq.c +++ b/arch/risc-v/src/common/riscv_doirq.c @@ -58,6 +58,7 @@ uintreg_t *riscv_doirq(int irq, uintreg_t *regs) { + struct tcb_s **running_task = &g_running_tasks[this_cpu()]; struct tcb_s *tcb = this_task(); board_autoled_on(LED_INIRQ); @@ -70,10 +71,14 @@ uintreg_t *riscv_doirq(int irq, uintreg_t *regs) if (irq >= RISCV_IRQ_ECALLU && irq <= RISCV_IRQ_ECALLM) { regs[REG_EPC] += 4; + if (regs[REG_A0] != SYS_restore_context) + { + (*running_task)->xcp.regs = regs; + } } else { - tcb->xcp.regs = regs; + (*running_task)->xcp.regs = regs; } /* Current regs non-zero indicates that we are processing an interrupt; @@ -97,7 +102,7 @@ uintreg_t *riscv_doirq(int irq, uintreg_t *regs) * returning from the interrupt. */ - if (regs != tcb->xcp.regs) + if ((*running_task)->xcp.regs != tcb->xcp.regs) { #ifdef CONFIG_ARCH_ADDRENV /* Make sure that the address environment for the previously @@ -114,15 +119,7 @@ uintreg_t *riscv_doirq(int irq, uintreg_t *regs) * crashes. */ - 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 - * different from the input regs, then the lower level will know - * that a context switch occurred during interrupt processing. - */ - - regs = tcb->xcp.regs; + *running_task = tcb; } /* Set current_regs to NULL to indicate that we are no longer in an @@ -133,5 +130,5 @@ uintreg_t *riscv_doirq(int irq, uintreg_t *regs) #endif board_autoled_off(LED_INIRQ); - return regs; + return tcb->xcp.regs; } diff --git a/arch/risc-v/src/common/riscv_internal.h b/arch/risc-v/src/common/riscv_internal.h index c8b5f184bfb09..d9165356a97c1 100644 --- a/arch/risc-v/src/common/riscv_internal.h +++ b/arch/risc-v/src/common/riscv_internal.h @@ -109,10 +109,6 @@ #define PMP_ACCESS_DENIED (-1) /* Access set and denied */ #define PMP_ACCESS_FULL (1) /* Access set and allowed */ -/* Return values from riscv_swint */ - -#define SWINT_CONTEXT_SWITCH (1) /* Indicate we need context switch */ - #ifndef __ASSEMBLY__ /* Use ASM as rv64ilp32 compiler generated address is limited */ diff --git a/arch/risc-v/src/common/riscv_swint.c b/arch/risc-v/src/common/riscv_swint.c index 4cf68ac0aa9c7..51973a2ceca57 100644 --- a/arch/risc-v/src/common/riscv_swint.c +++ b/arch/risc-v/src/common/riscv_swint.c @@ -199,7 +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; - uintreg_t *new_regs = regs; + bool contex_switch = false; /* Software interrupt 0 is invoked with REG_A0 (REG_X10) = system call * command and REG_A1-6 = variable number of @@ -231,7 +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; + contex_switch = true; riscv_restorecontext(next); } break; @@ -257,9 +257,8 @@ 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; + contex_switch = true; riscv_restorecontext(next); } break; @@ -482,7 +481,7 @@ int riscv_swint(int irq, void *context, void *arg) */ #ifdef CONFIG_DEBUG_SYSCALL_INFO - if (regs != new_regs) + if (contex_switch) { svcinfo("SWInt Return: Context switch!\n"); up_dump_register(new_regs); @@ -493,10 +492,9 @@ int riscv_swint(int irq, void *context, void *arg) } #endif - if (regs != new_regs) + if (contex_switch) { restore_critical_section(this_task(), this_cpu()); - return SWINT_CONTEXT_SWITCH; } return OK; 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 022c58155e3e1..2a9577e3d22e1 100644 --- a/arch/risc-v/src/common/supervisor/riscv_perform_syscall.c +++ b/arch/risc-v/src/common/supervisor/riscv_perform_syscall.c @@ -37,9 +37,10 @@ void *riscv_perform_syscall(uintreg_t *regs) { + struct tcb_s **running_task = &g_running_tasks[this_cpu()]; struct tcb_s *tcb; - int cpu; - int ret; + + (*running_task)->xcp.regs = regs; /* Set up the interrupt register set needed by swint() */ @@ -47,9 +48,10 @@ void *riscv_perform_syscall(uintreg_t *regs) /* Run the system call handler (swint) */ - ret = riscv_swint(0, regs, NULL); + riscv_swint(0, regs, NULL); + tcb = this_task(); - if (ret == SWINT_CONTEXT_SWITCH) + if ((*running_task)->xcp.regs != tcb->xcp.regs) { #ifdef CONFIG_ARCH_ADDRENV /* Make sure that the address environment for the previously @@ -65,20 +67,10 @@ void *riscv_perform_syscall(uintreg_t *regs) * assertion logic for reporting crashes. */ - cpu = this_cpu(); - tcb = current_task(cpu); - g_running_tasks[cpu] = tcb; - - /* If a context switch occurred while processing the interrupt then - * current_regs may have change value. If we return any value - * different from the input regs, then the lower level will know - * that a context switch occurred during interrupt processing. - */ - - regs = tcb->xcp.regs; + *running_task = tcb; } up_set_current_regs(NULL); - return regs; + return tcb->xcp.regs; }