海思(Hi3521a)uboot详细分析(7)——uboot环境变量分析

    uboot被加载到内存中运行后,在启动过程的第二阶段,uboot会去flash中将环境变量复制到ddr中,如果uboot中的环境变量校验不通过,则使用默认的环境变量值初始化环境变量,如果用户从命令终端修改了环境变量的值,那么需要使用saveenv命令才会将环境变量同步到flash中保存,因为在命令终端运行时,uboot是运行在内存中,修改的是DDR内存中的环境变量。本文也就是分析uboot是如何实现这些功能的。
    uboot启动分析可以查看博客《uboot启动第二阶段start_armboot函数分析》,其它的Uboot内容可以参考博客《序言与启动》

环境变量初始化接口env_relocate是定义在./u-boot-2010.06/common/env_common.c

void env_relocate (void)
{
#ifndef CONFIG_RELOC_FIXUP_WORKS
	DEBUGF ("%s[%d] offset = 0x%lx\n", __FUNCTION__,__LINE__,
		gd->reloc_off);
#endif

#ifdef CONFIG_AMIGAONEG3SE
	enable_nvram();
#endif

#ifdef ENV_IS_EMBEDDED
	/*
	 * The environment buffer is embedded with the text segment,
	 * just relocate the environment pointer
	 */
#ifndef CONFIG_RELOC_FIXUP_WORKS
	env_ptr = (env_t *)((ulong)env_ptr + gd->reloc_off);
#endif
	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 (CONFIG_ENV_SIZE);	//①
	DEBUGF ("%s[%d] malloced ENV at %p\n", __FUNCTION__,__LINE__,env_ptr);
#endif

	if (gd->env_valid == 0) {						//②
#if defined(CONFIG_GTH)	|| defined(CONFIG_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
}

(A)分配堆空间

  •  CONFIG_RELOC_FIXUP_WORKS,CONFIG_AMIGAONEG3SE,ENV_IS_EMBEDDED在海思hi3521a中都没有定义,所以进来后就直接运行到了①;
  • ①在3521a中CONFIG_ENV_SIZE=0x40000(256KB),定义在./u-boot-2010.06/include/configs/hi3521a.h中,这里是在堆中分配256K的空间来存放环境变量
  • ②gd->env_valid 这个全局变量在进行spi flash 初始化的时候默认将它强制赋值为1,./u-boot-2010.06/common/env_sf.c中的sf_env_init函数
int sf_env_init(void)
{
	/* SPI flash isn't usable before relocation */
	gd->env_addr = (ulong)&default_environment[0];
	gd->env_valid = 1;

	return 0;
}

(B)环境变量重定向 

  • ③这里它会去读取flash中的环境变量,然后对它的数据进行有效性分析。对于hi3521a设备,它是在./u-boot-2010.06/common/env_sf.c的sf_env_relocate_spec函数中实现。
void sf_env_relocate_spec(void)
{
	int ret;

	env_flash = spi_flash_probe(CONFIG_ENV_SPI_BUS, CONFIG_ENV_SPI_CS,
			CONFIG_ENV_SPI_MAX_HZ, CONFIG_ENV_SPI_MODE);
	if (!env_flash)
		goto err_probe;

	ret = spi_flash_read(env_flash, CONFIG_ENV_OFFSET, CONFIG_ENV_SIZE, env_ptr); //(1)
	if (ret)
		goto err_read;

	if (crc32(0, env_ptr->data, ENV_SIZE) != env_ptr->crc) //(2)
		goto err_crc;

	gd->env_valid = 1;			//(3)

	return;

err_read:
	spi_flash_free(env_flash);
	env_flash = NULL;
err_probe:
err_crc:
	puts("*** Warning - bad CRC, using default environment\n\n");

	set_default_env();
}
  • (1)这个是从flash中的CONFIG_ENV_OFFSET这个位置读取CONFIG_ENV_SIZE大小的值到env_ptr这个指针指向的地址。在海思hi3521a中CONFIG_ENV_OFFSET=0x80000=512KB,CONFIG_ENV_SIZE=0x40000=256KB。
  • (2)这里我们看env_t这个结构体
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;

(C)默认环境变量 

  • 环境变量的开始4字节是CRC校验码,在(2)这里是对环境变量进行CRC32计算并且跟环境变量中保存的CRC做对比,如果不相等,表示flash中没有环境变量或是环境变量数据异常,然后去设置默认的环境变量。默认环境变量定义如下
uchar default_environment[] = {
#ifdef	CONFIG_BOOTARGS
	"bootargs="	CONFIG_BOOTARGS			"\0"
#endif
#ifdef	CONFIG_SLAVE_BOOTARGS
	"slave_bootargs="	CONFIG_SLAVE_BOOTARGS	"\0"
#endif
#ifdef	CONFIG_BOOTCOMMAND
	"bootcmd="	CONFIG_BOOTCOMMAND		"\0"
#endif
#ifdef	CONFIG_SLAVE_BOOTCMD
	"slave_bootcmd="	CONFIG_SLAVE_BOOTCMD	"\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="	MK_STR(CONFIG_BOOTDELAY)	"\0"
#endif
#if defined(CONFIG_BAUDRATE) && (CONFIG_BAUDRATE >= 0)
	"baudrate="	MK_STR(CONFIG_BAUDRATE)		"\0"
#endif
#ifdef	CONFIG_LOADS_ECHO
	"loads_echo="	MK_STR(CONFIG_LOADS_ECHO)	"\0"
#endif
#ifdef	CONFIG_USE_MDIO
	"use_mdio="	CONFIG_USE_MDIO			"\0"
#endif
#ifdef	CONFIG_MDIO_INTF
	"mdio_intf="	CONFIG_MDIO_INTF	        "\0"
#endif
#ifdef	CONFIG_ETHADDR
	"ethaddr="	MK_STR(CONFIG_ETHADDR)		"\0"
#endif
#ifdef	CONFIG_ETH1ADDR
	"eth1addr="	MK_STR(CONFIG_ETH1ADDR)		"\0"
#endif
#ifdef	CONFIG_ETH2ADDR
	"eth2addr="	MK_STR(CONFIG_ETH2ADDR)		"\0"
#endif
#ifdef	CONFIG_ETH3ADDR
	"eth3addr="	MK_STR(CONFIG_ETH3ADDR)		"\0"
#endif
#ifdef	CONFIG_ETH4ADDR
	"eth4addr="	MK_STR(CONFIG_ETH4ADDR)		"\0"
#endif
#ifdef	CONFIG_ETH5ADDR
	"eth5addr="	MK_STR(CONFIG_ETH5ADDR)		"\0"
#endif
#ifdef	CONFIG_IPADDR
	"ipaddr="	MK_STR(CONFIG_IPADDR)		"\0"
#endif
#ifdef	CONFIG_SERVERIP
	"serverip="	MK_STR(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="	MK_STR(CONFIG_ROOTPATH)		"\0"
#endif
#ifdef	CONFIG_GATEWAYIP
	"gatewayip="	MK_STR(CONFIG_GATEWAYIP)	"\0"
#endif
#ifdef	CONFIG_NETMASK
	"netmask="	MK_STR(CONFIG_NETMASK)		"\0"
#endif
#ifdef	CONFIG_HOSTNAME
	"hostname="	MK_STR(CONFIG_HOSTNAME)		"\0"
#endif
#ifdef	CONFIG_BOOTFILE
	"bootfile="	MK_STR(CONFIG_BOOTFILE)		"\0"
#endif
#ifdef	CONFIG_LOADADDR
	"loadaddr="	MK_STR(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="	MK_STR(CONFIG_PCI_BOOTDELAY)	"\0"
#endif
#ifdef  CONFIG_EXTRA_ENV_SETTINGS
	CONFIG_EXTRA_ENV_SETTINGS
#endif
	"\0"
};

如果要添加默认环境变量,也可以直接修改这里。

  • (3)如果在(2)中判断flash中读取出来的环境变量校验正确,那么就将gd->env_valid的值初始化为1,表示flash中的环境变量是有效的。
  • ④将环境变量的地址赋值给Uboot运行的一个全局变量,以便其它地方的使用。

    uboot 中的其它相关内容可以参考博客《序言与目录》

发布了164 篇原创文章 · 获赞 229 · 访问量 62万+

猜你喜欢

转载自blog.csdn.net/li_wen01/article/details/103352638