U-Boot

一、什么是 U-Boot

二、获取源码

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/.h 中定义默认值。

七、自动启动

# 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

十二、调试