# Linux Kernel Development - Part 1: Hello Kernel!

June 2, 2019

Our very first program in every language or framework usually is the notorious "Hello World" program. For this Linux Kernel Modules Development introduction we will follow the same concept, but instead of the usual "Hello World" we will make a "Hello Kernel!" and you will understand the reason in a few moments. Note that in this article I will not focus on a deep explanation about this topic for the moment, since this is only the introduction.

But before we dive into code we need to have the minimum understand what is a Kernel Module and where it runs.

### Kernel Module and Kernel Space

A Kernel Module is a program or piece of code, usually written in C, that can be loaded or unloaded dynamically in the linux kernel. You can also built-in the module into the linux kernel, in this way it's not possible to dynamically load and unload.

The linux kernel modules runs in a space called Kernel Space, where the kernel runs and provides its services. That means that you should not use some "userland" headers and functions in you code. But don't worry about it, the kernel has most functions that you normally use in C translated to Kernel Space, usually they have the same name but beginning with a "k". For an example, instead of using printf() you will use kprintf().

### Your very first Kernel Module

Here is the code of our first kernel module.

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

/*
* Init function of our module
*/
static int __init hellokernelmod_init(void)
{
printk(KERN_INFO "Hello Kernel!\n");
return 0;
}

/*
* Exit function of our module.
*/
static void __exit hellokernelmod_exit(void)
{
printk(KERN_INFO "Hasta la vista, Kernel!\n");
}

MODULE_DESCRIPTION("Simple Kernel Module to display messages on init and exit.");

module_init(hellokernelmod_init);
module_exit(hellokernelmod_exit);

OK, let's see what is going on there.
First, we need to include the necessary headers for our module to work.

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

In our case we need kernel.h for the kernel functions (printk) and module.h for the module functions (init, exit..), every module needs this header.

Then, we have 2 functions:

static int __init hellokernelmod_init(void)
{
printk(KERN_INFO "Hello Kernel!\n");
return 0;
}

This function will execute when we load the module into the kernel. This is called the "init" function of the module, it needs to return 0 on success. Usually you alloc the memory you need and do the initialization of you module here.
The __init parameters tells the kernel to free the space of this function after the initialization. This only works for built-in kernel modules.

static void __exit hellokernelmod_exit(void)
{
printk(KERN_INFO "Hasta la vista, Kernel!\n");
}

This function will execute when we unload the module from the kernel. This is called the "exit" or "cleanup" function of the module, basically everything you did in the init function you need to "undo" here, like freeing memory space, closing sockets, finishing devices, etc.

The __exit parameter tells the kernel to omit this function when the module is built-in, since in built in modules this functions would never execute.

MODULE_AUTHOR("Your name here");
MODULE_DESCRIPTION("Simple Kernel Module to display messages on init and exit.");
MODULE_LICENSE("MIT");

The Modules API has some macros that helps to define your module, like describing its functionalities, naming the author, license, parameters and so on. That is what we are doing with these MODULE_* macros.

You can see those information with

$modinfo <PATH-TO>/hellokernel.ko. module_init(hellokernelmod_init); module_exit(hellokernelmod_exit); Here we are actually registering our functions to be executed in the beginning and in the exit of the module. Now we need to compile and run our code. If you try to compile this module with $ gcc hellokernel.c, you are going to have a bad time.

We need to proper build our kernel module, this Makefile should do the trick for us.

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

First we need to say what we are building. Note that the *.o needs to match your module .c file.

The "all" argument will build the module for us. The "-C" option following by the path to the build directory of the $(shell uname -r) (A.K.A. your kernel version) is going to make the "make" change the folder to the folder specified and reach it's top Makefile. The "M=" is saying to the "make" command where the compiled binaries should be copied after the compilation. And, finally, we are saying that we want to compile a kernel module with the "modules" argument. The "clean" is going to remove all compiled binaries of our destination folder. Now a simple $ make all command should proper compile our module.

The compilation generates a bunch of files, but we are going to focus on the .ko file generated, that's our kernel module.

To install-it, use the insmod tool. Only super users can load and unload kernel modules.

$sudo insmod <path-to>/hellokernel.ko To see if the kernel was load successfully use the lsmod tool, this tool will list all kernel modules loaded in your system. $ lsmod

Now, if you look into the kernel log you should see the glorious message "Hello Kernel!".

You can do this with the dmesg tool.

$dmesg To unload the kernel module, use the rmmod tool. $ sudo rmmod hellokernel

Again, use the dmesg tool to see our cleanup message "Hasta la vista, kernel!".

Congratulations, you just did your first (I think, so) kernel module.

In the next articles we will dive deep in the in this world of kernel modules and maybe do a LED driver, because there is anything more exciting than make a LED blink!

Happy coding :)

To post reply to a comment, click on the 'reply' button attached to each comment. To post a new comment (not a reply to a comment) check out the 'Write a Comment' tab at the top of the comments.