Archive for mai 2011

[ACTU] 3.0 finalement…

Actualité, Linux | Publié par cpb
mai 30 2011

Comme je l’avais évoque dans un précédent article, Linus Torvalds avait décidé de basculer la numérotation des noyaux Linux en 2.8 ou 3.0. Il s’est finalement décidé pour 3.0, et a publié cette nuit une version de test release-candidate 3.0.0-rc1. Il a d’ailleurs clairement déclaré dans son message sur la mailing list de développement du kernel que ce changement de numéro majeur n’aurait pas plus de répercussions que les évolutions de versions mineures auxquelles nous sommes habitués.

Il a simplement envie de marquer ainsi les vingt ans de Linux…

Je n’ai évidemment pas résisté au plaisir de compiler un noyau (de test pour la version) 3.0 sur mon poste de travail. En voici les traces :

[~]$ uname -a
Linux tr-a-0 3.0.0-rc1-cpb #1 SMP Mon May 30 17:18:35 CEST 2011 i686 i686 i386 GNU/Linux
[~]$ dmesg | head
[    0.000000] Initializing cgroup subsys cpuset
[    0.000000] Initializing cgroup subsys cpu
[    0.000000] Linux version 3.0.0-rc1-cpb (root@tr-a-0) (gcc version 4.5.1 20100924 (Red Hat 4.5.1-4) (GCC) ) #1 SMP Mon May 30 17:18:35 CEST 2011
[    0.000000] BIOS-provided physical RAM map:
[    0.000000]  BIOS-e820: 0000000000000000 - 000000000009fc00 (usable)
[    0.000000]  BIOS-e820: 00000000000f0000 - 0000000000100000 (reserved)
[    0.000000]  BIOS-e820: 0000000000100000 - 00000000bfe53c00 (usable)
[    0.000000]  BIOS-e820: 00000000bfe53c00 - 00000000bfe55c00 (ACPI NVS)
[    0.000000]  BIOS-e820: 00000000bfe55c00 - 00000000bfe57c00 (ACPI data)
[    0.000000]  BIOS-e820: 00000000bfe57c00 - 00000000c0000000 (reserved)
[~]$

Buildroot vs Crosstool-NG – Compilons notre cross-compiler

Embarqué, Linux | Publié par cpb
mai 27 2011

Lorsqu’on entame un projet de développement sur Linux embarqué, il est nécessaire de disposer d’un cross-compiler (souvent traduit un peu maladroitement par le terme « compilateur croisé » ) c’est-à-dire un compilateur fonctionnant sur la machine de développement (appelé poste hôte) capable de produire des fichiers exécutables qui pourront s’exécuter sur le processeur du système embarqué (la cible). Ce compilateur est généralement mis à disposition (gratuitement ou non) par le fournisseur de la carte embarquée. Toutefois, il y a de nombreux cas où l’on aimerait pouvoir choisir sa propre chaîne de compilation, pour des raisons de compatibilité entre outils ou entre bibliothèques par exemple.

La génération du cross-compiler a longtemps été une opération compliquée, longue et fastidieuse, mais de nos jours plusieurs projets encadrent cette étape préliminaire et simplifient grandement la vie des développeurs pour l’embarqué.

J’ai choisi de comparer deux approches différentes (même si au final les étapes de compilation sont assez proches) : Crosstool-NG et Buildroot. Sachez cependant qu’il existe encore bien d’autres projets du même genre, comme Scratchbox, Open embedded, etc.

  • Crosstool-NG est un outil qui nous permet de générer notre chaîne de compilation croisée. Après une phase de configuration relativement simple, il télécharge les packages nécessaires, puis les compile et construit une toolchain complète.
  • Buildroot est un projet plus vaste, qui génère le compilateur croisé, mais peut ensuite enchaîner sur la compilation du noyau, des utilitaires de base, des bibliothèques supplémentaires, du système de fichiers, etc. Nous allons nous limiter ici (c’est la configuration que j’ai préparée) à la production du cross-compiler.

 

Toute application qui fonctionne sur Linux a besoin, soit au moment de la compilation, soit au moment de l’exécution, d’une bibliothèque C. Cette dernière ne se cantonne nullement aux fonctions utilitaires du langage C, mais contient aussi tous les points d’accès à l’API du noyau (les appels-système). Même une application écrite en Ada ou en Fortran aura besoin d’accéder à cette partie de la bibliothèque C. Il s’agit donc d’une pièce cruciale du système Linux, aussi importante que le kernel lui-même.

Il existe plusieurs versions de bibliothèque C. Les plus courantes sont :

  • la GlibC (Gnu libC), très complète, très riche, très grosse. Il en existe une variante un peu allégée : la EglibC
  • la uClibC beaucoup plus petite, mais n’implémentant pas toujours les extensions trop récentes de la Glibc, ou les fonctionnalités non-standard.

 

Le choix d’une bibliothèque doit être établi dès la conception initiale du projet, puisqu’il influe sur la génération de la toolchain. Buildroot ne sait compiler que la uClibC, en revanche Crosstool-NG peut compiler une GlibC, une EglibC  ou une uClibC. Nous allons préparer deux chaînes de compilation différentes, toutes les deux pour processeurs Arm, en employant ces deux projets successivement.

Crosstool-NG

Téléchargeons et décompressons les sources de crosstool-ng

[~]$ mkdir tmp
[~]$ cd tmp
[tmp]$ wget http://crosstool-ng.org/download/crosstool-ng/crosstool-ng-1.11.1.tar.bz2
--2011-05-07 09:38:28--  http://crosstool-ng.org/download/crosstool-ng/crosstool-ng-1.11.1.tar.bz2
[...]
2011-05-07 09:38:31 (564 KB/s) - «crosstool-ng-1.11.1.tar.bz2» sauvegardé [1838987/1838987]
[tmp]$ tar xjf crosstool-ng-1.11.1.tar.bz2
[tmp]$ cd crosstool-ng-1.11.1

Configurons Crosstool-NG pour préparer la compilation. Nous allons indiquer un chemin (absolu, pas de chemin relatif ou de ~/) pour l’installation des scripts de compilation. Ce répertoire pourra être supprimé par la suite.

[crosstool-ng-1.11.1]$ ./configure --prefix=/home/votre-login/tmp/ctng
Checking for 'grep'... /bin/grep
Checking whether '/bin/grep' supports -E... yes
[...]
[crosstool-ng-1.11.1]$ make
  SED    'ct-ng'
  SED    'scripts/crosstool-NG.sh'
[...]
  SED    'docs/ct-ng.1'
  GZIP   'docs/ct-ng.1.gz'
[crosstool-ng-1.11.1]$ make install
  MKDIR   '/home/cpb/tmp/ctng/bin/'
  INST    'ct-ng'
[...]
For auto-completion, do not forget to install 'ct-ng.comp' into
your bash completion directory (usually /etc/bash_completion.d)
[crosstool-ng-1.11.1]$

Si la commande configure se plaint de l’absence de makeinfo, sachez qu’il s’agit du package texinfo qu’il faut installer.

Nous pouvons à présent supprimer ce répertoire de sources, et créer un répertoire de travail dans lequel seront stockés les fichiers temporaires pendant la génération du cross-compiler.

[crosstool-ng-1.11.1]$ cd ..
[tmp]$ rm -rf crosstool-ng-1.11.1
[tmp]$ mkdir ctng-build
[tmp]$ cd ctng-build/
[ctng-build]$

Il est important d’ajouter dans notre variable d’environnement PATH le chemin d’accès au répertoire bin/ dans le répertoire précédemment fourni :

[ctng-build]$ PATH=$PATH:~/tmp/ctng/bin/
[ctng-build]$

Nous allons maintenant configurer la compilation. Pour cela une interface en mode texte semi-graphique semblable à celle du noyau Linux est disponible. La configuration est enregistrée dans un fichier .config que l’on peut sauvegarder et restaurer manuellement. Vous en trouverez une version prête à télécharger.

[ctng-build]$ cp ~/config-ctng-1.11.1-arm-linux-generic ./.config
[ctng-build]$ ct-ng menuconfig
  MKDIR kconfig
  DEP   kconfig/lxdialog/menubox.dep
  DEP   kconfig/lxdialog/textbox.dep
[...]

Après examen des options disponibles, quittons en sauvegardant la configuration, puis lançons la compilation :

[ctng-build]$ ct-ng build
[INFO ]  Performing some trivial sanity checks
[INFO ]  Build started 20110507.100411
[INFO ]  Building environment variables
[WARN ]  Directory '/home/cpb/tmp/download' does not exist.
[WARN ]  Will not save downloaded tarballs to local storage.
[INFO ]  =================================================================
[INFO ]  Retrieving needed toolchain components' tarballs
[INFO ]  Retrieving needed toolchain components' tarballs: done in 727.77s (at 12:09)
[INFO ]  =================================================================
[INFO ]  Extracting and patching toolchain components
[INFO ]  Extracting and patching toolchain components: done in 73.42s (at 13:22)
[INFO ]  =================================================================
[INFO ]  Installing binutils
[INFO ]  Installing binutils: done in 33.22s (at 13:55)
[INFO ]  =================================================================
[INFO ]  Installing static core C compiler
[INFO ]  Installing static core C compiler: done in 75.13s (at 15:11)
[INFO ]  =================================================================
[INFO ]  Installing kernel headers
[INFO ]  Installing kernel headers: done in 5.10s (at 15:16)
[INFO ]  =================================================================
[INFO ]  Installing C library headers & start files
[INFO ]  Installing C library headers & start files: done in 79.14s (at 16:35)
[INFO ]  =================================================================
[INFO ]  Installing shared core C compiler
[INFO ]  Installing shared core C compiler: done in 112.33s (at 18:27)
[INFO ]  =================================================================
[INFO ]  Installing C library
[INFO ]  Installing C library: done in 463.23s (at 26:10)
[INFO ]  =================================================================
[INFO ]  Installing final compiler
[INFO ]  Installing final compiler: done in 85.82s (at 27:36)
[INFO ]  =================================================================
[INFO ]  Installing cross-gdb
[INFO ]  Installing cross-gdb: done in 83.66s (at 29:00)
[INFO ]  =================================================================
[INFO ]  Installing gdbserver
[INFO ]  Installing gdbserver: done in 7.75s (at 29:08)
[INFO ]  =================================================================
[INFO ]  Cleaning-up the toolchain's directory
[INFO ]    Stripping all toolchain executables
[INFO ]  Cleaning-up the toolchain's directory: done in 1.26s (at 29:09)
[INFO ]  Build completed at 20110507.103320
[INFO ]  (elapsed: 29:08.89)
[INFO ]  Finishing installation (may take a few seconds)...
[ctng-build]$ cd ..
[tmp]$ rm -rf ctng*
[tmp]$

Et voilà ! notre nouvelle toolchain est prête, disponible dans ~/cross-arm-linux-ctng/bin, les utilitaires étant préfixés par arm-generic-linux-gnueabi-

Utilisation du cross-compiler

Nous allons employer toolchain obtenue avec Crosstool-NG pour compiler un noyau Linux et une application utilisateur (Busybox par exemple). J’utiliserai ici des fichiers de configuration fonctionnant pour la carte Pandaboard.

Compilation du kernel Linux

Téléchargement et préparation des sources :

[~]$ cd tmp
[tmp]$ wget http://www.kernel.org/pub/linux/kernel/v2.6/testing/linux-2.6.39-rc6.tar.bz2
[...]
2011-05-08 03:40:59 (1,60 MB/s) - «linux-2.6.39-rc6.tar.bz2» sauvegardé [76087903/76087903]
[tmp]$ tar -xjf linux-2.6.39-rc6.tar.bz2 
[tmp]$ cd linux-2.6.39-rc6

Configuration de la compilation ; le fichier proposé ci-dessous est une configuration pour la carte Pandaboard que j’ai utilisée dans les articles des semaines précédentes (1, 2, et 3)

[linux-2.6.39-rc6]$ cp ~/config-linux-2.6.39-rc6-pandaboard-cpb ./.config
[linux-2.6.39-rc6]$ make ARCH=arm menuconfig

Après avoir vérifié la configuration, nous quittons et lançons la compilation ainsi :

[linux-2.6.39-rc6]$ PATH=$PATH:~/Projets/Panda/u-boot/tools/
[linux-2.6.39-rc6]$ make ARCH=arm CROSS_COMPILE=~/cross-arm-linux-ctng/bin/arm-generic-linux-gnueabi- -j 16 uImage

Deux remarques :

  • La modification du PATH permet d’inclure le répertoire dans lequel nous avions compilé U-boot, afin d’avoir accès à l’utilitaire mkimage qui permet de produire des fichiers uImage. Pour en savoir plus, se reporter à cet article.
  • Il est possible d’enregistrer le préfixe du cross-compiler directement dans la configuration du kernel (dans le menu General Setup), mais j’ai préféré indiquer ce préfixe explicitement sur la ligne de commande, car nous ré-utiliserons le même fichier de configuration pour comparer la compilation avec Buildroot.

La compilation se termine ainsi :

Image Name:   Linux-2.6.39-rc6-cpb-ctng
Created:      Sun May  8 03:52:04 2011
Image Type:   ARM Linux Kernel Image (uncompressed)
Data Size:    3053156 Bytes = 2981.60 kB = 2.91 MB
Load Address: 80008000
Entry Point:  80008000
  Image arch/arm/boot/uImage is ready
[linux-2.6.39-rc6]$ ls -l arch/arm/boot/uImage 
-rw-rw-r-- 1 cpb cpb 3053220  8 mai   03:52 arch/arm/boot/uImage
[linux-2.6.39-rc6]$

Après avoir sauvegardé l’image obtenue, passons un petit coup de « M. Propre » sur les sources du noyau afin d’effacer tous les fichiers de compilation

[linux-2.6.39-rc6]$ cp arch/arm/boot/uImage ~/tmp/uImage-ctng
[linux-2.6.39-rc6]$ make mrproper
  CLEAN   .
[...]
  CLEAN   .config .config.old .version include/linux/version.h Module.symvers
[linux-2.6.39-rc6]$

Compilation de busybox

Busybox est un package essentiel pour les systèmes embarqués, que l’on retrouve dans de très nombreux projets.

[~]$ cd tmp
[tmp]$ wget http://www.busybox.net/downloads/busybox-1.18.4.tar.bz2
[...]
2011-05-08 03:59:21 (523 KB/s) - «busybox-1.18.4.tar.bz2» sauvegardé [2130598/2130598]
[tmp]$ tar -xjf busybox-1.18.4.tar.bz2
[tmp]$ cd busybox-1.18.4
[busybox-1.18.4]$

Le fichier de configuration fourni ici est très complet, ceci nous donnera un fichier exécutable assez volumineux

[busybox-1.18.4]$ cp ~/config-busybox-1.18.4 ./.config
[busybox-1.18.4]$ make CROSS_COMPILE=~/cross-arm-linux-ctng/bin/arm-generic-linux-gnueabi-
[...]
  AR      shell/lib.a
  AR      libbb/lib.a
  LINK    busybox_unstripped
Trying libraries: crypt m
 Library crypt is not needed, excluding it
 Library m is needed, can't exclude it (yet)
Final link with: m
[busybox-1.18.4]$ ls -l busybox
-rwxrwxr-x 1 cpb cpb 896108  8 mai   04:07 busybox
[busybox-1.18.4]$ cp busybox ~/tmp/busybox-ctng[busybox-1.18.4]$

Pour que ce fichier exécutable puisse fonctionner, il faudra disposer sur la cible :

  • du chargeur de fichiers exécutables dynamiques ld-linux.so.3 (lien symbolique vers ld-2.12.2.so) ;
  • de la bibliothèque C : libc.so.6 (lien symbolique vers libc-2.12.2.so) ;
  • de la bibliothèque mathématique libm.so.6 (lien symbolique vers libm-2.12.2.so).

Tous ces fichiers ont été compilés avec la toolchain et se trouvent dans ~/cross-arm-linux-ctng/arm-generic-linux-gnueabi/sysroot/lib/. Voyons leurs tailles :

[lib]$ ls -l ld-2.12.2.so 
-r-xr-xr-x 1 cpb cpb 161023  7 mai   10:30 ld-2.12.2.so
[lib]$ ls -l libc-2.12.2.so 
-r-xr-xr-x 1 cpb cpb 1521599  7 mai   10:30 libc-2.12.2.so
[lib]$ ls -l libm-2.12.2.so 
-r-xr-xr-x 1 cpb cpb 729489  7 mai   10:29 libm-2.12.2.so
[lib]$

Au total, il nous faudra installer sur notre cible au minimum :

  • kernel Linux : 3053220 octets ≈ 3Mo
  • exécutable Busybox : 896108 octets ≈ 1 Mo
  • bibliothèques : 161023 + 1521599 + 729489 = 2412111 octets ≈ 2,3 Mo

 

Soit un total d’environ 6 Mo.

Buildroot

Obtention et préparation des sources de Buildroot :

[~]$ cd tmp
[tmp]$ wget http://buildroot.uclibc.org/downloads/buildroot-2011.02.tar.bz2
[...]
2011-05-08 04:28:58 (492 KB/s) - «buildroot-2011.02.tar.bz2» sauvegardé [1945895/1945895]
[tmp]$ tar xjf buildroot-2011.02.tar.bz2
[tmp]$ cd buildroot-2011.02
[buildroot-2011.02]$

Configuration de la compilation :

[buildroot-2011.02]$ cp ~/config-buildroot-arm-generic ./.config
[buildroot-2011.02]$ make menuconfig

Dans le menu de configuration, nous devons préciser l’emplacement final de la toolchain par un chemin absolu. Il faut donc modifier l’entrée « Host dir » du menu « Build Options » pour qu’elle contienne le répertoire d’installation du compilateur (remplacez mon nom de login « cpb » par le vôtre).

Puis on lance la compilation :

[buildroot-2011.02]$ make
[...]
if [ -x "/home/cpb/cross-arm-linux-buildroot/usr/bin/arm-unknown-linux-uclibcgnueabi-ldconfig" ]; \
then \
	/home/cpb/cross-arm-linux-buildroot/usr/bin/arm-unknown-linux-uclibcgnueabi-ldconfig -r /home/cpb/tmp/buildroot-2011.02/output/target; \
else \
	/sbin/ldconfig -r /home/cpb/tmp/buildroot-2011.02/output/target; \
fi
/home/cpb/cross-arm-linux-buildroot/usr/bin/arm-unknown-linux-uclibcgnueabi-ldconfig: can't resolve /usr/X11R6/lib in chroot .: No such file or directory
/home/cpb/cross-arm-linux-buildroot/usr/bin/arm-unknown-linux-uclibcgnueabi-ldconfig: skipping /usr/X11R6/lib: No such file or directory
echo 2011.02 > /home/cpb/tmp/buildroot-2011.02/output/target/etc/br-version
rm -f /home/cpb/tmp/buildroot-2011.02/output/build/.fakeroot*
[buildroot-2011.02]$ cd ..
[tmp]$ rm -rf buildroot-2011.02*
[tmp]$

Utilisation de Buildroot

Commençons par compiler un noyau Linux comme précédemment (nous avions nettoyé les sources de tous les fichiers de compilation précédents) :

[~]$ cd tmp/
[tmp]$ cd linux-2.6.39-rc6
[linux-2.6.39-rc6]$ cp ~/config-linux-2.6.39-rc6-pandaboard-cpb ./.config
[linux-2.6.39-rc6]$ make ARCH=arm menuconfig
  HOSTCC  scripts/basic/fixdep
  HOSTCC  scripts/basic/docproc
[...]

Vérifions la configuration et sauvegardons-la :

#
# configuration written to .config
[...]
[linux-2.6.39-rc6]$ PATH=$PATH:~/Projets/Panda/u-boot/tools/
[linux-2.6.39-rc6]$ make ARCH=arm CROSS_COMPILE=~/cross-arm-linux-buildroot/usr/bin/arm-linux- -j 16 uImage
[...]
Image Name:   Linux-2.6.39-rc6-cpb-buildroot
Created:      Sun May  8 09:31:34 2011
Image Type:   ARM Linux Kernel Image (uncompressed)
Data Size:    3050288 Bytes = 2978.80 kB = 2.91 MB
Load Address: 80008000
Entry Point:  80008000
  Image arch/arm/boot/uImage is ready
[linux-2.6.39-rc6]$ ls -l arch/arm/boot/uImage 
-rw-rw-r-- 1 cpb cpb 3050352  8 mai   09:31 arch/arm/boot/uImage
[linux-2.6.39-rc6]$ cp arch/arm/boot/uImage ../uImage-buildroot
[linux-2.6.39-rc6]$

La taille du noyau est approximativement égale à celle du noyau obtenu avec Crosstool-NG. Vérifions à présent la compilation d’une application utilisateur : Busybox.

[linux-2.6.39-rc6]$ cd ~/tmp/busybox-1.18.4
[busybox-1.18.4]$ make distclean
  CLEAN   applets
[...]
  CLEAN   .config include/autoconf.h include/bbconfigopts.h include/usage_compressed.h include/applet_tables.h
[busybox-1.18.4]$ cp ~/config-busybox-1.18.4 ./.config
[busybox-1.18.4]$ make menuconfig

Puis compilons Busybox :

[busybox-1.18.4]$ make CROSS_COMPILE=~/cross-arm-linux-buildroot/usr/bin/arm-linux- 
[...]
Trying libraries: crypt m
 Library crypt is not needed, excluding it
 Library m is needed, can't exclude it (yet)
Final link with: m
  DOC     busybox.pod
  DOC     BusyBox.txt
  DOC     busybox.1
  DOC     BusyBox.html
[busybox-1.18.4]$
[busybox-1.18.4]$ ls -l busybox
-rwxrwxr-x 1 cpb cpb 892444  8 mai   09:38 busybox

Les bibliothèques utiles se trouvent à présent dans ~/cross-arm-linux-buildroot/usr/arm-linux/sysroot/lib/

[cross-arm-linux-buildroot]$ ls -l /cross-arm-linux/usr/arm-linux/sysroot/lib/ld-uClibc-0.9.31.so 
-rwxr-xr-x 1 root root 21324  8 mai   04:55 /cross-arm-linux/usr/arm-linux/sysroot/lib/ld-uClibc-0.9.31.so
[cross-arm-linux-buildroot]$ ls -l /cross-arm-linux/usr/arm-linux/sysroot/lib/libuClibc-0.9.31.so
-rwxr-xr-x 1 root root 403651  8 mai   04:55 /cross-arm-linux/usr/arm-linux/sysroot/lib/libuClibc-0.9.31.so
[cross-arm-linux-buildroot]$ ls -l /cross-arm-linux/usr/arm-linux/sysroot/lib/libm-0.9.31.so
-rwxr-xr-x 1 root root 64479  8 mai   04:55 /cross-arm-linux/usr/arm-linux/sysroot/lib/libm-0.9.31.so

Nous pouvons récapituler les éléments nécessaires

  • kernel Linux : 3050288 octets ≈ 3Mo
  • exécutable Busybox : 892444 octets ≈ 1 Mo
  • bibliothèques : 21324 + 403651 + 64479 = 489454 octets ≈ 478 ko

 

Soit environ 4,4 Mo

Conclusion

Comme on pouvait s’y attendre la taille des bibliothèques nécessaires en utilisant la uClibC est sensiblement plus petite que celle de la EglibC. En revanche les tailles des exécutables (avec éditions des liens dynamique) et du noyau Linux sont équivalentes à celles obtenues avec la toolchain de Crosstool-NG.

Il y a des différences fonctionnelles entre les bibliothèques EglibC (ou GlibC) et uClibC. Cette dernière par exemple s’appuie encore pour offrir un support des threads Posix sur l’ancienne bibliothèque LinuxThreads, alors que la EglibC utilisent la bibliothèque NPTL plus riche et plus performante. C’est le cas pour d’autres fonctionnalités également (cela fera l’objet d’un prochain article).

Sur des systèmes fortement contraints, où l’économie de quelques méga-octets est appréciable, on pourra se tourner facilement vers la uClibC à l’aide de Buildroot. Sur des systèmes moins limités en mémoire, on pourra profiter de la richesse de la GlibC en utilisant le compilateur croisé fourni par Crosstool-NG.

 

[ACTU] 2.8 ou 3.0 ?

Actualité, Linux | Publié par cpb
mai 24 2011

Dans un article sur la mailing-list de développement du noyau, Linus Torvalds a laissé entendre hier que pour la prochaine mouture du kernel Linux – à paraître dans 3 mois environ – il pourrait bien s’affranchir des numérotations en 2.6 (qui datent de décembre 2003), et passer à un noyau 2.8. Cette annonce n’est pas anodine, les numéros des version actuelles de Linux (2.6.39 depuis une semaine) sont trop grands pour que l’on ressente intuitivement les évolutions. Passer d’un kernel 2.6.38 à 2.6.39 n’est a priori pas très excitant, il faut bien en convenir, et l’utilisateur n’imagine pas qu’entre deux numéros de version apparemment si proches peut se dissimuler une ré-écriture complète de certains sous-systèmes ou des ajouts de fonctionnalités influant sur l’ensemble du noyau (support de l’adressage PAE dans le 2.6.10, threaded interrupts dans le 2.6.30, etc.).

Linus a également évoqué la possibilité de passer à un noyau 3.0 et d’abandonner le quatrième numéro. Cette solution aurait l’avantage d’être plus compréhensible pour les utilisateurs.

Nous aurions des évolutions successives régulièrement 3.0, 3.1, 3.2, etc. (en conservant probablement le rythme actuel quasi trimestriel) comportant des ajouts (nouveaux drivers, systèmes de fichiers, protocoles, etc.), des améliorations de sous-systèmes complets (ordonnancement, gestion mémoire…)

Bien sûr, ces variantes seraient maintenues, et les corrections apportées seraient disponibles sous la forme d’incréments d’un troisième numéro 3.2.1, 3.2.2, 3.2.3, etc.   Entre ces corrections successives l’API interne du noyau (pour écrire des drivers par exemple) n’est pas modifiée, contrairement aux évolutions décrites précédemment.

Quand le changement va-t-il se produire ? Rien n’est décidé définitivement, semble-t-il, mais je parierais bien que cela pourrait se produire aux alentours du 25 août prochain, pour les vingt ans du fameux premier message de Linus annonçant son « hobby sans prétention » :

From: torvalds@klaava.Helsinki.FI (Linus Benedict Torvalds)
Newsgroups: comp.os.minix
Subject: What would you like to see most in minix?
Date: 25 Aug 91 20:57:08 GMT

Hello everybody out there using minix -

I’m doing a (free) operating system (just a hobby, won’t be big and professional like gnu) for 386(486) AT clones. This has been brewing since april, and is starting to get ready. I’d like any feedback on things people like/dislike in minix, as my OS resembles it somewhat (same physical layout of the file-system (due to practical reasons) among other things).
I’ve currently ported bash(1.08) and gcc(1.40), and things seem to work. This implies that I’ll get something practical within a few months, and I’d like to know what features most people would want. Any suggestions are welcome, but I won’t promise I’ll implement them :-)

Linus (torvalds@kruuna.helsinki.fi)

PS. Yes – it’s free of any minix code, and it has a multi-threaded fs. It is NOT protable (uses 386 task switching etc), and it probably never will support anything other than AT-harddisks, as that’s all I have :-(.

 

Pour en savoir plus sur les débuts de l’histoire de Linux : « Linux – Histoire d’un noyau« .

 

Construire son système personnel sur une carte Pandaboard (3)

Embarqué, Linux | Publié par cpb
mai 20 2011

Pandaboard Ethernet et USB

Dans les articles précédents (1 et 2) nous avons réussi à installer un système minimal sur notre Pandaboard. Toutefois, nous n’avons pour le moment pas abordé le problème du réseau. Je vous propose cette semaine d’initialiser l’interface Ethernet et d’installer quelques services, par exemple pour se connecter à distance ou transférer des fichiers sur la carte.

Initialisation de l’interface Ethernet

L’interface Ethernet de la carte Pandaboard est assurée par un composant SMSC LAN 9514. Celui offre un hub USB 2.0 ainsi qu’une interface RJ45 10/100 MBits/sec. Le driver de ce composant est bien présent dans le fichier de configuration du kernel que nous avons utilisé dans le premier article.

Toutefois, l’inconvénient de ce périphérique est que l’interface Ethernet utilise un support USB, et met ainsi plusieurs secondes après le boot à être détectée et initialisée par le noyau avant d’être accessible par l’espace utilisateur. Nous devrons donc utiliser une boucle d’attente avant de configurer l’interface.

Je vous propose de modifier le script d’initialisation précédent /etc/init.d/rcS pour ajouter les lignes suivantes à la fin du fichier :

while true
do
    if ifconfig -a | grep '^eth0' > /dev/null
    then
        break;
    fi
    sleep 1
done

ifconfig eth0 192.168.3.152
ifconfig lo 127.0.0.1

Ce script boucle en attendant que la commande ifconfig lui fournisse une ligne commençant par eth0. Ensuite elle configure l’adresse IP de cette interface avec l’adresse IP 192.168.3.152. Il s’agit d’une adresse que j’ai choisie arbitrairement car elle convient au sous-réseau de mon bureau. Vous devrez la modifier pour qu’elle corresponde à votre environnement.

Pour faire bonne mesure, nous initialisons également l’interface loopback avec l’adresse standard 127.0.0.1.

Lorsque l’on teste le script en redémarrant la carte, celle-ci se met à répondre aux pings envoyés depuis une autre machine.

Service de connexion telnet

Le premier service que nous allons mettre en œuvre est le démon telnetd intégré dans Busybox. Celui-ci a été compilé précédemment, et il nous suffit de rajouter son lancement dans le script de démarrage.

Le serveur telnetd permet à un client d’initier une connexion TCP/IP, puis il lance l’application /bin/login pour valider les permissions de l’utilisateur. Toutefois, nous n’avons créé aucun compte pour le moment aussi allons nous demander explicitement à telnetd de démarrer directement un shell, sans authentification supplémentaire. Naturellement ceci ne doit être utilisé qu’à des fins de tests sur un réseau privé. Ajoutons donc la ligne suivante à la fin du script de démarrage.

telnetd -l /bin/sh

Une dernière étape s’impose : le démon telnetd utilise les pseudo-terminaux Unix pour gérer la communication avec le client telnet. Pour cela, il doit ouvrir le fichier spécial /dev/pts/n, n étant un numéro fourni par le kernel. Pour que ce fichier soit disponible, nous pouvons demander au noyau de monter sur /dev/pts un pseudo-système de fichiers spécial nommé devpts. Cela s’obtient en ajoutant les lignes suivantes en début de script, juste après avoir remonté l’arborescence de la racine.

mkdir /dev/pts
mount none /dev/pts  -t devpts

Redémarrons notre Pandaboard, et vérifions le fonctionnement depuis un autre poste.

[~]$ ping 192.168.3.152
PING 192.168.3.152 (192.168.3.152) 56(84) bytes of data.
64 bytes from 192.168.3.152: icmp_req=1 ttl=64 time=0.770 ms
64 bytes from 192.168.3.152: icmp_req=2 ttl=64 time=109 ms
64 bytes from 192.168.3.152: icmp_req=3 ttl=64 time=0.835 ms
Ctrl-C
[~]$ telnet 192.168.3.152
Trying 192.168.3.152...
Connected to 192.168.3.152.
Escape character is '^]'.

/ # cat /proc/cpuinfo 
Processor       : ARMv7 Processor rev 2 (v7l)
processor       : 0
BogoMIPS        : 2007.19
[...]
Hardware        : OMAP4 Panda board
Revision        : 0020
Serial          : 0000000000000000
/ # Ctrl-D
Connection closed by foreign host.
[~]$

L’utilisation du protocole Telnet est très peu recommandée, car il n’y a aucune sécurité dans la transmission des données – ni dans celle des mots de passe. Aussi, on préfère généralement assurer la connexion sur un système Linux en employant le protocole SSH (Secure Shell) avec lequel non seulement les mots de passe mais également tout le contenu de la session est chiffré.

Connexion sécurisée par SSH

Il n’y a pas (encore) d’implémentation du serveur sshd dans Busybox, mais il en existe plusieurs libres (par exemple Open SSH). J’ai choisi d’utiliser plutôt Dropbear, dont l’empreinte mémoire est plus faible.

Téléchargeons la dernière version de Dropbear

[~]$ cd Projets/Panda
[Panda]$ wget http://matt.ucc.asn.au/dropbear/releases/dropbear-0.53.1.tar.bz2
[...]
2011-05-19 00:04:37 (169 KB/s) - «dropbear-0.53.1.tar.bz2» sauvegardé [1577227/1577227]
[Panda]$ tar -xjf dropbear-0.53.1.tar.bz2 
[Panda]$ cd dropbear-0.53.1
[dropbear-0.53.1]$

Ajoutons dans notre PATH le chemin permettant d’atteindre le cross-compiler (arm-linux-gcc).

[dropbear-0.53.1]$ export PATH=$PATH:/cross-arm-linux/usr/bin/
[dropbear-0.53.1]$

Puis préparons la compilation via le script configure. Nous lui indiquons dans la variable host le préfixe à ajouter devant les noms des outils de la toolchain pour réaliser la compilation croisée. Sur ma machine, le package zlib-devel est absent, aussi je désactive cette option non indispensable.

[dropbear-0.53.1]$ ./configure --host=arm-linux --disable-zlib
configure: WARNING: If you wanted to set the --build type, don't use --host.
    If a cross compiler is detected then cross compile mode will be used.
checking for arm-linux-gcc... arm-linux-gcc
[...]
configure:
configure: Now edit options.h to choose features.
[dropbear-0.53.1]$

Les options par défaut de options.h me satisfaisant, je démarre la compilation :

[dropbear-0.53.1]$ make
[...]
arm-linux-gcc  -o dropbearconvert dbutil.o buffer.o dss.o bignum.o signkey.o rsa.o random.o queue.o atomicio.o compat.o  fake-rfc2553.o  dropbearconvert.o keyimport.o libtomcrypt/libtomcrypt.a libtommath/libtommath.a -lutil
[dropbear-0.53.1]$

L’utilitaire scp permet de copier des fichiers facilement d’une machine à l’autre, nous devons le compiler séparément.

[dropbear-0.53.1]$ make scp
[...]
arm-linux-gcc  -o scp scp.o progressmeter.o atomicio.o scpmisc.o compat.o
[dropbear-0.53.1]$

Nous allons devoir réinsérer la carte mémoire Micro-SD de la Pandaboard sur le système cible. Par la suite, nous pourrons transférer directement les fichiers par le réseau. Copions déjà les trois fichiers exécutables nécessaires (dropbearkey sert à préparer la clé secrète du serveur SSH).

[dropbear-0.53.1]$ su
Mot de passe :
[dropbear-0.53.1]# cp dropbear /media/root/usr/bin/
[dropbear-0.53.1]# cp dropbearkey /media/root/usr/bin/
[dropbear-0.53.1]# cp scp /media/root/usr/bin/
[dropbear-0.53.1]#

Une connexion par SSH nécessite obligatoirement une identification avec un nom de compte et un mot de passe. Or nous n’avons créé aucun compte sur la Pandaboard. Corrigeons ceci en ajoutant un fichier /etc/passwd qui contient une unique ligne pour le compte root.

[dropbear-0.53.1]# echo "root:hij0peA8cbCDM:0:0:root:/root:/bin/sh" > /media/root/etc/passwd
[dropbear-0.53.1]# umount /media/root/
[dropbear-0.53.1]# umount /media/boot/
[dropbear-0.53.1]# exit
[dropbear-0.53.1]$

Cette ligne contient sept champs séparés par des deux-points. Le premier est le nom du compte, il est suivi du mot de passe crypté, des User IDentifier et Group IDentifier, du nom complet de l’utilisateur, de son répertoire personnel et enfin de son shell de connexion.

Le mot de passe ici est "root". Comment obtenir la chaîne cryptée ? simplement en utilisant l’utilitaire cryptpw contenu dans Busybox. Par exemple, j’avais saisi lors de la première session telnet la commande suivante pour obtenir le cryptage ci-dessus (la chaîne fournie change à chaque appel, elle contient une part aléatoire).

/ # cryptpw root
hij0peA8cbCDM
/ #

Dans le script d’initialisation, il va falloir d’abord générer la clé privée du serveur SSH (chose que l’on ne fait en principe qu’une seule fois), puis lancer le démon proprement dit. On ajoute donc les lignes suivantes.dans /etc/initd.d/rcS

if [ ! -f /etc/dbkey ]
then
    dropbearkey -t rsa -f /etc/dbkey
fi
dropbear -r /etc/dbkey

Naturellement, je vous encourage à regarder les options offertes par ces différentes commandes et à ajuster leur comportement en fonction de vos contraintes. Connectons-nous après avoir redémarré la cible :

[~]$ ssh root@192.168.3.152
The authenticity of host '192.168.3.152 (192.168.3.152)' can't be established.
RSA key fingerprint is 82:49:a3:b7:6e:5e:b2:99:df:6e:a9:45:8c:34:d2:09.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '192.168.3.152' (RSA) to the list of known hosts.
root@192.168.3.152's password:  (root)
~ # uname -a
Linux (none) 2.6.39-rc5-cpb #1 SMP Tue May 3 11:14:47 CEST 2011 armv7l GNU/Linux
~ #

Pas très facile de distinguer les commandes saisies sur l’hôte de développement de celles saisies sur la carte cible ? Pas de problème, nous allons rendre le prompt de la cible plus repérable en y ajoutant un fichier /etc/profile qui contient la ligne suivante :

export PS1="[PANDA \W]# "

Ce fichier est lu par le shell lors d’une connexion sur le système. La variable d’environnement PS1 correspond au prompt du shell, le \W étant remplacé par le nom du répertoire courant. Déconnectons-nous puis ré-établissons la connexion

 # exit
Connection to 192.168.3.152 closed.
[~]$ ssh root@192.168.3.152
root@192.168.3.152's password: (root)
[PANDA /root]#

Le mot « PANDA » nous permettra de distinguer le shell de la cible de celui de l’hôte de développement.

Transferts de fichiers par SCP

Pour pouvoir transférer des fichiers directement en employant SCP (Secure Copy), un descendant amélioré et sécurisé de RCP (Remote Copy), il faut que le démon dropbear puisse trouver l’exécutable scp. Pour cela, nous allons initialiser la variable d’environnement PATH correctement dans le script de démarrage /etc/init.d/rcS. Insérons la ligne suivante avant l’invocation de dropbear

export PATH=/bin:/usr/bin:/sbin:/usr/sbin:/usr/local/bin:/usr/local/sbin

Aucune importance si certains répertoires n’existent pas, ils seront ignorés lors des recherches d’exécutables. Profitons-en également pour ajouter la même ligne dans le fichier /etc/profile (disponible ici). Puis re-démarrons la carte Pandaboard. Une fois le boot terminé, nous pouvons envoyer un fichier depuis l’ordinateur hôte.

[~]$ echo "ESSAI DE TRANSFERT" > mon-fichier
[~]$ scp mon-fichier root@192.168.3.152:/root/ 
root@192.168.3.152's password: (root)
mon-fichier                                                                                                                        100%   19     0.0KB/s   00:00
[~]$ ssh root@192.168.3.152
root@192.168.3.152's password: (root)
[PANDA /root]# ls /root
mon-fichier
[PANDA /root]# cat /root/mon-fichier
ESSAI DE TRANSFERT
[PANDA /root]#

L’utilitaire scp peut s’employer dans les deux sens, la syntaxe est la suivante :

scp fichiers-locaux...  utilisateur@adresse-distante:/repertoire-distant/

ou

scp utilisateur@adresse-distante:/repertoire/distant/fichiers...  /repertoire/local

Naturellement, à ce stade il vous est possible de créer des comptes utilisateurs avec des droits limités et des mots de passe solides, et de supprimer la connexion root (ainsi bien entendu que celle par telnet). Nous pouvons à loisir nous connecter sur notre Pandaboard, et y transférer des fichiers. Terminons cette première partie sur le réseau en installant un petit service simple mais efficace : le serveur HTTP.

Mise en œuvre d’un serveur Web

L’utilisation d’un petit serveur web sur un système embarqué n’est pas rare, bien au contraire. Il est fréquent de disposer d’une interface HTTP pour paramétrer le système, récupérer des statistiques d’exécution, visualiser des états, etc. À tel point qu’il existe de nombreux projets concurrents disponibles pour ce genre de serveur. J’en retiendrai trois principaux.

  • Apache : le serveur HTTP de référence, utilisé par plus de la moitié des sites Web. Très complet, très modulaire, interfaçable avec de nombreux langages (Shell, PHP, Python, Perl, etc.). Sauf exception, je préfère le réserver à des serveurs dédiés sur Internet.
  • Lighttpd : serveur destiné à l’embarqué, il n’implémente pas toutes les fonctionnalités de sécurité d’Apache. Il est facilement interfaçable avec des modules extérieurs (tout particulièrement PHP) via une interface CGI.
  • Busybox : la présence d’un petit démon httpd au sein des applets de Busybox simplifie énormément la mise en œuvre d’un service HTTP simple. Nous allons l’utiliser immédiatement.

Il nous faut tout d’abord transférer sur la cible un fichier HTML que nous copierons dans un répertoire dédié au service HTTP. Commençons par créer le répertoire.

[PANDA /root]# mkdir /home/www
[PANDA /root]#

Puis transférons le petit fichier index.html que vous pouvez trouver ici.

[~]$ scp index.html root@192.168.3.152:/home/www/
root@192.168.3.152's password:
index.html                                               100%  199     0.2KB/s   00:00
[~]$

Enfin ajoutons la ligne suivante à la fin du script de démarrage /etc/init.d/rcS

httpd -f /home/www/

Après reboot de notre carte, essayons de joindre son adresse IP depuis un navigateur web sur notre réseau local en saisissant directement http://192.168.3.152 dans la barre d’URL.

Capture d'écran du navigateur connecté sur la carte Pandaboard

Conclusion

Nous avons ajouté plusieurs fonctionnalités facilement sur notre système embarqué, principalement en éditant le fichier /etc/init.d/rcS (dont voici la nouvelle version) car la plupart des services sont déjà compilés dans Busybox. Il y a toutefois quelques limites à ce système, que nous essayerons de dépasser dans les prochains articles :

  • nous n’avons initialisé que l’interface Ethernet, mais il existe une interface Wifi sur la Pandaboard ;
  • nous n’avons pas essayé de faire de routage ou de résolution de nom (par exemple pour accéder à Internet depuis la Pandaboard) ;
  • l’initialisation a été faite de manière statique avec une adresse attribuée manuellement. Bien que cette approche soit classique dans l’embarqué, on peut préférer utiliser une affectation dynamique d’adresse (en employant par exemple le protocole DHCP) ;
  • notre service Web, bien que fonctionnel est vraiment minimal. Il serait intéressant de l’étendre à l’aide de scripts CGI, voire d’utiliser un serveur un peu plus puissant (par exemple Lighttpd) ;
  • enfin, d’autres services réseau peuvent être intéressant à implémenter : citons par exemple FTP pour un transfert de fichiers plus connu que SCP,  NTP ou PTP pour configurer l’heure système de la carte, SNMP pour superviser des états à distance, etc.

Nous continuerons ces expériences dans de prochains articles…

[Actu] Bye-Bye Big Kernel Lock…

Actualité, Linux | Publié par cpb
mai 19 2011

Linus Torvalds a publié ce matin la version 2.6.39 du kernel Linux. Pour des raisons liées essentiellement à son emploi du temps chargé, il a préféré renoncer à la version release candidate rc8 et passer directement à la version stable.

Pas beaucoup de grosses nouveautés dans cette version, je note la présence d’une nouvelle interface nommée « Media Controller API » principalement destinée à l’acquisition vidéo et aux cameras (Menus « Drivers« , sous-menu « Multimedia Support« ), et quelques autres nouvelles options dans la configuration du noyau.

Une disparition remarquable : le Big Kernel Lock est (enfin) définitivement mort !

Rappelons que ce verrou, présent depuis les premières versions multiprocesseurs de Linux avait pour objectif de protéger certaines parties du noyau contre des exécutions parallèles (en configuration SMP) et les préemptions (en mode PREEMPT). Ce verrou n’était plus utilisé que dans quelques rares portions du kernel, et de nombreux développeurs cherchaient à s’en débarrasser depuis plusieurs années. Pour améliorer la granularité des verrouillages exclusifs, plusieurs mécanismes de synchronisation sont disponibles (spinlock, mutex, rcu, etc.).

Le noyau 2.6.39 marque enfin la disparition définitive du BKL. Vérifions-le en comparant les résultats de recherche de la chaine « kernel_lock() » sur les deux dernières versions stables :

[src ]# cd linux-2.6.38/
[linux-2.6.38]# find . -name '*.[cħ]' | xargs grep -E 'lock_kernel\(\)'
./fs/hpfs/dir.c:	lock_kernel();
./fs/hpfs/dir.c:	unlock_kernel();
./fs/hpfs/dir.c:	lock_kernel();
[...]
./drivers/staging/go7007/s2250-loader.c:	unlock_kernel();
./drivers/staging/usbip/usbip_common.c:	lock_kernel();
./drivers/staging/usbip/usbip_common.c:	unlock_kernel();
[root@tr-a-0 linux-2.6.38]# find . -name '*.[cħ]' | xargs grep -E 'lock_kernel\(\)' | wc -l
298
[root@tr-a-0 linux-2.6.38]# cd ..
[root@tr-a-0 src]# wget http://www.kernel.org/pub/linux/kernel/v2.6/linux-2.6.39.tar.bz2
--2011-05-19 15:19:56--  http://www.kernel.org/pub/linux/kernel/v2.6/linux-2.6.39.tar.bz2
[...]
2011-05-19 15:21:11 (1000 KB/s) - “linux-2.6.39.tar.bz2” saved [76096559/76096559]
[root@tr-a-0 src]# tar -xjf linux-2.6.39.tar.bz2 
[root@tr-a-0 src]# cd linux-2.6.39
[root@tr-a-0 linux-2.6.39]# find . -name '*.[cħ]' | xargs grep -E 'lock_kernel\(\)'
[root@tr-a-0 linux-2.6.39]# find . -name '*.[cħ]' | xargs grep -E 'lock_kernel\(\)' | wc -l
0
[root@tr-a-0 linux-2.6.39]#

Bon débarras !

Je testerai les nouvelles fonctionnalités (par exemple ipset qui permet d’appliquer des règles de filtrage sur des ensembles d’adresses IP) dans les jours à venir, mais pour le moment ce nouveau kernel fonctionne très bien :

[~]# uname -a
Linux tr-a 2.6.39-cpb #1 SMP Thu May 19 12:46:48 CEST 2011 i686 i686 i386 GNU/Linux
[root@tr-a-0 ~]#