blob: c601aab2fb36d992db913e38dd83faf975721505 [file] [log] [blame]
Carlos O'Donell342a0492006-09-07 13:05:17 -04001#ifndef _ASM_PARISC_FUTEX_H
2#define _ASM_PARISC_FUTEX_H
Jakub Jelinek4732efbe2005-09-06 15:16:25 -07003
Carlos O'Donell342a0492006-09-07 13:05:17 -04004#ifdef __KERNEL__
Jakub Jelinek4732efbe2005-09-06 15:16:25 -07005
Carlos O'Donell342a0492006-09-07 13:05:17 -04006#include <linux/futex.h>
Jeff Dike730f4122008-04-30 00:54:49 -07007#include <linux/uaccess.h>
Carlos O'Donelld9ba5fe2011-07-08 17:27:00 -04008#include <asm/atomic.h>
Carlos O'Donell342a0492006-09-07 13:05:17 -04009#include <asm/errno.h>
Carlos O'Donell342a0492006-09-07 13:05:17 -040010
John David Anglin8b232812011-10-09 16:40:10 -040011/* The following has to match the LWS code in syscall.S. We have
12 sixteen four-word locks. */
13
14static inline void
15_futex_spin_lock_irqsave(u32 __user *uaddr, unsigned long int *flags)
16{
17 extern u32 lws_lock_start[];
18 long index = ((long)uaddr & 0xf0) >> 2;
19 arch_spinlock_t *s = (arch_spinlock_t *)&lws_lock_start[index];
20 local_irq_save(*flags);
21 arch_spin_lock(s);
22}
23
24static inline void
25_futex_spin_unlock_irqrestore(u32 __user *uaddr, unsigned long int *flags)
26{
27 extern u32 lws_lock_start[];
28 long index = ((long)uaddr & 0xf0) >> 2;
29 arch_spinlock_t *s = (arch_spinlock_t *)&lws_lock_start[index];
30 arch_spin_unlock(s);
31 local_irq_restore(*flags);
32}
33
Carlos O'Donell342a0492006-09-07 13:05:17 -040034static inline int
Jiri Slaby30d6e0a2017-08-24 09:31:05 +020035arch_futex_atomic_op_inuser(int op, int oparg, int *oval, u32 __user *uaddr)
Carlos O'Donell342a0492006-09-07 13:05:17 -040036{
Carlos O'Donelld9ba5fe2011-07-08 17:27:00 -040037 unsigned long int flags;
John David Anglin99aed912016-05-21 15:03:54 -040038 int oldval, ret;
39 u32 tmp;
40
John David Anglin99aed912016-05-21 15:03:54 -040041 _futex_spin_lock_irqsave(uaddr, &flags);
Peter Zijlstraa8663742006-12-06 20:32:20 -080042 pagefault_disable();
Carlos O'Donell342a0492006-09-07 13:05:17 -040043
John David Anglin99aed912016-05-21 15:03:54 -040044 ret = -EFAULT;
45 if (unlikely(get_user(oldval, uaddr) != 0))
46 goto out_pagefault_enable;
47
48 ret = 0;
49 tmp = oldval;
Carlos O'Donelld9ba5fe2011-07-08 17:27:00 -040050
Carlos O'Donell342a0492006-09-07 13:05:17 -040051 switch (op) {
52 case FUTEX_OP_SET:
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_ADD:
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_OR:
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_ANDN:
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 case FUTEX_OP_XOR:
John David Anglin99aed912016-05-21 15:03:54 -040065 tmp ^= oparg;
Carlos O'Donelld9ba5fe2011-07-08 17:27:00 -040066 break;
Carlos O'Donell342a0492006-09-07 13:05:17 -040067 default:
68 ret = -ENOSYS;
69 }
70
John David Anglin99aed912016-05-21 15:03:54 -040071 if (ret == 0 && unlikely(put_user(tmp, uaddr) != 0))
72 ret = -EFAULT;
73
74out_pagefault_enable:
75 pagefault_enable();
John David Anglin8b232812011-10-09 16:40:10 -040076 _futex_spin_unlock_irqrestore(uaddr, &flags);
Carlos O'Donelld9ba5fe2011-07-08 17:27:00 -040077
Jiri Slaby30d6e0a2017-08-24 09:31:05 +020078 if (!ret)
79 *oval = oldval;
80
Carlos O'Donell342a0492006-09-07 13:05:17 -040081 return ret;
82}
83
Carlos O'Donell342a0492006-09-07 13:05:17 -040084static inline int
Michel Lespinasse8d7718a2011-03-10 18:50:58 -080085futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
86 u32 oldval, u32 newval)
Carlos O'Donell342a0492006-09-07 13:05:17 -040087{
Michel Lespinasse8d7718a2011-03-10 18:50:58 -080088 u32 val;
Carlos O'Donelld9ba5fe2011-07-08 17:27:00 -040089 unsigned long flags;
Carlos O'Donell342a0492006-09-07 13:05:17 -040090
Kyle McMartinc20a84c2008-03-01 10:25:52 -080091 /* futex.c wants to do a cmpxchg_inatomic on kernel NULL, which is
92 * our gateway page, and causes no end of trouble...
93 */
Al Virodb68ce12017-03-20 21:08:07 -040094 if (uaccess_kernel() && !uaddr)
Kyle McMartinc20a84c2008-03-01 10:25:52 -080095 return -EFAULT;
96
Michel Lespinasse8d7718a2011-03-10 18:50:58 -080097 if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
Carlos O'Donell342a0492006-09-07 13:05:17 -040098 return -EFAULT;
99
Carlos O'Donelld9ba5fe2011-07-08 17:27:00 -0400100 /* HPPA has no cmpxchg in hardware and therefore the
101 * best we can do here is use an array of locks. The
102 * lock selected is based on a hash of the userspace
103 * address. This should scale to a couple of CPUs.
104 */
105
John David Anglin8b232812011-10-09 16:40:10 -0400106 _futex_spin_lock_irqsave(uaddr, &flags);
John David Anglin99aed912016-05-21 15:03:54 -0400107 if (unlikely(get_user(val, uaddr) != 0)) {
108 _futex_spin_unlock_irqrestore(uaddr, &flags);
109 return -EFAULT;
110 }
Carlos O'Donelld9ba5fe2011-07-08 17:27:00 -0400111
John David Anglin99aed912016-05-21 15:03:54 -0400112 if (val == oldval && unlikely(put_user(newval, uaddr) != 0)) {
113 _futex_spin_unlock_irqrestore(uaddr, &flags);
114 return -EFAULT;
115 }
Carlos O'Donelld9ba5fe2011-07-08 17:27:00 -0400116
Michel Lespinasse37a9d912011-03-10 18:48:51 -0800117 *uval = val;
John David Anglin8b232812011-10-09 16:40:10 -0400118 _futex_spin_unlock_irqrestore(uaddr, &flags);
Carlos O'Donelld9ba5fe2011-07-08 17:27:00 -0400119
John David Anglin99aed912016-05-21 15:03:54 -0400120 return 0;
Carlos O'Donell342a0492006-09-07 13:05:17 -0400121}
122
Kyle McMartinc20a84c2008-03-01 10:25:52 -0800123#endif /*__KERNEL__*/
124#endif /*_ASM_PARISC_FUTEX_H*/