Mercurial > ecos
comparison packages/redboot/current/src/flash.c @ 115:6ed91473a1cd ecos-sw-2000-08-21
Merge from eCos master repository on 2000-08-21-22:40:54-BST
| author | jlarmour |
|---|---|
| date | Fri, 25 Aug 2000 17:32:38 +0000 |
| parents | |
| children | bd1a71e3e476 |
comparison
equal
deleted
inserted
replaced
| 114:5ad2b71d525e | 115:6ed91473a1cd |
|---|---|
| 1 //========================================================================== | |
| 2 // | |
| 3 // flash.c | |
| 4 // | |
| 5 // RedBoot - FLASH memory support | |
| 6 // | |
| 7 //========================================================================== | |
| 8 //####COPYRIGHTBEGIN#### | |
| 9 // | |
| 10 // ------------------------------------------- | |
| 11 // The contents of this file are subject to the Red Hat eCos Public License | |
| 12 // Version 1.1 (the "License"); you may not use this file except in | |
| 13 // compliance with the License. You may obtain a copy of the License at | |
| 14 // http://www.redhat.com/ | |
| 15 // | |
| 16 // Software distributed under the License is distributed on an "AS IS" | |
| 17 // basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the | |
| 18 // License for the specific language governing rights and limitations under | |
| 19 // the License. | |
| 20 // | |
| 21 // The Original Code is eCos - Embedded Configurable Operating System, | |
| 22 // released September 30, 1998. | |
| 23 // | |
| 24 // The Initial Developer of the Original Code is Red Hat. | |
| 25 // Portions created by Red Hat are | |
| 26 // Copyright (C) 1998, 1999, 2000 Red Hat, Inc. | |
| 27 // All Rights Reserved. | |
| 28 // ------------------------------------------- | |
| 29 // | |
| 30 //####COPYRIGHTEND#### | |
| 31 //========================================================================== | |
| 32 //#####DESCRIPTIONBEGIN#### | |
| 33 // | |
| 34 // Author(s): gthomas | |
| 35 // Contributors: gthomas | |
| 36 // Date: 2000-07-28 | |
| 37 // Purpose: | |
| 38 // Description: | |
| 39 // | |
| 40 // This code is part of RedBoot (tm). | |
| 41 // | |
| 42 //####DESCRIPTIONEND#### | |
| 43 // | |
| 44 //========================================================================== | |
| 45 | |
| 46 #include <redboot.h> | |
| 47 #include <cyg/io/flash.h> | |
| 48 | |
| 49 struct image_desc { | |
| 50 unsigned char name[16]; // Null terminated name | |
| 51 unsigned long flash_base; // Address within FLASH of image | |
| 52 unsigned long mem_base; // Address in memory where it executes | |
| 53 unsigned long size; // Length of image | |
| 54 unsigned long entry_point; // Execution entry point | |
| 55 unsigned char _pad[256-40]; | |
| 56 unsigned long desc_cksum; // Checksum over image descriptor | |
| 57 unsigned long file_cksum; // Checksum over image data | |
| 58 }; | |
| 59 | |
| 60 // Exported CLI functions | |
| 61 RedBoot_cmd("fis", | |
| 62 "Manage FLASH images", | |
| 63 "{cmds}", | |
| 64 do_fis | |
| 65 ); | |
| 66 RedBoot_cmd("fconfig", | |
| 67 "Manage configuration kept in FLASH memory", | |
| 68 "", | |
| 69 do_flash_config | |
| 70 ); | |
| 71 | |
| 72 // Internal commands | |
| 73 local_cmd_entry("init", | |
| 74 "Initialize FLASH Image System [FIS]", | |
| 75 "", | |
| 76 fis_init, | |
| 77 FIS_cmds | |
| 78 ); | |
| 79 local_cmd_entry("list", | |
| 80 "Display contents of FLASH Image System [FIS]", | |
| 81 "", | |
| 82 fis_list, | |
| 83 FIS_cmds | |
| 84 ); | |
| 85 local_cmd_entry("free", | |
| 86 "Display free [available] locations within FLASH Image System [FIS]", | |
| 87 "", | |
| 88 fis_free, | |
| 89 FIS_cmds | |
| 90 ); | |
| 91 local_cmd_entry("erase", | |
| 92 "Erase FLASH contents", | |
| 93 "-f <flash_addr> -l <length>", | |
| 94 fis_erase, | |
| 95 FIS_cmds | |
| 96 ); | |
| 97 local_cmd_entry("delete", | |
| 98 "Display an image from FLASH Image System [FIS]", | |
| 99 "name", | |
| 100 fis_delete, | |
| 101 FIS_cmds | |
| 102 ); | |
| 103 local_cmd_entry("load", | |
| 104 "Load image from FLASH Image System [FIS] into RAM", | |
| 105 "name", | |
| 106 fis_load, | |
| 107 FIS_cmds | |
| 108 ); | |
| 109 local_cmd_entry("create", | |
| 110 "Create an image", | |
| 111 "-b <mem_base> -l <length> [-f <flash_addr>] [-e <entry_point>] [-r <ram_addr>] <name>", | |
| 112 fis_create, | |
| 113 FIS_cmds | |
| 114 ); | |
| 115 | |
| 116 // Define table boundaries | |
| 117 CYG_HAL_TABLE_BEGIN( __FIS_cmds_TAB__, FIS_cmds); | |
| 118 CYG_HAL_TABLE_END( __FIS_cmds_TAB_END__, FIS_cmds); | |
| 119 | |
| 120 extern struct cmd __FIS_cmds_TAB__[], __FIS_cmds_TAB_END__; | |
| 121 | |
| 122 // Local data used by these routines | |
| 123 static void *flash_start, *flash_end; | |
| 124 static int block_size, blocks; | |
| 125 static void *fis_work_block; | |
| 126 | |
| 127 static void | |
| 128 fis_usage(char *why) | |
| 129 { | |
| 130 printf("*** invalid 'fis' command: %s\n", why); | |
| 131 cmd_usage(__FIS_cmds_TAB__, &__FIS_cmds_TAB_END__, "fis "); | |
| 132 } | |
| 133 | |
| 134 static void | |
| 135 fis_init(int argc, char *argv[]) | |
| 136 { | |
| 137 int stat, img_count = 0; | |
| 138 struct image_desc *img; | |
| 139 void *fis_base, *err_addr; | |
| 140 #ifdef CYGSEM_REDBOOT_FLASH_CONFIG | |
| 141 void *cfg_base; | |
| 142 #endif | |
| 143 bool full_init = false; | |
| 144 | |
| 145 if (argc > 2) { | |
| 146 if (strcmp(argv[2], "-f") != 0) { | |
| 147 fis_usage("bad parameter"); | |
| 148 return; | |
| 149 } | |
| 150 full_init = true; | |
| 151 } | |
| 152 if (!verify_action("About to initialize [format] FLASH image system")) { | |
| 153 printf("** Aborted\n"); | |
| 154 return; | |
| 155 } | |
| 156 printf("*** Initialize FLASH Image System\n"); | |
| 157 if (full_init) { | |
| 158 if ((stat = flash_erase((void *)((unsigned long)flash_start+(2*block_size)), | |
| 159 (blocks-4)*block_size, (void **)&err_addr)) != 0) { | |
| 160 printf(" initialization failed %p: %x(%s)\n", err_addr, stat, flash_errmsg(stat)); | |
| 161 } | |
| 162 } else { | |
| 163 printf(" Warning: device contents not erased, some blocks may not be usable\n"); | |
| 164 } | |
| 165 // Create a pseudo image for RedBoot | |
| 166 img = (struct image_desc *)fis_work_block; | |
| 167 memset(img, 0, sizeof(*img)); | |
| 168 strcpy(img->name, "RedBoot"); | |
| 169 img->flash_base = (unsigned long)flash_start; | |
| 170 img->mem_base = (unsigned long)flash_start; | |
| 171 img->size = 0; | |
| 172 img++; img_count++; | |
| 173 // And a backup image | |
| 174 memset(img, 0, sizeof(*img)); | |
| 175 strcpy(img->name, "RedBoot[backup]"); | |
| 176 img->flash_base = (unsigned long)flash_start+block_size; | |
| 177 img->mem_base = (unsigned long)flash_start+block_size; | |
| 178 img->size = 0; | |
| 179 img++; img_count++; | |
| 180 #ifdef CYGSEM_REDBOOT_FLASH_CONFIG | |
| 181 // And a descriptor for the configuration data | |
| 182 memset(img, 0, sizeof(*img)); | |
| 183 strcpy(img->name, "RedBoot config"); | |
| 184 cfg_base = (void *)((unsigned long)flash_end - (2*block_size)); | |
| 185 img->flash_base = (unsigned long)cfg_base; | |
| 186 img->mem_base = (unsigned long)cfg_base; | |
| 187 img->size = block_size; | |
| 188 img++; img_count++; | |
| 189 #endif | |
| 190 // And a descriptor for the descriptor table itself | |
| 191 memset(img, 0, sizeof(*img)); | |
| 192 strcpy(img->name, "FIS directory"); | |
| 193 fis_base = (void *)((unsigned long)flash_end - block_size); | |
| 194 img->flash_base = (unsigned long)fis_base; | |
| 195 img->mem_base = (unsigned long)fis_base; | |
| 196 img->size = block_size; | |
| 197 img++; img_count++; | |
| 198 if ((stat = flash_erase(fis_base, block_size, (void **)&err_addr)) != 0) { | |
| 199 printf(" initialization failed %p: %x(%s)\n", err_addr, stat, flash_errmsg(stat)); | |
| 200 } else { | |
| 201 if ((stat = flash_program(fis_base, fis_work_block, | |
| 202 img_count*sizeof(*img), (void **)&err_addr)) != 0) { | |
| 203 printf("Error writing image descriptors at %p: %x(%s)\n", | |
| 204 err_addr, stat, flash_errmsg(stat)); | |
| 205 } | |
| 206 } | |
| 207 } | |
| 208 | |
| 209 static void | |
| 210 fis_list(int argc, char *argv[]) | |
| 211 { | |
| 212 struct image_desc *img; | |
| 213 int i; | |
| 214 | |
| 215 img = (struct image_desc *)((unsigned long)flash_end - block_size); | |
| 216 printf("Name FLASH addr Mem addr Length Entry point\n"); | |
| 217 for (i = 0; i < block_size/sizeof(*img); i++, img++) { | |
| 218 if (img->name[0] != (unsigned char)0xFF) { | |
| 219 printf("%-16s 0x%08lX 0x%08lX 0x%06lX 0x%08lX\n", img->name, | |
| 220 img->flash_base, img->mem_base, img->size, img->entry_point); | |
| 221 } | |
| 222 } | |
| 223 } | |
| 224 | |
| 225 static void | |
| 226 fis_free(int argc, char *argv[]) | |
| 227 { | |
| 228 unsigned long *fis_ptr, *fis_end; | |
| 229 unsigned long *area_start; | |
| 230 | |
| 231 fis_ptr = (unsigned long *)((unsigned long)flash_start + 2*block_size); | |
| 232 fis_end = (unsigned long *)((unsigned long)flash_end + block_size); | |
| 233 fis_end = (unsigned long *)(unsigned long)flash_end; | |
| 234 area_start = fis_ptr; | |
| 235 while (fis_ptr < fis_end) { | |
| 236 if (*fis_ptr != (unsigned long)0xFFFFFFFF) { | |
| 237 if (area_start != fis_ptr) { | |
| 238 // Assume that this is something | |
| 239 printf(" 0x%08lX .. 0x%08lX\n", | |
| 240 (unsigned long)area_start, (unsigned long)fis_ptr); | |
| 241 } | |
| 242 // Find next blank block | |
| 243 area_start = fis_ptr; | |
| 244 while (area_start < fis_end) { | |
| 245 if (*area_start == (unsigned long)0xFFFFFFFF) { | |
| 246 break; | |
| 247 } | |
| 248 area_start += block_size / sizeof(unsigned long); | |
| 249 } | |
| 250 fis_ptr = area_start; | |
| 251 } else { | |
| 252 fis_ptr += block_size / sizeof(unsigned long); | |
| 253 } | |
| 254 } | |
| 255 if (area_start != fis_ptr) { | |
| 256 printf(" 0x%08lX .. 0x%08lX\n", | |
| 257 (unsigned long)area_start, (unsigned long)fis_ptr); | |
| 258 } | |
| 259 } | |
| 260 | |
| 261 // Find the first unused area of flash which is long enougn | |
| 262 static bool | |
| 263 fis_find_free(unsigned long *addr, unsigned long length) | |
| 264 { | |
| 265 unsigned long *fis_ptr, *fis_end; | |
| 266 unsigned long *area_start; | |
| 267 | |
| 268 fis_ptr = (unsigned long *)((unsigned long)flash_start + 2*block_size); | |
| 269 fis_end = (unsigned long *)(unsigned long)flash_end; | |
| 270 area_start = fis_ptr; | |
| 271 while (fis_ptr < fis_end) { | |
| 272 if (*fis_ptr != (unsigned long)0xFFFFFFFF) { | |
| 273 if (area_start != fis_ptr) { | |
| 274 // Assume that this is something | |
| 275 if ((fis_ptr-area_start) >= length) { | |
| 276 *addr = (unsigned long)area_start; | |
| 277 return true; | |
| 278 } | |
| 279 } | |
| 280 // Find next blank block | |
| 281 area_start = fis_ptr; | |
| 282 while (area_start < fis_end) { | |
| 283 if (*area_start == (unsigned long)0xFFFFFFFF) { | |
| 284 break; | |
| 285 } | |
| 286 area_start += block_size / sizeof(unsigned long); | |
| 287 } | |
| 288 fis_ptr = area_start; | |
| 289 } else { | |
| 290 fis_ptr += block_size / sizeof(unsigned long); | |
| 291 } | |
| 292 } | |
| 293 if (area_start != fis_ptr) { | |
| 294 if ((fis_ptr-area_start) >= length) { | |
| 295 *addr = (unsigned long)area_start; | |
| 296 return true; | |
| 297 } | |
| 298 } | |
| 299 return false; | |
| 300 } | |
| 301 | |
| 302 static void | |
| 303 fis_create(int argc, char *argv[]) | |
| 304 { | |
| 305 int i, stat; | |
| 306 unsigned long mem_addr, exec_addr, flash_addr, entry_addr, length; | |
| 307 char *name; | |
| 308 bool mem_addr_set = false; | |
| 309 bool exec_addr_set = false; | |
| 310 bool entry_addr_set = false; | |
| 311 bool flash_addr_set = false; | |
| 312 bool length_set = false; | |
| 313 void *fis_addr, *err_addr; | |
| 314 struct image_desc *img; | |
| 315 bool slot_found; | |
| 316 struct option_info opts[5]; | |
| 317 bool prog_ok; | |
| 318 | |
| 319 init_opts(&opts[0], 'b', true, OPTION_ARG_TYPE_NUM, | |
| 320 (void **)&mem_addr, (bool *)&mem_addr_set, "memory base address"); | |
| 321 init_opts(&opts[1], 'r', true, OPTION_ARG_TYPE_NUM, | |
| 322 (void **)&exec_addr, (bool *)&exec_addr_set, "ram base address"); | |
| 323 init_opts(&opts[2], 'e', true, OPTION_ARG_TYPE_NUM, | |
| 324 (void **)&entry_addr, (bool *)&entry_addr_set, "entry point address"); | |
| 325 init_opts(&opts[3], 'f', true, OPTION_ARG_TYPE_NUM, | |
| 326 (void **)&flash_addr, (bool *)&flash_addr_set, "FLASH memory base address"); | |
| 327 init_opts(&opts[4], 'l', true, OPTION_ARG_TYPE_NUM, | |
| 328 (void **)&length, (bool *)&length_set, "length"); | |
| 329 if (!scan_opts(argc, argv, 2, opts, 5, (void *)&name, OPTION_ARG_TYPE_STR, "file name")) | |
| 330 { | |
| 331 fis_usage("invalid arguments"); | |
| 332 return; | |
| 333 } | |
| 334 | |
| 335 | |
| 336 if (!mem_addr_set || !length_set || !name) { | |
| 337 fis_usage("required parameter missing"); | |
| 338 return; | |
| 339 } | |
| 340 if (flash_addr_set && | |
| 341 ((stat = flash_verify_addr((void *)flash_addr)) || | |
| 342 (stat = flash_verify_addr((void *)(flash_addr+length-1))))) { | |
| 343 printf("Invalid FLASH address: %p (%s)\n", (void *)flash_addr, flash_errmsg(stat)); | |
| 344 printf(" valid range is %p-%p\n", (void *)flash_start, (void *)flash_end); | |
| 345 return; | |
| 346 } | |
| 347 if ((mem_addr < (unsigned long)ram_start) || | |
| 348 ((mem_addr+length) >= (unsigned long)ram_end)) { | |
| 349 printf("Invalid RAM address: %p\n", (void *)mem_addr); | |
| 350 printf(" valid range is %p-%p\n", (void *)ram_start, (void *)ram_end); | |
| 351 return; | |
| 352 } | |
| 353 if (strlen(name) >= sizeof(img->name)) { | |
| 354 printf("Name is too long, must be less than %d chars\n", (int)sizeof(img->name)); | |
| 355 return; | |
| 356 } | |
| 357 if (!flash_addr_set && !fis_find_free(&flash_addr, length)) { | |
| 358 printf("Can't locate %ld bytes free in FLASH\n", length); | |
| 359 return; | |
| 360 } | |
| 361 // Find a slot in the directory for this entry | |
| 362 // First, see if an image by this name is already present | |
| 363 slot_found = false; | |
| 364 fis_addr = (void *)((unsigned long)flash_end - block_size); | |
| 365 memcpy(fis_work_block, fis_addr, block_size); | |
| 366 img = (struct image_desc *)fis_work_block; | |
| 367 for (i = 0; i < block_size/sizeof(*img); i++, img++) { | |
| 368 if ((img->name[0] != (unsigned char)0xFF) && (strcmp(name, img->name) == 0)) { | |
| 369 if (img->flash_base != flash_addr) { | |
| 370 printf("Image found, but FLASH address incorrect\n"); | |
| 371 return; | |
| 372 } | |
| 373 if (!verify_action("An image named '%s' exists", name)) { | |
| 374 return; | |
| 375 } else { | |
| 376 slot_found = true; | |
| 377 break; | |
| 378 } | |
| 379 } | |
| 380 } | |
| 381 // If not found, try and find an empty slot | |
| 382 if (!slot_found) { | |
| 383 img = (struct image_desc *)fis_work_block; | |
| 384 for (i = 0; i < block_size/sizeof(*img); i++, img++) { | |
| 385 if (img->name[0] == (unsigned char)0xFF) { | |
| 386 slot_found = true; | |
| 387 break; | |
| 388 } | |
| 389 } | |
| 390 } | |
| 391 // Safety check - make sure the address range is not within the code we're running | |
| 392 if (flash_code_overlaps((void *)flash_addr, (void *)(flash_addr+length-1))) { | |
| 393 printf("Can't program this region - contains code in use!\n"); | |
| 394 return; | |
| 395 } | |
| 396 prog_ok = true; | |
| 397 if (prog_ok) { | |
| 398 // Erase area to be programmed | |
| 399 if ((stat = flash_erase((void *)flash_addr, length, (void **)&err_addr)) != 0) { | |
| 400 printf("Can't erase region at %p: %x(%s)\n", err_addr, stat, flash_errmsg(stat)); | |
| 401 prog_ok = false; | |
| 402 } | |
| 403 } | |
| 404 if (prog_ok) { | |
| 405 // Now program it | |
| 406 if ((stat = flash_program((void *)flash_addr, (void *)mem_addr, length, (void **)&err_addr)) != 0) { | |
| 407 printf("Can't program region at %p: %x(%s)\n", err_addr, stat, flash_errmsg(stat)); | |
| 408 prog_ok = false; | |
| 409 } | |
| 410 } | |
| 411 // Update directory | |
| 412 memset(img, 0, sizeof(*img)); | |
| 413 strcpy(img->name, name); | |
| 414 img->flash_base = flash_addr; | |
| 415 img->mem_base = exec_addr_set ? exec_addr : (flash_addr_set ? flash_addr : mem_addr); | |
| 416 img->entry_point = entry_addr_set ? entry_addr : (unsigned long)entry_address; // Hope it's been set | |
| 417 img->size = length; | |
| 418 if ((stat = flash_erase((void *)fis_addr, block_size, (void **)&err_addr)) != 0) { | |
| 419 printf("Error erasing at %p: %x(%s)\n", err_addr, stat, flash_errmsg(stat)); | |
| 420 // Don't try to program if the erase failed | |
| 421 } else { | |
| 422 // Now program it | |
| 423 if ((stat = flash_program((void *)fis_addr, (void *)fis_work_block, block_size, (void **)&err_addr)) != 0) { | |
| 424 printf("Error programming at %p: %x(%s)\n", err_addr, stat, flash_errmsg(stat)); | |
| 425 } | |
| 426 } | |
| 427 } | |
| 428 | |
| 429 static void | |
| 430 fis_erase(int argc, char *argv[]) | |
| 431 { | |
| 432 int stat; | |
| 433 unsigned long flash_addr, length; | |
| 434 bool flash_addr_set = false; | |
| 435 bool length_set = false; | |
| 436 void *err_addr; | |
| 437 struct option_info opts[2]; | |
| 438 | |
| 439 init_opts(&opts[0], 'f', true, OPTION_ARG_TYPE_NUM, | |
| 440 (void **)&flash_addr, (bool *)&flash_addr_set, "FLASH memory base address"); | |
| 441 init_opts(&opts[1], 'l', true, OPTION_ARG_TYPE_NUM, | |
| 442 (void **)&length, (bool *)&length_set, "length"); | |
| 443 if (!scan_opts(argc, argv, 2, opts, 2, (void **)0, 0, "")) | |
| 444 { | |
| 445 fis_usage("invalid arguments"); | |
| 446 return; | |
| 447 } | |
| 448 | |
| 449 if (!flash_addr_set || !length_set) { | |
| 450 fis_usage("missing argument"); | |
| 451 return; | |
| 452 } | |
| 453 if (flash_addr_set && | |
| 454 ((stat = flash_verify_addr((void *)flash_addr)) || | |
| 455 (stat = flash_verify_addr((void *)(flash_addr+length-1))))) { | |
| 456 printf("Invalid FLASH address: %p (%s)\n", (void *)flash_addr, flash_errmsg(stat)); | |
| 457 printf(" valid range is %p-%p\n", (void *)flash_start, (void *)flash_end); | |
| 458 return; | |
| 459 } | |
| 460 // Safety check - make sure the address range is not within the code we're running | |
| 461 if (flash_code_overlaps((void *)flash_addr, (void *)(flash_addr+length-1))) { | |
| 462 printf("Can't program this region - contains code in use!\n"); | |
| 463 return; | |
| 464 } | |
| 465 if ((stat = flash_erase((void *)flash_addr, length, (void **)&err_addr)) != 0) { | |
| 466 printf("Error erasing at %p: %x(%s)\n", err_addr, stat, flash_errmsg(stat)); | |
| 467 } | |
| 468 } | |
| 469 | |
| 470 static void | |
| 471 fis_delete(int argc, char *argv[]) | |
| 472 { | |
| 473 char *name; | |
| 474 int i, stat; | |
| 475 void *fis_addr, *err_addr; | |
| 476 struct image_desc *img; | |
| 477 bool slot_found; | |
| 478 | |
| 479 if (!scan_opts(argc, argv, 2, 0, 0, (void **)&name, OPTION_ARG_TYPE_STR, "image name")) | |
| 480 { | |
| 481 fis_usage("invalid arguments"); | |
| 482 return; | |
| 483 } | |
| 484 | |
| 485 slot_found = false; | |
| 486 fis_addr = (void *)((unsigned long)flash_end - block_size); | |
| 487 memcpy(fis_work_block, fis_addr, block_size); | |
| 488 img = (struct image_desc *)fis_work_block; | |
| 489 img += 2; // Skip reserved files | |
| 490 for (i = 2; i < block_size/sizeof(*img); i++, img++) { | |
| 491 if ((img->name[0] != (unsigned char)0xFF) && (strcmp(name, img->name) == 0)) { | |
| 492 if (!verify_action("Delete image '%s'", name)) { | |
| 493 return; | |
| 494 } else { | |
| 495 slot_found = true; | |
| 496 break; | |
| 497 } | |
| 498 } | |
| 499 } | |
| 500 if (!slot_found) { | |
| 501 printf("No image '%s' found\n", name); | |
| 502 return; | |
| 503 } | |
| 504 // Erase data blocks (free space) | |
| 505 if ((stat = flash_erase((void *)img->flash_base, img->size, (void **)&err_addr)) != 0) { | |
| 506 printf("Error erasing at %p: %x(%s)\n", err_addr, stat, flash_errmsg(stat)); | |
| 507 } | |
| 508 // Update directory | |
| 509 memset(img, 0xFF, sizeof(*img)); | |
| 510 if ((stat = flash_erase((void *)fis_addr, block_size, (void **)&err_addr)) != 0) { | |
| 511 printf("Error erasing at %p: %x(%s)\n", err_addr, stat, flash_errmsg(stat)); | |
| 512 // Don't try to program if the erase failed | |
| 513 } else { | |
| 514 // Now program it | |
| 515 if ((stat = flash_program((void *)fis_addr, (void *)fis_work_block, block_size, (void **)&err_addr)) != 0) { | |
| 516 printf("Error programming at %p: %x(%s)\n", err_addr, stat, flash_errmsg(stat)); | |
| 517 } | |
| 518 } | |
| 519 } | |
| 520 | |
| 521 static void | |
| 522 fis_load(int argc, char *argv[]) | |
| 523 { | |
| 524 char *name; | |
| 525 int i; | |
| 526 void *fis_addr; | |
| 527 struct image_desc *img; | |
| 528 bool slot_found; | |
| 529 | |
| 530 if (!scan_opts(argc, argv, 2, 0, 0, (void **)&name, OPTION_ARG_TYPE_STR, "image name")) | |
| 531 { | |
| 532 fis_usage("invalid arguments"); | |
| 533 return; | |
| 534 } | |
| 535 | |
| 536 slot_found = false; | |
| 537 fis_addr = (void *)((unsigned long)flash_end - block_size); | |
| 538 memcpy(fis_work_block, fis_addr, block_size); | |
| 539 img = (struct image_desc *)fis_work_block; | |
| 540 for (i = 0; i < block_size/sizeof(*img); i++, img++) { | |
| 541 if ((img->name[0] != (unsigned char)0xFF) && (strcmp(name, img->name) == 0)) { | |
| 542 slot_found = true; | |
| 543 break; | |
| 544 } | |
| 545 } | |
| 546 if (!slot_found) { | |
| 547 printf("No image '%s' found\n", name); | |
| 548 return; | |
| 549 } | |
| 550 // Load image from FLASH into RAM | |
| 551 if ((img->mem_base < (unsigned long)ram_start) || | |
| 552 ((img->mem_base+img->size) >= (unsigned long)ram_end)) { | |
| 553 printf("Not a loadable image\n"); | |
| 554 return; | |
| 555 } | |
| 556 memcpy((void *)img->mem_base, (void *)img->flash_base, img->size); | |
| 557 entry_address = (unsigned long *)img->entry_point; | |
| 558 } | |
| 559 | |
| 560 static bool | |
| 561 do_flash_init(void) | |
| 562 { | |
| 563 int stat; | |
| 564 static int init = 0; | |
| 565 | |
| 566 if (!init) { | |
| 567 init = 1; | |
| 568 if ((stat = flash_init((void *)(ram_end-FLASH_MIN_WORKSPACE), | |
| 569 FLASH_MIN_WORKSPACE)) != 0) { | |
| 570 printf("FLASH: driver init failed!, status: %x\n", stat); | |
| 571 return false; | |
| 572 } | |
| 573 flash_get_limits((void *)0, (void **)&flash_start, (void **)&flash_end); | |
| 574 flash_get_block_info(&block_size, &blocks); | |
| 575 printf("FLASH: %p - %p, %d blocks of %p bytes ea.\n", | |
| 576 flash_start, flash_end, blocks, (void *)block_size); | |
| 577 fis_work_block = (unsigned char *)(ram_end-FLASH_MIN_WORKSPACE-block_size); | |
| 578 } | |
| 579 return true; | |
| 580 } | |
| 581 | |
| 582 void | |
| 583 do_fis(int argc, char *argv[]) | |
| 584 { | |
| 585 struct cmd *cmd; | |
| 586 | |
| 587 if (argc < 2) { | |
| 588 fis_usage("too few arguments"); | |
| 589 return; | |
| 590 } | |
| 591 if (!do_flash_init()) return; | |
| 592 if ((cmd = cmd_search(__FIS_cmds_TAB__, &__FIS_cmds_TAB_END__, | |
| 593 argv[1])) != (struct cmd *)0) { | |
| 594 (cmd->fun)(argc, argv); | |
| 595 return; | |
| 596 } | |
| 597 fis_usage("unrecognized command"); | |
| 598 } | |
| 599 | |
| 600 #ifdef CYGSEM_REDBOOT_FLASH_CONFIG | |
| 601 #include <flash_config.h> | |
| 602 | |
| 603 // Configuration data, saved in FLASH, used to set/update RedBoot | |
| 604 // normal "configuration" data items. | |
| 605 static struct _config { | |
| 606 unsigned long key1; | |
| 607 unsigned char config_data[1024-(3*4)]; | |
| 608 unsigned long key2; | |
| 609 unsigned long cksum; | |
| 610 } config; | |
| 611 | |
| 612 #define CONFIG_KEY1 0x0BADFACE | |
| 613 #define CONFIG_KEY2 0xDEADDEAD | |
| 614 | |
| 615 #define CONFIG_DONE 0 | |
| 616 #define CONFIG_ABORT -1 | |
| 617 #define CONFIG_CHANGED 1 | |
| 618 #define CONFIG_OK 2 | |
| 619 #define CONFIG_BACK 3 | |
| 620 #define CONFIG_BAD 4 | |
| 621 | |
| 622 // Note: the following options are related. If 'bootp' is false, then | |
| 623 // the other values are used in the configuration. Because of the way | |
| 624 // that configuration tables are generated, they should have names which | |
| 625 // are related. The configuration options will show up lexicographically | |
| 626 // ordered, thus the peculiar naming. | |
| 627 RedBoot_config_option("Run script at boot", | |
| 628 boot_script, | |
| 629 ALWAYS_ENABLED, true, | |
| 630 CONFIG_BOOL | |
| 631 ); | |
| 632 RedBoot_config_option("Boot script", | |
| 633 boot_script_data, | |
| 634 "boot_script", true, | |
| 635 CONFIG_SCRIPT | |
| 636 ); | |
| 637 RedBoot_config_option("Boot script timeout", | |
| 638 boot_script_timeout, | |
| 639 "boot_script", true, | |
| 640 CONFIG_INT | |
| 641 ); | |
| 642 | |
| 643 CYG_HAL_TABLE_BEGIN( __CONFIG_options_TAB__, RedBoot_config_options); | |
| 644 CYG_HAL_TABLE_END( __CONFIG_options_TAB_END__, RedBoot_config_options); | |
| 645 | |
| 646 extern struct config_option __CONFIG_options_TAB__[], __CONFIG_options_TAB_END__[]; | |
| 647 | |
| 648 static int | |
| 649 get_config(struct config_option *opt, int offset) | |
| 650 { | |
| 651 char line[80], *sp, *lp; | |
| 652 int ret; | |
| 653 bool hold_bool_val, enable; | |
| 654 unsigned long hold_int_val; | |
| 655 #ifdef CYGPKG_REDBOOT_NETWORKING | |
| 656 in_addr_t hold_ip_val; | |
| 657 enet_addr_t hold_esa_val; | |
| 658 int esa_ptr; | |
| 659 char *esp; | |
| 660 #endif | |
| 661 void *val_ptr; | |
| 662 | |
| 663 if (opt->enable) { | |
| 664 flash_get_config(opt->enable, &enable, CONFIG_BOOL); | |
| 665 if ((opt->enable_sense && !enable) || | |
| 666 (!opt->enable_sense && enable)) { | |
| 667 return CONFIG_OK; // Disabled field | |
| 668 } | |
| 669 } | |
| 670 val_ptr = (void *)((unsigned char *)&config + offset); | |
| 671 printf("%s: ", opt->title); | |
| 672 switch (opt->type) { | |
| 673 case CONFIG_BOOL: | |
| 674 printf("%s ", *(bool *)val_ptr ? "true" : "false"); | |
| 675 break; | |
| 676 case CONFIG_INT: | |
| 677 printf("%d ", *(int *)val_ptr); | |
| 678 break; | |
| 679 #ifdef CYGPKG_REDBOOT_NETWORKING | |
| 680 case CONFIG_IP: | |
| 681 printf("%s ", inet_ntoa((in_addr_t *)val_ptr)); | |
| 682 break; | |
| 683 case CONFIG_ESA: | |
| 684 for (esa_ptr = 0; esa_ptr < sizeof(enet_addr_t); esa_ptr++) { | |
| 685 printf("0x%02X", ((unsigned char *)val_ptr)[esa_ptr]); | |
| 686 if (esa_ptr < (sizeof(enet_addr_t)-1)) printf(":"); | |
| 687 } | |
| 688 printf(" "); | |
| 689 break; | |
| 690 #endif | |
| 691 case CONFIG_STRING: | |
| 692 printf("??"); | |
| 693 return CONFIG_OK; // FIXME - skip for now | |
| 694 case CONFIG_SCRIPT: | |
| 695 printf("\n"); | |
| 696 sp = lp = (unsigned char *)val_ptr; | |
| 697 while (*sp) { | |
| 698 while (*lp != '\n') lp++; | |
| 699 *lp = '\0'; | |
| 700 printf(".. %s\n", sp); | |
| 701 *lp++ = '\n'; | |
| 702 sp = lp; | |
| 703 } | |
| 704 break; | |
| 705 } | |
| 706 if (opt->type != CONFIG_SCRIPT) { | |
| 707 ret = gets(line, sizeof(line), 0); | |
| 708 if (ret < 0) return CONFIG_ABORT; | |
| 709 if (strlen(line) == 0) return CONFIG_OK; // Just a CR - leave value untouched | |
| 710 if (line[0] == '.') return CONFIG_DONE; | |
| 711 if (line[0] == '^') return CONFIG_BACK; | |
| 712 } | |
| 713 switch (opt->type) { | |
| 714 case CONFIG_BOOL: | |
| 715 hold_bool_val = *(bool *)val_ptr; | |
| 716 if (!parse_bool(line, (bool *)val_ptr)) { | |
| 717 return CONFIG_BAD; | |
| 718 } | |
| 719 if (hold_bool_val != *(bool *)val_ptr) { | |
| 720 return CONFIG_CHANGED; | |
| 721 } else { | |
| 722 return CONFIG_OK; | |
| 723 } | |
| 724 break; | |
| 725 case CONFIG_INT: | |
| 726 hold_int_val = *(unsigned long *)val_ptr; | |
| 727 if (!parse_num(line, (unsigned long *)val_ptr, 0, 0)) { | |
| 728 return CONFIG_BAD; | |
| 729 } | |
| 730 if (hold_int_val != *(unsigned long *)val_ptr) { | |
| 731 return CONFIG_CHANGED; | |
| 732 } else { | |
| 733 return CONFIG_OK; | |
| 734 } | |
| 735 break; | |
| 736 #ifdef CYGPKG_REDBOOT_NETWORKING | |
| 737 case CONFIG_IP: | |
| 738 hold_ip_val.s_addr = ((in_addr_t *)val_ptr)->s_addr; | |
| 739 if (!inet_aton(line, (in_addr_t *)val_ptr)) { | |
| 740 return CONFIG_BAD; | |
| 741 } | |
| 742 if (hold_ip_val.s_addr != ((in_addr_t *)val_ptr)->s_addr) { | |
| 743 return CONFIG_CHANGED; | |
| 744 } else { | |
| 745 return CONFIG_OK; | |
| 746 } | |
| 747 break; | |
| 748 case CONFIG_ESA: | |
| 749 memcpy(&hold_esa_val, val_ptr, sizeof(enet_addr_t)); | |
| 750 esp = line; | |
| 751 for (esa_ptr = 0; esa_ptr < sizeof(enet_addr_t); esa_ptr++) { | |
| 752 unsigned long esa_byte; | |
| 753 if (!parse_num(esp, &esa_byte, &esp, ":")) { | |
| 754 memcpy(val_ptr, &hold_esa_val, sizeof(enet_addr_t)); | |
| 755 return CONFIG_BAD; | |
| 756 } | |
| 757 ((unsigned char *)val_ptr)[esa_ptr] = esa_byte; | |
| 758 } | |
| 759 return CONFIG_CHANGED; | |
| 760 break; | |
| 761 #endif | |
| 762 case CONFIG_SCRIPT: | |
| 763 // Assume it always changes | |
| 764 sp = (unsigned char *)val_ptr; | |
| 765 printf("Enter script, terminate with empty line\n"); | |
| 766 while (true) { | |
| 767 *sp = '\0'; | |
| 768 printf(">> "); | |
| 769 ret = gets(line, sizeof(line), 0); | |
| 770 if (ret < 0) return CONFIG_ABORT; | |
| 771 if (strlen(line) == 0) break; | |
| 772 lp = line; | |
| 773 while (*lp) { | |
| 774 *sp++ = *lp++; | |
| 775 } | |
| 776 *sp++ = '\n'; | |
| 777 } | |
| 778 break; | |
| 779 case CONFIG_STRING: | |
| 780 printf("??"); | |
| 781 } | |
| 782 return CONFIG_CHANGED; | |
| 783 } | |
| 784 | |
| 785 // | |
| 786 // Manage configuration information with the FLASH | |
| 787 // | |
| 788 | |
| 789 // Calculate a simple checksum. This is used to validate configuration | |
| 790 // data. Since it is used for sensitive information, it makes sense to | |
| 791 // be somewhat careful when accepting it. Also, the [strange] addition | |
| 792 // of shifted data helps make this work even if the data layout changes | |
| 793 // over time. | |
| 794 | |
| 795 static unsigned long | |
| 796 _cksum(unsigned long *buf, int len) | |
| 797 { | |
| 798 unsigned long cksum = 0; | |
| 799 int shift = 0; | |
| 800 | |
| 801 // Round 'len' up to multiple of longwords | |
| 802 len = (len + (sizeof(unsigned long)-1)) / sizeof(unsigned long); | |
| 803 while (len-- > 0) { | |
| 804 cksum ^= (*buf | (*buf << shift)); | |
| 805 buf++; | |
| 806 if (++shift == 16) shift = 0; | |
| 807 } | |
| 808 return cksum; | |
| 809 } | |
| 810 | |
| 811 static int | |
| 812 config_length(int type) | |
| 813 { | |
| 814 switch (type) { | |
| 815 case CONFIG_BOOL: | |
| 816 return sizeof(bool); | |
| 817 case CONFIG_INT: | |
| 818 return sizeof(unsigned long); | |
| 819 #ifdef CYGPKG_REDBOOT_NETWORKING | |
| 820 case CONFIG_IP: | |
| 821 return sizeof(in_addr_t); | |
| 822 case CONFIG_ESA: | |
| 823 // Would like this to be sizeof(enet_addr_t), but that causes much | |
| 824 // pain since it fouls the alignment of data which follows. | |
| 825 return 8; | |
| 826 #endif | |
| 827 case CONFIG_STRING: | |
| 828 return 0; | |
| 829 case CONFIG_SCRIPT: | |
| 830 return MAX_SCRIPT_LENGTH; | |
| 831 } | |
| 832 } | |
| 833 | |
| 834 void | |
| 835 do_flash_config(int argc, char *argv[]) | |
| 836 { | |
| 837 int stat, ret; | |
| 838 void *cfg_base, *err_addr; | |
| 839 bool need_update = false; | |
| 840 struct config_option *optbeg = __CONFIG_options_TAB__; | |
| 841 struct config_option *optend = __CONFIG_options_TAB_END__; | |
| 842 struct config_option *opt = __CONFIG_options_TAB__; | |
| 843 struct _config hold_config; | |
| 844 int offset = sizeof(unsigned long); | |
| 845 | |
| 846 if (!do_flash_init()) return; | |
| 847 memcpy(&hold_config, &config, sizeof(config)); | |
| 848 script = (unsigned char *)0; | |
| 849 | |
| 850 while (opt != optend) { | |
| 851 ret = get_config(opt, offset); | |
| 852 switch (ret) { | |
| 853 case CONFIG_DONE: | |
| 854 goto done; | |
| 855 case CONFIG_ABORT: | |
| 856 memcpy(&config, &hold_config, sizeof(config)); | |
| 857 return; | |
| 858 case CONFIG_CHANGED: | |
| 859 need_update = true; | |
| 860 case CONFIG_OK: | |
| 861 offset += config_length(opt->type); | |
| 862 opt++; | |
| 863 break; | |
| 864 case CONFIG_BACK: | |
| 865 if (opt != optbeg) opt--; | |
| 866 continue; | |
| 867 case CONFIG_BAD: | |
| 868 // Nothing - make him do it again | |
| 869 printf ("** invalid entry\n"); | |
| 870 } | |
| 871 } | |
| 872 | |
| 873 done: | |
| 874 if (!need_update) return; | |
| 875 config.key1 = CONFIG_KEY1; config.key2 = CONFIG_KEY2; | |
| 876 config.cksum = _cksum((unsigned long *)&config, sizeof(config)-sizeof(config.cksum)); | |
| 877 cfg_base = (void *)((unsigned long)flash_end - (2*block_size)); | |
| 878 if (verify_action("Update RedBoot non-volatile configuration")) { | |
| 879 if ((stat = flash_erase(cfg_base, block_size, (void **)&err_addr)) != 0) { | |
| 880 printf(" initialization failed %p: %x(%s)\n", err_addr, stat, flash_errmsg(stat)); | |
| 881 } else { | |
| 882 if ((stat = flash_program(cfg_base, (void *)&config, | |
| 883 sizeof(config), (void **)&err_addr)) != 0) { | |
| 884 printf("Error writing config data at %p: %x(%s)\n", | |
| 885 err_addr, stat, flash_errmsg(stat)); | |
| 886 } | |
| 887 } | |
| 888 } | |
| 889 } | |
| 890 | |
| 891 void | |
| 892 flash_get_config(char *key, void *val, int type) | |
| 893 { | |
| 894 struct config_option *optend = __CONFIG_options_TAB_END__; | |
| 895 struct config_option *opt = __CONFIG_options_TAB__; | |
| 896 int offset = sizeof(unsigned long); // Offset past starting 'key' | |
| 897 void *val_ptr; | |
| 898 | |
| 899 if (!do_flash_init()) return; | |
| 900 | |
| 901 while (opt != optend) { | |
| 902 val_ptr = (void *)((unsigned char *)&config + offset); | |
| 903 if (strcmp(opt->key, key) == 0) { | |
| 904 if (opt->type == type) { | |
| 905 switch (opt->type) { | |
| 906 case CONFIG_BOOL: | |
| 907 *(bool *)val = *(bool *)val_ptr; | |
| 908 break; | |
| 909 case CONFIG_INT: | |
| 910 *(unsigned long *)val = *(unsigned long *)val_ptr; | |
| 911 break; | |
| 912 #ifdef CYGPKG_REDBOOT_NETWORKING | |
| 913 case CONFIG_IP: | |
| 914 memcpy(val, val_ptr, sizeof(in_addr_t)); | |
| 915 break; | |
| 916 case CONFIG_ESA: | |
| 917 memcpy(val, val_ptr, sizeof(enet_addr_t)); | |
| 918 break; | |
| 919 #endif | |
| 920 case CONFIG_STRING: | |
| 921 break; | |
| 922 case CONFIG_SCRIPT: | |
| 923 // Just return a pointer to the script | |
| 924 *(unsigned char **)val = (unsigned char *)val_ptr; | |
| 925 break; | |
| 926 } | |
| 927 } else { | |
| 928 printf("Request for config value '%s' - wrong type\n", key); | |
| 929 } | |
| 930 return; | |
| 931 } | |
| 932 offset += config_length(opt->type); | |
| 933 opt++; | |
| 934 } | |
| 935 | |
| 936 printf("Can't find config value '%s'\n", key); | |
| 937 } | |
| 938 | |
| 939 // | |
| 940 // Attempt to get configuration information from the FLASH. | |
| 941 // If available (i.e. good checksum, etc), initialize "known" | |
| 942 // values for later use. | |
| 943 // | |
| 944 static void | |
| 945 load_flash_config(void) | |
| 946 { | |
| 947 void *cfg_base; | |
| 948 bool use_boot_script; | |
| 949 | |
| 950 config_ok = false; | |
| 951 if (!do_flash_init()) return; | |
| 952 cfg_base = (void *)((unsigned long)flash_end - (2*block_size)); | |
| 953 memcpy(&config, cfg_base, sizeof(config)); | |
| 954 if ((_cksum((unsigned long *)&config, sizeof(config)-sizeof(config.cksum)) != config.cksum) || | |
| 955 (config.key1 != CONFIG_KEY1)|| (config.key2 != CONFIG_KEY2)) { | |
| 956 printf("FLASH configuration checksum error or invalid key\n"); | |
| 957 script = (unsigned char *)0; | |
| 958 memset(&config, 0, sizeof(config)); | |
| 959 return; | |
| 960 } | |
| 961 flash_get_config("boot_script", &use_boot_script, CONFIG_BOOL); | |
| 962 if (use_boot_script) { | |
| 963 flash_get_config("boot_script_data", &script, CONFIG_SCRIPT); | |
| 964 flash_get_config("boot_script_timeout", &script_timeout, CONFIG_INT); | |
| 965 } | |
| 966 config_ok = true; | |
| 967 } | |
| 968 | |
| 969 RedBoot_init(load_flash_config, RedBoot_INIT_FIRST); | |
| 970 | |
| 971 #endif |
