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