import of upstream 2.4.34.4 from kernel.org
[linux-2.4.git] / arch / mips / kernel / branch.c
1 /*
2  * Branch and jump emulation.
3  *
4  * This file is subject to the terms and conditions of the GNU General Public
5  * License.  See the file "COPYING" in the main directory of this archive
6  * for more details.
7  *
8  * Copyright (C) 1996, 97, 2000, 2001 by Ralf Baechle
9  * Copyright (C) 2001 MIPS Technologies, Inc.
10  */
11 #include <linux/kernel.h>
12 #include <linux/sched.h>
13 #include <linux/signal.h>
14 #include <asm/branch.h>
15 #include <asm/cpu.h>
16 #include <asm/inst.h>
17 #include <asm/ptrace.h>
18 #include <asm/uaccess.h>
19 #include <asm/processor.h>
20
21 /*
22  * Compute the return address and do emulate branch simulation, if required.
23  */
24 int __compute_return_epc(struct pt_regs *regs)
25 {
26         unsigned int *addr, bit, fcr31;
27         long epc;
28         union mips_instruction insn;
29
30         epc = regs->cp0_epc;
31         if (epc & 3)
32                 goto unaligned;
33
34         /*
35          * Read the instruction
36          */
37         addr = (unsigned int *) (unsigned long) epc;
38         if (__get_user(insn.word, addr)) {
39                 force_sig(SIGSEGV, current);
40                 return -EFAULT;
41         }
42
43         regs->regs[0] = 0;
44         switch (insn.i_format.opcode) {
45         /*
46          * jr and jalr are in r_format format.
47          */
48         case spec_op:
49                 switch (insn.r_format.func) {
50                 case jalr_op:
51                         regs->regs[insn.r_format.rd] = epc + 8;
52                         /* Fall through */
53                 case jr_op:
54                         regs->cp0_epc = regs->regs[insn.r_format.rs];
55                         break;
56                 }
57                 break;
58
59         /*
60          * This group contains:
61          * bltz_op, bgez_op, bltzl_op, bgezl_op,
62          * bltzal_op, bgezal_op, bltzall_op, bgezall_op.
63          */
64         case bcond_op:
65                 switch (insn.i_format.rt) {
66                 case bltz_op:
67                 case bltzl_op:
68                         if ((long)regs->regs[insn.i_format.rs] < 0)
69                                 epc = epc + 4 + (insn.i_format.simmediate << 2);
70                         else
71                                 epc += 8;
72                         regs->cp0_epc = epc;
73                         break;
74
75                 case bgez_op:
76                 case bgezl_op:
77                         if ((long)regs->regs[insn.i_format.rs] >= 0)
78                                 epc = epc + 4 + (insn.i_format.simmediate << 2);
79                         else
80                                 epc += 8;
81                         regs->cp0_epc = epc;
82                         break;
83
84                 case bltzal_op:
85                 case bltzall_op:
86                         regs->regs[31] = epc + 8;
87                         if ((long)regs->regs[insn.i_format.rs] < 0)
88                                 epc = epc + 4 + (insn.i_format.simmediate << 2);
89                         else
90                                 epc += 8;
91                         regs->cp0_epc = epc;
92                         break;
93
94                 case bgezal_op:
95                 case bgezall_op:
96                         regs->regs[31] = epc + 8;
97                         if ((long)regs->regs[insn.i_format.rs] >= 0)
98                                 epc = epc + 4 + (insn.i_format.simmediate << 2);
99                         else
100                                 epc += 8;
101                         regs->cp0_epc = epc;
102                         break;
103                 }
104                 break;
105
106         /*
107          * These are unconditional and in j_format.
108          */
109         case jal_op:
110                 regs->regs[31] = regs->cp0_epc + 8;
111         case j_op:
112                 epc += 4;
113                 epc >>= 28;
114                 epc <<= 28;
115                 epc |= (insn.j_format.target << 2);
116                 regs->cp0_epc = epc;
117                 break;
118
119         /*
120          * These are conditional and in i_format.
121          */
122         case beq_op:
123         case beql_op:
124                 if (regs->regs[insn.i_format.rs] ==
125                     regs->regs[insn.i_format.rt])
126                         epc = epc + 4 + (insn.i_format.simmediate << 2);
127                 else
128                         epc += 8;
129                 regs->cp0_epc = epc;
130                 break;
131
132         case bne_op:
133         case bnel_op:
134                 if (regs->regs[insn.i_format.rs] !=
135                     regs->regs[insn.i_format.rt])
136                         epc = epc + 4 + (insn.i_format.simmediate << 2);
137                 else
138                         epc += 8;
139                 regs->cp0_epc = epc;
140                 break;
141
142         case blez_op: /* not really i_format */
143         case blezl_op:
144                 /* rt field assumed to be zero */
145                 if ((long)regs->regs[insn.i_format.rs] <= 0)
146                         epc = epc + 4 + (insn.i_format.simmediate << 2);
147                 else
148                         epc += 8;
149                 regs->cp0_epc = epc;
150                 break;
151
152         case bgtz_op:
153         case bgtzl_op:
154                 /* rt field assumed to be zero */
155                 if ((long)regs->regs[insn.i_format.rs] > 0)
156                         epc = epc + 4 + (insn.i_format.simmediate << 2);
157                 else
158                         epc += 8;
159                 regs->cp0_epc = epc;
160                 break;
161
162         /*
163          * And now the FPA/cp1 branch instructions.
164          */
165         case cop1_op:
166                 if (!cpu_has_fpu)
167                         fcr31 = current->thread.fpu.soft.sr;
168                 else
169                         asm volatile("cfc1\t%0,$31" : "=r" (fcr31));
170                 bit = (insn.i_format.rt >> 2);
171                 bit += (bit != 0);
172                 bit += 23;
173                 switch (insn.i_format.rt) {
174                 case 0: /* bc1f */
175                 case 2: /* bc1fl */
176                         if (~fcr31 & (1 << bit))
177                                 epc = epc + 4 + (insn.i_format.simmediate << 2);
178                         else
179                                 epc += 8;
180                         regs->cp0_epc = epc;
181                         break;
182
183                 case 1: /* bc1t */
184                 case 3: /* bc1tl */
185                         if (fcr31 & (1 << bit))
186                                 epc = epc + 4 + (insn.i_format.simmediate << 2);
187                         else
188                                 epc += 8;
189                         regs->cp0_epc = epc;
190                         break;
191                 }
192                 break;
193         }
194
195         return 0;
196
197 unaligned:
198         printk("%s: unaligned epc - sending SIGBUS.\n", current->comm);
199         force_sig(SIGBUS, current);
200         return -EFAULT;
201 }