linux/arch/powerpc/include/asm/futex.h
<<
>>
Prefs
   1/* SPDX-License-Identifier: GPL-2.0 */
   2#ifndef _ASM_POWERPC_FUTEX_H
   3#define _ASM_POWERPC_FUTEX_H
   4
   5#ifdef __KERNEL__
   6
   7#include <linux/futex.h>
   8#include <linux/uaccess.h>
   9#include <asm/errno.h>
  10#include <asm/synch.h>
  11
  12#define __futex_atomic_op(insn, ret, oldval, uaddr, oparg) \
  13  __asm__ __volatile ( \
  14        PPC_ATOMIC_ENTRY_BARRIER \
  15"1:     lwarx   %0,0,%2\n" \
  16        insn \
  17"2:     stwcx.  %1,0,%2\n" \
  18        "bne-   1b\n" \
  19        PPC_ATOMIC_EXIT_BARRIER \
  20        "li     %1,0\n" \
  21"3:     .section .fixup,\"ax\"\n" \
  22"4:     li      %1,%3\n" \
  23        "b      3b\n" \
  24        ".previous\n" \
  25        EX_TABLE(1b, 4b) \
  26        EX_TABLE(2b, 4b) \
  27        : "=&r" (oldval), "=&r" (ret) \
  28        : "b" (uaddr), "i" (-EFAULT), "r" (oparg) \
  29        : "cr0", "memory")
  30
  31static inline int arch_futex_atomic_op_inuser(int op, int oparg, int *oval,
  32                u32 __user *uaddr)
  33{
  34        int oldval = 0, ret;
  35
  36        if (!user_access_begin(uaddr, sizeof(u32)))
  37                return -EFAULT;
  38
  39        switch (op) {
  40        case FUTEX_OP_SET:
  41                __futex_atomic_op("mr %1,%4\n", ret, oldval, uaddr, oparg);
  42                break;
  43        case FUTEX_OP_ADD:
  44                __futex_atomic_op("add %1,%0,%4\n", ret, oldval, uaddr, oparg);
  45                break;
  46        case FUTEX_OP_OR:
  47                __futex_atomic_op("or %1,%0,%4\n", ret, oldval, uaddr, oparg);
  48                break;
  49        case FUTEX_OP_ANDN:
  50                __futex_atomic_op("andc %1,%0,%4\n", ret, oldval, uaddr, oparg);
  51                break;
  52        case FUTEX_OP_XOR:
  53                __futex_atomic_op("xor %1,%0,%4\n", ret, oldval, uaddr, oparg);
  54                break;
  55        default:
  56                ret = -ENOSYS;
  57        }
  58        user_access_end();
  59
  60        *oval = oldval;
  61
  62        return ret;
  63}
  64
  65static inline int
  66futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
  67                              u32 oldval, u32 newval)
  68{
  69        int ret = 0;
  70        u32 prev;
  71
  72        if (!user_access_begin(uaddr, sizeof(u32)))
  73                return -EFAULT;
  74
  75        __asm__ __volatile__ (
  76        PPC_ATOMIC_ENTRY_BARRIER
  77"1:     lwarx   %1,0,%3         # futex_atomic_cmpxchg_inatomic\n\
  78        cmpw    0,%1,%4\n\
  79        bne-    3f\n"
  80"2:     stwcx.  %5,0,%3\n\
  81        bne-    1b\n"
  82        PPC_ATOMIC_EXIT_BARRIER
  83"3:     .section .fixup,\"ax\"\n\
  844:      li      %0,%6\n\
  85        b       3b\n\
  86        .previous\n"
  87        EX_TABLE(1b, 4b)
  88        EX_TABLE(2b, 4b)
  89        : "+r" (ret), "=&r" (prev), "+m" (*uaddr)
  90        : "r" (uaddr), "r" (oldval), "r" (newval), "i" (-EFAULT)
  91        : "cc", "memory");
  92
  93        user_access_end();
  94
  95        *uval = prev;
  96
  97        return ret;
  98}
  99
 100#endif /* __KERNEL__ */
 101#endif /* _ASM_POWERPC_FUTEX_H */
 102