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