Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit df77abca authored by Will Deacon's avatar Will Deacon Committed by Russell King
Browse files

ARM: 7099/1: futex: preserve oldval in SMP __futex_atomic_op



The SMP implementation of __futex_atomic_op clobbers oldval with the
status flag from the exclusive store. This causes it to always read as
zero when performing the FUTEX_OP_CMP_* operation.

This patch updates the ARM __futex_atomic_op implementations to take a
tmp argument, allowing us to store the strex status flag without
overwriting the register containing oldval.

Cc: stable@kernel.org
Reported-by: default avatarMinho Ban <mhban@samsung.com>
Reviewed-by: default avatarNicolas Pitre <nicolas.pitre@linaro.org>
Signed-off-by: default avatarWill Deacon <will.deacon@arm.com>
Signed-off-by: default avatarRussell King <rmk+kernel@arm.linux.org.uk>
parent d8e89b47
Loading
Loading
Loading
Loading
+17 −17
Original line number Diff line number Diff line
@@ -25,17 +25,17 @@

#ifdef CONFIG_SMP

#define __futex_atomic_op(insn, ret, oldval, uaddr, oparg)	\
#define __futex_atomic_op(insn, ret, oldval, tmp, uaddr, oparg)	\
	smp_mb();						\
	__asm__ __volatile__(					\
	"1:	ldrex	%1, [%2]\n"				\
	"1:	ldrex	%1, [%3]\n"				\
	"	" insn "\n"					\
	"2:	strex	%1, %0, [%2]\n"				\
	"	teq	%1, #0\n"				\
	"2:	strex	%2, %0, [%3]\n"				\
	"	teq	%2, #0\n"				\
	"	bne	1b\n"					\
	"	mov	%0, #0\n"				\
	__futex_atomic_ex_table("%4")				\
	: "=&r" (ret), "=&r" (oldval)				\
	__futex_atomic_ex_table("%5")				\
	: "=&r" (ret), "=&r" (oldval), "=&r" (tmp)		\
	: "r" (uaddr), "r" (oparg), "Ir" (-EFAULT)		\
	: "cc", "memory")

@@ -73,14 +73,14 @@ futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
#include <linux/preempt.h>
#include <asm/domain.h>

#define __futex_atomic_op(insn, ret, oldval, uaddr, oparg)	\
#define __futex_atomic_op(insn, ret, oldval, tmp, uaddr, oparg)	\
	__asm__ __volatile__(					\
	"1:	" T(ldr) "	%1, [%2]\n"			\
	"1:	" T(ldr) "	%1, [%3]\n"			\
	"	" insn "\n"					\
	"2:	" T(str) "	%0, [%2]\n"			\
	"2:	" T(str) "	%0, [%3]\n"			\
	"	mov	%0, #0\n"				\
	__futex_atomic_ex_table("%4")				\
	: "=&r" (ret), "=&r" (oldval)				\
	__futex_atomic_ex_table("%5")				\
	: "=&r" (ret), "=&r" (oldval), "=&r" (tmp)		\
	: "r" (uaddr), "r" (oparg), "Ir" (-EFAULT)		\
	: "cc", "memory")

@@ -117,7 +117,7 @@ futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr)
	int cmp = (encoded_op >> 24) & 15;
	int oparg = (encoded_op << 8) >> 20;
	int cmparg = (encoded_op << 20) >> 20;
	int oldval = 0, ret;
	int oldval = 0, ret, tmp;

	if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
		oparg = 1 << oparg;
@@ -129,19 +129,19 @@ futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr)

	switch (op) {
	case FUTEX_OP_SET:
		__futex_atomic_op("mov	%0, %3", ret, oldval, uaddr, oparg);
		__futex_atomic_op("mov	%0, %4", ret, oldval, tmp, uaddr, oparg);
		break;
	case FUTEX_OP_ADD:
		__futex_atomic_op("add	%0, %1, %3", ret, oldval, uaddr, oparg);
		__futex_atomic_op("add	%0, %1, %4", ret, oldval, tmp, uaddr, oparg);
		break;
	case FUTEX_OP_OR:
		__futex_atomic_op("orr	%0, %1, %3", ret, oldval, uaddr, oparg);
		__futex_atomic_op("orr	%0, %1, %4", ret, oldval, tmp, uaddr, oparg);
		break;
	case FUTEX_OP_ANDN:
		__futex_atomic_op("and	%0, %1, %3", ret, oldval, uaddr, ~oparg);
		__futex_atomic_op("and	%0, %1, %4", ret, oldval, tmp, uaddr, ~oparg);
		break;
	case FUTEX_OP_XOR:
		__futex_atomic_op("eor	%0, %1, %3", ret, oldval, uaddr, oparg);
		__futex_atomic_op("eor	%0, %1, %4", ret, oldval, tmp, uaddr, oparg);
		break;
	default:
		ret = -ENOSYS;