PageRenderTime 24ms CodeModel.GetById 14ms app.highlight 8ms RepoModel.GetById 1ms app.codeStats 0ms

/arch/mips/kernel/branch.c

https://bitbucket.org/evzijst/gittest
C | 199 lines | 148 code | 17 blank | 34 comment | 18 complexity | 697c9164ceb431481898d62102b186a8 MD5 | raw file
  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 */
 22int __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
195unaligned:
196	printk("%s: unaligned epc - sending SIGBUS.\n", current->comm);
197	force_sig(SIGBUS, current);
198	return -EFAULT;
199}