uboot 环境变量设置研究
2015-07-29 16:30
363 查看
首先要知道uboot的第二个阶段是从libarm/board.c开始的,
void start_armboot (void),这个函数是检查flash上的环境变量是否有效,下面的代码中的init_sequence就是初始化列表
env_init会找到很多,我用的板子nandflash,所以那些flash,nowhere,auto,onenand,nvram,都可以忽略
仔细看下面的代码, ENV_IS_EMBEDDED是把环境变量嵌入到代码段,这个没有配置,所以直接运行
gd->env_addr = (ulong)&default_environment[0];
gd->env_valid = 1;
接着board.c往下走,来到
/* initialize environment */
env_relocate ();
这个函数首先会读取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 */
用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是相等的
到drivers/mtd/nand/找到nand_base.c
看到如下代码:原来read就是nand_read
int nand_scan_tail(struct mtd_info *mtd)
这个/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再来分析
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再来分析
相关文章推荐
- ViewPager左右滑动
- const 用法
- 何谓组合事务ID
- 中谷教育05 Python数据类型
- JavaScript常用事件
- composer 报 zlib_decode(): data error
- ubuntu安装 scala
- 移动开发技术资源
- P - Atlantis - hdu1542(求面积)
- 小白学开发(iOS)OC_类的互引用(2015-07-29)
- easyui-combobox下拉多选
- HDU 5326(2015多校3)-Work(dfs)
- 帝国CMS常用函数介绍
- 关于Latex中pdf和eps图片的处理
- 动态链接库
- Map.keySet 和 Map.entrySet 的效率问题
- hdu 5326 work 搜索 2015多校联合训练赛
- mac homebrew 常用命令
- 模式识别 - 处理多个演示样本研究(MIL)特点(matlab)
- Android 中的Shape