uboot移植詳解
《嵌入式Linux應(yīng)用開發(fā)完全手冊》 韋東山編著 第15章 移植 U-boot
本文引用地址:http://butianyuan.cn/article/201611/316102.htmhttp://xgc94418297.blog.163.com/blog/static/112966040200952971543686/
uboot是一段小程序,它在系統(tǒng)上電是開始執(zhí)行,初始化硬件設(shè)備;準(zhǔn)備好軟件環(huán)境;最后調(diào)用操作系統(tǒng)內(nèi)核。
這里主要分析移植過程。
U-boot中有幾千個文件,要想了解對于某款開發(fā)板,使用哪些文件、哪個文件先執(zhí)行、可執(zhí)行文件占用內(nèi)存的情況,最好的方法就是閱讀它的Makefile文件。
要想使用哪款開發(fā)板就需首先執(zhí)行“make
U-Boot.bin:二進制可執(zhí)行文件,可直接燒入ROM、NORFLASH
U-Boot.elf
U-Boot.srec:Motorola S-Record格式的可執(zhí)行文件
U-Boot編譯命令
對于TX2440開發(fā)板,編譯U-Boot需要執(zhí)行如下的命令:
$makeTX2440_config
$makeall
使用上面的命令編譯U-Boot,編譯生成的所有文件都保存在源代碼目錄中。為了保持源代碼目錄的干凈,可以使用如下命令將編譯生成的文件輸出到一個外部目錄,而不是在源代碼目錄中,下面的2種方法都將編譯生成的文件輸出到/tmp/build目錄:
$exportBUILD_DIR=/tmp/build
$makeTX2440_config
$makeall
或
$makeO=/tmp/buildTX2440_config(注意是字母O,而不是數(shù)字0)
$makeall
makeTX2440_config命令執(zhí)行過程
下面分析命令“makeTX2440_config”執(zhí)行過程,為了簡化分析過程這里主要分析將編譯目標(biāo)輸出到源代碼目錄的情況。
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
其中“@”的作用是執(zhí)行該命令時不在shell顯示。“obj”變量就是編譯輸出的目錄,因此“unconfig”的作用就是清除上次執(zhí)行make*_config命令生成的配置文件(如include/config.h,include/config.mk等)。
$(MKCONFIG)在上面指定為“$(SRCTREE)/mkconfig”。$(@:_config=)為將傳進來的所有參數(shù)中的_config替換為空(其中“@”指規(guī)則的目標(biāo)文件名,在這里就是“TX2440_config”。$(text:patternA=patternB),這樣的語法表示把text變量每一個元素中結(jié)尾的patternA的文本替換為patternB,然后輸出)。因此$(@:_config=)的作用就是將TX2440_config中的_config去掉,得到TX2440。
因此@$(MKCONFIG) $(@:_config=) arm arm920t TX2440 NULL s3c24x0”實際上就是執(zhí)行了如下命令:
./mkconfigTX2440arm arm920t TX2410 NULL s3c24x0
即將“TX2440arm arm920t TX2440 NULL s3c24x0”作為參數(shù)傳遞給當(dāng)前目錄下的mkconfig腳本執(zhí)行。
在mkconfig腳本中給出了mkconfig的用法:
#Parameters:TargetArchitectureCPUBoard[VENDOR][SOC]
因此傳遞給mkconfig的參數(shù)的意義分別是:
TX2440:Target(目標(biāo)板型號)
arm:Architecture(目標(biāo)板的CPU架構(gòu))
arm920t:CPU(具體使用的CPU型號)
TX2440:Board
NULL:VENDOR(生產(chǎn)廠家名)
s3c24x0:SOC
下面分步分析mkconfig的作用:
(1)確定開發(fā)板的名稱BOARD_NAME
APPEND=no #no表示創(chuàng)建新的配置文件,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"
環(huán)境變量$#表示傳遞給腳本的參數(shù)個數(shù),這里的命令有6個參數(shù),因此$#是6。shift的作用是使$1=$2,$2=$3,$3=$4….,而原來的$1將丟失。因此while循環(huán)的作用是,依次處理傳遞給mkconfig腳本的選項。由于我們并沒有傳遞給mkconfig任何的選項,因此while循環(huán)中的代碼不起作用。
最后將BOARD_NAME的值設(shè)置為$1的值,在這里就是“TX2440”。
(2)創(chuàng)建到平臺/開發(fā)板的頭文件連接
33 if["$SRCTREE"!="$OBJTREE"];then/******判斷源代碼目錄和目標(biāo)文件目錄是否一樣,可以選擇在其他目錄下編譯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是不能為空的,否則會編譯失?。?/p>
59 if["$2"="arm"];then
60 rm-fasm-$2/proc
61 ln-s${LNPREFIX}proc-armvasm-$2/proc
62 fi
若目標(biāo)板是arm架構(gòu),則上面的代碼將建立符號連接include/asm-arm/proc,使其鏈接到目錄proc-armv目錄。
建立以上的鏈接的好處:編譯U-Boot時直接進入鏈接文件指向的目錄進行編譯,而不必根據(jù)不同開發(fā)板來選擇不同目錄。
(3)創(chuàng)建頂層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
上面代碼將會把如下內(nèi)容寫入文件inlcude/config.mk文件:
ARCH=arm
CPU=arm920t
BOARD=TX2440
SOC=s3c24x0
(4)創(chuàng)建開發(fā)板相關(guān)的頭文件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
創(chuàng)建新的include/config.h文件。若APPEND為yes,則將新的配置內(nèi)容追加到include/config.h文件后面。由于APPEND的值保持“no”,因此config.h被創(chuàng)建了,內(nèi)容如下:
/*Automaticallygenerated-donotedit*/
#include
下面總結(jié)命令makeTX2440_config執(zhí)行的結(jié)果(僅針對編譯目標(biāo)輸出到源代碼目錄的情況):
(1) 創(chuàng)建開發(fā)板名稱BOARD_NAME等于$1
(2)創(chuàng)建到目標(biāo)板相關(guān)的文件的鏈接
ln-sasm-armasm
ln-sarch-$6asm-$2/arch
ln-sproc-armvasm-arm/proc //如果$2不是arm,此行沒有
(3)創(chuàng)建i頂層Makefile包含的文件 include/config.mk文件,內(nèi)容如下所示:
ARCH=$2
CPU=$3
BOARD=$4
VENDOR=$5
SOC=$6
(4)創(chuàng)建與目標(biāo)板相關(guān)的文件include/config.h,如下所示:
/*Automaticallygenerated-donotedit*/
#include
從這四個結(jié)果可以知道,如果要在board目錄下新建一個開發(fā)板
配置文件中有兩類宏:一類是選項(option)前綴為“CONFIG_”它們用于選擇CPU、SOC、開發(fā)板類型、設(shè)置系統(tǒng)時鐘、選擇設(shè)備驅(qū)動。
如:#define CONFIG_ARM920T1/* This is an ARM920T Core*/
#defineCONFIG_S3C24101/* in a SAMSUNG S3C2410 SoC */
#define CONFIG_SMDK24101/* on a SAMSUNG SMDK2410 Board */
另一類是參數(shù)(setting),前綴為“CFG_”,它們用于設(shè)置malloc緩沖池的大小、U-BOOT提示符、U-boot下載文件時的默認(rèn)加載地址、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*/
可以這樣認(rèn)為,“CONFIG_”除了設(shè)置一些參數(shù)外,主要來設(shè)置U-Boot的功能、選擇使用文件中的哪一部分;而“CFG_”用來設(shè)置更細(xì)節(jié)的參數(shù)。
U-Boot的編譯、鏈接過程
配置完后,執(zhí)行“make all”既可編譯,從Makefile中可以了解U-Boot使用了哪些文件、哪個文件首先執(zhí)行、可執(zhí)行文件占用內(nèi)存情況。
若沒有執(zhí)行過“make
Systemnotconfigured-seeREADME
U-Boot是如何知道用戶沒有執(zhí)行過“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)命令執(zhí)行的結(jié)果是“$(obj)include/config.mk”展開的字符串,否則結(jié)果為空。由于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文件,它根據(jù)上面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需要的庫文件,包括平臺/開發(fā)板相關(guān)的目錄、通用目錄下相應(yīng)的庫,都通過相應(yīng)的子目錄編譯得到的。
OBJS、LIBS所代表的.o、.a文件就是U-Boot的構(gòu)成,他們通過如下命令由相應(yīng)的源文件或相應(yīng)的子目錄下的文件編譯得到
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兩行的規(guī)則表示,對于OBJS中的每個成員,都將進入cpu/$(cpu)目錄編譯他們?,F(xiàn)在OBJS為cpu/arm920t/start.o,它將由cpu/arm920t/start.s編譯得到。第271、272兩行規(guī)則表示,對于LIBS中的每個成員,都將進入相應(yīng)的子目錄執(zhí)行“make”命令。這些子目錄中的Makefile,結(jié)構(gòu)相似,他們將Makefile中指定的文件編譯、鏈接成一個庫文件。
當(dāng)所有的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_.*)/-u1/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的規(guī)則鏈接到ELF格式的U-Boot,最后轉(zhuǎn)換為二進制格式的U-Boot.bin、S-Record格式的U-Boot.srec。LDFLAGS確定了連接的方式。(前面有提到)。
分析完這些對移植的整體輪廓應(yīng)該有了一個認(rèn)識,了解其原理了。具體要修改什么就要根據(jù)實際需要了。
評論