電子產(chǎn)業(yè)一站式賦能平臺

PCB聯(lián)盟網(wǎng)

搜索
查看: 1504|回復(fù): 0
收起左側(cè)

Uboot簡單介紹

[復(fù)制鏈接]

2607

主題

2607

帖子

7472

積分

高級會(huì)員

Rank: 5Rank: 5

積分
7472
跳轉(zhuǎn)到指定樓層
樓主
發(fā)表于 2020-12-13 11:56:14 | 只看該作者 回帖獎(jiǎng)勵(lì) |倒序?yàn)g覽 |閱讀模式
Uboot簡單介紹, 1、認(rèn)識uboot

U-Boot,全稱 Universal Boot Loader,是遵循GPL條款是一個(gè)開源項(xiàng)目,用于啟動(dòng)操作系統(tǒng)內(nèi)核,操作系統(tǒng)并不是一開機(jī)就會(huì)自動(dòng)啟動(dòng),是要有引導(dǎo)程序的。uboot就是一個(gè)這樣的開源的引導(dǎo)程序。uboot的官方網(wǎng)站:http://www.denx.de/wiki/U-Boot/SourceCode uboot早期的版本號是這樣的 uboot1.4.3,后來是是這樣的uboot-2018.11.

2、使用uboot

我們可以在uboot啟動(dòng)過程中進(jìn)入uboot的控制臺底下,使用uboot。所謂的使用uboot也就是使用uboot的環(huán)境變量和命令。ping

3、配置編譯下載uboot

這里說一下如何配置編譯下載uboot,后面的部分為詳細(xì)講解uboot源代碼的部分,F(xiàn)在最新版本的uboot的配置方法和Linux內(nèi)核的配置方法是一樣的,后面我會(huì)有Linux內(nèi)核配置的文章。

配置

uboot和linux kernel等復(fù)雜項(xiàng)目,都不能直接編譯,都要先配置才能編譯。uboot也要先配置,配置方法是:首先cd進(jìn)入uboot源碼的根目錄,然后在根目錄下執(zhí)行:make x210_sd_config(就看Makefile中的那個(gè)目標(biāo)來確定,其實(shí)也就是include/configs/目錄下的配置文件后面加上_config,比如我這里include/configs/x210_sd.h,所以這里就是make x210_sd_config)。執(zhí)行配置命令后,如果出現(xiàn):Configuring for x210_sd board…說明配置好了,如果不是這個(gè)是別的說明配置出錯(cuò)了。

編譯

編譯之前一定要注意檢查arm-linux-gcc對不對,檢查份2步: 第一步:檢查當(dāng)前編譯環(huán)境中有沒有安裝合適的arm-linux-gcc。我們裝的是arm-2009q3,因?yàn)檫@個(gè)是三星官方、九鼎官方開發(fā)uboot時(shí)使用的。 第二步:檢查當(dāng)前目錄下(uboot根目錄)的Makefile中編譯器的設(shè)置是否正確。在工程的總Makefile中會(huì)設(shè)置交叉編譯工具鏈的路徑和名字,必須確保這個(gè)路徑和名字和我們自己裝的一致,否則編譯會(huì)出錯(cuò)。 確保了以上2點(diǎn),即可進(jìn)行編譯。編譯很簡單,直接make即可;蛘呖梢詍ake -j4 (多線程編譯,主機(jī)如果是多核心電腦,可以嘗試多線程編譯,會(huì)快一些)

下載

uboot根目錄下有一個(gè)sd_fusing文件夾,進(jìn)去之后先檢查sd_fusing.sh的執(zhí)行權(quán)限有沒有,文件中的bin文件與根目錄中生成的bin文件是否一致,文件中的reader_type1=“/dev/sdc“ 中是否是對應(yīng)的自己的SD卡,make clean,然后make,然后插入SD卡。執(zhí)行./sd_fusing.sh /dev/sdc,即可

uboot中各個(gè)文件夾的介紹

文件介紹

(1).gitignore。git工具的文件,git是一個(gè)版本管理工具(類似的還有個(gè)svn),這個(gè)文件和git有關(guān),和uboot本身無關(guān)的,不用去管。 (2)arm_config.mk。后綴是.mk,是一個(gè)Makefile文件,將來在某個(gè)Makefile中會(huì)去調(diào)用它。 (3)三個(gè)Changelog文件,修改記錄文件,該文件記錄了這個(gè)uboot項(xiàng)目的版本變遷以及每個(gè)版本較上個(gè)版本修改的記錄。正式的項(xiàng)目都有這些記錄的。可以直接忽略,主要是給維護(hù)uboot的人用的。 (4)config.mk。和arm_config.mk差不多性質(zhì)。 (5)COPYING。版權(quán)聲明,uboot本身是GPL許可證的。 (6)CREDITS。鳴謝,里面記錄了對uboot有貢獻(xiàn)的人,感謝目錄。 (7)image_split。一個(gè)腳本,看說明是用來分割uboot.bin到BL1的,暫時(shí)用不到,先不管。 (8)MAINTAINERS。維護(hù)者,就是當(dāng)前在參與維護(hù)uboot源碼的社區(qū)工作者。 (9)MAKEALL。一個(gè)腳本,應(yīng)該是幫助編譯uboot的。 (10)Makefile。這個(gè)很重要,是uboot源代碼的主Makefile,將來整個(gè)uboot被編譯時(shí)就是用這個(gè)Makefile管理編譯的,所以我們在下個(gè)課程中研究uboot配置編譯過程時(shí)就要分析這個(gè)Makefile。 (11)mk?焖倬幾g的腳本,其實(shí)就是先清理然后配置然后編譯而已。 (12)mkconfig。這個(gè)很重要,是uboot配置階段的主要配置腳本。uboot的可移植性很大程度就是靠這個(gè)配置腳本在維護(hù)的。我們在下個(gè)課程中研究uboot配置編譯過程時(shí)就要分析這個(gè)配置腳本。 (13)mkmovi。暫時(shí)不去管他,一個(gè)腳本,和iNand/SD卡啟動(dòng)有關(guān) (14)README。所有的軟件都有README,一般拿到一個(gè)東西要先讀README,這個(gè)東西其實(shí)就是個(gè)簡單的使用說明書。 (15)rules.mk。這個(gè)文件是我們uboot的Makefile使用的規(guī)則,本身非常重要,但是我們不去分析他,不去看他。

文件夾介紹:

(1)api. 硬件無關(guān)的功能函數(shù)的API。uboot移植時(shí)基本不用管,這些函數(shù)是uboot本身使用的。 (2)api_examples. API相關(guān)的測試事例代碼。 (3)board。board是板的意思,板就是開發(fā)板。board文件夾下每一個(gè)文件都代表一個(gè)開發(fā)板,這個(gè)文件夾下面放的文件就是用來描述這一個(gè)開發(fā)板的信息的。board目錄下有多少個(gè)文件夾,就表示當(dāng)前這個(gè)uboot已經(jīng)被移植到多少個(gè)開發(fā)板上了(當(dāng)前的uboot支持多少個(gè)開發(fā)板)。 (4)common。common是普遍的普通的,這個(gè)文件夾下放的是一些與具體硬件無關(guān)的普遍適用的一些代碼。譬如控制臺實(shí)現(xiàn)、crc校驗(yàn)的。但是更多的主要是兩類: 一類是cmd開頭的,是用來實(shí)現(xiàn)uboot的命令系統(tǒng)的;另一類是env開頭的,是用來實(shí)現(xiàn)環(huán)境變量的。 (5)cpu。這個(gè)目錄是SoC相關(guān)的,里面存放的代碼都是SoC相關(guān)初始化和控制代碼(譬如CPU的、中斷的、串口等SoC內(nèi)部外設(shè)的,包括起始代碼start.S也在這里)。里面很多子文件夾,每一個(gè)子文件夾就是一個(gè)SoC系列。 注意:這個(gè)問價(jià)是嚴(yán)格和硬件相關(guān)的,因此移植時(shí)也是要注意的。但是因?yàn)檫@個(gè)文件夾內(nèi)都是SoC有關(guān)的,我們自己的開發(fā)板和三星的開發(fā)板雖然板子設(shè)計(jì)不同但是SoC都是同一個(gè),因此實(shí)際移植時(shí)這個(gè)目錄幾乎不用動(dòng)。 (6)disk。磁盤有關(guān)的,沒研究過,沒用過。 (7)doc。文檔目錄,里面存放了很多uboot相關(guān)文檔,這些文檔可以幫助我們理解uboot代碼。但是因?yàn)槭羌冇⑽牡,而且很雜亂,所以幾乎沒用。 (8)drivers。顧名思義,驅(qū)動(dòng)。這里面放的就是從linux源代碼中扣出來的原封不動(dòng)的linux設(shè)備驅(qū)動(dòng),主要是開發(fā)板上必須用到的一些驅(qū)動(dòng),如網(wǎng)卡驅(qū)動(dòng)、Inand/SD卡、NandFlash等的驅(qū)動(dòng)。要知道:uboot中的驅(qū)動(dòng)其實(shí)就是linux中的驅(qū)動(dòng),uboot在一定程度上移植了linux的驅(qū)動(dòng)給自己用。但是linux是操作系統(tǒng)而uboot只是個(gè)裸機(jī)程序,因此這種移植會(huì)有不同,讓我說:uboot中的驅(qū)動(dòng)其實(shí)是linux中的驅(qū)動(dòng)的一部分。 (9)examples。示例代碼,沒用過。 (10)fs。filesystem,文件系統(tǒng)。這個(gè)也是從linux源代碼中移植過來的,用來管理Flash等資源。 (11)include。頭文件目錄。uboot和linux kernel在管理頭文件時(shí)都采用了同一個(gè)思路,就是把所有的頭文件全部集中存放在include目錄下,而不是頭文件跟著自己對應(yīng)的c文件。所以在uboot中頭文件包含時(shí)路徑結(jié)構(gòu)要在這里去找。 (12)lib_開頭的一坨。(典型的lib_arm和lib_generic)架構(gòu)相關(guān)的庫文件。譬如lib_arm里面就是arm架構(gòu)使用的一些庫文件。lib_generic里是所有架構(gòu)通用的庫文件。這類文件夾中的內(nèi)容移植時(shí)基本不用管。 (13)libfdt。設(shè)備樹有關(guān)的。linux內(nèi)核在3.4左右的版本的時(shí)候更改了啟動(dòng)傳參的機(jī)制,改用設(shè)備樹來進(jìn)行啟動(dòng)傳參,進(jìn)行硬件信息的描述了。 (14)nand_spl。nand相關(guān)的,不講。 (15)net。網(wǎng)絡(luò)相關(guān)的代碼,譬如uboot中的tftp nfs ping命令 都是在這里實(shí)現(xiàn)的。 (16)onenand開頭的,是onenand相關(guān)的代碼,是三星加的,標(biāo)準(zhǔn)uboot中應(yīng)該是沒有的。 (17)post。沒關(guān)注過,不知道干嘛的。 (18)sd_fusing。這里面代碼實(shí)現(xiàn)了燒錄uboot鏡像到SD卡的代碼。后面要仔細(xì)研究的。 (19)tools。里面是一些工具類的代碼。譬如mkimage。

uboot主Makefile分析

1、uboot version確定(Makefile的24-29行) (1)uboot的版本號分3個(gè)級別: VERSION:主板本號 PATCHLEVEL:次版本號 SUBLEVEL:再次版本號 EXTRAVERSION:另外附加的版本信息 這4個(gè)用.分隔開共同構(gòu)成了最終的版本號。 (2)Makefile中版本號最終生成了一個(gè)變量U_BOOT_VERSION,這個(gè)變量記錄了Makefile中配置的版本號。 (3)include/version_autogenerated.h文件是編譯過程中自動(dòng)生成的一個(gè)文件,所以源目錄中沒有,但是編譯過后的uboot中就有了。它里面的內(nèi)容是一個(gè)宏定義,宏定義的值內(nèi)容就是我們在Makefile中配置的uboot的版本號。 (4)驗(yàn)證方法:自己修改主Makefile中幾個(gè)Version有關(guān)的變量,然后重新編譯uboot,然后燒錄到SD卡中,從SD卡啟動(dòng),然后去看啟動(dòng)時(shí)uboot打印出來的版本信息,看看變化是不是和自己的分析一致。

2、HOSTARCH和HOSTOS (1)直接在shell中執(zhí)行uname -m得到i686,得到的值其實(shí)你當(dāng)前執(zhí)行這個(gè)命令的電腦的CPU的版本號。 (2)shell中的    叫做管道,管道的作用就是把管道前面一個(gè)運(yùn)算式的輸出作為后面一個(gè)的輸入再去做處理,最終的輸出才是我們整個(gè)式子的輸出。 (3)HOSTARCH這個(gè)名字:HOST是主機(jī),就是當(dāng)前在做開發(fā)用的這臺電腦就叫主機(jī);ARCH是architecture(架構(gòu))的縮寫,表示CPU的架構(gòu)。所以HOSTARCH就表示主機(jī)的CPU的架構(gòu)。 (4)這兩個(gè)環(huán)境變量是主機(jī)的操作系統(tǒng)和主機(jī)的CPU架構(gòu),得出后保存?zhèn)溆,后面自然?huì)用到。

3、靜默編譯(50-54行) (1)平時(shí)默認(rèn)編譯時(shí)命令行會(huì)打印出來很多編譯信息。但是有時(shí)候我們不希望看到這些編譯信息,就后臺編譯即可。這就叫靜默編譯。 (2)使用方法就是編譯時(shí)make -s,-s會(huì)作為MAKEFLAGS傳給Makefile,在50-54行這段代碼作用下XECHO變量就會(huì)被變成空(默認(rèn)等于echo),于是實(shí)現(xiàn)了靜默編譯。

4、2種編譯方法(原地編譯和單獨(dú)輸出文件夾編譯) (1)編譯復(fù)雜項(xiàng)目,Makefile提供2種編譯管理方法。默認(rèn)情況下是當(dāng)前文件夾中的.c文件,編譯出來的.o文件會(huì)放在同一文件夾下。這種方式叫原地編譯。原地編譯的好處就是處理起來簡單。 (2)原地編譯有一些壞處:第一,污染了源文件目錄。第二的缺陷就是一套源代碼只能按照一種配置和編譯方法進(jìn)行處理,無法同時(shí)維護(hù)2個(gè)或2個(gè)以上的配置編譯方式。 (3)為了解決以上2種缺陷,uboot支持單獨(dú)輸出文件夾方式的編譯(linux kernel也支持,而且uboot的這種技術(shù)就是從linux kernel學(xué)習(xí)來的)。基本思路就是在編譯時(shí)另外指定一個(gè)輸出目錄,將來所有的編譯生成的.o文件或生成的其他文件全部丟到那個(gè)輸出目錄下去。源代碼目錄不做任何污染,這樣輸出目錄就承載了本次配置編譯的所有結(jié)果。 (4)具體用法:默認(rèn)的就是原地編譯。如果需要指定具體的輸出目錄編譯則有2種方式來指定輸出目錄。(具體參考Makefile 56-76行注釋內(nèi)容) 第一種:make O=輸出目錄 第二種:export BUILD_DIR=輸出目錄 然后再make ,如果兩個(gè)都指定了(既有BUILD_DIR環(huán)境變量存在,又有O=xx),則O=xx具有更高優(yōu)先級,聽他的。 (5)兩種編譯的實(shí)現(xiàn)代碼在Makefile的78-123行。

5、OBJTREE、SRCTREE、TOPDIR (1)OBJTREE:編譯出的.o文件存放的目錄的根目錄。在默認(rèn)編譯下,OBJTREE等于當(dāng)前目錄;在O=xx編譯下,OBJTREE就等于我們設(shè)置的那個(gè)輸出目錄。 (2)SRCTREE: 源碼目錄,其實(shí)就是源代碼的根目錄,也就是當(dāng)前目錄。 總結(jié):在默認(rèn)編譯下,OBJTREE和SRCTREE相等;在O=xx這種編譯下OBJTREE和SRCTREE不相等。Makefile中定義這兩個(gè)變量,其實(shí)就是為了記錄編譯后的.o文件往哪里放,就是為了實(shí)現(xiàn)O=xx的這種編譯方式的。

6、MKCONFIG(Makefile的101行) (1)Makefile中定義的一個(gè)變量(在這里定義,在后面使用),它的值就是我們源碼根目錄下面的mkconfig。 這個(gè)mkconfig是一個(gè)腳本,這個(gè)腳本就是uboot配置階段的配置腳本。后面仔細(xì)說

7、include $(obj)include/config.mk(133行) (1)include/config.mk不是源碼自帶的(你在沒有編譯過的源碼目錄下是找不到這個(gè)文件的),要在配置過程(make x210_sd_config)中才會(huì)生成這個(gè)文件。因此這個(gè)文件的值和我們配置過程有關(guān),是由配置過程根據(jù)我們的配置自動(dòng)生成的。 (2)我們X210在iNand情況下配置生成的config.mk內(nèi)容為: ARCH = arm CPU = s5pc11x BOARD = x210 VENDOR = samsung SOC = s5pc110 (3)我們在下一行(134行)export導(dǎo)出了這5個(gè)變量作為環(huán)境變量。所以著兩行加起來其實(shí)就是為當(dāng)前makefile定義了5個(gè)環(huán)境變量而已。之所以不直接給出這5個(gè)環(huán)境變量的值,是因?yàn)槲覀兿M@5個(gè)值是可以被人很容易的、集中的配置的。 (4)這里的配置值來自于2589行那里的配置項(xiàng)。如果我們要更改這里的某個(gè)配置值要到2589行那里調(diào)用MKCONFIG腳本傳參時(shí)的參數(shù)。

8、ARCH CROSS_COMPILE (1)接下來有2個(gè)很重要的環(huán)境變量。一個(gè)是ARCH,上面導(dǎo)出的,值來自于我們的配置過程,它的值會(huì)影響后面的CROSS_COMPILE環(huán)境變量的值。ARCH的意義是定義當(dāng)前編譯的目標(biāo)CPU的架構(gòu)。 (2)CROSS_COMPILE是定義交叉編譯工具鏈的前綴的。定義這些前綴是為了在后面用(用前綴加上后綴來定義編譯過程中用到的各種工具鏈中的工具)。我們把前綴和后綴分開還有一個(gè)原因就是:在不同CPU架構(gòu)上的交叉編譯工具鏈,只是前綴不一樣,后綴都是一樣的。因此定義時(shí)把前綴和后綴分開,只需要在定義前綴時(shí)區(qū)分各種架構(gòu)即可實(shí)現(xiàn)可移植性。 (3)CROSS_COMPILE在136-182行來確定。CROSS_COMPILE是被ARCH所確定的,只要配置了ARCH=arm,那么我們就只能在ARM的那個(gè)分支去設(shè)置CROSS_COMPILE的值。這個(gè)設(shè)置值只要能保證找到那個(gè)交叉編譯工具鏈即可,不一定非得是全路徑的,相對路徑也可以。(如果已經(jīng)將工具鏈導(dǎo)出到環(huán)境變量,并且設(shè)置了符號鏈接,這樣CROSS_COMPILE = arm-linux-就可以) (4)實(shí)際運(yùn)用時(shí),我們可以在Makefile中去更改設(shè)置CROSS_COMPILE的值,也可以在編譯時(shí)用make CROSS_COMPILE=xxxx來設(shè)置,而且編譯時(shí)傳參的方法可以覆蓋Makefile里面的設(shè)置。

9、$(TOPDIR)/config.mk(主Makefile的185行) 編譯工具定義(config.mk 94-107行) 包含開發(fā)板配置項(xiàng)目(config.mk, 112行) (1)autoconfig.mk文件不是源碼提供的,是配置過程自動(dòng)生成的。 (2)這個(gè)文件的作用就是用來指導(dǎo)整個(gè)uboot的編譯過程。這個(gè)文件的內(nèi)容其實(shí)就是很多CONFIG_開頭的宏(可以理解為變量),這些宏/變量會(huì)影響我們uboot編譯過程的走向(原理就是條件編譯)。在uboot代碼中有很多地方使用條件編譯進(jìn)行編寫,這個(gè)條件編譯是用來實(shí)現(xiàn)可移植性的。(可以說uboot的源代碼在很大程度來說是拼湊起來的,同一個(gè)代碼包含了各種不同開發(fā)板的適用代碼,用條件編譯進(jìn)行區(qū)別。) (3)這個(gè)文件不是憑空產(chǎn)生的,配置過程也是需要原材料來產(chǎn)生這個(gè)文件的。原材料在源碼目錄的inlcude/configs/xxx.h頭文件。(X210開發(fā)板中為include/configs/x210_sd.h)。這個(gè)h頭文件里面全都是宏定義,這些宏定義就是我們對當(dāng)前開發(fā)板的移植。每一個(gè)開發(fā)板的移植都對應(yīng)這個(gè)目錄下的一個(gè)頭文件,這個(gè)頭文件里每一個(gè)宏定義都很重要,這些配置的宏定義就是我們移植uboot的關(guān)鍵所在。

10、鏈接腳本(config.mk 142-149行) (1)如果定義了CONFIG_NAND_U_BOOT宏,則鏈接腳本叫u-boot-nand.lds,如果未定義這個(gè)宏則鏈接腳本叫u-boot.lds。 (2)從字面意思分析,即可知:CONFIG_NAND_U_BOOT是在Nand版本情況下才使用的,我們使用的X210都是iNand版本的,因此這個(gè)宏沒有的。 (3)實(shí)際在boardsamsungx210目錄下有u-boot.lds,這個(gè)就是鏈接腳本。我們在分析uboot的編譯鏈接過程時(shí)就要考慮這個(gè)鏈接腳本。

11、TEXT_BASE(config.mk 156-158行) (1)Makefile中在配置X210開發(fā)板時(shí),在board/samsung/x210目錄下生成了一個(gè)文件config.mk,其中的內(nèi)容就是:TEXT_BASE = 0xc3e00000相當(dāng)于定義了一個(gè)變量。 (2)TEXT_BASE是將來我們整個(gè)uboot鏈接時(shí)指定的鏈接地址。因?yàn)閡boot中啟用了虛擬地址映射,因此這個(gè)C3E00000地址就等于0x23E00000(也可能是33E00000具體地址要取決于uboot中做的虛擬地址映射關(guān)系)。 (3)回顧裸機(jī)中講的鏈接地址的問題,再想想dnw方式先下載x210_usb.bin然后再下載uboot.bin時(shí)為什么第二個(gè)地址是23E00000.

12、自動(dòng)推導(dǎo)規(guī)則(config.mk 239-256行) 我們在講Makefile時(shí)提到過自動(dòng)推導(dǎo)規(guī)則

13、Makefile的目標(biāo) (1)291行出現(xiàn)了整個(gè)主Makefile中第一個(gè)目標(biāo)all(也就是默認(rèn)目標(biāo),我們直接在uboot根目錄下make其實(shí)就等于make all,就等于make這個(gè)目標(biāo)) (2)目標(biāo)中有一些比較重要的。譬如:u-boot是最終編譯鏈接生成的elf格式的可執(zhí)行文件, (3)unconfig字面意思來理解就是未配置。這個(gè)符號用來做為我們各個(gè)開發(fā)板配置目標(biāo)的依賴。目標(biāo)是當(dāng)我們已經(jīng)配置過一個(gè)開發(fā)板后再次去配置時(shí)還可以配置。 (4)我們配置開發(fā)板時(shí)使用:make x210_sd_config,因此分析x210_sd_config肯定是主Makefile中的一個(gè)目標(biāo)。

uboot配置過程詳解

(1)mkconfig腳本的6個(gè)參數(shù) $(@:_config=) arm  s5pc11x  x210  samsung  s5pc110(Makefile中2590行) x210_sd_config里的_config部分用空替換,得到:x210_sd,這就是第一個(gè)參數(shù),所以: $1: x210_sd $2: arm $3: s5pc11x $4: x210 $5: samsumg $6: s5pc110 所以,$# = 6 (2)第23行:其實(shí)就是看BOARD_NAME變量是否有值,如果有值就維持不變;如果無值就給他賦值為$1,實(shí)際分析結(jié)果:BOARD_NAME=x210_sd (3)第25行:如果$#小于4,則exit 1(mkconfig腳本返回1) (4)第26行:如果$#大于6,則也返回1. 所以:mkconfig腳本傳參只能是4、5、6,如果大于6或者小于4都不行。 (5)從第33行到第118行,都是在創(chuàng)建符號鏈接。為什么要?jiǎng)?chuàng)建符號鏈接?這些符號鏈接文件的存在就是整個(gè)配置過程的核心,這些符號鏈接文件(文件夾)的主要作用是給頭文件包含等過程提供指向性連接。根本目的是讓uboot具有可移植性。uboot可移植性的實(shí)現(xiàn)原理:在uboot中有很多彼此平行的代碼,各自屬于各自不同的架構(gòu)/CPU/開發(fā)板,我們在具體到一個(gè)開發(fā)板的編譯時(shí)用符號連接的方式提供一個(gè)具體的名字的文件夾供編譯時(shí)使用。這樣就可以在配置的過程中通過不同的配置使用不同的文件,就可以正確的包含正確的文件。 (6)創(chuàng)建的符號鏈接: 第一個(gè):在include目錄下創(chuàng)建asm文件,指向asm-arm。(46-48行) 第二個(gè):在inlcude/asm-arm下創(chuàng)建一個(gè)arch文件,指向include/asm-arm/arch-s5pc110 第三個(gè):在include目錄下創(chuàng)建regs.h文件,指向include/s5pc110.h 刪除第二個(gè)。 第四個(gè):在inlcude/asm-arm下創(chuàng)建一個(gè)arch文件,指向include/asm-arm/arch-s5pc11x 第五個(gè):在include/asm-arm下創(chuàng)建一個(gè)proc文件,指向include/asm-arm/proc-armv 總結(jié):一共創(chuàng)建了4個(gè)符號鏈接。這4個(gè)符號鏈接將來在寫代碼過程中,頭文件包含時(shí)非常有用。譬如一個(gè)頭文件包含可能是:#include <asm/xx.h> (7)創(chuàng)建include/config.mk文件(mkconfig文件123-129行) (8)創(chuàng)建include/config.mk文件是為了讓主Makefile在第133行去包含的。 (9)思考:uboot的配置和編譯過程的配合。編譯的時(shí)候需要ARCH=arm、CPU=xx等這些變量來指導(dǎo)編譯,配置的時(shí)候就是為編譯階段提供這些變量。那為什么不在Makefile中直接定義這些變量去使用,而要在mkconfig腳本中創(chuàng)建config.mk文件然后又在Makefile中include這些文件呢? 個(gè)人理解是為了uboot的可移植性。 (10)理解這些腳本時(shí),時(shí)刻要注意自己當(dāng)前所處的路徑。 (11)創(chuàng)建(默認(rèn)情況)/追加(make -a時(shí)追加)include/config.h文件(mkconfig文件的134-141行)。 (12)這個(gè)文件里面的內(nèi)容就一行#include <configs/x210_sd.h>,這個(gè)頭文件是我們移植x210開發(fā)板時(shí),對開發(fā)板的宏定義配置文件。這個(gè)文件是我們移植x210時(shí)最主要的文件。 (13)x210_sd.h文件會(huì)被用來生成一個(gè)autoconfig.mk文件,這個(gè)文件會(huì)被主Makefile引入,指導(dǎo)整個(gè)編譯過程。這里面的這些宏定義會(huì)影響我們對uboot中大部分.c文件中一些條件編譯的選擇。從而實(shí)現(xiàn)最終的可移植性。 注意:uboot的整個(gè)配置過程,很多文件之間是有關(guān)聯(lián)的(有時(shí)候這個(gè)文件是在那個(gè)文件中創(chuàng)建出來的;有時(shí)候這個(gè)文件被那個(gè)文件包含進(jìn)去;有時(shí)候這個(gè)文件是由那個(gè)文件的內(nèi)容生成的決定的) 注意:uboot中配置和編譯過程,所有的文件或者全局變量都是字符串形式的(不是指的C語言字符串的概念,指的是都是字符組成的序列)。這意味著我們整個(gè)uboot的配置過程都是字符串匹配的,所以一定要細(xì)節(jié),注意大小寫,要注意不要輸錯(cuò)字符,因?yàn)橐坏╁e(cuò)一個(gè)最后會(huì)出現(xiàn)一些莫名其妙的錯(cuò)誤,很難排查,這個(gè)是uboot移植過程中新手來說最難的地方。

uboot的鏈接腳本

(1)uboot的鏈接腳本和我們之前裸機(jī)中的鏈接腳本并沒有本質(zhì)區(qū)別,只是復(fù)雜度高一些,文件多一些,使用到的技巧多一些。

(2)ENTRY(_start)用來指定整個(gè)程序的入口地址。所謂入口地址就是整個(gè)程序的開頭地址,可以認(rèn)為就是整個(gè)程序的第一句指令。有點(diǎn)像C語言中的main。

(3)之前在裸機(jī)中指定程序的鏈接地址有2種方法:一種是在Makefile中l(wèi)d的flags用-Ttext 0x20000000來指定;第二種是在鏈接腳本的SECTIONS開頭用.=0x20000000來指定。兩種都可以實(shí)現(xiàn)相同效果。其實(shí),這兩種技巧是可以共同配合使用的,也就是說既在鏈接腳本中指定也在ld flags中用-Ttext來指定。兩個(gè)都指定以后以-Ttext指定的為準(zhǔn)。

4、以啟動(dòng)內(nèi)核為主線分析代碼

1、start.S引入

u-boot.lds中找到start.S入口 (1)在C語言中整個(gè)項(xiàng)目的入口就是main函數(shù)(這是C語言規(guī)定的),所以譬如說一個(gè)有10000個(gè).c文件的項(xiàng)目,第一個(gè)要分析的文件就是包含了main函數(shù)的那個(gè)文件。 (2)在uboot中因?yàn)橛袇R編階段參與,因此不能直接找main.c。整個(gè)程序的入口取決于鏈接腳本中ENTRY聲明的地方。ENTRY(_start)因此_start符號所在的文件就是整個(gè)程序的起始文件,_start所在處的代碼就是整個(gè)程序的起始代碼。

2、不簡單的頭文件包含 (1)#include <config.h>。 config.h是在include目錄下的,這個(gè)文件不是源碼中本身存在的文件,而是配置過程中自動(dòng)生成的文件。(詳見mkconfig腳本)。 這個(gè)文件的內(nèi)容其實(shí)是包含了一個(gè)頭文件:#include <configs/x210_sd.h>“. (2)經(jīng)過分析后,發(fā)現(xiàn)start.S中包含的第一個(gè)頭文件就是:include/configs/x210_sd.h,這個(gè)文件是整個(gè)uboot移植時(shí)的配置文件。這里面是好多宏。 因此這個(gè)頭文件包含將include/configs/x210_sd.h文件和start.S文件關(guān)聯(lián)了起來。因此之后在分析start.S文件時(shí),主要要考慮的就是x210_sd.h文件。 (3)#include <version.h>。include/version.h中包含了include/version_autogenerated.h,這個(gè)頭文件就是配置過程中自動(dòng)生成的。里面就一行內(nèi)容: #define U_BOOT_VERSION “U-Boot 1.3.4“。這里面定義的宏U_BOOT_VERSION的值是一個(gè)字符串,字符串中的版本號信息來自于Makefile中的配置值。這個(gè)宏在程序中會(huì)被調(diào)用,在uboot啟動(dòng)過程中會(huì)串口打印出uboot的版本號,那個(gè)版本號信息就是從這來的。 (4)#include <asm/proc/domain.h>。asm目錄不是uboot中的原生目錄,uboot中本來是沒有這個(gè)目錄的。asm目錄是配置時(shí)創(chuàng)建的一個(gè)符號鏈接,實(shí)際指向的是就是asm-arm(詳解上一章節(jié)分析mkconfig腳本時(shí)). (5)經(jīng)過分析后發(fā)現(xiàn),實(shí)際文件是:include/asm-arm/proc-armv/domain.h (6)從這里可以看出之前配置時(shí)創(chuàng)建的符號鏈接的作用,如果沒有這些符號鏈接則編譯時(shí)根本通不過,因?yàn)檎也坏筋^文件。(所以uboot不能在windows的共享文件夾下配置編譯,因?yàn)閣indows中沒有符號鏈接) 思考:為什么start.S不直接包含asm-arm/proc-armv/domain.h,而要用asm/proc/domain.h。這樣的設(shè)計(jì)主要是為了可移植性。因?yàn)槿绻苯影,則start.S文件和CPU架構(gòu)(和硬件)有關(guān)了,可移植性就差了。譬如我要把uboot移植到mips架構(gòu)下,則start.S源代碼中所有的頭文件包含全部要修改。我們用了符號鏈接之后,則start.S中源代碼不用改,只需要在具體的硬件移植時(shí)配置不同,創(chuàng)建的符號鏈接指向的不同,則可以具有可移植性。

3、uboot匯編部分

1、啟動(dòng)代碼的16字節(jié)頭部

(1)裸機(jī)中講過,在SD卡啟動(dòng)/Nand啟動(dòng)等整個(gè)鏡像開頭需要16字節(jié)的校驗(yàn)頭。(mkv210image.c中就是為了計(jì)算這個(gè)校驗(yàn)頭)。我們以前做裸機(jī)程序時(shí)根本沒考慮這16字節(jié)校驗(yàn)頭,因?yàn)椋?、如果我們是usb啟動(dòng)直接下載的方式啟動(dòng)的則不需要16字節(jié)校驗(yàn)頭(irom application note);2、如果是SD卡啟動(dòng)mkv210image.c中會(huì)給原鏡像前加16字節(jié)的校驗(yàn)頭。 (2)uboot這里start.S中在開頭位置放了16字節(jié)的填充占位,這個(gè)占位的16字節(jié)只是保證正式的image的頭部確實(shí)有16字節(jié),但是這16字節(jié)的內(nèi)容是不對的,還是需要后面去計(jì)算校驗(yàn)和然后重新填充的。

2、異常向量表的構(gòu)建 (1)異常向量表是硬件決定的,軟件只是參照硬件的設(shè)計(jì)來實(shí)現(xiàn)它。 (2)異常向量表中每種異常都應(yīng)該被處理,否則真遇到了這種異常就跑飛了。但是我們在uboot中并未非常細(xì)致的處理各種異常。 (3)復(fù)位異常處的代碼是:b reset,因此在CPU復(fù)位后真正去執(zhí)行的有效代碼是reset處的代碼,因此reset符號處才是真正的有意義的代碼開始的地方。

3、有點(diǎn)意思的deadbeef (1).balignl 16,0xdeadbeef.    這一句指令是讓當(dāng)前地址對齊排布,如果當(dāng)前地址不對齊則自動(dòng)向后走地址直到對齊,并且向后走的那些內(nèi)存要用0xdeadbeef來填充。 (2)0xdeadbeef這是一個(gè)十六進(jìn)制的數(shù)字,這個(gè)數(shù)字很有意思,組成這個(gè)數(shù)字的十六進(jìn)制數(shù)全是abcdef之中的字母,而且這8個(gè)字母剛好組成了英文的dead beef這兩個(gè)單詞,字面意思是壞牛肉 (3)為什么要對齊訪問?有時(shí)候是效率的要求,有時(shí)候是硬件的特殊要求。

4、TEXT_BASE等 (1)第100行這個(gè)TEXT_BASE就是上個(gè)課程中分析Makefile時(shí)講到的那個(gè)配置階段的TEXT_BASE,其實(shí)就是我們鏈接時(shí)指定的uboot的鏈接地址。(值就是c3e00000) (2)源代碼中和配置Makefile中很多變量是可以互相運(yùn)送的。簡單來說有些符號的值可以從Makefile中傳遞到源代碼中。 (1)CFG_PHY_UBOOT_BASE     33e00000    uboot在DDR中的物理地址

5、設(shè)置CPU為SVC模式 (1)msr    cpsr_c, #0xd3    將CPU設(shè)置為禁止FIQ IRQ,ARM狀態(tài),SVC模式。 (2)其實(shí)ARM CPU在復(fù)位時(shí)默認(rèn)就會(huì)進(jìn)入SVC模式,但是這里還是使用軟件將其置為SVC模式。整個(gè)uboot工作時(shí)CPU一直處于SVC模式。

6、設(shè)置L2、L1cache和MMU (1)bl    disable_l2cache        // 禁止L2 cache (2)bl    set_l2cache_auxctrl_cycle    // l2 cache相關(guān)初始化 (3)bl    enable_l2cache        // 使能l2 cache (4)刷新L1 cache的icache和dcache。 (5)關(guān)閉MMU 總結(jié):上面這5步都是和CPU的cache和mmu有關(guān)的,不用去細(xì)看,大概知道即可。

7、識別并暫存啟動(dòng)介質(zhì)選擇 (1)從哪里啟動(dòng)是由SoC的OM5:OM0這6個(gè)引腳的高低電平?jīng)Q定的。 (2)實(shí)際上在210內(nèi)部有一個(gè)寄存器(地址是0xE0000004),這個(gè)寄存器中的值是硬件根據(jù)OM引腳的設(shè)置而自動(dòng)設(shè)置值的。這個(gè)值反映的就是OM引腳的接法(電平高低),也就是真正的啟動(dòng)介質(zhì)是誰。 (3)我們代碼中可以通過讀取這個(gè)寄存器的值然后判斷其值來確定當(dāng)前選中的啟動(dòng)介質(zhì)是Nand還是SD還是其他的。 (4)start.S的225-227行執(zhí)行完后,在r2寄存器中存儲(chǔ)了一個(gè)數(shù)字,這個(gè)數(shù)字等于某個(gè)特定值時(shí)就表示SD啟動(dòng),等于另一個(gè)特定值時(shí)表示從Nand啟動(dòng)

發(fā)表回復(fù)

您需要登錄后才可以回帖 登錄 | 立即注冊

本版積分規(guī)則


聯(lián)系客服 關(guān)注微信 下載APP 返回頂部 返回列表