Laboratori 9: Programació de mòduls per al Kernel de Linux
En aquest laboratori aprendrem a programar mòduls per al kernel de Linux. Aquesta és una de les tasques més complexes que es poden fer en el món de la programació de sistemes. Per això, realitzarem uns exemples senzills per a entendre com es programen els mòduls i com es poden integrar al kernel.
Requisits previs
- Màquina virtual amb Debian.
- Realitzar una snapshot de la màquina virtual abans de començar el laboratori.
- Programari necessari:
Eines de construcció de programari:
build-essentialCapçaleres del kernel:
linux-headers-$(uname -r)Altres eines:
libncurses-dev,bison,flex,kmodInstal·lació de les eines necessàries:
su -c "apt update && apt upgrade -y" su -c "apt install build-essential linux-headers-$(uname -r) libncurses-dev bison flex kmod -y"
Tasques
Explorant el kernel
Obtenir informació sobre la versió del kernel actual:
uname -rEn el meu cas, la versió del kernel és
6.1.0-39-arm64.Per veure els mòduls carregats al kernel, podem fer servir la comanda
lsmod:su -c "lsmod"També podem fer servir la comanda
catper llegir el fitxer/proc/modules:su -c "cat /proc/modules"Si volem filtrar un mòdul concret, podem fer servir la comanda
grep:su -c "lsmod | grep fat"
Els moduls del kernel registren la informació de log en una consola, però per defecte no la podreu veure per la sortida estàndard (sdtout) o la sortida d’error (stderr). Per veure aquesta informació, necessitarem fer servir la comanda dmesg.
Per exemple, si volem veure els últims missatges del kernel, podem fer servir la comanda:
su -c "dmesg | tail -n 10"Aquest missatge provenen dels mòduls del kernel que utilitzen la funció printk per imprimir informació de log. Aquesta funció permet especificar el nivell de log i el mòdul que genera el missatge. Per canviar el nivell de log, podem fer servir la comanda dmesg amb l’opció -n:
su -c "dmesg -n 4"En aquest cas, el nivell de log és 4, que correspon a WARNING. Això significa que només es mostraran els missatges de log amb nivell WARNING o superior.
Nivells de log disponibles:
- 0:
KERN_EMERG: Missatges d’emergència. - 1:
KERN_ALERT: Missatges d’alerta. - 2:
KERN_CRIT: Missatges crítics. - 3:
KERN_ERR: Missatges d’error. - 4:
KERN_WARNING: Missatges d’avís. - 5:
KERN_NOTICE: Missatges de notificació. - 6:
KERN_INFO: Missatges d’informació. - 7:
KERN_DEBUG: Missatges de depuració. - 8:
KERN_DEFAULT: Nivell per defecte.
Programant un mòdul
En aquesta secció, programarem un mòdul senzill per al kernel de Linux. Aquest mòdul imprimirà un missatge d’inici i un missatge de finalització quan es carregui i descarregui al kernel.
Creem un directori per al nostre mòdul:
mkdir -p $HOME/kernel cd $HOME/kernelCreem un fitxer anomenat
hello.camb el següent contingut:#include <linux/kernel.h> #include <linux/module.h> MODULE_LICENSE("GPL"); int init_module(void) { printk(KERN_INFO "Hello, world!\n"); return 0; } void cleanup_module(void) { printk(KERN_INFO "Goodbye, world!\n"); }Crearem un fitxer
Makefileper compilar el nostre mòdul amb el següent contingut:CONFIG_MODULE_SIG=n 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) cleanNota:
- El fitxer
Makefileés sensible a la indentació. Assegureu-vos que utilitzeu tabuladors en lloc d’espais. - La variable
obj-mindica quin és el mòdul que volem compilar. - La variable
PWDconté la ruta del directori actual. $(shell uname -r)retorna la versió del kernel actual.CONFIG_MODULE_SIG=ndesactiva la verificació de la signatura del mòdul.
- El fitxer
Compil·lem el nostre mòdul amb la comanda
make:makeTroubleshooting:
- Si obteniu un error de
missing separator, assegureu-vos que utilitzeu tabuladors en lloc d’espais. - Si obteniu un error de
/lib/modules/, assegureu-vos que teniu instal·lat el paquetlinux-headers. - Si obteniu un error de
missing MODULE_LICENSE(), podeu afegir la següent línia al vostre fitxerhello.c:
- Si obteniu un error de
Carreguem el nostre mòdul amb la comanda
insmod:su - insmod /home/jordi/laboratoris/lab2-kernel/kernel-modules/hello.koNota: Si teniu errors assegureu-vos que esteu executant la comanda com a
root. Quan canviem a l’usuariroot, la variable$HOMEcanvia a/root. Per tant, assegureu-vos d’apuntar a la ruta correcta.Comprovem que el mòdul s’ha carregat correctament amb la comanda
lsmod:lsmod | grep helloSi el mòdul s’ha carregat correctament, veureu una sortida similar a aquesta:
hello 16384 0Comprovem els missatges del kernel amb la comanda
dmesg:su -c "dmesg"Si tot ha anat bé, veureu els missatges
Hello, world!al final de la sortida.Descarreguem el mòdul amb la comanda
rmmod:rmmod helloComprovem que el mòdul s’ha descarregat correctament amb la comanda
lsmod:lsmod | grep helloSi el mòdul s’ha descarregat correctament, hauríeu de veure el missatge
Goodbye, world!al final de la sortida dedmesg.
Es poden fer diferents millores i moduls més complexos, però aquest és un exemple senzill per a començar a programar mòduls per al kernel de Linux. Per exemple, podeu afegir més informació al mòdul com llicència, autor, descripció i versió. També podeu utilitzar les macros __init i __exit per optimitzar el mòdul i reduir la memòria utilitzada.
Per exemple, aquí teniu un exemple millorat del mòdul hello.c:
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Jordi Mateo");
MODULE_DESCRIPTION("Hello World OS Kernel Module");
MODULE_VERSION("0.1");
static int __init hello_init(void) {
printk(KERN_INFO "WOW I AM A KERNEL HACKER!!!\n");
return 0;
}
static void __exit hello_cleanup(void) {
printk(KERN_INFO "I am dead.\n");
}
module_init(hello_init);
module_exit(hello_cleanup);