~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/Documentation/hid/hid-bpf.rst

Version: ~ [ linux-6.12-rc7 ] ~ [ linux-6.11.7 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.60 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.116 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.171 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.229 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.285 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.323 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.12 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

Diff markup

Differences between /Documentation/hid/hid-bpf.rst (Version linux-6.12-rc7) and /Documentation/hid/hid-bpf.rst (Version linux-6.7.12)


  1 .. SPDX-License-Identifier: GPL-2.0                 1 .. SPDX-License-Identifier: GPL-2.0
  2                                                     2 
  3 =======                                             3 =======
  4 HID-BPF                                             4 HID-BPF
  5 =======                                             5 =======
  6                                                     6 
  7 HID is a standard protocol for input devices b      7 HID is a standard protocol for input devices but some devices may require
  8 custom tweaks, traditionally done with a kerne      8 custom tweaks, traditionally done with a kernel driver fix. Using the eBPF
  9 capabilities instead speeds up development and      9 capabilities instead speeds up development and adds new capabilities to the
 10 existing HID interfaces.                           10 existing HID interfaces.
 11                                                    11 
 12 .. contents::                                      12 .. contents::
 13     :local:                                        13     :local:
 14     :depth: 2                                      14     :depth: 2
 15                                                    15 
 16                                                    16 
 17 When (and why) to use HID-BPF                      17 When (and why) to use HID-BPF
 18 =============================                      18 =============================
 19                                                    19 
 20 There are several use cases when using HID-BPF     20 There are several use cases when using HID-BPF is better
 21 than standard kernel driver fix:                   21 than standard kernel driver fix:
 22                                                    22 
 23 Dead zone of a joystick                            23 Dead zone of a joystick
 24 -----------------------                            24 -----------------------
 25                                                    25 
 26 Assuming you have a joystick that is getting o     26 Assuming you have a joystick that is getting older, it is common to see it
 27 wobbling around its neutral point. This is usu     27 wobbling around its neutral point. This is usually filtered at the application
 28 level by adding a *dead zone* for this specifi     28 level by adding a *dead zone* for this specific axis.
 29                                                    29 
 30 With HID-BPF, we can apply this filtering in t     30 With HID-BPF, we can apply this filtering in the kernel directly so userspace
 31 does not get woken up when nothing else is hap     31 does not get woken up when nothing else is happening on the input controller.
 32                                                    32 
 33 Of course, given that this dead zone is specif     33 Of course, given that this dead zone is specific to an individual device, we
 34 can not create a generic fix for all of the sa     34 can not create a generic fix for all of the same joysticks. Adding a custom
 35 kernel API for this (e.g. by adding a sysfs en     35 kernel API for this (e.g. by adding a sysfs entry) does not guarantee this new
 36 kernel API will be broadly adopted and maintai     36 kernel API will be broadly adopted and maintained.
 37                                                    37 
 38 HID-BPF allows the userspace program to load t     38 HID-BPF allows the userspace program to load the program itself, ensuring we
 39 only load the custom API when we have a user.      39 only load the custom API when we have a user.
 40                                                    40 
 41 Simple fixup of report descriptor                  41 Simple fixup of report descriptor
 42 ---------------------------------                  42 ---------------------------------
 43                                                    43 
 44 In the HID tree, half of the drivers only fix      44 In the HID tree, half of the drivers only fix one key or one byte
 45 in the report descriptor. These fixes all requ     45 in the report descriptor. These fixes all require a kernel patch and the
 46 subsequent shepherding into a release, a long      46 subsequent shepherding into a release, a long and painful process for users.
 47                                                    47 
 48 We can reduce this burden by providing an eBPF     48 We can reduce this burden by providing an eBPF program instead. Once such a
 49 program  has been verified by the user, we can     49 program  has been verified by the user, we can embed the source code into the
 50 kernel tree and ship the eBPF program and load     50 kernel tree and ship the eBPF program and load it directly instead of loading
 51 a specific kernel module for it.                   51 a specific kernel module for it.
 52                                                    52 
 53 Note: distribution of eBPF programs and their      53 Note: distribution of eBPF programs and their inclusion in the kernel is not
 54 yet fully implemented                              54 yet fully implemented
 55                                                    55 
 56 Add a new feature that requires a new kernel A     56 Add a new feature that requires a new kernel API
 57 ----------------------------------------------     57 ------------------------------------------------
 58                                                    58 
 59 An example for such a feature are the Universa     59 An example for such a feature are the Universal Stylus Interface (USI) pens.
 60 Basically, USI pens require a new kernel API b     60 Basically, USI pens require a new kernel API because there are new
 61 channels of communication that our HID and inp     61 channels of communication that our HID and input stack do not support.
 62 Instead of using hidraw or creating new sysfs      62 Instead of using hidraw or creating new sysfs entries or ioctls, we can rely
 63 on eBPF to have the kernel API controlled by t     63 on eBPF to have the kernel API controlled by the consumer and to not
 64 impact the performances by waking up userspace     64 impact the performances by waking up userspace every time there is an
 65 event.                                             65 event.
 66                                                    66 
 67 Morph a device into something else and control     67 Morph a device into something else and control that from userspace
 68 ----------------------------------------------     68 ------------------------------------------------------------------
 69                                                    69 
 70 The kernel has a relatively static mapping of      70 The kernel has a relatively static mapping of HID items to evdev bits.
 71 It cannot decide to dynamically transform a gi     71 It cannot decide to dynamically transform a given device into something else
 72 as it does not have the required context and a     72 as it does not have the required context and any such transformation cannot be
 73 undone (or even discovered) by userspace.          73 undone (or even discovered) by userspace.
 74                                                    74 
 75 However, some devices are useless with that st     75 However, some devices are useless with that static way of defining devices. For
 76 example, the Microsoft Surface Dial is a pushb     76 example, the Microsoft Surface Dial is a pushbutton with haptic feedback that
 77 is barely usable as of today.                      77 is barely usable as of today.
 78                                                    78 
 79 With eBPF, userspace can morph that device int     79 With eBPF, userspace can morph that device into a mouse, and convert the dial
 80 events into wheel events. Also, the userspace      80 events into wheel events. Also, the userspace program can set/unset the haptic
 81 feedback depending on the context. For example     81 feedback depending on the context. For example, if a menu is visible on the
 82 screen we likely need to have a haptic click e     82 screen we likely need to have a haptic click every 15 degrees. But when
 83 scrolling in a web page the user experience is     83 scrolling in a web page the user experience is better when the device emits
 84 events at the highest resolution.                  84 events at the highest resolution.
 85                                                    85 
 86 Firewall                                           86 Firewall
 87 --------                                           87 --------
 88                                                    88 
 89 What if we want to prevent other users to acce     89 What if we want to prevent other users to access a specific feature of a
 90 device? (think a possibly broken firmware upda     90 device? (think a possibly broken firmware update entry point)
 91                                                    91 
 92 With eBPF, we can intercept any HID command em     92 With eBPF, we can intercept any HID command emitted to the device and
 93 validate it or not.                                93 validate it or not.
 94                                                    94 
 95 This also allows to sync the state between the     95 This also allows to sync the state between the userspace and the
 96 kernel/bpf program because we can intercept an     96 kernel/bpf program because we can intercept any incoming command.
 97                                                    97 
 98 Tracing                                            98 Tracing
 99 -------                                            99 -------
100                                                   100 
101 The last usage is tracing events and all the f    101 The last usage is tracing events and all the fun we can do we BPF to summarize
102 and analyze events.                               102 and analyze events.
103                                                   103 
104 Right now, tracing relies on hidraw. It works     104 Right now, tracing relies on hidraw. It works well except for a couple
105 of issues:                                        105 of issues:
106                                                   106 
107 1. if the driver doesn't export a hidraw node,    107 1. if the driver doesn't export a hidraw node, we can't trace anything
108    (eBPF will be a "god-mode" there, so this m    108    (eBPF will be a "god-mode" there, so this may raise some eyebrows)
109 2. hidraw doesn't catch other processes' reque    109 2. hidraw doesn't catch other processes' requests to the device, which
110    means that we have cases where we need to a    110    means that we have cases where we need to add printks to the kernel
111    to understand what is happening.               111    to understand what is happening.
112                                                   112 
113 High-level view of HID-BPF                        113 High-level view of HID-BPF
114 ==========================                        114 ==========================
115                                                   115 
116 The main idea behind HID-BPF is that it works     116 The main idea behind HID-BPF is that it works at an array of bytes level.
117 Thus, all of the parsing of the HID report and    117 Thus, all of the parsing of the HID report and the HID report descriptor
118 must be implemented in the userspace component    118 must be implemented in the userspace component that loads the eBPF
119 program.                                          119 program.
120                                                   120 
121 For example, in the dead zone joystick from ab    121 For example, in the dead zone joystick from above, knowing which fields
122 in the data stream needs to be set to ``0`` ne    122 in the data stream needs to be set to ``0`` needs to be computed by userspace.
123                                                   123 
124 A corollary of this is that HID-BPF doesn't kn    124 A corollary of this is that HID-BPF doesn't know about the other subsystems
125 available in the kernel. *You can not directly    125 available in the kernel. *You can not directly emit input event through the
126 input API from eBPF*.                             126 input API from eBPF*.
127                                                   127 
128 When a BPF program needs to emit input events,    128 When a BPF program needs to emit input events, it needs to talk with the HID
129 protocol, and rely on the HID kernel processin    129 protocol, and rely on the HID kernel processing to translate the HID data into
130 input events.                                     130 input events.
131                                                   131 
132 In-tree HID-BPF programs and ``udev-hid-bpf``  << 
133 =============================================  << 
134                                                << 
135 Official device fixes are shipped in the kerne << 
136 ``drivers/hid/bpf/progs`` directory. This allo << 
137 ``tools/testing/selftests/hid``.               << 
138                                                << 
139 However, the compilation of these objects is n << 
140 given that they need an external tool to be lo << 
141 `udev-hid-bpf <https://libevdev.pages.freedesk << 
142                                                << 
143 For convenience, that external repository dupl << 
144 ``drivers/hid/bpf/progs`` into its own ``src/b << 
145 distributions to not have to pull the entire k << 
146 those HID-BPF fixes. ``udev-hid-bpf`` also has << 
147 objects files depending on the kernel the user << 
148                                                << 
149 Available types of programs                       132 Available types of programs
150 ===========================                       133 ===========================
151                                                   134 
152 HID-BPF is built "on top" of BPF, meaning that !! 135 HID-BPF is built "on top" of BPF, meaning that we use tracing method to
153 declare our programs.                             136 declare our programs.
154                                                   137 
155 HID-BPF has the following attachment types ava    138 HID-BPF has the following attachment types available:
156                                                   139 
157 1. event processing/filtering with ``SEC("stru !! 140 1. event processing/filtering with ``SEC("fmod_ret/hid_bpf_device_event")`` in libbpf
158 2. actions coming from userspace with ``SEC("s    141 2. actions coming from userspace with ``SEC("syscall")`` in libbpf
159 3. change of the report descriptor with ``SEC( !! 142 3. change of the report descriptor with ``SEC("fmod_ret/hid_bpf_rdesc_fixup")`` in libbpf
160    ``SEC("struct_ops.s/hid_rdesc_fixup")`` in  << 
161                                                   143 
162 A ``hid_device_event`` is calling a BPF progra !! 144 A ``hid_bpf_device_event`` is calling a BPF program when an event is received from
163 the device. Thus we are in IRQ context and can    145 the device. Thus we are in IRQ context and can act on the data or notify userspace.
164 And given that we are in IRQ context, we can n    146 And given that we are in IRQ context, we can not talk back to the device.
165                                                   147 
166 A ``syscall`` means that userspace called the     148 A ``syscall`` means that userspace called the syscall ``BPF_PROG_RUN`` facility.
167 This time, we can do any operations allowed by    149 This time, we can do any operations allowed by HID-BPF, and talking to the device is
168 allowed.                                          150 allowed.
169                                                   151 
170 Last, ``hid_rdesc_fixup`` is different from th !! 152 Last, ``hid_bpf_rdesc_fixup`` is different from the others as there can be only one
171 BPF program of this type. This is called on ``    153 BPF program of this type. This is called on ``probe`` from the driver and allows to
172 change the report descriptor from the BPF prog !! 154 change the report descriptor from the BPF program. Once a ``hid_bpf_rdesc_fixup``
173 program has been loaded, it is not possible to    155 program has been loaded, it is not possible to overwrite it unless the program which
174 inserted it allows us by pinning the program a    156 inserted it allows us by pinning the program and closing all of its fds pointing to it.
175                                                   157 
176 Note that ``hid_rdesc_fixup`` can be declared  << 
177                                                << 
178                                                << 
179 Developer API:                                    158 Developer API:
180 ==============                                    159 ==============
181                                                   160 
182 Available ``struct_ops`` for HID-BPF:          << 
183 -------------------------------------          << 
184                                                << 
185 .. kernel-doc:: include/linux/hid_bpf.h        << 
186    :identifiers: hid_bpf_ops                   << 
187                                                << 
188                                                << 
189 User API data structures available in programs    161 User API data structures available in programs:
190 ----------------------------------------------    162 -----------------------------------------------
191                                                   163 
192 .. kernel-doc:: include/linux/hid_bpf.h           164 .. kernel-doc:: include/linux/hid_bpf.h
193    :identifiers: hid_bpf_ctx                   << 
194                                                   165 
195 Available API that can be used in all HID-BPF  !! 166 Available tracing functions to attach a HID-BPF program:
196 ---------------------------------------------- !! 167 --------------------------------------------------------
                                                   >> 168 
                                                   >> 169 .. kernel-doc:: drivers/hid/bpf/hid_bpf_dispatch.c
                                                   >> 170    :functions: hid_bpf_device_event hid_bpf_rdesc_fixup
                                                   >> 171 
                                                   >> 172 Available API that can be used in all HID-BPF programs:
                                                   >> 173 -------------------------------------------------------
197                                                   174 
198 .. kernel-doc:: drivers/hid/bpf/hid_bpf_dispat    175 .. kernel-doc:: drivers/hid/bpf/hid_bpf_dispatch.c
199    :identifiers: hid_bpf_get_data              !! 176    :functions: hid_bpf_get_data
200                                                   177 
201 Available API that can be used in syscall HID- !! 178 Available API that can be used in syscall HID-BPF programs:
202 ---------------------------------------------- !! 179 -----------------------------------------------------------
203                                                   180 
204 .. kernel-doc:: drivers/hid/bpf/hid_bpf_dispat    181 .. kernel-doc:: drivers/hid/bpf/hid_bpf_dispatch.c
205    :identifiers: hid_bpf_hw_request hid_bpf_hw !! 182    :functions: hid_bpf_attach_prog hid_bpf_hw_request hid_bpf_allocate_context hid_bpf_release_context
206                                                   183 
207 General overview of a HID-BPF program             184 General overview of a HID-BPF program
208 =====================================             185 =====================================
209                                                   186 
210 Accessing the data attached to the context        187 Accessing the data attached to the context
211 ------------------------------------------        188 ------------------------------------------
212                                                   189 
213 The ``struct hid_bpf_ctx`` doesn't export the     190 The ``struct hid_bpf_ctx`` doesn't export the ``data`` fields directly and to access
214 it, a bpf program needs to first call :c:func:    191 it, a bpf program needs to first call :c:func:`hid_bpf_get_data`.
215                                                   192 
216 ``offset`` can be any integer, but ``size`` ne    193 ``offset`` can be any integer, but ``size`` needs to be constant, known at compile
217 time.                                             194 time.
218                                                   195 
219 This allows the following:                        196 This allows the following:
220                                                   197 
221 1. for a given device, if we know that the rep    198 1. for a given device, if we know that the report length will always be of a certain value,
222    we can request the ``data`` pointer to poin    199    we can request the ``data`` pointer to point at the full report length.
223                                                   200 
224    The kernel will ensure we are using a corre    201    The kernel will ensure we are using a correct size and offset and eBPF will ensure
225    the code will not attempt to read or write     202    the code will not attempt to read or write outside of the boundaries::
226                                                   203 
227      __u8 *data = hid_bpf_get_data(ctx, 0 /* o    204      __u8 *data = hid_bpf_get_data(ctx, 0 /* offset */, 256 /* size */);
228                                                   205 
229      if (!data)                                   206      if (!data)
230          return 0; /* ensure data is correct,     207          return 0; /* ensure data is correct, now the verifier knows we
231                     * have 256 bytes available    208                     * have 256 bytes available */
232                                                   209 
233      bpf_printk("hello world: %02x %02x %02x",    210      bpf_printk("hello world: %02x %02x %02x", data[0], data[128], data[255]);
234                                                   211 
235 2. if the report length is variable, but we kn    212 2. if the report length is variable, but we know the value of ``X`` is always a 16-bit
236    integer, we can then have a pointer to that    213    integer, we can then have a pointer to that value only::
237                                                   214 
238       __u16 *x = hid_bpf_get_data(ctx, offset,    215       __u16 *x = hid_bpf_get_data(ctx, offset, sizeof(*x));
239                                                   216 
240       if (!x)                                     217       if (!x)
241           return 0; /* something went wrong */    218           return 0; /* something went wrong */
242                                                   219 
243       *x += 1; /* increment X by one */           220       *x += 1; /* increment X by one */
244                                                   221 
245 Effect of a HID-BPF program                       222 Effect of a HID-BPF program
246 ---------------------------                       223 ---------------------------
247                                                   224 
248 For all HID-BPF attachment types except for :c !! 225 For all HID-BPF attachment types except for :c:func:`hid_bpf_rdesc_fixup`, several eBPF
249 programs can be attached to the same device. I !! 226 programs can be attached to the same device.
250 :c:func:`hid_rdesc_fixup` while another is alr !! 227 
251 kernel will return `-EINVAL` when attaching th !! 228 Unless ``HID_BPF_FLAG_INSERT_HEAD`` is added to the flags while attaching the
252                                                !! 229 program, the new program is appended at the end of the list.
253 Unless ``BPF_F_BEFORE`` is added to the flags  !! 230 ``HID_BPF_FLAG_INSERT_HEAD`` will insert the new program at the beginning of the
254 program is appended at the end of the list.    !! 231 list which is useful for e.g. tracing where we need to get the unprocessed events
255 ``BPF_F_BEFORE`` will insert the new program a !! 232 from the device.
256 useful for e.g. tracing where we need to get t << 
257                                                   233 
258 Note that if there are multiple programs using !! 234 Note that if there are multiple programs using the ``HID_BPF_FLAG_INSERT_HEAD`` flag,
259 only the most recently loaded one is actually     235 only the most recently loaded one is actually the first in the list.
260                                                   236 
261 ``SEC("struct_ops/hid_device_event")``         !! 237 ``SEC("fmod_ret/hid_bpf_device_event")``
262 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~         !! 238 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
263                                                   239 
264 Whenever a matching event is raised, the eBPF     240 Whenever a matching event is raised, the eBPF programs are called one after the other
265 and are working on the same data buffer.          241 and are working on the same data buffer.
266                                                   242 
267 If a program changes the data associated with     243 If a program changes the data associated with the context, the next one will see
268 the modified data but it will have *no* idea o    244 the modified data but it will have *no* idea of what the original data was.
269                                                   245 
270 Once all the programs are run and return ``0``    246 Once all the programs are run and return ``0`` or a positive value, the rest of the
271 HID stack will work on the modified data, with    247 HID stack will work on the modified data, with the ``size`` field of the last hid_bpf_ctx
272 being the new size of the input stream of data    248 being the new size of the input stream of data.
273                                                   249 
274 A BPF program returning a negative error disca    250 A BPF program returning a negative error discards the event, i.e. this event will not be
275 processed by the HID stack. Clients (hidraw, i    251 processed by the HID stack. Clients (hidraw, input, LEDs) will **not** see this event.
276                                                   252 
277 ``SEC("syscall")``                                253 ``SEC("syscall")``
278 ~~~~~~~~~~~~~~~~~~                                254 ~~~~~~~~~~~~~~~~~~
279                                                   255 
280 ``syscall`` are not attached to a given device    256 ``syscall`` are not attached to a given device. To tell which device we are working
281 with, userspace needs to refer to the device b    257 with, userspace needs to refer to the device by its unique system id (the last 4 numbers
282 in the sysfs path: ``/sys/bus/hid/devices/xxxx    258 in the sysfs path: ``/sys/bus/hid/devices/xxxx:yyyy:zzzz:0000``).
283                                                   259 
284 To retrieve a context associated with the devi    260 To retrieve a context associated with the device, the program must call
285 hid_bpf_allocate_context() and must release it !! 261 :c:func:`hid_bpf_allocate_context` and must release it with :c:func:`hid_bpf_release_context`
286 before returning.                                 262 before returning.
287 Once the context is retrieved, one can also re    263 Once the context is retrieved, one can also request a pointer to kernel memory with
288 hid_bpf_get_data(). This memory is big enough  !! 264 :c:func:`hid_bpf_get_data`. This memory is big enough to support all input/output/feature
289 reports of the given device.                      265 reports of the given device.
290                                                   266 
291 ``SEC("struct_ops/hid_rdesc_fixup")``          !! 267 ``SEC("fmod_ret/hid_bpf_rdesc_fixup")``
292 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~          !! 268 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
293                                                   269 
294 The ``hid_rdesc_fixup`` program works in a sim !! 270 The ``hid_bpf_rdesc_fixup`` program works in a similar manner to
295 of ``struct hid_driver``.                      !! 271 ``.report_fixup`` of ``struct hid_driver``.
296                                                   272 
297 When the device is probed, the kernel sets the    273 When the device is probed, the kernel sets the data buffer of the context with the
298 content of the report descriptor. The memory a    274 content of the report descriptor. The memory associated with that buffer is
299 ``HID_MAX_DESCRIPTOR_SIZE`` (currently 4kB).      275 ``HID_MAX_DESCRIPTOR_SIZE`` (currently 4kB).
300                                                   276 
301 The eBPF program can modify the data buffer at    277 The eBPF program can modify the data buffer at-will and the kernel uses the
302 modified content and size as the report descri    278 modified content and size as the report descriptor.
303                                                   279 
304 Whenever a struct_ops containing a ``SEC("stru !! 280 Whenever a ``SEC("fmod_ret/hid_bpf_rdesc_fixup")`` program is attached (if no
305 is attached (if no program was attached before !! 281 program was attached before), the kernel immediately disconnects the HID device
306 the HID device and does a reprobe.             !! 282 and does a reprobe.
307                                                   283 
308 In the same way, when this struct_ops is detac !! 284 In the same way, when the ``SEC("fmod_ret/hid_bpf_rdesc_fixup")`` program is
309 on the device.                                 !! 285 detached, the kernel issues a disconnect on the device.
310                                                   286 
311 There is no ``detach`` facility in HID-BPF. De    287 There is no ``detach`` facility in HID-BPF. Detaching a program happens when
312 all the user space file descriptors pointing a !! 288 all the user space file descriptors pointing at a program are closed.
313 Thus, if we need to replace a report descripto    289 Thus, if we need to replace a report descriptor fixup, some cooperation is
314 required from the owner of the original report    290 required from the owner of the original report descriptor fixup.
315 The previous owner will likely pin the struct_ !! 291 The previous owner will likely pin the program in the bpffs, and we can then
316 replace it through normal bpf operations.         292 replace it through normal bpf operations.
317                                                   293 
318 Attaching a bpf program to a device               294 Attaching a bpf program to a device
319 ===================================               295 ===================================
320                                                   296 
321 We now use standard struct_ops attachment thro !! 297 ``libbpf`` does not export any helper to attach a HID-BPF program.
322 But given that we need to attach a struct_ops  !! 298 Users need to use a dedicated ``syscall`` program which will call
323 must set ``hid_id`` in the struct_ops map befo !! 299 ``hid_bpf_attach_prog(hid_id, program_fd, flags)``.
324                                                   300 
325 ``hid_id`` is the unique system ID of the HID     301 ``hid_id`` is the unique system ID of the HID device (the last 4 numbers in the
326 sysfs path: ``/sys/bus/hid/devices/xxxx:yyyy:z    302 sysfs path: ``/sys/bus/hid/devices/xxxx:yyyy:zzzz:0000``)
327                                                   303 
328 One can also set ``flags``, which is of type ` !! 304 ``progam_fd`` is the opened file descriptor of the program to attach.
                                                   >> 305 
                                                   >> 306 ``flags`` is of type ``enum hid_bpf_attach_flags``.
329                                                   307 
330 We can not rely on hidraw to bind a BPF progra    308 We can not rely on hidraw to bind a BPF program to a HID device. hidraw is an
331 artefact of the processing of the HID device,     309 artefact of the processing of the HID device, and is not stable. Some drivers
332 even disable it, so that removes the tracing c    310 even disable it, so that removes the tracing capabilities on those devices
333 (where it is interesting to get the non-hidraw    311 (where it is interesting to get the non-hidraw traces).
334                                                   312 
335 On the other hand, the ``hid_id`` is stable fo    313 On the other hand, the ``hid_id`` is stable for the entire life of the HID device,
336 even if we change its report descriptor.          314 even if we change its report descriptor.
337                                                   315 
338 Given that hidraw is not stable when the devic    316 Given that hidraw is not stable when the device disconnects/reconnects, we recommend
339 accessing the current report descriptor of the    317 accessing the current report descriptor of the device through the sysfs.
340 This is available at ``/sys/bus/hid/devices/BU    318 This is available at ``/sys/bus/hid/devices/BUS:VID:PID.000N/report_descriptor`` as a
341 binary stream.                                    319 binary stream.
342                                                   320 
343 Parsing the report descriptor is the responsib    321 Parsing the report descriptor is the responsibility of the BPF programmer or the userspace
344 component that loads the eBPF program.            322 component that loads the eBPF program.
345                                                   323 
346 An (almost) complete example of a BPF enhanced    324 An (almost) complete example of a BPF enhanced HID device
347 ==============================================    325 =========================================================
348                                                   326 
349 *Foreword: for most parts, this could be imple    327 *Foreword: for most parts, this could be implemented as a kernel driver*
350                                                   328 
351 Let's imagine we have a new tablet device that    329 Let's imagine we have a new tablet device that has some haptic capabilities
352 to simulate the surface the user is scratching    330 to simulate the surface the user is scratching on. This device would also have
353 a specific 3 positions switch to toggle betwee    331 a specific 3 positions switch to toggle between *pencil on paper*, *cray on a wall*
354 and *brush on a painting canvas*. To make thin    332 and *brush on a painting canvas*. To make things even better, we can control the
355 physical position of the switch through a feat    333 physical position of the switch through a feature report.
356                                                   334 
357 And of course, the switch is relying on some u    335 And of course, the switch is relying on some userspace component to control the
358 haptic feature of the device itself.              336 haptic feature of the device itself.
359                                                   337 
360 Filtering events                                  338 Filtering events
361 ----------------                                  339 ----------------
362                                                   340 
363 The first step consists in filtering events fr    341 The first step consists in filtering events from the device. Given that the switch
364 position is actually reported in the flow of t    342 position is actually reported in the flow of the pen events, using hidraw to implement
365 that filtering would mean that we wake up user    343 that filtering would mean that we wake up userspace for every single event.
366                                                   344 
367 This is OK for libinput, but having an externa    345 This is OK for libinput, but having an external library that is just interested in
368 one byte in the report is less than ideal.        346 one byte in the report is less than ideal.
369                                                   347 
370 For that, we can create a basic skeleton for o    348 For that, we can create a basic skeleton for our BPF program::
371                                                   349 
372   #include "vmlinux.h"                            350   #include "vmlinux.h"
373   #include <bpf/bpf_helpers.h>                    351   #include <bpf/bpf_helpers.h>
374   #include <bpf/bpf_tracing.h>                    352   #include <bpf/bpf_tracing.h>
375                                                   353 
376   /* HID programs need to be GPL */               354   /* HID programs need to be GPL */
377   char _license[] SEC("license") = "GPL";         355   char _license[] SEC("license") = "GPL";
378                                                   356 
379   /* HID-BPF kfunc API definitions */             357   /* HID-BPF kfunc API definitions */
380   extern __u8 *hid_bpf_get_data(struct hid_bpf    358   extern __u8 *hid_bpf_get_data(struct hid_bpf_ctx *ctx,
381                               unsigned int off    359                               unsigned int offset,
382                               const size_t __s    360                               const size_t __sz) __ksym;
                                                   >> 361   extern int hid_bpf_attach_prog(unsigned int hid_id, int prog_fd, u32 flags) __ksym;
383                                                   362 
384   struct {                                        363   struct {
385         __uint(type, BPF_MAP_TYPE_RINGBUF);       364         __uint(type, BPF_MAP_TYPE_RINGBUF);
386         __uint(max_entries, 4096 * 64);           365         __uint(max_entries, 4096 * 64);
387   } ringbuf SEC(".maps");                         366   } ringbuf SEC(".maps");
388                                                   367 
                                                   >> 368   struct attach_prog_args {
                                                   >> 369         int prog_fd;
                                                   >> 370         unsigned int hid;
                                                   >> 371         unsigned int flags;
                                                   >> 372         int retval;
                                                   >> 373   };
                                                   >> 374 
                                                   >> 375   SEC("syscall")
                                                   >> 376   int attach_prog(struct attach_prog_args *ctx)
                                                   >> 377   {
                                                   >> 378         ctx->retval = hid_bpf_attach_prog(ctx->hid,
                                                   >> 379                                           ctx->prog_fd,
                                                   >> 380                                           ctx->flags);
                                                   >> 381         return 0;
                                                   >> 382   }
                                                   >> 383 
389   __u8 current_value = 0;                         384   __u8 current_value = 0;
390                                                   385 
391   SEC("struct_ops/hid_device_event")           !! 386   SEC("?fmod_ret/hid_bpf_device_event")
392   int BPF_PROG(filter_switch, struct hid_bpf_c    387   int BPF_PROG(filter_switch, struct hid_bpf_ctx *hid_ctx)
393   {                                               388   {
394         __u8 *data = hid_bpf_get_data(hid_ctx,    389         __u8 *data = hid_bpf_get_data(hid_ctx, 0 /* offset */, 192 /* size */);
395         __u8 *buf;                                390         __u8 *buf;
396                                                   391 
397         if (!data)                                392         if (!data)
398                 return 0; /* EPERM check */       393                 return 0; /* EPERM check */
399                                                   394 
400         if (current_value != data[152]) {         395         if (current_value != data[152]) {
401                 buf = bpf_ringbuf_reserve(&rin    396                 buf = bpf_ringbuf_reserve(&ringbuf, 1, 0);
402                 if (!buf)                         397                 if (!buf)
403                         return 0;                 398                         return 0;
404                                                   399 
405                 *buf = data[152];                 400                 *buf = data[152];
406                                                   401 
407                 bpf_ringbuf_commit(buf, 0);       402                 bpf_ringbuf_commit(buf, 0);
408                                                   403 
409                 current_value = data[152];        404                 current_value = data[152];
410         }                                         405         }
411                                                   406 
412         return 0;                                 407         return 0;
413   }                                               408   }
414                                                   409 
415   SEC(".struct_ops.link")                      !! 410 To attach ``filter_switch``, userspace needs to call the ``attach_prog`` syscall
416   struct hid_bpf_ops haptic_tablet = {         !! 411 program first::
417         .hid_device_event = (void *)filter_swi << 
418   };                                           << 
419                                                << 
420                                                << 
421 To attach ``haptic_tablet``, userspace needs t << 
422                                                   412 
423   static int attach_filter(struct hid *hid_ske    413   static int attach_filter(struct hid *hid_skel, int hid_id)
424   {                                               414   {
425         int err, link_fd;                      !! 415         int err, prog_fd;
426                                                !! 416         int ret = -1;
427         hid_skel->struct_ops.haptic_tablet->hi !! 417         struct attach_prog_args args = {
428         err = hid__load(skel);                 !! 418                 .hid = hid_id,
429         if (err)                               !! 419         };
430                 return err;                    !! 420         DECLARE_LIBBPF_OPTS(bpf_test_run_opts, tattrs,
431                                                !! 421                 .ctx_in = &args,
432         link_fd = bpf_map__attach_struct_ops(h !! 422                 .ctx_size_in = sizeof(args),
433         if (!link_fd) {                        !! 423         );
434                 fprintf(stderr, "can not attac !! 424 
435                 return -1;                     !! 425         args.prog_fd = bpf_program__fd(hid_skel->progs.filter_switch);
436         }                                      !! 426 
                                                   >> 427         prog_fd = bpf_program__fd(hid_skel->progs.attach_prog);
                                                   >> 428 
                                                   >> 429         err = bpf_prog_test_run_opts(prog_fd, &tattrs);
                                                   >> 430         if (err)
                                                   >> 431                 return err;
437                                                   432 
438         return link_fd; /* the fd of the creat !! 433         return args.retval; /* the fd of the created bpf_link */
439   }                                               434   }
440                                                   435 
441 Our userspace program can now listen to notifi    436 Our userspace program can now listen to notifications on the ring buffer, and
442 is awaken only when the value changes.            437 is awaken only when the value changes.
443                                                   438 
444 When the userspace program doesn't need to lis    439 When the userspace program doesn't need to listen to events anymore, it can just
445 close the returned bpf link from :c:func:`atta !! 440 close the returned fd from :c:func:`attach_filter`, which will tell the kernel to
446 detach the program from the HID device.           441 detach the program from the HID device.
447                                                   442 
448 Of course, in other use cases, the userspace p    443 Of course, in other use cases, the userspace program can also pin the fd to the
449 BPF filesystem through a call to :c:func:`bpf_    444 BPF filesystem through a call to :c:func:`bpf_obj_pin`, as with any bpf_link.
450                                                   445 
451 Controlling the device                            446 Controlling the device
452 ----------------------                            447 ----------------------
453                                                   448 
454 To be able to change the haptic feedback from     449 To be able to change the haptic feedback from the tablet, the userspace program
455 needs to emit a feature report on the device i    450 needs to emit a feature report on the device itself.
456                                                   451 
457 Instead of using hidraw for that, we can creat    452 Instead of using hidraw for that, we can create a ``SEC("syscall")`` program
458 that talks to the device::                        453 that talks to the device::
459                                                   454 
460   /* some more HID-BPF kfunc API definitions *    455   /* some more HID-BPF kfunc API definitions */
461   extern struct hid_bpf_ctx *hid_bpf_allocate_    456   extern struct hid_bpf_ctx *hid_bpf_allocate_context(unsigned int hid_id) __ksym;
462   extern void hid_bpf_release_context(struct h    457   extern void hid_bpf_release_context(struct hid_bpf_ctx *ctx) __ksym;
463   extern int hid_bpf_hw_request(struct hid_bpf    458   extern int hid_bpf_hw_request(struct hid_bpf_ctx *ctx,
464                               __u8* data,         459                               __u8* data,
465                               size_t len,         460                               size_t len,
466                               enum hid_report_    461                               enum hid_report_type type,
467                               enum hid_class_r    462                               enum hid_class_request reqtype) __ksym;
468                                                   463 
469                                                   464 
470   struct hid_send_haptics_args {                  465   struct hid_send_haptics_args {
471         /* data needs to come at offset 0 so w    466         /* data needs to come at offset 0 so we can do a memcpy into it */
472         __u8 data[10];                            467         __u8 data[10];
473         unsigned int hid;                         468         unsigned int hid;
474   };                                              469   };
475                                                   470 
476   SEC("syscall")                                  471   SEC("syscall")
477   int send_haptic(struct hid_send_haptics_args    472   int send_haptic(struct hid_send_haptics_args *args)
478   {                                               473   {
479         struct hid_bpf_ctx *ctx;                  474         struct hid_bpf_ctx *ctx;
480         int ret = 0;                              475         int ret = 0;
481                                                   476 
482         ctx = hid_bpf_allocate_context(args->h    477         ctx = hid_bpf_allocate_context(args->hid);
483         if (!ctx)                                 478         if (!ctx)
484                 return 0; /* EPERM check */       479                 return 0; /* EPERM check */
485                                                   480 
486         ret = hid_bpf_hw_request(ctx,             481         ret = hid_bpf_hw_request(ctx,
487                                  args->data,      482                                  args->data,
488                                  10,              483                                  10,
489                                  HID_FEATURE_R    484                                  HID_FEATURE_REPORT,
490                                  HID_REQ_SET_R    485                                  HID_REQ_SET_REPORT);
491                                                   486 
492         hid_bpf_release_context(ctx);             487         hid_bpf_release_context(ctx);
493                                                   488 
494         return ret;                               489         return ret;
495   }                                               490   }
496                                                   491 
497 And then userspace needs to call that program     492 And then userspace needs to call that program directly::
498                                                   493 
499   static int set_haptic(struct hid *hid_skel,     494   static int set_haptic(struct hid *hid_skel, int hid_id, __u8 haptic_value)
500   {                                               495   {
501         int err, prog_fd;                         496         int err, prog_fd;
502         int ret = -1;                             497         int ret = -1;
503         struct hid_send_haptics_args args = {     498         struct hid_send_haptics_args args = {
504                 .hid = hid_id,                    499                 .hid = hid_id,
505         };                                        500         };
506         DECLARE_LIBBPF_OPTS(bpf_test_run_opts,    501         DECLARE_LIBBPF_OPTS(bpf_test_run_opts, tattrs,
507                 .ctx_in = &args,                  502                 .ctx_in = &args,
508                 .ctx_size_in = sizeof(args),      503                 .ctx_size_in = sizeof(args),
509         );                                        504         );
510                                                   505 
511         args.data[0] = 0x02; /* report ID of t    506         args.data[0] = 0x02; /* report ID of the feature on our device */
512         args.data[1] = haptic_value;              507         args.data[1] = haptic_value;
513                                                   508 
514         prog_fd = bpf_program__fd(hid_skel->pr    509         prog_fd = bpf_program__fd(hid_skel->progs.set_haptic);
515                                                   510 
516         err = bpf_prog_test_run_opts(prog_fd,     511         err = bpf_prog_test_run_opts(prog_fd, &tattrs);
517         return err;                               512         return err;
518   }                                               513   }
519                                                   514 
520 Now our userspace program is aware of the hapt    515 Now our userspace program is aware of the haptic state and can control it. The
521 program could make this state further availabl    516 program could make this state further available to other userspace programs
522 (e.g. via a DBus API).                            517 (e.g. via a DBus API).
523                                                   518 
524 The interesting bit here is that we did not cr    519 The interesting bit here is that we did not created a new kernel API for this.
525 Which means that if there is a bug in our impl    520 Which means that if there is a bug in our implementation, we can change the
526 interface with the kernel at-will, because the    521 interface with the kernel at-will, because the userspace application is
527 responsible for its own usage.                    522 responsible for its own usage.
                                                      

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php