嵌入式应用程序实际如何使用设备树 blob?
How are device tree blobs actually used from an embedded application?
我正在尝试了解 device tree
的工作原理。我已经阅读了一些文档并且或多或少地了解什么是 dts
、dtsi
和 dtb
文件。
我不太明白的是 dtb
文件中的信息是如何从最终应用程序访问的。我一直在阅读 zephyr
os 文档和一些 linux 内核来理解这一点,但我仍然不是很清楚。
我现在的理解是最终应用程序(possibly OS 内核)读取并解析 dtb
文件 'manually'。这意味着每个 OS 内核将以自己的方式解析 dtb
文件,这是正确的吗?
然而,据我了解,应用程序没有链接到 dtb
文件,后者在某个内存区域中闪烁,然后是应用程序。以某种方式访问它。那么,如果在构建时 ose 符号不可用,如何构建应用程序?
免责声明:我不是 Linux 内核专家。
您的问题已得到解答 here 我想。
是的,每个 OS 内核都会以自己的方式解析 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中提取一次,然后放入一个高效的数据结构中。例如,从 'flatened' 格式转换为 'expanded' 格式。
强烈建议阅读:
- 这 introduction 到 Bootlin 的 Thomas Petazzoni 编写的设备树,
- 这篇 ELC Europe 2014 论文由当时来自索尼移动通信公司的 Frank Rowand 撰写,标题为 Devicetree: kernel internals and practical troubleshooting。
请注意,Zephyr 方法不是标准的:当 Open Firmware/Device Tree 方案旨在允许 'late binding' 应用程序和硬件描述时,他们选择了更静态的方法.
Zephyr 实际上使用了一种自定义工具,该工具确实处理 DTB 文件并生成 C header 文件,其中包含遵循某些命名约定的宏形式的相同信息。这可能就是为什么您对 DTB 内容和使用它的应用程序将绑定在一起的确切阶段感到困惑。
不要尝试 ramping-up 使用 Zephyr 的设备树概念。
此外,他们的工具在处理完全有效的 DTB 文件时仍然远非完美和阻塞。
Linux 内核 driver 代码的一个摘录,将 DTB 绑定到 driver:
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 代码中找到的等价物(虽然 driver 不同):
#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
我正在尝试了解 device tree
的工作原理。我已经阅读了一些文档并且或多或少地了解什么是 dts
、dtsi
和 dtb
文件。
我不太明白的是 dtb
文件中的信息是如何从最终应用程序访问的。我一直在阅读 zephyr
os 文档和一些 linux 内核来理解这一点,但我仍然不是很清楚。
我现在的理解是最终应用程序(possibly OS 内核)读取并解析 dtb
文件 'manually'。这意味着每个 OS 内核将以自己的方式解析 dtb
文件,这是正确的吗?
然而,据我了解,应用程序没有链接到 dtb
文件,后者在某个内存区域中闪烁,然后是应用程序。以某种方式访问它。那么,如果在构建时 ose 符号不可用,如何构建应用程序?
免责声明:我不是 Linux 内核专家。
您的问题已得到解答 here 我想。 是的,每个 OS 内核都会以自己的方式解析 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中提取一次,然后放入一个高效的数据结构中。例如,从 'flatened' 格式转换为 'expanded' 格式。
强烈建议阅读:
- 这 introduction 到 Bootlin 的 Thomas Petazzoni 编写的设备树,
- 这篇 ELC Europe 2014 论文由当时来自索尼移动通信公司的 Frank Rowand 撰写,标题为 Devicetree: kernel internals and practical troubleshooting。
请注意,Zephyr 方法不是标准的:当 Open Firmware/Device Tree 方案旨在允许 'late binding' 应用程序和硬件描述时,他们选择了更静态的方法.
Zephyr 实际上使用了一种自定义工具,该工具确实处理 DTB 文件并生成 C header 文件,其中包含遵循某些命名约定的宏形式的相同信息。这可能就是为什么您对 DTB 内容和使用它的应用程序将绑定在一起的确切阶段感到困惑。
不要尝试 ramping-up 使用 Zephyr 的设备树概念。 此外,他们的工具在处理完全有效的 DTB 文件时仍然远非完美和阻塞。
Linux 内核 driver 代码的一个摘录,将 DTB 绑定到 driver:
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 代码中找到的等价物(虽然 driver 不同):
#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