当前位置: 首页 > news >正文

U-Boot零基础入门第二篇(如何看懂uboot目录?)

引言

当我们从香橙派官网下载uboot之后我们进行一直

第一部分:文件(构建系统和项目管理)

Makefile 、Kconfig 、.config、config.mk 之间的关系

为什么需要这四个文件?

你有 U-Boot 的源代码,上千个 .c 文件散落在几十个目录里。现在问题来了:

问题1:怎么知道编译哪些文件? 你的开发板可能需要 USB 驱动,但不需要网卡驱动。另一个板子正好相反。不可能把所有源文件都编译进去,镜像会太大,而且有些代码会冲突。→ 需要一个配置系统,让你选择"要 USB、不要网卡",这个系统生成一个配置清单→ 这个配置清单就是 .config 文件 → 生成这个清单的工具叫 Kconfig

问题2:用什么编译器编译? 你在 x86 电脑上开发,但目标板子是 ARM 架构。不能用本机的 gcc,必须用 ARM 交叉编译器 arm-linux-gnueabi-gcc。编译选项也要设置好,比如优化等级 -O2、警告开关 -Wall。→ 需要一个地方统一定义编译工具和参数 → 这个文件叫 config.mk → 它里面写着:CC = arm-linux-gnueabi-gccCFLAGS = -O2 -Wall

问题3:怎么自动化整个编译过程? 手动编译是这样的:gcc -c file1.c -o file1.ogcc -c file2.c -o file2.o ...重复几百次gcc file1.o file2.o ... -o u-boot太蠢了,而且文件改了还要记住重新编译哪些。→ 需要一个自动化工具,告诉它最终目标是 u-boot.bin,它自动找出要编译哪些文件、按什么顺序→ 这个工具是 GNU Make,它读取的规则文件叫 Makefile

问题4:子目录的编译怎么处理? drivers/usb/ 目录下有一堆 USB 相关的 .c 文件,需要统一管理。每个子目录都要有编译规则,但不能每个目录都写一遍重复的逻辑。→ 需要一套通用的构建规则模板,所有子目录都遵循这套规则
→ 这套规则叫 Kbuild 系统 → 顶层 Makefile 引入 Kbuild 后,可以用统一的方式处理所有子目录

它们怎么协作?

第一步:配置阶段(决定编译什么)

你运行 make menuconfig,看到一个菜单:

[ ] Enable USB support
[ ] Enable Network support
[*] Enable MMC support

→ 这个菜单是 Kconfig 文件生成的。Kconfig 里写着:

config USB_SUPPORTbool "Enable USB support"depends on DM_USB

→ 你勾选了 USB support,Kconfig 检查依赖:USB 需要先启用 DM_USB,于是自动帮你勾上 DM_USB

→ 退出菜单保存后,生成 .config 文件

CONFIG_USB_SUPPORT=y
CONFIG_DM_USB=y
CONFIG_NETWORK=n
CONFIG_MMC=y

第二步:编译阶段(实际执行编译)

你运行 make

第一件事:Makefile 准备编译环境

Makefile 开头执行:

include config.mk

读取 config.mk,获得:

CROSS_COMPILE = arm-linux-gnueabi-
CC = $(CROSS_COMPILE)gcc
LD = $(CROSS_COMPILE)ld
CFLAGS = -O2 -Wall -fno-common

→ 现在 Makefile 知道了用什么编译器、用什么参数

第二件事:Makefile 读取配置

Makefile 继续执行:

include .config

读取 .config,看到 CONFIG_USB_SUPPORT=yCONFIG_MMC=y

→ 这些配置会影响后面的编译决策

第三件事:Makefile 引入 Kbuild 规则

Makefile 执行:

include scripts/Kbuild.include

引入 Kbuild 的通用规则,比如怎么递归编译子目录、怎么处理依赖关系

→ 现在 Makefile 有了处理复杂项目的能力

第四件事:开始递归编译

Makefile 看到要编译的目录列表(lib/、drivers/、common/ 等),开始递归处理。

进入 drivers/usb/ 目录,这个目录有个 Kbuild 文件(或 Makefile):

obj-$(CONFIG_USB_SUPPORT) += usb-common.o
obj-$(CONFIG_USB_STORAGE) += usb-storage.o

→ Kbuild 读取 .config,看到 CONFIG_USB_SUPPORT=y

obj-$(CONFIG_USB_SUPPORT) += usb-common.o 展开成 obj-y += usb-common.o

obj-y 表示要编译的文件,于是 usb-common.c 被加入编译列表

→ 执行编译命令(使用 config.mk 定义的编译器和参数):

arm-linux-gnueabi-gcc -O2 -Wall -DCONFIG_USB_SUPPORT -c usb-common.c -o usb-common.o

→ 注意 -DCONFIG_USB_SUPPORT,这是把 .config 中的配置传给编译器的宏定义

所有子目录都这样处理完后,最后链接:

arm-linux-gnueabi-ld usb-common.o mmc.o ... -o u-boot

生成最终的 u-boot.bin


四个文件的角色总结

Kconfig:决策者

  • 作用时机:配置阶段(make menuconfig
  • 干什么:生成 .config 文件,记录"要编译什么"
  • 不参与实际编译

config.mk:工具箱

  • 作用时机:编译阶段开始前
  • 干什么:告诉 Makefile"用什么工具编译"(编译器路径、编译参数)
  • 被 Makefile include,提供编译环境

Kbuild:执行规则

  • 作用时机:编译阶段
  • 干什么:提供通用的编译规则模板,处理复杂的递归编译
  • 被 Makefile include,提供自动化能力

Makefile:总指挥

  • 作用时机:编译阶段(make
  • 干什么:协调其他三者,执行整个编译流程
  • 先 include config.mk 获取工具
  • 再 include .config 获取配置
  • 再 include Kbuild 获取规则
  • 最后递归编译所有目录,生成最终文件

完整流程示例

你要给 ARM 板子编译支持 USB 的 U-Boot:

  1. 配置make menuconfig → Kconfig 生成菜单 → 你选中 USB → 保存生成 .config 文件(CONFIG_USB_SUPPORT=y

  2. 编译make → Makefile 开始工作:

  • include config.mk → 获得 CC=arm-linux-gnueabi-gcc
  • include .config → 知道 CONFIG_USB_SUPPORT=y
  • include Kbuild.include → 获得递归编译能力
  • 递归进入 drivers/usb/ → 读取该目录的 Kbuild → 看到 obj-$(CONFIG_USB_SUPPORT)+=usb-common.o → 因为 CONFIG_USB_SUPPORT=y,所以编译 usb-common.c → 用 arm-linux-gnueabi-gcc 编译
  • 所有目录处理完 → 链接生成 u-boot.bin
配置阶段(make menuconfig)
═══════════════════════════════════════════════════════════════════┌─────────────┐│   Kconfig   │  定义所有配置选项(USB、网卡、MMC...)│  (规则定义) │  和它们之间的依赖关系└──────┬──────┘││ 用户通过menuconfig选择配置│ Kconfig检查依赖、自动启用必需项↓┌─────────────┐│  .config    │  CONFIG_USB_SUPPORT=y│ (配置清单)CONFIG_MMC=y└─────────────┘  CONFIG_NETWORK=n│          (决定编译哪些代码)││ 配置完成,进入编译阶段│↓编译阶段(make)
═══════════════════════════════════════════════════════════════════┌────────────────────────┐│      Makefile          ││    (总指挥/协调者)      │└───────────┬────────────┘│┌───────────┼───────────┐│           │           │第1步   │   第2步   │   第3步   │↓           ↓           ↓┌──────────────┐  ┌─────────┐  ┌──────────────┐│  config.mk   │  │ .config │  │Kbuild.include││  (工具箱)    │  │(配置单)  │  │ (执行规则)   │└──────────────┘  └─────────┘  └──────────────┘│                 │             ││ 提供:           │ 提供:       │ 提供:│ CC=arm-gcc      │ CONFIG_     │ build函数│ CFLAGS=-O2      │ USB=y       │ 递归编译规则│ LD=arm-ld       │ CONFIG_     │ 依赖处理│                 │ MMC=y       │└─────────┬───────┴──────┬──────┴──────┬─────────│              │             │└──────────────┼─────────────┘││ Makefile获得完整能力:│ ① 知道用什么编译│ ② 知道编译什么│ ③ 知道怎么编译│↓┌─────────────────────────┐│  递归处理各个子目录      │└────────────┬────────────┘│┌───────────────────────┼───────────────────────┐│                       │                       │↓                       ↓                       ↓┌─────────┐            ┌─────────┐            ┌─────────┐│drivers/ │            │  lib/   │            │common/  ││  usb/   │            │         │            │         │└────┬────┘            └────┬────┘            └────┬────┘│                      │                      ││ 读取该目录的Kbuild   │                      │↓                      │                      │┌──────────────────────┐   │                      ││drivers/usb/Kbuild    │   │                      ││                      │   │                      ││obj-$(CONFIG_USB)     │   │                      ││  += usb-common.o     │   │                      │└──────┬───────────────┘   │                      ││                    │                      ││ CONFIG_USB=y       │                      ││ 所以展开为:        │                      ││ obj-y += usb-      │                      ││ common.o           │                      │↓                    ↓                      ↓┌──────────────────────────────────────────────────────┐│           执行实际的编译命令                          ││                                                       ││  arm-linux-gnueabi-gcc \                             ││    -O2 -Wall \              ← 来自config.mk         ││    -DCONFIG_USB_SUPPORT \   ← 来自.config           ││    -c usb-common.c \        ← 来自Kbuild规则        ││    -o usb-common.o                                   │└───────────────────────┬──────────────────────────────┘││ 所有.c编译成.o│↓┌───────────────┐│ usb-common.o  ││ mmc.o         ││ serial.o      ││ ...           │└───────┬───────┘││ 链接所有.o文件↓┌───────────────┐│ arm-ld \      ││   *.o \       ││   -o u-boot   │└───────┬───────┘│↓┌───────────────┐│  u-boot.bin   │  ← 最终产物└───────────────┘关系图(各文件职责)
═══════════════════════════════════════════════════════════════════Kconfig          config.mk         Kbuild           Makefile(配置者)          (工具箱)         (规则库)         (总指挥)│                 │                │                ││生成             │定义            │定义            │协调全局↓                 ↓                ↓                ↓.config          编译工具           构建规则        编译流程(要编什么)       (用什么编)        (怎么编)        (按序执行)│                 │                │                │└─────────────────┴────────────────┴────────────────┘│↓编译成功u-boot.bin数据流向
═══════════════════════════════════════════════════════════════════用户选择配置↓[Kconfig] ─生成→ [.config]││ 读取↓[config.mk] ←─包含─ [Makefile] ←─包含─ [Kbuild.include]│                  │                     ││提供工具          │协调                │提供规则│                  ↓                     │└──────→ 编译命令 ←────────────────────┘↓[源码.c][目标.o][u-boot.bin]

这就是四个文件如何配合完成从配置到编译的整个过程。

README - 项目说明文档。U-Boot 的简介、编译方法、基本使用。拿到源码首先要看这个文件。

MAINTAINERS - 代码维护者列表。记录每个模块的负责人和联系方式。提交补丁时需要抄送对应维护者。

COPYING - 版权声明文件。U-Boot 使用 GPL 开源协议,这里是协议原文。说明了代码的使用和分发规则。

CREDITS - 贡献者名单。记录了对 U-Boot 有贡献的开发者,这是致谢和荣誉名单。

.gitignore - Git 版本控制的忽略规则。定义哪些文件不纳入版本管理(编译生成的 .o 文件、u-boot.bin 等临时文件)。这是 Git 工具使用的,与 U-Boot 功能无关。


第二部分:文件夹(功能模块)

第一层:CPU 和开发板适配

arch/ - 处理器架构实现代码。你的 RK3588S 是 ARM64 架构,上电后第一条指令在 arch/arm 下。包含:

  • CPU 启动汇编代码(start.S)
  • 异常向量表
  • MMU 和 Cache 控制
  • 架构相关的底层操作

board/ - 开发板配置代码。这个目录下有多少个文件夹,就表示当前 U-Boot 支持多少个开发板。每个开发板的硬件连接不同:电源管理芯片、DDR 型号、外设连接方式。

重要机制说明:为了管理越来越多的开发板,board 下采用了两级目录结构:

  • 第一级是厂商目录(vendor,如 rockchip、samsung)
  • 第二级是具体的开发板目录
  • 你的板子路径应该是:board/rockchip/orangepi-5-pro 或类似结构
  • 配置阶段(Kconfig)需要正确指定这个路径,否则编译时找不到文件

configs/ - 板级配置文件集合。每个开发板有一个 _defconfig 文件,定义了编译选项:启用哪些驱动、支持哪些功能、内存地址设置。你的板子是 orangepi-5-pro_defconfig。执行 make orangepi-5-pro_defconfig 应用这个配置,这一步就是在确定使用 board 目录下的哪个文件夹。

dts/ - 设备树编译的工作目录。实际的 .dts 源文件在 arch/arm/dts 下,编译时在这个目录生成 .dtb 二进制文件。这是设备树的中转站。

第二层:硬件驱动

drivers/ - 硬件驱动代码。这些驱动大部分是从 Linux 内核移植过来的,但 U-Boot 是裸机程序,所以驱动是 Linux 驱动的简化版本。包含:

  • GPIO、I2C、SPI 等总线驱动
  • MMC/SD 卡驱动
  • USB 驱动
  • 网卡驱动
  • NAND Flash 驱动
    开发板必须用到的驱动都在这里。

include/ - 头文件集中目录。U-Boot 和 Linux 内核采用同样的管理方式:所有头文件集中放在 include 目录,而不是跟着对应的 .c 文件。包含:

  • 函数声明
  • 结构体定义
  • 寄存器地址宏定义
  • CONFIG_ 开头的配置选项

第三层:存储和文件系统

disk/ - 磁盘分区管理。解析 SD 卡和 eMMC 上的分区表(GPT 或 MBR),确定各分区的位置和大小。

fs/ - 文件系统支持。从 Linux 移植过来的文件系统驱动:

  • FAT32(SD 卡常用)
  • EXT4(Linux 分区)
  • UBIFS(NAND Flash)
  • BTRFS、SquashFS 等
    有了文件系统驱动才能按文件名读取内核镜像。

第四层:启动和命令系统

boot/ - 启动流程主控。协调各模块完成启动:定位内核、加载到内存、加载设备树、设置参数、跳转到内核入口。

cmd/ - 命令行实现。U-Boot 提供的所有命令都在这里实现:

  • bootm:启动内核
  • mmc:操作 SD 卡
  • setenv:设置环境变量
  • md/mw:读写内存
    每个命令对应一个 cmd_xxx.c 文件。

common/ - 公共功能代码。不属于特定硬件的通用逻辑:

  • cmd_ 开头的文件:命令系统的框架实现
  • env_ 开头的文件:环境变量的管理实现
  • 控制台输入输出
  • CRC 校验
    这是连接底层硬件和上层功能的桥梁。

env/ - 环境变量管理的底层实现。环境变量(bootcmd、bootargs、ipaddr 等)需要持久化到 Flash,这里实现了不同存储介质的环境变量读写。

第五层:网络功能

net/ - 网络协议栈。实现了:

  • TCP/IP、UDP 协议
  • DHCP、TFTP、NFS
  • ping、tftp 等命令
    支持通过网络加载内核、网络启动。

第六层:库和通用支撑

lib/ - 基础库函数。所有架构通用的库代码:

  • 字符串操作
  • 数据结构
  • 加密算法(AES、RSA、SHA)
  • 压缩解压(gzip、lzma)
    这是最底层的运算能力提供者。

api/ - 应用程序接口。定义了外部程序调用 U-Boot 功能的接口,允许在 U-Boot 环境下运行扩展应用。

第七层:开发工具

scripts/ - 构建辅助脚本。Makefile 调用的各种脚本:

  • 设备树编译器(dtc)
  • Kconfig 配置工具
  • 依赖关系分析
  • 头文件生成
    这些脚本在编译时自动运行。

tools/ - 开发工具集。在主机上使用的工具:

  • mkimage:制作 U-Boot 格式的镜像文件(重要)
  • menuconfig:图形配置界面
  • 镜像处理工具
    这些工具不在开发板运行,是交叉编译时使用的。

第八层:测试和示例

test/ - 测试代码。单元测试、集成测试、Python 测试脚本,验证功能正确性。

examples/ - 示例程序。演示如何使用 U-Boot 的 API 编写独立应用。

post/ - 上电自检(Power-On Self Test)。系统启动时可选的硬件检测:内存测试、CPU 测试、外设自检。

第九层:文档

doc/ - 文档目录。使用手册、移植指南、设计文档、各模块 README。虽然是英文且较杂乱,但是理解源码的重要参考。

Licenses/ - 开源许可证。GPL 协议原文和各组件的授权声明。


关键理解点

配置阶段的重要性

U-Boot 的可移植性依靠配置系统维护。配置阶段解决的核心问题是:

  1. 确定使用哪个开发板:从 board 目录的众多文件夹中选择一个
  2. 确定文件路径:board 下有的是一级目录(开发板名),有的是二级目录(厂商/开发板),配置时必须指定正确的路径深度
  3. 确定编译选项:启用哪些驱动、哪些功能

不配置就无法编译,因为编译器不知道要编译哪些文件、去哪里找这些文件。

目录重要性总结

必须深入理解的

  • board/ - 开发板适配的关键
  • arch/arm/mach-rockchip/rk3588/ - RK3588 芯片初始化
  • configs/orangepi-5-pro_defconfig - 你的板子配置
  • arch/arm/dts/rk3588s-orangepi-5-pro.dts - 设备树

需要了解的

  • drivers/ - 驱动在哪里
  • common/ - 命令和环境变量实现
  • include/ - 头文件位置
  • lib/ - 库函数

移植时几乎不动的

  • arch/arm/cpu/ - SoC 代码,同芯片的板子通用
  • net/fs/ - 协议和文件系统,通用代码
  • lib/ - 库函数,通用代码

http://www.dtcms.com/a/569450.html

相关文章:

  • Javascript循环语句之while循环
  • BuildingAI 用户信息弹出页面技术架构
  • C#串口通讯助手
  • 企业网站icp备案建站哪家好
  • SparkSQL读取普通文件的方式
  • 网站平台推广方案网站内页如何做排名
  • 各个系统的 docker安装
  • 大庆建设网站表格下载建设一个网站需要哪些方面的开支
  • 各种网站建设报价制作网页网站的软件是
  • 在多阶段松弛实验中使用分布式光纤传感量化局部和非局部岩石变形
  • (ACP广源盛)GSV6172---MIPI/LVDS 信号转换为 Type-C/DisplayPort 1.4/HDMI 2.0 并集成嵌入式 MCU
  • 【每天一个AI小知识】:什么是少样本学习?
  • 建网站找那家企业好横岗网站建设公司
  • Vue面试项目经验分享:如何专业展示技术能力与解决问题
  • 浏阳网站开发顺德做网站的公司
  • 20、docker跨主机网络-Vxlan、vtep补充
  • CONCAT函数使用中出现空指针异常问题分析
  • 织梦网站挂马教程wordpress数据盘
  • 网站更改备案深圳工程招标交易网
  • 盐城网站建设方案珠海设计公司排名
  • 天津建设网站安管人员成绩查询新闻资讯app开发
  • 2025 Vscode安装Python教程
  • Iconfont 的本质原理和使用场景
  • 企业TB级数据加密迁移至AWS云:AWS Snowball Edge Storage Optimized成本效益方案解析
  • 网站后台是怎么做的上海关键词优化
  • p2p金融网站开发东莞短视频的推广方法
  • 晋江wap站是什么意思自己做的网站怎么爬数据
  • mongo的docker修复
  • Excel怎么快速提取混合单元格中的中文、英文、数字?
  • 易思企业网站管理系统wordpress页面输入密码