讯为4412开发板嵌入式学习(十一)Makefile代码分析

文章目录

    • 五、Makefile源码分析
      • (一)、删除不相关数据
      • (二)、Makefile中mkconfig部分
        • 1、@$(MKCONFIG)的意思
        • 2、$(@:_config=)的意思
      • (三)、mkconfig详解
        • line 1
        • line 3~9
        • line 11~13
        • line 15~28
        • line 30~38
        • line 40~50
        • line 52~71
        • line 73~84
        • line 86~102
        • line 106~121
        • line 124~137
        • line 139~150
      • (四)、Makefile源码分析
        • line 1~22
        • line 23~34
        • line 36~43
        • line 58~64
        • line 66~95
        • line 97~117
        • line 119~138
        • line 140~151
        • line 153~196
        • line 198~215
        • line 217~299
        • line 301~321
        • line 323~396
          • 1、u-boot.lds分析
          • 2、start.S分析
            • line 53~56
            • line 57~86
            • line 184~198
            • line 200~227
            • line 230~237
            • line 240~287
            • line 293
            • line 296~298
            • line 301~304
            • line 313~322
            • line 326~338
            • line 359~380
            • line 418~433
            • line 441~509
    • 六、杂项
      • (一)、操作系统分层概念
      • (二)、bootloader种类
      • (三)、NandFlash纠错ECC算法
      • (四)、tf卡烧写和fastboot烧写的指令文件
      • (五)、vim查看二进制文件
      • (六)删除除某文件之外的所有文件
      • (七)、vim删除指定行
      • (八)、vim撤销和重做
      • (九)、zsh找不到匹配项

上上篇:讯为4412开发板嵌入式学习(九)uboot启动过程
上一篇:讯为4412开发板嵌入式学习(十)uboot源代码结构

五、Makefile源码分析

(一)、删除不相关数据

4412的主板为arm架构,cortex-A9内核。假如指令为itop_4412_android_config_scp_1GDDR,我们分析Makefile文件。

首先删除不相关的架构配置和信息。

删除行数范围为3264~3810的数据

讯为4412开发板嵌入式学习(十一)Makefile代码分析_第1张图片

讯为4412开发板嵌入式学习(十一)Makefile代码分析_第2张图片

删除行数范围为530~3201的数据

讯为4412开发板嵌入式学习(十一)Makefile代码分析_第3张图片
讯为4412开发板嵌入式学习(十一)Makefile代码分析_第4张图片

(二)、Makefile中mkconfig部分

由于makefile之前都需要先进行配置,所以先讲配置部分的代码。

下面分析Makefile中配置(mkconfig)部分。

itop_4412_android_config_scp_1GDDR:             unconfig
        @$(MKCONFIG) $(@:_config=) arm arm_cortexa9 smdkc210 samsung s5pc210 SCP_1GDDR

1、@$(MKCONFIG)的意思

MKCONFIG := $(SRCTREE)/mkconfig
SRCTREE := $(CURDIR)
CURDIR是make的内嵌变量,代表的是当前目录./

所以 @$(MKCONFIG) 代表的是 ./mkconfig@ 表示不输出该命令行。

2、$(@:_config=)的意思

这是Makefile中常用的字符串处理方式,$(@)的意思是目标文件集,而输入的文件集就是itop_4412_android_config_scp_1GDDR,后面的 :_config= 指的是用目标的字符串 _config 之前的字符串代替它,并且后面的 = 意思是省略其后面的字段。

所以 $(@:_config=) 代表的是 itop_4412_android

综上所述,整句话的意思如下:
./mkconfig itop_4412_android arm arm_cortexa9 smdkc210 samsung s5pc210 SCP_1GDDR

(三)、mkconfig详解

由上述可知,传入mkconfig的完整参数表如下:

$0 $1 $2 $3 $4 $5 $6 $7
mkconfig itop_4412_android arm arm_cortexa9 smdkc210 samsung s5pc210 SCP_1GDDR

line 1

#!/bin/sh -e
#指定解释器路径,同时`-e`表示的是程序会自动根据指令返回值$?是否为零判断是否执行正确指令,非零则自动退出脚本。

line 3~9

# Script to create header files and links to configure  文件的说明,意思是该脚本的作用是创建要配置的头文件和链接。
# U-Boot for a specific board.      为特定板子服务的U-boot。
#
# Parameters:  Target  Architecture  CPU  Board [VENDOR] [SOC] 输入参数为Target(目标)  Architecture(架构)  CPU  Board(开发板) \[VENDOR\](供应商) \[SOC\](片上系统)
#
# (C) 2002-2006 DENX Software Engineering, Wolfgang Denk  代码编写/维护者
#

line 11~13

APPEND=no	# Default: Create new config file 默认创建一个新的配置文件
#BOARD_NAME=""	# Name to print in make output make要输出的名字
TARGETS="" #目标名

line 15~28

echo "CoreBoard  is $7...... " #根据输入参数$7输出核心板信息(此处$7是SCP_1GDDR)
# 根据$7选择板子名并输出核心板运行的OS信息
if   [ "$7" = "SCP_1GDDR" ]  ||   [ "$7" = "SCP_2GDDR" ] || [ "$7" = "POP_1GDDR" ]  ||   [ "$7" = "POP_2GDDR" ]
then 
      BOARD_NAME="itop_4412_android"
      echo "CoreBoard OS is android or linux...... "

elif [ "$7" = "SCP_1GDDR_Ubuntu" ]  ||  [ "$7" = "SCP_2GDDR_Ubuntu" ] || [ "$7" = "POP_1GDDR_Ubuntu" ] ||  [ "$7" = "POP_2GDDR_Ubuntu" ]
then
      BOARD_NAME="itop_4412_ubuntu"
      echo "CoreBoard OS is Ubuntu...... "
else
      echo "unknown coreboard type and os type......"
fi

line 30~38

#传给脚本的参数数量(不算上$0)大于0则进入while循环
while [ $# -gt 0 ] ; do
#判断参数$1是否为 -- -a -t 或是其他输入并执行相应动作。
	case "$1" in
	--) shift ; break ;;
	-a) shift ; APPEND=yes ;;
#	-n) shift ; BOARD_NAME="${1%%_config}" ; shift ;;
    #获取参数$1 字符'_'替换为空格并将结果赋值给TARGETS
	-t) shift ; TARGETS="`echo $1 | sed 's:_: :g'` ${TARGETS}" ; shift ;;
	*)  break ;;
	esac
done

line 40~50

#判断参数BOARD_NAME是否为空,为空的话则将输入参数$1赋值给BOARD_NAME。(使用逻辑或的短路特性)
[ "${BOARD_NAME}" ] || BOARD_NAME="$1"
#如果输入参数数量小于4或大于7则退出脚本,即输入参数数量要 4<=$#<=7
[ $# -lt 4 ] && exit 1
[ $# -gt 7 ] && exit 1
#判断是否为ARM架构
if [ "${ARCH}" -a "${ARCH}" != "$2" ]; then
    #不是则输出错误信息,并将标准输出至通道2
	echo "Failed: \$ARCH=${ARCH}, should be '$2' for ${BOARD_NAME}" 1>&2
    #退出脚本
	exit 1
fi
#输出板子开始配置的信息
echo "Configuring for ${BOARD_NAME} board..."

line 52~71

#
# Create link to architecture specific headers 创建架构特定的头文件链接
#
#在Makefile中有以下两句定义
#如果$BUILD_DIR不为空的话,则将$BUILD_DIR赋值给$OBJTREE,否则将$CURDIR赋值给$OBJTREE
#OBJTREE		:= $(if $(BUILD_DIR),$(BUILD_DIR),$(CURDIR)) 
#SRCTREE		:= $(CURDIR) #当前目录
#
if [ "$SRCTREE" != "$OBJTREE" ] ; then
#OBJTREE不是当前目录路径,则新建文件夹,将asm-arm和asm链接起来
	mkdir -p ${OBJTREE}/include
	mkdir -p ${OBJTREE}/include2
	cd ${OBJTREE}/include2
	rm -f asm
	ln -s ${SRCTREE}/include/asm-$2 asm
	LNPREFIX="../../include2/asm/"
	cd ../include
	rm -rf asm-$2
	rm -f asm
	mkdir asm-$2
	ln -s asm-$2 asm
else
#OBJTREE是当前目录路径,直接将asm-arm和asm链接起来,成立
	cd ./include
	rm -f asm
    #等价于	ln -s asm-arm asm
	ln -s asm-$2 asm
fi

直接将asm->asm-arm链接起来便于不同平台的移植。在代码内部直接使用#include即可。

在这里插入图片描述

line 73~84

rm -f asm-$2/arch # 删除与架构相关的目录asm-arm/arch
#判断$6(s5pc210)是否为0或者是否为空
if [ -z "$6" -o "$6" = "NULL" ] ; then
#成立则将arch-arm_cortexa9和asm-arm/arch链接起来(${LNPREFIX}未定义,为空)
	ln -s ${LNPREFIX}arch-$3 asm-$2/arch
else
#否则将arch-s5pc210和asm-arm/arch链接起来,成立
	ln -s ${LNPREFIX}arch-$6 asm-$2/arch
fi

#判断参数$2是否等于arm
if [ "$2" = "arm" ] ; then
#删除原先的asm-arm/proc,将proc-armv和asm-arm/proc链接起来,成立
	rm -f asm-$2/proc
	ln -s ${LNPREFIX}proc-armv asm-$2/proc
fi

此处将arch-s5pc210和asm-arm/arch链接起来了。

在这里插入图片描述

此处将proc-armv和asm-arm/proc链接起来了。

在这里插入图片描述

line 86~102

#
# Create include file for Make 为make创建包含文件
#
#将这三个参数打印到config.mk文件 "ARCH=arm" "CPU=arm_cortexa9" "BOARD=smdkc210"
echo "ARCH   = $2" >  config.mk #一个'>'表示新建一个config.mk并把数据添加进去
echo "CPU    = $3" >> config.mk #两个'>'表示在后面追加数据
echo "BOARD  = $4" >> config.mk
#参数$5存在且不等于NULL,然后在config.mk后追加"VENDOR=samsung" 
[ "$5" ] && [ "$5" != "NULL" ] && echo "VENDOR = $5" >> config.mk
#参数$6存在且不等于NULL,然后在config.mk后追加"SOC=s5pc210"
[ "$6" ] && [ "$6" != "NULL" ] && echo "SOC    = $6" >> config.mk

# Assign board directory to BOARDIR variable 为BOARDIR变量分配板子相关信息的目录
#判断参数$5(samsung)是否等于0且为空
if [ -z "$5" -o "$5" = "NULL" ] ; then
#BOARDDIR设置为smdkc210
    BOARDDIR=$4
else
#BOARDDIR设置为samsung/smdkc210,成立
    BOARDDIR=$5/$4
fi

讯为4412开发板嵌入式学习(十一)Makefile代码分析_第5张图片

line 106~121

#add by dg for kinds of coreboard 添加各种核心板
#判断参数$7(SCP_1GDDR)是否为几种SCP_系列的核心板,成立
if   [ "$7" = "SCP_1GDDR" ] ||   [ "$7" = "SCP_2GDDR" ] || [ "$7" = "SCP_1GDDR_Ubuntu" ] ||   [ "$7" = "SCP_2GDDR_Ubuntu" ]
then 
    # 在文件config.mk后追加"CORE   =  SCP"
     echo "CORE   =  SCP" >> config.mk
     #将板子和CPU相关的启动文件链接起来
     ln -sf ${SRCTREE}/board/samsung/smdkc210/lowlevel_init_SCP.S  ${SRCTREE}/board/samsung/smdkc210/lowlevel_init.S	
     ln -sf ${SRCTREE}/cpu/arm_cortexa9/s5pc210/cpu_init_SCP.S     ${SRCTREE}/cpu/arm_cortexa9/s5pc210/cpu_init.S
#同理可得
elif [ "$7" = "POP_1GDDR" ]  ||  [ "$7" = "POP_2GDDR" ] || [ "$7" = "POP_1GDDR_Ubuntu" ] ||  [ "$7" = "POP_2GDDR_Ubuntu" ]
then
     echo "CORE   =  POP" >>  config.mk
     ln -sf ${SRCTREE}/board/samsung/smdkc210/lowlevel_init_POP.S  ${SRCTREE}/board/samsung/smdkc210/lowlevel_init.S	
     ln -sf ${SRCTREE}/cpu/arm_cortexa9/s5pc210/cpu_init_POP.S     ${SRCTREE}/cpu/arm_cortexa9/s5pc210/cpu_init.S
else
      echo "make config error,please use correct params......"
      exit 0
fi

在这里插入图片描述

line 124~137

#
# Create board specific header file 创建板子特定的头文件
#
#如果参数$APPEND为yes则往现有的config.h文件追加信息
if [ "$APPEND" = "yes" ]	# Append to existing config file
then
	echo >> config.h
else
	> config.h		# Create new config file 否则创建新的config头文件,成立
fi
#往config.h后追加信息
echo "/* Automatically generated - do not edit */" >>config.h
#依次将参数$TARGETS内的参数和#define CONFIG_MK_${i} 1整合起来追加到config.h后面,此处$TARGETS为空,不执行
for i in ${TARGETS} ; do
	echo "#define CONFIG_MK_${i} 1" >>config.h ;
done

line 139~150

#add by dg for all itop4412 type boards 添加应用于全部itop4412类型板子的信息
#判断参数$7(SCP_1GDDR)是否存在且不为空,成立则并将相关信息追加到config.h
[ "$7" ] && [ "$7" != "NULL" ] && echo "#define CONFIG_$7" >> config.h

#将下面EOF前面的数据追加到文件config.h
cat << EOF >> config.h
#define CONFIG_BOARDDIR board/$BOARDDIR
#include 
#include 
#include 
EOF

exit 0

查看config.h的内部信息

讯为4412开发板嵌入式学习(十一)Makefile代码分析_第6张图片

综上所述,Makefile配置文件mkconfig主要实现的作用有:

  • 创建和平台相关的链接文件
  • 创建config.mk
  • 创建config.h

(四)、Makefile源码分析

line 1~22

有关贡献人员和代码分享相关的GNU通用公共许可证(GNU General Public Licence)的说明。

line 23~34

VERSION = 2010
PATCHLEVEL = 03
SUBLEVEL =
EXTRAVERSION =
ifneq "$(SUBLEVEL)" ""
U_BOOT_VERSION = $(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
else
U_BOOT_VERSION = $(VERSION).$(PATCHLEVEL)$(EXTRAVERSION)
endif
TIMESTAMP_FILE = $(obj)include/timestamp_autogenerated.h
VERSION_FILE = $(obj)include/version_autogenerated.h

版本相关的信息。

line 36~43

#获取主机平台
HOSTARCH := $(shell uname -m | \  
	sed -e s/i.86/i386/ \
	    -e s/sun4u/sparc64/ \
	    -e s/arm.*/arm/ \
	    -e s/sa110/arm/ \
	    -e s/powerpc/ppc/ \
	    -e s/ppc64/ppc/ \
	    -e s/macppc/ppc/)
        
#获取主机操作系统
HOSTOS := $(shell uname -s | tr '[:upper:]' '[:lower:]' | \
	    sed -e 's/\(cygwin\).*/cygwin/')

# Set shell to bash if possible, otherwise fall back to sh 可能的话将shell设置为bash,否则回退到sh

#获取shell路径
SHELL := $(shell if [ -x "$$BASH" ]; then echo $$BASH; \
	else if [ -x /bin/bash ]; then echo /bin/bash; \
	else echo sh; fi; fi)
    
#设置环境变量
export	HOSTARCH HOSTOS SHELL

# Deal with colliding definitions from tcsh etc. 定义一个变量用于处理tcsh等的冲突定义。
VENDOR=

获取主机平台(ubuntu中执行uname -m即可,但这里是为了尽可能匹配所有设备)。

讯为4412开发板嵌入式学习(十一)Makefile代码分析_第7张图片

获取主机操作系统(ubuntu中执行uname -s即可)。

在这里插入图片描述

获取shell路径。

在这里插入图片描述

综上有如下结果:

HOSTARCH = x86_64
HOSTOS = Linux
SHELL = /bin/bash
VENDOR=

line 58~64

#########################################################################
# Allow for silent builds 允许在编译的时候不输出信息
#在变量MAKEFLAGS中查找是否存在s字符串,查找到则返回s,否则返回NULL。然后判断NULL和结果是否相同,从而通过变量XECHO决定是否输出编译信息。
ifeq (,$(findstring s,$(MAKEFLAGS)))
XECHO = echo
else
XECHO = :
endif

line 66~95

在编译的时候可使用命令行输入参数(在命令行使用make O=),从而设置BUILD_DIR的路径。

ifdef O
ifeq ("$(origin O)", "command line")
BUILD_DIR := $(O)
endif
endif

#如果BUILD_DIR不为空,则将saved-output设置为BUILD_DIR
ifneq ($(BUILD_DIR),)
saved-output := $(BUILD_DIR)

具体操作可参考$(origin variable)详解

line 97~117

# Attempt to create a output directory.尝试创建一个新的输出文件夹
#-d(directory)判断路径BUILD_DIR是否为文件夹,是则返回0并退出,否则在目录下递归创建新的文件夹。这里利用到||的短路特性
$(shell [ -d ${BUILD_DIR} ] || mkdir -p ${BUILD_DIR})

# Verify if it was successful. 验证是否正确
# 如果BUILD_DIR用的是相对路径,则将它转换为绝对路径(pwd就是打印当前的绝对目录的绝对路径),这里利用到&&的断路特性
BUILD_DIR := $(shell cd $(BUILD_DIR) && /bin/pwd)
#如果BUILD_DIR为空,则输出错误信息
$(if $(BUILD_DIR),,$(error output directory "$(saved-output)" does not exist))
endif # ifneq ($(BUILD_DIR),)

#各种路径变量
OBJTREE		:= $(if $(BUILD_DIR),$(BUILD_DIR),$(CURDIR))
SRCTREE		:= $(CURDIR)
TOPDIR		:= $(SRCTREE)
LNDIR		:= $(OBJTREE)
#设置环境变量
export	TOPDIR SRCTREE OBJTREE

#设置mkconfig的路径并设置环境变量
MKCONFIG	:= $(SRCTREE)/mkconfig
export MKCONFIG

#如果OBJTREE和SRCTREE不一样,则设置环境变量REMOTE_BUILD为1,说明是在外部编译
ifneq ($(OBJTREE),$(SRCTREE))
REMOTE_BUILD	:= 1
export REMOTE_BUILD
endif

line 119~138

#obj和src定义在config.mk,但在这里的这两个变量在makefile文件中。
#同时以防一些复位清理的操作,在config.mk被包含之前我们需要使用它们。
# $(obj) and (src) are defined in config.mk but here in main Makefile
# we also need them before config.mk is included which is the case for
# some targets like unconfig, clean, clobber, distclean, etc.
#如果OBJTREE和SRCTREE不相等,分别将其赋值,否则清零。并设置环境变量
ifneq ($(OBJTREE),$(SRCTREE))
obj := $(OBJTREE)/
src := $(SRCTREE)/
else
obj :=
src :=
endif
export obj src

#确保CDPATH不被干涉,取消这个环境变量
# Make sure CDPATH settings don't interfere
unexport CDPATH

#########################################################################
#如果架构为powerpc则将其更改为ppc(Performance Optimization With Enhanced RISC-Performance Computing,是一种精简指令集RISC的CPU)
ifeq ($(ARCH),powerpc)
ARCH = ppc
endif

line 140~151

#判断是否存在config.mk,wildcard的作用是找出和规则匹配的项。
ifeq ($(obj)include/config.mk,$(wildcard $(obj)include/config.mk))

#在执行config.mk之前先让模块包含autoconf.mk,这样可以使配置信息对全部上层编译文件有效。
# Include autoconf.mk before config.mk so that the config options are available
# to all top level build files.  We need the dummy all: target to prevent the
# dependency target in autoconf.mk.dep from being the default.
all:
#通常我们在Makefile中可使用“-include”来代替“include”,来忽略由于包含文件不存在或者无法创建时的错误提示(“-”的意思是告诉make,忽略此操作的错误。make继续执行)
#使全部模块包含自动配置的依赖包和配置文件
sinclude $(obj)include/autoconf.mk.dep
sinclude $(obj)include/autoconf.mk

# load ARCH, BOARD, and CPU configuration 加载配置并设置环境变量
include $(obj)include/config.mk
export	ARCH CPU BOARD VENDOR SOC

yixiasinclude/autoconfig.mk文件内容,由CONFIG_xx组成的宏定义。

讯为4412开发板嵌入式学习(十一)Makefile代码分析_第8张图片

以下是include/autoconfig.mk.dep文件内容,包含include目录下(包括子目录)所有头文件。

讯为4412开发板嵌入式学习(十一)Makefile代码分析_第9张图片

以下是include/config.mk文件内容,这部分内容在之前mkconfig中生成。

讯为4412开发板嵌入式学习(十一)Makefile代码分析_第10张图片

line 153~196

根据架构选择编译器(如arm架构使用编译器前缀为arm-none-linux-gnueabi-)并设置环境变量

line 198~215

加载其他配置

# load other configuration 加载顶层的config.mk
include $(TOPDIR)/config.mk
#########################################################################
# U-Boot objects....order is important (i.e. start must be first) U-Boot目标运行的次序很重要,也就是说必须先运行start

#根据特定CPU添加启动程序,其中resetvec.o是通过使用复位向量是程序跳转到启动位置
OBJS  = cpu/$(CPU)/start.o
ifeq ($(CPU),i386)
OBJS += cpu/$(CPU)/start16.o
OBJS += cpu/$(CPU)/resetvec.o
endif
ifeq ($(CPU),ppc4xx)
OBJS += cpu/$(CPU)/resetvec.o
endif
ifeq ($(CPU),mpc85xx)
OBJS += cpu/$(CPU)/resetvec.o
endif

#将前缀$obj(即路径)添加到OBJS
OBJS := $(addprefix $(obj),$(OBJS))

resetvec.S源码

讯为4412开发板嵌入式学习(十一)Makefile代码分析_第11张图片

line 217~299

加载各种库,如通用库、原厂库、CPU库、文件系统库、磁盘相关库、驱动库、接口库和GCC库等。

LIBS  = lib_generic/libgeneric.a
#......中间还有很多
LIBS += libfdt/libfdt.a
LIBS += api/libapi.a
LIBS += post/libpost.a

#为LIBS添加前缀$obj(即路径)
LIBS := $(addprefix $(obj),$(LIBS))
#将待生成的库文件当成伪目标来处理
.PHONY : $(LIBS) $(TIMESTAMP_FILE) $(VERSION_FILE)

#和板子相关的库,并添加路径
LIBBOARD = board/$(BOARDDIR)/lib$(BOARD).a
LIBBOARD := $(addprefix $(obj),$(LIBBOARD))

line 301~321

# Special flags for CPP when processing the linker script. 当处理链接脚本时CPP特殊标志位
# Pass the version down so we can handle backwards compatibility 为了能够处理向后兼容而传递版本号
# on the fly.
#...
#subst是替换字符串函数,去除OBJS中的字串$obj
__OBJS := $(subst $(obj),,$(OBJS))
__LIBS := $(subst $(obj),,$(LIBS)) $(subst $(obj),,$(LIBBOARD))

line 323~396

使用所提供的依赖编译出指定类型文件,看到最下面编译u-boot时使用到链接文件u-boot.lds,我们先对其进行分析。

1、u-boot.lds分析
OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm") #输出文件格式为小端模式的elf32位文件
OUTPUT_ARCH(arm) #输出架构为arm
ENTRY(_start) #进入起始入口
SECTIONS #段定义
{
 . = 0x00000000; #u-boot的起始地址,main的起始地址在此基础上还要加上偏移0xc3e00000
 . = ALIGN(4); #4字节对齐
 .text :  #代码段,指定路径的文件按照顺序摆放
 {
  cpu/arm_cortexa9/start.o (.text) #startup启动代码
  cpu/arm_cortexa9/s5pc210/cpu_init.o (.text) #cpu初始化代码
  board/samsung/smdkc210/lowlevel_init.o (.text) #底层初始化代码
  common/ace_sha1.o (.text) #sha1加密代码
  *(.text) #剩余的代码
 }
 . = ALIGN(4); #4字节对齐
 .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) } #只读数据段RO,数据按照名字进行排列
 . = ALIGN(4); #4字节对齐
 .data : { *(.data) } #读写数据段RW
 . = ALIGN(4); #4字节对齐
 .got : { *(.got) } #uboot自定义的数据段got
 __u_boot_cmd_start = .; #把当前位置设为uboot命令段起始
 .u_boot_cmd : { *(.u_boot_cmd) } #uboot cmd命令段
 __u_boot_cmd_end = .; #uboot命令段末尾设为当前位置
 . = ALIGN(4); #4字节对齐
 __bss_start = .; #把当前位置设为bss段起始
 .bss : { *(.bss) }#bss段(Block Started by Symbol,存储未被初始化的静态和全局变量)
 _end = .; #把当前位置设为bss段末尾
}
2、start.S分析

由于cpu最先执行的文件是start.S,我们先对其进行分析。

line 53~56

BL1前16字节预留给iROM用于标识BL1。

line 57~86

中断向量的设置,58行跳转(b,不返回跳转)到184行的reset。

line 184~198

设置CPU工作模式为SVC,拥有最高的权限修改底层。

line 200~227

cache缓存初始化,关闭缓冲器(TLBs)和内部缓存(icache),关闭内存管理单元(mmu)。

line 230~237

测试LED

line 240~287

读取启动信息,即OM寄存器的状态。

查看源码可得知如下两个宏定义的具体值:

#define POWER_BASE      0x10020000
#define OMR_OFFSET      0x0

电源管理单元PMU基址

讯为4412开发板嵌入式学习(十一)Makefile代码分析_第12张图片

PMU内部寄存器偏移及说明

讯为4412开发板嵌入式学习(十一)Makefile代码分析_第13张图片

接下来根据读取到的OM状态值r2选择启动设备,并将对应的设备值存储到r0。

在这里插入图片描述

line 293

作为子程序跳转(bl)到底层初始化程序(board/samsung/smdkc210/lowlevel_init.o),初始化锁相环、多路复用器和存储器等(pll,mux,memory)。

line 296~298

上电冷启动使PS_HOLD引脚输出高电平,和手机开机长按电源键一个道理,使电源管理芯片开始工作。

line 301~304

准备调用C函数,设置栈指针。

line 313~322

判断程序是在eMMC还是在内存。

当程序已经在ram中运行时,我们不需要重新定位到U-Boot。实际上,在U-Boot在ram中运行之前必须配置内存控制器(memory controller)。

line 326~338

置位指定IO口,点亮两盏灯。延时一段时间。

line 359~380

根据保存起来的OM值跳转到对应启动设备标签的代码位置。这里用的是eMMC441作为启动设备,故跳转到emmc441_boot,即第418行。

line 418~433

配置时钟,然后返回跳转到emmc441_uboot_copy,将uboot从eMMC拷贝到内存,然后返回到原来调用的位置(此时mmu还是关闭的,内存还不能工作)。

其中emmc441_uboot_copy函数在cpu/arm_cortexa9/s5pc210/movi.c文件中。它的作用是复制BL2。

讯为4412开发板嵌入式学习(十一)Makefile代码分析_第14张图片

然后判断拷贝是否成功,否则进入TF卡拷贝。

一切正常后跳转到after_copy标签。

line 441~509

使能MMU和开启MMU,然后进行堆栈设置,清空BSS段,最后启动C语言相关start_armboot函数,它被定义在lib_arm\board.c中,至此,汇编部分的代码到此结束。

讯为4412开发板嵌入式学习(十一)Makefile代码分析_第15张图片

六、杂项

(一)、操作系统分层概念

  • Windows:BIOS->内核模式->用户模式->用户程序
  • Linux:BootLoader->内核模式->文件系统->用户程序

(二)、bootloader种类

  • U-boot,最常用的bootloader。、
  • vivi,针对三性的ARM定制的2440

(三)、NandFlash纠错ECC算法

由于NandFlash工艺问题会存在坏块,需要ECC(Error Checking and Correcting,错误检查和纠正)进行纠错,4412内部具有16bit的纠错能力。

各存储器内部组成:

  • TF卡(SDMMC):纠错控制器(具有ECC功能)+存储器;
  • eMMC:纠错控制器+MMC(
    Multi Media Card,多媒体存储卡)。

(四)、tf卡烧写和fastboot烧写的指令文件

通过三星原厂提供的文档进行烧写,文件名为:SEC_Exynos4x12_[SSCR][TC4]ICS_Installation_Guide_RTM1.0.2

(五)、vim查看二进制文件

假如要读取abc.bin这个二进制文件,则可以如下操作:
1、以二进制形式打开文件

vim -b abc.bin

2、转换字符为16进制

:%!xxd

3、当查看完成,输入

%!xxd -r

或者直接输入q!退出即可。

(六)删除除某文件之外的所有文件

假如要删除文件abc之外的文件,可通过指令

sudo rm -rf `ls | grep -v "^abc$"`

又或者要删除文件aa和bb之外的文件,可通过指令

sudo rm -rf `ls | grep -v "^aa$" | grep -v "^bb$"`

参数说明:

  • -v:显示不包含匹配文本的所有行。
  • ^: 表示字符串开始。
  • $: 表示字符串结束。

所以^aa$的意思是全文匹配。

(七)、vim删除指定行

1、明确知道行的范围进行删除
假如要删除m行到n行,输入指令:m,n d

2、从当前行m开始往n行删除

  • 在vim命令行中输入mg(m是数字,指定的行数)将光标移动到m行。
  • 接着输入:.,nd删除第m行到第n行(m:n,.d,其中’.'代表的是当前行)。

(八)、vim撤销和重做

撤销:u(undo)
重做:ctrl+r(redo)

(九)、zsh找不到匹配项

出现如下错误:

zsh: no matches found: s/arm.*/arm/

1、在~/.zshrc添加

setopt no_nomatch

2、执行

source ~/.zshrc

参考资料:
ARM 中断状态和SVC状态的堆栈切换 (异常)

ARM官方手册

IRAM IROM 区别

Linux grep 命令

Linux awk 命令

makefile下$^,$@,$?定义使用详解

Linux sed 命令

Shell 传递参数

makefile中的:BUILD_DIR解释

cat <

Tcsh脚本编程

makefile之findstring函数

$(origin variable)详解

uboot笔记之makefile分析

u-boot.lds链接文件详解

x86 Assembly Language Reference Manual

ARM Assembly Language Programming

你可能感兴趣的:(Linux,uboot)