linux-arm-kernel.lists.infradead.org archive mirror
 help / color / mirror / Atom feed
* [PATCHv2 0/5] Legacy instruction emulation for arm64
@ 2014-10-01 12:07 Punit Agrawal
  2014-10-01 12:07 ` [PATCHv2 1/5] arm64: Add support for hooks to handle undefined instructions Punit Agrawal
                   ` (5 more replies)
  0 siblings, 6 replies; 16+ messages in thread
From: Punit Agrawal @ 2014-10-01 12:07 UTC (permalink / raw)
  To: linux-arm-kernel

Hi,

This is the second posting of the legacy instruction support for
arm64. The previous posting can be found at [1].

The patchset ports the infrastructure to register hooks for undefined
instruction abort and uses this to adds support for the emulation of
SWP{B} and CP15 Barrier instructions from ARMv7 to the v8 port of
Linux.

Via sysctl, it is possible to control the runtime state of emulation
* Off
  sysctl value: 0
  Generates undefined instruction abort. Default for instructions that
  have been obsoleted in the architecture, e.g., SWP

* Emulate
  sysctl value: 1
  Uses software emulation. To aid migration of software, in this mode
  usage of emulated instruction is traced as well as rate limited
  warnings are issued. This is the default for deprecated
  instructions, .e.g., CP15 barriers

* Enable
  sysctl value: 2
  Although marked as deprecated, some implementations may support the
  enabling/disabling of hardware support for the execution of these
  instructions. Using hardware execution generally provides better
  performance, but at the loss of ability to gather runtime statistics
  about the use of the deprecated instructions.

Patches 1-2/5 add infrastructure code to add support for undefined
instruction hooks and decoding condition checks.

Patch 3-4/6 adds support for SWP and CP15 barriers respectively. They
also provide the ability to control the emulation by writing one of
the above three values to /proc/sys/abi file nodes.

Patch 6/6 introduces a trace point to log instruction emulation and then
uses this to trace the usage of the above instructions when using
emulation.

Although not in a merge window, the intention of the posting is to
allow early access to the code to reduce divergenece in product
kernels where additional features are being worked on.

Cheers,
Punit

Changes since [1]:
* Added support for Thumb instructions when registering undefined
hooks as well
* Emulation support is now added to armv8_deprecated.c (was previously
v7_obsolete.c)
* Instruction support level - Off, Emulate or Enable (when supported
in hardware) - is now controlled through sysctl
* Using trace points instead of debugfs for stats reporting


[1] http://thread.gmane.org/gmane.linux.ports.arm.kernel/351054

Punit Agrawal (5):
  arm64: Add support for hooks to handle undefined instructions
  arm64: Add AArch32 instruction set condition code checks
  arm64: Port SWP/SWPB emulation support from arm
  arm64: Emulate CP15 Barrier instructions
  arm64: Trace emulation of AArch32 legacy instructions

 arch/arm64/Kconfig                   |   54 ++++
 arch/arm64/include/asm/insn.h        |   10 +
 arch/arm64/include/asm/opcodes.h     |    1 +
 arch/arm64/include/asm/traps.h       |   16 ++
 arch/arm64/kernel/Makefile           |    5 +-
 arch/arm64/kernel/armv8_deprecated.c |  489 ++++++++++++++++++++++++++++++++++
 arch/arm64/kernel/insn.c             |   26 ++
 arch/arm64/kernel/traps.c            |   68 +++++
 include/trace/events/emulation.h     |   35 +++
 9 files changed, 703 insertions(+), 1 deletion(-)
 create mode 100644 arch/arm64/include/asm/opcodes.h
 create mode 100644 arch/arm64/kernel/armv8_deprecated.c
 create mode 100644 include/trace/events/emulation.h

-- 
1.7.10.4

^ permalink raw reply	[flat|nested] 16+ messages in thread

* [PATCHv2 1/5] arm64: Add support for hooks to handle undefined instructions
  2014-10-01 12:07 [PATCHv2 0/5] Legacy instruction emulation for arm64 Punit Agrawal
@ 2014-10-01 12:07 ` Punit Agrawal
  2014-10-01 12:07 ` [PATCHv2 2/5] arm64: Add AArch32 instruction set condition code checks Punit Agrawal
                   ` (4 subsequent siblings)
  5 siblings, 0 replies; 16+ messages in thread
From: Punit Agrawal @ 2014-10-01 12:07 UTC (permalink / raw)
  To: linux-arm-kernel

Add support to register hooks for undefined instructions. The handlers
will be called when the undefined instruction and the processor state
(as contained in pstate) match criteria used at registration.

Signed-off-by: Punit Agrawal <punit.agrawal@arm.com>
---
 arch/arm64/include/asm/traps.h |   16 ++++++++++
 arch/arm64/kernel/traps.c      |   68 ++++++++++++++++++++++++++++++++++++++++
 2 files changed, 84 insertions(+)

diff --git a/arch/arm64/include/asm/traps.h b/arch/arm64/include/asm/traps.h
index 10ca8ff..4faaf03 100644
--- a/arch/arm64/include/asm/traps.h
+++ b/arch/arm64/include/asm/traps.h
@@ -18,6 +18,22 @@
 #ifndef __ASM_TRAP_H
 #define __ASM_TRAP_H
 
+#include <linux/list.h>
+
+struct pt_regs;
+
+struct undef_hook {
+	struct list_head node;
+	u32 instr_mask;
+	u32 instr_val;
+	u64 pstate_mask;
+	u64 pstate_val;
+	int (*fn)(struct pt_regs *regs, u32 instr);
+};
+
+int register_undef_hook(struct undef_hook *hook);
+void unregister_undef_hook(struct undef_hook *hook);
+
 static inline int in_exception_text(unsigned long ptr)
 {
 	extern char __exception_text_start[];
diff --git a/arch/arm64/kernel/traps.c b/arch/arm64/kernel/traps.c
index 02cd3f0..bcde9de 100644
--- a/arch/arm64/kernel/traps.c
+++ b/arch/arm64/kernel/traps.c
@@ -260,6 +260,71 @@ void arm64_notify_die(const char *str, struct pt_regs *regs,
 	}
 }
 
+static LIST_HEAD(undef_hook);
+static DEFINE_RAW_SPINLOCK(undef_lock);
+
+int register_undef_hook(struct undef_hook *hook)
+{
+	unsigned long flags;
+
+	raw_spin_lock_irqsave(&undef_lock, flags);
+	list_add(&hook->node, &undef_hook);
+	raw_spin_unlock_irqrestore(&undef_lock, flags);
+
+	return 0;
+}
+
+void unregister_undef_hook(struct undef_hook *hook)
+{
+	unsigned long flags;
+
+	raw_spin_lock_irqsave(&undef_lock, flags);
+	list_del(&hook->node);
+	raw_spin_unlock_irqrestore(&undef_lock, flags);
+}
+
+static int call_undef_hook(struct pt_regs *regs)
+{
+	struct undef_hook *hook;
+	unsigned long flags;
+	u32 instr;
+	int (*fn)(struct pt_regs *regs, u32 instr) = NULL;
+	void __user *pc = (void __user *)instruction_pointer(regs);
+
+	if (!user_mode(regs))
+		return 1;
+
+	if (compat_thumb_mode(regs)) {
+		/* 16-bit Thumb instruction */
+		if (get_user(instr, (u16 __user *)pc))
+			goto exit;
+		instr = le16_to_cpu(instr);
+		if (aarch32_insn_is_wide_instruction(instr)) {
+			u32 instr2;
+
+			if (get_user(instr2, (u16 __user *)(pc + 2)))
+				goto exit;
+			instr2 = le16_to_cpu(instr2);
+			instr = (instr << 16) | instr2;
+		}
+	} else {
+		/* 32-bit ARM instruction */
+		if (get_user(instr, (u32 __user *)pc))
+			goto exit;
+		instr = le32_to_cpu(instr);
+	}
+
+	raw_spin_lock_irqsave(&undef_lock, flags);
+	list_for_each_entry(hook, &undef_hook, node)
+		if ((instr & hook->instr_mask) == hook->instr_val &&
+			(regs->pstate & hook->pstate_mask) == hook->pstate_val)
+			fn = hook->fn;
+
+	raw_spin_unlock_irqrestore(&undef_lock, flags);
+exit:
+	return fn ? fn(regs, instr) : 1;
+}
+
 asmlinkage void __exception do_undefinstr(struct pt_regs *regs)
 {
 	siginfo_t info;
@@ -269,6 +334,9 @@ asmlinkage void __exception do_undefinstr(struct pt_regs *regs)
 	if (!aarch32_break_handler(regs))
 		return;
 
+	if (call_undef_hook(regs) == 0)
+		return;
+
 	if (show_unhandled_signals && unhandled_signal(current, SIGILL) &&
 	    printk_ratelimit()) {
 		pr_info("%s[%d]: undefined instruction: pc=%p\n",
-- 
1.7.10.4

^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCHv2 2/5] arm64: Add AArch32 instruction set condition code checks
  2014-10-01 12:07 [PATCHv2 0/5] Legacy instruction emulation for arm64 Punit Agrawal
  2014-10-01 12:07 ` [PATCHv2 1/5] arm64: Add support for hooks to handle undefined instructions Punit Agrawal
@ 2014-10-01 12:07 ` Punit Agrawal
  2014-10-01 12:07 ` [PATCHv2 3/5] arm64: Port SWP/SWPB emulation support from arm Punit Agrawal
                   ` (3 subsequent siblings)
  5 siblings, 0 replies; 16+ messages in thread
From: Punit Agrawal @ 2014-10-01 12:07 UTC (permalink / raw)
  To: linux-arm-kernel

Port support for AArch32 instruction condition code checking from arm
to arm64.

Signed-off-by: Punit Agrawal <punit.agrawal@arm.com>
---
 arch/arm64/include/asm/opcodes.h |    1 +
 arch/arm64/kernel/Makefile       |    4 +++-
 2 files changed, 4 insertions(+), 1 deletion(-)
 create mode 100644 arch/arm64/include/asm/opcodes.h

diff --git a/arch/arm64/include/asm/opcodes.h b/arch/arm64/include/asm/opcodes.h
new file mode 100644
index 0000000..4e603ea
--- /dev/null
+++ b/arch/arm64/include/asm/opcodes.h
@@ -0,0 +1 @@
+#include <../../arm/include/asm/opcodes.h>
diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile
index df7ef87..e77dd61 100644
--- a/arch/arm64/kernel/Makefile
+++ b/arch/arm64/kernel/Makefile
@@ -18,7 +18,9 @@ arm64-obj-y		:= cputable.o debug-monitors.o entry.o irq.o fpsimd.o	\
 			   cpuinfo.o
 
 arm64-obj-$(CONFIG_COMPAT)		+= sys32.o kuser32.o signal32.o 	\
-					   sys_compat.o
+					   sys_compat.o 			\
+					   $(addprefix ../../arm/kernel/,	\
+						opcodes.o)
 arm64-obj-$(CONFIG_FUNCTION_TRACER)	+= ftrace.o entry-ftrace.o
 arm64-obj-$(CONFIG_MODULES)		+= arm64ksyms.o module.o
 arm64-obj-$(CONFIG_SMP)			+= smp.o smp_spin_table.o topology.o
-- 
1.7.10.4

^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCHv2 3/5] arm64: Port SWP/SWPB emulation support from arm
  2014-10-01 12:07 [PATCHv2 0/5] Legacy instruction emulation for arm64 Punit Agrawal
  2014-10-01 12:07 ` [PATCHv2 1/5] arm64: Add support for hooks to handle undefined instructions Punit Agrawal
  2014-10-01 12:07 ` [PATCHv2 2/5] arm64: Add AArch32 instruction set condition code checks Punit Agrawal
@ 2014-10-01 12:07 ` Punit Agrawal
  2014-10-01 12:07 ` [PATCHv2 4/5] arm64: Emulate CP15 Barrier instructions Punit Agrawal
                   ` (2 subsequent siblings)
  5 siblings, 0 replies; 16+ messages in thread
From: Punit Agrawal @ 2014-10-01 12:07 UTC (permalink / raw)
  To: linux-arm-kernel

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. With ARMv8, the option to enable these instructions
through System Control Register was dropped as well.

This patch ports the alternate solution to emulate the SWP and SWPB
instructions using LDXR/STXR sequences from the arm port to
arm64. The emulation is turned off by default and can be enabled at
runtime using sysctl.

Signed-off-by: Punit Agrawal <punit.agrawal@arm.com>
---
 arch/arm64/Kconfig                   |   39 +++++
 arch/arm64/include/asm/insn.h        |    8 +
 arch/arm64/kernel/Makefile           |    1 +
 arch/arm64/kernel/armv8_deprecated.c |  287 ++++++++++++++++++++++++++++++++++
 arch/arm64/kernel/insn.c             |   13 ++
 5 files changed, 348 insertions(+)
 create mode 100644 arch/arm64/kernel/armv8_deprecated.c

diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index fd4e81a..89262da 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -149,6 +149,45 @@ config ARCH_XGENE
 	help
 	  This enables support for AppliedMicro X-Gene SOC Family
 
+comment "Processor Features"
+
+menuconfig ARMV8_DEPRECATED
+	bool "Emulate deprecated/obsolete ARMv8 instructions"
+	depends on COMPAT
+	help
+	  Legacy software support may require certain instructions
+	  that have been deprecated or obsoleted in the architecture.
+
+	  Enable this config to enable selective emulation of these
+	  features.
+
+	  If unsure, say N
+
+if ARMV8_DEPRECATED
+
+config SWP_EMULATION
+	bool "Emulate SWP/SWPB instructions"
+	help
+	  ARMv8 obsoletes the use of A32 SWP/SWPB instructions such that
+	  they are always undefined. Say Y here to enable software
+	  emulation of these instructions for userspace using LDXR/STXR.
+
+	  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, LDXR/STXR 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 N
+
+endif
+
 endmenu
 
 menu "Bus support"
diff --git a/arch/arm64/include/asm/insn.h b/arch/arm64/include/asm/insn.h
index dc1f73b..c3b7c2f 100644
--- a/arch/arm64/include/asm/insn.h
+++ b/arch/arm64/include/asm/insn.h
@@ -105,6 +105,14 @@ bool aarch64_insn_hotpatch_safe(u32 old_insn, u32 new_insn);
 int aarch64_insn_patch_text_nosync(void *addr, u32 insn);
 int aarch64_insn_patch_text_sync(void *addrs[], u32 insns[], int cnt);
 int aarch64_insn_patch_text(void *addrs[], u32 insns[], int cnt);
+
+bool aarch32_insn_is_wide_instruction(u32 instr);
+
+#define RN_OFFSET	16
+#define RT_OFFSET	12
+#define RT2_OFFSET	 0
+
+u32 aarch32_insn_extract_reg_num(u32 insn, int offset);
 #endif /* __ASSEMBLY__ */
 
 #endif	/* __ASM_INSN_H */
diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile
index e77dd61..39590f3 100644
--- a/arch/arm64/kernel/Makefile
+++ b/arch/arm64/kernel/Makefile
@@ -31,6 +31,7 @@ arm64-obj-$(CONFIG_ARM64_CPU_SUSPEND)	+= sleep.o suspend.o
 arm64-obj-$(CONFIG_JUMP_LABEL)		+= jump_label.o
 arm64-obj-$(CONFIG_KGDB)		+= kgdb.o
 arm64-obj-$(CONFIG_EFI)			+= efi.o efi-stub.o efi-entry.o
+arm64-obj-$(CONFIG_ARMV8_DEPRECATED)	+= armv8_deprecated.o
 
 obj-y					+= $(arm64-obj-y) vdso/
 obj-m					+= $(arm64-obj-m)
diff --git a/arch/arm64/kernel/armv8_deprecated.c b/arch/arm64/kernel/armv8_deprecated.c
new file mode 100644
index 0000000..23fc6f8
--- /dev/null
+++ b/arch/arm64/kernel/armv8_deprecated.c
@@ -0,0 +1,287 @@
+/*
+ *  Copied from arch/arm/kernel/swp_emulate.c and modified for ARMv8
+ *
+ *  Copyright (C) 2009,2012,2014 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.
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/perf_event.h>
+#include <linux/sched.h>
+#include <linux/sysctl.h>
+
+#include <asm/insn.h>
+#include <asm/opcodes.h>
+#include <asm/system_misc.h>
+#include <asm/traps.h>
+#include <asm/uaccess.h>
+
+/*
+ * The runtime support for deprecated instruction support can be in one of
+ * following two states -
+ *
+ * 0 = undef
+ * 1 = emulate (software emulation)
+ */
+#define INSTR_UNDEF (0)
+#define INSTR_EMULATE (1)
+
+/*
+ *  Implement emulation of the SWP/SWPB instructions using load-exclusive and
+ *  store-exclusive.
+ *
+ *  Syntax of SWP{B} instruction: SWP{B}<c> <Rt>, <Rt2>, [<Rn>]
+ *  Where: Rt  = destination
+ *	   Rt2 = source
+ *	   Rn  = address
+ */
+
+/*
+ * SWP defaults to undef as it's been obsoleted in the architecture
+ */
+static int swp_enable = 0;
+static int swp_enable_min = INSTR_UNDEF;
+static int swp_enable_max = INSTR_EMULATE;
+
+/*
+ * Error-checking SWP macros implemented using ldxr{b}/stxr{b}
+ */
+#define __user_swpX_asm(data, addr, res, temp, B)		\
+	__asm__ __volatile__(					\
+	"	mov		%w2, %w1\n"			\
+	"0:	ldxr"B"		%w1, [%3]\n"			\
+	"1:	stxr"B"		%w0, %w2, [%3]\n"		\
+	"	cbz		%w0, 2f\n"			\
+	"	mov		%w0, %w4\n"			\
+	"2:\n"							\
+	"	.pushsection	 .fixup,\"ax\"\n"		\
+	"	.align		2\n"				\
+	"3:	mov		%w0, %w5\n"			\
+	"	b		2b\n"				\
+	"	.popsection"					\
+	"	.pushsection	 __ex_table,\"a\"\n"		\
+	"	.align		3\n"				\
+	"	.quad		0b, 3b\n"			\
+	"	.quad		1b, 3b\n"			\
+	"	.popsection"					\
+	: "=&r" (res), "+r" (data), "=&r" (temp)		\
+	: "r" (addr), "i" (-EAGAIN), "i" (-EFAULT)		\
+	: "memory")
+
+#define __user_swp_asm(data, addr, res, temp) \
+	__user_swpX_asm(data, addr, res, temp, "")
+#define __user_swpb_asm(data, addr, res, temp) \
+	__user_swpX_asm(data, addr, res, temp, "b")
+
+/*
+ * Bit 22 of the instruction encoding distinguishes between
+ * the SWP and SWPB variants (bit set means SWPB).
+ */
+#define TYPE_SWPB (1 << 22)
+
+/*
+ * 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;
+
+	down_read(&current->mm->mmap_sem);
+	if (find_vma(current->mm, addr) == NULL)
+		info.si_code = SEGV_MAPERR;
+	else
+		info.si_code = SEGV_ACCERR;
+	up_read(&current->mm->mmap_sem);
+
+	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");
+	arm64_notify_die("Illegal memory access", regs, &info, 0);
+}
+
+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) {
+		unsigned long temp;
+
+		if (type == TYPE_SWPB)
+			__user_swpb_asm(*data, address, res, temp);
+		else
+			__user_swp_asm(*data, address, res, temp);
+
+		if (likely(res != -EAGAIN) || signal_pending(current))
+			break;
+
+		cond_resched();
+	}
+
+	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, u32 instr)
+{
+	u32 destreg, data, type, address = 0;
+	int rn, rt2, res = 0;
+
+	perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, 1, regs, regs->pc);
+
+	type = instr & TYPE_SWPB;
+
+	switch (arm_check_condition(instr, regs->pstate)) {
+	case ARM_OPCODE_CONDTEST_PASS:
+		break;
+	case ARM_OPCODE_CONDTEST_FAIL:
+		/* Condition failed - return to next instruction */
+		goto ret;
+	case ARM_OPCODE_CONDTEST_UNCOND:
+		/* If unconditional encoding - not a SWP, undef */
+		return -EFAULT;
+	default:
+		return -EINVAL;
+	}
+
+	rn = aarch32_insn_extract_reg_num(instr, RN_OFFSET);
+	rt2 = aarch32_insn_extract_reg_num(instr, RT2_OFFSET);
+
+	address = (u32)regs->user_regs.regs[rn];
+	data	= (u32)regs->user_regs.regs[rt2];
+	destreg = aarch32_insn_extract_reg_num(instr, RT_OFFSET);
+
+	pr_debug("addr in r%d->0x%08x, dest is r%d, source in r%d->0x%08x)\n",
+		rn, address, destreg,
+		aarch32_insn_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 0x%08x not allowed!\n",
+			address);
+		goto fault;
+	}
+
+	res = emulate_swpX(address, &data, type);
+	if (res == -EFAULT)
+		goto fault;
+	else if (res == 0)
+		regs->user_regs.regs[destreg] = data;
+
+ret:
+	pr_warn_ratelimited("\"%s\" (%ld) uses obsolete SWP{B} instruction at 0x%llx\n",
+			current->comm, (unsigned long)current->pid, regs->pc);
+
+	regs->pc += 4;
+	return 0;
+
+fault:
+	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.
+ */
+static struct undef_hook swp_hook = {
+	.instr_mask	= 0x0fb00ff0,
+	.instr_val	= 0x01000090,
+	.pstate_mask	= COMPAT_PSR_MODE_MASK,
+	.pstate_val	= COMPAT_PSR_MODE_USR,
+	.fn		= swp_handler
+};
+
+static void swp_emulation_init(void)
+{
+	if (register_undef_hook(&swp_hook) == 0)
+		pr_notice("Registered SWP/SWPB emulation handler\n");
+}
+
+static void swp_emulation_remove(void)
+{
+	unregister_undef_hook(&swp_hook);
+	pr_notice("Removed SWP/SWPB emulation handler\n");
+}
+
+static void swp_init(void)
+{
+	if (swp_enable)
+		swp_emulation_init();
+}
+
+static int proc_swp_handler(struct ctl_table *table, int write,
+			void __user *buffer, size_t *lenp, loff_t *ppos)
+{
+	u32 prev = swp_enable;
+	int ret = proc_dointvec_minmax(table, write, buffer, lenp, ppos);
+
+	if (ret || !write || prev == swp_enable)
+		return ret;
+
+	switch (swp_enable) {
+	case INSTR_UNDEF: /* Turned off */
+		swp_emulation_remove();
+		break;
+	case INSTR_EMULATE: /* Emulation turned on */
+		swp_emulation_init();
+		break;
+	}
+
+	return 0;
+}
+
+static struct ctl_table ctl_armv8_deprecated[] = {
+	{
+		.procname = "swp_enable",
+		.data = &swp_enable,
+		.maxlen = sizeof(u32),
+		.mode = 0644,
+		.proc_handler = proc_swp_handler,
+		.extra1 = &swp_enable_min,
+		.extra2 = &swp_enable_max,
+	},
+	{ }
+};
+
+static struct ctl_table ctl_abi[] = {
+	{
+		.procname = "abi",
+		.mode = 0555,
+		.child = ctl_armv8_deprecated,
+	},
+	{ }
+};
+
+/*
+ * Invoked as late_initcall, since not needed before init spawned.
+ */
+static int __init armv8_deprecated_init(void)
+{
+	if (IS_ENABLED(CONFIG_SWP_EMULATION))
+		swp_init();
+
+	register_sysctl_table(ctl_abi);
+
+	return 0;
+}
+
+late_initcall(armv8_deprecated_init);
diff --git a/arch/arm64/kernel/insn.c b/arch/arm64/kernel/insn.c
index 92f3683..6e77a54 100644
--- a/arch/arm64/kernel/insn.c
+++ b/arch/arm64/kernel/insn.c
@@ -302,3 +302,16 @@ u32 __kprobes aarch64_insn_gen_nop(void)
 {
 	return aarch64_insn_gen_hint(AARCH64_INSN_HINT_NOP);
 }
+
+bool aarch32_insn_is_wide_instruction(u32 instr)
+{
+	return instr >= 0xe800;
+}
+
+/*
+ * Macros/defines for extracting register numbers from instruction.
+ */
+u32 aarch32_insn_extract_reg_num(u32 insn, int offset)
+{
+	return (insn & (0xf << offset)) >> offset;
+}
-- 
1.7.10.4

^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCHv2 4/5] arm64: Emulate CP15 Barrier instructions
  2014-10-01 12:07 [PATCHv2 0/5] Legacy instruction emulation for arm64 Punit Agrawal
                   ` (2 preceding siblings ...)
  2014-10-01 12:07 ` [PATCHv2 3/5] arm64: Port SWP/SWPB emulation support from arm Punit Agrawal
@ 2014-10-01 12:07 ` Punit Agrawal
  2014-10-01 12:07 ` [PATCHv2 5/5] arm64: Trace emulation of AArch32 legacy instructions Punit Agrawal
  2014-10-01 13:37 ` [PATCHv2 0/5] Legacy instruction emulation for arm64 Punit Agrawal
  5 siblings, 0 replies; 16+ messages in thread
From: Punit Agrawal @ 2014-10-01 12:07 UTC (permalink / raw)
  To: linux-arm-kernel

The CP15 barrier instructions (CP15ISB, CP15DSB and CP15DMB) are
deprecated in the ARMv7 architecture, superseded by ISB, DSB and DMB
instructions respectively. Some implementations may provide the
ability to disable the CP15 barriers by disabling the CP15BEN bit in
SCTLR_EL1. If not enabled, the encodings for these instructions become
undefined.

To support legacy software using these instructions, this patch adds
support to -
* emulate CP15 barriers and warn the user about their use
* toggle CP15BEN in SCTLR_EL1

The choice between using emulation or hardware execution is controlled
via sysctl. To aid migration of software it defaults to emulation.

Signed-off-by: Punit Agrawal <punit.agrawal@arm.com>
---
 arch/arm64/Kconfig                   |   15 +++
 arch/arm64/include/asm/insn.h        |    2 +
 arch/arm64/kernel/armv8_deprecated.c |  189 +++++++++++++++++++++++++++++++++-
 arch/arm64/kernel/insn.c             |   13 +++
 4 files changed, 218 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 89262da..0abaf7b 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -186,6 +186,21 @@ config SWP_EMULATION
 
 	  If unsure, say N
 
+config CP15_BARRIER_EMULATION
+	bool "Emulate CP15 Barrier instructions"
+	help
+	  The CP15 barrier instructions - CP15ISB, CP15DSB, and
+	  CP15DMB - are deprecated in ARMv8 (and ARMv7). It is
+	  strongly recommended to use the ISB, DSB, and DMB
+	  instructions instead.
+
+	  Say Y here to enable software emulation of these
+	  instructions for AArch32 userspace code. When this option is
+	  enabled, CP15 barrier usage is traced which can help
+	  identify software that needs updating.
+
+	  If unsure, say N
+
 endif
 
 endmenu
diff --git a/arch/arm64/include/asm/insn.h b/arch/arm64/include/asm/insn.h
index c3b7c2f..de684fe 100644
--- a/arch/arm64/include/asm/insn.h
+++ b/arch/arm64/include/asm/insn.h
@@ -113,6 +113,8 @@ bool aarch32_insn_is_wide_instruction(u32 instr);
 #define RT2_OFFSET	 0
 
 u32 aarch32_insn_extract_reg_num(u32 insn, int offset);
+u32 aarch32_insn_mcr_extract_opc2(u32 insn);
+u32 aarch32_insn_mcr_extract_crm(u32 insn);
 #endif /* __ASSEMBLY__ */
 
 #endif	/* __ASM_INSN_H */
diff --git a/arch/arm64/kernel/armv8_deprecated.c b/arch/arm64/kernel/armv8_deprecated.c
index 23fc6f8..53a6252 100644
--- a/arch/arm64/kernel/armv8_deprecated.c
+++ b/arch/arm64/kernel/armv8_deprecated.c
@@ -9,6 +9,7 @@
  * published by the Free Software Foundation.
  */
 
+#include <linux/cpu.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/perf_event.h>
@@ -23,13 +24,15 @@
 
 /*
  * The runtime support for deprecated instruction support can be in one of
- * following two states -
+ * following three states -
  *
  * 0 = undef
  * 1 = emulate (software emulation)
+ * 2 = enable (supported in hardware)
  */
 #define INSTR_UNDEF (0)
 #define INSTR_EMULATE (1)
+#define INSTR_ENABLE (2)
 
 /*
  *  Implement emulation of the SWP/SWPB instructions using load-exclusive and
@@ -249,6 +252,178 @@ static int proc_swp_handler(struct ctl_table *table, int write,
 	return 0;
 }
 
+/*
+ * CP15 barriers default to emulate as they have been deprecated in the
+ * architecture.
+ */
+static u32 cp15_barrier_enable = 1;
+static u32 cp15_barrier_enable_min = INSTR_UNDEF;
+static u32 cp15_barrier_enable_max = INSTR_ENABLE;
+
+static int cp15barrier_handler(struct pt_regs *regs, u32 instr)
+{
+	perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, 1, regs, regs->pc);
+
+	switch (arm_check_condition(instr, regs->pstate)) {
+	case ARM_OPCODE_CONDTEST_PASS:
+		break;
+	case ARM_OPCODE_CONDTEST_FAIL:
+		/* Condition failed - return to next instruction */
+		goto ret;
+	case ARM_OPCODE_CONDTEST_UNCOND:
+		/* If unconditional encoding - not a barrier instruction */
+		return -EFAULT;
+	default:
+		return -EINVAL;
+	}
+
+	switch (aarch32_insn_mcr_extract_crm(instr)) {
+	case 10:
+		/*
+		 * dmb - mcr p15, 0, Rt, c7, c10, 5
+		 * dsb - mcr p15, 0, Rt, c7, c10, 4
+		 */
+		if (aarch32_insn_mcr_extract_opc2(instr) == 5)
+			dmb(sy);
+		else
+			dsb(sy);
+		break;
+	case 5:
+		/*
+		 * isb - mcr p15, 0, Rt, c7, c5, 4
+		 */
+		isb();
+		break;
+	}
+
+ret:
+	pr_warn_ratelimited("\"%s\" (%ld) uses deprecated CP15 Barrier instruction at 0x%llx\n",
+			current->comm, (unsigned long)current->pid, regs->pc);
+
+	regs->pc += 4;
+	return 0;
+}
+
+/* data barrier */
+static struct undef_hook cp15db_hook = {
+	.instr_mask	= 0x0fff0fdf,
+	.instr_val	= 0x0e070f9a,
+	.pstate_mask	= COMPAT_PSR_MODE_MASK,
+	.pstate_val	= COMPAT_PSR_MODE_USR,
+	.fn		= cp15barrier_handler,
+};
+
+/* instruction barrier */
+static struct undef_hook cp15isb_hook = {
+	.instr_mask	= 0x0fff0fff,
+	.instr_val	= 0x0e070f95,
+	.pstate_mask	= COMPAT_PSR_MODE_MASK,
+	.pstate_val	= COMPAT_PSR_MODE_USR,
+	.fn		= cp15barrier_handler,
+};
+
+static void cp15_barrier_emulation_init(void)
+{
+	if (register_undef_hook(&cp15db_hook) == 0 &&
+		register_undef_hook(&cp15isb_hook) == 0)
+		pr_notice("Registered CP15 Barrier emulation handler\n");
+}
+
+static void cp15_barrier_emulation_remove(void)
+{
+	unregister_undef_hook(&cp15db_hook);
+	unregister_undef_hook(&cp15isb_hook);
+
+	pr_notice("Removed CP15 Barrier emulation handler\n");
+}
+
+#define SCTLR_EL1_CP15BEN (1 << 5)
+
+static inline void config_sctlr_el1(u32 clear, u32 set)
+{
+	u32 val;
+
+	asm volatile("mrs %0, sctlr_el1" : "=r" (val));
+	val &= ~clear;
+	val |= set;
+	asm volatile("msr sctlr_el1, %0" : : "r" (val));
+}
+
+static void enable_cp15_ben(void *info)
+{
+	config_sctlr_el1(0, SCTLR_EL1_CP15BEN);
+}
+
+static void disable_cp15_ben(void *info)
+{
+	config_sctlr_el1(SCTLR_EL1_CP15BEN, 0);
+}
+
+static int cpu_hotplug_notify(struct notifier_block *b, unsigned long action,
+			  void *hcpu)
+{
+	switch (action) {
+	case CPU_STARTING:
+		enable_cp15_ben(NULL);
+		return NOTIFY_DONE;
+	}
+
+	return NOTIFY_OK;
+}
+
+static struct notifier_block cpu_hotplug_notifier = {
+	.notifier_call = cpu_hotplug_notify,
+};
+
+static void cp15_barrier_init(void)
+{
+	switch (cp15_barrier_enable) {
+	case INSTR_UNDEF: /* turned off, nothing to do */
+		break;
+	case INSTR_EMULATE: /* register emulation hooks */
+		cp15_barrier_emulation_init();
+		break;
+	case INSTR_ENABLE: /* Set CP15BEN in SCTLR_EL1 */
+		register_cpu_notifier(&cpu_hotplug_notifier);
+		on_each_cpu(enable_cp15_ben, NULL, true);
+		break;
+	}
+}
+
+static void cp15_barrier_remove(u32 deprecated_feature_state)
+{
+	/* Disable current handling */
+	switch (deprecated_feature_state) {
+	case INSTR_UNDEF: /* already off, do nothing */
+		break;
+	case INSTR_EMULATE: /* unregister emulation hooks */
+		cp15_barrier_emulation_remove();
+		break;
+	case INSTR_ENABLE: /* Clear CP15BEN in SCTLR_EL1 */
+		unregister_cpu_notifier(&cpu_hotplug_notifier);
+		on_each_cpu(disable_cp15_ben, NULL, true);
+		break;
+	}
+}
+
+static int proc_cp15_barrier_handler(struct ctl_table *table, int write,
+		void __user *buffer, size_t *lenp, loff_t *ppos)
+{
+	u32 prev = cp15_barrier_enable;
+	int ret = proc_dointvec_minmax(table, write, buffer, lenp, ppos);
+
+	if (ret || !write || prev == cp15_barrier_enable)
+		return ret;
+
+	/* disable previous mechanism */
+	cp15_barrier_remove(prev);
+
+	/* Install new mechanism */
+	cp15_barrier_init();
+
+	return ret;
+}
+
 static struct ctl_table ctl_armv8_deprecated[] = {
 	{
 		.procname = "swp_enable",
@@ -259,6 +434,15 @@ static struct ctl_table ctl_armv8_deprecated[] = {
 		.extra1 = &swp_enable_min,
 		.extra2 = &swp_enable_max,
 	},
+	{
+		.procname = "cp15_barrier_enable",
+		.data = &cp15_barrier_enable,
+		.maxlen = sizeof(u32),
+		.mode = 0644,
+		.proc_handler = proc_cp15_barrier_handler,
+		.extra1 = &cp15_barrier_enable_min,
+		.extra2 = &cp15_barrier_enable_max,
+	},
 	{ }
 };
 
@@ -279,6 +463,9 @@ static int __init armv8_deprecated_init(void)
 	if (IS_ENABLED(CONFIG_SWP_EMULATION))
 		swp_init();
 
+	if (IS_ENABLED(CONFIG_CP15_BARRIER_EMULATION))
+		cp15_barrier_init();
+
 	register_sysctl_table(ctl_abi);
 
 	return 0;
diff --git a/arch/arm64/kernel/insn.c b/arch/arm64/kernel/insn.c
index 6e77a54..b01b8e4 100644
--- a/arch/arm64/kernel/insn.c
+++ b/arch/arm64/kernel/insn.c
@@ -315,3 +315,16 @@ u32 aarch32_insn_extract_reg_num(u32 insn, int offset)
 {
 	return (insn & (0xf << offset)) >> offset;
 }
+
+#define OPC2_MASK	0x7
+#define OPC2_OFFSET	5
+u32 aarch32_insn_mcr_extract_opc2(u32 insn)
+{
+	return (insn & (OPC2_MASK << OPC2_OFFSET)) >> OPC2_OFFSET;
+}
+
+#define CRM_MASK	0xf
+u32 aarch32_insn_mcr_extract_crm(u32 insn)
+{
+	return insn & CRM_MASK;
+}
-- 
1.7.10.4

^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCHv2 5/5] arm64: Trace emulation of AArch32 legacy instructions
  2014-10-01 12:07 [PATCHv2 0/5] Legacy instruction emulation for arm64 Punit Agrawal
                   ` (3 preceding siblings ...)
  2014-10-01 12:07 ` [PATCHv2 4/5] arm64: Emulate CP15 Barrier instructions Punit Agrawal
@ 2014-10-01 12:07 ` Punit Agrawal
  2014-10-01 14:40   ` Steven Rostedt
  2014-10-01 13:37 ` [PATCHv2 0/5] Legacy instruction emulation for arm64 Punit Agrawal
  5 siblings, 1 reply; 16+ messages in thread
From: Punit Agrawal @ 2014-10-01 12:07 UTC (permalink / raw)
  To: linux-arm-kernel

Introduce an event to trace the usage of emulated instructions. The
trace event is intended to help identify and encourage the migration
of legacy software using the emulation features.

Use this event to trace usage of swp and CP15 barrier emulation.

Cc: Steven Rostedt <rostedt@goodmis.org>
Signed-off-by: Punit Agrawal <punit.agrawal@arm.com>
---
 arch/arm64/kernel/armv8_deprecated.c |   19 ++++++++++++++++--
 include/trace/events/emulation.h     |   35 ++++++++++++++++++++++++++++++++++
 2 files changed, 52 insertions(+), 2 deletions(-)
 create mode 100644 include/trace/events/emulation.h

diff --git a/arch/arm64/kernel/armv8_deprecated.c b/arch/arm64/kernel/armv8_deprecated.c
index 53a6252..1726b3f 100644
--- a/arch/arm64/kernel/armv8_deprecated.c
+++ b/arch/arm64/kernel/armv8_deprecated.c
@@ -16,6 +16,9 @@
 #include <linux/sched.h>
 #include <linux/sysctl.h>
 
+#define CREATE_TRACE_POINTS
+#include <trace/events/emulation.h>
+
 #include <asm/insn.h>
 #include <asm/opcodes.h>
 #include <asm/system_misc.h>
@@ -189,6 +192,11 @@ static int swp_handler(struct pt_regs *regs, u32 instr)
 		regs->user_regs.regs[destreg] = data;
 
 ret:
+	if (type == TYPE_SWPB)
+		trace_instruction_emulation("swpb", regs->pc);
+	else
+		trace_instruction_emulation("swp", regs->pc);
+
 	pr_warn_ratelimited("\"%s\" (%ld) uses obsolete SWP{B} instruction at 0x%llx\n",
 			current->comm, (unsigned long)current->pid, regs->pc);
 
@@ -283,16 +291,23 @@ static int cp15barrier_handler(struct pt_regs *regs, u32 instr)
 		 * dmb - mcr p15, 0, Rt, c7, c10, 5
 		 * dsb - mcr p15, 0, Rt, c7, c10, 4
 		 */
-		if (aarch32_insn_mcr_extract_opc2(instr) == 5)
+		if (aarch32_insn_mcr_extract_opc2(instr) == 5) {
 			dmb(sy);
-		else
+			trace_instruction_emulation(
+				"mcr p15, 0, Rt, c7, c10, 5", regs->pc);
+		} else {
 			dsb(sy);
+			trace_instruction_emulation(
+				"mcr p15, 0, Rt, c7, c10, 4", regs->pc);
+		}
 		break;
 	case 5:
 		/*
 		 * isb - mcr p15, 0, Rt, c7, c5, 4
 		 */
 		isb();
+		trace_instruction_emulation(
+			"mcr p15, 0, Rt, c7, c5, 4", regs->pc);
 		break;
 	}
 
diff --git a/include/trace/events/emulation.h b/include/trace/events/emulation.h
new file mode 100644
index 0000000..e77726a
--- /dev/null
+++ b/include/trace/events/emulation.h
@@ -0,0 +1,35 @@
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM emulation
+
+#if !defined(_TRACE_EMULATION_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_EMULATION_H
+
+#include <linux/tracepoint.h>
+
+TRACE_EVENT(instruction_emulation,
+
+	TP_PROTO(const char *instr, u64 addr),
+	TP_ARGS(instr, addr),
+
+	TP_STRUCT__entry(
+		__array(char, comm, TASK_COMM_LEN)
+		__field(pid_t, pid)
+		__string(instr, instr)
+		__field(u64, addr)
+	),
+
+	TP_fast_assign(
+		memcpy(__entry->comm, current->comm, TASK_COMM_LEN);
+		__entry->pid = current->pid;
+		__assign_str(instr, instr);
+		__entry->addr = addr;
+	),
+
+	TP_printk("instr=%s comm=%s pid=%d addr=0x%llx", __get_str(instr),
+		__entry->comm, __entry->pid, __entry->addr)
+);
+
+#endif /* _TRACE_EMULATION_H */
+
+/* This part must be outside protection */
+#include <trace/define_trace.h>
-- 
1.7.10.4

^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCHv2 0/5] Legacy instruction emulation for arm64
  2014-10-01 12:07 [PATCHv2 0/5] Legacy instruction emulation for arm64 Punit Agrawal
                   ` (4 preceding siblings ...)
  2014-10-01 12:07 ` [PATCHv2 5/5] arm64: Trace emulation of AArch32 legacy instructions Punit Agrawal
@ 2014-10-01 13:37 ` Punit Agrawal
  2014-10-01 13:37   ` [PATCHv2 1/5] arm64: Add support for hooks to handle undefined instructions Punit Agrawal
                     ` (5 more replies)
  5 siblings, 6 replies; 16+ messages in thread
From: Punit Agrawal @ 2014-10-01 13:37 UTC (permalink / raw)
  To: linux-arm-kernel

[ Correcting Arnd's email. Apologies for the extra copy ]

Hi,

This is the second posting of the legacy instruction support for
arm64. The previous posting can be found at [1].

The patchset ports the infrastructure to register hooks for undefined
instruction abort and uses this to adds support for the emulation of
SWP{B} and CP15 Barrier instructions from ARMv7 to the v8 port of
Linux.

Via sysctl, it is possible to control the runtime state of emulation
* Off
  sysctl value: 0
  Generates undefined instruction abort. Default for instructions that
  have been obsoleted in the architecture, e.g., SWP

* Emulate
  sysctl value: 1
  Uses software emulation. To aid migration of software, in this mode
  usage of emulated instruction is traced as well as rate limited
  warnings are issued. This is the default for deprecated
  instructions, .e.g., CP15 barriers

* Enable
  sysctl value: 2
  Although marked as deprecated, some implementations may support the
  enabling/disabling of hardware support for the execution of these
  instructions. Using hardware execution generally provides better
  performance, but at the loss of ability to gather runtime statistics
  about the use of the deprecated instructions.

Patches 1-2/5 add infrastructure code to add support for undefined
instruction hooks and decoding condition checks.

Patch 3-4/6 adds support for SWP and CP15 barriers respectively. They
also provide the ability to control the emulation by writing one of
the above three values to /proc/sys/abi file nodes.

Patch 6/6 introduces a trace point to log instruction emulation and then
uses this to trace the usage of the above instructions when using
emulation.

Although not in a merge window, the intention of the posting is to
allow early access to the code to reduce divergenece in product
kernels where additional features are being worked on.

Cheers,
Punit

Changes since [1]:
* Added support for Thumb instructions when registering undefined
hooks as well
* Emulation support is now added to armv8_deprecated.c (was previously
v7_obsolete.c)
* Instruction support level - Off, Emulate or Enable (when supported
in hardware) - is now controlled through sysctl
* Using trace points instead of debugfs for stats reporting


[1] http://thread.gmane.org/gmane.linux.ports.arm.kernel/351054

Punit Agrawal (5):
  arm64: Add support for hooks to handle undefined instructions
  arm64: Add AArch32 instruction set condition code checks
  arm64: Port SWP/SWPB emulation support from arm
  arm64: Emulate CP15 Barrier instructions
  arm64: Trace emulation of AArch32 legacy instructions

 arch/arm64/Kconfig                   |   54 ++++
 arch/arm64/include/asm/insn.h        |   10 +
 arch/arm64/include/asm/opcodes.h     |    1 +
 arch/arm64/include/asm/traps.h       |   16 ++
 arch/arm64/kernel/Makefile           |    5 +-
 arch/arm64/kernel/armv8_deprecated.c |  489 ++++++++++++++++++++++++++++++++++
 arch/arm64/kernel/insn.c             |   26 ++
 arch/arm64/kernel/traps.c            |   68 +++++
 include/trace/events/emulation.h     |   35 +++
 9 files changed, 703 insertions(+), 1 deletion(-)
 create mode 100644 arch/arm64/include/asm/opcodes.h
 create mode 100644 arch/arm64/kernel/armv8_deprecated.c
 create mode 100644 include/trace/events/emulation.h

-- 
1.7.10.4

^ permalink raw reply	[flat|nested] 16+ messages in thread

* [PATCHv2 1/5] arm64: Add support for hooks to handle undefined instructions
  2014-10-01 13:37 ` [PATCHv2 0/5] Legacy instruction emulation for arm64 Punit Agrawal
@ 2014-10-01 13:37   ` Punit Agrawal
  2014-10-01 13:37   ` [PATCHv2 2/5] arm64: Add AArch32 instruction set condition code checks Punit Agrawal
                     ` (4 subsequent siblings)
  5 siblings, 0 replies; 16+ messages in thread
From: Punit Agrawal @ 2014-10-01 13:37 UTC (permalink / raw)
  To: linux-arm-kernel

Add support to register hooks for undefined instructions. The handlers
will be called when the undefined instruction and the processor state
(as contained in pstate) match criteria used at registration.

Signed-off-by: Punit Agrawal <punit.agrawal@arm.com>
---
 arch/arm64/include/asm/traps.h |   16 ++++++++++
 arch/arm64/kernel/traps.c      |   68 ++++++++++++++++++++++++++++++++++++++++
 2 files changed, 84 insertions(+)

diff --git a/arch/arm64/include/asm/traps.h b/arch/arm64/include/asm/traps.h
index 10ca8ff..4faaf03 100644
--- a/arch/arm64/include/asm/traps.h
+++ b/arch/arm64/include/asm/traps.h
@@ -18,6 +18,22 @@
 #ifndef __ASM_TRAP_H
 #define __ASM_TRAP_H
 
+#include <linux/list.h>
+
+struct pt_regs;
+
+struct undef_hook {
+	struct list_head node;
+	u32 instr_mask;
+	u32 instr_val;
+	u64 pstate_mask;
+	u64 pstate_val;
+	int (*fn)(struct pt_regs *regs, u32 instr);
+};
+
+int register_undef_hook(struct undef_hook *hook);
+void unregister_undef_hook(struct undef_hook *hook);
+
 static inline int in_exception_text(unsigned long ptr)
 {
 	extern char __exception_text_start[];
diff --git a/arch/arm64/kernel/traps.c b/arch/arm64/kernel/traps.c
index 02cd3f0..bcde9de 100644
--- a/arch/arm64/kernel/traps.c
+++ b/arch/arm64/kernel/traps.c
@@ -260,6 +260,71 @@ void arm64_notify_die(const char *str, struct pt_regs *regs,
 	}
 }
 
+static LIST_HEAD(undef_hook);
+static DEFINE_RAW_SPINLOCK(undef_lock);
+
+int register_undef_hook(struct undef_hook *hook)
+{
+	unsigned long flags;
+
+	raw_spin_lock_irqsave(&undef_lock, flags);
+	list_add(&hook->node, &undef_hook);
+	raw_spin_unlock_irqrestore(&undef_lock, flags);
+
+	return 0;
+}
+
+void unregister_undef_hook(struct undef_hook *hook)
+{
+	unsigned long flags;
+
+	raw_spin_lock_irqsave(&undef_lock, flags);
+	list_del(&hook->node);
+	raw_spin_unlock_irqrestore(&undef_lock, flags);
+}
+
+static int call_undef_hook(struct pt_regs *regs)
+{
+	struct undef_hook *hook;
+	unsigned long flags;
+	u32 instr;
+	int (*fn)(struct pt_regs *regs, u32 instr) = NULL;
+	void __user *pc = (void __user *)instruction_pointer(regs);
+
+	if (!user_mode(regs))
+		return 1;
+
+	if (compat_thumb_mode(regs)) {
+		/* 16-bit Thumb instruction */
+		if (get_user(instr, (u16 __user *)pc))
+			goto exit;
+		instr = le16_to_cpu(instr);
+		if (aarch32_insn_is_wide_instruction(instr)) {
+			u32 instr2;
+
+			if (get_user(instr2, (u16 __user *)(pc + 2)))
+				goto exit;
+			instr2 = le16_to_cpu(instr2);
+			instr = (instr << 16) | instr2;
+		}
+	} else {
+		/* 32-bit ARM instruction */
+		if (get_user(instr, (u32 __user *)pc))
+			goto exit;
+		instr = le32_to_cpu(instr);
+	}
+
+	raw_spin_lock_irqsave(&undef_lock, flags);
+	list_for_each_entry(hook, &undef_hook, node)
+		if ((instr & hook->instr_mask) == hook->instr_val &&
+			(regs->pstate & hook->pstate_mask) == hook->pstate_val)
+			fn = hook->fn;
+
+	raw_spin_unlock_irqrestore(&undef_lock, flags);
+exit:
+	return fn ? fn(regs, instr) : 1;
+}
+
 asmlinkage void __exception do_undefinstr(struct pt_regs *regs)
 {
 	siginfo_t info;
@@ -269,6 +334,9 @@ asmlinkage void __exception do_undefinstr(struct pt_regs *regs)
 	if (!aarch32_break_handler(regs))
 		return;
 
+	if (call_undef_hook(regs) == 0)
+		return;
+
 	if (show_unhandled_signals && unhandled_signal(current, SIGILL) &&
 	    printk_ratelimit()) {
 		pr_info("%s[%d]: undefined instruction: pc=%p\n",
-- 
1.7.10.4

^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCHv2 2/5] arm64: Add AArch32 instruction set condition code checks
  2014-10-01 13:37 ` [PATCHv2 0/5] Legacy instruction emulation for arm64 Punit Agrawal
  2014-10-01 13:37   ` [PATCHv2 1/5] arm64: Add support for hooks to handle undefined instructions Punit Agrawal
@ 2014-10-01 13:37   ` Punit Agrawal
  2014-10-01 13:37   ` [PATCHv2 3/5] arm64: Port SWP/SWPB emulation support from arm Punit Agrawal
                     ` (3 subsequent siblings)
  5 siblings, 0 replies; 16+ messages in thread
From: Punit Agrawal @ 2014-10-01 13:37 UTC (permalink / raw)
  To: linux-arm-kernel

Port support for AArch32 instruction condition code checking from arm
to arm64.

Signed-off-by: Punit Agrawal <punit.agrawal@arm.com>
---
 arch/arm64/include/asm/opcodes.h |    1 +
 arch/arm64/kernel/Makefile       |    4 +++-
 2 files changed, 4 insertions(+), 1 deletion(-)
 create mode 100644 arch/arm64/include/asm/opcodes.h

diff --git a/arch/arm64/include/asm/opcodes.h b/arch/arm64/include/asm/opcodes.h
new file mode 100644
index 0000000..4e603ea
--- /dev/null
+++ b/arch/arm64/include/asm/opcodes.h
@@ -0,0 +1 @@
+#include <../../arm/include/asm/opcodes.h>
diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile
index df7ef87..e77dd61 100644
--- a/arch/arm64/kernel/Makefile
+++ b/arch/arm64/kernel/Makefile
@@ -18,7 +18,9 @@ arm64-obj-y		:= cputable.o debug-monitors.o entry.o irq.o fpsimd.o	\
 			   cpuinfo.o
 
 arm64-obj-$(CONFIG_COMPAT)		+= sys32.o kuser32.o signal32.o 	\
-					   sys_compat.o
+					   sys_compat.o 			\
+					   $(addprefix ../../arm/kernel/,	\
+						opcodes.o)
 arm64-obj-$(CONFIG_FUNCTION_TRACER)	+= ftrace.o entry-ftrace.o
 arm64-obj-$(CONFIG_MODULES)		+= arm64ksyms.o module.o
 arm64-obj-$(CONFIG_SMP)			+= smp.o smp_spin_table.o topology.o
-- 
1.7.10.4

^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCHv2 3/5] arm64: Port SWP/SWPB emulation support from arm
  2014-10-01 13:37 ` [PATCHv2 0/5] Legacy instruction emulation for arm64 Punit Agrawal
  2014-10-01 13:37   ` [PATCHv2 1/5] arm64: Add support for hooks to handle undefined instructions Punit Agrawal
  2014-10-01 13:37   ` [PATCHv2 2/5] arm64: Add AArch32 instruction set condition code checks Punit Agrawal
@ 2014-10-01 13:37   ` Punit Agrawal
  2014-10-06 10:52     ` Will Deacon
  2014-10-01 13:37   ` [PATCHv2 4/5] arm64: Emulate CP15 Barrier instructions Punit Agrawal
                     ` (2 subsequent siblings)
  5 siblings, 1 reply; 16+ messages in thread
From: Punit Agrawal @ 2014-10-01 13:37 UTC (permalink / raw)
  To: linux-arm-kernel

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. With ARMv8, the option to enable these instructions
through System Control Register was dropped as well.

This patch ports the alternate solution to emulate the SWP and SWPB
instructions using LDXR/STXR sequences from the arm port to
arm64. The emulation is turned off by default and can be enabled at
runtime using sysctl.

Signed-off-by: Punit Agrawal <punit.agrawal@arm.com>
---
 arch/arm64/Kconfig                   |   39 +++++
 arch/arm64/include/asm/insn.h        |    8 +
 arch/arm64/kernel/Makefile           |    1 +
 arch/arm64/kernel/armv8_deprecated.c |  287 ++++++++++++++++++++++++++++++++++
 arch/arm64/kernel/insn.c             |   13 ++
 5 files changed, 348 insertions(+)
 create mode 100644 arch/arm64/kernel/armv8_deprecated.c

diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index fd4e81a..89262da 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -149,6 +149,45 @@ config ARCH_XGENE
 	help
 	  This enables support for AppliedMicro X-Gene SOC Family
 
+comment "Processor Features"
+
+menuconfig ARMV8_DEPRECATED
+	bool "Emulate deprecated/obsolete ARMv8 instructions"
+	depends on COMPAT
+	help
+	  Legacy software support may require certain instructions
+	  that have been deprecated or obsoleted in the architecture.
+
+	  Enable this config to enable selective emulation of these
+	  features.
+
+	  If unsure, say N
+
+if ARMV8_DEPRECATED
+
+config SWP_EMULATION
+	bool "Emulate SWP/SWPB instructions"
+	help
+	  ARMv8 obsoletes the use of A32 SWP/SWPB instructions such that
+	  they are always undefined. Say Y here to enable software
+	  emulation of these instructions for userspace using LDXR/STXR.
+
+	  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, LDXR/STXR 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 N
+
+endif
+
 endmenu
 
 menu "Bus support"
diff --git a/arch/arm64/include/asm/insn.h b/arch/arm64/include/asm/insn.h
index dc1f73b..c3b7c2f 100644
--- a/arch/arm64/include/asm/insn.h
+++ b/arch/arm64/include/asm/insn.h
@@ -105,6 +105,14 @@ bool aarch64_insn_hotpatch_safe(u32 old_insn, u32 new_insn);
 int aarch64_insn_patch_text_nosync(void *addr, u32 insn);
 int aarch64_insn_patch_text_sync(void *addrs[], u32 insns[], int cnt);
 int aarch64_insn_patch_text(void *addrs[], u32 insns[], int cnt);
+
+bool aarch32_insn_is_wide_instruction(u32 instr);
+
+#define RN_OFFSET	16
+#define RT_OFFSET	12
+#define RT2_OFFSET	 0
+
+u32 aarch32_insn_extract_reg_num(u32 insn, int offset);
 #endif /* __ASSEMBLY__ */
 
 #endif	/* __ASM_INSN_H */
diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile
index e77dd61..39590f3 100644
--- a/arch/arm64/kernel/Makefile
+++ b/arch/arm64/kernel/Makefile
@@ -31,6 +31,7 @@ arm64-obj-$(CONFIG_ARM64_CPU_SUSPEND)	+= sleep.o suspend.o
 arm64-obj-$(CONFIG_JUMP_LABEL)		+= jump_label.o
 arm64-obj-$(CONFIG_KGDB)		+= kgdb.o
 arm64-obj-$(CONFIG_EFI)			+= efi.o efi-stub.o efi-entry.o
+arm64-obj-$(CONFIG_ARMV8_DEPRECATED)	+= armv8_deprecated.o
 
 obj-y					+= $(arm64-obj-y) vdso/
 obj-m					+= $(arm64-obj-m)
diff --git a/arch/arm64/kernel/armv8_deprecated.c b/arch/arm64/kernel/armv8_deprecated.c
new file mode 100644
index 0000000..23fc6f8
--- /dev/null
+++ b/arch/arm64/kernel/armv8_deprecated.c
@@ -0,0 +1,287 @@
+/*
+ *  Copied from arch/arm/kernel/swp_emulate.c and modified for ARMv8
+ *
+ *  Copyright (C) 2009,2012,2014 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.
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/perf_event.h>
+#include <linux/sched.h>
+#include <linux/sysctl.h>
+
+#include <asm/insn.h>
+#include <asm/opcodes.h>
+#include <asm/system_misc.h>
+#include <asm/traps.h>
+#include <asm/uaccess.h>
+
+/*
+ * The runtime support for deprecated instruction support can be in one of
+ * following two states -
+ *
+ * 0 = undef
+ * 1 = emulate (software emulation)
+ */
+#define INSTR_UNDEF (0)
+#define INSTR_EMULATE (1)
+
+/*
+ *  Implement emulation of the SWP/SWPB instructions using load-exclusive and
+ *  store-exclusive.
+ *
+ *  Syntax of SWP{B} instruction: SWP{B}<c> <Rt>, <Rt2>, [<Rn>]
+ *  Where: Rt  = destination
+ *	   Rt2 = source
+ *	   Rn  = address
+ */
+
+/*
+ * SWP defaults to undef as it's been obsoleted in the architecture
+ */
+static int swp_enable = 0;
+static int swp_enable_min = INSTR_UNDEF;
+static int swp_enable_max = INSTR_EMULATE;
+
+/*
+ * Error-checking SWP macros implemented using ldxr{b}/stxr{b}
+ */
+#define __user_swpX_asm(data, addr, res, temp, B)		\
+	__asm__ __volatile__(					\
+	"	mov		%w2, %w1\n"			\
+	"0:	ldxr"B"		%w1, [%3]\n"			\
+	"1:	stxr"B"		%w0, %w2, [%3]\n"		\
+	"	cbz		%w0, 2f\n"			\
+	"	mov		%w0, %w4\n"			\
+	"2:\n"							\
+	"	.pushsection	 .fixup,\"ax\"\n"		\
+	"	.align		2\n"				\
+	"3:	mov		%w0, %w5\n"			\
+	"	b		2b\n"				\
+	"	.popsection"					\
+	"	.pushsection	 __ex_table,\"a\"\n"		\
+	"	.align		3\n"				\
+	"	.quad		0b, 3b\n"			\
+	"	.quad		1b, 3b\n"			\
+	"	.popsection"					\
+	: "=&r" (res), "+r" (data), "=&r" (temp)		\
+	: "r" (addr), "i" (-EAGAIN), "i" (-EFAULT)		\
+	: "memory")
+
+#define __user_swp_asm(data, addr, res, temp) \
+	__user_swpX_asm(data, addr, res, temp, "")
+#define __user_swpb_asm(data, addr, res, temp) \
+	__user_swpX_asm(data, addr, res, temp, "b")
+
+/*
+ * Bit 22 of the instruction encoding distinguishes between
+ * the SWP and SWPB variants (bit set means SWPB).
+ */
+#define TYPE_SWPB (1 << 22)
+
+/*
+ * 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;
+
+	down_read(&current->mm->mmap_sem);
+	if (find_vma(current->mm, addr) == NULL)
+		info.si_code = SEGV_MAPERR;
+	else
+		info.si_code = SEGV_ACCERR;
+	up_read(&current->mm->mmap_sem);
+
+	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");
+	arm64_notify_die("Illegal memory access", regs, &info, 0);
+}
+
+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) {
+		unsigned long temp;
+
+		if (type == TYPE_SWPB)
+			__user_swpb_asm(*data, address, res, temp);
+		else
+			__user_swp_asm(*data, address, res, temp);
+
+		if (likely(res != -EAGAIN) || signal_pending(current))
+			break;
+
+		cond_resched();
+	}
+
+	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, u32 instr)
+{
+	u32 destreg, data, type, address = 0;
+	int rn, rt2, res = 0;
+
+	perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, 1, regs, regs->pc);
+
+	type = instr & TYPE_SWPB;
+
+	switch (arm_check_condition(instr, regs->pstate)) {
+	case ARM_OPCODE_CONDTEST_PASS:
+		break;
+	case ARM_OPCODE_CONDTEST_FAIL:
+		/* Condition failed - return to next instruction */
+		goto ret;
+	case ARM_OPCODE_CONDTEST_UNCOND:
+		/* If unconditional encoding - not a SWP, undef */
+		return -EFAULT;
+	default:
+		return -EINVAL;
+	}
+
+	rn = aarch32_insn_extract_reg_num(instr, RN_OFFSET);
+	rt2 = aarch32_insn_extract_reg_num(instr, RT2_OFFSET);
+
+	address = (u32)regs->user_regs.regs[rn];
+	data	= (u32)regs->user_regs.regs[rt2];
+	destreg = aarch32_insn_extract_reg_num(instr, RT_OFFSET);
+
+	pr_debug("addr in r%d->0x%08x, dest is r%d, source in r%d->0x%08x)\n",
+		rn, address, destreg,
+		aarch32_insn_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 0x%08x not allowed!\n",
+			address);
+		goto fault;
+	}
+
+	res = emulate_swpX(address, &data, type);
+	if (res == -EFAULT)
+		goto fault;
+	else if (res == 0)
+		regs->user_regs.regs[destreg] = data;
+
+ret:
+	pr_warn_ratelimited("\"%s\" (%ld) uses obsolete SWP{B} instruction at 0x%llx\n",
+			current->comm, (unsigned long)current->pid, regs->pc);
+
+	regs->pc += 4;
+	return 0;
+
+fault:
+	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.
+ */
+static struct undef_hook swp_hook = {
+	.instr_mask	= 0x0fb00ff0,
+	.instr_val	= 0x01000090,
+	.pstate_mask	= COMPAT_PSR_MODE_MASK,
+	.pstate_val	= COMPAT_PSR_MODE_USR,
+	.fn		= swp_handler
+};
+
+static void swp_emulation_init(void)
+{
+	if (register_undef_hook(&swp_hook) == 0)
+		pr_notice("Registered SWP/SWPB emulation handler\n");
+}
+
+static void swp_emulation_remove(void)
+{
+	unregister_undef_hook(&swp_hook);
+	pr_notice("Removed SWP/SWPB emulation handler\n");
+}
+
+static void swp_init(void)
+{
+	if (swp_enable)
+		swp_emulation_init();
+}
+
+static int proc_swp_handler(struct ctl_table *table, int write,
+			void __user *buffer, size_t *lenp, loff_t *ppos)
+{
+	u32 prev = swp_enable;
+	int ret = proc_dointvec_minmax(table, write, buffer, lenp, ppos);
+
+	if (ret || !write || prev == swp_enable)
+		return ret;
+
+	switch (swp_enable) {
+	case INSTR_UNDEF: /* Turned off */
+		swp_emulation_remove();
+		break;
+	case INSTR_EMULATE: /* Emulation turned on */
+		swp_emulation_init();
+		break;
+	}
+
+	return 0;
+}
+
+static struct ctl_table ctl_armv8_deprecated[] = {
+	{
+		.procname = "swp_enable",
+		.data = &swp_enable,
+		.maxlen = sizeof(u32),
+		.mode = 0644,
+		.proc_handler = proc_swp_handler,
+		.extra1 = &swp_enable_min,
+		.extra2 = &swp_enable_max,
+	},
+	{ }
+};
+
+static struct ctl_table ctl_abi[] = {
+	{
+		.procname = "abi",
+		.mode = 0555,
+		.child = ctl_armv8_deprecated,
+	},
+	{ }
+};
+
+/*
+ * Invoked as late_initcall, since not needed before init spawned.
+ */
+static int __init armv8_deprecated_init(void)
+{
+	if (IS_ENABLED(CONFIG_SWP_EMULATION))
+		swp_init();
+
+	register_sysctl_table(ctl_abi);
+
+	return 0;
+}
+
+late_initcall(armv8_deprecated_init);
diff --git a/arch/arm64/kernel/insn.c b/arch/arm64/kernel/insn.c
index 92f3683..6e77a54 100644
--- a/arch/arm64/kernel/insn.c
+++ b/arch/arm64/kernel/insn.c
@@ -302,3 +302,16 @@ u32 __kprobes aarch64_insn_gen_nop(void)
 {
 	return aarch64_insn_gen_hint(AARCH64_INSN_HINT_NOP);
 }
+
+bool aarch32_insn_is_wide_instruction(u32 instr)
+{
+	return instr >= 0xe800;
+}
+
+/*
+ * Macros/defines for extracting register numbers from instruction.
+ */
+u32 aarch32_insn_extract_reg_num(u32 insn, int offset)
+{
+	return (insn & (0xf << offset)) >> offset;
+}
-- 
1.7.10.4

^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCHv2 4/5] arm64: Emulate CP15 Barrier instructions
  2014-10-01 13:37 ` [PATCHv2 0/5] Legacy instruction emulation for arm64 Punit Agrawal
                     ` (2 preceding siblings ...)
  2014-10-01 13:37   ` [PATCHv2 3/5] arm64: Port SWP/SWPB emulation support from arm Punit Agrawal
@ 2014-10-01 13:37   ` Punit Agrawal
  2014-10-01 13:37   ` [PATCHv2 5/5] arm64: Trace emulation of AArch32 legacy instructions Punit Agrawal
  2014-10-06 10:22   ` [PATCHv2 0/5] Legacy instruction emulation for arm64 Will Deacon
  5 siblings, 0 replies; 16+ messages in thread
From: Punit Agrawal @ 2014-10-01 13:37 UTC (permalink / raw)
  To: linux-arm-kernel

The CP15 barrier instructions (CP15ISB, CP15DSB and CP15DMB) are
deprecated in the ARMv7 architecture, superseded by ISB, DSB and DMB
instructions respectively. Some implementations may provide the
ability to disable the CP15 barriers by disabling the CP15BEN bit in
SCTLR_EL1. If not enabled, the encodings for these instructions become
undefined.

To support legacy software using these instructions, this patch adds
support to -
* emulate CP15 barriers and warn the user about their use
* toggle CP15BEN in SCTLR_EL1

The choice between using emulation or hardware execution is controlled
via sysctl. To aid migration of software it defaults to emulation.

Signed-off-by: Punit Agrawal <punit.agrawal@arm.com>
---
 arch/arm64/Kconfig                   |   15 +++
 arch/arm64/include/asm/insn.h        |    2 +
 arch/arm64/kernel/armv8_deprecated.c |  189 +++++++++++++++++++++++++++++++++-
 arch/arm64/kernel/insn.c             |   13 +++
 4 files changed, 218 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 89262da..0abaf7b 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -186,6 +186,21 @@ config SWP_EMULATION
 
 	  If unsure, say N
 
+config CP15_BARRIER_EMULATION
+	bool "Emulate CP15 Barrier instructions"
+	help
+	  The CP15 barrier instructions - CP15ISB, CP15DSB, and
+	  CP15DMB - are deprecated in ARMv8 (and ARMv7). It is
+	  strongly recommended to use the ISB, DSB, and DMB
+	  instructions instead.
+
+	  Say Y here to enable software emulation of these
+	  instructions for AArch32 userspace code. When this option is
+	  enabled, CP15 barrier usage is traced which can help
+	  identify software that needs updating.
+
+	  If unsure, say N
+
 endif
 
 endmenu
diff --git a/arch/arm64/include/asm/insn.h b/arch/arm64/include/asm/insn.h
index c3b7c2f..de684fe 100644
--- a/arch/arm64/include/asm/insn.h
+++ b/arch/arm64/include/asm/insn.h
@@ -113,6 +113,8 @@ bool aarch32_insn_is_wide_instruction(u32 instr);
 #define RT2_OFFSET	 0
 
 u32 aarch32_insn_extract_reg_num(u32 insn, int offset);
+u32 aarch32_insn_mcr_extract_opc2(u32 insn);
+u32 aarch32_insn_mcr_extract_crm(u32 insn);
 #endif /* __ASSEMBLY__ */
 
 #endif	/* __ASM_INSN_H */
diff --git a/arch/arm64/kernel/armv8_deprecated.c b/arch/arm64/kernel/armv8_deprecated.c
index 23fc6f8..53a6252 100644
--- a/arch/arm64/kernel/armv8_deprecated.c
+++ b/arch/arm64/kernel/armv8_deprecated.c
@@ -9,6 +9,7 @@
  * published by the Free Software Foundation.
  */
 
+#include <linux/cpu.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/perf_event.h>
@@ -23,13 +24,15 @@
 
 /*
  * The runtime support for deprecated instruction support can be in one of
- * following two states -
+ * following three states -
  *
  * 0 = undef
  * 1 = emulate (software emulation)
+ * 2 = enable (supported in hardware)
  */
 #define INSTR_UNDEF (0)
 #define INSTR_EMULATE (1)
+#define INSTR_ENABLE (2)
 
 /*
  *  Implement emulation of the SWP/SWPB instructions using load-exclusive and
@@ -249,6 +252,178 @@ static int proc_swp_handler(struct ctl_table *table, int write,
 	return 0;
 }
 
+/*
+ * CP15 barriers default to emulate as they have been deprecated in the
+ * architecture.
+ */
+static u32 cp15_barrier_enable = 1;
+static u32 cp15_barrier_enable_min = INSTR_UNDEF;
+static u32 cp15_barrier_enable_max = INSTR_ENABLE;
+
+static int cp15barrier_handler(struct pt_regs *regs, u32 instr)
+{
+	perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, 1, regs, regs->pc);
+
+	switch (arm_check_condition(instr, regs->pstate)) {
+	case ARM_OPCODE_CONDTEST_PASS:
+		break;
+	case ARM_OPCODE_CONDTEST_FAIL:
+		/* Condition failed - return to next instruction */
+		goto ret;
+	case ARM_OPCODE_CONDTEST_UNCOND:
+		/* If unconditional encoding - not a barrier instruction */
+		return -EFAULT;
+	default:
+		return -EINVAL;
+	}
+
+	switch (aarch32_insn_mcr_extract_crm(instr)) {
+	case 10:
+		/*
+		 * dmb - mcr p15, 0, Rt, c7, c10, 5
+		 * dsb - mcr p15, 0, Rt, c7, c10, 4
+		 */
+		if (aarch32_insn_mcr_extract_opc2(instr) == 5)
+			dmb(sy);
+		else
+			dsb(sy);
+		break;
+	case 5:
+		/*
+		 * isb - mcr p15, 0, Rt, c7, c5, 4
+		 */
+		isb();
+		break;
+	}
+
+ret:
+	pr_warn_ratelimited("\"%s\" (%ld) uses deprecated CP15 Barrier instruction at 0x%llx\n",
+			current->comm, (unsigned long)current->pid, regs->pc);
+
+	regs->pc += 4;
+	return 0;
+}
+
+/* data barrier */
+static struct undef_hook cp15db_hook = {
+	.instr_mask	= 0x0fff0fdf,
+	.instr_val	= 0x0e070f9a,
+	.pstate_mask	= COMPAT_PSR_MODE_MASK,
+	.pstate_val	= COMPAT_PSR_MODE_USR,
+	.fn		= cp15barrier_handler,
+};
+
+/* instruction barrier */
+static struct undef_hook cp15isb_hook = {
+	.instr_mask	= 0x0fff0fff,
+	.instr_val	= 0x0e070f95,
+	.pstate_mask	= COMPAT_PSR_MODE_MASK,
+	.pstate_val	= COMPAT_PSR_MODE_USR,
+	.fn		= cp15barrier_handler,
+};
+
+static void cp15_barrier_emulation_init(void)
+{
+	if (register_undef_hook(&cp15db_hook) == 0 &&
+		register_undef_hook(&cp15isb_hook) == 0)
+		pr_notice("Registered CP15 Barrier emulation handler\n");
+}
+
+static void cp15_barrier_emulation_remove(void)
+{
+	unregister_undef_hook(&cp15db_hook);
+	unregister_undef_hook(&cp15isb_hook);
+
+	pr_notice("Removed CP15 Barrier emulation handler\n");
+}
+
+#define SCTLR_EL1_CP15BEN (1 << 5)
+
+static inline void config_sctlr_el1(u32 clear, u32 set)
+{
+	u32 val;
+
+	asm volatile("mrs %0, sctlr_el1" : "=r" (val));
+	val &= ~clear;
+	val |= set;
+	asm volatile("msr sctlr_el1, %0" : : "r" (val));
+}
+
+static void enable_cp15_ben(void *info)
+{
+	config_sctlr_el1(0, SCTLR_EL1_CP15BEN);
+}
+
+static void disable_cp15_ben(void *info)
+{
+	config_sctlr_el1(SCTLR_EL1_CP15BEN, 0);
+}
+
+static int cpu_hotplug_notify(struct notifier_block *b, unsigned long action,
+			  void *hcpu)
+{
+	switch (action) {
+	case CPU_STARTING:
+		enable_cp15_ben(NULL);
+		return NOTIFY_DONE;
+	}
+
+	return NOTIFY_OK;
+}
+
+static struct notifier_block cpu_hotplug_notifier = {
+	.notifier_call = cpu_hotplug_notify,
+};
+
+static void cp15_barrier_init(void)
+{
+	switch (cp15_barrier_enable) {
+	case INSTR_UNDEF: /* turned off, nothing to do */
+		break;
+	case INSTR_EMULATE: /* register emulation hooks */
+		cp15_barrier_emulation_init();
+		break;
+	case INSTR_ENABLE: /* Set CP15BEN in SCTLR_EL1 */
+		register_cpu_notifier(&cpu_hotplug_notifier);
+		on_each_cpu(enable_cp15_ben, NULL, true);
+		break;
+	}
+}
+
+static void cp15_barrier_remove(u32 deprecated_feature_state)
+{
+	/* Disable current handling */
+	switch (deprecated_feature_state) {
+	case INSTR_UNDEF: /* already off, do nothing */
+		break;
+	case INSTR_EMULATE: /* unregister emulation hooks */
+		cp15_barrier_emulation_remove();
+		break;
+	case INSTR_ENABLE: /* Clear CP15BEN in SCTLR_EL1 */
+		unregister_cpu_notifier(&cpu_hotplug_notifier);
+		on_each_cpu(disable_cp15_ben, NULL, true);
+		break;
+	}
+}
+
+static int proc_cp15_barrier_handler(struct ctl_table *table, int write,
+		void __user *buffer, size_t *lenp, loff_t *ppos)
+{
+	u32 prev = cp15_barrier_enable;
+	int ret = proc_dointvec_minmax(table, write, buffer, lenp, ppos);
+
+	if (ret || !write || prev == cp15_barrier_enable)
+		return ret;
+
+	/* disable previous mechanism */
+	cp15_barrier_remove(prev);
+
+	/* Install new mechanism */
+	cp15_barrier_init();
+
+	return ret;
+}
+
 static struct ctl_table ctl_armv8_deprecated[] = {
 	{
 		.procname = "swp_enable",
@@ -259,6 +434,15 @@ static struct ctl_table ctl_armv8_deprecated[] = {
 		.extra1 = &swp_enable_min,
 		.extra2 = &swp_enable_max,
 	},
+	{
+		.procname = "cp15_barrier_enable",
+		.data = &cp15_barrier_enable,
+		.maxlen = sizeof(u32),
+		.mode = 0644,
+		.proc_handler = proc_cp15_barrier_handler,
+		.extra1 = &cp15_barrier_enable_min,
+		.extra2 = &cp15_barrier_enable_max,
+	},
 	{ }
 };
 
@@ -279,6 +463,9 @@ static int __init armv8_deprecated_init(void)
 	if (IS_ENABLED(CONFIG_SWP_EMULATION))
 		swp_init();
 
+	if (IS_ENABLED(CONFIG_CP15_BARRIER_EMULATION))
+		cp15_barrier_init();
+
 	register_sysctl_table(ctl_abi);
 
 	return 0;
diff --git a/arch/arm64/kernel/insn.c b/arch/arm64/kernel/insn.c
index 6e77a54..b01b8e4 100644
--- a/arch/arm64/kernel/insn.c
+++ b/arch/arm64/kernel/insn.c
@@ -315,3 +315,16 @@ u32 aarch32_insn_extract_reg_num(u32 insn, int offset)
 {
 	return (insn & (0xf << offset)) >> offset;
 }
+
+#define OPC2_MASK	0x7
+#define OPC2_OFFSET	5
+u32 aarch32_insn_mcr_extract_opc2(u32 insn)
+{
+	return (insn & (OPC2_MASK << OPC2_OFFSET)) >> OPC2_OFFSET;
+}
+
+#define CRM_MASK	0xf
+u32 aarch32_insn_mcr_extract_crm(u32 insn)
+{
+	return insn & CRM_MASK;
+}
-- 
1.7.10.4

^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCHv2 5/5] arm64: Trace emulation of AArch32 legacy instructions
  2014-10-01 13:37 ` [PATCHv2 0/5] Legacy instruction emulation for arm64 Punit Agrawal
                     ` (3 preceding siblings ...)
  2014-10-01 13:37   ` [PATCHv2 4/5] arm64: Emulate CP15 Barrier instructions Punit Agrawal
@ 2014-10-01 13:37   ` Punit Agrawal
  2014-10-06 10:22   ` [PATCHv2 0/5] Legacy instruction emulation for arm64 Will Deacon
  5 siblings, 0 replies; 16+ messages in thread
From: Punit Agrawal @ 2014-10-01 13:37 UTC (permalink / raw)
  To: linux-arm-kernel

Introduce an event to trace the usage of emulated instructions. The
trace event is intended to help identify and encourage the migration
of legacy software using the emulation features.

Use this event to trace usage of swp and CP15 barrier emulation.

Cc: Steven Rostedt <rostedt@goodmis.org>
Signed-off-by: Punit Agrawal <punit.agrawal@arm.com>
---
 arch/arm64/kernel/armv8_deprecated.c |   19 ++++++++++++++++--
 include/trace/events/emulation.h     |   35 ++++++++++++++++++++++++++++++++++
 2 files changed, 52 insertions(+), 2 deletions(-)
 create mode 100644 include/trace/events/emulation.h

diff --git a/arch/arm64/kernel/armv8_deprecated.c b/arch/arm64/kernel/armv8_deprecated.c
index 53a6252..1726b3f 100644
--- a/arch/arm64/kernel/armv8_deprecated.c
+++ b/arch/arm64/kernel/armv8_deprecated.c
@@ -16,6 +16,9 @@
 #include <linux/sched.h>
 #include <linux/sysctl.h>
 
+#define CREATE_TRACE_POINTS
+#include <trace/events/emulation.h>
+
 #include <asm/insn.h>
 #include <asm/opcodes.h>
 #include <asm/system_misc.h>
@@ -189,6 +192,11 @@ static int swp_handler(struct pt_regs *regs, u32 instr)
 		regs->user_regs.regs[destreg] = data;
 
 ret:
+	if (type == TYPE_SWPB)
+		trace_instruction_emulation("swpb", regs->pc);
+	else
+		trace_instruction_emulation("swp", regs->pc);
+
 	pr_warn_ratelimited("\"%s\" (%ld) uses obsolete SWP{B} instruction at 0x%llx\n",
 			current->comm, (unsigned long)current->pid, regs->pc);
 
@@ -283,16 +291,23 @@ static int cp15barrier_handler(struct pt_regs *regs, u32 instr)
 		 * dmb - mcr p15, 0, Rt, c7, c10, 5
 		 * dsb - mcr p15, 0, Rt, c7, c10, 4
 		 */
-		if (aarch32_insn_mcr_extract_opc2(instr) == 5)
+		if (aarch32_insn_mcr_extract_opc2(instr) == 5) {
 			dmb(sy);
-		else
+			trace_instruction_emulation(
+				"mcr p15, 0, Rt, c7, c10, 5", regs->pc);
+		} else {
 			dsb(sy);
+			trace_instruction_emulation(
+				"mcr p15, 0, Rt, c7, c10, 4", regs->pc);
+		}
 		break;
 	case 5:
 		/*
 		 * isb - mcr p15, 0, Rt, c7, c5, 4
 		 */
 		isb();
+		trace_instruction_emulation(
+			"mcr p15, 0, Rt, c7, c5, 4", regs->pc);
 		break;
 	}
 
diff --git a/include/trace/events/emulation.h b/include/trace/events/emulation.h
new file mode 100644
index 0000000..e77726a
--- /dev/null
+++ b/include/trace/events/emulation.h
@@ -0,0 +1,35 @@
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM emulation
+
+#if !defined(_TRACE_EMULATION_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_EMULATION_H
+
+#include <linux/tracepoint.h>
+
+TRACE_EVENT(instruction_emulation,
+
+	TP_PROTO(const char *instr, u64 addr),
+	TP_ARGS(instr, addr),
+
+	TP_STRUCT__entry(
+		__array(char, comm, TASK_COMM_LEN)
+		__field(pid_t, pid)
+		__string(instr, instr)
+		__field(u64, addr)
+	),
+
+	TP_fast_assign(
+		memcpy(__entry->comm, current->comm, TASK_COMM_LEN);
+		__entry->pid = current->pid;
+		__assign_str(instr, instr);
+		__entry->addr = addr;
+	),
+
+	TP_printk("instr=%s comm=%s pid=%d addr=0x%llx", __get_str(instr),
+		__entry->comm, __entry->pid, __entry->addr)
+);
+
+#endif /* _TRACE_EMULATION_H */
+
+/* This part must be outside protection */
+#include <trace/define_trace.h>
-- 
1.7.10.4

^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCHv2 5/5] arm64: Trace emulation of AArch32 legacy instructions
  2014-10-01 12:07 ` [PATCHv2 5/5] arm64: Trace emulation of AArch32 legacy instructions Punit Agrawal
@ 2014-10-01 14:40   ` Steven Rostedt
  2014-10-14 16:18     ` Punit Agrawal
  0 siblings, 1 reply; 16+ messages in thread
From: Steven Rostedt @ 2014-10-01 14:40 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed,  1 Oct 2014 13:07:59 +0100
Punit Agrawal <punit.agrawal@arm.com> wrote:

> Introduce an event to trace the usage of emulated instructions. The
> trace event is intended to help identify and encourage the migration
> of legacy software using the emulation features.
> 
> Use this event to trace usage of swp and CP15 barrier emulation.

Do you expect this to be a generic tracepoint? Something any arch can
use, and more importantly, will use?

If not, please keep this tracepoint in the arch/arm64 directories. The
sample code in samples/trace_events/ explains how to do this.

Thanks,

-- Steve

^ permalink raw reply	[flat|nested] 16+ messages in thread

* [PATCHv2 0/5] Legacy instruction emulation for arm64
  2014-10-01 13:37 ` [PATCHv2 0/5] Legacy instruction emulation for arm64 Punit Agrawal
                     ` (4 preceding siblings ...)
  2014-10-01 13:37   ` [PATCHv2 5/5] arm64: Trace emulation of AArch32 legacy instructions Punit Agrawal
@ 2014-10-06 10:22   ` Will Deacon
  5 siblings, 0 replies; 16+ messages in thread
From: Will Deacon @ 2014-10-06 10:22 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Oct 01, 2014 at 02:37:05PM +0100, Punit Agrawal wrote:
> [ Correcting Arnd's email. Apologies for the extra copy ]
> 
> Hi,

Hi Punit,

> This is the second posting of the legacy instruction support for
> arm64. The previous posting can be found at [1].
> 
> The patchset ports the infrastructure to register hooks for undefined
> instruction abort and uses this to adds support for the emulation of
> SWP{B} and CP15 Barrier instructions from ARMv7 to the v8 port of
> Linux.
> 
> Via sysctl, it is possible to control the runtime state of emulation
> * Off
>   sysctl value: 0
>   Generates undefined instruction abort. Default for instructions that
>   have been obsoleted in the architecture, e.g., SWP
> 
> * Emulate
>   sysctl value: 1
>   Uses software emulation. To aid migration of software, in this mode
>   usage of emulated instruction is traced as well as rate limited
>   warnings are issued. This is the default for deprecated
>   instructions, .e.g., CP15 barriers
> 
> * Enable
>   sysctl value: 2
>   Although marked as deprecated, some implementations may support the
>   enabling/disabling of hardware support for the execution of these
>   instructions. Using hardware execution generally provides better
>   performance, but at the loss of ability to gather runtime statistics
>   about the use of the deprecated instructions.

This needs to be documented in Documentation/arm64/ so that people can
easily understand how to control the emulations that we have, what they
default to and why that is the case.

Will

^ permalink raw reply	[flat|nested] 16+ messages in thread

* [PATCHv2 3/5] arm64: Port SWP/SWPB emulation support from arm
  2014-10-01 13:37   ` [PATCHv2 3/5] arm64: Port SWP/SWPB emulation support from arm Punit Agrawal
@ 2014-10-06 10:52     ` Will Deacon
  0 siblings, 0 replies; 16+ messages in thread
From: Will Deacon @ 2014-10-06 10:52 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Oct 01, 2014 at 02:37:08PM +0100, Punit Agrawal wrote:
> 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. With ARMv8, the option to enable these instructions
> through System Control Register was dropped as well.
> 
> This patch ports the alternate solution to emulate the SWP and SWPB
> instructions using LDXR/STXR sequences from the arm port to
> arm64. The emulation is turned off by default and can be enabled at
> runtime using sysctl.

[...]

> diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
> index fd4e81a..89262da 100644
> --- a/arch/arm64/Kconfig
> +++ b/arch/arm64/Kconfig
> @@ -149,6 +149,45 @@ config ARCH_XGENE
>  	help
>  	  This enables support for AppliedMicro X-Gene SOC Family
>  
> +comment "Processor Features"
> +
> +menuconfig ARMV8_DEPRECATED
> +	bool "Emulate deprecated/obsolete ARMv8 instructions"
> +	depends on COMPAT
> +	help
> +	  Legacy software support may require certain instructions
> +	  that have been deprecated or obsoleted in the architecture.
> +
> +	  Enable this config to enable selective emulation of these
> +	  features.
> +
> +	  If unsure, say N
> +
> +if ARMV8_DEPRECATED
> +
> +config SWP_EMULATION
> +	bool "Emulate SWP/SWPB instructions"
> +	help
> +	  ARMv8 obsoletes the use of A32 SWP/SWPB instructions such that
> +	  they are always undefined. Say Y here to enable software
> +	  emulation of these instructions for userspace using LDXR/STXR.
> +
> +	  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, LDXR/STXR 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 N
> +
> +endif
> +
>  endmenu
>  
>  menu "Bus support"
> diff --git a/arch/arm64/include/asm/insn.h b/arch/arm64/include/asm/insn.h
> index dc1f73b..c3b7c2f 100644
> --- a/arch/arm64/include/asm/insn.h
> +++ b/arch/arm64/include/asm/insn.h
> @@ -105,6 +105,14 @@ bool aarch64_insn_hotpatch_safe(u32 old_insn, u32 new_insn);
>  int aarch64_insn_patch_text_nosync(void *addr, u32 insn);
>  int aarch64_insn_patch_text_sync(void *addrs[], u32 insns[], int cnt);
>  int aarch64_insn_patch_text(void *addrs[], u32 insns[], int cnt);
> +
> +bool aarch32_insn_is_wide_instruction(u32 instr);
> +
> +#define RN_OFFSET	16
> +#define RT_OFFSET	12
> +#define RT2_OFFSET	 0

We should prefix these with A32_ or similar.

> +u32 aarch32_insn_extract_reg_num(u32 insn, int offset);
>  #endif /* __ASSEMBLY__ */
>  
>  #endif	/* __ASM_INSN_H */
> diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile
> index e77dd61..39590f3 100644
> --- a/arch/arm64/kernel/Makefile
> +++ b/arch/arm64/kernel/Makefile
> @@ -31,6 +31,7 @@ arm64-obj-$(CONFIG_ARM64_CPU_SUSPEND)	+= sleep.o suspend.o
>  arm64-obj-$(CONFIG_JUMP_LABEL)		+= jump_label.o
>  arm64-obj-$(CONFIG_KGDB)		+= kgdb.o
>  arm64-obj-$(CONFIG_EFI)			+= efi.o efi-stub.o efi-entry.o
> +arm64-obj-$(CONFIG_ARMV8_DEPRECATED)	+= armv8_deprecated.o
>  
>  obj-y					+= $(arm64-obj-y) vdso/
>  obj-m					+= $(arm64-obj-m)
> diff --git a/arch/arm64/kernel/armv8_deprecated.c b/arch/arm64/kernel/armv8_deprecated.c
> new file mode 100644
> index 0000000..23fc6f8
> --- /dev/null
> +++ b/arch/arm64/kernel/armv8_deprecated.c
> @@ -0,0 +1,287 @@
> +/*
> + *  Copied from arch/arm/kernel/swp_emulate.c and modified for ARMv8
> + *
> + *  Copyright (C) 2009,2012,2014 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.
> + */
> +
> +#include <linux/init.h>
> +#include <linux/kernel.h>
> +#include <linux/perf_event.h>
> +#include <linux/sched.h>
> +#include <linux/sysctl.h>
> +
> +#include <asm/insn.h>
> +#include <asm/opcodes.h>
> +#include <asm/system_misc.h>
> +#include <asm/traps.h>
> +#include <asm/uaccess.h>
> +
> +/*
> + * The runtime support for deprecated instruction support can be in one of
> + * following two states -
> + *
> + * 0 = undef
> + * 1 = emulate (software emulation)
> + */
> +#define INSTR_UNDEF (0)
> +#define INSTR_EMULATE (1)

You don't need these brackets, but I think this is better off as an enum
anyway.

> +
> +/*
> + *  Implement emulation of the SWP/SWPB instructions using load-exclusive and
> + *  store-exclusive.
> + *
> + *  Syntax of SWP{B} instruction: SWP{B}<c> <Rt>, <Rt2>, [<Rn>]
> + *  Where: Rt  = destination
> + *	   Rt2 = source
> + *	   Rn  = address
> + */
> +
> +/*
> + * SWP defaults to undef as it's been obsoleted in the architecture
> + */
> +static int swp_enable = 0;
> +static int swp_enable_min = INSTR_UNDEF;
> +static int swp_enable_max = INSTR_EMULATE;

Since we're going to be adding other emulations that need similar code,
perhaps it would be better to have a way to register an emulation?

E.g. something like:

enum insn_emulation_type {
	INSN_UNDEF,
	INSN_EMULATE,
	INSN_HW,
};

enum legacy_insn_status {
	INSN_DEPRECATED,
	INSN_OPTIONAL,
	INSN_OBSOLETE,
};

struct insn_emulation_ops {
	const char		*name;
	enum legacy_insn_type	status;
	struct undef_hook	hook;
	int			(*set_emulation_type)(enum insn_emulation_type type);
};

That way, we can move all the default behaviour handling, proc/sys
munging and undef hook handling into a single place.

Will

^ permalink raw reply	[flat|nested] 16+ messages in thread

* [PATCHv2 5/5] arm64: Trace emulation of AArch32 legacy instructions
  2014-10-01 14:40   ` Steven Rostedt
@ 2014-10-14 16:18     ` Punit Agrawal
  0 siblings, 0 replies; 16+ messages in thread
From: Punit Agrawal @ 2014-10-14 16:18 UTC (permalink / raw)
  To: linux-arm-kernel

[ Correcting Arnd's email address ]

Hi Steve,

Thanks for having a look.

Steven Rostedt <rostedt@goodmis.org> writes:

> On Wed,  1 Oct 2014 13:07:59 +0100
> Punit Agrawal <punit.agrawal@arm.com> wrote:
>
>> Introduce an event to trace the usage of emulated instructions. The
>> trace event is intended to help identify and encourage the migration
>> of legacy software using the emulation features.
>> 
>> Use this event to trace usage of swp and CP15 barrier emulation.
>
> Do you expect this to be a generic tracepoint? Something any arch can
> use, and more importantly, will use?

The intention was to create a generic event to trace instruction
emulation irrespective of the architecture but at the moment the only
user will be arm64.

Whether other architectures start using it... I am not sure.

>
> If not, please keep this tracepoint in the arch/arm64 directories. The
> sample code in samples/trace_events/ explains how to do this.

I'll move this to arm64 in the next version.

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

^ permalink raw reply	[flat|nested] 16+ messages in thread

end of thread, other threads:[~2014-10-14 16:18 UTC | newest]

Thread overview: 16+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-10-01 12:07 [PATCHv2 0/5] Legacy instruction emulation for arm64 Punit Agrawal
2014-10-01 12:07 ` [PATCHv2 1/5] arm64: Add support for hooks to handle undefined instructions Punit Agrawal
2014-10-01 12:07 ` [PATCHv2 2/5] arm64: Add AArch32 instruction set condition code checks Punit Agrawal
2014-10-01 12:07 ` [PATCHv2 3/5] arm64: Port SWP/SWPB emulation support from arm Punit Agrawal
2014-10-01 12:07 ` [PATCHv2 4/5] arm64: Emulate CP15 Barrier instructions Punit Agrawal
2014-10-01 12:07 ` [PATCHv2 5/5] arm64: Trace emulation of AArch32 legacy instructions Punit Agrawal
2014-10-01 14:40   ` Steven Rostedt
2014-10-14 16:18     ` Punit Agrawal
2014-10-01 13:37 ` [PATCHv2 0/5] Legacy instruction emulation for arm64 Punit Agrawal
2014-10-01 13:37   ` [PATCHv2 1/5] arm64: Add support for hooks to handle undefined instructions Punit Agrawal
2014-10-01 13:37   ` [PATCHv2 2/5] arm64: Add AArch32 instruction set condition code checks Punit Agrawal
2014-10-01 13:37   ` [PATCHv2 3/5] arm64: Port SWP/SWPB emulation support from arm Punit Agrawal
2014-10-06 10:52     ` Will Deacon
2014-10-01 13:37   ` [PATCHv2 4/5] arm64: Emulate CP15 Barrier instructions Punit Agrawal
2014-10-01 13:37   ` [PATCHv2 5/5] arm64: Trace emulation of AArch32 legacy instructions Punit Agrawal
2014-10-06 10:22   ` [PATCHv2 0/5] Legacy instruction emulation for arm64 Will Deacon

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).