logo

Programmazione del modulo kernel Linux: programma Hello World

I moduli del kernel sono pezzi di codice che possono essere caricati e scaricati nel kernel su richiesta. Estendono la funzionalità del kernel senza la necessità di riavviare il sistema. I codici personalizzati possono essere aggiunti ai kernel Linux tramite due metodi.
  • Il modo base è aggiungere il codice all'albero dei sorgenti del kernel e ricompilare il kernel.
  • Un modo più efficiente per farlo è aggiungere codice al kernel mentre è in esecuzione. Questo processo si chiama caricamento del modulo dove modulo si riferisce al codice che vogliamo aggiungere al kernel.
Poiché stiamo caricando questi codici in fase di esecuzione e non fanno parte del kernel Linux ufficiale, questi sono chiamati modulo kernel caricabile (LKM) che è diverso dal kernel di base. Il kernel di base si trova nella directory /boot e viene sempre caricato quando si avvia la macchina, mentre gli LKM vengono caricati dopo che il kernel di base è già stato caricato. Tuttavia questi LKM fanno parte integrante del nostro kernel e comunicano con il kernel base per completare le loro funzioni. Gli LKM possono svolgere una varietà di compiti ma fondamentalmente rientrano in tre categorie principali
  • driver del dispositivo
  • driver del file system e
  • Chiamate di sistema.
Quindi quale vantaggio offrono gli LKM? Uno dei principali vantaggi che hanno è che non abbiamo bisogno di continuare a ricostruire il kernel ogni volta che aggiungiamo un nuovo dispositivo o se aggiorniamo un vecchio dispositivo. Ciò fa risparmiare tempo e aiuta anche a mantenere il nostro kernel di base privo di errori. Un'utile regola pratica è che non dovremmo cambiare il nostro kernel di base una volta che abbiamo un kernel di base funzionante. Inoltre aiuta a diagnosticare i problemi del sistema. Ad esempio, supponiamo di aver aggiunto un modulo al kernel di base (ovvero di aver modificato il nostro kernel di base ricompilandolo) e che il modulo contenga un bug. Ciò causerà un errore nell'avvio del sistema e non sapremo mai quale parte del kernel sta causando problemi. Mentre se carichiamo il modulo in fase di runtime e causa problemi, riconosceremo immediatamente il problema e potremo scaricare il modulo finché non lo risolveremo. Gli LKM sono molto flessibili nel senso che possono essere caricati e scaricati con un'unica riga di comando. Questo aiuta a risparmiare memoria poiché carichiamo l'LKM solo quando ne abbiamo bisogno. Inoltre non sono più lenti del kernel base perché richiamare uno di essi equivale semplicemente a caricare il codice da una parte diversa della memoria. **Avvertenza: gli LKM non sono programmi in spazio utente. Fanno parte del kernel. Hanno libero accesso al sistema e possono facilmente bloccarlo. 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); 
Spiegazione per il codice sopra: I moduli del kernel devono avere almeno due funzioni: una funzione di 'inizio' (inizializzazione) chiamata init_module() che viene chiamata quando il modulo viene inserito nel kernel e una funzione di 'fine' (pulizia) chiamata cleanup_module() che viene chiamata appena prima che venga rmmodato. In realtà le cose sono cambiate a partire dal kernel 2.3.13. Ora puoi utilizzare il nome che preferisci per le funzioni di inizio e fine di un modulo. In effetti il ​​nuovo metodo è il metodo preferito. Tuttavia molte persone usano ancora init_module() e cleanup_module() per le loro funzioni di inizio e fine. In questo codice abbiamo utilizzato hello_start() come funzione init e hello_end() come funzione di pulizia. Un'altra cosa che potresti aver notato è che invece della funzione printf() abbiamo usato printk(). Questo perché il modulo non stamperà nulla sulla console ma registrerà il messaggio in /var/log/kern.log. Quindi viene utilizzato per eseguire il debug dei moduli del kernel. Inoltre ci sono otto possibili stringhe di livello log definite nell'intestazione che sono richieste durante l'utilizzo di printk(). Li elenchiamo in ordine di gravità decrescente:
  • KERN_EMERG: utilizzato per i messaggi di emergenza, solitamente quelli che precedono un incidente.
  • KERN_ALERT: una situazione che richiede un'azione immediata.
  • KERN_CRIT: condizioni critiche spesso correlate a gravi guasti hardware o software.
  • KERN_ERR: Utilizzato per segnalare condizioni di errore; i driver di dispositivo spesso utilizzano KERN_ERR per segnalare problemi hardware.
  • KERN_WARNING: Avvisi su situazioni problematiche che di per sé non creano seri problemi al sistema.
  • KERN_NOTICE: Situazioni normali ma comunque degne di nota. A questo livello vengono segnalate numerose condizioni relative alla sicurezza.
  • KERN_INFO: messaggi informativi. Molti driver stampano le informazioni sull'hardware che trovano all'avvio a questo livello.
  • KERN_DEBUG: utilizzato per il debug dei messaggi.
  • Abbiamo usato KERN_INFO per stampare il messaggio. Preparazione del sistema per eseguire il codice: 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 per compilare il codice sorgente:
    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 
    **Nota: non dimenticare gli spazi di tabulazione nel Makefile Compilazione e caricamento del modulo: 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 
    Testare il modulo: 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.