U-Boot的配置编译过程


U-Boot,全称 Universal BootLoader,官方名称为 DENX U-Boot 或者 Das U-Boot,是嵌入式系统业内用的最多的BootLoader。之所以能在名字开头冠以 Universal 一字,原因之一,是因为它能支持众多的CPU体系结构,包括x86,powerpc,mips,arm,blackfin等等;原因之二,是因为它能在上面这些体系结构中引导相当多的操作系统,包括Linux,VxWorks,NetBSD,QNX等等。因此我们说,其名并非虚传。

现今网路上关于UBoot的资料已相当多,但其针对的,却多是X.Y.Z形式的老旧版本。其实,自2008年年底以来,UBoot新版本的发行机制就改了,现在基本上是每两个月出一个新的版本,其对应的版本号就是 YYYY.MM 的形式。相对于老旧版本的UBoot,代码的布局、内容等方面都已经做出了修改,而且在官方的新版本中也加入了对yaffs2文件系统的支持,这在老版本中是需要自己动手加的。

 所以,虽然我们说前后版本不同、原理却相同,但是对一个新手来说,拿新版本来学习研究和移植自然是有现实意义的。本人不才,但在嵌入式Linux开发方面却稍有经验。所以为帮助那些新手少走弯路,也为追求一份因帮助过别人才能得到的快乐,我考虑将自己移植新版本UBoot的经验体会,记录成一系列的文章,发表在我位于JulianTec的博客上。大家可以自由转载以供学习研究之用,当然,写明出处是起码也是必要的。

我手上待移植的板子,是JulianTec设计监制并提供的,其上使用的CPU(SOC, actually)是三星提供的ARM9芯片S3C2440。要往这样一块板子上移植UBoot,第一步显然是下载官方发布的新版本UBoot代码(我这里使用的新版本是2010.06),下载下来解压后,作为开发人员的本能反应就是找出解压目录中的README、INSTALL之类的文件,打开并详加研读,希望找出移植所需要的第一手信息。(我在这里废话那么多,是希望我们的新手也能养成如此的习惯,并使之质变为本能。)

根据README中 Porting Guide 的指示精神,我们要在新板子上移植UBoot,最快速的办法就是查看当前UBoot代码中是否有对相似于待移植板子的其他板子的支持(这应该又是一个可考虑成为习惯甚至本能的做法。也即拿到不熟悉的软件包后,看看里面有没有自己熟悉的、或者和自己目前要做的东西很相似的部分,从这个部分入手往往能很快的解决问题)。很幸运,我们在里面找到了三星公司所生产的SMDK2410参考板,这是三星公司早先为推销其生产的ARM9芯片-S3C2410所推出的一块PCB参考设计板(推出时随板子附加了很多的软硬件资料)。知道这个后,我们很高兴,因为我们知道我们板子上的CPU——S3C2440正是S3C2410的升级版。所以,在真正动手移植之前,分析一下新版本UBoot中如何支持SMDK2410的,自然成为接下来要做的事情。

UBoot本身是用GNU工具链开发的,那这就意味着其代码包里面必然会有很多的Makefile文件,因为GNU Make正是用来管理软件项目编译的GNU工具。而且,正如我们前面说的,UBoot能支持如此多的CPU体系结构和操作系统,那它就必定会有很多的配置选项用于配置。所以分析支持SMDK2410参考板的具体代码之前,我们必须先弄懂UBoot的配置编译过程。我们只有对此了然于胸了,才能比较顺利的完成移植。所幸的是,不像Linux内核代码,UBoot的代码量并不多,分析起来并不痛苦。

作为UBoot学习移植系列的第一篇文章,我在这里就以SMDK2410板子的支持作为例子,分析新版本UBoot(2010.06)的配置编译过程。作为前提,你应该知道一些GNU Make以及一些Bash Shell Script的知识。但是,为帮助你理解,我在相对应的地方也会做出一些解释,你如果有不明白的地方,可直接在Mail List上进行交流,或直接发邮件向我咨询。

从UBOOT用户的角度来讲,其编译配置过程倒是非常的简单,只需要在命令行中切换到UBoot目录下输入两个命令:

[csicong@juliantec u-boot-2010.06]$ make ARCH=arm CROSS_COMPILE=arm-linux- smdk2410_config
[csicong@juliantec u-boot-2010.06]$ make ARCH=arm CROSS_COMPILE=arm-linux-

第一个命令完成UBoot for smdk2410参考板的配置,第二个命令则真正编译出所需要的 UBoot 二进制映像文件,编译出来之后我们需要将其下载到FLASH中。在这两个命令中,参数ARCH表示我们要给具有何种体系结构的CPU编译UBoot,因为不管SMDK2410参考板上的CPU——S3C2410,还是我手头板子上的CPU,皆为ARM9芯片,所以这里显然应该为arm;CROSS_COMPILE为交叉编译工具链各工具的名称前缀。我们需要用到arm-linux-gcc作为编译器、arm-linux-ld为链接器。。。所以这里取值为 arm-linux- 。

在第一个命令中,我们以 smdk2410_config 作为本次 make 的目标。查找UBoot项目顶层 Makefile 得到关于此目标的规则如下:

smdk2410_config :       unconfig
        @$(MKCONFIG) $(@:_config=) arm arm920t smdk2410 samsung s3c24x0

根据 Makefile 规则的定义,GNU Make在处理这条规则的时候,先判断其依赖——也就是 unconfig 是否需要更新。而我们在同一Makefile中找到 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

由于目录下没有一个叫 unconfig 的文件存在,所以和 unconfig 相关的这条规则总是得到处理,也就是其中的 rm 命令总是得到执行,该命令的目的是删除一些配置编译过程中产生的文件。在这些文件中,与本文讨论密切相关的是前面两个,以及后面两个。前面两个是用第一条命令来配置UBoot的过程中产生的,后面则是用第二条命令来编译UBoot的过程中产生的。这条规则先把他们全部删除。注意rm命令前面的@符号是取消该命令执行时的回显。

执行完对依赖——unconfig的处理,GNU Make 回到对 smdk2410_config 的处理。它接下来执行命令:

       @$(MKCONFIG) $(@:_config=) arm arm920t smdk2410 samsung s3c24x0

在这条命令中,$(MKCONFIG) 指代的就是 UBoot 根目录下的 mkconfig 脚本,因为你可以在同一Makefile中找到该变量的定义:

MKCONFIG        := $(SRCTREE)/mkconfig
export MKCONFIG

其中 $(SRCTREE) 指代的就是UBoot 根目录。另外在上面的命令中,$(@:_config=) 的部分实际上是处理自动变量 $@,也就是第一次 make 的目标 smdk2410_config,这里将其中"_config"的部分用空来代替。去掉"_config"的部分后,剩余的 smdk2410 也就是三星参考板的名称。所以最后上面的命令也就可直接写作:

        ./mkconfig smdk2410 arm arm920t smdk2410 samsung s3c24x0

很清楚,执行 mkconfig 脚本,并传之以所在的目录名称,sansung 是产商名称,s3c24x0是对应的SOC芯片名称。有人对arm920和s3c24x0两者所指东西混淆不清,我自己在平时为方便起见也经常混用这两个词,有时候也将它们统称为CPU。但实际上,更精确的说法认为arm920t是arm9类型的CPU核,而s3c2410则是用该核搭配另外一些外设做在一块芯片内形成的SOC芯片。由于三星本身出了很多使用arm920tCPU核的芯片,如s3c2400、s3c2410以及s3c2440,所以在UBoot代码中,用s3c24x0来统称这一类SOC芯片。

mkconfig 脚本是 bash 脚本。对应于smdk2410参考板,其主要做三件事情:

1,在include目录下制作一些软连接,参见代码:

#
# 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}/arch/$2/include/asm asm
        LNPREFIX=${SRCTREE}/arch/$2/include/asm/
        cd ../include
        rm -f asm
        ln -s ${SRCTREE}/arch/$2/include/asm asm
else
        cd ./include
        rm -f asm
        ln -s ../arch/$2/include/asm asm
fi
 
rm -f asm/arch
 
if [ -z "$6" -o "$6" = "NULL" ] ; then
        ln -s ${LNPREFIX}arch-$3 asm/arch
else
        ln -s ${LNPREFIX}arch-$6 asm/arch
fi
 
if [ "$2" = "arm" ] ; then
        rm -f asm/proc
        ln -s ${LNPREFIX}proc-armv asm/proc
fi

由于我们编译UBoot时,通常都是在UBoot原有目录下编译的,并且针对smdk2410参考板,"$2"="arm","$6"="s3c24x0",所以,以上代码的效果等同于我们用下面这些命令来手工创建软连接。

[csicong@juliantec include]$ ln -s ../arch/arm/include/asm ./asm
[csicong@juliantec include]$ ln -s arch-s3c24x0 ./asm/arch
[csicong@juliantec include]$ ln -s proc-armv ./asm/proc

2, 在include目录下制作顶层Makefile要包含的文件 include/config.mk,参见代码:

#
# 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

很明显,制作出来的文件 include/config.mk,其内容非常简单,只包括 ARCH、CPU、BOARD、VENDOR、SOC等变量的定义。后面我们会知道,这个文件虽然简单,但是却决定了顶层 Makefile的一大部分逻辑框架。

  • 1
  • 2
  • 3
  • 4
  • 下一页

相关内容