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