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内核中进行了。