8 minute read

Get started with Kernel Module Programming

Get Started with Kernel

Module Programming

Advertisement

Kernel module programming helps create drivers that are missing in the current kernel's list. This article takes readers through the basics of creating a kernel module, navigating through the output, loading and removing a module. Knowledge of 'C' language (most of the kernel code is in C) and the GNU C extensions is required.

Iuse the 10.04 32-bit desktop edition, with kernel 2.6.34.12. New distros carry the kernel 3.x series. There is a very slight difference between the architecture of 2.x and 3.x series, so what I discuss in this article will work on both. The source code for this article can be downloaded from http://www.linuxforu.com/article source_code/oct12/ kernel module.zip

So let's get started with the traditional ‘hello world’ module; the filename is hello.c.

#include<linux/init.h> #1 #include<linux/module.h> #2

MODULE_LICENSE(“GPL”); #3

static int hello_init(void){ #4 printk(KERN_ALERT "Hello world"); #5 return 0; } static void hello_exit(void) { #6 printk(KERN_ALERT "GoodBye"); } module_init(hello_init); #7 module_exit(hello_exit); #8

Note: Most libraries are in the include folder of the kernel root directory. In module programming as well as in core kernel programming, <linux/headerfile> is short for /root kernel directory/include/linux/ headerfile. So you can easily say that include is the base directory for simple libraries. For architecturerelated libraries, arch is the base directory.

Now let me explain the code, line by line. 1. init.h is included because it will get executed as soon as you load the module in the kernel space. It is mandatory to include this header file in almost every program. 2. All the module functions and recognisers are present in

Figure 1: Build, load, remove and verify output

the module.h header file. It is also mandatory if you are writing a module for the kernel. 3. MODULE_LICENSE() will specify the licence type under which this module is written. Get into a habit of writing it, otherwise you will unnecessary ‘taint’ warnings in the kernel log. I have used the GPL. 4. A static int function is created to execute on loading of the module. This function is also known as an initialise function. It must not be of the void type because the function must return false if initialisation failed. 5. There is no printf() in kernel programming; whereas here, there is printk(), which copies the formatted string into the kernel log buffer, which is normally read by the syslog program. It works similar to printf(); the only difference is that printk() enables us to specify a priority flag that is used by syslogd to decide where to display kernel messages. In the line, KERN_ALERT, is the flag.

KERN_ERR, KERN_WARNING etc, are some other flags. It also works well without the flags. 6. Like the initialise function, you made a function which will be executed when you remove the module from the kernel space. The function usually has a void return type. 7. The module_init(function name) call will tell the kernel which function to execute on the module’s initialisation. 8. The module_exit(function name) call will tell the kernel which function to execute on module removal.

Makefile

obj-m += hello.o #1

all: make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules #2

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

Let’s compile the above module using a Makefile with the above code, which should be in the same folder as hello.c; otherwise, you need to specify an absolute path to the file. obj-m is a list of what kernel modules to build. The .o and other objects will be automatically built from the corresponding .c file (no need to list the source files explicitly). So just give the name of your program file against obj-m (without the .c extension).

Describing the base build path

It will compile and build your module with respect to the mentioned path. Please note that the above path is generic for most Linux distributions. It will act as a base for the module build.

Compile, load and remove

Compile the module using make. A lot of files will be generated, such as hello.ko, hello.mod.o, hello.o, etc. Load the module into kernel space using the insmod utility, and you must need root permissions to do that. So run sudo insmod hello.ko in the terminal. Your module gets loaded. To check the output of the module, since printk() doesn't write to the console (though this can be done by a kernel hack), check the kernel log with the dmesg command. Run it and you will see ‘Hello World’ in the output.

Now let’s remove the module from the kernel space using sudo rmmod hello.ko in the terminal. Verify this using dmesg again; you will see GoodBye printed at the end of the syslog stack. See the screen-shot (Figure 1).

Note: You can't load a module twice successively. If you have just loaded a module, and you want to load it again, you need to unload it first; else you will get a console error message.

Passing parameters

If you want to pass a single or a series of parameters along with the module itself, which is quite useful when your module depends on other modules' output, follow the steps shown below.

Passing a single parameter

Module filename: parameter.c

#include<linux/init.h> #include<linux/module.h> #include<linux/moduleparam.h> #1

MODULE_LICENSE("GPL");

int paramTest; module_param(paramTest, int, S_IRUSR|S_IWUSR); #2

static int param_init(void) { printk(KERN_ALERT "Showing the parameter Demo"); printk(KERN_ALERT "Value of paramTest is: %d", paramTest); #3 return 0; }

static void param_exit(void) { printk(KERN_ALERT "Exiting the parameter demo"); }

module_init(param_init); module_exit(param_exit);

Here’s an explanation of the code that's different from the Hello World module: 1. All module parameter-related functions are in the moduleparam header file. 2. Here, module_param(parameter name, data type, permission) is used to tell the kernel the name of the parameter, its variable data type, and the permissions for it. Permissions are generally of five types: S_

IWUSR, S_IRUSR, S_IXUSR, S_IRGRP, and S_IWGRP.

S_I is a common prefix; R corresponds to read, W to write and X to execute. USR means the user, and GRP, the group. Permission in module_param can be a single permission or multiple ones using the | OR operator in between, as shown in the code.

Displaying the value of the parameter in the initialise function

Change hello.o to parameter.o in the Makefile; compile using make. Pass the parameter to the module during its insertion into the kernel space. Run sudo insmod parameter.ko paramTest=2. Please note that the name is case-sensitive. After inserting, check the kernel log. You will see the output ‘Value of paramTest is:2’. If you don't specify a value for the parameter during insertion, it will take the data type's default value—0 for int. See Figure 2.

Passing a series of parameters

You can pass more than one parameter to the module using the concept of the arrays. Here's the code (parameterArray.c):

#include<linux/init.h> #include<linux/module.h> #include<linux/moduleparam.h>

MODULE_LICENSE("GPL");

int paramArray[3]; #1 module_param_array(paramArray, int, NULL, S_IWUSR|S_IRUSR); #2

static int array_init(void) { printk("Into the Parameter Array Demo"); printk("Array Elements are: %d\t%d\t%d", paramArray[0], paramArray[1], paramArray[2]); return 0; }

static void array_exit(void) { printk("Exiting the Array Parameter Demo"); module_init(array_init); module_exit(array_exit);

Figure 2: Passing a single parameter with module

Figure 3: Retrieving process information

1. Declaring an int array of size 3. 2. To make the array variable act as parameters, use the module_param_array() function instead of module_ param(). Arguments to the function are the variable name, data type, counter and permissions, respectively.

What is a counter? It is used to track the number of parameters passed to the module. In your option, you could also ignore the count and pass NULL as I did.

Compile the module. To insert, run sudo insmod parameterArray.ko paramArray=1,2,3. To verify, check the kernel log and you will see paramArray values as 1,2,3. If parameters are missing, the kernel again takes the default value of the data type, 0 for int.

Playing with processes

Each process in Linux has certain properties associated with it, such as process ID, runnable state, flags, etc, in a structure present in the sched.h header file in / include/linux. The structure is named 'task_struct'. You can retrieve lots of real-time information by accessing this structure; all you need is to create a pointer to the structure, and then start using it.

I want to retrieve the process ID, process name and its state in a real-time environment; here's the code (process.c):

#include<linux/init.h> #include<linux/module.h> #include<linux/sched.h>

MODULE_LICENSE("GPL");

static int test_init(void) { struct task_struct *task; #1 for_each_process(task) { #2 printk("Process Name: %s\t PID:%d\t Process State:%ld\n", task->comm, task->pid, task->state); #3 }

return 0; }

static void test_exit(void) { printk(KERN_INFO "Cleaning Up.\n"); }

module_init(test_init); module_exit(test_exit);

Explanations: 1. A pointer named task was created to the structure task_struct. 2. You iterate over the processes handled by the kernel (whether they are in executing or waiting state). 3. You access the structure through the pointer and display its properties.

Make the necessary changes in the old Makefile, compile, and insert it. You should see something like what’s shown in Figure 3. You will see process names along with their process IDs and the process state (integer value; and Google for what those values mean). There are over 50 properties associated with processes defined in that structure. So take a reading at the beautifully documented structure and start playing with processes.

Linux kernel module programming is the best thing I have come across so far. I am learning it in depth, and will share my experiences in the future too. A large number of e-books are also available online. The power of Google is tremendous. So explore them. Queries and suggestions are always welcome.

Ankur Aggarwal

The author loves to explore open source technologies and enjoys programming. He has learned Python, PHP, C and C++. He loves rock and metal music, and plays the guitar too. He runs a blog related to Linux at www.flossstuff.wordpress.com and can be contacted via ankur.aggarwal2390@gmail.com or on Twitter as @ankurtwi.

This article is from: