This is the link for this afternoon’s livestream.

HID-BPF – Benjamin Tissoires

HID-BPF combines Human Interface Devices (HID) and eBPF (extended Berkeley Packet Filter). It is currently in review upstream.

HID is a simple protocol to report input devices events. It is well supported in Linux, and most devices work with the generic driver. Custom drivers are usually quite short (less than 100 lines), and only do a few transforms.

eBPF is an interesting technology that Benjamin saw at many conferences, and was wondering what to do with it. You’ll get a more complete introduction on it with Alexei’s talk tomorrow.

HID-BPF works on arrays of bytes, and is not intended to do any smart processing. It aims to work in a Compile-Once Run Everywhere mode, where users don’t need to have llvm installed.

In HID, there’s a quite involved process to add a new quirk when a device is somewhat broken: a key is not properly reported. There’s a long time between the first identification of the issue, to the fix reaching the user’s through standard (distro) means.

With HID-BPF, quirks become much simpler to write and deploy: the developer sends a test program (blob + source) to the user, which tests if it fixes the issue, and then can keep using as-is if it works.

Another usecase for HID-BPF is to have some kind of firewall for HID devices: they can work in two directions (can both send and receive events), and this is often used to enable the firmware update mode. For example on linux, Steam opens-up game controllers to everyone (with uaccess) in hidraw mode; and SDL is happy with that. It also prevents a random Chrome plugin to initiate a controller firmware upgrade over the network.

Benjamin Tissoires

It’s also possible to change dynamically the way a device work. For example, the Surface Dial is reported in the inputs as a Dial, but depending on the use case, one might want to report it as mouse, or mouse wheel; you would need to change the kernel driver to do that. You can also use HID-BPF to do HID tracing, in a more powerful way than just hidraw.

With HID-BPF, you can load programs for various types of events: when a device is plug, or a sends a report: you can for example change the neutral zone of a joystick dynamically.

HID-BPF is built on top of BPF, but outside of it. It uses ALLOW_ERROR_INJECTION to enable functions to be tracepoints for BPF programs. Kfuncs are used to export a kernel function as eBPF dynamic API; once the signature is done, the rest is done automatically by eBPF: argument checking, versioning etc.

To conclude, the goal is to simplify the easy fixes in the future. Quirks and live fixes will be simpler without having to update the kernel. Custom uAPIs for devices won’t need to be added anymore: they could just use eBPF programs instead.

New brightness uAPI – Hans de Goede

The problems with /sys/class/backlight aren’t very new: Hans did a presentation on them 8 years ago. With the current uAPI, there is no way to map a given backlight sysfs to a given display, so you might be lost if a you have multiple displays. Sometimes, there might even be multiple sysfs devices for a single display, so userspace won’t know which one to use. The value 0 is also undefined: might be low backlight, or no backlight at all.

The new proposal add new display_brightness and display_brightness_max properties on the drm connector object (which handles a screen): this way the mapping between display and backlight is clear. If the max is 0, it means brightness control is not supported. The latter can also change on hotplug events, for example if a monitor is plugged.

Hans de Goede

The main issue stems from the fact that in x86 laptops, there is a lot of technical debt: multiple control methods were used over the years, from the GPU, to any random firmware interface. The current approach registers a sysfs device for all of them on a laptop; sometimes a kernel heuristic might say a native device should be preferred, and then unregister all others (that were loaded asynchronously); but the rest of the time the userspace needs to pick the sysfs device to pick one (firmware, platform, or native ?). This is all very messy, which is how Hans is now making time to clean this up.

There are also probe ordering issues, between acpi_video backlight and native GPU drivers. But the latter, which are preferred, will take longer to probe; so the acpi_video_backlight userspace interface loading is delayed by up to 8 seconds after probing, giving time to the native driver.

Another ordering issue is between platform(-x86) drivers, and GPU drivers. GPU drivers load earlier, so sometime userspace might try to access backlight, but find it’s not available (yet). Hotplugging events are needed here as well.

Looking at yourself – Arnaldo Carvalho de Melo

Linux has instrumentation to be able to look at itself: its own types, etc.; and it’s not used only for humans, but can also serve runtime-decisions.

Arnaldo’s (kernel) introspection story started a long time ago with struct sock which wasn’t simple to debug with a complex hierarchy, and per-family variants. He looked at how gdb knew about all the type information, and worked with DWARF, ELF and ORC, to create pahole, a tool rebuilding the source with type information, and showing holes in structures, cache boundaries, etc.


After a while, someone from CERN came along, and added support for C++ to it, as well as a 32 to 64-bit migration.

pahole nowadays has the --reorganize option to automatically re-order struct fields, optimizing for size.

In addition to DWARF, the CTF format was added from Solaris; the core of pahole is now multi-format. DWARF has a few issues: debuginfo files are very big, going to hundred of megabytes. This is mainly due to type duplication: because types are per compilation unit (file).

At some point, BPF needed type info to pretty print maps, and to have CO-RE (Compile Once – Run Everywhere). This lead to the creation of BTF, the BPF Type Format. It reused the infrastructure created for CTF in pahole. BTF is de-duplicated, which makes it much smaller, and is available in /sys/kernel/btf/vmlinux. It’s about 3MB nowadays, and very fast to load, which is why pahole uses it by default nowadays. For example, pahole spinlock will print the struct spinlock from the runtime BTF information.

You can dump the whole BTF information in a C header file with bpftool or pahole. BTF can store program lines for disassembly, and this is supported by perf as well.

If BTF is available, it allows perf to do some dynamic things, without patching the kernel. For example, handle the new argument in the sched_switch tracepoint dynamically at runtime to support multiple kernel versions.

It’s possible to use bpftool to list, disassemble bpf programs, or even dump their maps.

Finally, pahole is now built in the kernel and modules build when using BTF. For now, pahole is required, but eventually compilers will produce BTF. In the next version 1.24, pahole will be able to encode BTF in parallel for faster builds.

In Rust, struct fields are reorganized by default (what pahole --reorganize does), but if you build BTF from this, the offsets might not be in order, which is not supported by the BPF verifier. Offsets for BTF rust builds, have been removed for now until a fix is found.

Some people are starting to build products that rely on BTF, like Tetragon from Cilium, or HID-BPF, in the presentation we had earlier.

That’s it for today ! Continued tomorrow !