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
6 * Copyright (C) 1996, 97, 2000, 2001 by Ralf Baechle
7 * Copyright (C) 2001 MIPS Technologies, Inc.
9 #include <linux/kernel.h>
10 #include <linux/sched.h>
11 #include <linux/signal.h>
12 #include <asm/branch.h>
14 #include <asm/cpu-features.h>
17 #include <asm/ptrace.h>
18 #include <asm/uaccess.h>
21 * Compute the return address and do emulate branch simulation, if required.
23 int __compute_return_epc(struct pt_regs *regs)
25 unsigned int __user *addr;
26 unsigned int bit, fcr31, dspcontrol;
28 union mips_instruction insn;
35 * Read the instruction
37 addr = (unsigned int __user *) epc;
38 if (__get_user(insn.word, addr)) {
39 force_sig(SIGSEGV, current);
44 switch (insn.i_format.opcode) {
46 * jr and jalr are in r_format format.
49 switch (insn.r_format.func) {
51 regs->regs[insn.r_format.rd] = epc + 8;
54 regs->cp0_epc = regs->regs[insn.r_format.rs];
60 * This group contains:
61 * bltz_op, bgez_op, bltzl_op, bgezl_op,
62 * bltzal_op, bgezal_op, bltzall_op, bgezall_op.
65 switch (insn.i_format.rt) {
68 if ((long)regs->regs[insn.i_format.rs] < 0)
69 epc = epc + 4 + (insn.i_format.simmediate << 2);
77 if ((long)regs->regs[insn.i_format.rs] >= 0)
78 epc = epc + 4 + (insn.i_format.simmediate << 2);
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);
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);
107 dspcontrol = rddsp(0x01);
109 if (dspcontrol >= 32) {
110 epc = epc + 4 + (insn.i_format.simmediate << 2);
119 * These are unconditional and in j_format.
122 regs->regs[31] = regs->cp0_epc + 8;
127 epc |= (insn.j_format.target << 2);
132 * These are conditional and in i_format.
136 if (regs->regs[insn.i_format.rs] ==
137 regs->regs[insn.i_format.rt])
138 epc = epc + 4 + (insn.i_format.simmediate << 2);
146 if (regs->regs[insn.i_format.rs] !=
147 regs->regs[insn.i_format.rt])
148 epc = epc + 4 + (insn.i_format.simmediate << 2);
154 case blez_op: /* not really i_format */
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);
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);
175 * And now the FPA/cp1 branch instructions.
180 asm volatile("cfc1\t%0,$31" : "=r" (fcr31));
182 fcr31 = current->thread.fpu.fcr31;
185 bit = (insn.i_format.rt >> 2);
188 switch (insn.i_format.rt & 3) {
191 if (~fcr31 & (1 << bit))
192 epc = epc + 4 + (insn.i_format.simmediate << 2);
200 if (fcr31 & (1 << bit))
201 epc = epc + 4 + (insn.i_format.simmediate << 2);
213 printk("%s: unaligned epc - sending SIGBUS.\n", current->comm);
214 force_sig(SIGBUS, current);
218 printk("%s: DSP branch but not DSP ASE - sending SIGBUS.\n", current->comm);
219 force_sig(SIGBUS, current);