summaryrefslogtreecommitdiff
path: root/arch/mips/math-emu/dsemul.c
diff options
context:
space:
mode:
authorMaciej W. Rozycki <macro@imgtec.com>2016-01-22 05:20:46 +0000
committerRalf Baechle <ralf@linux-mips.org>2016-01-24 01:35:46 +0100
commit733b8bc183f491e8263009edf8ef184fb44a6882 (patch)
tree66645e3de66dd678e42db66113be76c21a0c766a /arch/mips/math-emu/dsemul.c
parenta87265cfedce49fa362030ae3e6ef047e08bc12c (diff)
MIPS: math-emu: Make microMIPS branch delay slot emulation work
Complement commit 102cedc32a6e ("MIPS: microMIPS: Floating point support.") which introduced microMIPS FPU emulation, but did not adjust the encoding of the BREAK instruction used to terminate the branch delay slot emulation frame. Consequently the execution of any such frame is indeterminate and, depending on CPU configuration, will result in random code execution or an offending program being terminated with SIGILL. This is because the regular MIPS BREAK instruction is encoded with the 0 major and the 0xd minor opcode, however in the microMIPS instruction set this major/minor opcode pair denotes an encoding reserved for the DSP ASE. Instead the microMIPS BREAK instruction is encoded with the 0 major and the 0x7 minor opcode. Use the correct BREAK encoding for microMIPS FPU emulation then. Signed-off-by: Maciej W. Rozycki <macro@imgtec.com> Cc: Aurelien Jarno <aurelien@aurel32.net> Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/12174/ Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Diffstat (limited to 'arch/mips/math-emu/dsemul.c')
-rw-r--r--arch/mips/math-emu/dsemul.c11
1 files changed, 7 insertions, 4 deletions
diff --git a/arch/mips/math-emu/dsemul.c b/arch/mips/math-emu/dsemul.c
index 4e30bfc3cdd5..32ec5d7e1728 100644
--- a/arch/mips/math-emu/dsemul.c
+++ b/arch/mips/math-emu/dsemul.c
@@ -38,6 +38,7 @@ struct emuframe {
*/
int mips_dsemul(struct pt_regs *regs, mips_instruction ir, unsigned long cpc)
{
+ mips_instruction break_math;
struct emuframe __user *fr;
int err;
@@ -65,6 +66,7 @@ int mips_dsemul(struct pt_regs *regs, mips_instruction ir, unsigned long cpc)
* branches, but gives us a cleaner interface to the exception
* handler (single entry point).
*/
+ break_math = BREAK_MATH(get_isa16_mode(regs->cp0_epc));
/* Ensure that the two instructions are in the same cache line */
fr = (struct emuframe __user *)
@@ -79,13 +81,13 @@ int mips_dsemul(struct pt_regs *regs, mips_instruction ir, unsigned long cpc)
(u16 __user *)(&fr->emul));
err |= __put_user(ir & 0xffff,
(u16 __user *)((long)(&fr->emul) + 2));
- err |= __put_user(BREAK_MATH >> 16,
+ err |= __put_user(break_math >> 16,
(u16 __user *)(&fr->badinst));
- err |= __put_user(BREAK_MATH & 0xffff,
+ err |= __put_user(break_math & 0xffff,
(u16 __user *)((long)(&fr->badinst) + 2));
} else {
err = __put_user(ir, &fr->emul);
- err |= __put_user((mips_instruction)BREAK_MATH, &fr->badinst);
+ err |= __put_user(break_math, &fr->badinst);
}
err |= __put_user((mips_instruction)BD_COOKIE, &fr->cookie);
@@ -139,7 +141,8 @@ int do_dsemulret(struct pt_regs *xcp)
}
err |= __get_user(cookie, &fr->cookie);
- if (unlikely(err || (insn != BREAK_MATH) || (cookie != BD_COOKIE))) {
+ if (unlikely(err || insn != BREAK_MATH(get_isa16_mode(xcp->cp0_epc)) ||
+ cookie != BD_COOKIE)) {
MIPS_FPU_EMU_INC_STATS(errors);
return 0;
}