u-boot (1) —— 编译分析

目录

1、编译方式

2、变量、文件分析

2.1、版本号 U_BOOT_VERSION

2.2、主机信息 HOSTARCH、HOSTOS

2.3、静默编译 XECHO

2.4、目标文件目录 BUILD_DIR

2.5、目录 TOPDIR、SRCTREE、OBJTREE

2.5.1、src、obj 目录

2.6、生成配置的文件 MKCONFIG

2.7、体系架构 ARCH、CPU、BOARD、VENDOR、SOC

2.7.1、mkconfig

2.7.2、小结

2.8、autoconf.mk、autoconf.mk.dep

2.9、CROSS_COMPILE

2.10、源码下的 config.mk

2.11、OBJS

2.12、LIBS

3、make all


uboot 是什么不用多说了,是用于引导系统启动的 bootloader,配置完基本硬件后,把代码 Copy 到内存,引导内核启动;

为了支持多种不同的体系架构引导启动,以及各式各样的流程,uboot 源码中包含了几乎所有常见的 CPU 体系架构,包括 ARM,X86,MIPS,PowerPC;现在基于的这款 Exynos 4412 是 ARM Cortex-A9 Qual Core 的四核 CPU 环境来分析 uboot;

既然是彻底分析,那么就从编译部分开始吧;目录结构这些暂时就不多说了,网上到处都有说,其实,从编译的视角来分析目录结构,也会对目录结构理解得更加深刻和透彻;

那么我们从一个已经移植完毕的 u-boot 的编译开始分析,拿着放大镜看看他是怎么编译出来的;

首先还是看 uboot 目录下的 Makefile,这个是整个 uboot 编译的入口;

关于 Makefile 部分的语法和用法,参考 《GNU Makefile》一文;

1、编译方式

按照标准的方式,编译一个 u-boot,不是直接 make,而是需要先:

make xxx_config

然后再:

make all

可以参考 u-boot 目录下的 README 文件,搜索关键字:“Building the Software”,可以看到:

U-Boot is intended to be simple to build. After installing the sources you must configure U-Boot for one specific board type. This is done by typing:

    make NAME_config

where "NAME_config" is the name of one of the existing configurations; see the main Makefile for supported names.

Note: for some board special configuration names may exist; check if additional information is available from the board vendor; for instance, the TQM823L systems are available without (standard) or with LCD support. You can select such additional "features"
when choosing the configuration, i. e.

      make TQM823L_config
    - will configure for a plain TQM823L, i. e. no LCD support

      make TQM823L_LCD_config
    - will configure for a TQM823L with U-Boot console on LCD

      etc.

Finally, type "make all", and you should get some working U-Boot images ready for download to / installation on your system:

  • "u-boot.bin" is a raw binary image
  • "u-boot" is an image in ELF binary format
  • "u-boot.srec" is in Motorola S-Record format

很多关于 u-boot 的东西,都在这个 README 中有描述,我们可以好好参考一下这个文档,包括如何移植一个自己的 u-boot,以及 u-boot 中的一些 CONFIG 的含义,等等;

由于现在是在谈编译,所以暂时看这部分;

我拿到的这个 u-boot 下,有一个编译脚本 build_uboot.sh

#!/bin/sh

if [ -z $1 ]
then	
   echo "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
   echo "Please use correct make config.for example make SCP_1GDDR for SCP 1G DDR CoreBoard linux,android OS"
   echo "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
   exit 0
fi

if   [ "$1" = "SCP_1GDDR" ] ||   [ "$1" = "SCP_2GDDR" ] || [ "$1" = "SCP_1GDDR_Ubuntu" ] ||   [ "$1" = "SCP_2GDDR_Ubuntu" ]
then 
      sec_path="../CodeSign4SecureBoot_SCP/"
      CoreBoard_type="SCP"

elif [ "$1" = "POP_1GDDR" ] || [ "$1" = "POP_1GDDR_Ubuntu" ]
then
      sec_path="../CodeSign4SecureBoot_POP/"
      CoreBoard_type="POP"

elif [ "$1" = "POP_2GDDR" ] ||  [ "$1" = "POP_2GDDR_Ubuntu" ]
then
     sec_path="../CodeSign4SecureBoot_POP/"
     CoreBoard_type="POP2G"
else
      echo "make config error,please use correct params......"
      exit 0
fi

CPU_JOB_NUM=$(grep processor /proc/cpuinfo | awk '{field=$NF};END{print field+1}')
ROOT_DIR=$(pwd)
CUR_DIR=${ROOT_DIR##*/}

#clean
make distclean

#rm link file
rm ${ROOT_DIR}/board/samsung/smdkc210/lowlevel_init.S	
rm ${ROOT_DIR}/cpu/arm_cortexa9/s5pc210/cpu_init.S

case "$1" in
	clean)
		echo make clean
		make mrproper
		;;
	*)
			
		if [ ! -d $sec_path ]
		then
			echo "**********************************************"
			echo "[ERR]please get the CodeSign4SecureBoot first"
			echo "**********************************************"
			return
		fi

                if [ "$1" = "SCP_1GDDR" ]
                then
                	make itop_4412_android_config_scp_1GDDR

                elif [ "$1" = "SCP_2GDDR" ]
                then
                       make itop_4412_android_config_scp_2GDDR

                elif [ "$1" = "POP_1GDDR" ]
                then
                       make itop_4412_android_config_pop_1GDDR

                elif [ "$1" = "POP_2GDDR" ]
                then
                       make itop_4412_android_config_pop_2GDDR

                elif [ "$1" = "SCP_1GDDR_Ubuntu" ]	
                then
                       make itop_4412_ubuntu_config_scp_1GDDR

                elif [ "$1" = "SCP_2GDDR_Ubuntu" ]
                then
                       make itop_4412_ubuntu_config_scp_2GDDR

                elif [ "$1" = "POP_1GDDR_Ubuntu" ]
                then
                       make itop_4412_ubuntu_config_pop_1GDDR

                elif [ "$1" = "POP_2GDDR_Ubuntu" ]
                then
                       make itop_4412_ubuntu_config_pop_2GDDR
		fi	

		make -j$CPU_JOB_NUM

		if [ ! -f checksum_bl2_14k.bin ]
		then
			echo "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
			echo "There are some error(s) while building uboot, please use command make to check."
			echo "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
			exit 0
		fi
		
		cp -rf checksum_bl2_14k.bin $sec_path
		cp -rf u-boot.bin $sec_path
		rm checksum_bl2_14k.bin
		
		cd $sec_path
		#./codesigner_v21 -v2.1 checksum_bl2_14k.bin BL2.bin.signed.4412 Exynos4412_V21.prv -STAGE2

		# gernerate the uboot bin file support trust zone
		#cat E4412.S.BL1.SSCR.EVT1.1.bin E4412.BL2.TZ.SSCR.EVT1.1.bin all00_padding.bin u-boot.bin E4412.TZ.SSCR.EVT1.1.bin > u-boot-iTOP-4412.bin

                if  [ "$CoreBoard_type" = "SCP" ]
                then
		        cat E4412_N.bl1.SCP2G.bin bl2.bin all00_padding.bin u-boot.bin tzsw_SMDK4412_SCP_2GB.bin > u-boot-iTOP-4412.bin

                elif [ "$CoreBoard_type" = "POP" ]
                then
                   cat E4412.S.BL1.SSCR.EVT1.1.bin E4412.BL2.TZ.SSCR.EVT1.1.bin all00_padding.bin u-boot.bin E4412.TZ.SSCR.EVT1.1.bin > u-boot-iTOP-4412.bin

                elif [ "$CoreBoard_type" = "POP2G"  ]
                then
                   cat bl2.bin u-boot.bin E4412.TZ.SSCR.EVT1.1.bin > u-boot-iTOP-4412.bin

                else
                   echo  "make uboot image error......" 
                fi

		mv u-boot-iTOP-4412.bin $ROOT_DIR

		rm checksum_bl2_14k.bin
		#rm BL2.bin.signed.4412
		rm u-boot.bin

		echo 
		echo 
		;;
		
esac

编译的时候,输入

./build_uboot.sh SCP_1GDDR

略去一些其他和 u-boot 无关的因素后,其实关键的就是这两句:

make itop_4412_android_config_scp_1GDDR

make -j$CPU_JOB_NUM

-j$CPU_JOB_NUM 这个多线程编译的核心数目,通过前面 Shell 中找到 CPU 核心数,然后 -j;

后面这两行命令展开分析;

2、变量、文件分析

我们暂时不直接分析上面两个命令产生的后果,因为需要仔细的了解他们,首先需要看明白 Makefile 里面的一些变量,这样可以为后面仔细分析打下基础;

打开 u-boot 的 Makefile 逐行进行分析;

2.1、版本号 U_BOOT_VERSION

VERSION = 2010
PATCHLEVEL = 03
SUBLEVEL =
EXTRAVERSION =
ifneq "$(SUBLEVEL)" ""
U_BOOT_VERSION = $(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
else
U_BOOT_VERSION = $(VERSION).$(PATCHLEVEL)$(EXTRAVERSION)
endif

定义了 u-boot 的版本号:

U_BOOT_VERSION 的值,由这几个的值拼接而来:

VERSION:主板本号

PATCHLEVEL:Patch 版本号

SUBLEVEL:子版本号

EXTRAVERSION:附加的版本信息

2.2、主机信息 HOSTARCH、HOSTOS

通过 Makefile 中使用 $(shell ) 函数,来执行 shell 命令,获取主机的 CPU 架构和主机操作系统,以及 Shell 环境:

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 := $(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

使用 export 将这三个变量导出,使得这三个变量,在下一级的 Makefile 也生效;

2.3、静默编译 XECHO

通过获取 make 后面的参数,来查看是否启用静默模式编译,静默模式指的是编译的时候,不向控制台输出编译内容:

#########################################################################
# Allow for silent builds
ifeq (,$(findstring s,$(MAKEFLAGS)))
XECHO = echo
else
XECHO = :
endif

$(MAKEFIAGS) 代表了在敲入 make 的时候,带入的参数,比如 make -s;-s 的意思就是静默编译的意思;

这里如果没有使用了静默编译,那么 XECHO 就为 echo,即编译阶段,调用 $(XECHO)打印信息;

2.4、目标文件目录 BUILD_DIR

编译 u-boot 的时候,我们可以指定最终生成目标文件的目录,以避免目标文件污染当前目录,在 Makefile 中有:

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

ifneq ($(BUILD_DIR),)
saved-output := $(BUILD_DIR)

# Attempt to create a output directory.
$(shell [ -d ${BUILD_DIR} ] || mkdir -p ${BUILD_DIR})

# Verify if it was successful.
BUILD_DIR := $(shell cd $(BUILD_DIR) && /bin/pwd)
$(if $(BUILD_DIR),,$(error output directory "$(saved-output)" does not exist))
endif # ifneq ($(BUILD_DIR),)

首先使用 ifeq ("$(origin O)", "command line") 来判断是否在终端有通过如下方式,指定输出目标文件的目录,比如:

make O=/tmp/build all

这就代表了这个 O 存在了,而且来自于 command line(origin 这个函数,在 Makefile 中用于查找这个变量的来源,后面跟了 “command line”,意思是查看这个变量是否来源于命令行);

当然,也可以通过直接赋值 BUILD_DIR 的方式,来指定 build 的目录:

export BUILD_DIR=/tmp/build
make

u-boot 使用 O=xxxx,这个 O 的意思,就是 Output 的缩写而已,你也可以把它定义为 OUT,或者其他名字,都行,相应的,修改 Makefile 就行;

下面,我们假设在 make 的时候,没有指定目标文件输出的目录;

2.5、目录 TOPDIR、SRCTREE、OBJTREE

写一个 Makefile,一般来讲,都要定义一些类似 Top 目录,源码目录,头文件目录和中间文件目录,等等;

u-boot 也一样:

OBJTREE		:= $(if $(BUILD_DIR),$(BUILD_DIR),$(CURDIR))
SRCTREE		:= $(CURDIR)
TOPDIR		:= $(SRCTREE)
LNDIR		:= $(OBJTREE)
export	TOPDIR SRCTREE OBJTREE

如果 BUILD_DIR 不为空,那么就以 BUILD_DIR 的值赋给 OBJTREE,否则使用 $(CURDIR) 赋值给 OBJTREE;

$(CURDIR) 是 Makefile 的默认变量,可以直接引用,指的是当前的目录;

假设,我们编译的时候,不指定 BUILD_DIR,那么:

$(OBJTREE):为当前目录,即,u-boot 的 Toplevel 目录;

$(SRCTREE):为当前目录,即,u-boot 的 Toplevel 目录;

$(TOPDIR):为当前目录,即,u-boot 的 Toplevel 目录;

使用 export 导出这三个参数;

2.5.1、src、obj 目录

在定义完 TOPDIR、SRCTREE、OBJTREE 后,立马定定义了 src 和 obj 这两个变量:

# $(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.
ifneq ($(OBJTREE),$(SRCTREE))
obj := $(OBJTREE)/
src := $(SRCTREE)/
else
obj :=
src :=
endif
export obj src

可以看到,如果目标文件的目录和当前源码目录不一样的话,obj 变量的值就是 $(OBJTREE) 多了一个 “/”,src 也是 $(SRCTREE) 多了一个 “/”,也就是代表了下级目录而已;

如果目标文件的目录和当前源码目录一样,那 obj 和 src 为空;

2.6、生成配置的文件 MKCONFIG

继续往下读 Makefile,会发现如下

MKCONFIG	:= $(SRCTREE)/mkconfig
export MKCONFIG

定义了一个变量 MKCONFIG,他指向了 u-boot 目录下的 mkconfig 文件,并使用 export 导出这个变量;

这破玩意,要记住他,并且好好的记住它:

mkconfig 他是用来生成另外的文件的

我们先不看他的内容,稍后里面会看得到;

2.7、体系架构 ARCH、CPU、BOARD、VENDOR、SOC

继续看 Makefile:

ifeq ($(obj)include/config.mk,$(wildcard $(obj)include/config.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:
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

首先使用 ifeq 来判断 config.mk 这个文件是否存在,那么这个文件该不该存在呢?显然是应该存在的,那么看官可以看下,include 下面有没有这个 config.mk;

结论是:没有;

因为这个 include/config.mk,是生成的,怎么生成的呢?就是之前的第一条指令:

make itop_4412_android_config_scp_1GDDR

我们在 Makefile 中可以找到这个 itop_4412_android_config_scp_1GDDR 目标:

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

这个目标依赖一个 unconfig:

unconfig:
	@rm -f $(obj)include/config.h $(obj)include/config.mk \
		$(obj)board/*/config.tmp $(obj)board/*/*/config.tmp \
		$(obj)include/autoconf.mk $(obj)include/autoconf.mk.dep

好了,先来分析一下这个 itop_4412_android_config_scp_1GDDR 的规则;首先会 unconfig 去删除 include 下($(obj) 为空 )的诸多文件;

然后执行:

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

之前我们知道,这个 $(MKCONFIG) 其实就等于源码目录下的 mkconfig;前面加一个@,代表这个过程,不打印出来;

$(@)的意思是目标文件集,而输入的文件集就是 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,后面带了一串参数;

2.7.1、mkconfig

终于轮到打开这个文件了,先提前说好,这个文件是用来执行的,可以理解为一个 Shell 脚本;

#!/bin/sh -e

# Script to create header files and links to configure
# U-Boot for a specific board.
#
# Parameters:  Target  Architecture  CPU  Board [VENDOR] [SOC]
#
# (C) 2002-2006 DENX Software Engineering, Wolfgang Denk <wd@denx.de>
#

APPEND=no	# Default: Create new config file
#BOARD_NAME=""	# Name to print in make output
TARGETS=""

echo "CoreBoard  is $7...... "

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

既然是 Shell 脚本,而且传入了很多参数,这里我们先把参数列举一下:

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

接着看这个 mkconfig:

while [ $# -gt 0 ] ; do
	case "$1" in
	--) shift ; break ;;
	-a) shift ; APPEND=yes ;;
#	-n) shift ; BOARD_NAME="${1%%_config}" ; shift ;;
	-t) shift ; TARGETS="`echo $1 | sed 's:_: :g'` ${TARGETS}" ; shift ;;
	*)  break ;;
	esac
done

首先这个 while [ $# -gt 0 ] 判断如果入参的个数是否大于 0(不包含 $0),如果是,那么进入下面的 case;

判断入参的第一个,也就是 $1 的值是否为:

--

-a

-t

如果是,那么执行响应的操作,这里,我们的入参 $1 为 itop_4412_android,不是这些个玩意;

接下来为:

[ "${BOARD_NAME}" ] || BOARD_NAME="$1"

[ $# -lt 4 ] && exit 1
[ $# -gt 7 ] && exit 1

if [ "${ARCH}" -a "${ARCH}" != "$2" ]; then
	echo "Failed: \$ARCH=${ARCH}, should be '$2' for ${BOARD_NAME}" 1>&2
	exit 1
fi

echo "Configuring for ${BOARD_NAME} board..."

首先判断参数 BOARD_NAME 是否为空,为空的话则将输入参数$1赋值给 BOARD_NAME;

然后判断参数的个数,如果小于 4 或者大于 7,那么直接退出;

然后判断 ARCH 这个是否有被预先定义,如果被定义了,却不等于输入的 $2 那么报错;

接着看:

#
# Create link to architecture specific headers
#
if [ "$SRCTREE" != "$OBJTREE" ] ; then
	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
	cd ./include
	rm -f asm
	ln -s asm-$2 asm
fi

这部分是创建软链接的,先判断 SRCTREE 和 OBJTREE 是否相等,之前我们知道,在顶层的 Makefile 中,我们是已经定义了这两个玩意,结论是,如果不指定编译目录,那么这两个玩意是相等的;

所以我们只需要看后面的 else 那部分;进入 include 下面,删除 asm 目录,并将 asm-$2 软连接到 asm,由于我们的 $2 为 arm,所以呢,就是:

asm-arm -> asm

为啥这样做呢,为了做更好的抽象,所有的平台都这样做的话,在代码里面就可以访问一样的路径:#include<asm/xxx.h>

接着看:

rm -f asm-$2/arch

if [ -z "$6" -o "$6" = "NULL" ] ; then
	ln -s ${LNPREFIX}arch-$3 asm-$2/arch
else
	ln -s ${LNPREFIX}arch-$6 asm-$2/arch
fi

if [ "$2" = "arm" ] ; then
	rm -f asm-$2/proc
	ln -s ${LNPREFIX}proc-armv asm-$2/proc
fi

删除了 asm-arm/arch 目录;

判断 $6 是否为空(此刻为 s5pc210),显然不为空,所以进入 else 分支:

arch-s5pc210 链接到 asm-arch/arch

然后链接 asm-arm/proc:

继续看脚本:

#
# Create include file for Make
#
echo "ARCH   = $2" >  config.mk
echo "CPU    = $3" >> config.mk
echo "BOARD  = $4" >> config.mk

[ "$5" ] && [ "$5" != "NULL" ] && echo "VENDOR = $5" >> config.mk

[ "$6" ] && [ "$6" != "NULL" ] && echo "SOC    = $6" >> config.mk

# Assign board directory to BOARDIR variable
if [ -z "$5" -o "$5" = "NULL" ] ; then
    BOARDDIR=$4
else
    BOARDDIR=$5/$4
fi

 使用 echo 将一些信息添加到 config.mk;

注意:include 下的这个 config.mk 本来是没有的,是通过这个 mkconfig 来生成的

 这些信息包括了 ARCH、CPU、BOARD、VENDOR、SOC;这些就是对应在使用这个 mkconfig 时候的入参;所以生成后的 include/config.mk 是如下内容:

 继续看脚本:

if   [ "$7" = "SCP_1GDDR" ] ||   [ "$7" = "SCP_2GDDR" ] || [ "$7" = "SCP_1GDDR_Ubuntu" ] ||   [ "$7" = "SCP_2GDDR_Ubuntu" ]
then 
     echo "CORE   =  SCP" >> config.mk
     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

这里根据入参,住了两个事情:

赋值了 CORE 这个变量到 config.mk

由于 SCP 和 POP 不一样,但是呢,最后代码里面编译的时候使用到的都是叫做:

lowlevel_init.S 和 cpu_init.S

所以,这里做了软链接,来加以区分;

接着看:

#
# Create board specific header file
#
if [ "$APPEND" = "yes" ]	# Append to existing config file
then
	echo >> config.h
else
	> config.h		# Create new config file
fi
echo "/* Automatically generated - do not edit */" >>config.h

for i in ${TARGETS} ; do
	echo "#define CONFIG_MK_${i} 1" >>config.h ;
done

#add by dg for all itop4412 type boards

[ "$7" ] && [ "$7" != "NULL" ] && echo "#define CONFIG_$7" >> config.h

cat << EOF >> config.h
#define CONFIG_BOARDDIR board/$BOARDDIR
#include <config_defaults.h>
#include <configs/$BOARD_NAME.h>
#include <asm/config.h>
EOF

exit 0

判断 APPEND 是否为 yes,这个意思就是是否往已经存在了的 config.h 里面追加东西;

我们的 u-boot 本身在 include 下面是没有这个 config.h 的,而且在这个 mkconfig 脚本中,第一行已经将这个 APPEND 设置为了 no;

这里就是直接创建了一个 include/config.h 文件,往这个文件里面增加了很多东西:

2.7.2、小结

这里简单的做一个小结,在 make itop_4412_android_config_scp_1GDDR 之后啊,会调用 mkconfig,去生成

include/config.mk

include/config.h

还有一些软链接被设置准备好;

2.8、autoconf.mk、autoconf.mk.dep

继续读 Makefile 会发现如下内容:

ifeq ($(obj)include/config.mk,$(wildcard $(obj)include/config.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:
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

我们知道,include/config.mk 已经在我们 make 配置的时候,生成了;但是呢,这两行需要仔细看看:

sinclude $(obj)include/autoconf.mk.dep
sinclude $(obj)include/autoconf.mk

sinclude 和 -include 是一个意思,代表着如果包含文件失败,忽略错误;

但是实际情况是,这个 autoconf.mk.dep 和 autoconf.mk 的确在源码目录下没有,那么这个 sinclude 真的会失败吗?

其实不然,这个 autoconf.mk.dep 和 autoconf.mk 在 Makefile 中,也是一个目标,我们在 Makefile 中可以搜索这两个玩意,可以在后面发现如下:

#
# Auto-generate the autoconf.mk file (which is included by all makefiles)
#
# This target actually generates 2 files; autoconf.mk and autoconf.mk.dep.
# the dep file is only include in this top level makefile to determine when
# to regenerate the autoconf.mk file.
$(obj)include/autoconf.mk.dep: $(obj)include/config.h include/common.h
	@$(XECHO) Generating $@ ; \
	set -e ; \
	: Generate the dependancies ; \
	$(CC) -x c -DDO_DEPS_ONLY -M $(HOSTCFLAGS) $(CPPFLAGS) \
		-MQ $(obj)include/autoconf.mk include/common.h > $@

$(obj)include/autoconf.mk: $(obj)include/config.h
	@$(XECHO) Generating $@ ; \
	set -e ; \
	: Extract the config macros ; \
	$(CPP) $(CFLAGS) -DDO_DEPS_ONLY -dM include/common.h | \
		sed -n -f tools/scripts/define2mk.sed > $@.tmp && \
	mv $@.tmp $@

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

我们看他的注释便知:

1、autoconf.mk 这玩意是生成的;

2、autoconf.mk 这玩意要被所有的 Makefile 包含;

autoconf.mk 依赖 include/config.h 文件(前一步生成的)

编译选项 “-dM” 的作用是输出include/common.h中定义的所有宏。根据上面的规则,编译器提取include/common.h中定义的宏,然后输出给tools/scripts/define2mk.sed脚本处理,处理的结果就是include/autoconf.mk文件。其中tools/scripts/define2mk.sed脚本的主要完成了在include/common.h中查找和处理以“CONFIG_”开头的宏定义的功能;

include/common.h 文件包含了 include/config.h文件;

而 include/config.h文件又包含了config_defaults.h,configs/itop_4412_android.h,asm/config.h文件。

因此include/autoconf.mk实质上就是 config_defaults.h、configs/itop_4412_android.h、asm/config.h 三个文件中“CONFIG_”开头的有效的宏定义的集合。

而 autoconf.mk.dep 是 autoconf.mk 的依赖,我们打开 autoconf.mk 看看: 

autoconf.mk.dep 内容为:

此刻,我们回到之前 Makefile 包含 autoconf.mk 和 autoconf.mk.dep 的地方; 

ifeq ($(obj)include/config.mk,$(wildcard $(obj)include/config.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:
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

这里,autoconfig.mk、config.mk 都被 include 了

解释一下 Makefile 的 include,是将被 include 的文件内容直接全部原地展开;

所以各种 CONFIG_ 都被 include 进来了;并且把 ARCH、CPU 等都包含了进来,并且呢,export 了这些;

2.9、CROSS_COMPILE

CROSS_COMPILE 交叉编译器,这个必须要指定,没什么好说的:

ifeq ($(ARCH),arm)
CROSS_COMPILE = /usr/local/arm/arm-2009q3/bin/arm-none-linux-gnueabi-
endif

export	CROSS_COMPILE

2.10、源码下的 config.mk

之前我们说了一下,执行 make xxx_config 会调用 mkconfig 去生成一个 include/config.mk 文件,我们读 Makefile 的时候,发现如下内容:

# load other configuration
include $(TOPDIR)/config.mk
#########################################################################
# U-Boot objects....order is important (i.e. start must be first)

Makefile 还包括了其源码目录下的 config.mk,虽然是同名,但是我们要把这个 config.mk 与 include/config.mk 区别开来,我们知道,Makefile 的 include 是会直接把后面被包含的内容之间原地展开的,所以这里相当于展开了源码目录下面的 config.mk,那么我们来看看这个里面又有什么:

ifneq ($(OBJTREE),$(SRCTREE))
ifeq ($(CURDIR),$(SRCTREE))
dir :=
else
dir := $(subst $(SRCTREE)/,,$(CURDIR))
endif

obj := $(if $(dir),$(OBJTREE)/$(dir)/,$(OBJTREE)/)
src := $(if $(dir),$(SRCTREE)/$(dir)/,$(SRCTREE)/)

$(shell mkdir -p $(obj))
else
obj :=
src :=
endif

首先判断 OBJTREE 和 SRCTREE 是否相等,这里,我们默认让他们相等,所以会走到最下面那个 else,即 obj 和 src 为空;

注意:这个 obj 和 src 是和顶层 Makefile 一样的那个 obj 和 src,这里使用 ":=" 的赋值方式,可以覆盖之前的对 obj 和 src 的值;

接着看:

# clean the slate ...
PLATFORM_RELFLAGS =
PLATFORM_CPPFLAGS =
PLATFORM_LDFLAGS =

清除了这几个变量;

config.mk 里面还定义了交叉编译链的工具:

#
# Include the make variables (CC, etc...)
#
AS	= $(CROSS_COMPILE)as
LD	= $(CROSS_COMPILE)ld
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
RANLIB	= $(CROSS_COMPILE)RANLIB

其他的内容,有兴趣的可以仔细看看;

2.11、OBJS

接着看 Makefile,接着定义了一些 .o 文件:

#########################################################################
# U-Boot objects....order is important (i.e. start must be first)

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

OBJS := $(addprefix $(obj),$(OBJS))

这里还 专门由一个说明:

U-Boot objects....order is important (i.e. start must be first)

最先放在前面的是 cpu/arm_cortexa9/start.o,我们的 CPU 是 arm,所以那些 ifeq 都不满足,直接到最后一行,这个 addprefix 是加前缀的意思,obj 为空,所以就当没有;

2.12、LIBS

再看 Makefile,定义了这个 LIBS

LIBS  = lib_generic/libgeneric.a
LIBS += lib_generic/lzma/liblzma.a
LIBS += lib_generic/lzo/liblzo.a
LIBS += $(shell if [ -f board/$(VENDOR)/common/Makefile ]; then echo \
	"board/$(VENDOR)/common/lib$(VENDOR).a"; fi)
LIBS += cpu/$(CPU)/lib$(CPU).a
ifdef SOC
LIBS += cpu/$(CPU)/$(SOC)/lib$(SOC).a
endif
ifeq ($(CPU),ixp)
LIBS += cpu/ixp/npe/libnpe.a
endif
LIBS += lib_$(ARCH)/lib$(ARCH).a
LIBS += fs/cramfs/libcramfs.a fs/fat/libfat.a fs/fdos/libfdos.a fs/jffs2/libjffs2.a \
	fs/reiserfs/libreiserfs.a fs/ext2/libext2fs.a fs/yaffs2/libyaffs2.a \
	fs/ubifs/libubifs.a
LIBS += net/libnet.a
LIBS += disk/libdisk.a
LIBS += drivers/bios_emulator/libatibiosemu.a
LIBS += drivers/block/libblock.a
LIBS += drivers/dma/libdma.a
LIBS += drivers/fpga/libfpga.a
LIBS += drivers/gpio/libgpio.a
LIBS += drivers/hwmon/libhwmon.a
LIBS += drivers/i2c/libi2c.a
LIBS += drivers/input/libinput.a
LIBS += drivers/misc/libmisc.a
LIBS += drivers/mmc/libmmc.a
LIBS += drivers/mtd/libmtd.a
LIBS += drivers/mtd/nand/libnand.a
LIBS += drivers/mtd/onenand/libonenand.a
LIBS += drivers/mtd/ubi/libubi.a
LIBS += drivers/mtd/spi/libspi_flash.a
LIBS += drivers/net/libnet.a
LIBS += drivers/net/phy/libphy.a
LIBS += drivers/pci/libpci.a
LIBS += drivers/pcmcia/libpcmcia.a
LIBS += drivers/power/libpower.a
LIBS += drivers/spi/libspi.a
ifeq ($(CPU),mpc83xx)
LIBS += drivers/qe/qe.a
endif
ifeq ($(CPU),mpc85xx)
LIBS += drivers/qe/qe.a
LIBS += cpu/mpc8xxx/ddr/libddr.a
LIBS += cpu/mpc8xxx/lib8xxx.a
endif
ifeq ($(CPU),mpc86xx)
LIBS += cpu/mpc8xxx/ddr/libddr.a
LIBS += cpu/mpc8xxx/lib8xxx.a
endif
LIBS += drivers/rtc/librtc.a
LIBS += drivers/serial/libserial.a
LIBS += drivers/twserial/libtws.a
LIBS += drivers/usb/gadget/libusb_gadget.a
LIBS += drivers/usb/host/libusb_host.a
LIBS += drivers/usb/musb/libusb_musb.a
LIBS += drivers/usb/phy/libusb_phy.a
LIBS += drivers/video/libvideo.a
LIBS += drivers/watchdog/libwatchdog.a
LIBS += common/libcommon.a
LIBS += libfdt/libfdt.a
LIBS += api/libapi.a
LIBS += post/libpost.a

LIBS := $(addprefix $(obj),$(LIBS))
.PHONY : $(LIBS) $(TIMESTAMP_FILE) $(VERSION_FILE)

这些个 .a 静态库文件,是由各个子目录进行编译出来的,目前暂时还没有被编译出来,要进入到各个子目录去使用 Makefile 进行编译,我们打个比方:

第一个

LIBS = lib_generic/libgeneric.a

我们进入到 lib_generic,打开它的 Makefile:

include $(TOPDIR)/config.mk

LIB = $(obj)libgeneric.a

COBJS-$(CONFIG_ADDR_MAP) += addr_map.o
COBJS-$(CONFIG_BZIP2) += bzlib.o
COBJS-$(CONFIG_BZIP2) += bzlib_crctable.o
COBJS-$(CONFIG_BZIP2) += bzlib_decompress.o
COBJS-$(CONFIG_BZIP2) += bzlib_randtable.o
COBJS-$(CONFIG_BZIP2) += bzlib_huffman.o
COBJS-$(CONFIG_USB_TTY) += circbuf.o
COBJS-y += crc16.o
COBJS-y += crc32.o
COBJS-y += ctype.o
COBJS-y += display_options.o
COBJS-y += div64.o
COBJS-$(CONFIG_GZIP) += gunzip.o
COBJS-$(CONFIG_LMB) += lmb.o
COBJS-y += ldiv.o
COBJS-$(CONFIG_MD5) += md5.o
COBJS-y += net_utils.o
COBJS-$(CONFIG_SHA1) += sha1.o
COBJS-$(CONFIG_SHA256) += sha256.o
COBJS-y += string.o
COBJS-y += strmhz.o
COBJS-y += time.o
COBJS-y += vsprintf.o
COBJS-$(CONFIG_ZLIB) += zlib.o
COBJS-$(CONFIG_RBTREE)  += rbtree.o

COBJS   := $(COBJS-y)
SRCS    := $(COBJS:.o=.c)
OBJS    := $(addprefix $(obj),$(COBJS))

$(LIB): $(obj).depend $(OBJS)
    $(AR) $(ARFLAGS) $@ $(OBJS)

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

# defines $(obj).depend target
include $(SRCTREE)/rules.mk

首先,它包含了顶层的 config.mk 文件,定义了这个 Makefile 的目标文件:

LIB = $(obj)libgeneric.a

然后定义了一堆的:

COBJS-$(CONFIG_XXX) += xxx.o

这种东西,在我们的配置中,如果使用了某个配置,我们会往这个配置写 y,也就是:

CONFIG_XXX = y

所以,目标依赖的都是一个叫做 $(COBJS-y) 的东西;

这个 $(AR) 是被定义在 config.mk 中的 AR:

AR	= $(CROSS_COMPILE)ar

这个 $(ARFLAGS) 也是config.mk 中的:

ifneq (,$(findstring s,$(MAKEFLAGS)))
ARFLAGS = cr
else
ARFLAGS = crv
endif

这样就用 ar 这个工具,以 .o 作为输入,生成了 .a 了;其他的 .a 类似,不再多说;

3、make all

前面看的差不多了,现在来看最后的 make all 了;

# Always append ALL so that arch config.mk's can add custom ones
ALL += $(obj)u-boot.srec $(obj)u-boot.bin $(obj)System.map $(U_BOOT_NAND) $(U_BOOT_ONENAND)
all:		$(ALL)

$(obj)u-boot.hex:	$(obj)u-boot
		$(OBJCOPY) ${OBJCFLAGS} -O ihex $< $@

$(obj)u-boot.srec:	$(obj)u-boot
		$(OBJCOPY) -O srec $< $@

$(obj)u-boot.bin:	$(obj)u-boot
		$(OBJCOPY) ${OBJCFLAGS} -O binary $< $@
		@#./mkuboot
		
		@split -b 14336 u-boot.bin bl2
		@+make -C sdfuse_q/
		@#cp u-boot.bin u-boot-4212.bin
		@#cp u-boot.bin u-boot-4412.bin
		@#./sdfuse_q/add_sign
		@./sdfuse_q/chksum
		@./sdfuse_q/add_padding
		@rm bl2a*
		
		@echo

$(obj)u-boot.ldr:	$(obj)u-boot
		$(CREATE_LDR_ENV)
		$(LDR) -T $(CONFIG_BFIN_CPU) -c $@ $< $(LDR_FLAGS)

$(obj)u-boot.ldr.hex:	$(obj)u-boot.ldr
		$(OBJCOPY) ${OBJCFLAGS} -O ihex $< $@ -I binary

$(obj)u-boot.ldr.srec:	$(obj)u-boot.ldr
		$(OBJCOPY) ${OBJCFLAGS} -O srec $< $@ -I binary

$(obj)u-boot.img:	$(obj)u-boot.bin
		./tools/mkimage -A $(ARCH) -T firmware -C none \
		-a $(TEXT_BASE) -e 0 \
		-n $(shell sed -n -e 's/.*U_BOOT_VERSION//p' $(VERSION_FILE) | \
			sed -e 's/"[	 ]*$$/ for $(BOARD) board"/') \
		-d $< $@

$(obj)u-boot.imx:       $(obj)u-boot.bin
		$(obj)tools/mkimage -n $(IMX_CONFIG) -T imximage \
		-e $(TEXT_BASE) -d $< $@

$(obj)u-boot.kwb:       $(obj)u-boot.bin
		$(obj)tools/mkimage -n $(KWD_CONFIG) -T kwbimage \
		-a $(TEXT_BASE) -e $(TEXT_BASE) -d $< $@

$(obj)u-boot.sha1:	$(obj)u-boot.bin
		$(obj)tools/ubsha1 $(obj)u-boot.bin

$(obj)u-boot.dis:	$(obj)u-boot
		$(OBJDUMP) -d $< > $@

可以看到,最后我们 make all 的时候,依赖生成 3 个目标:

  • u-boot.srec
  • u-boot.bin
  • System.map

第一个 u-boot.srec 从 u-boot 的 README 中看到,是一个说明摩托罗拉的格式,不管他;

第二个 u-boot.bin 是纯二进制文件,也就是烧写到板端的文件;

第三个是 map 文件;

可以发现,要生成 u-boot.srec 和 u-boot.bin,都依赖一个叫 u-boot 的文件,使用 objcopy 来得到,这个 u-boot 是 elf 文件;

GEN_UBOOT = \
		UNDEF_SYM=`$(OBJDUMP) -x $(LIBBOARD) $(LIBS) | \
		sed  -n -e 's/.*\($(SYM_PREFIX)__u_boot_cmd_.*\)/-u\1/p'|sort|uniq`;\
		cd $(LNDIR) && $(LD) $(LDFLAGS) $$UNDEF_SYM $(__OBJS) \
			--start-group $(__LIBS) --end-group $(PLATFORM_LIBS) \
			-Map u-boot.map -o u-boot
$(obj)u-boot:	depend $(SUBDIRS) $(OBJS) $(LIBBOARD) $(LIBS) $(LDSCRIPT) $(obj)u-boot.lds
		$(GEN_UBOOT)
ifeq ($(CONFIG_KALLSYMS),y)
		smap=`$(call SYSTEM_MAP,u-boot) | \
			awk '$$2 ~ /[tTwW]/ {printf $$1 $$3 "\\\\000"}'` ; \
		$(CC) $(CFLAGS) -DSYSTEM_MAP="\"$${smap}\"" \
			-c common/system_map.c -o $(obj)common/system_map.o
		$(GEN_UBOOT) $(obj)common/system_map.o
endif

可以看到,u-boot 这个终极大 boss,依赖很多东西,在生成这个目标之前,需要先把 u-boot 的依赖全部生成(各种 .o 和 .a),最后,GEN_UBOOT 这个就是用于生成 u-boot 的命令了,将所有的文件(.o 和 .a)全部打包,生成 elf 格式的 u-boot;

u-boot 的依赖生成被定义到了紧接着的下面:

$(OBJS):	depend
		$(MAKE) -C cpu/$(CPU) $(if $(REMOTE_BUILD),$@,$(notdir $@))

$(LIBS):	depend $(SUBDIRS)
		$(MAKE) -C $(dir $(subst $(obj),,$@))

$(LIBBOARD):	depend $(LIBS)
		$(MAKE) -C $(dir $(subst $(obj),,$@))

$(SUBDIRS):	depend
		$(MAKE) -C $@ all

$(LDSCRIPT):	depend
		$(MAKE) -C $(dir $@) $(notdir $@)

..............
..............

其中,$(MAKE) 其实就是 make,make -C 的意思是进入到文件夹下面去执行子 Makefile,说白了,就是去编译那些子文件夹;

当然,最好分析的方法,可以将 Makefile 和编译过程中的打印相结合,这样的话,会更加直观;

  • 7
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
资源大于15MB分2次上传。 清晰度一般。加到11章 第12,13章没有。 第1章 嵌入式系统基础. 1.1 嵌入式系统简介 1.1.1 嵌入式系统定义 1.1.2 嵌入式系统与PC 1.1.3 嵌入式系统的特点 1.2 嵌入式系统的发展 1.2.1 嵌入式系统现状 1.2.2 嵌入式系统发展趋势 1.3 嵌入式操作系统与实时操作系统 1.3.1 Linux 1.3.2 uC/OS 1.3.3 Windows CE 1.3.4 VxWorks 1.3.5 Palm OS 1.3.6 QNX 1.4 嵌入式系统选型 第2章 基于ARM9处理器的硬件开发平台 2.1 ARM处理器简介 2.1.1 ARM公司简介 2.1.2 ARM微处理器核 .2.2 ARM9微处理器简介 2.2.1 与ARM7处理器的比较 2.2.2 三星S3C2410X处理器详解 2.3 FS2410开发平台 第3章 创建嵌入式系统开发环境 3.1 嵌入式Linux开发环境 3.2 Cygwin 3.3 虚拟机 3.4 交叉编译的预备知识 3.4.1 Make命令和Makefile文件 3.4.2 binutils工具包 3.4.3 gcc编译器 3.4.4 Glibc库 3.4.5 GDB 3.5 交叉编译 3.5.1 创建编译环境 3.5.2 编译binutils 3.5.3 编译bootstrap_gcc 3.5.4 编译Glibc 3.5.5 编译完整的gcc 3.5.6 编译GDB 3.5.7 成果 3.5.8 其他交叉编译方法 3.6 通过二进制软件包创建交叉编译环境 3.7 开发套件 第4章 调试嵌入式系统程序 4.1 嵌入式系统调试方法 4.1.1 实时在线仿真 4.1.2 模拟调试 4.1.3 软件调试 4.1.4 BDM/JTAG调试 4.2 ARM仿真器 4.2.1 techorICE ARM仿真器 4.2.2 ARM仿真器工作原理 4.2.3 ARM仿真器的系统功能层次 4.2.4 使用仿真器和ADS Debugger调试ARM开发板 4.3 JTAG接口 4.3.1 JTAG引脚定义 4.3.2 通过JTAG烧写Flash 4.3.3 烧写Flash技术内幕 第5章 Bootloader 5.1 嵌入式系统的引导代码 5.1.1 初识Bootloader 5.1.2 Bootloader的启动流程 5.2 Bootloader之vivi 5.2.1 vivi简介 5.2.2 vivi的配置与编译 5.2.3 vivi代码导读 5.3 Bootloader之U-Boot 5.3.1 U-Boot代码结构分析 5.3.2 编译U-Boot代码 5.3.3 U-Boot代码导读 5.3.4 U-Boot命令 5.4 FS2410的Bootloader 第6章 Linux系统在ARM平台的移植 6.1 移植的概念 6.2 Linux内核结构 6.3 Linux-2.4内核向ARM平台的移植 6.3.1 根目录 6.3.2 arch目录 6.3.3 arch/arm/boot目录 6.3.4 arch/arm/def-configs目录 6.3.5 arch/arm/kernel目录 6.3.6 arch/arm/mm目录 6.3.7 arch/arm/mach-s3c2410目录 6.4 Linux-2.6内核向ARM平台的移植 6.4.1 定义平台和编译器 6.4.2 arch/arm/mach-s3c2410/devs.c 6.4.3 arch/arm/mach-s3c2410/mach-fs2410.c 6.4.4 串口输出 6.5 编译Linux内核 6.5.1 代码成熟等级选项 6.5.2 通用的一些选项 6.5.3 和模块相关的选项 6.5.4 和块相关的选项 6.5.5 和系统类型相关的选项 6.5.6 和总线相关的选项 6.5.7 和内核特性相关的选项 6.5.8 和系统启动相关的选项 6.5.9 和浮点运算相关的选项 6.5.10 用户空间使用的二进制文件格式的选项 6.5.11 和电源管理相关的选项 6.5.12 和网络协议相关的选项 6.5.13 和设备驱动程序相关的选项 6.5.14 和文件系统相关的选项 6.5.15 和程序性能分析相关的选项 6.5.16 和内核调试相关的选项 6.5.17 和安全相关的选项 6.5.18 和加密算法相关的选项 6.5.19 库选项 6.5.20 保存内核配置 第7章 Linux设备驱动程序开发 7.1 设备驱动概述 7.1.1 设备驱动和文件系统的关系 7.1.2 设备类型分类 7.1.3 内核空间和用户空间.. 7.2 设备驱动基础 7.2.1 设备驱动中关键数据结构 7.2.2 字符设备驱动开发 第8章 网络设备驱动程序开发 8.1 网络设备驱动程序简介 8.1.1 device数据结构 8.1.2 sk_buff数据结构 8.1.3 内核的驱动程序接口 8.2 以太网控制器CS8900A 8.2.1 特性 8.2.2 工作原理 8.2.3 电路连接 8.2.4 引脚 8.2.5 操作模式 8.3 网络设备驱动程序实例 8.3.1 初始化函数 8.3.2 打开函数 8.3.3 关闭函数 8.3.4 发送函数 8.3.5 接收函数 8.3.6 中断处理函数 第9章 USB驱动程序开发 9.1 USB驱动程序简介 9.1.1 USB背景知识 9.1.2 Linux内核对USB规范的支持 9.1.3 OHCI简介 9.2 Linux下USB系统文件结点 9.3 USB主机驱动结构 9.3.1 USB数据传输时序 9.3.2 USB设备连接/断开时序 9.4 主要数据结构及接口函数 9.4.1 数据传输管道 9.4.2 统一的USB数据传输块 9.4.3 USBD数据描述 9.4.4 USBD与HCD驱动程序接口 9.4.5 USBD层的设备管理 9.4.6 设备类驱动与USBD接口 9.5 USBD文件系统接口 9.5.1 设备驱动程序访问 9.5.2 设备拓扑访问 9.5.3 设备信息访问 9.6 设备类驱动与文件系统接口 9.7 USB HUB驱动程序 9.7.1 HUB驱动初始化 9.7.2 HUB Probe相关函数 9.8 OHCI HCD实现 9.8.1 OHCI驱动初始化 9.8.2 与USBD连接 9.8.3 OHCI根HUB 9.9 扫描仪设备驱动程序 9.9.1 USBD接口 9.9.2 文件系统接口 9.10 USB主机驱动在S3C2410X平台的实现 9.10.1 USB主机控制器简介 9.10.2 驱动程序的移植 第10章 图形用户接口 10.1 嵌入式系统中的GUI简介 10.1.1 MicroWindows 10.1.2 MiniGUI 10.1.3 Qt/Embedded 10.2 MiniGUI编程 10.2.1 MiniGUI移植 10.2.2 MiniGUI编程 10.3 初识Qt/Embedded 10.3.1 Qt介绍 10.3.2 系统要求 10.3.3 Qt的架构 10.4 Qt/Embedded嵌入式图形开发基础 10.4.1 建立Qt/Embedded 开发环境 10.4.2 认识Qt/Embedded开发环境 10.4.3 窗体 10.4.4 对话框 10.4.5 外形与感觉 10.4.6 国际化 10.5 Qt/Embedded实战演练 10.5.1 安装Qt/Embedded工具开发包 10.5.2 交叉编译Qt/Embedded库 10.5.3 Hello,World 10.5.4 发布Qt/Embedded程序到目标板 10.5.5 添加一个Qt/Embedded应用到QPE 第11章 Java虚拟机的移植 11.1 Java虚拟机概述 11.1.1 Java虚拟机的概念 11.1.2 J2ME 11.1.3 KVM 11.2 Java虚拟机的移植 11.2.1 获得源码 11.2.2 编译环境的建立 11.2.3 JDK的安装 11.2.4 KVM的移植及编译 11.2.5 KVM的测试 11.3 其他可选的虚拟机 11.4 性能优化
介绍了源码开放的通用启动模块U-Boot 的文件结构,并以Broadcom 公司的4 内核处理器BCM1480 和RMI的32 内核处理器XLR732 为例,阐述了该模块在64 位多内核MIPS体系结构处理器上的移植经验,包括文件的修改、新增、编译、多内核的启动顺序等。   目前,微处理器架构呈百家争鸣之势,x86、PowerPC、MIPS、68x、ARM、Xscale 等架构纷纷在广阔的电子产品市场划分势力范围。x86 架构在PC机领域独领风骚——虽然基于x86的处理器迄今最多集成4 个内核,小于MIPS 架构的32 内核。ARM 架构的处理器统治着消费类电子市场,而在嵌入式领域,尤其是通信产品领域,x86、MIPS、PowerPC 架构的处理器正逐鹿中原。不同特性的处理器架构组成了丰富多彩的计算控制平台,但是无论是什么类型的处理平台,“开门第一件事”都是调用启动代码。   启动代码一般存放在外部的非易失性存储器上,例如Flash芯片。通常不同的处理器,即便基于相同的架构,启动代码往往大相径庭,更何况不同的处理器架构了。例如,BIOS 启动代码适合于x86 的处理器,风河(Windriver)公司的基于VxWorks操作系统的Bootrom 支持PowerPC、ARM、MIPS 等多种处理器。但是,这些启动代码往往源码不开放、开发工具和许可费用昂贵、通用性差。   U-Boot 是德国Denx 软件中心依照GPL 发布的源码公开的公共软件,其全称是Universal Bootloader,即通用启动模块,目前它支持x86、PowerPC、MIPS、ARM 等处理器架构,支持1000 多种嵌入式平台。然而,因为U-Boot 的前身是ppcboot,是一种专用于PowerPC 架构处理器的启动模块,后来Denx 软件中心将其扩展到ARM 处理器等其他架构,所以目前U-Boot支持的平台中,PowerPC 架构的处理器最多。其他架构的处理器平台正在全世界有兴趣的工程师的努力下逐渐完善。   U-Boot 的最新版本是1.1.5,支持4Kc、5Kc、MIPS32AU1x00 等少数MIPS 架构单内核处理器。笔者将U-Boot 扩展到了业界先进的两款64位多内核MIPS处理器上。
### 回答1: 编译mt7621配置的U-Boot需要进行以下步骤: 首先,确认已经准备好编译环境,包括安装好交叉编译工具链和相关依赖库。 然后,从U-Boot官方仓库中获取最新的源代码。可以使用git命令进行克隆,例如: git clone https://github.com/u-boot/u-boot.git 接下来,切换到代码目录并进入配置界面,执行以下命令: cd u-boot make menuconfig 在配置界面中,选择"MTK",然后选择"MTK_MT7621"作为目标平台。根据需要,可以进行其他选项的配置,如串口、网络等。 配置完成后,保存退出配置界面。然后,执行以下命令进行编译: make CROSS_COMPILE=<交叉编译工具链前缀> 编译过程可能需要一段时间,取决于计算机性能和代码规模。 编译完成后,可以得到u-boot.bin文件作为编译结果。该文件可以烧录到MT7621芯片的Flash中,用于启动设备。 以上是编译mt7621配置的U-Boot的大致步骤。根据具体需求,可能还需要进行其他配置和调整。在进行编译前,建议查阅U-Boot的官方文档和相关资料,以便更详细地了解配置和编译过程。 ### 回答2: 编译 U-Boot for MT7621 配置需要先准备编译环境和相关工具链。以下是编译 MT7621 配置的步骤: 1. 首先,确保你的系统上已经安装了交叉编译工具链。可以通过执行以下命令来检查是否已安装交叉编译工具链: ``` arm-openwrt-linux-gcc -v ``` 如果显示出工具链的版本信息,则表示已经安装成功。 2. 下载 U-Boot 的源码。你可以通过 Git 或者下载压缩包的方式获取源码。例如,使用 Git 命令来克隆 U-Boot 的仓库: ``` git clone https://github.com/u-boot/u-boot.git ``` 3. 进入源码目录,并创建编译配置文件。执行以下命令: ``` cd u-boot make mt7621_xxx_config ``` 其中,`mt7621_xxx_config` 是针对你的具体设备的配置文件,例如 `mt7621_rfb_config` 或 `mt7621_xxx_config` 等。你可以查阅相关文档来确定正确的配置文件。 4. 根据配置文件生成编译规则。执行以下命令: ``` make oldconfig ``` 根据你的需求来回答一些提示问题。默认选项通常是可以满足大多数需求的。 5. 开始编译。执行以下命令: ``` make ``` 编译时间会根据你的机器性能和代码大小而不同。最终编译产生的 U-Boot 可执行文件将位于生成文件夹中。 完成上述步骤后,你将获得一个适用于 MT7621 的 U-Boot 可执行文件。你可以将它用于你的项目中,并在启动过程中加载它。当然,在编译之前,你可能需要修改一些配置文件,以确保 U-Boot 适配你的具体硬件环境。 ### 回答3: 要编译 mt7621 的 u-boot 需要进行一些配置。 首先,你需要下载 u-boot 的源代码。可以从官方网站或者 GitHub 上找到 mt7621 相关的 u-boot 仓库,并下载代码至你的开发环境中。 接下来,你需要进入 u-boot 的源代码目录。使用终端命令行工具进入该目录。 在源代码目录中,你可以找到一个名为 `configs` 的文件夹,其中包含了不同平台的配置文件。你需要找到一个名为 `mt7621_bpir2_defconfig` 的文件,这是针对 mt7621 平台的默认配置文件。 如果你想进行自定义配置,可复制该文件,并在复制的文件上进行修改。你可以使用一个文本编辑器打开配置文件,找到需要修改的选项,并进行相应的修改。例如,你可以修改串口配置、内存配置、网络协议等选项,以适配你的具体需求。 完成修改后,你可以保存文件,并返回到源代码的根目录。 最后,你需要运行编译命令来生成可执行的 u-boot 映像文件。通常情况下,你可以通过运行 `make` 命令来进行编译编译过程可能会耗费一些时间,请耐心等待。 当编译完成后,你可以在源代码目录下找到生成的 u-boot 映像文件。该文件一般以 `u-boot.bin` 或者 `u-boot.img` 的形式存在。 编译完成后,你可以将生成的 u-boot 映像文件烧录到 mt7621 平台的 Flash 存储器中,以替换原有的 u-boot 程序。 总而言之,编译 mt7621 的 u-boot 需要下载源代码、进行配置修改,并通过编译命令生成 u-boot 映像文件。最后,将生成的映像文件烧录到目标平台中。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值