1/* 2 * Copyright (C) 2006-2008 Gabor Juhos <juhosg@openwrt.org> 3 * 4 * This program is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU General Public License 6 * as published by the Free Software Foundation; either version 2 7 * of the License, or (at your option) any later version. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program; if not, write to the 16 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 17 * Boston, MA 02110-1301, USA. 18 * 19 */ 20 21#include <stdio.h> 22#include <stdlib.h> 23#include <stdint.h> 24#include <string.h> 25#include <unistd.h> /* for unlink() */ 26#include <libgen.h> 27#include <getopt.h> /* for getopt() */ 28#include <stdarg.h> 29#include <errno.h> 30#include <sys/stat.h> 31#include <endian.h> /* for __BYTE_ORDER */ 32 33#if defined(__CYGWIN__) 34# include <byteswap.h> 35#endif 36 37#if (__BYTE_ORDER == __LITTLE_ENDIAN) 38# define HOST_TO_LE16(x) (x) 39# define HOST_TO_LE32(x) (x) 40#else 41# define HOST_TO_LE16(x) bswap_16(x) 42# define HOST_TO_LE32(x) bswap_32(x) 43#endif 44 45#include "myloader.h" 46 47#define MAX_FW_BLOCKS 32 48#define MAX_ARG_COUNT 32 49#define MAX_ARG_LEN 1024 50#define FILE_BUF_LEN (16*1024) 51#define PART_NAME_LEN 32 52 53struct fw_block { 54 uint32_t addr; 55 uint32_t blocklen; /* length of the block */ 56 uint32_t flags; 57 58 char *name; /* name of the file */ 59 uint32_t size; /* length of the file */ 60 uint32_t crc; /* crc value of the file */ 61}; 62 63struct fw_part { 64 struct mylo_partition mylo; 65 char name[PART_NAME_LEN]; 66}; 67 68#define BLOCK_FLAG_HAVEHDR 0x0001 69 70struct cpx_board { 71 char *model; /* model number*/ 72 char *name; /* model name*/ 73 char *desc; /* description */ 74 uint16_t vid; /* vendor id */ 75 uint16_t did; /* device id */ 76 uint16_t svid; /* sub vendor id */ 77 uint16_t sdid; /* sub device id */ 78 uint32_t flash_size; /* size of flash */ 79 uint32_t part_offset; /* offset of the partition_table */ 80 uint32_t part_size; /* size of the partition_table */ 81}; 82 83#define BOARD(_vid, _did, _svid, _sdid, _flash, _mod, _name, _desc, _po, _ps) { \ 84 .model = _mod, .name = _name, .desc = _desc, \ 85 .vid = _vid, .did = _did, .svid = _svid, .sdid = _sdid, \ 86 .flash_size = (_flash << 20), \ 87 .part_offset = _po, .part_size = _ps } 88 89#define CPX_BOARD(_did, _flash, _mod, _name, _desc, _po, _ps) \ 90 BOARD(VENID_COMPEX, _did, VENID_COMPEX, _did, _flash, _mod, _name, _desc, _po, _ps) 91 92#define CPX_BOARD_ADM(_did, _flash, _mod, _name, _desc) \ 93 CPX_BOARD(_did, _flash, _mod, _name, _desc, 0x10000, 0x10000) 94 95#define CPX_BOARD_AR71XX(_did, _flash, _mod, _name, _desc) \ 96 CPX_BOARD(_did, _flash, _mod, _name, _desc, 0x20000, 0x8000) 97 98#define CPX_BOARD_AR23XX(_did, _flash, _mod, _name, _desc) \ 99 CPX_BOARD(_did, _flash, _mod, _name, _desc, 0x10000, 0x10000) 100 101#define ALIGN(x,y) ((x)+((y)-1)) & ~((y)-1) 102 103char *progname; 104char *ofname = NULL; 105 106uint32_t flash_size = 0; 107int fw_num_partitions = 0; 108int fw_num_blocks = 0; 109int verblevel = 0; 110 111struct mylo_fw_header fw_header; 112struct fw_part fw_parts[MYLO_MAX_PARTITIONS]; 113struct fw_block fw_blocks[MAX_FW_BLOCKS]; 114struct cpx_board *board; 115 116struct cpx_board boards[] = { 117 CPX_BOARD_ADM(DEVID_COMPEX_NP18A, 4, 118 "NP18A", "Compex NetPassage 18A", 119 "Dualband Wireless A+G Internet Gateway"), 120 CPX_BOARD_ADM(DEVID_COMPEX_NP26G8M, 2, 121 "NP26G8M", "Compex NetPassage 26G (8M)", 122 "Wireless-G Broadband Multimedia Gateway"), 123 CPX_BOARD_ADM(DEVID_COMPEX_NP26G16M, 4, 124 "NP26G16M", "Compex NetPassage 26G (16M)", 125 "Wireless-G Broadband Multimedia Gateway"), 126 CPX_BOARD_ADM(DEVID_COMPEX_NP27G, 4, 127 "NP27G", "Compex NetPassage 27G", 128 "Wireless-G 54Mbps eXtended Range Router"), 129 CPX_BOARD_ADM(DEVID_COMPEX_NP28G, 4, 130 "NP28G", "Compex NetPassage 28G", 131 "Wireless 108Mbps Super-G XR Multimedia Router with 4 USB Ports"), 132 CPX_BOARD_ADM(DEVID_COMPEX_NP28GHS, 4, 133 "NP28GHS", "Compex NetPassage 28G (HotSpot)", 134 "HotSpot Solution"), 135 CPX_BOARD_ADM(DEVID_COMPEX_WP18, 4, 136 "WP18", "Compex NetPassage WP18", 137 "Wireless-G 54Mbps A+G Dualband Access Point"), 138 CPX_BOARD_ADM(DEVID_COMPEX_WP54G, 4, 139 "WP54G", "Compex WP54G", 140 "Wireless-G 54Mbps XR Access Point"), 141 CPX_BOARD_ADM(DEVID_COMPEX_WP54Gv1C, 2, 142 "WP54Gv1C", "Compex WP54G rev.1C", 143 "Wireless-G 54Mbps XR Access Point"), 144 CPX_BOARD_ADM(DEVID_COMPEX_WP54AG, 4, 145 "WP54AG", "Compex WP54AG", 146 "Wireless-AG 54Mbps XR Access Point"), 147 CPX_BOARD_ADM(DEVID_COMPEX_WPP54G, 4, 148 "WPP54G", "Compex WPP54G", 149 "Outdoor Access Point"), 150 CPX_BOARD_ADM(DEVID_COMPEX_WPP54AG, 4, 151 "WPP54AG", "Compex WPP54AG", 152 "Outdoor Access Point"), 153 154 CPX_BOARD_AR71XX(DEVID_COMPEX_WP543, 2, 155 "WP543", "Compex WP543", 156 "BareBoard"), 157 CPX_BOARD_AR71XX(DEVID_COMPEX_WPE72, 8, 158 "WPE72", "Compex WPE72", 159 "BareBoard"), 160 161 CPX_BOARD_AR23XX(DEVID_COMPEX_NP25G, 4, 162 "NP25G", "Compex NetPassage 25G", 163 "Wireless 54Mbps XR Router"), 164 CPX_BOARD_AR23XX(DEVID_COMPEX_WPE53G, 4, 165 "WPE53G", "Compex NetPassage 25G", 166 "Wireless 54Mbps XR Access Point"), 167 {.model = NULL} 168}; 169 170void 171errmsgv(int syserr, const char *fmt, va_list arg_ptr) 172{ 173 int save = errno; 174 175 fflush(0); 176 fprintf(stderr, "[%s] Error: ", progname); 177 vfprintf(stderr, fmt, arg_ptr); 178 if (syserr != 0) { 179 fprintf(stderr, ": %s", strerror(save)); 180 } 181 fprintf(stderr, "\n"); 182} 183 184void 185errmsg(int syserr, const char *fmt, ...) 186{ 187 va_list arg_ptr; 188 va_start(arg_ptr, fmt); 189 errmsgv(syserr, fmt, arg_ptr); 190 va_end(arg_ptr); 191} 192 193void 194dbgmsg(int level, const char *fmt, ...) 195{ 196 va_list arg_ptr; 197 if (verblevel >= level) { 198 fflush(0); 199 va_start(arg_ptr, fmt); 200 vfprintf(stderr, fmt, arg_ptr); 201 fprintf(stderr, "\n"); 202 va_end(arg_ptr); 203 } 204} 205 206 207void 208usage(int status) 209{ 210 FILE *stream = (status != EXIT_SUCCESS) ? stderr : stdout; 211 struct cpx_board *board; 212 213 fprintf(stream, "Usage: %s [OPTION...] <file>\n", progname); 214 fprintf(stream, 215"\n" 216" <file> write output to the <file>\n" 217"\n" 218"Options:\n" 219" -B <board> create firmware for the board specified with <board>.\n" 220" This option set vendor id, device id, subvendor id,\n" 221" subdevice id, and flash size options to the right value.\n" 222" valid <board> values:\n"); 223 for (board = boards; board->model != NULL; board++){ 224 fprintf(stream, 225" %-12s: %s\n", 226 board->model, board->name); 227 }; 228 fprintf(stream, 229" -i <vid>:<did>[:<svid>[:<sdid>]]\n" 230" create firmware for board with vendor id <vid>, device\n" 231" id <did>, subvendor id <svid> and subdevice id <sdid>.\n" 232" -r <rev> set board revision to <rev>.\n" 233" -s <size> set flash size to <size>\n" 234" -b <addr>:<len>[:[<flags>]:<file>]\n" 235" define block at <addr> with length of <len>.\n" 236" valid <flag> values:\n" 237" h : add crc header before the file data.\n" 238" -p <addr>:<len>[:<flags>[:<param>[:<name>[:<file>]]]]\n" 239" add partition at <addr>, with size of <len> to the\n" 240" partition table, set partition name to <name>, partition \n" 241" flags to <flags> and partition parameter to <param>.\n" 242" If the <file> is specified content of the file will be \n" 243" added to the firmware image.\n" 244" valid <flag> values:\n" 245" a: this is the active partition. The bootloader loads\n" 246" the firmware from this partition.\n" 247" h: the partition data have a header.\n" 248" l: the partition data uses LZMA compression.\n" 249" p: the bootloader loads data from this partition to\n" 250" the RAM before decompress it.\n" 251" -h show this screen\n" 252 ); 253 254 exit(status); 255} 256 257/* 258 * Code to compute the CRC-32 table. Borrowed from 259 * gzip-1.0.3/makecrc.c. 260 */ 261 262static uint32_t crc_32_tab[256]; 263 264void 265init_crc_table(void) 266{ 267 /* Not copyrighted 1990 Mark Adler */ 268 269 uint32_t c; /* crc shift register */ 270 uint32_t e; /* polynomial exclusive-or pattern */ 271 int i; /* counter for all possible eight bit values */ 272 int k; /* byte being shifted into crc apparatus */ 273 274 /* terms of polynomial defining this crc (except x^32): */ 275 static const int p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26}; 276 277 /* Make exclusive-or pattern from polynomial */ 278 e = 0; 279 for (i = 0; i < sizeof(p)/sizeof(int); i++) 280 e |= 1L << (31 - p[i]); 281 282 crc_32_tab[0] = 0; 283 284 for (i = 1; i < 256; i++) { 285 c = 0; 286 for (k = i | 256; k != 1; k >>= 1) { 287 c = c & 1 ? (c >> 1) ^ e : c >> 1; 288 if (k & 1) 289 c ^= e; 290 } 291 crc_32_tab[i] = c; 292 } 293} 294 295 296void 297update_crc(uint8_t *p, uint32_t len, uint32_t *crc) 298{ 299 uint32_t t; 300 301 t = *crc ^ 0xFFFFFFFFUL; 302 while (len--) { 303 t = crc_32_tab[(t ^ *p++) & 0xff] ^ (t >> 8); 304 } 305 *crc = t ^ 0xFFFFFFFFUL; 306} 307 308 309uint32_t 310get_crc(uint8_t *p, uint32_t len) 311{ 312 uint32_t crc; 313 314 crc = 0; 315 update_crc(p ,len , &crc); 316 return crc; 317} 318 319 320int 321str2u32(char *arg, uint32_t *val) 322{ 323 char *err = NULL; 324 uint32_t t; 325 326 errno=0; 327 t = strtoul(arg, &err, 0); 328 if (errno || (err==arg) || ((err != NULL) && *err)) { 329 return -1; 330 } 331 332 *val = t; 333 return 0; 334} 335 336 337int 338str2u16(char *arg, uint16_t *val) 339{ 340 char *err = NULL; 341 uint32_t t; 342 343 errno=0; 344 t = strtoul(arg, &err, 0); 345 if (errno || (err==arg) || ((err != NULL) && *err) || (t >= 0x10000)) { 346 return -1; 347 } 348 349 *val = t & 0xFFFF; 350 return 0; 351} 352 353 354struct cpx_board * 355find_board(char *model){ 356 struct cpx_board *board; 357 struct cpx_board *tmp; 358 359 board = NULL; 360 for (tmp = boards; tmp->model != NULL; tmp++){ 361 if (strcasecmp(model, tmp->model) == 0) { 362 board = tmp; 363 break; 364 } 365 }; 366 367 return board; 368} 369 370 371int 372get_file_crc(struct fw_block *ff) 373{ 374 FILE *f; 375 uint8_t buf[FILE_BUF_LEN]; 376 uint32_t readlen = sizeof(buf); 377 int res = -1; 378 size_t len; 379 380 if ((ff->flags & BLOCK_FLAG_HAVEHDR) == 0) { 381 res = 0; 382 goto out; 383 } 384 385 errno = 0; 386 f = fopen(ff->name,"r"); 387 if (errno) { 388 errmsg(1,"unable to open file %s", ff->name); 389 goto out; 390 } 391 392 ff->crc = 0; 393 len = ff->size; 394 while (len > 0) { 395 if (len < readlen) 396 readlen = len; 397 398 errno = 0; 399 fread(buf, readlen, 1, f); 400 if (errno) { 401 errmsg(1,"unable to read from file %s", ff->name); 402 goto out_close; 403 } 404 405 update_crc(buf, readlen, &ff->crc); 406 len -= readlen; 407 } 408 409 res = 0; 410 411out_close: 412 fclose(f); 413out: 414 return res; 415} 416 417 418int 419process_files(void) 420{ 421 struct fw_block *b; 422 struct stat st; 423 int i; 424 425 for (i = 0; i < fw_num_blocks; i++) { 426 b = &fw_blocks[i]; 427 if ((b->addr + b->blocklen) > flash_size) { 428 errmsg(0, "block at 0x%08X is too big", b->addr); 429 return -1; 430 } 431 if (b->name == NULL) 432 continue; 433 434 if (stat(b->name, &st) < 0) { 435 errmsg(0, "stat failed on %s",b->name); 436 return -1; 437 } 438 if (b->blocklen == 0) { 439 b->blocklen = flash_size - b->addr; 440 } 441 if (st.st_size > b->blocklen) { 442 errmsg(0,"file %s is too big",b->name); 443 return -1; 444 } 445 446 b->size = st.st_size; 447 } 448 449 return 0; 450} 451 452 453int 454process_partitions(void) 455{ 456 struct mylo_partition *part; 457 int i; 458 459 for (i = 0; i < fw_num_partitions; i++) { 460 part = &fw_parts[i].mylo; 461 462 if (part->addr > flash_size) { 463 errmsg(0, "invalid partition at 0x%08X", part->addr); 464 return -1; 465 } 466 467 if ((part->addr + part->size) > flash_size) { 468 errmsg(0, "partition at 0x%08X is too big", part->addr); 469 return -1; 470 } 471 } 472 473 return 0; 474} 475 476 477/* 478 * routines to write data to the output file 479 */ 480int 481write_out_data(FILE *outfile, uint8_t *data, size_t len, uint32_t *crc) 482{ 483 errno = 0; 484 485 fwrite(data, len, 1, outfile); 486 if (errno) { 487 errmsg(1,"unable to write output file"); 488 return -1; 489 } 490 491 if (crc) { 492 update_crc(data, len, crc); 493 } 494 495 return 0; 496} 497 498 499int 500write_out_desc(FILE *outfile, struct mylo_fw_blockdesc *desc, uint32_t *crc) 501{ 502 return write_out_data(outfile, (uint8_t *)desc, 503 sizeof(*desc), crc); 504} 505 506 507int 508write_out_padding(FILE *outfile, size_t len, uint8_t padc, uint32_t *crc) 509{ 510 uint8_t buff[512]; 511 size_t buflen = sizeof(buff); 512 513 memset(buff, padc, buflen); 514 515 while (len > 0) { 516 if (len < buflen) 517 buflen = len; 518 519 if (write_out_data(outfile, buff, buflen, crc)) 520 return -1; 521 522 len -= buflen; 523 } 524 525 return 0; 526} 527 528 529int 530write_out_file(FILE *outfile, struct fw_block *block, uint32_t *crc) 531{ 532 char buff[FILE_BUF_LEN]; 533 size_t buflen = sizeof(buff); 534 FILE *f; 535 size_t len; 536 537 errno = 0; 538 539 if (block->name == NULL) { 540 return 0; 541 } 542 543 if ((block->flags & BLOCK_FLAG_HAVEHDR) != 0) { 544 struct mylo_partition_header ph; 545 546 if (get_file_crc(block) != 0) 547 return -1; 548 549 ph.crc = HOST_TO_LE32(block->crc); 550 ph.len = HOST_TO_LE32(block->size); 551 552 if (write_out_data(outfile, (uint8_t *)&ph, sizeof(ph), crc) != 0) 553 return -1; 554 } 555 556 f = fopen(block->name,"r"); 557 if (errno) { 558 errmsg(1,"unable to open file: %s", block->name); 559 return -1; 560 } 561 562 len = block->size; 563 while (len > 0) { 564 if (len < buflen) 565 buflen = len; 566 567 /* read data from source file */ 568 errno = 0; 569 fread(buff, buflen, 1, f); 570 if (errno != 0) { 571 errmsg(1,"unable to read from file: %s",block->name); 572 return -1; 573 } 574 575 if (write_out_data(outfile, buff, buflen, crc) != 0) 576 return -1; 577 578 len -= buflen; 579 } 580 581 fclose(f); 582 583 /* align next block on a 4 byte boundary */ 584 len = ALIGN(len,4) - block->size; 585 if (write_out_padding(outfile, len, 0xFF, crc)) 586 return -1; 587 588 dbgmsg(1,"file %s written out", block->name); 589 return 0; 590} 591 592 593int 594write_out_header(FILE *outfile, uint32_t *crc) 595{ 596 struct mylo_fw_header hdr; 597 598 memset(&hdr, 0, sizeof(hdr)); 599 600 hdr.magic = HOST_TO_LE32(MYLO_MAGIC_FIRMWARE); 601 hdr.crc = HOST_TO_LE32(fw_header.crc); 602 hdr.vid = HOST_TO_LE16(fw_header.vid); 603 hdr.did = HOST_TO_LE16(fw_header.did); 604 hdr.svid = HOST_TO_LE16(fw_header.svid); 605 hdr.sdid = HOST_TO_LE16(fw_header.sdid); 606 hdr.rev = HOST_TO_LE32(fw_header.rev); 607 hdr.fwhi = HOST_TO_LE32(fw_header.fwhi); 608 hdr.fwlo = HOST_TO_LE32(fw_header.fwlo); 609 hdr.flags = HOST_TO_LE32(fw_header.flags); 610 611 if (fseek(outfile, 0, SEEK_SET) != 0) { 612 errmsg(1,"fseek failed on output file"); 613 return -1; 614 } 615 616 return write_out_data(outfile, (uint8_t *)&hdr, sizeof(hdr), crc); 617} 618 619 620int 621write_out_partitions(FILE *outfile, uint32_t *crc) 622{ 623 struct mylo_partition_table p; 624 char part_names[MYLO_MAX_PARTITIONS][PART_NAME_LEN]; 625 int ret; 626 int i; 627 628 if (fw_num_partitions == 0) 629 return 0; 630 631 memset(&p, 0, sizeof(p)); 632 memset(part_names, 0, sizeof(part_names)); 633 634 p.magic = HOST_TO_LE32(MYLO_MAGIC_PARTITIONS); 635 for (i = 0; i < fw_num_partitions; i++) { 636 struct mylo_partition *mp; 637 struct fw_part *fp; 638 639 mp = &p.partitions[i]; 640 fp = &fw_parts[i]; 641 mp->flags = HOST_TO_LE16(fp->mylo.flags); 642 mp->type = HOST_TO_LE16(PARTITION_TYPE_USED); 643 mp->addr = HOST_TO_LE32(fp->mylo.addr); 644 mp->size = HOST_TO_LE32(fp->mylo.size); 645 mp->param = HOST_TO_LE32(fp->mylo.param); 646 647 memcpy(part_names[i], fp->name, PART_NAME_LEN); 648 } 649 650 ret = write_out_data(outfile, (uint8_t *)&p, sizeof(p), crc); 651 if (ret) 652 return ret; 653 654 ret = write_out_data(outfile, (uint8_t *)part_names, sizeof(part_names), 655 crc); 656 return ret; 657} 658 659 660int 661write_out_blocks(FILE *outfile, uint32_t *crc) 662{ 663 struct mylo_fw_blockdesc desc; 664 struct fw_block *b; 665 uint32_t dlen; 666 int i; 667 668 /* 669 * if at least one partition specified, write out block descriptor 670 * for the partition table 671 */ 672 if (fw_num_partitions > 0) { 673 desc.type = HOST_TO_LE32(FW_DESC_TYPE_USED); 674 desc.addr = HOST_TO_LE32(board->part_offset); 675 desc.dlen = HOST_TO_LE32(sizeof(struct mylo_partition_table) + 676 (MYLO_MAX_PARTITIONS * PART_NAME_LEN)); 677 desc.blen = HOST_TO_LE32(board->part_size); 678 679 if (write_out_desc(outfile, &desc, crc) != 0) 680 return -1; 681 } 682 683 /* 684 * write out block descriptors for each files 685 */ 686 for (i = 0; i < fw_num_blocks; i++) { 687 b = &fw_blocks[i]; 688 689 /* detect block size */ 690 dlen = b->size; 691 if ((b->flags & BLOCK_FLAG_HAVEHDR) != 0) { 692 dlen += sizeof(struct mylo_partition_header); 693 } 694 695 /* round up to 4 bytes */ 696 dlen = ALIGN(dlen, 4); 697 698 /* setup the descriptor */ 699 desc.type = HOST_TO_LE32(FW_DESC_TYPE_USED); 700 desc.addr = HOST_TO_LE32(b->addr); 701 desc.dlen = HOST_TO_LE32(dlen); 702 desc.blen = HOST_TO_LE32(b->blocklen); 703 704 if (write_out_desc(outfile, &desc, crc) != 0) 705 return -1; 706 } 707 708 /* 709 * write out the null block descriptor 710 */ 711 memset(&desc, 0, sizeof(desc)); 712 if (write_out_desc(outfile, &desc, crc) != 0) 713 return -1; 714 715 if (write_out_partitions(outfile, crc) != 0) 716 return -1; 717 718 /* 719 * write out data for each blocks 720 */ 721 for (i = 0; i < fw_num_blocks; i++) { 722 b = &fw_blocks[i]; 723 if (write_out_file(outfile, b, crc) != 0) 724 return -1; 725 } 726 727 return 0; 728} 729 730 731/* 732 * argument parsing 733 */ 734int 735parse_arg(char *arg, char *buf, char *argv[]) 736{ 737 int res = 0; 738 size_t argl; 739 char *tok; 740 char **ap = &buf; 741 int i; 742 743 if ((arg == NULL)) { 744 /* invalid argument string */ 745 return -1; 746 } 747 748 argl = strlen(arg); 749 if (argl == 0) { 750 /* no arguments */ 751 return res; 752 } 753 754 if (argl >= MAX_ARG_LEN) { 755 /* argument is too long */ 756 argl = MAX_ARG_LEN-1; 757 } 758 759 memset(argv, 0, MAX_ARG_COUNT * sizeof(void *)); 760 memcpy(buf, arg, argl); 761 buf[argl] = '\0'; 762 763 for (i = 0; i < MAX_ARG_COUNT; i++) { 764 tok = strsep(ap, ":"); 765 if (tok == NULL) { 766 break; 767 } 768#if 0 769 else if (tok[0] == '\0') { 770 break; 771 } 772#endif 773 argv[i] = tok; 774 res++; 775 } 776 777 return res; 778} 779 780 781int 782required_arg(char c, char *arg) 783{ 784 if ((optarg != NULL) && (*arg == '-')){ 785 errmsg(0,"option %c requires an argument\n", c); 786 return -1; 787 } 788 789 return 0; 790} 791 792 793int 794is_empty_arg(char *arg) 795{ 796 int ret = 1; 797 if (arg != NULL) { 798 if (*arg) ret = 0; 799 }; 800 return ret; 801} 802 803 804int 805parse_opt_flags(char ch, char *arg) 806{ 807 if (required_arg(ch, arg)) { 808 goto err_out; 809 } 810 811 if (str2u32(arg, &fw_header.flags) != 0) { 812 errmsg(0,"invalid firmware flags: %s", arg); 813 goto err_out; 814 } 815 816 dbgmsg(1, "firmware flags set to %X bytes", fw_header.flags); 817 818 return 0; 819 820err_out: 821 return -1; 822} 823 824 825int 826parse_opt_size(char ch, char *arg) 827{ 828 if (required_arg(ch, arg)) { 829 goto err_out; 830 } 831 832 if (str2u32(arg, &flash_size) != 0) { 833 errmsg(0,"invalid flash size: %s", arg); 834 goto err_out; 835 } 836 837 dbgmsg(1, "flash size set to %d bytes", flash_size); 838 839 return 0; 840 841err_out: 842 return -1; 843} 844 845 846int 847parse_opt_id(char ch, char *arg) 848{ 849 char buf[MAX_ARG_LEN]; 850 char *argv[MAX_ARG_COUNT]; 851 int argc; 852 char *p; 853 854 if (required_arg(ch, arg)) { 855 goto err_out; 856 } 857 858 argc = parse_arg(arg, buf, argv); 859 860 /* processing vendor ID*/ 861 p = argv[0]; 862 if (is_empty_arg(p)) { 863 errmsg(0,"vendor id is missing from -%c %s",ch, arg); 864 goto err_out; 865 } else if (str2u16(p, &fw_header.vid) != 0) { 866 errmsg(0,"invalid vendor id: %s", p); 867 goto err_out; 868 } 869 870 dbgmsg(1, "vendor id is set to 0x%04X", fw_header.vid); 871 872 /* processing device ID*/ 873 p = argv[1]; 874 if (is_empty_arg(p)) { 875 errmsg(0,"device id is missing from -%c %s",ch, arg); 876 goto err_out; 877 } else if (str2u16(p, &fw_header.did) != 0) { 878 errmsg(0,"invalid device id: %s", p); 879 goto err_out; 880 } 881 882 dbgmsg(1, "device id is set to 0x%04X", fw_header.did); 883 884 /* processing sub vendor ID*/ 885 p = argv[2]; 886 if (is_empty_arg(p)) { 887 fw_header.svid = fw_header.vid; 888 } else if (str2u16(p, &fw_header.svid) != 0) { 889 errmsg(0,"invalid sub vendor id: %s", p); 890 goto err_out; 891 } 892 893 dbgmsg(1, "sub vendor id is set to 0x%04X", fw_header.svid); 894 895 /* processing device ID*/ 896 p = argv[3]; 897 if (is_empty_arg(p)) { 898 fw_header.sdid = fw_header.did; 899 } else if (str2u16(p, &fw_header.sdid) != 0) { 900 errmsg(0,"invalid sub device id: %s", p); 901 goto err_out; 902 } 903 904 dbgmsg(1, "sub device id is set to 0x%04X", fw_header.sdid); 905 906 /* processing revision */ 907 p = argv[4]; 908 if (is_empty_arg(p)) { 909 fw_header.rev = 0; 910 } else if (str2u32(arg, &fw_header.rev) != 0) { 911 errmsg(0,"invalid revision number: %s", p); 912 goto err_out; 913 } 914 915 dbgmsg(1, "board revision is set to 0x%08X", fw_header.rev); 916 917 return 0; 918 919err_out: 920 return -1; 921} 922 923 924int 925parse_opt_block(char ch, char *arg) 926{ 927 char buf[MAX_ARG_LEN]; 928 char *argv[MAX_ARG_COUNT]; 929 int argc; 930 struct fw_block *b; 931 char *p; 932 933 if (required_arg(ch, arg)) { 934 goto err_out; 935 } 936 937 if (fw_num_blocks >= MAX_FW_BLOCKS) { 938 errmsg(0,"too many blocks specified"); 939 goto err_out; 940 } 941 942 argc = parse_arg(arg, buf, argv); 943 dbgmsg(1,"processing block option %s, count %d", arg, argc); 944 945 b = &fw_blocks[fw_num_blocks++]; 946 947 /* processing block address */ 948 p = argv[0]; 949 if (is_empty_arg(p)) { 950 errmsg(0,"no block address specified in %s", arg); 951 goto err_out; 952 } else if (str2u32(p, &b->addr) != 0) { 953 errmsg(0,"invalid block address: %s", p); 954 goto err_out; 955 } 956 957 /* processing block length */ 958 p = argv[1]; 959 if (is_empty_arg(p)) { 960 errmsg(0,"no block length specified in %s", arg); 961 goto err_out; 962 } else if (str2u32(p, &b->blocklen) != 0) { 963 errmsg(0,"invalid block length: %s", p); 964 goto err_out; 965 } 966 967 if (argc < 3) { 968 dbgmsg(1,"empty block %s", arg); 969 goto success; 970 } 971 972 /* processing flags */ 973 p = argv[2]; 974 if (is_empty_arg(p) == 0) { 975 for ( ; *p != '\0'; p++) { 976 switch (*p) { 977 case 'h': 978 b->flags |= BLOCK_FLAG_HAVEHDR; 979 break; 980 default: 981 errmsg(0, "invalid block flag \"%c\"", *p); 982 goto err_out; 983 } 984 } 985 } 986 987 /* processing file name */ 988 p = argv[3]; 989 if (is_empty_arg(p)) { 990 errmsg(0,"file name missing in %s", arg); 991 goto err_out; 992 } 993 994 b->name = strdup(p); 995 if (b->name == NULL) { 996 errmsg(0,"not enough memory"); 997 goto err_out; 998 } 999 1000success: 1001 1002 return 0; 1003 1004err_out: 1005 return -1; 1006} 1007 1008 1009int 1010parse_opt_partition(char ch, char *arg) 1011{ 1012 char buf[MAX_ARG_LEN]; 1013 char *argv[MAX_ARG_COUNT]; 1014 int argc; 1015 char *p; 1016 struct mylo_partition *part; 1017 struct fw_part *fp; 1018 1019 if (required_arg(ch, arg)) { 1020 goto err_out; 1021 } 1022 1023 if (fw_num_partitions >= MYLO_MAX_PARTITIONS) { 1024 errmsg(0, "too many partitions specified"); 1025 goto err_out; 1026 } 1027 1028 fp = &fw_parts[fw_num_partitions++]; 1029 part = &fp->mylo; 1030 1031 argc = parse_arg(arg, buf, argv); 1032 1033 /* processing partition address */ 1034 p = argv[0]; 1035 if (is_empty_arg(p)) { 1036 errmsg(0,"partition address missing in -%c %s",ch, arg); 1037 goto err_out; 1038 } else if (str2u32(p, &part->addr) != 0) { 1039 errmsg(0,"invalid partition address: %s", p); 1040 goto err_out; 1041 } 1042 1043 /* processing partition size */ 1044 p = argv[1]; 1045 if (is_empty_arg(p)) { 1046 errmsg(0,"partition size missing in -%c %s",ch, arg); 1047 goto err_out; 1048 } else if (str2u32(p, &part->size) != 0) { 1049 errmsg(0,"invalid partition size: %s", p); 1050 goto err_out; 1051 } 1052 1053 /* processing partition flags */ 1054 p = argv[2]; 1055 if (is_empty_arg(p) == 0) { 1056 for ( ; *p != '\0'; p++) { 1057 switch (*p) { 1058 case 'a': 1059 part->flags |= PARTITION_FLAG_ACTIVE; 1060 break; 1061 case 'p': 1062 part->flags |= PARTITION_FLAG_PRELOAD; 1063 break; 1064 case 'l': 1065 part->flags |= PARTITION_FLAG_LZMA; 1066 break; 1067 case 'h': 1068 part->flags |= PARTITION_FLAG_HAVEHDR; 1069 break; 1070 default: 1071 errmsg(0, "invalid partition flag \"%c\"", *p); 1072 goto err_out; 1073 } 1074 } 1075 } 1076 1077 /* processing partition parameter */ 1078 p = argv[3]; 1079 if (is_empty_arg(p)) { 1080 /* set default partition parameter */ 1081 part->param = 0; 1082 } else if (str2u32(p, &part->param) != 0) { 1083 errmsg(0,"invalid partition parameter: %s", p); 1084 goto err_out; 1085 } 1086 1087 p = argv[4]; 1088 if (is_empty_arg(p)) { 1089 /* set default partition parameter */ 1090 fp->name[0] = '\0'; 1091 } else { 1092 strncpy(fp->name, p, PART_NAME_LEN); 1093 } 1094 1095#if 1 1096 if (part->size == 0) { 1097 part->size = flash_size - part->addr; 1098 } 1099 1100 /* processing file parameter */ 1101 p = argv[5]; 1102 if (is_empty_arg(p) == 0) { 1103 struct fw_block *b; 1104 1105 if (fw_num_blocks == MAX_FW_BLOCKS) { 1106 errmsg(0,"too many blocks specified", p); 1107 goto err_out; 1108 } 1109 b = &fw_blocks[fw_num_blocks++]; 1110 b->name = strdup(p); 1111 b->addr = part->addr; 1112 b->blocklen = part->size; 1113 if (part->flags & PARTITION_FLAG_HAVEHDR) { 1114 b->flags |= BLOCK_FLAG_HAVEHDR; 1115 } 1116 } 1117#endif 1118 1119 return 0; 1120 1121err_out: 1122 return -1; 1123} 1124 1125 1126int 1127parse_opt_board(char ch, char *arg) 1128{ 1129 if (required_arg(ch, arg)) { 1130 goto err_out; 1131 } 1132 1133 board = find_board(arg); 1134 if (board == NULL){ 1135 errmsg(0,"invalid/unknown board specified: %s", arg); 1136 goto err_out; 1137 } 1138 1139 fw_header.vid = board->vid; 1140 fw_header.did = board->did; 1141 fw_header.svid = board->svid; 1142 fw_header.sdid = board->sdid; 1143 1144 flash_size = board->flash_size; 1145 1146 return 0; 1147 1148err_out: 1149 return -1; 1150} 1151 1152 1153int 1154parse_opt_rev(char ch, char *arg) 1155{ 1156 if (required_arg(ch, arg)) { 1157 return -1; 1158 } 1159 1160 if (str2u32(arg, &fw_header.rev) != 0) { 1161 errmsg(0,"invalid revision number: %s", arg); 1162 return -1; 1163 } 1164 1165 return 0; 1166} 1167 1168 1169/* 1170 * main 1171 */ 1172int 1173main(int argc, char *argv[]) 1174{ 1175 int optinvalid = 0; /* flag for invalid option */ 1176 int c; 1177 int res = EXIT_FAILURE; 1178 1179 FILE *outfile; 1180 uint32_t crc; 1181 1182 progname=basename(argv[0]); 1183 1184 memset(&fw_header, 0, sizeof(fw_header)); 1185 1186 /* init header defaults */ 1187 fw_header.vid = VENID_COMPEX; 1188 fw_header.did = DEVID_COMPEX_WP54G; 1189 fw_header.svid = VENID_COMPEX; 1190 fw_header.sdid = DEVID_COMPEX_WP54G; 1191 fw_header.fwhi = 0x20000; 1192 fw_header.fwlo = 0x20000; 1193 fw_header.flags = 0; 1194 1195 opterr = 0; /* could not print standard getopt error messages */ 1196 while ((c = getopt(argc, argv, "b:B:f:hi:p:r:s:v")) != -1) { 1197 optinvalid = 0; 1198 switch (c) { 1199 case 'b': 1200 optinvalid = parse_opt_block(c,optarg); 1201 break; 1202 case 'B': 1203 optinvalid = parse_opt_board(c,optarg); 1204 break; 1205 case 'f': 1206 optinvalid = parse_opt_flags(c,optarg); 1207 break; 1208 case 'h': 1209 usage(EXIT_SUCCESS); 1210 break; 1211 case 'i': 1212 optinvalid = parse_opt_id(c,optarg); 1213 break; 1214 case 'p': 1215 optinvalid = parse_opt_partition(c,optarg); 1216 break; 1217 case 'r': 1218 optinvalid = parse_opt_rev(c,optarg); 1219 break; 1220 case 's': 1221 optinvalid = parse_opt_size(c,optarg); 1222 break; 1223 case 'v': 1224 verblevel++; 1225 break; 1226 default: 1227 optinvalid = 1; 1228 break; 1229 } 1230 if (optinvalid != 0 ){ 1231 errmsg(0, "invalid option: -%c", optopt); 1232 goto out; 1233 } 1234 } 1235 1236 if (optind == argc) { 1237 errmsg(0, "no output file specified"); 1238 goto out; 1239 } 1240 1241 ofname = argv[optind++]; 1242 1243 if (optind < argc) { 1244 errmsg(0, "invalid option: %s", argv[optind]); 1245 goto out; 1246 } 1247 1248 if (!board) { 1249 errmsg(0, "no board specified"); 1250 goto out; 1251 } 1252 1253 if (flash_size == 0) { 1254 errmsg(0, "no flash size specified"); 1255 goto out; 1256 } 1257 1258 if (process_files() != 0) { 1259 goto out; 1260 } 1261 1262 if (process_partitions() != 0) { 1263 goto out; 1264 } 1265 1266 outfile = fopen(ofname, "w"); 1267 if (outfile == NULL) { 1268 errmsg(1, "could not open \"%s\" for writing", ofname); 1269 goto out; 1270 } 1271 1272 crc = 0; 1273 init_crc_table(); 1274 1275 if (write_out_header(outfile, &crc) != 0) 1276 goto out_flush; 1277 1278 if (write_out_blocks(outfile, &crc) != 0) 1279 goto out_flush; 1280 1281 fw_header.crc = crc; 1282 if (write_out_header(outfile, NULL) != 0) 1283 goto out_flush; 1284 1285 dbgmsg(1,"Firmware file %s completed.", ofname); 1286 1287 res = EXIT_SUCCESS; 1288 1289out_flush: 1290 fflush(outfile); 1291 fclose(outfile); 1292 if (res != EXIT_SUCCESS) { 1293 unlink(ofname); 1294 } 1295out: 1296 return res; 1297} 1298