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

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

Archive Download this file



interactive