1 //==========================================================================
5 // RedBoot - persistent data storage support (FLASH or EEPROM)
7 //==========================================================================
8 //####ECOSGPLCOPYRIGHTBEGIN####
9 // -------------------------------------------
10 // This file is part of eCos, the Embedded Configurable Operating System.
11 // Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004 Red Hat, Inc.
12 // Copyright (C) 2003 Gary Thomas
14 // eCos is free software; you can redistribute it and/or modify it under
15 // the terms of the GNU General Public License as published by the Free
16 // Software Foundation; either version 2 or (at your option) any later version.
18 // eCos is distributed in the hope that it will be useful, but WITHOUT ANY
19 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
20 // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
23 // You should have received a copy of the GNU General Public License along
24 // with eCos; if not, write to the Free Software Foundation, Inc.,
25 // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
27 // As a special exception, if other files instantiate templates or use macros
28 // or inline functions from this file, or you compile this file and link it
29 // with other works to produce a work based on this file, this file does not
30 // by itself cause the resulting work to be covered by the GNU General Public
31 // License. However the source code for this file must still be made available
32 // in accordance with section (3) of the GNU General Public License.
34 // This exception does not invalidate any other reasons why a work based on
35 // this file might be covered by the GNU General Public License.
37 // Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
38 // at http://sources.redhat.com/ecos/ecos-license/
39 // -------------------------------------------
40 //####ECOSGPLCOPYRIGHTEND####
41 //==========================================================================
42 //#####DESCRIPTIONBEGIN####
45 // Contributors: gthomas, tkoeller
50 // This code is part of RedBoot (tm).
52 //####DESCRIPTIONEND####
54 //==========================================================================
57 #include <cyg/io/flash.h>
58 #ifdef CYGOPT_REDBOOT_FIS
62 #ifdef CYGSEM_REDBOOT_FLASH_COMBINED_FIS_AND_CONFIG
63 // Note horrid intertwining of functions, to save precious FLASH
64 externC void fis_read_directory(void);
65 externC void fis_update_directory(void);
68 #ifdef CYGHWR_REDBOOT_FLASH_CONFIG_MEDIA_EEPROM
69 externC void write_eeprom(void *buf, int len);
70 externC void read_eeprom(void *buf, int len);
73 #ifdef CYGSEM_REDBOOT_PLF_ESA_VALIDATE
74 externC bool cyg_plf_redboot_esa_validate(unsigned char *val);
77 #ifdef CYGHWR_REDBOOT_FLASH_CONFIG_MEDIA_FLASH
78 externC int do_flash_init(void);
79 externC int flash_read(void *flash_base, void *ram_base, int len, void **err_address);
82 // Round a quantity up
83 #define _rup(n,s) ((((n)+(s-1))/s)*s)
85 #include <flash_config.h>
87 // Configuration data, saved in FLASH, used to set/update RedBoot
88 // normal "configuration" data items.
89 struct _config *config, *backup_config;
91 // Local data used by these routines
92 #ifdef CYGHWR_REDBOOT_FLASH_CONFIG_MEDIA_FLASH
93 extern void *flash_start, *flash_end;
94 extern int flash_block_size, flash_num_blocks;
95 extern int __flash_init;
96 #ifdef CYGOPT_REDBOOT_FIS
97 extern void *fis_work_block;
98 extern void *fis_addr;
99 extern int fisdir_size; // Size of FIS directory.
101 #ifdef CYGSEM_REDBOOT_FLASH_CONFIG_READONLY_FALLBACK
102 static struct _config *readonly_config;
104 void *cfg_base; // Location in Flash of config data
105 int cfg_size; // Length of config data - rounded to Flash block size
106 #endif // FLASH MEDIA
108 // Prototypes for local functions
109 static unsigned char *flash_lookup_config(char *key);
111 static bool config_ok;
113 #define CONFIG_KEY1 0x0BADFACE
114 #define CONFIG_KEY2 0xDEADDEAD
116 #define CONFIG_DONE 0
117 #define CONFIG_ABORT -1
118 #define CONFIG_CHANGED 1
120 #define CONFIG_BACK 3
123 // Note: the following options are related. If 'boot_script' is false, then
124 // the other values are used in the configuration. Because of the way
125 // that configuration tables are generated, they should have names which
126 // are related. The configuration options will show up lexicographically
127 // ordered, thus the peculiar naming.
128 RedBoot_config_option("Run script at boot",
130 ALWAYS_ENABLED, true,
134 RedBoot_config_option("Boot script",
140 // Some preprocessor magic for building the [constant] prompt string
141 #define __cat(s1,c2,s3) s1 #c2 s3
142 #define _cat(s1,c2,s3) __cat(s1,c2,s3)
143 RedBoot_config_option(_cat("Boot script timeout (",
144 CYGNUM_REDBOOT_BOOT_SCRIPT_TIMEOUT_RESOLUTION,
154 #ifdef CYGSEM_REDBOOT_VARIABLE_BAUD_RATE
155 RedBoot_config_option("Console baud rate",
157 ALWAYS_ENABLED, true,
159 CYGNUM_HAL_VIRTUAL_VECTOR_CONSOLE_CHANNEL_BAUD
163 CYG_HAL_TABLE_BEGIN( __CONFIG_options_TAB__, RedBoot_config_options);
164 CYG_HAL_TABLE_END( __CONFIG_options_TAB_END__, RedBoot_config_options);
166 extern struct config_option __CONFIG_options_TAB__[], __CONFIG_options_TAB_END__[];
169 // Layout of config data
170 // Each data item is variable length, with the name, type and dependencies
171 // encoded into the object.
174 // 1 length of name (N)
176 // 3 length of enable key (M)
182 #define CONFIG_OBJECT_TYPE(dp) (dp)[0]
183 #define CONFIG_OBJECT_KEYLEN(dp) (dp)[1]
184 #define CONFIG_OBJECT_ENABLE_SENSE(dp) (dp)[2]
185 #define CONFIG_OBJECT_ENABLE_KEYLEN(dp) (dp)[3]
186 #define CONFIG_OBJECT_KEY(dp) ((dp)+4)
187 #define CONFIG_OBJECT_ENABLE_KEY(dp) ((dp)+4+CONFIG_OBJECT_KEYLEN(dp))
188 #define CONFIG_OBJECT_VALUE(dp) ((dp)+4+CONFIG_OBJECT_KEYLEN(dp)+CONFIG_OBJECT_ENABLE_KEYLEN(dp))
190 #define LIST_OPT_LIST_ONLY (1)
191 #define LIST_OPT_NICKNAMES (2)
192 #define LIST_OPT_FULLNAMES (4)
193 #define LIST_OPT_DUMBTERM (8)
195 static void config_init(void);
196 static int config_length(int type);
198 // Change endianness of config data
200 conf_endian_fixup(void *ptr)
202 #ifdef REDBOOT_FLASH_REVERSE_BYTEORDER
203 struct _config *p = (struct _config *)ptr;
204 unsigned char *dp = p->config_data;
210 p->len = CYG_SWAP32(p->len);
211 p->key1 = CYG_SWAP32(p->key1);
212 p->key2 = CYG_SWAP32(p->key2);
213 p->cksum = CYG_SWAP32(p->cksum);
215 while (dp < &p->config_data[sizeof(config->config_data)]) {
216 len = 4 + CONFIG_OBJECT_KEYLEN(dp) + CONFIG_OBJECT_ENABLE_KEYLEN(dp) +
217 config_length(CONFIG_OBJECT_TYPE(dp));
218 val_ptr = CONFIG_OBJECT_VALUE(dp);
220 switch (CONFIG_OBJECT_TYPE(dp)) {
221 // Note: the data may be unaligned in the configuration data
223 if (sizeof(bool) == 2) {
224 memcpy(&u16, val_ptr, 2);
225 u16 = CYG_SWAP16(u16);
226 memcpy(val_ptr, &u16, 2);
227 } else if (sizeof(bool) == 4) {
228 memcpy(&u32, val_ptr, 4);
229 u32 = CYG_SWAP32(u32);
230 memcpy(val_ptr, &u32, 4);
234 if (sizeof(unsigned long) == 2) {
235 memcpy(&u16, val_ptr, 2);
236 u16 = CYG_SWAP16(u16);
237 memcpy(val_ptr, &u16, 2);
238 } else if (sizeof(unsigned long) == 4) {
239 memcpy(&u32, val_ptr, 4);
240 u32 = CYG_SWAP32(u32);
241 memcpy(val_ptr, &u32, 4);
252 get_config(unsigned char *dp, char *title, int list_opt, char *newvalue )
254 char line[256], hold_line[256], *sp, *lp;
256 bool hold_bool_val, new_bool_val, enable;
257 unsigned long hold_int_val, new_int_val;
258 #ifdef CYGPKG_REDBOOT_NETWORKING
259 in_addr_t hold_ip_val, new_ip_val;
260 enet_addr_t hold_esa_val;
265 int type, script_len;
267 if (CONFIG_OBJECT_ENABLE_KEYLEN(dp)) {
268 flash_get_config(CONFIG_OBJECT_ENABLE_KEY(dp), &enable, CONFIG_BOOL);
269 if (((bool)CONFIG_OBJECT_ENABLE_SENSE(dp) && !enable) ||
270 (!(bool)CONFIG_OBJECT_ENABLE_SENSE(dp) && enable)) {
271 return CONFIG_OK; // Disabled field
276 val_ptr = CONFIG_OBJECT_VALUE(dp);
277 if (LIST_OPT_NICKNAMES & list_opt)
278 diag_printf("%s: ", CONFIG_OBJECT_KEY(dp));
279 if (LIST_OPT_FULLNAMES & list_opt) {
281 diag_printf("%s: ", title);
283 diag_printf("%s: ", CONFIG_OBJECT_KEY(dp));
286 switch (type = CONFIG_OBJECT_TYPE(dp)) {
288 memcpy(&hold_bool_val, val_ptr, sizeof(bool));
289 lp += diag_sprintf(lp, "%s", hold_bool_val ? "true" : "false");
292 memcpy(&hold_int_val, val_ptr, sizeof(unsigned long));
293 lp += diag_sprintf(lp, "%ld", hold_int_val);
295 #ifdef CYGPKG_REDBOOT_NETWORKING
297 lp += diag_sprintf(lp, "%s", inet_ntoa((in_addr_t *)val_ptr));
298 if (0 == strcmp("0.0.0.0", line) && !(LIST_OPT_LIST_ONLY & list_opt)) {
299 // then we have a deeply unhelpful starting text - kill it off
300 // (unless we are just listing all values)
301 lp = line; *lp = '\0';
305 for (esa_ptr = 0; esa_ptr < sizeof(enet_addr_t); esa_ptr++) {
306 lp += diag_sprintf(lp, "0x%02X", ((unsigned char *)val_ptr)[esa_ptr]);
307 if (esa_ptr < (sizeof(enet_addr_t)-1)) lp += diag_sprintf(lp, ":");
310 #if defined(CYGHWR_NET_DRIVERS) && (CYGHWR_NET_DRIVERS > 1)
312 lp += diag_sprintf(lp, "%s", (unsigned char *)val_ptr);
317 lp += diag_sprintf(lp, "%s", (unsigned char *)val_ptr);
321 sp = lp = (unsigned char *)val_ptr;
323 while (*lp != '\n') lp++;
325 diag_printf(".. %s\n", sp);
331 if (LIST_OPT_LIST_ONLY & list_opt) {
332 diag_printf("%s\n", line);
335 if (type != CONFIG_SCRIPT) {
336 if (NULL != newvalue) {
337 ret = strlen(newvalue);
338 if (ret > sizeof(line))
340 strcpy(hold_line, line); // Hold the old value for comparison
341 strcpy(line, newvalue);
342 diag_printf("Setting to %s\n", newvalue);
344 // read from terminal
345 strcpy(hold_line, line);
346 if (LIST_OPT_DUMBTERM & list_opt) {
347 diag_printf( (CONFIG_STRING == type ?
352 ret = _rb_gets_preloaded(line, sizeof(line), 0);
354 if (ret < 0) return CONFIG_ABORT;
355 // empty input - leave value untouched (else DNS goes away for a
356 // minute to try to look it up) but we must accept empty value for strings.
357 if (0 == line[0] && CONFIG_STRING != type) return CONFIG_OK;
358 if (strcmp(line, hold_line) == 0) return CONFIG_OK; // Just a CR - leave value untouched
359 lp = &line[strlen(line)-1];
360 if (*lp == '.') return CONFIG_DONE;
361 if (*lp == '^') return CONFIG_BACK;
365 memcpy(&hold_bool_val, val_ptr, sizeof(bool));
366 if (!parse_bool(line, &new_bool_val)) {
369 if (hold_bool_val != new_bool_val) {
370 memcpy(val_ptr, &new_bool_val, sizeof(bool));
371 return CONFIG_CHANGED;
377 memcpy(&hold_int_val, val_ptr, sizeof(unsigned long));
378 if (!parse_num(line, &new_int_val, 0, 0)) {
381 if (hold_int_val != new_int_val) {
382 memcpy(val_ptr, &new_int_val, sizeof(unsigned long));
383 return CONFIG_CHANGED;
388 #ifdef CYGPKG_REDBOOT_NETWORKING
390 memcpy(&hold_ip_val.s_addr, &((in_addr_t *)val_ptr)->s_addr, sizeof(in_addr_t));
391 if (!_gethostbyname(line, &new_ip_val)) {
394 if (hold_ip_val.s_addr != new_ip_val.s_addr) {
395 memcpy(val_ptr, &new_ip_val, sizeof(in_addr_t));
396 return CONFIG_CHANGED;
402 memcpy(&hold_esa_val, val_ptr, sizeof(enet_addr_t));
404 for (esa_ptr = 0; esa_ptr < sizeof(enet_addr_t); esa_ptr++) {
405 unsigned long esa_byte;
406 if (!parse_num(esp, &esa_byte, &esp, ":")) {
407 memcpy(val_ptr, &hold_esa_val, sizeof(enet_addr_t));
410 ((unsigned char *)val_ptr)[esa_ptr] = esa_byte;
412 #ifdef CYGSEM_REDBOOT_PLF_ESA_VALIDATE
413 if (!cyg_plf_redboot_esa_validate(val_ptr)) {
414 memcpy(val_ptr, &hold_esa_val, sizeof(enet_addr_t));
418 return CONFIG_CHANGED;
420 #if defined(CYGHWR_NET_DRIVERS) && (CYGHWR_NET_DRIVERS > 1)
422 if (strlen(line) >= MAX_STRING_LENGTH || net_devindex(line) < 0) {
425 diag_printf("Sorry, Port name must be one of:\n");
426 for (index = 0; (name = net_devname(index)) != NULL; index++)
427 diag_printf(" %s\n", name);
430 strcpy((unsigned char *)val_ptr, line);
435 // Assume it always changes
436 sp = (unsigned char *)val_ptr;
438 diag_printf("Enter script, terminate with empty line\n");
442 ret = _rb_gets(line, sizeof(line), 0);
443 if (ret < 0) return CONFIG_ABORT;
444 if (strlen(line) == 0) break;
445 script_len += strlen(line) + 1;
446 if (script_len > config_length(CONFIG_SCRIPT)) {
447 diag_printf("script longer than %d not allowed!\n",
448 config_length(CONFIG_SCRIPT));
459 if (strlen(line) >= MAX_STRING_LENGTH) {
460 diag_printf("Sorry, value is too long\n");
463 strcpy((unsigned char *)val_ptr, line);
466 return CONFIG_CHANGED;
470 // Manage configuration information with the FLASH
474 config_length(int type)
480 return sizeof(unsigned long);
481 #ifdef CYGPKG_REDBOOT_NETWORKING
483 return sizeof(in_addr_t);
485 // Would like this to be sizeof(enet_addr_t), but that causes much
486 // pain since it fouls the alignment of data which follows.
488 #if defined(CYGHWR_NET_DRIVERS) && (CYGHWR_NET_DRIVERS > 1)
490 return MAX_STRING_LENGTH;
494 return MAX_STRING_LENGTH;
496 return MAX_SCRIPT_LENGTH;
502 static cmd_fun do_flash_config;
503 RedBoot_cmd("fconfig",
504 "Manage configuration kept in FLASH memory",
505 "[-i] [-l] [-n] [-f] [-d] | [-d] nickname [value]",
510 do_flash_config(int argc, char *argv[])
512 bool need_update = false;
513 struct config_option *optend = __CONFIG_options_TAB_END__;
514 struct config_option *opt = __CONFIG_options_TAB__;
515 struct option_info opts[5];
524 char *onlyone = NULL;
525 char *onevalue = NULL;
526 bool doneone = false;
529 #ifdef CYGHWR_REDBOOT_FLASH_CONFIG_MEDIA_FLASH
531 diag_printf("Sorry, no FLASH memory is available\n");
535 memcpy(backup_config, config, sizeof(struct _config));
538 init_opts(&opts[0], 'l', false, OPTION_ARG_TYPE_FLG,
539 &list_only, NULL, "list configuration only");
540 init_opts(&opts[1], 'n', false, OPTION_ARG_TYPE_FLG,
541 &nicknames, NULL, "show nicknames");
542 init_opts(&opts[2], 'f', false, OPTION_ARG_TYPE_FLG,
543 &fullnames, NULL, "show full names");
544 init_opts(&opts[3], 'i', false, OPTION_ARG_TYPE_FLG,
545 &init, NULL, "initialize configuration database");
546 init_opts(&opts[4], 'd', false, OPTION_ARG_TYPE_FLG,
547 &dumbterminal, NULL, "dumb terminal: no clever edits");
549 // First look to see if we are setting or getting a single option
550 // by just quoting its nickname
551 if ( (2 == argc && '-' != argv[1][0]) ||
552 (3 == argc && '-' != argv[1][0] && '-' != argv[2][0])) {
553 // then the command was "fconfig foo [value]"
555 onevalue = (3 == argc) ? argv[2] : NULL;
556 list_opt = LIST_OPT_NICKNAMES;
558 // Next see if we are setting or getting a single option with a dumb
559 // terminal invoked, ie. no line editing.
560 else if (3 == argc &&
561 '-' == argv[1][0] && 'd' == argv[1][1] && 0 == argv[1][2] &&
563 // then the command was "fconfig -d foo"
566 list_opt = LIST_OPT_NICKNAMES | LIST_OPT_DUMBTERM;
569 if (!scan_opts(argc, argv, 1, opts, 5, 0, 0, ""))
571 list_opt |= list_only ? LIST_OPT_LIST_ONLY : 0;
572 list_opt |= nicknames ? LIST_OPT_NICKNAMES : LIST_OPT_FULLNAMES;
573 list_opt |= fullnames ? LIST_OPT_FULLNAMES : 0;
574 list_opt |= dumbterminal ? LIST_OPT_DUMBTERM : 0;
577 if (init && verify_action("Initialize non-volatile configuration")) {
582 dp = config->config_data;
583 while (dp < &config->config_data[sizeof(config->config_data)]) {
584 if (CONFIG_OBJECT_TYPE(dp) == CONFIG_EMPTY) {
587 len = 4 + CONFIG_OBJECT_KEYLEN(dp) + CONFIG_OBJECT_ENABLE_KEYLEN(dp) +
588 config_length(CONFIG_OBJECT_TYPE(dp));
589 // Provide a title for well known [i.e. builtin] objects
591 opt = __CONFIG_options_TAB__;
592 while (opt != optend) {
593 if (strcmp(opt->key, CONFIG_OBJECT_KEY(dp)) == 0) {
599 if (onlyone && 0 != strcmp(CONFIG_OBJECT_KEY(dp), onlyone))
600 ret = CONFIG_OK; // skip this entry
603 ret = get_config(dp, title, list_opt, onevalue); // do this opt
609 memcpy(config, backup_config, sizeof(struct _config));
617 dp = config->config_data;
620 // Nothing - make him do it again
621 diag_printf ("** invalid entry\n");
622 onevalue = NULL; // request a good value be typed in - or abort/whatever
627 if (NULL != onlyone && !doneone) {
628 #ifdef CYGSEM_REDBOOT_ALLOW_DYNAMIC_FLASH_CONFIG_DATA
629 if (verify_action("** entry '%s' not found - add", onlyone)) {
630 struct config_option opt;
631 diag_printf("Trying to add value\n");
634 diag_printf("** entry '%s' not found\n", onlyone);
639 flash_write_config(true);
643 #ifdef CYGSEM_REDBOOT_FLASH_ALIASES
644 static cmd_fun do_alias;
646 "Manage aliases kept in FLASH memory",
652 make_alias(char *alias, char *name)
654 diag_sprintf(alias, "alias/%s", name);
658 do_alias(int argc, char *argv[])
662 struct config_option opt;
666 make_alias(name, argv[1]);
667 if (flash_get_config(name, &val, CONFIG_STRING)) {
668 diag_printf("'%s' = '%s'\n", argv[1], val);
670 diag_printf("'%s' not found\n", argv[1]);
674 if (strlen(argv[2]) >= MAX_STRING_LENGTH) {
675 diag_printf("Sorry, value is too long\n");
678 make_alias(name, argv[1]);
679 opt.type = CONFIG_STRING;
681 opt.enable_sense = 1;
683 opt.dflt = (CYG_ADDRESS)argv[2];
684 flash_add_config(&opt, true);
687 diag_printf("usage: alias name [value]\n");
691 // Lookup an alias. First try plain string aliases. If that fails try
692 // other types so allowing access to all configured values. This allows
693 // for alias (macro) expansion of normal 'fconfig' data, such as the
696 flash_lookup_alias(char *alias, char *alias_buf)
705 #ifdef CYGPKG_REDBOOT_NETWORKING
709 make_alias(name, alias);
710 if (flash_get_config(name, &val, CONFIG_STRING)) {
713 dp = flash_lookup_config(alias);
715 val_ptr = CONFIG_OBJECT_VALUE(dp);
716 switch (type = CONFIG_OBJECT_TYPE(dp)) {
718 memcpy(&hold_bool_val, val_ptr, sizeof(bool));
719 diag_sprintf(alias_buf, "%s", hold_bool_val ? "true" : "false");
722 memcpy(&hold_long_val, val_ptr, sizeof(unsigned long));
723 diag_sprintf(alias_buf,"%ld", hold_long_val);
725 #ifdef CYGPKG_REDBOOT_NETWORKING
727 diag_sprintf(alias_buf,"%s", inet_ntoa((in_addr_t *)val_ptr));
730 for (esa_ptr = 0; esa_ptr < sizeof(enet_addr_t); esa_ptr++) {
731 diag_sprintf(alias_buf+(3*esa_ptr), "0x%02X", ((unsigned char *)val_ptr)[esa_ptr]);
732 if (esa_ptr < (sizeof(enet_addr_t)-1)) diag_printf(":");
748 #endif // CYGSEM_REDBOOT_FLASH_ALIASES
751 flash_crc(struct _config *conf)
754 #ifdef REDBOOT_FLASH_REVERSE_BYTEORDER
757 if (conf->key1 == CONFIG_KEY1 && conf->key2 == CONFIG_KEY2) {
759 conf_endian_fixup(conf);
763 crc = cyg_crc32((unsigned char *)conf, sizeof(*conf)-sizeof(conf->cksum));
765 #ifdef REDBOOT_FLASH_REVERSE_BYTEORDER
767 conf_endian_fixup(conf);
773 // Write the in-memory copy of the configuration data to the flash device.
776 flash_write_config(bool prompt)
778 #if defined(CYGHWR_REDBOOT_FLASH_CONFIG_MEDIA_FLASH)
779 #if !defined(CYGSEM_REDBOOT_FLASH_COMBINED_FIS_AND_CONFIG)
785 config->len = sizeof(struct _config);
786 config->key1 = CONFIG_KEY1;
787 config->key2 = CONFIG_KEY2;
788 config->cksum = flash_crc(config);
789 if (!prompt || verify_action("Update RedBoot non-volatile configuration")) {
790 #ifdef CYGHWR_REDBOOT_FLASH_CONFIG_MEDIA_FLASH
791 #ifdef CYGSEM_REDBOOT_FLASH_COMBINED_FIS_AND_CONFIG
792 fis_read_directory();
793 fis_update_directory();
795 #ifdef CYGSEM_REDBOOT_FLASH_LOCK_SPECIAL
796 // Ensure [quietly] that the config page is unlocked before trying to update
797 flash_unlock(cfg_base, cfg_size, &err_addr);
799 if ((stat = flash_erase(cfg_base, cfg_size, &err_addr)) != 0) {
800 diag_printf(" initialization failed at %p: %s\n", err_addr, flash_errmsg(stat));
802 conf_endian_fixup(config);
803 if ((stat = FLASH_PROGRAM(cfg_base, config, sizeof(struct _config), &err_addr)) != 0) {
804 diag_printf("Error writing config data at %p: %s\n",
805 err_addr, flash_errmsg(stat));
807 conf_endian_fixup(config);
809 #ifdef CYGSEM_REDBOOT_FLASH_LOCK_SPECIAL
810 // Ensure [quietly] that the config data is locked after the update
811 flash_lock(cfg_base, cfg_size, &err_addr);
813 #endif // CYGSEM_REDBOOT_FLASH_COMBINED_FIS_AND_CONFIG
814 #else // CYGHWR_REDBOOT_FLASH_CONFIG_MEDIA_FLASH
815 write_eeprom(config, sizeof(struct _config)); // into 'config'
821 // Find the configuration entry for a particular key
823 static unsigned char *
824 flash_lookup_config(char *key)
829 if (!config_ok) return NULL;
831 dp = config->config_data;
832 while (dp < &config->config_data[sizeof(config->config_data)]) {
833 len = 4 + CONFIG_OBJECT_KEYLEN(dp) + CONFIG_OBJECT_ENABLE_KEYLEN(dp) +
834 config_length(CONFIG_OBJECT_TYPE(dp));
835 if (strcmp(key, CONFIG_OBJECT_KEY(dp)) == 0) {
840 // diag_printf("Can't find config data for '%s'\n", key);
845 // Enumerate the keys from the configuration
848 flash_next_key(char *key, int keylen, int *type, int *offset)
853 if (!config_ok) return false;
854 if ((*offset < 0) || (*offset >= MAX_CONFIG_DATA)) return false;
856 dp = &config->config_data[*offset];
857 if ((*type = CONFIG_OBJECT_TYPE(dp)) == CONFIG_EMPTY) return false;
858 if ((len = CONFIG_OBJECT_KEYLEN(dp)) > keylen) return false;
859 memcpy(key, CONFIG_OBJECT_KEY(dp), len);
860 *offset += 4 + CONFIG_OBJECT_KEYLEN(dp) + CONFIG_OBJECT_ENABLE_KEYLEN(dp) +
861 config_length(CONFIG_OBJECT_TYPE(dp));
866 // Retrieve a data object from the data base (in memory copy)
869 flash_get_config(char *key, void *val, int type)
873 #ifdef CYGSEM_REDBOOT_FLASH_CONFIG_READONLY_FALLBACK
874 struct _config *save_config = 0;
878 if (!config_ok) return false;
880 if ((dp = flash_lookup_config(key)) != NULL) {
881 if (CONFIG_OBJECT_TYPE(dp) == type) {
882 val_ptr = CONFIG_OBJECT_VALUE(dp);
884 // Note: the data may be unaligned in the configuration data
886 memcpy(val, val_ptr, sizeof(bool));
889 memcpy(val, val_ptr, sizeof(unsigned long));
891 #ifdef CYGPKG_REDBOOT_NETWORKING
893 memcpy(val, val_ptr, sizeof(in_addr_t));
896 memcpy(val, val_ptr, sizeof(enet_addr_t));
899 #if defined(CYGHWR_NET_DRIVERS) && (CYGHWR_NET_DRIVERS > 1)
904 // Just return a pointer to the script/line
905 *(unsigned char **)val = (unsigned char *)val_ptr;
909 diag_printf("Request for config value '%s' - wrong type\n", key);
913 #ifdef CYGSEM_REDBOOT_FLASH_CONFIG_READONLY_FALLBACK
914 // Did not find key. Is configuration data valid?
915 // Check to see if the config data is valid, if not, revert to
916 // readonly mode, by setting config to readonly_config. We
917 // will set it back before we leave this function.
918 if ( (config != readonly_config) && ((flash_crc(config) != config->cksum) ||
919 (config->key1 != CONFIG_KEY1)|| (config->key2 != CONFIG_KEY2))) {
920 save_config = config;
921 config = readonly_config;
922 if ((flash_crc(config) != config->cksum) ||
923 (config->key1 != CONFIG_KEY1)|| (config->key2 != CONFIG_KEY2)) {
924 diag_printf("FLASH configuration checksum error or invalid key\n");
925 config = save_config;
929 diag_printf("Getting config information in READONLY mode\n");
930 res = flash_get_config(key, val, type);
931 config = save_config;
940 // Update a data object in the data base (in memory copy & backing store)
943 flash_set_config(char *key, void *val, int type)
948 if (!config_ok) return false;
950 if ((dp = flash_lookup_config(key)) != NULL) {
951 if (CONFIG_OBJECT_TYPE(dp) == type) {
952 val_ptr = CONFIG_OBJECT_VALUE(dp);
954 // Note: the data may be unaligned in the configuration data
956 memcpy(val_ptr, val, sizeof(bool));
959 memcpy(val_ptr, val, sizeof(unsigned long));
961 #ifdef CYGPKG_REDBOOT_NETWORKING
963 memcpy(val_ptr, val, sizeof(in_addr_t));
966 memcpy(val_ptr, val, sizeof(enet_addr_t));
969 #if defined(CYGHWR_NET_DRIVERS) && (CYGHWR_NET_DRIVERS > 1)
974 memcpy(val_ptr, val, config_length(CONFIG_STRING));
978 diag_printf("Can't set config value '%s' - wrong type\n", key);
981 flash_write_config(false);
988 // Copy data into the config area
991 flash_config_insert_value(unsigned char *dp, struct config_option *opt)
994 // Note: the data may be unaligned in the configuration data
996 memcpy(dp, &opt->dflt, sizeof(bool));
999 memcpy(dp, &opt->dflt, sizeof(unsigned long));
1001 #ifdef CYGPKG_REDBOOT_NETWORKING
1003 memcpy(dp, &opt->dflt, sizeof(in_addr_t));
1006 memcpy(dp, (void *)opt->dflt, sizeof(enet_addr_t));
1008 #if defined(CYGHWR_NET_DRIVERS) && (CYGHWR_NET_DRIVERS > 1)
1009 case CONFIG_NETPORT:
1010 // validate dflt and if not acceptable use first port
1014 for (index = 0; (name = net_devname(index)) != NULL; index++)
1015 if (!strcmp((char *)opt->dflt, name))
1018 name = net_devname(0);
1019 memcpy(dp, name, strlen(name) + 1);
1025 memcpy(dp, (void *)opt->dflt, config_length(CONFIG_STRING));
1033 // Add a new option to the database
1036 flash_add_config(struct config_option *opt, bool update)
1038 unsigned char *dp, *kp;
1039 int len, elen, size;
1041 // If data item is already present, just update it
1042 // Note: only the data value can be thusly changed
1043 if ((dp = flash_lookup_config(opt->key)) != NULL) {
1044 flash_config_insert_value(CONFIG_OBJECT_VALUE(dp), opt);
1046 flash_write_config(true);
1050 // Add the data item
1051 dp = config->config_data;
1053 while (size < sizeof(config->config_data)) {
1054 if (CONFIG_OBJECT_TYPE(dp) == CONFIG_EMPTY) {
1056 len = strlen(kp) + 1;
1057 size += len + 2 + 2 + config_length(opt->type);
1059 elen = strlen(opt->enable) + 1;
1064 if (size > sizeof(config->config_data)) {
1067 CONFIG_OBJECT_TYPE(dp) = opt->type;
1068 CONFIG_OBJECT_KEYLEN(dp) = len;
1069 CONFIG_OBJECT_ENABLE_SENSE(dp) = opt->enable_sense;
1070 CONFIG_OBJECT_ENABLE_KEYLEN(dp) = elen;
1071 dp = CONFIG_OBJECT_KEY(dp);
1072 while (*kp) *dp++ += *kp++;
1076 while (*kp) *dp++ += *kp++;
1079 flash_config_insert_value(dp, opt);
1081 flash_write_config(true);
1085 len = 4 + CONFIG_OBJECT_KEYLEN(dp) + CONFIG_OBJECT_ENABLE_KEYLEN(dp) +
1086 config_length(CONFIG_OBJECT_TYPE(dp));
1091 diag_printf("No space to add '%s'\n", opt->key);
1096 // Reset/initialize configuration data - used only when starting from scratch
1101 // Well known option strings
1102 struct config_option *optend = __CONFIG_options_TAB_END__;
1103 struct config_option *opt = __CONFIG_options_TAB__;
1105 memset(config, 0, sizeof(struct _config));
1106 while (opt != optend) {
1107 if (!flash_add_config(opt, false)) {
1116 // Attempt to get configuration information from the FLASH.
1117 // If available (i.e. good checksum, etc), initialize "known"
1118 // values for later use.
1121 load_flash_config(void)
1123 bool use_boot_script;
1124 unsigned char *cfg_temp = workspace_end;
1125 #ifdef CYGHWR_REDBOOT_FLASH_CONFIG_MEDIA_FLASH
1131 cfg_temp -= sizeof(struct _config); // Space for primary config data
1132 config = (struct _config *)cfg_temp;
1133 cfg_temp -= sizeof(struct _config); // Space for backup config data
1134 backup_config = (struct _config *)cfg_temp;
1135 #ifdef CYGSEM_REDBOOT_FLASH_CONFIG_READONLY_FALLBACK
1136 cfg_temp -= sizeof(struct _config); // Space for readonly copy of config data
1137 readonly_config = (struct _config *)cfg_temp;
1139 workspace_end = cfg_temp;
1140 #ifdef CYGHWR_REDBOOT_FLASH_CONFIG_MEDIA_FLASH
1141 if (do_flash_init()<0) return;
1142 #ifdef CYGSEM_REDBOOT_FLASH_COMBINED_FIS_AND_CONFIG
1143 cfg_size = _rup(sizeof(struct _config), sizeof(struct fis_image_desc));
1144 if ((fisdir_size-cfg_size) < (CYGNUM_REDBOOT_FIS_DIRECTORY_ENTRY_COUNT *
1145 CYGNUM_REDBOOT_FIS_DIRECTORY_ENTRY_SIZE)) {
1146 // Too bad this can't be checked at compile/build time
1147 diag_printf("Sorry, FLASH config exceeds available space in FIS directory\n");
1150 cfg_base = (void *)(((CYG_ADDRESS)fis_addr + fisdir_size) - cfg_size);
1151 fisdir_size -= cfg_size;
1153 cfg_size = (flash_block_size > sizeof(struct _config)) ?
1154 sizeof(struct _config) :
1155 _rup(sizeof(struct _config), flash_block_size);
1156 if (CYGNUM_REDBOOT_FLASH_CONFIG_BLOCK < 0) {
1157 cfg_base = (void *)((CYG_ADDRESS)flash_end + 1 -
1158 _rup(_rup((-CYGNUM_REDBOOT_FLASH_CONFIG_BLOCK * flash_block_size), cfg_size),
1161 cfg_base = (void *)((CYG_ADDRESS)flash_start +
1162 _rup(_rup((CYGNUM_REDBOOT_FLASH_CONFIG_BLOCK * flash_block_size), cfg_size),
1166 FLASH_READ(cfg_base, config, sizeof(struct _config), &err_addr);
1167 conf_endian_fixup(config);
1169 read_eeprom(config, sizeof(struct _config)); // into 'config'
1171 #ifdef CYGSEM_REDBOOT_FLASH_CONFIG_READONLY_FALLBACK
1172 memcpy(readonly_config, config, sizeof(struct _config));
1174 if ((flash_crc(config) != config->cksum) ||
1175 (config->key1 != CONFIG_KEY1)|| (config->key2 != CONFIG_KEY2)) {
1176 diag_printf("**Warning** FLASH configuration checksum error or invalid key\n");
1177 diag_printf("Use 'fconfig -i' to [re]initialize database\n");
1182 flash_get_config("boot_script", &use_boot_script, CONFIG_BOOL);
1183 if (use_boot_script) {
1184 flash_get_config("boot_script_data", &script, CONFIG_SCRIPT);
1185 flash_get_config("boot_script_timeout", &script_timeout, CONFIG_INT);
1187 #ifdef CYGSEM_REDBOOT_VARIABLE_BAUD_RATE
1188 if (flash_get_config("console_baud_rate", &console_baud_rate, CONFIG_INT)) {
1189 extern int set_console_baud_rate(int);
1190 set_console_baud_rate(console_baud_rate);
1195 RedBoot_init(load_flash_config, RedBoot_INIT_SECOND);