futex.h 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. #ifndef _ASM_S390_FUTEX_H
  2. #define _ASM_S390_FUTEX_H
  3. #include <linux/uaccess.h>
  4. #include <linux/futex.h>
  5. #include <asm/mmu_context.h>
  6. #include <asm/errno.h>
  7. #define __futex_atomic_op(insn, ret, oldval, newval, uaddr, oparg) \
  8. asm volatile( \
  9. " sacf 256\n" \
  10. "0: l %1,0(%6)\n" \
  11. "1:"insn \
  12. "2: cs %1,%2,0(%6)\n" \
  13. "3: jl 1b\n" \
  14. " lhi %0,0\n" \
  15. "4: sacf 768\n" \
  16. EX_TABLE(0b,4b) EX_TABLE(2b,4b) EX_TABLE(3b,4b) \
  17. : "=d" (ret), "=&d" (oldval), "=&d" (newval), \
  18. "=m" (*uaddr) \
  19. : "0" (-EFAULT), "d" (oparg), "a" (uaddr), \
  20. "m" (*uaddr) : "cc");
  21. static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
  22. {
  23. int op = (encoded_op >> 28) & 7;
  24. int cmp = (encoded_op >> 24) & 15;
  25. int oparg = (encoded_op << 8) >> 20;
  26. int cmparg = (encoded_op << 20) >> 20;
  27. int oldval = 0, newval, ret;
  28. load_kernel_asce();
  29. if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
  30. oparg = 1 << oparg;
  31. pagefault_disable();
  32. switch (op) {
  33. case FUTEX_OP_SET:
  34. __futex_atomic_op("lr %2,%5\n",
  35. ret, oldval, newval, uaddr, oparg);
  36. break;
  37. case FUTEX_OP_ADD:
  38. __futex_atomic_op("lr %2,%1\nar %2,%5\n",
  39. ret, oldval, newval, uaddr, oparg);
  40. break;
  41. case FUTEX_OP_OR:
  42. __futex_atomic_op("lr %2,%1\nor %2,%5\n",
  43. ret, oldval, newval, uaddr, oparg);
  44. break;
  45. case FUTEX_OP_ANDN:
  46. __futex_atomic_op("lr %2,%1\nnr %2,%5\n",
  47. ret, oldval, newval, uaddr, oparg);
  48. break;
  49. case FUTEX_OP_XOR:
  50. __futex_atomic_op("lr %2,%1\nxr %2,%5\n",
  51. ret, oldval, newval, uaddr, oparg);
  52. break;
  53. default:
  54. ret = -ENOSYS;
  55. }
  56. pagefault_enable();
  57. if (!ret) {
  58. switch (cmp) {
  59. case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
  60. case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
  61. case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
  62. case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
  63. case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
  64. case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
  65. default: ret = -ENOSYS;
  66. }
  67. }
  68. return ret;
  69. }
  70. static inline int futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
  71. u32 oldval, u32 newval)
  72. {
  73. int ret;
  74. load_kernel_asce();
  75. asm volatile(
  76. " sacf 256\n"
  77. "0: cs %1,%4,0(%5)\n"
  78. "1: la %0,0\n"
  79. "2: sacf 768\n"
  80. EX_TABLE(0b,2b) EX_TABLE(1b,2b)
  81. : "=d" (ret), "+d" (oldval), "=m" (*uaddr)
  82. : "0" (-EFAULT), "d" (newval), "a" (uaddr), "m" (*uaddr)
  83. : "cc", "memory");
  84. *uval = oldval;
  85. return ret;
  86. }
  87. #endif /* _ASM_S390_FUTEX_H */