From d02a40aff6e043bae1cd6e6416e9048990928b1d Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Mon, 27 Jul 2015 12:58:18 -0700 Subject: [PATCH] MIPS: Use common FP sigcontext code for O32 compat Make use of the common FP sigcontext code for O32 binaries running on MIPS64 kernels now that it is taking appropriate offsets into struct sigcontext(32) from struct mips_abi. [ralf@linux-mips.org: Fixed reject.] Signed-off-by: Paul Burton Cc: linux-mips@linux-mips.org Cc: Guenter Roeck Cc: Matthew Fortune Cc: Leonid Yegoshin Cc: Michael Ellerman Cc: linux-kernel@vger.kernel.org Cc: Richard Weinberger Cc: James Hogan Cc: Andrew Morton Cc: Andy Lutomirski Cc: Markos Chandras Cc: Manuel Lauss Cc: Maciej W. Rozycki Patchwork: https://patchwork.linux-mips.org/patch/10792/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/signal.h | 3 + arch/mips/kernel/asm-offsets.c | 11 --- arch/mips/kernel/r4k_fpu.S | 114 ------------------------- arch/mips/kernel/signal.c | 4 +- arch/mips/kernel/signal32.c | 150 ++------------------------------- 5 files changed, 11 insertions(+), 271 deletions(-) diff --git a/arch/mips/include/asm/signal.h b/arch/mips/include/asm/signal.h index 8efe5a9e2c3e..003e273eff4c 100644 --- a/arch/mips/include/asm/signal.h +++ b/arch/mips/include/asm/signal.h @@ -23,4 +23,7 @@ #define __ARCH_HAS_IRIX_SIGACTION +extern int protected_save_fp_context(void __user *sc); +extern int protected_restore_fp_context(void __user *sc); + #endif /* _ASM_SIGNAL_H */ diff --git a/arch/mips/kernel/asm-offsets.c b/arch/mips/kernel/asm-offsets.c index 072fab13645d..3706091b6351 100644 --- a/arch/mips/kernel/asm-offsets.c +++ b/arch/mips/kernel/asm-offsets.c @@ -245,17 +245,6 @@ void output_sc_defines(void) } #endif -#ifdef CONFIG_MIPS32_COMPAT -void output_sc32_defines(void) -{ - COMMENT("Linux 32-bit sigcontext offsets."); - OFFSET(SC32_FPREGS, sigcontext32, sc_fpregs); - OFFSET(SC32_FPC_CSR, sigcontext32, sc_fpc_csr); - OFFSET(SC32_FPC_EIR, sigcontext32, sc_fpc_eir); - BLANK(); -} -#endif - void output_signal_defined(void) { COMMENT("Linux signal numbers."); diff --git a/arch/mips/kernel/r4k_fpu.S b/arch/mips/kernel/r4k_fpu.S index b8044d612ad3..0ed139889245 100644 --- a/arch/mips/kernel/r4k_fpu.S +++ b/arch/mips/kernel/r4k_fpu.S @@ -107,66 +107,6 @@ LEAF(_save_fp_context) .set pop END(_save_fp_context) -#ifdef CONFIG_MIPS32_COMPAT - /* Save 32-bit process floating point context */ -LEAF(_save_fp_context32) - .set push - .set MIPS_ISA_ARCH_LEVEL_RAW - SET_HARDFLOAT - cfc1 t1, fcr31 - -#ifndef CONFIG_CPU_MIPS64_R6 - mfc0 t0, CP0_STATUS - sll t0, t0, 5 - bgez t0, 1f # skip storing odd if FR=0 - nop -#endif - - /* Store the 16 odd double precision registers */ - EX sdc1 $f1, SC32_FPREGS+8(a0) - EX sdc1 $f3, SC32_FPREGS+24(a0) - EX sdc1 $f5, SC32_FPREGS+40(a0) - EX sdc1 $f7, SC32_FPREGS+56(a0) - EX sdc1 $f9, SC32_FPREGS+72(a0) - EX sdc1 $f11, SC32_FPREGS+88(a0) - EX sdc1 $f13, SC32_FPREGS+104(a0) - EX sdc1 $f15, SC32_FPREGS+120(a0) - EX sdc1 $f17, SC32_FPREGS+136(a0) - EX sdc1 $f19, SC32_FPREGS+152(a0) - EX sdc1 $f21, SC32_FPREGS+168(a0) - EX sdc1 $f23, SC32_FPREGS+184(a0) - EX sdc1 $f25, SC32_FPREGS+200(a0) - EX sdc1 $f27, SC32_FPREGS+216(a0) - EX sdc1 $f29, SC32_FPREGS+232(a0) - EX sdc1 $f31, SC32_FPREGS+248(a0) - - /* Store the 16 even double precision registers */ -1: EX sdc1 $f0, SC32_FPREGS+0(a0) - EX sdc1 $f2, SC32_FPREGS+16(a0) - EX sdc1 $f4, SC32_FPREGS+32(a0) - EX sdc1 $f6, SC32_FPREGS+48(a0) - EX sdc1 $f8, SC32_FPREGS+64(a0) - EX sdc1 $f10, SC32_FPREGS+80(a0) - EX sdc1 $f12, SC32_FPREGS+96(a0) - EX sdc1 $f14, SC32_FPREGS+112(a0) - EX sdc1 $f16, SC32_FPREGS+128(a0) - EX sdc1 $f18, SC32_FPREGS+144(a0) - EX sdc1 $f20, SC32_FPREGS+160(a0) - EX sdc1 $f22, SC32_FPREGS+176(a0) - EX sdc1 $f24, SC32_FPREGS+192(a0) - EX sdc1 $f26, SC32_FPREGS+208(a0) - EX sdc1 $f28, SC32_FPREGS+224(a0) - EX sdc1 $f30, SC32_FPREGS+240(a0) - EX sw t1, SC32_FPC_CSR(a0) - cfc1 t0, $0 # implementation/version - EX sw t0, SC32_FPC_EIR(a0) - .set pop - - jr ra - li v0, 0 # success - END(_save_fp_context32) -#endif - /** * _restore_fp_context() - restore FP context to the FPU * @a0 - pointer to fpregs field of sigcontext @@ -232,60 +172,6 @@ LEAF(_restore_fp_context) li v0, 0 # success END(_restore_fp_context) -#ifdef CONFIG_MIPS32_COMPAT -LEAF(_restore_fp_context32) - /* Restore an o32 sigcontext. */ - .set push - SET_HARDFLOAT - EX lw t1, SC32_FPC_CSR(a0) - -#ifndef CONFIG_CPU_MIPS64_R6 - mfc0 t0, CP0_STATUS - sll t0, t0, 5 - bgez t0, 1f # skip loading odd if FR=0 - nop -#endif - - EX ldc1 $f1, SC32_FPREGS+8(a0) - EX ldc1 $f3, SC32_FPREGS+24(a0) - EX ldc1 $f5, SC32_FPREGS+40(a0) - EX ldc1 $f7, SC32_FPREGS+56(a0) - EX ldc1 $f9, SC32_FPREGS+72(a0) - EX ldc1 $f11, SC32_FPREGS+88(a0) - EX ldc1 $f13, SC32_FPREGS+104(a0) - EX ldc1 $f15, SC32_FPREGS+120(a0) - EX ldc1 $f17, SC32_FPREGS+136(a0) - EX ldc1 $f19, SC32_FPREGS+152(a0) - EX ldc1 $f21, SC32_FPREGS+168(a0) - EX ldc1 $f23, SC32_FPREGS+184(a0) - EX ldc1 $f25, SC32_FPREGS+200(a0) - EX ldc1 $f27, SC32_FPREGS+216(a0) - EX ldc1 $f29, SC32_FPREGS+232(a0) - EX ldc1 $f31, SC32_FPREGS+248(a0) - -1: EX ldc1 $f0, SC32_FPREGS+0(a0) - EX ldc1 $f2, SC32_FPREGS+16(a0) - EX ldc1 $f4, SC32_FPREGS+32(a0) - EX ldc1 $f6, SC32_FPREGS+48(a0) - EX ldc1 $f8, SC32_FPREGS+64(a0) - EX ldc1 $f10, SC32_FPREGS+80(a0) - EX ldc1 $f12, SC32_FPREGS+96(a0) - EX ldc1 $f14, SC32_FPREGS+112(a0) - EX ldc1 $f16, SC32_FPREGS+128(a0) - EX ldc1 $f18, SC32_FPREGS+144(a0) - EX ldc1 $f20, SC32_FPREGS+160(a0) - EX ldc1 $f22, SC32_FPREGS+176(a0) - EX ldc1 $f24, SC32_FPREGS+192(a0) - EX ldc1 $f26, SC32_FPREGS+208(a0) - EX ldc1 $f28, SC32_FPREGS+224(a0) - EX ldc1 $f30, SC32_FPREGS+240(a0) - ctc1 t1, fcr31 - jr ra - li v0, 0 # success - .set pop - END(_restore_fp_context32) -#endif - #ifdef CONFIG_CPU_HAS_MSA .macro op_one_wr op, idx, base diff --git a/arch/mips/kernel/signal.c b/arch/mips/kernel/signal.c index cc3a01f5c5af..08f521567d64 100644 --- a/arch/mips/kernel/signal.c +++ b/arch/mips/kernel/signal.c @@ -124,7 +124,7 @@ static int restore_hw_fp_context(void __user *sc) /* * Helper routines */ -static int protected_save_fp_context(void __user *sc) +int protected_save_fp_context(void __user *sc) { struct mips_abi *abi = current->thread.abi; uint64_t __user *fpregs = sc + abi->off_sc_fpregs; @@ -167,7 +167,7 @@ static int protected_save_fp_context(void __user *sc) return err; } -static int protected_restore_fp_context(void __user *sc) +int protected_restore_fp_context(void __user *sc) { struct mips_abi *abi = current->thread.abi; uint64_t __user *fpregs = sc + abi->off_sc_fpregs; diff --git a/arch/mips/kernel/signal32.c b/arch/mips/kernel/signal32.c index da70ea5cf6ec..7c45cb3e075a 100644 --- a/arch/mips/kernel/signal32.c +++ b/arch/mips/kernel/signal32.c @@ -36,12 +36,6 @@ #include "signal-common.h" -static int (*save_fp_context32)(struct sigcontext32 __user *sc); -static int (*restore_fp_context32)(struct sigcontext32 __user *sc); - -extern asmlinkage int _save_fp_context32(struct sigcontext32 __user *sc); -extern asmlinkage int _restore_fp_context32(struct sigcontext32 __user *sc); - /* * Including would give use the 64-bit syscall numbers ... */ @@ -74,99 +68,11 @@ struct rt_sigframe32 { struct ucontext32 rs_uc; }; -/* - * Thread saved context copy to/from a signal context presumed to be on the - * user stack, and therefore accessed with appropriate macros from uaccess.h. - */ -static int copy_fp_to_sigcontext32(struct sigcontext32 __user *sc) -{ - int i; - int err = 0; - int inc = test_thread_flag(TIF_32BIT_FPREGS) ? 2 : 1; - - for (i = 0; i < NUM_FPU_REGS; i += inc) { - err |= - __put_user(get_fpr64(¤t->thread.fpu.fpr[i], 0), - &sc->sc_fpregs[i]); - } - err |= __put_user(current->thread.fpu.fcr31, &sc->sc_fpc_csr); - - return err; -} - -static int copy_fp_from_sigcontext32(struct sigcontext32 __user *sc) -{ - int i; - int err = 0; - int inc = test_thread_flag(TIF_32BIT_FPREGS) ? 2 : 1; - u64 fpr_val; - - for (i = 0; i < NUM_FPU_REGS; i += inc) { - err |= __get_user(fpr_val, &sc->sc_fpregs[i]); - set_fpr64(¤t->thread.fpu.fpr[i], 0, fpr_val); - } - err |= __get_user(current->thread.fpu.fcr31, &sc->sc_fpc_csr); - - return err; -} - -/* - * sigcontext handlers - */ -static int protected_save_fp_context32(struct sigcontext32 __user *sc) -{ - int err; - while (1) { - lock_fpu_owner(); - if (is_fpu_owner()) { - err = save_fp_context32(sc); - unlock_fpu_owner(); - } else { - unlock_fpu_owner(); - err = copy_fp_to_sigcontext32(sc); - } - if (likely(!err)) - break; - /* touch the sigcontext and try again */ - err = __put_user(0, &sc->sc_fpregs[0]) | - __put_user(0, &sc->sc_fpregs[31]) | - __put_user(0, &sc->sc_fpc_csr); - if (err) - break; /* really bad sigcontext */ - } - return err; -} - -static int protected_restore_fp_context32(struct sigcontext32 __user *sc) -{ - int err, tmp __maybe_unused; - while (1) { - lock_fpu_owner(); - if (is_fpu_owner()) { - err = restore_fp_context32(sc); - unlock_fpu_owner(); - } else { - unlock_fpu_owner(); - err = copy_fp_from_sigcontext32(sc); - } - if (likely(!err)) - break; - /* touch the sigcontext and try again */ - err = __get_user(tmp, &sc->sc_fpregs[0]) | - __get_user(tmp, &sc->sc_fpregs[31]) | - __get_user(tmp, &sc->sc_fpc_csr); - if (err) - break; /* really bad sigcontext */ - } - return err; -} - static int setup_sigcontext32(struct pt_regs *regs, struct sigcontext32 __user *sc) { int err = 0; int i; - u32 used_math; err |= __put_user(regs->cp0_epc, &sc->sc_pc); @@ -186,35 +92,18 @@ static int setup_sigcontext32(struct pt_regs *regs, err |= __put_user(mflo3(), &sc->sc_lo3); } - used_math = !!used_math(); - err |= __put_user(used_math, &sc->sc_used_math); + /* + * Save FPU state to signal context. Signal handler + * will "inherit" current FPU state. + */ + err |= protected_save_fp_context(sc); - if (used_math) { - /* - * Save FPU state to signal context. Signal handler - * will "inherit" current FPU state. - */ - err |= protected_save_fp_context32(sc); - } return err; } -static int -check_and_restore_fp_context32(struct sigcontext32 __user *sc) -{ - int err, sig; - - err = sig = fpcsr_pending(&sc->sc_fpc_csr); - if (err > 0) - err = 0; - err |= protected_restore_fp_context32(sc); - return err ?: sig; -} - static int restore_sigcontext32(struct pt_regs *regs, struct sigcontext32 __user *sc) { - u32 used_math; int err = 0; s32 treg; int i; @@ -238,19 +127,7 @@ static int restore_sigcontext32(struct pt_regs *regs, 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_context32(sc); - } else { - /* signal handler may have used FPU. Give it up. */ - lose_fpu(0); - } - - return err; + return err ?: protected_restore_fp_context(sc); } /* @@ -591,18 +468,3 @@ struct mips_abi mips_abi_32 = { .off_sc_fpc_csr = offsetof(struct sigcontext32, sc_fpc_csr), .off_sc_used_math = offsetof(struct sigcontext32, sc_used_math), }; - -static int signal32_init(void) -{ - if (cpu_has_fpu) { - save_fp_context32 = _save_fp_context32; - restore_fp_context32 = _restore_fp_context32; - } else { - save_fp_context32 = copy_fp_to_sigcontext32; - restore_fp_context32 = copy_fp_from_sigcontext32; - } - - return 0; -} - -arch_initcall(signal32_init); -- 2.39.5