diff options
author | Max Filippov <jcmvbkbc@gmail.com> | 2018-12-20 06:48:37 +0300 |
---|---|---|
committer | Max Filippov <jcmvbkbc@gmail.com> | 2018-12-21 01:44:38 +0300 |
commit | 64711f9a47d4defa90417f5e8db8ed0060bc3275 (patch) | |
tree | 78a9fbb468c6b667ea99b57e6563689792b285d3 /arch/xtensa/include | |
parent | af5395c214c15c18de3decf2229373a8c88c4fde (diff) | |
download | linux-64711f9a47d4defa90417f5e8db8ed0060bc3275.tar.xz |
xtensa: implement jump_label support
Use 3-byte 'nop' and 'j' instructions that are always present. Don't let
assembler mark a spot right after patchable 'j' instruction as
unreachable and later put literals or padding bytes there. Add separate
implementations of patch_text for SMP and UP cases, avoiding use of
atomics on UP.
Signed-off-by: Max Filippov <jcmvbkbc@gmail.com>
Diffstat (limited to 'arch/xtensa/include')
-rw-r--r-- | arch/xtensa/include/asm/jump_label.h | 65 |
1 files changed, 65 insertions, 0 deletions
diff --git a/arch/xtensa/include/asm/jump_label.h b/arch/xtensa/include/asm/jump_label.h new file mode 100644 index 000000000000..c812bf85021c --- /dev/null +++ b/arch/xtensa/include/asm/jump_label.h @@ -0,0 +1,65 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright (C) 2018 Cadence Design Systems Inc. */ + +#ifndef _ASM_XTENSA_JUMP_LABEL_H +#define _ASM_XTENSA_JUMP_LABEL_H + +#ifndef __ASSEMBLY__ + +#include <linux/types.h> + +#define JUMP_LABEL_NOP_SIZE 3 + +static __always_inline bool arch_static_branch(struct static_key *key, + bool branch) +{ + asm_volatile_goto("1:\n\t" + "_nop\n\t" + ".pushsection __jump_table, \"aw\"\n\t" + ".word 1b, %l[l_yes], %c0\n\t" + ".popsection\n\t" + : : "i" (&((char *)key)[branch]) : : l_yes); + + return false; +l_yes: + return true; +} + +static __always_inline bool arch_static_branch_jump(struct static_key *key, + bool branch) +{ + /* + * Xtensa assembler will mark certain points in the code + * as unreachable, so that later assembler or linker relaxation + * passes could use them. A spot right after the J instruction + * is one such point. Assembler and/or linker may insert padding + * or literals here, breaking code flow in case the J instruction + * is later replaced with NOP. Put a label right after the J to + * make it reachable and wrap both into a no-transform block + * to avoid any assembler interference with this. + */ + asm_volatile_goto("1:\n\t" + ".begin no-transform\n\t" + "_j %l[l_yes]\n\t" + "2:\n\t" + ".end no-transform\n\t" + ".pushsection __jump_table, \"aw\"\n\t" + ".word 1b, %l[l_yes], %c0\n\t" + ".popsection\n\t" + : : "i" (&((char *)key)[branch]) : : l_yes); + + return false; +l_yes: + return true; +} + +typedef u32 jump_label_t; + +struct jump_entry { + jump_label_t code; + jump_label_t target; + jump_label_t key; +}; + +#endif /* __ASSEMBLY__ */ +#endif |