M2 SETI B4 / MS SE SE758


TP 1

Introduction

Objectifs

L’objectif de ce premier TP est de prendre en main les éléments de base pour démarrer un système Linux minimaliste :

Pré-requis

Convention : Dans la suite du texte, lorsque vous avez des commandes à taper dans un terminal, elles sont indiquées avec un caractère $ en début de ligne. Ce caractère $ au début des lignes de commande représente l’invite de commande, c’est-à-dire les caractères affichés par votre interpréteur de commande pour vous inviter à taper une commande (ils varient d’un interpréteur de commande à un autre et en fonction de votre configuration). Ce caractère $ (uniquement au début de la ligne) n’est donc pas à taper.

Préparation de l’environnement de TP

Nous vous recommandons, pour la suite du TP, de travailler dans un nouveau répertoire. Dans la suite du texte (et dans les TP ultérieurs), nous nous y référerons grâce à la variable d’environnement TPROOT.

Si vous êtes sur votre machine personnelle, vous pouvez créer le répertoire où vous le souhaitez et lui donnez le nom que vous voulez. Par exemple, pour créer un répertoire seti-b4-tp dans votre répertoire personnel, vous pouvez taper :

$ export TPROOT=~/seti-b4-tp
$ mkdir $TPROOT
$ cd $TPROOT

Attention, si vous ouvrez un autre terminal, vous aurez besoin de redéfinir la variable TPROOT (à l’aide de la première ligne).

Si vous êtes sur une machine de TP de l’école, attention, la taille de votre répertoire personnel est très limitée (quelques gigaoctets). Or nous aurons besoin de plus de place. Heureusement, les machines disposent d’un répertoire local que vous pouvez utiliser pour stocker des fichiers volumineux. Néanmoins, attention, les fichiers dans ce répertoire ne sont pas sauvegardés et ne sont accessibles que depuis la machine que vous utilisez (contrairement à votre répertoire personnel qu iest accessible depuis n’importe quelle machine de TP). Utilisez les commandes suivantes pour créer un répertoire de travail en local (remplacez xxx par votre nom d’utilisateur) :

$ export TPROOT=/home/users/xxx/seti-b4-tp
$ mkdir $TPROOT
$ cd $TPROOT

Si la commande mkdir échoue, n’allez pas plus loin.

Attention, si vous ouvrez un autre terminal, vous aurez besoin de redéfinir la variable TPROOT (à l’aide de la première ligne).

QEMU

Pour simuler un système embarqué complet à base de processeur ARM, nous allons utiliser QEMU. En plus de ne pas avoir besoin de matériel physique pour expérimenter, Qemu permet également de facilement tester, mais aussi débugger votre système embarqué.

Plus précisément, nous allons utiliser qemu-system-arm qui est un émulateur de machine complète, en l’occurrence, une carte de développement Arm Versatile Express munie d’une carte d’extension CoreTile Express A9x4 à base de Cortex-A9.

Les détails de ce que QEMU simule concernant cette carte sont disponibles dans la documentation : https://www.qemu.org/docs/master/system/arm/vexpress.html.

Nous utiliserons une version particulière de qemu-system-arm (elle ajoute à QEMU un périphérique émulé pour lequel vous allez écrire un pilote de périphérique dans la suite du cours).

Téléchargez :

Placez l’exécutable téléchargé dans votre répertoire $TPROOT, puis vérifiez que les droits sont corrects pour l’exécution :

$ chmod u+x qemu-system-arm

Normalement, cet exécutable utilise des bibliothèques partagées qui devraient être disponibles sur votre machine. Néanmoins, vérifiez que toutes les bibliothèques sont présentes en tapant :

$ ldd qemu-system-arm

Si vous désirez, le code source de QEMU ainsi que les modifications apportées sont disponibles dans la branche adxl345 du dépôt https://gitlab.telecom-paris.fr/guillaume.duc/qemu.

Cross-compilateur

Toutes les couches logicielles que nous allons compiler (noyau, outils, etc.) sont destinées à être exécutées sur une machine à base de processeur ARM Cortex-A. Or, il est très probable que vous réalisiez le TP sur une machine à base de processeur x86 ou x86_64.

Donc si vous compilez en utilisant le compilateur classique de votre machine, vous obtiendrez du code machine pour processeur x86 ou x86_64 qui ne pourra donc pas s’exécuter sur un processeur ARM.

Vous devrez donc utiliser un cross-compilateur, c’est-à-dire un compilateur qui s’exécute sur une architecture A (ici x86_64) mais qui produit du code pour une architecture B (ici arm).

Nous verrons comment construire un cross-compilateur dans un cours ultérieur, pour le moment, nous utiliserons la chaîne arm-linux-gnueabihf fournie par Linaro.

Si vous êtes sur votre machine personnelle :

Téléchargez-la ici : https://releases.linaro.org/components/toolchain/binaries/7.4-2019.02/arm-linux-gnueabihf/gcc-linaro-7.4.1-2019.02-x86_64_arm-linux-gnueabihf.tar.xz

Puis décompressez-la quelque part (par exemple dans votre répertoire de TP) et ajoutez le chemin /.../gcc-linaro-7.4.1-2019.02-x86_64_arm-linux-gnueabihf/bin (en remplaçant /.../ par le chemin correct) dans votre variable d’environnement PATH.

Si vous êtes sur une machine des salles de TP :

La chaîne étant déjà installée, ajoutez simplement le répertoire /comelec/softs/opt/gnu_tools_for_arm/gcc-linaro-7.4.1-2019.02-x86_64_arm-linux-gnueabihf/bin/ dans votre variable d’environnement PATH :

$ export PATH=$PATH:/comelec/softs/opt/gnu_tools_for_arm/gcc-linaro-7.4.1-2019.02-x86_64_arm-linux-gnueabihf/bin/

Outils classiques

Si vous êtes sur votre machine personnelle, pour réaliser ce TP, et les suivants, vous aurez besoin d’un certain nombre d’outils classiques de développement, certains étant probablement déjà installés sur votre distribution.

Pour Debian/Ubuntu, installez les paquets suivants :

Le noyau Linux

Le composant le plus important d’un système à base de Linux est… le noyau Linux lui-même.

Sources officielles

Les versions officielles du noyau Linux sont téléchargeables depuis https://www.kernel.org. La page d’accueil permet un accès rapide à :

Les sources peuvent être récupérées sous forme d’une archive contenant une version donnée (format .tar.xz). Une fois décompressées, les sources d’une version prennent un peu plus d’1 Gio.

Il est également possible (et même conseillé si on veut développer), de récupérer directement le dépôt git officiel incluant tout l’historique (depuis que les développeurs du noyau utilisent git !) :

Note : ne pas taper les commandes ci-dessous, elles ne sont données qu’à titre indicatif pour le moment.

$ git clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git

ou bien (par exemple si un pare-feu paranoïaque bloque l’accès au protocole git (port TCP 9418)) :

$ git clone https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git

En décembre 2021, une copie du dépôt git officiel prend environ 3,8 Gio.

Sources alternatives

De nombreux fabricants maintiennent leurs propres versions des sources du noyau incluant le support pour leurs produits quand il n’est pas encore intégré aux versions officielles.

Par exemple, les sources du noyau Linux pour les FPGA SoC d’Altera sont disponibles ici : https://github.com/altera-opensource/linux-socfpga.

De même, certaines distributions maintiennent des versions divergentes du noyau pour diverses raisons.

Configuration du noyau

Note préliminaire : les commandes contenues dans cette section sont données à titre d’exemple et ne sont pas à exécuter.

Le noyau Linux est extrêmement versatile (il est conçu pour fonctionner sur de nombreuses architectures, depuis un petit système embarqués jusqu’à de gros supercalculateurs, il gère de très nombreux périphériques différents, de nombreux protocoles réseaux, etc.). Il dispose donc d’un système de configuration permettant d’adapter le noyau aux besoins de l’utilisateur en ne sélectionnant que ce qui est nécessaire.

Outils de gestion de la configuration

Plusieurs cibles du Makefile principal du noyau permettent de créer et de modifier cette configuration :

Si aucun fichier de configuration n’existe (ce qui est le cas lorsque l’on récupère les sources officielles), ces outils vont chercher s’il existe un fichier dont le nom est de la forme /boot/config-* et le prendre comme base. Sinon, les valeurs par défaut des paramètres sont choisies.

Si vous disposez déjà d’un fichier de configuration, issu par exemple d’une version précédente du noyau, la commande make oldconfig peut se révéler très utile. Elle supprime les options qui n’existent plus et demande l’avis de l’utilisateur uniquement pour les nouvelles options.

Enfin, un certain nombre de fichiers de configuration par défaut pour de nombreuses cartes embarquées sont disponibles dans le répertoire arch/xxx/configs (où xxx représente une architecture, comme arm). Pour les utiliser, il suffira de taper make yyy_defconfig.

Syntaxe et signification de la configuration

La configuration est stockée, sous un format textuel simple (cle=valeur), dans le fichier .config.

Plusieurs types sont possibles pour une valeur :

Des options peuvent dépendre d’autres options (exemple : le support des périphériques de stockage USB (mass storage device) dépend du support de l’USB).

Pour les types bool ou tristate, la valeur a la signification suivante :

Voici un extrait d’un fichier de configuration du noyau :

#
# USB Host Controller Drivers
#
# CONFIG_USB_C67X00_HCD is not set
CONFIG_USB_XHCI_HCD=m
# CONFIG_USB_XHCI_PLATFORM is not set
CONFIG_USB_EHCI_HCD=m
CONFIG_USB_EHCI_ROOT_HUB_TT=y
CONFIG_USB_EHCI_TT_NEWSCHED=y
CONFIG_USB_EHCI_PCI=m

Compilation du noyau

Note préliminaire : les commandes contenues dans cette section sont données à titre d’exemple et ne sont pas à exécuter.

Compilation native

Pour compiler le noyau pour une architecture identique à celle sur laquelle est lancée le compilateur, il suffit de lancer la commande make à la racine du noyau.

Il est possible de faire en sorte que tous les fichiers produits lors de la compilation soient stockés dans un autre répertoire (par exemple si les sources sont en lecture seule pour l’utilisateur ou si on ne veut pas les polluer) :

$ make O=/home/toto/build menuconfig
$ make O=/home/toto/build

Plusieurs fichiers sont produits par la compilation dont notamment :

Installation du noyau et des modules

L’installation du noyau se fait à l’aide de la cible install du Makefile :

# make install

ou, si vous avez compilé le noyau en utilisant un répertoire à part :

# make O=/home/toto/build install

Cette commande effectue les opérations suivantes :

L’accès en écriture au répertoire /boot n’étant normalement pas possible pour un utilisateur normal, la commande make a besoin des privilèges administrateurs pour pouvoir réaliser l’installation.

L’installation des modules se fait à l’aide de la cible modules_install du Makefile :

# make modules_install

Elle installe les modules (fichiers *.ko ainsi que les informations de dépendance entre modules, de table des symboles et d’alias) dans /lib/modules/<version>.

Compilation croisée (Cross-compilation)

Il est parfois nécessaire de compiler le noyau pour une architecture différente de celle sur laquelle s’effectue la compilation. On parle alors de cross-compilation ou compilation croisée.

Deux variables sont utilisées par le Makefile pour permettre la compilation croisée :

Ces deux variables doivent être passées à chaque invocation d’une cible du Makefile, soit en les spécifiant sur la ligne de commande, soit en les exportant en tant que variables d’environnement.

$ make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- menuconfig
$ make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf-

ou bien :

$ export ARCH=arm
$ export CROSS_COMPILE=arm-linux-gnueabihf-
$ make menuconfig
$ make

Nettoyage des sources

Trois cibles du Makefile sont disponibles pour permettre le nettoyage des sources :

Travail à faire

  1. Récupérez la dernière version stable du noyau (5.15.6 lors de l’écriture de ce texte).
$ cd $TPROOT
$ wget https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.15.6.tar.xz
  1. Décompressez là dans votre répertoire de TP :
$ tar xJf linux-5.15.6.tar.xz
$ cd linux-5.15.6
  1. Définissez les variables d’environnement pour la cross-compilation du noyau :
$ export ARCH=arm
$ export CROSS_COMPILE=arm-linux-gnueabihf-
  1. Lancez la configuration à partir du fichier de configuration par défaut pour la carte Versatile Express (nous utiliserons un répertoire à part build pour la compilation) :
$ make O=build vexpress_defconfig
$ make O=build menuconfig
  1. Parcourez rapidement la configuration. Nous aurons besoin dans la suite d’une option qui n’est pas activée dans la configuration par défaut : Support for uevent helper (dans Device Drivers -> Generic Driver Options).

  2. Compilez le noyau :

$ make O=build

Deux fichiers importants sont produits par la compilation :

  1. Lancez QEMU :
$ cd $TPROOT
$ ./qemu-system-arm -machine vexpress-a9 -nographic -kernel \
linux-5.15.6/build/arch/arm/boot/zImage -dtb \
linux-5.15.6/build/arch/arm/boot/dts/vexpress-v2p-ca9.dtb

Cette commande lance QEMU en lui indiquant le type de machine à émuler (vexpress-a9), l’image du noyau à utiliser (linux-5.15.6/build/arch/arm/boot/zImage) et l’arbre des périphériques à utiliser (linux-5.15.6/build/arch/arm/boot/dts/vexpress-v2p-ca9.dtb). Dans ce mode, QEMU va placer en mémoire RAM l’image du noyau et le DTB, et lancer l’exécution du noyau, comme le ferait un bootloader (voir le cours sur le démarrage d’un système Linux).

Vous devriez voir les messages de démarrage du noyau s’afficher (ils s’affichent car QEMU redirige vers le terminal la première liaison série de la carte émulée, qui se trouve être celle utilisée par le noyau pour envoyer ses messages). Le noyau va paniquer et s’arrêter. Pourquoi ?

Quand QEMU fonctionne, tout ce que vous tapez dans votre terminal est envoyé à votre machine virtuelle par l’intermédiaire de la liaison série émulée. Vous pouvez accéder à la console de QEMU en tapant ctrl-a c. Puis dans cette console, tapez quit (ou q) pour arrêter QEMU.

Un premier système de fichiers et un premier processus init

Le noyau ne trouve pas de système de fichiers. Nous allons donc, dans un premier temps, lui fournir une image mémoire initramfs et un premier petit processus init.

$ cd $TPROOT
$ mkdir initramfs_simple
$ cd initramfs_simple
  1. Créez le fichier init.c avec le contenu suivant (vous êtes libres d’adapter si vous voulez) :
#include <stdio.h>
#include <unistd.h>

int main(int argc, char *argv[])
{
  printf("Hello world!\n");
  sleep(10);
}
  1. Compilez-le :
$ arm-linux-gnueabihf-gcc -static init.c -o init

Note : nous utilisons ici -static pour lier la bibliothèque C avec l’exécutable afin que ce dernier contiennent tout ce dont il a besoin pour s’exécuter (dans le cas contraire, il aurait fallu copier dans l’archive la bibliothèque standard, l’éditeur de liens dynamique et le chargeur dynamique).

  1. Créez ensuite une image initramfs à l’aide de cpio (profitez-en pour regarder la page de manuel de cpio pour comprendre le fonctionnement de la ligne de commande suivante) :
$ echo init | cpio -o -H newc | gzip > test.cpio.gz
  1. Puis lancez la simulation :
$ cd ..
$ ./qemu-system-arm -machine vexpress-a9 -nographic -kernel \
linux-5.15.6/build/arch/arm/boot/zImage \
-dtb linux-5.15.6/build/arch/arm/boot/dts/vexpress-v2p-ca9.dtb \
-initrd initramfs_simple/test.cpio.gz

Vous devriez voir que votre programme est exécuté puis, quand il se termine (au bout de quelques secondes), le noyau panique (init n’est pas censé se terminer).

Une image mémoire un peu plus ambitieuse avec BusyBox

BusyBox

BusyBox se décrit lui-même comme le couteau suisse pour les systèmes Linux embarqués. Il combine des versions simplifiées de nombreux utilitaires Unix courants (init, mount, cp, ls, ifconfig…) dans un seul petit exécutable. Il fournit donc à lui seul, un environnement quasiment complet pour de petits systèmes embarqués.

Nous allons donc utiliser BusyBox pour faire une image mémoire initiale un peu plus fonctionnelle que la précédente.

  1. Commencez par récupérer la dernière version de BusyBox (1.34.1 lors de l’écriture de ce TP) :
$ cd $TPROOT
$ wget https://busybox.net/downloads/busybox-1.34.1.tar.bz2
  1. Décompressez-la :

$ tar xjf busybox-1.34.1.tar.bz2
  1. Nous allons ensuite configurer BusyBox :
$ cd busybox-1.34.1
$ export ARCH=arm
$ export CROSS_COMPILE=arm-linux-gnueabihf-
$ make defconfig
$ make menuconfig

Dans la configuration, pensez à activer l’option Build Static Binary dans le menu Settings (comme précédemment, on veut éviter d’avoir à gérer les bibliothèques dynamiques pour le moment).

  1. Puis lancez la compilation :
$ make
$ make install

Création de l’image complète

Nous allons maintenant préparer une image initramfs un peu plus complète intégrant BusyBox.

  1. Créez un répertoire de travail
$ cd $TPROOT
$ mkdir initramfs_busybox
$ cd initramfs_busybox
  1. Uniquement si vous êtes sur les machines des salles de TP : nous allons devoir créer des fichiers spéciaux (avec mknod), ce qui est normalement interdit à un utilisateur normal. Nous allons donc faire ces opérations dans un environnement virtuel nous permettant de le faire uniquement dans le but de créer une archive correcte :
$ fakeroot /bin/bash
  1. Copiez l’installation de BusyBox
$ cp -r ../busybox-1.34.1/_install/* .

Vous vous retrouvez avec des répertoires bin, sbin, usr/bin et usr/sbin qui contiennent des liens symboliques portant le nom des commandes classiques Linux (cp, insmod, mount…) vers le seul réel exécutable : bin/busybox. Busybox se sert du nom utilisé pour lancer la commande (qui, pour rappel, est le premier argument récupéré depuis la ligne de commande) pour identifier ce qu’il doit faire. Par exemple, s’il est appelé via bin/cp, il se comportera comme la commande cp.

  1. Il y a un lien symbolique linuxrc à la racine de votre image. Pour rappel, c’est cet exécutable que le noyau va lancer depuis une image initrd. Or nous sommes en train de construire une image initramfs, donc renommons ce lien symbolique :
$ rm linuxrc
$ ln -s bin/sh init
  1. Créez ensuite le reste de l’arborescence classique
$ mkdir proc sys tmp root var mnt dev etc
  1. Vous devez également créer dans dev quelques fichiers spéciaux pour les terminaux (si vous êtes sur votre machine personnelle, exécutez ces commandes en tant que root avec su ou sudo)
$ mknod dev/console c 5 1
$ mknod dev/tty1 c 4 1
$ mknod dev/tty2 c 4 2
$ mknod dev/tty3 c 4 3
$ mknod dev/tty4 c 4 4
  1. Il reste à mettre quelques fichiers de configuration dans etc :
$ cd etc
$ cp ../../busybox-1.34.1/examples/inittab .
$ mkdir init.d
$ cd init.d
$ cat <<EOF > rcS
#!/bin/sh
mount -a
mkdir -p /dev/pts
mount -t devpts devpts /dev/pts
echo /sbin/mdev > /proc/sys/kernel/hotplug
mdev -s
mkdir -p /var/lock
ifconfig lo 127.0.0.1
EOF
$ chmod 755 rcS
$ cd ..
$ cat <<EOF > fstab
proc             /proc           proc    defaults                0       0
tmpfs            /tmp            tmpfs   defaults                0       0
sysfs            /sys            sysfs   defaults                0       0
tmpfs            /dev            tmpfs   defaults                0       0
EOF

Le fichier etc/inittab est tiré directement de l’exemple fourni par BusyBox. Il lui indique ce qu’il doit exécuter au démarrage et à l’arrêt du système et les terminaux à ouvrir.

Le fichier etc/init.d/rcS est un script exécuté par BusyBox au démarrage. Tel que rempli ci-dessus, il monte les systèmes de fichiers décrits dans /etc/fstab, active mdev qui va peupler statiquement et dynamiquement /dev et configure l’interface réseau loopback.

Enfin, le fichier etc/fstab liste les systèmes de fichiers à monter au démarrage.

  1. Il ne reste plus qu’à créer l’image avec cpio
$ cd ..
$ find . | cpio -o -H newc -R +0:+0 | gzip > initramfs.gz

Puis, si vous êtes en salle de TP, quittez l’environnement fakeroot :

$ exit
  1. Vous pouvez ensuite la lancer avec QEMU :
$ cd ..
$ ./qemu-system-arm -machine vexpress-a9 -nographic -kernel \
linux-5.15.6/build/arch/arm/boot/zImage \
-dtb linux-5.15.6/build/arch/arm/boot/dts/vexpress-v2p-ca9.dtb \
-initrd initramfs_busybox/initramfs.gz

Une fois Linux démarré, il suffit d’appuyer sur une touche pour accéder à un interpréteur de commande.

Bootloader : Das U-Boot

Le dernier élément dont nous aurions besoin sur un système réel est un bootloader (comme nous l’avons vu, QEMU sait faire démarrer le noyau Linux correctement et a donc fait office jusqu’ici de bootloader).

Nous allons utiliser Das U-Boot qui est l’un des bootloaders les plus utilisés dans le monde de l’embarqué avec Linux.

  1. Téléchargez U-Boot :
$ cd $TPROOT
$ wget https://ftp.denx.de/pub/u-boot/u-boot-2020.10.tar.bz2
  1. Décompressez l’archive
$ tar xjf u-boot-2020.10.tar.bz2
  1. Configurez et compilez U-Boot (en utilisant la configuration par défaut fournie pour la carte Versatile Express)
$ cd u-boot-2020.10
$ make distclean
$ export ARCH=arm
$ export CROSS_COMPILE=arm-linux-gnueabihf-
$ make vexpress_ca9x4_defconfig
$ make
  1. Vous pouvez ensuite démarrer U-Boot avec QEMU pour tester
$ cd ..
$ ./qemu-system-arm -machine vexpress-a9 -nographic -kernel u-boot-2020.10/u-boot

Pensez à appuyer sur une touche pendant le compte-à-rebours d’U-Boot. À défaut, il va essayer de trouver une image de Linux à charger depuis les périphériques qu’il supporte (carte SD, mémoire flash, réseau). Comme aucun de ces périphériques émulés ne contient le noyau, le processus de démarrage va échouer.

Tout ensemble

Cette section n’est pas réalisable sur les machines des salles de TP, vous pouvez vous contentez de la lire.

Dans un système réel, le bootloader (U-Boot) serait stocké très probablement sur une carte SD ou dans une mémoire flash du système et serait mis en mémoire et lancé par un preloader (cette partie est très dépendante d’un système à un autre). Dans le cadre de ce TP, ce preloader est simulé par QEMU qui place l’image d’U-Boot en mémoire et lance son exécution.

Ensuite, dans un système réel, U-Boot irait chercher l’image du noyau Linux, le système de fichiers mémoire initial (initramfs ou initrd) et l’arbre des périphériques depuis un périphérique (le plus souvent carte SD ou mémoire flash interne, mais cela peut également être le réseau via TFTP par exemple) et les placerait en mémoire.

Nous allons simuler cette situation en générant une image de carte SD contenant ces éléments et en demandant à QEMU de l’utiliser pour que U-Boot puisse charger les éléments qu’elle contient.

ATTENTION : Faites très attention en utilisant les commandes suivantes (parted, mkfs, etc., surtout lorsqu’elles sont précédées de sudo). Vous pourriez vous retrouver à écraser vos données si vous ne faites pas attention aux arguments que vous passez à ces commandes.

  1. Créez un fichier sdcard qui contiendra l’image de cette carte SD
$ cd $TPROOT
$ mkdir sdcard
$ cd sdcard
$ dd if=/dev/zero of=sd bs=1M count=64
  1. Partitionnez cette carte SD (pour le moment une seule partition FAT couvrant toute la carte)
$ parted sd
(parted) mklabel msdos
(parted) mkpart primary fat32 1MiB 100%
(parted) print
Modèle :  (file)
Disque : 67,1MB
Taille des secteurs (logiques/physiques) : 512B/512B
Table de partitions : msdos
Drapeaux de disque :

Numéro  Début   Fin     Taille  Type     Système de fichiers  Drapeaux
 1      1049kB  67,1MB  66,1MB  primary  fat32                lba

(parted) quit
  1. Grâce à losetup faites apparaître cette partition comme un périphérique dans /dev
$ sudo losetup -f --show -P sd
/dev/loop0

(si la commande renvoie un autre numéro que loop0, modifiez les lignes suivantes)

  1. Créez le système de fichier FAT sur la partition
$ sudo mkfs.fat -F 32 /dev/loop0p1
  1. Montez cette partition
$ mkdir mnt
$ sudo mount /dev/loop0p1 mnt
  1. Copiez-y les fichiers contenant le noyau, le DTB et l’image initramfs
$ sudo cp ../linux-5.15.6/build/arch/arm/boot/zImage mnt
$ sudo cp ../linux-5.15.6/build/arch/arm/boot/dts/vexpress-v2p-ca9.dtb mnt
$ sudo cp ../initramfs_busybox/initramfs.gz mnt
  1. L’image mémoire initiale doit être encapsulée avec un entête spécial pour U-Boot (on pourrait faire de même avec l’image noyau et le DTB mais ce n’est pas indispensable)
$ cd mnt
$ sudo ../../u-boot-2020.10/tools/mkimage -A arm -O linux -T ramdisk -d initramfs.gz uinitramfs
  1. Démontez l’image de la carte SD
$ cd ..
$ sudo umount mnt
$ sudo losetup -d /dev/loop0
  1. Lancez QEMU en utilisant la carte SD et arrêtez le compte-à-rebours
$ cd $TPROOT
$ qemu-system-arm -machine vexpress-a9 -nographic -kernel \
u-boot-2020.10/u-boot -sd sdcard/sd
  1. Avec U-Boot, chargez les fichiers en mémoire
=> fatload mmc 0:1 0x62000000 zImage
=> fatload mmc 0:1 0x63000000 vexpress-v2p-ca9.dtb
=> fatload mmc 0:1 0x63100000 uinitramfs
  1. Démarrez le noyau
=> bootz 0x62000000 0x63100000 0x63000000

Et voilà !

Dans un système réel, ces commandes pourraient être automatisées pour être exécutées automatiquement. Cette automatisation peut se faire en dur lors de la compilation d’U-Boot.


© Copyright 2020 Guillaume Duc. Le contenu de cette page est mis à disposition selon les termes de la Licence Creative Commons Attribution - Partage dans les Mêmes Conditions 4.0 International (à l'exception des exemples de code tirés du noyau Linux et qui sont distribués sous leurs licences d'origine).

Licence
Creative Commons