Linux embarqué
Tout autour de nous, l'électronique est de plus en plus présente : téléphones portables, organiseurs électroniques... Même les réfrigérateurs se mettent à surfer sur Internet ! Le mot d'ordre est : plus petit , moins cher, plus puissant. Sur ce point, l'informatique vient souvent à la rescousse de l'électronique en remplaçant des systèmes matériels par du logiciel.
Mais comme vous le savez certainement, et à moins de réinventer la roue, un programme a besoin d'un composant logiciel essentiel : le système d'exploitation. Aujourd'hui, de par ses caractéristiques, Linux est en passe de devenir le système d'exploitation de référence sur les systèmes dits "embarqués".
Système embarqué
Que signifie donc "système embarqué" ? C'est une traduction (approximative) de l'expression anglaise "embedded system". Il conviendrait plutôt de parler de "système intégré" ou "système dédié", par opposition à "système ouvert multi-usage", comme l'ordinateur de bureau. Donc, quand on parle de "système embarqué", il faut souvent y associer des notions comme :
- le faible encombrement ;
- la faible consommation ;
- la robustesse ;
- la simplicité...
Pourquoi Linux ?
Face à des alternatives commerciales, Linux possède de sérieux atouts :
- Prix - Tout d'abord, et n'ayons pas peur de le dire, Linux est gratuit, et peut être distribué sans avoir à reverser de "royalties", ce qui est important pour des systèmes destinés à être fabriqués en grande série, et où chaque coût supplémentaire doit être évité.
- Stabilité - Utilisé sur des millions de machines à travers le monde, y compris sur des serveurs disponibles en permanence, Linux a largement prouvé sa stabilité et sa solidité.
- Efficacité - Linux est un système d'exploitation intégrant les toutes dernières technologies permettant d'améliorer la gestion des ressources : mémoire, fichiers, processus. Avec Linux, pas besoin de "défragmenter" un disque, ou pas de plantage parce qu'une application ne libère pas la mémoire allouée ;-)
- Scalabilité - Aujourd'hui, Linux tourne sur des machines allant de l'organiseur électronique aux mainframes, ce qui prouve bien la modularité de son design.
- Modèle "Open Source" - Ceci n'est aujourd'hui heureusement plus à prouver, le modèle de développement "Open Source" marche. Certes, il n'y a pas de support direct d'un logiciel, mais grâce à Internet, la réponse à un problème est souvent bien plus rapide et pertinente que si l'on s'adresse à une "hotline" propriétaire. La possibilité donnée de comprendre le fonctionnement interne d'un programme conduit à une saine émulation (quelquefois compétition) permettant de résoudre les problèmes les plus complexes, et tend à améliorer la qualité du logiciel.
- Pilotes - Dans une situation où les composants électroniques évoluent rapidement, les constructeurs n'ont pas le temps de fournir les pilotes logiciels pour tous les systèmes d'exploitation existants. Seuls les plus courants sont développés, souvent Windows® et Linux. Or, Linux offre l'avantage que ces pilotes existent souvent en modèle "Open Source", et sont donc facilement modifiables ou adaptables, si le besoin s'en faisait sentir.
- Chaîne de développement : Contrairement à ses homologues commerciaux, Linux fournit en standard tous les outils de développement nécessaires. De plus, la "cross-compilation" (compilation pour une machine cible différente de la machine qui sert à générer un programme) est prévue d'emblée.
C'est donc tout naturellement que le petit pingouin est en train de grignoter le marché des systèmes embarqués, au grand dam des éditeurs de logiciels commerciaux. En ce sens, le phénomène est comparable à la percée de Linux dans le domaine des serveurs, à ceci près que cela risque de nous toucher d'encore plus près : dans notre poche, sur le bureau, sur l'oreille...
Si le choix de Linux paraît donc aujourd'hui évident, cela ne signifie pas pour autant que tous les problèmes soient résolus... En effet, pratiquement chaque système embarqué possède ses propres spécificités. D'abord sa fonction, ensuite ses contraintes en termes de mémoire, d'affichage, de réseau, de vitesse... Si bien qu'il est difficile de créer un système Linux embarqué valable pour tous.
Par contre, le concepteur d'un système de ce type sera toujours confronté aux mêmes choix, auxquels il apportera une réponse adaptée à ses besoins. Je vous propose donc ici de décrire la démarche à effectuer pour développer un système embarqué.
Distributions Linux
Plutôt que de recréer un système de toutes pièces, il est bon de se demander si une distribution standard ne pourrait pas répondre aux besoins du système. Il est toujours bon de se poser la question, lorsque les contraintes de place ne sont pas trop importantes : inutile dans ce cas de créer un système spécifique, il suffit en général d'épurer tous les paquetages superflus...
Inconvénients des distributions standards
Cependant, dans la plupart des cas, cette solution ne sera pas satisfaisante. Ces distributions, adaptées à des stations de travail ou à des serveurs, ont des tendances à la "boulimie" : destinées à des ordinateurs multi-usages, elles regroupent tout un tas de paquetages inutiles dans un système embarqué, dont l'utilisation et les ressources sont connues à l'avance. Ces paquetages ont de plus la fâcheuse tendance à avoir de nombreuses dépendances, et il est la plupart du temps difficile de n'installer que le strict minimum.
Disquettes de démarrage
Vous trouverez également de nombreux projets visant à créer des disquettes de démarrage, où les concepteurs tentent de mettre un maximum de fonctions sur une disquette. En général, celles-ci n'ont qu'une utilisation bien précise : démarrer un ordinateur sans disque fonctionnel installé. Pour ce faire, la technique employée consiste à mettre un noyau avec un RAMDisk initial compressé sur la disquette. Ainsi, lors du démarrage sur disquette, le noyau est lancé avec un système de fichier en RAM. L'inconvénient de cette approche pour un système embarqué est que ce système de fichier, bien que rentrant sur la disquette compressé, peut avoir une taille rédhibitoire. De même, à l'exécution, la facteur taille n'est en général pas important, car ces disquettes sont destinées à être utilisées sur des ordinateurs équipés d'une bonne quantité de mémoire.
Temps réel ou pas ?
De nombreux projets de systèmes embarqués revendiquent la dénomination de "système temps réel". Bon, soyons réaliste : avez-vous besoin d'un temps de réveil de tâche déterministe et de l'ordre de la dizaine de microsecondes ? Si non, passez au paragraphe suivant !
Dans l'autre cas, qui se rencontre généralement dans des systèmes d'asservissement rapides, il faut savoir que Linux même est incapable de telles performances. L'approche consiste alors à utiliser un noyau "temps réel" acceptant ces contraintes, qui vient se placer entre le matériel et les couches basses de Linux.
Linux n'est alors qu'une tâche non prioritaire de ce noyau temps réel. C'est ainsi que fonctionne par exemple la distribution
RTLinux et son homologue embarqué Mini-RTLinux.
Répétabilité
A la lecture de cet article, vous vous apercevrez bien vite que la création d'un système embarqué consiste à assembler un bon nombre de programmes, de fichiers et de répertoires divers. On peut donc imaginer effectuer ces opérations manuellement, sans avoir recours à une distribution quelconque. Bien sûr, cet exploit est réalisable un soir (une nuit ?) de grande forme, mais comme l'expérience vous le montrera assez rapidement, la création d'un tel système se fait souvent par essais successifs... Dans ce cas, mieux vaut prévoir dès le départ un système permettant de reproduire de manière certaine une même installation : on parle alors de répétabilité.
La distribution
PeeWee Linux est un exemple de distribution assurant un tel service : à l'aide de menus ressemblant aux "menuconfig" du noyau Linux, vous pouvez choisir les paquetages (et même chaque fichier individuel) à installer, et sauvegarder chaque configuration dans des projets distincts. C'est pour cette raison que je conseillerai cette distribution aux débutants.
Il est également possible de créer des "super-makefile", chargés de produire la distribution finale à partir des paquetages individuels. Mais cette méthode est plutôt à réserver aux spécialistes...
Plate-forme
Contrairement aux ordinateurs de bureau, le but lorsqu'on conçoit un système embarqué est d'obtenir une configuration de machine la plus petite possible permettant de faire marcher les applications désirées. On peut même dire que si vous ne rencontrez pas de problème de taille (mémoire, disque...), c'est que vous n'avez pas choisi le bon système ! Passons donc en revue les différentes options possibles :
PC de bureau
D'abord, il convient de considérer les PC de bureau standards. Je ne parle pas forcément d'un PC dernier cri, mais peut-être d'un vieux 386 ou 486 qui traîne dans votre grenier ou votre cave... Savez-vous que vous pouvez très bien le recycler en quelque chose d'utile : un routeur, par exemple ! Voyez à ce sujet le "Linux Router Project" (LRP).
Ceci dit, dans la plupart des cas, cette solution est un peu trop luxueuse... sans parler de la taille, de la consommation, du bruit, de la résistance aux chocs...
Organiseurs de poche
Il existe aujourd'hui de nombreux petits organiseurs de poche, fonctionnant de base avec des systèmes d'exploitation tels que Windows CE®, EPOC® ou PalmOS®. Pour certains d'entre eux, vous pouvez remplacer le système d'exploitation par une version de Linux : voir l'article de Christophe Le Cannellier dans Linux Magazine France n°26 pour le iPaQ, ou le projet ArmLinux.
Cartes spécialisées, dont PC104
Il est aujourd'hui relativement aisé de trouver des cartes bon marché comprenant toutes les fonctionnalités d'un ordinateur, voire d'un PC standard. Ces machines sont basées sur des processeurs ARM, 80x86 ou autres, dont beaucoup supportent Linux.
A noter parmi toutes ces cartes, celles qui supportent le standard PC104 : il s'agit d'une norme décrivant les caractéristiques mécaniques des cartes (10 cm x 10 cm), le moyen de les assembler par empilage, ainsi que les caractéristiques électroniques du connecteur inter-cartes (il s'agit en gros d'un bus PCI). L'intérêt principal réside surtout dans le fait qu'un grand nombre de constructeurs respectent ce standard, et donc qu'il est aisé de trouver ce que l'on cherche à un prix très compétitif. Par exemple, on peut trouver une carte à base de 80386/25MHz, 8 Mo RAM/8 Mo Flash, 2 RS232, 1 port //, 1 IDE, 1 floppy, pour moins de 2000 FF... sans compter la consommation (moins d'1A/5V).
Cartes personnalisées
Si vous êtes électronicien, il est toujours possible de fabriquer vous-même votre carte à base de microprocesseur. Sachez seulement qu'à moins d'envisager des volumes de production élevés, ce n'est en général plus rentable : les composants s'achètent par barrettes entières, même s'il ne vous en faut qu'un... Et puis, cela oblige à surveiller l'obsolescence de tous les composants. Il faut également prendre en compte le design, les tests, le circuit imprimé (souvent de l'ordre de 1000 FF à l'unité) et les tests !
Stockage
Quelle que soit la plate-forme choisie, il est certain que vous aurez besoin de stocker des informations de manière permanente : votre programme d'application, des données, des paramètres... Voici les alternatives possibles :
Disque dur
C'est la solution de stockage la moins coûteuse, et celle offrant les plus grandes capacités. Hélas, les disques durs magnétiques sont souvent peu recommandés pour des applications embarquées : ils sont encombrants, bruyants, sensibles aux chocs, à la température, aux rayonnements électromagnétiques et gourmands en énergie. De plus, une coupure d'alimentation au milieu d'une écriture peut avoir des conséquences désastreuses. Bref, les disques durs sont loin d'être les candidats idéaux, sauf si les contraintes ne sont pas trop fortes : il vaut donc mieux les oublier.
CompactFlash
Les CompactFlash sont des composants électroniques sans aucune mécanique, basés sur la technologie de mémoire Flash, et émulant un disque dur magnétique. On en trouve aujourd'hui beaucoup dans les appareils photo numériques. Petits, silencieux, résistants aux chocs, aux rayonnements et économes, ils semblent donc posséder toutes les qualités requises... sauf l'immunité en cas de coupure d'alimentation. En effet, les fabricants de tels composants ne font pas trop de tapage là-dessus, mais les CompactFlash ne sont absolument pas fiables en cas de coupure d'énergie intempestive : au mieux, vous obtiendrez des blocs défectueux irrécupérables (même après formatage) ; au pire, votre CompactFlash se transformera en carré de chocolat complètement inutilisable ! Ceci a malheureusement été démontré, ne vous engagez donc pas à la légère dans la voie de la facilité.
DiskOnChip®
Ces composants électroniques sont fabriqués à partir de puces de mémoire Flash, avec une logique intégrée de contrôle, qui permet de garantir une bonne résistance en cas de coupure d'alimentation. Ces composants intègrent également une extension BIOS qui permet de "booter" directement en mémoire Flash, lorsque ce composant est utilisé sur une carte mère compatible PC. Le fabricant de ce composant (M-Systems®) fournit des drivers pour Linux, ainsi qu'une documentation détaillée. Malheureusement, ces drivers ne sont pas "Open Source", et ne peuvent donc pas de ce fait être "linkés" avec le noyau Linux dans le but d'être distribués. En effet, la licence GPL de Linux interdit explicitement d'inclure un composant logiciel dont vous ne pouvez fournir les sources.
Il convient donc de faire très attention si vous voulez distribuer le système embarqué : vous devez pouvoir fournir les sources de tous les programmes en licence GPL que vous utilisez, mais également ne pas les polluer avec des morceaux de programmes dont vous n'avez pas les sources.
Cependant, il existe un moyen technique de contourner cette difficulté légale : il n'est pas interdit d'utiliser le driver dont vous ne possédez pas les sources en tant que module chargeable du noyau Linux. La ruse consiste donc à démarrer Linux avec un RAMDisk initial contenant ledit module et tout ce qu'il faut pour l'insérer en tant que module du noyau, de démarrer Linux sur cette partition, d'insérer le module, puis enfin de basculer la racine sur la partition du DiskOnChip®. Ouf ! Ceci est quelque peu tordu, mais est très bien expliqué dans les documentations disponibles sur le site Web du constructeur.
La dernière solution est d'utiliser un driver OpenSource, capable de gérer ce composant : il s'agit du driver
MTD (Memory Technology Device), disponible dans le noyau Linux depuis la version 2.4. Cela vous demandera certes plus de travail (oubliez la version intégrée dans le noyau et partez du CVS ;-)), mais vous aurez la satisfaction d'avoir un système complètement "OpenSource" !
Mémoires Flash
Ce même driver MTD peut également gérer les mémoires Flash brutes, c'est-à-dire celles ne comportant aucun dispositif électronique masquant les détails de leur fonctionnement. Car ces mémoires sont assez délicates à gérer : elles s'effacent par blocs relativement gros (64Ko ou plus), on ne peut programmer leurs bits que dans un sens (de 0 vers 1 ou de 1 vers 0, suivant la technologie employée), et le nombre d'effacements de blocs est limité (de l'ordre de 100 000). Ne pensez donc pas y écrire simplement vos fichiers par blocs de 512 octets, ceci n'est pas possible directement, sans l'aide du driver MTD.
Ces inconvénients mis à part, ces mémoires sont idéales pour des systèmes embarqués, et de plus, leur coût est inférieur aux CompactFlash ou DiskOnChip®.
Systèmes de fichiers
Nous avons évoqué dans les paragraphes précédents les problèmes liés à la coupure brutale d'alimentation sur les supports de stockage. Ceci ne représente qu'une partie du problème. En effet, la garantie de ne pas perdre de blocs de données sur le support ne suffit pas à obtenir un système résistant : la mise à jour d'un fichier nécessite toujours la mise à jour de plusieurs blocs sur le disque, et il faut envisager le cas où une partie des blocs seulement a pu être enregistrée. Le système de fichiers peut être corrompu, même si les blocs du disque sont intacts.
Système de fichier ext2
Le système de fichier "ext2" est le système de fichier par défaut de Linux. Efficace sur les stations de travail et les serveurs, il fournit une redondance des structures vitales, qui permet souvent de retomber sur un système cohérent après un arrêt brutal, grâce à un utilitaire de restauration "e2fsck". Cette procédure semi-automatique nécessite généralement l'intervention d'un administrateur système, ce qui dans le domaine qui nous intéresse est irréaliste. C'est pourquoi "ext2" n'est en général pas une bonne solution pour les systèmes embarqués.
Systèmes de fichiers journalisés : jffs et jffs2
La solution idéale se trouve en employant un système de fichiers journalisé. Sans rentrer dans les détails, chaque modification est enregistrée dans un "journal". En cas de coupure brutale, l'état du système de fichiers est comparé au journal, et les opérations non complètement achevées sont défaites. Ainsi, le système de fichiers se trouve toujours dans un état cohérent, même si des informations ont pu être perdues. Pour plus d'informations, reportez-vous au n°27 de Linux Magazine France.
Sur les "grosses" machines, le système de fichiers "reiserfs" constitue une solution de choix, notamment pour les serveurs sensibles. Malheureusement, il est beaucoup trop encombrant pour nos petites machines...
Heureusement, il existe une solution adaptée en OpenSource : les systèmes "jffs" et "jffs2" (
Journaling Flash File System ou JFFS). Développés à l'origine pour les mémoires Flash, qui ont la contrainte importante d'un nombre très limité de modifications d'une zone donnée (de l'ordre de 100 000 modifications), ces systèmes de fichiers ne récrivent jamais les données au même emplacement, et conservent les versions antérieures du fichier. Cette technique est donc parfaite en cas d'interruption brutale de la machine, car on possède toujours une version antérieure cohérente des données. De plus, ces systèmes ont été conçus dès le départ pour des systèmes aux ressources limitées. Aujourd'hui, ils font partie des modules MTD évoqués plus haut pour la mémoire Flash, et font partie intégrante du noyau Linux 2.4. Leur développement est toutefois assez instable, et demande de partir des derniers fichiers sous CVS, qui sont quelquefois cassés, mais vite réparés ;-).
Partition en lecture seule
Une dernière solution, qui peut être satisfaisante dans certains cas, consiste à utiliser des partitions en lecture seule, et à stocker les données variables dans des partitions réinitialisées à chaque démarrage : un RAMDisk, par exemple, ou encore la mémoire non volatile de l'horloge dans un PC (/dev/nvram). En effet, un système de fichiers que l'on ne peut modifier ne peut plus être corrompu !
Un article très intéressant de Christophe Blaess a été publié dans Linux Magazine France n° 20 ("Renforcer une station Linux face à un risque d'arrêt intempestif"), qui explique les problèmes liés à cette approche.
Démarrage
Bon, admettons que nous ayons un système de stockage de fichiers qui ne perde ni blocs, ni fichiers. Le problème suivant consiste à pouvoir lancer Linux au démarrage de la machine. Dans le cas d'une carte personnalisée, tout est possible, il suffit à un moment donné de passer la main au noyau Linux présent en ROM ou chargé depuis le support de stockage, après avoir un tant soit peu initialisé la carte. Nous ne nous étendrons donc pas sur ce cas, qui dépend étroitement de la plate-forme.
Dans le cas d'un disque dur matériel ou de mémoire les émulant (cas des mémoires CompactFlash), le problème est semblable à celui rencontré sur des PC "normaux".
En revanche, si le support de stockage est constitué de mémoire Flash, le problème est plus délicat. Le seul moyen de récupérer la main sur un PC, après l'initialisation, est d'avoir une "extension BIOS" qui va être reconnue par le BIOS en parcourant la mémoire. Cette extension BIOS peut être présente en ROM, ou dans le composant Flash lui-même (c'est le cas pour les DiskOnChip®).
Vous pouvez évidemment écrire cette extension de toutes pièces, et charger directement le noyau Linux avant de l'exécuter. Le problème est alors de trouver un emplacement en mémoire où stocker cette extension : en ROM ou sur la mémoire Flash, si celle-ci est accessible lors du démarrage de la machine.
L'approche adoptée par les constructeurs est en général différente : elle consiste à faire passer la mémoire Flash pour un disque dur DOS en "patchant" les points d'entrée du disque dur dans le BIOS. Dans la plupart des cas, le disque a un formatage propriétaire, non documenté (FlashFX®, par exemple). Dans certains cas, comme avec les DiskOnChip®, il est possible de "booter" directement sur une partition "ext2" ou "jffs2", et d'exécuter un "chargeur" (bootloader) :
Syslinux
Syslinux est un chargeur très facile à utiliser, puisqu'il s'agit d'un programme DOS, qui prend en argument un fichier de configuration et une image du noyau Linux, stockés également sous forme de fichier DOS. Il est donc particulièrement recommandé dans le cas où le démarrage fait appel à une extension BIOS ne fournissant qu'une compatibilité avec DOS, à l'exclusion de tout autre système de fichiers. Vous pouvez alors partitionner votre mémoire Flash en une petite partition DOS de démarrage, et le reste comme partition Linux, utilisée pour stocker vos fichiers.
Lilo
lilo est le chargeur par défaut de Linux. Dans le cas où vous démarrez à l'aide d'une extension BIOS avec un formatage documenté, vous pouvez utiliser une variante de lilo adaptée au composant et au système de fichiers que vous utilisez : pour les DiskOnChip®, doc-lilo et mtd-lilo, pour les partitions "ext2" et "jffs2", respectivement.
Grub
grub remplit la même fonction que lilo. Il a cependant l'avantage de reconnaître le système de fichiers pour rechercher le noyau à lancer, alors que lilo nécessite de spécifier le bloc initial contenant le noyau, information qui doit être ajustée à chaque modification du noyau Linux. grub est capable de démarrer sur une partition "ext2", et théoriquement sur une partition "jffs2", bien que cela soit un peu expérimental... Le gain par rapport à l'utilisation de lilo dans un système embarqué n'est cependant pas flagrant, surtout si l'on considère la somme des autres problèmes à résoudre !
Noyau Linux
Le noyau Linux constitue le c ur du système : il faut donc apporter une attention toute particulière à sa configuration. Même si les partisans du HURD objecteront que Linux n'est pas un micro-noyau mais un noyau monolithique, en pratique, Linux peut être configuré de manière à réduire sa taille de manière significative.
Contrairement aux ordinateurs de bureau, les systèmes embarqués ont l'avantage de posséder une configuration matérielle connue et figée. Ceci permet d'éliminer sans remord tous les modules non nécessaires : si vous n'avez pas de carte réseau, vous pouvez éliminer tout ce qui concerne le réseau. La même chose avec le SCSI, l'USB et tous les autres périphériques. Et même si vous disposez de certaines interfaces non utilisées de manière courante, vous pouvez toujours les intégrer en tant que module chargeable, de manière à limiter la taille du noyau en mémoire. Appliquez une méthode minimaliste : lancez la configuration du noyau, et affichez l'aide pour chaque option proposée, en partant du principe que vous n'en avez pas besoin, quitte à la rajouter si le besoin se fait sentir. Vous obtiendrez alors un noyau "dégraissé" d'à peu près 500 Ko.
Il est possible d'optimiser encore plus le noyau, car tout le code inutile ne figure malheureusement pas dans le menu de configuration ;-). Un exemple : le support pour les disquettes 360Ko ! Le meilleur moyen consiste à survoler les sources, et rechercher des pans entiers de code inutile, et de supprimer de manière conditionnelle les plus gros.
Vous pouvez aller encore plus loin, car Linux possède un grand nombre de constantes qui définissent la taille de certaines ressources, qui peuvent être diminuées sans conséquences néfastes sur un système embarqué. Vous pouvez par exemple faire un "grep" récursif de "#define NR_", "#define N_" et "#define MAX_" dans les sources du noyau : vous tomberez sur la plupart des constantes en question...
Un exemple de telles optimisations est réalisé par
ETLinux. Je ne pourrais que vous conseiller d'appliquer ces modifications sous forme de "patch", de manière à pouvoir les appliquer facilement en cas de changement de noyau.
Vous pouvez également décider d'utiliser une version de noyau plus ancienne, en général plus petite. Cette méthode n'est pas à conseiller, car même si elles sont plus grosses, n'oubliez pas que les nouvelles versions corrigent des problèmes !
Bibliothèques
Le noyau Linux seul ne permet pas de faire tourner un programme : celui-ci utilise en général un ensemble de bibliothèques "linkées", qui permettent l'accès au noyau. La plus importante est la "libc", qui contient la grande majorité des fonctions POSIX.
Dynamiques ou statiques ?
Les bibliothèques peuvent être "linkées" à un programme de deux manières différentes : soit statiquement, soit dynamiquement. Dans le cas du lien statique, chaque programme intègre dans le fichier exécutable les fonctions dont il a besoin pour son propre usage. Dans le cas du lien dynamique, le fichier exécutable ne comporte que les points d'entrée et de quoi charger les bibliothèques nécessaires à la demande, celles-ci étant présentes dans des fichiers distincts et partagées par tous les programme y faisant appel.
Sur un ordinateur standard, lançant beaucoup de programmes simultanément, cette solution est de loin la meilleure, car elle permet de réduire considérablement les temps de chargement des exécutables, et d'optimiser la place en mémoire en partageant ce qui peut l'être entre les différents programmes.
Cela doit être remis en question sur les systèmes embarqués : en effet, la plupart du temps, seuls quelques programmes tournent de manière simultanée. Dans ce cas, la solution statique est généralement meilleure, car vous n'avez pas besoin de bibliothèques séparées, qui peuvent avoir une taille non négligeable, notamment la "libc" standard, qui pèse quelques 4 Mo.
Bibliothèques alternatives
Face à la boulimie de la "libc" standard, il existe plusieurs bibliothèques alternatives, dont le but est de fournir une partie des fonctionnalités de la bibliothèque originale, avec une taille réduite. C'est le cas de la "µclibc". Sachez toutefois que celles-ci sont en général très limitées, et ne conviennent pas à des programmes sophistiqués.
Mklibs
Une technique intéressante consiste à essayer de dégraisser les bibliothèques. En effet, celles-ci sont composées de modules distincts, bien que possédant des dépendances. Le script "mklibs.sh" utilisé pour générer la disquette de démarrage de la distribution Debian est à ce titre très intéressant. Le principe est de créer un graphe des dépendances d'une arborescence d'exécutables et de bibliothèques, et de créer une version des bibliothèques débarrassée des modules inutiles. Bien sûr, cette approche est très spécifique à un système, et demande à être effectuée à nouveau à chaque changement d'un exécutable ou d'une bibliothèque. Cela doit donc plutôt être effectué lorsque le système est stable, avant de le diffuser.
A noter qu'une version C++ existe (
Mklibc), bien plus rapide.
Init
A l'issue du lancement et de l'initialisation du noyau Linux, celui-ci va à son tour lancer la première tâche utilisateur. En général, il s'agit d'un programme nommé "init", placé dans le répertoire /sbin, bien que l'on puisse spécifier son nom et son emplacement en passant des paramètres au noyau.
Init personnalisé
Il est tout à fait possible de lancer un programme personnalisé, chargé de réaliser la fonction pour laquelle le système est prévu. Si ce programme n'a été généré qu'avec des bibliothèques statiques, il se suffit à lui-même. Dans le cas où il utilise des bibliothèques dynamiques, celles-ci devront évidemment être présentes sur le système. Ce programme aura pour charge de lancer toutes les tâches sur la machine. Cette solution peut être acceptable dans le cas où la fonction du système embarqué est très spécifique, mais manque beaucoup de souplesse : si vous désirez lancer une nouvelle tâche, vous devrez modifier ce programme compilé.
Init avec configuration
C'est pourquoi une solution utilisant un script de configuration est préférable. Sur les systèmes Unix, le script /etc/inittab définit les différentes tâches à lancer par la tâche init, comme les différents terminaux virtuels accessibles par la combinaison de touches "Ctrl + Alt + Fx", le serveur graphique X11... Ainsi, il est beaucoup plus facile de modifier les tâches lancées avec un simple éditeur de texte.
Cette possibilité, bien qu'un peu plus complexe que la précédente, est tout de même très intéressante dans un système embarqué, car elle ne nécessite peu ou pas de ressources supplémentaires (la présence d'un interpréteur de commandes "shell" n'est pas nécessaire).
Init "System V"
Unix "System V" utilise le principe du fichier de configuration d'init /etc/inittab, et va même plus loin, en définissant des "niveaux d'exécution" : mono-utilisateur, multi-utilisateur, multi-utilisateur avec réseau, multi-utilisateur avec réseau et interface graphique, reboot, arrêt. A chaque niveau est associé un répertoire /etc/rc.d/rc.x (où "x" est le niveau en question) contenant des scripts shell organisés par priorité. Pour chaque niveau, ces scripts sont chargés de lancer ou d'arrêter les services assurant le fonctionnement de la machine pour ce niveau d'exécution.
Ce mécanisme, s'il est adapté aux stations de travail et aux serveurs, est un peu luxueux pour un système embarqué, où les niveaux d'exécution n'ont que peu d'intérêt, et où le nombre de services à lancer est réduit. De plus, la présence d'un interpréteur de commandes est presque obligatoire.
Shell
Contrairement aux ordinateurs normaux, la présence d'un interpréteur de commandes "shell" dans un système embarqué n'est pas une nécessité. En effet, ces systèmes ne sont pas destinés à interagir avec un opérateur tapant des commandes au clavier, qui souvent n'existe même pas !
Cependant, la présence d'un "shell" peut s'avérer intéressante : par rapport à un programme compilé réalisant de nombreuses opérations, un ensemble de scripts interprétés avec un interpréteur sont souvent plus petits. Les possibilités de débogage sont aussi plus importantes, et permettent de raccourcir le sempiternel cycle "édition / compilation / link / transfert / débogage".
L'interpréteur de commande "bash" utilisé sur les ordinateurs normaux peut être employé (il n'a pas une taille énorme), mais si vous n'avez pas besoin de la fonction d'historique des commandes tapées, il peut être avantageusement remplacé par une version légère "
ash". En outre, la syntaxe de "ash" est compatible avec son grand frère, ce qui facilite le portage des scripts.
Commandes shell
Si certaines commandes du shell sont intégrées à l'interpréteur de commande shell, la plupart de ces commandes sont en fait des programmes externes sur les ordinateurs normaux.
Commandes standard
Les commandes externes peuvent bien sûr être utilisées telles quelles, mais il est intéressant de remarquer deux points :
- ces nombreuses commandes sont en général des programmes de taille modeste ;
- certaines commandes possèdent de nombreuses options inutilisées.
Busybox
Busybox est un programme intégrant de nombreuses commandes shell en un unique fichier exécutable. Ceci a pour but de diminuer la taille nécessaire, par rapport aux commandes shell standard. En effet, chaque fichier exécutable individuel contient un en-tête de chargement, dont la taille est loin d'être négligeable par rapport aux instructions du programme proprement dit. En regroupant les commandes en un seul fichier, cet en-tête n'existe qu'en un unique exemplaire.
Les commandes shell incorporées dans Busybox ne possèdent pas toutes les options des commandes externes équivalentes, mais en pratique, elles s'avèrent plus que suffisantes. Il est également possible de ne compiler dans Busybox que les commandes que l'on désire.
C'est pourquoi, Busybox est rapidement devenu le véritable "couteau suisse" des systèmes embarqués.
Tinylogin
Tinylogin complète généralement Busybox, en fournissant sur le même principe un complément de commandes shell pour la gestion des connexions et des utilisateurs (getty, adduser, deluser, passwd...).
Editeur
Sur un système Unix, la présence d'un éditeur est presque obligatoire, car la grande majorité des fichiers de configuration est composée de fichiers texte. S'il vous reste un peu de place de disponible sur votre système, l'éditeur "e3" est à recommander : en moins de 12 Ko, il fournit un éditeur avec des raccourcis compatibles avec vi, emacs et wordstar (excusez du peu !).
Interface graphique
Sur les systèmes embarqués possédant un écran, il est possible d'intégrer une interface graphique. Il convient de faire très attention, car les capacités requises en terme de mémoire sont importantes. Dans le cas d'une machine en réseau, il est souvent beaucoup moins coûteux d'intégrer un serveur Web simple comme mini-httpd, et de réaliser l'interface avec l'utilisateur par le biais d'un navigateur.
X11
Le système d'interface graphique client / serveur X11 est peu adapté aux systèmes embarqués : l'ensemble des programmes, des bibliothèques et des polices de caractères nécessaires est souvent énorme, même si quelques distributions arrivent à faire tenir Linux et X11 en moins de 8 Mo...
Nano-X et Microwindows
C'est pourquoi une alternative mono-poste, orientée vers les petits systèmes a été lancée. Il s'agit du couple Nano-X et MicroWindows, tous les deux basés sur une bibliohtèque commune fonctionnant avec les "framebuffers" de Linux, et qui fournissent une interface de programmation proche de X11 et Windows®, respectivement.
Malheureusement, la description de ces deux produits nécessite un article complet, et ne peuvent donc pas être traités ici.
Optimisations
Sur les ordinateurs standard, il faut savoir que les exécutables et les bibliothèques ne sont guère optimisés et comportent par exemple des informations de débogage ou des commentaires. Il est facile de diminuer sans trop de fatigue la taille de ces fichiers en utilisant la commande strip, qui supprime ces informations sans modification apparente pour l'utilisateur normal. Cette opération est donc fortement recommandée dans le cas des systèmes embarqués.
L'emploi d'un utilitaire d'épuration de bibliothèques partagées ("mklibs") est également intéressant, comme nous l'avons déjà indiqué plus haut.
Conclusion
Comme vous pouvez le constater si vous avez eu le courage de suivre cet article jusqu'à son terme, l'assemblage d'un système Linux embarqué est un véritable puzzle. De nombreuses contraintes existent, que chacun résoudra à sa manière. Il s'agit encore d'un domaine où beaucoup de recherches restent à faire.
Cet exercice est toutefois très intéressant, car il permet d'appréhender la connaissance complète d'une machine Linux. La complexité des systèmes embarqués étant nécessairement réduite, ils constituent une base intéressante d'expérimentation tout en gardant une échelle humaine, et offrent des débouchés industriels presque immédiats.
En résumé, j'espère que comme moi, vous conviendrez que "ce qui est petit est joli" !
Michel Stempin
mstempin@com1.fr
Références
RTLinux
http://www.rtlinux.org
MiniRTL
http://www.rtlinux.org/minirtl.html
PeeWeeLinux
http://embedded.adis.on.ca
LRP
http://master-www.linuxrouter.org:8080
ArmLinux
http://www.arm.uk.linux.org/~rmk
M-Systems
http://www.m-sys.com
MTD
http://www.linux-mtd.infradead.org
JFFS
http://developer.axis.com/software/jffs
Syslinux
http://syslinux.zytor.com
ETLinux
http://www.etlinux.org
µclibc
http://cvs.uclinux.org/uClibc.html
Mklibs
http://www.croftj.net/~fawcett/yard/reducing_glibc.html
http://cvs.debian.org/boot-floppies/scripts/rootdisk/mklibs.sh?sortby=file
Mklibc
http://www.lpsg.demon.co.uk/linux
Ash
http://linuxberg.surfnet.nl/conhtml/adnload/8049_31517.html
Busybox
http://busybox.lineo.com
Tinylogin
http://tinylogin.lineo.com
E3
http://www.sax.de/~adlibit
mini-httpd
http://www.acme.com/software/mini_httpd
Nano-X
MicroWindows
http://www.microwindows.org