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
6 * Copyright (C) 1996, 97, 2000, 2001 by Ralf Baechle
7 * Copyright (C) 2001 MIPS Technologies, Inc.
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>
15 #include <asm/cpu-features.h>
18 #include <asm/ptrace.h>
19 #include <asm/uaccess.h>
22 * __compute_return_epc_for_insn - Computes the return address and do emulate
23 * branch simulation, if required.
25 * @regs: Pointer to pt_regs
26 * @insn: branch instruction to decode
27 * @returns: -EFAULT on error and forces SIGBUS, and on success
28 * returns 0 or BRANCH_LIKELY_TAKEN as appropriate after
29 * evaluating the branch.
31 int __compute_return_epc_for_insn(struct pt_regs
*regs
,
32 union mips_instruction insn
)
34 unsigned int bit
, fcr31
, dspcontrol
;
35 long epc
= regs
->cp0_epc
;
38 switch (insn
.i_format
.opcode
) {
40 * jr and jalr are in r_format format.
43 switch (insn
.r_format
.func
) {
45 regs
->regs
[insn
.r_format
.rd
] = epc
+ 8;
48 regs
->cp0_epc
= regs
->regs
[insn
.r_format
.rs
];
54 * This group contains:
55 * bltz_op, bgez_op, bltzl_op, bgezl_op,
56 * bltzal_op, bgezal_op, bltzall_op, bgezall_op.
59 switch (insn
.i_format
.rt
) {
62 if ((long)regs
->regs
[insn
.i_format
.rs
] < 0) {
63 epc
= epc
+ 4 + (insn
.i_format
.simmediate
<< 2);
64 if (insn
.i_format
.rt
== bltzl_op
)
65 ret
= BRANCH_LIKELY_TAKEN
;
73 if ((long)regs
->regs
[insn
.i_format
.rs
] >= 0) {
74 epc
= epc
+ 4 + (insn
.i_format
.simmediate
<< 2);
75 if (insn
.i_format
.rt
== bgezl_op
)
76 ret
= BRANCH_LIKELY_TAKEN
;
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 if (insn
.i_format
.rt
== bltzall_op
)
88 ret
= BRANCH_LIKELY_TAKEN
;
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 if (insn
.i_format
.rt
== bgezall_op
)
100 ret
= BRANCH_LIKELY_TAKEN
;
110 dspcontrol
= rddsp(0x01);
112 if (dspcontrol
>= 32) {
113 epc
= epc
+ 4 + (insn
.i_format
.simmediate
<< 2);
122 * These are unconditional and in j_format.
125 regs
->regs
[31] = regs
->cp0_epc
+ 8;
130 epc
|= (insn
.j_format
.target
<< 2);
135 * These are conditional and in i_format.
139 if (regs
->regs
[insn
.i_format
.rs
] ==
140 regs
->regs
[insn
.i_format
.rt
]) {
141 epc
= epc
+ 4 + (insn
.i_format
.simmediate
<< 2);
142 if (insn
.i_format
.rt
== beql_op
)
143 ret
= BRANCH_LIKELY_TAKEN
;
151 if (regs
->regs
[insn
.i_format
.rs
] !=
152 regs
->regs
[insn
.i_format
.rt
]) {
153 epc
= epc
+ 4 + (insn
.i_format
.simmediate
<< 2);
154 if (insn
.i_format
.rt
== bnel_op
)
155 ret
= BRANCH_LIKELY_TAKEN
;
161 case blez_op
: /* not really i_format */
163 /* rt field assumed to be zero */
164 if ((long)regs
->regs
[insn
.i_format
.rs
] <= 0) {
165 epc
= epc
+ 4 + (insn
.i_format
.simmediate
<< 2);
166 if (insn
.i_format
.rt
== bnel_op
)
167 ret
= BRANCH_LIKELY_TAKEN
;
175 /* rt field assumed to be zero */
176 if ((long)regs
->regs
[insn
.i_format
.rs
] > 0) {
177 epc
= epc
+ 4 + (insn
.i_format
.simmediate
<< 2);
178 if (insn
.i_format
.rt
== bnel_op
)
179 ret
= BRANCH_LIKELY_TAKEN
;
186 * And now the FPA/cp1 branch instructions.
191 asm volatile("cfc1\t%0,$31" : "=r" (fcr31
));
193 fcr31
= current
->thread
.fpu
.fcr31
;
196 bit
= (insn
.i_format
.rt
>> 2);
199 switch (insn
.i_format
.rt
& 3) {
202 if (~fcr31
& (1 << bit
)) {
203 epc
= epc
+ 4 + (insn
.i_format
.simmediate
<< 2);
204 if (insn
.i_format
.rt
== 2)
205 ret
= BRANCH_LIKELY_TAKEN
;
213 if (fcr31
& (1 << bit
)) {
214 epc
= epc
+ 4 + (insn
.i_format
.simmediate
<< 2);
215 if (insn
.i_format
.rt
== 3)
216 ret
= BRANCH_LIKELY_TAKEN
;
223 #ifdef CONFIG_CPU_CAVIUM_OCTEON
224 case lwc2_op
: /* This is bbit0 on Octeon */
225 if ((regs
->regs
[insn
.i_format
.rs
] & (1ull<<insn
.i_format
.rt
))
227 epc
= epc
+ 4 + (insn
.i_format
.simmediate
<< 2);
232 case ldc2_op
: /* This is bbit032 on Octeon */
233 if ((regs
->regs
[insn
.i_format
.rs
] &
234 (1ull<<(insn
.i_format
.rt
+32))) == 0)
235 epc
= epc
+ 4 + (insn
.i_format
.simmediate
<< 2);
240 case swc2_op
: /* This is bbit1 on Octeon */
241 if (regs
->regs
[insn
.i_format
.rs
] & (1ull<<insn
.i_format
.rt
))
242 epc
= epc
+ 4 + (insn
.i_format
.simmediate
<< 2);
247 case sdc2_op
: /* This is bbit132 on Octeon */
248 if (regs
->regs
[insn
.i_format
.rs
] &
249 (1ull<<(insn
.i_format
.rt
+32)))
250 epc
= epc
+ 4 + (insn
.i_format
.simmediate
<< 2);
261 printk("%s: DSP branch but not DSP ASE - sending SIGBUS.\n", current
->comm
);
262 force_sig(SIGBUS
, current
);
265 EXPORT_SYMBOL_GPL(__compute_return_epc_for_insn
);
267 int __compute_return_epc(struct pt_regs
*regs
)
269 unsigned int __user
*addr
;
271 union mips_instruction insn
;
278 * Read the instruction
280 addr
= (unsigned int __user
*) epc
;
281 if (__get_user(insn
.word
, addr
)) {
282 force_sig(SIGSEGV
, current
);
286 return __compute_return_epc_for_insn(regs
, insn
);
289 printk("%s: unaligned epc - sending SIGBUS.\n", current
->comm
);
290 force_sig(SIGBUS
, current
);