Starterkit 5 Release 1.6
[karo-tx-redboot.git] / packages / redboot / v2_0 / src / flash.c
1 //==========================================================================
2 //
3 //      flash.c
4 //
5 //      RedBoot - FLASH memory support
6 //
7 //==========================================================================
8 //####ECOSGPLCOPYRIGHTBEGIN####
9 // -------------------------------------------
10 // This file is part of eCos, the Embedded Configurable Operating System.
11 // Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004 Red Hat, Inc.
12 // Copyright (C) 2003, 2004 Gary Thomas
13 //
14 // eCos is free software; you can redistribute it and/or modify it under
15 // the terms of the GNU General Public License as published by the Free
16 // Software Foundation; either version 2 or (at your option) any later version.
17 //
18 // eCos is distributed in the hope that it will be useful, but WITHOUT ANY
19 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
20 // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
21 // for more details.
22 //
23 // You should have received a copy of the GNU General Public License along
24 // with eCos; if not, write to the Free Software Foundation, Inc.,
25 // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
26 //
27 // As a special exception, if other files instantiate templates or use macros
28 // or inline functions from this file, or you compile this file and link it
29 // with other works to produce a work based on this file, this file does not
30 // by itself cause the resulting work to be covered by the GNU General Public
31 // License. However the source code for this file must still be made available
32 // in accordance with section (3) of the GNU General Public License.
33 //
34 // This exception does not invalidate any other reasons why a work based on
35 // this file might be covered by the GNU General Public License.
36 //
37 // Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
38 // at http://sources.redhat.com/ecos/ecos-license/
39 // -------------------------------------------
40 //####ECOSGPLCOPYRIGHTEND####
41 //==========================================================================
42 //#####DESCRIPTIONBEGIN####
43 //
44 // Author(s):    gthomas
45 // Contributors: gthomas, tkoeller
46 // Date:         2000-07-28
47 // Purpose:
48 // Description:
49 //
50 // This code is part of RedBoot (tm).
51 //
52 //####DESCRIPTIONEND####
53 //
54 //==========================================================================
55
56 #include <redboot.h>
57 #define  _FLASH_PRIVATE_
58 #include <cyg/io/flash.h>
59 #include <fis.h>
60 #include <sib.h>
61 #include <cyg/infra/cyg_ass.h>         // assertion macros
62
63 #ifdef CYGBLD_BUILD_REDBOOT_WITH_WINCE_SUPPORT
64 #include <wince.h>
65 #endif
66
67 #ifdef CYGSEM_REDBOOT_FLASH_COMBINED_FIS_AND_CONFIG
68 // Note horrid intertwining of functions, to save precious FLASH
69 extern void conf_endian_fixup(void *p);
70 #endif
71
72 // Round a quantity up
73 #define _rup(n,s) ((((n)+(s-1))/s)*s)
74
75 #ifdef CYGOPT_REDBOOT_FIS
76 // Image management functions
77 local_cmd_entry("init",
78                 "Initialize FLASH Image System [FIS]",
79                 "[-f]",
80                 fis_init,
81                 FIS_cmds
82     );
83 #ifdef CYGSEM_REDBOOT_FIS_CRC_CHECK
84 # define FIS_LIST_OPTS "[-c] [-d]"
85 #else
86 # define FIS_LIST_OPTS "[-d]"
87 #endif
88 local_cmd_entry("list",
89                 "Display contents of FLASH Image System [FIS]",
90                 FIS_LIST_OPTS,
91                 fis_list,
92                 FIS_cmds
93     );
94 local_cmd_entry("free",
95                 "Display free [available] locations within FLASH Image System [FIS]",
96                 "",
97                 fis_free,
98                 FIS_cmds
99     );
100 local_cmd_entry("delete",
101                 "Delete an image from FLASH Image System [FIS]",
102                 "name",
103                 fis_delete,
104                 FIS_cmds
105     );
106
107 static char fis_load_usage[] =
108 #ifdef CYGPRI_REDBOOT_ZLIB_FLASH
109                       "[-d] "
110 #endif
111                       "[-b <memory_load_address>] [-c] "
112 #ifdef CYGBLD_BUILD_REDBOOT_WITH_WINCE_SUPPORT
113                       "[-w]"
114 #endif
115                       "name\n"
116                       "Options:\n"
117 #ifdef CYGPRI_REDBOOT_ZLIB_FLASH
118                       "\t-d: decompress\n"
119 #endif
120                       "\t-c: print checksum\n"
121 #ifdef CYGBLD_BUILD_REDBOOT_WITH_WINCE_SUPPORT
122                       "\t-w: load as Windows CE image\n"
123 #endif
124                       ;
125
126 local_cmd_entry("load",
127                 "Load image from FLASH Image System [FIS] into RAM",
128                 fis_load_usage,
129                 fis_load,
130                 FIS_cmds
131     );
132 local_cmd_entry("create",
133                 "Create an image",
134                 "[-b <mem_base>] [-l <image_length>] [-s <data_length>]\n"
135                 "      [-f <flash_addr>] [-e <entry_point>] [-r <ram_addr>] [-n] <name>",
136                 fis_create,
137                 FIS_cmds
138     );
139 #endif
140
141 // Raw flash access functions
142 local_cmd_entry("erase",
143                 "Erase FLASH contents",
144                 "-f <flash_addr> -l <length>",
145                 fis_erase,
146                 FIS_cmds
147     );
148 #ifdef CYGHWR_IO_FLASH_BLOCK_LOCKING
149 local_cmd_entry("lock",
150                 "LOCK FLASH contents",
151                 "[-f <flash_addr> -l <length>] [name]",
152                 fis_lock,
153                 FIS_cmds
154     );
155 local_cmd_entry("unlock",
156                 "UNLOCK FLASH contents",
157                 "[-f <flash_addr> -l <length>] [name]",
158                 fis_unlock,
159                 FIS_cmds
160     );
161 #endif
162 local_cmd_entry("write",
163                 "Write raw data directly to FLASH",
164                 "-f <flash_addr> -b <mem_base> -l <image_length>",
165                 fis_write,
166                 FIS_cmds
167     );
168
169 // Define table boundaries
170 CYG_HAL_TABLE_BEGIN( __FIS_cmds_TAB__, FIS_cmds);
171 CYG_HAL_TABLE_END( __FIS_cmds_TAB_END__, FIS_cmds);
172
173 extern struct cmd __FIS_cmds_TAB__[], __FIS_cmds_TAB_END__;
174
175 // CLI function
176 static cmd_fun do_fis;
177 RedBoot_nested_cmd("fis",
178             "Manage FLASH images",
179             "{cmds}",
180             do_fis,
181             __FIS_cmds_TAB__, &__FIS_cmds_TAB_END__
182     );
183
184 // Local data used by these routines
185 void *flash_start, *flash_end;
186 int flash_block_size, flash_num_blocks;
187 #ifdef CYGOPT_REDBOOT_FIS
188 void *fis_work_block;
189 void *fis_addr;
190 #ifdef CYGOPT_REDBOOT_REDUNDANT_FIS
191 void *redundant_fis_addr;
192 #endif
193 int fisdir_size;  // Size of FIS directory.
194 #endif
195 #ifdef CYGSEM_REDBOOT_FLASH_CONFIG
196 extern void *cfg_base;   // Location in Flash of config data
197 extern int   cfg_size;   // Length of config data - rounded to Flash block size
198 extern struct _config *config;
199 #endif
200
201 static void
202 fis_usage(char *why)
203 {
204     diag_printf("*** invalid 'fis' command: %s\n", why);
205     cmd_usage(__FIS_cmds_TAB__, &__FIS_cmds_TAB_END__, "fis ");
206 }
207
208 static void
209 _show_invalid_flash_address(CYG_ADDRESS flash_addr, int stat)
210 {
211     diag_printf("Invalid FLASH address %p: %s\n", (void *)flash_addr, flash_errmsg(stat));
212     diag_printf("   valid range is %p-%p\n", flash_start, flash_end);
213 }
214
215 #ifdef CYGOPT_REDBOOT_FIS
216
217 // fis_endian_fixup() is used to swap endianess if required.
218 //
219 static inline void fis_endian_fixup(void *addr)
220 {
221 #ifdef REDBOOT_FLASH_REVERSE_BYTEORDER
222     struct fis_image_desc *p = addr;
223     int cnt = fisdir_size / sizeof(struct fis_image_desc);
224
225     while (cnt-- > 0) {
226                 p->flash_base = CYG_SWAP32(p->flash_base);
227                 p->mem_base = CYG_SWAP32(p->mem_base);
228                 p->size = CYG_SWAP32(p->size);
229                 p->entry_point = CYG_SWAP32(p->entry_point);
230                 p->data_length = CYG_SWAP32(p->data_length);
231                 p->desc_cksum = CYG_SWAP32(p->desc_cksum);
232                 p->file_cksum = CYG_SWAP32(p->file_cksum);
233                 p++;
234     }
235 #endif
236 }
237
238 void
239 fis_read_directory(void)
240 {
241     void *err_addr;
242
243     FLASH_READ(fis_addr, fis_work_block, fisdir_size, &err_addr);
244     fis_endian_fixup(fis_work_block);
245 }
246
247 struct fis_image_desc *
248 fis_lookup(char *name, int *num)
249 {
250     int i;
251     struct fis_image_desc *img;
252
253     fis_read_directory();
254
255     img = (struct fis_image_desc *)fis_work_block;
256     for (i = 0;  i < fisdir_size/sizeof(*img);  i++, img++) {
257                 if ((img->u.name[0] != 0xFF) &&
258                         (strcasecmp(name, img->u.name) == 0)) {
259                         if (num) *num = i;
260                         return img;
261                 }
262     }
263     return NULL;
264 }
265
266 int fis_start_update_directory(int autolock)
267 {
268 #ifdef CYGOPT_REDBOOT_REDUNDANT_FIS
269 #ifdef CYGHWR_IO_FLASH_BLOCK_LOCKING
270 #ifdef CYGSEM_REDBOOT_FLASH_LOCK_SPECIAL
271         // Ensure [quietly] that the directory is unlocked before trying to update and locked again afterwards
272         int do_autolock = 1;
273 #else
274         int do_autolock = autolock;
275 #endif
276 #endif
277
278         struct fis_image_desc *img;
279         void *err_addr;
280         void *tmp_fis_addr;
281
282         /*exchange old and new valid fis tables*/
283         tmp_fis_addr = fis_addr;
284         fis_addr = redundant_fis_addr;
285         redundant_fis_addr = tmp_fis_addr;
286
287         //adjust the contents of the new fis table
288         img = fis_work_block;
289
290         memcpy(img->u.valid_info.magic_name, CYG_REDBOOT_RFIS_VALID_MAGIC,
291                    CYG_REDBOOT_RFIS_VALID_MAGIC_LENGTH);
292         img->u.valid_info.valid_flag[0] = CYG_REDBOOT_RFIS_IN_PROGRESS;
293         img->u.valid_info.valid_flag[1] = CYG_REDBOOT_RFIS_IN_PROGRESS;
294         img->u.valid_info.version_count = img->u.valid_info.version_count+1;
295
296         //ready to go....
297 #ifdef CYGHWR_IO_FLASH_BLOCK_LOCKING
298         if (do_autolock)
299                 flash_unlock((void *)fis_addr, fisdir_size, &err_addr);
300 #endif
301
302         flash_erase(fis_addr, fisdir_size, &err_addr);
303         //now magic is 0xffffffff
304         fis_endian_fixup(fis_work_block);
305         flash_program(fis_addr, fis_work_block, flash_block_size, &err_addr);
306         fis_endian_fixup(fis_work_block);
307         //now magic is 0xff1234ff, valid is IN_PROGRESS, version_count is the old one +1
308
309 #else
310         /* nothing to do here without redundant fis */
311 #endif
312         return 0;
313
314 }
315
316 int
317 fis_update_directory(int autolock, int error)
318 {
319         void *err_addr;
320
321 #ifdef CYGHWR_IO_FLASH_BLOCK_LOCKING
322 #ifdef CYGSEM_REDBOOT_FLASH_LOCK_SPECIAL
323         // Ensure [quietly] that the directory is unlocked before trying to update and locked again afterwards
324         int do_autolock = 1;
325 #else
326         int do_autolock = autolock;
327 #endif
328 #endif
329
330 #ifdef CYGOPT_REDBOOT_REDUNDANT_FIS
331
332         struct fis_image_desc *img = fis_work_block;
333
334         // called from invalid state
335         if (img->u.valid_info.valid_flag[0] != CYG_REDBOOT_RFIS_IN_PROGRESS)
336                 return -1;
337
338         //if it failed, reset is0Valid to the state before startUpdateDirectory()
339         //g_data.fisTable hasn't been changed yet, so it doesn't have to be reset now
340         //then reread the contents from flash
341         //setting the valid flag of the failed table to "INVALID" might also be not too bad
342         //but IN_PROGRESS is also good enough I think
343         if (error != 0) {
344                 void *swap_fis_addr = fis_addr;
345                 fis_addr = redundant_fis_addr;
346                 redundant_fis_addr = swap_fis_addr;
347         } else {
348                 //success
349                 void *tmp_fis_addr = (void *)((CYG_ADDRESS)fis_addr +
350                                                                           CYG_REDBOOT_RFIS_VALID_MAGIC_LENGTH);
351
352                 img->u.valid_info.valid_flag[0] = CYG_REDBOOT_RFIS_VALID;
353                 img->u.valid_info.valid_flag[1] = CYG_REDBOOT_RFIS_VALID;
354
355                 flash_program(tmp_fis_addr, img->u.valid_info.valid_flag,
356                                           sizeof(img->u.valid_info.valid_flag), &err_addr);
357         }
358 #ifdef CYGHWR_IO_FLASH_BLOCK_LOCKING
359         if (do_autolock)
360                 flash_lock((void *)fis_addr, fisdir_size, &err_addr);
361 #endif
362
363 #else // CYGOPT_REDBOOT_REDUNDANT_FIS
364     int blk_size = fisdir_size;
365     int stat;
366
367     fis_endian_fixup(fis_work_block);
368 #ifdef CYGSEM_REDBOOT_FLASH_COMBINED_FIS_AND_CONFIG
369     memcpy((char *)fis_work_block+fisdir_size, config, cfg_size);
370     conf_endian_fixup((char *)fis_work_block+fisdir_size);
371     blk_size += cfg_size;
372 #endif
373 #ifdef CYGHWR_IO_FLASH_BLOCK_LOCKING
374     if (do_autolock)
375                 flash_unlock((void *)fis_addr, blk_size, &err_addr);
376 #endif
377     if ((stat = flash_erase(fis_addr, flash_block_size, &err_addr)) != 0) {
378                 diag_printf("Error erasing FIS directory at %p: %s\n", err_addr, flash_errmsg(stat));
379     } else {
380                 if ((stat = FLASH_PROGRAM(fis_addr, fis_work_block,
381                                                                   flash_block_size, &err_addr)) != 0) {
382                         diag_printf("Error writing FIS directory at %p: %s\n",
383                                                 err_addr, flash_errmsg(stat));
384                 }
385     }
386     fis_endian_fixup(fis_work_block);
387 #ifdef CYGHWR_IO_FLASH_BLOCK_LOCKING
388     if (do_autolock)
389                 flash_lock((void *)fis_addr, blk_size, &err_addr);
390 #endif
391
392 #endif // CYGOPT_REDBOOT_REDUNDANT_FIS
393
394     return 0;
395 }
396
397 #ifdef CYGOPT_REDBOOT_REDUNDANT_FIS
398
399 int
400 fis_get_valid_buf(struct fis_image_desc *img0, struct fis_image_desc *img1, int *update_was_interrupted)
401 {
402         *update_was_interrupted = 0;
403         if (strncmp(img1->u.valid_info.magic_name, CYG_REDBOOT_RFIS_VALID_MAGIC,
404                                 CYG_REDBOOT_RFIS_VALID_MAGIC_LENGTH) != 0) {
405                 //buf0 must be valid
406                 if (img0->u.valid_info.version_count > 0) {
407                         *update_was_interrupted = 1;
408                 }
409                 return 0;
410         } else if (strncmp(img0->u.valid_info.magic_name, CYG_REDBOOT_RFIS_VALID_MAGIC,
411                                            CYG_REDBOOT_RFIS_VALID_MAGIC_LENGTH) != 0) {
412                 //buf1 must be valid
413                 if (img1->u.valid_info.version_count > 0) {
414                         *update_was_interrupted = 1;
415                 }
416                 return 1;
417         }
418         //magic is ok for both, now check the valid flag
419         if ((img1->u.valid_info.valid_flag[0] != CYG_REDBOOT_RFIS_VALID) ||
420                 (img1->u.valid_info.valid_flag[1] != CYG_REDBOOT_RFIS_VALID)) {
421                 //buf0 must be valid
422                 *update_was_interrupted = 1;
423                 return 0;
424         } else if ((img0->u.valid_info.valid_flag[0] != CYG_REDBOOT_RFIS_VALID) ||
425                            (img0->u.valid_info.valid_flag[1] != CYG_REDBOOT_RFIS_VALID)) {
426                 //buf1 must be valid
427                 *update_was_interrupted = 1;
428                 return 1;
429         }
430
431         //now check the version
432         return img1->u.valid_info.version_count == (img0->u.valid_info.version_count + 1);
433 }
434
435 void
436 fis_erase_redundant_directory(void)
437 {
438     int stat;
439     void *err_addr;
440
441 #ifdef CYGSEM_REDBOOT_FLASH_LOCK_SPECIAL
442     // Ensure [quietly] that the directory is unlocked before trying
443     // to update
444     flash_unlock((void *)redundant_fis_addr, fisdir_size,
445                  &err_addr);
446 #endif
447     if ((stat = flash_erase(redundant_fis_addr, fisdir_size,
448                             &err_addr)) != 0) {
449                 diag_printf("Error erasing FIS directory at %p: %s\n",
450                                         err_addr, flash_errmsg(stat));
451     }
452 #ifdef CYGSEM_REDBOOT_FLASH_LOCK_SPECIAL
453     // Ensure [quietly] that the directory is locked after the update
454     flash_lock((void *)redundant_fis_addr, fisdir_size, &err_addr);
455 #endif
456 }
457 #endif
458
459 static void
460 fis_init(int argc, char *argv[])
461 {
462     int stat;
463     struct fis_image_desc *img;
464     void *err_addr;
465     bool full_init = false;
466     struct option_info opts[1];
467     CYG_ADDRESS redboot_flash_start;
468     unsigned long redboot_image_size;
469
470     init_opts(&opts[0], 'f', false, OPTION_ARG_TYPE_FLG,
471                           &full_init, NULL, "full initialization, erases all of flash");
472     if (!scan_opts(argc, argv, 2, opts, 1, 0, 0, "")) {
473                 return;
474     }
475
476     if (!verify_action("About to initialize [format] FLASH image system")) {
477                 diag_printf("** Aborted\n");
478                 return;
479     }
480     diag_printf("*** Initialize FLASH Image System\n");
481
482 #define MIN_REDBOOT_IMAGE_SIZE CYGBLD_REDBOOT_MIN_IMAGE_SIZE
483     redboot_image_size = flash_block_size > MIN_REDBOOT_IMAGE_SIZE ?
484                 flash_block_size : MIN_REDBOOT_IMAGE_SIZE;
485
486     img = fis_work_block;
487     memset(img, 0xFF, fisdir_size);  // Start with erased data
488
489 #ifdef CYGOPT_REDBOOT_REDUNDANT_FIS
490     //create the valid flag entry
491     memset(img, 0, sizeof(struct fis_image_desc));
492     strcpy(img->u.valid_info.magic_name, CYG_REDBOOT_RFIS_VALID_MAGIC);
493     img->u.valid_info.valid_flag[0] = CYG_REDBOOT_RFIS_VALID;
494     img->u.valid_info.valid_flag[1] = CYG_REDBOOT_RFIS_VALID;
495     img->u.valid_info.version_count = 0;
496     img++;
497 #endif
498
499     // Create a pseudo image for RedBoot
500 #ifdef CYGOPT_REDBOOT_FIS_RESERVED_BASE
501     memset(img, 0, sizeof(*img));
502     strcpy(img->u.name, "(reserved)");
503     img->flash_base = (CYG_ADDRESS)flash_start;
504     img->mem_base = (CYG_ADDRESS)flash_start;
505     img->size = CYGNUM_REDBOOT_FLASH_RESERVED_BASE;
506     img++;
507 #endif
508     redboot_flash_start = (CYG_ADDRESS)flash_start + CYGBLD_REDBOOT_FLASH_BOOT_OFFSET;
509 #ifdef CYGOPT_REDBOOT_FIS_REDBOOT
510     memset(img, 0, sizeof(*img));
511     strcpy(img->u.name, "RedBoot");
512     img->flash_base = redboot_flash_start;
513     img->mem_base = redboot_flash_start;
514     img->size = redboot_image_size;
515     img++;
516     redboot_flash_start += redboot_image_size;
517 #endif
518 #ifdef CYGOPT_REDBOOT_FIS_REDBOOT_POST
519 #ifdef CYGNUM_REDBOOT_FIS_REDBOOT_POST_OFFSET
520     // Take care to place the POST entry at the right offset:
521     redboot_flash_start = (CYG_ADDRESS)flash_start + CYGNUM_REDBOOT_FIS_REDBOOT_POST_OFFSET;
522 #endif
523     memset(img, 0, sizeof(*img));
524     strcpy(img->u.name, "RedBoot[post]");
525     img->flash_base = redboot_flash_start;
526     img->mem_base = redboot_flash_start;
527     img->size = redboot_image_size;
528     img++;
529     redboot_flash_start += redboot_image_size;
530 #endif
531 #ifdef CYGOPT_REDBOOT_FIS_REDBOOT_BACKUP
532     // And a backup image
533     memset(img, 0, sizeof(*img));
534     strcpy(img->u.name, "RedBoot[backup]");
535     img->flash_base = redboot_flash_start;
536     img->mem_base = redboot_flash_start;
537     img->size = redboot_image_size;
538     img++;
539     redboot_flash_start += redboot_image_size;
540 #endif
541 #if defined(CYGSEM_REDBOOT_FLASH_CONFIG) && defined(CYGHWR_REDBOOT_FLASH_CONFIG_MEDIA_FLASH)
542     // And a descriptor for the configuration data
543     memset(img, 0, sizeof(*img));
544     strcpy(img->u.name, "RedBoot config");
545     img->flash_base = (CYG_ADDRESS)cfg_base;
546     img->mem_base = (CYG_ADDRESS)cfg_base;
547     img->size = cfg_size;
548     img++;
549 #endif
550     // And a descriptor for the descriptor table itself
551     memset(img, 0, sizeof(*img));
552     strcpy(img->u.name, "FIS directory");
553     img->flash_base = (CYG_ADDRESS)fis_addr;
554     img->mem_base = (CYG_ADDRESS)fis_addr;
555     img->size = fisdir_size;
556     img++;
557
558     //create the entry for the redundant fis table
559 #ifdef CYGOPT_REDBOOT_REDUNDANT_FIS
560     memset(img, 0, sizeof(*img));
561     strcpy(img->u.name, "Redundant FIS");
562     img->flash_base = (CYG_ADDRESS)redundant_fis_addr;
563     img->mem_base = (CYG_ADDRESS)redundant_fis_addr;
564     img->size = fisdir_size;
565     img++;
566 #endif
567
568 #ifdef CYGOPT_REDBOOT_FIS_DIRECTORY_ARM_SIB_ID
569     // FIS gets the size of a full block - note, this should be changed
570     // if support is added for multi-block FIS structures.
571     img = (struct fis_image_desc *)((CYG_ADDRESS)fis_work_block + fisdir_size);
572     // Add a footer so the FIS will be recognized by the ARM Boot
573     // Monitor as a reserved area.
574     {
575                 tFooter *footer_p = (tFooter*)((CYG_ADDRESS)img - sizeof(tFooter));
576                 cyg_uint32 check = 0;
577                 cyg_uint32 *check_ptr = (cyg_uint32 *)footer_p;
578                 cyg_int32 count = (sizeof(tFooter) - 4) >> 2;
579
580                 // Prepare footer. Try to protect all but the reserved space
581                 // and the first RedBoot image (which is expected to be
582                 // bootable), but fall back to just protecting the FIS if it's
583                 // not at the default position in the flash.
584 #if defined(CYGOPT_REDBOOT_FIS_RESERVED_BASE) && (-1 == CYGNUM_REDBOOT_FIS_DIRECTORY_BLOCK)
585                 footer_p->blockBase = (char*)_ADDR_REDBOOT_TO_ARM(flash_start);
586                 footer_p->blockBase += CYGNUM_REDBOOT_FLASH_RESERVED_BASE + redboot_image_size;
587 #else
588                 footer_p->blockBase = (char*)_ADDR_REDBOOT_TO_ARM(fis_work_block);
589 #endif
590                 footer_p->infoBase = NULL;
591                 footer_p->signature = FLASH_FOOTER_SIGNATURE;
592                 footer_p->type = TYPE_REDHAT_REDBOOT;
593
594                 // and compute its checksum
595                 for ( ; count > 0; count--) {
596                         if (*check_ptr > ~check)
597                                 check++;
598                         check += *check_ptr++;
599                 }
600                 footer_p->checksum = ~check;
601     }
602 #endif
603
604     // Do this after creating the initialized table because that inherently
605     // calculates where the high water mark of default RedBoot images is.
606
607     if (full_init) {
608                 unsigned long erase_size;
609                 CYG_ADDRESS erase_start;
610                 // Erase everything except default RedBoot images, fis block,
611                 // and config block.
612                 // First deal with the possible first part, before RedBoot images:
613 #if (CYGBLD_REDBOOT_FLASH_BOOT_OFFSET > CYGNUM_REDBOOT_FLASH_RESERVED_BASE)
614                 erase_start = (CYG_ADDRESS)flash_start + CYGNUM_REDBOOT_FLASH_RESERVED_BASE;
615                 erase_size =  (CYG_ADDRESS)flash_start + CYGBLD_REDBOOT_FLASH_BOOT_OFFSET;
616                 if ( erase_size > erase_start ) {
617                         erase_size -= erase_start;
618                         if ((stat = flash_erase((void *)erase_start, erase_size,
619                                                                         &err_addr)) != 0) {
620                                 diag_printf("   initialization failed at %p: %s\n",
621                                                         err_addr, flash_errmsg(stat));
622                         }
623                 }
624 #endif
625                 // second deal with the larger part in the main:
626                 erase_start = redboot_flash_start; // high water of created images
627                 // Now the empty bits between the end of Redboot and the cfg and dir
628                 // blocks.
629 #if defined(CYGSEM_REDBOOT_FLASH_CONFIG) && \
630     defined(CYGHWR_REDBOOT_FLASH_CONFIG_MEDIA_FLASH) && \
631     !defined(CYGSEM_REDBOOT_FLASH_COMBINED_FIS_AND_CONFIG)
632                 if (fis_addr > cfg_base) {
633                         erase_size = (CYG_ADDRESS)cfg_base - erase_start; // the gap between HWM and config data
634                 } else {
635                         erase_size = (CYG_ADDRESS)fis_addr - erase_start; // the gap between HWM and fis data
636                 }
637                 if ((stat = flash_erase((void *)erase_start, erase_size,
638                                                                 &err_addr)) != 0) {
639                         diag_printf("     initialization failed %p: %s\n",
640                                                 err_addr, flash_errmsg(stat));
641                 }
642                 erase_start += erase_size + flash_block_size;
643                 if (fis_addr > cfg_base) {
644                         erase_size = (CYG_ADDRESS)fis_addr - erase_start; // the gap between config and fis data
645                 } else {
646                         erase_size = (CYG_ADDRESS)cfg_base - erase_start; // the gap between fis and config data
647                 }
648                 if ((stat = flash_erase((void *)erase_start, erase_size,
649                                                                 &err_addr)) != 0) {
650                         diag_printf("     initialization failed %p: %s\n",
651                                                 err_addr, flash_errmsg(stat));
652                 }
653                 erase_start += erase_size + flash_block_size;
654 #else  // !CYGSEM_REDBOOT_FLASH_CONFIG
655                 erase_size = (CYG_ADDRESS)fis_addr - erase_start; // the gap between HWM and fis data
656                 if ((stat = flash_erase((void *)erase_start, erase_size,
657                                                                 &err_addr)) != 0) {
658                         diag_printf("     initialization failed %p: %s\n",
659                                                 err_addr, flash_errmsg(stat));
660                 }
661                 erase_start += erase_size + flash_block_size;
662 #endif
663                 // Lastly, anything at the end, if there is any
664                 if ( erase_start < (((CYG_ADDRESS)flash_end)+1) ) {
665                         erase_size = ((CYG_ADDRESS)flash_end - erase_start) + 1;
666                         if ((stat = flash_erase((void *)erase_start, erase_size,
667                                                                         &err_addr)) != 0) {
668                                 diag_printf("   initialization failed at %p: %s\n",
669                                                         err_addr, flash_errmsg(stat));
670                         }
671                 }
672 #ifndef CYGDAT_REDBOOT_FIS_MAX_FREE_CHUNKS
673                 // In this case, 'fis free' works by scanning for erased blocks.  Since the
674                 // "-f" option was not supplied, there may be areas which are not used but
675                 // don't appear to be free since they are not erased - thus the warning
676     } else {
677                 diag_printf("    Warning: device contents not erased, some blocks may not be usable\n");
678 #endif
679     }
680     fis_start_update_directory(0);
681     fis_update_directory(0, 0);
682 #ifdef CYGOPT_REDBOOT_REDUNDANT_FIS
683     fis_erase_redundant_directory();
684 #endif
685 }
686
687 static void
688 fis_list(int argc, char *argv[])
689 {
690     struct fis_image_desc *img;
691     int i = 0, image_indx;
692     bool show_cksums = false;
693     bool show_datalen = false;
694     struct option_info opts[2];
695     unsigned long last_addr, lowest_addr;
696     bool image_found;
697
698 #ifdef CYGHWR_REDBOOT_ARM_FLASH_SIB
699     // FIXME: this is somewhat half-baked
700     extern void arm_fis_list(void);
701     arm_fis_list();
702     return;
703 #endif
704
705     init_opts(&opts[i++], 'd', false, OPTION_ARG_TYPE_FLG,
706                           &show_datalen, NULL, "display data length");
707 #ifdef CYGSEM_REDBOOT_FIS_CRC_CHECK
708     init_opts(&opts[i++], 'c', false, OPTION_ARG_TYPE_FLG,
709                           &show_cksums, NULL, "display checksums");
710 #endif
711     if (!scan_opts(argc, argv, 2, opts, i, 0, 0, "")) {
712                 return;
713     }
714     fis_read_directory();
715
716     // Let diag_printf do the formatting in both cases, rather than counting
717     // cols by hand....
718     diag_printf("%-16s  %-10s  %-10s  %-10s  %-s\n",
719                                 "Name","FLASH addr",
720                                 show_cksums ? "Checksum" : "Mem addr",
721                                 show_datalen ? "Datalen" : "Length",
722                                 "Entry point" );
723     last_addr = 0;
724     image_indx = 0;
725     do {
726                 image_found = false;
727                 lowest_addr = 0xFFFFFFFF;
728                 img = fis_work_block;
729                 for (i = 0;  i < fisdir_size/sizeof(*img);  i++, img++) {
730                         if (img->u.name[0] != 0xFF) {
731                                 if ((img->flash_base >= last_addr) && (img->flash_base < lowest_addr)) {
732                                         lowest_addr = img->flash_base;
733                                         image_found = true;
734                                         image_indx = i;
735                                 }
736                         }
737                 }
738                 if (image_found) {
739                         img = fis_work_block;
740                         img += image_indx;
741                         diag_printf("%-16s  0x%08lX  0x%08lX  0x%08lX  0x%08lX\n", img->u.name,
742                                                 (unsigned long)img->flash_base,
743 #ifdef CYGSEM_REDBOOT_FIS_CRC_CHECK
744                                                 show_cksums ? img->file_cksum : (unsigned long)img->mem_base,
745                                                 show_datalen ? img->data_length : img->size,
746 #else
747                                                 (unsigned long)img->mem_base,
748                                                 img->size,
749 #endif
750                                                 (unsigned long)img->entry_point);
751                 }
752                 last_addr = lowest_addr + 1;
753     } while (image_found == true);
754 }
755
756 #ifdef CYGDAT_REDBOOT_FIS_MAX_FREE_CHUNKS
757 struct free_chunk {
758     CYG_ADDRESS start, end;
759 };
760
761 static int
762 find_free(struct free_chunk *chunks)
763 {
764     CYG_ADDRESS *fis_ptr, *fis_end;
765     struct fis_image_desc *img;
766     int i, idx;
767     int num_chunks = 1;
768
769     // Do not search the area reserved for pre-RedBoot systems:
770     fis_ptr = (CYG_ADDRESS *)((CYG_ADDRESS)flash_start +
771                                                           CYGNUM_REDBOOT_FLASH_RESERVED_BASE);
772     fis_end = (CYG_ADDRESS *)flash_end;
773     chunks[num_chunks - 1].start = (CYG_ADDRESS)fis_ptr;
774     chunks[num_chunks - 1].end = (CYG_ADDRESS)fis_end;
775     fis_read_directory();
776     img = fis_work_block;
777     for (i = 0;  i < fisdir_size/sizeof(*img);  i++, img++) {
778         if (img->u.name[0] != 0xFF) {
779             // Figure out which chunk this is in and split it
780             for (idx = 0;  idx < num_chunks;  idx++) {
781                 if ((img->flash_base >= chunks[idx].start) &&
782                     (img->flash_base <= chunks[idx].end)) {
783                     if (img->flash_base == chunks[idx].start) {
784                         chunks[idx].start += img->size;
785                         if (chunks[idx].start >= chunks[idx].end) {
786                             // This free chunk has collapsed
787                             while (idx < (num_chunks-1)) {
788                                 chunks[idx] = chunks[idx+1];
789                                 idx++;
790                             }
791                             num_chunks--;
792                         }
793                     } else if ((img->flash_base+img->size) == chunks[idx].end) {
794                         chunks[idx].end = img->flash_base;
795                     } else {
796                         // Split chunk into two parts
797                         if ((img->flash_base+img->size) < (CYG_ADDRESS)fis_end) {
798                             int j;
799                             // make room for new chunk
800                             for (j = num_chunks; j > idx + 1; j--)
801                                 chunks[j] = chunks[j-1];
802                             chunks[idx+1].start = img->flash_base + img->size;
803                             chunks[idx+1].end = chunks[idx].end;
804                             if (++num_chunks == CYGDAT_REDBOOT_FIS_MAX_FREE_CHUNKS) {
805                                 diag_printf("Warning: too many free chunks\n");
806                                 return num_chunks;
807                             }
808                         }
809                         chunks[idx].end = img->flash_base;
810                     }
811                     break;
812                 }
813             }
814         }
815     }
816     return num_chunks;
817 }
818 #endif // CYGDAT_REDBOOT_FIS_MAX_FREE_CHUNKS
819
820 static void
821 fis_free(int argc, char *argv[])
822 {
823 #ifndef CYGDAT_REDBOOT_FIS_MAX_FREE_CHUNKS
824     unsigned long *fis_ptr, *fis_end, flash_data;
825     unsigned long *area_start;
826     void *err_addr;
827
828         FLASH_Enable(flash_start, flash_end);
829     // Do not search the area reserved for pre-RedBoot systems:
830     fis_ptr = (unsigned long *)((CYG_ADDRESS)flash_start +
831                                                                 CYGNUM_REDBOOT_FLASH_RESERVED_BASE);
832     fis_end = (unsigned long *)(CYG_ADDRESS)flash_end;
833     area_start = fis_ptr;
834     while (fis_ptr < fis_end) {
835                 flash_read(fis_ptr, &flash_data, sizeof(unsigned long), &err_addr);
836                 if (flash_data != 0xFFFFFFFF) {
837                         if (area_start != fis_ptr) {
838                                 // Assume that this is something
839                                 diag_printf("  0x%08x .. 0x%08x\n",
840                                                         (CYG_ADDRESS)area_start, (CYG_ADDRESS)fis_ptr);
841                         }
842                         // Find next blank block
843                         area_start = fis_ptr;
844                         while (area_start < fis_end) {
845                                 flash_read(area_start, &flash_data, sizeof(unsigned long), &err_addr);
846                                 if (flash_data == 0xFFFFFFFF) {
847                                         break;
848                                 }
849                                 area_start += flash_block_size / sizeof(CYG_ADDRESS);
850                         }
851                         fis_ptr = area_start;
852                 } else {
853                         fis_ptr += flash_block_size / sizeof(CYG_ADDRESS);
854                 }
855     }
856     if (area_start != fis_ptr) {
857                 diag_printf("  0x%08x .. 0x%08x\n",
858                                         (CYG_ADDRESS)area_start, (CYG_ADDRESS)fis_ptr);
859     }
860         FLASH_Disable(flash_start, flash_end);
861 #else
862     struct free_chunk chunks[CYGDAT_REDBOOT_FIS_MAX_FREE_CHUNKS];
863     int idx, num_chunks;
864
865     num_chunks = find_free(chunks);
866     for (idx = 0; idx < num_chunks; idx++) {
867                 diag_printf("  0x%08x .. 0x%08x\n",
868                                         chunks[idx].start,
869                                         chunks[idx].end);
870     }
871 #endif
872 }
873
874 // Find the first unused area of flash which is long enough
875 static bool
876 fis_find_free(CYG_ADDRESS *addr, unsigned long length)
877 {
878 #ifndef CYGDAT_REDBOOT_FIS_MAX_FREE_CHUNKS
879     unsigned long *fis_ptr, *fis_end, flash_data;
880     unsigned long *area_start;
881     void *err_addr;
882
883     // Do not search the area reserved for pre-RedBoot systems:
884     fis_ptr = (unsigned long *)((CYG_ADDRESS)flash_start +
885                                                                 CYGNUM_REDBOOT_FLASH_RESERVED_BASE);
886     fis_end = (unsigned long *)(CYG_ADDRESS)flash_end;
887         FLASH_Enable(fis_ptr, fis_end);
888     area_start = fis_ptr;
889     while (fis_ptr < fis_end) {
890                 flash_read(fis_ptr, &flash_data, sizeof(unsigned long), &err_addr);
891                 if (flash_data != 0xFFFFFFFF) {
892                         if (area_start != fis_ptr) {
893                                 // Assume that this is something
894                                 if ((fis_ptr - area_start) >= (length / sizeof(unsigned))) {
895                                         *addr = (CYG_ADDRESS)area_start;
896                                         return true;
897                                 }
898                         }
899                         // Find next blank block
900                         area_start = fis_ptr;
901                         while (area_start < fis_end) {
902                                 flash_read(area_start, &flash_data, sizeof(unsigned long), &err_addr);
903                                 if (flash_data == 0xFFFFFFFF) {
904                                         break;
905                                 }
906                                 area_start += flash_block_size / sizeof(CYG_ADDRESS);
907                         }
908                         fis_ptr = area_start;
909                 } else {
910                         fis_ptr += flash_block_size / sizeof(CYG_ADDRESS);
911                 }
912     }
913         FLASH_Disable((void *)((CYG_ADDRESS)flash_start +
914                                                    CYGNUM_REDBOOT_FLASH_RESERVED_BASE), fis_end);
915     if (area_start != fis_ptr) {
916                 if (fis_ptr - area_start >= length / sizeof(unsigned)) {
917                         *addr = (CYG_ADDRESS)area_start;
918                         return true;
919                 }
920     }
921     return false;
922 #else
923     struct free_chunk chunks[CYGDAT_REDBOOT_FIS_MAX_FREE_CHUNKS];
924     int idx, num_chunks;
925
926     num_chunks = find_free(chunks);
927     for (idx = 0; idx < num_chunks; idx++) {
928                 if (chunks[idx].end + 1 - chunks[idx].start >= length) {
929                         *addr = (CYG_ADDRESS)chunks[idx].start;
930                         return true;
931                 }
932     }
933     return false;
934 #endif
935 }
936
937 static void
938 fis_create(int argc, char *argv[])
939 {
940     int i, stat;
941     unsigned long length, img_size;
942     CYG_ADDRESS mem_addr, exec_addr, flash_addr, entry_addr;
943     char *name;
944     bool mem_addr_set = false;
945     bool exec_addr_set = false;
946     bool entry_addr_set = false;
947     bool flash_addr_set = false;
948     bool length_set = false;
949     bool img_size_set = false;
950     bool no_copy = false;
951     void *err_addr;
952     struct fis_image_desc *img = NULL;
953     bool defaults_assumed;
954     struct option_info opts[7];
955     bool prog_ok = true;
956
957     init_opts(&opts[0], 'b', true, OPTION_ARG_TYPE_NUM,
958                           &mem_addr, &mem_addr_set, "memory base address");
959     init_opts(&opts[1], 'r', true, OPTION_ARG_TYPE_NUM,
960                           &exec_addr, &exec_addr_set, "ram base address");
961     init_opts(&opts[2], 'e', true, OPTION_ARG_TYPE_NUM,
962                           &entry_addr, &entry_addr_set, "entry point address");
963     init_opts(&opts[3], 'f', true, OPTION_ARG_TYPE_NUM,
964                           &flash_addr, &flash_addr_set, "FLASH memory base address");
965     init_opts(&opts[4], 'l', true, OPTION_ARG_TYPE_NUM,
966                           &length, &length_set, "image length [in FLASH]");
967     init_opts(&opts[5], 's', true, OPTION_ARG_TYPE_NUM,
968                           &img_size, &img_size_set, "image size [actual data]");
969     init_opts(&opts[6], 'n', false, OPTION_ARG_TYPE_FLG,
970                           &no_copy, NULL, "don't copy from RAM to FLASH, just update directory");
971     if (!scan_opts(argc, argv, 2, opts, 7, &name, OPTION_ARG_TYPE_STR, "file name")) {
972                 fis_usage("invalid arguments");
973                 return;
974         }
975
976     fis_read_directory();
977     defaults_assumed = false;
978     if (name) {
979                 // Search existing files to acquire defaults for params not specified:
980                 img = fis_lookup(name, NULL);
981                 if (img) {
982                         // Found it, so get image size from there
983                         if (!length_set) {
984                                 length_set = true;
985                                 length = img->size;
986                                 defaults_assumed = true;
987                         }
988                 }
989     }
990     if (!mem_addr_set && (load_address >= (CYG_ADDRESS)ram_start) &&
991                 (load_address_end) < (CYG_ADDRESS)ram_end) {
992                 mem_addr = load_address;
993                 mem_addr_set = true;
994                 defaults_assumed = true;
995                 // Get entry address from loader, unless overridden
996                 if (!entry_addr_set)
997                         entry_addr = entry_address;
998                 if (!length_set) {
999                         length = load_address_end - load_address;
1000                         length_set = true;
1001                 } else if (defaults_assumed && !img_size_set) {
1002                         /* We got length from the FIS table, so the size of the
1003                            actual loaded image becomes img_size */
1004                         img_size = load_address_end - load_address;
1005                         img_size_set = true;
1006                 }
1007     }
1008     // Get the remaining fall-back values from the fis
1009     if (img) {
1010                 if (!exec_addr_set) {
1011                         // Preserve "normal" behaviour
1012                         exec_addr_set = true;
1013                         exec_addr = flash_addr_set ? flash_addr : mem_addr;
1014                 }
1015                 if (!flash_addr_set) {
1016                         flash_addr_set = true;
1017                         flash_addr = img->flash_base;
1018                         defaults_assumed = true;
1019                 }
1020     }
1021
1022     if ((!no_copy && !mem_addr_set) || (no_copy && !flash_addr_set) ||
1023                 !length_set || !name) {
1024                 fis_usage("required parameter missing");
1025                 return;
1026     }
1027     if (!img_size_set) {
1028                 img_size = length;
1029     }
1030     // 'length' is size of FLASH image, 'img_size' is actual data size
1031     // Round up length to FLASH block size
1032 #ifndef CYGPKG_HAL_MIPS // FIXME: compiler is b0rken
1033     length = ((length + flash_block_size - 1) / flash_block_size) * flash_block_size;
1034     if (length < img_size) {
1035                 diag_printf("Invalid FLASH image size/length combination\n");
1036                 return;
1037     }
1038 #endif
1039     if (flash_addr_set &&
1040                 ((stat = flash_verify_addr((void *)flash_addr)) ||
1041                  (stat = flash_verify_addr((void *)(flash_addr + length - 1))))) {
1042                 _show_invalid_flash_address(flash_addr, stat);
1043                 return;
1044     }
1045     if (flash_addr_set && ((flash_addr & (flash_block_size - 1)) != 0)) {
1046                 diag_printf("Invalid FLASH address: %p\n", (void *)flash_addr);
1047                 diag_printf("   must be 0x%x aligned\n", flash_block_size);
1048                 return;
1049     }
1050     if (strlen(name) >= sizeof(img->u.name)) {
1051                 diag_printf("Name is too long, must be less than %d chars\n",
1052                                         sizeof(img->u.name));
1053                 return;
1054     }
1055     if (!no_copy) {
1056                 if ((mem_addr < (CYG_ADDRESS)ram_start) ||
1057                         ((mem_addr+img_size) >= (CYG_ADDRESS)ram_end)) {
1058                         diag_printf("** WARNING: RAM address: %p may be invalid\n", (void *)mem_addr);
1059                         diag_printf("   valid range is %p-%p\n", (void *)ram_start, (void *)ram_end);
1060                 }
1061                 if (!flash_addr_set && !fis_find_free(&flash_addr, length)) {
1062                         diag_printf("Can't locate %lx(%ld) bytes free in FLASH\n", length, length);
1063                         return;
1064                 }
1065     }
1066     // First, see if the image by this name has agreable properties
1067     if (img) {
1068                 if (flash_addr_set && (img->flash_base != flash_addr)) {
1069                         diag_printf("Image found, but flash address (%p)\n"
1070                                                 "             is incorrect (present image location %p)\n",
1071                                                 (void *)flash_addr, (void *)img->flash_base);
1072
1073                         return;
1074                 }
1075                 if (img->size != length) {
1076                         diag_printf("Image found, but length (0x%lx, necessitating image size 0x%lx)\n"
1077                                                 "             is incorrect (present image size 0x%lx)\n",
1078                                                 img_size, length, img->size);
1079                         return;
1080                 }
1081                 if (!verify_action("An image named '%s' exists", name)) {
1082                         return;
1083                 } else {
1084                         if (defaults_assumed) {
1085                                 if (no_copy &&
1086                                         !verify_action("* CAUTION * about to program '%s'\n                at %p..%p from %p",
1087                                                                    name, (void *)flash_addr,
1088                                                                    (void *)(flash_addr + img_size - 1),
1089                                                                    (void *)mem_addr)) {
1090                                         return;  // The guy gave up
1091                                 }
1092                         }
1093                 }
1094     } else {
1095 #ifdef CYGDAT_REDBOOT_FIS_MAX_FREE_CHUNKS
1096                 // Make sure that any FLASH address specified directly is truly free
1097                 if (flash_addr_set && !no_copy) {
1098                         struct free_chunk chunks[CYGDAT_REDBOOT_FIS_MAX_FREE_CHUNKS];
1099                         int idx, num_chunks;
1100                         bool is_free = false;
1101
1102                         num_chunks = find_free(chunks);
1103                         for (idx = 0;  idx < num_chunks;  idx++) {
1104                                 if ((flash_addr >= chunks[idx].start) &&
1105                                         ((flash_addr + length - 1) <= chunks[idx].end)) {
1106                                         is_free = true;
1107                                 }
1108                         }
1109                         if (!is_free) {
1110                                 diag_printf("Invalid FLASH address - not free!\n");
1111                                 return;
1112                         }
1113                 }
1114 #endif
1115                 // If not image by that name, try and find an empty slot
1116                 img = fis_work_block;
1117                 for (i = 0;  i < fisdir_size / sizeof(*img);  i++, img++) {
1118                         if (img->u.name[0] == 0xFF) {
1119                                 break;
1120                         }
1121                 }
1122                 if (i >= fisdir_size / sizeof(*img)) {
1123                         diag_printf("Can't find an empty slot in FIS directory!\n");
1124                         return;
1125                 }
1126     }
1127     if (!no_copy) {
1128                 // Safety check - make sure the address range is not within the code we're running
1129                 if (flash_code_overlaps((void *)flash_addr,
1130                                                                 (void *)(flash_addr + img_size - 1))) {
1131                         diag_printf("Can't program this region - contains code in use!\n");
1132                         return;
1133                 }
1134                 if (prog_ok) {
1135                         // Erase area to be programmed
1136                         if ((stat = flash_erase((void *)flash_addr, length, &err_addr)) != 0) {
1137                                 diag_printf("Can't erase region at %p: %s\n", err_addr, flash_errmsg(stat));
1138                                 prog_ok = false;
1139                         }
1140                 }
1141                 if (prog_ok) {
1142                         // Now program it
1143                         FLASH_Enable((void *)flash_addr, (void *)(flash_addr + length));
1144                         stat = FLASH_PROGRAM((void *)flash_addr, (void *)mem_addr,
1145                                                                  img_size, &err_addr);
1146                         FLASH_Disable((void *)flash_addr, (void *)(flash_addr + length));
1147                         if (stat != 0) {
1148                                 diag_printf("Can't program region at %p: %s\n", err_addr, flash_errmsg(stat));
1149                                 prog_ok = false;
1150                         }
1151                 }
1152     }
1153     if (prog_ok) {
1154                 // Update directory
1155                 memset(img, 0, sizeof(*img));
1156                 strcpy(img->u.name, name);
1157                 img->flash_base = flash_addr;
1158                 img->mem_base = exec_addr_set ? exec_addr : (mem_addr_set ? mem_addr : flash_addr);
1159                 img->entry_point = entry_addr_set ? entry_addr : (CYG_ADDRESS)entry_address;  // Hope it's been set
1160                 img->size = length;
1161                 img->data_length = img_size;
1162 #ifdef CYGSEM_REDBOOT_FIS_CRC_CHECK
1163                 if (!no_copy) {
1164                         img->file_cksum = cyg_crc32((unsigned char *)mem_addr, img_size);
1165                 } else {
1166                         // No way to compute this, sorry
1167                         img->file_cksum = 0;
1168                 }
1169 #endif
1170                 fis_start_update_directory(0);
1171                 fis_update_directory(0, 0);
1172     }
1173 }
1174
1175 extern void arm_fis_delete(char *);
1176 static void
1177 fis_delete(int argc, char *argv[])
1178 {
1179     char *name;
1180     int num_reserved, i, stat;
1181     void *err_addr;
1182     struct fis_image_desc *img;
1183
1184     if (!scan_opts(argc, argv, 2, 0, 0, &name, OPTION_ARG_TYPE_STR, "image name")) {
1185                 fis_usage("invalid arguments");
1186                 return;
1187         }
1188 #ifdef CYGHWR_REDBOOT_ARM_FLASH_SIB
1189     // FIXME: this is somewhat half-baked
1190     arm_fis_delete(name);
1191     return;
1192 #endif
1193     img = (struct fis_image_desc *)fis_work_block;
1194     num_reserved = 0;
1195 #ifdef CYGOPT_REDBOOT_FIS_RESERVED_BASE
1196     num_reserved++;
1197 #endif
1198 #ifdef CYGOPT_REDBOOT_FIS_REDBOOT
1199     num_reserved++;
1200 #endif
1201 #ifdef CYGOPT_REDBOOT_FIS_REDBOOT_BACKUP
1202     num_reserved++;
1203 #endif
1204 #ifdef CYGOPT_REDBOOT_FIS_REDBOOT_POST
1205     num_reserved++;
1206 #endif
1207 #if defined(CYGSEM_REDBOOT_FLASH_CONFIG) && defined(CYGHWR_REDBOOT_FLASH_CONFIG_MEDIA_FLASH)
1208     num_reserved++;
1209 #endif
1210 #if 1 // And the descriptor for the descriptor table itself
1211     num_reserved++;
1212 #endif
1213
1214     img = fis_lookup(name, &i);
1215     if (img) {
1216         if (i < num_reserved) {
1217             diag_printf("Sorry, '%s' is a reserved image and cannot be deleted\n", img->u.name);
1218             return;
1219         }
1220         if (!verify_action("Delete image '%s'", name)) {
1221             return;
1222         }
1223     } else {
1224                 diag_printf("No image '%s' found\n", name);
1225         return;
1226     }
1227     // Erase Data blocks (free space)
1228     if ((stat = flash_erase((void *)img->flash_base, img->size, &err_addr)) != 0) {
1229                 diag_printf("Error erasing at %p: %s\n", err_addr, flash_errmsg(stat));
1230     } else {
1231                 img->u.name[0] = 0xFF;
1232                 fis_start_update_directory(0);
1233                 fis_update_directory(0, 0);
1234     }
1235 }
1236
1237 static void
1238 fis_load(int argc, char *argv[])
1239 {
1240     char *name;
1241     struct fis_image_desc *img;
1242     CYG_ADDRESS mem_addr;
1243     bool mem_addr_set = false;
1244     bool show_cksum = false;
1245     bool load_ce = false;
1246     struct option_info opts[4];
1247 #if defined(CYGSEM_REDBOOT_FIS_CRC_CHECK)
1248     unsigned long cksum;
1249 #endif
1250     int num_options = 0;
1251 #if defined(CYGPRI_REDBOOT_ZLIB_FLASH) ||  defined(CYGSEM_REDBOOT_FIS_CRC_CHECK)
1252     bool decompress = false;
1253 #endif
1254     void *err_addr;
1255
1256     init_opts(&opts[num_options++], 'b', true, OPTION_ARG_TYPE_NUM,
1257                           &mem_addr, &mem_addr_set, "memory [load] base address");
1258     init_opts(&opts[num_options++], 'c', false, OPTION_ARG_TYPE_FLG,
1259                           &show_cksum, NULL, "display checksum");
1260 #ifdef CYGBLD_BUILD_REDBOOT_WITH_WINCE_SUPPORT
1261     init_opts(&opts[num_options++], 'w', false, OPTION_ARG_TYPE_FLG,
1262                           &load_ce, NULL, "parse as Windows CE image");
1263 #endif
1264 #ifdef CYGPRI_REDBOOT_ZLIB_FLASH
1265     init_opts(&opts[num_options++], 'd', false, OPTION_ARG_TYPE_FLG,
1266                           &decompress, 0, "decompress");
1267 #endif
1268
1269     CYG_ASSERT(num_options <= num_options, "Too many options");
1270
1271     if (!scan_opts(argc, argv, 2, opts, num_options, &name,
1272                                    OPTION_ARG_TYPE_STR, "image name")) {
1273                 fis_usage("invalid arguments");
1274                 return;
1275     }
1276     if ((img = fis_lookup(name, NULL)) == NULL) {
1277                 diag_printf("No image '%s' found\n", name);
1278                 return;
1279     }
1280     if (!mem_addr_set || load_ce) {
1281                 mem_addr = img->mem_base;
1282     }
1283     // Load image from FLASH into RAM
1284 #ifdef CYGSEM_REDBOOT_VALIDATE_USER_RAM_LOADS
1285     if (!valid_address((void *)mem_addr)) {
1286                 if (!load_ce) {
1287                         diag_printf("Not a loadable image - try using -b ADDRESS option\n");
1288                 } else {
1289                         diag_printf("Not a loadable image\n");
1290                 }
1291                 return;
1292     }
1293 #endif
1294 #ifdef CYGBLD_BUILD_REDBOOT_WITH_WINCE_SUPPORT
1295     if (load_ce) {
1296                 if (mem_addr_set) {
1297                         diag_printf("Warning: -b argument ignored for Windows CE image\n");
1298                 }
1299                 FLASH_Enable((void *)img->flash_base, (void *)(img->flash_base + img->size));
1300                 if (!ce_is_bin_image((void *)img->flash_base, img->size)) {
1301                         diag_printf("** Error: This does not seem to be a valid Windows CE image\n");
1302                         return;
1303                 }
1304                 if (!ce_bin_load((void *)img->flash_base, img->size)) {
1305                         diag_printf("** Error: Failed to load Windows CE image\n");
1306                 }
1307                 FLASH_Disable((void *)img->flash_base, (void *)(img->flash_base + img->size));
1308                 // Set load address/top
1309                 load_address = mem_addr;
1310                 load_address_end = mem_addr + img->data_length;
1311                 return;
1312     }
1313 #endif
1314 #ifdef CYGPRI_REDBOOT_ZLIB_FLASH
1315     if (decompress) {
1316                 int err;
1317                 _pipe_t fis_load_pipe;
1318                 _pipe_t *p = &fis_load_pipe;
1319                 p->out_buf = (unsigned char*) mem_addr;
1320                 p->out_max = p->out_size = -1;
1321                 p->in_buf = (unsigned char*) img->flash_base;
1322                 p->in_avail = img->data_length;
1323
1324                 err = (*_dc_init)(p);
1325
1326                 if (0 == err)
1327                         err = (*_dc_inflate)(p);
1328
1329                 // Free used resources, do final translation of
1330                 // error value.
1331                 err = (*_dc_close)(p, err);
1332
1333                 if (0 != err && p->msg) {
1334                         diag_printf("decompression error: %s\n", p->msg);
1335                 } else {
1336                         diag_printf("Image loaded from %p-%p\n", (unsigned char *)mem_addr, p->out_buf);
1337                 }
1338
1339                 // Set load address/top
1340                 load_address = mem_addr;
1341                 load_address_end = (unsigned long)p->out_buf;
1342
1343                 // Reload fis directory
1344                 fis_read_directory();
1345     } else // dangling block
1346 #endif
1347                 {
1348                         int err;
1349
1350                         FLASH_Enable((void *)img->flash_base, (void *)(img->flash_base + img->size));
1351                         err = flash_read((void *)img->flash_base, (void *)mem_addr,
1352                                                          img->data_length, &err_addr);
1353                         FLASH_Disable((void *)img->flash_base, (void *)(img->flash_base + img->size));
1354                         if (err != FLASH_ERR_OK) {
1355                                 diag_printf("** Error: Failed to load image from flash\n");
1356                                 return;
1357                         }
1358
1359                         // Set load address/top
1360                         load_address = mem_addr;
1361                         load_address_end = mem_addr + img->data_length;
1362                 }
1363     entry_address = (unsigned long)img->entry_point;
1364
1365 #ifdef CYGSEM_REDBOOT_FIS_CRC_CHECK
1366     cksum = cyg_crc32((unsigned char *)mem_addr, img->data_length);
1367     if (show_cksum) {
1368                 diag_printf("Checksum: 0x%08lx\n", cksum);
1369     }
1370     // When decompressing, leave CRC checking to decompressor
1371     if (!decompress && img->file_cksum) {
1372                 if (cksum != img->file_cksum) {
1373                         diag_printf("** Warning - checksum failure.      stored: 0x%08lx, computed: 0x%08lx\n",
1374                                                 img->file_cksum, cksum);
1375                         entry_address = (unsigned long)NO_MEMORY;
1376                 }
1377     }
1378 #endif
1379     diag_printf("image loaded 0x%08lx-0x%08lx, assumed entry at 0x%08lx\n",
1380                                 load_address, load_address_end - 1, entry_address);
1381 }
1382 #endif // CYGOPT_REDBOOT_FIS
1383
1384 static void
1385 fis_write(int argc, char *argv[])
1386 {
1387     int stat;
1388     unsigned long length;
1389     CYG_ADDRESS mem_addr, flash_addr;
1390     bool mem_addr_set = false;
1391     bool flash_addr_set = false;
1392     bool length_set = false;
1393     void *err_addr;
1394     struct option_info opts[3];
1395     bool prog_ok;
1396
1397     init_opts(&opts[0], 'b', true, OPTION_ARG_TYPE_NUM,
1398                           &mem_addr, &mem_addr_set, "memory base address");
1399     init_opts(&opts[1], 'f', true, OPTION_ARG_TYPE_NUM,
1400                           &flash_addr, &flash_addr_set, "FLASH memory base address");
1401     init_opts(&opts[2], 'l', true, OPTION_ARG_TYPE_NUM,
1402                           &length, &length_set, "image length [in FLASH]");
1403     if (!scan_opts(argc, argv, 2, opts, 3, 0, 0, 0))
1404                 {
1405                         fis_usage("invalid arguments");
1406                         return;
1407                 }
1408
1409     if (!mem_addr_set || !flash_addr_set || !length_set) {
1410                 fis_usage("required parameter missing");
1411                 return;
1412     }
1413
1414     // Round up length to FLASH block size
1415 #ifndef CYGPKG_HAL_MIPS // FIXME: compiler is b0rken
1416     length = ((length + flash_block_size - 1) / flash_block_size) * flash_block_size;
1417 #endif
1418     if (flash_addr_set &&
1419                 ((stat = flash_verify_addr((void *)flash_addr)) ||
1420                  (stat = flash_verify_addr((void *)(flash_addr + length - 1))))) {
1421                 _show_invalid_flash_address(flash_addr, stat);
1422                 return;
1423     }
1424     if (flash_addr_set && flash_addr & (flash_block_size-1)) {
1425                 diag_printf("Invalid FLASH address: %p\n", (void *)flash_addr);
1426                 diag_printf("   must be 0x%x aligned\n", flash_block_size);
1427                 return;
1428     }
1429     if ((mem_addr < (CYG_ADDRESS)ram_start) ||
1430                 ((mem_addr + length) >= (CYG_ADDRESS)ram_end)) {
1431                 diag_printf("** WARNING: RAM address: %p may be invalid\n", (void *)mem_addr);
1432                 diag_printf("   valid range is %p-%p\n", (void *)ram_start, (void *)ram_end);
1433     }
1434     // Safety check - make sure the address range is not within the code we're running
1435     if (flash_code_overlaps((void *)flash_addr, (void *)(flash_addr + length - 1))) {
1436                 diag_printf("Can't program this region - contains code in use!\n");
1437                 return;
1438     }
1439     if (!verify_action("* CAUTION * about to program FLASH\n            at %p..%p from %p",
1440                                            (void *)flash_addr, (void *)(flash_addr + length - 1),
1441                                            (void *)mem_addr)) {
1442                 return;  // The guy gave up
1443     }
1444     prog_ok = true;
1445     if (prog_ok) {
1446                 // Erase area to be programmed
1447                 if ((stat = flash_erase((void *)flash_addr, length, &err_addr)) != 0) {
1448                         diag_printf("Can't erase region at %p: %s\n", err_addr, flash_errmsg(stat));
1449                         prog_ok = false;
1450                 }
1451     }
1452     if (prog_ok) {
1453                 // Now program it
1454                 stat = FLASH_PROGRAM((void *)flash_addr, (void *)mem_addr, length, &err_addr);
1455                 if (stat != 0) {
1456                         diag_printf("Can't program region at %p: %s\n", err_addr, flash_errmsg(stat));
1457                         prog_ok = false;
1458                 }
1459     }
1460 }
1461
1462 static void
1463 fis_erase(int argc, char *argv[])
1464 {
1465     int stat;
1466     unsigned long length;
1467     CYG_ADDRESS flash_addr;
1468     bool flash_addr_set = false;
1469     bool length_set = false;
1470     void *err_addr;
1471     struct option_info opts[2];
1472
1473     init_opts(&opts[0], 'f', true, OPTION_ARG_TYPE_NUM,
1474                           &flash_addr, &flash_addr_set, "FLASH memory base address");
1475     init_opts(&opts[1], 'l', true, OPTION_ARG_TYPE_NUM,
1476                           &length, &length_set, "length");
1477     if (!scan_opts(argc, argv, 2, opts, 2, NULL, 0, NULL))
1478                 {
1479                         fis_usage("invalid arguments");
1480                         return;
1481                 }
1482
1483     if (!flash_addr_set || !length_set) {
1484                 fis_usage("missing argument");
1485                 return;
1486     }
1487     if (flash_addr_set &&
1488                 ((stat = flash_verify_addr((void *)flash_addr)) ||
1489                  (stat = flash_verify_addr((void *)(flash_addr + length - 1))))) {
1490                 _show_invalid_flash_address(flash_addr, stat);
1491                 return;
1492     }
1493     if (flash_addr_set && flash_addr & (flash_block_size-1)) {
1494                 diag_printf("Invalid FLASH address: %p\n", (void *)flash_addr);
1495                 diag_printf("   must be 0x%x aligned\n", flash_block_size);
1496                 return;
1497     }
1498     // Safety check - make sure the address range is not within the code we're running
1499     if (flash_code_overlaps((void *)flash_addr, (void *)(flash_addr + length - 1))) {
1500                 diag_printf("Can't erase this region - contains code in use!\n");
1501                 return;
1502     }
1503     if ((stat = flash_erase((void *)flash_addr, length, &err_addr)) != 0) {
1504                 diag_printf("Error erasing at %p: %s\n", err_addr, flash_errmsg(stat));
1505     }
1506 }
1507
1508 #ifdef CYGHWR_IO_FLASH_BLOCK_LOCKING
1509
1510 static void
1511 fis_lock(int argc, char *argv[])
1512 {
1513     char *name;
1514     int stat;
1515     unsigned long length;
1516     CYG_ADDRESS flash_addr;
1517     bool flash_addr_set = false;
1518     bool length_set = false;
1519     void *err_addr;
1520     struct option_info opts[2];
1521
1522     init_opts(&opts[0], 'f', true, OPTION_ARG_TYPE_NUM,
1523                           &flash_addr, &flash_addr_set, "FLASH memory base address");
1524     init_opts(&opts[1], 'l', true, OPTION_ARG_TYPE_NUM,
1525                           &length, &length_set, "length");
1526     if (!scan_opts(argc, argv, 2, opts, 2, &name, OPTION_ARG_TYPE_STR, "image name")) {
1527                 fis_usage("invalid arguments");
1528                 return;
1529         }
1530 #ifdef CYGOPT_REDBOOT_FIS
1531     /* Get parameters from image if specified */
1532     if (name) {
1533                 struct fis_image_desc *img;
1534                 if ((img = fis_lookup(name, NULL)) == NULL) {
1535                         diag_printf("No image '%s' found\n", name);
1536                         return;
1537                 }
1538
1539                 flash_addr = img->flash_base;
1540                 length = img->size;
1541     } else
1542 #endif
1543                 if (!flash_addr_set || !length_set) {
1544                         fis_usage("missing argument");
1545                         return;
1546                 }
1547     if (flash_addr_set &&
1548                 ((stat = flash_verify_addr((void *)flash_addr)) ||
1549                  (stat = flash_verify_addr((void *)(flash_addr + length - 1))))) {
1550                 _show_invalid_flash_address(flash_addr, stat);
1551                 return;
1552     }
1553     if ((stat = flash_lock((void *)flash_addr, length, &err_addr)) != 0) {
1554                 diag_printf("Error locking at %p: %s\n", err_addr, flash_errmsg(stat));
1555     }
1556 }
1557
1558 static void
1559 fis_unlock(int argc, char *argv[])
1560 {
1561     char *name;
1562     int stat;
1563     unsigned long length;
1564     CYG_ADDRESS flash_addr;
1565     bool flash_addr_set = false;
1566     bool length_set = false;
1567     void *err_addr;
1568     struct option_info opts[2];
1569
1570     init_opts(&opts[0], 'f', true, OPTION_ARG_TYPE_NUM,
1571                           &flash_addr, &flash_addr_set, "FLASH memory base address");
1572     init_opts(&opts[1], 'l', true, OPTION_ARG_TYPE_NUM,
1573                           &length, &length_set, "length");
1574     if (!scan_opts(argc, argv, 2, opts, 2, &name, OPTION_ARG_TYPE_STR, "image name")) {
1575                 fis_usage("invalid arguments");
1576                 return;
1577         }
1578 #ifdef CYGOPT_REDBOOT_FIS
1579     if (name) {
1580                 struct fis_image_desc *img;
1581                 if ((img = fis_lookup(name, NULL)) == NULL) {
1582                         diag_printf("No image '%s' found\n", name);
1583                         return;
1584                 }
1585
1586                 flash_addr = img->flash_base;
1587                 length = img->size;
1588     } else
1589 #endif
1590                 if (!flash_addr_set || !length_set) {
1591                         fis_usage("missing argument");
1592                         return;
1593                 }
1594     if (flash_addr_set &&
1595                 ((stat = flash_verify_addr((void *)flash_addr)) ||
1596                  (stat = flash_verify_addr((void *)(flash_addr + length - 1))))) {
1597                 _show_invalid_flash_address(flash_addr, stat);
1598                 return;
1599     }
1600
1601     if ((stat = flash_unlock((void *)flash_addr, length, &err_addr)) != 0) {
1602                 diag_printf("Error unlocking at %p: %s\n", err_addr, flash_errmsg(stat));
1603     }
1604 }
1605 #endif
1606
1607 // This is set non-zero if the FLASH subsystem has successfully been initialized
1608 int __flash_init = 0;
1609
1610 void
1611 _flash_info(void)
1612 {
1613     if (!__flash_init) return;
1614     diag_printf("FLASH: %p - 0x%x, %d blocks of 0x%08x bytes each.\n",
1615                                 flash_start, (CYG_ADDRWORD)flash_end + 1, flash_num_blocks, flash_block_size);
1616 }
1617
1618 /* Returns -1 on failure, 0 on success, 1 if it was successfull
1619  but a failed fis update was detected  */
1620 int
1621 do_flash_init(void)
1622 {
1623         int stat;
1624
1625 #ifdef CYGOPT_REDBOOT_REDUNDANT_FIS
1626         struct fis_image_desc img0;
1627         struct fis_image_desc img1;
1628         int fis_update_was_interrupted = 0;
1629         void *err_addr;
1630
1631         //check the size of fis_valid_info
1632         CYG_ASSERT((sizeof(struct fis_valid_info) <= sizeof(img0.u.name)),
1633                            "fis_valid_info size mismatch");
1634         //try to check the alignment of version_count
1635         CYG_ASSERT(((&img0.u.valid_info.version_count - &img0) % sizeof(unsigned long) == 0),
1636                            "alignment problem");
1637 #endif
1638         if (!__flash_init) {
1639                 __flash_init = 1;
1640                 if ((stat = flash_init(diag_printf)) != 0) {
1641                         diag_printf("FLASH: driver init failed: %s\n", flash_errmsg(stat));
1642                         return -1;
1643                 }
1644                 flash_get_limits(NULL, &flash_start, &flash_end);
1645                 // Keep 'end' address as last valid location, to avoid wrap around problems
1646                 flash_end = (void *)((CYG_ADDRESS)flash_end - 1);
1647                 flash_get_block_info(&flash_block_size, &flash_num_blocks);
1648 #ifdef CYGOPT_REDBOOT_FIS
1649                 fisdir_size = CYGNUM_REDBOOT_FIS_DIRECTORY_ENTRY_COUNT * CYGNUM_REDBOOT_FIS_DIRECTORY_ENTRY_SIZE;
1650                 fisdir_size = ((fisdir_size + flash_block_size - 1) / flash_block_size) * flash_block_size;
1651 # if defined(CYGPRI_REDBOOT_ZLIB_FLASH) && defined(CYGOPT_REDBOOT_FIS_ZLIB_COMMON_BUFFER)
1652                 fis_work_block = fis_zlib_common_buffer;
1653                 if (CYGNUM_REDBOOT_FIS_ZLIB_COMMON_BUFFER_SIZE < fisdir_size) {
1654                         diag_printf("FLASH: common buffer too small\n");
1655                         return -1;
1656                 }
1657 # else
1658                 workspace_end = (unsigned char *)(workspace_end - fisdir_size);
1659                 fis_work_block = workspace_end;
1660 # endif
1661                 if (CYGNUM_REDBOOT_FIS_DIRECTORY_BLOCK < 0) {
1662                         fis_addr = (void *)((CYG_ADDRESS)flash_end + 1 +
1663                                                                 (CYGNUM_REDBOOT_FIS_DIRECTORY_BLOCK * flash_block_size));
1664                 } else {
1665                         fis_addr = (void *)((CYG_ADDRESS)flash_start +
1666                                                                 (CYGNUM_REDBOOT_FIS_DIRECTORY_BLOCK * flash_block_size));
1667                 }
1668 #if defined(CYGHWR_DEVS_FLASH_MXC_MULTI) && defined(MXCFLASH_SELECT_NAND)
1669                 extern int mxc_nand_fis_start(void);
1670                 if (IS_FIS_FROM_NAND()) {
1671                         fis_addr = (void *)((CYG_ADDRESS)flash_start + mxc_nand_fis_start());
1672                 }
1673 #endif
1674
1675 #if defined(IMXFLASH_SELECT_SPI_NOR)
1676                 extern int mxc_spi_nor_fis_start(void);
1677                 if (IS_FIS_FROM_SPI_NOR()) {
1678                         fis_addr = (void *)((CYG_ADDRESS)flash_start + mxc_spi_nor_fis_start());
1679                 }
1680 #endif
1681
1682 #if defined(MXCFLASH_SELECT_MMC)
1683                 if (IS_FIS_FROM_MMC()) {
1684                         fis_addr = (void *)REDBOOT_IMAGE_SIZE;
1685                 }
1686 #endif
1687
1688                 if (((CYG_ADDRESS)fis_addr + fisdir_size - 1) > (CYG_ADDRESS)flash_end) {
1689                         diag_printf("FIS directory doesn't fit\n");
1690                         return -1;
1691                 }
1692 #ifdef CYGOPT_REDBOOT_REDUNDANT_FIS
1693
1694                 if (CYGNUM_REDBOOT_FIS_REDUNDANT_DIRECTORY_BLOCK < 0) {
1695                         redundant_fis_addr = (void *)((CYG_ADDRESS)flash_end + 1 +
1696                                                                                   (CYGNUM_REDBOOT_FIS_REDUNDANT_DIRECTORY_BLOCK *
1697                                                                                    flash_block_size));
1698                 } else {
1699                         redundant_fis_addr = (void *)((CYG_ADDRESS)flash_start +
1700                                                                                   (CYGNUM_REDBOOT_FIS_REDUNDANT_DIRECTORY_BLOCK *
1701                                                                                    flash_block_size));
1702                 }
1703
1704                 if (((CYG_ADDRESS)redundant_fis_addr + fisdir_size - 1) > (CYG_ADDRESS)flash_end) {
1705                         diag_printf("Redundant FIS directory doesn't fit\n");
1706                         return -1;
1707                 }
1708                 FLASH_READ(fis_addr, &img0, sizeof(img0), &err_addr);
1709                 FLASH_READ(redundant_fis_addr, &img1, sizeof(img1), &err_addr);
1710
1711                 if (strncmp(img0.u.valid_info.magic_name, CYG_REDBOOT_RFIS_VALID_MAGIC,
1712                                         CYG_REDBOOT_RFIS_VALID_MAGIC_LENGTH) != 0) {
1713                                 memset(&img0, 0, sizeof(img0));
1714                         }
1715
1716                 if (strncmp(img1.u.valid_info.magic_name, CYG_REDBOOT_RFIS_VALID_MAGIC,
1717                                         CYG_REDBOOT_RFIS_VALID_MAGIC_LENGTH) != 0) {
1718                         memset(&img1, 0, sizeof(img0));
1719                 }
1720
1721 #ifdef REDBOOT_FLASH_REVERSE_BYTEORDER
1722                 img0.u.valid_info.version_count = CYG_SWAP32(img0.u.valid_info.version_count);
1723                 img1.u.valid_info.version_count = CYG_SWAP32(img1.u.valid_info.version_count);
1724 #endif
1725
1726                 if (fis_get_valid_buf(&img0, &img1, &fis_update_was_interrupted) == 1) {
1727                         // Valid, so swap primary and secondary
1728                         void *tmp;
1729                         tmp = fis_addr;
1730                         fis_addr = redundant_fis_addr;
1731                         redundant_fis_addr = tmp;
1732                 }
1733 #endif
1734                 fis_read_directory();
1735 #endif
1736         }
1737 #ifdef CYGOPT_REDBOOT_REDUNDANT_FIS
1738         if (fis_update_was_interrupted)
1739                 return 1;
1740         else
1741                 return 0;
1742 #else
1743         return 0;
1744 #endif
1745 }
1746
1747 // Wrapper to avoid compiler warnings
1748 static void
1749 _do_flash_init(void)
1750 {
1751     static int init_done = 0;
1752     if (init_done) return;
1753     init_done = 1;
1754     do_flash_init();
1755 }
1756
1757 RedBoot_init(_do_flash_init, RedBoot_INIT_FIRST);
1758
1759 static void
1760 do_fis(int argc, char *argv[])
1761 {
1762     struct cmd *cmd;
1763
1764     if (argc < 2) {
1765                 fis_usage("too few arguments");
1766                 return;
1767     }
1768     if (do_flash_init() < 0) {
1769         diag_printf("Sorry, no FLASH memory is available\n");
1770         return;
1771     }
1772     if ((cmd = cmd_search(__FIS_cmds_TAB__, &__FIS_cmds_TAB_END__,
1773                           argv[1])) != NULL) {
1774                 (cmd->fun)(argc, argv);
1775                 return;
1776     }
1777     fis_usage("unrecognized command");
1778 }