1. 程式人生 > >[uboot] uboot啟動kernel篇(一)——Legacy-uImage & FIT-uImage

[uboot] uboot啟動kernel篇(一)——Legacy-uImage & FIT-uImage

一、uImage

編譯kernel之後,會生成Image或者壓縮過的zImage。但是這兩種映象的格式並沒有辦法提供給uboot的足夠的資訊來進行load、jump或者驗證操作等等。因此,uboot提供了mkimage工具,來將kernel製作為uboot可以識別的格式,將生成的檔案稱之為uImage。  uboot支援兩種型別的uImage。

  • Legacy-uImage  在kernel映象的基礎上,加上64Byte的資訊提供給uboot使用。

  • FIT-uImage  以類似FDT的方式,將kernel、fdt、ramdisk等等映象打包到一個image file中,並且加上一些需要的資訊(屬性)。uboot只要獲得了這個image file,就可以得到kernel、fdt、ramdisk等等映象的具體資訊和內容。

Legacy-uImage實現較為簡單,並且長度較小。但是實際上使用較為麻煩,需要在啟動kernel的命令中額外新增fdt、ramdisk的載入資訊。  而FIT-uImage實現較為複雜,但是使用起來較為簡單,相容性較好,(可以相容多種配置)。但是需要的額外資訊也較長。

二、Legacy-uImage

1、使能需要開啟的巨集

CONFIG_IMAGE_FORMAT_LEGACY=y

注意,這個巨集在自動生成的autoconf.mk中會自動配置,不需要額外配置。

2、如何製作 & 使用

(1)工具mkimage  編譯完uboot之後會在uboot的tools目錄下生成mkimage可執行檔案  (2)命令

mkimage -A arm -O linux -C none -T kernel -a 0x20008000 -e 0x20008040 -n Linux_Image -d zImage uImage 

各個引數意義如下
Usage: mkimage -l image
          -l ==> list image header information
       mkimage [-x] -A arch -O os -T type -C comp -a addr -e ep -n name -d data_file[:data_file...] image
          -A ==> set architecture to 'arch'  // 體系
          -O ==> set operating system to 'os' // 作業系統
          -T ==> set image type to 'type' // 映象型別
          -C ==> set compression type 'comp' // 壓縮型別
          -a ==> set load address to 'addr' (hex) // 載入地址
          -e ==> set entry point to 'ep' (hex) // 入口地址
          -n ==> set image name to 'name' // 映象名稱,注意不能超過32B
          -d ==> use image data from 'datafile' // 輸入檔案
          -x ==> set XIP (execute in place) 

(3)使用  將生成的Legacy-uImage下載到引數中指定的load address中,使用bootm ‘實際load address’命令跳轉到kernel中。  但是注意,如果使用Legacy-uImage後面還需要跟上檔案系統的ram地址以及dtb的ram地址,否則可能會導致bootm失敗。  格式如下:

bootm Legacy-uImage載入地址 ramdisk載入地址 dtb載入地址

3、和zImage的區別

-rw-rw-rw-  1 hlos hlos 1560120 Dec  5 14:46 uImage
-rwxrwxrwx  1 hlos hlos 1560056 Nov 30 15:42 zImage*

可以看出uImage比zImage多了64Byte,通過對比可以發現這64Byte的資料是載入zImage的頭部的。  直接檢視這64Byte的資料,通過od命令檢視如下:

[email protected]:boot$ od -tx1 -tc -Ax -N64 uImage
000000  27  05  19  56  5a  f3  f7  8e  58  45  0d  3d  00  17  cd  f8
         ' 005 031   V   Z 363 367 216   X   E  \r   =  \0 027 315 370
000010  20  00  80  00  20  00  80  40  e2  4b  43  b6  05  02  02  00
            \0 200  \0      \0 200   @ 342   K   C 266 005 002 002  \0
000020  4c  69  6e  75  78  5f  49  6d  61  67  65  00  00  00  00  00
         L   i   n   u   x   _   I   m   a   g   e  \0  \0  \0  \0  \0
000030  00  00  00  00  00  00  00  00  00  00  00  00  00  00  00  00
        \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0

Legacy-uImage是在zImage的基礎上加上64Byte的頭部。  下面通過Legacy-uImage的頭部資料結構來解析這串資料。

4、格式頭說明

uboot用image_header來表示Legacy-uImage的頭部

typedef struct image_header {
    __be32      ih_magic;   /* Image Header Magic Number    */   // 幻數頭,用來校驗是否是一個Legacy-uImage
    __be32      ih_hcrc;    /* Image Header CRC Checksum    */ // 頭部的CRC校驗值
    __be32      ih_time;    /* Image Creation Timestamp */ // 映象建立的時間戳
    __be32      ih_size;    /* Image Data Size      */ // 映象資料長度
    __be32      ih_load;    /* Data  Load  Address      */ // 載入地址
    __be32      ih_ep;      /* Entry Point Address      */ // 入口地址
    __be32      ih_dcrc;    /* Image Data CRC Checksum  */ // 映象的CRC校驗
    uint8_t     ih_os;      /* Operating System     */ // 作業系統型別
    uint8_t     ih_arch;    /* CPU architecture     */ // 體系 
    uint8_t     ih_type;    /* Image Type           */ // 映象型別
    uint8_t     ih_comp;    /* Compression Type     */ // 壓縮型別
    uint8_t     ih_name[IH_NMLEN];  /* Image Name       */ // 映象名
} image_header_t;
#define IH_NMLEN        32  /* Image Name Length        */

可以發現這個頭部就是64Byte。根據上述3來說明一下這個資料結構

  • ih_magic  27 05 19 56  頭部幻數,用來判斷這個是否是Legacy-uImage的頭部。為0x27051956則表示是一個Legacy-uImage。
  • ih_size  00 17 cd f8  資料映象長度。這裡是0x17cdf8,也就是1560056,和我們前面測得的zImage的長度一致。
  • ih_load  20 00 80 00  載入地址,也就是0x20008000, 和我們執行mkimage使用的引數一致。
  • ih_ep  20 00 80 40  入口地址,也就是0x20008040, 和我們執行mkimage使用的引數一致。

三、FIT-uImage

0、原理說明

flattened image tree,類似於FDT(flattened device tree)的一種實現機制。其通過一定語法和格式將一些需要使用到的映象(例如kernel、dtb以及檔案系統)組合到一起生成一個image檔案。其主要使用四個元件。

  • its檔案  image source file,類似於dts檔案,負責描述要聲稱的image的的資訊。需要自行進行構造。
  • itb檔案  最終得到的image檔案,類似於dtb檔案,也就是uboot可以直接對其進行識別和解析的FIT-uImage。
  • mkimage  mkimage則負責dtc的角色,用於通過解析its檔案、獲取對應的映象,最終生成一個uboot可以直接進行識別和解析的itb檔案。
  • image data file  實際使用到的映象檔案。

mkimage將its檔案以及對應的image data file,打包成一個itb檔案,也就是uboot可以識別的image file(FIT-uImage)。我們將這個檔案下載到麼memory中,使用bootm命令就可以執行了。

1、使能需要開啟的巨集

CONFIG_FIT=y

2、如何製作 & 使用

(1)its檔案製作  因為mkimage是根據its檔案中的描述來打包映象生成itb檔案(FIT-uImage),所以首先需要製作一個its檔案,在its檔案中描述需要被打包的映象,主要是kernel映象,dtb檔案,ramdisk映象。  簡單的例子如下:

/*
 * U-Boot uImage source file for "X project"
 */

/dts-v1/;

/ {
    description = "U-Boot uImage source file for X project";
    #address-cells = <1>;

    images {
        [email protected] {
            description = "Unify(TODO) Linux kernel for project-x";
            data = /incbin/("/home/hlos/code/xys/temp/project-x/build/out/linux/arch/arm/boot/zImage");
            type = "kernel";
            arch = "arm";
            os = "linux";
            compression = "none";
            load = <0x20008000>;
            entry = <0x20008000>;
        };
        [email protected] {
            description = "Flattened Device Tree blob for project-x";
            data = /incbin/("/home/hlos/code/xys/temp/project-x/build/out/linux/arch/arm/boot/dts/s5pv210-tiny210.dtb");
            type = "flat_dt";
            arch = "arm";
            compression = "none";
        };
        [email protected] {
            description = "Ramdisk for project-x";
            data = /incbin/("/home/hlos/code/xys/temp/project-x/build/out/rootfs/initramfs.gz");
            type = "ramdisk";
            arch = "arm";
            os = "linux";
            compression = "gzip";
        };
    };

    configurations {
        default = "[email protected]";
        [email protected] {
            description = "Boot Linux kernel with FDT blob";
            kernel = "[email protected]";
            fdt = "[email protected]";
            ramdisk = "[email protected]";
        };
    };
};
  • 語法可以參考蝸窩科技的u-boot FIT image介紹 注意,可以有多個kernel節點或者fdt節點等等,相容性更強。同時,可以有多種configurations,來對kernel、fdt、ramdisk來進行組合,使FIT-uImage可以兼容於多種板子,而無需重新進行編譯燒寫。

(2)生成FIT-uImage  生成的命令相對Legacy-uImage較為簡單,因為資訊都在its檔案裡面描述了

mkimage -f ITS檔案 要生成的ITB檔案,如下:
${UBOOT_OUT_DIR}/tools/mkimage -f ${UIMAGE_ITS_FILE} ${UIMAGE_ITB_FILE}

最終在project X專案上生成了xprj_uImage.itb,這就是我們需要的FIT-uImage檔案。

(3)使用  將生成的FIT-uImage下載到引數中指定的load address中,使用bootm ‘實際load address’命令跳轉到kernel中。  uboot會自動解析出FIT-uImage中,kernel、ramdisk、dtb的資訊,使用起來相當方便。

3、簡單說明

FIT-uImage的格式類似於DTB。uboot會去解析出FIT-uImage中的configurations節點,根據節點選擇出需要的kernel、dtb、rootfs。因此,在節點的基礎上,新增很多節點資訊,提供uboot使用。