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
@ -328,7 +328,6 @@ struct fpu_reg
|
|||||||
__int128 q[32];
|
__int128 q[32];
|
||||||
uint32_t fpsr;
|
uint32_t fpsr;
|
||||||
uint32_t fpcr;
|
uint32_t fpcr;
|
||||||
uint64_t fpu_trap;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#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)
|
void arm64_init_fpu(struct tcb_s *tcb)
|
||||||
{
|
{
|
||||||
struct fpu_reg *fpu_reg;
|
|
||||||
|
|
||||||
if (tcb->pid < CONFIG_SMP_NCPUS)
|
if (tcb->pid < CONFIG_SMP_NCPUS)
|
||||||
{
|
{
|
||||||
memset(&g_cpu_fpu_ctx[this_cpu()], 0,
|
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));
|
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 */
|
/* 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 tcb_s *owner;
|
||||||
struct fpu_reg *fpu_reg;
|
|
||||||
|
|
||||||
UNUSED(regs);
|
UNUSED(regs);
|
||||||
|
|
||||||
@ -359,25 +354,14 @@ void arm64_fpu_trap(struct regs_context * regs)
|
|||||||
/* become new owner */
|
/* become new owner */
|
||||||
|
|
||||||
g_cpu_fpu_ctx[this_cpu()].fpu_owner = owner;
|
g_cpu_fpu_ctx[this_cpu()].fpu_owner = owner;
|
||||||
fpu_reg = (struct fpu_reg *)owner->xcp.fpu_regs;
|
|
||||||
fpu_reg->fpu_trap = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void arm64_fpu_context_restore(void)
|
void arm64_fpu_context_restore(void)
|
||||||
{
|
{
|
||||||
struct tcb_s *new_tcb = (struct tcb_s *)arch_get_current_tcb();
|
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 */
|
|
||||||
|
|
||||||
arm64_fpu_access_trap_enable();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* FPU trap has happened at this task */
|
/* FPU trap has happened at this task */
|
||||||
|
|
||||||
if (new_tcb == g_cpu_fpu_ctx[this_cpu()].fpu_owner)
|
if (new_tcb == g_cpu_fpu_ctx[this_cpu()].fpu_owner)
|
||||||
@ -388,11 +372,26 @@ void arm64_fpu_context_restore(void)
|
|||||||
{
|
{
|
||||||
arm64_fpu_access_trap_enable();
|
arm64_fpu_access_trap_enable();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
g_cpu_fpu_ctx[this_cpu()].switch_count++;
|
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)
|
void arm64_fpu_enable(void)
|
||||||
{
|
{
|
||||||
irqstate_t flags = up_irq_save();
|
irqstate_t flags = up_irq_save();
|
||||||
|
@ -121,6 +121,14 @@ SECTION_FUNC(text, arm64_context_switch)
|
|||||||
cmp x1, #0x0
|
cmp x1, #0x0
|
||||||
beq restore_new
|
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 */
|
/* Save the current SP_EL0 */
|
||||||
mov x4, sp
|
mov x4, sp
|
||||||
str x4, [x1, #8 * REG_SP_ELX]
|
str x4, [x1, #8 * REG_SP_ELX]
|
||||||
|
Loading…
Reference in New Issue
Block a user