source: trunk/tools/firmware-utils/src/mkzynfw.c @ 8352

Last change on this file since 8352 was 8352, checked in by juhosg, 9 years ago

remove case sensitivity from the board name checking

  • Property svn:eol-style set to native
  • Property svn:executable set to *
  • Property svn:keywords set to Author Date Id Revision
File size: 19.5 KB
Line 
1/*
2 *  $Id$
3 *
4 *  Copyright (C) 2007 OpenWrt.org
5 *  Copyright (C) 2007 Gabor Juhos <juhosg@freemail.hu>
6 *
7 *  This code was based on the information of the ZyXEL's firmware
8 *  image format written by Kolja Waschk, can be found at:
9 *  http://www.ixo.de/info/zyxel_uclinux
10 *
11 *  This program is free software; you can redistribute it and/or
12 *  modify it under the terms of the GNU General Public License
13 *  as published by the Free Software Foundation; either version 2
14 *  of the License, or (at your option) any later version.
15 *
16 *  This program is distributed in the hope that it will be useful,
17 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
18 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19 *  GNU General Public License for more details.
20 *
21 *  You should have received a copy of the GNU General Public License
22 *  along with this program; if not, write to the
23 *  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
24 *  Boston, MA  02110-1301, USA.
25 */
26
27#include <stdio.h>
28#include <stdlib.h>
29#include <stdint.h>
30#include <string.h>
31#include <unistd.h>     /* for unlink() */
32#include <libgen.h>
33#include <getopt.h>     /* for getopt() */
34#include <stdarg.h>
35#include <errno.h>
36#include <sys/stat.h>
37#include <endian.h>     /* for __BYTE_ORDER */
38#if defined(__CYGWIN__)
39#  include <byteswap.h>
40#endif
41
42#include "zynos.h"
43
44#if (__BYTE_ORDER == __LITTLE_ENDIAN)
45#  define HOST_TO_LE16(x)       (x)
46#  define HOST_TO_LE32(x)       (x)
47#  define LE16_TO_HOST(x)       (x)
48#  define LE32_TO_HOST(x)       (x)
49#  define HOST_TO_BE16(x)       bswap_16(x)
50#  define HOST_TO_BE32(x)       bswap_32(x)
51#  define BE16_TO_HOST(x)       bswap_16(x)
52#  define BE32_TO_HOST(x)       bswap_32(x)
53#else
54#  define HOST_TO_BE16(x)       (x)
55#  define HOST_TO_BE32(x)       (x)
56#  define BE16_TO_HOST(x)       (x)
57#  define BE32_TO_HOST(x)       (x)
58#  define HOST_TO_LE16(x)       bswap_16(x)
59#  define HOST_TO_LE32(x)       bswap_32(x)
60#  define LE16_TO_HOST(x)       bswap_16(x)
61#  define LE32_TO_HOST(x)       bswap_32(x)
62#endif
63
64#define ALIGN(x,y)      (((x)+((y)-1)) & ~((y)-1))
65
66#define MAX_NUM_BLOCKS  8
67#define MAX_ARG_COUNT   32
68#define MAX_ARG_LEN     1024
69#define FILE_BUF_LEN    (16*1024)
70
71
72struct csum_state{
73        int             odd;
74        uint32_t        sum;
75        uint32_t        tmp;
76};
77
78struct fw_block {
79        uint32_t        align;          /* alignment of this block */
80        char            *file_name;     /* name of the file */
81        uint32_t        file_size;      /* length of the file */
82        char            *mmap_name;     /* name in the MMAP table */
83        int             type;           /* block type */
84        uint32_t        padlen;
85        uint8_t         padc;
86};
87
88#define BLOCK_TYPE_BOOTEXT      0
89#define BLOCK_TYPE_RAW          1
90
91struct fw_mmap {
92        uint32_t        addr;
93        uint32_t        size;
94        uint32_t        user_addr;
95        uint32_t        user_size;
96};
97#define MMAP_DATA_SIZE  1024
98#define MMAP_ALIGN      16
99
100struct board_info {
101        char *name;             /* model name */
102        char *desc;             /* description */
103        uint16_t model;         /* model id */
104        uint32_t flash_base;    /* flash base address */
105        uint32_t flash_size;    /* board flash size */
106        uint32_t code_start;    /* code start address */
107        uint32_t fw_offs;       /* offset of the firmware within the flash */
108};
109
110/*
111 * Globals
112 */
113char *progname;
114char *ofname = NULL;
115int verblevel = 0;
116
117struct board_info *board = NULL;
118
119struct fw_block blocks[MAX_NUM_BLOCKS];
120struct fw_block *bootext_block = NULL;
121int num_blocks = 0;
122
123#define ADM5120_FLASH_BASE      0xBFC00000
124#define ADM5120_CODE_START      0x80008000
125
126/* TODO: check values for AR7 */
127#define AR7_FLASH_BASE          0xB0000000
128#define AR7_CODE_START          0x94008000
129
130#define BOARD(n, d, m, fb, fs, cs, fo) { \
131        .name = (n), .desc=(d), .model = (m), \
132        .flash_base = (fb), .flash_size = (fs)<<20, \
133        .code_start = (cs), .fw_offs = (fo) \
134        }
135
136#define ADMBOARD1(n, d, m, fs) BOARD(n, d, m, \
137        ADM5120_FLASH_BASE, fs, ADM5120_CODE_START, 0x8000)
138
139#define ADMBOARD2(n, d, m, fs) BOARD(n, d, m, \
140        ADM5120_FLASH_BASE, fs, ADM5120_CODE_START, 0x10000)
141
142#define AR7BOARD1(n, d, m, fs) BOARD(n, d, m, \
143        AR7_FLASH_BASE, fs, AR7_CODE_START, 0x8000)
144
145static struct board_info boards[] = {
146        /*
147         * Infineon/ADMtek ADM5120 based boards
148         */
149        ADMBOARD2("ES-2024A",   "ZyXEL ES-2024A", ZYNOS_MODEL_ES_2024A, 4),
150        ADMBOARD2("ES-2024PWR", "ZyXEL ES-2024PWR", ZYNOS_MODEL_ES_2024PWR, 4),
151        ADMBOARD2("ES-2108",    "ZyXEL ES-2108", ZYNOS_MODEL_ES_2108, 4),
152        ADMBOARD2("ES-2108-F",  "ZyXEL ES-2108-F", ZYNOS_MODEL_ES_2108_F, 4),
153        ADMBOARD2("ES-2108-G",  "ZyXEL ES-2108-G", ZYNOS_MODEL_ES_2108_G, 4),
154        ADMBOARD2("ES-2108-LC", "ZyXEL ES-2108-LC", ZYNOS_MODEL_ES_2108_LC, 4),
155        ADMBOARD2("ES-2108PWR", "ZyXEL ES-2108PWR", ZYNOS_MODEL_ES_2108PWR, 4),
156        ADMBOARD1("HS-100",     "ZyXEL HomeSafe 100", ZYNOS_MODEL_HS_100, 2),
157        ADMBOARD1("HS-100W",    "ZyXEL HomeSafe 100W", ZYNOS_MODEL_HS_100W, 2),
158        ADMBOARD1("P-334",      "ZyXEL Prestige 334", ZYNOS_MODEL_P_334, 2),
159        ADMBOARD1("P-334U",     "ZyXEL Prestige 334U", ZYNOS_MODEL_P_334U, 4),
160        ADMBOARD1("P-334W",     "ZyXEL Prestige 334W", ZYNOS_MODEL_P_334W, 2),
161        ADMBOARD1("P-334WH",    "ZyXEL Prestige 334WH", ZYNOS_MODEL_P_334WH, 4),
162        ADMBOARD1("P-334WHD",   "ZyXEL Prestige 334WHD", ZYNOS_MODEL_P_334WHD, 4),
163        ADMBOARD1("P-334WT",    "ZyXEL Prestige 334WT", ZYNOS_MODEL_P_334WT, 4),
164        ADMBOARD1("P-335",      "ZyXEL Prestige 335", ZYNOS_MODEL_P_335, 4),
165        ADMBOARD1("P-335Plus",  "ZyXEL Prestige 335Plus", ZYNOS_MODEL_P_335PLUS, 4),
166        ADMBOARD1("P-335U",     "ZyXEL Prestige 335U", ZYNOS_MODEL_P_335U, 4),
167        ADMBOARD1("P-335WT",    "ZyXEL Prestige 335WT", ZYNOS_MODEL_P_335WT, 4),
168#if 0
169        /*
170         * Texas Instruments AR7 based boards
171         */
172        AR7BOARD1("P-660H-61",  "ZyXEL P-660H-61", ZYNOS_MODEL_P_660H_61, 2),
173        AR7BOARD1("P-660H-63",  "ZyXEL P-660H-63", ZYNOS_MODEL_P_660H_63, 2),
174        AR7BOARD1("P-660H-D1",  "ZyXEL P-660H-D1", ZYNOS_MODEL_P_660H_D1, 2),
175        AR7BOARD1("P-660H-D3",  "ZyXEL P-660H-D3", ZYNOS_MODEL_P_660H_D3, 2),
176        AR7BOARD1("P-660HW-61", "ZyXEL P-660HW-61", ZYNOS_MODEL_P_660HW_61, 2),
177        AR7BOARD1("P-660HW-63", "ZyXEL P-660HW-63", ZYNOS_MODEL_P_660HW_63, 2),
178        AR7BOARD1("P-660HW-67", "ZyXEL P-660HW-67", ZYNOS_MODEL_P_660HW_67, 2),
179        AR7BOARD1("P-660HW-D1", "ZyXEL P-660HW-D1", ZYNOS_MODEL_P_660HW_D1, 2),
180        AR7BOARD1("P-660HW-D3", "ZyXEL P-660HW-D3", ZYNOS_MODEL_P_660HW_D3, 2),
181        AR7BOARD1("P-660R-61",  "ZyXEL P-660R-61", ZYNOS_MODEL_P_660R_61, 2),
182        AR7BOARD1("P-660R-61C", "ZyXEL P-660R-61C", ZYNOS_MODEL_P_660R_61C, 2),
183        AR7BOARD1("P-660R-63",  "ZyXEL P-660R-63", ZYNOS_MODEL_P_660R_63, 2),
184        AR7BOARD1("P-660R-63C", "ZyXEL P-660R-63C", ZYNOS_MODEL_P_660R_63C, 2),
185        AR7BOARD1("P-660R-67",  "ZyXEL P-660R-67", ZYNOS_MODEL_P_660R_67, 2),
186        AR7BOARD1("P-660R-D1",  "ZyXEL P-660R-D1", ZYNOS_MODEL_P_660R_D1, 2),
187        AR7BOARD1("P-660R-D3",  "ZyXEL P-660R-D3", ZYNOS_MODEL_P_660R_D3, 2),
188#endif
189        {.name = NULL}
190};
191
192/*
193 * Message macros
194 */
195#define ERR(fmt, ...) do { \
196        fflush(0); \
197        fprintf(stderr, "[%s] *** error: " fmt "\n", progname, ## __VA_ARGS__ ); \
198} while (0)
199
200#define ERRS(fmt, ...) do { \
201        int save = errno; \
202        fflush(0); \
203        fprintf(stderr, "[%s] *** error: " fmt ", %s\n", progname, ## __VA_ARGS__ \
204                , strerror(save)); \
205} while (0)
206
207#define WARN(fmt, ...) do { \
208        fprintf(stderr, "[%s] *** warning: " fmt "\n", progname, ## __VA_ARGS__ ); \
209} while (0)
210
211#define DBG(lev, fmt, ...) do { \
212        if (verblevel < lev) \
213                break;\
214        fprintf(stderr, "[%s] " fmt "\n", progname, ## __VA_ARGS__ ); \
215} while (0)
216
217#define ERR_FATAL               -1
218#define ERR_INVALID_IMAGE       -2
219
220/*
221 * Helper routines
222 */
223void
224usage(int status)
225{
226        FILE *stream = (status != EXIT_SUCCESS) ? stderr : stdout;
227        struct board_info *board;
228
229        fprintf(stream, "Usage: %s [OPTIONS...]\n", progname);
230        fprintf(stream,
231"\n"
232"Options:\n"
233"  -B <board>      create image for the board specified with <board>.\n"
234"                  valid <board> values:\n"
235        );
236        for (board = boards; board->name != NULL; board++){
237                fprintf(stream,
238"                    %-12s= %s\n",
239                 board->name, board->desc);
240        };
241        fprintf(stream,
242"  -b <file>[:<align>]\n"
243"                  add boot extension block to the image\n"
244"  -r <file>[:<align>]\n"
245"                  add raw block to the image\n"
246"  -o <file>       write output to the file <file>\n"
247"  -h              show this screen\n"
248        );
249
250        exit(status);
251}
252
253
254/*
255 * argument parsing
256 */
257int
258str2u32(char *arg, uint32_t *val)
259{
260        char *err = NULL;
261        uint32_t t;
262       
263        errno=0;
264        t = strtoul(arg, &err, 0);
265        if (errno || (err==arg) || ((err != NULL) && *err)) {
266                return -1;
267        }
268
269        *val = t;
270        return 0;
271}
272
273
274int
275str2u16(char *arg, uint16_t *val)
276{
277        char *err = NULL;
278        uint32_t t;
279
280        errno=0;
281        t = strtoul(arg, &err, 0);
282        if (errno || (err==arg) || ((err != NULL) && *err) || (t >= 0x10000)) {
283                return -1;
284        }
285       
286        *val = t & 0xFFFF;
287        return 0;
288}
289
290int
291str2u8(char *arg, uint8_t *val)
292{
293        char *err = NULL;
294        uint32_t t;
295
296        errno=0;
297        t = strtoul(arg, &err, 0);
298        if (errno || (err==arg) || ((err != NULL) && *err) || (t >= 0x100)) {
299                return -1;
300        }
301       
302        *val = t & 0xFF;
303        return 0;
304}
305
306int
307str2sig(char *arg, uint32_t *sig)
308{
309        if (strlen(arg) != 4)
310                return -1;
311
312        *sig = arg[0] | (arg[1] << 8) | (arg[2] << 16) | (arg[3] << 24);
313       
314        return 0;
315}
316
317
318int
319parse_arg(char *arg, char *buf, char *argv[])
320{
321        int res = 0;
322        size_t argl;
323        char *tok;
324        char **ap = &buf;
325        int i;
326
327        memset(argv, 0, MAX_ARG_COUNT * sizeof(void *));
328
329        if ((arg == NULL)) {
330                /* no arguments */
331                return 0;
332        }
333
334        argl = strlen(arg);
335        if (argl == 0) {
336                /* no arguments */
337                return 0;
338        }
339
340        if (argl >= MAX_ARG_LEN) {
341                /* argument is too long */
342                argl = MAX_ARG_LEN-1;
343        }
344
345        memcpy(buf, arg, argl);
346        buf[argl] = '\0';
347
348        for (i = 0; i < MAX_ARG_COUNT; i++) {
349                tok = strsep(ap, ":");
350                if (tok == NULL) {
351                        break;
352                }
353#if 0
354                else if (tok[0] == '\0') {
355                        break;
356                }
357#endif
358                argv[i] = tok;
359                res++;
360        }
361
362        return res;
363}
364
365
366int
367required_arg(char c, char *arg)
368{
369        if (arg == NULL || *arg != '-')
370                return 0;
371
372        ERR("option -%c requires an argument\n", c);
373        return -1;
374}
375
376
377int
378is_empty_arg(char *arg)
379{
380        int ret = 1;
381        if (arg != NULL) {
382                if (*arg) ret = 0;
383        };
384        return ret;
385}
386
387
388void
389csum_init(struct csum_state *css)
390{
391        css->odd = 0;
392        css->sum = 0;
393        css->tmp = 0;
394}
395
396
397void
398csum_update(uint8_t *p, uint32_t len, struct csum_state *css)
399{
400        if (len == 0)
401                return;
402
403        if (css->odd) {
404                css->sum += (css->tmp << 8) + p[0];
405                if (css->sum > 0xFFFF) {
406                        css->sum += 1;
407                        css->sum &= 0xFFFF;
408                }
409                css->odd = 0;
410                len--;
411                p++;
412        }
413
414        for ( ; len > 1; len -= 2, p +=2 ) {
415                css->sum  += (p[0] << 8) + p[1];
416                if (css->sum > 0xFFFF) {
417                        css->sum += 1;
418                        css->sum &= 0xFFFF;
419                }
420        }
421
422        if (len == 1){
423                css->tmp = p[0];
424                css->odd = 1;
425        }
426}
427
428
429uint16_t
430csum_get(struct csum_state *css)
431{
432        char pad = 0;
433
434        csum_update(&pad, 1, css);
435        return css->sum;
436}
437
438uint16_t
439csum_buf(uint8_t *p, uint32_t len)
440{
441        struct csum_state css;
442
443        csum_init(&css);
444        csum_update(p, len, &css);
445        return csum_get(&css);
446
447}
448
449/*
450 * routines to write data to the output file
451 */
452int
453write_out_data(FILE *outfile, uint8_t *data, size_t len,
454                struct csum_state *css)
455{
456        errno = 0;
457
458        fwrite(data, len, 1, outfile);
459        if (errno) {
460                ERR("unable to write output file");
461                return -1;
462        }
463
464        if (css) {
465                csum_update(data, len, css);
466        }
467
468        return 0;
469}
470
471
472int
473write_out_padding(FILE *outfile, size_t len, uint8_t padc,
474                 struct csum_state *css)
475{
476        uint8_t buf[512];
477        size_t buflen = sizeof(buf);
478
479        memset(buf, padc, buflen);
480        while (len > 0) {
481                if (len < buflen)
482                        buflen = len;
483
484                if (write_out_data(outfile, buf, buflen, css))
485                        return -1;
486                       
487                len -= buflen;
488        }
489
490        return 0;
491}
492
493
494int
495write_out_data_align(FILE *outfile, uint8_t *data, size_t len, size_t align,
496                struct csum_state *css)
497{
498        size_t padlen;
499        int res;
500
501        res = write_out_data(outfile, data, len, css);
502        if (res)
503                return res;
504
505        padlen = ALIGN(len,align) - len;
506        res = write_out_padding(outfile, padlen, 0xFF, css);
507
508        return res;
509}
510
511
512int
513write_out_header(FILE *outfile, struct zyn_rombin_hdr *hdr)
514{
515        struct zyn_rombin_hdr t;
516
517        errno = 0;
518        if (fseek(outfile, 0, SEEK_SET) != 0) {
519                ERRS("fseek failed on output file");
520                return -1;
521        }
522
523        /* setup temporary header fields */
524        memset(&t,0, sizeof(t));
525        t.addr = HOST_TO_BE32(hdr->addr);
526        memcpy(&t.sig, ROMBIN_SIGNATURE, ROMBIN_SIG_LEN);
527        t.type = hdr->type;
528        t.flags = hdr->flags;
529        t.osize = HOST_TO_BE32(hdr->osize);
530        t.csize = HOST_TO_BE32(hdr->csize);
531        t.ocsum = HOST_TO_BE16(hdr->ocsum);
532        t.ccsum = HOST_TO_BE16(hdr->ccsum);
533        t.mmap_addr = HOST_TO_BE32(hdr->mmap_addr);
534
535        return write_out_data(outfile, (uint8_t *)&t, sizeof(t), NULL);
536}
537
538
539int
540write_out_mmap(FILE *outfile, struct fw_mmap *mmap, struct csum_state *css)
541{
542        struct zyn_mmt_hdr *mh;
543        uint8_t buf[MMAP_DATA_SIZE];
544        uint32_t user_size;
545        char *data;
546        int res;
547
548        memset(buf,0,sizeof(buf));
549
550        mh = (struct zyn_mmt_hdr *)buf;
551
552        /* TODO: needs to recreate the memory map too? */
553        mh->count=0;
554       
555        /* Build user data section */
556        data = buf+sizeof(*mh);
557        data += sprintf(data,"Model 1 %d", BE16_TO_HOST(board->model));
558        *data++ = '\0';
559        /* TODO: make hardware version configurable? */
560        data += sprintf(data,"HwVerRange 2 %d %d", 0, 0);
561        *data++ = '\0';
562
563        user_size = (uint8_t *)data - buf;
564        mh->user_start= HOST_TO_BE32(mmap->addr+sizeof(*mh));
565        mh->user_end= HOST_TO_BE32(mmap->addr+user_size);
566        mh->csum = HOST_TO_BE16(csum_buf(buf+sizeof(*mh), user_size));
567
568        res = write_out_data(outfile, buf, sizeof(buf), css);
569       
570        return res;
571}
572
573
574int
575block_stat_file(struct fw_block *block)
576{
577        struct stat st;
578        int res;
579
580        if (block->file_name == NULL)
581                return 0;
582
583        res = stat(block->file_name, &st);
584        if (res){
585                ERRS("stat failed on %s", block->file_name);
586                return res;
587        }
588
589        block->file_size = st.st_size;
590        return 0;
591}
592
593
594int
595write_out_file(FILE *outfile, char *name, size_t len, struct csum_state *css)
596{
597        char buf[FILE_BUF_LEN];
598        size_t buflen = sizeof(buf);
599        FILE *f;
600        int res;
601
602        DBG(2, "writing out file, name=%s, len=%d",
603                name, len);
604
605        errno = 0;
606        f = fopen(name,"r");
607        if (errno) {
608                ERRS("unable to open file: %s", name);
609                return -1;
610        }
611
612        while (len > 0) {
613                if (len < buflen)
614                        buflen = len;
615
616                /* read data from source file */
617                errno = 0;
618                fread(buf, buflen, 1, f);
619                if (errno != 0) {
620                        ERRS("unable to read from file: %s",name);
621                        res = -1;
622                        break;
623                }
624
625                res = write_out_data(outfile, buf, buflen, css);
626                if (res)
627                        break;
628
629                len -= buflen;
630        }
631
632        fclose(f);
633        return res;
634}
635
636
637int
638write_out_block(FILE *outfile, struct fw_block *block, struct csum_state *css)
639{
640        int res;
641       
642        if (block == NULL)
643                return 0;
644
645        if (block->file_name == NULL)
646                return 0;
647
648        if (block->file_size == 0)
649                return 0;
650
651        res = write_out_file(outfile, block->file_name, 
652                        block->file_size, css);
653        return res;
654}
655
656
657int
658write_out_image(FILE *outfile)
659{
660        struct fw_block *block;
661        struct fw_mmap mmap;
662        struct zyn_rombin_hdr hdr;
663        struct csum_state css;
664        int i, res;
665        uint32_t offset;
666        uint32_t padlen;
667
668        /* setup header fields */
669        hdr.addr = board->code_start;
670        hdr.type = OBJECT_TYPE_BOOTEXT;
671        hdr.flags = ROMBIN_FLAG_40;
672
673        res = write_out_header(outfile, &hdr);
674        if (res)
675                return res;
676
677        offset = sizeof(hdr);
678
679        csum_init(&css);
680        res = write_out_block(outfile, bootext_block, &css);
681        if (res)
682                return res;
683
684        offset += bootext_block->file_size;
685
686        padlen = ALIGN(offset,MMAP_ALIGN) - offset;
687        res = write_out_padding(outfile, padlen, 0xFF, &css);
688        if (res)
689                return res;
690
691        offset += padlen;
692
693        mmap.addr = board->flash_base + board->fw_offs + offset;
694        hdr.mmap_addr = mmap.addr;
695        res = write_out_mmap(outfile, &mmap, &css);
696        if (res)
697                return res;
698
699        offset += MMAP_DATA_SIZE;
700        hdr.osize = offset - sizeof(hdr);
701        hdr.ocsum = csum_get(&css);
702
703        for (i=0; i < num_blocks; i++) {
704                block = &blocks[i];
705
706                if (block->type == BLOCK_TYPE_BOOTEXT)
707                        continue;
708
709                padlen = ALIGN(offset,block->align) - offset;
710                res = write_out_padding(outfile, padlen, 0xFF, NULL);
711                if (res)
712                        return res;
713                offset += padlen;
714
715                res = write_out_block(outfile, block, NULL);
716                if (res)
717                        return res;
718                offset += block->file_size;
719        }
720
721        res = write_out_header(outfile, &hdr);
722
723        return res;
724}
725
726
727struct board_info *
728find_board(char *name)
729{
730        struct board_info *ret;
731        struct board_info *board;
732
733        ret = NULL;
734        for (board = boards; board->name != NULL; board++){
735                if (strcasecmp(name, board->name) == 0) {
736                        ret = board;
737                        break;
738                }
739        };
740
741        return ret;
742}
743
744
745int
746parse_opt_board(char ch, char *arg)
747{
748
749        DBG(1,"parsing board option: -%c %s", ch, arg);
750
751        if (board != NULL) {
752                ERR("only one board option allowed");
753                return -1;
754        }
755
756        if (required_arg(ch, arg))
757                return -1;
758
759        board = find_board(arg);
760        if (board == NULL){
761                ERR("invalid/unknown board specified: %s", arg);
762                return -1;
763        }
764
765        return 0;
766}
767
768
769int
770parse_opt_ofname(char ch, char *arg)
771{
772
773        if (ofname != NULL) {
774                ERR("only one output file allowed");
775                return -1;
776        }
777
778        if (required_arg(ch, arg)) 
779                return -1;
780
781        ofname = arg;
782
783        return 0;
784}
785
786
787int
788parse_opt_block(char ch, char *arg)
789{
790        char buf[MAX_ARG_LEN];
791        char *argv[MAX_ARG_COUNT];
792        int argc;
793        char *p;
794        struct fw_block *block;
795        int i;
796
797        if ( num_blocks > MAX_NUM_BLOCKS ) {
798                ERR("too many blocks specified");
799                return -1;
800        }
801
802        block = &blocks[num_blocks++];
803       
804        /* setup default field values */
805        block->padc = 0xFF;
806
807        switch(ch) {
808        case 'b':
809                if (bootext_block) {
810                        ERR("only one boot extension block allowed");
811                        break;
812                }
813                block->type = BLOCK_TYPE_BOOTEXT;
814                bootext_block = block;
815                break;
816        case 'r':
817                block->type = BLOCK_TYPE_RAW;
818                break;
819        }
820
821        argc = parse_arg(arg, buf, argv);
822
823        i = 0;
824        p = argv[i++];
825        if (is_empty_arg(p)) {
826                ERR("no file specified in %s", arg);
827                return -1;
828        } else {
829                block->file_name = strdup(p);
830                if (block->file_name == NULL) {
831                        ERR("not enough memory");
832                        return -1;
833                }
834        }
835
836        if(block->type == BLOCK_TYPE_BOOTEXT)
837                return 0;
838
839        p = argv[i++];
840        if (!is_empty_arg(p)) {
841                if (str2u32(p, &block->align) != 0) {
842                        ERR("invalid block align in %s", arg);
843                        return -1;
844                }
845        }
846
847        return 0;
848}
849
850
851int
852calc_block_offsets(int type, uint32_t *offset)
853{
854        struct fw_block *block;
855        uint32_t next_offs;
856        uint32_t avail;
857        int i, res;
858
859        DBG(1,"calculating block offsets, starting with %lu",
860                *offset);
861
862        res = 0;
863        for (i = 0; i < num_blocks; i++) {
864                block = &blocks[i];
865
866                if (block->type != type)
867                        continue;
868
869                next_offs = ALIGN(*offset, block->align);
870                avail = board->flash_size - board->fw_offs - next_offs;
871                if (next_offs + block->file_size > avail) {
872                        ERR("file %s is too big, offset = %u, size=%u,"
873                                " align = %u", block->file_name, 
874                                (unsigned)next_offs, 
875                                (unsigned)block->file_size, 
876                                (unsigned)block->align);
877                        res = -1;
878                        break;
879                }
880
881                block->padlen = next_offs - *offset;
882                *offset += block->file_size;
883        }
884       
885        return res;
886}
887
888int
889process_blocks(void)
890{
891        struct fw_block *block;
892        uint32_t offset;
893        int i;
894        int res;
895
896        /* collecting file stats */
897        for (i = 0; i < num_blocks; i++) {
898                block = &blocks[i];
899                res = block_stat_file(block);
900                if (res)
901                        return res;
902        }
903
904        offset = board->fw_offs + bootext_block->file_size;
905        res = calc_block_offsets(BLOCK_TYPE_RAW, &offset);
906
907        return res;
908}
909
910
911int
912main(int argc, char *argv[])
913{
914        int optinvalid = 0;   /* flag for invalid option */
915        int c;
916        int res = EXIT_FAILURE;
917
918        FILE *outfile;
919       
920        progname=basename(argv[0]);
921
922        opterr = 0;  /* could not print standard getopt error messages */
923        while ( 1 ) {
924                optinvalid = 0;
925               
926                c = getopt(argc, argv, "b:B:ho:r:v");
927                if (c == -1)
928                        break;
929
930                switch (c) {
931                case 'b':
932                case 'r':
933                        optinvalid = parse_opt_block(c,optarg);
934                        break;
935                case 'B':
936                        optinvalid = parse_opt_board(c,optarg);
937                        break;
938                case 'o':
939                        optinvalid = parse_opt_ofname(c,optarg);
940                        break;
941                case 'v':
942                        verblevel++;
943                        break;
944                case 'h':
945                        usage(EXIT_SUCCESS);
946                        break;
947                default:
948                        optinvalid = 1;
949                        break;
950                }
951                if (optinvalid != 0 ) {
952                        ERR("invalid option: -%c", optopt);
953                        goto out;
954                }
955        }
956
957        if (board == NULL) {
958                ERR("no board specified");
959                goto out;
960        }
961
962        if (ofname == NULL) {
963                ERR("no output file specified");
964                goto out;
965        }
966
967        if (optind < argc) {
968                ERR("invalid option: %s", argv[optind]);
969                goto out;
970        }
971       
972
973        if (process_blocks() != 0) {
974                goto out;
975        }
976
977        outfile = fopen(ofname, "w");
978        if (outfile == NULL) {
979                ERRS("could not open \"%s\" for writing", ofname);
980                goto out;
981        }
982
983        if (write_out_image(outfile) != 0)
984                goto out_flush;
985
986        DBG(1,"Image file %s completed.", ofname);
987
988        res = EXIT_SUCCESS;
989
990out_flush:
991        fflush(outfile);
992        fclose(outfile);
993        if (res != EXIT_SUCCESS) {
994                unlink(ofname);
995        }
996out:
997        return res;
998}
Note: See TracBrowser for help on using the repository browser.