Back to home page

OSCL-LXR

 
 

    


0001 /* SPDX-License-Identifier: GPL-2.0 */
0002 #ifndef _ASM_POWERPC_FUTEX_H
0003 #define _ASM_POWERPC_FUTEX_H
0004 
0005 #ifdef __KERNEL__
0006 
0007 #include <linux/futex.h>
0008 #include <linux/uaccess.h>
0009 #include <asm/errno.h>
0010 #include <asm/synch.h>
0011 
0012 #define __futex_atomic_op(insn, ret, oldval, uaddr, oparg) \
0013   __asm__ __volatile ( \
0014     PPC_ATOMIC_ENTRY_BARRIER \
0015 "1: lwarx   %0,0,%2\n" \
0016     insn \
0017 "2: stwcx.  %1,0,%2\n" \
0018     "bne-   1b\n" \
0019     PPC_ATOMIC_EXIT_BARRIER \
0020     "li %1,0\n" \
0021 "3: .section .fixup,\"ax\"\n" \
0022 "4: li  %1,%3\n" \
0023     "b  3b\n" \
0024     ".previous\n" \
0025     EX_TABLE(1b, 4b) \
0026     EX_TABLE(2b, 4b) \
0027     : "=&r" (oldval), "=&r" (ret) \
0028     : "b" (uaddr), "i" (-EFAULT), "r" (oparg) \
0029     : "cr0", "memory")
0030 
0031 static inline int arch_futex_atomic_op_inuser(int op, int oparg, int *oval,
0032         u32 __user *uaddr)
0033 {
0034     int oldval = 0, ret;
0035 
0036     if (!user_access_begin(uaddr, sizeof(u32)))
0037         return -EFAULT;
0038 
0039     switch (op) {
0040     case FUTEX_OP_SET:
0041         __futex_atomic_op("mr %1,%4\n", ret, oldval, uaddr, oparg);
0042         break;
0043     case FUTEX_OP_ADD:
0044         __futex_atomic_op("add %1,%0,%4\n", ret, oldval, uaddr, oparg);
0045         break;
0046     case FUTEX_OP_OR:
0047         __futex_atomic_op("or %1,%0,%4\n", ret, oldval, uaddr, oparg);
0048         break;
0049     case FUTEX_OP_ANDN:
0050         __futex_atomic_op("andc %1,%0,%4\n", ret, oldval, uaddr, oparg);
0051         break;
0052     case FUTEX_OP_XOR:
0053         __futex_atomic_op("xor %1,%0,%4\n", ret, oldval, uaddr, oparg);
0054         break;
0055     default:
0056         ret = -ENOSYS;
0057     }
0058     user_access_end();
0059 
0060     *oval = oldval;
0061 
0062     return ret;
0063 }
0064 
0065 static inline int
0066 futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
0067                   u32 oldval, u32 newval)
0068 {
0069     int ret = 0;
0070     u32 prev;
0071 
0072     if (!user_access_begin(uaddr, sizeof(u32)))
0073         return -EFAULT;
0074 
0075         __asm__ __volatile__ (
0076         PPC_ATOMIC_ENTRY_BARRIER
0077 "1:     lwarx   %1,0,%3         # futex_atomic_cmpxchg_inatomic\n\
0078         cmpw    0,%1,%4\n\
0079         bne-    3f\n"
0080 "2:     stwcx.  %5,0,%3\n\
0081         bne-    1b\n"
0082         PPC_ATOMIC_EXIT_BARRIER
0083 "3: .section .fixup,\"ax\"\n\
0084 4:  li  %0,%6\n\
0085     b   3b\n\
0086     .previous\n"
0087     EX_TABLE(1b, 4b)
0088     EX_TABLE(2b, 4b)
0089         : "+r" (ret), "=&r" (prev), "+m" (*uaddr)
0090         : "r" (uaddr), "r" (oldval), "r" (newval), "i" (-EFAULT)
0091         : "cc", "memory");
0092 
0093     user_access_end();
0094 
0095     *uval = prev;
0096 
0097         return ret;
0098 }
0099 
0100 #endif /* __KERNEL__ */
0101 #endif /* _ASM_POWERPC_FUTEX_H */