Linux Embedded

Le blog des technologies libres et embarquées

Utilisation de printascii pour la mise au point du noyau Linux/ARM

Lors de la mise au point du noyau Linux sur une cible, il est possible que les messages sur la console (issus de l’utilisation de printk()) n’apparaissent pas car le pilote associé nécessite un meilleur niveau de fonctionnement du noyau. Bien entendu, la sonde JTAG est la meilleure solution mais elle n’est pas toujours disponible.
L’utilisation de early printk permet d’améliorer les choses en permettant l’enregistrement de la console en amont, mais la aussi les résultats dépendent du niveau fonctionnel du noyau en cours de mise au point.
La version ARM du noyau Linux dispose de fonctions très bas niveau permettant de piloter directement le contrôleur série (UART) par des routines en assembleur de quelques lignes, ce qui suffit largement pour la mise au point. La fonction printascii() est définie dans le fichier arch/arm/kernel/debug.S. La compilation de ces fonctions nécessite d’activer l’option Kernel hacking>Kernel low-level debugging functions lors de la configuration du noyau par make menuconfig.
Cette option correspond à CONFIG_DEBUG_LL dans le fichier de configuration .config.
Une fois l’option activée, il est nécessaire de modifier légèrement le code de la fonction printk() afin d’ajouter l’appel à printascii(). La fonction est définie dans kernel/printk.c et il faut ajouter l’appel à printascii() au code de la fonction vprintk() elle-même appelée par printk() .

extern void printascii(const char *);

asmlinkage int vprintk(const char *fmt, va_list args)
{
	...

	/* Emit the output into the temporary buffer */
	printed_len += vscnprintf(printk_buf + printed_len,
				  sizeof(printk_buf) - printed_len, fmt, args);

	//Low level debug
	printascii(printk_buf);

	p = printk_buf;

	/* Do we have a loglevel in the string? */
	if (p[0] == '<') {

      ...
}

Dans l’exemple suivant, un noyau compilé pour la carte ARM Integrator/CP ne fonctionne pas au démarrage et n’affiche aucun message d’erreur malgré l’activation de l’option CONFIG_EARLY_PRINTK dans le menu Kernel hacking>Kernel low-level debugging functions .

$ qemu-system-arm -M integratorcp -m 64 -kernel linux-2.6.33/arch/arm/boot/zImage -initrd rootfs_qemu.gz -append "console=ttyAMA0" -nographic
Uncompressing Linux... done, booting the kernel.
QEMU: Terminated

Si l’on effectue les modifications décrites précédemment, soit la modification de la fonction printk(), on obtient des traces beaucoup plus intéressantes. Nous remarquons que les messages sont préfixés par le niveau d’affichage (exemple: <5>) puisque nous affichons directement le message en l’envoyant à l’UART. A la fin des messages, nous constatons que l’erreur est liée à l’initialisation de la console VGA.

Uncompressing Linux... done, booting the kernel.
<5>Linux version 2.6.33 (pierre@dellpf) (gcc version 4.2.2) #4 Tue Feb 15 15:48:37 CET 2011
CPU: ARM926EJ-S [41069265] revision 5 (ARMv5TEJ), cr=00093177
CPU: VIVT data cache, VIVT instruction cache
Machine: ARM-IntegratorCP
Memory policy: ECC disabled, Data cache writeback
<7>On node 0 totalpages: 16384
<7>free_area_init_node: node 0, pgdat c0317c1c, node_mem_map c0349000
<7>  Normal zone: 128 pages used for memmap
<7>  Normal zone: 0 pages reserved
<7>  Normal zone: 16256 pages, LIFO batch:3
Built 1 zonelists in Zone order, mobility grouping on.  Total pages: 16256
<5>Kernel command line: console=ttyAMA0
<6>PID hash table entries: 256 (order: -2, 1024 bytes)
<6>Dentry cache hash table entries: 8192 (order: 3, 32768 bytes)
<6>Inode-cache hash table entries: 4096 (order: 2, 16384 bytes)
<6>Memory: 64MB = 64MB total
<5>Memory: 59888KB available (2832K code, 286K data, 108K init, 0K highmem)
<6>SLUB: Genslabs=11, HWalign=32, Order=0-3, MinObjects=0, CPUs=1, Nodes=1
<6>Hierarchical RCU implementation.
<6>NR_IRQS:47
<6>I-pipe 1.18-00: pipeline enabled.
<1>Unable to handle kernel paging request at virtual address ee0003da
<1>pgd = c0004000
<1>[ee0003da] *pgd=00000000
<0>Internal error: Oops: 35 [#1]
<0>last sysfs file:
Modules linked in:
CPU: 0    Not tainted  (2.6.33 #4)
PC is at vgacon_startup+0x1c4/0x440
LR is at 0x3df
pc : []    lr : [<000003df>]    psr: 80000153
sp : c0301f88  ip : c0305e64  fp : 00000000
r10: 0001f578  r9 : 41069265  r8 : 0001f5ac
r7 : c0304430  r6 : c0021010  r5 : 00000001  r4 : 00000000
r3 : 00000000  r2 : 00000000  r1 : 00000001  r0 : ee000300
Flags: Nzcv  IRQs on  FIQs off  Mode SVC_32  ISA ARM  Segment kernel
Control: 00093177  Table: 00004000  DAC: 00000017
<0>Process swapper (pid: 0, stack limit = 0xc0300270)
<0>Stack: (0xc0301f88 to 0xc0302000)
<0>1f80:                   00000028 c001fc68 c001fc6c c0021010 c0304430 c0018838
<0>1fa0: c0021010 c0304430 0001f5ac 41069265 0001f578 c001fc68 c001fc6c c0021010
<0>1fc0: c0304430 c0017edc 60000153 c0308d18 c0318270 c0008abc c00084ec 00000000
<0>1fe0: 00000000 c0021010 00093175 c0318518 c0021414 00008034 00000000 00000000
[] (vgacon_startup+0x1c4/0x440) from [] (con_init+0x24/0x288)
...

Si l’on désactive la console VGA (CONFIG_VGA_CONSOLE), le noyau démarre alors correctement. Bien entendu, il est nécessaire de désactiver cette modification lorsque le problème est corrigé car cela génère un grand nombre de traces devenues inutiles.

4 commentaires sur “ Utilisation de printascii pour la mise au point du noyau Linux/ARM ”

  1. Chanteperdrix
    le 25 mars 2011 à 10 h 59 min

    Bonjour Pierre,

    Le coup du printascii dans printk est devenu inutile depuis l’introduction de l'”early printk” sur ARM en discussion depuis à peu près fin janvier 2009. Il est étonnant que CONFIG_EARLY_PRINTK n’ait pas marché dans ton cas, étant donné que l’implémentation de l’early printk revient au même qu’appeler printascii dans le code de printk. As-tu bien pensé à passer “earlyprintk” sur la ligne de commande du kernel? Il y a aussi peut-être aussi un bug sur integrator /CP, car sur les quelques boards auxquelles j’ai accès ça marche, en tout état de cause, ça doit se debugguer au printascii 😉

    Gilles.

  2. Pierre Ficheux
    le 25 mars 2011 à 11 h 49 min

    Il me semble que j’avais testé correctement. Peut-être avais-je oublié l’option…

  3. Ermis
    le 28 mars 2011 à 12 h 04 min

    Tu peux voir l’utilisation de earlyprintk dans /Documentation/kernel-parameters.txt. Pour moi earlyprintk=ttyS0 sur la ligne de commande du kernel suffit.

    • Pierre Ficheux
      le 5 avril 2011 à 17 h 53 min

      Effectivement, Gilles m’en a parlé (voir commentaire précédent). J’avais du oublier l’option.

Répondre à Pierre Ficheux Annuler la réponse.

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *