branch.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:4k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

  1. /*
  2.  * Branch and jump emulation.
  3.  *
  4.  * This file is subject to the terms and conditions of the GNU General Public
  5.  * License.  See the file "COPYING" in the main directory of this archive
  6.  * for more details.
  7.  *
  8.  * Copyright (C) 1996, 97, 2000, 2001 by Ralf Baechle
  9.  * Copyright (C) 2001 MIPS Technologies, Inc.
  10.  */
  11. #include <linux/kernel.h>
  12. #include <linux/sched.h>
  13. #include <linux/signal.h>
  14. #include <asm/branch.h>
  15. #include <asm/cpu.h>
  16. #include <asm/inst.h>
  17. #include <asm/ptrace.h>
  18. #include <asm/uaccess.h>
  19. #include <asm/processor.h>
  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 *addr, bit, fcr31;
  26. long epc;
  27. union mips_instruction insn;
  28. epc = regs->cp0_epc;
  29. if (epc & 3)
  30. goto unaligned;
  31. /*
  32.  * Read the instruction
  33.  */
  34. addr = (unsigned int *) (unsigned long) epc;
  35. if (__get_user(insn.word, addr)) {
  36. force_sig(SIGSEGV, current);
  37. return -EFAULT;
  38. }
  39. regs->regs[0] = 0;
  40. switch (insn.i_format.opcode) {
  41. /*
  42.  * jr and jalr are in r_format format.
  43.  */
  44. case spec_op:
  45. switch (insn.r_format.func) {
  46. case jalr_op:
  47. regs->regs[insn.r_format.rd] = epc + 8;
  48. /* Fall through */
  49. case jr_op:
  50. regs->cp0_epc = regs->regs[insn.r_format.rs];
  51. break;
  52. }
  53. break;
  54. /*
  55.  * This group contains:
  56.  * bltz_op, bgez_op, bltzl_op, bgezl_op,
  57.  * bltzal_op, bgezal_op, bltzall_op, bgezall_op.
  58.  */
  59. case bcond_op:
  60. switch (insn.i_format.rt) {
  61.   case bltz_op:
  62. case bltzl_op:
  63. if ((long)regs->regs[insn.i_format.rs] < 0)
  64. epc = epc + 4 + (insn.i_format.simmediate << 2);
  65. else
  66. epc += 8;
  67. regs->cp0_epc = epc;
  68. break;
  69. case bgez_op:
  70. case bgezl_op:
  71. if ((long)regs->regs[insn.i_format.rs] >= 0)
  72. epc = epc + 4 + (insn.i_format.simmediate << 2);
  73. else
  74. epc += 8;
  75. regs->cp0_epc = epc;
  76. break;
  77. case bltzal_op:
  78. case bltzall_op:
  79. regs->regs[31] = epc + 8;
  80. if ((long)regs->regs[insn.i_format.rs] < 0)
  81. epc = epc + 4 + (insn.i_format.simmediate << 2);
  82. else
  83. epc += 8;
  84. regs->cp0_epc = epc;
  85. break;
  86. case bgezal_op:
  87. case bgezall_op:
  88. regs->regs[31] = epc + 8;
  89. if ((long)regs->regs[insn.i_format.rs] >= 0)
  90. epc = epc + 4 + (insn.i_format.simmediate << 2);
  91. else
  92. epc += 8;
  93. regs->cp0_epc = epc;
  94. break;
  95. }
  96. break;
  97. /*
  98.  * These are unconditional and in j_format.
  99.  */
  100. case jal_op:
  101. regs->regs[31] = regs->cp0_epc + 8;
  102. case j_op:
  103. epc += 4;
  104. epc >>= 28;
  105. epc <<= 28;
  106. epc |= (insn.j_format.target << 2);
  107. regs->cp0_epc = epc;
  108. break;
  109. /*
  110.  * These are conditional and in i_format.
  111.  */
  112. case beq_op:
  113. case beql_op:
  114. if (regs->regs[insn.i_format.rs] ==
  115.     regs->regs[insn.i_format.rt])
  116. epc = epc + 4 + (insn.i_format.simmediate << 2);
  117. else
  118. epc += 8;
  119. regs->cp0_epc = epc;
  120. break;
  121. case bne_op:
  122. case bnel_op:
  123. if (regs->regs[insn.i_format.rs] !=
  124.     regs->regs[insn.i_format.rt])
  125. epc = epc + 4 + (insn.i_format.simmediate << 2);
  126. else
  127. epc += 8;
  128. regs->cp0_epc = epc;
  129. break;
  130. case blez_op: /* not really i_format */
  131. case blezl_op:
  132. /* rt field assumed to be zero */
  133. if ((long)regs->regs[insn.i_format.rs] <= 0)
  134. epc = epc + 4 + (insn.i_format.simmediate << 2);
  135. else
  136. epc += 8;
  137. regs->cp0_epc = epc;
  138. break;
  139. case bgtz_op:
  140. case bgtzl_op:
  141. /* rt field assumed to be zero */
  142. if ((long)regs->regs[insn.i_format.rs] > 0)
  143. epc = epc + 4 + (insn.i_format.simmediate << 2);
  144. else
  145. epc += 8;
  146. regs->cp0_epc = epc;
  147. break;
  148. /*
  149.  * And now the FPA/cp1 branch instructions.
  150.  */
  151. case cop1_op:
  152. if (!(mips_cpu.options & MIPS_CPU_FPU))
  153. fcr31 = current->thread.fpu.soft.sr;
  154. else
  155. asm("cfc1t%0,$31":"=r" (fcr31));
  156. bit = (insn.i_format.rt >> 2);
  157. bit += (bit != 0);
  158. bit += 23;
  159. switch (insn.i_format.rt) {
  160. case 0: /* bc1f */
  161. case 2: /* bc1fl */
  162. if (~fcr31 & (1 << bit))
  163. epc = epc + 4 + (insn.i_format.simmediate << 2);
  164. else
  165. epc += 8;
  166. regs->cp0_epc = epc;
  167. break;
  168. case 1: /* bc1t */
  169. case 3: /* bc1tl */
  170. if (fcr31 & (1 << bit))
  171. epc = epc + 4 + (insn.i_format.simmediate << 2);
  172. else
  173. epc += 8;
  174. regs->cp0_epc = epc;
  175. break;
  176. }
  177. break;
  178. }
  179. return 0;
  180. unaligned:
  181. printk("%s: unaligned epc - sending SIGBUS.n", current->comm);
  182. force_sig(SIGBUS, current);
  183. return -EFAULT;
  184. }