Basic Framework of Linux Kernel Modules

The writing of Linux kernel modules intimidates many people, but it is actually not that difficult or complicated. Here’s a basic framework to help those with a little knowledge get started quickly.
1. Basic Framework (Before Kernel 2.3.13)
#include<linux/kernel.h>
#include<linux/module.h>

int init_module(void){
	pr_info("hello module.\n");
	return 0;
}

void cleanup_module(void){
	pr_info("hello end.\n");
}

MODULE_LICENSE("GPL");
#include<linux/module.h>

int init_module(void){
	pr_info("hello module.\n");
	return 0;
}

void cleanup_module(void){
	pr_info("hello end.\n");
}

MODULE_LICENSE("GPL");

Makefile:

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

Then, execute make.

Check the basic output:

Basic Framework of Linux Kernel Modules

2. Basic Framework (After Kernel 2.3.13)

In fact, starting from kernel 2.3.13, things have changed. You can now use any name you like for the module’s start and end functions. In fact, the new method is preferred. However, many still use init_module() and cleanup_module() as their start and end functions.

Create a new file hello2.c in the previous directory.

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

static int __init hello2_init(void){
	pr_info("hello2 .\n");
	return 0;
}

static void __exit hello2_exit(void){

	pr_info("hello2 bye.\n");
}

module_init(hello2_init);
module_exit(hello2_exit);

MODULE_LICENSE("GPL");

Using the new syntax, with custom init and exit functions. Also includes the new header file <linux/init.h>.

The Makefile only needs to change hello.o to hello2.o, execute and check the effect:

Basic Framework of Linux Kernel Modules

3. Passing Command Line Parameters to Modules

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

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Peter Jay Salzman");

static short int myshort = 1;
static int myint = 420;
static long int mylong = 9999;
static char *mystring = "blah";

/*
 * module_param(foo, int, 0000)
 * The first param is the parameters name
 * The second param is its data type
 * The final argument is the permissions bits,
 * for exposing parameters in sysfs (if non-zero) at a later stage.
 */

module_param(myshort, short, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
MODULE_PARM_DESC(myshort, "A short integer");
module_param(myint, int, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
MODULE_PARM_DESC(myint, "An integer");
module_param(mylong, long, S_IRUSR);
MODULE_PARM_DESC(mylong, "A long integer");
module_param(mystring, charp, 0000);
MODULE_PARM_DESC(mystring, "A character string");

static int __init hello_5_init(void)
{
        printk(KERN_ALERT "Hello, world 5\n=============%s\n", mystring);
        printk(KERN_ALERT "myshort is a short integer: %hd\n", myshort);
        printk(KERN_ALERT "myint is an integer: %d\n", myint);
        printk(KERN_ALERT "mylong is a long integer: %ld\n", mylong);
        printk(KERN_ALERT "mystring is a string: %s\n", mystring);
        return 0;
}

static void __exit hello_5_exit(void)
{
        printk(KERN_ALERT "Goodbye, world 5\n");
}

module_init(hello_5_init);
module_exit(hello_5_exit);

Input: insmod hello-5.o mystring="bebop" mybyte=255 myintArray=-1

The above example looks a bit messy, here’s a simplified version:

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

MODULE_LICENSE("GPL");
MODULE_AUTHOR("FTANG");

static int myint = 100;
module_param(myint, int, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);

static int __init hello_param_init(void){
	pr_info("hello param.\n");
	pr_info("myint value is : %d\n", myint);
	return 0;
}

static void __exit hello_param_exit(void){
	pr_info("param exit.\n");
}

module_init(hello_param_init);
module_exit(hello_param_exit);

Here’s the output result:

Basic Framework of Linux Kernel Modules

4. Modules Across Multiple Files

Next, let’s enter the writing of kernel modules across multiple files, which is actually quite simple.

Assuming divided into two parts: start.c and stop.c, the writing is as follows:

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

int init_module(void){
	pr_info("hello, this is starting part.\n");
	return 0;
}

MODULE_LICENSE("GPL");
// stop.c
#include<linux/kernel.h>
#include<linux/module.h>

void cleanup_module(){
	pr_info("this is the end part.\n");
}

MODULE_LICENSE("GPL");

The writing looks quite similar, just that the previous example is separated.

Then the Makefile has a slight change:

obj-m += startstop.o
startstop-objs := start.o stop.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

At this point, it’s a simple multi-file writing method.

Summary: This article outlines various writing methods for Linux kernel modules, without delving deeply into kernel-related knowledge, but provides a validated framework to help everyone take the first step. I hope it is helpful.

Leave a Comment