branch.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:4k
源码类别:

嵌入式Linux

开发平台:

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/inst.h>
  15. #include <asm/ptrace.h>
  16. #include <asm/uaccess.h>
  17. /*
  18.  * Compute the return address and do emulate branch simulation, if required.
  19.  */
  20. int __compute_return_epc(struct pt_regs *regs)
  21. {
  22. unsigned int *addr, bit, fcr31;
  23. long epc;
  24. union mips_instruction insn;
  25. epc = regs->cp0_epc;
  26. if (epc & 3) {
  27. printk("%s: unaligned epc - sending SIGBUS.n", current->comm);
  28. force_sig(SIGBUS, current);
  29. return -EFAULT;
  30. }
  31. /*
  32.  * Read the instruction
  33.  */
  34. addr = (unsigned int *) 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. asm ("cfc1t%0,$31":"=r" (fcr31));
  153. bit = (insn.i_format.rt >> 2);
  154. bit += (bit != 0);
  155. bit += 23;
  156. switch (insn.i_format.rt) {
  157. case 0: /* bc1f */
  158. case 2: /* bc1fl */
  159. if (~fcr31 & (1 << bit))
  160. epc = epc + 4 + (insn.i_format.simmediate << 2);
  161. else
  162. epc += 8;
  163. regs->cp0_epc = epc;
  164. break;
  165. case 1: /* bc1t */
  166. case 3: /* bc1tl */
  167. if (fcr31 & (1 << bit))
  168. epc = epc + 4 + (insn.i_format.simmediate << 2);
  169. else
  170. epc += 8;
  171. regs->cp0_epc = epc;
  172. break;
  173. }
  174. break;
  175. }
  176. return 0;
  177. }