Gestion des mises à jour de Linux sous U-boot

Cette page présente en détails les scripts implémentant le système de mise à jour automatique des systèmes embarqués présenté sur le blog linuxembedded (ici).

Pour télécharger directement la solution, c'est ici.

Les paramètres : Environnement U-boot

Tout le système repose sur l'environnement d'U-boot contenant toutes les données nécessaires au fonctionnement du système de partitions (état d'une partition, ordre de démarrage des partitions, configuration du système, ...).
Les variables nécessaire au fonctionnement du système sont les suivantes :

Cet environnement est accessible depuis U-boot et depuis Linux. De plus, une option de redondance peut être activée, ce qui permet d'avoir un système robuste aux erreurs d'écritures et coupures de courant.

Installation des scripts

Script U-boot

Pour prévenir des problèmes des pertes d'alimentation ou des erreurs pendant l'écriture des variables d'environnements, souvent vitales pour le fonctionnement d'U-boot, la fonctionnalité de redondance de l'environnement U-boot doit être activée. Elle permet d'écrire l'environnement en alternance sur deux espaces mémoire. Ainsi si un problème survient pendant l'écriture, l'environnement précédent sera chargé depuis l'autre emplacement. Pour activer cette fonctionnalité, il faut définir les deux macros CONFIG_ENV_OFFSET_REDUND et CONFIG_ENV_SIZE_REDUND qui correspondent respectivement à l'adresse en mémoire du second environnement et de sa taille. Il peut être nécessaire d'augmenter la taille maximal du malloc de U-boot en la multipliant par deux la valeur de CONFIG_SYS_MALLOC_LEN.

Pour que U-boot puisse utiliser le script, il faut créer une image de celui-ci. Cette image contient un CRC, un nom et quelques informations utiles à U-boot pour vérifier que le script peut être exécuté sur la machine sans problèmes. Pour construire cette image, on utilise l'outil mkimage de U-boot :

mkimage -T script -C none -n 'Smart Uboot script' -d uboot_script uboot_script.img

Une fois cette image créée, il suffit de l'écrire quelque part dans la mémoire de la machine. Cela peut être par exemple une partition nommée u-boot-script de la mémoire flash.

Script Linux

Pour interagir sous Linux avec l'environnement de U-boot, on utilise les outils U-boot fw_setenv et fw_printenv disponible dans les générateur de rootfs comme Buildroot (Hardware handling → U-boot tools). Ces utilitaires permettent respectivement de lire une ou plusieurs variables depuis l'environnement d'U-boot et d'écrire une ou plusieurs variables dans l'environnement d'U-boot.

Ces utilitaires utilisent un fichier de configuration fw_env.config permettant de spécifier l'emplacement des environnements d'U-boot dans la mémoire ainsi que la configuration de la mémoire. Un exemple est donné dans les téléchargements plus bas.

Utilisation des scripts

Script U-boot

Pour lancer ensuite le script sous U-boot, il faut tout d'abord charger le script en mémoire RAM. Le lancement ce fait ensuite avec la commande source (anciennement autoscr) avec l'adresse mémoire où se trouve le script en RAM. Voici un exemple de commande pouvant être exécutée au démarrage d'U-boot :

nand read 0x80000000 u-boot-script; source 0x80000000

On charge le script depuis la partition nommée u-boot-script vers la RAM à l'adresse 0x80000000 et on lance le script avec source.

Script Linux

Le script smart_boot.sh permet d’interagir avec le gestionnaire de versions. Ce script donne l'état de démarrage et permet de faire des actions spécifiques en fonctions de la situation. On utilise l'option status qui renvoie un code en fonction de la situation et permet de nous indiquer si on a démarré sur une partition « mise à jour » ou sur l'ancienne partition car la partition « mise à jour » est corrompue. Ainsi dans les deux cas respectivement, on pourra valider avec validate ou invalider avec invalidate la mise à jour.

Voici un résumé des commandes possibles du script :

Liste des commandes :
print Affiche l'état des partitions.
allocate Alloue et bloque une partition vide ou la plus vielle partition pour installer une mise à jour.
update Marque la partition bloquée en partition mise à jour. Il faut appeler allocate avant.
validate Valide la partition marquée comme « mise à jour ». Appelé au premier démarrage sur la nouvelle partition.
invalidate Invalide la partition marquée comme « mise à jour ». Cette commande permet de revenir à la version précédente.
partition Affiche le numéro de la partition démarrée.
real-partition Affiche le numéro de la partition réellement démarrée en lisant un paramètre de la ligne de commande Linux.
clean Corrige les erreurs de démarrage et rétablit une situation stable.
force-rescue Permet de démarrer sur la partition de secours au prochain redémarrage.
unforce-rescue Rétablit le démarrage normal.
status Renvoie un code par rapport à la situation de démarrage.
Commandes avancées (informations) :
get-flag PART Renvoie l'état de la partition PART.
get-text PART Renvoie la description de version de la partition PART.
get-count PART Renvoie le nombre de tentative de démarrage pour la partition PART.
get-boot-seq Renvoie la séquence de démarrage.
Commandes avancées (modifications) :
set-flag PART FLAG Change l'état de la partition PART avec FLAG.
set-text PART TXT Change la description de version de la partition PART avec TXT.
set-count PART CNT Change le nombre de tentatives de démarrage pour la partition PART avec CNT.
set-boot-seq SEQ Change la séquence de démarrage avec SEQ.

Les cas possibles de démarrage donnés par status sont les suivants :

Le script s’exécute de la manière suivante :

./smart_boot.sh CMD

où CMD est une des commandes énoncées plus haut.

Ce script fonctionne avec le shell de Busybox, ce qui le rend compatible avec la plupart des shells.

Exemple : script de mise à jour intègre

Un script supplémentaire est disponible montrant un exemple de mise à jour d'un système embarqué de manière intègre : le script update.sh réalise les différentes étapes de l'installation de mise à jour suivantes :

Pour chacune de ces étapes, une chaîne est enregistrée dans un fichier state permettant de reprendre une mise à jour à la dernière étape connue en cas d'erreur ou de coupure d'alimentation. Le processus d'écriture est particulier : on écrit d'abord un fichier temporaire state.tmp que l'on « sync » sur la mémoire flash, puis on le renomme en fichier state. Cette technique permet de toujours conserver un fichier state intact même en cas de perte de courant puisque la fonction rename doit être atomique, c'est à dire qu'il y a deux états possibles : un avant et un après l'appel à la fonction. L'état avant appel correspond à la présence du nouveau fichier state.tmp et le précédent fichier state. L'état après appel correspond à la présence unique du nouveau fichier state. Ainsi, l'état où state serait plus ou moins écrit ne peux pas exister.

La mise à jour nécessite quatre fichiers :

Pour lancer la mise à jour il suffit de lancer le script update.sh dans le dossier contenant tous les fichiers de mise à jour. On obtient alors la sortie suivante dans le cas parfait. Si une erreur survient, la mise à jour est interrompue et un message d'erreur est émis.

Télechargements

Script U-boot :
uboot-script
Script Linux : smart_boot.sh
Script de mise à jour : update.sh
Fichier de configuration (exemple) : fw_env.config