启动参数bootcmd=nand read.jffs2 0x30007FC0 kernel; bootm 0x30007FC0中kernel在哪定义,为什么可以直接引用?针对这个问题展开思考最终定位到了MTD分区的实现。 在u-boot之start_armboot函数分析中提到过实现nand flash的分区。执行run_command("mtdparts default", 0)可以实现分区功能,run_command函数在u-boot之内核是怎么启动的已经详细介绍过,现在只是说明mtdparts命令的执行函数do_jffs2_mtdparts,它位于Cmd_jffs2.c (common)文件下。
1、环境变量的初始化
2、mtdparts default命令分析(实现分区)
3、nand read.jffs2 0x30007FC0 kernel命令中kernel的值
1、环境变量的初始化
环境变量的初始化在u-boot之start_armboot函数分析的时候已经粗略的提及过,但是没有具体分析,现在接着详细分析下,首先是在初始化数组中初始化的环境变量:
env_init, /* initialize environment *///初始化环境变量,采用默认环境变量 by andy
具体的函数为:
int env_init(void) { #if defined(ENV_IS_EMBEDDED)//ENV_IS_EMBEDDED表示环境变量存放在ram中,不存储在flash上 /****此处省略******/ #else /* ENV_IS_EMBEDDED */ gd->env_addr = (ulong)&default_environment[0];//取得默认的环境变量地址 gd->env_valid = 1; //环境变量已经存在标志 #endif /* ENV_IS_EMBEDDED */ return (0); }
接着继续重新定位环境变量,函数如下
/* initialize environment */ env_relocate ();//初始化环境变量,crc有效的话从nand中读取存储的环境变量,否则采用默认的环境变量
对env_relocate分析
void env_relocate (void) { DEBUGF ("%s[%d] offset = 0x%lx ", __FUNCTION__,__LINE__, gd->reloc_off); #ifdef ENV_IS_EMBEDDED /*******省略*********/ #else /* * We must allocate a buffer for the environment */ env_ptr = (env_t *)malloc (CFG_ENV_SIZE);//在RAM中为环境变量的存放分配一个堆区 DEBUGF ("%s[%d] malloced ENV at %p ", __FUNCTION__,__LINE__,env_ptr); #endif /* * After relocation to RAM, we can always use the "memory" functions */ env_get_char = env_get_char_memory;//得到环境变量的地址的函数 if (gd->env_valid == 0) {//如果环境变量在一开始初始化的时候无效,重新定位默认环境变量 #if defined(CONFIG_GTH) || defined(CFG_ENV_IS_NOWHERE) /* Environment not changable */ puts ("Using default environment "); #else puts ("*** Warning - bad CRC, using default environment "); SHOW_BOOT_PROGRESS (-1); #endif if (sizeof(default_environment) > ENV_SIZE) { puts ("*** Error - default environment is too large "); return; } memset (env_ptr, 0, sizeof(env_t)); memcpy (env_ptr->data, default_environment, sizeof(default_environment)); #ifdef CFG_REDUNDAND_ENVIRONMENT env_ptr->flags = 0xFF; #endif env_crc_update (); gd->env_valid = 1; } else { env_relocate_spec ();//从nand中取出有效的数据,如果无效,还是使用默认的环境变量 } gd->env_addr = (ulong)&(env_ptr->data);//取得首个环境变量的地址env_ptr为一个结构体,包含了crc、flags、以及data指针 }
2、mtdparts default命令分析(实现分区)
跟着do_jffs2_mtdparts函数往里看,setenv为设置环境变量函数。
if (argc == 2) {//如果参数个数为2个 if (strcmp(argv[1], "default") == 0) { //默认参数 setenv("mtdids", (char *)mtdids_default); //设置mtdids环境变量 setenv("mtdparts", (char *)mtdparts_default);//设置mtdparts环境变量 setenv("partition", NULL); //设置partition环境变量 mtdparts_init();//分区初始化 by andy return 0; } else if (strcmp(argv[1], "delall") == 0) {//删除所有分区 /* this may be the first run, initialize lists if needed */ mtdparts_init(); setenv("mtdparts", NULL); /* devices_init() calls current_save() */ return devices_init(); } }
继续往里看mtdparts_init函数,这函数比较复杂,先看一下它的调用层次。
mtdparts_init();//分区初始化 by andy parse_mtdids(ids); //添加mtdids到mtdids链表 nand0=nandflash0 parse_mtdparts(parts);//添加分区parts devices_init();//0初始化成功,主要是做了删除所有分区设备的工作 device_parse(p, &p, &dev);//添加分区设备,返回的设备为dev,p为从环境变量取得的字符串 id_find_by_mtd_id(mtd_id, mtd_id_len - 1);//找到parse_mtdids(ids);中添加的mtdids以及名称nandflash0 while (p && (*p != '