2.9、uboot源码分析5-uboot的环境变量(2021-5-8)


2.9.1、uboot的环境变量基础

2.9.1.1、环境变量的作用

在这里插入图片描述

2.9.1.2、环境变量的优先级

在这里插入图片描述

x210 # bdinfo                    //环境变量
arch_number = 0x00000998
env_t       = 0x00000000
boot_params = 0x30000100
DRAM bank   = 0x00000000
-> start    = 0x30000000
-> size     = 0x10000000
DRAM bank   = 0x00000001
-> start    = 0x40000000
-> size     = 0x10000000
ethaddr     = 00:40:5C:26:0A:5B
ip_addr     = 192.168.1.20
baudrate    = 115200 bps
// An highlighted block
var foo = 'bar';

2.9.1.3、环境变量在uboot中工作方式

在这里插入图片描述

/************************************************************************
 * Default settings to be used when no valid environment is found
 * 找不到有效环境时使用的默认设置
 */
#define XMK_STR(x)	#x
#define MK_STR(x)	XMK_STR(x)

#if defined(CONFIG_S3C6410) || defined(CONFIG_S3C6430) || defined(CONFIG_S5P6440) || defined(CONFIG_S5PC100) || defined(CONFIG_S5PC110) || defined(CONFIG_S5P6442)
uchar default_environment[CFG_ENV_SIZE] = {            //default_environment:默认环境变量
#else
uchar default_environment[] = {
#endif
#ifdef	CONFIG_BOOTARGS                         //CONFIG_BOOTARGS(启动参数)如果定义了
	"bootargs="	CONFIG_BOOTARGS			"\0"    //字符串+\0
#endif
#ifdef	CONFIG_BOOTCOMMAND                     //CONFIG_BOOTCOMMAND如果定义了
	"bootcmd="	CONFIG_BOOTCOMMAND		"\0"

在这里插入图片描述


2.9.2、环境变量相关命令源码解析1

2.9.2.1、printenv

在这里插入图片描述

x210 # print
mtdpart=80000 400000 3000000
baudrate=115200
ethaddr=00:40:5c:26:0a:5b
bootargs=console=ttySAC2,115200 root=/dev/mmcblk0p2 rw init=/linuxrc rootfstype=ext3
bootcmd=movi read kernel 30008000; bootm 30008000
filesize=37B800
fileaddr=30000000
gatewayip=192.168.1.1
netmask=255.255.255.0
ipaddr=192.168.1.20
serverip=192.168.1.141
bootdelay=10
//Cmd_nvedit.c
U_BOOT_CMD(
	printenv, CFG_MAXARGS, 1,	do_printenv,
	"printenv- print environment variables\n",
	"\n    - print values of all environment variables\n"
	"printenv name ...\n"
	"    - print value of environment variable 'name'\n"
);

在这里插入图片描述

//Cmd_nvedit.c
if (argc == 1) {		/* Print all env variables	打印所有环境变量*/
		//第一重for循环就是处理各个环境变量。所以有多少个环境变量则第一重就执行循环多少圈。
		for (i=0; env_get_char(i) != '\0'; i=nxt+1) {
			for (nxt=i; env_get_char(nxt) != '\0'; ++nxt)  
				;                     
			//执行结束之后,i指向命令首地址,nxt指向命令结束地址
			//用下面的for循环打印出此命令
			for (k=i; k<nxt; ++k)
				putc(env_get_char(k));
			putc  ('\n');              //换行

			//如果在打印过程中按下ctrl+c,可以打断此过程
			//终止打印
			if (ctrlc()) {
				puts ("\n ** Abort\n");
				return 1;
			}
		}
		//ENV_SIZE:整个环境变量的大小
		//CFG_ENV_SIZE:16KB
		//# define ENV_HEADER_SIZE	(sizeof(uint32_t) + 1)
		//#define ENV_SIZE (CFG_ENV_SIZE - ENV_HEADER_SIZE)   4B
		printf("\nEnvironment size: %d/%ld bytes\n",      //打印信息
			i, (ulong)ENV_SIZE);

		return 0;
	}

//Env_common.c
uchar env_get_char (int index)
{
	uchar c;

	/* if relocated to RAM */
	if (gd->flags & GD_FLG_RELOC)
		c = env_get_char_memory(index);
	else
		c = env_get_char_init(index);

	return (c);
}

2.9.3、环境变量相关命令源码解析2

2.9.3.1、setenv

在这里插入图片描述

//uboot/common/cmd_nvedit.c
U_BOOT_CMD(
	setenv, CFG_MAXARGS, 0,	do_setenv,
	"setenv  - set environment variables\n",
	"name value ...\n"
	"    - set environment variable 'name' to 'value ...'\n"
	"setenv name\n"
	"    - delete environment variable 'name'\n"
);
//uboot/common/cmd_nvedit.c
int do_setenv (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
{
	if (argc < 2) {
		printf ("Usage:\n%s\n", cmdtp->usage);
		return 1;
	}
	//没有_:自己可以随便用的
	//一个_:系统自己用的
	//两个_:系统内部自己用的,不用改
	//三个_:不用看
	//_do_setenv:只被do_setenv()函数调用
	return _do_setenv (flag, argc, argv);
}

在这里插入图片描述

	/*
	 * search if variable with this name already exists
	 * 搜索同名变量是否已经存在
	 */
	 //第1步:遍历DDR中环境变量的数组,找到原来就有的那个环境变量对应的地址。
	oldval = -1;
	for (env=env_data; *env; env=nxt+1) {
		for (nxt=env; *nxt; ++nxt)          //第一个字符串走完
			;
		if ((oldval = envmatch((uchar *)name, env-env_data)) >= 0)   //表示找到
			break;                 //退出循环
	}
		//第2步:擦除原来的环境变量,
		if (*++nxt == '\0') {
			if (env > env_data) {
				env--;
			} else {
				*env = '\0';
			}
		} else {
		//第3步:写入新的环境变量,
			for (;;) {
				*env = *nxt++;
				if ((*env == '\0') && (*nxt == '\0'))
					break;
				++env;
			}
		}
		*++env = '\0';
	}

在这里插入图片描述


2.9.4、环境变量相关命令源码解析2

2.9.4.1、saveenv

在这里插入图片描述

//uboot/common/cmd_nvedit.c
#if ((defined(CFG_ENV_IS_IN_NVRAM) || defined(CFG_ENV_IS_IN_EEPROM) \
    || (defined(CONFIG_CMD_ENV) && defined(CONFIG_CMD_FLASH)) \
    || (defined(CONFIG_CMD_ENV) && defined(CONFIG_CMD_NAND)) \
    || (defined(CONFIG_CMD_ENV) && defined(CONFIG_CMD_ONENAND)) \
	|| (defined(CONFIG_CMD_ENV) && defined(CONFIG_CMD_MOVINAND)) \
    && !defined(CFG_ENV_IS_NOWHERE)))
U_BOOT_CMD(
	saveenv, 1, 0,	do_saveenv,
	"saveenv - save environment variables to persistent storage\n",
	NULL
);

#endif
//uboot/common/cmd_nvedit.c
#if ((defined(CFG_ENV_IS_IN_NVRAM) || defined(CFG_ENV_IS_IN_EEPROM) \
    || (defined(CONFIG_CMD_ENV) && defined(CONFIG_CMD_FLASH)) \
    || (defined(CONFIG_CMD_ENV) && defined(CONFIG_CMD_NAND)) \
    || (defined(CONFIG_CMD_ENV) && defined(CONFIG_CMD_ONENAND)) \
	|| (defined(CONFIG_CMD_ENV) && defined(CONFIG_CMD_MOVINAND)) \
    && !defined(CFG_ENV_IS_NOWHERE)))
int do_saveenv (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
{
	extern char * env_name_spec;

	printf ("Saving Environment to %s...\n", env_name_spec);

	return (saveenv() ? 1 : 0);
}
#endif

在这里插入图片描述

x210 # save
Saving Environment to SMDK bootable device...    //uboot实际执行saveenv命令的输出
done

//Env_auto.c
char * env_name_spec = "SMDK bootable device";

//X210_sd.h
#define CFG_ENV_IS_IN_AUTO         //x210_sd.h中的配置(#define CFG_ENV_IS_IN_AUTO)
//Env_auto.c
int saveenv(void)                  //------------------------------------------
{
#if defined(CONFIG_S5PC100) || defined(CONFIG_S5PC110) || defined(CONFIG_S5P6442)
//在程序中读取INF_REG(OMpin内部对应的寄存器)从而知道我们的启动介质,
//然后调用这种启动介质对应的操作函数来操作。
	if (INF_REG3_REG == 2)
		saveenv_nand();
	else if (INF_REG3_REG == 3)
		saveenv_movinand();
	else if (INF_REG3_REG == 1)
		saveenv_onenand();
	else if (INF_REG3_REG == 4)
		saveenv_nor();
#elif	defined(CONFIG_SMD

在这里插入图片描述

//S5pc110.h
#define INF_REG_BASE			0xE010F000 
#define INF_REG3_OFFSET			0x0c 

//INF_REG_BASE+INF_REG3_OFFSET = 0xE010 F00C
#define INF_REG3_REG			__REG(INF_REG_BASE+INF_REG3_OFFSET)
//Env_auto.c
int saveenv_movinand(void)
{
#if defined(CONFIG_CMD_MOVINAND)       //CONFIG_CMD_MOVINAND定义
        movi_write_env(virt_to_phys((ulong)env_ptr));   //执行movi_write_env()函数
        puts("done\n");

        return 1;
#else
	return 0;
#endif	/* CONFIG_CMD_MOVINAND */
}

在这里插入图片描述

void movi_write_env(ulong addr)
{
	//ulong movi_write(ulong start, lbaint_t blkcnt, void *src)
	//start:开始扇区
	//blkcnt:扇区数
	//src:原字符串
	movi_write(raw_area_control.image[2].start_blk,
		   raw_area_control.image[2].used_blk, addr);
}

2.9.5、uboot内部获取环境变量

2.9.5.1、getenv

在这里插入图片描述

//Board.c
/************************************************************************
 * Look up variable from environment,
 * return address of storage for that variable,
 * or NULL if not found
 * 从环境中查找变量,返回该变量的存储地址,如果没有找到,则返回空值
 */
 //getenv函数用来获取字符串格式的环境变量的地址
char *getenv (char *name)
{
	int i, nxt;

	WATCHDOG_RESET();        //空的
	//遍历default数组
	for (i=0; env_get_char(i) != '\0'; i=nxt+1) {
		int val;

		for (nxt=i; env_get_char(nxt) != '\0'; ++nxt) {
			if (nxt >= CFG_ENV_SIZE) {   //有无越界
				return (NULL);
			}
		}
		if ((val=envmatch((uchar *)name, i)) < 0)  //寻找环境变量,小于0没找到
			continue;
		return ((char *)env_get_addr(val));
	}

	return (NULL);
}

2.9.5.2、getenv_r

在这里插入图片描述

//Board.c
//char *name:环境变量的名字
//char *buf:要获取环境变量的值将来写在这里
//unsigned len:长度
//读取环境变量成功:返回值大于0;
//读取环境变量失败:返回值小于0;
int getenv_r (char *name, char *buf, unsigned len)         //读取环境变量
{
	int i, nxt;

	for (i=0; env_get_char(i) != '\0'; i=nxt+1) {
		int val, n;

		for (nxt=i; env_get_char(nxt) != '\0'; ++nxt) {
			if (nxt >= CFG_ENV_SIZE) {
				return (-1);
			}
		}
		if ((val=envmatch((uchar *)name, i)) < 0)
			continue;
		/* found; copy out */
		//发现,复制出来
		n = 0;
		while ((len > n++) && (*buf++ = env_get_char(val++)) != '\0')
			;
		if (len == n)
			*buf = '\0';
		return (n);
	}
	return (-1);
}

2.9.5.3、总结

在这里插入图片描述


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值