This is an intro to modern Linux kernel module programming as opposed to compiling an entire kernel. We will present the preliminary knowledge needed and the basic setup. You will learn how to identify your kernel version, be presented a starter code template, learn how to compile, and how to load your module.
You have basic C programming skills and are familiar with the Linux kernel.
Linux operating systems are secure by design. They are designed with a layer of separation between the software that needs direct access to hardware that is the Linux Kernel and all other software that is referred to "user" software. The kernel has it's own space on memory and cpu and user programs have their own space; kernel space is safely separated from user space. So with kernel programming you are directly operating on hardware and so you do not have that safety buffer layer of separation.
"A single wild pointer can wipe out your file system."
"A core dump means a reboot"
REF paragraph 1: tldp.org/LDP/lkmpg/2.6/html/x40.html
$ cat /etc/os-release
Debian GNU/Linux 12 (bookworm)
We are running the Debian 12 codenamed Bookworm which is the current stable version of Debian as of the date of this article Jan 2025; debian.org/releases.
$ uname -r
6.1.0-28-amd64
We are running Linux version 6.1. The most recent Linux version at kernel.org is 6.13 btw.
We will need the kernel headers to compile kernel modules.
$ apt search linux headers 6.1.0-28-amd64
linux-headers-6.1.0-28-amd64
Install it.
# apt install linux-headers-6.1.0-28-amd64
The following additional packages will be installed:
linux-compiler-gcc-12-x86
linux-headers-6.1.0-28-common
linux-kbuild-6.1
linux-libc-dev
Ahh, so kernels requires their own special gcc compiler and a special build tool called Kbuild.
Here is the template for programming a kernel module. It just prints using printk which is a the kernel print function. It is just 14 lines.
REF tldp.org/LDP/lkmpg/2.6/html/hello2.html
File link: ./km-hw-01/km_hw_01.c
Kernel modules are built using a special build tool called Kbuild. A special Makefile variable is availabe in make's extended syntax for building using Kbuild namely "obj-m". This variable sets the ".o" object file that is passed to Kbuild. Usually we call "gcc" in our Makefile but with kernel modules we call "make" in our Makefile. When we call make in our Makefile, we need to cd(change directory) into the Linux source tree build directory using the "-C". Next we need to assign our development module's path to the special Makefile variable "M=". Finally we must supply the keyword option "module".
REF tldp.org/LDP/lkmpg/2.6/html/x181.html
REF oreilly.com/library/view/linux-device-drivers/0596005903/ch02.html
File link: ./km-hw-01/Makefile
As mentioned about, our Makefile has set the "M=" assignment to "$(PWD)" and so we must run make from the directory or our module program
$ ls
km_hw_01.c Makefile
$ make
make[1] ; CC [M] ; MODPOST ; CC [M] ; LD [M] ; BTF [M]
Skipping BTF generation
A number of files have been generated. We will load the ".ko" file. We can ignore that last warning regarding BTF.
# insmod km_hw_01.ko
If insmod returned without error we are good to go.
We can see our Kernel module running on our Linux system using lsmod.
# lsmod | grep km_hw_01
km_hw_01 16384 0
We can do the same as above by viewing the /proc/modules file; lsmod reads from it.
# cat /proc/modules | grep km_hw_01
km_hw_01 16384 0
# rmmod km_hw_01
Since km_hw_01 is loaded into the Kernel it is listed in the /proc/modules file and we can call rmmod from any path location where as we needed to be in the module development directory where the ".ko" file is located to insert it into the Kernel.
Recall our module did not do anything except call the kernel print function printk(). In the recent past, Kernel logs used to be viewable at /var/log/messages. Since the Debian Bookwork update we now use journalctl.
REF debian.org/releases/bookworm/amd64/release-notes/ch-information.en.html#changes-to-system-logging
It is a long print out; pages upon pages going back for days. We can jump to the end using the "-e" option. Or we can us the "-f" option to see Kernel logs as they print out. So when you insmod, you should see the init print out, and when we rmmod the exit printout. You can also use dmesg.
Notice repeated init_km_hw_01() print outs in the above dmesg screenshot. Linux allows us to repeatedly load the same module. It does not return error such as "a module by the same name is already loaded" or similar. Also notice, if you were to run lsmod or cat /proc/modules you would see that only one init_km_hw_01() is loaded.
For a more detailed explanation of kbuild for building an out-of-tree kernel module see the following reference: kernel.org/doc/Documentation/kbuild/modules.txt