diff --git a/arch/arm64/configs/openeuler_defconfig b/arch/arm64/configs/openeuler_defconfig index 13e6529e38f3793196a9a0cdf5c50123b78372b2..9d071bb380f6038248753ddcb135d41384add0fe 100644 --- a/arch/arm64/configs/openeuler_defconfig +++ b/arch/arm64/configs/openeuler_defconfig @@ -6548,6 +6548,12 @@ CONFIG_USB4=m # CONFIG_ANDROID_BINDER_IPC is not set # end of Android +# +# Vendor Hooks +# +CONFIG_VENDOR_HOOKS=y +# end of Vendor Hooks + CONFIG_LIBNVDIMM=m CONFIG_BLK_DEV_PMEM=m CONFIG_ND_CLAIM=y diff --git a/arch/x86/configs/openeuler_defconfig b/arch/x86/configs/openeuler_defconfig index b8e216f3fa24451a3e98250c6a0e59f371d28d60..9591ce7a17cfdecb15c37ffbc98abe7e5464d054 100644 --- a/arch/x86/configs/openeuler_defconfig +++ b/arch/x86/configs/openeuler_defconfig @@ -7791,6 +7791,12 @@ CONFIG_USB4=m # CONFIG_ANDROID_BINDER_IPC is not set # end of Android +# +# Vendor Hooks +# +CONFIG_VENDOR_HOOKS=y +# end of Vendor Hooks + CONFIG_LIBNVDIMM=m CONFIG_BLK_DEV_PMEM=m CONFIG_ND_CLAIM=y diff --git a/drivers/Kconfig b/drivers/Kconfig index cc09f02c76d0f9271f4c5c6be583a353078a4834..07700cc35d163914569bf35e90fdc4b30826e29e 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -207,6 +207,8 @@ source "drivers/thunderbolt/Kconfig" source "drivers/android/Kconfig" +source "drivers/hooks/Kconfig" + source "drivers/gpu/trace/Kconfig" source "drivers/nvdimm/Kconfig" diff --git a/drivers/Makefile b/drivers/Makefile index 45e1f63f20adc88310e4b55abd9cfaaba5d60bc8..7c4a51caf4ba9a196600fd19f7231562cc5f3468 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -181,6 +181,7 @@ obj-y += hwtracing/intel_th/ obj-$(CONFIG_STM) += hwtracing/stm/ obj-$(CONFIG_HISI_PTT) += hwtracing/ptt/ obj-y += android/ +obj-$(CONFIG_VENDOR_HOOKS) += hooks/ obj-$(CONFIG_NVMEM) += nvmem/ obj-$(CONFIG_FPGA) += fpga/ obj-$(CONFIG_FSI) += fsi/ diff --git a/drivers/hooks/Kconfig b/drivers/hooks/Kconfig new file mode 100644 index 0000000000000000000000000000000000000000..1c0e33ef9a564971365d906d4b2303a75fdb84a6 --- /dev/null +++ b/drivers/hooks/Kconfig @@ -0,0 +1,13 @@ +# SPDX-License-Identifier: GPL-2.0 +menu "Vendor Hooks" + +config VENDOR_HOOKS + bool "Vendor Hooks" + depends on TRACEPOINTS + help + Enable vendor hooks implemented as tracepoints + + Allow vendor modules to attach to tracepoint "hooks" defined via + DECLARE_HOOK or DECLARE_RESTRICTED_HOOK. + +endmenu diff --git a/drivers/hooks/Makefile b/drivers/hooks/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1592308269665617d8327b735842281142810995 --- /dev/null +++ b/drivers/hooks/Makefile @@ -0,0 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0-only +ccflags-y += -I$(src) # needed for trace events + +obj-$(CONFIG_VENDOR_HOOKS) += vendor_hooks.o diff --git a/drivers/hooks/vendor_hooks.c b/drivers/hooks/vendor_hooks.c new file mode 100644 index 0000000000000000000000000000000000000000..359989d1bb32e39f9b656a8e1091e1250a55645e --- /dev/null +++ b/drivers/hooks/vendor_hooks.c @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* vendor_hook.c + * + * Vendor Hook Support + * + * Copyright (C) 2020 Google, Inc. + */ + +#define CREATE_TRACE_POINTS +#include + +/* + * Export tracepoints that act as a bare tracehook (ie: have no trace event + * associated with them) to allow external modules to probe them. + */ + diff --git a/include/trace/hooks/vendor_hooks.h b/include/trace/hooks/vendor_hooks.h new file mode 100644 index 0000000000000000000000000000000000000000..ab8864da66d812ae8281f74f0d10f0e516a16fe7 --- /dev/null +++ b/include/trace/hooks/vendor_hooks.h @@ -0,0 +1,119 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +/* + * Note: we intentionally omit include file ifdef protection + * This is due to the way trace events work. If a file includes two + * trace event headers under one "CREATE_TRACE_POINTS" the first include + * will override the DECLARE_RESTRICTED_HOOK and break the second include. + */ + +#include + +#if defined(CONFIG_TRACEPOINTS) && defined(CONFIG_VENDOR_HOOKS) + +#define DECLARE_HOOK DECLARE_TRACE + +#ifdef TRACE_HEADER_MULTI_READ + +#define DEFINE_HOOK_FN(_name, _reg, _unreg, proto, args) \ + static const char __tpstrtab_##_name[] \ + __section("__tracepoints_strings") = #_name; \ + extern struct static_call_key STATIC_CALL_KEY(tp_func_##_name); \ + int __traceiter_##_name(void *__data, proto); \ + struct tracepoint __tracepoint_##_name __used \ + __section("__tracepoints") = { \ + .name = __tpstrtab_##_name, \ + .key = STATIC_KEY_INIT_FALSE, \ + .static_call_key = &STATIC_CALL_KEY(tp_func_##_name), \ + .static_call_tramp = STATIC_CALL_TRAMP_ADDR(tp_func_##_name), \ + .iterator = &__traceiter_##_name, \ + .regfunc = _reg, \ + .unregfunc = _unreg, \ + .funcs = NULL }; \ + __TRACEPOINT_ENTRY(_name); \ + int __traceiter_##_name(void *__data, proto) \ + { \ + struct tracepoint_func *it_func_ptr; \ + void *it_func; \ + \ + it_func_ptr = (&__tracepoint_##_name)->funcs; \ + it_func = (it_func_ptr)->func; \ + __data = (it_func_ptr)->data; \ + ((void(*)(void *, proto))(it_func))(__data, args); \ + WARN_ON(((++it_func_ptr)->func)); \ + return 0; \ + } \ + DEFINE_STATIC_CALL(tp_func_##_name, __traceiter_##_name); + +#undef DECLARE_RESTRICTED_HOOK +#define DECLARE_RESTRICTED_HOOK(name, proto, args, cond) \ + DEFINE_HOOK_FN(name, NULL, NULL, PARAMS(proto), PARAMS(args)) + +/* prevent additional recursion */ +#undef TRACE_HEADER_MULTI_READ +#else /* TRACE_HEADER_MULTI_READ */ + +#ifdef CONFIG_HAVE_STATIC_CALL +#define __DO_RESTRICTED_HOOK_CALL(name, args) \ + do { \ + struct tracepoint_func *it_func_ptr; \ + void *__data; \ + it_func_ptr = (&__tracepoint_##name)->funcs; \ + if (it_func_ptr) { \ + __data = (it_func_ptr)->data; \ + static_call(tp_func_##name)(__data, args); \ + } \ + } while (0) +#else +#define __DO_RESTRICTED_HOOK_CALL(name, args) __traceiter_##name(NULL, args) +#endif + +#define DO_RESTRICTED_HOOK(name, args, cond) \ + do { \ + if (!(cond)) \ + return; \ + \ + __DO_RESTRICTED_HOOK_CALL(name, TP_ARGS(args)); \ + } while (0) + +#define __DECLARE_RESTRICTED_HOOK(name, proto, args, cond, data_proto) \ + extern int __traceiter_##name(data_proto); \ + DECLARE_STATIC_CALL(tp_func_##name, __traceiter_##name); \ + extern struct tracepoint __tracepoint_##name; \ + static inline void trace_##name(proto) \ + { \ + if (static_key_false(&__tracepoint_##name.key)) \ + DO_RESTRICTED_HOOK(name, \ + TP_ARGS(args), \ + TP_CONDITION(cond)); \ + } \ + static inline bool \ + trace_##name##_enabled(void) \ + { \ + return static_key_false(&__tracepoint_##name.key); \ + } \ + static inline int \ + register_trace_##name(void (*probe)(data_proto), void *data) \ + { \ + /* only allow a single attachment */ \ + if (trace_##name##_enabled()) \ + return -EBUSY; \ + return tracepoint_probe_register(&__tracepoint_##name, \ + (void *)probe, data); \ + } \ + /* vendor hooks cannot be unregistered */ \ + +#undef DECLARE_RESTRICTED_HOOK +#define DECLARE_RESTRICTED_HOOK(name, proto, args, cond) \ + __DECLARE_RESTRICTED_HOOK(name, PARAMS(proto), PARAMS(args), \ + cond, \ + PARAMS(void *__data, proto)) + +#endif /* TRACE_HEADER_MULTI_READ */ + +#else /* !CONFIG_TRACEPOINTS || !CONFIG_VENDOR_HOOKS */ +/* suppress trace hooks */ +#define DECLARE_HOOK DECLARE_EVENT_NOP +#define DECLARE_RESTRICTED_HOOK(name, proto, args, cond) \ + DECLARE_EVENT_NOP(name, PARAMS(proto), PARAMS(args)) +#endif