From e40140db5da810c4ead632ae5d346558f2b93695 Mon Sep 17 00:00:00 2001
From: Julien Grall <julien.grall@arm.com>
Date: Mon, 29 Apr 2019 15:05:18 +0100
Subject: [PATCH v2 4.12 05/17] xen/arm64: bitops: Rewrite bitop helpers in C

This is part of XSA-295.

Signed-off-by: Julien Grall <julien.grall@arm.com>
Reviewed-by: Stefano Stabellini <sstabellini@kernel.org>
Signed-off-by: Stefano Stabellini <stefanos@xilinx.com>
---
 xen/arch/arm/README.LinuxPrimitives |  1 -
 xen/arch/arm/arm64/lib/bitops.S     | 67 ---------------------
 xen/arch/arm/arm64/lib/bitops.c     | 90 +++++++++++++++++++++++++++++
 3 files changed, 90 insertions(+), 68 deletions(-)
 delete mode 100644 xen/arch/arm/arm64/lib/bitops.S
 create mode 100644 xen/arch/arm/arm64/lib/bitops.c

diff --git a/xen/arch/arm/README.LinuxPrimitives b/xen/arch/arm/README.LinuxPrimitives
index 028e8721f9..891667a5da 100644
--- a/xen/arch/arm/README.LinuxPrimitives
+++ b/xen/arch/arm/README.LinuxPrimitives
@@ -8,7 +8,6 @@ arm64:
 
 bitops: last sync @ v3.16-rc6 (last commit: 8715466b6027)
 
-linux/arch/arm64/lib/bitops.S           xen/arch/arm/arm64/lib/bitops.S
 linux/arch/arm64/include/asm/bitops.h   xen/include/asm-arm/arm64/bitops.h
 
 ---------------------------------------------------------------------
diff --git a/xen/arch/arm/arm64/lib/bitops.S b/xen/arch/arm/arm64/lib/bitops.S
deleted file mode 100644
index 6471dd1875..0000000000
--- a/xen/arch/arm/arm64/lib/bitops.S
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Based on linux/arch/arm64/lib/bitops.h which in turn is
- * Based on arch/arm/lib/bitops.h
- *
- * Copyright (C) 2013 ARM Ltd.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-/*
- * x0: bits 4:0  bit offset
- *     bits 31:5 word offset
- * x1: address
- */
-	.macro	bitop, name, instr
-ENTRY(	\name	)
-	and	w3, w0, #31		// Get bit offset
-	eor	w0, w0, w3		// Clear low bits
-	mov	x2, #1
-	add	x1, x1, x0, lsr #3	// Get word offset
-	lsl	x3, x2, x3		// Create mask
-1:	ldxr	w2, [x1]
-	\instr	w2, w2, w3
-	stxr	w0, w2, [x1]
-	cbnz	w0, 1b
-	ret
-ENDPROC(\name	)
-	.endm
-
-	.macro	testop, name, instr
-ENTRY(	\name	)
-	and	w3, w0, #31		// Get bit offset
-	eor	w0, w0, w3		// Clear low bits
-	mov	x2, #1
-	add	x1, x1, x0, lsr #3	// Get word offset
-	lsl	x4, x2, x3		// Create mask
-1:	ldxr	w2, [x1]
-	lsr	w0, w2, w3		// Save old value of bit
-	\instr	w2, w2, w4		// toggle bit
-	stlxr	w5, w2, [x1]
-	cbnz	w5, 1b
-	dmb	ish
-	and	w0, w0, #1
-3:	ret
-ENDPROC(\name	)
-	.endm
-
-/*
- * Atomic bit operations.
- */
-	bitop	change_bit, eor
-	bitop	clear_bit, bic
-	bitop	set_bit, orr
-
-	testop	test_and_change_bit, eor
-	testop	test_and_clear_bit, bic
-	testop	test_and_set_bit, orr
diff --git a/xen/arch/arm/arm64/lib/bitops.c b/xen/arch/arm/arm64/lib/bitops.c
new file mode 100644
index 0000000000..b1c681c642
--- /dev/null
+++ b/xen/arch/arm/arm64/lib/bitops.c
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2018 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <xen/bitops.h>
+#include <asm/system.h>
+
+/*
+ * The atomic bit operations pass the number of bit in a signed number
+ * (not sure why). This has the drawback to increase the complexity of
+ * the resulting assembly.
+ *
+ * To generate simpler code, the number of bit (nr) will be cast to
+ * unsigned int.
+ *
+ * XXX: Rework the interface to use unsigned int.
+ */
+
+#define bitop(name, instr)                                                  \
+void name(int nr, volatile void *p)                                         \
+{                                                                           \
+    volatile uint32_t *ptr = (uint32_t *)p + BIT_WORD((unsigned int)nr);    \
+    const uint32_t mask = BIT_MASK((unsigned int)nr);                       \
+    unsigned long res, tmp;                                                 \
+                                                                            \
+    do                                                                      \
+    {                                                                       \
+        asm volatile ("// " __stringify(name) "\n"                          \
+        "   ldxr    %w2, %1\n"                                              \
+        "   " __stringify(instr) "     %w2, %w2, %w3\n"                     \
+        "   stxr    %w0, %w2, %1\n"                                         \
+        : "=&r" (res), "+Q" (*ptr), "=&r" (tmp)                             \
+        : "r" (mask));                                                      \
+    } while ( res );                                                        \
+}                                                                           \
+
+#define testop(name, instr)                                                 \
+int name(int nr, volatile void *p)                                          \
+{                                                                           \
+    volatile uint32_t *ptr = (uint32_t *)p + BIT_WORD((unsigned int)nr);    \
+    unsigned int bit = (unsigned int)nr % BITS_PER_WORD;                    \
+    const uint32_t mask = BIT_MASK(bit);                                    \
+    unsigned long res, tmp;                                                 \
+    unsigned long oldbit;                                                   \
+                                                                            \
+    do                                                                      \
+    {                                                                       \
+        asm volatile ("// " __stringify(name) "\n"                          \
+        "   ldxr    %w3, %2\n"                                              \
+        "   lsr     %w1, %w3, %w5 // Save old value of bit\n"               \
+        "   " __stringify(instr) "  %w3, %w3, %w4 // Toggle bit\n"          \
+        "   stlxr   %w0, %w3, %2\n"                                         \
+        : "=&r" (res), "=&r" (oldbit), "+Q" (*ptr), "=&r" (tmp)             \
+        : "r" (mask), "r" (bit)                                             \
+        : "memory");                                                        \
+    } while ( res );                                                        \
+                                                                            \
+    dmb(ish);                                                               \
+                                                                            \
+    return oldbit & 1;                                                      \
+}
+
+bitop(change_bit, eor)
+bitop(clear_bit, bic)
+bitop(set_bit, orr)
+
+testop(test_and_change_bit, eor)
+testop(test_and_clear_bit, bic)
+testop(test_and_set_bit, orr)
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
-- 
2.17.1

