1. Bootloader 和 TI Uboot
Bootloader的一种,用来引导系统,通常HLOS如LINUX,WINDOWS等系统的镜像保存在硬盘、EMMC等介质中,Bootloader的主要功能是为这些系统准备硬件环境,然后将HLOS系统加载到RAM中,最后把HLOS给运行起来。通常在IC、特别是嵌入式IC复位后,它会跳转到片内ROM去运行特定的固化代码(也可能是上电后从特定的地址运行,这时需要在该地址上放上可执行的器件,如NORFLASH),在固化代码中做基本的硬件初始化之后它要决定下一步的运行,即从哪里拿到镜像,在哪里运行;通常来讲下一步要运行的镜像保存在flash当中,有些IC可能内置动态RAM,有些则可能不具备(需要外部的RAM),因此Uboot将bootloader过程分为两个SPL和Uboot两个部分,SPL是可选的(Secondary Program Loader),便于开发者自己选择。对于TI板子(AM57xx),它的启动过程是 片内ROM -> SPL(TI改成MLO) -> UBOOT -> HLOS(Linux,Android等)。
2. 编译
首先介绍UBOOT的编译,最新的UBOOT采用和Kernel类似的Kbuild编译系统,它是基于make的一套编译系统。编译方法首先make config,然后make target,即我们常说的先配置再编译。对于make系统来讲,两个编译命令运行的位置一样(UBOOT根目录),所以它们的入口文件的入口都是顶层Makefile文件,在顶层Makefile中会处理环境,变量,引入Kbuild的其它模块,定义UBOOT的libs和依赖,最后根据编译的对象生成不同的结果;对于config来说,需要收集config文件和KCONFIG文件,生成.config.h文件等,最终的目的是将我们定义的config引入到源文件(.h文件)和编译target的mk文件中(.mk),后面将会分析到;而对于编译target来说,由于前面编译config的时候已经引入了不同的编译控制变量(如宏控),所以编译的结果也是不同的,如编译哪个平台、哪些源文件等等。通常我们在移植工作中的编译部分的工作也遵循这个思路。
在TI SDK中使能SPL,所以编译时会编译出2个镜像,一个是SPL(u-boot-spl-dtb.bin),会重新处理成MLO镜像;另一个是u-boot的镜像。对于SPL,它的编译入口会从顶层Makefile跳转到子Makefile中 scripts/Makefile.spl,原理类似,都是lib- -> libs- -> buildin.o -> image,期间会使用script中定义的基本函数或者变量,我们先列出后面用到的几个以便后面查阅。
build变量通过scripts/Kbuild.include引入:
#### Shorthand for $(Q)$(MAKE) -f scripts/Makefile.build obj=# Usage:# $(Q)$(MAKE) $(build)=dirbuild := -f $(srctree)/scripts/Makefile.build obj
TODO: add more details if any。
2.2 config编译
依赖关系如下, 比如编译am57xx_evm_config时,匹配的是%config,%是Makefile中的通配符。
config: scripts_basic outputmakefile FORCE$(Q)$(MAKE) $(build)=scripts/kconfig $@%config: scripts_basic outputmakefile FORCE$(Q)$(MAKE) $(build)=scripts/kconfig $@
config编译依赖依赖scripts_basic,还有outputmakefile。结合上一节中的几个变量定义,scripts_basic的编译命令变成:
$(Q)$(MAKE) -f $(srctree)/scripts/Makefile.build obj=scripts/basic,指定了makefile文件和obj,由于没有指定目标,所以默认的目标是Makefile.build中第一个目标__build:
# Basic helpers built in scripts/PHONY += scripts_basicscripts_basic:$(Q)$(MAKE) $(build)=scripts/basic$(Q)rm -f .tmp_quiet_recordmcount
这个__build目标为
__build: $(if $(KBUILD_BUILTIN),$(builtin-target) $(lib-target) $(extra-y)) \$(if $(KBUILD_MODULES),$(obj-m) $(modorder-target)) \$(subdir-ym) $(always)@:
回到开头查看Makefile.build文件,需要首先包含一些脚本:
如果include/config/auto.conf存在,则包含之。编译config时这个文件不存在,但在后面编译uboot的时候需要包含该文件,其中定义了宏控。$(prefix)/include/autoconf.mk如果存在,则包含之。关于prefix的赋值几个if的解释如下,首先赋值tpl,如果obj的路径以tpl开始(这里是scripts/basic,为否)则第一个if不成立,此时prefix为tpl,同理prefix也可能为spl和.;此时src是去除了前缀的路径名。所以这里是包含scripts/basic/include/autoconf.mk包含scripts/Makefile.uncmd_spl,该文件和spl有关,该文件通过宏控CONFIG_SPL_BUILD来控制,所以对uboot来讲,没有定义该宏控,问题也不大。包含scripts/Kbuild.include,该文件中定义了很多基础函数。如果$(src)/Kbuild存在,则包含之; 如果不存在则包含$(src)/Makefile, 关于$(src)请看第2点。这里因为obj=scripts/basic,所以查找的是该目录下的这两个文件。
# Modified for U-Bootprefix := tplsrc := $(patsubst $(prefix)/%,%,$(obj))ifeq ($(obj),$(src))prefix := splsrc := $(patsubst $(prefix)/%,%,$(obj))ifeq ($(obj),$(src))prefix := .endifendif...# Read auto.conf if it exists, otherwise ignore# Modified for U-Boot-include include/config/auto.conf-include $(prefix)/include/autoconf.mkinclude scripts/Makefile.uncmd_splinclude scripts/Kbuild.include# For backward compatibility check that these variables do not changesave-cflags := $(CFLAGS)# The filename Kbuild has precedence over Makefilekbuild-dir := $(if $(filter /%,$(src)),$(src),$(srctree)/$(src))kbuild-file := $(if $(wildcard $(kbuild-dir)/Kbuild),$(kbuild-dir)/Kbuild,$(kbuild-dir)/Makefile)include $(kbuild-file)
在script/basic/Makefile文件,定义了fixdep目标并加入到always
hostprogs-y:= fixdepalways:= $(hostprogs-y)# fixdep is needed to compile other host programs$(addprefix $(obj)/,$(filter-out fixdep,$(always))): $(obj)/fixdep
再次回到Makfefile.build, 增加一些编译的flag,包含Makefile.lib。这个makefile.lib的作用就是收集-y,-m变量;我们在Makefile.build中定义这些变量并将其都设置为空,同时在该文件中include了目标路径的Kbuild或者Makefile,这将对这些变量重新赋值。
# Added for U-Bootasflags-y += $(PLATFORM_CPPFLAGS)ccflags-y += $(PLATFORM_CPPFLAGS)cppflags-y += $(PLATFORM_CPPFLAGS)# If the save-* variables changed error outifeq ($(KBUILD_NOPEDANTIC),)ifneq ("$(save-cflags)","$(CFLAGS)")$(error CFLAGS was changed in "$(kbuild-file)". Fix it to use ccflags-y)endifendifinclude scripts/Makefile.lib
如果定义了hostprogs-y或者m,则将Makefile.host包含进来。我们在scripts/basic/Makefile中已经定义了hostprogs-y := fixdep;Makefile.host中会解析hostprogs-y,并且使用HOSTCC和HOSTFLAGS等host相关的工具去编译相应的文件。
# Do not include host rules unless neededifneq ($(hostprogs-y)$(hostprogs-m),)include scripts/Makefile.hostendif
在Makefile.host中以单个文件编译为例,首先解析得到源文件,如果依赖改变则调用cmd_host-csingle来进行编译。
# C code# Executables compiled from a single .c filehost-csingle:= $(foreach m,$(__hostprogs), \$(if $($(m)-objs)$($(m)-cxxobjs)$($(m)-sharedobjs),,$(m)))# Create executable from a single .c file# host-csingle -> Executablequiet_cmd_host-csingle = HOSTCC $@cmd_host-csingle= $(HOSTCC) $(hostc_flags) -o $@ $< \$(HOST_LOADLIBES) $(HOSTLOADLIBES_$(@F))$(host-csingle): $(obj)/%: $(src)/%.c FORCE$(call if_changed_dep,host-csingle)
if_changed_dep在scripts/Kbuild.include中定义,用来检查依赖是否发生改变(我们平时看到目录中的.cmd文件),其中会用到fixdep。到这里,scripts_basic目标是编译fixdep.c文件,并生成fixdep工具。
再次回到%config,它依赖第二个目标outputmakefile。
%config: scripts_basic outputmakefile FORCE$(Q)$(MAKE) $(build)=scripts/kconfig $@
如下,这个outputmakefile主要作用是在output目录下产生一个Makefile的链接。
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
所以我们回到%config的依赖关系,build := -f $(srctree)/scripts/Makefile.build obj,翻译过来就是:
$(Q) $(MAKE)-f $(srctree)/scripts/Makefile.build obj=scripts/kconfigam57xx_evm_config,这里的分析和前面分析scripts_basic一样。
%config: scripts_basic outputmakefile FORCE$(Q)$(MAKE) $(build)=scripts/kconfig $@
我们这里假设编译的目标是am57xx_evm_config,在scripts/config/Makefile中定义如下。
ifdef KBUILD_KCONFIGKconfig := $(KBUILD_KCONFIG)elseKconfig := Kconfigendif%_defconfig: $(obj)/conf$(Q)$< $(silent) --defconfig=arch/$(SRCARCH)/configs/$@ $(Kconfig)# Added for U-Boot (backward compatibility)%_config: %_defconfig@:
和之前fixdep一样,另一个host上工具conf;然后就是调用这个conf工具,并传入我们指定的config,最终额编译命令为:
$(obj)/conf --defconfig=arch/arm/configs/am57xx_evm_config Kconfig
它解析顶层的Kconfig文件(一步一步source子目录的Kconfig),并将config文件中的默认值分配给定义的选项,最终生成.config文件。conf对应的源文件conf.c等也在目录scripts/kconfig目录之中。到此make config就完成了。
在接下来make目标的时候,实际上使用的并不是.config文件。首先会生成autoconf,并通过-incldue include/config/autoconf引入到make;
比较autoconf和.config文件内容,发现两者基本上是一样的;make rk3399_box_defconfig汇集了CONFIG_XXX变量到.config文件,在make时由-incldue include/config/autoconf引入到make,这样make就可以使用这些变量的定义了。
然而CONFIG_XXX变量不止在makefile中定义,更多情况实在.h头文件中定义为宏,例如CONFIG_RAM_PHY_START在include/configs/rk30plat.h中定义:
#define CONFIG_RAM_PHY_START0x60000000
那么,make如何获取这些在头文件中定义的宏呢?就是这个autoconf.mk文件,这个文件将所有相关头文件中的CONFIG_XXX宏,转化为makefile变量,再被-include include/autoconf.mk这句话包含进Makefile,供make使用。
接下来在Makefile中:
ifneq ($(autoconf_is_current),)
include $(srctree)/config.mk
endif
包含进了源码顶级目录的config.mk,这个config.mk定义了一些变量,并且引入了cpu和board目录下的config.mk。
至此,所有的CONFIG_XXX变量(makefile中定义的和.h中的宏定义)就被make包含进了。
原文:/weixin_41469511/article/details/78856047
2.3 SPL编译
通过CONFIG_SPL=y使能SPL编译,编译脚本为Makefile.spl
spl/u-boot-spl: tools prepare \$(if $(CONFIG_OF_SEPARATE)$(CONFIG_OF_EMBED)$(CONFIG_SPL_OF_PLATDATA),dts/dt.dtb) \$(if $(CONFIG_OF_SEPARATE)$(CONFIG_OF_EMBED)$(CONFIG_TPL_OF_PLATDATA),dts/dt.dtb)$(Q)$(MAKE) obj=spl -f $(srctree)/scripts/Makefile.spl all
其中,arch、common、dts、include、board、drivers、fs是对应代码的编译目录,各个目录下都会生成相应的built.o,是由同目录下的目标文件连接而成。
重点说一下以下几个文件:
文件 说明
u-boot-spl 初步链接后得到的spl文件
u-boot-spl-nodtb.bin 在u-boot-spl的基础上,经过objcopy去除符号表信息之后的可执行程序
u-boot-spl.bin 在不需要dtb的情况下,直接由u-boot-spl-nodtb.bin复制而来,也就是编译spl的最终目标
tiny210-spl.bin 由s5pv210平台决定,需要在u-boot-spl.bin的基础上加上16B的header用作校验
u-boot-spl.lds spl的连接脚本
u-boot-spl.map 连接之后的符号表文件
u-boot-spl.cfg 由spl配置生成的文件
原文:/ooonebook/article/details/52949584
上面的引用是spl(uboot也类似)的编译流程,对于TI而言,还需要将镜像最终转换成MLO,我们后面分析时会看到。首先,在Makefile.spl中定义CONFIG_SPL_BUILD宏,在代码中该宏用来控制SPL还是UBOOT。我们这里假设以编译am57xx_evm_config。
KBUILD_CPPFLAGS += -DCONFIG_SPL_BUILDifeq ($(CONFIG_TPL_BUILD),y)KBUILD_CPPFLAGS += -DCONFIG_TPL_BUILDendif
然后包含Kbuild.include, 然后包含auto.conf 和autoconf.mk, 这两个文件是config的时候生成的,其中定义了config变量,分析代码和make的时候可以查阅;同时包含根目录下的config.mk,这个mk文件会进一步将前面两个conf文件进一步进行加工。
include $(srctree)/scripts/Kbuild.include-include include/config/auto.conf-include $(obj)/include/autoconf.mk...include $(srctree)/config.mk
比如auto.conf中定义ARCH和CPU如下。
CONFIG_SYS_ARCH="arm"CONFIG_SYS_CPU="armv7"CONFIG_SYS_SOC="omap5"CONFIG_SYS_BOARD="am57xx"CONFIG_SYS_VENDOR="ti"
在config.mk中将会它们转化成ARCH=arm、CPU=armv7、SOC=omap5,BOARD=am57xx,VENDOR=ti
ARCH := $(CONFIG_SYS_ARCH:"%"=%)CPU := $(CONFIG_SYS_CPU:"%"=%)SOC := $(CONFIG_SYS_SOC:"%"=%)BOARD := $(CONFIG_SYS_BOARD:"%"=%)VENDOR := $(CONFIG_SYS_VENDOR:"%"=%)
我们将下面这些翻译之后记录如下
CPUDIR=arch/$(ARCH)/cpu$(if $(CPU),/$(CPU),)sinclude $(srctree)/arch/$(ARCH)/config.mk# include architecture dependend rulessinclude $(srctree)/$(CPUDIR)/config.mk# include CPUspecific rulesifdefSOCsinclude $(srctree)/$(CPUDIR)/$(SOC)/config.mk# include SoCspecific rulesendififneq ($(BOARD),)ifdefVENDORBOARDDIR = $(VENDOR)/$(BOARD)elseBOARDDIR = $(BOARD)endifendififdefBOARDsinclude $(srctree)/board/$(BOARDDIR)/config.mk# include board specific rulesendif
CPUDIR=arch/arm/cpu/armv7
include 了 arch/arm/config.mk
include 了 arch/arm/cpu/armv7/config.mk
include 了 arch/arm/cpu/omap5/config.mk
BOARDDIR = ti/am57xx
include 了 board/am57xx/config.mk
以上这些mk文件也定义平台和IC相关的变量
在定义了ARCH等变量之后,在Makefile.spl中包含ARCH相关的Makefile
include $(srctree)/arch/$(ARCH)/Makefile
这文件中将会根据config确定一些ARCH相关的libs-y
machine-$(CONFIG_ARCH_OMAP2PLUS)+= omap2machdirs := $(patsubst %,arch/arm/mach-%/,$(machine-y))libs-y += $(machdirs)head-y := arch/arm/cpu/$(CPU)/start.olibs-y += arch/arm/cpu/$(CPU)/libs-y += arch/arm/cpu/libs-y += arch/arm/lib/-include $(machdirs)/config.mk
之后再Makefile.spl中包含Makefile.lib,该脚本会收集lib-y和-m。
include $(srctree)/scripts/Makefile.lib
先看libs-y的处理,它将所有的libs-y的路径加上一个build-in.o(就是说每个libs-y相当于一个小模块的.o文件的集合)
libs-y := $(patsubst %/, %/built-in.o, $(libs-y))
这些libs-y(所有的build-in.o)成为u-boot-spl-main,而u-boot-spl-init则是head-y,head-y在arch/arm/Makefile中定义head-y := arch/arm/cpu/$(CPU)/start.o,所以u-boot-spl-main就是系列的build-in.o的集合
u-boot-spl-init := $(head-y)u-boot-spl-main := $(libs-y)
那这些.o是如何被编译的呢,我们看到在u-boot-spl-main加上build-in.o之前,将其赋值给了u-boot-spl-dirs,并且去掉了后面/
u-boot-spl-dirs:= $(patsubst %/,%,$(filter %/, $(libs-y)))
并且依赖init和main是依赖于u-boot-spl-dir的
$(sort $(u-boot-spl-init) $(u-boot-spl-main)): $(u-boot-spl-dirs) ;
我们看到u-boot-spl-dirs的依赖如下,结合上面的build变量的定义知道。这里对个每一个objs-y目录下面执行一遍Makefile.build
PHONY += $(u-boot-spl-dirs)$(u-boot-spl-dirs): $(u-boot-spl-platdata)$(Q)$(MAKE) $(build)=$@
我们以arch/arm/mach-omap2为例,
make -f scripts/Makefile.build obj=arch/arm/mach-omap2
在Makefile.build中定义了built-in.o, .lib以及.o的生成规则。并完成该子目录的.lib、built-in.o以及目标文件.o;并且Makefile.build文件会将libs-y目录下(通过obj传入)的Makefile文件给include,而我们知道在这些Makefile文件中定义了lib-y和lib-m,这些lib-y和lib-m就是由对应的.c或者.s文件编译而成,最终将这些.o集合成built-in.o。
built-in.o和start.o依赖于我们配置的源文件并最终在定义的规则下生成,接下来就是将这些文件给链接起来。
# Rule to link u-boot-spl# May be overridden by arch/$(ARCH)/config.mkquiet_cmd_u-boot-spl ?= LD$@cmd_u-boot-spl ?= (cd $(obj) && $(LD) $(LDFLAGS) $(LDFLAGS_$(@F)) \$(patsubst $(obj)/%,%,$(u-boot-spl-init)) --start-group \$(patsubst $(obj)/%,%,$(u-boot-spl-main)) \$(patsubst $(obj)/%,%,$(u-boot-spl-platdata)) \--end-group \$(PLATFORM_LIBS) -Map $(SPL_BIN).map -o $(SPL_BIN))$(obj)/$(SPL_BIN): $(u-boot-spl-platdata) $(u-boot-spl-init) \$(u-boot-spl-main) $(obj)/u-boot-spl.lds FORCE$(call if_changed,u-boot-spl)
链接脚本:CONFIG_SPL_LDSCRIPT="arch/arm/mach-omap2/u-boot-spl.lds"
链接log:
(cd spl && ti/linux-devkit/sysroots/x86_64-arago-linux/usr/bin/arm-linux-gnueabihf-ld.bfd -T u-boot-spl.lds --gc-sections -Bstatic --gc-sections --no-dynamic-linker -Ttext 0x40300000 arch/arm/cpu/armv7/start.o --start-group arch/arm/mach-omap2/built-in.o arch/arm/cpu/armv7/built-in.o arch/arm/cpu/built-in.o arch/arm/lib/built-in.o board/ti/am57xx/built-in.o board/ti/common/built-in.o common/spl/built-in.o common/init/built-in.o common/built-in.o cmd/built-in.o env/built-in.o lib/built-in.o disk/built-in.o drivers/built-in.o dts/built-in.o fs/built-in.o --end-group arch/arm/lib/eabi_compat.o arch/arm/lib/lib.a -Map u-boot-spl.map -o u-boot-spl)
编译最后需要生成MLO文件,调用cmd_mkimage
MLO MLO.byteswap: $(obj)/u-boot-spl.bin FORCE$(call if_changed,mkimage)...quiet_cmd_mkimage = MKIMAGE $@cmd_mkimage = $(objtree)/tools/mkimage $(MKIMAGEFLAGS_$(@F)) -d $< $@ \$(if $(KBUILD_VERBOSE:1=), >$(MKIMAGEOUTPUT))
需要注意, 譬如在arch/arm/cpu/armv7和arch/arm/omap2/中同时有lowlevel_init.S这个文件都会被编译,而且看到有相同的符号被编译而没有报错,这是因为使用汇编中WEAK修饰符,就类似于C++中多态的概念,这样使得板级(比如board/xxx, xxx/omap2/中的函数可以覆盖armv7/中的函数),我们把spl中定义的模块列出如下,便于后面阅读代码。
libs-y += board/board/ti/am57xxlibs-y += common/init/libs-y += common/spl/libs-y += drivers/libs-y += dts/libs-y += fs/libs-y += arch/arm/omap2libs-y += arch/arm/cpu/armv7/libs-y += arch/arm/cpu/libs-y += arch/arm/lib/head-y := arch/arm/cpu/armv7/start.o
还有一点需要注意,SPL和Uboot共用了很多代码,通过宏控CONFIG_SPL_BUILD来区分,这个可以在Makefile.spl中找到,而编译UBOOT时这个宏是没有被编译的。在具体看代码的时候需要注意该宏控。
KBUILD_CPPFLAGS += -DCONFIG_SPL_BUILDifeq ($(CONFIG_TPL_BUILD),y)KBUILD_CPPFLAGS += -DCONFIG_TPL_BUILDendif
2.4 Uboot编译编译
Uboot编译和SPL编译相差不大,不再继续贴出代码。它依赖u-boot-init,u-boot-main和u-boot.lds,
u-boot:$(u-boot-init) $(u-boot-main) u-boot.lds FORCE+$(call if_changed,u-boot__)
把在顶层Makefile中定义了libs也同样列出。
libs-y += lib/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/mtd/libs-y += drivers/mtd/onenand/libs-y += drivers/mtd/spi/libs-y += drivers/net/libs-y += drivers/net/phy/libs-y += drivers/pci/libs-y += drivers/power/ \drivers/power/fuel_gauge/ \drivers/power/mfd/ \drivers/power/pmic/ \drivers/power/battery/ \drivers/power/regulator/libs-y += drivers/spi/libs-y += drivers/serial/libs-y += drivers/usb/dwc3/libs-y += drivers/usb/common/libs-y += drivers/usb/emul/libs-y += drivers/usb/eth/libs-y += drivers/usb/gadget/libs-y += drivers/usb/gadget/udc/libs-y += drivers/usb/host/libs-y += drivers/usb/musb/libs-y += drivers/usb/musb-new/libs-y += drivers/usb/phy/libs-y += drivers/usb/ulpi/libs-y += cmd/libs-y += common/libs-y += env/libs-y += test/libs-y += test/dm/libs-y += board/ti/am57xxlibs-y:= $(patsubst %/, %/built-in.o, $(libs-y))u-boot-init := $(head-y)u-boot-main := $(libs-y)
链接脚本:arch/arm/cpu/u-boot.lds
同时在Makefile中还会include config.mk和ARCH中的makefile,所以实际上uboot的编译也会包含arch中的镜像,如下是编译log输出。
ti/linux-devkit/sysroots/x86_64-arago-linux/usr/bin/arm-linux-gnueabihf-ld.bfd -pie --gc-sections -Bstatic --no-dynamic-linker -Ttext 0x80800000 -o u-boot -T u-boot.lds arch/arm/cpu/armv7/start.o --start-group arch/arm/cpu/built-in.o arch/arm/cpu/armv7/built-in.o arch/arm/lib/built-in.o arch/arm/mach-omap2/built-in.o board/ti/am57xx/built-in.o board/ti/common/built-in.o cmd/built-in.o common/built-in.o disk/built-in.o drivers/built-in.o drivers/dma/built-in.o drivers/gpio/built-in.o drivers/i2c/built-in.o drivers/mtd/built-in.o drivers/mtd/onenand/built-in.o drivers/mtd/spi/built-in.o drivers/net/built-in.o drivers/net/phy/built-in.o drivers/pci/built-in.o drivers/power/built-in.o drivers/power/battery/built-in.o drivers/power/fuel_gauge/built-in.o drivers/power/mfd/built-in.o drivers/power/pmic/built-in.o drivers/power/regulator/built-in.o drivers/serial/built-in.o drivers/spi/built-in.o drivers/usb/common/built-in.o drivers/usb/dwc3/built-in.o drivers/usb/emul/built-in.o drivers/usb/eth/built-in.o drivers/usb/gadget/built-in.o drivers/usb/gadget/udc/built-in.o drivers/usb/host/built-in.o drivers/usb/musb-new/built-in.o drivers/usb/musb/built-in.o drivers/usb/phy/built-in.o drivers/usb/ulpi/built-in.o env/built-in.o fs/built-in.o lib/built-in.o net/built-in.o test/built-in.o test/dm/built-in.o --end-group arch/arm/lib/eabi_compat.o arch/arm/lib/lib.a -Map u-boot.map; true
3. 启动流程
要细致的了解启动流程,需要结合AM57xx的spec,datasheet,比如参考文档中的:1,2。
简单的说是上电之后芯片固话的ROM code执行,其加载MLO进入到片内的RAM并跳转到MLO;MLO加载UBOOT到RAM中并执行;最后UBOOT加载HLOS。在UBOOT中只有前述2者。
ROM code大小有48KB,我们通过pin脚设置选择boot的设备,可以是eMMC,SD,NAND,SATA,USB,UART,等等;片内RAM内存能够达到504K,所以MLO的大小必须小于此值;如下是示意图。PS:ROM code最后会进入死循环监听看门狗?
链接脚本决定着程序链接的地址,从u-boot-spl.lds中看到如下:
MEMORY { .sram : ORIGIN = CONFIG_SPL_TEXT_BASE,\LENGTH = CONFIG_SPL_MAX_SIZE }MEMORY { .sdram : ORIGIN = CONFIG_SPL_BSS_START_ADDR, \LENGTH = CONFIG_SPL_BSS_MAX_SIZE }
#define CONFIG_SPL_TEXT_BASE 0x40300000#define CONFIG_SPL_MAX_SIZE (SRAM_SCRATCH_SPACE_ADDR - CONFIG_SPL_TEXT_BASE)#define CONFIG_SPL_BSS_START_ADDR 0x80a00000#define CONFIG_SPL_BSS_MAX_SIZE 0x80000
下图是内部RAM的地址分布, 和上述变量需要保持一致。另外,DDR地址从0x8000 0000开始。
参考资料:
/lit/ug/spruih8a/spruih8a.pdf
/lit/ug/spruih8a/spruih8a.pdf
/wangweijundeqq/article/details/79127800
/heart18335101121/article/details/80319431