嵌入式 Linux 启动四件套:U-Boot、zImage、DTB、Rootfs
在嵌入式 Linux 开发中,一个完整的系统通常由四个核心部分组成:U-Boot、zImage、DTB、Rootfs。它们像接力赛一样,从设备上电开始,一步步把硬件初始化、内核加载、设备识别、文件系统挂载完成,最终让我们看到终端登录界面。
如果把这四个组件拆开看,会发现它们各自承担的职责非常清晰。
U-Boot:嵌入式系统的"第一棒"
U-Boot 是 Universal Boot Loader 的缩写,也就是通用启动加载器。
设备上电后,CPU 并不能直接运行 Linux 内核。它首先需要一段最基础的程序来完成硬件初始化,比如初始化 DDR 内存、串口、时钟、Flash 等。U-Boot 就负责完成这些工作。
它的主要作用包括:
- 初始化基本硬件;
- 提供交互式命令行;
- 从 Flash、SD 卡、网络等位置加载内核和设备树;
- 把内核镜像和设备树放到内存指定位置;
- 最后将 CPU 控制权交给 Linux 内核。
在普通电脑上,这个"第一棒"通常由 BIOS 或 UEFI 完成;而在嵌入式开发板上,U-Boot 就承担了类似的角色。
不过,U-Boot 比传统 BIOS 更灵活。它不仅可以启动系统,还支持网络下载、文件读写、环境变量配置、脚本执行等功能,是嵌入式开发中非常重要的调试工具。
zImage:压缩后的 Linux 内核镜像
zImage 是 Linux 内核编译后生成的一种镜像格式。名字里的 z 表示它经过了压缩。
Linux 内核本身比较大,如果直接存放会占用更多 Flash 空间,启动时也会更慢。所以内核会被压缩成 zImage。U-Boot 把它加载到内存后,内核会先完成自解压,然后正式开始运行。
zImage 主要负责:
- 解压自身;
- 初始化内存管理、进程调度、中断系统;
- 加载驱动;
- 挂载根文件系统;
- 启动用户空间的第一个进程。
可以把它理解为嵌入式 Linux 系统的"心脏"。没有内核,硬件即使被初始化了,也无法形成完整的操作系统。
DTB:内核的硬件地图
DTB 的全称是 Device Tree Blob,中文叫设备树二进制文件。
早期的 Linux 内核经常把硬件信息写死在代码里,比如某个 GPIO 的地址、某个中断号、某个外设的寄存器基地址。但随着 SoC 和开发板越来越多,这种方式变得越来越臃肿。
设备树就是为了解决这个问题而出现的。
.dts 文件描述了板级硬件信息,例如:
- 有哪些外设;
- 外设的寄存器地址;
- 中断号;
- 时钟配置;
- GPIO 引脚;
- 网卡、串口、I2C、SPI 等设备信息。
.dts 文件经过编译后会生成 .dtb 文件。内核启动时,会读取 DTB,从而知道当前板子上到底有哪些硬件,以及这些硬件该如何配置。
如果把内核比作操作系统的大脑,那么 DTB 就是它的"硬件地图"。没有这张地图,内核可能不知道该怎么驱动板子上的具体外设。
Rootfs:用户空间的操作系统
Rootfs 是 Root Filesystem 的缩写,也就是根文件系统。
内核启动完成后,会挂载根文件系统,并寻找 /sbin/init 或类似的初始化程序来运行。这个程序启动后,系统才会真正进入用户空间,出现 Shell 终端、桌面环境,或者嵌入式设备上的应用程序。
根文件系统中通常包含:
/bin、/sbin:常用命令;/lib:库文件;/etc:配置文件;/dev:设备节点;/proc、/sys:内核虚拟文件系统;/home、/tmp、/var等目录。
常见的根文件系统方案包括 BusyBox、Buildroot、Yocto、Debian ARM、Ubuntu ARM 等。嵌入式开发中,BusyBox 因为体积小、结构简单,经常被用来制作最小根文件系统。
可以把它类比为电脑里的 C 盘:内核负责管理硬件和系统核心,而根文件系统则提供了用户真正能使用的程序和环境。
启动流程:从"上电"到"登录界面"
嵌入式 Linux 的启动过程可以概括为一条清晰的接力链:
- 设备上电,CPU 开始执行固化在芯片或 Flash 中的启动代码;
- U-Boot 启动,初始化 DDR、串口、时钟等基本硬件;
- U-Boot 从存储介质或网络中加载 zImage 和 DTB 到内存;
- U-Boot 设置启动参数,跳转到内核入口地址;
- zImage 解压并启动,解析 DTB,识别硬件;
- 内核初始化驱动、挂载 Rootfs;
- 根文件系统中的
/sbin/init启动,进入用户空间; - 系统出现 Shell 终端或应用界面。
用一句话总结就是:
U-Boot 负责把内核和设备树搬进内存,zImage 负责运行操作系统,DTB 负责告诉内核硬件长什么样,Rootfs 负责提供用户能使用的程序和环境。
为什么理解这四个组件很重要?
在学习嵌入式 Linux 驱动开发时,经常会遇到这些问题:
- 为什么内核加载了却启动不了?
- 为什么驱动加载后设备节点没有生成?
- 为什么修改了设备树却没有生效?
- 为什么文件系统里找不到某个命令?
- 为什么 U-Boot 能识别网卡,但进入系统后不行?
这些问题背后,往往都和 U-Boot、zImage、DTB、Rootfs 之间的配合有关。
把启动流程理清楚之后,再去看驱动加载、设备树配置、根文件系统制作、内核裁剪,思路会更清晰。驱动并不是孤立存在的,它运行在内核中,依赖设备树描述硬件,最终通过根文件系统里的应用程序被访问。
小结
嵌入式 Linux 系统的启动过程看似复杂,但只要抓住四个核心组件,就能建立完整框架:
| 组件 | 作用 | 类比 |
|---|---|---|
| U-Boot | 启动加载器,初始化硬件并加载内核 | BIOS/UEFI |
| zImage | 压缩内核镜像,操作系统核心 | 操作系统内核 |
| DTB | 设备树二进制,描述硬件信息 | 硬件配置清单 |
| Rootfs | 根文件系统,提供用户空间环境 | 系统 C 盘 |
后续可以进一步展开写 U-Boot 常用命令、DTB 编译与修改、内核裁剪、BusyBox 制作根文件系统 等内容,形成一套完整的嵌入式 Linux 学习笔记。