|
| 1 | +// SPDX-License-Identifier: GPL-2.0+ |
| 2 | +/* |
| 3 | + * Copyright (C) 2019 Helge Deller <[email protected]> |
| 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(distance >> 2); |
| 39 | + } else { |
| 40 | + insn = INSN_NOP; |
| 41 | + } |
| 42 | + |
| 43 | + patch_text(addr, insn); |
| 44 | +} |
| 45 | + |
| 46 | +void arch_jump_label_transform_static(struct jump_entry *entry, |
| 47 | + enum jump_label_type type) |
| 48 | +{ |
| 49 | + /* |
| 50 | + * We use the architected NOP in arch_static_branch, so there's no |
| 51 | + * need to patch an identical NOP over the top of it here. The core |
| 52 | + * will call arch_jump_label_transform from a module notifier if the |
| 53 | + * NOP needs to be replaced by a branch. |
| 54 | + */ |
| 55 | +} |
0 commit comments