ARM: Add SWP/SWPB emulation for ARMv7 processors (v6)
Subsystems (2)
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.
---
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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
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
Signed-off-by Leif Lindholm <[email protected]>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.cDocumentation/arm/00-INDEX +2
-0@@ -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 descriptionDocumentation/arm/swp_emulation new file +27
-0@@ -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@@ -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=ep9312arch/arm/kernel/swp_emulate.c new file +260
-0@@ -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@@ -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_ENDIANarch/arm/mm/proc-v7.S +4
-0@@ -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
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
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
PATCH 1/1 ARM: Add SWP/SWPB emulation for ARMv7 processors (v6)
In reply to Linus WalleijQuoted 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
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
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
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
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.
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
@@ -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
@@ -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 *regif (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 ;
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:29First 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
PATCH 1/1 ARM: Add SWP/SWPB emulation for ARMv7 processors (v6)
In reply to Linus WalleijQuoted 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
PATCH 1/1 ARM: Add SWP/SWPB emulation for ARMv7 processors (v6)
In reply to Leif LindholmQuoted 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
Signed-off-by Leif Lindholm <[email protected]>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: