Dans ce premier billet, je vous propose de démontrer qu’il est très simple de lire et écrire une EEPROM sous Linux. Malheureusement, en embarqué, les problèmes les plus simples se compliquent toujours. C’est pourquoi, dans un 2e billet, nous verrons comment contourner les petits soucis à l’aide de quelques connaissances au niveau de l’architecture matérielle, des pilotes linux et du bus i2c. Tout cela sans aucune compilation, mais avec un peu d’huile de coude.
Un problème?
Il y a quelques jours, un ingénieur matériel m’expose un problème délicat. Deux cent équipements ont été déployés mais ne fonctionnent pas car ils sont mal configurés. La configuration en question se trouve sur une mémoire non-volatile programmable de type EEPROM. Habituellement, les techniciens suivent la procédure qui suit:
- Démonter l’équipement de son support
- Démonter le boîtier
- Connecter un émulateur JTAG à l’équipement
- Reprogrammer la mémoire à l’aide de la connexion JTAG
- Remonter le boîtier
- Remonter l’équipement sur son support
- goto 1 et répéter pour les 200 équipements.
Ouch! Voilà qui risque d’être long! Bonne nouvelle, cependant : le système roule un Linux plutôt récent (2.6.30). On devrait donc pouvoir faire plus subtil en utilisant la méthode logicielle.
I-squared-C
Les EEPROM sont le plus souvent interfacées sur un bus i2c. L’i2c est un bus à 2 fils, normalisé par Philips en 1992, dont le protocole de communication maître/esclave est simple et très bien supporté par Linux. Dans un système Linux, les périphériques i2c se trouvent dans /sys/bus/i2c/devices
.
# ls -l /sys/bus/i2c/devices
total 0
lrwxrwxrwx 1 root root 0 Feb 11 01:49 0-004c -> ../../../devices/e0000000.soc/e0003000.i2c/i2c-0/0-004c
lrwxrwxrwx 1 root root 0 Feb 11 01:49 0-0050 -> ../../../devices/e0000000.soc/e0003000.i2c/i2c-0/0-0050
lrwxrwxrwx 1 root root 0 Feb 11 01:49 0-0068 -> ../../../devices/e0000000.soc/e0003000.i2c/i2c-0/0-0068
lrwxrwxrwx 1 root root 0 Feb 11 01:49 1-0070 -> ../../../devices/e0000000.soc/e0003100.i2c/i2c-1/1-0070
lrwxrwxrwx 1 root root 0 Feb 11 01:49 2-0024 -> ../../../devices/e0000000.soc/e0003100.i2c/i2c-1/i2c-2/2-0024
lrwxrwxrwx 1 root root 0 Feb 11 01:49 2-004c -> ../../../devices/e0000000.soc/e0003100.i2c/i2c-1/i2c-2/2-004c
lrwxrwxrwx 1 root root 0 Feb 11 01:49 2-0054 -> ../../../devices/e0000000.soc/e0003100.i2c/i2c-1/i2c-2/2-0054
lrwxrwxrwx 1 root root 0 Feb 11 01:49 2-0055 -> ../../../devices/e0000000.soc/e0003100.i2c/i2c-1/i2c-2/2-0055
lrwxrwxrwx 1 root root 0 Feb 11 01:49 i2c-0 -> ../../../devices/e0000000.soc/e0003000.i2c/i2c-0
lrwxrwxrwx 1 root root 0 Feb 11 01:49 i2c-1 -> ../../../devices/e0000000.soc/e0003100.i2c/i2c-1
lrwxrwxrwx 1 root root 0 Feb 11 01:49 i2c-2 -> ../../../devices/e0000000.soc/e0003100.i2c/i2c-1/i2c-2
Le premier chiffre renseigne le numéro du bus sur lequel le périphérique est connecté (4). Le nombre suivant représente l’adresse hexadécimale (0x54) du périphérique. Celui-ci va répondre aux commandes contenant cette adresse et ignorer les commandes contenant une adresse différente.
Hexadécimal après la virgule
Habituellement les EEPROM sont programmées en hexadécimal, c’est à dire que leur contenu n’est pas lisible par un éditeur de texte classique. Une telle lecture ne retournera pas grand chose d’utile. Par exemple :
# cat /sys/bus/i2c/devices/4-0054/eeprom
♦®♦™♦©♦
Il existe cependant de nombreux outils sous Linux pour lire l’hexadécimal, comme hexdump
, od
ou xxd
:
# od -x eeprom
0000000 4b5a 2020 2020 2020 2020 2020 2020 2020
0000020 2020 2020 2020 2020 2020 2020 2020 2020
0000040 2020 2020 2020 2020 2020 2020 2020 4e50
0000080 454e 3031 2020 2020 2020 2020 2020 2020
# hexdump -C eeprom
00000000 4b 5a 20 20 20 20 20 20 20 20 20 20 20 20 20 20 |KZ |
00000010 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 | |
00000020 20 20 20 20 20 20 20 20 20 20 20 20 20 20 4e 50 | NP|
00000030 45 4e 30 31 20 20 20 20 20 20 20 20 20 20 20 20 |EN01 |
Pour éditer le contenu, il faudrait un éditeur hexadécimal. Malheureusement :
- Il est plutôt rare d’avoir ce genre d’outil disponible sur un Linux embarqué
- Certaines (vieilles) EEPROM ne peuvent pas être reprogrammées partiellement. On ne peut que tout effacer et tout réécrire.
Nous allons donc employer la méthode suivante :
- Faire une copie locale
- La transférer sur la machine de travail
- Modifier la copie à l’aide d’un éditeur hexadécimal
- Transférer la copie modifiée sur l’équipement
- Reprogrammer l’EEPROM à l’aide du fichier modifié.
Pour la copie locale, on va utiliser dd
:
# dd if=/sys/bus/i2c/devices/4-0054/eeprom of=/tmp/eeprom.orig conv=direct
C’est l’utilisation la plus simple de dd
: on copie le contenu du fichier d’entrée (if
: input file) vers le fichier de sortie (of
: output file). L’option conv=direct
empêche l’utilisation de mémoire tampon (cache) pour le transfert. Notez qu’on aurait aussi pu utiliser un simple cp
, ici.
Passons au transfert sur la machine de travail. L’équipement est connecté en ethernet et dispose d’un client FTP embarqué (busybox
) qui permet de transférer le fichier facilement. Si votre équipement est équipé d’un serveur SSH (dropbear
), pensez aussi à scp
. Dernièrement, je suis tombé sur un équipement ne disposant ni d’un serveur, ni d’un client ssh ou FTP. Eh oui, ça existe! Heureusement, netcat
était présent et la copie a pu se faire ainsi :
(target) $ nc -w 3 192.168.1.22 1234 < ~/tmp/eeprom.orig
(host) # nc -l -p 1234 > ~/eeprom.orig
Place à la modification. Si votre poste de travail est sous Linux, vous pouvez éditer le fichier en mode hexadécimal avec vim
etxxd
ou l’outil graphique bless
. Sous Windows, jetez un oeil à frhed. Sous Mac OS, regardez HexEdit. La modification terminée, on ramène le fichier modifié eeprom.new
sur l’équipement. Puis on réécrit l’EEPROM, toujours avec dd
:
# dd if=/tmp/eeprom.new of=/sys/bus/i2c/devices/4-0054/eeprom conv=direct
Ecran bleu sous Linux
Vous pouvez essayer chez vous, c’est sans danger et cela devrait fonctionner. Dans mon cas, j’ai eu droit à une jolie error: permission denied
. Réfléchissons. Nous sommes connectés en tant que root, essayons (naïvement) de changer les droits d’accès:
# chmod 777 /sys/bus/i2c/devices/4-0054/eeprom
# ls -l /sys/bus/i2c/devices/4-0054/eeprom
-rwxrwxrwx 1 root root 0 fév 28 21:57 eeprom
# dd if=/tmp/eeprom.new of=/sys/bus/i2c/devices/4-0054/eeprom conv=direct
error: permission denied
On dirait que cela ne va pas être aussi simple que prévu.
Comment s’en sortir dans ce cas-là?
Avez-vous une idée?
Solution au prochain épisode!
C’est quoi comme EEPROM? c’est quoi le driver?
Ton driver doit être en read-only ou ne pas donner d’API pour write().
ton driver doit être en RO
En effet, et quel outil sortirais-tu dans ce cas-là?