Dieser Artikel ist älter als zwei Jahre und womöglich veraltet!

Linux-Kernelmodule - Teil 1

Auch wenn es sich bei Linux um ein monolithisches Betriebssystem handelt, sind viele Teile davon in Modulen aufgebaut. Diese Kernelmodule können zur Laufzeit geladen und auch wieder entladen werden. Wie man so ein Modul entwickelt und zum Laufen bringt möchte ich hier kurz zeigen.

C-Code

Linux wird in C entwickelt und darum werden auch Kernel-Module in C geschrieben. Sie bestehen im Grunde aus zwei Funktionen: Eine, die beim Laden ausgeführt wird und eine, die beim Entladen ausgeführt wird.

Beginnen wir mit einem einfachen Hello-World-Beispiel:

Zuerst brauchen wir eine Bibliothek, die wir brauchen um ein Modul laden zu können:

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

Die Header-Datei module.h wird von jedem Modul benötigt und die Datei init.h stellt Makros zur Verfügung, die wir brauchen um die Funktionen zu registrieren, was wir jetzt auch machen:

 1#include <linux/module.h>
 2#include <linux/init.h>
 3
 4// Methode, die beim Laden ausgeführt wird
 5static int __init hello_init(void)
 6{
 7	return 0;
 8}
 9
10// Methode, die beim Entladen ausgeführt wird
11static void __exit hello_exit(void)
12{
13}
14
15// Registrieren der Methoden
16module_init(hello_init);
17module_exit(hello_exit);

An dieser Stellen wurden zwei Funktionen eingebaut, die jeweils entweder beim Laden oder Entladen ausgeführt werden. Mit module_init und module_exit wird dem Betriebssystem mitgeteilt, welche es sind.

Das alles sieht zwar nett aus, tut aber noch nichts. Darum soll das Modul das berühmte “Hello world” ins syslog schreiben:

 1#include <linux/module.h>
 2#include <linux/init.h>
 3#include <linux/kernel.h>
 4
 5// Methode, die beim Laden ausgeführt wird
 6static int __init hello_init(void)
 7{
 8	printk(KERN_DEBUG  "Hello World!");
 9	return 0;
10}
11
12// Methode, die beim Entladen ausgeführt wird
13static void __exit hello_exit(void)
14{
15	printk(KERN_DEBUG  "Bye World!");
16}
17
18// Registrieren der Methoden
19module_init(hello_init);
20module_exit(hello_exit);

Mit printk(<loglevel>,<text>) lässt sich das bewerkstelligen. Um das Loglevel angeben zu können, benötigen wir aber noch zusätzlich die Datei kernel.h.

Wenn man das Module so ausführt wird Linux übrigens sofort über die fehlende Lizenzangabe jammern. An dieser Stelle sollte man aber auch gleich noch Informationen über den Autor angeben:

 1#include <linux/module.h>
 2#include <linux/init.h>
 3#include <linux/kernel.h>
 4
 5#define DRIVER_AUTHOR "Johannes Mittendorfer <...@... .com>"
 6#define DRIVER_DESC "Hello world"
 7
 8// Methode, die beim Laden ausgeführt wird
 9static int __init hello_init(void)
10{
11	printk(KERN_DEBUG  "Hello World!");
12	return 0;
13}
14
15// Methode, die beim Entladen ausgeführt wird
16static void __exit hello_exit(void)
17{
18	printk(KERN_DEBUG  "Bye World!");
19}
20
21// Registrieren der Methoden
22module_init(hello_init);
23module_exit(hello_exit);
24
25MODULE_LICENSE("GPL");
26MODULE_AUTHOR(DRIVER_AUTHOR);
27MODULE_DESCRIPTION(DRIVER_DESC);

In diesem Beispiel habe ich den Autor und den Titel oben definiert und unterhalb samt Lizenz, in diesem Fall GPL, angegeben.

Jetzt kann man das Modul ausführen. Aber wie eigentlich? Dazu braucht man ein…

Makefile

Das Makefile gibt an, wie der Code kompiliert werden soll. Alles was man dazu braucht ist eine Datei namens Makefile mit folgendem Inhalt:

1obj-m += helloworld.o

Wenn man jetzt im Verzeichnis make ausführt, dann sollte in etwa so etwas erscheinen:

1make -C /lib/modules/3.11.0-19-generic/build M=/home/johannes/Schreibtisch/kernel modules
2make[1]: Betrete Verzeichnis '/usr/src/linux-headers-3.11.0-19-generic'
3  CC [M]  /home/johannes/Schreibtisch/kernel/helloworld.o
4  Building modules, stage 2.
5  MODPOST 1 modules
6  CC      /home/johannes/Schreibtisch/kernel/helloworld.mod.o
7  LD [M]  /home/johannes/Schreibtisch/kernel/helloworld.ko
8make[1]: Verlasse Verzeichnis '/usr/src/linux-headers-3.11.0-19-generic'

Außerdem sollte im Verzeichnis eine Datei namens helloworld.ko entstanden sein. Das ist das fertige Modul. Das muss aber jetzt noch an einen vorgesehenen Platz.

Installation

Die ko-Datei muss unterhalb des Ordners /lib/modules/<kernel-version>/kernel/ kopiert werden. Die Kernelversion lässt sich durch den Befehl uname -r herausfinden. Um die Module neu einzulesen braucht es dann den Befehl sudo depmod -a und schließlich zum Laden des Modules modprobe helloworld.

Wenn alles geklappt hat, sollte man jetzt im Syslog ein “Hello world” sehen!

(Das sieht man zum Beispiel durch tail -f /var/log/syslog)

Teil 2 kommt dann irgendwann, wenn ich Zeit habe. ;)