u-boot 1.1.6分析:start_armboot()分析二

四、其余部分初始化

  1、Nor flash初始化

    (1)这里由于未添加开发板对应型号Nor flash,所以读到的大小为0

  size = flash_init();
  display_flash_config(size);

  2、对u-boot的malloc区域清零

  mem_malloc_init (_armboot_start - CFG_MALLOC_LEN);

  3、Nand flash初始化

    puts ("NAND:  ");
    nand_init();       

  4、环境变量的重定向

    (1)env_relocate()定义在/common/env_common.c文件中。

    (2)env_relocate_spec()定义在/common/env_nand.c文件中

  void env_relocate_spec (void)
  {
    ulong total = CFG_ENV_SIZE;
    int ret;

    ret = nand_read(&nand_info[0], CFG_ENV_OFFSET, &total, (u_char*)env_ptr);
    if (ret || total != CFG_ENV_SIZE)
      return use_default();

    if (crc32(0, env_ptr->data, ENV_SIZE) != env_ptr->crc)
      return use_default();
  }


  static void use_default()   {     puts ("*** Warning - bad CRC or NAND, using default environment\n\n");     if (default_environment_size > CFG_ENV_SIZE)
    {       puts (
"*** Error - default environment is too large\n\n");       return;     }     memset (env_ptr, 0, sizeof(env_t));     memcpy (env_ptr->data, default_environment, default_environment_size);     env_ptr->crc = crc32(0, env_ptr->data, ENV_SIZE);     gd->env_valid = 1;   }      void env_relocate (void)   {   env_ptr = (env_t *)malloc (CFG_ENV_SIZE); //在malloc区域中分配环境变量的大小   DEBUGF ("%s[%d] malloced ENV at %p\n", __FUNCTION__,__LINE__,env_ptr);     env_get_char = env_get_char_memory; //取得获取特地环境变量的调用函数     env_relocate_spec();  //将环境变量拷贝到malloc区域中     gd->env_addr = (ulong)&(env_ptr->data);   }

  5、在其他一些初始化完成后,就进入死循环,在这个循环中,可以启动Linux内核,可以调用u-boot所提供的命令,还可以自定义一些操作

  for (;;) 
  {
      main_loop ();
  }

 

五、Linux内核启动

  1、根据传进来的mtd环境变量进行分区

    (1)mtdparts命令定义在cmd_jffs2.c文件中。分区命令定义在配置头文件的宏中,而cmd_jffs2.c文件会获取到这些宏,并使用。

    (2)这里将Nand flash分成四个区(nandflash0 - nandflash3),而且由于只有一块Nand flash,所以id为nandflash0。

    (3)所以kernel分区表示的起始地址为 0x00060000,大小为0x00200000,这会在启动内核时使用到。

  #define   MTDIDS_DEFAULT   "nand0=nandflash0"
  #define   MTDPARTS_DEFAULT "mtdparts=nandflash0:256k@0(bootloader)," \
                       "128k(params)," \
                       "2m(kernel)," \
                       "-(root)"

 if (!getenv("mtdparts"))
 {
     run_command("mtdparts default", 0);
 }

  2、获取u-boot的延时时间

 s = getenv ("bootdelay");
 bootdelay = s ? (int)simple_strtol(s, NULL, 10) : CONFIG_BOOTDELAY;

  3、获取到启动命令,并启动内核

    (1)在前面分析,我们已经知道启动命令为“nand read.jffs2 0x30007FC0 kernel; bootm 0x30007FC0”

    (2)nand read.jffs2命令定义在cmd_nand.c文件中,其格式为nand read[.jffs2] addr off size,表示的意思是从NAND FLASH偏移地址off读取size个字节的数据到开始地址为addr的内存中,而后缀.jffs2表示的意思是如果遇到坏块,则跳过坏块。而且不需要页对齐。

        具体展开就是:nand read.jffs2 0x30007FC0 0x00060000 0x00200000

    (3)至于为什么不是0x30008000,是因为Linux内核编译完成,生成镜像,压缩(并在压缩后的头部添加了解压缩代码)生成zImage文件,而在u-boot中,zImage头部还会加入一些头部信息(struct image_header)。所以将内核读到0x30007FC0,这时候加上头部

                          信息的偏移,刚好就是0x30008000,可以加快Linux内核的启动过程。

    (4)bootm命令定义在cmd_bootm.c文件中,其格式为bootm [addr [arg..]],表示启动存放在地址addr处的u-boot格式的映射文件(用mkimage工具制作得到的映像),arg表示参数(可选)。

    (5)从u-boot跳转到Linux内核之前,需要设置一个标签列表,用于向Linux内核传递参数,其格式为struct tag。

 

 s = getenv ("bootcmd");
 
 if (bootdelay >= 0 && s && !abortboot (bootdelay)) 
 {
    printf("Booting Linux ...\n");            
    run_command (s, 0);
 }

//对do_bootm()函数简要分析
int do_bootm(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
{
  ......
  do_bootm_linux(cmdtp, flag, argc, argv, addr, len_ptr, verify);  //该函数定义在/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)
{
  setup_start_tag (bd);              //根据gd->bd中的信息,设置存放标签的起始地址为0x30000100
  setup_memory_tags (bd);             //存放sdram的信息
  setup_commandline_tag (bd, commandline);    //存放"bootargs"信息
  setup_end_tag (bd);               //标签结束
  
  ......
  theKernel = (void (*)(int, int, uint))ntohl(hdr->ih_ep);  //指向0x30008000
  ......
  theKernel (0, bd->bi_arch_number, bd->bi_boot_params);   //运行内核,分别传进三个参数:0,开发板的芯片ID,存放标签列表的地址0x30000100
}

 

 

六、到这里,u-boot就完成了它的工作了,后面的工作是在Linux内核中进行了。

 

posted @ 2019-09-08 00:45  Recca  阅读(230)  评论(0编辑  收藏  举报