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

Linux/Unix编程

开发平台:

Unix_Linux

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