Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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 <ralf@linux-mips.org>
Signed-off-by: Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>

+37 -37
+1
arch/mips/include/asm/break.h
··· 29 29 #define _BRK_THREADBP 11 /* For threads, user bp (used by debuggers) */ 30 30 #define BRK_BUG 512 /* Used by BUG() */ 31 31 #define BRK_KDB 513 /* Used in KDB_ENTER() */ 32 + #define BRK_MEMU 514 /* Used by FPU emulator */ 32 33 #define BRK_MULOVF 1023 /* Multiply overflow */ 33 34 34 35 #endif /* __ASM_BREAK_H */
+17
arch/mips/include/asm/fpu_emulator.h
··· 23 23 #ifndef _ASM_FPU_EMULATOR_H 24 24 #define _ASM_FPU_EMULATOR_H 25 25 26 + #include <asm/break.h> 27 + #include <asm/inst.h> 28 + 26 29 struct mips_fpu_emulator_stats { 27 30 unsigned int emulated; 28 31 unsigned int loads; ··· 36 33 }; 37 34 38 35 extern struct mips_fpu_emulator_stats fpuemustats; 36 + 37 + extern int mips_dsemul(struct pt_regs *regs, mips_instruction ir, 38 + unsigned long cpc); 39 + extern int do_dsemulret(struct pt_regs *xcp); 40 + 41 + /* 42 + * Instruction inserted following the badinst to further tag the sequence 43 + */ 44 + #define BD_COOKIE 0x0000bd36 /* tne $0, $0 with baggage */ 45 + 46 + /* 47 + * Break instruction with special math emu break code set 48 + */ 49 + #define BREAK_MATH (0x0000000d | (BRK_MEMU << 16)) 39 50 40 51 #endif /* _ASM_FPU_EMULATOR_H */
+16
arch/mips/kernel/traps.c
··· 32 32 #include <asm/cpu.h> 33 33 #include <asm/dsp.h> 34 34 #include <asm/fpu.h> 35 + #include <asm/fpu_emulator.h> 35 36 #include <asm/mipsregs.h> 36 37 #include <asm/mipsmtregs.h> 37 38 #include <asm/module.h> ··· 721 720 break; 722 721 case BRK_BUG: 723 722 die_if_kernel("Kernel bug detected", regs); 723 + force_sig(SIGTRAP, current); 724 + break; 725 + case BRK_MEMU: 726 + /* 727 + * Address errors may be deliberately induced by the FPU 728 + * emulator to retake control of the CPU after executing the 729 + * instruction in the delay slot of an emulated branch. 730 + * 731 + * Terminate if exception was recognized as a delay slot return 732 + * otherwise handle as normal. 733 + */ 734 + if (do_dsemulret(regs)) 735 + return; 736 + 737 + die_if_kernel("Math emu break/trap", regs); 724 738 force_sig(SIGTRAP, current); 725 739 break; 726 740 default:
-12
arch/mips/kernel/unaligned.c
··· 499 499 500 500 asmlinkage void do_ade(struct pt_regs *regs) 501 501 { 502 - extern int do_dsemulret(struct pt_regs *); 503 502 unsigned int __user *pc; 504 503 mm_segment_t seg; 505 - 506 - /* 507 - * Address errors may be deliberately induced by the FPU emulator to 508 - * retake control of the CPU after executing the instruction in the 509 - * delay slot of an emulated branch. 510 - */ 511 - /* Terminate if exception was recognized as a delay slot return */ 512 - if (do_dsemulret(regs)) 513 - return; 514 - 515 - /* Otherwise handle as normal */ 516 504 517 505 /* 518 506 * Did we catch a fault trying to load an instruction?
-4
arch/mips/math-emu/cp1emu.c
··· 48 48 #include <asm/branch.h> 49 49 50 50 #include "ieee754.h" 51 - #include "dsemul.h" 52 51 53 52 /* Strap kernel emulator for full MIPS IV emulation */ 54 53 ··· 345 346 /* cop control register rd -> gpr[rt] */ 346 347 u32 value; 347 348 348 - if (ir == CP1UNDEF) { 349 - return do_dsemulret(xcp); 350 - } 351 349 if (MIPSInst_RD(ir) == FPCREG_CSR) { 352 350 value = ctx->fcr31; 353 351 value = (value & ~0x3) | mips_rm[value & 0x3];
+3 -4
arch/mips/math-emu/dsemul.c
··· 18 18 #include <asm/fpu_emulator.h> 19 19 20 20 #include "ieee754.h" 21 - #include "dsemul.h" 22 21 23 22 /* Strap kernel emulator for full MIPS IV emulation */ 24 23 ··· 93 94 return SIGBUS; 94 95 95 96 err = __put_user(ir, &fr->emul); 96 - err |= __put_user((mips_instruction)BADINST, &fr->badinst); 97 + err |= __put_user((mips_instruction)BREAK_MATH, &fr->badinst); 97 98 err |= __put_user((mips_instruction)BD_COOKIE, &fr->cookie); 98 99 err |= __put_user(cpc, &fr->epc); 99 100 ··· 129 130 /* 130 131 * Do some sanity checking on the stackframe: 131 132 * 132 - * - Is the instruction pointed to by the EPC an BADINST? 133 + * - Is the instruction pointed to by the EPC an BREAK_MATH? 133 134 * - Is the following memory word the BD_COOKIE? 134 135 */ 135 136 err = __get_user(insn, &fr->badinst); 136 137 err |= __get_user(cookie, &fr->cookie); 137 138 138 - if (unlikely(err || (insn != BADINST) || (cookie != BD_COOKIE))) { 139 + if (unlikely(err || (insn != BREAK_MATH) || (cookie != BD_COOKIE))) { 139 140 fpuemustats.errors++; 140 141 return 0; 141 142 }
-17
arch/mips/math-emu/dsemul.h
··· 1 - extern int mips_dsemul(struct pt_regs *regs, mips_instruction ir, unsigned long cpc); 2 - extern int do_dsemulret(struct pt_regs *xcp); 3 - 4 - /* Instruction which will always cause an address error */ 5 - #define AdELOAD 0x8c000001 /* lw $0,1($0) */ 6 - /* Instruction which will plainly cause a CP1 exception when FPU is disabled */ 7 - #define CP1UNDEF 0x44400001 /* cfc1 $0,$0 undef */ 8 - 9 - /* Instruction inserted following the badinst to further tag the sequence */ 10 - #define BD_COOKIE 0x0000bd36 /* tne $0,$0 with baggage */ 11 - 12 - /* Setup which instruction to use for trampoline */ 13 - #ifdef STANDALONE_EMULATOR 14 - #define BADINST CP1UNDEF 15 - #else 16 - #define BADINST AdELOAD 17 - #endif