首页 > 其他分享 >uboot-spl 编译流程

uboot-spl 编译流程

时间:2024-05-28 17:45:46浏览次数:24  
标签:bin uboot ## boot 编译 spl obj SPL

以下例子都以project X项目tiny210(s5pv210平台,armv7架构)为例

[uboot] uboot流程系列
[project X] tiny210(s5pv210)上电启动流程(BL0-BL2)

建议先看《[project X] tiny210(s5pv210)上电启动流程(BL0-BL2)》,根据例子了解一下上电之后的BL0\BL1\BL2阶段,以及各个阶段的运行位置,功能。

=================================================================================

一、uboot-spl编译和生成文件

spl的编译是编译uboot的一部分,和uboot.bin走的是两条编译流程,这个要重点注意。
正常来说,会先编译主体uboot,也就是uboot.bin.再编译uboot-spl,也就是uboot-spl.bin,虽然编译命令是一起的,但是编译流程是分开的。

1、编译方法

在project X项目中,所有镜像,包括uboot、kernel、rootfs都是放在build目录下进行编译的。具体去参考该项目build的Makefile的实现。
假设config已经配置完成,在build编译命令如下:

make uboot
 

 

Makefile中对应的命令如下:

  1.   BUILD_DIR=$(shell pwd)
  2.   OUT_DIR=$(BUILD_DIR)/out
  3.   UBOOT_OUT_DIR=$(OUT_DIR)/u-boot
  4.   UBOOT_DIR=$(BUILD_DIR)/../u-boot
  5.   uboot:
  6.   mkdir -p $(UBOOT_OUT_DIR)
  7.   make -C $(UBOOT_DIR) CROSS_COMPILE=$(CROSS_COMPILE) KBUILD_OUTPUT=$(UBOOT_OUT_DIR) $(BOARD_NAME)_defconfig
  8.   make -C $(UBOOT_DIR) CROSS_COMPILE=$(CROSS_COMPILE) KBUILD_OUTPUT=$(UBOOT_OUT_DIR)
  9.   ## -C $(UBOOT_DIR) 指定了要在../uboot,也就是uboot的代码根目录下执行make
  10.   ## CROSS_COMPILE=$(CROSS_COMPILE) 指定了交叉编译器
  11.   ## KBUILD_OUTPUT=$(UBOOT_OUT_DIR) 指定了最终编译的输出目录是build/out/u-boot.

 

最终,相当于进入了uboot目录执行了make动作。
也就是说spl的编译是编译uboot的一部分,和uboot.bin走的是两条编译流程,这个要重点注意。
正常来说,会先编译主体uboot,也就是uboot.bin.再编译uboot-spl,也就是uboot-spl.bin,虽然编译命令是一起的,但是编译流程是分开的。

2、生成文件
最终编译完成之后,会在project-x/build/out/u-boot/spl下生成如下文件:

  1.   arch common dts include u-boot-spl u-boot-spl.cfg u-boot-spl.map
  2.   board drivers fs tiny210-spl.bin u-boot-spl.bin u-boot-spl.lds u-boot-spl-nodtb.bin

 

其中,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配置生成的文件

二、uboot-spl编译流程

1、编译整体流程

根据零、2生成的文件说明可知简单流程如下:
(1)各目录下built-in.o的生成

Created with Raphaël 2.1.0源文件、代码文件编译、汇编目标文件同目录目标文件连接built-in目标文件

对应二、2(5)的实现
(2)由所有built-in.o以u-boot-spl.lds为连接脚本通过连接来生成u-boot-spl

Created with Raphaël 2.1.0built-in目标文件以u-boot-spl.lds为连接脚本进行统一连接u-boot-spl

对应二、2(4)的实现
(3)由u-boot-spl生成u-boot-spl-nodtb.bin

Created with Raphaël 2.1.0u-boot-splobjcopy动作去掉符号信息表u-boot-spl-nodtb.bin

对应二、2(3)的实现
(4)由u-boot-spl-nodtb.bin生成u-boot-spl.bin,也就是spl的bin文件

Created with Raphaël 2.1.0u-boot-spl-nodtb.bin在不需要dtb的情况下,复制u-boot-spl.bin

对应二、2(2)的实现

后续的编译的核心过程就是按照上述的四个编译流程就是按照上述四个步骤来的。


2、具体编译流程分析

我们直接从make uboot命令分析,也就是从uboot下的Makefile的依赖关系来分析整个编译流程。
注意,这个分析顺序和上述的整体编译流程的顺序是反着的。

  • (1)入口分析
    在project-x/u-boot/Makefile中

  1.   all: $(ALL-y)
  2.    
  3.   ALL-$(CONFIG_SPL) += spl/u-boot-spl.bin
  4.   ## 当配置了CONFIG_SPL,make的时候就会执行spl/u-boot-spl.bin这个目标
  5.    
  6.   spl/u-boot-spl.bin: spl/u-boot-spl
  7.   @:
  8.   spl/u-boot-spl: tools prepare $(if $(CONFIG_OF_SEPARATE),dts/dt.dtb)
  9.   $(Q)$(MAKE) obj=spl -f $(srctree)/scripts/Makefile.spl all
  10.   ## obj=spl 会在out/u-boot目录下生成spl目录
  11.   ## -f $(srctree)/scripts/Makefile.spl 说明执行的Makefile文件是scripts/Makefile.spl
  12.   ## $(MAKE) all 相当于make的目标是all

 

综上,由CONFIG_SPL来决定是否需要编译出spl文件,也就是BL1。
后续相当于执行了 “make -f u-boot/scripts/Makefile.spl obj=spl all” 命令。
在project-x/u-boot/scripts/Makefile.spl中,

  1.   SPL_BIN := u-boot-spl
  2.   ALL-y += $(obj)/$(SPL_BIN).bin $(obj)/$(SPL_BIN).cfg
  3.   ## 所以最终目标是spl/u-boot-spl.bin和spl/u-boot-spl.cfg

 

在project-x/u-boot/scripts/Makefile.spl中建立了spl/u-boot-spl.bin的依赖关系,后续make过程的主体都是在Makefile.spl中。


  • (2)spl/u-boot-spl.bin的依赖关系

在project-x/u-boot/scripts/Makefile.spl中

  1.   $(obj)/$(SPL_BIN).bin: $(obj)/$(SPL_BIN)-nodtb.bin FORCE
  2.   $(call if_changed,copy)
  3.   ## $(obj)/$(SPL_BIN).bin依赖于$(obj)/$(SPL_BIN)-nodtb.bin。
  4.   ## $(call if_changed,copy)表示当依赖文件发生变化时,直接把依赖文件复制为目标文件,即直接把$(obj)/$(SPL_BIN)-nodtb.bin复制为$(obj)/$(SPL_BIN).bin

 

如上述Makefile代码spl/u-boot-spl.bin依赖于spl/u-boot-spl-nodtb.bin,并且由spl/u-boot-spl-nodtb.bin复制而成。
对应于上述二、1(4)流程。


  • (3)spl/u-boot-spl-nodtb.bin的依赖关系
    在project-x/u-boot/scripts/Makefile.spl中

  1.   $(obj)/$(SPL_BIN)-nodtb.bin: $(obj)/$(SPL_BIN) FORCE
  2.   $(call if_changed,objcopy)
  3.   $(obj)/$(SPL_BIN)-nodtb.bin依赖于$(obj)/$(SPL_BIN)。也就是spl/u-boot-spl-nodtb.bin依赖于spl/u-boot-spl.
  4.   ## $(call if_changed,objcopy)表示当依赖文件发生变化时,将依赖文件经过objcopy处理之后得到目标文件。
  5.   ## 也就是通过objcopy把spl/u-boot-spl的符号信息以及一些无用信息去掉之后,得到了spl/u-boot-spl-nodtb.bin。

 

如上述Makefile代码spl/u-boot-spl-nodtb.bin依赖于spl/u-boot-spl,并且由spl/u-boot-spl经过objcopy操作之后得到。
对应于上述二、1(3)流程。


  • (4)spl/u-boot-spl的依赖关系
    在project-x/u-boot/scripts/Makefile.spl中

  1.   $(obj)/$(SPL_BIN): $(u-boot-spl-init) $(u-boot-spl-main) $(obj)/u-boot-spl.lds FORCE
  2.   $(call if_changed,u-boot-spl)
  3.   ## $(call if_changed,u-boot-spl)来生成目标
  4.   ## $(call if_changed,u-boot-spl)对应cmd_u-boot-spl命令

 

如上,spl/u-boot-spl依赖于$(u-boot-spl-init) 、$(u-boot-spl-main)和spl/u-boot-spl.ld,并且最终会调用cmd_u-boot-spl来生成spl/u-boot-spl。
cmd_u-boot-spl实现如下:

  1.   quiet_cmd_u-boot-spl = LD $@
  2.   cmd_u-boot-spl = (cd $(obj) && $(LD) $(LDFLAGS) $(LDFLAGS_$(@F)) \
  3.   $(patsubst $(obj)/%,%,$(u-boot-spl-init)) --start-group \
  4.   $(patsubst $(obj)/%,%,$(u-boot-spl-main)) --end-group \
  5.   $(PLATFORM_LIBS) -Map $(SPL_BIN).map -o $(SPL_BIN))

 

将cmd_u-boot-spl通过echo命令打印出来之后得到如下(拆分出来看的):

  1.   cmd_u-boot-spl=(
  2.   cd spl &&
  3.   /build/arm-none-linux-gnueabi-4.8/bin/arm-none-linux-gnueabi-ld
  4.   -T u-boot-spl.lds --gc-sections -Bstatic --gc-sections
  5.   arch/arm/cpu/armv7/start.o
  6.   --start-group
  7.   arch/arm/mach-s5pc1xx/built-in.o arch/arm/cpu/armv7/built-in.o arch/arm/cpu/built-in.o arch/arm/lib/built-in.o board/samsung/tiny210/built-in.o board/samsung/common/built-in.o common/init/built-in.o drivers/built-in.o dts/built-in.o fs/built-in.o
  8.   --end-group
  9.   arch/arm/lib/eabi_compat.o
  10.   -L /home/disk3/xys/temp/project-x/build/arm-none-linux-gnueabi-4.8/bin/../lib/gcc/arm-none-linux-gnueabi/4.8.3 -lgcc
  11.   -Map u-boot-spl.map
  12.   -o u-boot-spl)

 

可以看出上述是一条连接命令,以spl/u-boot-spl.ld为链接脚本,把$(u-boot-spl-init) 、$(u-boot-spl-main)的指定的目标文件连接到u-boot-spl中。
连接很重要的东西就是连接标识,也就是 $(LD) $(LDFLAGS) $(LDFLAGS_$(@F)的定义。
尝试把$(LD) \$(LDFLAGS) \$(LDFLAGS_\$(@F)) 打印出来,结果如下:

  1.   LD=/home/disk3/xys/temp/project-x/build/arm-none-linux-gnueabi-4.8/bin/arm-none-linux-gnueabi-ld
  2.   LDFLAGS=
  3.   LDFLAGS_u-boot-spl=-T u-boot-spl.lds --gc-sections -Bstatic --gc-sections
  4.   ## $(LDFLAGS_$(@F)对应于LDFLAGS_u-boot-spl

 

也就是说在LDFLAGS_u-boot-spl中指定了链接脚本。
重点关注$(LDFLAGS_$(@F))的由来

  1.   ## @F是一个自动化变量,提取目标的文件名,比如目标是$(obj)/$(SPL_BIN),也就是spl/u-boot-spl,那么@F就是u-boot-spl。
  2.   ## 所以LDFLAGS_$(@F)就是LDFLAGS_u-boot-spl
  3.   ## 定义如下
  4.   LDFLAGS_$(SPL_BIN) += -T u-boot-spl.lds $(LDFLAGS_FINAL)
  5.   ifneq ($(CONFIG_SPL_TEXT_BASE),)
  6.   LDFLAGS_$(SPL_BIN) += -Ttext $(CONFIG_SPL_TEXT_BASE)
  7.   endif
  8.   ## 当指定CONFIG_SPL_TEXT_BASE时,会配置连接地址。在tiny210项目中,因为spl是地址无关代码设计,故没有设置连接地址。
  9.    
  10.   ## $(LDFLAGS_FINAL)在如下几个地方定义了
  11.   ## ./config.mk:19:LDFLAGS_FINAL :=
  12.   ## ./config.mk:80:LDFLAGS_FINAL += -Bstatic
  13.   ## ./arch/arm/config.mk:16:LDFLAGS_FINAL += --gc-sections
  14.   ## ./scripts/Makefile.spl:43:LDFLAGS_FINAL += --gc-sections
  15.   ## 综上:最后LDFLAGS_u-boot-spl=-T u-boot-spl.lds --gc-sections -Bstatic --gc-sections就可以理解了。
  16.   ## 对应于上述二、1(2)流程。

 


  • (5)u-boot-spl-init & u-boot-spl-main依赖关系(代码是如何被编译的)
    先看一下这两个值打印出来的

  1.   u-boot-spl-init=spl/arch/arm/cpu/armv7/start.o
  2.    
  3.   u-boot-spl-main= spl/arch/arm/mach-s5pc1xx/built-in.o spl/arch/arm/cpu/armv7/built-in.o spl/arch/arm/cpu/built-in.o spl/arch/arm/lib/built-in.o spl/board/samsung/tiny210/built-in.o spl/board/samsung/common/built-in.o spl/common/init/built-in.o spl/drivers/built-in.o spl/dts/built-in.o spl/fs/built-in.o

 

可以观察到是一堆目标文件的路径。这些目标文件最终都要被连接到u-boot-spl中。
u-boot-spl-init & u-boot-spl-main的定义如下代码:
project-x/u-boot/scripts/Makefile.spl

  1.   u-boot-spl-init := $(head-y)
  2.   head-y := $(addprefix $(obj)/,$(head-y))
  3.   ## 加spl路径
  4.   ## ./arch/arm/Makefile定义了如下:
  5.   ## head-y := arch/arm/cpu/$(CPU)/start.o
  6.    
  7.   u-boot-spl-main := $(libs-y)
  8.   libs-y += $(if $(BOARDDIR),board/$(BOARDDIR)/)
  9.   libs-$(HAVE_VENDOR_COMMON_LIB) += board/$(VENDOR)/common/
  10.   libs-$(CONFIG_SPL_FRAMEWORK) += common/spl/
  11.   libs-y += common/init/
  12.   libs-$(CONFIG_SPL_LIBCOMMON_SUPPORT) += common/ cmd/
  13.   libs-$(CONFIG_SPL_LIBDISK_SUPPORT) += disk/
  14.   libs-y += drivers/
  15.   libs-y += dts/
  16.   libs-y += fs/
  17.   libs-$(CONFIG_SPL_LIBGENERIC_SUPPORT) += lib/
  18.   libs-$(CONFIG_SPL_POST_MEM_SUPPORT) += post/drivers/
  19.   libs-$(CONFIG_SPL_NET_SUPPORT) += net/
  20.   libs-y := $(addprefix $(obj)/,$(libs-y))
  21.   ## 加spl路径
  22.   u-boot-spl-dirs := $(patsubst %/,%,$(filter %/, $(libs-y)))
  23.   ## 这里注意一下,u-boot-spl-dir是libs-y没有加built-in.o后缀的时候被定义的。
  24.   libs-y := $(patsubst %/, %/built-in.o, $(libs-y))
  25.   ## 加built-in.o文件后缀

 

那么u-boot-spl-init & u-boot-spl-main是如何生成的呢?
需要看一下对应的依赖如下:

  1.   $(sort $(u-boot-spl-init) $(u-boot-spl-main)): $(u-boot-spl-dirs) ;
  2.   ## 也就是说$(u-boot-spl-init) $(u-boot-spl-main)依赖于$(u-boot-spl-dirs)
  3.   ## sort函数根据首字母进行排序并去除掉重复的。
  4.   ## u-boot-spl-dirs := $(patsubst %/,%,$(filter %/, $(libs-y)))
  5.   ## $(filter %/, $(libs-y)过滤出'/'结尾的字符串,注意,此时$(libs-y)的内容还没有加上built-in.o文件后缀
  6.   ## patsubst去掉字符串中最后的'/'的字符。
  7.   ## 最后u-boot-spl-dirs打印出来如下:
  8.   ## u-boot-spl-dirs=spl/arch/arm/mach-s5pc1xx spl/arch/arm/cpu/armv7 spl/arch/arm/cpu spl/arch/arm/lib spl/board/samsung/tiny210 spl/board/samsung/common spl/common/init spl/drivers spl/dts spl/fs
  9.   ## 也就是从libs-y改造而来的。
  10.    
  11.   ## $(u-boot-spl-dirs) 的依赖规则如下:
  12.   $(u-boot-spl-dirs):
  13.   $(Q)$(MAKE) $(build)=$@

 

也就是会对每一个目标文件依次执行make $(build)=目标文件
$(build)定义如下:
project-x/u-boot/scripts/Kbuild.include

build := -f $(srctree)/scripts/Makefile.build obj
 

 

以arch/arm/mach-s5pc1xx为例
“$(MAKE) $(build)=$@”展开后格式如下
make -f ~/code/temp/project-x/u-boot/scripts/Makefile.build obj=spl/arch/arm/mach-s5pc1xx。

Makefile.build定义built-in.o、.lib以及目标文件.o的生成规则。这个Makefile文件生成了子目录的.lib、built-in.o以及目标文件.o。
Makefile.build第一个编译目标是__build,如下

  1.   PHONY := __build
  2.   __build:
  3.   ## 所以会直接编译执行__build这个目标,其依赖如下
  4.   __build: $(if $(KBUILD_BUILTIN),$(builtin-target) $(lib-target) $(extra-y)) \
  5.   $(if $(KBUILD_MODULES),$(obj-m) $(modorder-target)) \
  6.   $(subdir-ym) $(always)
  7.   @:
  8.   ## 和built-in.o相关的是依赖builtin-target。下面来看这个依赖。
  9.    
  10.   builtin-target := $(obj)/built-in.o
  11.   ## 以obj=spl/arch/arm/mach-s5pc1xx为例,那么builtin-target就是spl/arch/arm/mach-s5pc1xx/built-in.o.
  12.    
  13.   ## 依赖关系如下:
  14.   $(builtin-target): $(obj-y) FORCE
  15.   $(call if_changed,link_o_target)
  16.   ## $(call if_changed,link_o_target)将所有依赖连接到$(builtin-target),也就是相应的built-in.o中了。
  17.   ## 具体实现可以查看cmd_link_o_target的实现,这里不详细说明了。
  18.    
  19.    
  20.   ## 那么$(obj-y)是从哪里来的呢?是从相应目录下的Makefile中include得到的。
  21.   # The filename Kbuild has precedence over Makefile
  22.   kbuild-dir := $(if $(filter /%,$(src)),$(src),$(srctree)/$(src))
  23.   kbuild-file := $(if $(wildcard $(kbuild-dir)/Kbuild),$(kbuild-dir)/Kbuild,$(kbuild-dir)/Makefile)
  24.   include $(kbuild-file)
  25.   ## 当obj=spl/arch/arm/mach-s5pc1xx时,得到对应的kbuild-file=u-boot/arch/arm/mach-s5pc1xx/Makefile
  26.   ## 而在u-boot/arch/arm/mach-s5pc1xx/Makefile中定义了obj-y如下:
  27.   ## obj-y = cache.o
  28.   ## obj-y += reset.o
  29.   ## obj-y += clock.o
  30.   ## 对应obj-y对应一些目标文件,由C文件编译而来,这里就不说明了。

 

对应于上述二、1(1)流程。


  • (6)spl/u-boot-spl.lds依赖关系
    这里主要是为了找到一个匹配的连接文件。

  1.   $(obj)/u-boot-spl.lds
  2.   $(obj)/u-boot-spl.lds: $(LDSCRIPT) FORCE
  3.   $(call if_changed_dep,cpp_lds)
  4.   ## 依赖于$(LDSCRIPT),$(LDSCRIPT)定义了连接脚本所在的位置,
  5.   ## 然后把链接脚本经过cpp_lds处理之后复制到$(obj)/u-boot-spl.lds中,也就是spl/u-boot-spl.lds中。
  6.   ## cpp_lds处理具体实现看cmd_cpu_lds定义,具体是对应连接脚本里面的宏定义进行展开。
  7.    
  8.   ## $(LDSCRIPT)定义如下
  9.   ifeq ($(wildcard $(LDSCRIPT)),)
  10.   LDSCRIPT := $(srctree)/board/$(BOARDDIR)/u-boot-spl.lds
  11.   endif
  12.   ifeq ($(wildcard $(LDSCRIPT)),)
  13.   LDSCRIPT := $(srctree)/$(CPUDIR)/u-boot-spl.lds
  14.   endif
  15.   ifeq ($(wildcard $(LDSCRIPT)),)
  16.   LDSCRIPT := $(srctree)/arch/$(ARCH)/cpu/u-boot-spl.lds
  17.   endif
  18.   ifeq ($(wildcard $(LDSCRIPT)),)
  19.   $(error could not find linker script)
  20.   endif
  21.   ## 也就是说依次从board/板级目录、cpudir目录、arch/架构/cpu/目录下去搜索u-boot-spl.lds文件。
  22.   ## 例如,tiny210(s5vp210 armv7)最终会在./arch/arm/cpu/下搜索到u-boot-spl.lds

 

综上,最终指定了project-X/u-boot/arch/arm/cpu/u-boot-spl.lds作为连接脚本。


三、一些重点定义

  • 1、CONFIG_SPL
    在二、2(1)中说明。
    用于指定是否需要编译SPL,也就是是否需要编译出uboot-spl.bin文件

  • 2、连接脚本的位置
    在二、2(6)中说明。
    对于tiny210(s5pv210 armv7)来说,连接脚本的位置在
    project-x/u-boot/arch/arm/cpu/u-boot-spl.lds

  • 3、CONFIG_SPL_TEXT_BASE
    在二、2(4)中说明。
    用于指定SPL的连接地址,可以定义在板子对应的config文件中。

  • 4、CONFIG_SPL_BUILD
    在编译spl过程中,会配置
    project-x/scripts/Makefile.spl中定义了如下

KBUILD_CPPFLAGS += -DCONFIG_SPL_BUILD
 

 

也就是说在编译uboot-spl.bin的过程中,CONFIG_SPL_BUILD这个宏是被定义的。

四、uboot-spl链接脚本说明

1、连接脚本整体分析

相对比较简单,直接看连接脚本的内容project-x/u-boot/arch/arm/cpu/u-boot-spl.lds
前面有一篇分析连接脚本的文章了《[kernel 启动流程] 前篇——vmlinux.lds分析》,可以参考一下。

  1.   ENTRY(_start)
  2.   //定义了地址为_start的地址,所以我们分析代码就是从这个函数开始分析的!!!
  3.   SECTIONS
  4.   {
  5.   . = 0x00000000;
  6.    
  7.   //以下定义文本段
  8.   . = ALIGN(4);
  9.   .text :
  10.   {
  11.   __image_copy_start = .;
  12.   //定义__image_copy_start这个标号地址为当前地址
  13.   *(.vectors)
  14.   //所有目标文件的vectors段,也就是中断向量表连接到这里来
  15.   CPUDIR/start.o (.text*)
  16.   //start.o文件的.text段链接到这里来
  17.   *(.text*)
  18.   //所有目标文件的.text段链接到这里来
  19.   }
  20.    
  21.   //以下定义只读数据段
  22.   . = ALIGN(4);
  23.   .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
  24.    
  25.   //以下定义数据段
  26.   . = ALIGN(4);
  27.   .data : {
  28.   *(.data*)
  29.   //所有目标文件的.data段链接到这里来
  30.   }
  31.    
  32.   //以下定义u_boot_list段,具体功能未知
  33.   . = ALIGN(4);
  34.   .u_boot_list : {
  35.   KEEP(*(SORT(.u_boot_list*)));
  36.   }
  37.    
  38.   . = ALIGN(4);
  39.    
  40.   __image_copy_end = .;
  41.   //定义__image_copy_end符号的地址为当前地址
  42.   //从__image_copy_start 到__image_copy_end的区间,包含了代码段和数据段。
  43.    
  44.   //以下定义rel.dyn段,这个段用于uboot资源重定向的时候使用,后面会说明
  45.   .rel.dyn : {
  46.   __rel_dyn_start = .;
  47.   //定义__rel_dyn_start 符号的地址为当前地址,后续在代码中会使用到
  48.   *(.rel*)
  49.   __rel_dyn_end = .;
  50.   //定义__rel_dyn_end 符号的地址为当前地址,后续在代码中会使用到
  51.   //从__rel_dyn_start 到__rel_dyn_end 的区间,应该是在代码重定向的过程中会使用到,后续遇到再说明。
  52.   }
  53.    
  54.   .end :
  55.   {
  56.   *(.__end)
  57.   }
  58.    
  59.   _image_binary_end = .;
  60.   //定义_image_binary_end 符号的地址为当前地址
  61.    
  62.   //以下定义bss段
  63.   .bss __rel_dyn_start (OVERLAY) : {
  64.   __bss_start = .;
  65.   *(.bss*)
  66.   . = ALIGN(4);
  67.   __bss_end = .;
  68.   }
  69.   __bss_size = __bss_end - __bss_start;
  70.   .dynsym _image_binary_end : { *(.dynsym) }
  71.   .dynbss : { *(.dynbss) }
  72.   .dynstr : { *(.dynstr*) }
  73.   .dynamic : { *(.dynamic*) }
  74.   .hash : { *(.hash*) }
  75.   .plt : { *(.plt*) }
  76.   .interp : { *(.interp*) }
  77.   .gnu : { *(.gnu*) }
  78.   .ARM.exidx : { *(.ARM.exidx*) }
  79.   }

 

2、符号表中需要注意的符号

project-x/build/out/u-boot/spl/u-boot-spl.map

  1.   Linker script and memory map
  2.   .text 0x00000000 0xd10
  3.   0x00000000 __image_copy_start = .
  4.   *(.vectors)
  5.   0x00000000 _start
  6.   0x00000020 _undefined_instruction
  7.   0x00000024 _software_interrupt
  8.   0x00000028 _prefetch_abort
  9.   0x0000002c _data_abort
  10.   0x00000030 _not_used
  11.   0x00000034 _irq
  12.   0x00000038 _fiq
  13.   ...
  14.   0x00000d10 __image_copy_end = .
  15.   .rel.dyn 0x00000d10 0x0
  16.   0x00000d10 __rel_dyn_start = .
  17.   *(.rel*)
  18.   .rel.iplt 0x00000000 0x0 arch/arm/cpu/armv7/start.o
  19.   0x00000d10 __rel_dyn_end = .
  20.   .end
  21.   *(.__end)
  22.   0x00000d10 _image_binary_end = .
  23.    
  24.   .bss 0x00000d10 0x0
  25.   0x00000d10 __bss_start = .
  26.   *(.bss*)
  27.   0x00000d10 . = ALIGN (0x4)
  28.   0x00000d10 __bss_end = .

 

重点关注
* __image_copy_start & __image_copy_end
界定了代码的位置,用于重定向代码的时候使用,后面碰到了再分析。
* _start
在u-boot-spl.lds中ENTRY(_start),也就规定了代码的入口函数是_start。所以后续分析代码的时候就是从这里开始分析。
* __rel_dyn_start & __rel_dyn_end
* _image_binary_end

五、tiny210(s5pv210)的额外操作

1、为什么tiny210的spl需要额外操作?需要什么额外操作?

建议先参考《[project X] tiny210(s5pv210)上电启动流程(BL0-BL2)》一文。
tiny210只支持SD启动的方式和NAND FLASH启动的方式。
从《[project X] tiny210(s5pv210)上电启动流程(BL0-BL2)》一文中,我们已经得知了当使用SD启动的方式和NAND FLASH启动的方式,也就是BL1镜像存放在SD上或者nand flash上时,s5pv210中固化的BL0,都需要对BL1的前16B的header做校验。BL1就是我们所说的uboot-spl.bin,但是默认编译出来的uboot-spl.bin就是一个纯粹的可执行文件,并没有加上特别的header。
因此,我们需要在生成uboot-spl.bin之后,再为其加上16B的header后生成tiny210-spl.bin。
16B的header格式如下:

地址

数据

0xD002_0000

BL1镜像包括header的长度

0xD002_0004

保留,设置为0

0xD002_0008

BL1镜像除去header的校验和

0xD002_000c

保留,设置为0

2、如何生成header?(如何生成tiny210-spl.bin)

project-x/u-boot/scripts/Makefile.spl

  1.   ifdef CONFIG_SAMSUNG
  2.   ALL-y += $(obj)/$(BOARD)-spl.bin
  3.   endif
  4.   ## 当平台是SAMSUNG平台的时候,也就是CONFIG_SAMSUNG被定义的时候,就需要生成对应的板级spl.bin文件,例如tiny210的话,就应该生成对应的spl/tiny210-spl.bin文件。
  5.    
  6.   ifdef CONFIG_S5PC110
  7.   $(obj)/$(BOARD)-spl.bin: $(obj)/u-boot-spl.bin
  8.   $(objtree)/tools/mks5pc1xxspl $< $@
  9.   ## 如果是S5PC110系列的cpu的话,则使用如上方法打上header。tiny210的cpu是s5pv210的,属于S5PC110系列,所以走的是这路。
  10.   ## $(objtree)/tools/mks5pc1xxspl对应于编译uboot时生成的build/out/u-boot/tools/mks5pc1xxspl
  11.   ## 其代码路径位于u-boot/tools/mks5pc1xxspl.c,会根据s5pc1xx系列的header规则为输入bin文件加上16B的header,具体参考代码。
  12.   ## 这里就构成了u-boot-spl.bin到tiny210-spl.bin的过程了。
  13.   else
  14.   $(obj)/$(BOARD)-spl.bin: $(obj)/u-boot-spl.bin
  15.   $(if $(wildcard $(objtree)/spl/board/samsung/$(BOARD)/tools/mk$(BOARD)spl),\
  16.   $(objtree)/spl/board/samsung/$(BOARD)/tools/mk$(BOARD)spl,\
  17.   $(objtree)/tools/mkexynosspl) $(VAR_SIZE_PARAM) $< $@
  18.   endif
  19.   endif

 

这里就构成了u-boot-spl.bin到tiny210-spl.bin的过程了。

综上,spl的编译就完成了。

--------------------- 本文来自 ooonebook 的CSDN 博客 ,全文地址请点击:https://blog.csdn.net/ooonebook/article/details/52949584?utm_source=copy

 

标签:bin,uboot,##,boot,编译,spl,obj,SPL
From: https://www.cnblogs.com/zxdplay/p/18218533

相关文章

  • 本地编译memos, 不使用dock
    memos简介memos是一个开源的个人博客,类似个人朋友圈,日记本之内的。先从memos的官方github项目主页下载源码、解压这些就不说了。前端使用nodejs,后端使用go后端编译直接进入解压后的bin目录下(.\memos-0.19.1\bin\memos),执行编译命令(这个过程中会下载一些go的包,可能需要kx......
  • WPF Splash Screen – A New Splash Screen Manager (v20.1) 启动页 闪屏页 初始加载
    WPFSplashScreen–ANewSplashScreenManager(v20.1)(devexpress.com)  WPFTeamBlog RSS06July2020A splashscreen isaneffectivewaytoimproveanapp’suserexperienceduringlengthystartupoperations.Unfortunately,creatinganef......
  • golang的交叉编译是什么
     Go(Golang)的交叉编译是指在一种硬件架构或操作系统环境下,使用Go编译器生成适用于另一种架构或操作系统的可执行程序。Go语言的设计使得交叉编译变得非常简单和高效,它允许开发者在开发环境中构建目标平台上的代码,而无需在目标平台上实际运行编译过程。 在Go中,交叉编译主要涉......
  • 安装和使用delphi最后的余辉:lazarus集成编译环境@FreeBSD
    遥想当年,最牛最流行的两个编程IDE是Delphi和VisualBasic,结果这么多年下来,VB已经没有往昔的热度,而Delphi也已经消亡在历史的长河中。不过Delphi的精神没消失,lazarus坚守delphi的编程风格,散发delphi最后的余辉。Lazarus介绍Lazarus是一个基于FreePascal的跨平台集成开发环境(I......
  • 源码编译安装LAMP
    目录1.Apache网站服务2.MySQL服务3.PHP服务4.LAMP架构应用实例LAMP:网站服务架构同时提供静态页面和动态页面能力Linux:提供网站服务应用的运行环境,也支持Windows作为AMP的运行环境Apache:作为前端网站服务,直接面向用户提供网站访问入口,并处理静态页面请求MySQL:作为后端......
  • 部署经典黄金架构LAMP----编译安装MySQL----2
    版本要求:mysql-5.6.49安装目录:/usr/local/msyql数据目录:/usr/local/msyql/data端口:33061、检查是否安装了mariadb(如果有会返回,给它卸载了) [root@localhostlocal]#rpm-qa|grep-imariadbmariadb-libs-5.5.65-1.el7.x86_64[root@localhostlocal]#rpm-qa|grep-im......
  • 在openkylin上编译UKUI开源组件
    目录一、准备工作二、搭建Qt编译环境三、编译UKUI开源组件这里就不赘述怎么安装openkylin系统了,可以虚拟机安装也可以使用本地安装,UKUI桌面环境主要是使用Qt开发,下面讲解从搭建Qt编译环境到编译开源组件,这里使用的openkylin系统是openkylin2.0nile 一、准备工作打开......
  • Android交叉编译
    https://www.jianshu.com/p/b31acea79717https://www.jianshu.com/p/f77554b0caef概念编译环境和运行环境不同(在一个平台(pc)生成另一个平台(Androidios等)的可执行代码)使用到的工具CC编译器对C源文件进行编译处理,生成汇编文件(CCompiler)ls-l/usr/bin/cc AS将......
  • 源码编译安装LAMP
    1、LAMPLAMP架构是目前成熟的企业网站应用模式之一,指的是协同工作的一整套系统和相关软件,能够提供动态Web站点服务及其应用开发环境。LAMP是一个缩写词,具体包括Linux操作系统、Apache网站服务器、MySQL数据库服务器、PHP(或Perl、Python)网页编程语言。各组件的作用(平台)Li......
  • Java中编译异常与运行异常的区别
    编译期异常和运行期异常的区别编译期异常和运行期异常的区别如下异常处理要求不同:编译期异常(也称为检测异常checkedException)要求在代码中显式地处理(使用try-catch或者throws)。运行时异常(也称为uncheckedException)不要求显式地处理。异常检测时机不同:编译期异常在代码编译阶......