Skip to content

Working with the Linux Kernel

The Kernel

The Linux kernel is the software that drives and orchestrates access to hardware on your computer.

The Linux Kernel is monolithic by design. To this end, it is compiled with optional or additional modules as required by a developers use case: you can extend the kernel's functionality by dynamically loading kernel modules.

Certain kernel modules sometimes depend on one or more other kernel modules. The /lib/modules/<KERNEL_VERSION>/modules.dep file contains a complete list of kernel module dependencies for the respective kernel version. This file is created by the depmod program.

Tip:

  • You can find which kernel you're currently running by using the uname -r command
  • Other useful information can be found by using the uname -a command

Though you don't want to alter the kernel while it's running, you can manage kernel functionality without a reboot using Loadable Kernel Modules (LKMs). Kernel modules act as translators between hardware devices and the Linux kernel.

[! INFO] aarch64 and arm64 refer to the same architecture The Linux kernel community opted to call their port of the kernel to this architecture arm64 instead of aarch64, which is where the usage of arm64 comes from.

Kernel Modules

  • Compiled modules have a .ko (kernel object) extension and reside in the /lib/modules/$(uname -r)/kernel directory.
  • You can quickly see which kernel modules are currently loaded using lsmod.
  • You can find all available modules using modprobe -c.
  • Check whether you have configured modules with grep -i =m /usr/src/linux/.config (replacing linux with the appropriate directory). If there is no output, kernel modules are not configured.
  • Check whether you have built modules with find /lib/modules/*/ -type f -iname '*.ko' | less. If there is no output, there are no kernel modules built.

Adding a module to the kernel is a lot easier than it sounds

  1. Ensure that the module is available using find /lib/modules/$(uname -r) -type f -name <module-name>
  2. Load the module with modprobe <module-name>
  3. If required, use rmmod to remove a module

Compiling the Linux Kernel

You will need some dependencies before compiling will work

sudo apt install make libncurses-dev flex bison openssl libssl-dev dkms libelf-dev \
	libudev-dev libpci-dev libiberty-dev autoconf build-essential
sudo apt install make libncurses-dev flex bison openssl libssl-dev dkms libelf-dev \
	libudev-dev libpci-dev libiberty-dev autoconf build-essential

Assumption: You have the Linux source code, either cloned from git or downloaded as a tarball.

To begin, the kernel has to be configured. This includes with target ARCHitecture and any specific kernel features. To generate a default configuration (defconfig) for an arm64 kernel, use

sh
make ARCH=arm64 defconfig
make ARCH=arm64 defconfig

You may want to create alternative default configurations for your specific kernel.

To further configure kernel features, e.g., add device drivers, specify loadable modules, etc., it's best to use menuconfig.

sh
make ARCH=arm64 menuconfig
make ARCH=arm64 menuconfig

This will open an NCurses style GUI configuration tool. Use the arrow keys and Enter button, select Y to build features directly into the kernel, M to make them loadable kernel modules, and N to omit them.

Once the kernel is configured, it can be compiled using make.

sh
make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- dtbs Image modules
make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- dtbs Image modules

In order to cross compile as shown above, you need to have the toolchain installed. The CROSS_COMPILE flag sets a prefix on the executables it will access such that it uses {$CROSS_COMPILE}gcc, for example. Thus, install the toolchain sudo apt install gcc-aarch64-linux-gnu.

Note that if you're compiling on an aarch64 device this the CROSS_COMPILE argument can be omitted, and it will compile with the native toolchain. See the additional resources for more information about available toolchains. Remember to only use the prefix of the toolchain executables; if you look at the Makefile itself you will see, e.g., CC = $(CROSS_COMPILE)gcc which will convert into CC = aarch64-linux-gnu-gcc with the above make command.

Tips

  • The best way to further understand how to work with the kernel source code it to read the output from make help.
  • Check the version of the kernel that will be built with make kernelversion or make kernelrelease
  • Compile kernel DTS file with make dtbs
  • Compile kernel with make Image, make zImage, or make uImage
  • Compile kernel modules with make modules
  • Use LOCALVERSION=-custom-name to compile your kernel so it shows 5.7.0-custom-name when you run uname -r

Boot Loaders

In simple terms, the boot loader loads the kernel from the disk into memory and then initializes the kernel with certain kernel parameters. This process is more complicated than it sounds because the boot loader needs to know where the kernel is and which parameters it needs to be initialized with.

Modern disk hardware is typically shipped with firmware to enable the BIOS or UEFI to access storage hardware via Logical Block Addressing (LBA).

Resources