由zImage生成uImage

一、手动使用mkimage命令
mkimage -A arm -O linux -T kernel -C none -a 30007fc0 -e 30007fc0 -n uImage   -d /work/jz2440/kernel/linux-2.6.22.6/arch/arm/boot/zImage uImage
 
我的内核目录:/work/jz2440/kernel/linux-2.6.22.6

我的tftpboot:/work/tftpbootuboot——bootm地址:30007fc0
 
U-boot mkimage指定Linux内核地址时的两种方式    http://blog.csdn.net/embededswordman/article/details/6704197
 
uImage的制作是使用的u-boot工具mkimage,build完u-boot后也会将mkimage build出來到/tools目录下,可以直接拿來用,它的作用就是在zImage的前面加上64个字节的头,让u-boot能够识别要加载内核的类型、加载地址等。

基本格式:mkimage -A arch -O os -T type -C comp -a addr -e ep -n name -d data_file[:data_file...] image

-A 指定CPU的体系结构:(u-boot支持多种的架构,这里应该是arm)
取值        表示的体系结构
alpha       Alpha
arm          A RM
x86          Intel x86
ia64         IA64
mips         MIPS
mips64     MIPS 64 Bit
ppc          PowerPC
s390        IBM S390
sh            SuperH
sparc       SPARC
sparc64   SPARC 64 Bit
m68k       MC68000


-O 指定操作系统类型,可以取以下值:(u-boot支持多种的OS,这里应该是linux)
openbsd、netbsd、freebsd、4_4bsd、linux、svr4、esix、solaris、irix、sco、dell、ncr、lynxos、vxworks、psos、qnx、u-boot、rtems、artos


-T 指定映象类型,可以取以下值:(u-boot可以加载不同的映像,这里应该是kernel)
standalone、kernel、ramdisk、multi、firmware、script、filesystem


-C 指定映象压缩方式,可以取以下值:(除了zImage本身是压缩格式外,u-boot还可以对其再压缩,这里应该是none)
none 不压缩
gzip 用gzip的压缩方式
bzip2 用bzip2的压缩方式


-a 指定映象在内存中的加载地址,可以于实际加载(如tftp加载)时的地址不相同,也可以相同,详见后面的解释。


-e 指定映像运行的入口地址,可以等于加载地址,也可以是加载地址偏移64字节(+0x40)后的地址,详见后面的解释。


-n 指定映像名称


-d 指定【源文件】和生成的【目标文件名】

调整的最多的参数是-a, -e,这两个参数需要与实际加载到内存时的动作保持一致。


1、如果加载时的地址与-a参数指定的不相同,则-e必须等于-a。u-boot会把kernel image去掉不包括64字节的信息头后搬移到-e处,直接启动。要注意两个image的存储空间不要重叠,两者之间至少要留image size的空间。

编译环境:

mkimage -A arm -O linux -T kernel -C none -a 0x70008000 -e 0x70008000 -n 'Linux' -d zImage uImage
        cp uImage /tftpboot/       

目标板环境:

tftp   0x72200000  uImage;   bootm   0x72200000;

2、如果加载时的地址与-a参数指定相同,则-e必须是-a + 0x40的地址。这时u-boot不需要再执行搬移的动作,根据-e的地址直接启动。 

        编译环境:

        mkimage -A arm -O linux -T kernel -C none -a 0x0x70008000 -e 0x70008040 -n 'Linux‘ -d zImage uImage

        cp uImage /tftpboot/           

        目标板环境:
        tftp   0x70008000  uImage;    bootm  0x70008000;

 


名字:uImage
需要先安装mkimage工具
----------------------------------------------------------------------------------------
参考:http://blog.sina.com.cn/s/blog_7776b9d301017pck.html

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 。
 
 
二、jz2440 linux-2.6.22.6 make uImage自动生成uImage的过程追溯;

执行”make uImage“ = “make” + “mkimage -A arm -O linux -T kernel  -C none -a 0x30008000 -e 0x30008000  -n 'Linux-2.6.22.6' -d zImage uImage

1.1. linux-2.6.22.6/arch/arm/boot/Makefile
quiet_cmd_uimage = UIMAGE  $@
      cmd_uimage = $(CONFIG_SHELL) $(MKIMAGE) -A arm -O linux -T kernel \
                   -C none -a $(ZRELADDR) -e $(ZRELADDR) \
                   -n 'Linux-$(KERNELRELEASE)' -d $< $@
 
# Note: the following conditions must always be true:
#   ZRELADDR == virt_to_phys(PAGE_OFFSET + TEXT_OFFSET)
#   PARAMS_PHYS must be within 4MB of ZRELADDR
#   INITRD_PHYS must be in RAM
ZRELADDR    := $(zreladdr-y)
 
1.2. linux-2.6.22.6/scripts/mkuboot.sh
    MKIMAGE=$(type -path mkimage)
 
 
 
2. linux-2.6.22.6/arch/arm/mach-s3c2410/Makefile.boot
zreladdr-y     := 0x30008000
 
posted @ 2014-09-26 11:11  oucaijun  阅读(1925)  评论(0编辑  收藏  举报
下载TeamViewer完整版 下载TeamViewer