Skip to content

Linux kernel programming using loadable kernel modules (LKMs)

License

Notifications You must be signed in to change notification settings

tleonhardt/linux_lkm

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

12 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Linux Kernel Programming

This repository contains a basic introduction to Linux kernel programming. It focuses on using an embedded device such as a Raspberry Pi, but a Linux VM can also be used.

A few simple example Loadable Kernel Modules (LKMs) are presented for learning purposes.

The first example is a straightforward "Hello World" module that can be used to make sure your setup for LKM development is working.

Intro

A loadable kernel module (or LKM) is an object file that contains code to extend the running kernel, or so-called base kernel, of an operating system. LKMs are typically used to add support for new hardware (as device drivers) and/or filesystems, or for adding system calls. When the functionality provided by a LKM is no longer required, it can be unloaded in order to free memory and other resources.

Without this modular capability of extending the kernel at run time, the Linux kernel would be huge because it would need to support every driver in existence out of the box.

Even though LKMs are loaded at run time, they are executed in kernel space and not in user space. The OS treats the memory available in kernel space as completely separate from the memory available in user space. User space applications can access kernel services in a controlled way by making system calls via the Linux C library.

Kernel modules are written in the C programming language, but they are a lot different from normal user-space C programs. Some of the key differences include:

  • LKMs do not have a main() function
  • LKMs do not execute sequentially. Similar to event-driven programming
  • Any resources that are allocated to the module must be manually released when the module is unloaded (no automatic cleanup)
  • Do not have printf() and similar functions. Though there is a printk()
  • LKMs must have a consistent and valid behavior when they are interrupted
  • LKMs have a higher level of execution privilege
  • LKMs do not have floating-point support

It is very easy to crash the OS when you are writing and testing LKMs. It is possible that you you can crash it in a way that could corrupt your file system and make it unbootable. I strongly recommend you use one of two basic setups for learning kernel development:

  1. Use a Linux virtual machine (VM) that you have taken a snapshot of
  • That way you can revert to the snapshot if it gets hosed
  1. Use an embedded Linux system which boots of an SD card such as a Raspberry Pi
  • Then if unbootable you can put the SD card in a card reader and fix the file system

Why Write LKMs

Performance

With a stock Linux kernel and typical minimalist user-space configuration, pure user-space code may be able to reliably service an external event with a response time on the order of one eighth to one quarter of a millisecond (0.125 ms to 0.25 ms).

However, a stock Linux kernel can typically reliably service an interrupt-driven Kernel module with a response time of about 25 microseconds (25 us = 0.025ms), or 5 to 10 times faster than user space. This is for a stock Linux kernel, there are special real-time variants of Linux that can do significantly better.

But usually if you need better hard real-time performance than this, you should use a real-time co-processor of some sort (microcontroller, DSP, FPGA, etc.) that is running bare-metal with no OS.

Access to hardware

To access hardware, you need some sort of kernel-mode driver, typically in the form of a LKM. For all of your standard hardware, drivers exist. But if you are manufacturing custom hardware, someone will need to write a driver.

Security applications

Certain types of security-related code need to run in kernel space. Things like rootkits, firewalls, and anti-virus products all need at least a kernel-mode component.

Prerequisites

In order to build LKMs, the Linux kernel headers need to be installed on your build machine. The Linux kernel headers are C header files that define the interfaces between the different kernel modules, the kernel, and user space. The header files present must be the exact same version as the kernel for which you want to build a module.

Installing the Linux Kernel headers

On a Debian, Ubuntu, or Mint Linux OS, you can install the kernel headers like so:

sudo apt install linux-headers-$(uname -r)

This should install the headers in /lib/modules/$(uname -r)/build/ which should likely be a symbolic link to the location /usr/src/linux/$(uname -r)/.

Building the LKM

Once the Linux kernel headers are in place, you can build the hello_world LKM using the Makefile by typing make:

cd hello_world
make

This creates the LKM with the name hello_world.ko. Note that this LKM can only be executed on a machine running the exact same kernel version.

Testing the LKM

The "Hello World" LKM can be tested by loading it into the kernel. This requires superuser permission. The LKM can be loading using the insmod program to insert a module into the Linux kernel:

cd hello_world
sudo insmod hello_world.ko

You can list loaded kernel modules with the lsmod command:

lsmod | grep hello

You can get information about a LKM file using the modinfo command, which identifies the description, author, and any module parameters that are defined by the LKM souce code:

/sbin/modinfo hello_world.ko

The module can be removed from the kernel using the rmmod program:

sudo rmmod hello_world

You can view the output live in the kernel log as a result of the use of the printk() function. I recommend that you use a second terminal window and view the live output as your LKM is loaded and unloaded, as follows:

sudo tail -f /var/log/kern.log

Testing the LKM Parameter

The hello_world.ko LKM contains a custom paramter that can be set when the module is being loaded, for example:

sudo insmod hello_world.ko name=Todd

If you view /var/log/kern.log at this point, the message "Hello Todd" appears in place of "Hello World".

You can also see information about the kernel module that is loaded within the /proc virtual files system:

ct /proc/modules | grep hello

This is the same info as provided by the lsmod command, but it also provides the current kernel memory offset for the loaded module, which is useful for debugging.

The /sys virtual file system provides you with direct access to the custom parameter state as well as other info such as version, whehter it is tainted or not, etc.:

pushd /sys/module/hello_world
cat version
cat taint
cd parameters
cat name
popd

It is important that you leave any virtual filesystem directory associated with the LKM before you unload it, otherwise you can cause a kernel panic with something as simple as a call to ls.

Attribution

Much of the material here comes from the excellent book Exploring Raspberry PI by Derek Molloy. If you want to learn more, I recommend you use that book as a reference to get started. Chapter 16 covers Kernel Programming.

A more detailed book specific to Linux kernel programming is Linux Kernel Development, 3rd Ed by Robert Love.

About

Linux kernel programming using loadable kernel modules (LKMs)

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published