forked from Minki/linux
5a1aca4469
Sanitize FCSR Cause bit handling, following a trail of past attempts: * commit4249548454
("MIPS: ptrace: Fix FP context restoration FCSR regression"), * commit443c44032a
("MIPS: Always clear FCSR cause bits after emulation"), * commit64bedffe49
("MIPS: Clear [MSA]FPE CSR.Cause after notify_die()"), * commitb1442d39fa
("MIPS: Prevent user from setting FCSR cause bits"), * commit b54d2901517d ("Properly handle branch delay slots in connection with signals."). Specifically do not mask these bits out in ptrace(2) processing and send a SIGFPE signal instead whenever a matching pair of an FCSR Cause and Enable bit is seen as execution of an affected context is about to resume. Only then clear Cause bits, and even then do not clear any bits that are set but masked with the respective Enable bits. Adjust Cause bit clearing throughout code likewise, except within the FPU emulator proper where they are set according to IEEE 754 exceptions raised as the operation emulated executed. Do so so that any IEEE 754 exceptions subject to their default handling are recorded like with operations executed by FPU hardware. Signed-off-by: Maciej W. Rozycki <macro@imgtec.com> Cc: Paul Burton <paul.burton@imgtec.com> Cc: James Hogan <james.hogan@imgtec.com> Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/14460/ Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
98 lines
3.0 KiB
C
98 lines
3.0 KiB
C
/*
|
|
* This program is free software; you can distribute it and/or modify it
|
|
* under the terms of the GNU General Public License (Version 2) as
|
|
* published by the Free Software Foundation.
|
|
*
|
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
* for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License along
|
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
|
* 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
|
|
*
|
|
* Further private data for which no space exists in mips_fpu_struct.
|
|
* This should be subsumed into the mips_fpu_struct structure as
|
|
* defined in processor.h as soon as the absurd wired absolute assembler
|
|
* offsets become dynamic at compile time.
|
|
*
|
|
* Kevin D. Kissell, kevink@mips.com and Carsten Langgaard, carstenl@mips.com
|
|
* Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved.
|
|
*/
|
|
#ifndef _ASM_FPU_EMULATOR_H
|
|
#define _ASM_FPU_EMULATOR_H
|
|
|
|
#include <linux/sched.h>
|
|
#include <asm/dsemul.h>
|
|
#include <asm/thread_info.h>
|
|
#include <asm/inst.h>
|
|
#include <asm/local.h>
|
|
#include <asm/processor.h>
|
|
|
|
#ifdef CONFIG_DEBUG_FS
|
|
|
|
struct mips_fpu_emulator_stats {
|
|
unsigned long emulated;
|
|
unsigned long loads;
|
|
unsigned long stores;
|
|
unsigned long cp1ops;
|
|
unsigned long cp1xops;
|
|
unsigned long errors;
|
|
unsigned long ieee754_inexact;
|
|
unsigned long ieee754_underflow;
|
|
unsigned long ieee754_overflow;
|
|
unsigned long ieee754_zerodiv;
|
|
unsigned long ieee754_invalidop;
|
|
unsigned long ds_emul;
|
|
};
|
|
|
|
DECLARE_PER_CPU(struct mips_fpu_emulator_stats, fpuemustats);
|
|
|
|
#define MIPS_FPU_EMU_INC_STATS(M) \
|
|
do { \
|
|
preempt_disable(); \
|
|
__this_cpu_inc(fpuemustats.M); \
|
|
preempt_enable(); \
|
|
} while (0)
|
|
|
|
#else
|
|
#define MIPS_FPU_EMU_INC_STATS(M) do { } while (0)
|
|
#endif /* CONFIG_DEBUG_FS */
|
|
|
|
extern int fpu_emulator_cop1Handler(struct pt_regs *xcp,
|
|
struct mips_fpu_struct *ctx, int has_fpu,
|
|
void *__user *fault_addr);
|
|
void force_fcr31_sig(unsigned long fcr31, void __user *fault_addr,
|
|
struct task_struct *tsk);
|
|
int process_fpemu_return(int sig, void __user *fault_addr,
|
|
unsigned long fcr31);
|
|
int isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn,
|
|
unsigned long *contpc);
|
|
int mm_isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn,
|
|
unsigned long *contpc);
|
|
|
|
#define SIGNALLING_NAN 0x7ff800007ff80000LL
|
|
|
|
static inline void fpu_emulator_init_fpu(void)
|
|
{
|
|
struct task_struct *t = current;
|
|
int i;
|
|
|
|
for (i = 0; i < 32; i++)
|
|
set_fpr64(&t->thread.fpu.fpr[i], 0, SIGNALLING_NAN);
|
|
}
|
|
|
|
/*
|
|
* Mask the FCSR Cause bits according to the Enable bits, observing
|
|
* that Unimplemented is always enabled.
|
|
*/
|
|
static inline unsigned long mask_fcr31_x(unsigned long fcr31)
|
|
{
|
|
return fcr31 & (FPU_CSR_UNI_X |
|
|
((fcr31 & FPU_CSR_ALL_E) <<
|
|
(ffs(FPU_CSR_ALL_X) - ffs(FPU_CSR_ALL_E))));
|
|
}
|
|
|
|
#endif /* _ASM_FPU_EMULATOR_H */
|