由zImage生成uImage
內核編譯(make):make menuconfig
make def
make
內核編譯(make)之後會生成兩個文件,一個Image,一個zImage,其中Image為內核映像文件,而zImage為內核的一種映像壓縮文件,Image大約為4M,而zImage不到2M。
那麼uImage又是什麼的?它是uboot專用的映像文件,它是在zImage之前加上一個長度為64字節的“頭”,說明這個內核的版本、加載位置、生成時間、大小等信息;其0x40之後與zImage沒區別。
如 何生成uImage文件?首先在uboot的/tools目錄下尋找mkimage文件,把其copy到係統/usr/local/bin目錄下,這樣就 完成製作工具。然後在內核目錄下運行make uImage,如果成功,便可以在arch/arm/boot/目錄下發現uImage文件,其大小比 zImage多64個字節。
其實就是一個自動跟手動的區別,有了uImage頭部的描述,u-boot就知道對應Image的信息,如果沒有頭部則需要自己手動去搞那些參數。
U-boot的U是“通用”的意思。
zImage 是ARM Linux常用的一種壓縮映像文件,uImage是U-boot專用的映像文件,它是在zImage之前加上一個長度為0x40的“頭”,說明 這個映像文件的類型、加載位置、生成時間、大小等信息。換句話說,如果直接從uImage的0x40位置開始執行,zImage和uImage沒有任何區 別。另外,Linux2.4內核不支持uImage,Linux2.6內核加入了很多對嵌入式係統的支持,但是uImage的生成也需要設置。
如何生成 uImage
U-boot 就是為加載kernel而服務的
簡單來講:u-boot 啟動過程分為兩個部分 :Stage 1 and Stage2
Stage1 主要是初始化硬件設備, 然後最主要的功能就是把Stage2 load到RAM中去。
u-boot與kernel的關係
U-boot為kernel服務, u-boot為kernel提供一些kernel無法知道的信息,比如ramdisk在RAM中的地址
Kernel也必須為U-boot提供必要的信息:通過mkimage這個tool可以給zImage添加一個header:
typedef struct image_header {
uint32_t ih_magic;
uint32_t ih_hcrc;
uint32_t ih_time;
uint32_t ih_size;
uint32_t ih_load;
uint32_t ih_ep;
uint32_t ih_dcrc;
uint8_t ih_os;
uint8_t ih_arch;
uint8_t ih_type;
uint8_t ih_comp;
uint8_t ih_name[IH_NMLEN];
} image_header_t;
利用u-boot裏麵的mkimage工具來生成uImage (u-boot源碼包/tools/mkimage.c )
用法:
-A arm -------- 架構是arm-O linux -------- 操作係統是linux-T kernel -------- 類型是kernel-C none -------- 壓縮類型為無壓縮-a 30008000 ---- image的載入地址(hex)-e 30008040 ---- 內核的入口地址(hex),因為信息頭的大小是0x40-n linux-2.6.18.8 --- image的名字-d zImage ---- 無頭信息的image文件名uImage2.6.
18.8 ---- 加了頭信息之後的image文件名
生成uImage 的方法
mkimage -A arm -O linux -T kernel -C none -a 30008000 -e 30008000 -n linux-2.6.18.8 -d zImage uImage2.6.18.8
注釋:這裏的意思就是把zImage的前麵加上一個0x40長度的header ,沒有壓縮(none) , kernel的load地址是:-a 30008000 ; kernel的入口地址是 –e 30008000
不知道是否對入口地址有疑問:為什麼入口地址不是 0x80003040 呢? 答案就在 u-boot 裏麵的bootm命令的實現代碼上, 我會在 “分析bootm源碼”中給予分析介紹 , 來詳細分析
1> mkimage 如何指定入口參數 ( -e 0xxxxxx)
2> mkimage 指定了入口參數後, 你用tftpboot 下載kernel到哪個地址?
#/usr/local/src/u-boot-1.2.0/tools/mkimage -A arm -O linux-T kernel -C none -a 30008000 -e 30008000 -n linux-2.6.18.8 -d zImage uImage2.6.18.8
imagefile = uImage2.6.18.8
Image Name: linux-2.6.18.8
Created: Fri Jun 15 13:56:06 2007
Image Type: ARM Linux Kernel Image (uncompressed)
Data Size: 1068212 Bytes = 1043.18 kB = 1.02 MB
Load Address: 0x30008000
Entry Point: 0x30008000
生成uImage的方法: 利用mkimage 命令 把zImage 包裝 , mkimage -A arm -O linux -T kernel -C none -a 30008000 -e 30008000 -n linux-2.6.18.8 -d zImage uImage2.6.18.8 下麵的總結都是 稍微調整一下上麵的 -a -e -x 參數什麼的, 你會發現這些參數不同, 就會導致你 tftp dowload的地址會有不同, 有的時候kernel會run不起來。
addr是地址 , 如果兩個地方都是addr ,說明是同一個地址, 否則 我會比如addr+0x40 的 1> mkimage -a addr -e addr 那麼tftp 下載kernel 就一定不能下載 addr處 , 否則,kernelrun不起來。 因為u-boot並不搬運kernel 代碼,也就是沒有把header去掉。所以隻有入口是 addr+0x40才是kernel的入口。 當然也不能下到 < addr + 2M 的地方,否則搬運的時候會有一些覆蓋, 導致搬運後的kernel不完整, bootm的時候,u-boot就會RESET
的。
2> mkimage -a addr -e addr+0x40 或者 mkimage -a addr -x 兩個是一回事 。 -x的意思 是就在kernel所在地執行。 不必搬運(代碼裏麵的條件是 tftp 下kernel的時候 就下到 addr處,這樣bootm就沒有必要搬運了) 這種情況: tftp 就一定把kernel 下載到addr處 ,這樣u-boot 在bootm的時候 就不搬運了。 其實這種情況更多的用在flash裏麵 。 // -----------------------------------------------------
switch (hdr->ih_comp) {
case IH_COMP_NONE: // -C none
if(ntohl(hdr->ih_load) == addr) { //不搬運
printf (“ XIP %s ... ”, name);//注意屏幕信息
} else {
memmove ((void *) ntohl(hdr->ih_load), (uchar *)data, len); //搬運:這裏data指向實際的kernel ,把kernel搬運到hdr->ih_load處,這個值就是mkimage –d 0x30008000
}
對於u-boot最常用得命令莫過於:
tftpboot 和 bootm 命令了。
具體分析一下這兩個過程,這樣大家用的時候就知其所以然了,也就能少犯一些錯誤了。具體參考:common/cmd_bootm.c ? do_bootm()
還有do_bootm_linux() 函數
比如 :
Tftpboot 0x3300,0000 uImage
Tftpboot 0x3080,0000 ramdisk.gz
Bootm 0x3300,0000 0x3080,0000
過程:tftpboot把uImage 下載地址0x33000000 ,然後把ramdisk.gz 下載到0x30800000 .
最後執行bootm ,
Bootm 會首先取出uImage的0x40個header ,然後讀取header的ih_load字段,
隻有這樣u-boot 才知道把uImage搬運到哪裏。
在中間的時候, u-boot 會判斷tftp 下載kernel的地址是否等於ih_load ,這裏非常關鍵。如果等於就不搬運;如果不等於u-boot 把指針定位到0x40之後的位置, 這裏才是真正的kernel(zImage), 把zImage 搬運(copy)到 ih_load這個地址上去。 然後執行kernel 。
最後更新:2017-04-03 16:48:39