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