Commit | Line | Data |
---|---|---|
b2441318 | 1 | /* SPDX-License-Identifier: GPL-2.0 */ |
342a0497 CD |
2 | #ifndef _ASM_PARISC_FUTEX_H |
3 | #define _ASM_PARISC_FUTEX_H | |
4732efbe | 4 | |
342a0497 | 5 | #ifdef __KERNEL__ |
4732efbe | 6 | |
342a0497 | 7 | #include <linux/futex.h> |
730f412c | 8 | #include <linux/uaccess.h> |
d9ba5fe7 | 9 | #include <asm/atomic.h> |
342a0497 | 10 | #include <asm/errno.h> |
342a0497 | 11 | |
8b232816 JDA |
12 | /* The following has to match the LWS code in syscall.S. We have |
13 | sixteen four-word locks. */ | |
14 | ||
15 | static 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 | ||
25 | static 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 | ||
342a0497 | 35 | static inline int |
30d6e0a4 | 36 | arch_futex_atomic_op_inuser(int op, int oparg, int *oval, u32 __user *uaddr) |
342a0497 | 37 | { |
d9ba5fe7 | 38 | unsigned long int flags; |
99aed91a JDA |
39 | int oldval, ret; |
40 | u32 tmp; | |
41 | ||
99aed91a | 42 | _futex_spin_lock_irqsave(uaddr, &flags); |
a866374a | 43 | pagefault_disable(); |
342a0497 | 44 | |
99aed91a JDA |
45 | ret = -EFAULT; |
46 | if (unlikely(get_user(oldval, uaddr) != 0)) | |
47 | goto out_pagefault_enable; | |
48 | ||
49 | ret = 0; | |
50 | tmp = oldval; | |
d9ba5fe7 | 51 | |
342a0497 CD |
52 | switch (op) { |
53 | case FUTEX_OP_SET: | |
99aed91a | 54 | tmp = oparg; |
d9ba5fe7 | 55 | break; |
342a0497 | 56 | case FUTEX_OP_ADD: |
99aed91a | 57 | tmp += oparg; |
d9ba5fe7 | 58 | break; |
342a0497 | 59 | case FUTEX_OP_OR: |
99aed91a | 60 | tmp |= oparg; |
d9ba5fe7 | 61 | break; |
342a0497 | 62 | case FUTEX_OP_ANDN: |
99aed91a | 63 | tmp &= ~oparg; |
d9ba5fe7 | 64 | break; |
342a0497 | 65 | case FUTEX_OP_XOR: |
99aed91a | 66 | tmp ^= oparg; |
d9ba5fe7 | 67 | break; |
342a0497 CD |
68 | default: |
69 | ret = -ENOSYS; | |
70 | } | |
71 | ||
99aed91a JDA |
72 | if (ret == 0 && unlikely(put_user(tmp, uaddr) != 0)) |
73 | ret = -EFAULT; | |
d9ba5fe7 | 74 | |
99aed91a | 75 | out_pagefault_enable: |
a866374a | 76 | pagefault_enable(); |
99aed91a | 77 | _futex_spin_unlock_irqrestore(uaddr, &flags); |
342a0497 | 78 | |
30d6e0a4 JS |
79 | if (!ret) |
80 | *oval = oldval; | |
81 | ||
342a0497 CD |
82 | return ret; |
83 | } | |
84 | ||
342a0497 | 85 | static inline int |
8d7718aa ML |
86 | futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, |
87 | u32 oldval, u32 newval) | |
342a0497 | 88 | { |
8d7718aa | 89 | u32 val; |
d9ba5fe7 | 90 | unsigned long flags; |
342a0497 | 91 | |
c20a84c9 KM |
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 | */ | |
db68ce10 | 95 | if (uaccess_kernel() && !uaddr) |
c20a84c9 KM |
96 | return -EFAULT; |
97 | ||
8d7718aa | 98 | if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32))) |
342a0497 CD |
99 | return -EFAULT; |
100 | ||
d9ba5fe7 CD |
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 | ||
8b232816 | 107 | _futex_spin_lock_irqsave(uaddr, &flags); |
99aed91a JDA |
108 | if (unlikely(get_user(val, uaddr) != 0)) { |
109 | _futex_spin_unlock_irqrestore(uaddr, &flags); | |
110 | return -EFAULT; | |
111 | } | |
d9ba5fe7 | 112 | |
99aed91a JDA |
113 | if (val == oldval && unlikely(put_user(newval, uaddr) != 0)) { |
114 | _futex_spin_unlock_irqrestore(uaddr, &flags); | |
115 | return -EFAULT; | |
116 | } | |
d9ba5fe7 | 117 | |
37a9d912 | 118 | *uval = val; |
8b232816 | 119 | _futex_spin_unlock_irqrestore(uaddr, &flags); |
d9ba5fe7 | 120 | |
99aed91a | 121 | return 0; |
342a0497 CD |
122 | } |
123 | ||
c20a84c9 KM |
124 | #endif /*__KERNEL__*/ |
125 | #endif /*_ASM_PARISC_FUTEX_H*/ |