3. U-Boot源码结构:顶层目录、board目录、arch目录、drivers目录功能解析

U-Boot的源码组织遵循清晰的模块化分层原则。理解顶层目录、board、arch和drivers四大核心目录的功能,是进行移植工作的第一步。本章将逐一解析这些目录的职责与协作关系,帮助你在庞大的代码库中快速定位关键文件。

3.1 顶层目录:构建系统的骨架

U-Boot顶层目录包含了构建系统、通用配置、文档以及核心初始化逻辑。以下是必须掌握的关键子目录与文件:

目录/文件 功能说明 移植关注点
Makefile 顶层构建入口,定义编译规则、链接脚本、目标架构等。 通常无需修改,但需确认交叉编译工具链路径。
Kconfig / configs/ Kconfig是配置系统核心;configs/目录存放各板卡的默认配置文件(如xxx_defconfig)。 移植时需在此创建或修改板级defconfig。
include/ 全局头文件,包括configs/(板级配置头文件)、asm-*(架构相关头文件链接)等。 板级配置头文件(如include/configs/myboard.h)是移植核心。
common/ 通用核心代码,如命令行解析、环境变量、启动流程(board_f.c, board_r.c)。 理解board_init_f和board_init_r的调用顺序。
lib/ 通用库函数,如字符串操作、CRC校验、时间函数等。 一般无需修改。
tools/ 主机端工具,如mkimage(制作U-Boot镜像)、fdtgrep等。 用于打包和验证镜像。
doc/ 文档与设备树绑定说明。 查阅README和device-tree-bindings/。
移植提示: 在顶层目录执行 make <board>_defconfig 时,系统会从 configs/ 读取默认配置,并生成 .config 文件。这是移植的第一步。

3.2 board目录:板级硬件初始化的主场

board/目录按照厂商和板卡名称组织,存放与具体硬件平台强相关的初始化代码。这是移植工作中修改最频繁的区域。

  • 目录结构: board/<vendor>/<board_name>/,例如 board/ti/am335x/。
  • 核心文件:
    • board.c:板级初始化函数,如 board_init()、board_late_init()、dram_init()。
    • Kconfig:板级配置选项。
    • MAINTAINERS:维护者信息。
    • Makefile:编译当前板卡源码的规则。
  • 关键函数:
    • dram_init():必须实现,用于初始化DDR控制器并填充 gd->ram_size。
    • board_init():早期板级初始化,如配置GPIO、时钟、调试串口。
    • board_early_init_f():在 board_init_f 早期调用的极简初始化。
常见错误: 移植新板卡时,如果忘记在 board/ 下创建对应的目录和 board.c,链接阶段会报 undefined reference to 'board_init' 错误。

3.3 arch目录:架构与SoC核心代码

arch/目录封装了与CPU架构和SoC内部模块相关的底层代码。它按架构(如arm、riscv、x86)和SoC厂商进一步细分。

子目录 功能说明 移植关注点
arch/arm/cpu/ ARM架构CPU核心代码,包括异常向量表、MMU、缓存、启动汇编(start.S)。 start.S 是U-Boot的第一条指令入口,负责设置CPU模式、初始化栈、重定位。
arch/arm/mach-<soc>/ SoC级代码,如 mach-sunxi/(全志)、mach-imx/(NXP i.MX)。 包含SoC特有的时钟、复位、DDR控制器驱动初始化。
arch/arm/include/asm/ 架构相关头文件,如 arch/arm/include/asm/arch-<soc>/ 包含SoC寄存器定义。 DDR控制器寄存器地址和位域定义通常在此。
arch/arm/dts/ 设备树源文件(.dts)和头文件(.dtsi)。 移植时必须创建或修改板级.dts文件。
关键路径: 对于ARM平台,DDR初始化的核心代码通常位于 arch/arm/mach-<soc>/ 或 drivers/ram/ 中。例如,全志H3的DDR初始化在 arch/arm/mach-sunxi/dram_sun8i_h3.c。

3.4 drivers目录:外设驱动的仓库

drivers/目录按照设备类型分类,包含了U-Boot支持的所有外设驱动。移植时,你需要确保所需驱动被正确启用并适配。

  • 核心子目录:
    • drivers/serial/:串口驱动(调试信息输出关键)。
    • drivers/mmc/:MMC/SD卡驱动(启动介质)。
    • drivers/net/:网络接口驱动(网络启动与下载)。
    • drivers/spi/ / drivers/i2c/:总线驱动。
    • drivers/ram/:DDR控制器驱动(部分SoC的DDR初始化在此)。
    • drivers/mtd/:NAND Flash、SPI Flash等存储驱动。
  • 驱动模型(DM): 现代U-Boot使用Driver Model,驱动通过设备树匹配。移植时需在设备树中添加正确的 compatible 属性。
调试技巧: 如果串口无输出,首先检查 drivers/serial/ 中对应的串口驱动是否被编译进U-Boot,以及设备树中串口节点的 status = "okay"; 是否设置。

3.5 目录协作关系与启动流程

下图展示了U-Boot启动过程中,顶层目录、board、arch和drivers之间的协作关系:

U-Boot目录协作与启动流程 U-Boot 目录协作与启动流程 顶层目录 (Makefile/Kconfig) arch/arm/cpu/start.S board/xxx/board.c arch/arm/mach-xxx/ (时钟/复位/DDR控制器) drivers/ (serial/mmc/net/ram) 设备树 (arch/arm/dts/) 驱动匹配与参数配置 U-Boot 启动完成,进入命令行或加载内核 说明: 1. start.S 设置CPU后跳转 2. board_init_f() 调用板级代码 3. 驱动通过设备树匹配

3.6 移植实战:快速定位关键文件

假设你要为一块基于 NXP i.MX6ULL 的板卡移植U-Boot,以下是定位关键文件的步骤:

  1. 创建板级目录: board/mycompany/myboard/,复制参考板 board/freescale/mx6ullevk/ 中的文件。
  2. 配置头文件: 创建 include/configs/myboard.h,参考 include/configs/mx6ullevk.h,修改DDR参数、环境变量等。
  3. 设备树: 创建 arch/arm/dts/myboard.dts,包含 imx6ull.dtsi,并添加板级外设节点。
  4. 默认配置: 创建 configs/myboard_defconfig,指定目标架构、板卡、设备树文件。
  5. DDR初始化: 在 board/mycompany/myboard/ 中实现 dram_init(),或确认 drivers/ram/ 中是否有对应驱动。
核心原则: 移植的本质是“复制-修改-验证”。先找到一个与目标板最接近的参考板,然后逐步替换 board/、include/configs/ 和 arch/arm/dts/ 中的关键文件。