2019-06-03 13:44:50 +08:00
|
|
|
/* SPDX-License-Identifier: GPL-2.0-only */
|
2012-03-05 19:49:29 +08:00
|
|
|
/*
|
|
|
|
* Copyright (C) 2012 ARM Ltd.
|
|
|
|
*/
|
|
|
|
#ifndef __ASM_FUTEX_H
|
|
|
|
#define __ASM_FUTEX_H
|
|
|
|
|
|
|
|
#include <linux/futex.h>
|
|
|
|
#include <linux/uaccess.h>
|
2015-07-23 02:05:54 +08:00
|
|
|
|
2012-03-05 19:49:29 +08:00
|
|
|
#include <asm/errno.h>
|
|
|
|
|
2019-04-08 21:23:17 +08:00
|
|
|
#define FUTEX_MAX_LOOPS 128 /* What's the largest number you can think of? */
|
|
|
|
|
2012-03-05 19:49:29 +08:00
|
|
|
#define __futex_atomic_op(insn, ret, oldval, uaddr, tmp, oparg) \
|
2016-07-01 21:58:21 +08:00
|
|
|
do { \
|
2019-04-08 21:23:17 +08:00
|
|
|
unsigned int loops = FUTEX_MAX_LOOPS; \
|
|
|
|
\
|
2016-07-01 21:58:21 +08:00
|
|
|
uaccess_enable(); \
|
2012-03-05 19:49:29 +08:00
|
|
|
asm volatile( \
|
2015-05-29 20:31:10 +08:00
|
|
|
" prfm pstl1strm, %2\n" \
|
arm64: atomics: fix use of acquire + release for full barrier semantics
Linux requires a number of atomic operations to provide full barrier
semantics, that is no memory accesses after the operation can be
observed before any accesses up to and including the operation in
program order.
On arm64, these operations have been incorrectly implemented as follows:
// A, B, C are independent memory locations
<Access [A]>
// atomic_op (B)
1: ldaxr x0, [B] // Exclusive load with acquire
<op(B)>
stlxr w1, x0, [B] // Exclusive store with release
cbnz w1, 1b
<Access [C]>
The assumption here being that two half barriers are equivalent to a
full barrier, so the only permitted ordering would be A -> B -> C
(where B is the atomic operation involving both a load and a store).
Unfortunately, this is not the case by the letter of the architecture
and, in fact, the accesses to A and C are permitted to pass their
nearest half barrier resulting in orderings such as Bl -> A -> C -> Bs
or Bl -> C -> A -> Bs (where Bl is the load-acquire on B and Bs is the
store-release on B). This is a clear violation of the full barrier
requirement.
The simple way to fix this is to implement the same algorithm as ARMv7
using explicit barriers:
<Access [A]>
// atomic_op (B)
dmb ish // Full barrier
1: ldxr x0, [B] // Exclusive load
<op(B)>
stxr w1, x0, [B] // Exclusive store
cbnz w1, 1b
dmb ish // Full barrier
<Access [C]>
but this has the undesirable effect of introducing *two* full barrier
instructions. A better approach is actually the following, non-intuitive
sequence:
<Access [A]>
// atomic_op (B)
1: ldxr x0, [B] // Exclusive load
<op(B)>
stlxr w1, x0, [B] // Exclusive store with release
cbnz w1, 1b
dmb ish // Full barrier
<Access [C]>
The simple observations here are:
- The dmb ensures that no subsequent accesses (e.g. the access to C)
can enter or pass the atomic sequence.
- The dmb also ensures that no prior accesses (e.g. the access to A)
can pass the atomic sequence.
- Therefore, no prior access can pass a subsequent access, or
vice-versa (i.e. A is strictly ordered before C).
- The stlxr ensures that no prior access can pass the store component
of the atomic operation.
The only tricky part remaining is the ordering between the ldxr and the
access to A, since the absence of the first dmb means that we're now
permitting re-ordering between the ldxr and any prior accesses.
From an (arbitrary) observer's point of view, there are two scenarios:
1. We have observed the ldxr. This means that if we perform a store to
[B], the ldxr will still return older data. If we can observe the
ldxr, then we can potentially observe the permitted re-ordering
with the access to A, which is clearly an issue when compared to
the dmb variant of the code. Thankfully, the exclusive monitor will
save us here since it will be cleared as a result of the store and
the ldxr will retry. Notice that any use of a later memory
observation to imply observation of the ldxr will also imply
observation of the access to A, since the stlxr/dmb ensure strict
ordering.
2. We have not observed the ldxr. This means we can perform a store
and influence the later ldxr. However, that doesn't actually tell
us anything about the access to [A], so we've not lost anything
here either when compared to the dmb variant.
This patch implements this solution for our barriered atomic operations,
ensuring that we satisfy the full barrier requirements where they are
needed.
Cc: <stable@vger.kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Signed-off-by: Will Deacon <will.deacon@arm.com>
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
2014-02-04 20:29:12 +08:00
|
|
|
"1: ldxr %w1, %2\n" \
|
2012-03-05 19:49:29 +08:00
|
|
|
insn "\n" \
|
2019-04-08 19:45:09 +08:00
|
|
|
"2: stlxr %w0, %w3, %2\n" \
|
2019-04-08 21:23:17 +08:00
|
|
|
" cbz %w0, 3f\n" \
|
|
|
|
" sub %w4, %w4, %w0\n" \
|
|
|
|
" cbnz %w4, 1b\n" \
|
|
|
|
" mov %w0, %w7\n" \
|
2012-03-05 19:49:29 +08:00
|
|
|
"3:\n" \
|
2019-04-08 21:23:17 +08:00
|
|
|
" dmb ish\n" \
|
2012-03-05 19:49:29 +08:00
|
|
|
" .pushsection .fixup,\"ax\"\n" \
|
2013-11-07 03:31:24 +08:00
|
|
|
" .align 2\n" \
|
2019-04-08 21:23:17 +08:00
|
|
|
"4: mov %w0, %w6\n" \
|
2012-03-05 19:49:29 +08:00
|
|
|
" b 3b\n" \
|
|
|
|
" .popsection\n" \
|
2016-01-01 22:02:12 +08:00
|
|
|
_ASM_EXTABLE(1b, 4b) \
|
|
|
|
_ASM_EXTABLE(2b, 4b) \
|
2019-04-08 21:23:17 +08:00
|
|
|
: "=&r" (ret), "=&r" (oldval), "+Q" (*uaddr), "=&r" (tmp), \
|
|
|
|
"+r" (loops) \
|
|
|
|
: "r" (oparg), "Ir" (-EFAULT), "Ir" (-EAGAIN) \
|
2016-07-01 21:58:21 +08:00
|
|
|
: "memory"); \
|
|
|
|
uaccess_disable(); \
|
|
|
|
} while (0)
|
2012-03-05 19:49:29 +08:00
|
|
|
|
|
|
|
static inline int
|
2018-02-05 23:34:24 +08:00
|
|
|
arch_futex_atomic_op_inuser(int op, int oparg, int *oval, u32 __user *_uaddr)
|
2012-03-05 19:49:29 +08:00
|
|
|
{
|
2019-04-17 15:21:21 +08:00
|
|
|
int oldval = 0, ret, tmp;
|
2018-02-05 23:34:24 +08:00
|
|
|
u32 __user *uaddr = __uaccess_mask_ptr(_uaddr);
|
2012-03-05 19:49:29 +08:00
|
|
|
|
2020-02-16 23:17:27 +08:00
|
|
|
if (!access_ok(_uaddr, sizeof(u32)))
|
|
|
|
return -EFAULT;
|
2012-03-05 19:49:29 +08:00
|
|
|
|
|
|
|
switch (op) {
|
|
|
|
case FUTEX_OP_SET:
|
2019-04-08 21:23:17 +08:00
|
|
|
__futex_atomic_op("mov %w3, %w5",
|
2012-03-05 19:49:29 +08:00
|
|
|
ret, oldval, uaddr, tmp, oparg);
|
|
|
|
break;
|
|
|
|
case FUTEX_OP_ADD:
|
2019-04-08 21:23:17 +08:00
|
|
|
__futex_atomic_op("add %w3, %w1, %w5",
|
2012-03-05 19:49:29 +08:00
|
|
|
ret, oldval, uaddr, tmp, oparg);
|
|
|
|
break;
|
|
|
|
case FUTEX_OP_OR:
|
2019-04-08 21:23:17 +08:00
|
|
|
__futex_atomic_op("orr %w3, %w1, %w5",
|
2012-03-05 19:49:29 +08:00
|
|
|
ret, oldval, uaddr, tmp, oparg);
|
|
|
|
break;
|
|
|
|
case FUTEX_OP_ANDN:
|
2019-04-08 21:23:17 +08:00
|
|
|
__futex_atomic_op("and %w3, %w1, %w5",
|
2012-03-05 19:49:29 +08:00
|
|
|
ret, oldval, uaddr, tmp, ~oparg);
|
|
|
|
break;
|
|
|
|
case FUTEX_OP_XOR:
|
2019-04-08 21:23:17 +08:00
|
|
|
__futex_atomic_op("eor %w3, %w1, %w5",
|
2012-03-05 19:49:29 +08:00
|
|
|
ret, oldval, uaddr, tmp, oparg);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
ret = -ENOSYS;
|
|
|
|
}
|
|
|
|
|
2017-08-24 15:31:05 +08:00
|
|
|
if (!ret)
|
|
|
|
*oval = oldval;
|
|
|
|
|
2012-03-05 19:49:29 +08:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline int
|
2018-02-05 23:34:24 +08:00
|
|
|
futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *_uaddr,
|
2012-03-05 19:49:29 +08:00
|
|
|
u32 oldval, u32 newval)
|
|
|
|
{
|
|
|
|
int ret = 0;
|
2019-04-08 21:23:17 +08:00
|
|
|
unsigned int loops = FUTEX_MAX_LOOPS;
|
2012-03-05 19:49:29 +08:00
|
|
|
u32 val, tmp;
|
2018-02-05 23:34:24 +08:00
|
|
|
u32 __user *uaddr;
|
2012-03-05 19:49:29 +08:00
|
|
|
|
Remove 'type' argument from access_ok() function
Nobody has actually used the type (VERIFY_READ vs VERIFY_WRITE) argument
of the user address range verification function since we got rid of the
old racy i386-only code to walk page tables by hand.
It existed because the original 80386 would not honor the write protect
bit when in kernel mode, so you had to do COW by hand before doing any
user access. But we haven't supported that in a long time, and these
days the 'type' argument is a purely historical artifact.
A discussion about extending 'user_access_begin()' to do the range
checking resulted this patch, because there is no way we're going to
move the old VERIFY_xyz interface to that model. And it's best done at
the end of the merge window when I've done most of my merges, so let's
just get this done once and for all.
This patch was mostly done with a sed-script, with manual fix-ups for
the cases that weren't of the trivial 'access_ok(VERIFY_xyz' form.
There were a couple of notable cases:
- csky still had the old "verify_area()" name as an alias.
- the iter_iov code had magical hardcoded knowledge of the actual
values of VERIFY_{READ,WRITE} (not that they mattered, since nothing
really used it)
- microblaze used the type argument for a debug printout
but other than those oddities this should be a total no-op patch.
I tried to fix up all architectures, did fairly extensive grepping for
access_ok() uses, and the changes are trivial, but I may have missed
something. Any missed conversion should be trivially fixable, though.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2019-01-04 10:57:57 +08:00
|
|
|
if (!access_ok(_uaddr, sizeof(u32)))
|
2012-03-05 19:49:29 +08:00
|
|
|
return -EFAULT;
|
|
|
|
|
2018-02-05 23:34:24 +08:00
|
|
|
uaddr = __uaccess_mask_ptr(_uaddr);
|
2016-07-01 21:58:21 +08:00
|
|
|
uaccess_enable();
|
2012-03-05 19:49:29 +08:00
|
|
|
asm volatile("// futex_atomic_cmpxchg_inatomic\n"
|
2015-05-29 20:31:10 +08:00
|
|
|
" prfm pstl1strm, %2\n"
|
arm64: atomics: fix use of acquire + release for full barrier semantics
Linux requires a number of atomic operations to provide full barrier
semantics, that is no memory accesses after the operation can be
observed before any accesses up to and including the operation in
program order.
On arm64, these operations have been incorrectly implemented as follows:
// A, B, C are independent memory locations
<Access [A]>
// atomic_op (B)
1: ldaxr x0, [B] // Exclusive load with acquire
<op(B)>
stlxr w1, x0, [B] // Exclusive store with release
cbnz w1, 1b
<Access [C]>
The assumption here being that two half barriers are equivalent to a
full barrier, so the only permitted ordering would be A -> B -> C
(where B is the atomic operation involving both a load and a store).
Unfortunately, this is not the case by the letter of the architecture
and, in fact, the accesses to A and C are permitted to pass their
nearest half barrier resulting in orderings such as Bl -> A -> C -> Bs
or Bl -> C -> A -> Bs (where Bl is the load-acquire on B and Bs is the
store-release on B). This is a clear violation of the full barrier
requirement.
The simple way to fix this is to implement the same algorithm as ARMv7
using explicit barriers:
<Access [A]>
// atomic_op (B)
dmb ish // Full barrier
1: ldxr x0, [B] // Exclusive load
<op(B)>
stxr w1, x0, [B] // Exclusive store
cbnz w1, 1b
dmb ish // Full barrier
<Access [C]>
but this has the undesirable effect of introducing *two* full barrier
instructions. A better approach is actually the following, non-intuitive
sequence:
<Access [A]>
// atomic_op (B)
1: ldxr x0, [B] // Exclusive load
<op(B)>
stlxr w1, x0, [B] // Exclusive store with release
cbnz w1, 1b
dmb ish // Full barrier
<Access [C]>
The simple observations here are:
- The dmb ensures that no subsequent accesses (e.g. the access to C)
can enter or pass the atomic sequence.
- The dmb also ensures that no prior accesses (e.g. the access to A)
can pass the atomic sequence.
- Therefore, no prior access can pass a subsequent access, or
vice-versa (i.e. A is strictly ordered before C).
- The stlxr ensures that no prior access can pass the store component
of the atomic operation.
The only tricky part remaining is the ordering between the ldxr and the
access to A, since the absence of the first dmb means that we're now
permitting re-ordering between the ldxr and any prior accesses.
From an (arbitrary) observer's point of view, there are two scenarios:
1. We have observed the ldxr. This means that if we perform a store to
[B], the ldxr will still return older data. If we can observe the
ldxr, then we can potentially observe the permitted re-ordering
with the access to A, which is clearly an issue when compared to
the dmb variant of the code. Thankfully, the exclusive monitor will
save us here since it will be cleared as a result of the store and
the ldxr will retry. Notice that any use of a later memory
observation to imply observation of the ldxr will also imply
observation of the access to A, since the stlxr/dmb ensure strict
ordering.
2. We have not observed the ldxr. This means we can perform a store
and influence the later ldxr. However, that doesn't actually tell
us anything about the access to [A], so we've not lost anything
here either when compared to the dmb variant.
This patch implements this solution for our barriered atomic operations,
ensuring that we satisfy the full barrier requirements where they are
needed.
Cc: <stable@vger.kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Signed-off-by: Will Deacon <will.deacon@arm.com>
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
2014-02-04 20:29:12 +08:00
|
|
|
"1: ldxr %w1, %2\n"
|
2019-04-08 21:23:17 +08:00
|
|
|
" sub %w3, %w1, %w5\n"
|
|
|
|
" cbnz %w3, 4f\n"
|
|
|
|
"2: stlxr %w3, %w6, %2\n"
|
|
|
|
" cbz %w3, 3f\n"
|
|
|
|
" sub %w4, %w4, %w3\n"
|
|
|
|
" cbnz %w4, 1b\n"
|
|
|
|
" mov %w0, %w8\n"
|
2012-03-05 19:49:29 +08:00
|
|
|
"3:\n"
|
2019-04-08 21:23:17 +08:00
|
|
|
" dmb ish\n"
|
|
|
|
"4:\n"
|
2012-03-05 19:49:29 +08:00
|
|
|
" .pushsection .fixup,\"ax\"\n"
|
2019-04-08 21:23:17 +08:00
|
|
|
"5: mov %w0, %w7\n"
|
|
|
|
" b 4b\n"
|
2012-03-05 19:49:29 +08:00
|
|
|
" .popsection\n"
|
2019-04-08 21:23:17 +08:00
|
|
|
_ASM_EXTABLE(1b, 5b)
|
|
|
|
_ASM_EXTABLE(2b, 5b)
|
|
|
|
: "+r" (ret), "=&r" (val), "+Q" (*uaddr), "=&r" (tmp), "+r" (loops)
|
|
|
|
: "r" (oldval), "r" (newval), "Ir" (-EFAULT), "Ir" (-EAGAIN)
|
2014-02-04 20:29:13 +08:00
|
|
|
: "memory");
|
2016-07-01 21:58:21 +08:00
|
|
|
uaccess_disable();
|
2012-03-05 19:49:29 +08:00
|
|
|
|
2019-04-10 18:49:11 +08:00
|
|
|
if (!ret)
|
|
|
|
*uval = val;
|
|
|
|
|
2012-03-05 19:49:29 +08:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif /* __ASM_FUTEX_H */
|