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(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 } 56