I currently own an Apple M1 MacBook Pro, because I was excited to try Linux on ARM as my daily driver. When the Asahi Linux project announced that it would be moving away from Arch Linux ARM as its base distribution, I decided not to follow the community to Fedora, but instead to switch to Gentoo.

This was my first brush with Gentoo, so there were some issues coming out of the gate. The issue I decided to tackle today is the use of the new Apple OpenGL driver.

Asahi Linux provides two kernel configurations for downstream distributions–a “stable” version, and an “edge” version. As of today, the only difference between these two versions is a small amount of kernel configuration. This can be seen in the PKGBUILD for linux-asahi, which builds the two binary packages from the same revision of the sources.

Well, here’s the issue. I thought I was already running the edge kernel. I applied the kernel configuration changes just as they were in that repository, but the Sway Window Manager felt incredibly slow and laggy, and I kept seeing messages like these in my journal:

May 13 18:28:27 hackbook wayland[675]: MESA-LOADER: failed to open apple: /usr/lib64/dri/apple_dri.so: cannot open shared object file: No such file or directory (search paths /usr/lib64/dri, suffix _dri)
May 13 18:28:27 hackbook wayland[675]: MESA-LOADER: failed to open zink: /usr/lib64/dri/zink_dri.so: cannot open shared object file: No such file or directory (search paths /usr/lib64/dri, suffix _dri)
May 13 18:28:27 hackbook wayland[675]: 00:00:00.103 [ERROR] [wlr] [render/egl.c:312] Software rendering detected, please use the WLR_RENDERER_ALLOW_SOFTWARE environment variable to proceed
May 13 18:28:27 hackbook wayland[675]: 00:00:00.104 [ERROR] [wlr] [render/egl.c:554] Failed to initialize EGL context
May 13 18:28:27 hackbook wayland[675]: 00:00:00.104 [ERROR] [wlr] [render/gles2/renderer.c:679] Could not initialize EGL

What gives? To start, I decided to take a look at the kernel configuration changes that specifically enable the Asahi DRM driver:

CONFIG_DRM_SIMPLEDRM_BACKLIGHT=n
CONFIG_BACKLIGHT_GPIO=n
CONFIG_DRM_APPLE=m
CONFIG_APPLE_SMC=m
CONFIG_APPLE_SMC_RTKIT=m
CONFIG_APPLE_RTKIT=m
CONFIG_APPLE_MBOX=m
CONFIG_GPIO_MACSMC=m
CONFIG_LOCALVERSION="-edge-ARCH"
CONFIG_DRM_VGEM=n
CONFIG_DRM_SCHED=y
CONFIG_DRM_GEM_SHMEM_HELPER=y
CONFIG_DRM_ASAHI=m
CONFIG_SUSPEND=y

There’s not a lot there, so I double-checked that all of that was set in my running kernel by grep-ing /proc/config.gz. This activity showed that CONFIG_DRM_ASAHI wasn’t set. Interesting! Taking a look in menuconfig, we see:

Symbol: DRM_ASAHI [=n]
    Type  : tristate
    Defined at drivers/gpu/drm/asahi/Kconfig:16
      Prompt: Asahi (DRM support for Apple AGX GPUs)
      Depends on: HAS_IOMEM [=y] && RUST [=n] && DRM [=y] && (ARM64 [=y] && ARCH_APPLE [=y] || COMPILE_TEST [=n] && !GENERIC_ATOMIC64 [=n]) && MMU [=y]
      Location:
        -> Device Drivers
    (1)   -> Graphics support
            -> Asahi (DRM support for Apple AGX GPUs) (DRM_ASAHI [=n])
    Selects: RUST_DRM_SCHED [=n] && IOMMU_SUPPORT [=y] && IOMMU_IO_PGTABLE_LPAE [=y] && RUST_DRM_GEM_SHMEM_HELPER [=n] && RUST_APPLE_RTKIT [=n]

CONFIG_RUST is unset! Why would that be? I have rust installed, and I have the Rust USE flag set on the sys-kernel/asahi-sources. What gives? Looking a little further, CONFIG_RUST depends on CONFIG_RUST_IS_AVAILABLE, a variable that is unset and has no description in menuconfig. As you might imagine, it’s not possible to set this variable in your .config. I tried. So, I decided to go back to the instructions to build the kernel with Rust support.

[edtwardy@hackbook test-kernel]$ make -C /usr/src/linux-6.2.0_p12-asahi O=$PWD LLVM=1 rustavailable
make: Entering directory '/usr/src/linux-6.2.0_p12-asahi'
***
*** Rust bindings generator 'bindgen' could not be found.
***
make[1]: *** [/usr/src/linux-6.2.0_p12-asahi/Makefile:1829: rustavailable] Error 1
make: *** [Makefile:242: __sub-make] Error 2
make: Leaving directory '/usr/src/linux-6.2.0_p12-asahi'

This is how it started. This first one is obvious–cargo install --version 0.56.0 bindgen. But then I get this one:

[edtwardy@hackbook test-kernel]$ make -C /usr/src/linux-6.2.0_p12-asahi O=$PWD LLVM=1 rustavailable
make: Entering directory '/usr/src/linux-6.2.0_p12-asahi'
***
*** libclang (used by the Rust bindings generator 'bindgen') is too old.
***   Your version:    6.2.0
***   Minimum version: 11.0.0
***
make[1]: *** [/usr/src/linux-6.2.0_p12-asahi/Makefile:1829: rustavailable] Error 1
make: *** [Makefile:242: __sub-make] Error 2
make: Leaving directory '/usr/src/linux-6.2.0_p12-asahi'

Something is suspicious about this one. I’m running clang version 16.0.0, according to equery. I get the impression that something is wrong here. Clang version 6.2.0 is not even available in the Gentoo repository, and installing older versions also doesn’t seem to resolve the issue.

So, I opened the failing Makefile, and chased the failure down to these lines in scripts/rust_is_available.sh:

# Check that the `libclang` used by the Rust bindings generator is suitable.
bindgen_libclang_version=$( \
	LC_ALL=C "$BINDGEN" $(dirname $0)/rust_is_available_bindgen_libclang.h 2>&1 >/dev/null \
		| grep -F 'clang version ' \
		| grep -oE '[0-9]+\.[0-9]+\.[0-9]+' \
		| head -n 1 \

Running each command here and iteratively adding the piped expressions reveals what’s going on. This is the input to the grep -oE '[0-9]+\.[0-9]+\.[0-9]+' command:

/usr/src/linux-6.2.0_p12-asahi/scripts/rust_is_available_bindgen_libclang.h:2:9: warning: clang version 16.0.3  [-W#pragma-messages], err: false

Do you see it? My filepath has a version string in it, and that grep command stops after the first match, so the result of this expression is 6.2.0. This is a pretty simple issue to fix, and it became my very first kernel patch.

With that patch applied to my kernel tree, and after resolving a couple of additonal issues uncovered by the rustavailable target, however, it got worse:

[edtwardy@hackbook test-kernel]$ cat ../PKGBUILDs/linux-asahi/config{,.edge} > .config
[edtwardy@hackbook test-kernel]$ make -C /usr/src/linux-6.2.0_p12-asahi O=$PWD LLVM=1 olddefconfig prepare
 [...omitted...]
  BINDGEN rust/bindings/bindings_generated.rs
thread 'main' panicked at '"ftrace_branch_data_union_(anonymous_at_/home/edtwardy/Git/linux/include/linux/compiler_types_h_121_2)" is not a valid Ident', /home/edtwardy/.cargo/registry/src/github.com-1ecc6299db9ec823/proc-macro2-1.0.56/src/fallback.rs:811:9
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
make[3]: *** [/home/edtwardy/Git/linux/rust/Makefile:298: rust/bindings/bindings_generated.rs] Error 1

About an hour of scraping Linux kernel mailing lists, StackOverflow, and GitHub finally caused me to stumble upon this issue in the rust-bindgen repository, where one of the maintainers suggests that maybe there was a change in name mangling in clang 16. Another maintainer comments that the issue cannot be reproduced at rust-bindgen version 0.62, where the changelog ambiguously states: “Various issues with upcoming clang/libclang versions have been fixed.” So, I install that version, and my kernel build is off to the races!

[edtwardy@hackbook test-kernel]$ make -C /usr/src/linux-6.2.0_p12-asahi O=$PWD LLVM=1 -j10 KCFLAGS="-O3 -march=native -pipe"
[edtwardy@hackbook test-kernel]$ sudo make -C /usr/src/linux-6.2.0_p12-asahi O=$PWD LLVM=1 modules_install
[edtwardy@hackbook test-kernel]$ sudo make -C /usr/src/linux-6.2.0_p12-asahi O=$PWD LLVM=1 install
[edtwardy@hackbook test-kernel]$ sudo dracut --hostonly --kver 6.2.0-asahi-12-edge-ARCH --force

Almost there! This doesn’t fix the error message from wlroots, though, if you remember. It’s complaining about not being able to find apple_dri.so. Pulling down the Arch Linux package for mesa from the Asahi Linux mirror shows the Apple OpenGL driver should definitely be there. Examining the USE flags for the media-libs/mesa::asahi package shows that there’s a flag VIDEO_CARDS: asahi which is currently unset. Enabling this causes the compilation of Mesa to take a lot longer than I remember.

A clean reboot, and wlroots sings the praises of OpenGL acceleration–the error message disappears! Just to verify my sanity, let’s check glxinfo:

[edtwardy@hackbook test-kernel]$ glxinfo
 [...omitted...]
Extended renderer info (GLX_MESA_query_renderer):
    Vendor: Mesa (0xffffffff)
    Device: Apple M1 Pro (G13S C0) (0xffffffff)
    Version: 23.1.0
    Accelerated: yes
    Video memory: 15455MB
    Unified memory: yes
    Preferred profile: compat (0x2)
    Max core profile version: 0.0
    Max compat profile version: 2.1
    Max GLES1 profile version: 1.1
    Max GLES[23] profile version: 2.0
OpenGL vendor string: Mesa
OpenGL renderer string: Apple M1 Pro (G13S C0)
OpenGL version string: 2.1 Mesa 23.1.0-devel
 [...omitted...]

Success! The machine feels so much snappier, and I can now even set the alpha to less than 1.0 in my foot config without causing hair-pulling performance issues. Hopefully my kernel patch will merge soon, so others who are trying to build kernels with Rust support on Gentoo won’t have to follow in my debugging steps.