




版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)
文檔簡介
1、第六章 Bootloader 一個嵌入式 Linux 系統(tǒng)從軟件的角度看通??梢苑譃槲鍌€層次: 引導加載程序 包括固化在固件中的 boot 代碼(可選),和 Bootloader 兩大部分。 2. Linux 內(nèi)核 特定于嵌入式板子的定制內(nèi)核(包括驅(qū)動程序)以及內(nèi)核的 啟動參數(shù)。 3. 文件系統(tǒng) 建立于 Flash 設(shè)備之上文件系統(tǒng)。4.驅(qū)動程序編寫(移植) 5. 用戶應(yīng)用程序 特定于用戶的應(yīng)用程序。有時在用戶應(yīng)用程序和內(nèi)核層之間 可能還會包括一個嵌入式圖形用戶界面。常用的嵌入式 GUI 有:QT 和 MiniGUI 。 第1頁,共69頁。固態(tài)存儲設(shè)備的典型空間分配結(jié)構(gòu)第2頁,共69頁。 引導
2、加載程序是系統(tǒng)加電后運行的第一段軟件代碼。 在 PC 機中: PC 機中的引導加載程序由 BIOS(其本質(zhì)就是一段固件程序)和位于硬盤中的OS Boot Loader(比如,LILO 和 GRUB 等)一起組成。 BIOS: 在完成硬件檢測和資源分配后,將硬盤中的 Boot Loader 讀到系統(tǒng)的 RAM 中,然后將控制權(quán)交給 OS Boot Loader。 Boot Loader: 主要運行任務(wù)就是將內(nèi)核映象從硬盤上讀到 RAM 中,然后跳轉(zhuǎn)到內(nèi)核的入口點去運行,也即開始啟動操作系統(tǒng)。 第3頁,共69頁。在嵌入式系統(tǒng)中: 通常并沒有像 BIOS 那樣的固件程序(有的嵌入式 CPU 也會內(nèi)嵌
3、一段短小的啟動程序),因此整個系統(tǒng)的加載啟動任務(wù)就完全由 Boot Loader 來完成。 比如在一個基于 ARM7TDMI core 的嵌入式系統(tǒng)中,系統(tǒng)在上電或復位時通常都從地址 0 x00000000 處開始執(zhí)行,而在這個地址處安排的通常就是系統(tǒng)的 Boot Loader 程序。 第4頁,共69頁。 系統(tǒng)加電或復位后,所有的處理器通常都從某個預先 安排的地址上取指令。 比如,ARM在復位時從地址0 x0取指。 嵌入式系統(tǒng)中通常都有某種類型的固態(tài)存儲設(shè)備(比 如:ROM、EEPROM 或FLASH 等)被映射到這個預先安 排的地址上。因此在系統(tǒng)加電后,處理器將首先執(zhí)行 Bootloader
4、 程序。 Bootloader是最先被系統(tǒng)執(zhí)行的程序。第5頁,共69頁。 每種不同的 CPU 體系結(jié)構(gòu)都有不同的 Boot Loader。有些 Boot Loader 也支持多種體系結(jié)構(gòu)的 CPU,比如 U-Boot 就同時支持 ARM 體系結(jié)構(gòu)和MIPS體系結(jié)構(gòu)。Boot Loader 實際上也依賴于具體的嵌入式板級 設(shè)備的配置。對于兩塊不同的嵌入式板而言,即使 它們是基于同一種 CPU 而構(gòu)建的,要想讓運行在一 塊板子上的 Boot Loader 程序也能運行在另一塊 板子上,通常也都需要修改 Boot Loader 的源程序。 第6頁,共69頁。 一、 bootloader的基本概念 1
5、、什么是bootloader(引導加載程序) 簡單地說BootLoader就是在操作系統(tǒng)內(nèi)核或用戶應(yīng)用程序運行之前運行的一段小程序。通過這段小程序,我們可以初始化硬件設(shè)備、建立內(nèi)存空間的映射圖(有的CPU沒有內(nèi)存映射功能如S3C44B0),從而將系統(tǒng)的軟硬件環(huán)境帶到一個合適的狀態(tài),以便為最終調(diào)用操作系統(tǒng)內(nèi)核或用戶應(yīng)用程序準備好正確的環(huán)境。 第7頁,共69頁。 2、 BootLoader的操作模式 多數(shù)BootLoader都包含兩種不同的操作模式?!皢蛹虞d”模式和“下載”模式,這種區(qū)別僅對于開發(fā)人員才有意義。但從最終用戶的角度看,BootLoader的作用就是用來加載操作系統(tǒng),而并不存在所謂的
6、啟動加載模式與下載工作模式的區(qū)別。 啟動加載(Boot loading)模式:這種模式也稱為“自主”(Autonomous)模式,也即BootLoader從目標機上的某個固態(tài)存儲設(shè)備上將操作系統(tǒng)加載到RAM中運行,整個過程并沒有用戶的介入。這種模式是BootLoader的正常工作模式。因此在嵌入式產(chǎn)品發(fā)布的時候, BootLoader顯然必須工作在這種模式下。第8頁,共69頁。下載(Down loading)模式: 在這種模式下 目標機上的BootLoader 將通過串口連接或網(wǎng)絡(luò)連接等通信手段從主機下載文件,比如:下載應(yīng)用程序、數(shù)據(jù)文件、內(nèi)核映像等。從主機下載的文件通常首先被BootLoad
7、er保存到目標機的RAM中,然后再被BootLoader寫到目標機上的固態(tài)存儲設(shè)備中。BootLoader的這種模式通常在系統(tǒng)更新時使用。工作于這種模式下的 BootLoader通常都會向它的終端用戶提供一個簡單的命令行接口。第9頁,共69頁。 最常見的情況是,目標機上的BootLoader通過串口與主機之間進行文件傳輸,傳輸協(xié)議通常xmodem/ymodem/zmodem協(xié)議中的一種。但是,由于串口傳輸?shù)乃俣仁怯邢薜?,因此通過以太網(wǎng)連接并借助TFTP協(xié)議來下載文件是個更好的選擇。但是,在通過以太網(wǎng)連接和TFTP協(xié)議來下載文件時,因為主機方必須有一個軟件用來的提供TFTP服務(wù),所以操作相對復雜
8、。 第10頁,共69頁。 3、BootLoader的啟動過程 由于 Boot Loader 的實現(xiàn)依賴于 CPU 的體系結(jié)構(gòu),因此大多數(shù) Boot Loader 的啟動都分為 stage1 和 stage2兩大部分。依賴于 CPU 體系結(jié)構(gòu)的代碼,比如設(shè)備初始化代碼等,通常都放在 stage1中,而且通常都用匯編語言來實現(xiàn),以達到短小精悍的目的。而 stage2則通常用C語言來實現(xiàn),這樣可以實現(xiàn)更復雜的功能,而且代碼會具有更好的可讀性和可移植性。第11頁,共69頁。通常包括以下步驟(以執(zhí)行的先后順序):硬件設(shè)備初始化 1 屏蔽所有的中斷。為中斷提供服務(wù)通常是 OS 設(shè)備驅(qū)動程序的責任,因此在
9、Boot Loader 的執(zhí)行全過程中可以不必響應(yīng)任何中斷。中斷屏蔽可以通過寫 CPU 的中斷屏蔽寄存器或狀態(tài)寄存器(比如 ARM 的 CPSR 寄存器)來完成。 2 設(shè)置 CPU 的速度和時鐘頻率。 3 RAM 初始化。包括正確地設(shè)置系統(tǒng)的內(nèi)存控制器的功能寄存器以及各內(nèi)存庫控制寄存器等。 4 初始化 LED。典型地,通過 GPIO 來驅(qū)動 LED,其目的是表明系統(tǒng)的狀態(tài)是 OK 還是 Error。如果板子上沒有 LED,那么也可以通過初始化 UART 向串口打印 Boot Loader 的 Logo 字符信息來完成這一點。 5 關(guān)閉 CPU 內(nèi)部指令數(shù)據(jù) cache。 Boot Loader
10、 的 stage1第12頁,共69頁。為加載 Boot Loader 的 stage2 準備 RAM 空間。 為了獲得更快的執(zhí)行速度,通常把 stage2 加載到 RAM 空間中來執(zhí)行,因此必須為加載 Boot Loader 的 stage2 準備好一段可用的 RAM 空間范圍??臻g大小最好是 memory page 大小(通常是4KB)的倍數(shù)。一般而言,1M 的 RAM 空間已經(jīng)足夠了。具體的地址范圍可以任意安排。 比如 blob 就將它的 stage2 可執(zhí)行映像安排到從系統(tǒng) RAM 起始地址 0 xc0200000 開始的 1M 空間內(nèi)執(zhí)行。 拷貝 Boot Loader 的 stage
11、2 到 RAM 空間中。 拷貝時要確定兩點:(1) stage2 的可執(zhí)行映象在固態(tài)存儲設(shè)備的存放起始地址和終止地址;(2) RAM 空間的起始地址。設(shè)置好堆棧。 堆棧指針的設(shè)置是為了執(zhí)行 C 語言代碼作好準備。 通常我們可以把 sp 的值設(shè)置為(stage2_end-4),也即在前面所安排的那個1MB的RAM 空間的最頂端(堆棧向下生長)。 此外,在設(shè)置堆棧指針 sp 之前,也可以關(guān)閉 LED ,以提示用戶準備跳轉(zhuǎn)到 stage2。 第13頁,共69頁。跳轉(zhuǎn)到 stage2 的 C 入口點。 在上述一切都就緒后,就可以跳轉(zhuǎn)到 Boot Loader 的 stage2 去執(zhí)行了。在ARM系統(tǒng)中
12、,可以通過修改PC寄存器為合適的地址來實現(xiàn)。比如,用以下代碼來實現(xiàn)兩個階段的交接工作。 如(U-Boot中可以用以下兩行代碼實現(xiàn)) ldr pc _start_armboot _start_armboot:.word start_armboot 在vivi中是通過以下實現(xiàn)的: bl main mov pc,#FLASH_BASE第14頁,共69頁。stage2 的代碼通常用 C 語言來實現(xiàn),以便于實現(xiàn)更復雜的功能和取得更好的代碼可讀性和可移植性。Boot Loader 的 stage2 通常包括以下步驟(以執(zhí)行的先后順序):初始化本階段要使用到的硬件設(shè)備。 通常包括:(1)初始化至少一個串口,
13、以便和終端用戶進行 I/O 輸出信息;(2)初始化計時器等。設(shè)備初始化完成后,可以輸出一些打印信息,程序名字字符串、版本號等。 檢測系統(tǒng)內(nèi)存映射(memory map)。 所謂內(nèi)存映射就是指在整個 4GB 物理地址空間中有哪些地址范圍被分配用來尋址系統(tǒng)的 RAM 單元。比如,在 SA-1100 CPU 中,從0 xC000,0000 開始的 512M 地址空間被用作系統(tǒng)的 RAM 地址空間,而在 Samsung S3C44B0X CPU 中,從0 x0c00,0000 到 0 x1000,0000 之間的 64M 地址空間被用作系統(tǒng)的 RAM 地址空間。Bootloader 的stage2第1
14、5頁,共69頁。將 kernel 映像和根文件系統(tǒng)映像從 flash 上讀到 RAM 空間中。(1)規(guī)劃內(nèi)存占用的布局這里包括兩個方面:內(nèi)核映像所占用的內(nèi)存范圍;根文件系統(tǒng)所占用的內(nèi)存范圍。在規(guī)劃內(nèi)存占用的布局時,主要考慮基地址和映像的大小兩個方面。(2)從 Flash 上拷貝數(shù)據(jù)為內(nèi)核設(shè)置啟動參數(shù)。 在將內(nèi)核映像和根文件系統(tǒng)映像拷貝到 RAM 空間中后,就可以準備啟動 Linux 內(nèi)核了。但是在調(diào)用內(nèi)核之前,應(yīng)該作一步準備工作,即:設(shè)置 Linux 內(nèi)核的啟動參數(shù)。 調(diào)用內(nèi)核。第16頁,共69頁。第17頁,共69頁。VIVI簡介 VIVI是韓國Mizi公司開發(fā)的BootLoader,可用于A
15、RM9處理器的引導。VIVI利用串行通信為用戶提供接口。為連接VIVI,首先利用串口電纜連接宿主機和目標板,然后在主機上運行串口通信程序(minicom),并在目標板上正確設(shè)置VIVI以支持串口。正確連接后,就可以由串口通信程序顯示提示信息,提示信息的最后一行如下所示:Press Return to start the LINUX now, any other key for vivi. VIVI也有前面說過的兩種工作模式,啟動模式可以在一段時間后自行啟動Linux內(nèi)核,這是VIVI的默認方式。出現(xiàn)上述信息后,如果按除回車鍵外的任意鍵,即可進入下載模式,出現(xiàn)“vivi”提示符。在下載模式下,V
16、IVI為用戶提供了一個命令行接口,通過該接口可以使用VIVI提供的一些命令。二、常用BootLoader代碼分析第18頁,共69頁。1load命令將二進制文件載入到Flash或者RAM,命令格式:load | 其中命令行參數(shù)描述裝載位置,有flash和ram兩種選項;參數(shù) 或 描述裝載的地址,如果有提前定義的MTD分區(qū)信息,可以只輸入分區(qū)名稱,否則需要指定地址和大小;參數(shù) 確定文件的傳輸協(xié)議,常采用的選項“x”用來指定采用xmodem協(xié)議。 例如:vivi load flash kernel x,裝載壓縮映像文件zImage到flash存儲器中,地址是kernel分區(qū),并采用xmodem傳輸協(xié)
17、議。 也可以指定地址和大小,例如:vivi load flash 0 x80000 0 xc0000 x。 第19頁,共69頁。2part命令操作MTD分區(qū)信息,比如,顯示、增加、刪除、復位、保存MTD分區(qū)等。 part show:顯示mtd分區(qū)信息。 part add :增加新的mtd分區(qū),其中為新mtd分區(qū)名稱,是mtd器件的偏移,表示mtd分區(qū)的大小,表示分區(qū)類型,可選項有JFFS2、LOCKED和BONFS。 part del :刪除一個mtd分區(qū)。 part reset:恢復mtd 分區(qū)為默認值。 part save:在flash中永久保存參數(shù)值和分區(qū)信息。3param命令用來設(shè)置或
18、者察看參數(shù)。例如:改變“l(fā)inux command line”,使用 vivi param set linux_cmd_line “you wish.”。也可以改變引導程序啟動的時間,使用vivi param set boot_delay 100000實現(xiàn)。第20頁,共69頁。4boot命令 用來引導存儲在flash存儲器或者RAM中的linux內(nèi)核。命令格式:boot | 參數(shù) 設(shè)定存儲linux內(nèi)核映像的位置,可選項有ram、nor和smc。參數(shù) 或 描述存儲內(nèi)核的地址,如果有提前定義的MTD分區(qū)信息,可以只輸入分區(qū)名稱,否則需要指定地址和大小。例如:vivi boot nor 0 x80
19、000表示從flash存儲器中讀出linux內(nèi)核,偏移是0 x80000。5flash命令存儲器管理命令,例如:flash erase | ,表示擦除flash存儲器。 第21頁,共69頁。VIVI的代碼分析與移植 1arch此目錄包括了所有VIVI支持的目標板的子目錄,例如s3c2410目錄 。2Documentation存放了許多文檔,非常詳細,主要是VIVI的使用指南。3drivers 其中包括了引導內(nèi)核所需的MTD設(shè)備(mtd)和串口驅(qū)動程序(serial)。MTD目錄下分maps、nand和nor三個目錄,實現(xiàn)對Nand Flash和Nor Flash的讀寫控制。Serial目錄下的
20、文件實現(xiàn)對串口的控制,并支持xmodem和ymodem協(xié)議。4include 頭文件的公共目錄,其中的S3C2410.h定義了處理器的一些寄存器,以及NAND Flash的一些寄存器等。Platform/smdk2410.h定義了與目標板相關(guān)的資源配置參數(shù),修改波特率、引導參數(shù)和物理內(nèi)存映射等參數(shù)就可適用于自己的目標板。第22頁,共69頁。5Init 這個目錄只有main.c和version.c兩個文件。與普通的C程序一樣,VIVI將從main函數(shù)開始執(zhí)行。6Lib 一些平臺公共的接口代碼,比如,time.c里的udelay()和mdelay()。7scripts 主要在配置時用到,存放了配置
21、所需的腳本文件,如Menuconfig和Configure文件,以方便對VIVI的配置。 第23頁,共69頁。 VIVI的運行也可以分為兩個階段。 在第一階段完成含有依賴于CPU體系結(jié)構(gòu)硬件初始化的代碼,利用匯編語言完成。 第二階段是用C語言完成的。在跳轉(zhuǎn)進main()函數(shù)之前,利用匯編語言編寫了一段trampoline程序(彈簧床)作為階段2可執(zhí)行鏡像的執(zhí)行入口點。之后可以在trampoline中用處理器的跳轉(zhuǎn)指令進入main()函數(shù)中去執(zhí)行。 當main()函數(shù)返回時,CPU就進行復位。第24頁,共69頁。 vivi的第一階段 完成含依賴于CPU的體系結(jié)構(gòu)硬件初始化的代碼,包括禁止中斷、初
22、始化串口、復制自身到RAM等。相關(guān)代碼集中在head.S(viviarchs3c2410目錄下):Head.S: #include config.h#include linkage.h#include machine.h Start of executable code ENTRY(_start) ;程序入口點 ENTRY(ResetEntryPoint) Exception vector table (physical address = 0 x00000000) ;異常向量表物理地址 0 x00: Reset ;復位異常 b Reset 0 x04: Undefined instructi
23、on exception ;未定義的指令異常UndefEntryPoint: b HandleUndef 0 x08: Software interrupt exception ;軟件中斷異常第25頁,共69頁。 SWIEntryPoint: b HandleSWI 0 x0c: Prefetch Abort (Instruction Fetch Memory Abort) ;內(nèi)存操作異常PrefetchAbortEnteryPoint: b HandlePrefetchAbort 0 x10: Data Access Memory Abort ;數(shù)據(jù)異常DataAbortEntryPoint
24、: b HandleDataAbort 0 x14: Not used ;未使用NotUsedEntryPoint: b HandleNotUsed 0 x18: IRQ(Interrupt Request) exception ;普通中斷異常IRQEntryPoint: b HandleIRQ 0 x1c: FIQ(Fast Interrupt Request) exception ;快速中斷異常FIQEntryPoint: b HandleFIQ VIVI magics第26頁,共69頁。 ARM規(guī)定,在起始必須有8條跳轉(zhuǎn)指令,可以用b,也可以用ldr pc,文件名。這樣的8條規(guī)則的標志被
25、arm定義為bootloader的識別標志,檢測到這樣的標志后,就可以從該位置啟動。這樣的做法是因為開始的時候不一定有bootloader,必須有一種識別機制,如果識別到bootloader,那么就從bootloader啟動。下面是固定位置存放環(huán)境變量 對vivi的這些magic number,雖然設(shè)計在這里,不過大部分沒有使用。其中0 x20和0 x24沒有使用,在0 x2C處,設(shè)計了一個magic number,組成的格式如下:bit31:24為platform,bit23:16為cpu type,bit15:0為machine id。關(guān)于ARCHITECTURE_MAGIC的定義,在【i
26、nclude/platform/smdk2410.h】第27頁,共69頁。 0 x20: magic number so we can verify that we only put .long 0 0 x24: .long 0 0 x28: where this vivi was linked, so we can put it in memory in the right place .long _start 0 x2C: this contains the platform, cpu and machine id .long ARCHITECTURE_MAGIC 0 x30: vivi
27、capabilities .long 0#ifdef CONFIG_PM ;vivi沒有使用電源管理 0 x34: b SleepRamProc#endif#ifdef CONFIG_TEST 0 x38: b hmi#endif Start VIVI headReset:第28頁,共69頁。 disable watch dog timer ;禁止看門狗計時器 mov r1, #0 x53000000 ;WTCON寄存器地址是 0 x53000000,清0 mov r2, #0 x0 str r2, r1#ifdef CONFIG_S3C2410_MPORT3 ;不符合條件,跳到下面的關(guān)中斷/
28、* 在/vivi/include/autoconf.h中#undef CONFIG_S3C2410_MPORT3*/ mov r1, #0 x56000000 ;GPACON寄存器地址是 0 x56000000 mov r2, #0 x00000005 str r2, r1, #0 x70 ;配置GPHCON控制寄存器 mov r2, #0 x00000001 str r2, r1, #0 x78 ;配置GPHUP上拉寄存器 mov r2, #0 x00000001 str r2, r1, #0 x74 ;配置GPHDAT數(shù)據(jù)寄存器#endif disable all interrupts ;
29、禁止全部中斷 mov r1, #INT_CTL_BASE mov r2, #0 xffffffff str r2, r1, #oINTMSK ;掩碼關(guān)閉所有中斷 ldr r2, =0 x7ff str r2, r1, #oINTSUBMSK 第29頁,共69頁。 initialise system clocks ;初始化系統(tǒng)時鐘 mov r1, #CLK_CTL_BASE ;定義CLK_CTL_BASE ox4C000000 mvn r2, #0 xff000000 str r2, r1, #oLOCKTIME ldr r2, mpll_50mhz ;CPU的頻率是50MHz str r2,
30、r1, #oMPLLCON#ifndef CONFIG_S3C2410_MPORT1 ;滿足條件,向下執(zhí)行/* 在/vivi/include/autoconf.h中#undef CONFIG_S3C2410_MPORT1*/ 1:2:4 mov r1, #CLK_CTL_BASE mov r2, #0 x3 str r2, r1, #oCLKDIVN mrc p15, 0, r1, c1, c0, 0 read ctrl register orr r1, r1, #0 xc0000000 Asynchronous mcr p15, 0, r1, c1, c0, 0 write ctrl reg
31、ister now, CPU clock is 200 Mhz ;CPU的頻率是200MHz mov r1, #CLK_CTL_BASE ldr r2, mpll_200mhz str r2, r1, #oMPLLCON第30頁,共69頁。 #else 1:2:2 mov r1, #CLK_CTL_BASE ldr r2, clock_clkdivn str r2, r1, #oCLKDIVN mrc p15, 0, r1, c1, c0, 0 read ctrl register orr r1, r1, #0 xc0000000 Asynchronous mcr p15, 0, r1, c1
32、, c0, 0 write ctrl register now, CPU clock is 100 Mhz ;CPU的頻率是100MHz mov r1, #CLK_CTL_BASE ldr r2, mpll_100mhz str r2, r1, #oMPLLCON#endif bl memsetup ;跳轉(zhuǎn)到memsetup函數(shù)第31頁,共69頁。 /*Memsetup函數(shù)的實現(xiàn):ENTRY(memsetup) initialise the static memory set memory control registers ;設(shè)置內(nèi)存控制寄存器的初值 mov r1, #MEM_CTL_BAS
33、E adrl r2, mem_cfg_val/* Data Area Memory configuration values.align 4mem_cfg_val: ;定義好的13*4=52個字節(jié)初值.long vBWSCON ;總線寬度和等待控制寄存器 在/vivi/include/platform/smdk2410.h中賦值/* SDRAM從32位變成16位,需要修改vBWSCON的值 */ .long vBANKCON0 .long vBANKCON1 .long vBANKCON2 .long vBANKCON3第32頁,共69頁。 /* 網(wǎng)卡控制器vBANKCON3的值可能需要修改
34、*/ .long vBANKCON4 .long vBANKCON5 .long vBANKCON6/* SDRAM從32位變成16位,可能需要修改vBANKCON6的值 */ .long vBANKCON7 .long vREFRESH ;SDRAM刷新控制寄存器 .long vBANKSIZE ;可變的組大小寄存器/* SDRAM從64MB變成32MB,需要修改vBANKSIZE的值 */ .long vMRSRB6 ;BANK6的模式設(shè)置寄存器 .long vMRSRB7 ;BANK7的模式設(shè)置寄存器*/ add r3, r1, #521: ldr r4, r2, #4 str r4,
35、r1, #4 cmp r1, r3 bne 1b ;循環(huán)操作,直到13個寄存器賦值完成 mov pc, lr第33頁,共69頁。 */#ifdef CONFIG_PM ;vivi考慮不需要使用電源管理 Check if this is a wake-up from sleep ldr r1, PMST_ADDR ldr r0, r1 tst r0, #(PMST_SMR) bne WakeupStart ;查看狀態(tài),判斷是否需要跳轉(zhuǎn)到WakeupStart #endif#ifdef CONFIG_S3C2410_SMDK ;SMDK開發(fā)板使用 All LED on ;點亮開發(fā)板上的LED mo
36、v r1, #GPIO_CTL_BASE add r1, r1, #oGPIO_F ;LED使用GPIOF組的管腳 ldr r2,=0 x55aa ;使能EINT0,EINT1,EINT2,EINT3,;另四個管腳配置成輸出,屏蔽EINT4,5,6,7 str r2, r1, #oGPIO_CON ;配置管腳 mov r2, #0 xff str r2, r1, #oGPIO_UP ;禁止上拉功能 mov r2, #0 x00 str r2, r1, #oGPIO_DAT ;PORT H 數(shù)據(jù)寄存器第34頁,共69頁。 #endif#if 0 SVC ;進入系統(tǒng)管理模式 mrs r0, cps
37、r bic r0, r0, #0 xdf orr r1, r0, #0 xd3 msr cpsr_all, r1#endif set GPIO for UART ;設(shè)置串口 mov r1, #GPIO_CTL_BASE add r1, r1, #oGPIO_H ;設(shè)置GPIO_H組管腳為串口 ldr r2, gpio_con_uart str r2, r1, #oGPIO_CON ldr r2, gpio_up_uart str r2, r1, #oGPIO_UP /* initial values for GPIOgpio_con_uart: .long vGPHCON ;vGPHCON在/
38、vivi/include/platform/smdk2410.h中賦值 ;#define vGPHCON 0 x0016faaa ;GPIO_H配置為nCTS0,nRTS0, RXD0,TXD0, RXD1, ,TXD1,nCTS1,nRTS1,第35頁,共69頁。 /* 三個串口都使能,可能需要修改#define vGPHCON 0 x0016aaaa */gpio_up_uart: .long Vgphup ;同上#define vGPHUP 0 x000007ff ;The pull-up function is disabled.*/ bl InitUART ;跳轉(zhuǎn)到InitUART串
39、口初始化函數(shù) Initialize UART r0 = number of UART portInitUART: ldr r1, SerBase/*.align 4 ;缺省情況下在vivi中只初始化了UART0SerBase:#if defined(CONFIG_SERIAL_UART0) .long UART0_CTL_BASE ;基地址在/vivi/include/s3c2410.h中定義#elif defined(CONFIG_SERIAL_UART1) .long UART1_CTL_BASE#elif defined(CONFIG_SERIAL_UART2) .long UART2_
40、CTL_BASE#else#error not defined base address of serial#endif第36頁,共69頁。 */ mov r2, #0 x0 str r2, r1, #oUFCON ; UART FIFO控制寄存器 str r2, r1, #oUMCON ; UART MODEM控制寄存器 mov r2, #0 x3 str r2, r1, #oULCON ; UART 列控制寄存器 ldr r2, =0 x245 str r2, r1, #oUCON ; UART控制寄存器#define UART_BRD (50000000 / (UART_BAUD_RAT
41、E * 16) - 1) mov r2, #UART_BRD; 波特率設(shè)置 str r2, r1, #oUBRDIV ;波特率約數(shù)寄存器 mov r3, #100 mov r2, #0 x01: sub r3, r3, #0 x1 tst r2, r3 bne 1b #if 0 mov r2, #U str r2, r1, #oUTXHL ; UART 傳輸緩沖區(qū)寄存器1: ldr r3, r1, #oUTRSTAT ;UART 錯誤寄存器第37頁,共69頁。 and r3, r3, #UTRSTAT_TX_EMPTY tst r3, #UTRSTAT_TX_EMPTY bne 1b mov
42、r2, #0 str r2, r1, #oUTXHL1: ldr r3, r1, #oUTRSTAT ;UART TX/RX狀態(tài)寄存器 and r3, r3, #UTRSTAT_TX_EMPTY tst r3, #UTRSTAT_TX_EMPTY bne 1b #endif mov pc, lr*/#ifdef CONFIG_DEBUG_LL ;打印調(diào)試信息,缺省未定義 Print current Program Counter ldr r1, SerBase mov r0, #r bl PrintChar mov r0, #n bl PrintChar mov r0, #第38頁,共69頁。
43、 bl PrintChar mov r0, pc bl PrintHexWord#endif#ifdef CONFIG_BOOTUP_MEMTEST simple memory test to find some DRAM flaults. bl memtest#endif#ifdef CONFIG_S3C2410_NAND_BOOT ;從NAND Flash啟動 bl copy_myself ;跳轉(zhuǎn)到copy_myself函數(shù), /* copy_myself: copy vivi to ram;復制到RAMcopy_myself: mov r10, lr reset NAND; 復位NAND
44、 FLASH mov r1, #NAND_CTL_BASE ldr r2, =0 xf830 initial value第39頁,共69頁。 str r2, r1, #oNFCONF ;配置NAND FLASH ldr r2, r1, #oNFCONF bic r2, r2, #0 x800 ;芯片使能,Bit11為0,使能,即允許訪問 str r2, r1, #oNFCONF mov r2, #0 xff RESET command strb r2, r1, #oNFCMD ;設(shè)置NAND FLASH命令 mov r3, #0 wait 1: add r3, r3, #0 x1 cmp r3
45、, #0 xa blt 1b2: ldr r2, r1, #oNFSTAT wait ready ; NAND FLASH操作狀態(tài)寄存器 tst r2, #0 x1 beq 2b ldr r2, r1, #oNFCONF orr r2, r2, #0 x800 ;禁止芯片,不允許訪問 str r2, r1, #oNFCONF get read to call C functions (for nand_read() ldr sp, DW_STACK_START setup stack pointer mov fp, #0 no previous frame, so fp=0 copy vivi
46、 to RAM ldr r0, =VIVI_RAM_BASE第40頁,共69頁。*/ mov r1, #0 x0 mov r2, #0 x20000 ;0 x20000-128k字節(jié) bl nand_read_ll ;nand_read_ll在/vivi/arch/s3c2410/nand_read.c中定義 ;r0,r1,r2分別為函數(shù)的三個參數(shù) ;從NANDFlash的0地址拷貝128k到SDRAM指定處 tst r0, #0 x0 beq ok_nand_read#ifdef CONFIG_DEBUG_LLbad_nand_read: ldr r0, STR_FAIL ldr r1, S
47、erBase bl PrintWord1: b 1b infinite loop #endifok_nand_read:#ifdef CONFIG_DEBUG_LL ldr r0, STR_OK ldr r1, SerBase bl PrintWord#endif/*在/vivi/linux/platform/smdk2410.h中定義#define VIVI_RAM_BASE (DRAM_BASE + DRAM_SIZE - VIVI_RAM_SIZE)第41頁,共69頁。 verify mov r0, #0 ldr r1, =0 x33f00000 mov r2, #0 x400 4 by
48、tes * 1024 = 4K-bytesgo_next: ldr r3, r0, #4 ldr r4, r1, #4 teq r3, r4 bne notmatch subs r2, r2, #4 beq done_nand_read bne go_nextnotmatch:#ifdef CONFIG_DEBUG_LL sub r0, r0, #4 ldr r1, SerBase bl PrintHexWord ldr r0, STR_FAIL ldr r1, SerBase bl PrintWord#endif第42頁,共69頁。 1: b 1bdone_nand_read:#ifdef
49、CONFIG_DEBUG_LL ldr r0, STR_OK ldr r1, SerBase bl PrintWord#endif mov pc, r10 ;vivi拷貝到SDRAM完成,函數(shù)返回*/ jump to ram ldr r1, =on_the_ram add pc, r1, #0 nop nop1: b 1b infinite loopon_the_ram:#endif#ifdef CONFIG_DEBUG_LL ldr r1, SerBase ldr r0, STR_STACK bl PrintWord ldr r0, DW_STACK_START bl PrintHexWor
50、d#endif第43頁,共69頁。 get read to call C functions ldr sp, DW_STACK_START setup stack pointer mov fp, #0 no previous frame, so fp=0 mov a2, #0 set argv to NULL bl main call main mov pc, #FLASH_BASE otherwise, reboot End VIVI head第44頁,共69頁。 Bootloader的第二階段是用C語言完成的,但是與普通 C語言應(yīng)用程序不同的是,在編譯和鏈接Bootloader時,不能使用
51、glibc庫中的任何支持函數(shù),從哪里跳轉(zhuǎn)進 main() 函數(shù)呢? 直接把 main() 函數(shù)的起始地址作為整個 stage2 執(zhí)行映像的入口點或許是最直接的想法。 但是這樣做有兩個缺點: 1)無法通過main() 函數(shù)傳遞函數(shù)參數(shù); 2)無法處理 main() 函數(shù)返回的情況。 一種較為巧妙的方法是利用彈簧床的概念,也就是用匯編語言寫一段trampoline 小程序,并將這段程序作為stage2可執(zhí)行映象的執(zhí)行入口點,然后在trampoline匯編小程序中用CPU跳轉(zhuǎn)指令跳入main()函數(shù)中去執(zhí)行。當main()函數(shù)返回時,CPU執(zhí)行路徑再次回到trampoline程序。簡而言之,這種方法
52、的思想就是:用這段 trampoline小程序來作為main()函數(shù)的外部包裹。 vivi的第二階段 第45頁,共69頁。Trampoline程序的源代碼如下:ldrsp,DW_STACK_START;設(shè)置堆棧指針movfp,#0 ;no previous frame,so fp=0mova2,#0 ;set argv to NULLblmain ;call mainmovpc,#FLASH_BASE ;否則,reboot第46頁,共69頁。 vivi的第二階段是從main()函數(shù)開始,同一般的C語言程序一樣,該函數(shù)在/init/main.c文件中,總共可以分為8個步驟。 (1) 函數(shù)開始,通
53、過putstr(vivi_banner)打印出vivi的版本。 Vivi_banner在/init/version.c文件中定義 (2) 對開發(fā)板進行初始化(board_init函數(shù)),board_init是與開發(fā)板緊密相關(guān)的,這個函數(shù)在/arch/s3c2410/smdk.c文件中。開發(fā)板初始化主要完成兩個功能,時鐘初始化(init_time())和通用IO口設(shè)置(set_gpios())。 第47頁,共69頁。 void set_gpios(void) GPACON = vGPACON; GPBCON = vGPBCON; GPBUP = vGPBUP; GPCCON = vGPCCON;
54、 GPCUP = vGPCUP; GPDCON = vGPDCON; GPDUP = vGPDUP; GPECON = vGPECON; GPEUP = vGPEUP; GPFCON = vGPFCON; GPFUP = vGPFUP; GPGCON = vGPGCON; GPGUP = vGPGUP; GPHCON = vGPHCON; GPHUP = vGPHUP; EXTINT0 = vEXTINT0; EXTINT1 = vEXTINT1; EXTINT2 = vEXTINT2;GPIO口在smdk2410.h(viviincludeplatform目錄下)文件中定義。這里vGPxCO
55、N中的v表示value,oGPxCON中的o表示offset 第48頁,共69頁。 (3) 內(nèi)存映射初始化和內(nèi)存管理單元的初始化工作:mem_map_init();mmu_init();這兩個函數(shù)都在/arch/s3c2410/mmu.c文件中。void mem_map_init(void)#ifdef CONFIG_S3C2410_NAND_BOOT mem_map_nand_boot();#else mem_map_nor();#endif cache_clean_invalidate(); tlb_invalidate(); 如果配置vivi時使用了NAND作為啟動設(shè)備,則執(zhí)行mem_m
56、ap_nand_boot(),否則執(zhí)行mem_map_nor()。這里要注意的是,如果使用NOR啟動,則必須先把vivi代碼復制到RAM中。這個過程是由copy_vivi_to_ram()函數(shù)來完成的。代碼如下: static void copy_vivi_to_ram(void) putstr_hex(Evacuating 1MB of Flash to DRAM at 0 x, VIVI_RAM_BASE); memcpy(void *)VIVI_RAM_BASE, (void *)VIVI_ROM_BASE,VIVI_RAM_SIZE);第49頁,共69頁。 VIVI_RAM_BASE、
57、VIVI_ROM_BASE、VIVI_RAM_SIZE這些值都可以在smdk2410.h中查到,并且這些值必須根據(jù)自己開發(fā)板的RAM實際大小修改。這也是在移植vivi的過程中需要注意的一個地方。 mmu_init()函數(shù)中執(zhí)行了arm920_setup()函數(shù)。這段代碼是用匯編語言實現(xiàn)的,針對arm920t核的處理器。 (4) 初始化堆棧,heap_init()。(定義在vivilibheap.c文件中)int heap_init(void) return mmalloc_init(unsigned char *)(HEAP_BASE), HEAP_SIZE); 第50頁,共69頁。 (5)
58、初始化mtd設(shè)備,mtd_dev_init()。int mtd_init(void) int ret;#ifdef CONFIG_MTD_CFI ret = cfi_init();#endif#ifdef CONFIG_MTD_SMC ret = smc_init();#endif#ifdef CONFIG_S3C2410_AMD_BOOT ret = amd_init();#endif if (ret) mymtd = NULL; return ret; return 0;這幾個函數(shù)可以在/drivers/mtd/maps/s3c2410_flash.c里找到。第51頁,共69頁。 (6)
59、初始化私有數(shù)據(jù),init_priv_data()。(定義在vivilibpriv_datarw.c文件中) 此部分的功能是把vivi可能用到的所有私有參數(shù)都放在預先規(guī)劃的內(nèi)存區(qū)域,大小為48K,基地址為0 x33df0000。在內(nèi)存的分配示意圖方面,可以參考s3c2410完全開發(fā)。這48K區(qū)域分為三個組成部分:MTD參數(shù)、vivi parameter、Linux啟動命令。 到此為止,vivi作為bootloader的三大核心任務(wù):initialise various devices, and eventually call the Linux kernel,passing informatio
60、n to the kernel,現(xiàn)在只是完成第一方面的工作,設(shè)備初始化基本完成,實際上step 6是為啟動Linux內(nèi)核和傳遞參數(shù)做準備的,把vivi的私有信息,內(nèi)核啟動參數(shù),mtd分區(qū)信息等都放到特定的內(nèi)存區(qū)域,等待后面兩個重要工作使用(在step 8完成,后面的step 7也是為step 8服務(wù)的)。(7) 初始化內(nèi)置命令,init_builtin_cmds()。 通過add_command函數(shù),加載vivi內(nèi)置的幾個命令。(8) 啟動vivi-boot_or_vivi()。啟動成功后,將通過vivi_shell()啟動一個shell(如果配置了CONFIG_SERIAL_TERM),此時
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
- 6. 下載文件中如有侵權(quán)或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 勞務(wù)合同范本林業(yè)
- 傳單派發(fā)合同范本
- 鄉(xiāng)鎮(zhèn)物業(yè)收費合同范本
- 勞務(wù)公司租車合同范本
- 公會主播合同范本
- 勞務(wù)購買合同范例
- 公司經(jīng)營模式合同范本
- 出售買賣合同范本
- 勞動合同轉(zhuǎn)簽合同范本
- 2025國合通測校園招聘筆試參考題庫附帶答案詳解
- 不規(guī)則抗體篩查與鑒定
- 2023-2024人教版小學2二年級數(shù)學下冊(全冊)教案【新教材】
- 中國銀行海爾多聯(lián)機方案書
- 小學《體育與健康》體育基礎(chǔ)理論知識
- JJG 144-2007標準測力儀
- GB/T 8417-2003燈光信號顏色
- GB/T 7984-2001輸送帶具有橡膠或塑料覆蓋層的普通用途織物芯輸送帶
- GB/T 7324-2010通用鋰基潤滑脂
- GB/T 5916-2020產(chǎn)蛋雞和肉雞配合飼料
- GB/T 28114-2011鎂質(zhì)強化瓷器
- GB/T 15566.1-2020公共信息導向系統(tǒng)設(shè)置原則與要求第1部分:總則
評論
0/150
提交評論