Tutoriel:liaison Jtag avec OpenOCD

De Le Glitch Wiki
Aller à : navigation, rechercher

descriptif

Technologies : FTDI 232H + OPENOCD+ARM AT91SAM7
Initiateur du projet : Joss
Contributeurs : Joss
Date de début : Juin 2017
Date de dernière mise à jour : Juin 2017

résumé

Voila comment, de l'achat d'un proxmark V3 en chine afin d'explorer le monde merveilleux du RFID, l'auteur se retrouva à arpenter les contrées arides du JTAG afin de reprogrammer un composant qu'il avait mis en panne après une mise à jour hasardeuse...
Dans ce tutoriel, on parlera donc du JTAG (sommairement, les possibilités du JTAG étant trop étendues pour un simple tuto), des interfaces de programmation (au niveau matériel, ce sera en prenant le composant générique FTDI FT232H. Au niveau logiciel, en utilisant OpenOCD) et enfin, votre serviteur vous fournira un script tout fait, dans le cas où vous voudriez suivre ses pas.

En route pour l'aventure :)

LE JTAG: kesako?

pourquoi le jtag?

Pour faire un résumé simpliste, le jtag, c'est une méthode de liaison vers les composants, ainsi qu'une architecture et une logique intégrée à ces derniers, qui a remplacé les sondes (alias "lits à clous") dans le test des cartes électroniques.
Au fur et à mesure de la généralisation de l'électronique numérique, du passage des composants traversants aux composants montés en surface avec du multi-pistes (parfois avec des points de soudure cachés comme c'est le cas pour les composants dits "Chip Scale Packaging" "BGA" ou autre 3D Flip chip), la miniaturisation et du passage à des fréquences de composants ultra rapides, un protocole de test normalisé devenait indispensable.

et là, comment je fais pour tester ma liaison CPU <-> memoire?



fonctionnement

registres JTAG (source XJTAG.com)

JTAG fournit une méthode pour accéder aux valeurs qui seraient sur les broches. La figure à droite montre que, en plaçant des « cellules JTAG » entre la broche et la logique interne de la puce, configurées comme registre à décalage, le système JTAG peut définir et récupérer les valeurs des broches sans accès physique direct.

Il y a également une option pour observer simplement le débit des données entre les broches et la logique interne du composant au cours du fonctionnement normal de la puce.

L’interface JTAG se connecte à quatre broches sur chaque circuit intégré, dont TDI pour l’entrée des données vers la puce, TDO pour la sortie des données de la puce, TMS pour contrôler ce qui doit être fait avec les données et finalement TCK, un signal d’horloge pour synchroniser le processus.

Pour qu’un dispositif soit considéré compatible JTAG, il faut que le fabricant fournisse un fichier BSDL (Boundary Scan Description Language) qui décrit le fonctionnement des aspects JTAG de la puce.
Et c'est là où se trouve la finesse: chaque fabricant peut faire ce qu'il veut.

Dans le cas où un PCB ou système contient plus d’un composant JTAG, ceux-ci peuvent être reliés entre eux pour former une « chaîne JTAG ». Dans une chaîne, la sortie de données du premier dispositif devient l’entrée de données au second dispositif. Le signal d’horloge et celui de contrôle sont communs à tous les dispositifs dans la chaîne. La figure suivante donne une représentation d’une chaîne contenant trois composants JTAG.

chaine JTAG


Pour plus de précisions sur ce qu'est le JTAG, je vous laisse suivre ce deux liens:



composant matériel d'interfaçage

Une carte FTDI 232 de chez Adafruit

Pour pouvoir exploiter les possibilités du JTAG, il va falloir une interface. Et là, c'est la foire. Entre les solutions propriétaires qui vont d'une centaine à plusieurs milliers d'euros pour une seule famille de composant et les "génériques", voire les bricolés maisons. Au final , le signal JTAG étant une suite de 0 ou de 1 sur quelques pattes, on peut faire ce qu'on veut (c'est le cas du "bitbanging", où un composant qui ne "parle" pas le JTAG va se retrouver piloté pour ça, comme l'arduino). En bref, on a l'embarras du choix (le lecteur pourra trouver un large choix d'interface et de scripts à cette adresse : Jtag par CuVoodoo. On n'aura pas forcement les mêmes possibilités en fonction surtout de la vitesse de fonctionnement du composant d'interfaçage contre les composants à joindre (simulation d'état, examen temps réel), mais pour l'objectif de ce tuto, un composant simple fera l'affaire. C'est le cas du FT232H qu'on peut trouver pour la modique somme de 10€ sur tout bon site en ligne (Ce n'est d'ailleurs pas la seule manière de s'en servir. Ce petit bijou prend en charge de nombreux protocoles I²C,SPI,UART, etc... DS_FT232H.pdf).


Pour le cas qui nous occupe, sur n'importe quelle carte, ou adaptateur, à base de FT 232H, le branchement doit respecter le plan suivant:

Pin No. Name Pin Name MPSSE Configuration Description
13 TCK/SK AD0 JTAG - TCK, Test interface clock
14 TDI/DO AD1 JTAG – TDI, Test Data Input
15 TDO/DI AD2 JTAG – TDO, Test Data output
16 TMS/CS AD3 JTAG – TMS, Test Mode Select

Reste à connecter l'alimentation en respectant le voltage. Présents sur les adaptateurs, vérifiez bien que le voltage est compatible avec le matériel. En rêgle général, le voltage pour les Pins JTAG sont à 3,3V. Parfois, 1,8V, parfois5V.
Une erreur et il vous reste vos yeux pour pleurer...
Afin d'éviter ce genre d'ultime galère, on peut brancher directement le matériel avec son alimentation.

composant logiciel d'interfaçage

Encore une fois, il existe de nombreuses solutions.
Les solutions propriétaires permettent d'exploiter toute la puissance des interfaces idoines pour effectuer les boundary scans, la programmation et toutes les interactions temps réel possible. Cependant, au delà du coût, la plupart des logiciels proposés par les fondeurs permettent de dialoguer avec les composants de ce dernier.
Bien dommage, surtout quand sur une même chaine JTAG se trouvent 3 composants.

Heureusement, le monde du libre vient à la rescousse de l'amateur éclairé comme du programmeur chevronné grâce à OpenOCD pour Open On Chip Debugging.
Je ne vais pas vous le cacher, ce programme est une mine tout autant qu'un supplice et il suffit de se plonger dans sa documentation pour avoir le tournis. Oui, il est possible de faire pleins de choses avec, mais tout d'abord, il faut comprendre comment il fonctionne.

Suite à rédiger

how-to-use-the-gdb-gnu-debugger-and-openocd-for-microcontroller-debugging-fr

application du blabla précédent au problème du proxmark 3

Pour que ce soit clair, et avant de parler du jtag pour le proxmark, une petite description de ce qui est présent sur la bête s'impose:

proxmark 3, l’outil RFID pour pentest et expertise

En gros, avec le proxmark, on peut analyser n'importe quel type de carte RFID fonctionnant sur les fréquences 13,56 Mhz et 125/134KHz. Quand le type de carte est connu, c'est un vrai boulevard. Quand le type est inconnu, on peut réaliser de l'analyse de protocole avec. Ce matériel est bien suivi par une communauté de passionnés de sécurité (http://www.proxmark.org/forum/index.php) et il n'est pas rare que des firmwares spécifiques sortent afin d'exploiter certaines possibilités du matériel (lecture et replay offline de tags, brute-force autonome.. ).

sous le capot de la bête, il y a:
- CPU : ARM, 512K (AT91SAM7S512) of flash memory, 64kB of RAM
- FPGA : Xilinx Spartan-II

C'est ce premier composant qui va nous intéresser pour la procédure de mise à jour. En effet, en temps normal, l'ARM possède un bootloader qui permet de prendre en charge le port usb et le processus de mise à jour par ce biais.
En cas d'erreur, adieu port USB, bonjour galère. Sauf quand on peut passer par le JTAG pour "pousser" le firmware dans la bonne zone mémoire et ainsi redonner ces possibilitées au composant.
L'exploration des possibilités de l'ARM SAM7, des zones mémoires et des dizaines de thématiques associées à ce composant est un vrai casse-tête / bonheur, mais ce n'est pas le thème de ce tuto. N'hésitez pas à être curieux et à explorer...

et maintenant, on agite le tout ...

/!\ Attention /!\
Mais pourquoi y a-t-il des dièses partout dans ce chapitre?
Et bien, comme je suis un gars sympa, je vous ai préparé une explication que vous pouvez copier/coller dans notepad++ et enregistrer sous forme d'un .CFG pour l’exécuter ensuite avec openOCD.

#On va créer un .CFG spécifique à notre matériel:
#Pour cela on va créer un fichier nommé MaConfig.cfg avec notepad++
#et le placer dans le même répertoire que openocd (méthode sale)
#ou le placer dans le repertoire comportant les scripts (Scripts\interface\ftdi\)

#tout d'abord, ouvrir un port telnet et gdb
#(ce dernier n'est pas utile dans le cas actuel)
# General OpenOCD configuration
# Ports
telnet_port 4444
gdb_port 3333

#ensuite on utilise le FT232H pour servir d'interface jtag
#module FT232H
echo "configuration du ftdi FT232H"
interface ft2232
ft2232_device_desc "Single RS232-HS"
#pour la partie suivant les VID et PID sont standard au composant FTDI
ft2232_vid_pid 0x0403 0x6014
ft2232_layout "usbjtag"
adapter_khz 2000

#enfin, on déclare le matériel qui est en face et la manière de lui parler
#pour ça, on utilise le .cfg correspondant au composant
#dans notre cas, un sam7x256 que l'on peut aussi bien déclarer en sam7x512
#On pourrait s'arrêter là et lancer la commande suivante
#C:\OpenOCD\bin>openocd.exe -f C:\OpenOCD\share\openocd\scripts
#\interface\ftdi\FT232H.cfg -f  C:\OpenOCD\share\openocd\scripts\
#target\at91sam7x512.cfg
#mais on va intégrer la logique dans notre fichier .cfg, comme suit

echo "connexion jtag avec le composant sam7"

#use combined on interfaces or targets that can't set TRST/SRST separately
reset_config srst_only srst_pulls_trst

if { [info exists CHIPNAME] } { 
set  _CHIPNAME $CHIPNAME 
} else { 
set  _CHIPNAME sam7x512
}
if { [info exists ENDIAN] } { 
set  _ENDIAN $ENDIAN} else { 
set  _ENDIAN little 
}
if { [info exists CPUTAPID] } { 
set _CPUTAPID $CPUTAPID
} else {
set _CPUTAPID 0x3f0f0f0f
}

jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID

set _TARGETNAME $_CHIPNAME.cpu
target create $_TARGETNAME arm7tdmi -endian $_ENDIAN -chain-position $_TARGETNAME

$_TARGETNAME configure -event reset-init { 
# disable watchdog
mww 0xfffffd44 0x00008000
# enable user reset
mww 0xfffffd08 0xa5000001
# CKGR_MOR : enable the main oscillator
mww 0xfffffc20 0x00000601
sleep 10
# CKGR_PLLR: 96.1097 MHz
mww 0xfffffc2c 0x00481c0e
sleep 10
# PMC_MCKR : MCK = PLL / 2 ~= 48 MHz
mww 0xfffffc30 0x00000007
sleep 10
# MC_FMR: flash mode (FWS=1,FMCN=60)
mww 0xffffff60 0x003c0100
sleep 100
}

$_TARGETNAME configure -work-area-phys 0x00200000 -work-area-size 0x4000 -work-area-backup 0

#flash bank <driver> <base_addr> <size> <chip_width> <bus_width> <target_number> [<target_name> <banks> <sectors_per_bank><pages_per_sector> <page_size> <num_nvmbits> <ext_freq_khz>]
set _FLASHNAME $_CHIPNAME.flash
flash bank $_FLASHNAME.0 at91sam7 0 0 0 0 $_TARGETNAME 0 0 0 0 0 0 0 18432
flash bank $_FLASHNAME.1 at91sam7 0 0 0 0 $_TARGETNAME 1 0 0 0 0 0 0 18432

Branchez votre module FT232 sur le port JTAG du proxmark, puis le FT232 sur l'ordinateur. Le proxmark démarre, alimenté par le port JTAG
Une fois les pilotes du FT232 correctement installés, il est possible d'utiliser OpenOCD. Si vous avez placé votre .cfg dans le même répertoire que OpenOCD, on peut désormais utiliser la commande:

OpenOCD -f MaConfig.cfg

ou utiliser la même commande en indiquant le chemin absolu vers notre .cfg.
OpenOCD se lance, ouvre un port telnet et liaison GDB (pas utile pour nous), reconnait l'interface et le composant. Cependant, si on reste sur cette fenêtre, on ne peut rien faire.
On va utiliser un client telnet pour lancer des commandes

telnet localhost 4444

la fenêtre OpenOCD fait apparaitre le message suivant : accepting 'telnet' connection on tcp/4444

Youpi, on continue

/!\ on se place désormais dans l'interface telnet /!\
Toutes les commandes entrée sur l'interface telnet sont recus par openocd, transformées pour correspondre à la logique du composant ARM et envoyées via le FT232H. Pour plus de clarté, j'ai ajouté la mention <Telnet> devant chaque ligne devant être saisie dans la fenêtre correspondante.
Dans le cas du proxmark, on va commencer par suspendre tous les processus:

<Telnet> halt

On va effacer certaines zones mémoire du composant afin d'implanter sans problème le bootloader et le fullimage

<Telnet> flash erase_sector 0 0 15
<Telnet> flash erase_sector 1 0 15

Puis on va implanter le nouveau firmware.
Le chemin est relatif par rapport à l'éxécutable OpenOCD, même si on passe par la fenêtre telnet, donc placez bien vos fichiers

<Telnet> flash write_image ./armsrc/obj/fullimage.elf
<Telnet> flash write_image ./bootrom/obj/bootrom.elf

Et voila !