summaryrefslogtreecommitdiff
path: root/arch/mips/kernel/traps.c
diff options
context:
space:
mode:
authorLeonid Yegoshin <Leonid.Yegoshin@imgtec.com>2014-12-03 15:47:03 +0000
committerMarkos Chandras <markos.chandras@imgtec.com>2015-02-17 15:37:37 +0000
commitb0a668fb2038d846a466c7a16a358d874002b697 (patch)
tree78e1a41109308a34e08dd552ddf6834f085d288c /arch/mips/kernel/traps.c
parentb55b9e271544a23ca23b7ca3a87baf6329fcb341 (diff)
MIPS: kernel: mips-r2-to-r6-emul: Add R2 emulator for MIPS R6
MIPS R6 removed quite a few R2 instructions. However, there is plenty of <R6 userland code so we add an in-kernel emulator so we can still be able to execute all R2 userland out there. The emulator comes with a handy debugfs under /mips/ directory (r2-emul-stats) to provide some basic statistics of the instructions that are being emulated. Below are some statistics from booting a minimal buildroot image: Instruction Total BDslot ------------------------------ movs 236969 0 hilo 56686 0 muls 55279 0 divs 10941 0 dsps 0 0 bops 1 0 traps 0 0 fpus 0 0 loads 214981 17 stores 103364 0 llsc 56898 0 dsemul 150418 0 jr 370158 bltzl 43 bgezl 1594 bltzll 0 bgezll 0 bltzal 39 bgezal 39 beql 14503 bnel 138741 blezl 0 bgtzl 3988 Signed-off-by: Leonid Yegoshin <Leonid.Yegoshin@imgtec.com> Signed-off-by: Markos Chandras <markos.chandras@imgtec.com>
Diffstat (limited to 'arch/mips/kernel/traps.c')
-rw-r--r--arch/mips/kernel/traps.c28
1 files changed, 27 insertions, 1 deletions
diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c
index 6e9d8505e128..fc157322f609 100644
--- a/arch/mips/kernel/traps.c
+++ b/arch/mips/kernel/traps.c
@@ -46,6 +46,7 @@
#include <asm/fpu.h>
#include <asm/fpu_emulator.h>
#include <asm/idle.h>
+#include <asm/mips-r2-to-r6-emul.h>
#include <asm/mipsregs.h>
#include <asm/mipsmtregs.h>
#include <asm/module.h>
@@ -837,7 +838,7 @@ out:
exception_exit(prev_state);
}
-static void do_trap_or_bp(struct pt_regs *regs, unsigned int code,
+void do_trap_or_bp(struct pt_regs *regs, unsigned int code,
const char *str)
{
siginfo_t info;
@@ -1027,7 +1028,32 @@ asmlinkage void do_ri(struct pt_regs *regs)
unsigned int opcode = 0;
int status = -1;
+ /*
+ * Avoid any kernel code. Just emulate the R2 instruction
+ * as quickly as possible.
+ */
+ if (mipsr2_emulation && cpu_has_mips_r6 &&
+ likely(user_mode(regs))) {
+ if (likely(get_user(opcode, epc) >= 0)) {
+ status = mipsr2_decoder(regs, opcode);
+ switch (status) {
+ case 0:
+ case SIGEMT:
+ return;
+ case SIGILL:
+ goto no_r2_instr;
+ default:
+ process_fpemu_return(status,
+ &current->thread.cp0_baduaddr);
+ return;
+ }
+ }
+ }
+
+no_r2_instr:
+
prev_state = exception_enter();
+
if (notify_die(DIE_RI, "RI Fault", regs, 0, regs_to_trapnr(regs),
SIGILL) == NOTIFY_STOP)
goto out;