#define TRACE_SYSCALLS()
 #endif
 
+#ifdef CONFIG_BPF_EVENTS
+#define BPF_RAW_TP() STRUCT_ALIGN();                                   \
+                        VMLINUX_SYMBOL(__start__bpf_raw_tp) = .;       \
+                        KEEP(*(__bpf_raw_tp_map))                      \
+                        VMLINUX_SYMBOL(__stop__bpf_raw_tp) = .;
+#else
+#define BPF_RAW_TP()
+#endif
+
 #ifdef CONFIG_SERIAL_EARLYCON
 #define EARLYCON_TABLE() STRUCT_ALIGN();                       \
                         VMLINUX_SYMBOL(__earlycon_table) = .;  \
        LIKELY_PROFILE()                                                \
        BRANCH_PROFILE()                                                \
        TRACE_PRINTKS()                                                 \
+       BPF_RAW_TP()                                                    \
        TRACEPOINT_STR()
 
 /*
 
 BPF_PROG_TYPE(BPF_PROG_TYPE_KPROBE, kprobe)
 BPF_PROG_TYPE(BPF_PROG_TYPE_TRACEPOINT, tracepoint)
 BPF_PROG_TYPE(BPF_PROG_TYPE_PERF_EVENT, perf_event)
+BPF_PROG_TYPE(BPF_PROG_TYPE_RAW_TRACEPOINT, raw_tracepoint)
 #endif
 #ifdef CONFIG_CGROUP_BPF
 BPF_PROG_TYPE(BPF_PROG_TYPE_CGROUP_DEVICE, cg_dev)
 
 int perf_event_attach_bpf_prog(struct perf_event *event, struct bpf_prog *prog);
 void perf_event_detach_bpf_prog(struct perf_event *event);
 int perf_event_query_prog_array(struct perf_event *event, void __user *info);
+int bpf_probe_register(struct bpf_raw_event_map *btp, struct bpf_prog *prog);
+int bpf_probe_unregister(struct bpf_raw_event_map *btp, struct bpf_prog *prog);
+struct bpf_raw_event_map *bpf_find_raw_tracepoint(const char *name);
 #else
 static inline unsigned int trace_call_bpf(struct trace_event_call *call, void *ctx)
 {
 {
        return -EOPNOTSUPP;
 }
+static inline int bpf_probe_register(struct bpf_raw_event_map *btp, struct bpf_prog *p)
+{
+       return -EOPNOTSUPP;
+}
+static inline int bpf_probe_unregister(struct bpf_raw_event_map *btp, struct bpf_prog *p)
+{
+       return -EOPNOTSUPP;
+}
+static inline struct bpf_raw_event_map *bpf_find_raw_tracepoint(const char *name)
+{
+       return NULL;
+}
 #endif
 
 enum {
 void perf_trace_buf_update(void *record, u16 type);
 void *perf_trace_buf_alloc(int size, struct pt_regs **regs, int *rctxp);
 
+void bpf_trace_run1(struct bpf_prog *prog, u64 arg1);
+void bpf_trace_run2(struct bpf_prog *prog, u64 arg1, u64 arg2);
+void bpf_trace_run3(struct bpf_prog *prog, u64 arg1, u64 arg2,
+                   u64 arg3);
+void bpf_trace_run4(struct bpf_prog *prog, u64 arg1, u64 arg2,
+                   u64 arg3, u64 arg4);
+void bpf_trace_run5(struct bpf_prog *prog, u64 arg1, u64 arg2,
+                   u64 arg3, u64 arg4, u64 arg5);
+void bpf_trace_run6(struct bpf_prog *prog, u64 arg1, u64 arg2,
+                   u64 arg3, u64 arg4, u64 arg5, u64 arg6);
+void bpf_trace_run7(struct bpf_prog *prog, u64 arg1, u64 arg2,
+                   u64 arg3, u64 arg4, u64 arg5, u64 arg6, u64 arg7);
+void bpf_trace_run8(struct bpf_prog *prog, u64 arg1, u64 arg2,
+                   u64 arg3, u64 arg4, u64 arg5, u64 arg6, u64 arg7,
+                   u64 arg8);
+void bpf_trace_run9(struct bpf_prog *prog, u64 arg1, u64 arg2,
+                   u64 arg3, u64 arg4, u64 arg5, u64 arg6, u64 arg7,
+                   u64 arg8, u64 arg9);
+void bpf_trace_run10(struct bpf_prog *prog, u64 arg1, u64 arg2,
+                    u64 arg3, u64 arg4, u64 arg5, u64 arg6, u64 arg7,
+                    u64 arg8, u64 arg9, u64 arg10);
+void bpf_trace_run11(struct bpf_prog *prog, u64 arg1, u64 arg2,
+                    u64 arg3, u64 arg4, u64 arg5, u64 arg6, u64 arg7,
+                    u64 arg8, u64 arg9, u64 arg10, u64 arg11);
+void bpf_trace_run12(struct bpf_prog *prog, u64 arg1, u64 arg2,
+                    u64 arg3, u64 arg4, u64 arg5, u64 arg6, u64 arg7,
+                    u64 arg8, u64 arg9, u64 arg10, u64 arg11, u64 arg12);
 void perf_trace_run_bpf_submit(void *raw_data, int size, int rctx,
                               struct trace_event_call *call, u64 count,
                               struct pt_regs *regs, struct hlist_head *head,
 
        struct tracepoint_func __rcu *funcs;
 };
 
+struct bpf_raw_event_map {
+       struct tracepoint       *tp;
+       void                    *bpf_func;
+       u32                     num_args;
+} __aligned(32);
+
 #endif
 
--- /dev/null
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#undef TRACE_SYSTEM_VAR
+
+#ifdef CONFIG_BPF_EVENTS
+
+#undef __entry
+#define __entry entry
+
+#undef __get_dynamic_array
+#define __get_dynamic_array(field)     \
+               ((void *)__entry + (__entry->__data_loc_##field & 0xffff))
+
+#undef __get_dynamic_array_len
+#define __get_dynamic_array_len(field) \
+               ((__entry->__data_loc_##field >> 16) & 0xffff)
+
+#undef __get_str
+#define __get_str(field) ((char *)__get_dynamic_array(field))
+
+#undef __get_bitmask
+#define __get_bitmask(field) (char *)__get_dynamic_array(field)
+
+#undef __perf_count
+#define __perf_count(c)        (c)
+
+#undef __perf_task
+#define __perf_task(t) (t)
+
+/* cast any integer, pointer, or small struct to u64 */
+#define UINTTYPE(size) \
+       __typeof__(__builtin_choose_expr(size == 1,  (u8)1, \
+                  __builtin_choose_expr(size == 2, (u16)2, \
+                  __builtin_choose_expr(size == 4, (u32)3, \
+                  __builtin_choose_expr(size == 8, (u64)4, \
+                                        (void)5)))))
+#define __CAST_TO_U64(x) ({ \
+       typeof(x) __src = (x); \
+       UINTTYPE(sizeof(x)) __dst; \
+       memcpy(&__dst, &__src, sizeof(__dst)); \
+       (u64)__dst; })
+
+#define __CAST1(a,...) __CAST_TO_U64(a)
+#define __CAST2(a,...) __CAST_TO_U64(a), __CAST1(__VA_ARGS__)
+#define __CAST3(a,...) __CAST_TO_U64(a), __CAST2(__VA_ARGS__)
+#define __CAST4(a,...) __CAST_TO_U64(a), __CAST3(__VA_ARGS__)
+#define __CAST5(a,...) __CAST_TO_U64(a), __CAST4(__VA_ARGS__)
+#define __CAST6(a,...) __CAST_TO_U64(a), __CAST5(__VA_ARGS__)
+#define __CAST7(a,...) __CAST_TO_U64(a), __CAST6(__VA_ARGS__)
+#define __CAST8(a,...) __CAST_TO_U64(a), __CAST7(__VA_ARGS__)
+#define __CAST9(a,...) __CAST_TO_U64(a), __CAST8(__VA_ARGS__)
+#define __CAST10(a,...) __CAST_TO_U64(a), __CAST9(__VA_ARGS__)
+#define __CAST11(a,...) __CAST_TO_U64(a), __CAST10(__VA_ARGS__)
+#define __CAST12(a,...) __CAST_TO_U64(a), __CAST11(__VA_ARGS__)
+/* tracepoints with more than 12 arguments will hit build error */
+#define CAST_TO_U64(...) CONCATENATE(__CAST, COUNT_ARGS(__VA_ARGS__))(__VA_ARGS__)
+
+#undef DECLARE_EVENT_CLASS
+#define DECLARE_EVENT_CLASS(call, proto, args, tstruct, assign, print) \
+static notrace void                                                    \
+__bpf_trace_##call(void *__data, proto)                                        \
+{                                                                      \
+       struct bpf_prog *prog = __data;                                 \
+       CONCATENATE(bpf_trace_run, COUNT_ARGS(args))(prog, CAST_TO_U64(args));  \
+}
+
+/*
+ * This part is compiled out, it is only here as a build time check
+ * to make sure that if the tracepoint handling changes, the
+ * bpf probe will fail to compile unless it too is updated.
+ */
+#undef DEFINE_EVENT
+#define DEFINE_EVENT(template, call, proto, args)                      \
+static inline void bpf_test_probe_##call(void)                         \
+{                                                                      \
+       check_trace_callback_type_##call(__bpf_trace_##template);       \
+}                                                                      \
+static struct bpf_raw_event_map        __used                                  \
+       __attribute__((section("__bpf_raw_tp_map")))                    \
+__bpf_trace_tp_map_##call = {                                          \
+       .tp             = &__tracepoint_##call,                         \
+       .bpf_func       = (void *)__bpf_trace_##template,               \
+       .num_args       = COUNT_ARGS(args),                             \
+};
+
+
+#undef DEFINE_EVENT_PRINT
+#define DEFINE_EVENT_PRINT(template, name, proto, args, print) \
+       DEFINE_EVENT(template, name, PARAMS(proto), PARAMS(args))
+
+#include TRACE_INCLUDE(TRACE_INCLUDE_FILE)
+#endif /* CONFIG_BPF_EVENTS */
 
 #ifdef TRACEPOINTS_ENABLED
 #include <trace/trace_events.h>
 #include <trace/perf.h>
+#include <trace/bpf_probe.h>
 #endif
 
 #undef TRACE_EVENT
 
        BPF_MAP_GET_FD_BY_ID,
        BPF_OBJ_GET_INFO_BY_FD,
        BPF_PROG_QUERY,
+       BPF_RAW_TRACEPOINT_OPEN,
 };
 
 enum bpf_map_type {
        BPF_PROG_TYPE_SK_SKB,
        BPF_PROG_TYPE_CGROUP_DEVICE,
        BPF_PROG_TYPE_SK_MSG,
+       BPF_PROG_TYPE_RAW_TRACEPOINT,
 };
 
 enum bpf_attach_type {
                __aligned_u64   prog_ids;
                __u32           prog_cnt;
        } query;
+
+       struct {
+               __u64 name;
+               __u32 prog_fd;
+       } raw_tracepoint;
 } __attribute__((aligned(8)));
 
 /* BPF helper function descriptions:
        __u32 minor;
 };
 
+struct bpf_raw_tracepoint_args {
+       __u64 args[0];
+};
+
 #endif /* _UAPI__LINUX_BPF_H__ */
 
                                attr->file_flags);
 }
 
+struct bpf_raw_tracepoint {
+       struct bpf_raw_event_map *btp;
+       struct bpf_prog *prog;
+};
+
+static int bpf_raw_tracepoint_release(struct inode *inode, struct file *filp)
+{
+       struct bpf_raw_tracepoint *raw_tp = filp->private_data;
+
+       if (raw_tp->prog) {
+               bpf_probe_unregister(raw_tp->btp, raw_tp->prog);
+               bpf_prog_put(raw_tp->prog);
+       }
+       kfree(raw_tp);
+       return 0;
+}
+
+static const struct file_operations bpf_raw_tp_fops = {
+       .release        = bpf_raw_tracepoint_release,
+       .read           = bpf_dummy_read,
+       .write          = bpf_dummy_write,
+};
+
+#define BPF_RAW_TRACEPOINT_OPEN_LAST_FIELD raw_tracepoint.prog_fd
+
+static int bpf_raw_tracepoint_open(const union bpf_attr *attr)
+{
+       struct bpf_raw_tracepoint *raw_tp;
+       struct bpf_raw_event_map *btp;
+       struct bpf_prog *prog;
+       char tp_name[128];
+       int tp_fd, err;
+
+       if (strncpy_from_user(tp_name, u64_to_user_ptr(attr->raw_tracepoint.name),
+                             sizeof(tp_name) - 1) < 0)
+               return -EFAULT;
+       tp_name[sizeof(tp_name) - 1] = 0;
+
+       btp = bpf_find_raw_tracepoint(tp_name);
+       if (!btp)
+               return -ENOENT;
+
+       raw_tp = kzalloc(sizeof(*raw_tp), GFP_USER);
+       if (!raw_tp)
+               return -ENOMEM;
+       raw_tp->btp = btp;
+
+       prog = bpf_prog_get_type(attr->raw_tracepoint.prog_fd,
+                                BPF_PROG_TYPE_RAW_TRACEPOINT);
+       if (IS_ERR(prog)) {
+               err = PTR_ERR(prog);
+               goto out_free_tp;
+       }
+
+       err = bpf_probe_register(raw_tp->btp, prog);
+       if (err)
+               goto out_put_prog;
+
+       raw_tp->prog = prog;
+       tp_fd = anon_inode_getfd("bpf-raw-tracepoint", &bpf_raw_tp_fops, raw_tp,
+                                O_CLOEXEC);
+       if (tp_fd < 0) {
+               bpf_probe_unregister(raw_tp->btp, prog);
+               err = tp_fd;
+               goto out_put_prog;
+       }
+       return tp_fd;
+
+out_put_prog:
+       bpf_prog_put(prog);
+out_free_tp:
+       kfree(raw_tp);
+       return err;
+}
+
 #ifdef CONFIG_CGROUP_BPF
 
 #define BPF_PROG_ATTACH_LAST_FIELD attach_flags
        case BPF_OBJ_GET_INFO_BY_FD:
                err = bpf_obj_get_info_by_fd(&attr, uattr);
                break;
+       case BPF_RAW_TRACEPOINT_OPEN:
+               err = bpf_raw_tracepoint_open(&attr);
+               break;
        default:
                err = -EINVAL;
                break;
 
        }
 }
 
+/*
+ * bpf_raw_tp_regs are separate from bpf_pt_regs used from skb/xdp
+ * to avoid potential recursive reuse issue when/if tracepoints are added
+ * inside bpf_*_event_output and/or bpf_get_stack_id
+ */
+static DEFINE_PER_CPU(struct pt_regs, bpf_raw_tp_regs);
+BPF_CALL_5(bpf_perf_event_output_raw_tp, struct bpf_raw_tracepoint_args *, args,
+          struct bpf_map *, map, u64, flags, void *, data, u64, size)
+{
+       struct pt_regs *regs = this_cpu_ptr(&bpf_raw_tp_regs);
+
+       perf_fetch_caller_regs(regs);
+       return ____bpf_perf_event_output(regs, map, flags, data, size);
+}
+
+static const struct bpf_func_proto bpf_perf_event_output_proto_raw_tp = {
+       .func           = bpf_perf_event_output_raw_tp,
+       .gpl_only       = true,
+       .ret_type       = RET_INTEGER,
+       .arg1_type      = ARG_PTR_TO_CTX,
+       .arg2_type      = ARG_CONST_MAP_PTR,
+       .arg3_type      = ARG_ANYTHING,
+       .arg4_type      = ARG_PTR_TO_MEM,
+       .arg5_type      = ARG_CONST_SIZE_OR_ZERO,
+};
+
+BPF_CALL_3(bpf_get_stackid_raw_tp, struct bpf_raw_tracepoint_args *, args,
+          struct bpf_map *, map, u64, flags)
+{
+       struct pt_regs *regs = this_cpu_ptr(&bpf_raw_tp_regs);
+
+       perf_fetch_caller_regs(regs);
+       /* similar to bpf_perf_event_output_tp, but pt_regs fetched differently */
+       return bpf_get_stackid((unsigned long) regs, (unsigned long) map,
+                              flags, 0, 0);
+}
+
+static const struct bpf_func_proto bpf_get_stackid_proto_raw_tp = {
+       .func           = bpf_get_stackid_raw_tp,
+       .gpl_only       = true,
+       .ret_type       = RET_INTEGER,
+       .arg1_type      = ARG_PTR_TO_CTX,
+       .arg2_type      = ARG_CONST_MAP_PTR,
+       .arg3_type      = ARG_ANYTHING,
+};
+
+static const struct bpf_func_proto *raw_tp_prog_func_proto(enum bpf_func_id func_id)
+{
+       switch (func_id) {
+       case BPF_FUNC_perf_event_output:
+               return &bpf_perf_event_output_proto_raw_tp;
+       case BPF_FUNC_get_stackid:
+               return &bpf_get_stackid_proto_raw_tp;
+       default:
+               return tracing_func_proto(func_id);
+       }
+}
+
+static bool raw_tp_prog_is_valid_access(int off, int size,
+                                       enum bpf_access_type type,
+                                       struct bpf_insn_access_aux *info)
+{
+       /* largest tracepoint in the kernel has 12 args */
+       if (off < 0 || off >= sizeof(__u64) * 12)
+               return false;
+       if (type != BPF_READ)
+               return false;
+       if (off % size != 0)
+               return false;
+       return true;
+}
+
+const struct bpf_verifier_ops raw_tracepoint_verifier_ops = {
+       .get_func_proto  = raw_tp_prog_func_proto,
+       .is_valid_access = raw_tp_prog_is_valid_access,
+};
+
+const struct bpf_prog_ops raw_tracepoint_prog_ops = {
+};
+
 static bool pe_prog_is_valid_access(int off, int size, enum bpf_access_type type,
                                    struct bpf_insn_access_aux *info)
 {
 
        return ret;
 }
+
+extern struct bpf_raw_event_map __start__bpf_raw_tp[];
+extern struct bpf_raw_event_map __stop__bpf_raw_tp[];
+
+struct bpf_raw_event_map *bpf_find_raw_tracepoint(const char *name)
+{
+       struct bpf_raw_event_map *btp = __start__bpf_raw_tp;
+
+       for (; btp < __stop__bpf_raw_tp; btp++) {
+               if (!strcmp(btp->tp->name, name))
+                       return btp;
+       }
+       return NULL;
+}
+
+static __always_inline
+void __bpf_trace_run(struct bpf_prog *prog, u64 *args)
+{
+       rcu_read_lock();
+       preempt_disable();
+       (void) BPF_PROG_RUN(prog, args);
+       preempt_enable();
+       rcu_read_unlock();
+}
+
+#define UNPACK(...)                    __VA_ARGS__
+#define REPEAT_1(FN, DL, X, ...)       FN(X)
+#define REPEAT_2(FN, DL, X, ...)       FN(X) UNPACK DL REPEAT_1(FN, DL, __VA_ARGS__)
+#define REPEAT_3(FN, DL, X, ...)       FN(X) UNPACK DL REPEAT_2(FN, DL, __VA_ARGS__)
+#define REPEAT_4(FN, DL, X, ...)       FN(X) UNPACK DL REPEAT_3(FN, DL, __VA_ARGS__)
+#define REPEAT_5(FN, DL, X, ...)       FN(X) UNPACK DL REPEAT_4(FN, DL, __VA_ARGS__)
+#define REPEAT_6(FN, DL, X, ...)       FN(X) UNPACK DL REPEAT_5(FN, DL, __VA_ARGS__)
+#define REPEAT_7(FN, DL, X, ...)       FN(X) UNPACK DL REPEAT_6(FN, DL, __VA_ARGS__)
+#define REPEAT_8(FN, DL, X, ...)       FN(X) UNPACK DL REPEAT_7(FN, DL, __VA_ARGS__)
+#define REPEAT_9(FN, DL, X, ...)       FN(X) UNPACK DL REPEAT_8(FN, DL, __VA_ARGS__)
+#define REPEAT_10(FN, DL, X, ...)      FN(X) UNPACK DL REPEAT_9(FN, DL, __VA_ARGS__)
+#define REPEAT_11(FN, DL, X, ...)      FN(X) UNPACK DL REPEAT_10(FN, DL, __VA_ARGS__)
+#define REPEAT_12(FN, DL, X, ...)      FN(X) UNPACK DL REPEAT_11(FN, DL, __VA_ARGS__)
+#define REPEAT(X, FN, DL, ...)         REPEAT_##X(FN, DL, __VA_ARGS__)
+
+#define SARG(X)                u64 arg##X
+#define COPY(X)                args[X] = arg##X
+
+#define __DL_COM       (,)
+#define __DL_SEM       (;)
+
+#define __SEQ_0_11     0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11
+
+#define BPF_TRACE_DEFN_x(x)                                            \
+       void bpf_trace_run##x(struct bpf_prog *prog,                    \
+                             REPEAT(x, SARG, __DL_COM, __SEQ_0_11))    \
+       {                                                               \
+               u64 args[x];                                            \
+               REPEAT(x, COPY, __DL_SEM, __SEQ_0_11);                  \
+               __bpf_trace_run(prog, args);                            \
+       }                                                               \
+       EXPORT_SYMBOL_GPL(bpf_trace_run##x)
+BPF_TRACE_DEFN_x(1);
+BPF_TRACE_DEFN_x(2);
+BPF_TRACE_DEFN_x(3);
+BPF_TRACE_DEFN_x(4);
+BPF_TRACE_DEFN_x(5);
+BPF_TRACE_DEFN_x(6);
+BPF_TRACE_DEFN_x(7);
+BPF_TRACE_DEFN_x(8);
+BPF_TRACE_DEFN_x(9);
+BPF_TRACE_DEFN_x(10);
+BPF_TRACE_DEFN_x(11);
+BPF_TRACE_DEFN_x(12);
+
+static int __bpf_probe_register(struct bpf_raw_event_map *btp, struct bpf_prog *prog)
+{
+       struct tracepoint *tp = btp->tp;
+
+       /*
+        * check that program doesn't access arguments beyond what's
+        * available in this tracepoint
+        */
+       if (prog->aux->max_ctx_offset > btp->num_args * sizeof(u64))
+               return -EINVAL;
+
+       return tracepoint_probe_register(tp, (void *)btp->bpf_func, prog);
+}
+
+int bpf_probe_register(struct bpf_raw_event_map *btp, struct bpf_prog *prog)
+{
+       int err;
+
+       mutex_lock(&bpf_event_mutex);
+       err = __bpf_probe_register(btp, prog);
+       mutex_unlock(&bpf_event_mutex);
+       return err;
+}
+
+int bpf_probe_unregister(struct bpf_raw_event_map *btp, struct bpf_prog *prog)
+{
+       int err;
+
+       mutex_lock(&bpf_event_mutex);
+       err = tracepoint_probe_unregister(btp->tp, (void *)btp->bpf_func, prog);
+       mutex_unlock(&bpf_event_mutex);
+       return err;
+}