In the Linux kernel, drivers can be integrated in two different ways.
One option is to compile the driver as part of the kernel, making it a section of the vmlinux image.
The other option is to build the driver separately and load it dynamically into the kernel. When a driver is loaded dynamically, it is called a Linux Kernel Module. These modules are extremely useful, especially during the development phase, as they allow flexibility without recompiling the entire kernel.
Before You Write a Linux Kernel Module
Before writing your first kernel module, it’s important to understand Kernel C.
Now, you might be wondering — do I need to learn a new programming language?
Don’t worry! Kernel C is just standard C with GNU extensions.
What Is “Pure C”?
Pure C refers to code that runs without user-space libraries, such as glibc.
In kernel programming, all required functions are included within the kernel itself.
This internal code is available under:
<kernel_source>/lib
Kernel and Object-Oriented Concepts
One of the most beautiful aspects of the Linux kernel is that, even though it’s written in C, it follows object-oriented design principles.
You can observe this behavior in your very first kernel module. Below is the Simple Kernel Module:
#include <linux/module.h>
#include <linux/version.h>
static int __init skm_init(void) /* Constructor */
{
printk(KERN_INFO "skm registered\n");
return 0;
}
static void __exit skm_exit(void) /* Destructor */
{
printk(KERN_INFO "skm unregistered\n");
}
module_init(skm_init);
module_exit(skm_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Embitude Trainings <info@embitude.in>");
MODULE_DESCRIPTION("Simple Kernel Module");
Structure of a Simple Kernel Module
Every kernel module includes:
- A constructor function
- A destructor function
For example:
skm_initacts as the constructor.skm_exitacts as the destructor.
The constructor runs when the module is loaded into the kernel. Similarly, the destructor runs when the module is removed.
Macros such as module_init() and module_exit() help define these functions.
Important Kernel Header Files
The kernel uses a few essential header files for module development:
module.h→ Includes module-related structures, APIs, and macros likemodule_init()andmodule_exit().version.h→ Defines kernel version compatibility for modules.
You’ll also find macros beginning with MODULE_, which describe module metadata and form the module’s signature.
Building a Kernel Module
To build a kernel module, you need kernel source code or at least the kernel headers.
Usually, these are located at:
/usr/src/linux-headers-<kernel version>/
Building a kernel module is different from compiling a normal application.
In typical C programs, the gcc compiler automatically links libraries from /usr/lib. However, kernel code is self-contained and does not use user-space libraries.
Therefore, you must instruct gcc not to link standard libraries.
Also, since the module is dynamically loaded into the kernel, it should be compiled with the same flags used for the kernel.
To handle this correctly, we invoke the kernel’s Makefile to compile the module.
Example: Makefile for Kernel Module
To point to to kernel headers, we use ,/lib/modules/$(shell uname -r)/build, which is symbolic link to corresponding kernel headers. With this, the Makefile might look like this:
obj-m := skm.o
KERNEL_SOURCE := /lib/modules/$(shell uname -r)/build
all:
make -C $(KERNEL_SOURCE) M=$(PWD) modules
clean:
make -C $(KERNEL_SOURCE) M=$(PWD) clean
If your kernel source is in another location, simply update the KERNEL_SOURCE variable.
Now, build the module using:
$ make
The output file will be:
skm.ko
Loading and Unloading a Kernel Module
Once the module is built, you can dynamically load and unload it.
Load the Module
Run the following command as root:
$ insmod skm.ko
List Loaded Modules
To confirm that your module is loaded, use:
$ lsmod
Unload the Module
To remove the module, execute:
$ rmmod skm
Note: While unloading, use the module name (skm) instead of the file name (skm.ko).
Conclusion
You’ve just learned how to write, build, and load a simple Linux kernel module.
This forms the foundation of Linux kernel development.
In upcoming articles, we’ll explore other kernel programming topics — including Kernel Source, Kernel Threads, Kernel Synchronization, interrupts, and process management. So, stay tuned!
💡 Want to Master Linux Device Drivers?
If you enjoyed learning about kernel modules, you’ll love taking your skills to the next level.
Join my Embedded Linux Device Drivers Course — a complete, hands-on program designed for embedded engineers who want to master Linux internals and driver development.
🎯 What You’ll Learn
- Write real-world character and interrupt-driven drivers
- Understand kernel synchronization, process blocking, and concurrency
- Work on a live project and get lifetime access to 30+ hours of sessions
- Learn through challenge-based lessons, assignments, and live mentorship
👉 Join the course today and start your journey to becoming an industry-ready Linux developer:
🔗 Enroll in Embedded Linux Device Drivers Course
💡 Want More Linux Kernel Insights?
Subscribe to my mailing list to get updates on hands-on Linux articles and tutorials:
👉 Join the Embitude Community