uboot环境变量

1、uboot环境变量结构

  • 外部环境变量:外部环境变量是固化在存储介质上的,可断电保存,具体保存在什么介质上,通过开发板定义的CONFIG_ENV_IS_IN_XXX选项来指定,例如nand、flash、mmc等。如果不使用外部环境变量,可定义CONFIG_ENV_IS_NO_WHERE。saveenv命令就是存储在外部环境变量。外部环境变量的前四个字节存储的是crc校验码。
./include/environment.h
typedef struct environment_s {
	uint32_t	crc;		/* CRC32 over data bytes	*/
#ifdef CONFIG_SYS_REDUNDAND_ENVIRONMENT
	unsigned char	flags;		/* active/obsolete flags	*/
#endif
	unsigned char	data[ENV_SIZE]; /* Environment data		*/
} env_t
  • 内部环境变量:内部环境变量是由default_environment[]存储在uboot的镜像中。
./include/env_default.h
static char default_environment[] = {
#else
const uchar default_environment[] = {
#endif
#ifdef	CONFIG_ENV_CALLBACK_LIST_DEFAULT
	ENV_CALLBACK_VAR "=" CONFIG_ENV_CALLBACK_LIST_DEFAULT "\0"
#endif
#ifdef	CONFIG_ENV_FLAGS_LIST_DEFAULT
	ENV_FLAGS_VAR "=" CONFIG_ENV_FLAGS_LIST_DEFAULT "\0"
#endif
#ifdef	CONFIG_BOOTARGS
	"bootargs="	CONFIG_BOOTARGS			"\0"
#endif
#ifdef	CONFIG_BOOTCOMMAND
	"bootcmd="	CONFIG_BOOTCOMMAND		"\0"
#endif
#ifdef	CONFIG_RAMBOOTCOMMAND
	"ramboot="	CONFIG_RAMBOOTCOMMAND		"\0"
#endif
#ifdef	CONFIG_NFSBOOTCOMMAND
	"nfsboot="	CONFIG_NFSBOOTCOMMAND		"\0"
#endif
#if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)
	"bootdelay="	__stringify(CONFIG_BOOTDELAY)	"\0"
#endif
#if defined(CONFIG_BAUDRATE) && (CONFIG_BAUDRATE >= 0)
	"baudrate="	__stringify(CONFIG_BAUDRATE)	"\0"
#endif
#ifdef	CONFIG_LOADS_ECHO
	"loads_echo="	__stringify(CONFIG_LOADS_ECHO)	"\0"
#endif
#ifdef	CONFIG_ETHADDR
	"ethaddr="	__stringify(CONFIG_ETHADDR)	"\0"
#endif
#ifdef	CONFIG_ETH1ADDR
	"eth1addr="	__stringify(CONFIG_ETH1ADDR)	"\0"
#endif
#ifdef	CONFIG_ETH2ADDR
	"eth2addr="	__stringify(CONFIG_ETH2ADDR)	"\0"
#endif
#ifdef	CONFIG_ETH3ADDR
	"eth3addr="	__stringify(CONFIG_ETH3ADDR)	"\0"
#endif
#ifdef	CONFIG_ETH4ADDR
	"eth4addr="	__stringify(CONFIG_ETH4ADDR)	"\0"
#endif
#ifdef	CONFIG_ETH5ADDR
	"eth5addr="	__stringify(CONFIG_ETH5ADDR)	"\0"
#endif
#ifdef	CONFIG_ETHPRIME
	"ethprime="	CONFIG_ETHPRIME			"\0"
#endif
#ifdef	CONFIG_IPADDR
	"ipaddr="	__stringify(CONFIG_IPADDR)	"\0"
#endif
#ifdef	CONFIG_SERVERIP
	"serverip="	__stringify(CONFIG_SERVERIP)	"\0"
#endif
#ifdef	CONFIG_SYS_AUTOLOAD
	"autoload="	CONFIG_SYS_AUTOLOAD		"\0"
#endif
#ifdef	CONFIG_PREBOOT
	"preboot="	CONFIG_PREBOOT			"\0"
#endif
#ifdef	CONFIG_ROOTPATH
	"rootpath="	CONFIG_ROOTPATH			"\0"
#endif
#ifdef	CONFIG_GATEWAYIP
	"gatewayip="	__stringify(CONFIG_GATEWAYIP)	"\0"
#endif
#ifdef	CONFIG_NETMASK
	"netmask="	__stringify(CONFIG_NETMASK)	"\0"
#endif
#ifdef	CONFIG_HOSTNAME
	"hostname="	__stringify(CONFIG_HOSTNAME)	"\0"
#endif
#ifdef	CONFIG_BOOTFILE
	"bootfile="	CONFIG_BOOTFILE			"\0"
#endif
#ifdef	CONFIG_LOADADDR
	"loadaddr="	__stringify(CONFIG_LOADADDR)	"\0"
#endif
#ifdef	CONFIG_CLOCKS_IN_MHZ
	"clocks_in_mhz=1\0"
#endif
#if defined(CONFIG_PCI_BOOTDELAY) && (CONFIG_PCI_BOOTDELAY > 0)
	"pcidelay="	__stringify(CONFIG_PCI_BOOTDELAY)"\0"
#endif
#ifdef	CONFIG_ENV_VARS_UBOOT_CONFIG
	"arch="		CONFIG_SYS_ARCH			"\0"
	"cpu="		CONFIG_SYS_CPU			"\0"
	"board="	CONFIG_SYS_BOARD		"\0"
	"board_name="	CONFIG_SYS_BOARD		"\0"
#ifdef CONFIG_SYS_VENDOR
	"vendor="	CONFIG_SYS_VENDOR		"\0"
#endif
#ifdef CONFIG_SYS_SOC
	"soc="		CONFIG_SYS_SOC			"\0"
#endif
#endif
#ifdef	CONFIG_EXTRA_ENV_SETTINGS
	CONFIG_EXTRA_ENV_SETTINGS
#endif
	"\0"
#ifdef DEFAULT_ENV_INSTANCE_EMBEDDED
	}
#endif
};

2、环境变量初始化

  • 环境变量初始化过程主要涉及两个函数:board_init_f和board_init_r。
1、board_init_r
  • 在board_init_f中调用 env_init,根据CONFIG_ENV_IS_IN_XXX,特定的./commom/env_xxx.c文件就会被编译,之后会调用特定.c中的env_init函数。对于env_flash.c与env_mmc.c中的env_init还不是完全一样。
./common/env_flash.c
int env_init(void)
{
	if (crc32(0, env_ptr->data, ENV_SIZE) == env_ptr->crc) {
		gd->env_addr	= (ulong)&(env_ptr->data);
		gd->env_valid	= 1;
		return 0;
	}

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

./common/env_mmc.c
int env_init(void)
{
	/* use default */
	gd->env_addr	= (ulong)&default_environment[0];
	gd->env_valid	= 1;

	return 0;
}
  • 对于flash中env_init函数会进行外部环境变量的检测,通过env_ptr直接指向存储介质上的外部环境变量区域来访问,计算env_ptr->data的crc和env_ptr->crc是否相等,验证外部环境变量是否有效。若有效,设置gd使用外部环境变量。若无效,使用内部环境变量。
  • 对于mmc,mmc需要初始化接口后才能访问,因此此时无法访问外部环境变量,因此直接使用内部环境变量。
  • 未理解的是为什么flash使用内部环境变量时gd->env_valid = 0,而mmc使用内部环境变量时gd->valid = 1。
2、board_init_r
  • 在board_init_r中调用initr_env。
./common/board_r.c
static int initr_env(void)
{
	/* initialize environment */
	if (should_load_env())	
		env_relocate();
	else
		set_default_env(NULL);

	/* Initialize from environment */
	load_addr = getenv_ulong("loadaddr", 16, load_addr);
	
	return 0;
}
./common/env_common.c
void env_relocate(void)
{
#if defined(CONFIG_NEEDS_MANUAL_RELOC)
	env_reloc();
	env_htab.change_ok += gd->reloc_off;
#endif
	if (gd->env_valid == 0) {
#if defined(CONFIG_ENV_IS_NOWHERE) || defined(CONFIG_SPL_BUILD)
		/* Environment not changable */
		set_default_env(NULL);
#else
		bootstage_error(BOOTSTAGE_ID_NET_CHECKSUM);
		set_default_env("!bad CRC");
#endif
	} else {
		env_relocate_spec();
	}
}
  • gd->env_valid在board_f阶段中的函数env_init调用中被赋值为1,这里将接着执行env_relocate_spec。env_relocate_spec针对不同的环境变量存储设备有多处实现,这里使用CONFIG_ENV_IS_IN_MMC宏,所以使用common/env_mmc.c中的定义(参见common/Makefile),由于没有定义CONFIG_ENV_OFFSET_REDUND,则
./common/env_mmc.c
void env_relocate_spec(void)
{
#if !defined(ENV_IS_EMBEDDED)
	ALLOC_CACHE_ALIGN_BUFFER(char, buf, CONFIG_ENV_SIZE);
	struct mmc *mmc;
	u32 offset;
	int ret;
	int dev = mmc_get_env_devno();

#ifdef CONFIG_SPL_BUILD
	dev = 0;
#endif

	mmc = find_mmc_device(dev);

	if (init_mmc_for_env(mmc)) {
		ret = 1;
		goto err;
	}

	if (mmc_get_env_addr(mmc, 0, &offset)) {
		ret = 1;
		goto fini;
	}

	if (read_env(mmc, CONFIG_ENV_SIZE, offset, buf)) {
		ret = 1;
		goto fini;
	}

	env_import(buf, 1);
	ret = 0;

fini:
	fini_mmc_for_env(mmc);
err:
	if (ret)
		set_default_env(NULL);
#endif
}
  • 如果从mmc中读取环境变量成功,则调用函数env_import,该函数将对读取到的环境变量进行CRC校验,如校验失败,会执行set_default_env。否则接着调用himport_r执行hash表的初始化。
    set_default_env函数用来配置默认的的环境变量。它在common/env_common.c中实现:
void set_default_env(const char *s)
{
	int flags = 0;

	if (sizeof(default_environment) > ENV_SIZE) {
		puts("*** Error - default environment is too large\n\n");
		return;
	}

	if (s) {
		if (*s == '!') {
			printf("*** Warning - %s, "
				"using default environment\n\n",
				s + 1);
		} else {
			flags = H_INTERACTIVE;
			puts(s);
		}
	} else {
		puts("Using default environment\n\n");
	}

	if (himport_r(&env_htab, (char *)default_environment,
			sizeof(default_environment), '\0', flags, 0,
			0, NULL) == 0)
		error("Environment import failed: errno = %d\n", errno);

	gd->flags |= GD_FLG_ENV_READY;
}

在这里插入图片描述

  • 无论是使用默认的环境变量,还是使用从flash、mmc读取到的有效环境变量配置,完成环境变量的读取后,都将调用himport_r将获取到的环境变量导入到hash表中。
  • 3
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值