In Linux kernel, drivers can be put in two ways. One is, you make it as a part of kernel and will be part of vmlinux image. Another thing is to build the drivers separately and dynamically plug it into the Kernel. So, the driver which is loaded dynamically into the kernel is known as kernel module. Modules are very handy during the development phase.
Writing a Simple Kernel Module
Before writing a module, you need to understand the kernel C. So, you might be wondering, do I need learn one more language for coding in Kernel? Don’t worry, Kernel C is normal pure C with GNU extensions. Now, what is pure C? It means C without access to any user space libraries such as glibc. Kernel includes all the code as a part of itself. This is the code which kernel developers have developed as a part of kernel and is placed at <kernel_source>/kernel/lib.
One of the beautiful thing about the kernel is that, though its written in C, but it follows the object oriented concepts. This is evident from the very first module which we will try. Below is the simple kernel module:
As can be seen, every module has a constructor and destruction function. skm_init is the constructor and skm_exit is the destructor. Now, as with object oriented programming, constructor is invoked when the the object is instantiated, similarly, over here, constructor is invoked when the module is dynamically loaded into the kernel. So, when will destructor be invoked? Of course, when the module is plugged out of the kernel. Macros module_init() and module_exit() are used to specify the constructor and destructor for a module.
Equivalent of printf() in kernel is printk().
Header file ‘kernel.h’ is kernel space header file which includes the prototype for printk and other commonly used functions. module.h includes the module related data structures and APIs. Macros module_init() and module_exit() are defined here. File version.h contains the kernel version. This is included for the module version to be compatible with kernel into which the module will be loaded.
Apart from this, we have a macros beginning with MODULE_. These specify the module related information and form the module’s signature.
Building a Kernel Module
In order to build a kernel module, you need to have the kernel source code which is usually found at /usr/src/linux. If not kernel source, at least you need the kernel headers. Building a kernel module is different from a building any application. Normally, applications are compiled using the gcc command and by default, gcc picks up the libraries in /usr/lib. But, as discussed earlier, kernel code is a self-contained and doesn’t uses the libraries from the user space. So, we need to give the command line options to gcc to not to take the standard libraries. Not only that, since the module is going to be the hot plugged into the kernel, it has to be compiled with the same flags as the kernel was compiled with. In order to take care of these things, we invoke the kernel makefile to compile our module.
Below is the makefile for compiling the module:
Here, it is assumed that the kernel source is placed at /usr/src/linux/. If it is placed at any other location, update the location in KERNEL_SOURCE variable in this Makefile.
To build the module, invoke make as below:
The output of the make would be skm.ko.
Dynamically Loading/Unloading a Kernel Module
We use insmod command to load the kernel module as below. We need to execute this command with root privileges
$ insmod skm.ko
In order to list the modules, execute lsmod as below. This will show you the skm loaded.
And for removing/unloading the module, execute rmmod command as below:
$ rmmod skm
Note that while unloading, we use module name (skm), not the file name (skm.ko).
So, now we are comfortable with writing & building a kernel module. This is the basic building block of the Linux kernel development. In the following articles, we will dive into the Linux Kernel Programming. So, stay tuned!