logo

Linux-Kernel-Modulprogrammierung: Hello World-Programm

Kernelmodule sind Codeteile, die bei Bedarf in den Kernel geladen und entladen werden können. Sie erweitern die Funktionalität des Kernels, ohne dass ein Neustart des Systems erforderlich ist. Benutzerdefinierte Codes können auf zwei Arten zu Linux-Kerneln hinzugefügt werden.
  • Der grundlegende Weg besteht darin, den Code zum Kernel-Quellbaum hinzuzufügen und den Kernel neu zu kompilieren.
  • Eine effizientere Möglichkeit besteht darin, Code zum Kernel hinzuzufügen, während dieser ausgeführt wird. Dieser Vorgang wird als Laden des Moduls bezeichnet, wobei sich Modul auf den Code bezieht, den wir dem Kernel hinzufügen möchten.
Da wir diese Codes zur Laufzeit laden und sie nicht Teil des offiziellen Linux-Kernels sind, werden sie als ladbares Kernelmodul (LKM) bezeichnet, das sich vom Basiskernel unterscheidet. Der Basiskernel befindet sich im Verzeichnis /boot und wird immer geladen, wenn wir unseren Computer starten, während LKMs geladen werden, nachdem der Basiskernel bereits geladen ist. Dennoch sind diese LKM ein wesentlicher Bestandteil unseres Kernels und kommunizieren mit dem Basiskernel, um ihre Funktionen zu erfüllen. LKMs können eine Vielzahl von Aufgaben erfüllen, lassen sich aber grundsätzlich in drei Hauptkategorien einteilen
  • Gerätetreiber
  • Dateisystemtreiber und
  • Systemaufrufe.
Welchen Vorteil bieten LKMs? Ein großer Vorteil besteht darin, dass wir den Kernel nicht jedes Mal neu erstellen müssen, wenn wir ein neues Gerät hinzufügen oder ein altes Gerät aktualisieren. Dies spart Zeit und hilft auch dabei, unseren Basiskernel fehlerfrei zu halten. Eine nützliche Faustregel ist, dass wir unseren Basiskernel nicht ändern sollten, sobald wir einen funktionierenden Basiskernel haben. Außerdem hilft es bei der Diagnose von Systemproblemen. Angenommen, wir haben dem Basiskernel ein Modul hinzugefügt (d. h. wir haben unseren Basiskernel durch Neukompilierung geändert) und das Modul weist einen Fehler auf. Dies führt zu Fehlern beim Systemstart und wir werden nie wissen, welcher Teil des Kernels Probleme verursacht. Wenn wir das Modul hingegen zur Laufzeit laden und es Probleme verursacht, erkennen wir das Problem sofort und können das Modul entladen, bis wir es behoben haben. LKMs sind in dem Sinne sehr flexibel, dass sie mit einer einzigen Befehlszeile geladen und entladen werden können. Dies hilft, Speicherplatz zu sparen, da wir die LKM nur dann laden, wenn wir sie benötigen. Darüber hinaus sind sie nicht langsamer als der Basiskernel, da der Aufruf eines von ihnen einfach Code aus einem anderen Teil des Speichers lädt. **Warnung: LKMs sind keine User-Space-Programme. Sie sind Teil des Kernels. Sie haben freien Lauf auf das System und können es leicht zum Absturz bringen. So now that we have established the use loadable kernel modules we are going to write a hello world kernel module. That will print a message when we load the module and an exit message when we unload the module. Code: CPP
/**  * @file hello.c  * @author Akshat Sinha  * @date 10 Sept 2016  * @version 0.1  * @brief An introductory 'Hello World!' loadable kernel  * module (LKM) that can display a message in the /var/log/kern.log  * file when the module is loaded and removed. The module can accept  * an argument when it is loaded -- the name which appears in the  * kernel log files. */ #include  /* Needed by all modules */ #include  /* Needed for KERN_INFO */ #include  /* Needed for the macros */ ///< The license type -- this affects runtime behavior MODULE_LICENSE('GPL'); ///< The author -- visible when you use modinfo MODULE_AUTHOR('Akshat Sinha'); ///< The description -- see modinfo MODULE_DESCRIPTION('A simple Hello world LKM!'); ///< The version of the module MODULE_VERSION('0.1'); static int __init hello_start(void) {  printk(KERN_INFO 'Loading hello module...n');  printk(KERN_INFO 'Hello worldn');  return 0; } static void __exit hello_end(void) {  printk(KERN_INFO 'Goodbye Mr.n'); } module_init(hello_start); module_exit(hello_end); 
Erklärung zum obigen Code: Kernel-Module müssen mindestens zwei Funktionen haben: eine „Start“-Funktion (Initialisierung) namens „init_module()“, die aufgerufen wird, wenn das Modul in den Kernel eingefügt wird, und eine „End“-Funktion (Bereinigung) namens „cleanup_module()“, die unmittelbar vor dem RM-Modem aufgerufen wird. Tatsächlich haben sich die Dinge ab Kernel 2.3.13 geändert. Sie können nun für die Start- und Endfunktionen eines Moduls einen beliebigen Namen verwenden. Tatsächlich ist die neue Methode die bevorzugte Methode. Allerdings verwenden viele Leute immer noch init_module() und cleanup_module() für ihre Start- und Endfunktionen. In diesem Code haben wir hello_start() als Init-Funktion und hello_end() als Bereinigungsfunktion verwendet. Eine weitere Sache, die Ihnen vielleicht aufgefallen ist, ist, dass wir anstelle der printf()-Funktion printk() verwendet haben. Dies liegt daran, dass das Modul nichts auf der Konsole ausgibt, die Meldung jedoch in /var/log/kern.log protokolliert. Daher wird es zum Debuggen von Kernelmodulen verwendet. Darüber hinaus sind im Header acht mögliche Loglevel-Strings definiert, die bei der Verwendung von printk() erforderlich sind. Wir haben sie in der Reihenfolge abnehmender Schwere aufgelistet:
  • KERN_EMERG: Wird für Notfallmeldungen verwendet, normalerweise solche, die einem Absturz vorausgehen.
  • KERN_ALERT: Eine Situation, die sofortiges Handeln erfordert.
  • KERN_CRIT: Kritische Zustände, die häufig mit schwerwiegenden Hardware- oder Softwarefehlern zusammenhängen.
  • KERN_ERR: Wird zum Melden von Fehlerbedingungen verwendet. Gerätetreiber verwenden häufig KERN_ERR, um Hardwareprobleme zu melden.
  • KERN_WARNING: Warnungen vor problematischen Situationen, die an sich keine ernsthaften Probleme mit dem System verursachen.
  • KERN_NOTICE: Situationen, die normal sind, aber dennoch bemerkenswert sind. Auf dieser Ebene werden eine Reihe sicherheitsrelevanter Bedingungen gemeldet.
  • KERN_INFO: Informationsnachrichten. Viele Treiber geben auf dieser Ebene Informationen über die Hardware aus, die sie beim Start finden.
  • KERN_DEBUG: Wird zum Debuggen von Nachrichten verwendet.
  • Wir haben KERN_INFO verwendet, um die Nachricht auszudrucken. Vorbereiten des Systems für die Ausführung des Codes: The system must be prepared to build kernel code and to do this you must have the Linux headers installed on your device. On a typical Linux desktop machine you can use your package manager to locate the correct package to install. For example under 64-bit Debian you can use:
    akshat@gfg:~$ sudo apt-get install build-essential linux-headers-$(uname -r) 
    Makefile zum Kompilieren des Quellcodes:
    obj-m = hello.o all: make -C /lib/modules/$(shell uname -r)/build/ M=$(PWD) modules clean: make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean 
    **Hinweis: Vergessen Sie nicht die Tabulator-Leerzeichen in Makefile Kompilieren und Laden des Moduls: Run the make command to compile the source code. Then use insmod to load the module.
    akshat@gfg:~$ make make -C /lib/modules/4.2.0-42-generic/build/ M=/home/akshat/Documents/hello-module modules make[1]: Entering directory `/usr/src/linux-headers-4.2.0-42-generic' CC [M] /home/akshat/Documents/hello-module/hello.o Building modules stage 2. MODPOST 1 modules CC /home/akshat/Documents/hello-module/hello.mod.o LD [M] /home/akshat/Documents/hello-module/hello.ko make[1]: Leaving directory `/usr/src/linux-headers-4.2.0-42-generic' 
    Now we will use insmod to load the hello.ko object.
    akshat@gfg:~$ sudo insmod hello.ko 
    Testen des Moduls: You can get information about the module using the modinfo command which will identify the description author and any module parameters that are defined:
    akshat@gfg:~$ modinfo hello.ko filename: /home/akshat/Documents/hello-module/hello.ko version: 0.1 description: A simple Hello world LKM author: Akshat Sinha license: GPL srcversion: 2F2B1B95DA1F08AC18B09BC depends: vermagic: 4.2.0-42-generic SMP mod_unload modversions 
    To see the message we need to read the kern.log in /var/log directory.
    akshat@gfg:~$ tail /var/log/kern.log ... ... Sep 10 17:43:39 akshat-gfg kernel: [26380.327886] Hello world To unload the module we run rmmod: akshat@gfg:~$ sudo rmmod hello Now run the tail command to get the exit message. akshat@gfg:~$ tail /var/log/kern.log ... Sep 10 17:43:39 akshat-gfg kernel: [26380.327886] Hello world Sep 10 17:45:42 akshat-gfg kernel: [26503.773982] Goodbye Mr.