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;
}



發佈了24 篇原創文章 · 獲贊 1 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章