logo

Programmation du module du noyau Linux : programme Hello World

Les modules du noyau sont des morceaux de code qui peuvent être chargés et déchargés dans le noyau à la demande. Ils étendent les fonctionnalités du noyau sans qu'il soit nécessaire de redémarrer le système. Des codes personnalisés peuvent être ajoutés aux noyaux Linux via deux méthodes.
  • La méthode de base consiste à ajouter le code à l’arborescence des sources du noyau et à recompiler le noyau.
  • Un moyen plus efficace consiste à ajouter du code au noyau pendant son exécution. Ce processus est appelé chargement du module où module fait référence au code que nous voulons ajouter au noyau.
Étant donné que nous chargeons ces codes au moment de l'exécution et qu'ils ne font pas partie du noyau Linux officiel, ils sont appelés module de noyau chargeable (LKM), qui est différent du noyau de base. Le noyau de base se trouve dans le répertoire /boot et est toujours chargé lorsque nous démarrons notre machine alors que les LKM sont chargés une fois le noyau de base déjà chargé. Néanmoins, ces LKM font partie intégrante de notre noyau et communiquent avec le noyau de base pour remplir leurs fonctions. Les LKM peuvent effectuer diverses tâches, mais ils se répartissent essentiellement en trois catégories principales.
  • pilote de périphérique
  • pilote de système de fichiers et
  • Appels système.
Alors, quel avantage offrent les LKM ? L’un de leurs principaux avantages est que nous n’avons pas besoin de reconstruire le noyau à chaque fois que nous ajoutons un nouveau périphérique ou si nous mettons à niveau un ancien périphérique. Cela permet de gagner du temps et contribue également à maintenir notre noyau de base exempt d'erreurs. Une règle générale utile est que nous ne devons pas changer notre noyau de base une fois que nous avons un noyau de base fonctionnel. Cela aide également à diagnostiquer les problèmes du système. Par exemple, supposons que nous ayons ajouté un module au noyau de base (c'est-à-dire que nous avons modifié notre noyau de base en le recompilant) et que le module contient un bogue. Cela provoquera une erreur au démarrage du système et nous ne saurons jamais quelle partie du noyau pose problème. Alors que si nous chargeons le module au moment de l'exécution et que cela pose des problèmes, nous connaîtrons immédiatement le problème et nous pourrons décharger le module jusqu'à ce que nous le résolvions. Les LKM sont très flexibles dans le sens où ils peuvent être chargés et déchargés avec une seule ligne de commande. Cela permet d'économiser de la mémoire car nous chargeons le LKM uniquement lorsque nous en avons besoin. De plus, ils ne sont pas plus lents que le noyau de base car appeler l’un ou l’autre revient simplement à charger du code depuis une partie différente de la mémoire. **Attention : les LKM ne sont pas des programmes en espace utilisateur. Ils font partie du noyau. Ils disposent d'un fonctionnement libre du système et peuvent facilement le faire planter. 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); 
Explication du code ci-dessus : Les modules du noyau doivent avoir au moins deux fonctions : une fonction de « démarrage » (initialisation) appelée init_module() qui est appelée lorsque le module est inséré dans le noyau et une fonction de « fin » (nettoyage) appelée cleanup_module() qui est appelée juste avant qu'il ne soit modifié. En fait, les choses ont changé depuis le noyau 2.3.13. Vous pouvez désormais utiliser le nom de votre choix pour les fonctions de début et de fin d'un module. En fait, la nouvelle méthode est la méthode préférée. Cependant, de nombreuses personnes utilisent encore init_module() et cleanup_module() pour leurs fonctions de début et de fin. Dans ce code, nous avons utilisé hello_start() comme fonction d'initialisation et hello_end() comme fonction de nettoyage. Une autre chose que vous avez peut-être remarquée est qu'au lieu de la fonction printf(), nous avons utilisé printk(). En effet, le module n'imprimera rien sur la console mais enregistrera le message dans /var/log/kern.log. Par conséquent, il est utilisé pour déboguer les modules du noyau. De plus, huit chaînes de niveau de journalisation possibles définies dans l'en-tête sont requises lors de l'utilisation de printk(). Nous les avons classés par ordre de gravité décroissante :
  • KERN_EMERG : utilisé pour les messages d'urgence, généralement ceux qui précèdent un crash.
  • KERN_ALERT : une situation nécessitant une action immédiate.
  • KERN_CRIT : conditions critiques souvent liées à de graves pannes matérielles ou logicielles.
  • KERN_ERR : utilisé pour signaler les conditions d'erreur ; les pilotes de périphériques utilisent souvent KERN_ERR pour signaler des difficultés matérielles.
  • KERN_WARNING : avertissements concernant des situations problématiques qui ne créent pas en elles-mêmes de graves problèmes avec le système.
  • KERN_NOTICE : situations normales mais néanmoins dignes de mention. Un certain nombre de conditions liées à la sécurité sont signalées à ce niveau.
  • KERN_INFO : messages d'information. De nombreux pilotes impriment des informations sur le matériel qu'ils trouvent au démarrage à ce niveau.
  • KERN_DEBUG : utilisé pour le débogage des messages.
  • Nous avons utilisé KERN_INFO pour imprimer le message. Préparation du système pour exécuter le code : 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 pour compiler le code source :
    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 
    **Remarque : n'oubliez pas les espaces de tabulation dans Makefile Compilation et chargement du module : 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 
    Test du module : 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.