do_ade may be invoked with preempt enabled. do_cpu will be invoked with preempt enabled. When it's preempted(in do_ade/do_cpu), TIF_USEDFPU will be cleared, when it returns to do_ade/do_cpu, the fpu is actually disabled. e.g. In do_ade() emulate_load_store_insn(): BUG_ON(!is_fpu_owner()); <-- This assertion may be breaked. In do_cpu() enable_restore_fp_context(): was_fpu_owner = is_fpu_owner(); This patch simply disables interrupts in related handlers, and disable preempt/enable interrupts in do_ade/do_cpu. --- arch/mips/kernel/genex.S | 4 ++-- arch/mips/kernel/traps.c | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/arch/mips/kernel/genex.S b/arch/mips/kernel/genex.S index ac35e12..a5c6931 100644 --- a/arch/mips/kernel/genex.S +++ b/arch/mips/kernel/genex.S @@ -370,7 +370,7 @@ NESTED(nmi_handler, PT_SIZE, sp) .macro __build_clear_ade MFC0 t0, CP0_BADVADDR PTR_S t0, PT_BVADDR(sp) - KMODE + CLI .endm .macro __BUILD_silent exception @@ -422,7 +422,7 @@ NESTED(nmi_handler, PT_SIZE, sp) BUILD_HANDLER dbe be cli silent /* #7 */ BUILD_HANDLER bp bp sti silent /* #9 */ BUILD_HANDLER ri ri sti silent /* #10 */ - BUILD_HANDLER cpu cpu sti silent /* #11 */ + BUILD_HANDLER cpu cpu cli silent /* #11 */ BUILD_HANDLER ov ov sti silent /* #12 */ BUILD_HANDLER tr tr sti silent /* #13 */ BUILD_HANDLER msa_fpe msa_fpe sti silent /* #14 */ diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index 51706d6..0e0f7de 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c @@ -1166,6 +1166,9 @@ asmlinkage void do_cpu(struct pt_regs *regs) int status, err; unsigned long __maybe_unused flags; + preempt_disable(); + local_irq_enable(); + prev_state = exception_enter(); cpid = (regs->cp0_cause >> CAUSEB_CE) & 3; @@ -1258,6 +1261,7 @@ asmlinkage void do_cpu(struct pt_regs *regs) out: exception_exit(prev_state); + preempt_enable(); } asmlinkage void do_msa_fpe(struct pt_regs *regs) -- 1.9.0