现在的位置: 首页 > 综合 > 正文

设计一个可靠的Flash env存储区WS_ENV

2013年12月04日 ⁄ 综合 ⁄ 共 19923字 ⁄ 字号 评论关闭

*******设计可靠的env存储区(WS_ENV)
*** 使用环境
    在嵌入式系统中,bootloader与linux kernel都需要互相传递变量,例如在bootloader中设
    置IP地址,在kernel中读取IP地址。如果让boot loader直接写linux的文件系统,bootloader
    将会变得非常大,一般都使用环境变量实现变量的传递。 

*** 算法设计
    通过研究发现,env使用的是字符串,而且flash的特点是由1变0容易,由0变1需要重新擦除。

可以顺序的按照tag value把env存储于flash中,例如:
    ⊙代表结束符”/0”.
    原始存储区orig:tag1⊙val1⊙tag2⊙val2⊙tag3⊙val3⊙剩余位置
  a. 增加操作ws_setenv:
 从orig增加一个tag4时,在结尾处增加,如:
    tag1⊙val1⊙tag2⊙val2⊙tag3⊙val3⊙tag4⊙val4⊙剩余位置
    从orig增加tag4的值为空字符串时,如下:
    tag1⊙val1⊙tag2⊙val2⊙tag3⊙val3⊙tag4⊙⊙剩余位置
    当剩余位置到达了env所在的块的结尾位置,则需要整理(defrag):
    将整块擦除,然后再从内存中的控制结构中写入所有的tag,下面会详述控制结构。
    为了保证擦除整块env后,突然断电,不会造成数据丢失,需要有一个备份env块。
    擦除前将env拷贝到备份env后,再擦除env。

  b. 删除操作ws_unsetenv:
     从orig删除一个tag1时,将对应的tag1与val全部变为⊙(因为1变0容易)。如:
     ⊙⊙⊙⊙⊙⊙⊙⊙⊙⊙tag2⊙val2⊙tag3⊙val3⊙剩余位置
  c. 修改操作ws_setenv:
     从orig修改tag1, 让其值变为changed,将实行删除后,再增加操作.如:
     ⊙⊙⊙⊙⊙⊙⊙⊙⊙⊙tag2⊙val2⊙tag3⊙val3⊙tag1⊙changed⊙剩余位置

     通过上述算法,可以设计出env的排列结构如下:
     若env块的前4个字节为“good”表示env存储区未损坏,不需要从备份区拷贝数据。否
     则需要擦除env,然后从备份区拷贝(64k-4)的数据。
     相应的内存数据结构设计如下所示。
  d. recovery env algorithm:
     1. 如果backup env的magic有效,从backup env中拷贝数据到env。数据拷贝完后,
        擦除backup env block。
     2. 当前env的数据存储满后,先把当前env的所有数据存储到backup env中,然后
        擦除env,再把内存中的数据写入env区。写完后,写入env magic, 然后擦除
        backup env block.
        分析:这里需要考虑极端情况:假设当前系统env已满,但defrag后剩余的空间
        只有一点点, 那么,例如设置一个相同tag的值时,首先找到env,然后设置为⊙,
        然后defrag,仅回收刚才设置为⊙的空间,这样会照成每设几个env,就要defrag,
        实在不划算。因此建议判断是否需要defrag的条件改为:
        当前系统有效空间+env值小于env size-4k。如果不满足,则直接返回空间已满。

***Hash设计
   为了提高查找效率,需要设计好的hash算法,对于env来说,字符串,让每个字母相加,
   得到的值再对hash表的大小取余,得到的位置就是env要插入的链表位置。

*** 数据结构设计
/* 每个env变量的结构 */
struct env_entry
{
 struct env_entry *next;     /* pointer to next entry */
 unsigned int tag_offset;    /* Offset in the env block */
 char *tag_name;
 char *tag_val;
};

/* 整个env的控制区 */
struct env_info
{
    unsigned int base_addr;     /* env base address, must start from a new block */
    unsigned int env_size;      /* env size, include backup env sector */
    unsigned int block_size;    /* memory block size, in byte */
    unsigned int env_valid_size;/* valid env entrys size */
    unsigned int free_offs;     /* Offset from base_addr */
    unsigned int numEntrys;     /* number of env entrys */
    struct env_entry **hash_bucket;
    void *priv;  /* private data, use it whateven you like */
    struct semaphore    env_lock; /* big lock */

    int (*ws_hash)(char *name);   /* hash function */
    int (*load_env)(struct env_info *info);   /* load env from memory */
    int (*erase)(struct env_info *info, unsigned addr, unsigned len);   /* erash method */
    int (*read)(struct env_info *info, unsigned from, unsigned len, char *buf); /* read method */
    int (*write)(struct env_info *info, unsigned to, unsigned len, char *buf);  /* write method */
};

 

*** 代码实现

ws_env.h

 

ws_env.c

 

ws_env_linux.

抱歉!评论已关闭.