diff options
| author | Leonid Yegoshin <Leonid.Yegoshin@imgtec.com> | 2014-12-03 10:47:03 -0500 |
|---|---|---|
| committer | Markos Chandras <markos.chandras@imgtec.com> | 2015-02-17 10:37:37 -0500 |
| commit | b0a668fb2038d846a466c7a16a358d874002b697 (patch) | |
| tree | 78e1a41109308a34e08dd552ddf6834f085d288c /arch/mips/include | |
| parent | b55b9e271544a23ca23b7ca3a87baf6329fcb341 (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/include')
| -rw-r--r-- | arch/mips/include/asm/branch.h | 3 | ||||
| -rw-r--r-- | arch/mips/include/asm/mips-r2-to-r6-emul.h | 96 |
2 files changed, 96 insertions, 3 deletions
diff --git a/arch/mips/include/asm/branch.h b/arch/mips/include/asm/branch.h index 2894ea58454d..de781cf54bc7 100644 --- a/arch/mips/include/asm/branch.h +++ b/arch/mips/include/asm/branch.h | |||
| @@ -13,9 +13,6 @@ | |||
| 13 | #include <asm/ptrace.h> | 13 | #include <asm/ptrace.h> |
| 14 | #include <asm/inst.h> | 14 | #include <asm/inst.h> |
| 15 | 15 | ||
| 16 | static int mipsr2_emulation = 0; | ||
| 17 | #define NO_R6EMU (cpu_has_mips_r6 && !mipsr2_emulation) | ||
| 18 | |||
| 19 | extern int __isa_exception_epc(struct pt_regs *regs); | 16 | extern int __isa_exception_epc(struct pt_regs *regs); |
| 20 | extern int __compute_return_epc(struct pt_regs *regs); | 17 | extern int __compute_return_epc(struct pt_regs *regs); |
| 21 | extern int __compute_return_epc_for_insn(struct pt_regs *regs, | 18 | extern int __compute_return_epc_for_insn(struct pt_regs *regs, |
diff --git a/arch/mips/include/asm/mips-r2-to-r6-emul.h b/arch/mips/include/asm/mips-r2-to-r6-emul.h new file mode 100644 index 000000000000..60570f2c3ba2 --- /dev/null +++ b/arch/mips/include/asm/mips-r2-to-r6-emul.h | |||
| @@ -0,0 +1,96 @@ | |||
| 1 | /* | ||
| 2 | * This file is subject to the terms and conditions of the GNU General Public | ||
| 3 | * License. See the file "COPYING" in the main directory of this archive | ||
| 4 | * for more details. | ||
| 5 | * | ||
| 6 | * Copyright (c) 2014 Imagination Technologies Ltd. | ||
| 7 | * Author: Markos Chandras <markos.chandras@imgtec.com> | ||
| 8 | */ | ||
| 9 | |||
| 10 | #ifndef __ASM_MIPS_R2_TO_R6_EMUL_H | ||
| 11 | #define __ASM_MIPS_R2_TO_R6_EMUL_H | ||
| 12 | |||
| 13 | struct mips_r2_emulator_stats { | ||
| 14 | u64 movs; | ||
| 15 | u64 hilo; | ||
| 16 | u64 muls; | ||
| 17 | u64 divs; | ||
| 18 | u64 dsps; | ||
| 19 | u64 bops; | ||
| 20 | u64 traps; | ||
| 21 | u64 fpus; | ||
| 22 | u64 loads; | ||
| 23 | u64 stores; | ||
| 24 | u64 llsc; | ||
| 25 | u64 dsemul; | ||
| 26 | }; | ||
| 27 | |||
| 28 | struct mips_r2br_emulator_stats { | ||
| 29 | u64 jrs; | ||
| 30 | u64 bltzl; | ||
| 31 | u64 bgezl; | ||
| 32 | u64 bltzll; | ||
| 33 | u64 bgezll; | ||
| 34 | u64 bltzall; | ||
| 35 | u64 bgezall; | ||
| 36 | u64 bltzal; | ||
| 37 | u64 bgezal; | ||
| 38 | u64 beql; | ||
| 39 | u64 bnel; | ||
| 40 | u64 blezl; | ||
| 41 | u64 bgtzl; | ||
| 42 | }; | ||
| 43 | |||
| 44 | #ifdef CONFIG_DEBUG_FS | ||
| 45 | |||
| 46 | #define MIPS_R2_STATS(M) \ | ||
| 47 | do { \ | ||
| 48 | u32 nir; \ | ||
| 49 | int err; \ | ||
| 50 | \ | ||
| 51 | preempt_disable(); \ | ||
| 52 | __this_cpu_inc(mipsr2emustats.M); \ | ||
| 53 | err = __get_user(nir, (u32 __user *)regs->cp0_epc); \ | ||
| 54 | if (!err) { \ | ||
| 55 | if (nir == BREAK_MATH) \ | ||
| 56 | __this_cpu_inc(mipsr2bdemustats.M); \ | ||
| 57 | } \ | ||
| 58 | preempt_enable(); \ | ||
| 59 | } while (0) | ||
| 60 | |||
| 61 | #define MIPS_R2BR_STATS(M) \ | ||
| 62 | do { \ | ||
| 63 | preempt_disable(); \ | ||
| 64 | __this_cpu_inc(mipsr2bremustats.M); \ | ||
| 65 | preempt_enable(); \ | ||
| 66 | } while (0) | ||
| 67 | |||
| 68 | #else | ||
| 69 | |||
| 70 | #define MIPS_R2_STATS(M) do { } while (0) | ||
| 71 | #define MIPS_R2BR_STATS(M) do { } while (0) | ||
| 72 | |||
| 73 | #endif /* CONFIG_DEBUG_FS */ | ||
| 74 | |||
| 75 | struct r2_decoder_table { | ||
| 76 | u32 mask; | ||
| 77 | u32 code; | ||
| 78 | int (*func)(struct pt_regs *regs, u32 inst); | ||
| 79 | }; | ||
| 80 | |||
| 81 | |||
| 82 | extern void do_trap_or_bp(struct pt_regs *regs, unsigned int code, | ||
| 83 | const char *str); | ||
| 84 | |||
| 85 | #ifndef CONFIG_MIPSR2_TO_R6_EMULATOR | ||
| 86 | static int mipsr2_emulation; | ||
| 87 | static __maybe_unused int mipsr2_decoder(struct pt_regs *regs, u32 inst) { return 0; }; | ||
| 88 | #else | ||
| 89 | /* MIPS R2 Emulator ON/OFF */ | ||
| 90 | extern int mipsr2_emulation; | ||
| 91 | extern int mipsr2_decoder(struct pt_regs *regs, u32 inst); | ||
| 92 | #endif /* CONFIG_MIPSR2_TO_R6_EMULATOR */ | ||
| 93 | |||
| 94 | #define NO_R6EMU (cpu_has_mips_r6 && !mipsr2_emulation) | ||
| 95 | |||
| 96 | #endif /* __ASM_MIPS_R2_TO_R6_EMUL_H */ | ||
