2、U-Boot源码结构:顶层目录结构、关键子目录功能、配置文件体系
好,咱们直接进入正题。上一章聊了U-Boot能干什么,这一章咱们把它的“骨架”拆开看看。你拿到一份U-Boot源码,第一眼肯定懵——这么多文件夹,从哪下手?
我刚开始接触U-Boot的时候,也对着目录发过呆。后来发现,它的结构其实很有规律。说白了,就是一套“硬件抽象 + 板级定制 + 通用逻辑”的框架。搞懂了这套框架,你往里面加板子、改驱动,心里就有底了。
2.1 顶层目录结构:一眼看穿全局
先看顶层。你解压U-Boot之后,会看到类似这样的布局:
u-boot/
├── arch/ # CPU架构相关代码
├── board/ # 具体板卡定制代码
├── common/ # 通用功能模块
├── configs/ # 板级默认配置文件
├── doc/ # 文档
├── drivers/ # 设备驱动
├── dts/ # 设备树源文件
├── fs/ # 文件系统支持
├── include/ # 头文件
├── lib/ # 库函数
├── net/ # 网络协议栈
├── scripts/ # 编译脚本
├── tools/ # 主机端工具
├── Makefile # 顶层构建文件
└── Kconfig # 配置菜单系统
嗯,这里要注意:arch/ 和 board/ 是移植工作的主战场。其他目录虽然也重要,但大部分时候你不需要动它们。
核心原则:U-Boot的目录划分遵循“分层隔离”思想。CPU架构相关代码放在 arch/,板级硬件差异放在 board/,通用逻辑放在 common/ 和 lib/。这样你换一块板子,只需要改 board/ 和 configs/,不用动核心代码。
2.2 关键子目录功能详解
咱们挑几个最常用的目录,一个一个说。我按实际开发中接触的频率来排。
2.2.1 arch/ —— CPU架构的“家”
这个目录下面按CPU架构分文件夹:
- arch/arm/ —— ARM架构,嵌入式绝对主力
- arch/x86/ —— x86架构,少数场景用
- arch/riscv/ —— RISC-V,新贵
- arch/mips/ —— MIPS,老牌选手
每个架构下面又细分:
arch/arm/
├── cpu/ # CPU初始化、异常处理
├── include/ # 架构相关头文件
├── lib/ # 架构通用函数(如cache操作)
├── mach-xxx/ # 具体SoC厂商的定制代码
└── dts/ # 设备树文件
我记得有一次移植一个新款ARM芯片,发现启动就卡死。查了两天,最后发现是 arch/arm/cpu/ 里某个cache初始化宏没开。你看,这种底层细节,全藏在这个目录里。
2.2.2 board/ —— 你的板子,你的代码
这是你最常打交道的目录。每个板子一个子文件夹:
board/
├── ti/
│ ├── am335x/ # BeagleBone Black
│ └── dra7xx/ # TI DRA7系列
├── freescale/
│ ├── imx6q_sabre/ # i.MX6Q开发板
│ └── ls1046a/ # Layerscape系列
├── rockchip/
│ ├── evb_rk3399/ # RK3399开发板
│ └── nanopi4/ # NanoPi4
└── mycompany/ # 你自己的板子
└── myboard/
每个板级目录里通常有:
- board.c —— 板级初始化函数(board_init、dram_init等)
- Kconfig —— 板级配置选项
- Makefile —— 编译规则
- imximage.cfg —— 镜像头配置(i.MX系列特有)
我的习惯:拿到一块新板子,先找board/下有没有参考设计。比如你用TI AM335x,直接复制board/ti/am335x/,改个名字,再改改内存参数和引脚配置。能省一半时间。
2.2.3 drivers/ —— 外设驱动的“大仓库”
这个目录按设备类型分:
| 子目录 | 功能 | 常见文件 |
|---|---|---|
| drivers/net/ | 网络接口驱动 | phy.c, designware.c, fec_mxc.c |
| drivers/mmc/ | SD/eMMC驱动 | sdhci.c, dw_mmc.c |
| drivers/spi/ | SPI总线驱动 | spi_flash.c, fsl_qspi.c |
| drivers/i2c/ | I2C总线驱动 | i2c_core.c, mvtwsi.c |
| drivers/usb/ | USB主机/设备驱动 | ehci-hcd.c, dwc2.c |
| drivers/video/ | 显示驱动 | simple_panel.c, rockchip_display.c |
你想想看,U-Boot的网络启动,核心就在 drivers/net/ 里。PHY芯片初始化、MAC控制器配置、MDIO总线通信,全在这。我调试网络启动时,经常要加打印看phy_read()的返回值,确认link状态。
2.2.4 common/ —— 通用功能“瑞士军刀”
这个目录放的是U-Boot的通用模块:
- main.c —— U-Boot主循环(命令行解析入口)
- command.c —— 命令注册框架
- console.c —— 控制台输入输出
- env_common.c —— 环境变量管理
- bootm.c —— 启动内核的核心函数
- autoboot.c —— 自动启动逻辑
说白了,你在U-Boot命令行敲的每个命令,背后都是common/里的代码在支撑。比如你敲 bootm 0x82000000,最终会调用到 common/bootm.c 里的 do_bootm() 函数。
2.2.5 其他重要目录
- net/ —— 网络协议栈。TFTP、NFS、DHCP的客户端实现都在这里。网络启动时,这个目录和drivers/net/配合工作。
- fs/ —— 文件系统支持。ext4、fat、ubifs等。你从TFTP下载内核后,如果要从eMMC的ext4分区读取设备树,就靠它。
- dts/ —— 设备树源文件。现代U-Boot几乎必用设备树,板级硬件描述全在这里。
- configs/ —— 板级默认配置。这个咱们下面重点说。
2.3 配置文件体系:U-Boot的“基因”
U-Boot的配置体系,我当年学的时候觉得挺绕。其实就三层:
- 板级默认配置(configs/xxx_defconfig)
- Kconfig菜单系统(各目录下的Kconfig文件)
- 头文件配置(include/configs/xxx.h)—— 老版本方式,新版本逐渐淘汰
咱们重点说前两个,因为这是现在的主流做法。
2.3.1 defconfig —— 板子的“身份证”
每个板子对应一个 defconfig 文件,放在 configs/ 目录下。比如:
# configs/myboard_defconfig
CONFIG_ARM=y
CONFIG_ARCH_MX6=y
CONFIG_TARGET_MYBOARD=y
CONFIG_DM=y
CONFIG_DM_ETH=y
CONFIG_ETH_DESIGNWARE=y
CONFIG_PHYLIB=y
CONFIG_CMD_DHCP=y
CONFIG_CMD_TFTP=y
CONFIG_BOOTCOMMAND="tftp 0x82000000 zImage; tftp 0x83000000 myboard.dtb; bootz 0x82000000 - 0x83000000"
CONFIG_BOOTARGS="console=ttymxc0,115200 root=/dev/nfs rw"
这个文件决定了:
- 用什么CPU架构
- 用什么板级代码
- 开启哪些驱动
- 开启哪些命令
- 默认启动命令是什么
我曾经踩过的坑:有次我改了defconfig,加了CONFIG_CMD_PING=y,但编译后ping命令还是不能用。查了半天,发现Kconfig里这个选项依赖CONFIG_NET,而我没开。所以改defconfig时,一定要看依赖链。
2.3.2 Kconfig —— 配置的“菜单树”
Kconfig文件定义了所有可配置选项的层次结构。比如你想知道“为什么我的板子没有TFTP命令”,就去查:
# net/Kconfig
config CMD_TFTP
bool "tftp command"
depends on NET
help
TFTP download command for network boot
配置流程是这样的:
make myboard_defconfig # 加载默认配置
make menuconfig # 进入图形化菜单,微调配置
make # 编译
menuconfig界面里,你可以按空格开关功能,按Y/N选择。我个人习惯是先加载defconfig,再用menuconfig微调,最后 make savedefconfig 生成新的defconfig。
2.4 一张图看懂U-Boot源码结构
下面这张SVG图,把U-Boot源码的核心层次和配置体系串起来了。你盯着看一分钟,比读十页文档管用。
2.5 小结:你该记住什么
这一章信息量不小,我帮你划重点:
- arch/ 和 board/ 是移植的核心,其他目录尽量别动
- drivers/ 是外设驱动的集合,网络启动重点关注 drivers/net/
- common/ 是U-Boot的大脑,命令和启动逻辑都在这里
- configs/ 里的defconfig是板子的“基因”,决定了U-Boot的功能集
- 配置体系是 defconfig → Kconfig → 编译 的三步走