Introduction to Kernel Modules
1.0 What is a Kernel Module
A kernel module is compiled code which can be loaded and linked into the kernel at runtime.
A kernel module can and often is, a device driver but it does not have to be. We can essentially compile any code provided that we respect the kernel interfaces.
1.1 A Simple Kernel Module
Below is a simple kernel module for us to start with.
#include <linux/module> int __init mymodule_init(void) { printk("Hello World!, In module init\n"); return 0; } void __exit mymodule_exit(void) { printk("Bye World!, In module exit\n"); } module_init(mymodule_init); module_exit(mymodule_exit); MODULE_ALIAS("mymodule"); MODULE_DESCRIPTION("First simple kernel module"); MODULE_LICENSE("GPL v2");
Each portion of the above code is explained below, but for now let’s compile this simple module and insert it into our kernel.
To build the above file, let’s do a quick and dirty Makefile:
PWD := $(shell pwd) KDIR=/home/user/kernel #Change this to your kernel path HOME=$(PWD) OBJ_NAME=hello_world.o default: $(MAKE) -C $(KDIR) M=$(HOME) obj-m=$(OBJ_NAME) \ clean modules
To invoke the above Makefile for an ARM platform, we need to invoke it with the CROSS_COMPILE option to specify the cross compiler and with the ARCH option to specify the architecture for which we want to build this module eg:
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf-
Will invoke the Makefile for the ARM architecture with appropriate cross compiler.
Moreover for the Makefile to execute correctly, the module which the Makefile attempts to build must be built against the kernel which is running on your target.
As such you must pull the kernel for your particular target and provide the path to it in the Makefile above.
For a wonderful guide on getting the cross compiler and the kernel for the BeagleBone, visit Robert Nelson’s page and follow the instructions there.
2.0 The anatomy of a Kernel Module
A kernel module is mostly denoted by 2 special functions:
– The init function, a function which is immediately run upon module insertion into the kernel.
– The exit function, a function which is run upon attempting to remove the module out of the running kernel.
2.1 The init Function
The init function is a function defined by the creator of the kernel module whose job is to initialize anything the module may needupon being inserted into the kernel. This includes but is not limited to, allocations of data structures, registration for kernel events or initialization
of hardware which does not support active probing, i.e i2c.
Should the init function ever return a status other than 0, the module is expunged from kernel memory.
After the init function has exited successfuly, the code belonging to the init function is also expunged from memory. This means that you may never attempt to call the init function from some other part of your code again.
The init function has the following declaration int __init mymodule_init() and is normally coupled with the macro module_init(my_module_init);
There are two things of interest regarding the init function declaration.
The first is the “__init” macro, this macro essentially relocates this init code in an area of memory which is cleared after the code is run.
The module_init macro, lets the build system know when attempting to build your kernel module that the function in the brackets is the function to be called upon module insertion.
Keep in mind that any interfaces or other resources which are publicized by the init function execution, can be invoked before the init function itself has returned.
Therefore we must be very careful that we do not first publicize system resources that have not been fully initialized yet by the init function.
2.1 The exit Function
The exit function is very similar to the init function except that it is called upon module exit. For more advanced modules in our exit functions we must clean any data structures that we allocated in during the entire lifetime of our module. Ideally we should be able to insert and remove the module an infinite number of times without leaking system resources, like having memory leaks or unregistered functionality.
3 Module Insertion
After you invoked the above makefile, if everything went correctly, the build process should have produced a file called “hello_world.ko”. Transfer this file to your target and execute
sudo insmod hello_world.ko
.
Now type
sudo tail dmesg
And you should see “Hello World!”. Congratulations the module insertion worked and we just executed code in the kernel.
3 Module Removal
To remove the module enter:
sudo rmmod hello_world.ko
.
To read our exit message enter:
sudo tail dmesg
- Timekeeping in Linux Userspace
- Enabling PWM on Beagle Bone Black