1
0
Fork 0
forked from nuttx/nuttx-update

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 <zhangyuan21@xiaomi.com>
This commit is contained in:
zhangyuan21 2023-04-26 20:34:01 +08:00 committed by Masayuki Ishikawa
parent 6c38c44af2
commit 6f8cb7edd3
3 changed files with 37 additions and 31 deletions

View file

@ -328,7 +328,6 @@ struct fpu_reg
__int128 q[32];
uint32_t fpsr;
uint32_t fpcr;
uint64_t fpu_trap;
};
#endif

View file

@ -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.

View file

@ -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]