162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */ 262306a36Sopenharmony_ci#ifndef _ASM_X86_FUTEX_H 362306a36Sopenharmony_ci#define _ASM_X86_FUTEX_H 462306a36Sopenharmony_ci 562306a36Sopenharmony_ci#ifdef __KERNEL__ 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#include <linux/futex.h> 862306a36Sopenharmony_ci#include <linux/uaccess.h> 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include <asm/asm.h> 1162306a36Sopenharmony_ci#include <asm/errno.h> 1262306a36Sopenharmony_ci#include <asm/processor.h> 1362306a36Sopenharmony_ci#include <asm/smap.h> 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci#define unsafe_atomic_op1(insn, oval, uaddr, oparg, label) \ 1662306a36Sopenharmony_cido { \ 1762306a36Sopenharmony_ci int oldval = 0, ret; \ 1862306a36Sopenharmony_ci asm volatile("1:\t" insn "\n" \ 1962306a36Sopenharmony_ci "2:\n" \ 2062306a36Sopenharmony_ci _ASM_EXTABLE_TYPE_REG(1b, 2b, EX_TYPE_EFAULT_REG, %1) \ 2162306a36Sopenharmony_ci : "=r" (oldval), "=r" (ret), "+m" (*uaddr) \ 2262306a36Sopenharmony_ci : "0" (oparg), "1" (0)); \ 2362306a36Sopenharmony_ci if (ret) \ 2462306a36Sopenharmony_ci goto label; \ 2562306a36Sopenharmony_ci *oval = oldval; \ 2662306a36Sopenharmony_ci} while(0) 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci#define unsafe_atomic_op2(insn, oval, uaddr, oparg, label) \ 3062306a36Sopenharmony_cido { \ 3162306a36Sopenharmony_ci int oldval = 0, ret, tem; \ 3262306a36Sopenharmony_ci asm volatile("1:\tmovl %2, %0\n" \ 3362306a36Sopenharmony_ci "2:\tmovl\t%0, %3\n" \ 3462306a36Sopenharmony_ci "\t" insn "\n" \ 3562306a36Sopenharmony_ci "3:\t" LOCK_PREFIX "cmpxchgl %3, %2\n" \ 3662306a36Sopenharmony_ci "\tjnz\t2b\n" \ 3762306a36Sopenharmony_ci "4:\n" \ 3862306a36Sopenharmony_ci _ASM_EXTABLE_TYPE_REG(1b, 4b, EX_TYPE_EFAULT_REG, %1) \ 3962306a36Sopenharmony_ci _ASM_EXTABLE_TYPE_REG(3b, 4b, EX_TYPE_EFAULT_REG, %1) \ 4062306a36Sopenharmony_ci : "=&a" (oldval), "=&r" (ret), \ 4162306a36Sopenharmony_ci "+m" (*uaddr), "=&r" (tem) \ 4262306a36Sopenharmony_ci : "r" (oparg), "1" (0)); \ 4362306a36Sopenharmony_ci if (ret) \ 4462306a36Sopenharmony_ci goto label; \ 4562306a36Sopenharmony_ci *oval = oldval; \ 4662306a36Sopenharmony_ci} while(0) 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_cistatic __always_inline int arch_futex_atomic_op_inuser(int op, int oparg, int *oval, 4962306a36Sopenharmony_ci u32 __user *uaddr) 5062306a36Sopenharmony_ci{ 5162306a36Sopenharmony_ci if (!user_access_begin(uaddr, sizeof(u32))) 5262306a36Sopenharmony_ci return -EFAULT; 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci switch (op) { 5562306a36Sopenharmony_ci case FUTEX_OP_SET: 5662306a36Sopenharmony_ci unsafe_atomic_op1("xchgl %0, %2", oval, uaddr, oparg, Efault); 5762306a36Sopenharmony_ci break; 5862306a36Sopenharmony_ci case FUTEX_OP_ADD: 5962306a36Sopenharmony_ci unsafe_atomic_op1(LOCK_PREFIX "xaddl %0, %2", oval, 6062306a36Sopenharmony_ci uaddr, oparg, Efault); 6162306a36Sopenharmony_ci break; 6262306a36Sopenharmony_ci case FUTEX_OP_OR: 6362306a36Sopenharmony_ci unsafe_atomic_op2("orl %4, %3", oval, uaddr, oparg, Efault); 6462306a36Sopenharmony_ci break; 6562306a36Sopenharmony_ci case FUTEX_OP_ANDN: 6662306a36Sopenharmony_ci unsafe_atomic_op2("andl %4, %3", oval, uaddr, ~oparg, Efault); 6762306a36Sopenharmony_ci break; 6862306a36Sopenharmony_ci case FUTEX_OP_XOR: 6962306a36Sopenharmony_ci unsafe_atomic_op2("xorl %4, %3", oval, uaddr, oparg, Efault); 7062306a36Sopenharmony_ci break; 7162306a36Sopenharmony_ci default: 7262306a36Sopenharmony_ci user_access_end(); 7362306a36Sopenharmony_ci return -ENOSYS; 7462306a36Sopenharmony_ci } 7562306a36Sopenharmony_ci user_access_end(); 7662306a36Sopenharmony_ci return 0; 7762306a36Sopenharmony_ciEfault: 7862306a36Sopenharmony_ci user_access_end(); 7962306a36Sopenharmony_ci return -EFAULT; 8062306a36Sopenharmony_ci} 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_cistatic inline int futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, 8362306a36Sopenharmony_ci u32 oldval, u32 newval) 8462306a36Sopenharmony_ci{ 8562306a36Sopenharmony_ci int ret = 0; 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci if (!user_access_begin(uaddr, sizeof(u32))) 8862306a36Sopenharmony_ci return -EFAULT; 8962306a36Sopenharmony_ci asm volatile("\n" 9062306a36Sopenharmony_ci "1:\t" LOCK_PREFIX "cmpxchgl %3, %2\n" 9162306a36Sopenharmony_ci "2:\n" 9262306a36Sopenharmony_ci _ASM_EXTABLE_TYPE_REG(1b, 2b, EX_TYPE_EFAULT_REG, %0) \ 9362306a36Sopenharmony_ci : "+r" (ret), "=a" (oldval), "+m" (*uaddr) 9462306a36Sopenharmony_ci : "r" (newval), "1" (oldval) 9562306a36Sopenharmony_ci : "memory" 9662306a36Sopenharmony_ci ); 9762306a36Sopenharmony_ci user_access_end(); 9862306a36Sopenharmony_ci *uval = oldval; 9962306a36Sopenharmony_ci return ret; 10062306a36Sopenharmony_ci} 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci#endif 10362306a36Sopenharmony_ci#endif /* _ASM_X86_FUTEX_H */ 104