嵌入式linux-u-boot优化

1.去掉启动时的按键等待

U-boot 启动的时候出现一个 Hit any key to stopautoboot 不爽,干吗要停上1秒?虽然可以通过设置参数bootdelay=0来关掉这个延时,但这样做了以后就再也进不去U-boot了,更烦。检查代码,发现是在main.c函数intabortboot(int bootdelay)来干这个活的,好吧,改掉它

static __inline__ intabortboot(int bootdelay)
    {
       int abort = 0;
       char inputkey;

    if(tstc())
       { 
           inputkey =getc(); 
           abort = (inputkey == 'u');

    }
       #ifdef CONFIG_SILENT_CONSOLE
         if (abort)
              gd->flags&= ~GD_FLG_SILENT;
       #endif
       return abort;
   }

这样,就不需要等待了,如果想进入U-boot,就在上电的时候按住u吧,把它改成一个固定的键而不是任意键,因为串口线很容易受到干扰,如果是任意键的话,运行时即使不想进去有时也会进入U-boot的命令行。 

2.去掉网卡的初始化

每次上电,U-boot都会初始化网卡,其实这根本不需要,把配置文件中

#defineCONFIG_MII   1

去掉,启动时就不会初始化了,需要使用TFTP时,它会自动初始化,又节省了3.4秒的启动时间。

3.智能读取OSImage

U-boot 通过nand read 来读取OSImage,通常为了避免麻烦,我们设置的读取长度要比实际OS长度长一些,多读的那部分纯粹是浪费CPU时间,能不能精确判断读取长度呢,当然可以,为了不影响系统的正常功能,扩展一个nandread.os 指令来读取,修改方法如下:

在 nand_read_options_t里面添加一个成员 int is_os_img

在函数 int do_nand(cmd_tbl_t* cmdtp, int flag, int argc, char *argv[])

修改读操作的判断语句,添加 !strcmp(s,".os"),然后设置opts.is_os_img = !strcmp(s, ".os");大概修改后结果参考第7步代码。

 
  最后,在函数intnand_read_opts(nand_info_t *meminfo, const nand_read_options_t*opts)中修改

代码,检测如果opts->is_os_img == 1并且是第一次读取(2024B)之后,检查度取得结果是否是OSImage,如果是更新需要读取的长度,否则,也不需要再往下读了,直接返回错误就可以了嵌入式Linux启动优化手记2 <wbr>U-boot优化
            image_header_t  *hdr = (image_header_t*)buffer;    
             if(image_check_magic(hdr) &&image_check_hcrc (hdr))
             {
                size_t ossz= uimage_to_cpu(hdr->ih_size);//+image_get_header_size();
                imglen =ossz + + image_get_header_size();
                printf("##Find valid OS image, at 0x%x, Size: %d Bytes = %d KB\n",
                     (unsigned int)mtdoffset, ossz,ossz/1024);
             }
             else
             {
               printf("Invalid OS image at 0x%x\n", (unsignedint)mtdoffset);
                return-1;
             }

4.去掉OS Image内存复制过程

使用 nand read 读取OS Image后,U-boot 使用 bootm 指令来启动Linux,检查其实现代码

int do_bootm (cmd_tbl_t*cmdtp, int flag, int argc, char *argv[])

发现他会把已经读取到内存中的OS Image在复制到一个指定的位置,OS Image 中的头部参数,这个值一般是固定的,本系统使用的是 0x70008000, 如果在 nandread 时读到的内存位置恰好合适,就可以省掉这些毫秒数了,做法如下:

nand read.os 0x70007FC00x100000 0x500000

(其中 0x70007FC0 =0x70008000 - sizeof(sizeof(image_header_t)))

然后在内存复制的地方(函数do_bootm中),加入修改,跳过内存复制

    switch(comp) {
    caseIH_COMP_NONE:
       if(load_start == (ulong)os_hdr) {
          printf("   XIP %s ... ",type_name);
       } else{
          if(load_start != os_data)//位置不匹配,依然移动,否则就跳过此部
         {
             printf("   Loading %s ... ",type_name);
             memmove_wd((void *)load_start, (void *)os_data, os_len,CHUNKSZ);
            puts("OK\n");
         }
       }
       load_end =load_start + os_len;

对于我们的Kernel,修改后大小是1.4M,省去这个搬移过程,节省了大约800ms的时间

5.减少内存初始化的时间

在U-boot 初始化时,在start_armboot 函数中,多次使用到了memset函数,其中最耗时的是在mem_malloc_init函数中调用memset 初始化 512K内存的调用,检查U-boot1.3.4对memset的实现,发现是最简单的字节复制,把它改为按32bits复制的方式,这些memset调用所花费的时间立即从202ms减少到了45ms

修改方法,再 string.c中,找到memset函数,修改其实现(代码是从U-boot 2011.12 中复制过来的嵌入式Linux启动优化手记2 <wbr>U-boot优化

void * memset(void *s,int c,size_t count)
    {
       unsigned long *sl = (unsigned long *) s;
       unsigned long cl = 0;
       char *s8;
       int i;
  
       if ( ((ulong)s& (sizeof(*sl) - 1)) == 0) {
          for (i = 0; i <sizeof(*sl); i++) {
             cl<<= 8;
             cl |= c & 0xff;
          }
          while (count>= sizeof(*sl)) {
             *sl++ = cl;
             count -= sizeof(*sl);
          }
       }
   
       s8 = (char *)sl;
       while (count--)
          *s8++ = c;
       return s;
    }

6.减少NAND初始化时间
    每次 U-boot启动,发现NAND初始化需要大约3秒的时间,仔细追踪发现,在nand_base.c文件中nand_scan函数的最后一步returnthis->scan_bbt(mtd);最花费时间,这个scan_bbt扫描整个NAND并检查坏块,重建坏块表,在启动过程中,这个耗时的操作毫无意义,去掉这一步,让nand_scan函数直接返回0就可以了。

7.添加Yaffs2支持

从网上各位前辈的论述中,都发现YAFFS比JFFS2要快,也决定测试一下,从YAFFS网站下载最新的代码,按照说明加入到Linux中,重新编译内核,让内核支持YAFFS2(按照默认的选项就可以了),弄一个空的分区,格式化成YAFFS2格式,感觉的确比较快,把ROOTFS复制到这个分区,然后修改Linux启动参数让它把YAFFS2分区当作根分区启动,发现果然快了不少,初始化和挂载根分区仅需要370ms,比JFFS2的速度快多了,决定就采用YAFFS2作为根文件系统了。自己在u-boot中添加对yaffs2image的支持

说起来容易,真正做起来还是很麻烦的,总是不能把yaffs2的image烧写成功,不知道是Image不正确还是Uboot没改对,折腾了几天也没搞定,最后终于发现了一个第三方的工具

http://code.google.com/p/yaffs2utils/

下载,编译,制作Image,验证,OK,把新工具生成的IMAGE与YAFFS2自带的工具对照,发现YAFFS2自带的工具生成的IMAGE不正确,晕死。

重新修改UBoot,改了很少一部份代码,就可以了。

依然是在函数do_nand中修改,添加一个扩展nand write.y 指令来写入Image:

按照惯例,YAFFS2的第一个块不使用,留给文件系统自己使用,在 nand_write_options_t 里面添加一个成员 intskip_first_block;

在函数 int do_nand(cmd_tbl_t* cmdtp, int flag, int argc, char *argv[])

修改读写操作的判断语句,添加 !strcmp(s,".y"),然后设置opts.is_os_img = !strcmp(s, ".os");大概修改后结果如下(红色部分)

   s = strchr(cmd, '.');
       if (s !=NULL && (!strcmp(s, ".jffs2") ||!strcmp(s, ".e") || !strcmp(s, ".i") || !strcmp(s, ".os") || !strcmp(s,".y")))    {
          if (read){
            
            nand_read_options_t opts;
            memset(&opts, 0, sizeof(opts));
            opts.buffer    =(u_char*) addr;
            opts.length    =size;
            opts.offset    =off;
             opts.readoob= 0;//remove this function.
            opts.is_os_img = !strcmp(s,".os");
            opts.quiet     = quiet;
             ret =nand_read_opts(nand, &opts);
            //printf("call nand_read_opts buffer %lu len %lu offset %d off, ret%d\n", addr, size, off, ret);
          } else{
            
            nand_write_options_t opts;
            memset(&opts, 0, sizeof(opts));
            opts.buffer    =(u_char*) addr;
            opts.length    =size;
          

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值