uboot中nand flash代码分析(2)

本例中,nand flash BBT(Bad Block Table)的建立是在读取环境变量时建立的。
先看下uboot环境变量的处理流程
start_armboot()                 arch/arm/lib/board.c
    -->init_sequence[]         arch/arm/lib/board.c
-->env_init()                       common/env_nand.c
-->env_relocate()              common/env_common.c
-->env_relocate_spec()   common/env_nand.c
 
主要涉及三个函数env_init()、env_relocate()和env_relocate_spec()
int env_init(void)
{
	gd->env_addr  = (ulong)&default_environment[0];//先指向默认的环境变量数组
	gd->env_valid = 1;
}	


本函数实际代码中会涉及ENV_IS_EMBEDDED和CONFIG_NAND_ENV_DST两个宏定义,其含义可以参考代码中的注释,一般不会用到。

void env_relocate (void)
{
	if (gd->env_valid == 0) {
		set_default_env();
	}
	else {
		env_relocate_spec ();
	}
	gd->env_addr = (ulong)&(env_ptr->data);
}

env_relocate()函数会调用env_relocate_spec()。
查看common/env_nand.c,common/env_dataflash.c,common/env_eeprom.c,common/env_sf.c文件
会发现这些文件中都含有env_get_char_spec()、saveenv()、env_init()、env_relocate_spec()函数,
可以推断出common/env_common.c文件向u-boot提供通用的函数接口,
它们隐藏了env的不同实现方式,比如dataflash, epprom, nand,spiflash等,
而common/env_nand.c,common/env_nand.c,common/env_eeprom.c,common/env_sf.c则是env在具体设备上的实现


nandflash 一般会保存两次环境变量
void env_relocate_spec (void)
{
	int crc1_ok = 0, crc2_ok = 0;
	env_t *tmp_env1, *tmp_env2;


	tmp_env1 = (env_t *) malloc(CONFIG_ENV_SIZE);//分配内存空间用于存放第一块环境变量
	tmp_env2 = (env_t *) malloc(CONFIG_ENV_SIZE);//分配内存空间用于存放第二块环境变量


	if ((tmp_env1 == NULL) || (tmp_env2 == NULL)) {
		puts("Can't allocate buffers for environment\n");
		free (tmp_env1);
		free (tmp_env2);
		return use_default();
	}


	if (readenv(CONFIG_ENV_OFFSET, (u_char *) tmp_env1))//从nand flash中读取第一块环境变量到tmp_env1,该函数会进行BBT的扫描
		puts("No Valid Environment Area Found\n");
	if (readenv(CONFIG_ENV_OFFSET_REDUND, (u_char *) tmp_env2))//从nand flash中读取第一块环境变量到tmp_env2
		puts("No Valid Reundant Environment Area Found\n");
	
	//计算crc,并和读取到的crc比较。nandflash保存环境变量的区域,
	//除了实际的环境变量之外,还含有crc值和flags。可以参见environment_s数据结构
	crc1_ok = (crc32(0, tmp_env1->data, ENV_SIZE) == tmp_env1->crc);
	crc2_ok = (crc32(0, tmp_env2->data, ENV_SIZE) == tmp_env2->crc);


	//判断使用第几块环境变量
	if(!crc1_ok && !crc2_ok) {
		free(tmp_env1);
		free(tmp_env2);
		return use_default();//crc都不对,就用默认的环境变量
	} else if(crc1_ok && !crc2_ok)
		gd->env_valid = 1;
	else if(!crc1_ok && crc2_ok)
		gd->env_valid = 2;
	else {
		/* both ok - check serial */
		if(tmp_env1->flags == 255 && tmp_env2->flags == 0)
			gd->env_valid = 2;
		else if(tmp_env2->flags == 255 && tmp_env1->flags == 0)
			gd->env_valid = 1;
		else if(tmp_env1->flags > tmp_env2->flags)
			gd->env_valid = 1;
		else if(tmp_env2->flags > tmp_env1->flags)
			gd->env_valid = 2;
		else /* flags are equal - almost impossible */
			gd->env_valid = 1;


	}


	free(env_ptr);
 	if(gd->env_valid == 1) {
		env_ptr = tmp_env1;
		free(tmp_env2);
	} else {
		env_ptr = tmp_env2;
		free(tmp_env1);
	}


}


函数返回后,gd->env_addr 等于 (ulong)&(env_ptr->data);
环境变量就被读到RAM中,以后访问环境变量就可以通过全局变量gd->env_addr进行访问
uchar env_get_char_spec (int index)
{
	return ( *((uchar *)(gd->env_addr + index)) );
}




下面分析readenv()函数,了解下flash BBT的建立流程

int readenv (size_t offset, u_char * buf)
{
	size_t end = offset + CONFIG_ENV_RANGE;
	size_t amount_loaded = 0;
	size_t blocksize, len;


	u_char *char_ptr;
	int ret;
	blocksize = nand_info[0].erasesize;//获取nand flash的块大小
	if (!blocksize)
	{
		printf("readenv blocksize = 0\n");
		return 1;
	}
	len = min(blocksize, CONFIG_ENV_SIZE);//如果环境变量的大小大于一个块的大小,则一块一块的读取


	while (amount_loaded < CONFIG_ENV_SIZE && offset < end) {
		//判断是否是坏块,是则读取下一块。第一次调用该函数时,会建立BBT
		if (nand_block_isbad(&nand_info[0], offset)) {
			offset += blocksize;
		} else {




			char_ptr = &buf[amount_loaded];
			//从nand flash中读取数据,偏移地址offset,读取长度len,保存地址char_ptr
			if (ret = nand_read(&nand_info[0], offset, &len, char_ptr))
			{
				printf("readenv nand_read ret = %d\n",ret);
				return 1;
			}
			//调整偏移地址
			offset += blocksize;
			//调整保存地址
			amount_loaded += len;
		  printf("readenv 2 amount_loaded = %d\n",amount_loaded);
		}
	}
	if (amount_loaded != CONFIG_ENV_SIZE)
	{
		printf("readenv amount_loaded = %d\n",amount_loaded);
		return 1;
	}
	return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值