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

Sources/firmware-utils/src/mkcsysimg.c

  1 // SPDX-License-Identifier: GPL-2.0-or-later
  2 /*
  3  *
  4  *  Copyright (C) 2007-2009 Gabor Juhos <juhosg@openwrt.org>
  5  *
  6  *  This program was based on the code found in various Linux
  7  *  source tarballs released by Edimax for it's devices.
  8  *  Original author: David Hsu <davidhsu@realtek.com.tw>
  9  */
 10 
 11 #include <stdio.h>
 12 #include <stdlib.h>
 13 #include <stdint.h>
 14 #include <string.h>
 15 #include <unistd.h>     /* for unlink() */
 16 #include <libgen.h>
 17 #include <getopt.h>     /* for getopt() */
 18 #include <stdarg.h>
 19 #include <errno.h>
 20 #include <sys/stat.h>
 21 #include <endian.h>     /* for __BYTE_ORDER */
 22 #include <byteswap.h>
 23 
 24 #include "csysimg.h"
 25 
 26 #if (__BYTE_ORDER == __LITTLE_ENDIAN)
 27 #  define HOST_TO_LE16(x)       (x)
 28 #  define HOST_TO_LE32(x)       (x)
 29 #  define LE16_TO_HOST(x)       (x)
 30 #  define LE32_TO_HOST(x)       (x)
 31 #else
 32 #  define HOST_TO_LE16(x)       bswap_16(x)
 33 #  define HOST_TO_LE32(x)       bswap_32(x)
 34 #  define LE16_TO_HOST(x)       bswap_16(x)
 35 #  define LE32_TO_HOST(x)       bswap_32(x)
 36 #endif
 37 
 38 #define MAX_NUM_BLOCKS  8
 39 #define MAX_ARG_COUNT   32
 40 #define MAX_ARG_LEN     1024
 41 #define FILE_BUF_LEN    (16*1024)
 42 #define CSYS_PADC       0xFF
 43 
 44 #define BLOCK_TYPE_BOOT 0
 45 #define BLOCK_TYPE_CONF 1
 46 #define BLOCK_TYPE_WEBP 2
 47 #define BLOCK_TYPE_CODE 3
 48 #define BLOCK_TYPE_XTRA 4
 49 
 50 #define DEFAULT_BLOCK_ALIGN     0x10000U
 51 
 52 #define CSUM_SIZE_NONE  0
 53 #define CSUM_SIZE_8     1
 54 #define CSUM_SIZE_16    2
 55 
 56 
 57 struct csum_state{
 58         int     size;
 59         uint16_t val;
 60         uint16_t tmp;
 61         int     odd;
 62 };
 63 
 64 
 65 struct csys_block {
 66         int             type;   /* type of the block */
 67 
 68         int             need_file;
 69         char            *file_name;     /* name of the file */
 70         uint32_t        file_size;      /* length of the file */
 71 
 72         unsigned char   sig[SIG_LEN];
 73         uint32_t        addr;
 74         int             addr_set;
 75         uint32_t        align;
 76         int             align_set;
 77         uint8_t         padc;
 78 
 79         uint32_t        size;
 80         uint32_t        size_hdr;
 81         uint32_t        size_csum;
 82         uint32_t        size_avail;
 83 
 84         struct csum_state *css;
 85 };
 86 
 87 
 88 struct board_info {
 89         char *model;
 90         char *name;
 91         uint32_t flash_size;
 92 
 93         char sig_boot[SIG_LEN];
 94         char sig_conf[SIG_LEN];
 95         char sig_webp[SIG_LEN];
 96 
 97         uint32_t boot_size;
 98         uint32_t conf_size;
 99         uint32_t webp_size;
100         uint32_t webp_size_max;
101         uint32_t code_size;
102 
103         uint32_t addr_code;
104         uint32_t addr_webp;
105 };
106 
107 #define BOARD(m, n, f, sigb, sigw, bs, cs, ws, ac, aw) {\
108         .model = m, .name = n, .flash_size = f<<20, \
109         .sig_boot = sigb, .sig_conf = SIG_CONF, .sig_webp = sigw, \
110         .boot_size = bs, .conf_size = cs, \
111         .webp_size = ws, .webp_size_max = 3*0x10000, \
112         .addr_code = ac, .addr_webp = aw \
113         }
114 
115 #define BOARD_ADM(m,n,f, sigw) BOARD(m,n,f, ADM_BOOT_SIG, sigw, \
116         ADM_BOOT_SIZE, ADM_CONF_SIZE, ADM_WEBP_SIZE, \
117         ADM_CODE_ADDR, ADM_WEBP_ADDR)
118 
119 
120 /*
121  * Globals
122  */
123 char *progname;
124 char *ofname = NULL;
125 int verblevel = 0;
126 int invalid_causes_error = 1;
127 int keep_invalid_images = 0;
128 
129 struct board_info *board = NULL;
130 
131 struct csys_block *boot_block = NULL;
132 struct csys_block *conf_block = NULL;
133 struct csys_block *webp_block = NULL;
134 struct csys_block *code_block = NULL;
135 
136 struct csys_block blocks[MAX_NUM_BLOCKS];
137 int num_blocks = 0;
138 
139 static struct board_info boards[] = {
140         /* The original Edimax products */
141         BOARD_ADM("BR-6104K", "Edimax BR-6104K", 2, SIG_BR6104K),
142         BOARD_ADM("BR-6104KP", "Edimax BR-6104KP", 2, SIG_BR6104KP),
143         BOARD_ADM("BR-6104Wg", "Edimax BR-6104Wg", 2, SIG_BR6104Wg),
144         BOARD_ADM("BR-6114WG", "Edimax BR-6114WG", 2, SIG_BR6114WG),
145         BOARD_ADM("BR-6524K", "Edimax BR-6524K", 2, SIG_BR6524K),
146         BOARD_ADM("BR-6524KP", "Edimax BR-6524KP", 2, SIG_BR6524KP),
147         BOARD_ADM("BR-6524N", "Edimax BR-6524N", 2, SIG_BR6524N),
148         BOARD_ADM("BR-6524WG", "Edimax BR-6524WG", 4, SIG_BR6524WG),
149         BOARD_ADM("BR-6524WP", "Edimax BR-6524WP", 4, SIG_BR6524WP),
150         BOARD_ADM("BR-6541K", "Edimax BR-6541K", 2, SIG_BR6541K),
151         BOARD_ADM("BR-6541KP", "Edimax BR-6541K", 2, SIG_BR6541KP),
152         BOARD_ADM("BR-6541WP", "Edimax BR-6541WP", 4, SIG_BR6541WP),
153         BOARD_ADM("EW-7207APg", "Edimax EW-7207APg", 2, SIG_EW7207APg),
154         BOARD_ADM("PS-1205UWg", "Edimax PS-1205UWg", 2, SIG_PS1205UWg),
155         BOARD_ADM("PS-3205U", "Edimax PS-3205U", 2, SIG_PS3205U),
156         BOARD_ADM("PS-3205UWg", "Edimax PS-3205UWg", 2, SIG_PS3205UWg),
157 
158         /* Hawking products */
159         BOARD_ADM("H2BR4", "Hawking H2BR4", 2, SIG_H2BR4),
160         BOARD_ADM("H2WR54G", "Hawking H2WR54G", 4, SIG_H2WR54G),
161 
162         /* Planet products */
163         BOARD_ADM("XRT-401D", "Planet XRT-401D", 2, SIG_XRT401D),
164         BOARD_ADM("XRT-402D", "Planet XRT-402D", 2, SIG_XRT402D),
165 
166         /* Conceptronic products */
167         BOARD_ADM("C54BSR4", "Conceptronic C54BSR4", 2, SIG_C54BSR4),
168 
169         /* OSBRiDGE products */
170         BOARD_ADM("5GXi", "OSBDRiDGE 5GXi", 2, SIG_5GXI),
171 
172         {.model = NULL}
173 };
174 
175 /*
176  * Message macros
177  */
178 #define ERR(fmt, ...) do { \
179         fflush(0); \
180         fprintf(stderr, "[%s] *** error: " fmt "\n", progname, ## __VA_ARGS__ ); \
181 } while (0)
182 
183 #define ERRS(fmt, ...) do { \
184         int save = errno; \
185         fflush(0); \
186         fprintf(stderr, "[%s] *** error: " fmt ": %s\n", progname, ## __VA_ARGS__ \
187                 , strerror(save)); \
188 } while (0)
189 
190 #define WARN(fmt, ...) do { \
191         fprintf(stderr, "[%s] *** warning: " fmt "\n", progname, ## __VA_ARGS__ ); \
192 } while (0)
193 
194 #define DBG(lev, fmt, ...) do { \
195         if (verblevel < lev) \
196                 break;\
197         fprintf(stderr, "[%s] " fmt "\n", progname, ## __VA_ARGS__ ); \
198 } while (0)
199 
200 #define ERR_FATAL               -1
201 #define ERR_INVALID_IMAGE       -2
202 
203 void
204 usage(int status)
205 {
206         FILE *stream = (status != EXIT_SUCCESS) ? stderr : stdout;
207         struct board_info *board;
208 
209         fprintf(stream, "Usage: %s [OPTIONS...] <file>\n", progname);
210         fprintf(stream,
211 "\n"
212 "Options:\n"
213 "  -B <board>      create image for the board specified with <board>.\n"
214 "                  valid <board> values:\n"
215         );
216         for (board = boards; board->model != NULL; board++){
217                 fprintf(stream,
218 "                  %-12s: %s\n",
219                  board->model, board->name);
220         };
221         fprintf(stream,
222 "  -d              don't throw error on invalid images\n"
223 "  -k              keep invalid images\n"
224 "  -b <file>[:<align>[:<padc>]]\n"
225 "                  add boot code to the image\n"
226 "  -c <file>[:<align>[:<padc>]]\n"
227 "                  add configuration settings to the image\n"
228 "  -r <file>:[<addr>][:<align>[:<padc>]]\n"
229 "                  add runtime code to the image\n"
230 "  -w [<file>:[<addr>][:<align>[:<padc>]]]\n"
231 "                  add webpages to the image\n"
232 "  -x <file>[:<align>[:<padc>]]\n"
233 "                  add extra data at the end of the image\n"
234 "  -h              show this screen\n"
235 "Parameters:\n"
236 "  <file>          write output to the file <file>\n"
237         );
238 
239         exit(status);
240 }
241 
242 static inline uint32_t align(uint32_t base, uint32_t alignment)
243 {
244         uint32_t ret;
245 
246         if (alignment) {
247                 ret = (base + alignment - 1);
248                 ret &= ~(alignment-1);
249         } else {
250                 ret = base;
251         }
252 
253         return ret;
254 }
255 
256 /*
257  * argument parsing
258  */
259 int
260 str2u32(char *arg, uint32_t *val)
261 {
262         char *err = NULL;
263         uint32_t t;
264 
265         errno=0;
266         t = strtoul(arg, &err, 0);
267         if (errno || (err==arg) || ((err != NULL) && *err)) {
268                 return -1;
269         }
270 
271         *val = t;
272         return 0;
273 }
274 
275 
276 int
277 str2u16(char *arg, uint16_t *val)
278 {
279         char *err = NULL;
280         uint32_t t;
281 
282         errno=0;
283         t = strtoul(arg, &err, 0);
284         if (errno || (err==arg) || ((err != NULL) && *err) || (t >= 0x10000)) {
285                 return -1;
286         }
287 
288         *val = t & 0xFFFF;
289         return 0;
290 }
291 
292 int
293 str2u8(char *arg, uint8_t *val)
294 {
295         char *err = NULL;
296         uint32_t t;
297 
298         errno=0;
299         t = strtoul(arg, &err, 0);
300         if (errno || (err==arg) || ((err != NULL) && *err) || (t >= 0x100)) {
301                 return -1;
302         }
303 
304         *val = t & 0xFF;
305         return 0;
306 }
307 
308 int
309 str2sig(char *arg, uint32_t *sig)
310 {
311         if (strlen(arg) != 4)
312                 return -1;
313 
314         *sig = arg[0] | (arg[1] << 8) | (arg[2] << 16) | (arg[3] << 24);
315 
316         return 0;
317 }
318 
319 
320 int
321 parse_arg(char *arg, char *buf, char *argv[])
322 {
323         int res = 0;
324         size_t argl;
325         char *tok;
326         char **ap = &buf;
327         int i;
328 
329         memset(argv, 0, MAX_ARG_COUNT * sizeof(void *));
330 
331         if ((arg == NULL)) {
332                 /* no arguments */
333                 return 0;
334         }
335 
336         argl = strlen(arg);
337         if (argl == 0) {
338                 /* no arguments */
339                 return 0;
340         }
341 
342         if (argl >= MAX_ARG_LEN) {
343                 /* argument is too long */
344                 argl = MAX_ARG_LEN-1;
345         }
346 
347         memcpy(buf, arg, argl);
348         buf[argl] = '\0';
349 
350         for (i = 0; i < MAX_ARG_COUNT; i++) {
351                 tok = strsep(ap, ":");
352                 if (tok == NULL) {
353                         break;
354                 }
355 #if 0
356                 else if (tok[0] == '\0') {
357                         break;
358                 }
359 #endif
360                 argv[i] = tok;
361                 res++;
362         }
363 
364         return res;
365 }
366 
367 
368 int
369 required_arg(char c, char *arg)
370 {
371         if (arg == NULL || *arg != '-')
372                 return 0;
373 
374         ERR("option -%c requires an argument\n", c);
375         return ERR_FATAL;
376 }
377 
378 
379 int
380 is_empty_arg(char *arg)
381 {
382         int ret = 1;
383         if (arg != NULL) {
384                 if (*arg) ret = 0;
385         };
386         return ret;
387 }
388 
389 
390 void
391 csum8_update(uint8_t *p, uint32_t len, struct csum_state *css)
392 {
393         for ( ; len > 0; len --) {
394                 css->val += *p++;
395         }
396 }
397 
398 
399 uint16_t
400 csum8_get(struct csum_state *css)
401 {
402         uint8_t t;
403 
404         t = css->val;
405         return ~t + 1;
406 }
407 
408 
409 void
410 csum16_update(void *data, uint32_t len, struct csum_state *css)
411 {
412         uint8_t *p = data;
413         uint16_t t;
414 
415         if (css->odd) {
416                 t = css->tmp + (p[0]<<8);
417                 css->val += LE16_TO_HOST(t);
418                 css->odd = 0;
419                 len--;
420                 p++;
421         }
422 
423         for ( ; len > 1; len -= 2, p +=2 ) {
424                 t = p[0] + (p[1] << 8);
425                 css->val += LE16_TO_HOST(t);
426         }
427 
428         if (len == 1) {
429                 css->tmp = p[0];
430                 css->odd = 1;
431         }
432 }
433 
434 
435 uint16_t
436 csum16_get(struct csum_state *css)
437 {
438         char pad = 0;
439 
440         csum16_update(&pad, 1, css);
441         return ~css->val + 1;
442 }
443 
444 
445 void
446 csum_init(struct csum_state *css, int size)
447 {
448         css->val = 0;
449         css->tmp = 0;
450         css->odd = 0;
451         css->size = size;
452 }
453 
454 
455 void
456 csum_update(void *data, uint32_t len, struct csum_state *css)
457 {
458         uint8_t *p = data;
459 
460         switch (css->size) {
461         case CSUM_SIZE_8:
462                 csum8_update(p,len,css);
463                 break;
464         case CSUM_SIZE_16:
465                 csum16_update(p,len,css);
466                 break;
467         }
468 }
469 
470 
471 uint16_t
472 csum_get(struct csum_state *css)
473 {
474         uint16_t ret;
475 
476         switch (css->size) {
477         case CSUM_SIZE_8:
478                 ret = csum8_get(css);
479                 break;
480         case CSUM_SIZE_16:
481                 ret = csum16_get(css);
482                 break;
483         default:
484                 ERR("invalid checksum size\n");
485                 return 0;
486         }
487 
488         return ret;
489 }
490 
491 
492 /*
493  * routines to write data to the output file
494  */
495 int
496 write_out_data(FILE *outfile, void *data, size_t len,
497                 struct csum_state *css)
498 {
499         uint8_t *ptr = data;
500 
501         errno = 0;
502 
503         fwrite(ptr, len, 1, outfile);
504         if (errno) {
505                 ERRS("unable to write output file");
506                 return ERR_FATAL;
507         }
508 
509         if (css) {
510                 csum_update(ptr, len, css);
511         }
512 
513         return 0;
514 }
515 
516 
517 int
518 write_out_padding(FILE *outfile, size_t len, uint8_t padc,
519                  struct csum_state *css)
520 {
521         uint8_t buf[512];
522         size_t buflen = sizeof(buf);
523         int err;
524 
525         memset(buf, padc, buflen);
526         while (len > 0) {
527                 if (len < buflen)
528                         buflen = len;
529 
530                 err = write_out_data(outfile, buf, buflen, css);
531                 if (err)
532                         return err;
533 
534                 len -= buflen;
535         }
536 
537         return 0;
538 }
539 
540 
541 int
542 block_stat_file(struct csys_block *block)
543 {
544         struct stat st;
545         int err;
546 
547         if (block->file_name == NULL)
548                 return 0;
549 
550         err = stat(block->file_name, &st);
551         if (err){
552                 ERRS("stat failed on %s", block->file_name);
553                 return ERR_FATAL;
554         }
555 
556         block->file_size = st.st_size;
557         return 0;
558 }
559 
560 
561 int
562 block_writeout_hdr(FILE *outfile, struct csys_block *block)
563 {
564         struct csys_header hdr;
565         int res;
566 
567         if (block->size_hdr == 0)
568                 return 0;
569 
570         /* setup header fields */
571         memcpy(hdr.sig, block->sig, 4);
572         hdr.addr = HOST_TO_LE32(block->addr);
573         hdr.size = HOST_TO_LE32(block->size - block->size_hdr - block->size_csum);
574 
575         DBG(1,"writing header for block");
576         res = write_out_data(outfile, (uint8_t *)&hdr, sizeof(hdr),NULL);
577         return res;
578 
579 }
580 
581 
582 int
583 block_writeout_file(FILE *outfile, struct csys_block *block)
584 {
585         char buf[FILE_BUF_LEN];
586         size_t buflen = sizeof(buf);
587         FILE *f;
588         size_t len;
589         int res;
590 
591         if (block->file_name == NULL)
592                 return 0;
593 
594         if (block->file_size == 0)
595                 return 0;
596 
597         errno = 0;
598         f = fopen(block->file_name,"r");
599         if (errno) {
600                 ERRS("unable to open file: %s", block->file_name);
601                 return ERR_FATAL;
602         }
603 
604         len = block->file_size;
605         while (len > 0) {
606                 if (len < buflen)
607                         buflen = len;
608 
609                 /* read data from source file */
610                 errno = 0;
611                 fread(buf, buflen, 1, f);
612                 if (errno != 0) {
613                         ERRS("unable to read from file: %s", block->file_name);
614                         res = ERR_FATAL;
615                         break;
616                 }
617 
618                 res = write_out_data(outfile, buf, buflen, block->css);
619                 if (res)
620                         break;
621 
622                 len -= buflen;
623         }
624 
625         fclose(f);
626         return res;
627 }
628 
629 
630 int
631 block_writeout_data(FILE *outfile, struct csys_block *block)
632 {
633         int res;
634         size_t padlen;
635 
636         res = block_writeout_file(outfile, block);
637         if (res)
638                 return res;
639 
640         /* write padding data if neccesary */
641         padlen = block->size_avail - block->file_size;
642         DBG(1,"padding block, length=%zu", padlen);
643         res = write_out_padding(outfile, padlen, block->padc, block->css);
644 
645         return res;
646 }
647 
648 
649 int
650 block_writeout_csum(FILE *outfile, struct csys_block *block)
651 {
652         uint16_t csum;
653         int res;
654 
655         if (block->size_csum == 0)
656                 return 0;
657 
658         DBG(1,"writing checksum for block");
659         csum = HOST_TO_LE16(csum_get(block->css));
660         res = write_out_data(outfile, (uint8_t *)&csum, block->size_csum, NULL);
661 
662         return res;
663 }
664 
665 
666 int
667 block_writeout(FILE *outfile, struct csys_block *block)
668 {
669         int res;
670         struct csum_state css;
671 
672         res = 0;
673 
674         if (block == NULL)
675                 return res;
676 
677         block->css = NULL;
678 
679         DBG(2, "writing block, file=%s, file_size=%d, space=%d",
680                 block->file_name, block->file_size, block->size_avail);
681         res = block_writeout_hdr(outfile, block);
682         if (res)
683                 return res;
684 
685         if (block->size_csum != 0) {
686                 block->css = &css;
687                 csum_init(&css, block->size_csum);
688         }
689 
690         res = block_writeout_data(outfile, block);
691         if (res)
692                 return res;
693 
694         res = block_writeout_csum(outfile, block);
695         if (res)
696                 return res;
697 
698         return res;
699 }
700 
701 
702 int
703 write_out_blocks(FILE *outfile)
704 {
705         struct csys_block *block;
706         int i, res;
707 
708         res = block_writeout(outfile, boot_block);
709         if (res)
710                 return res;
711 
712         res = block_writeout(outfile, conf_block);
713         if (res)
714                 return res;
715 
716         res = block_writeout(outfile, webp_block);
717         if (res)
718                 return res;
719 
720         res = block_writeout(outfile, code_block);
721         if (res)
722                 return res;
723 
724         res = 0;
725         for (i=0; i < num_blocks; i++) {
726                 block = &blocks[i];
727 
728                 if (block->type != BLOCK_TYPE_XTRA)
729                         continue;
730 
731                 res = block_writeout(outfile, block);
732                 if (res)
733                         break;
734         }
735 
736         return res;
737 }
738 
739 
740 struct board_info *
741 find_board(char *model)
742 {
743         struct board_info *ret;
744         struct board_info *board;
745 
746         ret = NULL;
747         for (board = boards; board->model != NULL; board++){
748                 if (strcasecmp(model, board->model) == 0) {
749                         ret = board;
750                         break;
751                 }
752         };
753 
754         return ret;
755 }
756 
757 
758 int
759 parse_opt_board(char ch, char *arg)
760 {
761 
762         DBG(1,"parsing board option: -%c %s", ch, arg);
763 
764         if (board != NULL) {
765                 ERR("only one board option allowed");
766                 return ERR_FATAL;
767         }
768 
769         if (required_arg(ch, arg))
770                 return ERR_FATAL;
771 
772         board = find_board(arg);
773         if (board == NULL){
774                 ERR("invalid/unknown board specified: %s", arg);
775                 return ERR_FATAL;
776         }
777 
778         return 0;
779 }
780 
781 
782 int
783 parse_opt_block(char ch, char *arg)
784 {
785         char buf[MAX_ARG_LEN];
786         char *argv[MAX_ARG_COUNT];
787         char *p;
788         struct csys_block *block;
789         int i;
790 
791         if ( num_blocks > MAX_NUM_BLOCKS ) {
792                 ERR("too many blocks specified");
793                 return ERR_FATAL;
794         }
795 
796         block = &blocks[num_blocks];
797 
798         /* setup default field values */
799         block->need_file = 1;
800         block->padc = 0xFF;
801 
802         switch (ch) {
803         case 'b':
804                 if (boot_block) {
805                         WARN("only one boot block allowed");
806                         break;
807                 }
808                 block->type = BLOCK_TYPE_BOOT;
809                 boot_block = block;
810                 break;
811         case 'c':
812                 if (conf_block) {
813                         WARN("only one config block allowed");
814                         break;
815                 }
816                 block->type = BLOCK_TYPE_CONF;
817                 conf_block = block;
818                 break;
819         case 'w':
820                 if (webp_block) {
821                         WARN("only one web block allowed");
822                         break;
823                 }
824                 block->type = BLOCK_TYPE_WEBP;
825                 block->size_hdr = sizeof(struct csys_header);
826                 block->size_csum = CSUM_SIZE_8;
827                 block->need_file = 0;
828                 webp_block = block;
829                 break;
830         case 'r':
831                 if (code_block) {
832                         WARN("only one runtime block allowed");
833                         break;
834                 }
835                 block->type = BLOCK_TYPE_CODE;
836                 block->size_hdr = sizeof(struct csys_header);
837                 block->size_csum = CSUM_SIZE_16;
838                 code_block = block;
839                 break;
840         case 'x':
841                 block->type = BLOCK_TYPE_XTRA;
842                 break;
843         default:
844                 ERR("unknown block type \"%c\"", ch);
845                 return ERR_FATAL;
846         }
847 
848         parse_arg(arg, buf, argv);
849 
850         i = 0;
851         p = argv[i++];
852         if (!is_empty_arg(p)) {
853                 block->file_name = strdup(p);
854                 if (block->file_name == NULL) {
855                         ERR("not enough memory");
856                         return ERR_FATAL;
857                 }
858         } else if (block->need_file){
859                 ERR("no file specified in %s", arg);
860                 return ERR_FATAL;
861         }
862 
863         if (block->size_hdr) {
864                 p = argv[i++];
865                 if (!is_empty_arg(p)) {
866                         if (str2u32(p, &block->addr) != 0) {
867                                 ERR("invalid start address in %s", arg);
868                                 return ERR_FATAL;
869                         }
870                         block->addr_set = 1;
871                 }
872         }
873 
874         p = argv[i++];
875         if (!is_empty_arg(p)) {
876                 if (str2u32(p, &block->align) != 0) {
877                         ERR("invalid alignment value in %s", arg);
878                         return ERR_FATAL;
879                 }
880                 block->align_set = 1;
881         }
882 
883         p = argv[i++];
884         if (!is_empty_arg(p) && (str2u8(p, &block->padc) != 0)) {
885                 ERR("invalid paddig character in %s", arg);
886                 return ERR_FATAL;
887         }
888 
889         num_blocks++;
890 
891         return 0;
892 }
893 
894 
895 int
896 process_blocks(void)
897 {
898         struct csys_block *block;
899         uint32_t offs = 0;
900         int i;
901         int res;
902 
903         res = 0;
904         /* collecting stats */
905         for (i = 0; i < num_blocks; i++) {
906                 block = &blocks[i];
907                 res = block_stat_file(block);
908                 if (res)
909                         return res;
910         }
911 
912         /* bootloader */
913         block = boot_block;
914         if (block) {
915                 block->size = board->boot_size;
916                 if (block->file_size > board->boot_size) {
917                         WARN("boot block is too big");
918                         res = ERR_INVALID_IMAGE;
919                 }
920         }
921         offs += board->boot_size;
922 
923         /* configuration data */
924         block = conf_block;
925         if (block) {
926                 block->size = board->conf_size;
927                 if (block->file_size > board->conf_size) {
928                         WARN("config block is too big");
929                         res = ERR_INVALID_IMAGE;
930                 }
931         }
932         offs += board->conf_size;
933 
934         /* webpages */
935         block = webp_block;
936         if (block) {
937 
938                 memcpy(block->sig, board->sig_webp, 4);
939 
940                 if (block->addr_set == 0)
941                         block->addr = board->addr_webp;
942 
943                 if (block->align_set == 0)
944                         block->align = DEFAULT_BLOCK_ALIGN;
945 
946                 block->size = align(offs + block->file_size + block->size_hdr +
947                                 block->size_csum, block->align) - offs;
948 
949                 if (block->size > board->webp_size_max) {
950                         WARN("webpages block is too big");
951                         res = ERR_INVALID_IMAGE;
952                 }
953 
954                 DBG(2,"webpages start at %08x, size=%08x", offs,
955                                 block->size);
956 
957                 offs += block->size;
958                 if (offs > board->flash_size) {
959                         WARN("webp block is too big");
960                         res = ERR_INVALID_IMAGE;
961                 }
962         }
963 
964         /* runtime code */
965         block = code_block;
966         if (block) {
967                 memcpy(code_block->sig, SIG_CSYS, 4);
968 
969                 if (block->addr_set == 0)
970                         block->addr = board->addr_code;
971 
972                 if (block->align_set == 0)
973                         block->align = DEFAULT_BLOCK_ALIGN;
974 
975                 block->size = align(offs + block->file_size +
976                                 block->size_hdr + block->size_csum,
977                                 block->align) - offs;
978 
979                 DBG(2,"code block start at %08x, size=%08x", offs,
980                                 block->size);
981 
982                 offs += block->size;
983                 if (offs > board->flash_size) {
984                         WARN("code block is too big");
985                         res = ERR_INVALID_IMAGE;
986                 }
987         }
988 
989         for (i = 0; i < num_blocks; i++) {
990                 block = &blocks[i];
991 
992                 if (block->type != BLOCK_TYPE_XTRA)
993                         continue;
994 
995                 if (block->align_set == 0)
996                         block->align = DEFAULT_BLOCK_ALIGN;
997 
998                 block->size = align(offs + block->file_size,
999                                 block->align) - offs;
1000 
1001                 DBG(2,"file %s start at %08x, size=%08x, align=%08x",
1002                         block->file_name, offs, block->size, block->align);
1003 
1004                 offs += block->size;
1005                 if (offs > board->flash_size) {
1006                         WARN("file %s is too big, size=%d, avail=%d",
1007                                 block->file_name, block->file_size,
1008                                 board->flash_size - offs);
1009                         res = ERR_INVALID_IMAGE;
1010                 }
1011         }
1012 
1013         for (i = 0; i < num_blocks; i++) {
1014                 block = &blocks[i];
1015 
1016                 block->size_avail = block->size - block->size_hdr -
1017                         block->size_csum;
1018 
1019                 if (block->size_avail < block->file_size) {
1020                         WARN("file %s is too big, size=%d, avail=%d",
1021                                 block->file_name, block->file_size,
1022                                 block->size_avail);
1023                         res = ERR_INVALID_IMAGE;
1024                 }
1025         }
1026 
1027         return res;
1028 }
1029 
1030 
1031 int
1032 main(int argc, char *argv[])
1033 {
1034         int optinvalid = 0;   /* flag for invalid option */
1035         int c;
1036         int res = ERR_FATAL;
1037 
1038         FILE *outfile;
1039 
1040         progname=basename(argv[0]);
1041 
1042         opterr = 0;  /* could not print standard getopt error messages */
1043         while ( 1 ) {
1044                 optinvalid = 0;
1045 
1046                 c = getopt(argc, argv, "b:B:c:dhkr:vw:x:");
1047                 if (c == -1)
1048                         break;
1049 
1050                 switch (c) {
1051                 case 'b':
1052                 case 'c':
1053                 case 'r':
1054                 case 'x':
1055                         optinvalid = parse_opt_block(c,optarg);
1056                         break;
1057                 case 'w':
1058                         if (optarg != NULL && *optarg == '-') {
1059                                 /* rollback */
1060                                 optind--;
1061                                 optarg = NULL;
1062                         }
1063                         optinvalid = parse_opt_block(c,optarg);
1064                         break;
1065                 case 'd':
1066                         invalid_causes_error = 0;
1067                         break;
1068                 case 'k':
1069                         keep_invalid_images = 1;
1070                         break;
1071                 case 'B':
1072                         optinvalid = parse_opt_board(c,optarg);
1073                         break;
1074                 case 'v':
1075                         verblevel++;
1076                         break;
1077                 case 'h':
1078                         usage(EXIT_SUCCESS);
1079                         break;
1080                 default:
1081                         optinvalid = 1;
1082                         break;
1083                 }
1084                 if (optinvalid != 0 ){
1085                         ERR("invalid option: -%c", optopt);
1086                         goto out;
1087                 }
1088         }
1089 
1090         if (board == NULL) {
1091                 ERR("no board specified");
1092                 goto out;
1093         }
1094 
1095         if (optind == argc) {
1096                 ERR("no output file specified");
1097                 goto out;
1098         }
1099 
1100         ofname = argv[optind++];
1101 
1102         if (optind < argc) {
1103                 ERR("invalid option: %s", argv[optind]);
1104                 goto out;
1105         }
1106 
1107         res = process_blocks();
1108         if (res == ERR_FATAL)
1109                 goto out;
1110 
1111         if (res == ERR_INVALID_IMAGE) {
1112                 if (invalid_causes_error)
1113                         res = ERR_FATAL;
1114 
1115                 if (keep_invalid_images == 0) {
1116                         WARN("generation of invalid images \"%s\" disabled", ofname);
1117                         goto out;
1118                 }
1119 
1120                 WARN("generating invalid image: \"%s\"", ofname);
1121         }
1122 
1123         outfile = fopen(ofname, "w");
1124         if (outfile == NULL) {
1125                 ERRS("could not open \"%s\" for writing", ofname);
1126                 res = ERR_FATAL;
1127                 goto out;
1128         }
1129 
1130         if (write_out_blocks(outfile) != 0) {
1131                 res = ERR_FATAL;
1132                 goto out_flush;
1133         }
1134 
1135         DBG(1,"Image file %s completed.", ofname);
1136 
1137 out_flush:
1138         fflush(outfile);
1139         fclose(outfile);
1140         if (res == ERR_FATAL) {
1141                 unlink(ofname);
1142         }
1143 out:
1144         if (res == ERR_FATAL)
1145                 return EXIT_FAILURE;
1146 
1147         return EXIT_SUCCESS;
1148 }
1149 

This page was automatically generated by LXR 0.3.1.  •  OpenWrt