| /* SPDX-License-Identifier: GPL-2.0 */ |
| #ifndef _STATIC_CALL_TYPES_H |
| #define _STATIC_CALL_TYPES_H |
| |
| #include <linux/types.h> |
| #include <linux/stringify.h> |
| #include <linux/compiler.h> |
| |
| #define STATIC_CALL_KEY_PREFIX __SCK__ |
| #define STATIC_CALL_KEY_PREFIX_STR __stringify(STATIC_CALL_KEY_PREFIX) |
| #define STATIC_CALL_KEY_PREFIX_LEN (sizeof(STATIC_CALL_KEY_PREFIX_STR) - 1) |
| #define STATIC_CALL_KEY(name) __PASTE(STATIC_CALL_KEY_PREFIX, name) |
| #define STATIC_CALL_KEY_STR(name) __stringify(STATIC_CALL_KEY(name)) |
| |
| #define STATIC_CALL_TRAMP_PREFIX __SCT__ |
| #define STATIC_CALL_TRAMP_PREFIX_STR __stringify(STATIC_CALL_TRAMP_PREFIX) |
| #define STATIC_CALL_TRAMP_PREFIX_LEN (sizeof(STATIC_CALL_TRAMP_PREFIX_STR) - 1) |
| #define STATIC_CALL_TRAMP(name) __PASTE(STATIC_CALL_TRAMP_PREFIX, name) |
| #define STATIC_CALL_TRAMP_STR(name) __stringify(STATIC_CALL_TRAMP(name)) |
| |
| /* |
| * Flags in the low bits of static_call_site::key. |
| */ |
| #define STATIC_CALL_SITE_TAIL 1UL /* tail call */ |
| #define STATIC_CALL_SITE_INIT 2UL /* init section */ |
| #define STATIC_CALL_SITE_FLAGS 3UL |
| |
| /* |
| * The static call site table needs to be created by external tooling (objtool |
| * or a compiler plugin). |
| */ |
| struct static_call_site { |
| s32 addr; |
| s32 key; |
| }; |
| |
| #define DECLARE_STATIC_CALL(name, func) \ |
| extern struct static_call_key STATIC_CALL_KEY(name); \ |
| extern typeof(func) STATIC_CALL_TRAMP(name); |
| |
| #ifdef CONFIG_HAVE_STATIC_CALL |
| |
| #define __raw_static_call(name) (&STATIC_CALL_TRAMP(name)) |
| |
| #ifdef CONFIG_HAVE_STATIC_CALL_INLINE |
| |
| /* |
| * __ADDRESSABLE() is used to ensure the key symbol doesn't get stripped from |
| * the symbol table so that objtool can reference it when it generates the |
| * .static_call_sites section. |
| */ |
| #define __STATIC_CALL_ADDRESSABLE(name) \ |
| __ADDRESSABLE(STATIC_CALL_KEY(name)) |
| |
| #define __static_call(name) \ |
| ({ \ |
| __STATIC_CALL_ADDRESSABLE(name); \ |
| __raw_static_call(name); \ |
| }) |
| |
| struct static_call_key { |
| void *func; |
| union { |
| /* bit 0: 0 = mods, 1 = sites */ |
| unsigned long type; |
| struct static_call_mod *mods; |
| struct static_call_site *sites; |
| }; |
| }; |
| |
| #else /* !CONFIG_HAVE_STATIC_CALL_INLINE */ |
| |
| #define __STATIC_CALL_ADDRESSABLE(name) |
| #define __static_call(name) __raw_static_call(name) |
| |
| struct static_call_key { |
| void *func; |
| }; |
| |
| #endif /* CONFIG_HAVE_STATIC_CALL_INLINE */ |
| |
| #ifdef MODULE |
| #define __STATIC_CALL_MOD_ADDRESSABLE(name) |
| #define static_call_mod(name) __raw_static_call(name) |
| #else |
| #define __STATIC_CALL_MOD_ADDRESSABLE(name) __STATIC_CALL_ADDRESSABLE(name) |
| #define static_call_mod(name) __static_call(name) |
| #endif |
| |
| #define static_call(name) __static_call(name) |
| |
| #else |
| |
| struct static_call_key { |
| void *func; |
| }; |
| |
| #define static_call(name) \ |
| ((typeof(STATIC_CALL_TRAMP(name))*)(STATIC_CALL_KEY(name).func)) |
| |
| #endif /* CONFIG_HAVE_STATIC_CALL */ |
| |
| #endif /* _STATIC_CALL_TYPES_H */ |