前文 sophpi uboot 网络功能使能 中介绍了 sophpi 开启网络功能,该文中最后提到了不能通过 saveenv 保存修改完成的 IP 地址相关环境变量。本文介绍如何使用 u-boot 的 saveenv 命令保存环境变量。
当设置完环境变量之后,如果执行了saveenv 命令,则下次重新运行的时候环境变量则会被保存为上次保存的值,如果不保存,只会在设置好时还没重启之前生效,重启之后设置值会恢复成原来的值。
sophpi# saveenv
Unknown command 'saveenv' - try 'help'
原因定位
由于 build/boards/cv181x/sg2002_wevb_riscv64_sd/u-boot/cvitek_sg2002_wevb_riscv64_sd_defconfig 文件未配置相关存储地址,或者开启了 CONFIG_ENV_IS_NOWHERE=y
,导致 u-boot 环境变量没有存储在任何地方,所以无法使用 saveenv 命令。
在 u-boot-2021.10/env/Kconfig 中定义了 “ENV_IS_NOWHERE” 这个宏,被默认选中。
config ENV_IS_NOWHEREbool "Environment is not stored"default y if !ENV_IS_IN_EEPROM && !ENV_IS_IN_EXT4 && \!ENV_IS_IN_FAT && !ENV_IS_IN_FLASH && \!ENV_IS_IN_MMC && !ENV_IS_IN_NAND && \!ENV_IS_IN_NVRAM && !ENV_IS_IN_ONENAND && \!ENV_IS_IN_REMOTE && !ENV_IS_IN_SPI_FLASH && \!ENV_IS_IN_UBIhelpDefine this if you don't want to or can't have an environment storedon a storage medium. In this case the environment will still existwhile U-Boot is running, but once U-Boot exits it will not bestored. U-Boot will therefore always start up with a defaultenvironment.
u-boot 在 u-boot-2021.10/build/sg2002_wevb_riscv64_sd/include/generated/autoconf.h 中自动生成了以下配置:
#define CONFIG_ENV_IS_NOWHERE 1
ENV_IS_NOWHERE
含义是 u-boot 环境变量没有存储在任何地方。
使能 saveenv
- 新增 build/boards/cv181x/sg2002_wevb_riscv64_sd/u-boot/cvitek_sg2002_wevb_riscv64_sd_defconfig 配置
CONFIG_ENV_IS_IN_FAT=y
CONFIG_ENV_FAT_INTERFACE="mmc"
CONFIG_ENV_FAT_DEVICE_AND_PART="0"
CONFIG_ENV_FAT_FILE="uboot.env"
- 修改 u-boot-2021.10/include/cvipart.h
在 u-boot-2021.10/include/configs/cv181x-asic.h 文件中调用了 cvipart.h,在该文件中定义了 CONFIG_ENV_IS_NOWHERE,导致 u-boot 中使能 saveenv 失效,需要注释掉。
// #ifndef CONFIG_ENV_IS_NOWHERE
// #define CONFIG_ENV_IS_NOWHERE
// #endif
完成以上修改后,重新编译 u-boot,即可执行 saveenv 命令保存环境变量。
u-boot 环境变量保存
在 u-boot 启动后,通过以下命令保存环境变量:
soph# saveenv
Saving Environment to FAT... OK
进入 u-boot 命令行,运行 setenv 修改对应的环境变量后,运行 saveenv,会在 SD 卡第一个分区创建 uboot.env 文件。重启后再次进入 u-boot 命令行,运行 printenv,可以看到环境变量已经保存成功。
源代码
config ENV_FAT_DEVICE_AND_PART
string “Device and partition for where to store the environemt in FAT”
depends on ENV_IS_IN_FAT
default “0:1” if TI_COMMON_CMD_OPTIONS
default “0:auto” if ARCH_ZYNQ || ARCH_ZYNQMP || ARCH_VERSAL
default “:auto” if ARCH_SUNXI
default “0” if ARCH_AT91
help
Define this to a string to specify the partition of the device. It can
be as following:
"D:P", "D:0", "D", "D:" or "D:auto" (D, P are integers. And P >= 1)- "D:P": device D partition P. Error occurs if device D has nopartition table.- "D:0": device D.- "D" or "D:": device D partition 1 if device D has partitiontable, or the whole device D if has no partitiontable.- "D:auto": first partition in device D with bootable flag set.If none, first valid partition in device D. If nopartition table then means device D.If ENV_FAT_INTERFACE is set to "mmc" then device 'D' can be omitted,leaving the string starting with a colon, and the boot device willbe used.
config ENV_FAT_FILE
string “Name of the FAT file to use for the environment”
depends on ENV_IS_IN_FAT
default “uboot.env”
help
It’s a string of the FAT file name. This file use to store the
environment.
config ENV_FAT_FILE_REDUND
string “Name of the FAT file to use for the environment”
depends on ENV_IS_IN_FAT && SYS_REDUNDAND_ENVIRONMENT
default “uboot-redund.env”
help
It’s a string of the FAT file name. This file use to store the
redundant environment.
源码分析
saveenv命令调用env/env.c --env_save()函数
函数内部会去调用注册的save函数,save()由各个存储介质的env操作文件注册,这里以flash为例, 未定义其他存储介质的话,则为nowhere;
参考
https://blog.csdn.net/qq_27087571/article/details/117411663
问题 :如何找到saveenv,这个环境变量的数据是保存在那里的
1. uboot 下搜索 saveenv
./common/env_eeprom.c:int saveenv(void)
./common/env_nand.c:int nand_saveenv(void)
./common/env_flash.c:int saveenv(void)
./common/env_flash.c:int saveenv(void)2. 在uboot/common 目录下找,Makefile中加载了那个.c文件
48 obj-$(CONFIG_ENV_IS_IN_MMC) += env_mmc.o
49 obj-$(CONFIG_ENV_IS_IN_UFS) += env_ufs.o
50 obj-$(CONFIG_ENV_IS_IN_FAT) += env_fat.o
51 obj-$(CONFIG_ENV_IS_IN_EXT4) += env_ext4.o
52 obj-$(CONFIG_ENV_IS_IN_NAND) += env_nand.o
53 obj-$(CONFIG_ENV_IS_IN_NVRAM) += env_nvram.o3. 可以看到这里有很多的宏定义,搜索宏定义在哪里定义的
./include/configs/hi3516dv200.h:#define CONFIG_ENV_IS_IN_NAND
./include/configs/hi3516dv200.h:#define CONFIG_ENV_IS_IN_NAND
./include/configs/iconnect.h:#define CONFIG_ENV_IS_IN_NAND
./include/configs/spear6xx_evb.h:#define CONFIG_ENV_IS_IN_NAND
./include/configs/hi3516ev300.h:#define CONFIG_ENV_IS_IN_NAND
./include/configs/hi3516ev300.h:#define CONFIG_ENV_IS_IN_NAND
https://blog.csdn.net/qq_40897531/article/details/106155218 (具体介绍了)
https://blog.csdn.net/ITdadada/article/details/105421719
https://blog.csdn.net/lqqtwo/article/details/126542569
为了从用户空间修改 U-Boot 环境变量,需要名为“mkenvimage”的程序,该程序可以从 U-Boot 源生成,按照 tools/env/README 文件中的说明进行操作。
make env
这将得到程序 “mkenvimage”
需要描述环境的文本文件 “uboot-env.txt” 如下:
git-bash
bootargs=console=ttyS0,115200
bootcmd=tftp 22000000 Image
[…]
然后按如下方式使用 mkenvimage:
./mkenvimage -s 0x40000 -o uboot-env.bin uboot-env.txt
-s 选项允许指定要创建的映像的大小。它必须与为 U-Boot 环境保留的闪存区域的大小相匹配。
echo “/boot/uboot.env 0x0000 0x20000” > /etc/fw_env.config
mkenvimage -s 0x20000 -o /boot/uboot.env /etc/u-boot-initial-env
在最后面有这样两句话:
/* 16k Total Size of Environment Sector */
#define CONFIG_ENV_SIZE 0x4000
这里定义了环境变量的空间大小,改成
/* 64k Total Size of Environment Sector */
#define CONFIG_ENV_SIZE 0x10000
改成一整个sector就可以了。
————————————————
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/chenqiai0/article/details/8821348
u-boot根目录下make menuconfig
存储配置:
Environment —>
Select the location of the environment
(X) Environment in a block device
build/boards/cv181x/sg2002_wevb_riscv64_sd/u-boot/cvitek_sg2002_wevb_riscv64_sd_defconfig
- CONFIG_ENV_IS_NOWHERE=y
soph# saveenv
Unknown command ‘saveenv’ - try ‘help’
/home/share/samba/risc-v/sophpi/u-boot-2021.10/build/sg2002_wevb_riscv64_sd
make menuconfig
CONFIG_ENV_IS_NOWHERE=y
CONFIG_ENV_IS_IN_FAT=y
soph# saveenv
Saving Environment to nowhere… not possible
错误解决:
/home/share/samba/risc-v/sophpi/u-boot-2021.10 is not clean, please run ‘make mrproper’
cd u-boot-2021.10
make mrproper
make mrproper命令会删除所有的编译生成文件、内核配置文件(.config文件)和各种备份文件
int env_save(void)
{
struct env_driver *drv;
drv = env_driver_lookup(ENVOP_SAVE, gd->env_load_prio);
if (drv) {int ret;printf("Saving Environment to %s... ", drv->name);if (!drv->save) {printf("not possible\n");return -ENODEV;}if (!env_has_inited(drv->location)) {printf("not initialized\n");return -ENODEV;}ret = drv->save();if (ret)printf("Failed (%d)\n", ret);elseprintf("OK\n");if (!ret)return 0;
}return -ENODEV;
}