对于不同的存储介质,它的读写操作方式也不同,本例使用SD。
uboot-imx/include/configs/mx6q_sabresd.h
#define CONFIG_FSL_ENV_IN_MMCuboot-imx/common/Makefile
COBJS-$(CONFIG_ENV_IS_IN_MMC) += env_mmc.o所以本例对应的是env_mmc.c
b. 事实上env即可在开机后从RAM中中分配一个数据结构临时保存,也可以直接将env放在u-boot的text段从而
节省RAM空间,本例描述的是前者,后者后面文档会描述如何实现。
c. environment_s结构
uboot-imx/include/environment.h
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;crc: 读取环境变量时先会校验,其中当第一次读取的时候,因为flash没有环境变量保存,所以会失败,这是正常的。
typedef struct global_data { bd_t *bd; unsigned long flags; unsigned long baudrate; unsigned long have_console; /* serial_init() was called */ unsigned long reloc_off; /* Relocation Offset */ unsigned long env_addr; /* Address of Environment struct */ unsigned long env_valid; /* Checksum of Environment valid? */ unsigned long fb_base; /* base address of frame buffer */ ...... } gd_t;
env_add: 上面env_t的地址,一开始是指向SD中的,后来是指向RAM中的拷贝数据。
env_valid: 如果crc检验成功,则此变量为1.
流程分析:
u-boot和env相关的启动流程有:
start_armboot -> init_sequence -> env_init -> env_relocate
env_init:
uboot-imx/common/env_mmc.c
int env_init(void) { /* use default */ /*初始化为默认值以及env有效*/ gd->env_addr = (ulong)&default_environment[0]; gd->env_valid = 1; #ifdef CONFIG_DYNAMIC_MMC_DEVNO /*读取当前使用sd的mmc number*/ extern int get_mmc_env_devno(void); mmc_env_devno = get_mmc_env_devno(); #else mmc_env_devno = CONFIG_SYS_MMC_ENV_DEV; #endif return 0; }default_environment:
uboot-imx/common/env_common.c
uchar default_environment[] = { #ifdef CONFIG_BOOTARGS "bootargs=" CONFIG_BOOTARGS "\0" #endif #ifdef CONFIG_BOOTCOMMAND "bootcmd=" CONFIG_BOOTCOMMAND "\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_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_RD_LOADADDR "rd_loadaddr=" MK_STR(CONFIG_RD_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" };本例定义了:
env_relocate:
uboot-imx/common/env_common.c
void env_relocate (void) { ...... /*未定义*/ #ifdef ENV_IS_EMBEDDED /* * The environment buffer is embedded with the text segment, * just relocate the environment pointer */ env_ptr = (env_t *)((ulong)env_ptr + gd->reloc_off); DEBUGF ("%s[%d] embedded ENV at %p\n", __FUNCTION__,__LINE__,env_ptr); #else /* * We must allocate a buffer for the environment */ /*从RAM中新分配一个struct env_t*/ env_ptr = (env_t *)malloc (CONFIG_ENV_SIZE); DEBUGF ("%s[%d] malloced ENV at %p\n", __FUNCTION__,__LINE__,env_ptr); #endif /*env_init()初始化为1了*/ 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 (); } /*替换掉默认env,重新指向从SD读取的新env*/ gd->env_addr = (ulong)&(env_ptr->data); ...... }
env_relocate_spec:
void env_relocate_spec(void) { #if !defined(ENV_IS_EMBEDDED) /*获取sd信息*/ struct mmc *mmc = find_mmc_device(mmc_env_devno); /*初始化sd*/ if (init_mmc_for_env(mmc)) return; /*从sd的CONFIG_ENV_OFFSET处读取CONFIG_ENV_SIZE大小数据,也就是读取env*/ if (read_env(mmc, CONFIG_ENV_SIZE, CONFIG_ENV_OFFSET, env_ptr)) return use_default(); /*读取的env进行crc校验,由于第一次开机没有env保存到SD,所以会失败。*/ if (crc32(0, env_ptr->data, ENV_SIZE) != env_ptr->crc) return use_default(); gd->env_valid = 1; #endif }
#if !defined(ENV_IS_EMBEDDED) static void use_default() { puts ("*** Warning - bad CRC or MMC, using default environment\n\n"); set_default_env(); } #endif void set_default_env(void) { if (sizeof(default_environment) > ENV_SIZE) { puts ("*** Error - default environment is too large\n\n"); return; } memset(env_ptr, 0, sizeof(env_t)); /*使用默认的env*/ memcpy(env_ptr->data, default_environment, sizeof(default_environment)); #ifdef CONFIG_SYS_REDUNDAND_ENVIRONMENT env_ptr->flags = 0xFF; #endif /*再做crc校验*/ env_crc_update (); /*当前env有效*/ gd->env_valid = 1; }
setenv和saveenv命令:
两者对应的函数分别是:do_setenv()和saveenv().
uboot-imx/common/env_nvedit.c
setenv:
U_BOOT_CMD( setenv, CONFIG_SYS_MAXARGS, 0, do_setenv, "set environment variables", "name value ...\n" " - set environment variable 'name' to 'value ...'\n" "setenv name\n" " - delete environment variable 'name'" );
uchar *env_get_addr (int index) { /*env 有效*/ if (gd->env_valid) { /*返回之前保存在内存中env地址*/ return ( ((uchar *)(gd->env_addr + index)) ); } else { return (&default_environment[index]); } }saveenv:
U_BOOT_CMD( saveenv, 1, 0, do_saveenv, "save environment variables to persistent storage", "" );do_saveenv -> saveenv
int saveenv(void) { struct mmc *mmc = find_mmc_device(mmc_env_devno); if (init_mmc_for_env(mmc)) return 1; printf("Writing to MMC(%d)... ", mmc_env_devno); /*写到SD中永久保存*/ if (write_env(mmc, CONFIG_ENV_SIZE, CONFIG_ENV_OFFSET, env_ptr)) { puts("failed\n"); return 1; } puts("done\n"); return 0; }