futex.c 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
  1. /* futex.c: futex operations
  2. *
  3. * Copyright (C) 2005 Red Hat, Inc. All Rights Reserved.
  4. * Written by David Howells (dhowells@redhat.com)
  5. *
  6. * This program is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU General Public License
  8. * as published by the Free Software Foundation; either version
  9. * 2 of the License, or (at your option) any later version.
  10. */
  11. #include <linux/futex.h>
  12. #include <linux/uaccess.h>
  13. #include <asm/futex.h>
  14. #include <asm/errno.h>
  15. /*
  16. * the various futex operations; MMU fault checking is ignored under no-MMU
  17. * conditions
  18. */
  19. static inline int atomic_futex_op_xchg_set(int oparg, u32 __user *uaddr, int *_oldval)
  20. {
  21. int oldval, ret;
  22. asm("0: \n"
  23. " orcc gr0,gr0,gr0,icc3 \n" /* set ICC3.Z */
  24. " ckeq icc3,cc7 \n"
  25. "1: ld.p %M0,%1 \n" /* LD.P/ORCR must be atomic */
  26. " orcr cc7,cc7,cc3 \n" /* set CC3 to true */
  27. "2: cst.p %3,%M0 ,cc3,#1 \n"
  28. " corcc gr29,gr29,gr0 ,cc3,#1 \n" /* clear ICC3.Z if store happens */
  29. " beq icc3,#0,0b \n"
  30. " setlos 0,%2 \n"
  31. "3: \n"
  32. ".subsection 2 \n"
  33. "4: setlos %5,%2 \n"
  34. " bra 3b \n"
  35. ".previous \n"
  36. ".section __ex_table,\"a\" \n"
  37. " .balign 8 \n"
  38. " .long 1b,4b \n"
  39. " .long 2b,4b \n"
  40. ".previous"
  41. : "+U"(*uaddr), "=&r"(oldval), "=&r"(ret), "=r"(oparg)
  42. : "3"(oparg), "i"(-EFAULT)
  43. : "memory", "cc7", "cc3", "icc3"
  44. );
  45. *_oldval = oldval;
  46. return ret;
  47. }
  48. static inline int atomic_futex_op_xchg_add(int oparg, u32 __user *uaddr, int *_oldval)
  49. {
  50. int oldval, ret;
  51. asm("0: \n"
  52. " orcc gr0,gr0,gr0,icc3 \n" /* set ICC3.Z */
  53. " ckeq icc3,cc7 \n"
  54. "1: ld.p %M0,%1 \n" /* LD.P/ORCR must be atomic */
  55. " orcr cc7,cc7,cc3 \n" /* set CC3 to true */
  56. " add %1,%3,%3 \n"
  57. "2: cst.p %3,%M0 ,cc3,#1 \n"
  58. " corcc gr29,gr29,gr0 ,cc3,#1 \n" /* clear ICC3.Z if store happens */
  59. " beq icc3,#0,0b \n"
  60. " setlos 0,%2 \n"
  61. "3: \n"
  62. ".subsection 2 \n"
  63. "4: setlos %5,%2 \n"
  64. " bra 3b \n"
  65. ".previous \n"
  66. ".section __ex_table,\"a\" \n"
  67. " .balign 8 \n"
  68. " .long 1b,4b \n"
  69. " .long 2b,4b \n"
  70. ".previous"
  71. : "+U"(*uaddr), "=&r"(oldval), "=&r"(ret), "=r"(oparg)
  72. : "3"(oparg), "i"(-EFAULT)
  73. : "memory", "cc7", "cc3", "icc3"
  74. );
  75. *_oldval = oldval;
  76. return ret;
  77. }
  78. static inline int atomic_futex_op_xchg_or(int oparg, u32 __user *uaddr, int *_oldval)
  79. {
  80. int oldval, ret;
  81. asm("0: \n"
  82. " orcc gr0,gr0,gr0,icc3 \n" /* set ICC3.Z */
  83. " ckeq icc3,cc7 \n"
  84. "1: ld.p %M0,%1 \n" /* LD.P/ORCR must be atomic */
  85. " orcr cc7,cc7,cc3 \n" /* set CC3 to true */
  86. " or %1,%3,%3 \n"
  87. "2: cst.p %3,%M0 ,cc3,#1 \n"
  88. " corcc gr29,gr29,gr0 ,cc3,#1 \n" /* clear ICC3.Z if store happens */
  89. " beq icc3,#0,0b \n"
  90. " setlos 0,%2 \n"
  91. "3: \n"
  92. ".subsection 2 \n"
  93. "4: setlos %5,%2 \n"
  94. " bra 3b \n"
  95. ".previous \n"
  96. ".section __ex_table,\"a\" \n"
  97. " .balign 8 \n"
  98. " .long 1b,4b \n"
  99. " .long 2b,4b \n"
  100. ".previous"
  101. : "+U"(*uaddr), "=&r"(oldval), "=&r"(ret), "=r"(oparg)
  102. : "3"(oparg), "i"(-EFAULT)
  103. : "memory", "cc7", "cc3", "icc3"
  104. );
  105. *_oldval = oldval;
  106. return ret;
  107. }
  108. static inline int atomic_futex_op_xchg_and(int oparg, u32 __user *uaddr, int *_oldval)
  109. {
  110. int oldval, ret;
  111. asm("0: \n"
  112. " orcc gr0,gr0,gr0,icc3 \n" /* set ICC3.Z */
  113. " ckeq icc3,cc7 \n"
  114. "1: ld.p %M0,%1 \n" /* LD.P/ORCR must be atomic */
  115. " orcr cc7,cc7,cc3 \n" /* set CC3 to true */
  116. " and %1,%3,%3 \n"
  117. "2: cst.p %3,%M0 ,cc3,#1 \n"
  118. " corcc gr29,gr29,gr0 ,cc3,#1 \n" /* clear ICC3.Z if store happens */
  119. " beq icc3,#0,0b \n"
  120. " setlos 0,%2 \n"
  121. "3: \n"
  122. ".subsection 2 \n"
  123. "4: setlos %5,%2 \n"
  124. " bra 3b \n"
  125. ".previous \n"
  126. ".section __ex_table,\"a\" \n"
  127. " .balign 8 \n"
  128. " .long 1b,4b \n"
  129. " .long 2b,4b \n"
  130. ".previous"
  131. : "+U"(*uaddr), "=&r"(oldval), "=&r"(ret), "=r"(oparg)
  132. : "3"(oparg), "i"(-EFAULT)
  133. : "memory", "cc7", "cc3", "icc3"
  134. );
  135. *_oldval = oldval;
  136. return ret;
  137. }
  138. static inline int atomic_futex_op_xchg_xor(int oparg, u32 __user *uaddr, int *_oldval)
  139. {
  140. int oldval, ret;
  141. asm("0: \n"
  142. " orcc gr0,gr0,gr0,icc3 \n" /* set ICC3.Z */
  143. " ckeq icc3,cc7 \n"
  144. "1: ld.p %M0,%1 \n" /* LD.P/ORCR must be atomic */
  145. " orcr cc7,cc7,cc3 \n" /* set CC3 to true */
  146. " xor %1,%3,%3 \n"
  147. "2: cst.p %3,%M0 ,cc3,#1 \n"
  148. " corcc gr29,gr29,gr0 ,cc3,#1 \n" /* clear ICC3.Z if store happens */
  149. " beq icc3,#0,0b \n"
  150. " setlos 0,%2 \n"
  151. "3: \n"
  152. ".subsection 2 \n"
  153. "4: setlos %5,%2 \n"
  154. " bra 3b \n"
  155. ".previous \n"
  156. ".section __ex_table,\"a\" \n"
  157. " .balign 8 \n"
  158. " .long 1b,4b \n"
  159. " .long 2b,4b \n"
  160. ".previous"
  161. : "+U"(*uaddr), "=&r"(oldval), "=&r"(ret), "=r"(oparg)
  162. : "3"(oparg), "i"(-EFAULT)
  163. : "memory", "cc7", "cc3", "icc3"
  164. );
  165. *_oldval = oldval;
  166. return ret;
  167. }
  168. /*****************************************************************************/
  169. /*
  170. * do the futex operations
  171. */
  172. int arch_futex_atomic_op_inuser(int op, int oparg, int *oval, u32 __user *uaddr)
  173. {
  174. int oldval = 0, ret;
  175. pagefault_disable();
  176. switch (op) {
  177. case FUTEX_OP_SET:
  178. ret = atomic_futex_op_xchg_set(oparg, uaddr, &oldval);
  179. break;
  180. case FUTEX_OP_ADD:
  181. ret = atomic_futex_op_xchg_add(oparg, uaddr, &oldval);
  182. break;
  183. case FUTEX_OP_OR:
  184. ret = atomic_futex_op_xchg_or(oparg, uaddr, &oldval);
  185. break;
  186. case FUTEX_OP_ANDN:
  187. ret = atomic_futex_op_xchg_and(~oparg, uaddr, &oldval);
  188. break;
  189. case FUTEX_OP_XOR:
  190. ret = atomic_futex_op_xchg_xor(oparg, uaddr, &oldval);
  191. break;
  192. default:
  193. ret = -ENOSYS;
  194. break;
  195. }
  196. pagefault_enable();
  197. if (!ret)
  198. *oval = oldval;
  199. return ret;
  200. } /* end arch_futex_atomic_op_inuser() */