blob: fcb61b4659b39db73a1636a9b893dd2620eafd56 [file] [log] [blame]
Greg Kroah-Hartmanb2441312017-11-01 15:07:57 +01001/* SPDX-License-Identifier: GPL-2.0 */
Jeff Dikef8aaeace2006-01-08 01:01:32 -08002#ifndef _ASM_GENERIC_FUTEX_H
3#define _ASM_GENERIC_FUTEX_H
4
Jeff Dikef8aaeace2006-01-08 01:01:32 -08005#include <linux/futex.h>
Jeff Dike730f4122008-04-30 00:54:49 -07006#include <linux/uaccess.h>
Jeff Dikef8aaeace2006-01-08 01:01:32 -08007#include <asm/errno.h>
Jeff Dikef8aaeace2006-01-08 01:01:32 -08008
Ley Foon Tan00f634b2014-11-06 15:19:34 +08009#ifndef CONFIG_SMP
10/*
11 * The following implementation only for uniprocessor machines.
David Hildenbrandf3dae072015-05-11 17:52:13 +020012 * It relies on preempt_disable() ensuring mutual exclusion.
Ley Foon Tan00f634b2014-11-06 15:19:34 +080013 *
14 */
15
16/**
Jiri Slaby30d6e0a2017-08-24 09:31:05 +020017 * arch_futex_atomic_op_inuser() - Atomic arithmetic operation with constant
Ley Foon Tan00f634b2014-11-06 15:19:34 +080018 * argument and comparison of the previous
19 * futex value with another constant.
20 *
21 * @encoded_op: encoded operation to execute
22 * @uaddr: pointer to user space address
23 *
24 * Return:
25 * 0 - On success
26 * <0 - On error
27 */
28static inline int
Jiri Slaby30d6e0a2017-08-24 09:31:05 +020029arch_futex_atomic_op_inuser(int op, u32 oparg, int *oval, u32 __user *uaddr)
Ley Foon Tan00f634b2014-11-06 15:19:34 +080030{
Ley Foon Tan00f634b2014-11-06 15:19:34 +080031 int oldval, ret;
32 u32 tmp;
33
David Hildenbrandf3dae072015-05-11 17:52:13 +020034 preempt_disable();
Ley Foon Tan00f634b2014-11-06 15:19:34 +080035 pagefault_disable();
36
37 ret = -EFAULT;
38 if (unlikely(get_user(oldval, uaddr) != 0))
39 goto out_pagefault_enable;
40
41 ret = 0;
42 tmp = oldval;
43
44 switch (op) {
45 case FUTEX_OP_SET:
46 tmp = oparg;
47 break;
48 case FUTEX_OP_ADD:
49 tmp += oparg;
50 break;
51 case FUTEX_OP_OR:
52 tmp |= oparg;
53 break;
54 case FUTEX_OP_ANDN:
55 tmp &= ~oparg;
56 break;
57 case FUTEX_OP_XOR:
58 tmp ^= oparg;
59 break;
60 default:
61 ret = -ENOSYS;
62 }
63
64 if (ret == 0 && unlikely(put_user(tmp, uaddr) != 0))
65 ret = -EFAULT;
66
67out_pagefault_enable:
68 pagefault_enable();
David Hildenbrandf3dae072015-05-11 17:52:13 +020069 preempt_enable();
Ley Foon Tan00f634b2014-11-06 15:19:34 +080070
Jiri Slaby30d6e0a2017-08-24 09:31:05 +020071 if (ret == 0)
72 *oval = oldval;
73
Ley Foon Tan00f634b2014-11-06 15:19:34 +080074 return ret;
75}
76
77/**
78 * futex_atomic_cmpxchg_inatomic() - Compare and exchange the content of the
79 * uaddr with newval if the current value is
80 * oldval.
81 * @uval: pointer to store content of @uaddr
82 * @uaddr: pointer to user space address
83 * @oldval: old value
84 * @newval: new value to store to @uaddr
85 *
86 * Return:
87 * 0 - On success
88 * <0 - On error
89 */
90static inline int
91futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
92 u32 oldval, u32 newval)
93{
94 u32 val;
95
David Hildenbrandd9b9ff82015-05-11 17:52:14 +020096 preempt_disable();
Romain Perierfba7cd62016-04-14 15:36:03 +020097 if (unlikely(get_user(val, uaddr) != 0)) {
98 preempt_enable();
Ley Foon Tan00f634b2014-11-06 15:19:34 +080099 return -EFAULT;
Romain Perierfba7cd62016-04-14 15:36:03 +0200100 }
Ley Foon Tan00f634b2014-11-06 15:19:34 +0800101
Romain Perierfba7cd62016-04-14 15:36:03 +0200102 if (val == oldval && unlikely(put_user(newval, uaddr) != 0)) {
103 preempt_enable();
Ley Foon Tan00f634b2014-11-06 15:19:34 +0800104 return -EFAULT;
Romain Perierfba7cd62016-04-14 15:36:03 +0200105 }
Ley Foon Tan00f634b2014-11-06 15:19:34 +0800106
107 *uval = val;
David Hildenbrandd9b9ff82015-05-11 17:52:14 +0200108 preempt_enable();
Ley Foon Tan00f634b2014-11-06 15:19:34 +0800109
110 return 0;
111}
112
113#else
Jeff Dikef8aaeace2006-01-08 01:01:32 -0800114static inline int
Jiri Slaby30d6e0a2017-08-24 09:31:05 +0200115arch_futex_atomic_op_inuser(int op, u32 oparg, int *oval, u32 __user *uaddr)
Jeff Dikef8aaeace2006-01-08 01:01:32 -0800116{
Jeff Dikef8aaeace2006-01-08 01:01:32 -0800117 int oldval = 0, ret;
Jeff Dikef8aaeace2006-01-08 01:01:32 -0800118
Peter Zijlstraa8663742006-12-06 20:32:20 -0800119 pagefault_disable();
Jeff Dikef8aaeace2006-01-08 01:01:32 -0800120
121 switch (op) {
122 case FUTEX_OP_SET:
123 case FUTEX_OP_ADD:
124 case FUTEX_OP_OR:
125 case FUTEX_OP_ANDN:
126 case FUTEX_OP_XOR:
127 default:
128 ret = -ENOSYS;
129 }
130
Peter Zijlstraa8663742006-12-06 20:32:20 -0800131 pagefault_enable();
Jeff Dikef8aaeace2006-01-08 01:01:32 -0800132
Jiri Slaby30d6e0a2017-08-24 09:31:05 +0200133 if (!ret)
134 *oval = oldval;
135
Jeff Dikef8aaeace2006-01-08 01:01:32 -0800136 return ret;
137}
138
Ingo Molnare9056f12006-03-27 01:16:21 -0800139static inline int
Michel Lespinasse8d7718a2011-03-10 18:50:58 -0800140futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
141 u32 oldval, u32 newval)
Ingo Molnare9056f12006-03-27 01:16:21 -0800142{
143 return -ENOSYS;
144}
145
Ley Foon Tan00f634b2014-11-06 15:19:34 +0800146#endif /* CONFIG_SMP */
Jeff Dikef8aaeace2006-01-08 01:01:32 -0800147#endif