Root/tools/firmware-utils/src/mkcsysimg.c

1/*
2 *
3 * Copyright (C) 2007-2009 Gabor Juhos <juhosg@openwrt.org>
4 *
5 * This program was based on the code found in various Linux
6 * source tarballs released by Edimax for it's devices.
7 * Original author: David Hsu <davidhsu@realtek.com.tw>
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License
11 * as published by the Free Software Foundation; either version 2
12 * of the License, or (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the
21 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
22 * Boston, MA 02110-1301, USA.
23 */
24
25#include <stdio.h>
26#include <stdlib.h>
27#include <stdint.h>
28#include <string.h>
29#include <unistd.h> /* for unlink() */
30#include <libgen.h>
31#include <getopt.h> /* for getopt() */
32#include <stdarg.h>
33#include <errno.h>
34#include <sys/stat.h>
35#include <endian.h> /* for __BYTE_ORDER */
36#if defined(__CYGWIN__)
37# include <byteswap.h>
38#endif
39
40#include "csysimg.h"
41
42#if (__BYTE_ORDER == __LITTLE_ENDIAN)
43# define HOST_TO_LE16(x) (x)
44# define HOST_TO_LE32(x) (x)
45# define LE16_TO_HOST(x) (x)
46# define LE32_TO_HOST(x) (x)
47#else
48# define HOST_TO_LE16(x) bswap_16(x)
49# define HOST_TO_LE32(x) bswap_32(x)
50# define LE16_TO_HOST(x) bswap_16(x)
51# define LE32_TO_HOST(x) bswap_32(x)
52#endif
53
54#define MAX_NUM_BLOCKS 8
55#define MAX_ARG_COUNT 32
56#define MAX_ARG_LEN 1024
57#define FILE_BUF_LEN (16*1024)
58#define CSYS_PADC 0xFF
59
60#define BLOCK_TYPE_BOOT 0
61#define BLOCK_TYPE_CONF 1
62#define BLOCK_TYPE_WEBP 2
63#define BLOCK_TYPE_CODE 3
64#define BLOCK_TYPE_XTRA 4
65
66#define DEFAULT_BLOCK_ALIGN 0x10000U
67
68#define CSUM_SIZE_NONE 0
69#define CSUM_SIZE_8 1
70#define CSUM_SIZE_16 2
71
72
73struct csum_state{
74    int size;
75    uint16_t val;
76    uint16_t tmp;
77    int odd;
78};
79
80
81struct csys_block {
82    int type; /* type of the block */
83
84    int need_file;
85    char *file_name; /* name of the file */
86    uint32_t file_size; /* length of the file */
87
88    unsigned char sig[SIG_LEN];
89    uint32_t addr;
90    int addr_set;
91    uint32_t align;
92    int align_set;
93    uint8_t padc;
94
95    uint32_t size;
96    uint32_t size_hdr;
97    uint32_t size_csum;
98    uint32_t size_avail;
99
100    struct csum_state *css;
101};
102
103
104struct board_info {
105    char *model;
106    char *name;
107    uint32_t flash_size;
108
109    char sig_boot[SIG_LEN];
110    char sig_conf[SIG_LEN];
111    char sig_webp[SIG_LEN];
112
113    uint32_t boot_size;
114    uint32_t conf_size;
115    uint32_t webp_size;
116    uint32_t webp_size_max;
117    uint32_t code_size;
118
119    uint32_t addr_code;
120    uint32_t addr_webp;
121};
122
123#define BOARD(m, n, f, sigb, sigw, bs, cs, ws, ac, aw) {\
124    .model = m, .name = n, .flash_size = f<<20, \
125    .sig_boot = sigb, .sig_conf = SIG_CONF, .sig_webp = sigw, \
126    .boot_size = bs, .conf_size = cs, \
127    .webp_size = ws, .webp_size_max = 3*0x10000, \
128    .addr_code = ac, .addr_webp = aw \
129    }
130
131#define BOARD_ADM(m,n,f, sigw) BOARD(m,n,f, ADM_BOOT_SIG, sigw, \
132    ADM_BOOT_SIZE, ADM_CONF_SIZE, ADM_WEBP_SIZE, \
133    ADM_CODE_ADDR, ADM_WEBP_ADDR)
134
135
136/*
137 * Globals
138 */
139char *progname;
140char *ofname = NULL;
141int verblevel = 0;
142int invalid_causes_error = 1;
143int keep_invalid_images = 0;
144
145struct board_info *board = NULL;
146
147struct csys_block *boot_block = NULL;
148struct csys_block *conf_block = NULL;
149struct csys_block *webp_block = NULL;
150struct csys_block *code_block = NULL;
151
152struct csys_block blocks[MAX_NUM_BLOCKS];
153int num_blocks = 0;
154
155static struct board_info boards[] = {
156    /* The original Edimax products */
157    BOARD_ADM("BR-6104K", "Edimax BR-6104K", 2, SIG_BR6104K),
158    BOARD_ADM("BR-6104KP", "Edimax BR-6104KP", 2, SIG_BR6104KP),
159    BOARD_ADM("BR-6104Wg", "Edimax BR-6104Wg", 2, SIG_BR6104Wg),
160    BOARD_ADM("BR-6114WG", "Edimax BR-6114WG", 2, SIG_BR6114WG),
161    BOARD_ADM("BR-6524K", "Edimax BR-6524K", 2, SIG_BR6524K),
162    BOARD_ADM("BR-6524KP", "Edimax BR-6524KP", 2, SIG_BR6524KP),
163    BOARD_ADM("BR-6524WG", "Edimax BR-6524WG", 4, SIG_BR6524WG),
164    BOARD_ADM("BR-6524WP", "Edimax BR-6524WP", 4, SIG_BR6524WP),
165    BOARD_ADM("BR-6541K", "Edimax BR-6541K", 2, SIG_BR6541K),
166    BOARD_ADM("BR-6541KP", "Edimax BR-6541K", 2, SIG_BR6541KP),
167    BOARD_ADM("BR-6541WP", "Edimax BR-6541WP", 4, SIG_BR6541WP),
168    BOARD_ADM("EW-7207APg", "Edimax EW-7207APg", 2, SIG_EW7207APg),
169    BOARD_ADM("PS-1205UWg", "Edimax PS-1205UWg", 2, SIG_PS1205UWg),
170    BOARD_ADM("PS-3205U", "Edimax PS-3205U", 2, SIG_PS3205U),
171    BOARD_ADM("PS-3205UWg", "Edimax PS-3205UWg", 2, SIG_PS3205UWg),
172
173    /* Hawking products */
174    BOARD_ADM("H2BR4", "Hawking H2BR4", 2, SIG_H2BR4),
175    BOARD_ADM("H2WR54G", "Hawking H2WR54G", 4, SIG_H2WR54G),
176
177    /* Planet products */
178    BOARD_ADM("XRT-401D", "Planet XRT-401D", 2, SIG_XRT401D),
179    BOARD_ADM("XRT-402D", "Planet XRT-402D", 2, SIG_XRT402D),
180
181    /* Conceptronic products */
182    BOARD_ADM("C54BSR4", "Conceptronic C54BSR4", 2, SIG_C54BSR4),
183
184    /* OSBRiDGE products */
185    BOARD_ADM("5GXi", "OSBDRiDGE 5GXi", 2, SIG_5GXI),
186
187    {.model = NULL}
188};
189
190/*
191 * Message macros
192 */
193#define ERR(fmt, ...) do { \
194    fflush(0); \
195    fprintf(stderr, "[%s] *** error: " fmt "\n", progname, ## __VA_ARGS__ ); \
196} while (0)
197
198#define ERRS(fmt, ...) do { \
199    int save = errno; \
200    fflush(0); \
201    fprintf(stderr, "[%s] *** error: " fmt "\n", progname, ## __VA_ARGS__ \
202        , strerror(save)); \
203} while (0)
204
205#define WARN(fmt, ...) do { \
206    fprintf(stderr, "[%s] *** warning: " fmt "\n", progname, ## __VA_ARGS__ ); \
207} while (0)
208
209#define DBG(lev, fmt, ...) do { \
210    if (verblevel < lev) \
211        break;\
212    fprintf(stderr, "[%s] " fmt "\n", progname, ## __VA_ARGS__ ); \
213} while (0)
214
215#define ERR_FATAL -1
216#define ERR_INVALID_IMAGE -2
217
218void
219usage(int status)
220{
221    FILE *stream = (status != EXIT_SUCCESS) ? stderr : stdout;
222    struct board_info *board;
223
224    fprintf(stream, "Usage: %s [OPTIONS...] <file>\n", progname);
225    fprintf(stream,
226"\n"
227"Options:\n"
228" -B <board> create image for the board specified with <board>.\n"
229" valid <board> values:\n"
230    );
231    for (board = boards; board->model != NULL; board++){
232        fprintf(stream,
233" %-12s: %s\n",
234         board->model, board->name);
235    };
236    fprintf(stream,
237" -d don't throw error on invalid images\n"
238" -k keep invalid images\n"
239" -b <file>[:<align>[:<padc>]]\n"
240" add boot code to the image\n"
241" -c <file>[:<align>[:<padc>]]\n"
242" add configuration settings to the image\n"
243" -r <file>:[<addr>][:<align>[:<padc>]]\n"
244" add runtime code to the image\n"
245" -w [<file>:[<addr>][:<align>[:<padc>]]]\n"
246" add webpages to the image\n"
247" -x <file>[:<align>[:<padc>]]\n"
248" add extra data at the end of the image\n"
249" -h show this screen\n"
250"Parameters:\n"
251" <file> write output to the file <file>\n"
252    );
253
254    exit(status);
255}
256
257static inline uint32_t align(uint32_t base, uint32_t alignment)
258{
259    uint32_t ret;
260
261    if (alignment) {
262        ret = (base + alignment - 1);
263        ret &= ~(alignment-1);
264    } else {
265        ret = base;
266    }
267
268    return ret;
269}
270
271/*
272 * argument parsing
273 */
274int
275str2u32(char *arg, uint32_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)) {
283        return -1;
284    }
285
286    *val = t;
287    return 0;
288}
289
290
291int
292str2u16(char *arg, uint16_t *val)
293{
294    char *err = NULL;
295    uint32_t t;
296
297    errno=0;
298    t = strtoul(arg, &err, 0);
299    if (errno || (err==arg) || ((err != NULL) && *err) || (t >= 0x10000)) {
300        return -1;
301    }
302
303    *val = t & 0xFFFF;
304    return 0;
305}
306
307int
308str2u8(char *arg, uint8_t *val)
309{
310    char *err = NULL;
311    uint32_t t;
312
313    errno=0;
314    t = strtoul(arg, &err, 0);
315    if (errno || (err==arg) || ((err != NULL) && *err) || (t >= 0x100)) {
316        return -1;
317    }
318
319    *val = t & 0xFF;
320    return 0;
321}
322
323int
324str2sig(char *arg, uint32_t *sig)
325{
326    if (strlen(arg) != 4)
327        return -1;
328
329    *sig = arg[0] | (arg[1] << 8) | (arg[2] << 16) | (arg[3] << 24);
330
331    return 0;
332}
333
334
335int
336parse_arg(char *arg, char *buf, char *argv[])
337{
338    int res = 0;
339    size_t argl;
340    char *tok;
341    char **ap = &buf;
342    int i;
343
344    memset(argv, 0, MAX_ARG_COUNT * sizeof(void *));
345
346    if ((arg == NULL)) {
347        /* no arguments */
348        return 0;
349    }
350
351    argl = strlen(arg);
352    if (argl == 0) {
353        /* no arguments */
354        return 0;
355    }
356
357    if (argl >= MAX_ARG_LEN) {
358        /* argument is too long */
359        argl = MAX_ARG_LEN-1;
360    }
361
362    memcpy(buf, arg, argl);
363    buf[argl] = '\0';
364
365    for (i = 0; i < MAX_ARG_COUNT; i++) {
366        tok = strsep(ap, ":");
367        if (tok == NULL) {
368            break;
369        }
370#if 0
371        else if (tok[0] == '\0') {
372            break;
373        }
374#endif
375        argv[i] = tok;
376        res++;
377    }
378
379    return res;
380}
381
382
383int
384required_arg(char c, char *arg)
385{
386    if (arg == NULL || *arg != '-')
387        return 0;
388
389    ERR("option -%c requires an argument\n", c);
390    return ERR_FATAL;
391}
392
393
394int
395is_empty_arg(char *arg)
396{
397    int ret = 1;
398    if (arg != NULL) {
399        if (*arg) ret = 0;
400    };
401    return ret;
402}
403
404
405void
406csum8_update(uint8_t *p, uint32_t len, struct csum_state *css)
407{
408    for ( ; len > 0; len --) {
409        css->val += *p++;
410    }
411}
412
413
414uint16_t
415csum8_get(struct csum_state *css)
416{
417    uint8_t t;
418
419    t = css->val;
420    return ~t + 1;
421}
422
423
424void
425csum16_update(uint8_t *p, uint32_t len, struct csum_state *css)
426{
427    uint16_t t;
428
429    if (css->odd) {
430        t = css->tmp + (p[0]<<8);
431        css->val += LE16_TO_HOST(t);
432        css->odd = 0;
433        len--;
434        p++;
435    }
436
437    for ( ; len > 1; len -= 2, p +=2 ) {
438        t = p[0] + (p[1] << 8);
439        css->val += LE16_TO_HOST(t);
440    }
441
442    if (len == 1) {
443        css->tmp = p[0];
444        css->odd = 1;
445    }
446}
447
448
449uint16_t
450csum16_get(struct csum_state *css)
451{
452    char pad = 0;
453
454    csum16_update(&pad, 1, css);
455    return ~css->val + 1;
456}
457
458
459void
460csum_init(struct csum_state *css, int size)
461{
462    css->val = 0;
463    css->tmp = 0;
464    css->odd = 0;
465    css->size = size;
466}
467
468
469void
470csum_update(uint8_t *p, uint32_t len, struct csum_state *css)
471{
472    switch (css->size) {
473    case CSUM_SIZE_8:
474        csum8_update(p,len,css);
475        break;
476    case CSUM_SIZE_16:
477        csum16_update(p,len,css);
478        break;
479    }
480}
481
482
483uint16_t
484csum_get(struct csum_state *css)
485{
486    uint16_t ret;
487
488    switch (css->size) {
489    case CSUM_SIZE_8:
490        ret = csum8_get(css);
491        break;
492    case CSUM_SIZE_16:
493        ret = csum16_get(css);
494        break;
495    }
496
497    return ret;
498}
499
500
501/*
502 * routines to write data to the output file
503 */
504int
505write_out_data(FILE *outfile, uint8_t *data, size_t len,
506        struct csum_state *css)
507{
508    errno = 0;
509
510    fwrite(data, len, 1, outfile);
511    if (errno) {
512        ERRS("unable to write output file");
513        return ERR_FATAL;
514    }
515
516    if (css) {
517        csum_update(data, len, css);
518    }
519
520    return 0;
521}
522
523
524int
525write_out_padding(FILE *outfile, size_t len, uint8_t padc,
526         struct csum_state *css)
527{
528    uint8_t buf[512];
529    size_t buflen = sizeof(buf);
530    int err;
531
532    memset(buf, padc, buflen);
533    while (len > 0) {
534        if (len < buflen)
535            buflen = len;
536
537        err = write_out_data(outfile, buf, buflen, css);
538        if (err)
539            return err;
540
541        len -= buflen;
542    }
543
544    return 0;
545}
546
547
548int
549block_stat_file(struct csys_block *block)
550{
551    struct stat st;
552    int err;
553
554    if (block->file_name == NULL)
555        return 0;
556
557    err = stat(block->file_name, &st);
558    if (err){
559        ERRS("stat failed on %s", block->file_name);
560        return ERR_FATAL;
561    }
562
563    block->file_size = st.st_size;
564    return 0;
565}
566
567
568int
569block_writeout_hdr(FILE *outfile, struct csys_block *block)
570{
571    struct csys_header hdr;
572    int res;
573
574    if (block->size_hdr == 0)
575        return 0;
576
577    /* setup header fields */
578    memcpy(hdr.sig, block->sig, 4);
579    hdr.addr = HOST_TO_LE32(block->addr);
580    hdr.size = HOST_TO_LE32(block->size - block->size_hdr - block->size_csum);
581
582    DBG(1,"writing header for block");
583    res = write_out_data(outfile, (uint8_t *)&hdr, sizeof(hdr),NULL);
584    return res;
585
586}
587
588
589int
590block_writeout_file(FILE *outfile, struct csys_block *block)
591{
592    char buf[FILE_BUF_LEN];
593    size_t buflen = sizeof(buf);
594    FILE *f;
595    size_t len;
596    int res;
597
598    if (block->file_name == NULL)
599        return 0;
600
601    if (block->file_size == 0)
602        return 0;
603
604    errno = 0;
605    f = fopen(block->file_name,"r");
606    if (errno) {
607        ERRS("unable to open file: %s", block->file_name);
608        return ERR_FATAL;
609    }
610
611    len = block->file_size;
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", block->file_name);
621            res = ERR_FATAL;
622            break;
623        }
624
625        res = write_out_data(outfile, buf, buflen, block->css);
626        if (res)
627            break;
628
629        len -= buflen;
630    }
631
632    fclose(f);
633    return res;
634}
635
636
637int
638block_writeout_data(FILE *outfile, struct csys_block *block)
639{
640    int res;
641    size_t padlen;
642
643    res = block_writeout_file(outfile, block);
644    if (res)
645        return res;
646
647    /* write padding data if neccesary */
648    padlen = block->size_avail - block->file_size;
649    DBG(1,"padding block, length=%d", padlen);
650    res = write_out_padding(outfile, padlen, block->padc, block->css);
651
652    return res;
653}
654
655
656int
657block_writeout_csum(FILE *outfile, struct csys_block *block)
658{
659    uint16_t csum;
660    int res;
661
662    if (block->size_csum == 0)
663        return 0;
664
665    DBG(1,"writing checksum for block");
666    csum = HOST_TO_LE16(csum_get(block->css));
667    res = write_out_data(outfile, (uint8_t *)&csum, block->size_csum, NULL);
668
669    return res;
670}
671
672
673int
674block_writeout(FILE *outfile, struct csys_block *block)
675{
676    int res;
677    struct csum_state css;
678
679    res = 0;
680
681    if (block == NULL)
682        return res;
683
684    block->css = NULL;
685
686    DBG(2, "writing block, file=%s, file_size=%d, space=%d",
687        block->file_name, block->file_size, block->size_avail);
688    res = block_writeout_hdr(outfile, block);
689    if (res)
690        return res;
691
692    if (block->size_csum != 0) {
693        block->css = &css;
694        csum_init(&css, block->size_csum);
695    }
696
697    res = block_writeout_data(outfile, block);
698    if (res)
699        return res;
700
701    res = block_writeout_csum(outfile, block);
702    if (res)
703        return res;
704
705    return res;
706}
707
708
709int
710write_out_blocks(FILE *outfile)
711{
712    struct csys_block *block;
713    int i, res;
714
715    res = block_writeout(outfile, boot_block);
716    if (res)
717        return res;
718
719    res = block_writeout(outfile, conf_block);
720    if (res)
721        return res;
722
723    res = block_writeout(outfile, webp_block);
724    if (res)
725        return res;
726
727    res = block_writeout(outfile, code_block);
728    if (res)
729        return res;
730
731    res = 0;
732    for (i=0; i < num_blocks; i++) {
733        block = &blocks[i];
734
735        if (block->type != BLOCK_TYPE_XTRA)
736            continue;
737
738        res = block_writeout(outfile, block);
739        if (res)
740            break;
741    }
742
743    return res;
744}
745
746
747struct board_info *
748find_board(char *model)
749{
750    struct board_info *ret;
751    struct board_info *board;
752
753    ret = NULL;
754    for (board = boards; board->model != NULL; board++){
755        if (strcasecmp(model, board->model) == 0) {
756            ret = board;
757            break;
758        }
759    };
760
761    return ret;
762}
763
764
765int
766parse_opt_board(char ch, char *arg)
767{
768
769    DBG(1,"parsing board option: -%c %s", ch, arg);
770
771    if (board != NULL) {
772        ERR("only one board option allowed");
773        return ERR_FATAL;
774    }
775
776    if (required_arg(ch, arg))
777        return ERR_FATAL;
778
779    board = find_board(arg);
780    if (board == NULL){
781        ERR("invalid/unknown board specified: %s", arg);
782        return ERR_FATAL;
783    }
784
785    return 0;
786}
787
788
789int
790parse_opt_block(char ch, char *arg)
791{
792    char buf[MAX_ARG_LEN];
793    char *argv[MAX_ARG_COUNT];
794    int argc;
795    char *p;
796    struct csys_block *block;
797    int i;
798
799    if ( num_blocks > MAX_NUM_BLOCKS ) {
800        ERR("too many blocks specified");
801        return ERR_FATAL;
802    }
803
804    block = &blocks[num_blocks];
805
806    /* setup default field values */
807    block->need_file = 1;
808    block->padc = 0xFF;
809
810    switch (ch) {
811    case 'b':
812        if (boot_block) {
813            WARN("only one boot block allowed");
814            break;
815        }
816        block->type = BLOCK_TYPE_BOOT;
817        boot_block = block;
818        break;
819    case 'c':
820        if (conf_block) {
821            WARN("only one config block allowed");
822            break;
823        }
824        block->type = BLOCK_TYPE_CONF;
825        conf_block = block;
826        break;
827    case 'w':
828        if (webp_block) {
829            WARN("only one web block allowed");
830            break;
831        }
832        block->type = BLOCK_TYPE_WEBP;
833        block->size_hdr = sizeof(struct csys_header);
834        block->size_csum = CSUM_SIZE_8;
835        block->need_file = 0;
836        webp_block = block;
837        break;
838    case 'r':
839        if (code_block) {
840            WARN("only one runtime block allowed");
841            break;
842        }
843        block->type = BLOCK_TYPE_CODE;
844        block->size_hdr = sizeof(struct csys_header);
845        block->size_csum = CSUM_SIZE_16;
846        code_block = block;
847        break;
848    case 'x':
849        block->type = BLOCK_TYPE_XTRA;
850        break;
851    default:
852        ERR("unknown block type \"%c\"", ch);
853        return ERR_FATAL;
854    }
855
856    argc = parse_arg(arg, buf, argv);
857
858    i = 0;
859    p = argv[i++];
860    if (!is_empty_arg(p)) {
861        block->file_name = strdup(p);
862        if (block->file_name == NULL) {
863            ERR("not enough memory");
864            return ERR_FATAL;
865        }
866    } else if (block->need_file){
867        ERR("no file specified in %s", arg);
868        return ERR_FATAL;
869    }
870
871    if (block->size_hdr) {
872        p = argv[i++];
873        if (!is_empty_arg(p)) {
874            if (str2u32(p, &block->addr) != 0) {
875                ERR("invalid start address in %s", arg);
876                return ERR_FATAL;
877            }
878            block->addr_set = 1;
879        }
880    }
881
882    p = argv[i++];
883    if (!is_empty_arg(p)) {
884        if (str2u32(p, &block->align) != 0) {
885            ERR("invalid alignment value in %s", arg);
886            return ERR_FATAL;
887        }
888        block->align_set = 1;
889    }
890
891    p = argv[i++];
892    if (!is_empty_arg(p) && (str2u8(p, &block->padc) != 0)) {
893        ERR("invalid paddig character in %s", arg);
894        return ERR_FATAL;
895    }
896
897    num_blocks++;
898
899    return 0;
900}
901
902
903int
904process_blocks(void)
905{
906    struct csys_block *block;
907    uint32_t offs = 0;
908    int i;
909    int res;
910
911    res = 0;
912    /* collecting stats */
913    for (i = 0; i < num_blocks; i++) {
914        block = &blocks[i];
915        res = block_stat_file(block);
916        if (res)
917            return res;
918    }
919
920    /* bootloader */
921    block = boot_block;
922    if (block) {
923        block->size = board->boot_size;
924        if (block->file_size > board->boot_size) {
925            WARN("boot block is too big");
926            res = ERR_INVALID_IMAGE;
927        }
928    }
929    offs += board->boot_size;
930
931    /* configuration data */
932    block = conf_block;
933    if (block) {
934        block->size = board->conf_size;
935        if (block->file_size > board->conf_size) {
936            WARN("config block is too big");
937            res = ERR_INVALID_IMAGE;
938        }
939    }
940    offs += board->conf_size;
941
942    /* webpages */
943    block = webp_block;
944    if (block) {
945
946        memcpy(block->sig, board->sig_webp, 4);
947
948        if (block->addr_set == 0)
949            block->addr = board->addr_webp;
950
951        if (block->align_set == 0)
952            block->align = DEFAULT_BLOCK_ALIGN;
953
954        block->size = align(offs + block->file_size + block->size_hdr +
955                block->size_csum, block->align) - offs;
956
957        if (block->size > board->webp_size_max) {
958            WARN("webpages block is too big");
959            res = ERR_INVALID_IMAGE;
960        }
961
962        DBG(2,"webpages start at %08x, size=%08x", offs,
963                block->size);
964
965        offs += block->size;
966        if (offs > board->flash_size) {
967            WARN("webp block is too big");
968            res = ERR_INVALID_IMAGE;
969        }
970    }
971
972    /* runtime code */
973    block = code_block;
974    if (block) {
975        memcpy(code_block->sig, SIG_CSYS, 4);
976
977        if (block->addr_set == 0)
978            block->addr = board->addr_code;
979
980        if (block->align_set == 0)
981            block->align = DEFAULT_BLOCK_ALIGN;
982
983        block->size = align(offs + block->file_size +
984                block->size_hdr + block->size_csum,
985                block->align) - offs;
986
987        DBG(2,"code block start at %08x, size=%08x", offs,
988                block->size);
989
990        offs += block->size;
991        if (offs > board->flash_size) {
992            WARN("code block is too big");
993            res = ERR_INVALID_IMAGE;
994        }
995    }
996
997    for (i = 0; i < num_blocks; i++) {
998        block = &blocks[i];
999
1000        if (block->type != BLOCK_TYPE_XTRA)
1001            continue;
1002
1003        if (block->align_set == 0)
1004            block->align = DEFAULT_BLOCK_ALIGN;
1005
1006        block->size = align(offs + block->file_size,
1007                block->align) - offs;
1008
1009        DBG(2,"file %s start at %08x, size=%08x, align=%08x",
1010            block->file_name, offs, block->size, block->align);
1011
1012        offs += block->size;
1013        if (offs > board->flash_size) {
1014            WARN("file %s is too big, size=%d, avail=%d",
1015                block->file_name, block->file_size,
1016                board->flash_size - offs);
1017            res = ERR_INVALID_IMAGE;
1018        }
1019    }
1020
1021    for (i = 0; i < num_blocks; i++) {
1022        block = &blocks[i];
1023
1024        block->size_avail = block->size - block->size_hdr -
1025            block->size_csum;
1026
1027        if (block->size_avail < block->file_size) {
1028            WARN("file %s is too big, size=%d, avail=%d",
1029                block->file_name, block->file_size,
1030                block->size_avail);
1031            res = ERR_INVALID_IMAGE;
1032        }
1033    }
1034
1035    return res;
1036}
1037
1038
1039int
1040main(int argc, char *argv[])
1041{
1042    int optinvalid = 0; /* flag for invalid option */
1043    int c;
1044    int res = ERR_FATAL;
1045
1046    FILE *outfile;
1047
1048    progname=basename(argv[0]);
1049
1050    opterr = 0; /* could not print standard getopt error messages */
1051    while ( 1 ) {
1052        optinvalid = 0;
1053
1054        c = getopt(argc, argv, "b:B:c:dhkr:vw:x:");
1055        if (c == -1)
1056            break;
1057
1058        switch (c) {
1059        case 'b':
1060        case 'c':
1061        case 'r':
1062        case 'x':
1063            optinvalid = parse_opt_block(c,optarg);
1064            break;
1065        case 'w':
1066            if (optarg != NULL && *optarg == '-') {
1067                /* rollback */
1068                optind--;
1069                optarg = NULL;
1070            }
1071            optinvalid = parse_opt_block(c,optarg);
1072            break;
1073        case 'd':
1074            invalid_causes_error = 0;
1075            break;
1076        case 'k':
1077            keep_invalid_images = 1;
1078            break;
1079        case 'B':
1080            optinvalid = parse_opt_board(c,optarg);
1081            break;
1082        case 'v':
1083            verblevel++;
1084            break;
1085        case 'h':
1086            usage(EXIT_SUCCESS);
1087            break;
1088        default:
1089            optinvalid = 1;
1090            break;
1091        }
1092        if (optinvalid != 0 ){
1093            ERR("invalid option: -%c", optopt);
1094            goto out;
1095        }
1096    }
1097
1098    if (board == NULL) {
1099        ERR("no board specified");
1100        goto out;
1101    }
1102
1103    if (optind == argc) {
1104        ERR("no output file specified");
1105        goto out;
1106    }
1107
1108    ofname = argv[optind++];
1109
1110    if (optind < argc) {
1111        ERR("invalid option: %s", argv[optind]);
1112        goto out;
1113    }
1114
1115    res = process_blocks();
1116    if (res == ERR_FATAL)
1117        goto out;
1118
1119    if (res == ERR_INVALID_IMAGE) {
1120        if (invalid_causes_error)
1121            res = ERR_FATAL;
1122
1123        if (keep_invalid_images == 0) {
1124            WARN("generation of invalid images disabled", ofname);
1125            goto out;
1126        }
1127
1128        WARN("generating invalid image", ofname);
1129    }
1130
1131    outfile = fopen(ofname, "w");
1132    if (outfile == NULL) {
1133        ERRS("could not open \"%s\" for writing", ofname);
1134        res = ERR_FATAL;
1135        goto out;
1136    }
1137
1138    if (write_out_blocks(outfile) != 0) {
1139        res = ERR_FATAL;
1140        goto out_flush;
1141    }
1142
1143    DBG(1,"Image file %s completed.", ofname);
1144
1145out_flush:
1146    fflush(outfile);
1147    fclose(outfile);
1148    if (res == ERR_FATAL) {
1149        unlink(ofname);
1150    }
1151out:
1152    if (res == ERR_FATAL)
1153        return EXIT_FAILURE;
1154
1155    return EXIT_SUCCESS;
1156}
1157

Archive Download this file



interactive