参阅:
《嵌入式Linux运用开发彻底手册》 韦东山编著 第15章 移植 U-boot
http://xgc94418297.blog.163.com/blog/static/112966040200952971543686/
uboot是一段小程序,它在体系上电是开端履行,初始化硬件设备;准备好软件环境;最终调用操作体系内核。
这儿首要剖析移植进程。
U-boot中有几千个文件,要想了解关于某款开发板,运用哪些文件、哪个文件先履行、可履行文件占用内存的状况,最好的办法便是阅览它的Makefile文件。
要想运用哪款开发板就需首要履行“make
U-Boot.bin:二进制可履行文件,可直接烧入ROM、NORFLASH
U-Boot.elf
U-Boot.srec:Motorola S-Record格局的可履行文件
U-Boot编译指令
关于TX2440开发板,编译U-Boot需求履行如下的指令:
$makeTX2440_config
$makeall
运用上面的指令编译U-Boot,编译生成的一切文件都保存在源代码目录中。为了坚持源代码目录的洁净,能够运用如下指令将编译生成的文件输出到一个外部目录,而不是在源代码目录中,下面的2种办法都将编译生成的文件输出到/tmp/build目录:
$exportBUILD_DIR=/tmp/build
$makeTX2440_config
$makeall
或
$makeO=/tmp/buildTX2440_config(留意是字母O,而不是数字0)
$makeall
makeTX2440_config指令履行进程
下面剖析指令“makeTX2440_config”履行进程,为了简化剖析进程这儿首要剖析将编译方针输出到源代码目录的状况。
TX2410_config:unconfig
@$(MKCONFIG) $(@:_config=) arm arm920t TX2410 NULL s3c24x0
其间的依靠“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
其间“@”的效果是履行该指令时不在shell显现。“obj”变量便是编译输出的目录,因而“unconfig”的效果便是铲除前次履行make*_config指令生成的装备文件(如include/config.h,include/config.mk等)。
$(MKCONFIG)在上面指定为“$(SRCTREE)/mkconfig”。$(@:_config=)为将传进来的一切参数中的_config替换为空(其间“@”指规矩的方针文件名,在这儿便是“TX2440_config”。$(text:patternA=patternB),这样的语法表明把text变量每一个元素中结束的patternA的文本替换为patternB,然后输出)。因而$(@:_config=)的效果便是将TX2440_config中的_config去掉,得到TX2440。
因而@$(MKCONFIG) $(@:_config=) arm arm920t TX2440 NULL s3c24x0”实际上便是履行了如下指令:
./mkconfigTX2440arm arm920t TX2410 NULL s3c24x0
行将“TX2440arm arm920t TX2440 NULL s3c24x0”作为参数传递给当时目录下的mkconfig脚本履行。
在mkconfig脚本中给出了mkconfig的用法:
#Parameters:TargetArchitectureCPUBoard[VENDOR][SOC]
因而传递给mkconfig的参数的含义分别是:
TX2440:Target(方针板类型)
arm:Architecture(方针板的CPU架构)
arm920t:CPU(详细运用的CPU类型)
TX2440:Board
NULL:VENDOR(生产厂家名)
s3c24x0:SOC
下面分步剖析mkconfig的效果:
(1)确认开发板的称号BOARD_NAME
APPEND=no #no表明创立新的装备文件,yes表明追加到装备文件中
BOARD_NAME=”” #Nametoprintinmakeoutput
TARGETS=””
while[$#-gt0];do
case”$1″in
–)shift;break;;
-a)shift;APPEND=yes;;
-n)shift;BOARD_NAME=”${1%%_config}”;shift;;
-t)shift;TARGETS=”`echo$1|seds:_::g`${TARGETS}”;shift;;
*)break;;
esac
done
[“${BOARD_NAME}”]||BOARD_NAME=”$1″
环境变量$#表明传递给脚本的参数个数,这儿的指令有6个参数,因而$#是6。shift的效果是使$1=$2,$2=$3,$3=$4….,而本来的$1将丢掉。因而while循环的效果是,顺次处理传递给mkconfig脚本的选项。因为咱们并没有传递给mkconfig任何的选项,因而while循环中的代码不起效果。
最终将BOARD_NAME的值设置为$1的值,在这儿便是“TX2440”。
(2)创立到渠道/开发板的头文件衔接
33 if[“$SRCTREE”!=”$OBJTREE”];then/******判别源代码目录和方针文件目录是否相同,能够挑选在其他目录下编译U-boot这可令代码目录坚持洁净。咱们运用的是直接在源代码目录下编译的,第33行不满足,跳到else分支的代码******/
45 else
46 cd./include
47 rm-fasm
48 ln-sasm-$2asm
49 fi
50
第46~48行进入include目录,删去asm文件(上一次装备时树立的链接文件),然后再次树立asm文件,并令它链向 asm-$2目录,即asm-arm.
51 rm-fasm-$2/arch
52
53 if[-z”$6″-o”$6″=”NULL”];then
54 ln-s${LNPREFIX}arch-$3asm-$2/arch
55 else
56 ln-s${LNPREFIX}arch-$6asm-$2/arch
57 fi
树立符号链接include/asm-arm/arch,若$6(SOC)为空,则使其链接到include/asm-arm/arch-arm920t目录,不然就使其链接到include/asm-arm/arch-s3c24x0目录。(事实上include/asm-arm/arch-arm920t并不存在,因而$6是不能为空的,不然会编译失利)
59 if[“$2″=”arm”];then
60 rm-fasm-$2/proc
61 ln-s${LNPREFIX}proc-armvasm-$2/proc
62 fi
若方针板是arm架构,则上面的代码将树立符号衔接include/asm-arm/proc,使其链接到目录proc-armv目录。
树立以上的链接的优点:编译U-Boot时直接进入链接文件指向的目录进行编译,而不用依据不同开发板来挑选不同目录。
(3)创立顶层Makefile包含的文件include/config.mk
64 #
65 #CreateincludefileforMake
66 #
67 echo”ARCH=$2″>config.mk
68 echo”CPU=$3″>>config.mk
69 echo”BOARD=$4″>>config.mk
70
71 [“$5”]&&[“$5″!=”NULL”]&&echo”VENDOR=$5″>>config.mk
72
73 [“$6”]&&[“$6″!=”NULL”]&&echo”SOC=$6″>>config.mk
上面代码将会把如下内容写入文件inlcude/config.mk文件:
ARCH=arm
CPU=arm920t
BOARD=TX2440
SOC=s3c24x0
(4)创立开发板相关的头文件include/config.h
75 #
76 #Createboardspecificheaderfile
77 #
78 if[“$APPEND”=”yes”] #Appendtoexistingconfigfile
79 then
80 echo>>config.h
81 else
82 >config.h #Createnewconfigfile
83 fi
84 echo”/*Automaticallygenerated-donotedit*/”>>config.h
85 echo “#include
创立新的include/config.h文件。若APPEND为yes,则将新的装备内容追加到include/config.h文件后边。因为APPEND的值坚持“no”,因而config.h被创立了,内容如下:
/*Automaticallygenerated-donotedit*/
#include
下面总结指令makeTX2440_config履行的成果(仅针对编译方针输出到源代码目录的状况):
(1) 创立开发板称号BOARD_NAME等于$1
(2)创立到方针板相关的文件的链接
ln-sasm-armasm
ln-sarch-$6asm-$2/arch
ln-sproc-armvasm-arm/proc //假如$2不是arm,此行没有
(3)创立i顶层Makefile包含的文件 include/config.mk文件,内容如下所示:
ARCH=$2
CPU=$3
BOARD=$4
VENDOR=$5
SOC=$6
(4)创立与方针板相关的文件include/config.h,如下所示:
/*Automaticallygenerated-donotedit*/
#include
从这四个成果能够知道,假如要在board目录下新建一个开发板
装备文件中有两类宏:一类是选项(option)前缀为“CONFIG_”它们用于挑选CPU、SOC、开发板类型、设置体系时钟、挑选设备驱动。
如:#define CONFIG_ARM920T1/* This is an ARM920T Core*/
#defineCONFIG_S3C24101/* in a SAMSUNG S3C2410 SoC */
#define CONFIG_SMDK24101/* on a SAMSUNG SMDK2410 Board */
另一类是参数(setting),前缀为“CFG_”,它们用于设置malloc缓冲池的巨细、U-BOOT提示符、U-boot下载文件时的默许加载地址、FLASH的开始地址等
如:#defineCFG_LONGHELP/* undef to save memory*/
#defineCFG_PROMPT”SMDK2410 # “/* Monitor Command Prompt*/
#defineCFG_CBSIZE256/* Console I/O Buffer Size*/
#defineCFG_PBSIZE (CFG_CBSIZE+sizeof(CFG_PROMPT)+16) /* Print Buffer Size */
#defineCFG_MAXARGS16/* max number of command args*/
#define CFG_BARGSIZECFG_CBSIZE/* Boot Argument Buffer Size*/
能够这样以为,“CONFIG_”除了设置一些参数外,首要来设置U-Boot的功用、挑选运用文件中的哪一部分;而“CFG_”用来设置更细节的参数。
U-Boot的编译、链接进程
装备完后,履行“make all”既可编译,从Makefile中能够了解U-Boot运用了哪些文件、哪个文件首要履行、可履行文件占用内存状况。
若没有履行过“make
Systemnotconfigured-seeREADME
U-Boot是怎么知道用户没有履行过“make
ifeq($(obj)include/config.mk,$(wildcard$(obj)include/config.mk))#config.mk存在
all:
sinclude$(obj)include/autoconf.mk.dep
sinclude$(obj)include/autoconf.mk
……
else #config.mk不存在
……
@echo”Systemnotconfigured-seeREADME”>&2
@exit1
……
endif #config.mk
若include/config.mk文件存在,则$(wildcard$(obj)include/config.mk)指令履行的成果是“$(obj)include/config.mk”打开的字符串,不然成果为空。因为include/config.mk是“make
117 include$(obj)include/config.mk
118 export ARCHCPUBOARDVENDORSOC
119
127 ifeq($(HOSTARCH),arm)
128 CROSS_COMPILE=arm-linux-
127 endif
163 #loadotherconfiguration
164 include$(TOPDIR)/config.mk
第117和164行用于包含其他的config.mk文件,第117行所包含的文件便是在上面的装备进程中制造出来的include/config.mk文件,其间界说了ARCH、CPU、BOARD、SOC等4个变量的值为arm、arm920t、TX2440、s3c24x0。第164行包含顶层的config.mk文件,它依据上面4个变量的值确认了编译器、编译选项。其间对咱们了解编译进程有协助的是BOARDDIR、LDFLAGS的值
#U-Bootobjects….orderisimportant(i.e.startmustbefirst)
169 OBJS=cpu/$(CPU)/start.o
LIBS+=cpu/$(CPU)/lib$(CPU).a
ifdefSOC
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.afs/fat/libfat.afs/fdos/libfdos.afs/jffs2/libjffs2.a\
fs/reiserfs/libreiserfs.afs/ext2/libext2fs.afs/yaffs2/libyaffs2.a\
fs/ubifs/libubifs.a
……
LIBS+=common/libcommon.a
LIBS+=libfdt/libfdt.a
LIBS+=api/libapi.a
LIBS+=post/libpost.a
LIBS:=$(addprefix$(obj),$(LIBS))
LIBS变量指明晰U-Boot需求的库文件,包含渠道/开发板相关的目录、通用目录下相应的库,都经过相应的子目录编译得到的。
OBJS、LIBS所代表的.o、.a文件便是U-Boot的构成,他们经过如下指令由相应的源文件或相应的子目录下的文件编译得到
268 $(OBJS):
269 $(MAKE) -C cpu/$(CPU) $(if $(REMOTE_BUILD),$@,$(notdir $@))
271 $(LIBS):
272 $(MAKE) -C $(dir $(subst $(obj),,$@))
274 $(SUBDIRS):
275$(MAKE) -C $@ all
第268、269两行的规矩表明,关于OBJS中的每个成员,都将进入cpu/$(cpu)目录编译他们。现在OBJS为cpu/arm920t/start.o,它将由cpu/arm920t/start.s编译得到。第271、272两行规矩表明,关于LIBS中的每个成员,都将进入相应的子目录履行“make”指令。这些子目录中的Makefile,结构类似,他们将Makefile中指定的文件编译、链接成一个库文件。
当一切的OBJS、LIBS所表明的.o、.a文件都生成后就剩余链接了,这对用Makefile中如下代码
245 $(obj)u-boot.srec:$(obj)u-boot
246 $(OBJCOPY) ${OBJCFLAGS} -O srec $< $@
248 $(obj)u-boot.bin:$(obj)u-boot
249$(OBJCOPY) ${OBJCFLAGS} -O binary $< $@
251 $(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 $< $@
263 $(obj)u-boot.dis:$(obj)u-boot
254 $(OBJDUMP) -d $< > $@
265 $(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) \
266 –start-group $(__LIBS) –end-group $(PLATFORM_LIBS) \
267 -Map u-boot.map -o u-boot
263到267的规矩链接到ELF格局的U-Boot,最终转换为二进制格局的U-Boot.bin、S-Record格局的U-Boot.srec。LDFLAGS确认了衔接的方法。(前面有说到)。
剖析完这些对移植的全体概括应该有了一个知道,了解其原理了。详细要修正什么就要依据实际需求了。