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