Raspberry PI sans Raspbian

Raspbian est une très bonne distribution pour cette petite carte de développement qu'est la raspberry PI. Elle a le mérite de se mettre en oeuvre très simplement et d'être suffisamment générique pour couvrir toute sorte de projet. Cependant, ce que je vous propose dans cette série d'articles est de se passer de Raspbian pour créer notre propre distribution depuis les sources des logiciels que nous utiliserons. Ceci représente plusieurs avantage par rapport à l'utilisation d'une distribution toute prête: le projet ainsi réalisé sera plus optimisé (plus réactif et empreinte mémoire plus faible) et cette création de distribution a un aspect pédagogique certain. Par contre, par rapport à l'utilisation d'une distribution toute prête, il faudra vous armer de patience et consacrer plus de temps à la compréhension de nouveaux concepts (ce qui est une partie du but recherché).

Avant de commencer, je tiens à vous rappeler que la production d'un firmware dédié dans un environnement industriel se fera plutôt à l'aide d'un outils de construction comme Buildroot ou Openembedded/Yocto, mais l'utilisation d'un tel outil nous fait perdre en partie l'aspect pédagogique d'une création "à la main". C'est pourquoi cet aspect de la réalisation d'un firmware sera abordé dans des articles différents.

1 - Avant de commencer...

Tout d'abord, pour cet article, je suppose que le lecteur possède déjà une maîtrise suffisante de GNU/Linux pour avoir déjà une distribution installée sur son poste de travail et qu'il sait comment y gérer son environnement. Cet article donne en effet les grandes lignes à suivre mais ne rentre pas forcément dans tous les détails possibles. Le but ici étant de rester relativement concis.

1.1 - Architecture d'une distribution

Un système d'exploitation embarqué, pour fonctionner correctement, s'appuie sur trois aspects principaux:

  • Le noyau système: Qui a pour rôle principal de faire l'interface entre le matériel et le reste du système (les programmes utilisateur)
  • Le rootfs: Qui est l'arborescence complète du système et contient donc tous les programmes utilisateurs.
  • Le boot: Qui sont les premières étapes du démarrage du système jusqu'à ce que celui-ci soit complètement initialisé et fonctionnel.

Je vous propose donc de reprendre ces points dans la suite de cet article afin de savoir comment les configurer finement et être ainsi capable de créer une distribution complète répondant aux besoins d'un projet spécifique.

1.2 - Environnement de développement

Pour réaliser notre système embarqué, nous allons partir du code source des éléments dont nous avons besoin et le compiler afin d'obtenir les exécutables correspondants​. Nous allons compiler ce code source sur une machine plus puissante que la carte raspberry mais qui a une architecture différente. Nous allons donc faire ce que l'on appelle de la cross-compilation. Notre machine de compilation sera donc un PC classique muni d'un distribution GNU/Linux. Personnellement, j'utilise le cross-compilateur fourni par l'organisation Linaro, mais tout ce qui suit devrait pouvoir s'adapter avec n'importe quel cross-compilateur de GNU/Linux x86 vers ARM.

Afin que cette cross-compilation se réalise dans de bonnes conditions, j'ai besoin de définir sur ma machine de développement quelques variables d'environnement:

export PATH=$PATH:$HOME/gcc-linaro-5.4.1-2017.01-x86_64_arm-linux-gnueabihf/bin
export ARCH=arm
export CROSS_COMPILE=arm-linux-gnueabihf-

 

2 - Le noyau système

2.1 - Présentation du noyau Linux

 Linus Trovald

Créé par Linus Trovald en 1991, puis repris par une large communauté de développeurs, Linux est un noyau système permettant de faire l'interface entre le matériel et les applicatifs utilisateurs via une API spécifique. Ce noyau système avait été conçu à l'origine pour les processeurs de type x86, mais il a été depuis porté vers de nombreuses autres architectures dont ARM, qui est très développée dans le domaine de l'embarqué. Il gère l'accès aux ressources matérielles ainsi que l'exécution et la coordination des différentes tâches via son ordonnanceur. C'est un noyau système multi-tâches et multi-utilisateurs, qui respecte la norme POSIX. Il est monolithique, mais certaines fonctionnalités peuvent être activées/déactivées à chaud via un système de modules.

Enfin, ce noyau ne constitue pas à lui tout seul le système d'exploitation, il a besoin aussi de toute une série d'applicatifs pour faire l'interface avec les utilisateurs.

2.2 - Noyau Linux pour Raspberry PI

 Le noyau Linux "officiel" dit mainline ne supporte pas la carte raspberry PI directement. Aussi, il faut apporter des modifications au code source du noyau pour en avoir un support complet, et c'est ce que nous fourni la fondation raspberry PI via son site internet :

github.com/raspberrypi/linux

On peut soit se rendre à cette adresse à l'aide d'un navigateur internet et télécharger l'archive ZIP correspondante à la version du noyau dont nous avons besoin (généralement la dernière version stable). Ou alors, on peut récupérer le code en ligne de commande sur n'importe quelle machine GNU/Linux via la commande git:

git clone https://github.com/raspberrypi/linux
cd linux/

si vous voulez modifier la version du code source du noyau, il faut le faire grâce aux lignes suivantes où <version> est à remplacer par le nom de la version désirée:

git checkout <version>

A partir de cet instant, vous avez les sources du noyau Linux dans le répertoire linux.

2.3 - Configuration et compilation du noyau

Maintenant, nous avons les sources du noyau Linux dans le répertoire linux et nous devons les configurer pour notre carte raspberry PI. Au vu du nombre d'options possibles pour la configuration, ceci peut s'avérer être une opération fastidieuse. Heureusement, plusieurs configurations par défaut ont été définies et peuvent donc nous permettre de gagner un temps précieux. La liste des configurations prédéfinies pour l'architecture ARM se trouve dans le répertoire : arch/arm/configs.

Pour les cartes raspberry PI, deux configurations peuvent nous intéresser ici:

  • bcmrpi_defconfig: pour une carte RPi
  • bcm2709_defconfig: pour une carte RPi2/RPi3

Vous pouvez directement appliquer cette configuration par la commande make. Il faudra donc taper la commande suivant pour une carte raspberry PI:

make bcmrpi_defconfig

et celle-ci si vous possédez une carte raspberry PI 2 ou 3:

make bcm2709_defconfig

ensuite, vous pouvez affiner cette configuration par défaut, via la commande:

make menuconfig

Une fois que vous êtes satisfait de votre configuration, vous pouvez lancer la compilation via la commande:

make

 En fonction de la puissance de votre machine de développement, cette compilation peu prendre plus ou moins de temps. Si vous possédez une machine multi-coeurs, vous pouvez profiter de cette architecture et grandement diminuer le temps de compilation en ajoutant l'option -j4 à la commande make si vous possédez 4 coeurs par exemple sur votre machine.

Une fois la compilation terminée, il nous reste à construire notre rootfs.  Une fois que celui-ci sera disponible, nous pourrons installer les modules du noyau sur celui-ci avec la commande:

make modules_install INSTALL_MOD_PATH=<chemin vers le rootfs>

mais j'y reviendrai plus tard.

3 - Le rootfs

3.1 - Présentation des outils GNU

 Richard Stallman

GNU est un projet initié en 1983 par Richard Stallman, visant à développer un système d'exploitation complet et libre fortement inspiré d'UNIX. Ce projet comporte d'une part la réalisation d'un noyau système (Hurd) et d'autre part la réalisation des applicatifs utilisateurs nécessaires. Ces applicatifs utilisateurs peuvent s'interfacer avec d'autres noyaux système que Hurd, comme Linux et kfreeBSD.

3.2 - Busybox, les outils GNU pour l'embarqué

 

3.3 - Création complète du rootfs

 

4 - Le boot

4.1 - Généralités sur le boot d'un système ARM

 

4.2 - Spécificités du Raspberry PI

 

5 - Finalisation de notre firmware

5.1 - Création de la carte SD

 

5.2 - Boot à travers le réseau

 Nous savons maintenant comment créer une carte SD complète contenant tous le logiciel nécessaire au bon fonctionnement de notre projet embarqué. Toutefois, lors de la phase de développement d'un projet quelconque, nous sommes amenés à apporter souvent des modifications à notre firmware afin d'y apporter des améliorations ou de corriger des bogues. Il peut alors être fastidieux de créer, flasher, insérer une carte SD à chaque étape itérative. Aussi, durant les étapes de développement, nous préférerons démarrer sur un rootfs qui se trouve sur une machine distante afin de pouvoir le modifier à volonté.