]> git.kernelconcepts.de Git - karo-tx-redboot.git/blob - packages/redboot/v2_0/src/flash.c
5517631a8f8b68672c3fd95c74724a5eb2f33c59
[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 : img->mem_base,
745                                                 show_datalen ? img->data_length : img->size,
746 #else
747                                                 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     // Do not search the area reserved for pre-RedBoot systems:
829     fis_ptr = (unsigned long *)((CYG_ADDRESS)flash_start +
830                                                                 CYGNUM_REDBOOT_FLASH_RESERVED_BASE);
831     fis_end = (unsigned long *)(CYG_ADDRESS)flash_end;
832     area_start = fis_ptr;
833     while (fis_ptr < fis_end) {
834                 flash_read(fis_ptr, &flash_data, sizeof(unsigned long), &err_addr);
835                 if (flash_data != 0xFFFFFFFF) {
836                         if (area_start != fis_ptr) {
837                                 // Assume that this is something
838                                 diag_printf("  0x%08x .. 0x%08x\n",
839                                                         (CYG_ADDRESS)area_start, (CYG_ADDRESS)fis_ptr);
840                         }
841                         // Find next blank block
842                         area_start = fis_ptr;
843                         while (area_start < fis_end) {
844                                 flash_read(area_start, &flash_data, sizeof(unsigned long), &err_addr);
845                                 if (flash_data == 0xFFFFFFFF) {
846                                         break;
847                                 }
848                                 area_start += flash_block_size / sizeof(CYG_ADDRESS);
849                         }
850                         fis_ptr = area_start;
851                 } else {
852                         fis_ptr += flash_block_size / sizeof(CYG_ADDRESS);
853                 }
854     }
855     if (area_start != fis_ptr) {
856                 diag_printf("  0x%08x .. 0x%08x\n",
857                                         (CYG_ADDRESS)area_start, (CYG_ADDRESS)fis_ptr);
858     }
859 #else
860     struct free_chunk chunks[CYGDAT_REDBOOT_FIS_MAX_FREE_CHUNKS];
861     int idx, num_chunks;
862
863     num_chunks = find_free(chunks);
864     for (idx = 0; idx < num_chunks; idx++) {
865                 diag_printf("  0x%08x .. 0x%08x\n",
866                                         chunks[idx].start,
867                                         chunks[idx].end);
868     }
869 #endif
870 }
871
872 // Find the first unused area of flash which is long enough
873 static bool
874 fis_find_free(CYG_ADDRESS *addr, unsigned long length)
875 {
876 #ifndef CYGDAT_REDBOOT_FIS_MAX_FREE_CHUNKS
877     unsigned long *fis_ptr, *fis_end, flash_data;
878     unsigned long *area_start;
879     void *err_addr;
880
881     // Do not search the area reserved for pre-RedBoot systems:
882     fis_ptr = (unsigned long *)((CYG_ADDRESS)flash_start +
883                                                                 CYGNUM_REDBOOT_FLASH_RESERVED_BASE);
884     fis_end = (unsigned long *)(CYG_ADDRESS)flash_end;
885     area_start = fis_ptr;
886     while (fis_ptr < fis_end) {
887                 flash_read(fis_ptr, &flash_data, sizeof(unsigned long), &err_addr);
888                 if (flash_data != 0xFFFFFFFF) {
889                         if (area_start != fis_ptr) {
890                                 // Assume that this is something
891                                 if ((fis_ptr - area_start) >= (length/sizeof(unsigned))) {
892                                         *addr = (CYG_ADDRESS)area_start;
893                                         return true;
894                                 }
895                         }
896                         // Find next blank block
897                         area_start = fis_ptr;
898                         while (area_start < fis_end) {
899                                 flash_read(area_start, &flash_data, sizeof(unsigned long), &err_addr);
900                                 if (flash_data == 0xFFFFFFFF) {
901                                         break;
902                                 }
903                                 area_start += flash_block_size / sizeof(CYG_ADDRESS);
904                         }
905                         fis_ptr = area_start;
906                 } else {
907                         fis_ptr += flash_block_size / sizeof(CYG_ADDRESS);
908                 }
909     }
910     if (area_start != fis_ptr) {
911                 if (fis_ptr - area_start >= length / sizeof(unsigned)) {
912                         *addr = (CYG_ADDRESS)area_start;
913                         return true;
914                 }
915     }
916     return false;
917 #else
918     struct free_chunk chunks[CYGDAT_REDBOOT_FIS_MAX_FREE_CHUNKS];
919     int idx, num_chunks;
920
921     num_chunks = find_free(chunks);
922     for (idx = 0; idx < num_chunks; idx++) {
923                 if (chunks[idx].end + 1 - chunks[idx].start >= length) {
924                         *addr = (CYG_ADDRESS)chunks[idx].start;
925                         return true;
926                 }
927     }
928     return false;
929 #endif
930 }
931
932 static void
933 fis_create(int argc, char *argv[])
934 {
935     int i, stat;
936     unsigned long length, img_size;
937     CYG_ADDRESS mem_addr, exec_addr, flash_addr, entry_addr;
938     char *name;
939     bool mem_addr_set = false;
940     bool exec_addr_set = false;
941     bool entry_addr_set = false;
942     bool flash_addr_set = false;
943     bool length_set = false;
944     bool img_size_set = false;
945     bool no_copy = false;
946     void *err_addr;
947     struct fis_image_desc *img = NULL;
948     bool defaults_assumed;
949     struct option_info opts[7];
950     bool prog_ok = true;
951
952     init_opts(&opts[0], 'b', true, OPTION_ARG_TYPE_NUM,
953                           &mem_addr, &mem_addr_set, "memory base address");
954     init_opts(&opts[1], 'r', true, OPTION_ARG_TYPE_NUM,
955                           &exec_addr, &exec_addr_set, "ram base address");
956     init_opts(&opts[2], 'e', true, OPTION_ARG_TYPE_NUM,
957                           &entry_addr, &entry_addr_set, "entry point address");
958     init_opts(&opts[3], 'f', true, OPTION_ARG_TYPE_NUM,
959                           &flash_addr, &flash_addr_set, "FLASH memory base address");
960     init_opts(&opts[4], 'l', true, OPTION_ARG_TYPE_NUM,
961                           &length, &length_set, "image length [in FLASH]");
962     init_opts(&opts[5], 's', true, OPTION_ARG_TYPE_NUM,
963                           &img_size, &img_size_set, "image size [actual data]");
964     init_opts(&opts[6], 'n', false, OPTION_ARG_TYPE_FLG,
965                           &no_copy, NULL, "don't copy from RAM to FLASH, just update directory");
966     if (!scan_opts(argc, argv, 2, opts, 7, &name, OPTION_ARG_TYPE_STR, "file name")) {
967                 fis_usage("invalid arguments");
968                 return;
969         }
970
971     fis_read_directory();
972     defaults_assumed = false;
973     if (name) {
974                 // Search existing files to acquire defaults for params not specified:
975                 img = fis_lookup(name, NULL);
976                 if (img) {
977                         // Found it, so get image size from there
978                         if (!length_set) {
979                                 length_set = true;
980                                 length = img->size;
981                                 defaults_assumed = true;
982                         }
983                 }
984     }
985     if (!mem_addr_set && (load_address >= (CYG_ADDRESS)ram_start) &&
986                 (load_address_end) < (CYG_ADDRESS)ram_end) {
987                 mem_addr = load_address;
988                 mem_addr_set = true;
989                 defaults_assumed = true;
990                 // Get entry address from loader, unless overridden
991                 if (!entry_addr_set)
992                         entry_addr = entry_address;
993                 if (!length_set) {
994                         length = load_address_end - load_address;
995                         length_set = true;
996                 } else if (defaults_assumed && !img_size_set) {
997                         /* We got length from the FIS table, so the size of the
998                            actual loaded image becomes img_size */
999                         img_size = load_address_end - load_address;
1000                         img_size_set = true;
1001                 }
1002     }
1003     // Get the remaining fall-back values from the fis
1004     if (img) {
1005                 if (!exec_addr_set) {
1006                         // Preserve "normal" behaviour
1007                         exec_addr_set = true;
1008                         exec_addr = flash_addr_set ? flash_addr : mem_addr;
1009                 }
1010                 if (!flash_addr_set) {
1011                         flash_addr_set = true;
1012                         flash_addr = img->flash_base;
1013                         defaults_assumed = true;
1014                 }
1015     }
1016
1017     if ((!no_copy && !mem_addr_set) || (no_copy && !flash_addr_set) ||
1018                 !length_set || !name) {
1019                 fis_usage("required parameter missing");
1020                 return;
1021     }
1022     if (!img_size_set) {
1023                 img_size = length;
1024     }
1025     // 'length' is size of FLASH image, 'img_size' is actual data size
1026     // Round up length to FLASH block size
1027 #ifndef CYGPKG_HAL_MIPS // FIXME: compiler is b0rken
1028     length = ((length + flash_block_size - 1) / flash_block_size) * flash_block_size;
1029     if (length < img_size) {
1030                 diag_printf("Invalid FLASH image size/length combination\n");
1031                 return;
1032     }
1033 #endif
1034     if (flash_addr_set &&
1035                 ((stat = flash_verify_addr((void *)flash_addr)) ||
1036                  (stat = flash_verify_addr((void *)(flash_addr + length - 1))))) {
1037                 _show_invalid_flash_address(flash_addr, stat);
1038                 return;
1039     }
1040     if (flash_addr_set && ((flash_addr & (flash_block_size - 1)) != 0)) {
1041                 diag_printf("Invalid FLASH address: %p\n", (void *)flash_addr);
1042                 diag_printf("   must be 0x%x aligned\n", flash_block_size);
1043                 return;
1044     }
1045     if (strlen(name) >= sizeof(img->u.name)) {
1046         diag_printf("Name is too long, must be less than %d chars\n", sizeof(img->u.name));
1047         return;
1048     }
1049     if (!no_copy) {
1050                 if ((mem_addr < (CYG_ADDRESS)ram_start) ||
1051                         ((mem_addr+img_size) >= (CYG_ADDRESS)ram_end)) {
1052                         diag_printf("** WARNING: RAM address: %p may be invalid\n", (void *)mem_addr);
1053                         diag_printf("   valid range is %p-%p\n", (void *)ram_start, (void *)ram_end);
1054                 }
1055                 if (!flash_addr_set && !fis_find_free(&flash_addr, length)) {
1056                         diag_printf("Can't locate %lx(%ld) bytes free in FLASH\n", length, length);
1057                         return;
1058                 }
1059     }
1060     // First, see if the image by this name has agreable properties
1061     if (img) {
1062                 if (flash_addr_set && (img->flash_base != flash_addr)) {
1063                         diag_printf("Image found, but flash address (%p)\n"
1064                                                 "             is incorrect (present image location %p)\n",
1065                                                 (void *)flash_addr, (void *)img->flash_base);
1066
1067                         return;
1068                 }
1069                 if (img->size != length) {
1070                         diag_printf("Image found, but length (0x%lx, necessitating image size 0x%lx)\n"
1071                                                 "             is incorrect (present image size 0x%lx)\n",
1072                                                 img_size, length, img->size);
1073                         return;
1074                 }
1075                 if (!verify_action("An image named '%s' exists", name)) {
1076                         return;
1077                 } else {
1078                         if (defaults_assumed) {
1079                                 if (no_copy &&
1080                                         !verify_action("* CAUTION * about to program '%s'\n                at %p..%p from %p",
1081                                                                    name, (void *)flash_addr, (void *)(flash_addr+img_size-1),
1082                                                                    (void *)mem_addr)) {
1083                                         return;  // The guy gave up
1084                                 }
1085                         }
1086                 }
1087     } else {
1088 #ifdef CYGDAT_REDBOOT_FIS_MAX_FREE_CHUNKS
1089         // Make sure that any FLASH address specified directly is truly free
1090         if (flash_addr_set && !no_copy) {
1091             struct free_chunk chunks[CYGDAT_REDBOOT_FIS_MAX_FREE_CHUNKS];
1092             int idx, num_chunks;
1093             bool is_free = false;
1094
1095             num_chunks = find_free(chunks);
1096             for (idx = 0;  idx < num_chunks;  idx++) {
1097                 if ((flash_addr >= chunks[idx].start) &&
1098                     ((flash_addr+length-1) <= chunks[idx].end)) {
1099                     is_free = true;
1100                 }
1101             }
1102             if (!is_free) {
1103                 diag_printf("Invalid FLASH address - not free!\n");
1104                 return;
1105             }
1106         }
1107 #endif
1108         // If not image by that name, try and find an empty slot
1109         img = fis_work_block;
1110         for (i = 0;  i < fisdir_size/sizeof(*img);  i++, img++) {
1111             if (img->u.name[0] == 0xFF) {
1112                 break;
1113             }
1114         }
1115                 if (i >= fisdir_size/sizeof(*img)) {
1116                         diag_printf("Can't find an empty slot in FIS directory!\n");
1117                         return;
1118                 }
1119     }
1120     if (!no_copy) {
1121                 // Safety check - make sure the address range is not within the code we're running
1122                 if (flash_code_overlaps((void *)flash_addr, (void *)(flash_addr+img_size-1))) {
1123                         diag_printf("Can't program this region - contains code in use!\n");
1124                         return;
1125                 }
1126                 if (prog_ok) {
1127                         // Erase area to be programmed
1128                         if ((stat = flash_erase((void *)flash_addr, length, &err_addr)) != 0) {
1129                                 diag_printf("Can't erase region at %p: %s\n", err_addr, flash_errmsg(stat));
1130                                 prog_ok = false;
1131                         }
1132                 }
1133                 if (prog_ok) {
1134                         // Now program it
1135                         if ((stat = FLASH_PROGRAM((void *)flash_addr, (void *)mem_addr, img_size, &err_addr)) != 0) {
1136                                 diag_printf("Can't program region at %p: %s\n", err_addr, flash_errmsg(stat));
1137                                 prog_ok = false;
1138                         }
1139                 }
1140     }
1141     if (prog_ok) {
1142         // Update directory
1143         memset(img, 0, sizeof(*img));
1144         strcpy(img->u.name, name);
1145         img->flash_base = flash_addr;
1146         img->mem_base = exec_addr_set ? exec_addr : (mem_addr_set ? mem_addr : flash_addr);
1147         img->entry_point = entry_addr_set ? entry_addr : (CYG_ADDRESS)entry_address;  // Hope it's been set
1148         img->size = length;
1149         img->data_length = img_size;
1150 #ifdef CYGSEM_REDBOOT_FIS_CRC_CHECK
1151                 if (!no_copy) {
1152                         img->file_cksum = cyg_crc32((unsigned char *)mem_addr, img_size);
1153                 } else {
1154                         // No way to compute this, sorry
1155                         img->file_cksum = 0;
1156                 }
1157 #endif
1158         fis_start_update_directory(0);
1159         fis_update_directory(0, 0);
1160     }
1161 }
1162
1163 extern void arm_fis_delete(char *);
1164 static void
1165 fis_delete(int argc, char *argv[])
1166 {
1167     char *name;
1168     int num_reserved, i, stat;
1169     void *err_addr;
1170     struct fis_image_desc *img;
1171
1172     if (!scan_opts(argc, argv, 2, 0, 0, &name, OPTION_ARG_TYPE_STR, "image name")) {
1173                 fis_usage("invalid arguments");
1174                 return;
1175         }
1176 #ifdef CYGHWR_REDBOOT_ARM_FLASH_SIB
1177     // FIXME: this is somewhat half-baked
1178     arm_fis_delete(name);
1179     return;
1180 #endif
1181     img = (struct fis_image_desc *)fis_work_block;
1182     num_reserved = 0;
1183 #ifdef CYGOPT_REDBOOT_FIS_RESERVED_BASE
1184     num_reserved++;
1185 #endif
1186 #ifdef CYGOPT_REDBOOT_FIS_REDBOOT
1187     num_reserved++;
1188 #endif
1189 #ifdef CYGOPT_REDBOOT_FIS_REDBOOT_BACKUP
1190     num_reserved++;
1191 #endif
1192 #ifdef CYGOPT_REDBOOT_FIS_REDBOOT_POST
1193     num_reserved++;
1194 #endif
1195 #if defined(CYGSEM_REDBOOT_FLASH_CONFIG) && defined(CYGHWR_REDBOOT_FLASH_CONFIG_MEDIA_FLASH)
1196     num_reserved++;
1197 #endif
1198 #if 1 // And the descriptor for the descriptor table itself
1199     num_reserved++;
1200 #endif
1201
1202     img = fis_lookup(name, &i);
1203     if (img) {
1204         if (i < num_reserved) {
1205             diag_printf("Sorry, '%s' is a reserved image and cannot be deleted\n", img->u.name);
1206             return;
1207         }
1208         if (!verify_action("Delete image '%s'", name)) {
1209             return;
1210         }
1211     } else {
1212                 diag_printf("No image '%s' found\n", name);
1213         return;
1214     }
1215     // Erase Data blocks (free space)
1216     if ((stat = flash_erase((void *)img->flash_base, img->size, &err_addr)) != 0) {
1217                 diag_printf("Error erasing at %p: %s\n", err_addr, flash_errmsg(stat));
1218     } else {
1219                 img->u.name[0] = 0xFF;
1220                 fis_start_update_directory(0);
1221                 fis_update_directory(0, 0);
1222     }
1223 }
1224
1225 static void
1226 fis_load(int argc, char *argv[])
1227 {
1228     char *name;
1229     struct fis_image_desc *img;
1230     CYG_ADDRESS mem_addr;
1231     bool mem_addr_set = false;
1232     bool show_cksum = false;
1233     bool load_ce = false;
1234     struct option_info opts[4];
1235 #if defined(CYGSEM_REDBOOT_FIS_CRC_CHECK)
1236     unsigned long cksum;
1237 #endif
1238     int num_options = 0;
1239 #if defined(CYGPRI_REDBOOT_ZLIB_FLASH) ||  defined(CYGSEM_REDBOOT_FIS_CRC_CHECK)
1240     bool decompress = false;
1241 #endif
1242     void *err_addr;
1243
1244     init_opts(&opts[num_options++], 'b', true, OPTION_ARG_TYPE_NUM,
1245                           &mem_addr, &mem_addr_set, "memory [load] base address");
1246     init_opts(&opts[num_options++], 'c', false, OPTION_ARG_TYPE_FLG,
1247                           &show_cksum, NULL, "display checksum");
1248 #ifdef CYGBLD_BUILD_REDBOOT_WITH_WINCE_SUPPORT
1249     init_opts(&opts[num_options++], 'w', false, OPTION_ARG_TYPE_FLG,
1250                           &load_ce, NULL, "parse as Windows CE image");
1251 #endif
1252 #ifdef CYGPRI_REDBOOT_ZLIB_FLASH
1253     init_opts(&opts[num_options++], 'd', false, OPTION_ARG_TYPE_FLG,
1254                           &decompress, 0, "decompress");
1255 #endif
1256
1257     CYG_ASSERT(num_options <= num_options, "Too many options");
1258
1259     if (!scan_opts(argc, argv, 2, opts, num_options, &name,
1260                                    OPTION_ARG_TYPE_STR, "image name")) {
1261                 fis_usage("invalid arguments");
1262                 return;
1263     }
1264     if ((img = fis_lookup(name, NULL)) == NULL) {
1265                 diag_printf("No image '%s' found\n", name);
1266                 return;
1267     }
1268     if (!mem_addr_set || load_ce) {
1269                 mem_addr = img->mem_base;
1270     }
1271     // Load image from FLASH into RAM
1272 #ifdef CYGSEM_REDBOOT_VALIDATE_USER_RAM_LOADS
1273     if (!valid_address((void *)mem_addr)) {
1274                 if (!load_ce) {
1275                         diag_printf("Not a loadable image - try using -b ADDRESS option\n");
1276                 } else {
1277                         diag_printf("Not a loadable image\n");
1278                 }
1279                 return;
1280     }
1281 #endif
1282 #ifdef CYGBLD_BUILD_REDBOOT_WITH_WINCE_SUPPORT
1283     if (load_ce) {
1284                 if (mem_addr_set) {
1285                         diag_printf("Warning: -b argument ignored for Windows CE image\n");
1286                 }
1287                 FLASH_Enable((void *)img->flash_base, (void *)(img->flash_base + img->size));
1288                 if (!ce_is_bin_image((void *)img->flash_base, img->size)) {
1289                         diag_printf("** Error: This does not seem to be a valid Windows CE image\n");
1290                         return;
1291                 }
1292                 if (!ce_bin_load((void *)img->flash_base, img->size)) {
1293                         diag_printf("** Error: Failed to load Windows CE image\n");
1294                 }
1295                 FLASH_Disable((void *)img->flash_base, (void *)(img->flash_base + img->size));
1296                 // Set load address/top
1297                 load_address = mem_addr;
1298                 load_address_end = mem_addr + img->data_length;
1299                 return;
1300     }
1301 #endif
1302 #ifdef CYGPRI_REDBOOT_ZLIB_FLASH
1303     if (decompress) {
1304                 int err;
1305                 _pipe_t fis_load_pipe;
1306                 _pipe_t *p = &fis_load_pipe;
1307                 p->out_buf = (unsigned char*) mem_addr;
1308                 p->out_max = p->out_size = -1;
1309                 p->in_buf = (unsigned char*) img->flash_base;
1310                 p->in_avail = img->data_length;
1311
1312                 err = (*_dc_init)(p);
1313
1314                 if (0 == err)
1315                         err = (*_dc_inflate)(p);
1316
1317                 // Free used resources, do final translation of
1318                 // error value.
1319                 err = (*_dc_close)(p, err);
1320
1321                 if (0 != err && p->msg) {
1322                         diag_printf("decompression error: %s\n", p->msg);
1323                 } else {
1324                         diag_printf("Image loaded from %p-%p\n", (unsigned char *)mem_addr, p->out_buf);
1325                 }
1326
1327                 // Set load address/top
1328                 load_address = mem_addr;
1329                 load_address_end = (unsigned long)p->out_buf;
1330
1331                 // Reload fis directory
1332                 fis_read_directory();
1333     } else // dangling block
1334 #endif
1335                 {
1336                         if (flash_read((void *)img->flash_base, (void *)mem_addr,
1337                                                    img->data_length, &err_addr) != FLASH_ERR_OK) {
1338                                 diag_printf("** Error: Failed to load image from flash\n");
1339                                 return;
1340                         }
1341
1342                         // Set load address/top
1343                         load_address = mem_addr;
1344                         load_address_end = mem_addr + img->data_length;
1345                 }
1346     entry_address = (unsigned long)img->entry_point;
1347
1348 #ifdef CYGSEM_REDBOOT_FIS_CRC_CHECK
1349     cksum = cyg_crc32((unsigned char *)mem_addr, img->data_length);
1350     if (show_cksum) {
1351                 diag_printf("Checksum: 0x%08lx\n", cksum);
1352     }
1353     // When decompressing, leave CRC checking to decompressor
1354     if (!decompress && img->file_cksum) {
1355                 if (cksum != img->file_cksum) {
1356                         diag_printf("** Warning - checksum failure.      stored: 0x%08lx, computed: 0x%08lx\n",
1357                                                 img->file_cksum, cksum);
1358                         entry_address = (unsigned long)NO_MEMORY;
1359                 }
1360     }
1361 #endif
1362     diag_printf("image loaded 0x%08lx-0x%08lx, assumed entry at 0x%08lx\n",
1363                                 load_address, load_address_end - 1, entry_address);
1364 }
1365 #endif // CYGOPT_REDBOOT_FIS
1366
1367 static void
1368 fis_write(int argc, char *argv[])
1369 {
1370     int stat;
1371     unsigned long length;
1372     CYG_ADDRESS mem_addr, flash_addr;
1373     bool mem_addr_set = false;
1374     bool flash_addr_set = false;
1375     bool length_set = false;
1376     void *err_addr;
1377     struct option_info opts[3];
1378     bool prog_ok;
1379
1380     init_opts(&opts[0], 'b', true, OPTION_ARG_TYPE_NUM,
1381                           &mem_addr, &mem_addr_set, "memory base address");
1382     init_opts(&opts[1], 'f', true, OPTION_ARG_TYPE_NUM,
1383                           &flash_addr, &flash_addr_set, "FLASH memory base address");
1384     init_opts(&opts[2], 'l', true, OPTION_ARG_TYPE_NUM,
1385                           &length, &length_set, "image length [in FLASH]");
1386     if (!scan_opts(argc, argv, 2, opts, 3, 0, 0, 0))
1387                 {
1388                         fis_usage("invalid arguments");
1389                         return;
1390                 }
1391
1392     if (!mem_addr_set || !flash_addr_set || !length_set) {
1393                 fis_usage("required parameter missing");
1394                 return;
1395     }
1396
1397     // Round up length to FLASH block size
1398 #ifndef CYGPKG_HAL_MIPS // FIXME: compiler is b0rken
1399     length = ((length + flash_block_size - 1) / flash_block_size) * flash_block_size;
1400 #endif
1401     if (flash_addr_set &&
1402                 ((stat = flash_verify_addr((void *)flash_addr)) ||
1403                  (stat = flash_verify_addr((void *)(flash_addr + length - 1))))) {
1404                 _show_invalid_flash_address(flash_addr, stat);
1405                 return;
1406     }
1407     if (flash_addr_set && flash_addr & (flash_block_size-1)) {
1408                 diag_printf("Invalid FLASH address: %p\n", (void *)flash_addr);
1409                 diag_printf("   must be 0x%x aligned\n", flash_block_size);
1410                 return;
1411     }
1412     if ((mem_addr < (CYG_ADDRESS)ram_start) ||
1413                 ((mem_addr+length) >= (CYG_ADDRESS)ram_end)) {
1414                 diag_printf("** WARNING: RAM address: %p may be invalid\n", (void *)mem_addr);
1415                 diag_printf("   valid range is %p-%p\n", (void *)ram_start, (void *)ram_end);
1416     }
1417     // Safety check - make sure the address range is not within the code we're running
1418     if (flash_code_overlaps((void *)flash_addr, (void *)(flash_addr + length - 1))) {
1419                 diag_printf("Can't program this region - contains code in use!\n");
1420                 return;
1421     }
1422     if (!verify_action("* CAUTION * about to program FLASH\n            at %p..%p from %p",
1423                                            (void *)flash_addr, (void *)(flash_addr + length - 1),
1424                                            (void *)mem_addr)) {
1425                 return;  // The guy gave up
1426     }
1427     prog_ok = true;
1428     if (prog_ok) {
1429                 // Erase area to be programmed
1430                 if ((stat = flash_erase((void *)flash_addr, length, &err_addr)) != 0) {
1431                         diag_printf("Can't erase region at %p: %s\n", err_addr, flash_errmsg(stat));
1432                         prog_ok = false;
1433                 }
1434     }
1435     if (prog_ok) {
1436                 // Now program it
1437                 if ((stat = FLASH_PROGRAM((void *)flash_addr, (void *)mem_addr, length, &err_addr)) != 0) {
1438                         diag_printf("Can't program region at %p: %s\n", err_addr, flash_errmsg(stat));
1439                         prog_ok = false;
1440                 }
1441     }
1442 }
1443
1444 static void
1445 fis_erase(int argc, char *argv[])
1446 {
1447     int stat;
1448     unsigned long length;
1449     CYG_ADDRESS flash_addr;
1450     bool flash_addr_set = false;
1451     bool length_set = false;
1452     void *err_addr;
1453     struct option_info opts[2];
1454
1455     init_opts(&opts[0], 'f', true, OPTION_ARG_TYPE_NUM,
1456                           &flash_addr, &flash_addr_set, "FLASH memory base address");
1457     init_opts(&opts[1], 'l', true, OPTION_ARG_TYPE_NUM,
1458                           &length, &length_set, "length");
1459     if (!scan_opts(argc, argv, 2, opts, 2, NULL, 0, NULL))
1460                 {
1461                         fis_usage("invalid arguments");
1462                         return;
1463                 }
1464
1465     if (!flash_addr_set || !length_set) {
1466                 fis_usage("missing argument");
1467                 return;
1468     }
1469     if (flash_addr_set &&
1470                 ((stat = flash_verify_addr((void *)flash_addr)) ||
1471                  (stat = flash_verify_addr((void *)(flash_addr + length - 1))))) {
1472                 _show_invalid_flash_address(flash_addr, stat);
1473                 return;
1474     }
1475     if (flash_addr_set && flash_addr & (flash_block_size-1)) {
1476                 diag_printf("Invalid FLASH address: %p\n", (void *)flash_addr);
1477                 diag_printf("   must be 0x%x aligned\n", flash_block_size);
1478                 return;
1479     }
1480     // Safety check - make sure the address range is not within the code we're running
1481     if (flash_code_overlaps((void *)flash_addr, (void *)(flash_addr + length - 1))) {
1482                 diag_printf("Can't erase this region - contains code in use!\n");
1483                 return;
1484     }
1485     if ((stat = flash_erase((void *)flash_addr, length, &err_addr)) != 0) {
1486                 diag_printf("Error erasing at %p: %s\n", err_addr, flash_errmsg(stat));
1487     }
1488 }
1489
1490 #ifdef CYGHWR_IO_FLASH_BLOCK_LOCKING
1491
1492 static void
1493 fis_lock(int argc, char *argv[])
1494 {
1495     char *name;
1496     int stat;
1497     unsigned long length;
1498     CYG_ADDRESS flash_addr;
1499     bool flash_addr_set = false;
1500     bool length_set = false;
1501     void *err_addr;
1502     struct option_info opts[2];
1503
1504     init_opts(&opts[0], 'f', true, OPTION_ARG_TYPE_NUM,
1505                           &flash_addr, &flash_addr_set, "FLASH memory base address");
1506     init_opts(&opts[1], 'l', true, OPTION_ARG_TYPE_NUM,
1507                           &length, &length_set, "length");
1508     if (!scan_opts(argc, argv, 2, opts, 2, &name, OPTION_ARG_TYPE_STR, "image name"))
1509                 {
1510                         fis_usage("invalid arguments");
1511                         return;
1512                 }
1513 #ifdef CYGOPT_REDBOOT_FIS
1514     /* Get parameters from image if specified */
1515     if (name) {
1516                 struct fis_image_desc *img;
1517                 if ((img = fis_lookup(name, NULL)) == NULL) {
1518                         diag_printf("No image '%s' found\n", name);
1519                         return;
1520                 }
1521
1522         flash_addr = img->flash_base;
1523         length = img->size;
1524     } else
1525 #endif
1526                 if (!flash_addr_set || !length_set) {
1527                         fis_usage("missing argument");
1528                         return;
1529                 }
1530     if (flash_addr_set &&
1531                 ((stat = flash_verify_addr((void *)flash_addr)) ||
1532                  (stat = flash_verify_addr((void *)(flash_addr + length - 1))))) {
1533                 _show_invalid_flash_address(flash_addr, stat);
1534                 return;
1535     }
1536     if ((stat = flash_lock((void *)flash_addr, length, &err_addr)) != 0) {
1537                 diag_printf("Error locking at %p: %s\n", err_addr, flash_errmsg(stat));
1538     }
1539 }
1540
1541 static void
1542 fis_unlock(int argc, char *argv[])
1543 {
1544     char *name;
1545     int stat;
1546     unsigned long length;
1547     CYG_ADDRESS flash_addr;
1548     bool flash_addr_set = false;
1549     bool length_set = false;
1550     void *err_addr;
1551     struct option_info opts[2];
1552
1553     init_opts(&opts[0], 'f', true, OPTION_ARG_TYPE_NUM,
1554                           &flash_addr, &flash_addr_set, "FLASH memory base address");
1555     init_opts(&opts[1], 'l', true, OPTION_ARG_TYPE_NUM,
1556                           &length, &length_set, "length");
1557     if (!scan_opts(argc, argv, 2, opts, 2, &name, OPTION_ARG_TYPE_STR, "image name"))
1558                 {
1559                         fis_usage("invalid arguments");
1560                         return;
1561                 }
1562 #ifdef CYGOPT_REDBOOT_FIS
1563     if (name) {
1564                 struct fis_image_desc *img;
1565                 if ((img = fis_lookup(name, NULL)) == NULL) {
1566                         diag_printf("No image '%s' found\n", name);
1567                         return;
1568                 }
1569
1570         flash_addr = img->flash_base;
1571         length = img->size;
1572     } else
1573 #endif
1574                 if (!flash_addr_set || !length_set) {
1575                         fis_usage("missing argument");
1576                         return;
1577                 }
1578     if (flash_addr_set &&
1579                 ((stat = flash_verify_addr((void *)flash_addr)) ||
1580                  (stat = flash_verify_addr((void *)(flash_addr + length - 1))))) {
1581                 _show_invalid_flash_address(flash_addr, stat);
1582                 return;
1583     }
1584
1585     if ((stat = flash_unlock((void *)flash_addr, length, &err_addr)) != 0) {
1586                 diag_printf("Error unlocking at %p: %s\n", err_addr, flash_errmsg(stat));
1587     }
1588 }
1589 #endif
1590
1591 // This is set non-zero if the FLASH subsystem has successfully been initialized
1592 int __flash_init = 0;
1593
1594 void
1595 _flash_info(void)
1596 {
1597     if (!__flash_init) return;
1598     diag_printf("FLASH: %p - 0x%x, %d blocks of 0x%08x bytes each.\n",
1599                                 flash_start, (CYG_ADDRWORD)flash_end + 1, flash_num_blocks, flash_block_size);
1600 }
1601
1602 /* Returns -1 on failure, 0 on success, 1 if it was successfull
1603  but a failed fis update was detected  */
1604 int
1605 do_flash_init(void)
1606 {
1607         int stat;
1608
1609 #ifdef CYGOPT_REDBOOT_REDUNDANT_FIS
1610         struct fis_image_desc img0;
1611         struct fis_image_desc img1;
1612         int fis_update_was_interrupted = 0;
1613         void *err_addr;
1614
1615         //check the size of fis_valid_info
1616         CYG_ASSERT((sizeof(struct fis_valid_info) <= sizeof(img0.u.name)),
1617                            "fis_valid_info size mismatch");
1618         //try to check the alignment of version_count
1619         CYG_ASSERT(((&img0.u.valid_info.version_count - &img0) % sizeof(unsigned long) == 0),
1620                            "alignment problem");
1621 #endif
1622         if (!__flash_init) {
1623                 __flash_init = 1;
1624                 if ((stat = flash_init(diag_printf)) != 0) {
1625                         diag_printf("FLASH: driver init failed: %s\n", flash_errmsg(stat));
1626                         return -1;
1627                 }
1628                 flash_get_limits(NULL, &flash_start, &flash_end);
1629                 // Keep 'end' address as last valid location, to avoid wrap around problems
1630                 flash_end = (void *)((CYG_ADDRESS)flash_end - 1);
1631                 flash_get_block_info(&flash_block_size, &flash_num_blocks);
1632 #ifdef CYGOPT_REDBOOT_FIS
1633                 fisdir_size = CYGNUM_REDBOOT_FIS_DIRECTORY_ENTRY_COUNT * CYGNUM_REDBOOT_FIS_DIRECTORY_ENTRY_SIZE;
1634                 fisdir_size = ((fisdir_size + flash_block_size - 1) / flash_block_size) * flash_block_size;
1635 # if defined(CYGPRI_REDBOOT_ZLIB_FLASH) && defined(CYGOPT_REDBOOT_FIS_ZLIB_COMMON_BUFFER)
1636                 fis_work_block = fis_zlib_common_buffer;
1637                 if (CYGNUM_REDBOOT_FIS_ZLIB_COMMON_BUFFER_SIZE < fisdir_size) {
1638                         diag_printf("FLASH: common buffer too small\n");
1639                         return -1;
1640                 }
1641 # else
1642                 workspace_end = (unsigned char *)(workspace_end - fisdir_size);
1643                 fis_work_block = workspace_end;
1644 # endif
1645                 if (CYGNUM_REDBOOT_FIS_DIRECTORY_BLOCK < 0) {
1646                         fis_addr = (void *)((CYG_ADDRESS)flash_end + 1 +
1647                                                                 (CYGNUM_REDBOOT_FIS_DIRECTORY_BLOCK * flash_block_size));
1648                 } else {
1649                         fis_addr = (void *)((CYG_ADDRESS)flash_start +
1650                                                                 (CYGNUM_REDBOOT_FIS_DIRECTORY_BLOCK * flash_block_size));
1651                 }
1652 #if defined(CYGHWR_DEVS_FLASH_MXC_MULTI) && defined(MXCFLASH_SELECT_NAND)
1653                 extern int mxc_nand_fis_start(void);
1654                 if (IS_FIS_FROM_NAND()) {
1655                         fis_addr = (void *)((CYG_ADDRESS)flash_start + mxc_nand_fis_start());
1656                 }
1657 #endif
1658
1659 #if defined(IMXFLASH_SELECT_SPI_NOR)
1660                 extern int mxc_spi_nor_fis_start(void);
1661                 if (IS_FIS_FROM_SPI_NOR()) {
1662                         fis_addr = (void *)((CYG_ADDRESS)flash_start + mxc_spi_nor_fis_start());
1663                 }
1664 #endif
1665
1666 #if defined(MXCFLASH_SELECT_MMC)
1667                 if (IS_FIS_FROM_MMC()) {
1668                         fis_addr = (void *)REDBOOT_IMAGE_SIZE;
1669                 }
1670 #endif
1671
1672                 if (((CYG_ADDRESS)fis_addr + fisdir_size - 1) > (CYG_ADDRESS)flash_end) {
1673                         diag_printf("FIS directory doesn't fit\n");
1674                         return -1;
1675                 }
1676 #ifdef CYGOPT_REDBOOT_REDUNDANT_FIS
1677
1678                 if (CYGNUM_REDBOOT_FIS_REDUNDANT_DIRECTORY_BLOCK < 0) {
1679                         redundant_fis_addr = (void *)((CYG_ADDRESS)flash_end + 1 +
1680                                                                                   (CYGNUM_REDBOOT_FIS_REDUNDANT_DIRECTORY_BLOCK *
1681                                                                                    flash_block_size));
1682                 } else {
1683                         redundant_fis_addr = (void *)((CYG_ADDRESS)flash_start +
1684                                                                                   (CYGNUM_REDBOOT_FIS_REDUNDANT_DIRECTORY_BLOCK *
1685                                                                                    flash_block_size));
1686                 }
1687
1688                 if (((CYG_ADDRESS)redundant_fis_addr + fisdir_size - 1) > (CYG_ADDRESS)flash_end) {
1689                         diag_printf("Redundant FIS directory doesn't fit\n");
1690                         return -1;
1691                 }
1692                 FLASH_READ(fis_addr, &img0, sizeof(img0), &err_addr);
1693                 FLASH_READ(redundant_fis_addr, &img1, sizeof(img1), &err_addr);
1694
1695                 if (strncmp(img0.u.valid_info.magic_name, CYG_REDBOOT_RFIS_VALID_MAGIC,
1696                                         CYG_REDBOOT_RFIS_VALID_MAGIC_LENGTH) != 0) {
1697                                 memset(&img0, 0, sizeof(img0));
1698                         }
1699
1700                 if (strncmp(img1.u.valid_info.magic_name, CYG_REDBOOT_RFIS_VALID_MAGIC,
1701                                         CYG_REDBOOT_RFIS_VALID_MAGIC_LENGTH) != 0) {
1702                         memset(&img1, 0, sizeof(img0));
1703                 }
1704
1705 #ifdef REDBOOT_FLASH_REVERSE_BYTEORDER
1706                 img0.u.valid_info.version_count = CYG_SWAP32(img0.u.valid_info.version_count);
1707                 img1.u.valid_info.version_count = CYG_SWAP32(img1.u.valid_info.version_count);
1708 #endif
1709
1710                 if (fis_get_valid_buf(&img0, &img1, &fis_update_was_interrupted) == 1) {
1711                         // Valid, so swap primary and secondary
1712                         void *tmp;
1713                         tmp = fis_addr;
1714                         fis_addr = redundant_fis_addr;
1715                         redundant_fis_addr = tmp;
1716                 }
1717 #endif
1718                 fis_read_directory();
1719 #endif
1720         }
1721 #ifdef CYGOPT_REDBOOT_REDUNDANT_FIS
1722         if (fis_update_was_interrupted)
1723                 return 1;
1724         else
1725                 return 0;
1726 #else
1727         return 0;
1728 #endif
1729 }
1730
1731 // Wrapper to avoid compiler warnings
1732 static void
1733 _do_flash_init(void)
1734 {
1735     static int init_done = 0;
1736     if (init_done) return;
1737     init_done = 1;
1738     do_flash_init();
1739 }
1740
1741 RedBoot_init(_do_flash_init, RedBoot_INIT_FIRST);
1742
1743 static void
1744 do_fis(int argc, char *argv[])
1745 {
1746     struct cmd *cmd;
1747
1748     if (argc < 2) {
1749                 fis_usage("too few arguments");
1750                 return;
1751     }
1752     if (do_flash_init() < 0) {
1753         diag_printf("Sorry, no FLASH memory is available\n");
1754         return;
1755     }
1756     if ((cmd = cmd_search(__FIS_cmds_TAB__, &__FIS_cmds_TAB_END__,
1757                           argv[1])) != NULL) {
1758                 (cmd->fun)(argc, argv);
1759                 return;
1760     }
1761     fis_usage("unrecognized command");
1762 }