LoongArch: Add jump-label implementation
authorYouling Tang <tangyouling@loongson.cn>
Thu, 29 Jun 2023 12:58:44 +0000 (20:58 +0800)
committerHuacai Chen <chenhuacai@loongson.cn>
Thu, 29 Jun 2023 12:58:44 +0000 (20:58 +0800)
Add support for jump labels based on the ARM64 version.

Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Signed-off-by: Youling Tang <tangyouling@loongson.cn>
Signed-off-by: Huacai Chen <chenhuacai@loongson.cn>
Documentation/features/core/jump-labels/arch-support.txt
arch/loongarch/Kconfig
arch/loongarch/include/asm/jump_label.h [new file with mode: 0644]
arch/loongarch/kernel/Makefile
arch/loongarch/kernel/jump_label.c [new file with mode: 0644]

index 2328eada3a491a4d386f3e99f10fa8fa15219840..94d9dece580f180189a7c3ccf6974892fa46d7d4 100644 (file)
@@ -13,7 +13,7 @@
     |        csky: |  ok  |
     |     hexagon: | TODO |
     |        ia64: | TODO |
-    |   loongarch: | TODO |
+    |   loongarch: |  ok  |
     |        m68k: | TODO |
     |  microblaze: | TODO |
     |        mips: |  ok  |
index 8c7b67eca8383a2940ed30dbfd1e97475ab806e2..64cdc68022954b28ae5f258c6efaeff0413a01ba 100644 (file)
@@ -87,6 +87,8 @@ config LOONGARCH
        select GPIOLIB
        select HAS_IOPORT
        select HAVE_ARCH_AUDITSYSCALL
+       select HAVE_ARCH_JUMP_LABEL
+       select HAVE_ARCH_JUMP_LABEL_RELATIVE
        select HAVE_ARCH_MMAP_RND_BITS if MMU
        select HAVE_ARCH_SECCOMP_FILTER
        select HAVE_ARCH_TRACEHOOK
diff --git a/arch/loongarch/include/asm/jump_label.h b/arch/loongarch/include/asm/jump_label.h
new file mode 100644 (file)
index 0000000..3cea299
--- /dev/null
@@ -0,0 +1,50 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) 2023 Loongson Technology Corporation Limited
+ *
+ * Based on arch/arm64/include/asm/jump_label.h
+ */
+#ifndef __ASM_JUMP_LABEL_H
+#define __ASM_JUMP_LABEL_H
+
+#ifndef __ASSEMBLY__
+
+#include <linux/types.h>
+
+#define JUMP_LABEL_NOP_SIZE    4
+
+#define JUMP_TABLE_ENTRY                               \
+        ".pushsection  __jump_table, \"aw\"    \n\t"   \
+        ".align        3                       \n\t"   \
+        ".long         1b - ., %l[l_yes] - .   \n\t"   \
+        ".quad         %0 - .                  \n\t"   \
+        ".popsection                           \n\t"
+
+static __always_inline bool arch_static_branch(struct static_key * const key, const bool branch)
+{
+       asm_volatile_goto(
+               "1:     nop                     \n\t"
+               JUMP_TABLE_ENTRY
+               :  :  "i"(&((char *)key)[branch]) :  : l_yes);
+
+       return false;
+
+l_yes:
+       return true;
+}
+
+static __always_inline bool arch_static_branch_jump(struct static_key * const key, const bool branch)
+{
+       asm_volatile_goto(
+               "1:     b       %l[l_yes]       \n\t"
+               JUMP_TABLE_ENTRY
+               :  :  "i"(&((char *)key)[branch]) :  : l_yes);
+
+       return false;
+
+l_yes:
+       return true;
+}
+
+#endif  /* __ASSEMBLY__ */
+#endif /* __ASM_JUMP_LABEL_H */
index 9a72d91cd10497407264ee0392434ed5e9b6ebce..64ea76f60e2c6abd952df8a72650bbddcaddd0a2 100644 (file)
@@ -54,4 +54,6 @@ obj-$(CONFIG_HAVE_HW_BREAKPOINT)      += hw_breakpoint.o
 
 obj-$(CONFIG_KPROBES)          += kprobes.o kprobes_trampoline.o
 
+obj-$(CONFIG_JUMP_LABEL)       += jump_label.o
+
 CPPFLAGS_vmlinux.lds           := $(KBUILD_CFLAGS)
diff --git a/arch/loongarch/kernel/jump_label.c b/arch/loongarch/kernel/jump_label.c
new file mode 100644 (file)
index 0000000..3189121
--- /dev/null
@@ -0,0 +1,22 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2023 Loongson Technology Corporation Limited
+ *
+ * Based on arch/arm64/kernel/jump_label.c
+ */
+#include <linux/kernel.h>
+#include <linux/jump_label.h>
+#include <asm/inst.h>
+
+void arch_jump_label_transform(struct jump_entry *entry, enum jump_label_type type)
+{
+       u32 insn;
+       void *addr = (void *)jump_entry_code(entry);
+
+       if (type == JUMP_LABEL_JMP)
+               insn = larch_insn_gen_b(jump_entry_code(entry), jump_entry_target(entry));
+       else
+               insn = larch_insn_gen_nop();
+
+       larch_insn_patch_text(addr, insn);
+}