futex.h 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. /* SPDX-License-Identifier: GPL-2.0 */
  2. #ifndef _ASM_X86_FUTEX_H
  3. #define _ASM_X86_FUTEX_H
  4. #ifdef __KERNEL__
  5. #include <linux/futex.h>
  6. #include <linux/uaccess.h>
  7. #include <asm/asm.h>
  8. #include <asm/errno.h>
  9. #include <asm/processor.h>
  10. #include <asm/smap.h>
  11. #define unsafe_atomic_op1(insn, oval, uaddr, oparg, label) \
  12. do { \
  13. int oldval = 0, ret; \
  14. asm volatile("1:\t" insn "\n" \
  15. "2:\n" \
  16. _ASM_EXTABLE_TYPE_REG(1b, 2b, EX_TYPE_EFAULT_REG, %1) \
  17. : "=r" (oldval), "=r" (ret), "+m" (*uaddr) \
  18. : "0" (oparg), "1" (0)); \
  19. if (ret) \
  20. goto label; \
  21. *oval = oldval; \
  22. } while(0)
  23. #define unsafe_atomic_op2(insn, oval, uaddr, oparg, label) \
  24. do { \
  25. int oldval = 0, ret, tem; \
  26. asm volatile("1:\tmovl %2, %0\n" \
  27. "2:\tmovl\t%0, %3\n" \
  28. "\t" insn "\n" \
  29. "3:\t" LOCK_PREFIX "cmpxchgl %3, %2\n" \
  30. "\tjnz\t2b\n" \
  31. "4:\n" \
  32. _ASM_EXTABLE_TYPE_REG(1b, 4b, EX_TYPE_EFAULT_REG, %1) \
  33. _ASM_EXTABLE_TYPE_REG(3b, 4b, EX_TYPE_EFAULT_REG, %1) \
  34. : "=&a" (oldval), "=&r" (ret), \
  35. "+m" (*uaddr), "=&r" (tem) \
  36. : "r" (oparg), "1" (0)); \
  37. if (ret) \
  38. goto label; \
  39. *oval = oldval; \
  40. } while(0)
  41. static __always_inline int arch_futex_atomic_op_inuser(int op, int oparg, int *oval,
  42. u32 __user *uaddr)
  43. {
  44. if (!user_access_begin(uaddr, sizeof(u32)))
  45. return -EFAULT;
  46. switch (op) {
  47. case FUTEX_OP_SET:
  48. unsafe_atomic_op1("xchgl %0, %2", oval, uaddr, oparg, Efault);
  49. break;
  50. case FUTEX_OP_ADD:
  51. unsafe_atomic_op1(LOCK_PREFIX "xaddl %0, %2", oval,
  52. uaddr, oparg, Efault);
  53. break;
  54. case FUTEX_OP_OR:
  55. unsafe_atomic_op2("orl %4, %3", oval, uaddr, oparg, Efault);
  56. break;
  57. case FUTEX_OP_ANDN:
  58. unsafe_atomic_op2("andl %4, %3", oval, uaddr, ~oparg, Efault);
  59. break;
  60. case FUTEX_OP_XOR:
  61. unsafe_atomic_op2("xorl %4, %3", oval, uaddr, oparg, Efault);
  62. break;
  63. default:
  64. user_access_end();
  65. return -ENOSYS;
  66. }
  67. user_access_end();
  68. return 0;
  69. Efault:
  70. user_access_end();
  71. return -EFAULT;
  72. }
  73. static inline int futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
  74. u32 oldval, u32 newval)
  75. {
  76. int ret = 0;
  77. if (!user_access_begin(uaddr, sizeof(u32)))
  78. return -EFAULT;
  79. asm volatile("\n"
  80. "1:\t" LOCK_PREFIX "cmpxchgl %3, %2\n"
  81. "2:\n"
  82. _ASM_EXTABLE_TYPE_REG(1b, 2b, EX_TYPE_EFAULT_REG, %0) \
  83. : "+r" (ret), "=a" (oldval), "+m" (*uaddr)
  84. : "r" (newval), "1" (oldval)
  85. : "memory"
  86. );
  87. user_access_end();
  88. *uval = oldval;
  89. return ret;
  90. }
  91. #endif
  92. #endif /* _ASM_X86_FUTEX_H */