Pierre Ficheux (pierre@alienor.fr)
Septembre 2000
La banalisation des performances a quelques effets pervers:
La tendance n'épargne pas les systèmes LINUX dont les distributions les plus célèbres prennent de plus en plus de poids. J'ai longtemps utilisé ma première distribution avec un kernel 0.99 puis 1.0 sur un 486SX25 avec 8Mo de RAM, peux-t-on l'imaginer sur les distributions standards d'aujourd'hui ?
Un avantage notable avec LINUX est la complète transparence du système. Un utilisateur averti pourra à partir d'une configuration standard créer un système très optimisé tant au niveau de l'espace disque que de la mémoire utilisée. A partir d'un certain niveau extrème de réduction, on pourra parler de système embarqué (embedded ou embeddable).
Cependant, l'évolution du matériel permet aujourd'hui d'envisager des systèmes d'exploitation embarquées ayant les même caractéristiques qu'un système utilisé sur une machine classique, ce qui présente un triple intérêt:
Cette même évolution permet d'envisager une migration rapide des produits de large consommation: téléphonie, audio, vidéo, electro-ménager, équipement automobile vers des versions plus évoluées et communicantes (les internet appliances). Un certain nombre d'applications de ce type sont citées à la fin de l'article.
Concernant la cible du système définitif, diverses solutions sont disponibles:
La structure générale simplifiée d'un système LINUX est la suivante:
La réduction du système passe par les étapes suivantes:
# System initialization (runs when system boots). si:S:sysinit:/etc/rc.d/rc.S
drwxr-xr-x 2 root root 1024 fév 10 2000 init.d -rwxr-xr-x 1 root root 1593 jun 7 1998 rc -rwxr-xr-x 1 root root 1175 aoû 1 14:29 rc.local -rwxr-xr-x 1 root root 7355 jun 18 1998 rc.sysinit drwxr-xr-x 2 root root 1024 fév 10 2000 rc0.d drwxr-xr-x 2 root root 1024 fév 10 2000 rc1.d drwxr-xr-x 2 root root 1024 fév 10 2000 rc2.d drwxr-xr-x 2 root root 1024 aoû 4 14:53 rc3.d drwxr-xr-x 2 root root 1024 aoû 4 14:53 rc4.d drwxr-xr-x 2 root root 1024 aoû 4 14:53 rc5.d drwxr-xr-x 2 root root 1024 fév 10 2000 rc6.d
La gestion de ce système est cependant relativement complexe pour un système embarqué comprenant normalement très peu de services à démarrer. Dans notre cas, les scripts de démarrage seront tous localisés dans le répertoire /etc/rc.d:
-r-xr-xr-x 1 root root 1634 mai 24 15:06 rc.S -rwxr-xr-x 1 root root 1148 mai 24 11:45 rc.inet1 -rwxr-xr-x 1 root root 264 mai 24 11:45 rc.inet2et les fichiers de configuration associé dans le répertoire /etc/sysconfig:
-rw-r--r-- 1 root root 41 mai 24 11:45 keyboard -rw-r--r-- 1 root root 181 mai 24 11:45 network
Le script rc.S effectue les actions suivantes:
# Start update. /sbin/update &
# Check the integrity of all filesystems /sbin/fsck -A -a -T
# Remount the root filesystem in read-write mode /sbin/mount -w -n -o remount / /sbin/mount -at nonfs
# Network /etc/rc.d/rc.inet1 start /etc/rc.d/rc.inet2 start
# Shell /bin/sh
Les scripts rc.inet1 et rc.inet2 sont appelés en fin du script rc.S pour l'initialisation du réseau:
La configuration du réseau est définie dans le fichier network:
HOSTNAME=myname DOMAINNAME=some.where DEVICE=eth0 IPADDR=192.168.1.1 NETWORK=192.168.1.0 GATEWAY= NETMASK=255.255.255.0 BROADCAST=192.168.1.255 DNS1= DNS2=
Le démarrage du réseau se fait de manière classique par l'initialisation de l'interface locale:
# Loopback /sbin/ifconfig lo 127.0.0.1 /sbin/route add -net 127.0.0.0 /sbin/ifconfig lo up
Si une adresse IP fixe est définie, on initialise l'interface ethernet, le routage ainsi qu'éventuellement le DNS (fichier /etc/resolv.conf):
# Ethernet if [ "$IPADDR" != "" ] then /sbin/ifconfig ${DEVICE} ${IPADDR} broadcast ${BROADCAST} netmask ${NETMASK} /sbin/route add -net ${NETWORK} netmask ${NETMASK} /sbin/ifconfig ${DEVICE} up # external addresses if [ "$GATEWAY" != "" ] then /sbin/route add default gw ${GATEWAY} fi fi # DNS if [ "$DNS1" != "" ]; then echo "nameserver $DNS1" >> $RESOLV fi if [ "$DNS2" != "" ]; then echo "nameserver $DNS2" >> $RESOLV fi
Dans le cas d'un système embarqué, il est très intéressant de pouvoir gérer une connexion DHCP (adresse IP dynamique), très utilisée pour les internet appliances. Il suffira pour cela de ne pas définir d'adresse dans le fichier network:
if [ "$DEVICE" != "" -a "$IPADDR" = "" ]; then echo -n "Using DHCP for ${DEVICE}" /sbin/dhcpcd ${DEVICE} for i in 1 2 3 4 5 6 7 8 9 10 11 12 do echo -n "." if [ -r /etc/dhcpc/hostinfo-${DEVICE} ]; then DHCP_OK=true break fi sleep 5 done if [ "$DHCP_OK" = "" ]; then echo "ERROR !" else echo "OK." fi fi
En général, les commandes indispensables au démarrage du système se trouvent sur le répertoire /sbin:
-rwxr-xr-x 1 root root 25144 mai 24 11:45 dhcpcd -rwxr-xr-x 1 root root 69252 mai 24 11:45 e2fsck -rwxr-xr-x 1 root root 9008 mai 24 11:45 fsck -r-xr-xr-x 1 root root 18761 mai 24 11:45 ifconfig -r-xr-xr-x 1 root root 16757 mai 24 11:45 inetd -r-xr-xr-x 1 root root 20592 mai 24 11:45 init -rwxr-xr-x 1 root root 58744 mai 24 11:45 lilo -rwsr-xr-x 1 root root 36084 mai 24 11:45 mount -r-xr-xr-x 1 root root 9513 mai 24 11:45 route -rwsr-xr-x 1 root root 20200 mai 24 11:45 umount -rwxr-xr-x 1 root root 7077 mai 24 11:45 update
On trouve sur le répertoire /bin les commandes moins orientées systèmes dont le nombre dépendra de l'utilisation du système:
-rwxr-xr-x 1 root root 62660 mai 24 11:44 ash -r-xr-xr-x 1 root root 7737 mai 24 11:44 cat -rwxr-xr-x 1 root root 9232 mai 24 11:44 chmod -rwxr-xr-x 1 root root 19652 mai 24 11:44 cp -rwxr-xr-x 1 root root 5268 mai 24 11:44 free -rwxr-xr-x 1 root root 64161 mai 24 11:44 grep -r-xr-xr-x 1 root root 5696 mai 24 11:44 hostname -rwxr-xr-x 1 root root 10644 mai 24 11:44 ln -r-xr-xr-x 1 root root 26976 mai 24 11:44 ls -r-xr-xr-x 1 root root 7416 mai 24 11:44 mkdir -rwsr-xr-x 1 root root 36084 mai 24 11:44 mount -rwxr-xr-x 1 root root 12464 mai 24 11:44 mv -r-xr-xr-x 1 root root 28948 mai 24 11:44 ps -rwxr-xr-x 1 root root 9424 mai 24 11:44 rm -rwxr-xr-x 1 root root 53672 mai 24 11:44 sed lrwxrwxrwx 1 root root 4 mai 24 11:44 sh -> ash -rwxr-xr-x 1 root root 4421 mai 24 11:44 sleep -rwxr-xr-x 1 root root 380 mai 24 11:44 sync -rwxr-xr-x 1 root root 10713 mai 24 11:44 tail
Le choix des commandes dépend directement de l'applicatif final installé sur le système, en particulier:
Le choix des bibliothèques à conserver est plus compliqué dans la mesure ou il faut connaitre exactement les bibliothèques utilisées par les programmes restants. On peut faire cela par la commande ldd:
[pierre@atkins pierre]$ ldd /sbin/init libutil.so.1 => /lib/libutil.so.1 (0x40007000) libc.so.6 => /lib/libc.so.6 (0x4000a000) /lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x00000000) [pierre@atkins pierre]$ ldd /bin/cat libc.so.6 => /lib/libc.so.6 (0x40007000) /lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x00000000)
Il faut noter que l'ajout de commandes supplémentaires peut entrainer l'ajout de biblitohèques partagées, exemple pour le client telnet:
[pierre@atkins pierre]$ ldd /usr/bin/telnet libncurses.so.4 => /usr/lib/libncurses.so.4 (0x40007000) libc.so.6 => /lib/libc.so.6 (0x40045000) /lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x00000000)Notons également que les distributions les plus récentes sont en général plus gourmandes en espace disque. Ceci s'explique le plus souvent par des fonctionnalités supplémentaires ou bien une meilleure modularité dans les bibliothèques utilisées mais dans le cas de la construction d'un système embarquée, les contraintes de ce type sont moins prépondérantes et le critère d'espace utilisé est souvent le plus important.
On peut donc se poser la question de la bibliothèque C à utiliser. Les anciennes distributions LINUX (comme la RedHat 4.2) utilisaient la libc5 alors que les distributions plus récentes (RedHat 5.x, compatibles, et suivantes...) utilisent la libc6 (ou glibc2). La glibc a apporté un grand nombre d'avantages concernant les fonctionnalités et la modularité mais le fait de baser un système embarqué sur la libc5 n'est pas forcément une aberration.
Le bibliothèques à utiliser dans de le case d'une distribution basé sur la glibc-2.0 sont les suivantes:
-rwxr-xr-x 1 root root 40452 jan 5 2000 ld-2.0.7.so lrwxrwxrwx 1 root root 11 mai 23 18:16 ld-linux.so.2 -> ld-2.0.7.so lrwxrwxrwx 1 root root 11 mai 23 18:16 ld.so -> ld.so.1.9.5 -rwxr-xr-x 1 root root 104236 jan 5 2000 ld.so.1.9.5 -rwxr-xr-x 1 root root 650524 jan 5 2000 libc-2.0.7.so lrwxrwxrwx 1 root root 13 mai 23 18:16 libc.so.6 -> libc-2.0.7.so -rwxr-xr-x 1 root root 181993 jan 5 2000 libcrypt-2.0.7.so lrwxrwxrwx 1 root root 17 mai 23 18:16 libcrypt.so.1 -> libcrypt-2.0.7.so -rwxr-xr-x 1 root root 37146 jan 5 2000 libdl-2.0.7.so lrwxrwxrwx 1 root root 14 mai 23 18:16 libdl.so.2 -> libdl-2.0.7.so -rwxr-xr-x 1 root root 35622 jan 5 2000 libproc.so.1.2.6 -rwxr-xr-x 1 root root 34674 jan 5 2000 libutil-2.0.7.so lrwxrwxrwx 1 root root 16 mai 23 18:16 libutil.so.1 -> libutil-2.0.7.so
et dans le cas de la libc5:
lrwxrwxrwx 1 root root 18 mai 24 11:45 ld-linux.so.1 -> ld-linux.so.1.7.14 -r-xr-xr-x 1 root root 21531 mai 24 11:45 ld-linux.so.1.7.14 lrwxrwxrwx 1 root root 12 mai 24 11:45 ld.so -> ld.so.1.7.14 -r-xr-xr-x 1 root root 24580 mai 24 11:45 ld.so.1.7.14 lrwxrwxrwx 1 root root 14 mai 24 11:45 libc.so.5 -> libc.so.5.4.44 -rw-r--r-- 1 root root 580816 mai 24 11:45 libc.so.5.4.44
De même il sera parfois nécessaire de recompiler certains applicatifs à partir des sources de manière à supprimer certaines fonctionnalités superflus qui peuvent augmenter la taille du code ou nécessiter l'ajout de bibliothèques partagées supplémentaires.
Prenons l'exemple des programmes login et passwd utilisés pour la validation des mots de passe:
[root@atkins /root]# ldd /bin/login libcrypt.so.1 => /lib/libcrypt.so.1 (0x40007000) libpam.so.0 => /lib/libpam.so.0 (0x40034000) libdl.so.2 => /lib/libdl.so.2 (0x4003b000) libpam_misc.so.0 => /lib/libpam_misc.so.0 (0x4003f000) libc.so.6 => /lib/libc.so.6 (0x40042000) /lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x00000000) [root@atkins /root]# ldd /usr/bin/passwd libpwdb.so.0 => /lib/libpwdb.so.0 (0x40007000) libpam.so.0 => /lib/libpam.so.0 (0x40048000) libpam_misc.so.0 => /lib/libpam_misc.so.0 (0x4004f000) libdl.so.2 => /lib/libdl.so.2 (0x40053000) libc.so.6 => /lib/libc.so.6 (0x40056000) libcrypt.so.1 => /lib/libcrypt.so.1 (0x400fb000) libnsl.so.1 => /lib/libnsl.so.1 (0x40128000) /lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x00000000)
Ce deux utilitaires utilisent PAM (Pluggable Authentification Module) qui impose la présence des bibliothèques et des fichiers de configuration correspondant. La recompilation de ces utilitaires SANS le support PAM peut simplifier la structure du système final.
L'absence totale d'outil de configuration sur le système (comme éditeurs de texte, clients ftp/telnet, etc...) peut se révèler très gènante lors de la mise au point de la plate-forme finale. Une solution simple est de définir un répertoire /extra sur lequel on pourra placer les programmes ou bibliothèques utiles à la mise au point mais à supprimer dans la version finale:
# ls -l /extra total 4 drwxr-xr-x 2 root root 1024 Sep 5 16:08 bin drwxr-xr-x 2 root root 1024 Sep 5 09:09 boot drwxr-xr-x 2 root root 1024 Sep 5 16:09 etc drwxr-xr-x 2 root root 1024 Sep 5 15:01 lib lrwxrwxrwx 1 root root 3 Sep 5 09:09 sbin -> bin
La principale optimisation consiste à supprimer tous les pilotes non utilisés par le matériel prévu ou les fonctionnalités finales du système. Pour cela, on utilisera la méthode classique de configuration du noyau LINUX:
cd /usr/src/linux make xconfigpuis
make dep; make clean; make zImage; make modules
La suppression des pilotes peut affecter en vrac:
Concernant les modules chargeable, on notera qu'il n'est pas forcément nécessaire de valider leur utilisation, leur intéret principal étant la possibilité d'obtenir un noyau de taille raisonnable malgré la présence d'un grand nombre de pilotes. La fonction de chargement/déchargement dynamique n'a pas forcément non plus un grand intérêt dans le cas d'un système embarqué destiné à une tache bien définie. Il est cependant simple de valider le support des modules en ajoutant le programme /sbin/kerneld et le répertoire /lib/modules.
On peut également effectuer quelques modifications plus avancée du noyau LINUX comme par exemple la suppression des messages de boot. Cette modification peut-être intéressante afin d'éviter au démarrage d'être trop verbeux en cas de disponibilité d'une console de visualisation.
Ceci peut se faire très facilement en ajoutant le code suivant en haut de la fonction printk() définie dans kernel/printk.c:
switch (my_anim) { case 0 : (*console_print_proc)("\\"); break; case 1 : (*console_print_proc)("|"); break; case 2 : (*console_print_proc)("/"); break; default : (*console_print_proc)("-"); break; } if (my_anim == 3) my_anim = 0; else my_anim++; (*console_print_proc)("\r"); return 0; }
L'affichage des messages de trace sera alors remplacé par une petite animation tournante.
L'installation du noyau se fera de manière classique par la copie du fichier zImage sur le répertoire /boot.
[root@atkins /root]# telnet 194.51.49.150 Trying 194.51.49.150... Connected to 194.51.49.150. Escape character is '^]'. Linux 2.0.36 (poste1) (ttyp0) poste1.local.com1.fr login: root # ls -l /etc# ls -l /etc total 35 drwxr-xr-x 2 root root 1024 Sep 5 17:36 dhcpc drwxr-xr-x 2 root root 1024 Sep 5 09:09 fs -r--r--r-- 1 root root 88 Sep 5 09:09 fstab -r--r--r-- 1 root root 330 Sep 5 09:09 group -r--r--r-- 1 root root 27 Sep 5 09:09 host.conf -rw-r--r-- 1 root root 118 Sep 7 09:51 hosts -r--r--r-- 1 root root 112 Sep 5 09:09 hosts.ref -r--r--r-- 1 root root 325 Sep 7 09:45 inetd.conf -r--r--r-- 1 root root 636 Sep 5 09:09 inittab -rw-r--r-- 1 root root 451 Sep 5 09:09 ld.so.cache -rw-r--r-- 1 root root 16 Sep 5 09:09 ld.so.conf -rw-r--r-- 1 root root 317 Sep 5 15:12 lilo.conf -rw-r--r-- 1 root root 47 Sep 7 09:51 mtab -rw-r--r-- 1 root root 180 Sep 5 15:20 passwd -rw-r--r-- 1 root root 51 Sep 5 09:09 profile -r--r--r-- 1 root root 595 Sep 5 09:09 protocols ---------- 1 root root 12288 Sep 5 16:09 psdevtab dr-xr-xr-x 2 root root 1024 Sep 5 16:11 rc.d -rw-r--r-- 1 root root 23 Sep 7 09:51 resolv.conf -r--r--r-- 1 root root 230 Sep 7 09:49 services -r--r--r-- 1 root root 18 Sep 5 09:09 shells drwxr-xr-x 2 root root 1024 Sep 5 17:34 sysconfig -r--r--r-- 1 root root 1868 Sep 5 09:09 termcap -rw-r--r-- 1 root root 0 Sep 5 09:09 utmp -rw-r--r-- 1 root root 0 Sep 5 09:09 wtmp # du -s /etc 47 /etc
Le répertoire /etc a été réduit à 47 Ko, sachant qu'il contient les scripts de démarrage dans rc.d et les fichiers de config dans sysconfig.
Le principe est simple:
# RamDisk /sbin/mke2fs -q /dev/ram mount -t ext2 /dev/ram /ramdisk
# Extraction des archives cd /ramdisk X=`ls /archives` 2>/dev/null if [ "$X" != "" ]; then for i in $X do tar -xzf /archives/$i done fi
Il existe bien entendu d'autre solutions plus évoluées mais aussi plus complexes à mettre en oeuvre comme par exemple l'utilisation de filesystems compressés comme le JFFS développé par la société AXIS, voir les liens en fin d'article.
# cd / # du -s . 3549 . # du -s extra 1519 extraLa partie définitive du système (sans le /extra) occupe donc un peu moins de 2 Mo ce qui est largement suffisant pour les disques flash de plus petite capacité (4Mo).
De part sa structure ouverte et modulaire, LINUX est particulièrement bien adapté à la construction de micro-systèmes. La preuve en est la société Lynx Real-Time Systems, un des leaders des systèmes embarqués depuis plusieurs années, qui a effectué une migration complète vers LINUX au point même de changer son nom en LynuxWorks!
LINUX everywhere est pour demain...
Le principal portail internet sur le sujet
Distribution spécialisée pour micro-controleurs (sans MMU)
Le JFFS (Journaling Flash File-System) de chez AXIS
Version développée par la société APLIO
eCOS, le LINUX embarqué de RedHat
Embedix, de chez LINEO
Hard Hat LINUX, de chez Montavista
BlueCat, de chez LynuxWorks
TiVO, magnétoscope numérique intelligent
ReplayTV, un autre magnétoscope numérique intelligent
Kerbango, poste de radio internet
Le PDA YOPI de SAMSUNG
Le projet PDA ITSY de COMPAQ
Caméra internet de chez AXIS
SANDISK
M-Systems
PQI
6. Bibliographie