Loading resume...
Introduction to Linux Kernel Modules
What Are Kernel Modules?
Linux kernel modules are pieces of code that can be loaded and unloaded into the kernel upon demand. They extend the functionality of the kernel without requiring a system reboot. Modules are ideal for device drivers, filesystem drivers, and system calls.
Kernel modules run with the same privileges as the kernel itself. They can access kernel functions and data structures directly, with no performance overhead.
Why Use Kernel Modules?
Kernel modules offer several advantages:
- Modularity: Keep the kernel small by only loading functionality when needed
- Runtime Flexibility: Add and remove functionality without rebooting
- Development Efficiency: Develop and test drivers without constantly rebooting
- Resource Optimization: Load only the drivers needed for your hardware
Bugs in kernel modules can crash the entire system or cause data corruption. Always test on development systems first, not production environments.
Setting Up Your Development Environment
Before we write our first kernel module, we need to set up the development environment:
# Update your system
sudo apt update && sudo apt upgrade -y
# Install necessary development packages
sudo apt install build-essential bc bison flex libssl-dev libelf-dev git
# Install kernel headers (required for building kernel modules)
sudo apt install raspberrypi-kernel-headers
# Create a directory for our kernel module
mkdir -p ~/kernel-modules/hello
cd ~/kernel-modules/hello
Your First Kernel Module: Hello World
Let’s create a simple “Hello World” kernel module that prints a message when loaded and unloaded.
Step 1: Create the Source File
#include <linux/module.h> // Core module functionality
#include <linux/kernel.h> // For KERN_INFO
#include <linux/init.h> // For module_init and module_exit macros
MODULE_LICENSE("GPL"); // Module license
MODULE_AUTHOR("Utsav Balar"); // Module author
MODULE_DESCRIPTION("A simple Hello World kernel module"); // Module description
MODULE_VERSION("0.1"); // Module version
/**
* hello_init - Module initialization function
*
* This function runs when the module is loaded into the kernel.
* It prints a welcome message to the kernel log.
*
* Return: 0 on success, negative errno on failure
*/
static int __init hello_init(void)
{
printk(KERN_INFO "Hello World: Module loaded\n");
return 0;
}
/**
* hello_exit - Module cleanup function
*
* This function runs when the module is unloaded from the kernel.
* It prints a goodbye message to the kernel log.
*/
static void __exit hello_exit(void)
{
printk(KERN_INFO "Hello World: Module unloaded\n");
}
// Register module initialization and cleanup functions
module_init(hello_init);
module_exit(hello_exit);
Step 2: Create the Makefile
A Makefile is needed to build our kernel module:
# If KERNELRELEASE is defined, we're being called from the kernel build system
ifneq ($(KERNELRELEASE),)
obj-m := hello.o
# Otherwise, we're being called directly from the command line
else
# Path to the kernel headers
KERNEL_DIR ?= /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
# Default target
all:
$(MAKE) -C $(KERNEL_DIR) M=$(PWD) modules
# Clean target
`Clean:
$(MAKE) -C $(KERNEL_DIR) M=$(PWD) clean
endif
Understanding the Code
Module Metadata
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Utsav Balar");
MODULE_DESCRIPTION("A simple Hello World kernel module");
MODULE_VERSION("0.1");
These macros provide metadata about the module:
- `MODULE_LICENSE`: Declares the license (important for compatibility)
- `MODULE_AUTHOR`: Who wrote the module
- `MODULE_DESCRIPTION`: What the module does
- `MODULE_VERSION`: The module's version number
Module Initialization Function
static int __init hello_init(void)
{
printk(KERN_INFO "Hello World: Module loaded\n");
return 0;
}
The __init
marker tells the kernel that this function is only needed during initialization. After the module is loaded, this memory can be freed.
The function must return 0 on success or a negative error code on failure.
Module Cleanup Function
static void __exit hello_exit(void)
{
printk(KERN_INFO "Hello World: Module unloaded\n");
}
The __exit
marker tells the kernel that this function is only needed during module removal.
Function Registration
module_init(hello_init);
module_exit(hello_exit);
These macros register our functions as the initialization and cleanup handlers for our module.
Building and Testing the Module
Now let’s build and test our kernel module:
# Build the module
make
# Check that the module was built successfully
ls -l hello.ko
# Load the module
sudo insmod hello.ko
# Check that the module is loaded
lsmod | grep hello
# View kernel log messages
dmesg | tail
# Unload the module
sudo rmmod hello
# Check log messages again to see the unload message
dmesg | tail
Understanding the Kernel Module Build Process
The build process for kernel modules is different from normal user-space programs:
- The source code is compiled against the kernel headers
- The module is linked against kernel symbols
- The result is a
.ko
(kernel object) file - This file can be loaded into and unloaded from the running kernel
The build system sets up the correct environment, including:
- Compiler flags matching the kernel build
- Symbol table information
- Module versioning and compatibility info
Module Parameters
Kernel modules can accept parameters at load time. Let’s modify our module to accept a string parameter:
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/moduleparam.h>
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Utsav Balar");
MODULE_DESCRIPTION("Hello World module with parameters");
MODULE_VERSION("0.2");
// Define a string parameter with a default value
static char *name = "world";
// Register the parameter
module_param(name, charp, S_IRUGO);
MODULE_PARM_DESC(name, "The name to display in hello message");
static int __init hello_init(void)
{
printk(KERN_INFO "Hello %s: Module loaded\n", name);
return 0;
}
static void __exit hello_exit(void)
{
printk(KERN_INFO "Goodbye %s: Module unloaded\n", name);
}
module_init(hello_init);
module_exit(hello_exit);
To load this module with a custom parameter:
# Build the module
make
# Load the module with a parameter
sudo insmod hello.ko name="Raspberry Pi"
# Check the kernel log
dmesg | tail
# Unload the module
sudo rmmod hello
Automatic Module Loading
In production systems, modules are typically loaded automatically by the kernel when needed, using one of these methods:
- Device Tree Matching: For platform and device drivers
- PCI/USB ID Matching: For PCI and USB devices
- Module Alias: For aliases in the module configuration
- Dependency Resolution: Via modprobe and modules.dep
Debugging Kernel Modules
Debugging kernel modules is different from user-space code:
- Kernel Logs: The primary debugging tool (use
dmesg
orjournalctl
) - printk Priorities: Different message levels (
KERN_EMERG
,KERN_ALERT
, etc.) - Dynamic Debug: Enable selective debug messages
- KGDB: Kernel debugger for advanced debugging
Common Pitfalls
When developing kernel modules, watch out for these common issues:
- Missing Cleanup: Always release all resources in the exit function
- Kernel Version Compatibility: Kernel APIs can change between versions
- Race Conditions: Kernel code is highly concurrent
- Memory Corruption: Buffer overflows in kernel space crash the system
- Stack Limitations: Kernel stack is much smaller than user-space stack
Next Steps
Now that you’ve created your first kernel module, you’re ready to learn about more advanced topics:
- Character device drivers
- Memory management in the kernel
- Kernel synchronization mechanisms
- Interrupt handling
Summary
In this tutorial, you’ve learned the basics of Linux kernel modules:
- What kernel modules are and why they’re used
- How to set up a development environment
- How to write a basic kernel module
- How to build and load/unload a module
- How to use module parameters
- Basic debugging techniques
With this foundation, you’re now ready to explore more complex kernel programming topics in the next tutorials.
References
- Linux Kernel Documentation: Module Parameters
- Linux Kernel Documentation: Kernel Modules
- Linux Driver Development for Embedded Processors
- Linux Kernel Development
Last updated: May 24, 2025