All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/2] Support deprecated SETEND instruction for AArch32
@ 2015-01-07 16:16 ` Suzuki K. Poulose
  0 siblings, 0 replies; 12+ messages in thread
From: Suzuki K. Poulose @ 2015-01-07 16:16 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: leo.yan, yexl, will.deacon, mark.rultand, catalin.marinas,
	linux-kernel, Suzuki K. Poulose

From: "Suzuki K. Poulose" <suzuki.poulose@arm.com>

This series add support for controlling the 'setend' instruction,
which is deprecated in ARMv8, using the legacy instruction emulation
framework, introduced by Punit Agrawal.

Patch 1 re-organises the infrastructure a little bit to avoid multiple
CPU hotplug notifiers.

Patch 2 adds the support for SETEND.

Testing :

 $ cat setend_sig.c 
 #include <stdio.h>
 #include <signal.h>

 #define setend_be(a)	asm __volatile__ ( "setend be" ::: "memory" )
 #define setend_le(a)	asm __volatile__ ( "setend le" ::: "memory" )

 volatile int flag = 1;

 void sigint(int sig)
 {
	printf("in sighandler %d\n", sig);
	flag = 0;
	return;
 }

 main()
 {
	volatile int a = 0x0;

	(void)signal(SIGINT, sigint);
	printf("Press Ctrl+C to continue\n");
	setend_be();
	a ++;

	while (flag);

	setend_le();
	a ++;

	printf("a: 0x%x\n", a);
	return 0;
 }
 $ cat /proc/sys/abi/setend 
 1
 $ echo 1 > /sys/kernel/debug/tracing/events/emulation/instruction_emulation/enable 
 $ echo 1 > /sys/kernel/debug/tracing/tracing_on 
 $ ./setend_sig_a32 
 Press Ctrl+C to continue
 ^Cin sighandler 2
 a: 0x1000001
 $ cat /sys/kernel/debug/tracing/trace
 # tracer: nop
 #
 # entries-in-buffer/entries-written: 2/2   #P:2
 #
 #                              _-----=> irqs-off
 #                             / _----=> need-resched
 #                            | / _---=> hardirq/softirq
 #                            || / _--=> preempt-depth
 #                            ||| /     delay
 #           TASK-PID   CPU#  ||||    TIMESTAMP  FUNCTION
 #              | |       |   ||||       |         |
   setend_sig_a32-1373  [000] ...1   491.554499: instruction_emulation: instr="setend be" addr=0x8460
   setend_sig_a32-1373  [000] ...1   492.833056: instruction_emulation: instr="setend le" addr=0x8488
 $ dmesg | tail
 [  491.554807] "setend_sig_a32" (1373) uses deprecated setend instruction at 0x8460
 [  492.833285] "setend_sig_a32" (1373) uses deprecated setend instruction at 0x8488
 $ echo 2 > /proc/sys/abi/setend
 $ ./setend_sig_t16 
 Press Ctrl+C to continue
 ^Cin sighandler 2
 a: 0x1000001
 $ dmesg | tail
 [  491.554807] "setend_sig_a32" (1373) uses deprecated setend instruction at 0x8460
 [  492.833285] "setend_sig_a32" (1373) uses deprecated setend instruction at 0x8488
 [  537.426216] Removed setend emulation handler
 [  537.426624] Enabled setend support
 ---

Suzuki K. Poulose (2):
  arm64: Consolidate hotplug notifier for instruction emulation
  arm64: Emulate SETEND for AArch32 tasks

 Documentation/arm64/legacy_instructions.txt |    5 +
 arch/arm64/Kconfig                          |   10 ++
 arch/arm64/include/asm/ptrace.h             |    7 ++
 arch/arm64/kernel/armv8_deprecated.c        |  174 +++++++++++++++++++--------
 arch/arm64/kernel/signal32.c                |    5 +-
 5 files changed, 151 insertions(+), 50 deletions(-)

-- 
1.7.9.5



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

* [PATCH 0/2] Support deprecated SETEND instruction for AArch32
@ 2015-01-07 16:16 ` Suzuki K. Poulose
  0 siblings, 0 replies; 12+ messages in thread
From: Suzuki K. Poulose @ 2015-01-07 16:16 UTC (permalink / raw)
  To: linux-arm-kernel

From: "Suzuki K. Poulose" <suzuki.poulose@arm.com>

This series add support for controlling the 'setend' instruction,
which is deprecated in ARMv8, using the legacy instruction emulation
framework, introduced by Punit Agrawal.

Patch 1 re-organises the infrastructure a little bit to avoid multiple
CPU hotplug notifiers.

Patch 2 adds the support for SETEND.

Testing :

 $ cat setend_sig.c 
 #include <stdio.h>
 #include <signal.h>

 #define setend_be(a)	asm __volatile__ ( "setend be" ::: "memory" )
 #define setend_le(a)	asm __volatile__ ( "setend le" ::: "memory" )

 volatile int flag = 1;

 void sigint(int sig)
 {
	printf("in sighandler %d\n", sig);
	flag = 0;
	return;
 }

 main()
 {
	volatile int a = 0x0;

	(void)signal(SIGINT, sigint);
	printf("Press Ctrl+C to continue\n");
	setend_be();
	a ++;

	while (flag);

	setend_le();
	a ++;

	printf("a: 0x%x\n", a);
	return 0;
 }
 $ cat /proc/sys/abi/setend 
 1
 $ echo 1 > /sys/kernel/debug/tracing/events/emulation/instruction_emulation/enable 
 $ echo 1 > /sys/kernel/debug/tracing/tracing_on 
 $ ./setend_sig_a32 
 Press Ctrl+C to continue
 ^Cin sighandler 2
 a: 0x1000001
 $ cat /sys/kernel/debug/tracing/trace
 # tracer: nop
 #
 # entries-in-buffer/entries-written: 2/2   #P:2
 #
 #                              _-----=> irqs-off
 #                             / _----=> need-resched
 #                            | / _---=> hardirq/softirq
 #                            || / _--=> preempt-depth
 #                            ||| /     delay
 #           TASK-PID   CPU#  ||||    TIMESTAMP  FUNCTION
 #              | |       |   ||||       |         |
   setend_sig_a32-1373  [000] ...1   491.554499: instruction_emulation: instr="setend be" addr=0x8460
   setend_sig_a32-1373  [000] ...1   492.833056: instruction_emulation: instr="setend le" addr=0x8488
 $ dmesg | tail
 [  491.554807] "setend_sig_a32" (1373) uses deprecated setend instruction at 0x8460
 [  492.833285] "setend_sig_a32" (1373) uses deprecated setend instruction at 0x8488
 $ echo 2 > /proc/sys/abi/setend
 $ ./setend_sig_t16 
 Press Ctrl+C to continue
 ^Cin sighandler 2
 a: 0x1000001
 $ dmesg | tail
 [  491.554807] "setend_sig_a32" (1373) uses deprecated setend instruction at 0x8460
 [  492.833285] "setend_sig_a32" (1373) uses deprecated setend instruction at 0x8488
 [  537.426216] Removed setend emulation handler
 [  537.426624] Enabled setend support
 ---

Suzuki K. Poulose (2):
  arm64: Consolidate hotplug notifier for instruction emulation
  arm64: Emulate SETEND for AArch32 tasks

 Documentation/arm64/legacy_instructions.txt |    5 +
 arch/arm64/Kconfig                          |   10 ++
 arch/arm64/include/asm/ptrace.h             |    7 ++
 arch/arm64/kernel/armv8_deprecated.c        |  174 +++++++++++++++++++--------
 arch/arm64/kernel/signal32.c                |    5 +-
 5 files changed, 151 insertions(+), 50 deletions(-)

-- 
1.7.9.5

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

* [PATCH 1/2] arm64: Consolidate hotplug notifier for instruction emulation
  2015-01-07 16:16 ` Suzuki K. Poulose
@ 2015-01-07 16:16   ` Suzuki K. Poulose
  -1 siblings, 0 replies; 12+ messages in thread
From: Suzuki K. Poulose @ 2015-01-07 16:16 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: leo.yan, yexl, will.deacon, mark.rultand, catalin.marinas,
	linux-kernel, Suzuki K. Poulose, Mark Rutland

From: "Suzuki K. Poulose" <suzuki.poulose@arm.com>

As of now each insn_emulation has a cpu hotplug notifier that
enables/disables the CPU feature bit for the functionality. This
patch re-arranges the code, such that there is only one notifier
that runs through the list of registered emulation hooks and runs
their corresponding set_hw_mode.

We do nothing when a CPU is dying as we will set the appropriate bits
when it comes back online based on the state of the hooks.

Signed-off-by: Suzuki K. Poulose <suzuki.poulose@arm.com>
Signed-off-by: Mark Rutland <mark.rutland@arm.com>
---
 arch/arm64/kernel/armv8_deprecated.c |   99 +++++++++++++++++-----------------
 1 file changed, 50 insertions(+), 49 deletions(-)

diff --git a/arch/arm64/kernel/armv8_deprecated.c b/arch/arm64/kernel/armv8_deprecated.c
index c363671..9054447 100644
--- a/arch/arm64/kernel/armv8_deprecated.c
+++ b/arch/arm64/kernel/armv8_deprecated.c
@@ -46,7 +46,7 @@ struct insn_emulation_ops {
 	const char		*name;
 	enum legacy_insn_status	status;
 	struct undef_hook	*hooks;
-	int			(*set_hw_mode)(bool enable);
+	void			(*set_hw_mode)(void *enable);
 };
 
 struct insn_emulation {
@@ -85,6 +85,30 @@ static void remove_emulation_hooks(struct insn_emulation_ops *ops)
 	pr_notice("Removed %s emulation handler\n", ops->name);
 }
 
+/* Run set_hw_mode(action) on all active CPUs */
+static int run_all_cpu_set_hw_mode(struct insn_emulation *insn, bool action)
+{
+	if (!insn->ops->set_hw_mode)
+		return -EINVAL;
+	on_each_cpu(insn->ops->set_hw_mode, (void *)action, true);
+	return 0;
+}
+
+/* Run set_hw_mode for all insns on a starting CPU */
+static void run_all_insn_set_hw_mode(void)
+{
+	unsigned long flags;
+	struct insn_emulation *insn;
+
+	raw_spin_lock_irqsave(&insn_emulation_lock, flags);
+	list_for_each_entry(insn, &insn_emulation, node) {
+		bool hw_mode = (insn->current_mode == INSN_HW);
+		if (insn->ops->set_hw_mode)
+			insn->ops->set_hw_mode((void *)hw_mode);
+	}
+	raw_spin_unlock_irqrestore(&insn_emulation_lock, flags);
+}
+
 static int update_insn_emulation_mode(struct insn_emulation *insn,
 				       enum insn_emulation_mode prev)
 {
@@ -97,10 +121,8 @@ static int update_insn_emulation_mode(struct insn_emulation *insn,
 		remove_emulation_hooks(insn->ops);
 		break;
 	case INSN_HW:
-		if (insn->ops->set_hw_mode) {
-			insn->ops->set_hw_mode(false);
+		if (!run_all_cpu_set_hw_mode(insn, false))
 			pr_notice("Disabled %s support\n", insn->ops->name);
-		}
 		break;
 	}
 
@@ -111,10 +133,9 @@ static int update_insn_emulation_mode(struct insn_emulation *insn,
 		register_emulation_hooks(insn->ops);
 		break;
 	case INSN_HW:
-		if (insn->ops->set_hw_mode && insn->ops->set_hw_mode(true))
+		ret = run_all_cpu_set_hw_mode(insn, true);
+		if (!ret)
 			pr_notice("Enabled %s support\n", insn->ops->name);
-		else
-			ret = -EINVAL;
 		break;
 	}
 
@@ -133,6 +154,8 @@ static void register_insn_emulation(struct insn_emulation_ops *ops)
 	switch (ops->status) {
 	case INSN_DEPRECATED:
 		insn->current_mode = INSN_EMULATE;
+		/* Disable the HW mode if it was turned on at early boot time */
+		run_all_cpu_set_hw_mode(insn, false);
 		insn->max = INSN_HW;
 		break;
 	case INSN_OBSOLETE:
@@ -453,7 +476,7 @@ ret:
 	return 0;
 }
 
-#define SCTLR_EL1_CP15BEN (1 << 5)
+#define SCTLR_EL1_CP15BEN 	(1 << 5)
 
 static inline void config_sctlr_el1(u32 clear, u32 set)
 {
@@ -465,48 +488,12 @@ static inline void config_sctlr_el1(u32 clear, u32 set)
 	asm volatile("msr sctlr_el1, %0" : : "r" (val));
 }
 
-static void enable_cp15_ben(void *info)
+static void cp15_barrier_set_hw_mode(void *enable)
 {
-	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:
-	case CPU_STARTING_FROZEN:
-		enable_cp15_ben(NULL);
-		return NOTIFY_DONE;
-	case CPU_DYING:
-	case CPU_DYING_FROZEN:
-		disable_cp15_ben(NULL);
-		return NOTIFY_DONE;
-	}
-
-	return NOTIFY_OK;
-}
-
-static struct notifier_block cpu_hotplug_notifier = {
-	.notifier_call = cpu_hotplug_notify,
-};
-
-static int cp15_barrier_set_hw_mode(bool enable)
-{
-	if (enable) {
-		register_cpu_notifier(&cpu_hotplug_notifier);
-		on_each_cpu(enable_cp15_ben, NULL, true);
-	} else {
-		unregister_cpu_notifier(&cpu_hotplug_notifier);
-		on_each_cpu(disable_cp15_ben, NULL, true);
-	}
-
-	return true;
+	if (enable)
+		config_sctlr_el1(0, SCTLR_EL1_CP15BEN);
+	else
+		config_sctlr_el1(SCTLR_EL1_CP15BEN, 0);
 }
 
 static struct undef_hook cp15_barrier_hooks[] = {
@@ -534,6 +521,19 @@ static struct insn_emulation_ops cp15_barrier_ops = {
 	.set_hw_mode = cp15_barrier_set_hw_mode,
 };
 
+static int insn_cpu_hotplug_notify(struct notifier_block *b,
+			      unsigned long action, void *hcpu)
+{
+	if ((action & ~CPU_TASKS_FROZEN) == CPU_STARTING)
+		run_all_insn_set_hw_mode();
+
+	return NOTIFY_DONE;
+}
+
+static struct notifier_block insn_cpu_hotplug_notifier = {
+	.notifier_call = insn_cpu_hotplug_notify,
+};
+
 /*
  * Invoked as late_initcall, since not needed before init spawned.
  */
@@ -545,6 +545,7 @@ static int __init armv8_deprecated_init(void)
 	if (IS_ENABLED(CONFIG_CP15_BARRIER_EMULATION))
 		register_insn_emulation(&cp15_barrier_ops);
 
+	register_cpu_notifier(&insn_cpu_hotplug_notifier);
 	register_insn_emulation_sysctl(ctl_abi);
 
 	return 0;
-- 
1.7.9.5



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

* [PATCH 1/2] arm64: Consolidate hotplug notifier for instruction emulation
@ 2015-01-07 16:16   ` Suzuki K. Poulose
  0 siblings, 0 replies; 12+ messages in thread
From: Suzuki K. Poulose @ 2015-01-07 16:16 UTC (permalink / raw)
  To: linux-arm-kernel

From: "Suzuki K. Poulose" <suzuki.poulose@arm.com>

As of now each insn_emulation has a cpu hotplug notifier that
enables/disables the CPU feature bit for the functionality. This
patch re-arranges the code, such that there is only one notifier
that runs through the list of registered emulation hooks and runs
their corresponding set_hw_mode.

We do nothing when a CPU is dying as we will set the appropriate bits
when it comes back online based on the state of the hooks.

Signed-off-by: Suzuki K. Poulose <suzuki.poulose@arm.com>
Signed-off-by: Mark Rutland <mark.rutland@arm.com>
---
 arch/arm64/kernel/armv8_deprecated.c |   99 +++++++++++++++++-----------------
 1 file changed, 50 insertions(+), 49 deletions(-)

diff --git a/arch/arm64/kernel/armv8_deprecated.c b/arch/arm64/kernel/armv8_deprecated.c
index c363671..9054447 100644
--- a/arch/arm64/kernel/armv8_deprecated.c
+++ b/arch/arm64/kernel/armv8_deprecated.c
@@ -46,7 +46,7 @@ struct insn_emulation_ops {
 	const char		*name;
 	enum legacy_insn_status	status;
 	struct undef_hook	*hooks;
-	int			(*set_hw_mode)(bool enable);
+	void			(*set_hw_mode)(void *enable);
 };
 
 struct insn_emulation {
@@ -85,6 +85,30 @@ static void remove_emulation_hooks(struct insn_emulation_ops *ops)
 	pr_notice("Removed %s emulation handler\n", ops->name);
 }
 
+/* Run set_hw_mode(action) on all active CPUs */
+static int run_all_cpu_set_hw_mode(struct insn_emulation *insn, bool action)
+{
+	if (!insn->ops->set_hw_mode)
+		return -EINVAL;
+	on_each_cpu(insn->ops->set_hw_mode, (void *)action, true);
+	return 0;
+}
+
+/* Run set_hw_mode for all insns on a starting CPU */
+static void run_all_insn_set_hw_mode(void)
+{
+	unsigned long flags;
+	struct insn_emulation *insn;
+
+	raw_spin_lock_irqsave(&insn_emulation_lock, flags);
+	list_for_each_entry(insn, &insn_emulation, node) {
+		bool hw_mode = (insn->current_mode == INSN_HW);
+		if (insn->ops->set_hw_mode)
+			insn->ops->set_hw_mode((void *)hw_mode);
+	}
+	raw_spin_unlock_irqrestore(&insn_emulation_lock, flags);
+}
+
 static int update_insn_emulation_mode(struct insn_emulation *insn,
 				       enum insn_emulation_mode prev)
 {
@@ -97,10 +121,8 @@ static int update_insn_emulation_mode(struct insn_emulation *insn,
 		remove_emulation_hooks(insn->ops);
 		break;
 	case INSN_HW:
-		if (insn->ops->set_hw_mode) {
-			insn->ops->set_hw_mode(false);
+		if (!run_all_cpu_set_hw_mode(insn, false))
 			pr_notice("Disabled %s support\n", insn->ops->name);
-		}
 		break;
 	}
 
@@ -111,10 +133,9 @@ static int update_insn_emulation_mode(struct insn_emulation *insn,
 		register_emulation_hooks(insn->ops);
 		break;
 	case INSN_HW:
-		if (insn->ops->set_hw_mode && insn->ops->set_hw_mode(true))
+		ret = run_all_cpu_set_hw_mode(insn, true);
+		if (!ret)
 			pr_notice("Enabled %s support\n", insn->ops->name);
-		else
-			ret = -EINVAL;
 		break;
 	}
 
@@ -133,6 +154,8 @@ static void register_insn_emulation(struct insn_emulation_ops *ops)
 	switch (ops->status) {
 	case INSN_DEPRECATED:
 		insn->current_mode = INSN_EMULATE;
+		/* Disable the HW mode if it was turned on at early boot time */
+		run_all_cpu_set_hw_mode(insn, false);
 		insn->max = INSN_HW;
 		break;
 	case INSN_OBSOLETE:
@@ -453,7 +476,7 @@ ret:
 	return 0;
 }
 
-#define SCTLR_EL1_CP15BEN (1 << 5)
+#define SCTLR_EL1_CP15BEN 	(1 << 5)
 
 static inline void config_sctlr_el1(u32 clear, u32 set)
 {
@@ -465,48 +488,12 @@ static inline void config_sctlr_el1(u32 clear, u32 set)
 	asm volatile("msr sctlr_el1, %0" : : "r" (val));
 }
 
-static void enable_cp15_ben(void *info)
+static void cp15_barrier_set_hw_mode(void *enable)
 {
-	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:
-	case CPU_STARTING_FROZEN:
-		enable_cp15_ben(NULL);
-		return NOTIFY_DONE;
-	case CPU_DYING:
-	case CPU_DYING_FROZEN:
-		disable_cp15_ben(NULL);
-		return NOTIFY_DONE;
-	}
-
-	return NOTIFY_OK;
-}
-
-static struct notifier_block cpu_hotplug_notifier = {
-	.notifier_call = cpu_hotplug_notify,
-};
-
-static int cp15_barrier_set_hw_mode(bool enable)
-{
-	if (enable) {
-		register_cpu_notifier(&cpu_hotplug_notifier);
-		on_each_cpu(enable_cp15_ben, NULL, true);
-	} else {
-		unregister_cpu_notifier(&cpu_hotplug_notifier);
-		on_each_cpu(disable_cp15_ben, NULL, true);
-	}
-
-	return true;
+	if (enable)
+		config_sctlr_el1(0, SCTLR_EL1_CP15BEN);
+	else
+		config_sctlr_el1(SCTLR_EL1_CP15BEN, 0);
 }
 
 static struct undef_hook cp15_barrier_hooks[] = {
@@ -534,6 +521,19 @@ static struct insn_emulation_ops cp15_barrier_ops = {
 	.set_hw_mode = cp15_barrier_set_hw_mode,
 };
 
+static int insn_cpu_hotplug_notify(struct notifier_block *b,
+			      unsigned long action, void *hcpu)
+{
+	if ((action & ~CPU_TASKS_FROZEN) == CPU_STARTING)
+		run_all_insn_set_hw_mode();
+
+	return NOTIFY_DONE;
+}
+
+static struct notifier_block insn_cpu_hotplug_notifier = {
+	.notifier_call = insn_cpu_hotplug_notify,
+};
+
 /*
  * Invoked as late_initcall, since not needed before init spawned.
  */
@@ -545,6 +545,7 @@ static int __init armv8_deprecated_init(void)
 	if (IS_ENABLED(CONFIG_CP15_BARRIER_EMULATION))
 		register_insn_emulation(&cp15_barrier_ops);
 
+	register_cpu_notifier(&insn_cpu_hotplug_notifier);
 	register_insn_emulation_sysctl(ctl_abi);
 
 	return 0;
-- 
1.7.9.5

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

* [PATCH 2/2] arm64: Emulate SETEND for AArch32 tasks
  2015-01-07 16:16 ` Suzuki K. Poulose
@ 2015-01-07 16:16   ` Suzuki K. Poulose
  -1 siblings, 0 replies; 12+ messages in thread
From: Suzuki K. Poulose @ 2015-01-07 16:16 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: leo.yan, yexl, will.deacon, mark.rultand, catalin.marinas,
	linux-kernel, Suzuki K. Poulose

From: "Suzuki K. Poulose" <suzuki.poulose@arm.com>

Emulate deprecated 'setend' instruction for AArch32 bit tasks.

	setend [le/be] - Sets the endianness of EL0

The hardware support for the instruction can be enabled by setting the
SCTLR_EL1.SED bit. Like the other emulated instructions it is controlled by
an entry in /proc/sys/abi/. For more information see :
	Documentation/arm64/legacy_instructions.txt

The instruction is emulated by setting/clearing the SPSR_EL1.E bit, which
will be reflected in the PSTATE.E in AArch32 context.

This patch also restores the native endianness for the execution of signal
handlers, since the process could have changed the endianness.

Signed-off-by: Suzuki K. Poulose <suzuki.poulose@arm.com>
---
 Documentation/arm64/legacy_instructions.txt |    5 ++
 arch/arm64/Kconfig                          |   10 ++++
 arch/arm64/include/asm/ptrace.h             |    7 +++
 arch/arm64/kernel/armv8_deprecated.c        |   75 +++++++++++++++++++++++++++
 arch/arm64/kernel/signal32.c                |    5 +-
 5 files changed, 101 insertions(+), 1 deletion(-)

diff --git a/Documentation/arm64/legacy_instructions.txt b/Documentation/arm64/legacy_instructions.txt
index a3b3da2..20e5621 100644
--- a/Documentation/arm64/legacy_instructions.txt
+++ b/Documentation/arm64/legacy_instructions.txt
@@ -43,3 +43,8 @@ Default: Undef (0)
 Node: /proc/sys/abi/cp15_barrier
 Status: Deprecated
 Default: Emulate (1)
+
+* SETEND
+Node: /proc/sys/abi/setend
+Status: Deprecated
+Default: Emulate (1)
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index b1f9a20..c6d1fd9 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -540,6 +540,16 @@ config CP15_BARRIER_EMULATION
 
 	  If unsure, say Y
 
+config SETEND_EMULATION
+	bool "Emulate SETEND instruction"
+	help
+	  The SETEND instruction alters the data-endianness of the
+	  AArch32 EL0, and is deprecated in ARMv8.
+
+	  Say Y here to enable software emulation of the instruction
+	  for AArch32 userspace code.
+
+	  If unsure, say Y
 endif
 
 endmenu
diff --git a/arch/arm64/include/asm/ptrace.h b/arch/arm64/include/asm/ptrace.h
index 41ed9e1..d6dd9fd 100644
--- a/arch/arm64/include/asm/ptrace.h
+++ b/arch/arm64/include/asm/ptrace.h
@@ -58,6 +58,13 @@
 #define COMPAT_PSR_Z_BIT	0x40000000
 #define COMPAT_PSR_N_BIT	0x80000000
 #define COMPAT_PSR_IT_MASK	0x0600fc00	/* If-Then execution state mask */
+
+#ifdef CONFIG_CPU_BIG_ENDIAN
+#define COMPAT_PSR_ENDSTATE	COMPAT_PSR_E_BIT
+#else
+#define COMPAT_PSR_ENDSTATE	0
+#endif
+
 /*
  * These are 'magic' values for PTRACE_PEEKUSR that return info about where a
  * process is located in memory.
diff --git a/arch/arm64/kernel/armv8_deprecated.c b/arch/arm64/kernel/armv8_deprecated.c
index 9054447..dc91bac 100644
--- a/arch/arm64/kernel/armv8_deprecated.c
+++ b/arch/arm64/kernel/armv8_deprecated.c
@@ -477,6 +477,7 @@ ret:
 }
 
 #define SCTLR_EL1_CP15BEN 	(1 << 5)
+#define SCTLR_EL1_SED		(1 << 8)
 
 static inline void config_sctlr_el1(u32 clear, u32 set)
 {
@@ -521,6 +522,77 @@ static struct insn_emulation_ops cp15_barrier_ops = {
 	.set_hw_mode = cp15_barrier_set_hw_mode,
 };
 
+static void setend_set_hw_mode(void *enable)
+{
+	if (enable)
+		config_sctlr_el1(SCTLR_EL1_SED, 0);
+	else
+		config_sctlr_el1(0, SCTLR_EL1_SED);
+}
+
+static int compat_setend_handler(struct pt_regs *regs, u32 endian)
+{
+	char insn[16] = "setend _e";
+
+	perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, 1, regs, regs->pc);
+
+	if (endian) {
+		/* Big Endian */
+		insn[7] = 'b';
+		regs->pstate |= COMPAT_PSR_E_BIT;
+	} else {
+		/* Little Endian */
+		insn[7] = 'l';
+		regs->pstate &= ~COMPAT_PSR_E_BIT;
+	}
+
+	trace_instruction_emulation(insn, regs->pc);
+	pr_warn_ratelimited("\"%s\" (%ld) uses deprecated setend instruction at 0x%llx\n",
+			current->comm, (unsigned long)current->pid, regs->pc);
+
+	return 0;
+}
+
+static int a32_setend_handler(struct pt_regs *regs, u32 instr)
+{
+	int rc = compat_setend_handler(regs, (instr >> 9) & 1);
+	regs->pc += 4;
+	return rc;
+}
+
+static int t16_setend_handler(struct pt_regs *regs, u32 instr)
+{
+	int rc = compat_setend_handler(regs, (instr >> 3) & 1);
+	regs->pc += 2;
+	return rc;
+}
+
+static struct undef_hook setend_hooks[] = {
+	{
+		.instr_mask	= 0xfffffdff,
+		.instr_val	= 0xf1010000,
+		.pstate_mask	= COMPAT_PSR_MODE_MASK,
+		.pstate_val	= COMPAT_PSR_MODE_USR,
+		.fn		= a32_setend_handler,
+	},
+	{
+		/* Thumb mode */
+		.instr_mask	= 0x0000fff7,
+		.instr_val	= 0x0000b650,
+		.pstate_mask	= (COMPAT_PSR_T_BIT | COMPAT_PSR_MODE_MASK),
+		.pstate_val	= (COMPAT_PSR_T_BIT | COMPAT_PSR_MODE_USR),
+		.fn		= t16_setend_handler,
+	},
+	{}
+};
+
+static struct insn_emulation_ops setend_ops = {
+	.name = "setend",
+	.status = INSN_DEPRECATED,
+	.hooks = setend_hooks,
+	.set_hw_mode = setend_set_hw_mode,
+};
+
 static int insn_cpu_hotplug_notify(struct notifier_block *b,
 			      unsigned long action, void *hcpu)
 {
@@ -545,6 +617,9 @@ static int __init armv8_deprecated_init(void)
 	if (IS_ENABLED(CONFIG_CP15_BARRIER_EMULATION))
 		register_insn_emulation(&cp15_barrier_ops);
 
+	if (IS_ENABLED(CONFIG_SETEND_EMULATION))
+		register_insn_emulation(&setend_ops);
+
 	register_cpu_notifier(&insn_cpu_hotplug_notifier);
 	register_insn_emulation_sysctl(ctl_abi);
 
diff --git a/arch/arm64/kernel/signal32.c b/arch/arm64/kernel/signal32.c
index 5a1ba6e..aa763a5 100644
--- a/arch/arm64/kernel/signal32.c
+++ b/arch/arm64/kernel/signal32.c
@@ -440,7 +440,7 @@ static void compat_setup_return(struct pt_regs *regs, struct k_sigaction *ka,
 {
 	compat_ulong_t handler = ptr_to_compat(ka->sa.sa_handler);
 	compat_ulong_t retcode;
-	compat_ulong_t spsr = regs->pstate & ~PSR_f;
+	compat_ulong_t spsr = regs->pstate & ~(PSR_f | COMPAT_PSR_E_BIT);
 	int thumb;
 
 	/* Check if the handler is written for ARM or Thumb */
@@ -454,6 +454,9 @@ static void compat_setup_return(struct pt_regs *regs, struct k_sigaction *ka,
 	/* The IT state must be cleared for both ARM and Thumb-2 */
 	spsr &= ~COMPAT_PSR_IT_MASK;
 
+	/* Restore the original endianness */
+	spsr |= COMPAT_PSR_ENDSTATE;
+
 	if (ka->sa.sa_flags & SA_RESTORER) {
 		retcode = ptr_to_compat(ka->sa.sa_restorer);
 	} else {
-- 
1.7.9.5



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

* [PATCH 2/2] arm64: Emulate SETEND for AArch32 tasks
@ 2015-01-07 16:16   ` Suzuki K. Poulose
  0 siblings, 0 replies; 12+ messages in thread
From: Suzuki K. Poulose @ 2015-01-07 16:16 UTC (permalink / raw)
  To: linux-arm-kernel

From: "Suzuki K. Poulose" <suzuki.poulose@arm.com>

Emulate deprecated 'setend' instruction for AArch32 bit tasks.

	setend [le/be] - Sets the endianness of EL0

The hardware support for the instruction can be enabled by setting the
SCTLR_EL1.SED bit. Like the other emulated instructions it is controlled by
an entry in /proc/sys/abi/. For more information see :
	Documentation/arm64/legacy_instructions.txt

The instruction is emulated by setting/clearing the SPSR_EL1.E bit, which
will be reflected in the PSTATE.E in AArch32 context.

This patch also restores the native endianness for the execution of signal
handlers, since the process could have changed the endianness.

Signed-off-by: Suzuki K. Poulose <suzuki.poulose@arm.com>
---
 Documentation/arm64/legacy_instructions.txt |    5 ++
 arch/arm64/Kconfig                          |   10 ++++
 arch/arm64/include/asm/ptrace.h             |    7 +++
 arch/arm64/kernel/armv8_deprecated.c        |   75 +++++++++++++++++++++++++++
 arch/arm64/kernel/signal32.c                |    5 +-
 5 files changed, 101 insertions(+), 1 deletion(-)

diff --git a/Documentation/arm64/legacy_instructions.txt b/Documentation/arm64/legacy_instructions.txt
index a3b3da2..20e5621 100644
--- a/Documentation/arm64/legacy_instructions.txt
+++ b/Documentation/arm64/legacy_instructions.txt
@@ -43,3 +43,8 @@ Default: Undef (0)
 Node: /proc/sys/abi/cp15_barrier
 Status: Deprecated
 Default: Emulate (1)
+
+* SETEND
+Node: /proc/sys/abi/setend
+Status: Deprecated
+Default: Emulate (1)
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index b1f9a20..c6d1fd9 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -540,6 +540,16 @@ config CP15_BARRIER_EMULATION
 
 	  If unsure, say Y
 
+config SETEND_EMULATION
+	bool "Emulate SETEND instruction"
+	help
+	  The SETEND instruction alters the data-endianness of the
+	  AArch32 EL0, and is deprecated in ARMv8.
+
+	  Say Y here to enable software emulation of the instruction
+	  for AArch32 userspace code.
+
+	  If unsure, say Y
 endif
 
 endmenu
diff --git a/arch/arm64/include/asm/ptrace.h b/arch/arm64/include/asm/ptrace.h
index 41ed9e1..d6dd9fd 100644
--- a/arch/arm64/include/asm/ptrace.h
+++ b/arch/arm64/include/asm/ptrace.h
@@ -58,6 +58,13 @@
 #define COMPAT_PSR_Z_BIT	0x40000000
 #define COMPAT_PSR_N_BIT	0x80000000
 #define COMPAT_PSR_IT_MASK	0x0600fc00	/* If-Then execution state mask */
+
+#ifdef CONFIG_CPU_BIG_ENDIAN
+#define COMPAT_PSR_ENDSTATE	COMPAT_PSR_E_BIT
+#else
+#define COMPAT_PSR_ENDSTATE	0
+#endif
+
 /*
  * These are 'magic' values for PTRACE_PEEKUSR that return info about where a
  * process is located in memory.
diff --git a/arch/arm64/kernel/armv8_deprecated.c b/arch/arm64/kernel/armv8_deprecated.c
index 9054447..dc91bac 100644
--- a/arch/arm64/kernel/armv8_deprecated.c
+++ b/arch/arm64/kernel/armv8_deprecated.c
@@ -477,6 +477,7 @@ ret:
 }
 
 #define SCTLR_EL1_CP15BEN 	(1 << 5)
+#define SCTLR_EL1_SED		(1 << 8)
 
 static inline void config_sctlr_el1(u32 clear, u32 set)
 {
@@ -521,6 +522,77 @@ static struct insn_emulation_ops cp15_barrier_ops = {
 	.set_hw_mode = cp15_barrier_set_hw_mode,
 };
 
+static void setend_set_hw_mode(void *enable)
+{
+	if (enable)
+		config_sctlr_el1(SCTLR_EL1_SED, 0);
+	else
+		config_sctlr_el1(0, SCTLR_EL1_SED);
+}
+
+static int compat_setend_handler(struct pt_regs *regs, u32 endian)
+{
+	char insn[16] = "setend _e";
+
+	perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, 1, regs, regs->pc);
+
+	if (endian) {
+		/* Big Endian */
+		insn[7] = 'b';
+		regs->pstate |= COMPAT_PSR_E_BIT;
+	} else {
+		/* Little Endian */
+		insn[7] = 'l';
+		regs->pstate &= ~COMPAT_PSR_E_BIT;
+	}
+
+	trace_instruction_emulation(insn, regs->pc);
+	pr_warn_ratelimited("\"%s\" (%ld) uses deprecated setend instruction at 0x%llx\n",
+			current->comm, (unsigned long)current->pid, regs->pc);
+
+	return 0;
+}
+
+static int a32_setend_handler(struct pt_regs *regs, u32 instr)
+{
+	int rc = compat_setend_handler(regs, (instr >> 9) & 1);
+	regs->pc += 4;
+	return rc;
+}
+
+static int t16_setend_handler(struct pt_regs *regs, u32 instr)
+{
+	int rc = compat_setend_handler(regs, (instr >> 3) & 1);
+	regs->pc += 2;
+	return rc;
+}
+
+static struct undef_hook setend_hooks[] = {
+	{
+		.instr_mask	= 0xfffffdff,
+		.instr_val	= 0xf1010000,
+		.pstate_mask	= COMPAT_PSR_MODE_MASK,
+		.pstate_val	= COMPAT_PSR_MODE_USR,
+		.fn		= a32_setend_handler,
+	},
+	{
+		/* Thumb mode */
+		.instr_mask	= 0x0000fff7,
+		.instr_val	= 0x0000b650,
+		.pstate_mask	= (COMPAT_PSR_T_BIT | COMPAT_PSR_MODE_MASK),
+		.pstate_val	= (COMPAT_PSR_T_BIT | COMPAT_PSR_MODE_USR),
+		.fn		= t16_setend_handler,
+	},
+	{}
+};
+
+static struct insn_emulation_ops setend_ops = {
+	.name = "setend",
+	.status = INSN_DEPRECATED,
+	.hooks = setend_hooks,
+	.set_hw_mode = setend_set_hw_mode,
+};
+
 static int insn_cpu_hotplug_notify(struct notifier_block *b,
 			      unsigned long action, void *hcpu)
 {
@@ -545,6 +617,9 @@ static int __init armv8_deprecated_init(void)
 	if (IS_ENABLED(CONFIG_CP15_BARRIER_EMULATION))
 		register_insn_emulation(&cp15_barrier_ops);
 
+	if (IS_ENABLED(CONFIG_SETEND_EMULATION))
+		register_insn_emulation(&setend_ops);
+
 	register_cpu_notifier(&insn_cpu_hotplug_notifier);
 	register_insn_emulation_sysctl(ctl_abi);
 
diff --git a/arch/arm64/kernel/signal32.c b/arch/arm64/kernel/signal32.c
index 5a1ba6e..aa763a5 100644
--- a/arch/arm64/kernel/signal32.c
+++ b/arch/arm64/kernel/signal32.c
@@ -440,7 +440,7 @@ static void compat_setup_return(struct pt_regs *regs, struct k_sigaction *ka,
 {
 	compat_ulong_t handler = ptr_to_compat(ka->sa.sa_handler);
 	compat_ulong_t retcode;
-	compat_ulong_t spsr = regs->pstate & ~PSR_f;
+	compat_ulong_t spsr = regs->pstate & ~(PSR_f | COMPAT_PSR_E_BIT);
 	int thumb;
 
 	/* Check if the handler is written for ARM or Thumb */
@@ -454,6 +454,9 @@ static void compat_setup_return(struct pt_regs *regs, struct k_sigaction *ka,
 	/* The IT state must be cleared for both ARM and Thumb-2 */
 	spsr &= ~COMPAT_PSR_IT_MASK;
 
+	/* Restore the original endianness */
+	spsr |= COMPAT_PSR_ENDSTATE;
+
 	if (ka->sa.sa_flags & SA_RESTORER) {
 		retcode = ptr_to_compat(ka->sa.sa_restorer);
 	} else {
-- 
1.7.9.5

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

* Re: [PATCH 2/2] arm64: Emulate SETEND for AArch32 tasks
  2015-01-07 16:16   ` Suzuki K. Poulose
@ 2015-01-08 18:43     ` Mark Rutland
  -1 siblings, 0 replies; 12+ messages in thread
From: Mark Rutland @ 2015-01-08 18:43 UTC (permalink / raw)
  To: Suzuki Poulose
  Cc: linux-arm-kernel, yexl, Catalin Marinas, Will Deacon,
	linux-kernel, leo.yan

Hi Suzuki,

On Wed, Jan 07, 2015 at 04:16:45PM +0000, Suzuki K. Poulose wrote:
> From: "Suzuki K. Poulose" <suzuki.poulose@arm.com>
> 
> Emulate deprecated 'setend' instruction for AArch32 bit tasks.
> 
> 	setend [le/be] - Sets the endianness of EL0
> 
> The hardware support for the instruction can be enabled by setting the
> SCTLR_EL1.SED bit. Like the other emulated instructions it is controlled by
> an entry in /proc/sys/abi/. For more information see :
> 	Documentation/arm64/legacy_instructions.txt
> 
> The instruction is emulated by setting/clearing the SPSR_EL1.E bit, which
> will be reflected in the PSTATE.E in AArch32 context.

A "fun" problem with emulating setend is that it will not always work
unless we emulate the entire instruction set when userspace wants to be
in an unsupported endianness.

For implementations which are not bi-endian at EL0 (i.e. where
ID_AA64MMFR0_EL1.BigEndEL0 == 0), SCTLR_EL1.E0E has a fixed value which
we cannot change. The field names are misleading: in a BE-only system
ID_AA64MMFR0_EL1.{BigEnd,BigEndEL0} == {0,0} and SCTLR_EL1.{EE,E0E} are
fixed to {1,1}.

I think we need to detect when EL0 has a fixed endianness such that we
can treat the setend instruction as undefined. Otherwise we will
silently fail to change EL0 endianness, advance the PC, and return to
userspace in the wrong endianness, which will be very painful to debug.
Userspace has the option of handling the resulting SIGILL in such cases.

That means we need to be able to fail to transition into INSN_EMULATE
mode as we currently can when transitioning to INSN_HW.

> This patch also restores the native endianness for the execution of signal
> handlers, since the process could have changed the endianness.
> 
> Signed-off-by: Suzuki K. Poulose <suzuki.poulose@arm.com>
> ---
>  Documentation/arm64/legacy_instructions.txt |    5 ++
>  arch/arm64/Kconfig                          |   10 ++++
>  arch/arm64/include/asm/ptrace.h             |    7 +++
>  arch/arm64/kernel/armv8_deprecated.c        |   75 +++++++++++++++++++++++++++
>  arch/arm64/kernel/signal32.c                |    5 +-
>  5 files changed, 101 insertions(+), 1 deletion(-)
> 
> diff --git a/Documentation/arm64/legacy_instructions.txt b/Documentation/arm64/legacy_instructions.txt
> index a3b3da2..20e5621 100644
> --- a/Documentation/arm64/legacy_instructions.txt
> +++ b/Documentation/arm64/legacy_instructions.txt
> @@ -43,3 +43,8 @@ Default: Undef (0)
>  Node: /proc/sys/abi/cp15_barrier
>  Status: Deprecated
>  Default: Emulate (1)
> +
> +* SETEND
> +Node: /proc/sys/abi/setend
> +Status: Deprecated
> +Default: Emulate (1)

Given we can't always emulate SETEND, should we document "Emulate where
possible" or something to that effect?

> diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
> index b1f9a20..c6d1fd9 100644
> --- a/arch/arm64/Kconfig
> +++ b/arch/arm64/Kconfig
> @@ -540,6 +540,16 @@ config CP15_BARRIER_EMULATION
>  
>  	  If unsure, say Y
>  
> +config SETEND_EMULATION
> +	bool "Emulate SETEND instruction"
> +	help
> +	  The SETEND instruction alters the data-endianness of the
> +	  AArch32 EL0, and is deprecated in ARMv8.
> +
> +	  Say Y here to enable software emulation of the instruction
> +	  for AArch32 userspace code.
> +
> +	  If unsure, say Y
>  endif
>  
>  endmenu
> diff --git a/arch/arm64/include/asm/ptrace.h b/arch/arm64/include/asm/ptrace.h
> index 41ed9e1..d6dd9fd 100644
> --- a/arch/arm64/include/asm/ptrace.h
> +++ b/arch/arm64/include/asm/ptrace.h
> @@ -58,6 +58,13 @@
>  #define COMPAT_PSR_Z_BIT	0x40000000
>  #define COMPAT_PSR_N_BIT	0x80000000
>  #define COMPAT_PSR_IT_MASK	0x0600fc00	/* If-Then execution state mask */
> +
> +#ifdef CONFIG_CPU_BIG_ENDIAN
> +#define COMPAT_PSR_ENDSTATE	COMPAT_PSR_E_BIT
> +#else
> +#define COMPAT_PSR_ENDSTATE	0
> +#endif
> +
>  /*
>   * These are 'magic' values for PTRACE_PEEKUSR that return info about where a
>   * process is located in memory.
> diff --git a/arch/arm64/kernel/armv8_deprecated.c b/arch/arm64/kernel/armv8_deprecated.c
> index 9054447..dc91bac 100644
> --- a/arch/arm64/kernel/armv8_deprecated.c
> +++ b/arch/arm64/kernel/armv8_deprecated.c
> @@ -477,6 +477,7 @@ ret:
>  }
>  
>  #define SCTLR_EL1_CP15BEN 	(1 << 5)
> +#define SCTLR_EL1_SED		(1 << 8)
>  
>  static inline void config_sctlr_el1(u32 clear, u32 set)
>  {
> @@ -521,6 +522,77 @@ static struct insn_emulation_ops cp15_barrier_ops = {
>  	.set_hw_mode = cp15_barrier_set_hw_mode,
>  };
>  
> +static void setend_set_hw_mode(void *enable)
> +{
> +	if (enable)
> +		config_sctlr_el1(SCTLR_EL1_SED, 0);
> +	else
> +		config_sctlr_el1(0, SCTLR_EL1_SED);
> +}
> +
> +static int compat_setend_handler(struct pt_regs *regs, u32 endian)

If we s/endian/big_endian/ here we can drop the comments within the
function as the test will be easier to read. We could also s/u32/bool/.

> +{
> +	char insn[16] = "setend _e";

Elsewhere (e.g. in cp15barrier_handler) we write these out in full
rather than modifying a string on the stack. I think we should do the
same here (we can change insn to a char * and assign the full relevant
string in either branch).

Doing so will mean grepping for '"setend be"' finds this function, which
is handy.

Thanks,
Mark.

> +
> +	perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, 1, regs, regs->pc);
> +
> +	if (endian) {
> +		/* Big Endian */
> +		insn[7] = 'b';
> +		regs->pstate |= COMPAT_PSR_E_BIT;
> +	} else {
> +		/* Little Endian */
> +		insn[7] = 'l';
> +		regs->pstate &= ~COMPAT_PSR_E_BIT;
> +	}
> +
> +	trace_instruction_emulation(insn, regs->pc);
> +	pr_warn_ratelimited("\"%s\" (%ld) uses deprecated setend instruction at 0x%llx\n",
> +			current->comm, (unsigned long)current->pid, regs->pc);
> +
> +	return 0;
> +}
> +
> +static int a32_setend_handler(struct pt_regs *regs, u32 instr)
> +{
> +	int rc = compat_setend_handler(regs, (instr >> 9) & 1);
> +	regs->pc += 4;
> +	return rc;
> +}
> +
> +static int t16_setend_handler(struct pt_regs *regs, u32 instr)
> +{
> +	int rc = compat_setend_handler(regs, (instr >> 3) & 1);
> +	regs->pc += 2;
> +	return rc;
> +}
> +
> +static struct undef_hook setend_hooks[] = {
> +	{
> +		.instr_mask	= 0xfffffdff,
> +		.instr_val	= 0xf1010000,
> +		.pstate_mask	= COMPAT_PSR_MODE_MASK,
> +		.pstate_val	= COMPAT_PSR_MODE_USR,
> +		.fn		= a32_setend_handler,
> +	},
> +	{
> +		/* Thumb mode */
> +		.instr_mask	= 0x0000fff7,
> +		.instr_val	= 0x0000b650,
> +		.pstate_mask	= (COMPAT_PSR_T_BIT | COMPAT_PSR_MODE_MASK),
> +		.pstate_val	= (COMPAT_PSR_T_BIT | COMPAT_PSR_MODE_USR),
> +		.fn		= t16_setend_handler,
> +	},
> +	{}
> +};
> +
> +static struct insn_emulation_ops setend_ops = {
> +	.name = "setend",
> +	.status = INSN_DEPRECATED,
> +	.hooks = setend_hooks,
> +	.set_hw_mode = setend_set_hw_mode,
> +};
> +
>  static int insn_cpu_hotplug_notify(struct notifier_block *b,
>  			      unsigned long action, void *hcpu)
>  {
> @@ -545,6 +617,9 @@ static int __init armv8_deprecated_init(void)
>  	if (IS_ENABLED(CONFIG_CP15_BARRIER_EMULATION))
>  		register_insn_emulation(&cp15_barrier_ops);
>  
> +	if (IS_ENABLED(CONFIG_SETEND_EMULATION))
> +		register_insn_emulation(&setend_ops);
> +
>  	register_cpu_notifier(&insn_cpu_hotplug_notifier);
>  	register_insn_emulation_sysctl(ctl_abi);
>  
> diff --git a/arch/arm64/kernel/signal32.c b/arch/arm64/kernel/signal32.c
> index 5a1ba6e..aa763a5 100644
> --- a/arch/arm64/kernel/signal32.c
> +++ b/arch/arm64/kernel/signal32.c
> @@ -440,7 +440,7 @@ static void compat_setup_return(struct pt_regs *regs, struct k_sigaction *ka,
>  {
>  	compat_ulong_t handler = ptr_to_compat(ka->sa.sa_handler);
>  	compat_ulong_t retcode;
> -	compat_ulong_t spsr = regs->pstate & ~PSR_f;
> +	compat_ulong_t spsr = regs->pstate & ~(PSR_f | COMPAT_PSR_E_BIT);
>  	int thumb;
>  
>  	/* Check if the handler is written for ARM or Thumb */
> @@ -454,6 +454,9 @@ static void compat_setup_return(struct pt_regs *regs, struct k_sigaction *ka,
>  	/* The IT state must be cleared for both ARM and Thumb-2 */
>  	spsr &= ~COMPAT_PSR_IT_MASK;
>  
> +	/* Restore the original endianness */
> +	spsr |= COMPAT_PSR_ENDSTATE;
> +
>  	if (ka->sa.sa_flags & SA_RESTORER) {
>  		retcode = ptr_to_compat(ka->sa.sa_restorer);
>  	} else {
> -- 
> 1.7.9.5
> 
> 
> 
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
> 

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

* [PATCH 2/2] arm64: Emulate SETEND for AArch32 tasks
@ 2015-01-08 18:43     ` Mark Rutland
  0 siblings, 0 replies; 12+ messages in thread
From: Mark Rutland @ 2015-01-08 18:43 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Suzuki,

On Wed, Jan 07, 2015 at 04:16:45PM +0000, Suzuki K. Poulose wrote:
> From: "Suzuki K. Poulose" <suzuki.poulose@arm.com>
> 
> Emulate deprecated 'setend' instruction for AArch32 bit tasks.
> 
> 	setend [le/be] - Sets the endianness of EL0
> 
> The hardware support for the instruction can be enabled by setting the
> SCTLR_EL1.SED bit. Like the other emulated instructions it is controlled by
> an entry in /proc/sys/abi/. For more information see :
> 	Documentation/arm64/legacy_instructions.txt
> 
> The instruction is emulated by setting/clearing the SPSR_EL1.E bit, which
> will be reflected in the PSTATE.E in AArch32 context.

A "fun" problem with emulating setend is that it will not always work
unless we emulate the entire instruction set when userspace wants to be
in an unsupported endianness.

For implementations which are not bi-endian at EL0 (i.e. where
ID_AA64MMFR0_EL1.BigEndEL0 == 0), SCTLR_EL1.E0E has a fixed value which
we cannot change. The field names are misleading: in a BE-only system
ID_AA64MMFR0_EL1.{BigEnd,BigEndEL0} == {0,0} and SCTLR_EL1.{EE,E0E} are
fixed to {1,1}.

I think we need to detect when EL0 has a fixed endianness such that we
can treat the setend instruction as undefined. Otherwise we will
silently fail to change EL0 endianness, advance the PC, and return to
userspace in the wrong endianness, which will be very painful to debug.
Userspace has the option of handling the resulting SIGILL in such cases.

That means we need to be able to fail to transition into INSN_EMULATE
mode as we currently can when transitioning to INSN_HW.

> This patch also restores the native endianness for the execution of signal
> handlers, since the process could have changed the endianness.
> 
> Signed-off-by: Suzuki K. Poulose <suzuki.poulose@arm.com>
> ---
>  Documentation/arm64/legacy_instructions.txt |    5 ++
>  arch/arm64/Kconfig                          |   10 ++++
>  arch/arm64/include/asm/ptrace.h             |    7 +++
>  arch/arm64/kernel/armv8_deprecated.c        |   75 +++++++++++++++++++++++++++
>  arch/arm64/kernel/signal32.c                |    5 +-
>  5 files changed, 101 insertions(+), 1 deletion(-)
> 
> diff --git a/Documentation/arm64/legacy_instructions.txt b/Documentation/arm64/legacy_instructions.txt
> index a3b3da2..20e5621 100644
> --- a/Documentation/arm64/legacy_instructions.txt
> +++ b/Documentation/arm64/legacy_instructions.txt
> @@ -43,3 +43,8 @@ Default: Undef (0)
>  Node: /proc/sys/abi/cp15_barrier
>  Status: Deprecated
>  Default: Emulate (1)
> +
> +* SETEND
> +Node: /proc/sys/abi/setend
> +Status: Deprecated
> +Default: Emulate (1)

Given we can't always emulate SETEND, should we document "Emulate where
possible" or something to that effect?

> diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
> index b1f9a20..c6d1fd9 100644
> --- a/arch/arm64/Kconfig
> +++ b/arch/arm64/Kconfig
> @@ -540,6 +540,16 @@ config CP15_BARRIER_EMULATION
>  
>  	  If unsure, say Y
>  
> +config SETEND_EMULATION
> +	bool "Emulate SETEND instruction"
> +	help
> +	  The SETEND instruction alters the data-endianness of the
> +	  AArch32 EL0, and is deprecated in ARMv8.
> +
> +	  Say Y here to enable software emulation of the instruction
> +	  for AArch32 userspace code.
> +
> +	  If unsure, say Y
>  endif
>  
>  endmenu
> diff --git a/arch/arm64/include/asm/ptrace.h b/arch/arm64/include/asm/ptrace.h
> index 41ed9e1..d6dd9fd 100644
> --- a/arch/arm64/include/asm/ptrace.h
> +++ b/arch/arm64/include/asm/ptrace.h
> @@ -58,6 +58,13 @@
>  #define COMPAT_PSR_Z_BIT	0x40000000
>  #define COMPAT_PSR_N_BIT	0x80000000
>  #define COMPAT_PSR_IT_MASK	0x0600fc00	/* If-Then execution state mask */
> +
> +#ifdef CONFIG_CPU_BIG_ENDIAN
> +#define COMPAT_PSR_ENDSTATE	COMPAT_PSR_E_BIT
> +#else
> +#define COMPAT_PSR_ENDSTATE	0
> +#endif
> +
>  /*
>   * These are 'magic' values for PTRACE_PEEKUSR that return info about where a
>   * process is located in memory.
> diff --git a/arch/arm64/kernel/armv8_deprecated.c b/arch/arm64/kernel/armv8_deprecated.c
> index 9054447..dc91bac 100644
> --- a/arch/arm64/kernel/armv8_deprecated.c
> +++ b/arch/arm64/kernel/armv8_deprecated.c
> @@ -477,6 +477,7 @@ ret:
>  }
>  
>  #define SCTLR_EL1_CP15BEN 	(1 << 5)
> +#define SCTLR_EL1_SED		(1 << 8)
>  
>  static inline void config_sctlr_el1(u32 clear, u32 set)
>  {
> @@ -521,6 +522,77 @@ static struct insn_emulation_ops cp15_barrier_ops = {
>  	.set_hw_mode = cp15_barrier_set_hw_mode,
>  };
>  
> +static void setend_set_hw_mode(void *enable)
> +{
> +	if (enable)
> +		config_sctlr_el1(SCTLR_EL1_SED, 0);
> +	else
> +		config_sctlr_el1(0, SCTLR_EL1_SED);
> +}
> +
> +static int compat_setend_handler(struct pt_regs *regs, u32 endian)

If we s/endian/big_endian/ here we can drop the comments within the
function as the test will be easier to read. We could also s/u32/bool/.

> +{
> +	char insn[16] = "setend _e";

Elsewhere (e.g. in cp15barrier_handler) we write these out in full
rather than modifying a string on the stack. I think we should do the
same here (we can change insn to a char * and assign the full relevant
string in either branch).

Doing so will mean grepping for '"setend be"' finds this function, which
is handy.

Thanks,
Mark.

> +
> +	perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, 1, regs, regs->pc);
> +
> +	if (endian) {
> +		/* Big Endian */
> +		insn[7] = 'b';
> +		regs->pstate |= COMPAT_PSR_E_BIT;
> +	} else {
> +		/* Little Endian */
> +		insn[7] = 'l';
> +		regs->pstate &= ~COMPAT_PSR_E_BIT;
> +	}
> +
> +	trace_instruction_emulation(insn, regs->pc);
> +	pr_warn_ratelimited("\"%s\" (%ld) uses deprecated setend instruction at 0x%llx\n",
> +			current->comm, (unsigned long)current->pid, regs->pc);
> +
> +	return 0;
> +}
> +
> +static int a32_setend_handler(struct pt_regs *regs, u32 instr)
> +{
> +	int rc = compat_setend_handler(regs, (instr >> 9) & 1);
> +	regs->pc += 4;
> +	return rc;
> +}
> +
> +static int t16_setend_handler(struct pt_regs *regs, u32 instr)
> +{
> +	int rc = compat_setend_handler(regs, (instr >> 3) & 1);
> +	regs->pc += 2;
> +	return rc;
> +}
> +
> +static struct undef_hook setend_hooks[] = {
> +	{
> +		.instr_mask	= 0xfffffdff,
> +		.instr_val	= 0xf1010000,
> +		.pstate_mask	= COMPAT_PSR_MODE_MASK,
> +		.pstate_val	= COMPAT_PSR_MODE_USR,
> +		.fn		= a32_setend_handler,
> +	},
> +	{
> +		/* Thumb mode */
> +		.instr_mask	= 0x0000fff7,
> +		.instr_val	= 0x0000b650,
> +		.pstate_mask	= (COMPAT_PSR_T_BIT | COMPAT_PSR_MODE_MASK),
> +		.pstate_val	= (COMPAT_PSR_T_BIT | COMPAT_PSR_MODE_USR),
> +		.fn		= t16_setend_handler,
> +	},
> +	{}
> +};
> +
> +static struct insn_emulation_ops setend_ops = {
> +	.name = "setend",
> +	.status = INSN_DEPRECATED,
> +	.hooks = setend_hooks,
> +	.set_hw_mode = setend_set_hw_mode,
> +};
> +
>  static int insn_cpu_hotplug_notify(struct notifier_block *b,
>  			      unsigned long action, void *hcpu)
>  {
> @@ -545,6 +617,9 @@ static int __init armv8_deprecated_init(void)
>  	if (IS_ENABLED(CONFIG_CP15_BARRIER_EMULATION))
>  		register_insn_emulation(&cp15_barrier_ops);
>  
> +	if (IS_ENABLED(CONFIG_SETEND_EMULATION))
> +		register_insn_emulation(&setend_ops);
> +
>  	register_cpu_notifier(&insn_cpu_hotplug_notifier);
>  	register_insn_emulation_sysctl(ctl_abi);
>  
> diff --git a/arch/arm64/kernel/signal32.c b/arch/arm64/kernel/signal32.c
> index 5a1ba6e..aa763a5 100644
> --- a/arch/arm64/kernel/signal32.c
> +++ b/arch/arm64/kernel/signal32.c
> @@ -440,7 +440,7 @@ static void compat_setup_return(struct pt_regs *regs, struct k_sigaction *ka,
>  {
>  	compat_ulong_t handler = ptr_to_compat(ka->sa.sa_handler);
>  	compat_ulong_t retcode;
> -	compat_ulong_t spsr = regs->pstate & ~PSR_f;
> +	compat_ulong_t spsr = regs->pstate & ~(PSR_f | COMPAT_PSR_E_BIT);
>  	int thumb;
>  
>  	/* Check if the handler is written for ARM or Thumb */
> @@ -454,6 +454,9 @@ static void compat_setup_return(struct pt_regs *regs, struct k_sigaction *ka,
>  	/* The IT state must be cleared for both ARM and Thumb-2 */
>  	spsr &= ~COMPAT_PSR_IT_MASK;
>  
> +	/* Restore the original endianness */
> +	spsr |= COMPAT_PSR_ENDSTATE;
> +
>  	if (ka->sa.sa_flags & SA_RESTORER) {
>  		retcode = ptr_to_compat(ka->sa.sa_restorer);
>  	} else {
> -- 
> 1.7.9.5
> 
> 
> 
> _______________________________________________
> 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] 12+ messages in thread

* Re: [PATCH 2/2] arm64: Emulate SETEND for AArch32 tasks
  2015-01-08 18:43     ` Mark Rutland
@ 2015-01-09 10:21       ` Suzuki K. Poulose
  -1 siblings, 0 replies; 12+ messages in thread
From: Suzuki K. Poulose @ 2015-01-09 10:21 UTC (permalink / raw)
  To: Mark Rutland
  Cc: linux-arm-kernel, yexl, Catalin Marinas, Will Deacon,
	linux-kernel, leo.yan

On 08/01/15 18:43, Mark Rutland wrote:
> Hi Suzuki,
>
> On Wed, Jan 07, 2015 at 04:16:45PM +0000, Suzuki K. Poulose wrote:
>> From: "Suzuki K. Poulose" <suzuki.poulose@arm.com>
>>
>> Emulate deprecated 'setend' instruction for AArch32 bit tasks.
>>
>> 	setend [le/be] - Sets the endianness of EL0
>>
>> The hardware support for the instruction can be enabled by setting the
>> SCTLR_EL1.SED bit. Like the other emulated instructions it is controlled by
>> an entry in /proc/sys/abi/. For more information see :
>> 	Documentation/arm64/legacy_instructions.txt
>>
>> The instruction is emulated by setting/clearing the SPSR_EL1.E bit, which
>> will be reflected in the PSTATE.E in AArch32 context.
>
> A "fun" problem with emulating setend is that it will not always work
> unless we emulate the entire instruction set when userspace wants to be
> in an unsupported endianness.
>
> For implementations which are not bi-endian at EL0 (i.e. where
> ID_AA64MMFR0_EL1.BigEndEL0 == 0), SCTLR_EL1.E0E has a fixed value which
> we cannot change. The field names are misleading: in a BE-only system
> ID_AA64MMFR0_EL1.{BigEnd,BigEndEL0} == {0,0} and SCTLR_EL1.{EE,E0E} are
> fixed to {1,1}.
>
> I think we need to detect when EL0 has a fixed endianness such that we
> can treat the setend instruction as undefined. Otherwise we will
> silently fail to change EL0 endianness, advance the PC, and return to
> userspace in the wrong endianness, which will be very painful to debug.
> Userspace has the option of handling the resulting SIGILL in such cases.

You are right. I missed this scenario. To add to that things get 
complicated when there are heterogeneous CPUs on the system that might 
have differing bits for BigEndEL0. I will take a look at this one. 
Thanks for pointing this out.
>
> That means we need to be able to fail to transition into INSN_EMULATE
> mode as we currently can when transitioning to INSN_HW.
>
>> This patch also restores the native endianness for the execution of signal
>> handlers, since the process could have changed the endianness.
>>
>> Signed-off-by: Suzuki K. Poulose <suzuki.poulose@arm.com>
>> ---
>>   Documentation/arm64/legacy_instructions.txt |    5 ++
>>   arch/arm64/Kconfig                          |   10 ++++
>>   arch/arm64/include/asm/ptrace.h             |    7 +++
>>   arch/arm64/kernel/armv8_deprecated.c        |   75 +++++++++++++++++++++++++++
>>   arch/arm64/kernel/signal32.c                |    5 +-
>>   5 files changed, 101 insertions(+), 1 deletion(-)
>>
>> diff --git a/Documentation/arm64/legacy_instructions.txt b/Documentation/arm64/legacy_instructions.txt
>> index a3b3da2..20e5621 100644
>> --- a/Documentation/arm64/legacy_instructions.txt
>> +++ b/Documentation/arm64/legacy_instructions.txt
>> @@ -43,3 +43,8 @@ Default: Undef (0)
>>   Node: /proc/sys/abi/cp15_barrier
>>   Status: Deprecated
>>   Default: Emulate (1)
>> +
>> +* SETEND
>> +Node: /proc/sys/abi/setend
>> +Status: Deprecated
>> +Default: Emulate (1)
>
> Given we can't always emulate SETEND, should we document "Emulate where
> possible" or something to that effect?
>
Will fix it in the next revision.

>> diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
>> index b1f9a20..c6d1fd9 100644
>> --- a/arch/arm64/Kconfig
>> +++ b/arch/arm64/Kconfig
>> @@ -540,6 +540,16 @@ config CP15_BARRIER_EMULATION
>>
>>   	  If unsure, say Y
>>
>> +config SETEND_EMULATION
>> +	bool "Emulate SETEND instruction"
>> +	help
>> +	  The SETEND instruction alters the data-endianness of the
>> +	  AArch32 EL0, and is deprecated in ARMv8.
>> +
>> +	  Say Y here to enable software emulation of the instruction
>> +	  for AArch32 userspace code.
>> +
>> +	  If unsure, say Y
>>   endif
>>
>>   endmenu
>> diff --git a/arch/arm64/include/asm/ptrace.h b/arch/arm64/include/asm/ptrace.h
>> index 41ed9e1..d6dd9fd 100644
>> --- a/arch/arm64/include/asm/ptrace.h
>> +++ b/arch/arm64/include/asm/ptrace.h
>> @@ -58,6 +58,13 @@
>>   #define COMPAT_PSR_Z_BIT	0x40000000
>>   #define COMPAT_PSR_N_BIT	0x80000000
>>   #define COMPAT_PSR_IT_MASK	0x0600fc00	/* If-Then execution state mask */
>> +
>> +#ifdef CONFIG_CPU_BIG_ENDIAN
>> +#define COMPAT_PSR_ENDSTATE	COMPAT_PSR_E_BIT
>> +#else
>> +#define COMPAT_PSR_ENDSTATE	0
>> +#endif
>> +
>>   /*
>>    * These are 'magic' values for PTRACE_PEEKUSR that return info about where a
>>    * process is located in memory.
>> diff --git a/arch/arm64/kernel/armv8_deprecated.c b/arch/arm64/kernel/armv8_deprecated.c
>> index 9054447..dc91bac 100644
>> --- a/arch/arm64/kernel/armv8_deprecated.c
>> +++ b/arch/arm64/kernel/armv8_deprecated.c
>> @@ -477,6 +477,7 @@ ret:
>>   }
>>
>>   #define SCTLR_EL1_CP15BEN 	(1 << 5)
>> +#define SCTLR_EL1_SED		(1 << 8)
>>
>>   static inline void config_sctlr_el1(u32 clear, u32 set)
>>   {
>> @@ -521,6 +522,77 @@ static struct insn_emulation_ops cp15_barrier_ops = {
>>   	.set_hw_mode = cp15_barrier_set_hw_mode,
>>   };
>>
>> +static void setend_set_hw_mode(void *enable)
>> +{
>> +	if (enable)
>> +		config_sctlr_el1(SCTLR_EL1_SED, 0);
>> +	else
>> +		config_sctlr_el1(0, SCTLR_EL1_SED);
>> +}
>> +
>> +static int compat_setend_handler(struct pt_regs *regs, u32 endian)
>
> If we s/endian/big_endian/ here we can drop the comments within the
> function as the test will be easier to read. We could also s/u32/bool/.
>
OK
>> +{
>> +	char insn[16] = "setend _e";
>
> Elsewhere (e.g. in cp15barrier_handler) we write these out in full
> rather than modifying a string on the stack. I think we should do the
> same here (we can change insn to a char * and assign the full relevant
> string in either branch).
>
> Doing so will mean grepping for '"setend be"' finds this function, which
> is handy.
>
Makes sense. Thanks for the review.

Thanks
Suzuki



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

* [PATCH 2/2] arm64: Emulate SETEND for AArch32 tasks
@ 2015-01-09 10:21       ` Suzuki K. Poulose
  0 siblings, 0 replies; 12+ messages in thread
From: Suzuki K. Poulose @ 2015-01-09 10:21 UTC (permalink / raw)
  To: linux-arm-kernel

On 08/01/15 18:43, Mark Rutland wrote:
> Hi Suzuki,
>
> On Wed, Jan 07, 2015 at 04:16:45PM +0000, Suzuki K. Poulose wrote:
>> From: "Suzuki K. Poulose" <suzuki.poulose@arm.com>
>>
>> Emulate deprecated 'setend' instruction for AArch32 bit tasks.
>>
>> 	setend [le/be] - Sets the endianness of EL0
>>
>> The hardware support for the instruction can be enabled by setting the
>> SCTLR_EL1.SED bit. Like the other emulated instructions it is controlled by
>> an entry in /proc/sys/abi/. For more information see :
>> 	Documentation/arm64/legacy_instructions.txt
>>
>> The instruction is emulated by setting/clearing the SPSR_EL1.E bit, which
>> will be reflected in the PSTATE.E in AArch32 context.
>
> A "fun" problem with emulating setend is that it will not always work
> unless we emulate the entire instruction set when userspace wants to be
> in an unsupported endianness.
>
> For implementations which are not bi-endian at EL0 (i.e. where
> ID_AA64MMFR0_EL1.BigEndEL0 == 0), SCTLR_EL1.E0E has a fixed value which
> we cannot change. The field names are misleading: in a BE-only system
> ID_AA64MMFR0_EL1.{BigEnd,BigEndEL0} == {0,0} and SCTLR_EL1.{EE,E0E} are
> fixed to {1,1}.
>
> I think we need to detect when EL0 has a fixed endianness such that we
> can treat the setend instruction as undefined. Otherwise we will
> silently fail to change EL0 endianness, advance the PC, and return to
> userspace in the wrong endianness, which will be very painful to debug.
> Userspace has the option of handling the resulting SIGILL in such cases.

You are right. I missed this scenario. To add to that things get 
complicated when there are heterogeneous CPUs on the system that might 
have differing bits for BigEndEL0. I will take a look at this one. 
Thanks for pointing this out.
>
> That means we need to be able to fail to transition into INSN_EMULATE
> mode as we currently can when transitioning to INSN_HW.
>
>> This patch also restores the native endianness for the execution of signal
>> handlers, since the process could have changed the endianness.
>>
>> Signed-off-by: Suzuki K. Poulose <suzuki.poulose@arm.com>
>> ---
>>   Documentation/arm64/legacy_instructions.txt |    5 ++
>>   arch/arm64/Kconfig                          |   10 ++++
>>   arch/arm64/include/asm/ptrace.h             |    7 +++
>>   arch/arm64/kernel/armv8_deprecated.c        |   75 +++++++++++++++++++++++++++
>>   arch/arm64/kernel/signal32.c                |    5 +-
>>   5 files changed, 101 insertions(+), 1 deletion(-)
>>
>> diff --git a/Documentation/arm64/legacy_instructions.txt b/Documentation/arm64/legacy_instructions.txt
>> index a3b3da2..20e5621 100644
>> --- a/Documentation/arm64/legacy_instructions.txt
>> +++ b/Documentation/arm64/legacy_instructions.txt
>> @@ -43,3 +43,8 @@ Default: Undef (0)
>>   Node: /proc/sys/abi/cp15_barrier
>>   Status: Deprecated
>>   Default: Emulate (1)
>> +
>> +* SETEND
>> +Node: /proc/sys/abi/setend
>> +Status: Deprecated
>> +Default: Emulate (1)
>
> Given we can't always emulate SETEND, should we document "Emulate where
> possible" or something to that effect?
>
Will fix it in the next revision.

>> diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
>> index b1f9a20..c6d1fd9 100644
>> --- a/arch/arm64/Kconfig
>> +++ b/arch/arm64/Kconfig
>> @@ -540,6 +540,16 @@ config CP15_BARRIER_EMULATION
>>
>>   	  If unsure, say Y
>>
>> +config SETEND_EMULATION
>> +	bool "Emulate SETEND instruction"
>> +	help
>> +	  The SETEND instruction alters the data-endianness of the
>> +	  AArch32 EL0, and is deprecated in ARMv8.
>> +
>> +	  Say Y here to enable software emulation of the instruction
>> +	  for AArch32 userspace code.
>> +
>> +	  If unsure, say Y
>>   endif
>>
>>   endmenu
>> diff --git a/arch/arm64/include/asm/ptrace.h b/arch/arm64/include/asm/ptrace.h
>> index 41ed9e1..d6dd9fd 100644
>> --- a/arch/arm64/include/asm/ptrace.h
>> +++ b/arch/arm64/include/asm/ptrace.h
>> @@ -58,6 +58,13 @@
>>   #define COMPAT_PSR_Z_BIT	0x40000000
>>   #define COMPAT_PSR_N_BIT	0x80000000
>>   #define COMPAT_PSR_IT_MASK	0x0600fc00	/* If-Then execution state mask */
>> +
>> +#ifdef CONFIG_CPU_BIG_ENDIAN
>> +#define COMPAT_PSR_ENDSTATE	COMPAT_PSR_E_BIT
>> +#else
>> +#define COMPAT_PSR_ENDSTATE	0
>> +#endif
>> +
>>   /*
>>    * These are 'magic' values for PTRACE_PEEKUSR that return info about where a
>>    * process is located in memory.
>> diff --git a/arch/arm64/kernel/armv8_deprecated.c b/arch/arm64/kernel/armv8_deprecated.c
>> index 9054447..dc91bac 100644
>> --- a/arch/arm64/kernel/armv8_deprecated.c
>> +++ b/arch/arm64/kernel/armv8_deprecated.c
>> @@ -477,6 +477,7 @@ ret:
>>   }
>>
>>   #define SCTLR_EL1_CP15BEN 	(1 << 5)
>> +#define SCTLR_EL1_SED		(1 << 8)
>>
>>   static inline void config_sctlr_el1(u32 clear, u32 set)
>>   {
>> @@ -521,6 +522,77 @@ static struct insn_emulation_ops cp15_barrier_ops = {
>>   	.set_hw_mode = cp15_barrier_set_hw_mode,
>>   };
>>
>> +static void setend_set_hw_mode(void *enable)
>> +{
>> +	if (enable)
>> +		config_sctlr_el1(SCTLR_EL1_SED, 0);
>> +	else
>> +		config_sctlr_el1(0, SCTLR_EL1_SED);
>> +}
>> +
>> +static int compat_setend_handler(struct pt_regs *regs, u32 endian)
>
> If we s/endian/big_endian/ here we can drop the comments within the
> function as the test will be easier to read. We could also s/u32/bool/.
>
OK
>> +{
>> +	char insn[16] = "setend _e";
>
> Elsewhere (e.g. in cp15barrier_handler) we write these out in full
> rather than modifying a string on the stack. I think we should do the
> same here (we can change insn to a char * and assign the full relevant
> string in either branch).
>
> Doing so will mean grepping for '"setend be"' finds this function, which
> is handy.
>
Makes sense. Thanks for the review.

Thanks
Suzuki

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

* Re: [PATCH 2/2] arm64: Emulate SETEND for AArch32 tasks
  2015-01-09 10:21       ` Suzuki K. Poulose
@ 2015-01-09 10:36         ` Mark Rutland
  -1 siblings, 0 replies; 12+ messages in thread
From: Mark Rutland @ 2015-01-09 10:36 UTC (permalink / raw)
  To: Suzuki K. Poulose
  Cc: linux-arm-kernel, yexl, Catalin Marinas, Will Deacon,
	linux-kernel, leo.yan

On Fri, Jan 09, 2015 at 10:21:00AM +0000, Suzuki K. Poulose wrote:
> On 08/01/15 18:43, Mark Rutland wrote:
> > Hi Suzuki,
> >
> > On Wed, Jan 07, 2015 at 04:16:45PM +0000, Suzuki K. Poulose wrote:
> >> From: "Suzuki K. Poulose" <suzuki.poulose@arm.com>
> >>
> >> Emulate deprecated 'setend' instruction for AArch32 bit tasks.
> >>
> >> 	setend [le/be] - Sets the endianness of EL0
> >>
> >> The hardware support for the instruction can be enabled by setting the
> >> SCTLR_EL1.SED bit. Like the other emulated instructions it is controlled by
> >> an entry in /proc/sys/abi/. For more information see :
> >> 	Documentation/arm64/legacy_instructions.txt
> >>
> >> The instruction is emulated by setting/clearing the SPSR_EL1.E bit, which
> >> will be reflected in the PSTATE.E in AArch32 context.
> >
> > A "fun" problem with emulating setend is that it will not always work
> > unless we emulate the entire instruction set when userspace wants to be
> > in an unsupported endianness.
> >
> > For implementations which are not bi-endian at EL0 (i.e. where
> > ID_AA64MMFR0_EL1.BigEndEL0 == 0), SCTLR_EL1.E0E has a fixed value which
> > we cannot change. The field names are misleading: in a BE-only system
> > ID_AA64MMFR0_EL1.{BigEnd,BigEndEL0} == {0,0} and SCTLR_EL1.{EE,E0E} are
> > fixed to {1,1}.
> >
> > I think we need to detect when EL0 has a fixed endianness such that we
> > can treat the setend instruction as undefined. Otherwise we will
> > silently fail to change EL0 endianness, advance the PC, and return to
> > userspace in the wrong endianness, which will be very painful to debug.
> > Userspace has the option of handling the resulting SIGILL in such cases.
> 
> You are right. I missed this scenario. To add to that things get 
> complicated when there are heterogeneous CPUs on the system that might 
> have differing bits for BigEndEL0. I will take a look at this one. 
> Thanks for pointing this out.

As I mention above the naming of {BigEnd,BigEndEL0} is misleading, as
the describe mixed endian support rather than big endian support.

For example, if all CPUs have ID_AA64MMFR0_EL1.BigEndEL0 == 0 the
endianness at EL0 is fixed, but that endianness may be LE or BE.

Thus you will need to check whether any CPU has
ID_AA64MMFR0_EL1.BigEndEL0 == 0, rather than whether the value of this
field differs across CPUs.

Cheers,
Mark.

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

* [PATCH 2/2] arm64: Emulate SETEND for AArch32 tasks
@ 2015-01-09 10:36         ` Mark Rutland
  0 siblings, 0 replies; 12+ messages in thread
From: Mark Rutland @ 2015-01-09 10:36 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Jan 09, 2015 at 10:21:00AM +0000, Suzuki K. Poulose wrote:
> On 08/01/15 18:43, Mark Rutland wrote:
> > Hi Suzuki,
> >
> > On Wed, Jan 07, 2015 at 04:16:45PM +0000, Suzuki K. Poulose wrote:
> >> From: "Suzuki K. Poulose" <suzuki.poulose@arm.com>
> >>
> >> Emulate deprecated 'setend' instruction for AArch32 bit tasks.
> >>
> >> 	setend [le/be] - Sets the endianness of EL0
> >>
> >> The hardware support for the instruction can be enabled by setting the
> >> SCTLR_EL1.SED bit. Like the other emulated instructions it is controlled by
> >> an entry in /proc/sys/abi/. For more information see :
> >> 	Documentation/arm64/legacy_instructions.txt
> >>
> >> The instruction is emulated by setting/clearing the SPSR_EL1.E bit, which
> >> will be reflected in the PSTATE.E in AArch32 context.
> >
> > A "fun" problem with emulating setend is that it will not always work
> > unless we emulate the entire instruction set when userspace wants to be
> > in an unsupported endianness.
> >
> > For implementations which are not bi-endian at EL0 (i.e. where
> > ID_AA64MMFR0_EL1.BigEndEL0 == 0), SCTLR_EL1.E0E has a fixed value which
> > we cannot change. The field names are misleading: in a BE-only system
> > ID_AA64MMFR0_EL1.{BigEnd,BigEndEL0} == {0,0} and SCTLR_EL1.{EE,E0E} are
> > fixed to {1,1}.
> >
> > I think we need to detect when EL0 has a fixed endianness such that we
> > can treat the setend instruction as undefined. Otherwise we will
> > silently fail to change EL0 endianness, advance the PC, and return to
> > userspace in the wrong endianness, which will be very painful to debug.
> > Userspace has the option of handling the resulting SIGILL in such cases.
> 
> You are right. I missed this scenario. To add to that things get 
> complicated when there are heterogeneous CPUs on the system that might 
> have differing bits for BigEndEL0. I will take a look at this one. 
> Thanks for pointing this out.

As I mention above the naming of {BigEnd,BigEndEL0} is misleading, as
the describe mixed endian support rather than big endian support.

For example, if all CPUs have ID_AA64MMFR0_EL1.BigEndEL0 == 0 the
endianness at EL0 is fixed, but that endianness may be LE or BE.

Thus you will need to check whether any CPU has
ID_AA64MMFR0_EL1.BigEndEL0 == 0, rather than whether the value of this
field differs across CPUs.

Cheers,
Mark.

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

end of thread, other threads:[~2015-01-09 10:37 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-01-07 16:16 [PATCH 0/2] Support deprecated SETEND instruction for AArch32 Suzuki K. Poulose
2015-01-07 16:16 ` Suzuki K. Poulose
2015-01-07 16:16 ` [PATCH 1/2] arm64: Consolidate hotplug notifier for instruction emulation Suzuki K. Poulose
2015-01-07 16:16   ` Suzuki K. Poulose
2015-01-07 16:16 ` [PATCH 2/2] arm64: Emulate SETEND for AArch32 tasks Suzuki K. Poulose
2015-01-07 16:16   ` Suzuki K. Poulose
2015-01-08 18:43   ` Mark Rutland
2015-01-08 18:43     ` Mark Rutland
2015-01-09 10:21     ` Suzuki K. Poulose
2015-01-09 10:21       ` Suzuki K. Poulose
2015-01-09 10:36       ` Mark Rutland
2015-01-09 10:36         ` Mark Rutland

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.