想实现的是boot环境变量双备份功能
我现在的代码实现是:
1、配置文件中增加:CONFIG_ENV_OFFSET_REDUND=0x1300000
CONFIG_ENV_RANGE=0x100000
CONFIG_SYS_REDUNDAND_ENVIRONMENT=y
2、在src/env/common.c中修改
void env_relocate(void)
{
#if defined(CONFIG_NEEDS_MANUAL_RELOC)
env_reloc();
env_fix_drivers();
env_htab.change_ok += gd->reloc_off;
#endif
if (gd->env_valid == ENV_INVALID) {
#if defined(CONFIG_ENV_IS_NOWHERE) || defined(CONFIG_SPL_BUILD)
/* Environment not changable */
env_set_default(NULL, 0);
#else
bootstage_error(BOOTSTAGE_ID_NET_CHECKSUM);
env_set_default("bad CRC", 0);
#endif
} else {
env_load();
}
}
为
void env_relocate(void)
{
#if defined(CONFIG_NEEDS_MANUAL_RELOC)
env_reloc();
env_fix_drivers();
env_htab.change_ok += gd->reloc_off;
#endif
if (gd->env_valid == ENV_INVALID) {
#if defined(CONFIG_ENV_IS_NOWHERE) || defined(CONFIG_SPL_BUILD)
/* Environment not changable */
env_set_default(NULL, 0);
#else
bootstage_error(BOOTSTAGE_ID_NET_CHECKSUM);
env_set_default("bad CRC", 0);
#endif
/* 设置默认环境后,将env_flags重置为0 */
#ifdef CONFIG_SYS_REDUNDAND_ENVIRONMENT
//gd->env_valid = ENV_VALID; // 标记内存环境为有效
env_flags = 0;
#endif
} else {
env_load();
}
}
3、在src/env/nand.c文件中
static int env_nand_save(void)
{
int ret = 0;
ALLOC_CACHE_ALIGN_BUFFER(env_t, env_new, 1);
int env_idx = 0;
static const struct nand_env_location location[] = {
{
.name = "NAND",
.erase_opts = {
.length = CONFIG_ENV_RANGE,
.offset = CONFIG_ENV_OFFSET,
},
},
#ifdef CONFIG_ENV_OFFSET_REDUND
{
.name = "redundant NAND",
.erase_opts = {
.length = CONFIG_ENV_RANGE,
.offset = CONFIG_ENV_OFFSET_REDUND,
},
},
#endif
};
if (CONFIG_ENV_RANGE < CONFIG_ENV_SIZE)
return 1;
ret = env_export(env_new);
if (ret)
return ret;
#ifdef CONFIG_ENV_OFFSET_REDUND
env_idx = (gd->env_valid == ENV_VALID);
#endif
ret = erase_and_write_env(&location[env_idx], (u_char *)env_new);
#ifdef CONFIG_ENV_OFFSET_REDUND
if (!ret) {
/* preset other copy for next write */
gd->env_valid = gd->env_valid == ENV_REDUND ? ENV_VALID :
ENV_REDUND;
return ret;
}
env_idx = (env_idx + 1) & 1;
ret = erase_and_write_env(&location[env_idx], (u_char *)env_new);
if (!ret)
printf("Warning: primary env write failed,"
" redundancy is lost!\n");
#endif
return ret;
}
和
#ifdef CONFIG_ENV_OFFSET_REDUND
static int env_nand_load(void)
{
#if defined(ENV_IS_EMBEDDED)
return 0;
#else
int read1_fail, read2_fail;
env_t *tmp_env1, *tmp_env2;
int ret = 0;
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");
env_set_default("malloc() failed", 0);
ret = -EIO;
goto done;
}
read1_fail = readenv(CONFIG_ENV_OFFSET, (u_char *) tmp_env1);
read2_fail = readenv(CONFIG_ENV_OFFSET_REDUND, (u_char *) tmp_env2);
ret = env_import_redund((char *)tmp_env1, read1_fail, (char *)tmp_env2,
read2_fail, H_EXTERNAL);
done:
free(tmp_env1);
free(tmp_env2);
return ret;
#endif /* ! ENV_IS_EMBEDDED */
}
修改为:
static int env_nand_save(void)
{
int ret = 0;
ALLOC_CACHE_ALIGN_BUFFER(env_t, env_new, 1);
int env_idx = 0;
static const struct nand_env_location location[] = {
{
.name = "env_main",
.erase_opts = {
.length = CONFIG_ENV_RANGE,
.offset = CONFIG_ENV_OFFSET,
},
},
#ifdef CONFIG_ENV_OFFSET_REDUND
{
.name = "env_backup",
.erase_opts = {
.length = CONFIG_ENV_RANGE,
.offset = CONFIG_ENV_OFFSET_REDUND,
},
},
#endif
};
if (CONFIG_ENV_RANGE < CONFIG_ENV_SIZE)
return 1;
ret = env_export(env_new);
if (ret)
return ret;
#ifdef CONFIG_ENV_OFFSET_REDUND
// 修复点:使用环境变量自身的flags管理序列号
uint8_t current_flags = env_new->flags; // 获取当前序列号
// 序列号递增并处理回绕
if (current_flags == 255) {
env_new->flags = 1; // 回绕处理:255 → 1
} else {
env_new->flags = current_flags + 1; // 正常递增
}
// 重新计算包含新序列号的CRC
env_new->crc = crc32(0, env_new->data, ENV_SIZE);
/* 确定写入目标分区 */
env_idx = (gd->env_valid == ENV_VALID) ? 1 : 0; // 主分区有效则写入备份,反之亦然
const char *target_name = location[env_idx].name;
const char *fallback_name = location[env_idx ^ 1].name;
printf("Saving Env to %s (flags: %u -> %u)...\n",
target_name, current_flags, env_new->flags);
#else
const char *target_name = location[0].name;
printf("Saving Env to %s...\n", target_name);
#endif
ret = erase_and_write_env(&location[env_idx], (u_char *)env_new);
#ifdef CONFIG_ENV_OFFSET_REDUND
if (!ret) {
/* preset other copy for next write */
gd->env_valid = gd->env_valid == ENV_REDUND ? ENV_VALID :
ENV_REDUND;
printf("Env saved to %s. New flags: %u\n", target_name, env_new->flags);
return 0;
}
/* 首选分区失败:尝试备选分区 */
printf("Warning: %s write failed (%d), trying %s...\n", target_name, ret, fallback_name);
env_idx = (env_idx + 1) & 1;
ret = erase_and_write_env(&location[env_idx], (u_char *)env_new);
if (!ret) {
/* 备选分区写入成功 */
gd->env_valid = (env_idx == 0) ? ENV_VALID : ENV_REDUND;
printf("Env saved to %s (fallback). New flags: %u\n",
fallback_name, env_new->flags);
return 0;
}
#endif
return ret;
}
#ifdef CONFIG_ENV_OFFSET_REDUND
static int env_nand_load(void)
{
#if defined(ENV_IS_EMBEDDED)
return 0;
#else
int read1_fail, read2_fail;
env_t *tmp_env1, *tmp_env2;
int ret = 0;
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");
env_set_default("malloc() failed", 0);
ret = -EIO;
goto done;
}
read1_fail = readenv(CONFIG_ENV_OFFSET, (u_char *) tmp_env1);
read2_fail = readenv(CONFIG_ENV_OFFSET_REDUND, (u_char *) tmp_env2);
ret = env_import_redund((char *)tmp_env1, read1_fail, (char *)tmp_env2,
read2_fail, H_EXTERNAL);
// 增强错误处理
if (ret == -EIO) {
// 主分区损坏时尝试备份分区
if (read1_fail && !read2_fail) {
ret = env_import((char *)tmp_env2, 1, H_EXTERNAL);
gd->env_valid = ENV_REDUND;
}
// 备份分区损坏时使用主分区
else if (!read1_fail && read2_fail) {
ret = env_import((char *)tmp_env1, 1, H_EXTERNAL);
gd->env_valid = ENV_VALID;
}
}
done:
free(tmp_env1);
free(tmp_env2);
return ret;
#endif /* ! ENV_IS_EMBEDDED */
}
看看这个代码流程对不对?是否还需要优化其他函数?以及将我当前实现的逻辑写一个详细的方案设计,我要写文档
最新发布