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>
16 #include <asm/ptrace.h>
17 #include <asm/uaccess.h>
20 * Compute the return address and do emulate branch simulation, if required.
22 int __compute_return_epc(struct pt_regs *regs)
24 unsigned int *addr, bit, fcr31;
26 union mips_instruction insn;
33 * Read the instruction
35 addr = (unsigned int *) epc;
36 if (__get_user(insn.word, addr)) {
37 force_sig(SIGSEGV, current);
42 switch (insn.i_format.opcode) {
44 * jr and jalr are in r_format format.
47 switch (insn.r_format.func) {
49 regs->regs[insn.r_format.rd] = epc + 8;
52 regs->cp0_epc = regs->regs[insn.r_format.rs];
58 * This group contains:
59 * bltz_op, bgez_op, bltzl_op, bgezl_op,
60 * bltzal_op, bgezal_op, bltzall_op, bgezall_op.
63 switch (insn.i_format.rt) {
66 if ((long)regs->regs[insn.i_format.rs] < 0)
67 epc = epc + 4 + (insn.i_format.simmediate << 2);
75 if ((long)regs->regs[insn.i_format.rs] >= 0)
76 epc = epc + 4 + (insn.i_format.simmediate << 2);
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);
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);
105 * These are unconditional and in j_format.
108 regs->regs[31] = regs->cp0_epc + 8;
113 epc |= (insn.j_format.target << 2);
118 * These are conditional and in i_format.
122 if (regs->regs[insn.i_format.rs] ==
123 regs->regs[insn.i_format.rt])
124 epc = epc + 4 + (insn.i_format.simmediate << 2);
132 if (regs->regs[insn.i_format.rs] !=
133 regs->regs[insn.i_format.rt])
134 epc = epc + 4 + (insn.i_format.simmediate << 2);
140 case blez_op: /* not really i_format */
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);
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);
161 * And now the FPA/cp1 branch instructions.
165 fcr31 = current->thread.fpu.soft.fcr31;
167 asm volatile("cfc1\t%0,$31" : "=r" (fcr31));
168 bit = (insn.i_format.rt >> 2);
171 switch (insn.i_format.rt) {
174 if (~fcr31 & (1 << bit))
175 epc = epc + 4 + (insn.i_format.simmediate << 2);
183 if (fcr31 & (1 << bit))
184 epc = epc + 4 + (insn.i_format.simmediate << 2);
196 printk("%s: unaligned epc - sending SIGBUS.\n", current->comm);
197 force_sig(SIGBUS, current);