• 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 RTL93XX_FLASH_BASE      0xB4000000
122 #define RTL93XX_CODE_START      0x80220000
123 #define RTL93XX_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 RTL93XXBOARD(n, d, m, fs, fo) {                                 \
154         .name = (n), .desc = (d),                                       \
155         .vendor = (ZYNOS_VENDOR_ID_ZYXEL), .model = (m),                \
156         .flash_base = (RTL93XX_FLASH_BASE), .flash_size = (fs)<<20,     \
157         .code_start = (RTL93XX_CODE_START), .romio_offs = (fo),         \
158         .bootext_size = (RTL93XX_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 RTL93xx based boards
242          */
243         RTL93XXBOARD("XGS1930-28", "Zyxel XGS1930-28", MID(24834), 32, 0x260000),       /* ABHT */
244         RTL93XXBOARD("XGS1930-28HP", "Zyxel XGS1930-28HP", MID(25090), 32, 0x260000),   /* ABHS */
245         RTL93XXBOARD("XGS1930-52", "Zyxel XGS1930-52", MID(25346), 32, 0x260000),       /* ABHU */
246         RTL93XXBOARD("XGS1930-52HP", "Zyxel XGS1930-52HP", MID(25602), 32, 0x260000),   /* ABHV */
247         RTL93XXBOARD("XMG1915-10E", "Zyxel XMG1915-10E", MID(37378), 32, 0x260000),     /* ACGO */
248         RTL93XXBOARD("XMG1915-10EP", "Zyxel XMG1915-10EP", MID(37634), 32, 0x260000),   /* ACGP */
249         RTL93XXBOARD("XMG1915-18EP", "Zyxel XMG1915-18EP", MID(37890), 32, 0x260000),   /* ACGQ */
250         RTL93XXBOARD("XMG1930-30", "Zyxel XMG1930-30", MID(33794), 32, 0x280000),       /* ACAR */
251         RTL93XXBOARD("XMG1930-30HP", "Zyxel XMG1930-30HP", MID(34050), 32, 0x280000),   /* ACAS */
252         RTL93XXBOARD("XS1930-10", "Zyxel XS1930-10", MID(29698), 32, 0x280000),         /* ABQE */
253         RTL93XXBOARD("XS1930-12F", "Zyxel XS1930-12F", MID(33026), 32, 0x280000),       /* ABZV */
254         RTL93XXBOARD("XS1930-12HP", "Zyxel XS1930-12HP", MID(29954), 32, 0x280000),     /* ABQF */
255 
256         {.name = NULL}
257 };
258 
259 /*
260  * Message macros
261  */
262 #define ERR(fmt, ...) do { \
263         fflush(0); \
264         fprintf(stderr, "[%s] *** error: " fmt "\n", \
265                         progname, ## __VA_ARGS__ ); \
266 } while (0)
267 
268 #define ERRS(fmt, ...) do { \
269         int save = errno; \
270         fflush(0); \
271         fprintf(stderr, "[%s] *** error: " fmt ", %s\n", \
272                         progname, ## __VA_ARGS__, strerror(save)); \
273 } while (0)
274 
275 #define WARN(fmt, ...) do { \
276         fprintf(stderr, "[%s] *** warning: " fmt "\n", \
277                         progname, ## __VA_ARGS__ ); \
278 } while (0)
279 
280 #define DBG(lev, fmt, ...) do { \
281         if (verblevel < lev) \
282                 break;\
283         fprintf(stderr, "[%s] " fmt "\n", progname, ## __VA_ARGS__ ); \
284 } while (0)
285 
286 #define ERR_FATAL               -1
287 #define ERR_INVALID_IMAGE       -2
288 
289 /*
290  * Helper routines
291  */
292 void
293 usage(int status)
294 {
295         FILE *stream = (status != EXIT_SUCCESS) ? stderr : stdout;
296         struct board_info *board;
297 
298         fprintf(stream, "Usage: %s [OPTIONS...]\n", progname);
299         fprintf(stream,
300 "\n"
301 "Options:\n"
302 "  -B <board>      create image for the board specified with <board>.\n"
303 "                  valid <board> values:\n"
304         );
305         for (board = boards; board->name != NULL; board++){
306                 fprintf(stream,
307 "                    %-12s= %s\n",
308                  board->name, board->desc);
309         };
310         fprintf(stream,
311 "  -b <file>[:<align>]\n"
312 "                  add boot extension block to the image\n"
313 "  -r <file>[:<align>]\n"
314 "                  add raw block to the image\n"
315 "  -o <file>       write output to the file <file>\n"
316 "  -h              show this screen\n"
317         );
318 
319         exit(status);
320 }
321 
322 
323 /*
324  * argument parsing
325  */
326 int
327 str2u32(char *arg, uint32_t *val)
328 {
329         char *err = NULL;
330         uint32_t t;
331 
332         errno=0;
333         t = strtoul(arg, &err, 0);
334         if (errno || (err==arg) || ((err != NULL) && *err)) {
335                 return -1;
336         }
337 
338         *val = t;
339         return 0;
340 }
341 
342 
343 int
344 str2u16(char *arg, uint16_t *val)
345 {
346         char *err = NULL;
347         uint32_t t;
348 
349         errno=0;
350         t = strtoul(arg, &err, 0);
351         if (errno || (err==arg) || ((err != NULL) && *err) || (t >= 0x10000)) {
352                 return -1;
353         }
354 
355         *val = t & 0xFFFF;
356         return 0;
357 }
358 
359 int
360 str2u8(char *arg, uint8_t *val)
361 {
362         char *err = NULL;
363         uint32_t t;
364 
365         errno=0;
366         t = strtoul(arg, &err, 0);
367         if (errno || (err==arg) || ((err != NULL) && *err) || (t >= 0x100)) {
368                 return -1;
369         }
370 
371         *val = t & 0xFF;
372         return 0;
373 }
374 
375 int
376 str2sig(char *arg, uint32_t *sig)
377 {
378         if (strlen(arg) != 4)
379                 return -1;
380 
381         *sig = arg[0] | (arg[1] << 8) | (arg[2] << 16) | (arg[3] << 24);
382 
383         return 0;
384 }
385 
386 
387 int
388 parse_arg(char *arg, char *buf, char *argv[])
389 {
390         int res = 0;
391         size_t argl;
392         char *tok;
393         char **ap = &buf;
394         int i;
395 
396         memset(argv, 0, MAX_ARG_COUNT * sizeof(void *));
397 
398         if ((arg == NULL)) {
399                 /* no arguments */
400                 return 0;
401         }
402 
403         argl = strlen(arg);
404         if (argl == 0) {
405                 /* no arguments */
406                 return 0;
407         }
408 
409         if (argl >= MAX_ARG_LEN) {
410                 /* argument is too long */
411                 argl = MAX_ARG_LEN-1;
412         }
413 
414         memcpy(buf, arg, argl);
415         buf[argl] = '\0';
416 
417         for (i = 0; i < MAX_ARG_COUNT; i++) {
418                 tok = strsep(ap, ":");
419                 if (tok == NULL) {
420                         break;
421                 }
422 #if 0
423                 else if (tok[0] == '\0') {
424                         break;
425                 }
426 #endif
427                 argv[i] = tok;
428                 res++;
429         }
430 
431         return res;
432 }
433 
434 
435 int
436 required_arg(char c, char *arg)
437 {
438         if (arg == NULL || *arg != '-')
439                 return 0;
440 
441         ERR("option -%c requires an argument\n", c);
442         return -1;
443 }
444 
445 
446 int
447 is_empty_arg(char *arg)
448 {
449         int ret = 1;
450         if (arg != NULL) {
451                 if (*arg) ret = 0;
452         };
453         return ret;
454 }
455 
456 
457 void
458 csum_init(struct csum_state *css)
459 {
460         css->odd = 0;
461         css->sum = 0;
462         css->tmp = 0;
463 }
464 
465 
466 void
467 csum_update(void *data, uint32_t len, struct csum_state *css)
468 {
469         uint8_t *p = data;
470 
471         if (len == 0)
472                 return;
473 
474         if (css->odd) {
475                 css->sum += (css->tmp << 8) + p[0];
476                 if (css->sum > 0xFFFF) {
477                         css->sum += 1;
478                         css->sum &= 0xFFFF;
479                 }
480                 css->odd = 0;
481                 len--;
482                 p++;
483         }
484 
485         for ( ; len > 1; len -= 2, p +=2 ) {
486                 css->sum  += (p[0] << 8) + p[1];
487                 if (css->sum > 0xFFFF) {
488                         css->sum += 1;
489                         css->sum &= 0xFFFF;
490                 }
491         }
492 
493         if (len == 1){
494                 css->tmp = p[0];
495                 css->odd = 1;
496         }
497 }
498 
499 
500 uint16_t
501 csum_get(struct csum_state *css)
502 {
503         char pad = 0;
504 
505         csum_update(&pad, 1, css);
506         return css->sum;
507 }
508 
509 uint16_t
510 csum_buf(uint8_t *p, uint32_t len)
511 {
512         struct csum_state css;
513 
514         csum_init(&css);
515         csum_update(p, len, &css);
516         return csum_get(&css);
517 
518 }
519 
520 /*
521  * routines to write data to the output file
522  */
523 int
524 write_out_data(FILE *outfile, void *data, size_t len,
525                 struct csum_state *css)
526 {
527         uint8_t *ptr = data;
528 
529         errno = 0;
530 
531         fwrite(ptr, len, 1, outfile);
532         if (errno) {
533                 ERR("unable to write output file");
534                 return -1;
535         }
536 
537         if (css) {
538                 csum_update(ptr, len, css);
539         }
540 
541         return 0;
542 }
543 
544 
545 int
546 write_out_padding(FILE *outfile, size_t len, uint8_t padc,
547                  struct csum_state *css)
548 {
549         uint8_t buf[512];
550         size_t buflen = sizeof(buf);
551 
552         memset(buf, padc, buflen);
553         while (len > 0) {
554                 if (len < buflen)
555                         buflen = len;
556 
557                 if (write_out_data(outfile, buf, buflen, css))
558                         return -1;
559 
560                 len -= buflen;
561         }
562 
563         return 0;
564 }
565 
566 
567 int
568 write_out_data_align(FILE *outfile, void *data, size_t len, size_t align,
569                 struct csum_state *css)
570 {
571         size_t padlen;
572         int res;
573 
574         res = write_out_data(outfile, data, len, css);
575         if (res)
576                 return res;
577 
578         padlen = ALIGN(len,align) - len;
579         res = write_out_padding(outfile, padlen, 0xFF, css);
580 
581         return res;
582 }
583 
584 
585 int
586 write_out_header(FILE *outfile, struct zyn_rombin_hdr *hdr)
587 {
588         struct zyn_rombin_hdr t;
589 
590         errno = 0;
591         if (fseek(outfile, 0, SEEK_SET) != 0) {
592                 ERRS("fseek failed on output file");
593                 return -1;
594         }
595 
596         /* setup temporary header fields */
597         memset(&t, 0, sizeof(t));
598         t.addr = HOST_TO_BE32(hdr->addr);
599         memcpy(&t.sig, ROMBIN_SIGNATURE, ROMBIN_SIG_LEN);
600         t.type = hdr->type;
601         t.flags = hdr->flags;
602         t.osize = HOST_TO_BE32(hdr->osize);
603         t.csize = HOST_TO_BE32(hdr->csize);
604         t.ocsum = HOST_TO_BE16(hdr->ocsum);
605         t.ccsum = HOST_TO_BE16(hdr->ccsum);
606         t.mmap_addr = HOST_TO_BE32(hdr->mmap_addr);
607 
608         DBG(2, "hdr.addr      = 0x%08x", hdr->addr);
609         DBG(2, "hdr.type      = 0x%02x", hdr->type);
610         DBG(2, "hdr.osize     = 0x%08x", hdr->osize);
611         DBG(2, "hdr.csize     = 0x%08x", hdr->csize);
612         DBG(2, "hdr.flags     = 0x%02x", hdr->flags);
613         DBG(2, "hdr.ocsum     = 0x%04x", hdr->ocsum);
614         DBG(2, "hdr.ccsum     = 0x%04x", hdr->ccsum);
615         DBG(2, "hdr.mmap_addr = 0x%08x", hdr->mmap_addr);
616 
617         return write_out_data(outfile, (uint8_t *)&t, sizeof(t), NULL);
618 }
619 
620 
621 int
622 write_out_mmap(FILE *outfile, struct fw_mmap *mmap, struct csum_state *css)
623 {
624         struct zyn_mmt_hdr *mh;
625         uint8_t buf[MMAP_DATA_SIZE];
626         uint32_t user_size;
627         char *data;
628         int res;
629 
630         memset(buf, 0, sizeof(buf));
631 
632         mh = (struct zyn_mmt_hdr *)buf;
633 
634         /* TODO: needs to recreate the memory map too? */
635         mh->count=0;
636 
637         /* Build user data section */
638         data = (char *)buf + sizeof(*mh);
639         data += sprintf(data, "Vendor 1 %d", board->vendor);
640         *data++ = '\0';
641         data += sprintf(data, "Model 1 %d", BE16_TO_HOST(board->model));
642         *data++ = '\0';
643         /* TODO: make hardware version configurable? */
644         data += sprintf(data, "HwVerRange 2 %d %d", 0, 0);
645         *data++ = '\0';
646 
647         user_size = (uint8_t *)data - buf;
648         mh->user_start= HOST_TO_BE32(mmap->addr+sizeof(*mh));
649         mh->user_end= HOST_TO_BE32(mmap->addr+user_size);
650         mh->csum = HOST_TO_BE16(csum_buf(buf+sizeof(*mh), user_size));
651 
652         res = write_out_data(outfile, buf, sizeof(buf), css);
653 
654         return res;
655 }
656 
657 
658 int
659 block_stat_file(struct fw_block *block)
660 {
661         struct stat st;
662         int res;
663 
664         if (block->file_name == NULL)
665                 return 0;
666 
667         res = stat(block->file_name, &st);
668         if (res){
669                 ERRS("stat failed on %s", block->file_name);
670                 return res;
671         }
672 
673         block->file_size = st.st_size;
674         return 0;
675 }
676 
677 
678 int
679 read_magic(uint16_t *magic)
680 {
681         FILE *f;
682         int res;
683 
684         errno = 0;
685         f = fopen(bootext_block->file_name,"r");
686         if (errno) {
687                 ERRS("unable to open file: %s", bootext_block->file_name);
688                 return -1;
689         }
690 
691         errno = 0;
692         fread(magic, 2, 1, f);
693         if (errno != 0) {
694                 ERRS("unable to read from file: %s", bootext_block->file_name);
695                 res = -1;
696                 goto err;
697         }
698 
699         res = 0;
700 
701 err:
702         fclose(f);
703         return res;
704 }
705 
706 
707 int
708 write_out_file(FILE *outfile, char *name, size_t len, struct csum_state *css)
709 {
710         char buf[FILE_BUF_LEN];
711         size_t buflen = sizeof(buf);
712         FILE *f;
713         int res;
714 
715         DBG(2, "writing out file, name=%s, len=%zu",
716                 name, len);
717 
718         errno = 0;
719         f = fopen(name,"r");
720         if (errno) {
721                 ERRS("unable to open file: %s", name);
722                 return -1;
723         }
724 
725         while (len > 0) {
726                 if (len < buflen)
727                         buflen = len;
728 
729                 /* read data from source file */
730                 errno = 0;
731                 fread(buf, buflen, 1, f);
732                 if (errno != 0) {
733                         ERRS("unable to read from file: %s",name);
734                         res = -1;
735                         break;
736                 }
737 
738                 res = write_out_data(outfile, buf, buflen, css);
739                 if (res)
740                         break;
741 
742                 len -= buflen;
743         }
744 
745         fclose(f);
746         return res;
747 }
748 
749 
750 int
751 write_out_block(FILE *outfile, struct fw_block *block, struct csum_state *css)
752 {
753         int res;
754 
755         if (block == NULL)
756                 return 0;
757 
758         if (block->file_name == NULL)
759                 return 0;
760 
761         if (block->file_size == 0)
762                 return 0;
763 
764         res = write_out_file(outfile, block->file_name,
765                         block->file_size, css);
766         return res;
767 }
768 
769 
770 int
771 write_out_image(FILE *outfile)
772 {
773         struct fw_block *block;
774         struct fw_mmap mmap;
775         struct zyn_rombin_hdr hdr;
776         struct csum_state css;
777         int i, res;
778         uint32_t offset;
779         uint32_t padlen;
780         uint16_t csum;
781         uint16_t t;
782 
783         /* setup header fields */
784         memset(&hdr, 0, sizeof(hdr));
785         hdr.addr = board->code_start;
786         hdr.type = OBJECT_TYPE_BOOTEXT;
787         hdr.flags = ROMBIN_FLAG_OCSUM;
788 
789         offset = board->romio_offs;
790 
791         res = write_out_header(outfile, &hdr);
792         if (res)
793                 return res;
794 
795         offset += sizeof(hdr);
796 
797         csum_init(&css);
798         res = write_out_block(outfile, bootext_block, &css);
799         if (res)
800                 return res;
801 
802         offset += bootext_block->file_size;
803         if (offset > (board->romio_offs + board->bootext_size)) {
804                 ERR("bootext file '%s' is too big", bootext_block->file_name);
805                 return -1;
806         }
807 
808         padlen = ALIGN(offset, MMAP_ALIGN) - offset;
809         res = write_out_padding(outfile, padlen, 0xFF, &css);
810         if (res)
811                 return res;
812 
813         offset += padlen;
814 
815         mmap.addr = board->flash_base + offset;
816         res = write_out_mmap(outfile, &mmap, &css);
817         if (res)
818                 return res;
819 
820         offset += MMAP_DATA_SIZE;
821 
822         if ((offset - board->romio_offs) < board->bootext_size) {
823                 padlen = board->romio_offs + board->bootext_size - offset;
824                 res = write_out_padding(outfile, padlen, 0xFF, &css);
825                 if (res)
826                         return res;
827                 offset += padlen;
828 
829                 DBG(2, "bootext end at %08x", offset);
830         }
831 
832         for (i = 0; i < num_blocks; i++) {
833                 block = &blocks[i];
834 
835                 if (block->type == BLOCK_TYPE_BOOTEXT)
836                         continue;
837 
838                 padlen = ALIGN(offset, block->align) - offset;
839                 res = write_out_padding(outfile, padlen, 0xFF, &css);
840                 if (res)
841                         return res;
842                 offset += padlen;
843 
844                 res = write_out_block(outfile, block, &css);
845                 if (res)
846                         return res;
847                 offset += block->file_size;
848         }
849 
850         padlen = ALIGN(offset, 4) - offset;
851         res = write_out_padding(outfile, padlen, 0xFF, &css);
852         if (res)
853                 return res;
854         offset += padlen;
855 
856         csum = csum_get(&css);
857         hdr.mmap_addr = mmap.addr;
858         hdr.osize = 2;
859 
860         res = read_magic(&hdr.ocsum);
861         if (res)
862                 return res;
863         hdr.ocsum = BE16_TO_HOST(hdr.ocsum);
864 
865         if (csum <= hdr.ocsum)
866                 t = hdr.ocsum - csum;
867         else
868                 t = hdr.ocsum - csum - 1;
869 
870         DBG(2, "ocsum=%04x, csum=%04x, fix=%04x", hdr.ocsum, csum, t);
871 
872         t = HOST_TO_BE16(t);
873         res = write_out_data(outfile, (uint8_t *)&t, 2, NULL);
874         if (res)
875                 return res;
876 
877 
878         res = write_out_header(outfile, &hdr);
879 
880         return res;
881 }
882 
883 
884 struct board_info *
885 find_board(char *name)
886 {
887         struct board_info *ret;
888         struct board_info *board;
889 
890         ret = NULL;
891         for (board = boards; board->name != NULL; board++){
892                 if (strcasecmp(name, board->name) == 0) {
893                         ret = board;
894                         break;
895                 }
896         };
897 
898         return ret;
899 }
900 
901 
902 int
903 parse_opt_board(char ch, char *arg)
904 {
905 
906         DBG(1,"parsing board option: -%c %s", ch, arg);
907 
908         if (board != NULL) {
909                 ERR("only one board option allowed");
910                 return -1;
911         }
912 
913         if (required_arg(ch, arg))
914                 return -1;
915 
916         board = find_board(arg);
917         if (board == NULL){
918                 ERR("invalid/unknown board specified: %s", arg);
919                 return -1;
920         }
921 
922         return 0;
923 }
924 
925 
926 int
927 parse_opt_ofname(char ch, char *arg)
928 {
929 
930         if (ofname != NULL) {
931                 ERR("only one output file allowed");
932                 return -1;
933         }
934 
935         if (required_arg(ch, arg))
936                 return -1;
937 
938         ofname = arg;
939 
940         return 0;
941 }
942 
943 
944 int
945 parse_opt_block(char ch, char *arg)
946 {
947         char buf[MAX_ARG_LEN];
948         char *argv[MAX_ARG_COUNT];
949         char *p;
950         struct fw_block *block;
951         int i;
952 
953         if ( num_blocks >= MAX_NUM_BLOCKS ) {
954                 ERR("too many blocks specified");
955                 return -1;
956         }
957 
958         block = &blocks[num_blocks++];
959 
960         /* setup default field values */
961         block->padc = 0xFF;
962 
963         switch(ch) {
964         case 'b':
965                 if (bootext_block) {
966                         ERR("only one boot extension block allowed");
967                         break;
968                 }
969                 block->type = BLOCK_TYPE_BOOTEXT;
970                 bootext_block = block;
971                 break;
972         case 'r':
973                 block->type = BLOCK_TYPE_RAW;
974                 break;
975         }
976 
977         parse_arg(arg, buf, argv);
978 
979         i = 0;
980         p = argv[i++];
981         if (is_empty_arg(p)) {
982                 ERR("no file specified in %s", arg);
983                 return -1;
984         } else {
985                 block->file_name = strdup(p);
986                 if (block->file_name == NULL) {
987                         ERR("not enough memory");
988                         return -1;
989                 }
990         }
991 
992         if (block->type == BLOCK_TYPE_BOOTEXT)
993                 return 0;
994 
995         p = argv[i++];
996         if (!is_empty_arg(p)) {
997                 if (str2u32(p, &block->align) != 0) {
998                         ERR("invalid block align in %s", arg);
999                         return -1;
1000                 }
1001         }
1002 
1003         return 0;
1004 }
1005 
1006 
1007 int
1008 calc_block_offsets(int type, uint32_t *offset)
1009 {
1010         struct fw_block *block;
1011         uint32_t next_offs;
1012         uint32_t avail;
1013         int i, res;
1014 
1015         DBG(1,"calculating block offsets, starting with %" PRIu32,
1016                 *offset);
1017 
1018         res = 0;
1019         for (i = 0; i < num_blocks; i++) {
1020                 block = &blocks[i];
1021 
1022                 if (block->type != type)
1023                         continue;
1024 
1025                 next_offs = ALIGN(*offset, block->align);
1026                 avail = board->flash_size - next_offs;
1027                 if (block->file_size > avail) {
1028                         ERR("file %s is too big, offset = %u, size=%u,"
1029                                 " avail = %u, align = %u", block->file_name,
1030                                 (unsigned)next_offs,
1031                                 (unsigned)block->file_size,
1032                                 (unsigned)avail,
1033                                 (unsigned)block->align);
1034                         res = -1;
1035                         break;
1036                 }
1037 
1038                 block->padlen = next_offs - *offset;
1039                 *offset += block->file_size;
1040         }
1041 
1042         return res;
1043 }
1044 
1045 int
1046 process_blocks(void)
1047 {
1048         struct fw_block *block;
1049         uint32_t offset;
1050         int i;
1051         int res;
1052 
1053         /* collecting file stats */
1054         for (i = 0; i < num_blocks; i++) {
1055                 block = &blocks[i];
1056                 res = block_stat_file(block);
1057                 if (res)
1058                         return res;
1059         }
1060 
1061         offset = board->romio_offs + bootext_block->file_size;
1062         res = calc_block_offsets(BLOCK_TYPE_RAW, &offset);
1063 
1064         return res;
1065 }
1066 
1067 
1068 int
1069 main(int argc, char *argv[])
1070 {
1071         int optinvalid = 0;   /* flag for invalid option */
1072         int c;
1073         int res = EXIT_FAILURE;
1074 
1075         FILE *outfile;
1076 
1077         progname=basename(argv[0]);
1078 
1079         opterr = 0;  /* could not print standard getopt error messages */
1080         while ( 1 ) {
1081                 optinvalid = 0;
1082 
1083                 c = getopt(argc, argv, "b:B:ho:r:v");
1084                 if (c == -1)
1085                         break;
1086 
1087                 switch (c) {
1088                 case 'b':
1089                 case 'r':
1090                         optinvalid = parse_opt_block(c,optarg);
1091                         break;
1092                 case 'B':
1093                         optinvalid = parse_opt_board(c,optarg);
1094                         break;
1095                 case 'o':
1096                         optinvalid = parse_opt_ofname(c,optarg);
1097                         break;
1098                 case 'v':
1099                         verblevel++;
1100                         break;
1101                 case 'h':
1102                         usage(EXIT_SUCCESS);
1103                         break;
1104                 default:
1105                         optinvalid = 1;
1106                         break;
1107                 }
1108                 if (optinvalid != 0 ) {
1109                         ERR("invalid option: -%c", optopt);
1110                         goto out;
1111                 }
1112         }
1113 
1114         if (board == NULL) {
1115                 ERR("no board specified");
1116                 goto out;
1117         }
1118 
1119         if (ofname == NULL) {
1120                 ERR("no output file specified");
1121                 goto out;
1122         }
1123 
1124         if (optind < argc) {
1125                 ERR("invalid option: %s", argv[optind]);
1126                 goto out;
1127         }
1128 
1129         if (process_blocks() != 0) {
1130                 goto out;
1131         }
1132 
1133         outfile = fopen(ofname, "w");
1134         if (outfile == NULL) {
1135                 ERRS("could not open \"%s\" for writing", ofname);
1136                 goto out;
1137         }
1138 
1139         if (write_out_image(outfile) != 0)
1140                 goto out_flush;
1141 
1142         DBG(1,"Image file %s completed.", ofname);
1143 
1144         res = EXIT_SUCCESS;
1145 
1146 out_flush:
1147         fflush(outfile);
1148         fclose(outfile);
1149         if (res != EXIT_SUCCESS) {
1150                 unlink(ofname);
1151         }
1152 out:
1153         return res;
1154 }
1155 

This page was automatically generated by LXR 0.3.1.  •  OpenWrt