1. 前言
Linux kernel在ARM架構中引入device tree(全稱是flattened device tree,后續將會以FDT代稱)的時候[1],其實懷揣了一個Unify Kernel的夢想----同一個Image,可以支持多個不同的平臺。隨著新的ARM64架構將FDT列為必選項,并將和體系結構有關的代碼剝離之后,這個夢想已經接近實現:
在編譯linux kernel的時候,不必特意的指定具體的架構和SOC,只需要告訴kernel本次編譯需要支持哪些板級的platform即可,最終將會生成一個Kernel image,以及多個和具體的板子(哪個架構、哪個SOC、哪個版型)有關的FDT image(dtb文件)。
bootloader在啟動的時候,根據硬件環境,加載不同的dtb文件,即可使linux kernel運行在不同的硬件平臺上,從而達到unify kernel的目標。
本文將基于嵌入式產品中普遍使用的u-boot,以其新的uImage格式(FIT image,Flattened uImage Tree)為例,介紹達到此目標的步驟,以及背后的思考和意義。
2. Legacy uImage
從u-boot的角度看,它要boot一個二進制文件(例如kernel Image),需要了解該文件的一些信息,例如:
該文件的類型,如kernel image、dtb文件、ramdisk image等等?
該文件需要放在memory的哪個位置(加載地址)?
該文件需要從memory哪個位置開始執行(執行地址)?
該文件是否有壓縮?
該文件是否有一些完整性校驗的信息(如CRC)?
等等
結合“X-010-UBOOT-使用booti命令啟動kernel(Bubblegum-96平臺)”中有關booti的例子,上面信息被隱含在我們的命令行中了,例如:
通過DFU工具,將指定的image文件下載到指定的memory地址,間接的指定了二進制文件加載地址;
booti命令本身,說明加載的文件類型是ARM64平臺的Image文件;
通過booti的參數,可以指定Kernel Image、ramdisk、DTB文件的執行位置;
等等。
不過,這種做法缺點很明顯(總結來說,就是太啰嗦了):
需要往memory中搬不同的二進制文件(Kernel、DTB、ramdisk等);
boot指令(booti等)有比較復雜的參數;
無法靈活地處理二進制文件的校驗、解壓縮等操作;
等等。
為了解決上述缺點,u-boot自定義了一種Image格式----uImage。最初的時候,uImage的格式比較簡單,就是為二進制文件加上一個header(具體可參考“include/image.h”中的定義),標示該文件的特性。然后在boot該類型的Image時,從header中讀取所需的信息,按照指示,進行相應的動作即可。這種原始的Image格式,稱作Legacy uImage,其特征可總結為:
1)使用mkimage工具(位于u-boot source code的tools/mkimage中)生成。
2)支持OS Kernel Images、RAMDisk Images等多種類型的Image。
3)支持gzip、bzip2等壓縮算法。
4)支持CRC32 checksums。
5)等等。
最后,之所以稱作Legacy,說明又有新花樣了,這種舊的方式,我們就不再過多關注了,擁抱新事物去吧。
3. FIT uImage
3.1 簡介
device tree在ARM架構中普及之后,u-boot也馬上跟進、大力支持,畢竟,美好的Unify kernel的理想,需要bootloader的成全。為了支持基于device tree的unify kernel,u-boot需要一種新的Image格式,這種格式需要具備如下能力:
1)Image中需要包含多個dtb文件。
2)可以方便的選擇使用哪個dtb文件boot kernel。
綜合上面的需求,u-boot推出了全新的image格式----FIT uImage,其中FIT是flattened image tree的簡稱。是不是覺得FIT和FDT(flattened device tree)有點像?沒錯,它利用了Device Tree Source files(DTS)的語法,生成的image文件也和dtb文件類似(稱作itb),下面我們會詳細描述。
3.2 思路
為了簡單,我們可以直接把FIT uImage類比為device tree的dtb文件,其生成和使用過程為[2]:
image source file??????? mkimage + dtc?????????????????????????? transfer to target?
?????????? +??????????????? -----------------------------> image file -----------------------------------> bootm?
image data file(s)
其中image source file(.its)和device tree source file(.dts)類似,負責描述要生成的image file的信息(上面第2章描述的信息)。mkimage和dtc工具,可以將.its文件以及對應的image data file,打包成一個image file。我們將這個文件下載到么memory中,使用bootm命令就可以執行了。
3.3 image source file的語法
image source file的語法和device tree source file完全一樣(可參考[3][4][5]中的例子),只不過自定義了一些特有的節點,包括images、configurations等。說明如下:
1)images節點
指定所要包含的二進制文件,可以指定多種類型的多個文件,例如multi.its[5]中的包含了3個kernel image、2個ramdisk image、2個fdt image。每個文件都是images下的一個子node,例如:
kernel@2 {?
??? description = "2.6.23-denx";?
??? data = /incbin/("./2.6.23-denx.bin.gz");?
??? type = "kernel";?
??? arch = "ppc";?
??? os = "linux";?
??? compression = "gzip";?
??? load = <00000000>;?
??? entry = <00000000>;?
??? hash@1 {?
??????? algo = "sha1";?
??? };?
};
可以包括如下的關鍵字:
description,描述,可以隨便寫;
data,二進制文件的路徑,格式為----/incbin/("path/to/data/file.bin");
type,二進制文件的類型,"kernel", "ramdisk", "flat_dt"等,具體可參考中[6]的介紹;
arch,平臺類型,“arm”, “i386”等,具體可參考中[6]的介紹;
os,操作系統類型,linux、vxworks等,具體可參考中[6]的介紹;
compression,二進制文件的壓縮格式,u-boot會按照執行的格式解壓;
load,二進制文件的加載位置,u-boot會把它copy對應的地址上;
entry,二進制文件入口地址,一般kernel Image需要提供,u-boot會跳轉到該地址上執行;
hash,使用的數據校驗算法。
2)configurations
可以將不同類型的二進制文件,根據不同的場景,組合起來,形成一個個的配置項,u-boot在boot的時候,以配置項為單位加載、執行,這樣就可以根據不同的場景,方便的選擇不同的配置,實現unify kernel目標。還以multi.its[5]為例,
configurations {?
??? default = "config@1";?
???? config@1 {?
???????? description = "tqm5200 vanilla-2.6.23 configuration";?
???????? kernel = "kernel@1";?
???????? ramdisk = "ramdisk@1";?
??????? fdt = "fdt@1";?
???? };?
???? config@2 {?
???????? description = "tqm5200s denx-2.6.23 configuration";?
???????? kernel = "kernel@2";?
???????? ramdisk = "ramdisk@1";?
???????? fdt = "fdt@2";?
??? };?
?????config@3?{?
???????? description = "tqm5200s denx-2.4.25 configuration";?
??????? kernel = "kernel@3";?
???????? ramdisk = "ramdisk@2";?
???? };?
};
它包含了3種配置,每種配置使用了不同的kernel、ramdisk和fdt,默認配置項由“default”指定,當然也可以在運行時指定。
3.4 Image的編譯和使用
FIT uImage的編譯過程很簡單,根據實際情況,編寫image source file之后(假設名稱為kernel_fdt.its),在命令行使用mkimage工具編譯即可:
$ mkimage -f kernel_fdt.its?kernel_fdt.itb
其中-f指定需要編譯的source文件,并在后面指定需要生成的image文件(一般以.itb為后綴,例如kernel_fdt.itb)。
Image文件生成后,也可以使用mkimage命令查看它的信息:
$ mkimage -l kernel.itb
最后,我們可以使用dfu工具將生成的.idb文件,下載的memory的某個地址(沒有特殊要求,例如0x100000),然后使用bootm命令即可啟動,步驟包括:
1)使用iminfo命令,查看memory中存在的images和configurations。
2)使用bootm命令,執行默認配置,或者指定配置。
使用默認配置啟動的話,可以直接使用bootm:
bootm 0x100000
選擇其它配置的話,可以指定配置名:
bootm 0x100000#config@2
以上可參考“doc/uImage.FIT/howto.txt[2]”,具體細節我們會在后續的文章中結合實例說明。
4. 總結
本文簡單的介紹了u-boot為了實現Unify kernel所做的努力,但有一個問題,大家可以思考一下:bootloader的unify怎么保證呢?
SOC廠家提供(固化、提供二進制文件等)?
格式統一,UEFI?
后面有時間的話,可以追著這個疑問研究研究。
?
評論
查看更多