嵌入式学习笔记---uboot(9)

总结于朱有鹏老师的嵌入式课程,感谢朱老师

文章目录

    • 环境变量
    • 不同位置的环境变量
    • do_printenv函数
    • setenv
    • saveenv
    • uboot内部获取环境变量
      • getenv
      • getenv_r

环境变量

可以不用修改uboot的源代码,而是通过修改环境变量来影响uboot运行时的一些数据和特性。

如果环境变量为空则使用代码中的值;如果环境变量不为空则优先使用环境变量对应的值。

不同位置的环境变量

默认环境变量,在uboot/common/env_common.c中
default_environment,这东西本质是一个字符数组,大小为CFG_ENV_SIZE(16kb),里面内容就是很多个环境变量连续分布组成的,每个环境变量最末端以’\0’结束。

SD卡中环境变量分区,在uboot的raw分区中。
SD卡中其实就是给了个分区,专门用来存储而已。存储时其实是把DDR中的环境变量整体的写入SD卡中分区里。所以当我们saveenv时其实整个所有的环境变量都被保存了一遍,而不是只保存更改了的。

DDR中环境变量,在default_environment中,实质是字符数组。
在uboot中其实是一个全局变量,链接时在数据段,重定位时default_environment就被重定位到DDR中一个内存地址处了。这个地址处这个全局字符数组就是我们uboot运行时的DDR中的环境变量了。

uboot第一次运行时加载的是uboot代码中自带的一份环境变量,叫默认环境变量。我们在saveenv时DDR中的环境变量会被更新到SD卡中的环境变量中,就可以被保存下来,下次开机会在环境变量relocate时会SD卡中的环境变量会被加载到DDR中去。
在uboot启动的第二阶段,env_relocate时代码会去判断SD卡中的env分区的crc是否通过。如果crc校验通过说明SD卡中有正确的环境变量存储,则relocate函数会从SD卡中读取环境变量来覆盖default_environment字符数组,从而每次开机可以保持上一次更改过的环境变量。

do_printenv函数

int do_printenv (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
{
	int i, j, k, nxt;
	int rcode = 0;

	if (argc == 1) {		/* Print all env variables	*/    //print用法显示所有环境变量
		for (i=0; env_get_char(i) != '\0'; i=nxt+1) {
			for (nxt=i; env_get_char(nxt) != '\0'; ++nxt)  //确定有多少环境变量,因为结尾有\0所以以此判断
				;
			for (k=i; k<nxt; ++k)              //for将所有环境变量输出
				putc(env_get_char(k));
			putc  ('\n');

			if (ctrlc()) {
				puts ("\n ** Abort\n");
				return 1;
			}
		}

		printf("\nEnvironment size: %d/%ld bytes\n",
			i, (ulong)ENV_SIZE);

		return 0;
	}
//如果命令中只有print一个段则只执行上面,否则执行下面
	for (i=1; i<argc; ++i) {	/* print single env variables	*/ //print加环境变量名用法显示单个
		char *name = argv[i];

		k = -1;

		for (j=0; env_get_char(j) != '\0'; j=nxt+1) {

			for (nxt=j; env_get_char(nxt) != '\0'; ++nxt)
				;
			k = envmatch((uchar *)name, j);
			if (k < 0) {
				continue;
			}
			puts (name);
			putc ('=');
			while (k < nxt)
				putc(env_get_char(k++));
			putc ('\n');
			break;
		}
		if (k < 0) {
			printf ("## Error: \"%s\" not defined\n", name);
			rcode ++;
		}
	}
	return rcode;
}

setenv

先去DDR中的环境变量处寻找原来有没有这个环境变量,如果原来就有则需要覆盖原来的环境变量,如果原来没有则在最后新增一个环境变量即可。uboot/common/cmd_nvedit.c中

第1步:遍历DDR中环境变量的数组,找到原来就有的那个环境变量对应的地址。168-174行。
第2步:擦除原来的环境变量,259-265行
第3步:写入新的环境变量,266-273行。

saveenv

在uboot/common/cmd_nvedit.c中,对应函数为do_saveenv。实际使用的是env_auto.c中相关的内容,程序中编译各种常见的flash芯片并读取INF_REG(OMpin内部对应的寄存器)从而知道我们的启动介质,然后调用这种启动介质对应的操作函数来操作。saveenv函数来执行实际的环境变量保存操作。在start.S中判断启动介质将#BOOT_MMCSD(就是3,定义在x210_sd.h)写入E010F000+0C=E010_F00C这个寄存器地址,真正执行保存环境变量操作的是:cpu/s5pc11x/movi.c中的movi_write_env函数,这个函数是写sd卡,将DDR中的default_environment环境变量数组写入iNand中的ENV分区中。

uboot内部获取环境变量

getenv

不可重入
实现方式就是去遍历default_environment数组,挨个拿出所有的环境变量比对name,找到相等的直接返回这个环境变量的首地址即可。

getenv_r

可重入
找到了DDR中环境变量地址后,将这个环境变量复制一份到提供的buf中,而不动原来DDR中环境变量。

你可能感兴趣的:(嵌入式)