轉載自: http://blog.chinaunix.net/uid-22713545-id-61844.html
本文是針友善之臂公司出品的mini2440進行移植,其CPU不ARM920T架構的S3C2440,一片
64M Nand Flash (K9F1208),一片2M Nor Flash 更具體數據請參考開發板手冊。
u-boot-1.1.6有幾千個文件,不可能對每一個文件都瞭解得非常細緻,我們只需要瞭解自己
工程所用到的相關文件即可,這也是一貫的做法。首先大概的看一下u-boot的文件結構,對其
有個大概的瞭解,最好的辦法是查看頂層的Makdfile由其推出其文件間的依賴關係,這樣對移
植有很大的幫助。
代碼結構與功能
board——目標板相關文件,主要包含SDRAM、Flash驅動;
common——獨立於處理器體系結構的通用代碼,如內存大小探測與故障檢測;
cpu——與處理器相關的文件,如mpc8xx子目錄下含串口、網口、LCD驅動及中斷初始化等文件;
driver——通用設備驅動,如CFI Flash驅動;
doc——U-Boot的說明文檔;
examples——可在U-Boot下運行的示例程序;如helloworld.c,timer.c;
include——U-Boot頭文件,configs子目錄下與目標板相關的配置頭文件是移植過程中經常要修改的文件;
lib_xxx——處理器體系相關的文件,如lib—ppc,lib_arm目錄分別包含與PowerPC、ARM體系結構相關的文件;
net——與網絡功能相關的文件目錄,如bootp、nfs、tftp;
post——上電自檢文件目錄,尚有待於進一步完善;
rtc——RTC驅動程序;
tools——用於創建U-Boot S-RECORD和BIN鏡像文件的工具
//********************************************************************************************************//
////////////////////////////////////////////////////////////////////////////////////////////////////////////
幾個重要的文件分析:
u-boot-1.1.5/Makefile
u-boot-1.1.5/mkconfig
u-boot-1.1.5/config.mk
u-boot根目錄下的Makefile文件(u-boot-1.1.5/Makefile)它負責配置u-boot的編譯方式,具體說來包括:使用何
種指令集,需包含哪些接口驅動、庫等。Makefile的內容從上到下分別是:分定義編譯環境:使用何種編譯器、編譯方式、
目標文件的生成及它們最終鏡像中的鏈接次序等。Mkconfig和config.mk在接下來的分析中會涉及到。
以SMDK2410爲例
在編譯U-BOOT之前,先要執行
# make smdk2410_config
smdk2410_config是Makefile的一個目標,定義如下:
smdk2410_config: unconfig
@$(MKCONFIG) $(@:_config=) arm arm920t smdk2410 NULL s3c24x0
其中,unconfig定義如下:
unconfig:
@rm -f $(obj)include/config.h $(obj)include/config.mk \
$(obj)board/*/config.tmp $(obj)board/*/*/config.tmp
所以可以看到,當執行make smdk2410_config時,那麼make就會先執行unconfig,由unconfig定義可得該命令是
執行清理上一次執行make *_config所生成的頭文件與和Makefile包含的相關文件,主要是include/config.h include/config.mk
board/*/config.tmp board/*/*/config.tmp (此處的*爲開發板的名稱,例如smdk2410)
注:如果命令行中指定了編譯目錄,則要到自己指定的編譯目錄中去刪除這幾個文件。
接着就是執行@$(MKCONFIG) $(@:_config=) arm arm920t smdk2410 NULL s3c24x0其中在這裏第一個@是GNU一種“所有匹配模式”規則,那麼
$(MKCONFIG)相當於./mkconfig
在這裏特別注意一下$(MKCONFIG)是指引用變量MKCONFIG,而在文件開頭有對MKCONFIG的定義
MKCONFIG :=$(SRCTREE)/mkconfig
而變量SRCTREE定義在前面指定爲
SRCTREE :=$(CURDIR)
再找到變量CURDIR的定義
在Makfile裏找不到其定義,因爲它是GNU make的環境變量不需要我們定義
此變量代表make的工作目錄當使用“-C”選項進入一個子目錄後,此變量將
被重新賦值。總之,如果在Makefile中沒有對此變量進行顯式的賦值操作,那
麼它代表make的工作目錄。我們也可以在Makefile爲這個變量賦一個新的值。
此時這變量將不再代表make的工作目錄。
例如當在目錄/下
輸入 make –C /usr/u-boot-1.1.6/ smdk2410_config
那麼CURDIR的值就是/usr/u-boot-1.1.6
而當我直接在目錄/usr/u-boot-1.1.6下
輸入 make smdk2410_config
那麼CURDIV的值就是.
由於我們直接在源代碼目錄下執行make一步步的向前推那就是$(MKCONFIG)相當於./mkconfig
接着下來就到命令行的第二部分$(@:_config=)在這裏更要特別的注意了,這裏不是變量的引用,在Makefile文件里根本就找不到“@:_config”變量,所以不能理解爲變量,它是GNU make的一個函數,其實這是一個簡化的函數 $(VAR:PATTERN=REPLACEMENT)
在GNU中有函數
$(patsubst ,,)
函數名稱:模式替換函數—patsubst
函數功能:查找中的單詞(單詞以“空格”、“Tab”或“回車”“換行”分隔)
是否符合模式< pattern>,如果匹配的話,則以替換。這
裏,可以包括通配符 “%”,表示任意長度的字串。如果
中也包含“%”,那麼,中的這個 “%”將是中
的那個“%”所代表的字串。(可以用“\”來轉義,以“\%”來表示真實含義的“%”字符)
返 回 值:替換後的新字符串
函數說明:參數“TEXT”單詞之間的多個空格在處理時被合併爲一個空格,並忽略前導和結尾空格
例如:
$(patsubst %.c,%.o,x.c.c bar.c)
把字串“x.c.c bar.c”中以.c結尾的單詞替換成以.o結尾的字符。函數的返回結果是“x.c.o bar.o”
而$(var:=)就是簡化的$(patsubst ,,)
所以在$(@:_config=)中就是$(smdk2410_config:_config=)
轉爲$(patsubst _config,,smdk2410_config)
依定義爲把字符串“smdk2410_config”的字符串“_config”用空代替,等於是去除“_config”
返回值爲“smdk2410”
到此爲止先看一下“@$(MKCONFIG) $(@:_config=) arm arm920t smdk2410 NULL s3c24x0”變成什麼樣了,下面就是真實的命令了
./mkconfig smdk2410 arm arm920t smdk2410 NULL s3c24x0
此命令是執行當前目錄下mkconfig腳本,並傳入參數,在這裏有六個參數,分別爲smdk2410 arm arm920t smdk2410 NULL s3c24x0
而這六個參數分別代表什麼含義就要到mkconfig裏看一看了
使用vim查看 vim mkconfig
//****************************************************************************************************//
////////////////////////////////////////////////////////////////////////////////////////////////////////
下面着重分析一下mkconfig:
(一)首先mkconfig第一行就是#!/bin/sh –e它的用途就是指出本腳本是用的哪種shell寫的,執行時系統應該用哪種
shell來解釋執行它,顯然這裏是用目錄下/bin/sh 的shell來解釋這個腳本。其實每一個文件我應該先認真讀一下前面的註解信息
這一句就簡單明瞭說出該腳的作用是“爲一個特定的開發板創建一些相關的頭文件和相關配置鏈接”
下一句 #Parameters: Target Architecture CPU Board [VENDOR] [SOC]說明了各種參數的意義
Target: 宿主機平臺
Architecture: 定義芯片架構(如MIPS、POWERPC、ARM等)
CPU: 定義芯片指令集版本(如ARM7、ARM9、ARM11等)
Board: 芯片廠商,它細分爲兩類
[VENDOR]: 按廠商劃分(如AT9200、S3C44B0等)
[SOC]: 按SOC類型(如S3C2440、S3C2410等)
對於#make smdk2410_config命令,由上面分析可以傳入參數爲
smdk2410 arm arm920t smdk2410 NULL s3c24x0
與Target Architecture CPU Board [WENDOR] [SOC]
一一對應[VENDOR]爲空,即是NULL 同時注意到上面六個參數與下面的
$1 $2 $3 $4 $5 $6也是一一對應的關係
//****************************************************************************************************//
////////////////////////////////////////////////////////////////////////////////////////////////////////
(二)接着下來分析mkconfig中的各個語句
下面的語中
11 APPEND=no # Default: Create new config file
默認情況下創建一個新的config文件
12 BOARD_NAME="" # Name to print in make output
顯示輸出的開發板名字,此時爲空
13
14 while [ $# -gt 0 ] ; do # [ ]是Bash裏的一個測試命令,在這裏是如果參
# 數變量個數大於(-gt)零則執行do後的語句
注:在Bash裏“$#”是傳到腳本里的位置參數的個數
15 case "$1" in # 第一個參數爲下列值中的一個
16 --) shift ; break ;; # 如果$1爲“--”時,所有參數向左移一位,
# 即把原$1丟棄,原$2補上$1<-$2<-$3<-$4<-$5<-$6
# 但要注意的是$0即腳本名,保持不變,只
# 是把原$1丟棄,接着跳出
17 -a) shift ; APPEND=yes ;; # 如果“$”1爲“-a”則APPEND的值
# 由no改成yes 接着跳出(這裏;;相當於break;)
18 -n) shift ; BOARD_NAME="${1%%_config}" ; shift ;;
# 如果“$1”爲“-n”則BOARD_NAME變
# 爲“$1”(注意此時的$1已不是剛傳入的
# “-n”)去掉從右往左算起最後一個“_config”
# 字符串剩下的字符串,接着所有參數再
# 左移一位,然後跳出循環與case語句
注:在Bash裏${1%%_config}是一種字符串操作,其標準
形式:${string%%substring} 從$string 的右邊截掉最後一個匹配的$substring
19 *) break ;; # 如果爲其他值則直接跳出
20 esac
21 done
22
23 [ "${BOARD_NAME}" ] || BOARD_NAME="$1"
# 這裏主要是給BOARD_NAME 賦值,當爲空時
# 賦值爲“$1”當不爲空這保持不變
24
25 [ $# -lt 4 ] && exit 1 # 如果位置參數的個數小於4則退出
26 [ $# -gt 6 ] && exit 1 # 如果位置參數的個數大於6則退出
27
28 echo "Configuring for ${BOARD_NAME} board..."
# 在終端上顯示Configuring for ${BOARD_NAME} board...
現在回頭看一下,總結到目前爲止腳本到底做了哪些事情。主要是根據傳入的參數做一些簡單的配置,對
一些變量進行設置,使之可以爲後面所用,讓我看下兩個例子:
當輸入爲make smdk2410_config時
在u-boot-1.1.6的根目錄下輸入make smdk2410_config由前面對Makefile粗淺認識
相當於執行了./mkconfig smdk2410 arm arm920t smdk2410 NULL s3c24x0 此時傳入的
位置參數
$1 = smdk2410
$2 = arm
$3 = arm920t
$4 = smdk2410
$5 = NULL(爲空)
$6 = s3c24x0
接着進入while部分,執行while [ $# -gt 0 ] ($#爲6,大於0)
進入case執行 *) break ;; (因爲$1爲smdk2410)
然後執行[ "${BOARD_NAME}" ] || BOARD_NAME="$1" (此時BOARD_NAME= smdk2410)
跳過[ $# -lt 4 ] && exit 1
跳過[ $# -gt 6 ] && exit 1
緊接執行echo "Configuring for ${BOARD_NAME} board..."
(在屏幕上可以看Configuring for ${BOARD_NAME} board.. )
當輸入爲 make cpci5200_config時
相當於執行了./mkconfig -a cpci5200 ppc mpc5xxx cpci5200 esd此時傳入的
位置參數
$1 = -a
$2 = cpci5200
$3 = ppc
$4 = mpc5xxx
$5 = cpci5200
$6 = esd
當執行完echo "Configuring for ${BOARD_NAME} board..."
此時
BOARD_NAME = cpci5200
APPEND=yes
//****************************************************************************************************//
////////////////////////////////////////////////////////////////////////////////////////////////////////
(三)接着下來分析mkconfig裏的下一部分代碼
由# Create link to architecture specific headers可知這一部分是
“爲指定的芯片架構創建文件鏈接”
33 if [ "$SRCTREE" != "$OBJTREE" ] ; then # 測試$SRCTREE與$OBJTREE不相等依情況執行不同分支
34 mkdir -p ${OBJTREE}/include # 如果不等,則創建目錄文件夾${OBJTREE}/include
35 mkdir -p ${OBJTREE}/include2 # 創建目錄文件夾${OBJTREE}/include2
36 cd ${OBJTREE}/include2 # 進入目錄文件夾${OBJTREE}/include2
37 rm -f asm # 刪除當前目錄下的asm
38 ln -s ${SRCTREE}/include/asm-$2 asm # 建立${SRCTREE}/include/asm-$2文件的符號鏈接,並命名爲asm
39 LNPREFIX="../../include2/asm/" # 給LNPREFIX賦值爲../../include2/asm/
40 cd ../include # 進入目錄${OBJTREE}/include
41 rm -rf asm-$2 # 刪除目錄asm-$2及下所有東西
42 rm -f asm # 刪除asm
43 mkdir asm-$2 # 創建目錄asm-$2(當前在目錄${OBJTREE}/include/)
44 ln -s asm-$2 asm # 建立asm-$2文件的符號鏈接,並命名爲asm
45 else
46 cd ./include # 如果$SRCTREE與$OBJTREE相等,則進入./include
47 rm -f asm # 刪除asrm
48 ln -s asm-$2 asm # 建立asm-$2文件的符號鏈接,並命名爲asm(在當前目錄下有asm)
49 fi
50
51 rm -f asm-$2/arch # 刪除目錄include/ asm-$2/下的arch
52
53 if [ -z "$6" -o "$6" = "NULL" ] ; then # 如果$6的長度爲0或爲NULL則執行then分支
# 這裏說明一下“-z 字符串爲"null".就是長度爲0”
# “-o 邏輯或”
54 ln -s ${LNPREFIX}arch-$3 asm-$2/arch # 建立${LNPREFIX}arch-$3文件的符號鏈接,並命名爲asm-$2/arch
55 else
56 ln -s ${LNPREFIX}arch-$6 asm-$2/arch # 建立${LNPREFIX}arch-$6文件的符號鏈接,並命名爲asm-$2/arch
57 fi
58
59 if [ "$2" = "arm" ] ; then # 如果第二個參數爲arm則執行then分支
60 rm -f asm-$2/proc # 刪除目錄asm-$2/proc(當前所在目錄爲${OBJTREE}/include/)
61 ln -s ${LNPREFIX}proc-armv asm-$2/proc # 建立${LNPREFIX}proc-armv文件
# 的符號鏈接,並命名爲asm-$2/ proc
62 fi
63
64 #
對於make smdk2410_config
執行cd ./include (當前目錄爲/usr/u-boot-1.1.6/include)
rm -f asm (別忘了是在目錄/usr/u-boot-1.1.6/include下的asm)
ln -s asm-$2 asm ($2爲arm)
rm -f asm-$2/arch ($2爲arm)
ln -s ${LNPREFIX}arch-$6 asm-$2/arch (LNPREFIX爲../../include/asm/)
rm -f asm-$2/proc (當前目錄爲/usr/u-boot-1.1.6/include)
ln -s ${LNPREFIX}proc-armv asm-$2/proc (LNPREFIX爲../../include/asm/,當前目錄爲/usr/u-boot-1.1.6/include)
結果如下
//****************************************************************************************************//
////////////////////////////////////////////////////////////////////////////////////////////////////////
(四)文件鏈接先告一段落,接着往下看另一部分
由# Create include file for Make可知這裏爲Make創建一些相關的包含文件
67 echo "ARCH = $2" > config.mk # 將ARCH = $2重定向到文件config.mk
# 如果沒有這個文件則創建,有這個文
# 件就覆蓋原來的文件內容,config.mk
# 在當前目錄下
68 echo "CPU = $3" >> config.mk # 重定向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
上面的依照分析即行
注:
在bash裏有> >>是IO重定向1 COMMAND_OUTPUT >
2 # 重定向stdout 到一個文件.
3 # 如果沒有這個文件就創建, 否則就覆蓋.
18 COMMAND_OUTPUT >>
19 # 重定向stdout 到一個文件.
20 # 如果文件不存在, 那麼就創建它, 如果存在, 那麼就追加到文件後邊.
所以這一部分就是將
ARCH = arm
CPU = arm920t
BOARD = smdk2410
SOC = s3c24x0
重定向到文件config.mk,即將其輸入到config.mk,這時在../include目錄下生成一個文件config.mk
如下圖所示:
打印其中的信息:
這文件就是記錄一些開發板的信息,被Makefile所用,打開Makefile在前面那裏可以找到相關的信息:
從這裏我們可以看到,把./include下的文件config.mk包含進Makefile裏
然後聲明一些環境變量 ARCH CPU BOARD VENDOR SOC
注:
當一個變量使用“export”進行聲明後,變量和它的值將被加入到當前工作的
環境變量中,以後在make執行的所有規則的命令都可以使用這個變量。而當沒
有使用指示符“export”對任何變量進行聲明的情況下,上層make只將那些已經
初始化的環境變量(在執行make之前已經存在的環境變量)和使用命令行指定
的變量(如命令“make CFLAGS +=-g”或者“make –e CFLAGS +=-g”)傳遞給子
make程序,在這裏主要是傳遞給MAKEALL
//****************************************************************************************************//
////////////////////////////////////////////////////////////////////////////////////////////////////////
(五)接下就要分析mkconfig最後的一部分了,很快就把mkconfig文件分析完:
這一部分裏主要的工作是創建對特定開以板的頭文件
從上面可以看到相應的結果
//******************************************************************************************************//
//////////////////////////////////////////////////////////////////////////////////////////////////////////
到此爲止就反mkconfig文件就全部分析完畢,也就是對於Makdfile裏的smdk2410_config作用分析也完成了,顯然這
樣有點亂,因爲在這過程中穿插了許多相關知識這些主要參考了《GNU中文手冊》《GCC中文手冊》《高級Bash 腳本編程指南》
現在認我們再從重頭總結一下命令執行的過程以及相關的結果,以smdk2410開發板爲例:
① 在終端下輸入make smdk2410_config
|
② 進入Makefile執行相關的命令即
smdk2410_config: unconfig
@$(MKCONFIG) $(@:_config=) arm arm920t smdk2410 NULL s3c24x0
|
③ 先執行uconfig刪除上次生成的相關文件
|
④ 緊接執行./mkconfig smdk2410 arm arm920t smdk2410 NULL s3c24x0
此時進入mkconfig文件裏執行相關語句
|
⑤ 變量APPEND=no BOARD_NAME=smdk24410
在終端上顯示Configuring for ${BOARD_NAME} board...
|
⑥ 在目錄./include下創建文件鏈接
asm-arm -> asm
../include/asm/arch-s3c24x0 -> asm-arm/arch
../include/asm/proc-armv -> asm-arm/proc
|
⑦ 在./include/config.mk文件裏寫入
ARCH = arm
CPU = arm920t
BOARD = smdk2410
SOC = s3c24x0
|
⑧ 接下來就在./include/config.h文件裏寫入
/* Automatically generated - do not edit */
#include
|
⑨完成./mkconfig