2、U-Boot源码结构:顶层目录结构分析、board目录与平台相关代码、arch目录与CPU架构代码

好,咱们今天来聊聊U-Boot的源码结构。说实话,我第一次打开U-Boot源码目录的时候,心里是有点懵的——这玩意儿怎么这么多文件夹?但别怕,摸清楚规律之后,你会发现它其实挺有条理的。

我个人习惯把U-Boot的源码结构分成三个层次来看:顶层目录、board目录、arch目录。这三层搞明白了,你基本就能在源码里找到任何你想要的东西。

2.1 顶层目录结构分析

先看顶层。你解压U-Boot源码后,第一眼看到的就是这些目录。我挑几个最重要的说说:

目录/文件 作用 我的经验
board/ 板级相关代码,每个板子一个子目录 移植时改得最多的就是这里
arch/ CPU架构相关代码,比如arm、x86、riscv 启动流程的核心在这里
common/ 通用功能模块,比如命令行、环境变量 一般不动,除非你要加新命令
drivers/ 各种外设驱动,串口、网卡、存储等 我经常在这里加新硬件支持
include/ 头文件,包括配置头文件 配置宏定义都在这里
configs/ 板级默认配置文件 make xxx_defconfig 就是读这里
scripts/ 编译脚本、工具脚本 偶尔看看,了解编译流程

嗯,这里要注意:board/和arch/是移植工作的两大主战场。其他目录虽然也重要,但大部分时候你不需要动它们。

核心思路:U-Boot的目录设计遵循「分层解耦」原则。架构相关代码在arch/,板级相关代码在board/,通用代码在common/。这样你换CPU架构时只改arch/,换板子时只改board/,互不干扰。

2.2 board目录与平台相关代码

board目录里,每个板子都有一个专属文件夹。比如你用的是TI的AM335x,那就会有一个board/ti/am335x/目录。里面放什么?

  • 板级初始化代码:比如DDR初始化、时钟配置、引脚复用
  • 板级特有功能:比如LED控制、按键检测、板载外设初始化
  • 板级配置文件:比如board/ti/am335x/board.c

我记得有一次,客户说他们的板子启动时网卡死活不通。我排查了半天,最后发现是board目录下的引脚复用配置错了——一个GPIO被配置成了其他功能。这种问题,说白了就是board目录没写对。

我的建议:拿到一个新板子,先看board目录下有没有现成的参考。如果有相近的板子,直接复制一份改,比从头写快得多。我曾经在给一个国产芯片做移植时,就是拿同系列的参考板改的,省了至少两周时间。

board目录的结构一般是这样的:

board/
  └── vendor/
      └── board_name/
          ├── board.c          # 板级初始化
          ├── Kconfig          # 板级配置选项
          ├── Makefile         # 编译规则
          └── ...              # 其他板级文件

你想想看,如果你要加一个新板子,只需要在board/下新建一个目录,然后实现那几个关键函数就行了。U-Boot的框架已经帮你搭好了,你只需要填空。

2.3 arch目录与CPU架构代码

arch目录是另一个重头戏。它按CPU架构分,比如arch/arm/、arch/x86/、arch/riscv/。每个架构下又细分:

  • cpu/:CPU核心代码,比如启动汇编、异常处理、缓存管理
  • include/:架构相关的头文件,比如寄存器定义
  • lib/:架构相关的库函数,比如内存操作、字节序转换
  • dts/:设备树文件,描述硬件信息

以ARM为例,arch/arm/cpu/下面还有armv7/、armv8/等子目录。每个目录里都有start.S——这是U-Boot的入口汇编代码。说白了,CPU一上电,第一条指令就是从这里开始的。

避坑指南:我曾经在移植时,直接复制了另一个架构的start.S,结果板子死活跑不起来。后来才发现,不同架构的启动流程差异很大——ARM需要设置异常向量表,RISC-V需要处理M模式,x86需要处理实模式到保护模式的切换。千万别偷懒,一定要用对应架构的代码。

arch目录的结构大致如下:

arch/
  └── arm/
      ├── cpu/
      │   ├── armv7/
      │   │   ├── start.S      # 启动汇编
      │   │   ├── cache_v7.c   # 缓存管理
      │   │   └── ...
      │   └── armv8/
      │       ├── start.S
      │       └── ...
      ├── include/
      │   └── asm/
      │       ├── arch-armv7.h # 架构寄存器定义
      │       └── ...
      ├── lib/
      │   ├── cache.c
      │   └── ...
      └── dts/
          └── ...              # 设备树文件

为什么要把架构代码单独放?原因很简单:不同CPU的启动方式、寄存器布局、指令集都不一样。如果混在一起,代码会变得一团糟。U-Boot这么设计,你换CPU时只需要换arch目录,其他代码基本不用动。

总结一下:

  • 顶层目录:功能划分清晰,common/放通用逻辑,drivers/放驱动,configs/放配置
  • board目录:板级专属代码,移植时主要改这里
  • arch目录:CPU架构代码,启动流程的核心

这三层搞清楚了,你就能在U-Boot源码里「指哪打哪」。下次遇到问题,先问自己:这是板级问题还是架构问题?然后直奔对应的目录。

嗯,最后说一句:别怕源码多。U-Boot虽然目录多,但每个目录的职责很清晰。你只要记住「架构相关找arch,板级相关找board,通用功能找common」这个口诀,基本不会迷路。

U-Boot 源码结构三层模型 顶层目录 (Top-Level) board/ | arch/ | common/ | drivers/ | include/ | configs/ | scripts/ 功能划分清晰,每个目录负责一类功能 board/ 目录 (板级相关) board/vendor/board_name/ board.c | Kconfig | Makefile | ... DDR初始化、时钟配置、引脚复用、板载外设 arch/ 目录 (CPU架构相关) arch/arm/ | arch/x86/ | arch/riscv/ | ... cpu/ (start.S) | include/ (寄存器定义) | lib/ | dts/ 启动汇编、异常处理、缓存管理、设备树 核心原则:分层解耦 — 架构相关找arch,板级相关找board,通用功能找common

可可精品资料库