数据模型
DT 只是一个描述硬件的数据结构。它没有什么神奇之处,它也不会神奇地使所有硬件配置问题消失。它所做的是提供一种语言,用于将硬件配置与 Linux 内核(或任何其他操作系统)中的板卡和设备驱动程序支持分离。使用它可以让电路板和设备支持成为数据驱动的;根据传递到内核的数据,而不是每台机器的硬编码选择来做出设置决策。
理想情况下,数据驱动的平台设置应减少代码重复,并更轻松地使用单个内核映像支持各种硬件。
Linux 将 DT 数据用于三个主要目的:
- 平台识别
- 运行时配置
- 设备接入
平台识别
首先,内核使用DT中的数据,识别特定的机器。在一个完美的世界中,特定的平台对内核不重要,因为所有平台细节都可以通过设备树,以一致且可靠的方式完美描述。但是硬件并不完美,因此,内核必须在早期引导期间识别机器,以便它有机会运行特定于机器的修复程序。
在大多数情况下,机器身份无关紧要,内核会根据机器的核心CPU或SoC选择设置代码。例如在 ARM 上,arch/arm/kernel/setup.c 中的 setup_arch() ,调用 arch/arm/kernel/devtree.c 中的 setup_machine_fdt(),它搜索 machine_desc 表,选择最匹配设备树数据的 machine_desc。它通过查看根设备树节点中的“兼容”属性,确定最佳匹配。
‘compatible’ 属性包含一个以机器的确切名称,开头的字符串排序列表,后跟一个可选的兼容板列表,从最兼容到最不兼容。例如,TI BeagleBoard 及其后续产品 BeagleBoard xM 板的根兼容属性如下所示:
compatible = "ti,omap3-beagleboard", "ti,omap3450", "ti,omap3";
compatible = "ti,omap3-beagleboard-xm", "ti,omap3450", "ti,omap3";
“ti,omap3-beagleboard-xm”指定确切型号,它还声称它与 OMAP 3450 SoC,以及 omap3 SoC 系列总体兼容。注意,该列表是从最具体的(精确的板)到最不具体的(SoC 系列)排序的。
Beagle xM 还声称与原始 Beagle 板兼容。但是,应该注意在板级,这样做,因为从一个板到另一个通常会有很大的变化,即使在同一产品线中,而且,很难确切地确定一个板声称的含义与另一个兼容。
最好谨慎行事,不要声称一个板与另一个兼容。一块板作为另一块板的母板的情况,是个例外,例如连接到母板上的CPU模块。
同样在 ARM 上,对于每个machine_desc,内核查看是否有任何 dt_compat 列表条目出现在 compatible属性中。如果有,那么machine_desc就是驱动机器的候选对象。在搜索整个 machine_descs表后,setup_machine_fdt() 根据每个 machine_desc 匹配的兼容属性中的哪个条目返回“最兼容”的 machine_desc。如果未找到匹配的 machine_desc,则返回 NULL。
该方案背后的原因是,观察到在大多数情况下,如果单个 machine_desc 都使用相同的 SoC 或相同的 SoC 系列,则它们可以支持大量板。但是,总会有一些例外情况,即特定板需要特殊的设置代码,而这些代码在一般情况下没有用。特殊情况可以通过在通用设置代码中显式检查有问题的板来处理。
相反,兼容列表允许通用 machine_desc 通过在 dt_compat 列表中指定“不兼容”的值,来为广泛的通用板集提供支持。在上面的示例中,通用板支持可以声称与“ti,omap3”或“ti,omap3450”兼容。如果在原始beagleboard上,发现了一个需要特殊解决方法代码的错误,那么可以添加一个新的machine_desc来解决,只匹配“ti,omap3-beagleboard”。
运行时配置
在大多数情况下,通过DT将数据传输到内核。因此,也经常通过DT,在早期启动期间,向系统内核传递运行时的配置数据,例如,内核参数字符串和 initrd 映像的位置。
大部分数据都包含在 /chosen 节点中,在启动 Linux 时,它看起来像这样:
chosen {
bootargs = "console=ttyS0,115200 loglevel=8";
initrd-start = <0xc800