Skip to contentSkip to conversation

ARM: Add SWP/SWPB emulation for ARMv7 processors (v6)

PATCH New Leif Lindholm 8 participants 13 messages Jul 19, 2010 – Aug 3, 2010

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

PATCH 1/1 ARM: Add SWP/SWPB emulation for ARMv7 processors (v6)

The SWP instruction was deprecated in the ARMv6 architecture, superseded by the LDREX/STREX family of instructions for load-linked/store-conditional operations. The ARMv7 multiprocessing extensions mandate that SWP/SWPB instructions are treated as undefined from reset, with the ability to enable them through the System Control Register SW bit.

This patch adds the alternative solution to emulate the SWP and SWPB instructions using LDREX/STREX sequences, and log statistics to /proc/cpu/swp_emulation.

CC Catalin Marinas <[email protected]>

---

This patch depends on Catalin Marinas' "Remove the domain switching on ARMv6k/v7 CPUs" patch for setting access privileges to kernel read-only when user read-only.

 Documentation/arm/00-INDEX      |    2 
 Documentation/arm/swp_emulation |   27 ++++
 arch/arm/kernel/Makefile        |    1 
 arch/arm/kernel/swp_emulate.c   |  260 +++++++++++++++++++++++++++++++++++++++
 arch/arm/mm/Kconfig             |   27 ++++
 arch/arm/mm/proc-v7.S           |    4 +
 6 files changed, 321 insertions(+), 0 deletions(-)
 create mode 100644 Documentation/arm/swp_emulation
 create mode 100644 arch/arm/kernel/swp_emulate.c
Documentation/arm/00-INDEX +2 -0
index 7f5fc3b..2d02564 100644
@@ -32,3 +32,5 @@ memory.txt
 	- description of the virtual memory layout
 nwfpe/
 	- NWFPE floating point emulator documentation
+swp_emulation
+	- SWP/SWPB emulation handler/logging description
Documentation/arm/swp_emulation new file +27 -0
new file mode 100644
index 0000000..af903d2
@@ -0,0 +1,27 @@
+Software emulation of deprecated SWP instruction (CONFIG_SWP_EMULATE)
+---------------------------------------------------------------------
+
+ARMv6 architecture deprecates use of the SWP/SWPB instructions, and recommeds
+moving to the load-locked/store-conditional instructions LDREX and STREX.
+
+ARMv7 multiprocessing extensions introduce the ability to disable these
+instructions, triggering an undefined instruction exception when executed.
+Trapped instructions are emulated using an LDREX/STREX or LDREXB/STREXB
+sequence. If a memory access fault (an abort) occurs, a segmentation fault is
+signalled to the triggering process.
+
+/proc/cpu/swp_emulation holds some statistics/information, including the PID of
+the last process to trigger the emulation to be invocated. For example:
+---
+Emulated SWP:		12
+Emulated SWPB:		0
+Aborted SWP{B}:		1
+Last process:		314
+---
+
+NOTE: when accessing uncached shared regions, LDREX/STREX rely on an external
+transaction monitoring block called a global monitor to maintain update
+atomicity. If your system does not implement a global monitor, this option can
+cause programs that perform SWP operations to uncached memory to deadlock, as
+the STREX operation will always fail.
+
arch/arm/kernel/Makefile +1 -0
index 26d302c..d022b76 100644
@@ -39,6 +39,7 @@ obj-$(CONFIG_ARM_THUMBEE)	+= thumbee.o
 obj-$(CONFIG_KGDB)		+= kgdb.o
 obj-$(CONFIG_ARM_UNWIND)	+= unwind.o
 obj-$(CONFIG_HAVE_TCM)		+= tcm.o
+obj-$(CONFIG_SWP_EMULATE)	+= swp_emulate.o
 
 obj-$(CONFIG_CRUNCH)		+= crunch.o crunch-bits.o
 AFLAGS_crunch-bits.o		:= -Wa,-mcpu=ep9312
arch/arm/kernel/swp_emulate.c new file +260 -0

260 lines not on this page · raw message

arch/arm/mm/Kconfig +27 -0
index 294a57d..0b57d73 100644
@@ -636,6 +636,33 @@ config ARM_THUMBEE
 	  Say Y here if you have a CPU with the ThumbEE extension and code to
 	  make use of it. Say N for code that can run on CPUs without ThumbEE.
 
+config SWP_EMULATE
+	bool "Emulate SWP/SWPB instructions"
+	depends on CPU_V7
+	select HAVE_PROC_CPU if PROC_FS
+	default y if SMP
+	help
+	  ARMv6 architecture deprecates use of the SWP/SWPB instructions.
+	  ARMv7 multiprocessing extensions introduce the ability to disable
+	  these instructions, triggering an undefined instruction exception
+	  when executed. Say Y here to enable software emulation of these
+	  instructions for userspace (not kernel) using LDREX/STREX.
+	  Also creates /proc/cpu/swp_emulation for statistics.
+
+	  In some older versions of glibc [<=2.8] SWP is used during futex
+	  trylock() operations with the assumption that the code will not
+	  be preempted. This invalid assumption may be more likely to fail
+	  with SWP emulation enabled, leading to deadlock of the user
+	  application.
+
+	  NOTE: when accessing uncached shared regions, LDREX/STREX rely
+	  on an external transaction monitoring block called a global
+	  monitor to maintain update atomicity. If your system does not
+	  implement a global monitor, this option can cause programs that
+	  perform SWP operations to uncached memory to deadlock.
+
+	  If unsure, say Y.
+
 config CPU_BIG_ENDIAN
 	bool "Build big-endian kernel"
 	depends on ARCH_SUPPORTS_BIG_ENDIAN
arch/arm/mm/proc-v7.S +4 -0
index c1c3fe0..656548a 100644
@@ -281,6 +281,10 @@ __v7_setup:
 #ifdef CONFIG_CPU_ENDIAN_BE8
 	orr	r6, r6, #1 << 25		@ big-endian page tables
 #endif
+#ifdef CONFIG_SWP_EMULATE
+	orr     r5, r5, #(1 << 10)              @ set SW bit in "clear"
+	bic     r6, r6, #(1 << 10)              @ clear it in "mmuset"
+#endif
    	mrc	p15, 0, r0, c1, c0, 0		@ read control register
 	bic	r0, r0, r5			@ clear bits them
 	orr	r0, r0, r6			@ set them
#1 lore raw

PATCH 1/1 ARM: Add SWP/SWPB emulation for ARMv7 processors (v6)

Quoted 10 lines · Leif Lindholm

The SWP instruction was deprecated in the ARMv6 architecture, superseded by the LDREX/STREX family of instructions for load-linked/store-conditional operations. The ARMv7 multiprocessing extensions mandate that SWP/SWPB instructions are treated as undefined from reset, with the ability to enable them through the System Control Register SW bit.

This patch adds the alternative solution to emulate the SWP and SWPB instructions using LDREX/STREX sequences, and log statistics to /proc/cpu/swp_emulation.

Why do we need this? Why do not just fix broken programs?

Quoted 398 lines
CC Catalin Marinas <[email protected]>

---

This patch depends on Catalin Marinas' "Remove the domain switching on ARMv6k/v7 CPUs" patch for setting access privileges to kernel read-only when user read-only.

 Documentation/arm/00-INDEX      |    2 
 Documentation/arm/swp_emulation |   27 ++++
 arch/arm/kernel/Makefile        |    1 
 arch/arm/kernel/swp_emulate.c   |  260 +++++++++++++++++++++++++++++++++++++++
 arch/arm/mm/Kconfig             |   27 ++++
 arch/arm/mm/proc-v7.S           |    4 +
 6 files changed, 321 insertions(+), 0 deletions(-)
 create mode 100644 Documentation/arm/swp_emulation
 create mode 100644 arch/arm/kernel/swp_emulate.c
Documentation/arm/00-INDEX +2 -0
index 7f5fc3b..2d02564 100644
@@ -32,3 +32,5 @@ memory.txt
 	- description of the virtual memory layout
 nwfpe/
 	- NWFPE floating point emulator documentation
+swp_emulation
+	- SWP/SWPB emulation handler/logging description
Documentation/arm/swp_emulation new file +27 -0
new file mode 100644
index 0000000..af903d2
@@ -0,0 +1,27 @@
+Software emulation of deprecated SWP instruction (CONFIG_SWP_EMULATE)
+---------------------------------------------------------------------
+
+ARMv6 architecture deprecates use of the SWP/SWPB instructions, and recommeds
+moving to the load-locked/store-conditional instructions LDREX and STREX.
+
+ARMv7 multiprocessing extensions introduce the ability to disable these
+instructions, triggering an undefined instruction exception when executed.
+Trapped instructions are emulated using an LDREX/STREX or LDREXB/STREXB
+sequence. If a memory access fault (an abort) occurs, a segmentation fault is
+signalled to the triggering process.
+
+/proc/cpu/swp_emulation holds some statistics/information, including the PID of
+the last process to trigger the emulation to be invocated. For example:
+---
+Emulated SWP:		12
+Emulated SWPB:		0
+Aborted SWP{B}:		1
+Last process:		314
+---
+
+NOTE: when accessing uncached shared regions, LDREX/STREX rely on an external
+transaction monitoring block called a global monitor to maintain update
+atomicity. If your system does not implement a global monitor, this option can
+cause programs that perform SWP operations to uncached memory to deadlock, as
+the STREX operation will always fail.
+
arch/arm/kernel/Makefile +1 -0
index 26d302c..d022b76 100644
@@ -39,6 +39,7 @@ obj-$(CONFIG_ARM_THUMBEE)	+= thumbee.o
 obj-$(CONFIG_KGDB)		+= kgdb.o
 obj-$(CONFIG_ARM_UNWIND)	+= unwind.o
 obj-$(CONFIG_HAVE_TCM)		+= tcm.o
+obj-$(CONFIG_SWP_EMULATE)	+= swp_emulate.o
 
 obj-$(CONFIG_CRUNCH)		+= crunch.o crunch-bits.o
 AFLAGS_crunch-bits.o		:= -Wa,-mcpu=ep9312
arch/arm/kernel/swp_emulate.c new file +260 -0
new file mode 100644
index 0000000..c254d1d
@@ -0,0 +1,260 @@
+/*
+ *  linux/arch/arm/kernel/swp_emulate.c
+ *
+ *  Copyright (C) 2009 ARM Limited
+ *  __user_* functions adapted from include/asm/uaccess.h
+ *
+ * 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.
+ *
+ *  Implements emulation of the SWP/SWPB instructions using load-exclusive and
+ *  store-exclusive for processors that have them disabled (or future ones that
+ *  might not implement them).
+ *
+ *  Syntax of SWP{B} instruction: SWP{B}<c> <Rt>, <Rt2>, [<Rn>]
+ *  Where: Rt  = destination
+ *	   Rt2 = source
+ *	   Rn  = address
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/proc_fs.h>
+#include <linux/sched.h>
+#include <linux/syscalls.h>
+
+#include <asm/traps.h>
+#include <asm/uaccess.h>
+
+/*
+ * Error-checking SWP macros implemented using ldrex{b}/strex{b}
+ */
+#define __user_swpX_asm(data, addr, res, B)			\
+	__asm__ __volatile__(					\
+	"	mov		r3, %1\n"			\
+	"0:	ldrex"B"	%1, [%2]\n"			\
+	"1:	strex"B"	%0, r3, [%2]\n"			\
+	"	cmp		%0, #0\n"			\
+	"	movne		%0, %3\n"			\
+	"2:\n"							\
+	"	.section	 .fixup,\"ax\"\n"		\
+	"	.align		2\n"				\
+	"3:	mov		%0, %4\n"			\
+	"	b		2b\n"				\
+	"	.previous\n"					\
+	"	.section	 __ex_table,\"a\"\n"		\
+	"	.align		3\n"				\
+	"	.long		0b, 3b\n"			\
+	"	.long		1b, 3b\n"			\
+	"	.previous"					\
+	: "=&r" (res), "+r" (data)				\
+	: "r" (addr), "i" (-EAGAIN), "i" (-EFAULT)		\
+	: "cc", "r3")
+
+#define __user_swp_asm(data, addr, res) __user_swpX_asm(data, addr, res, "")
+#define __user_swpb_asm(data, addr, res) __user_swpX_asm(data, addr, res, "b")
+
+/*
+ * Macros/defines for extracting register numbers from instruction.
+ */
+#define EXTRACT_REG_NUM(instruction, offset) \
+  (((instruction) & (0xf << (offset))) >> (offset))
+#define RN_OFFSET  16
+#define RT_OFFSET  12
+#define RT2_OFFSET  0
+/*
+ * Bit 22 of the instruction encoding distinguishes between
+ * the SWP and SWPB variants (bit set means SWPB).
+ */
+#define TYPE_SWPB (1 << 22)
+
+static unsigned long long swpcounter;
+static unsigned long long swpbcounter;
+static unsigned long long abtcounter;
+static long		  previous_pid;
+
+#ifdef CONFIG_PROC_FS
+static int proc_read_status(char *page, char **start, off_t off, int count,
+			    int *eof, void *data)
+{
+	char *p = page;
+	int len;
+
+	p += sprintf(p, "Emulated SWP:\t\t%llu\n", swpcounter);
+	p += sprintf(p, "Emulated SWPB:\t\t%llu\n", swpbcounter);
+	p += sprintf(p, "Aborted SWP{B}:\t\t%llu\n", abtcounter);
+	if (previous_pid != 0)
+		p += sprintf(p, "Last process:\t\t%ld\n", previous_pid);
+
+	len = (p - page) - off;
+	if (len < 0)
+		len = 0;
+
+	*eof = (len <= count) ? 1 : 0;
+	*start = page + off;
+
+	return len;
+}
+#endif
+
+/*
+ * Set up process info to signal segmentation fault - called on access error.
+ */
+static void set_segfault(struct pt_regs *regs, unsigned long addr)
+{
+	siginfo_t info;
+
+	if (find_vma(current->mm, addr) == NULL)
+		info.si_code = SEGV_MAPERR;
+	else
+		info.si_code = SEGV_ACCERR;
+
+	info.si_signo = SIGSEGV;
+	info.si_errno = 0;
+	info.si_addr  = (void *) instruction_pointer(regs);
+
+	pr_debug("SWP{B} emulation: access caused memory abort!\n");
+	arm_notify_die("Illegal memory access", regs, &info, 0, 0);
+
+	abtcounter++;
+}
+
+static int emulate_swpX(unsigned int address, unsigned int *data,
+			unsigned int type)
+{
+	unsigned int res = 0;
+
+	if ((type != TYPE_SWPB) && (address & 0x3)) {
+		/* SWP to unaligned address not permitted */
+		pr_debug("SWP instruction on unaligned pointer!\n");
+		return -EFAULT;
+	}
+
+	while (1) {
+		/*
+		 * Barrier required between accessing protected resource and
+		 * releasing a lock for it. Legacy code might not have done
+		 * this, and we cannot determine that this is not the case
+		 * being emulated, so insert always.
+		 */
+		smp_mb();
+
+		if (type == TYPE_SWPB)
+			__user_swpb_asm(*data, address, res);
+		else
+			__user_swp_asm(*data, address, res);
+
+		if (likely(res != -EAGAIN) || signal_pending(current))
+			break;
+
+		cond_resched();
+	}
+
+	if (res == 0) {
+		/*
+		 * Barrier also required between aquiring a lock for a
+		 * protected resource and accessing the resource. Inserted for
+		 * same reason as above.
+		 */
+		smp_mb();
+
+		if (type == TYPE_SWPB)
+			swpbcounter++;
+		else
+			swpcounter++;
+	}
+
+	return res;
+}
+
+/*
+ * swp_handler logs the id of calling process, dissects the instruction, sanity
+ * checks the memory location, calls emulate_swpX for the actual operation and
+ * deals with fixup/error handling before returning
+ */
+static int swp_handler(struct pt_regs *regs, unsigned int instr)
+{
+	unsigned int address, destreg, data, type;
+	unsigned int res = 0;
+
+	if (current->pid != previous_pid) {
+		pr_debug("\"%s\" (%ld) uses deprecated SWP{B} instruction\n",
+			 current->comm, (unsigned long)current->pid);
+		previous_pid = current->pid;
+	}
+
+	address = regs->uregs[EXTRACT_REG_NUM(instr, RN_OFFSET)];
+	data	= regs->uregs[EXTRACT_REG_NUM(instr, RT2_OFFSET)];
+	destreg = EXTRACT_REG_NUM(instr, RT_OFFSET);
+
+	type = instr & TYPE_SWPB;
+
+	pr_debug("addr in r%d->0x%08x, dest is r%d, source in r%d->0x%08x)\n",
+		 EXTRACT_REG_NUM(instr, RN_OFFSET), address,
+		 destreg, EXTRACT_REG_NUM(instr, RT2_OFFSET), data);
+
+	/* Check access in reasonable access range for both SWP and SWPB */
+	if (!access_ok(VERIFY_WRITE, (address & ~3), 4)) {
+		pr_debug("SWP{B} emulation: access to %p not allowed!\n",
+			 (void *)address);
+		res = -EFAULT;
+	} else {
+		res = emulate_swpX(address, &data, type);
+	}
+
+	if (res == 0) {
+		/*
+		 * On successful emulation, revert the adjustment to the PC
+		 * made in kernel/traps.c in order to resume execution at the
+		 * instruction following the SWP{B}.
+		 */
+		regs->ARM_pc += 4;
+		regs->uregs[destreg] = data;
+	} else if (res == -EFAULT) {
+		/*
+		 * Memory errors do not mean emulation failed.
+		 * Set up signal info to return SEGV, then return OK
+		 */
+		set_segfault(regs, address);
+	}
+
+	return 0;
+}
+
+/*
+ * Only emulate SWP/SWPB executed in ARM state/User mode.
+ * The kernel must be SWP free and SWP{B} does not exist in Thumb/ThumbEE.
+ */
+static struct undef_hook swp_hook = {
+	.instr_mask = 0x0fb00ff0,
+	.instr_val  = 0x01000090,
+	.cpsr_mask  = MODE_MASK | PSR_T_BIT | PSR_J_BIT,
+	.cpsr_val   = USR_MODE,
+	.fn	    = swp_handler
+};
+
+/*
+ * Register handler and create status file in /proc/cpu
+ * Invoked as late_initcall, since not needed before init spawned.
+ */
+static int __init swp_emulation_init(void)
+{
+#ifdef CONFIG_PROC_FS
+	struct proc_dir_entry *res;
+
+	res = create_proc_entry("cpu/swp_emulation", S_IRUGO, NULL);
+
+	if (!res)
+		return -ENOMEM;
+
+	res->read_proc = proc_read_status;
+#endif /* CONFIG_PROC_FS */
+
+	printk(KERN_NOTICE "Registering SWP/SWPB emulation handler\n");
+	register_undef_hook(&swp_hook);
+
+	return 0;
+}
+
+late_initcall(swp_emulation_init);
arch/arm/mm/Kconfig +27 -0
index 294a57d..0b57d73 100644
@@ -636,6 +636,33 @@ config ARM_THUMBEE
 	  Say Y here if you have a CPU with the ThumbEE extension and code to
 	  make use of it. Say N for code that can run on CPUs without ThumbEE.
 
+config SWP_EMULATE
+	bool "Emulate SWP/SWPB instructions"
+	depends on CPU_V7
+	select HAVE_PROC_CPU if PROC_FS
+	default y if SMP
+	help
+	  ARMv6 architecture deprecates use of the SWP/SWPB instructions.
+	  ARMv7 multiprocessing extensions introduce the ability to disable
+	  these instructions, triggering an undefined instruction exception
+	  when executed. Say Y here to enable software emulation of these
+	  instructions for userspace (not kernel) using LDREX/STREX.
+	  Also creates /proc/cpu/swp_emulation for statistics.
+
+	  In some older versions of glibc [<=2.8] SWP is used during futex
+	  trylock() operations with the assumption that the code will not
+	  be preempted. This invalid assumption may be more likely to fail
+	  with SWP emulation enabled, leading to deadlock of the user
+	  application.
+
+	  NOTE: when accessing uncached shared regions, LDREX/STREX rely
+	  on an external transaction monitoring block called a global
+	  monitor to maintain update atomicity. If your system does not
+	  implement a global monitor, this option can cause programs that
+	  perform SWP operations to uncached memory to deadlock.
+
+	  If unsure, say Y.
+
 config CPU_BIG_ENDIAN
 	bool "Build big-endian kernel"
 	depends on ARCH_SUPPORTS_BIG_ENDIAN
arch/arm/mm/proc-v7.S +4 -0
index c1c3fe0..656548a 100644
@@ -281,6 +281,10 @@ __v7_setup:
 #ifdef CONFIG_CPU_ENDIAN_BE8
 	orr	r6, r6, #1 << 25		@ big-endian page tables
 #endif
+#ifdef CONFIG_SWP_EMULATE
+	orr     r5, r5, #(1 << 10)              @ set SW bit in "clear"
+	bic     r6, r6, #(1 << 10)              @ clear it in "mmuset"
+#endif
    	mrc	p15, 0, r0, c1, c0, 0		@ read control register
 	bic	r0, r0, r5			@ clear bits them
 	orr	r0, r0, r6			@ set them

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel at lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

Signature · 1 line
 Kirill A. Shutemov
#2 lore raw

PATCH 1/1 ARM: Add SWP/SWPB emulation for ARMv7 processors (v6)

2010/7/19 Kirill A. Shutemov <[email protected]>:

Quoted 1 line

Why do we need this? Why do not just fix broken programs?

People tend to use some third-party precompiled binaries, some of them compiled with a compiler using SWP.

A typical example is the CDC Java runtime, JRE.

Yours,
Linus Walleij

#3 lore raw

PATCH 1/1 ARM: Add SWP/SWPB emulation for ARMv7 processors (v6)

Quoted 8 lines · Linus Walleij

2010/7/19 Kirill A. Shutemov <[email protected]>:

Quoted 1 line

Why do we need this? Why do not just fix broken programs?

People tend to use some third-party precompiled binaries, some of them compiled with a compiler using SWP.

A typical example is the CDC Java runtime, JRE.

I think beter to describe it in commit message.

Signature · 1 line
 Kirill A. Shutemov
#4 lore raw

PATCH 1/1 ARM: Add SWP/SWPB emulation for ARMv7 processors (v6)

In reply to Linus Walleij
Quoted 6 lines · Linus Walleij

2010/7/19 Kirill A. Shutemov <[email protected]>:

Quoted 1 line

Why do we need this? Why do not just fix broken programs?

People tend to use some third-party precompiled binaries, some of them compiled with a compiler using SWP.

Why not just let the cpu emulate it? It surely will be faster...?

Signature · 2 lines
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
#5 lore raw

PATCH 1/1 ARM: Add SWP/SWPB emulation for ARMv7 processors (v6)

Quoted 8 lines · On Wednesday 28 July 2010 09:06:49 ext Pavel Machek wrote:
Quoted 5 lines · Linus Walleij

2010/7/19 Kirill A. Shutemov <[email protected]>:

Quoted 1 line

Why do we need this? Why do not just fix broken programs?

People tend to use some third-party precompiled binaries, some of them compiled with a compiler using SWP.

Why not just let the cpu emulate it? It surely will be faster...?

IMHO, being able to identify the usage of SWP instructions and fix bad programs eventually (by spamming the said third-party programs bugtrackers) is a good enough reason.

That's somewhat similar to userspace unaligned memory accesses handling, except that the kernel being totally silent about them by default is not helping much in practice.

Signature · 2 lines
Best regards,
Siarhei Siamashka
#6 lore raw

PATCH 1/1 ARM: Add SWP/SWPB emulation for ARMv7 processors (v6)

Quoted 5 lines · Siarhei Siamashka
Quoted 4 lines · On Wednesday 28 July 2010 09:06:49 ext Pavel Machek wrote:
Quoted 3 lines · Linus Walleij

2010/7/19 Kirill A. Shutemov <[email protected]>:

Quoted 1 line

Why do we need this? Why do not just fix broken programs?

Quoted 8 lines
Quoted 4 lines
Quoted 2 lines

People tend to use some third-party precompiled binaries, some of them compiled with a compiler using SWP.

Why not just let the cpu emulate it? It surely will be faster...?

IMHO, being able to identify the usage of SWP instructions and fix bad programs eventually (by spamming the said third-party programs bugtrackers) is a good enough reason.

Why do we need _emulation_ for that?

Either you care about compatibility, then you let the CPU emulate SWP, or you want to fix your userspace, so you turn off SWP emulation and see what breaks.

I believe emulation just to annoy users into submitting bugreports is serious overengineering.
Pavel

Signature · 2 lines
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
#7 lore raw

PATCH 1/1 ARM: Add SWP/SWPB emulation for ARMv7 processors (v6)

Quoted 9 lines · On Thursday 29 July 2010 22:28:56 ext Pavel Machek wrote:
Quoted 8 lines · Siarhei Siamashka
Quoted 7 lines · On Wednesday 28 July 2010 09:06:49 ext Pavel Machek wrote:
Quoted 5 lines · Linus Walleij

2010/7/19 Kirill A. Shutemov <[email protected]>:

Quoted 1 line

Why do we need this? Why do not just fix broken programs?

People tend to use some third-party precompiled binaries, some of them compiled with a compiler using SWP.

Quoted 7 lines
Quoted 5 lines
Quoted 1 line

Why not just let the cpu emulate it? It surely will be faster...?

IMHO, being able to identify the usage of SWP instructions and fix bad programs eventually (by spamming the said third-party programs bugtrackers) is a good enough reason.

Why do we need _emulation_ for that?

In order to have it trapped and recorded in log, while still not causing disasterous effects for the users (their applications still work).

Quoted 3 lines

Either you care about compatibility, then you let the CPU emulate SWP, or you want to fix your userspace, so you turn off SWP emulation and see what breaks.

In practice, nobody would turn off SWP emulation ever in such setup, and the problems will remain unresolved for ages.

Quoted 2 lines

I believe emulation just to annoy users into submitting bugreports is serious overengineering.

It's not to annoy them, but to provide the users with the information about valid problems in their applications. It's up to the users to either do anything with it, or ignore.

Signature · 2 lines
Best regards,
Siarhei Siamashka
#8 lore raw

PATCH 1/1 ARM: Add SWP/SWPB emulation for ARMv7 processors (v6)

Quoted 7 lines · Siarhei Siamashka
Quoted 2 lines · On Thursday 29 July 2010 22:28:56 ext Pavel Machek wrote:

I believe emulation just to annoy users into submitting bugreports is serious overengineering.

It's not to annoy them, but to provide the users with the information about valid problems in their applications. It's up to the users to either do anything with it, or ignore.

What's missing is that the SWP instruction will eventually be dropped from the later ARM architecture revisions, so sooner or later programs will break without either SWP emulation support or being fixed.

The SWP instruction is already deprecated from ARMv6, and in ARMv6 it was still present (see the note in section A3.4). In ARMv7, it defaults to being disabled and causing an illegal instruction fault. The next step will be to remove it from the hardware entirely which I suspect isn't that far away.

So this patch makes total sense.

What I do think we need to do is collect all the definitions for decoding instructions together - we have stuff like (in kprobes-decode.c):

        int rd = (insn >> 12) & 0xf;

when we also have in arch/arm/mm/alignment.c:

#define RD_BITS(i) ((i >> 12) & 15) /* Rd */

and it seems we're going to get another version of this for the swp emulation support.

#9 lore raw

PATCH 1/1 ARM: Add SWP/SWPB emulation for ARMv7 processors (v6)

Quoted 24 lines · Russell King - ARM Linux
Quoted 7 lines · Siarhei Siamashka
Quoted 2 lines · On Thursday 29 July 2010 22:28:56 ext Pavel Machek wrote:

I believe emulation just to annoy users into submitting bugreports is serious overengineering.

It's not to annoy them, but to provide the users with the information about valid problems in their applications. It's up to the users to either do anything with it, or ignore.

What's missing is that the SWP instruction will eventually be dropped from the later ARM architecture revisions, so sooner or later programs will break without either SWP emulation support or being fixed.

The SWP instruction is already deprecated from ARMv6, and in ARMv6 it was still present (see the note in section A3.4). In ARMv7, it defaults to being disabled and causing an illegal instruction fault. The next step will be to remove it from the hardware entirely which I suspect isn't that far away.

So this patch makes total sense.

What I do think we need to do is collect all the definitions for decoding instructions together - we have stuff like (in kprobes-decode.c):

Quoted 8 lines
        int rd = (insn >> 12) & 0xf;

when we also have in arch/arm/mm/alignment.c:

#define RD_BITS(i) ((i >> 12) & 15) /* Rd */

and it seems we're going to get another version of this for the swp emulation support.

First stab at merging these ARM ISA decoding macros/code - I'm sure there's more which can be done:

arch/arm/include/asm/arm-isa.h +36 -0
index e69de29..aad7dd3 100644
@@ -0,0 +1,36 @@
+#ifndef __ASM_ARM_ISA_H
+#define __ASM_ARM_ISA_H
+
+#define CODING_BITS(i)	((i) & 0x0e000000)
+
+#define LDST_I_BIT(i)	((i) & (1 << 26))	/* Immediate constant	*/
+#define LDST_P_BIT(i)	((i) & (1 << 24))	/* Preindex		*/
+#define LDST_U_BIT(i)	((i) & (1 << 23))	/* Add offset		*/
+#define LDST_W_BIT(i)	((i) & (1 << 21))	/* Writeback		*/
+#define LDST_L_BIT(i)	((i) & (1 << 20))	/* Load			*/
+
+#define LDST_P_EQ_U(i)	((((i) ^ ((i) >> 1)) & (1 << 23)) == 0)
+
+#define LDSTHD_I_BIT(i)	((i) & (1 << 22))	/* double/half-word immed */
+
+#define RN_BITS(i)	(((i) >> 16) & 15)	/* Rn			*/
+#define RD_BITS(i)	(((i) >> 12) & 15)	/* Rd			*/
+#define RM_BITS(i)	((i) & 15)		/* Rm			*/
+
+#define OFFSET_BITS(i)	((i) & 0x0fff)
+
+#define LDM_S_BIT(i)	((i) & (1 << 22))	/* write CPSR from SPSR	*/
+#define LDM_REGMASK(i)	((i) & 0xffff)
+
+#define IS_SHIFT(i)	(i & 0x0ff0)
+#define SHIFT_BITS(i)	((i >> 7) & 0x1f)
+#define SHIFT_TYPE(i)	(i & 0x60)
+#define SHIFT_LSL	0x00
+#define SHIFT_LSR	0x20
+#define SHIFT_ASR	0x40
+#define SHIFT_RORRRX	0x60
+
+#define IS_T32(hi16) \
+	(((hi16) & 0xe000) == 0xe000 && ((hi16) & 0x1800))
+
+#endif
arch/arm/kernel/kprobes-decode.c +58 -56

275 lines not on this page · raw message

arch/arm/mm/alignment.c +5 -34
index 6f98c35..77ebbd3 100644
@@ -22,6 +22,7 @@
 #include <linux/sched.h>
 #include <linux/uaccess.h>
 
+#include <asm/arm-isa.h>
 #include <asm/unaligned.h>
 
 #include "fault.h"
@@ -36,39 +37,9 @@
  * *** NOTE ***
  * This code is not portable to processors with late data abort handling.
  */
-#define CODING_BITS(i)	(i & 0x0e000000)
-
-#define LDST_I_BIT(i)	(i & (1 << 26))		/* Immediate constant	*/
-#define LDST_P_BIT(i)	(i & (1 << 24))		/* Preindex		*/
-#define LDST_U_BIT(i)	(i & (1 << 23))		/* Add offset		*/
-#define LDST_W_BIT(i)	(i & (1 << 21))		/* Writeback		*/
-#define LDST_L_BIT(i)	(i & (1 << 20))		/* Load			*/
-
-#define LDST_P_EQ_U(i)	((((i) ^ ((i) >> 1)) & (1 << 23)) == 0)
-
-#define LDSTHD_I_BIT(i)	(i & (1 << 22))		/* double/half-word immed */
-#define LDM_S_BIT(i)	(i & (1 << 22))		/* write CPSR from SPSR	*/
-
-#define RN_BITS(i)	((i >> 16) & 15)	/* Rn			*/
-#define RD_BITS(i)	((i >> 12) & 15)	/* Rd			*/
-#define RM_BITS(i)	(i & 15)		/* Rm			*/
-
-#define REGMASK_BITS(i)	(i & 0xffff)
-#define OFFSET_BITS(i)	(i & 0x0fff)
-
-#define IS_SHIFT(i)	(i & 0x0ff0)
-#define SHIFT_BITS(i)	((i >> 7) & 0x1f)
-#define SHIFT_TYPE(i)	(i & 0x60)
-#define SHIFT_LSL	0x00
-#define SHIFT_LSR	0x20
-#define SHIFT_ASR	0x40
-#define SHIFT_RORRRX	0x60
-
 #define BAD_INSTR 	0xdeadc0de
 
 /* Thumb-2 32 bit format per ARMv7 DDI0406A A6.3, either f800h,e800h,f800h */
-#define IS_T32(hi16) \
-	(((hi16) & 0xe000) == 0xe000 && ((hi16) & 0x1800))
 
 static unsigned long ai_user;
 static unsigned long ai_sys;
@@ -462,7 +433,7 @@ do_alignment_ldmstm(unsigned long addr, unsigned long instr, struct pt_regs *reg
 	ai_multi += 1;
 
 	/* count the number of registers in the mask to be transferred */
-	nr_regs = hweight16(REGMASK_BITS(instr)) * 4;
+	nr_regs = hweight16(LDM_REGMASK(instr)) * 4;
 
 	rn = RN_BITS(instr);
 	newaddr = eaddr = regs->uregs[rn];
@@ -497,7 +468,7 @@ do_alignment_ldmstm(unsigned long addr, unsigned long instr, struct pt_regs *reg
 #endif
 
 	if (user_mode(regs)) {
-		for (regbits = REGMASK_BITS(instr), rd = 0; regbits;
+		for (regbits = LDM_REGMASK(instr), rd = 0; regbits;
 		     regbits >>= 1, rd += 1)
 			if (regbits & 1) {
 				if (LDST_L_BIT(instr)) {
@@ -509,7 +480,7 @@ do_alignment_ldmstm(unsigned long addr, unsigned long instr, struct pt_regs *reg
 				eaddr += 4;
 			}
 	} else {
-		for (regbits = REGMASK_BITS(instr), rd = 0; regbits;
+		for (regbits = LDM_REGMASK(instr), rd = 0; regbits;
 		     regbits >>= 1, rd += 1)
 			if (regbits & 1) {
 				if (LDST_L_BIT(instr)) {
@@ -524,7 +495,7 @@ do_alignment_ldmstm(unsigned long addr, unsigned long instr, struct pt_regs *reg
 
 	if (LDST_W_BIT(instr))
 		regs->uregs[rn] = newaddr;
-	if (!LDST_L_BIT(instr) || !(REGMASK_BITS(instr) & (1 << 15)))
+	if (!LDST_L_BIT(instr) || !(LDM_REGMASK(instr) & (1 << 15)))
 		regs->ARM_pc -= correction;
 	return TYPE_DONE;
 
#10 lore raw

PATCH 1/1 ARM: Add SWP/SWPB emulation for ARMv7 processors (v6)

Quoted 12 lines

-----Original Message-----
From: Russell King - ARM Linux [mailto:linux at arm.linux.org.uk]
Sent: 31 July 2010 12:29

First stab at merging these ARM ISA decoding macros/code - I'm sure there's more which can be done:

arch/arm/include/asm/arm- renamed from arch/arm/include/asm/arm-isa.h +0 -0

isa.h
index e69de29..aad7dd3 100644

arch/arm/include/asm/arm-isa.h

Quoted 4 lines
arch/arm/include/asm/arm-isa.h +3 -0
 
+#define RN_BITS(i)	(((i) >> 16) & 15)	/* Rn			*/
+#define RD_BITS(i)	(((i) >> 12) & 15)	/* Rd			*/
+#define RM_BITS(i)	((i) & 15)			/* Rm

*/

While I could bring the SWP emulation patch in line by just adding a couple of defines here for RT_BITS and RT2_BITS, unfortunately, the ARM instruction formats aren't 100% consistent about these offsets:

STREX* have their Rn and Rd fields at the same offsets as above, with an Rt field at offset 0.
| | | | Rn | Rd | | | Rt |
SWP/SWPB have Rt at offset 12 with an Rt2 at offset 0.
| | | | Rn | Rt | | | Rt2|
STRD likewise has Rt at offset 12, but with an Rm at 0.
| | | | Rn | Rt | | | Rm |
ASR has Rd at offset 12, but with Rm at 8 and Rn at 0.
| | | | | Rd | Rm | | Rn |
MLA has Rd at 16, with Ra at 12, Rm at 8 and Rn at 0.
| | | | Rd | Ra | Rm | | Rn |

So in the long run we would either need to implement an instruction decoder to extract the offsets of fields, or separate the least common ones out into separate defines. The former having potential negative impact on code size and performance.

If you'd like, I could update the SWP emulation patch to set up separate SWP_RT_BITS and SWP_RT2_BITS in arm-isa.h for now, along with a couple of other things I would need. At least that would gather the encoding stuff into one file.

/
Leif

#11 lore raw

PATCH 1/1 ARM: Add SWP/SWPB emulation for ARMv7 processors (v6)

In reply to Linus Walleij
Quoted 8 lines · Linus Walleij

2010/7/19 Kirill A. Shutemov <[email protected]>:

Quoted 1 line

Why do we need this? Why do not just fix broken programs?

People tend to use some third-party precompiled binaries, some of them compiled with a compiler using SWP.

A typical example is the CDC Java runtime, JRE.

Also people like to run the same binaries on different ARMs. E.g. Debian, Ubuntu.

System pthread libraries can have multiple implementations, but not every user of SWP or LDREX/STREX is in the pthread libraries.

-- Jamie

#12 lore raw

PATCH 1/1 ARM: Add SWP/SWPB emulation for ARMv7 processors (v6)

In reply to Leif Lindholm
Quoted 11 lines · Leif Lindholm

The SWP instruction was deprecated in the ARMv6 architecture, superseded by the LDREX/STREX family of instructions for load-linked/store-conditional operations. The ARMv7 multiprocessing extensions mandate that SWP/SWPB instructions are treated as undefined from reset, with the ability to enable them through the System Control Register SW bit.

This patch adds the alternative solution to emulate the SWP and SWPB instructions using LDREX/STREX sequences, and log statistics to /proc/cpu/swp_emulation.

Quoted 7 lines
CC Catalin Marinas <[email protected]>

---

This patch depends on Catalin Marinas' "Remove the domain switching on ARMv6k/v7 CPUs" patch for setting access privileges to kernel read-only when user read-only.

Since this patch depends on my domains one, I'll also merge it in my public tree until the domains patch is accepted.

Just for clarification - the reason it depends on my domains patch is because of the permission change for read-only user mappings (from kernel read/write to kernel read-only so that we get COW during SWP emulation).

An alternative would be to extract the permission settings part from my domains patch and merge it separately but I really don't think it's worth the effort as we need the domains patch in the kernel.

In the meantime: