Linux Kernel Programming – Part 1

Reading Time: 3 minutes
I’m going to start with some hands on code rather than get into details first. The reason being, it’ll be easier to absorb details once you’ve seen it in action.

First Kernel Module

Most distributions would come with kernel development packages. You should install them before proceeding further.

Some distributions may not provide kernel sources with kernel development package and you might’ve to install a kernel-source package for your distribution. However we’ll download kernel sources later on and install that.

Hello World

Linux kernel has the capability of being extended in the form of loadable modules. This is similar to third part plugins, which follow a strict contract of apis to be  exported or used, and can be installed independently extending the functionality of software.

The trouble with Linux kernel is that it’s responsible for making sure everything runs smoothly, hence any misbehaved module may compromise stability of the whole system. These extensions are called LKM (Linux Kernel Module) which can be loaded or unloaded dynamically without requiring a kernel re-build every time we want to extend Kernel’s functionality.

#include <linux/module.h>

static int __init load_module(void)
{
        struct module *__this_mod = THIS_MODULE;

        pr_debug("Loading module name %s\n", __this_mod->name);
        return 0; /*Extremely important!*/
}

static void __exit unload_module(void)
{
        struct module *__this_mod = THIS_MODULE;

        pr_debug("UnLoading module name %s\n", __this_mod->name);
}

module_init(load_module);
module_exit(unload_module);
 

Building the module

Building a kernel module is a bit different from building a regular C/C++ program. The following Makefile can do this for you. Make sure to place it in the same directory as the above source.

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

Couple of points,

  1. If you copy and paste the above, make sure you’ve correct tabs for all the targets
  2. You’ve installed kernel development package for your distribution

At this time all we’re doing is compiling the hello world source code for the kernel that’s currently running. The KDIR variable can be passed in to make if you wish to build this module for a kernel which is not the current one running.

Kbuild file

You’ll also require a file called Kbuild to be placed alongside this Makefile and source code. Kbuild file contains which source files you need to compile, what should be name of the final deliverable and if there are any compilation flags (viz #defines etc) which are required to build the module. The following is the Kbuild file for the Hello world module

obj-m := hello_world_mod.o
hello_world_mod-objs := hello_world_module.o 

Final Deliverable(s)

What the above Kbuild file says is that

  1. we want to build a kernel module hello_world_mod
  2. That module comprises of object file(s) hello_world_module.o

NOTE: You can name the module anything obj-m however you’ve to provide which files (object files) makeup that module. 

Loading the kernel module

You can load the module using the following command

insmod hello_world_mod.ko

Obviously you’ve to be root user in order to do that since you’re going to extend kernel functionality and not everyone can be allowed to do this. So if all was well you won’t see any output or you might see a warning that this module taints kernel.

Where's the output?

The output of the above module can be seen using dmesg and it will appear something like,

[ 3126.781550] hello_world_mod: module verification failed: signature and/or required key missing - tainting kernel
[ 3126.781791] Loading module name hello_world_mod 

So you can see the line Loading module name is coming from our code. Apart from spitting out this line, the module doesn’t do anything else. Usually kernel modules are written for device drivers so they respond to changes communicated by a device.

We’ll try to control a fake device eventually after we’ve learned some more concepts about kernel programming and what can / can’t be done within kernel.

Unloading the module

A module can be removed, and hence memory occupied by it can be freed, if it’s no longer required. You can use the following command in order to remove module

# rmmod hello_world_mod

Again you can see the output using dmesg and you should see the following line at the every end of that output.

[ 4348.117337] UnLoading module name hello_world_mod 

The above is again coming from our code. Thus you can see that kernel is calling our functions which we specified for initialisation and exit time automatically when we load or remove the module. More about what these are will be discussed in Part 2.

Grab the Linux kernel source

You can download the kernel source code from https://www.kernel.org just try to download a stable version. If you download very latest stable and are using quite an old distribution as a workstation, chances are it won’t compile and would complain of an older compiler version.

So make sure you have your compiler to at least the version where you can compile your kernel source. You can either 

  • Choose to download tarball.
  • Use git to clone the kernel repository.

A tarball would give you quick start time while if you wish to upload changes back to kernel then you’ll require to clone it. Cloning might take a lot of time depending on your internet speed.

Leave a Reply