ARM: 9426/1: vfp: Move sending signals outside of vfp_state_hold()ed section.

VFP_bounce() is invoked from within vfp_support_entry() and may send a
signal. Sending a signal uses spinlock_t which becomes a sleeping lock
on PREEMPT_RT and must not be acquired within a preempt-disabled
section.

Move the vfp_raise_sigfpe() block outside of the vfp_state_hold() section.

Reviewed-by: Ard Biesheuvel <ardb@kernel.org>
Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
This commit is contained in:
Sebastian Andrzej Siewior 2024-10-02 17:18:54 +01:00 committed by Russell King (Oracle)
parent 27035c23ba
commit c0b5195bad

View File

@ -268,7 +268,7 @@ static void vfp_panic(char *reason, u32 inst)
/* /*
* Process bitmask of exception conditions. * Process bitmask of exception conditions.
*/ */
static void vfp_raise_exceptions(u32 exceptions, u32 inst, u32 fpscr, struct pt_regs *regs) static int vfp_raise_exceptions(u32 exceptions, u32 inst, u32 fpscr)
{ {
int si_code = 0; int si_code = 0;
@ -276,8 +276,7 @@ static void vfp_raise_exceptions(u32 exceptions, u32 inst, u32 fpscr, struct pt_
if (exceptions == VFP_EXCEPTION_ERROR) { if (exceptions == VFP_EXCEPTION_ERROR) {
vfp_panic("unhandled bounce", inst); vfp_panic("unhandled bounce", inst);
vfp_raise_sigfpe(FPE_FLTINV, regs); return FPE_FLTINV;
return;
} }
/* /*
@ -305,8 +304,7 @@ static void vfp_raise_exceptions(u32 exceptions, u32 inst, u32 fpscr, struct pt_
RAISE(FPSCR_OFC, FPSCR_OFE, FPE_FLTOVF); RAISE(FPSCR_OFC, FPSCR_OFE, FPE_FLTOVF);
RAISE(FPSCR_IOC, FPSCR_IOE, FPE_FLTINV); RAISE(FPSCR_IOC, FPSCR_IOE, FPE_FLTINV);
if (si_code) return si_code;
vfp_raise_sigfpe(si_code, regs);
} }
/* /*
@ -352,6 +350,8 @@ static u32 vfp_emulate_instruction(u32 inst, u32 fpscr, struct pt_regs *regs)
static void VFP_bounce(u32 trigger, u32 fpexc, struct pt_regs *regs) static void VFP_bounce(u32 trigger, u32 fpexc, struct pt_regs *regs)
{ {
u32 fpscr, orig_fpscr, fpsid, exceptions; u32 fpscr, orig_fpscr, fpsid, exceptions;
int si_code2 = 0;
int si_code = 0;
pr_debug("VFP: bounce: trigger %08x fpexc %08x\n", trigger, fpexc); pr_debug("VFP: bounce: trigger %08x fpexc %08x\n", trigger, fpexc);
@ -397,8 +397,8 @@ static void VFP_bounce(u32 trigger, u32 fpexc, struct pt_regs *regs)
* unallocated VFP instruction but with FPSCR.IXE set and not * unallocated VFP instruction but with FPSCR.IXE set and not
* on VFP subarch 1. * on VFP subarch 1.
*/ */
vfp_raise_exceptions(VFP_EXCEPTION_ERROR, trigger, fpscr, regs); si_code = vfp_raise_exceptions(VFP_EXCEPTION_ERROR, trigger, fpscr);
return; goto exit;
} }
/* /*
@ -422,14 +422,14 @@ static void VFP_bounce(u32 trigger, u32 fpexc, struct pt_regs *regs)
*/ */
exceptions = vfp_emulate_instruction(trigger, fpscr, regs); exceptions = vfp_emulate_instruction(trigger, fpscr, regs);
if (exceptions) if (exceptions)
vfp_raise_exceptions(exceptions, trigger, orig_fpscr, regs); si_code2 = vfp_raise_exceptions(exceptions, trigger, orig_fpscr);
/* /*
* If there isn't a second FP instruction, exit now. Note that * If there isn't a second FP instruction, exit now. Note that
* the FPEXC.FP2V bit is valid only if FPEXC.EX is 1. * the FPEXC.FP2V bit is valid only if FPEXC.EX is 1.
*/ */
if ((fpexc & (FPEXC_EX | FPEXC_FP2V)) != (FPEXC_EX | FPEXC_FP2V)) if ((fpexc & (FPEXC_EX | FPEXC_FP2V)) != (FPEXC_EX | FPEXC_FP2V))
return; goto exit;
/* /*
* The barrier() here prevents fpinst2 being read * The barrier() here prevents fpinst2 being read
@ -441,7 +441,13 @@ static void VFP_bounce(u32 trigger, u32 fpexc, struct pt_regs *regs)
emulate: emulate:
exceptions = vfp_emulate_instruction(trigger, orig_fpscr, regs); exceptions = vfp_emulate_instruction(trigger, orig_fpscr, regs);
if (exceptions) if (exceptions)
vfp_raise_exceptions(exceptions, trigger, orig_fpscr, regs); si_code = vfp_raise_exceptions(exceptions, trigger, orig_fpscr);
exit:
vfp_state_release();
if (si_code2)
vfp_raise_sigfpe(si_code2, regs);
if (si_code)
vfp_raise_sigfpe(si_code, regs);
} }
static void vfp_enable(void *unused) static void vfp_enable(void *unused)
@ -773,6 +779,7 @@ static int vfp_support_entry(struct pt_regs *regs, u32 trigger)
* replay the instruction that trapped. * replay the instruction that trapped.
*/ */
fmxr(FPEXC, fpexc); fmxr(FPEXC, fpexc);
vfp_state_release();
} else { } else {
/* Check for synchronous or asynchronous exceptions */ /* Check for synchronous or asynchronous exceptions */
if (!(fpexc & (FPEXC_EX | FPEXC_DEX))) { if (!(fpexc & (FPEXC_EX | FPEXC_DEX))) {
@ -794,10 +801,10 @@ static int vfp_support_entry(struct pt_regs *regs, u32 trigger)
} }
} }
bounce: regs->ARM_pc += 4; bounce: regs->ARM_pc += 4;
/* VFP_bounce() will invoke vfp_state_release() */
VFP_bounce(trigger, fpexc, regs); VFP_bounce(trigger, fpexc, regs);
} }
vfp_state_release();
return 0; return 0;
} }