~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/arch/mips/kernel/branch.c

Version: ~ [ linux-5.1-rc1 ] ~ [ linux-5.0.3 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.30 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.107 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.164 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.176 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.19.8 ] ~ [ linux-3.18.136 ] ~ [ linux-3.17.8 ] ~ [ linux-3.16.63 ] ~ [ linux-3.15.10 ] ~ [ linux-3.14.79 ] ~ [ linux-3.13.11 ] ~ [ linux-3.12.74 ] ~ [ linux-3.11.10 ] ~ [ linux-3.10.108 ] ~ [ linux-3.9.11 ] ~ [ linux-3.8.13 ] ~ [ linux-3.7.10 ] ~ [ linux-3.6.11 ] ~ [ linux-3.5.7 ] ~ [ linux-3.4.113 ] ~ [ linux-3.3.8 ] ~ [ linux-3.2.102 ] ~ [ linux-3.1.10 ] ~ [ linux-3.0.101 ] ~ [ linux-2.6.39.4 ] ~ [ linux-2.6.38.8 ] ~ [ linux-2.6.37.6 ] ~ [ linux-2.6.36.4 ] ~ [ linux-2.6.35.14 ] ~ [ linux-2.6.34.15 ] ~ [ linux-2.6.33.20 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  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         switch (insn.i_format.opcode) {
 44         /*
 45          * jr and jalr are in r_format format.
 46          */
 47         case spec_op:
 48                 switch (insn.r_format.func) {
 49                 case jalr_op:
 50                         regs->regs[insn.r_format.rd] = epc + 8;
 51                         /* Fall through */
 52                 case jr_op:
 53                         regs->cp0_epc = regs->regs[insn.r_format.rs];
 54                         break;
 55                 }
 56                 break;
 57 
 58         /*
 59          * This group contains:
 60          * bltz_op, bgez_op, bltzl_op, bgezl_op,
 61          * bltzal_op, bgezal_op, bltzall_op, bgezall_op.
 62          */
 63         case bcond_op:
 64                 switch (insn.i_format.rt) {
 65                 case bltz_op:
 66                 case bltzl_op:
 67                         if ((long)regs->regs[insn.i_format.rs] < 0)
 68                                 epc = epc + 4 + (insn.i_format.simmediate << 2);
 69                         else
 70                                 epc += 8;
 71                         regs->cp0_epc = epc;
 72                         break;
 73 
 74                 case bgez_op:
 75                 case bgezl_op:
 76                         if ((long)regs->regs[insn.i_format.rs] >= 0)
 77                                 epc = epc + 4 + (insn.i_format.simmediate << 2);
 78                         else
 79                                 epc += 8;
 80                         regs->cp0_epc = epc;
 81                         break;
 82 
 83                 case bltzal_op:
 84                 case bltzall_op:
 85                         regs->regs[31] = epc + 8;
 86                         if ((long)regs->regs[insn.i_format.rs] < 0)
 87                                 epc = epc + 4 + (insn.i_format.simmediate << 2);
 88                         else
 89                                 epc += 8;
 90                         regs->cp0_epc = epc;
 91                         break;
 92 
 93                 case bgezal_op:
 94                 case bgezall_op:
 95                         regs->regs[31] = epc + 8;
 96                         if ((long)regs->regs[insn.i_format.rs] >= 0)
 97                                 epc = epc + 4 + (insn.i_format.simmediate << 2);
 98                         else
 99                                 epc += 8;
100                         regs->cp0_epc = epc;
101                         break;
102                 case bposge32_op:
103                         if (!cpu_has_dsp)
104                                 goto sigill;
105 
106                         dspcontrol = rddsp(0x01);
107 
108                         if (dspcontrol >= 32) {
109                                 epc = epc + 4 + (insn.i_format.simmediate << 2);
110                         } else
111                                 epc += 8;
112                         regs->cp0_epc = epc;
113                         break;
114                 }
115                 break;
116 
117         /*
118          * These are unconditional and in j_format.
119          */
120         case jal_op:
121                 regs->regs[31] = regs->cp0_epc + 8;
122         case j_op:
123                 epc += 4;
124                 epc >>= 28;
125                 epc <<= 28;
126                 epc |= (insn.j_format.target << 2);
127                 regs->cp0_epc = epc;
128                 break;
129 
130         /*
131          * These are conditional and in i_format.
132          */
133         case beq_op:
134         case beql_op:
135                 if (regs->regs[insn.i_format.rs] ==
136                     regs->regs[insn.i_format.rt])
137                         epc = epc + 4 + (insn.i_format.simmediate << 2);
138                 else
139                         epc += 8;
140                 regs->cp0_epc = epc;
141                 break;
142 
143         case bne_op:
144         case bnel_op:
145                 if (regs->regs[insn.i_format.rs] !=
146                     regs->regs[insn.i_format.rt])
147                         epc = epc + 4 + (insn.i_format.simmediate << 2);
148                 else
149                         epc += 8;
150                 regs->cp0_epc = epc;
151                 break;
152 
153         case blez_op: /* not really i_format */
154         case blezl_op:
155                 /* rt field assumed to be zero */
156                 if ((long)regs->regs[insn.i_format.rs] <= 0)
157                         epc = epc + 4 + (insn.i_format.simmediate << 2);
158                 else
159                         epc += 8;
160                 regs->cp0_epc = epc;
161                 break;
162 
163         case bgtz_op:
164         case bgtzl_op:
165                 /* rt field assumed to be zero */
166                 if ((long)regs->regs[insn.i_format.rs] > 0)
167                         epc = epc + 4 + (insn.i_format.simmediate << 2);
168                 else
169                         epc += 8;
170                 regs->cp0_epc = epc;
171                 break;
172 
173         /*
174          * And now the FPA/cp1 branch instructions.
175          */
176         case cop1_op:
177                 preempt_disable();
178                 if (is_fpu_owner())
179                         asm volatile("cfc1\t%0,$31" : "=r" (fcr31));
180                 else
181                         fcr31 = current->thread.fpu.fcr31;
182                 preempt_enable();
183 
184                 bit = (insn.i_format.rt >> 2);
185                 bit += (bit != 0);
186                 bit += 23;
187                 switch (insn.i_format.rt & 3) {
188                 case 0: /* bc1f */
189                 case 2: /* bc1fl */
190                         if (~fcr31 & (1 << bit))
191                                 epc = epc + 4 + (insn.i_format.simmediate << 2);
192                         else
193                                 epc += 8;
194                         regs->cp0_epc = epc;
195                         break;
196 
197                 case 1: /* bc1t */
198                 case 3: /* bc1tl */
199                         if (fcr31 & (1 << bit))
200                                 epc = epc + 4 + (insn.i_format.simmediate << 2);
201                         else
202                                 epc += 8;
203                         regs->cp0_epc = epc;
204                         break;
205                 }
206                 break;
207 #ifdef CONFIG_CPU_CAVIUM_OCTEON
208         case lwc2_op: /* This is bbit0 on Octeon */
209                 if ((regs->regs[insn.i_format.rs] & (1ull<<insn.i_format.rt))
210                      == 0)
211                         epc = epc + 4 + (insn.i_format.simmediate << 2);
212                 else
213                         epc += 8;
214                 regs->cp0_epc = epc;
215                 break;
216         case ldc2_op: /* This is bbit032 on Octeon */
217                 if ((regs->regs[insn.i_format.rs] &
218                     (1ull<<(insn.i_format.rt+32))) == 0)
219                         epc = epc + 4 + (insn.i_format.simmediate << 2);
220                 else
221                         epc += 8;
222                 regs->cp0_epc = epc;
223                 break;
224         case swc2_op: /* This is bbit1 on Octeon */
225                 if (regs->regs[insn.i_format.rs] & (1ull<<insn.i_format.rt))
226                         epc = epc + 4 + (insn.i_format.simmediate << 2);
227                 else
228                         epc += 8;
229                 regs->cp0_epc = epc;
230                 break;
231         case sdc2_op: /* This is bbit132 on Octeon */
232                 if (regs->regs[insn.i_format.rs] &
233                     (1ull<<(insn.i_format.rt+32)))
234                         epc = epc + 4 + (insn.i_format.simmediate << 2);
235                 else
236                         epc += 8;
237                 regs->cp0_epc = epc;
238                 break;
239 #endif
240         }
241 
242         return 0;
243 
244 unaligned:
245         printk("%s: unaligned epc - sending SIGBUS.\n", current->comm);
246         force_sig(SIGBUS, current);
247         return -EFAULT;
248 
249 sigill:
250         printk("%s: DSP branch but not DSP ASE - sending SIGBUS.\n", current->comm);
251         force_sig(SIGBUS, current);
252         return -EFAULT;
253 }
254 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp