@@ -129,57 +129,80 @@ When a BPF program needs to emit input events, it needs to talk with the HID
129
129
protocol, and rely on the HID kernel processing to translate the HID data into
130
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 kernel tree as source in the
136
+ ``drivers/hid/bpf/progs `` directory. This allows to add selftests to them in
137
+ ``tools/testing/selftests/hid ``.
138
+
139
+ However, the compilation of these objects is not part of a regular kernel compilation
140
+ given that they need an external tool to be loaded. This tool is currently
141
+ `udev-hid-bpf <https://libevdev.pages.freedesktop.org/udev-hid-bpf/index.html >`_.
142
+
143
+ For convenience, that external repository duplicates the files from here in
144
+ ``drivers/hid/bpf/progs `` into its own ``src/bpf/stable `` directory. This allows
145
+ distributions to not have to pull the entire kernel source tree to ship and package
146
+ those HID-BPF fixes. ``udev-hid-bpf `` also has capabilities of handling multiple
147
+ objects files depending on the kernel the user is running.
148
+
132
149
Available types of programs
133
150
===========================
134
151
135
- HID-BPF is built "on top" of BPF, meaning that we use tracing method to
152
+ HID-BPF is built "on top" of BPF, meaning that we use bpf struct_ops method to
136
153
declare our programs.
137
154
138
155
HID-BPF has the following attachment types available:
139
156
140
- 1. event processing/filtering with ``SEC("fmod_ret/hid_bpf_device_event ") `` in libbpf
157
+ 1. event processing/filtering with ``SEC("struct_ops/hid_device_event ") `` in libbpf
141
158
2. actions coming from userspace with ``SEC("syscall") `` in libbpf
142
- 3. change of the report descriptor with ``SEC("fmod_ret/hid_bpf_rdesc_fixup") `` in libbpf
159
+ 3. change of the report descriptor with ``SEC("struct_ops/hid_rdesc_fixup") `` or
160
+ ``SEC("struct_ops.s/hid_rdesc_fixup") `` in libbpf
143
161
144
- A ``hid_bpf_device_event `` is calling a BPF program when an event is received from
162
+ A ``hid_device_event `` is calling a BPF program when an event is received from
145
163
the device. Thus we are in IRQ context and can act on the data or notify userspace.
146
164
And given that we are in IRQ context, we can not talk back to the device.
147
165
148
166
A ``syscall `` means that userspace called the syscall ``BPF_PROG_RUN `` facility.
149
167
This time, we can do any operations allowed by HID-BPF, and talking to the device is
150
168
allowed.
151
169
152
- Last, ``hid_bpf_rdesc_fixup `` is different from the others as there can be only one
170
+ Last, ``hid_rdesc_fixup `` is different from the others as there can be only one
153
171
BPF program of this type. This is called on ``probe `` from the driver and allows to
154
- change the report descriptor from the BPF program. Once a ``hid_bpf_rdesc_fixup ``
172
+ change the report descriptor from the BPF program. Once a ``hid_rdesc_fixup ``
155
173
program has been loaded, it is not possible to overwrite it unless the program which
156
174
inserted it allows us by pinning the program and closing all of its fds pointing to it.
157
175
176
+ Note that ``hid_rdesc_fixup `` can be declared as sleepable (``SEC("struct_ops.s/hid_rdesc_fixup") ``).
177
+
178
+
158
179
Developer API:
159
180
==============
160
181
161
- User API data structures available in programs :
162
- -----------------------------------------------
182
+ Available `` struct_ops `` for HID-BPF :
183
+ -------------------------------------
163
184
164
185
.. kernel-doc :: include/linux/hid_bpf.h
186
+ :identifiers: hid_bpf_ops
165
187
166
- Available tracing functions to attach a HID-BPF program:
167
- --------------------------------------------------------
168
188
169
- .. kernel-doc :: drivers/hid/bpf/hid_bpf_dispatch.c
170
- :functions: hid_bpf_device_event hid_bpf_rdesc_fixup
189
+ User API data structures available in programs:
190
+ -----------------------------------------------
171
191
172
- Available API that can be used in all HID-BPF programs:
173
- -------------------------------------------------------
192
+ .. kernel-doc :: include/linux/hid_bpf.h
193
+ :identifiers: hid_bpf_ctx
194
+
195
+ Available API that can be used in all HID-BPF struct_ops programs:
196
+ ------------------------------------------------------------------
174
197
175
198
.. kernel-doc :: drivers/hid/bpf/hid_bpf_dispatch.c
176
- :functions : hid_bpf_get_data
199
+ :identifiers : hid_bpf_get_data
177
200
178
- Available API that can be used in syscall HID-BPF programs:
179
- -----------------------------------------------------------
201
+ Available API that can be used in syscall HID-BPF programs or in sleepable HID-BPF struct_ops programs :
202
+ -------------------------------------------------------------------------------------------------------
180
203
181
204
.. kernel-doc :: drivers/hid/bpf/hid_bpf_dispatch.c
182
- :functions: hid_bpf_attach_prog hid_bpf_hw_request hid_bpf_hw_output_report hid_bpf_input_report hid_bpf_allocate_context hid_bpf_release_context
205
+ :identifiers: hid_bpf_hw_request hid_bpf_hw_output_report hid_bpf_input_report hid_bpf_try_input_report hid_bpf_allocate_context hid_bpf_release_context
183
206
184
207
General overview of a HID-BPF program
185
208
=====================================
@@ -222,20 +245,21 @@ This allows the following:
222
245
Effect of a HID-BPF program
223
246
---------------------------
224
247
225
- For all HID-BPF attachment types except for :c:func: `hid_bpf_rdesc_fixup `, several eBPF
226
- programs can be attached to the same device.
248
+ For all HID-BPF attachment types except for :c:func: `hid_rdesc_fixup `, several eBPF
249
+ programs can be attached to the same device. If a HID-BPF struct_ops has a
250
+ :c:func: `hid_rdesc_fixup ` while another is already attached to the device, the
251
+ kernel will return `-EINVAL ` when attaching the struct_ops.
227
252
228
- Unless ``HID_BPF_FLAG_INSERT_HEAD `` is added to the flags while attaching the
229
- program, the new program is appended at the end of the list.
230
- ``HID_BPF_FLAG_INSERT_HEAD `` will insert the new program at the beginning of the
231
- list which is useful for e.g. tracing where we need to get the unprocessed events
232
- from the device.
253
+ Unless ``BPF_F_BEFORE `` is added to the flags while attaching the program, the new
254
+ program is appended at the end of the list.
255
+ ``BPF_F_BEFORE `` will insert the new program at the beginning of the list which is
256
+ useful for e.g. tracing where we need to get the unprocessed events from the device.
233
257
234
- Note that if there are multiple programs using the ``HID_BPF_FLAG_INSERT_HEAD `` flag,
258
+ Note that if there are multiple programs using the ``BPF_F_BEFORE `` flag,
235
259
only the most recently loaded one is actually the first in the list.
236
260
237
- ``SEC("fmod_ret/hid_bpf_device_event ") ``
238
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
261
+ ``SEC("struct_ops/hid_device_event ") ``
262
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
239
263
240
264
Whenever a matching event is raised, the eBPF programs are called one after the other
241
265
and are working on the same data buffer.
@@ -258,17 +282,17 @@ with, userspace needs to refer to the device by its unique system id (the last 4
258
282
in the sysfs path: ``/sys/bus/hid/devices/xxxx:yyyy:zzzz:0000 ``).
259
283
260
284
To retrieve a context associated with the device, the program must call
261
- :c:func: ` hid_bpf_allocate_context ` and must release it with :c:func: ` hid_bpf_release_context `
285
+ hid_bpf_allocate_context() and must release it with hid_bpf_release_context()
262
286
before returning.
263
287
Once the context is retrieved, one can also request a pointer to kernel memory with
264
- :c:func: ` hid_bpf_get_data ` . This memory is big enough to support all input/output/feature
288
+ hid_bpf_get_data() . This memory is big enough to support all input/output/feature
265
289
reports of the given device.
266
290
267
- ``SEC("fmod_ret/hid_bpf_rdesc_fixup ") ``
268
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
291
+ ``SEC("struct_ops/hid_rdesc_fixup ") ``
292
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
269
293
270
- The ``hid_bpf_rdesc_fixup `` program works in a similar manner to
271
- `` .report_fixup `` of ``struct hid_driver ``.
294
+ The ``hid_rdesc_fixup `` program works in a similar manner to `` .report_fixup ``
295
+ of ``struct hid_driver ``.
272
296
273
297
When the device is probed, the kernel sets the data buffer of the context with the
274
298
content of the report descriptor. The memory associated with that buffer is
@@ -277,33 +301,31 @@ content of the report descriptor. The memory associated with that buffer is
277
301
The eBPF program can modify the data buffer at-will and the kernel uses the
278
302
modified content and size as the report descriptor.
279
303
280
- Whenever a ``SEC("fmod_ret/hid_bpf_rdesc_fixup ") `` program is attached (if no
281
- program was attached before), the kernel immediately disconnects the HID device
282
- and does a reprobe.
304
+ Whenever a struct_ops containing a ``SEC("struct_ops/hid_rdesc_fixup ") `` program
305
+ is attached (if no program was attached before), the kernel immediately disconnects
306
+ the HID device and does a reprobe.
283
307
284
- In the same way, when the `` SEC("fmod_ret/hid_bpf_rdesc_fixup") `` program is
285
- detached, the kernel issues a disconnect on the device.
308
+ In the same way, when this struct_ops is detached, the kernel issues a disconnect
309
+ on the device.
286
310
287
311
There is no ``detach `` facility in HID-BPF. Detaching a program happens when
288
- all the user space file descriptors pointing at a program are closed.
312
+ all the user space file descriptors pointing at a HID-BPF struct_ops link are closed.
289
313
Thus, if we need to replace a report descriptor fixup, some cooperation is
290
314
required from the owner of the original report descriptor fixup.
291
- The previous owner will likely pin the program in the bpffs, and we can then
315
+ The previous owner will likely pin the struct_ops link in the bpffs, and we can then
292
316
replace it through normal bpf operations.
293
317
294
318
Attaching a bpf program to a device
295
319
===================================
296
320
297
- `` libbpf `` does not export any helper to attach a HID-BPF program .
298
- Users need to use a dedicated `` syscall `` program which will call
299
- `` hid_bpf_attach_prog( hid_id, program_fd, flags) `` .
321
+ We now use standard struct_ops attachment through `` bpf_map__attach_struct_ops() `` .
322
+ But given that we need to attach a struct_ops to a dedicated HID device, the caller
323
+ must set `` hid_id `` in the struct_ops map before loading the program in the kernel .
300
324
301
325
``hid_id `` is the unique system ID of the HID device (the last 4 numbers in the
302
326
sysfs path: ``/sys/bus/hid/devices/xxxx:yyyy:zzzz:0000 ``)
303
327
304
- ``progam_fd `` is the opened file descriptor of the program to attach.
305
-
306
- ``flags `` is of type ``enum hid_bpf_attach_flags ``.
328
+ One can also set ``flags ``, which is of type ``enum hid_bpf_attach_flags ``.
307
329
308
330
We can not rely on hidraw to bind a BPF program to a HID device. hidraw is an
309
331
artefact of the processing of the HID device, and is not stable. Some drivers
@@ -358,32 +380,15 @@ For that, we can create a basic skeleton for our BPF program::
358
380
extern __u8 *hid_bpf_get_data(struct hid_bpf_ctx *ctx,
359
381
unsigned int offset,
360
382
const size_t __sz) __ksym;
361
- extern int hid_bpf_attach_prog(unsigned int hid_id, int prog_fd, u32 flags) __ksym;
362
383
363
384
struct {
364
385
__uint(type, BPF_MAP_TYPE_RINGBUF);
365
386
__uint(max_entries, 4096 * 64);
366
387
} ringbuf SEC(".maps");
367
388
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
-
384
389
__u8 current_value = 0;
385
390
386
- SEC("?fmod_ret/hid_bpf_device_event ")
391
+ SEC("struct_ops/hid_device_event ")
387
392
int BPF_PROG(filter_switch, struct hid_bpf_ctx *hid_ctx)
388
393
{
389
394
__u8 *data = hid_bpf_get_data(hid_ctx, 0 /* offset */, 192 /* size */);
@@ -407,37 +412,37 @@ For that, we can create a basic skeleton for our BPF program::
407
412
return 0;
408
413
}
409
414
410
- To attach ``filter_switch ``, userspace needs to call the ``attach_prog `` syscall
411
- program first::
415
+ SEC(".struct_ops.link")
416
+ struct hid_bpf_ops haptic_tablet = {
417
+ .hid_device_event = (void *)filter_switch,
418
+ };
419
+
420
+
421
+ To attach ``haptic_tablet ``, userspace needs to set ``hid_id `` first::
412
422
413
423
static int attach_filter(struct hid *hid_skel, int hid_id)
414
424
{
415
- int err, prog_fd;
416
- int ret = -1;
417
- struct attach_prog_args args = {
418
- .hid = hid_id,
419
- };
420
- DECLARE_LIBBPF_OPTS(bpf_test_run_opts, tattrs,
421
- .ctx_in = &args,
422
- .ctx_size_in = sizeof(args),
423
- );
425
+ int err, link_fd;
424
426
425
- args.prog_fd = bpf_program__fd(hid_skel->progs.filter_switch);
427
+ hid_skel->struct_ops.haptic_tablet->hid_id = hid_id;
428
+ err = hid__load(skel);
429
+ if (err)
430
+ return err;
426
431
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;
432
+ link_fd = bpf_map__attach_struct_ops (hid_skel->maps.haptic_tablet );
433
+ if (!link_fd) {
434
+ fprintf(stderr, "can not attach HID-BPF program: %m\n" );
435
+ return -1;
436
+ }
432
437
433
- return args.retval ; /* the fd of the created bpf_link */
438
+ return link_fd ; /* the fd of the created bpf_link */
434
439
}
435
440
436
441
Our userspace program can now listen to notifications on the ring buffer, and
437
442
is awaken only when the value changes.
438
443
439
444
When the userspace program doesn't need to listen to events anymore, it can just
440
- close the returned fd from :c:func: `attach_filter `, which will tell the kernel to
445
+ close the returned bpf link from :c:func: `attach_filter `, which will tell the kernel to
441
446
detach the program from the HID device.
442
447
443
448
Of course, in other use cases, the userspace program can also pin the fd to the
0 commit comments