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 <paul.burton@imgtec.com> Cc: linux-mips@linux-mips.org Cc: Guenter Roeck <linux@roeck-us.net> Cc: Matthew Fortune <matthew.fortune@imgtec.com> Cc: Leonid Yegoshin <Leonid.Yegoshin@imgtec.com> Cc: Michael Ellerman <mpe@ellerman.id.au> Cc: linux-kernel@vger.kernel.org Cc: Richard Weinberger <richard@nod.at> Cc: James Hogan <james.hogan@imgtec.com> Cc: Andrew Morton <akpm@linux-foundation.org> Cc: Andy Lutomirski <luto@amacapital.net> Cc: Markos Chandras <markos.chandras@imgtec.com> Cc: Manuel Lauss <manuel.lauss@gmail.com> Cc: Maciej W. Rozycki <macro@codesourcery.com> Patchwork: https://patchwork.linux-mips.org/patch/10792/ Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
This commit is contained in:
parent
6f0aba63bf
commit
d02a40aff6
|
@ -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 */
|
||||
|
|
|
@ -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.");
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 <asm/unistd.h> 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);
|
||||
|
|
Loading…
Reference in New Issue