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
commit 040eb3c990adad935409cddd077976d7742ca043 Author: Ville Juven <ville.ju...@unikie.com> AuthorDate: Tue May 16 18:03:53 2023 +0300 riscv/swint: Give the full tcb to the context switch routine Why? The tcb can contain info that is needed by the context switch routine. One example is lazy-FPU handling; the integer registers can be stored into the stack, because they are always stored & restored. Lazy-FPU however needs a non-volatile location to store the FPU registers as the save feature will skip saving a clean FPU, but the restore must always restore the FPU registers if the thread uses FPU. --- arch/risc-v/src/common/riscv_exit.c | 2 +- arch/risc-v/src/common/riscv_internal.h | 25 +++++++++++++++++++------ arch/risc-v/src/common/riscv_sigdeliver.c | 4 +++- arch/risc-v/src/common/riscv_swint.c | 21 +++++++++++++-------- arch/risc-v/src/common/riscv_switchcontext.c | 6 +++--- 5 files changed, 39 insertions(+), 19 deletions(-) diff --git a/arch/risc-v/src/common/riscv_exit.c b/arch/risc-v/src/common/riscv_exit.c index c6177f29b7..143ffb438a 100644 --- a/arch/risc-v/src/common/riscv_exit.c +++ b/arch/risc-v/src/common/riscv_exit.c @@ -139,7 +139,7 @@ void up_exit(int status) /* Then switch contexts */ - riscv_fullcontextrestore(tcb->xcp.regs); + riscv_fullcontextrestore(tcb); /* riscv_fullcontextrestore() should not return but could if the software * interrupts are disabled. diff --git a/arch/risc-v/src/common/riscv_internal.h b/arch/risc-v/src/common/riscv_internal.h index f3a50d4c95..6b385818cb 100644 --- a/arch/risc-v/src/common/riscv_internal.h +++ b/arch/risc-v/src/common/riscv_internal.h @@ -29,6 +29,7 @@ #ifndef __ASSEMBLY__ # include <nuttx/compiler.h> +# include <nuttx/sched.h> # include <sys/types.h> # include <stdint.h> # include <syscall.h> @@ -207,6 +208,18 @@ void riscv_fpuconfig(void); # define riscv_fpuconfig() #endif +/* Save / restore context of task */ + +static inline void riscv_savecontext(struct tcb_s *tcb) +{ + tcb->xcp.regs = (uintptr_t *)CURRENT_REGS; +} + +static inline void riscv_restorecontext(struct tcb_s *tcb) +{ + CURRENT_REGS = (uintptr_t *)tcb->xcp.regs; +} + /* RISC-V PMP Config ********************************************************/ int riscv_config_pmp_region(uintptr_t region, uintptr_t attr, @@ -304,19 +317,19 @@ void *riscv_perform_syscall(uintptr_t *regs); /* SYS call 1: * - * void riscv_fullcontextrestore(uintptr_t *restoreregs) noreturn_function; + * void riscv_fullcontextrestore(struct tcb_s *next) noreturn_function; */ -#define riscv_fullcontextrestore(restoreregs) \ - sys_call1(SYS_restore_context, (uintptr_t)restoreregs) +#define riscv_fullcontextrestore(next) \ + sys_call1(SYS_restore_context, (uintptr_t)next) /* SYS call 2: * - * void riscv_switchcontext(uintptr_t *saveregs, uintptr_t *restoreregs); + * riscv_switchcontext(struct tcb_s *prev, struct tcb_s *next); */ -#define riscv_switchcontext(saveregs, restoreregs) \ - sys_call2(SYS_switch_context, (uintptr_t)saveregs, (uintptr_t)restoreregs) +#define riscv_switchcontext(prev, next) \ + sys_call2(SYS_switch_context, (uintptr_t)prev, (uintptr_t)next) #ifdef CONFIG_BUILD_KERNEL /* SYS call 3: diff --git a/arch/risc-v/src/common/riscv_sigdeliver.c b/arch/risc-v/src/common/riscv_sigdeliver.c index c5c61cd9ca..0ff3261785 100644 --- a/arch/risc-v/src/common/riscv_sigdeliver.c +++ b/arch/risc-v/src/common/riscv_sigdeliver.c @@ -155,5 +155,7 @@ retry: #ifdef CONFIG_SMP rtcb->irqcount--; #endif - riscv_fullcontextrestore(regs); + + rtcb->xcp.regs = regs; + riscv_fullcontextrestore(rtcb); } diff --git a/arch/risc-v/src/common/riscv_swint.c b/arch/risc-v/src/common/riscv_swint.c index 8eae2db37c..dc2c11f00e 100644 --- a/arch/risc-v/src/common/riscv_swint.c +++ b/arch/risc-v/src/common/riscv_swint.c @@ -135,12 +135,12 @@ int riscv_swint(int irq, void *context, void *arg) /* A0=SYS_restore_context: This a restore context command: * * void - * riscv_fullcontextrestore(uintptr_t *restoreregs) noreturn_function; + * void riscv_fullcontextrestore(struct tcb_s *prev) noreturn_function; * * At this point, the following values are saved in context: * * A0 = SYS_restore_context - * A1 = restoreregs + * 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 @@ -150,21 +150,23 @@ int riscv_swint(int irq, void *context, void *arg) case SYS_restore_context: { + struct tcb_s *next = (struct tcb_s *)regs[REG_A1]; + DEBUGASSERT(regs[REG_A1] != 0); - CURRENT_REGS = (uintptr_t *)regs[REG_A1]; + CURRENT_REGS = (uintptr_t *)next->xcp.regs; } break; /* A0=SYS_switch_context: This a switch context command: * * void - * riscv_switchcontext(uintptr_t *saveregs, uintptr_t *restoreregs); + * riscv_switchcontext(struct tcb_s *prev, struct tcb_s *next); * * At this point, the following values are saved in context: * * A0 = SYS_switch_context - * A1 = saveregs - * A2 = restoreregs + * A1 = prev + * 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 @@ -174,9 +176,12 @@ int riscv_swint(int irq, void *context, void *arg) case SYS_switch_context: { + struct tcb_s *prev = (struct tcb_s *)regs[REG_A1]; + struct tcb_s *next = (struct tcb_s *)regs[REG_A2]; + DEBUGASSERT(regs[REG_A1] != 0 && regs[REG_A2] != 0); - *(uintptr_t **)regs[REG_A1] = (uintptr_t *)regs; - CURRENT_REGS = (uintptr_t *)regs[REG_A2]; + prev->xcp.regs = (uintptr_t *)CURRENT_REGS; + CURRENT_REGS = (uintptr_t *)next->xcp.regs; } break; diff --git a/arch/risc-v/src/common/riscv_switchcontext.c b/arch/risc-v/src/common/riscv_switchcontext.c index 30ea84a00f..d39ad24b68 100644 --- a/arch/risc-v/src/common/riscv_switchcontext.c +++ b/arch/risc-v/src/common/riscv_switchcontext.c @@ -69,7 +69,7 @@ void up_switch_context(struct tcb_s *tcb, struct tcb_s *rtcb) * Just copy the CURRENT_REGS into the OLD rtcb. */ - riscv_savestate(rtcb->xcp.regs); + riscv_savecontext(rtcb); /* Update scheduler parameters */ @@ -79,7 +79,7 @@ void up_switch_context(struct tcb_s *tcb, struct tcb_s *rtcb) * changes will be made when the interrupt returns. */ - riscv_restorestate(tcb->xcp.regs); + riscv_restorecontext(tcb); } /* No, then we will need to perform the user context switch */ @@ -92,7 +92,7 @@ void up_switch_context(struct tcb_s *tcb, struct tcb_s *rtcb) /* Then switch contexts */ - riscv_switchcontext(&rtcb->xcp.regs, tcb->xcp.regs); + riscv_switchcontext(rtcb, tcb); /* riscv_switchcontext forces a context switch to the task at the * head of the ready-to-run list. It does not 'return' in the