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

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領

文檔簡介

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

7.1.1BootLoader的作用和任務

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

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

1.?vivi

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

●檢測目標板。

●下載程序并寫入Flash。

●初始化硬件。

●把內核從Flash復制到RAM,然后啟動它。

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

●?CVS:存放CVS工具相關的文件。

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

●?Arch:存放與CPU構架體系結構有關的代碼文件。

●?drivers:存放與vivi相關的驅動代碼文件。

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

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

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

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

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

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

2.?U-Boot

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

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

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

●?board:目標板相關文件,主要包含SDRAM、Flash驅動。

●?common:獨立于處理器體系結構的通用代碼,如內存大小探測與故障檢測代碼?!?cpu:與處理器相關的文件,如mpc8xx子目錄下的串口、網口、LCD驅動及中斷初始化等文件。

●?driver:通用設備驅動,如CFIFlash驅動(目前對IntelFlash支持較好)。

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

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

●?include:U-Boot頭文件,尤其是configs子目錄下與目標板相關的配置頭文件,它是移植過程中經常要修改的文件?!?lib_xxx:處理器體系相關的文件,如lib_ppc、lib_arm目錄分別包含的與PowerPC、ARM體系結構相關的文件。

●?net:與網絡功能相關的文件目錄,如boot、NFS和TFTP。

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

●?rtc:RTC(RealTimeClock,實時時鐘)驅動程序。

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

3.RedBoot

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

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

4.?ARMBoot

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

5.?Blob

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

6.?DIY

DIY(DoItYourself),即自己制作。上面介紹的U-Boot、vivi、Blob、RedBoot、ARMboot等成熟工具雖然移植起來簡單快捷,但它們都存在著一定的局限性。首先,因為它們是面向大部分硬件的工具,所以在功能上要滿足大部分硬件的需求,但一般情況下用戶只需要與特定的開發(fā)板相關的實現(xiàn)代碼,其他型號開發(fā)板的實現(xiàn)代碼對它來說是沒有用的,因此通常會有較大的無用代碼;其次,它們在使用上不夠靈活,如在這些BootLoader上添加自己的特有功能比較困難,因為必須熟悉該代碼的組織關系,且了解它的配置編譯等文件。用DIY的方式自己編寫針對目標的BootLoader,不但代碼量短小,而且靈活性很大,最重要的是將來容易維護。所以在實際嵌入式產品的開發(fā)中大多都選擇DIY的方式編寫B(tài)ootLoader。

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

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

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

1.啟動加載(BootLoading)模式

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

2.下載(DownLoading)模式

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

1.階段設計

BootLoader的啟動是可以分階段的,因此在設計時也可將BootLoader分為階段1和階段2。BootLoader的設計分為兩個階段的原因如下。

(1)基于編程語言的考慮。階段1主要用匯編語言編寫,這是因為它主要進行與CPU核心及存儲設備密切相關的處理工作和進行一些必要的初始化工作,是依賴于CPU體系結構的代碼,所以為了增加效率以及匹配協(xié)處理器的設置,只能用匯編語言編寫,這部分直接在Flash中執(zhí)行。階段2可以用C語言編寫,主要實現(xiàn)一般的流程以及對板級的一些驅動支持,這部分會被復制到RAM中執(zhí)行。

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

2.地址規(guī)劃設計

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

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

3.模式設計

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

7.3BootLoader的主要功能及典型結構

7.3.1BootLoader的階段1

1.基本的硬件初始化

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

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

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

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

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

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

2.加載階段2的RAM空間

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

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

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

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

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

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

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

3.復制階段2到RAM

復制階段2到RAM時要確定以下兩點:

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

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

4.設置堆棧指針(SP)

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

5.跳轉到階段2的C程序入口點

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

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

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

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

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

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

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

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

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

/*拷貝Flash地址0x10000內核到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.調用內核

所有硬件的設置完成之后,就可以跳轉到內核,并開始運行內核了。調用內核的程序代碼如下:

/*跳轉到RAM中執(zhí)行內核*/

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

movPC,R0;修改程序地址寄存器,完成跳轉

7.4S3C44B0X的BootLoader分析

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

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

*File:boot.s

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

WTCONEQU0x01D30000

;以下的幾個定義均是為了設置相應的控制寄存器,請注意查閱各位所對應的作用,

;理解所作的設置

PCONEEQU0x01D20028

LOCKTIMEEQU0x01D8000C

PLLCONEQU0x01D80000

CLKCONEQU0x01D80004

GLOBAL_start

_start:

breset;程序的第一條指令,在燒寫時,它將會被燒寫在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ù)組

DCD0x11110102

DCD0x600

DCD0x7FFC

DCD0x7FFC

DCD0x7FFC

DCD0x7FFC

DCD0x7FFC

DCD0x18000

DCD0x18000

DCD0x860459

DCD0x10

DCD0x20

DCD0x20

;復位地址

reset:

;關看門狗

ldrr0,=WTCON

ldrr1,=0x0

strr1,[r0]

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

ldrr1,=PCONE

ldrr0,=0x25529

strr0,[r1]

;設置時鐘控制寄存器

ldrr1,=LOCKTIME

ldrr0,=0xFFF

strr0,[r1]

ldrr1,=PLLCON

ldrr0,=0x78061

strr0,[r1]

ldrr1,=CLKCON

ldrr0,=0x7FF8

strr0,[r1]

;設置寄存器

memsetup:

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

;組用4條指令就可以完成設置

ldmiar0,{r1-r13}

ldrr0,=0x01C80000

stmiar0,{r1-r13}

;拷貝Flash地址0x1000內核到RAM0xC300000中

ldrr0,=0x10000

ldrr1,=0xC300000

addr2,r0,#(1536*1024) ;計算內核的終點地址

copy_kernel:

ldmiar0!,{r3-r10}

stmiar1!,{r3-r10}

cmpr0,r2

blecopy_kernel

;跳轉到RAM中執(zhí)行內核

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

movpc,r0 ;修改程序地址寄存器,完成跳轉

7.5U-Boot啟動流程及相關代碼分析

7.5.1U-Boot啟動流程

U-Boot作為ARM平臺常用的引導程序,具有結構強大和功能強大的特點。下載u-boot-1.2.0.tar.bz2源碼包,解壓后會生成u-boot-1.2.0目錄,該目錄主要包括三類子目錄:與處理器或硬件電路板相關的文件目錄,如cpu、board、libarm等;存放通用文件和設備驅動的目錄,如common、inculde、drivers等;存放U-Boot應用程序、工具和文檔的目錄,如examples、tools等。下面來分析U-Boot的啟動流程。

1.階段1

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

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

●設置異常向量(ExceptionVector)。

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

●初始化內存控制器。

●將ROM中的程序復制到RAM中。

●初始化堆棧。

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

2.階段2

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

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

●初始化Flash設備。

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

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

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

●初始化相關網絡設備,填寫IP、MAC地址等。

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

U-Boot代碼分析如下:

//U-Boot的start.S

//定義變量_start,然后跳轉到處理器復位代碼

.glob1_start;U-Boot啟動入口

_start:breset

//若產生中斷則利用pc來跳轉到對應的中斷處理程序中

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

ldrpc,_software_interrupt //軟件中斷向量

ldrpc,_prefetch_abort //預取指中止向量

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

ldrpc,_not_used //保留

ldrpc,_irq //中斷請求向量

ldrpc,_fiq //快速中斷請求向量

//利用.word在當前位置放置一個值,這個值實際上就是對應的中斷處理函數(shù)的地址

//.word的意義為在當前地址處放入一個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邏輯或操作

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

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

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

msrcpsr,r0 //設置處理器為32位管理模式

/*關閉看門狗*/

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

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

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

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

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

#defineCLKDIVN0x4C000014//時鐘分頻控制寄存器

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

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

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

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

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

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

ldrr0,=pWTCON

movr1,#0x0

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

movr1,#0xFFFFFFFF

ldrr0,=INTMSK

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

ldrr1,=0x3FF

ldrr0,=INTSUBMSK

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

//設置時鐘寄存器,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代碼******************/

//對關鍵寄存器的初始化,如果從RAM中啟動則不執(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

//在重定向代碼之前,必須初始化內存時序,因為重定向時需要將Flash中的代碼復制

//到內存中

//內存初始化的代碼在board/smdk2410/lowlevel_ini.S中

movip,lr

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

movlr,ip

movpc,lr //程序返回

/*********************↑cpu_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*/

//當前代碼地址,adr獲取當前代碼的地址信息,若從RAM運行,則_start=TEXT_BASE,

//否則_start=0x00000000

adrr0,_start/*r0<-currentpositionofcode*/

//獲取_TEXT_BASE

ldrr1,_TEXT_BASE/*testifwerunfromflashorRAM*/

cmpr0,r1/*don‘treloctduringdebug*/

//兩者相等,表示從RAM運行則跳轉到堆棧設置

bepstack_setup

//不相等則表示從Flash中運行,重定向代碼

ldrr2,_armboot_start

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

Ldrr3,_bss_start

//計算代碼段大小

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

//計算代碼段終止地址

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

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

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

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來存儲開發(fā)板信息

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

#ifdefCONFIG_USE_IRQ

subr0,r0,#(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ)

#endif

//再減去12B用于棧起點

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代碼********************/

//完成復制后跳轉到start_armboot,到這里則進入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ù)組,對硬件初始化按照該數(shù)組進行

init_fnc_t*init_sequence[]={

cpu_init,//cpu/arm920t/cpu.c中定義,該函數(shù)為空,因為沒有采用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”);

//清空該結構體

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

//獲取bd_info結構體指針

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

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

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

Monitor_flash_len=_bss_start-_armboot_start;

//調用初始化函數(shù),用來初始化gd結構體

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

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

//按頁對其方式保留顯存

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啟動的s3c2410移植U-Boot的關鍵,根據(jù)Flash

//時序編寫函數(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等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經權益所有人同意不得將文件中的內容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
  • 6. 下載文件中如有侵權或不適當內容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論