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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [ecos-2.0/] [packages/] [redboot/] [v2_0/] [src/] [flash.c] - Blame information for rev 773

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

Line No. Rev Author Line
1 27 unneback
//==========================================================================
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 Red Hat, 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 version.
16
//
17
// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
18
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
19
// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
20
// for more details.
21
//
22
// You should have received a copy of the GNU General Public License along
23
// with eCos; if not, write to the Free Software Foundation, Inc.,
24
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
25
//
26
// As a special exception, if other files instantiate templates or use macros
27
// or inline functions from this file, or you compile this file and link it
28
// with other works to produce a work based on this file, this file does not
29
// by itself cause the resulting work to be covered by the GNU General Public
30
// License. However the source code for this file must still be made available
31
// in accordance with section (3) of the GNU General Public License.
32
//
33
// This exception does not invalidate any other reasons why a work based on
34
// this file might be covered by the GNU General Public License.
35
//
36
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
37
// at http://sources.redhat.com/ecos/ecos-license/
38
// -------------------------------------------
39
//####ECOSGPLCOPYRIGHTEND####
40
//==========================================================================
41
//#####DESCRIPTIONBEGIN####
42
//
43
// Author(s):    gthomas
44
// Contributors: gthomas, tkoeller
45
// Date:         2000-07-28
46
// Purpose:      
47
// Description:  
48
//              
49
// This code is part of RedBoot (tm).
50
//
51
//####DESCRIPTIONEND####
52
//
53
//==========================================================================
54
 
55
#include <redboot.h>
56
#include <cyg/io/flash.h>
57
#include <fis.h>
58
#include <sib.h>
59
 
60
#ifdef CYGSEM_REDBOOT_FLASH_COMBINED_FIS_AND_CONFIG
61
// Note horrid intertwining of functions, to save precious FLASH
62
#endif
63
 
64
// Round a quantity up
65
#define _rup(n,s) ((((n)+(s-1))/s)*s)
66
 
67
#ifdef CYGSEM_REDBOOT_FLASH_CONFIG
68
#include <flash_config.h>
69
 
70
// Configuration data, saved in FLASH, used to set/update RedBoot
71
// normal "configuration" data items.
72
static struct _config {
73
    unsigned long len;
74
    unsigned long key1;
75
    unsigned char config_data[MAX_CONFIG_DATA-(4*4)];
76
    unsigned long key2;
77
    unsigned long cksum;
78
} *config, *backup_config;
79
#ifdef CYGSEM_REDBOOT_FLASH_CONFIG_READONLY_FALLBACK
80
static struct _config  *readonly_config;
81
#endif
82
#endif
83
 
84
#ifdef CYGOPT_REDBOOT_FIS
85
// Image management functions
86
local_cmd_entry("init",
87
                "Initialize FLASH Image System [FIS]",
88
                "[-f]",
89
                fis_init,
90
                FIS_cmds
91
    );
92
#ifdef CYGSEM_REDBOOT_FIS_CRC_CHECK
93
# define FIS_LIST_OPTS "[-c] [-d]"
94
#else
95
# define FIS_LIST_OPTS "[-d]"
96
#endif
97
local_cmd_entry("list",
98
                "Display contents of FLASH Image System [FIS]",
99
                FIS_LIST_OPTS,
100
                fis_list,
101
                FIS_cmds
102
    );
103
local_cmd_entry("free",
104
                "Display free [available] locations within FLASH Image System [FIS]",
105
                "",
106
                fis_free,
107
                FIS_cmds
108
    );
109
local_cmd_entry("delete",
110
                "Delete an image from FLASH Image System [FIS]",
111
                "name",
112
                fis_delete,
113
                FIS_cmds
114
    );
115
 
116
static char fis_load_usage[] =
117
#ifdef CYGPKG_COMPRESS_ZLIB
118
                      "[-d] "
119
#endif
120
                      "[-b <memory_load_address>] [-c] name";
121
 
122
local_cmd_entry("load",
123
                "Load image from FLASH Image System [FIS] into RAM",
124
                fis_load_usage,
125
                fis_load,
126
                FIS_cmds
127
    );
128
local_cmd_entry("create",
129
                "Create an image",
130
                "-b <mem_base> -l <image_length> [-s <data_length>]\n"
131
                "      [-f <flash_addr>] [-e <entry_point>] [-r <ram_addr>] [-n] <name>",
132
                fis_create,
133
                FIS_cmds
134
    );
135
#endif
136
 
137
// Raw flash access functions
138
local_cmd_entry("erase",
139
                "Erase FLASH contents",
140
                "-f <flash_addr> -l <length>",
141
                fis_erase,
142
                FIS_cmds
143
    );
144
#ifdef CYGHWR_IO_FLASH_BLOCK_LOCKING
145
local_cmd_entry("lock",
146
                "LOCK FLASH contents",
147
                "[-f <flash_addr> -l <length>] [name]",
148
                fis_lock,
149
                FIS_cmds
150
    );
151
local_cmd_entry("unlock",
152
                "UNLOCK FLASH contents",
153
                "[-f <flash_addr> -l <length>] [name]",
154
                fis_unlock,
155
                FIS_cmds
156
    );
157
#endif
158
local_cmd_entry("write",
159
                "Write raw data directly to FLASH",
160
                "-f <flash_addr> -b <mem_base> -l <image_length>",
161
                fis_write,
162
                FIS_cmds
163
    );
164
 
165
// Define table boundaries
166
CYG_HAL_TABLE_BEGIN( __FIS_cmds_TAB__, FIS_cmds);
167
CYG_HAL_TABLE_END( __FIS_cmds_TAB_END__, FIS_cmds);
168
 
169
extern struct cmd __FIS_cmds_TAB__[], __FIS_cmds_TAB_END__;
170
 
171
// CLI function
172
static cmd_fun do_fis;
173
RedBoot_nested_cmd("fis",
174
            "Manage FLASH images",
175
            "{cmds}",
176
            do_fis,
177
            __FIS_cmds_TAB__, &__FIS_cmds_TAB_END__
178
    );
179
 
180
// Local data used by these routines
181
static void *flash_start, *flash_end;
182
static int flash_block_size, flash_num_blocks;
183
#ifdef CYGOPT_REDBOOT_FIS
184
static void *fis_work_block;
185
static void *fis_addr;
186
static int fisdir_size;  // Size of FIS directory.
187
#endif
188
#ifdef CYGSEM_REDBOOT_FLASH_CONFIG
189
static void *cfg_base;   // Location in Flash of config data
190
static int   cfg_size;   // Length of config data - rounded to Flash block size
191
// Prototypes for local functions
192
static unsigned char *flash_lookup_config(char *key);
193
#endif
194
 
195
static void
196
fis_usage(char *why)
197
{
198
    diag_printf("*** invalid 'fis' command: %s\n", why);
199
    cmd_usage(__FIS_cmds_TAB__, &__FIS_cmds_TAB_END__, "fis ");
200
}
201
 
202
static void
203
_show_invalid_flash_address(CYG_ADDRESS flash_addr, int stat)
204
{
205
    diag_printf("Invalid FLASH address %p: %s\n", (void *)flash_addr, flash_errmsg(stat));
206
    diag_printf("   valid range is %p-%p\n", (void *)flash_start, (void *)flash_end);
207
}
208
 
209
#ifdef CYGOPT_REDBOOT_FIS
210
struct fis_image_desc *
211
fis_lookup(char *name, int *num)
212
{
213
    int i;
214
    struct fis_image_desc *img;
215
 
216
    img = (struct fis_image_desc *)fis_work_block;
217
    for (i = 0;  i < fisdir_size/sizeof(*img);  i++, img++) {
218
        if ((img->name[0] != (unsigned char)0xFF) &&
219
            (strcasecmp(name, img->name) == 0)) {
220
            if (num) *num = i;
221
            return img;
222
        }
223
    }
224
    return (struct fis_image_desc *)0;
225
}
226
 
227
static void
228
fis_update_directory(void)
229
{
230
    int stat;
231
    void *err_addr;
232
 
233
#ifdef CYGSEM_REDBOOT_FLASH_COMBINED_FIS_AND_CONFIG
234
    memcpy((char *)fis_work_block+fisdir_size, config, cfg_size);
235
#endif
236
#ifdef CYGSEM_REDBOOT_FLASH_LOCK_SPECIAL
237
    // Ensure [quietly] that the directory is unlocked before trying to update
238
    flash_unlock((void *)fis_addr, flash_block_size, (void **)&err_addr);
239
#endif
240
    if ((stat = flash_erase(fis_addr, flash_block_size, (void **)&err_addr)) != 0) {
241
        diag_printf("Error erasing FIS directory at %p: %s\n", err_addr, flash_errmsg(stat));
242
    } else {
243
        if ((stat = flash_program(fis_addr, fis_work_block, flash_block_size,
244
                                  (void **)&err_addr)) != 0) {
245
            diag_printf("Error writing FIS directory at %p: %s\n",
246
                        err_addr, flash_errmsg(stat));
247
        }
248
    }
249
#ifdef CYGSEM_REDBOOT_FLASH_LOCK_SPECIAL
250
    // Ensure [quietly] that the directory is locked after the update
251
    flash_lock((void *)fis_addr, flash_block_size, (void **)&err_addr);
252
#endif
253
}
254
 
255
static void
256
fis_init(int argc, char *argv[])
257
{
258
    int stat;
259
    struct fis_image_desc *img;
260
    void *err_addr;
261
    bool full_init = false;
262
    struct option_info opts[1];
263
    CYG_ADDRESS redboot_flash_start;
264
    unsigned long redboot_image_size;
265
 
266
    init_opts(&opts[0], 'f', false, OPTION_ARG_TYPE_FLG,
267
              (void **)&full_init, (bool *)0, "full initialization, erases all of flash");
268
    if (!scan_opts(argc, argv, 2, opts, 1, 0, 0, ""))
269
    {
270
        return;
271
    }
272
 
273
    if (!verify_action("About to initialize [format] FLASH image system")) {
274
        diag_printf("** Aborted\n");
275
        return;
276
    }
277
    diag_printf("*** Initialize FLASH Image System\n");
278
 
279
#define MIN_REDBOOT_IMAGE_SIZE CYGBLD_REDBOOT_MIN_IMAGE_SIZE
280
    redboot_image_size = flash_block_size > MIN_REDBOOT_IMAGE_SIZE ?
281
                         flash_block_size : MIN_REDBOOT_IMAGE_SIZE;
282
 
283
    // Create a pseudo image for RedBoot
284
    img = (struct fis_image_desc *)fis_work_block;
285
    memset(img, 0xFF, fisdir_size);  // Start with erased data
286
#ifdef CYGOPT_REDBOOT_FIS_RESERVED_BASE
287
    memset(img, 0, sizeof(*img));
288
    strcpy(img->name, "(reserved)");
289
    img->flash_base = (CYG_ADDRESS)flash_start;
290
    img->mem_base = (CYG_ADDRESS)flash_start;
291
    img->size = CYGNUM_REDBOOT_FLASH_RESERVED_BASE;
292
    img++;
293
#endif
294
    redboot_flash_start = (CYG_ADDRESS)flash_start + CYGBLD_REDBOOT_FLASH_BOOT_OFFSET;
295
#ifdef CYGOPT_REDBOOT_FIS_REDBOOT
296
    memset(img, 0, sizeof(*img));
297
    strcpy(img->name, "RedBoot");
298
    img->flash_base = redboot_flash_start;
299
    img->mem_base = redboot_flash_start;
300
    img->size = redboot_image_size;
301
    img++;
302
    redboot_flash_start += redboot_image_size;
303
#endif
304
#ifdef CYGOPT_REDBOOT_FIS_REDBOOT_POST
305
#ifdef CYGNUM_REDBOOT_FIS_REDBOOT_POST_OFFSET
306
    // Take care to place the POST entry at the right offset:
307
    redboot_flash_start = (CYG_ADDRESS)flash_start + CYGNUM_REDBOOT_FIS_REDBOOT_POST_OFFSET;
308
#endif
309
    memset(img, 0, sizeof(*img));
310
    strcpy(img->name, "RedBoot[post]");
311
    img->flash_base = redboot_flash_start;
312
    img->mem_base = redboot_flash_start;
313
    img->size = redboot_image_size;
314
    img++;
315
    redboot_flash_start += redboot_image_size;
316
#endif
317
#ifdef CYGOPT_REDBOOT_FIS_REDBOOT_BACKUP
318
    // And a backup image
319
    memset(img, 0, sizeof(*img));
320
    strcpy(img->name, "RedBoot[backup]");
321
    img->flash_base = redboot_flash_start;
322
    img->mem_base = redboot_flash_start;
323
    img->size = redboot_image_size;
324
    img++;
325
    redboot_flash_start += redboot_image_size;
326
#endif
327
#ifdef CYGSEM_REDBOOT_FLASH_CONFIG
328
    // And a descriptor for the configuration data
329
    memset(img, 0, sizeof(*img));
330
    strcpy(img->name, "RedBoot config");
331
    img->flash_base = (CYG_ADDRESS)cfg_base;
332
    img->mem_base = (CYG_ADDRESS)cfg_base;
333
    img->size = cfg_size;
334
    img++;
335
#endif
336
    // And a descriptor for the descriptor table itself
337
    memset(img, 0, sizeof(*img));
338
    strcpy(img->name, "FIS directory");
339
    img->flash_base = (CYG_ADDRESS)fis_addr;
340
    img->mem_base = (CYG_ADDRESS)fis_addr;
341
    img->size = fisdir_size;
342
    img++;
343
 
344
#ifdef CYGOPT_REDBOOT_FIS_DIRECTORY_ARM_SIB_ID
345
    // FIS gets the size of a full block - note, this should be changed
346
    // if support is added for multi-block FIS structures.
347
    img = (struct fis_image_desc *)((CYG_ADDRESS)fis_work_block + fisdir_size);
348
    // Add a footer so the FIS will be recognized by the ARM Boot
349
    // Monitor as a reserved area.
350
    {
351
        tFooter* footer_p = (tFooter*)((CYG_ADDRESS)img - sizeof(tFooter));
352
        cyg_uint32 check = 0;
353
        cyg_uint32 *check_ptr = (cyg_uint32 *)footer_p;
354
        cyg_int32 count = (sizeof(tFooter) - 4) >> 2;
355
 
356
        // Prepare footer. Try to protect all but the reserved space
357
        // and the first RedBoot image (which is expected to be
358
        // bootable), but fall back to just protecting the FIS if it's
359
        // not at the default position in the flash.
360
#if defined(CYGOPT_REDBOOT_FIS_RESERVED_BASE) && (-1 == CYGNUM_REDBOOT_FIS_DIRECTORY_BLOCK)
361
        footer_p->blockBase = (char*)_ADDR_REDBOOT_TO_ARM(flash_start);
362
        footer_p->blockBase += CYGNUM_REDBOOT_FLASH_RESERVED_BASE + redboot_image_size;
363
#else
364
        footer_p->blockBase = (char*)_ADDR_REDBOOT_TO_ARM(fis_work_block);
365
#endif
366
        footer_p->infoBase = NULL;
367
        footer_p->signature = FLASH_FOOTER_SIGNATURE;
368
        footer_p->type = TYPE_REDHAT_REDBOOT;
369
 
370
        // and compute its checksum
371
        for ( ; count > 0; count--) {
372
            if (*check_ptr > ~check)
373
                check++;
374
            check += *check_ptr++;
375
        }
376
        footer_p->checksum = ~check;
377
    }
378
#endif
379
 
380
    // Do this after creating the initialized table because that inherently
381
    // calculates where the high water mark of default RedBoot images is.
382
 
383
    if (full_init) {
384
        unsigned long erase_size;
385
        CYG_ADDRESS erase_start;
386
        // Erase everything except default RedBoot images, fis block, 
387
        // and config block.
388
        // First deal with the possible first part, before RedBoot images:
389
#if (CYGBLD_REDBOOT_FLASH_BOOT_OFFSET > CYGNUM_REDBOOT_FLASH_RESERVED_BASE)
390
        erase_start = (CYG_ADDRESS)flash_start + CYGNUM_REDBOOT_FLASH_RESERVED_BASE;
391
        erase_size =  (CYG_ADDRESS)flash_start + CYGBLD_REDBOOT_FLASH_BOOT_OFFSET;
392
        if ( erase_size > erase_start ) {
393
            erase_size -= erase_start;
394
            if ((stat = flash_erase((void *)erase_start, erase_size,
395
                                    (void **)&err_addr)) != 0) {
396
                diag_printf("   initialization failed at %p: %s\n",
397
                            err_addr, flash_errmsg(stat));
398
            }
399
        }
400
#endif
401
        // second deal with the larger part in the main:
402
        erase_start = redboot_flash_start; // high water of created images
403
        // Now the empty bits between the end of Redboot and the cfg and dir 
404
        // blocks. 
405
#if defined(CYGSEM_REDBOOT_FLASH_CONFIG) && !defined(CYGSEM_REDBOOT_FLASH_COMBINED_FIS_AND_CONFIG)
406
        if (fis_addr > cfg_base) {
407
          erase_size = (CYG_ADDRESS)cfg_base - erase_start; // the gap between HWM and config data
408
        } else {
409
          erase_size = (CYG_ADDRESS)fis_addr - erase_start; // the gap between HWM and fis data
410
        }
411
        if ((stat = flash_erase((void *)erase_start, erase_size,
412
                                (void **)&err_addr)) != 0) {
413
          diag_printf("   initialization failed %p: %s\n",
414
                 err_addr, flash_errmsg(stat));
415
        }
416
        erase_start += (erase_size + flash_block_size);
417
        if (fis_addr > cfg_base) {
418
          erase_size = (CYG_ADDRESS)fis_addr - erase_start; // the gap between config and fis data
419
        } else {
420
          erase_size = (CYG_ADDRESS)cfg_base - erase_start; // the gap between fis and config data
421
        }
422
        if ((stat = flash_erase((void *)erase_start, erase_size,
423
                                (void **)&err_addr)) != 0) {
424
          diag_printf("   initialization failed %p: %s\n",
425
                 err_addr, flash_errmsg(stat));
426
        }
427
        erase_start += (erase_size + flash_block_size);
428
#else  // !CYGSEM_REDBOOT_FLASH_CONFIG        
429
        erase_size = (CYG_ADDRESS)fis_addr - erase_start; // the gap between HWM and fis data
430
        if ((stat = flash_erase((void *)erase_start, erase_size,
431
                                (void **)&err_addr)) != 0) {
432
          diag_printf("   initialization failed %p: %s\n",
433
                 err_addr, flash_errmsg(stat));
434
        }
435
        erase_start += (erase_size + flash_block_size);
436
#endif
437
        // Lastly, anything at the end
438
        erase_size = ((CYG_ADDRESS)flash_end - erase_start) + 1;
439
        if ((stat = flash_erase((void *)erase_start, erase_size,
440
                                (void **)&err_addr)) != 0) {
441
            diag_printf("   initialization failed at %p: %s\n",
442
                        err_addr, flash_errmsg(stat));
443
        }
444
    } else {
445
        diag_printf("    Warning: device contents not erased, some blocks may not be usable\n");
446
    }
447
 
448
    fis_update_directory();
449
}
450
 
451
static void
452
fis_list(int argc, char *argv[])
453
{
454
    struct fis_image_desc *img;
455
    int i;
456
    bool show_cksums = false;
457
    bool show_datalen = false;
458
    struct option_info opts[2];
459
 
460
#ifdef CYGHWR_REDBOOT_ARM_FLASH_SIB
461
    // FIXME: this is somewhat half-baked
462
    extern void arm_fis_list(void);
463
    arm_fis_list();
464
    return;
465
#endif
466
 
467
    init_opts(&opts[0], 'd', false, OPTION_ARG_TYPE_FLG,
468
              (void **)&show_datalen, (bool *)0, "display data length");
469
#ifdef CYGSEM_REDBOOT_FIS_CRC_CHECK
470
    init_opts(&opts[1], 'c', false, OPTION_ARG_TYPE_FLG,
471
              (void **)&show_cksums, (bool *)0, "display checksums");
472
    i = 2;
473
#else
474
    i = 1;
475
#endif
476
    if (!scan_opts(argc, argv, 2, opts, i, 0, 0, ""))
477
    {
478
        return;
479
    }
480
    img = (struct fis_image_desc *) fis_addr;
481
    // Let diag_printf do the formatting in both cases, rather than counting
482
    // cols by hand....
483
    diag_printf("%-16s  %-10s  %-10s  %-10s  %-s\n",
484
                "Name","FLASH addr",
485
                show_cksums ? "Checksum" : "Mem addr",
486
                show_datalen ? "Datalen" : "Length",
487
                "Entry point" );
488
    for (i = 0;  i < fisdir_size/sizeof(*img);  i++, img++) {
489
        if (img->name[0] != (unsigned char)0xFF) {
490
            diag_printf("%-16s  0x%08lX  0x%08lX  0x%08lX  0x%08lX\n", img->name,
491
                        img->flash_base,
492
#ifdef CYGSEM_REDBOOT_FIS_CRC_CHECK
493
                        show_cksums ? img->file_cksum : img->mem_base,
494
                        show_datalen ? img->data_length : img->size,
495
#else
496
                        img->mem_base,
497
                        img->size,
498
#endif
499
                        img->entry_point);
500
        }
501
    }
502
}
503
 
504
static void
505
fis_free(int argc, char *argv[])
506
{
507
    unsigned long *fis_ptr, *fis_end;
508
    unsigned long *area_start;
509
 
510
    // Do not search the area reserved for pre-RedBoot systems:
511
    fis_ptr = (unsigned long *)((CYG_ADDRESS)flash_start + CYGNUM_REDBOOT_FLASH_RESERVED_BASE);
512
    fis_end = (unsigned long *)(CYG_ADDRESS)flash_end;
513
    area_start = fis_ptr;
514
    while (fis_ptr < fis_end) {
515
        if (*fis_ptr != (unsigned long)0xFFFFFFFF) {
516
            if (area_start != fis_ptr) {
517
                // Assume that this is something
518
                diag_printf("  0x%08lX .. 0x%08lX\n",
519
                            (CYG_ADDRESS)area_start, (CYG_ADDRESS)fis_ptr);
520
            }
521
            // Find next blank block
522
            area_start = fis_ptr;
523
            while (area_start < fis_end) {
524
                if (*area_start == (unsigned long)0xFFFFFFFF) {
525
                    break;
526
                }
527
                area_start += flash_block_size / sizeof(CYG_ADDRESS);
528
            }
529
            fis_ptr = area_start;
530
        } else {
531
            fis_ptr += flash_block_size / sizeof(CYG_ADDRESS);
532
        }
533
    }
534
    if (area_start != fis_ptr) {
535
        diag_printf("  0x%08lX .. 0x%08lX\n",
536
                    (CYG_ADDRESS)area_start, (CYG_ADDRESS)fis_ptr);
537
    }
538
}
539
 
540
// Find the first unused area of flash which is long enough
541
static bool
542
fis_find_free(CYG_ADDRESS *addr, unsigned long length)
543
{
544
    unsigned long *fis_ptr, *fis_end;
545
    unsigned long *area_start;
546
 
547
    // Do not search the area reserved for pre-RedBoot systems:
548
    fis_ptr = (unsigned long *)((CYG_ADDRESS)flash_start + CYGNUM_REDBOOT_FLASH_RESERVED_BASE);
549
    fis_end = (unsigned long *)(CYG_ADDRESS)flash_end;
550
    area_start = fis_ptr;
551
    while (fis_ptr < fis_end) {
552
        if (*fis_ptr != (unsigned long)0xFFFFFFFF) {
553
            if (area_start != fis_ptr) {
554
                // Assume that this is something
555
                if ((fis_ptr-area_start) >= (length/sizeof(unsigned))) {
556
                    *addr = (CYG_ADDRESS)area_start;
557
                    return true;
558
                }
559
            }
560
            // Find next blank block
561
            area_start = fis_ptr;
562
            while (area_start < fis_end) {
563
                if (*area_start == (unsigned long)0xFFFFFFFF) {
564
                    break;
565
                }
566
                area_start += flash_block_size / sizeof(CYG_ADDRESS);
567
            }
568
            fis_ptr = area_start;
569
        } else {
570
            fis_ptr += flash_block_size / sizeof(CYG_ADDRESS);
571
        }
572
    }
573
    if (area_start != fis_ptr) {
574
        if ((fis_ptr-area_start) >= (length/sizeof(unsigned))) {
575
            *addr = (CYG_ADDRESS)area_start;
576
            return true;
577
        }
578
    }
579
    return false;
580
}
581
 
582
static void
583
fis_create(int argc, char *argv[])
584
{
585
    int i, stat;
586
    unsigned long length, img_size;
587
    CYG_ADDRESS mem_addr, exec_addr, flash_addr, entry_addr;
588
    char *name;
589
    bool mem_addr_set = false;
590
    bool exec_addr_set = false;
591
    bool entry_addr_set = false;
592
    bool flash_addr_set = false;
593
    bool length_set = false;
594
    bool img_size_set = false;
595
    bool no_copy = false;
596
    void *err_addr;
597
    struct fis_image_desc *img = NULL;
598
    bool defaults_assumed;
599
    struct option_info opts[7];
600
    bool prog_ok = true;
601
 
602
    init_opts(&opts[0], 'b', true, OPTION_ARG_TYPE_NUM,
603
              (void **)&mem_addr, (bool *)&mem_addr_set, "memory base address");
604
    init_opts(&opts[1], 'r', true, OPTION_ARG_TYPE_NUM,
605
              (void **)&exec_addr, (bool *)&exec_addr_set, "ram base address");
606
    init_opts(&opts[2], 'e', true, OPTION_ARG_TYPE_NUM,
607
              (void **)&entry_addr, (bool *)&entry_addr_set, "entry point address");
608
    init_opts(&opts[3], 'f', true, OPTION_ARG_TYPE_NUM,
609
              (void **)&flash_addr, (bool *)&flash_addr_set, "FLASH memory base address");
610
    init_opts(&opts[4], 'l', true, OPTION_ARG_TYPE_NUM,
611
              (void **)&length, (bool *)&length_set, "image length [in FLASH]");
612
    init_opts(&opts[5], 's', true, OPTION_ARG_TYPE_NUM,
613
              (void **)&img_size, (bool *)&img_size_set, "image size [actual data]");
614
    init_opts(&opts[6], 'n', false, OPTION_ARG_TYPE_FLG,
615
              (void **)&no_copy, (bool *)0, "don't copy from RAM to FLASH, just update directory");
616
    if (!scan_opts(argc, argv, 2, opts, 7, (void *)&name, OPTION_ARG_TYPE_STR, "file name"))
617
    {
618
        fis_usage("invalid arguments");
619
        return;
620
    }
621
 
622
    memcpy(fis_work_block, fis_addr, fisdir_size);
623
    defaults_assumed = false;
624
    if (name) {
625
        // Search existing files to acquire defaults for params not specified:
626
        img = fis_lookup(name, NULL);
627
        if (img) {
628
            // Found it, so get image size from there
629
            if (!length_set) {
630
                length_set = true;
631
                length = img->size;
632
                defaults_assumed = true;
633
            }
634
        }
635
    }
636
    if (!mem_addr_set && (load_address >= (CYG_ADDRESS)ram_start) &&
637
        (load_address_end) < (CYG_ADDRESS)ram_end) {
638
        mem_addr = load_address;
639
        mem_addr_set = true;
640
        defaults_assumed = true;
641
        // Get entry address from loader, unless overridden
642
        if (!entry_addr_set)
643
            entry_addr = entry_address;
644
        if (!length_set) {
645
            length = load_address_end - load_address;
646
            length_set = true;
647
        } else if (defaults_assumed && !img_size_set) {
648
            /* We got length from the FIS table, so the size of the
649
               actual loaded image becomes img_size */
650
            img_size = load_address_end - load_address;
651
            img_size_set = true;
652
        }
653
    }
654
    // Get the remaining fall-back values from the fis
655
    if (img) {
656
        if (!exec_addr_set) {
657
            // Preserve "normal" behaviour
658
            exec_addr_set = true;
659
            exec_addr = flash_addr_set ? flash_addr : mem_addr;
660
        }
661
        if (!flash_addr_set) {
662
            flash_addr_set = true;
663
            flash_addr = img->flash_base;
664
            defaults_assumed = true;
665
        }
666
    }
667
 
668
    if ((!no_copy && !mem_addr_set) || (no_copy && !flash_addr_set) ||
669
        !length_set || !name) {
670
        fis_usage("required parameter missing");
671
        return;
672
    }
673
    if (!img_size_set) {
674
        img_size = length;
675
    }
676
    // 'length' is size of FLASH image, 'img_size' is actual data size
677
    // Round up length to FLASH block size
678
#ifndef CYGPKG_HAL_MIPS // FIXME: compiler is b0rken
679
    length = ((length + flash_block_size - 1) / flash_block_size) * flash_block_size;
680
    if (length < img_size) {
681
        diag_printf("Invalid FLASH image size/length combination\n");
682
        return;
683
    }
684
#endif
685
    if (flash_addr_set &&
686
        ((stat = flash_verify_addr((void *)flash_addr)) ||
687
         (stat = flash_verify_addr((void *)(flash_addr+img_size-1))))) {
688
        _show_invalid_flash_address(flash_addr, stat);
689
        return;
690
    }
691
    if (flash_addr_set && flash_addr & (flash_block_size-1)) {
692
        diag_printf("Invalid FLASH address: %p\n", (void *)flash_addr);
693
        diag_printf("   must be 0x%x aligned\n", flash_block_size);
694
        return;
695
    }
696
    if (strlen(name) >= sizeof(img->name)) {
697
        diag_printf("Name is too long, must be less than %d chars\n", (int)sizeof(img->name));
698
        return;
699
    }
700
    if (!no_copy) {
701
        if ((mem_addr < (CYG_ADDRESS)ram_start) ||
702
            ((mem_addr+img_size) >= (CYG_ADDRESS)ram_end)) {
703
            diag_printf("** WARNING: RAM address: %p may be invalid\n", (void *)mem_addr);
704
            diag_printf("   valid range is %p-%p\n", (void *)ram_start, (void *)ram_end);
705
        }
706
        if (!flash_addr_set && !fis_find_free(&flash_addr, length)) {
707
            diag_printf("Can't locate %lx(%ld) bytes free in FLASH\n", length, length);
708
            return;
709
        }
710
    }
711
    // First, see if the image by this name has agreable properties
712
    if (img) {
713
        if (flash_addr_set && (img->flash_base != flash_addr)) {
714
            diag_printf("Image found, but flash address (%p)\n"
715
                        "             is incorrect (present image location %p)\n",
716
                        flash_addr, img->flash_base);
717
 
718
            return;
719
        }
720
        if (img->size != length) {
721
            diag_printf("Image found, but length (0x%lx, necessitating image size 0x%lx)\n"
722
                        "             is incorrect (present image size 0x%lx)\n",
723
                        img_size, length, img->size);
724
            return;
725
        }
726
        if (!verify_action("An image named '%s' exists", name)) {
727
            return;
728
        } else {
729
            if (defaults_assumed) {
730
                if (no_copy &&
731
                    !verify_action("* CAUTION * about to program '%s'\n            at %p..%p from %p",
732
                                   name, (void *)flash_addr, (void *)(flash_addr+img_size-1),
733
                                   (void *)mem_addr)) {
734
                    return;  // The guy gave up
735
                }
736
            }
737
        }
738
    } else {
739
        // If not image by that name, try and find an empty slot
740
        img = (struct fis_image_desc *)fis_work_block;
741
        for (i = 0;  i < fisdir_size/sizeof(*img);  i++, img++) {
742
            if (img->name[0] == (unsigned char)0xFF) {
743
                break;
744
            }
745
        }
746
    }
747
    if (!no_copy) {
748
        // Safety check - make sure the address range is not within the code we're running
749
        if (flash_code_overlaps((void *)flash_addr, (void *)(flash_addr+img_size-1))) {
750
            diag_printf("Can't program this region - contains code in use!\n");
751
            return;
752
        }
753
        if (prog_ok) {
754
            // Erase area to be programmed
755
            if ((stat = flash_erase((void *)flash_addr, length, (void **)&err_addr)) != 0) {
756
                diag_printf("Can't erase region at %p: %s\n", err_addr, flash_errmsg(stat));
757
                prog_ok = false;
758
            }
759
        }
760
        if (prog_ok) {
761
            // Now program it
762
            if ((stat = flash_program((void *)flash_addr, (void *)mem_addr, img_size, (void **)&err_addr)) != 0) {
763
                diag_printf("Can't program region at %p: %s\n", err_addr, flash_errmsg(stat));
764
                prog_ok = false;
765
            }
766
        }
767
    }
768
    if (prog_ok) {
769
        // Update directory
770
        memset(img, 0, sizeof(*img));
771
        strcpy(img->name, name);
772
        img->flash_base = flash_addr;
773
        img->mem_base = exec_addr_set ? exec_addr : (flash_addr_set ? flash_addr : mem_addr);
774
        img->entry_point = entry_addr_set ? entry_addr : (CYG_ADDRESS)entry_address;  // Hope it's been set
775
        img->size = length;
776
        img->data_length = img_size;
777
#ifdef CYGSEM_REDBOOT_FIS_CRC_CHECK
778
        img->file_cksum = cyg_crc32((unsigned char *)flash_addr, img_size);
779
#endif
780
        fis_update_directory();
781
    }
782
}
783
 
784
extern void arm_fis_delete(char *);
785
static void
786
fis_delete(int argc, char *argv[])
787
{
788
    char *name;
789
    int num_reserved, i, stat;
790
    void *err_addr;
791
    struct fis_image_desc *img;
792
 
793
    if (!scan_opts(argc, argv, 2, 0, 0, (void **)&name, OPTION_ARG_TYPE_STR, "image name"))
794
    {
795
        fis_usage("invalid arguments");
796
        return;
797
    }
798
#ifdef CYGHWR_REDBOOT_ARM_FLASH_SIB
799
    // FIXME: this is somewhat half-baked
800
    arm_fis_delete(name);
801
    return;
802
#endif
803
    img = (struct fis_image_desc *)fis_work_block;
804
    num_reserved = 0;
805
#ifdef CYGOPT_REDBOOT_FIS_RESERVED_BASE
806
    num_reserved++;
807
#endif
808
#ifdef CYGOPT_REDBOOT_FIS_REDBOOT
809
    num_reserved++;
810
#endif
811
#ifdef CYGOPT_REDBOOT_FIS_REDBOOT_BACKUP
812
    num_reserved++;
813
#endif
814
#ifdef CYGOPT_REDBOOT_FIS_REDBOOT_POST
815
    num_reserved++;
816
#endif
817
#ifdef CYGSEM_REDBOOT_FLASH_CONFIG
818
    num_reserved++;
819
#endif
820
#if 1 // And the descriptor for the descriptor table itself
821
    num_reserved++;
822
#endif
823
 
824
    memcpy(fis_work_block, fis_addr, fisdir_size);
825
    img = fis_lookup(name, &i);
826
    if (img) {
827
        if (i < num_reserved) {
828
            diag_printf("Sorry, '%s' is a reserved image and cannot be deleted\n", img->name);
829
            return;
830
        }
831
        if (!verify_action("Delete image '%s'", name)) {
832
            return;
833
        }
834
    } else {
835
        diag_printf("No image '%s' found\n", name);
836
        return;
837
    }
838
    // Erase Data blocks (free space)
839
    if ((stat = flash_erase((void *)img->flash_base, img->size, (void **)&err_addr)) != 0) {
840
        diag_printf("Error erasing at %p: %s\n", err_addr, flash_errmsg(stat));
841
    } else {
842
        img->name[0] = (unsigned char)0xFF;
843
        fis_update_directory();
844
    }
845
}
846
 
847
static void
848
fis_load(int argc, char *argv[])
849
{
850
    char *name;
851
    struct fis_image_desc *img;
852
    CYG_ADDRESS mem_addr;
853
    bool mem_addr_set = false;
854
    bool show_cksum = false;
855
    struct option_info opts[3];
856
#ifdef CYGPKG_REDBOOT_FIS_CRC_CHECK
857
    unsigned long cksum;
858
#endif
859
    int num_options;
860
#ifdef CYGPKG_COMPRESS_ZLIB
861
    bool decompress = false;
862
#endif
863
 
864
    init_opts(&opts[0], 'b', true, OPTION_ARG_TYPE_NUM,
865
              (void **)&mem_addr, (bool *)&mem_addr_set, "memory [load] base address");
866
    init_opts(&opts[1], 'c', false, OPTION_ARG_TYPE_FLG,
867
              (void **)&show_cksum, (bool *)0, "display checksum");
868
    num_options = 2;
869
#ifdef CYGPKG_COMPRESS_ZLIB
870
    init_opts(&opts[num_options], 'd', false, OPTION_ARG_TYPE_FLG,
871
              (void **)&decompress, 0, "decompress");
872
    num_options++;
873
#endif
874
 
875
    if (!scan_opts(argc, argv, 2, opts, num_options, (void **)&name, OPTION_ARG_TYPE_STR, "image name"))
876
    {
877
        fis_usage("invalid arguments");
878
        return;
879
    }
880
    memcpy(fis_work_block, fis_addr, fisdir_size);
881
    if ((img = fis_lookup(name, NULL)) == (struct fis_image_desc *)0) {
882
        diag_printf("No image '%s' found\n", name);
883
        return;
884
    }
885
    if (!mem_addr_set) {
886
        mem_addr = img->mem_base;
887
    }
888
    // Load image from FLASH into RAM
889
    if ((mem_addr < (CYG_ADDRESS)user_ram_start) ||
890
        ((mem_addr+img->data_length) >= (CYG_ADDRESS)user_ram_end)) {
891
        diag_printf("Not a loadable image\n");
892
        return;
893
    }
894
#ifdef CYGPKG_COMPRESS_ZLIB
895
    if (decompress) {
896
        int err;
897
        _pipe_t fis_load_pipe;
898
        _pipe_t* p = &fis_load_pipe;
899
        p->out_buf = (unsigned char*) mem_addr;
900
        p->out_max = p->out_size = -1;
901
        p->in_buf = (unsigned char*) img->flash_base;
902
        p->in_avail = img->data_length;
903
 
904
        err = (*_dc_init)(p);
905
 
906
        if (0 == err)
907
            err = (*_dc_inflate)(p);
908
 
909
        // Free used resources, do final translation of
910
        // error value.
911
        err = (*_dc_close)(p, err);
912
 
913
        if (0 != err && p->msg) {
914
            diag_printf("decompression error: %s\n", p->msg);
915
        } else {
916
            diag_printf("Image loaded from %p-%p\n", (unsigned char *)mem_addr, p->out_buf);
917
        }
918
 
919
        // Set load address/top
920
        load_address = mem_addr;
921
        load_address_end = (unsigned long)p->out_buf;
922
 
923
        // Reload fis directory
924
        memcpy(fis_work_block, fis_addr, fisdir_size);
925
    } else // dangling block
926
#endif
927
    {
928
        memcpy((void *)mem_addr, (void *)img->flash_base, img->data_length);
929
 
930
        // Set load address/top
931
        load_address = mem_addr;
932
        load_address_end = mem_addr + img->data_length;
933
    }
934
    entry_address = (unsigned long)img->entry_point;
935
 
936
#ifdef CYGPKG_REDBOOT_FIS_CRC_CHECK
937
    cksum = cyg_crc32((unsigned char *)mem_addr, img->data_length);
938
    if (show_cksum) {
939
        diag_printf("Checksum: 0x%08lx\n", cksum);
940
    }
941
    // When decompressing, leave CRC checking to decompressor
942
    if (!decompress && img->file_cksum) {
943
        if (cksum != img->file_cksum) {
944
            diag_printf("** Warning - checksum failure.  stored: 0x%08lx, computed: 0x%08lx\n",
945
                        img->file_cksum, cksum);
946
        }
947
    }
948
#endif
949
}
950
#endif // CYGOPT_REDBOOT_FIS
951
 
952
static void
953
fis_write(int argc, char *argv[])
954
{
955
    int stat;
956
    unsigned long length;
957
    CYG_ADDRESS mem_addr, flash_addr;
958
    bool mem_addr_set = false;
959
    bool flash_addr_set = false;
960
    bool length_set = false;
961
    void *err_addr;
962
    struct option_info opts[3];
963
    bool prog_ok;
964
 
965
    init_opts(&opts[0], 'b', true, OPTION_ARG_TYPE_NUM,
966
              (void **)&mem_addr, (bool *)&mem_addr_set, "memory base address");
967
    init_opts(&opts[1], 'f', true, OPTION_ARG_TYPE_NUM,
968
              (void **)&flash_addr, (bool *)&flash_addr_set, "FLASH memory base address");
969
    init_opts(&opts[2], 'l', true, OPTION_ARG_TYPE_NUM,
970
              (void **)&length, (bool *)&length_set, "image length [in FLASH]");
971
    if (!scan_opts(argc, argv, 2, opts, 3, 0, 0, 0))
972
    {
973
        fis_usage("invalid arguments");
974
        return;
975
    }
976
 
977
    if (!mem_addr_set || !flash_addr_set || !length_set) {
978
        fis_usage("required parameter missing");
979
        return;
980
    }
981
 
982
    // Round up length to FLASH block size
983
#ifndef CYGPKG_HAL_MIPS // FIXME: compiler is b0rken
984
    length = ((length + flash_block_size - 1) / flash_block_size) * flash_block_size;
985
#endif
986
    if (flash_addr_set &&
987
        ((stat = flash_verify_addr((void *)flash_addr)) ||
988
         (stat = flash_verify_addr((void *)(flash_addr+length-1))))) {
989
        _show_invalid_flash_address(flash_addr, stat);
990
        return;
991
    }
992
    if (flash_addr_set && flash_addr & (flash_block_size-1)) {
993
        diag_printf("Invalid FLASH address: %p\n", (void *)flash_addr);
994
        diag_printf("   must be 0x%x aligned\n", flash_block_size);
995
        return;
996
    }
997
    if ((mem_addr < (CYG_ADDRESS)ram_start) ||
998
        ((mem_addr+length) >= (CYG_ADDRESS)ram_end)) {
999
        diag_printf("** WARNING: RAM address: %p may be invalid\n", (void *)mem_addr);
1000
        diag_printf("   valid range is %p-%p\n", (void *)ram_start, (void *)ram_end);
1001
    }
1002
    // Safety check - make sure the address range is not within the code we're running
1003
    if (flash_code_overlaps((void *)flash_addr, (void *)(flash_addr+length-1))) {
1004
        diag_printf("Can't program this region - contains code in use!\n");
1005
        return;
1006
    }
1007
    if (!verify_action("* CAUTION * about to program FLASH\n            at %p..%p from %p",
1008
                       (void *)flash_addr, (void *)(flash_addr+length-1),
1009
                       (void *)mem_addr)) {
1010
        return;  // The guy gave up
1011
    }
1012
    prog_ok = true;
1013
    if (prog_ok) {
1014
        // Erase area to be programmed
1015
        if ((stat = flash_erase((void *)flash_addr, length, (void **)&err_addr)) != 0) {
1016
            diag_printf("Can't erase region at %p: %s\n", err_addr, flash_errmsg(stat));
1017
            prog_ok = false;
1018
        }
1019
    }
1020
    if (prog_ok) {
1021
        // Now program it
1022
        if ((stat = flash_program((void *)flash_addr, (void *)mem_addr, length, (void **)&err_addr)) != 0) {
1023
            diag_printf("Can't program region at %p: %s\n", err_addr, flash_errmsg(stat));
1024
            prog_ok = false;
1025
        }
1026
    }
1027
}
1028
 
1029
static void
1030
fis_erase(int argc, char *argv[])
1031
{
1032
    int stat;
1033
    unsigned long length;
1034
    CYG_ADDRESS flash_addr;
1035
    bool flash_addr_set = false;
1036
    bool length_set = false;
1037
    void *err_addr;
1038
    struct option_info opts[2];
1039
 
1040
    init_opts(&opts[0], 'f', true, OPTION_ARG_TYPE_NUM,
1041
              (void **)&flash_addr, (bool *)&flash_addr_set, "FLASH memory base address");
1042
    init_opts(&opts[1], 'l', true, OPTION_ARG_TYPE_NUM,
1043
              (void **)&length, (bool *)&length_set, "length");
1044
    if (!scan_opts(argc, argv, 2, opts, 2, (void **)0, 0, ""))
1045
    {
1046
        fis_usage("invalid arguments");
1047
        return;
1048
    }
1049
 
1050
    if (!flash_addr_set || !length_set) {
1051
        fis_usage("missing argument");
1052
        return;
1053
    }
1054
    if (flash_addr_set &&
1055
        ((stat = flash_verify_addr((void *)flash_addr)) ||
1056
         (stat = flash_verify_addr((void *)(flash_addr+length-1))))) {
1057
        _show_invalid_flash_address(flash_addr, stat);
1058
        return;
1059
    }
1060
    if (flash_addr_set && flash_addr & (flash_block_size-1)) {
1061
        diag_printf("Invalid FLASH address: %p\n", (void *)flash_addr);
1062
        diag_printf("   must be 0x%x aligned\n", flash_block_size);
1063
        return;
1064
    }
1065
    // Safety check - make sure the address range is not within the code we're running
1066
    if (flash_code_overlaps((void *)flash_addr, (void *)(flash_addr+length-1))) {
1067
        diag_printf("Can't erase this region - contains code in use!\n");
1068
        return;
1069
    }
1070
    if ((stat = flash_erase((void *)flash_addr, length, (void **)&err_addr)) != 0) {
1071
        diag_printf("Error erasing at %p: %s\n", err_addr, flash_errmsg(stat));
1072
    }
1073
}
1074
 
1075
#ifdef CYGHWR_IO_FLASH_BLOCK_LOCKING
1076
 
1077
static void
1078
fis_lock(int argc, char *argv[])
1079
{
1080
    char *name;
1081
    int stat;
1082
    unsigned long length;
1083
    CYG_ADDRESS flash_addr;
1084
    bool flash_addr_set = false;
1085
    bool length_set = false;
1086
    void *err_addr;
1087
    struct option_info opts[2];
1088
 
1089
    init_opts(&opts[0], 'f', true, OPTION_ARG_TYPE_NUM,
1090
              (void **)&flash_addr, (bool *)&flash_addr_set, "FLASH memory base address");
1091
    init_opts(&opts[1], 'l', true, OPTION_ARG_TYPE_NUM,
1092
              (void **)&length, (bool *)&length_set, "length");
1093
    if (!scan_opts(argc, argv, 2, opts, 2, (void **)&name, OPTION_ARG_TYPE_STR, "image name"))
1094
    {
1095
        fis_usage("invalid arguments");
1096
        return;
1097
    }
1098
 
1099
    /* Get parameters from image if specified */
1100
    if (name) {
1101
        struct fis_image_desc *img;
1102
        memcpy(fis_work_block, fis_addr, fisdir_size);
1103
        if ((img = fis_lookup(name, NULL)) == (struct fis_image_desc *)0) {
1104
            diag_printf("No image '%s' found\n", name);
1105
            return;
1106
        }
1107
 
1108
        flash_addr = img->flash_base;
1109
        length = img->size;
1110
    } else if (!flash_addr_set || !length_set) {
1111
        fis_usage("missing argument");
1112
        return;
1113
    }
1114
    if (flash_addr_set &&
1115
        ((stat = flash_verify_addr((void *)flash_addr)) ||
1116
         (stat = flash_verify_addr((void *)(flash_addr+length-1))))) {
1117
        _show_invalid_flash_address(flash_addr, stat);
1118
        return;
1119
    }
1120
    if ((stat = flash_lock((void *)flash_addr, length, (void **)&err_addr)) != 0) {
1121
        diag_printf("Error locking at %p: %s\n", err_addr, flash_errmsg(stat));
1122
    }
1123
}
1124
 
1125
static void
1126
fis_unlock(int argc, char *argv[])
1127
{
1128
    char *name;
1129
    int stat;
1130
    unsigned long length;
1131
    CYG_ADDRESS flash_addr;
1132
    bool flash_addr_set = false;
1133
    bool length_set = false;
1134
    void *err_addr;
1135
    struct option_info opts[2];
1136
 
1137
    init_opts(&opts[0], 'f', true, OPTION_ARG_TYPE_NUM,
1138
              (void **)&flash_addr, (bool *)&flash_addr_set, "FLASH memory base address");
1139
    init_opts(&opts[1], 'l', true, OPTION_ARG_TYPE_NUM,
1140
              (void **)&length, (bool *)&length_set, "length");
1141
    if (!scan_opts(argc, argv, 2, opts, 2, (void **)&name, OPTION_ARG_TYPE_STR, "image name"))
1142
    {
1143
        fis_usage("invalid arguments");
1144
        return;
1145
    }
1146
 
1147
    if (name) {
1148
        struct fis_image_desc *img;
1149
        memcpy(fis_work_block, fis_addr, fisdir_size);
1150
        if ((img = fis_lookup(name, NULL)) == (struct fis_image_desc *)0) {
1151
            diag_printf("No image '%s' found\n", name);
1152
            return;
1153
        }
1154
 
1155
        flash_addr = img->flash_base;
1156
        length = img->size;
1157
    } else  if (!flash_addr_set || !length_set) {
1158
        fis_usage("missing argument");
1159
        return;
1160
    }
1161
    if (flash_addr_set &&
1162
        ((stat = flash_verify_addr((void *)flash_addr)) ||
1163
         (stat = flash_verify_addr((void *)(flash_addr+length-1))))) {
1164
        _show_invalid_flash_address(flash_addr, stat);
1165
        return;
1166
    }
1167
 
1168
    if ((stat = flash_unlock((void *)flash_addr, length, (void **)&err_addr)) != 0) {
1169
        diag_printf("Error unlocking at %p: %s\n", err_addr, flash_errmsg(stat));
1170
    }
1171
}
1172
#endif
1173
 
1174
// This is set non-zero if the FLASH subsystem has successfully been initialized
1175
static int __flash_init = 0;
1176
 
1177
void
1178
_flash_info(void)
1179
{
1180
    if (!__flash_init) return;
1181
    diag_printf("FLASH: %p - %p, %d blocks of %p bytes each.\n",
1182
           flash_start, (CYG_ADDRWORD)flash_end + 1, flash_num_blocks, (void *)flash_block_size);
1183
}
1184
 
1185
static bool
1186
do_flash_init(void)
1187
{
1188
    int stat;
1189
 
1190
    if (!__flash_init) {
1191
        if ((stat = flash_init((void *)(workspace_end-FLASH_MIN_WORKSPACE),
1192
                               FLASH_MIN_WORKSPACE, diag_printf)) != 0) {
1193
            diag_printf("FLASH: driver init failed: %s\n", flash_errmsg(stat));
1194
            return false;
1195
        }
1196
        flash_get_limits((void *)0, (void **)&flash_start, (void **)&flash_end);
1197
        // Keep 'end' address as last valid location, to avoid wrap around problems
1198
        flash_end = (void *)((CYG_ADDRESS)flash_end - 1);
1199
        flash_get_block_info(&flash_block_size, &flash_num_blocks);
1200
        workspace_end = (unsigned char *)(workspace_end-FLASH_MIN_WORKSPACE);
1201
#ifdef CYGOPT_REDBOOT_FIS
1202
# ifdef CYGOPT_REDBOOT_FIS_ZLIB_COMMON_BUFFER
1203
        fis_work_block = fis_zlib_common_buffer;
1204
        if(CYGNUM_REDBOOT_FIS_ZLIB_COMMON_BUFFER_SIZE < flash_block_size) {
1205
            diag_printf("FLASH: common buffer too small\n");
1206
            workspace_end += FLASH_MIN_WORKSPACE;
1207
            return false;
1208
        }
1209
# else
1210
        workspace_end = (unsigned char *)(workspace_end-flash_block_size);
1211
        fis_work_block = workspace_end;
1212
# endif
1213
        fisdir_size = flash_block_size;
1214
        if (CYGNUM_REDBOOT_FIS_DIRECTORY_BLOCK < 0) {
1215
            fis_addr = (void *)((CYG_ADDRESS)flash_end + 1 +
1216
                                (CYGNUM_REDBOOT_FIS_DIRECTORY_BLOCK*flash_block_size));
1217
        } else {
1218
            fis_addr = (void *)((CYG_ADDRESS)flash_start +
1219
                                (CYGNUM_REDBOOT_FIS_DIRECTORY_BLOCK*flash_block_size));
1220
        }
1221
#endif
1222
        __flash_init = 1;
1223
    }
1224
    return true;
1225
}
1226
 
1227
// Wrapper to avoid compiler warnings
1228
static void
1229
_do_flash_init(void)
1230
{
1231
    do_flash_init();
1232
}
1233
 
1234
#ifndef CYGOPT_REDBOOT_FLASH_CONFIG
1235
RedBoot_init(_do_flash_init, RedBoot_INIT_FIRST);
1236
#endif
1237
 
1238
static void
1239
do_fis(int argc, char *argv[])
1240
{
1241
    struct cmd *cmd;
1242
 
1243
    if (argc < 2) {
1244
        fis_usage("too few arguments");
1245
        return;
1246
    }
1247
    if (!do_flash_init()) {
1248
        diag_printf("Sorry, no FLASH memory is available\n");
1249
        return;
1250
    }
1251
    if ((cmd = cmd_search(__FIS_cmds_TAB__, &__FIS_cmds_TAB_END__,
1252
                          argv[1])) != (struct cmd *)0) {
1253
        (cmd->fun)(argc, argv);
1254
        return;
1255
    }
1256
    fis_usage("unrecognized command");
1257
}
1258
 
1259
#ifdef CYGSEM_REDBOOT_FLASH_CONFIG
1260
 
1261
static bool config_ok;
1262
 
1263
#define CONFIG_KEY1    0x0BADFACE
1264
#define CONFIG_KEY2    0xDEADDEAD
1265
 
1266
#define CONFIG_DONE    0
1267
#define CONFIG_ABORT  -1
1268
#define CONFIG_CHANGED 1
1269
#define CONFIG_OK      2
1270
#define CONFIG_BACK    3
1271
#define CONFIG_BAD     4
1272
 
1273
// Note: the following options are related.  If 'boot_script' is false, then
1274
// the other values are used in the configuration.  Because of the way
1275
// that configuration tables are generated, they should have names which
1276
// are related.  The configuration options will show up lexicographically
1277
// ordered, thus the peculiar naming.
1278
RedBoot_config_option("Run script at boot",
1279
                      boot_script,
1280
                      ALWAYS_ENABLED, true,
1281
                      CONFIG_BOOL,
1282
                      false
1283
    );
1284
RedBoot_config_option("Boot script",
1285
                      boot_script_data,
1286
                      "boot_script", true,
1287
                      CONFIG_SCRIPT,
1288
                      ""
1289
    );
1290
// Some preprocessor magic for building the [constant] prompt string
1291
#define __cat(s1,c2,s3) s1 #c2 s3
1292
#define _cat(s1,c2,s3) __cat(s1,c2,s3)
1293
RedBoot_config_option(_cat("Boot script timeout (",
1294
                           CYGNUM_REDBOOT_BOOT_SCRIPT_TIMEOUT_RESOLUTION,
1295
                           "ms resolution)"),
1296
                      boot_script_timeout,
1297
                      "boot_script", true,
1298
                      CONFIG_INT,
1299
 
1300
    );
1301
#undef __cat
1302
#undef _cat
1303
 
1304
#ifdef CYGSEM_REDBOOT_VARIABLE_BAUD_RATE
1305
RedBoot_config_option("Console baud rate",
1306
                      console_baud_rate,
1307
                      ALWAYS_ENABLED, true,
1308
                      CONFIG_INT,
1309
                      CYGNUM_HAL_VIRTUAL_VECTOR_CONSOLE_CHANNEL_BAUD
1310
    );
1311
#endif
1312
 
1313
CYG_HAL_TABLE_BEGIN( __CONFIG_options_TAB__, RedBoot_config_options);
1314
CYG_HAL_TABLE_END( __CONFIG_options_TAB_END__, RedBoot_config_options);
1315
 
1316
extern struct config_option __CONFIG_options_TAB__[], __CONFIG_options_TAB_END__[];
1317
 
1318
// 
1319
// Layout of config data
1320
// Each data item is variable length, with the name, type and dependencies
1321
// encoded into the object.
1322
//  offset   contents
1323
//       0   data type
1324
//       1   length of name (N)
1325
//       2   enable sense
1326
//       3   length of enable key (M)
1327
//       4   key name
1328
//     N+4   enable key
1329
//   M+N+4   data value
1330
//
1331
 
1332
#define CONFIG_OBJECT_TYPE(dp)          (dp)[0]
1333
#define CONFIG_OBJECT_KEYLEN(dp)        (dp)[1]
1334
#define CONFIG_OBJECT_ENABLE_SENSE(dp)  (dp)[2]
1335
#define CONFIG_OBJECT_ENABLE_KEYLEN(dp) (dp)[3]
1336
#define CONFIG_OBJECT_KEY(dp)           ((dp)+4)
1337
#define CONFIG_OBJECT_ENABLE_KEY(dp)    ((dp)+4+CONFIG_OBJECT_KEYLEN(dp))
1338
#define CONFIG_OBJECT_VALUE(dp)         ((dp)+4+CONFIG_OBJECT_KEYLEN(dp)+CONFIG_OBJECT_ENABLE_KEYLEN(dp))
1339
 
1340
#define LIST_OPT_LIST_ONLY (1)
1341
#define LIST_OPT_NICKNAMES (2)
1342
#define LIST_OPT_FULLNAMES (4)
1343
#define LIST_OPT_DUMBTERM  (8)
1344
 
1345
static void config_init(void);
1346
 
1347
static int
1348
get_config(unsigned char *dp, char *title, int list_opt, char *newvalue )
1349
{
1350
    char line[256], hold_line[256], *sp, *lp;
1351
    int ret;
1352
    bool hold_bool_val, new_bool_val, enable;
1353
    unsigned long hold_int_val, new_int_val;
1354
#ifdef CYGPKG_REDBOOT_NETWORKING
1355
    in_addr_t hold_ip_val, new_ip_val;
1356
    enet_addr_t hold_esa_val;
1357
    int esa_ptr;
1358
    char *esp;
1359
#endif
1360
    void *val_ptr;
1361
    int type;
1362
 
1363
    if (CONFIG_OBJECT_ENABLE_KEYLEN(dp)) {
1364
        flash_get_config(CONFIG_OBJECT_ENABLE_KEY(dp), &enable, CONFIG_BOOL);
1365
        if (((bool)CONFIG_OBJECT_ENABLE_SENSE(dp) && !enable) ||
1366
            (!(bool)CONFIG_OBJECT_ENABLE_SENSE(dp) && enable)) {
1367
            return CONFIG_OK;  // Disabled field
1368
        }
1369
    }
1370
    lp = line;  *lp = '\0';
1371
    val_ptr = (void *)CONFIG_OBJECT_VALUE(dp);
1372
    if (LIST_OPT_NICKNAMES & list_opt)
1373
        diag_printf("%s: ", CONFIG_OBJECT_KEY(dp));
1374
    if (LIST_OPT_FULLNAMES & list_opt) {
1375
        if (title != (char *)NULL) {
1376
            diag_printf("%s: ", title);
1377
        } else {
1378
            diag_printf("%s: ", CONFIG_OBJECT_KEY(dp));
1379
        }
1380
    }
1381
    switch (type = CONFIG_OBJECT_TYPE(dp)) {
1382
    case CONFIG_BOOL:
1383
        memcpy(&hold_bool_val, val_ptr, sizeof(bool));
1384
        lp += diag_sprintf(lp, "%s", hold_bool_val ? "true" : "false");
1385
        break;
1386
    case CONFIG_INT:
1387
        memcpy(&hold_int_val, val_ptr, sizeof(unsigned long));
1388
        lp += diag_sprintf(lp, "%ld", hold_int_val);
1389
        break;
1390
#ifdef CYGPKG_REDBOOT_NETWORKING
1391
    case CONFIG_IP:
1392
        lp += diag_sprintf(lp, "%s", inet_ntoa((in_addr_t *)val_ptr));
1393
        if (0 == strcmp("0.0.0.0", line) && !(LIST_OPT_LIST_ONLY & list_opt)) {
1394
            // then we have a deeply unhelpful starting text - kill it off
1395
            // (unless we are just listing all values)
1396
            lp = line;  *lp = '\0';
1397
        }
1398
        break;
1399
    case CONFIG_ESA:
1400
        for (esa_ptr = 0;  esa_ptr < sizeof(enet_addr_t);  esa_ptr++) {
1401
            lp += diag_sprintf(lp, "0x%02X", ((unsigned char *)val_ptr)[esa_ptr]);
1402
            if (esa_ptr < (sizeof(enet_addr_t)-1)) lp += diag_sprintf(lp, ":");
1403
        }
1404
        break;
1405
#endif
1406
    case CONFIG_STRING:
1407
        lp += diag_sprintf(lp, "%s", (unsigned char *)val_ptr);
1408
        break;
1409
    case CONFIG_SCRIPT:
1410
        diag_printf("\n");
1411
        sp = lp = (unsigned char *)val_ptr;
1412
        while (*sp) {
1413
            while (*lp != '\n') lp++;
1414
            *lp = '\0';
1415
            diag_printf(".. %s\n", sp);
1416
            *lp++ = '\n';
1417
            sp = lp;
1418
        }
1419
        break;
1420
    }
1421
    if (LIST_OPT_LIST_ONLY & list_opt) {
1422
        diag_printf("%s\n", line);
1423
        return CONFIG_OK;
1424
    }
1425
    if (type != CONFIG_SCRIPT) {
1426
        if (NULL != newvalue) {
1427
            ret = strlen(newvalue);
1428
            if (ret > sizeof(line))
1429
                return CONFIG_BAD;
1430
            strcpy(hold_line, line); // Hold the old value for comparison
1431
            strcpy(line, newvalue);
1432
            diag_printf("Setting to %s\n", newvalue);
1433
        } else {
1434
            // read from terminal
1435
            strcpy(hold_line, line);
1436
            if (LIST_OPT_DUMBTERM & list_opt) {
1437
                diag_printf( (CONFIG_STRING == type ?
1438
                              "%s > " :
1439
                              "%s ? " ), line);
1440
                *line = '\0';
1441
            }
1442
            ret = _rb_gets_preloaded(line, sizeof(line), 0);
1443
        }
1444
        if (ret < 0) return CONFIG_ABORT;
1445
        // empty input - leave value untouched (else DNS goes away for a
1446
        // minute to try to look it up) but we must accept empty value for strings.
1447
        if (0 == line[0] && CONFIG_STRING != type) return CONFIG_OK;
1448
        if (strcmp(line, hold_line) == 0) return CONFIG_OK;  // Just a CR - leave value untouched
1449
        lp = &line[strlen(line)-1];
1450
        if (*lp == '.') return CONFIG_DONE;
1451
        if (*lp == '^') return CONFIG_BACK;
1452
    }
1453
    switch (type) {
1454
    case CONFIG_BOOL:
1455
        memcpy(&hold_bool_val, val_ptr, sizeof(bool));
1456
        if (!parse_bool(line, &new_bool_val)) {
1457
            return CONFIG_BAD;
1458
        }
1459
        if (hold_bool_val != new_bool_val) {
1460
            memcpy(val_ptr, &new_bool_val, sizeof(bool));
1461
            return CONFIG_CHANGED;
1462
        } else {
1463
            return CONFIG_OK;
1464
        }
1465
        break;
1466
    case CONFIG_INT:
1467
        memcpy(&hold_int_val, val_ptr, sizeof(unsigned long));
1468
        if (!parse_num(line, &new_int_val, 0, 0)) {
1469
            return CONFIG_BAD;
1470
        }
1471
        if (hold_int_val != new_int_val) {
1472
            memcpy(val_ptr, &new_int_val, sizeof(unsigned long));
1473
            return CONFIG_CHANGED;
1474
        } else {
1475
            return CONFIG_OK;
1476
        }
1477
        break;
1478
#ifdef CYGPKG_REDBOOT_NETWORKING
1479
    case CONFIG_IP:
1480
        memcpy(&hold_ip_val.s_addr, &((in_addr_t *)val_ptr)->s_addr, sizeof(in_addr_t));
1481
        if (!_gethostbyname(line, &new_ip_val)) {
1482
            return CONFIG_BAD;
1483
        }
1484
        if (hold_ip_val.s_addr != new_ip_val.s_addr) {
1485
            memcpy(val_ptr, &new_ip_val, sizeof(in_addr_t));
1486
            return CONFIG_CHANGED;
1487
        } else {
1488
            return CONFIG_OK;
1489
        }
1490
        break;
1491
    case CONFIG_ESA:
1492
        memcpy(&hold_esa_val, val_ptr, sizeof(enet_addr_t));
1493
        esp = line;
1494
        for (esa_ptr = 0;  esa_ptr < sizeof(enet_addr_t);  esa_ptr++) {
1495
            unsigned long esa_byte;
1496
            if (!parse_num(esp, &esa_byte, &esp, ":")) {
1497
                memcpy(val_ptr, &hold_esa_val, sizeof(enet_addr_t));
1498
                return CONFIG_BAD;
1499
            }
1500
            ((unsigned char *)val_ptr)[esa_ptr] = esa_byte;
1501
        }
1502
        return CONFIG_CHANGED;
1503
        break;
1504
#endif
1505
    case CONFIG_SCRIPT:
1506
        // Assume it always changes
1507
        sp = (unsigned char *)val_ptr;
1508
        diag_printf("Enter script, terminate with empty line\n");
1509
        while (true) {
1510
            *sp = '\0';
1511
            diag_printf(">> ");
1512
            ret = _rb_gets(line, sizeof(line), 0);
1513
            if (ret < 0) return CONFIG_ABORT;
1514
            if (strlen(line) == 0) break;
1515
            lp = line;
1516
            while (*lp) {
1517
                *sp++ = *lp++;
1518
            }
1519
            *sp++ = '\n';
1520
        }
1521
        break;
1522
    case CONFIG_STRING:
1523
        if (strlen(line) >= MAX_STRING_LENGTH) {
1524
            diag_printf("Sorry, value is too long\n");
1525
            return CONFIG_BAD;
1526
        }
1527
        strcpy((unsigned char *)val_ptr, line);
1528
        break;
1529
    }
1530
    return CONFIG_CHANGED;
1531
}
1532
 
1533
//
1534
// Manage configuration information with the FLASH
1535
//
1536
 
1537
static int
1538
config_length(int type)
1539
{
1540
    switch (type) {
1541
    case CONFIG_BOOL:
1542
        return sizeof(bool);
1543
    case CONFIG_INT:
1544
        return sizeof(unsigned long);
1545
#ifdef CYGPKG_REDBOOT_NETWORKING
1546
    case CONFIG_IP:
1547
        return sizeof(in_addr_t);
1548
    case CONFIG_ESA:
1549
        // Would like this to be sizeof(enet_addr_t), but that causes much
1550
        // pain since it fouls the alignment of data which follows.
1551
        return 8;
1552
#endif
1553
    case CONFIG_STRING:
1554
        return MAX_STRING_LENGTH;
1555
    case CONFIG_SCRIPT:
1556
        return MAX_SCRIPT_LENGTH;
1557
    default:
1558
        return 0;
1559
    }
1560
}
1561
 
1562
static cmd_fun do_flash_config;
1563
RedBoot_cmd("fconfig",
1564
            "Manage configuration kept in FLASH memory",
1565
            "[-i] [-l] [-n] [-f] [-d] | [-d] nickname [value]",
1566
            do_flash_config
1567
    );
1568
 
1569
static void
1570
do_flash_config(int argc, char *argv[])
1571
{
1572
    bool need_update = false;
1573
    struct config_option *optend = __CONFIG_options_TAB_END__;
1574
    struct config_option *opt = __CONFIG_options_TAB__;
1575
    struct option_info opts[5];
1576
    bool list_only;
1577
    bool nicknames;
1578
    bool fullnames;
1579
    bool dumbterminal;
1580
    int list_opt = 0;
1581
    unsigned char *dp;
1582
    int len, ret;
1583
    char *title;
1584
    char *onlyone = NULL;
1585
    char *onevalue = NULL;
1586
    bool doneone = false;
1587
    bool init = false;
1588
 
1589
    if (!__flash_init) {
1590
        diag_printf("Sorry, no FLASH memory is available\n");
1591
        return;
1592
    }
1593
    memcpy(backup_config, config, sizeof(struct _config));
1594
    script = (unsigned char *)0;
1595
 
1596
    init_opts(&opts[0], 'l', false, OPTION_ARG_TYPE_FLG,
1597
              (void **)&list_only, (bool *)0, "list configuration only");
1598
    init_opts(&opts[1], 'n', false, OPTION_ARG_TYPE_FLG,
1599
              (void **)&nicknames, (bool *)0, "show nicknames");
1600
    init_opts(&opts[2], 'f', false, OPTION_ARG_TYPE_FLG,
1601
              (void **)&fullnames, (bool *)0, "show full names");
1602
    init_opts(&opts[3], 'i', false, OPTION_ARG_TYPE_FLG,
1603
              (void **)&init, (bool *)0, "initialize configuration database");
1604
    init_opts(&opts[4], 'd', false, OPTION_ARG_TYPE_FLG,
1605
              (void **)&dumbterminal, (bool *)0, "dumb terminal: no clever edits");
1606
 
1607
    // First look to see if we are setting or getting a single option
1608
    // by just quoting its nickname
1609
    if ( (2 == argc && '-' != argv[1][0]) ||
1610
         (3 == argc && '-' != argv[1][0] && '-' != argv[2][0])) {
1611
        // then the command was "fconfig foo [value]"
1612
        onlyone = argv[1];
1613
        onevalue = (3 == argc) ? argv[2] : NULL;
1614
        list_opt = LIST_OPT_NICKNAMES;
1615
    }
1616
    // Next see if we are setting or getting a single option with a dumb
1617
    // terminal invoked, ie. no line editing.
1618
    else if (3 == argc &&
1619
             '-' == argv[1][0] && 'd' == argv[1][1] && 0 == argv[1][2] &&
1620
             '-' != argv[2][0]) {
1621
        // then the command was "fconfig -d foo"
1622
        onlyone = argv[2];
1623
        onevalue = NULL;
1624
        list_opt = LIST_OPT_NICKNAMES | LIST_OPT_DUMBTERM;
1625
    }
1626
    else {
1627
        if (!scan_opts(argc, argv, 1, opts, 5, 0, 0, ""))
1628
            return;
1629
        list_opt |= list_only ? LIST_OPT_LIST_ONLY : 0;
1630
        list_opt |= nicknames ? LIST_OPT_NICKNAMES : LIST_OPT_FULLNAMES;
1631
        list_opt |= fullnames ? LIST_OPT_FULLNAMES : 0;
1632
        list_opt |= dumbterminal ? LIST_OPT_DUMBTERM : 0;
1633
    }
1634
 
1635
    if (init && verify_action("Initialize non-volatile configuration")) {
1636
        config_init();
1637
        need_update = true;
1638
    }
1639
 
1640
    dp = &config->config_data[0];
1641
    while (dp < &config->config_data[sizeof(config->config_data)]) {
1642
        if (CONFIG_OBJECT_TYPE(dp) == CONFIG_EMPTY) {
1643
            break;
1644
        }
1645
        len = 4 + CONFIG_OBJECT_KEYLEN(dp) + CONFIG_OBJECT_ENABLE_KEYLEN(dp) +
1646
            config_length(CONFIG_OBJECT_TYPE(dp));
1647
        // Provide a title for well known [i.e. builtin] objects
1648
        title = (char *)NULL;
1649
        opt = __CONFIG_options_TAB__;
1650
        while (opt != optend) {
1651
            if (strcmp(opt->key, CONFIG_OBJECT_KEY(dp)) == 0) {
1652
                title = opt->title;
1653
                break;
1654
            }
1655
            opt++;
1656
        }
1657
        if ( onlyone && 0 != strcmp(CONFIG_OBJECT_KEY(dp), onlyone) )
1658
            ret = CONFIG_OK; // skip this entry
1659
        else {
1660
            doneone = true;
1661
            ret = get_config(dp, title, list_opt, onevalue); // do this opt
1662
        }
1663
        switch (ret) {
1664
        case CONFIG_DONE:
1665
            goto done;
1666
        case CONFIG_ABORT:
1667
            memcpy(config, backup_config, sizeof(struct _config));
1668
            return;
1669
        case CONFIG_CHANGED:
1670
            need_update = true;
1671
        case CONFIG_OK:
1672
            dp += len;
1673
            break;
1674
        case CONFIG_BACK:
1675
            dp = &config->config_data[0];
1676
            continue;
1677
        case CONFIG_BAD:
1678
            // Nothing - make him do it again
1679
            diag_printf ("** invalid entry\n");
1680
            onevalue = NULL; // request a good value be typed in - or abort/whatever
1681
        }
1682
    }
1683
 
1684
 done:
1685
    if (NULL != onlyone && !doneone) {
1686
#ifdef CYGSEM_REDBOOT_ALLOW_DYNAMIC_FLASH_CONFIG_DATA
1687
        if (verify_action("** entry '%s' not found - add", onlyone)) {
1688
            struct config_option opt;
1689
            diag_printf("Trying to add value\n");
1690
        }
1691
#else
1692
        diag_printf("** entry '%s' not found", onlyone);
1693
#endif
1694
    }
1695
    if (!need_update)
1696
        return;
1697
    flash_write_config();
1698
}
1699
 
1700
 
1701
#ifdef CYGSEM_REDBOOT_FLASH_ALIASES
1702
static cmd_fun do_alias;
1703
RedBoot_cmd("alias",
1704
            "Manage aliases kept in FLASH memory",
1705
            "name [value]",
1706
            do_alias
1707
    );
1708
 
1709
static void
1710
make_alias(char *alias, char *name)
1711
{
1712
    diag_sprintf(alias, "alias/%s", name);
1713
}
1714
 
1715
static void
1716
do_alias(int argc, char *argv[])
1717
{
1718
    char name[80];
1719
    char *val;
1720
    struct config_option opt;
1721
 
1722
    switch (argc) {
1723
    case 2:
1724
        make_alias(name, argv[1]);
1725
        if (flash_get_config(name, &val, CONFIG_STRING)) {
1726
            diag_printf("'%s' = '%s'\n", argv[1], val);
1727
        } else {
1728
            diag_printf("'%s' not found\n", argv[1]);
1729
        }
1730
        break;
1731
    case 3:
1732
        if (strlen(argv[2]) >= MAX_STRING_LENGTH) {
1733
            diag_printf("Sorry, value is too long\n");
1734
            break;
1735
        }
1736
        make_alias(name, argv[1]);
1737
        opt.type = CONFIG_STRING;
1738
        opt.enable = (char *)0;
1739
        opt.enable_sense = 1;
1740
        opt.key = name;
1741
        opt.dflt = (CYG_ADDRESS)argv[2];
1742
        flash_add_config(&opt, true);
1743
        break;
1744
    default:
1745
        diag_printf("usage: alias name [value]\n");
1746
    }
1747
}
1748
 
1749
// Lookup an alias. First try plain string aliases. If that fails try
1750
// other types so allowing access to all configured values. This allows
1751
// for alias (macro) expansion of normal 'fconfig' data, such as the
1752
// board IP address.
1753
char *
1754
flash_lookup_alias(char *alias, char *alias_buf)
1755
{
1756
    char name[80];
1757
    char *val;
1758
    unsigned char * dp;
1759
    void *val_ptr;
1760
    int type;
1761
    bool hold_bool_val;
1762
    long hold_long_val;
1763
#ifdef CYGPKG_REDBOOT_NETWORKING
1764
    int esa_ptr;
1765
#endif
1766
 
1767
    make_alias(name, alias);
1768
    if (flash_get_config(name, &val, CONFIG_STRING)) {
1769
        return val;
1770
    } else {
1771
        dp = flash_lookup_config(alias);
1772
        if (dp) {
1773
            val_ptr = (void *)CONFIG_OBJECT_VALUE(dp);
1774
            switch (type = CONFIG_OBJECT_TYPE(dp)) {
1775
            case CONFIG_BOOL:
1776
                memcpy(&hold_bool_val, val_ptr, sizeof(bool));
1777
                diag_sprintf(alias_buf, "%s", hold_bool_val ? "true" : "false");
1778
                break;
1779
            case CONFIG_INT:
1780
                memcpy(&hold_long_val, val_ptr, sizeof(unsigned long));
1781
                diag_sprintf(alias_buf,"%ld", hold_long_val);
1782
                break;
1783
#ifdef CYGPKG_REDBOOT_NETWORKING
1784
            case CONFIG_IP:
1785
                diag_sprintf(alias_buf,"%s", inet_ntoa((in_addr_t *)val_ptr));
1786
                break;
1787
            case CONFIG_ESA:
1788
                for (esa_ptr = 0;  esa_ptr < sizeof(enet_addr_t);  esa_ptr++) {
1789
                    diag_sprintf(alias_buf+(3*esa_ptr), "0x%02X", ((unsigned char *)val_ptr)[esa_ptr]);
1790
                    if (esa_ptr < (sizeof(enet_addr_t)-1)) diag_printf(":");
1791
                }
1792
                break;
1793
#endif
1794
            case CONFIG_SCRIPT:
1795
                return (char *) val_ptr;
1796
                break;
1797
            default:
1798
                return (char *)NULL;
1799
            }
1800
            return alias_buf;
1801
        }
1802
        return (char *)NULL;
1803
    }
1804
}
1805
 
1806
#endif //  CYGSEM_REDBOOT_FLASH_ALIASES
1807
 
1808
//
1809
// Write the in-memory copy of the configuration data to the flash device.
1810
//
1811
void
1812
flash_write_config(void)
1813
{
1814
#ifndef CYGSEM_REDBOOT_FLASH_COMBINED_FIS_AND_CONFIG
1815
    int stat;
1816
    void *err_addr;
1817
#endif
1818
 
1819
    config->len = sizeof(struct _config);
1820
    config->key1 = CONFIG_KEY1;
1821
    config->key2 = CONFIG_KEY2;
1822
    config->cksum = cyg_crc32((unsigned char *)config, sizeof(struct _config)-sizeof(config->cksum));
1823
    if (verify_action("Update RedBoot non-volatile configuration")) {
1824
#ifdef CYGSEM_REDBOOT_FLASH_COMBINED_FIS_AND_CONFIG
1825
        memcpy(fis_work_block, fis_addr, fisdir_size);
1826
        fis_update_directory();
1827
#else //  CYGSEM_REDBOOT_FLASH_COMBINED_FIS_AND_CONFIG
1828
#ifdef CYGSEM_REDBOOT_FLASH_LOCK_SPECIAL
1829
        // Insure [quietly] that the config page is unlocked before trying to update
1830
        flash_unlock((void *)cfg_base, cfg_size, (void **)&err_addr);
1831
#endif
1832
        if ((stat = flash_erase(cfg_base, cfg_size, (void **)&err_addr)) != 0) {
1833
            diag_printf("   initialization failed at %p: %s\n", err_addr, flash_errmsg(stat));
1834
        } else {
1835
            if ((stat = flash_program(cfg_base, (void *)config, sizeof(struct _config),
1836
                                      (void **)&err_addr)) != 0) {
1837
                diag_printf("Error writing config data at %p: %s\n",
1838
                            err_addr, flash_errmsg(stat));
1839
            }
1840
        }
1841
#ifdef CYGSEM_REDBOOT_FLASH_LOCK_SPECIAL
1842
        // Insure [quietly] that the config data is locked after the update
1843
        flash_lock((void *)cfg_base, cfg_size, (void **)&err_addr);
1844
#endif
1845
#endif
1846
    }
1847
}
1848
 
1849
//
1850
// Find the configuration entry for a particular key
1851
//
1852
static unsigned char *
1853
flash_lookup_config(char *key)
1854
{
1855
    unsigned char *dp;
1856
    int len;
1857
 
1858
    if (!config_ok) return (unsigned char *)NULL;
1859
 
1860
    dp = &config->config_data[0];
1861
    while (dp < &config->config_data[sizeof(config->config_data)]) {
1862
        len = 4 + CONFIG_OBJECT_KEYLEN(dp) + CONFIG_OBJECT_ENABLE_KEYLEN(dp) +
1863
            config_length(CONFIG_OBJECT_TYPE(dp));
1864
        if (strcmp(key, CONFIG_OBJECT_KEY(dp)) == 0) {
1865
            return dp;
1866
        }
1867
        dp += len;
1868
    }
1869
//    diag_printf("Can't find config data for '%s'\n", key);
1870
    return false;
1871
}
1872
 
1873
//
1874
// Retrieve a data object from the data base (in memory copy)
1875
//
1876
bool
1877
flash_get_config(char *key, void *val, int type)
1878
{
1879
    unsigned char *dp;
1880
    void *val_ptr;
1881
#ifdef CYGSEM_REDBOOT_FLASH_CONFIG_READONLY_FALLBACK
1882
    struct _config *save_config = 0;
1883
#endif
1884
 
1885
    if (!config_ok) return false;
1886
 
1887
    if ((dp = flash_lookup_config(key)) != (unsigned char *)NULL) {
1888
        if (CONFIG_OBJECT_TYPE(dp) == type) {
1889
            val_ptr = (void *)CONFIG_OBJECT_VALUE(dp);
1890
            switch (type) {
1891
                // Note: the data may be unaligned in the configuration data
1892
            case CONFIG_BOOL:
1893
                memcpy(val, val_ptr, sizeof(bool));
1894
                break;
1895
            case CONFIG_INT:
1896
                memcpy(val, val_ptr, sizeof(unsigned long));
1897
                break;
1898
#ifdef CYGPKG_REDBOOT_NETWORKING
1899
            case CONFIG_IP:
1900
                memcpy(val, val_ptr, sizeof(in_addr_t));
1901
                break;
1902
            case CONFIG_ESA:
1903
                memcpy(val, val_ptr, sizeof(enet_addr_t));
1904
                break;
1905
#endif
1906
            case CONFIG_STRING:
1907
            case CONFIG_SCRIPT:
1908
                // Just return a pointer to the script/line
1909
                *(unsigned char **)val = (unsigned char *)val_ptr;
1910
                break;
1911
            }
1912
        } else {
1913
            diag_printf("Request for config value '%s' - wrong type\n", key);
1914
        }
1915
        return true;
1916
    }
1917
#ifdef CYGSEM_REDBOOT_FLASH_CONFIG_READONLY_FALLBACK
1918
    // Did not find key. Is configuration data valid?
1919
    // Check to see if the config data is valid, if not, revert to 
1920
    // readonly mode, by setting config to readonly_config.  We
1921
    // will set it back before we leave this function.
1922
    if ( (config != readonly_config) && ((cyg_crc32((unsigned char *)config,
1923
               sizeof(struct _config)-sizeof(config->cksum)) != config->cksum) ||
1924
        (config->key1 != CONFIG_KEY1)|| (config->key2 != CONFIG_KEY2))) {
1925
        save_config = config;
1926
        config = readonly_config;
1927
        if ((cyg_crc32((unsigned char *)config,
1928
                       sizeof(struct _config)-sizeof(config->cksum)) != config->cksum) ||
1929
            (config->key1 != CONFIG_KEY1)|| (config->key2 != CONFIG_KEY2)) {
1930
            diag_printf("FLASH configuration checksum error or invalid key\n");
1931
            config = save_config;
1932
            return false;
1933
        }
1934
        else{
1935
            diag_printf("Getting config information in READONLY mode\n");
1936
            return flash_get_config(key, val, type);
1937
        }
1938
    }
1939
#endif
1940
    return false;
1941
}
1942
 
1943
//
1944
// Copy data into the config area
1945
//
1946
static void
1947
flash_config_insert_value(unsigned char *dp, struct config_option *opt)
1948
{
1949
    switch (opt->type) {
1950
        // Note: the data may be unaligned in the configuration data
1951
    case CONFIG_BOOL:
1952
        memcpy(dp, (void *)&opt->dflt, sizeof(bool));
1953
        break;
1954
    case CONFIG_INT:
1955
        memcpy(dp, (void *)&opt->dflt, sizeof(unsigned long));
1956
        break;
1957
#ifdef CYGPKG_REDBOOT_NETWORKING
1958
    case CONFIG_IP:
1959
        memcpy(dp, (void *)&opt->dflt, sizeof(in_addr_t));
1960
        break;
1961
    case CONFIG_ESA:
1962
        memcpy(dp, (void *)&opt->dflt, sizeof(enet_addr_t));
1963
        break;
1964
#endif
1965
    case CONFIG_STRING:
1966
        memcpy(dp, (void *)opt->dflt, config_length(CONFIG_STRING));
1967
        break;
1968
    case CONFIG_SCRIPT:
1969
        break;
1970
    }
1971
}
1972
 
1973
//
1974
// Add a new option to the database
1975
//
1976
bool
1977
flash_add_config(struct config_option *opt, bool update)
1978
{
1979
    unsigned char *dp, *kp;
1980
    int len, elen, size;
1981
 
1982
    // If data item is already present, just update it
1983
    // Note: only the data value can be thusly changed
1984
    if ((dp = flash_lookup_config(opt->key)) != (unsigned char *)NULL) {
1985
        flash_config_insert_value(CONFIG_OBJECT_VALUE(dp), opt);
1986
        if (update) {
1987
            flash_write_config();
1988
        }
1989
        return true;
1990
    }
1991
    // Add the data item
1992
    dp = &config->config_data[0];
1993
    size = 0;
1994
    while (size < sizeof(config->config_data)) {
1995
        if (CONFIG_OBJECT_TYPE(dp) == CONFIG_EMPTY) {
1996
            kp = opt->key;
1997
            len = strlen(kp) + 1;
1998
            size += len + 2 + 2 + config_length(opt->type);
1999
            if (opt->enable) {
2000
                elen = strlen(opt->enable) + 1;
2001
                size += elen;
2002
            } else {
2003
                elen = 0;
2004
            }
2005
            if (size > sizeof(config->config_data)) {
2006
                break;
2007
            }
2008
            CONFIG_OBJECT_TYPE(dp) = opt->type;
2009
            CONFIG_OBJECT_KEYLEN(dp) = len;
2010
            CONFIG_OBJECT_ENABLE_SENSE(dp) = opt->enable_sense;
2011
            CONFIG_OBJECT_ENABLE_KEYLEN(dp) = elen;
2012
            dp = CONFIG_OBJECT_KEY(dp);
2013
            while (*kp) *dp++ += *kp++;
2014
            *dp++ = '\0';
2015
            if (elen) {
2016
                kp = opt->enable;
2017
                while (*kp) *dp++ += *kp++;
2018
                *dp++ = '\0';
2019
            }
2020
            flash_config_insert_value(dp, opt);
2021
            if (update) {
2022
                flash_write_config();
2023
            }
2024
            return true;
2025
        } else {
2026
            len = 4 + CONFIG_OBJECT_KEYLEN(dp) + CONFIG_OBJECT_ENABLE_KEYLEN(dp) +
2027
                config_length(CONFIG_OBJECT_TYPE(dp));
2028
            dp += len;
2029
            size += len;
2030
        }
2031
    }
2032
    diag_printf("No space to add '%s'\n", opt->key);
2033
    return false;
2034
}
2035
 
2036
//
2037
// Reset/initialize configuration data - used only when starting from scratch
2038
//
2039
static void
2040
config_init(void)
2041
{
2042
    // Well known option strings
2043
    struct config_option *optend = __CONFIG_options_TAB_END__;
2044
    struct config_option *opt = __CONFIG_options_TAB__;
2045
 
2046
    memset(config, 0, sizeof(struct _config));
2047
    while (opt != optend) {
2048
        if (!flash_add_config(opt, false)) {
2049
            return;
2050
        }
2051
        opt++;
2052
    }
2053
    config_ok = true;
2054
}
2055
 
2056
//
2057
// Attempt to get configuration information from the FLASH.
2058
// If available (i.e. good checksum, etc), initialize "known"
2059
// values for later use.
2060
//
2061
static void
2062
load_flash_config(void)
2063
{
2064
    bool use_boot_script;
2065
 
2066
    config_ok = false;
2067
    script = (unsigned char *)0;
2068
    if (!do_flash_init()) return;
2069
    config = (struct _config *)(workspace_end-sizeof(struct _config));
2070
    backup_config = (struct _config *)((CYG_ADDRESS)config-sizeof(struct _config));
2071
    workspace_end = (unsigned char *)backup_config;
2072
    cfg_size = (flash_block_size > sizeof(struct _config)) ?
2073
        sizeof(struct _config) :
2074
        _rup(sizeof(struct _config), flash_block_size);
2075
#ifdef CYGSEM_REDBOOT_FLASH_COMBINED_FIS_AND_CONFIG
2076
    cfg_size = _rup(cfg_size, sizeof(struct fis_image_desc));
2077
    if ((flash_block_size-cfg_size) < 8*sizeof(struct fis_image_desc)) {
2078
        // Too bad this can't be checked at compile/build time
2079
        diag_printf("Sorry, FLASH config exceeds available space in FIS directory\n");
2080
        return;
2081
    }
2082
    fisdir_size = flash_block_size - cfg_size;
2083
    cfg_base = (void *)(((CYG_ADDRESS)fis_addr + flash_block_size) - cfg_size);
2084
#else
2085
    if (CYGNUM_REDBOOT_FLASH_CONFIG_BLOCK < 0) {
2086
        cfg_base = (void *)((CYG_ADDRESS)flash_end + 1 -
2087
           _rup(_rup((-CYGNUM_REDBOOT_FLASH_CONFIG_BLOCK*flash_block_size), cfg_size), flash_block_size));
2088
    } else {
2089
        cfg_base = (void *)((CYG_ADDRESS)flash_start +
2090
           _rup(_rup((CYGNUM_REDBOOT_FLASH_CONFIG_BLOCK*flash_block_size), cfg_size), flash_block_size));
2091
    }
2092
#endif
2093
#ifdef CYGSEM_REDBOOT_FLASH_CONFIG_READONLY_FALLBACK
2094
    readonly_config = cfg_base;
2095
#endif
2096
    memcpy(config, cfg_base, sizeof(struct _config));
2097
    if ((cyg_crc32((unsigned char *)config,
2098
                   sizeof(struct _config)-sizeof(config->cksum)) != config->cksum) ||
2099
        (config->key1 != CONFIG_KEY1)|| (config->key2 != CONFIG_KEY2)) {
2100
        diag_printf("FLASH configuration checksum error or invalid key\n");
2101
        config_init();
2102
        return;
2103
    }
2104
    config_ok = true;
2105
    flash_get_config("boot_script", &use_boot_script, CONFIG_BOOL);
2106
    if (use_boot_script) {
2107
        flash_get_config("boot_script_data", &script, CONFIG_SCRIPT);
2108
        flash_get_config("boot_script_timeout", &script_timeout, CONFIG_INT);
2109
    }
2110
#ifdef CYGSEM_REDBOOT_VARIABLE_BAUD_RATE
2111
    if (flash_get_config("console_baud_rate", &console_baud_rate, CONFIG_INT)) {
2112
        extern int set_console_baud_rate(int);
2113
        set_console_baud_rate(console_baud_rate);
2114
    }
2115
#endif
2116
}
2117
 
2118
RedBoot_init(load_flash_config, RedBoot_INIT_FIRST);
2119
 
2120
#endif // CYGSEM_REDBOOT_FLASH_CONFIG
2121
 
2122
// EOF flash.c

powered by: WebSVN 2.1.0

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