U-boot启动内核原理


U-boot启动内核原理
 
 

 

 

ARM平台U-boot启动内核命令如:

bootcmd=bootm 0xc4040014 

 

在./common/cmd_bootm.c文件中,bootm命令对应的do_bootm函数,当分析uImage中信息发现OS是Linux时,调用./lib_arm/armlinux.c文件中的do_bootm_linux函数来启动Linux kernel。

do_bootm函数(bootm命令)分析

image_header_t header;

ulong load_addr = CFG_LOAD_ADDR;              /* Default Load Address */

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

{

……

       if (argc < 2) {

              addr = load_addr;

       } else {

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

       }

//判断运行bootm时是否指定了程序加载地址,若没有则使用默认的加载地址,load_addr在此函数前面是这样定义的: ulong load_addr = CFG_LOAD_ADDR;

……

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

//image  headeru-boot添加的64Byte文件头)复制到header指向的内存。

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

……

           {

              printf ("Bad Magic Number/n");

              SHOW_BOOT_PROGRESS (-1);

              return 1;

           }

       }

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

       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 (-2);

              return 1;

       }

//检查image 文件头headerCRC32校验和。

 

       data = addr + sizeof(image_header_t);

       len  = ntohl(hdr->ih_size);

……

       if (verify) {

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

                     printf ("Bad Data CRC/n");

                     SHOW_BOOT_PROGRESS (-3);

                     return 1;

              }

       }

//检查image 数据部分data的校验和。

 

       len_ptr = (ulong *)data;

#if defined(__PPC__)

       if (hdr->ih_arch != IH_CPU_PPC)

#elif defined(__ARM__)

       if (hdr->ih_arch != IH_CPU_ARM)

#elif defined(__I386__)

       if (hdr->ih_arch != IH_CPU_I386)

……

#else

# error Unknown CPU type

#endif

       {

              printf ("Unsupported Architecture 0x%x/n", hdr->ih_arch);

              SHOW_BOOT_PROGRESS (-4);

              return 1;

       }

//检查image header 中的arch类型是否正确。

 

       switch (hdr->ih_type) {

……

       case IH_TYPE_KERNEL:

              name = "Kernel Image";

              break;

……

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

              SHOW_BOOT_PROGRESS (-5);

              return 1;

       }

//判断image的类型

 

……

       switch (hdr->ih_comp) {

       case IH_COMP_NONE:

……

       case IH_COMP_GZIP:

……

#ifdef CONFIG_BZIP2

……

       default:

……

       }

//根据image所采用的压缩类型,将image解压到hdr->ih_load指向的地址,这个ih_load就是在做内核镜像时mkimage中的-a选项指定的地址,-a选项指定的是内核解压后的地址。

……

       switch (hdr->ih_os) {

       default:                  /* handled by (original) Linux case */

       case IH_OS_LINUX:

……

#ifdef CONFIG_RAW_FLASH_PART

              /* for raw flash partition */

           init_bd_kdcpart();

#endif

           do_bootm_linux  (cmdtp, flag, argc, argv,

                          addr, len_ptr, verify);              

           break;

……

       }

//内核已经解压完了,接下来启动Linux内核,把控制权传递给了do_bootm_linux函数。

 

 

 

do_bootm_linux函数分析

void do_bootm_linux (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[],

                   ulong addr, ulong *len_ptr, int verify)

{

……

       ulong initrd_start, initrd_end;          // initrd的起始地址和结束地址

       ulong data;

       void (*theKernel)(int zero, int arch, uint params);

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

       image_header_t *hdr = &header;

       bd_t *bd = gd->bd;

#ifdef CONFIG_CMDLINE_TAG

       char *commandline = getenv ("bootargs");

#endif

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

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

// hdr为指向image header的指针,hdr->ih_ep就是我们用mkimage创建image-e选项的参数:内核的入口地址。把函数地址hdr->ih_epEntry Point Address)赋给theKernel

……

#ifdef CONFIG_INITRD_TAG

        if (initrd_start && initrd_end)

                setup_initrd_tag (bd, initrd_start, initrd_end);

#endif

……

       memcpy((void *)(bd->bi_boot_params + BD_OFFSET), (const void *)bd, sizeof(bd_t));

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

//给内核传参数(含根文件系统地址)。这里bd->bi_arch_numberbd->bi_boot_params在具体开发板的board_init函数里面初始化

       gd->bd->bi_arch_number = 387;

       /* adress of boot parameters */

       gd->bd->bi_boot_params = 0x00000100;

       gd->flags = 0;

}

你可能感兴趣的:(U-boot启动内核原理)