[CRIU] [PATCH v5 14/33] bits: Add test_and_set_bit()
Kirill Tkhai
ktkhai at virtuozzo.com
Mon Dec 26 06:26:59 PST 2016
Borrowed from Linux Kernel
v5: New
Signed-off-by: Kirill Tkhai <ktkhai at virtuozzo.com>
---
criu/arch/aarch64/Makefile | 2 +
criu/arch/aarch64/bitops.S | 18 +++++++++++++
criu/arch/arm/Makefile | 2 +
criu/arch/arm/bitops.S | 22 ++++++++++++++++
include/common/arch/aarch64/asm/bitops.h | 2 +
include/common/arch/arm/asm/bitops.h | 2 +
include/common/arch/ppc64/asm/bitops.h | 41 ++++++++++++++++++++++++++++++
include/common/arch/x86/asm/bitops.h | 19 ++++++++++++++
8 files changed, 108 insertions(+)
create mode 100644 criu/arch/aarch64/bitops.S
create mode 100644 criu/arch/arm/bitops.S
diff --git a/criu/arch/aarch64/Makefile b/criu/arch/aarch64/Makefile
index 7b033e5bc..428e8081b 100644
--- a/criu/arch/aarch64/Makefile
+++ b/criu/arch/aarch64/Makefile
@@ -4,7 +4,9 @@ ccflags-y += -iquote $(obj) -iquote $(SRC_DIR)
ccflags-y += -iquote $(obj)/include -iquote $(SRC_DIR)/criu/include
ccflags-y += -iquote $(SRC_DIR)/include
ccflags-y += $(COMPEL_UAPI_INCLUDES)
+asflags-y += -D__ASSEMBLY__
obj-y += cpu.o
obj-y += crtools.o
obj-y += sigframe.o
+obj-y += bitops.o
diff --git a/criu/arch/aarch64/bitops.S b/criu/arch/aarch64/bitops.S
new file mode 100644
index 000000000..d8fa0efd8
--- /dev/null
+++ b/criu/arch/aarch64/bitops.S
@@ -0,0 +1,18 @@
+#include "common/asm/linkage.h"
+
+ .text
+
+ENTRY(test_and_set_bit)
+ and w3, w0, #63
+ eor w0, w0, w3
+ mov x2, #1
+ add x1, x1, x0, lsr #3
+ lsl x4, x2, x3
+1: ldaxr x2, [x1]
+ lsr x0, x2, x3
+ orr x2, x2, x4
+ stlxr w5, x2, [x1]
+ cbnz w5, 1b
+ and x0, x0, #1
+3: ret
+END(test_and_set_bit)
diff --git a/criu/arch/arm/Makefile b/criu/arch/arm/Makefile
index 5e60bacc4..99d236fae 100644
--- a/criu/arch/arm/Makefile
+++ b/criu/arch/arm/Makefile
@@ -4,7 +4,9 @@ ccflags-y += -iquote $(obj) -iquote $(SRC_DIR) -iquote $(obj)/include
ccflags-y += -iquote $(SRC_DIR)/criu/include -iquote $(SRC_DIR)/include
ccflags-y += $(COMPEL_UAPI_INCLUDES)
+asflags-y += -D__ASSEMBLY__
obj-y += cpu.o
obj-y += crtools.o
obj-y += sigframe.o
+obj-y += bitops.o
diff --git a/criu/arch/arm/bitops.S b/criu/arch/arm/bitops.S
new file mode 100644
index 000000000..db8360f51
--- /dev/null
+++ b/criu/arch/arm/bitops.S
@@ -0,0 +1,22 @@
+#include "common/asm/linkage.h"
+
+ENTRY(test_and_set_bit)
+ ands ip, r1, #3
+ strneb r1, [ip] @ assert word-aligned
+ mov r2, #1
+ and r3, r0, #31 @ Get bit offset
+ mov r0, r0, lsr #5
+ add r1, r1, r0, lsl #2 @ Get word offset
+ mov r3, r2, lsl r3 @ create mask
+ dmb ish
+1: ldrex r2, [r1]
+ ands r0, r2, r3 @ save old value of bit
+ orreq r2, r2, r3 @ toggle bit
+ strex ip, r2, [r1]
+ cmp ip, #0
+ bne 1b
+ dmb ish
+ cmp r0, #0
+ movne r0, #1
+2: bx lr
+END(test_and_set_bit)
diff --git a/include/common/arch/aarch64/asm/bitops.h b/include/common/arch/aarch64/asm/bitops.h
index cc1b7ca56..eb9aa6208 100644
--- a/include/common/arch/aarch64/asm/bitops.h
+++ b/include/common/arch/aarch64/asm/bitops.h
@@ -4,4 +4,6 @@
#include "common/compiler.h"
#include "common/asm-generic/bitops.h"
+extern int test_and_set_bit(int nr, volatile unsigned long *p);
+
#endif /* __CR_ASM_BITOPS_H__ */
diff --git a/include/common/arch/arm/asm/bitops.h b/include/common/arch/arm/asm/bitops.h
index cc1b7ca56..eb9aa6208 100644
--- a/include/common/arch/arm/asm/bitops.h
+++ b/include/common/arch/arm/asm/bitops.h
@@ -4,4 +4,6 @@
#include "common/compiler.h"
#include "common/asm-generic/bitops.h"
+extern int test_and_set_bit(int nr, volatile unsigned long *p);
+
#endif /* __CR_ASM_BITOPS_H__ */
diff --git a/include/common/arch/ppc64/asm/bitops.h b/include/common/arch/ppc64/asm/bitops.h
index 8da093f60..f9a327ccd 100644
--- a/include/common/arch/ppc64/asm/bitops.h
+++ b/include/common/arch/ppc64/asm/bitops.h
@@ -59,6 +59,17 @@
#define PPC_BIT(bit) (1UL << PPC_BITLSHIFT(bit))
#define PPC_BITMASK(bs, be) ((PPC_BIT(bs) - PPC_BIT(be)) | PPC_BIT(bs))
+#define PPC_INST_LDARX 0x7c0000a8
+#define ___PPC_RA(a) (((a) & 0x1f) << 16)
+#define ___PPC_RB(b) (((b) & 0x1f) << 11)
+#define ___PPC_RS(s) (((s) & 0x1f) << 21)
+#define __PPC_EH(eh) (((eh) & 0x1) << 0)
+#define ___PPC_RT(t) ___PPC_RS(t)
+
+#define PPC_LDARX(t, a, b, eh) stringify_in_c(.long PPC_INST_LDARX | \
+ ___PPC_RT(t) | ___PPC_RA(a) | \
+ ___PPC_RB(b) | __PPC_EH(eh))
+#define PPC_LLARX(t, a, b, eh) PPC_LDARX(t, a, b, eh)
/* Macro for generating the ***_bits() functions */
#define DEFINE_BITOP(fn, op) \
@@ -101,6 +112,36 @@ static inline int test_bit(int nr, const volatile unsigned long *addr)
return 1UL & (addr[BIT_WORD(nr)] >> (nr & (BITS_PER_LONG-1)));
}
+/* Like DEFINE_BITOP(), with changes to the arguments to 'op' and the output
+ * operands. */
+#define DEFINE_TESTOP(fn, op, prefix, postfix, eh) \
+static __inline__ unsigned long fn( \
+ unsigned long mask, \
+ volatile unsigned long *_p) \
+{ \
+ unsigned long old, t; \
+ unsigned long *p = (unsigned long *)_p; \
+ __asm__ __volatile__ ( \
+ prefix \
+"1:" PPC_LLARX(%0,0,%3,eh) "\n" \
+ stringify_in_c(op) "%1,%0,%2\n" \
+ "stdcx. %1,0,%3\n" \
+ "bne- 1b\n" \
+ postfix \
+ : "=&r" (old), "=&r" (t) \
+ : "r" (mask), "r" (p) \
+ : "cc", "memory"); \
+ return (old & mask); \
+}
+
+DEFINE_TESTOP(test_and_set_bits, or, "\nLWSYNC\n", "\nsync\n", 0)
+
+static __inline__ int test_and_set_bit(unsigned long nr,
+ volatile unsigned long *addr)
+{
+ return test_and_set_bits(BIT_MASK(nr), addr + BIT_WORD(nr)) != 0;
+}
+
/*
* Return the zero-based bit position (LE, not IBM bit numbering) of
* the most significant 1-bit in a double word.
diff --git a/include/common/arch/x86/asm/bitops.h b/include/common/arch/x86/asm/bitops.h
index 5c6895532..b60ead7fa 100644
--- a/include/common/arch/x86/asm/bitops.h
+++ b/include/common/arch/x86/asm/bitops.h
@@ -1,6 +1,7 @@
#ifndef __CR_BITOPS_H__
#define __CR_BITOPS_H__
+#include "common/arch/x86/asm/cmpxchg.h"
#include "common/asm/bitsperlong.h"
#define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d))
@@ -47,6 +48,24 @@ static inline void clear_bit(int nr, volatile unsigned long *addr)
}
/**
+ * test_and_set_bit - Set a bit and return its old value
+ * @nr: Bit to set
+ * @addr: Address to count from
+ *
+ * This operation is atomic and cannot be reordered.
+ * It also implies a memory barrier.
+ */
+static inline int test_and_set_bit(int nr, volatile unsigned long *addr)
+{
+ int oldbit;
+
+ asm volatile(LOCK_PREFIX "bts %2,%1\n\t"
+ "sbb %0,%0" : "=r" (oldbit), ADDR : "Ir" (nr) : "memory");
+
+ return oldbit;
+}
+
+/**
* __ffs - find first set bit in word
* @word: The word to search
*
More information about the CRIU
mailing list