futex.h 2.2 KB

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