17153c3cbSHuacai Chen /* SPDX-License-Identifier: GPL-2.0 */ 27153c3cbSHuacai Chen /* 37153c3cbSHuacai Chen * Copyright (C) 2020-2022 Loongson Technology Corporation Limited 47153c3cbSHuacai Chen */ 57153c3cbSHuacai Chen #ifndef _ASM_FUTEX_H 67153c3cbSHuacai Chen #define _ASM_FUTEX_H 77153c3cbSHuacai Chen 87153c3cbSHuacai Chen #include <linux/futex.h> 97153c3cbSHuacai Chen #include <linux/uaccess.h> 107153c3cbSHuacai Chen #include <asm/barrier.h> 117153c3cbSHuacai Chen #include <asm/compiler.h> 127153c3cbSHuacai Chen #include <asm/errno.h> 137153c3cbSHuacai Chen 147153c3cbSHuacai Chen #define __futex_atomic_op(insn, ret, oldval, uaddr, oparg) \ 157153c3cbSHuacai Chen { \ 167153c3cbSHuacai Chen __asm__ __volatile__( \ 177153c3cbSHuacai Chen "1: ll.w %1, %4 # __futex_atomic_op\n" \ 187153c3cbSHuacai Chen " " insn " \n" \ 197153c3cbSHuacai Chen "2: sc.w $t0, %2 \n" \ 20*d47b2dc8SWANG Xuerui " beqz $t0, 1b \n" \ 217153c3cbSHuacai Chen "3: \n" \ 227153c3cbSHuacai Chen " .section .fixup,\"ax\" \n" \ 237153c3cbSHuacai Chen "4: li.w %0, %6 \n" \ 247153c3cbSHuacai Chen " b 3b \n" \ 257153c3cbSHuacai Chen " .previous \n" \ 267153c3cbSHuacai Chen " .section __ex_table,\"a\" \n" \ 277153c3cbSHuacai Chen " "__UA_ADDR "\t1b, 4b \n" \ 287153c3cbSHuacai Chen " "__UA_ADDR "\t2b, 4b \n" \ 297153c3cbSHuacai Chen " .previous \n" \ 307153c3cbSHuacai Chen : "=r" (ret), "=&r" (oldval), \ 317153c3cbSHuacai Chen "=ZC" (*uaddr) \ 327153c3cbSHuacai Chen : "0" (0), "ZC" (*uaddr), "Jr" (oparg), \ 337153c3cbSHuacai Chen "i" (-EFAULT) \ 347153c3cbSHuacai Chen : "memory", "t0"); \ 357153c3cbSHuacai Chen } 367153c3cbSHuacai Chen 377153c3cbSHuacai Chen static inline int 387153c3cbSHuacai Chen arch_futex_atomic_op_inuser(int op, int oparg, int *oval, u32 __user *uaddr) 397153c3cbSHuacai Chen { 407153c3cbSHuacai Chen int oldval = 0, ret = 0; 417153c3cbSHuacai Chen 427153c3cbSHuacai Chen pagefault_disable(); 437153c3cbSHuacai Chen 447153c3cbSHuacai Chen switch (op) { 457153c3cbSHuacai Chen case FUTEX_OP_SET: 467153c3cbSHuacai Chen __futex_atomic_op("move $t0, %z5", ret, oldval, uaddr, oparg); 477153c3cbSHuacai Chen break; 487153c3cbSHuacai Chen case FUTEX_OP_ADD: 497153c3cbSHuacai Chen __futex_atomic_op("add.w $t0, %1, %z5", ret, oldval, uaddr, oparg); 507153c3cbSHuacai Chen break; 517153c3cbSHuacai Chen case FUTEX_OP_OR: 527153c3cbSHuacai Chen __futex_atomic_op("or $t0, %1, %z5", ret, oldval, uaddr, oparg); 537153c3cbSHuacai Chen break; 547153c3cbSHuacai Chen case FUTEX_OP_ANDN: 557153c3cbSHuacai Chen __futex_atomic_op("and $t0, %1, %z5", ret, oldval, uaddr, ~oparg); 567153c3cbSHuacai Chen break; 577153c3cbSHuacai Chen case FUTEX_OP_XOR: 587153c3cbSHuacai Chen __futex_atomic_op("xor $t0, %1, %z5", ret, oldval, uaddr, oparg); 597153c3cbSHuacai Chen break; 607153c3cbSHuacai Chen default: 617153c3cbSHuacai Chen ret = -ENOSYS; 627153c3cbSHuacai Chen } 637153c3cbSHuacai Chen 647153c3cbSHuacai Chen pagefault_enable(); 657153c3cbSHuacai Chen 667153c3cbSHuacai Chen if (!ret) 677153c3cbSHuacai Chen *oval = oldval; 687153c3cbSHuacai Chen 697153c3cbSHuacai Chen return ret; 707153c3cbSHuacai Chen } 717153c3cbSHuacai Chen 727153c3cbSHuacai Chen static inline int 737153c3cbSHuacai Chen futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, u32 oldval, u32 newval) 747153c3cbSHuacai Chen { 757153c3cbSHuacai Chen int ret = 0; 767153c3cbSHuacai Chen u32 val = 0; 777153c3cbSHuacai Chen 787153c3cbSHuacai Chen if (!access_ok(uaddr, sizeof(u32))) 797153c3cbSHuacai Chen return -EFAULT; 807153c3cbSHuacai Chen 817153c3cbSHuacai Chen __asm__ __volatile__( 827153c3cbSHuacai Chen "# futex_atomic_cmpxchg_inatomic \n" 837153c3cbSHuacai Chen "1: ll.w %1, %3 \n" 847153c3cbSHuacai Chen " bne %1, %z4, 3f \n" 8557ce5d3eSWANG Xuerui " move $t0, %z5 \n" 867153c3cbSHuacai Chen "2: sc.w $t0, %2 \n" 87*d47b2dc8SWANG Xuerui " beqz $t0, 1b \n" 887153c3cbSHuacai Chen "3: \n" 8946859ac8SHuacai Chen __WEAK_LLSC_MB 907153c3cbSHuacai Chen " .section .fixup,\"ax\" \n" 917153c3cbSHuacai Chen "4: li.d %0, %6 \n" 927153c3cbSHuacai Chen " b 3b \n" 937153c3cbSHuacai Chen " .previous \n" 947153c3cbSHuacai Chen " .section __ex_table,\"a\" \n" 957153c3cbSHuacai Chen " "__UA_ADDR "\t1b, 4b \n" 967153c3cbSHuacai Chen " "__UA_ADDR "\t2b, 4b \n" 977153c3cbSHuacai Chen " .previous \n" 987153c3cbSHuacai Chen : "+r" (ret), "=&r" (val), "=" GCC_OFF_SMALL_ASM() (*uaddr) 997153c3cbSHuacai Chen : GCC_OFF_SMALL_ASM() (*uaddr), "Jr" (oldval), "Jr" (newval), 1007153c3cbSHuacai Chen "i" (-EFAULT) 1017153c3cbSHuacai Chen : "memory", "t0"); 1027153c3cbSHuacai Chen 1037153c3cbSHuacai Chen *uval = val; 1047153c3cbSHuacai Chen 1057153c3cbSHuacai Chen return ret; 1067153c3cbSHuacai Chen } 1077153c3cbSHuacai Chen 1087153c3cbSHuacai Chen #endif /* _ASM_FUTEX_H */ 109