diff options
author | Markos Chandras <markos.chandras@imgtec.com> | 2014-11-25 10:54:14 -0500 |
---|---|---|
committer | Markos Chandras <markos.chandras@imgtec.com> | 2015-02-17 10:37:31 -0500 |
commit | 5f9f41c474befb4ebbc40b27f65bb7d649241581 (patch) | |
tree | 26108ad80ca556ac12466aac3f03fc29d0a8a4ca /arch/mips | |
parent | b5ad2c21934951bbf6aadd8adbdd9889baad0ac0 (diff) |
MIPS: kernel: Prepare the JR instruction for emulation on MIPS R6
The MIPS R6 JR instruction is an alias to the JALR one, so it may
need emulation for non-R6 userlands.
Signed-off-by: Markos Chandras <markos.chandras@imgtec.com>
Diffstat (limited to 'arch/mips')
-rw-r--r-- | arch/mips/include/asm/branch.h | 3 | ||||
-rw-r--r-- | arch/mips/kernel/branch.c | 11 | ||||
-rw-r--r-- | arch/mips/math-emu/cp1emu.c | 3 |
3 files changed, 15 insertions, 2 deletions
diff --git a/arch/mips/include/asm/branch.h b/arch/mips/include/asm/branch.h index de781cf54bc7..2894ea58454d 100644 --- a/arch/mips/include/asm/branch.h +++ b/arch/mips/include/asm/branch.h | |||
@@ -13,6 +13,9 @@ | |||
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 | |||
16 | extern int __isa_exception_epc(struct pt_regs *regs); | 19 | extern int __isa_exception_epc(struct pt_regs *regs); |
17 | extern int __compute_return_epc(struct pt_regs *regs); | 20 | extern int __compute_return_epc(struct pt_regs *regs); |
18 | extern int __compute_return_epc_for_insn(struct pt_regs *regs, | 21 | extern int __compute_return_epc_for_insn(struct pt_regs *regs, |
diff --git a/arch/mips/kernel/branch.c b/arch/mips/kernel/branch.c index 4d7d99d601cc..5736949896d1 100644 --- a/arch/mips/kernel/branch.c +++ b/arch/mips/kernel/branch.c | |||
@@ -417,6 +417,8 @@ int __compute_return_epc_for_insn(struct pt_regs *regs, | |||
417 | regs->regs[insn.r_format.rd] = epc + 8; | 417 | regs->regs[insn.r_format.rd] = epc + 8; |
418 | /* Fall through */ | 418 | /* Fall through */ |
419 | case jr_op: | 419 | case jr_op: |
420 | if (NO_R6EMU && insn.r_format.func == jr_op) | ||
421 | goto sigill_r6; | ||
420 | regs->cp0_epc = regs->regs[insn.r_format.rs]; | 422 | regs->cp0_epc = regs->regs[insn.r_format.rs]; |
421 | break; | 423 | break; |
422 | } | 424 | } |
@@ -477,7 +479,7 @@ int __compute_return_epc_for_insn(struct pt_regs *regs, | |||
477 | 479 | ||
478 | case bposge32_op: | 480 | case bposge32_op: |
479 | if (!cpu_has_dsp) | 481 | if (!cpu_has_dsp) |
480 | goto sigill; | 482 | goto sigill_dsp; |
481 | 483 | ||
482 | dspcontrol = rddsp(0x01); | 484 | dspcontrol = rddsp(0x01); |
483 | 485 | ||
@@ -631,10 +633,15 @@ int __compute_return_epc_for_insn(struct pt_regs *regs, | |||
631 | 633 | ||
632 | return ret; | 634 | return ret; |
633 | 635 | ||
634 | sigill: | 636 | sigill_dsp: |
635 | printk("%s: DSP branch but not DSP ASE - sending SIGBUS.\n", current->comm); | 637 | printk("%s: DSP branch but not DSP ASE - sending SIGBUS.\n", current->comm); |
636 | force_sig(SIGBUS, current); | 638 | force_sig(SIGBUS, current); |
637 | return -EFAULT; | 639 | return -EFAULT; |
640 | sigill_r6: | ||
641 | pr_info("%s: R2 branch but r2-to-r6 emulator is not preset - sending SIGILL.\n", | ||
642 | current->comm); | ||
643 | force_sig(SIGILL, current); | ||
644 | return -EFAULT; | ||
638 | } | 645 | } |
639 | EXPORT_SYMBOL_GPL(__compute_return_epc_for_insn); | 646 | EXPORT_SYMBOL_GPL(__compute_return_epc_for_insn); |
640 | 647 | ||
diff --git a/arch/mips/math-emu/cp1emu.c b/arch/mips/math-emu/cp1emu.c index 9dfcd7fc1bc3..9bf82117b4f2 100644 --- a/arch/mips/math-emu/cp1emu.c +++ b/arch/mips/math-emu/cp1emu.c | |||
@@ -448,6 +448,9 @@ static int isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn, | |||
448 | dec_insn.next_pc_inc; | 448 | dec_insn.next_pc_inc; |
449 | /* Fall through */ | 449 | /* Fall through */ |
450 | case jr_op: | 450 | case jr_op: |
451 | /* For R6, JR already emulated in jalr_op */ | ||
452 | if (NO_R6EMU && insn.r_format.opcode == jr_op) | ||
453 | break; | ||
451 | *contpc = regs->regs[insn.r_format.rs]; | 454 | *contpc = regs->regs[insn.r_format.rs]; |
452 | return 1; | 455 | return 1; |
453 | } | 456 | } |