1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * 4 * Copyright (C) 2007-2008 OpenWrt.org 5 * Copyright (C) 2007-2008 Gabor Juhos <juhosg at openwrt.org> 6 */ 7 8 #include <stdio.h> 9 #include <stdlib.h> 10 #include <stdint.h> 11 #include <string.h> 12 #include <byteswap.h> 13 #include <unistd.h> /* for unlink() */ 14 #include <libgen.h> 15 #include <getopt.h> /* for getopt() */ 16 #include <stdarg.h> 17 #include <errno.h> 18 #include <sys/stat.h> 19 #include <endian.h> /* for __BYTE_ORDER */ 20 #if defined(__CYGWIN__) 21 # include <byteswap.h> 22 #endif 23 #include <inttypes.h> 24 25 #include "zynos.h" 26 27 #if (__BYTE_ORDER == __LITTLE_ENDIAN) 28 # define HOST_TO_LE16(x) (x) 29 # define HOST_TO_LE32(x) (x) 30 # define LE16_TO_HOST(x) (x) 31 # define LE32_TO_HOST(x) (x) 32 # define HOST_TO_BE16(x) bswap_16(x) 33 # define HOST_TO_BE32(x) bswap_32(x) 34 # define BE16_TO_HOST(x) bswap_16(x) 35 # define BE32_TO_HOST(x) bswap_32(x) 36 #else 37 # define HOST_TO_BE16(x) (x) 38 # define HOST_TO_BE32(x) (x) 39 # define BE16_TO_HOST(x) (x) 40 # define BE32_TO_HOST(x) (x) 41 # define HOST_TO_LE16(x) bswap_16(x) 42 # define HOST_TO_LE32(x) bswap_32(x) 43 # define LE16_TO_HOST(x) bswap_16(x) 44 # define LE32_TO_HOST(x) bswap_32(x) 45 #endif 46 47 #define ALIGN(x,y) (((x)+((y)-1)) & ~((y)-1)) 48 49 #define MAX_NUM_BLOCKS 8 50 #define MAX_ARG_COUNT 32 51 #define MAX_ARG_LEN 1024 52 #define FILE_BUF_LEN (16*1024) 53 54 55 struct csum_state{ 56 int odd; 57 uint32_t sum; 58 uint32_t tmp; 59 }; 60 61 struct fw_block { 62 uint32_t align; /* alignment of this block */ 63 char *file_name; /* name of the file */ 64 uint32_t file_size; /* length of the file */ 65 char *mmap_name; /* name in the MMAP table */ 66 int type; /* block type */ 67 uint32_t padlen; 68 uint8_t padc; 69 }; 70 71 #define BLOCK_TYPE_BOOTEXT 0 72 #define BLOCK_TYPE_RAW 1 73 74 struct fw_mmap { 75 uint32_t addr; 76 uint32_t size; 77 uint32_t user_addr; 78 uint32_t user_size; 79 }; 80 #define MMAP_DATA_SIZE 1024 81 #define MMAP_ALIGN 16 82 83 struct board_info { 84 char *name; /* model name */ 85 char *desc; /* description */ 86 uint16_t vendor; /* vendor id */ 87 uint16_t model; /* model id */ 88 uint32_t flash_base; /* flash base address */ 89 uint32_t flash_size; /* board flash size */ 90 uint32_t code_start; /* code start address */ 91 uint32_t romio_offs; /* offset of the firmware within the flash */ 92 uint32_t bootext_size; /* maximum size of bootext block */ 93 }; 94 95 /* 96 * Globals 97 */ 98 char *progname; 99 char *ofname = NULL; 100 int verblevel = 0; 101 102 struct board_info *board = NULL; 103 104 struct fw_block blocks[MAX_NUM_BLOCKS]; 105 struct fw_block *bootext_block = NULL; 106 int num_blocks = 0; 107 108 #define ADM5120_FLASH_BASE 0xBFC00000 109 #define ADM5120_CODE_START 0x80008000 110 111 /* TODO: check values for AR7 */ 112 #define AR7_FLASH_BASE 0xB0000000 113 #define AR7_CODE_START 0x94008000 114 115 #define ATHEROS_FLASH_BASE 0xBFC00000 116 #define ATHEROS_CODE_START 0x80e00000 117 118 #define AR71XX_FLASH_BASE 0xBFC00000 119 #define AR71XX_CODE_START 0x81E00000 120 121 #define BOARD(n, d, v, m, fb, fs, cs, fo) { \ 122 .name = (n), .desc=(d), \ 123 .vendor = (v), .model = (m), \ 124 .flash_base = (fb), .flash_size = (fs)<<20, \ 125 .code_start = (cs), .romio_offs = (fo), \ 126 .bootext_size = BOOTEXT_DEF_SIZE \ 127 } 128 129 #define ADMBOARD1(n, d, m, fs) BOARD(n, d, ZYNOS_VENDOR_ID_ZYXEL, m, \ 130 ADM5120_FLASH_BASE, fs, ADM5120_CODE_START, 0x8000) 131 132 #define ADMBOARD2(n, d, m, fs) BOARD(n, d, ZYNOS_VENDOR_ID_ZYXEL, m, \ 133 ADM5120_FLASH_BASE, fs, ADM5120_CODE_START, 0x10000) 134 135 #define AR7BOARD1(n, d, m, fs) BOARD(n, d, ZYNOS_VENDOR_ID_ZYXEL, m, \ 136 AR7_FLASH_BASE, fs, AR7_CODE_START, 0x8000) 137 138 #define ATHEROSBOARD1(n, d, m, fs) BOARD(n, d, ZYNOS_VENDOR_ID_ZYXEL, m, \ 139 ATHEROS_FLASH_BASE, fs, ATHEROS_CODE_START, 0x30000) 140 141 #define AR71XXBOARD1(n, d, m, fs) { \ 142 .name = (n), .desc=(d), \ 143 .vendor = (ZYNOS_VENDOR_ID_ZYXEL), .model = (m), \ 144 .flash_base = (AR71XX_FLASH_BASE), .flash_size = (fs)<<20, \ 145 .code_start = (AR71XX_CODE_START), .romio_offs = (0x40000), \ 146 .bootext_size = 0x30000 \ 147 } 148 149 150 static struct board_info boards[] = { 151 /* 152 * Infineon/ADMtek ADM5120 based boards 153 */ 154 ADMBOARD2("ES-2024A", "ZyXEL ES-2024A", ZYNOS_MODEL_ES_2024A, 4), 155 ADMBOARD2("ES-2024PWR", "ZyXEL ES-2024PWR", ZYNOS_MODEL_ES_2024PWR, 4), 156 ADMBOARD2("ES-2108", "ZyXEL ES-2108", ZYNOS_MODEL_ES_2108, 4), 157 ADMBOARD2("ES-2108-F", "ZyXEL ES-2108-F", ZYNOS_MODEL_ES_2108_F, 4), 158 ADMBOARD2("ES-2108-G", "ZyXEL ES-2108-G", ZYNOS_MODEL_ES_2108_G, 4), 159 ADMBOARD2("ES-2108-LC", "ZyXEL ES-2108-LC", ZYNOS_MODEL_ES_2108_LC, 4), 160 ADMBOARD2("ES-2108PWR", "ZyXEL ES-2108PWR", ZYNOS_MODEL_ES_2108PWR, 4), 161 ADMBOARD1("HS-100", "ZyXEL HomeSafe 100", ZYNOS_MODEL_HS_100, 2), 162 ADMBOARD1("HS-100W", "ZyXEL HomeSafe 100W", ZYNOS_MODEL_HS_100W, 2), 163 ADMBOARD1("P-334", "ZyXEL Prestige 334", ZYNOS_MODEL_P_334, 2), 164 ADMBOARD1("P-334U", "ZyXEL Prestige 334U", ZYNOS_MODEL_P_334U, 4), 165 ADMBOARD1("P-334W", "ZyXEL Prestige 334W", ZYNOS_MODEL_P_334W, 2), 166 ADMBOARD1("P-334WH", "ZyXEL Prestige 334WH", ZYNOS_MODEL_P_334WH, 4), 167 ADMBOARD1("P-334WHD", "ZyXEL Prestige 334WHD", ZYNOS_MODEL_P_334WHD, 4), 168 ADMBOARD1("P-334WT", "ZyXEL Prestige 334WT", ZYNOS_MODEL_P_334WT, 4), 169 ADMBOARD1("P-335", "ZyXEL Prestige 335", ZYNOS_MODEL_P_335, 4), 170 ADMBOARD1("P-335Plus", "ZyXEL Prestige 335Plus", ZYNOS_MODEL_P_335PLUS, 4), 171 ADMBOARD1("P-335U", "ZyXEL Prestige 335U", ZYNOS_MODEL_P_335U, 4), 172 ADMBOARD1("P-335WT", "ZyXEL Prestige 335WT", ZYNOS_MODEL_P_335WT, 4), 173 174 { 175 .name = "P-2602HW-D1A", 176 .desc = "ZyXEL P-2602HW-D1A", 177 .vendor = ZYNOS_VENDOR_ID_ZYXEL, 178 .model = ZYNOS_MODEL_P_2602HW_D1A, 179 .flash_base = AR7_FLASH_BASE, 180 .flash_size = 4*1024*1024, 181 .code_start = 0x94008000, 182 .romio_offs = 0x20000, 183 .bootext_size = BOOTEXT_DEF_SIZE, 184 }, 185 186 #if 0 187 /* 188 * Texas Instruments AR7 based boards 189 */ 190 AR7BOARD1("P-660H-61", "ZyXEL P-660H-61", ZYNOS_MODEL_P_660H_61, 2), 191 AR7BOARD1("P-660H-63", "ZyXEL P-660H-63", ZYNOS_MODEL_P_660H_63, 2), 192 AR7BOARD1("P-660H-D1", "ZyXEL P-660H-D1", ZYNOS_MODEL_P_660H_D1, 2), 193 AR7BOARD1("P-660H-D3", "ZyXEL P-660H-D3", ZYNOS_MODEL_P_660H_D3, 2), 194 AR7BOARD1("P-660HW-61", "ZyXEL P-660HW-61", ZYNOS_MODEL_P_660HW_61, 2), 195 AR7BOARD1("P-660HW-63", "ZyXEL P-660HW-63", ZYNOS_MODEL_P_660HW_63, 2), 196 AR7BOARD1("P-660HW-67", "ZyXEL P-660HW-67", ZYNOS_MODEL_P_660HW_67, 2), 197 AR7BOARD1("P-660HW-D1", "ZyXEL P-660HW-D1", ZYNOS_MODEL_P_660HW_D1, 2), 198 AR7BOARD1("P-660HW-D3", "ZyXEL P-660HW-D3", ZYNOS_MODEL_P_660HW_D3, 2), 199 AR7BOARD1("P-660R-61", "ZyXEL P-660R-61", ZYNOS_MODEL_P_660R_61, 2), 200 AR7BOARD1("P-660R-61C", "ZyXEL P-660R-61C", ZYNOS_MODEL_P_660R_61C, 2), 201 AR7BOARD1("P-660R-63", "ZyXEL P-660R-63", ZYNOS_MODEL_P_660R_63, 2), 202 AR7BOARD1("P-660R-63C", "ZyXEL P-660R-63C", ZYNOS_MODEL_P_660R_63C, 2), 203 AR7BOARD1("P-660R-67", "ZyXEL P-660R-67", ZYNOS_MODEL_P_660R_67, 2), 204 AR7BOARD1("P-660R-D1", "ZyXEL P-660R-D1", ZYNOS_MODEL_P_660R_D1, 2), 205 AR7BOARD1("P-660R-D3", "ZyXEL P-660R-D3", ZYNOS_MODEL_P_660R_D3, 2), 206 #endif 207 { 208 .name = "O2SURF", 209 .desc = "O2 DSL Surf & Phone", 210 .vendor = ZYNOS_VENDOR_ID_O2, 211 .model = ZYNOS_MODEL_O2SURF, 212 .flash_base = AR7_FLASH_BASE, 213 .flash_size = 8*1024*1024, 214 .code_start = 0x94014000, 215 .romio_offs = 0x40000, 216 .bootext_size = BOOTEXT_DEF_SIZE, 217 }, 218 219 /* 220 :x 221 */ 222 ATHEROSBOARD1("NBG-318S", "ZyXEL NBG-318S", ZYNOS_MODEL_NBG_318S, 4), 223 224 /* 225 * Atheros ar71xx based boards 226 */ 227 AR71XXBOARD1("NBG-460N", "ZyXEL NBG-460N", ZYNOS_MODEL_NBG_460N, 4), 228 229 {.name = NULL} 230 }; 231 232 /* 233 * Message macros 234 */ 235 #define ERR(fmt, ...) do { \ 236 fflush(0); \ 237 fprintf(stderr, "[%s] *** error: " fmt "\n", \ 238 progname, ## __VA_ARGS__ ); \ 239 } while (0) 240 241 #define ERRS(fmt, ...) do { \ 242 int save = errno; \ 243 fflush(0); \ 244 fprintf(stderr, "[%s] *** error: " fmt ", %s\n", \ 245 progname, ## __VA_ARGS__, strerror(save)); \ 246 } while (0) 247 248 #define WARN(fmt, ...) do { \ 249 fprintf(stderr, "[%s] *** warning: " fmt "\n", \ 250 progname, ## __VA_ARGS__ ); \ 251 } while (0) 252 253 #define DBG(lev, fmt, ...) do { \ 254 if (verblevel < lev) \ 255 break;\ 256 fprintf(stderr, "[%s] " fmt "\n", progname, ## __VA_ARGS__ ); \ 257 } while (0) 258 259 #define ERR_FATAL -1 260 #define ERR_INVALID_IMAGE -2 261 262 /* 263 * Helper routines 264 */ 265 void 266 usage(int status) 267 { 268 FILE *stream = (status != EXIT_SUCCESS) ? stderr : stdout; 269 struct board_info *board; 270 271 fprintf(stream, "Usage: %s [OPTIONS...]\n", progname); 272 fprintf(stream, 273 "\n" 274 "Options:\n" 275 " -B <board> create image for the board specified with <board>.\n" 276 " valid <board> values:\n" 277 ); 278 for (board = boards; board->name != NULL; board++){ 279 fprintf(stream, 280 " %-12s= %s\n", 281 board->name, board->desc); 282 }; 283 fprintf(stream, 284 " -b <file>[:<align>]\n" 285 " add boot extension block to the image\n" 286 " -r <file>[:<align>]\n" 287 " add raw block to the image\n" 288 " -o <file> write output to the file <file>\n" 289 " -h show this screen\n" 290 ); 291 292 exit(status); 293 } 294 295 296 /* 297 * argument parsing 298 */ 299 int 300 str2u32(char *arg, uint32_t *val) 301 { 302 char *err = NULL; 303 uint32_t t; 304 305 errno=0; 306 t = strtoul(arg, &err, 0); 307 if (errno || (err==arg) || ((err != NULL) && *err)) { 308 return -1; 309 } 310 311 *val = t; 312 return 0; 313 } 314 315 316 int 317 str2u16(char *arg, uint16_t *val) 318 { 319 char *err = NULL; 320 uint32_t t; 321 322 errno=0; 323 t = strtoul(arg, &err, 0); 324 if (errno || (err==arg) || ((err != NULL) && *err) || (t >= 0x10000)) { 325 return -1; 326 } 327 328 *val = t & 0xFFFF; 329 return 0; 330 } 331 332 int 333 str2u8(char *arg, uint8_t *val) 334 { 335 char *err = NULL; 336 uint32_t t; 337 338 errno=0; 339 t = strtoul(arg, &err, 0); 340 if (errno || (err==arg) || ((err != NULL) && *err) || (t >= 0x100)) { 341 return -1; 342 } 343 344 *val = t & 0xFF; 345 return 0; 346 } 347 348 int 349 str2sig(char *arg, uint32_t *sig) 350 { 351 if (strlen(arg) != 4) 352 return -1; 353 354 *sig = arg[0] | (arg[1] << 8) | (arg[2] << 16) | (arg[3] << 24); 355 356 return 0; 357 } 358 359 360 int 361 parse_arg(char *arg, char *buf, char *argv[]) 362 { 363 int res = 0; 364 size_t argl; 365 char *tok; 366 char **ap = &buf; 367 int i; 368 369 memset(argv, 0, MAX_ARG_COUNT * sizeof(void *)); 370 371 if ((arg == NULL)) { 372 /* no arguments */ 373 return 0; 374 } 375 376 argl = strlen(arg); 377 if (argl == 0) { 378 /* no arguments */ 379 return 0; 380 } 381 382 if (argl >= MAX_ARG_LEN) { 383 /* argument is too long */ 384 argl = MAX_ARG_LEN-1; 385 } 386 387 memcpy(buf, arg, argl); 388 buf[argl] = '\0'; 389 390 for (i = 0; i < MAX_ARG_COUNT; i++) { 391 tok = strsep(ap, ":"); 392 if (tok == NULL) { 393 break; 394 } 395 #if 0 396 else if (tok[0] == '\0') { 397 break; 398 } 399 #endif 400 argv[i] = tok; 401 res++; 402 } 403 404 return res; 405 } 406 407 408 int 409 required_arg(char c, char *arg) 410 { 411 if (arg == NULL || *arg != '-') 412 return 0; 413 414 ERR("option -%c requires an argument\n", c); 415 return -1; 416 } 417 418 419 int 420 is_empty_arg(char *arg) 421 { 422 int ret = 1; 423 if (arg != NULL) { 424 if (*arg) ret = 0; 425 }; 426 return ret; 427 } 428 429 430 void 431 csum_init(struct csum_state *css) 432 { 433 css->odd = 0; 434 css->sum = 0; 435 css->tmp = 0; 436 } 437 438 439 void 440 csum_update(void *data, uint32_t len, struct csum_state *css) 441 { 442 uint8_t *p = data; 443 444 if (len == 0) 445 return; 446 447 if (css->odd) { 448 css->sum += (css->tmp << 8) + p[0]; 449 if (css->sum > 0xFFFF) { 450 css->sum += 1; 451 css->sum &= 0xFFFF; 452 } 453 css->odd = 0; 454 len--; 455 p++; 456 } 457 458 for ( ; len > 1; len -= 2, p +=2 ) { 459 css->sum += (p[0] << 8) + p[1]; 460 if (css->sum > 0xFFFF) { 461 css->sum += 1; 462 css->sum &= 0xFFFF; 463 } 464 } 465 466 if (len == 1){ 467 css->tmp = p[0]; 468 css->odd = 1; 469 } 470 } 471 472 473 uint16_t 474 csum_get(struct csum_state *css) 475 { 476 char pad = 0; 477 478 csum_update(&pad, 1, css); 479 return css->sum; 480 } 481 482 uint16_t 483 csum_buf(uint8_t *p, uint32_t len) 484 { 485 struct csum_state css; 486 487 csum_init(&css); 488 csum_update(p, len, &css); 489 return csum_get(&css); 490 491 } 492 493 /* 494 * routines to write data to the output file 495 */ 496 int 497 write_out_data(FILE *outfile, void *data, size_t len, 498 struct csum_state *css) 499 { 500 uint8_t *ptr = data; 501 502 errno = 0; 503 504 fwrite(ptr, len, 1, outfile); 505 if (errno) { 506 ERR("unable to write output file"); 507 return -1; 508 } 509 510 if (css) { 511 csum_update(ptr, len, css); 512 } 513 514 return 0; 515 } 516 517 518 int 519 write_out_padding(FILE *outfile, size_t len, uint8_t padc, 520 struct csum_state *css) 521 { 522 uint8_t buf[512]; 523 size_t buflen = sizeof(buf); 524 525 memset(buf, padc, buflen); 526 while (len > 0) { 527 if (len < buflen) 528 buflen = len; 529 530 if (write_out_data(outfile, buf, buflen, css)) 531 return -1; 532 533 len -= buflen; 534 } 535 536 return 0; 537 } 538 539 540 int 541 write_out_data_align(FILE *outfile, void *data, size_t len, size_t align, 542 struct csum_state *css) 543 { 544 size_t padlen; 545 int res; 546 547 res = write_out_data(outfile, data, len, css); 548 if (res) 549 return res; 550 551 padlen = ALIGN(len,align) - len; 552 res = write_out_padding(outfile, padlen, 0xFF, css); 553 554 return res; 555 } 556 557 558 int 559 write_out_header(FILE *outfile, struct zyn_rombin_hdr *hdr) 560 { 561 struct zyn_rombin_hdr t; 562 563 errno = 0; 564 if (fseek(outfile, 0, SEEK_SET) != 0) { 565 ERRS("fseek failed on output file"); 566 return -1; 567 } 568 569 /* setup temporary header fields */ 570 memset(&t, 0, sizeof(t)); 571 t.addr = HOST_TO_BE32(hdr->addr); 572 memcpy(&t.sig, ROMBIN_SIGNATURE, ROMBIN_SIG_LEN); 573 t.type = hdr->type; 574 t.flags = hdr->flags; 575 t.osize = HOST_TO_BE32(hdr->osize); 576 t.csize = HOST_TO_BE32(hdr->csize); 577 t.ocsum = HOST_TO_BE16(hdr->ocsum); 578 t.ccsum = HOST_TO_BE16(hdr->ccsum); 579 t.mmap_addr = HOST_TO_BE32(hdr->mmap_addr); 580 581 DBG(2, "hdr.addr = 0x%08x", hdr->addr); 582 DBG(2, "hdr.type = 0x%02x", hdr->type); 583 DBG(2, "hdr.osize = 0x%08x", hdr->osize); 584 DBG(2, "hdr.csize = 0x%08x", hdr->csize); 585 DBG(2, "hdr.flags = 0x%02x", hdr->flags); 586 DBG(2, "hdr.ocsum = 0x%04x", hdr->ocsum); 587 DBG(2, "hdr.ccsum = 0x%04x", hdr->ccsum); 588 DBG(2, "hdr.mmap_addr = 0x%08x", hdr->mmap_addr); 589 590 return write_out_data(outfile, (uint8_t *)&t, sizeof(t), NULL); 591 } 592 593 594 int 595 write_out_mmap(FILE *outfile, struct fw_mmap *mmap, struct csum_state *css) 596 { 597 struct zyn_mmt_hdr *mh; 598 uint8_t buf[MMAP_DATA_SIZE]; 599 uint32_t user_size; 600 char *data; 601 int res; 602 603 memset(buf, 0, sizeof(buf)); 604 605 mh = (struct zyn_mmt_hdr *)buf; 606 607 /* TODO: needs to recreate the memory map too? */ 608 mh->count=0; 609 610 /* Build user data section */ 611 data = (char *)buf + sizeof(*mh); 612 data += sprintf(data, "Vendor 1 %d", board->vendor); 613 *data++ = '\0'; 614 data += sprintf(data, "Model 1 %d", BE16_TO_HOST(board->model)); 615 *data++ = '\0'; 616 /* TODO: make hardware version configurable? */ 617 data += sprintf(data, "HwVerRange 2 %d %d", 0, 0); 618 *data++ = '\0'; 619 620 user_size = (uint8_t *)data - buf; 621 mh->user_start= HOST_TO_BE32(mmap->addr+sizeof(*mh)); 622 mh->user_end= HOST_TO_BE32(mmap->addr+user_size); 623 mh->csum = HOST_TO_BE16(csum_buf(buf+sizeof(*mh), user_size)); 624 625 res = write_out_data(outfile, buf, sizeof(buf), css); 626 627 return res; 628 } 629 630 631 int 632 block_stat_file(struct fw_block *block) 633 { 634 struct stat st; 635 int res; 636 637 if (block->file_name == NULL) 638 return 0; 639 640 res = stat(block->file_name, &st); 641 if (res){ 642 ERRS("stat failed on %s", block->file_name); 643 return res; 644 } 645 646 block->file_size = st.st_size; 647 return 0; 648 } 649 650 651 int 652 read_magic(uint16_t *magic) 653 { 654 FILE *f; 655 int res; 656 657 errno = 0; 658 f = fopen(bootext_block->file_name,"r"); 659 if (errno) { 660 ERRS("unable to open file: %s", bootext_block->file_name); 661 return -1; 662 } 663 664 errno = 0; 665 fread(magic, 2, 1, f); 666 if (errno != 0) { 667 ERRS("unable to read from file: %s", bootext_block->file_name); 668 res = -1; 669 goto err; 670 } 671 672 res = 0; 673 674 err: 675 fclose(f); 676 return res; 677 } 678 679 680 int 681 write_out_file(FILE *outfile, char *name, size_t len, struct csum_state *css) 682 { 683 char buf[FILE_BUF_LEN]; 684 size_t buflen = sizeof(buf); 685 FILE *f; 686 int res; 687 688 DBG(2, "writing out file, name=%s, len=%zu", 689 name, len); 690 691 errno = 0; 692 f = fopen(name,"r"); 693 if (errno) { 694 ERRS("unable to open file: %s", name); 695 return -1; 696 } 697 698 while (len > 0) { 699 if (len < buflen) 700 buflen = len; 701 702 /* read data from source file */ 703 errno = 0; 704 fread(buf, buflen, 1, f); 705 if (errno != 0) { 706 ERRS("unable to read from file: %s",name); 707 res = -1; 708 break; 709 } 710 711 res = write_out_data(outfile, buf, buflen, css); 712 if (res) 713 break; 714 715 len -= buflen; 716 } 717 718 fclose(f); 719 return res; 720 } 721 722 723 int 724 write_out_block(FILE *outfile, struct fw_block *block, struct csum_state *css) 725 { 726 int res; 727 728 if (block == NULL) 729 return 0; 730 731 if (block->file_name == NULL) 732 return 0; 733 734 if (block->file_size == 0) 735 return 0; 736 737 res = write_out_file(outfile, block->file_name, 738 block->file_size, css); 739 return res; 740 } 741 742 743 int 744 write_out_image(FILE *outfile) 745 { 746 struct fw_block *block; 747 struct fw_mmap mmap; 748 struct zyn_rombin_hdr hdr; 749 struct csum_state css; 750 int i, res; 751 uint32_t offset; 752 uint32_t padlen; 753 uint16_t csum; 754 uint16_t t; 755 756 /* setup header fields */ 757 memset(&hdr, 0, sizeof(hdr)); 758 hdr.addr = board->code_start; 759 hdr.type = OBJECT_TYPE_BOOTEXT; 760 hdr.flags = ROMBIN_FLAG_OCSUM; 761 762 offset = board->romio_offs; 763 764 res = write_out_header(outfile, &hdr); 765 if (res) 766 return res; 767 768 offset += sizeof(hdr); 769 770 csum_init(&css); 771 res = write_out_block(outfile, bootext_block, &css); 772 if (res) 773 return res; 774 775 offset += bootext_block->file_size; 776 if (offset > (board->romio_offs + board->bootext_size)) { 777 ERR("bootext file '%s' is too big", bootext_block->file_name); 778 return -1; 779 } 780 781 padlen = ALIGN(offset, MMAP_ALIGN) - offset; 782 res = write_out_padding(outfile, padlen, 0xFF, &css); 783 if (res) 784 return res; 785 786 offset += padlen; 787 788 mmap.addr = board->flash_base + offset; 789 res = write_out_mmap(outfile, &mmap, &css); 790 if (res) 791 return res; 792 793 offset += MMAP_DATA_SIZE; 794 795 if ((offset - board->romio_offs) < board->bootext_size) { 796 padlen = board->romio_offs + board->bootext_size - offset; 797 res = write_out_padding(outfile, padlen, 0xFF, &css); 798 if (res) 799 return res; 800 offset += padlen; 801 802 DBG(2, "bootext end at %08x", offset); 803 } 804 805 for (i = 0; i < num_blocks; i++) { 806 block = &blocks[i]; 807 808 if (block->type == BLOCK_TYPE_BOOTEXT) 809 continue; 810 811 padlen = ALIGN(offset, block->align) - offset; 812 res = write_out_padding(outfile, padlen, 0xFF, &css); 813 if (res) 814 return res; 815 offset += padlen; 816 817 res = write_out_block(outfile, block, &css); 818 if (res) 819 return res; 820 offset += block->file_size; 821 } 822 823 padlen = ALIGN(offset, 4) - offset; 824 res = write_out_padding(outfile, padlen, 0xFF, &css); 825 if (res) 826 return res; 827 offset += padlen; 828 829 csum = csum_get(&css); 830 hdr.mmap_addr = mmap.addr; 831 hdr.osize = 2; 832 833 res = read_magic(&hdr.ocsum); 834 if (res) 835 return res; 836 hdr.ocsum = BE16_TO_HOST(hdr.ocsum); 837 838 if (csum <= hdr.ocsum) 839 t = hdr.ocsum - csum; 840 else 841 t = hdr.ocsum - csum - 1; 842 843 DBG(2, "ocsum=%04x, csum=%04x, fix=%04x", hdr.ocsum, csum, t); 844 845 t = HOST_TO_BE16(t); 846 res = write_out_data(outfile, (uint8_t *)&t, 2, NULL); 847 if (res) 848 return res; 849 850 851 res = write_out_header(outfile, &hdr); 852 853 return res; 854 } 855 856 857 struct board_info * 858 find_board(char *name) 859 { 860 struct board_info *ret; 861 struct board_info *board; 862 863 ret = NULL; 864 for (board = boards; board->name != NULL; board++){ 865 if (strcasecmp(name, board->name) == 0) { 866 ret = board; 867 break; 868 } 869 }; 870 871 return ret; 872 } 873 874 875 int 876 parse_opt_board(char ch, char *arg) 877 { 878 879 DBG(1,"parsing board option: -%c %s", ch, arg); 880 881 if (board != NULL) { 882 ERR("only one board option allowed"); 883 return -1; 884 } 885 886 if (required_arg(ch, arg)) 887 return -1; 888 889 board = find_board(arg); 890 if (board == NULL){ 891 ERR("invalid/unknown board specified: %s", arg); 892 return -1; 893 } 894 895 return 0; 896 } 897 898 899 int 900 parse_opt_ofname(char ch, char *arg) 901 { 902 903 if (ofname != NULL) { 904 ERR("only one output file allowed"); 905 return -1; 906 } 907 908 if (required_arg(ch, arg)) 909 return -1; 910 911 ofname = arg; 912 913 return 0; 914 } 915 916 917 int 918 parse_opt_block(char ch, char *arg) 919 { 920 char buf[MAX_ARG_LEN]; 921 char *argv[MAX_ARG_COUNT]; 922 char *p; 923 struct fw_block *block; 924 int i; 925 926 if ( num_blocks >= MAX_NUM_BLOCKS ) { 927 ERR("too many blocks specified"); 928 return -1; 929 } 930 931 block = &blocks[num_blocks++]; 932 933 /* setup default field values */ 934 block->padc = 0xFF; 935 936 switch(ch) { 937 case 'b': 938 if (bootext_block) { 939 ERR("only one boot extension block allowed"); 940 break; 941 } 942 block->type = BLOCK_TYPE_BOOTEXT; 943 bootext_block = block; 944 break; 945 case 'r': 946 block->type = BLOCK_TYPE_RAW; 947 break; 948 } 949 950 parse_arg(arg, buf, argv); 951 952 i = 0; 953 p = argv[i++]; 954 if (is_empty_arg(p)) { 955 ERR("no file specified in %s", arg); 956 return -1; 957 } else { 958 block->file_name = strdup(p); 959 if (block->file_name == NULL) { 960 ERR("not enough memory"); 961 return -1; 962 } 963 } 964 965 if (block->type == BLOCK_TYPE_BOOTEXT) 966 return 0; 967 968 p = argv[i++]; 969 if (!is_empty_arg(p)) { 970 if (str2u32(p, &block->align) != 0) { 971 ERR("invalid block align in %s", arg); 972 return -1; 973 } 974 } 975 976 return 0; 977 } 978 979 980 int 981 calc_block_offsets(int type, uint32_t *offset) 982 { 983 struct fw_block *block; 984 uint32_t next_offs; 985 uint32_t avail; 986 int i, res; 987 988 DBG(1,"calculating block offsets, starting with %" PRIu32, 989 *offset); 990 991 res = 0; 992 for (i = 0; i < num_blocks; i++) { 993 block = &blocks[i]; 994 995 if (block->type != type) 996 continue; 997 998 next_offs = ALIGN(*offset, block->align); 999 avail = board->flash_size - next_offs; 1000 if (block->file_size > avail) { 1001 ERR("file %s is too big, offset = %u, size=%u," 1002 " avail = %u, align = %u", block->file_name, 1003 (unsigned)next_offs, 1004 (unsigned)block->file_size, 1005 (unsigned)avail, 1006 (unsigned)block->align); 1007 res = -1; 1008 break; 1009 } 1010 1011 block->padlen = next_offs - *offset; 1012 *offset += block->file_size; 1013 } 1014 1015 return res; 1016 } 1017 1018 int 1019 process_blocks(void) 1020 { 1021 struct fw_block *block; 1022 uint32_t offset; 1023 int i; 1024 int res; 1025 1026 /* collecting file stats */ 1027 for (i = 0; i < num_blocks; i++) { 1028 block = &blocks[i]; 1029 res = block_stat_file(block); 1030 if (res) 1031 return res; 1032 } 1033 1034 offset = board->romio_offs + bootext_block->file_size; 1035 res = calc_block_offsets(BLOCK_TYPE_RAW, &offset); 1036 1037 return res; 1038 } 1039 1040 1041 int 1042 main(int argc, char *argv[]) 1043 { 1044 int optinvalid = 0; /* flag for invalid option */ 1045 int c; 1046 int res = EXIT_FAILURE; 1047 1048 FILE *outfile; 1049 1050 progname=basename(argv[0]); 1051 1052 opterr = 0; /* could not print standard getopt error messages */ 1053 while ( 1 ) { 1054 optinvalid = 0; 1055 1056 c = getopt(argc, argv, "b:B:ho:r:v"); 1057 if (c == -1) 1058 break; 1059 1060 switch (c) { 1061 case 'b': 1062 case 'r': 1063 optinvalid = parse_opt_block(c,optarg); 1064 break; 1065 case 'B': 1066 optinvalid = parse_opt_board(c,optarg); 1067 break; 1068 case 'o': 1069 optinvalid = parse_opt_ofname(c,optarg); 1070 break; 1071 case 'v': 1072 verblevel++; 1073 break; 1074 case 'h': 1075 usage(EXIT_SUCCESS); 1076 break; 1077 default: 1078 optinvalid = 1; 1079 break; 1080 } 1081 if (optinvalid != 0 ) { 1082 ERR("invalid option: -%c", optopt); 1083 goto out; 1084 } 1085 } 1086 1087 if (board == NULL) { 1088 ERR("no board specified"); 1089 goto out; 1090 } 1091 1092 if (ofname == NULL) { 1093 ERR("no output file specified"); 1094 goto out; 1095 } 1096 1097 if (optind < argc) { 1098 ERR("invalid option: %s", argv[optind]); 1099 goto out; 1100 } 1101 1102 if (process_blocks() != 0) { 1103 goto out; 1104 } 1105 1106 outfile = fopen(ofname, "w"); 1107 if (outfile == NULL) { 1108 ERRS("could not open \"%s\" for writing", ofname); 1109 goto out; 1110 } 1111 1112 if (write_out_image(outfile) != 0) 1113 goto out_flush; 1114 1115 DBG(1,"Image file %s completed.", ofname); 1116 1117 res = EXIT_SUCCESS; 1118 1119 out_flush: 1120 fflush(outfile); 1121 fclose(outfile); 1122 if (res != EXIT_SUCCESS) { 1123 unlink(ofname); 1124 } 1125 out: 1126 return res; 1127 } 1128
This page was automatically generated by LXR 0.3.1. • OpenWrt