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

This page was automatically generated by LXR 0.3.1.  •  OpenWrt