Logo

Kernel

Matteo Salonia's Kernel build, optimized to maximize the hardware's performance, and be as light as possible.

Go to:
Introduction  Setup  Extra

Introduction

My setups are based on a system comprised of the following components:

  • Distro:  Gentoo Linux
  • Kernel Compression:  LZ4 for the initramfs, zstd for zswap
  • Initramfs:  Dracut
  • Bootloader:  GRUB
  • Init:  OpenRC
  • Filesystem:  FAT32 for the ESP, XFS for the RootFS, ext4 for various things.
  • Logind:  elogind
Warning

Since I use Gentoo, the package names may vary from your distro's (Arch, Debian, Fedora, ...) packages. Please verify whether the names may vary, and take note of them.

There are three default configs:

  1. config:  ThinkPad T470p, with CPU i7-7820HQ (Kaby Lake, 4C8T), Nvidia GeForce 940MX dGPU + Intel HD 630 iGPU, SATAIII/NVMe SSD, 2560x1440 display.
  2. config.t440p:  ThinkPad T440p, with CPU i7-4700MQ (Haswell, 4C8T), Intel HD4600 iGPU, SATAIII SSD, 1366x768 display.
  3. config.pc:  Custom-built PC, with CPU i5-11400 (Rocket Lake, 6C12T), Intel UHD 730 iGPU, NVMe SSD.

Verify your desired components are enabled in the Kernel, if you choose my config as a starting point. For example, components relative to AMD, Nvidia (not on T470p), NUMA, etc. have been disabled.

If you don't know where to start, use an already existing config that you know works on your hardware, if available, or else use any Kernel's default config, like the one provided by your distro, or the Kernel's very own default config.

Setup

Make sure to have all the tools necessary to proceed. Verify you have git, gcc, make, etc. Tipically, most compilation tools are provided by packages like base-devel. I suggest you also verify the presence of linux-firmware, in order to have the necessary firmware for any nonfree hardware. Don't forget to download the microcode that is most appropriate, whether it be Intel, AMD, or any other. Finally, make sure you have lz4 and zstd, in order to compress various Kernel components., 

Gentoo users: it is highly recommended you use sys-kernel/installkernel to automatically create the initramfs & update the bootloader config, by respecting your system preferences (e.g. initramfs->dracut, bootloader->GRUB)., 

1. Get the repository

We'll use the /usr/src/usr-kernel directory in order to save this project. Make sure you have read and write permissions, in order to create the directory.

   Copy
git clone --recurse-submodules \
https://github.com/saloniamatteo/kernel /usr/src/usr-kernel

cd /usr/src/usr-kernel
Info

Whenever the chosen directory differs from the default, don't forget to modify the CUSTDIR variable in build.sh

2. Version selection

Once you get the repository, choose an available version. To see which versions are available, you just need to list the directory contents with ls:

   Copy
$ ls
6.12.8-gentoo # <-- Kernel config
bore-scheduler
clear-patches
kernel_compiler_patch
patches
v4l2loopback
build.sh
README.md

In this example, we'll be using Linux 6.12.8-gentoo.

Info

Your Kernel will surely have a different version. No problem: you just need to copy the folder, and rename it according to your version. For example, if your version is 6.12.9-zen, you just need to run: cp -r 6.12.8-gentoo 6.12.9-zen. Don't forget to modify the KVER variable whenever the primary version differs (e.g.: 6.12.8 -> 6.12.9), and PVER whenever the secondary/custom version differs (e.g.: gentoo -> zen)

3. Modify the script

Now, we need to verify the contents of build.sh. Modify the file with any text editor, and note the following variables:

  • CUSTDIR:  this project's directory. Default: /usr/src/usr-kernel
  • KVER:  primary Kernel version.
  • PVER:  secondary/custom Kernel version.
  • KERNELDIR:  directory where Kernels are stored. Default: /usr/src
  • JOBS:  how many threads to use for compilation. Recommended: physical core count.
  • CONFIGFILE:  the Kernel config filename that will be copied from the config directory. Default: config

4. Flag selection

After modifying build.sh, we have to set the correct parameters in order to decide what to do.
Here's a table with all the parameters (flags).

Short flagLong flagDescription
Short flagLong flagDescription
-b--skip-buildDo not build the Kernel.
-c--skip-cfgDo not copy the Kernel config file (config).
-d--distccUse distcc to speed up Kernel compilation
-e--ccacheUse ccache to speed up Kernel compilation
-f--fastmathCompile the Kernel with Unsafe Fast Math options.
-g--graphiteCompile the Kernel with Graphite
-h--helpShow the help menu and exit.
-l--clearl-psApply Clear Linux patches.
-m--menuconfigExecute make menuconfig in the Kernel directory and exit without compiling.
-p--patchesApply user patches.
-r--boreBuild Kernel with BORE scheduler
-v--v4l2Compile the v4l2loopback module.
-y--flagsPrint flags and exit.
-z--varsPrint variables and exit.

5. Kernel configuration

Tipically, it'll be necessary to configure the Kernel, starting from a config file. To do so, you need to run the following as root:

   Copy
./build.sh -l -m -p

This will allow us to:

  • -l:  Apply Clear Linux patches
  • -m:  Configure the Kernel via make menuconfig
  • -p:  Apply included patches

Once the Kernel config process is done, the new config file will be available as /usr/src/linux/.config (or under $KERNELDIR/.config if KERNELDIR has been set).

Now we need to copy .config from the Kernel directory to the chosen Kernel directory (in this case, 6.12.8-gentoo), to then compare the two files and see any changes:

   Copy
cp /usr/src/linux/.config 6.12.8-gentoo/config.new
diff -u 6.12.8-gentoo/config{,.new} | vim

The last command executes the diff command, showing the differences between our starting config file, and the new config.new file, to then show everything with the Vim editor. Obviously, it's necessary to modify the name of the config file in the command above whenever needed (example: you use a custom config)

Note the 6.12.8-gentoo in both commands: modify this whenever you use a different Kernel version.

After verifying the differences, let's replace our config file with the config.new file, and move on to the actual Kernel compilation:

   Copy
mv 6.12.8-gentoo/config{.new,}

6. Kernel compilation

After making sure we have everything that's necessary, we can proceed with compiling the Kernel with the following command, executing it as root:

   Copy
./build.sh -f -l -p

Note the repeated presence of the patch options (-l, -p). This is because the script automatically reverts all changes made by the patches present in the Kernel directory, where possible, and removes said patches. This behavior is wanted, because it helps us reduce errors caused by patches that are malformed, not applied correctly, not wanted, and/or various errors.

Info

The script will show any compilation error, as well as showing the true compilation time, not considering the time it takes to apply patches, and so on.

Once the script finishes its execution, thanks to installkernel the initramfs will be generated, and the bootloader will be updated. With my configuration these correspond to dracut and grub. Obviously it'll be your responsibility to configure installkernel before trying to install the Kernel.

Extra

This section specifies any extra steps to take after Kernel compilation, that do not depend on the script. Using the script, it won't be necessary to manually update the initramfs, nor the bootloader, because they'll be automatically updated (see above).

V4L2loopback

The script will automatically install this module for the compiled Kernel version. The only step you need to take is add the module settings, because the script does not check whether they exist or not.

Modify /etc/modprobe.d/v4l2loopback.conf, and add the following:

   Copy
options v4l2loopback exclusive_caps=1 card_label="Camera2"

Here you can modify card_label to set the device name, whenever necessary, for example if you want to hide the fact this is a virtual device, or if you simply would like a better name.

Initramfs

To run the Kernel an initramfs is necessary. To generate it, I'll use dracut.

First of all, make sure you configured dracut. For example, here's my /etc/dracut.conf:

   Copy
# Equivalent to -H
hostonly="yes"

# Add various modules
# Module: description
# ==================================
# base: include basic utilities
# dash: include /bin/dash as /bin/sh
# fs-lib: include filesystem tools like mount
# kernel-modules: include kernel modules
# rescue: include various utils for rescue mode
# resume: allow initramfs to resume from low-power state
# rootfs-block: mount block device that contains rootfs
# shutdown: set up hooks to run on shutdown
# udev-rules: include udev and some basic rules
# usrmount: mount /usr
dracutmodules+=" base dash fs-lib kernel-modules rescue resume rootfs-block shutdown udev-rules usrmount "

# Do not include bash (we use dash)
omit_dracutmodules="bash"

# Include elogind
install_items="/lib64/elogind/elogind-uaccess-command"

# Use lz4 to compress the initramfs
compress="lz4"

# Add early microcode loading
early_microcode="yes"

It's sufficient to execute the following command as root:

   Copy
dracut --kver 6.8.2-gentoo -f

Replace 6.8.2-gentoo with your Kernel version. Pay attention to the -f flag: it forces the initramfs generation, even if it already exists for the chosen Kernel.

The initramfs will be available under /boot, together with the previously compiled Kernel's files.

Bootloader

To boot our new Kernel, we need to configure the bootloader. In this section we'll only see GRUB2.

Most users, at this point, will surely already have a working system, and a configured bootloader. This then lets us simply update the bootloader config, without modifying any other files.

So, you just need to run as root:

   Copy
grub-mkconfig -o /boot/grub/grub.cfg

This command will tell us the available Kernels (and any other OS), that will be available once we reboot our system, in addition to telling us which microcode(s) were found.

← Back to the main page