Création d’un système complet avec Buildroot 2015.11

Publié par cpb
Déc 08 2015

Création d'un système complet avec Buildroot 2015-11

Il y a quelques jours, la livraison trimestrielle de Buildroot a rendu disponible une version 2015.11. J’ai voulu l’essayer en construisant un petit système pour Raspberry Pi 2. et partager cette expérience qui viendra ainsi en complément de mon article précédent. Buildroot permet de construire un système embarqué plus traditionnel qu’en utilisant une distribution pré-compilée, et d’ajuster plus finement son contenu.

Nous allons successivement préparer une chaîne de compilation croisée, construire un système minimal pour vérifier le bon fonctionnement de celle-ci puis générer un système configuré de façon plus personnalisée.

Environnement de travail

Commençons par créer une arborescence de travail qui contiendra tous nos fichiers personnalisés, les répertoires de construction, la chaîne de compilation, etc.

[~]$ mkdir br-tree
[~]$ cd br-tree
[br-tree]$

Au sein de cet environnement, nous allons essayer de respecter l’organisation des fichiers proposées par le projet Buildroot : une arborescence board/ contenant un sous-répertoire pour chaque carte que nous supporterons (ici le Raspberry Pi 2 uniquement). Tous nos fichiers personnalisés se trouveront dans cette sous-arborescence.

[br-tree]$ mkdir -p board/raspberrypi2/

Nous téléchargeons les sources de la dernière version de Buildroot, les décompressons et entrons dans ce répertoire :

[br-tree]$ wget http://www.buildroot.org/downloads/buildroot-2015.11.tar.bz2
[br-tree]$ tar xjf buildroot-2015.11.tar.bz2
[br-tree]$ cd buildroot-2015.11/

Toolchain

J’ai l’habitude de commencer mes projets embarqués par la construction d’une toolchain de compilation croisée. Il s’agit d’obtenir un compilateur – et tous les outils associés – fonctionnant sur la machine de développement (un PC par exemple) et produisant du code pour la plate-forme cible (ici le Raspberry Pi 2).

Il est tout à fait possible de se procurer une toolchain pré-compilée, mais je trouve qu’il est dommage de se priver de cette étape de construction, d’autant que cela nous permet de maîtriser exactement les versions de la bibliothèque C, du noyau, des outils, etc. que nous souhaitons.

Si j’isole cette étape de la production du système complet, c’est qu’elle prend un temps significatif (environ vingt minutes sur un PC portable moyen avec une connexion Internet ADSL correcte). La toolchain est donc compilée et installée une fois pour toutes, et ne sera plus modifiée même si nous réitérons autant de génération du système que nous le désirons.

J’ai l’habitude de placer la toolchain dans le répertoire board/<target>/cross.

Pour produire la toolchain, nous demandons une configuration de Buildroot par défaut pour la cible choisie, et l’élaguons pour ne laisser que la production du compilateur et de ses outils :

[buildroot-2015.11]$ make raspberrypi2_defconfig
[buildroot-2015.11]$ make menuconfig

Voici la liste des modifications apportées :

  • Menu Target options : pas de changement, mais on peut en profiter pour observer et vérifier le support du processeur cible.
  • Menu Build options :
    • Download dir : nous extrayons de l’arborescence de Buildroot ce répertoire dans lequel il stocke les fichiers téléchargés. Ainsi les compilations successives ne nécessiterons pas de nouveaux téléchargements. Nouvelle valeur : $(TOPDIR)/../dl
    • Host dir : l’emplacement où se trouvera la toolchain compilée. Comme indiqué plus haut, j’ai pour habitude de la placer dans le répertoire board/<target>/cross de notre arborescence de travail. Nouveau chemin : $(TOPDIR)/../board/raspberrypi2/cross
  • Menu Toolchain :
    • C library : c’est un choix qui dépend beaucoup du code métier. La bibliothèque C est un point-clé du système ; c’est elle qui permet d’entrer dans le noyau pour bénéficier de ses services (appels-système). Pour être le plus générique possible, nous choisissons la Gnu C library, un peu plus volumineuse que les autres, mais plus riche également. Nouvelle valeur : glibc
  • Menu System configuration :
    • Init system : cette option contient au préalable BusyBox mais nous la désactivons pour pouvoir éliminer ce package. Nouvelle valeur : None
  • Menu Kernel :
    • Linux Kernel : nous ne voulons, dans un premier temps, produire que la toolchain et rien d’autre. Nous désactivons cette option. Nouvelle valeur : [ ]
  • Menu Target packages :
    • BusyBox : c’est le seul package initialement présent. Nous le désactivons. Nouvelle valeur : [ ]
  • Menu Filesystem images :
    • tar the root filesystem : inutile, nous ne voulons pas de filesystem pour le moment. Nouvelle valeur : [ ]

Sauvegardons la configuration et lançons la compilation :

[buildroot-2015.11]$ cp .config ../board/raspberrypi2/buildroot-01.cfg
[buildroot-2015.11]$ make

Après quelques minutes, la compilation se termine avec ces lignes :

( \
		echo "NAME=Buildroot"; \
		echo "VERSION=2015.11"; \
		echo "ID=buildroot"; \
		echo "VERSION_ID=2015.11"; \
		echo "PRETTY_NAME=\"Buildroot 2015.11\"" \
	) >  /home/cpb/br-tree/buildroot-2015.11/output/target/etc/os-release

Attention, des messages alarmants apparaissent auparavant (des fichiers inexistants, un octet magique incorrect, etc.), c’est parfaitement normal puisque nous n’avons pas créé de système de fichiers.

Vérifions la toolchain produite :

[buildroot-2015.11]$ cd ..
[br-tree]$ ls board/raspberrypi2/cross/usr/bin/
arm-buildroot-linux-gnueabihf-addr2line          arm-linux-c++
arm-buildroot-linux-gnueabihf-ar                 arm-linux-c++.br_real
arm-buildroot-linux-gnueabihf-as                 arm-linux-cc
arm-buildroot-linux-gnueabihf-c++                arm-linux-cc.br_real
arm-buildroot-linux-gnueabihf-c++.br_real        arm-linux-c++filt
arm-buildroot-linux-gnueabihf-cc                 arm-linux-cpp
arm-buildroot-linux-gnueabihf-cc.br_real         arm-linux-cpp.br_real
arm-buildroot-linux-gnueabihf-c++filt            arm-linux-elfedit
arm-buildroot-linux-gnueabihf-cpp                arm-linux-g++
arm-buildroot-linux-gnueabihf-cpp.br_real        arm-linux-g++.br_real
arm-buildroot-linux-gnueabihf-elfedit            arm-linux-gcc
arm-buildroot-linux-gnueabihf-g++                arm-linux-gcc-4.9.3
arm-buildroot-linux-gnueabihf-g++.br_real        arm-linux-gcc-4.9.3.br_real
arm-buildroot-linux-gnueabihf-gcc                arm-linux-gcc-ar
arm-buildroot-linux-gnueabihf-gcc-4.9.3          arm-linux-gcc.br_real
arm-buildroot-linux-gnueabihf-gcc-4.9.3.br_real  arm-linux-gcc-nm
arm-buildroot-linux-gnueabihf-gcc-ar             arm-linux-gcc-ranlib
arm-buildroot-linux-gnueabihf-gcc.br_real        arm-linux-gcov
arm-buildroot-linux-gnueabihf-gcc-nm             arm-linux-gprof
arm-buildroot-linux-gnueabihf-gcc-ranlib         arm-linux-ld
arm-buildroot-linux-gnueabihf-gcov               arm-linux-ld.bfd
arm-buildroot-linux-gnueabihf-gprof              arm-linux-nm
arm-buildroot-linux-gnueabihf-ld                 arm-linux-objcopy
arm-buildroot-linux-gnueabihf-ld.bfd             arm-linux-objdump
arm-buildroot-linux-gnueabihf-nm                 arm-linux-ranlib
arm-buildroot-linux-gnueabihf-objcopy            arm-linux-readelf
arm-buildroot-linux-gnueabihf-objdump            arm-linux-size
arm-buildroot-linux-gnueabihf-ranlib             arm-linux-strings
arm-buildroot-linux-gnueabihf-readelf            arm-linux-strip
arm-buildroot-linux-gnueabihf-size               gawk
arm-buildroot-linux-gnueabihf-strings            igawk
arm-buildroot-linux-gnueabihf-strip              m4
arm-linux-addr2line                              mkknlimg
arm-linux-ar                                     toolchain-wrapper
arm-linux-as
[br-tree]$

La toolchain de cross-compilation regroupe tous les outils dont les noms sont préfixés par l’architecture (arm), l’outil de production (buildroot), le système d’exploitation de la cible (linux) et les conventions d’interfaçage binaire entre applications et système (gnueabi). Pour simplifier l’appel des outils, des liens symboliques existent raccourcissant le préfixe à l’architecture et le système d’exploitation. On invoquera donc arm-linux-gcc ou arm-linux-g++ par exemple.

[br-tree]$ board/raspberrypi2/cross/usr/bin/arm-linux-gcc -v
Utilisation des specs internes.
COLLECT_GCC=/home/cpb/br-tree/board/raspberrypi2/cross/usr/bin/arm-linux-gcc.br_real
COLLECT_LTO_WRAPPER=/home/cpb/br-tree/board/raspberrypi2/cross/usr/bin/../libexec/gcc/arm-buildroot-linux-gnueabihf/4.9.3/lto-wrapper
Target: arm-buildroot-linux-gnueabihf
Configuré avec: ./configure --prefix=/home/cpb/br-tree/buildroot-2015.11/../board/raspberrypi2/cross//usr --sysconfdir=/home/cpb/br-
tree/buildroot-2015.11/../board/raspberrypi2/cross//etc --enable-static --target=arm-buildroot-linux-gnueabihf --with-sysroot=/home/
cpb/br-tree/buildroot-2015.11/../board/raspberrypi2/cross//usr/arm-buildroot-linux-gnueabihf/sysroot --disable-__cxa_atexit --with-g
nu-ld --disable-libssp --disable-multilib --with-gmp=/home/cpb/br-tree/buildroot-2015.11/../board/raspberrypi2/cross//usr --with-mpf
r=/home/cpb/br-tree/buildroot-2015.11/../board/raspberrypi2/cross//usr --with-pkgversion='Buildroot 2015.11' --with-bugurl=http://bu
gs.buildroot.net/ --disable-libquadmath --enable-tls --disable-libmudflap --enable-threads --with-mpc=/home/cpb/br-tree/buildroot-20
15.11/../board/raspberrypi2/cross//usr --without-isl --without-cloog --disable-decimal-float --with-abi=aapcs-linux --with-cpu=corte
x-a7 --with-fpu=neon-vfpv4 --with-float=hard --with-mode=arm --enable-languages=c,c++ --with-build-time-tools=/home/cpb/br-tree/buil
droot-2015.11/../board/raspberrypi2/cross//usr/arm-buildroot-linux-gnueabihf/bin --enable-shared --disable-libgomp
Modèle de thread: posix
gcc version 4.9.3 (Buildroot 2015.11)

Si l’on souhaite pouvoir invoquer directement le cross-compiler depuis la ligne de commande sans préciser tout le chemin (par exemple pendant une phase de développement de code métier hors Buildroot), on peut éditer le fichier ~/.bashrc afin d’y ajouter à la fin la ligne suivante :

PATH=$PATH:~/br-tree/board/raspberrypi2/cross/usr/bin/

Système complet

Nous allons construire à présent une image d’un système complet, y compris le noyau, en utilisant la toolchain obtenue précédemment. Il nous faut effacer les fichiers objets, fichiers temporaires, etc. produits auparavant et l’on serait tenté de faire un make clean. Abstenons-nous en néanmoins car cela aurait pour effet d’effacer la toolchain compilée. La solution la plus simple pour éviter les erreurs de manipulation est de supprimer le répertoire de compilation de Buildroot et de décompresser à nouveau l’archive téléchargée.

[buildroot-2015.11]$ cd ..
[br-tree]$ rm -rf buildroot-2015.11
[br-tree]$ tar xjf buildroot-2015.11.tar.bz2
[br-tree]$ cd buildroot-2015.11

Puis nous préparons une nouvelle configuration, toujours, en partant de celle par défaut.

[buildroot-2015.11]$ make raspberrypi2_defconfig
[buildroot-2015.11]$ make menuconfig

Passons en revue les menus pour observer ce qu’il faut modifier :

  • Target options : rien à changer
  • Build options :
    • Download dir : configurons le répertoire de téléchargement pour retrouver le précédent. Nouvelle valeur : $(TOPDIR)/../dl
  • Toolchain : plusieurs modifications sont nécessaires pour retrouver la toolchain précédente.
    • Toolchain type : nous souhaitons que Buildroot considère la toolchain comme préexistante, même si c’est lui qui l’a créée auparavant. Nouvelle valeur : External toolchain
    • Toolchain : elle a été compilée spécifiquement. Nouvelle valeur : Custom toolchain
    • Toolchain origin : il n’est pas nécessaire de la télécharger. Valeur conservée : Pre-installed toolchain
    • Toolchain path : le répertoire dans lequel se trouve le sous-répertoire bin de la chaîne de compilation. Nouvelle valeur : $(TOPDIR)/../board/rapsberrypi2/cross/usr
    • External toolchain gcc version : si vous n’avez pas noté ce numéro de version lors de la configuration de la toolchain, vous pouvez l’obtenir en appelant arm-linux-gcc -v comme ci-dessus. Nouvelle valeur : 4.9.x
    • External toolchain kernel headers series : on peut retrouver le numéro de version si on ne l’a pas noté, mais c’est plus compliqué. Il faut regarder le contenu du fichier ../board/raspberrypi2/cross/usr/arm-buildroot-linux-gnueabihf/sysroot/usr/include/linux/version.h. On y trouve une valeur LINUX_VERSION_CODE 262405. Il faut convertir ce nombre en hexadécimal, par exemple en saisissant sur la ligne de commande du shell printf '%x\n' 262405. Ceci nous affiche 40105 qui représente le numéro de noyau 4.1.5. Nouvelle valeur : 4.1.x
    • External toolchain C library : en tant que bibliothèque C, nous avons choisi de compiler une GlibC. Nouvelle valeur : glibc/eglibc
    • Toolchain has C++ support : cette option était activée par défaut lors de la compilation précédente. Nouvelle valeur : [*]
  • System Configuration : pour l’instant nous ne changeons pratiquement rien dans ce menu, mais nous l’ajusterons un peu plus tard.
    • [*] Run a getty (login prompt) after boot ---> : Je préfère me connecter au Raspberry Pi 2 en utilisant la console série (comme sur la plupart des systèmes embarqués que je configure) plutôt que l’écran HDMI et le clavier USB. Je modifie en conséquence le paramètre suivant :
      • TTY port : j’indique le port série du Raspberry Pi 2. Nouvelle valeur : ttyAMA0
  • Kernel : rien à changer
  • Target packages : rien à changer
  • Filesystem images : rien à changer
  • Bootloaders : rien à changer
  • Host utilities : rien à changer
  • Legacy config options : rien à changer

À nouveau, sauvegardons notre configuration pour pouvoir la réutiliser directement si besoin et lançons la compilation.

[buildroot-2015.11]$ cp .config ../board/raspberrypi2/buildroot-02.cfg
[buildroot-2015.11]$ make

La compilation se termine au bout de quelques minutes sur un message plutôt surprenant…

/br-tree/buildroot-2015.11/output/build/_fakeroot.fs
rootdir=/home/cpb/br-tree/buildroot-2015.11/output/target
table='/home/cpb/br-tree/buildroot-2015.11/output/build/_device_table.txt'
/usr/bin/install -m 0644 support/misc/target-dir-warning.txt /home/cpb/br-tree/buildroot-2015.11/output/ta
rget/THIS_IS_NOT_YOUR_ROOT_FILESYSTEM
[buildroot-2015.11]

Mais que signifie donc ce THIS_IS_NOT_YOUR_ROOT_FILESYSTEM ?

Il s’agit en fait d’un nom de fichier, très anodin. Lorsque Buildroot prépare l’arborescence de la cible, il construit une représentation de son système de fichiers, qui se trouve dans output/target. Ces fichiers sont créés en appartenant à l’utilisateur courant. Or les fichiers systèmes (ceux se trouvant dans les répertoires /bin, /etc, /usr… de la cible) doivent appartenir à root. Pour pouvoir produire une image (une archive tar par exemple) avec les bonnes appartenances, on fait appel à un utilitaire nommé fakeroot qui modifie les droits au moment de la création de l’archive. Pas d’inquiétude, il n’y a rien de malicieux là-dessous, aucun problème de sécurité.

Comme le répertoire output/target contient des fichiers n’ayant pas la bonne appartenance, il ne faut pas l’utiliser aveuglément, ne pas le copier directement sur une cible où l’exporter pour un montage NFS root. C’est ce que Buildroot nous rappelle en créant ce fameux fichier :

[buildroot-2015.11]$ ls output/target/
bin  lib      media  proc  sbin                              tmp
dev  lib32    mnt    root  sys                               usr
etc  linuxrc  opt    run   THIS_IS_NOT_YOUR_ROOT_FILESYSTEM  var
[buildroot-2015.11]$

Installation et boot

Insérons une carte micro-SD sur le poste de développement (par exemple avec un adaptateur USB). On recherche alors le nom du périphérique bloc qu’elle représente.

[buildroot-2015.11]$ dmesg | tail
[21924.805390] sd 5:0:0:0: [sdc] No Caching mode page found
[21924.805395] sd 5:0:0:0: [sdc] Assuming drive cache: write through
[21924.805400] sd 5:0:0:0: [sdc] Attached SCSI removable disk
[21926.017065] EXT4-fs (sdc2): recovery complete
[21926.020278] EXT4-fs (sdc2): mounted filesystem with ordered data mode. Opts: (null)

Dans cet exemple, il s’agit du périphérique sdc, c’est ce que nous utiliserons ci-dessous.

Attention à ne pas vous tromper d’identifiant de périphérique ! cela pourrait être dangereux pour votre système si vous confondez avec votre disque dur par exemple.

Je démonte les partitions auto-montées de la carte micro-SD et j’efface complètement ses premiers secteurs.

[buildroot-2015.11]$ umount /dev/sdc?
[buildroot-2015.11]$ sudo dd if=/dev/zero of=/dev/sdc bs=1M count=16
16+0 enregistrements lus
16+0 enregistrements écrits
16777216 octets (17 MB) copiés, 3,82191 s, 4,4 MB/s

Partitionnons la carte pour obtenir :

  • Une première partition bootable au format Dos Vfat : ici j’ai choisi une taille de 128 Mo pour pouvoir faire des expériences avec des noyaux supplémentaires, U-boot, etc. En réalité une partition de 16 Mo suffira largement.
  • Une seconde partition au format Linux s’étendant sur le reste de la carte micro-SD.
[buildroot-2015.11]$ sudo fdisk /dev/sdc
  [...]
Commande (m pour l'aide) : n
Partition type:
   p   primary (0 primary, 0 extended, 4 free)
   e   extended
Select (default p):(Entrée)
Numéro de partition (1-4, 1 par défaut) : (Entrée)
Premier secteur (2048-7741439, 2048 par défaut) : (Entrée)
Dernier secteur, +secteurs ou +taille{K,M,G} (2048-7741439, 7741439 par défaut) : +128M
Commande (m pour l'aide) : t
Partition sélectionnée 1
Code Hexa (taper L pour lister les codes): c
Type système de partition modifié de 1 à c (W95 FAT32 (LBA))
Commande (m pour l'aide) : n
Partition type:
   p   primary (1 primary, 0 extended, 3 free)
   e   extended
Select (default p): (Entrée)
Numéro de partition (1-4, 2 par défaut) : (Entrée)
Premier secteur (264192-7741439, 264192 par défaut) : (Entrée)
Dernier secteur, +secteurs ou +taille{K,M,G} (264192-7741439, 7741439 par défaut) : (Entrée)
Commande (m pour l'aide) : a
Numéro de partition (1-4): 1
Commande (m pour l'aide) : p
[...]
Périphérique Amorçage  Début         Fin      Blocs    Id. Système
/dev/sdc1   *        2048      264191      131072    c  W95 FAT32 (LBA)
/dev/sdc2          264192     7741439     3738624   83  Linux
Commande (m pour l'aide) : w
  [...]
[buildroot-2015.11]$

Nous formatons les deux partitions, l’une au format vfat (le seul format connu par le firmware du Raspberry Pi 2 qui doit charger en mémoire le bootloader), la seconde au format classique Linux ext2. L’absence de journalisation des données dans ce format permet de limiter l’usure des cartes flash en évitant les écritures supplémentaires. Je nomme classiquement mes partitions BOOT et ROOT afin de les identifier aisément.

[buildroot-2015.11]$ sudo mkfs.vfat -n BOOT /dev/sdc1
[buildroot-2015.11]$ sudo mkfs.ext2 -L ROOT /dev/sdc2

Extrayons à présent la carte micro-SD et réinsérons-la afin que l’auto-monteur nous donne un accès immédiat aux partitions.

Tous les éléments produits par Buildroot se trouvent dans son arborescence output/. Je m’intéresse en particulier à output/images/ qui contient les éléments à installer sur le système cible.

Nous allons copier sur la première partition :

  • les fichiers du bootloader du Raspberry Pi 2, précompilés et propriétaires, que Buildroot à téléchargés et copiés dans output/images/rpi-firmware ;
  • le fichier dtb (Device Tree Blob) qui contient la description du matériel permettant l’utilisation d’un noyau générique.
  • le noyau zImage, que nous ne copions pas directement mais installons par l’intermédiaire de l’utilitaire mkknlimg qui lui ajoute un suffixe indiquant qu’il contient le support du Device Tree.
[buildroot-2015.11]$ ls output/images/
bcm2709-rpi-2-b.dtb  rootfs.tar  rpi-firmware  zImage
[buildroot-2015.11]$ sudo cp output/images/bcm2709-rpi-2-b.dtb  /media/cpb/BOOT/
[buildroot-2015.11]$ sudo cp output/images/rpi-firmware/*  /media/cpb/BOOT/
[buildroot-2015.11]$ sudo ./output/host/usr/bin/mkknlimg  output/images/zImage  /media/cpb/BOOT/zImage
Version: Linux version 4.1.5-v7 (cpb@Logilin) (gcc version 4.9.3 (Buildroot 2015.11) ) #1 SMP PREEMPT Wed Dec 2 13:38:15 CET 2015
DT: y
DDT: n
283x: n

Pour voir les traces de boot du noyau sur le port série du Raspberry Pi 2, nous éditons le fichier cmdline.txt se trouvant dans la partition BOOT, et ajoutons sur la première ligne (attention, il ne doit y avoir qu’une seule ligne dans ce fichier) la chaîne de caractères suivante console=ttyAMA0,115200.

Sur la seconde partition, nous décompressons toute l’archive tar produite par Buildroot. Pour que les appartenances des fichiers soient correctement respectées, il est nécessaire de le faire avec les droits root. Ensuite nous démontons proprement les deux partitions.

[buildroot-2015.11]$ sudo tar xf output/images/rootfs.tar  -C /media/cpb/ROOT/
[buildroot-2015.11]$ umount /media/cpb/*

J’insère la carte micro-SD sur un Raspberry Pi 2 auquel je suis relié par une liaison série, et j’observe les messages suivants à la mise sous tension.

Uncompressing Linux... done, booting the kernel.                                                                                                         
[    0.832142] Switched to clocksource arch_sys_counter                                                                                                   
[    0.888108] FS-Cache: Loaded                                                                                                                           
[    0.891365] CacheFiles: Loaded
[    0.906112] NET: Registered protocol family 2
[    0.911787] TCP established hash table entries: 8192 (order: 3, 32768 bytes)
[    0.919008] TCP bind hash table entries: 8192 (order: 4, 65536 bytes)
[    0.925674] TCP: Hash tables configured (established 8192 bind 8192)
[    0.932165] UDP hash table entries: 512 (order: 2, 16384 bytes)
[    0.938130] UDP-Lite hash table entries: 512 (order: 2, 16384 bytes)
[    0.944853] NET: Registered protocol family 1
[    0.949645] RPC: Registered named UNIX socket transport module.
[    0.955646] RPC: Registered udp transport module.
[    0.960346] RPC: Registered tcp transport module.
[    0.965063] RPC: Registered tcp NFSv4.1 backchannel transport module.
[    0.972612] hw perfevents: enabled with armv7_cortex_a7 PMU driver, 5 counters available
[    0.982104] futex hash table entries: 1024 (order: 4, 65536 bytes)
[    1.004416] VFS: Disk quotas dquot_6.6.0
[    1.008720] VFS: Dquot-cache hash table entries: 1024 (order 0, 4096 bytes)
[    1.018425] FS-Cache: Netfs 'nfs' registered for caching
[    1.024905] NFS: Registering the id_resolver key type
[    1.030011] Key type id_resolver registered
[    1.034264] Key type id_legacy registered
[    1.041110] Block layer SCSI generic (bsg) driver version 0.4 loaded (major 252)
[    1.048794] io scheduler noop registered
[    1.052810] io scheduler deadline registered
[    1.057414] io scheduler cfq registered (default)
[    1.064669] BCM2708FB: allocated DMA memory f8800000
[    1.069667] BCM2708FB: allocated DMA channel 0 @ f3007000
[    1.081887] Console: switching to colour frame buffer device 90x30
[    1.092405] Serial: 8250/16550 driver, 0 ports, IRQ sharing disabled
[    1.099985] vc-cma: Videocore CMA driver
[    1.103939] vc-cma: vc_cma_base      = 0x00000000
[    1.108636] vc-cma: vc_cma_size      = 0x00000000 (0 MiB)
[    1.114048] vc-cma: vc_cma_initial   = 0x00000000 (0 MiB)
[    1.119688] vc-mem: phys_addr:0x00000000 mem_base=0x3dc00000 mem_size:0x3f000000(1008 MiB)
[    1.143850] brd: module loaded
[    1.156001] loop: module loaded
[    1.160180] vchiq: vchiq_init_state: slot_zero = 0xb8880000, is_master = 0
[    1.168931] Loading iSCSI transport class v2.0-870.
[    1.174819] usbcore: registered new interface driver smsc95xx
[    1.180646] dwc_otg: version 3.00a 10-AUG-2012 (platform bus)
[    1.386775] Core Release: 2.80a
[    1.389922] Setting default values for core params
[    1.394786] Finished setting default values for core params
[    1.600754] Using Buffer DMA mode
[    1.604091] Periodic Transfer Interrupt Enhancement - disabled
[    1.609915] Multiprocessor Interrupt Enhancement - disabled
[    1.615500] OTG VER PARAM: 0, OTG VER FLAG: 0
[    1.619856] Dedicated Tx FIFOs mode
[    1.623734] WARN::dwc_otg_hcd_init:1047: FIQ DMA bounce buffers: virt = 0xb8814000 dma = 0xf8814000 len=9024
[    1.633612] FIQ FSM acceleration enabled for :
[    1.633612] Non-periodic Split Transactions
[    1.633612] Periodic Split Transactions
[    1.633612] High-Speed Isochronous Endpoints
[    1.650386] WARN::hcd_init_fiq:412: FIQ on core 1 at 0x80413218
[    1.656305] WARN::hcd_init_fiq:413: FIQ ASM at 0x80413588 length 36
[    1.662569] WARN::hcd_init_fiq:438: MPHI regs_base at 0xb909a000
[    1.668603] dwc_otg 3f980000.usb: DWC OTG Controller
[    1.673680] dwc_otg 3f980000.usb: new USB bus registered, assigned bus number 1
[    1.681016] dwc_otg 3f980000.usb: irq 32, io mem 0x00000000
[    1.686653] Init: Port Power? op_state=1
[    1.690569] Init: Power Port (0)
[    1.694101] usb usb1: New USB device found, idVendor=1d6b, idProduct=0002
[    1.700890] usb usb1: New USB device strings: Mfr=3, Product=2, SerialNumber=1
[    1.708137] usb usb1: Product: DWC OTG Controller
[    1.712863] usb usb1: Manufacturer: Linux 4.1.5-v7 dwc_otg_hcd
[    1.718692] usb usb1: SerialNumber: 3f980000.usb
[    1.724204] hub 1-0:1.0: USB hub found
[    1.728005] hub 1-0:1.0: 1 port detected
[    1.732954] usbcore: registered new interface driver usb-storage
[    1.739227] mousedev: PS/2 mouse device common for all mice
[    1.745700] bcm2835-cpufreq: min=600000 max=900000
[    1.750865] sdhci: Secure Digital Host Controller Interface driver
[    1.757068] sdhci: Copyright(c) Pierre Ossman
[    1.761869] mmc-bcm2835 3f300000.mmc: mmc_debug:0 mmc_debug2:0
[    1.767728] mmc-bcm2835 3f300000.mmc: DMA channels allocated
[    1.812493] sdhci-pltfm: SDHCI platform and OF driver helper
[    1.824209] ledtrig-cpu: registered to indicate activity on CPUs
[    1.830499] hidraw: raw HID events driver (C) Jiri Kosina
[    1.837286] usbcore: registered new interface driver usbhid
[    1.843977] usbhid: USB HID core driver
[    1.849291] Initializing XFRM netlink socket
[    1.853703] NET: Registered protocol family 17
[    1.861673] Key type dns_resolver registered
[    1.866448] Registering SWP/SWPB emulation handler
[    1.872248] registered taskstats version 1
[    1.876594] vc-sm: Videocore shared memory driver
[    1.881301] [vc_sm_connected_init]: start
[    1.886168] [vc_sm_connected_init]: end - returning 0
[    1.892592] uart-pl011 3f201000.uart: no DMA platform data
[    1.898409] Waiting for root device /dev/mmcblk0p2...
[    1.903640] mmc0: host does not support reading read-only switch, assuming write-enable
[    1.913753] mmc0: new high speed SDHC card at address b368
[    1.919832] mmcblk0: mmc0:b368 SMI   3.69 GiB 
[    1.924456] Indeed it is in host mode hprt0 = 00021501
[    1.942943]  mmcblk0: p1 p2
[    2.013559] EXT4-fs (mmcblk0p2): couldn't mount as ext3 due to feature incompatibilities
[    2.022462] EXT4-fs (mmcblk0p2): mounting ext2 file system using the ext4 subsystem
[    2.042841] EXT4-fs (mmcblk0p2): mounted filesystem without journal. Opts: (null)
[    2.050390] VFS: Mounted root (ext2 filesystem) readonly on device 179:2.
[    2.065487] devtmpfs: mounted
[    2.069355] Freeing unused kernel memory: 424K (80788000 - 807f2000)
[    2.102224] usb 1-1: new high-speed USB device number 2 using dwc_otg
[    2.108947] Indeed it is in host mode hprt0 = 00001101
[    2.297336] EXT4-fs (mmcblk0p2): warning: mounting unchecked fs, running e2fsck is recommended
[    2.312601] usb 1-1: New USB device found, idVendor=0424, idProduct=9514
[    2.319306] usb 1-1: New USB device strings: Mfr=0, Product=0, SerialNumber=0
[    2.327381] hub 1-1:1.0: USB hub found
[    2.331252] hub 1-1:1.0: 5 ports detected
[    2.368084] EXT4-fs (mmcblk0p2): re-mounted. Opts: (null)
Starting logging: OK
Initializing random number generator... [    2.505165] random: dd urandom read with 59 bits of entropy available
done.
Starting network...
[    2.612233] usb 1-1.1: new high-speed USB device number 3 using dwc_otg
Welcome to Buildroot
buildroot login: [    2.732562] usb 1-1.1: New USB device found, idVendor=0424, idProduct=ec00
[    2.739446] usb 1-1.1: New USB device strings: Mfr=0, Product=0, SerialNumber=0
[    2.750075] smsc95xx v1.0.4
[    2.816413] smsc95xx 1-1.1:1.0 eth0: register 'smsc95xx' at usb-3f980000.usb-1.1, smsc95xx USB 2.0 Ethernet, b8:27:eb:ff:aa:a8

En fait, le boot du noyau est bien terminé. Il a déjà affiché un message de bienvenue et une invite de connexion. Néanmoins le contrôleur USB a mis du temps à démarrer et de nouvelles traces ont été affichées, masquant la réussite du démarrage. Il faut appuyer sur Entrée pour que le système nous ré-affiche son prompt de connexion.

Welcome to Buildroot
buildroot login: root
# uname -a
Linux buildroot 4.1.5-v7 #1 SMP PREEMPT Wed Dec 2 13:38:15 CET 2015 armv7l GNU/Linux

Le noyau correspondant bien à la version indiquée plus haut. Vérifions le processeur du Raspberry Pi2.

# cat /proc/cpuinfo
processor       : 0
model name      : ARMv7 Processor rev 5 (v7l)
BogoMIPS        : 38.40
Features        : half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt vfpd32 lpae evtstrm 
CPU implementer : 0x41
CPU architecture: 7
CPU variant     : 0x0
CPU part        : 0xc07
CPU revision    : 5

processor       : 1
model name      : ARMv7 Processor rev 5 (v7l)
BogoMIPS        : 38.40
Features        : half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt vfpd32 lpae evtstrm 
CPU implementer : 0x41
CPU architecture: 7
CPU variant     : 0x0
CPU part        : 0xc07
CPU revision    : 5

processor       : 2
model name      : ARMv7 Processor rev 5 (v7l)
BogoMIPS        : 38.40
Features        : half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt vfpd32 lpae evtstrm 
CPU implementer : 0x41
CPU architecture: 7
CPU variant     : 0x0
CPU part        : 0xc07
CPU revision    : 5

processor       : 3
model name      : ARMv7 Processor rev 5 (v7l)
BogoMIPS        : 38.40
Features        : half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt vfpd32 lpae evtstrm 
CPU implementer : 0x41
CPU architecture: 7
CPU variant     : 0x0
CPU part        : 0xc07
CPU revision    : 5

Hardware        : BCM2709
Revision        : a01041
Serial          : 00000000f0ff000
#

Nous avons bien observé les quatre cœurs de processeur du Raspberry Pi 2. Examinons l’état de la mémoire :

# free
             total       used       free     shared    buffers     cached
Mem:        911512      18156     893356         40       1948       2128
-/+ buffers/cache:      14080     897432
Swap:            0          0          0

Le système compte au total un Go (dont une partie est réservée pour le contrôleur graphique) et dispose de 897 Mo de mémoire libre. En pressant deux fois la touche tabulation, nous pouvons voir la liste des commandes disponibles :

# (tab) (tab)
[                  flock              lzcat              sha256sum
[[                 fold               lzma               sha3sum
addgroup           free               makedevs           sha512sum
adduser            freeramdisk        md5sum             sleep
ar                 fsck               mdev               sort
arp                fstrim             mesg               start-stop-daemon
arping             fuser              microcom           strings
ash                getopt             mkdir              stty
awk                getty              mkfifo             su
basename           grep               mknod              sulogin
blkid              gunzip             mkswap             swapoff
bunzip2            gzip               mktemp             swapon
busybox            halt               modprobe           switch_root
bzcat              hdparm             more               sync
cat                head               mount              sysctl
catv               hexdump            mountpoint         syslogd
chattr             hostid             mt                 tail
chgrp              hostname           mv                 tar
chmod              hwclock            nameif             tee
chown              i2cdetect          netstat            telnet
chroot             i2cdump            nice               test
chrt               i2cget             nohup              tftp
chvt               i2cset             nslookup           time
cksum              id                 od                 top
clear              ifconfig           openvt             touch
cmp                ifdown             passwd             tr
cp                 ifup               patch              traceroute
cpio               inetd              pidof              true
crond              init               ping               truncate
crontab            insmod             pipe_progress      tty
cut                install            pivot_root         udhcpc
date               ip                 poweroff           uevent
dc                 ipaddr             printenv           umount
dd                 ipcrm              printf             uname
deallocvt          ipcs               ps                 uniq
delgroup           iplink             pwd                unix2dos
deluser            iproute            rdate              unlink
devmem             iprule             readlink           unlzma
df                 iptunnel           readprofile        unxz
diff               kill               realpath           unzip
dirname            killall            reboot             uptime
dmesg              killall5           renice             usleep
dnsd               klogd              reset              uudecode
dnsdomainname      last               resize             uuencode
dos2unix           less               rm                 vconfig
du                 linux32            rmdir              vi
dumpkmap           linux64            rmmod              vlock
echo               ln                 route              watch
egrep              loadfont           run-parts          watchdog
eject              loadkmap           runlevel           wc
env                logger             sed                wget
ether-wake         login              seq                which
expr               logname            setarch            who
false              losetup            setconsole         whoami
fbset              ls                 setkeycodes        xargs
fdflush            lsattr             setlogcons         xz
fdformat           lsmod              setserial          xzcat
fdisk              lsof               setsid             yes
fgrep              lspci              sh                 zcat
find               lsusb              sha1sum
#

La commande ps nous affiche la liste des processus présents :

# ps
PID   USER     COMMAND
    1 root     init
    2 root     [kthreadd]
    3 root     [ksoftirqd/0]
    4 root     [kworker/0:0]
    5 root     [kworker/0:0H]
    6 root     [kworker/u8:0]
    7 root     [rcu_preempt]
    8 root     [rcu_sched]
    9 root     [rcu_bh]
   10 root     [migration/0]
   11 root     [migration/1]
   12 root     [ksoftirqd/1]
   14 root     [kworker/1:0H]
   15 root     [migration/2]
   16 root     [ksoftirqd/2]
   17 root     [kworker/2:0]
   18 root     [kworker/2:0H]
   19 root     [migration/3]
   20 root     [ksoftirqd/3]
   21 root     [kworker/3:0]
   22 root     [kworker/3:0H]
   23 root     [khelper]
   24 root     [kdevtmpfs]
   25 root     [netns]
   26 root     [perf]
   27 root     [khungtaskd]
   28 root     [writeback]
   29 root     [crypto]
   30 root     [bioset]
   31 root     [kblockd]
   32 root     [kworker/1:1]
   33 root     [rpciod]
   34 root     [kswapd0]
   35 root     [fsnotify_mark]
   36 root     [nfsiod]
   42 root     [kthrotld]
   43 root     [kworker/0:1]
   44 root     [VCHIQ-0]
   45 root     [VCHIQr-0]
   46 root     [VCHIQs-0]
   47 root     [iscsi_eh]
   48 root     [dwc_otg]
   49 root     [DWC Notificatio]
   51 root     [VCHIQka-0]
   52 root     [SMIO]
   53 root     [deferwq]
   54 root     [kworker/u8:2]
   55 root     [mmcqd/0]
   56 root     [kworker/0:1H]
   57 root     [ext4-rsv-conver]
   58 root     [kworker/1:1H]
   59 root     [kworker/1:2]
   60 root     [kworker/2:1]
   69 root     [kworker/2:1H]
   71 root     /sbin/syslogd -n
   74 root     /sbin/klogd -n
   93 root     [kworker/3:1]
  145 root     [kworker/0:2]
  149 root     -sh
  153 root     ps
#

Hormis les threads du noyau (toutes les tâches avec des noms entre crochets), nous observons la présence de seulement cinq processus :

  • init : le premier processus qui est chargé d’abord de l’initialisation du système depuis l’espace utilisateur et par la suite de « l’adoption » des processus dont les parents se terminent ;
  • syslogd et klogd : démons chargés de l’enregistrement des messages du système ;
  • sh le shell sur lequel nous sommes connectés et la commande ps elle-même.

 

Voilà un système dont le contenu est bien sous contrôle !

 

Affinement de la configuration

Nous pouvons faire une première série d’améliorations, afin d’obtenir un système un peu plus convivial, accueillant un autre utilisateur que root par exemple ou renforçant la partition principale contre les risques de coupures d’alimentation intempestives.

Configuration de Buildroot

[buildroot-2015.11]$ make menuconfig
  • Menu System configuration :
    • System hostname: Choisissons un nom plus représentatif pour notre carte. Il apparaîtra par exemple dans l’invite de connexion, et nous l’afficherons également dans le prompt du shell. Nouvelle valeur : R-Pi.
    • System banner : Cette petite phrase s’affichera au démarrage avant la proposition de connexion ; on peut la personnaliser à volonté. Nouvelle valeur : Welcome on board!
    • Enable root login with password : Si le système a la moindre chance de se retrouver connecté à Internet, il est préférable de désactiver cette option. En effet le compte root sera le premier visé par les attaques automatiques par force brute. Si cette option est désactivée, il faudra intégrer la commande sudo afin de pouvoir réaliser les opérations d’administration. Sur un système expérimental, nous laissons la valeur originale : [*].
    • Root password : De même, il est conseillé de choisir pour tous les comptes des mots de passe solides (longs, assez faciles à retenir mais difficiles à deviner). Pour cette démonstration prenons un mot de passe ridiculement simple. Nouvelle valeur root.
    • remount root filesystem read-write during boot : Sur un système embarqué où l’alimentation peut être coupée à tout moment, il est conseillé de conserver le système de fichiers principal en lecture-seule. On le basculera en lecture-écriture temporairement pour des modifications de configuration par exemple. Nouvelle valeur : [ ]
    • Network interface to configure through DHCP : Suivant la configuration, on utilisera ou non une configuration réseau par DHCP. Si tel est le cas, on indique ici le nom de l’interface Ethernet. Nouvelle valeur : eth0.
    • Path to the users tables : On indique ici le chemin d’accès pour un fichier contenant la liste des utilisateurs (voir plus loin). Nouvelle valeur : $(TOPDIR)/../board/raspberrypi2/users.cfg.
    • Root filesystem overlay directories : Le répertoire indiqué ici est l’origine d’une arborescence qui sera appliquée « par-dessus » le système de fichiers obtenu à l’issue des compilations et installations, avant de préparer l’image de sortie. Autrement dit notre arborescence va venir se superposer (remplaçant éventuellement des fichiers) à celle se trouvant dans output/target avant de la stocker dans output/image/rootfs.tar. Nous détaillerons plus loin ce qu’il faut ajouter dans cet overlay. Nouvelle valeur : $(TOPDIR)/../board/raspberrypi2/ovl.

Table des utilisateurs

Nous avons rempli l’option Path to the users tables avec le nom d’un fichier qui contient la liste des utilisateurs. Il doit y avoir un compte par ligne. Les champs, séparés par un espace, sont les suivants :

  • login : identifiant de connexion du compte (sauf root).
  • uid : numéro d’utilisateur. -1 pour que l’attribution soit automatique.
  • group : groupe principal de l’utilisateur. Généralement le même nom que le login, ou alors un groupe global pour tous les comptes, comme users.
  • gid : numéro du groupe. -1 pour une attribution automatique.
  • password : le mot de passe, en clair si précédé d’un ‘=‘, crypté sinon. Si le mot de passe est ‘!‘, pas de connexion possible (compte utilisé pour un démon système par exemple).
  • home : répertoire personnel (aucun si ‘-‘).
  • shell : le shell de connexion. Sur notre système minimal, /bin/sh est un shell ash inclus dans Busybox.
  • groups : ce champ contient la liste des groupes supplémentaires auxquels appartient l’utilisateur (-1 si aucun).
  • gecos : des informations sur le compte, comme le nom en clair de l’utilisateur. Ce dernier champ peut contenir éventuellement des espaces.

 

Voici notre fichier ../board/raspberrypi2/users.cfg :

rpi -1 rpi -1 =rpi /home/rpi /bin/sh - Raspberry Pi 2 user

Overlay

Comme indiqué plus haut nous nous créons une arborescence spécifique, contenant des fichiers qui viendront s’ajouter à ceux produits par Buildroot.

[buildroot-2015.11]$ mkdir -p ../board/raspberrypi2/ovl/usr/local/bin/

Scripts supplémentaires

Le système de fichiers principal est monté en lecture seule. Mais il est parfois nécessaire de repasser temporairement en lecture-écriture. Pour cela j’ai l’habitude de créer deux petits scripts rw et ro qui remontent la racine du système de fichiers respectivement en lecture-écriture ou lecture seule. Pour que Buildroot puisse les intégrer automatiquement dans l’image qu’il produit, nous les plaçons dans l’arborescence overlay :

[buildroot-2015.11]$ nano ../board/raspberrypi2/ovl/usr/local/bin/rw

Contenu du script rw

#! /bin/sh

mount / -o rw,remount
[buildroot-2015.11]$ cp ../board/raspberrypi2/ovl/usr/local/bin/rw ../board/raspberrypi2/ovl/usr/local/bin/ro
[buildroot-2015.11]$ nano ../board/raspberrypi2/ovl/usr/local/bin/ro

Contenu du script ro

#! /bin/sh

mount / -o ro,remount
[buildroot-2015.11]$ chmod +x ../board/raspberrypi2/ovl/usr/local/bin/*

Lançons la nouvelle compilation

[buildroot-2015.11]$ make

Nous ré-insérons la carte micro-SD dans le PC de développement.Seule la partition ROOT doit être modifiée.

[buildroot-2015.11]$ sudo rm -rf /media/cpb/ROOT/*
[buildroot-2015.11]$ sudo tar xf output/images/rootfs.tar -C /media/cpb/ROOT/
[buildroot-2015.11]$ sudo umount /media/cpb/*

Après redémarrage du Raspberry Pi 2, vérifions la connexion avec l’identité root :

Welcome on board!
R-Pi login: root
Password: (root)
#

Vérifions tout de suite si le système de fichiers est bien monté en lecture seulement.

# ls /
bin      etc      lib      linuxrc  mnt      proc     run      sys      usr
dev      home     lib32    media    opt      root     sbin     tmp      var
# echo hello > /test-file
-sh: can't create /test-file: Read-only file system

Très bien. Vérifions qu’il soit possible de passer temporairement en lecture-écriture.

# rw
-sh: rw: not found
# /usr/local/bin/rw
[  287.714995] EXT4-fs (mmcblk0p2): warning: mounting unchecked fs, running e2fsck is recommended
[  287.725877] EXT4-fs (mmcblk0p2): re-mounted. Opts: (null)
# echo hello > /test-file
# ls /
bin        home       linuxrc    opt        run        test-file  var
dev        lib        media      proc       sbin       tmp
etc        lib32      mnt        root       sys        usr
# rm /test-file
# /usr/local/bin/ro
[  302.623095] EXT4-fs (mmcblk0p2): re-mounted. Opts: (null)
# echo hello > /test-file
-sh: can't create /test-file: Read-only file system
# exit

Malgré un petit souci de PATH qui ne permet pas d’invoquer directement rw ou ro, la protection du système est donc correcte. Vérifions l’accès en tant qu’utilisateur normal.

Welcome on board!
R-Pi login: rpi
Password: (rpi)
$ pwd
/home/rpi
$ ls
$ echo hello > my-file
-sh: can't create my-file: Read-only file system
$

Ici, un petit problème se pose. La partition « système » de notre Raspberry Pi est bien protégée contre les écritures, mais nous aimerions peut-être disposer de possibilités de stockage de données utilisateur. Pour cela il va falloir envisager l’ajout d’une partition supplémentaire montée en lecture-écriture

Nouvelles améliorations

Nous allons donc ajouter une nouvelle partition, formatée en vfat, afin de contenir les données utilisateur. Comme j’en ai parlé dans cet article, le format vfat est beaucoup plus simple que les traditionnels ext4 et consorts, mais il résiste bien à des coupures d’alimentations pendant une écriture.

Il faut indiquer la présence de cette partition dans le fichier /etc/fstab. Nous allons copier le fichier original produit par Buildroot dans notre overlay et lui ajouter une dernière ligne.

[buildroot-2015.11]$ mkdir  -p  ../board/raspberrypi2/ovl/etc
[buildroot-2015.11]$ cp output/target/etc/fstab ../board/raspberrypi2/ovl/etc/
[buildroot-2015.11]$ nano ../board/raspberrypi2/ovl/etc/fstab

Le fichier est modifié ainsi (dernière ligne ajoutée)

#                 
/dev/root       /               ext2    rw,noauto       0       1
proc            /proc           proc    defaults        0       0
devpts          /dev/pts        devpts  defaults,gid=5,mode=620 0       0
tmpfs           /dev/shm        tmpfs   mode=0777       0       0
tmpfs           /tmp            tmpfs   mode=1777       0       0
tmpfs           /run            tmpfs   mode=0755,nosuid,nodev  0       0
sysfs           /sys            sysfs   defaults        0       0
/dev/mmcblk0p3  /home/rpi       vfat    defaults,uid=1000,gid=1000  0 0

Nous pouvons également ajouter dans l’overlay un fichier ../board/raspberrypi2/etc/profile.d/custom.sh ajustant la configuration du PATH et du prompt du shell.

[buildroot-2015.11]$ mkdir  -p  ../board/raspberrypi2/ovl/etc/profile.d/
[buildroot-2015.11]$ nano ../board/raspberrypi2/ovl/etc/profile.d/custom.sh

Contenu du fichier custom.sh

# Acces aux scripts personnels et code metier.
PATH=$PATH:/usr/local/bin

# Prompt indiquant nom d'hote et repertoire courant.
PS1='\h[\W]\$ '

Recompilons notre système, et réinscrivons-le sur la carte SD en ajoutant une partition vfat de 1Go, destinée à recevoir les données utilisateur (applicatives).

[buildroot-2015.11]$ cp .config ../board/raspberrypi2/buildroot-03.cfg
[buildroot-2015.11]$ make
 [...]

Lors du partitionnement, nous pouvons placer la partition 3 (celle des données utilisateur) avant la partition 2 (celle du système). Ceci permet de donner une taille fixe à la partition 3, tout en laissant la partition 2 occuper tout l’espace disque disponible.

[buildroot-2015.11]$ sudo fdisk /dev/sdc
Commande (m pour l'aide) : n
Partition type:
   p   primary (0 primary, 0 extended, 4 free)
   e   extended
Select (default p): p
Numéro de partition (1-4, 1 par défaut) : 1
Premier secteur (2048-7741439, 2048 par défaut) : (Entrée)
Dernier secteur, +secteurs ou +taille{K,M,G} (2048-7741439, 7741439 par défaut) : +128M

Commande (m pour l'aide) : t
Numéro de partition (1-4): 1
Code Hexa (taper L pour lister les codes): C

Commande (m pour l'aide) : n
Partition type:
   p   primary (1 primary, 0 extended, 3 free)
   e   extended
Select (default p): p
Numéro de partition (1-4, 2 par défaut) : 3
Premier secteur (264192-7741439, 264192 par défaut) : (Entrée)
Dernier secteur, +secteurs ou +taille{K,M,G} (264192-7741439, 7741439 par défaut) : +1G

Commande (m pour l'aide) : t
Numéro de partition (1-4): 3
Code Hexa (taper L pour lister les codes): C

Commande (m pour l'aide) : n
Partition type:
   p   primary (2 primary, 0 extended, 2 free)
   e   extended
Select (default p): p
Numéro de partition (1-4, 2 par défaut) : 2
Premier secteur (2361344-7741439, 2361344 par défaut) : (Entrée)
Dernier secteur, +secteurs ou +taille{K,M,G} (2361344-7741439, 7741439 par défaut) : (Entrée)

Commande (m pour l'aide) : a
Numéro de partition (1-4): 1

Commande (m pour l'aide) : p
Périphérique Amorçage  Début         Fin      Blocs    Id. Système
/dev/sdc1   *        2048      264191      131072    c  W95 FAT32 (LBA)
/dev/sdc2         2361344     7741439     2690048   83  Linux
/dev/sdc3          264192     2361343     1048576    c  W95 FAT32 (LBA)

Les entrées de la table de partitions ne sont pas dans l'ordre du disque
Commande (m pour l'aide) : w

Formatage de toutes les partitions :

[buildroot-2015.11]$ sudo mkfs.vfat -n BOOT /dev/sdc1
[buildroot-2015.11]$ sudo mkfs.vfat -n DATA /dev/sdc3
[buildroot-2015.11]$ sudo mkfs.ext2 -L ROOT /dev/sdc2

Après retrait et réinsertion de la carte SD :

[buildroot-2015.11]$ sudo cp output/images/bcm2709-rpi-2-b.dtb  /media/cpb/BOOT/
[buildroot-2015.11]$ sudo cp output/images/rpi-firmware/*  /media/cpb/BOOT/
[buildroot-2015.11]$ sudo ./output/host/usr/bin/mkknlimg  output/images/zImage  /media/cpb/BOOT/zImage
[buildroot-2015.11]$ sudo tar xf output/images/rootfs.tar  -C /media/cpb/ROOT/

Nous devons toujours éditer le fichier cmdline.txt de la partition BOOT pour ajouter console=ttyAMA,115200 sur la première ligne. Nous verrons ultérieurement comment intégrer cela dans la configuration du noyau. J’ajoute également au passage un petit fichier sur la partition DATA afin de vérifier que tout soit bien monté au démarrage.

[buildroot-2015.11]$ sudo nano /media/cpb/BOOT/cmdline.txt
    [...]
[buildroot-2015.11]$ echo "Hello User !" > /media/cpb/DATA/file.txt
[buildroot-2015.11]$ sudo umount /media/cpb/*

Au démarrage du Raspberry Pi 2, nous observons :

Welcome on board!
R-Pi login: rpi
Password: (rpi)
R-Pi[~]$ ls
file.txt
R-Pi[~]$ cat file.txt
Hello User !
R-Pi[~]$ echo $PATH
/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin
R-Pi[~]$ echo Modification > file.txt
R-Pi[~]$ cat file.txt
Modification
R-Pi[~]$ rm file.txt
R-Pi[~]$ ls
R-Pi[~]$ 

Nos modifications concernant le prompt du shell, le PATH et le répertoire utilisateur en lecture-écriture ont bien été prises en compte.

Conclusion

Nous disposons ainsi d’un système Linux embarqué minimal assez personnalisé. Bien sûr nous sommes très loin d’un environnement de travail complet comme on peut l’obtenir avec une distribution précompilée comme Raspbian. Mais cela nous permet justement de maîtriser parfaitement le contenu de notre système.

La configuration ainsi établie (dont on peut télécharger ici les fichiers utilisés) nous permettra, dans de prochains articles, d’ajouter des applications et services standards (SSH, HTTP, NTP, etc.), d’ajuster le contenu du noyau, d’installer le bootloader U-Boot pour programmer des scripts de démarrage (et mise à jour) robustes, d’ajouter une application personnalisée (code métier) et même des modules kernel « maison ».

15 Réponses

  1. wcdr dit :

    Un grand merci, enfin un article clair qui fonctionne.

    Je souhaiterai faire une chaine de compilation croisée pour le RPI 1, quelles sont les modifications à apporter dans la section « Toolchain – Voici la liste des modifications apportées : »

    Merci,

    Wz

    • cpb dit :

      Bonjour et merci,

      Pour la toolchain comme pour le reste du système, la seule différence entre Raspberry Pi 1 et 2 sera le make raspberrypi_defconfig au lieu de make raspberrypi2_defconfig.

      Toutefois si vous souhaitez disposer des deux toolchains sur la même machine, (afin de les utiliser successivement pour les deux types de Raspberry par exemple), je vous conseille de vous créer des répertoires distincts board/raspberrypi et board/raspberrypi2 en ajustant les chemins des paramètres Host dir puis Toolchain path et enfin dans la dernière partie Overlay directory.

  2. ibd dit :

    Excellent post. Bravo et merci.

  3. Laurent dit :

    Bonjour,

    Merci pour ce tuto très intéressant !

    J’ai relevé une coquille (en faisant un bête copié-collé)

    Pour le menu « Build options » –> « Host dir » vous le valorisez à
    ($TOPDIR)/../board/raspberrypi2/cross/

    au lieu de
    $(TOPDIR)/../board/raspberrypi2/cross
    ($ pas à la bonne place et / de trop en fin )

    Merci !

  4. Christophe dit :

    Bonjour Christophe,
    Merci beaucoup pour vos tuto toujours très instructif.

    Je suis confronté à un problème:
    si je cherche à créer une chaîne de cross compilation sans changer le Host dir

  5. Christophe dit :

    Bonjour Christophe,

    Merci encore pour vos tutos très instructifs.

    Je suis confronté à un problème lors de la création de la chaîne de cross compilation:
    si je ne change pas le Host dir tout vat bien,
    mais si je fait la modification $(TOPDIR)/../board/raspberrypi2/cross
    j’obtiens l’erreur suivante:
    xargs: /home/radio/br-tree/buildroot-2015.11/../board/raspberrypi2/cross/usr/bin/arm-buildroot-linux-gnueabihf-strip: Aucun fichier ou dossier de ce type
    make[1]: *** [target-finalize] Erreur 127

    il semblerais que la variable $(TOPDIR) soit mal interprété, j’ai essayé de mettre un chemin complet même résultat, je ne vois pas ou se situe l’erreur.

    Le newbie que je suis est peut-être destiné à rester newbie?

    Cordialement.

    • Christophe dit :

      Re bonjour,

      Pour faire suite à mon post précédent, j’ai compris mon erreur elle est instructive.
      Au premier test de compilation j’ai fait une erreur dans l’écriture du paramètre Host dir à la suite de quoi
      Buildroot créé une chaîne de compilation mais pas au bon endroit et supprime des fichiers qui sont utiles
      par la suite.
      Pour contourner ce problème j’ai fait un effacement du répertoire buildroot et je recrée tout , ça fonctionne.

      le newbie est en progression!

      Cordialement

  6. Julien ROBIN dit :

    Bonjour

    Merci encore pour ces mines d’or d’informations,

    Me voilà entrain d’utiliser la même version de buildroot pour peu à peu m’attaquer, pour changer… à un Orange Pi 2 ! Il parait que c’est un challenge, mais je suis du genre à ne pas me dégonfler trop vite 🙂

    J’en reviens pour le moment aux bases : les datasheets des composants qui l’équipent, le site officiel ARM, big endian ou little endian, type de FPU utilisée…
    http://infocenter.arm.com/help/index.jsp

    Bref je commence à regarder tout ça, si j’arrive à quelque chose d’intéressant je vous tiens au jus !

  7. Mathieu dit :

    Bonjour et merci pour cet article très instructif.
    Une question me vient à l’esprit : quelle est la taille occupée par le système sur la carte sd ?

    • cpb dit :

      En regardant le répertoire output/images d’un Buildroot configuré globalement comme celui de l’article je vois :

      [images]$ ls -l
      total 53404
      -rw-r--r-- 1 cpb cpb    10180 janv.  8 01:39 bcm2709-rpi-2-b.dtb
      -rw-r--r-- 1 cpb cpb 46274560 janv.  8 01:49 rootfs.tar
      drwxr-xr-x 2 cpb cpb     4096 janv.  7 23:29 rpi-firmware
      -rw-r--r-- 1 cpb cpb   303560 janv.  8 01:22 u-boot.bin
      -rwxr-xr-x 1 cpb cpb  4040120 janv.  7 23:48 zImage
      [images]$ ls -l rpi-firmware/
      total 2684
      -rw-r--r-- 1 cpb cpb   17900 janv.  7 23:29 bootcode.bin
      -rw-r--r-- 1 cpb cpb      29 janv.  7 23:29 cmdline.txt
      -rw-r--r-- 1 cpb cpb     682 janv.  7 23:29 config.txt
      -rw-r--r-- 1 cpb cpb    6331 janv.  7 23:29 fixup.dat
      -rw-r--r-- 1 cpb cpb 2709752 janv.  7 23:29 start.elf
      [images]$ 

      Donc environ 7Mo sur la partition BOOT et 47Mo sur la partition ROOT. C’est un système plutôt léger !

  8. Richard Starzak dit :

    Bonjour,

    Merci pour ce tuto très intéressant.

    Mais, j’ai un problème.

    J’arrive à générer l’image, le boot (sur la RASPBERRY) démarre puis cale … : je ne vois vraiement pas que faire ?

    Voici la dernière ligne de la séquence de boot (après bien d’autres lignes) :

    —[ end Kernel panic – not syncing : VFS : Unable to mount root fs on unknown-block (0,0)

    Que puis-je faire ?

    Merci pour tout aide,

    Richard

  9. Claude dit :

    Bonjour,

    Encore merci pour la qualité de votre production. C’est rare.

    Dans le cadre du développement d’un GPS centimétrique (DGPS), j’ai pour projet d’installer l’application RTKLIB 2.4.2 (C++) sur RASPBERRY 3 tournant sous DEBIAN.

    En conséquence, je souhaiterai faire une chaine de compilation croisée pour le RPI 3, quelles sont les modifications à apporter?

    Merci pour votre aide.

    Claude

    • cpb dit :

      Bonjour Claude,

      Pour faire le même travail sur un Raspberry Pi 3, il suffit de prendre une version récente de Buildroot, par exemple la version 2016.05 ou 2016.08 qui est en finalisation, et de commencer par un make rasberrypi3_defconfig au lieu de make raspberrypi2_defconfig.

URL de trackback pour cette page