Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
at v5.5 125 lines 2.7 kB view raw
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*/