浅析redboot类似字典查询函数flash_get_config具体实现
比如我们获取key键值为"boot_script"对应的value,结果存入use_boot_script中,该
value对应的type为CONFIG_BOOL[这种实现形式又有些类似dbus总线上wire数据压缩格式][luther.gliethttp]
执行语句为:flash_get_config("boot_script", &use_boot_script, CONFIG_BOOL);
来看看源码实现[luther.gliethttp]
bool
flash_get_config(char *key, void *val, int type)
{
unsigned char *dp;
void *val_ptr;
#ifdef CYGSEM_REDBOOT_FLASH_CONFIG_READONLY_FALLBACK
struct _config *save_config = 0;
#endif
if (!config_ok) return false; // config内容已经从flash安全加载到了指定heap堆空间[luther.gliethtp]
// 下面查询键值"boot_script"对应的存储地址
if ((dp = flash_lookup_config(key)) != (unsigned char *)NULL) {
// 查看类型是否一致,
// 理论上说,如果不一致应该出现了key值相同的类一个类型的dp空间,
// 并不能说明我们不存在类型一致的key,所以应该continue继续下一个查找,
// 但是可能redboot本身不需要这种需求,另外没人拿redboot只是玩,大家都是很严肃的
// 来使用redboot,所以redboot这些必须的规则,大家都会严格来遵守,所以
// 实现到这种程度的key字典查询也已经足够了[luther.gliethttp]
if (CONFIG_OBJECT_TYPE(dp) == type) {
val_ptr = (void *)CONFIG_OBJECT_VALUE(dp);
switch (type) {
// Note: the data may be unaligned in the configuration data
case CONFIG_BOOL:
memcpy(val, val_ptr, sizeof(bool)); // 拷贝数据
break;
case CONFIG_INT:
memcpy(val, val_ptr, sizeof(unsigned long)); // 拷贝数据
break;
#ifdef CYGPKG_REDBOOT_NETWORKING
case CONFIG_IP:
memcpy(val, val_ptr, sizeof(in_addr_t));
break;
case CONFIG_ESA:
memcpy(val, val_ptr, sizeof(enet_addr_t));
break;
#endif
case CONFIG_STRING:
case CONFIG_SCRIPT:
// Just return a pointer to the script/line
*(unsigned char **)val = (unsigned char *)val_ptr; // 直接将字符串地址返回,不需要执行拷贝操作,因为config区
// 是一个readonly区,没人去改动[luther.gliethttp].
break;
}
} else {
diag_printf("Request for config value '%s' - wrong type\n", key);
}
return true; // ok, 正常找到,直接return 返回
}
#ifdef CYGSEM_REDBOOT_FLASH_CONFIG_READONLY_FALLBACK
// 我们定义了该宏,如果没有找到,那么
// 怀疑是否config区域遭到灾难性破坏,于是尝试进行数据恢复[luther.gliethttp]
// Did not find key. Is configuration data valid?
// Check to see if the config data is valid, if not, revert to
// readonly mode, by setting config to readonly_config. We
// will set it back before we leave this function.
if ( (config != readonly_config) && ((cyg_crc32((unsigned char *)config,
sizeof(struct _config)-sizeof(config->cksum)) != config->cksum) ||
(config->key1 != CONFIG_KEY1)|| (config->key2 != CONFIG_KEY2))) {
save_config = config;
config = readonly_config; // 那么使用readonly_config
if ((cyg_crc32((unsigned char *)config,
sizeof(struct _config)-sizeof(config->cksum)) != config->cksum) ||
(config->key1 != CONFIG_KEY1)|| (config->key2 != CONFIG_KEY2)) {
diag_printf("FLASH configuration checksum error or invalid key\n");
config = save_config;
return false;
}
else{
diag_printf("Getting config information in READONLY mode\n");
// 作最后查询,有就有,没有就没有了[luther.gliethttp]
return flash_get_config(key, val, type);
}
}
#endif
return false;
}
// 如下为plain数据区数据压缩存储格式
// Layout of config data
// Each data item is variable length, with the name, type and dependencies
// encoded into the object.
// offset contents
// 0 data type
// 1 length of name (N)
// 2 enable sense
// 3 length of enable key (M)
// 4 key name
// N+4 enable key
// M+N+4 data value
#define CONFIG_OBJECT_TYPE(dp) (dp)[0]
#define CONFIG_OBJECT_KEYLEN(dp) (dp)[1]
#define CONFIG_OBJECT_ENABLE_SENSE(dp) (dp)[2]
#define CONFIG_OBJECT_ENABLE_KEYLEN(dp) (dp)[3]
#define CONFIG_OBJECT_KEY(dp) ((dp)+4)
#define CONFIG_OBJECT_ENABLE_KEY(dp) ((dp)+4+CONFIG_OBJECT_KEYLEN(dp))
#define CONFIG_OBJECT_VALUE(dp) ((dp)+4+CONFIG_OBJECT_KEYLEN(dp)+CONFIG_OBJECT_ENABLE_KEYLEN(dp))
static int
config_length(int type)
{
switch (type) {
case CONFIG_BOOL:
return sizeof(bool);
case CONFIG_INT:
return sizeof(unsigned long);
#ifdef CYGPKG_REDBOOT_NETWORKING
case CONFIG_IP:
return sizeof(in_addr_t);
case CONFIG_ESA:
// Would like this to be sizeof(enet_addr_t), but that causes much
// pain since it fouls the alignment of data which follows.
return 8;
#endif
case CONFIG_STRING:
return MAX_STRING_LENGTH;
case CONFIG_SCRIPT:
return MAX_SCRIPT_LENGTH;
default:
return 0;
}
}
// 执行具体查询操作
static unsigned char *
flash_lookup_config(char *key)
{
unsigned char *dp;
int len;
if (!config_ok) return (unsigned char *)NULL;
dp = &config->config_data[0]; // plain数据区
while (dp < &config->config_data[sizeof(config->config_data)]) {
// 压缩存储格式见上面
// 0,1,2,3,4前4个字节为控制信息,比如
// 0字节对应数据类型
// 1字节对应key键值字符串长度(包含字符串结尾0)
// 2字节对应是否大小写敏感
// 3字节对应enable key字符串长度(包含字符串结尾0)
// 4字节开始存储key字符串数据N个字节,
// N+4紧随key字符串存储之后就是enable key字符串M个字节
//M+N+4之后就是data数据值了[luther.gliethttp]
len = 4 + CONFIG_OBJECT_KEYLEN(dp) + CONFIG_OBJECT_ENABLE_KEYLEN(dp) +
config_length(CONFIG_OBJECT_TYPE(dp)); // config_length返回该类型需要占用的存储空间.
// 首先比较键值key是否相同
// 为了加速比较,其实可以借鉴linux中的方法
// 首先比较字符传长度是否相等,如果相等
// 那么才继续进行如下耗cpu的字符串比较工作[luther.gliethttp]
if (strcmp(key, CONFIG_OBJECT_KEY(dp)) == 0) {
return dp; // ok, 该dp压缩结构体就是要找的key键值存储空间区[luther.gliethttp]
}
dp += len; // dp指向下一个压缩结构体开始处[luther.gliethttp]
}
// diag_printf("Can't find config data for '%s'\n", key);
return false;
}
阅读(1789) | 评论(0) | 转发(0) |