162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */
262306a36Sopenharmony_ci#ifndef _ASM_STATIC_CALL_H
362306a36Sopenharmony_ci#define _ASM_STATIC_CALL_H
462306a36Sopenharmony_ci
562306a36Sopenharmony_ci#include <asm/text-patching.h>
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci/*
862306a36Sopenharmony_ci * For CONFIG_HAVE_STATIC_CALL_INLINE, this is a temporary trampoline which
962306a36Sopenharmony_ci * uses the current value of the key->func pointer to do an indirect jump to
1062306a36Sopenharmony_ci * the function.  This trampoline is only used during boot, before the call
1162306a36Sopenharmony_ci * sites get patched by static_call_update().  The name of this trampoline has
1262306a36Sopenharmony_ci * a magical aspect: objtool uses it to find static call sites so it can create
1362306a36Sopenharmony_ci * the .static_call_sites section.
1462306a36Sopenharmony_ci *
1562306a36Sopenharmony_ci * For CONFIG_HAVE_STATIC_CALL, this is a permanent trampoline which
1662306a36Sopenharmony_ci * does a direct jump to the function.  The direct jump gets patched by
1762306a36Sopenharmony_ci * static_call_update().
1862306a36Sopenharmony_ci *
1962306a36Sopenharmony_ci * Having the trampoline in a special section forces GCC to emit a JMP.d32 when
2062306a36Sopenharmony_ci * it does tail-call optimization on the call; since you cannot compute the
2162306a36Sopenharmony_ci * relative displacement across sections.
2262306a36Sopenharmony_ci */
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci/*
2562306a36Sopenharmony_ci * The trampoline is 8 bytes and of the general form:
2662306a36Sopenharmony_ci *
2762306a36Sopenharmony_ci *   jmp.d32 \func
2862306a36Sopenharmony_ci *   ud1 %esp, %ecx
2962306a36Sopenharmony_ci *
3062306a36Sopenharmony_ci * That trailing #UD provides both a speculation stop and serves as a unique
3162306a36Sopenharmony_ci * 3 byte signature identifying static call trampolines. Also see tramp_ud[]
3262306a36Sopenharmony_ci * and __static_call_fixup().
3362306a36Sopenharmony_ci */
3462306a36Sopenharmony_ci#define __ARCH_DEFINE_STATIC_CALL_TRAMP(name, insns)			\
3562306a36Sopenharmony_ci	asm(".pushsection .static_call.text, \"ax\"		\n"	\
3662306a36Sopenharmony_ci	    ".align 4						\n"	\
3762306a36Sopenharmony_ci	    ".globl " STATIC_CALL_TRAMP_STR(name) "		\n"	\
3862306a36Sopenharmony_ci	    STATIC_CALL_TRAMP_STR(name) ":			\n"	\
3962306a36Sopenharmony_ci	    ANNOTATE_NOENDBR						\
4062306a36Sopenharmony_ci	    insns "						\n"	\
4162306a36Sopenharmony_ci	    ".byte 0x0f, 0xb9, 0xcc				\n"	\
4262306a36Sopenharmony_ci	    ".type " STATIC_CALL_TRAMP_STR(name) ", @function	\n"	\
4362306a36Sopenharmony_ci	    ".size " STATIC_CALL_TRAMP_STR(name) ", . - " STATIC_CALL_TRAMP_STR(name) " \n" \
4462306a36Sopenharmony_ci	    ".popsection					\n")
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ci#define ARCH_DEFINE_STATIC_CALL_TRAMP(name, func)			\
4762306a36Sopenharmony_ci	__ARCH_DEFINE_STATIC_CALL_TRAMP(name, ".byte 0xe9; .long " #func " - (. + 4)")
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ci#ifdef CONFIG_RETHUNK
5062306a36Sopenharmony_ci#define ARCH_DEFINE_STATIC_CALL_NULL_TRAMP(name)			\
5162306a36Sopenharmony_ci	__ARCH_DEFINE_STATIC_CALL_TRAMP(name, "jmp __x86_return_thunk")
5262306a36Sopenharmony_ci#else
5362306a36Sopenharmony_ci#define ARCH_DEFINE_STATIC_CALL_NULL_TRAMP(name)			\
5462306a36Sopenharmony_ci	__ARCH_DEFINE_STATIC_CALL_TRAMP(name, "ret; int3; nop; nop; nop")
5562306a36Sopenharmony_ci#endif
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci#define ARCH_DEFINE_STATIC_CALL_RET0_TRAMP(name)			\
5862306a36Sopenharmony_ci	ARCH_DEFINE_STATIC_CALL_TRAMP(name, __static_call_return0)
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci#define ARCH_ADD_TRAMP_KEY(name)					\
6162306a36Sopenharmony_ci	asm(".pushsection .static_call_tramp_key, \"a\"		\n"	\
6262306a36Sopenharmony_ci	    ".long " STATIC_CALL_TRAMP_STR(name) " - .		\n"	\
6362306a36Sopenharmony_ci	    ".long " STATIC_CALL_KEY_STR(name) " - .		\n"	\
6462306a36Sopenharmony_ci	    ".popsection					\n")
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ciextern bool __static_call_fixup(void *tramp, u8 op, void *dest);
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci#endif /* _ASM_STATIC_CALL_H */
69