PageRenderTime 42ms CodeModel.GetById 15ms app.highlight 22ms RepoModel.GetById 0ms app.codeStats 0ms

/arch/mips/kernel/branch.c

https://bitbucket.org/cresqo/cm7-p500-kernel
C | 254 lines | 199 code | 21 blank | 34 comment | 26 complexity | 59fed3a8bb137eadc65ab199fb9753db MD5 | raw file
Possible License(s): LGPL-2.0, AGPL-1.0, GPL-2.0
  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 */
 23int __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#ifdef CONFIG_CPU_CAVIUM_OCTEON
209	case lwc2_op: /* This is bbit0 on Octeon */
210		if ((regs->regs[insn.i_format.rs] & (1ull<<insn.i_format.rt))
211		     == 0)
212			epc = epc + 4 + (insn.i_format.simmediate << 2);
213		else
214			epc += 8;
215		regs->cp0_epc = epc;
216		break;
217	case ldc2_op: /* This is bbit032 on Octeon */
218		if ((regs->regs[insn.i_format.rs] &
219		    (1ull<<(insn.i_format.rt+32))) == 0)
220			epc = epc + 4 + (insn.i_format.simmediate << 2);
221		else
222			epc += 8;
223		regs->cp0_epc = epc;
224		break;
225	case swc2_op: /* This is bbit1 on Octeon */
226		if (regs->regs[insn.i_format.rs] & (1ull<<insn.i_format.rt))
227			epc = epc + 4 + (insn.i_format.simmediate << 2);
228		else
229			epc += 8;
230		regs->cp0_epc = epc;
231		break;
232	case sdc2_op: /* This is bbit132 on Octeon */
233		if (regs->regs[insn.i_format.rs] &
234		    (1ull<<(insn.i_format.rt+32)))
235			epc = epc + 4 + (insn.i_format.simmediate << 2);
236		else
237			epc += 8;
238		regs->cp0_epc = epc;
239		break;
240#endif
241	}
242
243	return 0;
244
245unaligned:
246	printk("%s: unaligned epc - sending SIGBUS.\n", current->comm);
247	force_sig(SIGBUS, current);
248	return -EFAULT;
249
250sigill:
251	printk("%s: DSP branch but not DSP ASE - sending SIGBUS.\n", current->comm);
252	force_sig(SIGBUS, current);
253	return -EFAULT;
254}