您的位置:首页 > 其它

4000 U-BOOT环境变量的获取和保存的实现分析

2016-06-10 23:21 393 查看
本文主要以U-boot(1.1.6)为例进行说明。
1.相关文件
common/env_common.c
供u-boot调用的通用函数接口,它们隐藏了env的不同实现方式,比如dataflash, epprom, flash等

common/env_dataflash.c
env 存储在dataflash中的实现

common/env_epprom.c
env 存储在epprom中的实现
 
common/env_flash.c
env 存储在flash中的实现
 
common/env_nand.c
env 存储在nand中的实现
 
common/env_nvedit.c
实现u-boot对环境变量的操作命令

environment.c
环境变量以及一些宏定义

env如果存储在Flash中还需要Flash的支持。

2.数据结构
env 在 u-boot 中通常有两种存在方式,在永久性存储介质中( Flash NVRAM等 )在SDRAM,可以配置不使用 env 的永久存储方式,但这不常用。u-boot 在启动的时候会将存储在永久性存储介质中的 env 重新定位到 RAM 中,这样可以快速访问,同时可以通过saveenv将 RAM 中的 env 保存到永久性存储介质中。

在tools/env/fw_env.c中定义了表示env的数据结构
typedef struct environment_s {
    ulong crc;            /* CRC32 over data bytes    */
    uchar flags;            /* active or obsolete */
    uchar *data;
} env_t;
关于以上结构的说明:
crc是u-boot在保存env 的时候加上去的校验头,在第一次启动时一般 crc校验会出错,这很正常,因为这时 Flash中的数据无效。data字段保存实际的环境变量。u-boot的env按 name=value”\0”的方式存储,在所有env的最后以”\0\0”表示整个env的结束。新的name=value对总是被添加到env数据块的末尾,当删除一个name=value时,后面的环境变量将前移,对一个已经存在的环境变量的修改实际上先删除再插入。
env可以保存在 u-boot的TEXT段中,这样env就可以同u-boot一同加载入RAM中,这种方法没有测试过。
       上文提到u-boot会将env从flash等存储设备重定位到RAM中,在env的不同实现版本( env_xxx.c )中定义了env_ptr, 它指向 env在RAM中的位置。u-boot在重定位env后对环境变量的操作都是针对 env_ptr。这个后面有说明。
       env_t中除了数据之外还包含校验头,u-boot把env_t 的数据指针又保存在了另外一个地方,这就是 gd_t结构(不同平台有不同的 gd_t结构),这里以ARM为例仅列出和 env 相关的部分
这个结构体在U-Boot的include/asm-arm/global_data.h中定义如下:
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
1a4bc
Environment struct */
........................
} gd_t;
gd_t.env_addr 即指向 env_ptr->data。

3.ENV的初始化
1):env_init函数
我们来看一下env_init函数,env 存储在不同的存储介质中,有不同的实现函数,这里以先以norflash,为例,它在common/env_flash.c中
在common/env_flash.c中对env_ptr定义如下:
char * env_name_spec = "Flash";

#ifdef ENV_IS_EMBEDDED

extern uchar environment[];
env_t *env_ptr = (env_t *)(&environment[0]); //env_ptr指向默认环境参数存放地址

#ifdef CMD_SAVEENV
/* static env_t *flash_addr = (env_t *)(&environment[0]);-broken on ARM-wd-*/
static env_t *flash_addr = (env_t *)CFG_ENV_ADDR;
#endif

#else /* ! ENV_IS_EMBEDDED */

env_t *env_ptr = (env_t *)CFG_ENV_ADDR;  //env_ptr指向norflash环境参数存放地址
#ifdef CMD_SAVEENV
static env_t *flash_addr = (env_t *)CFG_ENV_ADDR;
#endif

#endif /* ENV_IS_EMBEDDED */
注:env_ptr在不同的存储介质中都有相应的定义

int  env_init(void)
{
#ifdef CONFIG_OMAP2420H4
    int flash_probe(void);

    if(flash_probe() == 0)
        goto bad_flash;
#endif
    if (crc32(0, env_ptr->data, ENV_SIZE) == env_ptr->crc) {  //使用norflash中环境参数
        gd->env_addr  = (ulong)&(env_ptr->data);
        gd->env_valid = 1;   标识环境变量可用
        return(0);
    }
#ifdef CONFIG_OMAP2420H4
bad_flash:
#endif
    gd->env_addr  = (ulong)&default_environment[0];//否则使用默认的环境参数
    gd->env_valid = 0;  使用默认环境变量参数,gd->env_valid设置为0,标识环境变量不可用
    return (0);
}
实现 env的第一次初始化,对于nand env(非embedded方式)它在common/env_nand.c中:
char * env_name_spec = "NAND";

#ifdef ENV_IS_EMBEDDED
extern uchar environment[];
env_t *env_ptr = (env_t *)(&environment[0]); //env_ptr指向默认环境参数存放地址
#else /* ! ENV_IS_EMBEDDED */
env_t *env_ptr = 0;   //env_ptr初始化为空指针
#endif /* ENV_IS_EMBEDDED */

/* local functions */
#if !defined(ENV_IS_EMBEDDED)
static void use_default(void);
#endif

int env_init(void)
{
#if defined(ENV_IS_EMBEDDED)  
    ulong total;
    int crc1_ok = 0, crc2_ok = 0;
    env_t *tmp_env1, *tmp_env2;

    total = CFG_ENV_SIZE;

    tmp_env1 = env_ptr;
    tmp_env2 = (env_t *)((ulong)env_ptr + CFG_ENV_SIZE);

    crc1_ok = (crc32(0, tmp_env1->data, ENV_SIZE) == tmp_env1->crc);
    crc2_ok = (crc32(0, tmp_env2->data, ENV_SIZE) == tmp_env2->crc);

    if (!crc1_ok && !crc2_ok)
        gd->env_valid = 0;
    else if(crc1_ok && !crc2_ok)
        gd->env_valid = 1;
    else if(!crc1_ok && crc2_ok)
        gd->env_valid = 2;
    else {
        /* both ok - check serial */
        if(tmp_env1->flags == 255 && tmp_env2->flags == 0)
            gd->env_valid = 2;
        else if(tmp_env2->flags == 255 && tmp_env1->flags == 0)
            gd->env_valid = 1;
        else if(tmp_env1->flags > tmp_env2->flags)
            gd->env_valid = 1;
        else if(tmp_env2->flags > tmp_env1->flags)
            gd->env_valid = 2;
        else /* flags are equal - almost impossible */
            gd->env_valid = 1;
    }

    if (gd->env_valid == 1)
        env_ptr = tmp_env1;
    else if (gd->env_valid == 2)
        env_ptr = tmp_env2;
#else /* ENV_IS_EMBEDDED */
    gd->env_addr  = (ulong)&default_environment[0];//非embedded方式
    gd->env_valid = 1; //env有效位置1,标识环境变量可用
#endif /* ENV_IS_EMBEDDED */

    return (0);
}
2)环境变量的初始化env_relocate
common/env_common.c
void env_relocate (void)
{
    DEBUGF ("%s[%d] offset = 0x%lx\n", __FUNCTION__,__LINE__,
        gd->reloc_off);

#ifdef CONFIG_AMIGAONEG3SE  //未定义
    enable_nvram();
#endif

#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
     */
    env_ptr = (env_t *)malloc (CFG_ENV_SIZE);  //env_ptr重定位到内存空间
    DEBUGF ("%s[%d] malloced ENV at %p\n", __FUNCTION__,__LINE__,env_ptr);
#endif

    /*
     * After relocation to RAM, we can always use the "memory" functions
     */
    env_get_char = env_get_char_memory; //重新初始化函数指针,该函数指针原来在common/env_common.c文件中被初始化为env_get_char_init,现在改为env_get_char_memory。对于nand flash,这两个函数是一样的。

    if (gd->env_valid == 0) { //在 env_annd.c和env_flash.c : env_init 中已经将 gd->env_valid 置1

#if defined(CONFIG_GTH)    || defined(CFG_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 (-1);
#endif

        if (sizeof(default_environment) > ENV_SIZE)
        {
            puts ("*** Error - default environment is too large\n\n");
            return;
        }

        memset (env_ptr, 0, sizeof(env_t));
        memcpy (env_ptr->data,
            default_environment,
            sizeof(default_environment)); //拷贝环境变量
#ifdef CFG_REDUNDAND_ENVIRONMENT
        env_ptr->flags = 0xFF;
#endif
        env_crc_update (); //更新crc32校验
        gd->env_valid = 1; //标识环境变量可用
    }
    else {
        env_relocate_spec ();//如果flash上有参数表可用,则从flash上加载,通过调用具体的env_relocate_spec函数来实现
    }
    gd->env_addr = (ulong)&(env_ptr->data); //最终完成将环境变量搬移到内存,即将环境变量的值赋值给全局变量gd->env_addr,这样只要通过这个全局变量就可以访问这些变量了。值得一提的是,字符串数组data里面的变量与变量之间是通过’\0’来分割的。

#ifdef CONFIG_AMIGAONEG3SE
    disable_nvram();
#endif
}
这里涉及到两个和环境变量有关的宏,都在include/configs/smdk2410.h配置文件中定义
ENV_IS_EMBEDDED : env 是否存在于u-boot TEXT段中,未定义
CFG_ENV_SIZE : env 块的大小
实际上还需要几个宏来控制u-boot 对环境变量的处理
CFG_ENV_IS_IN_NAND : env 块是否存在于Nand Flash 中
CFG_ENV_OFFSET : env 块在 Flash 中偏移地址
#define PHYS_FLASH_1            0x00000000 /* Flash Bank #1 */
#define CFG_FLASH_BASE          PHYS_FLASH_1

#define CONFIG_AMD_LV400        1       /* uncomment this if you have a LV400 flash */
#if 0
#define CONFIG_AMD_LV800        1       /* uncomment this if you have a LV800 flash */
#endif

#define CFG_MAX_FLASH_BANKS     1       /* max number of memory banks */
#ifdef CONFIG_AMD_LV800
#define PHYS_FLASH_SIZE         0x00100000 /* 1MB */
#define CFG_MAX_FLASH_SECT      (19)    /* max number of sectors on one chip */
#define CFG_ENV_ADDR            (CFG_FLASH_BASE + 0x0F0000) /* addr of environment */
#endif
#ifdef CONFIG_AMD_LV400
#define PHYS_FLASH_SIZE         0x00080000 /* 512KB */
#define CFG_MAX_FLASH_SECT      (11)    /* max number of sectors on one chip */
#define CFG_ENV_ADDR            (CFG_FLASH_BASE + 0x070000) /* addr of environment */
#endif

/* timeout values are in ticks */
#define CFG_FLASH_ERASE_TOUT    (5*CFG_HZ) /* Timeout for Flash Erase */
#define CFG_FLASH_WRITE_TOUT    (5*CFG_HZ) /* Timeout for Flash Write */

#define CFG_ENV_IS_IN_FLASH     1
#define CFG_ENV_SIZE            0x10000 /* Total Size of Environment Sector */

3、env_relocate_spec
env_relocate_spec针对不同的存储介质有不同的实现
env_relocate_spec在common/env_flash.c中的实现
void env_relocate_spec (void)
{
#if !defined(ENV_IS_EMBEDDED) || defined(CFG_ENV_ADDR_REDUND)
#ifdef CFG_ENV_ADDR_REDUND  //未定义,boot的参数表还支持一种被称为CFG_ENV_OFFSET_REDUND的冗余模式,它会在flash上保存两个参数表副本,这样在一个副本出错的时候,还可以从另一个副本中去读取,通过这种方式,提高了数据的安全性。
    if (gd->env_addr != (ulong)&(flash_addr->data)) {
        env_t * etmp = flash_addr;
        ulong ltmp = end_addr;

        flash_addr = flash_addr_new;
        flash_addr_new = etmp;

        end_addr = end_addr_new;
        end_addr_new = ltmp;
    }

    if (flash_addr_new->flags != OBSOLETE_FLAG &&
        crc32(0, flash_addr_new->data, ENV_SIZE) ==
        flash_addr_new->crc) {
        char flag = OBSOLETE_FLAG;

        gd->env_valid = 2;
        flash_sect_protect (0, (ulong)flash_addr_new, end_addr_new);
        flash_write(&flag,
                (ulong)&(flash_addr_new->flags),
                sizeof(flash_addr_new->flags));
        flash_sect_protect (1, (ulong)flash_addr_new, end_addr_new);
    }

    if (flash_addr->flags != ACTIVE_FLAG &&
        (flash_addr->flags & ACTIVE_FLAG) == ACTIVE_FLAG) {
        char flag = ACTIVE_FLAG;

        gd->env_valid = 2;
        flash_sect_protect (0, (ulong)flash_addr, end_addr);
        flash_write(&flag,
                (ulong)&(flash_addr->flags),
                sizeof(flash_addr->flags));
        flash_sect_protect (1, (ulong)flash_addr, end_addr);
    }

    if (gd->env_valid == 2)
        puts ("*** Warning - some problems detected "
              "reading environment; recovered successfully\n\n");
#endif /* CFG_ENV_ADDR_REDUND */
    memcpy (env_ptr, (void*)flash_addr, CFG_ENV_SIZE);  //读出操作,将环境参数重定向到RAM中
#endif /* ! ENV_IS_EMBEDDED || CFG_ENV_ADDR_REDUND */
}

env_relocate_spec在common/env_nand.c中的实现
void env_relocate_spec (void)
{
#if !defined(ENV_IS_EMBEDDED)  //如果不是使用嵌入参数的形式,即为参数表的形式
    ulong total;
    int ret;

    total = CFG_ENV_SIZE;  //参数表大小,包括参数表头部
//读出操作,flash设备为nand_info,偏移为CFG_ENV_OFFSET,读出的大小为total,目标地址由env_ptr所指。
    ret = nand_read(&nand_info[0], CFG_ENV_OFFSET, &total, (u_char*)env_ptr);
      if (ret || total != CFG_ENV_SIZE)  //如果读出的长度不对或出错,则使用默认值
        return use_default();

    if (crc32(0, env_ptr->data, ENV_SIZE) != env_ptr->crc)  //如果校验出错,使用默认值
        return use_default();
#endif /* ! ENV_IS_EMBEDDED */
}

static void use_default()
{
        puts ("*** Warning - bad CRC or NAND, using default environment\n\n");

        if (default_environment_size > CFG_ENV_SIZE){
                puts ("*** Error - default environment is too large\n\n");
                return;
        }

        memset (env_ptr, 0, sizeof(env_t));
        memcpy (env_ptr->data,
                        default_environment,
                        default_environment_size);
        env_ptr->crc = crc32(0, env_ptr->data, ENV_SIZE);
        gd->env_valid = 1;  //设置环境参数有效

}

4、读取环境变量
Uboot中经常要读取环境变量,这是通过getenv来实现的:
它定义在common/cmd_nvedit.c文件中

 return (NULL);
}
这里重点理解env_get_char函数,它定义在common/env_common.c中:

 return c;
#else
 return *((uchar *)(gd->env_addr + index));
#endif
}
#endif
env_get_char_init函数功能就是如果保存了参数到flsah中就调用env_get_char_spec从指定的flash地址中读取参数字符,否则就从默认环境变量参数中读取参数字符。

uchar *env_get_addr (int index)
{
 if (gd->env_valid) {
  return ( ((uchar *)(gd->env_addr + index)) );
 } else {
  return (&default_environment[index]);
 }
}
这个函数功能是返回找到的环境变量字符串数组地址。

5、环境变量的设置过程

 return _do_setenv (flag, argc, argv);
}
int _do_setenv (int flag, int argc, char *argv[])
{
    int   i, len, oldval;
    int   console = -1;
    uchar *env, *nxt = NULL;
    char *name;
    bd_t *bd = gd->bd;

    uchar *env_data = env_get_addr(0);

    if (!env_data)    /* need copy in RAM */
        return 1;

    name = argv[1];

    if (strchr(name, '=')) {
        printf ("## Error: illegal character '=' in variable name \"%s\"\n", name);
        return 1;
    }

    /*
     * search if variable with this name already exists
     */
    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;
    }

    /*
     * Delete any existing definition
     */
    if (oldval >= 0) {
#ifndef CONFIG_ENV_OVERWRITE

        /*
         * Ethernet Address and serial# can be set only once,
         * ver is readonly.
         */
        if ( (strcmp (name, "serial#") == 0) ||
            ((strcmp (name, "ethaddr") == 0)
#if defined(CONFIG_OVERWRITE_ETHADDR_ONCE) && defined(CONFIG_ETHADDR)
             && (strcmp ((char *)env_get_addr(oldval),MK_STR(CONFIG_ETHADDR)) != 0)
#endif    /* CONFIG_OVERWRITE_ETHADDR_ONCE && CONFIG_ETHADDR */
            ) ) {
            printf ("Can't overwrite \"%s\"\n", name);
            return 1;
        }
#endif

        /* Check for console redirection */
        if (strcmp(name,"stdin") == 0) {
            console = stdin;
        } else if (strcmp(name,"stdout") == 0) {
            console = stdout;
        } else if (strcmp(name,"stderr") == 0) {
            console = stderr;
        }

        if (console != -1) {
            if (argc < 3) {        /* Cannot delete it! */
                printf("Can't delete \"%s\"\n", name);
                return 1;
            }

            /* Try assigning specified device */
            if (console_assign (console, argv[2]) < 0)
                return 1;

#ifdef CONFIG_SERIAL_MULTI
            if (serial_assign (argv[2]) < 0)
                return 1;
#endif
        }

        /*
         * Switch to new baudrate if new baudrate is supported
         */
        if (strcmp(argv[1],"baudrate") == 0) {
            int baudrate = simple_strtoul(argv[2], NULL, 10);
            int i;
            for (i=0; i<n_baudrates; ++i)="" {

                 if (baudrate == baudrate_table[i])

                    break;

            }

            if (i == N_BAUDRATES) {

                printf ("## Baudrate %d bps not supported\n",

                    baudrate);

                return 1;

            }

            printf ("## Switch baudrate to %d bps and press ENTER ...\n",

                baudrate);

            udelay(50000);

            gd->baudrate = baudrate;

#ifdef CONFIG_PPC

            gd->bd->bi_baudrate = baudrate;

#endif

            serial_setbrg ();

            udelay(50000);

            for (;;) {

                if (getc() == '\r')

                      break;

            }

        }

        if (*++nxt == '\0') {

            if (env > env_data) {

                env--;

            } else {

                *env = '\0';

            }

        } else {

            for (;;) {

                *env = *nxt++;

                if ((*env == '\0') && (*nxt == '\0'))

                    break;

                ++env;

            }

        }

        *++env = '\0';

    }

#ifdef CONFIG_NET_MULTI

    if (strncmp(name, "eth", 3) == 0) {

        char *end;

        int   num = simple_strtoul(name+3, &end, 10);

        if (strcmp(end, "addr") == 0) {

            eth_set_enetaddr(num, argv[2]);

        }

    }

#endif

    /* Delete only ? */

    if ((argc < 3) || argv[2] == NULL) {

        env_crc_update ();

        return 0;

    }

    /*

     * Append new definition at the end

     */

    for (env=env_data; *env || *(env+1); ++env)

        ;

    if (env > env_data)

        ++env;

    /*

     * Overflow when:

     * "name" + "=" + "val" +"\0\0"  > ENV_SIZE - (env-env_data)

     */

    len = strlen(name) + 2;

    /* add '=' for first arg, ' ' for all others */

    for (i=2; i<argc; ++i)="" {

         len += strlen(argv[i]) + 1;

    }

    if (len > (&env_data[ENV_SIZE]-env)) {

        printf ("## Error: environment overflow, \"%s\" deleted\n", name);

        return 1;

    }

    while ((*env = *name++) != '\0')

        env++;

    for (i=2; i<argc; ++i)="" {

         char *val = argv[i];

        *env = (i==2) ? '=' : ' ';

        while ((*++env = *val++) != '\0')

            ;

    }

    /* end is marked with double '\0' */

    *++env = '\0';

    /* Update CRC */

    env_crc_update ();

    /*

     * Some variables should be updated when the corresponding

     * entry in the enviornment is changed

     */

    if (strcmp(argv[1],"ethaddr") == 0) {

        char *s = argv[2];    /* always use only one arg */

        char *e;

        for (i=0; i<6; ++i) {

            bd->bi_enetaddr[i] = s ? simple_strtoul(s, &e, 16) : 0;

            if (s) s = (*e) ? e+1 : e;

        }

#ifdef CONFIG_NET_MULTI

        eth_set_enetaddr(0, argv[2]);

#endif

        return 0;

    }

    if (strcmp(argv[1],"ipaddr") == 0) {

        char *s = argv[2];    /* always use only one arg */

        char *e;

        unsigned long addr;

        bd->bi_ip_addr = 0;

        for (addr=0, i=0; i<4; ++i) {

            ulong val = s ? simple_strtoul(s, &e, 10) : 0;

            addr <<= 8;

            addr  |= (val & 0xFF);

            if (s) s = (*e) ? e+1 : e;

        }

        bd->bi_ip_addr = htonl(addr);

        return 0;

    }

    if (strcmp(argv[1],"loadaddr") == 0) {

        load_addr = simple_strtoul(argv[2], NULL, 16);

        return 0;

    }

#if (CONFIG_COMMANDS & CFG_CMD_NET)

    if (strcmp(argv[1],"bootfile") == 0) {

        copy_filename (BootFile, argv[2], sizeof(BootFile));

        return 0;

    }

#endif    /* CFG_CMD_NET */

#ifdef CONFIG_AMIGAONEG3SE

    if (strcmp(argv[1], "vga_fg_color") == 0 ||

        strcmp(argv[1], "vga_bg_color") == 0 ) {

        extern void video_set_color(unsigned char attr);

        extern unsigned char video_get_attr(void);

        video_set_color(video_get_attr());

        return 0;

    }

#endif    /* CONFIG_AMIGAONEG3SE */

    return 0;

}

6、环境变量的保存,保存是读取的反过程,所以跟上面的过程相似,如下:

common/env_nand.c

int saveenv(void)

{

    ulong total;

    int ret = 0;

    puts ("Erasing Nand..."); //先擦除

    if (nand_erase(&nand_info[0], CFG_ENV_OFFSET, CFG_ENV_SIZE))

        return 1;

    puts ("Writing to Nand... "); //后写入

    total = CFG_ENV_SIZE;

    ret = nand_write(&nand_info[0], CFG_ENV_OFFSET, &total, (u_char*)env_ptr);

    if (ret || total != CFG_ENV_SIZE)

        return 1;

    puts ("done\n");

    return ret;

}

common/env_flash.c

int saveenv(void)

{

    char *saved_data = NULL;

    int rc = 1;

    char flag = OBSOLETE_FLAG, new_flag = ACTIVE_FLAG;

#if CFG_ENV_SECT_SIZE > CFG_ENV_SIZE

    ulong up_data = 0;

#endif

    debug ("Protect off %08lX ... %08lX\n",

        (ulong)flash_addr, end_addr);

    if (flash_sect_protect (0, (ulong)flash_addr, end_addr)) {

        goto Done;

    }

    debug ("Protect off %08lX ... %08lX\n",

        (ulong)flash_addr_new, end_addr_new);

    if (flash_sect_protect (0, (ulong)flash_addr_new, end_addr_new)) {

        goto Done;

    }

#if CFG_ENV_SECT_SIZE > CFG_ENV_SIZE

    up_data = (end_addr_new + 1 - ((long)flash_addr_new + CFG_ENV_SIZE));

    debug ("Data to save 0x%x\n", up_data);

    if (up_data) {

        if ((saved_data = malloc(up_data)) == NULL) {

           
b45e
printf("Unable to save the rest of sector (%ld)\n",

                up_data);

            goto Done;

        }

        memcpy(saved_data,

            (void *)((long)flash_addr_new + CFG_ENV_SIZE), up_data);

        debug ("Data (start 0x%x, len 0x%x) saved at 0x%x\n",

               (long)flash_addr_new + CFG_ENV_SIZE,

                up_data, saved_data);

    }

#endif

    puts ("Erasing Flash...");

    debug (" %08lX ... %08lX ...",

        (ulong)flash_addr_new, end_addr_new);

    if (flash_sect_erase ((ulong)flash_addr_new, end_addr_new)) {

        goto Done;

    }

    puts ("Writing to Flash... ");

    debug (" %08lX ... %08lX ...",

        (ulong)&(flash_addr_new->data),

        sizeof(env_ptr->data)+(ulong)&(flash_addr_new->data));

    if ((rc = flash_write((char *)env_ptr->data,

            (ulong)&(flash_addr_new->data),

            sizeof(env_ptr->data))) ||

        (rc = flash_write((char *)&(env_ptr->crc),

            (ulong)&(flash_addr_new->crc),

            sizeof(env_ptr->crc))) ||

        (rc = flash_write(&flag,

            (ulong)&(flash_addr->flags),

            sizeof(flash_addr->flags))) ||

        (rc = flash_write(&new_flag,

            (ulong)&(flash_addr_new->flags),

            sizeof(flash_addr_new->flags))))

    {

        flash_perror (rc);

        goto Done;

    }

    puts ("done\n");

#if CFG_ENV_SECT_SIZE > CFG_ENV_SIZE

    if (up_data) { /* restore the rest of sector */

        debug ("Restoring the rest of data to 0x%x len 0x%x\n",

               (long)flash_addr_new + CFG_ENV_SIZE, up_data);

        if (flash_write(saved_data,

                (long)flash_addr_new + CFG_ENV_SIZE,

                up_data)) {

            flash_perror(rc);

            goto Done;

        }

    }

#endif

    {

        env_t * etmp = flash_addr;

        ulong ltmp = end_addr;

        flash_addr = flash_addr_new;

        flash_addr_new = etmp;

        end_addr = end_addr_new;

        end_addr_new = ltmp;

    }

    rc = 0;

Done:

    if (saved_data)

        free (saved_data);

    /* try to re-protect */

    (void) flash_sect_protect (1, (ulong)flash_addr, end_addr);

    (void) flash_sect_protect (1, (ulong)flash_addr_new, end_addr_new);

    return rc;
}

转自http://blog.chinaunix.net/uid-20672257-id-2430683.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: