一.Bootloader 本文引用地址:http://www.104case.com/article/201611/316768.htm是 ARM系統的開機程序,用匯編語言編寫,完成系統的初始化操作.是系統上電復位后,操作系統或用戶應用程序運行前,首先必須運行的一段程序. 作用:1,初始化硬件; 2,建立內存空間的映射圖(有的CPU沒有內存映射功能如S3C44B0). 二. 啟動流程 2種啟動方式: - 直接從Flash 啟動
- 將壓縮的內存映像文件從Flash中復制,解壓到RAM,再從RAM啟動
(節省Flash資源,提高速度) 啟動流程圖: 
1. 啟動代碼的第一步是設置中斷和異常向量 2. 完成系統啟動所必須的最小配置. 某些處理器芯片包含一個或幾個全局寄存器,這些寄存器必須在系統啟動的最初進行配置. 3. 設置看門狗,擁護設置的部分外圍電路如果必須在系統啟動時初始化,就可以放在這一步. 4. 配置系統所使用的寄存器,包括Flash,SRAM,DRAM等,并為他們分配地址空間.如果系統使用了DRAM或其他外設,就需要設置相關的寄存器,以確定其刷新頻率,數據總線寬度等信息,初始化存儲器系統 有些芯片可通過寄存器編程初始化存儲器系統,而對于較復雜系統通常集成有 MMU 來管理內存空間。 5. 為處理器的每個工作模式設置棧指針. ARM 處理器有多種工作模式,每種工作模式都需要設置單獨的棧空間。 6. 變量初始化. 這里的變量指的是在軟件中定義的已經賦好初值的全局變量,啟動過程中需要將這部分變量從只讀區域,也就是 Flash 拷貝到讀寫區域中,因為這部分變量的值在軟件運行時有可能重新賦值。還有一種變量不需要處理,就是已經賦好初值的靜態全局變量,這部分變量在軟件運行過程中不會改變,因此可以直接固化在只讀的 Flash 或 EEPROM 中。 7. 數據區準備 對于軟件中所有未賦初值的全局變量,啟動過程中需要將這部分變量所在區域全部清零。 8. 調用高級語言函數.比如 main 函數等。 三.程序分析 下面根據實際經過測試的代碼詳細講述系統的啟動過程。 .text/* 將此操作符開始的代碼編譯到代碼段或代碼段子段中 */ /* 集成開發環境( IDE )可以通過鏈接腳本文件將下面的語句定位在零起始地址,系統上電后 CPU 從此處開始執行 */ ENTRY:/*用于指定匯編程序的入口點*/ b ResetHandler/* 跳至 ResetHandler ,此句被定位在零起始地址 */ /* 除用戶模式外的其他 6 種模式稱為特權模式。特權操作模式主要處理異常和監控調用(有時稱為軟件中斷),它們可以自由的訪問系統資源和改變模式。特權模式中除系統模式以外的 5 種模式又稱為異常模式,下面的代碼用于出現異常時 CPU 就會根據以下的語句自動跳轉到對應的異常處理程序處 */ b HandlerUndef /* handlerUndef */ b HandlerSWI /* SWI interrupt handler */ b HandlerPabort /* handlerPAbort */ b HandlerDabort /* handlerDAbort */ b . /* handlerReserved */ b HandlerIRQ b HandlerFIQ ... ... ResetHandler:/* 上電后跳轉到此處開始執行 */ LDR R0, =WTCON/* 禁止看門狗 */ LDR R1, =0x0 STRR1, [R0] LDRR0, =INTMSK /* 屏蔽所有中斷請求 */ LDR R1, =0x07FFFFFF STRR1, [R0] /* 設置時鐘控制寄存器 */ ldrr0,=LOCKTIME ldrr1,=0xfff strr1,[r0] .if PLLONSTART ldrr0,=PLLCON/* 設置 PLL */ ldrr1,=((M_DIV<<12)+(P_DIV<<4)+S_DIV)/*Fin=8MHz,Fout=64MHz*/ strr1,[r0] .endif ldr r0,=CLKCON ldr r1,=0x7ff8 /* 所有單元時鐘允許 */ str r1,[r0] /* 為 BDMA 設置復位值 */ ldr r0,=BDIDES0 ldr r1,=0x40000000 /* BDIDESn 復位值應為 0x40000000 */ str r1,[r0] ldr r0,=BDIDES1 ldr r1,=0x40000000 /* BDIDESn 復位值應為 0x40000000 */ str r1,[r0] /* 設置存儲器控制寄存器,存儲器的配置數據都存儲在 SMRDATA 為起始地址的數據表中,下面的代碼可以一次將預先配置好的初始化數據存入與存儲器控制器相關的 13 個寄存器,這些寄存器則是以 0x01c80000 為起始地址的 13 個連續的 32 位寄存器 */ ldr r0,=SMRDATA ldmia r0,{r1-r13} ldr r0,=0x01c80000 /* BWSCON 存儲控制寄存器地址 */ stmia r0,{r1-r13} /* 初始化堆棧 */ /* CPU 復位后是處于管理模式下的,所以首先要初始化管理模式下的堆棧寄存器 */ ldr sp, =SVCStack /* 由于處理器的每種運行模式都要有自己獨立的物理堆棧寄存器 R13 ,在用戶應用程序的初始化部分,一般都要初始化每種模式下的 R13 ,使其指向該運行模式的棧空間,這樣,當程序的運行進入異常模式時,可以將需要保護的寄存器放入 R13 所指向的堆棧,而當程序從異常模式返回時,則從對應的堆棧中恢復,采用這種方式可以保證異常發生后程序的正常執行 */ bl InitStacks/* 跳轉至其它堆棧初始化程序并返回 */ /* 設置 IRQ 中斷處理 */ /*44B0 有兩種中斷模式:一種是沒有中斷向量表;一種是使用了中斷向量表,使用中斷向量表只能是 IRQ 方式。當使用中斷向量表的時候,中斷發生時由 S3C44B0 的中斷控制器根據中斷向量表,利用硬件方式自動跳轉到相應的中斷處理服務程序所在的位置;不使用中斷向量表時按下面的代碼,利用軟件方式跳轉而進行中斷處理,因為 S3C44B0 有 30 個中斷源,所以需要程序判斷以確定調用那個中斷服務程序 */ ldr r0,=HandleIRQ/* 如果在 0x18 和 0x1c 地址處無 “subs pc,lr,#4”*/ ldr r1,=IsrIRQ/* 為了中斷正常返回這些語句是必須的 */ str r1,[r0] /* 拷貝讀寫區域數據 / 數據區準備,將系統需要讀寫的數據和變量從 ROM 拷貝到 RAM 里。 Image_RO_Limit 、 Image_RW_Base 、 Image_ZI_Base 等這些符號還會在另外的鏈接腳本文件中出現,這些符號是用來定位程序各個段的參考信息。集成開發環境在編譯鏈接的時候會根據我們編寫的程序,把它們轉換成用來對各個段定位的地址信息 */ LDR r0, =Image_RO_Limit/* 取只讀數據區域地址指針 */ LDR r1, =Image_RW_Base/* 準備執行拷貝操作 */ LDR r3, =Image_ZI_Base CMP r0, r1 /* 檢查是否相同 */ BEQ F1 /* 相同則跳過拷貝操作 */ F0: CMP r1, r3/* 執行拷貝操作 */ LDRCC r2, [r0], #4 STRCC r2, [r1], #4 BCC F0 F1: LDR r1, =Image_ZI_Base/* 零數據準備區起始地址 */ MOV r2, #0 F2: CMP r3, r1 /* 執行數據區清零 */ STRCC r2, [r3], #4 BCC F2 MRSr0, CPSR BICr0, r0, #NOINT /* 中斷請求允許 */ MSRCPSR_cxsf, r0 /* 跳轉到 C 入口程序 */ BLMain B . 四 . 總結: 啟動過程中的初始化程序就是初始化 CPU 內部各個關鍵的寄存器、配置外圍硬件電路相關寄存器、建立中斷向量表等,然后跳轉到一般由高級語言編寫的主函數的應用程序代碼去執行,這樣就可以利用高級語言來編寫完成系統設計所要求的各種功能。初始化的過程對大多數初學者來說,比較難理解的是中斷的處理和一些少見的操作符號,這些符號多是一些宏定義或系統用于在內存空間中對各個段的定位標識符號。掌握了S3C44B0的啟動代碼之后,對系統功能程序設計會起到很大的幫助,是進行下一步程序設計的基礎。 |
評論