您好,登录后才能下订单哦!
# 如何进行Linux设备树传递及Kernel对设备树分析
## 1. 设备树技术背景
### 1.1 设备树的起源与发展
设备树(Device Tree)最初由Open Firmware提出,用于描述硬件配置信息。随着Linux在嵌入式领域的广泛应用,传统的"硬编码"硬件描述方式暴露出严重问题:
1. 每个板级支持包(BSP)都需要单独维护
2. 内核镜像需要为不同硬件重新编译
3. 硬件变更导致大量代码修改
设备树通过将硬件描述与内核代码分离,实现了:
- **硬件描述标准化**:采用.dts文本格式描述硬件
- **平台无关性**:同一内核镜像可支持多种硬件
- **维护便利性**:硬件变更只需修改设备树文件
### 1.2 设备树在ARM体系中的采用
2011年后,ARM社区正式采用设备树作为标准硬件描述方法。主要推动因素包括:
- ARM架构变种繁多(如Cortex-A/R/M系列)
- 同一SoC在不同板卡上外设配置不同
- 嵌入式系统对快速启动的需求
典型应用场景:
```dts
// 示例:描述UART控制器
uart0: serial@101f1000 {
compatible = "arm,pl011";
reg = <0x101f1000 0x1000>;
interrupts = <0 12 4>;
};
在设备树普及前,ARM Linux使用ATAGS(ARM Tagged List)传递参数: - 通过寄存器r2传递物理地址 - 包含内存大小、命令行参数等基本信息 - 无法描述复杂硬件拓扑
现代Bootloader(如U-Boot)使用更先进的DTB传递:
1. Bootloader加载DTB到内存
2. 通过寄存器r2传递DTB物理地址
3. 内核通过early_init_dt_scan()
解析
关键数据结构对比:
特性 | ATAGS | DTB |
---|---|---|
扩展性 | 有限 | 强(树形结构) |
硬件描述能力 | 仅基础参数 | 完整硬件拓扑 |
维护成本 | 需修改内核代码 | 仅修改DTB文件 |
DTB文件由四部分组成:
struct fdt_header {
uint32_t magic; // 0xd00dfeed
uint32_t totalsize;
uint32_t off_dt_struct;
uint32_t off_dt_strings;
uint32_t off_mem_rsvmap;
uint32_t version;
uint32_t last_comp_version;
// ...
};
Memory Reserve Map:保留内存区域列表
Structure Block:设备树结构主体,采用嵌套标记:
Strings Block:属性名字符串池
以U-Boot为例的关键步骤:
int fdt_chosen(void *fdt) {
int nodeoffset;
char *str;
nodeoffset = fdt_add_subnode(fdt, 0, "chosen");
fdt_setprop(fdt, nodeoffset, "bootargs", str, strlen(str)+1);
}
// ARMv7启动代码片段
ldr r0, =0x10000000 // DTB物理地址
ldr r1, =0x10000 // DTB大小
mov r2, #0 | 机器ID(已弃用)
内核启动阶段的关键函数调用链:
start_kernel()
→ setup_arch()
→ setup_machine_fdt()
unflatten_device_tree()
:将DTB转换为内核数据结构of_platform_populate()
:创建设备节点内存转换过程:
DTB二进制 → device_node结构体 → platform_device
内核通过以下步骤完成转换:
const struct of_device_id matches[] = {
{ .compatible = "simple-bus", },
{ /* sentinel */ }
};
of_platform_populate(NULL, matches, NULL, NULL);
struct platform_device *pdev;
pdev = of_device_alloc(np, bus_id, parent);
if (pdev)
of_device_add(pdev);
struct resource res;
of_address_to_resource(np, 0, &res);
platform_device_add_resources(pdev, &res, 1);
驱动匹配的核心是compatible
属性:
static const struct of_device_id mydrv_match[] = {
{ .compatible = "vendor,device-123" },
{}
};
MODULE_DEVICE_TABLE(of, mydrv_match);
struct platform_driver mydrv = {
.probe = mydrv_probe,
.driver = {
.name = "mydrv",
.of_match_table = mydrv_match,
},
};
of_device_is_compatible() → driver_match_device() → probe()
动态设备树修改实现原理:
fdtoverlay -i base.dtb -o final.dtb overlay1.dtbo overlay2.dtbo
int of_overlay_fdt_apply(void *fdt, u32 fdt_size);
通过/sys文件系统访问设备树:
# 查看完整设备树
cat /sys/firmware/devicetree/base/compatible
# 查看特定节点属性
ls /sys/firmware/devicetree/base/soc/
关键配置选项:
CONFIG_DEBUG_FS=y
CONFIG_OF_DEBUG=y
CONFIG_OF_OVERLAY=y
常用调试函数:
of_print_phandle_args(const struct of_phandle_args *args);
of_node_full_name(const struct device_node *np);
在x86/ARM混合架构下的处理策略:
if (acpi_disabled)
setup_device_tree();
else
acpi_boot_table_init();
acpi=force|off
树莓派4B的典型设备树结构:
/ {
compatible = "raspberrypi,4-model-b";
memory@0 {
device_type = "memory";
reg = <0 0x40000000>;
};
soc {
ranges = <0x7e000000 0xfe000000 0x1000000>;
gpio@7e200000 {
compatible = "brcm,bcm2711-gpio";
reg = <0x7e200000 0xb4>;
};
};
};
[ 0.000000] OF: fdt: Machine model: Raspberry Pi 4 Model B
[ 0.000000] OF: reserved mem: initialized node linux,cma
添加新设备的完整流程:
/ {
my_device {
compatible = "custom,mydev";
reg = <0x12340000 0x1000>;
interrupts = <0 45 4>;
status = "okay";
};
};
dtc -I dts -O dtb -o mydev.dtbo mydev.dts
fdtdump mydev.dtbo # 验证二进制内容
static int mydev_probe(struct platform_device *pdev)
{
struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
void __iomem *base = devm_ioremap_resource(&pdev->dev, res);
// ...
}
&node
)#include "common.dtsi"
dtc -@ -Hepapr -O dtb -o reduced.dtb -Wno-unit_address_vs_reg input.dts
典型错误处理流程: 1. 检查内核日志:
[ 0.000000] OF: bad range /soc/usb@7e980000
-dump-dtb
参数保存实际使用的DTBdtc -I dtb -O dts dumped.dtb > debug.dts
识别方法:
cat /proc/iomem
cat /proc/interrupts
设备树解决方案:
/delete-node/ &conflicting_node;
最新规范发展:
- Devicetree Specification v0.4新增特性:
- 条件包含(#ifdef
样式语法)
- 增强类型系统
- 更严格的验证规则
accelerator {
compatible = "opencl,accelerator";
method = "pci";
regions = <&fpga_region 0>;
};
Linux设备树技术通过将硬件描述与内核代码解耦,显著提高了嵌入式系统的灵活性和可维护性。本文详细分析了从Bootloader传递DTB到内核解析的完整流程,深入探讨了设备节点到平台设备的转换机制,并给出了实际开发中的优化建议。随着Specification的持续演进,设备树将继续作为ARM体系结构的标准硬件描述方法,并在异构计算、虚拟化等新兴领域发挥更重要作用。
”`
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。