U-Boot环境变量
源文(http://www.cnitblog.com/buf/archive/2008/11/11/51335.html)
U-Boot通过环境变量(env)为用户提供一定程度的可配置性,这些环境变量包括串口终端所使用的波特率(baudrate)、启动操作系统内核的参数(bootargs)、本地IP地址(ipaddr)、网卡MAC地址(ethaddr)等等。环境变量可以固化到非易失性存储介质中,使用printenv / saveenv命令来查看和修改。本例中,环境变量固化到Flash中(AM29LV160DB,2MB)。
可配置性意味着环境变量中的项目是可以被添加、删除和修改的,即环境变量的内容可能会频繁变化。为了不让这种变化对U-Boot的代码和数据造成破坏,通常的选择是在Flash中准备一个专用的sector来存储环境变量。简化的ROM分配模型如下图所示,monitor占用 Flash前256KB,env置于其后,Flash的最后一部分用来存放压缩的操作系统内核。
AM29LV160DB分为35个sector,地址范围分配如下:
Sector |
Size ( KB ) |
Address Range ( Hex ) |
SA0 |
16 |
000000 ~ 003FFF |
SA1 |
8 |
004000 ~ 005FFF |
SA2 |
8 |
006000 ~ 007FFF |
SA3 |
16 |
008000 ~ 00FFFF |
SA4 |
32 |
010000 ~ 01FFFF |
SA5 |
64 |
020000 ~ 02FFFF |
... |
64 |
... |
SA34 |
64 |
1F0000 ~ 1FFFFF |
由于U-Boot代码通常达到100KB左右,且必须从地址0处开始,按照这样的分配方式,我们将不得不为env分配一块64KB的sector,而实际中使用到的可能只是其中的几百字节!U-Boot还会为env在RAM中保持一块同样大小的空间,这就造成ROM和RAM空间不必要的浪费。
为了尽可能地减少资源浪费,同时保证系统的健壮性,我们可以把env放置在Flash中容量最小的sector里。这样,env嵌入(embed)到U-Boot的代码段。在common/environment.h中会比较env和monitor的范围,如果确定env位于monitor内,则定义ENV_IS_EMBEDDED。
# 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
修改board/buf/EVB44B0/u-boot.lds:
/*------------------------------------------------------------
* Environment Variable setup
*/
#define CFG_ENV_IS_IN_FLASH 1 /* 使用Flash存储env */
#define CFG_ENV_SIZE 0x2000 /* 容量8KB (SA1) */
#define CFG_ENV_OFFSET 0x4000 /* 偏移地址 (SA1) */
$(LD)将一系列的obj文件连接成elf格式文件,其输出文件的内存布局由linker script决定。修改board/buf/EVB44B0/u-boot.lds:
SECTIONS
{
. = 0x00000000;
. = ALIGN(4);
.text :
{
cpu/s3c44b0/start.o (.text)
board/buf/EVB44B0/lowlevel_init.o (.text)
lib_generic/string.o (.text)
lib_generic/zlib.o (.text)
. = env_offset;
common/environment.o (.text)
*(.text)
}
/* other sections ... */
}
从u-boot.map选择那些U-Boot运行必须的,且不易受CFG_*宏影响的obj文件,填充到start.o后面。可以参考board/trab/u-boot.lds。
env_offset定义在common/environment.c中:
#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))
GEN_ABS(env_offset, CFG_ENV_OFFSET);