From 6f8cb7edd3058630bb6ad3a2418d5486c8e96070 Mon Sep 17 00:00:00 2001 From: zhangyuan21 Date: Wed, 26 Apr 2023 20:34:01 +0800 Subject: [PATCH] arch/arm64: Save FPU context when a context switch occurs in SMP mode In SMP mode, the fpu owner may switch from core0 to core1, so it is necessary to force saving the FPU context when a context switch occurs. This PR fixed the crash issue mentioned in #8799. Signed-off-by: zhangyuan21 --- arch/arm64/src/common/arm64_arch.h | 1 - arch/arm64/src/common/arm64_fpu.c | 59 +++++++++++++-------------- arch/arm64/src/common/arm64_vectors.S | 8 ++++ 3 files changed, 37 insertions(+), 31 deletions(-) diff --git a/arch/arm64/src/common/arm64_arch.h b/arch/arm64/src/common/arm64_arch.h index 2a9fef9561..b3361b8f6f 100644 --- a/arch/arm64/src/common/arm64_arch.h +++ b/arch/arm64/src/common/arm64_arch.h @@ -328,7 +328,6 @@ struct fpu_reg __int128 q[32]; uint32_t fpsr; uint32_t fpcr; - uint64_t fpu_trap; }; #endif diff --git a/arch/arm64/src/common/arm64_fpu.c b/arch/arm64/src/common/arm64_fpu.c index 6cfd75741f..7ef96b4009 100644 --- a/arch/arm64/src/common/arm64_fpu.c +++ b/arch/arm64/src/common/arm64_fpu.c @@ -268,8 +268,6 @@ static int arm64_fpu_procfs_stat(const char *relpath, struct stat *buf) void arm64_init_fpu(struct tcb_s *tcb) { - struct fpu_reg *fpu_reg; - if (tcb->pid < CONFIG_SMP_NCPUS) { memset(&g_cpu_fpu_ctx[this_cpu()], 0, @@ -280,13 +278,11 @@ void arm64_init_fpu(struct tcb_s *tcb) } memset(tcb->xcp.fpu_regs, 0, sizeof(struct fpu_reg)); - fpu_reg = (struct fpu_reg *)tcb->xcp.fpu_regs; - fpu_reg->fpu_trap = 0; } -void arm64_destory_fpu(struct tcb_s * tcb) +void arm64_destory_fpu(struct tcb_s *tcb) { - struct tcb_s * owner; + struct tcb_s *owner; /* save current fpu owner's context */ @@ -314,10 +310,9 @@ void arm64_fpu_exit_exception(void) { } -void arm64_fpu_trap(struct regs_context * regs) +void arm64_fpu_trap(struct regs_context *regs) { - struct tcb_s * owner; - struct fpu_reg *fpu_reg; + struct tcb_s *owner; UNUSED(regs); @@ -358,41 +353,45 @@ void arm64_fpu_trap(struct regs_context * regs) /* become new owner */ - g_cpu_fpu_ctx[this_cpu()].fpu_owner = owner; - fpu_reg = (struct fpu_reg *)owner->xcp.fpu_regs; - fpu_reg->fpu_trap = 0; + g_cpu_fpu_ctx[this_cpu()].fpu_owner = owner; } void arm64_fpu_context_restore(void) { struct tcb_s *new_tcb = (struct tcb_s *)arch_get_current_tcb(); - struct fpu_reg *fpu_reg = (struct fpu_reg *)new_tcb->xcp.fpu_regs; - arm64_fpu_access_trap_enable(); + arm64_fpu_access_trap_disable(); - if (fpu_reg->fpu_trap == 0) + /* FPU trap has happened at this task */ + + if (new_tcb == g_cpu_fpu_ctx[this_cpu()].fpu_owner) { - /* FPU trap hasn't happened at this task */ - - arm64_fpu_access_trap_enable(); + arm64_fpu_access_trap_disable(); } else { - /* FPU trap has happened at this task */ - - if (new_tcb == g_cpu_fpu_ctx[this_cpu()].fpu_owner) - { - arm64_fpu_access_trap_disable(); - } - else - { - arm64_fpu_access_trap_enable(); - } + arm64_fpu_access_trap_enable(); } g_cpu_fpu_ctx[this_cpu()].switch_count++; } +#ifdef CONFIG_SMP +void arm64_fpu_context_save(void) +{ + struct tcb_s *tcb = (struct tcb_s *)arch_get_current_tcb(); + + if (tcb == g_cpu_fpu_ctx[this_cpu()].fpu_owner) + { + arm64_fpu_access_trap_disable(); + arm64_fpu_save((struct fpu_reg *)tcb->xcp.fpu_regs); + ARM64_DSB(); + g_cpu_fpu_ctx[this_cpu()].save_count++; + g_cpu_fpu_ctx[this_cpu()].fpu_owner = NULL; + } +} +#endif + void arm64_fpu_enable(void) { irqstate_t flags = up_irq_save(); @@ -426,8 +425,8 @@ void arm64_fpu_disable(void) bool up_fpucmp(const void *saveregs1, const void *saveregs2) { - const uint64_t *regs1 = saveregs1 + XCPTCONTEXT_GP_SIZE; - const uint64_t *regs2 = saveregs2 + XCPTCONTEXT_GP_SIZE; + const uint64_t *regs1 = saveregs1 + XCPTCONTEXT_GP_SIZE; + const uint64_t *regs2 = saveregs2 + XCPTCONTEXT_GP_SIZE; /* Only compare callee-saved registers, caller-saved registers do not * need to be preserved. diff --git a/arch/arm64/src/common/arm64_vectors.S b/arch/arm64/src/common/arm64_vectors.S index 77507cfad9..e2158a3a03 100644 --- a/arch/arm64/src/common/arm64_vectors.S +++ b/arch/arm64/src/common/arm64_vectors.S @@ -121,6 +121,14 @@ SECTION_FUNC(text, arm64_context_switch) cmp x1, #0x0 beq restore_new +#if defined(CONFIG_ARCH_FPU) && defined(CONFIG_SMP) + stp x0, x1, [sp, #-16]! + stp xzr, x30, [sp, #-16]! + bl arm64_fpu_context_save + ldp xzr, x30, [sp], #16 + ldp x0, x1, [sp], #16 +#endif + /* Save the current SP_EL0 */ mov x4, sp str x4, [x1, #8 * REG_SP_ELX]