CPU上電后,會在某個地址開始執行,比如MIPS結構的CPU會從0xBFC00000取第一條指令,而ARM結構的CPU則從0x00000000開始,嵌入式開發板中,需要把存儲器件ROM或Flash等映射到這個地址。而Bootloader就存在這個地址的開始處,這樣一上電后就會從這個地址處執行。Bootloader執行后從板子上的某個固態存儲設備上將操作系統OS加載到RAM中運行。(一些功能強大的Bootloader,比如U-boot在正常啟動加載后可以延時若干秒(也可以自己設置),等待終端用戶按下任意鍵后便可進入到下載模式;如果在指定的時間內沒有按鍵,U-boot則會啟動Linux內核,內核的啟動參數可以是默認的或是由U-boot傳遞給它的)。
**注意:有的CPU在運行Bootloader之前 先運行一段固件(firmware)中固化的boot代碼,比如x86結構的CPU就是先運行BIOS中的 固件然后才開始運行硬盤第一個分區中的Bootloader。在大多數的嵌入式系統中並沒有固件,Bootloader是上電后運行的第一個代碼。**
下面便更細致得說明Bootloader的啟動過程:
從固態存儲器上啟動的Bootloader大多數是分二個階段來啟動的。
**第一個階段**使用匯編代碼來實現,它主要完成一些依賴於CPU體系結構的初始化,比如關看門狗、關中斷、初始化RAM、將第二階段調用的C語言代碼復制到RAM(非必須,例如對於NOR Flash等設備可以直接在上面執行,只不過比在RAM上執行效率低),設置CPU的速度和時鍾頻率(非必需,也可以放在第二階段),設置好棧,跳轉到第二階段的C語言入口處等;
**第二個階段**通常用C語言來實現,它主要用來:初始化本階段要用到的硬件設備、檢測系統內存映射(就是確定板上使用了多少內存,他們的地址空間是什么)、將內核映像和根文件系統映像從Flash上復制到內存RAM並且在內存中的某個固定位置為內核設置啟動參數Boot parameters(Flash上的內核映像有可能是經過壓縮的,那么讀到RAM后還要進行解壓。對於有自解壓功能的內核不需要Bootloader來解壓。另外將根文件系統映像復制到RAM是非必須的,這取決於是什么類型的根文件系統,以及內核訪問它的方法)、調用內核(內核啟動后會掛載根文件系統,所以典型的嵌入式Linux系統的分區結構為Botloader + Boot parameters + Kernel + Root filesystem)。
**從上面的分析可知將內核放到適當的位置后,直接跳到其入口點便可以啟動內核,在內核之前需要滿足那些條件呢,下面我們來具體分析:**
**CPU寄存器R0、R1和R2值的設置**
由於U-boot在設置完啟動參數標記列表后最終是調用theKernel函數來跳轉執行linux內核的,uboot調用這個函數(其實就是linux內核)時會直接傳遞給linux內核3個參數,而這3個參數就是通過寄存器來實現傳參的。其中第1個參數固定為0,就放在r0寄存器中,第二個參數為機器類型ID也就是我們常說的機器碼,就放在r1寄存器中,第3個參數就是啟動參數標記列表在RAM中的首地址,就放在r2寄存器中。
**CPU工作模式的設置**
必須禁止中斷(IRQs和FIQs),並且要將CPU設置為SVC模式。
這是因為uboot只是完成硬件初始化,環境參數設置,代碼搬運等工作,用不到中斷。屏蔽中斷是為了避免因為意外中斷使得boot失敗,畢竟很多外設還沒有初始化,對應中斷代碼也都沒有准備好。
那么為什么要將CPU設置為SVC模式呢?我們先簡單的來分析一下CPU的7種模式:
中止abt和未定義und模式:
首先可以排除的是,中止abt和未定義und模式,那都是不太正常的模式,此處程序是正常運行的,所以不應該設置CPU為其中任何一種模式,所以可以排除。
快中斷fiq和中斷irq模式:
其次,對於快中斷fiq和中斷irq來說,此處uboot初始化的時候,也還沒啥中斷要處理和能夠處理,而且即使是注冊了終端服務程序后,能夠處理中斷,那么這兩種模式,也是自動切換過去的,所以,此處也不應該設置為其中任何一種模式。
用戶usr模式:
雖然從理論上來說,可以設置CPU為用戶usr模式,但是由於此模式無法直接訪問很多的硬件資源,而uboot初始化,就必須要去訪問這類資源,所以此處可以排除,不能設置為用戶usr模式。
系統sys模式 vs 管理svc模式:
首先,sys模式和usr模式相比,所用的寄存器組,都是一樣的,但是增加了一些訪問一些在usr模式下不能訪問的資源。
而svc模式本身就屬於特權模式,本身就可以訪問那些受控資源,而且,比sys模式還多了些自己模式下的影子寄存器,所以,相對sys模式來說,可以訪問資源的能力相同,但是擁有更多的硬件資源。
所以,從理論上來說,雖然可以設置為sys和svc模式的任一種,但是從uboot方面考慮,其要做的事情是初始化系統相關硬件資源,需要獲取盡量多的權限,以方便操作硬件,初始化硬件。
從uboot的目的是初始化硬件的角度來說,設置為svc模式,更有利於其工作。
因此,此處將CPU設置為SVC模式。
另外uboot作為一個bootloader來說,最終目的是為了啟動Linux的kernel,在做好准備工作(即初始化硬件,准備好kernel和rootfs等)跳轉到kernel之前,本身就要滿足一些條件,其中一個條件,就是要求CPU處於SVC模式的。
所以,uboot在最初的初始化階段,就將CPU設置為SVC模式,也是最合適的。
**Cache和MMU的設置**
MMU和數據Cache必須必須關閉,指令Cache可以打開也可以關閉。
由於MMU在上電之初是沒有任何作用的,也就是說U-boo第一階段的匯編代碼以及第二階段的源代碼初始化相關外設時訪問的都是都是實際地址,MMU起不到任何作用,為了啟動之初不影響對程序的啟動常關閉MMU。
Cache是位於RAM和CPU內部寄存器之間的一個存儲設施,用來加速二者之間的數據傳輸速度,即用來加快CPU從內存中取出指令的速度。但是在上電后CPU的初始化要比內存RAM快一拍,當CPU初始化完成后需要讀取來自內存的數據,若內存還沒有准備好那勢必會造成異常,系統就掛掉了,因此需要關閉數據Cache,而指令Cache關與不關影響不大。