futex.h 1.9 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283
  1. #ifndef _ASM_FUTEX_H
  2. #define _ASM_FUTEX_H
  3. #ifdef __KERNEL__
  4. #include <linux/futex.h>
  5. #include <asm/errno.h>
  6. #include <asm/memory.h>
  7. #include <asm/uaccess.h>
  8. #define __futex_atomic_op(insn, ret, oldval, uaddr, oparg) \
  9. __asm__ __volatile (SYNC_ON_SMP \
  10. "1: lwarx %0,0,%2\n" \
  11. insn \
  12. "2: stwcx. %1,0,%2\n\
  13. bne- 1b\n\
  14. li %1,0\n\
  15. 3: .section .fixup,\"ax\"\n\
  16. 4: li %1,%3\n\
  17. b 3b\n\
  18. .previous\n\
  19. .section __ex_table,\"a\"\n\
  20. .align 3\n\
  21. .llong 1b,4b,2b,4b\n\
  22. .previous" \
  23. : "=&r" (oldval), "=&r" (ret) \
  24. : "b" (uaddr), "i" (-EFAULT), "1" (oparg) \
  25. : "cr0", "memory")
  26. static inline int
  27. futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
  28. {
  29. int op = (encoded_op >> 28) & 7;
  30. int cmp = (encoded_op >> 24) & 15;
  31. int oparg = (encoded_op << 8) >> 20;
  32. int cmparg = (encoded_op << 20) >> 20;
  33. int oldval = 0, ret;
  34. if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
  35. oparg = 1 << oparg;
  36. if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int)))
  37. return -EFAULT;
  38. inc_preempt_count();
  39. switch (op) {
  40. case FUTEX_OP_SET:
  41. __futex_atomic_op("", ret, oldval, uaddr, oparg);
  42. break;
  43. case FUTEX_OP_ADD:
  44. __futex_atomic_op("add %1,%0,%1\n", ret, oldval, uaddr, oparg);
  45. break;
  46. case FUTEX_OP_OR:
  47. __futex_atomic_op("or %1,%0,%1\n", ret, oldval, uaddr, oparg);
  48. break;
  49. case FUTEX_OP_ANDN:
  50. __futex_atomic_op("andc %1,%0,%1\n", ret, oldval, uaddr, oparg);
  51. break;
  52. case FUTEX_OP_XOR:
  53. __futex_atomic_op("xor %1,%0,%1\n", ret, oldval, uaddr, oparg);
  54. break;
  55. default:
  56. ret = -ENOSYS;
  57. }
  58. dec_preempt_count();
  59. if (!ret) {
  60. switch (cmp) {
  61. case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
  62. case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
  63. case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
  64. case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
  65. case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
  66. case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
  67. default: ret = -ENOSYS;
  68. }
  69. }
  70. return ret;
  71. }
  72. #endif
  73. #endif