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