]> git.kernelconcepts.de Git - karo-tx-redboot.git/blob - packages/redboot/v2_0/src/flash.c
TX51 pre-release
[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 }