#include #include #include #include #include #include #include #include "hal_env.h" #include "hlog.h" #define TAG "TAG_ENV" #define BACKUP_MAGIC 0x5A5AA5A5 static int8_t g_actflag = -1; static int8_t g_modifyed_flag = 0; static int8_t g_inited = 0; static OS_MUTEX g_env_mutex = {0}; static Env_Header g_env_header = {0}; static char * g_env_values[ENV_CFG_MAX] = {0}; //all string are hv_malloc-ed static inline int32_t hal_env_is_valid(int32_t index) { if ( index <= ENV_CFG_START || index >= ENV_CFG_MAX) { hloge("Invalid env index : %d\n", index); return 0; } return 1; } static void hal_env_header_print(const char * prefix, const Env_Header* header) { hlogd("%s crc:%x age:%d version:%d\n", prefix,header->crc, header->age, header->version); } int32_t hal_env_mutex_lock() { return os_mutex_lock(&g_env_mutex); } int32_t hal_env_mutex_unlock() { return os_mutex_unlock(&g_env_mutex); } //load header and g_env_values from envbuff static int32_t hal_env_load_head_values(const void * envbuff, Env_Header * header) { //backup headers. memcpy(header, envbuff, sizeof(Env_Header)); //hv_free old value int32_t i = 0; for (; i < ENV_CFG_MAX; i++) { if ( g_env_values[i]) { hv_free(g_env_values[i]); g_env_values[i] = NULL; } } //extract/parse all values. ENV_CFG e; const unsigned char * p = (const unsigned char *)envbuff + sizeof(Env_Header); int32_t index; int32_t values = 0; //envbuff is sth like header+3hello\02world\0(the end of valid data)+\0 while ( (e = (ENV_CFG)*p) != ENV_CFG_START) { index = e; p++; //p now point to string value start if (hal_env_is_valid(index)) { g_env_values[index] = strdup((const char *)p); //clone a string for easy use values++; } while(*p) p++; //to string end p+=1; //skip '\0', p now is next ENV_CFG } return values; } int32_t hal_env_dump(){ int32_t i = 1; for (; i < ENV_CFG_MAX; i++) { const char * value = g_env_values[i]; if ( value && value[0]) { hlogd("#%d=%s\n", i, value); } else { hlogd("#%d not set.\n", i); } } return 0; } int32_t hal_env_save() { iobuffer buf; iobuffer_init(&buf); unsigned char key; unsigned char zero = 0; int32_t hasZero = 0; if (!g_modifyed_flag) return 0; hal_env_mutex_lock(); g_env_header.age++; //Note: the crc is not right at this time, will update later. iobuffer_appendData(&buf, &g_env_header, sizeof(g_env_header)); int32_t i = 0; for (; i < ENV_CFG_MAX; i++) { key = i; char * value = g_env_values[i]; if ( value && value[0] ) { iobuffer_appendData(&buf, &key, 1); iobuffer_appendData(&buf,value, strlen(value)); iobuffer_appendData(&buf, &zero, 1); hasZero = 1; } } iobuffer_appendData(&buf,&zero, 1); if (!hasZero) { //write 0 again as no any value has written iobuffer_appendData(&buf,&zero, 1); } Env_Header* header = (Env_Header*)buf.iodata; //update crc, exclude crc(4 bytes), already contains last 00 2 bytes. g_env_header.crc = header->crc = crc32(0, buf.iodata + 4, buf.size - 4); if (0 == g_actflag) { hlogd("update env1 addr : %p, size=%d,age=%d\n", ENV_CFG_1, buf.size, g_env_header.age); hal_flash_write(ENV_CFG_1, buf.iodata, buf.size); g_actflag = 1; } else { hlogd("update env0 addr : %p, size=%d,age=%d\n", ENV_CFG_0, buf.size, g_env_header.age); hal_flash_write(ENV_CFG_0, buf.iodata, buf.size); g_actflag = 0; } g_modifyed_flag = 0; hal_env_mutex_unlock(); return g_modifyed_flag; } int32_t hal_env_set_string(ENV_CFG e, const char * value) { int32_t index = (int32_t)e; if (!hal_env_is_valid(index)) return 0; //set both value and current not null for strcmp const char * current = hal_env_get_string(e, ""); value = value ? value : ""; if ( strcmp(current, value) == 0) return 0; //no change g_modifyed_flag = 1; hv_free(g_env_values[index]); if ( *value != '\0' ) { g_env_values[index] = strdup(value); }else { g_env_values[index] = NULL; } return 1; } const char* hal_env_get_string(ENV_CFG e, const char * def_val) { int32_t index = (int32_t)e; if (!hal_env_is_valid(index)) return def_val; const char * value = g_env_values[index]; if (!value || value[0] == '\0') return def_val; return value; } int32_t hal_env_is_same_value(ENV_CFG e, const char * value){ const char * val = hal_env_get_string(e, NULL); if (val == NULL || value == NULL) return 0; return !strcmp(val, value); } int32_t hal_env_get_int(ENV_CFG e, int32_t def_val) { const char * str = hal_env_get_string(e, NULL); if (str == NULL) { //hlogd("%s, e:%d, str NULL\n", __func__, e); return def_val; } //hlogd("%s, e:%d, str:%s\n", __func__, e, str); char *endptr; long ret = strtol(str, &endptr, 10); if ( *endptr != '\0' ) { hlogd("env(%d) contains a invalid int32_t: %s\n", e, str); return def_val; } return (int32_t)ret; } int32_t hal_env_set_int(ENV_CFG e, int32_t value) { char buf[64]; sprintf(buf, "%d", value); return hal_env_set_string(e, buf); } //used by cli_command.cpp only, so no definition in .h file extern void hal_env_clear() { int32_t i = ENV_CFG_START+1; for (; i < ENV_CFG_MAX; i++) { if ( g_env_values[i]) { hv_free(g_env_values[i]); g_env_values[i] = NULL; } } // no need u-boot as well g_modifyed_flag = 1; } int32_t hal_env_active_age_load(Env_Header* header) { const char* start = (const char*)header; const char* tail = start + ENV_SIZE - 1; //找到两个连续?,知道env有效长度的结? const char * p = start + sizeof(Env_Header); while( (p < tail) && (p[0] || p[1])) p++; if (p >= tail) { hloge("env data not found end,age=%d\n", header->age); return -1; } //p指向第一个结尾的0, 加上最后一0也参与crc验证,需要加2,然后去掉最前面的crc本身 int32_t avalid = p - start + 2 - 4; uint32_t crc = crc32(0, &header->age, avalid); if ( crc != header->crc) { hloge("env data crc error, age:%d, len:%d, crc %X!=%X\n", header->age, avalid, crc, header->crc); return -1; } //Good // hlogd("env data len:%d,crc:%X,age:%d\n", avalid, crc, header->age); return avalid; } //find which address is the right env. static int32_t find_right_env(char* buf0, char* buf1) { int32_t actflag = -1; //invalid value Env_Header* header0 = (Env_Header* )buf0; Env_Header* header1= (Env_Header* )buf1; hal_flash_read(ENV_CFG_0, buf0, ENV_SIZE); hal_flash_read(ENV_CFG_1, buf1, ENV_SIZE); if (header0->age >= header1->age) { if (hal_env_active_age_load(header0) > 0) actflag = 0; else if (hal_env_active_age_load(header1) > 0) actflag = 1; } else { if (hal_env_active_age_load(header1) > 0) actflag = 1; else if (hal_env_active_age_load(header0) > 0) actflag = 0; } return actflag; } int32_t hal_env_init() { int32_t ret = -1; if (!g_inited) { Env_Header* env0 = NULL, * env1 = NULL; Env_Header* cur_env; os_mutex_create(&g_env_mutex); env0 = (Env_Header*)hv_malloc(ENV_SIZE); env1 = (Env_Header*)hv_malloc(ENV_SIZE); if (!env0 || !env1 ) { hloge("memory alloc error!\n"); goto exit; } //read boot env g_actflag = find_right_env((char *)env0, (char *)env1); if (g_actflag < 0) { memset(env0, 0, ENV_SIZE); env0->age = 1; env0->version = 1; env0->crc = crc32(0, &env0->age, sizeof(Env_Header) - 4 + 2); // exclude crc(4 bytes), plus 2 bytes for 00 hal_flash_write(ENV_CFG_1, (char *)env0, sizeof(Env_Header) + 2); env0->crc = crc32(0, &env0->age, sizeof(Env_Header) - 4 + 2); // exclude crc(4 bytes), plus 2 bytes for 00 hal_flash_write(ENV_CFG_0, (char *)env0, sizeof(Env_Header) + 2); g_actflag = 0; } cur_env = (g_actflag == 0) ? env0 : env1; int32_t valid_items = hal_env_load_head_values(cur_env, &g_env_header); char buf[128]; snprintf(buf, sizeof(buf), "Active env=%d items=%d", g_actflag, valid_items); hal_env_header_print(buf, cur_env); ret = 0; g_inited = 1; exit: hv_free(env0); hv_free(env1); }else{ ret = 0; } return ret; } int32_t hal_env_deinit(){ if (g_inited){ g_inited = 0; os_mutex_delete(&g_env_mutex); } return 0; } static int32_t hal_env_cmd(int32_t argc, char ** argv) { hal_env_mutex_lock(); if ( argc == 1 ) { hal_env_dump(); } else if ( !strcmp(argv[1], "get")) { const char * key = argv[2]; if (!key) { hal_env_dump(); } else { hlogd("%s\n", hal_env_get_string((ENV_CFG)atoi(key), "")); } } else if ( !strcmp(argv[1], "save")) { hal_env_save(); } else if ( !strcmp(argv[1], "set")) { const char * key = argv[2]; const char * value = argv[3]; if (key){ hal_env_set_string((ENV_CFG)atoi(key), value); } } else if ( !strcmp(argv[1], "clear")) { hal_env_clear(); }else if ( !strcmp(argv[1], "both")) { hal_env_dump(); } else { hlogd("Unknown command: <%s>\n", argv[1]); } hal_env_mutex_unlock(); return 0; }