What is and how to create a Linux Kernel Module

Introduction

This article is a basic explanation of what is and how to create a Linux kernel module.

The Linux Kernel

As we know the Linux kernel is an open-source, monolithic, soft preemptive UNIX like operating system partially compatible with POSIX specification. The Linux kernel is widely used in specific and general purpose applications.

The Monolithic Kernel

Wolfgang Mauerer (2016)1, in his book Professional Linux Kernel Architecture, says that a monolithic kernel is on that:

[…] each function has access to all other parts of the kernel; […]

Chandra Mohan (1997)2, in his book Operating Systems, defines a monolithic kernel as an unpartitioned operating system:

[…] They are a collection of procedures. Any procedure can call for some help in its computation to any other procedure whenever the need arises. […]

Personally, I define a monolithic kernel as an operating system that has two basic characteristics:

  1. All procedures run in the same address space;
  2. All direct software interface to the hardware and its filesystems are procedures of the kernel;

The characteristic of being monolithic states that, to add new functionality at runtime, the systems should be able to load plugins at runtime.

The Linux Kernel supports loading and executing binaries at runtime, this is what we call Kernel Modules.

To load modules at runtime in the same address space, the Linux Kernel uses a dynamically loadable kernel object file with ``.ko” extension.

An example in C of the monolithic characteristic

Imagine two procedures. In this case, I am going to explain using C code.

proc_a.ko

static int a = 0;

void proc_a() {
    // ... do something with a
}

proc_b.ko

extern int a;

void proc_b() {
    // ... do something with a
}

all the memory is shared between both procedures. That is, a global variable to both contexts is going to be visible by both procedures, even if the procedures run in different threads. As in a single process, access control to the memory is necessary to work safely in the kernel space. That is, evenly if both procedures belong to different objects, the address of the variable a relatively to proc_a is going to be the same as the address of a relative to proc_b.

Kernel Module In Practice

If you just want a makefile to your project jump to the next session.

Kernel modules can be written in C programming language and basically have an entry function and a cleanup function.

The init_module() function is the entry point and it is called when the module is loaded. The cleanup_module() function is the cleanup function and it is called when the module is unloaded.

#include <linux/module.h>    /* Needed by all modules */
#include <linux/kernel.h>    /* Needed for KERN_INFO */

int init_module(void)
{
    printk(KERN_INFO "Example Module Initialized\n");
    return 0;
}

void cleanup_module(void)
{
    printk(KERN_INFO "Example Module Cleaned\n");
}

To every type of hardware, there is a specific Linux kernel API to use in order to create an interface between the real hardware and a kernel software interface to the userspace. The Linux kernel uses its filesystem as an interface to the hardware. Every procedure, every parameter is abstracted in a file read or write operation in a file on its filesystem structure.

The /dev, /proc and /sys directories of the filesystem group this interfaces in the directory tree.

By example, the actual video stream can be read in /dev/videoX file. Serial terminal devices can be open as a file in /dev/ttySX. The same methodology is used in complex modules in the case of /dev/nvidiaX which is related to Nvidia graphics.

This makes programming Linux kernel modules an easy and comprehensible task to who is used to build programs in C programming language.

A Kernel Module Example

To make the process easier, I’ve created a repository as an entry point to a kernel module project. and it is available at http://git.afarias.org/arthur/kernel-module-example.

The kernel source is available at src/kernel-module-example-base.c the kernel module can be built by issuing following command make. It can be installed by issuing sudo make modules_install && sudo depmod command.

The module can be loaded by issuing modprobe kernel-module-example and can be removed by modprobe -rf kernel-module-example.

comments powered by Disqus