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:
parent
6c38c44af2
commit
6f8cb7edd3
3 changed files with 37 additions and 31 deletions
|
@ -328,7 +328,6 @@ struct fpu_reg
|
|||
__int128 q[32];
|
||||
uint32_t fpsr;
|
||||
uint32_t fpcr;
|
||||
uint64_t fpu_trap;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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]
|
||||
|
|
Loading…
Reference in a new issue