- 了解uboot 编译流程
1.uboot编译流程
1.1.编译生成文件
1.2.编译整体流程
2.编译流程分析
编译时一般执行 make 或者 make all 命令进行编译。一般在根目录的 Makefile 中定义相应的编译命令。
1).入口分析
all: $(ALL-y)
# 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 binary_size_check
...
ALL-$(CONFIG_SPL) += spl/u-boot-spl.bin
ALL-$(CONFIG_SPL_FRAMEWORK) += u-boot.img
ALL-$(CONFIG_OF_HOSTFILE) += u-boot.dtb
ALL-$(CONFIG_OF_SEPARATE) += u-boot-dtb.img
2).u-boot.bin依赖关系
else 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
如上所示,u-boot-dtb.bin是由命令cat将u-boot-nodtb.bin和dts/dt.dtb拼接而成,即
cat u-boot-nodtb.bin dts/dt.dtb > u-boot.dtb.bin
而u-boot.bin 是u-boot-nodtb.bin的拷贝。
3).u-boot-nodtb.bin依赖关系
u-boot-nodtb.bin: u-boot FORCE
$(call if_changed,objcopy)
$(call DO_STATIC_RELA,$<,$@,$(CONFIG_SYS_TEXT_BASE))
$(BOARD_SIZE_CHECK)
4).u-boot 依赖关系
u-boot: $(u-boot-init) $(u-boot-main) u-boot.lds FORCE
$(call if_changed,u-boot__)
## $(call if_changed,u-boot__)对应cmd_u-boot__命令
如上,u-boot依赖于$(u-boot-init) 、$(u-boot-main)和u-boot.lds,并且最终调用cmd_u-boot__来生成u-boot。 cmd_u-boot__实现如下 :
# Rule to link u-boot
# May be overridden by arch/$(ARCH)/config.mk
quiet_cmd_u-boot__ ?= LD $@
cmd_u-boot__ ?= $(LD) $(LDFLAGS) $(LDFLAGS_u-boot) -o $@ \
-T u-boot.lds $(u-boot-init) \
--start-group $(u-boot-main) --end-group \
$(PLATFORM_LIBS) -Map u-boot.map; \
$(if $(ARCH_POSTLINK), $(MAKE) -f $(ARCH_POSTLINK) $@, true)
展开分析一下,在开头添加#,然后编译u-boot,输出如下:
u-boot: $(u-boot-init) $(u-boot-main) u-boot.lds FORCE
#+$(call if_changed,u-boot__)
>#+ @set -e; echo ' LD u-boot'; aarch64-linux-gnu-ld.bfd -pie --gc-sections -Bstatic --no-dynamic-linker ***-Ttext 0x00200000*** -o u-boot -T u-boot.lds arch/arm/cpu/armv8/start.o --start-group arch/arm/cpu/built-in.o arch/arm/cpu/armv8/built-in.o arch/arm/lib/built-in.o arch/arm/mach-rockchip/built-in.o board/rockchip/evb_rk3399/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/power/built-in.o drivers/power/battery/built-in.o drivers/power/domain/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/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 --end-group -L /home/zhaoxiao/Documents/work/tools/cross_tool_chain/gcc-linaro-7.3.1-2018.05-x86_64_aarch64-linux-gnu/bin/../lib/gcc/aarch64-linux-gnu/7.3.1 -lgcc -Map u-boot.map; true; printf '%s\n' 'cmd_u-boot := aarch64-linux-gnu-ld.bfd -pie --gc-sections -Bstatic --no-dynamic-linker -Ttext 0x00200000 -o u-boot -T u-boot.lds arch/arm/cpu/armv8/start.o --start-group arch/arm/cpu/built-in.o arch/arm/cpu/armv8/built-in.o arch/arm/lib/built-in.o arch/arm/mach-rockchip/built-in.o board/rockchip/evb_rk3399/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/power/built-in.o drivers/power/battery/built-in.o drivers/power/domain/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/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 --end-group -L /home/zhaoxiao/Documents/work/tools/cross_tool_chain/gcc-linaro-7.3.1-2018.05-x86_64_aarch64-linux-gnu/bin/../lib/gcc/aarch64-linux-gnu/7.3.1 -lgcc -Map u-boot.map; true' > ./.u-boot.cmd
可以看出上述是一条连接命令,以u-boot.lds为链接脚本,把$(u-boot-init) 、$(u-boot-main)的指定的目标文件连接到u-boot中,并且已经指定输出文件为u-boot。
链接地址是由CONFIG_SYS_TEXT_BASE(configs/xxx_defconfig)定义的,该变量指定text segment的起始链接地址。即 -Ttext 0x00200000。
5).u-boot-init & u-boot-main依赖关系
u-boot-init=arch/arm/cpu/armv8/start.o
u-boot-main= arch/arm/cpu/built-in.o arch/arm/cpu/armv7/built-in.o arch/arm/lib/built-in.o arch/arm/mach-s5pc1xx/built-in.o board/samsung/common/built-in.o board/samsung/tiny210/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/mmc/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 fs/built-in.o lib/built-in.o net/built-in.o test/built-in.o test/dm/built-in.o
如上所示都是一堆目标文件的路径,这些目标文件最终都要被连接到u-boot中。
u-boot-init & u-boot-main的定义如下:
u-boot-init := $(head-y)
u-boot-main := $(libs-y)
arch/xxx/Makefile:
head-y := arch/arm/cpu/$(CPU)/start.o
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/
...
u-boot-dirs := $(patsubst %/,%,$(filter %/, $(libs-y))) tools examples
## 过滤出路径之后,加上tools目录和example目录
libs-y := $(patsubst %/, %/built-in.o, $(libs-y))
## 先加上后缀built-in.o
u-boot-main := $(libs-y)
u-boot-init & u-boot-main生成依赖于u-boot-dirs:
$(sort $(u-boot-init) $(u-boot-main)): $(u-boot-dirs) ;
u-boot-dirs依赖规则如下:
PHONY += $(u-boot-dirs)
$(u-boot-dirs): prepare scripts
( Q ) (Q) (Q)(MAKE) ( b u i l d ) = (build)= (build)=@
对每一个目标文件依次执行make $(build)=目标文件 ,$(build)定义如下:
scripts/Kbuild.include
build := -f $(srctree)/scripts/Makefile.build obj
scripts/Makefile.build定义built-in.o、.lib以及目标文件.o的生成规则。这个Makefile文件生成了子目录的.lib、built-in.o以及目标文件.o。Makefile.build第一个编译目标是__build,如下所示:
PHONY := __build
__build:
## 直接编译执行__build这个目标,其依赖如下:
__build: $(if $(KBUILD_BUILTIN),$(builtin-target) $(lib-target) $(extra-y)) \
$(if $(KBUILD_MODULES),$(obj-m) $(modorder-target)) \
$(subdir-ym) $(always)
@:
## 和built-in.o相关的是依赖builtin-target
builtin-target := $(obj)/built-in.o
$(builtin-target): $(obj-y) FORCE
$(call if_changed,link_o_target)
目标文件的编译流程:
./scripts/Makefile.build:
# Built-in and composite module parts
$(obj)/%.o: $(src)/%.c $(recordmcount_source) FORCE
$(call cmd,force_checksrc)
$(call if_changed_rule,cc_o_c)
## 调用cmd_cc_o_c对.c文件进行编译
## cmd_cc_o_c格式如下:
cmd_cc_o_c = $(CC) $(c_flags) -c -o $@ $<
6).u-boot.lds依赖关系
u-boot.lds: $(LDSCRIPT) prepare FORCE
$(call if_changed_dep,cpp_lds)
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
依次从board/板级目录、cpudir目录、arch/架构/cpu/目录下去搜索u-boot.lds文件。
7). dts/dt.dtb依赖关系
该依赖关系的主要目的是生成dtb文件,dt.dtb对应的命令如下,执行make dtbs 产生dtb文件。
Makefile:
PHONY += dtbs
dtbs: dts/dt.dtb
@:
dts/dt.dtb: u-boot
$(Q)$(MAKE) $(build)=dts dtbs
展开该命令:
@make -f ./scripts/Makefile.build obj=dts dtbs
如上所示:
Make进入由参数-f指定的Make文件scripts/Makefile.build,并传入参数obj=build_dir 和argv。
- $(MAKE) = make -f (-f mean read file as a makefile)
- $(build) = ./scripts/Makefile.build obj = dts
- $@ = dtbs
此时./scripts/Makefile.build文件中src变量等于obj传入的值dts,然后include dts/Makefile.
src := $(patsubst $(prefix)/%,%,$(obj))
# 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)
dts/Makefile:
DEVICE_TREE ?= $(CONFIG_DEFAULT_DEVICE_TREE:"%"=%)
变量CONFIG_DEFAULT_DEVICE_TREE是在配置文件configs/xxx_defconfig中指定设备数镜像文件名。
CONFIG_DEFAULT_DEVICE_TREE="rk3399-firefly"
目标dtbs生成命令:
dts/Makefile
ifneq ($(EXT_DTB),)
DTB := $(EXT_DTB)
else
DTB := arch/$(ARCH)/dts/$(DEVICE_TREE).dtb
endif
$(obj)/dt-spl.dtb: $(DTB) $(objtree)/tools/fdtgrep FORCE
$(call if_changed,fdtgrep)
$(obj)/dt.dtb: $(DTB) FORCE
$(call if_changed,shipped)
targets += dt.dtb dt-spl.dtb
如上所示,obj就是dts目录,生成dt.dtb和dt-spl.dtb分别调用命令:shipped和fdtgrep,这两个命令定义在./scripts/Makefile.lib文件中:
quiet_cmd_shipped = SHIPPED $@
cmd_shipped = cat $< > $@
$(obj)/%: $(src)/%_shipped
$(call cmd,shipped)
quiet_cmd_fdtgrep = FDTGREP $@
cmd_fdtgrep = $(objtree)/tools/fdtgrep $(fdtgrep_props) -RT $< \
-n /chosen -n /config -O dtb | \
$(objtree)/tools/fdtgrep -r -O dtb - -o $@ \
-P u-boot,dm-pre-reloc -P u-boot,dm-spl -P u-boot,dm-tpl \
$(addprefix -P ,$(subst $\",,$(CONFIG_OF_SPL_REMOVE_PROPS)))
shipped执行展开:
cat arch/arm/dts/rk3399-firefly.dtb > dts/dt.dtb
fdtgrep执行展开:
对arch/arm/dts/rk3399-firefly.dtb进行裁剪,然后输出到dts/dt-spl.dtb.
接下来看看生成dtb需要的依赖文件:
$(DTB): (dtb_depends)
ifeq ($(EXT_DTB),)
$(Q)$(MAKE) $(build)=$(ARCH_PATH) dtbs
...
arch-dtbs:
$(Q)$(MAKE) $(build)=$(ARCH_PATH) dtbs
通过如下设置,可以将此行展开,执行make dtbs 即可。
#$(MAKE) $(build)=$(ARCH_PATH) dtbs
展开如下:
@make -f ./scripts/Makefile.build obj=arch/arm/dts arch/arm/dts/rk3399-firefly.dtb
其中dtb_depends为arch/arm/dts/rk3399-firefly.dts,ARCH_PATH为arch/arm/dts。最后arch/arm/dts/Makefile通过如下所示被include,该文件中定义了dtbs的目标。
arch-dtbs:
$(Q)$(MAKE) $(build)=arch/$(ARCH)/dts dtbs
而在scripts/Makefile.lib文件中定义dtb生成:
$(obj)/%.dtb: $(src)/%.dts FORCE
$(call if_changed_dep,dtc)
进入arch/arm/dts/Makefile,如下所示:
arch/arm/dts/Makefile:
dtb-$(CONFIG_S5PC110) += s5pc1xx-goni.dtb
dtb-$(CONFIG_EXYNOS5) += exynos5250-arndale.dtb \
exynos5250-snow.dtb \
exynos5250-spring.dtb \
exynos5250-smdk5250.dtb \
exynos5420-smdk5420.dtb \
exynos5420-peach-pit.dtb \
exynos5800-peach-pi.dtb \
exynos5422-odroidxu3.dtb
dtb-$(CONFIG_TARGET_TINY210) += \
s5pv210-tiny210.dtb
## 填充选择dtb-y
targets += $(dtb-y)
# Add any required device tree compiler flags here
DTC_FLAGS +=
## 用于添加DTC编译选项
PHONY += dtbs
dtbs: $(addprefix $(obj)/, $(dtb-y))
@: //表示什么都不做
3.SPL(u-boot-spl.bin) 编译流程
The object files for SPL are built separately and placed in the “spl” directory. The final binaries which are generated are u-boot-spl, u-boot-spl.bin and u-boot-spl.map.
A config option named CONFIG_SPL_BUILD is enabled by Kconfig for SPL.Source files can therefore be compiled for SPL with different settings.(doc/README.SPL)
3.1.编译生成文件
3.2.uboot-spl编译流程
u-boot-spl.bin编译是编译uboot的一部分,和uboot.bin走的是两条编译流程。首先编译uboot.bin,再编译uboot-spl.bin,虽然编译命令是一起的,但是编译流程是分开的。通过CONFIG_SPL_BUILD宏来进行区分的:
scripts/Makefile.spl:
KBUILD_CPPFLAGS += -DCONFIG_SPL_BUILD
编译u-boot-spl使用脚本scripts/Makefile.spl :
Makefile:
spl/u-boot-spl.bin: spl/u-boot-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
修改为:
#$(Q)$(MAKE) obj=spl -f $(srctree)/scripts/Makefile.spl all
编译展开后为:
#@make obj=spl -f ./scripts/Makefile.spl all
类似u-boot.bin编译,ALL-y 包含编译目录:
scripts/Makefile.spl:
SPL_BIN := u-boot-spl
all: $(ALL-y)
ALL-y += $(obj)/$(SPL_BIN).bin
如下所示,编译u-boot-spl.bin:spl/u-boot-spl依赖于$(u-boot-spl-init) ,$(u-boot-spl-main),spl/u-boot-spl.lds,并且最终调用cmd_u-boot-spl来生成spl/u-boot-spl。
# Rule to link u-boot-spl
# May be overridden by arch/$(ARCH)/config.mk
quiet_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)
下面分别介绍一下这几个依赖关系:
- u-boot-spl-init := $(head-y)
- arch/arm/Makefile :head-y := arch/arm/cpu/$(CPU)/start.o
- u-boot-spl-main := $(libs-y)
- u-boot-spl.lds
Because SPL images normally have a different text base, one has to be configured by defining CONFIG_SPL_TEXT_BASE. The linker script has to be defined with CONFIG_SPL_LDSCRIPT.
- CONFIG_SPL_TEXT_BASE :SPL的入口地址
- include/configs/xxx.h
- CONFIG_SPL_LDSCRIPT :SPL的链接脚本
如下所示,CONFIG_SPL_LDSCRIPT 指定spl链接脚本,定义在configs/xxx_defconfig中,如果没有定义,则依次从board/板级目录、cpudir目录、arch/架构/cpu/目录下去搜索u-boot-spl.lds文件。
configs/taurus_defconfig:
CONFIG_SPL_LDSCRIPT="arch/$(ARCH)/cpu/u-boot-spl.lds"
scripts/Makefiel.spl:
ifneq ($(CONFIG_SPL_LDSCRIPT),)
# need to strip off double quotes
LDSCRIPT := $(addprefix $(srctree)/,$(CONFIG_SPL_LDSCRIPT:"%"=%))
endif
endif
ifeq ($(wildcard $(LDSCRIPT)),)
LDSCRIPT := $(srctree)/board/$(BOARDDIR)/u-boot-spl.lds
endif
ifeq ($(wildcard $(LDSCRIPT)),)
LDSCRIPT := $(srctree)/$(CPUDIR)/u-boot-spl.lds
endif
ifeq ($(wildcard $(LDSCRIPT)),)
LDSCRIPT := $(srctree)/arch/$(ARCH)/cpu/u-boot-spl.lds
endif
同理编译u-boot-spl-nodtb.bin,u-boot-spl-dtb.bin。
$(obj)/$(SPL_BIN)-nodtb.bin: $(obj)/$(SPL_BIN) FORCE
$(call if_changed,objcopy)
ifneq ($(build_dtb),)
$(obj)/$(SPL_BIN)-dtb.bin: $(obj)/$(SPL_BIN)-nodtb.bin \
$(if $(CONFIG_SPL_SEPARATE_BSS),,$(obj)/$(SPL_BIN)-pad.bin) \
$(FINAL_DTB_CONTAINER) FORCE
$(call if_changed,cat)
$(obj)/$(SPL_BIN).bin: $(obj)/$(SPL_BIN)-dtb.bin FORCE
$(call if_changed,copy)
else
$(obj)/$(SPL_BIN).bin: $(obj)/$(SPL_BIN)-nodtb.bin FORCE
$(call if_changed,copy)
endif
参考资料:
https://blog.csdn.net/ooonebook/article/details/52949584