summaryrefslogtreecommitdiff
path: root/arch/csky/kernel
diff options
context:
space:
mode:
authorGuo Ren <guoren@linux.alibaba.com>2022-04-18 21:01:54 +0800
committerGuo Ren <guoren@linux.alibaba.com>2022-07-30 11:12:03 -0400
commit4e8bb4ba5a558159ffbfa7e60322a1c151c3903c (patch)
treec7dd06510ade6d45e5d67799ada379795d489437 /arch/csky/kernel
parent01ab4649ef5a377074d2ad4bf2ba6d2270d2807b (diff)
csky: Add jump-label implementation
Add jump-label implementation for static branch Signed-off-by: Guo Ren <guoren@linux.alibaba.com> Signed-off-by: Guo Ren <guoren@kernel.org>
Diffstat (limited to 'arch/csky/kernel')
-rw-r--r--arch/csky/kernel/Makefile1
-rw-r--r--arch/csky/kernel/jump_label.c54
2 files changed, 55 insertions, 0 deletions
diff --git a/arch/csky/kernel/Makefile b/arch/csky/kernel/Makefile
index 4eb41421ca5b..6f14c924b20d 100644
--- a/arch/csky/kernel/Makefile
+++ b/arch/csky/kernel/Makefile
@@ -13,6 +13,7 @@ obj-$(CONFIG_STACKTRACE) += stacktrace.o
obj-$(CONFIG_CSKY_PMU_V1) += perf_event.o
obj-$(CONFIG_PERF_EVENTS) += perf_callchain.o
obj-$(CONFIG_HAVE_PERF_REGS) += perf_regs.o
+obj-$(CONFIG_JUMP_LABEL) += jump_label.o
ifdef CONFIG_FUNCTION_TRACER
CFLAGS_REMOVE_ftrace.o = $(CC_FLAGS_FTRACE)
diff --git a/arch/csky/kernel/jump_label.c b/arch/csky/kernel/jump_label.c
new file mode 100644
index 000000000000..d0e8b21447e1
--- /dev/null
+++ b/arch/csky/kernel/jump_label.c
@@ -0,0 +1,54 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include <linux/jump_label.h>
+#include <linux/kernel.h>
+#include <linux/memory.h>
+#include <linux/mutex.h>
+#include <linux/uaccess.h>
+#include <asm/cacheflush.h>
+
+#define NOP32_HI 0xc400
+#define NOP32_LO 0x4820
+#define BSR_LINK 0xe000
+
+void arch_jump_label_transform(struct jump_entry *entry,
+ enum jump_label_type type)
+{
+ unsigned long addr = jump_entry_code(entry);
+ u16 insn[2];
+ int ret = 0;
+
+ if (type == JUMP_LABEL_JMP) {
+ long offset = jump_entry_target(entry) - jump_entry_code(entry);
+
+ if (WARN_ON(offset & 1 || offset < -67108864 || offset >= 67108864))
+ return;
+
+ offset = offset >> 1;
+
+ insn[0] = BSR_LINK |
+ ((uint16_t)((unsigned long) offset >> 16) & 0x3ff);
+ insn[1] = (uint16_t)((unsigned long) offset & 0xffff);
+ } else {
+ insn[0] = NOP32_HI;
+ insn[1] = NOP32_LO;
+ }
+
+ ret = copy_to_kernel_nofault((void *)addr, insn, 4);
+ WARN_ON(ret);
+
+ flush_icache_range(addr, addr + 4);
+}
+
+void arch_jump_label_transform_static(struct jump_entry *entry,
+ enum jump_label_type type)
+{
+ /*
+ * We use the same instructions in the arch_static_branch and
+ * arch_static_branch_jump inline functions, so there's no
+ * need to patch them up here.
+ * The core will call arch_jump_label_transform when those
+ * instructions need to be replaced.
+ */
+ arch_jump_label_transform(entry, type);
+}