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