FLUSP logo FLUSP - FLOSS at USP

Play with Kernel Modules

Written by Rodrigo Siqueira

Written on , last modified on

This tutorial provides a guide for using Linux Kernel modules. We just cover basic issues, such as load and unload of modules.

Command summary

If you did not read this tutorial yet, skip this section. I added this section as a summary for someone that already read this tutorial and just want to remember a specific command.

make modules
make M=drivers/<TARGET_DRIVER>
sudo make modules_install
modinfo <DRIVER_NAME>
lsmod | grep <DRIVER_NAME>
dmesg -H
sudo modprobe <TARGET_DRIVER>
sudo modprobe -r <TARGET_DRIVER>
modprobe --show-depends <module>

Introduction

During my first attempts to start working with Linux Kernel, I read many books and tutorials about device drivers. Although most of them had examples of compiling an external module, some things were still not so clear to me. I was a newcomer, and I felt that I needed to have a deep understanding on how to compile and install in-tree modules in order to start working with kernel drivers.

How can I compile a single in-tree module? How can I install it? Doubts still lingered in my mind…

I confess that I had a difficult time achieving this task for the first time; it took me half a day to learn the essential steps. Nowadays, I see that this is a simple task; however, I want to shed some light on this issue to help newcomers.

For this tutorial, I decided to work with a module named IIO dummy (drivers/iio/dummy [1]) because we can conduct some experiments with that in future tutorials. Please note that the steps and tips described here apply easily to other modules.

Some of the operations described here requires sudo. If you are not 100% comfortable with Linux system or you are a newcomer, I strongly advise you to start working inside a virtual machine; you can read more about this here: Use Qemu to play with Linux Kernel.

Compile In-tree Module

When we start to work with in-tree drivers, we want to spread some pr_info [2] around the code and make other small changes to find a way to understand the code. In this sense, every time that we make a change, we can compile the modules with the following command:

make modules

The above command works pretty well, and I still use it in the present day. Note that only make works, too. Sometimes, we just want to compile and clean a single module. To do this, we can use the following command:

make M=drivers/iio/dummy

The parameter M expects a path to the target driver. This allows you to compile and clean a target module without touching other drivers. For example, try:

make M=drivers/iio/dummy clean

There is a small trick to use this command correctly: your module must be enabled in the .config file, and your kernel should be compiled with this option before you use M. If you don’t know how to do it, take a look at [3]

Install In-tree Module

Before introducing you to the module installation method, it is worth to elaborate a little about loadable modules in a Linux file system. First of all, try the commands below:

$ uname -r
4.9.0-8-amd64

$ ls /lib/modules
4.9.0-6-amd64  4.9.0-7-amd64  4.9.0-8-amd64

The command uname -r print the kernel release and the /lib/modules directory stores all modules [4]. It is important to notice that in /lib/modules/ each version of kernel compiled for your system has its directory; from the practical point of view if you install a new module, you can check it in here.

For installing the module, I use the command:

sudo make modules_install

If you are working in a module and for any reason, you decide to install a modified version of it, you should take a careful look at (1) /lib/modules/, (2) uname -r, and (3) the current kernel version that you are working on. A common mistake is installing modules from the latest kernel version without update the kernel image.

Load and unload

GNU/Linux can dynamically load kernel modules; from the user perspective, users can load modules during the execution time. There’s a different way to load and unload modules, and we will briefly describe it in this section.

modprobe vs insmod

When I started to play with modules, I tried to work with insmod and rmmod command. But since I had just begun to work with drivers, these commands made the whole experience really painful because they are easy to misuse, as a consequence, may lead to a kernel panic. After long hours of reading and debugging, I understood why people always recommend the command modprobe. To understand how module loading works, keep in mind that all drivers installed in the system can be found at /lib/modules/$(uname -r). Also, it is essential to know that modprobe command is a wrapper for insmod and rmmod. By the way, the reason why the command modprobe makes it easier to load and unload modules is because it handles dependencies for you and avoids kernel problems.

Ok, let’s try to load the module with the following command:

sudo modprobe iio_dummy

Besides analyzing the output from modprobe, you can also verify if everything worked correctly with the command lsmod | grep <TARGET_MODULE> or by taking a look at the end of the dmesg log. Try:

lsmod | grep iio_dummy

dmesg -H

If you want to remove a modules, you can try:

sudo modprobe -r iio_dummy

Compile Kernel Module Outside from In-Tree

It is possible to develop a driver as a separate project from the Kernel. In this tutorial, we are only interested in how to load and unload modules; in this sense, I want to introduce commands insmod and rmmod. First, download a simple module at:

Download

Extract the project file with:

tar -xaf simple_dd.tar.gz

Compile the module with:

cd simple_dd
make

To test this module, it would be nice for you to open two terminals side by side. In a terminal, just type dmesg -wH and, in the other, type:

sudo insmod hello_world.ko
sudo rmmod hello_world

Tips and Troubleshooting

Here I want to add some tips and troubleshoots briefly. I will probably update this section in the future. If you have any helpful advice to improve this section, please mail it to me.

Check Installed Module

Sometimes, I do not feel confident that my module has been loaded correctly; because of this, I like to add some prints or make a simple change in the code. The most straightforward approach to check if your module was correctly loaded in the system is changing the MODULE_DESCRIPTION macro and check the metadata with the command modinfo. For example, change the line MODULE_DESCRIPTION in any driver that you use with something like that:

MODULE_DESCRIPTION("YEP... I LOADED THE CORRECT DRIVER");

Then install and load the module again; after that, you can check the description with the modinfo command. For example:

$ modinfo iio_dummy
filename:       /lib/modules/4.16.0-rc3-TORVALDS+/kernel/drivers/iio/dummy/iio_dummy.ko.xz
license:        GPL v2
description:    YEP... I LOADED THE CORRECT DRIVER
author:         Jonathan Cameron <jic23@kernel.org>
srcversion:     1C4C5F875A87E3DFD4F2820
depends:        industrialio-sw-device,industrialio,iio_dummy_evgen,kfifo_buf
retpoline:      Y
name:           iio_dummy
vermagic:       4.16.0-rc3-TORVALDS+ SMP preempt mod_unload modversions

The command modinfo collects information from the Linux kernel modules directory [5]. This is really useful, to help you to figure out if your module is correctly loaded. A common mistake is to compile the module with a different kernel target, this produces errors such as:

FATAL: Module drivers/<path> not found in directory /lib/modules/<kernel_version>

If you get this error, the tip above can help you to figure out what is wrong. Lastly, remember to verify the kernel Makefile to be sure about your kernel version or your distro version.

Get Dependencies Information

Sometimes, it is important to know the modules dependencies. You can use the following command:

$ modprobe --show-depends <module>

Why is this important? If you try something really radical as rmmod -f, it is a good idea to know the exact dependencies related to your device.

From my experience, it is not a good idea to use rmmod -f with large modules. It is ok, if the module is small or if you make it. If you really know what you are doing, use it; if not, avoid. Prefer modprobe -r

Acknowledgments

I would like to thanks Melissa Wen for her detailed review. I really appreciate you taking the time out to share your feedback.

History

  1. V1: Release

References

[1] “IIO dummy source code”. URL: https://github.com/torvalds/linux/tree/master/drivers/iio/dummy

[2] Jonathan Corbet. “The perils of pr_info()”. (2012/03/21) URL: https://lwn.net/Articles/487437/

[3] Rodrigo Siqueira. “Kernel Compilation and Installation”. (2019/02/16) URL: https://flusp.ime.usp.br/kernel/2019/02/16/Kernel-compilation-and-installation/

[4] “Linux kernel modules”. URL: http://linux-training.be/sysadmin/ch28.html#idp68121456

[5] Computer Hope. “Linux modinfo command”. (07/12/2017) URL: https://www.computerhope.com/unix/modinfo.htm


comments powered by Disqus