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