我编写了一个 Linux 内核模块,用作基于 Freescale P2020RDB 的定制板的 FPGA 驱动程序。该驱动程序包含几个 #defines
来指定各种地址、大小、总线宽度等。我想从驱动程序内部访问板的扁平设备树 (FDT) 来配置这些地址,因此该驱动程序可用于其他板,其中 FPGA 具有不同的大小或位于不同的地址。
我在模块的初始化函数中添加了以下简单代码,这是我在浏览 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;
}
不幸的是,插入模块会在试图找到设备节点时产生段错误。
# 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
这说明什么?有什么方法可以验证设备树 blob 是否已正确加载和可用?我是否需要更多的“设置”代码来准备这样的查询?或者,我是想用 Screwdriver 当锤子吗?
谢谢!
顺便说一句,这是我的 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";
};
};
最佳答案
这个问题我专门回答一下:
验证 FDT 是否正确的 2 种方法。
首先在 u-boot 中。您可以转储 FDT。
例如,如果您的 FDT 驻留在 NV 内存中,请先将其复制到 RAM。
cp.b 0xFFF70000 0x800000 0x200
设置 fdt,然后转储 fdt 树(如 u-boot 所见)fdt addr 800000
fdt print
这应该有效,因为您的节点是静态的。此时您将很容易看到设备树是否不正确。其次是在内核中,但您必须通过调试重新编译!
您必须在
CONFIG_DEBUG_FS=y
中启用 #define DEBUG
和 arch/powerpc/kernel/prom.c
。这将导出 /proc
中的设备树 :-)还有第三种方式。您可以转储设备树,因为内核在启动过程中很早就对其进行了解析。确切的方法现在逃脱了我。我很确定您需要重新编译内核并添加引导参数。
祝你好运。
关于linux - 如何从 Linux 驱动程序访问和调试 FDT/DTS 设备树(seg-fault),我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/9606709/