linux/arch/mips/kernel/branch.c
<<
>>
Prefs
   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 <linux/module.h>
  13#include <asm/branch.h>
  14#include <asm/cpu.h>
  15#include <asm/cpu-features.h>
  16#include <asm/fpu.h>
  17#include <asm/inst.h>
  18#include <asm/ptrace.h>
  19#include <asm/uaccess.h>
  20
  21/**
  22 * __compute_return_epc_for_insn - Computes the return address and do emulate
  23 *                                  branch simulation, if required.
  24 *
  25 * @regs:       Pointer to pt_regs
  26 * @insn:       branch instruction to decode
  27 * @returns:    -EFAULT on error and forces SIGBUS, and on success
  28 *              returns 0 or BRANCH_LIKELY_TAKEN as appropriate after
  29 *              evaluating the branch.
  30 */
  31int __compute_return_epc_for_insn(struct pt_regs *regs,
  32                                   union mips_instruction insn)
  33{
  34        unsigned int bit, fcr31, dspcontrol;
  35        long epc = regs->cp0_epc;
  36        int ret = 0;
  37
  38        switch (insn.i_format.opcode) {
  39        /*
  40         * jr and jalr are in r_format format.
  41         */
  42        case spec_op:
  43                switch (insn.r_format.func) {
  44                case jalr_op:
  45                        regs->regs[insn.r_format.rd] = epc + 8;
  46                        /* Fall through */
  47                case jr_op:
  48                        regs->cp0_epc = regs->regs[insn.r_format.rs];
  49                        break;
  50                }
  51                break;
  52
  53        /*
  54         * This group contains:
  55         * bltz_op, bgez_op, bltzl_op, bgezl_op,
  56         * bltzal_op, bgezal_op, bltzall_op, bgezall_op.
  57         */
  58        case bcond_op:
  59                switch (insn.i_format.rt) {
  60                case bltz_op:
  61                case bltzl_op:
  62                        if ((long)regs->regs[insn.i_format.rs] < 0) {
  63                                epc = epc + 4 + (insn.i_format.simmediate << 2);
  64                                if (insn.i_format.rt == bltzl_op)
  65                                        ret = BRANCH_LIKELY_TAKEN;
  66                        } else
  67                                epc += 8;
  68                        regs->cp0_epc = epc;
  69                        break;
  70
  71                case bgez_op:
  72                case bgezl_op:
  73                        if ((long)regs->regs[insn.i_format.rs] >= 0) {
  74                                epc = epc + 4 + (insn.i_format.simmediate << 2);
  75                                if (insn.i_format.rt == bgezl_op)
  76                                        ret = BRANCH_LIKELY_TAKEN;
  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                                if (insn.i_format.rt == bltzall_op)
  88                                        ret = BRANCH_LIKELY_TAKEN;
  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                                if (insn.i_format.rt == bgezall_op)
 100                                        ret = BRANCH_LIKELY_TAKEN;
 101                        } else
 102                                epc += 8;
 103                        regs->cp0_epc = epc;
 104                        break;
 105
 106                case bposge32_op:
 107                        if (!cpu_has_dsp)
 108                                goto sigill;
 109
 110                        dspcontrol = rddsp(0x01);
 111
 112                        if (dspcontrol >= 32) {
 113                                epc = epc + 4 + (insn.i_format.simmediate << 2);
 114                        } else
 115                                epc += 8;
 116                        regs->cp0_epc = epc;
 117                        break;
 118                }
 119                break;
 120
 121        /*
 122         * These are unconditional and in j_format.
 123         */
 124        case jal_op:
 125                regs->regs[31] = regs->cp0_epc + 8;
 126        case j_op:
 127                epc += 4;
 128                epc >>= 28;
 129                epc <<= 28;
 130                epc |= (insn.j_format.target << 2);
 131                regs->cp0_epc = epc;
 132                break;
 133
 134        /*
 135         * These are conditional and in i_format.
 136         */
 137        case beq_op:
 138        case beql_op:
 139                if (regs->regs[insn.i_format.rs] ==
 140                    regs->regs[insn.i_format.rt]) {
 141                        epc = epc + 4 + (insn.i_format.simmediate << 2);
 142                        if (insn.i_format.rt == beql_op)
 143                                ret = BRANCH_LIKELY_TAKEN;
 144                } else
 145                        epc += 8;
 146                regs->cp0_epc = epc;
 147                break;
 148
 149        case bne_op:
 150        case bnel_op:
 151                if (regs->regs[insn.i_format.rs] !=
 152                    regs->regs[insn.i_format.rt]) {
 153                        epc = epc + 4 + (insn.i_format.simmediate << 2);
 154                        if (insn.i_format.rt == bnel_op)
 155                                ret = BRANCH_LIKELY_TAKEN;
 156                } else
 157                        epc += 8;
 158                regs->cp0_epc = epc;
 159                break;
 160
 161        case blez_op: /* not really i_format */
 162        case blezl_op:
 163                /* rt field assumed to be zero */
 164                if ((long)regs->regs[insn.i_format.rs] <= 0) {
 165                        epc = epc + 4 + (insn.i_format.simmediate << 2);
 166                        if (insn.i_format.rt == bnel_op)
 167                                ret = BRANCH_LIKELY_TAKEN;
 168                } else
 169                        epc += 8;
 170                regs->cp0_epc = epc;
 171                break;
 172
 173        case bgtz_op:
 174        case bgtzl_op:
 175                /* rt field assumed to be zero */
 176                if ((long)regs->regs[insn.i_format.rs] > 0) {
 177                        epc = epc + 4 + (insn.i_format.simmediate << 2);
 178                        if (insn.i_format.rt == bnel_op)
 179                                ret = BRANCH_LIKELY_TAKEN;
 180                } else
 181                        epc += 8;
 182                regs->cp0_epc = epc;
 183                break;
 184
 185        /*
 186         * And now the FPA/cp1 branch instructions.
 187         */
 188        case cop1_op:
 189                preempt_disable();
 190                if (is_fpu_owner())
 191                        asm volatile("cfc1\t%0,$31" : "=r" (fcr31));
 192                else
 193                        fcr31 = current->thread.fpu.fcr31;
 194                preempt_enable();
 195
 196                bit = (insn.i_format.rt >> 2);
 197                bit += (bit != 0);
 198                bit += 23;
 199                switch (insn.i_format.rt & 3) {
 200                case 0: /* bc1f */
 201                case 2: /* bc1fl */
 202                        if (~fcr31 & (1 << bit)) {
 203                                epc = epc + 4 + (insn.i_format.simmediate << 2);
 204                                if (insn.i_format.rt == 2)
 205                                        ret = BRANCH_LIKELY_TAKEN;
 206                        } else
 207                                epc += 8;
 208                        regs->cp0_epc = epc;
 209                        break;
 210
 211                case 1: /* bc1t */
 212                case 3: /* bc1tl */
 213                        if (fcr31 & (1 << bit)) {
 214                                epc = epc + 4 + (insn.i_format.simmediate << 2);
 215                                if (insn.i_format.rt == 3)
 216                                        ret = BRANCH_LIKELY_TAKEN;
 217                        } else
 218                                epc += 8;
 219                        regs->cp0_epc = epc;
 220                        break;
 221                }
 222                break;
 223#ifdef CONFIG_CPU_CAVIUM_OCTEON
 224        case lwc2_op: /* This is bbit0 on Octeon */
 225                if ((regs->regs[insn.i_format.rs] & (1ull<<insn.i_format.rt))
 226                     == 0)
 227                        epc = epc + 4 + (insn.i_format.simmediate << 2);
 228                else
 229                        epc += 8;
 230                regs->cp0_epc = epc;
 231                break;
 232        case ldc2_op: /* This is bbit032 on Octeon */
 233                if ((regs->regs[insn.i_format.rs] &
 234                    (1ull<<(insn.i_format.rt+32))) == 0)
 235                        epc = epc + 4 + (insn.i_format.simmediate << 2);
 236                else
 237                        epc += 8;
 238                regs->cp0_epc = epc;
 239                break;
 240        case swc2_op: /* This is bbit1 on Octeon */
 241                if (regs->regs[insn.i_format.rs] & (1ull<<insn.i_format.rt))
 242                        epc = epc + 4 + (insn.i_format.simmediate << 2);
 243                else
 244                        epc += 8;
 245                regs->cp0_epc = epc;
 246                break;
 247        case sdc2_op: /* This is bbit132 on Octeon */
 248                if (regs->regs[insn.i_format.rs] &
 249                    (1ull<<(insn.i_format.rt+32)))
 250                        epc = epc + 4 + (insn.i_format.simmediate << 2);
 251                else
 252                        epc += 8;
 253                regs->cp0_epc = epc;
 254                break;
 255#endif
 256        }
 257
 258        return ret;
 259
 260sigill:
 261        printk("%s: DSP branch but not DSP ASE - sending SIGBUS.\n", current->comm);
 262        force_sig(SIGBUS, current);
 263        return -EFAULT;
 264}
 265EXPORT_SYMBOL_GPL(__compute_return_epc_for_insn);
 266
 267int __compute_return_epc(struct pt_regs *regs)
 268{
 269        unsigned int __user *addr;
 270        long epc;
 271        union mips_instruction insn;
 272
 273        epc = regs->cp0_epc;
 274        if (epc & 3)
 275                goto unaligned;
 276
 277        /*
 278         * Read the instruction
 279         */
 280        addr = (unsigned int __user *) epc;
 281        if (__get_user(insn.word, addr)) {
 282                force_sig(SIGSEGV, current);
 283                return -EFAULT;
 284        }
 285
 286        return __compute_return_epc_for_insn(regs, insn);
 287
 288unaligned:
 289        printk("%s: unaligned epc - sending SIGBUS.\n", current->comm);
 290        force_sig(SIGBUS, current);
 291        return -EFAULT;
 292
 293}
 294