Linux內核DTB文件啓動的幾種方式

 
版權:  凌雲物網智科實驗室< www.iot-yun.com >
聲明:  本文檔由凌雲物網智科實驗室郭工編著!
做者:  郭文學< QQ: 281143292   guowenxue@gmail.com
版本:  v1.0.0
 
1. Device Tree簡介
 
  Linus Torvalds在2011年3月17日的ARM Linux郵件列表宣稱「this whole ARM thing is a fucking pain in the ass」,引起ARM Linux社區的地震,隨後ARM社區進行了一系列的重大修正。在過去的ARM Linux中,arch/arm/plat-xxx和arch/arm/mach-xxx中充斥着大量的垃圾代碼,至關多數的代碼只是在描述板級細節,而這些板級細節對於內核來說,不過是垃圾,如板上的platform設備、resource、i2c_board_info、spi_board_info以及各類硬件的platform_data。 社區必須改變這種局面,因而PowerPC等其餘體系架構下已經使用的Flattened Device Tree(FDT)進入ARM社區的視野。Device Tree是一種描述硬件的數據結構,它起源於OpenFirmware(OF)。在Linux2.6中,ARM架構的板極硬件細節過多地被硬編碼在arch/arm/plat-xxx和arch/arm/mach-xxx,採用Device Tree後,許多硬件的細節能夠直接透過它傳遞給Linux,而再也不須要在kernel中進行大量的冗餘編碼。
 
Device Tree由一系列被命名的結點(node)和屬性(property)組成,而結點自己可包含子結點。所謂屬性,其實就是成對出現的name和value。在Device Tree中,可描述的信息包括(原先這些信息大多被hard code到kernel中):
 
  • CPU的數量和類別
  • 內存基地址和大小
  • 總線和橋
  • 外設鏈接
  • 中斷控制器和中斷使用狀況
  • GPIO控制器和GPIO使用狀況
 
它基本上就是畫一棵電路板上CPU、總線、設備組成的樹,Bootloader會將這棵樹傳遞給內核,而後內核能夠識別這棵樹,並根據它展開出Linux內核中的platform_device、i2c_client、spi_device等設備。這些設備用到的內存、IRQ等資源,也被傳遞給了kernel,kernel會將這些資源綁定給展開的相應的設備。
 
 
2. Device Tree編譯
 
Device Tree文件的格式爲dts,包含的頭文件格式爲dtsi,dts文件是一種人能夠看懂的編碼格式。可是uboot和linux不能直接識別,他們只能識別二進制文件,因此須要把dts文件編譯成dtb文件。dtb文件是一種能夠被kernel和uboot識別的二進制文件。把dts編譯成dtb文件的工具是dtc。Linux源碼目錄下scripts/dtc目錄包含dtc工具的源碼。在Linux的scripts/dtc目錄下除了提供dtc工具外,也能夠本身安裝dtc工具,linux下執行:sudo apt-get install device-tree-compiler安裝dtc工具。其中還提供了一個fdtdump的工具,能夠反編譯dtb文件。dts和dtb文件的轉換如圖1所示。
dtc工具的使用方法是:dtc –I dts –O dtb –o xxx.dtb xxx.dts,便可生成dts文件對應的dtb文件了。
 
 
 
3.  早期Linux內核啓動
 
   早期的Linux內核(Linux-3.0之前)裏的設備信息(platform_device)和驅動信息(platform_driver)都是經過C代碼硬寫入到Linux內核裏去了,這些源文件都在arch/arm/mach-xxx或plat-xxx下:
 
 
例如咱們移植Linux內核代碼到FL2440開發板時,就會在設備文件 arch/arm/mach-s3c2440/mach-smdk2440.c中做大量修改的,該文件就描述了開發板上全部的設備信息。
 
 
咱們在編譯Linux內核源碼以後會生成zImage文件,該文件並不能直接被u-boot啓動。以後須要使用u-boot裏的mkimage工具生成uImage。
 
 
在將zImage轉換成uImage文件後,咱們在u-boot下就能夠直接使用tftp 下載並經過bootm 命令啓動Linux內核了。
 
U-Boot> tftp 30008000 linuxrom-s3c2440.bin && bootm 30008000
 
   在前些年咱們玩ARM Linux時大可能是使用的這種方法。但自從Linus大神發飆以後, ARM社區幾乎「一晚上」之間將 arch/arm/mach-xxx 或 arch/arm/plat-xxx的代碼所有廢除,並再也不支持。這也就是使用像S3C2440這樣的開發板,最高Linux內核版本只能到Linux-3.0的緣由。而最新的內核中全部硬件信息都必須經過arch/arm/boot/dts中的DTS(Device Tree Source)文件來描述。這樣若是S3C2440想要升級到更高版本的Linux話,就必須本身重寫S3C2440的DTS文件,固然不多有人願意爲一個停產的CPU作這些無用功的。
 
 
4.  設備樹啓動
 
   Linux-3.x以後的內核統一啓用Device Tree機制以後,全部的設備硬件信息描述都會放到 arch/arm/boot/dts/ 路徑下的 xxx.dts文件中描述。這些dts(Device Tree Source)文件並非C代碼,而是具備相應語法格式的源文件。在編譯內核時,咱們可使用 make dtbs 命令編譯生成相應開發板的dtb(Device Tree Blob)文件。由於這些源文件並非C程序,因此不是用gcc來編譯,而是由其相應的編譯工具dtc(Device Tree Compiler)來編譯。
 
 
  以下面我對Atmel SAMA5D44開發板移植Linux內核的編譯過程和結果:
 
 
很顯然,這裏Linux內核uImage文件中只包含了Linux內核驅動相關的信息,而全部的設備硬件信息都在編譯生成的at91-sama5d4_xplained.dtb設備樹文件中。這也就意味着u-boot在啓動時只有uImage是不夠的,而是兩個文件都須要。對於這種狀況,u-boot在啓動時須要這兩個文件,同時bootm命令裏還要指定它們加載到內存中的地址。以下所示:
 
 
 
5  設備樹和uImage合併
 
  參考上面的例子咱們能夠看到,在這裏使用dtb文件會有一個很大的好處,即經過dtb文件將設備的硬件信息和Linux內核分離開了。這樣也就意味着咱們只須要編譯一個Linux內核,而後加載不一樣的dtb文件,就能夠爲不一樣的硬件開發板服務了。譬如在上面的例子中,我使用同一個內核uImage,若是我想在Atmel的SAMA5D4 Xplained開發板上運行就只須要加載dtb文件at91-sama5d4_xplained.dtb便可; 而若是咱們想啓動開發板SAMA5D3 Xplained的話,只須要將DTB文件更新爲at91-sama5d3_xplained.dtb便可,而不需更新uImage。這爲從此的產品升級換代提供了很大的便利。
 
  但嵌入式是一個軟硬件高度定製的產品,咱們通常不多使用這種特性。由於在生產時Linux系統內核要提供兩個文件(uImage和dtb)並下載燒錄,顯得有點繁瑣,這時咱們更多地是但願將dtb和uImage打包到一個image中燒錄啓動。這時候能夠分別經過Linux內核和u-boot來實現:
 
5.1  Linux內核append DTB
 
   之因此Linux內核會提供這種方式是由於不少廠家都有本身的bootloader,可是這些bootloader並不都必定支持設備樹,爲了實現支持設備樹啓動,就引入了這種啓動方式,即將編譯出的zImage和編譯出的設備樹鏡像文件拼成一個新的鏡像,在內核的自解壓代碼中會識別到,不會出現自解壓時致使設備樹被覆蓋。2016年在本人深圳消安作的一個LoRa物聯網網關產品使用的Atmel的處理器AT91SAM9X35+Linux-4.1內核,在該內核代碼中就是經過內核裏支持的功能來合併uImage和dtb文件的。具體的實現方式是:
 
首先在內核 make menuconfig的「 Boot options  --->」選項裏要選擇:
 
 
在編譯Linux內核生成uImage和dtb文件以後,使用cat命令將他們合併,而後再使用mkimage命令生成u-boot啓動相關的uImage文件:
 
guowenxue@ubuntu-master: ~/linux-at91-linux4sam_5.3$  cat arch/arm/boot/dts/at91sam9x35ek.dtb >> arch/arm/boot/zImage
guowenxue@ubuntu-master: ~/linux-at91-linux4sam_5.3$  mkimage -A arm -O linux -n AT91SAM9X35EK -C NONE -a 0x20008000 -e 0x20008000 -d arch/arm/boot/zImage linuxrom-sam9x35ek.bin
guowenxue@ubuntu-master: ~/linux-at91-linux4sam_5.3$  chmod a+x linuxrom-sam9x35ek.bin
            
這樣,在u-boot裏直接下載生成的uImage文件啓動便可。
 
U-Boot> tftp 22000000 linuxrom-sam9x35ek.bin && bootm 22000000
          
 
5.2  u-boot FIT image合併
 
  最近接的馬來西亞CoherentPlus的一個NFC支付讀卡器項目,選用Atmel的Cortex A5處理器SAMA5D44,所使用的是Linux-4.9和U-Boot 2014.07。一樣嘗試上面SAM9X35的套路打包uImage和dtb文件並啓動Linux內核時失敗,U-boot啓動時提示以下錯誤。畢竟如今已是9102年了,在這裏沒有太大興趣研究這種老的打包方式,而轉向u-boot的全興工做方式FIT Image。
 
 
  咱們知道,Linux kernel在ARM架構中引入device tree(全稱是Flattened Device Tree,後續將會以FDT代稱)的時候,其實懷揣了一個Unify Kernel的夢想----同一個Image,能夠支持多個不一樣的平臺。隨着新的ARM64架構將FDT列爲必選項,並將和體系結構有關的代碼剝離以後,這個夢想已經接近實現。Device Tree在ARM架構中普及以後,u-boot也立刻跟進、大力支持,畢竟,美好的Unify kernel的理想,須要bootloader的成全。爲了支持基於device tree的unify kernel,u-boot須要一種新的Image格式,這種格式須要具有以下能力:
  1. Image中須要包含多個dtb文件;
  2. 能夠方便的選擇使用哪一個dtb文件boot kernel;
 
  是否是這樣就感受跟Linux內核同樣Niubility了?沒錯!要的就是這種感受。綜合上面的需求,u-boot推出了全新的image格式----FIT uImage,其中FIT是flattened image tree的簡稱。它利用了Device Tree Source files(DTS)的語法,生成的image文件也和dtb文件相似(稱做itb),下面是咱們項目中的示例代碼。:
 
guowenxue@ubuntu-master:~/sama5d4-sdk/linux-bsp/linux-at91$ cat linuxrom-sama5d4.its
 
/* U-Boot uImage source file for "sama5d4_xplained" */
/dts-v1/;
/ {
    description = "U-Boot uImage source file for SAMA5D4 Xplained";
    #address-cells = <1>;

    images {

        kernel@sama5d4 {
            description = "Linux kernel for SAMA5D4 Xplained";
            data = /incbin/("arch/arm/boot/zImage");
            type = "kernel";
            arch = "arm";
            os = "linux";
            compression = "none";
            load = <0x20008000>;
            entry = <0x20008000>;
        };

        fdt@sama5d4 {
            description = "Flattened Device Tree blob for SAMA5D4 Xplained";
            data = /incbin/("arch/arm/boot/dts/at91-sama5d4_xplained.dtb");
            type = "flat_dt";
            arch = "arm";
            compression = "none";
        };
    };

    configurations {
        default = "conf@sama5d4";
        conf@sama5d4 {
            description = "Boot Linux kernel with FDT blob";
            kernel = "kernel@sama5d4";
            fdt = "fdt@sama5d4";
        };
    };
};

 

 上面的代碼是否是很眼熟?沒錯,就是跟Linux內核樹裏的DTS文件語法同樣,裏面的一些參數就是mkimage製做uImage時的一些參數。在編譯生成Linux內核zImage和dtb文件以後,咱們只須要使用mkimage命令就能夠生成相應的itb文件了。固然,上面的文件遵循dts語法,那他的編譯就須要dtc編譯器,默認ubuntu並無安裝該命令,因此在使用以前還得安裝相應的命令,好在ubuntu下都提供了,若是沒有能夠在u-boot或linux內核下去找:
 
guowenxue@ubuntu-master:~/sama5d4-sdk/linux-bsp/linux-at91$ sudo apt-get install u-boot-tools device-tree-compiler
guowenxue@ubuntu-master:~/sama5d4-sdk/linux-bsp/linux-at91$ mkimage -f linuxrom-sama5d4.its linuxrom-sama5d4.itb
 
FIT description: U-Boot uImage source file for SAMA5D4 Xplained
Created:         Fri Aug 23 21:43:12 2019

Image 0 (kernel@sama5d4)
  Description:  Linux kernel for SAMA5D4 Xplained
  Created:      Fri Aug 23 21:43:12 2019
  Type:         Kernel Image
  Compression:  uncompressed
  Data Size:    4879744 Bytes = 4765.38 kB = 4.65 MB
  Architecture: ARM
  OS:           Linux
  Load Address: 0x20008000
  Entry Point:  0x20008000

Image 1 (fdt@sama5d4)
  Description:  Flattened Device Tree blob for SAMA5D4 Xplained
  Created:      Fri Aug 23 21:43:12 2019
  Type:         Flat Device Tree
  Compression:  uncompressed
  Data Size:    32670 Bytes = 31.90 kB = 0.03 MB
  Architecture: ARM

Default Configuration: 'conf@sama5d4'
Configuration 0 (conf@sama5d4)
  Description:  Boot Linux kernel with FDT blob
  Kernel:       kernel@sama5d4
  FDT:          fdt@sama5d4
 
既然是全新的東西,u-boot默認並不必定支持。若是要U-boot支持FIT Image啓動的話,咱們還得在u-boot的配置文件中添加它的支持,即加上 CONFIG_FIT 宏定義便可:
 
guowenxue@ubuntu-master:~/sama5d4-sdk/linux-bsp/u-boot-at91$ vim include/configs/sama5d4_xplained.h
 
/* add by guowenxue, 2019.08.22 */
#define CONFIG_FIT              1
#define CONFIG_ENV_OVERWRITE    1
#define CONFIG_ETHADDR          42:96:ab:be:a7:5e
#define CONFIG_IPADDR           192.168.2.199
#define CONFIG_SERVERIP         192.168.2.2
 
編譯升級u-boot以後,咱們則能夠直接啓動該itb文件了。啓動過程以下所示:
 
 
 
 
6  PS:
 
   本文檔主要是講解Linux內核設備樹的使用,並不涉及到Device Tree Source的語法和原理,若是有須要的請自行百度、參考Linux內核裏的設備樹文件學習。
相關文章
相關標籤/搜索