如何从 Linux 驱动程序访问和调试 FDT/DTS 设备树(seg-fault)
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/9606709/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
how to access and debug a FDT/DTS device tree from a Linux driver (seg-fault)
提问by Trevor
I have written a Linux kernel-module to act as an FPGA driver for a custom board based off the Freescale P2020RDB. The driver contains several #defines
to specify various addresses, sizes, bus-widths, etc. I would like to access the board's Flattened Device Tree (FDT) from within the driver to configure these addresses, so the driver can be used for other boards, where the FPGA has different sizes or resides at different addresses.
我编写了一个 Linux 内核模块,用作基于 Freescale P2020RDB 的定制板的 FPGA 驱动程序。该驱动程序包含几个#defines
来指定各种地址、大小、总线宽度等。我想从驱动程序内部访问板的扁平设备树 (FDT) 以配置这些地址,因此该驱动程序可用于其他板,其中FPGA 有不同的大小或驻留在不同的地址。
I have added the following simple code to my module's initialization function, which code I found while cruising the Linux kernel source code tree:
我在模块的初始化函数中添加了以下简单代码,这是我在浏览 Linux 内核源代码树时发现的代码:
...
#include <linux/of_device.h>
#include <linux/of_platform.h>
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 retrieving property.\n");
property = of_get_property(dt_node, "reg", &len);
printk(KERN_INFO "(I) reg=0x%08lX\n", (unsigned long) property[0]);
...
return 0;
}
Unfortunately, inserting the module produces a segmentation fault while just trying to find the device node.
不幸的是,插入模块会在试图找到设备节点时产生分段错误。
# 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 <EE,ME,CE> 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 <80830000> 3c60e117 386361f8 4cc63182
---[ end trace 40317dd8a9588d98 ]---
Segmentation fault
What does this indicate? Is there some way to verify that the device tree blob was properly loaded and usable? Do I need some more "setup" code to prepare for such a query? Or, am I trying to use a screwdriver as a hammer?
这说明什么?有什么方法可以验证设备树 blob 是否已正确加载和可用?我是否需要更多的“设置”代码来准备这样的查询?或者,我是想用螺丝刀当锤子吗?
Thanks!
谢谢!
BTW, Here is my FDT (DTS) source:
顺便说一句,这是我的 FDT (DTS) 来源:
/dts-v1/;
/ {
model = "fsl,P2020";
compatible = "fsl,P2020RDB";
#address-cells = <2>;
#size-cells = <2>;
...
fpga_dt@c0000000 {
#address-cells = <1>;
#size-cells = <1>;
compatible = "xilinx,xc6vlx240t", "virtex6";
model = "xilinx,XC6VLX240T";
reg = <0xc0000000 1 0xc8000000 0x08000000>;
label = "Xilinx FPGA XC6VLX240T for My Custom Board";
};
};
采纳答案by sessyargc.jp
I will specifically answer this question:
这个问题我专门回答一下:
Is there some way to verify that the device tree blob was properly loaded and usable?
有什么方法可以验证设备树 blob 是否已正确加载和可用?
2 ways to verify if the FDT is correct.
First in u-boot. You can dump the FDT.
For example if your FDT resides in NV memory first copy it to RAM.
验证 FDT 是否正确的 2 种方法。
首先在 u-boot 中。您可以转储 FDT。
例如,如果您的 FDT 驻留在 NV 内存中,请先将其复制到 RAM。
cp.b 0xFFF70000 0x800000 0x200
Setup the fdt, then dump the fdt tree (as seen by u-boot)
设置 fdt,然后转储 fdt 树(如 u-boot 所见)
fdt addr 800000
fdt print
This should work because your node is static. You will easily see if the device tree is incorrect or not at this point.
Second is in kernel but you have to recompile with debugging! You have to enable CONFIG_DEBUG_FS and define DEBUG arch/powerpc/kernel/prom.c. This will export the device tree in /proc :-)
There is a third way. You can dump the device tree as the kernel parses it very early during the bootup. The exact method escapes me now. I'm pretty certain you need to recompile the kernel and add a bootarg.
Goodluck.
这应该有效,因为您的节点是静态的。此时您将很容易看到设备树是否不正确。
其次是在内核中,但您必须通过调试重新编译!您必须启用 CONFIG_DEBUG_FS 并定义 DEBUG arch/powerpc/kernel/prom.c。这将在 /proc 中导出设备树 :-)
还有第三种方法。您可以转储设备树,因为内核在启动过程中很早就对其进行了解析。确切的方法现在逃脱了我。我很确定您需要重新编译内核并添加引导参数。
祝你好运。
回答by Trevor
sessyargc.jp's answer was sufficient; however, just for completeness, I wanted to offer a bit of C code that I used to print out some basic tree info from inside the driver:
sessyargc.jp 的回答就足够了;然而,为了完整起见,我想提供一些 C 代码,我用来从驱动程序内部打印出一些基本的树信息:
#include <linux/of_device.h>
#include <linux/of_platform.h>
...
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] = '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 retrieving 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]);
';
++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);
}
}
I wish I knew how to determine each properties type, so I could format the value and output it correctly. Any suggestions?
我希望我知道如何确定每个属性类型,这样我就可以格式化值并正确输出它。有什么建议?
Lastly, here is the original snippet, modified oh-so slightly:
最后,这是原始片段,稍微修改了一下:
##代码##The seg-fault was happening on some bad device-tree paths. Apparently, there was some typeo error. I ultimately fixed the problem by probing the root path, and then some other basic nodes (like, /cpu0, /memory, etc.), and finally I was able to probe my fpga. I am not sure what really changed, but I am able to reference my FPGA's device-tree node correctly now, when using the above code.
段错误发生在一些错误的设备树路径上。显然,有一些类型错误。我最终通过探测根路径和其他一些基本节点(如 /cpu0、/memory 等)解决了问题,最后我能够探测我的 fpga。我不确定真正发生了什么变化,但是当使用上述代码时,我现在可以正确引用我的 FPGA 设备树节点。
Thanks for all the help! :)
感谢所有的帮助!:)