====== Linux-Kernel-Hacking ====== :!: Noch in Rekonstruktion :!: Im Dezember 2012 hat [[https://lists.uvena.de/pipermail/hackspace-jena/2012-December/002754.html|Yu]] vorgeschlagen, einen tieferen Einblick in die Programmierung von Modulen für den [[https://kernel.org/|Linux-Kernel]] zu geben. Am 9. Februar 2013 trafen wir uns und haben gemeinsam ein einfaches Modul für den Linux-Kernel erstellt. Dies legt ein Char-Device an. Darüber kann man die Ausgabe eines Zählers abfragen. ===== Shownotes ===== ==== Einstieg in das Kernelbauen ==== Yu hat für den Vortrag ein paar Folien zusammengestellt, die es {{:hswiki:vortraege:kernel.pdf|hier}} gibt und einige der Grundlagen zusammen fassen. === Das Minimal-Kernel-Modul === Als Anfang das simpelste Kernelmodul. Benötigte Utensilien: - Ein Linux (Header nicht vergessen) - Editor/Terminal - C-Code und passenden Compiler (aka GCC) - Makefile (Nicht unbedingt in dieser Reihenfolge) Ist alles zur Hand, kann es losgehen. Das einfachste Kernelmodul sieht ungefähr so aus: // The simplest kernel module. #include #include #include #include #include int init_module(void) { printk(KERN_INFO "Hello world!\n"); return 0; } void cleanup_module(void) { printk(KERN_INFO "Goodbye world!\n"); } Es macht im Grunde nichts anderes, als beim Laden via ''insmod geruest.ko'' die Nachricht //Hello world!// in das Log zu schreiben. Wenn man es mit ''rmmod geruest'' wieder entlädt, wird die Nachricht //Goodbye world!// in das Log geschrieben. Um es aber zu übersetzen, benötigt man ein Makefile (benötigt man nicht, macht die Sache aber einfacher). Dieses könnte ungefähr so aussehen: obj-m += geruest.o all: make -C /lib/modules/$(shell uname -r)/build M=$(shell pwd) modules clean: make -C /lib/modules/$(shell uname -r)/build M=$(shell pwd) clean Damit kann durch die Aufruf von ''make'' das Modul übersetzen. Damit kann durch die Aufruf von ''make'' das Modul übersetzen und über ''insmod'' bzw ''rmmod'' laden und entladen. Im nächsten Schritt soll das Modul noch ein paar Informationen erhalten, die z.B. mit ''modinfo'' ausglesen werden können. Dazu kann man diese Zeilen, natürlich mit sinvollem Inhalt gefüllt, in die Quellen einbauen: MODULE_AUTHOR("Dein Name") MODULE_LICENSE("Name der Lizenz, z.B. GPL") MODULE_DESCRIPTION("Beschreibung, was dein Modul so macht") MODULE_SUPPORTED_DEVICE("Gerad unwichtig. Zur Dokumentationszwecken nutzbar") === Variablen im Kernelland === Der Kernel definiert zum Teil seine eigenen Variablentypen. Diese könnten z.B. sein: * byte, short, ushort, int, uint, long, ulong * **charp**: a character pointer * **bool**: a bool, values 0/1, y/n, Y/N. * **invbool**: the above, only sense-reversed (N = true). Diese kann man nutzen, um Parameter vom Terminal einzulesen, die z.B. beim Laden des Moduls mit übergeben werden. Um Parameter vom Terminal einzulesen nutzt man: /* Prototyp */ module_param(variablenname, type, permission); /* Hauptsächlich für modinfo */ MODULE_PARM_DESC(variablenname, "Beschreibung"); Um tatsächlich auf das neu geschaffene Device zugreifen zu können, muss man ein device in ''/dev'' erstellen. Dies geht ungefähr so: dev_t devnr = MKDEV(int majornr, int minornr); In dem konrketen Beispiel sollten wobei ''majornr'' 120 und ''minornr'' 1 sein. Als nächstes braucht man ein struct, welches die character-device-Struktur des Kernels beinhaltet. struct cdev *char_dev; Sowie noch einen ''int'' fuer den Rückgabewert, sowie den Names des Devices als char*. Dies könnte dann ungefähr so aussehen: // .. dev_t devnr = MKDEV(120, 1); struct cdev *char_dev; int rv; char* name = "device_name"; //..