1 /* SPDX-License-Identifier: GPL-2.0 */ 2 /* 3 * Copyright (C) 2020-2022 Loongson Technology Corporation Limited 4 */ 5 #ifndef _ASM_FUTEX_H 6 #define _ASM_FUTEX_H 7 8 #include <linux/futex.h> 9 #include <linux/uaccess.h> 10 #include <asm/barrier.h> 11 #include <asm/errno.h> 12 13 #define __futex_atomic_op(insn, ret, oldval, uaddr, oparg) \ 14 { \ 15 __asm__ __volatile__( \ 16 "1: ll.w %1, %4 # __futex_atomic_op\n" \ 17 " " insn " \n" \ 18 "2: sc.w $t0, %2 \n" \ 19 " beqz $t0, 1b \n" \ 20 "3: \n" \ 21 " .section .fixup,\"ax\" \n" \ 22 "4: li.w %0, %6 \n" \ 23 " b 3b \n" \ 24 " .previous \n" \ 25 " .section __ex_table,\"a\" \n" \ 26 " "__UA_ADDR "\t1b, 4b \n" \ 27 " "__UA_ADDR "\t2b, 4b \n" \ 28 " .previous \n" \ 29 : "=r" (ret), "=&r" (oldval), \ 30 "=ZC" (*uaddr) \ 31 : "0" (0), "ZC" (*uaddr), "Jr" (oparg), \ 32 "i" (-EFAULT) \ 33 : "memory", "t0"); \ 34 } 35 36 static inline int 37 arch_futex_atomic_op_inuser(int op, int oparg, int *oval, u32 __user *uaddr) 38 { 39 int oldval = 0, ret = 0; 40 41 pagefault_disable(); 42 43 switch (op) { 44 case FUTEX_OP_SET: 45 __futex_atomic_op("move $t0, %z5", ret, oldval, uaddr, oparg); 46 break; 47 case FUTEX_OP_ADD: 48 __futex_atomic_op("add.w $t0, %1, %z5", ret, oldval, uaddr, oparg); 49 break; 50 case FUTEX_OP_OR: 51 __futex_atomic_op("or $t0, %1, %z5", ret, oldval, uaddr, oparg); 52 break; 53 case FUTEX_OP_ANDN: 54 __futex_atomic_op("and $t0, %1, %z5", ret, oldval, uaddr, ~oparg); 55 break; 56 case FUTEX_OP_XOR: 57 __futex_atomic_op("xor $t0, %1, %z5", ret, oldval, uaddr, oparg); 58 break; 59 default: 60 ret = -ENOSYS; 61 } 62 63 pagefault_enable(); 64 65 if (!ret) 66 *oval = oldval; 67 68 return ret; 69 } 70 71 static inline int 72 futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, u32 oldval, u32 newval) 73 { 74 int ret = 0; 75 u32 val = 0; 76 77 if (!access_ok(uaddr, sizeof(u32))) 78 return -EFAULT; 79 80 __asm__ __volatile__( 81 "# futex_atomic_cmpxchg_inatomic \n" 82 "1: ll.w %1, %3 \n" 83 " bne %1, %z4, 3f \n" 84 " move $t0, %z5 \n" 85 "2: sc.w $t0, %2 \n" 86 " beqz $t0, 1b \n" 87 "3: \n" 88 __WEAK_LLSC_MB 89 " .section .fixup,\"ax\" \n" 90 "4: li.d %0, %6 \n" 91 " b 3b \n" 92 " .previous \n" 93 " .section __ex_table,\"a\" \n" 94 " "__UA_ADDR "\t1b, 4b \n" 95 " "__UA_ADDR "\t2b, 4b \n" 96 " .previous \n" 97 : "+r" (ret), "=&r" (val), "=ZC" (*uaddr) 98 : "ZC" (*uaddr), "Jr" (oldval), "Jr" (newval), 99 "i" (-EFAULT) 100 : "memory", "t0"); 101 102 *uval = val; 103 104 return ret; 105 } 106 107 #endif /* _ASM_FUTEX_H */ 108