2. U-Boot源码结构:顶层目录、board、arch、common、drivers等关键目录解析

拿到一份U-Boot源码,第一件事是什么?我个人的习惯是——先看目录结构。别急着编译,也别急着改代码。你得先搞清楚,这个庞大的工程里,什么东西放在哪里。

U-Boot的源码目录,说白了就是一套高度模块化的嵌入式启动方案。它不像Linux内核那么复杂,但麻雀虽小五脏俱全。今天我就带你走一遍,把那些关键目录挨个说清楚。

2.1 顶层目录:一眼看穿全局

解压U-Boot源码后,你会在顶层看到一堆文件和文件夹。我挑几个最重要的说:

目录/文件 作用 我的经验
board/ 板级相关代码,每个板子一个子目录 移植时最常改的地方
arch/ CPU架构相关代码(ARM、RISC-V、x86等) 启动汇编就在这里
common/ 通用核心功能,如命令行、环境变量 调试时经常翻
drivers/ 各种外设驱动(串口、网卡、Flash等) 加新硬件必看
include/ 头文件、配置宏定义 配置板子全靠它
configs/ 默认配置文件(defconfig) make xxx_defconfig 的源头
scripts/ 编译脚本、Kconfig工具 一般不用动
tools/ 主机端工具(mkimage等) 打包镜像时用

嗯,这里要注意:board/ 和 arch/ 是移植工作的主战场。其他目录虽然也重要,但大部分时候你不需要动它们。

2.2 board/ 目录:板级代码的根据地

每个板子都在 board/ 下有自己的文件夹。命名规则一般是 board/厂商/板子名。比如:

board/
├── freescale/
│   ├── mx6ul_14x14_evk/
│   └── ls1046ardb/
├── rockchip/
│   ├── evb_rk3399/
│   └── tinker_board/
└── mycompany/
    └── myboard/   ← 你自己新建的板子目录

这个目录里放什么?说白了就是三样东西:

  • 板子初始化代码(如 board.c、board_init.c)
  • 板级设备树文件(.dts 或 .dtsi)
  • 板子特有的配置头文件
我的习惯: 移植新板子时,我会先找一个参考板,把它的 board/ 目录整个复制过来,然后改名字、改引脚、改内存参数。这样比从零开始写快得多。

2.3 arch/ 目录:CPU架构的核心

U-Boot支持多种CPU架构。以最常用的ARM为例,arch/arm/ 下的结构是这样的:

arch/arm/
├── cpu/          ← CPU核心代码
│   ├── armv7/
│   ├── armv8/
│   └── ...
├── dts/          ← 设备树文件
├── include/      ← 架构相关头文件
├── lib/          ← 架构通用库函数
└── mach-*/       ← 厂商SoC相关代码

这里有个关键点:启动时的第一条指令就在 arch/arm/cpu/ 下。我记得第一次看U-Boot启动流程时,在 arch/arm/cpu/armv7/start.S 里找了半天入口。那个文件里就是最底层的汇编代码——设置CPU模式、关中断、初始化栈指针。

我曾经踩过的坑: 有一次移植时,板子死活起不来。查了两天,最后发现是 arch/arm/cpu/ 下的 cache 初始化代码和我的SoC不匹配。所以,如果你遇到莫名其妙的启动失败,先检查 arch/ 下的CPU相关代码。

2.4 common/ 目录:U-Boot的“内脏”

common/ 目录包含了U-Boot的核心功能模块。这里的东西,你几乎每天都会打交道:

  • main.c — U-Boot的主循环入口
  • command/ — 所有命令行命令的实现(如 md、mw、bootm)
  • env/ — 环境变量管理(保存、加载、默认值)
  • bootm.c — 启动内核的核心逻辑
  • console.c — 控制台输入输出

你想想看,你在U-Boot命令行里敲的每一个命令,背后都是 common/command/ 里的代码在干活。如果你要添加自定义命令,也是在这里加。

2.5 drivers/ 目录:硬件驱动的仓库

U-Boot的驱动模型(Driver Model)把所有外设驱动都放在 drivers/ 下。按功能分类:

子目录 驱动类型 典型场景
serial/ 串口驱动 调试输出、控制台
net/ 网卡驱动 TFTP下载、网络启动
mmc/ SD卡/eMMC驱动 从存储设备加载镜像
spi/ SPI Flash驱动 存储U-Boot本身
usb/ USB主机/设备驱动 U盘启动、USB下载
gpio/ GPIO驱动 控制LED、复位等

这里有个趋势:新版本的U-Boot越来越依赖设备树来配置驱动。你不需要在C代码里硬编码引脚信息,而是在.dts文件里描述硬件,驱动自己解析。这样做的好处是——换板子时,改设备树就行,驱动代码不用动。

2.6 其他重要目录

除了上面几个,还有几个目录值得提一下:

  • include/configs/ — 板级配置头文件。老版本U-Boot全靠这个文件配置,新版本逐渐被Kconfig替代,但很多项目还在用。
  • configs/ — 默认配置文件。执行 make xxx_defconfig 时,就是从这读取配置。
  • lib/ — 通用库函数,比如字符串处理、CRC校验、sha256等。
  • fs/ — 文件系统支持(ext4、fat、ubifs等)。

2.7 一张图看懂U-Boot源码结构

说了这么多,不如一张图来得直观。下面这张SVG图展示了U-Boot源码的核心目录层次和它们之间的关系:

U-Boot源码核心目录结构 U-Boot 源码核心目录结构 U-Boot 根目录 board/ arch/ drivers/ 板级初始化代码 CPU/SoC 相关代码 外设驱动集合 board.c / board_init.c start.S / cpu.c serial / net / mmc / spi common/ main.c / command/ / env/ 💡 移植工作主战场 board/ + arch/ + configs/ 这三个目录改得最多

2.8 总结一下:移植时你该关注什么

说了这么多,其实就一句话:移植U-Boot,本质上就是填好 board/、配好 arch/、选好 drivers/。具体来说:

  1. 先找参考板 — 在 board/ 下找一个和你硬件最接近的板子
  2. 复制并改名 — 整个目录复制,改成你的板子名
  3. 改配置 — 修改 include/configs/ 下的头文件,或者用Kconfig重新配置
  4. 调驱动 — 在 drivers/ 下找到对应的外设驱动,确认是否支持你的芯片
  5. 编译测试 — 用 make 编译,烧录到板子上看串口输出

核心原则: 不要试图一次性理解所有目录。你只需要关注 board/、arch/、configs/ 和 drivers/ 这四个目录。其他目录,用到的时候再去看。