Linux Embedded

Le blog des technologies libres et embarquées

OpenOCD from scratch

Introduction

Le débogage est une procédure importante dans les processus d'amélioration de la programmation ou de l'équipement, qu'il s'agisse d'un objet commercial, d'une entreprise ou d'une application personnelle. La plupart des projets contiennent un grand nombre de lignes de code, susceptibles de contenir des bogues. Les outils d'investigation ou les débogueurs distinguent les erreurs de codage à différentes étapes.

Cet article est le premier d'une série concernant les outils d'investigation, de trace, de mesure, de débogage. Il est consacré à la description d'une méthode de débogage bas-niveau, le débogage JTAG.

Après avoir exposé quelques généralités, nous présentons le JTAG, ses principes, les signaux. Cependant, exploiter le JTAG nécessite de l'outillage pour contrôler les signaux afférents. Le projet open source le plus connu est nommé OpenOCD, il permet d'interfacer une sonde JTAG avec un environnement de débogage tel que gdb. Nous présenterons en détail OpenOCD, puis un outil permettant de le configurer aisément : OESdebug.

Quelques généralités

La nécessité de déboguer

Le but d'un système d'exploitation est d'offrir à l'utilisateur une interface riche permettant de manipuler la couche matérielle. Cependant, la complexité des besoins actuels (même la loi de Moore est révolue) impose d'avoir des OS plus évolués, robustes et sécurisés.
Pour avoir une idée de la complexité d'un noyau Linux moderne, nous allons utiliser l'utilitaire cloc pour obtenir une vue globale sur l'ensemble des sources linux-4.17.2 :

Linux number lines of code

On peut constater qu'on est face à un système qui évolue depuis 1991, et qui peut être décrit brièvement comme suit :

  • Plus de 16 millions lignes de code.
  • Un nombre important de fichiers (en plusieurs langages) à maintenir.

On se rend compte qu'il est nécessaire d'avoir des outils dédiés pour traquer les bugs qui peuvent se manifester ou même les anticiper.

Comment déboguer un noyau?

Voici les méthodes les plus communes pour déboguer un noyau Linux :

  • KGDB/KDB : Ce sont les débogueurs du noyau Linux (équivalent de GDBserver pour l'applicatif).
  • Les fautes système : le noyau bascule vers cet état lors d'une détection d'erreur, on peut alors récupérer les logs du problème dans le buffer de ce dernier (ces erreurs sont appelées kernel oops), on peut également utiliser les touches magiques SysRQ pour exécuter des fonctions de bas nivaux.
  • Kernel Panic : Les fautes système peuvent rapidement mener à un kernel Panic, kdump et kexec peuvent créer un fichier dump de l'espace virtuel du noyau pour pouvoir l'analyser plus tard (avec un utilitaire comme crash).

Toutes ces solutions sont purement logicielles (Software debug), intuitives et très appréciées dans l'industrie. Cependant, il existe une autre manière qui permet d'accéder au niveau matériel (Hardware debug). Ce type de débogage est considéré comme la méthode la plus puissante (mais aussi la plus complexe).

Le débogage matériel se fait généralement par voie du connecteur JTAG de la cible.

Mais une petite histoire de PCB reste primordiale pour la suite...

A l'assaut des PCB

Un circuit imprimé (PCB) est une carte faite pour connecter des composants électroniques ensemble, on les trouve dans presque tous les équipements d'électronique (voir l'image ci-dessous - source : http://www.robotroom.com/SandwichPCB.html).

PCB board

Les cartes sont faites d'un isolant électrique, généralement en fibre de verre (le processus de fabrication est expliqué sur ce lien : https://www.youtube.com/watch?v=QWuUGm7m4qs).

Après l'étape de la fabrication vient l’étape de test de fonctionnement. Toutes les connectiques du circuit imprimé doivent être testées, cela est devenu laborieux et compliqué (avec les circuits d'aujourd'hui), c'est la raison qui a poussé le standard JTAG à voir le jour.

A retenir

JTAG est une norme de l'industrie pour vérifier les conceptions et tester les cartes de circuits imprimés après leur fabrication.

Au cours des années, l'industrie réalise que JTAG peut être utilisé pour ne pas seulement conduire des tests mais aussi pour déboguer.

Alors comment JTAG peut faire toutes ces choses?

Le JTAG

Où se trouve le connecteur JTAG?

Les connecteurs JTAG sont très variés selon le constructeur et la version des cartes. Il est impératif de consulter la documentation officielle de la plateforme pour le trouver (un exemple de connecteur JTAG est montré ci-dessous - source : https://blog.senr.io/blog/jtag-explained).

Jtag connector
Quelques autres formats de connecteurs JTAG :
- ARM : ARM 10-Pin, ARM 14-Pin
- TI (Texas Instruments ) : TI 14, TI 20-Pin
- et d'autres encore : Xilinx JTAG, Toshiba MIPS, MIPS EJTAG, ..., etc.
Pour plus d'information sur les formats de connecteurs JTAG : http://processors.wiki.ti.com/index.php/JTAG_Connectors ou http://www.jtagtest.com/pinouts/

Mais que représentent toutes ces broches du connecteur JTAG?

Nous devons commencer par comprendre quelques notions de bases liées au JTAG.

Un peu de jargon ne fait pas de mal.

JTAG se décompose principalement en deux parties; les signaux et les registres :

  1. Les signaux JTAG : Le protocole définit 4 signaux obligatoire (voir l'image ci-dessous - source : http://wiki.konilabs.net/en/electronics/standards/jtag) :
    • TCK : l'horloge de fonctionnement.
    • TMS : désigne le prochain état du contrôleur TAP (JTAG est une machine de 16 états, le contrôleur Tap décide vers lequel il faut basculer).
    • TDI : entrée de données de tests.
    • TDO : sortie de données (résultat du test).
    • TRST (optionnel) : permet de réinitialiser le contrôleur JTAG.
  2. Les registres JTAG : on distingue 2 types de registres
    • Registre d'instruction : contient l'instruction à exécuter.
    • Registre de données : JTAG définit 3 différents registres de données (au minimum) :
      • BSR (Boundary Scan Register) : pour tester les entrées et sorties du processeur.
      • BYPASS : registre de 1 bit qui permet de connecter directement les signaux TDI et TDO pour passer au prochain processeur.
      • IDCODE : registre 32 bit qui inclut le code du fabricant, un numéro attribué par ce dernier et un code de version.

      N.B : un cours plus détaillé sur JTAG est disponible sur ce lien : https://www.xjtag.com/about-jtag/jtag-a-technical-overview/

Comprendre Le JTAG en s'amusant

Nous avons fourni une animation qui peut être très utile pour mieux comprendre le JTAG

https://jugurthab.github.io/debug_linux_kernel/jtag-basic-operation.html

Tout ça est bien lourd à comprendre au début, mais surtout manipuler tous ces signaux aux niveaux électrique nécéssite d'un savoir faire particulier. Heureusement pour nous, il existe des logiciels qui permettent de manipuler facilement le JTAG. Certaines des ces solutions peuvent rapidement coûter trop cher (comme : XJTAG), mais la communauté Open Source propose une alternative appelé OpenOCD.

Remarque : Aujourd'hui le JTAG n'est pas la seule interface qui offre un accès physique à la cible, il existe d'autres interfaces telles que SWD (Serial Wire Debug) dédié aux platformes basées sur ARM (SWD utilise 2 broches contrairement à JTAG qui à besoin de 5).

OpenOCD; l'interface open source pour JTAG

OpenOCD est un projet Open Source créé par Dominic Rath (sa thèse est disponible sur : http://openocd.org/files/thesis.pdf). C'est un outil qui permet d'abstraire l'interaction avec le JTAG sans directement manipuler les signaux (TMS, TCK, TDI, TDO, ...,etc).
On peut installer OpenOCD à partir du gestionnaire de paquets des distributions Linux (sudo apt-get install openocd) mais il est toujours préférable de compiler les sources qui sont maintenues sur sourceforge pour avoir la dernière version.

La version d'OpenOCD

Chaque nouvelle version d'OpenOCD supporte plus de cible (par exemple : le fichier de support de Raspberry PI 2 n'est disponible que depuis la version 0.8.0).

Prendre en main OpenOCD

Pour bien démarrer OpenOCD, il faut connaître 3 choses :

Configuration générale d'OpenOCD

Le fonctionnement d'OpenOCD peut se résumer de la manière suivante :

  • L'utilisateur démarre OpenOCD et lui fournit les fichiers de configuration (au minimum l'adaptateur et la cible).
  • Si OpenOCD a bien reconnu l'adaptateur et la cible, on peut lui fournir les instructions à exécuter sur la cible via Telnet ou GDB.
  • OpenOCD affiche dans le stdout (Terminal) la réponse reçue de la cible (la verbosité est configurable).

N.B : par défaut, Telnet démarre sur le port : 4444 et GDB sur le port 3333 (Cela peut être modifié comme on le verra plus tard)

Adaptateur JTAG (JTAG adapter)

L'adaptateur est indispensable car il permettra de transformer les instructions de OpenOCD (logiciel) en signaux électriques pouvant être interprétés par la cible.

Les adaptateurs JTAG sont souvent très coûteux, mais il existe des solutions à bon prix comme les sondes proposées par Olimex. Nous allons utiliser la sonde JTAG arm-usb-tiny-h pour illustrer le fonctionnement d'OpenOCD.

Le header JTAG 2*10 de la sonde Olimex est définit par la connectique suivante :

Compiler les sources OpenOCD

Le protocole de l'adaptateur doit être inclus pendant la compilation des sources, la sonde arm-usb-tiny-h utilise le protocole FTDI.

$ git clone git://repo.or.cz/openocd.git
$ cd openocd
$ ./bootstrap
$ ./configure --enable-ftdi # Inclure le support FTDI
$ make

Remarque : OpenOCD peut déboguer des cibles avec JTAG (le premier protocole supporté par OpenOCD), SWD et SPI.

Structure de OpenOCD

Une fois les sources compilées, observons le contenu du répertoire racine d'OpenOCD et plus précisément le dossier : openocd/tcl (ou /usr/share/openocd/scripts/ si OpenOCD à été installé sur le système) comme le montre la figure suivante:

OpenOCD folders

Le contenu peut se diviser en 3 parties :

  • interface : contient les fichiers de configuration de l'adaptateur (aussi appelé dongle).
  • target : on trouve les fichiers de configuration des différents processeurs ou dsp.
  • board : définit la configuration de toute la plateforme (cpu, dsp et les mémoires comme SDRAM ou FLASH), les fichiers de ce dossier incluent généralement ceux du dossier target (c'est une bonne pratique pour réutiliser du code).

Utilisation de OpenOCD

Pour consulter la liste des commandes proposées par OpenOCD, il suffit de se positionner sur le dossier racine des sources et lancer :

$ openocd -h

Une liste d'option est proposée par OpenOCD :

  • version (-v) : renvoie la version of OpenOCD
  • file (-f) : indique à OpenOCD l'emplacement d'un fichier de configuration.
  • debug (-d) : par défaut, OpenOCD affiche le minimum d'information mais en cas de problèmes, il est préférable d'augmenter la verbosité.
  • log_output (-l) : on peut rediriger le résultat de OpenOCD vers un fichier, ce qui est très utile pour avoir de l'aide en cas d'erreurs (il faut penser à utiliser l'option -d).
  • command (-c) : on peut fournir rapidement certaines instructions à la cible sans modifier les fichiers de configuration (utilisé pour les tests).

Démarrer OpenOCD

La commande générale pour lancer OpenOCD (à partir du dossier racine des sources) est la suivante :

$ sudo ./src/openocd -f tcl/interface/fichier_config_adaptateur \
> -f tcl/dossier_target_ou_board/fichier_configuration_cible

Comme on peut le constater, OpenOCD à besoin de deux fichiers au minimum :

  • tcl/interface/fichier_config_adaptateur : emplacement du fichier de configuration de l'adaptateur
  • tcl/target_ou_board/fichier_configuration_cible : emplacement du fichier de configuration de la cible.

Bonne pratique pour démarrer OpenOCD

Parfois, certains fichiers ont besoin d'en charger d'autres, il faut alors indiquer à OpenOCD où les trouver (il suffit d'ajouter le chemin du dossier tcl) en ajoutant l'option -s comme suit :

$ sudo ./src/openocd -s tcl/ -f tcl/interface/fichier_config_adaptateur \
  -f tcl/target_ou_board/fichier_configuration_cible

Recommandation : il est toujours préférable d'inclure l'option -s (c'est souvent une source d'erreur).

Ce qu'il faut savoir sur OpenOCD

Lancement de OpenOCD

Si aucun des paramètres -f (ce paramètre indique où se trouvent les fichiers de configuration) ou -c n'est fourni , OpenOCD va chercher un fichier "openocd.cfg" dans les endroits suivants :

  • Le dossier courant.
  • Le dossier précisé avec -s (si ce paramètre est indiqué).
  • dans le $HOME/openocd.cfg.

Mode verbeux de OpenOCD

OpenOCD peut avoir des difficultés à communiquer avec la cible (généralement à cause de problèmes de broches mal connectées), il est important d'activer ce mode pour pouvoir essayer de détecter la source du problème.

Pour utiliser le mode verbosité (une valeur entre 0 et 3) :

$ ./src/openocd --debug 3

Remarque : il ne faut pas oublier que dans ce cas, OpenOCD va chercher un fichier "openocd.cfg".

Quelques exemples de configuration

Configuration pour un STM32F407 - supportée par OpenOCD -

Le fichier de configuration du STM32F407 est déjà existant dans OpenOCD, il suffit juste de :

    • Connecter la cible (STM32F407) avec l'adaptateur : Cette étape est généralement la première raison de l'échec du débogage, il est impératif de la mener à bien.
      Pin ARM-USB-TINY-H Pin STM32F407
      1 (VREF) VDD (P1)
      3 (nTRST) PB4 (P2)
      4 (GND) GND (P1)
      5 (TDI) PA15 (P2)
      7 (TMS) PA13 (P2)
      9 (TCK) PA14 (P2)
      13 (TDO) PB3 (P2)
    • Lancer OpenOCD : On peut démarrer OpenOCD en lui indiquant l'emplacement du fichier de configuration de l'adaptateur (olimex-arm-usb-tiny-h.cfg) et de la cible (stm32f4x.cfg) :
$ sudo ./src/openocd -s tcl/ -f tcl/interface/ftdi/olimex-arm-usb-tiny-h.cfg -f \
> tcl/target/stm32f4x.cfg

La commande devra retourner un résultat semblable à l'image suivante :

STM32-detected by OpenOCD

Si la ligne "hardware has 6 breakpoints, 4 watchpoints" est présente alors OpenOCD a réussi à détecter la cible.

Rappel

OpenOCD affiche les ports de telnet et GDB (si cela est mentionné dans les fichiers de configuration), mais parfois cela n'est pas le cas. On peut alors considérer que telnet et GDB écoutent sur les port : 4444 et 3333 respectivement.

 

Remarque : Il est aussi possible de démarrer gdb et telnet sur d'autres ports (notamment si les ports par défaut sont déja occupés) avec l'option -c :

$ sudo ./src/openocd -s tcl/ -f tcl/interface/fichier_adapteur -f tcl/target/target_fichier \
> -c "gdb_port 7777" -c "telnet_port 8888"

Déboguer la cible

OpenOCD accepte des connexions telnet ou GDB comme illustré ci-dessous :

  • GDB : il ne faut pas oublier d'utitiser un GDB compatible avec la cible
    • Se connecter à la cible : GDB à besoin de l'image du noyau cible (compilé avec les symboles de débogage) :
$ sudo gdb vmlinux_avec_symbole_de_debogage -q
  • Arrêter la cible : il est important d'arrêter la cible, cela permet à OpenOCD de placer la plateforme en mode débogage pour pouvoir l'inspecter (voir l'image ci-dessous).
    Halt target using GDB
  • Obtenir l'état des registres : On peut dumper le contenu des registres à tout moment (voir l'image ci-dessous).
  • Telnet : Nous allons utiliser putty
    • Se connecter à la cible : les paramètres suivants seront utilisés avec putty :
      telnet configuration
    • Arrêter et obtenir l'état des registres : encore une fois, il faut toujours arrêter la cible avant d'aller plus loin comme le montre la figure ci dessous :
      Halt and dump register contents Telnet

Remarque

Il faut arrêter la cible, dans le cas contraire OpenOCD ne sera pas en mesure de l'inspecter (comme le montre la figure ci-dessous)

Cannot access registers after reset

On voit clairement que le contenu des registres ne peut plus être lu.

Configuration pour une Raspberry PI 3 - non supporté par openOCD -

Cette configuration n'est pas encore disponible en standard avec OpenOCD, et, de plus, nous avons besoin de configurer les ports de la Raspberry PI avant d'utiliser OpenOCD.

Raspberry PI 3 est une plate-forme intéressante, mais déboguer en JTAG nécéssite quelques ajustements.

  1. Connecter la raspeberry PI 3 avec la sonde ARM-USB-TINY-H : (voir le tableau ci-dessous).
    Pin ARM-USB-TINY-H GPIO Raspberry PI 3
    1 (VREF) 1 (DC Power)
    3 (nTRST) 15 (GPIO22)
    4 (GND) 9 (GROUND)
    5 (TDI) 7 (GPIO4)
    7 (TMS) 13 (GPIO27)
    9 (TCK) 22 (GPIO25)
    11 (RTCK) 16 (GPIO23)
    13 (TDO) 18 (GPIO24)

    et voici une illustration du schéma après le branchement :

  2. Activation du débogage JTAG sur Raspberry PI 3 : par défaut, les ports de la Raspberry PI ne sont pas configurés pour accepter les connnnexions JTAG. La procédure disponible sur : https://sysprogs.com/VisualKernel/tutorials/raspberry/jtagsetup/ fournit une solution au problème. Cependant, quelques changement doivent être apportés au programme pour le faire fonctionner sur Raspberry PI 3.
#define BCM2708_PERI_BASE 0x3F000000
#define GPIO_BASE (BCM2708_PERI_BASE + 0x200000)
  • Compiler le programme : une fois les modifications effectuées, on peut compiler :
$ g++ -o JtagEnabler JtagEnabler.cpp
  • Exécuter le programme sur Raspberry PI : une fois exécuté, le débogage JTAG sera disponible sur la Raspberry PI 3.
    Enable JTAG on Raspberry PI 3
  1. Obtenir le fichier de configuration OpenOCD bcm2837 :
    Le SoC de la Raspberry PI 3 est un Broadcom bcm2837, mais OpenOCD n'a pas de fichier de configuration pour ce dernier. AZO234 a déjà écrit les fichiers de configuration pour ce genre de processeurs. Les fichiers sont disponibles sur le lien suivant:

    https://github.com/AZO234/RaspberryPi_BareMetal/tree/master/rp_jtagenable/cfg/ARMv8

    Téléchargez le fichier compatible avec votre Raspberry PI 3, et copiez-le dans le dossier "target" de OpenOCD

  2. Démarrer OpenOCD : maintenant, nous avons toutes les pièces nécessaires pour OpenOCD :
$ sudo ./src/openocd -s tcl/ -f tcl/interface/ftdi/olimex-arm-usb-tiny-h.cfg -f tcl/target/bcm2837_64.cfg

La commande retourne le résultat suivant :

Debugging Rasberry PI 3 OpenOCD
  1. Démarrer telnet ou GDB : OpenOCD reçoit les commandes à exécuter sur la cible avec Telnet ou GDB.
    Voici un exemple avec telnet, nous devons configurer putty comme suit :
    • adresse IP : 127.0.0.1
    • Port : 4444
    • Type de connexion : Telnet

    En cas de réussite de connexion, le message "Open On-Chip Debugger" sera affiché. Nous devons arrêter l'exécution de la cible avant de poursuivre l'opération (voir l'image ci dessous).
    debugging raspberry pi with openOCD telnet

Création de fichiers de configuration OpenOCD pour de nouvelles cibles

Dans ce paragraphe, nous détaillons comment configurer une cible qui n'est pas supportée par OpenOCD.

Nous devons rappeler que OpenOCD utilise une approche modulaire pour organiser les fichiers. Les fichiers target contiennent la configuration concernant le chip (cpu, dsp, FPGA, ..., etc) et les fichiers board regroupent tous les paramètres d'une carte (y compris les fichiers target, configuration Flash et d'autres options spécifiques à la carte).

Pour créer de nouveaux fichiers OpenOCD nous devons écrire le fichier target puis le fichier board.

N.B : les commentaires sont définis par # dans OpenOCD.

Fichier target

OpenOCD a besoin de connaître les détails de notre SoC (CPU, DSP, ..., etc.). La création d'un fichier de configuration target peut être fait en 6 étapes :

Définir le nom du SOC : Techniquement, il est suffisant d'indiquer à OpenOCD le nom de notre chip comme ceci :

# indique le nom du chip (CPU, DSP, ..., etc)
set _CHIPNAME stm32f0407

Cepandant, on doit respecter une convention; les noms de variable d'un fichier target peuvent être écrasés et réécrits par un fichier board (qui les inclut) et donc la syntaxe à suivre est la suivante :

# indiquer le nom du chip (CPU, DSP, ..., etc) avec vérification de réécriture par le fichier board
if { [info exists CHIPNAME] } {
set _CHIPNAME $CHIPNAME
} else {
set _CHIPNAME stm32f0407
}

La condition if{ [info exists CHIPNAME] } vérifie si le fichier board a fournit une nouvelle valeur pour le nom, si c'est le cas on doit l'utiliser sinon on garde celle qui est définit dans le fichier target (dans notre cas stm32f0407). Remarque : les variables qui commencent par "_" (exemple : _CHIPNAME) designent des variables temporaires qui peuvent être réécrites par un fichier board.

Boutisme (endianness) : il faut indiquer l'organisation des octets :

#little ou big endian? OpenOCD considére little endian par défaut
if { [info exists ENDIAN] } {
set _ENDIAN $ENDIAN
} else {
set _ENDIAN little
}

Important : si ce paramètre n'est pas indiqué, OpenOCD considère le boutisme "little indian" par défaut.

Indiquer le TAP ID : Ce paramètre est facultatif mais peut aider lorsque la cible possède plusieurs chips (architecture SMP) :

# Tap ID controller (facultatif)
if { [info exists CPUTAPID] } {
set _CPUTAPID $CPUTAPID
} else {
set _CPUTAPID 0x4ba00477
}

Créer une instance d'un TAP ID : La syntaxe générale pour déclarer un nouveau processeur est la suivante :

jtag newtap $_CHIPNAME chip_type -irlen length -expected-id $_CPUTAPID
  • jtag newtap $_CHIPNAME : définition d'un nouveau contrôleur TAP .
  • chip_type : représente l'objet pouvant être débogué par le contrôleur TAP (cpu, dsp).
  • -irlen length (instruction register length) : taille du registre d'instruction (JTAG).
  • -expected-id $_CPUTAPID : force OpenOCD à controler le TAP ID pour vérifier qu'on débogue le bon processeur (utile pour différencier des processeurs dans un environement SMP).

Voici l'exemple de notre carte cible :

#create a tap ID controller
jtag newtap $_CHIPNAME cpu -irlen 4 -expected-id $_CPUTAPID

Pour OpenOCD cela veut dire : "il existe un contrôleur TAP avec un ID ($_CPUTAPID) que je doit vérifier. Ce contrôleur débogue un CPU qui se nomme $_CHIPNAME, la taille du registre d'instruction est 4".

Créer une instance du SOC : il faut aussi définir le type du chip :

target create $_TARGETNAME architecure -chain-position $_TARGETNAME
  • target create $_TARGETNAME : définit un nouveau processeur, dsp, ..., etc.
  • architecure : désigne l'architecure du processeur : avr, cortex_m, arm11, ..., etc.
  • -chain-position $_TARGETNAME : pointe vers le TAP qui contrôle ce processeur.

Par exemple :

set _TARGETNAME $_CHIPNAME.cpu
target create $_TARGETNAME cortex_m -chain-position $_TARGETNAME

Configuration de la mémoire interne-SDRAM (étape optionnelle) : certains processeurs peuvent utiliser une mémoire interne (onchip memory) :

$_TARGETNAME configure -work-area-phys 0x00200000 -work-area-size 0x8000 -work-area-backup 0
  • $_TARGETNAME configure : déclarer une SDRAM
  • -work-area-phys début_adresse : indique le début d'adresse de la SDRAM
  • -work-area-size taille : quantité de mémoire disponible à partir du début d'adresse (-work-area-phys)
  • -work-area-backup oui_ou_non : indique si la SDRAM peut avoir une sauvegarde

Comprendre La syntaxe OpenOCD en s'amusant

Une animation est disponible sur :
https://jugurthab.github.io/debug_linux_kernel/zero-to-hero-openocd.html

Fichier Board

  1. Définir la vitesse de communication de l'adaptateur : Il est préférable de consulter le site du constructeur.

    Remarque : généralement une vitesse minimale de 8 KHz est utilisée en cas d'incertitude ou de difficulté à obtenir ce paramètre.

  2. Inclure le fichier target : comme déja mentionné, le fichier Board reprend le fichier (ou les fichiers si plusieurs processeurs existent sur la cible) target et l'inclut comme montré ci-dessous :
    source [find my-custum-script-target.cfg]

    On peut ajouter plus de fichiers target (autant qu'il y'a de chips sur la platforme).

  3. Configurer la mémoire Flash : Après avoir ajouté le fichier target, on peut configurer la mémoire flash et l'initialiser.
    1. Identifier la technologie mémoire FLASH : jusqu'à présent, OpenOCD supporte 3 types de mémoire Flash; Nor, Nand, mFlash.
    2. Lorsque le type de la mémoire est identifié : il suffit de recopier la commande de configuration de la mémoire Flash du manuel d'utilisation d'OpenOCD (les commandes sont organisées selon le driver utilisé par la mémoire Flash).

    Dans notre cas, la carte possède une mémoire Flash de type Nor interne, le driver associé est : stm32f2x. le manuel OpenOCD propose la ligne qu'on doit ajouter.

    flash bank $_FLASHNAME stm32f2x 0 0 0 0 $_TARGETNAME

    Cependant, on doit toujours garder la convention d'OpenOCD et permettre à nos variables d'être modifiées lorsque nos fichiers sont inclus dans d'autres, on doit toujours écrire :

#declare the nor flash mapping
set _FLASHNAME $_CHIPNAME.flash
flash bank $_FLASHNAME stm32f2x 0 0 0 0 $_TARGETNAME

Les sources sont disponibles sur : https://github.com/jugurthab/Linux_kernel_debug/tree/master/debug-examples/Chap5-JTAG-OpenOCD-Debug/stm32f2x-OpenOCD-File-From-Scratch

OESdebug, une interface de configuration pour openOCD

OpenOCD est assez ardu à prendre en main et demande de la pratique, OESdebug est un générateur de script OpenOCD. Nous allons l'utiliser pour ajouter un nouveau SoC (fichier target d'un avr AT32UC3C-EK) qui n'existe pas sous OpenOCD.

Les sources OESdebug

OESdebug est disponible sur ce lien : https://github.com/jugurthab/Linux_kernel_debug/tree/master/DebugSoftware/OpenOCD-wrapper

Prendre en main OESdebug

  • Détection d'OPENOCD : OESDebug est un programme wrapper sur OpenOCD, la première étape est d'essayer de détecter ce dernier (voir l'image ci-dessous).
    OESDebug detecting OpenOCD

    Si OpenOCD à été compilé à partir des sources, on doit indiquer à OESdebug le dossier root des sources.

  • Support d'adaptateur : il suffit de sélectionner notre dongle dans la liste (voir l'image ci-dessous).
    OESdebug select adapter interface
  • Support Target et Board : AT32UC3C-EK n'existe pas dans OpenOCD, nous devons le créer. il suffit de renseigner les champs demandés (voir l'image ci-dessous).
    OESdebug - Create new Target file

    Important : Les champs "IR" et "CPU TAP ID" peuvent être découverts par une option offerte par OpenOCD (Autoprobe feature), avec OESdebug, il suffit d'aller dans le menu "Tools" puis "Discover TAP ID"

    N.B : Il est possible de configurer la SDRAM et la mémoire Flash en cochant la case "Enable Memory Config"

  • Génération du fichier config : Il suffit de cliquer sur le bouton "Generate File" pour générer le fichier de configuration (voir l'image ci-dessous).
    OESdebug - Generate OpenOCD configuration files
  • Brancher la carte cible avec l'adaptateur : Nous devons connecter le dongle et la carte cible comme suit :
    Pin ARM-USB-TINY-H Pin AT32UC3C
    1 (VREF) 7 (VSUPP)
    3 (nTRST) 8
    4 (GND) 2
    5 (TDI) 9
    7 (TMS) 5
    9 (TCK) 1
    13 (TDO) 3

    Remarque : la datasheet du "AT32UC3C-EK" est disponible sur ce lien http://www.farnell.com/datasheets/1511964.pdf

  • Lancer OpenOCD : Aprés la génération du fichier de configuration, on peut démarrer OpenOCD (en cliquant sur le boutton "Start OpenOCD").

Quelques options de OESdebug

  • La fonction Autoprobe : OpenOCD permet de récupérer le "TAP ID" et la taille du registre d'instruction. En effet, ces derniers sont parfois difficiles à obtenir. OESdebug nous permet d'utiliser cette fonctionnalité en toute simplicité.
    1. Connecter la cible et le dongle.
    2. Choisir le fichier de configuration du dongle (voir l'image ci-dessous).
      set adapter before autoprob dicovery - oesdebug
    3. Dans le menu "tools", choisir "Dicover TAP ID".
    4. Récupérer le TAP ID : OpenOCD renvoie le résultat (voir l'image ci-dessous).
       

    Dans l'exemple ci dessus, OpenOCD a identifié deux TAP ID (0x4ba00477 et 0x06413041). OpenOCD nous propose même comment intégrer ces informations dans un script OpenOCD.

    Enfin, pour permettre à OpenOCD de dialoguer avec le contrôleur TAP (qui posséde un ID 0x4ba00477), on doit écrire :

    jtag newtap auto0 tap -irlen 4 -expected-id 0x4ba00477
    

    Mais il faut toujours suivre les conventions des script OpenOCD et bien nommer ses variables comme suit:

    jtag newtap $_CHIPNAME tap -irlen 4 -expected-id $_CPUTAPID
    

     

    Important : La fonction autoprobe nécéssite la présence du signal RCLK pour fonctionner.

  • Partager les scripts générés : les scripts obtenus avec OESdebug peuvent être partagés. L'onglet "Config File" permet d'enregistrer les fichiers de configuration obtenus.
    Ensuite, il faut choisir le dossier où les fichiers seront sauvegardés (il est recommandé de laisser le répertoire par défaut "savedConfig") puis de cliquer sur "Save file". l'opération produira deux fichiers :
    • cfg : est le fichier de configuration qui peut être utilisé avec OpenOCD.
    • oes : pour repopuler l'interface graphique avec la configuration exacte qui a été faite pour produire le fichier cfg.

    On peut désormais partager nos fichiers (.cfg et .oes). Pour charger les fichiers dans OESdebug, il suffit d'aller dans l'onglet "OpenOCD support" et de sélectionner "Load config" et choisir le fichier cfg (le fichier oes sera chargé au même temps).

Conclusion

Cet article nous a permis de découvrir le débogage JTAG avec OpenOCD. Nous avons appréhendé son utilisation ainsi que la création de fichiers de configuration from scratch. Il existe d'autres manières de déboguer un noyau Linux que nous couvrirons dans d'autres articles. L'outil OESdebug permet de faciliter la configuration de OpenOCD, il est encore jeune, nous vous invitons donc à proposer des axes d'améliorations, des corrections pour cet outil.

Enfin, si vous configurez de nouvelles interfaces, n'hésitez pas à partager votre travail auprès d'OpenOCD.

 

    • le 23 novembre 2018 à 16:22

      […] C’est la méthode de débogage la plus puissante (mais la plus complexe) car, à la différence des autres solutions (qui sont purement logiciel), c’est un débogage au niveau matériel (JTAG, SWD et autres). OpenOCD est une solution Open Source qui nous permet de mener un débogage matériel, un article entier lui a été réservé sur : http://www.linuxembedded.fr/2018/08/openocd-from-scratch/. […]

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée.