版權(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ì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 分包合同范本(2篇)
- 2025合同自由原則的辯析
- 2025轉(zhuǎn)移財(cái)產(chǎn)使用權(quán)的合同
- 2025茨威格電氣《母線銷售合同范本》V
- 2025執(zhí)業(yè)藥師合同范本
- 2024年度四川省公共營養(yǎng)師之三級(jí)營養(yǎng)師考前沖刺模擬試卷B卷含答案
- 2025關(guān)于水果采購合同
- 年產(chǎn)500噸機(jī)械零部件可行性研究報(bào)告申請(qǐng)建議書
- 2025年OAK-BOND瞬間膠項(xiàng)目可行性研究報(bào)告
- 鋼帶裁制行業(yè)深度研究報(bào)告
- 深圳分區(qū)地圖可移動(dòng)編輯
- 商戶清場協(xié)議書
- 2023年新版烏斯特統(tǒng)計(jì)公報(bào)即將發(fā)布
- 污水處理廠安全生產(chǎn)風(fēng)險(xiǎn)分級(jí)管控體系方案全套資料匯編完整版
- 人教部編版三年級(jí)語文上冊(cè)古詩詞日積月累默寫模板
- 高危急性胸痛的快速診斷和誤診病案分析
- (完整版)綜合醫(yī)院康復(fù)醫(yī)學(xué)科建設(shè)與管理指南
- GB/T 41649-2022木制玩具中甲醛釋放量的測定燒瓶法
- JJF 1384-2012開口/閉口閃點(diǎn)測定儀校準(zhǔn)規(guī)范
- GB/T 33720-2017LED照明產(chǎn)品光通量衰減加速試驗(yàn)方法
- 教師政治紀(jì)律方面存在的問題及整改措施集合5篇 教師政治紀(jì)律方面存在的問題及整改措施怎么寫
評(píng)論
0/150
提交評(píng)論