xref: /openbmc/linux/arch/mips/kernel/branch.c (revision 8fa5723aa7e053d498336b48448b292fc2e0458b)
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 __user *addr;
26 	unsigned int bit, fcr31, dspcontrol;
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 __user *) 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 		case bposge32_op:
104 			if (!cpu_has_dsp)
105 				goto sigill;
106 
107 			dspcontrol = rddsp(0x01);
108 
109 			if (dspcontrol >= 32) {
110 				epc = epc + 4 + (insn.i_format.simmediate << 2);
111 			} else
112 				epc += 8;
113 			regs->cp0_epc = epc;
114 			break;
115 		}
116 		break;
117 
118 	/*
119 	 * These are unconditional and in j_format.
120 	 */
121 	case jal_op:
122 		regs->regs[31] = regs->cp0_epc + 8;
123 	case j_op:
124 		epc += 4;
125 		epc >>= 28;
126 		epc <<= 28;
127 		epc |= (insn.j_format.target << 2);
128 		regs->cp0_epc = epc;
129 		break;
130 
131 	/*
132 	 * These are conditional and in i_format.
133 	 */
134 	case beq_op:
135 	case beql_op:
136 		if (regs->regs[insn.i_format.rs] ==
137 		    regs->regs[insn.i_format.rt])
138 			epc = epc + 4 + (insn.i_format.simmediate << 2);
139 		else
140 			epc += 8;
141 		regs->cp0_epc = epc;
142 		break;
143 
144 	case bne_op:
145 	case bnel_op:
146 		if (regs->regs[insn.i_format.rs] !=
147 		    regs->regs[insn.i_format.rt])
148 			epc = epc + 4 + (insn.i_format.simmediate << 2);
149 		else
150 			epc += 8;
151 		regs->cp0_epc = epc;
152 		break;
153 
154 	case blez_op: /* not really i_format */
155 	case blezl_op:
156 		/* rt field assumed to be zero */
157 		if ((long)regs->regs[insn.i_format.rs] <= 0)
158 			epc = epc + 4 + (insn.i_format.simmediate << 2);
159 		else
160 			epc += 8;
161 		regs->cp0_epc = epc;
162 		break;
163 
164 	case bgtz_op:
165 	case bgtzl_op:
166 		/* rt field assumed to be zero */
167 		if ((long)regs->regs[insn.i_format.rs] > 0)
168 			epc = epc + 4 + (insn.i_format.simmediate << 2);
169 		else
170 			epc += 8;
171 		regs->cp0_epc = epc;
172 		break;
173 
174 	/*
175 	 * And now the FPA/cp1 branch instructions.
176 	 */
177 	case cop1_op:
178 		preempt_disable();
179 		if (is_fpu_owner())
180 			asm volatile("cfc1\t%0,$31" : "=r" (fcr31));
181 		else
182 			fcr31 = current->thread.fpu.fcr31;
183 		preempt_enable();
184 
185 		bit = (insn.i_format.rt >> 2);
186 		bit += (bit != 0);
187 		bit += 23;
188 		switch (insn.i_format.rt & 3) {
189 		case 0:	/* bc1f */
190 		case 2:	/* bc1fl */
191 			if (~fcr31 & (1 << bit))
192 				epc = epc + 4 + (insn.i_format.simmediate << 2);
193 			else
194 				epc += 8;
195 			regs->cp0_epc = epc;
196 			break;
197 
198 		case 1:	/* bc1t */
199 		case 3:	/* bc1tl */
200 			if (fcr31 & (1 << bit))
201 				epc = epc + 4 + (insn.i_format.simmediate << 2);
202 			else
203 				epc += 8;
204 			regs->cp0_epc = epc;
205 			break;
206 		}
207 		break;
208 	}
209 
210 	return 0;
211 
212 unaligned:
213 	printk("%s: unaligned epc - sending SIGBUS.\n", current->comm);
214 	force_sig(SIGBUS, current);
215 	return -EFAULT;
216 
217 sigill:
218 	printk("%s: DSP branch but not DSP ASE - sending SIGBUS.\n", current->comm);
219 	force_sig(SIGBUS, current);
220 	return -EFAULT;
221 }
222