OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [ecos-3.0/] [packages/] [redboot/] [current/] [src/] [flash.c] - Blame information for rev 838

Go to most recent revision | Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.