1 //==========================================================================
5 // RedBoot - FLASH memory support
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, 2004 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 #define _FLASH_PRIVATE_
58 #include <cyg/io/flash.h>
61 #include <cyg/infra/cyg_ass.h> // assertion macros
63 #ifdef CYGBLD_BUILD_REDBOOT_WITH_WINCE_SUPPORT
67 #ifdef CYGSEM_REDBOOT_FLASH_COMBINED_FIS_AND_CONFIG
68 // Note horrid intertwining of functions, to save precious FLASH
69 extern void conf_endian_fixup(void *p);
72 // Round a quantity up
73 #define _rup(n,s) ((((n)+(s-1))/s)*s)
75 #ifdef CYGOPT_REDBOOT_FIS
76 // Image management functions
77 local_cmd_entry("init",
78 "Initialize FLASH Image System [FIS]",
83 #ifdef CYGSEM_REDBOOT_FIS_CRC_CHECK
84 # define FIS_LIST_OPTS "[-c] [-d]"
86 # define FIS_LIST_OPTS "[-d]"
88 local_cmd_entry("list",
89 "Display contents of FLASH Image System [FIS]",
94 local_cmd_entry("free",
95 "Display free [available] locations within FLASH Image System [FIS]",
100 local_cmd_entry("delete",
101 "Delete an image from FLASH Image System [FIS]",
107 static char fis_load_usage[] =
108 #ifdef CYGPRI_REDBOOT_ZLIB_FLASH
111 "[-b <memory_load_address>] [-c] "
112 #ifdef CYGBLD_BUILD_REDBOOT_WITH_WINCE_SUPPORT
117 #ifdef CYGPRI_REDBOOT_ZLIB_FLASH
120 "\t-c: print checksum\n"
121 #ifdef CYGBLD_BUILD_REDBOOT_WITH_WINCE_SUPPORT
122 "\t-w: load as Windows CE image\n"
126 local_cmd_entry("load",
127 "Load image from FLASH Image System [FIS] into RAM",
132 local_cmd_entry("create",
134 "[-b <mem_base>] [-l <image_length>] [-s <data_length>]\n"
135 " [-f <flash_addr>] [-e <entry_point>] [-r <ram_addr>] [-n] <name>",
141 // Raw flash access functions
142 local_cmd_entry("erase",
143 "Erase FLASH contents",
144 "-f <flash_addr> -l <length>",
148 #ifdef CYGHWR_IO_FLASH_BLOCK_LOCKING
149 local_cmd_entry("lock",
150 "LOCK FLASH contents",
151 "[-f <flash_addr> -l <length>] [name]",
155 local_cmd_entry("unlock",
156 "UNLOCK FLASH contents",
157 "[-f <flash_addr> -l <length>] [name]",
162 local_cmd_entry("write",
163 "Write raw data directly to FLASH",
164 "-f <flash_addr> -b <mem_base> -l <image_length>",
169 // Define table boundaries
170 CYG_HAL_TABLE_BEGIN( __FIS_cmds_TAB__, FIS_cmds);
171 CYG_HAL_TABLE_END( __FIS_cmds_TAB_END__, FIS_cmds);
173 extern struct cmd __FIS_cmds_TAB__[], __FIS_cmds_TAB_END__;
176 static cmd_fun do_fis;
177 RedBoot_nested_cmd("fis",
178 "Manage FLASH images",
181 __FIS_cmds_TAB__, &__FIS_cmds_TAB_END__
184 // Local data used by these routines
185 void *flash_start, *flash_end;
186 int flash_block_size, flash_num_blocks;
187 #ifdef CYGOPT_REDBOOT_FIS
188 void *fis_work_block;
190 #ifdef CYGOPT_REDBOOT_REDUNDANT_FIS
191 void *redundant_fis_addr;
193 int fisdir_size; // Size of FIS directory.
195 #ifdef CYGSEM_REDBOOT_FLASH_CONFIG
196 extern void *cfg_base; // Location in Flash of config data
197 extern int cfg_size; // Length of config data - rounded to Flash block size
198 extern struct _config *config;
204 diag_printf("*** invalid 'fis' command: %s\n", why);
205 cmd_usage(__FIS_cmds_TAB__, &__FIS_cmds_TAB_END__, "fis ");
209 _show_invalid_flash_address(CYG_ADDRESS flash_addr, int stat)
211 diag_printf("Invalid FLASH address %p: %s\n", (void *)flash_addr, flash_errmsg(stat));
212 diag_printf(" valid range is %p-%p\n", flash_start, flash_end);
215 #ifdef CYGOPT_REDBOOT_FIS
217 // fis_endian_fixup() is used to swap endianess if required.
219 static inline void fis_endian_fixup(void *addr)
221 #ifdef REDBOOT_FLASH_REVERSE_BYTEORDER
222 struct fis_image_desc *p = addr;
223 int cnt = fisdir_size / sizeof(struct fis_image_desc);
226 p->flash_base = CYG_SWAP32(p->flash_base);
227 p->mem_base = CYG_SWAP32(p->mem_base);
228 p->size = CYG_SWAP32(p->size);
229 p->entry_point = CYG_SWAP32(p->entry_point);
230 p->data_length = CYG_SWAP32(p->data_length);
231 p->desc_cksum = CYG_SWAP32(p->desc_cksum);
232 p->file_cksum = CYG_SWAP32(p->file_cksum);
239 fis_read_directory(void)
243 FLASH_READ(fis_addr, fis_work_block, fisdir_size, &err_addr);
244 fis_endian_fixup(fis_work_block);
247 struct fis_image_desc *
248 fis_lookup(char *name, int *num)
251 struct fis_image_desc *img;
253 fis_read_directory();
255 img = (struct fis_image_desc *)fis_work_block;
256 for (i = 0; i < fisdir_size/sizeof(*img); i++, img++) {
257 if ((img->u.name[0] != 0xFF) &&
258 (strcasecmp(name, img->u.name) == 0)) {
266 int fis_start_update_directory(int autolock)
268 #ifdef CYGOPT_REDBOOT_REDUNDANT_FIS
269 #ifdef CYGHWR_IO_FLASH_BLOCK_LOCKING
270 #ifdef CYGSEM_REDBOOT_FLASH_LOCK_SPECIAL
271 // Ensure [quietly] that the directory is unlocked before trying to update and locked again afterwards
274 int do_autolock = autolock;
278 struct fis_image_desc *img;
282 /*exchange old and new valid fis tables*/
283 tmp_fis_addr = fis_addr;
284 fis_addr = redundant_fis_addr;
285 redundant_fis_addr = tmp_fis_addr;
287 //adjust the contents of the new fis table
288 img = fis_work_block;
290 memcpy(img->u.valid_info.magic_name, CYG_REDBOOT_RFIS_VALID_MAGIC,
291 CYG_REDBOOT_RFIS_VALID_MAGIC_LENGTH);
292 img->u.valid_info.valid_flag[0] = CYG_REDBOOT_RFIS_IN_PROGRESS;
293 img->u.valid_info.valid_flag[1] = CYG_REDBOOT_RFIS_IN_PROGRESS;
294 img->u.valid_info.version_count = img->u.valid_info.version_count+1;
297 #ifdef CYGHWR_IO_FLASH_BLOCK_LOCKING
299 flash_unlock((void *)fis_addr, fisdir_size, &err_addr);
302 flash_erase(fis_addr, fisdir_size, &err_addr);
303 //now magic is 0xffffffff
304 fis_endian_fixup(fis_work_block);
305 flash_program(fis_addr, fis_work_block, flash_block_size, &err_addr);
306 fis_endian_fixup(fis_work_block);
307 //now magic is 0xff1234ff, valid is IN_PROGRESS, version_count is the old one +1
310 /* nothing to do here without redundant fis */
317 fis_update_directory(int autolock, int error)
321 #ifdef CYGHWR_IO_FLASH_BLOCK_LOCKING
322 #ifdef CYGSEM_REDBOOT_FLASH_LOCK_SPECIAL
323 // Ensure [quietly] that the directory is unlocked before trying to update and locked again afterwards
326 int do_autolock = autolock;
330 #ifdef CYGOPT_REDBOOT_REDUNDANT_FIS
332 struct fis_image_desc *img = fis_work_block;
334 // called from invalid state
335 if (img->u.valid_info.valid_flag[0] != CYG_REDBOOT_RFIS_IN_PROGRESS)
338 //if it failed, reset is0Valid to the state before startUpdateDirectory()
339 //g_data.fisTable hasn't been changed yet, so it doesn't have to be reset now
340 //then reread the contents from flash
341 //setting the valid flag of the failed table to "INVALID" might also be not too bad
342 //but IN_PROGRESS is also good enough I think
344 void *swap_fis_addr = fis_addr;
345 fis_addr = redundant_fis_addr;
346 redundant_fis_addr = swap_fis_addr;
349 void *tmp_fis_addr = (void *)((CYG_ADDRESS)fis_addr +
350 CYG_REDBOOT_RFIS_VALID_MAGIC_LENGTH);
352 img->u.valid_info.valid_flag[0] = CYG_REDBOOT_RFIS_VALID;
353 img->u.valid_info.valid_flag[1] = CYG_REDBOOT_RFIS_VALID;
355 flash_program(tmp_fis_addr, img->u.valid_info.valid_flag,
356 sizeof(img->u.valid_info.valid_flag), &err_addr);
358 #ifdef CYGHWR_IO_FLASH_BLOCK_LOCKING
360 flash_lock((void *)fis_addr, fisdir_size, &err_addr);
363 #else // CYGOPT_REDBOOT_REDUNDANT_FIS
364 int blk_size = fisdir_size;
367 fis_endian_fixup(fis_work_block);
368 #ifdef CYGSEM_REDBOOT_FLASH_COMBINED_FIS_AND_CONFIG
369 memcpy((char *)fis_work_block+fisdir_size, config, cfg_size);
370 conf_endian_fixup((char *)fis_work_block+fisdir_size);
371 blk_size += cfg_size;
373 #ifdef CYGHWR_IO_FLASH_BLOCK_LOCKING
375 flash_unlock((void *)fis_addr, blk_size, &err_addr);
377 if ((stat = flash_erase(fis_addr, flash_block_size, &err_addr)) != 0) {
378 diag_printf("Error erasing FIS directory at %p: %s\n", err_addr, flash_errmsg(stat));
380 if ((stat = FLASH_PROGRAM(fis_addr, fis_work_block,
381 flash_block_size, &err_addr)) != 0) {
382 diag_printf("Error writing FIS directory at %p: %s\n",
383 err_addr, flash_errmsg(stat));
386 fis_endian_fixup(fis_work_block);
387 #ifdef CYGHWR_IO_FLASH_BLOCK_LOCKING
389 flash_lock((void *)fis_addr, blk_size, &err_addr);
392 #endif // CYGOPT_REDBOOT_REDUNDANT_FIS
397 #ifdef CYGOPT_REDBOOT_REDUNDANT_FIS
400 fis_get_valid_buf(struct fis_image_desc *img0, struct fis_image_desc *img1, int *update_was_interrupted)
402 *update_was_interrupted = 0;
403 if (strncmp(img1->u.valid_info.magic_name, CYG_REDBOOT_RFIS_VALID_MAGIC,
404 CYG_REDBOOT_RFIS_VALID_MAGIC_LENGTH) != 0) {
406 if (img0->u.valid_info.version_count > 0) {
407 *update_was_interrupted = 1;
410 } else if (strncmp(img0->u.valid_info.magic_name, CYG_REDBOOT_RFIS_VALID_MAGIC,
411 CYG_REDBOOT_RFIS_VALID_MAGIC_LENGTH) != 0) {
413 if (img1->u.valid_info.version_count > 0) {
414 *update_was_interrupted = 1;
418 //magic is ok for both, now check the valid flag
419 if ((img1->u.valid_info.valid_flag[0] != CYG_REDBOOT_RFIS_VALID) ||
420 (img1->u.valid_info.valid_flag[1] != CYG_REDBOOT_RFIS_VALID)) {
422 *update_was_interrupted = 1;
424 } else if ((img0->u.valid_info.valid_flag[0] != CYG_REDBOOT_RFIS_VALID) ||
425 (img0->u.valid_info.valid_flag[1] != CYG_REDBOOT_RFIS_VALID)) {
427 *update_was_interrupted = 1;
431 //now check the version
432 return img1->u.valid_info.version_count == (img0->u.valid_info.version_count + 1);
436 fis_erase_redundant_directory(void)
441 #ifdef CYGSEM_REDBOOT_FLASH_LOCK_SPECIAL
442 // Ensure [quietly] that the directory is unlocked before trying
444 flash_unlock((void *)redundant_fis_addr, fisdir_size,
447 if ((stat = flash_erase(redundant_fis_addr, fisdir_size,
449 diag_printf("Error erasing FIS directory at %p: %s\n",
450 err_addr, flash_errmsg(stat));
452 #ifdef CYGSEM_REDBOOT_FLASH_LOCK_SPECIAL
453 // Ensure [quietly] that the directory is locked after the update
454 flash_lock((void *)redundant_fis_addr, fisdir_size, &err_addr);
460 fis_init(int argc, char *argv[])
463 struct fis_image_desc *img;
465 bool full_init = false;
466 struct option_info opts[1];
467 CYG_ADDRESS redboot_flash_start;
468 unsigned long redboot_image_size;
470 init_opts(&opts[0], 'f', false, OPTION_ARG_TYPE_FLG,
471 &full_init, NULL, "full initialization, erases all of flash");
472 if (!scan_opts(argc, argv, 2, opts, 1, 0, 0, "")) {
476 if (!verify_action("About to initialize [format] FLASH image system")) {
477 diag_printf("** Aborted\n");
480 diag_printf("*** Initialize FLASH Image System\n");
482 #define MIN_REDBOOT_IMAGE_SIZE CYGBLD_REDBOOT_MIN_IMAGE_SIZE
483 redboot_image_size = flash_block_size > MIN_REDBOOT_IMAGE_SIZE ?
484 flash_block_size : MIN_REDBOOT_IMAGE_SIZE;
486 img = fis_work_block;
487 memset(img, 0xFF, fisdir_size); // Start with erased data
489 #ifdef CYGOPT_REDBOOT_REDUNDANT_FIS
490 //create the valid flag entry
491 memset(img, 0, sizeof(struct fis_image_desc));
492 strcpy(img->u.valid_info.magic_name, CYG_REDBOOT_RFIS_VALID_MAGIC);
493 img->u.valid_info.valid_flag[0] = CYG_REDBOOT_RFIS_VALID;
494 img->u.valid_info.valid_flag[1] = CYG_REDBOOT_RFIS_VALID;
495 img->u.valid_info.version_count = 0;
499 // Create a pseudo image for RedBoot
500 #ifdef CYGOPT_REDBOOT_FIS_RESERVED_BASE
501 memset(img, 0, sizeof(*img));
502 strcpy(img->u.name, "(reserved)");
503 img->flash_base = (CYG_ADDRESS)flash_start;
504 img->mem_base = (CYG_ADDRESS)flash_start;
505 img->size = CYGNUM_REDBOOT_FLASH_RESERVED_BASE;
508 redboot_flash_start = (CYG_ADDRESS)flash_start + CYGBLD_REDBOOT_FLASH_BOOT_OFFSET;
509 #ifdef CYGOPT_REDBOOT_FIS_REDBOOT
510 memset(img, 0, sizeof(*img));
511 strcpy(img->u.name, "RedBoot");
512 img->flash_base = redboot_flash_start;
513 img->mem_base = redboot_flash_start;
514 img->size = redboot_image_size;
516 redboot_flash_start += redboot_image_size;
518 #ifdef CYGOPT_REDBOOT_FIS_REDBOOT_POST
519 #ifdef CYGNUM_REDBOOT_FIS_REDBOOT_POST_OFFSET
520 // Take care to place the POST entry at the right offset:
521 redboot_flash_start = (CYG_ADDRESS)flash_start + CYGNUM_REDBOOT_FIS_REDBOOT_POST_OFFSET;
523 memset(img, 0, sizeof(*img));
524 strcpy(img->u.name, "RedBoot[post]");
525 img->flash_base = redboot_flash_start;
526 img->mem_base = redboot_flash_start;
527 img->size = redboot_image_size;
529 redboot_flash_start += redboot_image_size;
531 #ifdef CYGOPT_REDBOOT_FIS_REDBOOT_BACKUP
532 // And a backup image
533 memset(img, 0, sizeof(*img));
534 strcpy(img->u.name, "RedBoot[backup]");
535 img->flash_base = redboot_flash_start;
536 img->mem_base = redboot_flash_start;
537 img->size = redboot_image_size;
539 redboot_flash_start += redboot_image_size;
541 #if defined(CYGSEM_REDBOOT_FLASH_CONFIG) && defined(CYGHWR_REDBOOT_FLASH_CONFIG_MEDIA_FLASH)
542 // And a descriptor for the configuration data
543 memset(img, 0, sizeof(*img));
544 strcpy(img->u.name, "RedBoot config");
545 img->flash_base = (CYG_ADDRESS)cfg_base;
546 img->mem_base = (CYG_ADDRESS)cfg_base;
547 img->size = cfg_size;
550 // And a descriptor for the descriptor table itself
551 memset(img, 0, sizeof(*img));
552 strcpy(img->u.name, "FIS directory");
553 img->flash_base = (CYG_ADDRESS)fis_addr;
554 img->mem_base = (CYG_ADDRESS)fis_addr;
555 img->size = fisdir_size;
558 //create the entry for the redundant fis table
559 #ifdef CYGOPT_REDBOOT_REDUNDANT_FIS
560 memset(img, 0, sizeof(*img));
561 strcpy(img->u.name, "Redundant FIS");
562 img->flash_base = (CYG_ADDRESS)redundant_fis_addr;
563 img->mem_base = (CYG_ADDRESS)redundant_fis_addr;
564 img->size = fisdir_size;
568 #ifdef CYGOPT_REDBOOT_FIS_DIRECTORY_ARM_SIB_ID
569 // FIS gets the size of a full block - note, this should be changed
570 // if support is added for multi-block FIS structures.
571 img = (struct fis_image_desc *)((CYG_ADDRESS)fis_work_block + fisdir_size);
572 // Add a footer so the FIS will be recognized by the ARM Boot
573 // Monitor as a reserved area.
575 tFooter *footer_p = (tFooter*)((CYG_ADDRESS)img - sizeof(tFooter));
576 cyg_uint32 check = 0;
577 cyg_uint32 *check_ptr = (cyg_uint32 *)footer_p;
578 cyg_int32 count = (sizeof(tFooter) - 4) >> 2;
580 // Prepare footer. Try to protect all but the reserved space
581 // and the first RedBoot image (which is expected to be
582 // bootable), but fall back to just protecting the FIS if it's
583 // not at the default position in the flash.
584 #if defined(CYGOPT_REDBOOT_FIS_RESERVED_BASE) && (-1 == CYGNUM_REDBOOT_FIS_DIRECTORY_BLOCK)
585 footer_p->blockBase = (char*)_ADDR_REDBOOT_TO_ARM(flash_start);
586 footer_p->blockBase += CYGNUM_REDBOOT_FLASH_RESERVED_BASE + redboot_image_size;
588 footer_p->blockBase = (char*)_ADDR_REDBOOT_TO_ARM(fis_work_block);
590 footer_p->infoBase = NULL;
591 footer_p->signature = FLASH_FOOTER_SIGNATURE;
592 footer_p->type = TYPE_REDHAT_REDBOOT;
594 // and compute its checksum
595 for ( ; count > 0; count--) {
596 if (*check_ptr > ~check)
598 check += *check_ptr++;
600 footer_p->checksum = ~check;
604 // Do this after creating the initialized table because that inherently
605 // calculates where the high water mark of default RedBoot images is.
608 unsigned long erase_size;
609 CYG_ADDRESS erase_start;
610 // Erase everything except default RedBoot images, fis block,
612 // First deal with the possible first part, before RedBoot images:
613 #if (CYGBLD_REDBOOT_FLASH_BOOT_OFFSET > CYGNUM_REDBOOT_FLASH_RESERVED_BASE)
614 erase_start = (CYG_ADDRESS)flash_start + CYGNUM_REDBOOT_FLASH_RESERVED_BASE;
615 erase_size = (CYG_ADDRESS)flash_start + CYGBLD_REDBOOT_FLASH_BOOT_OFFSET;
616 if ( erase_size > erase_start ) {
617 erase_size -= erase_start;
618 if ((stat = flash_erase((void *)erase_start, erase_size,
620 diag_printf(" initialization failed at %p: %s\n",
621 err_addr, flash_errmsg(stat));
625 // second deal with the larger part in the main:
626 erase_start = redboot_flash_start; // high water of created images
627 // Now the empty bits between the end of Redboot and the cfg and dir
629 #if defined(CYGSEM_REDBOOT_FLASH_CONFIG) && \
630 defined(CYGHWR_REDBOOT_FLASH_CONFIG_MEDIA_FLASH) && \
631 !defined(CYGSEM_REDBOOT_FLASH_COMBINED_FIS_AND_CONFIG)
632 if (fis_addr > cfg_base) {
633 erase_size = (CYG_ADDRESS)cfg_base - erase_start; // the gap between HWM and config data
635 erase_size = (CYG_ADDRESS)fis_addr - erase_start; // the gap between HWM and fis data
637 if ((stat = flash_erase((void *)erase_start, erase_size,
639 diag_printf(" initialization failed %p: %s\n",
640 err_addr, flash_errmsg(stat));
642 erase_start += erase_size + flash_block_size;
643 if (fis_addr > cfg_base) {
644 erase_size = (CYG_ADDRESS)fis_addr - erase_start; // the gap between config and fis data
646 erase_size = (CYG_ADDRESS)cfg_base - erase_start; // the gap between fis and config data
648 if ((stat = flash_erase((void *)erase_start, erase_size,
650 diag_printf(" initialization failed %p: %s\n",
651 err_addr, flash_errmsg(stat));
653 erase_start += erase_size + flash_block_size;
654 #else // !CYGSEM_REDBOOT_FLASH_CONFIG
655 erase_size = (CYG_ADDRESS)fis_addr - erase_start; // the gap between HWM and fis data
656 if ((stat = flash_erase((void *)erase_start, erase_size,
658 diag_printf(" initialization failed %p: %s\n",
659 err_addr, flash_errmsg(stat));
661 erase_start += erase_size + flash_block_size;
663 // Lastly, anything at the end, if there is any
664 if ( erase_start < (((CYG_ADDRESS)flash_end)+1) ) {
665 erase_size = ((CYG_ADDRESS)flash_end - erase_start) + 1;
666 if ((stat = flash_erase((void *)erase_start, erase_size,
668 diag_printf(" initialization failed at %p: %s\n",
669 err_addr, flash_errmsg(stat));
672 #ifndef CYGDAT_REDBOOT_FIS_MAX_FREE_CHUNKS
673 // In this case, 'fis free' works by scanning for erased blocks. Since the
674 // "-f" option was not supplied, there may be areas which are not used but
675 // don't appear to be free since they are not erased - thus the warning
677 diag_printf(" Warning: device contents not erased, some blocks may not be usable\n");
680 fis_start_update_directory(0);
681 fis_update_directory(0, 0);
682 #ifdef CYGOPT_REDBOOT_REDUNDANT_FIS
683 fis_erase_redundant_directory();
688 fis_list(int argc, char *argv[])
690 struct fis_image_desc *img;
691 int i = 0, image_indx;
692 bool show_cksums = false;
693 bool show_datalen = false;
694 struct option_info opts[2];
695 unsigned long last_addr, lowest_addr;
698 #ifdef CYGHWR_REDBOOT_ARM_FLASH_SIB
699 // FIXME: this is somewhat half-baked
700 extern void arm_fis_list(void);
705 init_opts(&opts[i++], 'd', false, OPTION_ARG_TYPE_FLG,
706 &show_datalen, NULL, "display data length");
707 #ifdef CYGSEM_REDBOOT_FIS_CRC_CHECK
708 init_opts(&opts[i++], 'c', false, OPTION_ARG_TYPE_FLG,
709 &show_cksums, NULL, "display checksums");
711 if (!scan_opts(argc, argv, 2, opts, i, 0, 0, "")) {
714 fis_read_directory();
716 // Let diag_printf do the formatting in both cases, rather than counting
718 diag_printf("%-16s %-10s %-10s %-10s %-s\n",
720 show_cksums ? "Checksum" : "Mem addr",
721 show_datalen ? "Datalen" : "Length",
727 lowest_addr = 0xFFFFFFFF;
728 img = fis_work_block;
729 for (i = 0; i < fisdir_size/sizeof(*img); i++, img++) {
730 if (img->u.name[0] != 0xFF) {
731 if ((img->flash_base >= last_addr) && (img->flash_base < lowest_addr)) {
732 lowest_addr = img->flash_base;
739 img = fis_work_block;
741 diag_printf("%-16s 0x%08lX 0x%08lX 0x%08lX 0x%08lX\n", img->u.name,
742 (unsigned long)img->flash_base,
743 #ifdef CYGSEM_REDBOOT_FIS_CRC_CHECK
744 show_cksums ? img->file_cksum : (unsigned long)img->mem_base,
745 show_datalen ? img->data_length : img->size,
747 (unsigned long)img->mem_base,
750 (unsigned long)img->entry_point);
752 last_addr = lowest_addr + 1;
753 } while (image_found == true);
756 #ifdef CYGDAT_REDBOOT_FIS_MAX_FREE_CHUNKS
758 CYG_ADDRESS start, end;
762 find_free(struct free_chunk *chunks)
764 CYG_ADDRESS *fis_ptr, *fis_end;
765 struct fis_image_desc *img;
769 // Do not search the area reserved for pre-RedBoot systems:
770 fis_ptr = (CYG_ADDRESS *)((CYG_ADDRESS)flash_start +
771 CYGNUM_REDBOOT_FLASH_RESERVED_BASE);
772 fis_end = (CYG_ADDRESS *)flash_end;
773 chunks[num_chunks - 1].start = (CYG_ADDRESS)fis_ptr;
774 chunks[num_chunks - 1].end = (CYG_ADDRESS)fis_end;
775 fis_read_directory();
776 img = fis_work_block;
777 for (i = 0; i < fisdir_size/sizeof(*img); i++, img++) {
778 if (img->u.name[0] != 0xFF) {
779 // Figure out which chunk this is in and split it
780 for (idx = 0; idx < num_chunks; idx++) {
781 if ((img->flash_base >= chunks[idx].start) &&
782 (img->flash_base <= chunks[idx].end)) {
783 if (img->flash_base == chunks[idx].start) {
784 chunks[idx].start += img->size;
785 if (chunks[idx].start >= chunks[idx].end) {
786 // This free chunk has collapsed
787 while (idx < (num_chunks-1)) {
788 chunks[idx] = chunks[idx+1];
793 } else if ((img->flash_base+img->size) == chunks[idx].end) {
794 chunks[idx].end = img->flash_base;
796 // Split chunk into two parts
797 if ((img->flash_base+img->size) < (CYG_ADDRESS)fis_end) {
799 // make room for new chunk
800 for (j = num_chunks; j > idx + 1; j--)
801 chunks[j] = chunks[j-1];
802 chunks[idx+1].start = img->flash_base + img->size;
803 chunks[idx+1].end = chunks[idx].end;
804 if (++num_chunks == CYGDAT_REDBOOT_FIS_MAX_FREE_CHUNKS) {
805 diag_printf("Warning: too many free chunks\n");
809 chunks[idx].end = img->flash_base;
818 #endif // CYGDAT_REDBOOT_FIS_MAX_FREE_CHUNKS
821 fis_free(int argc, char *argv[])
823 #ifndef CYGDAT_REDBOOT_FIS_MAX_FREE_CHUNKS
824 unsigned long *fis_ptr, *fis_end, flash_data;
825 unsigned long *area_start;
828 FLASH_Enable(flash_start, flash_end);
829 // Do not search the area reserved for pre-RedBoot systems:
830 fis_ptr = (unsigned long *)((CYG_ADDRESS)flash_start +
831 CYGNUM_REDBOOT_FLASH_RESERVED_BASE);
832 fis_end = (unsigned long *)(CYG_ADDRESS)flash_end;
833 area_start = fis_ptr;
834 while (fis_ptr < fis_end) {
835 flash_read(fis_ptr, &flash_data, sizeof(unsigned long), &err_addr);
836 if (flash_data != 0xFFFFFFFF) {
837 if (area_start != fis_ptr) {
838 // Assume that this is something
839 diag_printf(" 0x%08x .. 0x%08x\n",
840 (CYG_ADDRESS)area_start, (CYG_ADDRESS)fis_ptr);
842 // Find next blank block
843 area_start = fis_ptr;
844 while (area_start < fis_end) {
845 flash_read(area_start, &flash_data, sizeof(unsigned long), &err_addr);
846 if (flash_data == 0xFFFFFFFF) {
849 area_start += flash_block_size / sizeof(CYG_ADDRESS);
851 fis_ptr = area_start;
853 fis_ptr += flash_block_size / sizeof(CYG_ADDRESS);
856 if (area_start != fis_ptr) {
857 diag_printf(" 0x%08x .. 0x%08x\n",
858 (CYG_ADDRESS)area_start, (CYG_ADDRESS)fis_ptr);
860 FLASH_Disable(flash_start, flash_end);
862 struct free_chunk chunks[CYGDAT_REDBOOT_FIS_MAX_FREE_CHUNKS];
865 num_chunks = find_free(chunks);
866 for (idx = 0; idx < num_chunks; idx++) {
867 diag_printf(" 0x%08x .. 0x%08x\n",
874 // Find the first unused area of flash which is long enough
876 fis_find_free(CYG_ADDRESS *addr, unsigned long length)
878 #ifndef CYGDAT_REDBOOT_FIS_MAX_FREE_CHUNKS
879 unsigned long *fis_ptr, *fis_end, flash_data;
880 unsigned long *area_start;
883 // Do not search the area reserved for pre-RedBoot systems:
884 fis_ptr = (unsigned long *)((CYG_ADDRESS)flash_start +
885 CYGNUM_REDBOOT_FLASH_RESERVED_BASE);
886 fis_end = (unsigned long *)(CYG_ADDRESS)flash_end;
887 FLASH_Enable(fis_ptr, fis_end);
888 area_start = fis_ptr;
889 while (fis_ptr < fis_end) {
890 flash_read(fis_ptr, &flash_data, sizeof(unsigned long), &err_addr);
891 if (flash_data != 0xFFFFFFFF) {
892 if (area_start != fis_ptr) {
893 // Assume that this is something
894 if ((fis_ptr - area_start) >= (length / sizeof(unsigned))) {
895 *addr = (CYG_ADDRESS)area_start;
899 // Find next blank block
900 area_start = fis_ptr;
901 while (area_start < fis_end) {
902 flash_read(area_start, &flash_data, sizeof(unsigned long), &err_addr);
903 if (flash_data == 0xFFFFFFFF) {
906 area_start += flash_block_size / sizeof(CYG_ADDRESS);
908 fis_ptr = area_start;
910 fis_ptr += flash_block_size / sizeof(CYG_ADDRESS);
913 FLASH_Disable((void *)((CYG_ADDRESS)flash_start +
914 CYGNUM_REDBOOT_FLASH_RESERVED_BASE), fis_end);
915 if (area_start != fis_ptr) {
916 if (fis_ptr - area_start >= length / sizeof(unsigned)) {
917 *addr = (CYG_ADDRESS)area_start;
923 struct free_chunk chunks[CYGDAT_REDBOOT_FIS_MAX_FREE_CHUNKS];
926 num_chunks = find_free(chunks);
927 for (idx = 0; idx < num_chunks; idx++) {
928 if (chunks[idx].end + 1 - chunks[idx].start >= length) {
929 *addr = (CYG_ADDRESS)chunks[idx].start;
938 fis_create(int argc, char *argv[])
941 unsigned long length, img_size;
942 CYG_ADDRESS mem_addr, exec_addr, flash_addr, entry_addr;
944 bool mem_addr_set = false;
945 bool exec_addr_set = false;
946 bool entry_addr_set = false;
947 bool flash_addr_set = false;
948 bool length_set = false;
949 bool img_size_set = false;
950 bool no_copy = false;
952 struct fis_image_desc *img = NULL;
953 bool defaults_assumed;
954 struct option_info opts[7];
957 init_opts(&opts[0], 'b', true, OPTION_ARG_TYPE_NUM,
958 &mem_addr, &mem_addr_set, "memory base address");
959 init_opts(&opts[1], 'r', true, OPTION_ARG_TYPE_NUM,
960 &exec_addr, &exec_addr_set, "ram base address");
961 init_opts(&opts[2], 'e', true, OPTION_ARG_TYPE_NUM,
962 &entry_addr, &entry_addr_set, "entry point address");
963 init_opts(&opts[3], 'f', true, OPTION_ARG_TYPE_NUM,
964 &flash_addr, &flash_addr_set, "FLASH memory base address");
965 init_opts(&opts[4], 'l', true, OPTION_ARG_TYPE_NUM,
966 &length, &length_set, "image length [in FLASH]");
967 init_opts(&opts[5], 's', true, OPTION_ARG_TYPE_NUM,
968 &img_size, &img_size_set, "image size [actual data]");
969 init_opts(&opts[6], 'n', false, OPTION_ARG_TYPE_FLG,
970 &no_copy, NULL, "don't copy from RAM to FLASH, just update directory");
971 if (!scan_opts(argc, argv, 2, opts, 7, &name, OPTION_ARG_TYPE_STR, "file name")) {
972 fis_usage("invalid arguments");
976 fis_read_directory();
977 defaults_assumed = false;
979 // Search existing files to acquire defaults for params not specified:
980 img = fis_lookup(name, NULL);
982 // Found it, so get image size from there
986 defaults_assumed = true;
990 if (!mem_addr_set && (load_address >= (CYG_ADDRESS)ram_start) &&
991 (load_address_end) < (CYG_ADDRESS)ram_end) {
992 mem_addr = load_address;
994 defaults_assumed = true;
995 // Get entry address from loader, unless overridden
997 entry_addr = entry_address;
999 length = load_address_end - load_address;
1001 } else if (defaults_assumed && !img_size_set) {
1002 /* We got length from the FIS table, so the size of the
1003 actual loaded image becomes img_size */
1004 img_size = load_address_end - load_address;
1005 img_size_set = true;
1008 // Get the remaining fall-back values from the fis
1010 if (!exec_addr_set) {
1011 // Preserve "normal" behaviour
1012 exec_addr_set = true;
1013 exec_addr = flash_addr_set ? flash_addr : mem_addr;
1015 if (!flash_addr_set) {
1016 flash_addr_set = true;
1017 flash_addr = img->flash_base;
1018 defaults_assumed = true;
1022 if ((!no_copy && !mem_addr_set) || (no_copy && !flash_addr_set) ||
1023 !length_set || !name) {
1024 fis_usage("required parameter missing");
1027 if (!img_size_set) {
1030 // 'length' is size of FLASH image, 'img_size' is actual data size
1031 // Round up length to FLASH block size
1032 #ifndef CYGPKG_HAL_MIPS // FIXME: compiler is b0rken
1033 length = ((length + flash_block_size - 1) / flash_block_size) * flash_block_size;
1034 if (length < img_size) {
1035 diag_printf("Invalid FLASH image size/length combination\n");
1039 if (flash_addr_set &&
1040 ((stat = flash_verify_addr((void *)flash_addr)) ||
1041 (stat = flash_verify_addr((void *)(flash_addr + length - 1))))) {
1042 _show_invalid_flash_address(flash_addr, stat);
1045 if (flash_addr_set && ((flash_addr & (flash_block_size - 1)) != 0)) {
1046 diag_printf("Invalid FLASH address: %p\n", (void *)flash_addr);
1047 diag_printf(" must be 0x%x aligned\n", flash_block_size);
1050 if (strlen(name) >= sizeof(img->u.name)) {
1051 diag_printf("Name is too long, must be less than %d chars\n",
1052 sizeof(img->u.name));
1056 if ((mem_addr < (CYG_ADDRESS)ram_start) ||
1057 ((mem_addr+img_size) >= (CYG_ADDRESS)ram_end)) {
1058 diag_printf("** WARNING: RAM address: %p may be invalid\n", (void *)mem_addr);
1059 diag_printf(" valid range is %p-%p\n", (void *)ram_start, (void *)ram_end);
1061 if (!flash_addr_set && !fis_find_free(&flash_addr, length)) {
1062 diag_printf("Can't locate %lx(%ld) bytes free in FLASH\n", length, length);
1066 // First, see if the image by this name has agreable properties
1068 if (flash_addr_set && (img->flash_base != flash_addr)) {
1069 diag_printf("Image found, but flash address (%p)\n"
1070 " is incorrect (present image location %p)\n",
1071 (void *)flash_addr, (void *)img->flash_base);
1075 if (img->size != length) {
1076 diag_printf("Image found, but length (0x%lx, necessitating image size 0x%lx)\n"
1077 " is incorrect (present image size 0x%lx)\n",
1078 img_size, length, img->size);
1081 if (!verify_action("An image named '%s' exists", name)) {
1084 if (defaults_assumed) {
1086 !verify_action("* CAUTION * about to program '%s'\n at %p..%p from %p",
1087 name, (void *)flash_addr,
1088 (void *)(flash_addr + img_size - 1),
1089 (void *)mem_addr)) {
1090 return; // The guy gave up
1095 #ifdef CYGDAT_REDBOOT_FIS_MAX_FREE_CHUNKS
1096 // Make sure that any FLASH address specified directly is truly free
1097 if (flash_addr_set && !no_copy) {
1098 struct free_chunk chunks[CYGDAT_REDBOOT_FIS_MAX_FREE_CHUNKS];
1099 int idx, num_chunks;
1100 bool is_free = false;
1102 num_chunks = find_free(chunks);
1103 for (idx = 0; idx < num_chunks; idx++) {
1104 if ((flash_addr >= chunks[idx].start) &&
1105 ((flash_addr + length - 1) <= chunks[idx].end)) {
1110 diag_printf("Invalid FLASH address - not free!\n");
1115 // If not image by that name, try and find an empty slot
1116 img = fis_work_block;
1117 for (i = 0; i < fisdir_size / sizeof(*img); i++, img++) {
1118 if (img->u.name[0] == 0xFF) {
1122 if (i >= fisdir_size / sizeof(*img)) {
1123 diag_printf("Can't find an empty slot in FIS directory!\n");
1128 // Safety check - make sure the address range is not within the code we're running
1129 if (flash_code_overlaps((void *)flash_addr,
1130 (void *)(flash_addr + img_size - 1))) {
1131 diag_printf("Can't program this region - contains code in use!\n");
1135 FLASH_Enable((void *)flash_addr, (void *)(flash_addr + length));
1136 // Erase area to be programmed
1137 stat = flash_erase((void *)flash_addr, length, &err_addr);
1138 FLASH_Disable((void *)flash_addr, (void *)(flash_addr + length));
1140 diag_printf("Can't erase region at %p: %s\n", err_addr, flash_errmsg(stat));
1146 FLASH_Enable((void *)flash_addr, (void *)(flash_addr + length));
1147 stat = FLASH_PROGRAM((void *)flash_addr, (void *)mem_addr,
1148 img_size, &err_addr);
1149 FLASH_Disable((void *)flash_addr, (void *)(flash_addr + length));
1151 diag_printf("Can't program region at %p: %s\n", err_addr, flash_errmsg(stat));
1158 memset(img, 0, sizeof(*img));
1159 strcpy(img->u.name, name);
1160 img->flash_base = flash_addr;
1161 img->mem_base = exec_addr_set ? exec_addr : (mem_addr_set ? mem_addr : flash_addr);
1162 img->entry_point = entry_addr_set ? entry_addr : (CYG_ADDRESS)entry_address; // Hope it's been set
1164 img->data_length = img_size;
1165 #ifdef CYGSEM_REDBOOT_FIS_CRC_CHECK
1167 img->file_cksum = cyg_crc32((unsigned char *)mem_addr, img_size);
1169 // No way to compute this, sorry
1170 img->file_cksum = 0;
1173 fis_start_update_directory(0);
1174 fis_update_directory(0, 0);
1178 extern void arm_fis_delete(char *);
1180 fis_delete(int argc, char *argv[])
1183 int num_reserved, i, stat;
1185 struct fis_image_desc *img;
1187 if (!scan_opts(argc, argv, 2, 0, 0, &name, OPTION_ARG_TYPE_STR, "image name")) {
1188 fis_usage("invalid arguments");
1191 #ifdef CYGHWR_REDBOOT_ARM_FLASH_SIB
1192 // FIXME: this is somewhat half-baked
1193 arm_fis_delete(name);
1196 img = (struct fis_image_desc *)fis_work_block;
1198 #ifdef CYGOPT_REDBOOT_FIS_RESERVED_BASE
1201 #ifdef CYGOPT_REDBOOT_FIS_REDBOOT
1204 #ifdef CYGOPT_REDBOOT_FIS_REDBOOT_BACKUP
1207 #ifdef CYGOPT_REDBOOT_FIS_REDBOOT_POST
1210 #if defined(CYGSEM_REDBOOT_FLASH_CONFIG) && defined(CYGHWR_REDBOOT_FLASH_CONFIG_MEDIA_FLASH)
1213 #if 1 // And the descriptor for the descriptor table itself
1217 img = fis_lookup(name, &i);
1219 if (i < num_reserved) {
1220 diag_printf("Sorry, '%s' is a reserved image and cannot be deleted\n", img->u.name);
1223 if (!verify_action("Delete image '%s'", name)) {
1227 diag_printf("No image '%s' found\n", name);
1230 // Erase Data blocks (free space)
1231 if ((stat = flash_erase((void *)img->flash_base, img->size, &err_addr)) != 0) {
1232 diag_printf("Error erasing at %p: %s\n", err_addr, flash_errmsg(stat));
1234 img->u.name[0] = 0xFF;
1235 fis_start_update_directory(0);
1236 fis_update_directory(0, 0);
1241 fis_load(int argc, char *argv[])
1244 struct fis_image_desc *img;
1245 CYG_ADDRESS mem_addr;
1246 bool mem_addr_set = false;
1247 bool show_cksum = false;
1248 bool load_ce = false;
1249 struct option_info opts[4];
1250 #if defined(CYGSEM_REDBOOT_FIS_CRC_CHECK)
1251 unsigned long cksum;
1253 int num_options = 0;
1254 #if defined(CYGPRI_REDBOOT_ZLIB_FLASH) || defined(CYGSEM_REDBOOT_FIS_CRC_CHECK)
1255 bool decompress = false;
1259 init_opts(&opts[num_options++], 'b', true, OPTION_ARG_TYPE_NUM,
1260 &mem_addr, &mem_addr_set, "memory [load] base address");
1261 init_opts(&opts[num_options++], 'c', false, OPTION_ARG_TYPE_FLG,
1262 &show_cksum, NULL, "display checksum");
1263 #ifdef CYGBLD_BUILD_REDBOOT_WITH_WINCE_SUPPORT
1264 init_opts(&opts[num_options++], 'w', false, OPTION_ARG_TYPE_FLG,
1265 &load_ce, NULL, "parse as Windows CE image");
1267 #ifdef CYGPRI_REDBOOT_ZLIB_FLASH
1268 init_opts(&opts[num_options++], 'd', false, OPTION_ARG_TYPE_FLG,
1269 &decompress, 0, "decompress");
1272 CYG_ASSERT(num_options <= num_options, "Too many options");
1274 if (!scan_opts(argc, argv, 2, opts, num_options, &name,
1275 OPTION_ARG_TYPE_STR, "image name")) {
1276 fis_usage("invalid arguments");
1279 if ((img = fis_lookup(name, NULL)) == NULL) {
1280 diag_printf("No image '%s' found\n", name);
1283 if (!mem_addr_set || load_ce) {
1284 mem_addr = img->mem_base;
1286 // Load image from FLASH into RAM
1287 #ifdef CYGSEM_REDBOOT_VALIDATE_USER_RAM_LOADS
1288 if (!valid_address((void *)mem_addr)) {
1290 diag_printf("Not a loadable image - try using -b ADDRESS option\n");
1292 diag_printf("Not a loadable image\n");
1297 #ifdef CYGBLD_BUILD_REDBOOT_WITH_WINCE_SUPPORT
1300 diag_printf("Warning: -b argument ignored for Windows CE image\n");
1302 FLASH_Enable((void *)img->flash_base, (void *)(img->flash_base + img->size));
1303 if (!ce_is_bin_image((void *)img->flash_base, img->size)) {
1304 diag_printf("** Error: This does not seem to be a valid Windows CE image\n");
1307 if (!ce_bin_load((void *)img->flash_base, img->size)) {
1308 diag_printf("** Error: Failed to load Windows CE image\n");
1310 FLASH_Disable((void *)img->flash_base, (void *)(img->flash_base + img->size));
1311 // Set load address/top
1312 load_address = mem_addr;
1313 load_address_end = mem_addr + img->data_length;
1317 #ifdef CYGPRI_REDBOOT_ZLIB_FLASH
1320 _pipe_t fis_load_pipe;
1321 _pipe_t *p = &fis_load_pipe;
1322 p->out_buf = (unsigned char*) mem_addr;
1323 p->out_max = p->out_size = -1;
1324 p->in_buf = (unsigned char*) img->flash_base;
1325 p->in_avail = img->data_length;
1327 err = (*_dc_init)(p);
1330 err = (*_dc_inflate)(p);
1332 // Free used resources, do final translation of
1334 err = (*_dc_close)(p, err);
1336 if (0 != err && p->msg) {
1337 diag_printf("decompression error: %s\n", p->msg);
1339 diag_printf("Image loaded from %p-%p\n", (unsigned char *)mem_addr, p->out_buf);
1342 // Set load address/top
1343 load_address = mem_addr;
1344 load_address_end = (unsigned long)p->out_buf;
1346 // Reload fis directory
1347 fis_read_directory();
1348 } else // dangling block
1353 FLASH_Enable((void *)img->flash_base, (void *)(img->flash_base + img->size));
1354 err = flash_read((void *)img->flash_base, (void *)mem_addr,
1355 img->data_length, &err_addr);
1356 FLASH_Disable((void *)img->flash_base, (void *)(img->flash_base + img->size));
1357 if (err != FLASH_ERR_OK) {
1358 diag_printf("** Error: Failed to load image from flash\n");
1362 // Set load address/top
1363 load_address = mem_addr;
1364 load_address_end = mem_addr + img->data_length;
1366 entry_address = (unsigned long)img->entry_point;
1368 #ifdef CYGSEM_REDBOOT_FIS_CRC_CHECK
1369 cksum = cyg_crc32((unsigned char *)mem_addr, img->data_length);
1371 diag_printf("Checksum: 0x%08lx\n", cksum);
1373 // When decompressing, leave CRC checking to decompressor
1374 if (!decompress && img->file_cksum) {
1375 if (cksum != img->file_cksum) {
1376 diag_printf("** Warning - checksum failure. stored: 0x%08lx, computed: 0x%08lx\n",
1377 img->file_cksum, cksum);
1378 entry_address = (unsigned long)NO_MEMORY;
1382 diag_printf("image loaded 0x%08lx-0x%08lx, assumed entry at 0x%08lx\n",
1383 load_address, load_address_end - 1, entry_address);
1385 #endif // CYGOPT_REDBOOT_FIS
1388 fis_write(int argc, char *argv[])
1391 unsigned long length;
1392 CYG_ADDRESS mem_addr, flash_addr;
1393 bool mem_addr_set = false;
1394 bool flash_addr_set = false;
1395 bool length_set = false;
1397 struct option_info opts[3];
1400 init_opts(&opts[0], 'b', true, OPTION_ARG_TYPE_NUM,
1401 &mem_addr, &mem_addr_set, "memory base address");
1402 init_opts(&opts[1], 'f', true, OPTION_ARG_TYPE_NUM,
1403 &flash_addr, &flash_addr_set, "FLASH memory base address");
1404 init_opts(&opts[2], 'l', true, OPTION_ARG_TYPE_NUM,
1405 &length, &length_set, "image length [in FLASH]");
1406 if (!scan_opts(argc, argv, 2, opts, 3, 0, 0, 0))
1408 fis_usage("invalid arguments");
1412 if (!mem_addr_set || !flash_addr_set || !length_set) {
1413 fis_usage("required parameter missing");
1417 // Round up length to FLASH block size
1418 #ifndef CYGPKG_HAL_MIPS // FIXME: compiler is b0rken
1419 length = ((length + flash_block_size - 1) / flash_block_size) * flash_block_size;
1421 if (flash_addr_set &&
1422 ((stat = flash_verify_addr((void *)flash_addr)) ||
1423 (stat = flash_verify_addr((void *)(flash_addr + length - 1))))) {
1424 _show_invalid_flash_address(flash_addr, stat);
1427 if (flash_addr_set && flash_addr & (flash_block_size-1)) {
1428 diag_printf("Invalid FLASH address: %p\n", (void *)flash_addr);
1429 diag_printf(" must be 0x%x aligned\n", flash_block_size);
1432 if ((mem_addr < (CYG_ADDRESS)ram_start) ||
1433 ((mem_addr + length) >= (CYG_ADDRESS)ram_end)) {
1434 diag_printf("** WARNING: RAM address: %p may be invalid\n", (void *)mem_addr);
1435 diag_printf(" valid range is %p-%p\n", (void *)ram_start, (void *)ram_end);
1437 // Safety check - make sure the address range is not within the code we're running
1438 if (flash_code_overlaps((void *)flash_addr, (void *)(flash_addr + length - 1))) {
1439 diag_printf("Can't program this region - contains code in use!\n");
1442 if (!verify_action("* CAUTION * about to program FLASH\n at %p..%p from %p",
1443 (void *)flash_addr, (void *)(flash_addr + length - 1),
1444 (void *)mem_addr)) {
1445 return; // The guy gave up
1449 // Erase area to be programmed
1450 if ((stat = flash_erase((void *)flash_addr, length, &err_addr)) != 0) {
1451 diag_printf("Can't erase region at %p: %s\n", err_addr, flash_errmsg(stat));
1457 stat = FLASH_PROGRAM((void *)flash_addr, (void *)mem_addr, length, &err_addr);
1459 diag_printf("Can't program region at %p: %s\n", err_addr, flash_errmsg(stat));
1466 fis_erase(int argc, char *argv[])
1469 unsigned long length;
1470 CYG_ADDRESS flash_addr;
1471 bool flash_addr_set = false;
1472 bool length_set = false;
1474 struct option_info opts[2];
1476 init_opts(&opts[0], 'f', true, OPTION_ARG_TYPE_NUM,
1477 &flash_addr, &flash_addr_set, "FLASH memory base address");
1478 init_opts(&opts[1], 'l', true, OPTION_ARG_TYPE_NUM,
1479 &length, &length_set, "length");
1480 if (!scan_opts(argc, argv, 2, opts, 2, NULL, 0, NULL))
1482 fis_usage("invalid arguments");
1486 if (!flash_addr_set || !length_set) {
1487 fis_usage("missing argument");
1490 if (flash_addr_set &&
1491 ((stat = flash_verify_addr((void *)flash_addr)) ||
1492 (stat = flash_verify_addr((void *)(flash_addr + length - 1))))) {
1493 _show_invalid_flash_address(flash_addr, stat);
1496 if (flash_addr_set && flash_addr & (flash_block_size-1)) {
1497 diag_printf("Invalid FLASH address: %p\n", (void *)flash_addr);
1498 diag_printf(" must be 0x%x aligned\n", flash_block_size);
1501 // Safety check - make sure the address range is not within the code we're running
1502 if (flash_code_overlaps((void *)flash_addr, (void *)(flash_addr + length - 1))) {
1503 diag_printf("Can't erase this region - contains code in use!\n");
1506 if ((stat = flash_erase((void *)flash_addr, length, &err_addr)) != 0) {
1507 diag_printf("Error erasing at %p: %s\n", err_addr, flash_errmsg(stat));
1511 #ifdef CYGHWR_IO_FLASH_BLOCK_LOCKING
1514 fis_lock(int argc, char *argv[])
1518 unsigned long length;
1519 CYG_ADDRESS flash_addr;
1520 bool flash_addr_set = false;
1521 bool length_set = false;
1523 struct option_info opts[2];
1525 init_opts(&opts[0], 'f', true, OPTION_ARG_TYPE_NUM,
1526 &flash_addr, &flash_addr_set, "FLASH memory base address");
1527 init_opts(&opts[1], 'l', true, OPTION_ARG_TYPE_NUM,
1528 &length, &length_set, "length");
1529 if (!scan_opts(argc, argv, 2, opts, 2, &name, OPTION_ARG_TYPE_STR, "image name")) {
1530 fis_usage("invalid arguments");
1533 #ifdef CYGOPT_REDBOOT_FIS
1534 /* Get parameters from image if specified */
1536 struct fis_image_desc *img;
1537 if ((img = fis_lookup(name, NULL)) == NULL) {
1538 diag_printf("No image '%s' found\n", name);
1542 flash_addr = img->flash_base;
1546 if (!flash_addr_set || !length_set) {
1547 fis_usage("missing argument");
1550 if (flash_addr_set &&
1551 ((stat = flash_verify_addr((void *)flash_addr)) ||
1552 (stat = flash_verify_addr((void *)(flash_addr + length - 1))))) {
1553 _show_invalid_flash_address(flash_addr, stat);
1556 if ((stat = flash_lock((void *)flash_addr, length, &err_addr)) != 0) {
1557 diag_printf("Error locking at %p: %s\n", err_addr, flash_errmsg(stat));
1562 fis_unlock(int argc, char *argv[])
1566 unsigned long length;
1567 CYG_ADDRESS flash_addr;
1568 bool flash_addr_set = false;
1569 bool length_set = false;
1571 struct option_info opts[2];
1573 init_opts(&opts[0], 'f', true, OPTION_ARG_TYPE_NUM,
1574 &flash_addr, &flash_addr_set, "FLASH memory base address");
1575 init_opts(&opts[1], 'l', true, OPTION_ARG_TYPE_NUM,
1576 &length, &length_set, "length");
1577 if (!scan_opts(argc, argv, 2, opts, 2, &name, OPTION_ARG_TYPE_STR, "image name")) {
1578 fis_usage("invalid arguments");
1581 #ifdef CYGOPT_REDBOOT_FIS
1583 struct fis_image_desc *img;
1584 if ((img = fis_lookup(name, NULL)) == NULL) {
1585 diag_printf("No image '%s' found\n", name);
1589 flash_addr = img->flash_base;
1593 if (!flash_addr_set || !length_set) {
1594 fis_usage("missing argument");
1597 if (flash_addr_set &&
1598 ((stat = flash_verify_addr((void *)flash_addr)) ||
1599 (stat = flash_verify_addr((void *)(flash_addr + length - 1))))) {
1600 _show_invalid_flash_address(flash_addr, stat);
1604 if ((stat = flash_unlock((void *)flash_addr, length, &err_addr)) != 0) {
1605 diag_printf("Error unlocking at %p: %s\n", err_addr, flash_errmsg(stat));
1610 // This is set non-zero if the FLASH subsystem has successfully been initialized
1611 int __flash_init = 0;
1616 if (!__flash_init) return;
1617 diag_printf("FLASH: %p - 0x%x, %d blocks of 0x%08x bytes each.\n",
1618 flash_start, (CYG_ADDRWORD)flash_end + 1, flash_num_blocks, flash_block_size);
1621 /* Returns -1 on failure, 0 on success, 1 if it was successfull
1622 but a failed fis update was detected */
1628 #ifdef CYGOPT_REDBOOT_REDUNDANT_FIS
1629 struct fis_image_desc img0;
1630 struct fis_image_desc img1;
1631 int fis_update_was_interrupted = 0;
1634 //check the size of fis_valid_info
1635 CYG_ASSERT((sizeof(struct fis_valid_info) <= sizeof(img0.u.name)),
1636 "fis_valid_info size mismatch");
1637 //try to check the alignment of version_count
1638 CYG_ASSERT(((&img0.u.valid_info.version_count - &img0) % sizeof(unsigned long) == 0),
1639 "alignment problem");
1641 if (!__flash_init) {
1643 if ((stat = flash_init(diag_printf)) != 0) {
1644 diag_printf("FLASH: driver init failed: %s\n", flash_errmsg(stat));
1647 flash_get_limits(NULL, &flash_start, &flash_end);
1648 // Keep 'end' address as last valid location, to avoid wrap around problems
1649 flash_end = (void *)((CYG_ADDRESS)flash_end - 1);
1650 flash_get_block_info(&flash_block_size, &flash_num_blocks);
1651 #ifdef CYGOPT_REDBOOT_FIS
1652 fisdir_size = CYGNUM_REDBOOT_FIS_DIRECTORY_ENTRY_COUNT * CYGNUM_REDBOOT_FIS_DIRECTORY_ENTRY_SIZE;
1653 fisdir_size = ((fisdir_size + flash_block_size - 1) / flash_block_size) * flash_block_size;
1654 # if defined(CYGPRI_REDBOOT_ZLIB_FLASH) && defined(CYGOPT_REDBOOT_FIS_ZLIB_COMMON_BUFFER)
1655 fis_work_block = fis_zlib_common_buffer;
1656 if (CYGNUM_REDBOOT_FIS_ZLIB_COMMON_BUFFER_SIZE < fisdir_size) {
1657 diag_printf("FLASH: common buffer too small\n");
1661 workspace_end = (unsigned char *)(workspace_end - fisdir_size);
1662 fis_work_block = workspace_end;
1664 if (CYGNUM_REDBOOT_FIS_DIRECTORY_BLOCK < 0) {
1665 fis_addr = (void *)((CYG_ADDRESS)flash_end + 1 +
1666 (CYGNUM_REDBOOT_FIS_DIRECTORY_BLOCK * flash_block_size));
1668 fis_addr = (void *)((CYG_ADDRESS)flash_start +
1669 (CYGNUM_REDBOOT_FIS_DIRECTORY_BLOCK * flash_block_size));
1671 #if defined(CYGHWR_DEVS_FLASH_MXC_MULTI) && defined(MXCFLASH_SELECT_NAND)
1672 extern int mxc_nand_fis_start(void);
1673 if (IS_FIS_FROM_NAND()) {
1674 fis_addr = (void *)((CYG_ADDRESS)flash_start + mxc_nand_fis_start());
1678 #if defined(IMXFLASH_SELECT_SPI_NOR)
1679 extern int mxc_spi_nor_fis_start(void);
1680 if (IS_FIS_FROM_SPI_NOR()) {
1681 fis_addr = (void *)((CYG_ADDRESS)flash_start + mxc_spi_nor_fis_start());
1685 #if defined(MXCFLASH_SELECT_MMC)
1686 if (IS_FIS_FROM_MMC()) {
1687 fis_addr = (void *)REDBOOT_IMAGE_SIZE;
1691 if (((CYG_ADDRESS)fis_addr + fisdir_size - 1) > (CYG_ADDRESS)flash_end) {
1692 diag_printf("FIS directory doesn't fit\n");
1695 #ifdef CYGOPT_REDBOOT_REDUNDANT_FIS
1697 if (CYGNUM_REDBOOT_FIS_REDUNDANT_DIRECTORY_BLOCK < 0) {
1698 redundant_fis_addr = (void *)((CYG_ADDRESS)flash_end + 1 +
1699 (CYGNUM_REDBOOT_FIS_REDUNDANT_DIRECTORY_BLOCK *
1702 redundant_fis_addr = (void *)((CYG_ADDRESS)flash_start +
1703 (CYGNUM_REDBOOT_FIS_REDUNDANT_DIRECTORY_BLOCK *
1707 if (((CYG_ADDRESS)redundant_fis_addr + fisdir_size - 1) > (CYG_ADDRESS)flash_end) {
1708 diag_printf("Redundant FIS directory doesn't fit\n");
1711 FLASH_READ(fis_addr, &img0, sizeof(img0), &err_addr);
1712 FLASH_READ(redundant_fis_addr, &img1, sizeof(img1), &err_addr);
1714 if (strncmp(img0.u.valid_info.magic_name, CYG_REDBOOT_RFIS_VALID_MAGIC,
1715 CYG_REDBOOT_RFIS_VALID_MAGIC_LENGTH) != 0) {
1716 memset(&img0, 0, sizeof(img0));
1719 if (strncmp(img1.u.valid_info.magic_name, CYG_REDBOOT_RFIS_VALID_MAGIC,
1720 CYG_REDBOOT_RFIS_VALID_MAGIC_LENGTH) != 0) {
1721 memset(&img1, 0, sizeof(img0));
1724 #ifdef REDBOOT_FLASH_REVERSE_BYTEORDER
1725 img0.u.valid_info.version_count = CYG_SWAP32(img0.u.valid_info.version_count);
1726 img1.u.valid_info.version_count = CYG_SWAP32(img1.u.valid_info.version_count);
1729 if (fis_get_valid_buf(&img0, &img1, &fis_update_was_interrupted) == 1) {
1730 // Valid, so swap primary and secondary
1733 fis_addr = redundant_fis_addr;
1734 redundant_fis_addr = tmp;
1737 fis_read_directory();
1740 #ifdef CYGOPT_REDBOOT_REDUNDANT_FIS
1741 if (fis_update_was_interrupted)
1750 // Wrapper to avoid compiler warnings
1752 _do_flash_init(void)
1754 static int init_done = 0;
1755 if (init_done) return;
1760 RedBoot_init(_do_flash_init, RedBoot_INIT_FIRST);
1763 do_fis(int argc, char *argv[])
1768 fis_usage("too few arguments");
1771 if (do_flash_init() < 0) {
1772 diag_printf("Sorry, no FLASH memory is available\n");
1775 if ((cmd = cmd_search(__FIS_cmds_TAB__, &__FIS_cmds_TAB_END__,
1776 argv[1])) != NULL) {
1777 (cmd->fun)(argc, argv);
1780 fis_usage("unrecognized command");