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 & 0xf0) >> 2;
  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 & 0xf0) >> 2;
  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        pagefault_disable();
  44
  45        ret = -EFAULT;
  46        if (unlikely(get_user(oldval, uaddr) != 0))
  47                goto out_pagefault_enable;
  48
  49        ret = 0;
  50        tmp = oldval;
  51
  52        switch (op) {
  53        case FUTEX_OP_SET:
  54                tmp = oparg;
  55                break;
  56        case FUTEX_OP_ADD:
  57                tmp += oparg;
  58                break;
  59        case FUTEX_OP_OR:
  60                tmp |= oparg;
  61                break;
  62        case FUTEX_OP_ANDN:
  63                tmp &= ~oparg;
  64                break;
  65        case FUTEX_OP_XOR:
  66                tmp ^= oparg;
  67                break;
  68        default:
  69                ret = -ENOSYS;
  70        }
  71
  72        if (ret == 0 && unlikely(put_user(tmp, uaddr) != 0))
  73                ret = -EFAULT;
  74
  75out_pagefault_enable:
  76        pagefault_enable();
  77        _futex_spin_unlock_irqrestore(uaddr, &flags);
  78
  79        if (!ret)
  80                *oval = oldval;
  81
  82        return ret;
  83}
  84
  85static inline int
  86futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
  87                              u32 oldval, u32 newval)
  88{
  89        u32 val;
  90        unsigned long flags;
  91
  92        /* futex.c wants to do a cmpxchg_inatomic on kernel NULL, which is
  93         * our gateway page, and causes no end of trouble...
  94         */
  95        if (uaccess_kernel() && !uaddr)
  96                return -EFAULT;
  97
  98        if (!access_ok(uaddr, sizeof(u32)))
  99                return -EFAULT;
 100
 101        /* HPPA has no cmpxchg in hardware and therefore the
 102         * best we can do here is use an array of locks. The
 103         * lock selected is based on a hash of the userspace
 104         * address. This should scale to a couple of CPUs.
 105         */
 106
 107        _futex_spin_lock_irqsave(uaddr, &flags);
 108        if (unlikely(get_user(val, uaddr) != 0)) {
 109                _futex_spin_unlock_irqrestore(uaddr, &flags);
 110                return -EFAULT;
 111        }
 112
 113        if (val == oldval && unlikely(put_user(newval, uaddr) != 0)) {
 114                _futex_spin_unlock_irqrestore(uaddr, &flags);
 115                return -EFAULT;
 116        }
 117
 118        *uval = val;
 119        _futex_spin_unlock_irqrestore(uaddr, &flags);
 120
 121        return 0;
 122}
 123
 124#endif /*__KERNEL__*/
 125#endif /*_ASM_PARISC_FUTEX_H*/
 126