Skip to content

Commit

Permalink
riscv: use g_running_task store current regs
Browse files Browse the repository at this point in the history
This commit fixes the regression from #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>
  • Loading branch information
hujun260 committed Sep 24, 2024
1 parent 898a5d5 commit 7b5ca0e
Show file tree
Hide file tree
Showing 4 changed files with 22 additions and 39 deletions.
21 changes: 9 additions & 12 deletions arch/risc-v/src/common/riscv_doirq.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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;
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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;
}
4 changes: 0 additions & 4 deletions arch/risc-v/src/common/riscv_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down
12 changes: 5 additions & 7 deletions arch/risc-v/src/common/riscv_swint.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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);
Expand All @@ -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;
Expand Down
24 changes: 8 additions & 16 deletions arch/risc-v/src/common/supervisor/riscv_perform_syscall.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,19 +37,21 @@

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() */

up_set_current_regs(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
Expand All @@ -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;
}

0 comments on commit 7b5ca0e

Please sign in to comment.