Depuis trois jours, j’installe Debian 7 sur un DreamPlug. Il avait auparavant le Debian 6 d’usine fourni par Marvell, mais cela commençait à devenir vieux : sécurité de moins en moins assurée, noyau Linux 2.6, évolution des versions des logiciels, etc. À partir de Debian 7, Debian prend en charge directement les DreamPlugs, ou disons la famille des GuruPlugs. J’ai donc tenté la mise à jour qui n’a pas été de tout repos. Je retrace ci-après les grandes étapes et surtout les problèmes que j’ai rencontrés.

Ce qui suit s’applique au passage du Debian 6 customisé Marvell au Debian 7 naturel en passant par l’installeur Debian naturel, et en écrasant tout le système préexistant. Il est peut-être possible de faire une mise à jour simple avec apt-get dist-upgrade, mais il y aurait peut-être des problèmes du fait qu’il faudrait probablement mettre à jour en même temps U-Boot, le bootloader, en 2012.04 et Debian (j’ai eu des problèmes de par le passé à vouloir mettre à jour U-Boot en gardant Debian 6). Cet article tente de donner (presque) toutes les commandes qui ont été nécessaires à cette installation de Debian 7 sur DreamPlug.

Préparation

Je supposerai dans la suite que vous disposez, outre le DreamPlug, d’un autre ordinateur sous GNU/Linux relié au DreamPlug au moyen d’une connexion UART/JTAGUSB (vendue avec le DreamPlug ou à l’unité). Sur cet ordinateur, vous pouvez utiliser l’utilitaire minicom (fourni dans un paquet Debian et probablement disponible ailleurs aussi). Si vous avez un autre plug computer que le DreamPlug, ne suivez pas directement ces instructions et reportez-vous à ces autres documents. Bien sûr, il va sans dire mais ça va mieux en le disant qu’il est très souhaitable de faire une sauvegarde des données existantes du DreamPlug avant l’installation de Debian 7.

Martin Michlmayr a écrit plusieurs documents sur les plugs computers, dont les DreamPlugs qui nous intéressent, et en particulier un guide de mise à jour vers Debian 7. La première étape importante est de mettre à jour Das U-Boot, le bootloader des DreamPlugs, vers la version 2011.12-3 ou plus récente. Pour ma part, j’ai utilisé la version 2012.04.01-2 de Debian 7 en téléchargeant ce paquet et en utilisant la version spécialement compilée pour le DreamPlug (copier le bon fichier u-book.kwb sur une partition accessible à U-Boot, par exemple sur une carte SD ou une clé USB formatée en ext2, ext3 ou FAT32 -- de mémoire l’ext4 n’est pas lu par les vieilles versions de U-Boot antérieures à 2010).

Avant de se lancer dans cette mise à jour de U-Boot, j’ai également mis sur une partition accessible à U-Boot l’installeur de Debian 7 récupéré dans l’archive Debian (copier les uImage et uInitrd spécifiques au DreamPlug ; leur donner des noms spécifiques plutôt que d’écraser les fichiers existants, par exemple uImageD7 et uInitrdD7). Noter qu’une bonne pratique est de vérifier les sommes de contrôle des paquets téléchargés lorsque c’est possible pour prévenir toute corruption des paquets ; pour Debian, les sommes MD5, SHA-1 et SHA-256 sont indiquées sur la page de téléchargement et peuvent être vérifiées avec md5sum, sha1sum et sha256sum.

Mise à jour de U-Boot

Une fois le DreamPlug redémarré et observé au travers de la connexion série UART/JTAG, il faut arrêter le lancement du système en appuyant sur une touche (par défaut on a trois secondes pour ce faire). Ensuite peuvent être affichées les variables d’environnement U-Boot pour vérification :
Marvell>> print
ou
Marvell>> printenv

La variable d’environnement la plus importante est bootcmd qui est celle qui sera exécutée lors des lancements automatiques, et bootargs est également importante puisqu’elle contient les arguments qui seront passés au noyau Linux. Il est possible d’exécuter du code inscrit dans d’autres variables d’environnement U-Boot en appellant run NOM-VARIABLE ; cela permet de décomposer les instructions de démarrage en plusieurs sous-sections.

Pour lancer la mise à jour de U-Boot, il faut commencer par lancer le sous-système USB de U-Boot :
Marvell>> usb start
puis chercher la partition sur laquelle vous avez mis les fichiers u-boot.kwb et les uImageD7/uInitrdD7 de l’installeur Debian. Si vous ne savez pas, vous pouvez essayer successivement les numéros de 0 à 5 (?) dans les commandes suivantes jusqu’à trouver les fichiers :
Marvell>> ext2ls usb 0
(Si la partition est en ext2 ou ext3 ; si la partition est en FAT32, ce sera fatls et fatload dans la suite.)

Pour mettre à jour U-Boot, il faut exécuter la séquence qui suit. Bien sûr, le usb NUMÉRO est issu de l’étape précédente. Attention, en cas d’interruption au milieu, il est possible que le DreamPlug ne redémarre pas, assurez-vous qu’il n’y a pas d’orage, que le courant ne sera pas coupé, etc.
Marvell>> ext2load usb NUMÉRO 0x0800000 u-boot.kwb
Marvell>> sf probe 0
Marvell>> sf erase 0x0 0x60000
Marvell>> sf write 0x0800000 0x0 0x60000

Enfin, redémarrez le DreamPlug et arrêtez à nouveau le démarrage.
Marvell>> reset

Installation de Debian 7

Si vous avez bien mis les deux fichiers d’installation de Debian 7 uImageD7 et uInitrdD7 sur une partition accessible à U-Boot, chargez ces deux fichiers en mémoire (sinon il est encore temps de les mettre sur une clé USB à partir d’un autre ordinateur).
Marvell>> usb start
Marvell>> ext2load usb NUMÉRO 0x00800000 uImageD7
Marvell>> ext2load usb NUMÉRO 0x01100000 uInitrdD7
Marvell>> setenv bootargs console=ttyS0,115200n8 base-installer/initramfs-tools/driver-policy=most
Marvell>> bootm 0x00800000 0x01100000

Ensuite, l’installeur Debian va se lancer, vous poser des questions pendant un petit quart d’heure et prendra ensuite quelques heures pour installer le système Debian 7. Je n’ai pas eu de problèmes lors de cette étape mis à part un avertissement à la fin de l’installation prévenant que le bootloader ne pouvait pas être mis à jour, mais cela peut être ignoré puisqu’on a fait la mise à jour à l’étape précédente. J’ai ensuite redémarré le système, ce qui n’était peut-être pas la meilleure idée : s’il est proposé de lancer directement le système à la suite, sautez sur l’occasion et passez au dernier titre ci-après pour compiler un noyau « sans NAND_ORION » – j’expliquerai ce que c’est.

Problème d’identification de la machine par Linux : machid

Normalement, l’installeur Debian a déposé dans le dossier /boot du système le noyau (3.2.0-4-kirkwood pour moi) et le système Debian 7 devrait normalement se charger avec la séquence suivante de U-Boot :
Marvell>> usb start
Marvell>> ext2load usb NUMÉRO 0x00800000 uImage
Marvell>> ext2load usb NUMÉRO 0x01100000 uInitrd
Marvell>> setenv bootargs 'console=ttyS0,115200 rw root=/dev/sda1 rootdelay=10 panic=10'
Marvell>> bootm 0x00800000 0x01100000

Notez que le /dev/sda1 est peut-être à remplacer si votre système racine a été installé sur une autre partition, et que les uImage et uInitrd ont peut-être d’autres noms.
Notez aussi que vous pouvez automatiser le processus de lancement en fixant une fois pour toutes la variable d’environnement bootargs et surtout bootcmd, cette dernière avec :
Marvell>> setenv bootargs 'printenv; usb start; ext2load usb NUMÉRO 0x00800000 uImage; ext2load usb NUMÉRO 0x01100000 uInitrd; bootm 0x00800000 0x01100000'
Marvell>> saveenv

En lançant ce noyau Linux Debian 7, celui-ci (le noyau Linux) répond dès le début qu’il ne reconnait pas le matériel :

Error: unrecognized/unsupported machine ID (r1 = 0x00000dde).
Available machine support:
ID (hex)        NAME
00000690        Marvell DB-88F6281-BP Development Board
00000691        Marvell RD-88F6192-NAS Development Board
00000692        Marvell RD-88F6281 Reference Board
0000078c        Marvell 88F6281 GTW GE Board
00000a76        Marvell eSATA SheevaPlug Reference Board
00000831        Marvell SheevaPlug Reference Board
00000a63        Marvell GuruPlug Reference Board
[...]
00000b1e        HP t5325 Thin Client
ffffffff        Marvell Kirkwood (Flattened Device Tree)
Please check your kernel config and/or bootloader.

Puisque j’ai recherché les causes de ceci, je vais vous en faire profiter :-) Linux s’attend à reçevoir une indication sur le type de matériel sur lequel il se trouve ; dans le cas des processeurs ARM, ces numéros sont référencés dans le fichier arch/arm/tools/mach-types du noyau Linux. Dans notre cas, le DreamPlug a le numéro hexadécimal 0xdde (=3550) (ne cherchez pas dans la liste de Linux, il n’y est pas :/ il est sur le site officiel de ARM). La version U-Boot de Debian indique donc le bon identifiant de matériel, mais Linux ne le connait pas.

L’ancienne version de U-Boot (Marvell customisée) donnait à Linux l’identifiant hexadécimal 0xa63 (=2659), le GuruPlug étant très proche du DreamPlug. C’est donc ce que nous allons faire. Pour cela, il faut configurer la variable d’environnement U-Boot machid à 0xa63 :
Marvell>> setenv machid a63
Marvell>> saveenv

Sur les forums, il est évoqué aussi la variable arcNumber mais il semble que cela était pour les (très) vieilles versions de U-Boot (d’ailleurs arcNumber n’apparaît pas dans les sources de U-Boot, contrairement à machid). L’option Flattened Device Tree est censée être une unification des configurations matérielles pour le futur, mais elle n’a pas fonctionné pour moi (le noyau ne se lance pas) et l’expérience est identique pour David Madore (que je remercie vraiment au passage car c’est lui qui m’a débloqué grâce à cette page dans les deux gros problèmes que j’ai rencontrés, avec quelques autres recherches sur le Web pour les instructions précises).

Une fois ces commandes exécutées, le démarrage de Linux se lance bien. Du moins dans mon cas pendant les 15 secondes suivantes.

Arrêt du chargement du noyau lors de l’initialisation du NAND Orion, inexistant sur DreamPlug

Le chargement du noyau Debian (3.2.0-4-kirkwood) s’arrêtait systématiquement après "console [ttyS0] enabled" dans la fonction "nand_read_byte". Plus exactement, c’est le watchdog qui retourne ce message toutes les 22 secondes. Pour être plus précis, c’est avec la fonction "orion_nand_probe" que les problèmes se posent. Voici mon log d’erreur exact :

[   11.167148] console [ttyS0] enabled
[   38.208674] BUG: soft lockup - CPU#0 stuck for 22s! [swapper:1]
[   38.214621] Modules linked in:
[   38.217690]
[   38.219183] Pid: 1, comm:              swapper
[   38.223641] CPU: 0    Not tainted  (3.2.0-4-kirkwood #1 Debian 3.2.54-2)
[   38.230380] PC is at nand_read_byte+0xc/0x10
[   38.234673] LR is at nand_command+0x184/0x1c4
[   38.239051] pc : [<c0207e6c>]    lr : [<c020ace0>]    psr: 60000013
[   38.239056] sp : df82be80  ip : c020ab5c  fp : 00000000
[   38.250593] r10: 00000000  r9 : 00000000  r8 : ffffffff
[   38.255844] r7 : ffffffff  r6 : df8c4800  r5 : 000000ff  r4 : df8c4a20
[   38.262400] r3 : e08aa000  r2 : 00000081  r1 : ffffffff  r0 : 00000000
[   38.268958] Flags: nZCv  IRQs on  FIQs on  Mode SVC_32  ISA ARM  Segment kernel
[   38.276300] Control: 0005397f  Table: 00004000  DAC: 00000017
[   38.282093] [<c00137c4>] (unwind_backtrace+0x0/0xe0) from [<c0065068>] (watchdog_timer_fn+0xe0/0x134)
[   38.291361] [<c0065068>] (watchdog_timer_fn+0xe0/0x134) from [<c0043c94>] (__run_hrtimer+0x118/0x1ec)
[   38.300628] [<c0043c94>] (__run_hrtimer+0x118/0x1ec) from [<c00444bc>] (hrtimer_interrupt+0xf4/0x23c)
[   38.309903] [<c00444bc>] (hrtimer_interrupt+0xf4/0x23c) from [<c001a3a8>] (orion_timer_interrupt+0x20/0x30)
[   38.319701] [<c001a3a8>] (orion_timer_interrupt+0x20/0x30) from [<c0065958>] (handle_irq_event_percpu+0x7c/0x23c)
[   38.330015] [<c0065958>] (handle_irq_event_percpu+0x7c/0x23c) from [<c0065b40>] (handle_irq_event+0x28/0x38)
[   38.339895] [<c0065b40>] (handle_irq_event+0x28/0x38) from [<c0067d04>] (handle_level_irq+0xac/0xbc)
[   38.349077] [<c0067d04>] (handle_level_irq+0xac/0xbc) from [<c0065328>] (generic_handle_irq+0x28/0x44)
[   38.358438] [<c0065328>] (generic_handle_irq+0x28/0x44) from [<c000ee14>] (handle_IRQ+0x60/0x84)
[   38.367266] [<c000ee14>] (handle_IRQ+0x60/0x84) from [<c000db34>] (__irq_svc+0x34/0x78)
[   38.375314] [<c000db34>] (__irq_svc+0x34/0x78) from [<c0207e6c>] (nand_read_byte+0xc/0x10)
[   38.383627] [<c0207e6c>] (nand_read_byte+0xc/0x10) from [<c020ace0>] (nand_command+0x184/0x1c4)
[   38.392372] [<c020ace0>] (nand_command+0x184/0x1c4) from [<c020a150>] (nand_scan_ident+0x16c/0xa94)
[   38.401466] [<c020a150>] (nand_scan_ident+0x16c/0xa94) from [<c020be9c>] (nand_scan+0x48/0x68)
[   38.410128] [<c020be9c>] (nand_scan+0x48/0x68) from [<c040048c>] (orion_nand_probe+0x120/0x1b0)
[   38.418876] [<c040048c>] (orion_nand_probe+0x120/0x1b0) from [<c01ef9e0>] (platform_drv_probe+0x14/0x18)
[   38.428403] [<c01ef9e0>] (platform_drv_probe+0x14/0x18) from [<c01eeb10>] (driver_probe_device+0xd4/0x198)
[   38.438107] [<c01eeb10>] (driver_probe_device+0xd4/0x198) from [<c01eec34>] (__driver_attach+0x60/0x84)
[   38.447550] [<c01eec34>] (__driver_attach+0x60/0x84) from [<c01ed798>] (bus_for_each_dev+0x50/0x84)
[   38.456645] [<c01ed798>] (bus_for_each_dev+0x50/0x84) from [<c01ee40c>] (bus_add_driver+0x9c/0x218)
[   38.465740] [<c01ee40c>] (bus_add_driver+0x9c/0x218) from [<c01eeedc>] (driver_register+0xa0/0x12c)
[   38.474836] [<c01eeedc>] (driver_register+0xa0/0x12c) from [<c01efbb4>] (platform_driver_probe+0x18/0x68)
[   38.484454] [<c01efbb4>] (platform_driver_probe+0x18/0x68) from [<c00085a4>] (do_one_initcall+0x90/0x168)
[   38.494079] [<c00085a4>] (do_one_initcall+0x90/0x168) from [<c03e882c>] (kernel_init+0xbc/0x164)
[   38.502917] [<c03e882c>] (kernel_init+0xbc/0x164) from [<c000ee98>] (kernel_thread_exit+0x0/0x8)

Après recherches, et en particulier la page de David Madore, une page de forum de Fedora 17 et la discussion liée sur la liste ARM de Fedora et probablement ici aussi, il apparaît que le DreamPlug n’a pas le périphérique NAND Orion (contrairement à d’autres plug computers de la famille GuruPlug) mais le noyau essaye quand même de lire ce périphérique. Plus précisément, ce périphérique est géré par le module orion_nand du noyau. La solution évoquée pour Fedora et qui fonctionnait était de blacklister ce module. Pour Debian 7, cela ne fonctionnait pas d’après mes tests, d’autant que le module orion_nand chez Debian est un module intégré (built-in), impossible à désactiver donc. Pour Debian, ce problème correspond au bug 717470, rapporté pour les noyaux à partir de 3.9.x, et j’ai rencontré le problème également avec le noyau 2.6.x de Debian 7.

D’après David Madore, il faut compiler un noyau sans la directive de compilation CONFIG_MTD_NAND_ORION, et il apparaît que cela fonctionne effectivement pour le noyau Linux 3.2.x de Debian 7. Je détaille ci-après le mode opératoire pour compiler ce noyau fonctionnel sur DreamPlug. Je me suis permis de ne pas changer le nom du noyau (pas de « +nonand » ajouté au nom du noyau) étant donné que ce noyau est presque pareil que celui de Debian 7 à une directive de compilation (et donc réutiliser tous les autres modules) près et surtout que ça ne voulait pas compiler lorsque je changeai abi.abiname dans debian/config/defines (exception Python lors de l’exécution de make -f debian/rules source). À part ça, j’ai suivi HowToRebuildAnOfficialDebianKernelPackage sur le wiki Debian. (note : c’est la première fois que je compilai un noyau, il y a sûrement matière à mieux compiler ce noyau-ci.)

Pour éviter d’avoir à faire du cross-build depuis une autre architecture, le plus simple (qui a fonctionné pour moi) est de charger le système Debian 7 avec le noyau 2.6 de Marvell (téléchargeable ici). Redémarrer le DreamPlug et exécuter dans U-Boot :
Marvell>> usb start; ext2load usb NUMÉRO 0x00800000 uImage_dreamplug_v10_Aug-28-2012; bootm 0x00800000

Une fois connecté en root à Debian, exécutez :
$ apt-get install fakeroot build-essential devscripts quilt u-boot-tools
$ apt-get build-dep linux
$ apt-get source linux
$ cd linux-*
$ make -f debian/rules source
$ fakeroot make -f debian/rules.gen setup_armel_none_kirkwood
$ cd debian/build/build_armel_none_kirkwood
$ make menuconfig

Dans le menu de configuration du noyau qui apparaît, allez dans "Device Drivers" > "Memory Technology Device (MTD) support" > "NAND Device Support" > "NAND Flash support for Marvell Orion SoC" et désactivez cette dernière option.
$ cd ../../..
$ fakeroot make -f debian/rules.gen binary-arch_armel_none_kirkwood binary-indep DEBIAN_KERNEL_JOBS=1

Après quelques heures (et j’ai arrêté lors de la compilation des pages de manuel vu qu’elles étaient déjà présentes, et ça m’a pris entre 1 et 2 Gio), le noyau devient disponible dans le répertoire debian/linux-image-3.2.0-4-kirkwood/boot (les fichiers vmlinuz-3.2.0-4-kirkwood, System.map-3.2.0-4-kirkwood et config-3.2.0-4-kirkwood).
$ cd debian/linux-image-3.2.0-4-kirkwood

À partir de là, il faut créer le fichier initrd.img pour la version 3.2.0-4-kirkwood si vous ne l’avez pas déjà.
$ update-initramfs -u -k 3.2.0-4-kirkwood

Et enfin transformer les fichiers vmlinuz et initrd.img au format de fichier de U-Boot :
$ mkimage -A arm -O linux -T kernel -C none -a 0x00008000 -e 0x00008000 -n "Linux kernel 3.2.0-4-kirkwood" -d vmlinuz-3.2.0-4-kirkwood /boot/uImage-3.2.0-4+nonand-kirkwood
$ mkimage -A arm -O linux -T ramdisk -C none -a 0x00000000 -e 0x00000000 -n "Linux ramdisk 3.2.0-4-kirkwood" -d /boot/initrd.img-3.2.0-4-kirkwood /boot/uInitrd-3.2.0-4+nonand-kirkwood

Maintenant, pour charger ces noyau et ramdisk, il peut être pratique d’utiliser des liens symboliques pour les fichiers /boot/uImage et /boot/uInitrd (dans l’étape précédente, on a demandé à U-Boot de charger ces fichiers spécifiquement) (ça ne marche pas pour les partitions FAT32, il renommer explicitement les fichiers).
$ cd /boot
$ mv uImage uImage.old
$ mv uInitrd uInitrd.old
$ ln -s uImage-3.2.0-4+nonand-kirkwood uImage
$ ln -s uInitrd-3.2.0-4+nonand-kirkwood uInitrd

Maintenant, redémarrez le DreamPlug. Le système Debian 7 avec le noyau 3.2.x devrait se charger correctement (ça a été mon cas du moins). En cas de mise à jour du noyau, il faudrait également recompiler un noyau sans la directive de compilation CONFIG_MTD_NAND_ORION.

Je vais évoquer cette solution dans le bug 717470, mais je ne suis pas sûr de la résolution propre à effectuer, et cela rejoint les interrogations sur la liste de Fedora : comment faire en sorte de charger ce module orion_nand pour certains plug computers mais pas pour les DreamPlugs ? Il pourrait être utilisé la variable d’environnement machid donnée par U-Boot (0xdde = DreamPlug) mais Linux ne reconnait pas cette valeur et oblige donc à utiliser encore 0xa63 (= GuruPlug), ou alors utiliser 0xffffffff (= Marvell Kirkwood (Flattened Device Tree)) mais cela n’était pas encore fonctionnel. Si vous avez des idées ou plus d’expérience que moi, n’hésitez pas à compléter sur ce bug.