Linux Kernel映射文件vmlinux、Image、zImage、uImage及设备树
2025-07-28
24
0
makemenconfig依赖:
sudo apt-get install libncurses5-dev libncursesw5-dev
Linuxkernel编译后生成的IMAGE文件大概有以下几种:
- vmlinux : vmlinux是 ELF 格式的文件,是编译出来的最原始的内核文件,是未压缩的.
- Image:是使用objcopy工具取消掉vmlinux的其它信息如符号表后的文件。
- zImage:是经过gzip压缩后的Image
- uImage:是在zImage前面加了64字节的头信息(文件类型,加载位置,生成时间,大小等),用于老的uboot启动。
新的uboot已经支持了zImage,故uImage已经用的经较少了。
其中 vmlinux编译后位于根makefile目录下,其余的的位于
zzmt@zzmt:~/Desktop/kernel/arch/arm/boot$ ls
bootp compressed dts Image install.sh Makefile zImage
编译脚本:
#!/bin/sh
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- distclean
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf-imx_v7_defconfig
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- menuconfig
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- all -j16
make menuconfig之后会生成.config,故make all是执行的编译脚本是.config
- ARM =arm:目标CPU架构
- CROSS_COMPILE=arm-linux-gnueabihf- 交叉工具编译链
- distclean:Makefile 伪指令
1.设备树
Linux 内核编译过程中,生成 .dtb(Device Tree Blob) 文件是 ARM、RISC-V 等架构 上的常见步骤,但并非所有架构都强制需要。它的存在与否取决于硬件平台和内核配置。
传统方式(无设备树)的弊端
- x86 架构:硬件信息由 BIOS/UEFI 直接提供给内核,无需额外配置。
- ARM 等嵌入式架构:硬件差异极大,传统方式需在内核源码中硬编码每个板子的硬件信息(如寄存器地址、外设列表),导致:
- 内核臃肿(需为每款板子编写代码)。
- 难以支持新硬件(需重新编译内核)。
设备树的解决方案
- 描述硬件,而非编码硬件:将硬件信息(CPU、内存、外设等)以结构化数据(.dts 文本文件)描述,编译为二进制 .dtb。
- 内核与硬件解耦:同一内核镜像可搭配不同 .dtb 文件运行在不同硬件上。
2.设备树的原理
文件/工具 | 作用 |
---|---|
.dts | 设备树源码(人类可读的文本文件,描述硬件布局)。 |
.dtsi | 设备树头文件(类似 C 的 .h 文件,包含通用定义,可被多个 .dts 包含)。 |
dtc | 设备树编译器(将 .dts 编译为 .dtb )。 |
.dtb | 设备树二进制文件(由 Bootloader 加载并传递给内核)。 |
工作流程
- 编写
.dts/.dtsi
:定义硬件信息(如 CPU 型号、内存地址、GPIO 引脚等)。 - 编译为
.dtb
:使用dtc
工具编译(内核编译时自动完成)。 - Bootloader 加载:如 U-Boot 将
.dtb
和内核镜像一起加载到内存,并传递给内核。 - 内核解析
.dtb
:初始化硬件驱动时,直接从.dtb
中读取硬件信息,无需硬编码。
3.是否必须生成 .dtb
?
场景 | 是否需要 .dtb ? |
示例架构/平台 |
---|---|---|
使用设备树的平台 | ✅ 必须 | ARM(如树莓派)、RISC-V、PowerPC |
传统非设备树平台 | ❌ 不需要 | x86、旧版 ARM(如 ARMv6 之前) |
内核配置关闭设备树 | ❌ 不生成 | 手动关闭 CONFIG_OF 选项 |
如何检查当前内核是否使用设备树?
# 查看内核启动日志
dmesg | grep -i "device tree"
# 或检查 /proc 文件系统
cat /proc/device-tree/model # 若存在,说明使用了设备树
4. 设备树的优势与挑战
优势
- 硬件可移植性:同一内核支持多种硬件。
- 减少内核冗余:无需为每款板子维护独立代码分支。
- 动态硬件发现:支持热插拔设备(如 USB、PCIe)。
挑战
- 学习曲线:需掌握设备树语法(类似 JSON 的结构化语言)。
- 调试复杂度:硬件问题可能源于设备树配置错误(如寄存器地址错误)。
5. 手动操作设备树的示例
编译单个 .dts
为 .dtb
# 使用 dtc 工具(通常随内核源码提供)
dtc -I dts -O dtb -o output.dtb input.dts
反编译 .dtb
为 .dts
(调试用)
dtc -I dtb -O dts -o decompiled.dts input.dtb
6.查看内核支持的设备树绑定(Bindings)
# 内核源码中的文档
ls Documentation/devicetree/bindings/
常见问题
Q1: 为什么修改 .dts
后需重新编译内核?
- 实际上,只需重新编译
.dts
生成新的.dtb
,无需重编整个内核。但某些内核模块可能依赖设备树信息,需重新加载。
Q2: 一个系统可以有多个 .dtb
吗?
- 是的!Bootloader(如 U-Boot)可根据硬件自动选择匹配的
.dtb
文件(例如树莓派的bcm2711-rpi-4-b.dtb
和bcm2711-rpi-400.dtb
)。
Q3: 设备树会影响性能吗?
- 几乎不影响。设备树仅在启动时解析一次,之后驻留在内存中,不占用运行时资源。
总结
.dtb
是设备树的二进制形式,用于非 x86 架构的硬件描述,是现代嵌入式 Linux 的核心机制。- 非所有架构必需,但在 ARM/RISC-V 等平台中不可或缺。
- 掌握设备树能显著提升嵌入式开发效率,尤其在定制硬件时。