comment accéder et déboguer une arborescence FDT / DTS à partir d’un pilote Linux (seg-fault)

J’ai écrit un module kernel Linux pour agir comme pilote FPGA pour une carte personnalisée basée sur le Freescale P2020RDB. Le pilote contient plusieurs #defines pour spécifier différentes adresses, tailles, largeurs de bus, etc. Je souhaite accéder à l’arborescence FDT (Flattened Device Tree) du pilote pour configurer ces adresses, afin que le pilote puisse être utilisé pour d’autres cartes , où le FPGA a des tailles différentes ou réside à des adresses différentes.

J’ai ajouté le code simple suivant à la fonction d’initialisation de mon module, le code que j’ai trouvé en parcourant l’arborescence du code source du kernel Linux:

 ... #include  #include  static int __init fpga_init(void) { struct device_node *dt_node; const u8 *property; int len; printk(KERN_INFO "(I) FPGA module loaded at 0x%p\n", fpga_init); dt_node = of_find_node_by_path("/fpga_dt@c0000000"); if (!dt_node) { printk(KERN_ERR "(E) Failed to find device-tree node: /fpga_dt@c0000000\n"); return -ENODEV; } printk(KERN_INFO "(I) Found device-tree node. Now resortingeving property.\n"); property = of_get_property(dt_node, "reg", &len); printk(KERN_INFO "(I) reg=0x%08lX\n", (unsigned long) property[0]); ... return 0; } 

Malheureusement, l’insertion du module génère une erreur de segmentation en essayant simplement de trouver le nœud du périphérique.

 # insmod fpga_drv.ko (I) FPGA module loaded at 0xe112d000 Unable to handle kernel paging request for data at address 0x00000000 Faulting instruction address: 0xe112d07c Oops: Kernel access of bad area, sig: 11 [#1] SMP NR_CPUS=2 P2020 RDB Modules linked in: fpga_drv(P+) NIP: e112d07c LR: e112d078 CTR: c03ed6a4 REGS: df043e10 TRAP: 0300 Tainted: P (2.6.32.13) MSR: 00029000  CR: 24000222 XER: 20000000 DEAR: 00000000, ESR: 00000000 TASK = dfb85300[1167] 'insmod' THREAD: df042000 CPU: 1 GPR00: e112d078 df043ec0 dfb85300 00000000 e11761f4 c05838c4 00000000 dfffc650 GPR08: 00000020 00000000 00000012 c03ed6a4 24000282 10098374 1ff92100 10081fc8 GPR16: 1007a3e0 1007a434 00000000 00000002 00000000 00000000 bfbe6364 4801f468 GPR24: 10094009 1007ca88 c064d07c 00000000 e112d000 c0690000 e1170000 e1170000 NIP [e112d07c] fpga_init+0x7c/0x460 [fpga_drv] LR [e112d078] fpga_init+0x78/0x460 [fpga_drv] Call Trace: [df043ec0] [e112d078] fpga_init+0x78/0x460 [fpga_drv] (unreliable) [df043ef0] [c0001d94] do_one_initcall+0x3c/0x1e8 [df043f20] [c0077720] sys_init_module+0xf8/0x220 [df043f40] [c0010644] ret_from_syscall+0x0/0x3c Instruction dump: 3860ffed 80010034 bb410018 38210030 7c0803a6 4e800020 3c80e117 38a10008 388461f4 3fe0e117 4800038d 3fc0e117  3c60e117 386361f8 4cc63182 ---[ end trace 40317dd8a9588d98 ]--- Segmentation fault 

Qu’est-ce que cela indique? Y a-t-il un moyen de vérifier que le blob de l’arborescence des périphériques était correctement chargé et utilisable? Ai-je besoin de plus de code “setup” pour préparer une telle requête? Ou est-ce que j’essaie d’utiliser un tournevis comme un marteau?

Merci!

BTW, voici ma source FDT (DTS):

 /dts-v1/; / { model = "fsl,P2020"; compatible = "fsl,P2020RDB"; #address-cells = ; #size-cells = ; ... fpga_dt@c0000000 { #address-cells = ; #size-cells = ; compatible = "xilinx,xc6vlx240t", "virtex6"; model = "xilinx,XC6VLX240T"; reg = ; label = "Xilinx FPGA XC6VLX240T for My Custom Board"; }; }; 

Je vais spécifiquement répondre à cette question:

Y a-t-il un moyen de vérifier que le blob de l’arborescence des périphériques était correctement chargé et utilisable?

2 façons de vérifier si le FDT est correct.

D’abord dans u-boot. Vous pouvez vider le FDT.
Par exemple, si votre FDT réside dans la mémoire NV, copiez-le d’abord dans la RAM.

 cp.b 0xFFF70000 0x800000 0x200 

Configurez le fdt, puis videz l’arborescence fdt (vu par u-boot)

 fdt addr 800000 fdt print 

Cela devrait fonctionner car votre noeud est statique. Vous verrez facilement si l’arborescence des périphériques est incorrecte ou pas à ce stade.

Deuxième est dans le kernel mais vous devez recomstackr avec le débogage! Vous devez activer CONFIG_DEBUG_FS et définir DEBUG arch / powerpc / kernel / prom.c. Cela exportera l’arborescence dans / proc 🙂

Il y a une troisième voie. Vous pouvez vider l’arborescence des périphériques au fur et à mesure que le kernel parsing très tôt le démarrage. La méthode exacte m’échappe maintenant. Je suis certain que vous devez recomstackr le kernel et append un bootarg.

Bonne chance.

La réponse de sessyargc.jp était suffisante; Cependant, pour être complet, je voulais offrir un peu de code C que j’ai utilisé pour imprimer des informations de base à partir du pilote:

 #include  #include  ... print_device_tree_node(of_find_node_by_path("/"), 0); ... static void print_device_tree_node(struct device_node *node, int depth) { int i = 0; struct device_node *child; struct property *properties; char indent[255] = ""; for(i = 0; i < depth * 3; i++) { indent[i] = ' '; } indent[i] = '\0'; ++depth; for_each_child_of_node(node, child) { printk(KERN_INFO "%s{ name = %s\n", indent, child->name); printk(KERN_INFO "%s type = %s\n", indent, child->type); for (properties = child->properties; properties != NULL; properties = properties->next) { printk(KERN_INFO "%s %s (%d)\n", indent, properties->name, properties->length); } print_device_tree_node(child, depth); printk(KERN_INFO "%s}\n", indent); } } 

Je souhaite savoir comment déterminer chaque type de propriétés, afin que je puisse formater la valeur et la sortir correctement. Aucune suggestion?

Enfin, voici l’extrait original, modifié si légèrement:

 char *path = "/fpga_dt@c0000000"; struct device_node *dt_node; const u32 *property; int len; dt_node = of_find_node_by_path(path); if (!dt_node) { printk(KERN_ERR "(E) Failed to find device-tree node: %s\n", path); return -ENODEV; } printk(KERN_INFO "(I) Found device-tree node. Now resortingeving property.\n"); property = of_get_property(dt_node, "reg", &len); printk(KERN_INFO "(I) len=%d\n", len); printk(KERN_INFO "(I) reg[0]=0x%08lX\n", (unsigned long) property[0]); printk(KERN_INFO "(I) reg[1]=0x%08lX\n", (unsigned long) property[1]); printk(KERN_INFO "(I) reg[2]=0x%08lX\n", (unsigned long) property[2]); printk(KERN_INFO "(I) reg[3]=0x%08lX\n", (unsigned long) property[3]); 

Le défaut de segmentation se produisait sur certains chemins d’access incorrects. Apparemment, il y avait une erreur de type. J’ai finalement résolu le problème en sondant le chemin racine, puis quelques autres nœuds de base (comme, / cpu0, / memory, etc.), et finalement j’ai pu sonder mon fpga. Je ne suis pas sûr de ce qui a vraiment changé, mais je peux maintenant référencer correctement le nœud périphérique de mon FPGA, lorsque vous utilisez le code ci-dessus.

Merci pour votre aide! 🙂