Welcome 微信登录

首页 / 操作系统 / Linux / bootm命令分析

bootm命令函数do_bootm位于Cmd_bootm.c,其流程为:确定是否要校验uImage和ramdisk里的数据,默认校验,若想不校验:设置了环境变量verify=n。 s = getenv ("verify");
 verify = (s && (*s == "n")) ? 0 : 1;判断命令是否制定了 操作系统 的加载地址。如果没有,使用默认地址CFG_LOAD_ADDR,一般CFG_LOAD_ADDR可以在include/configs文件夹自己单板的配置文件里配置。if (argc < 2) {
  addr = load_addr;
 } else {
  addr = simple_strtoul(argv[1], NULL, 16);
 }
根据image 加载地址是在 flash还是内存,获取image的 头信息。#ifdef CONFIG_HAS_DATAFLASH
 if (addr_dataflash(addr)){
  read_dataflash(addr, sizeof(image_header_t), (char *)&header);
 } else
#endif
 memmove (&header, (char *)addr, sizeof(image_header_t));
校验头里的MAGIC NUM和CRC是否正确,头部的CRC计算内容是 :头部64B,且头部CRC处按内容0来计算。if (ntohl(hdr->ih_magic) != IH_MAGIC) {
     {  .............................................

  puts ("Bad Magic Number ");
  SHOW_BOOT_PROGRESS (-1);
  return 1;
     }
 }
);  .............................................
 if (crc32 (0, (uchar *)data, len) != checksum) {
  puts ("Bad Header Checksum ");
  SHOW_BOOT_PROGRESS (-2);
  return 1;
 } 根据image type进行不同的处理,如果是linux kernel后面再处理: switch (hdr->ih_type) {  .............................................
  case IH_TYPE_KERNEL:
  name = "Kernel Image";
  break; .............................................

 }
判断压缩类型,做不同拷贝处理。
未压缩:
如果镜像中load地址与第一个参数一致的话,意思是内核已经在loadaddr准备好了,无需处理。
如果镜像中load地址与第一个参数不一致的话,就要从传递的地址拷贝到 image指定的loadaddr(hdr->ih_load)了。如果是压缩类型gzip或者bzip2:就调用相应解压缩函数,将镜像解压到image指定的loadaddr(hdr->ih_load)了。默认预留解压后的大小为8M。当然这个空间大小可以使用这个宏定义CFG_BOOTM_LEN来修改 switch (hdr->ih_comp) {
 case IH_COMP_NONE:
  if(ntohl(hdr->ih_load) == addr) {
   printf ("   XIP %s ... ", name);
  } else {
#if defined(CONFIG_HW_WATCHDOG) || defined(CONFIG_WATCHDOG)
   size_t l = len;
   void *to = (void *)ntohl(hdr->ih_load);
   void *from = (void *)data;   printf ("   Loading %s ... ", name);   while (l > 0) {
    size_t tail = (l > CHUNKSZ) ? CHUNKSZ : l;
    WATCHDOG_RESET();
    memmove (to, from, tail);
    to += tail;
    from += tail;
    l -= tail;
   }
#else /* !(CONFIG_HW_WATCHDOG || CONFIG_WATCHDOG) */
   memmove ((void *) ntohl(hdr->ih_load), (uchar *)data, len);
#endif /* CONFIG_HW_WATCHDOG || CONFIG_WATCHDOG */
  }
  break;
 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 to recover ");
   SHOW_BOOT_PROGRESS (-6);
   do_reset (cmdtp, flag, argc, argv);
  }
  break;
 .............................................

 }判断如果是内核,暂时不用处理
 switch (hdr->ih_type) {
 .............................................
 case IH_TYPE_KERNEL:
 case IH_TYPE_MULTI:
  /* handled below */
  break; 根据镜像的不同类型,调用不同的操作系统启动函数。
 switch (hdr->ih_os) {
 default:   /* handled by (original) Linux case */
 case IH_OS_LINUX:
#ifdef CONFIG_SILENT_CONSOLE
     fixup_silent_linux();
#endif
     do_bootm_linux  (cmdtp, flag, argc, argv,
        addr, len_ptr, verify);
     break; .............................................
如果linux操作系统就调用do_bootm_linux ,其流程为:如果定义了CONFIG_CMDLINE_TAG,就从环境变量取出bootargs,准备传参数给内核。#ifdef CONFIG_CMDLINE_TAG
 char *commandline = getenv ("bootargs");
#endif 从镜像文件的头里提取entry point,即内核的入口地址。 theKernel = (void (*)(int, int, uint))ntohl(hdr->ih_ep); 确认命令是否传递了initrd地址,如果有进行相应的处理校验ramdisk的magic num和头的CRC
打印头并校验数据CRC/*
  * Check if there is an initrd image
  */
 if (argc >= 3) { .............................................}根据配置,准备向内核传递相应的参数。setup_end_tag (bd);
#endif关闭cache和中断,启动内核。bd->bi_boot_params:传递给内核参数地址。tag类型
bd->bi_arch_number:CPU类型
在各自单板的board_init函数中初始化。 cleanup_before_linux (); theKernel (0, bd->bi_arch_number, bd->bi_boot_params);