U-Boot
一、什么是 U-Boot
- Das U-Boot:开源 bootloader,ARM/MIPS/PowerPC/RISC-V 通用
- 由 DENX 维护
- 几乎是嵌入式 Linux 标配
二、获取源码
git clone https://source.denx.de/u-boot/u-boot.git
# 或
git clone https://github.com/u-boot/u-boot.git
git checkout v2024.01
厂商 fork:
- NXP:git clone https://github.com/nxp-imx/uboot-imx
- ST:git clone https://github.com/STMicroelectronics/u-boot
三、编译
1. 配置
make myboard_defconfig
make menuconfig # 进一步调整
常用 defconfig:
imx6ull_myboard_defconfig
rpi_4_defconfig
zynq_zc706_defconfig
2. 编译
make CROSS_COMPILE=arm-linux-gnueabihf- -j$(nproc)
# 输出
├── u-boot ELF
├── u-boot.bin 二进制
├── u-boot.img 含 mkimage 头(uImage)
├── u-boot-spl SPL
├── u-boot-spl.bin SPL 二进制
├── MLO SPL + 头(OMAP 风格)
└── spl/u-boot-spl.bin 默认 SPL 位置
四、目录结构
├── arch/arm/ 架构相关
│ ├── cpu/ CPU 初始化
│ ├── lib/ 汇编工具
│ └── mach-xxx/ SoC 板级代码
├── board/ 板级代码
├── cmd/ 命令(bootm、loadb、...)
├── common/ 通用代码
│ ├── board_r.c 重定位后初始化
│ └── board_f.c 前初始化
├── configs/ defconfig
├── drivers/ 驱动(mmc、net、serial、...)
├── dts/ 设备树
├── include/
├── lib/ 通用库(crc、lzma、...)
├── net/ 网络协议
├── fs/ 文件系统(fat、ext4、...)
├── tools/ 工具(mkimage、mkimage-spl)
├── test/ 测试
├── doc/ 文档
├── Kconfig
├── Makefile
└── README
五、U-Boot 命令
printenv # 打印环境变量
setenv foo bar # 设置
saveenv # 保存到 flash
editenv foo # 编辑
# 内存
md 0x80000000 100 # 内存显示
mw 0x80000000 0x12345678 # 内存写
cp 0x80000000 0x80100000 100 # 复制
cmp a b 100 # 比较
loop 0xAABBCCDD # 进入死循环(reset)
# Flash
sf probe # 探测 SPI flash
sf read 0x80800000 0 0x100000 # 读
sf write 0x80800000 0 0x100000 # 写
# 网络
dhcp
ping 192.168.1.1
tftp 0x80800000 uImage
tftpboot $fdt_addr_r myboard.dtb
# MMC
mmc info
mmc list
mmc dev 1 # 选择 MMC
mmc read 0x80800000 0 0x200 # 读 0x200 块到 0x80800000
mmc write 0x80800000 0 0x200
fatls mmc 1:1
fatload mmc 1:1 0x80800000 uImage
# USB
usb start
usb info
fatload usb 0:1 ...
# 引导
bootm 0x80800000 # uImage
bootm 0x80800000 - 0x83000000 # 含 dtb
bootz 0x80800000 - 0x83000000 # zImage
bootefi 0x80800000 # EFI
bootm 0x80800000 0x82000000 0x83000000 # ramdisk
# 其他
reset
version
bdinfo
printenv
六、环境变量
# 关键环境变量
bootargs=console=ttymxc0,115200 root=/dev/mmcblk0p2 rootwait
bootcmd=mmc dev 1; load mmc 1:1 ${loadaddr} zImage; load mmc 1:1 ${fdt_addr_r} myboard.dtb; bootz ${loadaddr} - ${fdt_addr_r}
# 自定义环境变量
myvar=hello
# 常用变量
loadaddr=0x80800000 # 内核加载地址
fdt_addr_r=0x83000000 # dtb 地址
ramdisk_addr_r=0x84000000 # initramfs 地址
在 include/configs/
七、自动启动
# autoboot 等待时间(毫秒)
CONFIG_AUTOBOOT_KEYED
CONFIG_BOOTDELAY=3
# 倒计时期间按任意键进入命令行
八、U-Boot 启动流程
reset
↓
_start (arch/arm/lib/crt0.S)
↓
lowlevel_init → 初始化栈 → 复制自身到 RAM → 清 BSS
↓
board_init_f() (common/board_f.c)
- 早期初始化:DRAM、串口、MMC
↓
relocate_code() 重定位
↓
board_init_r() (common/board_r.c)
- 后期初始化:环境变量、Flash、网络
↓
main_loop()
- autoboot 倒计时
- 命令行
九、设备树在 U-Boot
# 启动时打印
Model: MY Board
设备树 blob 通常从内核传给 OS(bootm $kernel - $fdt)。
U-Boot 也可用 fdt 命令操作:
fdt addr 0x83000000
fdt print
fdt set /soc/uart1 status "disabled"
十、自定义启动脚本
# bootcmd 完整示例
setenv bootcmd '
mmc dev ${mmcdev};
if mmc rescan; then
if load mmc ${mmcdev}:1 ${loadaddr} ${bootfile}; then
load mmc ${mmcdev}:1 ${fdt_addr_r} ${fdtfile};
bootz ${loadaddr} - ${fdt_addr_r};
fi;
fi;
'
saveenv
十一、烧录
# 通过 JTAG / OpenOCD
openocd -f board/myboard.cfg
# 通过 SD 卡
sudo dd if=u-boot.imx of=/dev/sdX bs=1k seek=1 status=progress
# 通过 U-Boot 自身
# 网络烧录
tftp 0x80800000 u-boot.bin
sf erase 0 0x100000
sf write 0x80800000 0 0x100000
十二、调试
- 加
#define DEBUG重新编译 - printf / pr_info / pr_debug
- 串口日志
- JTAG + GDB