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 <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 */
  23int __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#ifdef CONFIG_CPU_CAVIUM_OCTEON
 209        case lwc2_op: /* This is bbit0 on Octeon */
 210                if ((regs->regs[insn.i_format.rs] & (1ull<<insn.i_format.rt))
 211                     == 0)
 212                        epc = epc + 4 + (insn.i_format.simmediate << 2);
 213                else
 214                        epc += 8;
 215                regs->cp0_epc = epc;
 216                break;
 217        case ldc2_op: /* This is bbit032 on Octeon */
 218                if ((regs->regs[insn.i_format.rs] &
 219                    (1ull<<(insn.i_format.rt+32))) == 0)
 220                        epc = epc + 4 + (insn.i_format.simmediate << 2);
 221                else
 222                        epc += 8;
 223                regs->cp0_epc = epc;
 224                break;
 225        case swc2_op: /* This is bbit1 on Octeon */
 226                if (regs->regs[insn.i_format.rs] & (1ull<<insn.i_format.rt))
 227                        epc = epc + 4 + (insn.i_format.simmediate << 2);
 228                else
 229                        epc += 8;
 230                regs->cp0_epc = epc;
 231                break;
 232        case sdc2_op: /* This is bbit132 on Octeon */
 233                if (regs->regs[insn.i_format.rs] &
 234                    (1ull<<(insn.i_format.rt+32)))
 235                        epc = epc + 4 + (insn.i_format.simmediate << 2);
 236                else
 237                        epc += 8;
 238                regs->cp0_epc = epc;
 239                break;
 240#endif
 241        }
 242
 243        return 0;
 244
 245unaligned:
 246        printk("%s: unaligned epc - sending SIGBUS.\n", current->comm);
 247        force_sig(SIGBUS, current);
 248        return -EFAULT;
 249
 250sigill:
 251        printk("%s: DSP branch but not DSP ASE - sending SIGBUS.\n", current->comm);
 252        force_sig(SIGBUS, current);
 253        return -EFAULT;
 254}
 255