Guix sur une carte ARM

par Julien Lepiller — mer. 27 novembre 2019

De plus en plus les gens qui découvrent Guix veulent l'essayer sur une carte ARM, au lieu de leur ordinateur x86. Il peut y avoir plusieurs raisons pour cela, comme la consommation de ressources ou la sécurité. Dans mon cas, j'ai trouvé ces cartes pratiques pour l'autohébergement et je crois que les propriétés uniques de Guix font que ce système est parfaitement adapté à ce cas d'utilisation. J'ai installé GNU Guix sur un Cubietruck, donc mes exemples ci-dessous parleront de cette carte. Cependant, vous devriez être capables de changer les exemples pour votre propre cas.

Installer le système Guix sur une carte ARM n'est pas aussi facile que pour un ordinateur de bureau à base x86 : il n'y a pas d'image d'installation. Cependant, Guix prend en charge ARM et peut être installé sur une distribution externe qui tourne sur cette architecture. L'astuce consiste à utiliser le Guix installé sur cette distribution externe pour initialiser le système Guix. Cet article va vous montrer comment installer le système Guix sur votre carte, sans utiliser d'image d'installation. Comme cela a déjà été mentionné, il est possible de générer une image d'installation par vous-même, si votre carte est prise en charge.

La plupart des cartes peuvent être démarrées avec une distribution GNU+Linux existante. Vous aurez besoin d'installer une distribution (n'importe laquelle) et d'installer GNU Guix dessus, en utilisant p. ex. le script d'installation. Ensuite, mon plan était d'installer le système Guix sur un disque SSD externe, au lieu de la carte SD, mais nous verrons que les deux cas sont parfaitement possibles.

La première partie de cet article se concentrera sur la création d'une configuration u-boot appropriée et d'une déclaration du système d'exploitation qui correspond à votre carte. La seconde partie de cet article se concentrera sur la procédure d'installation, quand il n'y a pas d'installateur pour votre système.

Écrirure un fichier de configuration pour une carte ARM

Un fichier de configuration pour une carte ARM n'est pas très différent d'un fichier de configuration pour un bureau ou un serveur qui utilise une autre architecture. Cependant, la plupart des cartes utilise le chargeur d'amorçage u-boot et ont besoin de modules moins communs au démarrages.

Le système de fichiers racine

Tout d'abord, vous devriez décider où votre système de fichiers racine sera installé. Dans mon cas, je voulais l'installer sur le SSD externe, donc j'ai choisi ceci :

(file-systems
  (cons* (file-system
           (mount-point "/")
           (device "/dev/sda1")
           (type "ext4"))
         %base-file-systems))

Si vous voulez plutôt installer le système de fichiers racine sur une carte SD, vous devrez trouver son nom de périphérique associé, généralement /dev/mmcblk0 et le numéro de partition. Le périphérique correspondant à la première partition devrait être /dev/mmcblk0p1. Dans ce cas, vous devriez avoir :

(file-systems
  (cons* (file-system
           (mount-point "/")
           (device "/dev/mmcblk0p1")
           (type "ext4"))
         %base-file-systems))

Le chargeur d'amorçage

Because of the way the Guix System is designed, you cannot use an already existing bootloader to boot your system: it wouldn't know where to look for the kernel, because it doesn't know its store path. It wouldn't be able to let you boot older generations either. Most boards use the u-boot bootloader, so we will focus on that bootloader here.

Contrary to grub, there are multiple variants of u-boot, one per board type. The installation procedure for u-boot is also somewhat specific to the board, so there are two things that you need to take care of: the u-boot package and the bootloader declaration.

Guix défini déjà quelques chargeurs d'amorçages basés sur u-boot, comme u-boot-a20-olinuxino-lime-bootloader ou u-boot-pine64-plus-bootloader entre autres. Si votre carte a déjà un u-boot-*-bootloader défini dans (gnu bootloader u-boot), vous avez de la chance et vous pouvez passer cette partie de l'article !

Sinon, peut-être que le paquet du chargeur d'amorçage est défini dans (gnu packages bootloaders), comme c'est le cas du paquet u-boot-cubietruck. Si c'est le cas, vous avez un peu de chance et vous pouvez passer la création de votre propre définition d'un paquet.

Si votre carte n'a pas de paquet u-boot-* défini, vous pouvez en créer un. Cela peut être aussi simple que (make-u-boot-package "Cubietruck" "arm-linux-gnueabihf"). Le premier argument est le nom de la carte, tel que le connait le système de construction de u-boot. Le second argument est le triplet cible qui correspond à l'architecture de la carte. Vous devriez vous référer à la documentation de votre carte pour choisir les bonnes valeurs. Si vous n'avez vraiment pas de chance, vous devrez travailler un peu plus pour que le paquet u-boot que vous venez de créer fonctionne, comme c'est le cas de u-boot-puma-rk3399 par exemple : il a besoin de phases supplémentaires pour installer un firmware.

Vous pouvez ajouter la définition du paquet à votre fichier de configuration du système d'exploitation comme ceci, avant la déclaration du système d'exploitation :

(use-modules (gnu packages bootloaders))

(define u-boot-my-board
  (make-u-boot-package "Myboard" "arm-linux-gnueabihf"))

(operating-system
  [...])

Ensuite, vous devrez définir le chargeur d'amorçage. Un chargeur d'amorçage est une structure qui a un nom, un paquet, un installateur, un fichier de configuration et un générateur de fichiers de configuration. Heureusement, Guix défini déjà un chargeur d'amorçage u-boot de base, donc on peut en hériter et seulement définir une partie.

Le Cubietruck est basé sur un cœur allwinner, pour lequel il y a déjà une définition du chargeur d'amorçage u-boot u-boot-allwinner-bootloader. Ce chargeur d'amorçage n'est pas utilisable par le Cubietruck, mais il défini presque tout ce dont on a besoin. Pour en faire un chargeur d'amorçage correct pour le Cubietruck, nous définissons un chargeur d'amorçage basé sur la définition du chargeur d'amorçage pour Allwinner :

(define u-boot-cubietruck-bootloader
  (bootloader
    (inherit u-boot-allwinner-bootloader)
    (package u-boot-cubietruck)))

Maintenant que nous avons nos définitions, nous pouvons choisir où installer le chargeur d'amorçage. Dans le cas du Cubietruck, j'ai décidé de l'installer sur la carte SD, parce qu'il ne peut pas démarrer depuis le SSD directement. Référez-vous à la documentation de votre carte pour vous assurer d'installer u-boot sur un périphérique amorçable. Comme je le disais tout à l'heure, la carte SD est /dev/mmcblk0 sur mon appareil.

On peut maintenant tout mettre ensemble comme ceci :

(use-modules (gnu packages bootloaders))

(define u-boot-cubietruck
  (make-u-boot-package "Cubietruck" "arm-linux-gnueabihf"))

;; u-boot-allwinner-bootloader n'est pas exporté par (gnu bootloader u-boot),
;; donc nous utilisons @@ pour le récupérer.  (@ (module) variable) signifie :
;; récupère la valeur de « variable » définie (et exportée) dans (module).
;; (@@ (module) variable) signifie la même chose, mais se fiche de savoir
;; si la variable est exportée ou non.
(define u-boot-allwinner-bootloader
  (@@ (gnu bootloader u-boot) u-boot-allwinner-bootloader))

(define u-boot-cubietruck-bootloader
  (bootloader
    (inherit u-boot-allwinner-bootloader)
    (package u-boot-cubietruck)))

(operating-system
  [...]
  (bootloader
    (bootloader-configuration
      (target "/dev/mmcblk0")
      (bootloader u-boot-cubietruck-bootloader)))
  [...])

Les modules du noyau

Pour que Guix puisse charger le système à partir de l'initramfs, il aura surement besoin de charger quelques modules, surtout pour accéder au système de fichiers racine. Dans mon cas, le SSD est un périphérique AHCI, donc j'ai besoin d'un pilote approprié. Le noyau défini ahci_sunx pour ce périphiérique sur toutes les cartes sunxi. La carte SD elle-même a besoin de deux pilotes : sunxi-mmc et sd_mod.

Votre propre carte peut avoir besoin d'autres modules du noyau pour démarrer correctement, mais il est difficile de les découvrir. Guix peut vous indiquer qu'un module manque dans votre configuration s'il est chargé en tant que module. La plupart des distributions construisent ces modules en dur dans le noyau directement, donc Guix ne peut pas les détecter correctement. Une autre manière de découvrir les pilotes qui peuvent être requis consiste à regarder la sortie de dmesg. Vous trouverez des messages comme :

[    5.193684] sunxi-mmc 1c0f000.mmc: Got CD GPIO
[    5.219697] sunxi-mmc 1c0f000.mmc: initialized, max. request size: 16384 KB
[    5.221819] sunxi-mmc 1c12000.mmc: allocated mmc-pwrseq
[    5.245620] sunxi-mmc 1c12000.mmc: initialized, max. request size: 16384 KB
[    5.255341] mmc0: host does not support reading read-only switch, assuming write-enable
[    5.265310] mmc0: new high speed SDHC card at address 0007
[    5.268723] mmcblk0: mmc0:0007 SD32G 29.9 GiB

ou

[    5.614961] ahci-sunxi 1c18000.sata: controller can't do PMP, turning off CAP_PMP
[    5.614981] ahci-sunxi 1c18000.sata: forcing PORTS_IMPL to 0x1
[    5.615067] ahci-sunxi 1c18000.sata: AHCI 0001.0100 32 slots 1 ports 3 Gbps 0x1 impl platform mode
[    5.615083] ahci-sunxi 1c18000.sata: flags: ncq sntf pm led clo only pio slum part ccc 
[    5.616840] scsi host0: ahci-sunxi
[    5.617458] ata1: SATA max UDMA/133 mmio [mem 0x01c18000-0x01c18fff] port 0x100 irq 37
[    5.933494] ata1: SATA link up 3.0 Gbps (SStatus 123 SControl 300)

Remarquez aussi que les noms des modules ne sont pas cohérents entre ce qu'attend Guix et ce qui est affiché par dmesg, surtout quand ils contiennent un « - » ou un « _ ». Vous trouverez le bon nom de fichier en construisant (ou en utilisant un substitute pour) linux-libre :

find `guix build linux-libre`/lib/modules -name '*mmc*'

Ici, j'ai trouvé un fichier nommé kernel/drivers/mmc/host/sunxi-mmc.ke, d'où le nom de module sunxi-mmc. Pour l'autre pilote, j'ai trouvé kernel/drivers/ata/ahci_sunxi.ko, d'où le nom ahci_sunxi, même si dmesg suggérait ahci-sunxi.

Une fois que vous avez trouvé les modules que vous voulez charger avant de monter votre partition racine, vous pouvez les ajouter à votre fichier de déclaration du système d'exploitation :

(initrd-modules (cons* "sunxi-mmc" "sd_mod" "ahci_sunxi" %base-initrd-modules))

Installer le système Guix

Installer sur un autre périphérique

Dans mon cas, je voulais installer le système sur un SSD externe, alors que le système de la distribution externe tournait sur la carte SD. Ce qui est bien avec ce scénario, c'est qu'en cas de vrai souci (votre SSD a pris feu ou est cassé), vous pouvez toujours démarrer sur l'ancien système extrene avec Guix installé dessus et tous vos outils en reflashant simplement le chargeur d'amorçage.

Dans ce scénario, nous utilisons le système externe comme nous aurions utilisé l'iso de l'installateur, en utilisant la procédure l'installation manuelle décrite dans le manuel. EN gros, vous devez partitionner votre SSD comme vous le souhaitez, formater vos nouvelles partitions et vous assurer de référencer la bonne partition qui contient le système de fichiers racine dans votre fichier de configuration. Ensuite, initialisez le système avec :

mount /dev/sda1 /mnt
mkdir /mnt/etc
$EDITOR /mnt/etc/config.scm # create the configuration file
guix system init /mnt/etc/config.scm /mnt

Vous pouvez maintenant redémarrer et jouer avec votre nouveau système Guix !

Installer sur le même périphérique

Une autre option consiste à installer le système Guix par dessus une distribution externe existante, en la remplaçant complètement. Remarquez que le système de fichiers racine du nouveau système Guix est le système de fichiers racine actuel, donc il n'est pas nécessaire de le monter. Les commandes suivantes vont initialiser votre système :

$EDITOR /etc/config.scm # create the configuration file
guix system init /etc/config.scm /

Assurez-vous de supprimer les fichiers de votre ancien système. Vous devriez au moins vous débarrasser du répertoire /etc, comme ceci :

mv /etc{,.bak}
mkdir /etc

Assurez-vous qu'il y a un dossier /etc vide, ou le nouveau système ne démarrera pas correctement. Vous pouvez copier votre config.scm vers votre nouveau répertoire /etc. Vous pouvez maintenant redémarrer et profiter de votre nouveau système Guix !

À propos de GNU Guix

GNU Guix est un gestionnaire de paquets transactionnel et une distribution avancée du système GNU qui respecte les libertés de ses utilisateurs. Guix est utilisable sur tous les systèmes qui utilisent le noyau Linux ou en tant que distribution de système d'exploitation indépendante pour le machines à base i686, x86_64, ARMv7 et AArch64.

En plus des fonctionnalités de gestion des paquets standards, Guix prend en charge les mises à jour et les retours transactionnels, la gestion de paquets non privilégiée, les profils par utilisateur et le nettoyage. Lorsqu'il est utilisé comme distribution GNU/Linux indépendante, Guix propose une approche déclarative et sans état à la gestion de configuration du système d'exploitation. Guix est facilement personnalisable et hackable à travers ses interfaces de programmation Guile et ses extensions au langage Scheme.