• source navigation  • diff markup  • identifier search  • freetext search  • 

Sources/firmware-utils/src/mkzynfw.c

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

This page was automatically generated by LXR 0.3.1.  •  OpenWrt