dev-guides

Kernel Compilation in Debian Linux

Overview

In Debian Linux, there are two ways to compile custom kernels:

  1. Using Debian packages

  2. The traditional method

We’ll use the traditional method because it applies to all Linux distributions (in fact, the guide we linked is from the ArchWiki).

Preparation

  1. First and foremost, please take a snapshot of your VM before you get started.

  2. Make sure you have the following kernel configuration/compilation dependencies installed:

    # apt-get install build-essential bc python bison flex rsync libelf-dev libssl-dev libncurses-dev dwarves
    
  3. Reboot and make sure that your system is all good.

  4. Run uname -r to make sure that you are running the stock kernel that ships with Debian. At this time of writing, our arm64 system reports 5.10.0-27-arm64. If you are on an x86 system, it should report 5.10.0-27-amd64. If you’ve updated your kernel, it might say 5.10.0-28-... instead—that should be fine too.

Obtain kernel source

In the Spring 2024 semester, you will be working with Linux kernel version 5.10.205. But instead of fetching the Linux source code from kernel.org, you will be compiling the kernel source code provided in each kernel assignment’s skeleton repo. You will find the pristine, mainline Linux kernel source tree in the linux/ directory in your assignment repo.

You should verify the version of the kernel. The first 6 lines of Linux’s top-level Makefile will show you the version:

$ head -n 6 Makefile
# SPDX-License-Identifier: GPL-2.0
VERSION = 5
PATCHLEVEL = 10
SUBLEVEL = 205
EXTRAVERSION =
NAME = Dare mighty things

It is standard practice to run make mrproper in a freshly cloned repo before proceeding. This removes any configuration files that might have been accidentally left over from previous builds.

Configuring the kernel build

The Linux kernel build system can be configured using .config, which must be located at the root of the Linux source tree. This file is used to specify a truly astounding number of options with which you can build your kernel.

You can start with the .config file of your running kernel (e.g. the stock Debian kernel). The .config file that was used to build the stock Debian kernel is located in the /boot/ directory. The following command copies over that .config file, and updates any missing options with default values:

$ make olddefconfig

Depending on how your stock kernel is configured, this may report some warnings. For example:

/boot/config-5.10.0-20-arm64:7855:warning: symbol value 'm' invalid for ASHMEM
/boot/config-5.10.0-20-arm64:8981:warning: symbol value 'm' invalid for ANDROID_BINDER_IPC

You should be able to ignore these without running into any trouble.

There are two recommended methods to edit your .config file:

  1. You can run make menuconfig, which will open up an interactive menu that organizes configuration options in a more user-friendly manner. If you make any configuration changes, it will also create a backup of your original .config file, named .config.old.

    config.old will be created every time you run a make target related to config, and every time you save in make menuconfig. If you choose this method, we recommend that you save once, only after making all of the changes listed below – this will allow you to take a clear diff of the updated .config vs. the original config file saved in .config.old.

  2. You can use the scripts/config command, which allows you to manipulate options in a .config file from the command line. Note that this method does not create a .config.old file. However, you can find the original .config file in the /boot directory if necessary.

Make the following changes, using either of the above methods:

After setting your local version, take a moment to inspect the contents of the .config file. Make sure that the options you configured are set to what you expect them to be, using scripts/config --state <option> for each of the above options.

Linux also provides the scripts/diffconfig utility, which can be used to compare different .config files. For example, if you used make menuconfig, you would see:

$ scripts/diffconfig .config.old .config
 LOCALVERSION "" -> "-cs4118"
 SYSTEM_TRUSTED_KEYS "debian/certs/debian-uefi-certs.pem" -> ""

If you used scripts/config, you can find your stock .config file in the /boot directory, as config-5.10.0-20-arm64 (on an arm64 machine). You can then run scripts/diffconfig /boot/config-5.10.0-20-arm64 .config, and should see the same output.

localmodconfig

A large amount of time is spent compiling and installing kernel modules you never use. You can regenerate .config so that it contains only the modules your system is currently using. This will drastically cut down the number of modules built.

Running make localmodconfig will take your current .config and turn off any unused modules. Running this will ask you several questions about how to configure the kernel, so rather than doing this manually, run:

$ yes '' | make localmodconfig

This should generate a much smaller .config, leading to a shorter compilation time. You can use the scripts/config commands listed above to verify that the configuration options we care about are still set properly.

Build and Install a New Kernel

Compiling a kernel takes a long time – it can take over an hour on a slow machine. You can speed up this process by running compilation jobs in parallel by using make’s -j flag, which takes the number of parallel jobs to spawn as an argument. If your computer has multiple CPU cores, you should configure your VM to use them.

Run make as a non-root user:

$ make -j$(nproc)

This uses command substitution to invoke the nproc command, which prints the number of cores available on the machine.

Check that running umask yields 0022 (this should be the case by default). If not, run umask 0022. This will ensure that the kernel modules are installed with correct permissions. Note that if your umask is not 0022, you’ve likely modified your umask in your ~/.bashrc or ~/.bash_profile to a non-default value. Since this is a single-user system, a umask of 0022 is reasonable, and you should undo those changes.

Then, install the kernel modules and the kernel itself:

# make modules_install
# make install

Verify that you have the following 3 files in /boot/:

initrd.img-5.10.205-cs4118
System.map-5.10.205-cs4118
vmlinuz-5.10.205-cs4118

Don’t Reinstall Modules

When you are hacking kernel code, you’ll often make simple changes to only a handful of source files. If you didn’t modify any header or module source files, the modules will not be rebuilt when you run make. As such, there is no reason to reinstall all modules every time you rebuild your kernel.

Boot to the New Kernel

Reboot by running:

# reboot

Make sure to pick your custom kernel from the boot loader menu.

Now verify that you’re running your own custom kernel by running:

$ uname -a

Instead of 5.10.0-27-arm64, you should now see your kernel version string, 5.10.205-cs4118!


Last updated: 2023-01-04