Kernel Modules

If you’ve been around the Hardkernel Forum long enough the word ‘kernel module’ should sound familiar to you. However, if you’re new to the Linux world the details about what exactly Kernel Modules are might be unclear. This article is intended to not only make you aware of what exactly a Kernel Module but how to interact and build your own.

What Is a Kernel Module?

The Linux kernel is monolithic, meaning everything the operating system needs is part of kernel space. This has the benefit of being faster than other kernel designs such as a micro-kernel, but comes at the cost of lacking modulatory and flexibility. Kernel Modules are designed to help fix this issue of modulatory. In order to add functionality into the kernel, such as a new driver or file system format, the code with that particular new functionality is compiled into a kernel module and then loaded into the Linux kernel.

Hello World Example

For the example code and the rest of the article I assumed the filename would be “examplemod.c”

#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>

MODULE_DESCRIPTION("Example kernel module");
MODULE_AUTHOR("ODROID");

static int example_init(void)
{
      printk(KERN_ALERT "Hello World!\n");
      return 0;
}

static void example_exit(void)
{
      printk(KERN_ALERT "Goodbye World\n");
}

module_init(example_init);
module_exit(example_exit);
The code was kept to a minimal “hello world”, as the focus of this article is about the definition and functionality of Kernel Modules. The example here uses the kernel logging functions to print a simple hello upon initialisation and goodbye when the kernel is removed. The code has two parts that stand out and I address below.
MODULE_DESCRIPTION("Example kernel module");
MODULE_AUTHOR("ODROID");
These macros help fill out information about the module, there are additional field types that can be used such as ‘MODULE_VERSION’, ‘MODULE_LICENSE’, etc. Later we will see commands on how to view this information for any given module.
module_init(simple_init);
module_exit(simple_cleanup);
module_init and module_exit functions register the simple_init and simple_cleanup functions that are defined earlier. These calls register which user created functions will be called for initialization and code exit. printk(), while at first glance might seem similar or interchangeable with printf(), should be thought of differently. As mentioned earlier printk is a mechanism for kernel message logging and not for directly interacting or displaying information to the user. The log level, which range from 0 to 7 (7 least important) is placed before the string without a command as they form a single parameter passed to printk().

Compiling

After writing the module, there are a couple of notes before just calling ‘gcc’. Kernel modules are pretty persnickety about how they are compiled the following rules must be abided by:

  • Non-kernel headers cannot be included
  • The module shouldn’t be linked to any libraries
  • The compiler flags used for the module need to match the ones used for the kernel

To make things simpler, we can use the makefile below:

obj-m += examplemod.o

all:
      make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules

clean:
      make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
The makefile is fairly straightforward but the part that is most important is the following line:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
The path here points to a location where the kernel Makefiles and headers can be found. The Makefile here simply calls the one located there to provide the functionality for the build as well as clean. After running the Makefile, we should be left with a file named examplemod.ko, this is our compiled kernel module.

Commands

Now that we have created our Kernel Module it is time to load into the Linux kernel. The following command can be used to load a *.ko file. When the module is loaded, the function that was set by module_init will be called.

$ sudo insmod ./examplemod.ko
If we remove a Kernel Module that has been loaded, it will call the function set by module_exit. To remove our Kernel Module or any Module that has been loaded, we can use the following command.
$ sudo rmmod examplemod
While not a Kernel Module specific command, the following command allows us to view what has been logged by the kernel. If the previous two commands were run then we should see the two printk() statements near the bottom (more recent) of the log.
$ dmesg
Or to see just the last 2 lines that were printed.
$ dmesg | tail -2
Figure 1 - Loading and removing the kernel module, then printing the kernel log

This will list all currently loaded kernel modules. However, this information is pretty limited if we want to dig deeper we can use the name of a module from the list with the following command.

$ lsmod
Figure 2 - lsmod printout showing examplemod curing loaded

This will print of a more detailed view of the module. If we look at the information from the example module we made, we will see the information that we set at the beginning of our module code.

$ modinfo examplemod
Figure 3 - modinfo printout of the information for our kernel module

Conclusion

These are only the basics to understand what a Kernel Module is and how to create and interact with them. Future articles will take a look at more complex uses and applications of Kernel Modules and how to allow some level of interaction with them to provide meaningful functionality.

Be the first to comment

Leave a Reply