18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */ 28c2ecf20Sopenharmony_ci#ifndef _ASM_FUTEX_H 38c2ecf20Sopenharmony_ci#define _ASM_FUTEX_H 48c2ecf20Sopenharmony_ci 58c2ecf20Sopenharmony_ci#include <linux/futex.h> 68c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 78c2ecf20Sopenharmony_ci#include <asm/errno.h> 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#define __futex_atomic_op1(insn, ret, oldval, uaddr, oparg) \ 108c2ecf20Sopenharmony_cido { \ 118c2ecf20Sopenharmony_ci register unsigned long r8 __asm ("r8") = 0; \ 128c2ecf20Sopenharmony_ci __asm__ __volatile__( \ 138c2ecf20Sopenharmony_ci " mf;; \n" \ 148c2ecf20Sopenharmony_ci "[1:] " insn ";; \n" \ 158c2ecf20Sopenharmony_ci " .xdata4 \"__ex_table\", 1b-., 2f-. \n" \ 168c2ecf20Sopenharmony_ci "[2:]" \ 178c2ecf20Sopenharmony_ci : "+r" (r8), "=r" (oldval) \ 188c2ecf20Sopenharmony_ci : "r" (uaddr), "r" (oparg) \ 198c2ecf20Sopenharmony_ci : "memory"); \ 208c2ecf20Sopenharmony_ci ret = r8; \ 218c2ecf20Sopenharmony_ci} while (0) 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci#define __futex_atomic_op2(insn, ret, oldval, uaddr, oparg) \ 248c2ecf20Sopenharmony_cido { \ 258c2ecf20Sopenharmony_ci register unsigned long r8 __asm ("r8") = 0; \ 268c2ecf20Sopenharmony_ci int val, newval; \ 278c2ecf20Sopenharmony_ci do { \ 288c2ecf20Sopenharmony_ci __asm__ __volatile__( \ 298c2ecf20Sopenharmony_ci " mf;; \n" \ 308c2ecf20Sopenharmony_ci "[1:] ld4 %3=[%4];; \n" \ 318c2ecf20Sopenharmony_ci " mov %2=%3 \n" \ 328c2ecf20Sopenharmony_ci insn ";; \n" \ 338c2ecf20Sopenharmony_ci " mov ar.ccv=%2;; \n" \ 348c2ecf20Sopenharmony_ci "[2:] cmpxchg4.acq %1=[%4],%3,ar.ccv;; \n" \ 358c2ecf20Sopenharmony_ci " .xdata4 \"__ex_table\", 1b-., 3f-.\n" \ 368c2ecf20Sopenharmony_ci " .xdata4 \"__ex_table\", 2b-., 3f-.\n" \ 378c2ecf20Sopenharmony_ci "[3:]" \ 388c2ecf20Sopenharmony_ci : "+r" (r8), "=r" (val), "=&r" (oldval), \ 398c2ecf20Sopenharmony_ci "=&r" (newval) \ 408c2ecf20Sopenharmony_ci : "r" (uaddr), "r" (oparg) \ 418c2ecf20Sopenharmony_ci : "memory"); \ 428c2ecf20Sopenharmony_ci if (unlikely (r8)) \ 438c2ecf20Sopenharmony_ci break; \ 448c2ecf20Sopenharmony_ci } while (unlikely (val != oldval)); \ 458c2ecf20Sopenharmony_ci ret = r8; \ 468c2ecf20Sopenharmony_ci} while (0) 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_cistatic inline int 498c2ecf20Sopenharmony_ciarch_futex_atomic_op_inuser(int op, int oparg, int *oval, u32 __user *uaddr) 508c2ecf20Sopenharmony_ci{ 518c2ecf20Sopenharmony_ci int oldval = 0, ret; 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci if (!access_ok(uaddr, sizeof(u32))) 548c2ecf20Sopenharmony_ci return -EFAULT; 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci switch (op) { 578c2ecf20Sopenharmony_ci case FUTEX_OP_SET: 588c2ecf20Sopenharmony_ci __futex_atomic_op1("xchg4 %1=[%2],%3", ret, oldval, uaddr, 598c2ecf20Sopenharmony_ci oparg); 608c2ecf20Sopenharmony_ci break; 618c2ecf20Sopenharmony_ci case FUTEX_OP_ADD: 628c2ecf20Sopenharmony_ci __futex_atomic_op2("add %3=%3,%5", ret, oldval, uaddr, oparg); 638c2ecf20Sopenharmony_ci break; 648c2ecf20Sopenharmony_ci case FUTEX_OP_OR: 658c2ecf20Sopenharmony_ci __futex_atomic_op2("or %3=%3,%5", ret, oldval, uaddr, oparg); 668c2ecf20Sopenharmony_ci break; 678c2ecf20Sopenharmony_ci case FUTEX_OP_ANDN: 688c2ecf20Sopenharmony_ci __futex_atomic_op2("and %3=%3,%5", ret, oldval, uaddr, 698c2ecf20Sopenharmony_ci ~oparg); 708c2ecf20Sopenharmony_ci break; 718c2ecf20Sopenharmony_ci case FUTEX_OP_XOR: 728c2ecf20Sopenharmony_ci __futex_atomic_op2("xor %3=%3,%5", ret, oldval, uaddr, oparg); 738c2ecf20Sopenharmony_ci break; 748c2ecf20Sopenharmony_ci default: 758c2ecf20Sopenharmony_ci ret = -ENOSYS; 768c2ecf20Sopenharmony_ci } 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci if (!ret) 798c2ecf20Sopenharmony_ci *oval = oldval; 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci return ret; 828c2ecf20Sopenharmony_ci} 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_cistatic inline int 858c2ecf20Sopenharmony_cifutex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, 868c2ecf20Sopenharmony_ci u32 oldval, u32 newval) 878c2ecf20Sopenharmony_ci{ 888c2ecf20Sopenharmony_ci if (!access_ok(uaddr, sizeof(u32))) 898c2ecf20Sopenharmony_ci return -EFAULT; 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci { 928c2ecf20Sopenharmony_ci register unsigned long r8 __asm ("r8") = 0; 938c2ecf20Sopenharmony_ci unsigned long prev; 948c2ecf20Sopenharmony_ci __asm__ __volatile__( 958c2ecf20Sopenharmony_ci " mf;; \n" 968c2ecf20Sopenharmony_ci " mov ar.ccv=%4;; \n" 978c2ecf20Sopenharmony_ci "[1:] cmpxchg4.acq %1=[%2],%3,ar.ccv \n" 988c2ecf20Sopenharmony_ci " .xdata4 \"__ex_table\", 1b-., 2f-. \n" 998c2ecf20Sopenharmony_ci "[2:]" 1008c2ecf20Sopenharmony_ci : "+r" (r8), "=&r" (prev) 1018c2ecf20Sopenharmony_ci : "r" (uaddr), "r" (newval), 1028c2ecf20Sopenharmony_ci "rO" ((long) (unsigned) oldval) 1038c2ecf20Sopenharmony_ci : "memory"); 1048c2ecf20Sopenharmony_ci *uval = prev; 1058c2ecf20Sopenharmony_ci return r8; 1068c2ecf20Sopenharmony_ci } 1078c2ecf20Sopenharmony_ci} 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci#endif /* _ASM_FUTEX_H */ 110