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