Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ba3049ed authored by Ralf Baechle's avatar Ralf Baechle
Browse files

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: default avatarRalf Baechle <ralf@linux-mips.org>
Signed-off-by: default avatarYoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
parent 076c6e4f
Loading
Loading
Loading
Loading
+1 −0
Original line number Original line Diff line number Diff line
@@ -29,6 +29,7 @@
#define _BRK_THREADBP	11	/* For threads, user bp (used by debuggers) */
#define _BRK_THREADBP	11	/* For threads, user bp (used by debuggers) */
#define BRK_BUG		512	/* Used by BUG() */
#define BRK_BUG		512	/* Used by BUG() */
#define BRK_KDB		513	/* Used in KDB_ENTER() */
#define BRK_KDB		513	/* Used in KDB_ENTER() */
#define BRK_MEMU	514	/* Used by FPU emulator */
#define BRK_MULOVF	1023	/* Multiply overflow */
#define BRK_MULOVF	1023	/* Multiply overflow */


#endif /* __ASM_BREAK_H */
#endif /* __ASM_BREAK_H */
+17 −0
Original line number Original line Diff line number Diff line
@@ -23,6 +23,9 @@
#ifndef _ASM_FPU_EMULATOR_H
#ifndef _ASM_FPU_EMULATOR_H
#define _ASM_FPU_EMULATOR_H
#define _ASM_FPU_EMULATOR_H


#include <asm/break.h>
#include <asm/inst.h>

struct mips_fpu_emulator_stats {
struct mips_fpu_emulator_stats {
	unsigned int emulated;
	unsigned int emulated;
	unsigned int loads;
	unsigned int loads;
@@ -34,4 +37,18 @@ struct mips_fpu_emulator_stats {


extern struct mips_fpu_emulator_stats fpuemustats;
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 */
#endif /* _ASM_FPU_EMULATOR_H */
+16 −0
Original line number Original line Diff line number Diff line
@@ -32,6 +32,7 @@
#include <asm/cpu.h>
#include <asm/cpu.h>
#include <asm/dsp.h>
#include <asm/dsp.h>
#include <asm/fpu.h>
#include <asm/fpu.h>
#include <asm/fpu_emulator.h>
#include <asm/mipsregs.h>
#include <asm/mipsregs.h>
#include <asm/mipsmtregs.h>
#include <asm/mipsmtregs.h>
#include <asm/module.h>
#include <asm/module.h>
@@ -722,6 +723,21 @@ static void do_trap_or_bp(struct pt_regs *regs, unsigned int code,
		die_if_kernel("Kernel bug detected", regs);
		die_if_kernel("Kernel bug detected", regs);
		force_sig(SIGTRAP, current);
		force_sig(SIGTRAP, current);
		break;
		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:
	default:
		scnprintf(b, sizeof(b), "%s instruction in kernel code", str);
		scnprintf(b, sizeof(b), "%s instruction in kernel code", str);
		die_if_kernel(b, regs);
		die_if_kernel(b, regs);
+0 −12
Original line number Original line Diff line number Diff line
@@ -499,21 +499,9 @@ sigill:


asmlinkage void do_ade(struct pt_regs *regs)
asmlinkage void do_ade(struct pt_regs *regs)
{
{
	extern int do_dsemulret(struct pt_regs *);
	unsigned int __user *pc;
	unsigned int __user *pc;
	mm_segment_t seg;
	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?
	 * Did we catch a fault trying to load an instruction?
	 * Or are we running in MIPS16 mode?
	 * Or are we running in MIPS16 mode?
+0 −4
Original line number Original line Diff line number Diff line
@@ -48,7 +48,6 @@
#include <asm/branch.h>
#include <asm/branch.h>


#include "ieee754.h"
#include "ieee754.h"
#include "dsemul.h"


/* Strap kernel emulator for full MIPS IV emulation */
/* 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] */
			/* cop control register rd -> gpr[rt] */
			u32 value;
			u32 value;


			if (ir == CP1UNDEF) {
				return do_dsemulret(xcp);
			}
			if (MIPSInst_RD(ir) == FPCREG_CSR) {
			if (MIPSInst_RD(ir) == FPCREG_CSR) {
				value = ctx->fcr31;
				value = ctx->fcr31;
				value = (value & ~0x3) | mips_rm[value & 0x3];
				value = (value & ~0x3) | mips_rm[value & 0x3];
Loading