This is an automated email from the ASF dual-hosted git repository.

masayuki pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git


The following commit(s) were added to refs/heads/master by this push:
     new 6f8cb7edd3 arch/arm64: Save FPU context when a context switch occurs 
in SMP mode
6f8cb7edd3 is described below

commit 6f8cb7edd3058630bb6ad3a2418d5486c8e96070
Author: zhangyuan21 <[email protected]>
AuthorDate: Wed Apr 26 20:34:01 2023 +0800

    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 <[email protected]>
---
 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 hasn't happened at this task */
+  /* FPU trap has happened at this task */
 
-      arm64_fpu_access_trap_enable();
+  if (new_tcb == g_cpu_fpu_ctx[this_cpu()].fpu_owner)
+    {
+      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]

Reply via email to