xref: /linux/arch/openrisc/kernel/jump_label.c (revision 742adaa16db994ba1748465b95548e2f28aa18ca)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright (C) 2025 Chen Miao
4  *
5  * Based on arch/arm/kernel/jump_label.c
6  */
7 #include <linux/jump_label.h>
8 #include <linux/kernel.h>
9 #include <linux/memory.h>
10 #include <asm/bug.h>
11 #include <asm/cacheflush.h>
12 #include <asm/text-patching.h>
13 
arch_jump_label_transform_queue(struct jump_entry * entry,enum jump_label_type type)14 bool arch_jump_label_transform_queue(struct jump_entry *entry,
15 				     enum jump_label_type type)
16 {
17 	void *addr = (void *)jump_entry_code(entry);
18 	u32 insn;
19 
20 	if (type == JUMP_LABEL_JMP) {
21 		long offset;
22 
23 		offset = jump_entry_target(entry) - jump_entry_code(entry);
24 		/*
25 		 * The actual maximum range of the l.j instruction's offset is -134,217,728
26 		 * ~ 134,217,724 (sign 26-bit imm).
27 		 * For the original jump range, we need to right-shift N by 2 to obtain the
28 		 * instruction's offset.
29 		 */
30 		WARN_ON_ONCE(offset < -134217728 || offset > 134217724);
31 
32 		/* 26bit imm mask */
33 		offset = (offset >> 2) & 0x03ffffff;
34 
35 		insn = offset;
36 	} else {
37 		insn = OPENRISC_INSN_NOP;
38 	}
39 
40 	if (early_boot_irqs_disabled)
41 		copy_to_kernel_nofault(addr, &insn, sizeof(insn));
42 	else
43 		patch_insn_write(addr, insn);
44 
45 	return true;
46 }
47 
arch_jump_label_transform_apply(void)48 void arch_jump_label_transform_apply(void)
49 {
50 	kick_all_cpus_sync();
51 }
52