summaryrefslogtreecommitdiffstats
path: root/arch/mips/math-emu/dsemul.c
diff options
context:
space:
mode:
authorLeonid Yegoshin <Leonid.Yegoshin@imgtec.com>2013-03-25 18:09:02 +0100
committerRalf Baechle <ralf@linux-mips.org>2013-05-09 17:55:18 +0200
commit102cedc32a6e3cd537374a3678d407591d5a6fab (patch)
tree7a91493a82e65c0da845afb12020e1534d83ee5d /arch/mips/math-emu/dsemul.c
parentMIPS: microMIPS: Fix macro naming in micro-assembler. (diff)
downloadlinux-102cedc32a6e3cd537374a3678d407591d5a6fab.tar.xz
linux-102cedc32a6e3cd537374a3678d407591d5a6fab.zip
MIPS: microMIPS: Floating point support.
Add logic needed to do floating point emulation in microMIPS mode. Signed-off-by: Leonid Yegoshin <Leonid.Yegoshin@imgtec.com> Signed-off-by: Steven J. Hill <Steven. Hill@imgtec.com>
Diffstat (limited to 'arch/mips/math-emu/dsemul.c')
-rw-r--r--arch/mips/math-emu/dsemul.c30
1 files changed, 24 insertions, 6 deletions
diff --git a/arch/mips/math-emu/dsemul.c b/arch/mips/math-emu/dsemul.c
index 384a3b0091ea..7ea622ab8dad 100644
--- a/arch/mips/math-emu/dsemul.c
+++ b/arch/mips/math-emu/dsemul.c
@@ -55,7 +55,9 @@ int mips_dsemul(struct pt_regs *regs, mips_instruction ir, unsigned long cpc)
struct emuframe __user *fr;
int err;
- if (ir == 0) { /* a nop is easy */
+ if ((get_isa16_mode(regs->cp0_epc) && ((ir >> 16) == MM_NOP16)) ||
+ (ir == 0)) {
+ /* NOP is easy */
regs->cp0_epc = cpc;
regs->cp0_cause &= ~CAUSEF_BD;
return 0;
@@ -91,8 +93,16 @@ int mips_dsemul(struct pt_regs *regs, mips_instruction ir, unsigned long cpc)
if (unlikely(!access_ok(VERIFY_WRITE, fr, sizeof(struct emuframe))))
return SIGBUS;
- err = __put_user(ir, &fr->emul);
- err |= __put_user((mips_instruction)BREAK_MATH, &fr->badinst);
+ if (get_isa16_mode(regs->cp0_epc)) {
+ err = __put_user(ir >> 16, (u16 __user *)(&fr->emul));
+ err |= __put_user(ir & 0xffff, (u16 __user *)((long)(&fr->emul) + 2));
+ err |= __put_user(BREAK_MATH >> 16, (u16 __user *)(&fr->badinst));
+ 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((mips_instruction)BD_COOKIE, &fr->cookie);
err |= __put_user(cpc, &fr->epc);
@@ -101,7 +111,8 @@ int mips_dsemul(struct pt_regs *regs, mips_instruction ir, unsigned long cpc)
return SIGBUS;
}
- regs->cp0_epc = (unsigned long) &fr->emul;
+ regs->cp0_epc = ((unsigned long) &fr->emul) |
+ get_isa16_mode(regs->cp0_epc);
flush_cache_sigtramp((unsigned long)&fr->badinst);
@@ -114,9 +125,10 @@ int do_dsemulret(struct pt_regs *xcp)
unsigned long epc;
u32 insn, cookie;
int err = 0;
+ u16 instr[2];
fr = (struct emuframe __user *)
- (xcp->cp0_epc - sizeof(mips_instruction));
+ (msk_isa16_mode(xcp->cp0_epc) - sizeof(mips_instruction));
/*
* If we can't even access the area, something is very wrong, but we'll
@@ -131,7 +143,13 @@ int do_dsemulret(struct pt_regs *xcp)
* - 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);
+ if (get_isa16_mode(xcp->cp0_epc)) {
+ err = __get_user(instr[0], (u16 __user *)(&fr->badinst));
+ err |= __get_user(instr[1], (u16 __user *)((long)(&fr->badinst) + 2));
+ insn = (instr[0] << 16) | instr[1];
+ } else {
+ err = __get_user(insn, &fr->badinst);
+ }
err |= __get_user(cookie, &fr->cookie);
if (unlikely(err || (insn != BREAK_MATH) || (cookie != BD_COOKIE))) {