Mercurial > ecos
diff packages/redboot/current/src/flash.c @ 151:25e238959bae
Merge from eCos master repository on 2001-02-12-23:44:24-GMT
| author | jlarmour |
|---|---|
| date | Tue, 13 Feb 2001 01:23:16 +0000 |
| parents | d397fc472bcf |
| children | f935b880e96c |
line wrap: on
line diff
--- a/packages/redboot/current/src/flash.c +++ b/packages/redboot/current/src/flash.c @@ -131,20 +131,6 @@ static void *flash_start, *flash_end; static int block_size, blocks; static void *fis_work_block; -// Simple XOR style checksum -static unsigned long -_cksum(unsigned long *buf, int len) -{ - unsigned long cksum = 0; - - // Round 'len' up to multiple of longwords - len = (len + (sizeof(unsigned long)-1)) / sizeof(unsigned long); - while (len-- > 0) { - cksum ^= *buf++; - } - return cksum; -} - struct fis_image_desc * fis_lookup(char *name) { @@ -532,7 +518,7 @@ fis_create(int argc, char *argv[]) img->entry_point = entry_addr_set ? entry_addr : (unsigned long)entry_address; // Hope it's been set img->size = length; img->data_length = img_size; - img->file_cksum = _cksum((unsigned long *)flash_addr, img_size); + img->file_cksum = crc32((unsigned char *)flash_addr, img_size); #ifdef CYGSEM_REDBOOT_FLASH_LOCK_SPECIAL // Insure [quietly] that the directory is unlocked before trying to update flash_unlock((void *)fis_addr, block_size, (void **)&err_addr); @@ -762,7 +748,7 @@ fis_load(int argc, char *argv[]) } memcpy((void *)mem_addr, (void *)img->flash_base, img->size); entry_address = (unsigned long *)img->entry_point; - cksum = _cksum((unsigned long *)mem_addr, img->data_length); + cksum = crc32((unsigned char *)mem_addr, img->data_length); if (show_cksum) { printf("Checksum: 0x%08lx\n", cksum); } @@ -820,11 +806,13 @@ do_fis(int argc, char *argv[]) // Configuration data, saved in FLASH, used to set/update RedBoot // normal "configuration" data items. static struct _config { + unsigned long len; unsigned long key1; - unsigned char config_data[1024-(3*4)]; + unsigned char config_data[MAX_CONFIG_DATA-(4*4)]; unsigned long key2; unsigned long cksum; } config; +static bool config_ok; #define CONFIG_KEY1 0x0BADFACE #define CONFIG_KEY2 0xDEADDEAD @@ -844,12 +832,14 @@ static struct _config { RedBoot_config_option("Run script at boot", boot_script, ALWAYS_ENABLED, true, - CONFIG_BOOL + CONFIG_BOOL, + false ); RedBoot_config_option("Boot script", boot_script_data, "boot_script", true, - CONFIG_SCRIPT + CONFIG_SCRIPT, + "" ); // Some preprocessor magic for building the [constant] prompt string #define __cat(s1,c2,s3) s1 ## #c2 ## s3 @@ -859,7 +849,8 @@ RedBoot_config_option(_cat("Boot script "ms resolution)"), boot_script_timeout, "boot_script", true, - CONFIG_INT + CONFIG_INT, + 0 ); #undef __cat #undef _cat @@ -869,36 +860,65 @@ CYG_HAL_TABLE_END( __CONFIG_options_TAB_ extern struct config_option __CONFIG_options_TAB__[], __CONFIG_options_TAB_END__[]; +// +// 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 -get_config(struct config_option *opt, int offset, bool list_only) +get_config(unsigned char *dp, char *title, bool list_only) { char line[256], *sp, *lp; int ret; - bool hold_bool_val, enable; - unsigned long hold_int_val; + bool hold_bool_val, new_bool_val, enable; + unsigned long hold_int_val, new_int_val; #ifdef CYGPKG_REDBOOT_NETWORKING - in_addr_t hold_ip_val; + in_addr_t hold_ip_val, new_ip_val; enet_addr_t hold_esa_val; int esa_ptr; char *esp; #endif void *val_ptr; + int type; - if (opt->enable) { - flash_get_config(opt->enable, &enable, CONFIG_BOOL); - if ((opt->enable_sense && !enable) || - (!opt->enable_sense && enable)) { + if (CONFIG_OBJECT_ENABLE_KEYLEN(dp)) { + flash_get_config(CONFIG_OBJECT_ENABLE_KEY(dp), &enable, CONFIG_BOOL); + if (((bool)CONFIG_OBJECT_ENABLE_SENSE(dp) && !enable) || + (!(bool)CONFIG_OBJECT_ENABLE_SENSE(dp) && enable)) { return CONFIG_OK; // Disabled field } } - val_ptr = (void *)((unsigned char *)&config + offset); - printf("%s: ", opt->title); - switch (opt->type) { + val_ptr = (void *)CONFIG_OBJECT_VALUE(dp); + if (title != (char *)NULL) { + printf("%s: ", title); + } else { + printf("%s: ", CONFIG_OBJECT_KEY(dp)); + } + switch (type = CONFIG_OBJECT_TYPE(dp)) { case CONFIG_BOOL: - printf("%s ", *(bool *)val_ptr ? "true" : "false"); + memcpy(&hold_bool_val, val_ptr, sizeof(bool)); + printf("%s ", hold_bool_val ? "true" : "false"); break; case CONFIG_INT: - printf("%d ", *(int *)val_ptr); + memcpy(&hold_int_val, val_ptr, sizeof(unsigned long)); + printf("%ld ", hold_int_val); break; #ifdef CYGPKG_REDBOOT_NETWORKING case CONFIG_IP: @@ -931,31 +951,33 @@ get_config(struct config_option *opt, in printf("\n"); return CONFIG_OK; } - if (opt->type != CONFIG_SCRIPT) { + if (type != CONFIG_SCRIPT) { ret = gets(line, sizeof(line), 0); if (ret < 0) return CONFIG_ABORT; if (strlen(line) == 0) return CONFIG_OK; // Just a CR - leave value untouched if (line[0] == '.') return CONFIG_DONE; if (line[0] == '^') return CONFIG_BACK; } - switch (opt->type) { + switch (type) { case CONFIG_BOOL: - hold_bool_val = *(bool *)val_ptr; - if (!parse_bool(line, (bool *)val_ptr)) { + memcpy(&hold_bool_val, val_ptr, sizeof(bool)); + if (!parse_bool(line, &new_bool_val)) { return CONFIG_BAD; } - if (hold_bool_val != *(bool *)val_ptr) { + if (hold_bool_val != new_bool_val) { + memcpy(val_ptr, &new_bool_val, sizeof(bool)); return CONFIG_CHANGED; } else { return CONFIG_OK; } break; case CONFIG_INT: - hold_int_val = *(unsigned long *)val_ptr; - if (!parse_num(line, (unsigned long *)val_ptr, 0, 0)) { + memcpy(&hold_int_val, val_ptr, sizeof(unsigned long)); + if (!parse_num(line, &new_int_val, 0, 0)) { return CONFIG_BAD; } - if (hold_int_val != *(unsigned long *)val_ptr) { + if (hold_int_val != new_int_val) { + memcpy(val_ptr, &new_int_val, sizeof(unsigned long)); return CONFIG_CHANGED; } else { return CONFIG_OK; @@ -963,11 +985,12 @@ get_config(struct config_option *opt, in break; #ifdef CYGPKG_REDBOOT_NETWORKING case CONFIG_IP: - hold_ip_val.s_addr = ((in_addr_t *)val_ptr)->s_addr; - if (!inet_aton(line, (in_addr_t *)val_ptr)) { + memcpy(&hold_ip_val.s_addr, &((in_addr_t *)val_ptr)->s_addr, sizeof(in_addr_t)); + if (!inet_aton(line, &new_ip_val)) { return CONFIG_BAD; } - if (hold_ip_val.s_addr != ((in_addr_t *)val_ptr)->s_addr) { + if (hold_ip_val.s_addr != new_ip_val.s_addr) { + memcpy(val_ptr, &new_ip_val, sizeof(in_addr_t)); return CONFIG_CHANGED; } else { return CONFIG_OK; @@ -1014,28 +1037,6 @@ get_config(struct config_option *opt, in // Manage configuration information with the FLASH // -// Calculate a simple checksum. This is used to validate configuration -// data. Since it is used for sensitive information, it makes sense to -// be somewhat careful when accepting it. Also, the [strange] addition -// of shifted data helps make this work even if the data layout changes -// over time. - -static unsigned long -_fconfig_cksum(unsigned long *buf, int len) -{ - unsigned long cksum = 0; - int shift = 0; - - // Round 'len' up to multiple of longwords - len = (len + (sizeof(unsigned long)-1)) / sizeof(unsigned long); - while (len-- > 0) { - cksum ^= (*buf | (*buf << shift)); - buf++; - if (++shift == 16) shift = 0; - } - return cksum; -} - static int config_length(int type) { @@ -1062,16 +1063,15 @@ config_length(int type) void do_flash_config(int argc, char *argv[]) { - int stat, ret; - void *cfg_base, *err_addr; bool need_update = false; - struct config_option *optbeg = __CONFIG_options_TAB__; struct config_option *optend = __CONFIG_options_TAB_END__; struct config_option *opt = __CONFIG_options_TAB__; struct _config hold_config; - int offset = sizeof(unsigned long); struct option_info opts[1]; bool list_only; + unsigned char *dp; + int len, ret; + char *title; if (!do_flash_init()) return; memcpy(&hold_config, &config, sizeof(config)); @@ -1084,8 +1084,24 @@ do_flash_config(int argc, char *argv[]) return; } - while (opt != optend) { - ret = get_config(opt, offset, list_only); + dp = &config.config_data[0]; + while (dp < &config.config_data[sizeof(config.config_data)]) { + if (CONFIG_OBJECT_TYPE(dp) == CONFIG_EMPTY) { + break; + } + len = 4 + CONFIG_OBJECT_KEYLEN(dp) + CONFIG_OBJECT_ENABLE_KEYLEN(dp) + + config_length(CONFIG_OBJECT_TYPE(dp)); + // Provide a title for well known [i.e. builtin] objects + title = (char *)NULL; + opt = __CONFIG_options_TAB__; + while (opt != optend) { + if (strcmp(opt->key, CONFIG_OBJECT_KEY(dp)) == 0) { + title = opt->title; + break; + } + opt++; + } + ret = get_config(dp, title, list_only); switch (ret) { case CONFIG_DONE: goto done; @@ -1095,11 +1111,10 @@ do_flash_config(int argc, char *argv[]) case CONFIG_CHANGED: need_update = true; case CONFIG_OK: - offset += config_length(opt->type); - opt++; + dp += len; break; case CONFIG_BACK: - if (opt != optbeg) opt--; + dp = &config.config_data[0]; continue; case CONFIG_BAD: // Nothing - make him do it again @@ -1109,8 +1124,22 @@ do_flash_config(int argc, char *argv[]) done: if (!need_update) return; - config.key1 = CONFIG_KEY1; config.key2 = CONFIG_KEY2; - config.cksum = _fconfig_cksum((unsigned long *)&config, sizeof(config)-sizeof(config.cksum)); + flash_write_config(); +} + +// +// Write the in-memory copy of the configuration data to the flash device. +// +void +flash_write_config(void) +{ + int stat; + void *cfg_base, *err_addr; + + config.len = sizeof(config); + config.key1 = CONFIG_KEY1; + config.key2 = CONFIG_KEY2; + config.cksum = crc32((unsigned char *)&config, sizeof(config)-sizeof(config.cksum)); cfg_base = (void *)((unsigned long)flash_end - (2*block_size)); if (verify_action("Update RedBoot non-volatile configuration")) { #ifdef CYGSEM_REDBOOT_FLASH_LOCK_SPECIAL @@ -1133,26 +1162,32 @@ do_flash_config(int argc, char *argv[]) } } -void +// +// Retrieve a data object from the data base (in memory copy) +// +bool flash_get_config(char *key, void *val, int type) { - struct config_option *optend = __CONFIG_options_TAB_END__; - struct config_option *opt = __CONFIG_options_TAB__; - int offset = sizeof(unsigned long); // Offset past starting 'key' + unsigned char *dp; void *val_ptr; + int len; - if (!do_flash_init()) return; + if (!config_ok) return false; - while (opt != optend) { - val_ptr = (void *)((unsigned char *)&config + offset); - if (strcmp(opt->key, key) == 0) { - if (opt->type == type) { - switch (opt->type) { + dp = &config.config_data[0]; + while (dp < &config.config_data[sizeof(config.config_data)]) { + len = 4 + CONFIG_OBJECT_KEYLEN(dp) + CONFIG_OBJECT_ENABLE_KEYLEN(dp) + + config_length(CONFIG_OBJECT_TYPE(dp)); + val_ptr = (void *)CONFIG_OBJECT_VALUE(dp); + if (strcmp(key, CONFIG_OBJECT_KEY(dp)) == 0) { + if (CONFIG_OBJECT_TYPE(dp) == type) { + switch (type) { + // Note: the data may be unaligned in the configuration data case CONFIG_BOOL: - *(bool *)val = *(bool *)val_ptr; + memcpy(val, val_ptr, sizeof(bool)); break; case CONFIG_INT: - *(unsigned long *)val = *(unsigned long *)val_ptr; + memcpy(val, val_ptr, sizeof(unsigned long)); break; #ifdef CYGPKG_REDBOOT_NETWORKING case CONFIG_IP: @@ -1172,13 +1207,102 @@ flash_get_config(char *key, void *val, i } else { printf("Request for config value '%s' - wrong type\n", key); } + return true; + } + dp += len; + } + printf("Can't find config data for '%s'\n", key); + return false; +} + +// +// Add a new option to the database +// +bool +flash_add_config(struct config_option *opt) +{ + unsigned char *dp, *kp; + int len, elen, size; + + dp = &config.config_data[0]; + size = 0; + while (size < sizeof(config.config_data)) { + if (CONFIG_OBJECT_TYPE(dp) == CONFIG_EMPTY) { + kp = opt->key; + len = strlen(kp) + 1; + size += len + 2 + 2 + config_length(opt->type); + if (opt->enable) { + elen = strlen(opt->enable) + 1; + size += elen; + } else { + elen = 0; + } + if (size > sizeof(config.config_data)) { + break; + } + CONFIG_OBJECT_TYPE(dp) = opt->type; + CONFIG_OBJECT_KEYLEN(dp) = len; + CONFIG_OBJECT_ENABLE_SENSE(dp) = opt->enable_sense; + CONFIG_OBJECT_ENABLE_KEYLEN(dp) = elen; + dp = CONFIG_OBJECT_KEY(dp); + while (*kp) *dp++ += *kp++; + *dp++ = '\0'; + if (elen) { + kp = opt->enable; + while (*kp) *dp++ += *kp++; + *dp++ = '\0'; + } + switch (opt->type) { + // Note: the data may be unaligned in the configuration data + case CONFIG_BOOL: + memcpy(dp, (void *)&opt->dflt, sizeof(bool)); + break; + case CONFIG_INT: + memcpy(dp, (void *)&opt->dflt, sizeof(unsigned long)); + break; +#ifdef CYGPKG_REDBOOT_NETWORKING + case CONFIG_IP: + memcpy(dp, (void *)&opt->dflt, sizeof(in_addr_t)); + break; + case CONFIG_ESA: + memcpy(dp, (void *)&opt->dflt, sizeof(enet_addr_t)); + break; +#endif + case CONFIG_STRING: + case CONFIG_SCRIPT: + break; + } + dp += config_length(opt->type); + return true; + } else { + len = 4 + CONFIG_OBJECT_KEYLEN(dp) + CONFIG_OBJECT_ENABLE_KEYLEN(dp) + + config_length(CONFIG_OBJECT_TYPE(dp)); + dp += len; + size += len; + } + } + printf("No space to add '%s'\n", opt->key); + return false; +} + +// +// Reset/initialize configuration data - used only when starting from scratch +// +static void +config_init(void) +{ + // Well known option strings + struct config_option *optend = __CONFIG_options_TAB_END__; + struct config_option *opt = __CONFIG_options_TAB__; + + memset(&config, 0, sizeof(config)); + while (opt != optend) { + if (!flash_add_config(opt)) { return; } - offset += config_length(opt->type); opt++; } - - printf("Can't find config value '%s'\n", key); + config_ok = true; } // @@ -1197,10 +1321,10 @@ load_flash_config(void) if (!do_flash_init()) return; cfg_base = (void *)((unsigned long)flash_end - (2*block_size)); memcpy(&config, cfg_base, sizeof(config)); - if ((_fconfig_cksum((unsigned long *)&config, sizeof(config)-sizeof(config.cksum)) != config.cksum) || + if ((crc32((unsigned char *)&config, sizeof(config)-sizeof(config.cksum)) != config.cksum) || (config.key1 != CONFIG_KEY1)|| (config.key2 != CONFIG_KEY2)) { printf("FLASH configuration checksum error or invalid key\n"); - memset(&config, 0, sizeof(config)); + config_init(); return; } flash_get_config("boot_script", &use_boot_script, CONFIG_BOOL);
