]> git.kernelconcepts.de Git - karo-tx-redboot.git/blobdiff - packages/redboot/v2_0/src/flash.c
unified MX27, MX25, MX37 trees
[karo-tx-redboot.git] / packages / redboot / v2_0 / src / flash.c
index 5a2cbfc492f8d386e87f925ff0d0aed44ca01d61..5517631a8f8b68672c3fd95c74724a5eb2f33c59 100644 (file)
@@ -1,8 +1,8 @@
 //==========================================================================
 //
-//      flash.c
+//     flash.c
 //
-//      RedBoot - FLASH memory support
+//     RedBoot - FLASH memory support
 //
 //==========================================================================
 //####ECOSGPLCOPYRIGHTBEGIN####
 //==========================================================================
 //#####DESCRIPTIONBEGIN####
 //
-// Author(s):    gthomas
+// Author(s):   gthomas
 // Contributors: gthomas, tkoeller
-// Date:         2000-07-28
-// Purpose:      
-// Description:  
-//              
+// Date:        2000-07-28
+// Purpose:
+// Description:
+//
 // This code is part of RedBoot (tm).
 //
 //####DESCRIPTIONEND####
 //==========================================================================
 
 #include <redboot.h>
+#define         _FLASH_PRIVATE_
 #include <cyg/io/flash.h>
 #include <fis.h>
 #include <sib.h>
-#include <cyg/infra/cyg_ass.h>         // assertion macros
+#include <cyg/infra/cyg_ass.h>        // assertion macros
+
+#ifdef CYGBLD_BUILD_REDBOOT_WITH_WINCE_SUPPORT
+#include <wince.h>
+#endif
 
 #ifdef CYGSEM_REDBOOT_FLASH_COMBINED_FIS_AND_CONFIG
 // Note horrid intertwining of functions, to save precious FLASH
@@ -70,10 +75,10 @@ extern void conf_endian_fixup(void *p);
 #ifdef CYGOPT_REDBOOT_FIS
 // Image management functions
 local_cmd_entry("init",
-                "Initialize FLASH Image System [FIS]",
-                "[-f]",
-                fis_init,
-                FIS_cmds
+               "Initialize FLASH Image System [FIS]",
+               "[-f]",
+               fis_init,
+               FIS_cmds
     );
 #ifdef CYGSEM_REDBOOT_FIS_CRC_CHECK
 # define FIS_LIST_OPTS "[-c] [-d]"
@@ -81,71 +86,84 @@ local_cmd_entry("init",
 # define FIS_LIST_OPTS "[-d]"
 #endif
 local_cmd_entry("list",
-                "Display contents of FLASH Image System [FIS]",
-                FIS_LIST_OPTS,
-                fis_list,
-                FIS_cmds
+               "Display contents of FLASH Image System [FIS]",
+               FIS_LIST_OPTS,
+               fis_list,
+               FIS_cmds
     );
 local_cmd_entry("free",
-                "Display free [available] locations within FLASH Image System [FIS]",
-                "",
-                fis_free,
-                FIS_cmds
+               "Display free [available] locations within FLASH Image System [FIS]",
+               "",
+               fis_free,
+               FIS_cmds
     );
 local_cmd_entry("delete",
-                "Delete an image from FLASH Image System [FIS]",
-                "name",
-                fis_delete,
-                FIS_cmds
+               "Delete an image from FLASH Image System [FIS]",
+               "name",
+               fis_delete,
+               FIS_cmds
     );
 
-static char fis_load_usage[] = 
+static char fis_load_usage[] =
+#ifdef CYGPRI_REDBOOT_ZLIB_FLASH
+                     "[-d] "
+#endif
+                     "[-b <memory_load_address>] [-c] "
+#ifdef CYGBLD_BUILD_REDBOOT_WITH_WINCE_SUPPORT
+                     "[-w]"
+#endif
+                     "name\n"
+                     "Options:\n"
 #ifdef CYGPRI_REDBOOT_ZLIB_FLASH
-                      "[-d] "
+                     "\t-d: decompress\n"
+#endif
+                     "\t-c: print checksum\n"
+#ifdef CYGBLD_BUILD_REDBOOT_WITH_WINCE_SUPPORT
+                     "\t-w: load as Windows CE image\n"
 #endif
-                      "[-b <memory_load_address>] [-c] name";
+                     ;
 
 local_cmd_entry("load",
-                "Load image from FLASH Image System [FIS] into RAM",
-                fis_load_usage,
-                fis_load,
-                FIS_cmds
+               "Load image from FLASH Image System [FIS] into RAM",
+               fis_load_usage,
+               fis_load,
+               FIS_cmds
     );
 local_cmd_entry("create",
-                "Create an image",
-                "[-b <mem_base>] [-l <image_length>] [-s <data_length>]\n"
-                "      [-f <flash_addr>] [-e <entry_point>] [-r <ram_addr>] [-n] <name>",
-                fis_create,
-                FIS_cmds
+               "Create an image",
+               "[-b <mem_base>] [-l <image_length>] [-s <data_length>]\n"
+               "      [-f <flash_addr>] [-e <entry_point>] [-r <ram_addr>] [-n] <name>",
+               fis_create,
+               FIS_cmds
     );
 #endif
 
 // Raw flash access functions
 local_cmd_entry("erase",
-                "Erase FLASH contents",
-                "-f <flash_addr> -l <length>",
-                fis_erase,
-                FIS_cmds
+               "Erase FLASH contents",
+               "-f <flash_addr> -l <length>",
+               fis_erase,
+               FIS_cmds
     );
 #ifdef CYGHWR_IO_FLASH_BLOCK_LOCKING
 local_cmd_entry("lock",
-                "LOCK FLASH contents",
-                "[-f <flash_addr> -l <length>] [name]",
-                fis_lock,
-                FIS_cmds
+               "LOCK FLASH contents",
+               "[-f <flash_addr> -l <length>] [name]",
+               fis_lock,
+               FIS_cmds
     );
 local_cmd_entry("unlock",
-                "UNLOCK FLASH contents",
-                "[-f <flash_addr> -l <length>] [name]",
-                fis_unlock,
-                FIS_cmds
+               "UNLOCK FLASH contents",
+               "[-f <flash_addr> -l <length>] [name]",
+               fis_unlock,
+               FIS_cmds
     );
 #endif
 local_cmd_entry("write",
-                "Write raw data directly to FLASH",
-                "-f <flash_addr> -b <mem_base> -l <image_length>",
-                fis_write,
-                FIS_cmds
+               "Write raw data directly to FLASH",
+               "-f <flash_addr> -b <mem_base> -l <image_length>",
+               fis_write,
+               FIS_cmds
     );
 
 // Define table boundaries
@@ -156,11 +174,11 @@ extern struct cmd __FIS_cmds_TAB__[], __FIS_cmds_TAB_END__;
 
 // CLI function
 static cmd_fun do_fis;
-RedBoot_nested_cmd("fis", 
-            "Manage FLASH images", 
-            "{cmds}",
-            do_fis,
-            __FIS_cmds_TAB__, &__FIS_cmds_TAB_END__
+RedBoot_nested_cmd("fis",
+           "Manage FLASH images",
+           "{cmds}",
+           do_fis,
+           __FIS_cmds_TAB__, &__FIS_cmds_TAB_END__
     );
 
 // Local data used by these routines
@@ -169,11 +187,14 @@ int flash_block_size, flash_num_blocks;
 #ifdef CYGOPT_REDBOOT_FIS
 void *fis_work_block;
 void *fis_addr;
+#ifdef CYGOPT_REDBOOT_REDUNDANT_FIS
+void *redundant_fis_addr;
+#endif
 int fisdir_size;  // Size of FIS directory.
 #endif
 #ifdef CYGSEM_REDBOOT_FLASH_CONFIG
-extern void *cfg_base;   // Location in Flash of config data
-extern int   cfg_size;   // Length of config data - rounded to Flash block size
+extern void *cfg_base;  // Location in Flash of config data
+extern int   cfg_size;  // Length of config data - rounded to Flash block size
 extern struct _config *config;
 #endif
 
@@ -184,11 +205,11 @@ fis_usage(char *why)
     cmd_usage(__FIS_cmds_TAB__, &__FIS_cmds_TAB_END__, "fis ");
 }
 
-static void        
+static void
 _show_invalid_flash_address(CYG_ADDRESS flash_addr, int stat)
 {
     diag_printf("Invalid FLASH address %p: %s\n", (void *)flash_addr, flash_errmsg(stat));
-    diag_printf("   valid range is %p-%p\n", (void *)flash_start, (void *)flash_end);
+    diag_printf("   valid range is %p-%p\n", flash_start, flash_end);
 }
 
 #ifdef CYGOPT_REDBOOT_FIS
@@ -202,14 +223,14 @@ static inline void fis_endian_fixup(void *addr)
     int cnt = fisdir_size / sizeof(struct fis_image_desc);
 
     while (cnt-- > 0) {
-        p->flash_base = CYG_SWAP32(p->flash_base);
-        p->mem_base = CYG_SWAP32(p->mem_base);
-        p->size = CYG_SWAP32(p->size);
-        p->entry_point = CYG_SWAP32(p->entry_point);
-        p->data_length = CYG_SWAP32(p->data_length);
-        p->desc_cksum = CYG_SWAP32(p->desc_cksum);
-        p->file_cksum = CYG_SWAP32(p->file_cksum);
-        p++;
+               p->flash_base = CYG_SWAP32(p->flash_base);
+               p->mem_base = CYG_SWAP32(p->mem_base);
+               p->size = CYG_SWAP32(p->size);
+               p->entry_point = CYG_SWAP32(p->entry_point);
+               p->data_length = CYG_SWAP32(p->data_length);
+               p->desc_cksum = CYG_SWAP32(p->desc_cksum);
+               p->file_cksum = CYG_SWAP32(p->file_cksum);
+               p++;
     }
 #endif
 }
@@ -219,7 +240,7 @@ fis_read_directory(void)
 {
     void *err_addr;
 
-    FLASH_READ(fis_addr, fis_work_block, fisdir_size, (void **)&err_addr);
+    FLASH_READ(fis_addr, fis_work_block, fisdir_size, &err_addr);
     fis_endian_fixup(fis_work_block);
 }
 
@@ -232,46 +253,208 @@ fis_lookup(char *name, int *num)
     fis_read_directory();
 
     img = (struct fis_image_desc *)fis_work_block;
-    for (i = 0;  i < fisdir_size/sizeof(*img);  i++, img++) {
-        if ((img->name[0] != (unsigned char)0xFF) && 
-            (strcasecmp(name, img->name) == 0)) {
-            if (num) *num = i;
-            return img;
-        }
-    }
-    return (struct fis_image_desc *)0;
+    for (i = 0;         i < fisdir_size/sizeof(*img);  i++, img++) {
+               if ((img->u.name[0] != 0xFF) &&
+                       (strcasecmp(name, img->u.name) == 0)) {
+                       if (num) *num = i;
+                       return img;
+               }
+    }
+    return NULL;
 }
 
-void
-fis_update_directory(void)
+int fis_start_update_directory(int autolock)
+{
+#ifdef CYGOPT_REDBOOT_REDUNDANT_FIS
+#ifdef CYGHWR_IO_FLASH_BLOCK_LOCKING
+#ifdef CYGSEM_REDBOOT_FLASH_LOCK_SPECIAL
+       // Ensure [quietly] that the directory is unlocked before trying to update and locked again afterwards
+       int do_autolock = 1;
+#else
+       int do_autolock = autolock;
+#endif
+#endif
+
+       struct fis_image_desc *img;
+       void *err_addr;
+       void *tmp_fis_addr;
+
+       /*exchange old and new valid fis tables*/
+       tmp_fis_addr = fis_addr;
+       fis_addr = redundant_fis_addr;
+       redundant_fis_addr = tmp_fis_addr;
+
+       //adjust the contents of the new fis table
+       img = fis_work_block;
+
+       memcpy(img->u.valid_info.magic_name, CYG_REDBOOT_RFIS_VALID_MAGIC,
+                  CYG_REDBOOT_RFIS_VALID_MAGIC_LENGTH);
+       img->u.valid_info.valid_flag[0] = CYG_REDBOOT_RFIS_IN_PROGRESS;
+       img->u.valid_info.valid_flag[1] = CYG_REDBOOT_RFIS_IN_PROGRESS;
+       img->u.valid_info.version_count = img->u.valid_info.version_count+1;
+
+       //ready to go....
+#ifdef CYGHWR_IO_FLASH_BLOCK_LOCKING
+       if (do_autolock)
+               flash_unlock((void *)fis_addr, fisdir_size, &err_addr);
+#endif
+
+       flash_erase(fis_addr, fisdir_size, &err_addr);
+       //now magic is 0xffffffff
+       fis_endian_fixup(fis_work_block);
+       flash_program(fis_addr, fis_work_block, flash_block_size, &err_addr);
+       fis_endian_fixup(fis_work_block);
+       //now magic is 0xff1234ff, valid is IN_PROGRESS, version_count is the old one +1
+
+#else
+       /* nothing to do here without redundant fis */
+#endif
+       return 0;
+
+}
+
+int
+fis_update_directory(int autolock, int error)
 {
+       void *err_addr;
+
+#ifdef CYGHWR_IO_FLASH_BLOCK_LOCKING
+#ifdef CYGSEM_REDBOOT_FLASH_LOCK_SPECIAL
+       // Ensure [quietly] that the directory is unlocked before trying to update and locked again afterwards
+       int do_autolock = 1;
+#else
+       int do_autolock = autolock;
+#endif
+#endif
+
+#ifdef CYGOPT_REDBOOT_REDUNDANT_FIS
+
+       struct fis_image_desc *img = fis_work_block;
+
+       // called from invalid state
+       if (img->u.valid_info.valid_flag[0] != CYG_REDBOOT_RFIS_IN_PROGRESS)
+               return -1;
+
+       //if it failed, reset is0Valid to the state before startUpdateDirectory()
+       //g_data.fisTable hasn't been changed yet, so it doesn't have to be reset now
+       //then reread the contents from flash
+       //setting the valid flag of the failed table to "INVALID" might also be not too bad
+       //but IN_PROGRESS is also good enough I think
+       if (error != 0) {
+               void *swap_fis_addr = fis_addr;
+               fis_addr = redundant_fis_addr;
+               redundant_fis_addr = swap_fis_addr;
+       } else {
+               //success
+               void *tmp_fis_addr = (void *)((CYG_ADDRESS)fis_addr +
+                                                                         CYG_REDBOOT_RFIS_VALID_MAGIC_LENGTH);
+
+               img->u.valid_info.valid_flag[0] = CYG_REDBOOT_RFIS_VALID;
+               img->u.valid_info.valid_flag[1] = CYG_REDBOOT_RFIS_VALID;
+
+               flash_program(tmp_fis_addr, img->u.valid_info.valid_flag,
+                                         sizeof(img->u.valid_info.valid_flag), &err_addr);
+       }
+#ifdef CYGHWR_IO_FLASH_BLOCK_LOCKING
+       if (do_autolock)
+               flash_lock((void *)fis_addr, fisdir_size, &err_addr);
+#endif
+
+#else // CYGOPT_REDBOOT_REDUNDANT_FIS
+    int blk_size = fisdir_size;
     int stat;
-    void *err_addr;
 
     fis_endian_fixup(fis_work_block);
 #ifdef CYGSEM_REDBOOT_FLASH_COMBINED_FIS_AND_CONFIG
     memcpy((char *)fis_work_block+fisdir_size, config, cfg_size);
     conf_endian_fixup((char *)fis_work_block+fisdir_size);
+    blk_size += cfg_size;
 #endif
-#ifdef CYGSEM_REDBOOT_FLASH_LOCK_SPECIAL
-    // Ensure [quietly] that the directory is unlocked before trying to update
-    flash_unlock((void *)fis_addr, flash_block_size, (void **)&err_addr);
+#ifdef CYGHWR_IO_FLASH_BLOCK_LOCKING
+    if (do_autolock)
+       flash_unlock((void *)fis_addr, blk_size, &err_addr);
 #endif
-    if ((stat = flash_erase(fis_addr, flash_block_size, (void **)&err_addr)) != 0) {
-        diag_printf("Error erasing FIS directory at %p: %s\n", err_addr, flash_errmsg(stat));
+    if ((stat = flash_erase(fis_addr, flash_block_size, &err_addr)) != 0) {
+               diag_printf("Error erasing FIS directory at %p: %s\n", err_addr, flash_errmsg(stat));
     } else {
-        if ((stat = FLASH_PROGRAM(fis_addr, fis_work_block,
-                                  flash_block_size, (void **)&err_addr)) != 0) {
-            diag_printf("Error writing FIS directory at %p: %s\n", 
-                        err_addr, flash_errmsg(stat));
-        }
+               if ((stat = FLASH_PROGRAM(fis_addr, fis_work_block,
+                                                                 flash_block_size, &err_addr)) != 0) {
+                       diag_printf("Error writing FIS directory at %p: %s\n",
+                                               err_addr, flash_errmsg(stat));
+               }
+    }
+    fis_endian_fixup(fis_work_block);
+#ifdef CYGHWR_IO_FLASH_BLOCK_LOCKING
+    if (do_autolock)
+               flash_lock((void *)fis_addr, blk_size, &err_addr);
+#endif
+
+#endif // CYGOPT_REDBOOT_REDUNDANT_FIS
+
+    return 0;
+}
+
+#ifdef CYGOPT_REDBOOT_REDUNDANT_FIS
+
+int
+fis_get_valid_buf(struct fis_image_desc *img0, struct fis_image_desc *img1, int *update_was_interrupted)
+{
+       *update_was_interrupted = 0;
+       if (strncmp(img1->u.valid_info.magic_name, CYG_REDBOOT_RFIS_VALID_MAGIC,
+                               CYG_REDBOOT_RFIS_VALID_MAGIC_LENGTH) != 0) {
+               //buf0 must be valid
+               if (img0->u.valid_info.version_count > 0) {
+                       *update_was_interrupted = 1;
+               }
+               return 0;
+       } else if (strncmp(img0->u.valid_info.magic_name, CYG_REDBOOT_RFIS_VALID_MAGIC,
+                                          CYG_REDBOOT_RFIS_VALID_MAGIC_LENGTH) != 0) {
+               //buf1 must be valid
+               if (img1->u.valid_info.version_count > 0) {
+                       *update_was_interrupted = 1;
+               }
+               return 1;
+       }
+       //magic is ok for both, now check the valid flag
+       if ((img1->u.valid_info.valid_flag[0] != CYG_REDBOOT_RFIS_VALID) ||
+               (img1->u.valid_info.valid_flag[1] != CYG_REDBOOT_RFIS_VALID)) {
+               //buf0 must be valid
+               *update_was_interrupted = 1;
+               return 0;
+       } else if ((img0->u.valid_info.valid_flag[0] != CYG_REDBOOT_RFIS_VALID) ||
+                          (img0->u.valid_info.valid_flag[1] != CYG_REDBOOT_RFIS_VALID)) {
+               //buf1 must be valid
+               *update_was_interrupted = 1;
+               return 1;
+       }
+
+       //now check the version
+       return img1->u.valid_info.version_count == (img0->u.valid_info.version_count + 1);
+}
+
+void
+fis_erase_redundant_directory(void)
+{
+    int stat;
+    void *err_addr;
+
+#ifdef CYGSEM_REDBOOT_FLASH_LOCK_SPECIAL
+    // Ensure [quietly] that the directory is unlocked before trying
+    // to update
+    flash_unlock((void *)redundant_fis_addr, fisdir_size,
+                &err_addr);
+#endif
+    if ((stat = flash_erase(redundant_fis_addr, fisdir_size,
+                           &err_addr)) != 0) {
+               diag_printf("Error erasing FIS directory at %p: %s\n",
+                                       err_addr, flash_errmsg(stat));
     }
 #ifdef CYGSEM_REDBOOT_FLASH_LOCK_SPECIAL
     // Ensure [quietly] that the directory is locked after the update
-    flash_lock((void *)fis_addr, flash_block_size, (void **)&err_addr);
+    flash_lock((void *)redundant_fis_addr, fisdir_size, &err_addr);
 #endif
-    fis_endian_fixup(fis_work_block);
 }
+#endif
 
 static void
 fis_init(int argc, char *argv[])
@@ -284,29 +467,39 @@ fis_init(int argc, char *argv[])
     CYG_ADDRESS redboot_flash_start;
     unsigned long redboot_image_size;
 
-    init_opts(&opts[0], 'f', false, OPTION_ARG_TYPE_FLG, 
-              (void *)&full_init, (bool *)0, "full initialization, erases all of flash");
-    if (!scan_opts(argc, argv, 2, opts, 1, 0, 0, ""))
-    {
-        return;
+    init_opts(&opts[0], 'f', false, OPTION_ARG_TYPE_FLG,
+                         &full_init, NULL, "full initialization, erases all of flash");
+    if (!scan_opts(argc, argv, 2, opts, 1, 0, 0, "")) {
+               return;
     }
 
     if (!verify_action("About to initialize [format] FLASH image system")) {
-        diag_printf("** Aborted\n");
-        return;
+               diag_printf("** Aborted\n");
+               return;
     }
     diag_printf("*** Initialize FLASH Image System\n");
 
 #define MIN_REDBOOT_IMAGE_SIZE CYGBLD_REDBOOT_MIN_IMAGE_SIZE
-    redboot_image_size = flash_block_size > MIN_REDBOOT_IMAGE_SIZE ? 
-                         flash_block_size : MIN_REDBOOT_IMAGE_SIZE;
+    redboot_image_size = flash_block_size > MIN_REDBOOT_IMAGE_SIZE ?
+               flash_block_size : MIN_REDBOOT_IMAGE_SIZE;
 
-    // Create a pseudo image for RedBoot
-    img = (struct fis_image_desc *)fis_work_block;
+    img = fis_work_block;
     memset(img, 0xFF, fisdir_size);  // Start with erased data
+
+#ifdef CYGOPT_REDBOOT_REDUNDANT_FIS
+    //create the valid flag entry
+    memset(img, 0, sizeof(struct fis_image_desc));
+    strcpy(img->u.valid_info.magic_name, CYG_REDBOOT_RFIS_VALID_MAGIC);
+    img->u.valid_info.valid_flag[0] = CYG_REDBOOT_RFIS_VALID;
+    img->u.valid_info.valid_flag[1] = CYG_REDBOOT_RFIS_VALID;
+    img->u.valid_info.version_count = 0;
+    img++;
+#endif
+
+    // Create a pseudo image for RedBoot
 #ifdef CYGOPT_REDBOOT_FIS_RESERVED_BASE
     memset(img, 0, sizeof(*img));
-    strcpy(img->name, "(reserved)");
+    strcpy(img->u.name, "(reserved)");
     img->flash_base = (CYG_ADDRESS)flash_start;
     img->mem_base = (CYG_ADDRESS)flash_start;
     img->size = CYGNUM_REDBOOT_FLASH_RESERVED_BASE;
@@ -315,7 +508,7 @@ fis_init(int argc, char *argv[])
     redboot_flash_start = (CYG_ADDRESS)flash_start + CYGBLD_REDBOOT_FLASH_BOOT_OFFSET;
 #ifdef CYGOPT_REDBOOT_FIS_REDBOOT
     memset(img, 0, sizeof(*img));
-    strcpy(img->name, "RedBoot");
+    strcpy(img->u.name, "RedBoot");
     img->flash_base = redboot_flash_start;
     img->mem_base = redboot_flash_start;
     img->size = redboot_image_size;
@@ -328,7 +521,7 @@ fis_init(int argc, char *argv[])
     redboot_flash_start = (CYG_ADDRESS)flash_start + CYGNUM_REDBOOT_FIS_REDBOOT_POST_OFFSET;
 #endif
     memset(img, 0, sizeof(*img));
-    strcpy(img->name, "RedBoot[post]");
+    strcpy(img->u.name, "RedBoot[post]");
     img->flash_base = redboot_flash_start;
     img->mem_base = redboot_flash_start;
     img->size = redboot_image_size;
@@ -338,7 +531,7 @@ fis_init(int argc, char *argv[])
 #ifdef CYGOPT_REDBOOT_FIS_REDBOOT_BACKUP
     // And a backup image
     memset(img, 0, sizeof(*img));
-    strcpy(img->name, "RedBoot[backup]");
+    strcpy(img->u.name, "RedBoot[backup]");
     img->flash_base = redboot_flash_start;
     img->mem_base = redboot_flash_start;
     img->size = redboot_image_size;
@@ -348,7 +541,7 @@ fis_init(int argc, char *argv[])
 #if defined(CYGSEM_REDBOOT_FLASH_CONFIG) && defined(CYGHWR_REDBOOT_FLASH_CONFIG_MEDIA_FLASH)
     // And a descriptor for the configuration data
     memset(img, 0, sizeof(*img));
-    strcpy(img->name, "RedBoot config");
+    strcpy(img->u.name, "RedBoot config");
     img->flash_base = (CYG_ADDRESS)cfg_base;
     img->mem_base = (CYG_ADDRESS)cfg_base;
     img->size = cfg_size;
@@ -356,12 +549,22 @@ fis_init(int argc, char *argv[])
 #endif
     // And a descriptor for the descriptor table itself
     memset(img, 0, sizeof(*img));
-    strcpy(img->name, "FIS directory");
+    strcpy(img->u.name, "FIS directory");
     img->flash_base = (CYG_ADDRESS)fis_addr;
     img->mem_base = (CYG_ADDRESS)fis_addr;
     img->size = fisdir_size;
     img++;
 
+    //create the entry for the redundant fis table
+#ifdef CYGOPT_REDBOOT_REDUNDANT_FIS
+    memset(img, 0, sizeof(*img));
+    strcpy(img->u.name, "Redundant FIS");
+    img->flash_base = (CYG_ADDRESS)redundant_fis_addr;
+    img->mem_base = (CYG_ADDRESS)redundant_fis_addr;
+    img->size = fisdir_size;
+    img++;
+#endif
+
 #ifdef CYGOPT_REDBOOT_FIS_DIRECTORY_ARM_SIB_ID
     // FIS gets the size of a full block - note, this should be changed
     // if support is added for multi-block FIS structures.
@@ -369,32 +572,32 @@ fis_init(int argc, char *argv[])
     // Add a footer so the FIS will be recognized by the ARM Boot
     // Monitor as a reserved area.
     {
-        tFooter* footer_p = (tFooter*)((CYG_ADDRESS)img - sizeof(tFooter));
-        cyg_uint32 check = 0;
-        cyg_uint32 *check_ptr = (cyg_uint32 *)footer_p;
-        cyg_int32 count = (sizeof(tFooter) - 4) >> 2;
-
-        // Prepare footer. Try to protect all but the reserved space
-        // and the first RedBoot image (which is expected to be
-        // bootable), but fall back to just protecting the FIS if it's
-        // not at the default position in the flash.
+               tFooter *footer_p = (tFooter*)((CYG_ADDRESS)img - sizeof(tFooter));
+               cyg_uint32 check = 0;
+               cyg_uint32 *check_ptr = (cyg_uint32 *)footer_p;
+               cyg_int32 count = (sizeof(tFooter) - 4) >> 2;
+
+               // Prepare footer. Try to protect all but the reserved space
+               // and the first RedBoot image (which is expected to be
+               // bootable), but fall back to just protecting the FIS if it's
+               // not at the default position in the flash.
 #if defined(CYGOPT_REDBOOT_FIS_RESERVED_BASE) && (-1 == CYGNUM_REDBOOT_FIS_DIRECTORY_BLOCK)
-        footer_p->blockBase = (char*)_ADDR_REDBOOT_TO_ARM(flash_start);
-        footer_p->blockBase += CYGNUM_REDBOOT_FLASH_RESERVED_BASE + redboot_image_size;
+               footer_p->blockBase = (char*)_ADDR_REDBOOT_TO_ARM(flash_start);
+               footer_p->blockBase += CYGNUM_REDBOOT_FLASH_RESERVED_BASE + redboot_image_size;
 #else
-        footer_p->blockBase = (char*)_ADDR_REDBOOT_TO_ARM(fis_work_block);
-#endif
-        footer_p->infoBase = NULL;
-        footer_p->signature = FLASH_FOOTER_SIGNATURE;
-        footer_p->type = TYPE_REDHAT_REDBOOT;
-
-        // and compute its checksum
-        for ( ; count > 0; count--) {
-            if (*check_ptr > ~check)
-                check++;
-            check += *check_ptr++;
-        }
-        footer_p->checksum = ~check;
+               footer_p->blockBase = (char*)_ADDR_REDBOOT_TO_ARM(fis_work_block);
+#endif
+               footer_p->infoBase = NULL;
+               footer_p->signature = FLASH_FOOTER_SIGNATURE;
+               footer_p->type = TYPE_REDHAT_REDBOOT;
+
+               // and compute its checksum
+               for ( ; count > 0; count--) {
+                       if (*check_ptr > ~check)
+                               check++;
+                       check += *check_ptr++;
+               }
+               footer_p->checksum = ~check;
     }
 #endif
 
@@ -402,86 +605,90 @@ fis_init(int argc, char *argv[])
     // calculates where the high water mark of default RedBoot images is.
 
     if (full_init) {
-        unsigned long erase_size;
-        CYG_ADDRESS erase_start;
-        // Erase everything except default RedBoot images, fis block, 
-        // and config block.
-        // First deal with the possible first part, before RedBoot images:
+               unsigned long erase_size;
+               CYG_ADDRESS erase_start;
+               // Erase everything except default RedBoot images, fis block,
+               // and config block.
+               // First deal with the possible first part, before RedBoot images:
 #if (CYGBLD_REDBOOT_FLASH_BOOT_OFFSET > CYGNUM_REDBOOT_FLASH_RESERVED_BASE)
-        erase_start = (CYG_ADDRESS)flash_start + CYGNUM_REDBOOT_FLASH_RESERVED_BASE;
-        erase_size =  (CYG_ADDRESS)flash_start + CYGBLD_REDBOOT_FLASH_BOOT_OFFSET;
-        if ( erase_size > erase_start ) {
-            erase_size -= erase_start;
-            if ((stat = flash_erase((void *)erase_start, erase_size,
-                                    (void **)&err_addr)) != 0) {
-                diag_printf("   initialization failed at %p: %s\n",
-                            err_addr, flash_errmsg(stat));
-            }
-        }
-#endif
-        // second deal with the larger part in the main:
-        erase_start = redboot_flash_start; // high water of created images
-        // Now the empty bits between the end of Redboot and the cfg and dir 
-        // blocks. 
+               erase_start = (CYG_ADDRESS)flash_start + CYGNUM_REDBOOT_FLASH_RESERVED_BASE;
+               erase_size =  (CYG_ADDRESS)flash_start + CYGBLD_REDBOOT_FLASH_BOOT_OFFSET;
+               if ( erase_size > erase_start ) {
+                       erase_size -= erase_start;
+                       if ((stat = flash_erase((void *)erase_start, erase_size,
+                                                                       &err_addr)) != 0) {
+                               diag_printf("   initialization failed at %p: %s\n",
+                                                       err_addr, flash_errmsg(stat));
+                       }
+               }
+#endif
+               // second deal with the larger part in the main:
+               erase_start = redboot_flash_start; // high water of created images
+               // Now the empty bits between the end of Redboot and the cfg and dir
+               // blocks.
 #if defined(CYGSEM_REDBOOT_FLASH_CONFIG) && \
     defined(CYGHWR_REDBOOT_FLASH_CONFIG_MEDIA_FLASH) && \
     !defined(CYGSEM_REDBOOT_FLASH_COMBINED_FIS_AND_CONFIG)
-        if (fis_addr > cfg_base) {
-          erase_size = (CYG_ADDRESS)cfg_base - erase_start; // the gap between HWM and config data
-        } else {
-          erase_size = (CYG_ADDRESS)fis_addr - erase_start; // the gap between HWM and fis data
-        }
-        if ((stat = flash_erase((void *)erase_start, erase_size,
-                                (void **)&err_addr)) != 0) {
-          diag_printf("   initialization failed %p: %s\n",
-                 err_addr, flash_errmsg(stat));
-        }
-        erase_start += (erase_size + flash_block_size);
-        if (fis_addr > cfg_base) {
-          erase_size = (CYG_ADDRESS)fis_addr - erase_start; // the gap between config and fis data
-        } else {
-          erase_size = (CYG_ADDRESS)cfg_base - erase_start; // the gap between fis and config data
-        }
-        if ((stat = flash_erase((void *)erase_start, erase_size,
-                                (void **)&err_addr)) != 0) {
-          diag_printf("   initialization failed %p: %s\n",
-                 err_addr, flash_errmsg(stat));
-        }
-        erase_start += (erase_size + flash_block_size);
-#else  // !CYGSEM_REDBOOT_FLASH_CONFIG        
-        erase_size = (CYG_ADDRESS)fis_addr - erase_start; // the gap between HWM and fis data
-        if ((stat = flash_erase((void *)erase_start, erase_size,
-                                (void **)&err_addr)) != 0) {
-          diag_printf("   initialization failed %p: %s\n",
-                 err_addr, flash_errmsg(stat));
-        }
-        erase_start += (erase_size + flash_block_size);          
-#endif
-        // Lastly, anything at the end, if there is any
-        if ( erase_start < (((CYG_ADDRESS)flash_end)+1) ) {
-            erase_size = ((CYG_ADDRESS)flash_end - erase_start) + 1;
-            if ((stat = flash_erase((void *)erase_start, erase_size,
-                                    (void **)&err_addr)) != 0) {
-                diag_printf("   initialization failed at %p: %s\n",
-                            err_addr, flash_errmsg(stat));
-            }
-        }
+               if (fis_addr > cfg_base) {
+                       erase_size = (CYG_ADDRESS)cfg_base - erase_start; // the gap between HWM and config data
+               } else {
+                       erase_size = (CYG_ADDRESS)fis_addr - erase_start; // the gap between HWM and fis data
+               }
+               if ((stat = flash_erase((void *)erase_start, erase_size,
+                                                               &err_addr)) != 0) {
+                       diag_printf("     initialization failed %p: %s\n",
+                                               err_addr, flash_errmsg(stat));
+               }
+               erase_start += erase_size + flash_block_size;
+               if (fis_addr > cfg_base) {
+                       erase_size = (CYG_ADDRESS)fis_addr - erase_start; // the gap between config and fis data
+               } else {
+                       erase_size = (CYG_ADDRESS)cfg_base - erase_start; // the gap between fis and config data
+               }
+               if ((stat = flash_erase((void *)erase_start, erase_size,
+                                                               &err_addr)) != 0) {
+                       diag_printf("     initialization failed %p: %s\n",
+                                               err_addr, flash_errmsg(stat));
+               }
+               erase_start += erase_size + flash_block_size;
+#else  // !CYGSEM_REDBOOT_FLASH_CONFIG
+               erase_size = (CYG_ADDRESS)fis_addr - erase_start; // the gap between HWM and fis data
+               if ((stat = flash_erase((void *)erase_start, erase_size,
+                                                               &err_addr)) != 0) {
+                       diag_printf("     initialization failed %p: %s\n",
+                                               err_addr, flash_errmsg(stat));
+               }
+               erase_start += erase_size + flash_block_size;
+#endif
+               // Lastly, anything at the end, if there is any
+               if ( erase_start < (((CYG_ADDRESS)flash_end)+1) ) {
+                       erase_size = ((CYG_ADDRESS)flash_end - erase_start) + 1;
+                       if ((stat = flash_erase((void *)erase_start, erase_size,
+                                                                       &err_addr)) != 0) {
+                               diag_printf("   initialization failed at %p: %s\n",
+                                                       err_addr, flash_errmsg(stat));
+                       }
+               }
 #ifndef CYGDAT_REDBOOT_FIS_MAX_FREE_CHUNKS
-    // In this case, 'fis free' works by scanning for erased blocks.  Since the
-    // "-f" option was not supplied, there may be areas which are not used but
-    // don't appear to be free since they are not erased - thus the warning
+               // In this case, 'fis free' works by scanning for erased blocks.  Since the
+               // "-f" option was not supplied, there may be areas which are not used but
+               // don't appear to be free since they are not erased - thus the warning
     } else {
-        diag_printf("    Warning: device contents not erased, some blocks may not be usable\n");
+               diag_printf("    Warning: device contents not erased, some blocks may not be usable\n");
 #endif
     }
-    fis_update_directory();
+    fis_start_update_directory(0);
+    fis_update_directory(0, 0);
+#ifdef CYGOPT_REDBOOT_REDUNDANT_FIS
+    fis_erase_redundant_directory();
+#endif
 }
 
 static void
 fis_list(int argc, char *argv[])
 {
     struct fis_image_desc *img;
-    int i, image_indx;
+    int i = 0, image_indx;
     bool show_cksums = false;
     bool show_datalen = false;
     struct option_info opts[2];
@@ -495,57 +702,54 @@ fis_list(int argc, char *argv[])
     return;
 #endif
 
-    init_opts(&opts[0], 'd', false, OPTION_ARG_TYPE_FLG, 
-              (void *)&show_datalen, (bool *)0, "display data length");
+    init_opts(&opts[i++], 'd', false, OPTION_ARG_TYPE_FLG,
+                         &show_datalen, NULL, "display data length");
 #ifdef CYGSEM_REDBOOT_FIS_CRC_CHECK
-    init_opts(&opts[1], 'c', false, OPTION_ARG_TYPE_FLG, 
-              (void *)&show_cksums, (bool *)0, "display checksums");
-    i = 2;
-#else
-    i = 1;
+    init_opts(&opts[i++], 'c', false, OPTION_ARG_TYPE_FLG,
+                         &show_cksums, NULL, "display checksums");
 #endif
     if (!scan_opts(argc, argv, 2, opts, i, 0, 0, "")) {
-        return;
+               return;
     }
     fis_read_directory();
 
     // Let diag_printf do the formatting in both cases, rather than counting
     // cols by hand....
     diag_printf("%-16s  %-10s  %-10s  %-10s  %-s\n",
-                "Name","FLASH addr",
-                show_cksums ? "Checksum" : "Mem addr",
-                show_datalen ? "Datalen" : "Length",
-                "Entry point" );
+                               "Name","FLASH addr",
+                               show_cksums ? "Checksum" : "Mem addr",
+                               show_datalen ? "Datalen" : "Length",
+                               "Entry point" );
     last_addr = 0;
     image_indx = 0;
     do {
-        image_found = false;
-        lowest_addr = 0xFFFFFFFF;
-        img = (struct fis_image_desc *) fis_work_block;
-        for (i = 0;  i < fisdir_size/sizeof(*img);  i++, img++) {
-            if (img->name[0] != (unsigned char)0xFF) {
-                if ((img->flash_base > last_addr) && (img->flash_base < lowest_addr)) {
-                    lowest_addr = img->flash_base;
-                    image_found = true;
-                    image_indx = i;
-                }
-            }
-        }
-        if (image_found) {
-            img = (struct fis_image_desc *) fis_work_block;
-            img += image_indx;
-            diag_printf("%-16s  0x%08lX  0x%08lX  0x%08lX  0x%08lX\n", img->name, 
-                        (unsigned long)img->flash_base, 
+       image_found = false;
+       lowest_addr = 0xFFFFFFFF;
+       img = fis_work_block;
+       for (i = 0;  i < fisdir_size/sizeof(*img);  i++, img++) {
+           if (img->u.name[0] != 0xFF) {
+               if ((img->flash_base >= last_addr) && (img->flash_base < lowest_addr)) {
+                   lowest_addr = img->flash_base;
+                   image_found = true;
+                   image_indx = i;
+               }
+           }
+       }
+       if (image_found) {
+           img = fis_work_block;
+           img += image_indx;
+           diag_printf("%-16s  0x%08lX  0x%08lX  0x%08lX  0x%08lX\n", img->u.name,
+                       (unsigned long)img->flash_base,
 #ifdef CYGSEM_REDBOOT_FIS_CRC_CHECK
-                        show_cksums ? img->file_cksum : img->mem_base, 
-                        show_datalen ? img->data_length : img->size, 
+                                               show_cksums ? img->file_cksum : img->mem_base,
+                                               show_datalen ? img->data_length : img->size,
 #else
-                        img->mem_base, 
-                        img->size, 
+                                               img->mem_base,
+                                               img->size,
 #endif
-                        (unsigned long)img->entry_point);
-        }
-        last_addr = lowest_addr;
+                       (unsigned long)img->entry_point);
+       }
+       last_addr = lowest_addr + 1;
     } while (image_found == true);
 }
 
@@ -563,51 +767,51 @@ find_free(struct free_chunk *chunks)
     int num_chunks = 1;
 
     // Do not search the area reserved for pre-RedBoot systems:
-    fis_ptr = (CYG_ADDRESS *)((CYG_ADDRESS)flash_start + 
-                              CYGNUM_REDBOOT_FLASH_RESERVED_BASE);
+    fis_ptr = (CYG_ADDRESS *)((CYG_ADDRESS)flash_start +
+                                                         CYGNUM_REDBOOT_FLASH_RESERVED_BASE);
     fis_end = (CYG_ADDRESS *)flash_end;
-    chunks[num_chunks-1].start = (CYG_ADDRESS)fis_ptr;
-    chunks[num_chunks-1].end = (CYG_ADDRESS)fis_end;
+    chunks[num_chunks - 1].start = (CYG_ADDRESS)fis_ptr;
+    chunks[num_chunks - 1].end = (CYG_ADDRESS)fis_end;
     fis_read_directory();
-    img = (struct fis_image_desc *) fis_work_block;
+    img = fis_work_block;
     for (i = 0;  i < fisdir_size/sizeof(*img);  i++, img++) {
-        if (img->name[0] != (unsigned char)0xFF) {
-            // Figure out which chunk this is in and split it
-            for (idx = 0;  idx < num_chunks;  idx++) {
-                if ((img->flash_base >= chunks[idx].start) && 
-                    (img->flash_base <= chunks[idx].end)) {
-                    if (img->flash_base == chunks[idx].start) {
-                        chunks[idx].start += img->size;
-                        if (chunks[idx].start >= chunks[idx].end) {
-                            // This free chunk has collapsed
-                            while (idx < (num_chunks-1)) {
-                                chunks[idx] = chunks[idx+1];
-                                idx++;
-                            }
-                            num_chunks--;
-                        }
-                    } else if ((img->flash_base+img->size) == chunks[idx].end) {
-                        chunks[idx].end = img->flash_base;
-                    } else {
-                        // Split chunk into two parts
-                        if ((img->flash_base+img->size) < (CYG_ADDRESS)fis_end) {
-                            int j;
-                            // make room for new chunk
-                            for (j = num_chunks; j > (idx+1); j--)
-                                chunks[j] = chunks[j-1];
-                            chunks[idx+1].start = img->flash_base + img->size;
-                            chunks[idx+1].end = chunks[idx].end;
-                            if (++num_chunks == CYGDAT_REDBOOT_FIS_MAX_FREE_CHUNKS) {
-                                diag_printf("Warning: too many free chunks\n");
-                                return num_chunks;
-                            }
-                        }
-                        chunks[idx].end = img->flash_base;
-                    }
-                    break;
-                }
-            }
-        }
+       if (img->u.name[0] != 0xFF) {
+           // Figure out which chunk this is in and split it
+           for (idx = 0;  idx < num_chunks;  idx++) {
+               if ((img->flash_base >= chunks[idx].start) &&
+                   (img->flash_base <= chunks[idx].end)) {
+                   if (img->flash_base == chunks[idx].start) {
+                       chunks[idx].start += img->size;
+                       if (chunks[idx].start >= chunks[idx].end) {
+                           // This free chunk has collapsed
+                           while (idx < (num_chunks-1)) {
+                               chunks[idx] = chunks[idx+1];
+                               idx++;
+                           }
+                           num_chunks--;
+                       }
+                   } else if ((img->flash_base+img->size) == chunks[idx].end) {
+                       chunks[idx].end = img->flash_base;
+                   } else {
+                       // Split chunk into two parts
+                       if ((img->flash_base+img->size) < (CYG_ADDRESS)fis_end) {
+                           int j;
+                           // make room for new chunk
+                           for (j = num_chunks; j > idx + 1; j--)
+                               chunks[j] = chunks[j-1];
+                           chunks[idx+1].start = img->flash_base + img->size;
+                           chunks[idx+1].end = chunks[idx].end;
+                           if (++num_chunks == CYGDAT_REDBOOT_FIS_MAX_FREE_CHUNKS) {
+                               diag_printf("Warning: too many free chunks\n");
+                               return num_chunks;
+                           }
+                       }
+                       chunks[idx].end = img->flash_base;
+                   }
+                   break;
+               }
+           }
+       }
     }
     return num_chunks;
 }
@@ -622,45 +826,45 @@ fis_free(int argc, char *argv[])
     void *err_addr;
 
     // Do not search the area reserved for pre-RedBoot systems:
-    fis_ptr = (unsigned long *)((CYG_ADDRESS)flash_start + 
-                                CYGNUM_REDBOOT_FLASH_RESERVED_BASE);
+    fis_ptr = (unsigned long *)((CYG_ADDRESS)flash_start +
+                                                               CYGNUM_REDBOOT_FLASH_RESERVED_BASE);
     fis_end = (unsigned long *)(CYG_ADDRESS)flash_end;
     area_start = fis_ptr;
     while (fis_ptr < fis_end) {
-        flash_read(fis_ptr, &flash_data, sizeof(unsigned long), (void **)&err_addr);
-        if (flash_data != (unsigned long)0xFFFFFFFF) {
-            if (area_start != fis_ptr) {
-                // Assume that this is something
-                diag_printf("  0x%08lX .. 0x%08lX\n",
-                            (CYG_ADDRESS)area_start, (CYG_ADDRESS)fis_ptr);
-            }
-            // Find next blank block
-            area_start = fis_ptr;
-            while (area_start < fis_end) {
-                flash_read(area_start, &flash_data, sizeof(unsigned long), (void **)&err_addr);
-                if (flash_data == (unsigned long)0xFFFFFFFF) {
-                    break;
-                }
-                area_start += flash_block_size / sizeof(CYG_ADDRESS);
-            }
-            fis_ptr = area_start;
-        } else {
-            fis_ptr += flash_block_size / sizeof(CYG_ADDRESS);
-        }
+               flash_read(fis_ptr, &flash_data, sizeof(unsigned long), &err_addr);
+               if (flash_data != 0xFFFFFFFF) {
+                       if (area_start != fis_ptr) {
+                               // Assume that this is something
+                               diag_printf("  0x%08x .. 0x%08x\n",
+                                                       (CYG_ADDRESS)area_start, (CYG_ADDRESS)fis_ptr);
+                       }
+                       // Find next blank block
+                       area_start = fis_ptr;
+                       while (area_start < fis_end) {
+                               flash_read(area_start, &flash_data, sizeof(unsigned long), &err_addr);
+                               if (flash_data == 0xFFFFFFFF) {
+                                       break;
+                               }
+                               area_start += flash_block_size / sizeof(CYG_ADDRESS);
+                       }
+                       fis_ptr = area_start;
+               } else {
+                       fis_ptr += flash_block_size / sizeof(CYG_ADDRESS);
+               }
     }
     if (area_start != fis_ptr) {
-        diag_printf("  0x%08lX .. 0x%08lX\n", 
-                    (CYG_ADDRESS)area_start, (CYG_ADDRESS)fis_ptr);
+               diag_printf("  0x%08x .. 0x%08x\n",
+                                       (CYG_ADDRESS)area_start, (CYG_ADDRESS)fis_ptr);
     }
 #else
     struct free_chunk chunks[CYGDAT_REDBOOT_FIS_MAX_FREE_CHUNKS];
     int idx, num_chunks;
 
     num_chunks = find_free(chunks);
-    for (idx = 0;  idx < num_chunks;  idx++) {
-        diag_printf("  0x%08lX .. 0x%08lX\n", 
-                   (unsigned long)chunks[idx].start,
-                   (unsigned long)chunks[idx].end);
+    for (idx = 0; idx < num_chunks; idx++) {
+               diag_printf("  0x%08x .. 0x%08x\n",
+                                       chunks[idx].start,
+                                       chunks[idx].end);
     }
 #endif
 }
@@ -675,39 +879,39 @@ fis_find_free(CYG_ADDRESS *addr, unsigned long length)
     void *err_addr;
 
     // Do not search the area reserved for pre-RedBoot systems:
-    fis_ptr = (unsigned long *)((CYG_ADDRESS)flash_start + 
-                                CYGNUM_REDBOOT_FLASH_RESERVED_BASE);
+    fis_ptr = (unsigned long *)((CYG_ADDRESS)flash_start +
+                                                               CYGNUM_REDBOOT_FLASH_RESERVED_BASE);
     fis_end = (unsigned long *)(CYG_ADDRESS)flash_end;
     area_start = fis_ptr;
     while (fis_ptr < fis_end) {
-        flash_read(fis_ptr, &flash_data, sizeof(unsigned long), (void **)&err_addr);
-        if (flash_data != (unsigned long)0xFFFFFFFF) {
-            if (area_start != fis_ptr) {
-                // Assume that this is something
-                if ((fis_ptr-area_start) >= (length/sizeof(unsigned))) {
-                    *addr = (CYG_ADDRESS)area_start;
-                    return true;
-                }
-            }
-            // Find next blank block
-            area_start = fis_ptr;
-            while (area_start < fis_end) {
-                flash_read(area_start, &flash_data, sizeof(unsigned long), (void **)&err_addr);
-                if (flash_data == (unsigned long)0xFFFFFFFF) {
-                    break;
-                }
-                area_start += flash_block_size / sizeof(CYG_ADDRESS);
-            }
-            fis_ptr = area_start;
-        } else {
-            fis_ptr += flash_block_size / sizeof(CYG_ADDRESS);
-        }
+               flash_read(fis_ptr, &flash_data, sizeof(unsigned long), &err_addr);
+               if (flash_data != 0xFFFFFFFF) {
+                       if (area_start != fis_ptr) {
+                               // Assume that this is something
+                               if ((fis_ptr - area_start) >= (length/sizeof(unsigned))) {
+                                       *addr = (CYG_ADDRESS)area_start;
+                                       return true;
+                               }
+                       }
+                       // Find next blank block
+                       area_start = fis_ptr;
+                       while (area_start < fis_end) {
+                               flash_read(area_start, &flash_data, sizeof(unsigned long), &err_addr);
+                               if (flash_data == 0xFFFFFFFF) {
+                                       break;
+                               }
+                               area_start += flash_block_size / sizeof(CYG_ADDRESS);
+                       }
+                       fis_ptr = area_start;
+               } else {
+                       fis_ptr += flash_block_size / sizeof(CYG_ADDRESS);
+               }
     }
     if (area_start != fis_ptr) {
-        if ((fis_ptr-area_start) >= (length/sizeof(unsigned))) {
-            *addr = (CYG_ADDRESS)area_start;
-            return true;
-        }
+               if (fis_ptr - area_start >= length / sizeof(unsigned)) {
+                       *addr = (CYG_ADDRESS)area_start;
+                       return true;
+               }
     }
     return false;
 #else
@@ -715,11 +919,11 @@ fis_find_free(CYG_ADDRESS *addr, unsigned long length)
     int idx, num_chunks;
 
     num_chunks = find_free(chunks);
-    for (idx = 0;  idx < num_chunks;  idx++) {
-        if ((chunks[idx].end - chunks[idx].start) >= length) {
-            *addr = (CYG_ADDRESS)chunks[idx].start;
-            return true;
-        }
+    for (idx = 0; idx < num_chunks; idx++) {
+               if (chunks[idx].end + 1 - chunks[idx].start >= length) {
+                       *addr = (CYG_ADDRESS)chunks[idx].start;
+                       return true;
+               }
     }
     return false;
 #endif
@@ -745,214 +949,214 @@ fis_create(int argc, char *argv[])
     struct option_info opts[7];
     bool prog_ok = true;
 
-    init_opts(&opts[0], 'b', true, OPTION_ARG_TYPE_NUM, 
-              (void *)&mem_addr, (bool *)&mem_addr_set, "memory base address");
-    init_opts(&opts[1], 'r', true, OPTION_ARG_TYPE_NUM, 
-              (void *)&exec_addr, (bool *)&exec_addr_set, "ram base address");
-    init_opts(&opts[2], 'e', true, OPTION_ARG_TYPE_NUM, 
-              (void *)&entry_addr, (bool *)&entry_addr_set, "entry point address");
-    init_opts(&opts[3], 'f', true, OPTION_ARG_TYPE_NUM, 
-              (void *)&flash_addr, (bool *)&flash_addr_set, "FLASH memory base address");
-    init_opts(&opts[4], 'l', true, OPTION_ARG_TYPE_NUM, 
-              (void *)&length, (bool *)&length_set, "image length [in FLASH]");
-    init_opts(&opts[5], 's', true, OPTION_ARG_TYPE_NUM, 
-              (void *)&img_size, (bool *)&img_size_set, "image size [actual data]");
-    init_opts(&opts[6], 'n', false, OPTION_ARG_TYPE_FLG, 
-              (void *)&no_copy, (bool *)0, "don't copy from RAM to FLASH, just update directory");
-    if (!scan_opts(argc, argv, 2, opts, 7, (void *)&name, OPTION_ARG_TYPE_STR, "file name"))
-    {
-        fis_usage("invalid arguments");
-        return;
-    }
+    init_opts(&opts[0], 'b', true, OPTION_ARG_TYPE_NUM,
+                         &mem_addr, &mem_addr_set, "memory base address");
+    init_opts(&opts[1], 'r', true, OPTION_ARG_TYPE_NUM,
+                         &exec_addr, &exec_addr_set, "ram base address");
+    init_opts(&opts[2], 'e', true, OPTION_ARG_TYPE_NUM,
+                         &entry_addr, &entry_addr_set, "entry point address");
+    init_opts(&opts[3], 'f', true, OPTION_ARG_TYPE_NUM,
+                         &flash_addr, &flash_addr_set, "FLASH memory base address");
+    init_opts(&opts[4], 'l', true, OPTION_ARG_TYPE_NUM,
+                         &length, &length_set, "image length [in FLASH]");
+    init_opts(&opts[5], 's', true, OPTION_ARG_TYPE_NUM,
+                         &img_size, &img_size_set, "image size [actual data]");
+    init_opts(&opts[6], 'n', false, OPTION_ARG_TYPE_FLG,
+                         &no_copy, NULL, "don't copy from RAM to FLASH, just update directory");
+    if (!scan_opts(argc, argv, 2, opts, 7, &name, OPTION_ARG_TYPE_STR, "file name")) {
+               fis_usage("invalid arguments");
+               return;
+       }
 
     fis_read_directory();
     defaults_assumed = false;
     if (name) {
-        // Search existing files to acquire defaults for params not specified:
-        img = fis_lookup(name, NULL);
-        if (img) {
-            // Found it, so get image size from there
-            if (!length_set) {
-                length_set = true;
-                length = img->size;
-                defaults_assumed = true;
-            }
-        }
+               // Search existing files to acquire defaults for params not specified:
+               img = fis_lookup(name, NULL);
+               if (img) {
+                       // Found it, so get image size from there
+                       if (!length_set) {
+                               length_set = true;
+                               length = img->size;
+                               defaults_assumed = true;
+                       }
+               }
     }
     if (!mem_addr_set && (load_address >= (CYG_ADDRESS)ram_start) &&
-       (load_address_end) < (CYG_ADDRESS)ram_end) {
-       mem_addr = load_address;
-       mem_addr_set = true;
-        defaults_assumed = true;
-        // Get entry address from loader, unless overridden
-        if (!entry_addr_set)
-            entry_addr = entry_address;
-       if (!length_set) {
-           length = load_address_end - load_address;
-           length_set = true;
-       } else if (defaults_assumed && !img_size_set) {
-           /* We got length from the FIS table, so the size of the
-              actual loaded image becomes img_size */
-           img_size = load_address_end - load_address;
-           img_size_set = true;
-       }
+               (load_address_end) < (CYG_ADDRESS)ram_end) {
+               mem_addr = load_address;
+               mem_addr_set = true;
+               defaults_assumed = true;
+               // Get entry address from loader, unless overridden
+               if (!entry_addr_set)
+                       entry_addr = entry_address;
+               if (!length_set) {
+                       length = load_address_end - load_address;
+                       length_set = true;
+               } else if (defaults_assumed && !img_size_set) {
+                       /* We got length from the FIS table, so the size of the
+                          actual loaded image becomes img_size */
+                       img_size = load_address_end - load_address;
+                       img_size_set = true;
+               }
     }
     // Get the remaining fall-back values from the fis
     if (img) {
-        if (!exec_addr_set) {
-            // Preserve "normal" behaviour
-            exec_addr_set = true;
-            exec_addr = flash_addr_set ? flash_addr : mem_addr;
-        }
-        if (!flash_addr_set) {
-            flash_addr_set = true;
-            flash_addr = img->flash_base;
-            defaults_assumed = true;
-        }
+               if (!exec_addr_set) {
+                       // Preserve "normal" behaviour
+                       exec_addr_set = true;
+                       exec_addr = flash_addr_set ? flash_addr : mem_addr;
+               }
+               if (!flash_addr_set) {
+                       flash_addr_set = true;
+                       flash_addr = img->flash_base;
+                       defaults_assumed = true;
+               }
     }
 
     if ((!no_copy && !mem_addr_set) || (no_copy && !flash_addr_set) ||
-        !length_set || !name) {
-        fis_usage("required parameter missing");
-        return;
+               !length_set || !name) {
+               fis_usage("required parameter missing");
+               return;
     }
     if (!img_size_set) {
-        img_size = length;
+               img_size = length;
     }
     // 'length' is size of FLASH image, 'img_size' is actual data size
     // Round up length to FLASH block size
 #ifndef CYGPKG_HAL_MIPS // FIXME: compiler is b0rken
     length = ((length + flash_block_size - 1) / flash_block_size) * flash_block_size;
     if (length < img_size) {
-        diag_printf("Invalid FLASH image size/length combination\n");
-        return;
+               diag_printf("Invalid FLASH image size/length combination\n");
+               return;
     }
 #endif
     if (flash_addr_set &&
-        ((stat = flash_verify_addr((void *)flash_addr)) ||
-         (stat = flash_verify_addr((void *)(flash_addr+length-1))))) {
-        _show_invalid_flash_address(flash_addr, stat);
-        return;
+               ((stat = flash_verify_addr((void *)flash_addr)) ||
+                (stat = flash_verify_addr((void *)(flash_addr + length - 1))))) {
+               _show_invalid_flash_address(flash_addr, stat);
+               return;
     }
-    if (flash_addr_set && ((flash_addr & (flash_block_size-1)) != 0)) {
-        diag_printf("Invalid FLASH address: %p\n", (void *)flash_addr);
-        diag_printf("   must be 0x%x aligned\n", flash_block_size);
-        return;
+    if (flash_addr_set && ((flash_addr & (flash_block_size - 1)) != 0)) {
+               diag_printf("Invalid FLASH address: %p\n", (void *)flash_addr);
+               diag_printf("   must be 0x%x aligned\n", flash_block_size);
+               return;
     }
-    if (strlen(name) >= sizeof(img->name)) {
-        diag_printf("Name is too long, must be less than %d chars\n", (int)sizeof(img->name));
-        return;
+    if (strlen(name) >= sizeof(img->u.name)) {
+       diag_printf("Name is too long, must be less than %d chars\n", sizeof(img->u.name));
+       return;
     }
     if (!no_copy) {
-        if ((mem_addr < (CYG_ADDRESS)ram_start) ||
-            ((mem_addr+img_size) >= (CYG_ADDRESS)ram_end)) {
-            diag_printf("** WARNING: RAM address: %p may be invalid\n", (void *)mem_addr);
-            diag_printf("   valid range is %p-%p\n", (void *)ram_start, (void *)ram_end);
-        }
-        if (!flash_addr_set && !fis_find_free(&flash_addr, length)) {
-            diag_printf("Can't locate %lx(%ld) bytes free in FLASH\n", length, length);
-            return;
-        }
+               if ((mem_addr < (CYG_ADDRESS)ram_start) ||
+                       ((mem_addr+img_size) >= (CYG_ADDRESS)ram_end)) {
+                       diag_printf("** WARNING: RAM address: %p may be invalid\n", (void *)mem_addr);
+                       diag_printf("   valid range is %p-%p\n", (void *)ram_start, (void *)ram_end);
+               }
+               if (!flash_addr_set && !fis_find_free(&flash_addr, length)) {
+                       diag_printf("Can't locate %lx(%ld) bytes free in FLASH\n", length, length);
+                       return;
+               }
     }
     // First, see if the image by this name has agreable properties
     if (img) {
-        if (flash_addr_set && (img->flash_base != flash_addr)) {
-            diag_printf("Image found, but flash address (%p)\n"
-                        "             is incorrect (present image location %p)\n",
-                        (void*)flash_addr, (void*)img->flash_base);
-            
-            return;
-        }
-        if (img->size != length) {
-            diag_printf("Image found, but length (0x%lx, necessitating image size 0x%lx)\n"
-                        "             is incorrect (present image size 0x%lx)\n",
-                        img_size, length, img->size);
-            return;
-        }
-        if (!verify_action("An image named '%s' exists", name)) {
-            return;
-        } else {                
-            if (defaults_assumed) {
-                if (no_copy &&
-                    !verify_action("* CAUTION * about to program '%s'\n            at %p..%p from %p", 
-                                   name, (void *)flash_addr, (void *)(flash_addr+img_size-1),
-                                   (void *)mem_addr)) {
-                    return;  // The guy gave up
-                }
-            }
-        }
+               if (flash_addr_set && (img->flash_base != flash_addr)) {
+                       diag_printf("Image found, but flash address (%p)\n"
+                                               "             is incorrect (present image location %p)\n",
+                                               (void *)flash_addr, (void *)img->flash_base);
+
+                       return;
+               }
+               if (img->size != length) {
+                       diag_printf("Image found, but length (0x%lx, necessitating image size 0x%lx)\n"
+                                               "             is incorrect (present image size 0x%lx)\n",
+                                               img_size, length, img->size);
+                       return;
+               }
+               if (!verify_action("An image named '%s' exists", name)) {
+                       return;
+               } else {
+                       if (defaults_assumed) {
+                               if (no_copy &&
+                                       !verify_action("* CAUTION * about to program '%s'\n                at %p..%p from %p",
+                                                                  name, (void *)flash_addr, (void *)(flash_addr+img_size-1),
+                                                                  (void *)mem_addr)) {
+                                       return;  // The guy gave up
+                               }
+                       }
+               }
     } else {
 #ifdef CYGDAT_REDBOOT_FIS_MAX_FREE_CHUNKS
-        // Make sure that any FLASH address specified directly is truly free
-        if (flash_addr_set && !no_copy) {
-            struct free_chunk chunks[CYGDAT_REDBOOT_FIS_MAX_FREE_CHUNKS];
-            int idx, num_chunks;
-            bool is_free = false;
-
-            num_chunks = find_free(chunks);
-            for (idx = 0;  idx < num_chunks;  idx++) {
-                if ((flash_addr >= chunks[idx].start) && 
-                    ((flash_addr+length-1) <= chunks[idx].end)) {
-                    is_free = true;
-                }
-            }
-            if (!is_free) {
-                diag_printf("Invalid FLASH address - not free!\n");
-                return;
-            }
-        }
-#endif
-        // If not image by that name, try and find an empty slot
-        img = (struct fis_image_desc *)fis_work_block;
-        for (i = 0;  i < fisdir_size/sizeof(*img);  i++, img++) {
-            if (img->name[0] == (unsigned char)0xFF) {
-                break;
-            }
-        }
-       if (i >= fisdir_size/sizeof(*img)) {
-           diag_printf("Can't find an empty slot in FIS directory!\n");
-           return;
+       // Make sure that any FLASH address specified directly is truly free
+       if (flash_addr_set && !no_copy) {
+           struct free_chunk chunks[CYGDAT_REDBOOT_FIS_MAX_FREE_CHUNKS];
+           int idx, num_chunks;
+           bool is_free = false;
+
+           num_chunks = find_free(chunks);
+           for (idx = 0;  idx < num_chunks;  idx++) {
+               if ((flash_addr >= chunks[idx].start) &&
+                   ((flash_addr+length-1) <= chunks[idx].end)) {
+                   is_free = true;
+               }
+           }
+           if (!is_free) {
+               diag_printf("Invalid FLASH address - not free!\n");
+               return;
+           }
        }
+#endif
+       // If not image by that name, try and find an empty slot
+       img = fis_work_block;
+       for (i = 0;  i < fisdir_size/sizeof(*img);  i++, img++) {
+           if (img->u.name[0] == 0xFF) {
+               break;
+           }
+       }
+               if (i >= fisdir_size/sizeof(*img)) {
+                       diag_printf("Can't find an empty slot in FIS directory!\n");
+                       return;
+               }
     }
     if (!no_copy) {
-        // Safety check - make sure the address range is not within the code we're running
-        if (flash_code_overlaps((void *)flash_addr, (void *)(flash_addr+img_size-1))) {
-            diag_printf("Can't program this region - contains code in use!\n");
-            return;
-        }
-        if (prog_ok) {
-            // Erase area to be programmed
-            if ((stat = flash_erase((void *)flash_addr, length, (void **)&err_addr)) != 0) {
-                diag_printf("Can't erase region at %p: %s\n", err_addr, flash_errmsg(stat));
-                prog_ok = false;
-            }
-        }
-        if (prog_ok) {
-            // Now program it
-            if ((stat = FLASH_PROGRAM((void *)flash_addr, (void *)mem_addr, img_size, (void **)&err_addr)) != 0) {
-                diag_printf("Can't program region at %p: %s\n", err_addr, flash_errmsg(stat));
-                prog_ok = false;
-            }
-        }
+               // Safety check - make sure the address range is not within the code we're running
+               if (flash_code_overlaps((void *)flash_addr, (void *)(flash_addr+img_size-1))) {
+                       diag_printf("Can't program this region - contains code in use!\n");
+                       return;
+               }
+               if (prog_ok) {
+                       // Erase area to be programmed
+                       if ((stat = flash_erase((void *)flash_addr, length, &err_addr)) != 0) {
+                               diag_printf("Can't erase region at %p: %s\n", err_addr, flash_errmsg(stat));
+                               prog_ok = false;
+                       }
+               }
+               if (prog_ok) {
+                       // Now program it
+                       if ((stat = FLASH_PROGRAM((void *)flash_addr, (void *)mem_addr, img_size, &err_addr)) != 0) {
+                               diag_printf("Can't program region at %p: %s\n", err_addr, flash_errmsg(stat));
+                               prog_ok = false;
+                       }
+               }
     }
     if (prog_ok) {
-        // Update directory
-        memset(img, 0, sizeof(*img));
-        strcpy(img->name, name);
-        img->flash_base = flash_addr;
-        img->mem_base = exec_addr_set ? exec_addr : (mem_addr_set ? mem_addr : flash_addr);
-        img->entry_point = entry_addr_set ? entry_addr : (CYG_ADDRESS)entry_address;  // Hope it's been set
-        img->size = length;
-        img->data_length = img_size;
+       // Update directory
+       memset(img, 0, sizeof(*img));
+       strcpy(img->u.name, name);
+       img->flash_base = flash_addr;
+       img->mem_base = exec_addr_set ? exec_addr : (mem_addr_set ? mem_addr : flash_addr);
+       img->entry_point = entry_addr_set ? entry_addr : (CYG_ADDRESS)entry_address;  // Hope it's been set
+       img->size = length;
+       img->data_length = img_size;
 #ifdef CYGSEM_REDBOOT_FIS_CRC_CHECK
-        if (!no_copy) {
-            img->file_cksum = cyg_crc32((unsigned char *)mem_addr, img_size);
-        } else {
-            // No way to compute this, sorry
-            img->file_cksum = 0;
-        }
-#endif
-        fis_update_directory();
+               if (!no_copy) {
+                       img->file_cksum = cyg_crc32((unsigned char *)mem_addr, img_size);
+               } else {
+                       // No way to compute this, sorry
+                       img->file_cksum = 0;
+               }
+#endif
+       fis_start_update_directory(0);
+       fis_update_directory(0, 0);
     }
 }
 
@@ -965,11 +1169,10 @@ fis_delete(int argc, char *argv[])
     void *err_addr;
     struct fis_image_desc *img;
 
-    if (!scan_opts(argc, argv, 2, 0, 0, (void *)&name, OPTION_ARG_TYPE_STR, "image name"))
-    {
-        fis_usage("invalid arguments");
-        return;
-    }
+    if (!scan_opts(argc, argv, 2, 0, 0, &name, OPTION_ARG_TYPE_STR, "image name")) {
+               fis_usage("invalid arguments");
+               return;
+       }
 #ifdef CYGHWR_REDBOOT_ARM_FLASH_SIB
     // FIXME: this is somewhat half-baked
     arm_fis_delete(name);
@@ -998,23 +1201,24 @@ fis_delete(int argc, char *argv[])
 
     img = fis_lookup(name, &i);
     if (img) {
-        if (i < num_reserved) {
-            diag_printf("Sorry, '%s' is a reserved image and cannot be deleted\n", img->name);
-            return;
-        }
-        if (!verify_action("Delete image '%s'", name)) {
-            return;
-        }
+       if (i < num_reserved) {
+           diag_printf("Sorry, '%s' is a reserved image and cannot be deleted\n", img->u.name);
+           return;
+       }
+       if (!verify_action("Delete image '%s'", name)) {
+           return;
+       }
     } else {
-        diag_printf("No image '%s' found\n", name);
-        return;
+               diag_printf("No image '%s' found\n", name);
+       return;
     }
     // Erase Data blocks (free space)
-    if ((stat = flash_erase((void *)img->flash_base, img->size, (void **)&err_addr)) != 0) {
-        diag_printf("Error erasing at %p: %s\n", err_addr, flash_errmsg(stat));
+    if ((stat = flash_erase((void *)img->flash_base, img->size, &err_addr)) != 0) {
+               diag_printf("Error erasing at %p: %s\n", err_addr, flash_errmsg(stat));
     } else {
-        img->name[0] = (unsigned char)0xFF;    
-        fis_update_directory();
+               img->u.name[0] = 0xFF;
+               fis_start_update_directory(0);
+               fis_update_directory(0, 0);
     }
 }
 
@@ -1026,104 +1230,137 @@ fis_load(int argc, char *argv[])
     CYG_ADDRESS mem_addr;
     bool mem_addr_set = false;
     bool show_cksum = false;
-    struct option_info opts[3];
+    bool load_ce = false;
+    struct option_info opts[4];
 #if defined(CYGSEM_REDBOOT_FIS_CRC_CHECK)
     unsigned long cksum;
 #endif
-    int num_options;
+    int num_options = 0;
 #if defined(CYGPRI_REDBOOT_ZLIB_FLASH) ||  defined(CYGSEM_REDBOOT_FIS_CRC_CHECK)
     bool decompress = false;
 #endif
     void *err_addr;
 
-    init_opts(&opts[0], 'b', true, OPTION_ARG_TYPE_NUM, 
-              (void *)&mem_addr, (bool *)&mem_addr_set, "memory [load] base address");
-    init_opts(&opts[1], 'c', false, OPTION_ARG_TYPE_FLG, 
-              (void *)&show_cksum, (bool *)0, "display checksum");
-    num_options = 2;
+    init_opts(&opts[num_options++], 'b', true, OPTION_ARG_TYPE_NUM,
+                         &mem_addr, &mem_addr_set, "memory [load] base address");
+    init_opts(&opts[num_options++], 'c', false, OPTION_ARG_TYPE_FLG,
+                         &show_cksum, NULL, "display checksum");
+#ifdef CYGBLD_BUILD_REDBOOT_WITH_WINCE_SUPPORT
+    init_opts(&opts[num_options++], 'w', false, OPTION_ARG_TYPE_FLG,
+                         &load_ce, NULL, "parse as Windows CE image");
+#endif
 #ifdef CYGPRI_REDBOOT_ZLIB_FLASH
-    init_opts(&opts[num_options], 'd', false, OPTION_ARG_TYPE_FLG, 
-              (void *)&decompress, 0, "decompress");
-    num_options++;
+    init_opts(&opts[num_options++], 'd', false, OPTION_ARG_TYPE_FLG,
+                         &decompress, 0, "decompress");
 #endif
 
-    CYG_ASSERT(num_options <= NUM_ELEMS(opts), "Too many options");
+    CYG_ASSERT(num_options <= num_options, "Too many options");
 
-    if (!scan_opts(argc, argv, 2, opts, num_options, (void *)&name, OPTION_ARG_TYPE_STR, "image name"))
-    {
-        fis_usage("invalid arguments");
-        return;
+    if (!scan_opts(argc, argv, 2, opts, num_options, &name,
+                                  OPTION_ARG_TYPE_STR, "image name")) {
+               fis_usage("invalid arguments");
+               return;
     }
-    if ((img = fis_lookup(name, NULL)) == (struct fis_image_desc *)0) {
-        diag_printf("No image '%s' found\n", name);
-        return;
+    if ((img = fis_lookup(name, NULL)) == NULL) {
+               diag_printf("No image '%s' found\n", name);
+               return;
     }
-    if (!mem_addr_set) {
-        mem_addr = img->mem_base;
+    if (!mem_addr_set || load_ce) {
+               mem_addr = img->mem_base;
     }
     // Load image from FLASH into RAM
 #ifdef CYGSEM_REDBOOT_VALIDATE_USER_RAM_LOADS
     if (!valid_address((void *)mem_addr)) {
-        diag_printf("Not a loadable image - try using -b ADDRESS option\n");
-        return;
+               if (!load_ce) {
+                       diag_printf("Not a loadable image - try using -b ADDRESS option\n");
+               } else {
+                       diag_printf("Not a loadable image\n");
+               }
+               return;
+    }
+#endif
+#ifdef CYGBLD_BUILD_REDBOOT_WITH_WINCE_SUPPORT
+    if (load_ce) {
+               if (mem_addr_set) {
+                       diag_printf("Warning: -b argument ignored for Windows CE image\n");
+               }
+               FLASH_Enable((void *)img->flash_base, (void *)(img->flash_base + img->size));
+               if (!ce_is_bin_image((void *)img->flash_base, img->size)) {
+                       diag_printf("** Error: This does not seem to be a valid Windows CE image\n");
+                       return;
+               }
+               if (!ce_bin_load((void *)img->flash_base, img->size)) {
+                       diag_printf("** Error: Failed to load Windows CE image\n");
+               }
+               FLASH_Disable((void *)img->flash_base, (void *)(img->flash_base + img->size));
+               // Set load address/top
+               load_address = mem_addr;
+               load_address_end = mem_addr + img->data_length;
+               return;
     }
 #endif
 #ifdef CYGPRI_REDBOOT_ZLIB_FLASH
     if (decompress) {
-        int err;
-        _pipe_t fis_load_pipe;
-        _pipe_t* p = &fis_load_pipe;
-        p->out_buf = (unsigned char*) mem_addr;
-        p->out_max = p->out_size = -1;
-        p->in_buf = (unsigned char*) img->flash_base;
-        p->in_avail = img->data_length;
-
-        err = (*_dc_init)(p);
-
-        if (0 == err)
-            err = (*_dc_inflate)(p);
-
-        // Free used resources, do final translation of
-        // error value.
-        err = (*_dc_close)(p, err);
-
-        if (0 != err && p->msg) {
-            diag_printf("decompression error: %s\n", p->msg);
-        } else {
-            diag_printf("Image loaded from %p-%p\n", (unsigned char *)mem_addr, p->out_buf);
-        }
-
-        // Set load address/top
-        load_address = mem_addr;
-        load_address_end = (unsigned long)p->out_buf;
-
-        // Reload fis directory
-        fis_read_directory();
+               int err;
+               _pipe_t fis_load_pipe;
+               _pipe_t *p = &fis_load_pipe;
+               p->out_buf = (unsigned char*) mem_addr;
+               p->out_max = p->out_size = -1;
+               p->in_buf = (unsigned char*) img->flash_base;
+               p->in_avail = img->data_length;
+
+               err = (*_dc_init)(p);
+
+               if (0 == err)
+                       err = (*_dc_inflate)(p);
+
+               // Free used resources, do final translation of
+               // error value.
+               err = (*_dc_close)(p, err);
+
+               if (0 != err && p->msg) {
+                       diag_printf("decompression error: %s\n", p->msg);
+               } else {
+                       diag_printf("Image loaded from %p-%p\n", (unsigned char *)mem_addr, p->out_buf);
+               }
+
+               // Set load address/top
+               load_address = mem_addr;
+               load_address_end = (unsigned long)p->out_buf;
+
+               // Reload fis directory
+               fis_read_directory();
     } else // dangling block
 #endif
-    {
-        flash_read((void *)img->flash_base, (void *)mem_addr, img->data_length, (void **)&err_addr);
-
-        // Set load address/top
-        load_address = mem_addr;
-        load_address_end = mem_addr + img->data_length;
-    }
+               {
+                       if (flash_read((void *)img->flash_base, (void *)mem_addr,
+                                                  img->data_length, &err_addr) != FLASH_ERR_OK) {
+                               diag_printf("** Error: Failed to load image from flash\n");
+                               return;
+                       }
+
+                       // Set load address/top
+                       load_address = mem_addr;
+                       load_address_end = mem_addr + img->data_length;
+               }
     entry_address = (unsigned long)img->entry_point;
 
 #ifdef CYGSEM_REDBOOT_FIS_CRC_CHECK
     cksum = cyg_crc32((unsigned char *)mem_addr, img->data_length);
     if (show_cksum) {
-        diag_printf("Checksum: 0x%08lx\n", cksum);
+               diag_printf("Checksum: 0x%08lx\n", cksum);
     }
     // When decompressing, leave CRC checking to decompressor
     if (!decompress && img->file_cksum) {
-        if (cksum != img->file_cksum) {
-            diag_printf("** Warning - checksum failure.  stored: 0x%08lx, computed: 0x%08lx\n",
-                        img->file_cksum, cksum);
-            entry_address = (unsigned long)NO_MEMORY;
-        }
+               if (cksum != img->file_cksum) {
+                       diag_printf("** Warning - checksum failure.      stored: 0x%08lx, computed: 0x%08lx\n",
+                                               img->file_cksum, cksum);
+                       entry_address = (unsigned long)NO_MEMORY;
+               }
     }
 #endif
+    diag_printf("image loaded 0x%08lx-0x%08lx, assumed entry at 0x%08lx\n",
+                               load_address, load_address_end - 1, entry_address);
 }
 #endif // CYGOPT_REDBOOT_FIS
 
@@ -1140,21 +1377,21 @@ fis_write(int argc, char *argv[])
     struct option_info opts[3];
     bool prog_ok;
 
-    init_opts(&opts[0], 'b', true, OPTION_ARG_TYPE_NUM, 
-              (void *)&mem_addr, (bool *)&mem_addr_set, "memory base address");
-    init_opts(&opts[1], 'f', true, OPTION_ARG_TYPE_NUM, 
-              (void *)&flash_addr, (bool *)&flash_addr_set, "FLASH memory base address");
-    init_opts(&opts[2], 'l', true, OPTION_ARG_TYPE_NUM, 
-              (void *)&length, (bool *)&length_set, "image length [in FLASH]");
+    init_opts(&opts[0], 'b', true, OPTION_ARG_TYPE_NUM,
+                         &mem_addr, &mem_addr_set, "memory base address");
+    init_opts(&opts[1], 'f', true, OPTION_ARG_TYPE_NUM,
+                         &flash_addr, &flash_addr_set, "FLASH memory base address");
+    init_opts(&opts[2], 'l', true, OPTION_ARG_TYPE_NUM,
+                         &length, &length_set, "image length [in FLASH]");
     if (!scan_opts(argc, argv, 2, opts, 3, 0, 0, 0))
-    {
-        fis_usage("invalid arguments");
-        return;
-    }
+               {
+                       fis_usage("invalid arguments");
+                       return;
+               }
 
     if (!mem_addr_set || !flash_addr_set || !length_set) {
-        fis_usage("required parameter missing");
-        return;
+               fis_usage("required parameter missing");
+               return;
     }
 
     // Round up length to FLASH block size
@@ -1162,45 +1399,45 @@ fis_write(int argc, char *argv[])
     length = ((length + flash_block_size - 1) / flash_block_size) * flash_block_size;
 #endif
     if (flash_addr_set &&
-        ((stat = flash_verify_addr((void *)flash_addr)) ||
-         (stat = flash_verify_addr((void *)(flash_addr+length-1))))) {
-        _show_invalid_flash_address(flash_addr, stat);
-        return;
+               ((stat = flash_verify_addr((void *)flash_addr)) ||
+                (stat = flash_verify_addr((void *)(flash_addr + length - 1))))) {
+               _show_invalid_flash_address(flash_addr, stat);
+               return;
     }
     if (flash_addr_set && flash_addr & (flash_block_size-1)) {
-        diag_printf("Invalid FLASH address: %p\n", (void *)flash_addr);
-        diag_printf("   must be 0x%x aligned\n", flash_block_size);
-        return;
+               diag_printf("Invalid FLASH address: %p\n", (void *)flash_addr);
+               diag_printf("   must be 0x%x aligned\n", flash_block_size);
+               return;
     }
     if ((mem_addr < (CYG_ADDRESS)ram_start) ||
-        ((mem_addr+length) >= (CYG_ADDRESS)ram_end)) {
-        diag_printf("** WARNING: RAM address: %p may be invalid\n", (void *)mem_addr);
-        diag_printf("   valid range is %p-%p\n", (void *)ram_start, (void *)ram_end);
+               ((mem_addr+length) >= (CYG_ADDRESS)ram_end)) {
+               diag_printf("** WARNING: RAM address: %p may be invalid\n", (void *)mem_addr);
+               diag_printf("   valid range is %p-%p\n", (void *)ram_start, (void *)ram_end);
     }
     // Safety check - make sure the address range is not within the code we're running
-    if (flash_code_overlaps((void *)flash_addr, (void *)(flash_addr+length-1))) {
-        diag_printf("Can't program this region - contains code in use!\n");
-        return;
+    if (flash_code_overlaps((void *)flash_addr, (void *)(flash_addr + length - 1))) {
+               diag_printf("Can't program this region - contains code in use!\n");
+               return;
     }
-    if (!verify_action("* CAUTION * about to program FLASH\n            at %p..%p from %p", 
-                       (void *)flash_addr, (void *)(flash_addr+length-1),
-                       (void *)mem_addr)) {
-        return;  // The guy gave up
+    if (!verify_action("* CAUTION * about to program FLASH\n           at %p..%p from %p",
+                                          (void *)flash_addr, (void *)(flash_addr + length - 1),
+                                          (void *)mem_addr)) {
+               return;  // The guy gave up
     }
     prog_ok = true;
     if (prog_ok) {
-        // Erase area to be programmed
-        if ((stat = flash_erase((void *)flash_addr, length, (void **)&err_addr)) != 0) {
-            diag_printf("Can't erase region at %p: %s\n", err_addr, flash_errmsg(stat));
-            prog_ok = false;
-        }
+               // Erase area to be programmed
+               if ((stat = flash_erase((void *)flash_addr, length, &err_addr)) != 0) {
+                       diag_printf("Can't erase region at %p: %s\n", err_addr, flash_errmsg(stat));
+                       prog_ok = false;
+               }
     }
     if (prog_ok) {
-        // Now program it
-        if ((stat = FLASH_PROGRAM((void *)flash_addr, (void *)mem_addr, length, (void **)&err_addr)) != 0) {
-            diag_printf("Can't program region at %p: %s\n", err_addr, flash_errmsg(stat));
-            prog_ok = false;
-        }
+               // Now program it
+               if ((stat = FLASH_PROGRAM((void *)flash_addr, (void *)mem_addr, length, &err_addr)) != 0) {
+                       diag_printf("Can't program region at %p: %s\n", err_addr, flash_errmsg(stat));
+                       prog_ok = false;
+               }
     }
 }
 
@@ -1215,38 +1452,38 @@ fis_erase(int argc, char *argv[])
     void *err_addr;
     struct option_info opts[2];
 
-    init_opts(&opts[0], 'f', true, OPTION_ARG_TYPE_NUM, 
-              (void *)&flash_addr, (bool *)&flash_addr_set, "FLASH memory base address");
-    init_opts(&opts[1], 'l', true, OPTION_ARG_TYPE_NUM, 
-              (void *)&length, (bool *)&length_set, "length");
-    if (!scan_opts(argc, argv, 2, opts, 2, (void **)0, 0, ""))
-    {
-        fis_usage("invalid arguments");
-        return;
-    }
+    init_opts(&opts[0], 'f', true, OPTION_ARG_TYPE_NUM,
+                         &flash_addr, &flash_addr_set, "FLASH memory base address");
+    init_opts(&opts[1], 'l', true, OPTION_ARG_TYPE_NUM,
+                         &length, &length_set, "length");
+    if (!scan_opts(argc, argv, 2, opts, 2, NULL, 0, NULL))
+               {
+                       fis_usage("invalid arguments");
+                       return;
+               }
 
     if (!flash_addr_set || !length_set) {
-        fis_usage("missing argument");
-        return;
+               fis_usage("missing argument");
+               return;
     }
     if (flash_addr_set &&
-        ((stat = flash_verify_addr((void *)flash_addr)) ||
-         (stat = flash_verify_addr((void *)(flash_addr+length-1))))) {
-        _show_invalid_flash_address(flash_addr, stat);
-        return;
+               ((stat = flash_verify_addr((void *)flash_addr)) ||
+                (stat = flash_verify_addr((void *)(flash_addr + length - 1))))) {
+               _show_invalid_flash_address(flash_addr, stat);
+               return;
     }
     if (flash_addr_set && flash_addr & (flash_block_size-1)) {
-        diag_printf("Invalid FLASH address: %p\n", (void *)flash_addr);
-        diag_printf("   must be 0x%x aligned\n", flash_block_size);
-        return;
+               diag_printf("Invalid FLASH address: %p\n", (void *)flash_addr);
+               diag_printf("   must be 0x%x aligned\n", flash_block_size);
+               return;
     }
     // Safety check - make sure the address range is not within the code we're running
-    if (flash_code_overlaps((void *)flash_addr, (void *)(flash_addr+length-1))) {
-        diag_printf("Can't erase this region - contains code in use!\n");
-        return;
+    if (flash_code_overlaps((void *)flash_addr, (void *)(flash_addr + length - 1))) {
+               diag_printf("Can't erase this region - contains code in use!\n");
+               return;
     }
-    if ((stat = flash_erase((void *)flash_addr, length, (void **)&err_addr)) != 0) {
-        diag_printf("Error erasing at %p: %s\n", err_addr, flash_errmsg(stat));
+    if ((stat = flash_erase((void *)flash_addr, length, &err_addr)) != 0) {
+               diag_printf("Error erasing at %p: %s\n", err_addr, flash_errmsg(stat));
     }
 }
 
@@ -1264,38 +1501,40 @@ fis_lock(int argc, char *argv[])
     void *err_addr;
     struct option_info opts[2];
 
-    init_opts(&opts[0], 'f', true, OPTION_ARG_TYPE_NUM, 
-              (void *)&flash_addr, (bool *)&flash_addr_set, "FLASH memory base address");
-    init_opts(&opts[1], 'l', true, OPTION_ARG_TYPE_NUM, 
-              (void *)&length, (bool *)&length_set, "length");
+    init_opts(&opts[0], 'f', true, OPTION_ARG_TYPE_NUM,
+                         &flash_addr, &flash_addr_set, "FLASH memory base address");
+    init_opts(&opts[1], 'l', true, OPTION_ARG_TYPE_NUM,
+                         &length, &length_set, "length");
     if (!scan_opts(argc, argv, 2, opts, 2, &name, OPTION_ARG_TYPE_STR, "image name"))
-    {
-        fis_usage("invalid arguments");
-        return;
-    }
-
+               {
+                       fis_usage("invalid arguments");
+                       return;
+               }
+#ifdef CYGOPT_REDBOOT_FIS
     /* Get parameters from image if specified */
     if (name) {
-        struct fis_image_desc *img;
-        if ((img = fis_lookup(name, NULL)) == (struct fis_image_desc *)0) {
-            diag_printf("No image '%s' found\n", name);
-            return;
-        }
-
-        flash_addr = img->flash_base;
-        length = img->size;
-    } else if (!flash_addr_set || !length_set) {
-        fis_usage("missing argument");
-        return;
-    }
+               struct fis_image_desc *img;
+               if ((img = fis_lookup(name, NULL)) == NULL) {
+                       diag_printf("No image '%s' found\n", name);
+                       return;
+               }
+
+       flash_addr = img->flash_base;
+       length = img->size;
+    } else
+#endif
+               if (!flash_addr_set || !length_set) {
+                       fis_usage("missing argument");
+                       return;
+               }
     if (flash_addr_set &&
-        ((stat = flash_verify_addr((void *)flash_addr)) ||
-         (stat = flash_verify_addr((void *)(flash_addr+length-1))))) {
-        _show_invalid_flash_address(flash_addr, stat);
-        return;
+               ((stat = flash_verify_addr((void *)flash_addr)) ||
+                (stat = flash_verify_addr((void *)(flash_addr + length - 1))))) {
+               _show_invalid_flash_address(flash_addr, stat);
+               return;
     }
-    if ((stat = flash_lock((void *)flash_addr, length, (void **)&err_addr)) != 0) {
-        diag_printf("Error locking at %p: %s\n", err_addr, flash_errmsg(stat));
+    if ((stat = flash_lock((void *)flash_addr, length, &err_addr)) != 0) {
+               diag_printf("Error locking at %p: %s\n", err_addr, flash_errmsg(stat));
     }
 }
 
@@ -1311,38 +1550,40 @@ fis_unlock(int argc, char *argv[])
     void *err_addr;
     struct option_info opts[2];
 
-    init_opts(&opts[0], 'f', true, OPTION_ARG_TYPE_NUM, 
-              (void *)&flash_addr, (bool *)&flash_addr_set, "FLASH memory base address");
-    init_opts(&opts[1], 'l', true, OPTION_ARG_TYPE_NUM, 
-              (void *)&length, (bool *)&length_set, "length");
+    init_opts(&opts[0], 'f', true, OPTION_ARG_TYPE_NUM,
+                         &flash_addr, &flash_addr_set, "FLASH memory base address");
+    init_opts(&opts[1], 'l', true, OPTION_ARG_TYPE_NUM,
+                         &length, &length_set, "length");
     if (!scan_opts(argc, argv, 2, opts, 2, &name, OPTION_ARG_TYPE_STR, "image name"))
-    {
-        fis_usage("invalid arguments");
-        return;
-    }
-
+               {
+                       fis_usage("invalid arguments");
+                       return;
+               }
+#ifdef CYGOPT_REDBOOT_FIS
     if (name) {
-        struct fis_image_desc *img;
-        if ((img = fis_lookup(name, NULL)) == (struct fis_image_desc *)0) {
-            diag_printf("No image '%s' found\n", name);
-            return;
-        }
-
-        flash_addr = img->flash_base;
-        length = img->size;
-    } else  if (!flash_addr_set || !length_set) {
-        fis_usage("missing argument");
-        return;
-    }
+               struct fis_image_desc *img;
+               if ((img = fis_lookup(name, NULL)) == NULL) {
+                       diag_printf("No image '%s' found\n", name);
+                       return;
+               }
+
+       flash_addr = img->flash_base;
+       length = img->size;
+    } else
+#endif
+               if (!flash_addr_set || !length_set) {
+                       fis_usage("missing argument");
+                       return;
+               }
     if (flash_addr_set &&
-        ((stat = flash_verify_addr((void *)flash_addr)) ||
-         (stat = flash_verify_addr((void *)(flash_addr+length-1))))) {
-        _show_invalid_flash_address(flash_addr, stat);
-        return;
+               ((stat = flash_verify_addr((void *)flash_addr)) ||
+                (stat = flash_verify_addr((void *)(flash_addr + length - 1))))) {
+               _show_invalid_flash_address(flash_addr, stat);
+               return;
     }
 
-    if ((stat = flash_unlock((void *)flash_addr, length, (void **)&err_addr)) != 0) {
-        diag_printf("Error unlocking at %p: %s\n", err_addr, flash_errmsg(stat));
+    if ((stat = flash_unlock((void *)flash_addr, length, &err_addr)) != 0) {
+               diag_printf("Error unlocking at %p: %s\n", err_addr, flash_errmsg(stat));
     }
 }
 #endif
@@ -1354,53 +1595,137 @@ void
 _flash_info(void)
 {
     if (!__flash_init) return;
-    diag_printf("FLASH: %p - 0x%x, %d blocks of %p bytes each.\n", 
-           flash_start, (CYG_ADDRWORD)flash_end + 1, flash_num_blocks, (void *)flash_block_size);
+    diag_printf("FLASH: %p - 0x%x, %d blocks of 0x%08x bytes each.\n",
+                               flash_start, (CYG_ADDRWORD)flash_end + 1, flash_num_blocks, flash_block_size);
 }
 
-bool
+/* Returns -1 on failure, 0 on success, 1 if it was successfull
+ but a failed fis update was detected  */
+int
 do_flash_init(void)
 {
-    int stat;
-
-    if (!__flash_init) {
-        __flash_init = 1;
-        if ((stat = flash_init(diag_printf)) != 0) {
-            diag_printf("FLASH: driver init failed: %s\n", flash_errmsg(stat));
-            return false;
-        }
-        flash_get_limits((void *)0, (void **)&flash_start, (void **)&flash_end);
-        // Keep 'end' address as last valid location, to avoid wrap around problems
-        flash_end = (void *)((CYG_ADDRESS)flash_end - 1);
-        flash_get_block_info(&flash_block_size, &flash_num_blocks);
+       int stat;
+
+#ifdef CYGOPT_REDBOOT_REDUNDANT_FIS
+       struct fis_image_desc img0;
+       struct fis_image_desc img1;
+       int fis_update_was_interrupted = 0;
+       void *err_addr;
+
+       //check the size of fis_valid_info
+       CYG_ASSERT((sizeof(struct fis_valid_info) <= sizeof(img0.u.name)),
+                          "fis_valid_info size mismatch");
+       //try to check the alignment of version_count
+       CYG_ASSERT(((&img0.u.valid_info.version_count - &img0) % sizeof(unsigned long) == 0),
+                          "alignment problem");
+#endif
+       if (!__flash_init) {
+               __flash_init = 1;
+               if ((stat = flash_init(diag_printf)) != 0) {
+                       diag_printf("FLASH: driver init failed: %s\n", flash_errmsg(stat));
+                       return -1;
+               }
+               flash_get_limits(NULL, &flash_start, &flash_end);
+               // Keep 'end' address as last valid location, to avoid wrap around problems
+               flash_end = (void *)((CYG_ADDRESS)flash_end - 1);
+               flash_get_block_info(&flash_block_size, &flash_num_blocks);
 #ifdef CYGOPT_REDBOOT_FIS
-        fisdir_size = CYGNUM_REDBOOT_FIS_DIRECTORY_ENTRY_COUNT * CYGNUM_REDBOOT_FIS_DIRECTORY_ENTRY_SIZE;
-        fisdir_size = ((fisdir_size + flash_block_size - 1) / flash_block_size) * flash_block_size;
+               fisdir_size = CYGNUM_REDBOOT_FIS_DIRECTORY_ENTRY_COUNT * CYGNUM_REDBOOT_FIS_DIRECTORY_ENTRY_SIZE;
+               fisdir_size = ((fisdir_size + flash_block_size - 1) / flash_block_size) * flash_block_size;
 # if defined(CYGPRI_REDBOOT_ZLIB_FLASH) && defined(CYGOPT_REDBOOT_FIS_ZLIB_COMMON_BUFFER)
-       fis_work_block = fis_zlib_common_buffer;
-       if(CYGNUM_REDBOOT_FIS_ZLIB_COMMON_BUFFER_SIZE < fisdir_size) {
-            diag_printf("FLASH: common buffer too small\n");
-            return false;
-       }
+               fis_work_block = fis_zlib_common_buffer;
+               if (CYGNUM_REDBOOT_FIS_ZLIB_COMMON_BUFFER_SIZE < fisdir_size) {
+                       diag_printf("FLASH: common buffer too small\n");
+                       return -1;
+               }
 # else
-        workspace_end = (unsigned char *)(workspace_end-fisdir_size);
-        fis_work_block = workspace_end;
+               workspace_end = (unsigned char *)(workspace_end - fisdir_size);
+               fis_work_block = workspace_end;
 # endif
-        if (CYGNUM_REDBOOT_FIS_DIRECTORY_BLOCK < 0) {
-            fis_addr = (void *)((CYG_ADDRESS)flash_end + 1 +
-                                (CYGNUM_REDBOOT_FIS_DIRECTORY_BLOCK*flash_block_size));
-        } else {
-            fis_addr = (void *)((CYG_ADDRESS)flash_start + 
-                                (CYGNUM_REDBOOT_FIS_DIRECTORY_BLOCK*flash_block_size));
-        }
-        if (((CYG_ADDRESS)fis_addr + fisdir_size - 1) > (CYG_ADDRESS)flash_end) {
-            diag_printf("FIS directory doesn't fit\n");
-            return false;
-        }
-        fis_read_directory();
+               if (CYGNUM_REDBOOT_FIS_DIRECTORY_BLOCK < 0) {
+                       fis_addr = (void *)((CYG_ADDRESS)flash_end + 1 +
+                                                               (CYGNUM_REDBOOT_FIS_DIRECTORY_BLOCK * flash_block_size));
+               } else {
+                       fis_addr = (void *)((CYG_ADDRESS)flash_start +
+                                                               (CYGNUM_REDBOOT_FIS_DIRECTORY_BLOCK * flash_block_size));
+               }
+#if defined(CYGHWR_DEVS_FLASH_MXC_MULTI) && defined(MXCFLASH_SELECT_NAND)
+               extern int mxc_nand_fis_start(void);
+               if (IS_FIS_FROM_NAND()) {
+                       fis_addr = (void *)((CYG_ADDRESS)flash_start + mxc_nand_fis_start());
+               }
+#endif
+
+#if defined(IMXFLASH_SELECT_SPI_NOR)
+               extern int mxc_spi_nor_fis_start(void);
+               if (IS_FIS_FROM_SPI_NOR()) {
+                       fis_addr = (void *)((CYG_ADDRESS)flash_start + mxc_spi_nor_fis_start());
+               }
+#endif
+
+#if defined(MXCFLASH_SELECT_MMC)
+               if (IS_FIS_FROM_MMC()) {
+                       fis_addr = (void *)REDBOOT_IMAGE_SIZE;
+               }
+#endif
+
+               if (((CYG_ADDRESS)fis_addr + fisdir_size - 1) > (CYG_ADDRESS)flash_end) {
+                       diag_printf("FIS directory doesn't fit\n");
+                       return -1;
+               }
+#ifdef CYGOPT_REDBOOT_REDUNDANT_FIS
+
+               if (CYGNUM_REDBOOT_FIS_REDUNDANT_DIRECTORY_BLOCK < 0) {
+                       redundant_fis_addr = (void *)((CYG_ADDRESS)flash_end + 1 +
+                                                                                 (CYGNUM_REDBOOT_FIS_REDUNDANT_DIRECTORY_BLOCK *
+                                                                                  flash_block_size));
+               } else {
+                       redundant_fis_addr = (void *)((CYG_ADDRESS)flash_start +
+                                                                                 (CYGNUM_REDBOOT_FIS_REDUNDANT_DIRECTORY_BLOCK *
+                                                                                  flash_block_size));
+               }
+
+               if (((CYG_ADDRESS)redundant_fis_addr + fisdir_size - 1) > (CYG_ADDRESS)flash_end) {
+                       diag_printf("Redundant FIS directory doesn't fit\n");
+                       return -1;
+               }
+               FLASH_READ(fis_addr, &img0, sizeof(img0), &err_addr);
+               FLASH_READ(redundant_fis_addr, &img1, sizeof(img1), &err_addr);
+
+               if (strncmp(img0.u.valid_info.magic_name, CYG_REDBOOT_RFIS_VALID_MAGIC,
+                                       CYG_REDBOOT_RFIS_VALID_MAGIC_LENGTH) != 0) {
+                               memset(&img0, 0, sizeof(img0));
+                       }
+
+               if (strncmp(img1.u.valid_info.magic_name, CYG_REDBOOT_RFIS_VALID_MAGIC,
+                                       CYG_REDBOOT_RFIS_VALID_MAGIC_LENGTH) != 0) {
+                       memset(&img1, 0, sizeof(img0));
+               }
+
+#ifdef REDBOOT_FLASH_REVERSE_BYTEORDER
+               img0.u.valid_info.version_count = CYG_SWAP32(img0.u.valid_info.version_count);
+               img1.u.valid_info.version_count = CYG_SWAP32(img1.u.valid_info.version_count);
+#endif
+
+               if (fis_get_valid_buf(&img0, &img1, &fis_update_was_interrupted) == 1) {
+                       // Valid, so swap primary and secondary
+                       void *tmp;
+                       tmp = fis_addr;
+                       fis_addr = redundant_fis_addr;
+                       redundant_fis_addr = tmp;
+               }
+#endif
+               fis_read_directory();
+#endif
+       }
+#ifdef CYGOPT_REDBOOT_REDUNDANT_FIS
+       if (fis_update_was_interrupted)
+               return 1;
+       else
+               return 0;
+#else
+       return 0;
 #endif
-    }
-    return true;
 }
 
 // Wrapper to avoid compiler warnings
@@ -1421,19 +1746,17 @@ do_fis(int argc, char *argv[])
     struct cmd *cmd;
 
     if (argc < 2) {
-        fis_usage("too few arguments");
-        return;
+               fis_usage("too few arguments");
+               return;
     }
-    if (!do_flash_init()) {
-        diag_printf("Sorry, no FLASH memory is available\n");
-        return;
+    if (do_flash_init() < 0) {
+       diag_printf("Sorry, no FLASH memory is available\n");
+       return;
     }
-    if ((cmd = cmd_search(__FIS_cmds_TAB__, &__FIS_cmds_TAB_END__, 
-                          argv[1])) != (struct cmd *)0) {
-        (cmd->fun)(argc, argv);
-        return;
+    if ((cmd = cmd_search(__FIS_cmds_TAB__, &__FIS_cmds_TAB_END__,
+                         argv[1])) != NULL) {
+               (cmd->fun)(argc, argv);
+               return;
     }
     fis_usage("unrecognized command");
 }
-
-// EOF flash.c