diff options
author | Helge Deller <deller@gmx.de> | 2019-05-03 23:51:00 +0200 |
---|---|---|
committer | Helge Deller <deller@gmx.de> | 2019-05-06 00:10:03 +0200 |
commit | 62217beb394e654bbd2bb87c533dadd2d8bf62c6 (patch) | |
tree | 3adcd75c34fa8d4aa3836a5e30e0d8a72995a95a /arch/parisc/kernel/jump_label.c | |
parent | bdca5d64ee92abeacd6dada0bc6f6f8e6350dd67 (diff) | |
download | talos-op-linux-62217beb394e654bbd2bb87c533dadd2d8bf62c6.tar.gz talos-op-linux-62217beb394e654bbd2bb87c533dadd2d8bf62c6.zip |
parisc: Add static branch and JUMP_LABEL feature
Signed-off-by: Helge Deller <deller@gmx.de>
Diffstat (limited to 'arch/parisc/kernel/jump_label.c')
-rw-r--r-- | arch/parisc/kernel/jump_label.c | 55 |
1 files changed, 55 insertions, 0 deletions
diff --git a/arch/parisc/kernel/jump_label.c b/arch/parisc/kernel/jump_label.c new file mode 100644 index 000000000000..d2f3cb12e282 --- /dev/null +++ b/arch/parisc/kernel/jump_label.c @@ -0,0 +1,55 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2019 Helge Deller <deller@gmx.de> + * + * Based on arch/arm64/kernel/jump_label.c + */ +#include <linux/kernel.h> +#include <linux/jump_label.h> +#include <linux/bug.h> +#include <asm/alternative.h> +#include <asm/patch.h> + +static inline int reassemble_17(int as17) +{ + return (((as17 & 0x10000) >> 16) | + ((as17 & 0x0f800) << 5) | + ((as17 & 0x00400) >> 8) | + ((as17 & 0x003ff) << 3)); +} + +void arch_jump_label_transform(struct jump_entry *entry, + enum jump_label_type type) +{ + void *addr = (void *)jump_entry_code(entry); + u32 insn; + + if (type == JUMP_LABEL_JMP) { + void *target = (void *)jump_entry_target(entry); + int distance = target - addr; + /* + * Encode the PA1.1 "b,n" instruction with a 17-bit + * displacement. In case we hit the BUG(), we could use + * another branch instruction with a 22-bit displacement on + * 64-bit CPUs instead. But this seems sufficient for now. + */ + distance -= 8; + BUG_ON(distance > 262143 || distance < -262144); + insn = 0xe8000002 | reassemble_17(distance >> 2); + } else { + insn = INSN_NOP; + } + + patch_text(addr, insn); +} + +void arch_jump_label_transform_static(struct jump_entry *entry, + enum jump_label_type type) +{ + /* + * We use the architected NOP in arch_static_branch, so there's no + * need to patch an identical NOP over the top of it here. The core + * will call arch_jump_label_transform from a module notifier if the + * NOP needs to be replaced by a branch. + */ +} |