futex.h 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. /* SPDX-License-Identifier: GPL-2.0 */
  2. /*
  3. * Copyright (c) 2006 Ralf Baechle (ralf@linux-mips.org)
  4. * Copyright (c) 2018 Jim Wilson (jimw@sifive.com)
  5. */
  6. #ifndef _ASM_FUTEX_H
  7. #define _ASM_FUTEX_H
  8. #ifndef CONFIG_RISCV_ISA_A
  9. /*
  10. * Use the generic interrupt disabling versions if the A extension
  11. * is not supported.
  12. */
  13. #ifdef CONFIG_SMP
  14. #error "Can't support generic futex calls without A extension on SMP"
  15. #endif
  16. #include <asm-generic/futex.h>
  17. #else /* CONFIG_RISCV_ISA_A */
  18. #include <linux/futex.h>
  19. #include <linux/uaccess.h>
  20. #include <linux/errno.h>
  21. #include <asm/asm.h>
  22. #define __futex_atomic_op(insn, ret, oldval, uaddr, oparg) \
  23. { \
  24. uintptr_t tmp; \
  25. __enable_user_access(); \
  26. __asm__ __volatile__ ( \
  27. "1: " insn " \n" \
  28. "2: \n" \
  29. " .section .fixup,\"ax\" \n" \
  30. " .balign 4 \n" \
  31. "3: li %[r],%[e] \n" \
  32. " jump 2b,%[t] \n" \
  33. " .previous \n" \
  34. " .section __ex_table,\"a\" \n" \
  35. " .balign " RISCV_SZPTR " \n" \
  36. " " RISCV_PTR " 1b, 3b \n" \
  37. " .previous \n" \
  38. : [r] "+r" (ret), [ov] "=&r" (oldval), \
  39. [u] "+m" (*uaddr), [t] "=&r" (tmp) \
  40. : [op] "Jr" (oparg), [e] "i" (-EFAULT) \
  41. : "memory"); \
  42. __disable_user_access(); \
  43. }
  44. static inline int
  45. arch_futex_atomic_op_inuser(int op, int oparg, int *oval, u32 __user *uaddr)
  46. {
  47. int oldval = 0, ret = 0;
  48. pagefault_disable();
  49. switch (op) {
  50. case FUTEX_OP_SET:
  51. __futex_atomic_op("amoswap.w.aqrl %[ov],%z[op],%[u]",
  52. ret, oldval, uaddr, oparg);
  53. break;
  54. case FUTEX_OP_ADD:
  55. __futex_atomic_op("amoadd.w.aqrl %[ov],%z[op],%[u]",
  56. ret, oldval, uaddr, oparg);
  57. break;
  58. case FUTEX_OP_OR:
  59. __futex_atomic_op("amoor.w.aqrl %[ov],%z[op],%[u]",
  60. ret, oldval, uaddr, oparg);
  61. break;
  62. case FUTEX_OP_ANDN:
  63. __futex_atomic_op("amoand.w.aqrl %[ov],%z[op],%[u]",
  64. ret, oldval, uaddr, ~oparg);
  65. break;
  66. case FUTEX_OP_XOR:
  67. __futex_atomic_op("amoxor.w.aqrl %[ov],%z[op],%[u]",
  68. ret, oldval, uaddr, oparg);
  69. break;
  70. default:
  71. ret = -ENOSYS;
  72. }
  73. pagefault_enable();
  74. if (!ret)
  75. *oval = oldval;
  76. return ret;
  77. }
  78. static inline int
  79. futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
  80. u32 oldval, u32 newval)
  81. {
  82. int ret = 0;
  83. u32 val;
  84. uintptr_t tmp;
  85. if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
  86. return -EFAULT;
  87. __enable_user_access();
  88. __asm__ __volatile__ (
  89. "1: lr.w.aqrl %[v],%[u] \n"
  90. " bne %[v],%z[ov],3f \n"
  91. "2: sc.w.aqrl %[t],%z[nv],%[u] \n"
  92. " bnez %[t],1b \n"
  93. "3: \n"
  94. " .section .fixup,\"ax\" \n"
  95. " .balign 4 \n"
  96. "4: li %[r],%[e] \n"
  97. " jump 3b,%[t] \n"
  98. " .previous \n"
  99. " .section __ex_table,\"a\" \n"
  100. " .balign " RISCV_SZPTR " \n"
  101. " " RISCV_PTR " 1b, 4b \n"
  102. " " RISCV_PTR " 2b, 4b \n"
  103. " .previous \n"
  104. : [r] "+r" (ret), [v] "=&r" (val), [u] "+m" (*uaddr), [t] "=&r" (tmp)
  105. : [ov] "Jr" (oldval), [nv] "Jr" (newval), [e] "i" (-EFAULT)
  106. : "memory");
  107. __disable_user_access();
  108. *uval = val;
  109. return ret;
  110. }
  111. #endif /* CONFIG_RISCV_ISA_A */
  112. #endif /* _ASM_FUTEX_H */