![]() |
M2 SETI B4 / MS SE SE758 |
L’objectif de ce TP est de compiler et charger votre premier module noyau.
Vous aller créer un répertoire de travail pour y stocker les différents fichiers nécessaires pour les travaux pratiques.
Si vous travaillez sur les machines de TP de l’école, compte-tenu de
la taille des fichiers à récupérer, je vous conseille de mettre votre
répertoire de travail dans /home/users/xxx
(où
xxx
est votre nom d’utilisateur) afin de ne pas saturer
votre répertoire personnel (qui est limité en taille). Faites attention
par contre, /home/users/xxx
est un répertoire local à la
machine sur laquelle vous êtes (il n’est pas partagé entre les machines
comme l’est votre répertoire personnel) et il n’est pas sauvegardé.
$ export TPROOT=~/se758 # Si vous êtes sur votre machine
$ export TPROOT=/home/users/xxx/se758 # Si vous êtes sur une machine de l'école (adaptez xxx)
$ mkdir $TPROOT
$ cd $TPROOT
Dans la suite des TP, nous ferons référence à ce répertoire de
travail par l’intermédiaire de la variable d’environnement
TPROOT
.
Vous aurez besoin par la suite de la chaîne de compilation
arm-linux-gnueabihf
fournie par Linaro en version
7.4.1.
Si vous êtes sur une machine de l’école, ajoutez simplement le
répertoire
/comelec/softs/opt/gnu_tools_for_arm/gcc-linaro-7.4.1-2019.02-x86_64_arm-linux-gnueabihf/bin
dans votre variable d’environnement PATH
.
Si vous êtes sur votre machine personnelle, téléchargez-la ici : https://releases.linaro.org/components/toolchain/binaries/7.4-2019.02/arm-linux-gnueabihf/gcc-linaro-7.4.1-2019.02-x86_64_arm-linux-gnueabihf.tar.xz,
puis décompressez-la quelque part (par exemple dans votre répertoire de
TP) et ajoutez le chemin
/xxx/gcc-linaro-7.4.1-2019.02-x86_64_arm-linux-gnueabihf/bin
(en remplaçant /xxx/
par le chemin correct) dans votre
variable d’environnement PATH
.
Dans les deux cas, une fois votre variable PATH
ajustée,
tapez la commande :
$ arm-linux-gnueabihf-gcc --version
et vérifiez que le résultat est bien celui-ci :
arm-linux-gnueabihf-gcc (Linaro GCC 7.4-2019.02) 7.4.1 20181213 [linaro-7.4-2019.02 revision 56ec6f6b99cc167ff0c2f8e1a2eed33b1edc85d4]
Pour pouvoir compiler un module, vous aurez besoin des en-têtes du noyau utilisé ainsi que quelques autres informations.
Récupérez donc l’archive contenant les sources du noyau et le résultat de sa compilation linux_build.tar.xz (300 Mo, 1,9 Go après désarchivage).
Décompressez l’archive dans votre répertoire de travail :
$ tar xJf linux_build.tar.xz
Pour simuler un système embarqué complet à base de processeur ARM, nous allons utiliser QEMU. En plus de ne pas avoir besoin de matériel physique pour expérimenter, Qemu permet également de facilement tester, mais aussi débugger votre système embarqué.
Plus précisément, nous allons utiliser qemu-system-arm
qui est un émulateur de machine complète, en l’occurrence, une carte de
développement Arm Versatile Express munie d’une carte
d’extension CoreTile Express A9x4 à base de
Cortex-A9.
Les détails de ce que QEMU simule concernant cette carte sont disponibles dans la documentation : https://www.qemu.org/docs/master/system/arm/vexpress.html.
Nous utiliserons une version particulière de
qemu-system-arm
(elle ajoute à QEMU un périphérique émulé
pour lequel vous allez écrire un pilote de périphérique dans la suite du
cours).
Téléchargez :
Placez l’exécutable téléchargé dans votre répertoire
$TPROOT
, puis vérifiez que les droits sont corrects pour
l’exécution :
$ chmod u+x qemu-system-arm
Normalement, cet exécutable utilise des bibliothèques partagées qui devraient être disponibles sur votre machine. Néanmoins, vérifiez que toutes les bibliothèques sont présentes en tapant :
$ ldd qemu-system-arm
Si vous désirez, le code source de QEMU ainsi que les modifications
apportées sont disponibles dans la branche adxl345
du dépôt
https://gitlab.telecom-paris.fr/guillaume.duc/qemu.
Le dernier élément à récupérer est un système de fichier minimal pour le linux embarqué tournant dans QEMU. Cette image a été générée en utilisant Buildroot version 2020.02.11 et contient :
Téléchargez le fichier rootfs.cpio.gz.
Vérifiez que le noyau et l’image fournis démarrent correctement :
$ ./qemu-system-arm -nographic -machine vexpress-a9 -kernel linux-5.10.19/build/arch/arm/boot/zImage \
-initrd rootfs.cpio.gz -dtb linux-5.10.19/build/arch/arm/boot/dts/vexpress-v2p-ca9.dtb
QEMU va démarrer la simulation d’une carte Versatile Express en plaçant dans la mémoire (simulée) de cette carte, le noyau, l’arbre des périphérique et l’image du système de fichier initial fournis. Il va également connecter le port série (virtuel) de cette carte à la console. Donc tout ce que vous verrez s’afficher dans votre terminal proviendra de cette simulation et tout ce que vous tapez sera envoyé, par l’intermédiaire du port série virtuel, à la carte simulée.
Vous devriez voir sur la console le démarrage de Linux puis un écran
de login. Vous pouvez vous connecter en tant que root
(sans
mot de passe).
Pour quitter QEMU, faites ctrl-a c
, puis
quit
(ou q
). La simulation s’arrête alors et
vous revenez à votre terminal classique sur votre machine.
Voici le code de votre premier module.
/* first.c */
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
static int __init first_init(void)
{
("Hello world!\n");
pr_inforeturn 0;
}
static void __exit first_exit(void)
{
("Bye\n");
pr_info}
(first_init);
module_init(first_exit);
module_exit
("GPL");
MODULE_LICENSE("My first module");
MODULE_DESCRIPTION("Me"); MODULE_AUTHOR
Ce module ne fait pas grand chose, à l’exception d’afficher un message lors de son chargement et un autre lors de son déchargement.
Voici le fichier Makefile
nécessaire pour compiler le
module :
ifneq ($(KERNELRELEASE),)
# kbuild part of makefile
obj-m := first.o
else
# normal makefile
KDIR ?= /lib/modules/`uname -r`/build
default:
$(MAKE) -C $(KDIR) M=$$PWD
endif
Attention ! La ligne $(MAKE) -C...
qui
indique la commande à exécuter pour construire la cible
default
doit être indentée à l’aide d’une tabulation et non
d’un ou plusieurs espaces.
Ce Makefile
est très bien adapté à la compilation d’un
module depuis la machine sur lequel vous voulez l’utiliser (compilation
native). Nous verrons par la suite comment l’utiliser dans le contexte
de la compilation croisée (cross-compilation).
Plusieurs outils vous permettent de manipuler les modules :
modinfo <nom_module|module.ko>
permet d’obtenir
les informations sur un module (auteur, description, licence
d’utilisation, version du noyau pour laquelle il a été compilé, liste
des paramètres acceptés, etc.)insmod <module.ko>
permet de charger un
modulemodprobe <nom_module>
permet de charger un module
et ses dépendances éventuelleslsmod
permet de lister les modules actuellement
chargésrmmod <nom_module>
permet de décharger un module.
Cette opération n’est possible que si le module n’est pas en cours
d’utilisationmodprobe -r <nom_module>
permet également de
décharger un module et toutes ses dépendances si elles ne sont pas
utiliséesCréez un répertoire de travail pour votre premier module :
$ cd $TPROOT
$ mkdir premier_module
$ cd premier_module
Copiez le module ci-dessus ainsi que le
Makefile
Compilez votre module
$ make CROSS_COMPILE=arm-linux-gnueabihf- ARCH=arm KDIR=../linux-5.10.19/build/
La variable CROSS_COMPILE
indique le préfixe des outils
de la chaîne de compilation que nous utilisons (donc le gcc
qui sera appelé est arm-linux-gnueabihf-gcc
). La variable
ARCH
indique que nous compilons pour l’architecture
arm
. Enfin KDIR
pointe vers le répertoire dans
lequel le noyau a été compilé (en effet, bien que vous compilez le code
de votre module à l’extérieur de l’arbre des sources du noyau, le
mécanisme de compilation a besoin notamment des fichiers d’entêtes du
noyau).
Votre module est maintenant dans le fichier
first.ko
.
Démarrez QEMU :
$ cd ..
$ ./qemu-system-arm -nographic -machine vexpress-a9 -kernel linux-5.10.19/build/arch/arm/boot/zImage \
-initrd rootfs.cpio.gz \
-dtb linux-5.10.19/build/arch/arm/boot/dts/vexpress-v2p-ca9.dtb -device virtio-9p-device,fsdev=mnt,mount_tag=mnt -fsdev local,path=premier_module,security_model=mapped,id=mnt
Voici quelques explications sur les différents arguments passés à QEMU :
-machine vexpress-a9
: indique le type de machine à
simuler (ici une carte Arm Versatile Express munie d’une carte
d’extension CoreTile Express A9x4)-kernel linux-5.10.19/build/arch/arm/boot/zImage
:
indique l’image du noyau Linux à charger au démarrage-dtb linux-5.10.19/build/arch/arm/boot/dts/vexpress-v2p-ca9.dtb
: indique le fichier contenant l’arbre des périphériques à charger au
démarrage-initrd rootfs.cpio.gz
: indique l’image du système de
fichiers racine à charger en mémoire (ici une image
initramfs
)-fsdev local,path=premier_module,security_model=mapped,id=mnt -device virtio-9p-device,fsdev=mnt,mount_tag=mnt
permet de partager le contenu du répertoire premier_module
entre votre machine et la machine émulée par QEMUAprès vous être loggué en tant que root
, montez le
partage avec la machine hôte en tapant, dans la console émulée par QEMU
:
$ mount -t 9p -o trans=virtio mnt /mnt -oversion=9p2000.L,msize=10240
Si cette commande s’exécute correctement, vous aurez alors accès,
dans le répertoire /mnt
de la machine émulée par QEMU, au
contenu du répertoire premier_module
de votre machine (et
donc au module que vous venez de compiler).
Chargez votre module (depuis QEMU) :
$ insmod /mnt/first.ko
Déchargez votre module
$ rmmod first
Félicitations, vous avez écrit votre premier module pour le noyau.
© Copyright 2020 Guillaume Duc. Le contenu de cette page est mis à disposition selon les termes de la Licence Creative Commons Attribution - Partage dans les Mêmes Conditions 4.0 International (à l'exception des exemples de code tirés du noyau Linux et qui sont distribués sous leurs licences d'origine).