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 bool 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 = (void *)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
274 lp = line; *lp = '\0';
275 val_ptr = (void *)CONFIG_OBJECT_VALUE(dp);
276 if (LIST_OPT_NICKNAMES & list_opt)
277 diag_printf("%s: ", CONFIG_OBJECT_KEY(dp));
278 if (LIST_OPT_FULLNAMES & list_opt) {
279 if (title != (char *)NULL) {
280 diag_printf("%s: ", title);
282 diag_printf("%s: ", CONFIG_OBJECT_KEY(dp));
285 switch (type = CONFIG_OBJECT_TYPE(dp)) {
287 memcpy(&hold_bool_val, val_ptr, sizeof(bool));
288 lp += diag_sprintf(lp, "%s", hold_bool_val ? "true" : "false");
291 memcpy(&hold_int_val, val_ptr, sizeof(unsigned long));
292 lp += diag_sprintf(lp, "%ld", hold_int_val);
294 #ifdef CYGPKG_REDBOOT_NETWORKING
296 lp += diag_sprintf(lp, "%s", inet_ntoa((in_addr_t *)val_ptr));
297 if (0 == strcmp("0.0.0.0", line) && !(LIST_OPT_LIST_ONLY & list_opt)) {
298 // then we have a deeply unhelpful starting text - kill it off
299 // (unless we are just listing all values)
300 lp = line; *lp = '\0';
304 for (esa_ptr = 0; esa_ptr < sizeof(enet_addr_t); esa_ptr++) {
305 lp += diag_sprintf(lp, "0x%02X", ((unsigned char *)val_ptr)[esa_ptr]);
306 if (esa_ptr < (sizeof(enet_addr_t)-1)) lp += diag_sprintf(lp, ":");
309 #if defined(CYGHWR_NET_DRIVERS) && (CYGHWR_NET_DRIVERS > 1)
311 lp += diag_sprintf(lp, "%s", (unsigned char *)val_ptr);
316 lp += diag_sprintf(lp, "%s", (unsigned char *)val_ptr);
320 sp = lp = (unsigned char *)val_ptr;
322 while (*lp != '\n') lp++;
324 diag_printf(".. %s\n", sp);
330 if (LIST_OPT_LIST_ONLY & list_opt) {
331 diag_printf("%s\n", line);
334 if (type != CONFIG_SCRIPT) {
335 if (NULL != newvalue) {
336 ret = strlen(newvalue);
337 if (ret > sizeof(line))
339 strcpy(hold_line, line); // Hold the old value for comparison
340 strcpy(line, newvalue);
341 diag_printf("Setting to %s\n", newvalue);
343 // read from terminal
344 strcpy(hold_line, line);
345 if (LIST_OPT_DUMBTERM & list_opt) {
346 diag_printf( (CONFIG_STRING == type ?
351 ret = _rb_gets_preloaded(line, sizeof(line), 0);
353 if (ret < 0) return CONFIG_ABORT;
354 // empty input - leave value untouched (else DNS goes away for a
355 // minute to try to look it up) but we must accept empty value for strings.
356 if (0 == line[0] && CONFIG_STRING != type) return CONFIG_OK;
357 if (strcmp(line, hold_line) == 0) return CONFIG_OK; // Just a CR - leave value untouched
358 lp = &line[strlen(line)-1];
359 if (*lp == '.') return CONFIG_DONE;
360 if (*lp == '^') return CONFIG_BACK;
364 memcpy(&hold_bool_val, val_ptr, sizeof(bool));
365 if (!parse_bool(line, &new_bool_val)) {
368 if (hold_bool_val != new_bool_val) {
369 memcpy(val_ptr, &new_bool_val, sizeof(bool));
370 return CONFIG_CHANGED;
376 memcpy(&hold_int_val, val_ptr, sizeof(unsigned long));
377 if (!parse_num(line, &new_int_val, 0, 0)) {
380 if (hold_int_val != new_int_val) {
381 memcpy(val_ptr, &new_int_val, sizeof(unsigned long));
382 return CONFIG_CHANGED;
387 #ifdef CYGPKG_REDBOOT_NETWORKING
389 memcpy(&hold_ip_val.s_addr, &((in_addr_t *)val_ptr)->s_addr, sizeof(in_addr_t));
390 if (!_gethostbyname(line, &new_ip_val)) {
393 if (hold_ip_val.s_addr != new_ip_val.s_addr) {
394 memcpy(val_ptr, &new_ip_val, sizeof(in_addr_t));
395 return CONFIG_CHANGED;
401 memcpy(&hold_esa_val, val_ptr, sizeof(enet_addr_t));
403 for (esa_ptr = 0; esa_ptr < sizeof(enet_addr_t); esa_ptr++) {
404 unsigned long esa_byte;
405 if (!parse_num(esp, &esa_byte, &esp, ":")) {
406 memcpy(val_ptr, &hold_esa_val, sizeof(enet_addr_t));
409 ((unsigned char *)val_ptr)[esa_ptr] = esa_byte;
411 #ifdef CYGSEM_REDBOOT_PLF_ESA_VALIDATE
412 if (!cyg_plf_redboot_esa_validate(val_ptr)) {
413 memcpy(val_ptr, &hold_esa_val, sizeof(enet_addr_t));
417 return CONFIG_CHANGED;
419 #if defined(CYGHWR_NET_DRIVERS) && (CYGHWR_NET_DRIVERS > 1)
421 if (strlen(line) >= MAX_STRING_LENGTH || net_devindex(line) < 0) {
424 diag_printf("Sorry, Port name must be one of:\n");
425 for (index = 0; (name = net_devname(index)) != NULL; index++)
426 diag_printf(" %s\n", name);
429 strcpy((unsigned char *)val_ptr, line);
434 // Assume it always changes
435 sp = (unsigned char *)val_ptr;
437 diag_printf("Enter script, terminate with empty line\n");
441 ret = _rb_gets(line, sizeof(line), 0);
442 if (ret < 0) return CONFIG_ABORT;
443 if (strlen(line) == 0) break;
444 script_len += strlen(line) + 1;
445 if (script_len > config_length(CONFIG_SCRIPT)) {
446 diag_printf("script longer than %d not allowed!\n",
447 config_length(CONFIG_SCRIPT));
458 if (strlen(line) >= MAX_STRING_LENGTH) {
459 diag_printf("Sorry, value is too long\n");
462 strcpy((unsigned char *)val_ptr, line);
465 return CONFIG_CHANGED;
469 // Manage configuration information with the FLASH
473 config_length(int type)
479 return sizeof(unsigned long);
480 #ifdef CYGPKG_REDBOOT_NETWORKING
482 return sizeof(in_addr_t);
484 // Would like this to be sizeof(enet_addr_t), but that causes much
485 // pain since it fouls the alignment of data which follows.
487 #if defined(CYGHWR_NET_DRIVERS) && (CYGHWR_NET_DRIVERS > 1)
489 return MAX_STRING_LENGTH;
493 return MAX_STRING_LENGTH;
495 return MAX_SCRIPT_LENGTH;
501 static cmd_fun do_flash_config;
502 RedBoot_cmd("fconfig",
503 "Manage configuration kept in FLASH memory",
504 "[-i] [-l] [-n] [-f] [-d] | [-d] nickname [value]",
509 do_flash_config(int argc, char *argv[])
511 bool need_update = false;
512 struct config_option *optend = __CONFIG_options_TAB_END__;
513 struct config_option *opt = __CONFIG_options_TAB__;
514 struct option_info opts[5];
523 char *onlyone = NULL;
524 char *onevalue = NULL;
525 bool doneone = false;
528 #ifdef CYGHWR_REDBOOT_FLASH_CONFIG_MEDIA_FLASH
530 diag_printf("Sorry, no FLASH memory is available\n");
534 memcpy(backup_config, config, sizeof(struct _config));
535 script = (unsigned char *)0;
537 init_opts(&opts[0], 'l', false, OPTION_ARG_TYPE_FLG,
538 (void *)&list_only, (bool *)0, "list configuration only");
539 init_opts(&opts[1], 'n', false, OPTION_ARG_TYPE_FLG,
540 (void *)&nicknames, (bool *)0, "show nicknames");
541 init_opts(&opts[2], 'f', false, OPTION_ARG_TYPE_FLG,
542 (void *)&fullnames, (bool *)0, "show full names");
543 init_opts(&opts[3], 'i', false, OPTION_ARG_TYPE_FLG,
544 (void *)&init, (bool *)0, "initialize configuration database");
545 init_opts(&opts[4], 'd', false, OPTION_ARG_TYPE_FLG,
546 (void *)&dumbterminal, (bool *)0, "dumb terminal: no clever edits");
548 // First look to see if we are setting or getting a single option
549 // by just quoting its nickname
550 if ( (2 == argc && '-' != argv[1][0]) ||
551 (3 == argc && '-' != argv[1][0] && '-' != argv[2][0])) {
552 // then the command was "fconfig foo [value]"
554 onevalue = (3 == argc) ? argv[2] : NULL;
555 list_opt = LIST_OPT_NICKNAMES;
557 // Next see if we are setting or getting a single option with a dumb
558 // terminal invoked, ie. no line editing.
559 else if (3 == argc &&
560 '-' == argv[1][0] && 'd' == argv[1][1] && 0 == argv[1][2] &&
562 // then the command was "fconfig -d foo"
565 list_opt = LIST_OPT_NICKNAMES | LIST_OPT_DUMBTERM;
568 if (!scan_opts(argc, argv, 1, opts, 5, 0, 0, ""))
570 list_opt |= list_only ? LIST_OPT_LIST_ONLY : 0;
571 list_opt |= nicknames ? LIST_OPT_NICKNAMES : LIST_OPT_FULLNAMES;
572 list_opt |= fullnames ? LIST_OPT_FULLNAMES : 0;
573 list_opt |= dumbterminal ? LIST_OPT_DUMBTERM : 0;
576 if (init && verify_action("Initialize non-volatile configuration")) {
581 dp = &config->config_data[0];
582 while (dp < &config->config_data[sizeof(config->config_data)]) {
583 if (CONFIG_OBJECT_TYPE(dp) == CONFIG_EMPTY) {
586 len = 4 + CONFIG_OBJECT_KEYLEN(dp) + CONFIG_OBJECT_ENABLE_KEYLEN(dp) +
587 config_length(CONFIG_OBJECT_TYPE(dp));
588 // Provide a title for well known [i.e. builtin] objects
589 title = (char *)NULL;
590 opt = __CONFIG_options_TAB__;
591 while (opt != optend) {
592 if (strcmp(opt->key, CONFIG_OBJECT_KEY(dp)) == 0) {
598 if ( onlyone && 0 != strcmp(CONFIG_OBJECT_KEY(dp), onlyone) )
599 ret = CONFIG_OK; // skip this entry
602 ret = get_config(dp, title, list_opt, onevalue); // do this opt
608 memcpy(config, backup_config, sizeof(struct _config));
616 dp = &config->config_data[0];
619 // Nothing - make him do it again
620 diag_printf ("** invalid entry\n");
621 onevalue = NULL; // request a good value be typed in - or abort/whatever
626 if (NULL != onlyone && !doneone) {
627 #ifdef CYGSEM_REDBOOT_ALLOW_DYNAMIC_FLASH_CONFIG_DATA
628 if (verify_action("** entry '%s' not found - add", onlyone)) {
629 struct config_option opt;
630 diag_printf("Trying to add value\n");
633 diag_printf("** entry '%s' not found\n", onlyone);
638 flash_write_config(true);
642 #ifdef CYGSEM_REDBOOT_FLASH_ALIASES
643 static cmd_fun do_alias;
645 "Manage aliases kept in FLASH memory",
651 make_alias(char *alias, char *name)
653 diag_sprintf(alias, "alias/%s", name);
657 do_alias(int argc, char *argv[])
661 struct config_option opt;
665 make_alias(name, argv[1]);
666 if (flash_get_config(name, &val, CONFIG_STRING)) {
667 diag_printf("'%s' = '%s'\n", argv[1], val);
669 diag_printf("'%s' not found\n", argv[1]);
673 if (strlen(argv[2]) >= MAX_STRING_LENGTH) {
674 diag_printf("Sorry, value is too long\n");
677 make_alias(name, argv[1]);
678 opt.type = CONFIG_STRING;
679 opt.enable = (char *)0;
680 opt.enable_sense = 1;
682 opt.dflt = (CYG_ADDRESS)argv[2];
683 flash_add_config(&opt, true);
686 diag_printf("usage: alias name [value]\n");
690 // Lookup an alias. First try plain string aliases. If that fails try
691 // other types so allowing access to all configured values. This allows
692 // for alias (macro) expansion of normal 'fconfig' data, such as the
695 flash_lookup_alias(char *alias, char *alias_buf)
704 #ifdef CYGPKG_REDBOOT_NETWORKING
708 make_alias(name, alias);
709 if (flash_get_config(name, &val, CONFIG_STRING)) {
712 dp = flash_lookup_config(alias);
714 val_ptr = (void *)CONFIG_OBJECT_VALUE(dp);
715 switch (type = CONFIG_OBJECT_TYPE(dp)) {
717 memcpy(&hold_bool_val, val_ptr, sizeof(bool));
718 diag_sprintf(alias_buf, "%s", hold_bool_val ? "true" : "false");
721 memcpy(&hold_long_val, val_ptr, sizeof(unsigned long));
722 diag_sprintf(alias_buf,"%ld", hold_long_val);
724 #ifdef CYGPKG_REDBOOT_NETWORKING
726 diag_sprintf(alias_buf,"%s", inet_ntoa((in_addr_t *)val_ptr));
729 for (esa_ptr = 0; esa_ptr < sizeof(enet_addr_t); esa_ptr++) {
730 diag_sprintf(alias_buf+(3*esa_ptr), "0x%02X", ((unsigned char *)val_ptr)[esa_ptr]);
731 if (esa_ptr < (sizeof(enet_addr_t)-1)) diag_printf(":");
736 return (char *) val_ptr;
747 #endif // CYGSEM_REDBOOT_FLASH_ALIASES
750 flash_crc(struct _config *conf)
753 #ifdef REDBOOT_FLASH_REVERSE_BYTEORDER
756 if (conf->key1 == CONFIG_KEY1 && conf->key2 == CONFIG_KEY2) {
758 conf_endian_fixup(conf);
762 crc = cyg_crc32((unsigned char *)conf, sizeof(*conf)-sizeof(conf->cksum));
764 #ifdef REDBOOT_FLASH_REVERSE_BYTEORDER
766 conf_endian_fixup(conf);
772 // Write the in-memory copy of the configuration data to the flash device.
775 flash_write_config(bool prompt)
777 #if defined(CYGHWR_REDBOOT_FLASH_CONFIG_MEDIA_FLASH)
778 #if !defined(CYGSEM_REDBOOT_FLASH_COMBINED_FIS_AND_CONFIG)
784 config->len = sizeof(struct _config);
785 config->key1 = CONFIG_KEY1;
786 config->key2 = CONFIG_KEY2;
787 config->cksum = flash_crc(config);
788 if (!prompt || verify_action("Update RedBoot non-volatile configuration")) {
789 #ifdef CYGHWR_REDBOOT_FLASH_CONFIG_MEDIA_FLASH
790 #ifdef CYGSEM_REDBOOT_FLASH_COMBINED_FIS_AND_CONFIG
791 fis_read_directory();
792 fis_update_directory();
794 #ifdef CYGSEM_REDBOOT_FLASH_LOCK_SPECIAL
795 // Insure [quietly] that the config page is unlocked before trying to update
796 flash_unlock((void *)cfg_base, cfg_size, (void **)&err_addr);
798 if ((stat = flash_erase(cfg_base, cfg_size, (void **)&err_addr)) != 0) {
799 diag_printf(" initialization failed at %p: %s\n", err_addr, flash_errmsg(stat));
801 conf_endian_fixup(config);
802 if ((stat = FLASH_PROGRAM(cfg_base, config, sizeof(struct _config), (void **)&err_addr)) != 0) {
803 diag_printf("Error writing config data at %p: %s\n",
804 err_addr, flash_errmsg(stat));
806 conf_endian_fixup(config);
808 #ifdef CYGSEM_REDBOOT_FLASH_LOCK_SPECIAL
809 // Insure [quietly] that the config data is locked after the update
810 flash_lock((void *)cfg_base, cfg_size, (void **)&err_addr);
812 #endif // CYGSEM_REDBOOT_FLASH_COMBINED_FIS_AND_CONFIG
813 #else // CYGHWR_REDBOOT_FLASH_CONFIG_MEDIA_FLASH
814 write_eeprom(config, sizeof(struct _config)); // into 'config'
820 // Find the configuration entry for a particular key
822 static unsigned char *
823 flash_lookup_config(char *key)
828 if (!config_ok) return (unsigned char *)NULL;
830 dp = &config->config_data[0];
831 while (dp < &config->config_data[sizeof(config->config_data)]) {
832 len = 4 + CONFIG_OBJECT_KEYLEN(dp) + CONFIG_OBJECT_ENABLE_KEYLEN(dp) +
833 config_length(CONFIG_OBJECT_TYPE(dp));
834 if (strcmp(key, CONFIG_OBJECT_KEY(dp)) == 0) {
839 // diag_printf("Can't find config data for '%s'\n", key);
844 // Enumerate the keys from the configuration
847 flash_next_key(char *key, int keylen, int *type, int *offset)
852 if (!config_ok) return false;
853 if ((*offset < 0) || (*offset >= MAX_CONFIG_DATA)) return false;
855 dp = &config->config_data[*offset];
856 if ((*type = CONFIG_OBJECT_TYPE(dp)) == CONFIG_EMPTY) return false;
857 if ((len = CONFIG_OBJECT_KEYLEN(dp)) > keylen) return false;
858 memcpy(key, CONFIG_OBJECT_KEY(dp), len);
859 *offset += 4 + CONFIG_OBJECT_KEYLEN(dp) + CONFIG_OBJECT_ENABLE_KEYLEN(dp) +
860 config_length(CONFIG_OBJECT_TYPE(dp));
865 // Retrieve a data object from the data base (in memory copy)
868 flash_get_config(char *key, void *val, int type)
872 #ifdef CYGSEM_REDBOOT_FLASH_CONFIG_READONLY_FALLBACK
873 struct _config *save_config = 0;
877 if (!config_ok) return false;
879 if ((dp = flash_lookup_config(key)) != (unsigned char *)NULL) {
880 if (CONFIG_OBJECT_TYPE(dp) == type) {
881 val_ptr = (void *)CONFIG_OBJECT_VALUE(dp);
883 // Note: the data may be unaligned in the configuration data
885 memcpy(val, val_ptr, sizeof(bool));
888 memcpy(val, val_ptr, sizeof(unsigned long));
890 #ifdef CYGPKG_REDBOOT_NETWORKING
892 memcpy(val, val_ptr, sizeof(in_addr_t));
895 memcpy(val, val_ptr, sizeof(enet_addr_t));
898 #if defined(CYGHWR_NET_DRIVERS) && (CYGHWR_NET_DRIVERS > 1)
903 // Just return a pointer to the script/line
904 *(unsigned char **)val = (unsigned char *)val_ptr;
908 diag_printf("Request for config value '%s' - wrong type\n", key);
912 #ifdef CYGSEM_REDBOOT_FLASH_CONFIG_READONLY_FALLBACK
913 // Did not find key. Is configuration data valid?
914 // Check to see if the config data is valid, if not, revert to
915 // readonly mode, by setting config to readonly_config. We
916 // will set it back before we leave this function.
917 if ( (config != readonly_config) && ((flash_crc(config) != config->cksum) ||
918 (config->key1 != CONFIG_KEY1)|| (config->key2 != CONFIG_KEY2))) {
919 save_config = config;
920 config = readonly_config;
921 if ((flash_crc(config) != config->cksum) ||
922 (config->key1 != CONFIG_KEY1)|| (config->key2 != CONFIG_KEY2)) {
923 diag_printf("FLASH configuration checksum error or invalid key\n");
924 config = save_config;
928 diag_printf("Getting config information in READONLY mode\n");
929 res = flash_get_config(key, val, type);
930 config = save_config;
939 // Update a data object in the data base (in memory copy & backing store)
942 flash_set_config(char *key, void *val, int type)
947 if (!config_ok) return false;
949 if ((dp = flash_lookup_config(key)) != (unsigned char *)NULL) {
950 if (CONFIG_OBJECT_TYPE(dp) == type) {
951 val_ptr = (void *)CONFIG_OBJECT_VALUE(dp);
953 // Note: the data may be unaligned in the configuration data
955 memcpy(val_ptr, val, sizeof(bool));
958 memcpy(val_ptr, val, sizeof(unsigned long));
960 #ifdef CYGPKG_REDBOOT_NETWORKING
962 memcpy(val_ptr, val, sizeof(in_addr_t));
965 memcpy(val_ptr, val, sizeof(enet_addr_t));
968 #if defined(CYGHWR_NET_DRIVERS) && (CYGHWR_NET_DRIVERS > 1)
973 memcpy(val_ptr, val, config_length(CONFIG_STRING));
977 diag_printf("Can't set config value '%s' - wrong type\n", key);
980 flash_write_config(false);
987 // Copy data into the config area
990 flash_config_insert_value(unsigned char *dp, struct config_option *opt)
993 // Note: the data may be unaligned in the configuration data
995 memcpy(dp, (void *)&opt->dflt, sizeof(bool));
998 memcpy(dp, (void *)&opt->dflt, sizeof(unsigned long));
1000 #ifdef CYGPKG_REDBOOT_NETWORKING
1002 memcpy(dp, (void *)&opt->dflt, sizeof(in_addr_t));
1005 memcpy(dp, (void *)opt->dflt, sizeof(enet_addr_t));
1007 #if defined(CYGHWR_NET_DRIVERS) && (CYGHWR_NET_DRIVERS > 1)
1008 case CONFIG_NETPORT:
1009 // validate dflt and if not acceptable use first port
1013 for (index = 0; (name = net_devname(index)) != NULL; index++)
1014 if (!strcmp((char *)opt->dflt, name))
1017 name = net_devname(0);
1018 memcpy(dp, name, strlen(name) + 1);
1024 memcpy(dp, (void *)opt->dflt, config_length(CONFIG_STRING));
1032 // Add a new option to the database
1035 flash_add_config(struct config_option *opt, bool update)
1037 unsigned char *dp, *kp;
1038 int len, elen, size;
1040 // If data item is already present, just update it
1041 // Note: only the data value can be thusly changed
1042 if ((dp = flash_lookup_config(opt->key)) != (unsigned char *)NULL) {
1043 flash_config_insert_value(CONFIG_OBJECT_VALUE(dp), opt);
1045 flash_write_config(true);
1049 // Add the data item
1050 dp = &config->config_data[0];
1052 while (size < sizeof(config->config_data)) {
1053 if (CONFIG_OBJECT_TYPE(dp) == CONFIG_EMPTY) {
1055 len = strlen(kp) + 1;
1056 size += len + 2 + 2 + config_length(opt->type);
1058 elen = strlen(opt->enable) + 1;
1063 if (size > sizeof(config->config_data)) {
1066 CONFIG_OBJECT_TYPE(dp) = opt->type;
1067 CONFIG_OBJECT_KEYLEN(dp) = len;
1068 CONFIG_OBJECT_ENABLE_SENSE(dp) = opt->enable_sense;
1069 CONFIG_OBJECT_ENABLE_KEYLEN(dp) = elen;
1070 dp = CONFIG_OBJECT_KEY(dp);
1071 while (*kp) *dp++ += *kp++;
1075 while (*kp) *dp++ += *kp++;
1078 flash_config_insert_value(dp, opt);
1080 flash_write_config(true);
1084 len = 4 + CONFIG_OBJECT_KEYLEN(dp) + CONFIG_OBJECT_ENABLE_KEYLEN(dp) +
1085 config_length(CONFIG_OBJECT_TYPE(dp));
1090 diag_printf("No space to add '%s'\n", opt->key);
1095 // Reset/initialize configuration data - used only when starting from scratch
1100 // Well known option strings
1101 struct config_option *optend = __CONFIG_options_TAB_END__;
1102 struct config_option *opt = __CONFIG_options_TAB__;
1104 memset(config, 0, sizeof(struct _config));
1105 while (opt != optend) {
1106 if (!flash_add_config(opt, false)) {
1115 // Attempt to get configuration information from the FLASH.
1116 // If available (i.e. good checksum, etc), initialize "known"
1117 // values for later use.
1120 load_flash_config(void)
1122 bool use_boot_script;
1123 unsigned char *cfg_temp = (unsigned char *)workspace_end;
1124 #ifdef CYGHWR_REDBOOT_FLASH_CONFIG_MEDIA_FLASH
1129 script = (unsigned char *)0;
1130 cfg_temp -= sizeof(struct _config); // Space for primary config data
1131 config = (struct _config *)cfg_temp;
1132 cfg_temp -= sizeof(struct _config); // Space for backup config data
1133 backup_config = (struct _config *)cfg_temp;
1134 #ifdef CYGSEM_REDBOOT_FLASH_CONFIG_READONLY_FALLBACK
1135 cfg_temp -= sizeof(struct _config); // Space for readonly copy of config data
1136 readonly_config = (struct _config *)cfg_temp;
1138 workspace_end = cfg_temp;
1139 #ifdef CYGHWR_REDBOOT_FLASH_CONFIG_MEDIA_FLASH
1140 if (!do_flash_init()) return;
1141 #ifdef CYGSEM_REDBOOT_FLASH_COMBINED_FIS_AND_CONFIG
1142 cfg_size = _rup(sizeof(struct _config), sizeof(struct fis_image_desc));
1143 if ((fisdir_size-cfg_size) < (CYGNUM_REDBOOT_FIS_DIRECTORY_ENTRY_COUNT *
1144 CYGNUM_REDBOOT_FIS_DIRECTORY_ENTRY_SIZE)) {
1145 // Too bad this can't be checked at compile/build time
1146 diag_printf("Sorry, FLASH config exceeds available space in FIS directory\n");
1149 cfg_base = (void *)(((CYG_ADDRESS)fis_addr + fisdir_size) - cfg_size);
1150 fisdir_size -= cfg_size;
1152 cfg_size = (flash_block_size > sizeof(struct _config)) ?
1153 sizeof(struct _config) :
1154 _rup(sizeof(struct _config), flash_block_size);
1155 if (CYGNUM_REDBOOT_FLASH_CONFIG_BLOCK < 0) {
1156 cfg_base = (void *)((CYG_ADDRESS)flash_end + 1 -
1157 _rup(_rup((-CYGNUM_REDBOOT_FLASH_CONFIG_BLOCK*flash_block_size), cfg_size), flash_block_size));
1159 cfg_base = (void *)((CYG_ADDRESS)flash_start +
1160 _rup(_rup((CYGNUM_REDBOOT_FLASH_CONFIG_BLOCK*flash_block_size), cfg_size), flash_block_size));
1163 FLASH_READ(cfg_base, config, sizeof(struct _config), &err_addr);
1164 conf_endian_fixup(config);
1166 read_eeprom(config, sizeof(struct _config)); // into 'config'
1168 #ifdef CYGSEM_REDBOOT_FLASH_CONFIG_READONLY_FALLBACK
1169 memcpy(readonly_config, config, sizeof(struct _config));
1171 if ((flash_crc(config) != config->cksum) ||
1172 (config->key1 != CONFIG_KEY1)|| (config->key2 != CONFIG_KEY2)) {
1173 diag_printf("**Warning** FLASH configuration checksum error or invalid key\n");
1174 diag_printf("Use 'fconfig -i' to [re]initialize database\n");
1179 flash_get_config("boot_script", &use_boot_script, CONFIG_BOOL);
1180 if (use_boot_script) {
1181 flash_get_config("boot_script_data", &script, CONFIG_SCRIPT);
1182 flash_get_config("boot_script_timeout", &script_timeout, CONFIG_INT);
1184 #ifdef CYGSEM_REDBOOT_VARIABLE_BAUD_RATE
1185 if (flash_get_config("console_baud_rate", &console_baud_rate, CONFIG_INT)) {
1186 extern int set_console_baud_rate(int);
1187 set_console_baud_rate(console_baud_rate);
1192 RedBoot_init(load_flash_config, RedBoot_INIT_SECOND);