这里使用九鼎X210开发板的uboot来做分析。uboot版本号u-boot 1.3.4
VERSION = 1
PATCHLEVEL = 3
SUBLEVEL = 4
EXTRAVERSION =
U_BOOT_VERSION = $(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
VERSION_FILE = $(obj)include/version_autogenerated.h
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/')
export HOSTARCH HOSTOS
#Deal with colliding definitions from tcsh etc.
VENDOR=
HOSTARCH
-这里定义主机系统架构和操作系统,使用ubuntu和intel的电脑的情况下一般是i386和i686,这里sed指令后面的i.86
中的.
是通配符,这里满足所有i.86
的宿主机都改为i386
。|
是管道符,表示将前面的参数传递给后面使用。HOSTOS
-定义宿主机的操作系统,使用ubuntu系统的话,这里的操作系统是Linux,然后后面将所有字符转换为大写,然后再转换为小写,最后宿主机操作系统名称为linuxexport
将宿主机型号和操作系统声明为全局变量,供其他文件使用VENDOR
设置厂商,这里设置为空#Allow for silent builds
ifeq (,$(findstring s,$(MAKEFLAGS)))
XECHO = echo
else
XECHO = :
endif
MAKEFLAGS
表示在执行makefile的时候,在make后面添加的标志,如果没有找到s,则定义XECHO为echo,否则定义XECHO为空(这里:
在bash中表示空命令,只起到占位符的作用)#########################################################################
#
#U-boot build supports producing a object files to the separate external
#directory. Two use cases are supported:
#
#1) Add O= to the make command line
#'make O=/tmp/build all'
#
#2) Set environement variable BUILD_DIR to point to the desired location
#'export BUILD_DIR=/tmp/build'
#'make'
#
#The second approach can also be used with a MAKEALL script
#'export BUILD_DIR=/tmp/build'
#'./MAKEALL'
#
#Command line 'O=' setting overrides BUILD_DIR environent variable.
#
#When none of the above methods is used the local build is performed and
#the object files are placed in the source directory.
#
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),)
OBJTREE := $(if $(BUILD_DIR),$(BUILD_DIR),$(CURDIR))
SRCTREE := $(CURDIR)
TOPDIR := $(SRCTREE)
LNDIR := $(OBJTREE)
export TOPDIR SRCTREE OBJTREE
MKCONFIG := $(SRCTREE)/mkconfig
export MKCONFIG
ifneq ($(OBJTREE),$(SRCTREE))
REMOTE_BUILD := 1
export REMOTE_BUILD
endif
#$(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
#Make sure CDPATH settings don't interfere
unexport CDPATH
#########################################################################
make O=/tmp/build all
#load ARCH, BOARD, and CPU configuration
include $(obj)include/config.mk
export ARCH CPU BOARD VENDOR SOC
这里包含了一个config.mk文件,这个文件在uboot源码里面找不到,是我们在配置uboot时生成的(从obj这个变量也可以看出是在编译的时候生成的)具体在配置的哪个阶段生成的?还需要看配置过程(具体参考mkconfig脚本文件)。
config.mk具体内容如下
ARCH = arm
CPU = s5pc11x
BOARD = x210
VENDOR = samsung
SOC = s5pc110
这里包含了config.mk文件后,将ARCH、CPU、BOARD、VENDOR、SOC声明为全局变量,这里面主要是配置相关的内容。关于config.mk的生成过程如下。
#### 1.1 config.mk文件的生成过程
在配置uboot的时候,使用命令make x210_sd_config
,该命令执行了makefile中x210_sd_config
目标,该目标的定义如下:
MKCONFIG := $(SRCTREE)/mkconfig
export MKCONFIG
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 \
$(obj)board/$(VENDOR)/$(BOARD)/config.mk
x210_sd_config : unconfig
@$(MKCONFIG) $(@:_config=) arm s5pc11x x210 samsung s5pc110
@echo "TEXT_BASE = 0xc3e00000" > $(obj)board/samsung/x210/config.mk
X210_sd_config有一个依赖,因此,在执行目标时,先执行该依赖,unconfig依赖主要清除了旧的配置文件,然后执行新的配置,配置过程如下:
首先MKCONFIG表示顶层目录下mkconfig脚本,这里执行mkconfig脚本,并且给该脚本传递6个参数,这六个参数分别是
执行第二句,在board/samsung/x210文件夹下面新建一个config.mk文件,并将字符串TEXT_BASE = 0xc3e00000
写入文件中
mkconfig脚本实现了uboot配置阶段的大部分工作。
APPEND=no # Default: Create new config file
BOARD_NAME="" # Name to print in make output
while [ $# -gt 0 ] ; do
case "$1" in
--) shift ; break ;;
-a) shift ; APPEND=yes ;;
-n) shift ; BOARD_NAME="${1%%_config}" ; shift ;;
*) break ;;
esac
done
[ "${BOARD_NAME}" ] || BOARD_NAME="$1"
[ $# -lt 4 ] && exit 1
[ $# -gt 6 ] && exit 1
echo "Configuring for ${BOARD_NAME} board..."
- 这里我们没有给mkconfig文件传递-- -a -n等参数,因此,在while中匹配\*,执行break,跳出while循环
- BOARD\_NAME没有定义,是空,因此,\[ "${BOARD\_NAME}" ]结果是false,需要执行后面的语句,BOARD\_NAME的值为传递的第一个参数,即X210\_sd
- 参数小于4个或者大于六个,就返回1,表示错误
- 最后打印出配置提示文本
#
#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
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
- 这里判断目标文件和源文件是否在同一目录,在同一个目录执行else,不在同一个目录执行then后面的,这里我们在同一个目录,则进入到./include文件夹下,删除asm文件,然后给asm-arm文件创建符号链接asm
- 删除asm-arm文件夹下面的arch文件
- 判断第六个参数是否为空,这里不为空,就给arch-s5pc110建立符号链接asm-arm/arch
#create link for s5pc11x SoC
if [ "$3" = "s5pc11x" ] ; then
rm -f regs.h
ln -s $6.h regs.h
rm -f asm-$2/arch
ln -s arch-$3 asm-$2/arch
fi
- 这里判断$3为s5pc11x,则会删除regs.h,给s5pc110.h建立regs.h符号链接
- 删除asm-arm/arch文件,然后给arch-s5pc11x 建立符号链接asm-arm/arch
if [ "$2" = "arm" ] ; then
rm -f asm-$2/proc
ln -s ${LNPREFIX}proc-armv asm-$2/proc
fi
- 这里给asm-arm/proc-armv创建符号链接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
- 这里创建config.mk文件,并向里面写入ARCH、CPU、BOARD、VENDOR、SOC,这个文件就是主Makefile包含的文件(上文分析的文件)
#
#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
echo "#include $1 .h>" >>config.h
exit 0
- 这里在include文件夹下创建config.h头文件,并向里面写入`#include `
- 执行完之后,`exit 0`返回,表示执行成功
分析完mkconfig文件之后,可以返回主Makefile继续分析剩余部分。
ifndef CROSS_COMPILE
ifeq ($(HOSTARCH),$(ARCH))
CROSS_COMPILE =
else
ifeq ($(ARCH),arm)
#CROSS_COMPILE = arm-linux-
#CROSS_COMPILE = /usr/local/arm/4.4.1-eabi-cortex-a8/usr/bin/arm-linux-
#CROSS_COMPILE = /usr/local/arm/4.2.2-eabi/usr/bin/arm-linux-
CROSS_COMPILE = /usr/local/arm/arm-2009q3/bin/arm-none-linux-gnueabi-
endif
endif # HOSTARCH,ARCH
endif # CROSS_COMPILE
export CROSS_COMPILE
#load other configuration
include $(TOPDIR)/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
#Load generated board configuration
sinclude $(OBJTREE)/include/autoconf.mk
CONFIG_CMD_FAT=y
CONFIG_USB_OHCI=y
CONFIG_SYS_CLK_FREQ=24000000
CONFIG_CMD_ITEST=y
CONFIG_S3C_HSMMC=y
CONFIG_DISPLAY_BOARDINFO=y
CONFIG_CMD_XIMG=y
CONFIG_CMD_CACHE=y
CONFIG_STACKSIZE="0x40000"
CONFIG_BOOTDELAY=3
CONFIG_CHECK_MPLL_LOCK=y
CONFIG_NR_DRAM_BANKS=2
CONFIG_ETHADDR="00:40:5c:26:0a:5b"
CONFIG_CMD_CONSOLE=y
CONFIG_SW_WORKAROUND=y
CONFIG_GATEWAYIP="192.168.0.1"
CONFIG_DRIVER_DM9000=y
CONFIG_ZIMAGE_BOOT=y
CONFIG_CMD_REGINFO=y
CONFIG_MMC=y
CONFIG_NAND_BL1_8BIT_ECC=y
CONFIG_CMD_MISC=y
CONFIG_ZERO_BOOTDELAY_CHECK=y
CONFIG_ENV_OVERWRITE=y
CONFIG_CMD_NET=y
CONFIG_CMD_NFS=y
ifdef ARCH
sinclude $(TOPDIR)/$(ARCH)_config.mk # include architecture dependend rules
endif
ifdef CPU
sinclude $(TOPDIR)/cpu/$(CPU)/config.mk # include CPU specific rules
endif
ifdef SOC
sinclude $(TOPDIR)/cpu/$(CPU)/$(SOC)/config.mk # include SoC specific rules
endif
ifdef VENDOR
BOARDDIR = $(VENDOR)/$(BOARD)
else
BOARDDIR = $(BOARD)
endif
ifdef BOARD
sinclude $(TOPDIR)/board/$(BOARDDIR)/config.mk # include board specific rules
endif
ifndef LDSCRIPT
#LDSCRIPT := $(TOPDIR)/board/$(BOARDDIR)/u-boot.lds.debug
ifeq ($(CONFIG_NAND_U_BOOT),y)
LDSCRIPT := $(TOPDIR)/board/$(BOARDDIR)/u-boot-nand.lds
else
LDSCRIPT := $(TOPDIR)/board/$(BOARDDIR)/u-boot.lds
endif
endif
LDFLAGS += -Bstatic -T $(LDSCRIPT) $(PLATFORM_LDFLAGS)
ifneq ($(TEXT_BASE),)
LDFLAGS += -Ttext $(TEXT_BASE)
endif
ifndef REMOTE_BUILD
%.s: %.S
$(CPP) $(AFLAGS) -o $@ $<
%.o: %.S
$(CC) $(AFLAGS) -c -o $@ $<
%.o: %.c
$(CC) $(CFLAGS) -c -o $@ $<
else
$(obj)%.s: %.S
$(CPP) $(AFLAGS) -o $@ $<
$(obj)%.o: %.S
$(CC) $(AFLAGS) -c -o $@ $<
$(obj)%.o: %.c
$(CC) $(CFLAGS) -c -o $@ $<
endif
回到主Makefile,接着往下,就是make编译的目标(这里只截取部分代码)
ALL += $(obj)u-boot.srec $(obj)u-boot.bin $(obj)System.map $(U_BOOT_NAND) $(U_BOOT_ONENAND) $(obj)u-boot.dis
ifeq ($(ARCH),blackfin)
ALL += $(obj)u-boot.ldr
endif
all: $(ALL)
$(obj)u-boot.hex: $(obj)u-boot
$(OBJCOPY) ${OBJCFLAGS} -O ihex $< $@
$(obj)u-boot.srec: $(obj)u-boot
$(OBJCOPY) ${OBJCFLAGS} -O srec $< $@
########以下部分省略
这就是make执行uboot编译的时候执行的目标文件,执行整个uboot的编译链接过程,最终生成uboot.bin文件