您的位置:首页 > 其它

uboot 环境变量设置研究

2015-07-29 16:30 363 查看
首先要知道uboot的第二个阶段是从libarm/board.c开始的,

void start_armboot (void),这个函数是检查flash上的环境变量是否有效,下面的代码中的init_sequence就是初始化列表

for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {
if ((*init_fnc_ptr)() != 0) {
hang ();
}
}
init_fnc_t *init_sequence[] = {
cpu_init,		/* basic cpu dependent setup */
#if defined(CONFIG_SKIP_RELOCATE_UBOOT)
reloc_init,		/* Set the relocation done flag, must
do this AFTER cpu_init(), but as soon
as possible */
#endif
board_init,		/* basic board dependent setup */
interrupt_init,		/* set up exceptions */
env_init,		/* initialize environment */
init_baudrate,		/* initialze baudrate settings */
serial_init,		/* serial communications setup */
console_init_f,		/* stage 1 init of console */
#ifndef CONFIG_DIS_BOARD_INFO
display_banner,		/* say that we are here */
#if defined(CONFIG_DISPLAY_CPUINFO)
print_cpuinfo,		/* display cpu info (and speed) */
#endif
#if defined(CONFIG_DISPLAY_BOARDINFO)
checkboard,		/* display board info */
#endif
#endif
#if defined(CONFIG_HARD_I2C) || defined(CONFIG_SOFT_I2C)
init_func_i2c,
#endif
dram_init,		/* configure available RAM banks */
display_dram_config,
NULL,
};

env_init会找到很多,我用的板子nandflash,所以那些flash,nowhere,auto,onenand,nvram,都可以忽略

仔细看下面的代码, ENV_IS_EMBEDDED是把环境变量嵌入到代码段,这个没有配置,所以直接运行

 gd->env_addr  = (ulong)&default_environment[0];

 gd->env_valid = 1;

int env_init(void)
{
#if defined(ENV_IS_EMBEDDED)
size_t total;
int crc1_ok = 0, crc2_ok = 0;
env_t *tmp_env1, *tmp_env2;

total = CFG_ENV_SIZE;

tmp_env1 = env_ptr;
tmp_env2 = (env_t *)((ulong)env_ptr + CFG_ENV_SIZE);

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)
gd->env_valid = 0;
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;
}

if (gd->env_valid == 1)
env_ptr = tmp_env1;
else if (gd->env_valid == 2)
env_ptr = tmp_env2;
#else /* ENV_IS_EMBEDDED */
gd->env_addr  = (ulong)&default_environment[0];
gd->env_valid = 1;
#endif /* ENV_IS_EMBEDDED */

return (0);
}


接着board.c往下走,来到

 /* initialize environment */

 env_relocate ();

void env_relocate (void)
{
DEBUGF ("%s[%d] offset = 0x%lx\n", __FUNCTION__,__LINE__,
gd->reloc_off);//gd->reloc_off结果是0

#ifdef CONFIG_AMIGAONEG3SE
enable_nvram();
#endif

#ifdef ENV_IS_EMBEDDED
/*
* The environment buffer is embedded with the text segment,
* just relocate the environment pointer
*/
env_ptr = (env_t *)((ulong)env_ptr + gd->reloc_off);
DEBUGF ("%s[%d] embedded ENV at %p\n", __FUNCTION__,__LINE__,env_ptr);
#else
/*
* We must allocate a buffer for the environment
*/
env_ptr = (env_t *)malloc (CFG_ENV_SIZE);
DEBUGF ("%s[%d] malloced ENV at %p\n", __FUNCTION__,__LINE__,env_ptr);//新开辟的空间地址:0xc3f7d2a0
#endif

if (gd->env_valid == 0) {//上个步骤已经置为1
#if defined(CONFIG_GTH)	|| defined(CFG_ENV_IS_NOWHERE)	/* Environment not changable */
puts ("Using default environment\n\n");
#else
puts ("*** Warning - bad CRC, using default environment\n\n");
show_boot_progress (-60);
#endif
set_default_env();
}
else {
env_relocate_spec ();//跟踪这个函数
}
gd->env_addr = (ulong)&(env_ptr->data);

#ifdef CONFIG_AMIGAONEG3SE
disable_nvram();
#endif
}

这个函数首先会读取flash的 环境变量,若读取失败或者读到的大小不对会用默认的环境变量

先看看nand_read的定义

static inline int nand_read(nand_info_t *info, off_t ofs, size_t *len, u_char *buf)

{

 return info->read(info, ofs, *len, (size_t *)len, buf);

}

int (*read) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);

可以理解为从nand[0](第一块nandflash)的偏移 CFG_ENV_OFFSET读数据, 返回值:total, (u_char*)env_ptr,

env_ptr是下面的结构体,包含三个东西,都是

typedef struct environment_s {
uint32_t crc; /* CRC32 over data bytes */
#ifdef CFG_REDUNDAND_ENVIRONMENT
unsigned char flags; /* active/obsolete flags */
#endif
unsigned char data[ENV_SIZE]; /* Environment data */
} env_t;

#define CFG_ENV_OFFSET      0x00100000//0x00080000

#define CFG_ENV_SIZE      0x4000 /* 0x8000//Total Size of Environment Sector */

void env_relocate_spec (void)
{
#if !defined(ENV_IS_EMBEDDED)
size_t total;
int ret;

total = CFG_ENV_SIZE;
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();
#endif /* ! ENV_IS_EMBEDDED */
}

用default env,就是填充env_ptr的data区域,并把flags置为0xFF,计算crc放入env_ptr的crc区域,flags是什么东东,下次更新????
void set_default_env(void)
{
if (sizeof(default_environment) > 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,
sizeof(default_environment));
#ifdef CFG_REDUNDAND_ENVIRONMENT
env_ptr->flags = 0xFF;
#endif
env_crc_update ();
gd->env_valid = 1;
}


下面的read是在哪里实现的呢?

首先记住mtd_info 和 nand_info_t是相等的

typedef struct mtd_info nand_info_t;

extern int nand_curr_device;
extern nand_info_t nand_info[];

static inline int nand_read(nand_info_t *info, off_t ofs, size_t *len, u_char *buf)
{
return info->read(info, ofs, *len, (size_t *)len, buf);
}

到drivers/mtd/nand/找到nand_base.c

看到如下代码:原来read就是nand_read

 int nand_scan_tail(struct mtd_info *mtd)
/* Fill in remaining MTD driver data */
mtd->type = MTD_NANDFLASH;
mtd->flags = MTD_CAP_NANDFLASH;
mtd->ecctype = MTD_ECC_SW;
mtd->erase = nand_erase;
mtd->point = NULL;
mtd->unpoint = NULL;
mtd->read = nand_read;
mtd->write = nand_write;
mtd->read_oob = nand_read_oob;
mtd->write_oob = nand_write_oob;
mtd->sync = nand_sync;
mtd->lock = NULL;
mtd->unlock = NULL;
mtd->suspend = nand_suspend;
mtd->resume = nand_resume;
mtd->block_isbad = nand_block_isbad;
mtd->block_markbad = nand_block_markbad;


int nand_read(struct mtd_info *mtd, loff_t from, size_t len,
size_t *retlen, uint8_t *buf)
{
struct nand_chip *chip = mtd->priv;
int ret;

/* Do not allow reads past end of device */
if ((from + len) > mtd->size)
return -EINVAL;
if (!len)
return 0;

nand_get_device(chip, mtd, FL_READING);

chip->ops.len = len;
chip->ops.datbuf = buf;
chip->ops.oobbuf = NULL;

ret = nand_do_read_ops(mtd, from, &chip->ops);

*retlen = chip->ops.retlen;

nand_release_device(mtd);

return ret;
}


这个/drivers/mtd/nand/nand_base.c由内核的/drivers/mtd/nand/nand_base.c移植而来

nand_base中 s3c_nand_write_page_8bit等等 s3c_nand_XX 这个函数定义在 /cpu/s5pv210/nand.c中。要支持硬件ECC,必须保证uboot和linux内核的ecc校验模式和算法一致,这个nand.c就由内核的/drivers/mtd/nand/s3c_nand.c移植而来

分析ECC模式和FLASH操作内容比较多,就要再写一篇文章了,本文暂不讨论这些,目前项目用到的存储器为emmc,若涉及到nandflash再来分析




内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: