uboot如何啟動核心

2021-09-12 20:56:29 字數 3946 閱讀 9831

uboot的本質是乙個裸機程式,作業系統核心本質也是裸機程式。區別就是作業系統執行起來後,在軟體上分為核心層和應用層,分層後兩層的許可權不同,記憶體訪問和裝置操作的管理更加精細(核心可以隨便訪問各種硬體,而應用程式只能被限制地訪問硬體和記憶體位址)。

直觀來看,uboot的映象是uboot.bin,linux系統的映象是zimage,這兩個東西其實都是兩個裸機程式映象,從系統啟動的角度來講,核心其實就是乙個大的、複雜的裸機程式。

乙個完整的軟體+硬體的嵌入式系統,靜止時(未上電時)bootloader、kernel、rootfs等必須的軟體都以映象的形式儲存在啟動介質中(x210中是inand/sd卡);執行時都是在ddr記憶體中執行的,與儲存介質無關。上面兩個狀態都是穩定狀態,第3個狀態是動態過程,也就是啟動過程。

動態啟動過程就是乙個從sd卡逐步搬移到ddr記憶體,並且執行啟動**進行相關的硬體初始化和軟體架構的建立,最終達到執行時穩定狀態。

靜止時uboot.bin、zimage、rootfs都在sd卡中,它們不可能隨意存放在sd卡的任意位置,因此需要對sd卡進行乙個分割槽,然後將各種映象各自存放在各自的分割槽,這樣在啟動過程中uboot、核心等就知道到**去找誰。

uboot在第一階段中進行重定位時將第二階段(整個uboot映象)載入到ddr的0xc3e00000位址處,這個位址就是uboot的鏈結位址。

核心也有類似要求,uboot啟動核心時將記憶體從sd卡讀取放到ddr中(其實就是個重定位的過程),不能隨意放置,必須放在核心的鏈結位址處,否則啟動不起來。

uboot是無條件啟動的,從零開始啟動的;核心啟動需要幫忙,uboot要幫助核心實現重定位(從sd卡到ddr),uboot還要給核心提供啟動引數。

uboot要啟動核心,分為兩個步驟:第一步是將核心映象從啟動介質中載入到ddr中,第二步是去ddr中啟動核心映象。(核心**沒有考慮重定位,而是直接由uboot載入到ddr中的它的鏈結位址)。

常規啟動時,各種映象都在sd卡中,因此uboot只需要從sd卡的kernel分割槽去讀取核心映象到ddr中即可。讀取要使用uboot的命令來讀取。譬如x210的inand版本時movi命令,movi read kernel 30008000。其中kernel指的是uboot中的kernel分割槽(uboot規定的sd卡中的乙個區域範圍)。

命令前加do_即可構成這個命令對應的函式,因此當我們bootm命令執行時,uboot實際執行的函式叫do_bootm函式,在cmd_bootm.c。

do_bootm剛開始定義了一些變數,然後用巨集來條件編譯執行secureboot的一些**(主要進行簽名認證);然後到了config_zimage_boot,用這個巨集來控制進行條件編譯一些**,這段**是用來支援zimage格式的核心啟動的。

linux核心經過編譯後也會生成乙個elf格式的可執行程式,叫vmlinux或vmlinuz,這個就是原始的未經任何處理加工的原版核心elf檔案;嵌入式系統部署時刻錄的一般不是這個,而是要用objcopy工具去製作成燒錄映象格式(就是uboot.bin格式,但是沒有bin字尾),經過製作加工成燒錄映象的檔案就叫image(製作把78m大的精簡成了7.5m,因此這個製作燒錄映象的目的就是縮減大小,節省磁碟)。

原則上image就可以直接被燒錄到flash上進行啟動執行(類似於uboot.bin)。實際上linux得作者們覺得image還是太大了所以對image進行了壓縮,並且在image壓縮後的檔案的前端加了一部分解壓縮的**,構成了乙個壓縮格式的映象就叫做zimage。

uboot為了啟動核心,還發明了一種核心格式叫uimage,uimage是由zimage加工得到的。(注意,uimage不關linux核心的事,linux只管生成zimage)。

do_bootm函式中一直到397行的after_header_check這個符號處,都是在進行映象的頭部資訊校驗。校驗時就要根據不同種類的image型別進行不同的校驗。所以do_bootm函式的核心就是去分辨傳進來的image到底是什麼型別,然後按照這種型別的頭資訊格式去校驗。校驗通過則進入下一步去啟動核心;失敗則認為核心有問題,不能啟動。

這個是乙個定義的魔數,表示這個映象是乙個zimage,也就是說zimage格式的映象中在頭部的乙個固定位置存放了這個數作為格式標記。如果我們拿到乙個image,去他的那個位置去取4位元組判斷它是否等於對應魔數,就可知道映象型別。

這個資料結構是uboot啟動核心時使用的乙個標準啟動資料結構,zimage頭資訊也是乙個image_header_t,但是在實際啟動之前需要進行一些改造。hdr->ih_os = ih_os_linux;hdr->ih_ep = ntohl(addr),這兩句就是在進行改造。

images全域性變數是do_bootm函式中使用的,用來完成啟動過程的。zimage的校驗過程其實就是先確認是不是zimage,確認後再修改zimage的頭資訊到合適,修改後用頭資訊去初始化images這個全域性變數,然後就完成校驗。

legacy(遺留的),在do_bootm函式中,這種方式指的就是uimage方式。

uimage方式是uboot本身發明的支援linux啟動的映象格式,但是後來這種方式被一種新的方式替代,這個新的方式就是裝置樹方式。

uimage的啟動校驗主要在boot_get_kernel函式中,主要任務就是校驗uimage的頭資訊,並且得到真正的kernel的起始位置去啟動。

上述校驗頭資訊即為啟動核心第二步;第三階段是呼叫do_bootm_linux函式。

函式在uboot/lib_arm/bootm.c中。

ep就是entrypoint的縮寫,就是程式入口。乙個映象檔案的起始執行部分不是在映象的開頭(開頭是n位元組的頭資訊),真正的映象檔案執行時第一句**在映象的中部某個位元組處,相當於一定的偏移量,這個偏移量記錄在頭資訊中。

一般執行乙個映象都是:第一步先讀取頭資訊,然後在頭資訊的特定位址去找magic_num,由此來確定映象種類;第二步對映象進行校驗;第三步再次讀取頭資訊,由特定位址知道這個映象的各種資訊(映象長度,映象種類,入口位址);第四步就是去entrypoint處執行映象。

thekernel = (void (*)(int, int, uint))ep;

將ep賦值給thekernel,則這個函式就指向了記憶體中載入的os映象的真正入口位址(就是作業系統的第一句執行**)。

uboot在啟動核心時,機器碼要傳給核心。uboot傳給核心的機器碼如何確定?第一順序是環境變數machid,第二順序是gd->bd->bi_arch_num(x210_sd.h中硬編碼配置的)

starting kernel ... 這個是uboot中最後一句列印出來的東西。這句如果能出現,說明uboot整個是成功的,也成功載入了核心映象,也校驗通過了,也找到入口位址了,也試圖去執行了。如果這句之後串列埠沒有輸出,說明核心沒有被成功執行,原因一般是:傳參(佔80%)、核心在ddr中的載入位址。

struct tag,tag是乙個資料結構,在uboot和linux kernel中都有定義tag資料結構,而且定義是一樣的。

tag_header和tag_***:tag_header中有這個tag的size和型別編碼,kernel拿到乙個tag後先分析tag_header得到tag的型別和大小,然後將tag中剩餘部分當作乙個tag_***處理。

tag_start與tag_end:kernel接收到的引數是若干個tag組成的,這些tag由tag_start開始,由tag_end結束。

tag傳參的方式是由linux kernel發明的,kernel定義了這種向自身傳參的方式,uboot只是實現了這種方式從而可以支援給kernel傳參。

config_setup_memory_tags,tag_mem,傳參內容是記憶體配置資訊。

config_cmdline_tag,tag_cmdline,傳參內容是啟動命令列引數,也就是uboot環境變數的bootargs。

核心如何拿到這些tag?

uboot最終是呼叫thekernel函式來執行linux核心的,uboot呼叫這個函式(其實就是linux核心)時傳遞了3個引數。這3個引數就是uboot直接傳遞給linux核心的3個引數,通過暫存器來實現傳參的。(第乙個引數就放在r0中,第二個引數放在r1中,第三個引數放在r2中)第乙個引數固定為0,第二個引數時機器碼,第三個引數傳遞的就是大片傳參tag的首位址。

U boot如何啟動核心

本文 我們用的u boot已經改的面目全非,不過核心還是完全相同的,換了個面目而已。開源的好處,想改就改來玩玩。不過流程還是人家的。u boot通過bootm命令來啟動核心,這個命令的處理函式是do bootm,這個函式處理的是uboot mkimage製作的映像,如果正好這個映像是核心,那麼它就會...

Uboot到底如何啟動核心

1.uboot 啟動核心的 縮減如下 uboot 1.16 lib arm board.c 中start armboot 函式呼叫 common main.c 中main loop 函式,在 main loop 中有uboot 啟動核心的 s getenv bootcmd debug main lo...

Uboot到底如何啟動核心

1.uboot啟動核心的 縮減如下 uboot 1.16 lib arm board.c中start armboot 函式呼叫 common main.c中main loop 函式,在main loop 中有uboot啟動核心的 s getenv bootcmd debug main loop bo...