U-Boot 工程目录分析
 

  arch 文件夹

        与 架构有关的文件

 

   board 文件夹

       与具体的板子有关的
 

configs文件夹

   uboot 配置文件

  在编译 uboot 之前一定要使用 defconfig 来配置 uboot!


 .u-boot.xxx_cmd 文件

         编译生成的,都是一些命令文件

     .u-boot.bin.cmd

// 拷贝 u-boot-nodtb.bin 文件,并重命名为 u-boot.bin
cmd_u-boot.bin := cp u-boot-dtb.bin u-boot.bin

    u-boot-nodtb.bin

        文 件 .u-boot-nodtb.bin.cmd 就 是 用 于 生 成 uboot.nodtb.bin
 

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

        arm-linux-gnueabihf-objcopy : 使用 objcopy 将 ELF 格式的 u-boot 文件转换为 二进制的 u-boot-nodtb.bin 文件

       u-boot 文件 是 ELF 格式

.u-boot.cmd

      生成 u-boot

cmd_u-boot := arm-linux-gnueabihf-ld.bfd   -pie  --gc-sections -Bstatic \
 --no-dynamic-linker -Ttext 0x4a000000 -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-sunxi/built-in.o  board/sunxi/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/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/cdns3/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 \
--end-group arch/arm/lib/eabi_compat.o  arch/arm/lib/lib.a -Map u-boot.map; \
 true

 链接工具 : arm-linux-gnueabihf-ld.bfd
  ld.bfd 将各个 builtin.o 文件链接在一起就形成了 u-boot 文件

.u-boot.img.cmd

cmd_u-boot.img := ./tools/mkimage -A arm -T firmware -C none -O u-boot -a\
 0x4a000000 -e 0 -n "U-Boot 2020.01"" for sunxi board" -d u-boot.bin u-boot.img\
 >/dev/null 


.u-boot.lds.cmd

       生成 u-boot.lds 链接脚本

       来源于 arch/arm/cpu/u-boot.lds文件

Makefile 文件

     顶层 Makefile 文件,顶层 Makefile 可以调用子目录中的 Makefile 文件

u-boot.xxx 文件

u-boot 编译ELF格式的uboot镜像文件
u-boot.bin 编译二进制格式的uboot可执行镜像文件
u-boot.cfg uboot的另一配置文件
u-boot.img u-boot.bin添加头部信息的文件
u-boot.srec S-Record格式的镜像文件
u-boot.lds 链接脚本
u-boot.map uboot映射文件
u-boot.sym uboot符号文件
u-boot-nodtb.bin u-boot.bin复制文件

config 文件

     uboot 配置文件,使用命令“make xxx_defconfig”配置 uboot 以后就会自动生成

#
# Automatically generated file; DO NOT EDIT.
# U-Boot 2020.01 Configuration
#
CONFIG_CREATE_ARCH_SYMLINK=y
# CONFIG_ARC is not set
CONFIG_ARM=y
# CONFIG_M68K is not set
# CONFIG_MICROBLAZE is not set
# CONFIG_MIPS is not set
# CONFIG_NDS32 is not set
# CONFIG_NIOS2 is not set
# CONFIG_PPC is not set
# CONFIG_RISCV is not set
# CONFIG_SANDBOX is not set
# CONFIG_SH is not set
# CONFIG_X86 is not set
# CONFIG_XTENSA is not set
CONFIG_SYS_ARCH="arm"
CONFIG_SYS_CPU="armv7"
CONFIG_SYS_SOC="sunxi"
CONFIG_SYS_BOARD="sunxi"
CONFIG_SYS_CONFIG_NAME="sun7i"
# CONFIG_SYS_ICACHE_OFF is not set
# CONFIG_SPL_SYS_ICACHE_OFF is not set
# CONFIG_SYS_DCACHE_OFF is not set
# CONFIG_SPL_SYS_DCACHE_OFF is not set

#

          以“ CONFIG_ ”开始的配置项
          ‘ y ’的变量一般用于控制某项功能是否使能


    README

            描述了 uboot 的详细信息


U-Boot 顶层 Makefile 分析

      版本号

# SPDX-License-Identifier: GPL-2.0+

# 主版本号
VERSION = 2020
# 补丁版本号
PATCHLEVEL = 01
# 次版本号
SUBLEVEL =
# 附加版本信息
EXTRAVERSION =
# 名字
NAME =
# o Do not use make's built-in rules and variables
#   (this increases performance and avoids hard-to-debug behaviour);
# o Look for make include files relative to root of kernel src
# += : 追加
# -rR : 禁止使用内置的隐含规则和变量定义
# --include-dir : 搜索路径
# $(CURDIR) : $(CURDIR)
MAKEFLAGS += -rR --include-dir=$(CURDIR)
# 不导出变量给子 make
unexport HOST_ARCH

else ifeq ("armv7l", $(MK_ARCH))
  # 导出变量给子 make
  export HOST_ARCH=$(HOST_ARCH_ARM)

命令输出

    uboot 默认编译是 短命令
    变量“ V=1 “ : 长命令

     变量 quiet 和 Q 控制编译时是否在终端输出完整的命令

# 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 "是否相等
# origin 返回值:变量来源
ifeq ("$(origin V)", "command line")

  # KBUILD_VERBOSE=1
  KBUILD_VERBOSE = $(V)
endif

# KBUILD_VERBOSE=0
ifndef KBUILD_VERBOSE
  KBUILD_VERBOSE = 0
endif

# 判断 KBUILD_VERBOSE 是否为 1
ifeq ($(KBUILD_VERBOSE),1)
  quiet =
  Q =
else
  quiet=quiet_

  # 命令前加“ @ ”,不会在终端输出命令
  Q = @
endif

 

# quiet 为空 长命令
# quiet 为“ quiet_ ” 短命令
# quiet 为" silent_ " 无输出

# 短命令
quiet_cmd_sym ?= SYM     $@

    # 长命令
    cmd_sym ?= $(OBJDUMP) -t $< > $@

  静默输出

       make -s :静默输出

# If the user is running make -s (silent mode), suppress echoing of commands

# 判断 编译器版本号是否为 4.x
# $(filter <pattern...>,<text>):过滤函数
# %:通配符
# text :过滤单词
# MAKE_VERSION :make工具的版本号
# make -v:查看 make工具版本号
# 不为空:条件成立
ifneq ($(filter 4.%,$(MAKE_VERSION)),)	# make-4

    # $(firstword <text>)
    # 滤出符合“ %s ”的单词
    # firstword :获取 text 的首单词
    # 返回值不为空,条件成立
    ifneq ($(filter %s ,$(firstword x$(MAKEFLAGS))),)
      quiet=silent_
    endif
else			# make-3.8x
    ifneq ($(filter s% -s%,$(MAKEFLAGS)),)
      quiet=silent_
    endif
endif

# 导出变量 quiet Q KBUILD_VERBOSE
export quiet Q KBUILD_VERBOSE

    设置编译结果输出目录

        

# kbuild supports saving output files in a separate directory.
# To locate output files in a separate directory two syntaxes are supported.
# In both cases the working directory must be the root of the kernel src.
# 1) O=
# Use "make O=dir/to/store/output/files/"
#
# 2) Set KBUILD_OUTPUT
# Set the environment variable KBUILD_OUTPUT to point to the directory
# where the output files shall be placed.
# export KBUILD_OUTPUT=dir/to/store/output/files/
# make
#
# The O= assignment takes precedence over the KBUILD_OUTPUT environment
# variable.

# KBUILD_SRC is set on invocation of make in OBJ directory
# KBUILD_SRC is not intended to be used by the regular user (for now)
ifeq ($(KBUILD_SRC),)

    # OK, Make called in directory where kernel src resides
    # Do we want to locate output files in a separate directory?
    # 判断“ O ”是否来自于命令行
    # 来自,条件成立
    ifeq ("$(origin O)", "command line")
      # KBUILD_OUTPUT:输出目录
      KBUILD_OUTPUT := $(O)
    endif

    # That's our default target when none is given on the command line
    PHONY := _all
    _all:

    # Cancel implicit rules on top Makefile
    $(CURDIR)/Makefile Makefile: ;

    # 判断 KBUILD_OUTPUT 是否为空
    ifneq ($(KBUILD_OUTPUT),)
        # Invoke a second make in the output directory, passing relevant variables
        # check that the output directory actually exists
        saved-output := $(KBUILD_OUTPUT)

        # mkdir :创建 KBUILD_OUTPUT 目录
        # 创建成功,绝对路径给 KBUILD_OUTPUT
        KBUILD_OUTPUT := $(shell mkdir -p $(KBUILD_OUTPUT) && cd $(KBUILD_OUTPUT) \
								&& /bin/pwd)
        $(if $(KBUILD_OUTPUT),, \
             $(error failed to create output directory "$(saved-output)"))

        PHONY += $(MAKECMDGOALS) sub-make

        $(filter-out _all sub-make $(CURDIR)/Makefile, $(MAKECMDGOALS)) _all: sub-make
        	@:

        sub-make: FORCE
        	$(Q)$(MAKE) -C $(KBUILD_OUTPUT) KBUILD_SRC=$(CURDIR) \
        	-f $(CURDIR)/Makefile $(filter-out _all sub-make,$(MAKECMDGOALS))

        # Leave processing to above invocation of make
        skip-makefile := 1
    endif # ifneq ($(KBUILD_OUTPUT),)
endif # ifeq ($(KBUILD_SRC),)

  代码检查

# Call a source code checker (by default, "sparse") as part of the
# C compilation.
#
# Use 'make C=1' to enable checking of only re-compiled files.
# Use 'make C=2' to enable checking of *all* source files, regardless
# of whether they are re-compiled or not.
#
# See the file "doc/sparse.txt" for more details, including
# where to get the "sparse" utility.

# 判断 C 是否来源于命令行
ifeq ("$(origin C)", "command line")
  KBUILD_CHECKSRC = $(C)
endif

# 命令行没有 C
ifndef KBUILD_CHECKSRC
  KBUILD_CHECKSRC = 0
endif

  模块编译

      uboot 允许单独编译某个模块

# Use make M=dir to specify directory of external module to build
# Old syntax make ... SUBDIRS=$PWD is still supported
# Setting the environment variable KBUILD_EXTMOD take precedence
# 判断是否定义SUBDIRS
ifdef SUBDIRS
  KBUILD_EXTMOD ?= $(SUBDIRS)
endif

# 判断命令行是否定义了 M
ifeq ("$(origin M)", "command line")
  KBUILD_EXTMOD := $(M)
endif

# If building an external module we do not care about the all: rule
# but instead _all depend on modules
PHONY += all

# KBUILD_EXTMOD为空
ifeq ($(KBUILD_EXTMOD),)
    # 目标_all 依赖 all
    _all: all

else
    # _all 依赖 modules
    # 先编译模块
    _all: modules
endif

#  KBUILD_SRC 为空
ifeq ($(KBUILD_SRC),)
    # building in the source tree
    # 设置变量 srctree 为当前目录
    srctree := .
else
    ifeq ($(KBUILD_SRC)/,$(dir $(CURDIR)))
          # building in a subdirectory of the source tree
          srctree := ..
    else
          srctree := $(KBUILD_SRC)
    endif
endif

# 设置变量 objtree 为当前目录
objtree		:= .

# 设置变量 obj为srctree的目录
src		:= $(srctree)

# 设置变量 obj 为当前目录
obj		:= $(objtree)

# 设置 VPATH
VPATH		:= $(srctree)$(if $(KBUILD_EXTMOD),:$(KBUILD_EXTMOD))

# 导出变量 scrtree objtree VPATH
export srctree objtree VPATH

获取主机架构和系统

# 变量 HOSTARCH:保存主机架构
# shell 命令“ uname -m “:获取架构名称
# | :管道
# sed -e :替换命令
HOSTARCH := $(shell uname -m | \
	sed -e s/i.86/x86/ \
	    -e s/sun4u/sparc64/ \
	    -e s/arm.*/arm/ \
	    -e s/sa110/arm/ \
	    -e s/ppc64/powerpc/ \
	    -e s/ppc/powerpc/ \
	    -e s/macppc/powerpc/\
	    -e s/sh.*/sh/)

# HOSTOS : 保存主机 OS 的值
# shell 命令“name -s”: 获取主机 OS
# “tr '[:upper:]' '[:lower:]'”: 将所有的大写字母替换为小写字母
# ” | “管道:将“ Linux ”作为“sed -e 's/\(cygwin\).*/cygwin/'”的输入
# sed -e:将cygwin.*替换为 cygwin
HOSTOS := $(shell uname -s | tr '[:upper:]' '[:lower:]' | \
	    sed -e 's/\(cygwin\).*/cygwin/')

# 导出 HOSTARCH=x86_64 HOSTOS=linux
export	HOSTARCH HOSTOS

 设置目标架构、交叉编译器和配置文件

# set default to nothing for native builds
# 设置目标板架构和 交叉编译器
# 判断 HOSTARCH 和 ARCH 是否相等
ifeq ($(HOSTARCH),$(ARCH))
  CROSS_COMPILE ?=
endif

# 可定义
#ARCH ?= arm
#CROSS_COMPILE ?= arm-linux-gnueabihf-

# .config:实时有效的配置
KCONFIG_CONFIG	?= .config
export KCONFIG_CONFIG

 调用 scripts/Kbuild.include

 

# We need some generic definitions (do not try to remake the file).
# 调用文件 scripts/Kbuild.include 
scripts/Kbuild.include: ;
include scripts/Kbuild.include

交叉编译工具变量设置

# Make variables (CC, etc...)

AS		= $(CROSS_COMPILE)as

# Always use GNU ld
ifneq ($(shell $(CROSS_COMPILE)ld.bfd -v 2> /dev/null),)
  LD		= $(CROSS_COMPILE)ld.bfd
else
  LD		= $(CROSS_COMPILE)ld
endif

CC		= $(CROSS_COMPILE)gcc
CPP		= $(CC) -E
AR		= $(CROSS_COMPILE)ar
NM		= $(CROSS_COMPILE)nm
LDR		= $(CROSS_COMPILE)ldr
STRIP		= $(CROSS_COMPILE)strip
OBJCOPY		= $(CROSS_COMPILE)objcopy
OBJDUMP		= $(CROSS_COMPILE)objdump

  导出其他变量

export VERSION PATCHLEVEL SUBLEVEL UBOOTRELEASE UBOOTVERSION
export ARCH CPU BOARD VENDOR SOC CPUDIR BOARDDIR
export CONFIG_SHELL HOSTCC HOSTCFLAGS HOSTLDFLAGS CROSS_COMPILE AS LD CC
export CPP AR NM LDR STRIP OBJCOPY OBJDUMP
export MAKE LEX YACC AWK PERL PYTHON PYTHON2 PYTHON3
export HOSTCXX HOSTCXXFLAGS CHECK CHECKFLAGS DTC DTC_FLAGS

export KBUILD_CPPFLAGS NOSTDINC_FLAGS UBOOTINCLUDE OBJCOPYFLAGS LDFLAGS
export KBUILD_CFLAGS KBUILD_AFLAGS


#mytext:
#    @echo 'ARCH='   $(ARCH)
#    @echo 'CPU='    $(CPU)
#    @echo 'BOARD='  $(BOARD)
#    @echo 'VENDOR=' $(VENDOR)
#    @echo 'SOC='    $(SOC)
#    @echo 'CPURIR'  $(CPUDIR)
#    @echo 'BOARDDIR'$(BOARDDIR)

   uboot 根目录下文件 config.mk

# SPDX-License-Identifier: GPL-2.0+
#
# (C) Copyright 2000-2013
# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
#########################################################################

# This file is included from ./Makefile and spl/Makefile.
# Clean the state to avoid the same flags added twice.
#
# (Tegra needs different flags for SPL.
#  That's the reason why this file must be included from spl/Makefile too.
#  If we did not have Tegra SoCs, build system would be much simpler...)
PLATFORM_RELFLAGS :=
PLATFORM_CPPFLAGS :=
PLATFORM_LDFLAGS :=
LDFLAGS :=
LDFLAGS_FINAL :=
LDFLAGS_STANDALONE :=
OBJCOPYFLAGS :=
# clear VENDOR for tcsh
VENDOR :=
#########################################################################

# 提取CONFIG_SYS_ARCH 里面双引号""内容
ARCH := $(CONFIG_SYS_ARCH:"%"=%)
CPU := $(CONFIG_SYS_CPU:"%"=%)
ifdef CONFIG_SPL_BUILD
    ifdef CONFIG_TEGRA
        CPU := arm720t
    endif
endif
BOARD := $(CONFIG_SYS_BOARD:"%"=%)
ifneq ($(CONFIG_SYS_VENDOR),)
    VENDOR := $(CONFIG_SYS_VENDOR:"%"=%)
endif
ifneq ($(CONFIG_SYS_SOC),)
    SOC := $(CONFIG_SYS_SOC:"%"=%)
endif

# Some architecture config.mk files need to know what CPUDIR is set to,
# so calculate CPUDIR before including ARCH/SOC/CPU config.mk files.
# Check if arch/$ARCH/cpu/$CPU exists, otherwise assume arch/$ARCH/cpu contains
# CPU-specific code.
CPUDIR=arch/$(ARCH)/cpu$(if $(CPU),/$(CPU),)

# 读取文件$(srctree)/arch/$(ARCH)/config.mk 的内容
sinclude $(srctree)/arch/$(ARCH)/config.mk	# include architecture dependend rules
sinclude $(srctree)/$(CPUDIR)/config.mk		# include  CPU	specific rules

ifdef	SOC
    sinclude $(srctree)/$(CPUDIR)/$(SOC)/config.mk	# include  SoC	specific rules
endif
ifneq ($(BOARD),)
    ifdef	VENDOR
        BOARDDIR = $(VENDOR)/$(BOARD)
    else
        BOARDDIR = $(BOARD)
    endif
endif

ifdef	BOARD
    sinclude $(srctree)/board/$(BOARDDIR)/config.mk	# include board specific rules
endif

ifdef FTRACE
    PLATFORM_CPPFLAGS += -finstrument-functions -DFTRACE
endif

#########################################################################

RELFLAGS := $(PLATFORM_RELFLAGS)

PLATFORM_CPPFLAGS += $(RELFLAGS)
PLATFORM_CPPFLAGS += -pipe

LDFLAGS += $(PLATFORM_LDFLAGS)
LDFLAGS_FINAL += -Bstatic

# uboot 根目录下的.config 文件
export PLATFORM_CPPFLAGS
export RELFLAGS
export LDFLAGS_FINAL
export LDFLAGS_STANDALONE
export CONFIG_STANDALONE_LOAD_ADDR

 

CONFIG_SYS_ARCH="arm"
CONFIG_SYS_CPU="armv7"
CONFIG_SYS_SOC="sunxi"
CONFIG_SYS_BOARD="sunxi"
CONFIG_SYS_CONFIG_NAME="sun7i"

 

# To make sure we do not include .config for any of the *config targets
# catch them early, and hand them over to scripts/kconfig/Makefile
# It is allowed to specify more targets when calling make, including
# mixing *config targets and build targets.
# For example 'make oldconfig all'.
# Detect when mixed targets is specified, and make a second invocation
# of make so .config is not included in this case either (for *config).

version_h := include/generated/version_autogenerated.h
timestamp_h := include/generated/timestamp_autogenerated.h
defaultenv_h := include/generated/defaultenv_autogenerated.h

no-dot-config-targets := clean clobber mrproper distclean \
			 help %docs check% coccicheck \
			 ubootversion backup tests check qcheck

config-targets := 0
mixed-targets  := 0
dot-config     := 1

ifneq ($(filter $(no-dot-config-targets), $(MAKECMDGOALS)),)
	ifeq ($(filter-out $(no-dot-config-targets), $(MAKECMDGOALS)),)
		dot-config := 0
	endif
endif

ifeq ($(KBUILD_EXTMOD),)
        ifneq ($(filter config %config,$(MAKECMDGOALS)),)
                config-targets := 1
                ifneq ($(words $(MAKECMDGOALS)),1)
                        mixed-targets := 1
                endif
        endif
endif

ifeq ($(mixed-targets),1)
# ===========================================================================
# We're called with mixed targets (*config and build targets).
# Handle them one by one.

PHONY += $(MAKECMDGOALS) __build_one_by_one

$(filter-out __build_one_by_one, $(MAKECMDGOALS)): __build_one_by_one
	@:

__build_one_by_one:
	$(Q)set -e; \
	for i in $(MAKECMDGOALS); do \
		$(MAKE) -f $(srctree)/Makefile $$i; \
	done

else
ifeq ($(config-targets),1)
# ===========================================================================
# *config targets only - make sure prerequisites are updated, and descend
# in scripts/kconfig to make the *config target

KBUILD_DEFCONFIG := sandbox_defconfig
export KBUILD_DEFCONFIG KBUILD_KCONFIG

config: scripts_basic outputmakefile FORCE
	$(Q)$(MAKE) $(build)=scripts/kconfig $@

%config: scripts_basic outputmakefile FORCE
	$(Q)$(MAKE) $(build)=scripts/kconfig $@

else
# ===========================================================================
# Build targets only - this includes vmlinux, arch specific targets, clean
# targets and others. In general all targets except *config targets.

# Additional helpers built in scripts/
# Carefully list dependencies so we do not try to build scripts twice
# in parallel
PHONY += scripts
scripts: scripts_basic include/config/auto.conf
	$(Q)$(MAKE) $(build)=$(@)

ifeq ($(dot-config),1)
# Read in config
-include include/config/auto.conf