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 7 #ifndef _ASM_FUTEX_H 8 #define _ASM_FUTEX_H 9 10 #include <linux/futex.h> 11 #include <linux/uaccess.h> 12 #include <linux/errno.h> 13 #include <asm/asm.h> 14 15 #define __futex_atomic_op(insn, ret, oldval, uaddr, oparg) \ 16 { \ 17 uintptr_t tmp; \ 18 __enable_user_access(); \ 19 __asm__ __volatile__ ( \ 20 "1: " insn " \n" \ 21 "2: \n" \ 22 " .section .fixup,\"ax\" \n" \ 23 " .balign 4 \n" \ 24 "3: li %[r],%[e] \n" \ 25 " jump 2b,%[t] \n" \ 26 " .previous \n" \ 27 " .section __ex_table,\"a\" \n" \ 28 " .balign " RISCV_SZPTR " \n" \ 29 " " RISCV_PTR " 1b, 3b \n" \ 30 " .previous \n" \ 31 : [r] "+r" (ret), [ov] "=&r" (oldval), \ 32 [u] "+m" (*uaddr), [t] "=&r" (tmp) \ 33 : [op] "Jr" (oparg), [e] "i" (-EFAULT) \ 34 : "memory"); \ 35 __disable_user_access(); \ 36 } 37 38 static inline int 39 arch_futex_atomic_op_inuser(int op, int oparg, int *oval, u32 __user *uaddr) 40 { 41 int oldval = 0, ret = 0; 42 43 pagefault_disable(); 44 45 switch (op) { 46 case FUTEX_OP_SET: 47 __futex_atomic_op("amoswap.w.aqrl %[ov],%z[op],%[u]", 48 ret, oldval, uaddr, oparg); 49 break; 50 case FUTEX_OP_ADD: 51 __futex_atomic_op("amoadd.w.aqrl %[ov],%z[op],%[u]", 52 ret, oldval, uaddr, oparg); 53 break; 54 case FUTEX_OP_OR: 55 __futex_atomic_op("amoor.w.aqrl %[ov],%z[op],%[u]", 56 ret, oldval, uaddr, oparg); 57 break; 58 case FUTEX_OP_ANDN: 59 __futex_atomic_op("amoand.w.aqrl %[ov],%z[op],%[u]", 60 ret, oldval, uaddr, ~oparg); 61 break; 62 case FUTEX_OP_XOR: 63 __futex_atomic_op("amoxor.w.aqrl %[ov],%z[op],%[u]", 64 ret, oldval, uaddr, oparg); 65 break; 66 default: 67 ret = -ENOSYS; 68 } 69 70 pagefault_enable(); 71 72 if (!ret) 73 *oval = oldval; 74 75 return ret; 76 } 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 86 if (!access_ok(uaddr, sizeof(u32))) 87 return -EFAULT; 88 89 __enable_user_access(); 90 __asm__ __volatile__ ( 91 "1: lr.w.aqrl %[v],%[u] \n" 92 " bne %[v],%z[ov],3f \n" 93 "2: sc.w.aqrl %[t],%z[nv],%[u] \n" 94 " bnez %[t],1b \n" 95 "3: \n" 96 " .section .fixup,\"ax\" \n" 97 " .balign 4 \n" 98 "4: li %[r],%[e] \n" 99 " jump 3b,%[t] \n" 100 " .previous \n" 101 " .section __ex_table,\"a\" \n" 102 " .balign " RISCV_SZPTR " \n" 103 " " RISCV_PTR " 1b, 4b \n" 104 " " RISCV_PTR " 2b, 4b \n" 105 " .previous \n" 106 : [r] "+r" (ret), [v] "=&r" (val), [u] "+m" (*uaddr), [t] "=&r" (tmp) 107 : [ov] "Jr" (oldval), [nv] "Jr" (newval), [e] "i" (-EFAULT) 108 : "memory"); 109 __disable_user_access(); 110 111 *uval = val; 112 return ret; 113 } 114 115 #endif /* _ASM_FUTEX_H */ 116