blob: 2a19215baae53aa1a6e23d01c5e714c3353c0968 [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
Arnd Bergmann3f2beda2021-10-26 12:03:47 +02009#ifndef futex_atomic_cmpxchg_inatomic
Ley Foon Tan00f634b2014-11-06 15:19:34 +080010#ifndef CONFIG_SMP
11/*
12 * The following implementation only for uniprocessor machines.
David Hildenbrandf3dae07e2015-05-11 17:52:13 +020013 * It relies on preempt_disable() ensuring mutual exclusion.
Ley Foon Tan00f634b2014-11-06 15:19:34 +080014 *
15 */
Arnd Bergmann3f2beda2021-10-26 12:03:47 +020016#define futex_atomic_cmpxchg_inatomic(uval, uaddr, oldval, newval) \
Arnd Bergmann4e0d8462021-11-26 10:58:40 +010017 futex_atomic_cmpxchg_inatomic_local(uval, uaddr, oldval, newval)
Arnd Bergmann3f2beda2021-10-26 12:03:47 +020018#define arch_futex_atomic_op_inuser(op, oparg, oval, uaddr) \
Arnd Bergmann4e0d8462021-11-26 10:58:40 +010019 futex_atomic_op_inuser_local(op, oparg, oval, uaddr)
Arnd Bergmann3f2beda2021-10-26 12:03:47 +020020#endif /* CONFIG_SMP */
21#endif
Ley Foon Tan00f634b2014-11-06 15:19:34 +080022
23/**
Arnd Bergmann0f09c272021-12-03 09:07:56 +010024 * futex_atomic_op_inuser_local() - Atomic arithmetic operation with constant
Ley Foon Tan00f634b2014-11-06 15:19:34 +080025 * argument and comparison of the previous
26 * futex value with another constant.
27 *
28 * @encoded_op: encoded operation to execute
29 * @uaddr: pointer to user space address
30 *
31 * Return:
32 * 0 - On success
Will Deacon42750352019-04-10 11:51:54 +010033 * -EFAULT - User access resulted in a page fault
34 * -EAGAIN - Atomic operation was unable to complete due to contention
35 * -ENOSYS - Operation not supported
Ley Foon Tan00f634b2014-11-06 15:19:34 +080036 */
37static inline int
Arnd Bergmann3f2beda2021-10-26 12:03:47 +020038futex_atomic_op_inuser_local(int op, u32 oparg, int *oval, u32 __user *uaddr)
Ley Foon Tan00f634b2014-11-06 15:19:34 +080039{
Ley Foon Tan00f634b2014-11-06 15:19:34 +080040 int oldval, ret;
41 u32 tmp;
42
David Hildenbrandf3dae07e2015-05-11 17:52:13 +020043 preempt_disable();
Ley Foon Tan00f634b2014-11-06 15:19:34 +080044
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:
David Hildenbrandf3dae07e2015-05-11 17:52:13 +020076 preempt_enable();
Ley Foon Tan00f634b2014-11-06 15:19:34 +080077
Jiri Slaby30d6e0a2017-08-24 09:31:05 +020078 if (ret == 0)
79 *oval = oldval;
80
Ley Foon Tan00f634b2014-11-06 15:19:34 +080081 return ret;
82}
83
84/**
Arnd Bergmann3f2beda2021-10-26 12:03:47 +020085 * futex_atomic_cmpxchg_inatomic_local() - Compare and exchange the content of the
Ley Foon Tan00f634b2014-11-06 15:19:34 +080086 * uaddr with newval if the current value is
87 * oldval.
88 * @uval: pointer to store content of @uaddr
89 * @uaddr: pointer to user space address
90 * @oldval: old value
91 * @newval: new value to store to @uaddr
92 *
93 * Return:
94 * 0 - On success
Will Deacon42750352019-04-10 11:51:54 +010095 * -EFAULT - User access resulted in a page fault
96 * -EAGAIN - Atomic operation was unable to complete due to contention
Ley Foon Tan00f634b2014-11-06 15:19:34 +080097 */
98static inline int
Arnd Bergmann3f2beda2021-10-26 12:03:47 +020099futex_atomic_cmpxchg_inatomic_local(u32 *uval, u32 __user *uaddr,
Ley Foon Tan00f634b2014-11-06 15:19:34 +0800100 u32 oldval, u32 newval)
101{
102 u32 val;
103
David Hildenbrandd9b9ff82015-05-11 17:52:14 +0200104 preempt_disable();
Romain Perierfba7cd62016-04-14 15:36:03 +0200105 if (unlikely(get_user(val, uaddr) != 0)) {
106 preempt_enable();
Ley Foon Tan00f634b2014-11-06 15:19:34 +0800107 return -EFAULT;
Romain Perierfba7cd62016-04-14 15:36:03 +0200108 }
Ley Foon Tan00f634b2014-11-06 15:19:34 +0800109
Romain Perierfba7cd62016-04-14 15:36:03 +0200110 if (val == oldval && unlikely(put_user(newval, uaddr) != 0)) {
111 preempt_enable();
Ley Foon Tan00f634b2014-11-06 15:19:34 +0800112 return -EFAULT;
Romain Perierfba7cd62016-04-14 15:36:03 +0200113 }
Ley Foon Tan00f634b2014-11-06 15:19:34 +0800114
115 *uval = val;
David Hildenbrandd9b9ff82015-05-11 17:52:14 +0200116 preempt_enable();
Ley Foon Tan00f634b2014-11-06 15:19:34 +0800117
118 return 0;
119}
120
Jeff Dikef8aaeace2006-01-08 01:01:32 -0800121#endif