4. U-Boot基础与配置:U-Boot源码结构、编译配置(defconfig)、设备树(dts)在U-Boot中的作用、常用命令与脚本化

U-Boot(Das U-Boot)是嵌入式Linux系统中应用最广泛的引导加载程序(Bootloader)。它负责初始化硬件、加载内核和设备树,并将控制权移交给操作系统。本章将深入剖析U-Boot的源码结构、配置体系、设备树的作用以及常用命令与脚本化方法,为后续的启动优化打下坚实基础。

4.1 U-Boot源码结构

U-Boot的源码采用模块化、层次化的组织方式,主要分为平台相关代码、通用驱动、命令处理、文件系统支持等部分。理解其目录结构是进行定制和优化的前提。

核心目录说明:
  • arch/:存放与CPU架构相关的代码,如arm、riscv、x86等。每个架构下又细分board、cpu、include等子目录。
  • board/:特定板级(Board)的初始化代码,包括内存初始化、引脚复用、时钟配置等。
  • configs/:存放所有支持的板级默认配置文件(defconfig),是编译配置的入口。
  • drivers/:各类设备驱动,如串口、网卡、MMC、NAND Flash、USB等。
  • cmd/:U-Boot命令行命令的实现,如bootm、load、setenv等。
  • common/:通用功能模块,如控制台、环境变量、HUSH shell等。
  • dts/:设备树源文件(.dts)和绑定(bindings),用于描述硬件拓扑。
  • include/:全局头文件,包括配置宏、数据结构定义等。
  • net/:网络协议栈实现,支持TFTP、NFS、DHCP等。
  • fs/:文件系统支持,如ext4、fat、ubifs等。
U-Boot 源码结构层次图 U-Boot 源码根目录 arch/ board/ configs/ drivers/ cmd/ arm/ riscv/ x86/ ti/ rockchip/ nxp/ serial/ mmc/ net/ boot.c load.c mem.c 说明:U-Boot 源码通过 Kconfig / Makefile 体系将 arch、board、drivers 等模块组合成最终的二进制文件。

4.2 编译配置:defconfig 体系

U-Boot 采用 Kconfig 配置系统(与Linux内核类似),通过 make menuconfig 或直接编辑 defconfig 文件来定制功能。默认配置文件位于 configs/ 目录下,命名规则通常为 <board_name>_defconfig。

4.2.1 配置流程

  1. 选择默认配置:make <board_name>_defconfig,例如 make stm32mp157d_atk_defconfig。
  2. 自定义配置(可选):make menuconfig 进行图形化调整。
  3. 保存配置:make savedefconfig 生成精简的 defconfig 文件。
  4. 编译:make 生成 u-boot.bin 或 u-boot.itb。

4.2.2 defconfig 文件示例

# configs/stm32mp157d_atk_defconfig
CONFIG_ARM=y
CONFIG_TARGET_STM32MP15X=y
CONFIG_DEFAULT_DEVICE_TREE="stm32mp157d-atk"
CONFIG_SYS_EXTRA_OPTIONS="RAM_BASE=0xC0000000"
CONFIG_BOOTCOMMAND="ext4load mmc 0:4 0xC2000000 /boot/Image; ext4load mmc 0:4 0xC4000000 /boot/stm32mp157d-atk.dtb; booti 0xC2000000 - 0xC4000000"
CONFIG_CMD_EXT4=y
CONFIG_CMD_FAT=y
CONFIG_CMD_NET=y
CONFIG_CMD_PING=y
CONFIG_NET_RANDOM_ETHADDR=y
# CONFIG_VIDEO is not set
优化提示: 在启动优化场景中,应通过 defconfig 禁用不必要的驱动和命令(如 CONFIG_CMD_USB、CONFIG_CMD_SOUND),以减小U-Boot体积并缩短加载时间。使用 make savedefconfig 可以自动生成最小化配置。

4.3 设备树(DTS)在U-Boot中的作用

设备树(Device Tree)是一种描述硬件拓扑结构的数据结构,在U-Boot中扮演着关键角色。U-Boot使用设备树来获取板级硬件信息,从而避免为每个板子编写硬编码的初始化代码。

4.3.1 设备树在U-Boot中的主要用途

用途 说明
硬件探测 U-Boot在启动早期解析设备树,获取内存基址与大小、时钟频率、外设地址等。
驱动匹配 U-Boot驱动模型(Driver Model)通过设备树中的 compatible 属性匹配对应的驱动。
内核传递 U-Boot将设备树二进制(DTB)加载到内存,并在跳转内核时通过寄存器传递DTB地址。
配置覆盖 通过设备树覆盖(overlay)机制,可以在不修改主DTB的情况下调整硬件配置。

4.3.2 U-Boot中的设备树处理流程

U-Boot 设备树处理流程 DTS 源文件 DTC 编译 DTB 二进制 U-Boot 解析 DTB 驱动模型初始化 传递 DTB 给内核 关键点:U-Boot 使用 fdt 命令可以在运行时修改设备树,例如设置内核启动参数(chosen 节点)。

4.4 常用命令与脚本化

U-Boot提供了一套丰富的命令行接口,用于调试、加载镜像、配置环境变量和启动系统。在启动优化中,脚本化是减少人工干预、实现自动化启动的关键手段。

4.4.1 核心命令分类

类别 命令 功能描述
存储操作 mmc read / mmc write 从/向 MMC/SD 卡读写数据
存储操作 sf read / sf write 从/向 SPI Flash 读写数据
网络操作 tftp 通过 TFTP 协议从服务器下载文件
网络操作 dhcp 通过 DHCP 获取 IP 地址
文件系统 ext4load / fatload 从 ext4/FAT 文件系统加载文件到内存
内存操作 md / mw 内存显示与写入
设备树 fdt 设备树操作(设置、查看、修改)
启动 booti / bootm 启动内核镜像(booti 用于 AArch64,bootm 用于 uImage)
环境变量 setenv / saveenv 设置/保存环境变量

4.4.2 脚本化启动示例

U-Boot支持HUSH shell脚本语法,可以将多个命令组合成自动执行序列。以下是一个典型的脚本化启动流程:

# 设置环境变量 bootcmd
setenv bootcmd 'echo "=== Starting Boot Sequence ==="; \
    mmc dev 0; \
    ext4load mmc 0:4 ${kernel_addr_r} /boot/Image; \
    ext4load mmc 0:4 ${fdt_addr_r} /boot/board.dtb; \
    fdt addr ${fdt_addr_r}; \
    fdt set /chosen bootargs "console=ttySTM0,115200 root=/dev/mmcblk0p5 rootwait"; \
    booti ${kernel_addr_r} - ${fdt_addr_r}'

# 保存环境变量
saveenv

# 执行启动
run bootcmd
避坑指南:
  • 环境变量存储在固定的存储区域(如MMC的特定分区或SPI Flash),saveenv 操作会擦写存储介质,频繁操作可能缩短寿命。
  • 脚本中的地址(如 ${kernel_addr_r})需与 defconfig 中定义的 CONFIG_SYS_LOAD_ADDR 一致,否则可能导致加载失败。
  • 在优化启动时间时,建议将 bootcmd 中的 echo 和冗余延时命令移除,以缩短U-Boot执行时间。

4.4.3 启动时间测量命令

U-Boot提供了 bootstage 命令用于测量各阶段的耗时,是启动优化的利器。

# 启用 bootstage
setenv bootstage_report 1
saveenv

# 启动后查看时间报告
=> bootstage report
Timer summary in microseconds:
       Elapsed(s)  Stage
       ----------  -----
          0.000   start
          0.015   board_init_f
          0.120   board_init_r
          0.350   main_loop
          0.450   bootm_start
          0.520   bootm_load_os
          0.680   start_kernel
优化实践: 通过 bootstage 报告,可以精准定位耗时瓶颈。例如,如果 board_init_f 阶段过长,应检查时钟初始化或DDR训练代码;如果 main_loop 阶段过长,应检查 bootdelay 是否设置过大或 bootcmd 中是否存在冗余命令。

4.5 本章小结

  • U-Boot源码采用 arch/board/drivers/cmd 的模块化结构,便于移植和裁剪。
  • defconfig 是编译配置的核心,通过 make menuconfig 和 make savedefconfig 可以高效管理配置。
  • 设备树(DTS/DTB) 在U-Boot中用于硬件描述、驱动匹配和内核传递,是硬件与软件解耦的关键。
  • 常用命令 覆盖存储、网络、文件系统、内存和启动操作,脚本化 通过 bootcmd 实现自动化启动。
  • 使用 bootstage 命令进行启动时间测量,是启动优化的第一步。