linux/arch/parisc/include/asm/futex.h
<<
>>
Prefs
   1/* SPDX-License-Identifier: GPL-2.0 */
   2#ifndef _ASM_PARISC_FUTEX_H
   3#define _ASM_PARISC_FUTEX_H
   4
   5#ifdef __KERNEL__
   6
   7#include <linux/futex.h>
   8#include <linux/uaccess.h>
   9#include <asm/atomic.h>
  10#include <asm/errno.h>
  11
  12/* The following has to match the LWS code in syscall.S.  We have
  13   sixteen four-word locks. */
  14
  15static inline void
  16_futex_spin_lock_irqsave(u32 __user *uaddr, unsigned long int *flags)
  17{
  18        extern u32 lws_lock_start[];
  19        long index = ((long)uaddr & 0x3f8) >> 1;
  20        arch_spinlock_t *s = (arch_spinlock_t *)&lws_lock_start[index];
  21        local_irq_save(*flags);
  22        arch_spin_lock(s);
  23}
  24
  25static inline void
  26_futex_spin_unlock_irqrestore(u32 __user *uaddr, unsigned long int *flags)
  27{
  28        extern u32 lws_lock_start[];
  29        long index = ((long)uaddr & 0x3f8) >> 1;
  30        arch_spinlock_t *s = (arch_spinlock_t *)&lws_lock_start[index];
  31        arch_spin_unlock(s);
  32        local_irq_restore(*flags);
  33}
  34
  35static inline int
  36arch_futex_atomic_op_inuser(int op, int oparg, int *oval, u32 __user *uaddr)
  37{
  38        unsigned long int flags;
  39        int oldval, ret;
  40        u32 tmp;
  41
  42        _futex_spin_lock_irqsave(uaddr, &flags);
  43
  44        ret = -EFAULT;
  45        if (unlikely(get_user(oldval, uaddr) != 0))
  46                goto out_pagefault_enable;
  47
  48        ret = 0;
  49        tmp = oldval;
  50
  51        switch (op) {
  52        case FUTEX_OP_SET:
  53                tmp = oparg;
  54                break;
  55        case FUTEX_OP_ADD:
  56                tmp += oparg;
  57                break;
  58        case FUTEX_OP_OR:
  59                tmp |= oparg;
  60                break;
  61        case FUTEX_OP_ANDN:
  62                tmp &= ~oparg;
  63                break;
  64        case FUTEX_OP_XOR:
  65                tmp ^= oparg;
  66                break;
  67        default:
  68                ret = -ENOSYS;
  69        }
  70
  71        if (ret == 0 && unlikely(put_user(tmp, uaddr) != 0))
  72                ret = -EFAULT;
  73
  74out_pagefault_enable:
  75        _futex_spin_unlock_irqrestore(uaddr, &flags);
  76
  77        if (!ret)
  78                *oval = oldval;
  79
  80        return ret;
  81}
  82
  83static inline int
  84futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
  85                              u32 oldval, u32 newval)
  86{
  87        u32 val;
  88        unsigned long flags;
  89
  90        /* futex.c wants to do a cmpxchg_inatomic on kernel NULL, which is
  91         * our gateway page, and causes no end of trouble...
  92         */
  93        if (uaccess_kernel() && !uaddr)
  94                return -EFAULT;
  95
  96        if (!access_ok(uaddr, sizeof(u32)))
  97                return -EFAULT;
  98
  99        /* HPPA has no cmpxchg in hardware and therefore the
 100         * best we can do here is use an array of locks. The
 101         * lock selected is based on a hash of the userspace
 102         * address. This should scale to a couple of CPUs.
 103         */
 104
 105        _futex_spin_lock_irqsave(uaddr, &flags);
 106        if (unlikely(get_user(val, uaddr) != 0)) {
 107                _futex_spin_unlock_irqrestore(uaddr, &flags);
 108                return -EFAULT;
 109        }
 110
 111        if (val == oldval && unlikely(put_user(newval, uaddr) != 0)) {
 112                _futex_spin_unlock_irqrestore(uaddr, &flags);
 113                return -EFAULT;
 114        }
 115
 116        *uval = val;
 117        _futex_spin_unlock_irqrestore(uaddr, &flags);
 118
 119        return 0;
 120}
 121
 122#endif /*__KERNEL__*/
 123#endif /*_ASM_PARISC_FUTEX_H*/
 124