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]