diff options
Diffstat (limited to 'arch/openrisc/kernel/jump_label.c')
-rw-r--r-- | arch/openrisc/kernel/jump_label.c | 51 |
1 files changed, 51 insertions, 0 deletions
diff --git a/arch/openrisc/kernel/jump_label.c b/arch/openrisc/kernel/jump_label.c new file mode 100644 index 000000000000..ab7137c23b46 --- /dev/null +++ b/arch/openrisc/kernel/jump_label.c @@ -0,0 +1,51 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2025 Chen Miao + * + * Based on arch/arm/kernel/jump_label.c + */ +#include <linux/jump_label.h> +#include <linux/kernel.h> +#include <linux/memory.h> +#include <asm/bug.h> +#include <asm/cacheflush.h> +#include <asm/text-patching.h> + +bool arch_jump_label_transform_queue(struct jump_entry *entry, + enum jump_label_type type) +{ + void *addr = (void *)jump_entry_code(entry); + u32 insn; + + if (type == JUMP_LABEL_JMP) { + long offset; + + offset = jump_entry_target(entry) - jump_entry_code(entry); + /* + * The actual maximum range of the l.j instruction's offset is -134,217,728 + * ~ 134,217,724 (sign 26-bit imm). + * For the original jump range, we need to right-shift N by 2 to obtain the + * instruction's offset. + */ + WARN_ON_ONCE(offset < -134217728 || offset > 134217724); + + /* 26bit imm mask */ + offset = (offset >> 2) & 0x03ffffff; + + insn = offset; + } else { + insn = OPENRISC_INSN_NOP; + } + + if (early_boot_irqs_disabled) + copy_to_kernel_nofault(addr, &insn, sizeof(insn)); + else + patch_insn_write(addr, insn); + + return true; +} + +void arch_jump_label_transform_apply(void) +{ + kick_all_cpus_sync(); +} |