一、嵌入式Linux系统组成
嵌入式Linux系统一般由以下几部分组成:
-
引导加载程序,包括固化在固件中的boot代码和BootLoader两大部分。有些CPU在运行BootLoader之前会先运行一段固化程序,比如x86的CPU会先运行BIOS中的固件,然后才运行硬盘的第一个分区(MBR)中的BootLoader,但是在大多的嵌入式系统中,是没有固件的,BootLoader就是上电后执行的第一个程序。
-
linux内核:特定于嵌入式板子的定制内核以及内核的启动参数,内核的启动参数可以是内核默认的,也可以是由BootLoader传递给它的。
-
文件系统: 包括根文件系统和建立于Flash内存设备上的文件系统,里面包含了linux系统能够运行所必须的应用程序、库等等,比如可以给用户提供Linux的控制界面shell程序、动态链接的程序时所需要的glibc或uClibc库等。
-
用户应用程序 特定于用户的应用程序,它们也存储在文件系统中,有时在用户应用程序和内核层之间可能还会包括一个嵌入式图形用户界面,常用的嵌入式GUI有:Qtopia和MinGUI等。显然,在嵌入式系统的固态存储设备上有相应的分区来存储它们。
在Flash存储器中,它们的分布一般如下:
二、BootLoader
Bootloader是在操作系统运行之前执行的一段小程序。通过这段小程序,我们可以初始化硬件设备、建立内存空间的映射表,从而建立适当的系统软硬件环境,为最终调用操作系统内核做好准备。
对于嵌入式系统,Bootloader是基于特定硬件平台来实现的。因此,几乎不可能为所有的嵌入式系统建立一个通用的Bootloader,不同的处理器架构都有不同的Bootloader。Bootloader不但依赖于CPU的体系结构,而且依赖于嵌入式系统板级设备的配置。对于2块不同的嵌入式板而言,即使它们使用同一种处理器,要想让运行在一块板子上的Bootloader程序也能运行在另一块板子上,一般也都需要修改Bootloader的源程序。 反过来,大部分Bootloader仍然具有很多共性,某些Bootloader也能够支持多种体系结构的嵌入式系统。
例如,u-boot就同时支持PowerPC、ARM、MIPS和X86等体系结构,支持的板子有上百种。通常,它们都能够自动从存储介质上启动,都能够引导操作系统启动,并且大部分都可以支持串口和以太网接口。
本节将对各种Bootloader总结分类,分析它们的共同特点。以u-boot为例,详细讨论Bootloader的设计与实现。
2.1 u-boot工程简介
最早,DENX软件工程中心的Wolfgang Denk基于8xxrom的源码创建了ppcboot工程,并且不断添加处理器的支持。后来,Sysgo Gmbh把ppcboot移植到ARM平台上,创建了ARMboot工程。然后以ppcboot工程和armboot工程为基础,创建了u-boot工程。
现在u-boot已经能够支持PowerPC、ARM、X86、MIPS体系结构的上百种开发板,已经成为功能最多、灵活性最强并且开发最积极的开放源码BootLoader。目前仍然由DENX的Wolfgang Denk维护。
u-boot的源码包可以从sourceforge网站下载,还可以订阅该网站活跃的U-Boot Users邮件论坛,这个邮件论坛对于U-Boot的开发和使用都很有帮助。
u-boot软件包下载网站:https://ftp.denx.de/pub/u-boot/。
DENX相关的网站:http://www.denx.de/re/DPLG.html。
u-boot git仓库:https://gitlab.denx.de/u-boot/u-boot。
2.2 u-boot源码结构
从网站上下载得到u-boot源码包,例如:u-boot-2016.05.tar.bz2 (最新的u-boot版本已经不支持s3c2440)。
解压就可以得到全部u-boot源程序。在顶层目录下有20个子目录:
分别存放和管理不同的源程序。这些目录中所要存放的文件有其规则,可以分为3类。
- 第1类目录与处理器体系结构或者开发板硬件直接相关; ·
- 第2类目录是一些通用的函数或者驱动程序;
- 第3类目录是u-boot的应用程序、工具或者文档。
下面列出了u-boot顶层目录下各级目录存放原则:
- api: 硬件无关的功能函数的API。uboot移植时基本不用管,这些函数是uboot本身使用的。
- arch: 与体系结构相关的代码。比如 arm、 avr32、 m68k 等,我们现在用的是 ARM 芯片,所以只需要关心 arm 文件夹即可。
- board:存放电路板相关的目录文件,主要包含SDRAM、FLASH驱动,例如:samsung/smdk2410、samsung/smdk5250等目录。
- cmd:命令相关代码。
- common:common是普遍的普通的,这个文件夹下放的是一些与具体硬件无关的普遍适用的一些代码。譬如控制台实现、crc校验的。但是更多的主要是两类:一类是cmd开头的,是用来实现uboot的命令系统的;另一类是env开头的,是用来实现环境变量的。
- cpu: 这个目录是SoC相关的,里面存放的代码都是SoC相关初始化和控制代码(譬如CPU的、中断的、串口等SoC内部外设的,包括起始代码start.S也在这里)。里面很多子文件夹,每一个子文件夹就是一个SoC系列。
- configs:此文件夹为 uboot 配置文件, uboot 是可配置的,但是你要是自己从头开始一个一个项目的配置,那就太麻烦了,因此一般半导体或者开发板厂商都会制作好一个配置文件。我们可以在这个做好的配置文件基础上来添加自己想要的功能,这些半导体厂商或者开发板厂商制作好的配置文件统一命名为“xxx_defconfig”, xxx 表示开发板名字,这些 defconfig 文件都存放在 configs文件夹。
- disk: 磁盘有关的。
- doc:文档目录,里面存放了很多uboot相关文档,这些文档可以帮助我们理解uboot代码。
- drivers:顾名思义,驱动。这里面放的就是从linux源代码中扣出来的原封不动的linux设备驱动,主要是开发板上必须用到的一些驱动,如网卡驱动、Inand/SD卡、NandFlash等的驱动。要知道:uboot中的驱动其实就是linux中的驱动,uboot在一定程度上移植了linux的驱动给自己用。但是linux是操作系统而uboot只是个裸机程序,因此这种移植会有不同,让我说:uboot中的驱动其实是linux中的驱动的一部分。
- dts:设备树。
- examples:示例代码。
- fs:filesystem,文件系统。这个也是从linux源代码中移植过来的,用来管理Flash等资源。
- include:头文件目录。uboot和linux kernel在管理头文件时都采用了同一个思路,就是把所有的头文件全部集中存放在include目录下,而不是头文件跟着自己对应的c文件。所以在uboot中头文件包含时路径结构要在这里去找。
- lib:架构相关的库文件。这类文件夹中的内容移植时基本不用管。
- Licenses:许可证相关文件。
- net: 网络相关的代码,譬如uboot中的tftp nfs ping命令 都是在这里实现的。
- post:加电自检程序。
- scripts:脚本文件。
- test:测试代码。
- tools:里面是一些工具类的代码。譬如mkimage。
u-boot的源代码包含对几十种处理器、数百种开发板的支持。可是对于特定的开发板,配置编译过程只需要其中部分程序。这里具体以S3C2440 ARM920T处理器为例,具体分析S3C2410处理器和开发板所依赖的程序,以及u-boot的通用函数和工具。
2.3 u-boot编译
我们将下载的u-boot通过samba上传到ubuntu服务器上:
复制uboot到/word/hardware路径下,解压u-boot-2016.tar.bz2:
cd /work/sambashare mv u-boot-2016.05.tar.bz2 /work/hardware cd /work/hardware sudo apt-get install bzip2
tar -jxvf u-boot-2016.05.tar.bz2 cd u-boot-2016.05
uboot的编译分为两步:配置、编译。
2.3.1 配置
配置选择所要使用的board ,我调试使用的是S3C2440,但是configs目录下没有smdk2440_defconfig这个文件,只有smdk2410_defconfig,因此执行如下命令,生成.config文件:
make smdk2410_defconfig
2.3.2 编译
执行make命令,生成u-boot:
make ARCH=arm CROSS_COMPILE=arm-linux-
CROSS-COPILE是在Makefile文件中定义的变量,是用来指定交叉工具链,ARCH用来指定处理器架构。此外,我们可以在u-boot的顶层Makefile中定义:
CROSS_COMPILE=arm-linux- ARCH=arm
这样就省去了每次编译都要在控制台输入的麻烦。
编译成功后会生成一个u-boot.bin,可以烧写到开发板上,不过一般是用不起来的,需要进一步修改。
三 Source Insight加载u-boot
3.1 安装Source Insignt
下载Source Insight,并根据安装步骤进行安装。
3.2 打开Source Insight
点击上面的Project--->new project 然后弹出对话框:
这里project的名字我取成ubootProject,该project保存在我自己在G盘建立的一个文件文件夹下。 点击OK。
3.3 共享文件夹
在之前章节我们设置过samba服务器共享路径为/work/sambashare。而我们u-boot程序位于linux服务器的路径为/work/hardware/u-boot-2016.05,我们将u-boot移动到/work/sambashare路径:
windows下访问samba服务器:步骤:网络--->\\192.168.0.200--->Enter回车键:就可以看到我们共享的u-boot程序了:
3.4 映射网络驱动器
打开我的电脑,点击此电脑 --->映射网络驱动器 把\\192.168.0.200\share路径填进去,然后点击完成:
然后在我的电脑以下就能够看到例如以下截图了:
3.5 New Project Settings
继续回到Source Insight,进入设置页面,这里映射的是Z盘(自己的依据实际情况而定),点击OK:
3.6 添加文件
进入Add and Remove Project File页面:
然后点击确定,等待一下!成功之后选择close。
3.7 打开项目
成功后,我们点击右上角Project Symbal List:
3.8 增加文件类型
因为SI软件有个特点,它只能发现自己识别了的文件类型,对于它未识别的文件视而不见。例如刚开始.s文件就不认识,要在C源文件中加入*s文件,欺骗SI软件*.s也是C的源文件。点击options--->File Type Options,选择C/C++ Source File,添加*.S:
3.9 解析工程文件
点击Project -> Synchronize Files,进行设置。
SI工作原理就是把所有的源代码中的所有符号全部解析存储到数据库中,然后等我们进行符号查找时,SI不是查找文件而是查找数据库帮我们索引符号,因此SI查找速度非常快。因此我们使用SI查阅源码前先解析。
3.10 使用技巧之查找
3.11 显示行号
3.12 重新添加文件
四、make smdk2410_defconfig配置分析
Kconfig是各种配置界面的源文件,通过make menuconfig就可以打开u-boot配置界面,并可以对u-boot功能进行裁切,裁切后的配置保存到configs/smdk2410_defconfig文件。
执行配置命令make smdk2410_defconfig时先搜集所有默认的Kconfig配置,然后再用命令行指定的smdk2410_defconfig配置生成配置文件.config。
4.1 makefile基本语法
在分析u-boot编译过程之前,你必须了解makefile语法,这里我准备了一份makefile入门博客。
由于u-boot的Makefile中存在相互调用,这里介绍一下make -f和make -C区别:
- -C选项 :Makefile中使用make -C会改变当前的工作目录,表示到子目录下执行子目录的Makefile,顶层Makefile中的export的变量还有make默认的变量是可以传递给子目录中的Makefile的;
- -f选项:顶层Makefile使用make -f调用子目录中的文件(文件名可以随意,不一定用Makefile作为文件名,顶层Makefile中的export的变量也可以传递变量到底层目录,另外在命令行中加入变量赋值选项,将覆盖顶层Makefile中export的变量;
注意:在顶层Makefile中使用-f选项,例如make -f ./xxx/xx/build.mk 此时make命令的工作目录仍然是顶层目录,即CUDIR变量依然是./目录而不是./xxx/xx/目录。
4.2 执行make smdk2410_defconfig V=1配置命令
命令行输入如下:
make smdk2410_defconfig V=1
V=1 指示编译显示详细的输出。默认V=0,编译仅显示必要的简略信息。
configs/smdk2410_defconfig:
CONFIG_ARM=y CONFIG_TARGET_SMDK2410=y CONFIG_HUSH_PARSER=y CONFIG_SYS_PROMPT="SMDK2410 # " CONFIG_CMD_USB=y # CONFIG_CMD_SETEXPR is not set CONFIG_CMD_DHCP=y CONFIG_CMD_PING=y CONFIG_CMD_CACHE=y CONFIG_CMD_EXT2=y CONFIG_CMD_FAT=y
编译输出如下:
- 第一步:执行make -f ./scripts/Makefile.build obj=scripts/basic,编译生成scripts/basic/fixdep工具;
- 第二步:执行make -f ./scripts/Makefile.build obj=scripts/kconfig smdk2410_defconfig,编译生成scripts/kcofig/conf工具;
- 第三步:执行scripts/kconfig/conf --defconfig=arch/../configs/smdk2410_defconfig Kconfig,scripts/kconfig/conf根据smdk2410_defconfig生成.config配置文件;
其中.config文件比较重要,在后续编译中会用到,.config部分代码:
言归正传,整个配置流程的目的就是为了生成.config文件,实际上就是根据configs/smdk2410_defconfig 文件以及我们make menuconfig看到的那些默认配置(或者说是各个目录下的Kconfig文件中有效的default项)生成的。
下面详细分析.config文件是如何一步一步生成的。 Makefile的核心是依赖和命令,对于每个目标,首先会检查依赖,如果依赖存在,则执行命令更新目标;如果依赖不存在,则会以依赖为目标,先生成依赖,待依赖生成后,再执行命令生成目标。
4.3 顶层make smdk2410_defconfig规则
执行make smdk2410_defconfig命令时,u-boot根目录下的Makefile中有唯一的规则匹配目标:
第476行:
config: scripts_basic outputmakefile FORCE $(Q)$(MAKE) $(build)=scripts/kconfig $@ %config: scripts_basic outputmakefile FORCE $(Q)$(MAKE) $(build)=scripts/kconfig $@
对于目标,smdk2410_defconfig,展开则有:
smdk2410_defconfig: scripts_basic outputmakefile FORCE $(Q)$(MAKE) $(build)=scripts/kconfig smdk2410_defconfig
build 在 scripts/Kbuild.include定义:
build := -f $(srctree)/scripts/Makefile.build obj
最终执行的命令就是:
make -f scripts/Makefile.build obj=scripts/kconfig smdk2410_defconfig
也就是我们4.2节中所说的第二步,编译生成scripts/kcofig/conf工具。我们先来分析smdk2410_defconfig目标依赖的执行,然后再来分析该条命令。
4.4 scripts_basic依赖
目标smdk2410_defconfig的生成依赖于scripts_basic,outputmakefile和FORCE中,只有scripts_basic需要执行命令,如下:
# Basic helpers built in scripts/ PHONY += scripts_basic scripts_basic: $(Q)$(MAKE) $(build)=scripts/basic $(Q)rm -f .tmp_quiet_recordmcount
可见scripts_basic没有进一步的依赖,展开后规则如下:
scripts_basic: $(Q) make -f ./scripts/Makefile.build obj=scripts/basic $(Q) rm -f .tmp_quiet_recordmcount
也就是我们4.2节中所说的第一步,make命令会转到文件scripts/Makefile.build去执行。
大量实际目标的编译都是调用scripts/Makefile.build完成的,文件script/Makefile.build的开头会根据传入的obj=scripts/basic参数设置src=scripts/basic:
# Modified for U-Boot
prefix := tpl
src := $(patsubst $(prefix)/%,%,$(obj))
ifeq ($(obj),$(src))
prefix := spl
src := $(patsubst $(prefix)/%,%,$(obj))
ifeq ($(obj),$(src))
prefix := .
endif
endif
kbuild-dir根据src变量(等于obj变量)是绝对路径还是相对路径来确定当前编译的目录,若为绝对路径则该目录即src变量的值,若为相对路径则该变量就是src变量相对于源码根目录的目录。kbuild-file即在该目录下查找Kbuild文件,若能找到,则使用kbuild作为该目录的编译文件,若找不到则使用该目录下的Makefile作为该目录的编译文件,然后将该文件包含进来。
# The filename Kbuild has precedence over Makefile
kbuild-dir := $(if $(filter /%,$(src)),$(src),$(srctree)/$(src))
kbuild-file := $(if $(wildcard $(kbuild-dir)/Kbuild),$(kbuild-dir)/Kbuild,$(kbuild-dir)/Makefile)
include $(kbuild-file)
注意:具体的分析可以看这篇博客:六 makefile.build的分析,写的很详细。
这里展开替换后相当于:
include ./scripts/basic/Makefile
文件scripts/basic/Makefile中定义了编译在主机上执行的工具fixdep:
hostprogs-y := fixdep always := $(hostprogs-y) # fixdep is needed to compile other host programs $(addprefix $(obj)/,$(filter-out fixdep,$(always))): $(obj)/fixdep
工具fixdep用于更新每一个生成目标的依赖文件*.cmd。
上面定义的这个$(always)在scripts/Makefile.build里会被添加到targets中:
targets += $(extra-y) $(MAKECMDGOALS) $(always)
简而言之,scripts_basic规则:
scripts_basic: $(Q) make -f ./scripts/Makefile.build obj=scripts/basic
最终结果就是编译scripts/basic/fixdep.c生成主机上的可执行文件fixdep。至于为什么要编译fixdep和如何使用fixdep,会在后面介绍。
4.5 outputmakefile依赖
依赖outputmakefile:
PHONY += outputmakefile # outputmakefile generates a Makefile in the output directory, if using a # separate output directory. This allows convenient use of make in the # output directory. outputmakefile: ifneq ($(KBUILD_SRC),) $(Q)ln -fsn $(srctree) source $(Q)$(CONFIG_SHELL) $(srctree)/scripts/mkmakefile \ $(srctree) $(objtree) $(VERSION) $(PATCHLEVEL) endif
outputmakefile也没有进一步的依赖。 如果执行如下命令:
make smdk2410_defconfig O=out
那么所有生成的目标都将放到out目录,此时会通过outputmakefile导出一个makefile到out目录进行编译。 由于在当前目录下编译,$(KBUILD_SRC)为空,不需要导出makefile文件,outputmakefile为空目标。
4.6 FORCE依赖
PHONY += FORCE FORCE:
FORCE被定义为一个空目标。 如果一个目标添加FORCE依赖,每次编译都会去先去执行FORCE(实际上什么都不做),然后运行命令更新目标,这样就能确保目标每次都会被更新。在这里也就保证目标smdk2410_defconfig的命令:
$(Q)$(MAKE) $(build)=scripts/kconfig smdk2410_defconfig
总是能够被执行。
4.7 make -f scripts/Makefile.build obj=scripts/kconfig smdk2410_defconfig
完成对目标smdk2410_defconfig依赖的更新后,接下来就是执行顶层目标的命令完成对smdk2410_defconfig的更新,也就是执行如下命令:
smdk2410_defconfig: scripts_basic outputmakefile FORCE make -f ./scripts/Makefile.build obj= scripts/kconfig smdk2410_defconfig
这个make命令会第二次转到scripts/Makefile.build去执行。
文件script/Makefile.build的开头会根据传入的obj=scripts/kconfig参数设置src=scripts/kconfig。然后搜寻\$(srctree)/\$(src)子目录下的makefile,由于src=scripts/kconfig参数不同于第一次调用的参数(src=scripts/basic),此处包含的makefile也不同于第一次的makefile了:
# The filename Kbuild has precedence over Makefile
kbuild-dir := $(if $(filter /%,$(src)),$(src),$(srctree)/$(src))
kbuild-file := $(if $(wildcard $(kbuild-dir)/Kbuild),$(kbuild-dir)/Kbuild,$(kbuild-dir)/Makefile)
include $(kbuild-file)
这里替换展开后相当于:
include ./scripts/kconfig/Makefile
文件scripts/kconfig/Makefile中定义了所有匹配%config的目标:
PHONY += xconfig gconfig menuconfig config silentoldconfig update-po-config \
localmodconfig localyesconfig
PHONY += oldnoconfig savedefconfig defconfig
PHONY += kvmconfig
PHONY += tinyconfig
对于这里传入的smdk2410_defconfig,匹配的目标是:
%_defconfig: $(obj)/conf $(Q)$< $(silent) --defconfig=arch/$(SRCARCH)/configs/$@ $(Kconfig)
展开为:
smdk2410_defconfig: scripts/kconfig/conf $(Q)scripts/kconfig/conf --defconfig=arch/../configs/smdk2410_defconfig Kconfig
此处目标smdk2410_defconfig依赖于scripts/kconfig/conf,接下来检查并生成依赖。
hostprogs-y := conf nconf mconf kxgettext qconf gconf
hostprogs-y指出conf被定义为主机上执行的程序,其依赖于另外两个文件:
conf-objs := conf.o zconf.tab.o
通过编译conf.c和zconf.tab.c生成conf-objs,并链接为scripts/kconfig/conf。
生成依赖后就是执行目标的命令了,这也是我们4.2节中所说的第三步:
$(Q)scripts/kconfig/conf --defconfig=arch/../configs/rpi_3_32b_defconfig Kconfig
此处只做简要的说明:
conf工具从根目录下开始树状读取默认的Kconfig文件,分析其配置并保存在内存中。分析完默认的Kconfig后再读取指定文件(即arch/../configs/smdk2410_defconfig)更新得到最终的符号表,并输出到.config文件中。
至此完成了make smdk2410_defconfig执行配置涉及的所有依赖和命令的分析。
4.8 make defconfig配置流程简图
五、make编译正向分析之顶层目标依赖
执行make进行编译,生成可执行的二进制文件u-boot.bin或u-boot.elf。由于make编译日志信息比较多,这里就不展开了:

1 scripts/kconfig/conf --silentoldconfig Kconfig 2 CHK include/config.h 3 UPD include/config.h 4 GEN include/autoconf.mk 5 GEN include/autoconf.mk.dep 6 CHK include/config/uboot.release 7 UPD include/config/uboot.release 8 CHK include/generated/version_autogenerated.h 9 UPD include/generated/version_autogenerated.h 10 CHK include/generated/timestamp_autogenerated.h 11 UPD include/generated/timestamp_autogenerated.h 12 CC lib/asm-offsets.s 13 CHK include/generated/generic-asm-offsets.h 14 UPD include/generated/generic-asm-offsets.h 15 CC arch/arm/lib/asm-offsets.s 16 CHK include/generated/asm-offsets.h 17 UPD include/generated/asm-offsets.h 18 HOSTCC tools/envcrc.o 19 WRAP tools/lib/crc32.c 20 HOSTCC tools/lib/crc32.o 21 WRAP tools/common/env_embedded.c 22 HOSTCC tools/common/env_embedded.o 23 WRAP tools/lib/sha1.c 24 HOSTCC tools/lib/sha1.o 25 HOSTLD tools/envcrc 26 HOSTCC tools/gen_eth_addr 27 HOSTCC tools/img2srec 28 HOSTCC tools/mkenvimage.o 29 HOSTCC tools/os_support.o 30 HOSTLD tools/mkenvimage 31 HOSTCC tools/aisimage.o 32 HOSTCC tools/atmelimage.o 33 WRAP tools/common/bootm.c 34 HOSTCC tools/common/bootm.o 35 HOSTCC tools/default_image.o 36 WRAP tools/lib/fdtdec_common.c 37 HOSTCC tools/lib/fdtdec_common.o 38 WRAP tools/lib/fdtdec.c 39 HOSTCC tools/lib/fdtdec.o 40 HOSTCC tools/fit_common.o 41 HOSTCC tools/fit_image.o 42 HOSTCC tools/gpimage.o 43 HOSTCC tools/gpimage-common.o 44 WRAP tools/common/image-fit.c 45 HOSTCC tools/common/image-fit.o 46 HOSTCC tools/image-host.o 47 WRAP tools/common/image.c 48 HOSTCC tools/common/image.o 49 HOSTCC tools/imagetool.o 50 HOSTCC tools/imximage.o 51 HOSTCC tools/kwbimage.o 52 WRAP tools/lib/md5.c 53 HOSTCC tools/lib/md5.o 54 HOSTCC tools/lpc32xximage.o 55 HOSTCC tools/mxsimage.o 56 HOSTCC tools/omapimage.o 57 HOSTCC tools/pblimage.o 58 HOSTCC tools/pbl_crc32.o 59 WRAP tools/lib/rc4.c 60 HOSTCC tools/lib/rc4.o 61 HOSTCC tools/rkcommon.o 62 HOSTCC tools/rkimage.o 63 HOSTCC tools/rksd.o 64 HOSTCC tools/rkspi.o 65 HOSTCC tools/socfpgaimage.o 66 WRAP tools/lib/sha256.c 67 HOSTCC tools/lib/sha256.o 68 WRAP tools/common/hash.c 69 HOSTCC tools/common/hash.o 70 HOSTCC tools/ublimage.o 71 HOSTCC tools/zynqimage.o 72 WRAP tools/lib/libfdt/fdt.c 73 HOSTCC tools/lib/libfdt/fdt.o 74 WRAP tools/lib/libfdt/fdt_ro.c 75 HOSTCC tools/lib/libfdt/fdt_ro.o 76 WRAP tools/lib/libfdt/fdt_rw.c 77 HOSTCC tools/lib/libfdt/fdt_rw.o 78 WRAP tools/lib/libfdt/fdt_strerror.c 79 HOSTCC tools/lib/libfdt/fdt_strerror.o 80 WRAP tools/lib/libfdt/fdt_wip.c 81 HOSTCC tools/lib/libfdt/fdt_wip.o 82 WRAP tools/lib/libfdt/fdt_region.c 83 HOSTCC tools/lib/libfdt/fdt_region.o 84 WRAP tools/lib/libfdt/fdt_sw.c 85 HOSTCC tools/lib/libfdt/fdt_sw.o 86 HOSTCC tools/dumpimage.o 87 HOSTLD tools/dumpimage 88 HOSTCC tools/mkimage.o 89 HOSTLD tools/mkimage 90 HOSTCC tools/proftool 91 HOSTCC tools/fdtgrep.o 92 HOSTLD tools/fdtgrep 93 LD arch/arm/cpu/built-in.o 94 CC arch/arm/cpu/arm920t/cpu.o 95 CC arch/arm/cpu/arm920t/s3c24x0/cpu_info.o 96 CC arch/arm/cpu/arm920t/s3c24x0/speed.o 97 CC arch/arm/cpu/arm920t/s3c24x0/timer.o 98 LD arch/arm/cpu/arm920t/s3c24x0/built-in.o 99 LD arch/arm/cpu/arm920t/built-in.o 100 AS arch/arm/cpu/arm920t/start.o 101 AS arch/arm/lib/vectors.o 102 AS arch/arm/lib/crt0.o 103 AS arch/arm/lib/relocate.o 104 CC arch/arm/lib/bootm.o 105 CC arch/arm/lib/sections.o 106 CC arch/arm/lib/stack.o 107 CC arch/arm/lib/interrupts.o 108 CC arch/arm/lib/reset.o 109 CC arch/arm/lib/cache.o 110 CC arch/arm/lib/cache-cp15.o 111 LD arch/arm/lib/built-in.o 112 AR arch/arm/lib/lib.a 113 CC arch/arm/lib/eabi_compat.o 114 LD board/samsung/common/built-in.o 115 CC board/samsung/smdk2410/smdk2410.o 116 AS board/samsung/smdk2410/lowlevel_init.o 117 LD board/samsung/smdk2410/built-in.o 118 CC cmd/boot.o 119 CC cmd/bootm.o 120 CC cmd/help.o 121 CC cmd/version.o 122 CC cmd/source.o 123 CC cmd/bdinfo.o 124 CC cmd/cache.o 125 CC cmd/console.o 126 CC cmd/date.o 127 CC cmd/echo.o 128 CC cmd/elf.o 129 CC cmd/exit.o 130 CC cmd/ext2.o 131 CC cmd/fat.o 132 CC cmd/flash.o 133 CC cmd/itest.o 134 CC cmd/load.o 135 CC cmd/mem.o 136 CC cmd/misc.o 137 CC cmd/mtdparts.o 138 CC cmd/nand.o 139 CC cmd/net.o 140 CC cmd/pcmcia.o 141 CC cmd/reginfo.o 142 CC cmd/test.o 143 CC cmd/ubi.o 144 CC cmd/ubifs.o 145 CC cmd/usb.o 146 CC cmd/ximg.o 147 CC cmd/yaffs2.o 148 CC cmd/nvedit.o 149 CC cmd/disk.o 150 LD cmd/built-in.o 151 CC common/init/board_init.o 152 LD common/init/built-in.o 153 CC common/main.o 154 CC common/exports.o 155 CC common/hash.o 156 CC common/cli_hush.o 157 CC common/autoboot.o 158 CC common/bootretry.o 159 CC common/board_f.o 160 CC common/board_r.o 161 CC common/bootm.o 162 CC common/bootm_os.o 163 CC common/env_attr.o 164 CC common/env_callback.o 165 CC common/env_flags.o 166 CC common/env_flash.o 167 CC common/usb.o 168 CC common/usb_hub.o 169 CC common/usb_storage.o 170 CC common/flash.o 171 CC common/splash.o 172 CC common/usb_kbd.o 173 CC common/env_common.o 174 CC common/console.o 175 CC common/dlmalloc.o 176 CC common/image.o 177 CC common/memsize.o 178 CC common/stdio.o 179 CC common/cli_simple.o 180 CC common/cli.o 181 CC common/cli_readline.o 182 CC common/command.o 183 CC common/s_record.o 184 CC common/xyzModem.o 185 LD common/built-in.o 186 CC common/env_embedded.o 187 CC disk/part.o 188 CC disk/part_dos.o 189 LD disk/built-in.o 190 LD drivers/adc/built-in.o 191 LD drivers/block/built-in.o 192 CC drivers/crypto/fsl/sec.o 193 LD drivers/crypto/fsl/built-in.o 194 LD drivers/crypto/rsa_mod_exp/built-in.o 195 LD drivers/crypto/built-in.o 196 LD drivers/dfu/built-in.o 197 LD drivers/hwmon/built-in.o 198 CC drivers/input/input.o 199 LD drivers/input/built-in.o 200 LD drivers/memory/built-in.o 201 LD drivers/misc/built-in.o 202 CC drivers/pcmcia/tqm8xx_pcmcia.o 203 LD drivers/pcmcia/built-in.o 204 LD drivers/pwm/built-in.o 205 CC drivers/rtc/date.o 206 CC drivers/rtc/s3c24x0_rtc.o 207 LD drivers/rtc/built-in.o 208 LD drivers/soc/built-in.o 209 LD drivers/sound/built-in.o 210 LD drivers/spmi/built-in.o 211 LD drivers/thermal/built-in.o 212 LD drivers/timer/built-in.o 213 LD drivers/tpm/built-in.o 214 LD drivers/twserial/built-in.o 215 LD drivers/video/bridge/built-in.o 216 LD drivers/video/built-in.o 217 LD drivers/watchdog/built-in.o 218 LD drivers/built-in.o 219 LD drivers/dma/built-in.o 220 LD drivers/gpio/built-in.o 221 LD drivers/i2c/built-in.o 222 LD drivers/mmc/built-in.o 223 CC drivers/mtd/mtdcore.o 224 CC drivers/mtd/mtd_uboot.o 225 CC drivers/mtd/mtdpart.o 226 CC drivers/mtd/cfi_flash.o 227 CC drivers/mtd/jedec_flash.o 228 LD drivers/mtd/built-in.o 229 CC drivers/mtd/nand/nand.o 230 CC drivers/mtd/nand/nand_bbt.o 231 CC drivers/mtd/nand/nand_ids.o 232 CC drivers/mtd/nand/nand_util.o 233 CC drivers/mtd/nand/nand_ecc.o 234 CC drivers/mtd/nand/nand_base.o 235 CC drivers/mtd/nand/nand_timings.o 236 CC drivers/mtd/nand/s3c2410_nand.o 237 LD drivers/mtd/nand/built-in.o 238 LD drivers/mtd/onenand/built-in.o 239 LD drivers/mtd/spi/built-in.o 240 CC drivers/mtd/ubi/attach.o 241 CC drivers/mtd/ubi/build.o 242 CC drivers/mtd/ubi/vtbl.o 243 CC drivers/mtd/ubi/vmt.o 244 CC drivers/mtd/ubi/upd.o 245 CC drivers/mtd/ubi/kapi.o 246 CC drivers/mtd/ubi/eba.o 247 CC drivers/mtd/ubi/io.o 248 CC drivers/mtd/ubi/wl.o 249 CC drivers/mtd/ubi/crc32.o 250 CC drivers/mtd/ubi/misc.o 251 CC drivers/mtd/ubi/debug.o 252 LD drivers/mtd/ubi/built-in.o 253 CC drivers/net/cs8900.o 254 LD drivers/net/built-in.o 255 LD drivers/net/phy/built-in.o 256 LD drivers/pci/built-in.o 257 LD drivers/power/built-in.o 258 LD drivers/power/battery/built-in.o 259 LD drivers/power/fuel_gauge/built-in.o 260 LD drivers/power/mfd/built-in.o 261 LD drivers/power/pmic/built-in.o 262 LD drivers/power/regulator/built-in.o 263 CC drivers/serial/serial.o 264 CC drivers/serial/serial_s3c24x0.o 265 LD drivers/serial/built-in.o 266 CC drivers/spi/spi.o 267 LD drivers/spi/built-in.o 268 LD drivers/usb/common/built-in.o 269 LD drivers/usb/dwc3/built-in.o 270 LD drivers/usb/emul/built-in.o 271 LD drivers/usb/eth/built-in.o 272 LD drivers/usb/gadget/built-in.o 273 LD drivers/usb/gadget/udc/built-in.o 274 CC drivers/usb/host/ohci-s3c24xx.o 275 LD drivers/usb/host/built-in.o 276 LD drivers/usb/musb-new/built-in.o 277 LD drivers/usb/musb/built-in.o 278 LD drivers/usb/phy/built-in.o 279 LD drivers/usb/ulpi/built-in.o 280 CC fs/fs.o 281 CC fs/ext4/ext4fs.o 282 CC fs/ext4/ext4_common.o 283 CC fs/ext4/dev.o 284 LD fs/ext4/built-in.o 285 CC fs/fat/fat.o 286 CC fs/fat/file.o 287 LD fs/fat/built-in.o 288 CC fs/ubifs/ubifs.o 289 CC fs/ubifs/io.o 290 CC fs/ubifs/super.o 291 CC fs/ubifs/sb.o 292 CC fs/ubifs/master.o 293 CC fs/ubifs/lpt.o 294 CC fs/ubifs/lpt_commit.o 295 CC fs/ubifs/scan.o 296 CC fs/ubifs/lprops.o 297 CC fs/ubifs/tnc.o 298 CC fs/ubifs/tnc_misc.o 299 CC fs/ubifs/debug.o 300 CC fs/ubifs/crc16.o 301 CC fs/ubifs/budget.o 302 CC fs/ubifs/log.o 303 CC fs/ubifs/orphan.o 304 CC fs/ubifs/recovery.o 305 CC fs/ubifs/replay.o 306 CC fs/ubifs/gc.o 307 LD fs/ubifs/built-in.o 308 CC fs/yaffs2/yaffs_allocator.o 309 CC fs/yaffs2/yaffs_attribs.o 310 CC fs/yaffs2/yaffs_bitmap.o 311 CC fs/yaffs2/yaffs_uboot_glue.o 312 CC fs/yaffs2/yaffs_checkptrw.o 313 CC fs/yaffs2/yaffs_ecc.o 314 CC fs/yaffs2/yaffs_error.o 315 CC fs/yaffs2/yaffsfs.o 316 CC fs/yaffs2/yaffs_guts.o 317 CC fs/yaffs2/yaffs_nameval.o 318 CC fs/yaffs2/yaffs_nand.o 319 CC fs/yaffs2/yaffs_packedtags1.o 320 CC fs/yaffs2/yaffs_packedtags2.o 321 CC fs/yaffs2/yaffs_qsort.o 322 CC fs/yaffs2/yaffs_summary.o 323 CC fs/yaffs2/yaffs_tagscompat.o 324 CC fs/yaffs2/yaffs_verify.o 325 CC fs/yaffs2/yaffs_yaffs1.o 326 CC fs/yaffs2/yaffs_yaffs2.o 327 CC fs/yaffs2/yaffs_mtdif.o 328 CC fs/yaffs2/yaffs_mtdif2.o 329 LD fs/yaffs2/built-in.o 330 LD fs/built-in.o 331 CC lib/bzip2/bzlib.o 332 CC lib/bzip2/bzlib_crctable.o 333 CC lib/bzip2/bzlib_decompress.o 334 CC lib/bzip2/bzlib_randtable.o 335 CC lib/bzip2/bzlib_huffman.o 336 LD lib/bzip2/built-in.o 337 CC lib/lzma/LzmaDec.o 338 CC lib/lzma/LzmaTools.o 339 LD lib/lzma/built-in.o 340 CC lib/lzo/lzo1x_decompress.o 341 LD lib/lzo/built-in.o 342 CC lib/zlib/zlib.o 343 LD lib/zlib/built-in.o 344 CC lib/crc7.o 345 CC lib/crc8.o 346 CC lib/crc16.o 347 CC lib/gunzip.o 348 CC lib/initcall.o 349 CC lib/lmb.o 350 CC lib/ldiv.o 351 CC lib/net_utils.o 352 CC lib/qsort.o 353 CC lib/rc4.o 354 CC lib/strmhz.o 355 CC lib/rbtree.o 356 CC lib/list_sort.o 357 CC lib/hashtable.o 358 CC lib/errno.o 359 CC lib/display_options.o 360 CC lib/crc32.o 361 CC lib/ctype.o 362 CC lib/div64.o 363 CC lib/hang.o 364 CC lib/linux_compat.o 365 CC lib/linux_string.o 366 CC lib/membuff.o 367 CC lib/slre.o 368 CC lib/string.o 369 CC lib/time.o 370 CC lib/vsprintf.o 371 CC lib/panic.o 372 CC lib/strto.o 373 LD lib/built-in.o 374 CC net/checksum.o 375 CC net/arp.o 376 CC net/bootp.o 377 CC net/eth_legacy.o 378 CC net/eth_common.o 379 CC net/net.o 380 CC net/nfs.o 381 CC net/ping.o 382 CC net/tftp.o 383 LD net/built-in.o 384 LD test/built-in.o 385 LD test/dm/built-in.o 386 CC examples/standalone/stubs.o 387 LD examples/standalone/libstubs.o 388 CC examples/standalone/hello_world.o 389 LD examples/standalone/hello_world 390 OBJCOPY examples/standalone/hello_world.srec 391 OBJCOPY examples/standalone/hello_world.bin 392 LDS u-boot.lds
393 LD u-boot 394 OBJCOPY u-boot.srec 395 OBJCOPY u-boot-nodtb.bin 396 COPY u-boot.bin 397 SYM u-boot.sym 398 CFG u-boot.cfg
实际上,通过这个日志输出,我们可以发现编译的文件中有一些是带有s3c24x0、smdk2410字样的,这也是告诉我们这些文件是和cpu直接相关的,如果我们想新加一个开发板,那么我们也应该为该开发板cpu配置这些相关文件。
95 CC arch/arm/cpu/arm920t/s3c24x0/cpu_info.o 96 CC arch/arm/cpu/arm920t/s3c24x0/speed.o 97 CC arch/arm/cpu/arm920t/s3c24x0/timer.o 98 LD arch/arm/cpu/arm920t/s3c24x0/built-in.o 115 CC board/samsung/smdk2410/smdk2410.o 116 AS board/samsung/smdk2410/lowlevel_init.o 117 LD board/samsung/smdk2410/built-in.o
LD为链接操作,由arm-linux-ld完成,将各个每个目录下的.o文件链接生成built-in.o目标文件。
CC为编译操作,由arm-linux-gcc完成,将各个源文件编译生成.o目标文件。
5.1 编译参数
在编译的时候我们需要配置ARCH、以及CROSS_COMPILE参数,那这两个参数有什么用呢?
5.1.1 ARCH
直接在顶层的Makefile搜索ARCH,发现文件中存在大量的$(srctree)/arch/$(ARCH)/,$(srctree)表示uboot当前路径.,不难猜出$(ARCH)实际上就是arch路径下的文件名称:可以看到arch目录下文件夹的名字实际上表示的就是处理器架构:
drwxr-xr-x 17 root root 4096 2月 8 2022 ./ drwxr-xr-x 22 root root 4096 5月 9 20:07 ../ drwxr-xr-x 6 root root 4096 2月 8 2022 arc/ drwxr-xr-x 28 root root 4096 2月 8 2022 arm/ drwxr-xr-x 5 root root 4096 2月 8 2022 avr32/ drwxr-xr-x 5 root root 4096 2月 8 2022 blackfin/ -rw-r--r-- 1 root root 20 2月 8 2022 .gitignore -rw-r--r-- 1 root root 4385 2月 8 2022 Kconfig drwxr-xr-x 5 root root 4096 2月 8 2022 m68k/ drwxr-xr-x 6 root root 4096 2月 8 2022 microblaze/ drwxr-xr-x 8 root root 4096 2月 8 2022 mips/ drwxr-xr-x 5 root root 4096 2月 8 2022 nds32/ drwxr-xr-x 6 root root 4096 2月 8 2022 nios2/ drwxr-xr-x 5 root root 4096 2月 8 2022 openrisc/ drwxr-xr-x 6 root root 4096 2月 8 2022 powerpc/ drwxr-xr-x 6 root root 4096 2月 8 2022 sandbox/ drwxr-xr-x 5 root root 4096 2月 8 2022 sh/ drwxr-xr-x 5 root root 4096 2月 8 2022 sparc/ drwxr-xr-x 6 root root 4096 2月 8 2022 x86/
5.1.2 CROSS_COMPILE
直接在顶层的Makefile搜索CROSS_COMPILE,我们会发现下面这些变量引用了CROSS_COMPILE:
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
那么LD、CC这些是什么,这些实际上就是交叉编译工具。如果我们想使用arm-linux-gcc编译器,我们就必须指定CROSS_COMPILE = arm-linux-。
5.1.3 V=1
在Makefile中找到$(V)引用:
# # Normally, we echo the whole command before executing it. By making # that echo $($(quiet)$(cmd)), we now have the possibility to set # $(quiet) to choose other forms of output instead, e.g. # # quiet_cmd_cc_o_c = Compiling $(RELDIR)/$@ # cmd_cc_o_c = $(CC) $(c_flags) -c -o $@ $< # # If $(quiet) is empty, the whole command will be printed. # If it is set to "quiet_", only the short version will be printed. # If it is set to "silent_", nothing will be printed at all, since # the variable $(silent_cmd_cc_o_c) doesn't exist. # # A simple variant is to prefix commands with $(Q) - that's useful # for commands that shall be hidden in non-verbose mode. # # $(Q)ln $@ :< # # If KBUILD_VERBOSE equals 0 then the above command will be hidden. # If KBUILD_VERBOSE equals 1 then the above command is displayed. # # To put more focus on warnings, be less verbose as default # Use 'make V=1' to see the full commands ifeq ("$(origin V)", "command line") # V变量 来自命令行 KBUILD_VERBOSE = $(V) endif ifndef KBUILD_VERBOSE KBUILD_VERBOSE = 0 endif ifeq ($(KBUILD_VERBOSE),1) quiet = Q = else quiet=quiet_ Q = @ endif
可以看到如果在命令行指定了V=1,那么:
quiet =
Q =
如果不设置Q,那么在执行命令时将会打印整个命令,也就是会回显命令。
否则:
quiet=quiet_
Q = @
如果设置为Q=@。在执行命令时关闭回显。
5.2 目标_all和all对$(ALL-y)的依赖
从顶层的Makefile开始查找,找到的第一个目标为_all,128行:
# That's our default target when none is given on the command line
PHONY := _all _all:
在Makefile中,.PHONY后面的target表示的也是一个伪造的target, 而不是真实存在的文件target,注意Makefile的target默认是文件。
紧接着会对_all伪目标添加all伪目标依赖,194行:
# If building an external module we do not care about the all: rule # but instead _all depend on modules PHONY += all ifeq ($(KBUILD_EXTMOD),) _all: all else _all: modules endif
当我们定义了M变量或者SUBDIRS时表示编译一个外部模块,显然我们并没有编译一个外部模块。因此伪目标_all依赖all。
all自身依赖于$(ALL-y),803行:
all: $(ALL-y) ifneq ($(CONFIG_SYS_GENERIC_BOARD),y) @echo "===================== WARNING ======================" @echo "Please convert this board to generic board." @echo "Otherwise it will be removed by the end of 2014." @echo "See doc/README.generic-board for further information" @echo "====================================================" endif ifeq ($(CONFIG_DM_I2C_COMPAT),y) @echo "===================== WARNING ======================" @echo "This board uses CONFIG_DM_I2C_COMPAT. Please remove" @echo "(possibly in a subsequent patch in your series)" @echo "before sending patches to the mailing list." @echo "====================================================" endif
5.3 目标$(ALL-y)
$(ALL-y)定义了最终需要生成的所有文件,731行
# Always append ALL so that arch config.mk's can add custom ones
ALL-y += u-boot.srec u-boot.bin u-boot.sym System.map u-boot.cfg binary_size_check ALL-$(CONFIG_ONENAND_U_BOOT) += u-boot-onenand.bin ifeq ($(CONFIG_SPL_FSL_PBL),y) ALL-$(CONFIG_RAMBOOT_PBL) += u-boot-with-spl-pbl.bin else ifneq ($(CONFIG_SECURE_BOOT), y) # For Secure Boot The Image needs to be signed and Header must also # be included. So The image has to be built explicitly ALL-$(CONFIG_RAMBOOT_PBL) += u-boot.pbl endif endif ALL-$(CONFIG_SPL) += spl/u-boot-spl.bin ALL-$(CONFIG_SPL_FRAMEWORK) += u-boot.img # 镜像文件 ALL-$(CONFIG_TPL) += tpl/u-boot-tpl.bin ALL-$(CONFIG_OF_SEPARATE) += u-boot.dtb # 设备树文件 ifeq ($(CONFIG_SPL_FRAMEWORK),y) ALL-$(CONFIG_OF_SEPARATE) += u-boot-dtb.img # 设备树镜像文件 endif ALL-$(CONFIG_OF_HOSTFILE) += u-boot.dtb ifneq ($(CONFIG_SPL_TARGET),) ALL-$(CONFIG_SPL) += $(CONFIG_SPL_TARGET:"%"=%) endif ALL-$(CONFIG_REMAKE_ELF) += u-boot.elf # u-boot.bin文件加入了调试信息,可以用来调试 ALL-$(CONFIG_EFI_APP) += u-boot-app.efi ALL-$(CONFIG_EFI_STUB) += u-boot-payload.efi ifneq ($(BUILD_ROM),) ALL-$(CONFIG_X86_RESET_VECTOR) += u-boot.rom endif # enable combined SPL/u-boot/dtb rules for tegra ifeq ($(CONFIG_TEGRA)$(CONFIG_SPL),yy) ALL-y += u-boot-tegra.bin u-boot-nodtb-tegra.bin ALL-$(CONFIG_OF_SEPARATE) += u-boot-dtb-tegra.bin endif # Add optional build target if defined in board/cpu/soc headers ifneq ($(CONFIG_BUILD_TARGET),) ALL-y += $(CONFIG_BUILD_TARGET:"%"=%) endif
以上的$(ALL-y)目标中看起来很复杂,但是除了第一行的通用目标外,其余的目标都只有在特殊条件下才生成,这里略去不提,只分析通用目标依赖:
ALL-y += u-boot.srec u-boot.bin u-boot.sym System.map u-boot.cfg binary_size_check
这里有必要说一下u-boot.img,u-boot.bin:
- u-boot.bin:是二进制编译的uboot引导加载程序, 很多image 文件的生成都需要依赖于它;
- u-boot.img:它是给u-boot.bin 加上0x40 Byte 长度的Header。 里面包含加载地址,运行地址,CRC等重要信息, 用来让它的加载程序识别;这个只有在配置CONFIG_SPL_FRAMEWORK时才有效;
芯片烧录选择u-boot.bin还是u-boot.img取决于设备的性质。目前许多SoC/CPU启动ROM都能够加载u-boot.img,读取文件的头部,加载u-boot.bin到内存中并最终执行它。
其中u-bootimg文件生成规则如下
u-boot-dtb.img u-boot.img u-boot.kwb u-boot.pbl u-boot-ivt.img: \ $(if $(CONFIG_SPL_LOAD_FIT),u-boot-nodtb.bin dts/dt.dtb,u-boot.bin) FORCE $(call if_changed,mkimage) u-boot.itb: u-boot-nodtb.bin dts/dt.dtb $(U_BOOT_ITS) FORCE $(call if_changed,mkfitimage) u-boot-spl.kwb: u-boot.img spl/u-boot-spl.bin FORCE $(call if_changed,mkimage)
5.3.1 u-boot.srec
$(ALL-y)依赖u-boot.srec:
u-boot.hex u-boot.srec: u-boot FORCE $(call if_changed,objcopy)
5.3.2 u-boot.bin
$(ALL-y)依赖u-boot.bin,826行:
ifeq ($(CONFIG_OF_SEPARATE),y) u-boot-dtb.bin: u-boot-nodtb.bin dts/dt.dtb FORCE $(call if_changed,cat) u-boot.bin: u-boot-dtb.bin FORCE $(call if_changed,copy) else u-boot.bin: u-boot-nodtb.bin FORCE $(call if_changed,copy) endif
如果打开了device tree支持,则有依赖关系:
u-boot.bin --> u-boot-dtb.bin --> u-boot-nodtb.bin + dts/dt.dtb
由于没有定义CONFIG_OF_SEPARATE选项,所以ifeq执行结果为false,我们关心else中定义的依赖关系:
u-boot.bin --> u-boot-nodtb.bin
u-boot.bin目标文件的生成依赖于u-boot-nodtb.bin,FORCE依赖起到一个强制更新目标的作用。
u-boot-nodtb.bin: u-boot FORCE $(call if_changed,objcopy) $(call DO_STATIC_RELA,$<,$@,$(CONFIG_SYS_TEXT_BASE)) $(BOARD_SIZE_CHECK)
命令中的if_changed函数定义在scripts/Kbuild.include文件中,这是通过327行include引进的:
# We need some generic definitions (do not try to remake the file).
scripts/Kbuild.include: ;
include scripts/Kbuild.include
if_changed函数定义如下,这里外层是一个if函数,然后又内嵌了一个strip函数:
if_changed = $(if $(strip $(any-prereq) $(arg-check)), \ @set -e; \ $(echo-cmd) $(cmd_$(1)); \ printf '%s\n' 'cmd_$@ := $(make-cmd)' > $(dot-target).cmd)
# Normally we fill empty space with 0xff
quiet_cmd_objcopy = OBJCOPY $@
cmd_objcopy = $(OBJCOPY) --gap-fill=0xff $(OBJCOPYFLAGS) \
$(OBJCOPYFLAGS_$(@F)) $< $@
OBJCOPY = $(CROSS_COMPILE)objcopy
很显然OBJCOPY=arm-linux-objcopy。$(call if_changed,objcopy)展开后大致如下:
echo 'arm-linux-objcopy $< $@'; arm-linux-objcopy $< $@
这里就是利用arm-linux-objcopy命令将u-boot的转换为二进制文件u-boot-nodtb.bin。
5.3.3 u-boot.sym
$(ALL-y)依赖u-boot.sym:
u-boot.sym: u-boot FORCE $(call if_changed,sym)
5.3.4 System.map
$(ALL-y)依赖System.map:
System.map: u-boot @$(call SYSTEM_MAP,$<) > $@
5.3.5 u-boot.cfg
$(ALL-y)依赖u-boot.cfg:
u-boot.cfg: include/config.h FORCE $(call if_changed,cpp_cfg)
include/config.h文件在make smdk2410_config时创建,主要包含以下信息:
/* Automatically generated - do not edit */ #define CONFIG_BOARDDIR board/samsung/smdk2410 #include <config_defaults.h> #include <config_uncmd_spl.h> #include <configs/smdk2410.h> #include <asm/config.h> #include <config_fallbacks.h>
#include <configs/smdk2410.h>从这里可以看出在configs目录下,包含smdk2410.h文件,如果在board目录下新建一个开发板的目录,则在include/configs目录下要创建一个.h文件,里面存放的开发板配置信息:

/* * (C) Copyright 2002 * Sysgo Real-Time Solutions, GmbH <www.elinos.com> * Marius Groeger <mgroeger@sysgo.de> * Gary Jennejohn <garyj@denx.de> * David Mueller <d.mueller@elsoft.ch> * * Configuation settings for the SAMSUNG SMDK2410 board. * * SPDX-License-Identifier: GPL-2.0+ */ #ifndef __CONFIG_H #define __CONFIG_H
/* * High Level Configuration Options * (easy to change) */
#define CONFIG_S3C24X0 /* This is a SAMSUNG S3C24x0-type SoC */
#define CONFIG_S3C2410 /* specifically a SAMSUNG S3C2410 SoC */
#define CONFIG_SMDK2410 /* on a SAMSUNG SMDK2410 Board */
#define CONFIG_SYS_TEXT_BASE 0x0
#define CONFIG_SYS_ARM_CACHE_WRITETHROUGH
/* input clock of PLL (the SMDK2410 has 12MHz input clock) */
#define CONFIG_SYS_CLK_FREQ 12000000
#define CONFIG_CMDLINE_TAG /* enable passing of ATAGs */
#define CONFIG_SETUP_MEMORY_TAGS
#define CONFIG_INITRD_TAG
/* * Hardware drivers */
#define CONFIG_CS8900 /* we have a CS8900 on-board */
#define CONFIG_CS8900_BASE 0x19000300
#define CONFIG_CS8900_BUS16 /* the Linux driver does accesses as shorts */
/* * select serial console configuration */
#define CONFIG_S3C24X0_SERIAL
#define CONFIG_SERIAL1 1 /* we use SERIAL 1 on SMDK2410 */
/************************************************************ * USB support (currently only works with D-cache off) ************************************************************/
#define CONFIG_USB_OHCI
#define CONFIG_USB_OHCI_S3C24XX
#define CONFIG_USB_KEYBOARD
#define CONFIG_USB_STORAGE
#define CONFIG_DOS_PARTITION
/************************************************************ * RTC ************************************************************/
#define CONFIG_RTC_S3C24X0
#define CONFIG_BAUDRATE 115200
/* * BOOTP options */
#define CONFIG_BOOTP_BOOTFILESIZE
#define CONFIG_BOOTP_BOOTPATH
#define CONFIG_BOOTP_GATEWAY
#define CONFIG_BOOTP_HOSTNAME
/* * Command line configuration. */
#define CONFIG_CMD_BSP
#define CONFIG_CMD_DATE
#define CONFIG_CMD_NAND
#define CONFIG_CMD_REGINFO
#define CONFIG_CMDLINE_EDITING
/* autoboot */
#define CONFIG_BOOTDELAY 5
#define CONFIG_BOOT_RETRY_TIME -1
#define CONFIG_RESET_TO_RETRY
#define CONFIG_ZERO_BOOTDELAY_CHECK
#define CONFIG_NETMASK 255.255.255.0
#define CONFIG_IPADDR 10.0.0.110
#define CONFIG_SERVERIP 10.0.0.1
#if defined(CONFIG_CMD_KGDB)
#define CONFIG_KGDB_BAUDRATE 115200 /* speed to run kgdb serial port */
#endif
/* * Miscellaneous configurable options */
#define CONFIG_SYS_LONGHELP /* undef to save memory */
#define CONFIG_SYS_CBSIZE 256
/* Print Buffer Size */
#define CONFIG_SYS_PBSIZE (CONFIG_SYS_CBSIZE + \
sizeof(CONFIG_SYS_PROMPT)+16) #define CONFIG_SYS_MAXARGS 16
#define CONFIG_SYS_BARGSIZE CONFIG_SYS_CBSIZE
#define CONFIG_DISPLAY_CPUINFO /* Display cpu info */
#define CONFIG_SYS_MEMTEST_START 0x30000000 /* memtest works on */
#define CONFIG_SYS_MEMTEST_END 0x33F00000 /* 63 MB in DRAM */
#define CONFIG_SYS_LOAD_ADDR 0x30800000
/* support additional compression methods */
#define CONFIG_BZIP2
#define CONFIG_LZO
#define CONFIG_LZMA
/*----------------------------------------------------------------------- * Physical Memory Map */
#define CONFIG_NR_DRAM_BANKS 1 /* we have 1 bank of DRAM */
#define PHYS_SDRAM_1 0x30000000 /* SDRAM Bank #1 */
#define PHYS_SDRAM_1_SIZE 0x04000000 /* 64 MB */
#define PHYS_FLASH_1 0x00000000 /* Flash Bank #0 */
#define CONFIG_SYS_FLASH_BASE PHYS_FLASH_1
/*----------------------------------------------------------------------- * FLASH and environment organization */
#define CONFIG_SYS_FLASH_CFI
#define CONFIG_FLASH_CFI_DRIVER
#define CONFIG_FLASH_CFI_LEGACY
#define CONFIG_SYS_FLASH_LEGACY_512Kx16
#define CONFIG_FLASH_SHOW_PROGRESS 45
#define CONFIG_SYS_MAX_FLASH_BANKS 1
#define CONFIG_SYS_FLASH_BANKS_LIST { CONFIG_SYS_FLASH_BASE }
#define CONFIG_SYS_MAX_FLASH_SECT (19)
#define CONFIG_ENV_ADDR (CONFIG_SYS_FLASH_BASE + 0x070000)
#define CONFIG_ENV_IS_IN_FLASH
#define CONFIG_ENV_SIZE 0x10000
/* allow to overwrite serial and ethaddr */
#define CONFIG_ENV_OVERWRITE
/* * Size of malloc() pool * BZIP2 / LZO / LZMA need a lot of RAM */
#define CONFIG_SYS_MALLOC_LEN (4 * 1024 * 1024)
#define CONFIG_SYS_MONITOR_LEN (448 * 1024)
#define CONFIG_SYS_MONITOR_BASE CONFIG_SYS_FLASH_BASE
/* * NAND configuration */ #ifdef CONFIG_CMD_NAND #define CONFIG_NAND_S3C2410
#define CONFIG_SYS_S3C2410_NAND_HWECC
#define CONFIG_SYS_MAX_NAND_DEVICE 1
#define CONFIG_SYS_NAND_BASE 0x4E000000
#endif
/* * File system */
#define CONFIG_CMD_UBI
#define CONFIG_CMD_UBIFS
#define CONFIG_CMD_MTDPARTS
#define CONFIG_MTD_DEVICE
#define CONFIG_MTD_PARTITIONS
#define CONFIG_YAFFS2
#define CONFIG_RBTREE
/* additions for new relocation code, must be added to all boards */
#define CONFIG_SYS_SDRAM_BASE PHYS_SDRAM_1
#define CONFIG_SYS_INIT_SP_ADDR (CONFIG_SYS_SDRAM_BASE + 0x1000 - \ GENERATED_GBL_DATA_SIZE) #define CONFIG_BOARD_EARLY_INIT_F
#endif /* __CONFIG_H */
5.3.6 binary_size_check
$(ALL-y)依赖binary_size_check:
binary_size_check: u-boot-nodtb.bin FORCE @file_size=$(shell wc -c u-boot-nodtb.bin | awk '{print $$1}') ; \
map_size=$(shell cat u-boot.map | \ awk '/_image_copy_start/ {start = $$1} /_image_binary_end/ {end = $$1} END {if (start != "" && end != "") print "ibase=16; " toupper(end) " - " toupper(start)}' \ | sed 's/0X//g' \ | bc); \
if [ "" != "$$map_size" ]; then \
if test $$map_size -ne $$file_size; then \
echo "u-boot.map shows a binary size of $$map_size" >&2 ; \
echo " but u-boot-nodtb.bin shows $$file_size" >&2 ; \
exit 1; \
fi \ fi
显然对于binary_size_check有下列依赖关系:
binary_size_check --> u-boot-nodtb.bin --> u-boot
以上通用目标$(ALL-y)的依赖有一个共同点,除了u-boot.cfg依赖于include/config.h外,其余目标全都依赖于u-boot(实际上除了依赖于u-boot外,还依赖于FORCE,由于FORCE依赖本身是一个空目标,为了方便,这里略去了对FORCE依赖的描述):
六、make编译正向分析之目标u-boot
分析1191行:
u-boot: $(u-boot-init) $(u-boot-main) u-boot.lds FORCE $(call if_changed,u-boot__) ifeq ($(CONFIG_KALLSYMS),y) $(call cmd,smap) $(call cmd,u-boot__) common/system_map.o endif
u-boot依赖于\$(u-boot-init) \$(u-boot-main) u-boot.lds。
其中\$(u-boot-init)和\$(u-boot-main)分别被定义为:
u-boot-init := $(head-y)
u-boot-main := $(libs-y)
6.1 依赖 u-boot.lds
这里先介绍u-boot.lds,1328行:
u-boot.lds: $(LDSCRIPT) prepare FORCE $(call if_changed_dep,cpp_lds)
它的依赖有两个:\$(LDSCRIPT)和prepare。这里先分析\$(LDSCRIPT):
ifndef LDSCRIPT #LDSCRIPT := $(srctree)/board/$(BOARDDIR)/u-boot.lds.debug ifdef CONFIG_SYS_LDSCRIPT # need to strip off double quotes LDSCRIPT := $(srctree)/$(CONFIG_SYS_LDSCRIPT:"%"=%) endif endif # If there is no specified link script, we look in a number of places for it ifndef LDSCRIPT ifeq ($(wildcard $(LDSCRIPT)),) LDSCRIPT := $(srctree)/board/$(BOARDDIR)/u-boot.lds endif ifeq ($(wildcard $(LDSCRIPT)),) LDSCRIPT := $(srctree)/$(CPUDIR)/u-boot.lds endif ifeq ($(wildcard $(LDSCRIPT)),) LDSCRIPT := $(srctree)/arch/$(ARCH)/cpu/u-boot.lds endif endif
解析:如果没有定义LDSCRIPT和CONFIG_SYS_LDSCRIPT,则默认使用u-boot自带的lds文件,包括board/\$(BOARDDIR)和\$(CPUDIR)目录下定制的针对board或cpu的lds文件;如果没有定制的lds文件,则采用arch/arm/cpu目录下默认的lds链接文件u-boot.lds,链接脚本分析可以参考这篇博客。
6.2 依赖$(head-y)
在linux上搜索head-y这个目标: grep 'head-y' * -nR 得到下面这个结果:
arch/arm/Makefile:74:head-y := arch/arm/cpu/$(CPU)/start.o
所以head-y指的是start.S。
6.3 依赖$(libs-y)
在顶层目录Makefile中搜索libs-y可以发现其包含许多目录, 比如:
libs-y += lib/ libs-$(HAVE_VENDOR_COMMON_LIB) += board/$(VENDOR)/common/ libs-$(CONFIG_OF_EMBED) += dts/ libs-y += fs/ libs-y += net/ libs-y += disk/ libs-y += drivers/ libs-y += drivers/dma/ libs-y += drivers/gpio/ libs-y += drivers/i2c/ libs-y += drivers/mmc/ libs-y += drivers/mtd/ libs-$(CONFIG_CMD_NAND) += drivers/mtd/nand/ libs-y += drivers/mtd/onenand/ libs-$(CONFIG_CMD_UBI) += drivers/mtd/ubi/ libs-y += drivers/mtd/spi/ libs-y += drivers/net/ libs-y += drivers/net/phy/
另:
libs-y := $(patsubst %/, %/built-in.o, $(libs-y))
这条规则使libs-y中每个条目的最后一个斜杠替换成 /built-in.o,比如 drivers/mtd/ 会变为 drivers/mtd/built-in.o。
可见libs-y被定义为各层驱动目录下build-in.o的集合,而这些built-in.o则由 Kbuild Makefile 将obj-y所包含的各个文件编译而成,具体可研究scripts/Kbuild.include 和 scripts/Makefile.build。
ifneq ($(strip $(obj-y) $(obj-m) $(obj-) $(subdir-m) $(lib-target)),) builtin-target := $(obj)/built-in.o endif
$(builtin-target): $(obj-y) FORCE $(call if_changed,link_o_target)
u-boot文件目标依赖:
七、make编译正向分析之目标prepare
实际上prepare是一系列prepare伪目标和动作的组合,完成编译前的准备工作:
# Listed in dependency order PHONY += prepare archprepare prepare0 prepare1 prepare2 prepare3 # prepare3 is used to check if we are building in a separate output directory, # and if so do: # 1) Check that make has not been executed in the kernel src $(srctree) prepare3: include/config/uboot.release ifneq ($(KBUILD_SRC),) @$(kecho) ' Using $(srctree) as source for U-Boot' $(Q)if [ -f $(srctree)/.config -o -d $(srctree)/include/config ]; then \ echo >&2 " $(srctree) is not clean, please run 'make mrproper'"; \ echo >&2 " in the '$(srctree)' directory.";\ /bin/false; \ fi; endif # prepare2 creates a makefile if using a separate output directory prepare2: prepare3 outputmakefile prepare1: prepare2 $(version_h) $(timestamp_h) \ include/config/auto.conf ifeq ($(CONFIG_HAVE_GENERIC_BOARD),) ifeq ($(CONFIG_SYS_GENERIC_BOARD),y) @echo >&2 " Your architecture does not support generic board." @echo >&2 " Please undefine CONFIG_SYS_GENERIC_BOARD in your board config file." @/bin/false endif endif ifeq ($(wildcard $(LDSCRIPT)),) @echo >&2 " Could not find linker script." @/bin/false endif archprepare: prepare1 scripts_basic prepare0: archprepare FORCE $(Q)$(MAKE) $(build)=. # All the preparing.. prepare: prepare0
伪目标prepare,prepare0,archprepare,prepare1,prepare2,prepare3之间的依赖如下:
在prepare1的依赖列表中,除了include/config/auto.conf之外,还有\$(version_h)和\$(timestamp_h),它们的依赖关系如下:
version_h := include/generated/version_autogenerated.h timestamp_h := include/generated/timestamp_autogenerated.h defaultenv_h := include/generated/defaultenv_autogenerated.h
对于位于最后的prepare3的依赖include/config/uboot.release,它还有下一级依赖:
# Store (new) UBOOTRELEASE string in include/config/uboot.release include/config/uboot.release: include/config/auto.conf FORCE $(call filechk,uboot.release)
对于include/config/auto.conf,Makefile中有一个匹配规则:
# If .config is newer than include/config/auto.conf, someone tinkered # with it and forgot to run make oldconfig. # if auto.conf.cmd is missing then we are probably in a cleaned tree so # we execute the config step to be sure to catch updated Kconfig files include/config/%.conf: $(KCONFIG_CONFIG) include/config/auto.conf.cmd $(Q)$(MAKE) -f $(srctree)/Makefile syncconfig @# If the following part fails, include/config/auto.conf should be @# deleted so "make silentoldconfig" will be re-run on the next build. $(Q)$(MAKE) -f $(srctree)/scripts/Makefile.autoconf || \ { rm -f include/config/auto.conf; false; } @# include/config.h has been updated after "make silentoldconfig". @# We need to touch include/config/auto.conf so it gets newer @# than include/config.h. @# Otherwise, 'make silentoldconfig' would be invoked twice. $(Q)touch include/config/auto.conf
include/config/auto.conf依赖于$(KCONFIG_CONFIG)和include/config/auto.conf.cmd,其中:
- $(KCONFIG_CONFIG)实际上就是.config文件;
- include/config/auto.conf.cmd是由fixdep在编译时生成的依赖文件。
八 make编译流程图
完成目标依赖分析后,剩下的就是基于完整的目标依赖关系图,从最底层的依赖开始,逐层运行命令生成目标,直到生成顶层目标。
参考文章:
[1] bootloader 详细介绍
[2] 新版u-boot移植到s3c2440开发板(一)--建立单板
[3] UBOOT2016.07移植(第一篇)初步分析(部分转载)
[4]u-boot-2016.09 make配置过程分析(部分转载)
[5]u-boot-2016.09 make编译过程分析(一)(部分转载)