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
(replacinglinux
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
- Ensure that the module is available using
find /lib/modules/$(uname -r) -type f -name <module-name>
- Load the module with
modprobe <module-name>
- 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
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.
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.
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
ormake kernelrelease
- Compile kernel DTS file with
make dtbs
- Compile kernel with
make Image
,make zImage
, ormake uImage
- Compile kernel modules with
make modules
- Use
LOCALVERSION=-custom-name
to compile your kernel so it shows5.7.0-custom-name
when you rununame -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
- Linux Kernel Documentation
- https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/7/html/kernel_administration_guide/chap-documentation-kernel_administration_guide-working_with_kernel_modules
- https://cs4118.github.io/dev-guides/
- https://wiki.archlinux.org/title/Kernel/Traditional_compilation
- https://debian-handbook.info/browse/stable/sect.kernel-compilation.html Toolchains
- https://elinux.org/Toolchains#Getting_a_toolchain Linux Kernel and Filesystem for ARM Devices
- https://developer.arm.com/documentation/den0013/d/Building-Linux-for-ARM-Systems/Building-the-Linux-kernel
- https://developer.arm.com/documentation/den0013/d/Building-Linux-for-ARM-Systems/Creating-the-Linux-filesystem Devicetree
- https://elinux.org/images/f/f9/Petazzoni-device-tree-dummies_0.pdf