]> git.karo-electronics.de Git - karo-tx-linux.git/blob - arch/mips/kernel/branch.c
MIPS: microMIPS: Support handling of delay slots.
[karo-tx-linux.git] / arch / mips / kernel / branch.c
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) 1996, 97, 2000, 2001 by Ralf Baechle
7  * Copyright (C) 2001 MIPS Technologies, Inc.
8  */
9 #include <linux/kernel.h>
10 #include <linux/sched.h>
11 #include <linux/signal.h>
12 #include <linux/module.h>
13 #include <asm/branch.h>
14 #include <asm/cpu.h>
15 #include <asm/cpu-features.h>
16 #include <asm/fpu.h>
17 #include <asm/fpu_emulator.h>
18 #include <asm/inst.h>
19 #include <asm/ptrace.h>
20 #include <asm/uaccess.h>
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  */
26 int __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  */
52 int __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
99 sigsegv:
100         force_sig(SIGSEGV, current);
101         return -EFAULT;
102 }
103
104 /**
105  * __compute_return_epc_for_insn - Computes the return address and do emulate
106  *                                  branch simulation, if required.
107  *
108  * @regs:       Pointer to pt_regs
109  * @insn:       branch instruction to decode
110  * @returns:    -EFAULT on error and forces SIGBUS, and on success
111  *              returns 0 or BRANCH_LIKELY_TAKEN as appropriate after
112  *              evaluating the branch.
113  */
114 int __compute_return_epc_for_insn(struct pt_regs *regs,
115                                    union mips_instruction insn)
116 {
117         unsigned int bit, fcr31, dspcontrol;
118         long epc = regs->cp0_epc;
119         int ret = 0;
120
121         switch (insn.i_format.opcode) {
122         /*
123          * jr and jalr are in r_format format.
124          */
125         case spec_op:
126                 switch (insn.r_format.func) {
127                 case jalr_op:
128                         regs->regs[insn.r_format.rd] = epc + 8;
129                         /* Fall through */
130                 case jr_op:
131                         regs->cp0_epc = regs->regs[insn.r_format.rs];
132                         break;
133                 }
134                 break;
135
136         /*
137          * This group contains:
138          * bltz_op, bgez_op, bltzl_op, bgezl_op,
139          * bltzal_op, bgezal_op, bltzall_op, bgezall_op.
140          */
141         case bcond_op:
142                 switch (insn.i_format.rt) {
143                 case bltz_op:
144                 case bltzl_op:
145                         if ((long)regs->regs[insn.i_format.rs] < 0) {
146                                 epc = epc + 4 + (insn.i_format.simmediate << 2);
147                                 if (insn.i_format.rt == bltzl_op)
148                                         ret = BRANCH_LIKELY_TAKEN;
149                         } else
150                                 epc += 8;
151                         regs->cp0_epc = epc;
152                         break;
153
154                 case bgez_op:
155                 case bgezl_op:
156                         if ((long)regs->regs[insn.i_format.rs] >= 0) {
157                                 epc = epc + 4 + (insn.i_format.simmediate << 2);
158                                 if (insn.i_format.rt == bgezl_op)
159                                         ret = BRANCH_LIKELY_TAKEN;
160                         } else
161                                 epc += 8;
162                         regs->cp0_epc = epc;
163                         break;
164
165                 case bltzal_op:
166                 case bltzall_op:
167                         regs->regs[31] = epc + 8;
168                         if ((long)regs->regs[insn.i_format.rs] < 0) {
169                                 epc = epc + 4 + (insn.i_format.simmediate << 2);
170                                 if (insn.i_format.rt == bltzall_op)
171                                         ret = BRANCH_LIKELY_TAKEN;
172                         } else
173                                 epc += 8;
174                         regs->cp0_epc = epc;
175                         break;
176
177                 case bgezal_op:
178                 case bgezall_op:
179                         regs->regs[31] = epc + 8;
180                         if ((long)regs->regs[insn.i_format.rs] >= 0) {
181                                 epc = epc + 4 + (insn.i_format.simmediate << 2);
182                                 if (insn.i_format.rt == bgezall_op)
183                                         ret = BRANCH_LIKELY_TAKEN;
184                         } else
185                                 epc += 8;
186                         regs->cp0_epc = epc;
187                         break;
188
189                 case bposge32_op:
190                         if (!cpu_has_dsp)
191                                 goto sigill;
192
193                         dspcontrol = rddsp(0x01);
194
195                         if (dspcontrol >= 32) {
196                                 epc = epc + 4 + (insn.i_format.simmediate << 2);
197                         } else
198                                 epc += 8;
199                         regs->cp0_epc = epc;
200                         break;
201                 }
202                 break;
203
204         /*
205          * These are unconditional and in j_format.
206          */
207         case jal_op:
208                 regs->regs[31] = regs->cp0_epc + 8;
209         case j_op:
210                 epc += 4;
211                 epc >>= 28;
212                 epc <<= 28;
213                 epc |= (insn.j_format.target << 2);
214                 regs->cp0_epc = epc;
215                 if (insn.i_format.opcode == jalx_op)
216                         set_isa16_mode(regs->cp0_epc);
217                 break;
218
219         /*
220          * These are conditional and in i_format.
221          */
222         case beq_op:
223         case beql_op:
224                 if (regs->regs[insn.i_format.rs] ==
225                     regs->regs[insn.i_format.rt]) {
226                         epc = epc + 4 + (insn.i_format.simmediate << 2);
227                         if (insn.i_format.rt == beql_op)
228                                 ret = BRANCH_LIKELY_TAKEN;
229                 } else
230                         epc += 8;
231                 regs->cp0_epc = epc;
232                 break;
233
234         case bne_op:
235         case bnel_op:
236                 if (regs->regs[insn.i_format.rs] !=
237                     regs->regs[insn.i_format.rt]) {
238                         epc = epc + 4 + (insn.i_format.simmediate << 2);
239                         if (insn.i_format.rt == bnel_op)
240                                 ret = BRANCH_LIKELY_TAKEN;
241                 } else
242                         epc += 8;
243                 regs->cp0_epc = epc;
244                 break;
245
246         case blez_op: /* not really i_format */
247         case blezl_op:
248                 /* rt field assumed to be zero */
249                 if ((long)regs->regs[insn.i_format.rs] <= 0) {
250                         epc = epc + 4 + (insn.i_format.simmediate << 2);
251                         if (insn.i_format.rt == bnel_op)
252                                 ret = BRANCH_LIKELY_TAKEN;
253                 } else
254                         epc += 8;
255                 regs->cp0_epc = epc;
256                 break;
257
258         case bgtz_op:
259         case bgtzl_op:
260                 /* rt field assumed to be zero */
261                 if ((long)regs->regs[insn.i_format.rs] > 0) {
262                         epc = epc + 4 + (insn.i_format.simmediate << 2);
263                         if (insn.i_format.rt == bnel_op)
264                                 ret = BRANCH_LIKELY_TAKEN;
265                 } else
266                         epc += 8;
267                 regs->cp0_epc = epc;
268                 break;
269
270         /*
271          * And now the FPA/cp1 branch instructions.
272          */
273         case cop1_op:
274                 preempt_disable();
275                 if (is_fpu_owner())
276                         asm volatile("cfc1\t%0,$31" : "=r" (fcr31));
277                 else
278                         fcr31 = current->thread.fpu.fcr31;
279                 preempt_enable();
280
281                 bit = (insn.i_format.rt >> 2);
282                 bit += (bit != 0);
283                 bit += 23;
284                 switch (insn.i_format.rt & 3) {
285                 case 0: /* bc1f */
286                 case 2: /* bc1fl */
287                         if (~fcr31 & (1 << bit)) {
288                                 epc = epc + 4 + (insn.i_format.simmediate << 2);
289                                 if (insn.i_format.rt == 2)
290                                         ret = BRANCH_LIKELY_TAKEN;
291                         } else
292                                 epc += 8;
293                         regs->cp0_epc = epc;
294                         break;
295
296                 case 1: /* bc1t */
297                 case 3: /* bc1tl */
298                         if (fcr31 & (1 << bit)) {
299                                 epc = epc + 4 + (insn.i_format.simmediate << 2);
300                                 if (insn.i_format.rt == 3)
301                                         ret = BRANCH_LIKELY_TAKEN;
302                         } else
303                                 epc += 8;
304                         regs->cp0_epc = epc;
305                         break;
306                 }
307                 break;
308 #ifdef CONFIG_CPU_CAVIUM_OCTEON
309         case lwc2_op: /* This is bbit0 on Octeon */
310                 if ((regs->regs[insn.i_format.rs] & (1ull<<insn.i_format.rt))
311                      == 0)
312                         epc = epc + 4 + (insn.i_format.simmediate << 2);
313                 else
314                         epc += 8;
315                 regs->cp0_epc = epc;
316                 break;
317         case ldc2_op: /* This is bbit032 on Octeon */
318                 if ((regs->regs[insn.i_format.rs] &
319                     (1ull<<(insn.i_format.rt+32))) == 0)
320                         epc = epc + 4 + (insn.i_format.simmediate << 2);
321                 else
322                         epc += 8;
323                 regs->cp0_epc = epc;
324                 break;
325         case swc2_op: /* This is bbit1 on Octeon */
326                 if (regs->regs[insn.i_format.rs] & (1ull<<insn.i_format.rt))
327                         epc = epc + 4 + (insn.i_format.simmediate << 2);
328                 else
329                         epc += 8;
330                 regs->cp0_epc = epc;
331                 break;
332         case sdc2_op: /* This is bbit132 on Octeon */
333                 if (regs->regs[insn.i_format.rs] &
334                     (1ull<<(insn.i_format.rt+32)))
335                         epc = epc + 4 + (insn.i_format.simmediate << 2);
336                 else
337                         epc += 8;
338                 regs->cp0_epc = epc;
339                 break;
340 #endif
341         }
342
343         return ret;
344
345 sigill:
346         printk("%s: DSP branch but not DSP ASE - sending SIGBUS.\n", current->comm);
347         force_sig(SIGBUS, current);
348         return -EFAULT;
349 }
350 EXPORT_SYMBOL_GPL(__compute_return_epc_for_insn);
351
352 int __compute_return_epc(struct pt_regs *regs)
353 {
354         unsigned int __user *addr;
355         long epc;
356         union mips_instruction insn;
357
358         epc = regs->cp0_epc;
359         if (epc & 3)
360                 goto unaligned;
361
362         /*
363          * Read the instruction
364          */
365         addr = (unsigned int __user *) epc;
366         if (__get_user(insn.word, addr)) {
367                 force_sig(SIGSEGV, current);
368                 return -EFAULT;
369         }
370
371         return __compute_return_epc_for_insn(regs, insn);
372
373 unaligned:
374         printk("%s: unaligned epc - sending SIGBUS.\n", current->comm);
375         force_sig(SIGBUS, current);
376         return -EFAULT;
377
378 }