csky: Add jump-label implementation
authorGuo Ren <guoren@linux.alibaba.com>
Mon, 18 Apr 2022 13:01:54 +0000 (21:01 +0800)
committerGuo Ren <guoren@linux.alibaba.com>
Sat, 30 Jul 2022 15:12:03 +0000 (11:12 -0400)
Add jump-label implementation for static branch

Signed-off-by: Guo Ren <guoren@linux.alibaba.com>
Signed-off-by: Guo Ren <guoren@kernel.org>
arch/csky/Kconfig
arch/csky/include/asm/jump_label.h [new file with mode: 0644]
arch/csky/kernel/Makefile
arch/csky/kernel/jump_label.c [new file with mode: 0644]

index 21d72b078eefc95ac9277f203e07cc20029599ed..41d7d614f7a25e69779abb4705a4010f9b7d7ba0 100644 (file)
@@ -40,6 +40,8 @@ config CSKY
        select GX6605S_TIMER if CPU_CK610
        select HAVE_ARCH_TRACEHOOK
        select HAVE_ARCH_AUDITSYSCALL
+       select HAVE_ARCH_JUMP_LABEL if !CPU_CK610
+       select HAVE_ARCH_JUMP_LABEL_RELATIVE
        select HAVE_ARCH_MMAP_RND_BITS
        select HAVE_ARCH_SECCOMP_FILTER
        select HAVE_CONTEXT_TRACKING
diff --git a/arch/csky/include/asm/jump_label.h b/arch/csky/include/asm/jump_label.h
new file mode 100644 (file)
index 0000000..d488ba6
--- /dev/null
@@ -0,0 +1,47 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef __ASM_CSKY_JUMP_LABEL_H
+#define __ASM_CSKY_JUMP_LABEL_H
+
+#ifndef __ASSEMBLY__
+
+#include <linux/types.h>
+
+#define JUMP_LABEL_NOP_SIZE 4
+
+static __always_inline bool arch_static_branch(struct static_key *key,
+                                              bool branch)
+{
+       asm_volatile_goto(
+               "1:     nop32                                   \n"
+               "       .pushsection    __jump_table, \"aw\"    \n"
+               "       .align          2                       \n"
+               "       .long           1b - ., %l[label] - .   \n"
+               "       .long           %0 - .                  \n"
+               "       .popsection                             \n"
+               :  :  "i"(&((char *)key)[branch]) :  : label);
+
+       return false;
+label:
+       return true;
+}
+
+static __always_inline bool arch_static_branch_jump(struct static_key *key,
+                                                   bool branch)
+{
+       asm_volatile_goto(
+               "1:     bsr32           %l[label]               \n"
+               "       .pushsection    __jump_table, \"aw\"    \n"
+               "       .align          2                       \n"
+               "       .long           1b - ., %l[label] - .   \n"
+               "       .long           %0 - .                  \n"
+               "       .popsection                             \n"
+               :  :  "i"(&((char *)key)[branch]) :  : label);
+
+       return false;
+label:
+       return true;
+}
+
+#endif  /* __ASSEMBLY__ */
+#endif /* __ASM_CSKY_JUMP_LABEL_H */
index 4eb41421ca5b467205a09e5b926252ce93b497d1..6f14c924b20d261f92280f9cc40c9da9359db034 100644 (file)
@@ -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 (file)
index 0000000..d0e8b21
--- /dev/null
@@ -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);
+}