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

This page was automatically generated by LXR 0.3.1.  •  OpenWrt