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

【嵌入式Linux】U-Boot源码分析

编译出来之后的U-Boot的文件结构及其作用如下:

其中比较重要的文件夹有如下几个:

1、arch文件夹
主要存放架构相关文件,存储着包括不同架构下不同CPU的内容,包括arm\x86等等。在存放着arm架构相关设置的文件夹arm下,(\uboot\arch\arm\cpu),包含着各个arm版本的设置文件夹,以及根本的ARM 芯片所使用的 u-boot 链接脚本文件u-boot.lds

2、board文件夹
board 文件夹就是和具体的板子有关的,打开此文件夹,里面全是不同的板子,这是对开发板做的适配文件,本文使用的是mx6ullevk这个开发板。

3、configs文件夹
此文件夹为 uboot 配置文件,uboot 是可配置的,但是你要是自己从头开始一个一个项目的配置,那就太麻烦了,因此一般半导体或者开发板厂商都会制作好一个配置文件。我们可以在这个做好的配置文件基础上来添加自己想要的功能,这些半导体厂商或者开发板厂商制作好的配置文件统一命名为“xxx_defconfig”,xxx 表示开发板名字。

我们只关心 mx6ull_14x14_ddr512_emmc_defconfig 和 mx6ull_14x14_ddr256_nand_defconfig这两个文件,分别是正点原子 I.MX6ULL EMMC 核心板和 NAND 核心板的配置文件。

4、 .u-boot.xxx_cmd 文件
.u-boot.xxx_cmd 是一系列的文件,这些文件都是编译生成的,都是一些命令文件,比如文件.u-boot.bin.cmd,看名字应该是和 u-boot.bin有关的。

cmd_u-boot.bin := cp u-boot-nodtb.bin u-boot.bin

u-boot-nodtb.bin是 怎么来的呢?文件 .u-boot-nodtb.bin.cmd 就 是 用 于 生 成 u-boot.nodtb.bin 的,此文件内容如下:

cmd_u-boot-nodtb.bin := arm-linux-gnueabihf-objcopy \
--gap-fill=0xff -j .text -j .secure_text \
-j .rodata -j .hash -j .data -j .got \
-j .got.plt -j .u_boot_list -j \
.rel.dyn -O binary u-boot u-boot-nodtb.bin

文件.u-boot.lds.cmd 就是用于生成 u-boot.lds 链接脚本的,由于.u-boot.lds.cmd 文件内容太多,这里就不列出来了。uboot 根目录下的 u-boot.lds 链接脚本就是来源于 arch/arm/cpu/u-boot.lds文件。

5、Makefile文件
这个是顶层 Makefile 文件,Makefile 是支持嵌套的,也就是顶层 Makefile 可以调用子目录中的 Makefile 文件。

6、u-boot.xxx文件

  • u-boot:编译出来的 ELF 格式的 uboot 镜像文件。
  • u-boot.bin:编译出来的二进制格式的 uboot 可执行镜像文件。
  • u-boot.cfg:uboot 的另外一种配置文件。
  • u-boot.imx:u-boot.bin 添加头部信息以后的文件,NXP 的 CPU 专用文件。
  • u-boot.lds:链接脚本。
  • u-boot.map:uboot 映射文件,通过查看此文件可以知道某个函数被链接到了哪个地址上。
  • u-boot.srec:S-Record 格式的镜像文件。
  • u-boot.sym:uboot 符号文件。
  • u-boot-nodtb.bin:和 u-boot.bin 一样,u-boot.bin 就是 u-boot-nodtb.bin 的复制文件。

7、 .config
uboot 配置文件,使用命令“make xxx_defconfig”配置 uboot 以后就会自动生成。.config中的众多选项会决定uboot编译时会编译什么模块或某些功能,

8.fs
file system,存放uboot支持的文件系统的相关支持文件

其实我们移植uboot的时候重点关注的就是board和.config的内容

U-Boot顶层Makefile分析

顶层Makefile位于uboot/arch/arm/Makefile

1.递归make设置
首先是第二十行的

MAKEFLAGS += -rR --include-dir=$(CURDIR)

make是支持递归调用的,可以使用Makefile的make命令递归调用其他子目录或者同一目录的Makefile。在顶层目录的Makefile中可以使用

$(MAKE) -C subdir

来编译子目录,其中subdir是子目录的相对地址。这时候如果需要将本级Makefile的变量传递给子Makefile,可以使用export来声明导出标量

export VARIABLE …… //导出变量给子 make 。
unexport VARIABLE…… //不导出变量给子 make。

在这种递归调用makefile的结构中,有两个特殊的变量。“SHELL”和“MAKEFLAGS”,这两个变量除非使用“unexport”声明,
否则的话在整个make的执行过程中,它们的值始终自动的传递给子make,回到上面的第20行命令,里面还有一些别的参数,其中“-rR”表示禁止使用内置的隐含规则和变量定义,“–include-dir”指明搜索路径,”$(CURDIR)”表示当前目录。

2.设置编译结果输出目录
uboot 可以将编译出来的目标文件输出到单独的目录中,在 make 的时候使用“O”来指定输出目录,比如“make O=out”就是设置目标文件输出到 out 目录中。这么做是为了将源文件和编译产生的文件分开,当然也可以不指定 O 参数,不指定的话源文件和编译产生的文件都在同一个目录内,一般我们不指定 O 参数。

124 ifeq ("$(origin O)", "command line")
125 KBUILD_OUTPUT := $(O)
126 endif
135 ifneq ($(KBUILD_OUTPUT),)
139 KBUILD_OUTPUT := $(shell mkdir -p $(KBUILD_OUTPUT) && cd  $(KBUILD_OUTPUT)  && /bin/pwd)
155 endif # ifneq ($(KBUILD_OUTPUT),)

注意看行号,

  • 第 124 行判断“O”是否来自于命令行,如果来自命令行的话条件成立,KBUILD_OUTPUT就为$(O),因此变量 KBUILD_OUTPUT 就是输出目录。
  • 第 135 行判断 KBUILD_OUTPUT 是否为空。如果是空,则第 139 行调用 mkdir 命令,创建 KBUILD_OUTPUT 目录,并且将创建成功以后的绝对路径赋值给 KBUILD_OUTPUT。至此,通过 O 指定的输出目录就存在了。

3.模块编译

4.获取主机架构和操作系统

5.设置目标架构、交叉编译器和配置文件
编译uboot的时候 需要设置目标板架构和交叉编译器 ,“ make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf-”就是用于设置 ARCH 和 CROSS_COMPILE,在顶层Makefile 中代码如下:

244 # set default to nothing for native builds
245 ifeq ($(HOSTARCH),$(ARCH))
246 CROSS_COMPILE ?=
247 endif
248
249 KCONFIG_CONFIG ?= .config
250 export KCONFIG_CONFIG

第 245 行判断 HOSTARCH 和 ARCH 这两个变量是否相等,主机架构(变量 HOSTARCH)是x86_64,而我们编译的是 ARM 版本 uboot,肯定不相等,所以 CROSS_COMPILE= arm-linux-gnueabihf-,也就是需要启动交叉编译。我们每次编译 uboot 的时候都要在 make 命令后面设置ARCH 和 CROSS_COMPILE,使用起来很麻烦,可以直接修改顶层 Makefile,在里面加入 ARCH和 CROSS_COMPILE 的定义。

ifeq ($(HOSTARCH),$(ARCH))
CROSS_COMPILE ?=
endif

ARCH ?= arm
CROSS_COMPILE ?= arm-linux-gnueabihf-

第 249 行定义变量 KCONFIG_CONFIG,用于设置uboot编译使用的配置文件,这里设置配置文件为.config,.config 默认是没有的,需要使用命令“make xxx_defconfig”对 uboot 进行配置,配置完成以后就会在 uboot 根目录下生成.config。默认情况下.config 和xxx_defconfig 内容是一样的,因为.config 就是从 xxx_defconfig 复制过来的。如果后续自行调整了 uboot 的一些配置参数,那么这些新的配置参数就添加到了.config 中,而不是 xxx_defconfig。相当于 xxx_defconfig 只是一些初始配置,而.config 里面的才是实时有效的配置

6.交叉编译工具变量设置
上面我们只是设置了 CROSS_COMPILE 的名字,但是交叉编译器其他的工具还没有设置,顶层 Makefile 中相关代码如下:

# Make variables (CC, etc...)
AS = $(CROSS_COMPILE)as
# Always use GNU ld
ifneq ($(shell $(CROSS_COMPILE)ld.bfd -v 2> /dev/null),)
LD = $(CROSS_COMPILE)ld.bfd
else
LD = $(CROSS_COMPILE)ld
endif
CC = $(CROSS_COMPILE)gcc
CPP = $(CC) -E
AR = $(CROSS_COMPILE)ar
NM = $(CROSS_COMPILE)nm
LDR = $(CROSS_COMPILE)ldr
STRIP = $(CROSS_COMPILE)strip
OBJCOPY = $(CROSS_COMPILE)objcopy
OBJDUMP = $(CROSS_COMPILE)objdump

这些变量主要是进行交叉编译的时候的各类工具,比如

  • CC:编译器,用于编译C语言源文件。
  • CPP:C预处理器,用于处理源文件中的预处理指令。
  • AR:归档器,用于创建、修改静态库文件。
  • NM:符号表提取工具,用于列出目标文件或库文件中的符号。

这也解释了为什么交叉编译器只需要写到arm-linux-gnueabihf-,因为如果需要编译C语言文件,会调用CC变量,也就是arm-linux-gnueabihf-gcc,其他的归档、连接、符号表提取也同理

7.导出其他变量
在这里插入图片描述
这些变量中大部分都已经在前面定义了,我们重点来看一下下面这几个变量:
ARCH CPU BOARD VENDOR SOC CPUDIR BOARDDIR
这些变量主要是存储在根目录下的config.mk文件中,从25行开始有如下代码:

ARCH := $(CONFIG_SYS_ARCH:"%"=%)
CPU := $(CONFIG_SYS_CPU:"%"=%)
ifdef CONFIG_SPL_BUILD
ifdef CONFIG_TEGRA
CPU := arm720t
endif
endif
BOARD := $(CONFIG_SYS_BOARD:"%"=%)
ifneq ($(CONFIG_SYS_VENDOR),)
VENDOR := $(CONFIG_SYS_VENDOR:"%"=%)
endif
ifneq ($(CONFIG_SYS_SOC),)
SOC := $(CONFIG_SYS_SOC:"%"=%)
endif

第 25 行定义变量 ARCH ,值为 $(CONFIG_SYS_ARCH:“%”=%) , 也 就 是 提 取CONFIG_SYS_ARCH 里面双引号“”之间的内容。比如 CONFIG_SYS_ARCH=“arm”的话,ARCH=arm。其他的几个也类似,那么接下来就是要找接下来需要找到 CONFIG_SYS_ARCH、CONFIG_SYS_CPU、CONFIG_SYS_BOARD、CONFIG_SYS_VENDOR 和 CONFIG_SYS_SOC 这 5 个变量的值。这 5 个变量在 uboot 根目录下的.config 文件中有定义

在这里插入图片描述
好吧,其实是根Makefile找到config.mk,然后config.mk又找.config,最终取得规定的值的故事。

7.make xxx_defconfig 过程
在编译 uboot 之前要使用“make xxx_defconfig”命令来配置 uboot,那么这个配置过程是如何运行的呢?
在这里插入图片描述

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

相关文章:

  • JMeter接口自动化发包与示例
  • Windows连接服务器Ubuntu_MobaXterm
  • 【Mysql】基础(函数,约束,多表查询,事务)
  • PHP语言基础
  • 深入解析C++类:面向对象编程的核心基石
  • 前端css+html面试题
  • 面向对象分析与设计的多过程多层级实现
  • Generic Mapping Tools(GMT):开源的地球、海洋和行星科学的工具箱、Python与matlab包
  • 从零构建大语言模型全栈开发指南:第四部分:工程实践与部署-4.3.2知识库增强与外部API集成(代码示例:HTTP节点与检索增强生成)
  • uniapp 微信小程序 使用ucharts
  • 实战打靶集锦-36-Deception
  • 封装可拖动弹窗(vue jquery引入到html的版本)
  • SQL语句(一)—— DDL
  • [Lc6_记忆化搜索] 最长递增子序列 | 矩阵中的最长递增路径
  • 【大模型系列篇】大模型基建工程:使用 FastAPI 构建 SSE MCP 服务器
  • 14-SpringBoot3入门-MyBatis-Plus之CRUD
  • 树莓派超全系列文档--(15)无需交互使用raspi-config工具其二
  • clickhouse集群版本部署文档
  • jenkins 参数化发布到服务器 publish over ssh、label、Parameterized publishing
  • 基于DeepSeek、ChatGPT支持下的地质灾害风险评估、易发性分析、信息化建库及灾后重建
  • js实现一个可指定超时时间的异步函数重试机制
  • tomcat 目录结构组成
  • python的def
  • 计算机网络 第二章:应用层(1)
  • 结构体补充:位段
  • 我该怎么设置SVN客户端的认证信息?
  • C++ I/O 流通俗指南
  • 【卫星参数】高分二号卫星参数光谱波段_应用说明_数据来源
  • 查询条件与查询数据的ajax拼装
  • MySQL-- 函数(单行函数):数值函数, 字符串函数