xref: /linux/arch/mips/kernel/branch.c (revision 4bedea94545165364618d403d03b61d797acba0b)
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 }
200