]> git.kernelconcepts.de Git - karo-tx-redboot.git/blob - packages/redboot/v2_0/src/flash.c
b3f0beaa4ab56514e3fbf6ff9ed61ec6deba6338
[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                         FLASH_Enable((void *)flash_addr, (void *)(flash_addr + length));
1136                         // Erase area to be programmed
1137                         stat = flash_erase((void *)flash_addr, length, &err_addr);
1138                         FLASH_Disable((void *)flash_addr, (void *)(flash_addr + length));
1139                         if (stat != 0) {
1140                                 diag_printf("Can't erase region at %p: %s\n", err_addr, flash_errmsg(stat));
1141                                 prog_ok = false;
1142                         }
1143                 }
1144                 if (prog_ok) {
1145                         // Now program it
1146                         FLASH_Enable((void *)flash_addr, (void *)(flash_addr + length));
1147                         stat = FLASH_PROGRAM((void *)flash_addr, (void *)mem_addr,
1148                                                                  img_size, &err_addr);
1149                         FLASH_Disable((void *)flash_addr, (void *)(flash_addr + length));
1150                         if (stat != 0) {
1151                                 diag_printf("Can't program region at %p: %s\n", err_addr, flash_errmsg(stat));
1152                                 prog_ok = false;
1153                         }
1154                 }
1155     }
1156     if (prog_ok) {
1157                 // Update directory
1158                 memset(img, 0, sizeof(*img));
1159                 strcpy(img->u.name, name);
1160                 img->flash_base = flash_addr;
1161                 img->mem_base = exec_addr_set ? exec_addr : (mem_addr_set ? mem_addr : flash_addr);
1162                 img->entry_point = entry_addr_set ? entry_addr : (CYG_ADDRESS)entry_address;  // Hope it's been set
1163                 img->size = length;
1164                 img->data_length = img_size;
1165 #ifdef CYGSEM_REDBOOT_FIS_CRC_CHECK
1166                 if (!no_copy) {
1167                         img->file_cksum = cyg_crc32((unsigned char *)mem_addr, img_size);
1168                 } else {
1169                         // No way to compute this, sorry
1170                         img->file_cksum = 0;
1171                 }
1172 #endif
1173                 fis_start_update_directory(0);
1174                 fis_update_directory(0, 0);
1175     }
1176 }
1177
1178 extern void arm_fis_delete(char *);
1179 static void
1180 fis_delete(int argc, char *argv[])
1181 {
1182     char *name;
1183     int num_reserved, i, stat;
1184     void *err_addr;
1185     struct fis_image_desc *img;
1186
1187     if (!scan_opts(argc, argv, 2, 0, 0, &name, OPTION_ARG_TYPE_STR, "image name")) {
1188                 fis_usage("invalid arguments");
1189                 return;
1190         }
1191 #ifdef CYGHWR_REDBOOT_ARM_FLASH_SIB
1192     // FIXME: this is somewhat half-baked
1193     arm_fis_delete(name);
1194     return;
1195 #endif
1196     img = (struct fis_image_desc *)fis_work_block;
1197     num_reserved = 0;
1198 #ifdef CYGOPT_REDBOOT_FIS_RESERVED_BASE
1199     num_reserved++;
1200 #endif
1201 #ifdef CYGOPT_REDBOOT_FIS_REDBOOT
1202     num_reserved++;
1203 #endif
1204 #ifdef CYGOPT_REDBOOT_FIS_REDBOOT_BACKUP
1205     num_reserved++;
1206 #endif
1207 #ifdef CYGOPT_REDBOOT_FIS_REDBOOT_POST
1208     num_reserved++;
1209 #endif
1210 #if defined(CYGSEM_REDBOOT_FLASH_CONFIG) && defined(CYGHWR_REDBOOT_FLASH_CONFIG_MEDIA_FLASH)
1211     num_reserved++;
1212 #endif
1213 #if 1 // And the descriptor for the descriptor table itself
1214     num_reserved++;
1215 #endif
1216
1217     img = fis_lookup(name, &i);
1218     if (img) {
1219         if (i < num_reserved) {
1220             diag_printf("Sorry, '%s' is a reserved image and cannot be deleted\n", img->u.name);
1221             return;
1222         }
1223         if (!verify_action("Delete image '%s'", name)) {
1224             return;
1225         }
1226     } else {
1227                 diag_printf("No image '%s' found\n", name);
1228         return;
1229     }
1230     // Erase Data blocks (free space)
1231     if ((stat = flash_erase((void *)img->flash_base, img->size, &err_addr)) != 0) {
1232                 diag_printf("Error erasing at %p: %s\n", err_addr, flash_errmsg(stat));
1233     } else {
1234                 img->u.name[0] = 0xFF;
1235                 fis_start_update_directory(0);
1236                 fis_update_directory(0, 0);
1237     }
1238 }
1239
1240 static void
1241 fis_load(int argc, char *argv[])
1242 {
1243     char *name;
1244     struct fis_image_desc *img;
1245     CYG_ADDRESS mem_addr;
1246     bool mem_addr_set = false;
1247     bool show_cksum = false;
1248     bool load_ce = false;
1249     struct option_info opts[4];
1250 #if defined(CYGSEM_REDBOOT_FIS_CRC_CHECK)
1251     unsigned long cksum;
1252 #endif
1253     int num_options = 0;
1254 #if defined(CYGPRI_REDBOOT_ZLIB_FLASH) ||  defined(CYGSEM_REDBOOT_FIS_CRC_CHECK)
1255     bool decompress = false;
1256 #endif
1257     void *err_addr;
1258
1259     init_opts(&opts[num_options++], 'b', true, OPTION_ARG_TYPE_NUM,
1260                           &mem_addr, &mem_addr_set, "memory [load] base address");
1261     init_opts(&opts[num_options++], 'c', false, OPTION_ARG_TYPE_FLG,
1262                           &show_cksum, NULL, "display checksum");
1263 #ifdef CYGBLD_BUILD_REDBOOT_WITH_WINCE_SUPPORT
1264     init_opts(&opts[num_options++], 'w', false, OPTION_ARG_TYPE_FLG,
1265                           &load_ce, NULL, "parse as Windows CE image");
1266 #endif
1267 #ifdef CYGPRI_REDBOOT_ZLIB_FLASH
1268     init_opts(&opts[num_options++], 'd', false, OPTION_ARG_TYPE_FLG,
1269                           &decompress, 0, "decompress");
1270 #endif
1271
1272     CYG_ASSERT(num_options <= num_options, "Too many options");
1273
1274     if (!scan_opts(argc, argv, 2, opts, num_options, &name,
1275                                    OPTION_ARG_TYPE_STR, "image name")) {
1276                 fis_usage("invalid arguments");
1277                 return;
1278     }
1279     if ((img = fis_lookup(name, NULL)) == NULL) {
1280                 diag_printf("No image '%s' found\n", name);
1281                 return;
1282     }
1283     if (!mem_addr_set || load_ce) {
1284                 mem_addr = img->mem_base;
1285     }
1286     // Load image from FLASH into RAM
1287 #ifdef CYGSEM_REDBOOT_VALIDATE_USER_RAM_LOADS
1288     if (!valid_address((void *)mem_addr)) {
1289                 if (!load_ce) {
1290                         diag_printf("Not a loadable image - try using -b ADDRESS option\n");
1291                 } else {
1292                         diag_printf("Not a loadable image\n");
1293                 }
1294                 return;
1295     }
1296 #endif
1297 #ifdef CYGBLD_BUILD_REDBOOT_WITH_WINCE_SUPPORT
1298     if (load_ce) {
1299                 if (mem_addr_set) {
1300                         diag_printf("Warning: -b argument ignored for Windows CE image\n");
1301                 }
1302                 FLASH_Enable((void *)img->flash_base, (void *)(img->flash_base + img->size));
1303                 if (!ce_is_bin_image((void *)img->flash_base, img->size)) {
1304                         diag_printf("** Error: This does not seem to be a valid Windows CE image\n");
1305                         return;
1306                 }
1307                 if (!ce_bin_load((void *)img->flash_base, img->size)) {
1308                         diag_printf("** Error: Failed to load Windows CE image\n");
1309                 }
1310                 FLASH_Disable((void *)img->flash_base, (void *)(img->flash_base + img->size));
1311                 // Set load address/top
1312                 load_address = mem_addr;
1313                 load_address_end = mem_addr + img->data_length;
1314                 return;
1315     }
1316 #endif
1317 #ifdef CYGPRI_REDBOOT_ZLIB_FLASH
1318     if (decompress) {
1319                 int err;
1320                 _pipe_t fis_load_pipe;
1321                 _pipe_t *p = &fis_load_pipe;
1322                 p->out_buf = (unsigned char*) mem_addr;
1323                 p->out_max = p->out_size = -1;
1324                 p->in_buf = (unsigned char*) img->flash_base;
1325                 p->in_avail = img->data_length;
1326
1327                 err = (*_dc_init)(p);
1328
1329                 if (0 == err)
1330                         err = (*_dc_inflate)(p);
1331
1332                 // Free used resources, do final translation of
1333                 // error value.
1334                 err = (*_dc_close)(p, err);
1335
1336                 if (0 != err && p->msg) {
1337                         diag_printf("decompression error: %s\n", p->msg);
1338                 } else {
1339                         diag_printf("Image loaded from %p-%p\n", (unsigned char *)mem_addr, p->out_buf);
1340                 }
1341
1342                 // Set load address/top
1343                 load_address = mem_addr;
1344                 load_address_end = (unsigned long)p->out_buf;
1345
1346                 // Reload fis directory
1347                 fis_read_directory();
1348     } else // dangling block
1349 #endif
1350                 {
1351                         int err;
1352
1353                         FLASH_Enable((void *)img->flash_base, (void *)(img->flash_base + img->size));
1354                         err = flash_read((void *)img->flash_base, (void *)mem_addr,
1355                                                          img->data_length, &err_addr);
1356                         FLASH_Disable((void *)img->flash_base, (void *)(img->flash_base + img->size));
1357                         if (err != FLASH_ERR_OK) {
1358                                 diag_printf("** Error: Failed to load image from flash\n");
1359                                 return;
1360                         }
1361
1362                         // Set load address/top
1363                         load_address = mem_addr;
1364                         load_address_end = mem_addr + img->data_length;
1365                 }
1366     entry_address = (unsigned long)img->entry_point;
1367
1368 #ifdef CYGSEM_REDBOOT_FIS_CRC_CHECK
1369     cksum = cyg_crc32((unsigned char *)mem_addr, img->data_length);
1370     if (show_cksum) {
1371                 diag_printf("Checksum: 0x%08lx\n", cksum);
1372     }
1373     // When decompressing, leave CRC checking to decompressor
1374     if (!decompress && img->file_cksum) {
1375                 if (cksum != img->file_cksum) {
1376                         diag_printf("** Warning - checksum failure.      stored: 0x%08lx, computed: 0x%08lx\n",
1377                                                 img->file_cksum, cksum);
1378                         entry_address = (unsigned long)NO_MEMORY;
1379                 }
1380     }
1381 #endif
1382     diag_printf("image loaded 0x%08lx-0x%08lx, assumed entry at 0x%08lx\n",
1383                                 load_address, load_address_end - 1, entry_address);
1384 }
1385 #endif // CYGOPT_REDBOOT_FIS
1386
1387 static void
1388 fis_write(int argc, char *argv[])
1389 {
1390     int stat;
1391     unsigned long length;
1392     CYG_ADDRESS mem_addr, flash_addr;
1393     bool mem_addr_set = false;
1394     bool flash_addr_set = false;
1395     bool length_set = false;
1396     void *err_addr;
1397     struct option_info opts[3];
1398     bool prog_ok;
1399
1400     init_opts(&opts[0], 'b', true, OPTION_ARG_TYPE_NUM,
1401                           &mem_addr, &mem_addr_set, "memory base address");
1402     init_opts(&opts[1], 'f', true, OPTION_ARG_TYPE_NUM,
1403                           &flash_addr, &flash_addr_set, "FLASH memory base address");
1404     init_opts(&opts[2], 'l', true, OPTION_ARG_TYPE_NUM,
1405                           &length, &length_set, "image length [in FLASH]");
1406     if (!scan_opts(argc, argv, 2, opts, 3, 0, 0, 0))
1407                 {
1408                         fis_usage("invalid arguments");
1409                         return;
1410                 }
1411
1412     if (!mem_addr_set || !flash_addr_set || !length_set) {
1413                 fis_usage("required parameter missing");
1414                 return;
1415     }
1416
1417     // Round up length to FLASH block size
1418 #ifndef CYGPKG_HAL_MIPS // FIXME: compiler is b0rken
1419     length = ((length + flash_block_size - 1) / flash_block_size) * flash_block_size;
1420 #endif
1421     if (flash_addr_set &&
1422                 ((stat = flash_verify_addr((void *)flash_addr)) ||
1423                  (stat = flash_verify_addr((void *)(flash_addr + length - 1))))) {
1424                 _show_invalid_flash_address(flash_addr, stat);
1425                 return;
1426     }
1427     if (flash_addr_set && flash_addr & (flash_block_size-1)) {
1428                 diag_printf("Invalid FLASH address: %p\n", (void *)flash_addr);
1429                 diag_printf("   must be 0x%x aligned\n", flash_block_size);
1430                 return;
1431     }
1432     if ((mem_addr < (CYG_ADDRESS)ram_start) ||
1433                 ((mem_addr + length) >= (CYG_ADDRESS)ram_end)) {
1434                 diag_printf("** WARNING: RAM address: %p may be invalid\n", (void *)mem_addr);
1435                 diag_printf("   valid range is %p-%p\n", (void *)ram_start, (void *)ram_end);
1436     }
1437     // Safety check - make sure the address range is not within the code we're running
1438     if (flash_code_overlaps((void *)flash_addr, (void *)(flash_addr + length - 1))) {
1439                 diag_printf("Can't program this region - contains code in use!\n");
1440                 return;
1441     }
1442     if (!verify_action("* CAUTION * about to program FLASH\n            at %p..%p from %p",
1443                                            (void *)flash_addr, (void *)(flash_addr + length - 1),
1444                                            (void *)mem_addr)) {
1445                 return;  // The guy gave up
1446     }
1447     prog_ok = true;
1448     if (prog_ok) {
1449                 // Erase area to be programmed
1450                 if ((stat = flash_erase((void *)flash_addr, length, &err_addr)) != 0) {
1451                         diag_printf("Can't erase region at %p: %s\n", err_addr, flash_errmsg(stat));
1452                         prog_ok = false;
1453                 }
1454     }
1455     if (prog_ok) {
1456                 // Now program it
1457                 stat = FLASH_PROGRAM((void *)flash_addr, (void *)mem_addr, length, &err_addr);
1458                 if (stat != 0) {
1459                         diag_printf("Can't program region at %p: %s\n", err_addr, flash_errmsg(stat));
1460                         prog_ok = false;
1461                 }
1462     }
1463 }
1464
1465 static void
1466 fis_erase(int argc, char *argv[])
1467 {
1468     int stat;
1469     unsigned long length;
1470     CYG_ADDRESS flash_addr;
1471     bool flash_addr_set = false;
1472     bool length_set = false;
1473     void *err_addr;
1474     struct option_info opts[2];
1475
1476     init_opts(&opts[0], 'f', true, OPTION_ARG_TYPE_NUM,
1477                           &flash_addr, &flash_addr_set, "FLASH memory base address");
1478     init_opts(&opts[1], 'l', true, OPTION_ARG_TYPE_NUM,
1479                           &length, &length_set, "length");
1480     if (!scan_opts(argc, argv, 2, opts, 2, NULL, 0, NULL))
1481                 {
1482                         fis_usage("invalid arguments");
1483                         return;
1484                 }
1485
1486     if (!flash_addr_set || !length_set) {
1487                 fis_usage("missing argument");
1488                 return;
1489     }
1490     if (flash_addr_set &&
1491                 ((stat = flash_verify_addr((void *)flash_addr)) ||
1492                  (stat = flash_verify_addr((void *)(flash_addr + length - 1))))) {
1493                 _show_invalid_flash_address(flash_addr, stat);
1494                 return;
1495     }
1496     if (flash_addr_set && flash_addr & (flash_block_size-1)) {
1497                 diag_printf("Invalid FLASH address: %p\n", (void *)flash_addr);
1498                 diag_printf("   must be 0x%x aligned\n", flash_block_size);
1499                 return;
1500     }
1501     // Safety check - make sure the address range is not within the code we're running
1502     if (flash_code_overlaps((void *)flash_addr, (void *)(flash_addr + length - 1))) {
1503                 diag_printf("Can't erase this region - contains code in use!\n");
1504                 return;
1505     }
1506     if ((stat = flash_erase((void *)flash_addr, length, &err_addr)) != 0) {
1507                 diag_printf("Error erasing at %p: %s\n", err_addr, flash_errmsg(stat));
1508     }
1509 }
1510
1511 #ifdef CYGHWR_IO_FLASH_BLOCK_LOCKING
1512
1513 static void
1514 fis_lock(int argc, char *argv[])
1515 {
1516     char *name;
1517     int stat;
1518     unsigned long length;
1519     CYG_ADDRESS flash_addr;
1520     bool flash_addr_set = false;
1521     bool length_set = false;
1522     void *err_addr;
1523     struct option_info opts[2];
1524
1525     init_opts(&opts[0], 'f', true, OPTION_ARG_TYPE_NUM,
1526                           &flash_addr, &flash_addr_set, "FLASH memory base address");
1527     init_opts(&opts[1], 'l', true, OPTION_ARG_TYPE_NUM,
1528                           &length, &length_set, "length");
1529     if (!scan_opts(argc, argv, 2, opts, 2, &name, OPTION_ARG_TYPE_STR, "image name")) {
1530                 fis_usage("invalid arguments");
1531                 return;
1532         }
1533 #ifdef CYGOPT_REDBOOT_FIS
1534     /* Get parameters from image if specified */
1535     if (name) {
1536                 struct fis_image_desc *img;
1537                 if ((img = fis_lookup(name, NULL)) == NULL) {
1538                         diag_printf("No image '%s' found\n", name);
1539                         return;
1540                 }
1541
1542                 flash_addr = img->flash_base;
1543                 length = img->size;
1544     } else
1545 #endif
1546                 if (!flash_addr_set || !length_set) {
1547                         fis_usage("missing argument");
1548                         return;
1549                 }
1550     if (flash_addr_set &&
1551                 ((stat = flash_verify_addr((void *)flash_addr)) ||
1552                  (stat = flash_verify_addr((void *)(flash_addr + length - 1))))) {
1553                 _show_invalid_flash_address(flash_addr, stat);
1554                 return;
1555     }
1556     if ((stat = flash_lock((void *)flash_addr, length, &err_addr)) != 0) {
1557                 diag_printf("Error locking at %p: %s\n", err_addr, flash_errmsg(stat));
1558     }
1559 }
1560
1561 static void
1562 fis_unlock(int argc, char *argv[])
1563 {
1564     char *name;
1565     int stat;
1566     unsigned long length;
1567     CYG_ADDRESS flash_addr;
1568     bool flash_addr_set = false;
1569     bool length_set = false;
1570     void *err_addr;
1571     struct option_info opts[2];
1572
1573     init_opts(&opts[0], 'f', true, OPTION_ARG_TYPE_NUM,
1574                           &flash_addr, &flash_addr_set, "FLASH memory base address");
1575     init_opts(&opts[1], 'l', true, OPTION_ARG_TYPE_NUM,
1576                           &length, &length_set, "length");
1577     if (!scan_opts(argc, argv, 2, opts, 2, &name, OPTION_ARG_TYPE_STR, "image name")) {
1578                 fis_usage("invalid arguments");
1579                 return;
1580         }
1581 #ifdef CYGOPT_REDBOOT_FIS
1582     if (name) {
1583                 struct fis_image_desc *img;
1584                 if ((img = fis_lookup(name, NULL)) == NULL) {
1585                         diag_printf("No image '%s' found\n", name);
1586                         return;
1587                 }
1588
1589                 flash_addr = img->flash_base;
1590                 length = img->size;
1591     } else
1592 #endif
1593                 if (!flash_addr_set || !length_set) {
1594                         fis_usage("missing argument");
1595                         return;
1596                 }
1597     if (flash_addr_set &&
1598                 ((stat = flash_verify_addr((void *)flash_addr)) ||
1599                  (stat = flash_verify_addr((void *)(flash_addr + length - 1))))) {
1600                 _show_invalid_flash_address(flash_addr, stat);
1601                 return;
1602     }
1603
1604     if ((stat = flash_unlock((void *)flash_addr, length, &err_addr)) != 0) {
1605                 diag_printf("Error unlocking at %p: %s\n", err_addr, flash_errmsg(stat));
1606     }
1607 }
1608 #endif
1609
1610 // This is set non-zero if the FLASH subsystem has successfully been initialized
1611 int __flash_init = 0;
1612
1613 void
1614 _flash_info(void)
1615 {
1616     if (!__flash_init) return;
1617     diag_printf("FLASH: %p - 0x%x, %d blocks of 0x%08x bytes each.\n",
1618                                 flash_start, (CYG_ADDRWORD)flash_end + 1, flash_num_blocks, flash_block_size);
1619 }
1620
1621 /* Returns -1 on failure, 0 on success, 1 if it was successfull
1622  but a failed fis update was detected  */
1623 int
1624 do_flash_init(void)
1625 {
1626         int stat;
1627
1628 #ifdef CYGOPT_REDBOOT_REDUNDANT_FIS
1629         struct fis_image_desc img0;
1630         struct fis_image_desc img1;
1631         int fis_update_was_interrupted = 0;
1632         void *err_addr;
1633
1634         //check the size of fis_valid_info
1635         CYG_ASSERT((sizeof(struct fis_valid_info) <= sizeof(img0.u.name)),
1636                            "fis_valid_info size mismatch");
1637         //try to check the alignment of version_count
1638         CYG_ASSERT(((&img0.u.valid_info.version_count - &img0) % sizeof(unsigned long) == 0),
1639                            "alignment problem");
1640 #endif
1641         if (!__flash_init) {
1642                 __flash_init = 1;
1643                 if ((stat = flash_init(diag_printf)) != 0) {
1644                         diag_printf("FLASH: driver init failed: %s\n", flash_errmsg(stat));
1645                         return -1;
1646                 }
1647                 flash_get_limits(NULL, &flash_start, &flash_end);
1648                 // Keep 'end' address as last valid location, to avoid wrap around problems
1649                 flash_end = (void *)((CYG_ADDRESS)flash_end - 1);
1650                 flash_get_block_info(&flash_block_size, &flash_num_blocks);
1651 #ifdef CYGOPT_REDBOOT_FIS
1652                 fisdir_size = CYGNUM_REDBOOT_FIS_DIRECTORY_ENTRY_COUNT * CYGNUM_REDBOOT_FIS_DIRECTORY_ENTRY_SIZE;
1653                 fisdir_size = ((fisdir_size + flash_block_size - 1) / flash_block_size) * flash_block_size;
1654 # if defined(CYGPRI_REDBOOT_ZLIB_FLASH) && defined(CYGOPT_REDBOOT_FIS_ZLIB_COMMON_BUFFER)
1655                 fis_work_block = fis_zlib_common_buffer;
1656                 if (CYGNUM_REDBOOT_FIS_ZLIB_COMMON_BUFFER_SIZE < fisdir_size) {
1657                         diag_printf("FLASH: common buffer too small\n");
1658                         return -1;
1659                 }
1660 # else
1661                 workspace_end = (unsigned char *)(workspace_end - fisdir_size);
1662                 fis_work_block = workspace_end;
1663 # endif
1664                 if (CYGNUM_REDBOOT_FIS_DIRECTORY_BLOCK < 0) {
1665                         fis_addr = (void *)((CYG_ADDRESS)flash_end + 1 +
1666                                                                 (CYGNUM_REDBOOT_FIS_DIRECTORY_BLOCK * flash_block_size));
1667                 } else {
1668                         fis_addr = (void *)((CYG_ADDRESS)flash_start +
1669                                                                 (CYGNUM_REDBOOT_FIS_DIRECTORY_BLOCK * flash_block_size));
1670                 }
1671 #if defined(CYGHWR_DEVS_FLASH_MXC_MULTI) && defined(MXCFLASH_SELECT_NAND)
1672                 extern int mxc_nand_fis_start(void);
1673                 if (IS_FIS_FROM_NAND()) {
1674                         fis_addr = (void *)((CYG_ADDRESS)flash_start + mxc_nand_fis_start());
1675                 }
1676 #endif
1677
1678 #if defined(IMXFLASH_SELECT_SPI_NOR)
1679                 extern int mxc_spi_nor_fis_start(void);
1680                 if (IS_FIS_FROM_SPI_NOR()) {
1681                         fis_addr = (void *)((CYG_ADDRESS)flash_start + mxc_spi_nor_fis_start());
1682                 }
1683 #endif
1684
1685 #if defined(MXCFLASH_SELECT_MMC)
1686                 if (IS_FIS_FROM_MMC()) {
1687                         fis_addr = (void *)REDBOOT_IMAGE_SIZE;
1688                 }
1689 #endif
1690
1691                 if (((CYG_ADDRESS)fis_addr + fisdir_size - 1) > (CYG_ADDRESS)flash_end) {
1692                         diag_printf("FIS directory doesn't fit\n");
1693                         return -1;
1694                 }
1695 #ifdef CYGOPT_REDBOOT_REDUNDANT_FIS
1696
1697                 if (CYGNUM_REDBOOT_FIS_REDUNDANT_DIRECTORY_BLOCK < 0) {
1698                         redundant_fis_addr = (void *)((CYG_ADDRESS)flash_end + 1 +
1699                                                                                   (CYGNUM_REDBOOT_FIS_REDUNDANT_DIRECTORY_BLOCK *
1700                                                                                    flash_block_size));
1701                 } else {
1702                         redundant_fis_addr = (void *)((CYG_ADDRESS)flash_start +
1703                                                                                   (CYGNUM_REDBOOT_FIS_REDUNDANT_DIRECTORY_BLOCK *
1704                                                                                    flash_block_size));
1705                 }
1706
1707                 if (((CYG_ADDRESS)redundant_fis_addr + fisdir_size - 1) > (CYG_ADDRESS)flash_end) {
1708                         diag_printf("Redundant FIS directory doesn't fit\n");
1709                         return -1;
1710                 }
1711                 FLASH_READ(fis_addr, &img0, sizeof(img0), &err_addr);
1712                 FLASH_READ(redundant_fis_addr, &img1, sizeof(img1), &err_addr);
1713
1714                 if (strncmp(img0.u.valid_info.magic_name, CYG_REDBOOT_RFIS_VALID_MAGIC,
1715                                         CYG_REDBOOT_RFIS_VALID_MAGIC_LENGTH) != 0) {
1716                                 memset(&img0, 0, sizeof(img0));
1717                         }
1718
1719                 if (strncmp(img1.u.valid_info.magic_name, CYG_REDBOOT_RFIS_VALID_MAGIC,
1720                                         CYG_REDBOOT_RFIS_VALID_MAGIC_LENGTH) != 0) {
1721                         memset(&img1, 0, sizeof(img0));
1722                 }
1723
1724 #ifdef REDBOOT_FLASH_REVERSE_BYTEORDER
1725                 img0.u.valid_info.version_count = CYG_SWAP32(img0.u.valid_info.version_count);
1726                 img1.u.valid_info.version_count = CYG_SWAP32(img1.u.valid_info.version_count);
1727 #endif
1728
1729                 if (fis_get_valid_buf(&img0, &img1, &fis_update_was_interrupted) == 1) {
1730                         // Valid, so swap primary and secondary
1731                         void *tmp;
1732                         tmp = fis_addr;
1733                         fis_addr = redundant_fis_addr;
1734                         redundant_fis_addr = tmp;
1735                 }
1736 #endif
1737                 fis_read_directory();
1738 #endif
1739         }
1740 #ifdef CYGOPT_REDBOOT_REDUNDANT_FIS
1741         if (fis_update_was_interrupted)
1742                 return 1;
1743         else
1744                 return 0;
1745 #else
1746         return 0;
1747 #endif
1748 }
1749
1750 // Wrapper to avoid compiler warnings
1751 static void
1752 _do_flash_init(void)
1753 {
1754     static int init_done = 0;
1755     if (init_done) return;
1756     init_done = 1;
1757     do_flash_init();
1758 }
1759
1760 RedBoot_init(_do_flash_init, RedBoot_INIT_FIRST);
1761
1762 static void
1763 do_fis(int argc, char *argv[])
1764 {
1765     struct cmd *cmd;
1766
1767     if (argc < 2) {
1768                 fis_usage("too few arguments");
1769                 return;
1770     }
1771     if (do_flash_init() < 0) {
1772         diag_printf("Sorry, no FLASH memory is available\n");
1773         return;
1774     }
1775     if ((cmd = cmd_search(__FIS_cmds_TAB__, &__FIS_cmds_TAB_END__,
1776                           argv[1])) != NULL) {
1777                 (cmd->fun)(argc, argv);
1778                 return;
1779     }
1780     fis_usage("unrecognized command");
1781 }