1 | // SPDX-License-Identifier: GPL-2.0+ |
---|---|
2 | /* |
3 | * Copyright (C) 2019 Helge Deller <deller@gmx.de> |
4 | * |
5 | * Based on arch/arm64/kernel/jump_label.c |
6 | */ |
7 | #include <linux/kernel.h> |
8 | #include <linux/jump_label.h> |
9 | #include <linux/bug.h> |
10 | #include <asm/alternative.h> |
11 | #include <asm/patch.h> |
12 | |
13 | static inline int reassemble_17(int as17) |
14 | { |
15 | return (((as17 & 0x10000) >> 16) | |
16 | ((as17 & 0x0f800) << 5) | |
17 | ((as17 & 0x00400) >> 8) | |
18 | ((as17 & 0x003ff) << 3)); |
19 | } |
20 | |
21 | void arch_jump_label_transform(struct jump_entry *entry, |
22 | enum jump_label_type type) |
23 | { |
24 | void *addr = (void *)jump_entry_code(entry); |
25 | u32 insn; |
26 | |
27 | if (type == JUMP_LABEL_JMP) { |
28 | void *target = (void *)jump_entry_target(entry); |
29 | int distance = target - addr; |
30 | /* |
31 | * Encode the PA1.1 "b,n" instruction with a 17-bit |
32 | * displacement. In case we hit the BUG(), we could use |
33 | * another branch instruction with a 22-bit displacement on |
34 | * 64-bit CPUs instead. But this seems sufficient for now. |
35 | */ |
36 | distance -= 8; |
37 | BUG_ON(distance > 262143 || distance < -262144); |
38 | insn = 0xe8000002 | reassemble_17(as17: distance >> 2); |
39 | } else { |
40 | insn = INSN_NOP; |
41 | } |
42 | |
43 | patch_text(addr, insn); |
44 | } |
45 |