Open Source im professionellen Einsatz

Kernel- und Treiberprogrammierung mit dem Kernel 2.6 - Folge 10

Kern-Technik

,

Aus Platz- und Übersichtsgründen lagert der Kernel seine Funktionalität größtenteils in Module aus. Dieser Vorgang lässt sich über Parameter fein einstellen. Linux 2.6 bietet Typsicherheit für Modulparameter und erlaubt es dem Kernelprogrammierer, dafür eigene Datentypen zu verwenden.

Auch bei Modulen bringt Linux 2.6 im Vergleich zu 2.4 kleine Veränderungen mit: Kernelprogrammierer müssen Parameter nun anders implementieren, können aber eigene Datentypen definieren. Wenn der neue Kernel dynamische Module lädt und dabei Parameter übergeben bekommt, kann er sie auf ihre Gültigkeit überprüfen. IO-Adressen, Speicherbereiche, Gerätemerkmale und Betriebsarten sind nur einige Anwendungsbeispiele dafür.

Die Parameter eines Moduls bestehen aus zwei Komponenten: dem Namen und dem Wert. Die dafür vordefinierten Datentypen zeigt Tabelle 1. Den Datentyp »byte«, im Kernel 2.4 noch vorhanden, gibt es in 2.6 nicht mehr. Um in einem eigenen Modul einen Parameter zu implementieren, muss der Programmierer Folgendes tun:

  • Eine Variable definieren, die im laufenden Modul den
    Parameterwert aufnimmt.
  • Eine Beschreibung des Parameters erstellen, die der Anwender
    des Moduls auslesen kann.
  • Per Makro den Parameter dem Kernel bekannt geben.

Tabelle 1:
Mögliche Datentypen für Modulparameter

 

Bezeichnung

Beschreibung

short

Short-Wert mit Vorzeichen

ushort

Short-Wert ohne Vorzeichen

int

Integer-Wert mit Vorzeichen

uint

Integer-Wert ohne Vorzeichen

long

Long-Wert mit Vorzeichen

ulong

Long-Wert ohne Vorzeichen

charp

Zeiger auf einen String

bool

boolescher Wert, mögliche Werte sind »y«,
»Y«, »n«, »N«, »0«,
»1«

Array

Feld eines der Standard-Datentypen

String

Zeichenfeld

Die Definition der Variablen ist trivial. Hier ist nur zu beachten, dass der Datentyp der Variablen mit dem des Parameters übereinstimmt. Die Beschreibung des Parameters ist zwar nicht zwingend notwendig, aber für den Modulbenutzer oft nützlich, deshalb sollte der Kernelprogrammierer diese Zusatzarbeit leisten. Dazu übergibt er dem Makro »MODULE_PARM_DESCR()« den beschreibenden Text. Der Anwender liest diese Beschreibung mit dem Programm »mod_info«.

Makros für alle

Um den Parameter dem Kernel bekannt zu machen, stehen gleich zwei Makros zur Auswahl. Am einfachsten ist es, wenn der Name des Parameters mit dem Namen der Variablen übereinstimmt. In diesem Fall kommt das Makro »module_param()« zum Einsatz. Es bekommt den Variablen- beziehungsweise den Parameternamen übergeben, den Datentyp (siehe Tabelle 1) und einen Dateizugriffsmodus. In einer der kommenden Kernelversionen wird das Gerätemodell[1] nämlich eine Gerätedatei mit dem Namen des Parameters erstellen. Der Zugriffsmodus auf diese Gerätedatei wird dann dem an dieser Stelle angegebenen Zugriffsmodus entsprechen.

Die Funktionen und Makros für Modulparameter sind in »linux/moduleparam .h« definiert. Listing 1 zeigt hierzu ein Beispiel: ein Modul, dem der Benutzer beim Laden den Parameter »myint« vom Typ »int« übergeben kann. Aus »param1 .c« (Listing 1) erzeugt der Compiler nach Anleitung des Makefile (Listing 2) das Modul »param1.ko«, das der Befehl »insmod« in den laufenden Kernel lädt (Abbildung 1). Liegt der angegebene Parameter außerhalb des Definitionsbereichs, wird das Modul nicht geladen. So entspricht der Wert »abcd« nicht der Definition eines Integer-Parameters.

Nur mit einem gültigem Parameter wie »myint=1234« lässt sich das Modul laden. Das Syslog (meist »/var/log/messages«) zeigt den Wert des Parameters, den das Modul mit »printk()« ausgibt (Listing 1, Zeile 12). Der Befehl »rmmod param1« entfernt das Modul wieder.

Stimmen die Namen von Variable und Parameter hingegen nicht überein, hilft das Makro »module_param_named()« weiter. Es besitzt als erstes Argument den Namen des Modulparameters, als zweites den Variablennamen im Modul. Die letzten beiden Parameter von »module_param_named()« repräsentieren wieder den zugehörigen Datentyp und die Zugriffsrechte. Listing 3 zeigt die Verwendung des Makros.

Für einen Test lässt sich das Modul wieder wie oben beschrieben laden. Nur lautet jetzt der Name des Modulparameters »maxtime«, während die modulinterne Variable den alten Namen »myint« weiterhin behält.

Listing 1: Parameter mit
»module_param()«

01 #include <linux/module.h>
02 #include <linux/moduleparam.h>
03 
04 MODULE_LICENSE("GPL");
05 MODULE_PARM_DESC(myint, "Testparameter");
06 
07 static int myint;
08 module_param( myint, int, 666 );
09 
10 static int __init mod_init(void)
11 {
12         printk("myint = %dn", myint);
13         return 0;
14 }
15 
16 static void __exit mod_exit(void)
17 {
18 }
19 module_init( mod_init );
20 module_exit( mod_exit );

Listing 2: Makefile für
»param1.c«

01 TARGET=param1
02 
03 ifneq ($(KERNELRELEASE),)
04 obj-m   := ${TARGET}.o
05 
06 else
07 KDIR    := /lib/modules/$(shell uname -r)/build
08 PWD     := $(shell pwd)
09 
10 default:
11         $(MAKE) -C $(KDIR)      SUBDIRS=$(PWD) modules
12 endif

Listing 3: Makro
»module_param _named()«

01 ...
02 static int myint;
03 module_param_named(maxtime, myint, int, 666);
04 
05 static int __init mod_init(void)
06 {
07    printk("myint = %dn", myint);
08    return 0;
09 }
10 ...

Abbildung 1: Der Versuch, mit »insmod« das Beispiel aus Listing 1 in den laufenden Kernel zu laden, funktioniert nur, wenn der Parameter innerhalb des definierten Wertebereichs liegt.

Abbildung 1: Der Versuch, mit »insmod« das Beispiel aus Listing 1 in den laufenden Kernel zu laden, funktioniert nur, wenn der Parameter innerhalb des definierten Wertebereichs liegt.

Felder und Strings

Wie Tabelle 1 zeigt, stehen neben den Standarddatentypen auch Feld- beziehungsweise String-Datentypen zur Auswahl. Sie in einem Kernelmodul einzusetzen ist etwas schwieriger, doch auch für sie existieren jeweils eigene Makros. Außerdem braucht das Modul für Strings und Felder zwei Variablen, denn der Kernel muss über Feld- und Stringlänge Buch führen.

Zusätzlich teilt er dem Treiber mit, wie viele Elemente des Parameters der Anwender tatsächlich beim Aufruf verwendet hat. Leider ist hierbei nicht zu unterscheiden, ob der Benutzer sämtliche Elemente vorbelegt hat oder ob der Parameter gänzlich unbesetzt blieb.

Das Makro zur Übergabe eines Felds als Modulparameter heißt »module_param _array()«. Es besitzt ebenfalls vier Parameter: Variablen- beziehungsweise Parametername, Datentyp des Feldes, Anzahl der Feldelemente und schließlich die Zugriffsrechte. Eine Variante, bei der Variablenname und Parametername nicht übereinstimmen müssen, existiert ebenfalls, und zwar »module_param_array _named()«. Listing 4 zeigt den Einsatz der Makros anhand eines Beispiels. Es wertet die Zählervariable aus und zeigt die Anzahl der vom Anwender übergebenen Variablen an.

Listing 4: Übergabe von
Feldern

01 #include <linux/module.h>
02 #include <linux/moduleparam.h>
03 
04 MODULE_LICENSE("GPL");
05 
06 static int intarray[4];
07 static int intarraycount=4;
08 module_param_array(intarray, int, intarraycount, 666);
09 MODULE_PARM_DESC(intarray, "Ein Feld mit bis zu 4 Int");
10 
11 static int __init mod_init(void)
12 {
13    printk("intarraycount=%dn", intarraycount);
14    for(; intarraycount; intarraycount--)
15        printk("%d: %dn", intarraycount,
16        intarray[intarraycount - 1]);
17    return 0;
18 }
19 
20 static void __exit mod_exit(void)
21 {
22 }
23 module_init(mod_init);
24 module_exit(mod_exit);

Für Strings als Modulparameter stehen die beiden Makros »module_param_string()« und »module_param_string_named()« zur Verfügung. Ihre Parameter entsprechen denen der Feldmakros. Listing 5 zeigt ihre Anwendung.

Listing 5: Definition eines
String-Parameters

01 ...
02 static char string[10];
03 module_param_string( optionname, string, sizeof(string), 666 );
04 
05 static int __init mod_init(void)
06 {
07    if( string[0] )
08       printk("string: %sn", string);
09    ...

Diesen Artikel als PDF kaufen

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