futex.h 2.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  1. /* SPDX-License-Identifier: GPL-2.0 */
  2. #ifndef _ASM_POWERPC_FUTEX_H
  3. #define _ASM_POWERPC_FUTEX_H
  4. #ifdef __KERNEL__
  5. #include <linux/futex.h>
  6. #include <linux/uaccess.h>
  7. #include <asm/errno.h>
  8. #include <asm/synch.h>
  9. #define __futex_atomic_op(insn, ret, oldval, uaddr, oparg) \
  10. __asm__ __volatile ( \
  11. PPC_ATOMIC_ENTRY_BARRIER \
  12. "1: lwarx %0,0,%2\n" \
  13. insn \
  14. "2: stwcx. %1,0,%2\n" \
  15. "bne- 1b\n" \
  16. PPC_ATOMIC_EXIT_BARRIER \
  17. "li %1,0\n" \
  18. "3: .section .fixup,\"ax\"\n" \
  19. "4: li %1,%3\n" \
  20. "b 3b\n" \
  21. ".previous\n" \
  22. EX_TABLE(1b, 4b) \
  23. EX_TABLE(2b, 4b) \
  24. : "=&r" (oldval), "=&r" (ret) \
  25. : "b" (uaddr), "i" (-EFAULT), "r" (oparg) \
  26. : "cr0", "memory")
  27. static inline int arch_futex_atomic_op_inuser(int op, int oparg, int *oval,
  28. u32 __user *uaddr)
  29. {
  30. int oldval = 0, ret;
  31. if (!user_access_begin(uaddr, sizeof(u32)))
  32. return -EFAULT;
  33. switch (op) {
  34. case FUTEX_OP_SET:
  35. __futex_atomic_op("mr %1,%4\n", ret, oldval, uaddr, oparg);
  36. break;
  37. case FUTEX_OP_ADD:
  38. __futex_atomic_op("add %1,%0,%4\n", ret, oldval, uaddr, oparg);
  39. break;
  40. case FUTEX_OP_OR:
  41. __futex_atomic_op("or %1,%0,%4\n", ret, oldval, uaddr, oparg);
  42. break;
  43. case FUTEX_OP_ANDN:
  44. __futex_atomic_op("andc %1,%0,%4\n", ret, oldval, uaddr, oparg);
  45. break;
  46. case FUTEX_OP_XOR:
  47. __futex_atomic_op("xor %1,%0,%4\n", ret, oldval, uaddr, oparg);
  48. break;
  49. default:
  50. ret = -ENOSYS;
  51. }
  52. user_access_end();
  53. *oval = oldval;
  54. return ret;
  55. }
  56. static inline int
  57. futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
  58. u32 oldval, u32 newval)
  59. {
  60. int ret = 0;
  61. u32 prev;
  62. if (!user_access_begin(uaddr, sizeof(u32)))
  63. return -EFAULT;
  64. __asm__ __volatile__ (
  65. PPC_ATOMIC_ENTRY_BARRIER
  66. "1: lwarx %1,0,%3 # futex_atomic_cmpxchg_inatomic\n\
  67. cmpw 0,%1,%4\n\
  68. bne- 3f\n"
  69. "2: stwcx. %5,0,%3\n\
  70. bne- 1b\n"
  71. PPC_ATOMIC_EXIT_BARRIER
  72. "3: .section .fixup,\"ax\"\n\
  73. 4: li %0,%6\n\
  74. b 3b\n\
  75. .previous\n"
  76. EX_TABLE(1b, 4b)
  77. EX_TABLE(2b, 4b)
  78. : "+r" (ret), "=&r" (prev), "+m" (*uaddr)
  79. : "r" (uaddr), "r" (oldval), "r" (newval), "i" (-EFAULT)
  80. : "cc", "memory");
  81. user_access_end();
  82. *uval = prev;
  83. return ret;
  84. }
  85. #endif /* __KERNEL__ */
  86. #endif /* _ASM_POWERPC_FUTEX_H */