2. U-Boot 源码结构:顶层目录与关键子目录解析
拿到一份 U-Boot 源码,第一眼看到几十个文件夹,很多人会懵。我刚开始接触 U-Boot 时也一样,对着目录列表发呆——这玩意儿从哪看起?
其实没那么复杂。U-Boot 的目录结构设计得很清晰,说白了就是「平台相关」和「平台无关」两大块。今天我就带你捋一遍,哪些是核心,哪些是辅助,哪些你平时根本不用碰。
核心观点:U-Boot 源码结构遵循「分层 + 模块化」设计。顶层目录按功能划分,关键子目录对应硬件抽象、驱动框架、命令系统、配置体系四大块。理解了这个骨架,你就能快速定位任何功能代码。
2.1 顶层目录结构总览
先看一张我画的整体框架图,把顶层目录的关系理清楚:
这张图我建议你保存下来。每次移植新板子时,对着图找目录,效率高很多。
2.2 board/ 目录——板级硬件描述
board/ 是我个人认为移植时最重要的目录。它存放的是「这块板子长什么样」的信息。
每个板子厂商或型号在这里都有一个子目录,比如:
board/
├── samsung/
│ ├── smdk2440/
│ └── exynos5/
├── ti/
│ ├── am335x/
│ └── omap5/
└── mycompany/
└── myboard/
每个板级目录里通常包含:
- board.c:板级初始化代码,比如 DDR 初始化、GPIO 配置
- Kconfig 和 Makefile:编译配置
- 有时还有 lowlevel_init.S:最早期的汇编初始化
我的经验:移植新板子时,最快的方法是找一个参考板,把它的 board/ 目录复制一份,然后改 DDR 参数和时钟配置。我在做 i.MX6 项目时就这么干的,省了至少一周时间。
2.3 cpu/ 目录——CPU 架构核心代码
cpu/ 目录存放的是与 CPU 架构紧密相关的代码。说白了,ARM、RISC-V、x86 的启动流程完全不同,这部分就是处理这些差异的。
常见的子目录:
| 子目录 | 架构 | 关键文件 |
|---|---|---|
| arm/ | ARM 系列 | start.S, interrupts.c, cache.c |
| armv7/ | Cortex-A7/A8/A9 | lowlevel_init.S, cpu.c |
| armv8/ | Cortex-A53/A72 等 64位 | start.S, exceptions.S |
| riscv/ | RISC-V | start.S, trap.S |
| x86/ | x86 架构 | start.S, car.S |
这里有个坑,我提醒一下:cpu/ 里的 start.S 是 U-Boot 的第一条指令入口。如果你改了链接脚本或者入口地址,一定要同步修改这里。我曾经因为忘了改 start.S 中的链接地址,折腾了两天才发现是这里的问题。
2.4 drivers/ 目录——驱动框架
drivers/ 是 U-Boot 中最大的目录,没有之一。它实现了所有外设的驱动:串口、网卡、MMC、USB、NAND Flash、SPI、I2C 等等。
目录结构大致如下:
drivers/
├── serial/ # 串口驱动
├── net/ # 网卡驱动(如 DM9000、RTL8169)
├── mmc/ # SD/MMC/eMMC 驱动
├── spi/ # SPI 控制器驱动
├── i2c/ # I2C 控制器驱动
├── mtd/ # NAND/NOR Flash 驱动
├── usb/ # USB 主机/设备驱动
├── gpio/ # GPIO 驱动
└── pinctrl/ # 引脚复用控制
U-Boot 现在全面采用 DM(Driver Model) 框架。你写驱动时,需要实现 DM 规定的接口,比如 probe()、remove()、of_to_plat() 等。
注意:不是所有驱动都用了 DM 框架。一些老旧的板子还在用「legacy」驱动方式。移植时先确认你的板子用的是哪种,否则容易混淆。我建议新项目一律用 DM,维护起来省心很多。
2.5 include/ 目录——配置与头文件
include/ 目录是 U-Boot 的「大脑」。它包含所有全局头文件和板级配置。
重点关注两个子目录:
- include/configs/:板级配置头文件,比如
smdk2440.h。这里定义了内存大小、环境变量分区、支持的命令列表等。 - include/dt-bindings/:设备树绑定头文件,定义时钟、中断、GPIO 等宏。
举个例子,一个典型的板级配置头文件片段:
/* include/configs/myboard.h */
#define CONFIG_SYS_TEXT_BASE 0x87800000
#define CONFIG_NR_DRAM_BANKS 1
#define CONFIG_SYS_SDRAM_BASE 0x80000000
#define CONFIG_SYS_SDRAM_SIZE (512 << 20) /* 512 MB */
#define CONFIG_ENV_SIZE 0x20000 /* 128 KB */
#define CONFIG_ENV_OFFSET 0xE0000
这些宏直接决定了 U-Boot 的运行地址、内存布局、环境变量位置。改错一个,板子就可能起不来。
2.6 其他关键目录速览
剩下的目录我快速过一遍,你有个印象就行:
| 目录 | 作用 | 什么时候用 |
|---|---|---|
| common/ | 通用函数,如命令行解析、控制台输出 | 几乎不用改,除非你要加新命令 |
| cmd/ | 所有 U-Boot 命令的实现(如 bootm、ping) |
想自定义命令时来这里 |
| lib/ | 加密库、压缩库、字符串处理等 | 一般不动,除非要加新算法 |
| net/ | 网络协议栈(ARP、ICMP、TFTP 等) | 调试网络启动时可能会看 |
| fs/ | 文件系统支持(FAT、ext4、UBIFS 等) | 需要从文件系统加载内核时用到 |
| tools/ | 主机端工具,如 mkimage、env 工具 | 制作镜像、打包固件时用 |
| dts/ | 设备树源文件(.dts) | 新板子必须在这里添加设备树 |
2.7 我的目录导航建议
刚接触 U-Boot 时,别想着把所有目录都看懂。我建议你按这个顺序来:
- 先看
board/:找到你的板子目录,看board.c和Kconfig - 再看
include/configs/:找到板级配置头文件,理解宏定义 - 然后看
dts/:确认设备树是否正确描述了硬件 - 最后看
drivers/:如果某个外设不工作,来这里找对应驱动
一句话总结:U-Boot 源码结构不复杂。平台相关的在 board/、cpu/、include/configs/、dts/;平台无关的在 drivers/、common/、cmd/、lib/。移植时改前者,调试时看后者。记住这个原则,你就能在 U-Boot 源码里来去自如。