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