Skip to content
Naveen Naidu

Hello World! Kernel Module

lkmp, linux, kernel4 min read

Yohooooo people!

Today we'll learn how to greet hoomans from Linux Kernel :P, i.e we'll learned how to write "Hello World!" Kernel Module \o/

We'll directly jump into the action and I'll explain what's happening in the later sections :)

Hello World! - Kernel Module

1. Prepare your cauldron for the magical experiment

1mkdir hello-world
2cd hello-world

2. Let's put our spells into the cauldron

1vim hello-world.c

Add the following into the hello-world.c file.

1/*
2 * hello_world.c -- A Kernel Module that prints Hello World
3 */
4#include<linux/init.h>
5#include<linux/module.h>
6
7// This function is executed when you load the module using insmod
8static int __init helloworld_init(void)
9{
10 printk(KERN_INFO KBUILD_MODNAME ": Hello Confused Hooman!! \n");
11 /*
12 * A non 0 return means that module can't be loaded.
13 */
14 return 0;
15
16}
17
18static void __exit helloworld_cleanup(void)
19{
20 printk(KERN_INFO KBUILD_MODNAME ": Sayonara Hooman. \n");
21}
22
23// Register the module
24module_init(helloworld_init);
25module_exit(helloworld_cleanup);
26
27// Information Regarding the module
28MODULE_LICENSE("GPL");
29MODULE_AUTHOR("Naveen Naidu");
30MODULE_DESCRIPTION("A Hello World Kernel Module");

3. Create a new spell which will invoke the magic

1vim Makefile

Time for creating the new spell

1obj-m := hello_world.o
2KDIR := /lib/modules/$(shell uname -r)/build
3
4all:
5 $(MAKE) -C $(KDIR) M=$(PWD) modules
6
7clean:
8 $(MAKE) -C $(KDIR) M=$(PWD) clean

4. Speak the new spell

1make all

5. Time to see the magic in action

1# Add the kernel module
2sudo insmod hello_world.ko
3sudo dmesg -t -l info > dmesg_current_info
4
5# Time to see hello world message
6cat dmesg_current_info | grep "hello"
7
8# Remove the module and see if the module say's Byee
9sudo rmmod hello_world.ko
10sudo dmesg -t -l info > dmesg_current_info
11
12# See the Goodbye message from our module
13cat dmesg_current_info | grep "hello"

TADA!! you have written your first Kernel module \o/ \o/

Note: For the folks who don't wanna try it out on your system but still wanna feast on the magic :P, I prepared an asciinema for you. Have a look at asciinema


Time for Explanation!! & My learning while doing this ^^

What are Kernel Modules

These are the type of code that could be loaded and unloaded into the kernel on demand. This helps in extending the functionality of the kernel without the need to reboot the system.

Without the functionality of Kernel modules the only way we could have added new code was by statically linking it to the kernel that would mean, building the kernel after making any change. This would have had a very adverse impact on the development time of new features.

Having Kernel Modules also helps in easy debugging of the issues in a module instead of panicking the Kernel and crashing it.

Basic Structure of a Kernel Module

A kernel module must have at least two functions:

  1. Initialization “start” function , init_module()
  2. Cleanup Function, cleanup_module()

The Initialization function is called whenever the kernel is loaded or whenever it is insmoded and the “end”/cleanup function is called whenever we unload/rmmod the module.

Though the first google results directed me to the page where the init_module() function was used, but while browsing through the kernel code these functions were rarely used and further reading I realized that I need not name my functions as init_module() or cleanup_module mandatorily.

With the Kernel 2.4, I could use module_init() and module_exit() to name the Initialization function and the ending function.

Logging/Printing from inside a Kernel module

In order to print/log information from inside the kernel we use a function called “printk()”. The format of it is as follows:

1printk( <LOG LEVEL> <MORE OPTIONS> "Message String");

There is also a improved version of “printk()” which is “prinfo()” or “pr*” variants. For the sake of this task, I chose to use the “printk()” since it suited well for the needs of the task.

The logs/messages from the printk() is stored/logged in the /var/log/kern.log and could easily be accessed using dmesg.

Log Levels available
  • KERN_EMERG: Used for emergency messages, usually those that precede a crash.
  • KERN_ALERT: A situation requiring immediate action.
  • KERN_CRIT: Critical conditions, often related to serious hardware or software failures.
  • KERN_ERR: Used to report error conditions; device drivers often use KERN_ERR to report hardware difficulties.
  • KERN_WARNING: Warnings about problematic situations that do not, in themselves, create serious problems with the system.
  • KERN_NOTICE: Situations that are normal, but still worthy of note. A number of security-related conditions are reported at this level.
  • KERN_INFO: Informational messages. Many drivers print information about the hardware they find at startup time at this level.
  • KERN_DEBUG: Used for debugging messages.

For the sake of the task, I chose to use the KERN_INFO log level.


Building a Kernel Module

Types of Kernel Module

There are two kinds of kernel modules:

  • In Tree Modules - Modules present in the linux tree
  • Out of the Tree modules - Modules external to the linux tree

The way we build these two modules are slightly different but the gist says the same.

The following information is gathered after reading through the documentation in Documentation/kbuild/modules.rst. Though I was not able to comprehend everything present in the documentation (I hope someday with experience I could be able to do so :) but it was an interesting read and helped me a lot with my task.

Build External Modules

The main highlights/important points for this is:

  • We must use “kbuild” only so that we could stay compatible with the changes in the build infrastructure and also helps us choose the right flags for GCC.
  • When building out of tree module, we must have a complete and precompiled kernel source tree on our system. This is necessary since modules are linked against the object files found in the kernel source tree.
  • We must not compile our module with one kernel version and then use the same module with other Kernel version. This might lead to run time errors since the symbols might differ between kernel versions.
1. Creating a Local Makefile

Create a local makefile where we define a kbuild variable like below.

1obj-<X> := <module_name>.o

The <X> stands for kbuild variable and X takes one of the following values

  • X = n , Do not compile the module
  • X = y , Compile the module and statically link with kernel image
  • X = m , Compile the module as a dynamically loadable kernel module

The above line is enough for the Makefile, but we can also add additional make rules to make our life easy.

2. Installing the Modules

The command syntax for this is:

1make -C $KDIR M=$PWD [target]

KDIR stands for the default kernel directory where the source is located.

M=$PWD, this informs kbuild that an external module is being built. The value that we give to the M is the absolute path where the external module (kbuild file) is present.

3. Combining the above two things in a Makefile

To make our life easier we could combine the above two commands in our Makefile. For my Makefile, I have the following thing

1obj-m := hello_world.o
2KDIR := /lib/modules/$(shell uname -r)/build
3
4all:
5 $(MAKE) -C $(KDIR) M=$(PWD) modules
6clean:
7 $(MAKE) -C $(KDIR) M=$(PWD) clean

Thus when you run make all, the kbuild system will build the hello_world.o file from the hello_world.c and after linking, will result in the kernel module hello_world.ko being created. And this will also install the module.

Loading/Unloading the Module
1. To Load the module

You can use the insmod command to the .ko file that is created after the make command. This will load the module. If you want to see if the module is loaded you could use the lsmod command.

For example in my case:

1sudo insmod hello_world.ko
2sudo lsmod | grep "hello"
2. To Unload the module

Use the rmmod command to unload the module.

For example in my case:

1sudo rmmod hello_world.ko
2sudo lsmod | grep "hello"

That's the end of this post folks!!
Sayonara :3