《ARM嵌入式系統(tǒng)原理及應(yīng)用開發(fā)》課件第7章_第1頁
《ARM嵌入式系統(tǒng)原理及應(yīng)用開發(fā)》課件第7章_第2頁
《ARM嵌入式系統(tǒng)原理及應(yīng)用開發(fā)》課件第7章_第3頁
《ARM嵌入式系統(tǒng)原理及應(yīng)用開發(fā)》課件第7章_第4頁
《ARM嵌入式系統(tǒng)原理及應(yīng)用開發(fā)》課件第7章_第5頁
已閱讀5頁,還剩74頁未讀 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡介

第7章嵌入式系統(tǒng)的BootLoader7.1BootLoader概述7.2BootLoader與嵌入式系統(tǒng)的關(guān)系7.3BootLoader的主要功能及典型結(jié)構(gòu)7.4S3C44B0X的BootLoader分析7.5U-Boot啟動(dòng)流程及相關(guān)代碼分析 7.1BootLoader概述

7.1.1BootLoader的作用和任務(wù)

當(dāng)一個(gè)微處理器啟動(dòng)時(shí),它首先執(zhí)行預(yù)定地址處的指令。通常這個(gè)位置是只讀內(nèi)存,其中存放著系統(tǒng)初始化或引導(dǎo)程序,如PC中的BIOS。BIOS進(jìn)行低級(jí)的處理器初始化并配置其他硬件,接著判斷哪一個(gè)磁盤包含有操作系統(tǒng)(OS),再把該操作系統(tǒng)復(fù)制到RAM中,并把控制權(quán)交給操作系統(tǒng)。嵌入式系統(tǒng)的BootLoader程序,即系統(tǒng)的引導(dǎo)裝載程序,簡單地說,就是在操作系統(tǒng)內(nèi)核或用戶應(yīng)用程序之前運(yùn)行的一段小程序。通過這段小程序可以初始化硬件設(shè)備和建立內(nèi)存空間的映射圖,將系統(tǒng)的軟、硬件環(huán)境帶到一個(gè)合適的狀態(tài),以便為最終調(diào)用操作系統(tǒng)內(nèi)核或用戶應(yīng)用程序準(zhǔn)備好正確的環(huán)境。有的操作系統(tǒng)比較簡單,或只有簡單的應(yīng)用程序,因而不需要專門的BootLoader來安裝內(nèi)核和文件系統(tǒng)。但仔細(xì)分析就會(huì)發(fā)現(xiàn),它們都需要一個(gè)初始化程序來完成初始化,為后面程序的執(zhí)行準(zhǔn)備一個(gè)正確的環(huán)境。通常,BootLoader是依賴于硬件而實(shí)現(xiàn)的,因此,為嵌入式系統(tǒng)建立一個(gè)通用的BootLoader是很困難的。但是可以歸納出一些通用的概念,以便了解特定BootLoader的設(shè)計(jì)與實(shí)現(xiàn)。BootLoader的主要任務(wù)如圖7.1所示。圖7.1BootLoader的主要任務(wù)7.1.2常用嵌入式BootLoader介紹

常用的嵌入式BootLoader有vivi、U-Boot、RedBoot、ARMBoot、Blob和DIY。

1.?vivi

vivi是由韓國MIZI公司開發(fā)的一種專門用于ARM產(chǎn)品線的BootLoader。因?yàn)関ivi目前只支持使用串口與主機(jī)通信,所以必須使用一條串口電纜來連接目標(biāo)板和主機(jī)。vivi的源代碼下載地址為/developer/s3c2410x/download/vivi.html。vivi有以下作用:

●檢測目標(biāo)板。

●下載程序并寫入Flash。

●初始化硬件。

●把內(nèi)核從Flash復(fù)制到RAM,然后啟動(dòng)它。

vivi源代碼的主要目錄的解釋如下:

●?CVS:存放CVS工具相關(guān)的文件。

●?Documentation:存放一些vivi的幫助文檔。

●?Arch:存放與CPU構(gòu)架體系結(jié)構(gòu)有關(guān)的代碼文件。

●?drivers:存放與vivi相關(guān)的驅(qū)動(dòng)代碼文件。

●?include:存放所有vivi源代碼的頭文件。

●?init:存放vivi初始化代碼文件。

●?lib:存放vivi實(shí)現(xiàn)的庫函數(shù)文件。

●?scripts:存放vivi腳本配置文件。

●?test:存放一些測試代碼文件。

●?util:存放一些與NandFlash燒寫image相關(guān)的工具實(shí)現(xiàn)代碼。

2.?U-Boot

U-Boot是德國DENX小組開發(fā)的用于多種嵌入式CPU的BootLoader程序,它可以運(yùn)行在PowerPC、ARM、MIPS等多種嵌入式開發(fā)板上。從/或

ftp://ftp.denx.de/pub/u-boot/站點(diǎn)均可以下載U-Boot的源代碼。

U-Boot源代碼的主要目錄的解釋如下:

●?board:目標(biāo)板相關(guān)文件,主要包含SDRAM、Flash驅(qū)動(dòng)。

●?common:獨(dú)立于處理器體系結(jié)構(gòu)的通用代碼,如內(nèi)存大小探測與故障檢測代碼。●?cpu:與處理器相關(guān)的文件,如mpc8xx子目錄下的串口、網(wǎng)口、LCD驅(qū)動(dòng)及中斷初始化等文件。

●?driver:通用設(shè)備驅(qū)動(dòng),如CFIFlash驅(qū)動(dòng)(目前對(duì)IntelFlash支持較好)。

●?doc:U-Boot的說明文檔。

●?examples:可以在U-Boot下運(yùn)行的示例程序,如hello_world.c和timer.c。

●?include:U-Boot頭文件,尤其是configs子目錄下與目標(biāo)板相關(guān)的配置頭文件,它是移植過程中經(jīng)常要修改的文件。●?lib_xxx:處理器體系相關(guān)的文件,如lib_ppc、lib_arm目錄分別包含的與PowerPC、ARM體系結(jié)構(gòu)相關(guān)的文件。

●?net:與網(wǎng)絡(luò)功能相關(guān)的文件目錄,如boot、NFS和TFTP。

●?post:上電自檢文件目錄,尚有待進(jìn)一步完善。

●?rtc:RTC(RealTimeClock,實(shí)時(shí)時(shí)鐘)驅(qū)動(dòng)程序。

●?tools:用于創(chuàng)建U-Boot、S-RECORD和BIN鏡像文件的工具。

3.RedBoot

RedBoot是一個(gè)專門為嵌入式系統(tǒng)定制的引導(dǎo)啟動(dòng)工具,最初由RedHat公司開發(fā)。它基于ECOS(EmbeddedConfigurableOperatingSystem)的硬件抽象層,同時(shí)繼承了ECOS的高可靠性、簡潔性、可配置性和可移植性等特點(diǎn)。在/redboot站點(diǎn)可以下載RedBoot源碼,同時(shí)也可以了解更多關(guān)于Redboot的詳情信息。Redboot在嵌入式體系中應(yīng)用非常廣泛。

RedBoot是集BootLoader、調(diào)試和Flash燒寫于一體的,支持串口、網(wǎng)絡(luò)下載的可執(zhí)行嵌入式應(yīng)用程序。它既可以用在產(chǎn)品的開發(fā)階段(調(diào)試功能),也可以用在最終的產(chǎn)品上(Flash更新、網(wǎng)絡(luò)啟動(dòng))。RedBoot支持下載和調(diào)試應(yīng)用程序,用戶可以通過TFTP協(xié)議下載應(yīng)用程序和image,或者通過串口用X-modem/Y-modem下載。開發(fā)板可以通過BOOTP/DHCP協(xié)議動(dòng)態(tài)配置IP地址,并支持跨網(wǎng)段訪問,所以可對(duì)gcc編譯的程序進(jìn)行源代碼級(jí)的調(diào)試。相比于簡易JTAG調(diào)試器,它可靠、高速、穩(wěn)定。RedBoot支持用GDB通過串口或網(wǎng)卡調(diào)試嵌入式程序。用戶可通過串口或網(wǎng)卡以命令行的形式管理Flash上的image,并下載image到Flash。動(dòng)態(tài)配置RedBoot啟動(dòng)的各種參數(shù)、啟動(dòng)腳本,上電后RedBoot可自動(dòng)從Flash或TFTP服務(wù)器上下載應(yīng)用程序執(zhí)行。

4.?ARMBoot

ARMBoot是一個(gè)以ARM或StrongARM為CPU內(nèi)核的嵌入式系統(tǒng)的BootLoader固件程序,該軟件的主要目標(biāo)是使新的平臺(tái)更容易被移植,并且盡可能地發(fā)揮其強(qiáng)大性能。它只基于ARM固件,但是它支持多種類型的啟動(dòng),如Flash,網(wǎng)絡(luò)下載通過BOOTP、DHCP、TFTP等。它也是開源項(xiàng)目,可以從/projects/armboot網(wǎng)站獲得最新的ARMBoot源碼和詳細(xì)資料,它在ARM處理器方面應(yīng)用非常廣泛。

5.?Blob

Blob是BootLoaderObject的縮寫,是一款功能強(qiáng)大的BootLoader,其源代碼在/projects/blob上可以獲取。Blob最初是由Jan-DerkBakker和ErikMouw兩人為一塊名為LART(LinuxAdvancedRadioTerminal)的開發(fā)板編寫的,該板使用的處理器是strongARMSA-1100?,F(xiàn)在Blob已經(jīng)被成功地移植到許多基于ARM的CPU上。

6.?DIY

DIY(DoItYourself),即自己制作。上面介紹的U-Boot、vivi、Blob、RedBoot、ARMboot等成熟工具雖然移植起來簡單快捷,但它們都存在著一定的局限性。首先,因?yàn)樗鼈兪敲嫦虼蟛糠钟布墓ぞ?,所以在功能上要滿足大部分硬件的需求,但一般情況下用戶只需要與特定的開發(fā)板相關(guān)的實(shí)現(xiàn)代碼,其他型號(hào)開發(fā)板的實(shí)現(xiàn)代碼對(duì)它來說是沒有用的,因此通常會(huì)有較大的無用代碼;其次,它們?cè)谑褂蒙喜粔蜢`活,如在這些BootLoader上添加自己的特有功能比較困難,因?yàn)楸仨毷煜ぴ摯a的組織關(guān)系,且了解它的配置編譯等文件。用DIY的方式自己編寫針對(duì)目標(biāo)的BootLoader,不但代碼量短小,而且靈活性很大,最重要的是將來容易維護(hù)。所以在實(shí)際嵌入式產(chǎn)品的開發(fā)中大多都選擇DIY的方式編寫B(tài)ootLoader。

7.2BootLoader與嵌入式系統(tǒng)的關(guān)系

不同的BootLoader有不同的處理器體系結(jié)構(gòu),有些BootLoader還支持多種體系結(jié)構(gòu)的處理器,比如U-Boot就同時(shí)支持ARM體系結(jié)構(gòu)和MIPS體系結(jié)構(gòu)。除了依賴處理器的體系結(jié)構(gòu)外,BootLoader實(shí)際上也依賴于具體的嵌入式板級(jí)設(shè)備的配置。即使是基于同一種處理器構(gòu)建的兩塊不同的嵌入式板級(jí)設(shè)備,它們的BootLoader也是不同的。BootLoader源程序是很關(guān)鍵的代碼,因?yàn)樗前烟囟ǖ臄?shù)字寫入指定硬件寄存器的指令序列。系統(tǒng)加電復(fù)位后,所有的處理器都從處理器制造商預(yù)先安排的地址上取指令,如基于S3C44B0X的處理器在復(fù)位時(shí)通常都從地址0x00000000上取它的第一條指令。而且基于處理器構(gòu)建的嵌入式系統(tǒng)通常都有某種類型的固態(tài)存儲(chǔ)設(shè)備(如ROM、E2PPOM、Flash等)被映射到這個(gè)預(yù)先安排的地址上,因此在系統(tǒng)加電后,處理器將首先執(zhí)行BootLoader程序。

裝有BootLoader內(nèi)核的啟動(dòng)參數(shù)、內(nèi)核映像和根文件系統(tǒng)映像的固態(tài)存儲(chǔ)設(shè)備的典型空間分配結(jié)構(gòu)如圖7.2所示。圖7.2存儲(chǔ)設(shè)備典型空間分配結(jié)構(gòu)7.2.1BootLoader的操作模式

1.啟動(dòng)加載(BootLoading)模式

啟動(dòng)加載模式也稱為自主(Autonomous)模式,即BootLoader從目標(biāo)機(jī)的某個(gè)固態(tài)存儲(chǔ)設(shè)備上將操作系統(tǒng)加載到RAM中運(yùn)行,整個(gè)過程并沒有用戶的介入。這種模式是BootLoader的正常工作模式,因此在嵌入式產(chǎn)品發(fā)布的時(shí)候,BootLoader顯然必須工作在這種模式下。只有工作在這種模式下,當(dāng)系統(tǒng)上電或復(fù)位后,才能正常地運(yùn)行操作系統(tǒng),出現(xiàn)通信信息或圖形界面供用戶操作。

2.下載(DownLoading)模式

當(dāng)采用下載模式時(shí),目標(biāo)機(jī)的BootLoader將通過串口連接、網(wǎng)絡(luò)連接等通信手段從主機(jī)上下載文件,如應(yīng)用程序、數(shù)據(jù)文件、內(nèi)核映像等。從主機(jī)下載的文件通常先被BootLoader保存到目標(biāo)機(jī)的RAM中,然后再被BootLoader寫到目標(biāo)機(jī)上的固態(tài)存儲(chǔ)設(shè)備中。下載模式要求在BootLoader中完成對(duì)串口或以太網(wǎng)口的初始化、定義相關(guān)的命令和向其終端提供相應(yīng)簡單的命令接口。BootLoader的這種模式通常在系統(tǒng)更新時(shí)使用。7.2.2BootLoader的總體設(shè)計(jì)

1.階段設(shè)計(jì)

BootLoader的啟動(dòng)是可以分階段的,因此在設(shè)計(jì)時(shí)也可將BootLoader分為階段1和階段2。BootLoader的設(shè)計(jì)分為兩個(gè)階段的原因如下。

(1)基于編程語言的考慮。階段1主要用匯編語言編寫,這是因?yàn)樗饕M(jìn)行與CPU核心及存儲(chǔ)設(shè)備密切相關(guān)的處理工作和進(jìn)行一些必要的初始化工作,是依賴于CPU體系結(jié)構(gòu)的代碼,所以為了增加效率以及匹配協(xié)處理器的設(shè)置,只能用匯編語言編寫,這部分直接在Flash中執(zhí)行。階段2可以用C語言編寫,主要實(shí)現(xiàn)一般的流程以及對(duì)板級(jí)的一些驅(qū)動(dòng)支持,這部分會(huì)被復(fù)制到RAM中執(zhí)行。

(2)為了使代碼具有更好的可讀性與可移植性。對(duì)于相同的CPU以及存儲(chǔ)設(shè)備,若要增加外設(shè)支持,階段1的代碼可以維持不變,只對(duì)階段2的代碼進(jìn)行修改;而對(duì)于不同的CPU,則只需在階段1中修改基礎(chǔ)代碼。

2.地址規(guī)劃設(shè)計(jì)

當(dāng)BootLoader的階段設(shè)計(jì)完成之后,需要考慮的是鏡像存儲(chǔ)的地址分配,如總鏡像保存在什么地方、階段2對(duì)應(yīng)的鏡像會(huì)被復(fù)制到什么地方、內(nèi)核鏡像原先存放在什么地方及BootLoader會(huì)把它又重新加載到什么地方、如何進(jìn)行準(zhǔn)確的地址規(guī)劃以保證沒有相互沖突等。

本章所介紹的內(nèi)核鏡像以及根文件系統(tǒng)鏡像都是被加載到SDRAM中運(yùn)行的,這樣做是基于運(yùn)行速度的考慮。盡管在嵌入式系統(tǒng)中內(nèi)核鏡像與根文件系統(tǒng)鏡像也可以直接在ROM或Flash這樣的固態(tài)存儲(chǔ)設(shè)備中直接運(yùn)行,但是BootLoader在啟動(dòng)以及加載內(nèi)核時(shí)通常要考慮這一點(diǎn)。雖然BootLoader最終會(huì)生成一個(gè)可執(zhí)行鏡像,但是為了能更清楚地解釋其實(shí)現(xiàn)流程,將其與啟動(dòng)階段對(duì)應(yīng)起來分成鏡像1和鏡像2。事實(shí)上,在編譯過程中也會(huì)形成這兩個(gè)鏡像,即總的鏡像1和被復(fù)制至SDRAM中的鏡像2。這里用物理地址的0x00000000~0x00040000存放BootLoader的鏡像;內(nèi)核鏡像放在物理地址0x000C0000之后的1?MB空間內(nèi)(內(nèi)核鏡像一般都小于1?MB);鏡像2則在SDRAM中運(yùn)行,這樣BootLoader的啟動(dòng)速度會(huì)大大加快。因此這里鏡像2放在SDRAM的以0xA0000000為起始地址的空間內(nèi)運(yùn)行;而內(nèi)核鏡像則規(guī)劃至物理地址的0xA0300000處執(zhí)行。

3.模式設(shè)計(jì)

對(duì)于普通用戶來說只需要BootLoader的啟動(dòng)加載模式;但是對(duì)于開發(fā)者來說,則需要下載模式,因?yàn)樗麄冃枰獙?shí)時(shí)地進(jìn)行一些鏡像的更新。為了在兩者之間做到兼顧,這里介紹一個(gè)既支持啟動(dòng)加載模式又支持下載模式的具體思路:在BootLoader完成一些硬件初始化工作之后、在加載內(nèi)核鏡像之前,判斷一定的時(shí)間內(nèi)有沒有用戶的鍵盤輸入。如果沒有,則為啟動(dòng)加載模式,直接加載內(nèi)核鏡像進(jìn)行啟動(dòng);如果有,則進(jìn)入命令行格式,這時(shí)開發(fā)者就可以根據(jù)自己的需要以及BootLoader的支持情況,做一些其他的工作。模式的轉(zhuǎn)換設(shè)計(jì)主要在階段2中實(shí)現(xiàn)。

7.3BootLoader的主要功能及典型結(jié)構(gòu)

7.3.1BootLoader的階段1

1.基本的硬件初始化

基本的硬件初始化是BootLoader一開始就執(zhí)行的操作,其目的是為了階段2的內(nèi)核的執(zhí)行準(zhǔn)備好一些基本的硬件環(huán)境。它執(zhí)行的步驟如下。

(1)屏蔽所有的中斷。為中斷提供服務(wù)通常是操作系統(tǒng)設(shè)備驅(qū)動(dòng)程序的責(zé)任,因此在BootLoader的執(zhí)行全過程中可以不必響應(yīng)任何中斷。中斷屏蔽可以通過寫處理中斷屏蔽寄存器或狀態(tài)寄存器(比如ARM的CPSR寄存器)來完成。

(2)設(shè)置處理器的速度和時(shí)鐘頻率。這一步驟可以通過設(shè)置時(shí)鐘控制寄存器來完成,注意設(shè)置的時(shí)候應(yīng)該根據(jù)晶振的振蕩頻率和實(shí)際需要的頻率來設(shè)置。

(3)初始化RAM,包括正確地設(shè)置系統(tǒng)內(nèi)存控制器的功能寄存器以及各內(nèi)存控制寄存器。

(4)初始化LED。LED一般通過GPIO來驅(qū)動(dòng),其目的是表明系統(tǒng)的狀態(tài)是否正常。如果板子上沒有LED,那么也可以通過初始化UART向串行口輸出BootLoader的特定字符,如“OK!”信息來完成。這樣可方便用戶判斷BootLoader是否已經(jīng)成功啟動(dòng)。

(5)關(guān)閉處理器內(nèi)部指令/數(shù)據(jù)緩存。

2.加載階段2的RAM空間

為了獲得更快的執(zhí)行速度,通常把階段2加載到RAM空間中來執(zhí)行,因此必須為加載BootLoader的階段2準(zhǔn)備好一段可用的RAM空間。由于階段2通常用C語言來執(zhí)行,因此在考慮空間大小時(shí),除了階段2可執(zhí)行映像的大小外,還必須把堆??臻g也考慮進(jìn)來。此外,空間大小最好是頁面文件(MemoryPage)大小(通常是4?KB)的倍數(shù)。一般而言,1?MB的RAM空間已經(jīng)足夠了。具體的地址范圍可以任意安排,比如Blob方式就是將它的階段2可執(zhí)行映像安排到系統(tǒng)RAM地址0xC0200000開始的1MB空間內(nèi)執(zhí)行。但是,將階段2安排到整個(gè)RAM最頂層的1?MB空間是一種最常用的方法。為了后面敘述的方便,這里把所安排的RAM空間的大小記為stage2_size(字節(jié)),把起始地址和終止地址分別記為stage2_start和stage2_end(這兩個(gè)地址均為以4字節(jié)邊界對(duì)齊)。另外,還必須確保所安排的的地址是可讀寫的RAM空間,因此,必須對(duì)所安排的地址進(jìn)行測試。具體的測試方法可以采用類似于Blob的方法,即以MemoryPage為被測試單位,測試每個(gè)MemoryPage開始的兩個(gè)字是否是可讀寫的。為了后面敘述的方便,這個(gè)檢測算法記為test_mempage,其具體步驟如下。

(1)先保存MemoryPage最開始兩個(gè)字的內(nèi)容。

(2)向這兩個(gè)字寫入任意的數(shù)字,如向第一個(gè)字寫入0x55,第二個(gè)字寫入0xAA。

(3)立即將這兩個(gè)字的內(nèi)容讀回。正常情況下,讀到的內(nèi)容應(yīng)該分別是0x55和0xAA。如果不是,則說明這個(gè)MemoryPage所占據(jù)的地址不是一段有效的RAM空間。

(4)再向這兩個(gè)字中寫入任意的數(shù)字,如向第一個(gè)字寫入0xAA,向第2字寫入0x55。

(5)立即將這兩個(gè)字的內(nèi)容讀回。讀到的內(nèi)容應(yīng)該分別是0xAA和0x55。如果不是,則說明這個(gè)MemoryPage所占據(jù)的地址不是一段有效的RAM空間。

(6)恢復(fù)這兩個(gè)字的原始內(nèi)容,測試完畢。為了得到一段干凈的RAM空間范圍,也可以將所安排的RAM空間進(jìn)行清零操作。

3.復(fù)制階段2到RAM

復(fù)制階段2到RAM時(shí)要確定以下兩點(diǎn):

(1)階段2的可執(zhí)行映像在固態(tài)存儲(chǔ)設(shè)備的存放起始地址和終止地址。

(2)?RAM空間的起始地址。

4.設(shè)置堆棧指針(SP)

堆棧指針的設(shè)置是為執(zhí)行C語言代碼作準(zhǔn)備的。通??梢园裇P的值設(shè)置為stage2_end-4,即在7.3.2節(jié)中提到的那個(gè)1MB的RAM空間的最頂端(堆棧向下生長)。此外,在設(shè)置堆棧指針SP之前,也可以關(guān)閉LED燈,以提示用戶程序準(zhǔn)備跳轉(zhuǎn)到階段2。

5.跳轉(zhuǎn)到階段2的C程序入口點(diǎn)

在上述一切都就緒后,就可以跳轉(zhuǎn)到BootLoader的階段2去執(zhí)行了。比如,在ARM系統(tǒng)中,就可以通過修改寄存器PC為合適的地址來實(shí)現(xiàn)。BootLoader在Flash和RAM中的系統(tǒng)布局如圖7.3所示。圖7.3BootLoader在Flash和RAM中的系統(tǒng)布局7.3.2BootLoader的階段2

階段2的代碼通常用C語言來實(shí)現(xiàn),以便實(shí)現(xiàn)更復(fù)雜的功能和取得更好的代碼可讀性及可移植性。

1.初始化階段2要使用的硬件設(shè)備

初始化階段2通常包括初始化一個(gè)串行口,以便和終端用戶進(jìn)行I/O輸出信息;初始化計(jì)時(shí)器等。

2.檢測系統(tǒng)內(nèi)存映射

所謂內(nèi)存映射就是指整個(gè)物理地址空間中那些分配用來尋址系統(tǒng)的RAM單元。在S3C44B0X處理器中,從0x0C000000到0x10000000之間的64MB地址空間被用作系統(tǒng)的RAM地址空間。雖然CPU通常預(yù)留出一大段足夠的地址空間給系統(tǒng)RAM,但是在搭建具體的嵌入式系統(tǒng)時(shí)卻不一定會(huì)實(shí)現(xiàn)CPU預(yù)留的全部RAM地址空間。也就是說,具體的嵌入式系統(tǒng)往往只把CPU預(yù)留的全部RAM地址空間處于未使用狀態(tài)。由于上述事實(shí),BootLoader的階段2必須在執(zhí)行操作(比如,將存儲(chǔ)在Flash上的內(nèi)核映像讀到RAM空間中)之前檢測整個(gè)系統(tǒng)的內(nèi)存映射情況,即它必須知道處理器預(yù)留的全部RAM地址空間哪些被真正映射到RAM地址單元,哪些是處于“未使用”狀態(tài)的。

3.加載內(nèi)核映像和根文件系統(tǒng)映像

(1)規(guī)劃內(nèi)存占用的布局。在規(guī)劃內(nèi)存占用的布局時(shí),主要考慮內(nèi)核映像所占用的內(nèi)存范圍和根文件系統(tǒng)所占用的內(nèi)存范圍兩個(gè)方面。

(2)從Flash上復(fù)制。由于像ARM這樣的嵌入式處理器通常都是在統(tǒng)一的內(nèi)存地址空間中尋找Flash等固態(tài)存儲(chǔ)設(shè)備的,因此從Flash上讀取數(shù)據(jù)與從RAM單元中讀取數(shù)據(jù)并沒有什么不同。用一個(gè)簡單的循環(huán)就可以完成從Flash設(shè)備上拷貝映像的工作,程序代碼如下:

/*拷貝Flash地址0x10000內(nèi)核到RAM0xC300000中*/

ldrR0, =0x10000

ldrR1, =0xC300000

addR2, R0,#(1536*1024)

copy_kernel:

ldmia R0!,{R3-R10}

stmia R1!,{R3-R10}

cmp

R0,R2

ble

copy_kernel

4.調(diào)用內(nèi)核

所有硬件的設(shè)置完成之后,就可以跳轉(zhuǎn)到內(nèi)核,并開始運(yùn)行內(nèi)核了。調(diào)用內(nèi)核的程序代碼如下:

/*跳轉(zhuǎn)到RAM中執(zhí)行內(nèi)核*/

ldrR0,=0xC30000 ;0xC30000正是前面拷貝kernel函數(shù)中的目的地址

movPC,R0;修改程序地址寄存器,完成跳轉(zhuǎn)

7.4S3C44B0X的BootLoader分析

S3C44B0X下的μCLinux的BootLoader只是一個(gè)比較簡單的BootLoader,所以它的階段1和階段2是一起由匯編完成的,程序流程如圖7.4所示。圖7.4簡單的BootLoader工作流程圖以下是該BootLoader的完整程序:

/**********************************************************

*File:boot.s

**********************************************************/

WTCONEQU0x01D30000

;以下的幾個(gè)定義均是為了設(shè)置相應(yīng)的控制寄存器,請(qǐng)注意查閱各位所對(duì)應(yīng)的作用,

;理解所作的設(shè)置

PCONEEQU0x01D20028

LOCKTIMEEQU0x01D8000C

PLLCONEQU0x01D80000

CLKCONEQU0x01D80004

GLOBAL_start

_start:

breset;程序的第一條指令,在燒寫時(shí),它將會(huì)被燒寫在0x00000000地址

addpc,pc,#0x0C000000

addpc,pc,#0x0C000000

addpc,pc,#0x0C000000

addpc,pc,#0x0C000000

addpc,pc,#0x0C000000

addpc,pc,#0x0C000000

addpc,pc,#0x0C000000

MEMORY_CONFIG: ;定義一組數(shù)據(jù)用來設(shè)置后面的存儲(chǔ)器,可以把它看做一個(gè)數(shù)組

DCD0x11110102

DCD0x600

DCD0x7FFC

DCD0x7FFC

DCD0x7FFC

DCD0x7FFC

DCD0x7FFC

DCD0x18000

DCD0x18000

DCD0x860459

DCD0x10

DCD0x20

DCD0x20

;復(fù)位地址

reset:

;關(guān)看門狗

ldrr0,=WTCON

ldrr1,=0x0

strr1,[r0]

;設(shè)置端口控制寄存器PortE,打開RxD0和TxD0(串口輸入功能)

ldrr1,=PCONE

ldrr0,=0x25529

strr0,[r1]

;設(shè)置時(shí)鐘控制寄存器

ldrr1,=LOCKTIME

ldrr0,=0xFFF

strr0,[r1]

ldrr1,=PLLCON

ldrr0,=0x78061

strr0,[r1]

ldrr1,=CLKCON

ldrr0,=0x7FF8

strr0,[r1]

;設(shè)置寄存器

memsetup:

ldrr0,=MEMORY_CONFIG ;注意不用一個(gè)一個(gè)設(shè)置,通過前面已經(jīng)定義好的數(shù)

;組用4條指令就可以完成設(shè)置

ldmiar0,{r1-r13}

ldrr0,=0x01C80000

stmiar0,{r1-r13}

;拷貝Flash地址0x1000內(nèi)核到RAM0xC300000中

ldrr0,=0x10000

ldrr1,=0xC300000

addr2,r0,#(1536*1024) ;計(jì)算內(nèi)核的終點(diǎn)地址

copy_kernel:

ldmiar0!,{r3-r10}

stmiar1!,{r3-r10}

cmpr0,r2

blecopy_kernel

;跳轉(zhuǎn)到RAM中執(zhí)行內(nèi)核

ldrr0,=0xC300000 ;0xC300000正是前面拷貝內(nèi)核函數(shù)中的目的地址

movpc,r0 ;修改程序地址寄存器,完成跳轉(zhuǎn)

7.5U-Boot啟動(dòng)流程及相關(guān)代碼分析

7.5.1U-Boot啟動(dòng)流程

U-Boot作為ARM平臺(tái)常用的引導(dǎo)程序,具有結(jié)構(gòu)強(qiáng)大和功能強(qiáng)大的特點(diǎn)。下載u-boot-1.2.0.tar.bz2源碼包,解壓后會(huì)生成u-boot-1.2.0目錄,該目錄主要包括三類子目錄:與處理器或硬件電路板相關(guān)的文件目錄,如cpu、board、libarm等;存放通用文件和設(shè)備驅(qū)動(dòng)的目錄,如common、inculde、drivers等;存放U-Boot應(yīng)用程序、工具和文檔的目錄,如examples、tools等。下面來分析U-Boot的啟動(dòng)流程。

1.階段1

U-Boot的階段1(Stage1)代碼通常放在u-boot-1.2.0\cpu\arm920t\start.s文件中,用匯編語言寫成,其主要代碼功能如下:

●定義入口。由于一個(gè)可執(zhí)行的Image必須有一個(gè)入口點(diǎn),并且只能有一個(gè)全局入口,通常這個(gè)入口放在ROM(Flash)的0x0地址,因此,必須使編譯器知道這個(gè)入口。該工作可通過修改鏈接器腳本來完成。

●設(shè)置異常向量(ExceptionVector)。

●設(shè)置CPU的速度、時(shí)鐘頻率及終端控制寄存器。

●初始化內(nèi)存控制器。

●將ROM中的程序復(fù)制到RAM中。

●初始化堆棧。

●轉(zhuǎn)到RAM中執(zhí)行,該工作可使用指令ldrpc來完成。

2.階段2

對(duì)于ARM平臺(tái)來說,U-Boot的階段2(Stage2)代碼在u-boot-1.2.0\lib_arm\board.c文件中。文件中的start_armboot函數(shù)是整個(gè)C語言啟動(dòng)代碼中的主函數(shù),同時(shí)還是整個(gè)U-Boot(針對(duì)ARM平臺(tái))的主函數(shù),該函數(shù)將完成如下操作:

●調(diào)用一系列的初始化函數(shù)。

●初始化Flash設(shè)備。

●初始化系統(tǒng)內(nèi)存分配函數(shù)。

●如果目標(biāo)系統(tǒng)擁有NAND設(shè)備,則初始化NAND設(shè)備。

●如果目標(biāo)系統(tǒng)有顯示設(shè)備,則初始化該設(shè)備。

●初始化相關(guān)網(wǎng)絡(luò)設(shè)備,填寫IP、MAC地址等。

●進(jìn)入命令循環(huán)(即整個(gè)boot的工作循環(huán)),接收用戶從串口輸入的命令,然后進(jìn)行相應(yīng)的工作。圖7.5U-Boot啟動(dòng)代碼順序圖7.5.2U-Boot代碼分析

U-Boot代碼分析如下:

//U-Boot的start.S

//定義變量_start,然后跳轉(zhuǎn)到處理器復(fù)位代碼

.glob1_start;U-Boot啟動(dòng)入口

_start:breset

//若產(chǎn)生中斷則利用pc來跳轉(zhuǎn)到對(duì)應(yīng)的中斷處理程序中

ldrpc,_undefined_instruction //未定義指令向量

ldrpc,_software_interrupt //軟件中斷向量

ldrpc,_prefetch_abort //預(yù)取指中止向量

ldrpc,_data_abort //數(shù)據(jù)中止向量

ldrpc,_not_used //保留

ldrpc,_irq //中斷請(qǐng)求向量

ldrpc,_fiq //快速中斷請(qǐng)求向量

//利用.word在當(dāng)前位置放置一個(gè)值,這個(gè)值實(shí)際上就是對(duì)應(yīng)的中斷處理函數(shù)的地址

//.word的意義為在當(dāng)前地址處放入一個(gè)16bits的值

_undefined_instruction: .wordundefined_instruction

_software_interrupt: .wordsoftware_interrupt

_prefetch_abort: .wordprefetch_abort

_data_abort: .worddata_abort

_not_used: .wordnot_used

_irq: .wordirq

_fiq: .wordfiq

.balignl16,0xdeadbeef

/************************↓reset代碼***********************/

reset:

mrsr0,cpsr

bicr0,r0,#0x1f//bic清除指定為1的位

orrr0,r0,#0xd3//orr邏輯或操作

//經(jīng)過以上兩步r0值控制位為11010011,第0~4位表示處理器當(dāng)前所處模式為10011(32

//位管理模式);第6、7位為1表示禁止IRQ和FIQ中斷;第5位為0表示程序在ARM

//狀態(tài),若其為1則運(yùn)行在Thumb狀態(tài)

msrcpsr,r0 //設(shè)置處理器為32位管理模式

/*關(guān)閉看門狗*/

#definepWTCON0x53000000 //看門狗寄存器地址

#defineINTMSK0x4A00008 //中斷掩碼寄存器,決定哪個(gè)中斷源被屏蔽,某位為1則

//屏蔽中斷源,初始值為0xffffffff,屏蔽所有中斷

#defineINTSUBMSK0x4A00001C //中斷子掩碼寄存器,該寄存器只能屏蔽11個(gè)中斷源,

//因此其僅低11位有效,初始值為0x7ff

#defineCLKDIVN0x4C000014//時(shí)鐘分頻控制寄存器

//將看門狗寄存器清空,其各位含義為:第0位為1則當(dāng)看門狗定時(shí)器溢出時(shí)重啟,為

//0則不重啟,初值為1

//第2位為中斷使能位,初值為0

//第3、4位為時(shí)鐘分頻因子,初值為00

//第5位為看門狗的使能位,初值為1

//第8~15位為比例因子,初值為0x80

ldrr0,=pWTCON

movr1,#0x0

strr1,[r0] //將看門狗寄存器所有位置0,關(guān)閉看門狗,其實(shí)只要將第5位置0即可

movr1,#0xFFFFFFFF

ldrr0,=INTMSK

strr1,[r0] //屏蔽所有中斷,實(shí)際上中斷掩碼寄器初值即為0xFFFFFFF

ldrr1,=0x3FF

ldrr0,=INTSUBMSK

strr1,[r0] //設(shè)置中斷子掩碼寄存器

//設(shè)置時(shí)鐘寄存器,CLKDIVN第0位為PDIVN,為0則PCLK=HCLK,為1則

//PCLK=HCLK/2

//第1位為HDIVN,為0則HCLK=FCLK,為1則HCLK=FCLK/2

//這里兩位均為1,則FCLK∶HCLK∶PCLK=4∶2∶1

ldrr0,=CLKDIVN

movri,#3

strr1,[r0]

/***********************↑reset代碼**********************/

/*********************↓cpu_init_crit代碼******************/

//對(duì)關(guān)鍵寄存器的初始化,如果從RAM中啟動(dòng)則不執(zhí)行cpu_init_crit段代碼

cpu_init_crit:

//清空指令和數(shù)據(jù)caches

movr0,#0

mcrp15,0,r0,c7,c7,0

mcrp15,0,r0,c8,c7,0

/*disableMMUstuffandcaches*/

mrcp15,0,r0,c1,c0,0

bicr0,r0,#0x00002300@clearbits13,9:8(--V--RS)

bicr0,r0,#0x00000087@clearbits7,2:0(B--CAM)

orrr0,r0,#0x00000002@setbit2(A)Align

orrr0,r0,#0x00001000@setbit12(I)I-Cache

mcrp15,0,r0,c2,c0,0

//在重定向代碼之前,必須初始化內(nèi)存時(shí)序,因?yàn)橹囟ㄏ驎r(shí)需要將Flash中的代碼復(fù)制

//到內(nèi)存中

//內(nèi)存初始化的代碼在board/smdk2410/lowlevel_ini.S中

movip,lr

bllowlevel_init //調(diào)用lowlevel_init子程序(board/smdk2410/lowlevel_ini.S)

movlr,ip

movpc,lr //程序返回

/*********************↑c(diǎn)pu_init_crit代碼*******************/

/************↓lowlevel_init代碼(lowlevel_ini.S)**************/

lowlevel_init:

/*memorycontrolconfiguration*/

/*maker0relativethecurrentlocationsothatit*/

/*readsSMRDATAoutofFlashratherthanmemory!*/

ldr r0,=SMRDATA

ldr r1,_TEXT_BASE

sub r0,r0,r1

ldr r1,=BWSCON /*BusWidthStatusController*/

add r2,r0,#13*4

0b:

ldr r3,[r0],#4

str r3,[r1],#4

cmp r2,r0

bne 0b

/*everythingisfinenow*/

mov pc,lr

/**************↑lowlevel_init代碼(lowlevel_ini.s)*************/

/**************↓relocate代碼******************************/

relocate:/*relocateU-BoottoRAM*/

//當(dāng)前代碼地址,adr獲取當(dāng)前代碼的地址信息,若從RAM運(yùn)行,則_start=TEXT_BASE,

//否則_start=0x00000000

adrr0,_start/*r0<-currentpositionofcode*/

//獲取_TEXT_BASE

ldrr1,_TEXT_BASE/*testifwerunfromflashorRAM*/

cmpr0,r1/*don‘treloctduringdebug*/

//兩者相等,表示從RAM運(yùn)行則跳轉(zhuǎn)到堆棧設(shè)置

bepstack_setup

//不相等則表示從Flash中運(yùn)行,重定向代碼

ldrr2,_armboot_start

//獲取未初始化數(shù)據(jù)段地址

Ldrr3,_bss_start

//計(jì)算代碼段大小

subr2,r3,r2/*r2<-sizeofarmboot*/

//計(jì)算代碼段終止地址

addr2,r0,r2/*r2<-sourceendaddress*/

//復(fù)制代碼,r0為代碼的起始地址,r1為RAM中地址,r2為代碼的終止地址

//每次復(fù)制后將r0值遞增同r2比較來判斷是否復(fù)制完成

copy_loop:

ldmiar0!,{r3-r10}/*copyfromsourceaddress[r0]*/

stmiar1!,{r3-r10}/*copytotargetaddress[r1]*/

cmpr0,r2/*untilsourceendaddreee[r2]*/

blecopy_loop

/*******************↑relocate代碼**************************/

/*******************↓stack_setup代碼***********************/

stack_setup:

//獲取_TEXT_BASE

ldrro,_TEXT_BASE/*upper128K/B:relocateduboot*/

//獲取分配區(qū)域起始指針,CFG_MALLOC_LEN=128*1024+CFG_ENV_SIZE

//=128*1024+0X1000=192K

subr0,r0,#CFG_MALLOC_LEN/*mallocarea*/

//另外分配128B來存儲(chǔ)開發(fā)板信息

subr0,r0,#(CFG_GBL_DATA_SIZE/*bdinfo*/

#ifdefCONFIG_USE_IRQ

subr0,r0,#(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ)

#endif

//再減去12B用于棧起點(diǎn)

subsp,r0,#12/*leave3wordsforabort-stack*/

//清空未初始化數(shù)據(jù)段

clear_bss;

ldrr0,_bss_start/*findstartofbsssegment*/

ldrr1,_bss_end/*stophere*/

movr2,#0x00000000/*clear*/

clbss_1:strr2,[r0]/*clearloop…*/

addr0,r0,#4

cmpr0,r1

bleclbss_1

/*********************↑stack_setup代碼********************/

//完成復(fù)制后跳轉(zhuǎn)到start_armboot,到這里則進(jìn)入lib_arm/board.c的start-armboot函數(shù)中

ldrpc,_start_armboot

_start_armboot:.wordstart_armboot

在lib_arm/board.c中,首先定義函數(shù)指針數(shù)組,代碼如下:

typedefint(init_fnc_t)(void);

//定義函數(shù)指針數(shù)組,對(duì)硬件初始化按照該數(shù)組進(jìn)行

init_fnc_t*init_sequence[]={

cpu_init,//cpu/arm920t/cpu.c中定義,該函數(shù)為空,因?yàn)闆]有采用IPQ或FIQ模式

board_init,//board/smdk2410/smdk2410.c

interrupt_init,//cpu/arm920t/s3c24x0/interrupt.c

env_init,//tools/env/FW_env.c

init_baudrate,//lib_arm/board.c

serial_init,//cpu/arm920t/s3c24x0/serial.c

console_init_f,//common/console.c

display_banner,//lib_arm/board.c

#ifdefined(CONFIG_DISPLAY_BOARDINFO)

print_cpuinfo,//

#endif

#ifdefined(CONFIG_DISPLAY_BOARDINFO)

checkboard,//

#endif

dram_init,//board/smdk2410/smdk2410.c

display_dram_config,//lib_arm/board.c

NULL,

};

/*************↓start_armboot代碼***************/

voidstar_armboot(void)

{

init_fnc_t**init_fnc_ptr;

char*s;

#ifndefCFG_NO_FLASH

ulongsize;

#endif

#ifdefined(CONFIG_VFD)||defined(CONFIG_LCD)

unsignedlongaddr;

#endif

/*Pointeriswritablesinceweallocatedaregisterforit*/

//獲取全局gd指針

gd=(gd_t*)(_armboot_start-CFG_MALLOC_LEN-sizeof(gd_t));

/*compileroptimizationbarrierneededforGCC>=3.4*/

__asm__volatile__(**:::”memory”);

//清空該結(jié)構(gòu)體

memset((void*)gd,0,sizeof(gd_t));

//獲取bd_info結(jié)構(gòu)體指針

gd->bd=(bd_t*)((char*)gd–sizeof(bd_t));

memset(gd->bd,0,sizeof(bd_t));

//整個(gè)代碼區(qū)的長度

Monitor_flash_len=_bss_start-_armboot_start;

//調(diào)用初始化函數(shù),用來初始化gd結(jié)構(gòu)體

for(init_fnc_ptr=init_sequence;*init_fnc_ptr;++ini_fnc_ptr){

if((*init_fnc_ptr)()!=0){

hang();

}

}

#ifndefCFG_NO_FLASH

/*configureavailableFLASHbanks*/

//board/smdk2410/flash.c配置flash

//從其實(shí)現(xiàn)來看,好像只是配置NORFlash

//按頁對(duì)其方式保留顯存

addr=(_bss_end+(PAGE_SIZE-1))&~(PAGE_SIZE-1);

size=vfd_setmem(addr);

gd->fb_base=addr;

#endif /*CONFIG_VFD*/

//顯示器為LCD,同上

#ifdefCONFIG_VFD

#ifndefPAGE_SIZE

#definePAGE_SIZE4096

#endif

/*reservememoryforLCDdisplay(alwaysfullpages)*/

/*bss_endisdefinedintheboard-specificlinkerscript*/

size=flash_init();

//顯示Flash信息

display_flash_config(size);

#endif /*CFG_NO_FLASH*/

//定義顯示類型

#ifdefCONFIG_VFD

#ifndefPAGE_SIZE

#definePAGE_SIZE4096

#endif

/*reservememoryforVFDdisplay(alwaysfullpages)*/

/*bss_endisdefinedintheboard-specificlinkerscript*/

addr=(_bss_end+(PAGE_SIZE-))&~(PAGE_SIZE-1);

size=lcd_setmem(addr);

gd->fb_base=addr;

#endif /*CONFIG_LCD*/

//初始化CFG_MALLOC_LEN大小空間

/*armboot_startisdefinedintheboard-specificlinkerscript*/

mem_malloc_init(_armboot_start–CFG_MALLOC_LEN);

//初始化NANDFlash,這是在NANDFlash啟動(dòng)的s3c2410移植U-Boot的關(guān)鍵,根據(jù)Flash

//時(shí)序編寫函數(shù)即可

//在include/configs/smdk2410.h中的commanddefinition中增加CONFIG_COMMANDS

//和CFG_CMD_NAND命令

#if(CONFIG_COMMAND&CFG_CMD_NAND)

puts("NAND:");

nand_init();//board/smdk2410/smdk2410.c

#endif

#ifdefCONFIG_HAS_DATAFLASH

AT91F_DataflashInit();

dataflash_print_info();

#endif

/*initializeenvironment*/

//初始化環(huán)境參數(shù)

env_relocate();

//framebuf

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

評(píng)論

0/150

提交評(píng)論