Skip to contentSkip to conversation

parisc: Add static branch / JUMP_LABEL feature

PATCH In review Helge Deller 3 participants 4 messages May 1, 2019 – May 3, 2019

Subsystems (2)
lore
Share & tools
lore

Helge Deller

author maintainer
#0 lore raw

PATCH 1/1 parisc: Add static branch / JUMP_LABEL feature

arch/parisc/Kconfig +2 -0
index 49212f31b461..bdd4fea0150b 100644
@@ -45,6 +45,8 @@ config PARISC
 	select HAVE_DEBUG_STACKOVERFLOW
 	select HAVE_ARCH_AUDITSYSCALL
 	select HAVE_ARCH_HASH
+	select HAVE_ARCH_JUMP_LABEL
+	select HAVE_ARCH_JUMP_LABEL_RELATIVE
 	select HAVE_ARCH_SECCOMP_FILTER
 	select HAVE_ARCH_TRACEHOOK
 	select HAVE_REGS_AND_STACK_ACCESS_API
arch/parisc/include/asm/jump_label.h new file +43 -0

43 lines not on this page · raw message

arch/parisc/kernel/Makefile +1 -0
index b818b28c8a99..fc0df5c44468 100644
@@ -33,5 +33,6 @@ obj-$(CONFIG_64BIT)	+= perf.o perf_asm.o $(obj64-y)
 obj-$(CONFIG_PARISC_CPU_TOPOLOGY)	+= topology.o
 obj-$(CONFIG_FUNCTION_TRACER)		+= ftrace.o
 obj-$(CONFIG_FUNCTION_GRAPH_TRACER)	+= ftrace.o
+obj-$(CONFIG_JUMP_LABEL)		+= jump_label.o
 obj-$(CONFIG_KGDB)			+= kgdb.o
 obj-$(CONFIG_KPROBES)			+= kprobes.o
arch/parisc/kernel/jump_label.c new file +37 -0
new file mode 100644
index 000000000000..0d077c6d3ca7
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2019 Helge Deller <[email protected]>
+ *
+ * Based on arch/arm64/kernel/jump_label.c
+ */
+#include <linux/kernel.h>
+#include <linux/jump_label.h>
+#include <asm/alternative.h>
+#include <asm/patch.h>
+
+void arch_jump_label_transform(struct jump_entry *entry,
+			       enum jump_label_type type)
+{
+	void *addr = (void *)jump_entry_code(entry);
+	u32 insn;
+
+	if (type == JUMP_LABEL_JMP) {
+		void *target = (void *)jump_entry_target(entry);
+		unsigned len = target - addr;
+		insn = 0xe8000002 + (len-2)*8; /* "b,n .+8" */
+	} else {
+		insn = INSN_NOP;
+	}
+
+	patch_text(addr, insn); // nosync ?
+}
+
+void arch_jump_label_transform_static(struct jump_entry *entry,
+				      enum jump_label_type type)
+{
+	/*
+	 * We use the architected NOP in arch_static_branch, so there's no
+	 * need to patch an identical NOP over the top of it here. The core
+	 * will call arch_jump_label_transform from a module notifier if the
+	 * NOP needs to be replaced by a branch.
+	 */
+}
arch/parisc/kernel/vmlinux.lds.S +3 -0
index c3b1b9c24ede..a8be7a47fcc0 100644
@@ -18,6 +18,9 @@
 				*(.data..vm0.pgd) \
 				*(.data..vm0.pte)
 
+/* No __ro_after_init data in the .rodata section - which will always be ro */
+#define RO_AFTER_INIT_DATA
+
 #include <asm-generic/vmlinux.lds.h>
 
 /* needed for the processor specific cache alignment size */
#1 lore raw

Hi Helge,

Quoted 91 lines · Helge Deller
arch/parisc/Kconfig +2 -0
index 49212f31b461..bdd4fea0150b 100644
@@ -45,6 +45,8 @@ config PARISC
 	select HAVE_DEBUG_STACKOVERFLOW
 	select HAVE_ARCH_AUDITSYSCALL
 	select HAVE_ARCH_HASH
+	select HAVE_ARCH_JUMP_LABEL
+	select HAVE_ARCH_JUMP_LABEL_RELATIVE
 	select HAVE_ARCH_SECCOMP_FILTER
 	select HAVE_ARCH_TRACEHOOK
 	select HAVE_REGS_AND_STACK_ACCESS_API
arch/parisc/include/asm/jump_label.h new file +43 -0
new file mode 100644
index 000000000000..2d82368b6ed3
@@ -0,0 +1,43 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _ASM_PARISC_JUMP_LABEL_H
+#define _ASM_PARISC_JUMP_LABEL_H
+
+#ifndef __ASSEMBLY__
+
+#include <linux/types.h>
+#include <asm/assembly.h>
+
+#define JUMP_LABEL_NOP_SIZE 4
+
+static __always_inline bool arch_static_branch(struct static_key *key, bool branch)
+{
+	asm_volatile_goto("1:\n\t"
+		 "nop\n\t"
+		 ".pushsection __jump_table,  \"aw\"\n\t"
+		 ".word 1b - ., %l[l_yes] - .\n\t"
+		 __stringify(ASM_ULONG_INSN) " %c0\n\t"
+		 ".popsection\n\t"
+		 : :  "i" (&((char *)key)[branch]) :  : l_yes);
+
+	return false;
+l_yes:
+	return true;
+}
+
+static __always_inline bool arch_static_branch_jump(struct static_key *key, bool branch)
+{
+	asm_volatile_goto("1:\n\t"
+		 "b,n %l[l_yes]\n\t"
+		 ".pushsection __jump_table,  \"aw\"\n\t"
+		 ".word 1b - ., %l[l_yes] - .\n\t"
+		 __stringify(ASM_ULONG_INSN) " %c0\n\t"
+		 ".popsection\n\t"
+		 : :  "i" (&((char *)key)[branch]) :  : l_yes);
+
+	return false;
+l_yes:
+	return true;
+}
+
+#endif  /* __ASSEMBLY__ */
+#endif
arch/parisc/kernel/Makefile +1 -0
index b818b28c8a99..fc0df5c44468 100644
@@ -33,5 +33,6 @@ obj-$(CONFIG_64BIT)	+= perf.o perf_asm.o $(obj64-y)
 obj-$(CONFIG_PARISC_CPU_TOPOLOGY)	+= topology.o
 obj-$(CONFIG_FUNCTION_TRACER)		+= ftrace.o
 obj-$(CONFIG_FUNCTION_GRAPH_TRACER)	+= ftrace.o
+obj-$(CONFIG_JUMP_LABEL)		+= jump_label.o
 obj-$(CONFIG_KGDB)			+= kgdb.o
 obj-$(CONFIG_KPROBES)			+= kprobes.o
arch/parisc/kernel/jump_label.c new file +10 -0
new file mode 100644
index 000000000000..0d077c6d3ca7
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2019 Helge Deller <[email protected]>
+ *
+ * Based on arch/arm64/kernel/jump_label.c
+ */
+#include <linux/kernel.h>
+#include <linux/jump_label.h>
+#include <asm/alternative.h>
+#include <asm/patch.h>
+

arch/parisc/kernel/jump_label.c line 20

Quoted 10 lines
arch/parisc/kernel/jump_label.c new file +10 -0
+void arch_jump_label_transform(struct jump_entry *entry,
+			       enum jump_label_type type)
+{
+	void *addr = (void *)jump_entry_code(entry);
+	u32 insn;
+
+	if (type == JUMP_LABEL_JMP) {
+		void *target = (void *)jump_entry_target(entry);
+		unsigned len = target - addr;
+		insn = 0xe8000002 + (len-2)*8; /* "b,n .+8" */

I don't know the maximum jump distance here that could be encountered, but this won't work for negative offsets and offsets > 2^11 bits due to the weird immediate encoding PA-RISC uses. I think this should use proper bit shifting to match the immediate encoding and have a BUG_ON(len < $MAX_NEG_DISTANCE || len > $MAX_POS_DISTANCE) to make sure we're not patching invalid branch instructions into the Kernel.

Quoted 31 lines
arch/parisc/kernel/jump_label.c new file +17 -0
+	} else {
+		insn = INSN_NOP;
+	}
+
+	patch_text(addr, insn); // nosync ?
+}
+
+void arch_jump_label_transform_static(struct jump_entry *entry,
+				      enum jump_label_type type)
+{
+	/*
+	 * We use the architected NOP in arch_static_branch, so there's no
+	 * need to patch an identical NOP over the top of it here. The core
+	 * will call arch_jump_label_transform from a module notifier if the
+	 * NOP needs to be replaced by a branch.
+	 */
+}
arch/parisc/kernel/vmlinux.lds.S +3 -0
index c3b1b9c24ede..a8be7a47fcc0 100644
@@ -18,6 +18,9 @@
 				*(.data..vm0.pgd) \
 				*(.data..vm0.pte)
 
+/* No __ro_after_init data in the .rodata section - which will always be ro */
+#define RO_AFTER_INIT_DATA
+
 #include <asm-generic/vmlinux.lds.h>
 
 /* needed for the processor specific cache alignment size */
author maintainer
#2 lore raw

PATCH 1/1 parisc: Add static branch and JUMP_LABEL feature (v2)

v1: Initial patch
v2: Fixes, correctly encode branch instruction, check distance, check on 32-
and 64-bit kernel

arch/parisc/Kconfig +2 -0
index 26c215570adf..c971256a74d2 100644
@@ -45,6 +45,8 @@ config PARISC
 	select HAVE_DEBUG_STACKOVERFLOW
 	select HAVE_ARCH_AUDITSYSCALL
 	select HAVE_ARCH_HASH
+	select HAVE_ARCH_JUMP_LABEL
+	select HAVE_ARCH_JUMP_LABEL_RELATIVE
 	select HAVE_ARCH_SECCOMP_FILTER
 	select HAVE_ARCH_TRACEHOOK
 	select HAVE_REGS_AND_STACK_ACCESS_API
arch/parisc/include/asm/jump_label.h new file +43 -0

43 lines not on this page · raw message

arch/parisc/kernel/Makefile +1 -0
index b818b28c8a99..fc0df5c44468 100644
@@ -33,5 +33,6 @@ obj-$(CONFIG_64BIT)	+= perf.o perf_asm.o $(obj64-y)
 obj-$(CONFIG_PARISC_CPU_TOPOLOGY)	+= topology.o
 obj-$(CONFIG_FUNCTION_TRACER)		+= ftrace.o
 obj-$(CONFIG_FUNCTION_GRAPH_TRACER)	+= ftrace.o
+obj-$(CONFIG_JUMP_LABEL)		+= jump_label.o
 obj-$(CONFIG_KGDB)			+= kgdb.o
 obj-$(CONFIG_KPROBES)			+= kprobes.o
arch/parisc/kernel/jump_label.c new file +55 -0

55 lines not on this page · raw message

arch/parisc/kernel/vmlinux.lds.S +3 -0
index c3b1b9c24ede..a8be7a47fcc0 100644
@@ -18,6 +18,9 @@
 				*(.data..vm0.pgd) \
 				*(.data..vm0.pte)
 
+/* No __ro_after_init data in the .rodata section - which will always be ro */
+#define RO_AFTER_INIT_DATA
+
 #include <asm-generic/vmlinux.lds.h>
 
 /* needed for the processor specific cache alignment size */
#3 lore raw

Re: [PATCH] parisc: Add static branch and JUMP_LABEL feature (v2)

arch/parisc/kernel/jump_label.c line 35

Quoted 8 lines · Helge Deller
arch/parisc/kernel/jump_label.c new file +8 -0
+		void *target = (void *)jump_entry_target(entry);
+		int distance = target - addr;
+		/*
+		 * Encode the PA1.1 "b,n" instruction with a 17-bit
+		 * displacement.  In case we hit the BUG(), we could use
+		 * another branch instruction with a 22-bit displacement on
+		 * 64-bit CPUs instead. But this seems sufficient for now.
+		 */

Just a note on the comment.  The branch instruction with 22-bit displacement uses the return pointer register %rp.  It is available on 32 and 64-bit PA 2.0 machines but one would have to clobber %rp, or save and restore it on stack. The former would cause %rp to be saved and restored in the function's prologue and epilogue, respectively.

Dave

Signature · 1 line
John David Anglin  [email protected]