一般情況下,內核需要的參數都是通過bootargs傳入kernel,而kernel一般對其也不需要進行寫操作。但一些特殊情況,如OTA升級時候需要修改標志,讓bootloader可以在下次啟動時進入recovery模式。此時就有可能對env變量進行寫入。這個寫入通常可以通過uboot中的fw_env控件來實現。編譯方法很簡單 ,在uboot下
make env
進入uboot/tools/env可以看到編譯完成的fw_printenv,但是這個只能顯示,如果需要修改,則必須ln 一個軟鏈接到fw_printenv,否則無法操作
ln -s fw_printenv fw_setenv
這里還需要注意,如果選擇了定義CONFIG文件位置,如/etc/fw_env.config,需要把fw_env.config拷貝到系統的/etc目錄下,這個config文件用於配置uboot env的存儲位置,如下文件,默認存儲了兩份,一份在/dev/mtd1 0x0000 0x4000,一份在/dev/mtd2 0x0000 0x4000,這個根據你的系統來定,如emmc 分區中可以配成/dev/mmcblk0 0xc000 0x4000
# Configuration file for fw_(printenv/setenv) utility. # Up to two entries are valid, in this case the redundant # environment sector is assumed present. # Notice, that the "Number of sectors" is not required on NOR and SPI-dataflash. # Futhermore, if the Flash sector size is ommitted, this value is assumed to # be the same as the Environment size, which is valid for NOR and SPI-dataflash # NOR example # MTD device name Device offset Env. size Flash sector size Number of sectors /dev/mtd1 0x0000 0x4000 0x4000 /dev/mtd2 0x0000 0x4000 0x4000 # MTD SPI-dataflash example # MTD device name Device offset Env. size Flash sector size Number of sectors #/dev/mtd5 0x4200 0x4200 #/dev/mtd6 0x4200 0x4200 # NAND example #/dev/mtd0 0x4000 0x4000 0x20000 2 # Block device example #/dev/mmcblk0 0xc0000 0x20000 # VFAT example #/boot/uboot.env 0x0000 0x4000
另外如果你想直接在你的應用程序中使用這個庫文件,可以把目錄下的lib.a鏈接到你的應用中。導出的函數有
extern int fw_printenv(int argc, char *argv[]); extern char *fw_getenv (char *name); extern int fw_setenv (int argc, char *argv[]); extern int fw_parse_script(char *fname); extern int fw_env_open(void); extern int fw_env_write(char *name, char *value); extern int fw_env_close(void); extern unsigned long crc32 (unsigned long, const unsigned char *, unsigned);
根據自己需要,使用起來非常方便。
唯一需要注意的是操作是加文件鎖,防止多個進程寫入,數據出錯,大概流程如下,具體可以參考 fw_env_main.c
const char *lockname = "/var/lock/" CMD_PRINTENV ".lock"; int lockfd = -1; lockfd = open(lockname, O_WRONLY | O_CREAT | O_TRUNC, 0666); flock(lockfd, LOCK_EX); //set or read uboot env flock(lockfd, LOCK_UN);