aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips/kernel
diff options
context:
space:
mode:
authorLeonid Yegoshin <Leonid.Yegoshin@imgtec.com>2013-03-25 14:08:40 -0400
committerRalf Baechle <ralf@linux-mips.org>2013-05-09 11:55:18 -0400
commitfb6883e5809c08e43de23581759af4570ca91b0f (patch)
tree2bf479748d969f85c79cb8880a1573b2ca7c61ee /arch/mips/kernel
parent2a0b24f56c2492b932f1aed617ae80fb23500d21 (diff)
MIPS: microMIPS: Support handling of delay slots.
Add logic needed to properly calculate exceptions for delay slots when 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/kernel')
-rw-r--r--arch/mips/kernel/branch.c85
1 files changed, 85 insertions, 0 deletions
diff --git a/arch/mips/kernel/branch.c b/arch/mips/kernel/branch.c
index 83ffe950f710..a03836b5b683 100644
--- a/arch/mips/kernel/branch.c
+++ b/arch/mips/kernel/branch.c
@@ -14,10 +14,93 @@
14#include <asm/cpu.h> 14#include <asm/cpu.h>
15#include <asm/cpu-features.h> 15#include <asm/cpu-features.h>
16#include <asm/fpu.h> 16#include <asm/fpu.h>
17#include <asm/fpu_emulator.h>
17#include <asm/inst.h> 18#include <asm/inst.h>
18#include <asm/ptrace.h> 19#include <asm/ptrace.h>
19#include <asm/uaccess.h> 20#include <asm/uaccess.h>
20 21
22/*
23 * Calculate and return exception PC in case of branch delay
24 * slot for microMIPS. It does not clear the ISA mode bit.
25 */
26int __isa_exception_epc(struct pt_regs *regs)
27{
28 long epc = regs->cp0_epc;
29 unsigned short inst;
30
31 /* Calculate exception PC in branch delay slot. */
32 if (__get_user(inst, (u16 __user *) msk_isa16_mode(epc))) {
33 /* This should never happen because delay slot was checked. */
34 force_sig(SIGSEGV, current);
35 return epc;
36 }
37
38 if (mm_insn_16bit(inst))
39 epc += 2;
40 else
41 epc += 4;
42
43 return epc;
44}
45
46/*
47 * Compute return address and emulate branch in microMIPS mode after an
48 * exception only. It does not handle compact branches/jumps and cannot
49 * be used in interrupt context. (Compact branches/jumps do not cause
50 * exceptions.)
51 */
52int __microMIPS_compute_return_epc(struct pt_regs *regs)
53{
54 u16 __user *pc16;
55 u16 halfword;
56 unsigned int word;
57 unsigned long contpc;
58 struct mm_decoded_insn mminsn = { 0 };
59
60 mminsn.micro_mips_mode = 1;
61
62 /* This load never faults. */
63 pc16 = (unsigned short __user *)msk_isa16_mode(regs->cp0_epc);
64 __get_user(halfword, pc16);
65 pc16++;
66 contpc = regs->cp0_epc + 2;
67 word = ((unsigned int)halfword << 16);
68 mminsn.pc_inc = 2;
69
70 if (!mm_insn_16bit(halfword)) {
71 __get_user(halfword, pc16);
72 pc16++;
73 contpc = regs->cp0_epc + 4;
74 mminsn.pc_inc = 4;
75 word |= halfword;
76 }
77 mminsn.insn = word;
78
79 if (get_user(halfword, pc16))
80 goto sigsegv;
81 mminsn.next_pc_inc = 2;
82 word = ((unsigned int)halfword << 16);
83
84 if (!mm_insn_16bit(halfword)) {
85 pc16++;
86 if (get_user(halfword, pc16))
87 goto sigsegv;
88 mminsn.next_pc_inc = 4;
89 word |= halfword;
90 }
91 mminsn.next_insn = word;
92
93 mm_isBranchInstr(regs, mminsn, &contpc);
94
95 regs->cp0_epc = contpc;
96
97 return 0;
98
99sigsegv:
100 force_sig(SIGSEGV, current);
101 return -EFAULT;
102}
103
21/** 104/**
22 * __compute_return_epc_for_insn - Computes the return address and do emulate 105 * __compute_return_epc_for_insn - Computes the return address and do emulate
23 * branch simulation, if required. 106 * branch simulation, if required.
@@ -129,6 +212,8 @@ int __compute_return_epc_for_insn(struct pt_regs *regs,
129 epc <<= 28; 212 epc <<= 28;
130 epc |= (insn.j_format.target << 2); 213 epc |= (insn.j_format.target << 2);
131 regs->cp0_epc = epc; 214 regs->cp0_epc = epc;
215 if (insn.i_format.opcode == jalx_op)
216 set_isa16_mode(regs->cp0_epc);
132 break; 217 break;
133 218
134 /* 219 /*