futex.h 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. #ifndef _ASM_X86_FUTEX_H
  2. #define _ASM_X86_FUTEX_H
  3. #ifdef __KERNEL__
  4. #include <linux/futex.h>
  5. #include <linux/uaccess.h>
  6. #include <asm/asm.h>
  7. #include <asm/errno.h>
  8. #include <asm/processor.h>
  9. #define __futex_atomic_op1(insn, ret, oldval, uaddr, oparg) \
  10. asm volatile("1:\t" insn "\n" \
  11. "2:\t.section .fixup,\"ax\"\n" \
  12. "3:\tmov\t%3, %1\n" \
  13. "\tjmp\t2b\n" \
  14. "\t.previous\n" \
  15. _ASM_EXTABLE(1b, 3b) \
  16. : "=r" (oldval), "=r" (ret), "+m" (*uaddr) \
  17. : "i" (-EFAULT), "0" (oparg), "1" (0))
  18. #define __futex_atomic_op2(insn, ret, oldval, uaddr, oparg) \
  19. asm volatile("1:\tmovl %2, %0\n" \
  20. "\tmovl\t%0, %3\n" \
  21. "\t" insn "\n" \
  22. "2:\t" LOCK_PREFIX "cmpxchgl %3, %2\n" \
  23. "\tjnz\t1b\n" \
  24. "3:\t.section .fixup,\"ax\"\n" \
  25. "4:\tmov\t%5, %1\n" \
  26. "\tjmp\t3b\n" \
  27. "\t.previous\n" \
  28. _ASM_EXTABLE(1b, 4b) \
  29. _ASM_EXTABLE(2b, 4b) \
  30. : "=&a" (oldval), "=&r" (ret), \
  31. "+m" (*uaddr), "=&r" (tem) \
  32. : "r" (oparg), "i" (-EFAULT), "1" (0))
  33. static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
  34. {
  35. int op = (encoded_op >> 28) & 7;
  36. int cmp = (encoded_op >> 24) & 15;
  37. int oparg = (encoded_op << 8) >> 20;
  38. int cmparg = (encoded_op << 20) >> 20;
  39. int oldval = 0, ret, tem;
  40. if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
  41. oparg = 1 << oparg;
  42. if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
  43. return -EFAULT;
  44. #if defined(CONFIG_X86_32) && !defined(CONFIG_X86_BSWAP)
  45. /* Real i386 machines can only support FUTEX_OP_SET */
  46. if (op != FUTEX_OP_SET && boot_cpu_data.x86 == 3)
  47. return -ENOSYS;
  48. #endif
  49. pagefault_disable();
  50. switch (op) {
  51. case FUTEX_OP_SET:
  52. __futex_atomic_op1("xchgl %0, %2", ret, oldval, uaddr, oparg);
  53. break;
  54. case FUTEX_OP_ADD:
  55. __futex_atomic_op1(LOCK_PREFIX "xaddl %0, %2", ret, oldval,
  56. uaddr, oparg);
  57. break;
  58. case FUTEX_OP_OR:
  59. __futex_atomic_op2("orl %4, %3", ret, oldval, uaddr, oparg);
  60. break;
  61. case FUTEX_OP_ANDN:
  62. __futex_atomic_op2("andl %4, %3", ret, oldval, uaddr, ~oparg);
  63. break;
  64. case FUTEX_OP_XOR:
  65. __futex_atomic_op2("xorl %4, %3", ret, oldval, uaddr, oparg);
  66. break;
  67. default:
  68. ret = -ENOSYS;
  69. }
  70. pagefault_enable();
  71. if (!ret) {
  72. switch (cmp) {
  73. case FUTEX_OP_CMP_EQ:
  74. ret = (oldval == cmparg);
  75. break;
  76. case FUTEX_OP_CMP_NE:
  77. ret = (oldval != cmparg);
  78. break;
  79. case FUTEX_OP_CMP_LT:
  80. ret = (oldval < cmparg);
  81. break;
  82. case FUTEX_OP_CMP_GE:
  83. ret = (oldval >= cmparg);
  84. break;
  85. case FUTEX_OP_CMP_LE:
  86. ret = (oldval <= cmparg);
  87. break;
  88. case FUTEX_OP_CMP_GT:
  89. ret = (oldval > cmparg);
  90. break;
  91. default:
  92. ret = -ENOSYS;
  93. }
  94. }
  95. return ret;
  96. }
  97. static inline int futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
  98. u32 oldval, u32 newval)
  99. {
  100. int ret = 0;
  101. #if defined(CONFIG_X86_32) && !defined(CONFIG_X86_BSWAP)
  102. /* Real i386 machines have no cmpxchg instruction */
  103. if (boot_cpu_data.x86 == 3)
  104. return -ENOSYS;
  105. #endif
  106. if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
  107. return -EFAULT;
  108. asm volatile("1:\t" LOCK_PREFIX "cmpxchgl %4, %2\n"
  109. "2:\t.section .fixup, \"ax\"\n"
  110. "3:\tmov %3, %0\n"
  111. "\tjmp 2b\n"
  112. "\t.previous\n"
  113. _ASM_EXTABLE(1b, 3b)
  114. : "+r" (ret), "=a" (oldval), "+m" (*uaddr)
  115. : "i" (-EFAULT), "r" (newval), "1" (oldval)
  116. : "memory"
  117. );
  118. *uval = oldval;
  119. return ret;
  120. }
  121. #endif
  122. #endif /* _ASM_X86_FUTEX_H */