futex.h 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  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. * Copyright (c) 2006 Ralf Baechle (ralf@linux-mips.org)
  7. */
  8. #ifndef _ASM_FUTEX_H
  9. #define _ASM_FUTEX_H
  10. #ifdef __KERNEL__
  11. #include <linux/futex.h>
  12. #include <linux/uaccess.h>
  13. #include <asm/barrier.h>
  14. #include <asm/errno.h>
  15. #include <asm/war.h>
  16. #define __futex_atomic_op(insn, ret, oldval, uaddr, oparg) \
  17. { \
  18. if (cpu_has_llsc && R10000_LLSC_WAR) { \
  19. __asm__ __volatile__( \
  20. " .set push \n" \
  21. " .set noat \n" \
  22. " .set mips3 \n" \
  23. "1: ll %1, %4 # __futex_atomic_op \n" \
  24. " .set mips0 \n" \
  25. " " insn " \n" \
  26. " .set mips3 \n" \
  27. "2: sc $1, %2 \n" \
  28. " beqzl $1, 1b \n" \
  29. __WEAK_LLSC_MB \
  30. "3: \n" \
  31. " .set pop \n" \
  32. " .set mips0 \n" \
  33. " .section .fixup,\"ax\" \n" \
  34. "4: li %0, %6 \n" \
  35. " j 3b \n" \
  36. " .previous \n" \
  37. " .section __ex_table,\"a\" \n" \
  38. " "__UA_ADDR "\t1b, 4b \n" \
  39. " "__UA_ADDR "\t2b, 4b \n" \
  40. " .previous \n" \
  41. : "=r" (ret), "=&r" (oldval), "=R" (*uaddr) \
  42. : "0" (0), "R" (*uaddr), "Jr" (oparg), "i" (-EFAULT) \
  43. : "memory"); \
  44. } else if (cpu_has_llsc) { \
  45. __asm__ __volatile__( \
  46. " .set push \n" \
  47. " .set noat \n" \
  48. " .set mips3 \n" \
  49. "1: ll %1, %4 # __futex_atomic_op \n" \
  50. " .set mips0 \n" \
  51. " " insn " \n" \
  52. " .set mips3 \n" \
  53. "2: sc $1, %2 \n" \
  54. " beqz $1, 1b \n" \
  55. __WEAK_LLSC_MB \
  56. "3: \n" \
  57. " .set pop \n" \
  58. " .set mips0 \n" \
  59. " .section .fixup,\"ax\" \n" \
  60. "4: li %0, %6 \n" \
  61. " j 3b \n" \
  62. " .previous \n" \
  63. " .section __ex_table,\"a\" \n" \
  64. " "__UA_ADDR "\t1b, 4b \n" \
  65. " "__UA_ADDR "\t2b, 4b \n" \
  66. " .previous \n" \
  67. : "=r" (ret), "=&r" (oldval), "=R" (*uaddr) \
  68. : "0" (0), "R" (*uaddr), "Jr" (oparg), "i" (-EFAULT) \
  69. : "memory"); \
  70. } else \
  71. ret = -ENOSYS; \
  72. }
  73. static inline int
  74. futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
  75. {
  76. int op = (encoded_op >> 28) & 7;
  77. int cmp = (encoded_op >> 24) & 15;
  78. int oparg = (encoded_op << 8) >> 20;
  79. int cmparg = (encoded_op << 20) >> 20;
  80. int oldval = 0, ret;
  81. if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
  82. oparg = 1 << oparg;
  83. if (! access_ok (VERIFY_WRITE, uaddr, sizeof(u32)))
  84. return -EFAULT;
  85. pagefault_disable();
  86. switch (op) {
  87. case FUTEX_OP_SET:
  88. __futex_atomic_op("move $1, %z5", ret, oldval, uaddr, oparg);
  89. break;
  90. case FUTEX_OP_ADD:
  91. __futex_atomic_op("addu $1, %1, %z5",
  92. ret, oldval, uaddr, oparg);
  93. break;
  94. case FUTEX_OP_OR:
  95. __futex_atomic_op("or $1, %1, %z5",
  96. ret, oldval, uaddr, oparg);
  97. break;
  98. case FUTEX_OP_ANDN:
  99. __futex_atomic_op("and $1, %1, %z5",
  100. ret, oldval, uaddr, ~oparg);
  101. break;
  102. case FUTEX_OP_XOR:
  103. __futex_atomic_op("xor $1, %1, %z5",
  104. ret, oldval, uaddr, oparg);
  105. break;
  106. default:
  107. ret = -ENOSYS;
  108. }
  109. pagefault_enable();
  110. if (!ret) {
  111. switch (cmp) {
  112. case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
  113. case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
  114. case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
  115. case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
  116. case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
  117. case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
  118. default: ret = -ENOSYS;
  119. }
  120. }
  121. return ret;
  122. }
  123. static inline int
  124. futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
  125. u32 oldval, u32 newval)
  126. {
  127. int ret = 0;
  128. u32 val;
  129. if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
  130. return -EFAULT;
  131. if (cpu_has_llsc && R10000_LLSC_WAR) {
  132. __asm__ __volatile__(
  133. "# futex_atomic_cmpxchg_inatomic \n"
  134. " .set push \n"
  135. " .set noat \n"
  136. " .set mips3 \n"
  137. "1: ll %1, %3 \n"
  138. " bne %1, %z4, 3f \n"
  139. " .set mips0 \n"
  140. " move $1, %z5 \n"
  141. " .set mips3 \n"
  142. "2: sc $1, %2 \n"
  143. " beqzl $1, 1b \n"
  144. __WEAK_LLSC_MB
  145. "3: \n"
  146. " .set pop \n"
  147. " .section .fixup,\"ax\" \n"
  148. "4: li %0, %6 \n"
  149. " j 3b \n"
  150. " .previous \n"
  151. " .section __ex_table,\"a\" \n"
  152. " "__UA_ADDR "\t1b, 4b \n"
  153. " "__UA_ADDR "\t2b, 4b \n"
  154. " .previous \n"
  155. : "+r" (ret), "=&r" (val), "=R" (*uaddr)
  156. : "R" (*uaddr), "Jr" (oldval), "Jr" (newval), "i" (-EFAULT)
  157. : "memory");
  158. } else if (cpu_has_llsc) {
  159. __asm__ __volatile__(
  160. "# futex_atomic_cmpxchg_inatomic \n"
  161. " .set push \n"
  162. " .set noat \n"
  163. " .set mips3 \n"
  164. "1: ll %1, %3 \n"
  165. " bne %1, %z4, 3f \n"
  166. " .set mips0 \n"
  167. " move $1, %z5 \n"
  168. " .set mips3 \n"
  169. "2: sc $1, %2 \n"
  170. " beqz $1, 1b \n"
  171. __WEAK_LLSC_MB
  172. "3: \n"
  173. " .set pop \n"
  174. " .section .fixup,\"ax\" \n"
  175. "4: li %0, %6 \n"
  176. " j 3b \n"
  177. " .previous \n"
  178. " .section __ex_table,\"a\" \n"
  179. " "__UA_ADDR "\t1b, 4b \n"
  180. " "__UA_ADDR "\t2b, 4b \n"
  181. " .previous \n"
  182. : "+r" (ret), "=&r" (val), "=R" (*uaddr)
  183. : "R" (*uaddr), "Jr" (oldval), "Jr" (newval), "i" (-EFAULT)
  184. : "memory");
  185. } else
  186. return -ENOSYS;
  187. *uval = val;
  188. return ret;
  189. }
  190. #endif
  191. #endif /* _ASM_FUTEX_H */