M2 SETI B4 / MS SE SE758


TP Votre premier module

Introduction

Objectifs

L’objectif de ce TP est de compiler et charger votre premier module noyau.

Pré-requis

Environnement de TP

Nous allons reprendre le répertoire créé lors du précédent TP.

$ export TPROOT=xxx
$ cd $TPROOT

Pensez à adapter les commandes ci-dessus en fonction du nom donné au répertoire lors du premier TP (remplaçez xxx par /home/users/xxx/seti-b4-tp par exemple si vous êtes sur les machines de l’école).

Chaîne de compilation

Par rapport aux deux TP précédents, vous devez conserver :

Profitez-en pour vérifier qu’elle est toujours dans votre PATH en tapant :

$ arm-linux-gnueabihf-gcc --version

Vérifiez que le résultat de cette commande est :

arm-linux-gnueabihf-gcc (Linaro GCC 7.4-2019.02) 7.4.1 20181213 [linaro-7.4-2019.02 revision 56ec6f6b99cc167ff0c2f8e1a2eed33b1edc85d4]

Vous pouvez supprimer le reste afin de libérer de la place si besoin.

Téléchargements

Pour ce TP, ainsi que les suivants, vous aurez besoin de récupérer :

Déplacez ces trois composants dans votre répertoire $TPROOT et décompressez l’archive contenant le noyau :

$ tar xJf linux_build.tar.xz

Vous pouvez supprimer l’archive une fois décompressée afin de gagner de la place :

$ rm linux_build.tar.xz

Vérifiez que tout fonctionne ensemble

Vérifiez que le noyau et l’image fournie démarrent correctement :

$ cd $TPROOT
$ ./qemu-system-arm -nographic -machine vexpress-a9 -kernel linux-5.10.19/build/arch/arm/boot/zImage \
-dtb linux-5.10.19/build/arch/arm/boot/dts/vexpress-v2p-ca9.dtb -initrd rootfs.cpio.gz

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).

Rappel : pour quitter QEMU, faites ctrl-a c, puis quit.

Votre premier module

Code

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)
{
  pr_info("Hello world!\n");
  return 0;
}

static void __exit first_exit(void)
{
  pr_info("Bye\n");
}

module_init(first_init);
module_exit(first_exit);

MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("My first module");
MODULE_AUTHOR("Me");

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.

Makefile

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).

Outils de gestion des modules

Plusieurs outils vous permettent de manipuler les modules :

Travail à faire

  1. Créez un répertoire de travail pour votre premier module :

    $ cd $TPROOT
    $ mkdir premier_module
    $ cd premier_module
  2. Copiez le module ci-dessus ainsi que le Makefile

  3. 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.

  4. Démarrez QEMU :

    $ cd ..
    $ ./qemu-system-arm -nographic -machine vexpress-a9 -kernel linux-5.10.19/build/arch/arm/boot/zImage \
    -dtb linux-5.10.19/build/arch/arm/boot/dts/vexpress-v2p-ca9.dtb -initrd rootfs.cpio.gz \
    -fsdev local,path=premier_module,security_model=mapped,id=mnt -device virtio-9p-device,fsdev=mnt,mount_tag=mnt

    Voici quelques explications sur les différents arguments passés à QEMU :

  5. Aprè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).

  6. Chargez votre module (depuis QEMU) :

    $ insmod /mnt/first.ko
  7. 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).

Licence
Creative Commons