blob: 9cd4dd6e63ad9dc578721add9beebbc9ccacd9cd [file] [log] [blame]
Greg Kroah-Hartmanb2441312017-11-01 15:07:57 +01001/* SPDX-License-Identifier: GPL-2.0 */
Carlos O'Donell342a0492006-09-07 13:05:17 -04002#ifndef _ASM_PARISC_FUTEX_H
3#define _ASM_PARISC_FUTEX_H
Jakub Jelinek4732efbe2005-09-06 15:16:25 -07004
Carlos O'Donell342a0492006-09-07 13:05:17 -04005#include <linux/futex.h>
Jeff Dike730f4122008-04-30 00:54:49 -07006#include <linux/uaccess.h>
Carlos O'Donelld9ba5fe2011-07-08 17:27:00 -04007#include <asm/atomic.h>
Carlos O'Donell342a0492006-09-07 13:05:17 -04008#include <asm/errno.h>
Carlos O'Donell342a0492006-09-07 13:05:17 -04009
John David Anglin8b232812011-10-09 16:40:10 -040010/* The following has to match the LWS code in syscall.S. We have
11 sixteen four-word locks. */
12
13static inline void
Dave Anglin7e992712021-11-03 12:49:32 +010014_futex_spin_lock(u32 __user *uaddr)
John David Anglin8b232812011-10-09 16:40:10 -040015{
16 extern u32 lws_lock_start[];
John David Anglind3a5a682021-12-21 13:33:16 -050017 long index = ((long)uaddr & 0x7f8) >> 1;
John David Anglin8b232812011-10-09 16:40:10 -040018 arch_spinlock_t *s = (arch_spinlock_t *)&lws_lock_start[index];
Dave Anglin7e992712021-11-03 12:49:32 +010019 preempt_disable();
John David Anglin8b232812011-10-09 16:40:10 -040020 arch_spin_lock(s);
21}
22
23static inline void
Dave Anglin7e992712021-11-03 12:49:32 +010024_futex_spin_unlock(u32 __user *uaddr)
John David Anglin8b232812011-10-09 16:40:10 -040025{
26 extern u32 lws_lock_start[];
John David Anglind3a5a682021-12-21 13:33:16 -050027 long index = ((long)uaddr & 0x7f8) >> 1;
John David Anglin8b232812011-10-09 16:40:10 -040028 arch_spinlock_t *s = (arch_spinlock_t *)&lws_lock_start[index];
29 arch_spin_unlock(s);
Dave Anglin7e992712021-11-03 12:49:32 +010030 preempt_enable();
John David Anglin8b232812011-10-09 16:40:10 -040031}
32
Carlos O'Donell342a0492006-09-07 13:05:17 -040033static inline int
Jiri Slaby30d6e0a2017-08-24 09:31:05 +020034arch_futex_atomic_op_inuser(int op, int oparg, int *oval, u32 __user *uaddr)
Carlos O'Donell342a0492006-09-07 13:05:17 -040035{
John David Anglin99aed912016-05-21 15:03:54 -040036 int oldval, ret;
37 u32 tmp;
38
John David Anglin99aed912016-05-21 15:03:54 -040039 ret = -EFAULT;
Dave Anglin7e992712021-11-03 12:49:32 +010040
41 _futex_spin_lock(uaddr);
John David Anglin99aed912016-05-21 15:03:54 -040042 if (unlikely(get_user(oldval, uaddr) != 0))
43 goto out_pagefault_enable;
44
45 ret = 0;
46 tmp = oldval;
Carlos O'Donelld9ba5fe2011-07-08 17:27:00 -040047
Carlos O'Donell342a0492006-09-07 13:05:17 -040048 switch (op) {
49 case FUTEX_OP_SET:
John David Anglin99aed912016-05-21 15:03:54 -040050 tmp = oparg;
Carlos O'Donelld9ba5fe2011-07-08 17:27:00 -040051 break;
Carlos O'Donell342a0492006-09-07 13:05:17 -040052 case FUTEX_OP_ADD:
John David Anglin99aed912016-05-21 15:03:54 -040053 tmp += oparg;
Carlos O'Donelld9ba5fe2011-07-08 17:27:00 -040054 break;
Carlos O'Donell342a0492006-09-07 13:05:17 -040055 case FUTEX_OP_OR:
John David Anglin99aed912016-05-21 15:03:54 -040056 tmp |= oparg;
Carlos O'Donelld9ba5fe2011-07-08 17:27:00 -040057 break;
Carlos O'Donell342a0492006-09-07 13:05:17 -040058 case FUTEX_OP_ANDN:
John David Anglin99aed912016-05-21 15:03:54 -040059 tmp &= ~oparg;
Carlos O'Donelld9ba5fe2011-07-08 17:27:00 -040060 break;
Carlos O'Donell342a0492006-09-07 13:05:17 -040061 case FUTEX_OP_XOR:
John David Anglin99aed912016-05-21 15:03:54 -040062 tmp ^= oparg;
Carlos O'Donelld9ba5fe2011-07-08 17:27:00 -040063 break;
Carlos O'Donell342a0492006-09-07 13:05:17 -040064 default:
65 ret = -ENOSYS;
66 }
67
John David Anglin99aed912016-05-21 15:03:54 -040068 if (ret == 0 && unlikely(put_user(tmp, uaddr) != 0))
69 ret = -EFAULT;
70
71out_pagefault_enable:
Dave Anglin7e992712021-11-03 12:49:32 +010072 _futex_spin_unlock(uaddr);
Carlos O'Donelld9ba5fe2011-07-08 17:27:00 -040073
Jiri Slaby30d6e0a2017-08-24 09:31:05 +020074 if (!ret)
75 *oval = oldval;
76
Carlos O'Donell342a0492006-09-07 13:05:17 -040077 return ret;
78}
79
Carlos O'Donell342a0492006-09-07 13:05:17 -040080static inline int
Michel Lespinasse8d7718a2011-03-10 18:50:58 -080081futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
82 u32 oldval, u32 newval)
Carlos O'Donell342a0492006-09-07 13:05:17 -040083{
Michel Lespinasse8d7718a2011-03-10 18:50:58 -080084 u32 val;
Carlos O'Donell342a0492006-09-07 13:05:17 -040085
Kyle McMartinc20a84c2008-03-01 10:25:52 -080086 /* futex.c wants to do a cmpxchg_inatomic on kernel NULL, which is
87 * our gateway page, and causes no end of trouble...
88 */
Al Virodb68ce12017-03-20 21:08:07 -040089 if (uaccess_kernel() && !uaddr)
Kyle McMartinc20a84c2008-03-01 10:25:52 -080090 return -EFAULT;
91
Linus Torvalds96d4f262019-01-03 18:57:57 -080092 if (!access_ok(uaddr, sizeof(u32)))
Carlos O'Donell342a0492006-09-07 13:05:17 -040093 return -EFAULT;
94
Carlos O'Donelld9ba5fe2011-07-08 17:27:00 -040095 /* HPPA has no cmpxchg in hardware and therefore the
96 * best we can do here is use an array of locks. The
97 * lock selected is based on a hash of the userspace
98 * address. This should scale to a couple of CPUs.
99 */
100
Dave Anglin7e992712021-11-03 12:49:32 +0100101 _futex_spin_lock(uaddr);
John David Anglin99aed912016-05-21 15:03:54 -0400102 if (unlikely(get_user(val, uaddr) != 0)) {
Dave Anglin7e992712021-11-03 12:49:32 +0100103 _futex_spin_unlock(uaddr);
John David Anglin99aed912016-05-21 15:03:54 -0400104 return -EFAULT;
105 }
Carlos O'Donelld9ba5fe2011-07-08 17:27:00 -0400106
John David Anglin99aed912016-05-21 15:03:54 -0400107 if (val == oldval && unlikely(put_user(newval, uaddr) != 0)) {
Dave Anglin7e992712021-11-03 12:49:32 +0100108 _futex_spin_unlock(uaddr);
John David Anglin99aed912016-05-21 15:03:54 -0400109 return -EFAULT;
110 }
Carlos O'Donelld9ba5fe2011-07-08 17:27:00 -0400111
Michel Lespinasse37a9d912011-03-10 18:48:51 -0800112 *uval = val;
Dave Anglin7e992712021-11-03 12:49:32 +0100113 _futex_spin_unlock(uaddr);
Carlos O'Donelld9ba5fe2011-07-08 17:27:00 -0400114
John David Anglin99aed912016-05-21 15:03:54 -0400115 return 0;
Carlos O'Donell342a0492006-09-07 13:05:17 -0400116}
117
Kyle McMartinc20a84c2008-03-01 10:25:52 -0800118#endif /*_ASM_PARISC_FUTEX_H*/