3. u-boot基础与编译:u-boot简介、源码获取、配置与编译流程(以ARM架构vexpress-a9为例)
u-boot(Das U-Boot)是嵌入式Linux系统中使用最广泛的引导加载程序(Bootloader),负责初始化硬件、加载操作系统内核并传递启动参数。本章将系统讲解u-boot的核心概念、源码获取方式、针对ARM架构vexpress-a9开发板的配置与编译流程,以及编译生成的关键文件。
3.1 u-boot简介
u-boot是一个开源、多架构支持的引导加载程序,支持ARM、x86、RISC-V、MIPS等多种处理器架构。在嵌入式系统中,u-boot承担以下核心职责:
- 硬件初始化:设置时钟、内存控制器、串口等外设,使系统达到可用状态。
- 引导内核:从存储介质(Flash、SD卡、网络等)读取内核映像,跳转到内核入口。
- 提供命令行接口:允许开发者交互式调试、修改启动参数、烧写固件。
- 支持多种启动设备:NAND/NOR Flash、MMC/SD卡、USB、网络(TFTP)等。
3.2 源码获取
u-boot源码托管在多个公共仓库中,推荐使用官方Git仓库获取最新稳定版本。以下是常用的获取方式:
| 获取方式 | 命令/地址 | 说明 |
|---|---|---|
| Git克隆(官方) | git clone https://source.denx.de/u-boot/u-boot.git |
获取主线最新开发版本 |
| Git克隆(镜像) | git clone https://github.com/u-boot/u-boot.git |
GitHub镜像,国内访问较快 |
| 下载稳定版tarball | wget https://ftp.denx.de/pub/u-boot/u-boot-2024.01.tar.bz2 |
指定版本,适合教学环境 |
获取源码后,进入目录查看顶层结构:
cd u-boot-2024.01
ls -F
arch/ board/ configs/ doc/ drivers/ dts/
fs/ include/ lib/ net/ scripts/ tools/
Makefile Kconfig README
关键目录说明:
- arch/:架构相关代码,ARM代码位于
arch/arm/。 - board/:板级支持包,vexpress-a9相关代码位于
board/armltd/vexpress/。 - configs/:默认配置文件,命名格式为
<board>_defconfig。 - dts/:设备树源文件,vexpress-a9的设备树位于
arch/arm/dts/vexpress-v2p-ca9.dts。
3.3 配置与编译流程
u-boot采用Kconfig配置系统(类似Linux内核),配置流程分为两步:配置和编译。以下以vexpress-a9开发板为例,演示完整操作。
3.3.1 配置
vexpress-a9开发板对应的默认配置文件为 vexpress_ca9x4_defconfig。执行配置命令:
make vexpress_ca9x4_defconfig
该命令会读取 configs/vexpress_ca9x4_defconfig 文件,生成 .config 配置文件。如需自定义配置,可运行:
make menuconfig
menuconfig提供图形化界面,允许开发者调整驱动、命令、文件系统等选项。
arm-linux-gnueabihf- 工具链,可通过 apt install gcc-arm-linux-gnueabihf 安装。
3.3.2 编译
配置完成后,执行编译命令。需指定交叉编译工具链前缀:
export CROSS_COMPILE=arm-linux-gnueabihf-
make -j$(nproc)
编译过程会依次执行:编译设备树、编译架构代码、编译驱动、链接生成最终映像。成功编译后,终端输出类似:
LD u-boot
OBJCOPY u-boot.srec
OBJCOPY u-boot.bin
SYM u-boot.sym
CFG u-boot.cfg
MKIMAGE u-boot.img
CROSS_COMPILE:指定交叉编译工具链前缀,必须与目标架构匹配。ARCH:指定目标架构,ARM架构设置为 ARCH=arm(通常由defconfig自动设置)。-j$(nproc):并行编译,加速构建过程。
3.4 生成的关键文件
编译完成后,在源码根目录下生成多个重要文件。下表列出核心输出及其用途:
| 文件名 | 格式 | 大小(典型值) | 用途 |
|---|---|---|---|
| u-boot.bin | 纯二进制 | ~500KB | 可直接烧录到Flash或由QEMU加载的原始映像 |
| u-boot.elf | ELF | ~2MB | 包含调试符号,用于GDB调试、QEMU -kernel加载 |
| u-boot | ELF(无扩展名) | ~2MB | 链接生成的原始ELF文件,与u-boot.elf等价 |
| u-boot.img | uImage格式 | ~500KB | 包含u-boot头部的映像,用于某些启动方式 |
| u-boot.srec | Motorola S-record | ~1.5MB | ASCII格式的映像,用于串口烧录 |
| u-boot.sym | 符号表 | ~100KB | 函数符号地址映射,辅助调试 |
3.4.1 u-boot.bin 与 u-boot.elf 的差异
这两个文件是调试过程中最常使用的,理解其差异至关重要:
- u-boot.bin:去除了所有调试信息和ELF头部,是纯粹的机器码映像。QEMU加载时直接将其内容放到指定内存地址,不解析任何元数据。
- u-boot.elf:保留ELF文件格式,包含段表、符号表、调试信息(如DWARF)。QEMU的
-kernel选项可以解析ELF文件,自动将各段加载到正确地址,并读取入口点。
-kernel u-boot.elf 加载,配合GDB的 symbol-file u-boot.elf 加载符号,可实现源码级调试。
3.4.2 验证编译产物
使用以下命令检查生成文件的格式和入口地址:
# 查看u-boot.elf的入口地址
arm-linux-gnueabihf-readelf -h u-boot.elf | grep Entry
# 查看u-boot.bin的起始内容(前16字节)
hexdump -C u-boot.bin | head -2
# 查看符号表,定位start_code
arm-linux-gnueabihf-nm u-boot.elf | grep start_code
典型输出示例:
Entry point address: 0x60000000
00000000 13 00 00 ea 14 f0 9f e5 14 f0 9f e5 14 f0 9f e5 |................|
60000000 T _start
60000020 T _main
入口地址 0x60000000 对应vexpress-a9开发板的DDR起始地址,u-boot被编译为从该地址运行。
3.5 常见编译问题与解决
| 问题现象 | 可能原因 | 解决方案 |
|---|---|---|
arm-linux-gnueabihf-gcc: command not found |
交叉编译工具链未安装 | sudo apt install gcc-arm-linux-gnueabihf |
*** Your GCC is too old |
主机GCC版本过低 | 升级GCC或使用容器化编译环境 |
undefined reference to `__aeabi_*' |
工具链与架构不匹配 | 确认使用arm-linux-gnueabihf而非arm-linux-gnueabi |
make: *** No rule to make target 'vexpress_ca9x4_defconfig' |
拼写错误或版本不支持 | 执行 make help 查看支持的defconfig列表 |
python3 --version 检查版本。
3.6 本章小结
本章完成了u-boot的基础知识学习,包括:
- u-boot在嵌入式启动流程中的核心地位
- 从官方仓库获取源码的多种方式
- 针对vexpress-a9开发板的配置与编译完整流程
- 编译生成的关键文件(u-boot.bin、u-boot.elf等)及其用途
- 常见编译问题的排查方法