Commit 904e28c6 authored by Benjamin Tissoires's avatar Benjamin Tissoires

Merge branch 'for-6.3/hid-bpf' into for-linus

Initial support of HID-BPF (Benjamin Tissoires)

The history is a little long for this series, as it was intended to be
sent for v6.2. However some last minute issues forced us to postpone it
to v6.3.

Conflicts:
* drivers/hid/i2c-hid/Kconfig:
  commit bf7660da ("HID: stop drivers from selecting CONFIG_HID")
  conflicts with commit 2afac81d ("HID: fix I2C_HID not selected
  when I2C_HID_OF_ELAN is")
  the resolution is simple enough: just drop the "default" and "select"
  lines as the new commit from Arnd is doing
parents a7386881 2f7f4efb
......@@ -9,7 +9,7 @@ Currently ALPS HID driver supports U1 Touchpad device.
U1 device basic information.
========== ======
Vender ID 0x044E
Vendor ID 0x044E
Product ID 0x120B
Version ID 0x0121
========== ======
......
This diff is collapsed.
......@@ -8,7 +8,7 @@ Introduction
In addition to the normal input type HID devices, USB also uses the
human interface device protocols for things that are not really human
interfaces, but have similar sorts of communication needs. The two big
examples for this are power devices (especially uninterruptable power
examples for this are power devices (especially uninterruptible power
supplies) and monitor control on higher end monitors.
To support these disparate requirements, the Linux USB system provides
......
......@@ -163,7 +163,7 @@ HIDIOCGOUTPUT(len):
Get an Output Report
This ioctl will request an output report from the device using the control
endpoint. Typically, this is used to retrive the initial state of
endpoint. Typically, this is used to retrieve the initial state of
an output report of a device, before an application updates it as necessary either
via a HIDIOCSOUTPUT request, or the regular device write() interface. The format
of the buffer issued with this report is identical to that of HIDIOCGFEATURE.
......
......@@ -11,6 +11,7 @@ Human Interface Devices (HID)
hidraw
hid-sensor
hid-transport
hid-bpf
uhid
......
......@@ -199,7 +199,7 @@ the sender that the memory region for that message may be reused.
DMA initialization is started with host sending DMA_ALLOC_NOTIFY bus message
(that includes RX buffer) and FW responds with DMA_ALLOC_NOTIFY_ACK.
Additionally to DMA address communication, this sequence checks capabilities:
if thw host doesn't support DMA, then it won't send DMA allocation, so FW can't
if the host doesn't support DMA, then it won't send DMA allocation, so FW can't
send DMA; if FW doesn't support DMA then it won't respond with
DMA_ALLOC_NOTIFY_ACK, in which case host will not use DMA transfers.
Here ISH acts as busmaster DMA controller. Hence when host sends DMA_XFER,
......
......@@ -9207,9 +9207,12 @@ M: Benjamin Tissoires <benjamin.tissoires@redhat.com>
L: linux-input@vger.kernel.org
S: Maintained
T: git git://git.kernel.org/pub/scm/linux/kernel/git/hid/hid.git
F: Documentation/hid/
F: drivers/hid/
F: include/linux/hid*
F: include/uapi/linux/hid*
F: samples/hid/
F: tools/testing/selftests/hid/
HID LOGITECH DRIVERS
R: Filipe Laíns <lains@riseup.net>
......
......@@ -137,7 +137,7 @@ obj-$(CONFIG_CRYPTO) += crypto/
obj-$(CONFIG_SUPERH) += sh/
obj-y += clocksource/
obj-$(CONFIG_DCA) += dca/
obj-$(CONFIG_HID) += hid/
obj-$(CONFIG_HID_SUPPORT) += hid/
obj-$(CONFIG_PPC_PS3) += ps3/
obj-$(CONFIG_OF) += of/
obj-$(CONFIG_SSB) += ssb/
......
......@@ -2,13 +2,20 @@
#
# HID driver configuration
#
menu "HID support"
depends on INPUT
menuconfig HID_SUPPORT
bool "HID bus support"
default y
depends on INPUT
help
This option adds core support for human interface device (HID).
You will also need drivers from the following menu to make use of it.
if HID_SUPPORT
config HID
tristate "HID bus support"
depends on INPUT
tristate "HID bus core support"
default y
depends on INPUT
help
A human interface device (HID) is a type of computer device that
interacts directly with and takes input from humans. The term "HID"
......@@ -1295,6 +1302,8 @@ config HID_KUNIT_TEST
endmenu
source "drivers/hid/bpf/Kconfig"
endif # HID
source "drivers/hid/usbhid/Kconfig"
......@@ -1307,4 +1316,4 @@ source "drivers/hid/amd-sfh-hid/Kconfig"
source "drivers/hid/surface-hid/Kconfig"
endmenu
endif # HID_SUPPORT
......@@ -5,6 +5,8 @@
hid-y := hid-core.o hid-input.o hid-quirks.o
hid-$(CONFIG_DEBUG_FS) += hid-debug.o
obj-$(CONFIG_HID_BPF) += bpf/
obj-$(CONFIG_HID) += hid.o
obj-$(CONFIG_UHID) += uhid.o
......
......@@ -2,10 +2,10 @@
menu "AMD SFH HID Support"
depends on X86_64 || COMPILE_TEST
depends on PCI
depends on HID
config AMD_SFH_HID
tristate "AMD Sensor Fusion Hub"
depends on HID
help
If you say yes to this option, support will be included for the
AMD Sensor Fusion Hub.
......
# SPDX-License-Identifier: GPL-2.0-only
menu "HID-BPF support"
config HID_BPF
bool "HID-BPF support"
default HID_SUPPORT
depends on BPF && BPF_SYSCALL && \
DYNAMIC_FTRACE_WITH_DIRECT_CALLS
help
This option allows to support eBPF programs on the HID subsystem.
eBPF programs can fix HID devices in a lighter way than a full
kernel patch and allow a lot more flexibility.
For documentation, see Documentation/hid/hid-bpf.rst
If unsure, say Y.
endmenu
# SPDX-License-Identifier: GPL-2.0
#
# Makefile for HID-BPF
#
LIBBPF_INCLUDE = $(srctree)/tools/lib
obj-$(CONFIG_HID_BPF) += hid_bpf.o
CFLAGS_hid_bpf_dispatch.o += -I$(LIBBPF_INCLUDE)
CFLAGS_hid_bpf_jmp_table.o += -I$(LIBBPF_INCLUDE)
hid_bpf-objs += hid_bpf_dispatch.o hid_bpf_jmp_table.o
# SPDX-License-Identifier: GPL-2.0
OUTPUT := .output
abs_out := $(abspath $(OUTPUT))
CLANG ?= clang
LLC ?= llc
LLVM_STRIP ?= llvm-strip
TOOLS_PATH := $(abspath ../../../../tools)
BPFTOOL_SRC := $(TOOLS_PATH)/bpf/bpftool
BPFTOOL_OUTPUT := $(abs_out)/bpftool
DEFAULT_BPFTOOL := $(BPFTOOL_OUTPUT)/bootstrap/bpftool
BPFTOOL ?= $(DEFAULT_BPFTOOL)
LIBBPF_SRC := $(TOOLS_PATH)/lib/bpf
LIBBPF_OUTPUT := $(abs_out)/libbpf
LIBBPF_DESTDIR := $(LIBBPF_OUTPUT)
LIBBPF_INCLUDE := $(LIBBPF_DESTDIR)/include
BPFOBJ := $(LIBBPF_OUTPUT)/libbpf.a
INCLUDES := -I$(OUTPUT) -I$(LIBBPF_INCLUDE) -I$(TOOLS_PATH)/include/uapi
CFLAGS := -g -Wall
VMLINUX_BTF_PATHS ?= $(if $(O),$(O)/vmlinux) \
$(if $(KBUILD_OUTPUT),$(KBUILD_OUTPUT)/vmlinux) \
../../../../vmlinux \
/sys/kernel/btf/vmlinux \
/boot/vmlinux-$(shell uname -r)
VMLINUX_BTF ?= $(abspath $(firstword $(wildcard $(VMLINUX_BTF_PATHS))))
ifeq ($(VMLINUX_BTF),)
$(error Cannot find a vmlinux for VMLINUX_BTF at any of "$(VMLINUX_BTF_PATHS)")
endif
ifeq ($(V),1)
Q =
msg =
else
Q = @
msg = @printf ' %-8s %s%s\n' "$(1)" "$(notdir $(2))" "$(if $(3), $(3))";
MAKEFLAGS += --no-print-directory
submake_extras := feature_display=0
endif
.DELETE_ON_ERROR:
.PHONY: all clean
all: entrypoints.lskel.h
clean:
$(call msg,CLEAN)
$(Q)rm -rf $(OUTPUT) entrypoints
entrypoints.lskel.h: $(OUTPUT)/entrypoints.bpf.o | $(BPFTOOL)
$(call msg,GEN-SKEL,$@)
$(Q)$(BPFTOOL) gen skeleton -L $< > $@
$(OUTPUT)/entrypoints.bpf.o: entrypoints.bpf.c $(OUTPUT)/vmlinux.h $(BPFOBJ) | $(OUTPUT)
$(call msg,BPF,$@)
$(Q)$(CLANG) -g -O2 -target bpf $(INCLUDES) \
-c $(filter %.c,$^) -o $@ && \
$(LLVM_STRIP) -g $@
$(OUTPUT)/vmlinux.h: $(VMLINUX_BTF) $(BPFTOOL) | $(INCLUDE_DIR)
ifeq ($(VMLINUX_H),)
$(call msg,GEN,,$@)
$(Q)$(BPFTOOL) btf dump file $(VMLINUX_BTF) format c > $@
else
$(call msg,CP,,$@)
$(Q)cp "$(VMLINUX_H)" $@
endif
$(OUTPUT) $(LIBBPF_OUTPUT) $(BPFTOOL_OUTPUT):
$(call msg,MKDIR,$@)
$(Q)mkdir -p $@
$(BPFOBJ): $(wildcard $(LIBBPF_SRC)/*.[ch] $(LIBBPF_SRC)/Makefile) | $(LIBBPF_OUTPUT)
$(Q)$(MAKE) $(submake_extras) -C $(LIBBPF_SRC) \
OUTPUT=$(abspath $(dir $@))/ prefix= \
DESTDIR=$(LIBBPF_DESTDIR) $(abspath $@) install_headers
ifeq ($(CROSS_COMPILE),)
$(DEFAULT_BPFTOOL): $(BPFOBJ) | $(BPFTOOL_OUTPUT)
$(Q)$(MAKE) $(submake_extras) -C $(BPFTOOL_SRC) \
OUTPUT=$(BPFTOOL_OUTPUT)/ \
LIBBPF_BOOTSTRAP_OUTPUT=$(LIBBPF_OUTPUT)/ \
LIBBPF_BOOTSTRAP_DESTDIR=$(LIBBPF_DESTDIR)/ bootstrap
else
$(DEFAULT_BPFTOOL): | $(BPFTOOL_OUTPUT)
$(Q)$(MAKE) $(submake_extras) -C $(BPFTOOL_SRC) \
OUTPUT=$(BPFTOOL_OUTPUT)/ bootstrap
endif
WARNING:
If you change "entrypoints.bpf.c" do "make -j" in this directory to rebuild "entrypoints.skel.h".
Make sure to have clang 10 installed.
See Documentation/bpf/bpf_devel_QA.rst
// SPDX-License-Identifier: GPL-2.0
/* Copyright (c) 2022 Benjamin Tissoires */
#include ".output/vmlinux.h"
#include <bpf/bpf_helpers.h>
#include <bpf/bpf_tracing.h>
#define HID_BPF_MAX_PROGS 1024
struct {
__uint(type, BPF_MAP_TYPE_PROG_ARRAY);
__uint(max_entries, HID_BPF_MAX_PROGS);
__uint(key_size, sizeof(__u32));
__uint(value_size, sizeof(__u32));
} hid_jmp_table SEC(".maps");
SEC("fmod_ret/__hid_bpf_tail_call")
int BPF_PROG(hid_tail_call, struct hid_bpf_ctx *hctx)
{
bpf_tail_call(ctx, &hid_jmp_table, hctx->index);
return 0;
}
char LICENSE[] SEC("license") = "GPL";
This diff is collapsed.
This diff is collapsed.
/* SPDX-License-Identifier: GPL-2.0-only */
#ifndef _BPF_HID_BPF_DISPATCH_H
#define _BPF_HID_BPF_DISPATCH_H
#include <linux/hid.h>
struct hid_bpf_ctx_kern {
struct hid_bpf_ctx ctx;
u8 *data;
};
int hid_bpf_preload_skel(void);
void hid_bpf_free_links_and_skel(void);
int hid_bpf_get_prog_attach_type(int prog_fd);
int __hid_bpf_attach_prog(struct hid_device *hdev, enum hid_bpf_prog_type prog_type, int prog_fd,
__u32 flags);
void __hid_bpf_destroy_device(struct hid_device *hdev);
int hid_bpf_prog_run(struct hid_device *hdev, enum hid_bpf_prog_type type,
struct hid_bpf_ctx_kern *ctx_kern);
int hid_bpf_reconnect(struct hid_device *hdev);
struct bpf_prog;
#endif
This diff is collapsed.
......@@ -1215,7 +1215,8 @@ int hid_open_report(struct hid_device *device)
return -ENODEV;
size = device->dev_rsize;
buf = kmemdup(start, size, GFP_KERNEL);
/* call_hid_bpf_rdesc_fixup() ensures we work on a copy of rdesc */
buf = call_hid_bpf_rdesc_fixup(device, start, &size);
if (buf == NULL)
return -ENOMEM;
......@@ -2042,6 +2043,12 @@ int hid_input_report(struct hid_device *hid, enum hid_report_type type, u8 *data
report_enum = hid->report_enum + type;
hdrv = hid->driver;
data = dispatch_hid_bpf_device_event(hid, type, data, &size, interrupt);
if (IS_ERR(data)) {
ret = PTR_ERR(data);
goto unlock;
}
if (!size) {
dbg_hid("empty report\n");
ret = -1;
......@@ -2156,6 +2163,10 @@ int hid_connect(struct hid_device *hdev, unsigned int connect_mask)
int len;
int ret;
ret = hid_bpf_connect_device(hdev);
if (ret)
return ret;
if (hdev->quirks & HID_QUIRK_HIDDEV_FORCE)
connect_mask |= (HID_CONNECT_HIDDEV_FORCE | HID_CONNECT_HIDDEV);
if (hdev->quirks & HID_QUIRK_HIDINPUT_FORCE)
......@@ -2257,6 +2268,8 @@ void hid_disconnect(struct hid_device *hdev)
if (hdev->claimed & HID_CLAIMED_HIDRAW)
hidraw_disconnect(hdev);
hdev->claimed = 0;
hid_bpf_disconnect_device(hdev);
}
EXPORT_SYMBOL_GPL(hid_disconnect);
......@@ -2792,6 +2805,8 @@ struct hid_device *hid_allocate_device(void)
sema_init(&hdev->driver_input_lock, 1);
mutex_init(&hdev->ll_open_lock);
hid_bpf_device_init(hdev);
return hdev;
}
EXPORT_SYMBOL_GPL(hid_allocate_device);
......@@ -2818,6 +2833,7 @@ static void hid_remove_device(struct hid_device *hdev)
*/
void hid_destroy_device(struct hid_device *hdev)
{
hid_bpf_destroy_device(hdev);
hid_remove_device(hdev);
put_device(&hdev->dev);
}
......@@ -2904,6 +2920,15 @@ int hid_check_keys_pressed(struct hid_device *hid)
}
EXPORT_SYMBOL_GPL(hid_check_keys_pressed);
#ifdef CONFIG_HID_BPF
static struct hid_bpf_ops hid_ops = {
.hid_get_report = hid_get_report,
.hid_hw_raw_request = hid_hw_raw_request,
.owner = THIS_MODULE,
.bus_type = &hid_bus_type,
};
#endif
static int __init hid_init(void)
{
int ret;
......@@ -2914,6 +2939,10 @@ static int __init hid_init(void)
goto err;
}
#ifdef CONFIG_HID_BPF
hid_bpf_ops = &hid_ops;
#endif
ret = hidraw_init();
if (ret)
goto err_bus;
......@@ -2929,6 +2958,9 @@ static int __init hid_init(void)
static void __exit hid_exit(void)
{
#ifdef CONFIG_HID_BPF
hid_bpf_ops = NULL;
#endif
hid_debug_exit();
hidraw_exit();
bus_unregister(&hid_bus_type);
......
# SPDX-License-Identifier: GPL-2.0-only
menu "I2C HID support"
depends on I2C
menuconfig I2C_HID
tristate "I2C HID support"
default y
depends on I2C && INPUT && HID
if I2C_HID
config I2C_HID_ACPI
tristate "HID over I2C transport layer ACPI driver"
default n
depends on I2C && INPUT && ACPI
depends on ACPI
select I2C_HID_CORE
help
Say Y here if you use a keyboard, a touchpad, a touchscreen, or any
other HID based devices which is connected to your computer via I2C.
......@@ -19,8 +23,8 @@ config I2C_HID_ACPI
config I2C_HID_OF
tristate "HID over I2C transport layer Open Firmware driver"
default n
depends on I2C && INPUT && OF
depends on OF
select I2C_HID_CORE
help
Say Y here if you use a keyboard, a touchpad, a touchscreen, or any
other HID based devices which is connected to your computer via I2C.
......@@ -34,8 +38,8 @@ config I2C_HID_OF
config I2C_HID_OF_ELAN
tristate "Driver for Elan hid-i2c based devices on OF systems"
default n
depends on I2C && INPUT && OF
depends on OF
select I2C_HID_CORE
help
Say Y here if you want support for Elan i2c devices that use
the i2c-hid protocol on Open Firmware (Device Tree)-based
......@@ -49,8 +53,8 @@ config I2C_HID_OF_ELAN
config I2C_HID_OF_GOODIX
tristate "Driver for Goodix hid-i2c based devices on OF systems"
default n
depends on I2C && INPUT && OF
depends on OF
select I2C_HID_CORE
help
Say Y here if you want support for Goodix i2c devices that use
the i2c-hid protocol on Open Firmware (Device Tree)-based
......@@ -62,10 +66,7 @@ config I2C_HID_OF_GOODIX
will be called i2c-hid-of-goodix. It will also build/depend on
the module i2c-hid.
endmenu
config I2C_HID_CORE
tristate
default y if I2C_HID_ACPI=y || I2C_HID_OF=y || I2C_HID_OF_ELAN=y || I2C_HID_OF_GOODIX=y
default m if I2C_HID_ACPI=m || I2C_HID_OF=m || I2C_HID_OF_ELAN=m || I2C_HID_OF_GOODIX=m
select HID
endif
......@@ -6,7 +6,7 @@ config INTEL_ISH_HID
tristate "Intel Integrated Sensor Hub"
default n
depends on X86
select HID
depends on HID
help
The Integrated Sensor Hub (ISH) enables the ability to offload
sensor polling and algorithm processing to a dedicated low power
......
......@@ -26,6 +26,7 @@
#include <linux/mutex.h>
#include <linux/power_supply.h>
#include <uapi/linux/hid.h>
#include <linux/hid_bpf.h>
/*
* We parse each description item into this structure. Short items data
......@@ -654,6 +655,10 @@ struct hid_device { /* device report descriptor */
wait_queue_head_t debug_wait;
unsigned int id; /* system unique id */
#ifdef CONFIG_BPF
struct hid_bpf bpf; /* hid-bpf data */
#endif /* CONFIG_BPF */
};
#define to_hid_device(pdev) \
......
/* SPDX-License-Identifier: GPL-2.0+ */
#ifndef __HID_BPF_H
#define __HID_BPF_H
#include <linux/bpf.h>
#include <linux/spinlock.h>
#include <uapi/linux/hid.h>
struct hid_device;
/*
* The following is the user facing HID BPF API.
*
* Extra care should be taken when editing this part, as
* it might break existing out of the tree bpf programs.
*/
/**
* struct hid_bpf_ctx - User accessible data for all HID programs
*
* ``data`` is not directly accessible from the context. We need to issue
* a call to ``hid_bpf_get_data()`` in order to get a pointer to that field.
*
* All of these fields are currently read-only.
*
* @index: program index in the jump table. No special meaning (a smaller index
* doesn't mean the program will be executed before another program with
* a bigger index).
* @hid: the ``struct hid_device`` representing the device itself
* @report_type: used for ``hid_bpf_device_event()``
* @allocated_size: Allocated size of data.
*
* This is how much memory is available and can be requested
* by the HID program.
* Note that for ``HID_BPF_RDESC_FIXUP``, that memory is set to
* ``4096`` (4 KB)
* @size: Valid data in the data field.
*
* Programs can get the available valid size in data by fetching this field.
* Programs can also change this value by returning a positive number in the
* program.
* To discard the event, return a negative error code.
*
* ``size`` must always be less or equal than ``allocated_size`` (it is enforced
* once all BPF programs have been run).
* @retval: Return value of the previous program.
*/
struct hid_bpf_ctx {
__u32 index;
const struct hid_device *hid;
__u32 allocated_size;
enum hid_report_type report_type;
union {
__s32 retval;
__s32 size;
};
};
/**
* enum hid_bpf_attach_flags - flags used when attaching a HIF-BPF program
*
* @HID_BPF_FLAG_NONE: no specific flag is used, the kernel choses where to
* insert the program
* @HID_BPF_FLAG_INSERT_HEAD: insert the given program before any other program
* currently attached to the device. This doesn't
* guarantee that this program will always be first
* @HID_BPF_FLAG_MAX: sentinel value, not to be used by the callers
*/
enum hid_bpf_attach_flags {
HID_BPF_FLAG_NONE = 0,
HID_BPF_FLAG_INSERT_HEAD = _BITUL(0),
HID_BPF_FLAG_MAX,
};
/* Following functions are tracepoints that BPF programs can attach to */
int hid_bpf_device_event(struct hid_bpf_ctx *ctx);
int hid_bpf_rdesc_fixup(struct hid_bpf_ctx *ctx);
/* Following functions are kfunc that we export to BPF programs */
/* available everywhere in HID-BPF */
__u8 *hid_bpf_get_data(struct hid_bpf_ctx *ctx, unsigned int offset, const size_t __sz);
/* only available in syscall */
int hid_bpf_attach_prog(unsigned int hid_id, int prog_fd, __u32 flags);
int hid_bpf_hw_request(struct hid_bpf_ctx *ctx, __u8 *buf, size_t buf__sz,
enum hid_report_type rtype, enum hid_class_request reqtype);
struct hid_bpf_ctx *hid_bpf_allocate_context(unsigned int hid_id);
void hid_bpf_release_context(struct hid_bpf_ctx *ctx);
/*
* Below is HID internal
*/
/* internal function to call eBPF programs, not to be used by anybody */
int __hid_bpf_tail_call(struct hid_bpf_ctx *ctx);
#define HID_BPF_MAX_PROGS_PER_DEV 64
#define HID_BPF_FLAG_MASK (((HID_BPF_FLAG_MAX - 1) << 1) - 1)
/* types of HID programs to attach to */
enum hid_bpf_prog_type {
HID_BPF_PROG_TYPE_UNDEF = -1,
HID_BPF_PROG_TYPE_DEVICE_EVENT, /* an event is emitted from the device */
HID_BPF_PROG_TYPE_RDESC_FIXUP,
HID_BPF_PROG_TYPE_MAX,
};
struct hid_report_enum;
struct hid_bpf_ops {
struct hid_report *(*hid_get_report)(struct hid_report_enum *report_enum, const u8 *data);
int (*hid_hw_raw_request)(struct hid_device *hdev,
unsigned char reportnum, __u8 *buf,
size_t len, enum hid_report_type rtype,
enum hid_class_request reqtype);
struct module *owner;
struct bus_type *bus_type;
};
extern struct hid_bpf_ops *hid_bpf_ops;
struct hid_bpf_prog_list {
u16 prog_idx[HID_BPF_MAX_PROGS_PER_DEV];
u8 prog_cnt;
};
/* stored in each device */
struct hid_bpf {
u8 *device_data; /* allocated when a bpf program of type
* SEC(f.../hid_bpf_device_event) has been attached
* to this HID device
*/
u32 allocated_data;
struct hid_bpf_prog_list __rcu *progs[HID_BPF_PROG_TYPE_MAX]; /* attached BPF progs */
bool destroyed; /* prevents the assignment of any progs */
spinlock_t progs_lock; /* protects RCU update of progs */
};
/* specific HID-BPF link when a program is attached to a device */
struct hid_bpf_link {
struct bpf_link link;
int hid_table_index;
};
#ifdef CONFIG_HID_BPF
u8 *dispatch_hid_bpf_device_event(struct hid_device *hid, enum hid_report_type type, u8 *data,
u32 *size, int interrupt);
int hid_bpf_connect_device(struct hid_device *hdev);
void hid_bpf_disconnect_device(struct hid_device *hdev);
void hid_bpf_destroy_device(struct hid_device *hid);
void hid_bpf_device_init(struct hid_device *hid);
u8 *call_hid_bpf_rdesc_fixup(struct hid_device *hdev, u8 *rdesc, unsigned int *size);
#else /* CONFIG_HID_BPF */
static inline u8 *dispatch_hid_bpf_device_event(struct hid_device *hid, enum hid_report_type type,
u8 *data, u32 *size, int interrupt) { return data; }
static inline int hid_bpf_connect_device(struct hid_device *hdev) { return 0; }
static inline void hid_bpf_disconnect_device(struct hid_device *hdev) {}
static inline void hid_bpf_destroy_device(struct hid_device *hid) {}
static inline void hid_bpf_device_init(struct hid_device *hid) {}
static inline u8 *call_hid_bpf_rdesc_fixup(struct hid_device *hdev, u8 *rdesc, unsigned int *size)
{
return kmemdup(rdesc, *size, GFP_KERNEL);
}
#endif /* CONFIG_HID_BPF */
#endif /* __HID_BPF_H */
# SPDX-License-Identifier: GPL-2.0-only
config BT_HIDP
tristate "HIDP protocol support"
depends on BT_BREDR && INPUT
depends on BT_BREDR && INPUT && HID_SUPPORT
select HID
help
HIDP (Human Interface Device Protocol) is a transport layer
......
# SPDX-License-Identifier: GPL-2.0-only
hid_mouse
hid_surface_dial
*.out
*.skel.h
/vmlinux.h
/bpftool/
/libbpf/
# SPDX-License-Identifier: GPL-2.0
HID_SAMPLES_PATH ?= $(abspath $(srctree)/$(src))
TOOLS_PATH := $(HID_SAMPLES_PATH)/../../tools
pound := \#
# List of programs to build
tprogs-y += hid_mouse
tprogs-y += hid_surface_dial
# Libbpf dependencies
LIBBPF_SRC = $(TOOLS_PATH)/lib/bpf
LIBBPF_OUTPUT = $(abspath $(HID_SAMPLES_PATH))/libbpf
LIBBPF_DESTDIR = $(LIBBPF_OUTPUT)
LIBBPF_INCLUDE = $(LIBBPF_DESTDIR)/include
LIBBPF = $(LIBBPF_OUTPUT)/libbpf.a
EXTRA_HEADERS := hid_bpf_attach.h
EXTRA_BPF_HEADERS := hid_bpf_helpers.h
hid_mouse-objs := hid_mouse.o
hid_surface_dial-objs := hid_surface_dial.o
# Tell kbuild to always build the programs
always-y := $(tprogs-y)
ifeq ($(ARCH), arm)
# Strip all except -D__LINUX_ARM_ARCH__ option needed to handle linux
# headers when arm instruction set identification is requested.
ARM_ARCH_SELECTOR := $(filter -D__LINUX_ARM_ARCH__%, $(KBUILD_CFLAGS))
BPF_EXTRA_CFLAGS := $(ARM_ARCH_SELECTOR)
TPROGS_CFLAGS += $(ARM_ARCH_SELECTOR)
endif
ifeq ($(ARCH), mips)
TPROGS_CFLAGS += -D__SANE_USERSPACE_TYPES__
ifdef CONFIG_MACH_LOONGSON64
BPF_EXTRA_CFLAGS += -I$(srctree)/arch/mips/include/asm/mach-loongson64
BPF_EXTRA_CFLAGS += -I$(srctree)/arch/mips/include/asm/mach-generic
endif
endif
TPROGS_CFLAGS += -Wall -O2
TPROGS_CFLAGS += -Wmissing-prototypes
TPROGS_CFLAGS += -Wstrict-prototypes
TPROGS_CFLAGS += -I$(objtree)/usr/include
TPROGS_CFLAGS += -I$(LIBBPF_INCLUDE)
TPROGS_CFLAGS += -I$(srctree)/tools/include
ifdef SYSROOT
TPROGS_CFLAGS += --sysroot=$(SYSROOT)
TPROGS_LDFLAGS := -L$(SYSROOT)/usr/lib
endif
TPROGS_LDLIBS += $(LIBBPF) -lelf -lz
# Allows pointing LLC/CLANG to a LLVM backend with bpf support, redefine on cmdline:
# make M=samples/bpf LLC=~/git/llvm-project/llvm/build/bin/llc CLANG=~/git/llvm-project/llvm/build/bin/clang
LLC ?= llc
CLANG ?= clang
OPT ?= opt
LLVM_DIS ?= llvm-dis
LLVM_OBJCOPY ?= llvm-objcopy
LLVM_READELF ?= llvm-readelf
BTF_PAHOLE ?= pahole
# Detect that we're cross compiling and use the cross compiler
ifdef CROSS_COMPILE
CLANG_ARCH_ARGS = --target=$(notdir $(CROSS_COMPILE:%-=%))
endif
# Don't evaluate probes and warnings if we need to run make recursively
ifneq ($(src),)
HDR_PROBE := $(shell printf "$(pound)include <linux/types.h>\n struct list_head { int a; }; int main() { return 0; }" | \
$(CC) $(TPROGS_CFLAGS) $(TPROGS_LDFLAGS) -x c - \
-o /dev/null 2>/dev/null && echo okay)
ifeq ($(HDR_PROBE),)
$(warning WARNING: Detected possible issues with include path.)
$(warning WARNING: Please install kernel headers locally (make headers_install).)
endif
BTF_LLC_PROBE := $(shell $(LLC) -march=bpf -mattr=help 2>&1 | grep dwarfris)
BTF_PAHOLE_PROBE := $(shell $(BTF_PAHOLE) --help 2>&1 | grep BTF)
BTF_OBJCOPY_PROBE := $(shell $(LLVM_OBJCOPY) --help 2>&1 | grep -i 'usage.*llvm')
BTF_LLVM_PROBE := $(shell echo "int main() { return 0; }" | \
$(CLANG) -target bpf -O2 -g -c -x c - -o ./llvm_btf_verify.o; \
$(LLVM_READELF) -S ./llvm_btf_verify.o | grep BTF; \
/bin/rm -f ./llvm_btf_verify.o)
BPF_EXTRA_CFLAGS += -fno-stack-protector
ifneq ($(BTF_LLVM_PROBE),)
BPF_EXTRA_CFLAGS += -g
else
ifneq ($(and $(BTF_LLC_PROBE),$(BTF_PAHOLE_PROBE),$(BTF_OBJCOPY_PROBE)),)
BPF_EXTRA_CFLAGS += -g
LLC_FLAGS += -mattr=dwarfris
DWARF2BTF = y
endif
endif
endif
# Trick to allow make to be run from this directory
all:
$(MAKE) -C ../../ M=$(CURDIR) HID_SAMPLES_PATH=$(CURDIR)
clean:
$(MAKE) -C ../../ M=$(CURDIR) clean
@find $(CURDIR) -type f -name '*~' -delete
@$(RM) -r $(CURDIR)/libbpf $(CURDIR)/bpftool
$(LIBBPF): $(wildcard $(LIBBPF_SRC)/*.[ch] $(LIBBPF_SRC)/Makefile) | $(LIBBPF_OUTPUT)
# Fix up variables inherited from Kbuild that tools/ build system won't like
$(MAKE) -C $(LIBBPF_SRC) RM='rm -rf' EXTRA_CFLAGS="$(TPROGS_CFLAGS)" \
LDFLAGS=$(TPROGS_LDFLAGS) srctree=$(HID_SAMPLES_PATH)/../../ \
O= OUTPUT=$(LIBBPF_OUTPUT)/ DESTDIR=$(LIBBPF_DESTDIR) prefix= \
$@ install_headers
BPFTOOLDIR := $(TOOLS_PATH)/bpf/bpftool
BPFTOOL_OUTPUT := $(abspath $(HID_SAMPLES_PATH))/bpftool
BPFTOOL := $(BPFTOOL_OUTPUT)/bootstrap/bpftool
$(BPFTOOL): $(wildcard $(BPFTOOLDIR)/*.[ch] $(BPFTOOLDIR)/Makefile) | $(BPFTOOL_OUTPUT)
$(MAKE) -C $(BPFTOOLDIR) srctree=$(HID_SAMPLES_PATH)/../../ \
OUTPUT=$(BPFTOOL_OUTPUT)/ bootstrap
$(LIBBPF_OUTPUT) $(BPFTOOL_OUTPUT):
$(call msg,MKDIR,$@)
$(Q)mkdir -p $@
FORCE:
# Verify LLVM compiler tools are available and bpf target is supported by llc
.PHONY: verify_cmds verify_target_bpf $(CLANG) $(LLC)
verify_cmds: $(CLANG) $(LLC)
@for TOOL in $^ ; do \
if ! (which -- "$${TOOL}" > /dev/null 2>&1); then \
echo "*** ERROR: Cannot find LLVM tool $${TOOL}" ;\
exit 1; \
else true; fi; \
done
verify_target_bpf: verify_cmds
@if ! (${LLC} -march=bpf -mattr=help > /dev/null 2>&1); then \
echo "*** ERROR: LLVM (${LLC}) does not support 'bpf' target" ;\
echo " NOTICE: LLVM version >= 3.7.1 required" ;\
exit 2; \
else true; fi
$(HID_SAMPLES_PATH)/*.c: verify_target_bpf $(LIBBPF)
$(src)/*.c: verify_target_bpf $(LIBBPF)
libbpf_hdrs: $(LIBBPF)
.PHONY: libbpf_hdrs
$(obj)/hid_mouse.o: $(obj)/hid_mouse.skel.h
$(obj)/hid_surface_dial.o: $(obj)/hid_surface_dial.skel.h
-include $(HID_SAMPLES_PATH)/Makefile.target
VMLINUX_BTF_PATHS ?= $(abspath $(if $(O),$(O)/vmlinux)) \
$(abspath $(if $(KBUILD_OUTPUT),$(KBUILD_OUTPUT)/vmlinux)) \
$(abspath ./vmlinux)
VMLINUX_BTF ?= $(abspath $(firstword $(wildcard $(VMLINUX_BTF_PATHS))))
$(obj)/vmlinux.h: $(VMLINUX_BTF) $(BPFTOOL)
ifeq ($(VMLINUX_H),)
ifeq ($(VMLINUX_BTF),)
$(error Cannot find a vmlinux for VMLINUX_BTF at any of "$(VMLINUX_BTF_PATHS)",\
build the kernel or set VMLINUX_BTF or VMLINUX_H variable)
endif
$(Q)$(BPFTOOL) btf dump file $(VMLINUX_BTF) format c > $@
else
$(Q)cp "$(VMLINUX_H)" $@
endif
clean-files += vmlinux.h
# Get Clang's default includes on this system, as opposed to those seen by
# '-target bpf'. This fixes "missing" files on some architectures/distros,
# such as asm/byteorder.h, asm/socket.h, asm/sockios.h, sys/cdefs.h etc.
#
# Use '-idirafter': Don't interfere with include mechanics except where the
# build would have failed anyways.
define get_sys_includes
$(shell $(1) -v -E - </dev/null 2>&1 \
| sed -n '/<...> search starts here:/,/End of search list./{ s| \(/.*\)|-idirafter \1|p }') \
$(shell $(1) -dM -E - </dev/null | grep '#define __riscv_xlen ' | sed 's/#define /-D/' | sed 's/ /=/')
endef
CLANG_SYS_INCLUDES = $(call get_sys_includes,$(CLANG))
EXTRA_BPF_HEADERS_SRC := $(addprefix $(src)/,$(EXTRA_BPF_HEADERS))
$(obj)/%.bpf.o: $(src)/%.bpf.c $(EXTRA_BPF_HEADERS_SRC) $(obj)/vmlinux.h
@echo " CLANG-BPF " $@
$(Q)$(CLANG) -g -O2 -target bpf -D__TARGET_ARCH_$(SRCARCH) \
-Wno-compare-distinct-pointer-types -I$(srctree)/include \
-I$(srctree)/samples/bpf -I$(srctree)/tools/include \
-I$(LIBBPF_INCLUDE) $(CLANG_SYS_INCLUDES) \
-c $(filter %.bpf.c,$^) -o $@
LINKED_SKELS := hid_mouse.skel.h hid_surface_dial.skel.h
clean-files += $(LINKED_SKELS)
hid_mouse.skel.h-deps := hid_mouse.bpf.o hid_bpf_attach.bpf.o
hid_surface_dial.skel.h-deps := hid_surface_dial.bpf.o hid_bpf_attach.bpf.o
LINKED_BPF_SRCS := $(patsubst %.bpf.o,%.bpf.c,$(foreach skel,$(LINKED_SKELS),$($(skel)-deps)))
BPF_SRCS_LINKED := $(notdir $(wildcard $(src)/*.bpf.c))
BPF_OBJS_LINKED := $(patsubst %.bpf.c,$(obj)/%.bpf.o, $(BPF_SRCS_LINKED))
BPF_SKELS_LINKED := $(addprefix $(obj)/,$(LINKED_SKELS))
$(BPF_SKELS_LINKED): $(BPF_OBJS_LINKED) $(BPFTOOL)
@echo " BPF GEN-OBJ " $(@:.skel.h=)
$(Q)$(BPFTOOL) gen object $(@:.skel.h=.lbpf.o) $(addprefix $(obj)/,$($(@F)-deps))
@echo " BPF GEN-SKEL" $(@:.skel.h=)
$(Q)$(BPFTOOL) gen skeleton $(@:.skel.h=.lbpf.o) name $(notdir $(@:.skel.h=)) > $@
# asm/sysreg.h - inline assembly used by it is incompatible with llvm.
# But, there is no easy way to fix it, so just exclude it since it is
# useless for BPF samples.
# below we use long chain of commands, clang | opt | llvm-dis | llc,
# to generate final object file. 'clang' compiles the source into IR
# with native target, e.g., x64, arm64, etc. 'opt' does bpf CORE IR builtin
# processing (llvm12) and IR optimizations. 'llvm-dis' converts
# 'opt' output to IR, and finally 'llc' generates bpf byte code.
$(obj)/%.o: $(src)/%.c
@echo " CLANG-bpf " $@
$(Q)$(CLANG) $(NOSTDINC_FLAGS) $(LINUXINCLUDE) $(BPF_EXTRA_CFLAGS) \
-I$(obj) -I$(srctree)/tools/testing/selftests/bpf/ \
-I$(LIBBPF_INCLUDE) \
-D__KERNEL__ -D__BPF_TRACING__ -Wno-unused-value -Wno-pointer-sign \
-D__TARGET_ARCH_$(SRCARCH) -Wno-compare-distinct-pointer-types \
-Wno-gnu-variable-sized-type-not-at-end \
-Wno-address-of-packed-member -Wno-tautological-compare \
-Wno-unknown-warning-option $(CLANG_ARCH_ARGS) \
-fno-asynchronous-unwind-tables \
-I$(srctree)/samples/hid/ \
-O2 -emit-llvm -Xclang -disable-llvm-passes -c $< -o - | \
$(OPT) -O2 -mtriple=bpf-pc-linux | $(LLVM_DIS) | \
$(LLC) -march=bpf $(LLC_FLAGS) -filetype=obj -o $@
ifeq ($(DWARF2BTF),y)
$(BTF_PAHOLE) -J $@
endif
# SPDX-License-Identifier: GPL-2.0
# ==========================================================================
# Building binaries on the host system
# Binaries are not used during the compilation of the kernel, and intended
# to be build for target board, target board can be host of course. Added to
# build binaries to run not on host system.
#
# Sample syntax
# tprogs-y := xsk_example
# Will compile xsk_example.c and create an executable named xsk_example
#
# tprogs-y := xdpsock
# xdpsock-objs := xdpsock_1.o xdpsock_2.o
# Will compile xdpsock_1.c and xdpsock_2.c, and then link the executable
# xdpsock, based on xdpsock_1.o and xdpsock_2.o
#
# Derived from scripts/Makefile.host
#
__tprogs := $(sort $(tprogs-y))
# C code
# Executables compiled from a single .c file
tprog-csingle := $(foreach m,$(__tprogs), \
$(if $($(m)-objs),,$(m)))
# C executables linked based on several .o files
tprog-cmulti := $(foreach m,$(__tprogs),\
$(if $($(m)-objs),$(m)))
# Object (.o) files compiled from .c files
tprog-cobjs := $(sort $(foreach m,$(__tprogs),$($(m)-objs)))
tprog-csingle := $(addprefix $(obj)/,$(tprog-csingle))
tprog-cmulti := $(addprefix $(obj)/,$(tprog-cmulti))
tprog-cobjs := $(addprefix $(obj)/,$(tprog-cobjs))
#####
# Handle options to gcc. Support building with separate output directory
_tprogc_flags = $(TPROGS_CFLAGS) \
$(TPROGCFLAGS_$(basetarget).o)
# $(objtree)/$(obj) for including generated headers from checkin source files
ifeq ($(KBUILD_EXTMOD),)
ifdef building_out_of_srctree
_tprogc_flags += -I $(objtree)/$(obj)
endif
endif
tprogc_flags = -Wp,-MD,$(depfile) $(_tprogc_flags)
# Create executable from a single .c file
# tprog-csingle -> Executable
quiet_cmd_tprog-csingle = CC $@
cmd_tprog-csingle = $(CC) $(tprogc_flags) $(TPROGS_LDFLAGS) -o $@ $< \
$(TPROGS_LDLIBS) $(TPROGLDLIBS_$(@F))
$(tprog-csingle): $(obj)/%: $(src)/%.c FORCE
$(call if_changed_dep,tprog-csingle)
# Link an executable based on list of .o files, all plain c
# tprog-cmulti -> executable
quiet_cmd_tprog-cmulti = LD $@
cmd_tprog-cmulti = $(CC) $(tprogc_flags) $(TPROGS_LDFLAGS) -o $@ \
$(addprefix $(obj)/,$($(@F)-objs)) \
$(TPROGS_LDLIBS) $(TPROGLDLIBS_$(@F))
$(tprog-cmulti): $(tprog-cobjs) FORCE
$(call if_changed,tprog-cmulti)
$(call multi_depend, $(tprog-cmulti), , -objs)
# Create .o file from a single .c file
# tprog-cobjs -> .o
quiet_cmd_tprog-cobjs = CC $@
cmd_tprog-cobjs = $(CC) $(tprogc_flags) -c -o $@ $<
$(tprog-cobjs): $(obj)/%.o: $(src)/%.c FORCE
$(call if_changed_dep,tprog-cobjs)
// SPDX-License-Identifier: GPL-2.0-only
/* Copyright (c) 2022 Benjamin Tissoires
*/
#include "vmlinux.h"
#include <bpf/bpf_helpers.h>
#include <bpf/bpf_tracing.h>
#include "hid_bpf_attach.h"
#include "hid_bpf_helpers.h"
SEC("syscall")
int attach_prog(struct attach_prog_args *ctx)
{
ctx->retval = hid_bpf_attach_prog(ctx->hid,
ctx->prog_fd,
0);
return 0;
}
/* SPDX-License-Identifier: GPL-2.0-only */
/* Copyright (c) 2022 Benjamin Tissoires
*/
#ifndef __HID_BPF_ATTACH_H
#define __HID_BPF_ATTACH_H
struct attach_prog_args {
int prog_fd;
unsigned int hid;
int retval;
};
#endif /* __HID_BPF_ATTACH_H */
/* SPDX-License-Identifier: GPL-2.0-only */
/* Copyright (c) 2022 Benjamin Tissoires
*/
#ifndef __HID_BPF_HELPERS_H
#define __HID_BPF_HELPERS_H
/* following are kfuncs exported by HID for HID-BPF */
extern __u8 *hid_bpf_get_data(struct hid_bpf_ctx *ctx,
unsigned int offset,
const size_t __sz) __ksym;
extern int hid_bpf_attach_prog(unsigned int hid_id, int prog_fd, u32 flags) __ksym;
extern struct hid_bpf_ctx *hid_bpf_allocate_context(unsigned int hid_id) __ksym;
extern void hid_bpf_release_context(struct hid_bpf_ctx *ctx) __ksym;
extern int hid_bpf_hw_request(struct hid_bpf_ctx *ctx,
__u8 *data,
size_t buf__sz,
enum hid_report_type type,
enum hid_class_request reqtype) __ksym;
#endif /* __HID_BPF_HELPERS_H */
// SPDX-License-Identifier: GPL-2.0
#include "vmlinux.h"
#include <bpf/bpf_helpers.h>
#include <bpf/bpf_tracing.h>
#include "hid_bpf_helpers.h"
SEC("fmod_ret/hid_bpf_device_event")
int BPF_PROG(hid_y_event, struct hid_bpf_ctx *hctx)
{
s16 y;
__u8 *data = hid_bpf_get_data(hctx, 0 /* offset */, 9 /* size */);
if (!data)
return 0; /* EPERM check */
bpf_printk("event: size: %d", hctx->size);
bpf_printk("incoming event: %02x %02x %02x",
data[0],
data[1],
data[2]);
bpf_printk(" %02x %02x %02x",
data[3],
data[4],
data[5]);
bpf_printk(" %02x %02x %02x",
data[6],
data[7],
data[8]);
y = data[3] | (data[4] << 8);
y = -y;
data[3] = y & 0xFF;
data[4] = (y >> 8) & 0xFF;
bpf_printk("modified event: %02x %02x %02x",
data[0],
data[1],
data[2]);
bpf_printk(" %02x %02x %02x",
data[3],
data[4],
data[5]);
bpf_printk(" %02x %02x %02x",
data[6],
data[7],
data[8]);
return 0;
}
SEC("fmod_ret/hid_bpf_device_event")
int BPF_PROG(hid_x_event, struct hid_bpf_ctx *hctx)
{
s16 x;
__u8 *data = hid_bpf_get_data(hctx, 0 /* offset */, 9 /* size */);
if (!data)
return 0; /* EPERM check */
x = data[1] | (data[2] << 8);
x = -x;
data[1] = x & 0xFF;
data[2] = (x >> 8) & 0xFF;
return 0;
}
SEC("fmod_ret/hid_bpf_rdesc_fixup")
int BPF_PROG(hid_rdesc_fixup, struct hid_bpf_ctx *hctx)
{
__u8 *data = hid_bpf_get_data(hctx, 0 /* offset */, 4096 /* size */);
if (!data)
return 0; /* EPERM check */
bpf_printk("rdesc: %02x %02x %02x",
data[0],
data[1],
data[2]);
bpf_printk(" %02x %02x %02x",
data[3],
data[4],
data[5]);
bpf_printk(" %02x %02x %02x ...",
data[6],
data[7],
data[8]);
/*
* The original report descriptor contains:
*
* 0x05, 0x01, // Usage Page (Generic Desktop) 30
* 0x16, 0x01, 0x80, // Logical Minimum (-32767) 32
* 0x26, 0xff, 0x7f, // Logical Maximum (32767) 35
* 0x09, 0x30, // Usage (X) 38
* 0x09, 0x31, // Usage (Y) 40
*
* So byte 39 contains Usage X and byte 41 Usage Y.
*
* We simply swap the axes here.
*/
data[39] = 0x31;
data[41] = 0x30;
return 0;
}
char _license[] SEC("license") = "GPL";
// SPDX-License-Identifier: GPL-2.0-only
/* Copyright (c) 2022 Benjamin Tissoires
*
* This is a pure HID-BPF example, and should be considered as such:
* on the Etekcity Scroll 6E, the X and Y axes will be swapped and
* inverted. On any other device... Not sure what this will do.
*
* This C main file is generic though. To adapt the code and test, users
* must amend only the .bpf.c file, which this program will load any
* eBPF program it finds.
*/
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <libgen.h>
#include <signal.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/resource.h>
#include <unistd.h>
#include <linux/bpf.h>
#include <linux/errno.h>
#include <bpf/bpf.h>
#include <bpf/libbpf.h>
#include "hid_mouse.skel.h"
#include "hid_bpf_attach.h"
static bool running = true;
static void int_exit(int sig)
{
running = false;
exit(0);
}
static void usage(const char *prog)
{
fprintf(stderr,
"%s: %s /sys/bus/hid/devices/0BUS:0VID:0PID:00ID\n\n",
__func__, prog);
fprintf(stderr,
"This program will upload and attach a HID-BPF program to the given device.\n"
"On the Etekcity Scroll 6E, the X and Y axis will be inverted, but on any other\n"
"device, chances are high that the device will not be working anymore\n\n"
"consider this as a demo and adapt the eBPF program to your needs\n"
"Hit Ctrl-C to unbind the program and reset the device\n");
}
static int get_hid_id(const char *path)
{
const char *str_id, *dir;
char uevent[1024];
int fd;
memset(uevent, 0, sizeof(uevent));
snprintf(uevent, sizeof(uevent) - 1, "%s/uevent", path);
fd = open(uevent, O_RDONLY | O_NONBLOCK);
if (fd < 0)
return -ENOENT;
close(fd);
dir = basename((char *)path);
str_id = dir + sizeof("0003:0001:0A37.");
return (int)strtol(str_id, NULL, 16);
}
int main(int argc, char **argv)
{
struct hid_mouse *skel;
struct bpf_program *prog;
int err;
const char *optstr = "";
const char *sysfs_path;
int opt, hid_id, attach_fd;
struct attach_prog_args args = {
.retval = -1,
};
DECLARE_LIBBPF_OPTS(bpf_test_run_opts, tattr,
.ctx_in = &args,
.ctx_size_in = sizeof(args),
);
while ((opt = getopt(argc, argv, optstr)) != -1) {
switch (opt) {
default:
usage(basename(argv[0]));
return 1;
}
}
if (optind == argc) {
usage(basename(argv[0]));
return 1;
}
sysfs_path = argv[optind];
if (!sysfs_path) {
perror("sysfs");
return 1;
}
skel = hid_mouse__open_and_load();
if (!skel) {
fprintf(stderr, "%s %s:%d", __func__, __FILE__, __LINE__);
return -1;
}
hid_id = get_hid_id(sysfs_path);
if (hid_id < 0) {
fprintf(stderr, "can not open HID device: %m\n");
return 1;
}
args.hid = hid_id;
attach_fd = bpf_program__fd(skel->progs.attach_prog);
if (attach_fd < 0) {
fprintf(stderr, "can't locate attach prog: %m\n");
return 1;
}
bpf_object__for_each_program(prog, *skel->skeleton->obj) {
/* ignore syscalls */
if (bpf_program__get_type(prog) != BPF_PROG_TYPE_TRACING)
continue;
args.retval = -1;
args.prog_fd = bpf_program__fd(prog);
err = bpf_prog_test_run_opts(attach_fd, &tattr);
if (err) {
fprintf(stderr, "can't attach prog to hid device %d: %m (err: %d)\n",
hid_id, err);
return 1;
}
}
signal(SIGINT, int_exit);
signal(SIGTERM, int_exit);
while (running)
sleep(1);
hid_mouse__destroy(skel);
return 0;
}
// SPDX-License-Identifier: GPL-2.0-only
/* Copyright (c) 2022 Benjamin Tissoires
*/
#include "vmlinux.h"
#include <bpf/bpf_helpers.h>
#include <bpf/bpf_tracing.h>
#include "hid_bpf_helpers.h"
#define HID_UP_BUTTON 0x0009
#define HID_GD_WHEEL 0x0038
SEC("fmod_ret/hid_bpf_device_event")
int BPF_PROG(hid_event, struct hid_bpf_ctx *hctx)
{
__u8 *data = hid_bpf_get_data(hctx, 0 /* offset */, 9 /* size */);
if (!data)
return 0; /* EPERM check */
/* Touch */
data[1] &= 0xfd;
/* X */
data[4] = 0;
data[5] = 0;
/* Y */
data[6] = 0;
data[7] = 0;
return 0;
}
/* 72 == 360 / 5 -> 1 report every 5 degrees */
int resolution = 72;
int physical = 5;
struct haptic_syscall_args {
unsigned int hid;
int retval;
};
static __u8 haptic_data[8];
SEC("syscall")
int set_haptic(struct haptic_syscall_args *args)
{
struct hid_bpf_ctx *ctx;
const size_t size = sizeof(haptic_data);
u16 *res;
int ret;
if (size > sizeof(haptic_data))
return -7; /* -E2BIG */
ctx = hid_bpf_allocate_context(args->hid);
if (!ctx)
return -1; /* EPERM check */
haptic_data[0] = 1; /* report ID */
ret = hid_bpf_hw_request(ctx, haptic_data, size, HID_FEATURE_REPORT, HID_REQ_GET_REPORT);
bpf_printk("probed/remove event ret value: %d", ret);
bpf_printk("buf: %02x %02x %02x",
haptic_data[0],
haptic_data[1],
haptic_data[2]);
bpf_printk(" %02x %02x %02x",
haptic_data[3],
haptic_data[4],
haptic_data[5]);
bpf_printk(" %02x %02x",
haptic_data[6],
haptic_data[7]);
/* whenever resolution multiplier is not 3600, we have the fixed report descriptor */
res = (u16 *)&haptic_data[1];
if (*res != 3600) {
// haptic_data[1] = 72; /* resolution multiplier */
// haptic_data[2] = 0; /* resolution multiplier */
// haptic_data[3] = 0; /* Repeat Count */
haptic_data[4] = 3; /* haptic Auto Trigger */
// haptic_data[5] = 5; /* Waveform Cutoff Time */
// haptic_data[6] = 80; /* Retrigger Period */
// haptic_data[7] = 0; /* Retrigger Period */
} else {
haptic_data[4] = 0;
}
ret = hid_bpf_hw_request(ctx, haptic_data, size, HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
bpf_printk("set haptic ret value: %d -> %d", ret, haptic_data[4]);
args->retval = ret;
hid_bpf_release_context(ctx);
return 0;
}
/* Convert REL_DIAL into REL_WHEEL */
SEC("fmod_ret/hid_bpf_rdesc_fixup")
int BPF_PROG(hid_rdesc_fixup, struct hid_bpf_ctx *hctx)
{
__u8 *data = hid_bpf_get_data(hctx, 0 /* offset */, 4096 /* size */);
__u16 *res, *phys;
if (!data)
return 0; /* EPERM check */
/* Convert TOUCH into a button */
data[31] = HID_UP_BUTTON;
data[33] = 2;
/* Convert REL_DIAL into REL_WHEEL */
data[45] = HID_GD_WHEEL;
/* Change Resolution Multiplier */
phys = (__u16 *)&data[61];
*phys = physical;
res = (__u16 *)&data[66];
*res = resolution;
/* Convert X,Y from Abs to Rel */
data[88] = 0x06;
data[98] = 0x06;
return 0;
}
char _license[] SEC("license") = "GPL";
u32 _version SEC("version") = 1;
// SPDX-License-Identifier: GPL-2.0-only
/* Copyright (c) 2022 Benjamin Tissoires
*
* This program will morph the Microsoft Surface Dial into a mouse,
* and depending on the chosen resolution enable or not the haptic feedback:
* - a resolution (-r) of 3600 will report 3600 "ticks" in one full rotation
* without haptic feedback
* - any other resolution will report N "ticks" in a full rotation with haptic
* feedback
*
* A good default for low resolution haptic scrolling is 72 (1 "tick" every 5
* degrees), and set to 3600 for smooth scrolling.
*/
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <libgen.h>
#include <signal.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/resource.h>
#include <unistd.h>
#include <linux/bpf.h>
#include <linux/errno.h>
#include <bpf/bpf.h>
#include <bpf/libbpf.h>
#include "hid_surface_dial.skel.h"
#include "hid_bpf_attach.h"
static bool running = true;
struct haptic_syscall_args {
unsigned int hid;
int retval;
};
static void int_exit(int sig)
{
running = false;
exit(0);
}
static void usage(const char *prog)
{
fprintf(stderr,
"%s: %s [OPTIONS] /sys/bus/hid/devices/0BUS:0VID:0PID:00ID\n\n"
" OPTIONS:\n"
" -r N\t set the given resolution to the device (number of ticks per 360°)\n\n",
__func__, prog);
fprintf(stderr,
"This program will morph the Microsoft Surface Dial into a mouse,\n"
"and depending on the chosen resolution enable or not the haptic feedback:\n"
"- a resolution (-r) of 3600 will report 3600 'ticks' in one full rotation\n"
" without haptic feedback\n"
"- any other resolution will report N 'ticks' in a full rotation with haptic\n"
" feedback\n"
"\n"
"A good default for low resolution haptic scrolling is 72 (1 'tick' every 5\n"
"degrees), and set to 3600 for smooth scrolling.\n");
}
static int get_hid_id(const char *path)
{
const char *str_id, *dir;
char uevent[1024];
int fd;
memset(uevent, 0, sizeof(uevent));
snprintf(uevent, sizeof(uevent) - 1, "%s/uevent", path);
fd = open(uevent, O_RDONLY | O_NONBLOCK);
if (fd < 0)
return -ENOENT;
close(fd);
dir = basename((char *)path);
str_id = dir + sizeof("0003:0001:0A37.");
return (int)strtol(str_id, NULL, 16);
}
static int attach_prog(struct hid_surface_dial *skel, struct bpf_program *prog, int hid_id)
{
struct attach_prog_args args = {
.hid = hid_id,
.retval = -1,
};
int attach_fd, err;
DECLARE_LIBBPF_OPTS(bpf_test_run_opts, tattr,
.ctx_in = &args,
.ctx_size_in = sizeof(args),
);
attach_fd = bpf_program__fd(skel->progs.attach_prog);
if (attach_fd < 0) {
fprintf(stderr, "can't locate attach prog: %m\n");
return 1;
}
args.prog_fd = bpf_program__fd(prog);
err = bpf_prog_test_run_opts(attach_fd, &tattr);
if (err) {
fprintf(stderr, "can't attach prog to hid device %d: %m (err: %d)\n",
hid_id, err);
return 1;
}
return 0;
}
static int set_haptic(struct hid_surface_dial *skel, int hid_id)
{
struct haptic_syscall_args args = {
.hid = hid_id,
.retval = -1,
};
int haptic_fd, err;
DECLARE_LIBBPF_OPTS(bpf_test_run_opts, tattr,
.ctx_in = &args,
.ctx_size_in = sizeof(args),
);
haptic_fd = bpf_program__fd(skel->progs.set_haptic);
if (haptic_fd < 0) {
fprintf(stderr, "can't locate haptic prog: %m\n");
return 1;
}
err = bpf_prog_test_run_opts(haptic_fd, &tattr);
if (err) {
fprintf(stderr, "can't set haptic configuration to hid device %d: %m (err: %d)\n",
hid_id, err);
return 1;
}
return 0;
}
int main(int argc, char **argv)
{
struct hid_surface_dial *skel;
struct bpf_program *prog;
const char *optstr = "r:";
const char *sysfs_path;
int opt, hid_id, resolution = 72;
while ((opt = getopt(argc, argv, optstr)) != -1) {
switch (opt) {
case 'r':
{
char *endp = NULL;
long l = -1;
if (optarg) {
l = strtol(optarg, &endp, 10);
if (endp && *endp)
l = -1;
}
if (l < 0) {
fprintf(stderr,
"invalid r option %s - expecting a number\n",
optarg ? optarg : "");
exit(EXIT_FAILURE);
};
resolution = (int) l;
break;
}
default:
usage(basename(argv[0]));
return 1;
}
}
if (optind == argc) {
usage(basename(argv[0]));
return 1;
}
sysfs_path = argv[optind];
if (!sysfs_path) {
perror("sysfs");
return 1;
}
skel = hid_surface_dial__open_and_load();
if (!skel) {
fprintf(stderr, "%s %s:%d", __func__, __FILE__, __LINE__);
return -1;
}
hid_id = get_hid_id(sysfs_path);
if (hid_id < 0) {
fprintf(stderr, "can not open HID device: %m\n");
return 1;
}
skel->data->resolution = resolution;
skel->data->physical = (int)(resolution / 72);
bpf_object__for_each_program(prog, *skel->skeleton->obj) {
/* ignore syscalls */
if (bpf_program__get_type(prog) != BPF_PROG_TYPE_TRACING)
continue;
attach_prog(skel, prog, hid_id);
}
signal(SIGINT, int_exit);
signal(SIGTERM, int_exit);
set_haptic(skel, hid_id);
while (running)
sleep(1);
hid_surface_dial__destroy(skel);
return 0;
}
......@@ -26,6 +26,7 @@ TARGETS += fpu
TARGETS += ftrace
TARGETS += futex
TARGETS += gpio
TARGETS += hid
TARGETS += intel_pstate
TARGETS += iommu
TARGETS += ipc
......
bpftool
*.skel.h
/tools
hid_bpf
results
# SPDX-License-Identifier: GPL-2.0
# based on tools/testing/selftest/bpf/Makefile
include ../../../build/Build.include
include ../../../scripts/Makefile.arch
include ../../../scripts/Makefile.include
CXX ?= $(CROSS_COMPILE)g++
HOSTPKG_CONFIG := pkg-config
CFLAGS += -g -O0 -rdynamic -Wall -Werror -I$(KHDR_INCLUDES) -I$(OUTPUT)
LDLIBS += -lelf -lz -lrt -lpthread
# Silence some warnings when compiled with clang
ifneq ($(LLVM),)
CFLAGS += -Wno-unused-command-line-argument
endif
# Order correspond to 'make run_tests' order
TEST_GEN_PROGS = hid_bpf
# Emit succinct information message describing current building step
# $1 - generic step name (e.g., CC, LINK, etc);
# $2 - optional "flavor" specifier; if provided, will be emitted as [flavor];
# $3 - target (assumed to be file); only file name will be emitted;
# $4 - optional extra arg, emitted as-is, if provided.
ifeq ($(V),1)
Q =
msg =
else
Q = @
msg = @printf ' %-8s%s %s%s\n' "$(1)" "$(if $(2), [$(2)])" "$(notdir $(3))" "$(if $(4), $(4))";
MAKEFLAGS += --no-print-directory
submake_extras := feature_display=0
endif
# override lib.mk's default rules
OVERRIDE_TARGETS := 1
override define CLEAN
$(call msg,CLEAN)
$(Q)$(RM) -r $(TEST_GEN_PROGS)
$(Q)$(RM) -r $(EXTRA_CLEAN)
endef
include ../lib.mk
TOOLSDIR := $(top_srcdir)/tools
LIBDIR := $(TOOLSDIR)/lib
BPFDIR := $(LIBDIR)/bpf
TOOLSINCDIR := $(TOOLSDIR)/include
BPFTOOLDIR := $(TOOLSDIR)/bpf/bpftool
SCRATCH_DIR := $(OUTPUT)/tools
BUILD_DIR := $(SCRATCH_DIR)/build
INCLUDE_DIR := $(SCRATCH_DIR)/include
KHDR_INCLUDES := $(SCRATCH_DIR)/uapi/include
BPFOBJ := $(BUILD_DIR)/libbpf/libbpf.a
ifneq ($(CROSS_COMPILE),)
HOST_BUILD_DIR := $(BUILD_DIR)/host
HOST_SCRATCH_DIR := $(OUTPUT)/host-tools
HOST_INCLUDE_DIR := $(HOST_SCRATCH_DIR)/include
else
HOST_BUILD_DIR := $(BUILD_DIR)
HOST_SCRATCH_DIR := $(SCRATCH_DIR)
HOST_INCLUDE_DIR := $(INCLUDE_DIR)
endif
HOST_BPFOBJ := $(HOST_BUILD_DIR)/libbpf/libbpf.a
RESOLVE_BTFIDS := $(HOST_BUILD_DIR)/resolve_btfids/resolve_btfids
VMLINUX_BTF_PATHS ?= $(if $(O),$(O)/vmlinux) \
$(if $(KBUILD_OUTPUT),$(KBUILD_OUTPUT)/vmlinux) \
../../../../vmlinux \
/sys/kernel/btf/vmlinux \
/boot/vmlinux-$(shell uname -r)
VMLINUX_BTF ?= $(abspath $(firstword $(wildcard $(VMLINUX_BTF_PATHS))))
ifeq ($(VMLINUX_BTF),)
$(error Cannot find a vmlinux for VMLINUX_BTF at any of "$(VMLINUX_BTF_PATHS)")
endif
# Define simple and short `make test_progs`, `make test_sysctl`, etc targets
# to build individual tests.
# NOTE: Semicolon at the end is critical to override lib.mk's default static
# rule for binaries.
$(notdir $(TEST_GEN_PROGS)): %: $(OUTPUT)/% ;
# sort removes libbpf duplicates when not cross-building
MAKE_DIRS := $(sort $(BUILD_DIR)/libbpf $(HOST_BUILD_DIR)/libbpf \
$(HOST_BUILD_DIR)/bpftool $(HOST_BUILD_DIR)/resolve_btfids \
$(INCLUDE_DIR))
$(MAKE_DIRS):
$(call msg,MKDIR,,$@)
$(Q)mkdir -p $@
# LLVM's ld.lld doesn't support all the architectures, so use it only on x86
ifeq ($(SRCARCH),x86)
LLD := lld
else
LLD := ld
endif
DEFAULT_BPFTOOL := $(HOST_SCRATCH_DIR)/sbin/bpftool
TEST_GEN_PROGS_EXTENDED += $(DEFAULT_BPFTOOL)
$(TEST_GEN_PROGS) $(TEST_GEN_PROGS_EXTENDED): $(BPFOBJ)
BPFTOOL ?= $(DEFAULT_BPFTOOL)
$(DEFAULT_BPFTOOL): $(wildcard $(BPFTOOLDIR)/*.[ch] $(BPFTOOLDIR)/Makefile) \
$(HOST_BPFOBJ) | $(HOST_BUILD_DIR)/bpftool
$(Q)$(MAKE) $(submake_extras) -C $(BPFTOOLDIR) \
ARCH= CROSS_COMPILE= CC=$(HOSTCC) LD=$(HOSTLD) \
EXTRA_CFLAGS='-g -O0' \
OUTPUT=$(HOST_BUILD_DIR)/bpftool/ \
LIBBPF_OUTPUT=$(HOST_BUILD_DIR)/libbpf/ \
LIBBPF_DESTDIR=$(HOST_SCRATCH_DIR)/ \
prefix= DESTDIR=$(HOST_SCRATCH_DIR)/ install-bin
$(BPFOBJ): $(wildcard $(BPFDIR)/*.[ch] $(BPFDIR)/Makefile) \
| $(BUILD_DIR)/libbpf
$(Q)$(MAKE) $(submake_extras) -C $(BPFDIR) OUTPUT=$(BUILD_DIR)/libbpf/ \
EXTRA_CFLAGS='-g -O0' \
DESTDIR=$(SCRATCH_DIR) prefix= all install_headers
ifneq ($(BPFOBJ),$(HOST_BPFOBJ))
$(HOST_BPFOBJ): $(wildcard $(BPFDIR)/*.[ch] $(BPFDIR)/Makefile) \
| $(HOST_BUILD_DIR)/libbpf
$(Q)$(MAKE) $(submake_extras) -C $(BPFDIR) \
EXTRA_CFLAGS='-g -O0' ARCH= CROSS_COMPILE= \
OUTPUT=$(HOST_BUILD_DIR)/libbpf/ CC=$(HOSTCC) LD=$(HOSTLD) \
DESTDIR=$(HOST_SCRATCH_DIR)/ prefix= all install_headers
endif
$(INCLUDE_DIR)/vmlinux.h: $(VMLINUX_BTF) $(BPFTOOL) | $(INCLUDE_DIR)
ifeq ($(VMLINUX_H),)
$(call msg,GEN,,$@)
$(Q)$(BPFTOOL) btf dump file $(VMLINUX_BTF) format c > $@
else
$(call msg,CP,,$@)
$(Q)cp "$(VMLINUX_H)" $@
endif
$(KHDR_INCLUDES)/linux/hid.h: $(top_srcdir)/include/uapi/linux/hid.h
$(MAKE) -C $(top_srcdir) INSTALL_HDR_PATH=$(SCRATCH_DIR)/uapi headers_install
$(RESOLVE_BTFIDS): $(HOST_BPFOBJ) | $(HOST_BUILD_DIR)/resolve_btfids \
$(TOOLSDIR)/bpf/resolve_btfids/main.c \
$(TOOLSDIR)/lib/rbtree.c \
$(TOOLSDIR)/lib/zalloc.c \
$(TOOLSDIR)/lib/string.c \
$(TOOLSDIR)/lib/ctype.c \
$(TOOLSDIR)/lib/str_error_r.c
$(Q)$(MAKE) $(submake_extras) -C $(TOOLSDIR)/bpf/resolve_btfids \
CC=$(HOSTCC) LD=$(HOSTLD) AR=$(HOSTAR) \
LIBBPF_INCLUDE=$(HOST_INCLUDE_DIR) \
OUTPUT=$(HOST_BUILD_DIR)/resolve_btfids/ BPFOBJ=$(HOST_BPFOBJ)
# Get Clang's default includes on this system, as opposed to those seen by
# '-target bpf'. This fixes "missing" files on some architectures/distros,
# such as asm/byteorder.h, asm/socket.h, asm/sockios.h, sys/cdefs.h etc.
#
# Use '-idirafter': Don't interfere with include mechanics except where the
# build would have failed anyways.
define get_sys_includes
$(shell $(1) -v -E - </dev/null 2>&1 \
| sed -n '/<...> search starts here:/,/End of search list./{ s| \(/.*\)|-idirafter \1|p }') \
$(shell $(1) -dM -E - </dev/null | grep '__riscv_xlen ' | awk '{printf("-D__riscv_xlen=%d -D__BITS_PER_LONG=%d", $$3, $$3)}')
endef
# Determine target endianness.
IS_LITTLE_ENDIAN = $(shell $(CC) -dM -E - </dev/null | \
grep 'define __BYTE_ORDER__ __ORDER_LITTLE_ENDIAN__')
MENDIAN=$(if $(IS_LITTLE_ENDIAN),-mlittle-endian,-mbig-endian)
CLANG_SYS_INCLUDES = $(call get_sys_includes,$(CLANG))
BPF_CFLAGS = -g -Werror -D__TARGET_ARCH_$(SRCARCH) $(MENDIAN) \
-I$(INCLUDE_DIR)
CLANG_CFLAGS = $(CLANG_SYS_INCLUDES) \
-Wno-compare-distinct-pointer-types
# Build BPF object using Clang
# $1 - input .c file
# $2 - output .o file
# $3 - CFLAGS
define CLANG_BPF_BUILD_RULE
$(call msg,CLNG-BPF,$(TRUNNER_BINARY),$2)
$(Q)$(CLANG) $3 -O2 -target bpf -c $1 -mcpu=v3 -o $2
endef
# Similar to CLANG_BPF_BUILD_RULE, but with disabled alu32
define CLANG_NOALU32_BPF_BUILD_RULE
$(call msg,CLNG-BPF,$(TRUNNER_BINARY),$2)
$(Q)$(CLANG) $3 -O2 -target bpf -c $1 -mcpu=v2 -o $2
endef
# Build BPF object using GCC
define GCC_BPF_BUILD_RULE
$(call msg,GCC-BPF,$(TRUNNER_BINARY),$2)
$(Q)$(BPF_GCC) $3 -O2 -c $1 -o $2
endef
BPF_PROGS_DIR := progs
BPF_BUILD_RULE := CLANG_BPF_BUILD_RULE
BPF_SRCS := $(notdir $(wildcard $(BPF_PROGS_DIR)/*.c))
BPF_OBJS := $(patsubst %.c,$(OUTPUT)/%.bpf.o, $(BPF_SRCS))
BPF_SKELS := $(patsubst %.c,$(OUTPUT)/%.skel.h, $(BPF_SRCS))
TEST_GEN_FILES += $(BPF_OBJS)
$(BPF_PROGS_DIR)-bpfobjs := y
$(BPF_OBJS): $(OUTPUT)/%.bpf.o: \
$(BPF_PROGS_DIR)/%.c \
$(wildcard $(BPF_PROGS_DIR)/*.h) \
$(INCLUDE_DIR)/vmlinux.h \
$(wildcard $(BPFDIR)/hid_bpf_*.h) \
$(wildcard $(BPFDIR)/*.bpf.h) \
| $(OUTPUT) $(BPFOBJ)
$(call $(BPF_BUILD_RULE),$<,$@, $(BPF_CFLAGS))
$(BPF_SKELS): %.skel.h: %.bpf.o $(BPFTOOL) | $(OUTPUT)
$(call msg,GEN-SKEL,$(BINARY),$@)
$(Q)$(BPFTOOL) gen object $(<:.o=.linked1.o) $<
$(Q)$(BPFTOOL) gen skeleton $(<:.o=.linked1.o) name $(notdir $(<:.bpf.o=)) > $@
$(OUTPUT)/%.o: %.c $(BPF_SKELS) $(KHDR_INCLUDES)/linux/hid.h
$(call msg,CC,,$@)
$(Q)$(CC) $(CFLAGS) -c $(filter %.c,$^) $(LDLIBS) -o $@
$(OUTPUT)/%: $(OUTPUT)/%.o
$(call msg,BINARY,,$@)
$(Q)$(LINK.c) $^ $(LDLIBS) -o $@
EXTRA_CLEAN := $(SCRATCH_DIR) $(HOST_SCRATCH_DIR) feature bpftool \
$(addprefix $(OUTPUT)/,*.o *.skel.h no_alu32)
CONFIG_BPF_EVENTS=y
CONFIG_BPFILTER=y
CONFIG_BPF_JIT_ALWAYS_ON=y
CONFIG_BPF_JIT=y
CONFIG_BPF_KPROBE_OVERRIDE=y
CONFIG_BPF_LSM=y
CONFIG_BPF_PRELOAD_UMD=y
CONFIG_BPF_PRELOAD=y
CONFIG_BPF_STREAM_PARSER=y
CONFIG_BPF_SYSCALL=y
CONFIG_BPF=y
CONFIG_CGROUP_BPF=y
CONFIG_DEBUG_INFO_BTF=y
CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS=y
CONFIG_FPROBE=y
CONFIG_FTRACE_SYSCALLS=y
CONFIG_FUNCTION_TRACER=y
CONFIG_HIDRAW=y
CONFIG_HID=y
CONFIG_INPUT_EVDEV=y
CONFIG_UHID=y
CONFIG_9P_FS_POSIX_ACL=y
CONFIG_9P_FS_SECURITY=y
CONFIG_9P_FS=y
CONFIG_AUDIT=y
CONFIG_BINFMT_MISC=y
CONFIG_BLK_CGROUP_IOLATENCY=y
CONFIG_BLK_CGROUP=y
CONFIG_BLK_DEV_BSGLIB=y
CONFIG_BLK_DEV_IO_TRACE=y
CONFIG_BLK_DEV_RAM_SIZE=16384
CONFIG_BLK_DEV_RAM=y
CONFIG_BLK_DEV_THROTTLING=y
CONFIG_BONDING=y
CONFIG_BOOTPARAM_HARDLOCKUP_PANIC=y
CONFIG_BOOTTIME_TRACING=y
CONFIG_BSD_DISKLABEL=y
CONFIG_BSD_PROCESS_ACCT=y
CONFIG_CFS_BANDWIDTH=y
CONFIG_CGROUP_CPUACCT=y
CONFIG_CGROUP_DEBUG=y
CONFIG_CGROUP_DEVICE=y
CONFIG_CGROUP_FREEZER=y
CONFIG_CGROUP_HUGETLB=y
CONFIG_CGROUP_NET_CLASSID=y
CONFIG_CGROUP_NET_PRIO=y
CONFIG_CGROUP_PERF=y
CONFIG_CGROUP_PIDS=y
CONFIG_CGROUP_RDMA=y
CONFIG_CGROUP_SCHED=y
CONFIG_CGROUPS=y
CONFIG_CGROUP_WRITEBACK=y
CONFIG_CMA_AREAS=7
CONFIG_CMA=y
CONFIG_COMPAT_32BIT_TIME=y
CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y
CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
CONFIG_CPU_FREQ_GOV_ONDEMAND=y
CONFIG_CPU_FREQ_GOV_USERSPACE=y
CONFIG_CPU_FREQ_STAT=y
CONFIG_CPU_IDLE_GOV_LADDER=y
CONFIG_CPUSETS=y
CONFIG_CRC_T10DIF=y
CONFIG_CRYPTO_BLAKE2B=y
CONFIG_CRYPTO_DEV_VIRTIO=y
CONFIG_CRYPTO_SEQIV=y
CONFIG_CRYPTO_XXHASH=y
CONFIG_DCB=y
CONFIG_DEBUG_ATOMIC_SLEEP=y
CONFIG_DEBUG_CREDENTIALS=y
CONFIG_DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT=y
CONFIG_DEBUG_MEMORY_INIT=y
CONFIG_DEFAULT_FQ_CODEL=y
CONFIG_DEFAULT_RENO=y
CONFIG_DEFAULT_SECURITY_DAC=y
CONFIG_DEVTMPFS_MOUNT=y
CONFIG_DEVTMPFS=y
CONFIG_DMA_CMA=y
CONFIG_DNS_RESOLVER=y
CONFIG_EFI_STUB=y
CONFIG_EFI=y
CONFIG_EXPERT=y
CONFIG_EXT4_FS_POSIX_ACL=y
CONFIG_EXT4_FS_SECURITY=y
CONFIG_EXT4_FS=y
CONFIG_FAIL_FUNCTION=y
CONFIG_FAULT_INJECTION_DEBUG_FS=y
CONFIG_FAULT_INJECTION=y
CONFIG_FB_MODE_HELPERS=y
CONFIG_FB_TILEBLITTING=y
CONFIG_FB_VESA=y
CONFIG_FB=y
CONFIG_FONT_8x16=y
CONFIG_FONT_MINI_4x6=y
CONFIG_FONTS=y
CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y
CONFIG_FRAMEBUFFER_CONSOLE_ROTATION=y
CONFIG_FRAMEBUFFER_CONSOLE=y
CONFIG_FUSE_FS=y
CONFIG_FW_LOADER_USER_HELPER=y
CONFIG_GART_IOMMU=y
CONFIG_GENERIC_PHY=y
CONFIG_HARDLOCKUP_DETECTOR=y
CONFIG_HIGH_RES_TIMERS=y
CONFIG_HPET=y
CONFIG_HUGETLBFS=y
CONFIG_HUGETLB_PAGE=y
CONFIG_HWPOISON_INJECT=y
CONFIG_HZ_1000=y
CONFIG_INET=y
CONFIG_INTEL_POWERCLAMP=y
CONFIG_IP6_NF_FILTER=y
CONFIG_IP6_NF_IPTABLES=y
CONFIG_IP6_NF_NAT=y
CONFIG_IP6_NF_TARGET_MASQUERADE=y
CONFIG_IP_ADVANCED_ROUTER=y
CONFIG_IP_MROUTE=y
CONFIG_IP_MULTICAST=y
CONFIG_IP_MULTIPLE_TABLES=y
CONFIG_IP_NF_FILTER=y
CONFIG_IP_NF_IPTABLES=y
CONFIG_IP_NF_NAT=y
CONFIG_IP_NF_TARGET_MASQUERADE=y
CONFIG_IP_PIMSM_V1=y
CONFIG_IP_PIMSM_V2=y
CONFIG_IP_ROUTE_MULTIPATH=y
CONFIG_IP_ROUTE_VERBOSE=y
CONFIG_IPV6_MIP6=y
CONFIG_IPV6_ROUTE_INFO=y
CONFIG_IPV6_ROUTER_PREF=y
CONFIG_IPV6_SEG6_LWTUNNEL=y
CONFIG_IPV6_SUBTREES=y
CONFIG_IRQ_POLL=y
CONFIG_JUMP_LABEL=y
CONFIG_KARMA_PARTITION=y
CONFIG_KEXEC=y
CONFIG_KPROBES=y
CONFIG_KSM=y
CONFIG_LEGACY_VSYSCALL_NONE=y
CONFIG_LOG_BUF_SHIFT=21
CONFIG_LOG_CPU_MAX_BUF_SHIFT=0
CONFIG_LOGO=y
CONFIG_LSM="selinux,bpf,integrity"
CONFIG_MAC_PARTITION=y
CONFIG_MAGIC_SYSRQ=y
CONFIG_MCORE2=y
CONFIG_MEMCG=y
CONFIG_MEMORY_FAILURE=y
CONFIG_MINIX_SUBPARTITION=y
CONFIG_MODULES=y
CONFIG_NAMESPACES=y
CONFIG_NET_9P_VIRTIO=y
CONFIG_NET_9P=y
CONFIG_NET_ACT_BPF=y
CONFIG_NET_CLS_CGROUP=y
CONFIG_NETDEVICES=y
CONFIG_NET_EMATCH=y
CONFIG_NETFILTER_NETLINK_LOG=y
CONFIG_NETFILTER_NETLINK_QUEUE=y
CONFIG_NETFILTER_XTABLES=y
CONFIG_NETFILTER_XT_MATCH_ADDRTYPE=y
CONFIG_NETFILTER_XT_MATCH_BPF=y
CONFIG_NETFILTER_XT_MATCH_COMMENT=y
CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y
CONFIG_NETFILTER_XT_MATCH_MARK=y
CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y
CONFIG_NETFILTER_XT_MATCH_STATISTIC=y
CONFIG_NETFILTER_XT_NAT=y
CONFIG_NETFILTER_XT_TARGET_MASQUERADE=y
CONFIG_NET_IPGRE_BROADCAST=y
CONFIG_NET_L3_MASTER_DEV=y
CONFIG_NETLABEL=y
CONFIG_NET_SCH_DEFAULT=y
CONFIG_NET_SCHED=y
CONFIG_NET_SCH_FQ_CODEL=y
CONFIG_NET_TC_SKB_EXT=y
CONFIG_NET_VRF=y
CONFIG_NET=y
CONFIG_NF_CONNTRACK=y
CONFIG_NF_NAT_MASQUERADE=y
CONFIG_NF_NAT=y
CONFIG_NLS_ASCII=y
CONFIG_NLS_CODEPAGE_437=y
CONFIG_NLS_DEFAULT="utf8"
CONFIG_NO_HZ=y
CONFIG_NR_CPUS=128
CONFIG_NUMA_BALANCING=y
CONFIG_NUMA=y
CONFIG_NVMEM=y
CONFIG_OSF_PARTITION=y
CONFIG_OVERLAY_FS_INDEX=y
CONFIG_OVERLAY_FS_METACOPY=y
CONFIG_OVERLAY_FS_XINO_AUTO=y
CONFIG_OVERLAY_FS=y
CONFIG_PACKET=y
CONFIG_PANIC_ON_OOPS=y
CONFIG_PARTITION_ADVANCED=y
CONFIG_PCIEPORTBUS=y
CONFIG_PCI_IOV=y
CONFIG_PCI_MSI=y
CONFIG_PCI=y
CONFIG_PHYSICAL_ALIGN=0x1000000
CONFIG_POSIX_MQUEUE=y
CONFIG_POWER_SUPPLY=y
CONFIG_PREEMPT=y
CONFIG_PRINTK_TIME=y
CONFIG_PROC_KCORE=y
CONFIG_PROFILING=y
CONFIG_PROVE_LOCKING=y
CONFIG_PTP_1588_CLOCK=y
CONFIG_RC_DEVICES=y
CONFIG_RC_LOOPBACK=y
CONFIG_RCU_CPU_STALL_TIMEOUT=60
CONFIG_SCHED_STACK_END_CHECK=y
CONFIG_SCHEDSTATS=y
CONFIG_SECURITY_NETWORK=y
CONFIG_SECURITY_SELINUX=y
CONFIG_SERIAL_8250_CONSOLE=y
CONFIG_SERIAL_8250_DETECT_IRQ=y
CONFIG_SERIAL_8250_EXTENDED=y
CONFIG_SERIAL_8250_MANY_PORTS=y
CONFIG_SERIAL_8250_NR_UARTS=32
CONFIG_SERIAL_8250_RSA=y
CONFIG_SERIAL_8250_SHARE_IRQ=y
CONFIG_SERIAL_8250=y
CONFIG_SERIAL_NONSTANDARD=y
CONFIG_SERIO_LIBPS2=y
CONFIG_SGI_PARTITION=y
CONFIG_SMP=y
CONFIG_SOCK_CGROUP_DATA=y
CONFIG_SOLARIS_X86_PARTITION=y
CONFIG_SUN_PARTITION=y
CONFIG_SYNC_FILE=y
CONFIG_SYSVIPC=y
CONFIG_TASK_DELAY_ACCT=y
CONFIG_TASK_IO_ACCOUNTING=y
CONFIG_TASKSTATS=y
CONFIG_TASK_XACCT=y
CONFIG_TCP_CONG_ADVANCED=y
CONFIG_TCP_MD5SIG=y
CONFIG_TLS=y
CONFIG_TMPFS_POSIX_ACL=y
CONFIG_TMPFS=y
CONFIG_TRANSPARENT_HUGEPAGE_MADVISE=y
CONFIG_TRANSPARENT_HUGEPAGE=y
CONFIG_TUN=y
CONFIG_UNIXWARE_DISKLABEL=y
CONFIG_UNIX=y
CONFIG_USER_NS=y
CONFIG_VALIDATE_FS_PARSER=y
CONFIG_VETH=y
CONFIG_VIRT_DRIVERS=y
CONFIG_VIRTIO_BALLOON=y
CONFIG_VIRTIO_BLK=y
CONFIG_VIRTIO_CONSOLE=y
CONFIG_VIRTIO_FS=y
CONFIG_VIRTIO_NET=y
CONFIG_VIRTIO_PCI=y
CONFIG_VLAN_8021Q=y
CONFIG_XFRM_SUB_POLICY=y
CONFIG_XFRM_USER=y
CONFIG_ZEROPLUS_FF=y
CONFIG_X86_ACPI_CPUFREQ=y
CONFIG_X86_CPUID=y
CONFIG_X86_MSR=y
CONFIG_X86_POWERNOW_K8=y
This diff is collapsed.
This diff is collapsed.
/* SPDX-License-Identifier: GPL-2.0-only */
/* Copyright (c) 2022 Benjamin Tissoires
*/
#ifndef __HID_BPF_HELPERS_H
#define __HID_BPF_HELPERS_H
/* following are kfuncs exported by HID for HID-BPF */
extern __u8 *hid_bpf_get_data(struct hid_bpf_ctx *ctx,
unsigned int offset,
const size_t __sz) __ksym;
extern int hid_bpf_attach_prog(unsigned int hid_id, int prog_fd, u32 flags) __ksym;
extern struct hid_bpf_ctx *hid_bpf_allocate_context(unsigned int hid_id) __ksym;
extern void hid_bpf_release_context(struct hid_bpf_ctx *ctx) __ksym;
extern int hid_bpf_hw_request(struct hid_bpf_ctx *ctx,
__u8 *data,
size_t buf__sz,
enum hid_report_type type,
enum hid_class_request reqtype) __ksym;
#endif /* __HID_BPF_HELPERS_H */
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment