Compilation du kernel Linux
La première étape consiste à compiler un kernel Linux mainline destiné à s'exécuter sur une Raspberry Pi 3B d'architecture ARM 32 bits. Il est donc nécessaire de mettre en place un compilateur croisé pour compiler notre kernel depuis une machine hôte x86_64.
Compilation croisée avec Linaro
Nous utiliserons le compilateur croisé Linaro. Vous pouvez télécharger ici le compilateur croisé x86_64 -> ARM gnueabihf basé sur GCC. Ou installer son paquet Debian via APT :
Les termes gnueabi ou gnueabihf sont importants, le mot se décompose en :
- gnu, signifie que la toolchain est sous licence GNU (GPL). Le kernel Linux utilisant la synthaxe assembleur de GNU (GAS), il est nécessaire de compiler le kernel avec une toolchain sous licence GPL.
- eabi, signifie que la toolchain utilise l'Embedded ABI de ARM.
- hf, signifie que les virgules flottantes sont gérées de façon hardware par le compilateur.
La Raspberry Pi 3B étant en armhf, il est nécessaire de prendre le compilateur gnueabihf.
Variables d'environnement
Pour utiliser votre compilateur croisé pour une compilation vous devez exporter
les variables CROSS_COMPILE
et ARCH
dans votre terminal.
Via APT, le compilateur a été installé dans /usr/bin
:
/usr/bin/arm-linux-gnueabihf-gcc
/usr/bin/arm-linux-gnueabihf-gcc-ar
/usr/bin/arm-linux-gnueabihf-gcc-nm
/usr/bin/arm-linux-gnueabihf-gcc-ranlib
Il faut donc exporter les valeurs suivantes :
La variable CROSS_COMPILE
va permettre de préfixer les appels aux binaire GCC
(gcc, gcc-ar, gcc-nm et gcc-ranlib) ainsi, il faut exporter le binaire de la toolchain
sans le suffixe gcc
.
Configuration du kernel
Créeons un dossier de travail et téléchargeons les sources :
Nous allons nous brancher sur la dernière version stable du kernel, soit la 5.17 au moment de la rédaction :
La raspberry Pi 3B utilise la Broadcom BCM2835.
Cela tombe bien, la configuration arch/arm/configs/bcm2835_defconfig
existe
dans les sources du kernel. Il suffit de la charger dans le .config avec :
#
# configuration written to .config
#
Compilation de l'image
La raspberry Pi 3B fonctionne avec des zImage, et non le format bzImage. Lançons la compilation de notre image kernel (et ses modules) :
L'image arch/arm/boot/zImage
produite est bien au format ARM 32 bits :
arch/arm/boot/zImage: ARM OpenFirmware FORTH Dictionary, Text length: -509607936 bytes, Data length: -509607936 bytes, Text Relocation Table length: -369098747 bytes, Data Relocation Table length: 24061976 bytes, Entry Point: 0x00000000, BSS length: 6021760 bytes
Compilation des devicetree
Il est nécessaire que le kernel puisse connaître le matériel physique sur lequel il s'exécute, afin de charger les bons drivers et d'utiliser toutes les ressources. Cette "découverte" du matériel peut se faire de plusieurs manière : le protocol ACPI est généralement utilisé en x86, et la structure devicetree (fichier .dts), est plutôt utilisé en ARM (32 et 64 bits).
L'ensemble des devicetree ont été compilé en .dtb dans arch/arm/boot/dts/
:
arch/arm/boot/dts/bcm2711-rpi-400.dtb
arch/arm/boot/dts/bcm2835-rpi-a-plus.dtb
...
Image finale
Nous allons nous baser sur une image Raspberry Pi OS officielle et la modifier avec notre propre image kernel. Cette image contient déjà une image kernel Linux et le système de fichiers pour la Raspberry Pi. Créez un dossier et téléchargez l'image :
Branchez la carte SD que vous voulez utiliser pour flasher l'image et trouvez le device
associé avec la commande lsblk
:
...
mmcblk0 8:32 1 14,5G 0 disk
├─mmcblk0p1 8:33 1 256M 0 part
└─mmcblk0p2 8:34 1 14,2G 0 part
...
Dans ma situation, le device associé à ma carte SD est /dev/mmcblk0
. Le device
fait 14,5G et on remarque qu'il y a déjà deux partitions présentes : mmcblk0p1
et mmcblk0p2
. Il s'agit du contenu actuel de la carte.
Si vous avez une carte vierge, ou partitionnée différement, lsblk
affichera autre chose.
Nous allons directement extraire l'image .xz sur le device mmcblk0
.
Remplacez la destination d'écriture of=/dev/{votre_device}
avec le device de votre
carte SD et exécutez la commande :
Les anciennes données et partitions, si présentes, ont été écrasées. Affichez les partitions de l'image Raspbian flashée sur votre device avec l'outil fdisk :
Disque /dev/mmcblk0: 14,5 GiB, 15552479232 octets, 30375936 secteurs
Disk model: MassStorageClass
Unités : secteur de 1 × 512 = 512 octets
Taille de secteur (logique / physique) : 512 octets / 512 octets
taille d'E/S (minimale / optimale) : 512 octets / 512 octets
Type d'étiquette de disque : dos
Identifiant de disque : 0x18bb6cde
Périphérique Amorçage Début Fin Secteurs Taille Id Type
/dev/mmcblk0p1 8192 532479 524288 256M c W95 FAT32 (LBA)
/dev/mmcblk0p2 532480 30375935 29843456 14,2G 83 Linux
Vous pouvez observer que le device de votre carte SD est divisé en
2 partitions : mmcblk0p1
et mmcblk0p2
.
Bien que /dev/mmcblk0
est le device de notre carte SD, les deux partitions
se trouvent dans /dev
et non dans /dev/mmcblk0
.
En effet, cela reste 3 devices différents :
- /dev/mmcblk0 : toute l'image. Un
dd
nous écrase tout le contenu. - /dev/mmcblk0p1 : la première partition de l'image, elle sera la partition de boot et contiendra l'image kernel, les devices tree et des fichiers de configuration.
- /dev/mmcblk0p2 : la deuxième partition de l'image, elle sera la partition du système de fichier de notre Raspberry.
Nous allons donc monter nos deux partitions boot
(/dev/mmcblk0p1
)
et rootfs
(/dev/mmcblk0p2
) de notre device /dev/mmcblk0
:
Vous pouvez observez avec lsblk
le point de montage de vos partitions :
...
mmcblk0 8:32 1 14,5G 0 disk
├─mmcblk0p1 8:33 1 256M 0 part howto/kernel/rpi/boot
└─mmcblk0p2 8:34 1 14,2G 0 part howto/kernel/rpi/rootfs
...
Copiez dès à present l'image kernel zImage produite et les devicetree compilés dans
la partition boot
:
Sans modification de la configuration de la raspberry, le kernel d'origine sera
executé. Ajoutez les lignes suivantes dans le fichier de configuration config.txt
pour surcharger le kernel et le devicetree avec ceux produit :
Vous pouvez entreprendre des modifications dans le rootfs en modifiant le dossier
rootfs
.
Démontez les partitions :
sync
demande au kernel de vider ses buffers et d'écrire toutes les données
qui étaient en attente. La commande est bloquante et se libère une fois les
écritures faites, assurrant ainsi aucune perte de donnée lors du démontage des
partitions.
Vous pouvez débrancher la carte SD.
Démarrage sur la Raspberry Pi
Branchez la carte SD et démarrez votre Raspberry Pi pour tester votre kernel.
Pour avoir accès à la console vous devez brancher un lien série UART entre
la Raspberry Pi 3B et l'ordinateur. Des modifications devrons être nécessaire dans le fichier
de configuration config.txt
.
Voici un article
sur la marche à suivre.