”ENV_IS_EMBEDDED“解惑以及相关的移植实验
一、概述( ENV_IS_EMBEDDED的目的)
经典资料



认识
ENV_IS_EMBEDDED只有在CFG_ENV_IS_IN_FLASH或者CFG_ENV_IS_IN_NAND定义了才有效。也就是说,这种功能只有在使用了norflash或者nandflash时才有效。本文是以使用norflash为例来说明的。
上边贴的几张图片讲的内容主要是这个意思:由于uboot.bin是100多kb,而环境变量要占一个扇区。norflash前100Kb中才有空间比较小的扇区,例如第二个扇区才8Kb,而后边的扇区比较大,都是64Kb。程序运行后,通常需要将环境变量拷贝到RAM中,这样访问速度才快,因此RAM中也需要为环境变量区占用和flash中一样大的空间。
倘若,不使用 ENV_IS_EMBEDDED这种功能,将环境变量区放在所有代码段的最后边,环境变量区只能占用64Kb的扇区,而环境变量区实际上有可能不需要那么大的空间,就造成了flash和RAM空间的浪费。
倘若使用ENV_IS_EMBEDDED功能,将环境变量区嵌入到代码段中,例如占用第二个扇区的8Kb(环境变量区的前后都有代码,故曰"嵌入环境变量"),就可以节省lash和RAM空间。
此外,这种功能的好处不止此。重定位时,将代码拷贝到RAM中了,顺便也将环境变量区拷贝了进来,这样环境变量初始化过程中,就不需要在堆区开辟空间然后搬移,省了不少事。
二、程序分析(怎样实现这个目的的)
1、定义(include/environment.h)
#if defined(CFG_ENV_IS_IN_FLASH)
some other define
# if (CFG_ENV_ADDR >= CFG_MONITOR_BASE) && \
(CFG_ENV_ADDR+CFG_ENV_SIZE) <= (CFG_MONITOR_BASE + CFG_MONITOR_LEN)
# define ENV_IS_EMBEDDED 1
# endif
# if defined(CFG_ENV_ADDR_REDUND) || defined(CFG_ENV_OFFSET_REDUND)
# define CFG_REDUNDAND_ENVIRONMENT 1
# endif
#endif /* CFG_ENV_IS_IN_FLASH */
只有定义了CFG_ENV_IS_IN_FLASH,并且满足下边的条件才有可能定义这个宏,这个宏是在smdk2410.h中定义的。
# if (CFG_ENV_ADDR >= CFG_MONITOR_BASE) && \
(CFG_ENV_ADDR+CFG_ENV_SIZE) <= (CFG_MONITOR_BASE + CFG_MONITOR_LEN)
2、与ENV_IS_EMBEDDED相关的全局变量定义(common/environment.c)
#if defined(ENV_IS_EMBEDDED)
/* XXX - This only works with GNU C */
# define __PPCENV__ __attribute__ ((section(".text"))) //强制将environment转换为代码区
# define __PPCTEXT__ __attribute__ ((section(".text")))
/*
* Macros to generate global absolutes.
*/
#define GEN_SYMNAME(str) SYM_CHAR #str
#define GEN_VALUE(str) #str
#define GEN_ABS(name, value) \
asm (".globl " GEN_SYMNAME(name)); \
asm (GEN_SYMNAME(name) " = " GEN_VALUE(value))
/*
* Macros to transform values
* into environment strings.
*/
#define XMK_STR(x) #x
#define MK_STR(x) XMK_STR(x)
/*
* Check to see if we are building with a
* computed CRC. Otherwise define it as ~0.
*/
#if !defined(ENV_CRC)
# define ENV_CRC ~0
#endif
env_t environment __PPCENV__ = {
ENV_CRC, /* CRC Sum */
#ifdef CFG_REDUNDAND_ENVIRONMENT
1, /* Flags: valid */
#endif
{
#if defined(CONFIG_BOOTARGS)
"bootargs=" CONFIG_BOOTARGS "\0"
#endif
other defines
#ifdef CONFIG_EXTRA_ENV_SETTINGS
CONFIG_EXTRA_ENV_SETTINGS
#endif
"\0" /* Term. env_t.data with 2 NULs */
}
};
#ifdef CFG_ENV_ADDR_REDUND
env_t redundand_environment __PPCENV__ = {
0, /* CRC Sum: invalid */
0, /* Flags: invalid */
{
"\0"
}
};
#endif /* CFG_ENV_ADDR_REDUND */
/*
* These will end up in the .text section
* if the environment strings are embedded
* in the image. When this is used for
* tools/envcrc, they are placed in the
* .data/.sdata section.
*
*/
unsigned long env_size __PPCTEXT__ = sizeof(env_t);
/*
* Add in absolutes.
*/
GEN_ABS(env_offset, CFG_ENV_OFFSET);
#endif /* ENV_IS_EMBEDDED */
这部分程序就是建立嵌入环境变量区,并强制性转换为代码区。这个环境变量区是完整的,包含头部crc。嵌入环境变量区一开始也在程序中初始化了(用常数初始化),我们知道crc是环境变量(data)的校验码,也不知道编译器是怎么实现在编译的时候直接根据环境变量data区实现crc的赋值(有初始化了data区生成的crc)。
3、 ENV_IS_EMBEDDED所涉及的在(common/env_flash.c)中的定义
#ifdef ENV_IS_EMBEDDED extern uchar environment[];
env_t *env_ptr = (env_t *)(&environment[]); //倘若定义了ENV_IS_EMBEDDED,那么指向嵌入环境区 #ifdef CMD_SAVEENV //如果使用了保存环境变量命令
/* static env_t *flash_addr = (env_t *)(&environment[0]);-broken on ARM-wd-*/
static env_t *flash_addr = (env_t *)CFG_ENV_ADDR; //保存环境变量区时的下载地址
#endif #else /* ! ENV_IS_EMBEDDED */ env_t *env_ptr = (env_t *)CFG_ENV_ADDR; // 定义flash中环境变量的地址
#ifdef CMD_SAVEENV
static env_t *flash_addr = (env_t *)CFG_ENV_ADDR;
#endif #endif /* ENV_IS_EMBEDDED */
4、env_init()函数(common/env_flash.c)
int env_init(void)
{
#ifdef CONFIG_OMAP2420H4 //没有定义
int flash_probe(void); if(flash_probe() == )
goto bad_flash;
#endif
if (crc32(0, env_ptr->data, ENV_SIZE) == env_ptr->crc) { //如果校验成功
gd->env_addr = (ulong)&(env_ptr->data); //定位在flash中
gd->env_valid = ; //代表flash中存在环境变量
return();
}
#ifdef CONFIG_OMAP2420H4
bad_flash:
#endif
gd->env_addr = (ulong)&default_environment[];
//不成功,则使用系统默认的环境变量
//default_environment仅仅是环境变量的data区,不包含头部crc 、flags
gd->env_valid = ; //0代表使用默认的环境变量
return ();
}
注意:由于编译器在编译的时候,已经给利用data生成了crc,所以肯定能够校验通过。
5、env_relocate()函数(common/env_common.c)
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 //有定义,所以下边的有效
//倘若定义了 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); //重定位
//我还不知道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); //为环境变量区分配空间
//在ENV_IS_EMBEDDED定义了的情况,不会为环境变量在堆区分配空间
DEBUGF ("%s[%d] malloced ENV at %p\n", __FUNCTION__,__LINE__,env_ptr);
#endif /*
* After relocation to RAM, we can always use the "memory" functions
*/
env_get_char = env_get_char_memory; //定义env_get_char函数 if (gd->env_valid == 0) { //env_init中决定了env_valid的值,倘若flash中存在的环境变量校验错误
#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 (-);
#endif
//#define ENV_SIZE (CFG_ENV_SIZE - ENV_HEADER_SIZE) ENV_SIZE在include/environment.h中定义
if (sizeof(default_environment) > ENV_SIZE)
{
puts ("*** Error - default environment is too large\n\n");
return;
} memset (env_ptr, , sizeof(env_t)); //为环境变量存储区清零空间
memcpy (env_ptr->data,
default_environment,
sizeof(default_environment)); //将环境默认变量拷贝到RAM中的指定区域
#ifdef CFG_REDUNDAND_ENVIRONMENT //没有定义
env_ptr->flags = 0xFF;
#endif
env_crc_update (); //更新crc
gd->env_valid = ; //env_valid确认有效了
}
else { //倘若flash中存在的环境变量校验成功
env_relocate_spec ();
/*该函数实现真正的重定位功能,先从NAND flash中读取环境变量,如果读取成*/
}
gd->env_addr = (ulong)&(env_ptr->data); //将环境变量的首地址(不含crc头部)赋给全局变量gd->env_addr #ifdef CONFIG_AMIGAONEG3SE
disable_nvram();
#endif
}
由于env_init()函数中,env_valid已经置为1,所以执行else分支,即 env_relocate_spec ()函数。
6、env_relocate_spec()函数(common/env_flash.c)
void env_relocate_spec (void) //此函数被env_relocate()函数调用
{
#if !defined(ENV_IS_EMBEDDED) || defined(CFG_ENV_ADDR_REDUND) //这两个变量都没有定义
#ifdef CFG_ENV_ADDR_REDUND
some process;
#endif /* CFG_ENV_ADDR_REDUND */
memcpy (env_ptr, (void*)flash_addr, CFG_ENV_SIZE); //在env_relocate已经将env_ptr指向环境变量存储区
#endif /* ! ENV_IS_EMBEDDED || CFG_ENV_ADDR_REDUND */ //倘若ENV_IS_EMBED定义了,并且CFG_ENV_ADDR_REDUND没有定义,那么这将是一个空函数
}
这个函数不包含任何代码,即不进行环境变量的搬移工作。
三、实验与分析
1、修改include/configs/TQ2440.h
/*-----------------------------------------------------------------------
* FLASH and environment organization
*/ #define CONFIG_AMD_LV800 1 /* uncomment this if you have a LV800 flash */
#if 0
#define CONFIG_AMD_LV400 1 /* uncomment this if you have a LV400 flash */
#endif #define CFG_MAX_FLASH_BANKS 1 /* max number of memory banks */
#ifdef CONFIG_AMD_LV800
#define PHYS_FLASH_SIZE 0x00200000 /* flash为2MB */
#define CFG_MAX_FLASH_SECT () /* 35个扇区*/
#define CFG_ENV_ADDR (CFG_FLASH_BASE + 0x04000) /* addr of environment */
#endif
#ifdef CONFIG_AMD_LV400
#define PHYS_FLASH_SIZE 0x00080000 /* 512KB */
#define CFG_MAX_FLASH_SECT (11) /* max number of sectors on one chip */
#define CFG_ENV_ADDR (CFG_FLASH_BASE + 0x04000) //环境变量下载地址
#endif /* timeout values are in ticks */
#define CFG_FLASH_ERASE_TOUT (5*CFG_HZ) /* Timeout for Flash Erase */
#define CFG_FLASH_WRITE_TOUT (5*CFG_HZ) /* Timeout for Flash Write */ #define CFG_ENV_IS_IN_FLASH 1
#define CFG_ENV_SIZE 0x2000 //环境变量大小
/*定义下边两个参数使ENV_IS_EMBEDDED有效*/
#define CFG_MONITOR_BASE CFG_ENV_ADDR
#define CFG_MONITOR_LEN 0x200000
实验现象
1> 编译后下载并启动开发板(第一次运行)

valid为1,环境变量在RAM中的0x33f926f0,在flash中的位置是0x33f926f0-0x33f80000=0x126f0,位于第五个扇区(SA4)。结合下边图片可以知道,上边第三个红框对应的行,正是下图中红色的框。也就是说ENV_IS_EMBEDDED确实生效了。

2> 保存环境变量

但是,环境变量却保存在第二个扇区(SA0)。
3> 重启(第二次运行)

遇到故障,重启不成功
4> 原因分析
0x33f926f0地址内容

0x33f84000内容

原因:环境变量区编译的地址不正确,所以保存环境变量后会把有效代码区(程序)破坏,所以重启不能正常执行。
2、修改board/TQ2440/u-boot.lds
. = ALIGN();
.text :
{
cpu/arm920t/start.o (.text)
. = env_offset;
common/environment.o(.text)
*(.text)
}
实验现象
1> 编译、下载、上电(第一次运行)

2> 保存环境变量

3> 重启(第二次运行)

保存后的环境变量不能使用,说是bad CRC。
4> 原因分析

原因:第一次上电,crc是编译器产生的(正确的),所以校验通过了。保存环境变量是放在flash的0x4000位置处,当加载到内存中,就是0x33f84000。但是,0x33f80000放的是env_size,被破坏了。而且,程序运行后,把环境变量定位在0x33f84004,产生了错误。
3.修改common/environment.c
/*
* These will end up in the .text section
* if the environment strings are embedded
* in the image. When this is used for
* tools/envcrc, they are placed in the
* .data/.sdata section.
*
*/
//unsigned long env_size __PPCTEXT__ = sizeof(env_t); /*
* Add in absolutes.
*/
GEN_ABS(env_offset, CFG_ENV_OFFSET);
env_size这个变量没什么用,所以注释掉。 实验现象
1> 编译、下载、上电(第一次运行)
正常
2> 保存环境变量
3> 重启(第二次运行)可以看到保存的环境变量已经能够正常加载。
四、疑问
1、 怎样把本应放在数据段的environment放在了代码段?
见__attribute__ ((section(".text")))的测试
2、 编译器是怎样根据环境变量产生crc校验码的?
3、 连接的时候是怎样将environment连接在0x33f84000位置上的?
见__attribute__ ((section(".text")))的测试
”ENV_IS_EMBEDDED“解惑以及相关的移植实验的更多相关文章
- FPGA之驱动sdram控制兼容性移植实验
cb早在2012年就推出了VIP 视频开发板 V1.4 这套开发板是ep2的,摄像头是ov7670,虽然不如当前的vip20强大,但也算是其雏形. 在vip20后期,cb对sdram以及其他模块进行 ...
- Linux VGA驱动移植实验【转】
本文转载自:http://m.blog.csdn.net/bzw73/article/details/46564275 有了前面的LCD驱动的框架,再移植VGA驱动就相当的容易了.默认在光盘中已经支持 ...
- uboot环境变量初始化
一.环境变量概述 1.环境变量的概念 可以理解为用户对软件的全局配置信息,这部分信息应该可以从永久性存储器上读取,能被查询,能被修改. 启动过程中,应该首先把环境变量读取到合适的内存区域,然后利用环境 ...
- __attribute__ ((section(".text")))的测试
一.测试原因 在学习u-boot的环境变量过程中,看到有如此的代码,现对涉及到的内容进行实验测试. 二.测试目的 1.了解gcc允许对段的属性进行更改的方法. 2.解决”ENV_IS_EMBEDDED ...
- 北京电子科技学院(BESTI)实验报告5
北京电子科技学院(BESTI)实验报告5 课程: 信息安全系统设计基础 班级:1452.1453 姓名:(按贡献大小排名) 郑凯杰.周恩德 学号:(按贡献大小排名) 20145314.20145217 ...
- 《信息安全系统设计基础》第一次实验报告--Linux 基础入门
北京电子科技学院(BESTI) 实 验 报 告 课程:信息安全设计基础 班级:1352 姓名:何伟钦 学号:20135223 成绩: 指导教师:娄嘉鹏 ...
- git实验
四.实例应用 应用1.现有项目移植到git代管 进入目标项目,进行git初始化: 初始化:git init 修改config:git config -- local user.name '名称' 和 ...
- 20145204&20145212信息安全系统实验三报告
实时系统的移植 实验目的与要求 1.根据实验指导书进行实时软件的安装 2.配置实验环境,并对软件进行测试. 3.正确使用连接线等仪器,注意保护试验箱. 实验内容与步骤 1.连接 arm 开发板 连接实 ...
- 20145227&20145201 《信息安全系统设计基础》实验三
北京电子科技学院(BESTI) 实 验 报 告 课程:信息安全系统设计基础 班级:1452 姓名:(按贡献大小排名)李子璇 鄢曼君 学号:(按贡献大小排名)20145201 20145227 成绩: ...
随机推荐
- 转载-Linux下搭建VPN服务器(CentOS、pptp)
转自:http://www.cnblogs.com/sixiweb/archive/2012/11/20/2778732.html 搭建过程参考这篇文章 先说我搭建过程中出现的问题吧: 按照 教程搭建 ...
- Linux中查看系统资源占用情况的命令【转载】
用 'top -i' 看看有多少进程处于 Running 状态,可能系统存在内存或 I/O 瓶颈,用 free 看看系统内存使用情况,swap 是否被占用很多,用 iostat 看看 I/O 负载 ...
- C#基础知识—父类和子类的关系
基础知识一: using System; using System.Collections.Generic; using System.Linq; using System.Windows.Forms ...
- URAL 1146 Maximum Sum(最大子矩阵的和 DP)
Maximum Sum 大意:给你一个n*n的矩阵,求最大的子矩阵的和是多少. 思路:最開始我想的是预处理矩阵,遍历子矩阵的端点,发现复杂度是O(n^4).就不知道该怎么办了.问了一下,是压缩矩阵,转 ...
- docker rancher 负载均衡做路由跳转
介绍 我们要实现的目的是 根据负载均衡 跳转到指定的应用容器中 负载均衡中配置好 跳转的地址 当执行URL 请求的时候会自动跳转 测试方法 curl -v --header 'Host:mu.03in ...
- MySQL源码:索引相关的数据结构
http://www.orczhou.com/index.php/2012/11/mysql-source-code-data-structure-about-index/ 本文将尝试介绍MySQL索 ...
- iOS开发-javaScript交互
前言 当前混合开发模式迎来了前所未有的发展,跨平台开发.热更新等优点决定了这种模式的重要地位.虽然前端界面在交互.动效等多方面距离原生应用还有差距,但毫无疑问混合开发只会被越来越多的公司接受.在iOS ...
- Oracle 安装安全补丁过程中出现的问题
为Oracle安装安全补丁,首先在官网上下载相应版本的补丁. 根据官方文档的说明安装,但是在安装的过程中会出项各种各样的错误,这里仅仅把我遇到的记录下来,给大家提供参考. 首先按照官方文档安装. 在这 ...
- 必应代码搜索 Bing Code Search 安装
微软这几天推出基于bing搜索引擎的 Bing Code Search ,可直接在浏览器上搜索和运行代码.目前中文版必应无法使用本功能,有需要的同学可以转到英文版进行搜索: 英文版必应: http ...
- .NET生成PDF文件
C#未借助第三方组件,自己封装通用类,生成PDF文件. 调用方式: //路径 string path = @"C:\yuannwu22.pdf"; //内容 string strC ...


可以看到保存的环境变量已经能够正常加载。