摘要:作用是將標準輸入中的所有大寫字母轉換為響應的小寫字母。的移植過的源代碼是在源代碼目錄下編譯的,所以源代碼目錄等于目標文件目錄,所以條件不滿足,將執行分支的代碼。
????????一個嵌入式產品的開發階段,需要不斷地把bootloader下載到存儲器中,如果存儲器使用nand flash,但是第一次里面什么都沒有,所以只能根據處理器的啟動方式從其他方式啟動如sd卡或nor存儲器啟動,然后在SD卡或nor存儲器啟動的基礎之上使用USB或網絡接口把u-boot.bin先下載到內存中,然后再把內存中的內容寫到nand中,但是寫前4頁時只能寫每頁的前2KB數據(對于OK6410開發板來說,處理器使用S3C6410處理器,nand使用每頁4KB的存儲器,當從nand啟動時,處理器會自動地把nand的前4頁的每一頁的前2KB拷貝片內8KB的SRAM中運行,這是處理器硬件所決定,所以這里只能存每一頁的前2KB),前4頁后的所有頁都是全寫。
????????由于u-boot開發中需要不斷調試u-boot,而此時nand中已經有u-boot,所以可以從nand存儲器啟動,然后根據開發的下載模式下的菜單選項,可以重新下載u-boot到nand中。
????????當u-boot開發好后,并且從nand啟動,一上電,處理器硬件會自動把nand flash的前4頁中每頁前2KB拷貝到片內SRAM中運行,而在SRAM中運行的代碼又實現了把nand中從0到240KB(這個大小可以變)的代碼拷貝到內存,然后跳到內存中運行,它在內存運行時,會申請更多的空間(除開本身占用的內存空間外,會包括12字節用于abort異常、堆棧空間、malloc內存池空間、環境參數空間、某些全局變量空間),總共2MB,詳細查看(三.2.1)u-boot內存分布圖。
????????一個嵌入式產品出廠時,在nand 存儲器里面已經有了u-boot、內核、文件系統,并能實現對應功能(如果使用nand存儲器,那么編譯好的映像是存儲在nand中的,運行是在內存中運行,對于S3C6410,先在8KB片內SRAM運行,然后才跳到內存DDR中運行)。U-boot運行時會把nand里的內核映像拷貝到內存,然后運行內核。
一、U-Boot-1.1.6頂層Makefile文件分析
(頂層makefile文件內容為黑色,其他文件中的內容為藍色,移植時修改過的代碼為紅色)
?????? 根據uboot根目錄下的Readme文件的說明,可以知道如果想把u-boot使用于開發板,應先配置,即執行make orlinx_nand_ram256_config命令進行配置(在頂層目錄Makefile中加入forlinx_nand_ram256_config目標等選項),然后執行make all,就可以生成如下3個文件:U-Boot.bin、U-Boot ELF格式文件、U-Boot.srec。
????????(1)版本說明
VERSION = 1PATCHLEVEL = 1SUBLEVEL = 6EXTRAVERSION =U_BOOT_VERSION = $(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)VERSION_FILE = $(obj)include/version_autogenerated.h
(2)定義主機系統架構
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/macppc/ppc/)
????????“sed? –e”表示后面跟的是一串命令腳本,而表達式“s/abc/def/”表示要從標準輸入中,查找到內容為“abc”的,然后替換成“def”。其中“abc”表達式用可以使用“.”作為通配符。命令“uname –m”將輸出主機 CPU 的體系架構類型。如電腦使用 Intel Core2 系列的CPU,那么 “uname? –m”將輸出“i686”。 “i686”可以匹配命令“sed? -e s/i.86/i386/”中的“i.86”,因此在機器上執行 Makefile,HOSTARCH 將被設置成“i386” 。
(3)定義主機操作系統類型
HOSTOS := $(shell uname -s | tr "[:upper:]" "[:lower:]" | / sed -e "s//(cygwin/).*/cygwin/")export HOSTARCH HOSTOS# Deal with colliding definitions from tcsh etc.VENDOR=
????????“uname? –s”輸出主機內核名字,開發主機使用 Linux 發行版 fedora-12,因此“uname? –s”結果是“Linux”?!皌r "[:upper:]" "[:lower:]"”作用是將標準輸入中的所有大寫字母轉換為響應的小寫字母。因此執行結果是將 HOSTOS 設置為“linux”。
(4)定義執行shell腳本的shell(源碼中沒有這部分)
# Set shell to bash if possible, otherwise fall back to shSHELL := $(shell if [ -x "$$BASH" ]; then echo $$BASH; /else if [ -x /bin/bash ]; then echo /bin/bash; /else echo sh; fi; fi)
????????"$$BASH"的作用實質上是生成了字符串“$BASH”(前一個$號的作用是指明第二個$是普通的字符)。若執行當前 Makefile 的 shell 中定義了“$BASH”環境變量,且文件“$BASH”是可執行文件,則 SHELL 的值為“$BASH”。否則,若“/bin/bash”是可執行文件,則 SHELL 值為“/bin/bash”。若以上兩條都不成立,則將“sh”賦值給 SHELL 變量。如果機器安裝了bash? shell,且shell 默認環境變量中定義了“$BASH”,因此 SHELL 被設置為$BASH 。
(5)設定編譯輸出目錄
ifdef O ifeq ("$(origin O)", "command line")BUILD_DIR := $(O)endifendif
????????函數$( origin, variable) 輸出的結果是一個字符串,輸出結果由變量 variable 定義的方式決定,若 variable 在命令行中定義過,則origin函數返回值為"command line"。假若在命令行中執行了“export BUILD_DIR=/tmp/build”的命令,則“$(origin O)”值為“command line”,而 BUILD_DIR 被設置為“/tmp/build”。
????????下面內容表示若${BUILD_DIR}表示的目錄沒有定義,則創建該目錄:
ifneq ($(BUILD_DIR),)saved-output := $(BUILD_DIR)# Attempt to create a output directory.$(shell [ -d ${BUILD_DIR} ] || mkdir -p ${BUILD_DIR})
????????下面內容表示若$(BUILD_DIR)為空,則將其賦值為當前目錄路徑(源代碼目錄)。并檢查$(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),)
????????在下面內容中,CURDIR 變量指示 Make 當前的工作目錄,由于當前 Make 在 U-Boot 頂層目錄執行 Makefile,因此 CURDIR 此時就是 U-Boot 頂層目錄。執行完下面的代碼后, SRCTREE,src變量就是U-Boot代碼頂層目錄,而OBJTREE,obj變量就是輸出目錄,若沒有定義BUILD_DIR環境變量,則SRCTREE, src變量與OBJTREE,obj變量都是U-Boot 源代碼目錄。而MKCONFIG則表示U-Boot根目錄下的mkconfig 腳本。
OBJTREE := $(if $(BUILD_DIR),$(BUILD_DIR),$(CURDIR))SRCTREE := $(CURDIR)TOPDIR := $(SRCTREE)LNDIR := $(OBJTREE)export TOPDIR SRCTREE OBJTREEMKCONFIG := $(SRCTREE)/mkconfigexport MKCONFIGifneq ($(OBJTREE),$(SRCTREE))REMOTE_BUILD := 1export REMOTE_BUILDendif# $(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)/elseobj :=src :=endifexport obj src
????????在上面內容中,MKCONFIG????? := $(SRCTREE)/mkconfig即在根目錄下的mkconfig文件。
(6)執行make ?forlinx_nand_ram256_config過程
????????分析這個過程有助于理解移植U-Boot過程中需要修改哪些文件。執行這個命令前提是在移植U-Boot時,在根目錄的Makefile中加入了類似如下的內容:
forlinx_nand_ram256_config : unconfig @$(MKCONFIG) smdk6410 arm s3c64xx smdk6410 samsung s3c6410 NAND ram256 其中的依賴“unconfig”定義如下(Makefile文件的330-350行左右):unconfig: @rm -f $(obj)include/config.h $(obj)include/config.mk / $(obj)board/*/config.tmp $(obj)board/*/*/config.tmp
????????其中“@”的作用是執行該命令時不在 shell 顯示。“obj”變量就是編譯輸出的目錄,因此“unconfig”的作用就是清除上次執行 make *_config 命令生成的配置文件(如include/config.h,include/config.mk 等)。
????????$(MKCONFIG)在上面(5)指定為“$(SRCTREE)/mkconfig”,即根目錄的mkconfig文件。如果有$(@:_config=)一項,$(@:_config=)為將傳進來的所有參數中的_config 替換為空(其中“@”指規則的目標文件名,在這里就是“forlinx_nand_ram256_config ”。$(text:patternA=patternB),這樣的語法表示把 text 變量每一個元素中結尾的 patternA 的文本替換為 patternB,然后輸出)。因此$(@:_config=)的作用就是將forlinx_nand_ram256_config中的_config 去掉,得到 forlinx_nand_ram256,而在OK6410移植過的U-BOOT中沒有$(@:_config=)項。
??? 根據以上分析,執行完make forlinx_nand_ram256_config,實際上執行如下命令:
./mkconfig ?smdk6410 ?arm ?s3c64xx ?smdk6410 ?samsung ?s3c6410 ?NAND ?ram256
????????所以執行make forlinx_nand_ram256_config即將“smdk6410 ?arm ?s3c64xx ?smdk6410 ?samsung ?s3c6410 ?NAND ?ram256”作為參數傳遞給當前目錄下的mkconfig 腳本執行。這些參數實際意義如下:
smdk6410:Target(目標板型號)
arm:Architecture (目標板的CPU架構)
s3c64xx:CPU(具體使用的 CPU型號)
smdk6410:Board
samsung:VENDOR(生產廠家名)
s3c6410:SOC
NAND:
ram256:
在mkconfig文件中,將進行如下幾點的工作:
APPEND=no # no 表示創建新的配置文件,yes 表示追加到配置文件中BOARD_NAME="" # Name to print in make outputTARGETS=""while [ $# -gt 0 ] ; docase "$1" in--) shift ; break ;;-a) shift ; APPEND=yes ;;-n) shift ; BOARD_NAME="${1%%_config}" ; shift ;;-t) shift ; TARGETS="`echo $1 | sed "s:_: :g"` ${TARGETS}" ; shift ;;*) break ;;esacdone[ "${BOARD_NAME}" ] || BOARD_NAME ="$1"
????????對于命令./mkconfig ?smdk6410 ?arm ?s3c64xx ?smdk6410 ?samsung ?s3c6410 ?NAND ?ram256,其中沒有“--”“-a”“-n”“-t”“*”符號,所以while循環里面沒有做任何事情。而頭兩行中的兩個值仍然維持原來的值,但執行完最后一行后,BOARD_NAME的值等于第1個參數,即smdk6410(傳進的幾個參數在mkconfig文件中以$x表示,$0= mkconfig,$1= smdk6410,$2= arm,$3= s3c64xx,$4= smdk6410,$5= samsung,$6= s3c6410,$7= NAND,$8= ram256)。
注意:
????????在U-Boot1.1.6-for-OK6410源代碼中,BOARD_NAME=""一行后還有一行SETMMU="no",表示在nand啟動是用mmu,只是這里先把值設置為no。
[ $# -lt 4 ] && exit 1
[ $# -gt 9 ] && exit 1
echo "Configuring for ${BOARD_NAME} board which boot from $7 $8 $9..."
??? 上面代碼的作用是檢查參數個數和參數是否正確,參數個數少于 4 個或多于9個都被認為是錯誤的。環境變量$#表示傳遞給腳本的參數個數,這里的命令有9個參數,因此$#是9。Configuring for ${BOARD_NAME} board which boot from $7 $8 $9...即執行完make forlinx_nand_ram256_config命令后串口終端輸出的信息。
# Create link to architecture specific headersif [ "$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 asmelse cd ./include rm -f asm ln -s asm-$2 asm # 符號連接,即軟鏈接fi
????????第一行代碼判斷源代碼目錄和目標文件目錄是否一樣,可以選擇在其他目錄下編譯U-BOOT,這可令源代碼保持干凈,可以同時使用不同的配置進行編譯。OK6410的U-BOOT移植過的源代碼是在源代碼目錄下編譯的,所以源代碼目錄等于目標文件目錄,所以條件不滿足,將執行else分支的代碼。
????????在else分支的代碼中,先進入include目錄,刪除asm文件(這是上一次配置時建立的鏈接文件),然后再次建立asm文件,并令它鏈接向asm-$2目錄,即asm-arm目錄。此舉的作用為:在源碼中常調用頭文件,如#include
1:rm -f asm-$2/arch2:if [ -z "$6" -o "$6" = "NULL" ] ; then3: ln -s ${LNPREFIX}arch-$3 asm-$2/arch4:else5: ln -s ${LNPREFIX}arch-$6 asm-$2/arch6:fi7:if [ "$2" = "arm" ] ; then8: rm -f asm-$2/proc9: ln -s ${LNPREFIX}proc-armv asm-$2/proc10:fi
????????第1行刪除include/asm-arm/arch目錄,對于命令./mkconfig ?smdk6410 ?arm ?s3c64xx ?smdk6410 ?samsung ?s3c6410 ?NAND ?ram256,$6為S3C6410,不為空,也不為NULL,所以第2行條件不滿足,執行else分支。第5行中,LNPREFIX為空(在頂層makefile中未定義),所以第5行即執行ln ?–s? arch-s3c6410? asm-arm/arch(在U-Boot1.1.6-for-OK6410源代碼中,后面又把include/asm-arm/arch鏈接到了include/asm-arm/arch-s3c64xx)。
?????? 第8-9行表示:若目標板是arm架構,則上面的代碼將建立符號連接 include/asm-arm/proc,使其鏈接到目錄 include/asm-arm/proc-armv 目錄。建立以上的鏈接的好處:編譯 U-Boot 時直接進入鏈接文件指向的目錄進行編譯,而不必根據不同開發板來選擇不同目錄。
注意:
??? 在U-Boot1.1.6-for-OK6410源代碼中,在第6行到7行之間,增加了如下部分代碼for OK6410:
# create link for s3c24xx SoC
if [ "$3" = "s3c24xx" ] ; then
?????? rm -f regs.h
?????? ln -s $6.h regs.h
?????? rm -f asm-$2/arch
?????? ln -s arch-$3 asm-$2/arch
fi
# create link for s3c64xx SoC
if [ "$3" = "s3c64xx" ] ; 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" = "s3c64xx",將刪除include/regs.h,并把regs.h鏈接到include/s3c6410.h,在此頭文件中做了寫S3C6410的寄存器定義。然后刪除include/asm-arm/arch目錄,重新建立并把include/asm-arm/arch目錄鏈接到include/asm-arm/arch-S3C64xx目錄。
??? 在第9行和10行之間,增加了如下部分代碼:
fi
# create link for s3c64xx-mp SoC
if [ "$3" = "s3c64xx-mp" ] ; then
?????? rm -f regs.h
?????? ln -s $6.h regs.h
?????? rm -f asm-$2/arch
?????? ln -s arch-$3 asm-$2/arch
?????? 由于$3=s3c64xx,所以上面代碼中條件不成立,即上面代碼沒有做任何事。
????????創建頂層Makfile包含的文件include/config.mk
# Create include file for Makeecho "ARCH = $2" > config.mk echo "CPU = $3" >> config.mkecho "BOARD = $4" >> config.mk[ "$5" ] && [ "$5" != "NULL" ] && echo "VENDOR = $5" >> config.mk[ "$6" ] && [ "$6" != "NULL" ] && echo "SOC = $6" >> config.mk
????????當執行“./mkconfig ?smdk6410 ?arm ?s3c64xx ?smdk6410 ?samsung ?s3c6410 ?NAND ?ram256”命令后,上面幾行代碼創建的include/config.mk文件內容如下:
ARCH = armCPU = s3c64xxBOARD = smdk6410VENDOR = samsungSOC = s3c6410
(可選,如果待移植的U-Boot源代碼中已經有了那些目錄,就不需要下面的代碼,比如三星官方提供的U-Boot源代碼。)
# Assign board directory to BOARDIR variableif [ -z "$5" -o "$5" = "NULL" ] ; thenBOARDDIR=$4elseBOARDDIR=$5/$4fi
????????以上代碼指定 board 目錄下的一個目錄為當前開發板專有代碼的目錄。若$5(VENDOR)為空則BOARDDIR設置為$4(BOARD),否則設置為$5/$4(VENDOR/BOARD,即samsung/smdk6410)。在這里由于$5 不為空,即BOARDDIR 被設置為 samsung/smdk6410 。
if [ "$APPEND" = "yes" ] # Append to existing config file2:then3: echo >> config.h4:else5: > config.h # Create new config file6:fi7:echo "/* Automatically generated - do not edit */" >>config.h8:echo "#include " >>config.h9:exit 0 “>” 和 “>>”為linux命令,> config.h表示重新建立config.h文件,echo "#include " >>config.h表示把#include 添加到config.h文件中。 APPEND維持原值”no”,所以config.h被重新建立,并添加了如下內容:/* Automatically generated - do not edit */#include 到這里,include/config.h文件中就有以上的內容了。
注意: 在U-Boot1.1.6-for-OK6410源代碼中,在第7行到8行之間,增加了如下部分代碼for OK6410: case $7 inSD) echo "#define FORLINX_BOOT_SD" >> config.h SETMMU="no" ;;NAND) echo "#define FORLINX_BOOT_NAND" >> config.h SETMMU="yes" ;;*) ;;esaccase $8 inram128) echo "#define FORLINX_BOOT_RAM128" >> config.h > ../board/samsung/smdk6410/config.mk # clear file context echo "ifndef TEXT_BASE" >> ../board/samsung/smdk6410/config.mk if [ ${SETMMU} = "yes" ] then echo "TEXT_BASE = 0xC7E00000" >> ../board/samsung/smdk6410/config.mk else echo "TEXT_BASE = 0x57E00000" >> ../board/samsung/smdk6410/config.mk fi echo "endif" >> ../board/samsung/smdk6410/config.mk ;;ram256) echo "#define FORLINX_BOOT_RAM256" >> config.h > ../board/samsung/smdk6410/config.mk # clear file context echo "ifndef TEXT_BASE" >> ../board/samsung/smdk6410/config.mk if [ ${SETMMU} = "yes" ] then echo "TEXT_BASE = 0xCFE00000" >> ../board/samsung/smdk6410/config.mk else echo "TEXT_BASE = 0x5FE00000" >> ../board/samsung/smdk6410/config.mk fi echo "endif" >> ../board/samsung/smdk6410/config.mk ;;*) ;;esacif [ "$9" = "hdmi" ] ; then echo "#define FORLINX_LCDOUT_HDMI" >> config.hfi 對于OK6410,$7=NAND,所以會把#define FORLINX_BOOT_NAND添加到include/config.h文件中,并把SETMMU值設置為yes(在上面確定開發板名稱BOARD_NAME部分代碼中把SETMMU值設為no,如果從nand啟動,需要用到mmu,所以這里設置為yes)。 對于OK6410,$8=ram256,所以會把#define FORLINX_BOOT_RAM256添加到include/config.h文件中,并且會把include的上層目錄的/board/samsung/smdk6410/config.mk文件(開發板代碼所在目錄)清空(執行“> ../board/samsung/smdk6410/config.mk # clear file context”一行即實現清空), 清空后再往里面添加ifndef TEXT_BASE,由于SETMMU的值為yes,所以再往里面添加TEXT_BASE = 0xCFE00000(此地址為映射過的地址,使用mmu后,這個內存地址被映射。如果是128內存,此值為0XC7E00000,只要不超過DMC1的最大范圍物理地址0x6FFFFFFF對應的虛擬地址即可),最后添加endif。 對于OK6410,$9沒有被傳入,所以沒有把#define FORLINX_LCDOUT_HDMI添加到/include/ config.h文件中。
????????總的來說,執行make forlinx_nand_ram256_config命令后,會在mkconfig腳本中進行上面第(6)點中的所有動作,由這些動作可知,要在board目錄下新建一個開發板< board_name >目錄,在include/configs目錄下建立一個
?????? U-Boot還沒有類似Linux一樣的可視化配置界面(如用make menuconfig來配置),需要手動修改配置頭文件/include/configs/smdk6410.h來裁剪、設置U-Boot。此配置頭文件中有以下兩類宏:
#define CONFIG_S3C6410?? ?????? 1??? ? /* in a SAMSUNG S3C6410 SoC???? ?*/
#define CONFIG_S3C64XX ???? ?1??? ? /* in a SAMSUNG S3C64XX Family? ?*/
#define CONFIG_SMDK6410????? 1??? ? /* on a SAMSUNG SMDK6410 Board? */
#define CFG_MALLOC_LEN? (CFG_ENV_SIZE+128*1024)
#define CFG_PROMPT??
#define CFG_LOAD_ADDR? 0x50000000
從下面的編譯、鏈接過程可知,U-Boot中幾乎每個文件都被編譯和鏈接,但是這樣文件是否包含有效代碼,則由宏開關來設置。比如對于網卡驅動drivers/dm9000x.c,它的格式為:#include #include #include #ifdef CONFIG_DRIVER_DM9000#include "dm9000x.h"/*實際代碼*/…#endif /* CONFIG_DRIVER_DM9000 */
????????如果在/include/configs/smdk6410.h中定義了宏CONFIG_DRIVER_DM9000,則文件中包含有效代碼;否則,文件被注釋為空。
??? 可以這樣認為,“CONFIG_”除了設置一些參數外,主要用來設置U-Boot的功能、選擇使用文件中的哪一部分;而“CFG_”用來設置更細節的參數。
2. U-Boot的編譯、鏈接過程(接著頂層目錄中的Makefile分析)
(1)頂層Config.mk文件、頂層Makefile文件剩余代碼分析
配置完后,執行“ make? all ”即可編譯。若沒有執行過“make forlinx_nand_ram256_config”命令就直接執行“make all”命令則會出現“System not configured - see README”錯誤信息,
然后停止編譯。
?????? 由于執行完“make forlinx_nand_ram256_config”命令后,會在include目錄下創建一個config.mk文件,U-Boot就是判斷是否有這個文件而確定用戶是否執行過“make forlinx_nand_ram256_config”命令,注意exit 1即返回,相關代碼如下:
114: ifeq ($(OBJTREE)/include/config.mk,$(wildcard $(OBJTREE)/include/config.mk))…241: all:…249: $(obj)u-boot.bin: $(obj)u-boot250: $(OBJCOPY) ${OBJCFLAGS} -O binary $< $@ …322: else …327: @echo "System not configured - see README" >&2328: @ exit 1329: endif 在頂層Makefile中,繼續分析如下代碼:# load ARCH, BOARD, and CPU configuration 下面為與ARM相關部分117: include $(OBJTREE)/include/config.mk118: export ARCH CPU BOARD VENDOR SOC…127: ifeq ($(ARCH),arm)128: CROSS_COMPILE = arm-linux-129: endif…162: export CROSS_COMPILE164: # load other configuration165: include $(TOPDIR)/config.mk
上面代碼中127-129行表示ARCH與目標機器體系架構相同,則使用 arm-linux編譯器(ARCH=arm)。
注意:
在U-Boot1.1.6-for-OK6410源代碼中,在162行前面加了如下代碼:
CROSS_COMPILE = /usr/local/arm/4.3.2/bin/arm-linux-即不管上面如何判斷等,交叉編譯器始終使用/usr/local/arm/4.3.2/bin目錄下的arm-linux-編譯器。
?????? 在117和165行中,用于包含config.mk文件,117行將make forlinx_nand_ram256_config命令生成的include/config.mk包含進來,即配置過程中制作出來的include/config.mk文件,其中定義了ARCH/CPU/BOARD/VENDOR/SOC的值分別為arm、s3c64xx、smdk6410、samsung、s3c6410。165行將 U-Boot 頂層目錄下的 config.mk 文件包含進來,該文件包含了對編譯的一些設置,它根據ARCH/CPU/BOARD/VENDOR/SOC變量的值確定了編譯器、編譯選項等。
頂層config.mk文件分析:?????
? 設置 obj 與 srcifneq ($(OBJTREE),$(SRCTREE))ifeq ($(CURDIR),$(SRCTREE))dir :=elsedir := $(subst $(SRCTREE)/,,$(CURDIR))endifobj := $(if $(dir),$(OBJTREE)/$(dir)/,$(OBJTREE)/)src := $(if $(dir),$(SRCTREE)/$(dir)/,$(SRCTREE)/)$(shell mkdir -p $(obj))elseobj :=src :=endif 由于目標輸出到源代碼目錄下,因此執行完上面的代碼后,src 和 obj 都是空。? 設置編譯選項PLATFORM_RELFLAGS =PLATFORM_CPPFLAGS = #編譯選項PLATFORM_ = #連接選項用這 3 個變量表示交叉編譯器的編譯選項,在后面 Make 會檢查交叉編譯器支持的編譯選項,然后將適當的選項添加到這3個變量中。? 包含與開發板相關的配置文件(跳過54到74行的代碼,這些代碼是在NetBSD上使用交叉編譯器時需要的定義)ifdef ARCHsinclude $(TOPDIR)/$(ARCH)_config.mk # include architecture dependend rulesendif$(ARCH)的值是“arm”,因此將頂層目錄下的“arm _ config.mk”包含進來,而頂層目錄的arm _ config.mk文件中基本上什么都沒有做,只有一行代碼用來設置PLATFORM_CPPFLAGS編譯選項(與arm處理器相關)。ifdef CPUsinclude $(TOPDIR)/cpu/$(CPU)/config.mk # include CPU specific rulesendif$(CPU)的值是“s3c64xx”,因此將“cpu/ s3c64xx /config.mk”包含進來。這個腳本主要設定了跟s3c64xx處理器相關的編譯選項(與arm相關的PLATFORM_CPPFLAGS編譯選項)。ifdef SOCsinclude $(TOPDIR)/cpu/$(CPU)/$(SOC)/config.mk # include SoC specific rulesendif$(SOC)的值是s3c6410,因此Make程序嘗試將cpu/s3c64xx/s3c6410/config.mk包含進來,而這個文件并不存在,但是由于用的是“sinclude”命令,所以并不會報錯。ifdef VENDORBOARDDIR = $(VENDOR)/$(BOARD)elseBOARDDIR = $(BOARD)endif$(BOARD)的值是smdk6410,VENDOR的值是 samsung,因此BOARDDIR的值是 samsung/ smdk6410。BOARDDIR 變量表示開發板特有的代碼所在的目錄。ifdef BOARDsinclude $(TOPDIR)/board/$(BOARDDIR)/config.mk # include board specific rulesendif頂層目錄下的config.mk文件將“board/samsung/smdk6410/config.mk”包含進來。該腳本內容如下:ifndef TEXT_BASETEXT_BASE = 0xCFE00000endifU-Boot編譯時將使用TEXT_BASE作為代碼段連接的起始地址(這個地址是經過MMU映射過的)。? 其他代碼1 (95行---115行)CONFIG_SHELL := $(shell if [ -x "$$BASH" ]; then echo $$BASH; / else if [ -x /bin/bash ]; then echo /bin/bash; / else echo sh; fi ; fi)ifeq ($(HOSTOS)-$(HOSTARCH),darwin-ppc)HOSTCC = ccelseHOSTCC = gccendifHOSTCFLAGS = -Wall -Wstrict-prototypes -O2 -fomit-frame-pointerHOSTSTRIP = stripcc-option = $(shell if $(CC) $(CFLAGS) $(1) -S -o /dev/null -xc /dev/null / > /dev/null 2>&1; then echo "$(1)"; else echo "$(2)"; fi ;)在上面最后兩行代碼中,變量CC和CFLAGS在后面的代碼定義為延時變量,其中的 CC 即 arm-linux-gcc。函數cc-option 用于檢查編譯器 CC 是否支持某選項。將 2 個選項作為參數傳遞給 cc-option 函數,該函數調用 CC 編譯器檢查參數 1 是否支持,若支持則函數返回參數 1,否則返回參數 2 (因此CC 編譯器必須支持參數 1 或參數 2,若兩個都不支持則會編譯出錯)。可以像下面這樣調用cc-option 函數,并將支持的選項添加到 FLAGS 中:FLAGS +=$(call cc-option,option1,option2)? 指定交叉編譯工具AS = $(CROSS_COMPILE)asLD = $(CROSS_COMPILE)ldCC = $(CROSS_COMPILE)gccCPP = $(CC) -EAR = $(CROSS_COMPILE)arNM = $(CROSS_COMPILE)nmSTRIP = $(CROSS_COMPILE)stripOBJCOPY = $(CROSS_COMPILE)objcopyOBJDUMP = $(CROSS_COMPILE)objdumpRANLIB = $(CROSS_COMPILE)RANLIB
????????對于 arm 架構處理器,其中的 CROSS_COMPILE在頂層makefile文件中定義:
CROSS_COMPILE = /usr/local/arm/4.3.2/bin/arm-linux-(161行左右)
因此以上代碼指定了使用前綴為“arm-linux-”的編譯工具,即arm-linux-gcc,arm-linux-ld 等等。
????????在這部分代碼中,143行(LDSCRIPT := $(TOPDIR)/board/$(BOARDDIR)/u-boot.lds)給出了LDSCRIPT的值為頂層目錄下/board/Samsung/smdk6410/u-boot.lds(:=表示替換以前的值),而189行代碼如下:
LDFLAGS += -Bstatic -T $(LDSCRIPT) -Ttext $(TEXT_BASE) $(PLATFORM_LDFLAGS)
???? 所以,根據189行,使LDFLAGS中包含“-Bstatic? -T /board/Samsung/smdk6410/u-boot.lds ”和“-Ttext ?0xCFE00000”的字樣(+=表示添加)。
????????在最后部分代碼中(218-246行),指定隱含的編譯規則,例如:根據以上的定義,以“.s”結尾的目標文件將根據第一條規則由同名但后綴為“.S”的源文件來生成,若不存在“.S”結尾的同名文件則根據最后一條規則由同名的“.c”文件生成。
上面就是頂層目錄config.mk文件的內容,下面為頂層目錄中Makefile剩下的內容。
166:#########################################################################167:# U-Boot objects....order is important (i.e. start must be first)168:169:OBJS = cpu/$(CPU)/start.o170:ifeq ($(CPU),i386)171:OBJS += cpu/$(CPU)/start16.o172:OBJS += cpu/$(CPU)/reset.o173:endif174:ifeq ($(CPU),ppc4xx)175:OBJS += cpu/$(CPU)/resetvec.o176:endif177:ifeq ($(CPU),mpc83xx)178:OBJS += cpu/$(CPU)/resetvec.o179:endif180:ifeq ($(CPU),mpc85xx)181:OBJS += cpu/$(CPU)/resetvec.o182:endif183:ifeq ($(CPU),mpc86xx)184:OBJS += cpu/$(CPU)/resetvec.o185:endif186:ifeq ($(CPU),bf533)187:OBJS += cpu/$(CPU)/start1.o cpu/$(CPU)/interrupt.o cpu/$(CPU)/cache.o188:OBJS += cpu/$(CPU)/cplbhdlr.o cpu/$(CPU)/cplbmgr.o cpu/$(CPU)/flush.o189:endif190:191:OBJS := $(addprefix $(obj),$(OBJS))192:193:LIBS = lib_generic/libgeneric.a194:LIBS += board/$(BOARDDIR)/lib$(BOARD).a195:LIBS += cpu/$(CPU)/lib$(CPU).a196:ifdef SOC197:LIBS += cpu/$(CPU)/$(SOC)/lib$(SOC).a198:endif199:LIBS += lib_$(ARCH)/lib$(ARCH).a200:LIBS += fs/cramfs/libcramfs.a fs/fat/libfat.a fs/fdos/libfdos.a fs/jffs2/libjffs2.a /201: fs/reiserfs/libreiserfs.a fs/ext2/libext2fs.a202:LIBS += net/libnet.a203:LIBS += disk/libdisk.a204:LIBS += rtc/librtc.a205:LIBS += dtt/libdtt.a206:LIBS += drivers/libdrivers.a207:LIBS += drivers/nand/libnand.a208:LIBS += drivers/nand_legacy/libnand_legacy.a209:LIBS += drivers/sk98lin/libsk98lin.a210:LIBS += post/libpost.a post/cpu/libcpu.a211:LIBS += common/libcommon.a212:LIBS += $(BOARDLIBS)213:214:LIBS := $(addprefix $(obj),$(LIBS))215:.PHONY : $(LIBS)216:217:# Add GCC lib218:PLATFORM_LIBS += -L $(shell dirname `$(CC) $(CFLAGS) -print-libgcc-file-name`) -lgcc219:220:# The "tools" are needed early, so put this first221:# Don"t include stuff already done in $(LIBS)222:SUBDIRS = tools /223: examples /224: post /225: post/cpu226:.PHONY : $(SUBDIRS)227:228:ifeq ($(CONFIG_NAND_U_BOOT),y)229:NAND_SPL = nand_spl230:U_BOOT_NAND = $(obj)u-boot-nand.bin231:endif232:233:__OBJS := $(subst $(obj),,$(OBJS))234:__LIBS := $(subst $(obj),,$(LIBS))235:236:#########################################################################237:#########################################################################238:239:ALL = $(obj)u-boot.srec $(obj)u-boot.bin $(obj)System.map $(U_BOOT_NAND)240:241:all: $(ALL)242:243:$(obj)u-boot.hex: $(obj)u-boot244: $(OBJCOPY) ${OBJCFLAGS} -O ihex $< $@245:246:$(obj)u-boot.srec: $(obj)u-boot247: $(OBJCOPY) ${OBJCFLAGS} -O srec $< $@248:249:$(obj)u-boot.bin: $(obj)u-boot250: $(OBJCOPY) ${OBJCFLAGS} -O binary $< $@251:252:$(obj)u-boot.img: $(obj)u-boot.bin253: ./tools/mkimage -A $(ARCH) -T firmware -C none /254: -a $(TEXT_BASE) -e 0 /255: -n $(shell sed -n -e "s/.*U_BOOT_VERSION//p" $(VERSION_FILE) | /256: sed -e "s/"[ ]*$$/ for $(BOARD) board"/") /257: -d $< $@258:259:$(obj)u-boot.dis: $(obj)u-boot260: $(OBJDUMP) -d $< > $@261:262:$(obj)u-boot: depend version $(SUBDIRS) $(OBJS) $(LIBS) $(LDSCRIPT)263: UNDEF_SYM=`$(OBJDUMP) -x $(LIBS) |sed -n -e "s/.*/(__u_boot_cmd_.*/)/-u/1/p"|sort|uniq`;/264: cd $(LNDIR) && $(LD) $(LDFLAGS) $$UNDEF_SYM $(__OBJS) /265: --start-group $(__LIBS) --end-group $(PLATFORM_LIBS) /266: -Map u-boot.map -o u-boot267:268:$(OBJS):269: $(MAKE) -C cpu/$(CPU) $(if $(REMOTE_BUILD),$@,$(notdir $@))270:271:$(LIBS):272: $(MAKE) -C $(dir $(subst $(obj),,$@))273:274:$(SUBDIRS):275: $(MAKE) -C $@ all276:277:$(NAND_SPL): version278: $(MAKE) -C nand_spl/board/$(BOARDDIR) all279:280:$(U_BOOT_NAND): $(NAND_SPL) $(obj)u-boot.bin281: cat $(obj)nand_spl/u-boot-spl-16k.bin $(obj)u-boot.bin > $(obj)u-boot-nand.bin282:283:version:284: @echo -n "#define U_BOOT_VERSION /"U-Boot " > $(VERSION_FILE); /285: echo -n "$(U_BOOT_VERSION)" >> $(VERSION_FILE); /286: echo -n $(shell $(CONFIG_SHELL) $(TOPDIR)/tools/setlocalversion /287: $(TOPDIR)) >> $(VERSION_FILE); /288: echo "/"" >> $(VERSION_FILE)289:290:gdbtools:291: $(MAKE) -C tools/gdb all || exit 1292:293:updater:294: $(MAKE) -C tools/updater all || exit 1295:296:env:297: $(MAKE) -C tools/env all || exit 1298:299:depend dep:300: for dir in $(SUBDIRS) ; do $(MAKE) -C $$dir _depend ; done301:302:tags ctags:303: ctags -w -o $(OBJTREE)/ctags `find $(SUBDIRS) include /304: lib_generic board/$(BOARDDIR) cpu/$(CPU) lib_$(ARCH) /305: fs/cramfs fs/fat fs/fdos fs/jffs2 /306: net disk rtc dtt drivers drivers/sk98lin common /307: /( -name CVS -prune /) -o /( -name "*.[ch]" -print /)`308:309:etags:310: etags -a -o $(OBJTREE)/etags `find $(SUBDIRS) include /311: lib_generic board/$(BOARDDIR) cpu/$(CPU) lib_$(ARCH) /312: fs/cramfs fs/fat fs/fdos fs/jffs2 /313: net disk rtc dtt drivers drivers/sk98lin common /314: /( -name CVS -prune /) -o /( -name "*.[ch]" -print /)`315:316:$(obj)System.map: $(obj)u-boot317: @$(NM) $< | /318: grep -v "/(compiled/)/|/(/.o$$/)/|/( [aUw] /)/|/(/./.ng$$/)/|/(LASH[RL]DI/)" | /319: sort > $(obj)System.map320:321:#########################################################################322:else323:all $(obj)u-boot.hex $(obj)u-boot.srec $(obj)u-boot.bin /324:$(obj)u-boot.img $(obj)u-boot.dis $(obj)u-boot /325:$(SUBDIRS) version gdbtools updater env depend /326:dep tags ctags etags $(obj)System.map:327: @echo "System not configured - see README" >&2328: @ exit 1329:endif330:331:.PHONY : CHANGELOG332:CHANGELOG:333: git log --no-merges U-Boot-1_1_5.. | /334: unexpand -a | sed -e "s//s/s*$$//" > $@335:336:#########################################################################337:338:unconfig:339: @rm -f $(obj)include/config.h $(obj)include/config.mk /340: $(obj)board/*/config.tmp $(obj)board/*/*/config.tmp341:
????????在上面代碼中的169行,OBJS的第一個值為“cpu/$(CPU)/start.o”,即“cpu/s3c64xx/start.o”,根據上一行的注釋,u-boot中OBJS(目標)非常重要,start.o必須放在第一個,即首先編譯的start.s。在上面代碼的170-191行為其他架構CPU的目標,在這里沒什么用處。
注意:
?????? 175-177行的代碼在U-Boot1.1.6-for-OK6410源代碼中沒有,理論上有沒有無影響。
????????在代碼193行到218行中,LIBS 變量指明了 U-Boot 需要的庫文件,包括平臺/開發板相關的目錄、通用目錄下相應的庫,都通過相應的子目錄編譯得到的,在215行中,定義偽目標(.PHONY : $(LIBS)),意在當前目錄下如果有LIBS變量對應的值(即U-Boot 需要的庫文件,.a文件)時,執行make后不會顯示“*.a is up-to-date”,而且會重新編譯生成對應的.a文件。
注意:在208-209行之間,U-Boot1.1.6-for-OK6410源代碼中增加了如下代碼:
# add to support onenand. by scsuhLIBS += drivers/onenand/libonenand.aifeq ($(CPU),mpc83xx)LIBS += drivers/qe/qe.aendif 增加對onenand flash的支持。
????????228到231行是些與平臺無關的代碼,因為對于某些開發板(包括OK6410),u-boot支持在nand flash啟動,這些開發板配置文件中可能宏定義了CONFIG_NAND_U_BOOT,這樣在239行依賴U_BOOT_NAND不會為空。239行代碼即在執行make all后,將要生成u-boot.srec,u-boot.bin,System.map。其中u-boot.srec 是 Motorola S-Record format 文件,System.map 是 U-Boot 的符號表,u-boot.bin 是最終燒寫到開發板的二進制可執行的文件。如果U_BOOT_NAND不為空,還將生成u-boot-nand.bin文件。
????????OBJS、LIBS所代表的.o、.a文件就是U-boot的構成,它們通過268-272行命令,由相應的源文件(或相應子目錄下的文件)編譯得到。第268-269行規則表示,對于OBJS的每個成員,都將進入cpu/$(CPU)目錄(即cpu/s3c64xx)編譯它們,對于smdk6410開發板,OBJS為cpu/s3c64xx/start.o,它將由cpu/s3c64xx/start.S編譯得到。第271-272行規則表示,對于LIBS中的每個成員,都將進入相應的子目錄執行“make”命令。這些子目錄的Makefile,結構相似,它們將Makefile中指定的文件編譯、鏈接成一個庫文件。
????????當所有的OBJS、LIBS所表示的.o和.a文件都生成后,最后連接,這對應上面代碼中的243到267行,先使用262-266行的規則鏈接得到ELF格式的U-BOOT,最后轉換為二進制格式的u-boot.bin、S-Record格式的U-Boot.srec等等(即243-261行)。對于ELF格式的U-Boot的依賴,下面分別介紹:
行為依賴目標depend的規則,對于300行中$(SUBDIRS),進入該目錄執行“make _depend”,生成各個子目錄的.depend 文件,.depend 列出每個目標文件的依賴文件。
對于version依賴,即U-Boot的版本,這里不詳細介紹。274-275行為依賴SUBDIRS的規則,SUBDIRS的值222-226有定義,所以將執行tools、examples、post、post/cpu目錄下的makefile。
這兩個依賴在上面已經說明。
此依賴在頂層config.mk文件中有定義,LDSCRIPT的值為頂層目錄下/board/Samsung/smdk6410/u-boot.lds。
??????? U-BOOT規則命令中,264-266行表示真正連接,LDFLAGS確定了連接方式,LDFLAGS里/board/Samsung/smdk6410/u-boot.lds ”和“-Ttext? 0xCFE00000”的字樣(根據頂層config.mk文件),這些字樣指定了程序的布局、地址(但是連接起始地址為連接腳本中的偏移地址0+0xCFE00000)。所以,$(LDFLAGS)即使用u-boot.lds鏈接腳本及-Ttext? 0xCFE00000。執行連接命令其實就是把 start.o 和各個子目錄 makefile 生成的庫文件按照 LDFLAGS 連接在一起,生成 ELF 文件 u-boot 和連接時內存分配圖文件 u-boot.map。
注意:在上面代碼中250到251行之間, U-Boot1.1.6-for-OK6410源代碼中增加了一行代碼:$(OBJDUMP) -d $< > $<.dis。目的是生成U-Boot的反匯編文件。
????????頂層Makefile代碼中341行以后的代碼都是添加CPU架構相關的_config文件(整個 makefile 剩下的內容全部是各種不同的開發板的*_config:目標的定義),本開發板OK6410添加了如下(當然還有三星s3c24及64系列的其他處理器):
forlinx_nand_ram256_config :? unconfig
??? @$(MKCONFIG) smdk6410 arm s3c64xx smdk6410 samsung s3c6410 NAND ram256
注意:在頂層目錄makefile文件的末尾部分,是執行make clean后的規則,在U-Boot1.1.6-for-OK6410源代碼中增加了二行代碼:分別在2261行后加了:????????
-o -name "*~" -o -name ".depend*" /
在2263行后增加了:
?rm -f u-boot*
(2)鏈接腳本分析(/board/Samsung/smdk6410/u-boot.lds)
24:OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")25:/*OUTPUT_FORMAT("elf32-arm", "elf32-arm", "elf32-arm")*/26:OUTPUT_ARCH(arm) /* 指定輸出平臺為arm */27:ENTRY(_start)28:SECTIONS29:{30: . = 0x00000000; 31:32: . = ALIGN(4); /* 代碼以4字節對齊 */33: .text : /* 指定代碼段,.text的基地址由LDFLAGS中-Ttext $(TEXT_BASE)指定*/34: {35: cpu/s3c64xx/start.o (.text) /* 代碼段的第一個代碼部份 */36: cpu/s3c64xx/s3c6410/cpu_init.o (.text)37: cpu/s3c64xx/onenand_cp.o (.text)38: cpu/s3c64xx/nand_cp.o (.text)39: cpu/s3c64xx/movi.o (.text) 40: *(.text) /*其他代碼部分*/41: lib_arm/div0.o42: }43:44: .
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/121955.html
摘要:要想放到樹莓派上運行,需要官方提供的固件四下載直接下載我們所需的在文件夾中,將其中的復制到卡的分區中之前分區時大小為,格式為的那個,再將編譯好的一同復制進去。 2021SC@SDUSC 一、uboot的介紹 1.1、計算機系統的主要部件 (1)計算機系統就是以CPU為核心來運行的系統。典型的...
摘要:表示,不是用壓縮的。兩者的不同之處在于,解壓縮內核到低端內存第一個,解壓縮內核到高端內存以上。如果內核比較小,那么采用或都行,如果比較大應該用。使得內核可以啟動文件的拷貝或指向的鏈接。 ...
摘要:基于開發的軟件包導師汪禮超學員崔林威摘要騰訊物聯網操作系統是騰訊面向物聯網領域開發的實時操作系統,具有低功耗,低資源占用,模塊化,可裁剪等特性。圖中斷函數處理進行生成工程配置,按如下界面進行配置,最后點擊,并點擊。 ...
閱讀 3939·2021-10-09 09:43
閱讀 2871·2021-10-08 10:05
閱讀 2734·2021-09-08 10:44
閱讀 882·2019-08-30 15:52
閱讀 2809·2019-08-26 17:01
閱讀 3016·2019-08-26 13:54
閱讀 1649·2019-08-26 10:48
閱讀 807·2019-08-23 14:41