最近在看关于嵌入式Linux关于Boot的一些资料,准备了一些资料。现在在这里将最近学习到的一些知识做个总结。
这次的总结主要关于Boot的一些参数解析与相应的启动流程总结。
使用了飞凌科技的IMXQ6的开发板2016.06的BOOT适配板搭配的源码进行分析。
因为Markdown插件对于&
符号判断的问题,我将代码中所有的&
替换成了¥
,修改回来即可。
makefile文件在现在是一个软件编译系统的核心,根据makefile可以了解当前的文件是否被包括在项目中,可以有效的排除相应的干扰项。
当前BOOT项目的makefile应该是autoconf进行生成的,所以文件中带有很多autoconf的痕迹,对一个大型项目来说,使用autoconf生成makefile是常见的。
飞凌科技的boot使用了脚本的方式进行编译,编译包括其公司各种产品的UBootImage,而我只需要一个需要的内核bin即可。
#!/bin/bash
make distclean //清除了相应的数据缓存
make mx6q-c-sabresd_defconfig //根据我的开发板进行编译数据配置
make -j5 //j5为5线程编译流程
cp u-boot.imx uboot-6q.tran //编译完成后的文件拷贝
这段代码就是相应的编译指令。而make mx6q-c-sabresd_defconfig
则是主要的make配置。
分析一个复杂软件的源代码可以直接使用其Makefile看出现在编译的文件,进而可以确定现在软件包括的源代码与数据。
打开makefile文件即可看到当前的数据标志:
# 版本相关
VERSION = 2016 //主要版本
PATCHLEVEL = 03 //次要版本
SUBLEVEL = //分支版本
EXTRAVERSION = //额外版本号
NAME = //开发代号
上述的数据主要是当前的版本号与版本的标志。主要版本号、次要版本号都是经常改变的。而分支版本号、开发代号主要是设备分支的版本代号,而额外版本号主要是当前的额外版本补丁号。一般只有在需要更新之后才会进行修改编译。
##############################正式编译###################################
#########################################################################
# 相应的数据定义,主要是选择当前需要的编译信息
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 := ¥(shell uname -s | tr '[:upper:]' '[:lower:]' | \
sed -e 's/\(cygwin\).*/cygwin/')
export HOSTARCH HOSTOS
跳过一般Makefile的一些常见递归编译代码与编译目录选择相关代码之后,可以看到这段代码。这段代码主要是定义当前的设备编译架构与设备系统类型。因为IMXQ6为ARM A9内核,所以当前选择的是arm架构与Linux.
随后就是大量的编译环境配置(因为这个makefile是由autoconf定制生成)。与相应的数据定义。
而选择编译的配置文件主要在makefile的编译之前:
# 正式编译脚本
# 选择编译配置脚本或者是手动编译配置
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.
# 单独编译
ifeq (¥(dot-config),1)
# Read in config
-include include/config/auto.conf
这样就可以进行选择,自动配置完成的脚本与单独配置。
相比Linux的配置繁琐,Uboot的配置较为简单。所以使用defconfig文件或者是手动配置方式都是可以的。但是如果是Linux内核编译则最好使用defconfig文件就可以完成,这样可以避免内核配置出现的不必要的错误。
下面就是包含config.mk
文件,这个文件包括了编译CPU相关的参数。
#
# (C) Copyright 2000-2013
# Wolfgang Denk, DENX Software Engineering, [email protected].
#
# SPDX-License-Identifier: GPL-2.0+
#
#########################################################################
# 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 :=
OBJCOPYFLAGS :=
# clear VENDOR for tcsh
VENDOR :=
#########################################################################
# 相应的编译属性
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.
# CPU配置
CPUDIR=arch/¥(ARCH)/cpu¥(if ¥(CPU),/¥(CPU),)
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
# Allow use of stdint.h if available
ifneq (¥(USE_STDINT),)
PLATFORM_CPPFLAGS += -DCONFIG_USE_STDINT
endif
#########################################################################
RELFLAGS := ¥(PLATFORM_RELFLAGS)
PLATFORM_CPPFLAGS += ¥(RELFLAGS)
PLATFORM_CPPFLAGS += -pipe
LDFLAGS += ¥(PLATFORM_LDFLAGS)
LDFLAGS_FINAL += -Bstatic
export PLATFORM_CPPFLAGS
export RELFLAGS
export LDFLAGS_FINAL
export CONFIG_STANDALONE_LOAD_ADDR
做完相应的配置后,就开始相应的编译,主要流程为:
# Read in dependencies to all Kconfig* files, make sure to run
# oldconfig if changes are detected.
# 配置相关的config.mk余项
-include include/config/auto.conf.cmd
# To avoid any implicit rule to kick in, define an empty command
¥(KCONFIG_CONFIG) include/config/auto.conf.cmd: ;
# 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 silentoldconfig
@# 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 include/autoconf.mk
-include include/autoconf.mk.dep
# We want to include arch/¥(ARCH)/config.mk only when include/config/auto.conf
# is up-to-date. When we switch to a different board configuration, old CONFIG
# macros are still remaining in include/config/auto.conf. Without the following
# gimmick, wrong config.mk would be included leading nasty warnings/errors.
ifneq (¥(wildcard ¥(KCONFIG_CONFIG)),)
ifneq (¥(wildcard include/config/auto.conf),)
autoconf_is_old := ¥(shell find . -path ./¥(KCONFIG_CONFIG) -newer \
include/config/auto.conf)
ifeq (¥(autoconf_is_old),)
# 当前配置需要重新生成
include config.mk
include arch/¥(ARCH)/Makefile
endif
endif
endif
# If board code explicitly specified LDSCRIPT or CONFIG_SYS_LDSCRIPT, use
# that (or fail if absent). Otherwise, search for a linker script in a
# standard location.
# 建立链接文件树
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
else
# 无需重新配置
# Dummy target needed, because used as prerequisite
include/config/auto.conf: ;
endif # ¥(dot-config)
# 根据相应的config.mk进行相应的标志位配置
ifdef CONFIG_CC_OPTIMIZE_FOR_SIZE
KBUILD_CFLAGS += -Os
else
KBUILD_CFLAGS += -O2
endif
KBUILD_CFLAGS += ¥(call cc-option,-fno-stack-protector)
KBUILD_CFLAGS += ¥(call cc-option,-fno-delete-null-pointer-checks)
KBUILD_CFLAGS += -g
# ¥(KBUILD_AFLAGS) sets -g, which causes gcc to pass a suitable -g
# option to the assembler.
KBUILD_AFLAGS += -g
# Report stack usage if supported
ifeq (¥(shell ¥(CONFIG_SHELL) ¥(srctree)/scripts/gcc-stack-usage.sh ¥(CC)),y)
KBUILD_CFLAGS += -fstack-usage
endif
KBUILD_CFLAGS += ¥(call cc-option,-Wno-format-nonliteral)
# turn jbsr into jsr for m68k
ifeq (¥(ARCH),m68k)
ifeq (¥(findstring 3.4,¥(shell ¥(CC) --version)),3.4)
KBUILD_AFLAGS += -Wa,-gstabs,-S
endif
endif
# Prohibit date/time macros, which would make the build non-deterministic
KBUILD_CFLAGS += ¥(call cc-option,-Werror=date-time)
include scripts/Makefile.extrawarn
# Add user supplied CPPFLAGS, AFLAGS and CFLAGS as the last assignments
KBUILD_CPPFLAGS += ¥(KCPPFLAGS)
KBUILD_AFLAGS += ¥(KAFLAGS)
KBUILD_CFLAGS += ¥(KCFLAGS)
# Use UBOOTINCLUDE when you must reference the include/ directory.
# Needed to be compatible with the O= option
# 包含相应的数据包与配置项
UBOOTINCLUDE := \
-Iinclude \
¥(if ¥(KBUILD_SRC), -I¥(srctree)/include) \
¥(if ¥(CONFIG_SYS_THUMB_BUILD), ¥(if ¥(CONFIG_HAS_THUMB2),, \
-I¥(srctree)/arch/¥(ARCH)/thumb1/include),) \
-I¥(srctree)/arch/¥(ARCH)/include \
-include ¥(srctree)/include/linux/kconfig.h
NOSTDINC_FLAGS += -nostdinc -isystem ¥(shell ¥(CC) -print-file-name=include)
CHECKFLAGS += ¥(NOSTDINC_FLAGS)
# FIX ME
cpp_flags := ¥(KBUILD_CPPFLAGS) ¥(PLATFORM_CPPFLAGS) ¥(UBOOTINCLUDE) \
¥(NOSTDINC_FLAGS)
c_flags := ¥(KBUILD_CFLAGS) ¥(cpp_flags)
#########################################################################
# U-Boot objects....order is important (i.e. start must be first)
# 包含各种库文件
HAVE_VENDOR_COMMON_LIB = ¥(if ¥(wildcard ¥(srctree)/board/¥(VENDOR)/common/Makefile),y,n)
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 += 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-¥(CONFIG_FMAN_ENET) += drivers/net/fm/
libs-¥(CONFIG_SYS_FSL_DDR) += drivers/ddr/fsl/
libs-¥(CONFIG_ALTERA_SDRAM) += drivers/ddr/altera/
libs-y += drivers/serial/
libs-y += drivers/usb/dwc3/
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-¥(CONFIG_API) += api/
libs-¥(CONFIG_HAS_POST) += post/
libs-y += test/
libs-y += test/dm/
libs-¥(CONFIG_UT_ENV) += test/env/
libs-y += ¥(if ¥(BOARDDIR),board/¥(BOARDDIR)/)
libs-y := ¥(sort ¥(libs-y))
u-boot-dirs := ¥(patsubst %/,%,¥(filter %/, ¥(libs-y))) tools examples
u-boot-alldirs := ¥(sort ¥(u-boot-dirs) ¥(patsubst %/,%,¥(filter %/, ¥(libs-))))
libs-y := ¥(patsubst %/, %/built-in.o, ¥(libs-y))
u-boot-init := ¥(head-y)
u-boot-main := ¥(libs-y)
# Add GCC lib
ifeq (¥(CONFIG_USE_PRIVATE_LIBGCC),y)
PLATFORM_LIBGCC = arch/¥(ARCH)/lib/lib.a
else
PLATFORM_LIBGCC := -L ¥(shell dirname `¥(CC) ¥(c_flags) -print-libgcc-file-name`) -lgcc
endif
PLATFORM_LIBS += ¥(PLATFORM_LIBGCC)
export PLATFORM_LIBS
export PLATFORM_LIBGCC
# Special flags for CPP when processing the linker script.
# Pass the version down so we can handle backwards compatibility
# on the fly.
LDPPFLAGS += \
-include ¥(srctree)/include/u-boot/u-boot.lds.h \
-DCPUDIR=¥(CPUDIR) \
¥(shell ¥(LD) --version | \
sed -ne 's/GNU ld version \([0-9][0-9]*\)\.\([0-9][0-9]*\).*/-DLD_MAJOR=\1 -DLD_MINOR=\2/p')
# 准备编译项
ifneq (¥(CONFIG_BOARD_SIZE_LIMIT),)
BOARD_SIZE_CHECK = \
@actual=`wc -c ¥@ | awk '{print ¥¥1}'`; \
limit=`printf "%d" ¥(CONFIG_BOARD_SIZE_LIMIT)`; \
if test ¥¥actual -gt ¥¥limit; then \
echo "¥@ exceeds file size limit:" >&2 ; \
echo " limit: ¥¥limit bytes" >&2 ; \
echo " actual: ¥¥actual bytes" >&2 ; \
echo " excess: ¥¥((actual - limit)) bytes" >&2; \
exit 1; \
fi
else
BOARD_SIZE_CHECK =
endif
# Statically apply RELA-style relocations (currently arm64 only)
ifneq (¥(CONFIG_STATIC_RELA),)
# ¥(1) is u-boot ELF, ¥(2) is u-boot bin, ¥(3) is text base
DO_STATIC_RELA = \
start=¥¥(¥(NM) ¥(1) | grep __rel_dyn_start | cut -f 1 -d ' '); \
end=¥¥(¥(NM) ¥(1) | grep __rel_dyn_end | cut -f 1 -d ' '); \
tools/relocate-rela ¥(2) ¥(3) ¥¥start ¥¥end
else
DO_STATIC_RELA =
endif
# 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
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
LDFLAGS_u-boot += ¥(LDFLAGS_FINAL)
ifneq (¥(CONFIG_SYS_TEXT_BASE),)
LDFLAGS_u-boot += -Ttext ¥(CONFIG_SYS_TEXT_BASE)
endif
# Normally we fill empty space with 0xff
quiet_cmd_objcopy = OBJCOPY ¥@
cmd_objcopy = ¥(OBJCOPY) --gap-fill=0xff ¥(OBJCOPYFLAGS) \
¥(OBJCOPYFLAGS_¥(@F)) ¥< ¥@
# Provide a version which does not do this, for use by EFI
quiet_cmd_zobjcopy = OBJCOPY ¥@
cmd_zobjcopy = ¥(OBJCOPY) ¥(OBJCOPYFLAGS) ¥(OBJCOPYFLAGS_¥(@F)) ¥< ¥@
quiet_cmd_efipayload = OBJCOPY ¥@
cmd_efipayload = ¥(OBJCOPY) -I binary -O ¥(EFIPAYLOAD_BFDTARGET) -B ¥(EFIPAYLOAD_BFDARCH) ¥< ¥@
quiet_cmd_mkimage = MKIMAGE ¥@
cmd_mkimage = ¥(objtree)/tools/mkimage ¥(MKIMAGEFLAGS_¥(@F)) -d ¥< ¥@ \
¥(if ¥(KBUILD_VERBOSE:1=), >/dev/null)
quiet_cmd_cat = CAT ¥@
cmd_cat = cat ¥(filter-out ¥(PHONY), ¥^) > ¥@
append = cat ¥(filter-out ¥< ¥(PHONY), ¥^) >> ¥@
quiet_cmd_pad_cat = CAT ¥@
cmd_pad_cat = ¥(cmd_objcopy) && ¥(append) || rm -f ¥@
# 开始正式编译
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
# 实际的编译项
PHONY += dtbs
dtbs dts/dt.dtb: checkdtc u-boot
¥(Q)¥(MAKE) ¥(build)=dts dtbs
quiet_cmd_copy = COPY ¥@
cmd_copy = cp ¥< ¥@
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
%.imx: %.bin
¥(Q)¥(MAKE) ¥(build)=arch/arm/imx-common ¥@
u-boot.dtb: dts/dt.dtb
¥(call cmd,copy)
OBJCOPYFLAGS_u-boot.hex := -O ihex
OBJCOPYFLAGS_u-boot.srec := -O srec
u-boot.hex u-boot.srec: u-boot FORCE
¥(call if_changed,objcopy)
OBJCOPYFLAGS_u-boot-nodtb.bin := -O binary \
¥(if ¥(CONFIG_X86_RESET_VECTOR),-R .start16 -R .resetvec)
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
u-boot-nodtb.bin: u-boot FORCE
¥(call if_changed,objcopy)
¥(call DO_STATIC_RELA,¥<,¥@,¥(CONFIG_SYS_TEXT_BASE))
¥(BOARD_SIZE_CHECK)
u-boot.ldr: u-boot
¥(CREATE_LDR_ENV)
¥(LDR) -T ¥(CONFIG_CPU) -c ¥@ ¥< ¥(LDR_FLAGS)
¥(BOARD_SIZE_CHECK)
OBJCOPYFLAGS_u-boot.ldr.hex := -I binary -O ihex
OBJCOPYFLAGS_u-boot.ldr.srec := -I binary -O srec
u-boot.ldr.hex u-boot.ldr.srec: u-boot.ldr FORCE
¥(call if_changed,objcopy)
# ………………………………………………………………………………………………………………………………………………………………
# 大抵都是差不多的编译项和链接项,以及一些clean相关的项目
# 编译完成
%PROJRCT%.imx
,%PROJRCT%
为自定义项。根据当前的配置项,可以发现当前的配置项主要是在board\freescale\mx6sabresd
文件夹下,当前文件夹下的数据为当前CPU适配代码,而arch/arm/imx-common
文件夹下主要是当前的开发板的配置。
相应的main函数与进入boot的函数都在这几个文件下。
启动时,指针会在数据0x00000000下读取指令进行运行:
init_fnc_t init_sequence_r[] = {
initr_trace,
initr_reloc,
/* TODO: could x86/PPC have this also perhaps? */
#ifdef CONFIG_ARM
initr_caches,
/* Note: For Freescale LS2 SoCs, new MMU table is created in DDR.
* A temporary mapping of IFC high region is since removed,
* so environmental variables in NOR flash is not availble
* until board_init() is called below to remap IFC to high
* region.
*/
#endif
initr_reloc_global_data,
#if defined(CONFIG_SYS_INIT_RAM_LOCK) && defined(CONFIG_E500)
initr_unlock_ram_in_cache,
#endif
initr_barrier,
initr_malloc,
initr_console_record,
#ifdef CONFIG_SYS_NONCACHED_MEMORY
initr_noncached,
#endif
bootstage_relocate,
#ifdef CONFIG_DM
initr_dm,
#endif
initr_bootstage,
#if defined(CONFIG_ARM) || defined(CONFIG_NDS32)
board_init, /* Setup chipselects */
#endif
/*
* TODO: printing of the clock inforamtion of the board is now
* implemented as part of bdinfo command. Currently only support for
* davinci SOC's is added. Remove this check once all the board
* implement this.
*/
#ifdef CONFIG_CLOCKS
set_cpu_clk_info, /* Setup clock information */
#endif
stdio_init_tables,
initr_serial,
initr_announce,
INIT_FUNC_WATCHDOG_RESET
#ifdef CONFIG_NEEDS_MANUAL_RELOC
initr_manual_reloc_cmdtable,
#endif
#if defined(CONFIG_PPC) || defined(CONFIG_M68K)
initr_trap,
#endif
#ifdef CONFIG_ADDR_MAP
initr_addr_map,
#endif
#if defined(CONFIG_BOARD_EARLY_INIT_R)
board_early_init_r,
#endif
INIT_FUNC_WATCHDOG_RESET
#ifdef CONFIG_LOGBUFFER
initr_logbuffer,
#endif
#ifdef CONFIG_POST
initr_post_backlog,
#endif
INIT_FUNC_WATCHDOG_RESET
#ifdef CONFIG_SYS_DELAYED_ICACHE
initr_icache_enable,
#endif
#if defined(CONFIG_PCI) && defined(CONFIG_SYS_EARLY_PCI_INIT)
/*
* Do early PCI configuration _before_ the flash gets initialised,
* because PCU ressources are crucial for flash access on some boards.
*/
initr_pci,
#endif
#ifdef CONFIG_WINBOND_83C553
initr_w83c553f,
#endif
#ifdef CONFIG_ARCH_EARLY_INIT_R
arch_early_init_r,
#endif
power_init_board,
#ifndef CONFIG_SYS_NO_FLASH
initr_flash,
#endif
INIT_FUNC_WATCHDOG_RESET
#if defined(CONFIG_PPC) || defined(CONFIG_M68K) || defined(CONFIG_X86) || \
defined(CONFIG_SPARC)
/* initialize higher level parts of CPU like time base and timers */
cpu_init_r,
#endif
#ifdef CONFIG_PPC
initr_spi,
#endif
#ifdef CONFIG_CMD_NAND
initr_nand,
#endif
#ifdef CONFIG_CMD_ONENAND
initr_onenand,
#endif
#ifdef CONFIG_GENERIC_MMC
initr_mmc,
#endif
#ifdef CONFIG_HAS_DATAFLASH
initr_dataflash,
#endif
initr_env,
#ifdef CONFIG_SYS_BOOTPARAMS_LEN
initr_malloc_bootparams,
#endif
INIT_FUNC_WATCHDOG_RESET
initr_secondary_cpu,
#if defined(CONFIG_ID_EEPROM) || defined(CONFIG_SYS_I2C_MAC_OFFSET)
mac_read_from_eeprom,
#endif
INIT_FUNC_WATCHDOG_RESET
#if defined(CONFIG_PCI) && !defined(CONFIG_SYS_EARLY_PCI_INIT)
/*
* Do pci configuration
*/
initr_pci,
#endif
stdio_add_devices,
initr_jumptable,
#ifdef CONFIG_API
initr_api,
#endif
console_init_r, /* fully init console as a device */
#ifdef CONFIG_DISPLAY_BOARDINFO_LATE
show_board_info,
#endif
#ifdef CONFIG_ARCH_MISC_INIT
arch_misc_init, /* miscellaneous arch-dependent init */
#endif
#ifdef CONFIG_MISC_INIT_R
misc_init_r, /* miscellaneous platform-dependent init */
#endif
INIT_FUNC_WATCHDOG_RESET
#ifdef CONFIG_CMD_KGDB
initr_kgdb,
#endif
interrupt_init,
#if defined(CONFIG_ARM) || defined(CONFIG_AVR32)
initr_enable_interrupts,
#endif
#if defined(CONFIG_MICROBLAZE) || defined(CONFIG_AVR32) || defined(CONFIG_M68K)
timer_init, /* initialize timer */
#endif
#if defined(CONFIG_STATUS_LED)
initr_status_led,
#endif
/* PPC has a udelay(20) here dating from 2002. Why? */
#ifdef CONFIG_CMD_NET
initr_ethaddr,
#endif
#ifdef CONFIG_BOARD_LATE_INIT
board_late_init,
#endif
#ifdef CONFIG_FSL_FASTBOOT
initr_fastboot_setup,
#endif
#if defined(CONFIG_CMD_AMBAPP)
ambapp_init_reloc,
#if defined(CONFIG_SYS_AMBAPP_PRINT_ON_STARTUP)
initr_ambapp_print,
#endif
#endif
#ifdef CONFIG_CMD_SCSI
INIT_FUNC_WATCHDOG_RESET
initr_scsi,
#endif
#ifdef CONFIG_CMD_DOC
INIT_FUNC_WATCHDOG_RESET
initr_doc,
#endif
#ifdef CONFIG_BITBANGMII
initr_bbmii,
#endif
#ifdef CONFIG_CMD_NET
INIT_FUNC_WATCHDOG_RESET
initr_net,
#endif
#ifdef CONFIG_POST
initr_post,
#endif
#if defined(CONFIG_CMD_PCMCIA) && !defined(CONFIG_CMD_IDE)
initr_pcmcia,
#endif
#if defined(CONFIG_CMD_IDE)
initr_ide,
#endif
#ifdef CONFIG_LAST_STAGE_INIT
INIT_FUNC_WATCHDOG_RESET
/*
* Some parts can be only initialized if all others (like
* Interrupts) are up and running (i.e. the PC-style ISA
* keyboard).
*/
last_stage_init,
#endif
#ifdef CONFIG_CMD_BEDBUG
INIT_FUNC_WATCHDOG_RESET
initr_bedbug,
#endif
#if defined(CONFIG_PRAM) || defined(CONFIG_LOGBUFFER)
initr_mem,
#endif
#ifdef CONFIG_PS2KBD
initr_kbd,
#endif
#if defined(CONFIG_SPARC)
prom_init,
#endif
#ifdef CONFIG_FSL_FASTBOOT
initr_check_fastboot,
#endif
/* 初始化完成 */
run_main_loop,
}
随后在进行了硬件初始化完成之后,运行了run_main_loop(),这个函数主要作用为进入main_loop()。
/* We come here after U-Boot is initialised and ready to process commands */
void main_loop(void)
{
const char *s;
bootstage_mark_name(BOOTSTAGE_ID_MAIN_LOOP, "main_loop");
#ifndef CONFIG_SYS_GENERIC_BOARD
puts("Warning: Your board does not use generic board. Please read\n");
puts("doc/README.generic-board and take action. Boards not\n");
puts("upgraded by the late 2014 may break or be removed.\n");
#endif
#ifdef CONFIG_VERSION_VARIABLE
setenv("ver", version_string); /* set version variable */
#endif /* CONFIG_VERSION_VARIABLE */
cli_init();
run_preboot_environment_command();
#if defined(CONFIG_UPDATE_TFTP)
update_tftp(0UL, NULL, NULL);
#endif /* CONFIG_UPDATE_TFTP */
/* BOOT等待一定时间,未出现键盘输入则自动跳走 */
s = bootdelay_process();
if (cli_process_fdt(&s))
cli_secure_boot_cmd(s);
autoboot_command(s);
run_command("scr_menu", 0);
cli_loop();
}
而如果这一段时间之后没有出现键盘输入则会跳入下方的程序,进入正式的Linux内核,而将当前的控制权交予Linux内核。
跳转函数为hang()
(不知道为啥叫了这么个奇奇怪怪的名字),是一个跳转指令,可以将CPU指令跳转进入Linux内核部分,随后进入了Linux自己的内核。
在之前,BOOT会清除Cache相应的数据,并且将相应的TAG数据存入内存中,并且修改了相应的中断相关入口。这些关键的数据都会在Linux进行使用。
因为当前BOOT的内核相应的代码,实在是太多了,分析起来不是很容易。所以还有很多没有分析到的逻辑,这个会在之后的文章上补全。
启动流程主要分为四步:
上电进入。
硬件初始化。
启动前数据清除与跳转后数据交互。
跳转到指定位置,并移交CPU控制权。
本文首发自 学:关于嵌入式Linux内核Boot的启动流程的总结(一)-我的博客,更多文章可进入我的博客详查。