Embitude Infotech1

Writing a Simple Linux Kernel Module

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_init acts as the constructor.
  • skm_exit acts 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 like module_init() and module_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

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top