u-boot于内核的关系

来源:互联网 发布:easybcd ubuntu 编辑:程序博客网 时间:2024/06/08 11:08

http://linux.chinaunix.net/techdoc/system/2007/08/07/964687.shtml


U-Boot作为Bootloader,具备多种引导内核启动的方式。常用的go和bootm命令可以直接引导内核映像启动。U-Boot与内核的关系主要是内核启动过程中参数的传递。
1.go命令的实现

/* common/cmd_boot.c  */
int do_go (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
{
       ulong addr, rc;
       int     rcode = 0;
       if (argc 
              printf ("Usage:\n%s\n", cmdtp->usage);
              return 1;
       }
       addr = simple_strtoul(argv[1], NULL, 16);
       printf ("## Starting application at 0x%08lX ...\n", addr);
       /*
        * pass address parameter as argv[0] (aka command name),
        * and all remaining args
        */
       rc = ((ulong (*)(int, char *[]))addr) (--argc, &argv[1]);
       if (rc != 0) rcode = 1;

       printf ("## Application terminated, rc = 0x%lX\n", rc);
       return rcode;
}

go命令调用do_go()函数,跳转到某个地址执行的。如果在这个地址准备好了自引导的内核映像,就可以启动了。尽管go命令可以带变参,实际使用时一般不用来传递参数。
2.bootm命令的实现

/* common/cmd_bootm.c */
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 = 0x400000;
       int   i, verify;
       char  *name, *s;
       int   (*appl)(int, char *[]);
       image_header_t *hdr = &header;

       s = getenv ("verify");
       verify = (s && (*s == 'n')) ? 0 : 1;
       if (argc 
              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));
       if (ntohl(hdr->ih_magic) != IH_MAGIC)
       {
              puts ("Bad Magic Number\n");
              SHOW_BOOT_PROGRESS (-1);
              return 1;
       }
       SHOW_BOOT_PROGRESS (2);
       data = (ulong)&header;
       len  = sizeof(image_header_t);

       checksum = ntohl(hdr->ih_hcrc);
       hdr->ih_hcrc = 0;

       if(crc32 (0, (char *)data, len) != checksum) {
              puts ("Bad Header Checksum\n");
              SHOW_BOOT_PROGRESS (-2);
              return 1;
       }
       SHOW_BOOT_PROGRESS (3);
       /* 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, (char *)data, len) != ntohl(hdr->ih_dcrc)) {
                     printf ("Bad Data CRC\n");
                     SHOW_BOOT_PROGRESS (-3);
                     return 1;
              }
              puts ("OK\n");
       }
       SHOW_BOOT_PROGRESS (4);
       len_ptr = (ulong *)data;
……
       switch (hdr->ih_os) {
       default:                /* handled by (original) Linux case */
       case IH_OS_LINUX:
             do_bootm_linux  (cmdtp, flag, argc, argv,
                        addr, len_ptr, verify);
             break;
       ……
}

bootm命令调用do_bootm函数。这个函数专门用来引导各种操作系统映像,可以支持引导Linux、vxWorks、QNX等操作系统。引导Linux的时候,调用do_bootm_linux()函数。
3.do_bootm_linux函数的实现

/* lib_arm/armlinux.c */
void do_bootm_linux (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[],
                   ulong addr, ulong *len_ptr, int verify)
{
       DECLARE_GLOBAL_DATA_PTR;
       ulong len = 0, checksum;
       ulong initrd_start, initrd_end;
       ulong data;
       void (*theKernel)(int zero, int arch, uint params);
       image_header_t *hdr = &header;
       bd_t *bd = gd->bd;
#ifdef CONFIG_CMDLINE_TAG
       char *commandline = getenv ("bootargs");
#endif
       theKernel = (void (*)(int, int, uint))ntohl(hdr->ih_ep);
       /* Check if there is an initrd image */
       if(argc >= 3) {
              SHOW_BOOT_PROGRESS (9);
              addr = simple_strtoul (argv[2], NULL, 16);
              printf ("## Loading Ramdisk Image at %08lx ...\n", addr);
              /* Copy header so we can blank CRC field for re-calculation */
              memcpy (&header, (char *) addr, sizeof (image_header_t));
              if (ntohl (hdr->ih_magic) != IH_MAGIC) {
                      printf ("Bad Magic Number\n");
                      SHOW_BOOT_PROGRESS (-10);
                      do_reset (cmdtp, flag, argc, argv);
              }
              data = (ulong) & header;
              len = sizeof (image_header_t);
              checksum = ntohl (hdr->ih_hcrc);
              hdr->ih_hcrc = 0;
              if(crc32 (0, (char *) data, len) != checksum) {
                     printf ("Bad Header Checksum\n");
                     SHOW_BOOT_PROGRESS (-11);
                     do_reset (cmdtp, flag, argc, argv);
              }
              SHOW_BOOT_PROGRESS (10);
              print_image_hdr (hdr);
              data = addr + sizeof (image_header_t);
              len = ntohl (hdr->ih_size);
              if(verify) {
                     ulong csum = 0;
                     printf ("   Verifying Checksum ... ");
                     csum = crc32 (0, (char *) data, len);
                     if (csum != ntohl (hdr->ih_dcrc)) {
                            printf ("Bad Data CRC\n");
                            SHOW_BOOT_PROGRESS (-12);
                            do_reset (cmdtp, flag, argc, argv);
                     }
                     printf ("OK\n");
              }
              SHOW_BOOT_PROGRESS (11);
              if ((hdr->ih_os != IH_OS_LINUX) ||
                     (hdr->ih_arch != IH_CPU_ARM) ||
                     (hdr->ih_type != IH_TYPE_RAMDISK)) {
                     printf ("No Linux ARM Ramdisk Image\n");
                     SHOW_BOOT_PROGRESS (-13);
                     do_reset (cmdtp, flag, argc, argv);
              }
              /* Now check if we have a multifile image */
       } else if ((hdr->ih_type == IH_TYPE_MULTI) && (len_ptr[1])) {
               ulong tail = ntohl (len_ptr[0]) % 4;
               int i;
               SHOW_BOOT_PROGRESS (13);
               /* skip kernel length and terminator */
               data = (ulong) (&len_ptr[2]);
               /* skip any additional image length fields */
               for (i = 1; len_ptr; ++i)
                       data += 4;
              /* add kernel length, and align */
              data += ntohl (len_ptr[0]);
              if (tail) {
                       data += 4 - tail;
              }
              len = ntohl (len_ptr[1]);
       } else {
               /* no initrd image */
              SHOW_BOOT_PROGRESS (14);
              len = data = 0;
       }
       if (data) {
               initrd_start = data;
               initrd_end = initrd_start + len;
       } else {
               initrd_start = 0;
               initrd_end = 0;
       }
       SHOW_BOOT_PROGRESS (15);
       debug ("## Transferring control to Linux (at address %08lx) ...\n",
               (ulong) theKernel);
#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
      setup_end_tag (bd);
#endif
      /* we assume that the kernel is in place */
      printf ("\nStarting kernel ...\n\n");
      cleanup_before_linux ();

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

do_bootm_linux()函数是专门引导Linux映像的函数,它还可以处理ramdisk文件系统的映像。这里引导的内核映像和ramdisk映像,必须是U-Boot格式的。U-Boot格式的映像可以通过mkimage工具来转换,其中包含了U-Boot可以识别的符号。

原创粉丝点击