futex.h 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
  1. /* SPDX-License-Identifier: GPL-2.0 */
  2. /*
  3. * Copyright (c) 2006 Ralf Baechle ([email protected])
  4. * Copyright (c) 2018 Jim Wilson ([email protected])
  5. */
  6. #ifndef _ASM_RISCV_FUTEX_H
  7. #define _ASM_RISCV_FUTEX_H
  8. #include <linux/futex.h>
  9. #include <linux/uaccess.h>
  10. #include <linux/errno.h>
  11. #include <asm/asm.h>
  12. #include <asm/asm-extable.h>
  13. /* We don't even really need the extable code, but for now keep it simple */
  14. #ifndef CONFIG_MMU
  15. #define __enable_user_access() do { } while (0)
  16. #define __disable_user_access() do { } while (0)
  17. #endif
  18. #define __futex_atomic_op(insn, ret, oldval, uaddr, oparg) \
  19. { \
  20. __enable_user_access(); \
  21. __asm__ __volatile__ ( \
  22. "1: " insn " \n" \
  23. "2: \n" \
  24. _ASM_EXTABLE_UACCESS_ERR(1b, 2b, %[r]) \
  25. : [r] "+r" (ret), [ov] "=&r" (oldval), \
  26. [u] "+m" (*uaddr) \
  27. : [op] "Jr" (oparg) \
  28. : "memory"); \
  29. __disable_user_access(); \
  30. }
  31. static inline int
  32. arch_futex_atomic_op_inuser(int op, int oparg, int *oval, u32 __user *uaddr)
  33. {
  34. int oldval = 0, ret = 0;
  35. if (!access_ok(uaddr, sizeof(u32)))
  36. return -EFAULT;
  37. switch (op) {
  38. case FUTEX_OP_SET:
  39. __futex_atomic_op("amoswap.w.aqrl %[ov],%z[op],%[u]",
  40. ret, oldval, uaddr, oparg);
  41. break;
  42. case FUTEX_OP_ADD:
  43. __futex_atomic_op("amoadd.w.aqrl %[ov],%z[op],%[u]",
  44. ret, oldval, uaddr, oparg);
  45. break;
  46. case FUTEX_OP_OR:
  47. __futex_atomic_op("amoor.w.aqrl %[ov],%z[op],%[u]",
  48. ret, oldval, uaddr, oparg);
  49. break;
  50. case FUTEX_OP_ANDN:
  51. __futex_atomic_op("amoand.w.aqrl %[ov],%z[op],%[u]",
  52. ret, oldval, uaddr, ~oparg);
  53. break;
  54. case FUTEX_OP_XOR:
  55. __futex_atomic_op("amoxor.w.aqrl %[ov],%z[op],%[u]",
  56. ret, oldval, uaddr, oparg);
  57. break;
  58. default:
  59. ret = -ENOSYS;
  60. }
  61. if (!ret)
  62. *oval = oldval;
  63. return ret;
  64. }
  65. static inline int
  66. futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
  67. u32 oldval, u32 newval)
  68. {
  69. int ret = 0;
  70. u32 val;
  71. uintptr_t tmp;
  72. if (!access_ok(uaddr, sizeof(u32)))
  73. return -EFAULT;
  74. __enable_user_access();
  75. __asm__ __volatile__ (
  76. "1: lr.w.aqrl %[v],%[u] \n"
  77. " bne %[v],%z[ov],3f \n"
  78. "2: sc.w.aqrl %[t],%z[nv],%[u] \n"
  79. " bnez %[t],1b \n"
  80. "3: \n"
  81. _ASM_EXTABLE_UACCESS_ERR(1b, 3b, %[r]) \
  82. _ASM_EXTABLE_UACCESS_ERR(2b, 3b, %[r]) \
  83. : [r] "+r" (ret), [v] "=&r" (val), [u] "+m" (*uaddr), [t] "=&r" (tmp)
  84. : [ov] "Jr" (oldval), [nv] "Jr" (newval)
  85. : "memory");
  86. __disable_user_access();
  87. *uval = val;
  88. return ret;
  89. }
  90. #endif /* _ASM_RISCV_FUTEX_H */