Building a Custom XanMod Kernel on Ubuntu 23.10

One of the first things I do when setting up a new machine is replace the distribution's Linux kernel with a XanMod build. They're up-to-date, reliable, and thoughtfully tuned for performance.

In most cases, I simply install one of their pre-built packages and call it a day, but on my laptop, there are a few additional tweaks and patches1 I like to apply, so need to build them manually.

That process isn't much different for a XanMod kernel than any other kernel flavor, but there isn't much in the way of documentation. (And most of what does exist seems to have been lifted from an obselete article I wrote several years ago. Haha.)

Let's fix that!

Gathering the Sources

XanMod releases are essentially just patchsets, so you'll need both the patches and corresponding mainline kernel sources to build them.

At the time of this writing, the current stable XanMod release is 6.7.5 so that's what we'll be using in our examples. To follow along in the future, just update the version parts as highlighted below.

The mainline source for this (major) release can be downloaded here:
https://cdn.kernel.org/pub/linux/kernel/v6.x/linux-6.7.tar.xz

The XanMod patches for this (minor) release can be downloaded here:
https://sourceforge.net/projects/xanmod/files/releases/main/6.7.5-xanmod1/patch-6.7.5-xanmod1.xz/download

Toss both to an empty folder and extract them:

# Download.
wget -O linux-6.7.tar.xz https://cdn.kernel.org/pub/linux/kernel/v6.x/linux-6.7.tar.xz
wget -O patch-6.7.5-xanmod1.xz https://sourceforge.net/projects/xanmod/files/releases/main/6.7.5-xanmod1/patch-6.7.5-xanmod1.xz/download

# Unpack the kernel sources.
tar -xJf linux-6.7.tar.xz

# Decompress the patches.
unxz -k patch-6.7.5-xanmod1.xz

Build Dependencies

XanMod kernels have the same general build dependencies as any other kernel. On Debian/Ubuntu, the following will get you everything you need:

# Make sure you have your distribution's source repositories enabled. In a
# traditional sources.list setup, they'll be included by default, but
# commented out. All you'll need to do in such cases is uncomment them:
sudo sed -i 's/# deb-src/deb-src/g' /etc/apt/sources.list

# Update and install the build dependencies.
sudo apt-get update
sudo apt-get build-dep linux

# And for good measure, make sure everything else is up-to-date too.
sudo apt-get dist-upgrade

(If you don't want to install all that crap on your main system, kernels can be built in a Docker container (or similar) instead.)

Configuration

First things first, apply the XanMod patches to the raw kernel sources:

# Move into the kernel source directory.
cd linux-6.7

# Apply the patches.
patch -Np1 -i ../patch-6.7.5-xanmod1

Among other things, this will add a CONFIGS directory populated with several possible configuration files, each targeting a different psABI micro-architecture level.

If you don't know what that means, that's okay. The main thing to understand is that this specificity results in easy performance wins for most users, and all that's needed on your part is to find the best match for your particular CPU.

To that end, copy-and-paste the following (all in one go) into your terminal to see which level your CPU supports:

clear; awk 'BEGIN {
    while (!/flags/) if (getline < "/proc/cpuinfo" != 1) exit 1
    if (/lm/&&/cmov/&&/cx8/&&/fpu/&&/fxsr/&&/mmx/&&/syscall/&&/sse2/) level = 1
    if (level == 1 && /cx16/&&/lahf/&&/popcnt/&&/sse4_1/&&/sse4_2/&&/ssse3/) level = 2
    if (level == 2 && /avx/&&/avx2/&&/bmi1/&&/bmi2/&&/f16c/&&/fma/&&/abm/&&/movbe/&&/xsave/) level = 3
    if (level == 3 && /avx512f/&&/avx512bw/&&/avx512cd/&&/avx512dq/&&/avx512vl/) level = 4
    if (level > 0) { print "v" level; exit level + 1 }
    exit 1
}'

From there, simply copy the corresponding configuration file into place:

# Replace the "v3" suffix with whatever level you've got:
cp -a CONFIGS/xanmod/gcc/config_x86-64-v3 .config

# Then run the following to reset any system-specific variables:
make olddefconfig

# Append a timestamp or something to the localversion to make it unique:
echo "$( cat localversion )-$( date +%s )" > localversion

Thus concludes the basic setup!

If you have any other tweaks or patches to apply, now's the time to apply them, otherwise all that's left to do is build it!

Build It!

On Debian/Ubuntu systems, I prefer using the bindeb-pkg make script because it bundles everything up into convenient .deb packages, allowing the custom kernels to be managed like any other software.2

That's a simple one-liner:

make bindeb-pkg -j$( nproc )

Anyhoo, let it run!

It will take a while, so if you have laundry to do, go ahead and do it.

When the build (finally) finishes, you'll find several .deb packages in the parent directory of the source folder.

You can ignore the *-dbg-* variants unless you need the debugging symbols for whatever reason, and just install the two main linux-image and linux-header packages.

Last things last, reboot!

Or: Build It With LLVM/Clang!

I would be remiss if I ended the article without mentioning the possibility of building the XanMod kernel with LLVM/Clang instead of GCC.

It's an easy switch these days, and there are even PGO-optimized binaries specifically tuned for building Linux kernels.3

To make the switch, all you need to do is add LLVM=/absolute/path/to/llvm/bins/ (with the trailing slash) — or just LLVM=1 if the binaries are within your $PATH — to each make command you run.

For example:

make olddefconfig LLVM=1
make bindeb-pkg -j$( nproc ) LLVM=1

That's it!

Unless you want to play around with the experimental Clang LTO options…

---

1. The ThinkPad ACPI code includes something called "lap detection", a pesky anti-feature mandated by Lenovo's lawyers that throttles performance any time the computer is vaguely jostled or tilted. The only way to avoid this nonsense is to build a kernel with the relevant lines patched out of existence.

2. For other systems, run make help to see the full list of options and build scripts. (Look for the "Kernel packaging" section near the end.)

3. Don't expect any miracles, but the PGO-optimized LLVM tools cut my build time by ~15% (compared to GCC), so not too shabby.

Josh Stoik
16 February 2024
Previous Introducing Rip Rip Hooray!
Next Making Up Numbers: Constrained Numerical Types in Rust