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