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」这个口诀,基本不会迷路。
可可精品资料库