免责声明:我不是 Linux 内核专家。
我猜你的问题在这里得到了回答。是的,每个操作系统内核都会以自己的方式解析 DTB 文件。在 Linux 的情况下,例如 DTB 将由 u-boot 读取,u-boot 将启动 Linux 内核并传递它加载 DTB BLOB 的地址。
在下面的示例中,u-boot 会将内核和 DTB 从 FAT 文件系统加载到内存中,然后将控制权转移到地址 0x80300000 处的内核,同时告诉它其 DTB BLOB 将在地址 0x815f0000 处可用:
fatload mmc 0:1 0x80300000 zImage
fatload mmc 0:1 0x815f0000 beagle-xm.dtb
bootz 0x80300000 - 0x815f0000
DTB BLOB 确实包含符号名称及其相关值。应用程序将使用一些专门用于读取 DTB 格式的代码,例如 libfdt,以从其符号名称中检索值。现在不需要在构建它时了解 DTB 内容。这确实允许相同的编译内核在不修改的情况下在不同的硬件上运行,DTB 中描述了各种硬件功能。
为了使操作系统能够有效地访问 DTB 中包含的信息,使用 libfdt 将信息从 DTB BLOB 中提取一次,然后放入一个有效的数据结构中。例如,从“扁平化”格式转换为“扩展”格式。
我强烈建议阅读:
- 这篇由 Bootlin 的 Thomas Petazzoni 编写的关于设备树的介绍,
- 这篇 ELC Europe 2014 论文由当时来自 Sony Mobile Communications 的 Frank Rowand 撰写,标题为Devicetree:内核内部和实际故障排除。
请注意,Zephyr 方法不是标准的:当开放固件/设备树方案被设计为允许应用程序和硬件描述的“后期绑定”时,他们选择了更静态的方法。
Zephyr 实际上使用了一个自定义工具,它处理 DTB 文件并生成 C 头文件,其中包含遵循某些命名约定的宏形式的相同信息。这可能是您对 DTB 内容和使用它的应用程序绑定在一起的确切阶段感到困惑的原因。
不要尝试使用 Zephyr 来提升设备树的概念。此外,他们的工具还远非完美,在处理完全有效的 DTB 文件时会卡住。
将 DTB 绑定到驱动程序的 Linux 内核驱动程序代码摘录:
static const struct platform_device_id mxs_auart_devtype[] = {
{ .name = "mxs-auart-imx23", .driver_data = IMX23_AUART },
{ .name = "mxs-auart-imx28", .driver_data = IMX28_AUART },
{ .name = "as-auart-asm9260", .driver_data = ASM9260_AUART },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(platform, mxs_auart_devtype);
static const struct of_device_id mxs_auart_dt_ids[] = {
{
.compatible = "fsl,imx28-auart",
.data = &mxs_auart_devtype[IMX28_AUART]
}, {
.compatible = "fsl,imx23-auart",
.data = &mxs_auart_devtype[IMX23_AUART]
}, {
.compatible = "alphascale,asm9260-auart",
.data = &mxs_auart_devtype[ASM9260_AUART]
}, { /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, mxs_auart_dt_ids);
在 Zephyr 代码中找到一个等效的(虽然不同的驱动程序):
#if DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(flexcomm5), nxp_lpc_spi, okay)
/* Attach 12 MHz clock to FLEXCOMM5 */
CLOCK_AttachClk(kFRO_HF_to_FLEXCOMM5);
/* reset FLEXCOMM for SPI */
RESET_PeripheralReset(kFC5_RST_SHIFT_RSTn);
#endif