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 <hujun5@xiaomi.com>
This commit is contained in:
hujun5 2024-09-27 14:42:11 +08:00 committed by Xiang Xiao
parent 57f84aaca8
commit d1fec65e1b
6 changed files with 26 additions and 35 deletions

View File

@ -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);
@ -71,9 +72,10 @@ uintreg_t *riscv_doirq(int irq, uintreg_t *regs)
{
regs[REG_EPC] += 4;
}
else
if (*running_task != NULL)
{
tcb->xcp.regs = regs;
(*running_task)->xcp.regs = regs;
}
/* Current regs non-zero indicates that we are processing an interrupt;
@ -97,7 +99,7 @@ uintreg_t *riscv_doirq(int irq, uintreg_t *regs)
* returning from the interrupt.
*/
if (regs != tcb->xcp.regs)
if ((*running_task) != tcb)
{
#ifdef CONFIG_ARCH_ADDRENV
/* Make sure that the address environment for the previously
@ -114,15 +116,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 +127,5 @@ uintreg_t *riscv_doirq(int irq, uintreg_t *regs)
#endif
board_autoled_off(LED_INIRQ);
return regs;
return tcb->xcp.regs;
}

View File

@ -78,6 +78,10 @@ void up_exit(int status)
nxsched_resume_scheduler(tcb);
/* g_running_tasks is not valid now */
g_running_tasks[this_cpu()] = NULL;
/* Then switch contexts */
riscv_fullcontextrestore(tcb);

View File

@ -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 */

View File

@ -162,6 +162,10 @@ retry:
rtcb->irqcount--;
#endif
/* g_running_tasks is not valid now */
g_running_tasks[this_cpu()] = NULL;
rtcb->xcp.regs = regs;
riscv_fullcontextrestore(rtcb);
}

View File

@ -257,7 +257,6 @@ 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);
@ -496,7 +495,6 @@ int riscv_swint(int irq, void *context, void *arg)
if (regs != new_regs)
{
restore_critical_section(this_task(), this_cpu());
return SWINT_CONTEXT_SWITCH;
}
return OK;

View File

@ -37,9 +37,13 @@
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;
if (*running_task != NULL)
{
(*running_task)->xcp.regs = regs;
}
/* Set up the interrupt register set needed by swint() */
@ -47,9 +51,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) != tcb)
{
#ifdef CONFIG_ARCH_ADDRENV
/* Make sure that the address environment for the previously
@ -65,20 +70,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;
}