3. 开发环境搭建
拿到一份U-Boot源码,很多人第一反应是懵的。几百个文件夹,几千个文件,从哪看起?
我刚开始接触U-Boot时也这样。后来带团队做移植,慢慢摸清了门道。说白了,U-Boot的目录结构设计得挺讲究——它把硬件相关、硬件无关、命令处理、驱动框架分得清清楚楚。
这一章,我就带你把这些关键目录挨个捋一遍。
3.1 顶层目录:U-Boot的“总指挥部”
先看顶层。你解压U-Boot源码后,第一眼看到的就是这些:
u-boot/
├── arch/ # 架构相关代码(CPU体系结构)
├── board/ # 板级相关代码(具体开发板)
├── common/ # 通用功能模块
├── cmd/ # 命令行命令实现
├── drivers/ # 设备驱动
├── include/ # 头文件
├── lib/ # 库函数
├── net/ # 网络协议栈
├── fs/ # 文件系统支持
├── disk/ # 磁盘分区处理
├── dts/ # 设备树源文件
├── scripts/ # 编译脚本、配置工具
├── tools/ # 主机端工具
├── configs/ # 默认配置文件(defconfig)
├── Makefile # 顶层Makefile
└── Kconfig # 顶层Kconfig配置菜单
顶层目录里,Makefile和Kconfig是编译系统的入口。你执行make menuconfig时,读的就是Kconfig;你执行make时,顶层Makefile会递归进入各个子目录。
ARCH和CROSS_COMPILE变量。这两个变量设对了,编译才可能过。
3.2 arch目录:CPU架构的“心脏”
arch/目录存放的是与CPU体系结构直接相关的代码。不同架构的CPU,启动流程、寄存器操作、异常处理完全不同,这些差异全收在这里。
arch/
├── arm/ # ARM架构(最常用)
│ ├── cpu/ # 具体CPU型号(armv7、armv8等)
│ ├── include/ # 架构相关头文件
│ ├── lib/ # 架构通用库函数
│ ├── mach-*/ # 厂商/SoC系列(mach-sunxi、mach-rockchip等)
│ └── dts/ # 架构级设备树
├── riscv/ # RISC-V架构
├── x86/ # x86架构
├── mips/ # MIPS架构
├── powerpc/ # PowerPC架构
└── sandbox/ # 模拟测试架构
以ARM为例,arch/arm/cpu/下面按ARMv7、ARMv8等版本分目录。每个目录里都有start.S——这是U-Boot的第一条指令,负责初始化CPU、设置栈指针、跳转到C语言入口。
arch/。但如果换了一个新架构(比如从ARM换成RISC-V),那arch/几乎要重写。
3.3 board目录:板级定制的“战场”
这是移植工作中改动最多的目录。board/下面按厂商或板子型号组织,存放与具体硬件平台相关的初始化代码。
board/
├── allwinner/ # 全志系列
│ ├── sunxi/ # sunxi平台通用
│ └── orangepi_zero2/ # 具体板子
├── rockchip/ # 瑞芯微系列
│ ├── common/ # Rockchip通用代码
│ └── evb_rk3568/ # 具体评估板
├── freescale/ # 飞思卡尔/NXP系列
└── ...
每个板子目录里通常包含:
board.c:板级初始化函数,比如DDR初始化、GPIO配置、时钟设置Kconfig:板级配置选项Makefile:编译规则lowlevel_init.S:极早期汇编初始化(有些板子放在这里)
3.4 common目录:通用功能的“工具箱”
common/目录存放的是与硬件无关的通用代码。不管你的板子是ARM还是RISC-V,这些代码基本都能直接用。
| 文件/子目录 | 作用 |
|---|---|
main.c |
U-Boot主循环,命令解析入口 |
board_r.c |
板级运行时初始化(第二阶段) |
board_f.c |
板级前初始化(第一阶段,在relocate之前) |
console.c |
控制台输入输出管理 |
env_*.c |
环境变量存储与加载(env_nand.c、env_mmc.c等) |
image.c |
镜像格式解析(uImage、FIT等) |
autoboot.c |
自动启动逻辑(倒计时、bootcmd执行) |
你想想看,common/main.c里的main_loop()函数,就是U-Boot启动后等待你输入命令的地方。这个函数在所有板子上都一样——它只负责“读命令、找命令、执行命令”。
3.5 cmd目录:命令的“仓库”
你在U-Boot命令行里敲的每一个命令,实现代码都在cmd/目录下。
cmd/
├── bootm.c # bootm命令(启动内核)
├── go.c # go命令(跳转到指定地址)
├── load.c # 文件加载命令(loadb、loadx等)
├── mmc.c # mmc命令(MMC/SD卡操作)
├── nand.c # nand命令(NAND Flash操作)
├── net.c # 网络命令(ping、tftpboot等)
├── fat.c # fat命令(FAT文件系统操作)
├── ext4.c # ext4命令(ext4文件系统操作)
├── gpio.c # gpio命令(GPIO操作调试)
├── i2c.c # i2c命令(I2C总线操作)
├── sf.c # sf命令(SPI Flash操作)
├── usb.c # usb命令(USB操作)
└── ...
每个命令文件的结构很固定:一个do_xxx()函数实现命令逻辑,一个U_BOOT_CMD宏注册命令。比如:
static int do_gpio(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
{
// 命令处理逻辑
return 0;
}
U_BOOT_CMD(
gpio, 4, 0, do_gpio,
"GPIO 操作命令",
"set <pin> <value> - 设置GPIO输出值\n"
"get <pin> - 读取GPIO输入值"
);
cmd/gpio.c和cmd/i2c.c编译进去。硬件出问题时,用gpio命令点灯、用i2c命令读传感器,比加打印快多了。
3.6 drivers目录:设备驱动的“大本营”
drivers/是U-Boot里代码量最大的目录。它按设备类型组织,每个子目录对应一类外设驱动。
drivers/
├── serial/ # 串口驱动(调试串口最关键)
├── mmc/ # MMC/SD卡驱动
├── net/ # 网卡驱动(以太网PHY、MAC)
├── spi/ # SPI总线驱动
├── i2c/ # I2C总线驱动
├── gpio/ # GPIO控制器驱动
├── usb/ # USB主机/设备驱动
├── mtd/ # MTD设备驱动(NAND、SPI Flash)
├── video/ # 显示驱动(LCD、HDMI)
├── pinctrl/ # 引脚控制驱动
├── clk/ # 时钟驱动
├── power/ # 电源管理驱动(PMIC)
└── ...
U-Boot的驱动模型(Driver Model,简称DM)从2014年开始引入。现在新版本的U-Boot,大部分驱动都基于DM框架。DM的好处是:驱动代码可以复用,板子只需要在设备树里描述硬件连接,驱动就能自动匹配。
drivers/serial/里有没有对应SoC的串口驱动,没有就自己写。
3.7 目录关系:一张图看懂
这些目录不是孤立的。它们通过编译系统和初始化流程串联起来。下面这张图展示了关键目录之间的关系:
从这张图能看出:
- 编译阶段:顶层Makefile根据你选的
ARCH和BOARD,决定编译哪些目录 - 启动阶段:先跑
arch/里的汇编代码,再进board/做板级初始化,然后common/接管通用流程,最后进入main_loop等待命令 - 运行阶段:你敲命令,
cmd/里的代码被调用;命令需要操作硬件时,调用drivers/里的驱动
3.8 其他重要目录
除了上面几个核心目录,还有几个也值得了解:
| 目录 | 作用 | 移植时关注度 |
|---|---|---|
include/ |
头文件,包括configs/下的板级配置头文件 |
高(要改配置宏) |
dts/ |
设备树源文件(.dts、.dtsi),描述硬件拓扑 | 高(新板子要写dts) |
configs/ |
默认配置文件(xxx_defconfig) | 高(要新建defconfig) |
lib/ |
通用库函数(字符串、数学、加密等) | 低(基本不用动) |
net/ |
网络协议栈(ARP、IP、UDP、TFTP等) | 中(网卡驱动调通后可用) |
fs/ |
文件系统支持(FAT、ext4、UBIFS等) | 中(需要文件系统操作时关注) |
tools/ |
主机端工具(mkimage、fdtgrep等) | 低(编译时自动构建) |
3.9 小结:移植时你该关注哪些目录?
总结一下,如果你要做U-Boot移植,按优先级关注这些目录:
- 第一优先级:
board/(板级代码)、include/configs/(配置头文件)、configs/(defconfig) - 第二优先级:
dts/(设备树)、drivers/(外设驱动,特别是serial和mmc) - 第三优先级:
arch/(如果CPU架构已支持,基本不动) - 基本不动:
common/、cmd/、lib/、net/、fs/