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

嵌入式Linux

开发平台:

Unix_Linux

  1. /* $Id: muldiv.c,v 1.5 1997/12/15 20:07:20 ecd Exp $
  2.  * muldiv.c: Hardware multiply/division illegal instruction trap
  3.  * for sun4c/sun4 (which do not have those instructions)
  4.  *
  5.  * Copyright (C) 1996 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
  6.  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
  7.  */
  8. #include <linux/kernel.h>
  9. #include <linux/sched.h>
  10. #include <linux/mm.h>
  11. #include <asm/ptrace.h>
  12. #include <asm/processor.h>
  13. #include <asm/system.h>
  14. #include <asm/uaccess.h>
  15. /* #define DEBUG_MULDIV */
  16. static inline int has_imm13(int insn)
  17. {
  18. return (insn & 0x2000);
  19. }
  20. static inline int is_foocc(int insn)
  21. {
  22. return (insn & 0x800000);
  23. }
  24. static inline int sign_extend_imm13(int imm)
  25. {
  26. return imm << 19 >> 19;
  27. }
  28. static inline void advance(struct pt_regs *regs)
  29. {
  30. regs->pc   = regs->npc;
  31. regs->npc += 4;
  32. }
  33. static inline void maybe_flush_windows(unsigned int rs1, unsigned int rs2,
  34.        unsigned int rd)
  35. {
  36. if(rs2 >= 16 || rs1 >= 16 || rd >= 16) {
  37. /* Wheee... */
  38. __asm__ __volatile__("save %sp, -0x40, %spnt"
  39.      "save %sp, -0x40, %spnt"
  40.      "save %sp, -0x40, %spnt"
  41.      "save %sp, -0x40, %spnt"
  42.      "save %sp, -0x40, %spnt"
  43.      "save %sp, -0x40, %spnt"
  44.      "save %sp, -0x40, %spnt"
  45.      "restore; restore; restore; restore;nt"
  46.      "restore; restore; restore;nt");
  47. }
  48. }
  49. #define fetch_reg(reg, regs) ({
  50. struct reg_window *win;
  51. register unsigned long ret;
  52. if (!(reg)) ret = 0;
  53. else if((reg) < 16) {
  54. ret = regs->u_regs[(reg)];
  55. } else {
  56. /* Ho hum, the slightly complicated case. */
  57. win = (struct reg_window *)regs->u_regs[UREG_FP];
  58. if (get_user (ret, &win->locals[(reg) - 16])) return -1;
  59. }
  60. ret;
  61. })
  62. static inline int
  63. store_reg(unsigned int result, unsigned int reg, struct pt_regs *regs)
  64. {
  65. struct reg_window *win;
  66. if (!reg)
  67. return 0;
  68. if (reg < 16) {
  69. regs->u_regs[reg] = result;
  70. return 0;
  71. } else {
  72. /* need to use put_user() in this case: */
  73. win = (struct reg_window *)regs->u_regs[UREG_FP];
  74. return (put_user(result, &win->locals[reg - 16]));
  75. }
  76. }
  77. extern void handle_hw_divzero (struct pt_regs *regs, unsigned long pc,
  78.        unsigned long npc, unsigned long psr);
  79. /* Should return 0 if mul/div emulation succeeded and SIGILL should not be issued */
  80. int do_user_muldiv(struct pt_regs *regs, unsigned long pc)
  81. {
  82. unsigned int insn;
  83. int inst;
  84. unsigned int rs1, rs2, rdv;
  85. if (!pc) return -1; /* This happens to often, I think */
  86. if (get_user (insn, (unsigned int *)pc)) return -1;
  87. if ((insn & 0xc1400000) != 0x80400000) return -1;
  88. inst = ((insn >> 19) & 0xf);
  89. if ((inst & 0xe) != 10 && (inst & 0xe) != 14) return -1;
  90. /* Now we know we have to do something with umul, smul, udiv or sdiv */
  91. rs1 = (insn >> 14) & 0x1f;
  92. rs2 = insn & 0x1f;
  93. rdv = (insn >> 25) & 0x1f;
  94. if(has_imm13(insn)) {
  95. maybe_flush_windows(rs1, 0, rdv);
  96. rs2 = sign_extend_imm13(insn);
  97. } else {
  98. maybe_flush_windows(rs1, rs2, rdv);
  99. rs2 = fetch_reg(rs2, regs);
  100. }
  101. rs1 = fetch_reg(rs1, regs);
  102. switch (inst) {
  103. case 10: /* umul */
  104. #ifdef DEBUG_MULDIV
  105. printk ("unsigned muldiv: 0x%x * 0x%x = ", rs1, rs2);
  106. #endif
  107. __asm__ __volatile__ ("nt"
  108. "mov %0, %%o0nt"
  109. "call .umulnt"
  110. " mov %1, %%o1nt"
  111. "mov %%o0, %0nt"
  112. "mov %%o1, %1nt"
  113. : "=r" (rs1), "=r" (rs2)
  114.         :
  115. : "o0", "o1", "o2", "o3", "o4", "o5", "o7", "cc");
  116. #ifdef DEBUG_MULDIV
  117. printk ("0x%x%08xn", rs2, rs1);
  118. #endif
  119. if (store_reg(rs1, rdv, regs))
  120. return -1;
  121. regs->y = rs2;
  122. break;
  123. case 11: /* smul */
  124. #ifdef DEBUG_MULDIV
  125. printk ("signed muldiv: 0x%x * 0x%x = ", rs1, rs2);
  126. #endif
  127. __asm__ __volatile__ ("nt"
  128. "mov %0, %%o0nt"
  129. "call .mulnt"
  130. " mov %1, %%o1nt"
  131. "mov %%o0, %0nt"
  132. "mov %%o1, %1nt"
  133. : "=r" (rs1), "=r" (rs2)
  134. :
  135. : "o0", "o1", "o2", "o3", "o4", "o5", "o7", "cc");
  136. #ifdef DEBUG_MULDIV
  137. printk ("0x%x%08xn", rs2, rs1);
  138. #endif
  139. if (store_reg(rs1, rdv, regs))
  140. return -1;
  141. regs->y = rs2;
  142. break;
  143. case 14: /* udiv */
  144. #ifdef DEBUG_MULDIV
  145. printk ("unsigned muldiv: 0x%x%08x / 0x%x = ", regs->y, rs1, rs2);
  146. #endif
  147. if (!rs2) {
  148. #ifdef DEBUG_MULDIV
  149. printk ("DIVISION BY ZEROn");
  150. #endif
  151. handle_hw_divzero (regs, pc, regs->npc, regs->psr);
  152. return 0;
  153. }
  154. __asm__ __volatile__ ("nt"
  155. "mov %2, %%o0nt"
  156. "mov %0, %%o1nt"
  157. "mov %%g0, %%o2nt"
  158. "call __udivdi3nt"
  159. " mov %1, %%o3nt"
  160. "mov %%o1, %0nt"
  161. "mov %%o0, %1nt"
  162. : "=r" (rs1), "=r" (rs2)
  163. : "r" (regs->y)
  164. : "o0", "o1", "o2", "o3", "o4", "o5", "o7",
  165.   "g1", "g2", "g3", "cc");
  166. #ifdef DEBUG_MULDIV
  167. printk ("0x%xn", rs1);
  168. #endif
  169. if (store_reg(rs1, rdv, regs))
  170. return -1;
  171. break;
  172. case 15: /* sdiv */
  173. #ifdef DEBUG_MULDIV
  174. printk ("signed muldiv: 0x%x%08x / 0x%x = ", regs->y, rs1, rs2);
  175. #endif
  176. if (!rs2) {
  177. #ifdef DEBUG_MULDIV
  178. printk ("DIVISION BY ZEROn");
  179. #endif
  180. handle_hw_divzero (regs, pc, regs->npc, regs->psr);
  181. return 0;
  182. }
  183. __asm__ __volatile__ ("nt"
  184. "mov %2, %%o0nt"
  185. "mov %0, %%o1nt"
  186. "mov %%g0, %%o2nt"
  187. "call __divdi3nt"
  188. " mov %1, %%o3nt"
  189. "mov %%o1, %0nt"
  190. "mov %%o0, %1nt"
  191. : "=r" (rs1), "=r" (rs2)
  192. : "r" (regs->y)
  193. : "o0", "o1", "o2", "o3", "o4", "o5", "o7",
  194.   "g1", "g2", "g3", "cc");
  195. #ifdef DEBUG_MULDIV
  196. printk ("0x%xn", rs1);
  197. #endif
  198. if (store_reg(rs1, rdv, regs))
  199. return -1;
  200. break;
  201. }
  202. if (is_foocc (insn)) {
  203. regs->psr &= ~PSR_ICC;
  204. if ((inst & 0xe) == 14) {
  205. /* ?div */
  206. if (rs2) regs->psr |= PSR_V;
  207. }
  208. if (!rs1) regs->psr |= PSR_Z;
  209. if (((int)rs1) < 0) regs->psr |= PSR_N;
  210. #ifdef DEBUG_MULDIV
  211. printk ("psr muldiv: %08xn", regs->psr);
  212. #endif
  213. }
  214. advance(regs);
  215. return 0;
  216. }