Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

riscv: Add jump-label implementation

Add jump-label implementation based on the ARM64 version
and add CONFIG_JUMP_LABEL=y to the defconfigs.

Signed-off-by: Emil Renner Berthing <kernel@esmil.dk>
Reviewed-by: Björn Töpel <bjorn.topel@gmail.com>
Tested-by: Björn Töpel <bjorn.topel@gmail.com>
Signed-off-by: Palmer Dabbelt <palmerdabbelt@google.com>

authored by

Emil Renner Berthing and committed by
Palmer Dabbelt
ebc00dde 11a54f42

+122 -1
+1 -1
Documentation/features/core/jump-labels/arch-support.txt
··· 23 23 | openrisc: | TODO | 24 24 | parisc: | ok | 25 25 | powerpc: | ok | 26 - | riscv: | TODO | 26 + | riscv: | ok | 27 27 | s390: | ok | 28 28 | sh: | TODO | 29 29 | sparc: | ok |
+2
arch/riscv/Kconfig
··· 47 47 select GENERIC_TIME_VSYSCALL if MMU && 64BIT 48 48 select HANDLE_DOMAIN_IRQ 49 49 select HAVE_ARCH_AUDITSYSCALL 50 + select HAVE_ARCH_JUMP_LABEL 51 + select HAVE_ARCH_JUMP_LABEL_RELATIVE 50 52 select HAVE_ARCH_KASAN if MMU && 64BIT 51 53 select HAVE_ARCH_KGDB 52 54 select HAVE_ARCH_KGDB_QXFER_PKT
+1
arch/riscv/configs/defconfig
··· 17 17 CONFIG_SOC_SIFIVE=y 18 18 CONFIG_SOC_VIRT=y 19 19 CONFIG_SMP=y 20 + CONFIG_JUMP_LABEL=y 20 21 CONFIG_MODULES=y 21 22 CONFIG_MODULE_UNLOAD=y 22 23 CONFIG_NET=y
+1
arch/riscv/configs/nommu_k210_defconfig
··· 33 33 CONFIG_NR_CPUS=2 34 34 CONFIG_CMDLINE="earlycon console=ttySIF0" 35 35 CONFIG_CMDLINE_FORCE=y 36 + CONFIG_JUMP_LABEL=y 36 37 # CONFIG_BLOCK is not set 37 38 CONFIG_BINFMT_FLAT=y 38 39 # CONFIG_COREDUMP is not set
+1
arch/riscv/configs/nommu_virt_defconfig
··· 30 30 CONFIG_SMP=y 31 31 CONFIG_CMDLINE="root=/dev/vda rw earlycon=uart8250,mmio,0x10000000,115200n8 console=ttyS0" 32 32 CONFIG_CMDLINE_FORCE=y 33 + CONFIG_JUMP_LABEL=y 33 34 # CONFIG_BLK_DEV_BSG is not set 34 35 CONFIG_PARTITION_ADVANCED=y 35 36 # CONFIG_MSDOS_PARTITION is not set
+1
arch/riscv/configs/rv32_defconfig
··· 17 17 CONFIG_SOC_VIRT=y 18 18 CONFIG_ARCH_RV32I=y 19 19 CONFIG_SMP=y 20 + CONFIG_JUMP_LABEL=y 20 21 CONFIG_MODULES=y 21 22 CONFIG_MODULE_UNLOAD=y 22 23 CONFIG_NET=y
+60
arch/riscv/include/asm/jump_label.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0-only */ 2 + /* 3 + * Copyright (C) 2020 Emil Renner Berthing 4 + * 5 + * Based on arch/arm64/include/asm/jump_label.h 6 + */ 7 + #ifndef __ASM_JUMP_LABEL_H 8 + #define __ASM_JUMP_LABEL_H 9 + 10 + #ifndef __ASSEMBLY__ 11 + 12 + #include <linux/types.h> 13 + #include <asm/asm.h> 14 + 15 + #define JUMP_LABEL_NOP_SIZE 4 16 + 17 + static __always_inline bool arch_static_branch(struct static_key *key, 18 + bool branch) 19 + { 20 + asm_volatile_goto( 21 + " .option push \n\t" 22 + " .option norelax \n\t" 23 + " .option norvc \n\t" 24 + "1: nop \n\t" 25 + " .option pop \n\t" 26 + " .pushsection __jump_table, \"aw\" \n\t" 27 + " .align " RISCV_LGPTR " \n\t" 28 + " .long 1b - ., %l[label] - . \n\t" 29 + " " RISCV_PTR " %0 - . \n\t" 30 + " .popsection \n\t" 31 + : : "i"(&((char *)key)[branch]) : : label); 32 + 33 + return false; 34 + label: 35 + return true; 36 + } 37 + 38 + static __always_inline bool arch_static_branch_jump(struct static_key *key, 39 + bool branch) 40 + { 41 + asm_volatile_goto( 42 + " .option push \n\t" 43 + " .option norelax \n\t" 44 + " .option norvc \n\t" 45 + "1: jal zero, %l[label] \n\t" 46 + " .option pop \n\t" 47 + " .pushsection __jump_table, \"aw\" \n\t" 48 + " .align " RISCV_LGPTR " \n\t" 49 + " .long 1b - ., %l[label] - . \n\t" 50 + " " RISCV_PTR " %0 - . \n\t" 51 + " .popsection \n\t" 52 + : : "i"(&((char *)key)[branch]) : : label); 53 + 54 + return false; 55 + label: 56 + return true; 57 + } 58 + 59 + #endif /* __ASSEMBLY__ */ 60 + #endif /* __ASM_JUMP_LABEL_H */
+2
arch/riscv/kernel/Makefile
··· 53 53 obj-$(CONFIG_HOTPLUG_CPU) += cpu-hotplug.o 54 54 obj-$(CONFIG_KGDB) += kgdb.o 55 55 56 + obj-$(CONFIG_JUMP_LABEL) += jump_label.o 57 + 56 58 clean:
+53
arch/riscv/kernel/jump_label.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + /* 3 + * Copyright (C) 2020 Emil Renner Berthing 4 + * 5 + * Based on arch/arm64/kernel/jump_label.c 6 + */ 7 + #include <linux/jump_label.h> 8 + #include <linux/kernel.h> 9 + #include <linux/memory.h> 10 + #include <linux/mutex.h> 11 + #include <asm/bug.h> 12 + #include <asm/patch.h> 13 + 14 + #define RISCV_INSN_NOP 0x00000013U 15 + #define RISCV_INSN_JAL 0x0000006fU 16 + 17 + void arch_jump_label_transform(struct jump_entry *entry, 18 + enum jump_label_type type) 19 + { 20 + void *addr = (void *)jump_entry_code(entry); 21 + u32 insn; 22 + 23 + if (type == JUMP_LABEL_JMP) { 24 + long offset = jump_entry_target(entry) - jump_entry_code(entry); 25 + 26 + if (WARN_ON(offset & 1 || offset < -524288 || offset >= 524288)) 27 + return; 28 + 29 + insn = RISCV_INSN_JAL | 30 + (((u32)offset & GENMASK(19, 12)) << (12 - 12)) | 31 + (((u32)offset & GENMASK(11, 11)) << (20 - 11)) | 32 + (((u32)offset & GENMASK(10, 1)) << (21 - 1)) | 33 + (((u32)offset & GENMASK(20, 20)) << (31 - 20)); 34 + } else { 35 + insn = RISCV_INSN_NOP; 36 + } 37 + 38 + mutex_lock(&text_mutex); 39 + patch_text_nosync(addr, &insn, sizeof(insn)); 40 + mutex_unlock(&text_mutex); 41 + } 42 + 43 + void arch_jump_label_transform_static(struct jump_entry *entry, 44 + enum jump_label_type type) 45 + { 46 + /* 47 + * We use the same instructions in the arch_static_branch and 48 + * arch_static_branch_jump inline functions, so there's no 49 + * need to patch them up here. 50 + * The core will call arch_jump_label_transform when those 51 + * instructions need to be replaced. 52 + */ 53 + }