Skip to content

Commit

Permalink
MIPS: kernel: mips-r2-to-r6-emul: Add R2 emulator for MIPS R6
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Leonid Yegoshin authored and Markos Chandras committed Feb 17, 2015
1 parent b55b9e2 commit b0a668f
Show file tree
Hide file tree
Showing 8 changed files with 2,518 additions and 5 deletions.
13 changes: 13 additions & 0 deletions arch/mips/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -2063,6 +2063,19 @@ config MIPS_MT_FPAFF
default y
depends on MIPS_MT_SMP

config MIPSR2_TO_R6_EMULATOR
bool "MIPS R2-to-R6 emulator"
depends on CPU_MIPSR6 && !SMP
default y
help
Choose this option if you want to run non-R6 MIPS userland code.
Even if you say 'Y' here, the emulator will still be disabled by
default. You can enable it using the 'mipsr2emul' kernel option.
The only reason this is a build-time option is to save ~14K from the
final kernel image.
comment "MIPS R2-to-R6 emulator is only available for UP kernels"
depends on SMP && CPU_MIPSR6

config MIPS_VPE_LOADER
bool "VPE loader support."
depends on SYS_SUPPORTS_MULTITHREADING && MODULES
Expand Down
3 changes: 0 additions & 3 deletions arch/mips/include/asm/branch.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,6 @@
#include <asm/ptrace.h>
#include <asm/inst.h>

static int mipsr2_emulation = 0;
#define NO_R6EMU (cpu_has_mips_r6 && !mipsr2_emulation)

extern int __isa_exception_epc(struct pt_regs *regs);
extern int __compute_return_epc(struct pt_regs *regs);
extern int __compute_return_epc_for_insn(struct pt_regs *regs,
Expand Down
96 changes: 96 additions & 0 deletions arch/mips/include/asm/mips-r2-to-r6-emul.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
/*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
* Copyright (c) 2014 Imagination Technologies Ltd.
* Author: Markos Chandras <markos.chandras@imgtec.com>
*/

#ifndef __ASM_MIPS_R2_TO_R6_EMUL_H
#define __ASM_MIPS_R2_TO_R6_EMUL_H

struct mips_r2_emulator_stats {
u64 movs;
u64 hilo;
u64 muls;
u64 divs;
u64 dsps;
u64 bops;
u64 traps;
u64 fpus;
u64 loads;
u64 stores;
u64 llsc;
u64 dsemul;
};

struct mips_r2br_emulator_stats {
u64 jrs;
u64 bltzl;
u64 bgezl;
u64 bltzll;
u64 bgezll;
u64 bltzall;
u64 bgezall;
u64 bltzal;
u64 bgezal;
u64 beql;
u64 bnel;
u64 blezl;
u64 bgtzl;
};

#ifdef CONFIG_DEBUG_FS

#define MIPS_R2_STATS(M) \
do { \
u32 nir; \
int err; \
\
preempt_disable(); \
__this_cpu_inc(mipsr2emustats.M); \
err = __get_user(nir, (u32 __user *)regs->cp0_epc); \
if (!err) { \
if (nir == BREAK_MATH) \
__this_cpu_inc(mipsr2bdemustats.M); \
} \
preempt_enable(); \
} while (0)

#define MIPS_R2BR_STATS(M) \
do { \
preempt_disable(); \
__this_cpu_inc(mipsr2bremustats.M); \
preempt_enable(); \
} while (0)

#else

#define MIPS_R2_STATS(M) do { } while (0)
#define MIPS_R2BR_STATS(M) do { } while (0)

#endif /* CONFIG_DEBUG_FS */

struct r2_decoder_table {
u32 mask;
u32 code;
int (*func)(struct pt_regs *regs, u32 inst);
};


extern void do_trap_or_bp(struct pt_regs *regs, unsigned int code,
const char *str);

#ifndef CONFIG_MIPSR2_TO_R6_EMULATOR
static int mipsr2_emulation;
static __maybe_unused int mipsr2_decoder(struct pt_regs *regs, u32 inst) { return 0; };
#else
/* MIPS R2 Emulator ON/OFF */
extern int mipsr2_emulation;
extern int mipsr2_decoder(struct pt_regs *regs, u32 inst);
#endif /* CONFIG_MIPSR2_TO_R6_EMULATOR */

#define NO_R6EMU (cpu_has_mips_r6 && !mipsr2_emulation)

#endif /* __ASM_MIPS_R2_TO_R6_EMUL_H */
1 change: 1 addition & 0 deletions arch/mips/kernel/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
obj-$(CONFIG_EARLY_PRINTK_8250) += early_printk_8250.o
obj-$(CONFIG_SPINLOCK_TEST) += spinlock_test.o
obj-$(CONFIG_MIPS_MACHINE) += mips_machine.o
obj-$(CONFIG_MIPSR2_TO_R6_EMULATOR) += mips-r2-to-r6-emul.o

CFLAGS_cpu-bugs64.o = $(shell if $(CC) $(KBUILD_CFLAGS) -Wa,-mdaddi -c -o /dev/null -x c /dev/null >/dev/null 2>&1; then echo "-DHAVE_AS_SET_DADDI"; fi)

Expand Down
1 change: 1 addition & 0 deletions arch/mips/kernel/branch.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include <asm/fpu.h>
#include <asm/fpu_emulator.h>
#include <asm/inst.h>
#include <asm/mips-r2-to-r6-emul.h>
#include <asm/ptrace.h>
#include <asm/uaccess.h>

Expand Down
Loading

0 comments on commit b0a668f

Please sign in to comment.