Open Source im professionellen Einsatz

Kernel- und Treiberprogrammierung mit dem Kernel 2.6 - Folge 48

Kern-Technik

,

Einen Treiber in den Kernel einzubinden ist leider wenig intuitiv. Deshalb gibt es hier ein Grundgerüst als Ausgangspunkt. Es zeigt, wie der Kernel dem Treiber Gerätenummern zuweist und der Gerätedateiverwalter Udev eigenständig die zugehörigen Gerätedateien anlegt.

Das einfachste Programm des Kernels, sein "Hello World", ist übersichtlich: 16 Zeilen Code, zwei Funktionen und ein passendes Makefile reichen aus, um Selbstgeschriebenes mit dem Kernel zu verknüpfen (Listing 1). Als Ergebnis steigt im Syslog der vom C-Erfinder Brian Kernighan entwickelte Willkommensgruß aus den Tiefen des Betriebssystem auf (Abbildung 1).

Listing 1: Hallo Kernelwelt
(»hellofromkernel.c«)

01 #include <linux/module.h>
02 
03 static int __init template_init(void)
04 {
05   printk("Hello worldn");
06   return 0;
07 }
08 
09 static void __exit template_exit(void)
10 {
11   return;
12 }
13 
14 module_init(template_init);
15 module_exit(template_exit);
16 MODULE_LICENSE("GPL");

Der kurze Code ist leicht nachzuvollziehen. Die erste Funktion (Zeile 3) ruft der Prozessor beim Laden, die zweite beim Entladen des Programms auf (Zeile 9). »printk()« (Zeile 5) steht für "Print Kernel" und entspricht »printf()« in anderen Programmen. Für den Kernel-Neuling bleiben lediglich die ungewöhnlichen Schlüsselwörter »__init« (Zeile 3) und »__exit« (Zeile 9) und die Makros »module_init()«, »module_exit()« und »MODULE_LICENSE()« (Zeilen 14 bis 16 ) erklärungsbedürftig.

Hallo Kernelwelt

»__init« klassifiziert die zugehörige Funktion als eine Initialisierungsfunktion, die nur ein einziges Mal in Aktion tritt, nämlich beim Laden des Code. Linux entfernt sie nach dem Aufruf und gibt den ansonsten unnütz belegten Speicher frei. Eine über »__exit« kategorisierte Funktion wandert unter bestimmten Umständen gar nicht erst in den Hauptspeicher. In beiden Fällen optimiert der Kernel den Programmablauf.

Die beiden Makros »module_init()« und »module_exit()« erlauben es dem Programmierer, die Namen der Modul-Initialisierungs- und Deinitialisierungsfunktion frei zu wählen. Der Programmtext des entstehenden Kernelmoduls wird dadurch besser lesbar. »MODULE_LICENSE()« schließlich verknüpft den Treibercode mit der vom Programmierer gewählten Lizenz (Zeile 16). Mit einer proprietären Lizenz steht ihm nur eingeschränkte Kernelfunktionalität zur Verfügung. Wer sich aber zur freien Software bekennt, greift auf alle vom Kernel bereitgestellten Routinen zu.

Garniert mit ein paar weiteren Codezeilen mutiert das vorliegende Hello-World-Kernelmodul schnell zu einem Gerätetreiber, auf den sein Schöpfer mit den Applikationsfunktionen »open()«, »close()«, »read()« und »write()« zugreift. Dazu erstellt er die Liste »struct file_operations« (Listing 2, Zeile 6), die die Adressen der im Treiber aufzurufenden Funktionen »driver_open()«, »driver_close()«, »driver_read()« und »driver_write()« zusammenfasst. Mit dieser Liste meldet sich der Kernelprogrammierer beim IO-Subsystem des Kernels an, indem er die Funktion »register_chrdev()« (Zeile 11) aufruft und eine Treiber-Identifikationsnummer angibt. Das spätere Abmelden übernimmt die Funktion »unregister_chrdev()« in Zeile 19.

Arbeitslos

Die Liste kann - wie in diesem Beispiel - leer sein. Dann erfüllt der Treiber einfach keine Funktion. Die erwähnte Identifikationsnummer oder Majornummer verbindet sich im Applikationsbereich durch Aufruf des Kommandos »mknod« mit einer Gerätedatei. Den Namen dieser Gerätedatei bekommt die Applikationsfunktion »open()« als ersten Parameter übergeben (Abbildung 2).

Abbildung 1: Mit einem geeigneten Makefile lässt sich aus dem Code von Listing 1 ein Kernelmodul generieren. Das Kommando »insmod« lädt das Modul in den Kern. Bei Erfolg grüßt der Kernel die Welt in seinen Messages mit einem Hallo.

Abbildung 1: Mit einem geeigneten Makefile lässt sich aus dem Code von Listing 1 ein Kernelmodul generieren. Das Kommando »insmod« lädt das Modul in den Kern. Bei Erfolg grüßt der Kernel die Welt in seinen Messages mit einem Hallo.

Mit Kernel 2.6 hat Linus Torvalds die antiquierten und in ihrer Zahl begrenzten Majornummern gegen moderne Gerätenummern ausgetauscht. Für sie baute der Treiber-Chef Greg Kroah-Hartman ein neues Interface, mit dem sich Treiber beim IO-Subsystem des Kernels anmelden. Das neue Interface wirkt offenbar auf viele Entwickler weder intuitiv noch elegant. Sie greifen daher weiterhin auf die eben genannte und bewährte »register _chrdev()«-Methode zurück. Auch wenn alles wie hier beschrieben programmierbar und funktionstüchtig ist, so ist dies nicht im Sinne der Erfinder, moderne Treibereinbindung sieht anders aus.

Diesen Artikel als PDF kaufen

Express-Kauf als PDF

Umfang: 4 Heftseiten

Preis € 0,99
(inkl. 19% MwSt.)

Als digitales Abo

Als PDF im Abo bestellen

comments powered by Disqus

Ausgabe 07/2013

Preis € 6,40

Insecurity Bulletin

Insecurity Bulletin

Im Insecurity Bulletin widmet sich Mark Vogelsberger aktuellen Sicherheitslücken sowie Hintergründen und Security-Grundlagen. mehr...

Linux-Magazin auf Facebook