uboot的一般性介绍
以下內容源于朱有鵬嵌入式課程的學習,如有侵權,請告知刪除。
一、uboot和內核的實質
1、uboot是一個裸機程序
- uboot的本質就是一個復雜點的裸機程序;
2、內核是一個裸機程序
- 操作系統內核也是一個裸機程序,和其他裸機程序并沒有本質區別。
- 區別是:操作系統運行起來后在軟件上分為內核層和應用層。分層后兩層的權限不同,內存訪問和設備操作的管理上更加精細(內核可以隨便訪問各種硬件,而應用程序只能被限制的訪問硬件和內存地址)。
3、均部署在SD卡中特定分區內
(1)一個完整的軟件+硬件的嵌入式系統
- 靜止時,bootloader、kernel、rootfs等都以鏡像的形式存儲在啟動介質中(X210中是iNand/SD卡)。
- 運行時,都是在DDR內存中運行的,與存儲介質無關。
- 從靜止態到運行態的過程,即啟動過程。
(2)動態啟動過程
- 一個從SD卡逐步搬移到DDR內存,并且運行啟動代碼進行相關的硬件初始化和軟件架構的建立,最終達到運行時穩定狀態的過程。
(3)靜止時u-boot.bin,zImage,rootfs都在SD卡中
- 不能隨意存在于SD卡的任意位置;
- 因此需要對SD卡進行一個分區,然后將各種鏡像各自存在各自的分區中,這樣在啟動過程中uboot、內核等就知道到哪里去找誰;
- uboot和kernel中的分區表必須一致,同時和SD卡的實際使用的分區要一致。
4、兩者運行時,都必須先加載到DDR中鏈接地址處
(1)uboot在第一階段中進行重定位時,將第二階段(整個uboot鏡像)加載到DDR的0xc3e00000地址處,這個地址就是uboot的鏈接地址。
(2)內核也有類似要求,uboot啟動內核時將內核從SD卡讀取放到DDR中(也是個重定位的過程),不能隨意放置,必須放在內核的鏈接地址處,否則啟動不起來。(這個見內核移植部分,因為解壓縮地址不是內核的鏈接地址,因此沒有正確解壓縮,內核運行不起來)
- 譬如我們使用的內核鏈接地址是0x30008000。
5、內核啟動需要必要的啟動參數
(1)uboot是無條件啟動的,從零開始啟動的;
(2)內核不能自動完全從零開始啟動,需要uboot幫忙。
- uboot要幫助內核實現重定位(從SD卡到DDR),uboot還要給內核提供啟動參數。
二、為什么要有uboot?
1、計算機系統的主要部件
- 典型的計算機系統有:PC機(臺式機+筆記本)、嵌入式設備(手機、平板電腦、游戲機)、單片機(家用電器像電飯鍋、空調);
- 所有的計算機系統運行時需要的主要核心部件都是3個東西:CPU + 外部存儲器(Flash/硬盤) + 內部存儲器(DDR SDRAM/SDRAM/SRAM)
- 典型的PC機的部署:BIOS程序部署在PC機主板上(隨主板出廠時已經預制了),操作系統部署在硬盤上,內存在掉電時無作用,CPU在掉電時不工作。
- 啟動過程:PC上電后先執行BIOS程序(實際上PC的BIOS就是NorFlash),BIOS程序負責初始化DDR內存,負責初始化硬盤,然后從硬盤上將OS鏡像讀取到DDR中,然后跳轉到DDR中去執行OS直到啟動(OS啟動后BIOS就無用了)。
- 典型嵌入式系統的部署:uboot程序部署在Flash(能作為啟動設備的Flash)上,OS部署在FLash(嵌入式系統中用Flash代替硬盤)上、內存在掉電時無作用,CPU在掉電時不工作。
- 啟動過程:嵌入式系統上電后先執行uboot、然后uboot負責初始化DDR,初始化Flash,然后將OS從Flash中讀取到DDR中,然后啟動OS(OS啟動后uboot就無用了)
4、總結
- 嵌入式系統和PC機的啟動過程幾乎沒有兩樣,只是BIOS成了uboot,硬盤成了Flash。
- android系統的啟動和linux系統(前面講的典型的嵌入式系統啟動)幾乎一樣,只是在內核啟動后加載根文件系統后不同了。
- 可以認為啟動分為2個階段:第一個階段是uboot到OS啟動;第二個階段是OS啟動后到rootfs加載到命令行執行。
- 現在我們主要研究第一個階段,android的啟動和linux的差別在第二階段。
- uboot主要作用是用來啟動操作系統內核。
- uboot還要負責部署整個計算機系統。
- uboot中還有操作Flash等板子上硬盤的驅動。
- uboot還得提供一個命令行界面供人來操作。
三、為什么是uboot?
1、uboot從哪里來的?
- uboot是SourceForge上的開源項目。
- uboot項目的作者:一個德國人最早發起的項目。
- uboot就是由一個人發起,然后由整個網絡上所有感興趣的人共同維護發展而來的一個bootloader。
- 自己使用的小開源項目。
- 被更多人認可使用。
- 被SoC廠商默認支持。
- uboot經過多年發展,已經成為事實上的業內bootloader標準。現在大部分的嵌入式設備都會默認使用uboot來做為bootloader。
- 早期的uboot的版本號類似于這樣:uboot1.3.4,后來版本號便成了類似于uboot-2010.06。
- uboot的核心部分幾乎沒怎么變化,越新的版本支持的開發板越多而已,對于一個老版本的芯片來說,新舊版本的uboot并沒有差異。
- uboot就是universal bootloader(通用的啟動代碼),通用的意思就是在各種地方都可以用,所以說uboot具有可移植性。
- uboot具有可移植性并不是說uboot在哪個開發板都可以隨便用,而是說uboot具有在源代碼級別的移植能力,可以針對多個開發板進行移植。
四、uboot必須解決哪些問題
1、自身可開機直接啟動- 一般的SoC都支持多種啟動方式,譬如SD卡啟動、NorFlash啟動、NandFlash啟動等。
- uboot要能夠開機啟動,必須根據具體的SoC的啟動設計來設計uboot。
- uboot必須進行和硬件相對應的代碼級別的更改和移植,才能夠保證可以從相應的啟動介質啟動。
- uboot中第一階段的start.S文件中具體處理了這一塊。
2、能夠引導操作系統內核啟動并給內核傳參
- uboot的終極目標就是啟動內核。
- linux內核在設計的時候,設計為可以被傳參。我們可以在uboot中事先給linux內核準備一些啟動參數,放在內存中特定位置然后傳給內核,內核啟動后會到這個特定位置去取這些參數,然后在內核中解析這些參數,這些參數將被用來指導linux內核的啟動過程。
3、能提供系統部署功能
- uboot必須能夠(被人借助而)完成整個系統(包括uboot、kernel、rootfs等的鏡像)在Flash上的燒錄下載工作。
- 裸機教程中刷機(ARM裸機第三部分)就是利用uboot中的fastboot功能將各種鏡像燒錄到iNand中,然后從iNand啟動。
4、能進行soc級和板級硬件管理
- uboot中實現了一部分硬件的控制能力(即uboot中初始化了一部分硬件),因為uboot為了完成一些任務必須讓這些硬件工作。
- 譬如uboot要實現刷機必須能驅動iNand,譬如uboot要在刷機時LCD上顯示進度條就必須能驅動LCD,譬如uboot能夠通過串口提供操作界面就必須驅動串口。譬如uboot要實現網絡功能就必須驅動網卡芯片。
- SoC級(譬如串口)就是SoC內部外設,板級就是SoC外面開發板上面的硬件(譬如網卡、iNand)
5、uboot的生命周期
- uboot的生命周期,指uboot什么時候開始運行,什么時候結束運行。
- uboot本質上是一個裸機程序(不是操作系統),一旦uboot開始SoC就會單純運行uboot,別的程序是不可能同時運行的,一旦uboot結束運行則無法再回到uboot。
- uboot的入口是開機自動啟動,uboot的唯一出口就是啟動內核。
- uboot還可以執行很多別的任務(譬如燒錄系統),一般任務執行完后都可以回到uboot的命令行,但啟動內核命令一旦執行就回不來了。
五、uboot的工作方式
1、從裸機程序鏡像uboot.bin說起
- uboot的本質就是一個裸機程序,和我們裸機全集中寫的那些裸機程序xx.bin并沒有本質區別。如果非說要有區別,那就是:我們寫的大部分小于16KB,而uboot大于16KB(一般uboot在180k-400k之間)。
- uboot本身是一個開源項目,由若干個.c文件和.h文件組成,配置編譯之后會生成一個uboot.bin,這就是uboot這個裸機程序的鏡像文件。然后這個鏡像文件被合理的燒錄到啟動介質中拿給SoC去啟動。也就是說uboot在沒有運行時表現為uboot.bin,一般躺在啟動介質中。
- uboot運行時會被加載到內存中然后一條指令一條指令的拿給CPU去運行。
2、uboot的命令式shell界面
- 普通的裸機程序運行起來就直接執行了,執行時效果和代碼有關。
- 有些程序需要和人進行交互,于是程序中就實現了一個shell(shell就是提供人機交互的一個界面),uboot就實現了一個shell。
- 注意:shell并不是操作系統,和操作系統一點關系都沒有。linux中打開一個終端后就得到了一個shell,可以輸入命令回車執行。uboot中的shell工作方式和linux中的終端shell非常像(其實幾乎是一樣的,只是命令集不一樣。譬如linux中可以ls,uboot中ls就不識別)
3、掌握uboot使用的2個關鍵點:命令和環境變量
- uboot啟動后大部分時間和工作都是在shell下完成的(譬如uboot部署系統要在shell下輸命令、要設置環境變量也得在命令行下,要啟動內核也要在命令行敲命令)
- 命令就是uboot的shell中可以識別的各種命令。uboot中有幾十個命令,其中有一些常用另一些不常用(我們還可以自己給uboot添加命令)。
- uboot的環境變量和操作系統的環境變量工作原理和方式幾乎完全相同。uboot在設計時借助了操作系統的設計理念(命令行工作方式借鑒了linux終端命令行,環境變量借鑒了操作系統的環境變量,uboot的驅動管理幾乎完全照抄了linux的驅動框架)。
- 環境變量可以被認為是系統的全局變量,環境變量名都是系統內置的(認識就認識,不認識就不認識,這部分是系統自帶的默認的環境變量,譬如PATH;但是也有一部分環境變量是自己添加的,自己添加的系統就不認識但是我們自己認識)。系統或者我們自己的程序在運行時可以通過讀取環境變量來指導程序的運行。這樣設計的好處就是靈活,譬如我們要讓一個程序更改運行方法,不用去重新修改程序代碼再重新編譯運行,而只要修改相應的環境變量就可以了。
- 環境變量就是運行時的配置屬性。
六、uboot的常用命令
1、類似linux終端的行緩沖命令行- 當我們向終端命令行輸入命令的時候,這些命令沒有立即被系統識別,而是被緩沖到一個緩存區(也就是系統認為我們還沒有輸入完),當我們按下回車鍵(換行)后系統就認為我們輸入完了,然后將緩沖區中所有剛才輸入的作為命令拿去分析處理。
- linux終端設計有3種緩沖機制:無緩沖、行緩沖、全緩沖
2、有些命令有簡化的別名
- 譬如printenv命令可以簡化為print,譬如setenv可以簡化為set
3、有些命令會帶參數(注意格式是固定的)
- uboot的每個命令都有事先規定好的各種格式。有些命令就是不帶參數的,譬如printenv/print命令;有些命令帶可選的參數(可以帶也可以不帶,當然帶不帶參數的執行結果是不同的);有些命令帶必須的參數(譬如setenv/set命令)
4、命令中的特殊符號(譬如單引號)
- uboot的有些命令帶的參數非常長,此時使用單引號把參數引起來。
5、有些命令是一個命令族(譬如movi)
- 命令族意思就是好多個命令開頭都是用同一個命令關鍵字的,但是后面的參數不一樣,這些命令的功能和作用也不同。這就叫一個命令族。
- 同一個命令族中所有的命令都有極大的關聯,譬如movi開頭的命令族都和moviNand(EMMC、iNand)操作有關。
6、第一個命令:printenv/print
- print命令不用帶參數,作用是打印出系統中所有的環境變量。
- 環境變量就好像程序的全局變量一樣。程序中任何地方都可以根據需要去調用或者更改環境變量(一般都是調用),環境變量和全局變量不同之處在于:全局變量的生命周期是在程序的一次運行當中,開始運行時誕生程序結束時死亡,下次運行程序時從頭開始;但是環境變量被存儲在Flash的另一塊專門區域(Flash上有一個環境變量分區),一旦我們在程序中保存了該環境變量,那么下次開機時該環境變量的值將維持上一次更改保存后的值。
7、設置(添加/更改)環境變量:setenv/set
- 用法:set name value
8、保存環境變量的更改:saveenv/save
- saveenv/save命令不帶參數,直接執行,作用是將內存中的環境變量的值同步保存到Flash中環境變量的分區。
- 注意:環境變量的保存是整體的覆蓋保存,也就是說內存中所有的環境變量都會整體的將Flash中環境變量分區中原來的內容整體覆蓋。
- 徹底更改一個環境變量的值,需要2步:第一步set命令來更改內存中的環境變量,第二步用save命令將其同步到Flash中環境變量的分區。
9、網絡測試指令:ping
- 命令用法: ping ip地址
- 注意:ping是測試開發板和主機之間的網絡鏈接。
10、tftp下載指令:tftp
(1)uboot主要目標是啟動內核,為了完成啟動內核必須要能夠部署內核,uboot為了部署內核就需要將內核鏡像從主機中下載過來然后燒錄到本地flash中。uboot如何從主機(windows或者虛擬機ubuntu)下載鏡像到開發板上?有很多種方式,主流方式是:fastboot和tftp。
- fastboot的方式是通過USB線進行數據傳輸。
- tftp的方式是通過有線網絡的。典型的方式就是通過網絡,fastboot是近些年才新發展的。
(2)tftp方式下載時實際上uboot扮演的是tftp客戶端程序角色,主機windows或虛擬機ubuntu中必須有一個tftp服務器,然后將要下載的鏡像文件放在服務器的下載目錄中,然后開發板中使用uboot的tftp命令去下載即可。
(3)虛擬機搭建的時候設置的tftp下載目錄是/tftpboot,將要被下載的鏡像復制到這個目錄下。
(4)檢查開發板uboot的環境變量,注意serverip必須設置為虛擬機ubuntu的ip地址。(serverip這個環境變量的意義就是主機tftp服務器的ip地址)
(5)然后在開發板的uboot下先ping通虛擬機ubuntu,然后再嘗試下載:tftp 0x30000000 zImage-qt
- 意思是將服務器上名為zImage-qt的文件下載到開發板內存的0x30000000地址處。
(6)鏡像下載到開發板的DDR中后,uboot就可以用movi指令進行鏡像的燒寫了。
11、nfs啟動內核命令:nfs
12、SD卡/iNand操作指令movi
(1)開發板如果用SD卡/EMMC/iNand等作為Flash,則在uboot中操作flash的指令為movi(或mmc)
(2)movi指令是一個命令集,有很多子命令,具體用法可以help movi查看。
(3)movi的指令都是movi read和movi write一組的
- movi read用來讀取iNand到DDR上,movi write用來將DDR中的內容寫入iNand中。
- 理解這些指令時一定要注意涉及到的2個硬件:iNand和DDR內存。
(4)movi read ?{u-boot | kernel} {addr} ??
- 這個命令使用了一種通用型的描述方法來描述:movi 和 read外面沒有任何標記說明每一次使用這個指令都是必選的;一對大括號{}括起來的部分必選1個,大括號中的豎線表是多選一。中括號[]表示可選參數(可以有也可以沒有)
- 譬如 movi read u-boot 0x30000000,意思就是把iNand中的u-boot分區讀出到DDR的0x30000000起始的位置處。
- uboot代碼中將iNand分成了很多個分區,每個分區有地址范圍和分區名,uboot程序操作中可以使用直接地址來操作iNand分區,也可以使用分區名來操作分區。
- 注意這里的0x30000000也可以直接寫作30000000,意思是一樣的(uboot的命令行中所有數字都被默認當作十六進制處理,不管你加不加0x都一樣)。
13、NandFlash操作指令nand
- 理解方法和操作方法完全類似于movi指令
14、內存操作指令:mm、mw、md
- DDR中是沒有分區的(只聽說過對硬盤、Flash進行分區,沒聽說過對內存進行分區……),但是內存使用時要注意,千萬不能越界踩到別人了。
- 因為uboot是一個裸機程序,不像操作系統會由系統整體管理所有內存,系統負責分配和管理,系統會保證內存不會隨便越界。
- uboot并不管理所有內存,內存是散的隨便用的,所以如果使用uboot的人不注意就可能出現自己把自己的數據給覆蓋了。
- md就是memory display,用來顯示內存中的內容。
- mw就是memory write,將內容寫到內存中
- mm就是memory modify,修改內存中的某一塊,說白了還是寫內存(如果需要批量的逐個單元的修改內存,用mm最合適)
15、啟動內核指令:bootm、go
- uboot的終極目標就是啟動內核,啟動內核在uboot中表現為一個指令,uboot命令行中調用這個指令就會啟動內核(不管成功與否,所以這個指令是一條死路)。
- 差別:bootm啟動內核同時給內核傳參,而go命令啟動內核不傳參。
- bootm其實才是正宗的啟動內核的命令,一般情況下都用這個。
- go命令本來不是專為啟動內核設計的,go命令內部其實就是一個函數指針指向一個內存地址然后直接調用那個函數,go命令的實質就是PC直接跳轉到一個內存地址去運行而已。
- go命令可以用來在uboot中執行任何的裸機程序(有一種調試裸機程序的方法就是事先啟動uboot,然后在uboot中去下載裸機程序,用go命令去執行裸機程序)。
七、uboot的常用環境變量
1、如何理解環境變量?
2、環境變量如何參與程序運行?
- 環境變量有2份,一份在Flash中,另一份在DDR中。uboot開機時一次性從Flash中讀取全部環境變量到DDR中作為環境變量的初始化值,然后使用過程中都是用DDR中這一份,用戶可以用saveenv指令將DDR中的環境變量重新寫入Flash中去更新Flash中環境變量。下次開機時又會從Flash中再讀一次。
- 環境變量在uboot中是用字符串表示的,也就是說uboot是按照字符匹配的方式來區分各個環境變量的。因此用的時候一定要注意不要打錯字了。
3、自動運行倒數時間:bootdelay
4、網絡設置:ipaddr serverip ……
(1)ipaddr是開發板的本地IP地址
(2)serverip是開發板通過tftp指令去tftp服務器下載東西時,tftp服務器的IP地址。
(3)gatewayip是開發板的本地網關地址
(4)netmask是子網掩碼
(5)ethaddr是開發板的本地網卡的MAC地址。
5、自動運行命令設置:bootcmd
(1)uboot啟動后會開機自動倒數bootdelay秒,如果沒有人按下回車打斷啟動,則uboot會自動執行啟動命令來啟動內核。
(2)uboot開機自動啟動時實際就是在內部執行了bootcmd這個環境變量的值所對應的命令集。
(3)bootcmd=movi read kernel 30008000; bootm 30008000 ??
- 意思是:將iNand的kernel分區讀取到DDR內存的0x30008000地址處,然后使用bootm啟動命令從內存0x30008000處去啟動內核。
- set bootcmd printenv,然后saveenv;然后重啟則會看到啟動倒數后自動執行printenv命令打印出環境變量。這個小實驗說明開機自動執行了bootcmd。
6、uboot給kernel傳參:bootargs
(1)linux內核啟動時可以接收uboot傳遞的啟動參數,這些啟動參數是uboot和內核約定好的形式、內容,linux內核在這些啟動參數的指導下完成啟動過程。
(2)我們要做的事情就是:在uboot的環境變量中設置bootargs,然后bootm命令啟動內核時會自動將bootargs傳給內核。
(3)bootargs=console=ttySAC2,115200 root=/dev/mmcblk0p2 rw init=/linuxrc rootfstype=ext3意義解釋:
- console=ttySAC2,115200 ,控制臺使用串口2,波特率115200
- root=/dev/mmcblk0p2?rw,根文件系統在SD卡端口0設備(iNand)第2分區,根文件系統是可讀可寫的
- init=/linuxrc,linux的進程1(init進程)的路徑
- rootfstype=ext3,根文件系統的類型是ext3
(4)內核傳參非常重要。在內核移植的時候,新手經常因為忘記給內核傳參,或者給內核傳遞的參數不對,造成內核啟動不起來。
7、新建、更改、刪除一個環境變量的方法
(1)新建一個環境變量,使用set var value
(2)更改一個環境變量,使用set var value
(3)刪除一個環境變量,使用set var
八、uboot中對Flash和DDR的管理
1、uboot階段Flash的分區
(1)所謂分區,就是說對Flash進行分塊管理。
(2)PC機等產品中,因為大家都是在操作系統下使用硬盤的,整個硬盤由操作系統統一管理,操作系統會使用文件系統幫我們管理硬盤空間。(管理保證了文件之間不會互相堆疊),使用者不用自己太過在意分區問題。
(3)在uboot中沒有操作系統,因此我們對Flash(相當于硬盤)的管理必須事先使用分區界定
- 實際上在uboot中和kernel中都有個分區表,分區表就是我們在做系統移植時對Flash的整體管理分配方法。
- 有了這個界定后,我們在部署系統時按照分區界定方法來部署,uboot和kernel的軟件中也是按照這個分區界定來工作,就不會錯。
(4)分區方法不是一定的,不是固定的,是可以變動的。但是在一個移植中必須事先設計好定死,一般在設計系統移植時就會定好,定的標準是:
- uboot必須從Flash起始地址開始存放(也許是扇區0,也許是扇區1,也許是其他,取決于SoC的啟動設計);
- uboot分區的大小必須保證uboot肯定能放下,一般設計為512KB或者1MB(因為一般uboot肯定不足512KB,給再大其實也可以工作,但是浪費);
- 環境變量:環境變量分區一般緊貼著uboot來存放,大小為32KB或者更多一點。
- kernel:kernel可以緊貼環境變量存放,大小一般為3MB或5MB或其他。
- rootfs:······
- 剩下的就是自由分區,一般kernel啟動后將自由分區掛載到rootfs下使用
(5)總結
- 各分區彼此相連,前面一個分區的結尾就是后一個分區的開頭。
- 整個flash充分利用,從開頭到結尾。
- uboot必須在Flash開頭,其他分區相對位置是可變的。
- 各分區的大小由系統移植工程師自己來定,一般定為合適大小(不能太小,太小了容易溢出;不能太大,太大了浪費空間)
- 分區在系統移植前確定好,在uboot中和kernel中使用同一個分區表。將來在系統部署時和系統代碼中的分區方法也必須一樣。
2、uboot階段DDR的分區
(1)DDR的分區和Flash的分區不同,主要是因為Flash是掉電存在的,而DDR是掉電消失,因此可以說DDR是每次系統運行時才開始部署使用的。
(2)內存的分區主要是在linux內核啟動起來之前,linux內核啟動后內核的內存管理模塊會接管整個內存空間,那時候就不用我們來管了。
(3)內存分區關鍵在于,內存中哪一塊用來干什么必須分配好,以避免各個不同功能使用了同一塊內存造成的互相踩踏。
- 譬如說我們tftp 0x23E00000 zImage去下載zImage到內存的0x23E00000處就會出錯,因為這個內存處實際是uboot的鏡像所在。這樣下載會導致下載的zImage把內存中的uboot給沖掉。
總結
以上是生活随笔為你收集整理的uboot的一般性介绍的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【无标题】计算机一级考试MS OFFIC
- 下一篇: android 软件盘弹回去的最好体验,