首先进入uboot 根目录,首先配置,然后才能进行编译。
所以先执行make smdk2410_config进行配置:
在makefile里面可以找到这条指令对应执行的内容为:
smdk2410_config : unconfig
@$(MKCONFIG) $(@:_config=) arm arm920t smdk2410 NULL s3c24x0
这个分为7个部分,第一个部分是执行的shell脚本文件, 其他的都是需要传入这个脚本文件的参数。
那么执行的脚本文件是什么?在makefile里面查看MKCONFIG变量:
OBJTREE := $(if $(BUILD_DIR),$(BUILD_DIR),$(CURDIR))
SRCTREE := $(CURDIR)
TOPDIR := $(SRCTREE)
LNDIR := $(OBJTREE)
export TOPDIR SRCTREE OBJTREE
MKCONFIG := $(SRCTREE)/mkconfig
这个变量就是根目录里面的mkconfig脚本文件。
然后这个脚本文件的第一个参数是
$(@:_config=)
表示过滤smdk2410_config的_config部分,所以参数为 smdk2410
所以执行make smdk2410_config实际上就是执行了下面的这条指令:
mkconfig smdk2410 arm arm920t smdk2410 NULL s3c24x0
后面的参数在脚本文件里面的表示方法是:
mkconfig smdk2410 arm arm920t smdk2410 NULL s3c24x0
$0 $1 $2 $3 $4 $5 $6
也就是说$1-$6分别表示第一个到第六个参数
再来看下mkconfig这个脚本文件:
#!/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
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..."
#
# 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
if [ "$2" = "arm" ] ; then
rm -f asm-$2/proc
ln -s ${LNPREFIX}proc-armv asm-$2/proc
fi
#
# 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
#
# 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 <configs/$1.h>" >>config.h
exit 0
14行while循环,这一句判断 $1 ,case 条件是判断$1 是不是-a -n ,所以都不符合,循环无效,往下走;
23行[ "${BOARD_NAME}" ] || BOARD_NAME="$1" 表示如果BOARD_NAME有值那么就是本身,如果不是就执行BOARD_NAME="$1" ,也就表示BOARD_NAME=“smdk2410”;
25行:
[ $# -lt 4 ] && exit 1
[ $# -gt 6 ] && exit 1
其中$# 表示参数个数,这里表示如果参数个数小于4个退出,大于6个也退出。这里我们是6个参数,不会退出,继续执行;
然后在终端打印一行这个信息:
echo "Configuring for ${BOARD_NAME} board..." 实际上是 "Configuring for smdk2410 board..."
33行if [ "$SRCTREE" != "$OBJTREE" ] ; then 这一行条件不满足,两个变量的值在makefile前面就定义了。这里执行到46行:
cd ./include
rm -f asm
ln -s asm-$2 asm
rm -f asm-$2/arch
进入include目录,删除之前建立的旧asm,再建立一个新的链接文件asm,链接到asm-$2 也就是asm-arm,然后删除asm-arm里面的arch;
53行如果$6为空或者=NULL的话就执行ln -s ${LNPREFIX}arch-$3 asm-$2/arch,这里显然条件不满足,所以执行ln -s ${LNPREFIX}arch-$6 asm-$2/arch创建一个新的arch文件,LNPREFIX未定义,所以为空,所以这句话相当于执行:ln -s arch-s3c24x0 asm-arm/arch 创建的arch链接到arch-s3c24x0文件夹;
59行if [ "$2" = "arm" ] ; 成立,执行:
rm -f asm-$2/proc
ln -s ${LNPREFIX}proc-armv asm-$2/proc
删除asm-arm/proc链接文件,创建新的proc文件链接到proc-armv文件夹;
上面创建了三个链接文件,创建的目的就是为了统一头文件在源代码里面的名称都为同一个名称,和具体平台和架构的名称无关,这样代码里面类似#include "arch-s3c24x0/memory" 这样的语句就可以用 #include "arch/memory" 来表示了。变换平台就不需要修改代码了。
67-69行:
echo "ARCH = $2" > config.mk #>表示创建文件
echo "CPU = $3" >> config.mk #>>表示往文件里面写数据
echo "BOARD = $4" >> config.mk
创建一个config.mk文件,并写入信息:
ARCH=arm
CPU=arm920t
BOARD=smdk2410
71行
[ "$5" ] && [ "$5" != "NULL" ] && echo "VENDOR = $5" >> config.mk #如果5参数存在而且不等于NULL 那么写入VENDOR = $5 到config.mk
[ "$6" ] && [ "$6" != "NULL" ] && echo "SOC = $6" >> config.mk #如果6参数存在而且不等于NULL 那么写入SOC = $6 到config.mk
所以SOC = s3c24x0 也写入config.mk ;
78行if [ "$APPEND" = "yes" ] APPEND 变量在第11行定义为no,所以条件不成立,执行> config.h 创建config.h 文件;
最后将"/* Automatically generated - do not edit */" 与"#include <configs/$1.h>" 写入config.h文件,也就是"#include <configs/smdk2410.h>" 。
最后退出。
所以通过解读shell脚本,实际上运行的脚本如下:
APPEND=no # Default: Create new config file
BOARD_NAME="" # Name to print in make output
BOARD_NAME="smdk2410"
echo "Configuring for smdk2410 board..."
cd ./include
rm -f asm
ln -s asm-arm asm
rm -f asm-arm/arch
ln -s arch-s3c24x0 asm-arm/arch
rm -f asm-arm/proc
ln -s proc-armv asm-$2/proc
echo "ARCH = arm" > config.mk
echo "CPU = arm920t" >> config.mk
echo "BOARD = smdk2410" >> config.mk
echo "SOC = s3c24x0" >> config.mk
> config.h # Create new config file
echo "/* Automatically generated - do not edit */" >>config.h
echo "#include <configs/smdk2410.h>" >>config.h
exit 0
这就是配置过程做的事情,再来看下makefile编译部分:
编译uboot直接用make命令进行编译;
在输入make的时候,实际上就是执行make all
我们在makefile里面找到这个入口点:239行,前面都是些变量赋值等操作,这里是真正要执行的编译工作。
#########################################################################
#########################################################################
ALL = $(obj)u-boot.srec $(obj)u-boot.bin $(obj)System.map $(U_BOOT_NAND)
all: $(ALL)
$(obj)u-boot.hex: $(obj)u-boot
$(OBJCOPY) ${OBJCFLAGS} -O ihex $< $@
$(obj)u-boot.srec: $(obj)u-boot
$(OBJCOPY) ${OBJCFLAGS} -O srec $< $@
$(obj)u-boot.bin: $(obj)u-boot
$(OBJCOPY) ${OBJCFLAGS} -O 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.dis: $(obj)u-boot
$(OBJDUMP) -d $< > $@
$(obj)u-boot: depend version $(SUBDIRS) $(OBJS) $(LIBS) $(LDSCRIPT)
UNDEF_SYM=`$(OBJDUMP) -x $(LIBS) |sed -n -e 's/.*\(__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
$(OBJS):
$(MAKE) -C cpu/$(CPU) $(if $(REMOTE_BUILD),$@,$(notdir $@))
$(LIBS):
$(MAKE) -C $(dir $(subst $(obj),,$@))
$(SUBDIRS):
$(MAKE) -C $@ all
$(NAND_SPL): version
$(MAKE) -C nand_spl/board/$(BOARDDIR) all
$(U_BOOT_NAND): $(NAND_SPL) $(obj)u-boot.bin
cat $(obj)nand_spl/u-boot-spl-16k.bin $(obj)u-boot.bin > $(obj)u-boot-nand.bin
version:
@echo -n "#define U_BOOT_VERSION \"U-Boot " > $(VERSION_FILE); \
echo -n "$(U_BOOT_VERSION)" >> $(VERSION_FILE); \
echo -n $(shell $(CONFIG_SHELL) $(TOPDIR)/tools/setlocalversion \
$(TOPDIR)) >> $(VERSION_FILE); \
echo "\"" >> $(VERSION_FILE)
gdbtools:
$(MAKE) -C tools/gdb all || exit 1
updater:
$(MAKE) -C tools/updater all || exit 1
env:
$(MAKE) -C tools/env all || exit 1
depend dep:
for dir in $(SUBDIRS) ; do $(MAKE) -C $$dir _depend ; done
tags ctags:
ctags -w -o $(OBJTREE)/ctags `find $(SUBDIRS) include \
lib_generic board/$(BOARDDIR) cpu/$(CPU) lib_$(ARCH) \
fs/cramfs fs/fat fs/fdos fs/jffs2 \
net disk rtc dtt drivers drivers/sk98lin common \
\( -name CVS -prune \) -o \( -name '*.[ch]' -print \)`
etags:
etags -a -o $(OBJTREE)/etags `find $(SUBDIRS) include \
lib_generic board/$(BOARDDIR) cpu/$(CPU) lib_$(ARCH) \
fs/cramfs fs/fat fs/fdos fs/jffs2 \
net disk rtc dtt drivers drivers/sk98lin common \
\( -name CVS -prune \) -o \( -name '*.[ch]' -print \)`
$(obj)System.map: $(obj)u-boot
@$(NM) $< | \
grep -v '\(compiled\)\|\(\.o$$\)\|\( [aUw] \)\|\(\.\.ng$$\)\|\(LASH[RL]DI\)' | \
sort > $(obj)System.map
从代码可以为了产生最后我们想要的文件,有很多依赖关系,太复杂了,没时间分析了。只能通过在开发板上make一下uboot才能知道哦具体干了些什么事情;具体就不详述了,总之最后我们知道的信息有几点:
1 uboot代码的入口在哪里 ---- cpu/$(CPU)/start.S
2 uboot代码放在SDRAM的哪个地址开始运行 ---- 在链接的时候通过board/$(BOARD)/config.mk里面设置TEXT_BASE指定的,
TEXT_BASE 表示board/$(BOARD)/u-boot.lds链接脚本里面的text段运行的地址,而cpu/$(CPU)/start.o放在text段的最开始,所以从TEXT_BASE开始运行。