Mercurial > nand-ecoscentric
comparison packages/redboot/current/src/flash.c @ 1223:dbcfe4e0dbd2
New platform - TAMS MOAB - and generic changes to support it
| author | gthomas |
|---|---|
| date | Fri, 19 Sep 2003 17:11:18 +0000 |
| parents | 517229d4051f |
| children | dc8c964619a0 |
comparison
equal
deleted
inserted
replaced
| 1222:f0bd64ec9405 | 1223:dbcfe4e0dbd2 |
|---|---|
| 7 //========================================================================== | 7 //========================================================================== |
| 8 //####ECOSGPLCOPYRIGHTBEGIN#### | 8 //####ECOSGPLCOPYRIGHTBEGIN#### |
| 9 // ------------------------------------------- | 9 // ------------------------------------------- |
| 10 // This file is part of eCos, the Embedded Configurable Operating System. | 10 // This file is part of eCos, the Embedded Configurable Operating System. |
| 11 // Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Red Hat, Inc. | 11 // Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Red Hat, Inc. |
| 12 // Copyright (C) 2003 Gary Thomas | |
| 12 // | 13 // |
| 13 // eCos is free software; you can redistribute it and/or modify it under | 14 // eCos is free software; you can redistribute it and/or modify it under |
| 14 // the terms of the GNU General Public License as published by the Free | 15 // the terms of the GNU General Public License as published by the Free |
| 15 // Software Foundation; either version 2 or (at your option) any later version. | 16 // Software Foundation; either version 2 or (at your option) any later version. |
| 16 // | 17 // |
| 62 #endif | 63 #endif |
| 63 | 64 |
| 64 // Round a quantity up | 65 // Round a quantity up |
| 65 #define _rup(n,s) ((((n)+(s-1))/s)*s) | 66 #define _rup(n,s) ((((n)+(s-1))/s)*s) |
| 66 | 67 |
| 67 #ifdef CYGSEM_REDBOOT_FLASH_CONFIG | |
| 68 #include <flash_config.h> | |
| 69 | |
| 70 // Configuration data, saved in FLASH, used to set/update RedBoot | |
| 71 // normal "configuration" data items. | |
| 72 static struct _config { | |
| 73 unsigned long len; | |
| 74 unsigned long key1; | |
| 75 unsigned char config_data[MAX_CONFIG_DATA-(4*4)]; | |
| 76 unsigned long key2; | |
| 77 unsigned long cksum; | |
| 78 } *config, *backup_config; | |
| 79 #ifdef CYGSEM_REDBOOT_FLASH_CONFIG_READONLY_FALLBACK | |
| 80 static struct _config *readonly_config; | |
| 81 #endif | |
| 82 #endif | |
| 83 | |
| 84 #ifdef CYGOPT_REDBOOT_FIS | 68 #ifdef CYGOPT_REDBOOT_FIS |
| 85 // Image management functions | 69 // Image management functions |
| 86 local_cmd_entry("init", | 70 local_cmd_entry("init", |
| 87 "Initialize FLASH Image System [FIS]", | 71 "Initialize FLASH Image System [FIS]", |
| 88 "[-f]", | 72 "[-f]", |
| 176 do_fis, | 160 do_fis, |
| 177 __FIS_cmds_TAB__, &__FIS_cmds_TAB_END__ | 161 __FIS_cmds_TAB__, &__FIS_cmds_TAB_END__ |
| 178 ); | 162 ); |
| 179 | 163 |
| 180 // Local data used by these routines | 164 // Local data used by these routines |
| 181 static void *flash_start, *flash_end; | 165 void *flash_start, *flash_end; |
| 182 static int flash_block_size, flash_num_blocks; | 166 int flash_block_size, flash_num_blocks; |
| 183 #ifdef CYGOPT_REDBOOT_FIS | 167 #ifdef CYGOPT_REDBOOT_FIS |
| 184 static void *fis_work_block; | 168 void *fis_work_block; |
| 185 static void *fis_addr; | 169 void *fis_addr; |
| 186 static int fisdir_size; // Size of FIS directory. | 170 int fisdir_size; // Size of FIS directory. |
| 187 #endif | 171 #endif |
| 188 #ifdef CYGSEM_REDBOOT_FLASH_CONFIG | 172 #ifdef CYGSEM_REDBOOT_FLASH_CONFIG |
| 189 static void *cfg_base; // Location in Flash of config data | 173 extern void *cfg_base; // Location in Flash of config data |
| 190 static int cfg_size; // Length of config data - rounded to Flash block size | 174 extern int cfg_size; // Length of config data - rounded to Flash block size |
| 191 // Prototypes for local functions | 175 extern struct _config *config; |
| 192 static unsigned char *flash_lookup_config(char *key); | |
| 193 #endif | 176 #endif |
| 194 | 177 |
| 195 static void | 178 static void |
| 196 fis_usage(char *why) | 179 fis_usage(char *why) |
| 197 { | 180 { |
| 210 struct fis_image_desc * | 193 struct fis_image_desc * |
| 211 fis_lookup(char *name, int *num) | 194 fis_lookup(char *name, int *num) |
| 212 { | 195 { |
| 213 int i; | 196 int i; |
| 214 struct fis_image_desc *img; | 197 struct fis_image_desc *img; |
| 215 | 198 void *err_addr; |
| 199 | |
| 200 flash_read(fis_addr, fis_work_block, fisdir_size, (void **)&err_addr); | |
| 216 img = (struct fis_image_desc *)fis_work_block; | 201 img = (struct fis_image_desc *)fis_work_block; |
| 217 for (i = 0; i < fisdir_size/sizeof(*img); i++, img++) { | 202 for (i = 0; i < fisdir_size/sizeof(*img); i++, img++) { |
| 218 if ((img->name[0] != (unsigned char)0xFF) && | 203 if ((img->name[0] != (unsigned char)0xFF) && |
| 219 (strcasecmp(name, img->name) == 0)) { | 204 (strcasecmp(name, img->name) == 0)) { |
| 220 if (num) *num = i; | 205 if (num) *num = i; |
| 222 } | 207 } |
| 223 } | 208 } |
| 224 return (struct fis_image_desc *)0; | 209 return (struct fis_image_desc *)0; |
| 225 } | 210 } |
| 226 | 211 |
| 227 static void | 212 void |
| 228 fis_update_directory(void) | 213 fis_update_directory(void) |
| 229 { | 214 { |
| 230 int stat; | 215 int stat; |
| 231 void *err_addr; | 216 void *err_addr; |
| 232 | 217 |
| 322 img->mem_base = redboot_flash_start; | 307 img->mem_base = redboot_flash_start; |
| 323 img->size = redboot_image_size; | 308 img->size = redboot_image_size; |
| 324 img++; | 309 img++; |
| 325 redboot_flash_start += redboot_image_size; | 310 redboot_flash_start += redboot_image_size; |
| 326 #endif | 311 #endif |
| 327 #ifdef CYGSEM_REDBOOT_FLASH_CONFIG | 312 #if defined(CYGSEM_REDBOOT_FLASH_CONFIG) && defined(CYGHWR_REDBOOT_FLASH_CONFIG_MEDIA_FLASH) |
| 328 // And a descriptor for the configuration data | 313 // And a descriptor for the configuration data |
| 329 memset(img, 0, sizeof(*img)); | 314 memset(img, 0, sizeof(*img)); |
| 330 strcpy(img->name, "RedBoot config"); | 315 strcpy(img->name, "RedBoot config"); |
| 331 img->flash_base = (CYG_ADDRESS)cfg_base; | 316 img->flash_base = (CYG_ADDRESS)cfg_base; |
| 332 img->mem_base = (CYG_ADDRESS)cfg_base; | 317 img->mem_base = (CYG_ADDRESS)cfg_base; |
| 400 #endif | 385 #endif |
| 401 // second deal with the larger part in the main: | 386 // second deal with the larger part in the main: |
| 402 erase_start = redboot_flash_start; // high water of created images | 387 erase_start = redboot_flash_start; // high water of created images |
| 403 // Now the empty bits between the end of Redboot and the cfg and dir | 388 // Now the empty bits between the end of Redboot and the cfg and dir |
| 404 // blocks. | 389 // blocks. |
| 405 #if defined(CYGSEM_REDBOOT_FLASH_CONFIG) && !defined(CYGSEM_REDBOOT_FLASH_COMBINED_FIS_AND_CONFIG) | 390 #if defined(CYGSEM_REDBOOT_FLASH_CONFIG) && \ |
| 391 defined(CYGHWR_REDBOOT_FLASH_CONFIG_MEDIA_FLASH) && \ | |
| 392 !defined(CYGSEM_REDBOOT_FLASH_COMBINED_FIS_AND_CONFIG) | |
| 406 if (fis_addr > cfg_base) { | 393 if (fis_addr > cfg_base) { |
| 407 erase_size = (CYG_ADDRESS)cfg_base - erase_start; // the gap between HWM and config data | 394 erase_size = (CYG_ADDRESS)cfg_base - erase_start; // the gap between HWM and config data |
| 408 } else { | 395 } else { |
| 409 erase_size = (CYG_ADDRESS)fis_addr - erase_start; // the gap between HWM and fis data | 396 erase_size = (CYG_ADDRESS)fis_addr - erase_start; // the gap between HWM and fis data |
| 410 } | 397 } |
| 454 struct fis_image_desc *img; | 441 struct fis_image_desc *img; |
| 455 int i; | 442 int i; |
| 456 bool show_cksums = false; | 443 bool show_cksums = false; |
| 457 bool show_datalen = false; | 444 bool show_datalen = false; |
| 458 struct option_info opts[2]; | 445 struct option_info opts[2]; |
| 446 void *err_addr; | |
| 459 | 447 |
| 460 #ifdef CYGHWR_REDBOOT_ARM_FLASH_SIB | 448 #ifdef CYGHWR_REDBOOT_ARM_FLASH_SIB |
| 461 // FIXME: this is somewhat half-baked | 449 // FIXME: this is somewhat half-baked |
| 462 extern void arm_fis_list(void); | 450 extern void arm_fis_list(void); |
| 463 arm_fis_list(); | 451 arm_fis_list(); |
| 475 #endif | 463 #endif |
| 476 if (!scan_opts(argc, argv, 2, opts, i, 0, 0, "")) | 464 if (!scan_opts(argc, argv, 2, opts, i, 0, 0, "")) |
| 477 { | 465 { |
| 478 return; | 466 return; |
| 479 } | 467 } |
| 480 img = (struct fis_image_desc *) fis_addr; | 468 flash_read(fis_addr, fis_work_block, fisdir_size, (void **)&err_addr); |
| 469 img = (struct fis_image_desc *) fis_work_block; | |
| 481 // Let diag_printf do the formatting in both cases, rather than counting | 470 // Let diag_printf do the formatting in both cases, rather than counting |
| 482 // cols by hand.... | 471 // cols by hand.... |
| 483 diag_printf("%-16s %-10s %-10s %-10s %-s\n", | 472 diag_printf("%-16s %-10s %-10s %-10s %-s\n", |
| 484 "Name","FLASH addr", | 473 "Name","FLASH addr", |
| 485 show_cksums ? "Checksum" : "Mem addr", | 474 show_cksums ? "Checksum" : "Mem addr", |
| 504 static void | 493 static void |
| 505 fis_free(int argc, char *argv[]) | 494 fis_free(int argc, char *argv[]) |
| 506 { | 495 { |
| 507 unsigned long *fis_ptr, *fis_end; | 496 unsigned long *fis_ptr, *fis_end; |
| 508 unsigned long *area_start; | 497 unsigned long *area_start; |
| 498 void *err_addr; | |
| 509 | 499 |
| 510 // Do not search the area reserved for pre-RedBoot systems: | 500 // Do not search the area reserved for pre-RedBoot systems: |
| 511 fis_ptr = (unsigned long *)((CYG_ADDRESS)flash_start + | 501 flash_read(fis_addr, fis_work_block, fisdir_size, (void **)&err_addr); |
| 502 fis_ptr = (unsigned long *)((CYG_ADDRESS)fis_work_block + | |
| 512 CYGNUM_REDBOOT_FLASH_RESERVED_BASE + | 503 CYGNUM_REDBOOT_FLASH_RESERVED_BASE + |
| 513 CYGBLD_REDBOOT_MIN_IMAGE_SIZE); | 504 CYGBLD_REDBOOT_MIN_IMAGE_SIZE); |
| 514 fis_end = (unsigned long *)(CYG_ADDRESS)flash_end; | 505 fis_end = (unsigned long *)(CYG_ADDRESS)flash_end; |
| 515 area_start = fis_ptr; | 506 area_start = fis_ptr; |
| 516 while (fis_ptr < fis_end) { | 507 while (fis_ptr < fis_end) { |
| 543 static bool | 534 static bool |
| 544 fis_find_free(CYG_ADDRESS *addr, unsigned long length) | 535 fis_find_free(CYG_ADDRESS *addr, unsigned long length) |
| 545 { | 536 { |
| 546 unsigned long *fis_ptr, *fis_end; | 537 unsigned long *fis_ptr, *fis_end; |
| 547 unsigned long *area_start; | 538 unsigned long *area_start; |
| 539 void *err_addr; | |
| 548 | 540 |
| 549 // Do not search the area reserved for pre-RedBoot systems: | 541 // Do not search the area reserved for pre-RedBoot systems: |
| 550 fis_ptr = (unsigned long *)((CYG_ADDRESS)flash_start + | 542 flash_read(fis_addr, fis_work_block, fisdir_size, (void **)&err_addr); |
| 543 fis_ptr = (unsigned long *)((CYG_ADDRESS)fis_work_block + | |
| 551 CYGNUM_REDBOOT_FLASH_RESERVED_BASE + | 544 CYGNUM_REDBOOT_FLASH_RESERVED_BASE + |
| 552 CYGBLD_REDBOOT_MIN_IMAGE_SIZE); | 545 CYGBLD_REDBOOT_MIN_IMAGE_SIZE); |
| 553 fis_end = (unsigned long *)(CYG_ADDRESS)flash_end; | 546 fis_end = (unsigned long *)(CYG_ADDRESS)flash_end; |
| 554 area_start = fis_ptr; | 547 area_start = fis_ptr; |
| 555 while (fis_ptr < fis_end) { | 548 while (fis_ptr < fis_end) { |
| 621 { | 614 { |
| 622 fis_usage("invalid arguments"); | 615 fis_usage("invalid arguments"); |
| 623 return; | 616 return; |
| 624 } | 617 } |
| 625 | 618 |
| 626 memcpy(fis_work_block, fis_addr, fisdir_size); | 619 flash_read(fis_addr, fis_work_block, fisdir_size, (void **)&err_addr); |
| 627 defaults_assumed = false; | 620 defaults_assumed = false; |
| 628 if (name) { | 621 if (name) { |
| 629 // Search existing files to acquire defaults for params not specified: | 622 // Search existing files to acquire defaults for params not specified: |
| 630 img = fis_lookup(name, NULL); | 623 img = fis_lookup(name, NULL); |
| 631 if (img) { | 624 if (img) { |
| 777 img->mem_base = exec_addr_set ? exec_addr : (flash_addr_set ? flash_addr : mem_addr); | 770 img->mem_base = exec_addr_set ? exec_addr : (flash_addr_set ? flash_addr : mem_addr); |
| 778 img->entry_point = entry_addr_set ? entry_addr : (CYG_ADDRESS)entry_address; // Hope it's been set | 771 img->entry_point = entry_addr_set ? entry_addr : (CYG_ADDRESS)entry_address; // Hope it's been set |
| 779 img->size = length; | 772 img->size = length; |
| 780 img->data_length = img_size; | 773 img->data_length = img_size; |
| 781 #ifdef CYGSEM_REDBOOT_FIS_CRC_CHECK | 774 #ifdef CYGSEM_REDBOOT_FIS_CRC_CHECK |
| 782 img->file_cksum = cyg_crc32((unsigned char *)flash_addr, img_size); | 775 if (!no_copy) { |
| 776 img->file_cksum = cyg_crc32((unsigned char *)mem_addr, img_size); | |
| 777 } else { | |
| 778 // No way to compute this, sorry | |
| 779 img->file_cksum = 0; | |
| 780 } | |
| 783 #endif | 781 #endif |
| 784 fis_update_directory(); | 782 fis_update_directory(); |
| 785 } | 783 } |
| 786 } | 784 } |
| 787 | 785 |
| 823 #endif | 821 #endif |
| 824 #if 1 // And the descriptor for the descriptor table itself | 822 #if 1 // And the descriptor for the descriptor table itself |
| 825 num_reserved++; | 823 num_reserved++; |
| 826 #endif | 824 #endif |
| 827 | 825 |
| 828 memcpy(fis_work_block, fis_addr, fisdir_size); | |
| 829 img = fis_lookup(name, &i); | 826 img = fis_lookup(name, &i); |
| 830 if (img) { | 827 if (img) { |
| 831 if (i < num_reserved) { | 828 if (i < num_reserved) { |
| 832 diag_printf("Sorry, '%s' is a reserved image and cannot be deleted\n", img->name); | 829 diag_printf("Sorry, '%s' is a reserved image and cannot be deleted\n", img->name); |
| 833 return; | 830 return; |
| 862 #endif | 859 #endif |
| 863 int num_options; | 860 int num_options; |
| 864 #ifdef CYGPKG_COMPRESS_ZLIB | 861 #ifdef CYGPKG_COMPRESS_ZLIB |
| 865 bool decompress = false; | 862 bool decompress = false; |
| 866 #endif | 863 #endif |
| 864 void *err_addr; | |
| 867 | 865 |
| 868 init_opts(&opts[0], 'b', true, OPTION_ARG_TYPE_NUM, | 866 init_opts(&opts[0], 'b', true, OPTION_ARG_TYPE_NUM, |
| 869 (void **)&mem_addr, (bool *)&mem_addr_set, "memory [load] base address"); | 867 (void **)&mem_addr, (bool *)&mem_addr_set, "memory [load] base address"); |
| 870 init_opts(&opts[1], 'c', false, OPTION_ARG_TYPE_FLG, | 868 init_opts(&opts[1], 'c', false, OPTION_ARG_TYPE_FLG, |
| 871 (void **)&show_cksum, (bool *)0, "display checksum"); | 869 (void **)&show_cksum, (bool *)0, "display checksum"); |
| 879 if (!scan_opts(argc, argv, 2, opts, num_options, (void **)&name, OPTION_ARG_TYPE_STR, "image name")) | 877 if (!scan_opts(argc, argv, 2, opts, num_options, (void **)&name, OPTION_ARG_TYPE_STR, "image name")) |
| 880 { | 878 { |
| 881 fis_usage("invalid arguments"); | 879 fis_usage("invalid arguments"); |
| 882 return; | 880 return; |
| 883 } | 881 } |
| 884 memcpy(fis_work_block, fis_addr, fisdir_size); | |
| 885 if ((img = fis_lookup(name, NULL)) == (struct fis_image_desc *)0) { | 882 if ((img = fis_lookup(name, NULL)) == (struct fis_image_desc *)0) { |
| 886 diag_printf("No image '%s' found\n", name); | 883 diag_printf("No image '%s' found\n", name); |
| 887 return; | 884 return; |
| 888 } | 885 } |
| 889 if (!mem_addr_set) { | 886 if (!mem_addr_set) { |
| 890 mem_addr = img->mem_base; | 887 mem_addr = img->mem_base; |
| 891 } | 888 } |
| 892 // Load image from FLASH into RAM | 889 // Load image from FLASH into RAM |
| 893 #ifdef CYGSEM_REDBOOT_VALIDATE_USER_RAM_LOADS | 890 #ifdef CYGSEM_REDBOOT_VALIDATE_USER_RAM_LOADS |
| 894 if ((mem_addr < (CYG_ADDRESS)user_ram_start) || | 891 if (!valid_address((void *)mem_addr)) { |
| 895 ((mem_addr+img->data_length) >= (CYG_ADDRESS)user_ram_end)) { | 892 diag_printf("Not a loadable image - try using -b ADDRESS option\n"); |
| 896 diag_printf("Not a loadable image\n"); | |
| 897 return; | 893 return; |
| 898 } | 894 } |
| 899 #endif | 895 #endif |
| 900 #ifdef CYGPKG_COMPRESS_ZLIB | 896 #ifdef CYGPKG_COMPRESS_ZLIB |
| 901 if (decompress) { | 897 if (decompress) { |
| 925 // Set load address/top | 921 // Set load address/top |
| 926 load_address = mem_addr; | 922 load_address = mem_addr; |
| 927 load_address_end = (unsigned long)p->out_buf; | 923 load_address_end = (unsigned long)p->out_buf; |
| 928 | 924 |
| 929 // Reload fis directory | 925 // Reload fis directory |
| 930 memcpy(fis_work_block, fis_addr, fisdir_size); | 926 flash_read(fis_addr, fis_work_block, fisdir_size, (void **)&err_addr); |
| 931 } else // dangling block | 927 } else // dangling block |
| 932 #endif | 928 #endif |
| 933 { | 929 { |
| 934 memcpy((void *)mem_addr, (void *)img->flash_base, img->data_length); | 930 flash_read((void *)img->flash_base, (void *)mem_addr, img->data_length, (void **)&err_addr); |
| 935 | 931 |
| 936 // Set load address/top | 932 // Set load address/top |
| 937 load_address = mem_addr; | 933 load_address = mem_addr; |
| 938 load_address_end = mem_addr + img->data_length; | 934 load_address_end = mem_addr + img->data_length; |
| 939 } | 935 } |
| 947 // When decompressing, leave CRC checking to decompressor | 943 // When decompressing, leave CRC checking to decompressor |
| 948 if (!decompress && img->file_cksum) { | 944 if (!decompress && img->file_cksum) { |
| 949 if (cksum != img->file_cksum) { | 945 if (cksum != img->file_cksum) { |
| 950 diag_printf("** Warning - checksum failure. stored: 0x%08lx, computed: 0x%08lx\n", | 946 diag_printf("** Warning - checksum failure. stored: 0x%08lx, computed: 0x%08lx\n", |
| 951 img->file_cksum, cksum); | 947 img->file_cksum, cksum); |
| 948 entry_address = NO_MEMORY; | |
| 952 } | 949 } |
| 953 } | 950 } |
| 954 #endif | 951 #endif |
| 955 } | 952 } |
| 956 #endif // CYGOPT_REDBOOT_FIS | 953 #endif // CYGOPT_REDBOOT_FIS |
| 1103 } | 1100 } |
| 1104 | 1101 |
| 1105 /* Get parameters from image if specified */ | 1102 /* Get parameters from image if specified */ |
| 1106 if (name) { | 1103 if (name) { |
| 1107 struct fis_image_desc *img; | 1104 struct fis_image_desc *img; |
| 1108 memcpy(fis_work_block, fis_addr, fisdir_size); | |
| 1109 if ((img = fis_lookup(name, NULL)) == (struct fis_image_desc *)0) { | 1105 if ((img = fis_lookup(name, NULL)) == (struct fis_image_desc *)0) { |
| 1110 diag_printf("No image '%s' found\n", name); | 1106 diag_printf("No image '%s' found\n", name); |
| 1111 return; | 1107 return; |
| 1112 } | 1108 } |
| 1113 | 1109 |
| 1150 return; | 1146 return; |
| 1151 } | 1147 } |
| 1152 | 1148 |
| 1153 if (name) { | 1149 if (name) { |
| 1154 struct fis_image_desc *img; | 1150 struct fis_image_desc *img; |
| 1155 memcpy(fis_work_block, fis_addr, fisdir_size); | |
| 1156 if ((img = fis_lookup(name, NULL)) == (struct fis_image_desc *)0) { | 1151 if ((img = fis_lookup(name, NULL)) == (struct fis_image_desc *)0) { |
| 1157 diag_printf("No image '%s' found\n", name); | 1152 diag_printf("No image '%s' found\n", name); |
| 1158 return; | 1153 return; |
| 1159 } | 1154 } |
| 1160 | 1155 |
| 1176 } | 1171 } |
| 1177 } | 1172 } |
| 1178 #endif | 1173 #endif |
| 1179 | 1174 |
| 1180 // This is set non-zero if the FLASH subsystem has successfully been initialized | 1175 // This is set non-zero if the FLASH subsystem has successfully been initialized |
| 1181 static int __flash_init = 0; | 1176 int __flash_init = 0; |
| 1182 | 1177 |
| 1183 void | 1178 void |
| 1184 _flash_info(void) | 1179 _flash_info(void) |
| 1185 { | 1180 { |
| 1186 if (!__flash_init) return; | 1181 if (!__flash_init) return; |
| 1187 diag_printf("FLASH: %p - %p, %d blocks of %p bytes each.\n", | 1182 diag_printf("FLASH: %p - %p, %d blocks of %p bytes each.\n", |
| 1188 flash_start, (CYG_ADDRWORD)flash_end + 1, flash_num_blocks, (void *)flash_block_size); | 1183 flash_start, (CYG_ADDRWORD)flash_end + 1, flash_num_blocks, (void *)flash_block_size); |
| 1189 } | 1184 } |
| 1190 | 1185 |
| 1191 static bool | 1186 bool |
| 1192 do_flash_init(void) | 1187 do_flash_init(void) |
| 1193 { | 1188 { |
| 1194 int stat; | 1189 int stat; |
| 1190 void *err_addr; | |
| 1195 | 1191 |
| 1196 if (!__flash_init) { | 1192 if (!__flash_init) { |
| 1197 if ((stat = flash_init((void *)(workspace_end-FLASH_MIN_WORKSPACE), | 1193 if ((stat = flash_init((void *)(workspace_end-FLASH_MIN_WORKSPACE), |
| 1198 FLASH_MIN_WORKSPACE, diag_printf)) != 0) { | 1194 FLASH_MIN_WORKSPACE, diag_printf)) != 0) { |
| 1199 diag_printf("FLASH: driver init failed: %s\n", flash_errmsg(stat)); | 1195 diag_printf("FLASH: driver init failed: %s\n", flash_errmsg(stat)); |
| 1222 (CYGNUM_REDBOOT_FIS_DIRECTORY_BLOCK*flash_block_size)); | 1218 (CYGNUM_REDBOOT_FIS_DIRECTORY_BLOCK*flash_block_size)); |
| 1223 } else { | 1219 } else { |
| 1224 fis_addr = (void *)((CYG_ADDRESS)flash_start + | 1220 fis_addr = (void *)((CYG_ADDRESS)flash_start + |
| 1225 (CYGNUM_REDBOOT_FIS_DIRECTORY_BLOCK*flash_block_size)); | 1221 (CYGNUM_REDBOOT_FIS_DIRECTORY_BLOCK*flash_block_size)); |
| 1226 } | 1222 } |
| 1227 memcpy(fis_work_block, fis_addr, flash_block_size); | 1223 flash_read(fis_addr, fis_work_block, fisdir_size, (void **)&err_addr); |
| 1228 #endif | 1224 #endif |
| 1229 __flash_init = 1; | 1225 __flash_init = 1; |
| 1230 } | 1226 } |
| 1231 return true; | 1227 return true; |
| 1232 } | 1228 } |
| 1261 return; | 1257 return; |
| 1262 } | 1258 } |
| 1263 fis_usage("unrecognized command"); | 1259 fis_usage("unrecognized command"); |
| 1264 } | 1260 } |
| 1265 | 1261 |
| 1266 #ifdef CYGSEM_REDBOOT_FLASH_CONFIG | |
| 1267 | |
| 1268 static bool config_ok; | |
| 1269 | |
| 1270 #define CONFIG_KEY1 0x0BADFACE | |
| 1271 #define CONFIG_KEY2 0xDEADDEAD | |
| 1272 | |
| 1273 #define CONFIG_DONE 0 | |
| 1274 #define CONFIG_ABORT -1 | |
| 1275 #define CONFIG_CHANGED 1 | |
| 1276 #define CONFIG_OK 2 | |
| 1277 #define CONFIG_BACK 3 | |
| 1278 #define CONFIG_BAD 4 | |
| 1279 | |
| 1280 // Note: the following options are related. If 'boot_script' is false, then | |
| 1281 // the other values are used in the configuration. Because of the way | |
| 1282 // that configuration tables are generated, they should have names which | |
| 1283 // are related. The configuration options will show up lexicographically | |
| 1284 // ordered, thus the peculiar naming. | |
| 1285 RedBoot_config_option("Run script at boot", | |
| 1286 boot_script, | |
| 1287 ALWAYS_ENABLED, true, | |
| 1288 CONFIG_BOOL, | |
| 1289 false | |
| 1290 ); | |
| 1291 RedBoot_config_option("Boot script", | |
| 1292 boot_script_data, | |
| 1293 "boot_script", true, | |
| 1294 CONFIG_SCRIPT, | |
| 1295 "" | |
| 1296 ); | |
| 1297 // Some preprocessor magic for building the [constant] prompt string | |
| 1298 #define __cat(s1,c2,s3) s1 #c2 s3 | |
| 1299 #define _cat(s1,c2,s3) __cat(s1,c2,s3) | |
| 1300 RedBoot_config_option(_cat("Boot script timeout (", | |
| 1301 CYGNUM_REDBOOT_BOOT_SCRIPT_TIMEOUT_RESOLUTION, | |
| 1302 "ms resolution)"), | |
| 1303 boot_script_timeout, | |
| 1304 "boot_script", true, | |
| 1305 CONFIG_INT, | |
| 1306 0 | |
| 1307 ); | |
| 1308 #undef __cat | |
| 1309 #undef _cat | |
| 1310 | |
| 1311 #ifdef CYGSEM_REDBOOT_VARIABLE_BAUD_RATE | |
| 1312 RedBoot_config_option("Console baud rate", | |
| 1313 console_baud_rate, | |
| 1314 ALWAYS_ENABLED, true, | |
| 1315 CONFIG_INT, | |
| 1316 CYGNUM_HAL_VIRTUAL_VECTOR_CONSOLE_CHANNEL_BAUD | |
| 1317 ); | |
| 1318 #endif | |
| 1319 | |
| 1320 CYG_HAL_TABLE_BEGIN( __CONFIG_options_TAB__, RedBoot_config_options); | |
| 1321 CYG_HAL_TABLE_END( __CONFIG_options_TAB_END__, RedBoot_config_options); | |
| 1322 | |
| 1323 extern struct config_option __CONFIG_options_TAB__[], __CONFIG_options_TAB_END__[]; | |
| 1324 | |
| 1325 // | |
| 1326 // Layout of config data | |
| 1327 // Each data item is variable length, with the name, type and dependencies | |
| 1328 // encoded into the object. | |
| 1329 // offset contents | |
| 1330 // 0 data type | |
| 1331 // 1 length of name (N) | |
| 1332 // 2 enable sense | |
| 1333 // 3 length of enable key (M) | |
| 1334 // 4 key name | |
| 1335 // N+4 enable key | |
| 1336 // M+N+4 data value | |
| 1337 // | |
| 1338 | |
| 1339 #define CONFIG_OBJECT_TYPE(dp) (dp)[0] | |
| 1340 #define CONFIG_OBJECT_KEYLEN(dp) (dp)[1] | |
| 1341 #define CONFIG_OBJECT_ENABLE_SENSE(dp) (dp)[2] | |
| 1342 #define CONFIG_OBJECT_ENABLE_KEYLEN(dp) (dp)[3] | |
| 1343 #define CONFIG_OBJECT_KEY(dp) ((dp)+4) | |
| 1344 #define CONFIG_OBJECT_ENABLE_KEY(dp) ((dp)+4+CONFIG_OBJECT_KEYLEN(dp)) | |
| 1345 #define CONFIG_OBJECT_VALUE(dp) ((dp)+4+CONFIG_OBJECT_KEYLEN(dp)+CONFIG_OBJECT_ENABLE_KEYLEN(dp)) | |
| 1346 | |
| 1347 #define LIST_OPT_LIST_ONLY (1) | |
| 1348 #define LIST_OPT_NICKNAMES (2) | |
| 1349 #define LIST_OPT_FULLNAMES (4) | |
| 1350 #define LIST_OPT_DUMBTERM (8) | |
| 1351 | |
| 1352 static void config_init(void); | |
| 1353 | |
| 1354 static int | |
| 1355 get_config(unsigned char *dp, char *title, int list_opt, char *newvalue ) | |
| 1356 { | |
| 1357 char line[256], hold_line[256], *sp, *lp; | |
| 1358 int ret; | |
| 1359 bool hold_bool_val, new_bool_val, enable; | |
| 1360 unsigned long hold_int_val, new_int_val; | |
| 1361 #ifdef CYGPKG_REDBOOT_NETWORKING | |
| 1362 in_addr_t hold_ip_val, new_ip_val; | |
| 1363 enet_addr_t hold_esa_val; | |
| 1364 int esa_ptr; | |
| 1365 char *esp; | |
| 1366 #endif | |
| 1367 void *val_ptr; | |
| 1368 int type; | |
| 1369 | |
| 1370 if (CONFIG_OBJECT_ENABLE_KEYLEN(dp)) { | |
| 1371 flash_get_config(CONFIG_OBJECT_ENABLE_KEY(dp), &enable, CONFIG_BOOL); | |
| 1372 if (((bool)CONFIG_OBJECT_ENABLE_SENSE(dp) && !enable) || | |
| 1373 (!(bool)CONFIG_OBJECT_ENABLE_SENSE(dp) && enable)) { | |
| 1374 return CONFIG_OK; // Disabled field | |
| 1375 } | |
| 1376 } | |
| 1377 lp = line; *lp = '\0'; | |
| 1378 val_ptr = (void *)CONFIG_OBJECT_VALUE(dp); | |
| 1379 if (LIST_OPT_NICKNAMES & list_opt) | |
| 1380 diag_printf("%s: ", CONFIG_OBJECT_KEY(dp)); | |
| 1381 if (LIST_OPT_FULLNAMES & list_opt) { | |
| 1382 if (title != (char *)NULL) { | |
| 1383 diag_printf("%s: ", title); | |
| 1384 } else { | |
| 1385 diag_printf("%s: ", CONFIG_OBJECT_KEY(dp)); | |
| 1386 } | |
| 1387 } | |
| 1388 switch (type = CONFIG_OBJECT_TYPE(dp)) { | |
| 1389 case CONFIG_BOOL: | |
| 1390 memcpy(&hold_bool_val, val_ptr, sizeof(bool)); | |
| 1391 lp += diag_sprintf(lp, "%s", hold_bool_val ? "true" : "false"); | |
| 1392 break; | |
| 1393 case CONFIG_INT: | |
| 1394 memcpy(&hold_int_val, val_ptr, sizeof(unsigned long)); | |
| 1395 lp += diag_sprintf(lp, "%ld", hold_int_val); | |
| 1396 break; | |
| 1397 #ifdef CYGPKG_REDBOOT_NETWORKING | |
| 1398 case CONFIG_IP: | |
| 1399 lp += diag_sprintf(lp, "%s", inet_ntoa((in_addr_t *)val_ptr)); | |
| 1400 if (0 == strcmp("0.0.0.0", line) && !(LIST_OPT_LIST_ONLY & list_opt)) { | |
| 1401 // then we have a deeply unhelpful starting text - kill it off | |
| 1402 // (unless we are just listing all values) | |
| 1403 lp = line; *lp = '\0'; | |
| 1404 } | |
| 1405 break; | |
| 1406 case CONFIG_ESA: | |
| 1407 for (esa_ptr = 0; esa_ptr < sizeof(enet_addr_t); esa_ptr++) { | |
| 1408 lp += diag_sprintf(lp, "0x%02X", ((unsigned char *)val_ptr)[esa_ptr]); | |
| 1409 if (esa_ptr < (sizeof(enet_addr_t)-1)) lp += diag_sprintf(lp, ":"); | |
| 1410 } | |
| 1411 break; | |
| 1412 #if defined(CYGHWR_NET_DRIVERS) && (CYGHWR_NET_DRIVERS > 1) | |
| 1413 case CONFIG_NETPORT: | |
| 1414 lp += diag_sprintf(lp, "%s", (unsigned char *)val_ptr); | |
| 1415 break; | |
| 1416 #endif | |
| 1417 #endif | |
| 1418 case CONFIG_STRING: | |
| 1419 lp += diag_sprintf(lp, "%s", (unsigned char *)val_ptr); | |
| 1420 break; | |
| 1421 case CONFIG_SCRIPT: | |
| 1422 diag_printf("\n"); | |
| 1423 sp = lp = (unsigned char *)val_ptr; | |
| 1424 while (*sp) { | |
| 1425 while (*lp != '\n') lp++; | |
| 1426 *lp = '\0'; | |
| 1427 diag_printf(".. %s\n", sp); | |
| 1428 *lp++ = '\n'; | |
| 1429 sp = lp; | |
| 1430 } | |
| 1431 break; | |
| 1432 } | |
| 1433 if (LIST_OPT_LIST_ONLY & list_opt) { | |
| 1434 diag_printf("%s\n", line); | |
| 1435 return CONFIG_OK; | |
| 1436 } | |
| 1437 if (type != CONFIG_SCRIPT) { | |
| 1438 if (NULL != newvalue) { | |
| 1439 ret = strlen(newvalue); | |
| 1440 if (ret > sizeof(line)) | |
| 1441 return CONFIG_BAD; | |
| 1442 strcpy(hold_line, line); // Hold the old value for comparison | |
| 1443 strcpy(line, newvalue); | |
| 1444 diag_printf("Setting to %s\n", newvalue); | |
| 1445 } else { | |
| 1446 // read from terminal | |
| 1447 strcpy(hold_line, line); | |
| 1448 if (LIST_OPT_DUMBTERM & list_opt) { | |
| 1449 diag_printf( (CONFIG_STRING == type ? | |
| 1450 "%s > " : | |
| 1451 "%s ? " ), line); | |
| 1452 *line = '\0'; | |
| 1453 } | |
| 1454 ret = _rb_gets_preloaded(line, sizeof(line), 0); | |
| 1455 } | |
| 1456 if (ret < 0) return CONFIG_ABORT; | |
| 1457 // empty input - leave value untouched (else DNS goes away for a | |
| 1458 // minute to try to look it up) but we must accept empty value for strings. | |
| 1459 if (0 == line[0] && CONFIG_STRING != type) return CONFIG_OK; | |
| 1460 if (strcmp(line, hold_line) == 0) return CONFIG_OK; // Just a CR - leave value untouched | |
| 1461 lp = &line[strlen(line)-1]; | |
| 1462 if (*lp == '.') return CONFIG_DONE; | |
| 1463 if (*lp == '^') return CONFIG_BACK; | |
| 1464 } | |
| 1465 switch (type) { | |
| 1466 case CONFIG_BOOL: | |
| 1467 memcpy(&hold_bool_val, val_ptr, sizeof(bool)); | |
| 1468 if (!parse_bool(line, &new_bool_val)) { | |
| 1469 return CONFIG_BAD; | |
| 1470 } | |
| 1471 if (hold_bool_val != new_bool_val) { | |
| 1472 memcpy(val_ptr, &new_bool_val, sizeof(bool)); | |
| 1473 return CONFIG_CHANGED; | |
| 1474 } else { | |
| 1475 return CONFIG_OK; | |
| 1476 } | |
| 1477 break; | |
| 1478 case CONFIG_INT: | |
| 1479 memcpy(&hold_int_val, val_ptr, sizeof(unsigned long)); | |
| 1480 if (!parse_num(line, &new_int_val, 0, 0)) { | |
| 1481 return CONFIG_BAD; | |
| 1482 } | |
| 1483 if (hold_int_val != new_int_val) { | |
| 1484 memcpy(val_ptr, &new_int_val, sizeof(unsigned long)); | |
| 1485 return CONFIG_CHANGED; | |
| 1486 } else { | |
| 1487 return CONFIG_OK; | |
| 1488 } | |
| 1489 break; | |
| 1490 #ifdef CYGPKG_REDBOOT_NETWORKING | |
| 1491 case CONFIG_IP: | |
| 1492 memcpy(&hold_ip_val.s_addr, &((in_addr_t *)val_ptr)->s_addr, sizeof(in_addr_t)); | |
| 1493 if (!_gethostbyname(line, &new_ip_val)) { | |
| 1494 return CONFIG_BAD; | |
| 1495 } | |
| 1496 if (hold_ip_val.s_addr != new_ip_val.s_addr) { | |
| 1497 memcpy(val_ptr, &new_ip_val, sizeof(in_addr_t)); | |
| 1498 return CONFIG_CHANGED; | |
| 1499 } else { | |
| 1500 return CONFIG_OK; | |
| 1501 } | |
| 1502 break; | |
| 1503 case CONFIG_ESA: | |
| 1504 memcpy(&hold_esa_val, val_ptr, sizeof(enet_addr_t)); | |
| 1505 esp = line; | |
| 1506 for (esa_ptr = 0; esa_ptr < sizeof(enet_addr_t); esa_ptr++) { | |
| 1507 unsigned long esa_byte; | |
| 1508 if (!parse_num(esp, &esa_byte, &esp, ":")) { | |
| 1509 memcpy(val_ptr, &hold_esa_val, sizeof(enet_addr_t)); | |
| 1510 return CONFIG_BAD; | |
| 1511 } | |
| 1512 ((unsigned char *)val_ptr)[esa_ptr] = esa_byte; | |
| 1513 } | |
| 1514 return CONFIG_CHANGED; | |
| 1515 break; | |
| 1516 #if defined(CYGHWR_NET_DRIVERS) && (CYGHWR_NET_DRIVERS > 1) | |
| 1517 case CONFIG_NETPORT: | |
| 1518 if (strlen(line) >= MAX_STRING_LENGTH || net_devindex(line) < 0) { | |
| 1519 int index; | |
| 1520 const char *name; | |
| 1521 diag_printf("Sorry, Port name must be one of:\n"); | |
| 1522 for (index = 0; (name = net_devname(index)) != NULL; index++) | |
| 1523 diag_printf(" %s\n", name); | |
| 1524 return CONFIG_BAD; | |
| 1525 } | |
| 1526 strcpy((unsigned char *)val_ptr, line); | |
| 1527 break; | |
| 1528 #endif | |
| 1529 #endif | |
| 1530 case CONFIG_SCRIPT: | |
| 1531 // Assume it always changes | |
| 1532 sp = (unsigned char *)val_ptr; | |
| 1533 diag_printf("Enter script, terminate with empty line\n"); | |
| 1534 while (true) { | |
| 1535 *sp = '\0'; | |
| 1536 diag_printf(">> "); | |
| 1537 ret = _rb_gets(line, sizeof(line), 0); | |
| 1538 if (ret < 0) return CONFIG_ABORT; | |
| 1539 if (strlen(line) == 0) break; | |
| 1540 lp = line; | |
| 1541 while (*lp) { | |
| 1542 *sp++ = *lp++; | |
| 1543 } | |
| 1544 *sp++ = '\n'; | |
| 1545 } | |
| 1546 break; | |
| 1547 case CONFIG_STRING: | |
| 1548 if (strlen(line) >= MAX_STRING_LENGTH) { | |
| 1549 diag_printf("Sorry, value is too long\n"); | |
| 1550 return CONFIG_BAD; | |
| 1551 } | |
| 1552 strcpy((unsigned char *)val_ptr, line); | |
| 1553 break; | |
| 1554 } | |
| 1555 return CONFIG_CHANGED; | |
| 1556 } | |
| 1557 | |
| 1558 // | |
| 1559 // Manage configuration information with the FLASH | |
| 1560 // | |
| 1561 | |
| 1562 static int | |
| 1563 config_length(int type) | |
| 1564 { | |
| 1565 switch (type) { | |
| 1566 case CONFIG_BOOL: | |
| 1567 return sizeof(bool); | |
| 1568 case CONFIG_INT: | |
| 1569 return sizeof(unsigned long); | |
| 1570 #ifdef CYGPKG_REDBOOT_NETWORKING | |
| 1571 case CONFIG_IP: | |
| 1572 return sizeof(in_addr_t); | |
| 1573 case CONFIG_ESA: | |
| 1574 // Would like this to be sizeof(enet_addr_t), but that causes much | |
| 1575 // pain since it fouls the alignment of data which follows. | |
| 1576 return 8; | |
| 1577 #if defined(CYGHWR_NET_DRIVERS) && (CYGHWR_NET_DRIVERS > 1) | |
| 1578 case CONFIG_NETPORT: | |
| 1579 return MAX_STRING_LENGTH; | |
| 1580 #endif | |
| 1581 #endif | |
| 1582 case CONFIG_STRING: | |
| 1583 return MAX_STRING_LENGTH; | |
| 1584 case CONFIG_SCRIPT: | |
| 1585 return MAX_SCRIPT_LENGTH; | |
| 1586 default: | |
| 1587 return 0; | |
| 1588 } | |
| 1589 } | |
| 1590 | |
| 1591 static cmd_fun do_flash_config; | |
| 1592 RedBoot_cmd("fconfig", | |
| 1593 "Manage configuration kept in FLASH memory", | |
| 1594 "[-i] [-l] [-n] [-f] [-d] | [-d] nickname [value]", | |
| 1595 do_flash_config | |
| 1596 ); | |
| 1597 | |
| 1598 static void | |
| 1599 do_flash_config(int argc, char *argv[]) | |
| 1600 { | |
| 1601 bool need_update = false; | |
| 1602 struct config_option *optend = __CONFIG_options_TAB_END__; | |
| 1603 struct config_option *opt = __CONFIG_options_TAB__; | |
| 1604 struct option_info opts[5]; | |
| 1605 bool list_only; | |
| 1606 bool nicknames; | |
| 1607 bool fullnames; | |
| 1608 bool dumbterminal; | |
| 1609 int list_opt = 0; | |
| 1610 unsigned char *dp; | |
| 1611 int len, ret; | |
| 1612 char *title; | |
| 1613 char *onlyone = NULL; | |
| 1614 char *onevalue = NULL; | |
| 1615 bool doneone = false; | |
| 1616 bool init = false; | |
| 1617 | |
| 1618 if (!__flash_init) { | |
| 1619 diag_printf("Sorry, no FLASH memory is available\n"); | |
| 1620 return; | |
| 1621 } | |
| 1622 memcpy(backup_config, config, sizeof(struct _config)); | |
| 1623 script = (unsigned char *)0; | |
| 1624 | |
| 1625 init_opts(&opts[0], 'l', false, OPTION_ARG_TYPE_FLG, | |
| 1626 (void **)&list_only, (bool *)0, "list configuration only"); | |
| 1627 init_opts(&opts[1], 'n', false, OPTION_ARG_TYPE_FLG, | |
| 1628 (void **)&nicknames, (bool *)0, "show nicknames"); | |
| 1629 init_opts(&opts[2], 'f', false, OPTION_ARG_TYPE_FLG, | |
| 1630 (void **)&fullnames, (bool *)0, "show full names"); | |
| 1631 init_opts(&opts[3], 'i', false, OPTION_ARG_TYPE_FLG, | |
| 1632 (void **)&init, (bool *)0, "initialize configuration database"); | |
| 1633 init_opts(&opts[4], 'd', false, OPTION_ARG_TYPE_FLG, | |
| 1634 (void **)&dumbterminal, (bool *)0, "dumb terminal: no clever edits"); | |
| 1635 | |
| 1636 // First look to see if we are setting or getting a single option | |
| 1637 // by just quoting its nickname | |
| 1638 if ( (2 == argc && '-' != argv[1][0]) || | |
| 1639 (3 == argc && '-' != argv[1][0] && '-' != argv[2][0])) { | |
| 1640 // then the command was "fconfig foo [value]" | |
| 1641 onlyone = argv[1]; | |
| 1642 onevalue = (3 == argc) ? argv[2] : NULL; | |
| 1643 list_opt = LIST_OPT_NICKNAMES; | |
| 1644 } | |
| 1645 // Next see if we are setting or getting a single option with a dumb | |
| 1646 // terminal invoked, ie. no line editing. | |
| 1647 else if (3 == argc && | |
| 1648 '-' == argv[1][0] && 'd' == argv[1][1] && 0 == argv[1][2] && | |
| 1649 '-' != argv[2][0]) { | |
| 1650 // then the command was "fconfig -d foo" | |
| 1651 onlyone = argv[2]; | |
| 1652 onevalue = NULL; | |
| 1653 list_opt = LIST_OPT_NICKNAMES | LIST_OPT_DUMBTERM; | |
| 1654 } | |
| 1655 else { | |
| 1656 if (!scan_opts(argc, argv, 1, opts, 5, 0, 0, "")) | |
| 1657 return; | |
| 1658 list_opt |= list_only ? LIST_OPT_LIST_ONLY : 0; | |
| 1659 list_opt |= nicknames ? LIST_OPT_NICKNAMES : LIST_OPT_FULLNAMES; | |
| 1660 list_opt |= fullnames ? LIST_OPT_FULLNAMES : 0; | |
| 1661 list_opt |= dumbterminal ? LIST_OPT_DUMBTERM : 0; | |
| 1662 } | |
| 1663 | |
| 1664 if (init && verify_action("Initialize non-volatile configuration")) { | |
| 1665 config_init(); | |
| 1666 need_update = true; | |
| 1667 } | |
| 1668 | |
| 1669 dp = &config->config_data[0]; | |
| 1670 while (dp < &config->config_data[sizeof(config->config_data)]) { | |
| 1671 if (CONFIG_OBJECT_TYPE(dp) == CONFIG_EMPTY) { | |
| 1672 break; | |
| 1673 } | |
| 1674 len = 4 + CONFIG_OBJECT_KEYLEN(dp) + CONFIG_OBJECT_ENABLE_KEYLEN(dp) + | |
| 1675 config_length(CONFIG_OBJECT_TYPE(dp)); | |
| 1676 // Provide a title for well known [i.e. builtin] objects | |
| 1677 title = (char *)NULL; | |
| 1678 opt = __CONFIG_options_TAB__; | |
| 1679 while (opt != optend) { | |
| 1680 if (strcmp(opt->key, CONFIG_OBJECT_KEY(dp)) == 0) { | |
| 1681 title = opt->title; | |
| 1682 break; | |
| 1683 } | |
| 1684 opt++; | |
| 1685 } | |
| 1686 if ( onlyone && 0 != strcmp(CONFIG_OBJECT_KEY(dp), onlyone) ) | |
| 1687 ret = CONFIG_OK; // skip this entry | |
| 1688 else { | |
| 1689 doneone = true; | |
| 1690 ret = get_config(dp, title, list_opt, onevalue); // do this opt | |
| 1691 } | |
| 1692 switch (ret) { | |
| 1693 case CONFIG_DONE: | |
| 1694 goto done; | |
| 1695 case CONFIG_ABORT: | |
| 1696 memcpy(config, backup_config, sizeof(struct _config)); | |
| 1697 return; | |
| 1698 case CONFIG_CHANGED: | |
| 1699 need_update = true; | |
| 1700 case CONFIG_OK: | |
| 1701 dp += len; | |
| 1702 break; | |
| 1703 case CONFIG_BACK: | |
| 1704 dp = &config->config_data[0]; | |
| 1705 continue; | |
| 1706 case CONFIG_BAD: | |
| 1707 // Nothing - make him do it again | |
| 1708 diag_printf ("** invalid entry\n"); | |
| 1709 onevalue = NULL; // request a good value be typed in - or abort/whatever | |
| 1710 } | |
| 1711 } | |
| 1712 | |
| 1713 done: | |
| 1714 if (NULL != onlyone && !doneone) { | |
| 1715 #ifdef CYGSEM_REDBOOT_ALLOW_DYNAMIC_FLASH_CONFIG_DATA | |
| 1716 if (verify_action("** entry '%s' not found - add", onlyone)) { | |
| 1717 struct config_option opt; | |
| 1718 diag_printf("Trying to add value\n"); | |
| 1719 } | |
| 1720 #else | |
| 1721 diag_printf("** entry '%s' not found", onlyone); | |
| 1722 #endif | |
| 1723 } | |
| 1724 if (!need_update) | |
| 1725 return; | |
| 1726 flash_write_config(); | |
| 1727 } | |
| 1728 | |
| 1729 | |
| 1730 #ifdef CYGSEM_REDBOOT_FLASH_ALIASES | |
| 1731 static cmd_fun do_alias; | |
| 1732 RedBoot_cmd("alias", | |
| 1733 "Manage aliases kept in FLASH memory", | |
| 1734 "name [value]", | |
| 1735 do_alias | |
| 1736 ); | |
| 1737 | |
| 1738 static void | |
| 1739 make_alias(char *alias, char *name) | |
| 1740 { | |
| 1741 diag_sprintf(alias, "alias/%s", name); | |
| 1742 } | |
| 1743 | |
| 1744 static void | |
| 1745 do_alias(int argc, char *argv[]) | |
| 1746 { | |
| 1747 char name[80]; | |
| 1748 char *val; | |
| 1749 struct config_option opt; | |
| 1750 | |
| 1751 switch (argc) { | |
| 1752 case 2: | |
| 1753 make_alias(name, argv[1]); | |
| 1754 if (flash_get_config(name, &val, CONFIG_STRING)) { | |
| 1755 diag_printf("'%s' = '%s'\n", argv[1], val); | |
| 1756 } else { | |
| 1757 diag_printf("'%s' not found\n", argv[1]); | |
| 1758 } | |
| 1759 break; | |
| 1760 case 3: | |
| 1761 if (strlen(argv[2]) >= MAX_STRING_LENGTH) { | |
| 1762 diag_printf("Sorry, value is too long\n"); | |
| 1763 break; | |
| 1764 } | |
| 1765 make_alias(name, argv[1]); | |
| 1766 opt.type = CONFIG_STRING; | |
| 1767 opt.enable = (char *)0; | |
| 1768 opt.enable_sense = 1; | |
| 1769 opt.key = name; | |
| 1770 opt.dflt = (CYG_ADDRESS)argv[2]; | |
| 1771 flash_add_config(&opt, true); | |
| 1772 break; | |
| 1773 default: | |
| 1774 diag_printf("usage: alias name [value]\n"); | |
| 1775 } | |
| 1776 } | |
| 1777 | |
| 1778 // Lookup an alias. First try plain string aliases. If that fails try | |
| 1779 // other types so allowing access to all configured values. This allows | |
| 1780 // for alias (macro) expansion of normal 'fconfig' data, such as the | |
| 1781 // board IP address. | |
| 1782 char * | |
| 1783 flash_lookup_alias(char *alias, char *alias_buf) | |
| 1784 { | |
| 1785 char name[80]; | |
| 1786 char *val; | |
| 1787 unsigned char * dp; | |
| 1788 void *val_ptr; | |
| 1789 int type; | |
| 1790 bool hold_bool_val; | |
| 1791 long hold_long_val; | |
| 1792 #ifdef CYGPKG_REDBOOT_NETWORKING | |
| 1793 int esa_ptr; | |
| 1794 #endif | |
| 1795 | |
| 1796 make_alias(name, alias); | |
| 1797 if (flash_get_config(name, &val, CONFIG_STRING)) { | |
| 1798 return val; | |
| 1799 } else { | |
| 1800 dp = flash_lookup_config(alias); | |
| 1801 if (dp) { | |
| 1802 val_ptr = (void *)CONFIG_OBJECT_VALUE(dp); | |
| 1803 switch (type = CONFIG_OBJECT_TYPE(dp)) { | |
| 1804 case CONFIG_BOOL: | |
| 1805 memcpy(&hold_bool_val, val_ptr, sizeof(bool)); | |
| 1806 diag_sprintf(alias_buf, "%s", hold_bool_val ? "true" : "false"); | |
| 1807 break; | |
| 1808 case CONFIG_INT: | |
| 1809 memcpy(&hold_long_val, val_ptr, sizeof(unsigned long)); | |
| 1810 diag_sprintf(alias_buf,"%ld", hold_long_val); | |
| 1811 break; | |
| 1812 #ifdef CYGPKG_REDBOOT_NETWORKING | |
| 1813 case CONFIG_IP: | |
| 1814 diag_sprintf(alias_buf,"%s", inet_ntoa((in_addr_t *)val_ptr)); | |
| 1815 break; | |
| 1816 case CONFIG_ESA: | |
| 1817 for (esa_ptr = 0; esa_ptr < sizeof(enet_addr_t); esa_ptr++) { | |
| 1818 diag_sprintf(alias_buf+(3*esa_ptr), "0x%02X", ((unsigned char *)val_ptr)[esa_ptr]); | |
| 1819 if (esa_ptr < (sizeof(enet_addr_t)-1)) diag_printf(":"); | |
| 1820 } | |
| 1821 break; | |
| 1822 #endif | |
| 1823 case CONFIG_SCRIPT: | |
| 1824 return (char *) val_ptr; | |
| 1825 break; | |
| 1826 default: | |
| 1827 return (char *)NULL; | |
| 1828 } | |
| 1829 return alias_buf; | |
| 1830 } | |
| 1831 return (char *)NULL; | |
| 1832 } | |
| 1833 } | |
| 1834 | |
| 1835 #endif // CYGSEM_REDBOOT_FLASH_ALIASES | |
| 1836 | |
| 1837 // | |
| 1838 // Write the in-memory copy of the configuration data to the flash device. | |
| 1839 // | |
| 1840 void | |
| 1841 flash_write_config(void) | |
| 1842 { | |
| 1843 #ifndef CYGSEM_REDBOOT_FLASH_COMBINED_FIS_AND_CONFIG | |
| 1844 int stat; | |
| 1845 void *err_addr; | |
| 1846 #endif | |
| 1847 | |
| 1848 config->len = sizeof(struct _config); | |
| 1849 config->key1 = CONFIG_KEY1; | |
| 1850 config->key2 = CONFIG_KEY2; | |
| 1851 config->cksum = cyg_crc32((unsigned char *)config, sizeof(struct _config)-sizeof(config->cksum)); | |
| 1852 if (verify_action("Update RedBoot non-volatile configuration")) { | |
| 1853 #ifdef CYGSEM_REDBOOT_FLASH_COMBINED_FIS_AND_CONFIG | |
| 1854 memcpy(fis_work_block, fis_addr, fisdir_size); | |
| 1855 fis_update_directory(); | |
| 1856 #else // CYGSEM_REDBOOT_FLASH_COMBINED_FIS_AND_CONFIG | |
| 1857 #ifdef CYGSEM_REDBOOT_FLASH_LOCK_SPECIAL | |
| 1858 // Insure [quietly] that the config page is unlocked before trying to update | |
| 1859 flash_unlock((void *)cfg_base, cfg_size, (void **)&err_addr); | |
| 1860 #endif | |
| 1861 if ((stat = flash_erase(cfg_base, cfg_size, (void **)&err_addr)) != 0) { | |
| 1862 diag_printf(" initialization failed at %p: %s\n", err_addr, flash_errmsg(stat)); | |
| 1863 } else { | |
| 1864 if ((stat = flash_program(cfg_base, (void *)config, sizeof(struct _config), | |
| 1865 (void **)&err_addr)) != 0) { | |
| 1866 diag_printf("Error writing config data at %p: %s\n", | |
| 1867 err_addr, flash_errmsg(stat)); | |
| 1868 } | |
| 1869 } | |
| 1870 #ifdef CYGSEM_REDBOOT_FLASH_LOCK_SPECIAL | |
| 1871 // Insure [quietly] that the config data is locked after the update | |
| 1872 flash_lock((void *)cfg_base, cfg_size, (void **)&err_addr); | |
| 1873 #endif | |
| 1874 #endif | |
| 1875 } | |
| 1876 } | |
| 1877 | |
| 1878 // | |
| 1879 // Find the configuration entry for a particular key | |
| 1880 // | |
| 1881 static unsigned char * | |
| 1882 flash_lookup_config(char *key) | |
| 1883 { | |
| 1884 unsigned char *dp; | |
| 1885 int len; | |
| 1886 | |
| 1887 if (!config_ok) return (unsigned char *)NULL; | |
| 1888 | |
| 1889 dp = &config->config_data[0]; | |
| 1890 while (dp < &config->config_data[sizeof(config->config_data)]) { | |
| 1891 len = 4 + CONFIG_OBJECT_KEYLEN(dp) + CONFIG_OBJECT_ENABLE_KEYLEN(dp) + | |
| 1892 config_length(CONFIG_OBJECT_TYPE(dp)); | |
| 1893 if (strcmp(key, CONFIG_OBJECT_KEY(dp)) == 0) { | |
| 1894 return dp; | |
| 1895 } | |
| 1896 dp += len; | |
| 1897 } | |
| 1898 // diag_printf("Can't find config data for '%s'\n", key); | |
| 1899 return false; | |
| 1900 } | |
| 1901 | |
| 1902 // | |
| 1903 // Retrieve a data object from the data base (in memory copy) | |
| 1904 // | |
| 1905 bool | |
| 1906 flash_get_config(char *key, void *val, int type) | |
| 1907 { | |
| 1908 unsigned char *dp; | |
| 1909 void *val_ptr; | |
| 1910 #ifdef CYGSEM_REDBOOT_FLASH_CONFIG_READONLY_FALLBACK | |
| 1911 struct _config *save_config = 0; | |
| 1912 #endif | |
| 1913 | |
| 1914 if (!config_ok) return false; | |
| 1915 | |
| 1916 if ((dp = flash_lookup_config(key)) != (unsigned char *)NULL) { | |
| 1917 if (CONFIG_OBJECT_TYPE(dp) == type) { | |
| 1918 val_ptr = (void *)CONFIG_OBJECT_VALUE(dp); | |
| 1919 switch (type) { | |
| 1920 // Note: the data may be unaligned in the configuration data | |
| 1921 case CONFIG_BOOL: | |
| 1922 memcpy(val, val_ptr, sizeof(bool)); | |
| 1923 break; | |
| 1924 case CONFIG_INT: | |
| 1925 memcpy(val, val_ptr, sizeof(unsigned long)); | |
| 1926 break; | |
| 1927 #ifdef CYGPKG_REDBOOT_NETWORKING | |
| 1928 case CONFIG_IP: | |
| 1929 memcpy(val, val_ptr, sizeof(in_addr_t)); | |
| 1930 break; | |
| 1931 case CONFIG_ESA: | |
| 1932 memcpy(val, val_ptr, sizeof(enet_addr_t)); | |
| 1933 break; | |
| 1934 #endif | |
| 1935 #if defined(CYGHWR_NET_DRIVERS) && (CYGHWR_NET_DRIVERS > 1) | |
| 1936 case CONFIG_NETPORT: | |
| 1937 #endif | |
| 1938 case CONFIG_STRING: | |
| 1939 case CONFIG_SCRIPT: | |
| 1940 // Just return a pointer to the script/line | |
| 1941 *(unsigned char **)val = (unsigned char *)val_ptr; | |
| 1942 break; | |
| 1943 } | |
| 1944 } else { | |
| 1945 diag_printf("Request for config value '%s' - wrong type\n", key); | |
| 1946 } | |
| 1947 return true; | |
| 1948 } | |
| 1949 #ifdef CYGSEM_REDBOOT_FLASH_CONFIG_READONLY_FALLBACK | |
| 1950 // Did not find key. Is configuration data valid? | |
| 1951 // Check to see if the config data is valid, if not, revert to | |
| 1952 // readonly mode, by setting config to readonly_config. We | |
| 1953 // will set it back before we leave this function. | |
| 1954 if ( (config != readonly_config) && ((cyg_crc32((unsigned char *)config, | |
| 1955 sizeof(struct _config)-sizeof(config->cksum)) != config->cksum) || | |
| 1956 (config->key1 != CONFIG_KEY1)|| (config->key2 != CONFIG_KEY2))) { | |
| 1957 save_config = config; | |
| 1958 config = readonly_config; | |
| 1959 if ((cyg_crc32((unsigned char *)config, | |
| 1960 sizeof(struct _config)-sizeof(config->cksum)) != config->cksum) || | |
| 1961 (config->key1 != CONFIG_KEY1)|| (config->key2 != CONFIG_KEY2)) { | |
| 1962 diag_printf("FLASH configuration checksum error or invalid key\n"); | |
| 1963 config = save_config; | |
| 1964 return false; | |
| 1965 } | |
| 1966 else{ | |
| 1967 diag_printf("Getting config information in READONLY mode\n"); | |
| 1968 return flash_get_config(key, val, type); | |
| 1969 } | |
| 1970 } | |
| 1971 #endif | |
| 1972 return false; | |
| 1973 } | |
| 1974 | |
| 1975 // | |
| 1976 // Copy data into the config area | |
| 1977 // | |
| 1978 static void | |
| 1979 flash_config_insert_value(unsigned char *dp, struct config_option *opt) | |
| 1980 { | |
| 1981 switch (opt->type) { | |
| 1982 // Note: the data may be unaligned in the configuration data | |
| 1983 case CONFIG_BOOL: | |
| 1984 memcpy(dp, (void *)&opt->dflt, sizeof(bool)); | |
| 1985 break; | |
| 1986 case CONFIG_INT: | |
| 1987 memcpy(dp, (void *)&opt->dflt, sizeof(unsigned long)); | |
| 1988 break; | |
| 1989 #ifdef CYGPKG_REDBOOT_NETWORKING | |
| 1990 case CONFIG_IP: | |
| 1991 memcpy(dp, (void *)&opt->dflt, sizeof(in_addr_t)); | |
| 1992 break; | |
| 1993 case CONFIG_ESA: | |
| 1994 memcpy(dp, (void *)opt->dflt, sizeof(enet_addr_t)); | |
| 1995 break; | |
| 1996 #if defined(CYGHWR_NET_DRIVERS) && (CYGHWR_NET_DRIVERS > 1) | |
| 1997 case CONFIG_NETPORT: | |
| 1998 // validate dflt and if not acceptable use first port | |
| 1999 { | |
| 2000 int index; | |
| 2001 const char *name; | |
| 2002 for (index = 0; (name = net_devname(index)) != NULL; index++) | |
| 2003 if (!strcmp((char *)opt->dflt, name)) | |
| 2004 break; | |
| 2005 if (name == NULL) | |
| 2006 name = net_devname(0); | |
| 2007 memcpy(dp, name, strlen(name) + 1); | |
| 2008 } | |
| 2009 break; | |
| 2010 #endif | |
| 2011 #endif | |
| 2012 case CONFIG_STRING: | |
| 2013 memcpy(dp, (void *)opt->dflt, config_length(CONFIG_STRING)); | |
| 2014 break; | |
| 2015 case CONFIG_SCRIPT: | |
| 2016 break; | |
| 2017 } | |
| 2018 } | |
| 2019 | |
| 2020 // | |
| 2021 // Add a new option to the database | |
| 2022 // | |
| 2023 bool | |
| 2024 flash_add_config(struct config_option *opt, bool update) | |
| 2025 { | |
| 2026 unsigned char *dp, *kp; | |
| 2027 int len, elen, size; | |
| 2028 | |
| 2029 // If data item is already present, just update it | |
| 2030 // Note: only the data value can be thusly changed | |
| 2031 if ((dp = flash_lookup_config(opt->key)) != (unsigned char *)NULL) { | |
| 2032 flash_config_insert_value(CONFIG_OBJECT_VALUE(dp), opt); | |
| 2033 if (update) { | |
| 2034 flash_write_config(); | |
| 2035 } | |
| 2036 return true; | |
| 2037 } | |
| 2038 // Add the data item | |
| 2039 dp = &config->config_data[0]; | |
| 2040 size = 0; | |
| 2041 while (size < sizeof(config->config_data)) { | |
| 2042 if (CONFIG_OBJECT_TYPE(dp) == CONFIG_EMPTY) { | |
| 2043 kp = opt->key; | |
| 2044 len = strlen(kp) + 1; | |
| 2045 size += len + 2 + 2 + config_length(opt->type); | |
| 2046 if (opt->enable) { | |
| 2047 elen = strlen(opt->enable) + 1; | |
| 2048 size += elen; | |
| 2049 } else { | |
| 2050 elen = 0; | |
| 2051 } | |
| 2052 if (size > sizeof(config->config_data)) { | |
| 2053 break; | |
| 2054 } | |
| 2055 CONFIG_OBJECT_TYPE(dp) = opt->type; | |
| 2056 CONFIG_OBJECT_KEYLEN(dp) = len; | |
| 2057 CONFIG_OBJECT_ENABLE_SENSE(dp) = opt->enable_sense; | |
| 2058 CONFIG_OBJECT_ENABLE_KEYLEN(dp) = elen; | |
| 2059 dp = CONFIG_OBJECT_KEY(dp); | |
| 2060 while (*kp) *dp++ += *kp++; | |
| 2061 *dp++ = '\0'; | |
| 2062 if (elen) { | |
| 2063 kp = opt->enable; | |
| 2064 while (*kp) *dp++ += *kp++; | |
| 2065 *dp++ = '\0'; | |
| 2066 } | |
| 2067 flash_config_insert_value(dp, opt); | |
| 2068 if (update) { | |
| 2069 flash_write_config(); | |
| 2070 } | |
| 2071 return true; | |
| 2072 } else { | |
| 2073 len = 4 + CONFIG_OBJECT_KEYLEN(dp) + CONFIG_OBJECT_ENABLE_KEYLEN(dp) + | |
| 2074 config_length(CONFIG_OBJECT_TYPE(dp)); | |
| 2075 dp += len; | |
| 2076 size += len; | |
| 2077 } | |
| 2078 } | |
| 2079 diag_printf("No space to add '%s'\n", opt->key); | |
| 2080 return false; | |
| 2081 } | |
| 2082 | |
| 2083 // | |
| 2084 // Reset/initialize configuration data - used only when starting from scratch | |
| 2085 // | |
| 2086 static void | |
| 2087 config_init(void) | |
| 2088 { | |
| 2089 // Well known option strings | |
| 2090 struct config_option *optend = __CONFIG_options_TAB_END__; | |
| 2091 struct config_option *opt = __CONFIG_options_TAB__; | |
| 2092 | |
| 2093 memset(config, 0, sizeof(struct _config)); | |
| 2094 while (opt != optend) { | |
| 2095 if (!flash_add_config(opt, false)) { | |
| 2096 return; | |
| 2097 } | |
| 2098 opt++; | |
| 2099 } | |
| 2100 config_ok = true; | |
| 2101 } | |
| 2102 | |
| 2103 // | |
| 2104 // Attempt to get configuration information from the FLASH. | |
| 2105 // If available (i.e. good checksum, etc), initialize "known" | |
| 2106 // values for later use. | |
| 2107 // | |
| 2108 static void | |
| 2109 load_flash_config(void) | |
| 2110 { | |
| 2111 bool use_boot_script; | |
| 2112 | |
| 2113 config_ok = false; | |
| 2114 script = (unsigned char *)0; | |
| 2115 if (!do_flash_init()) return; | |
| 2116 config = (struct _config *)(workspace_end-sizeof(struct _config)); | |
| 2117 backup_config = (struct _config *)((CYG_ADDRESS)config-sizeof(struct _config)); | |
| 2118 workspace_end = (unsigned char *)backup_config; | |
| 2119 cfg_size = (flash_block_size > sizeof(struct _config)) ? | |
| 2120 sizeof(struct _config) : | |
| 2121 _rup(sizeof(struct _config), flash_block_size); | |
| 2122 #ifdef CYGSEM_REDBOOT_FLASH_COMBINED_FIS_AND_CONFIG | |
| 2123 cfg_size = _rup(cfg_size, sizeof(struct fis_image_desc)); | |
| 2124 if ((flash_block_size-cfg_size) < 8*sizeof(struct fis_image_desc)) { | |
| 2125 // Too bad this can't be checked at compile/build time | |
| 2126 diag_printf("Sorry, FLASH config exceeds available space in FIS directory\n"); | |
| 2127 return; | |
| 2128 } | |
| 2129 fisdir_size = flash_block_size - cfg_size; | |
| 2130 cfg_base = (void *)(((CYG_ADDRESS)fis_addr + flash_block_size) - cfg_size); | |
| 2131 #else | |
| 2132 if (CYGNUM_REDBOOT_FLASH_CONFIG_BLOCK < 0) { | |
| 2133 cfg_base = (void *)((CYG_ADDRESS)flash_end + 1 - | |
| 2134 _rup(_rup((-CYGNUM_REDBOOT_FLASH_CONFIG_BLOCK*flash_block_size), cfg_size), flash_block_size)); | |
| 2135 } else { | |
| 2136 cfg_base = (void *)((CYG_ADDRESS)flash_start + | |
| 2137 _rup(_rup((CYGNUM_REDBOOT_FLASH_CONFIG_BLOCK*flash_block_size), cfg_size), flash_block_size)); | |
| 2138 } | |
| 2139 #endif | |
| 2140 #ifdef CYGSEM_REDBOOT_FLASH_CONFIG_READONLY_FALLBACK | |
| 2141 readonly_config = cfg_base; | |
| 2142 #endif | |
| 2143 memcpy(config, cfg_base, sizeof(struct _config)); | |
| 2144 if ((cyg_crc32((unsigned char *)config, | |
| 2145 sizeof(struct _config)-sizeof(config->cksum)) != config->cksum) || | |
| 2146 (config->key1 != CONFIG_KEY1)|| (config->key2 != CONFIG_KEY2)) { | |
| 2147 diag_printf("FLASH configuration checksum error or invalid key\n"); | |
| 2148 config_init(); | |
| 2149 return; | |
| 2150 } | |
| 2151 config_ok = true; | |
| 2152 flash_get_config("boot_script", &use_boot_script, CONFIG_BOOL); | |
| 2153 if (use_boot_script) { | |
| 2154 flash_get_config("boot_script_data", &script, CONFIG_SCRIPT); | |
| 2155 flash_get_config("boot_script_timeout", &script_timeout, CONFIG_INT); | |
| 2156 } | |
| 2157 #ifdef CYGSEM_REDBOOT_VARIABLE_BAUD_RATE | |
| 2158 if (flash_get_config("console_baud_rate", &console_baud_rate, CONFIG_INT)) { | |
| 2159 extern int set_console_baud_rate(int); | |
| 2160 set_console_baud_rate(console_baud_rate); | |
| 2161 } | |
| 2162 #endif | |
| 2163 } | |
| 2164 | |
| 2165 RedBoot_init(load_flash_config, RedBoot_INIT_FIRST); | |
| 2166 | |
| 2167 #endif // CYGSEM_REDBOOT_FLASH_CONFIG | |
| 2168 | |
| 2169 // EOF flash.c | 1262 // EOF flash.c |
