Programowanie modułu jądra systemu Linux: program Hello World
Moduły jądra to fragmenty kodu, które można ładować i wyładowywać do jądra na żądanie. Rozszerzają funkcjonalność jądra bez konieczności ponownego uruchamiania systemu. Niestandardowe kody można dodawać do jąder Linuksa na dwa sposoby.
- Podstawowym sposobem jest dodanie kodu do drzewa źródeł jądra i rekompilacja jądra.
- Bardziej efektywnym sposobem jest dodanie kodu do jądra podczas jego działania. Proces ten nazywa się ładowaniem modułu, gdzie moduł odnosi się do kodu, który chcemy dodać do jądra.
- sterownik urządzenia
- sterownik systemu plików i
- Wywołania systemowe.
/** * @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 world n ' ); return 0 ; } static void __exit hello_end ( void ) { printk ( KERN_INFO 'Goodbye Mr. n ' ); } module_init ( hello_start ); module_exit ( hello_end );
Wyjaśnienie powyższego kodu: Moduły jądra muszą mieć co najmniej dwie funkcje: funkcję „startu” (inicjalizacji) zwaną init_module(), która jest wywoływana, gdy moduł jest wstawiany do jądra, oraz funkcję „końca” (czyszczenia) zwaną cleanup_module(), która jest wywoływana tuż przed jego rmmodacją. Właściwie wszystko się zmieniło, począwszy od jądra 2.3.13. Możesz teraz używać dowolnej nazwy dla funkcji początkowej i końcowej modułu. W rzeczywistości nowa metoda jest metodą preferowaną. Jednak wiele osób nadal używa funkcji init_module() i cleanup_module() do funkcji początkowych i końcowych. W tym kodzie użyliśmy hello_start() jako funkcji inicjującej i hello_end() jako funkcji czyszczącej. Kolejną rzeczą, którą mogłeś zauważyć, jest to, że zamiast funkcji printf() użyliśmy printk(). Dzieje się tak dlatego, że moduł nie wydrukuje niczego na konsoli, ale zapisze wiadomość w pliku /var/log/kern.log. Dlatego służy do debugowania modułów jądra. Co więcej, w nagłówku zdefiniowanych jest osiem możliwych ciągów poziomu logowania, które są wymagane podczas korzystania z funkcji printk(). Podajemy je w kolejności malejącej ważności: - KERN_EMERG: Używany do komunikatów alarmowych, zwykle poprzedzających awarię.
- KERN_ALERT: Sytuacja wymagająca natychmiastowego działania.
- KERN_CRIT: Krytyczne warunki często związane z poważnymi awariami sprzętu lub oprogramowania.
- KERN_ERR: Używany do zgłaszania warunków błędów; sterowniki urządzeń często używają KERN_ERR do zgłaszania problemów sprzętowych.
- KERN_WARNING: Ostrzeżenia o problematycznych sytuacjach, które same w sobie nie powodują poważnych problemów z systemem.
- KERN_NOTICE: Sytuacje, które są normalne, ale nadal godne uwagi. Na tym poziomie zgłaszanych jest szereg warunków związanych z bezpieczeństwem.
- KERN_INFO: Wiadomości informacyjne. Wiele sterowników drukuje na tym poziomie informacje o sprzęcie, który znajdą podczas uruchamiania.
- KERN_DEBUG: Używany do debugowania komunikatów. Do wydrukowania wiadomości użyliśmy KERN_INFO. Przygotowanie systemu do uruchomienia kodu: 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 do kompilacji kodu źródłowego:
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**Uwaga: nie zapomnij o spacjach w Makefile Kompilacja i ładowanie modułu: 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.koTestowanie modułu: 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 modversionsTo 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.