DSP

从bootm看u-boot引导内核的过程

2019-07-13 17:48发布

  快乐虾 http://blog.csdn.net/lights_joy/ lights@hb165.com      本文适用于 ADI bf561 DSP 优视BF561EVB开发板 u-boot-1.1.6 (移植到vdsp5) Visual DSP++ 5.0    欢迎转载,但请保留作者信息 我们知道,在u-boot中可以使用bootm这个命令来引导uclinux内核,那么其具体的过程是怎样的呢?

1.1.1   bootm的命令参数

通过help bootm命令可以知道bootm所带的参数,以下内容来自于u-boot/common/cmd-bootm.c U_BOOT_CMD(      bootm,   CFG_MAXARGS,  1,   do_bootm,      "bootm   - boot application image from memory/n",      "[addr [arg ...]]/n    - boot application image stored in memory/n"      "/tpassing arguments 'arg ...'; when booting a Linux kernel,/n"      "/t'arg' can be the address of an initrd image/n" ); 从这里可以知道,bootm后面可以带两个参数,一个是内核所在的地址,这个地址就是通过tftp或者loadx指令下载内核时的存放地址,另一个可以指明initrd所处的位置。

1.1.2   do_bootm

u-boot检测到bootm命令后,它将调用do_bootm这个函数进行内核引导: int do_bootm (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) {      ulong    iflag;      ulong    addr;      ulong    data, len, checksum;      ulong  *len_ptr;      uint unc_len = CFG_BOOTM_LEN;      int  i, verify;      char *name, *s;      int  (*appl)(int, char *[]);      image_header_t *hdr = &header;   /* 1、提取命令行中的地址参数。 */      s = getenv ("verify");      verify = (s && (*s == 'n')) ? 0 : 1;        if (argc < 2) {          addr = load_addr;      } else {          addr = simple_strtoul(argv[1], NULL, 16);      }        SHOW_BOOT_PROGRESS (1);      printf ("## Booting image at %08lx .../n", addr);        /* Copy header so we can blank CRC field for re-calculation */      memmove (&header, (char *)addr, sizeof(image_header_t));   /* 2、检测内核文件头的签名是否有效。 */      if (ntohl(hdr->ih_magic) != IH_MAGIC) {          {          puts ("Bad Magic Number/n");          SHOW_BOOT_PROGRESS (-1);          return 1;          }      }      SHOW_BOOT_PROGRESS (2);   /* 3、通过CRC校验确定文件是否损坏。 */      data = (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 Checksum/n");          SHOW_BOOT_PROGRESS (-2);          return 1;      }      SHOW_BOOT_PROGRESS (3);   /* 4、输出内核文件头的信息。 */      /* for multi-file images we need the data part, too */      print_image_hdr ((image_header_t *)addr);        data = 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 CRC/n");               SHOW_BOOT_PROGRESS (-3);               return 1;          }          puts ("OK/n");      }      SHOW_BOOT_PROGRESS (4);   /* 5、检验内核是否为此ARCH编译的。 */      len_ptr = (ulong *)data;        if (hdr->ih_arch != IH_CPU_BLACKFIN)      {          printf ("Unsupported Architecture 0x%x/n", hdr->ih_arch);          SHOW_BOOT_PROGRESS (-4);          return 1;      }      SHOW_BOOT_PROGRESS (5);   /* 6、判断文件类型,对于uclinux内核,其值为IH_TYPE_KERNEL */      switch (hdr->ih_type) {      case IH_TYPE_STANDALONE:          name = "Standalone Application";          /* A second argument overwrites the load address */          if (argc > 2) {               hdr->ih_load = htonl(simple_strtoul(argv[2], NULL, 16));          }          break;      case IH_TYPE_KERNEL:          name = "Kernel Image";          break;      case IH_TYPE_MULTI:          name = "Multi-File Image";          len  = ntohl(len_ptr[0]);          /* OS kernel is always the first image */          data += 8; /* kernel_len + terminator */          for (i=1; len_ptr[i]; ++i)               data += 4;          break;      default: printf ("Wrong Image Type for %s command/n", cmdtp->name);          SHOW_BOOT_PROGRESS (-5);          return 1;      }      SHOW_BOOT_PROGRESS (6);        /*       * We have reached the point of no return: we are going to       * overwrite all exception vector code, so we cannot easily       * recover from any failures any more...       */ /* 7、将内核解压缩到文件头中指定的Load Address,从这里也可以知道,下载地址和文件头中的LoadAddress之间应该有足够的空间,否则将造成解压缩的失败。 */        iflag = disable_interrupts();        switch (hdr->ih_comp) {      case IH_COMP_NONE:          if(ntohl(hdr->ih_load) == addr) {               printf ("   XIP %s ... ", name);          } else {               memmove ((void *) ntohl(hdr->ih_load), (uchar *)data, len);          }          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/n");               SHOW_BOOT_PROGRESS (-6);               do_reset (cmdtp, flag, argc, argv);          }          break;      default:          if (iflag)               enable_interrupts();          printf ("Unimplemented compression type %d/n", hdr->ih_comp);          SHOW_BOOT_PROGRESS (-7);          return 1;      }      puts ("OK/n");      SHOW_BOOT_PROGRESS (7);   /* 8、由于引导的是内核,跳过本段代码。 */      switch (hdr->ih_type) {      case IH_TYPE_STANDALONE:          if (iflag)               enable_interrupts();            /* load (and uncompress), but don't start if "autostart"           * is set to "no"           */          if (((s = getenv("autostart")) != NULL) && (strcmp(s,"no") == 0)) {               char buf[32];               sprintf(buf, "%lX", len);               setenv("filesize", buf);               return 0;          }          appl = (int (*)(int, char *[]))ntohl(hdr->ih_ep);          (*appl)(argc-1, &argv[1]);          return 0;      case IH_TYPE_KERNEL:      case IH_TYPE_MULTI:          /* handled below */          break;      default:          if (iflag)               enable_interrupts();          printf ("Can't boot image type %d/n", hdr->ih_type);          SHOW_BOOT_PROGRESS (-8);          return 1;      }      SHOW_BOOT_PROGRESS (8);   /* 9、调用相应的函数进行内核引导。 */      switch (hdr->ih_os) {