Writing your first Linux module can appear to be a very daunting and challenging task. That’s mainly because it is. But, hey if it was easy, then everyone would do it.

Getting Started

In this post, you will hopefully create a very simple Linux kernel module that outputs some traditional messages like “Hello, World!” and “Goodbye, World!”.

I’ll try to focus on explaining the details of every line of code, as opposed to writing a complex module without much explanation.

Like most coding projects, there are some prerequisite tools that you need to install before developing. Luckily for this project, there aren’t that many, but you’ll still need to have access to the following:

Linux machine

make installed

sudo access

Header Files

To get started, we’ll need to first #include some header files to get the bare-minimum functionality of our “Hello, World!” module. We can do so by creating a file named hello_module.c with the following contents:

#include // Allows us to define Macros to replace init_module() and cleanup_module()

#include // Gives us access to KERN_INFO

The header file will basically allow us to define what our description does, while the header file will allow us to provide output from our module.

How to Init

Next, we’ll need to define how the kernel is supposed to initialize our module. We can do so by creating a static init function (you can use whatever function name you want):

static int __init hello_world_init(void){/* This is the entry initialization function of our module that runs when the module is first inserted into the kernel */

return 0; // 0 => Indicate success to the kernel}

Inside this function, we’ll want to add the code that prints the “Hello, World!” remark. One important drawback to note is that we can’t use the traditional printf() function, as the kernel has no header file that defines it. Instead, we’ll use a function calledprintk() which offers a similar way of printing.

Moreover, we can output “Hello, World!” to the kernel ring buffer (this is what KERN_INFOdoes) from our module by adding the following to our init function:

Although this code looks pretty solid, it won’t compile successfully for a few reasons. The first of being that we have to tell the kernel that we aren’t using the default init and exit function names. We also still need to create the Makefile that will compile our code, and turn it into a .ko file that the kernel can actually understand. Lastly, we will need to define macros which specify various details of our module.

Defining the custom init and exit functions

As mentioned previously, we’re not using the default entry and exit points in a Linux kernel module. This is because I think it will be slightly easier for beginners to grasp.

Anyways, since we included the header file, all we have to do to define the custom init and exit functions is add the following to the bottom of our module:

module_init(hello_world_init);module_exit(hello_world_exit);

This is self-explanatory code, but if you’re like me you’ll still want an explanation. So, the line module_init(hello_world_init); basically provides a pass-by-reference value of the hello_world_initstatic function(this is why the init function is defined with the static keyword) to the module_init(); function.

The module_exit(); function does the same exit thing, but with the hello_world_exit reference.

With the addition of the two previous lines of code, our total code now stands with this:

Creating the Makefile

Now instead of running a bunch of commands to compile our module in a specific way, we can just define a Makefile which will automate this compilation process for us. I’m not going to go much in detail about how and why we do what we do in this Makefile

But the key-take-away value is that it compiles our module to the requirements of a Linux kernel module using some built-in tools on Linux.

Now, let’s create the Makefile by simply creating a file named-so, and add the following contents:

obj-m += hello_module.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

In order to make use of this Makefile we can simply type and run make command.

Once this command finishes executing, we should a few files in our current directory. If all goes to plan, the compiled kernel module will be named hello_module.ko

Inserting the module

Now it’s time to actually insert our module into the kernel!

This is a rather simple process thanks to built-in commands in Linux. You can insert your module by running:

sudo insmod hello_module.ko

insmod simply stands for “insert module”

If your computer doesn’t catch fire, then your module has most likely been inserted.

Viewing the results

If you want to see if the module has actually worked (your Linux machine would crash if you did something wrong when inserting), then simply run the following:

dmesg | grep "Hello, World!"

If you see “Hello, World!” outputted back at you, then your module has been successfully loaded into the kernel!!! Although, if you don’t see the magical “Hello, World!” then make sure to re-read the tutorial.

Removing the module

Once your excitement of writing and loading your first Linux kernel module wears off, you might want to remove it from the kernel. I mean it’s surely not doing it too many favors!

To remove the module, we can simply run:

sudo rmmod hello_module

rmmod stands for “remove module”

Viewing the results again!

Again, if you wanted to view the results of removing your module from the Linux kernel, then simply run:

dmesg

If you see the “Goodbye, World!” message, then you know that your module has successfully unloaded from the kernel.

Defining our module

Lastly, we’ll want to define what our module does, that way your users can grasp a better understanding of it if they were to use it.

In order to start defining our module, we’ll need to include another header file that allows us to define macros. So, add #include into the top of your hello_module.c file.

Next, we need to define some macros which define our module. We can do so by adding the following right under all of our #include statements: