diff --git a/arch/mips/kernel/signal.c b/arch/mips/kernel/signal.c index 10f7dbc989c4..9c42c500134e 100644 --- a/arch/mips/kernel/signal.c +++ b/arch/mips/kernel/signal.c @@ -127,8 +127,15 @@ static int protected_save_fp_context(void __user *sc) struct mips_abi *abi = current->thread.abi; uint64_t __user *fpregs = sc + abi->off_sc_fpregs; uint32_t __user *csr = sc + abi->off_sc_fpc_csr; + uint32_t __user *used_math = sc + abi->off_sc_used_math; + unsigned int used; int err; + used = !!used_math(); + err = __put_user(used, used_math); + if (err || !used) + return err; + /* * EVA does not have userland equivalents of ldc1 or sdc1, so * save to the kernel FP context & copy that to userland below. @@ -163,7 +170,25 @@ static int protected_restore_fp_context(void __user *sc) struct mips_abi *abi = current->thread.abi; uint64_t __user *fpregs = sc + abi->off_sc_fpregs; uint32_t __user *csr = sc + abi->off_sc_fpc_csr; - int err, tmp __maybe_unused; + uint32_t __user *used_math = sc + abi->off_sc_used_math; + unsigned int used; + int err, sig, tmp __maybe_unused; + + err = __get_user(used, used_math); + conditional_used_math(used); + + /* + * The signal handler may have used FPU; give it up if the program + * doesn't want it following sigreturn. + */ + if (err || !used) { + lose_fpu(0); + return err; + } + + err = sig = fpcsr_pending(csr); + if (err < 0) + return err; /* * EVA does not have userland equivalents of ldc1 or sdc1, so we @@ -192,14 +217,13 @@ static int protected_restore_fp_context(void __user *sc) break; /* really bad sigcontext */ } - return err; + return err ?: sig; } int setup_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc) { int err = 0; int i; - unsigned int used_math; err |= __put_user(regs->cp0_epc, &sc->sc_pc); @@ -222,16 +246,13 @@ int setup_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc) err |= __put_user(rddsp(DSP_MASK), &sc->sc_dsp); } - used_math = !!used_math(); - err |= __put_user(used_math, &sc->sc_used_math); - if (used_math) { - /* - * Save FPU state to signal context. Signal handler - * will "inherit" current FPU state. - */ - err |= protected_save_fp_context(sc); - } + /* + * Save FPU state to signal context. Signal handler + * will "inherit" current FPU state. + */ + err |= protected_save_fp_context(sc); + return err; } @@ -254,22 +275,8 @@ int fpcsr_pending(unsigned int __user *fpcsr) return err ?: sig; } -static int -check_and_restore_fp_context(void __user *sc) -{ - struct mips_abi *abi = current->thread.abi; - int err, sig; - - err = sig = fpcsr_pending(sc + abi->off_sc_fpc_csr); - if (err > 0) - err = 0; - err |= protected_restore_fp_context(sc); - return err ?: sig; -} - int restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc) { - unsigned int used_math; unsigned long treg; int err = 0; int i; @@ -297,19 +304,7 @@ int restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc) for (i = 1; i < 32; i++) err |= __get_user(regs->regs[i], &sc->sc_regs[i]); - err |= __get_user(used_math, &sc->sc_used_math); - conditional_used_math(used_math); - - if (used_math) { - /* restore fpu context if we have used it before */ - if (!err) - err = check_and_restore_fp_context(sc); - } else { - /* signal handler may have used FPU. Give it up. */ - lose_fpu(0); - } - - return err; + return err ?: protected_restore_fp_context(sc); } void __user *get_sigframe(struct ksignal *ksig, struct pt_regs *regs,