xref: /linux/arch/csky/kernel/jump_label.c (revision 4f2c0a4acffbec01079c28f839422e64ddeff004)
1*4e8bb4baSGuo Ren // SPDX-License-Identifier: GPL-2.0-only
2*4e8bb4baSGuo Ren 
3*4e8bb4baSGuo Ren #include <linux/jump_label.h>
4*4e8bb4baSGuo Ren #include <linux/kernel.h>
5*4e8bb4baSGuo Ren #include <linux/memory.h>
6*4e8bb4baSGuo Ren #include <linux/mutex.h>
7*4e8bb4baSGuo Ren #include <linux/uaccess.h>
8*4e8bb4baSGuo Ren #include <asm/cacheflush.h>
9*4e8bb4baSGuo Ren 
10*4e8bb4baSGuo Ren #define NOP32_HI	0xc400
11*4e8bb4baSGuo Ren #define NOP32_LO	0x4820
12*4e8bb4baSGuo Ren #define BSR_LINK	0xe000
13*4e8bb4baSGuo Ren 
arch_jump_label_transform(struct jump_entry * entry,enum jump_label_type type)14*4e8bb4baSGuo Ren void arch_jump_label_transform(struct jump_entry *entry,
15*4e8bb4baSGuo Ren 			       enum jump_label_type type)
16*4e8bb4baSGuo Ren {
17*4e8bb4baSGuo Ren 	unsigned long addr = jump_entry_code(entry);
18*4e8bb4baSGuo Ren 	u16 insn[2];
19*4e8bb4baSGuo Ren 	int ret = 0;
20*4e8bb4baSGuo Ren 
21*4e8bb4baSGuo Ren 	if (type == JUMP_LABEL_JMP) {
22*4e8bb4baSGuo Ren 		long offset = jump_entry_target(entry) - jump_entry_code(entry);
23*4e8bb4baSGuo Ren 
24*4e8bb4baSGuo Ren 		if (WARN_ON(offset & 1 || offset < -67108864 || offset >= 67108864))
25*4e8bb4baSGuo Ren 			return;
26*4e8bb4baSGuo Ren 
27*4e8bb4baSGuo Ren 		offset = offset >> 1;
28*4e8bb4baSGuo Ren 
29*4e8bb4baSGuo Ren 		insn[0] = BSR_LINK |
30*4e8bb4baSGuo Ren 			((uint16_t)((unsigned long) offset >> 16) & 0x3ff);
31*4e8bb4baSGuo Ren 		insn[1] = (uint16_t)((unsigned long) offset & 0xffff);
32*4e8bb4baSGuo Ren 	} else {
33*4e8bb4baSGuo Ren 		insn[0] = NOP32_HI;
34*4e8bb4baSGuo Ren 		insn[1] = NOP32_LO;
35*4e8bb4baSGuo Ren 	}
36*4e8bb4baSGuo Ren 
37*4e8bb4baSGuo Ren 	ret = copy_to_kernel_nofault((void *)addr, insn, 4);
38*4e8bb4baSGuo Ren 	WARN_ON(ret);
39*4e8bb4baSGuo Ren 
40*4e8bb4baSGuo Ren 	flush_icache_range(addr, addr + 4);
41*4e8bb4baSGuo Ren }
42*4e8bb4baSGuo Ren 
arch_jump_label_transform_static(struct jump_entry * entry,enum jump_label_type type)43*4e8bb4baSGuo Ren void arch_jump_label_transform_static(struct jump_entry *entry,
44*4e8bb4baSGuo Ren 				      enum jump_label_type type)
45*4e8bb4baSGuo Ren {
46*4e8bb4baSGuo Ren 	/*
47*4e8bb4baSGuo Ren 	 * We use the same instructions in the arch_static_branch and
48*4e8bb4baSGuo Ren 	 * arch_static_branch_jump inline functions, so there's no
49*4e8bb4baSGuo Ren 	 * need to patch them up here.
50*4e8bb4baSGuo Ren 	 * The core will call arch_jump_label_transform  when those
51*4e8bb4baSGuo Ren 	 * instructions need to be replaced.
52*4e8bb4baSGuo Ren 	 */
53*4e8bb4baSGuo Ren 	arch_jump_label_transform(entry, type);
54*4e8bb4baSGuo Ren }
55