3. U-Boot源码结构解析:顶层目录结构、board与arch目录、configs与include/configs目录、scripts与tools目录
U-Boot的源码,说实话,第一次打开的时候确实会让人有点懵。我当年刚接触时,面对那一堆文件夹,心里直犯嘀咕:「这玩意儿从哪看起?」但只要你摸清了它的骨架,就会发现——其实它设计得相当清晰。
这一章,我就带你把这棵「源码树」从上到下捋一遍。咱们不追求面面俱到,而是抓住那些你移植时真正会碰到的目录。
3.1 顶层目录结构:一眼看穿U-Boot的家底
先看根目录。你执行 ls 后,会看到几十个文件夹和文件。别慌,我帮你把它们分成几类:
| 类别 | 目录/文件 | 一句话说明 |
|---|---|---|
| 核心代码 | arch/, board/, common/, drivers/ |
架构、板级、通用逻辑、驱动——移植主要动这里 |
| 配置体系 | configs/, include/configs/, Kconfig |
板级默认配置与头文件宏定义 |
| 构建工具 | scripts/, tools/, Makefile |
编译脚本、打包工具、镜像生成器 |
| 文档与示例 | doc/, examples/, api/ |
参考手册、API示例、Standalone程序 |
| 测试与维护 | test/, .gitignore, MAINTAINERS |
单元测试、版本管理、维护者列表 |
board/ 和 configs/ 这两个目录。它们能最快告诉你这个BSP支持哪些硬件、默认配置长什么样。
3.2 board与arch目录:板级与架构的「双核」
这两个目录是移植工作的主战场。说白了,arch/ 管CPU的事,board/ 管板子的事。
3.2.1 arch/:架构相关代码
进去看看,里面按CPU架构分文件夹:
arch/
├── arm/ # ARM架构(最常用)
│ ├── cpu/ # 具体CPU核:armv7, armv8, cortex-m...
│ ├── include/ # 架构级头文件
│ ├── lib/ # 架构公共函数
│ └── mach-xxx/ # SoC厂商相关:mach-sunxi, mach-imx...
├── riscv/ # RISC-V架构
├── x86/ # x86架构
└── sandbox/ # 模拟调试用
我记得有一次移植一个新款i.MX芯片,死活起不来。折腾了两天,最后发现是 arch/arm/mach-imx/ 下的时钟初始化代码里,PLL配置参数写错了。嗯,从那以后我养成了一个习惯——先看 mach-xxx/ 目录下的 Kconfig 和 Makefile,确认SoC型号有没有被正确选中。
3.2.2 board/:板级专属代码
这个目录的结构通常是 board/<厂商>/<板子名>/。比如:
board/
├── freescale/
│ ├── mx6ul_14x14_evk/
│ └── ls1046ardb/
├── rockchip/
│ ├── evb_rk3399/
│ └── tinker_board/
└── mycompany/ # 你自己的板子
└── myboard_v1/
每个板子目录下一般有这些文件:
Kconfig:板级配置选项MAINTAINERS:谁负责维护这块板Makefile:编译哪些文件board.c:板级初始化函数(board_init_f,board_init_r)dram.c:DDR初始化(这块最容易出问题)imximage.cfg或u-boot.lds:链接脚本或镜像头配置
board.c,结果GPIO初始化顺序不对,导致eMMC死活识别不了。后来花了半天逐行对比原理图才找到问题。所以——board目录下的代码,一定要对着你的原理图逐行确认,别偷懒。
3.3 configs与include/configs目录:配置的「双保险」
U-Boot的配置体系,说白了有两套机制在并行工作。理解它们,你才能知道改配置时该动哪里。
3.3.1 configs/:默认配置(defconfig)
这个目录下全是 xxx_defconfig 文件。每个文件对应一块板子的默认配置。比如:
configs/
├── mx6ul_14x14_evk_defconfig
├── rpi_3_defconfig
└── myboard_v1_defconfig
文件内容长这样:
CONFIG_ARM=y
CONFIG_TARGET_MYBOARD_V1=y
CONFIG_DM_MMC=y
CONFIG_BAUDRATE=115200
# CONFIG_SPL is not set
这里每一行都是一个Kconfig选项。你执行 make myboard_v1_defconfig 时,U-Boot就会根据这个文件生成完整的 .config。
3.3.2 include/configs/:传统头文件配置
这是U-Boot的「老派」配置方式。虽然现在Kconfig逐渐成为主流,但很多板子仍然保留着头文件配置。比如:
include/configs/
├── mx6ul_14x14_evk.h
└── myboard_v1.h
头文件里定义的是C语言的宏:
#define CONFIG_SYS_TEXT_BASE 0x87800000
#define CONFIG_SYS_MALLOC_LEN (16 << 20)
#define CONFIG_BOOTCOMMAND "run distro_bootcmd"
#define CONFIG_BAUDRATE 115200
configs/里的defconfig:控制「编译哪些模块」——用Kconfig的y/n/m语法。include/configs/里的头文件:控制「参数值是多少」——用C语言的#define语法。
你想想看,如果你要改DDR的基地址,该改哪里?对,头文件里的 CONFIG_SYS_TEXT_BASE。如果你要关掉某个驱动,该改哪里?defconfig里的 # CONFIG_XXX is not set。
3.4 scripts与tools目录:幕后英雄
这两个目录平时你可能不怎么直接碰,但编译和打包时,它们一直在默默干活。
3.4.1 scripts/:构建脚本与规则
这里存放的是Kconfig解析器、构建辅助脚本、DTB编译规则等。几个重要的:
scripts/kconfig/:Kconfig前端(menuconfig的图形界面就靠它)scripts/Makefile.*:各种编译规则片段scripts/dtc/:设备树编译器(dtc)的包装脚本scripts/basic/:fixdep等依赖生成工具
说实话,我很少直接改这里的东西。但有一次我需要给U-Boot加一个自定义的镜像签名步骤,就是在 scripts/Makefile.spl 里加了一段post-processing规则。
3.4.2 tools/:主机端工具集
这个目录下的工具,是在你的PC上运行的,用来处理镜像文件。常用的有:
| 工具 | 用途 | 我什么时候用过它 |
|---|---|---|
mkimage |
制作U-Boot可识别的镜像头 | 每次烧写内核时都要用 |
fdtgrep |
过滤/裁剪设备树 | SPL中为了减小体积,只保留必要节点 |
imx_mkimage |
生成i.MX系列专用的启动镜像 | 做i.MX板子时,这步绕不开 |
sunxi-tools |
全志系列的工具链 | 调试全志芯片时配合使用 |
envtools |
在PC上读写U-Boot环境变量 | 批量生产时,用脚本预设环境变量 |
mkimage 报错说「bad magic number」,八成是你传给它的镜像类型参数不对。用 mkimage -l <镜像文件> 可以查看现有镜像头信息,对照着改就行了。
3.5 本章知识结构图
下面这张图,帮你把U-Boot源码的「骨架」串起来。你可以把它当作一张地图,以后移植时,按图索骥就行。
嗯,这张图基本把U-Boot源码的「骨架」画清楚了。你以后做移植时,可以把它当作一张地图——从 configs/ 找到入口,到 board/ 和 arch/ 里改代码,最后用 tools/ 里的工具打包验证。每一步该去哪,心里就有数了。