BOOTM浅析

来源:互联网 发布:php订单管理系统源码 编辑:程序博客网 时间:2024/05/21 07:53

原文:http://hi.baidu.com/chenenzhi/blog/item/1a6eaf54b7115a143b293588.html


boom命令实现有关的源文件主要为common/cmd_bootm.clib_arm/armlinux.c。下面就这两个文件中的关键代码段进行分析。

 

common/cmd_bootm.c(前面数字为SourceInsight中显示的行号):

168if(argc < 2) {

             addr = load_addr;

      } else {

             addr = simple_strtoul(argv[1], NULL, 16);

      }

判断运行bootm时是否指定了程序加载地址,若没有则使用默认的加载地址,load_addrcmd_bootm.c中是这样定义的:

ulong load_addr = CFG_LOAD_ADDR;

 

183memmove (&header, (char *)addr,sizeof(image_header_t));

imageheaderu-boot添加的64Byte文件头)复制到header只向的内存。

 

185if(ntohl(hdr->ih_magic) != IH_MAGIC){

#ifdef __I386__    

             if (fake_header(hdr, (void*)addr, -1) != NULL){

                    

                    addr -= sizeof(image_header_t);

                    

                    verify = 0;

             } else

#endif    

         {

             puts ("Bad Magic Numbern");

             SHOW_BOOT_PROGRESS (-1);

             return 1;

         }

      }

判断文件头中的幻数是否为IH_MAGIC,所以如果不是u-boot镜像格式,会输出提示信息”BadMagic Number”

 

204data =(ulong)&header;

      len = sizeof(image_header_t);

 

      checksum =ntohl(hdr->ih_hcrc);

      hdr->ih_hcrc = 0;

 

      if (crc32 (0, (uchar *)data, len) != checksum){

             puts ("Bad Header Checksumn");

             SHOW_BOOT_PROGRESS (-2);

             return 1;

      }

比对u-boot image文件头的CRC32校验和。

 

229data = addr +sizeof(image_header_t);

      len = ntohl(hdr->ih_size);

 

      if (verify) {

             puts ("  Verifying Checksum ... ");

             if (crc32 (0, (uchar *)data, len) !=ntohl(hdr->ih_dcrc)) {

                    printf ("Bad Data CRCn");

                    SHOW_BOOT_PROGRESS (-3);

                    return 1;

             }

             puts ("OKn");

      }

比对u-boot image数据部分的校验和。

 

245#ifdefined(__PPC__)

            if (hdr->ih_arch !=IH_CPU_PPC)

#elif defined(__ARM__)

            if (hdr->ih_arch !=IH_CPU_ARM)

#else

# error Unknown CPU type

#endif

这部条件编译指令检验检验image header中的arch类型是否是否正确。

 

275switch (hdr->ih_type){

      

      case IH_TYPE_KERNEL:

             name = "Kernel Image";

             break;

      

      default: printf ("Wrong Image Type for %s commandn",cmdtp->name);

             SHOW_BOOT_PROGRESS (-5);

             return 1;

      }

判断image的类型,这里只列出了KernelImage类型的代码,直接break:)

 

switch (hdr->ih_comp) {

      

      case IH_COMP_GZIP:

             printf ("  Uncompressing %s ... ", name);

             if (gunzip ((void *)ntohl(hdr->ih_load),unc_len,

                       (uchar *)data, &len) != 0){

                    puts ("GUNZIP ERROR - must RESET board torecovern");

                    SHOW_BOOT_PROGRESS (-6);

                    do_reset (cmdtp, flag, argc, argv);

             }

             break;

             

            default:

             if (iflag)

                    enable_interrupts();

             printf ("Unimplemented compression type %dn",hdr->ih_comp);

             SHOW_BOOT_PROGRESS (-7);

             return 1;

      }

      puts ("OKn");

这段代码比较重要,它根据image所采用的压缩类型,将image解压到hdr->ih_load指向的地址,这个ih_load就是在mkimage中的-a选项指定的地址,这下明白了,-a选项指定的是内核解压后的地址

412switch (hdr->ih_os) {

      default:                 

      case IH_OS_LINUX:

#ifdef CONFIG_SILENT_CONSOLE

         fixup_silent_linux();

#endif

         do_bootm_linux (cmdtp, flag, argc, argv,

                        addr, len_ptr, verify);

         break;

             

      }

 

      SHOW_BOOT_PROGRESS (-9);

#ifdef DEBUG

      puts ("n## Control returned to monitor -resetting...n");

      do_reset (cmdtp, flag, argc, argv);

#endif

既然内核已经解压完了,接下来就改启动Linux内核了,这里有用到了imageheader中的另一个字段ih_os:指明操作系统的类型,我只列出Linux操作系统类型的处理,可以看到它把控制权传递给了do_bootm_linux这个do_bootm_linux对于不同的ARCH有不同的实现,而ARM的实现就是在lib_arm/armlinux.c中。

 

armlinux.c :do_bootm_linux

83   ulong initrd_start, initrd_end;

initrd的起始地址和结束地址

 

85   void (*theKernel)(int zero, int arch, uintparams);

Linux内核的入口参数,zero =0arch为平台编号,params为传递给内核的参数在内存中的地址

 

89   #ifdef CONFIG_CMDLINE_TAG

      char *commandline = getenv ("bootargs");

#endif

如果在include/configs/<boardname>.h定义了CONFIG_CMDLINE_TAG则将bootargs环境变量传递给内核。所以如果发现无法向内核传递参数,应该检查一下CONFIG_CMDLINE_TAG是否定义。

 

93   theKernel = (void (*)(int, int,uint))ntohl(hdr->ih_ep);

hdr为指向imageheader的指针,hdr->ih_ep就是我们用mkimage创建image-e选项的参数:内核的入口地址。

 

98207行为处理bootm命令传递的initrd参数。包括判断bootm是否传递了initrd参数,检验initrd的有效性(幻数,校验和等)

 

下面这一段代码在内核启动前,向内核传递参数(以Tag标记的形式),这段代码依赖于很多的宏定义,比如CONFIG_CMDLINE_TAG等,它们通常定义在include/configs/<boardname>.h中,所以如果要想u-boot给内核传递特定的标记,则必须定义相应的宏。传递标记是通过setup_<tagname>_tag函数完成的,具体可以参考cmd_boot.m里面的实现。

#if defined (CONFIG_SETUP_MEMORY_TAGS) ||

   defined (CONFIG_CMDLINE_TAG) ||

   defined (CONFIG_INITRD_TAG) ||

   defined (CONFIG_SERIAL_TAG) ||

   defined (CONFIG_REVISION_TAG) ||

   defined (CONFIG_LCD) ||

   defined (CONFIG_VFD)

      setup_start_tag (bd);

#ifdef CONFIG_SERIAL_TAG

      setup_serial_tag(&params);

#endif

 

#ifdef CONFIG_REVISION_TAG

      setup_revision_tag(&params);

#endif

 

#ifdef CONFIG_SETUP_MEMORY_TAGS

      setup_memory_tags (bd);

#endif

 

#ifdef CONFIG_CMDLINE_TAG

      setup_commandline_tag (bd, commandline);

#endif

 

#ifdef CONFIG_INITRD_TAG

      if (initrd_start &&initrd_end)

             setup_initrd_tag (bd, initrd_start,initrd_end);

#endif

 

#if defined (CONFIG_VFD) || defined(CONFIG_LCD)

      setup_videolfb_tag ((gd_t *) gd);

#endif

      setup_end_tag (bd);

#endif

 

      

      printf ("nStarting kernel ...nn");

 

#ifdef CONFIG_USB_DEVICE

      {

             extern void udc_disconnect (void);

             udc_disconnect ();

      }

#endif

 

275 theKernel (0, bd->bi_arch_number,bd->bi_boot_params);

经过一系列的准备,终于到了启动内核的时候了,这里bd->bi_arch_numberbd->bi_boot_params在具体开发板的board_init函数里面初始化,比如对于smdk2410board_init:

106        gd->bd->bi_arch_number =MACH_TYPE_SMDK2410;

107        gd->bd->bi_boot_params =0x30000100;

smdk2410把启动参数放在了0x30000100开始的地方。上面提到的Tag的传递,也是放到这个地址。这点可以从armli
原创粉丝点击