uClinux下,一种合并uzImage.bin和cramfs.bin的方法

以下这种方法最后合并出的文件不是通常uClinux“认为”的标准镜像文件,而且一定要修改bootload代码。请慎用此方法。


(一)、为什么要合并uzImage.bin和cramfs.bin?

一、为了升级时安全、方便

安全。当系统升级程序拿到升级文件时,它必然要判断该文件合法性。uzImage.bin有crc检查,判断起来很容易,cramfs.bin是不带的,有难度。如果两个合为一个,然后使用加在uzImage.bin上的crc机制,那合法性检查上就简单了。

方便。两个合为一个,升级时只须一个文件。

二、节省flash占用空间

分为uzImage.bin和cramfs.bin,则意味着必须给flash人为地分出两个空间,而且这两个空间大小被事先固定。像4M字节flash,uzImage.bin占用从0x040000开始的1M字节,cramfs.bin占用从0x140000开始的2,752K字节。

既分在两个区就使得分配时不得不存在一个权衡问题,代码不可能写得“恰好”占用。像对于uzImage.bin,这个版本可能是恰好占用,但代码写多了都知道,功能上的删、加、修改是不确定的,下个版块可能就要因一个意外修改而导致不得不修改uzImage.bin。为解决这个问题,可以使用在bootload环境变量中写上两区边界方法,但这种方法怎么说也没只是一个文件时方便,而且再“恰好”也肯定是有一定字节“空隙”。


(二)、如何合并

合并采用的方法分为宿主机链接时和uClinux的bootload加载时两个部分。

注:image.0000.img表示最终形成的单个镜像文件。

宿主机链接时

当拿到uzImage.bin.gz(这里多了个gz,这个文件不是最后mkimage后的,而是在mkimage之前gzip之后)和cramfs.bin,链接时执行:

cat $(cramfs.bin) $(uzImage.bin.gz) > $(uzImage.gz)
./mkimage -A arm -O linux -T kernel -C gzip -a <加载地址> -e <执行地址> -n "uClinux Kernel for xxxx" -d $(uzImage.gz) $(IMAGEDIR)/image.0000.img

简单来说,就是在mkimage uzImage.bin.gz之前,先用cat命令合并uzImage.bin.gz和cramfs.bin,合并时cramfs.bin必须放在前头。

cramfs.bin为何要放在前头?

cramfs.bin文件的[4h---7h]四字节存储了该cramfs.bin的文件长度。gzip之后的uzImage.bin.gz无法自识别长度。

至此形成的image.0000.img文件结构

image_header_t:mkImage添加的文件头,固定64字节
cramfs.bin:cramfs.bin部分,它的长度可由偏移68--71字节处得到,假设是cramfs_len。
uzImage.bin:uzImage.bin部分。它在image.0000.img开始址址是64+cramfs_len,它的长度则可以由image_head_t中的有效数据长度字段值减去cramfs_len得到。

uClinux的bootload加载时

加载还是要分两次进行,分别加载uzImage.bin和cramfs.bin。

当运行到要加载uzImage.bin时。开始地址:image.0000.img开始地址加上64+cramfs_len;长度:image_head_t中的有效数据长度字段值减去cramfs_len。

当运行到要加载cramfs.bin时。开始地址:image.0000.img开始地址加上64。长度:image.0000.img偏移处68--71字节处得到的值。


(三)、几点补充

一、检查镜像文件合法性上沿用原先给uzImage.bin的crc机制,可以说不增加较验上开销。

二、在flash向ram加载效率上,只是多了几个判断,和原先分两个文件加载方法上可说一样的执行效率。

 

 

一个实例:对bootload改动

bootload准备好flash和sdram可通信后,它接下执行:

1):把uzImage.bin从flash加载到sdram;
2):把cramfs.bin从flash加载到sdram;
3):把矢量表加载到sdram零处
4):运行uClinux内核

bootcmd环境变量表示以上四个过程:
  1. bootcmd=cp.l fc040000 01800000 40000; cp.l fc140000 02000000 AC000; cp.l fc3f8000 0 e;bootm 01800000
复制代码
cp.l是个复制命令,cp==>copy;l==>long,数量以4字节单位,以上的bootcmd类似下以命令
注:以下的flash地址像fc040000,完全大于了4M/8M,那时因为flash被map后它的起始地址就是0xfc000000,所以fc040000对应的其实是flash上的0x40000地址。
  1. flash-2-mem(0xfc040000, 0x01800000, 0x40000 << 2);
  2. flash-2-mem(0xfc140000, 0x02000000, 0xac000 << 2);
  3. flash-2-mem(0xfc3f8000, 0x00000000, 0xe << 2);
  4. bootm(0x1800000)
复制代码
以下就是从flash加载到sdram函数。uzImage.bin、cramfs.bin、矢量表被分次调用。
  1. int do_mem_cp(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
  2. {
  3.         ulong addr, dest, count;
  4.         int        size;
  5.         image_header_t* hdr;

  6.         if (argc != 4) {
  7.                 printf ("Usage:\n%s\n", cmdtp->usage);
  8.                 return 1;
  9.         }

  10.         /* Check for size specification.
  11.         */
  12.         if ((size = cmd_get_data_size(argv[0], 4)) < 0)
  13.                 return 1;

  14.         addr = simple_strtoul(argv[1], NULL, 16);
  15.         addr += base_address;

  16.         dest = simple_strtoul(argv[2], NULL, 16);
  17.         dest += base_address;

  18.         count = simple_strtoul(argv[3], NULL, 16);

  19.         if (count == 0) {
  20.                 puts ("Zero length ???\n");
  21.                 return 1;
  22.         }

  23.         //
  24.         // 由于使用了把uzImage.bin和cramfs.bin合并到一个文件,而在命令行上又保持不变,就须要修正一些变量意义。
  25.         //
  26.         if (addr == 0xfc040000) {
  27.                 // fc040000, flash(uzImage.bin)-->ram
  28.                 // dest = 0x01008000;

  29.                 // 读出cramfs.bin文件长度
  30.                 cramfs_len = *(ulong *)(0xfc040000 + sizeof(image_header_t) + 4);
  31.                 printf("addr == 0xfc040000, this is uzImage.bin, base_address: %lu, cramfs_len: %lu\n", base_address, cramfs_len);

  32.                 hdr = (image_header_t*)addr;
  33.                 count = sizeof(image_header_t) / size;        // sizeo = 4, sizeof(image_header_t)一般0x40字节,可以被4整除
  34.                 // 复制头
  35.                 while (count-- > 0) {
  36.                         if (size == 4)
  37.                                 *((ulong  *)dest) = *((ulong  *)addr);
  38.                         else if (size == 2)
  39.                                 *((ushort *)dest) = *((ushort *)addr);
  40.                         else
  41.                                 *((u_char *)dest) = *((u_char *)addr);
  42.                         addr += size;
  43.                         dest += size;
  44.                 }

  45.                 // 从image_header_t中取出数据长度(count = cramfs.bin + uzImage.bin.gz)
  46.                 count = SWAP_LONG(hdr->ih_size); // ntohl(ih_size)
  47.                
  48.                 // 注意,此时的addr已经变成, 函数参数中的addr + sizeof(image_header_t)
  49.                 addr = addr + cramfs_len;
  50.                 count = (count - cramfs_len) / size + 1; // cp.l时,size是4, uzImage.bin有效长度会由gzip压缩机制保证(4M flash)或只要至少比有效多就行(8M flash),这里多复制四个字节总不会出错
  51. #ifndef USE_4M_FLASH
  52.                 // 对于uzImage.bin来说,为减少字节占用一般使用gzip压缩(大概可以达到2:1压缩率),使整个软件能约束在4M字节以内。
  53.                 // 因为使用gzip压缩,bootload必须对uzImage.bin进行解压,这个过程有时较耗时间,为减少启动时间宁愿采用不压缩而使用8M字节flash

  54.                 // 这里就是8M情况

  55.                 // 对于8M, uzImage.bin没经过压缩, 这里就直接复制到解压后的uzImage.bin应该放到的地址, 省掉do_bootm()中的memcpy
  56.                 dest = SWAP_LONG(hdr->ih_load);
  57. #endif
  58.                
  59.         } else if ((addr == 0xfc140000) && cramfs_len) {
  60.                 // fc140000, flash(cramfs.bin)-->ram

  61.                 // 总是假定uzImage.bin已被下载
  62.                 printf("addr == 0xfc140000, this is cramfs.bin, base_address: %lu, cramfs_len: %lu\n", base_address, cramfs_len);
  63.                 addr = 0xfc040000 + sizeof(image_header_t);        // addr要回到flash开始内核开始处: 0xfc040000
  64.                 count = cramfs_len / size;
  65.         } else if (addr == 0xfc3f8000) {
  66.                 // 矢量表。这个才60字节,直接是以内存数组表示
  67.                 printf("addr == 0xfc3f8000, this is vector, count: %lu\n", count);
  68.                 addr = vectordata;
  69.         }

  70.         while (count-- > 0) {
  71.                 if (size == 4)
  72.                         *((ulong  *)dest) = *((ulong  *)addr);
  73.                 else if (size == 2)
  74.                         *((ushort *)dest) = *((ushort *)addr);
  75.                 else
  76.                         *((u_char *)dest) = *((u_char *)addr);
  77.                 addr += size;
  78.                 dest += size;
  79.         }
  80.         return 0;
  81. }
复制代码

来自:http://www.freeors.com/bbs/forum.php?mod=viewthread&tid=11149

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值