From ba3049ed4086737dab200b6087138a4b8e06915d Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Tue, 28 Oct 2008 17:38:42 +0000 Subject: [PATCH] MIPS: Switch FPU emulator trap to BREAK instruction. Arguably using the address error handler has always been ugly. But with processors that handle unaligned loads and stores in hardware the current mechanism ceases to work so switch it to a BREAK instruction and allocate break code 514 to the FPU emulator. Yoichi Yuasa provided a build fix for CONFIG_BUG=n. Signed-off-by: Ralf Baechle Signed-off-by: Yoichi Yuasa --- arch/mips/include/asm/break.h | 1 + arch/mips/include/asm/fpu_emulator.h | 17 +++++++++++++++++ arch/mips/kernel/traps.c | 16 ++++++++++++++++ arch/mips/kernel/unaligned.c | 12 ------------ arch/mips/math-emu/cp1emu.c | 4 ---- arch/mips/math-emu/dsemul.c | 7 +++---- arch/mips/math-emu/dsemul.h | 17 ----------------- 7 files changed, 37 insertions(+), 37 deletions(-) delete mode 100644 arch/mips/math-emu/dsemul.h diff --git a/arch/mips/include/asm/break.h b/arch/mips/include/asm/break.h index 25b980c91e7e..44437ed765e8 100644 --- a/arch/mips/include/asm/break.h +++ b/arch/mips/include/asm/break.h @@ -29,6 +29,7 @@ #define _BRK_THREADBP 11 /* For threads, user bp (used by debuggers) */ #define BRK_BUG 512 /* Used by BUG() */ #define BRK_KDB 513 /* Used in KDB_ENTER() */ +#define BRK_MEMU 514 /* Used by FPU emulator */ #define BRK_MULOVF 1023 /* Multiply overflow */ #endif /* __ASM_BREAK_H */ diff --git a/arch/mips/include/asm/fpu_emulator.h b/arch/mips/include/asm/fpu_emulator.h index 2731c38bd7ae..e5189572956c 100644 --- a/arch/mips/include/asm/fpu_emulator.h +++ b/arch/mips/include/asm/fpu_emulator.h @@ -23,6 +23,9 @@ #ifndef _ASM_FPU_EMULATOR_H #define _ASM_FPU_EMULATOR_H +#include +#include + struct mips_fpu_emulator_stats { unsigned int emulated; unsigned int loads; @@ -34,4 +37,18 @@ struct mips_fpu_emulator_stats { extern struct mips_fpu_emulator_stats fpuemustats; +extern int mips_dsemul(struct pt_regs *regs, mips_instruction ir, + unsigned long cpc); +extern int do_dsemulret(struct pt_regs *xcp); + +/* + * Instruction inserted following the badinst to further tag the sequence + */ +#define BD_COOKIE 0x0000bd36 /* tne $0, $0 with baggage */ + +/* + * Break instruction with special math emu break code set + */ +#define BREAK_MATH (0x0000000d | (BRK_MEMU << 16)) + #endif /* _ASM_FPU_EMULATOR_H */ diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index 3f6de76d485d..353056110f2b 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -722,6 +723,21 @@ static void do_trap_or_bp(struct pt_regs *regs, unsigned int code, die_if_kernel("Kernel bug detected", regs); force_sig(SIGTRAP, current); break; + case BRK_MEMU: + /* + * Address errors may be deliberately induced by the FPU + * emulator to retake control of the CPU after executing the + * instruction in the delay slot of an emulated branch. + * + * Terminate if exception was recognized as a delay slot return + * otherwise handle as normal. + */ + if (do_dsemulret(regs)) + return; + + die_if_kernel("Math emu break/trap", regs); + force_sig(SIGTRAP, current); + break; default: scnprintf(b, sizeof(b), "%s instruction in kernel code", str); die_if_kernel(b, regs); diff --git a/arch/mips/kernel/unaligned.c b/arch/mips/kernel/unaligned.c index 20709669e592..bf4c4a979abb 100644 --- a/arch/mips/kernel/unaligned.c +++ b/arch/mips/kernel/unaligned.c @@ -499,21 +499,9 @@ static void emulate_load_store_insn(struct pt_regs *regs, asmlinkage void do_ade(struct pt_regs *regs) { - extern int do_dsemulret(struct pt_regs *); unsigned int __user *pc; mm_segment_t seg; - /* - * Address errors may be deliberately induced by the FPU emulator to - * retake control of the CPU after executing the instruction in the - * delay slot of an emulated branch. - */ - /* Terminate if exception was recognized as a delay slot return */ - if (do_dsemulret(regs)) - return; - - /* Otherwise handle as normal */ - /* * Did we catch a fault trying to load an instruction? * Or are we running in MIPS16 mode? diff --git a/arch/mips/math-emu/cp1emu.c b/arch/mips/math-emu/cp1emu.c index 7ec0b217dfd3..890f77927d62 100644 --- a/arch/mips/math-emu/cp1emu.c +++ b/arch/mips/math-emu/cp1emu.c @@ -48,7 +48,6 @@ #include #include "ieee754.h" -#include "dsemul.h" /* Strap kernel emulator for full MIPS IV emulation */ @@ -346,9 +345,6 @@ static int cop1Emulate(struct pt_regs *xcp, struct mips_fpu_struct *ctx) /* cop control register rd -> gpr[rt] */ u32 value; - if (ir == CP1UNDEF) { - return do_dsemulret(xcp); - } if (MIPSInst_RD(ir) == FPCREG_CSR) { value = ctx->fcr31; value = (value & ~0x3) | mips_rm[value & 0x3]; diff --git a/arch/mips/math-emu/dsemul.c b/arch/mips/math-emu/dsemul.c index 653e325849e4..df7b9d928efc 100644 --- a/arch/mips/math-emu/dsemul.c +++ b/arch/mips/math-emu/dsemul.c @@ -18,7 +18,6 @@ #include #include "ieee754.h" -#include "dsemul.h" /* Strap kernel emulator for full MIPS IV emulation */ @@ -94,7 +93,7 @@ int mips_dsemul(struct pt_regs *regs, mips_instruction ir, unsigned long cpc) return SIGBUS; err = __put_user(ir, &fr->emul); - err |= __put_user((mips_instruction)BADINST, &fr->badinst); + err |= __put_user((mips_instruction)BREAK_MATH, &fr->badinst); err |= __put_user((mips_instruction)BD_COOKIE, &fr->cookie); err |= __put_user(cpc, &fr->epc); @@ -130,13 +129,13 @@ int do_dsemulret(struct pt_regs *xcp) /* * Do some sanity checking on the stackframe: * - * - Is the instruction pointed to by the EPC an BADINST? + * - Is the instruction pointed to by the EPC an BREAK_MATH? * - Is the following memory word the BD_COOKIE? */ err = __get_user(insn, &fr->badinst); err |= __get_user(cookie, &fr->cookie); - if (unlikely(err || (insn != BADINST) || (cookie != BD_COOKIE))) { + if (unlikely(err || (insn != BREAK_MATH) || (cookie != BD_COOKIE))) { fpuemustats.errors++; return 0; } diff --git a/arch/mips/math-emu/dsemul.h b/arch/mips/math-emu/dsemul.h deleted file mode 100644 index 091f0e76730f..000000000000 --- a/arch/mips/math-emu/dsemul.h +++ /dev/null @@ -1,17 +0,0 @@ -extern int mips_dsemul(struct pt_regs *regs, mips_instruction ir, unsigned long cpc); -extern int do_dsemulret(struct pt_regs *xcp); - -/* Instruction which will always cause an address error */ -#define AdELOAD 0x8c000001 /* lw $0,1($0) */ -/* Instruction which will plainly cause a CP1 exception when FPU is disabled */ -#define CP1UNDEF 0x44400001 /* cfc1 $0,$0 undef */ - -/* Instruction inserted following the badinst to further tag the sequence */ -#define BD_COOKIE 0x0000bd36 /* tne $0,$0 with baggage */ - -/* Setup which instruction to use for trampoline */ -#ifdef STANDALONE_EMULATOR -#define BADINST CP1UNDEF -#else -#define BADINST AdELOAD -#endif