Linux Kernel Modules

I’m reading the book Linux Device Drivers to get up to speed on writing Linux modules; I’ll be using this for an upcoming project, if all goes according to plan.  This isn’t much, but if you need to get the most basic of kernel modules built, this is what you need to do.

Linux Device Drivers can be implemented in User Mode or Kernel Mode.  We’re only going to be concerned with Kernel Mode Device Drivers.  This are implemented in the form of Kernel Modules. What is presented here is a very, very simple Hello World kernel module.

I’m doing all of this on a 2.6.17 kernel.

The following source code is from page 16 of Linux Device Drivers:

#include <linux/init.h>
#include <linux/module.h>
MODULE_LICENSE(“Dual BSD/GPL”);

static int hello_init(void)
{
printk(KERN_ALERT “Hello, world\n”);
return 0;
}

static void hello_exit(void)
{
printk(KERN_ALERT “Goodbye, cruel world\n”);
}

module_init(hello_init);
module_exit(hello_exit);

Save this to a file named hello_world.c.

The two include directives are needed in every Linux kernel module.

The MODULE_LICENSE macro defines what license applies to this particular module.  There are a couple of different possible values; “Dual BSD/GPL” is probably the preferred.  Another possibility is “Propietery.  If a module is loaded with this type of license, then the kernel is considered to be tainted–I didn’t know exactly what that meant until I read it in this book.

Two functions are defined in this Kernel Module: hello_init() and hello_exit().  When hello_init() is called, it prints the message “Hello World” to /var/log/messages and the Console (depending on how your system is configured)–a default Fedora Core install will behave this way.  Though, you’ll probably only see console messages, if your running in Run Level 3.  When hello_exit() is called, it prints the message “Goodbye, cruel world\n”–the conditions under which this string will be printed are identical to the first.

The last two lines register the functions as what should be called during module load and during module unload, respectively.

The following makefile is needed to compile kernel modules.  I got this makefile from here.

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

Save this to a file called Makefile in the same directory where hello_world.c is located.

In the same directory where the hello_world.c file and Makefile are located, type make.

You’ll see something like the following:

[root@taz hello_world]# make
make -C /lib/modules/2.6.17/build M=/home/broeckel/module/hello_world modules
make[1]: Entering directory `/home/broeckel/linux/linux-2.6.17′
CC [M]  /home/broeckel/module/hello_world/hello_world.o
Building modules, stage 2.
MODPOST
CC      /home/broeckel/module/hello_world/hello_world.mod.o
LD [M]  /home/broeckel/module/hello_world/hello_world.ko
make[1]: Leaving directory `/home/broeckel/linux/linux-2.6.17′

This will produce the following files:

rw——-  1 root     root     71847 Sep 17 23:50 hello_world.ko
-rw——-  1 root     root       660 Sep 17 23:50 hello_world.mod.c
-rw——-  1 root     root     40796 Sep 17 23:50 hello_world.mod.o
-rw——-  1 root     root     31864 Sep 17 23:50 hello_world.o
-rw-rw-r–  1 root   root     0 Sep 17 22:14 Modules.symvers

The hello_world.ko file is the Kernel Module that will actually be loaded into the Linux Kernel.

As root, run the following command: insmod ./hello_world.ko

You’ll see something similar to the following in /var/log/messages:

Sep 17 22:26:28 taz kernel: Goodbye, cruel world

This is from running the hello_init function.

To see that the hello_world kernel module is loaded in the kernel, run the following command:

[root@taz hello_world]# lsmod | grep hello_world
hello_world             5632  0

As root, run the following command: rmmod hello_world

This will unload the kernel module.  The following will be printed to /var/log/messages:

Sep 17 22:28:11 taz kernel: Hello, world