内核编译(make) 之后会生成两个文件,一个Image,一个zImage,其中Image为内核映像文件,而zImage为内核的一种映像压缩文件,Image大约为 4M,而zImage不到2M。
那么uImage又是 什么的?它是uboot专用的映像文件,它是在zImage之前加上一个长度为64字节的“头”,说明这个内核的版本、加载位置、生成时间、大小等信息; 其0x40之后与zImage没区别。
64字节的头结构如 下:
typedef struct image_header {
uint32_tih_magic;
uint32_tih_hcrc;
uint32_tih_time;
uint32_tih_size;
uint32_tih_load;
uint32_tih_ep;
uint32_tih_dcrc;
uint8_tih_os;
uint8_tih_arch;
uint8_tih_type;
uint8_tih_comp;
uint8_tih_name[IH_NMLEN];
} image_header_t;
所以,uImage和zImage 都是压缩后的内核映像。而uImage是用mkimage工具根据zImage制作而来的。mkimage工具介绍如下:
u-boot里面的mkimage工具来生成uImage(u-boot源码包/tools/mkimage.c )
这里解释一下参数的意义:
-A ==> set architecture to 'arch'
-O ==> set operating system to 'os'
-T ==> set image type to 'type' “kernel或是ramdisk”
-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'
-d==> use image data from 'datafile'
-x ==> set XIP (execute in place,即不进行文件的拷贝,在当前位置执行)
对于ARM linux内核映象用法:
-A arm -------- 架构是arm
-O linux -------- 操作系统是linux
-T kernel -------- 类型是kernel
-C none/bzip/gzip -------- 压缩类型
-a 20008000 ---- image的载入地址(hex),通常为0xX00008000
-e 200080XX---- 内核的入口地址(hex),XX为0x40或者0x00
-n linux-XXX --- image的名字,任意
-d nameXXX ---- 无头信息的image文件名,你 的源内核文件
uImageXXX ---- 加了头信息之后的image文件 名,任意取
原来在这个-C这个参数这里不太理解,因为我觉得既然mkimage是用zImage去制作uImage,而本身 zImage就是经过压缩了的,为什么这个地方还要有一个压缩了,后来想了下,觉得可能是这个工具也可以根据最原始的Image去制作uImage,所以 就有了这个参数,不深究。即使将zImage经过压缩后生成uImage的话,我觉得压缩比也很小。
关于-a和-e这两个参数,具体如下:
-a和-e后面跟的分别是image的载入地址 和内核的入口地址,两者可以一样,也可以不一样,依情况而定。
当-a后面指定的地址和bootm xxxx后面的地址一样时,-e后面的地址必须要比-a后面的地址多0x40,也就是映像头的大小64个字节。因为当他们地址一样时,uboot是不会搬 运映像的。
当-a后面指定的地址和bootm xxxx后面的地址不一样时,uboot会将bootm xxxx地址处的映像搬运到-a指定的地址处,此时,-e和-a必须要一样,因为映像头并没有搬运过去,载入地址就是内核的入口地址。需要注意的是,因为 uboot要重新搬运内核映像,所以要注意bootm xxxx的地址和-a之间的地址不要导致复制时的覆盖。
因为zImage是经过压缩而得到的,所以其自 身就有解压缩代码。
参考博文:http://blog.csdn.net/sailor_8318/article/details/2773412
2,内核编译(make)之后会生成两个文件,一个 Image,一个zImage,其中Image为内核映像文件,而zImage为内核的一种映像压缩文件,Image大约为4M,而zImage不到 2M。
其实就是一个自动跟手动的区别,有了uImage头部 的描述,u-boot就知道对应Image的信息,如果没有头部则需要自己手动去搞那些参数。
U-boot的U是“通用”的意思。
zImage 是ARM
按各地址起作用的顺序,uboot引导linux内核启动涉及到以下地址:
- load address:
- entry point: 这两个地址是mkimage时指定的
- bootm address:bootm为uboot的一个命令,以此从address启动kernel
- kernel运行地址:在具体mach目录中的Makefile.boot中指定,为kernel启动后实际运行的物理地址
mkimage -n 'linux-3.2.1' -A arm -O linux -T kernel -C none -a 0x30008000 -e 0x30008000-d zImage uImage
理论上因为mkimage要为zImage加上0x40字节的header,所以entry point = load address + 0x40
但由于uboot 的bootm对uImage处理不是简单的go操作,其对前三个地址都有比较判断,所以在实际的操作中,就分为两种不同的情况:
1. bootm地址和load address一样
此种情况下,bootm不会对uImage header后的zImage进行memory move的动作,而会直接go到entry point开始执行。因此此时的entry point必须设置为load address + 0x40。如果kernel boot过程没有到uncompressing the kernel,就可能是这里设置不对。
boom address == load address == entry point - 0x40
具体细节可参看uboot代码common/cmd_bootm.c中bootm_load_os函数的实现:
switch (comp) {
case IH_COMP_NONE:
if (load == blob_start || load == image_start) {
printf(" XIP %s ... ", type_name);
no_overlap = 1;
} else {
printf(" Loading %s ... ", type_name);
memmove_wd((void *)load, (void *)image_start,
image_len, CHUNKSZ);
}
*load_end = load + image_len;
puts("OK\n");
break;
2. bootm地址和load address不一样(但需要避免出现memory move时出现覆盖导致zImage被破坏的情况)
此种情况下,bootm会把uImage header后的zImage move到load address(见上方代码),然后go到entry point开始执行。 由此知道此时的load address必须等于entry point。
boom address != load address == entry point
因此,在mkimage以及设置uboot boot command的时候需要注意到以上两种情况。
至于kernel的运行地址,其与前3个地址没有关系,除了要避免内存覆盖导致解压后kernel不完整的情况。
zImage的头部有地址无关的自解压程序,因此刚开始执行的时候,zImage所在的内存地址(entry point)不需要同编译kernel的地址相同。自解压程序会把kernel解压到编译时指定的物理地址,然后开始地址相关代码的执行。在开启MMU之 前,kernel都是直接使用物理地址(可参看System.map)